From 458120dd40db6b4df55a4e96b650e16798ef06a0 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Tue, 3 May 2011 11:25:13 +0000 Subject: add hg and python --- sys/src/cmd/hg/CONTRIBUTORS | 41 + sys/src/cmd/hg/COPYING | 340 + sys/src/cmd/hg/Makefile | 103 + sys/src/cmd/hg/README | 10 + sys/src/cmd/hg/README.Plan9 | 5 + sys/src/cmd/hg/contrib/bash_completion | 532 + sys/src/cmd/hg/contrib/buildrpm | 72 + sys/src/cmd/hg/contrib/convert-repo | 27 + sys/src/cmd/hg/contrib/dumprevlog | 25 + sys/src/cmd/hg/contrib/git-viz/git-cat-file | 5 + sys/src/cmd/hg/contrib/git-viz/git-diff-tree | 5 + sys/src/cmd/hg/contrib/git-viz/git-rev-list | 5 + sys/src/cmd/hg/contrib/git-viz/git-rev-tree | 5 + sys/src/cmd/hg/contrib/git-viz/hg-viz | 26 + sys/src/cmd/hg/contrib/hg-relink | 128 + sys/src/cmd/hg/contrib/hg-ssh | 52 + sys/src/cmd/hg/contrib/hgdiff | 105 + sys/src/cmd/hg/contrib/hgk | 4001 +++++ sys/src/cmd/hg/contrib/hgsh/Makefile | 13 + sys/src/cmd/hg/contrib/hgsh/hgsh.c | 439 + sys/src/cmd/hg/contrib/hgwebdir.fcgi | 62 + sys/src/cmd/hg/contrib/hgwebdir.wsgi | 51 + sys/src/cmd/hg/contrib/logo-droplets.svg | 624 + sys/src/cmd/hg/contrib/macosx/Readme.html | 37 + sys/src/cmd/hg/contrib/macosx/Welcome.html | 20 + sys/src/cmd/hg/contrib/macosx/macosx-build.txt | 11 + sys/src/cmd/hg/contrib/mercurial.el | 1294 ++ sys/src/cmd/hg/contrib/mercurial.spec | 86 + sys/src/cmd/hg/contrib/mergetools.hgrc | 63 + sys/src/cmd/hg/contrib/mq.el | 418 + sys/src/cmd/hg/contrib/perf.py | 131 + sys/src/cmd/hg/contrib/python-hook-examples.py | 22 + sys/src/cmd/hg/contrib/rewrite-log | 23 + sys/src/cmd/hg/contrib/sample.hgrc | 133 + sys/src/cmd/hg/contrib/simplemerge | 67 + sys/src/cmd/hg/contrib/tcsh_completion | 49 + sys/src/cmd/hg/contrib/tcsh_completion_build.sh | 73 + sys/src/cmd/hg/contrib/tmplrewrite.py | 23 + sys/src/cmd/hg/contrib/undumprevlog | 37 + sys/src/cmd/hg/contrib/vim/HGAnnotate.vim | 27 + sys/src/cmd/hg/contrib/vim/hg-menu.vim | 93 + sys/src/cmd/hg/contrib/vim/hgcommand.vim | 1703 +++ sys/src/cmd/hg/contrib/vim/patchreview.txt | 97 + sys/src/cmd/hg/contrib/vim/patchreview.vim | 332 + sys/src/cmd/hg/contrib/win32/ReadMe.html | 163 + sys/src/cmd/hg/contrib/win32/hg.bat | 12 + sys/src/cmd/hg/contrib/win32/mercurial.ico | Bin 0 -> 2238 bytes sys/src/cmd/hg/contrib/win32/mercurial.ini | 124 + sys/src/cmd/hg/contrib/win32/mercurial.iss | 103 + sys/src/cmd/hg/contrib/win32/postinstall.txt | 9 + sys/src/cmd/hg/contrib/win32/win32-build.txt | 114 + sys/src/cmd/hg/contrib/zsh_completion | 946 ++ sys/src/cmd/hg/doc/Makefile | 48 + sys/src/cmd/hg/doc/README | 17 + sys/src/cmd/hg/doc/common.txt | 8 + sys/src/cmd/hg/doc/gendoc.py | 115 + sys/src/cmd/hg/doc/hg.1.txt | 96 + sys/src/cmd/hg/doc/hgignore.5.txt | 111 + sys/src/cmd/hg/doc/hgrc.5.txt | 934 ++ sys/src/cmd/hg/doc/ja/Makefile | 21 + sys/src/cmd/hg/doc/ja/docbook.ja.conf | 583 + sys/src/cmd/hg/doc/ja/docbook.ja.xsl | 23 + sys/src/cmd/hg/doc/ja/hg.1.ja.txt | 867 ++ sys/src/cmd/hg/doc/ja/hgrc.5.ja.txt | 204 + sys/src/cmd/hg/hg | 31 + sys/src/cmd/hg/hg.proto | 14 + sys/src/cmd/hg/hgeditor | 56 + sys/src/cmd/hg/hgext/__init__.py | 1 + sys/src/cmd/hg/hgext/acl.py | 107 + sys/src/cmd/hg/hgext/bookmarks.py | 340 + sys/src/cmd/hg/hgext/bugzilla.py | 439 + sys/src/cmd/hg/hgext/children.py | 44 + sys/src/cmd/hg/hgext/churn.py | 174 + sys/src/cmd/hg/hgext/color.py | 286 + sys/src/cmd/hg/hgext/convert/__init__.py | 296 + sys/src/cmd/hg/hgext/convert/bzr.py | 259 + sys/src/cmd/hg/hgext/convert/common.py | 389 + sys/src/cmd/hg/hgext/convert/convcmd.py | 396 + sys/src/cmd/hg/hgext/convert/cvs.py | 372 + sys/src/cmd/hg/hgext/convert/cvsps.py | 831 + sys/src/cmd/hg/hgext/convert/darcs.py | 135 + sys/src/cmd/hg/hgext/convert/filemap.py | 359 + sys/src/cmd/hg/hgext/convert/git.py | 152 + sys/src/cmd/hg/hgext/convert/gnuarch.py | 342 + sys/src/cmd/hg/hgext/convert/hg.py | 363 + sys/src/cmd/hg/hgext/convert/monotone.py | 217 + sys/src/cmd/hg/hgext/convert/p4.py | 205 + sys/src/cmd/hg/hgext/convert/subversion.py | 1136 ++ sys/src/cmd/hg/hgext/convert/transport.py | 128 + sys/src/cmd/hg/hgext/extdiff.py | 228 + sys/src/cmd/hg/hgext/fetch.py | 148 + sys/src/cmd/hg/hgext/gpg.py | 284 + sys/src/cmd/hg/hgext/graphlog.py | 378 + sys/src/cmd/hg/hgext/hgcia.py | 246 + sys/src/cmd/hg/hgext/hgk.py | 347 + sys/src/cmd/hg/hgext/highlight/__init__.py | 60 + sys/src/cmd/hg/hgext/highlight/highlight.py | 60 + sys/src/cmd/hg/hgext/inotify/__init__.py | 109 + sys/src/cmd/hg/hgext/inotify/client.py | 160 + sys/src/cmd/hg/hgext/inotify/common.py | 51 + sys/src/cmd/hg/hgext/inotify/linux/__init__.py | 41 + sys/src/cmd/hg/hgext/inotify/linux/_inotify.c | 608 + sys/src/cmd/hg/hgext/inotify/linux/watcher.py | 335 + sys/src/cmd/hg/hgext/inotify/server.py | 874 ++ sys/src/cmd/hg/hgext/interhg.py | 80 + sys/src/cmd/hg/hgext/keyword.py | 555 + sys/src/cmd/hg/hgext/mq.py | 2653 ++++ sys/src/cmd/hg/hgext/notify.py | 298 + sys/src/cmd/hg/hgext/pager.py | 64 + sys/src/cmd/hg/hgext/parentrevspec.py | 96 + sys/src/cmd/hg/hgext/patchbomb.py | 513 + sys/src/cmd/hg/hgext/purge.py | 111 + sys/src/cmd/hg/hgext/rebase.py | 471 + sys/src/cmd/hg/hgext/record.py | 551 + sys/src/cmd/hg/hgext/share.py | 30 + sys/src/cmd/hg/hgext/transplant.py | 606 + sys/src/cmd/hg/hgext/win32mbcs.py | 147 + sys/src/cmd/hg/hgext/win32text.py | 158 + sys/src/cmd/hg/hgext/zeroconf/Zeroconf.py | 1573 ++ sys/src/cmd/hg/hgext/zeroconf/__init__.py | 159 + sys/src/cmd/hg/hgweb.cgi | 28 + sys/src/cmd/hg/hgwebdir.cgi | 67 + sys/src/cmd/hg/i18n/da.po | 9275 +++++++++++ sys/src/cmd/hg/i18n/de.po | 9685 ++++++++++++ sys/src/cmd/hg/i18n/el.po | 8779 +++++++++++ sys/src/cmd/hg/i18n/fr.po | 9171 +++++++++++ sys/src/cmd/hg/i18n/hggettext | 123 + sys/src/cmd/hg/i18n/it.po | 9510 ++++++++++++ sys/src/cmd/hg/i18n/ja.po | 10605 +++++++++++++ sys/src/cmd/hg/i18n/pt_BR.po | 11609 ++++++++++++++ sys/src/cmd/hg/i18n/zh_CN.po | 9165 +++++++++++ sys/src/cmd/hg/i18n/zh_TW.po | 9255 +++++++++++ sys/src/cmd/hg/mercurial/__init__.py | 0 sys/src/cmd/hg/mercurial/__init__.pyc | Bin 0 -> 110 bytes sys/src/cmd/hg/mercurial/ancestor.py | 85 + sys/src/cmd/hg/mercurial/archival.py | 226 + sys/src/cmd/hg/mercurial/base85.c | 155 + sys/src/cmd/hg/mercurial/bdiff.c | 401 + sys/src/cmd/hg/mercurial/bundlerepo.py | 303 + sys/src/cmd/hg/mercurial/byterange.py | 468 + sys/src/cmd/hg/mercurial/changegroup.py | 140 + sys/src/cmd/hg/mercurial/changelog.py | 228 + sys/src/cmd/hg/mercurial/cmdutil.py | 1254 ++ sys/src/cmd/hg/mercurial/commands.py | 3565 +++++ sys/src/cmd/hg/mercurial/commands.pyc | Bin 0 -> 124515 bytes sys/src/cmd/hg/mercurial/config.py | 137 + sys/src/cmd/hg/mercurial/config.pyc | Bin 0 -> 5736 bytes sys/src/cmd/hg/mercurial/context.py | 818 + sys/src/cmd/hg/mercurial/copies.py | 233 + sys/src/cmd/hg/mercurial/demandimport.py | 139 + sys/src/cmd/hg/mercurial/demandimport.pyc | Bin 0 -> 4500 bytes sys/src/cmd/hg/mercurial/diffhelpers.c | 156 + sys/src/cmd/hg/mercurial/dirstate.py | 601 + sys/src/cmd/hg/mercurial/dispatch.py | 501 + sys/src/cmd/hg/mercurial/dispatch.pyc | Bin 0 -> 16165 bytes sys/src/cmd/hg/mercurial/encoding.py | 75 + sys/src/cmd/hg/mercurial/encoding.pyc | Bin 0 -> 2892 bytes sys/src/cmd/hg/mercurial/error.py | 72 + sys/src/cmd/hg/mercurial/error.pyc | Bin 0 -> 3986 bytes sys/src/cmd/hg/mercurial/extensions.py | 178 + sys/src/cmd/hg/mercurial/extensions.pyc | Bin 0 -> 5555 bytes sys/src/cmd/hg/mercurial/fancyopts.py | 110 + sys/src/cmd/hg/mercurial/fancyopts.pyc | Bin 0 -> 2621 bytes sys/src/cmd/hg/mercurial/filelog.py | 68 + sys/src/cmd/hg/mercurial/filemerge.py | 231 + sys/src/cmd/hg/mercurial/graphmod.py | 119 + sys/src/cmd/hg/mercurial/hbisect.py | 145 + sys/src/cmd/hg/mercurial/help.py | 527 + sys/src/cmd/hg/mercurial/hg.py | 367 + sys/src/cmd/hg/mercurial/hgweb/__init__.py | 16 + sys/src/cmd/hg/mercurial/hgweb/__init__.pyc | Bin 0 -> 499 bytes sys/src/cmd/hg/mercurial/hgweb/common.py | 105 + sys/src/cmd/hg/mercurial/hgweb/hgweb_mod.py | 315 + sys/src/cmd/hg/mercurial/hgweb/hgwebdir_mod.py | 333 + sys/src/cmd/hg/mercurial/hgweb/protocol.py | 206 + sys/src/cmd/hg/mercurial/hgweb/request.py | 134 + sys/src/cmd/hg/mercurial/hgweb/server.py | 298 + sys/src/cmd/hg/mercurial/hgweb/webcommands.py | 690 + sys/src/cmd/hg/mercurial/hgweb/webutil.py | 218 + sys/src/cmd/hg/mercurial/hgweb/wsgicgi.py | 70 + sys/src/cmd/hg/mercurial/hook.py | 135 + sys/src/cmd/hg/mercurial/httprepo.py | 258 + sys/src/cmd/hg/mercurial/i18n.py | 52 + sys/src/cmd/hg/mercurial/i18n.pyc | Bin 0 -> 1216 bytes sys/src/cmd/hg/mercurial/ignore.py | 103 + sys/src/cmd/hg/mercurial/keepalive.py | 671 + sys/src/cmd/hg/mercurial/localrepo.py | 2156 +++ sys/src/cmd/hg/mercurial/lock.py | 137 + sys/src/cmd/hg/mercurial/lock.pyc | Bin 0 -> 3987 bytes sys/src/cmd/hg/mercurial/lsprof.py | 113 + sys/src/cmd/hg/mercurial/lsprofcalltree.py | 86 + sys/src/cmd/hg/mercurial/mail.py | 190 + sys/src/cmd/hg/mercurial/manifest.py | 201 + sys/src/cmd/hg/mercurial/match.py | 249 + sys/src/cmd/hg/mercurial/mdiff.py | 269 + sys/src/cmd/hg/mercurial/merge.py | 481 + sys/src/cmd/hg/mercurial/minirst.py | 343 + sys/src/cmd/hg/mercurial/mpatch.c | 444 + sys/src/cmd/hg/mercurial/node.py | 18 + sys/src/cmd/hg/mercurial/node.pyc | Bin 0 -> 417 bytes sys/src/cmd/hg/mercurial/osutil.c | 534 + sys/src/cmd/hg/mercurial/parsers.c | 435 + sys/src/cmd/hg/mercurial/patch.py | 1454 ++ sys/src/cmd/hg/mercurial/posix.py | 252 + sys/src/cmd/hg/mercurial/posix.pyc | Bin 0 -> 9261 bytes sys/src/cmd/hg/mercurial/pure/base85.py | 74 + sys/src/cmd/hg/mercurial/pure/bdiff.py | 76 + sys/src/cmd/hg/mercurial/pure/diffhelpers.py | 56 + sys/src/cmd/hg/mercurial/pure/mpatch.py | 116 + sys/src/cmd/hg/mercurial/pure/osutil.py | 52 + sys/src/cmd/hg/mercurial/pure/parsers.py | 90 + sys/src/cmd/hg/mercurial/repair.py | 145 + sys/src/cmd/hg/mercurial/repo.py | 43 + sys/src/cmd/hg/mercurial/revlog.py | 1376 ++ sys/src/cmd/hg/mercurial/simplemerge.py | 451 + sys/src/cmd/hg/mercurial/sshrepo.py | 260 + sys/src/cmd/hg/mercurial/sshserver.py | 225 + sys/src/cmd/hg/mercurial/statichttprepo.py | 134 + sys/src/cmd/hg/mercurial/store.py | 333 + sys/src/cmd/hg/mercurial/streamclone.py | 67 + sys/src/cmd/hg/mercurial/strutil.py | 34 + sys/src/cmd/hg/mercurial/subrepo.py | 197 + sys/src/cmd/hg/mercurial/tags.py | 338 + sys/src/cmd/hg/mercurial/templatefilters.py | 211 + sys/src/cmd/hg/mercurial/templater.py | 245 + sys/src/cmd/hg/mercurial/transaction.py | 165 + sys/src/cmd/hg/mercurial/ui.py | 381 + sys/src/cmd/hg/mercurial/ui.pyc | Bin 0 -> 14752 bytes sys/src/cmd/hg/mercurial/url.py | 533 + sys/src/cmd/hg/mercurial/util.py | 1284 ++ sys/src/cmd/hg/mercurial/util.pyc | Bin 0 -> 42141 bytes sys/src/cmd/hg/mercurial/verify.py | 258 + sys/src/cmd/hg/mercurial/win32.py | 144 + sys/src/cmd/hg/mercurial/windows.py | 292 + sys/src/cmd/hg/mkfile | 17 + sys/src/cmd/hg/setup.py | 273 + sys/src/cmd/hg/templates/atom/changelog.tmpl | 10 + sys/src/cmd/hg/templates/atom/changelogentry.tmpl | 16 + sys/src/cmd/hg/templates/atom/error.tmpl | 17 + sys/src/cmd/hg/templates/atom/filelog.tmpl | 8 + sys/src/cmd/hg/templates/atom/header.tmpl | 2 + sys/src/cmd/hg/templates/atom/map | 11 + sys/src/cmd/hg/templates/atom/tagentry.tmpl | 8 + sys/src/cmd/hg/templates/atom/tags.tmpl | 11 + sys/src/cmd/hg/templates/coal/header.tmpl | 6 + sys/src/cmd/hg/templates/coal/map | 191 + sys/src/cmd/hg/templates/gitweb/branches.tmpl | 30 + sys/src/cmd/hg/templates/gitweb/changelog.tmpl | 39 + .../cmd/hg/templates/gitweb/changelogentry.tmpl | 14 + sys/src/cmd/hg/templates/gitweb/changeset.tmpl | 50 + sys/src/cmd/hg/templates/gitweb/error.tmpl | 25 + sys/src/cmd/hg/templates/gitweb/fileannotate.tmpl | 61 + sys/src/cmd/hg/templates/gitweb/filediff.tmpl | 47 + sys/src/cmd/hg/templates/gitweb/filelog.tmpl | 40 + sys/src/cmd/hg/templates/gitweb/filerevision.tmpl | 60 + sys/src/cmd/hg/templates/gitweb/footer.tmpl | 11 + sys/src/cmd/hg/templates/gitweb/graph.tmpl | 121 + sys/src/cmd/hg/templates/gitweb/header.tmpl | 8 + sys/src/cmd/hg/templates/gitweb/index.tmpl | 26 + sys/src/cmd/hg/templates/gitweb/manifest.tmpl | 38 + sys/src/cmd/hg/templates/gitweb/map | 248 + sys/src/cmd/hg/templates/gitweb/notfound.tmpl | 18 + sys/src/cmd/hg/templates/gitweb/search.tmpl | 36 + sys/src/cmd/hg/templates/gitweb/shortlog.tmpl | 41 + sys/src/cmd/hg/templates/gitweb/summary.tmpl | 58 + sys/src/cmd/hg/templates/gitweb/tags.tmpl | 30 + sys/src/cmd/hg/templates/map-cmdline.changelog | 14 + sys/src/cmd/hg/templates/map-cmdline.compact | 9 + sys/src/cmd/hg/templates/map-cmdline.default | 24 + sys/src/cmd/hg/templates/monoblue/branches.tmpl | 36 + sys/src/cmd/hg/templates/monoblue/changelog.tmpl | 40 + .../cmd/hg/templates/monoblue/changelogentry.tmpl | 6 + sys/src/cmd/hg/templates/monoblue/changeset.tmpl | 63 + sys/src/cmd/hg/templates/monoblue/error.tmpl | 34 + .../cmd/hg/templates/monoblue/fileannotate.tmpl | 63 + sys/src/cmd/hg/templates/monoblue/filediff.tmpl | 54 + sys/src/cmd/hg/templates/monoblue/filelog.tmpl | 49 + .../cmd/hg/templates/monoblue/filerevision.tmpl | 63 + sys/src/cmd/hg/templates/monoblue/footer.tmpl | 22 + sys/src/cmd/hg/templates/monoblue/graph.tmpl | 118 + sys/src/cmd/hg/templates/monoblue/header.tmpl | 6 + sys/src/cmd/hg/templates/monoblue/index.tmpl | 39 + sys/src/cmd/hg/templates/monoblue/manifest.tmpl | 51 + sys/src/cmd/hg/templates/monoblue/map | 214 + sys/src/cmd/hg/templates/monoblue/notfound.tmpl | 35 + sys/src/cmd/hg/templates/monoblue/search.tmpl | 34 + sys/src/cmd/hg/templates/monoblue/shortlog.tmpl | 41 + sys/src/cmd/hg/templates/monoblue/summary.tmpl | 66 + sys/src/cmd/hg/templates/monoblue/tags.tmpl | 36 + sys/src/cmd/hg/templates/paper/branches.tmpl | 45 + sys/src/cmd/hg/templates/paper/changeset.tmpl | 71 + sys/src/cmd/hg/templates/paper/error.tmpl | 43 + sys/src/cmd/hg/templates/paper/fileannotate.tmpl | 77 + sys/src/cmd/hg/templates/paper/filediff.tmpl | 72 + sys/src/cmd/hg/templates/paper/filelog.tmpl | 60 + sys/src/cmd/hg/templates/paper/filelogentry.tmpl | 5 + sys/src/cmd/hg/templates/paper/filerevision.tmpl | 72 + sys/src/cmd/hg/templates/paper/footer.tmpl | 4 + sys/src/cmd/hg/templates/paper/graph.tmpl | 132 + sys/src/cmd/hg/templates/paper/header.tmpl | 6 + sys/src/cmd/hg/templates/paper/index.tmpl | 26 + sys/src/cmd/hg/templates/paper/manifest.tmpl | 54 + sys/src/cmd/hg/templates/paper/map | 191 + sys/src/cmd/hg/templates/paper/notfound.tmpl | 12 + sys/src/cmd/hg/templates/paper/search.tmpl | 43 + sys/src/cmd/hg/templates/paper/shortlog.tmpl | 57 + sys/src/cmd/hg/templates/paper/shortlogentry.tmpl | 5 + sys/src/cmd/hg/templates/paper/tags.tmpl | 45 + sys/src/cmd/hg/templates/raw/changeset.tmpl | 9 + sys/src/cmd/hg/templates/raw/error.tmpl | 2 + sys/src/cmd/hg/templates/raw/fileannotate.tmpl | 5 + sys/src/cmd/hg/templates/raw/filediff.tmpl | 5 + sys/src/cmd/hg/templates/raw/index.tmpl | 2 + sys/src/cmd/hg/templates/raw/manifest.tmpl | 3 + sys/src/cmd/hg/templates/raw/map | 23 + sys/src/cmd/hg/templates/raw/notfound.tmpl | 2 + sys/src/cmd/hg/templates/rss/changelog.tmpl | 6 + sys/src/cmd/hg/templates/rss/changelogentry.tmpl | 7 + sys/src/cmd/hg/templates/rss/error.tmpl | 10 + sys/src/cmd/hg/templates/rss/filelog.tmpl | 6 + sys/src/cmd/hg/templates/rss/filelogentry.tmpl | 7 + sys/src/cmd/hg/templates/rss/header.tmpl | 5 + sys/src/cmd/hg/templates/rss/map | 10 + sys/src/cmd/hg/templates/rss/tagentry.tmpl | 6 + sys/src/cmd/hg/templates/rss/tags.tmpl | 6 + sys/src/cmd/hg/templates/spartan/branches.tmpl | 26 + sys/src/cmd/hg/templates/spartan/changelog.tmpl | 43 + .../cmd/hg/templates/spartan/changelogentry.tmpl | 25 + sys/src/cmd/hg/templates/spartan/changeset.tmpl | 51 + sys/src/cmd/hg/templates/spartan/error.tmpl | 15 + sys/src/cmd/hg/templates/spartan/fileannotate.tmpl | 48 + sys/src/cmd/hg/templates/spartan/filediff.tmpl | 36 + sys/src/cmd/hg/templates/spartan/filelog.tmpl | 28 + sys/src/cmd/hg/templates/spartan/filelogentry.tmpl | 25 + sys/src/cmd/hg/templates/spartan/filerevision.tmpl | 46 + sys/src/cmd/hg/templates/spartan/footer.tmpl | 8 + sys/src/cmd/hg/templates/spartan/graph.tmpl | 96 + sys/src/cmd/hg/templates/spartan/header.tmpl | 6 + sys/src/cmd/hg/templates/spartan/index.tmpl | 19 + sys/src/cmd/hg/templates/spartan/manifest.tmpl | 28 + sys/src/cmd/hg/templates/spartan/map | 178 + sys/src/cmd/hg/templates/spartan/notfound.tmpl | 12 + sys/src/cmd/hg/templates/spartan/search.tmpl | 36 + sys/src/cmd/hg/templates/spartan/shortlog.tmpl | 43 + .../cmd/hg/templates/spartan/shortlogentry.tmpl | 7 + sys/src/cmd/hg/templates/spartan/tags.tmpl | 26 + sys/src/cmd/hg/templates/static/background.png | Bin 0 -> 603 bytes sys/src/cmd/hg/templates/static/coal-file.png | Bin 0 -> 273 bytes sys/src/cmd/hg/templates/static/coal-folder.png | Bin 0 -> 284 bytes sys/src/cmd/hg/templates/static/excanvas.js | 19 + sys/src/cmd/hg/templates/static/graph.js | 137 + sys/src/cmd/hg/templates/static/hgicon.png | Bin 0 -> 792 bytes sys/src/cmd/hg/templates/static/hglogo.png | Bin 0 -> 4123 bytes sys/src/cmd/hg/templates/static/style-coal.css | 265 + sys/src/cmd/hg/templates/static/style-gitweb.css | 123 + sys/src/cmd/hg/templates/static/style-monoblue.css | 472 + sys/src/cmd/hg/templates/static/style-paper.css | 254 + sys/src/cmd/hg/templates/static/style.css | 105 + sys/src/cmd/hg/templates/template-vars.txt | 37 + sys/src/cmd/python/Demo/README | 61 + sys/src/cmd/python/Demo/cgi/README | 11 + sys/src/cmd/python/Demo/cgi/cgi0.sh | 8 + sys/src/cmd/python/Demo/cgi/cgi1.py | 14 + sys/src/cmd/python/Demo/cgi/cgi2.py | 22 + sys/src/cmd/python/Demo/cgi/cgi3.py | 10 + sys/src/cmd/python/Demo/cgi/wiki.py | 123 + sys/src/cmd/python/Demo/classes/Complex.py | 320 + sys/src/cmd/python/Demo/classes/Dates.py | 222 + sys/src/cmd/python/Demo/classes/Dbm.py | 66 + sys/src/cmd/python/Demo/classes/README | 13 + sys/src/cmd/python/Demo/classes/Range.py | 93 + sys/src/cmd/python/Demo/classes/Rat.py | 310 + sys/src/cmd/python/Demo/classes/Rev.py | 95 + sys/src/cmd/python/Demo/classes/Vec.py | 54 + sys/src/cmd/python/Demo/classes/bitvec.py | 332 + sys/src/cmd/python/Demo/comparisons/README | 60 + sys/src/cmd/python/Demo/comparisons/patterns | 4 + sys/src/cmd/python/Demo/comparisons/regextest.py | 47 + sys/src/cmd/python/Demo/comparisons/sortingtest.py | 51 + sys/src/cmd/python/Demo/comparisons/systemtest.py | 74 + sys/src/cmd/python/Demo/curses/README | 25 + sys/src/cmd/python/Demo/curses/life.py | 216 + sys/src/cmd/python/Demo/curses/ncurses.py | 273 + sys/src/cmd/python/Demo/curses/rain.py | 94 + sys/src/cmd/python/Demo/curses/repeat.py | 58 + sys/src/cmd/python/Demo/curses/tclock.py | 147 + sys/src/cmd/python/Demo/curses/xmas.py | 906 ++ sys/src/cmd/python/Demo/embed/Makefile | 57 + sys/src/cmd/python/Demo/embed/README | 19 + sys/src/cmd/python/Demo/embed/demo.c | 65 + sys/src/cmd/python/Demo/embed/importexc.c | 17 + sys/src/cmd/python/Demo/embed/loop.c | 33 + sys/src/cmd/python/Demo/imputil/importers.py | 248 + sys/src/cmd/python/Demo/imputil/knee.py | 126 + sys/src/cmd/python/Demo/md5test/README | 10 + sys/src/cmd/python/Demo/md5test/foo | 1 + sys/src/cmd/python/Demo/md5test/md5driver.py | 123 + sys/src/cmd/python/Demo/metaclasses/Eiffel.py | 113 + sys/src/cmd/python/Demo/metaclasses/Enum.py | 169 + sys/src/cmd/python/Demo/metaclasses/Meta.py | 118 + sys/src/cmd/python/Demo/metaclasses/Simple.py | 45 + sys/src/cmd/python/Demo/metaclasses/Synch.py | 256 + sys/src/cmd/python/Demo/metaclasses/Trace.py | 144 + sys/src/cmd/python/Demo/metaclasses/index.html | 605 + .../cmd/python/Demo/metaclasses/meta-vladimir.txt | 256 + sys/src/cmd/python/Demo/newmetaclasses/Eiffel.py | 141 + sys/src/cmd/python/Demo/newmetaclasses/Enum.py | 177 + sys/src/cmd/python/Demo/parser/FILES | 6 + sys/src/cmd/python/Demo/parser/README | 31 + sys/src/cmd/python/Demo/parser/docstring.py | 2 + sys/src/cmd/python/Demo/parser/example.py | 190 + sys/src/cmd/python/Demo/parser/simple.py | 1 + sys/src/cmd/python/Demo/parser/source.py | 27 + sys/src/cmd/python/Demo/parser/test_parser.py | 48 + sys/src/cmd/python/Demo/parser/texipre.dat | 100 + sys/src/cmd/python/Demo/parser/unparse.py | 519 + sys/src/cmd/python/Demo/pdist/FSProxy.py | 322 + sys/src/cmd/python/Demo/pdist/RCSProxy.py | 198 + sys/src/cmd/python/Demo/pdist/README | 121 + sys/src/cmd/python/Demo/pdist/client.py | 157 + sys/src/cmd/python/Demo/pdist/cmdfw.py | 144 + sys/src/cmd/python/Demo/pdist/cmptree.py | 208 + sys/src/cmd/python/Demo/pdist/cvslib.py | 364 + sys/src/cmd/python/Demo/pdist/cvslock.py | 280 + sys/src/cmd/python/Demo/pdist/mac.py | 19 + sys/src/cmd/python/Demo/pdist/makechangelog.py | 109 + sys/src/cmd/python/Demo/pdist/rcsbump | 33 + sys/src/cmd/python/Demo/pdist/rcsclient.py | 71 + sys/src/cmd/python/Demo/pdist/rcslib.py | 334 + sys/src/cmd/python/Demo/pdist/rcvs | 8 + sys/src/cmd/python/Demo/pdist/rcvs.py | 477 + sys/src/cmd/python/Demo/pdist/rrcs | 8 + sys/src/cmd/python/Demo/pdist/rrcs.py | 160 + sys/src/cmd/python/Demo/pdist/security.py | 33 + sys/src/cmd/python/Demo/pdist/server.py | 145 + sys/src/cmd/python/Demo/pdist/sumtree.py | 24 + sys/src/cmd/python/Demo/pysvr/Makefile | 57 + sys/src/cmd/python/Demo/pysvr/README | 9 + sys/src/cmd/python/Demo/pysvr/pysvr.c | 370 + sys/src/cmd/python/Demo/pysvr/pysvr.py | 124 + sys/src/cmd/python/Demo/rpc/MANIFEST | 10 + sys/src/cmd/python/Demo/rpc/README | 31 + sys/src/cmd/python/Demo/rpc/T.py | 22 + sys/src/cmd/python/Demo/rpc/mountclient.py | 202 + sys/src/cmd/python/Demo/rpc/nfsclient.py | 201 + sys/src/cmd/python/Demo/rpc/rnusersclient.py | 98 + sys/src/cmd/python/Demo/rpc/rpc.py | 893 ++ sys/src/cmd/python/Demo/rpc/test | 24 + sys/src/cmd/python/Demo/rpc/xdr.py | 200 + sys/src/cmd/python/Demo/scripts/README | 23 + sys/src/cmd/python/Demo/scripts/beer.py | 14 + sys/src/cmd/python/Demo/scripts/eqfix.py | 198 + sys/src/cmd/python/Demo/scripts/fact.py | 49 + sys/src/cmd/python/Demo/scripts/find-uname.py | 40 + sys/src/cmd/python/Demo/scripts/from.py | 35 + sys/src/cmd/python/Demo/scripts/ftpstats.py | 145 + sys/src/cmd/python/Demo/scripts/lpwatch.py | 110 + sys/src/cmd/python/Demo/scripts/makedir.py | 21 + sys/src/cmd/python/Demo/scripts/markov.py | 117 + sys/src/cmd/python/Demo/scripts/mboxconvert.py | 124 + sys/src/cmd/python/Demo/scripts/mkrcs.py | 61 + sys/src/cmd/python/Demo/scripts/morse.py | 149 + sys/src/cmd/python/Demo/scripts/newslist.doc | 59 + sys/src/cmd/python/Demo/scripts/newslist.py | 366 + sys/src/cmd/python/Demo/scripts/pi.py | 34 + sys/src/cmd/python/Demo/scripts/pp.py | 130 + sys/src/cmd/python/Demo/scripts/primes.py | 27 + sys/src/cmd/python/Demo/scripts/queens.py | 85 + sys/src/cmd/python/Demo/scripts/script.py | 33 + sys/src/cmd/python/Demo/scripts/unbirthday.py | 107 + sys/src/cmd/python/Demo/scripts/update.py | 92 + sys/src/cmd/python/Demo/scripts/wh.py | 2 + sys/src/cmd/python/Demo/sockets/README | 21 + sys/src/cmd/python/Demo/sockets/broadcast.py | 15 + sys/src/cmd/python/Demo/sockets/echosvr.py | 31 + sys/src/cmd/python/Demo/sockets/finger.py | 58 + sys/src/cmd/python/Demo/sockets/ftp.py | 146 + sys/src/cmd/python/Demo/sockets/gopher.py | 347 + sys/src/cmd/python/Demo/sockets/mcast.py | 93 + sys/src/cmd/python/Demo/sockets/radio.py | 14 + sys/src/cmd/python/Demo/sockets/rpython.py | 35 + sys/src/cmd/python/Demo/sockets/rpythond.py | 52 + sys/src/cmd/python/Demo/sockets/telnet.py | 109 + sys/src/cmd/python/Demo/sockets/throughput.py | 93 + sys/src/cmd/python/Demo/sockets/udpecho.py | 63 + sys/src/cmd/python/Demo/sockets/unicast.py | 14 + sys/src/cmd/python/Demo/sockets/unixclient.py | 12 + sys/src/cmd/python/Demo/sockets/unixserver.py | 24 + sys/src/cmd/python/Demo/threads/Coroutine.py | 159 + sys/src/cmd/python/Demo/threads/Generator.py | 84 + sys/src/cmd/python/Demo/threads/README | 13 + sys/src/cmd/python/Demo/threads/fcmp.py | 64 + sys/src/cmd/python/Demo/threads/find.py | 155 + sys/src/cmd/python/Demo/threads/squasher.py | 105 + sys/src/cmd/python/Demo/threads/sync.py | 603 + sys/src/cmd/python/Demo/threads/telnet.py | 114 + sys/src/cmd/python/Demo/tix/INSTALL.txt | 89 + sys/src/cmd/python/Demo/tix/README.txt | 19 + sys/src/cmd/python/Demo/tix/bitmaps/about.xpm | 50 + sys/src/cmd/python/Demo/tix/bitmaps/bold.xbm | 6 + sys/src/cmd/python/Demo/tix/bitmaps/capital.xbm | 6 + sys/src/cmd/python/Demo/tix/bitmaps/centerj.xbm | 6 + sys/src/cmd/python/Demo/tix/bitmaps/combobox.xbm | 14 + sys/src/cmd/python/Demo/tix/bitmaps/combobox.xpm | 49 + sys/src/cmd/python/Demo/tix/bitmaps/drivea.xbm | 14 + sys/src/cmd/python/Demo/tix/bitmaps/drivea.xpm | 43 + sys/src/cmd/python/Demo/tix/bitmaps/exit.xpm | 48 + sys/src/cmd/python/Demo/tix/bitmaps/filebox.xbm | 14 + sys/src/cmd/python/Demo/tix/bitmaps/filebox.xpm | 49 + sys/src/cmd/python/Demo/tix/bitmaps/italic.xbm | 6 + sys/src/cmd/python/Demo/tix/bitmaps/justify.xbm | 6 + sys/src/cmd/python/Demo/tix/bitmaps/leftj.xbm | 6 + sys/src/cmd/python/Demo/tix/bitmaps/netw.xbm | 14 + sys/src/cmd/python/Demo/tix/bitmaps/netw.xpm | 45 + sys/src/cmd/python/Demo/tix/bitmaps/optmenu.xpm | 48 + sys/src/cmd/python/Demo/tix/bitmaps/rightj.xbm | 6 + sys/src/cmd/python/Demo/tix/bitmaps/select.xpm | 52 + sys/src/cmd/python/Demo/tix/bitmaps/tix.gif | Bin 0 -> 11042 bytes sys/src/cmd/python/Demo/tix/bitmaps/underline.xbm | 6 + sys/src/cmd/python/Demo/tix/grid.py | 28 + sys/src/cmd/python/Demo/tix/samples/Balloon.py | 68 + sys/src/cmd/python/Demo/tix/samples/BtnBox.py | 44 + sys/src/cmd/python/Demo/tix/samples/CmpImg.py | 196 + sys/src/cmd/python/Demo/tix/samples/ComboBox.py | 102 + sys/src/cmd/python/Demo/tix/samples/Control.py | 122 + sys/src/cmd/python/Demo/tix/samples/DirList.py | 131 + sys/src/cmd/python/Demo/tix/samples/DirTree.py | 117 + sys/src/cmd/python/Demo/tix/samples/NoteBook.py | 119 + sys/src/cmd/python/Demo/tix/samples/OptMenu.py | 68 + sys/src/cmd/python/Demo/tix/samples/PanedWin.py | 98 + sys/src/cmd/python/Demo/tix/samples/PopMenu.py | 57 + sys/src/cmd/python/Demo/tix/samples/SHList1.py | 131 + sys/src/cmd/python/Demo/tix/samples/SHList2.py | 168 + sys/src/cmd/python/Demo/tix/samples/Tree.py | 80 + sys/src/cmd/python/Demo/tix/tixwidgets.py | 1003 ++ sys/src/cmd/python/Demo/tkinter/README | 10 + .../cmd/python/Demo/tkinter/guido/AttrDialog.py | 452 + sys/src/cmd/python/Demo/tkinter/guido/ManPage.py | 220 + .../cmd/python/Demo/tkinter/guido/MimeViewer.py | 143 + .../cmd/python/Demo/tkinter/guido/ShellWindow.py | 151 + sys/src/cmd/python/Demo/tkinter/guido/brownian.py | 50 + .../cmd/python/Demo/tkinter/guido/canvasevents.py | 244 + sys/src/cmd/python/Demo/tkinter/guido/dialog.py | 109 + sys/src/cmd/python/Demo/tkinter/guido/electrons.py | 91 + sys/src/cmd/python/Demo/tkinter/guido/hanoi.py | 154 + sys/src/cmd/python/Demo/tkinter/guido/hello.py | 17 + sys/src/cmd/python/Demo/tkinter/guido/imagedraw.py | 23 + sys/src/cmd/python/Demo/tkinter/guido/imageview.py | 12 + sys/src/cmd/python/Demo/tkinter/guido/kill.py | 98 + sys/src/cmd/python/Demo/tkinter/guido/listtree.py | 37 + sys/src/cmd/python/Demo/tkinter/guido/mbox.py | 285 + .../python/Demo/tkinter/guido/newmenubardemo.py | 47 + .../cmd/python/Demo/tkinter/guido/optionmenu.py | 27 + sys/src/cmd/python/Demo/tkinter/guido/paint.py | 60 + sys/src/cmd/python/Demo/tkinter/guido/rmt.py | 159 + sys/src/cmd/python/Demo/tkinter/guido/solitaire.py | 637 + sys/src/cmd/python/Demo/tkinter/guido/sortvisu.py | 634 + sys/src/cmd/python/Demo/tkinter/guido/ss1.py | 845 + sys/src/cmd/python/Demo/tkinter/guido/svkill.py | 128 + sys/src/cmd/python/Demo/tkinter/guido/switch.py | 55 + sys/src/cmd/python/Demo/tkinter/guido/tkman.py | 267 + sys/src/cmd/python/Demo/tkinter/guido/wish.py | 27 + .../cmd/python/Demo/tkinter/matt/00-HELLO-WORLD.py | 27 + sys/src/cmd/python/Demo/tkinter/matt/README | 30 + .../python/Demo/tkinter/matt/animation-simple.py | 35 + .../Demo/tkinter/matt/animation-w-velocity-ctrl.py | 44 + .../Demo/tkinter/matt/bind-w-mult-calls-p-type.py | 44 + .../python/Demo/tkinter/matt/canvas-demo-simple.py | 28 + .../python/Demo/tkinter/matt/canvas-gridding.py | 61 + .../Demo/tkinter/matt/canvas-moving-or-creating.py | 62 + .../Demo/tkinter/matt/canvas-moving-w-mouse.py | 55 + .../Demo/tkinter/matt/canvas-mult-item-sel.py | 78 + .../Demo/tkinter/matt/canvas-reading-tag-info.py | 49 + .../Demo/tkinter/matt/canvas-w-widget-draw-el.py | 36 + .../Demo/tkinter/matt/canvas-with-scrollbars.py | 60 + sys/src/cmd/python/Demo/tkinter/matt/dialog-box.py | 64 + .../cmd/python/Demo/tkinter/matt/entry-simple.py | 24 + .../tkinter/matt/entry-with-shared-variable.py | 46 + .../Demo/tkinter/matt/killing-window-w-wm.py | 42 + .../Demo/tkinter/matt/menu-all-types-of-entries.py | 244 + .../cmd/python/Demo/tkinter/matt/menu-simple.py | 112 + .../tkinter/matt/not-what-you-might-think-1.py | 28 + .../tkinter/matt/not-what-you-might-think-2.py | 30 + .../tkinter/matt/packer-and-placer-together.py | 41 + .../cmd/python/Demo/tkinter/matt/packer-simple.py | 32 + .../cmd/python/Demo/tkinter/matt/placer-simple.py | 39 + .../cmd/python/Demo/tkinter/matt/pong-demo-1.py | 54 + .../Demo/tkinter/matt/printing-coords-of-items.py | 61 + .../python/Demo/tkinter/matt/radiobutton-simple.py | 62 + .../Demo/tkinter/matt/rubber-band-box-demo-1.py | 58 + .../python/Demo/tkinter/matt/rubber-line-demo-1.py | 51 + .../cmd/python/Demo/tkinter/matt/slider-demo-1.py | 36 + .../Demo/tkinter/matt/subclass-existing-widgets.py | 28 + .../python/Demo/tkinter/matt/two-radio-groups.py | 110 + .../Demo/tkinter/matt/window-creation-more.py | 35 + .../Demo/tkinter/matt/window-creation-simple.py | 31 + .../tkinter/matt/window-creation-w-location.py | 45 + sys/src/cmd/python/Demo/xml/elem_count.py | 36 + sys/src/cmd/python/Demo/xml/roundtrip.py | 45 + sys/src/cmd/python/Demo/xml/rss2html.py | 91 + sys/src/cmd/python/Demo/zlib/minigzip.py | 133 + sys/src/cmd/python/Demo/zlib/zlibdemo.py | 48 + sys/src/cmd/python/Demo/zlib/zlibdemo.py.gz | Bin 0 -> 613 bytes sys/src/cmd/python/Doc/ACKS | 202 + sys/src/cmd/python/Doc/Makefile | 736 + sys/src/cmd/python/Doc/Makefile.deps | 386 + sys/src/cmd/python/Doc/README | 246 + sys/src/cmd/python/Doc/TODO | 74 + sys/src/cmd/python/Doc/api/abstract.tex | 1057 ++ sys/src/cmd/python/Doc/api/api.tex | 60 + sys/src/cmd/python/Doc/api/concrete.tex | 3203 ++++ sys/src/cmd/python/Doc/api/exceptions.tex | 442 + sys/src/cmd/python/Doc/api/init.tex | 884 ++ sys/src/cmd/python/Doc/api/intro.tex | 627 + sys/src/cmd/python/Doc/api/memory.tex | 204 + sys/src/cmd/python/Doc/api/newtypes.tex | 1780 +++ sys/src/cmd/python/Doc/api/refcounting.tex | 69 + sys/src/cmd/python/Doc/api/refcounts.dat | 1756 +++ sys/src/cmd/python/Doc/api/utilities.tex | 1023 ++ sys/src/cmd/python/Doc/api/veryhigh.tex | 287 + sys/src/cmd/python/Doc/commontex/boilerplate.tex | 9 + sys/src/cmd/python/Doc/commontex/copyright.tex | 14 + sys/src/cmd/python/Doc/commontex/license.tex | 673 + sys/src/cmd/python/Doc/commontex/reportingbugs.tex | 61 + sys/src/cmd/python/Doc/commontex/typestruct.h | 76 + sys/src/cmd/python/Doc/dist/dist.tex | 3795 +++++ sys/src/cmd/python/Doc/dist/sysconfig.tex | 113 + sys/src/cmd/python/Doc/doc/doc.tex | 2129 +++ sys/src/cmd/python/Doc/ext/building.tex | 143 + sys/src/cmd/python/Doc/ext/embedding.tex | 316 + sys/src/cmd/python/Doc/ext/ext.tex | 67 + sys/src/cmd/python/Doc/ext/extending.tex | 1390 ++ sys/src/cmd/python/Doc/ext/newtypes.tex | 1765 +++ sys/src/cmd/python/Doc/ext/noddy.c | 54 + sys/src/cmd/python/Doc/ext/noddy2.c | 190 + sys/src/cmd/python/Doc/ext/noddy3.c | 243 + sys/src/cmd/python/Doc/ext/noddy4.c | 224 + sys/src/cmd/python/Doc/ext/run-func.c | 68 + sys/src/cmd/python/Doc/ext/setup.py | 8 + sys/src/cmd/python/Doc/ext/shoddy.c | 91 + sys/src/cmd/python/Doc/ext/test.py | 213 + sys/src/cmd/python/Doc/ext/windows.tex | 320 + sys/src/cmd/python/Doc/howto/Makefile | 84 + sys/src/cmd/python/Doc/howto/TODO | 13 + sys/src/cmd/python/Doc/howto/advocacy.tex | 411 + sys/src/cmd/python/Doc/howto/curses.tex | 485 + sys/src/cmd/python/Doc/howto/doanddont.tex | 344 + sys/src/cmd/python/Doc/howto/regex.tex | 1463 ++ sys/src/cmd/python/Doc/howto/sockets.tex | 465 + sys/src/cmd/python/Doc/howto/unicode.rst | 766 + sys/src/cmd/python/Doc/howto/urllib2.rst | 598 + sys/src/cmd/python/Doc/html/about.dat | 24 + sys/src/cmd/python/Doc/html/about.html | 84 + sys/src/cmd/python/Doc/html/icons/blank.gif | Bin 0 -> 1958 bytes sys/src/cmd/python/Doc/html/icons/blank.png | Bin 0 -> 1031 bytes sys/src/cmd/python/Doc/html/icons/contents.gif | Bin 0 -> 438 bytes sys/src/cmd/python/Doc/html/icons/contents.png | Bin 0 -> 649 bytes sys/src/cmd/python/Doc/html/icons/index.gif | Bin 0 -> 289 bytes sys/src/cmd/python/Doc/html/icons/index.png | Bin 0 -> 529 bytes sys/src/cmd/python/Doc/html/icons/modules.gif | Bin 0 -> 385 bytes sys/src/cmd/python/Doc/html/icons/modules.png | Bin 0 -> 598 bytes sys/src/cmd/python/Doc/html/icons/next.gif | Bin 0 -> 253 bytes sys/src/cmd/python/Doc/html/icons/next.png | Bin 0 -> 511 bytes sys/src/cmd/python/Doc/html/icons/previous.gif | Bin 0 -> 252 bytes sys/src/cmd/python/Doc/html/icons/previous.png | Bin 0 -> 511 bytes sys/src/cmd/python/Doc/html/icons/pyfav.gif | Bin 0 -> 125 bytes sys/src/cmd/python/Doc/html/icons/pyfav.png | Bin 0 -> 240 bytes sys/src/cmd/python/Doc/html/icons/up.gif | Bin 0 -> 316 bytes sys/src/cmd/python/Doc/html/icons/up.png | Bin 0 -> 577 bytes sys/src/cmd/python/Doc/html/index.html.in | 140 + sys/src/cmd/python/Doc/html/stdabout.dat | 54 + sys/src/cmd/python/Doc/html/style.css | 243 + sys/src/cmd/python/Doc/info/Makefile | 82 + sys/src/cmd/python/Doc/info/README | 21 + sys/src/cmd/python/Doc/info/python.dir | 11 + sys/src/cmd/python/Doc/inst/inst.tex | 1112 ++ sys/src/cmd/python/Doc/lib/archiving.tex | 8 + sys/src/cmd/python/Doc/lib/asttable.tex | 283 + sys/src/cmd/python/Doc/lib/caseless.py | 60 + sys/src/cmd/python/Doc/lib/compiler.tex | 354 + sys/src/cmd/python/Doc/lib/custominterp.tex | 13 + sys/src/cmd/python/Doc/lib/datatypes.tex | 10 + sys/src/cmd/python/Doc/lib/development.tex | 13 + sys/src/cmd/python/Doc/lib/distutils.tex | 38 + sys/src/cmd/python/Doc/lib/email-dir.py | 115 + sys/src/cmd/python/Doc/lib/email-mime.py | 32 + sys/src/cmd/python/Doc/lib/email-simple.py | 25 + sys/src/cmd/python/Doc/lib/email-unpack.py | 68 + sys/src/cmd/python/Doc/lib/email.tex | 402 + sys/src/cmd/python/Doc/lib/emailcharsets.tex | 244 + sys/src/cmd/python/Doc/lib/emailencoders.tex | 47 + sys/src/cmd/python/Doc/lib/emailexc.tex | 87 + sys/src/cmd/python/Doc/lib/emailgenerator.tex | 133 + sys/src/cmd/python/Doc/lib/emailheaders.tex | 178 + sys/src/cmd/python/Doc/lib/emailiter.tex | 65 + sys/src/cmd/python/Doc/lib/emailmessage.tex | 561 + sys/src/cmd/python/Doc/lib/emailmimebase.tex | 186 + sys/src/cmd/python/Doc/lib/emailparser.tex | 208 + sys/src/cmd/python/Doc/lib/emailutil.tex | 157 + sys/src/cmd/python/Doc/lib/fileformats.tex | 7 + sys/src/cmd/python/Doc/lib/filesys.tex | 18 + sys/src/cmd/python/Doc/lib/frameworks.tex | 10 + sys/src/cmd/python/Doc/lib/i18n.tex | 11 + sys/src/cmd/python/Doc/lib/internet.tex | 13 + sys/src/cmd/python/Doc/lib/ipc.tex | 14 + sys/src/cmd/python/Doc/lib/language.tex | 10 + sys/src/cmd/python/Doc/lib/lib.tex | 487 + sys/src/cmd/python/Doc/lib/libaifc.tex | 202 + sys/src/cmd/python/Doc/lib/libal.tex | 181 + sys/src/cmd/python/Doc/lib/liballos.tex | 9 + sys/src/cmd/python/Doc/lib/libamoeba.tex | 132 + sys/src/cmd/python/Doc/lib/libanydbm.tex | 85 + sys/src/cmd/python/Doc/lib/libarray.tex | 241 + sys/src/cmd/python/Doc/lib/libascii.tex | 175 + sys/src/cmd/python/Doc/lib/libast.tex | 57 + sys/src/cmd/python/Doc/lib/libasynchat.tex | 254 + sys/src/cmd/python/Doc/lib/libasyncore.tex | 260 + sys/src/cmd/python/Doc/lib/libatexit.tex | 94 + sys/src/cmd/python/Doc/lib/libaudioop.tex | 259 + sys/src/cmd/python/Doc/lib/libbase64.tex | 169 + sys/src/cmd/python/Doc/lib/libbasehttp.tex | 245 + sys/src/cmd/python/Doc/lib/libbastion.tex | 57 + sys/src/cmd/python/Doc/lib/libbinascii.tex | 147 + sys/src/cmd/python/Doc/lib/libbinhex.tex | 55 + sys/src/cmd/python/Doc/lib/libbisect.tex | 84 + sys/src/cmd/python/Doc/lib/libbltin.tex | 44 + sys/src/cmd/python/Doc/lib/libbsddb.tex | 208 + sys/src/cmd/python/Doc/lib/libbz2.tex | 174 + sys/src/cmd/python/Doc/lib/libcalendar.tex | 304 + sys/src/cmd/python/Doc/lib/libcd.tex | 304 + sys/src/cmd/python/Doc/lib/libcfgparser.tex | 313 + sys/src/cmd/python/Doc/lib/libcgi.tex | 602 + sys/src/cmd/python/Doc/lib/libcgihttp.tex | 70 + sys/src/cmd/python/Doc/lib/libcgitb.tex | 67 + sys/src/cmd/python/Doc/lib/libchunk.tex | 111 + sys/src/cmd/python/Doc/lib/libcmath.tex | 142 + sys/src/cmd/python/Doc/lib/libcmd.tex | 198 + sys/src/cmd/python/Doc/lib/libcmp.tex | 36 + sys/src/cmd/python/Doc/lib/libcmpcache.tex | 21 + sys/src/cmd/python/Doc/lib/libcode.tex | 173 + sys/src/cmd/python/Doc/lib/libcodecs.tex | 1348 ++ sys/src/cmd/python/Doc/lib/libcodeop.tex | 103 + sys/src/cmd/python/Doc/lib/libcollections.tex | 341 + sys/src/cmd/python/Doc/lib/libcolorsys.tex | 54 + sys/src/cmd/python/Doc/lib/libcommands.tex | 62 + sys/src/cmd/python/Doc/lib/libcompileall.tex | 63 + sys/src/cmd/python/Doc/lib/libconsts.tex | 31 + sys/src/cmd/python/Doc/lib/libcontextlib.tex | 130 + sys/src/cmd/python/Doc/lib/libcookie.tex | 260 + sys/src/cmd/python/Doc/lib/libcookielib.tex | 720 + sys/src/cmd/python/Doc/lib/libcopy.tex | 97 + sys/src/cmd/python/Doc/lib/libcopyreg.tex | 40 + sys/src/cmd/python/Doc/lib/libcrypt.tex | 54 + sys/src/cmd/python/Doc/lib/libcrypto.tex | 19 + sys/src/cmd/python/Doc/lib/libcsv.tex | 538 + sys/src/cmd/python/Doc/lib/libctypes.tex | 2443 +++ sys/src/cmd/python/Doc/lib/libcurses.tex | 1395 ++ sys/src/cmd/python/Doc/lib/libcursespanel.tex | 96 + sys/src/cmd/python/Doc/lib/libdatetime.tex | 1441 ++ sys/src/cmd/python/Doc/lib/libdbhash.tex | 88 + sys/src/cmd/python/Doc/lib/libdbm.tex | 61 + sys/src/cmd/python/Doc/lib/libdecimal.tex | 1313 ++ sys/src/cmd/python/Doc/lib/libdifflib.tex | 704 + sys/src/cmd/python/Doc/lib/libdircache.tex | 49 + sys/src/cmd/python/Doc/lib/libdis.tex | 706 + sys/src/cmd/python/Doc/lib/libdl.tex | 101 + sys/src/cmd/python/Doc/lib/libdoctest.tex | 1949 +++ sys/src/cmd/python/Doc/lib/libdocxmlrpc.tex | 105 + sys/src/cmd/python/Doc/lib/libdumbdbm.tex | 63 + sys/src/cmd/python/Doc/lib/libdummythread.tex | 22 + sys/src/cmd/python/Doc/lib/libdummythreading.tex | 22 + sys/src/cmd/python/Doc/lib/liberrno.tex | 149 + sys/src/cmd/python/Doc/lib/libetree.tex | 356 + sys/src/cmd/python/Doc/lib/libexcs.tex | 466 + sys/src/cmd/python/Doc/lib/libfcntl.tex | 174 + sys/src/cmd/python/Doc/lib/libfilecmp.tex | 142 + sys/src/cmd/python/Doc/lib/libfileinput.tex | 192 + sys/src/cmd/python/Doc/lib/libfl.tex | 507 + sys/src/cmd/python/Doc/lib/libfm.tex | 94 + sys/src/cmd/python/Doc/lib/libfnmatch.tex | 86 + sys/src/cmd/python/Doc/lib/libformatter.tex | 329 + sys/src/cmd/python/Doc/lib/libfpectl.tex | 127 + sys/src/cmd/python/Doc/lib/libfpformat.tex | 54 + sys/src/cmd/python/Doc/lib/libftplib.tex | 288 + sys/src/cmd/python/Doc/lib/libfuncs.tex | 1321 ++ sys/src/cmd/python/Doc/lib/libfunctools.tex | 132 + sys/src/cmd/python/Doc/lib/libfuture.tex | 69 + sys/src/cmd/python/Doc/lib/libgc.tex | 196 + sys/src/cmd/python/Doc/lib/libgdbm.tex | 100 + sys/src/cmd/python/Doc/lib/libgetopt.tex | 154 + sys/src/cmd/python/Doc/lib/libgetpass.tex | 36 + sys/src/cmd/python/Doc/lib/libgettext.tex | 773 + sys/src/cmd/python/Doc/lib/libgl.tex | 224 + sys/src/cmd/python/Doc/lib/libglob.tex | 51 + sys/src/cmd/python/Doc/lib/libgopherlib.tex | 36 + sys/src/cmd/python/Doc/lib/libgrp.tex | 49 + sys/src/cmd/python/Doc/lib/libgzip.tex | 70 + sys/src/cmd/python/Doc/lib/libhashlib.tex | 114 + sys/src/cmd/python/Doc/lib/libheapq.tex | 214 + sys/src/cmd/python/Doc/lib/libhmac.tex | 54 + sys/src/cmd/python/Doc/lib/libhotshot.tex | 137 + sys/src/cmd/python/Doc/lib/libhtmllib.tex | 181 + sys/src/cmd/python/Doc/lib/libhtmlparser.tex | 169 + sys/src/cmd/python/Doc/lib/libhttplib.tex | 434 + sys/src/cmd/python/Doc/lib/libimageop.tex | 100 + sys/src/cmd/python/Doc/lib/libimaplib.tex | 507 + sys/src/cmd/python/Doc/lib/libimgfile.tex | 66 + sys/src/cmd/python/Doc/lib/libimghdr.tex | 60 + sys/src/cmd/python/Doc/lib/libimp.tex | 291 + sys/src/cmd/python/Doc/lib/libinspect.tex | 393 + sys/src/cmd/python/Doc/lib/libintro.tex | 53 + sys/src/cmd/python/Doc/lib/libitertools.tex | 546 + sys/src/cmd/python/Doc/lib/libjpeg.tex | 80 + sys/src/cmd/python/Doc/lib/libkeyword.tex | 20 + sys/src/cmd/python/Doc/lib/liblinecache.tex | 50 + sys/src/cmd/python/Doc/lib/liblocale.tex | 527 + sys/src/cmd/python/Doc/lib/liblogging.tex | 1729 +++ sys/src/cmd/python/Doc/lib/libmailbox.tex | 1444 ++ sys/src/cmd/python/Doc/lib/libmailcap.tex | 82 + sys/src/cmd/python/Doc/lib/libmain.tex | 16 + sys/src/cmd/python/Doc/lib/libmarshal.tex | 117 + sys/src/cmd/python/Doc/lib/libmath.tex | 209 + sys/src/cmd/python/Doc/lib/libmd5.tex | 92 + sys/src/cmd/python/Doc/lib/libmhlib.tex | 168 + sys/src/cmd/python/Doc/lib/libmimetools.tex | 120 + sys/src/cmd/python/Doc/lib/libmimetypes.tex | 226 + sys/src/cmd/python/Doc/lib/libmimewriter.tex | 80 + sys/src/cmd/python/Doc/lib/libmimify.tex | 94 + sys/src/cmd/python/Doc/lib/libmisc.tex | 7 + sys/src/cmd/python/Doc/lib/libmm.tex | 8 + sys/src/cmd/python/Doc/lib/libmmap.tex | 171 + sys/src/cmd/python/Doc/lib/libmodulefinder.tex | 51 + sys/src/cmd/python/Doc/lib/libmsilib.tex | 485 + sys/src/cmd/python/Doc/lib/libmsvcrt.tex | 109 + sys/src/cmd/python/Doc/lib/libmultifile.tex | 175 + sys/src/cmd/python/Doc/lib/libmutex.tex | 57 + sys/src/cmd/python/Doc/lib/libnetrc.tex | 68 + sys/src/cmd/python/Doc/lib/libnew.tex | 63 + sys/src/cmd/python/Doc/lib/libni.tex | 63 + sys/src/cmd/python/Doc/lib/libnis.tex | 63 + sys/src/cmd/python/Doc/lib/libnntplib.tex | 355 + sys/src/cmd/python/Doc/lib/libobjs.tex | 24 + sys/src/cmd/python/Doc/lib/liboperator.tex | 530 + sys/src/cmd/python/Doc/lib/liboptparse.tex | 1888 +++ sys/src/cmd/python/Doc/lib/libos.tex | 2006 +++ sys/src/cmd/python/Doc/lib/libossaudiodev.tex | 401 + sys/src/cmd/python/Doc/lib/libpanel.tex | 74 + sys/src/cmd/python/Doc/lib/libparser.tex | 711 + sys/src/cmd/python/Doc/lib/libpdb.tex | 456 + sys/src/cmd/python/Doc/lib/libpickle.tex | 888 ++ sys/src/cmd/python/Doc/lib/libpickletools.tex | 34 + sys/src/cmd/python/Doc/lib/libpipes.tex | 84 + sys/src/cmd/python/Doc/lib/libpkgutil.tex | 45 + sys/src/cmd/python/Doc/lib/libplatform.tex | 221 + sys/src/cmd/python/Doc/lib/libpopen2.tex | 189 + sys/src/cmd/python/Doc/lib/libpoplib.tex | 181 + sys/src/cmd/python/Doc/lib/libposix.tex | 97 + sys/src/cmd/python/Doc/lib/libposixfile.tex | 175 + sys/src/cmd/python/Doc/lib/libposixpath.tex | 281 + sys/src/cmd/python/Doc/lib/libpprint.tex | 210 + sys/src/cmd/python/Doc/lib/libprofile.tex | 722 + sys/src/cmd/python/Doc/lib/libpty.tex | 44 + sys/src/cmd/python/Doc/lib/libpwd.tex | 57 + sys/src/cmd/python/Doc/lib/libpyclbr.tex | 102 + sys/src/cmd/python/Doc/lib/libpycompile.tex | 53 + sys/src/cmd/python/Doc/lib/libpydoc.tex | 67 + sys/src/cmd/python/Doc/lib/libpyexpat.tex | 777 + sys/src/cmd/python/Doc/lib/libpython.tex | 8 + sys/src/cmd/python/Doc/lib/libqueue.tex | 145 + sys/src/cmd/python/Doc/lib/libquopri.tex | 61 + sys/src/cmd/python/Doc/lib/librandom.tex | 309 + sys/src/cmd/python/Doc/lib/libre.tex | 954 ++ sys/src/cmd/python/Doc/lib/libreadline.tex | 196 + sys/src/cmd/python/Doc/lib/librepr.tex | 133 + sys/src/cmd/python/Doc/lib/libresource.tex | 215 + sys/src/cmd/python/Doc/lib/librestricted.tex | 66 + sys/src/cmd/python/Doc/lib/librexec.tex | 275 + sys/src/cmd/python/Doc/lib/librfc822.tex | 336 + sys/src/cmd/python/Doc/lib/librgbimg.tex | 54 + sys/src/cmd/python/Doc/lib/librlcompleter.tex | 65 + sys/src/cmd/python/Doc/lib/librobotparser.tex | 66 + sys/src/cmd/python/Doc/lib/librunpy.tex | 74 + sys/src/cmd/python/Doc/lib/libsched.tex | 97 + sys/src/cmd/python/Doc/lib/libselect.tex | 132 + sys/src/cmd/python/Doc/lib/libsets.tex | 264 + sys/src/cmd/python/Doc/lib/libsgi.tex | 7 + sys/src/cmd/python/Doc/lib/libsgmllib.tex | 271 + sys/src/cmd/python/Doc/lib/libsha.tex | 83 + sys/src/cmd/python/Doc/lib/libshelve.tex | 174 + sys/src/cmd/python/Doc/lib/libshlex.tex | 274 + sys/src/cmd/python/Doc/lib/libshutil.tex | 151 + sys/src/cmd/python/Doc/lib/libsignal.tex | 174 + sys/src/cmd/python/Doc/lib/libsimplehttp.tex | 86 + sys/src/cmd/python/Doc/lib/libsimplexmlrpc.tex | 228 + sys/src/cmd/python/Doc/lib/libsite.tex | 88 + sys/src/cmd/python/Doc/lib/libsmtpd.tex | 63 + sys/src/cmd/python/Doc/lib/libsmtplib.tex | 295 + sys/src/cmd/python/Doc/lib/libsndhdr.tex | 41 + sys/src/cmd/python/Doc/lib/libsocket.tex | 910 ++ sys/src/cmd/python/Doc/lib/libsocksvr.tex | 293 + sys/src/cmd/python/Doc/lib/libsomeos.tex | 10 + sys/src/cmd/python/Doc/lib/libspwd.tex | 48 + sys/src/cmd/python/Doc/lib/libsqlite3.tex | 642 + sys/src/cmd/python/Doc/lib/libstat.tex | 157 + sys/src/cmd/python/Doc/lib/libstatvfs.tex | 55 + sys/src/cmd/python/Doc/lib/libstdtypes.tex | 2095 +++ sys/src/cmd/python/Doc/lib/libstdwin.tex | 832 + sys/src/cmd/python/Doc/lib/libstring.tex | 451 + sys/src/cmd/python/Doc/lib/libstringio.tex | 121 + sys/src/cmd/python/Doc/lib/libstringprep.tex | 136 + sys/src/cmd/python/Doc/lib/libstrings.tex | 10 + sys/src/cmd/python/Doc/lib/libstruct.tex | 256 + sys/src/cmd/python/Doc/lib/libsubprocess.tex | 402 + sys/src/cmd/python/Doc/lib/libsun.tex | 5 + sys/src/cmd/python/Doc/lib/libsunau.tex | 218 + sys/src/cmd/python/Doc/lib/libsunaudio.tex | 146 + sys/src/cmd/python/Doc/lib/libsymbol.tex | 30 + sys/src/cmd/python/Doc/lib/libsys.tex | 617 + sys/src/cmd/python/Doc/lib/libsyslog.tex | 76 + sys/src/cmd/python/Doc/lib/libtabnanny.tex | 62 + sys/src/cmd/python/Doc/lib/libtarfile.tex | 497 + sys/src/cmd/python/Doc/lib/libtelnetlib.tex | 215 + sys/src/cmd/python/Doc/lib/libtempfile.tex | 194 + sys/src/cmd/python/Doc/lib/libtermios.tex | 106 + sys/src/cmd/python/Doc/lib/libtest.tex | 278 + sys/src/cmd/python/Doc/lib/libtextwrap.tex | 181 + sys/src/cmd/python/Doc/lib/libthread.tex | 173 + sys/src/cmd/python/Doc/lib/libthreading.tex | 716 + sys/src/cmd/python/Doc/lib/libtime.tex | 461 + sys/src/cmd/python/Doc/lib/libtimeit.tex | 224 + sys/src/cmd/python/Doc/lib/libtoken.tex | 44 + sys/src/cmd/python/Doc/lib/libtokenize.tex | 119 + sys/src/cmd/python/Doc/lib/libtrace.tex | 125 + sys/src/cmd/python/Doc/lib/libtraceback.tex | 157 + sys/src/cmd/python/Doc/lib/libtty.tex | 34 + sys/src/cmd/python/Doc/lib/libturtle.tex | 268 + sys/src/cmd/python/Doc/lib/libtypes.tex | 215 + sys/src/cmd/python/Doc/lib/libundoc.tex | 113 + sys/src/cmd/python/Doc/lib/libunicodedata.tex | 160 + sys/src/cmd/python/Doc/lib/libunittest.tex | 974 ++ sys/src/cmd/python/Doc/lib/libunix.tex | 8 + sys/src/cmd/python/Doc/lib/liburllib.tex | 497 + sys/src/cmd/python/Doc/lib/liburllib2.tex | 872 ++ sys/src/cmd/python/Doc/lib/liburlparse.tex | 253 + sys/src/cmd/python/Doc/lib/libuser.tex | 71 + sys/src/cmd/python/Doc/lib/libuserdict.tex | 181 + sys/src/cmd/python/Doc/lib/libuu.tex | 58 + sys/src/cmd/python/Doc/lib/libuuid.tex | 233 + sys/src/cmd/python/Doc/lib/libwarnings.tex | 253 + sys/src/cmd/python/Doc/lib/libwave.tex | 169 + sys/src/cmd/python/Doc/lib/libweakref.tex | 336 + sys/src/cmd/python/Doc/lib/libwebbrowser.tex | 173 + sys/src/cmd/python/Doc/lib/libwhichdb.tex | 20 + sys/src/cmd/python/Doc/lib/libwinreg.tex | 414 + sys/src/cmd/python/Doc/lib/libwinsound.tex | 142 + sys/src/cmd/python/Doc/lib/libwsgiref.tex | 782 + sys/src/cmd/python/Doc/lib/libxdrlib.tex | 251 + sys/src/cmd/python/Doc/lib/libxmllib.tex | 287 + sys/src/cmd/python/Doc/lib/libxmlrpclib.tex | 383 + sys/src/cmd/python/Doc/lib/libzipfile.tex | 309 + sys/src/cmd/python/Doc/lib/libzipimport.tex | 133 + sys/src/cmd/python/Doc/lib/libzlib.tex | 197 + sys/src/cmd/python/Doc/lib/markup.tex | 29 + sys/src/cmd/python/Doc/lib/mimelib.tex | 65 + sys/src/cmd/python/Doc/lib/minidom-example.py | 64 + sys/src/cmd/python/Doc/lib/modules.tex | 9 + sys/src/cmd/python/Doc/lib/netdata.tex | 6 + sys/src/cmd/python/Doc/lib/numeric.tex | 13 + sys/src/cmd/python/Doc/lib/persistence.tex | 15 + sys/src/cmd/python/Doc/lib/required_1.py | 20 + sys/src/cmd/python/Doc/lib/required_2.py | 41 + .../cmd/python/Doc/lib/sqlite3/adapter_datetime.py | 14 + .../cmd/python/Doc/lib/sqlite3/adapter_point_1.py | 16 + .../cmd/python/Doc/lib/sqlite3/adapter_point_2.py | 17 + .../python/Doc/lib/sqlite3/collation_reverse.py | 15 + .../python/Doc/lib/sqlite3/complete_statement.py | 30 + sys/src/cmd/python/Doc/lib/sqlite3/connect_db_1.py | 3 + sys/src/cmd/python/Doc/lib/sqlite3/connect_db_2.py | 3 + .../cmd/python/Doc/lib/sqlite3/converter_point.py | 47 + sys/src/cmd/python/Doc/lib/sqlite3/countcursors.py | 15 + sys/src/cmd/python/Doc/lib/sqlite3/createdb.py | 28 + .../python/Doc/lib/sqlite3/execsql_fetchonerow.py | 17 + .../python/Doc/lib/sqlite3/execsql_printall_1.py | 13 + sys/src/cmd/python/Doc/lib/sqlite3/execute_1.py | 11 + sys/src/cmd/python/Doc/lib/sqlite3/execute_2.py | 12 + sys/src/cmd/python/Doc/lib/sqlite3/execute_3.py | 12 + .../cmd/python/Doc/lib/sqlite3/executemany_1.py | 24 + .../cmd/python/Doc/lib/sqlite3/executemany_2.py | 15 + .../cmd/python/Doc/lib/sqlite3/executescript.py | 24 + .../python/Doc/lib/sqlite3/insert_more_people.py | 16 + sys/src/cmd/python/Doc/lib/sqlite3/md5func.py | 11 + sys/src/cmd/python/Doc/lib/sqlite3/mysumaggr.py | 20 + .../cmd/python/Doc/lib/sqlite3/parse_colnames.py | 8 + .../python/Doc/lib/sqlite3/pysqlite_datetime.py | 20 + sys/src/cmd/python/Doc/lib/sqlite3/row_factory.py | 13 + sys/src/cmd/python/Doc/lib/sqlite3/rowclass.py | 12 + sys/src/cmd/python/Doc/lib/sqlite3/shared_cache.py | 6 + .../cmd/python/Doc/lib/sqlite3/shortcut_methods.py | 21 + .../python/Doc/lib/sqlite3/simple_tableprinter.py | 26 + sys/src/cmd/python/Doc/lib/sqlite3/text_factory.py | 42 + sys/src/cmd/python/Doc/lib/tkinter.tex | 1873 +++ sys/src/cmd/python/Doc/lib/tzinfo-examples.py | 139 + sys/src/cmd/python/Doc/lib/windows.tex | 8 + sys/src/cmd/python/Doc/lib/xmldom.tex | 928 ++ sys/src/cmd/python/Doc/lib/xmldomminidom.tex | 285 + sys/src/cmd/python/Doc/lib/xmldompulldom.tex | 61 + sys/src/cmd/python/Doc/lib/xmletree.tex | 27 + sys/src/cmd/python/Doc/lib/xmlsax.tex | 143 + sys/src/cmd/python/Doc/lib/xmlsaxhandler.tex | 381 + sys/src/cmd/python/Doc/lib/xmlsaxreader.tex | 351 + sys/src/cmd/python/Doc/lib/xmlsaxutils.tex | 81 + sys/src/cmd/python/Doc/mac/libaepack.tex | 82 + sys/src/cmd/python/Doc/mac/libaetools.tex | 83 + sys/src/cmd/python/Doc/mac/libaetypes.tex | 135 + sys/src/cmd/python/Doc/mac/libautogil.tex | 26 + sys/src/cmd/python/Doc/mac/libcolorpicker.tex | 23 + sys/src/cmd/python/Doc/mac/libframework.tex | 314 + sys/src/cmd/python/Doc/mac/libgensuitemodule.tex | 64 + sys/src/cmd/python/Doc/mac/libmac.tex | 29 + sys/src/cmd/python/Doc/mac/libmacfs.tex | 241 + sys/src/cmd/python/Doc/mac/libmacic.tex | 123 + sys/src/cmd/python/Doc/mac/libmacos.tex | 90 + sys/src/cmd/python/Doc/mac/libmacostools.tex | 105 + sys/src/cmd/python/Doc/mac/libmacui.tex | 266 + sys/src/cmd/python/Doc/mac/libminiae.tex | 65 + sys/src/cmd/python/Doc/mac/libscrap.tex | 42 + sys/src/cmd/python/Doc/mac/mac.tex | 89 + sys/src/cmd/python/Doc/mac/scripting.tex | 101 + sys/src/cmd/python/Doc/mac/toolbox.tex | 173 + sys/src/cmd/python/Doc/mac/undoc.tex | 97 + sys/src/cmd/python/Doc/mac/using.tex | 218 + sys/src/cmd/python/Doc/paper-a4/pypaper.sty | 17 + sys/src/cmd/python/Doc/perl/SynopsisTable.pm | 95 + sys/src/cmd/python/Doc/perl/distutils.perl | 21 + sys/src/cmd/python/Doc/perl/howto.perl | 12 + sys/src/cmd/python/Doc/perl/isilo.perl | 12 + sys/src/cmd/python/Doc/perl/l2hinit.perl | 801 + sys/src/cmd/python/Doc/perl/ltxmarkup.perl | 67 + sys/src/cmd/python/Doc/perl/manual.perl | 15 + sys/src/cmd/python/Doc/perl/python.perl | 2172 +++ sys/src/cmd/python/Doc/python-docs.txt | 183 + sys/src/cmd/python/Doc/ref/ref.tex | 68 + sys/src/cmd/python/Doc/ref/ref1.tex | 136 + sys/src/cmd/python/Doc/ref/ref2.tex | 731 + sys/src/cmd/python/Doc/ref/ref3.tex | 2225 +++ sys/src/cmd/python/Doc/ref/ref4.tex | 219 + sys/src/cmd/python/Doc/ref/ref5.tex | 1325 ++ sys/src/cmd/python/Doc/ref/ref6.tex | 928 ++ sys/src/cmd/python/Doc/ref/ref7.tex | 544 + sys/src/cmd/python/Doc/ref/ref8.tex | 112 + sys/src/cmd/python/Doc/ref/reswords.py | 23 + sys/src/cmd/python/Doc/templates/howto.tex | 112 + sys/src/cmd/python/Doc/templates/manual.tex | 89 + sys/src/cmd/python/Doc/templates/module.tex | 170 + sys/src/cmd/python/Doc/templates/whatsnewXY.tex | 149 + sys/src/cmd/python/Doc/tests/math.tex | 16 + sys/src/cmd/python/Doc/texinputs/distutils.sty | 33 + sys/src/cmd/python/Doc/texinputs/fancyhdr.sty | 329 + sys/src/cmd/python/Doc/texinputs/fncychap.sty | 433 + sys/src/cmd/python/Doc/texinputs/howto.cls | 109 + sys/src/cmd/python/Doc/texinputs/ltxmarkup.sty | 40 + sys/src/cmd/python/Doc/texinputs/manual.cls | 155 + sys/src/cmd/python/Doc/texinputs/pypaper.sty | 18 + sys/src/cmd/python/Doc/texinputs/python.ist | 11 + sys/src/cmd/python/Doc/texinputs/python.sty | 1327 ++ sys/src/cmd/python/Doc/texinputs/underscore.sty | 232 + sys/src/cmd/python/Doc/tools/anno-api.py | 71 + sys/src/cmd/python/Doc/tools/buildindex.py | 388 + sys/src/cmd/python/Doc/tools/checkargs.pm | 112 + sys/src/cmd/python/Doc/tools/cklatex | 26 + sys/src/cmd/python/Doc/tools/cmpcsyms | 157 + sys/src/cmd/python/Doc/tools/custlib.py | 78 + sys/src/cmd/python/Doc/tools/findcsyms | 136 + sys/src/cmd/python/Doc/tools/findmodrefs | 63 + sys/src/cmd/python/Doc/tools/findsyms | 128 + sys/src/cmd/python/Doc/tools/fix_hack | 2 + sys/src/cmd/python/Doc/tools/fix_libaux.sed | 3 + sys/src/cmd/python/Doc/tools/fixinfo.el | 15 + sys/src/cmd/python/Doc/tools/getpagecounts | 97 + sys/src/cmd/python/Doc/tools/getversioninfo | 71 + sys/src/cmd/python/Doc/tools/html2texi.pl | 1750 +++ sys/src/cmd/python/Doc/tools/indfix.py | 100 + sys/src/cmd/python/Doc/tools/keywords.py | 19 + sys/src/cmd/python/Doc/tools/listmodules | 183 + sys/src/cmd/python/Doc/tools/listmodules.py | 126 + sys/src/cmd/python/Doc/tools/makesec.sh | 129 + sys/src/cmd/python/Doc/tools/mkackshtml | 66 + sys/src/cmd/python/Doc/tools/mkhowto | 659 + sys/src/cmd/python/Doc/tools/mkinfo | 65 + sys/src/cmd/python/Doc/tools/mkmodindex | 158 + sys/src/cmd/python/Doc/tools/mkpkglist | 85 + sys/src/cmd/python/Doc/tools/mksourcepkg | 164 + sys/src/cmd/python/Doc/tools/node2label.pl | 71 + sys/src/cmd/python/Doc/tools/prechm.py | 519 + sys/src/cmd/python/Doc/tools/push-docs.sh | 138 + sys/src/cmd/python/Doc/tools/py2texi.el | 970 ++ sys/src/cmd/python/Doc/tools/refcounts.py | 98 + sys/src/cmd/python/Doc/tools/rewrite.py | 54 + sys/src/cmd/python/Doc/tools/sgmlconv/Makefile | 67 + sys/src/cmd/python/Doc/tools/sgmlconv/README | 58 + .../cmd/python/Doc/tools/sgmlconv/conversion.xml | 914 ++ sys/src/cmd/python/Doc/tools/sgmlconv/docfixer.py | 1073 ++ sys/src/cmd/python/Doc/tools/sgmlconv/esis2sgml.py | 264 + sys/src/cmd/python/Doc/tools/sgmlconv/esistools.py | 312 + .../cmd/python/Doc/tools/sgmlconv/latex2esis.py | 565 + sys/src/cmd/python/Doc/tools/sgmlconv/make.rules | 48 + sys/src/cmd/python/Doc/tools/support.py | 202 + sys/src/cmd/python/Doc/tools/toc2bkm.py | 160 + sys/src/cmd/python/Doc/tools/undoc_symbols.py | 94 + sys/src/cmd/python/Doc/tools/update-docs.sh | 31 + sys/src/cmd/python/Doc/tools/whichlibs | 2 + sys/src/cmd/python/Doc/tut/glossary.tex | 352 + sys/src/cmd/python/Doc/tut/tut.tex | 5907 +++++++ sys/src/cmd/python/Doc/whatsnew/Makefile | 3 + sys/src/cmd/python/Doc/whatsnew/whatsnew20.tex | 1337 ++ sys/src/cmd/python/Doc/whatsnew/whatsnew21.tex | 868 ++ sys/src/cmd/python/Doc/whatsnew/whatsnew22.tex | 1466 ++ sys/src/cmd/python/Doc/whatsnew/whatsnew23.tex | 2380 +++ sys/src/cmd/python/Doc/whatsnew/whatsnew24.tex | 1757 +++ sys/src/cmd/python/Doc/whatsnew/whatsnew25.tex | 2530 +++ sys/src/cmd/python/Extra/dummy.c | 6 + sys/src/cmd/python/Extra/mercurial/base85.c | 155 + sys/src/cmd/python/Extra/mercurial/bdiff.c | 401 + sys/src/cmd/python/Extra/mercurial/diffhelpers.c | 156 + sys/src/cmd/python/Extra/mercurial/mpatch.c | 444 + sys/src/cmd/python/Extra/mercurial/osutil.c | 534 + sys/src/cmd/python/Extra/mercurial/parsers.c | 435 + sys/src/cmd/python/Extra/mkfile | 16 + sys/src/cmd/python/Grammar/Grammar | 148 + sys/src/cmd/python/Include/Python-ast.h | 501 + sys/src/cmd/python/Include/Python.h | 173 + sys/src/cmd/python/Include/abstract.h | 1276 ++ sys/src/cmd/python/Include/asdl.h | 45 + sys/src/cmd/python/Include/ast.h | 13 + sys/src/cmd/python/Include/bitset.h | 32 + sys/src/cmd/python/Include/boolobject.h | 36 + sys/src/cmd/python/Include/bufferobject.h | 33 + sys/src/cmd/python/Include/cStringIO.h | 70 + sys/src/cmd/python/Include/cellobject.h | 28 + sys/src/cmd/python/Include/ceval.h | 157 + sys/src/cmd/python/Include/classobject.h | 81 + sys/src/cmd/python/Include/cobject.h | 54 + sys/src/cmd/python/Include/code.h | 94 + sys/src/cmd/python/Include/codecs.h | 167 + sys/src/cmd/python/Include/compile.h | 39 + sys/src/cmd/python/Include/complexobject.h | 58 + sys/src/cmd/python/Include/datetime.h | 245 + sys/src/cmd/python/Include/descrobject.h | 91 + sys/src/cmd/python/Include/dictobject.h | 141 + sys/src/cmd/python/Include/enumobject.h | 17 + sys/src/cmd/python/Include/errcode.h | 36 + sys/src/cmd/python/Include/eval.h | 25 + sys/src/cmd/python/Include/fileobject.h | 63 + sys/src/cmd/python/Include/floatobject.h | 100 + sys/src/cmd/python/Include/frameobject.h | 81 + sys/src/cmd/python/Include/funcobject.h | 76 + sys/src/cmd/python/Include/genobject.h | 37 + sys/src/cmd/python/Include/graminit.h | 84 + sys/src/cmd/python/Include/grammar.h | 93 + sys/src/cmd/python/Include/import.h | 64 + sys/src/cmd/python/Include/intobject.h | 64 + sys/src/cmd/python/Include/intrcheck.h | 15 + sys/src/cmd/python/Include/iterobject.h | 23 + sys/src/cmd/python/Include/listobject.h | 67 + sys/src/cmd/python/Include/longintrepr.h | 63 + sys/src/cmd/python/Include/longobject.h | 114 + sys/src/cmd/python/Include/marshal.h | 25 + sys/src/cmd/python/Include/metagrammar.h | 18 + sys/src/cmd/python/Include/methodobject.h | 91 + sys/src/cmd/python/Include/modsupport.h | 133 + sys/src/cmd/python/Include/moduleobject.h | 24 + sys/src/cmd/python/Include/node.h | 40 + sys/src/cmd/python/Include/object.h | 868 ++ sys/src/cmd/python/Include/objimpl.h | 336 + sys/src/cmd/python/Include/opcode.h | 152 + sys/src/cmd/python/Include/osdefs.h | 55 + sys/src/cmd/python/Include/parsetok.h | 50 + sys/src/cmd/python/Include/patchlevel.h | 40 + sys/src/cmd/python/Include/pgen.h | 18 + sys/src/cmd/python/Include/pgenheaders.h | 42 + sys/src/cmd/python/Include/py_curses.h | 176 + sys/src/cmd/python/Include/pyarena.h | 62 + sys/src/cmd/python/Include/pydebug.h | 34 + sys/src/cmd/python/Include/pyerrors.h | 334 + sys/src/cmd/python/Include/pyexpat.h | 47 + sys/src/cmd/python/Include/pyfpe.h | 176 + sys/src/cmd/python/Include/pygetopt.h | 17 + sys/src/cmd/python/Include/pymactoolbox.h | 189 + sys/src/cmd/python/Include/pymem.h | 105 + sys/src/cmd/python/Include/pyport.h | 771 + sys/src/cmd/python/Include/pystate.h | 195 + sys/src/cmd/python/Include/pystrtod.h | 18 + sys/src/cmd/python/Include/pythonrun.h | 171 + sys/src/cmd/python/Include/pythread.h | 47 + sys/src/cmd/python/Include/rangeobject.h | 28 + sys/src/cmd/python/Include/setobject.h | 93 + sys/src/cmd/python/Include/sliceobject.h | 43 + sys/src/cmd/python/Include/stringobject.h | 183 + sys/src/cmd/python/Include/structmember.h | 93 + sys/src/cmd/python/Include/structseq.h | 41 + sys/src/cmd/python/Include/symtable.h | 103 + sys/src/cmd/python/Include/sysmodule.h | 30 + sys/src/cmd/python/Include/timefuncs.h | 23 + sys/src/cmd/python/Include/token.h | 83 + sys/src/cmd/python/Include/traceback.h | 30 + sys/src/cmd/python/Include/tupleobject.h | 57 + sys/src/cmd/python/Include/ucnhash.h | 31 + sys/src/cmd/python/Include/unicodeobject.h | 1265 ++ sys/src/cmd/python/Include/weakrefobject.h | 75 + sys/src/cmd/python/LICENSE | 270 + sys/src/cmd/python/Misc/ACKS | 698 + sys/src/cmd/python/Misc/AIX-NOTES | 155 + sys/src/cmd/python/Misc/BeOS-NOTES | 43 + sys/src/cmd/python/Misc/BeOS-setup.py | 574 + sys/src/cmd/python/Misc/HISTORY | 15303 +++++++++++++++++++ sys/src/cmd/python/Misc/NEWS | 2782 ++++ sys/src/cmd/python/Misc/NEWS.help | 73 + sys/src/cmd/python/Misc/PURIFY.README | 97 + sys/src/cmd/python/Misc/Porting | 42 + sys/src/cmd/python/Misc/README | 33 + sys/src/cmd/python/Misc/README.OpenBSD | 38 + sys/src/cmd/python/Misc/README.coverity | 22 + sys/src/cmd/python/Misc/README.klocwork | 30 + sys/src/cmd/python/Misc/README.valgrind | 97 + sys/src/cmd/python/Misc/RFD | 114 + sys/src/cmd/python/Misc/RPM/README | 16 + sys/src/cmd/python/Misc/RPM/python-2.5.spec | 395 + sys/src/cmd/python/Misc/SpecialBuilds.txt | 261 + sys/src/cmd/python/Misc/Vim/python.vim | 147 + sys/src/cmd/python/Misc/Vim/syntax_test.py | 63 + sys/src/cmd/python/Misc/Vim/vim_syntax.py | 226 + sys/src/cmd/python/Misc/Vim/vimrc | 95 + sys/src/cmd/python/Misc/build.sh | 227 + sys/src/cmd/python/Misc/cheatsheet | 2279 +++ sys/src/cmd/python/Misc/developers.txt | 141 + sys/src/cmd/python/Misc/find_recursionlimit.py | 87 + sys/src/cmd/python/Misc/gdbinit | 140 + sys/src/cmd/python/Misc/indent.pro | 15 + sys/src/cmd/python/Misc/pymemcompat.h | 85 + sys/src/cmd/python/Misc/python-config.in | 53 + sys/src/cmd/python/Misc/python-mode.el | 3768 +++++ sys/src/cmd/python/Misc/python.man | 397 + sys/src/cmd/python/Misc/setuid-prog.c | 176 + sys/src/cmd/python/Misc/valgrind-python.supp | 349 + sys/src/cmd/python/Misc/vgrindefs | 10 + sys/src/cmd/python/Modules/Setup | 488 + sys/src/cmd/python/Modules/Setup.config | 13 + sys/src/cmd/python/Modules/Setup.config.in | 13 + sys/src/cmd/python/Modules/Setup.dist | 487 + sys/src/cmd/python/Modules/Setup.local | 1 + sys/src/cmd/python/Modules/_bisectmodule.c | 235 + sys/src/cmd/python/Modules/_bsddb.c | 6047 ++++++++ sys/src/cmd/python/Modules/_codecsmodule.c | 934 ++ sys/src/cmd/python/Modules/_csv.c | 1604 ++ sys/src/cmd/python/Modules/_ctypes/_ctypes.c | 4859 ++++++ sys/src/cmd/python/Modules/_ctypes/_ctypes_test.c | 548 + sys/src/cmd/python/Modules/_ctypes/_ctypes_test.h | 1 + sys/src/cmd/python/Modules/_ctypes/callbacks.c | 499 + sys/src/cmd/python/Modules/_ctypes/callproc.c | 1581 ++ sys/src/cmd/python/Modules/_ctypes/cfield.c | 1668 ++ sys/src/cmd/python/Modules/_ctypes/ctypes.h | 407 + sys/src/cmd/python/Modules/_ctypes/ctypes_dlfcn.h | 31 + sys/src/cmd/python/Modules/_ctypes/darwin/LICENSE | 31 + sys/src/cmd/python/Modules/_ctypes/darwin/README | 95 + .../python/Modules/_ctypes/darwin/README.ctypes | 11 + sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn.h | 84 + .../python/Modules/_ctypes/darwin/dlfcn_simple.c | 272 + sys/src/cmd/python/Modules/_ctypes/libffi/LICENSE | 20 + sys/src/cmd/python/Modules/_ctypes/libffi/README | 500 + .../cmd/python/Modules/_ctypes/libffi/aclocal.m4 | 92 + .../cmd/python/Modules/_ctypes/libffi/config.guess | 1453 ++ .../cmd/python/Modules/_ctypes/libffi/config.sub | 1569 ++ .../cmd/python/Modules/_ctypes/libffi/configure | 6864 +++++++++ .../cmd/python/Modules/_ctypes/libffi/configure.ac | 243 + .../python/Modules/_ctypes/libffi/fficonfig.h.in | 148 + .../python/Modules/_ctypes/libffi/fficonfig.py.in | 45 + .../python/Modules/_ctypes/libffi/include/ffi.h.in | 313 + .../Modules/_ctypes/libffi/include/ffi_common.h | 95 + .../cmd/python/Modules/_ctypes/libffi/install-sh | 294 + .../python/Modules/_ctypes/libffi/src/alpha/ffi.c | 252 + .../Modules/_ctypes/libffi/src/alpha/ffitarget.h | 48 + .../python/Modules/_ctypes/libffi/src/alpha/osf.S | 359 + .../python/Modules/_ctypes/libffi/src/arm/ffi.c | 185 + .../Modules/_ctypes/libffi/src/arm/ffitarget.h | 47 + .../python/Modules/_ctypes/libffi/src/arm/sysv.S | 209 + .../python/Modules/_ctypes/libffi/src/cris/ffi.c | 381 + .../Modules/_ctypes/libffi/src/cris/ffitarget.h | 50 + .../python/Modules/_ctypes/libffi/src/cris/sysv.S | 215 + .../Modules/_ctypes/libffi/src/darwin/ffitarget.h | 25 + .../python/Modules/_ctypes/libffi/src/frv/eabi.S | 130 + .../python/Modules/_ctypes/libffi/src/frv/ffi.c | 287 + .../Modules/_ctypes/libffi/src/frv/ffitarget.h | 60 + .../python/Modules/_ctypes/libffi/src/ia64/ffi.c | 562 + .../Modules/_ctypes/libffi/src/ia64/ffitarget.h | 49 + .../Modules/_ctypes/libffi/src/ia64/ia64_flags.h | 39 + .../python/Modules/_ctypes/libffi/src/ia64/unix.S | 555 + .../python/Modules/_ctypes/libffi/src/m32r/ffi.c | 247 + .../Modules/_ctypes/libffi/src/m32r/ffitarget.h | 48 + .../python/Modules/_ctypes/libffi/src/m32r/sysv.S | 121 + .../python/Modules/_ctypes/libffi/src/m68k/ffi.c | 176 + .../Modules/_ctypes/libffi/src/m68k/ffitarget.h | 47 + .../python/Modules/_ctypes/libffi/src/m68k/sysv.S | 97 + .../python/Modules/_ctypes/libffi/src/mips/ffi.c | 648 + .../Modules/_ctypes/libffi/src/mips/ffitarget.h | 167 + .../python/Modules/_ctypes/libffi/src/mips/n32.S | 320 + .../python/Modules/_ctypes/libffi/src/mips/o32.S | 377 + .../cmd/python/Modules/_ctypes/libffi/src/pa/ffi.c | 625 + .../Modules/_ctypes/libffi/src/pa/ffitarget.h | 59 + .../python/Modules/_ctypes/libffi/src/pa/linux.S | 307 + .../Modules/_ctypes/libffi/src/powerpc/aix.S | 225 + .../_ctypes/libffi/src/powerpc/aix_closure.S | 247 + .../Modules/_ctypes/libffi/src/powerpc/asm.h | 125 + .../Modules/_ctypes/libffi/src/powerpc/darwin.S | 247 + .../_ctypes/libffi/src/powerpc/darwin_closure.S | 319 + .../Modules/_ctypes/libffi/src/powerpc/ffi.c | 1249 ++ .../_ctypes/libffi/src/powerpc/ffi_darwin.c | 771 + .../Modules/_ctypes/libffi/src/powerpc/ffitarget.h | 100 + .../Modules/_ctypes/libffi/src/powerpc/linux64.S | 180 + .../_ctypes/libffi/src/powerpc/linux64_closure.S | 206 + .../_ctypes/libffi/src/powerpc/ppc_closure.S | 323 + .../Modules/_ctypes/libffi/src/powerpc/sysv.S | 217 + .../python/Modules/_ctypes/libffi/src/prep_cif.c | 210 + .../python/Modules/_ctypes/libffi/src/s390/ffi.c | 751 + .../Modules/_ctypes/libffi/src/s390/ffitarget.h | 59 + .../python/Modules/_ctypes/libffi/src/s390/sysv.S | 429 + .../cmd/python/Modules/_ctypes/libffi/src/sh/ffi.c | 728 + .../Modules/_ctypes/libffi/src/sh/ffitarget.h | 48 + .../python/Modules/_ctypes/libffi/src/sh/sysv.S | 845 + .../python/Modules/_ctypes/libffi/src/sh64/ffi.c | 451 + .../Modules/_ctypes/libffi/src/sh64/ffitarget.h | 52 + .../python/Modules/_ctypes/libffi/src/sh64/sysv.S | 525 + .../python/Modules/_ctypes/libffi/src/sparc/ffi.c | 608 + .../Modules/_ctypes/libffi/src/sparc/ffitarget.h | 65 + .../python/Modules/_ctypes/libffi/src/sparc/v8.S | 267 + .../python/Modules/_ctypes/libffi/src/sparc/v9.S | 302 + .../python/Modules/_ctypes/libffi/src/x86/darwin.S | 243 + .../python/Modules/_ctypes/libffi/src/x86/ffi.c | 469 + .../python/Modules/_ctypes/libffi/src/x86/ffi64.c | 569 + .../Modules/_ctypes/libffi/src/x86/ffi_darwin.c | 594 + .../Modules/_ctypes/libffi/src/x86/ffitarget.h | 81 + .../python/Modules/_ctypes/libffi/src/x86/sysv.S | 382 + .../python/Modules/_ctypes/libffi/src/x86/unix64.S | 412 + .../python/Modules/_ctypes/libffi/src/x86/win32.S | 373 + .../Modules/_ctypes/libffi_arm_wince/debug.c | 59 + .../python/Modules/_ctypes/libffi_arm_wince/ffi.c | 310 + .../python/Modules/_ctypes/libffi_arm_wince/ffi.h | 317 + .../Modules/_ctypes/libffi_arm_wince/ffi_common.h | 111 + .../Modules/_ctypes/libffi_arm_wince/fficonfig.h | 152 + .../Modules/_ctypes/libffi_arm_wince/ffitarget.h | 49 + .../Modules/_ctypes/libffi_arm_wince/prep_cif.c | 175 + .../Modules/_ctypes/libffi_arm_wince/sysv.asm | 228 + .../cmd/python/Modules/_ctypes/libffi_msvc/LICENSE | 20 + .../cmd/python/Modules/_ctypes/libffi_msvc/README | 500 + .../Modules/_ctypes/libffi_msvc/README.ctypes | 7 + .../cmd/python/Modules/_ctypes/libffi_msvc/ffi.c | 394 + .../cmd/python/Modules/_ctypes/libffi_msvc/ffi.h | 317 + .../Modules/_ctypes/libffi_msvc/ffi_common.h | 77 + .../python/Modules/_ctypes/libffi_msvc/fficonfig.h | 96 + .../python/Modules/_ctypes/libffi_msvc/ffitarget.h | 79 + .../python/Modules/_ctypes/libffi_msvc/prep_cif.c | 175 + .../cmd/python/Modules/_ctypes/libffi_msvc/types.c | 104 + .../cmd/python/Modules/_ctypes/libffi_msvc/win32.S | 243 + .../cmd/python/Modules/_ctypes/libffi_msvc/win32.c | 267 + .../cmd/python/Modules/_ctypes/malloc_closure.c | 110 + sys/src/cmd/python/Modules/_ctypes/stgdict.c | 494 + sys/src/cmd/python/Modules/_curses_panel.c | 480 + sys/src/cmd/python/Modules/_cursesmodule.c | 2760 ++++ sys/src/cmd/python/Modules/_elementtree.c | 2815 ++++ sys/src/cmd/python/Modules/_functoolsmodule.c | 277 + sys/src/cmd/python/Modules/_hashopenssl.c | 487 + sys/src/cmd/python/Modules/_heapqmodule.c | 619 + sys/src/cmd/python/Modules/_hotshot.c | 1647 ++ sys/src/cmd/python/Modules/_localemodule.c | 788 + sys/src/cmd/python/Modules/_lsprof.c | 875 ++ sys/src/cmd/python/Modules/_randommodule.c | 580 + sys/src/cmd/python/Modules/_sqlite/cache.c | 375 + sys/src/cmd/python/Modules/_sqlite/cache.h | 73 + sys/src/cmd/python/Modules/_sqlite/connection.c | 1255 ++ sys/src/cmd/python/Modules/_sqlite/connection.h | 129 + sys/src/cmd/python/Modules/_sqlite/cursor.c | 1057 ++ sys/src/cmd/python/Modules/_sqlite/cursor.h | 71 + .../cmd/python/Modules/_sqlite/microprotocols.c | 142 + .../cmd/python/Modules/_sqlite/microprotocols.h | 59 + sys/src/cmd/python/Modules/_sqlite/module.c | 409 + sys/src/cmd/python/Modules/_sqlite/module.h | 57 + .../cmd/python/Modules/_sqlite/prepare_protocol.c | 84 + .../cmd/python/Modules/_sqlite/prepare_protocol.h | 41 + sys/src/cmd/python/Modules/_sqlite/row.c | 202 + sys/src/cmd/python/Modules/_sqlite/row.h | 39 + sys/src/cmd/python/Modules/_sqlite/sqlitecompat.h | 34 + sys/src/cmd/python/Modules/_sqlite/statement.c | 432 + sys/src/cmd/python/Modules/_sqlite/statement.h | 59 + sys/src/cmd/python/Modules/_sqlite/util.c | 96 + sys/src/cmd/python/Modules/_sqlite/util.h | 38 + sys/src/cmd/python/Modules/_sre.c | 3429 +++++ sys/src/cmd/python/Modules/_ssl.c | 726 + sys/src/cmd/python/Modules/_struct.c | 1896 +++ sys/src/cmd/python/Modules/_testcapimodule.c | 898 ++ sys/src/cmd/python/Modules/_tkinter.c | 3165 ++++ sys/src/cmd/python/Modules/_typesmodule.c | 94 + sys/src/cmd/python/Modules/_weakref.c | 112 + sys/src/cmd/python/Modules/addrinfo.h | 176 + sys/src/cmd/python/Modules/almodule.c | 3226 ++++ sys/src/cmd/python/Modules/ar_beos | 73 + sys/src/cmd/python/Modules/arraymodule.c | 2141 +++ sys/src/cmd/python/Modules/audioop.c | 1612 ++ sys/src/cmd/python/Modules/binascii.c | 1350 ++ sys/src/cmd/python/Modules/bsddbmodule.c | 858 ++ sys/src/cmd/python/Modules/bz2module.c | 2230 +++ sys/src/cmd/python/Modules/cPickle.c | 5757 +++++++ sys/src/cmd/python/Modules/cStringIO.c | 745 + sys/src/cmd/python/Modules/cdmodule.c | 796 + sys/src/cmd/python/Modules/cgen.py | 520 + sys/src/cmd/python/Modules/cgensupport.c | 310 + sys/src/cmd/python/Modules/cgensupport.h | 64 + sys/src/cmd/python/Modules/cjkcodecs/README | 79 + sys/src/cmd/python/Modules/cjkcodecs/_codecs_cn.c | 443 + sys/src/cmd/python/Modules/cjkcodecs/_codecs_hk.c | 143 + .../cmd/python/Modules/cjkcodecs/_codecs_iso2022.c | 1131 ++ sys/src/cmd/python/Modules/cjkcodecs/_codecs_jp.c | 731 + sys/src/cmd/python/Modules/cjkcodecs/_codecs_kr.c | 355 + sys/src/cmd/python/Modules/cjkcodecs/_codecs_tw.c | 132 + .../cmd/python/Modules/cjkcodecs/alg_jisx0201.h | 24 + sys/src/cmd/python/Modules/cjkcodecs/cjkcodecs.h | 398 + .../python/Modules/cjkcodecs/emu_jisx0213_2000.h | 43 + sys/src/cmd/python/Modules/cjkcodecs/mappings_cn.h | 4103 +++++ sys/src/cmd/python/Modules/cjkcodecs/mappings_hk.h | 2340 +++ .../Modules/cjkcodecs/mappings_jisx0213_pair.h | 59 + sys/src/cmd/python/Modules/cjkcodecs/mappings_jp.h | 4765 ++++++ sys/src/cmd/python/Modules/cjkcodecs/mappings_kr.h | 3251 ++++ sys/src/cmd/python/Modules/cjkcodecs/mappings_tw.h | 2633 ++++ .../cmd/python/Modules/cjkcodecs/multibytecodec.c | 1793 +++ .../cmd/python/Modules/cjkcodecs/multibytecodec.h | 138 + sys/src/cmd/python/Modules/clmodule.c | 2559 ++++ sys/src/cmd/python/Modules/cmathmodule.c | 426 + sys/src/cmd/python/Modules/collectionsmodule.c | 1370 ++ sys/src/cmd/python/Modules/config | 54 + sys/src/cmd/python/Modules/config.c.in | 66 + sys/src/cmd/python/Modules/cryptmodule.c | 49 + sys/src/cmd/python/Modules/cstubs | 1364 ++ sys/src/cmd/python/Modules/datetimemodule.c | 4988 ++++++ sys/src/cmd/python/Modules/dbmmodule.c | 370 + sys/src/cmd/python/Modules/dlmodule.c | 278 + sys/src/cmd/python/Modules/errnomodule.c | 788 + sys/src/cmd/python/Modules/expat/amigaconfig.h | 96 + sys/src/cmd/python/Modules/expat/ascii.h | 85 + sys/src/cmd/python/Modules/expat/asciitab.h | 36 + sys/src/cmd/python/Modules/expat/expat.h | 1013 ++ sys/src/cmd/python/Modules/expat/expat_config.h | 19 + sys/src/cmd/python/Modules/expat/expat_external.h | 119 + sys/src/cmd/python/Modules/expat/iasciitab.h | 37 + sys/src/cmd/python/Modules/expat/internal.h | 73 + sys/src/cmd/python/Modules/expat/latin1tab.h | 36 + sys/src/cmd/python/Modules/expat/macconfig.h | 53 + sys/src/cmd/python/Modules/expat/nametab.h | 150 + sys/src/cmd/python/Modules/expat/pyexpatns.h | 124 + sys/src/cmd/python/Modules/expat/utf8tab.h | 37 + sys/src/cmd/python/Modules/expat/winconfig.h | 30 + sys/src/cmd/python/Modules/expat/xmlparse.c | 6268 ++++++++ sys/src/cmd/python/Modules/expat/xmlrole.c | 1330 ++ sys/src/cmd/python/Modules/expat/xmlrole.h | 114 + sys/src/cmd/python/Modules/expat/xmltok.c | 1639 ++ sys/src/cmd/python/Modules/expat/xmltok.h | 316 + sys/src/cmd/python/Modules/expat/xmltok_impl.c | 1779 +++ sys/src/cmd/python/Modules/expat/xmltok_impl.h | 46 + sys/src/cmd/python/Modules/expat/xmltok_ns.c | 106 + sys/src/cmd/python/Modules/fcntlmodule.c | 607 + sys/src/cmd/python/Modules/flmodule.c | 2139 +++ sys/src/cmd/python/Modules/fmmodule.c | 264 + sys/src/cmd/python/Modules/fpectlmodule.c | 303 + sys/src/cmd/python/Modules/fpetestmodule.c | 186 + sys/src/cmd/python/Modules/gc_weakref.txt | 219 + sys/src/cmd/python/Modules/gcmodule.c | 1390 ++ sys/src/cmd/python/Modules/gdbmmodule.c | 515 + sys/src/cmd/python/Modules/getaddrinfo.c | 638 + sys/src/cmd/python/Modules/getbuildinfo.c | 48 + sys/src/cmd/python/Modules/getnameinfo.c | 214 + sys/src/cmd/python/Modules/getpath.c | 694 + sys/src/cmd/python/Modules/glmodule.c | 7628 +++++++++ sys/src/cmd/python/Modules/grpmodule.c | 194 + sys/src/cmd/python/Modules/imageop.c | 785 + sys/src/cmd/python/Modules/imgfile.c | 504 + sys/src/cmd/python/Modules/itertoolsmodule.c | 2550 +++ sys/src/cmd/python/Modules/ld_so_aix | 187 + sys/src/cmd/python/Modules/ld_so_beos | 78 + sys/src/cmd/python/Modules/linuxaudiodev.c | 502 + sys/src/cmd/python/Modules/main.c | 584 + sys/src/cmd/python/Modules/makesetup | 297 + sys/src/cmd/python/Modules/makexp_aix | 81 + sys/src/cmd/python/Modules/mathmodule.c | 376 + sys/src/cmd/python/Modules/md5.c | 381 + sys/src/cmd/python/Modules/md5.h | 91 + sys/src/cmd/python/Modules/md5module.c | 312 + sys/src/cmd/python/Modules/mkfile | 135 + sys/src/cmd/python/Modules/mmapmodule.c | 1186 ++ sys/src/cmd/python/Modules/nismodule.c | 444 + sys/src/cmd/python/Modules/operator.c | 602 + sys/src/cmd/python/Modules/ossaudiodev.c | 1138 ++ sys/src/cmd/python/Modules/parsermodule.c | 3279 ++++ sys/src/cmd/python/Modules/posixmodule.c | 8752 +++++++++++ sys/src/cmd/python/Modules/puremodule.c | 988 ++ sys/src/cmd/python/Modules/pwdmodule.c | 198 + sys/src/cmd/python/Modules/pyexpat.c | 2149 +++ sys/src/cmd/python/Modules/python.c | 24 + sys/src/cmd/python/Modules/readline.c | 941 ++ sys/src/cmd/python/Modules/resource.c | 325 + sys/src/cmd/python/Modules/rgbimgmodule.c | 780 + sys/src/cmd/python/Modules/rotatingtree.c | 121 + sys/src/cmd/python/Modules/rotatingtree.h | 27 + sys/src/cmd/python/Modules/selectmodule.c | 734 + sys/src/cmd/python/Modules/sgimodule.c | 55 + sys/src/cmd/python/Modules/sha256module.c | 701 + sys/src/cmd/python/Modules/sha512module.c | 769 + sys/src/cmd/python/Modules/shamodule.c | 593 + sys/src/cmd/python/Modules/signalmodule.c | 676 + sys/src/cmd/python/Modules/socketmodule.c | 5100 ++++++ sys/src/cmd/python/Modules/socketmodule.h | 252 + sys/src/cmd/python/Modules/spwdmodule.c | 183 + sys/src/cmd/python/Modules/sre.h | 94 + sys/src/cmd/python/Modules/sre_constants.h | 86 + sys/src/cmd/python/Modules/stropmodule.c | 1248 ++ sys/src/cmd/python/Modules/sunaudiodev.c | 465 + sys/src/cmd/python/Modules/svmodule.c | 966 ++ sys/src/cmd/python/Modules/symtablemodule.c | 84 + sys/src/cmd/python/Modules/syslogmodule.c | 223 + sys/src/cmd/python/Modules/termios.c | 926 ++ sys/src/cmd/python/Modules/testcapi_long.h | 166 + sys/src/cmd/python/Modules/threadmodule.c | 720 + sys/src/cmd/python/Modules/timemodule.c | 1030 ++ sys/src/cmd/python/Modules/timing.h | 67 + sys/src/cmd/python/Modules/timingmodule.c | 58 + sys/src/cmd/python/Modules/tkappinit.c | 149 + sys/src/cmd/python/Modules/unicodedata.c | 1223 ++ sys/src/cmd/python/Modules/unicodedata_db.h | 5135 +++++++ sys/src/cmd/python/Modules/unicodename_db.h | 12543 +++++++++++++++ sys/src/cmd/python/Modules/xxmodule.c | 376 + sys/src/cmd/python/Modules/xxsubtype.c | 299 + sys/src/cmd/python/Modules/yuv.h | 99 + sys/src/cmd/python/Modules/yuvconvert.c | 118 + sys/src/cmd/python/Modules/zipimport.c | 1191 ++ sys/src/cmd/python/Modules/zlib/ChangeLog | 855 ++ sys/src/cmd/python/Modules/zlib/FAQ | 339 + sys/src/cmd/python/Modules/zlib/INDEX | 51 + sys/src/cmd/python/Modules/zlib/Makefile | 154 + sys/src/cmd/python/Modules/zlib/Makefile.in | 154 + sys/src/cmd/python/Modules/zlib/README | 125 + sys/src/cmd/python/Modules/zlib/adler32.c | 149 + sys/src/cmd/python/Modules/zlib/algorithm.txt | 209 + sys/src/cmd/python/Modules/zlib/compress.c | 79 + sys/src/cmd/python/Modules/zlib/configure | 459 + sys/src/cmd/python/Modules/zlib/crc32.c | 423 + sys/src/cmd/python/Modules/zlib/crc32.h | 441 + sys/src/cmd/python/Modules/zlib/deflate.c | 1736 +++ sys/src/cmd/python/Modules/zlib/deflate.h | 331 + sys/src/cmd/python/Modules/zlib/example.c | 565 + sys/src/cmd/python/Modules/zlib/gzio.c | 1026 ++ sys/src/cmd/python/Modules/zlib/infback.c | 623 + sys/src/cmd/python/Modules/zlib/inffast.c | 318 + sys/src/cmd/python/Modules/zlib/inffast.h | 11 + sys/src/cmd/python/Modules/zlib/inffixed.h | 94 + sys/src/cmd/python/Modules/zlib/inflate.c | 1368 ++ sys/src/cmd/python/Modules/zlib/inflate.h | 115 + sys/src/cmd/python/Modules/zlib/inftrees.c | 329 + sys/src/cmd/python/Modules/zlib/inftrees.h | 55 + sys/src/cmd/python/Modules/zlib/make_vms.com | 461 + sys/src/cmd/python/Modules/zlib/minigzip.c | 322 + sys/src/cmd/python/Modules/zlib/trees.c | 1219 ++ sys/src/cmd/python/Modules/zlib/trees.h | 128 + sys/src/cmd/python/Modules/zlib/uncompr.c | 61 + sys/src/cmd/python/Modules/zlib/zconf.h | 332 + sys/src/cmd/python/Modules/zlib/zconf.in.h | 332 + sys/src/cmd/python/Modules/zlib/zlib.3 | 159 + sys/src/cmd/python/Modules/zlib/zlib.h | 1357 ++ sys/src/cmd/python/Modules/zlib/zutil.c | 318 + sys/src/cmd/python/Modules/zlib/zutil.h | 269 + sys/src/cmd/python/Modules/zlibmodule.c | 1027 ++ sys/src/cmd/python/Objects/abstract.c | 2381 +++ sys/src/cmd/python/Objects/boolobject.c | 201 + sys/src/cmd/python/Objects/bufferobject.c | 706 + sys/src/cmd/python/Objects/cellobject.c | 133 + sys/src/cmd/python/Objects/classobject.c | 2580 ++++ sys/src/cmd/python/Objects/cobject.c | 161 + sys/src/cmd/python/Objects/codeobject.c | 590 + sys/src/cmd/python/Objects/complexobject.c | 1031 ++ sys/src/cmd/python/Objects/descrobject.c | 1283 ++ sys/src/cmd/python/Objects/dictnotes.txt | 250 + sys/src/cmd/python/Objects/dictobject.c | 2486 +++ sys/src/cmd/python/Objects/enumobject.c | 298 + sys/src/cmd/python/Objects/exceptions.c | 2147 +++ sys/src/cmd/python/Objects/fileobject.c | 2484 +++ sys/src/cmd/python/Objects/floatobject.c | 1748 +++ sys/src/cmd/python/Objects/frameobject.c | 849 + sys/src/cmd/python/Objects/funcobject.c | 888 ++ sys/src/cmd/python/Objects/genobject.c | 383 + sys/src/cmd/python/Objects/intobject.c | 1280 ++ sys/src/cmd/python/Objects/iterobject.c | 232 + sys/src/cmd/python/Objects/listobject.c | 2930 ++++ sys/src/cmd/python/Objects/listsort.txt | 677 + sys/src/cmd/python/Objects/longobject.c | 3458 +++++ sys/src/cmd/python/Objects/methodobject.c | 365 + sys/src/cmd/python/Objects/mkfile | 46 + sys/src/cmd/python/Objects/moduleobject.c | 259 + sys/src/cmd/python/Objects/object.c | 2139 +++ sys/src/cmd/python/Objects/obmalloc.c | 1745 +++ sys/src/cmd/python/Objects/rangeobject.c | 301 + sys/src/cmd/python/Objects/setobject.c | 2312 +++ sys/src/cmd/python/Objects/sliceobject.c | 351 + sys/src/cmd/python/Objects/stringlib/README.txt | 34 + sys/src/cmd/python/Objects/stringlib/count.h | 37 + sys/src/cmd/python/Objects/stringlib/fastsearch.h | 104 + sys/src/cmd/python/Objects/stringlib/find.h | 113 + sys/src/cmd/python/Objects/stringlib/partition.h | 111 + sys/src/cmd/python/Objects/stringobject.c | 5009 ++++++ sys/src/cmd/python/Objects/structseq.c | 407 + sys/src/cmd/python/Objects/tupleobject.c | 890 ++ sys/src/cmd/python/Objects/typeobject.c | 5891 +++++++ sys/src/cmd/python/Objects/unicodectype.c | 789 + sys/src/cmd/python/Objects/unicodeobject.c | 8067 ++++++++++ sys/src/cmd/python/Objects/unicodetype_db.h | 1269 ++ sys/src/cmd/python/Objects/weakrefobject.c | 941 ++ sys/src/cmd/python/Parser/Python.asdl | 115 + sys/src/cmd/python/Parser/acceler.c | 125 + sys/src/cmd/python/Parser/asdl.py | 415 + sys/src/cmd/python/Parser/asdl_c.py | 782 + sys/src/cmd/python/Parser/bitset.c | 66 + sys/src/cmd/python/Parser/firstsets.c | 113 + sys/src/cmd/python/Parser/grammar.c | 254 + sys/src/cmd/python/Parser/grammar.mak | 45 + sys/src/cmd/python/Parser/grammar1.c | 57 + sys/src/cmd/python/Parser/intrcheck.c | 176 + sys/src/cmd/python/Parser/listnode.c | 66 + sys/src/cmd/python/Parser/metagrammar.c | 159 + sys/src/cmd/python/Parser/mkfile | 44 + sys/src/cmd/python/Parser/myreadline.c | 219 + sys/src/cmd/python/Parser/node.c | 135 + sys/src/cmd/python/Parser/parser.c | 433 + sys/src/cmd/python/Parser/parser.h | 42 + sys/src/cmd/python/Parser/parsetok.c | 260 + sys/src/cmd/python/Parser/pgen.c | 706 + sys/src/cmd/python/Parser/pgenmain.c | 173 + sys/src/cmd/python/Parser/printgrammar.c | 113 + sys/src/cmd/python/Parser/spark.py | 840 + sys/src/cmd/python/Parser/tokenizer.c | 1535 ++ sys/src/cmd/python/Parser/tokenizer.h | 65 + sys/src/cmd/python/Parser/tokenizer_pgen.c | 2 + sys/src/cmd/python/Python/Python-ast.c | 3202 ++++ sys/src/cmd/python/Python/asdl.c | 36 + sys/src/cmd/python/Python/ast.c | 3292 ++++ sys/src/cmd/python/Python/atof.c | 50 + sys/src/cmd/python/Python/bltinmodule.c | 2620 ++++ sys/src/cmd/python/Python/ceval.c | 4351 ++++++ sys/src/cmd/python/Python/codecs.c | 860 ++ sys/src/cmd/python/Python/compile.c | 4570 ++++++ sys/src/cmd/python/Python/dup2.c | 30 + sys/src/cmd/python/Python/dynload_aix.c | 183 + sys/src/cmd/python/Python/dynload_atheos.c | 47 + sys/src/cmd/python/Python/dynload_beos.c | 254 + sys/src/cmd/python/Python/dynload_dl.c | 26 + sys/src/cmd/python/Python/dynload_hpux.c | 58 + sys/src/cmd/python/Python/dynload_next.c | 114 + sys/src/cmd/python/Python/dynload_os2.c | 46 + sys/src/cmd/python/Python/dynload_shlib.c | 143 + sys/src/cmd/python/Python/dynload_stub.c | 11 + sys/src/cmd/python/Python/dynload_win.c | 263 + sys/src/cmd/python/Python/errors.c | 822 + sys/src/cmd/python/Python/fmod.c | 27 + sys/src/cmd/python/Python/frozen.c | 38 + sys/src/cmd/python/Python/frozenmain.c | 68 + sys/src/cmd/python/Python/future.c | 136 + sys/src/cmd/python/Python/getargs.c | 1771 +++ sys/src/cmd/python/Python/getcompiler.c | 28 + sys/src/cmd/python/Python/getcopyright.c | 23 + sys/src/cmd/python/Python/getcwd.c | 83 + sys/src/cmd/python/Python/getmtime.c | 26 + sys/src/cmd/python/Python/getopt.c | 115 + sys/src/cmd/python/Python/getplatform.c | 12 + sys/src/cmd/python/Python/getversion.c | 15 + sys/src/cmd/python/Python/graminit.c | 2129 +++ sys/src/cmd/python/Python/hypot.c | 23 + sys/src/cmd/python/Python/import.c | 3160 ++++ sys/src/cmd/python/Python/importdl.c | 78 + sys/src/cmd/python/Python/importdl.h | 53 + sys/src/cmd/python/Python/mactoolboxglue.c | 470 + sys/src/cmd/python/Python/marshal.c | 1155 ++ sys/src/cmd/python/Python/memmove.c | 25 + sys/src/cmd/python/Python/mkfile | 64 + sys/src/cmd/python/Python/modsupport.c | 631 + sys/src/cmd/python/Python/mysnprintf.c | 93 + sys/src/cmd/python/Python/mystrtoul.c | 232 + sys/src/cmd/python/Python/pyarena.c | 220 + sys/src/cmd/python/Python/pyfpe.c | 23 + sys/src/cmd/python/Python/pystate.c | 632 + sys/src/cmd/python/Python/pystrtod.c | 248 + sys/src/cmd/python/Python/pythonrun.c | 1857 +++ sys/src/cmd/python/Python/sigcheck.c | 19 + sys/src/cmd/python/Python/strdup.c | 14 + sys/src/cmd/python/Python/strerror.c | 19 + sys/src/cmd/python/Python/strtod.c | 156 + sys/src/cmd/python/Python/structmember.c | 312 + sys/src/cmd/python/Python/symtable.c | 1425 ++ sys/src/cmd/python/Python/sysmodule.c | 1468 ++ sys/src/cmd/python/Python/thread.c | 384 + sys/src/cmd/python/Python/thread_atheos.h | 300 + sys/src/cmd/python/Python/thread_beos.h | 287 + sys/src/cmd/python/Python/thread_cthread.h | 156 + sys/src/cmd/python/Python/thread_foobar.h | 115 + sys/src/cmd/python/Python/thread_lwp.h | 149 + sys/src/cmd/python/Python/thread_nt.h | 364 + sys/src/cmd/python/Python/thread_os2.h | 307 + sys/src/cmd/python/Python/thread_plan9.h | 135 + sys/src/cmd/python/Python/thread_pth.h | 213 + sys/src/cmd/python/Python/thread_pthread.h | 533 + sys/src/cmd/python/Python/thread_sgi.h | 375 + sys/src/cmd/python/Python/thread_solaris.h | 174 + sys/src/cmd/python/Python/thread_wince.h | 171 + sys/src/cmd/python/Python/traceback.c | 262 + sys/src/cmd/python/README | 1297 ++ sys/src/cmd/python/README.Plan9 | 12 + sys/src/cmd/python/Tools/README | 47 + sys/src/cmd/python/Tools/audiopy/README | 112 + sys/src/cmd/python/Tools/audiopy/audiopy | 507 + sys/src/cmd/python/Tools/bgen/README | 7 + sys/src/cmd/python/Tools/bgen/bgen/bgen.py | 12 + sys/src/cmd/python/Tools/bgen/bgen/bgenBuffer.py | 301 + .../cmd/python/Tools/bgen/bgen/bgenGenerator.py | 302 + .../python/Tools/bgen/bgen/bgenGeneratorGroup.py | 40 + .../cmd/python/Tools/bgen/bgen/bgenHeapBuffer.py | 145 + sys/src/cmd/python/Tools/bgen/bgen/bgenModule.py | 94 + .../python/Tools/bgen/bgen/bgenObjectDefinition.py | 512 + sys/src/cmd/python/Tools/bgen/bgen/bgenOutput.py | 219 + .../cmd/python/Tools/bgen/bgen/bgenStackBuffer.py | 62 + .../cmd/python/Tools/bgen/bgen/bgenStringBuffer.py | 67 + sys/src/cmd/python/Tools/bgen/bgen/bgenType.py | 328 + sys/src/cmd/python/Tools/bgen/bgen/bgenVariable.py | 112 + sys/src/cmd/python/Tools/bgen/bgen/macsupport.py | 197 + sys/src/cmd/python/Tools/bgen/bgen/scantools.py | 849 + sys/src/cmd/python/Tools/buildbot/Makefile | 6 + sys/src/cmd/python/Tools/buildbot/build.bat | 5 + sys/src/cmd/python/Tools/buildbot/clean.bat | 6 + sys/src/cmd/python/Tools/buildbot/external.bat | 36 + sys/src/cmd/python/Tools/buildbot/kill_python.bat | 3 + sys/src/cmd/python/Tools/buildbot/kill_python.c | 68 + sys/src/cmd/python/Tools/buildbot/kill_python.mak | 2 + sys/src/cmd/python/Tools/buildbot/test.bat | 3 + sys/src/cmd/python/Tools/compiler/ACKS | 8 + sys/src/cmd/python/Tools/compiler/README | 18 + sys/src/cmd/python/Tools/compiler/ast.txt | 104 + sys/src/cmd/python/Tools/compiler/astgen.py | 289 + sys/src/cmd/python/Tools/compiler/compile.py | 51 + sys/src/cmd/python/Tools/compiler/demo.py | 38 + sys/src/cmd/python/Tools/compiler/dumppyc.py | 47 + sys/src/cmd/python/Tools/compiler/regrtest.py | 78 + sys/src/cmd/python/Tools/compiler/stacktest.py | 43 + sys/src/cmd/python/Tools/faqwiz/README | 114 + sys/src/cmd/python/Tools/faqwiz/faqconf.py | 577 + sys/src/cmd/python/Tools/faqwiz/faqcust.py | 1 + sys/src/cmd/python/Tools/faqwiz/faqw.py | 33 + sys/src/cmd/python/Tools/faqwiz/faqwiz.py | 841 + sys/src/cmd/python/Tools/faqwiz/move-faqwiz.sh | 49 + sys/src/cmd/python/Tools/framer/README.txt | 8 + sys/src/cmd/python/Tools/framer/TODO.txt | 6 + sys/src/cmd/python/Tools/framer/example.py | 126 + sys/src/cmd/python/Tools/framer/framer/__init__.py | 6 + sys/src/cmd/python/Tools/framer/framer/bases.py | 220 + sys/src/cmd/python/Tools/framer/framer/function.py | 173 + sys/src/cmd/python/Tools/framer/framer/member.py | 73 + sys/src/cmd/python/Tools/framer/framer/slots.py | 64 + sys/src/cmd/python/Tools/framer/framer/struct.py | 52 + .../cmd/python/Tools/framer/framer/structparse.py | 46 + sys/src/cmd/python/Tools/framer/framer/template.py | 102 + sys/src/cmd/python/Tools/framer/framer/util.py | 35 + sys/src/cmd/python/Tools/freeze/README | 296 + sys/src/cmd/python/Tools/freeze/bkfile.py | 47 + sys/src/cmd/python/Tools/freeze/checkextensions.py | 90 + .../python/Tools/freeze/checkextensions_win32.py | 188 + .../cmd/python/Tools/freeze/extensions_win32.ini | 171 + sys/src/cmd/python/Tools/freeze/freeze.py | 497 + sys/src/cmd/python/Tools/freeze/hello.py | 1 + sys/src/cmd/python/Tools/freeze/makeconfig.py | 61 + sys/src/cmd/python/Tools/freeze/makefreeze.py | 90 + sys/src/cmd/python/Tools/freeze/makemakefile.py | 29 + sys/src/cmd/python/Tools/freeze/parsesetup.py | 112 + sys/src/cmd/python/Tools/freeze/win32.html | 119 + sys/src/cmd/python/Tools/freeze/winmakemakefile.py | 146 + sys/src/cmd/python/Tools/i18n/makelocalealias.py | 73 + sys/src/cmd/python/Tools/i18n/msgfmt.py | 203 + sys/src/cmd/python/Tools/i18n/pygettext.py | 669 + sys/src/cmd/python/Tools/modulator/EXAMPLE.py | 53 + sys/src/cmd/python/Tools/modulator/README | 25 + .../cmd/python/Tools/modulator/ScrolledListbox.py | 37 + .../cmd/python/Tools/modulator/Templates/copyright | 0 .../python/Tools/modulator/Templates/module_head | 6 + .../python/Tools/modulator/Templates/module_method | 14 + .../python/Tools/modulator/Templates/module_tail | 37 + .../python/Tools/modulator/Templates/object_head | 13 + .../python/Tools/modulator/Templates/object_method | 14 + .../python/Tools/modulator/Templates/object_mlist | 8 + .../python/Tools/modulator/Templates/object_new | 13 + .../Tools/modulator/Templates/object_structure | 37 + .../python/Tools/modulator/Templates/object_tail | 33 + .../Tools/modulator/Templates/object_tp_as_mapping | 29 + .../Tools/modulator/Templates/object_tp_as_number | 169 + .../modulator/Templates/object_tp_as_sequence | 58 + .../Tools/modulator/Templates/object_tp_call | 7 + .../Tools/modulator/Templates/object_tp_compare | 6 + .../Tools/modulator/Templates/object_tp_dealloc | 7 + .../Tools/modulator/Templates/object_tp_getattr | 7 + .../Tools/modulator/Templates/object_tp_hash | 6 + .../Tools/modulator/Templates/object_tp_print | 7 + .../Tools/modulator/Templates/object_tp_repr | 9 + .../Tools/modulator/Templates/object_tp_setattr | 9 + .../python/Tools/modulator/Templates/object_tp_str | 10 + sys/src/cmd/python/Tools/modulator/Tkextra.py | 235 + sys/src/cmd/python/Tools/modulator/genmodule.py | 160 + sys/src/cmd/python/Tools/modulator/modulator.py | 383 + sys/src/cmd/python/Tools/modulator/varsubst.py | 56 + sys/src/cmd/python/Tools/msi/README.txt | 25 + sys/src/cmd/python/Tools/msi/msi.py | 1203 ++ sys/src/cmd/python/Tools/msi/msilib.py | 674 + sys/src/cmd/python/Tools/msi/msisupport.c | 102 + sys/src/cmd/python/Tools/msi/msisupport.mak | 25 + sys/src/cmd/python/Tools/msi/schema.py | 1007 ++ sys/src/cmd/python/Tools/msi/sequence.py | 126 + sys/src/cmd/python/Tools/msi/uisample.py | 1400 ++ sys/src/cmd/python/Tools/msi/uuids.py | 38 + sys/src/cmd/python/Tools/pybench/Arithmetic.py | 777 + sys/src/cmd/python/Tools/pybench/Calls.py | 502 + sys/src/cmd/python/Tools/pybench/CommandLine.py | 634 + sys/src/cmd/python/Tools/pybench/Constructs.py | 564 + sys/src/cmd/python/Tools/pybench/Dict.py | 504 + sys/src/cmd/python/Tools/pybench/Exceptions.py | 699 + sys/src/cmd/python/Tools/pybench/Imports.py | 138 + sys/src/cmd/python/Tools/pybench/Instances.py | 66 + sys/src/cmd/python/Tools/pybench/LICENSE | 25 + sys/src/cmd/python/Tools/pybench/Lists.py | 295 + sys/src/cmd/python/Tools/pybench/Lookups.py | 945 ++ sys/src/cmd/python/Tools/pybench/NewInstances.py | 75 + sys/src/cmd/python/Tools/pybench/Numbers.py | 784 + sys/src/cmd/python/Tools/pybench/README | 368 + sys/src/cmd/python/Tools/pybench/Setup.py | 39 + sys/src/cmd/python/Tools/pybench/Strings.py | 562 + sys/src/cmd/python/Tools/pybench/Tuples.py | 360 + sys/src/cmd/python/Tools/pybench/Unicode.py | 542 + sys/src/cmd/python/Tools/pybench/clockres.py | 43 + .../cmd/python/Tools/pybench/package/__init__.py | 0 .../cmd/python/Tools/pybench/package/submodule.py | 0 sys/src/cmd/python/Tools/pybench/pybench.py | 943 ++ sys/src/cmd/python/Tools/pybench/systimes.py | 211 + sys/src/cmd/python/Tools/pynche/ChipViewer.py | 131 + sys/src/cmd/python/Tools/pynche/ColorDB.py | 279 + sys/src/cmd/python/Tools/pynche/DetailsViewer.py | 273 + sys/src/cmd/python/Tools/pynche/ListViewer.py | 175 + sys/src/cmd/python/Tools/pynche/Main.py | 229 + sys/src/cmd/python/Tools/pynche/PyncheWidget.py | 309 + sys/src/cmd/python/Tools/pynche/README | 398 + sys/src/cmd/python/Tools/pynche/StripViewer.py | 433 + sys/src/cmd/python/Tools/pynche/Switchboard.py | 139 + sys/src/cmd/python/Tools/pynche/TextViewer.py | 188 + sys/src/cmd/python/Tools/pynche/TypeinViewer.py | 163 + sys/src/cmd/python/Tools/pynche/X/rgb.txt | 753 + sys/src/cmd/python/Tools/pynche/X/xlicense.txt | 29 + sys/src/cmd/python/Tools/pynche/__init__.py | 1 + sys/src/cmd/python/Tools/pynche/html40colors.txt | 17 + sys/src/cmd/python/Tools/pynche/namedcolors.txt | 100 + sys/src/cmd/python/Tools/pynche/pyColorChooser.py | 125 + sys/src/cmd/python/Tools/pynche/pynche | 7 + sys/src/cmd/python/Tools/pynche/pynche.pyw | 7 + sys/src/cmd/python/Tools/pynche/webcolors.txt | 141 + sys/src/cmd/python/Tools/pynche/websafe.txt | 217 + sys/src/cmd/python/Tools/scripts/README | 66 + sys/src/cmd/python/Tools/scripts/byext.py | 131 + sys/src/cmd/python/Tools/scripts/byteyears.py | 61 + sys/src/cmd/python/Tools/scripts/checkappend.py | 167 + sys/src/cmd/python/Tools/scripts/checkpyc.py | 66 + sys/src/cmd/python/Tools/scripts/classfix.py | 190 + sys/src/cmd/python/Tools/scripts/cleanfuture.py | 276 + sys/src/cmd/python/Tools/scripts/combinerefs.py | 127 + sys/src/cmd/python/Tools/scripts/copytime.py | 26 + sys/src/cmd/python/Tools/scripts/crlf.py | 23 + sys/src/cmd/python/Tools/scripts/cvsfiles.py | 72 + sys/src/cmd/python/Tools/scripts/db2pickle.py | 135 + sys/src/cmd/python/Tools/scripts/diff.py | 49 + sys/src/cmd/python/Tools/scripts/dutree.doc | 54 + sys/src/cmd/python/Tools/scripts/dutree.py | 60 + sys/src/cmd/python/Tools/scripts/eptags.py | 56 + sys/src/cmd/python/Tools/scripts/finddiv.py | 89 + sys/src/cmd/python/Tools/scripts/findlinksto.py | 43 + sys/src/cmd/python/Tools/scripts/findnocoding.py | 104 + sys/src/cmd/python/Tools/scripts/fixcid.py | 314 + sys/src/cmd/python/Tools/scripts/fixdiv.py | 380 + sys/src/cmd/python/Tools/scripts/fixheader.py | 49 + sys/src/cmd/python/Tools/scripts/fixnotice.py | 113 + sys/src/cmd/python/Tools/scripts/fixps.py | 33 + sys/src/cmd/python/Tools/scripts/ftpmirror.py | 400 + sys/src/cmd/python/Tools/scripts/google.py | 23 + sys/src/cmd/python/Tools/scripts/gprof2html.py | 79 + sys/src/cmd/python/Tools/scripts/h2py.py | 175 + sys/src/cmd/python/Tools/scripts/hotshotmain.py | 55 + sys/src/cmd/python/Tools/scripts/idle | 5 + sys/src/cmd/python/Tools/scripts/ifdef.py | 112 + sys/src/cmd/python/Tools/scripts/lfcr.py | 24 + sys/src/cmd/python/Tools/scripts/linktree.py | 80 + sys/src/cmd/python/Tools/scripts/lll.py | 28 + sys/src/cmd/python/Tools/scripts/logmerge.py | 185 + sys/src/cmd/python/Tools/scripts/mailerdaemon.py | 237 + sys/src/cmd/python/Tools/scripts/md5sum.py | 90 + sys/src/cmd/python/Tools/scripts/methfix.py | 171 + sys/src/cmd/python/Tools/scripts/mkreal.py | 66 + sys/src/cmd/python/Tools/scripts/ndiff.py | 133 + sys/src/cmd/python/Tools/scripts/nm2def.py | 103 + sys/src/cmd/python/Tools/scripts/objgraph.py | 215 + sys/src/cmd/python/Tools/scripts/parseentities.py | 64 + sys/src/cmd/python/Tools/scripts/pathfix.py | 149 + sys/src/cmd/python/Tools/scripts/pdeps.py | 167 + sys/src/cmd/python/Tools/scripts/pickle2db.py | 147 + sys/src/cmd/python/Tools/scripts/pindent.py | 543 + sys/src/cmd/python/Tools/scripts/ptags.py | 53 + sys/src/cmd/python/Tools/scripts/pydoc | 5 + sys/src/cmd/python/Tools/scripts/pydocgui.pyw | 7 + sys/src/cmd/python/Tools/scripts/pysource.py | 130 + sys/src/cmd/python/Tools/scripts/redemo.py | 171 + sys/src/cmd/python/Tools/scripts/reindent.py | 293 + sys/src/cmd/python/Tools/scripts/rgrep.py | 64 + sys/src/cmd/python/Tools/scripts/setup.py | 19 + sys/src/cmd/python/Tools/scripts/suff.py | 30 + sys/src/cmd/python/Tools/scripts/svneol.py | 77 + sys/src/cmd/python/Tools/scripts/texcheck.py | 233 + sys/src/cmd/python/Tools/scripts/texi2html.py | 2078 +++ sys/src/cmd/python/Tools/scripts/treesync.py | 205 + sys/src/cmd/python/Tools/scripts/untabify.py | 52 + sys/src/cmd/python/Tools/scripts/which.py | 60 + sys/src/cmd/python/Tools/scripts/xxci.py | 117 + sys/src/cmd/python/Tools/unicode/Makefile | 84 + sys/src/cmd/python/Tools/unicode/comparecodecs.py | 53 + sys/src/cmd/python/Tools/unicode/gencjkcodecs.py | 68 + sys/src/cmd/python/Tools/unicode/gencodec.py | 426 + sys/src/cmd/python/Tools/unicode/listcodecs.py | 41 + .../cmd/python/Tools/unicode/makeunicodedata.py | 943 ++ sys/src/cmd/python/Tools/unicode/mkstringprep.py | 431 + .../Tools/unicode/python-mappings/CP1140.TXT | 291 + .../Tools/unicode/python-mappings/KOI8-U.TXT | 298 + .../Tools/unicode/python-mappings/TIS-620.TXT | 284 + sys/src/cmd/python/Tools/versioncheck/README | 41 + .../cmd/python/Tools/versioncheck/_checkversion.py | 16 + .../cmd/python/Tools/versioncheck/checkversions.py | 52 + .../python/Tools/versioncheck/pyversioncheck.py | 98 + sys/src/cmd/python/Tools/webchecker/README | 23 + sys/src/cmd/python/Tools/webchecker/tktools.py | 366 + sys/src/cmd/python/Tools/webchecker/wcgui.py | 463 + sys/src/cmd/python/Tools/webchecker/wcmac.py | 7 + sys/src/cmd/python/Tools/webchecker/webchecker.py | 892 ++ sys/src/cmd/python/Tools/webchecker/websucker.py | 125 + sys/src/cmd/python/Tools/webchecker/wsgui.py | 242 + sys/src/cmd/python/Tools/world/README | 85 + sys/src/cmd/python/Tools/world/world | 551 + sys/src/cmd/python/mkconfig | 54 + sys/src/cmd/python/mkfile | 52 + sys/src/cmd/python/plan9.c | 55 + sys/src/cmd/python/pyconfig.h | 984 ++ sys/src/cmd/python/python.proto | 14 + 1960 files changed, 782563 insertions(+) create mode 100644 sys/src/cmd/hg/CONTRIBUTORS create mode 100644 sys/src/cmd/hg/COPYING create mode 100644 sys/src/cmd/hg/Makefile create mode 100644 sys/src/cmd/hg/README create mode 100644 sys/src/cmd/hg/README.Plan9 create mode 100644 sys/src/cmd/hg/contrib/bash_completion create mode 100755 sys/src/cmd/hg/contrib/buildrpm create mode 100755 sys/src/cmd/hg/contrib/convert-repo create mode 100644 sys/src/cmd/hg/contrib/dumprevlog create mode 100644 sys/src/cmd/hg/contrib/git-viz/git-cat-file create mode 100644 sys/src/cmd/hg/contrib/git-viz/git-diff-tree create mode 100644 sys/src/cmd/hg/contrib/git-viz/git-rev-list create mode 100644 sys/src/cmd/hg/contrib/git-viz/git-rev-tree create mode 100644 sys/src/cmd/hg/contrib/git-viz/hg-viz create mode 100755 sys/src/cmd/hg/contrib/hg-relink create mode 100755 sys/src/cmd/hg/contrib/hg-ssh create mode 100755 sys/src/cmd/hg/contrib/hgdiff create mode 100755 sys/src/cmd/hg/contrib/hgk create mode 100644 sys/src/cmd/hg/contrib/hgsh/Makefile create mode 100644 sys/src/cmd/hg/contrib/hgsh/hgsh.c create mode 100644 sys/src/cmd/hg/contrib/hgwebdir.fcgi create mode 100644 sys/src/cmd/hg/contrib/hgwebdir.wsgi create mode 100644 sys/src/cmd/hg/contrib/logo-droplets.svg create mode 100644 sys/src/cmd/hg/contrib/macosx/Readme.html create mode 100644 sys/src/cmd/hg/contrib/macosx/Welcome.html create mode 100644 sys/src/cmd/hg/contrib/macosx/macosx-build.txt create mode 100644 sys/src/cmd/hg/contrib/mercurial.el create mode 100755 sys/src/cmd/hg/contrib/mercurial.spec create mode 100644 sys/src/cmd/hg/contrib/mergetools.hgrc create mode 100644 sys/src/cmd/hg/contrib/mq.el create mode 100644 sys/src/cmd/hg/contrib/perf.py create mode 100644 sys/src/cmd/hg/contrib/python-hook-examples.py create mode 100755 sys/src/cmd/hg/contrib/rewrite-log create mode 100644 sys/src/cmd/hg/contrib/sample.hgrc create mode 100755 sys/src/cmd/hg/contrib/simplemerge create mode 100644 sys/src/cmd/hg/contrib/tcsh_completion create mode 100755 sys/src/cmd/hg/contrib/tcsh_completion_build.sh create mode 100755 sys/src/cmd/hg/contrib/tmplrewrite.py create mode 100644 sys/src/cmd/hg/contrib/undumprevlog create mode 100644 sys/src/cmd/hg/contrib/vim/HGAnnotate.vim create mode 100644 sys/src/cmd/hg/contrib/vim/hg-menu.vim create mode 100644 sys/src/cmd/hg/contrib/vim/hgcommand.vim create mode 100644 sys/src/cmd/hg/contrib/vim/patchreview.txt create mode 100644 sys/src/cmd/hg/contrib/vim/patchreview.vim create mode 100644 sys/src/cmd/hg/contrib/win32/ReadMe.html create mode 100644 sys/src/cmd/hg/contrib/win32/hg.bat create mode 100644 sys/src/cmd/hg/contrib/win32/mercurial.ico create mode 100644 sys/src/cmd/hg/contrib/win32/mercurial.ini create mode 100644 sys/src/cmd/hg/contrib/win32/mercurial.iss create mode 100644 sys/src/cmd/hg/contrib/win32/postinstall.txt create mode 100644 sys/src/cmd/hg/contrib/win32/win32-build.txt create mode 100644 sys/src/cmd/hg/contrib/zsh_completion create mode 100644 sys/src/cmd/hg/doc/Makefile create mode 100644 sys/src/cmd/hg/doc/README create mode 100644 sys/src/cmd/hg/doc/common.txt create mode 100644 sys/src/cmd/hg/doc/gendoc.py create mode 100644 sys/src/cmd/hg/doc/hg.1.txt create mode 100644 sys/src/cmd/hg/doc/hgignore.5.txt create mode 100644 sys/src/cmd/hg/doc/hgrc.5.txt create mode 100644 sys/src/cmd/hg/doc/ja/Makefile create mode 100644 sys/src/cmd/hg/doc/ja/docbook.ja.conf create mode 100644 sys/src/cmd/hg/doc/ja/docbook.ja.xsl create mode 100644 sys/src/cmd/hg/doc/ja/hg.1.ja.txt create mode 100644 sys/src/cmd/hg/doc/ja/hgrc.5.ja.txt create mode 100755 sys/src/cmd/hg/hg create mode 100644 sys/src/cmd/hg/hg.proto create mode 100755 sys/src/cmd/hg/hgeditor create mode 100644 sys/src/cmd/hg/hgext/__init__.py create mode 100644 sys/src/cmd/hg/hgext/acl.py create mode 100644 sys/src/cmd/hg/hgext/bookmarks.py create mode 100644 sys/src/cmd/hg/hgext/bugzilla.py create mode 100644 sys/src/cmd/hg/hgext/children.py create mode 100644 sys/src/cmd/hg/hgext/churn.py create mode 100644 sys/src/cmd/hg/hgext/color.py create mode 100644 sys/src/cmd/hg/hgext/convert/__init__.py create mode 100644 sys/src/cmd/hg/hgext/convert/bzr.py create mode 100644 sys/src/cmd/hg/hgext/convert/common.py create mode 100644 sys/src/cmd/hg/hgext/convert/convcmd.py create mode 100644 sys/src/cmd/hg/hgext/convert/cvs.py create mode 100644 sys/src/cmd/hg/hgext/convert/cvsps.py create mode 100644 sys/src/cmd/hg/hgext/convert/darcs.py create mode 100644 sys/src/cmd/hg/hgext/convert/filemap.py create mode 100644 sys/src/cmd/hg/hgext/convert/git.py create mode 100644 sys/src/cmd/hg/hgext/convert/gnuarch.py create mode 100644 sys/src/cmd/hg/hgext/convert/hg.py create mode 100644 sys/src/cmd/hg/hgext/convert/monotone.py create mode 100644 sys/src/cmd/hg/hgext/convert/p4.py create mode 100644 sys/src/cmd/hg/hgext/convert/subversion.py create mode 100644 sys/src/cmd/hg/hgext/convert/transport.py create mode 100644 sys/src/cmd/hg/hgext/extdiff.py create mode 100644 sys/src/cmd/hg/hgext/fetch.py create mode 100644 sys/src/cmd/hg/hgext/gpg.py create mode 100644 sys/src/cmd/hg/hgext/graphlog.py create mode 100644 sys/src/cmd/hg/hgext/hgcia.py create mode 100644 sys/src/cmd/hg/hgext/hgk.py create mode 100644 sys/src/cmd/hg/hgext/highlight/__init__.py create mode 100644 sys/src/cmd/hg/hgext/highlight/highlight.py create mode 100644 sys/src/cmd/hg/hgext/inotify/__init__.py create mode 100644 sys/src/cmd/hg/hgext/inotify/client.py create mode 100644 sys/src/cmd/hg/hgext/inotify/common.py create mode 100644 sys/src/cmd/hg/hgext/inotify/linux/__init__.py create mode 100644 sys/src/cmd/hg/hgext/inotify/linux/_inotify.c create mode 100644 sys/src/cmd/hg/hgext/inotify/linux/watcher.py create mode 100644 sys/src/cmd/hg/hgext/inotify/server.py create mode 100644 sys/src/cmd/hg/hgext/interhg.py create mode 100644 sys/src/cmd/hg/hgext/keyword.py create mode 100644 sys/src/cmd/hg/hgext/mq.py create mode 100644 sys/src/cmd/hg/hgext/notify.py create mode 100644 sys/src/cmd/hg/hgext/pager.py create mode 100644 sys/src/cmd/hg/hgext/parentrevspec.py create mode 100644 sys/src/cmd/hg/hgext/patchbomb.py create mode 100644 sys/src/cmd/hg/hgext/purge.py create mode 100644 sys/src/cmd/hg/hgext/rebase.py create mode 100644 sys/src/cmd/hg/hgext/record.py create mode 100644 sys/src/cmd/hg/hgext/share.py create mode 100644 sys/src/cmd/hg/hgext/transplant.py create mode 100644 sys/src/cmd/hg/hgext/win32mbcs.py create mode 100644 sys/src/cmd/hg/hgext/win32text.py create mode 100644 sys/src/cmd/hg/hgext/zeroconf/Zeroconf.py create mode 100644 sys/src/cmd/hg/hgext/zeroconf/__init__.py create mode 100644 sys/src/cmd/hg/hgweb.cgi create mode 100644 sys/src/cmd/hg/hgwebdir.cgi create mode 100644 sys/src/cmd/hg/i18n/da.po create mode 100644 sys/src/cmd/hg/i18n/de.po create mode 100644 sys/src/cmd/hg/i18n/el.po create mode 100644 sys/src/cmd/hg/i18n/fr.po create mode 100755 sys/src/cmd/hg/i18n/hggettext create mode 100644 sys/src/cmd/hg/i18n/it.po create mode 100644 sys/src/cmd/hg/i18n/ja.po create mode 100644 sys/src/cmd/hg/i18n/pt_BR.po create mode 100644 sys/src/cmd/hg/i18n/zh_CN.po create mode 100644 sys/src/cmd/hg/i18n/zh_TW.po create mode 100644 sys/src/cmd/hg/mercurial/__init__.py create mode 100644 sys/src/cmd/hg/mercurial/__init__.pyc create mode 100644 sys/src/cmd/hg/mercurial/ancestor.py create mode 100644 sys/src/cmd/hg/mercurial/archival.py create mode 100644 sys/src/cmd/hg/mercurial/base85.c create mode 100644 sys/src/cmd/hg/mercurial/bdiff.c create mode 100644 sys/src/cmd/hg/mercurial/bundlerepo.py create mode 100644 sys/src/cmd/hg/mercurial/byterange.py create mode 100644 sys/src/cmd/hg/mercurial/changegroup.py create mode 100644 sys/src/cmd/hg/mercurial/changelog.py create mode 100644 sys/src/cmd/hg/mercurial/cmdutil.py create mode 100644 sys/src/cmd/hg/mercurial/commands.py create mode 100644 sys/src/cmd/hg/mercurial/commands.pyc create mode 100644 sys/src/cmd/hg/mercurial/config.py create mode 100644 sys/src/cmd/hg/mercurial/config.pyc create mode 100644 sys/src/cmd/hg/mercurial/context.py create mode 100644 sys/src/cmd/hg/mercurial/copies.py create mode 100644 sys/src/cmd/hg/mercurial/demandimport.py create mode 100644 sys/src/cmd/hg/mercurial/demandimport.pyc create mode 100644 sys/src/cmd/hg/mercurial/diffhelpers.c create mode 100644 sys/src/cmd/hg/mercurial/dirstate.py create mode 100644 sys/src/cmd/hg/mercurial/dispatch.py create mode 100644 sys/src/cmd/hg/mercurial/dispatch.pyc create mode 100644 sys/src/cmd/hg/mercurial/encoding.py create mode 100644 sys/src/cmd/hg/mercurial/encoding.pyc create mode 100644 sys/src/cmd/hg/mercurial/error.py create mode 100644 sys/src/cmd/hg/mercurial/error.pyc create mode 100644 sys/src/cmd/hg/mercurial/extensions.py create mode 100644 sys/src/cmd/hg/mercurial/extensions.pyc create mode 100644 sys/src/cmd/hg/mercurial/fancyopts.py create mode 100644 sys/src/cmd/hg/mercurial/fancyopts.pyc create mode 100644 sys/src/cmd/hg/mercurial/filelog.py create mode 100644 sys/src/cmd/hg/mercurial/filemerge.py create mode 100644 sys/src/cmd/hg/mercurial/graphmod.py create mode 100644 sys/src/cmd/hg/mercurial/hbisect.py create mode 100644 sys/src/cmd/hg/mercurial/help.py create mode 100644 sys/src/cmd/hg/mercurial/hg.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/__init__.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/__init__.pyc create mode 100644 sys/src/cmd/hg/mercurial/hgweb/common.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/hgweb_mod.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/hgwebdir_mod.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/protocol.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/request.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/server.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/webcommands.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/webutil.py create mode 100644 sys/src/cmd/hg/mercurial/hgweb/wsgicgi.py create mode 100644 sys/src/cmd/hg/mercurial/hook.py create mode 100644 sys/src/cmd/hg/mercurial/httprepo.py create mode 100644 sys/src/cmd/hg/mercurial/i18n.py create mode 100644 sys/src/cmd/hg/mercurial/i18n.pyc create mode 100644 sys/src/cmd/hg/mercurial/ignore.py create mode 100644 sys/src/cmd/hg/mercurial/keepalive.py create mode 100644 sys/src/cmd/hg/mercurial/localrepo.py create mode 100644 sys/src/cmd/hg/mercurial/lock.py create mode 100644 sys/src/cmd/hg/mercurial/lock.pyc create mode 100644 sys/src/cmd/hg/mercurial/lsprof.py create mode 100644 sys/src/cmd/hg/mercurial/lsprofcalltree.py create mode 100644 sys/src/cmd/hg/mercurial/mail.py create mode 100644 sys/src/cmd/hg/mercurial/manifest.py create mode 100644 sys/src/cmd/hg/mercurial/match.py create mode 100644 sys/src/cmd/hg/mercurial/mdiff.py create mode 100644 sys/src/cmd/hg/mercurial/merge.py create mode 100644 sys/src/cmd/hg/mercurial/minirst.py create mode 100644 sys/src/cmd/hg/mercurial/mpatch.c create mode 100644 sys/src/cmd/hg/mercurial/node.py create mode 100644 sys/src/cmd/hg/mercurial/node.pyc create mode 100644 sys/src/cmd/hg/mercurial/osutil.c create mode 100644 sys/src/cmd/hg/mercurial/parsers.c create mode 100644 sys/src/cmd/hg/mercurial/patch.py create mode 100644 sys/src/cmd/hg/mercurial/posix.py create mode 100644 sys/src/cmd/hg/mercurial/posix.pyc create mode 100644 sys/src/cmd/hg/mercurial/pure/base85.py create mode 100644 sys/src/cmd/hg/mercurial/pure/bdiff.py create mode 100644 sys/src/cmd/hg/mercurial/pure/diffhelpers.py create mode 100644 sys/src/cmd/hg/mercurial/pure/mpatch.py create mode 100644 sys/src/cmd/hg/mercurial/pure/osutil.py create mode 100644 sys/src/cmd/hg/mercurial/pure/parsers.py create mode 100644 sys/src/cmd/hg/mercurial/repair.py create mode 100644 sys/src/cmd/hg/mercurial/repo.py create mode 100644 sys/src/cmd/hg/mercurial/revlog.py create mode 100644 sys/src/cmd/hg/mercurial/simplemerge.py create mode 100644 sys/src/cmd/hg/mercurial/sshrepo.py create mode 100644 sys/src/cmd/hg/mercurial/sshserver.py create mode 100644 sys/src/cmd/hg/mercurial/statichttprepo.py create mode 100644 sys/src/cmd/hg/mercurial/store.py create mode 100644 sys/src/cmd/hg/mercurial/streamclone.py create mode 100644 sys/src/cmd/hg/mercurial/strutil.py create mode 100644 sys/src/cmd/hg/mercurial/subrepo.py create mode 100644 sys/src/cmd/hg/mercurial/tags.py create mode 100644 sys/src/cmd/hg/mercurial/templatefilters.py create mode 100644 sys/src/cmd/hg/mercurial/templater.py create mode 100644 sys/src/cmd/hg/mercurial/transaction.py create mode 100644 sys/src/cmd/hg/mercurial/ui.py create mode 100644 sys/src/cmd/hg/mercurial/ui.pyc create mode 100644 sys/src/cmd/hg/mercurial/url.py create mode 100644 sys/src/cmd/hg/mercurial/util.py create mode 100644 sys/src/cmd/hg/mercurial/util.pyc create mode 100644 sys/src/cmd/hg/mercurial/verify.py create mode 100644 sys/src/cmd/hg/mercurial/win32.py create mode 100644 sys/src/cmd/hg/mercurial/windows.py create mode 100644 sys/src/cmd/hg/mkfile create mode 100644 sys/src/cmd/hg/setup.py create mode 100644 sys/src/cmd/hg/templates/atom/changelog.tmpl create mode 100644 sys/src/cmd/hg/templates/atom/changelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/atom/error.tmpl create mode 100644 sys/src/cmd/hg/templates/atom/filelog.tmpl create mode 100644 sys/src/cmd/hg/templates/atom/header.tmpl create mode 100644 sys/src/cmd/hg/templates/atom/map create mode 100644 sys/src/cmd/hg/templates/atom/tagentry.tmpl create mode 100644 sys/src/cmd/hg/templates/atom/tags.tmpl create mode 100644 sys/src/cmd/hg/templates/coal/header.tmpl create mode 100644 sys/src/cmd/hg/templates/coal/map create mode 100644 sys/src/cmd/hg/templates/gitweb/branches.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/changelog.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/changelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/changeset.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/error.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/fileannotate.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/filediff.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/filelog.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/filerevision.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/footer.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/graph.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/header.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/index.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/manifest.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/map create mode 100644 sys/src/cmd/hg/templates/gitweb/notfound.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/search.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/shortlog.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/summary.tmpl create mode 100644 sys/src/cmd/hg/templates/gitweb/tags.tmpl create mode 100644 sys/src/cmd/hg/templates/map-cmdline.changelog create mode 100644 sys/src/cmd/hg/templates/map-cmdline.compact create mode 100644 sys/src/cmd/hg/templates/map-cmdline.default create mode 100644 sys/src/cmd/hg/templates/monoblue/branches.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/changelog.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/changelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/changeset.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/error.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/fileannotate.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/filediff.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/filelog.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/filerevision.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/footer.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/graph.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/header.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/index.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/manifest.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/map create mode 100644 sys/src/cmd/hg/templates/monoblue/notfound.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/search.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/shortlog.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/summary.tmpl create mode 100644 sys/src/cmd/hg/templates/monoblue/tags.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/branches.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/changeset.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/error.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/fileannotate.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/filediff.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/filelog.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/filelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/filerevision.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/footer.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/graph.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/header.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/index.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/manifest.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/map create mode 100644 sys/src/cmd/hg/templates/paper/notfound.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/search.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/shortlog.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/shortlogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/paper/tags.tmpl create mode 100644 sys/src/cmd/hg/templates/raw/changeset.tmpl create mode 100644 sys/src/cmd/hg/templates/raw/error.tmpl create mode 100644 sys/src/cmd/hg/templates/raw/fileannotate.tmpl create mode 100644 sys/src/cmd/hg/templates/raw/filediff.tmpl create mode 100644 sys/src/cmd/hg/templates/raw/index.tmpl create mode 100644 sys/src/cmd/hg/templates/raw/manifest.tmpl create mode 100644 sys/src/cmd/hg/templates/raw/map create mode 100644 sys/src/cmd/hg/templates/raw/notfound.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/changelog.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/changelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/error.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/filelog.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/filelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/header.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/map create mode 100644 sys/src/cmd/hg/templates/rss/tagentry.tmpl create mode 100644 sys/src/cmd/hg/templates/rss/tags.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/branches.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/changelog.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/changelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/changeset.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/error.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/fileannotate.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/filediff.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/filelog.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/filelogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/filerevision.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/footer.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/graph.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/header.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/index.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/manifest.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/map create mode 100644 sys/src/cmd/hg/templates/spartan/notfound.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/search.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/shortlog.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/shortlogentry.tmpl create mode 100644 sys/src/cmd/hg/templates/spartan/tags.tmpl create mode 100644 sys/src/cmd/hg/templates/static/background.png create mode 100644 sys/src/cmd/hg/templates/static/coal-file.png create mode 100644 sys/src/cmd/hg/templates/static/coal-folder.png create mode 100644 sys/src/cmd/hg/templates/static/excanvas.js create mode 100644 sys/src/cmd/hg/templates/static/graph.js create mode 100644 sys/src/cmd/hg/templates/static/hgicon.png create mode 100644 sys/src/cmd/hg/templates/static/hglogo.png create mode 100644 sys/src/cmd/hg/templates/static/style-coal.css create mode 100644 sys/src/cmd/hg/templates/static/style-gitweb.css create mode 100644 sys/src/cmd/hg/templates/static/style-monoblue.css create mode 100644 sys/src/cmd/hg/templates/static/style-paper.css create mode 100644 sys/src/cmd/hg/templates/static/style.css create mode 100644 sys/src/cmd/hg/templates/template-vars.txt create mode 100644 sys/src/cmd/python/Demo/README create mode 100644 sys/src/cmd/python/Demo/cgi/README create mode 100755 sys/src/cmd/python/Demo/cgi/cgi0.sh create mode 100755 sys/src/cmd/python/Demo/cgi/cgi1.py create mode 100755 sys/src/cmd/python/Demo/cgi/cgi2.py create mode 100755 sys/src/cmd/python/Demo/cgi/cgi3.py create mode 100644 sys/src/cmd/python/Demo/cgi/wiki.py create mode 100755 sys/src/cmd/python/Demo/classes/Complex.py create mode 100755 sys/src/cmd/python/Demo/classes/Dates.py create mode 100755 sys/src/cmd/python/Demo/classes/Dbm.py create mode 100644 sys/src/cmd/python/Demo/classes/README create mode 100755 sys/src/cmd/python/Demo/classes/Range.py create mode 100755 sys/src/cmd/python/Demo/classes/Rat.py create mode 100755 sys/src/cmd/python/Demo/classes/Rev.py create mode 100755 sys/src/cmd/python/Demo/classes/Vec.py create mode 100755 sys/src/cmd/python/Demo/classes/bitvec.py create mode 100644 sys/src/cmd/python/Demo/comparisons/README create mode 100755 sys/src/cmd/python/Demo/comparisons/patterns create mode 100755 sys/src/cmd/python/Demo/comparisons/regextest.py create mode 100755 sys/src/cmd/python/Demo/comparisons/sortingtest.py create mode 100755 sys/src/cmd/python/Demo/comparisons/systemtest.py create mode 100644 sys/src/cmd/python/Demo/curses/README create mode 100755 sys/src/cmd/python/Demo/curses/life.py create mode 100644 sys/src/cmd/python/Demo/curses/ncurses.py create mode 100755 sys/src/cmd/python/Demo/curses/rain.py create mode 100755 sys/src/cmd/python/Demo/curses/repeat.py create mode 100644 sys/src/cmd/python/Demo/curses/tclock.py create mode 100644 sys/src/cmd/python/Demo/curses/xmas.py create mode 100644 sys/src/cmd/python/Demo/embed/Makefile create mode 100644 sys/src/cmd/python/Demo/embed/README create mode 100644 sys/src/cmd/python/Demo/embed/demo.c create mode 100644 sys/src/cmd/python/Demo/embed/importexc.c create mode 100644 sys/src/cmd/python/Demo/embed/loop.c create mode 100644 sys/src/cmd/python/Demo/imputil/importers.py create mode 100644 sys/src/cmd/python/Demo/imputil/knee.py create mode 100644 sys/src/cmd/python/Demo/md5test/README create mode 100755 sys/src/cmd/python/Demo/md5test/foo create mode 100755 sys/src/cmd/python/Demo/md5test/md5driver.py create mode 100644 sys/src/cmd/python/Demo/metaclasses/Eiffel.py create mode 100644 sys/src/cmd/python/Demo/metaclasses/Enum.py create mode 100644 sys/src/cmd/python/Demo/metaclasses/Meta.py create mode 100644 sys/src/cmd/python/Demo/metaclasses/Simple.py create mode 100644 sys/src/cmd/python/Demo/metaclasses/Synch.py create mode 100644 sys/src/cmd/python/Demo/metaclasses/Trace.py create mode 100644 sys/src/cmd/python/Demo/metaclasses/index.html create mode 100644 sys/src/cmd/python/Demo/metaclasses/meta-vladimir.txt create mode 100644 sys/src/cmd/python/Demo/newmetaclasses/Eiffel.py create mode 100644 sys/src/cmd/python/Demo/newmetaclasses/Enum.py create mode 100644 sys/src/cmd/python/Demo/parser/FILES create mode 100644 sys/src/cmd/python/Demo/parser/README create mode 100644 sys/src/cmd/python/Demo/parser/docstring.py create mode 100644 sys/src/cmd/python/Demo/parser/example.py create mode 100644 sys/src/cmd/python/Demo/parser/simple.py create mode 100644 sys/src/cmd/python/Demo/parser/source.py create mode 100755 sys/src/cmd/python/Demo/parser/test_parser.py create mode 100644 sys/src/cmd/python/Demo/parser/texipre.dat create mode 100644 sys/src/cmd/python/Demo/parser/unparse.py create mode 100755 sys/src/cmd/python/Demo/pdist/FSProxy.py create mode 100755 sys/src/cmd/python/Demo/pdist/RCSProxy.py create mode 100644 sys/src/cmd/python/Demo/pdist/README create mode 100755 sys/src/cmd/python/Demo/pdist/client.py create mode 100755 sys/src/cmd/python/Demo/pdist/cmdfw.py create mode 100755 sys/src/cmd/python/Demo/pdist/cmptree.py create mode 100755 sys/src/cmd/python/Demo/pdist/cvslib.py create mode 100755 sys/src/cmd/python/Demo/pdist/cvslock.py create mode 100755 sys/src/cmd/python/Demo/pdist/mac.py create mode 100755 sys/src/cmd/python/Demo/pdist/makechangelog.py create mode 100755 sys/src/cmd/python/Demo/pdist/rcsbump create mode 100755 sys/src/cmd/python/Demo/pdist/rcsclient.py create mode 100755 sys/src/cmd/python/Demo/pdist/rcslib.py create mode 100755 sys/src/cmd/python/Demo/pdist/rcvs create mode 100755 sys/src/cmd/python/Demo/pdist/rcvs.py create mode 100755 sys/src/cmd/python/Demo/pdist/rrcs create mode 100755 sys/src/cmd/python/Demo/pdist/rrcs.py create mode 100755 sys/src/cmd/python/Demo/pdist/security.py create mode 100755 sys/src/cmd/python/Demo/pdist/server.py create mode 100755 sys/src/cmd/python/Demo/pdist/sumtree.py create mode 100644 sys/src/cmd/python/Demo/pysvr/Makefile create mode 100644 sys/src/cmd/python/Demo/pysvr/README create mode 100644 sys/src/cmd/python/Demo/pysvr/pysvr.c create mode 100755 sys/src/cmd/python/Demo/pysvr/pysvr.py create mode 100644 sys/src/cmd/python/Demo/rpc/MANIFEST create mode 100644 sys/src/cmd/python/Demo/rpc/README create mode 100644 sys/src/cmd/python/Demo/rpc/T.py create mode 100644 sys/src/cmd/python/Demo/rpc/mountclient.py create mode 100644 sys/src/cmd/python/Demo/rpc/nfsclient.py create mode 100644 sys/src/cmd/python/Demo/rpc/rnusersclient.py create mode 100644 sys/src/cmd/python/Demo/rpc/rpc.py create mode 100755 sys/src/cmd/python/Demo/rpc/test create mode 100644 sys/src/cmd/python/Demo/rpc/xdr.py create mode 100644 sys/src/cmd/python/Demo/scripts/README create mode 100644 sys/src/cmd/python/Demo/scripts/beer.py create mode 100755 sys/src/cmd/python/Demo/scripts/eqfix.py create mode 100755 sys/src/cmd/python/Demo/scripts/fact.py create mode 100644 sys/src/cmd/python/Demo/scripts/find-uname.py create mode 100755 sys/src/cmd/python/Demo/scripts/from.py create mode 100755 sys/src/cmd/python/Demo/scripts/ftpstats.py create mode 100755 sys/src/cmd/python/Demo/scripts/lpwatch.py create mode 100755 sys/src/cmd/python/Demo/scripts/makedir.py create mode 100755 sys/src/cmd/python/Demo/scripts/markov.py create mode 100755 sys/src/cmd/python/Demo/scripts/mboxconvert.py create mode 100755 sys/src/cmd/python/Demo/scripts/mkrcs.py create mode 100755 sys/src/cmd/python/Demo/scripts/morse.py create mode 100755 sys/src/cmd/python/Demo/scripts/newslist.doc create mode 100755 sys/src/cmd/python/Demo/scripts/newslist.py create mode 100755 sys/src/cmd/python/Demo/scripts/pi.py create mode 100755 sys/src/cmd/python/Demo/scripts/pp.py create mode 100755 sys/src/cmd/python/Demo/scripts/primes.py create mode 100755 sys/src/cmd/python/Demo/scripts/queens.py create mode 100755 sys/src/cmd/python/Demo/scripts/script.py create mode 100755 sys/src/cmd/python/Demo/scripts/unbirthday.py create mode 100755 sys/src/cmd/python/Demo/scripts/update.py create mode 100755 sys/src/cmd/python/Demo/scripts/wh.py create mode 100644 sys/src/cmd/python/Demo/sockets/README create mode 100755 sys/src/cmd/python/Demo/sockets/broadcast.py create mode 100755 sys/src/cmd/python/Demo/sockets/echosvr.py create mode 100755 sys/src/cmd/python/Demo/sockets/finger.py create mode 100755 sys/src/cmd/python/Demo/sockets/ftp.py create mode 100755 sys/src/cmd/python/Demo/sockets/gopher.py create mode 100755 sys/src/cmd/python/Demo/sockets/mcast.py create mode 100755 sys/src/cmd/python/Demo/sockets/radio.py create mode 100755 sys/src/cmd/python/Demo/sockets/rpython.py create mode 100755 sys/src/cmd/python/Demo/sockets/rpythond.py create mode 100755 sys/src/cmd/python/Demo/sockets/telnet.py create mode 100755 sys/src/cmd/python/Demo/sockets/throughput.py create mode 100755 sys/src/cmd/python/Demo/sockets/udpecho.py create mode 100644 sys/src/cmd/python/Demo/sockets/unicast.py create mode 100644 sys/src/cmd/python/Demo/sockets/unixclient.py create mode 100644 sys/src/cmd/python/Demo/sockets/unixserver.py create mode 100644 sys/src/cmd/python/Demo/threads/Coroutine.py create mode 100644 sys/src/cmd/python/Demo/threads/Generator.py create mode 100644 sys/src/cmd/python/Demo/threads/README create mode 100644 sys/src/cmd/python/Demo/threads/fcmp.py create mode 100644 sys/src/cmd/python/Demo/threads/find.py create mode 100644 sys/src/cmd/python/Demo/threads/squasher.py create mode 100644 sys/src/cmd/python/Demo/threads/sync.py create mode 100644 sys/src/cmd/python/Demo/threads/telnet.py create mode 100644 sys/src/cmd/python/Demo/tix/INSTALL.txt create mode 100644 sys/src/cmd/python/Demo/tix/README.txt create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/about.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/bold.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/capital.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/centerj.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/combobox.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/combobox.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/drivea.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/drivea.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/exit.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/filebox.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/filebox.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/italic.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/justify.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/leftj.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/netw.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/netw.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/optmenu.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/rightj.xbm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/select.xpm create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/tix.gif create mode 100755 sys/src/cmd/python/Demo/tix/bitmaps/underline.xbm create mode 100644 sys/src/cmd/python/Demo/tix/grid.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/Balloon.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/BtnBox.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/CmpImg.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/ComboBox.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/Control.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/DirList.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/DirTree.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/NoteBook.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/OptMenu.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/PanedWin.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/PopMenu.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/SHList1.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/SHList2.py create mode 100755 sys/src/cmd/python/Demo/tix/samples/Tree.py create mode 100644 sys/src/cmd/python/Demo/tix/tixwidgets.py create mode 100644 sys/src/cmd/python/Demo/tkinter/README create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/AttrDialog.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/ManPage.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/MimeViewer.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/ShellWindow.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/brownian.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/canvasevents.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/dialog.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/electrons.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/hanoi.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/hello.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/imagedraw.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/imageview.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/kill.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/listtree.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/mbox.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/newmenubardemo.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/optionmenu.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/paint.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/rmt.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/solitaire.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/sortvisu.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/ss1.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/svkill.py create mode 100644 sys/src/cmd/python/Demo/tkinter/guido/switch.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/tkman.py create mode 100755 sys/src/cmd/python/Demo/tkinter/guido/wish.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/00-HELLO-WORLD.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/README create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/animation-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/animation-w-velocity-ctrl.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/bind-w-mult-calls-p-type.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-demo-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-gridding.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-moving-or-creating.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-moving-w-mouse.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-mult-item-sel.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-reading-tag-info.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-w-widget-draw-el.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/canvas-with-scrollbars.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/dialog-box.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/entry-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/entry-with-shared-variable.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/killing-window-w-wm.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/menu-all-types-of-entries.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/menu-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/not-what-you-might-think-1.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/not-what-you-might-think-2.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/packer-and-placer-together.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/packer-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/placer-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/pong-demo-1.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/printing-coords-of-items.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/radiobutton-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/rubber-band-box-demo-1.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/rubber-line-demo-1.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/slider-demo-1.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/subclass-existing-widgets.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/two-radio-groups.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/window-creation-more.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/window-creation-simple.py create mode 100644 sys/src/cmd/python/Demo/tkinter/matt/window-creation-w-location.py create mode 100644 sys/src/cmd/python/Demo/xml/elem_count.py create mode 100644 sys/src/cmd/python/Demo/xml/roundtrip.py create mode 100644 sys/src/cmd/python/Demo/xml/rss2html.py create mode 100755 sys/src/cmd/python/Demo/zlib/minigzip.py create mode 100644 sys/src/cmd/python/Demo/zlib/zlibdemo.py create mode 100644 sys/src/cmd/python/Demo/zlib/zlibdemo.py.gz create mode 100644 sys/src/cmd/python/Doc/ACKS create mode 100644 sys/src/cmd/python/Doc/Makefile create mode 100644 sys/src/cmd/python/Doc/Makefile.deps create mode 100644 sys/src/cmd/python/Doc/README create mode 100644 sys/src/cmd/python/Doc/TODO create mode 100644 sys/src/cmd/python/Doc/api/abstract.tex create mode 100644 sys/src/cmd/python/Doc/api/api.tex create mode 100644 sys/src/cmd/python/Doc/api/concrete.tex create mode 100644 sys/src/cmd/python/Doc/api/exceptions.tex create mode 100644 sys/src/cmd/python/Doc/api/init.tex create mode 100644 sys/src/cmd/python/Doc/api/intro.tex create mode 100644 sys/src/cmd/python/Doc/api/memory.tex create mode 100644 sys/src/cmd/python/Doc/api/newtypes.tex create mode 100644 sys/src/cmd/python/Doc/api/refcounting.tex create mode 100644 sys/src/cmd/python/Doc/api/refcounts.dat create mode 100644 sys/src/cmd/python/Doc/api/utilities.tex create mode 100644 sys/src/cmd/python/Doc/api/veryhigh.tex create mode 100644 sys/src/cmd/python/Doc/commontex/boilerplate.tex create mode 100644 sys/src/cmd/python/Doc/commontex/copyright.tex create mode 100644 sys/src/cmd/python/Doc/commontex/license.tex create mode 100644 sys/src/cmd/python/Doc/commontex/reportingbugs.tex create mode 100644 sys/src/cmd/python/Doc/commontex/typestruct.h create mode 100644 sys/src/cmd/python/Doc/dist/dist.tex create mode 100644 sys/src/cmd/python/Doc/dist/sysconfig.tex create mode 100644 sys/src/cmd/python/Doc/doc/doc.tex create mode 100644 sys/src/cmd/python/Doc/ext/building.tex create mode 100644 sys/src/cmd/python/Doc/ext/embedding.tex create mode 100644 sys/src/cmd/python/Doc/ext/ext.tex create mode 100644 sys/src/cmd/python/Doc/ext/extending.tex create mode 100644 sys/src/cmd/python/Doc/ext/newtypes.tex create mode 100644 sys/src/cmd/python/Doc/ext/noddy.c create mode 100644 sys/src/cmd/python/Doc/ext/noddy2.c create mode 100644 sys/src/cmd/python/Doc/ext/noddy3.c create mode 100644 sys/src/cmd/python/Doc/ext/noddy4.c create mode 100644 sys/src/cmd/python/Doc/ext/run-func.c create mode 100644 sys/src/cmd/python/Doc/ext/setup.py create mode 100644 sys/src/cmd/python/Doc/ext/shoddy.c create mode 100644 sys/src/cmd/python/Doc/ext/test.py create mode 100644 sys/src/cmd/python/Doc/ext/windows.tex create mode 100644 sys/src/cmd/python/Doc/howto/Makefile create mode 100644 sys/src/cmd/python/Doc/howto/TODO create mode 100644 sys/src/cmd/python/Doc/howto/advocacy.tex create mode 100644 sys/src/cmd/python/Doc/howto/curses.tex create mode 100644 sys/src/cmd/python/Doc/howto/doanddont.tex create mode 100644 sys/src/cmd/python/Doc/howto/regex.tex create mode 100644 sys/src/cmd/python/Doc/howto/sockets.tex create mode 100644 sys/src/cmd/python/Doc/howto/unicode.rst create mode 100644 sys/src/cmd/python/Doc/howto/urllib2.rst create mode 100644 sys/src/cmd/python/Doc/html/about.dat create mode 100644 sys/src/cmd/python/Doc/html/about.html create mode 100644 sys/src/cmd/python/Doc/html/icons/blank.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/blank.png create mode 100644 sys/src/cmd/python/Doc/html/icons/contents.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/contents.png create mode 100644 sys/src/cmd/python/Doc/html/icons/index.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/index.png create mode 100644 sys/src/cmd/python/Doc/html/icons/modules.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/modules.png create mode 100644 sys/src/cmd/python/Doc/html/icons/next.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/next.png create mode 100644 sys/src/cmd/python/Doc/html/icons/previous.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/previous.png create mode 100644 sys/src/cmd/python/Doc/html/icons/pyfav.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/pyfav.png create mode 100644 sys/src/cmd/python/Doc/html/icons/up.gif create mode 100644 sys/src/cmd/python/Doc/html/icons/up.png create mode 100644 sys/src/cmd/python/Doc/html/index.html.in create mode 100644 sys/src/cmd/python/Doc/html/stdabout.dat create mode 100644 sys/src/cmd/python/Doc/html/style.css create mode 100644 sys/src/cmd/python/Doc/info/Makefile create mode 100644 sys/src/cmd/python/Doc/info/README create mode 100644 sys/src/cmd/python/Doc/info/python.dir create mode 100644 sys/src/cmd/python/Doc/inst/inst.tex create mode 100644 sys/src/cmd/python/Doc/lib/archiving.tex create mode 100644 sys/src/cmd/python/Doc/lib/asttable.tex create mode 100755 sys/src/cmd/python/Doc/lib/caseless.py create mode 100644 sys/src/cmd/python/Doc/lib/compiler.tex create mode 100644 sys/src/cmd/python/Doc/lib/custominterp.tex create mode 100644 sys/src/cmd/python/Doc/lib/datatypes.tex create mode 100644 sys/src/cmd/python/Doc/lib/development.tex create mode 100644 sys/src/cmd/python/Doc/lib/distutils.tex create mode 100644 sys/src/cmd/python/Doc/lib/email-dir.py create mode 100644 sys/src/cmd/python/Doc/lib/email-mime.py create mode 100644 sys/src/cmd/python/Doc/lib/email-simple.py create mode 100644 sys/src/cmd/python/Doc/lib/email-unpack.py create mode 100644 sys/src/cmd/python/Doc/lib/email.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailcharsets.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailencoders.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailexc.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailgenerator.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailheaders.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailiter.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailmessage.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailmimebase.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailparser.tex create mode 100644 sys/src/cmd/python/Doc/lib/emailutil.tex create mode 100644 sys/src/cmd/python/Doc/lib/fileformats.tex create mode 100644 sys/src/cmd/python/Doc/lib/filesys.tex create mode 100644 sys/src/cmd/python/Doc/lib/frameworks.tex create mode 100644 sys/src/cmd/python/Doc/lib/i18n.tex create mode 100644 sys/src/cmd/python/Doc/lib/internet.tex create mode 100644 sys/src/cmd/python/Doc/lib/ipc.tex create mode 100644 sys/src/cmd/python/Doc/lib/language.tex create mode 100644 sys/src/cmd/python/Doc/lib/lib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libaifc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libal.tex create mode 100644 sys/src/cmd/python/Doc/lib/liballos.tex create mode 100644 sys/src/cmd/python/Doc/lib/libamoeba.tex create mode 100644 sys/src/cmd/python/Doc/lib/libanydbm.tex create mode 100644 sys/src/cmd/python/Doc/lib/libarray.tex create mode 100644 sys/src/cmd/python/Doc/lib/libascii.tex create mode 100644 sys/src/cmd/python/Doc/lib/libast.tex create mode 100644 sys/src/cmd/python/Doc/lib/libasynchat.tex create mode 100644 sys/src/cmd/python/Doc/lib/libasyncore.tex create mode 100644 sys/src/cmd/python/Doc/lib/libatexit.tex create mode 100644 sys/src/cmd/python/Doc/lib/libaudioop.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbase64.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbasehttp.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbastion.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbinascii.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbinhex.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbisect.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbltin.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbsddb.tex create mode 100644 sys/src/cmd/python/Doc/lib/libbz2.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcalendar.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcd.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcfgparser.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcgi.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcgihttp.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcgitb.tex create mode 100644 sys/src/cmd/python/Doc/lib/libchunk.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcmath.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcmd.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcmp.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcmpcache.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcode.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcodecs.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcodeop.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcollections.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcolorsys.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcommands.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcompileall.tex create mode 100644 sys/src/cmd/python/Doc/lib/libconsts.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcontextlib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcookie.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcookielib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcopy.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcopyreg.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcrypt.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcrypto.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcsv.tex create mode 100755 sys/src/cmd/python/Doc/lib/libctypes.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcurses.tex create mode 100644 sys/src/cmd/python/Doc/lib/libcursespanel.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdatetime.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdbhash.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdbm.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdecimal.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdifflib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdircache.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdis.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdl.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdoctest.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdocxmlrpc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdumbdbm.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdummythread.tex create mode 100644 sys/src/cmd/python/Doc/lib/libdummythreading.tex create mode 100644 sys/src/cmd/python/Doc/lib/liberrno.tex create mode 100644 sys/src/cmd/python/Doc/lib/libetree.tex create mode 100644 sys/src/cmd/python/Doc/lib/libexcs.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfcntl.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfilecmp.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfileinput.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfl.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfm.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfnmatch.tex create mode 100644 sys/src/cmd/python/Doc/lib/libformatter.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfpectl.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfpformat.tex create mode 100644 sys/src/cmd/python/Doc/lib/libftplib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfuncs.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfunctools.tex create mode 100644 sys/src/cmd/python/Doc/lib/libfuture.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgdbm.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgetopt.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgetpass.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgettext.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgl.tex create mode 100644 sys/src/cmd/python/Doc/lib/libglob.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgopherlib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgrp.tex create mode 100644 sys/src/cmd/python/Doc/lib/libgzip.tex create mode 100644 sys/src/cmd/python/Doc/lib/libhashlib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libheapq.tex create mode 100644 sys/src/cmd/python/Doc/lib/libhmac.tex create mode 100644 sys/src/cmd/python/Doc/lib/libhotshot.tex create mode 100644 sys/src/cmd/python/Doc/lib/libhtmllib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libhtmlparser.tex create mode 100644 sys/src/cmd/python/Doc/lib/libhttplib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libimageop.tex create mode 100644 sys/src/cmd/python/Doc/lib/libimaplib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libimgfile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libimghdr.tex create mode 100644 sys/src/cmd/python/Doc/lib/libimp.tex create mode 100644 sys/src/cmd/python/Doc/lib/libinspect.tex create mode 100644 sys/src/cmd/python/Doc/lib/libintro.tex create mode 100644 sys/src/cmd/python/Doc/lib/libitertools.tex create mode 100644 sys/src/cmd/python/Doc/lib/libjpeg.tex create mode 100644 sys/src/cmd/python/Doc/lib/libkeyword.tex create mode 100644 sys/src/cmd/python/Doc/lib/liblinecache.tex create mode 100644 sys/src/cmd/python/Doc/lib/liblocale.tex create mode 100644 sys/src/cmd/python/Doc/lib/liblogging.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmailbox.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmailcap.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmain.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmarshal.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmath.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmd5.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmhlib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmimetools.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmimetypes.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmimewriter.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmimify.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmisc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmm.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmmap.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmodulefinder.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmsilib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmsvcrt.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmultifile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libmutex.tex create mode 100644 sys/src/cmd/python/Doc/lib/libnetrc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libnew.tex create mode 100644 sys/src/cmd/python/Doc/lib/libni.tex create mode 100644 sys/src/cmd/python/Doc/lib/libnis.tex create mode 100644 sys/src/cmd/python/Doc/lib/libnntplib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libobjs.tex create mode 100644 sys/src/cmd/python/Doc/lib/liboperator.tex create mode 100644 sys/src/cmd/python/Doc/lib/liboptparse.tex create mode 100644 sys/src/cmd/python/Doc/lib/libos.tex create mode 100644 sys/src/cmd/python/Doc/lib/libossaudiodev.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpanel.tex create mode 100644 sys/src/cmd/python/Doc/lib/libparser.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpdb.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpickle.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpickletools.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpipes.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpkgutil.tex create mode 100644 sys/src/cmd/python/Doc/lib/libplatform.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpopen2.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpoplib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libposix.tex create mode 100644 sys/src/cmd/python/Doc/lib/libposixfile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libposixpath.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpprint.tex create mode 100644 sys/src/cmd/python/Doc/lib/libprofile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpty.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpwd.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpyclbr.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpycompile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpydoc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpyexpat.tex create mode 100644 sys/src/cmd/python/Doc/lib/libpython.tex create mode 100644 sys/src/cmd/python/Doc/lib/libqueue.tex create mode 100644 sys/src/cmd/python/Doc/lib/libquopri.tex create mode 100644 sys/src/cmd/python/Doc/lib/librandom.tex create mode 100644 sys/src/cmd/python/Doc/lib/libre.tex create mode 100644 sys/src/cmd/python/Doc/lib/libreadline.tex create mode 100644 sys/src/cmd/python/Doc/lib/librepr.tex create mode 100644 sys/src/cmd/python/Doc/lib/libresource.tex create mode 100644 sys/src/cmd/python/Doc/lib/librestricted.tex create mode 100644 sys/src/cmd/python/Doc/lib/librexec.tex create mode 100644 sys/src/cmd/python/Doc/lib/librfc822.tex create mode 100644 sys/src/cmd/python/Doc/lib/librgbimg.tex create mode 100644 sys/src/cmd/python/Doc/lib/librlcompleter.tex create mode 100644 sys/src/cmd/python/Doc/lib/librobotparser.tex create mode 100644 sys/src/cmd/python/Doc/lib/librunpy.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsched.tex create mode 100644 sys/src/cmd/python/Doc/lib/libselect.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsets.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsgi.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsgmllib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsha.tex create mode 100644 sys/src/cmd/python/Doc/lib/libshelve.tex create mode 100644 sys/src/cmd/python/Doc/lib/libshlex.tex create mode 100644 sys/src/cmd/python/Doc/lib/libshutil.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsignal.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsimplehttp.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsimplexmlrpc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsite.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsmtpd.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsmtplib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsndhdr.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsocket.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsocksvr.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsomeos.tex create mode 100644 sys/src/cmd/python/Doc/lib/libspwd.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsqlite3.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstat.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstatvfs.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstdtypes.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstdwin.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstring.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstringio.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstringprep.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstrings.tex create mode 100644 sys/src/cmd/python/Doc/lib/libstruct.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsubprocess.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsun.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsunau.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsunaudio.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsymbol.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsys.tex create mode 100644 sys/src/cmd/python/Doc/lib/libsyslog.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtabnanny.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtarfile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtelnetlib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtempfile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtermios.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtest.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtextwrap.tex create mode 100644 sys/src/cmd/python/Doc/lib/libthread.tex create mode 100644 sys/src/cmd/python/Doc/lib/libthreading.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtime.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtimeit.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtoken.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtokenize.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtrace.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtraceback.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtty.tex create mode 100644 sys/src/cmd/python/Doc/lib/libturtle.tex create mode 100644 sys/src/cmd/python/Doc/lib/libtypes.tex create mode 100644 sys/src/cmd/python/Doc/lib/libundoc.tex create mode 100644 sys/src/cmd/python/Doc/lib/libunicodedata.tex create mode 100644 sys/src/cmd/python/Doc/lib/libunittest.tex create mode 100644 sys/src/cmd/python/Doc/lib/libunix.tex create mode 100644 sys/src/cmd/python/Doc/lib/liburllib.tex create mode 100644 sys/src/cmd/python/Doc/lib/liburllib2.tex create mode 100644 sys/src/cmd/python/Doc/lib/liburlparse.tex create mode 100644 sys/src/cmd/python/Doc/lib/libuser.tex create mode 100644 sys/src/cmd/python/Doc/lib/libuserdict.tex create mode 100644 sys/src/cmd/python/Doc/lib/libuu.tex create mode 100644 sys/src/cmd/python/Doc/lib/libuuid.tex create mode 100644 sys/src/cmd/python/Doc/lib/libwarnings.tex create mode 100644 sys/src/cmd/python/Doc/lib/libwave.tex create mode 100644 sys/src/cmd/python/Doc/lib/libweakref.tex create mode 100644 sys/src/cmd/python/Doc/lib/libwebbrowser.tex create mode 100644 sys/src/cmd/python/Doc/lib/libwhichdb.tex create mode 100644 sys/src/cmd/python/Doc/lib/libwinreg.tex create mode 100644 sys/src/cmd/python/Doc/lib/libwinsound.tex create mode 100755 sys/src/cmd/python/Doc/lib/libwsgiref.tex create mode 100644 sys/src/cmd/python/Doc/lib/libxdrlib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libxmllib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libxmlrpclib.tex create mode 100644 sys/src/cmd/python/Doc/lib/libzipfile.tex create mode 100644 sys/src/cmd/python/Doc/lib/libzipimport.tex create mode 100644 sys/src/cmd/python/Doc/lib/libzlib.tex create mode 100644 sys/src/cmd/python/Doc/lib/markup.tex create mode 100644 sys/src/cmd/python/Doc/lib/mimelib.tex create mode 100644 sys/src/cmd/python/Doc/lib/minidom-example.py create mode 100644 sys/src/cmd/python/Doc/lib/modules.tex create mode 100644 sys/src/cmd/python/Doc/lib/netdata.tex create mode 100644 sys/src/cmd/python/Doc/lib/numeric.tex create mode 100644 sys/src/cmd/python/Doc/lib/persistence.tex create mode 100755 sys/src/cmd/python/Doc/lib/required_1.py create mode 100755 sys/src/cmd/python/Doc/lib/required_2.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/adapter_datetime.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_1.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_2.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/collation_reverse.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/complete_statement.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/connect_db_1.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/connect_db_2.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/converter_point.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/countcursors.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/createdb.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/execsql_fetchonerow.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/execsql_printall_1.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/execute_1.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/execute_2.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/execute_3.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/executemany_1.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/executemany_2.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/executescript.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/insert_more_people.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/md5func.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/mysumaggr.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/parse_colnames.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/pysqlite_datetime.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/row_factory.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/rowclass.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/shared_cache.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/shortcut_methods.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/simple_tableprinter.py create mode 100644 sys/src/cmd/python/Doc/lib/sqlite3/text_factory.py create mode 100644 sys/src/cmd/python/Doc/lib/tkinter.tex create mode 100644 sys/src/cmd/python/Doc/lib/tzinfo-examples.py create mode 100644 sys/src/cmd/python/Doc/lib/windows.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmldom.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmldomminidom.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmldompulldom.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmletree.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmlsax.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmlsaxhandler.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmlsaxreader.tex create mode 100644 sys/src/cmd/python/Doc/lib/xmlsaxutils.tex create mode 100644 sys/src/cmd/python/Doc/mac/libaepack.tex create mode 100644 sys/src/cmd/python/Doc/mac/libaetools.tex create mode 100644 sys/src/cmd/python/Doc/mac/libaetypes.tex create mode 100644 sys/src/cmd/python/Doc/mac/libautogil.tex create mode 100644 sys/src/cmd/python/Doc/mac/libcolorpicker.tex create mode 100644 sys/src/cmd/python/Doc/mac/libframework.tex create mode 100644 sys/src/cmd/python/Doc/mac/libgensuitemodule.tex create mode 100644 sys/src/cmd/python/Doc/mac/libmac.tex create mode 100644 sys/src/cmd/python/Doc/mac/libmacfs.tex create mode 100644 sys/src/cmd/python/Doc/mac/libmacic.tex create mode 100644 sys/src/cmd/python/Doc/mac/libmacos.tex create mode 100644 sys/src/cmd/python/Doc/mac/libmacostools.tex create mode 100644 sys/src/cmd/python/Doc/mac/libmacui.tex create mode 100644 sys/src/cmd/python/Doc/mac/libminiae.tex create mode 100644 sys/src/cmd/python/Doc/mac/libscrap.tex create mode 100644 sys/src/cmd/python/Doc/mac/mac.tex create mode 100644 sys/src/cmd/python/Doc/mac/scripting.tex create mode 100644 sys/src/cmd/python/Doc/mac/toolbox.tex create mode 100644 sys/src/cmd/python/Doc/mac/undoc.tex create mode 100644 sys/src/cmd/python/Doc/mac/using.tex create mode 100644 sys/src/cmd/python/Doc/paper-a4/pypaper.sty create mode 100644 sys/src/cmd/python/Doc/perl/SynopsisTable.pm create mode 100644 sys/src/cmd/python/Doc/perl/distutils.perl create mode 100644 sys/src/cmd/python/Doc/perl/howto.perl create mode 100644 sys/src/cmd/python/Doc/perl/isilo.perl create mode 100644 sys/src/cmd/python/Doc/perl/l2hinit.perl create mode 100644 sys/src/cmd/python/Doc/perl/ltxmarkup.perl create mode 100644 sys/src/cmd/python/Doc/perl/manual.perl create mode 100644 sys/src/cmd/python/Doc/perl/python.perl create mode 100644 sys/src/cmd/python/Doc/python-docs.txt create mode 100644 sys/src/cmd/python/Doc/ref/ref.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref1.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref2.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref3.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref4.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref5.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref6.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref7.tex create mode 100644 sys/src/cmd/python/Doc/ref/ref8.tex create mode 100644 sys/src/cmd/python/Doc/ref/reswords.py create mode 100644 sys/src/cmd/python/Doc/templates/howto.tex create mode 100644 sys/src/cmd/python/Doc/templates/manual.tex create mode 100644 sys/src/cmd/python/Doc/templates/module.tex create mode 100644 sys/src/cmd/python/Doc/templates/whatsnewXY.tex create mode 100644 sys/src/cmd/python/Doc/tests/math.tex create mode 100644 sys/src/cmd/python/Doc/texinputs/distutils.sty create mode 100644 sys/src/cmd/python/Doc/texinputs/fancyhdr.sty create mode 100644 sys/src/cmd/python/Doc/texinputs/fncychap.sty create mode 100644 sys/src/cmd/python/Doc/texinputs/howto.cls create mode 100644 sys/src/cmd/python/Doc/texinputs/ltxmarkup.sty create mode 100644 sys/src/cmd/python/Doc/texinputs/manual.cls create mode 100644 sys/src/cmd/python/Doc/texinputs/pypaper.sty create mode 100644 sys/src/cmd/python/Doc/texinputs/python.ist create mode 100644 sys/src/cmd/python/Doc/texinputs/python.sty create mode 100644 sys/src/cmd/python/Doc/texinputs/underscore.sty create mode 100755 sys/src/cmd/python/Doc/tools/anno-api.py create mode 100755 sys/src/cmd/python/Doc/tools/buildindex.py create mode 100644 sys/src/cmd/python/Doc/tools/checkargs.pm create mode 100755 sys/src/cmd/python/Doc/tools/cklatex create mode 100755 sys/src/cmd/python/Doc/tools/cmpcsyms create mode 100644 sys/src/cmd/python/Doc/tools/custlib.py create mode 100755 sys/src/cmd/python/Doc/tools/findcsyms create mode 100755 sys/src/cmd/python/Doc/tools/findmodrefs create mode 100755 sys/src/cmd/python/Doc/tools/findsyms create mode 100755 sys/src/cmd/python/Doc/tools/fix_hack create mode 100755 sys/src/cmd/python/Doc/tools/fix_libaux.sed create mode 100644 sys/src/cmd/python/Doc/tools/fixinfo.el create mode 100755 sys/src/cmd/python/Doc/tools/getpagecounts create mode 100755 sys/src/cmd/python/Doc/tools/getversioninfo create mode 100755 sys/src/cmd/python/Doc/tools/html2texi.pl create mode 100755 sys/src/cmd/python/Doc/tools/indfix.py create mode 100644 sys/src/cmd/python/Doc/tools/keywords.py create mode 100755 sys/src/cmd/python/Doc/tools/listmodules create mode 100644 sys/src/cmd/python/Doc/tools/listmodules.py create mode 100755 sys/src/cmd/python/Doc/tools/makesec.sh create mode 100755 sys/src/cmd/python/Doc/tools/mkackshtml create mode 100755 sys/src/cmd/python/Doc/tools/mkhowto create mode 100755 sys/src/cmd/python/Doc/tools/mkinfo create mode 100755 sys/src/cmd/python/Doc/tools/mkmodindex create mode 100755 sys/src/cmd/python/Doc/tools/mkpkglist create mode 100755 sys/src/cmd/python/Doc/tools/mksourcepkg create mode 100755 sys/src/cmd/python/Doc/tools/node2label.pl create mode 100644 sys/src/cmd/python/Doc/tools/prechm.py create mode 100755 sys/src/cmd/python/Doc/tools/push-docs.sh create mode 100644 sys/src/cmd/python/Doc/tools/py2texi.el create mode 100644 sys/src/cmd/python/Doc/tools/refcounts.py create mode 100644 sys/src/cmd/python/Doc/tools/rewrite.py create mode 100644 sys/src/cmd/python/Doc/tools/sgmlconv/Makefile create mode 100644 sys/src/cmd/python/Doc/tools/sgmlconv/README create mode 100644 sys/src/cmd/python/Doc/tools/sgmlconv/conversion.xml create mode 100755 sys/src/cmd/python/Doc/tools/sgmlconv/docfixer.py create mode 100755 sys/src/cmd/python/Doc/tools/sgmlconv/esis2sgml.py create mode 100644 sys/src/cmd/python/Doc/tools/sgmlconv/esistools.py create mode 100755 sys/src/cmd/python/Doc/tools/sgmlconv/latex2esis.py create mode 100644 sys/src/cmd/python/Doc/tools/sgmlconv/make.rules create mode 100644 sys/src/cmd/python/Doc/tools/support.py create mode 100755 sys/src/cmd/python/Doc/tools/toc2bkm.py create mode 100644 sys/src/cmd/python/Doc/tools/undoc_symbols.py create mode 100755 sys/src/cmd/python/Doc/tools/update-docs.sh create mode 100755 sys/src/cmd/python/Doc/tools/whichlibs create mode 100644 sys/src/cmd/python/Doc/tut/glossary.tex create mode 100644 sys/src/cmd/python/Doc/tut/tut.tex create mode 100644 sys/src/cmd/python/Doc/whatsnew/Makefile create mode 100644 sys/src/cmd/python/Doc/whatsnew/whatsnew20.tex create mode 100644 sys/src/cmd/python/Doc/whatsnew/whatsnew21.tex create mode 100644 sys/src/cmd/python/Doc/whatsnew/whatsnew22.tex create mode 100644 sys/src/cmd/python/Doc/whatsnew/whatsnew23.tex create mode 100644 sys/src/cmd/python/Doc/whatsnew/whatsnew24.tex create mode 100644 sys/src/cmd/python/Doc/whatsnew/whatsnew25.tex create mode 100644 sys/src/cmd/python/Extra/dummy.c create mode 100644 sys/src/cmd/python/Extra/mercurial/base85.c create mode 100644 sys/src/cmd/python/Extra/mercurial/bdiff.c create mode 100644 sys/src/cmd/python/Extra/mercurial/diffhelpers.c create mode 100644 sys/src/cmd/python/Extra/mercurial/mpatch.c create mode 100644 sys/src/cmd/python/Extra/mercurial/osutil.c create mode 100644 sys/src/cmd/python/Extra/mercurial/parsers.c create mode 100644 sys/src/cmd/python/Extra/mkfile create mode 100644 sys/src/cmd/python/Grammar/Grammar create mode 100644 sys/src/cmd/python/Include/Python-ast.h create mode 100644 sys/src/cmd/python/Include/Python.h create mode 100644 sys/src/cmd/python/Include/abstract.h create mode 100644 sys/src/cmd/python/Include/asdl.h create mode 100644 sys/src/cmd/python/Include/ast.h create mode 100644 sys/src/cmd/python/Include/bitset.h create mode 100644 sys/src/cmd/python/Include/boolobject.h create mode 100644 sys/src/cmd/python/Include/bufferobject.h create mode 100644 sys/src/cmd/python/Include/cStringIO.h create mode 100644 sys/src/cmd/python/Include/cellobject.h create mode 100644 sys/src/cmd/python/Include/ceval.h create mode 100644 sys/src/cmd/python/Include/classobject.h create mode 100644 sys/src/cmd/python/Include/cobject.h create mode 100644 sys/src/cmd/python/Include/code.h create mode 100644 sys/src/cmd/python/Include/codecs.h create mode 100644 sys/src/cmd/python/Include/compile.h create mode 100644 sys/src/cmd/python/Include/complexobject.h create mode 100644 sys/src/cmd/python/Include/datetime.h create mode 100644 sys/src/cmd/python/Include/descrobject.h create mode 100644 sys/src/cmd/python/Include/dictobject.h create mode 100644 sys/src/cmd/python/Include/enumobject.h create mode 100644 sys/src/cmd/python/Include/errcode.h create mode 100644 sys/src/cmd/python/Include/eval.h create mode 100644 sys/src/cmd/python/Include/fileobject.h create mode 100644 sys/src/cmd/python/Include/floatobject.h create mode 100644 sys/src/cmd/python/Include/frameobject.h create mode 100644 sys/src/cmd/python/Include/funcobject.h create mode 100644 sys/src/cmd/python/Include/genobject.h create mode 100644 sys/src/cmd/python/Include/graminit.h create mode 100644 sys/src/cmd/python/Include/grammar.h create mode 100644 sys/src/cmd/python/Include/import.h create mode 100644 sys/src/cmd/python/Include/intobject.h create mode 100644 sys/src/cmd/python/Include/intrcheck.h create mode 100644 sys/src/cmd/python/Include/iterobject.h create mode 100644 sys/src/cmd/python/Include/listobject.h create mode 100644 sys/src/cmd/python/Include/longintrepr.h create mode 100644 sys/src/cmd/python/Include/longobject.h create mode 100644 sys/src/cmd/python/Include/marshal.h create mode 100644 sys/src/cmd/python/Include/metagrammar.h create mode 100644 sys/src/cmd/python/Include/methodobject.h create mode 100644 sys/src/cmd/python/Include/modsupport.h create mode 100644 sys/src/cmd/python/Include/moduleobject.h create mode 100644 sys/src/cmd/python/Include/node.h create mode 100644 sys/src/cmd/python/Include/object.h create mode 100644 sys/src/cmd/python/Include/objimpl.h create mode 100644 sys/src/cmd/python/Include/opcode.h create mode 100644 sys/src/cmd/python/Include/osdefs.h create mode 100644 sys/src/cmd/python/Include/parsetok.h create mode 100644 sys/src/cmd/python/Include/patchlevel.h create mode 100644 sys/src/cmd/python/Include/pgen.h create mode 100644 sys/src/cmd/python/Include/pgenheaders.h create mode 100644 sys/src/cmd/python/Include/py_curses.h create mode 100644 sys/src/cmd/python/Include/pyarena.h create mode 100644 sys/src/cmd/python/Include/pydebug.h create mode 100644 sys/src/cmd/python/Include/pyerrors.h create mode 100644 sys/src/cmd/python/Include/pyexpat.h create mode 100644 sys/src/cmd/python/Include/pyfpe.h create mode 100644 sys/src/cmd/python/Include/pygetopt.h create mode 100644 sys/src/cmd/python/Include/pymactoolbox.h create mode 100644 sys/src/cmd/python/Include/pymem.h create mode 100644 sys/src/cmd/python/Include/pyport.h create mode 100644 sys/src/cmd/python/Include/pystate.h create mode 100644 sys/src/cmd/python/Include/pystrtod.h create mode 100644 sys/src/cmd/python/Include/pythonrun.h create mode 100644 sys/src/cmd/python/Include/pythread.h create mode 100644 sys/src/cmd/python/Include/rangeobject.h create mode 100644 sys/src/cmd/python/Include/setobject.h create mode 100644 sys/src/cmd/python/Include/sliceobject.h create mode 100644 sys/src/cmd/python/Include/stringobject.h create mode 100644 sys/src/cmd/python/Include/structmember.h create mode 100644 sys/src/cmd/python/Include/structseq.h create mode 100644 sys/src/cmd/python/Include/symtable.h create mode 100644 sys/src/cmd/python/Include/sysmodule.h create mode 100644 sys/src/cmd/python/Include/timefuncs.h create mode 100644 sys/src/cmd/python/Include/token.h create mode 100644 sys/src/cmd/python/Include/traceback.h create mode 100644 sys/src/cmd/python/Include/tupleobject.h create mode 100644 sys/src/cmd/python/Include/ucnhash.h create mode 100644 sys/src/cmd/python/Include/unicodeobject.h create mode 100644 sys/src/cmd/python/Include/weakrefobject.h create mode 100644 sys/src/cmd/python/LICENSE create mode 100644 sys/src/cmd/python/Misc/ACKS create mode 100644 sys/src/cmd/python/Misc/AIX-NOTES create mode 100644 sys/src/cmd/python/Misc/BeOS-NOTES create mode 100644 sys/src/cmd/python/Misc/BeOS-setup.py create mode 100644 sys/src/cmd/python/Misc/HISTORY create mode 100644 sys/src/cmd/python/Misc/NEWS create mode 100644 sys/src/cmd/python/Misc/NEWS.help create mode 100644 sys/src/cmd/python/Misc/PURIFY.README create mode 100644 sys/src/cmd/python/Misc/Porting create mode 100644 sys/src/cmd/python/Misc/README create mode 100644 sys/src/cmd/python/Misc/README.OpenBSD create mode 100644 sys/src/cmd/python/Misc/README.coverity create mode 100644 sys/src/cmd/python/Misc/README.klocwork create mode 100644 sys/src/cmd/python/Misc/README.valgrind create mode 100644 sys/src/cmd/python/Misc/RFD create mode 100644 sys/src/cmd/python/Misc/RPM/README create mode 100644 sys/src/cmd/python/Misc/RPM/python-2.5.spec create mode 100644 sys/src/cmd/python/Misc/SpecialBuilds.txt create mode 100644 sys/src/cmd/python/Misc/Vim/python.vim create mode 100644 sys/src/cmd/python/Misc/Vim/syntax_test.py create mode 100644 sys/src/cmd/python/Misc/Vim/vim_syntax.py create mode 100644 sys/src/cmd/python/Misc/Vim/vimrc create mode 100755 sys/src/cmd/python/Misc/build.sh create mode 100644 sys/src/cmd/python/Misc/cheatsheet create mode 100644 sys/src/cmd/python/Misc/developers.txt create mode 100644 sys/src/cmd/python/Misc/find_recursionlimit.py create mode 100644 sys/src/cmd/python/Misc/gdbinit create mode 100644 sys/src/cmd/python/Misc/indent.pro create mode 100644 sys/src/cmd/python/Misc/pymemcompat.h create mode 100644 sys/src/cmd/python/Misc/python-config.in create mode 100644 sys/src/cmd/python/Misc/python-mode.el create mode 100644 sys/src/cmd/python/Misc/python.man create mode 100644 sys/src/cmd/python/Misc/setuid-prog.c create mode 100644 sys/src/cmd/python/Misc/valgrind-python.supp create mode 100644 sys/src/cmd/python/Misc/vgrindefs create mode 100644 sys/src/cmd/python/Modules/Setup create mode 100644 sys/src/cmd/python/Modules/Setup.config create mode 100644 sys/src/cmd/python/Modules/Setup.config.in create mode 100644 sys/src/cmd/python/Modules/Setup.dist create mode 100644 sys/src/cmd/python/Modules/Setup.local create mode 100644 sys/src/cmd/python/Modules/_bisectmodule.c create mode 100644 sys/src/cmd/python/Modules/_bsddb.c create mode 100644 sys/src/cmd/python/Modules/_codecsmodule.c create mode 100644 sys/src/cmd/python/Modules/_csv.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/_ctypes.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/_ctypes_test.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/_ctypes_test.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/callbacks.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/callproc.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/cfield.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/ctypes.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/ctypes_dlfcn.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/darwin/LICENSE create mode 100644 sys/src/cmd/python/Modules/_ctypes/darwin/README create mode 100644 sys/src/cmd/python/Modules/_ctypes/darwin/README.ctypes create mode 100644 sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn_simple.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/LICENSE create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/README create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/aclocal.m4 create mode 100755 sys/src/cmd/python/Modules/_ctypes/libffi/config.guess create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/config.sub create mode 100755 sys/src/cmd/python/Modules/_ctypes/libffi/configure create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/configure.ac create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.h.in create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.py.in create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi.h.in create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi_common.h create mode 100755 sys/src/cmd/python/Modules/_ctypes/libffi/install-sh create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/osf.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/darwin/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/eabi.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ia64_flags.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/unix.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/n32.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/o32.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/linux.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix_closure.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/asm.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin_closure.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi_darwin.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64_closure.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ppc_closure.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/prep_cif.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v8.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v9.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/darwin.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi64.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi_darwin.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/sysv.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/unix64.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/win32.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/debug.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi_common.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/fficonfig.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/prep_cif.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/sysv.asm create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/LICENSE create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README.ctypes create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi_common.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/fficonfig.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffitarget.h create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/prep_cif.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/types.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.S create mode 100644 sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/malloc_closure.c create mode 100644 sys/src/cmd/python/Modules/_ctypes/stgdict.c create mode 100644 sys/src/cmd/python/Modules/_curses_panel.c create mode 100644 sys/src/cmd/python/Modules/_cursesmodule.c create mode 100644 sys/src/cmd/python/Modules/_elementtree.c create mode 100644 sys/src/cmd/python/Modules/_functoolsmodule.c create mode 100644 sys/src/cmd/python/Modules/_hashopenssl.c create mode 100644 sys/src/cmd/python/Modules/_heapqmodule.c create mode 100644 sys/src/cmd/python/Modules/_hotshot.c create mode 100644 sys/src/cmd/python/Modules/_localemodule.c create mode 100644 sys/src/cmd/python/Modules/_lsprof.c create mode 100644 sys/src/cmd/python/Modules/_randommodule.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/cache.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/cache.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/connection.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/connection.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/cursor.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/cursor.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/microprotocols.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/microprotocols.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/module.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/module.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/prepare_protocol.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/prepare_protocol.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/row.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/row.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/sqlitecompat.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/statement.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/statement.h create mode 100644 sys/src/cmd/python/Modules/_sqlite/util.c create mode 100644 sys/src/cmd/python/Modules/_sqlite/util.h create mode 100644 sys/src/cmd/python/Modules/_sre.c create mode 100644 sys/src/cmd/python/Modules/_ssl.c create mode 100644 sys/src/cmd/python/Modules/_struct.c create mode 100644 sys/src/cmd/python/Modules/_testcapimodule.c create mode 100644 sys/src/cmd/python/Modules/_tkinter.c create mode 100644 sys/src/cmd/python/Modules/_typesmodule.c create mode 100644 sys/src/cmd/python/Modules/_weakref.c create mode 100644 sys/src/cmd/python/Modules/addrinfo.h create mode 100644 sys/src/cmd/python/Modules/almodule.c create mode 100755 sys/src/cmd/python/Modules/ar_beos create mode 100644 sys/src/cmd/python/Modules/arraymodule.c create mode 100644 sys/src/cmd/python/Modules/audioop.c create mode 100644 sys/src/cmd/python/Modules/binascii.c create mode 100644 sys/src/cmd/python/Modules/bsddbmodule.c create mode 100644 sys/src/cmd/python/Modules/bz2module.c create mode 100644 sys/src/cmd/python/Modules/cPickle.c create mode 100644 sys/src/cmd/python/Modules/cStringIO.c create mode 100644 sys/src/cmd/python/Modules/cdmodule.c create mode 100644 sys/src/cmd/python/Modules/cgen.py create mode 100644 sys/src/cmd/python/Modules/cgensupport.c create mode 100644 sys/src/cmd/python/Modules/cgensupport.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/README create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/_codecs_cn.c create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/_codecs_hk.c create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/_codecs_iso2022.c create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/_codecs_jp.c create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/_codecs_kr.c create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/_codecs_tw.c create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/alg_jisx0201.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/cjkcodecs.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/emu_jisx0213_2000.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/mappings_cn.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/mappings_hk.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/mappings_jisx0213_pair.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/mappings_jp.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/mappings_kr.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/mappings_tw.h create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.c create mode 100644 sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.h create mode 100644 sys/src/cmd/python/Modules/clmodule.c create mode 100644 sys/src/cmd/python/Modules/cmathmodule.c create mode 100644 sys/src/cmd/python/Modules/collectionsmodule.c create mode 100644 sys/src/cmd/python/Modules/config create mode 100644 sys/src/cmd/python/Modules/config.c.in create mode 100644 sys/src/cmd/python/Modules/cryptmodule.c create mode 100644 sys/src/cmd/python/Modules/cstubs create mode 100644 sys/src/cmd/python/Modules/datetimemodule.c create mode 100644 sys/src/cmd/python/Modules/dbmmodule.c create mode 100644 sys/src/cmd/python/Modules/dlmodule.c create mode 100644 sys/src/cmd/python/Modules/errnomodule.c create mode 100644 sys/src/cmd/python/Modules/expat/amigaconfig.h create mode 100644 sys/src/cmd/python/Modules/expat/ascii.h create mode 100644 sys/src/cmd/python/Modules/expat/asciitab.h create mode 100644 sys/src/cmd/python/Modules/expat/expat.h create mode 100644 sys/src/cmd/python/Modules/expat/expat_config.h create mode 100644 sys/src/cmd/python/Modules/expat/expat_external.h create mode 100644 sys/src/cmd/python/Modules/expat/iasciitab.h create mode 100644 sys/src/cmd/python/Modules/expat/internal.h create mode 100644 sys/src/cmd/python/Modules/expat/latin1tab.h create mode 100644 sys/src/cmd/python/Modules/expat/macconfig.h create mode 100644 sys/src/cmd/python/Modules/expat/nametab.h create mode 100644 sys/src/cmd/python/Modules/expat/pyexpatns.h create mode 100644 sys/src/cmd/python/Modules/expat/utf8tab.h create mode 100644 sys/src/cmd/python/Modules/expat/winconfig.h create mode 100644 sys/src/cmd/python/Modules/expat/xmlparse.c create mode 100644 sys/src/cmd/python/Modules/expat/xmlrole.c create mode 100644 sys/src/cmd/python/Modules/expat/xmlrole.h create mode 100644 sys/src/cmd/python/Modules/expat/xmltok.c create mode 100644 sys/src/cmd/python/Modules/expat/xmltok.h create mode 100644 sys/src/cmd/python/Modules/expat/xmltok_impl.c create mode 100644 sys/src/cmd/python/Modules/expat/xmltok_impl.h create mode 100644 sys/src/cmd/python/Modules/expat/xmltok_ns.c create mode 100644 sys/src/cmd/python/Modules/fcntlmodule.c create mode 100644 sys/src/cmd/python/Modules/flmodule.c create mode 100644 sys/src/cmd/python/Modules/fmmodule.c create mode 100644 sys/src/cmd/python/Modules/fpectlmodule.c create mode 100644 sys/src/cmd/python/Modules/fpetestmodule.c create mode 100644 sys/src/cmd/python/Modules/gc_weakref.txt create mode 100644 sys/src/cmd/python/Modules/gcmodule.c create mode 100644 sys/src/cmd/python/Modules/gdbmmodule.c create mode 100644 sys/src/cmd/python/Modules/getaddrinfo.c create mode 100644 sys/src/cmd/python/Modules/getbuildinfo.c create mode 100644 sys/src/cmd/python/Modules/getnameinfo.c create mode 100644 sys/src/cmd/python/Modules/getpath.c create mode 100644 sys/src/cmd/python/Modules/glmodule.c create mode 100644 sys/src/cmd/python/Modules/grpmodule.c create mode 100644 sys/src/cmd/python/Modules/imageop.c create mode 100644 sys/src/cmd/python/Modules/imgfile.c create mode 100644 sys/src/cmd/python/Modules/itertoolsmodule.c create mode 100755 sys/src/cmd/python/Modules/ld_so_aix create mode 100755 sys/src/cmd/python/Modules/ld_so_beos create mode 100644 sys/src/cmd/python/Modules/linuxaudiodev.c create mode 100644 sys/src/cmd/python/Modules/main.c create mode 100755 sys/src/cmd/python/Modules/makesetup create mode 100755 sys/src/cmd/python/Modules/makexp_aix create mode 100644 sys/src/cmd/python/Modules/mathmodule.c create mode 100644 sys/src/cmd/python/Modules/md5.c create mode 100644 sys/src/cmd/python/Modules/md5.h create mode 100644 sys/src/cmd/python/Modules/md5module.c create mode 100644 sys/src/cmd/python/Modules/mkfile create mode 100644 sys/src/cmd/python/Modules/mmapmodule.c create mode 100644 sys/src/cmd/python/Modules/nismodule.c create mode 100644 sys/src/cmd/python/Modules/operator.c create mode 100644 sys/src/cmd/python/Modules/ossaudiodev.c create mode 100644 sys/src/cmd/python/Modules/parsermodule.c create mode 100644 sys/src/cmd/python/Modules/posixmodule.c create mode 100644 sys/src/cmd/python/Modules/puremodule.c create mode 100644 sys/src/cmd/python/Modules/pwdmodule.c create mode 100644 sys/src/cmd/python/Modules/pyexpat.c create mode 100644 sys/src/cmd/python/Modules/python.c create mode 100644 sys/src/cmd/python/Modules/readline.c create mode 100644 sys/src/cmd/python/Modules/resource.c create mode 100644 sys/src/cmd/python/Modules/rgbimgmodule.c create mode 100644 sys/src/cmd/python/Modules/rotatingtree.c create mode 100644 sys/src/cmd/python/Modules/rotatingtree.h create mode 100644 sys/src/cmd/python/Modules/selectmodule.c create mode 100644 sys/src/cmd/python/Modules/sgimodule.c create mode 100644 sys/src/cmd/python/Modules/sha256module.c create mode 100644 sys/src/cmd/python/Modules/sha512module.c create mode 100644 sys/src/cmd/python/Modules/shamodule.c create mode 100644 sys/src/cmd/python/Modules/signalmodule.c create mode 100644 sys/src/cmd/python/Modules/socketmodule.c create mode 100644 sys/src/cmd/python/Modules/socketmodule.h create mode 100644 sys/src/cmd/python/Modules/spwdmodule.c create mode 100644 sys/src/cmd/python/Modules/sre.h create mode 100644 sys/src/cmd/python/Modules/sre_constants.h create mode 100644 sys/src/cmd/python/Modules/stropmodule.c create mode 100644 sys/src/cmd/python/Modules/sunaudiodev.c create mode 100644 sys/src/cmd/python/Modules/svmodule.c create mode 100644 sys/src/cmd/python/Modules/symtablemodule.c create mode 100644 sys/src/cmd/python/Modules/syslogmodule.c create mode 100644 sys/src/cmd/python/Modules/termios.c create mode 100644 sys/src/cmd/python/Modules/testcapi_long.h create mode 100644 sys/src/cmd/python/Modules/threadmodule.c create mode 100644 sys/src/cmd/python/Modules/timemodule.c create mode 100644 sys/src/cmd/python/Modules/timing.h create mode 100644 sys/src/cmd/python/Modules/timingmodule.c create mode 100644 sys/src/cmd/python/Modules/tkappinit.c create mode 100644 sys/src/cmd/python/Modules/unicodedata.c create mode 100644 sys/src/cmd/python/Modules/unicodedata_db.h create mode 100644 sys/src/cmd/python/Modules/unicodename_db.h create mode 100644 sys/src/cmd/python/Modules/xxmodule.c create mode 100644 sys/src/cmd/python/Modules/xxsubtype.c create mode 100644 sys/src/cmd/python/Modules/yuv.h create mode 100644 sys/src/cmd/python/Modules/yuvconvert.c create mode 100644 sys/src/cmd/python/Modules/zipimport.c create mode 100644 sys/src/cmd/python/Modules/zlib/ChangeLog create mode 100644 sys/src/cmd/python/Modules/zlib/FAQ create mode 100644 sys/src/cmd/python/Modules/zlib/INDEX create mode 100644 sys/src/cmd/python/Modules/zlib/Makefile create mode 100644 sys/src/cmd/python/Modules/zlib/Makefile.in create mode 100644 sys/src/cmd/python/Modules/zlib/README create mode 100644 sys/src/cmd/python/Modules/zlib/adler32.c create mode 100644 sys/src/cmd/python/Modules/zlib/algorithm.txt create mode 100644 sys/src/cmd/python/Modules/zlib/compress.c create mode 100755 sys/src/cmd/python/Modules/zlib/configure create mode 100644 sys/src/cmd/python/Modules/zlib/crc32.c create mode 100644 sys/src/cmd/python/Modules/zlib/crc32.h create mode 100644 sys/src/cmd/python/Modules/zlib/deflate.c create mode 100644 sys/src/cmd/python/Modules/zlib/deflate.h create mode 100644 sys/src/cmd/python/Modules/zlib/example.c create mode 100644 sys/src/cmd/python/Modules/zlib/gzio.c create mode 100644 sys/src/cmd/python/Modules/zlib/infback.c create mode 100644 sys/src/cmd/python/Modules/zlib/inffast.c create mode 100644 sys/src/cmd/python/Modules/zlib/inffast.h create mode 100644 sys/src/cmd/python/Modules/zlib/inffixed.h create mode 100644 sys/src/cmd/python/Modules/zlib/inflate.c create mode 100644 sys/src/cmd/python/Modules/zlib/inflate.h create mode 100644 sys/src/cmd/python/Modules/zlib/inftrees.c create mode 100644 sys/src/cmd/python/Modules/zlib/inftrees.h create mode 100644 sys/src/cmd/python/Modules/zlib/make_vms.com create mode 100644 sys/src/cmd/python/Modules/zlib/minigzip.c create mode 100644 sys/src/cmd/python/Modules/zlib/trees.c create mode 100644 sys/src/cmd/python/Modules/zlib/trees.h create mode 100644 sys/src/cmd/python/Modules/zlib/uncompr.c create mode 100644 sys/src/cmd/python/Modules/zlib/zconf.h create mode 100644 sys/src/cmd/python/Modules/zlib/zconf.in.h create mode 100644 sys/src/cmd/python/Modules/zlib/zlib.3 create mode 100644 sys/src/cmd/python/Modules/zlib/zlib.h create mode 100644 sys/src/cmd/python/Modules/zlib/zutil.c create mode 100644 sys/src/cmd/python/Modules/zlib/zutil.h create mode 100644 sys/src/cmd/python/Modules/zlibmodule.c create mode 100644 sys/src/cmd/python/Objects/abstract.c create mode 100644 sys/src/cmd/python/Objects/boolobject.c create mode 100644 sys/src/cmd/python/Objects/bufferobject.c create mode 100644 sys/src/cmd/python/Objects/cellobject.c create mode 100644 sys/src/cmd/python/Objects/classobject.c create mode 100644 sys/src/cmd/python/Objects/cobject.c create mode 100644 sys/src/cmd/python/Objects/codeobject.c create mode 100644 sys/src/cmd/python/Objects/complexobject.c create mode 100644 sys/src/cmd/python/Objects/descrobject.c create mode 100644 sys/src/cmd/python/Objects/dictnotes.txt create mode 100644 sys/src/cmd/python/Objects/dictobject.c create mode 100644 sys/src/cmd/python/Objects/enumobject.c create mode 100644 sys/src/cmd/python/Objects/exceptions.c create mode 100644 sys/src/cmd/python/Objects/fileobject.c create mode 100644 sys/src/cmd/python/Objects/floatobject.c create mode 100644 sys/src/cmd/python/Objects/frameobject.c create mode 100644 sys/src/cmd/python/Objects/funcobject.c create mode 100644 sys/src/cmd/python/Objects/genobject.c create mode 100644 sys/src/cmd/python/Objects/intobject.c create mode 100644 sys/src/cmd/python/Objects/iterobject.c create mode 100644 sys/src/cmd/python/Objects/listobject.c create mode 100644 sys/src/cmd/python/Objects/listsort.txt create mode 100644 sys/src/cmd/python/Objects/longobject.c create mode 100644 sys/src/cmd/python/Objects/methodobject.c create mode 100644 sys/src/cmd/python/Objects/mkfile create mode 100644 sys/src/cmd/python/Objects/moduleobject.c create mode 100644 sys/src/cmd/python/Objects/object.c create mode 100644 sys/src/cmd/python/Objects/obmalloc.c create mode 100644 sys/src/cmd/python/Objects/rangeobject.c create mode 100644 sys/src/cmd/python/Objects/setobject.c create mode 100644 sys/src/cmd/python/Objects/sliceobject.c create mode 100644 sys/src/cmd/python/Objects/stringlib/README.txt create mode 100644 sys/src/cmd/python/Objects/stringlib/count.h create mode 100644 sys/src/cmd/python/Objects/stringlib/fastsearch.h create mode 100644 sys/src/cmd/python/Objects/stringlib/find.h create mode 100644 sys/src/cmd/python/Objects/stringlib/partition.h create mode 100644 sys/src/cmd/python/Objects/stringobject.c create mode 100644 sys/src/cmd/python/Objects/structseq.c create mode 100644 sys/src/cmd/python/Objects/tupleobject.c create mode 100644 sys/src/cmd/python/Objects/typeobject.c create mode 100644 sys/src/cmd/python/Objects/unicodectype.c create mode 100644 sys/src/cmd/python/Objects/unicodeobject.c create mode 100644 sys/src/cmd/python/Objects/unicodetype_db.h create mode 100644 sys/src/cmd/python/Objects/weakrefobject.c create mode 100644 sys/src/cmd/python/Parser/Python.asdl create mode 100644 sys/src/cmd/python/Parser/acceler.c create mode 100644 sys/src/cmd/python/Parser/asdl.py create mode 100755 sys/src/cmd/python/Parser/asdl_c.py create mode 100644 sys/src/cmd/python/Parser/bitset.c create mode 100644 sys/src/cmd/python/Parser/firstsets.c create mode 100644 sys/src/cmd/python/Parser/grammar.c create mode 100644 sys/src/cmd/python/Parser/grammar.mak create mode 100644 sys/src/cmd/python/Parser/grammar1.c create mode 100644 sys/src/cmd/python/Parser/intrcheck.c create mode 100644 sys/src/cmd/python/Parser/listnode.c create mode 100644 sys/src/cmd/python/Parser/metagrammar.c create mode 100644 sys/src/cmd/python/Parser/mkfile create mode 100644 sys/src/cmd/python/Parser/myreadline.c create mode 100644 sys/src/cmd/python/Parser/node.c create mode 100644 sys/src/cmd/python/Parser/parser.c create mode 100644 sys/src/cmd/python/Parser/parser.h create mode 100644 sys/src/cmd/python/Parser/parsetok.c create mode 100644 sys/src/cmd/python/Parser/pgen.c create mode 100644 sys/src/cmd/python/Parser/pgenmain.c create mode 100644 sys/src/cmd/python/Parser/printgrammar.c create mode 100644 sys/src/cmd/python/Parser/spark.py create mode 100644 sys/src/cmd/python/Parser/tokenizer.c create mode 100644 sys/src/cmd/python/Parser/tokenizer.h create mode 100644 sys/src/cmd/python/Parser/tokenizer_pgen.c create mode 100644 sys/src/cmd/python/Python/Python-ast.c create mode 100644 sys/src/cmd/python/Python/asdl.c create mode 100644 sys/src/cmd/python/Python/ast.c create mode 100644 sys/src/cmd/python/Python/atof.c create mode 100644 sys/src/cmd/python/Python/bltinmodule.c create mode 100644 sys/src/cmd/python/Python/ceval.c create mode 100644 sys/src/cmd/python/Python/codecs.c create mode 100644 sys/src/cmd/python/Python/compile.c create mode 100644 sys/src/cmd/python/Python/dup2.c create mode 100644 sys/src/cmd/python/Python/dynload_aix.c create mode 100644 sys/src/cmd/python/Python/dynload_atheos.c create mode 100644 sys/src/cmd/python/Python/dynload_beos.c create mode 100644 sys/src/cmd/python/Python/dynload_dl.c create mode 100644 sys/src/cmd/python/Python/dynload_hpux.c create mode 100644 sys/src/cmd/python/Python/dynload_next.c create mode 100644 sys/src/cmd/python/Python/dynload_os2.c create mode 100644 sys/src/cmd/python/Python/dynload_shlib.c create mode 100644 sys/src/cmd/python/Python/dynload_stub.c create mode 100644 sys/src/cmd/python/Python/dynload_win.c create mode 100644 sys/src/cmd/python/Python/errors.c create mode 100644 sys/src/cmd/python/Python/fmod.c create mode 100644 sys/src/cmd/python/Python/frozen.c create mode 100644 sys/src/cmd/python/Python/frozenmain.c create mode 100644 sys/src/cmd/python/Python/future.c create mode 100644 sys/src/cmd/python/Python/getargs.c create mode 100644 sys/src/cmd/python/Python/getcompiler.c create mode 100644 sys/src/cmd/python/Python/getcopyright.c create mode 100644 sys/src/cmd/python/Python/getcwd.c create mode 100644 sys/src/cmd/python/Python/getmtime.c create mode 100644 sys/src/cmd/python/Python/getopt.c create mode 100644 sys/src/cmd/python/Python/getplatform.c create mode 100644 sys/src/cmd/python/Python/getversion.c create mode 100644 sys/src/cmd/python/Python/graminit.c create mode 100644 sys/src/cmd/python/Python/hypot.c create mode 100644 sys/src/cmd/python/Python/import.c create mode 100644 sys/src/cmd/python/Python/importdl.c create mode 100644 sys/src/cmd/python/Python/importdl.h create mode 100644 sys/src/cmd/python/Python/mactoolboxglue.c create mode 100644 sys/src/cmd/python/Python/marshal.c create mode 100644 sys/src/cmd/python/Python/memmove.c create mode 100644 sys/src/cmd/python/Python/mkfile create mode 100644 sys/src/cmd/python/Python/modsupport.c create mode 100644 sys/src/cmd/python/Python/mysnprintf.c create mode 100644 sys/src/cmd/python/Python/mystrtoul.c create mode 100644 sys/src/cmd/python/Python/pyarena.c create mode 100644 sys/src/cmd/python/Python/pyfpe.c create mode 100644 sys/src/cmd/python/Python/pystate.c create mode 100644 sys/src/cmd/python/Python/pystrtod.c create mode 100644 sys/src/cmd/python/Python/pythonrun.c create mode 100644 sys/src/cmd/python/Python/sigcheck.c create mode 100644 sys/src/cmd/python/Python/strdup.c create mode 100644 sys/src/cmd/python/Python/strerror.c create mode 100644 sys/src/cmd/python/Python/strtod.c create mode 100644 sys/src/cmd/python/Python/structmember.c create mode 100644 sys/src/cmd/python/Python/symtable.c create mode 100644 sys/src/cmd/python/Python/sysmodule.c create mode 100644 sys/src/cmd/python/Python/thread.c create mode 100644 sys/src/cmd/python/Python/thread_atheos.h create mode 100644 sys/src/cmd/python/Python/thread_beos.h create mode 100644 sys/src/cmd/python/Python/thread_cthread.h create mode 100644 sys/src/cmd/python/Python/thread_foobar.h create mode 100644 sys/src/cmd/python/Python/thread_lwp.h create mode 100644 sys/src/cmd/python/Python/thread_nt.h create mode 100644 sys/src/cmd/python/Python/thread_os2.h create mode 100644 sys/src/cmd/python/Python/thread_plan9.h create mode 100644 sys/src/cmd/python/Python/thread_pth.h create mode 100644 sys/src/cmd/python/Python/thread_pthread.h create mode 100644 sys/src/cmd/python/Python/thread_sgi.h create mode 100644 sys/src/cmd/python/Python/thread_solaris.h create mode 100644 sys/src/cmd/python/Python/thread_wince.h create mode 100644 sys/src/cmd/python/Python/traceback.c create mode 100644 sys/src/cmd/python/README create mode 100644 sys/src/cmd/python/README.Plan9 create mode 100644 sys/src/cmd/python/Tools/README create mode 100644 sys/src/cmd/python/Tools/audiopy/README create mode 100755 sys/src/cmd/python/Tools/audiopy/audiopy create mode 100644 sys/src/cmd/python/Tools/bgen/README create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgen.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenBuffer.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenGenerator.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenGeneratorGroup.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenHeapBuffer.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenModule.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenObjectDefinition.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenOutput.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenStackBuffer.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenStringBuffer.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenType.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/bgenVariable.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/macsupport.py create mode 100644 sys/src/cmd/python/Tools/bgen/bgen/scantools.py create mode 100644 sys/src/cmd/python/Tools/buildbot/Makefile create mode 100644 sys/src/cmd/python/Tools/buildbot/build.bat create mode 100644 sys/src/cmd/python/Tools/buildbot/clean.bat create mode 100644 sys/src/cmd/python/Tools/buildbot/external.bat create mode 100644 sys/src/cmd/python/Tools/buildbot/kill_python.bat create mode 100644 sys/src/cmd/python/Tools/buildbot/kill_python.c create mode 100644 sys/src/cmd/python/Tools/buildbot/kill_python.mak create mode 100644 sys/src/cmd/python/Tools/buildbot/test.bat create mode 100644 sys/src/cmd/python/Tools/compiler/ACKS create mode 100644 sys/src/cmd/python/Tools/compiler/README create mode 100644 sys/src/cmd/python/Tools/compiler/ast.txt create mode 100644 sys/src/cmd/python/Tools/compiler/astgen.py create mode 100644 sys/src/cmd/python/Tools/compiler/compile.py create mode 100755 sys/src/cmd/python/Tools/compiler/demo.py create mode 100755 sys/src/cmd/python/Tools/compiler/dumppyc.py create mode 100644 sys/src/cmd/python/Tools/compiler/regrtest.py create mode 100644 sys/src/cmd/python/Tools/compiler/stacktest.py create mode 100644 sys/src/cmd/python/Tools/faqwiz/README create mode 100644 sys/src/cmd/python/Tools/faqwiz/faqconf.py create mode 100644 sys/src/cmd/python/Tools/faqwiz/faqcust.py create mode 100755 sys/src/cmd/python/Tools/faqwiz/faqw.py create mode 100644 sys/src/cmd/python/Tools/faqwiz/faqwiz.py create mode 100755 sys/src/cmd/python/Tools/faqwiz/move-faqwiz.sh create mode 100644 sys/src/cmd/python/Tools/framer/README.txt create mode 100644 sys/src/cmd/python/Tools/framer/TODO.txt create mode 100644 sys/src/cmd/python/Tools/framer/example.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/__init__.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/bases.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/function.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/member.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/slots.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/struct.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/structparse.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/template.py create mode 100644 sys/src/cmd/python/Tools/framer/framer/util.py create mode 100644 sys/src/cmd/python/Tools/freeze/README create mode 100644 sys/src/cmd/python/Tools/freeze/bkfile.py create mode 100644 sys/src/cmd/python/Tools/freeze/checkextensions.py create mode 100644 sys/src/cmd/python/Tools/freeze/checkextensions_win32.py create mode 100644 sys/src/cmd/python/Tools/freeze/extensions_win32.ini create mode 100755 sys/src/cmd/python/Tools/freeze/freeze.py create mode 100644 sys/src/cmd/python/Tools/freeze/hello.py create mode 100644 sys/src/cmd/python/Tools/freeze/makeconfig.py create mode 100644 sys/src/cmd/python/Tools/freeze/makefreeze.py create mode 100644 sys/src/cmd/python/Tools/freeze/makemakefile.py create mode 100644 sys/src/cmd/python/Tools/freeze/parsesetup.py create mode 100644 sys/src/cmd/python/Tools/freeze/win32.html create mode 100644 sys/src/cmd/python/Tools/freeze/winmakemakefile.py create mode 100644 sys/src/cmd/python/Tools/i18n/makelocalealias.py create mode 100755 sys/src/cmd/python/Tools/i18n/msgfmt.py create mode 100755 sys/src/cmd/python/Tools/i18n/pygettext.py create mode 100644 sys/src/cmd/python/Tools/modulator/EXAMPLE.py create mode 100644 sys/src/cmd/python/Tools/modulator/README create mode 100644 sys/src/cmd/python/Tools/modulator/ScrolledListbox.py create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/copyright create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/module_head create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/module_method create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/module_tail create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_head create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_method create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_mlist create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_new create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_structure create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tail create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_mapping create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_number create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_sequence create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_call create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_compare create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_dealloc create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_getattr create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_hash create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_print create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_repr create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_setattr create mode 100644 sys/src/cmd/python/Tools/modulator/Templates/object_tp_str create mode 100755 sys/src/cmd/python/Tools/modulator/Tkextra.py create mode 100755 sys/src/cmd/python/Tools/modulator/genmodule.py create mode 100755 sys/src/cmd/python/Tools/modulator/modulator.py create mode 100644 sys/src/cmd/python/Tools/modulator/varsubst.py create mode 100644 sys/src/cmd/python/Tools/msi/README.txt create mode 100644 sys/src/cmd/python/Tools/msi/msi.py create mode 100644 sys/src/cmd/python/Tools/msi/msilib.py create mode 100644 sys/src/cmd/python/Tools/msi/msisupport.c create mode 100644 sys/src/cmd/python/Tools/msi/msisupport.mak create mode 100644 sys/src/cmd/python/Tools/msi/schema.py create mode 100644 sys/src/cmd/python/Tools/msi/sequence.py create mode 100644 sys/src/cmd/python/Tools/msi/uisample.py create mode 100644 sys/src/cmd/python/Tools/msi/uuids.py create mode 100644 sys/src/cmd/python/Tools/pybench/Arithmetic.py create mode 100644 sys/src/cmd/python/Tools/pybench/Calls.py create mode 100644 sys/src/cmd/python/Tools/pybench/CommandLine.py create mode 100644 sys/src/cmd/python/Tools/pybench/Constructs.py create mode 100644 sys/src/cmd/python/Tools/pybench/Dict.py create mode 100644 sys/src/cmd/python/Tools/pybench/Exceptions.py create mode 100644 sys/src/cmd/python/Tools/pybench/Imports.py create mode 100644 sys/src/cmd/python/Tools/pybench/Instances.py create mode 100644 sys/src/cmd/python/Tools/pybench/LICENSE create mode 100644 sys/src/cmd/python/Tools/pybench/Lists.py create mode 100644 sys/src/cmd/python/Tools/pybench/Lookups.py create mode 100644 sys/src/cmd/python/Tools/pybench/NewInstances.py create mode 100644 sys/src/cmd/python/Tools/pybench/Numbers.py create mode 100644 sys/src/cmd/python/Tools/pybench/README create mode 100644 sys/src/cmd/python/Tools/pybench/Setup.py create mode 100644 sys/src/cmd/python/Tools/pybench/Strings.py create mode 100644 sys/src/cmd/python/Tools/pybench/Tuples.py create mode 100644 sys/src/cmd/python/Tools/pybench/Unicode.py create mode 100644 sys/src/cmd/python/Tools/pybench/clockres.py create mode 100644 sys/src/cmd/python/Tools/pybench/package/__init__.py create mode 100644 sys/src/cmd/python/Tools/pybench/package/submodule.py create mode 100755 sys/src/cmd/python/Tools/pybench/pybench.py create mode 100644 sys/src/cmd/python/Tools/pybench/systimes.py create mode 100644 sys/src/cmd/python/Tools/pynche/ChipViewer.py create mode 100644 sys/src/cmd/python/Tools/pynche/ColorDB.py create mode 100644 sys/src/cmd/python/Tools/pynche/DetailsViewer.py create mode 100644 sys/src/cmd/python/Tools/pynche/ListViewer.py create mode 100644 sys/src/cmd/python/Tools/pynche/Main.py create mode 100644 sys/src/cmd/python/Tools/pynche/PyncheWidget.py create mode 100644 sys/src/cmd/python/Tools/pynche/README create mode 100644 sys/src/cmd/python/Tools/pynche/StripViewer.py create mode 100644 sys/src/cmd/python/Tools/pynche/Switchboard.py create mode 100644 sys/src/cmd/python/Tools/pynche/TextViewer.py create mode 100644 sys/src/cmd/python/Tools/pynche/TypeinViewer.py create mode 100644 sys/src/cmd/python/Tools/pynche/X/rgb.txt create mode 100644 sys/src/cmd/python/Tools/pynche/X/xlicense.txt create mode 100644 sys/src/cmd/python/Tools/pynche/__init__.py create mode 100644 sys/src/cmd/python/Tools/pynche/html40colors.txt create mode 100644 sys/src/cmd/python/Tools/pynche/namedcolors.txt create mode 100644 sys/src/cmd/python/Tools/pynche/pyColorChooser.py create mode 100755 sys/src/cmd/python/Tools/pynche/pynche create mode 100755 sys/src/cmd/python/Tools/pynche/pynche.pyw create mode 100644 sys/src/cmd/python/Tools/pynche/webcolors.txt create mode 100644 sys/src/cmd/python/Tools/pynche/websafe.txt create mode 100644 sys/src/cmd/python/Tools/scripts/README create mode 100644 sys/src/cmd/python/Tools/scripts/byext.py create mode 100755 sys/src/cmd/python/Tools/scripts/byteyears.py create mode 100755 sys/src/cmd/python/Tools/scripts/checkappend.py create mode 100755 sys/src/cmd/python/Tools/scripts/checkpyc.py create mode 100755 sys/src/cmd/python/Tools/scripts/classfix.py create mode 100644 sys/src/cmd/python/Tools/scripts/cleanfuture.py create mode 100644 sys/src/cmd/python/Tools/scripts/combinerefs.py create mode 100755 sys/src/cmd/python/Tools/scripts/copytime.py create mode 100755 sys/src/cmd/python/Tools/scripts/crlf.py create mode 100755 sys/src/cmd/python/Tools/scripts/cvsfiles.py create mode 100644 sys/src/cmd/python/Tools/scripts/db2pickle.py create mode 100644 sys/src/cmd/python/Tools/scripts/diff.py create mode 100644 sys/src/cmd/python/Tools/scripts/dutree.doc create mode 100755 sys/src/cmd/python/Tools/scripts/dutree.py create mode 100755 sys/src/cmd/python/Tools/scripts/eptags.py create mode 100755 sys/src/cmd/python/Tools/scripts/finddiv.py create mode 100755 sys/src/cmd/python/Tools/scripts/findlinksto.py create mode 100755 sys/src/cmd/python/Tools/scripts/findnocoding.py create mode 100755 sys/src/cmd/python/Tools/scripts/fixcid.py create mode 100755 sys/src/cmd/python/Tools/scripts/fixdiv.py create mode 100755 sys/src/cmd/python/Tools/scripts/fixheader.py create mode 100755 sys/src/cmd/python/Tools/scripts/fixnotice.py create mode 100755 sys/src/cmd/python/Tools/scripts/fixps.py create mode 100755 sys/src/cmd/python/Tools/scripts/ftpmirror.py create mode 100755 sys/src/cmd/python/Tools/scripts/google.py create mode 100755 sys/src/cmd/python/Tools/scripts/gprof2html.py create mode 100755 sys/src/cmd/python/Tools/scripts/h2py.py create mode 100644 sys/src/cmd/python/Tools/scripts/hotshotmain.py create mode 100644 sys/src/cmd/python/Tools/scripts/idle create mode 100755 sys/src/cmd/python/Tools/scripts/ifdef.py create mode 100755 sys/src/cmd/python/Tools/scripts/lfcr.py create mode 100755 sys/src/cmd/python/Tools/scripts/linktree.py create mode 100755 sys/src/cmd/python/Tools/scripts/lll.py create mode 100755 sys/src/cmd/python/Tools/scripts/logmerge.py create mode 100755 sys/src/cmd/python/Tools/scripts/mailerdaemon.py create mode 100644 sys/src/cmd/python/Tools/scripts/md5sum.py create mode 100755 sys/src/cmd/python/Tools/scripts/methfix.py create mode 100755 sys/src/cmd/python/Tools/scripts/mkreal.py create mode 100755 sys/src/cmd/python/Tools/scripts/ndiff.py create mode 100755 sys/src/cmd/python/Tools/scripts/nm2def.py create mode 100755 sys/src/cmd/python/Tools/scripts/objgraph.py create mode 100755 sys/src/cmd/python/Tools/scripts/parseentities.py create mode 100755 sys/src/cmd/python/Tools/scripts/pathfix.py create mode 100755 sys/src/cmd/python/Tools/scripts/pdeps.py create mode 100644 sys/src/cmd/python/Tools/scripts/pickle2db.py create mode 100755 sys/src/cmd/python/Tools/scripts/pindent.py create mode 100755 sys/src/cmd/python/Tools/scripts/ptags.py create mode 100755 sys/src/cmd/python/Tools/scripts/pydoc create mode 100644 sys/src/cmd/python/Tools/scripts/pydocgui.pyw create mode 100644 sys/src/cmd/python/Tools/scripts/pysource.py create mode 100644 sys/src/cmd/python/Tools/scripts/redemo.py create mode 100644 sys/src/cmd/python/Tools/scripts/reindent.py create mode 100755 sys/src/cmd/python/Tools/scripts/rgrep.py create mode 100644 sys/src/cmd/python/Tools/scripts/setup.py create mode 100755 sys/src/cmd/python/Tools/scripts/suff.py create mode 100644 sys/src/cmd/python/Tools/scripts/svneol.py create mode 100644 sys/src/cmd/python/Tools/scripts/texcheck.py create mode 100755 sys/src/cmd/python/Tools/scripts/texi2html.py create mode 100755 sys/src/cmd/python/Tools/scripts/treesync.py create mode 100755 sys/src/cmd/python/Tools/scripts/untabify.py create mode 100755 sys/src/cmd/python/Tools/scripts/which.py create mode 100755 sys/src/cmd/python/Tools/scripts/xxci.py create mode 100644 sys/src/cmd/python/Tools/unicode/Makefile create mode 100644 sys/src/cmd/python/Tools/unicode/comparecodecs.py create mode 100644 sys/src/cmd/python/Tools/unicode/gencjkcodecs.py create mode 100644 sys/src/cmd/python/Tools/unicode/gencodec.py create mode 100644 sys/src/cmd/python/Tools/unicode/listcodecs.py create mode 100644 sys/src/cmd/python/Tools/unicode/makeunicodedata.py create mode 100644 sys/src/cmd/python/Tools/unicode/mkstringprep.py create mode 100644 sys/src/cmd/python/Tools/unicode/python-mappings/CP1140.TXT create mode 100644 sys/src/cmd/python/Tools/unicode/python-mappings/KOI8-U.TXT create mode 100644 sys/src/cmd/python/Tools/unicode/python-mappings/TIS-620.TXT create mode 100644 sys/src/cmd/python/Tools/versioncheck/README create mode 100644 sys/src/cmd/python/Tools/versioncheck/_checkversion.py create mode 100644 sys/src/cmd/python/Tools/versioncheck/checkversions.py create mode 100644 sys/src/cmd/python/Tools/versioncheck/pyversioncheck.py create mode 100644 sys/src/cmd/python/Tools/webchecker/README create mode 100644 sys/src/cmd/python/Tools/webchecker/tktools.py create mode 100755 sys/src/cmd/python/Tools/webchecker/wcgui.py create mode 100644 sys/src/cmd/python/Tools/webchecker/wcmac.py create mode 100755 sys/src/cmd/python/Tools/webchecker/webchecker.py create mode 100755 sys/src/cmd/python/Tools/webchecker/websucker.py create mode 100755 sys/src/cmd/python/Tools/webchecker/wsgui.py create mode 100644 sys/src/cmd/python/Tools/world/README create mode 100755 sys/src/cmd/python/Tools/world/world create mode 100755 sys/src/cmd/python/mkconfig create mode 100644 sys/src/cmd/python/mkfile create mode 100644 sys/src/cmd/python/plan9.c create mode 100644 sys/src/cmd/python/pyconfig.h create mode 100644 sys/src/cmd/python/python.proto (limited to 'sys/src') diff --git a/sys/src/cmd/hg/CONTRIBUTORS b/sys/src/cmd/hg/CONTRIBUTORS new file mode 100644 index 000000000..81f8143d1 --- /dev/null +++ b/sys/src/cmd/hg/CONTRIBUTORS @@ -0,0 +1,41 @@ +[This file is here for historical purposes, all recent contributors +should appear in the changelog directly] + +Andrea Arcangeli +Thomas Arendsen Hein +Goffredo Baroncelli +Muli Ben-Yehuda +Mikael Berthe +Benoit Boissinot +Brendan Cully +Vincent Danjean +Jake Edge +Michael Fetterman +Edouard Gomez +Eric Hopper +Alecs King +Volker Kleinfeld +Vadim Lebedev +Christopher Li +Chris Mason +Colin McMillen +Wojciech Milkowski +Chad Netzer +Bryan O'Sullivan +Vicent Seguí Pascual +Sean Perry +Nguyen Anh Quynh +Ollivier Robert +Alexander Schremmer +Arun Sharma +Josef "Jeff" Sipek +Kevin Smith +TK Soh +Radoslaw Szkodzinski +Samuel Tardieu +K Thananchayan +Andrew Thompson +Michael S. Tsirkin +Rafael Villar Burke +Tristan Wibberley +Mark Williamson diff --git a/sys/src/cmd/hg/COPYING b/sys/src/cmd/hg/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/sys/src/cmd/hg/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/sys/src/cmd/hg/Makefile b/sys/src/cmd/hg/Makefile new file mode 100644 index 000000000..2a4600490 --- /dev/null +++ b/sys/src/cmd/hg/Makefile @@ -0,0 +1,103 @@ +PREFIX=/usr/local +export PREFIX +PYTHON=python +PURE= +PYTHON_FILES:=$(shell find mercurial hgext doc -name '*.py') + +help: + @echo 'Commonly used make targets:' + @echo ' all - build program and documentation' + @echo ' install - install program and man pages to PREFIX ($(PREFIX))' + @echo ' install-home - install with setup.py install --home=HOME ($(HOME))' + @echo ' local - build for inplace usage' + @echo ' tests - run all tests in the automatic test suite' + @echo ' test-foo - run only specified tests (e.g. test-merge1)' + @echo ' dist - run all tests and create a source tarball in dist/' + @echo ' clean - remove files created by other targets' + @echo ' (except installed files or dist source tarball)' + @echo ' update-pot - update i18n/hg.pot' + @echo + @echo 'Example for a system-wide installation under /usr/local:' + @echo ' make all && su -c "make install" && hg version' + @echo + @echo 'Example for a local installation (usable in this directory):' + @echo ' make local && ./hg version' + +all: build doc + +local: + $(PYTHON) setup.py $(PURE) build_py -c -d . build_ext -i build_mo + $(PYTHON) hg version + +build: + $(PYTHON) setup.py $(PURE) build + +doc: + $(MAKE) -C doc + +clean: + -$(PYTHON) setup.py clean --all # ignore errors from this command + find . -name '*.py[cdo]' -exec rm -f '{}' ';' + rm -f MANIFEST mercurial/__version__.py mercurial/*.so tests/*.err + rm -rf locale + $(MAKE) -C doc clean + +install: install-bin install-doc + +install-bin: build + $(PYTHON) setup.py $(PURE) install --prefix="$(PREFIX)" --force + +install-doc: doc + cd doc && $(MAKE) $(MFLAGS) install + +install-home: install-home-bin install-home-doc + +install-home-bin: build + $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --force + +install-home-doc: doc + cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install + +MANIFEST-doc: + $(MAKE) -C doc MANIFEST + +MANIFEST: MANIFEST-doc + hg manifest > MANIFEST + echo mercurial/__version__.py >> MANIFEST + cat doc/MANIFEST >> MANIFEST + +dist: tests dist-notests + +dist-notests: doc MANIFEST + TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist + +tests: + cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) + +test-%: + cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@ + +update-pot: i18n/hg.pot + +i18n/hg.pot: $(PYTHON_FILES) + $(PYTHON) i18n/hggettext mercurial/commands.py \ + hgext/*.py hgext/*/__init__.py > i18n/hg.pot + # All strings marked for translation in Mercurial contain + # ASCII characters only. But some files contain string + # literals like this '\037\213'. xgettext thinks it has to + # parse them even though they are not marked for translation. + # Extracting with an explicit encoding of ISO-8859-1 will make + # xgettext "parse" and ignore them. + echo $^ | xargs \ + xgettext --package-name "Mercurial" \ + --msgid-bugs-address "" \ + --copyright-holder "Matt Mackall and others" \ + --from-code ISO-8859-1 --join --sort-by-file \ + -d hg -p i18n -o hg.pot + +%.po: i18n/hg.pot + msgmerge --no-location --update $@ $^ + +.PHONY: help all local build doc clean install install-bin install-doc \ + install-home install-home-bin install-home-doc dist dist-notests tests \ + update-pot diff --git a/sys/src/cmd/hg/README b/sys/src/cmd/hg/README new file mode 100644 index 000000000..d67e780a6 --- /dev/null +++ b/sys/src/cmd/hg/README @@ -0,0 +1,10 @@ +Basic install: + + $ make # see install targets + $ make install # do a system-wide install + $ hg debuginstall # sanity-check setup + $ hg # see help + +See http://mercurial.selenic.com/ for detailed installation +instructions, platform-specific notes, and Mercurial user information. + diff --git a/sys/src/cmd/hg/README.Plan9 b/sys/src/cmd/hg/README.Plan9 new file mode 100644 index 000000000..4ed1d16b5 --- /dev/null +++ b/sys/src/cmd/hg/README.Plan9 @@ -0,0 +1,5 @@ +Mercurial (cloned in 20090826) + +Federico G. Benavento +August 2009 +benavento@gmail.com diff --git a/sys/src/cmd/hg/contrib/bash_completion b/sys/src/cmd/hg/contrib/bash_completion new file mode 100644 index 000000000..28f1d0b41 --- /dev/null +++ b/sys/src/cmd/hg/contrib/bash_completion @@ -0,0 +1,532 @@ +# bash completion for the Mercurial distributed SCM + +# Docs: +# +# If you source this file from your .bashrc, bash should be able to +# complete a command line that uses hg with all the available commands +# and options and sometimes even arguments. +# +# Mercurial allows you to define additional commands through extensions. +# Bash should be able to automatically figure out the name of these new +# commands and their options. See below for how to define _hg_opt_foo +# and _hg_cmd_foo functions to fine-tune the completion for option and +# non-option arguments, respectively. +# +# +# Notes about completion for specific commands: +# +# - the completion function for the email command from the patchbomb +# extension will try to call _hg_emails to get a list of e-mail +# addresses. It's up to the user to define this function. For +# example, put the addresses of the lists that you usually patchbomb +# in ~/.patchbomb-to and the addresses that you usually use to send +# the patchbombs in ~/.patchbomb-from and use something like this: +# +# _hg_emails() +# { +# if [ -r ~/.patchbomb-$1 ]; then +# cat ~/.patchbomb-$1 +# fi +# } +# +# +# Writing completion functions for additional commands: +# +# If it exists, the function _hg_cmd_foo will be called without +# arguments to generate the completion candidates for the hg command +# "foo". If the command receives some arguments that aren't options +# even though they start with a "-", you can define a function called +# _hg_opt_foo to generate the completion candidates. If _hg_opt_foo +# doesn't return 0, regular completion for options is attempted. +# +# In addition to the regular completion variables provided by bash, +# the following variables are also set: +# - $hg - the hg program being used (e.g. /usr/bin/hg) +# - $cmd - the name of the hg command being completed +# - $cmd_index - the index of $cmd in $COMP_WORDS +# - $cur - the current argument being completed +# - $prev - the argument before $cur +# - $global_args - "|"-separated list of global options that accept +# an argument (e.g. '--cwd|-R|--repository') +# - $canonical - 1 if we canonicalized $cmd before calling the function +# 0 otherwise +# + +shopt -s extglob + +_hg_commands() +{ + local commands + commands="$("$hg" debugcomplete "$cur" 2>/dev/null)" || commands="" + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur")) +} + +_hg_paths() +{ + local paths="$("$hg" paths 2>/dev/null | sed -e 's/ = .*$//')" + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur")) +} + +_hg_repos() +{ + local i + for i in $(compgen -d -- "$cur"); do + test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i") + done +} + +_hg_status() +{ + local files="$("$hg" status -n$1 . 2>/dev/null)" + local IFS=$'\n' + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) +} + +_hg_tags() +{ + local tags="$("$hg" tags -q 2>/dev/null)" + local IFS=$'\n' + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur")) +} + +_hg_branches() +{ + local branches="$("$hg" branches -q 2>/dev/null)" + local IFS=$'\n' + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$branches' -- "$cur")) +} + +# this is "kind of" ugly... +_hg_count_non_option() +{ + local i count=0 + local filters="$1" + + for ((i=1; $i<=$COMP_CWORD; i++)); do + if [[ "${COMP_WORDS[i]}" != -* ]]; then + if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then + continue + fi + count=$(($count + 1)) + fi + done + + echo $(($count - 1)) +} + +_hg() +{ + local cur prev cmd cmd_index opts i + # global options that receive an argument + local global_args='--cwd|-R|--repository' + local hg="$1" + local canonical=0 + + COMPREPLY=() + cur="$2" + prev="$3" + + # searching for the command + # (first non-option argument that doesn't follow a global option that + # receives an argument) + for ((i=1; $i<=$COMP_CWORD; i++)); do + if [[ ${COMP_WORDS[i]} != -* ]]; then + if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then + cmd="${COMP_WORDS[i]}" + cmd_index=$i + break + fi + fi + done + + if [[ "$cur" == -* ]]; then + if [ "$(type -t "_hg_opt_$cmd")" = function ] && "_hg_opt_$cmd"; then + return + fi + + opts=$("$hg" debugcomplete --options "$cmd" 2>/dev/null) + + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur")) + return + fi + + # global options + case "$prev" in + -R|--repository) + _hg_paths + _hg_repos + return + ;; + --cwd) + # Stick with default bash completion + return + ;; + esac + + if [ -z "$cmd" ] || [ $COMP_CWORD -eq $i ]; then + _hg_commands + return + fi + + # try to generate completion candidates for whatever command the user typed + local help + if _hg_command_specific; then + return + fi + + # canonicalize the command name and try again + help=$("$hg" help "$cmd" 2>/dev/null) + if [ $? -ne 0 ]; then + # Probably either the command doesn't exist or it's ambiguous + return + fi + cmd=${help#hg } + cmd=${cmd%%[$' \n']*} + canonical=1 + _hg_command_specific +} + +_hg_command_specific() +{ + if [ "$(type -t "_hg_cmd_$cmd")" = function ]; then + "_hg_cmd_$cmd" + return 0 + fi + + if [ "$cmd" != status ] && [ "$prev" = -r ] || [ "$prev" == --rev ]; then + if [ $canonical = 1 ]; then + _hg_tags + _hg_branches + return 0 + elif [[ status != "$cmd"* ]]; then + _hg_tags + _hg_branches + return 0 + else + return 1 + fi + fi + + case "$cmd" in + help) + _hg_commands + ;; + export) + if _hg_ext_mq_patchlist qapplied && [ "${COMPREPLY[*]}" ]; then + return 0 + fi + _hg_tags + _hg_branches + ;; + manifest|update) + _hg_tags + _hg_branches + ;; + pull|push|outgoing|incoming) + _hg_paths + _hg_repos + ;; + paths) + _hg_paths + ;; + add) + _hg_status "u" + ;; + merge) + _hg_tags + _hg_branches + ;; + commit) + _hg_status "mar" + ;; + remove) + _hg_status "d" + ;; + forget) + _hg_status "a" + ;; + diff) + _hg_status "mar" + ;; + revert) + _hg_status "mard" + ;; + clone) + local count=$(_hg_count_non_option) + if [ $count = 1 ]; then + _hg_paths + fi + _hg_repos + ;; + debugindex|debugindexdot) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur")) + ;; + debugdata) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur")) + ;; + *) + return 1 + ;; + esac + + return 0 +} + +complete -o bashdefault -o default -F _hg hg 2>/dev/null \ + || complete -o default -F _hg hg + + +# Completion for commands provided by extensions + +# mq +_hg_ext_mq_patchlist() +{ + local patches + patches=$("$hg" $1 2>/dev/null) + if [ $? -eq 0 ] && [ "$patches" ]; then + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$patches' -- "$cur")) + return 0 + fi + return 1 +} + +_hg_ext_mq_queues() +{ + local root=$("$hg" root 2>/dev/null) + local n + for n in $(cd "$root"/.hg && compgen -d -- "$cur"); do + # I think we're usually not interested in the regular "patches" queue + # so just filter it. + if [ "$n" != patches ] && [ -e "$root/.hg/$n/series" ]; then + COMPREPLY=(${COMPREPLY[@]:-} "$n") + fi + done +} + +_hg_cmd_qpop() +{ + if [[ "$prev" = @(-n|--name) ]]; then + _hg_ext_mq_queues + return + fi + _hg_ext_mq_patchlist qapplied +} + +_hg_cmd_qpush() +{ + if [[ "$prev" = @(-n|--name) ]]; then + _hg_ext_mq_queues + return + fi + _hg_ext_mq_patchlist qunapplied +} + +_hg_cmd_qgoto() +{ + if [[ "$prev" = @(-n|--name) ]]; then + _hg_ext_mq_queues + return + fi + _hg_ext_mq_patchlist qseries +} + +_hg_cmd_qdelete() +{ + local qcmd=qunapplied + if [[ "$prev" = @(-r|--rev) ]]; then + qcmd=qapplied + fi + _hg_ext_mq_patchlist $qcmd +} + +_hg_cmd_qsave() +{ + if [[ "$prev" = @(-n|--name) ]]; then + _hg_ext_mq_queues + return + fi +} + +_hg_cmd_strip() +{ + _hg_tags + _hg_branches +} + +_hg_cmd_qcommit() +{ + local root=$("$hg" root 2>/dev/null) + # this is run in a sub-shell, so we can't use _hg_status + local files=$(cd "$root/.hg/patches" 2>/dev/null && + "$hg" status -nmar 2>/dev/null) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) +} + +_hg_cmd_qfold() +{ + _hg_ext_mq_patchlist qunapplied +} + +_hg_cmd_qrename() +{ + _hg_ext_mq_patchlist qseries +} + +_hg_cmd_qheader() +{ + _hg_ext_mq_patchlist qseries +} + +_hg_cmd_qclone() +{ + local count=$(_hg_count_non_option) + if [ $count = 1 ]; then + _hg_paths + fi + _hg_repos +} + +_hg_ext_mq_guards() +{ + "$hg" qselect --series 2>/dev/null | sed -e 's/^.//' +} + +_hg_cmd_qselect() +{ + local guards=$(_hg_ext_mq_guards) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$guards' -- "$cur")) +} + +_hg_cmd_qguard() +{ + local prefix='' + + if [[ "$cur" == +* ]]; then + prefix=+ + elif [[ "$cur" == -* ]]; then + prefix=- + fi + local ncur=${cur#[-+]} + + if ! [ "$prefix" ]; then + _hg_ext_mq_patchlist qseries + return + fi + + local guards=$(_hg_ext_mq_guards) + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -P $prefix -W '$guards' -- "$ncur")) +} + +_hg_opt_qguard() +{ + local i + for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do + if [[ ${COMP_WORDS[i]} != -* ]]; then + if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then + _hg_cmd_qguard + return 0 + fi + elif [ "${COMP_WORDS[i]}" = -- ]; then + _hg_cmd_qguard + return 0 + fi + done + return 1 +} + + +# hbisect +_hg_cmd_bisect() +{ + local i subcmd + + # find the sub-command + for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do + if [[ ${COMP_WORDS[i]} != -* ]]; then + if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then + subcmd="${COMP_WORDS[i]}" + break + fi + fi + done + + if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then + COMPREPLY=(${COMPREPLY[@]:-} + $(compgen -W 'bad good help init next reset' -- "$cur")) + return + fi + + case "$subcmd" in + good|bad) + _hg_tags + _hg_branches + ;; + esac + + return +} + + +# patchbomb +_hg_cmd_email() +{ + case "$prev" in + -c|--cc|-t|--to|-f|--from|--bcc) + # we need an e-mail address. let the user provide a function + # to get them + if [ "$(type -t _hg_emails)" = function ]; then + local arg=to + if [[ "$prev" == @(-f|--from) ]]; then + arg=from + fi + local addresses=$(_hg_emails $arg) + COMPREPLY=(${COMPREPLY[@]:-} + $(compgen -W '$addresses' -- "$cur")) + fi + return + ;; + -m|--mbox) + # fallback to standard filename completion + return + ;; + -s|--subject) + # free form string + return + ;; + esac + + _hg_tags + _hg_branches + return +} + + +# gpg +_hg_cmd_sign() +{ + _hg_tags + _hg_branches +} + + +# transplant +_hg_cmd_transplant() +{ + case "$prev" in + -s|--source) + _hg_paths + _hg_repos + return + ;; + --filter) + # standard filename completion + return + ;; + esac + + # all other transplant options values and command parameters are revisions + _hg_tags + _hg_branches + return +} + diff --git a/sys/src/cmd/hg/contrib/buildrpm b/sys/src/cmd/hg/contrib/buildrpm new file mode 100755 index 000000000..641ddbfac --- /dev/null +++ b/sys/src/cmd/hg/contrib/buildrpm @@ -0,0 +1,72 @@ +#!/bin/sh +# +# Build a Mercurial RPM in place. +# +# Bryan O'Sullivan +# +# Tested on +# - Fedora 10 +# - Fedora 11 +# - Centos 5.3 (with Fedora EPEL repo for asciidoc) + +HG="`dirname $0`/../hg" +PYTHONPATH="`dirname $0`/../mercurial/pure" +export PYTHONPATH + +root="`$HG root 2>/dev/null`" +specfile=contrib/mercurial.spec + +if [ -z "$root" ]; then + echo 'You are not inside a Mercurial repository!' 1>&2 + exit 1 +fi + +rpmdir=/tmp/"`basename $root | sed 's/ /_/'`"-rpm # FIXME: Insecure /tmp handling + +cd "$root" +rm -rf $rpmdir +mkdir -p $rpmdir/RPMS +$HG clone "$root" $rpmdir/BUILD + +if [ ! -f $specfile ]; then + echo "Cannot find $specfile!" 1>&2 + exit 1 +fi + +tmpspec=/tmp/`basename "$specfile"`.$$ # FIXME: Insecure /tmp handling +# Use the most recent tag as the version. +version=`$HG tags | python -c 'import sys; print [l for l in sys.stdin.readlines() if l[0].isdigit()][0].split()[0]'` +# Compute the release number as the difference in revision numbers +# between the tip and the most recent tag. +release=`$HG tags | python -c 'import sys; l = sys.stdin.readlines(); print int(l[0].split()[1].split(":")[0]) - int([x for x in l if x[0].isdigit()][0].split()[1].split(":")[0])'` +tip=`$HG -q tip` + +# Beat up the spec file +sed -e 's,^Source:.*,Source: /dev/null,' \ + -e "s,^Version:.*,Version: $version," \ + -e "s,^Release:.*,Release: $release," \ + -e "s,^%prep.*,Changeset: $tip\n\0," \ + -e 's,^%setup.*,,' \ + $specfile > $tmpspec + +cat <> $tmpspec +%changelog +* `LANG=en_US date +'%a %b %d %Y'` `$HG showconfig ui.username` $version-$release +- Automatically built via $0 + +EOF +$HG log \ + --template '* {date|rfc822date} {author}\n- {desc|firstline}\n\n' \ + .hgtags \ + | sed -e 's/^\(\* [MTWFS][a-z][a-z]\), \([0-3][0-9]\) \([A-Z][a-z][a-z]\) /\1 \3 \2 /' \ + -e '/^\* [MTWFS][a-z][a-z] /{s/ [012][0-9]:[0-9][0-9]:[0-9][0-9] [+-][0-9]\{4\}//}' \ + >> $tmpspec + +rpmbuild --define "_topdir $rpmdir" -bb $tmpspec +if [ $? = 0 ]; then + rm -rf $tmpspec $rpmdir/BUILD + mv $rpmdir/RPMS/*/* $rpmdir && rm -r $rpmdir/RPMS + echo + echo "Packages are in $rpmdir:" + ls -l $rpmdir/*.rpm +fi diff --git a/sys/src/cmd/hg/contrib/convert-repo b/sys/src/cmd/hg/contrib/convert-repo new file mode 100755 index 000000000..4113f40c0 --- /dev/null +++ b/sys/src/cmd/hg/contrib/convert-repo @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# +# Wrapper script around the convert.py hgext extension +# for foreign SCM conversion to mercurial format. +# + +import sys +from mercurial import ui, fancyopts +from hgext import convert + +# Options extracted from the cmdtable +func, options, help = convert.cmdtable['convert'] + +# An ui instance +u = ui.ui() + +opts = {} +args = [] +try: + args = list(fancyopts.fancyopts(sys.argv[1:], options, opts)) + args += [None]*(3 - len(args)) + src, dest, revmapfile = args +except (fancyopts.getopt.GetoptError, ValueError), inst: + u.warn('Usage:\n%s\n' % help) + sys.exit(-1) + +convert.convert(u, src, dest, revmapfile, **opts) diff --git a/sys/src/cmd/hg/contrib/dumprevlog b/sys/src/cmd/hg/contrib/dumprevlog new file mode 100644 index 000000000..caf287d49 --- /dev/null +++ b/sys/src/cmd/hg/contrib/dumprevlog @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# Dump revlogs as raw data stream +# $ find .hg/store/ -name "*.i" | xargs dumprevlog > repo.dump + +import sys +from mercurial import revlog, node, util + +for fp in (sys.stdin, sys.stdout, sys.stderr): + util.set_binary(fp) + +for f in sys.argv[1:]: + binopen = lambda fn: open(fn, 'rb') + r = revlog.revlog(binopen, f) + print "file:", f + for i in r: + n = r.node(i) + p = r.parents(n) + d = r.revision(n) + print "node:", node.hex(n) + print "linkrev:", r.linkrev(i) + print "parents:", node.hex(p[0]), node.hex(p[1]) + print "length:", len(d) + print "-start-" + print d + print "-end-" diff --git a/sys/src/cmd/hg/contrib/git-viz/git-cat-file b/sys/src/cmd/hg/contrib/git-viz/git-cat-file new file mode 100644 index 000000000..ee4a0aed6 --- /dev/null +++ b/sys/src/cmd/hg/contrib/git-viz/git-cat-file @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" + diff --git a/sys/src/cmd/hg/contrib/git-viz/git-diff-tree b/sys/src/cmd/hg/contrib/git-viz/git-diff-tree new file mode 100644 index 000000000..ee4a0aed6 --- /dev/null +++ b/sys/src/cmd/hg/contrib/git-viz/git-diff-tree @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" + diff --git a/sys/src/cmd/hg/contrib/git-viz/git-rev-list b/sys/src/cmd/hg/contrib/git-viz/git-rev-list new file mode 100644 index 000000000..ee4a0aed6 --- /dev/null +++ b/sys/src/cmd/hg/contrib/git-viz/git-rev-list @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" + diff --git a/sys/src/cmd/hg/contrib/git-viz/git-rev-tree b/sys/src/cmd/hg/contrib/git-viz/git-rev-tree new file mode 100644 index 000000000..ee4a0aed6 --- /dev/null +++ b/sys/src/cmd/hg/contrib/git-viz/git-rev-tree @@ -0,0 +1,5 @@ +#!/bin/sh + +op=`basename $0 | sed -e 's/^git-//'` +exec hgit $op "$@" + diff --git a/sys/src/cmd/hg/contrib/git-viz/hg-viz b/sys/src/cmd/hg/contrib/git-viz/hg-viz new file mode 100644 index 000000000..81bd57b45 --- /dev/null +++ b/sys/src/cmd/hg/contrib/git-viz/hg-viz @@ -0,0 +1,26 @@ +#!/bin/sh + +set -e + +if test x"$1" != x ; then + cd $1 +fi + +if [ ! -d ".hg" ]; then + echo "${1:-.} is not a mercurial repository" 1>&2 + echo "Aborting" 1>&2 + exit 1 +fi +if [ ! -d ".git" ]; then + mkdir -v ".git" +fi +if [ -e ".git/HEAD" ]; then + if [ ! -e ".git/HEAD.hg-viz-save" ]; then + mv -v ".git/HEAD" ".git/HEAD.hg-viz-save" + else + rm -vf ".git/HEAD" + fi +fi +hg history | head -1 | awk -F: '{print $3}' > .git/HEAD +git-viz + diff --git a/sys/src/cmd/hg/contrib/hg-relink b/sys/src/cmd/hg/contrib/hg-relink new file mode 100755 index 000000000..266e7edfc --- /dev/null +++ b/sys/src/cmd/hg/contrib/hg-relink @@ -0,0 +1,128 @@ +#!/usr/bin/env python +# +# Copyright (C) 2007 Brendan Cully +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import os, sys + +class ConfigError(Exception): pass + +def usage(): + print """relink + Recreate hard links between source and destination repositories""" + +class Config: + def __init__(self, args): + if len(args) != 3: + raise ConfigError("wrong number of arguments") + self.src = os.path.abspath(args[1]) + self.dst = os.path.abspath(args[2]) + for d in (self.src, self.dst): + if not os.path.exists(os.path.join(d, '.hg')): + raise ConfigError("%s: not a mercurial repository" % d) + +def collect(src): + seplen = len(os.path.sep) + candidates = [] + for dirpath, dirnames, filenames in os.walk(src): + relpath = dirpath[len(src) + seplen:] + for filename in filenames: + if not filename.endswith('.i'): + continue + st = os.stat(os.path.join(dirpath, filename)) + candidates.append((os.path.join(relpath, filename), st)) + + return candidates + +def prune(candidates, dst): + def getdatafile(path): + if not path.endswith('.i'): + return None, None + df = path[:-1] + 'd' + try: + st = os.stat(df) + except OSError: + return None, None + return df, st + + def linkfilter(dst, st): + try: + ts = os.stat(dst) + except OSError: + # Destination doesn't have this file? + return False + if st.st_ino == ts.st_ino: + return False + if st.st_dev != ts.st_dev: + # No point in continuing + raise Exception('Source and destination are on different devices') + if st.st_size != ts.st_size: + # TODO: compare revlog heads + return False + return st + + targets = [] + for fn, st in candidates: + tgt = os.path.join(dst, fn) + ts = linkfilter(tgt, st) + if not ts: + continue + targets.append((fn, ts.st_size)) + df, ts = getdatafile(tgt) + if df: + targets.append((fn[:-1] + 'd', ts.st_size)) + + return targets + +def relink(src, dst, files): + def relinkfile(src, dst): + bak = dst + '.bak' + os.rename(dst, bak) + try: + os.link(src, dst) + except OSError: + os.rename(bak, dst) + raise + os.remove(bak) + + CHUNKLEN = 65536 + relinked = 0 + savedbytes = 0 + + for f, sz in files: + source = os.path.join(src, f) + tgt = os.path.join(dst, f) + sfp = file(source) + dfp = file(tgt) + sin = sfp.read(CHUNKLEN) + while sin: + din = dfp.read(CHUNKLEN) + if sin != din: + break + sin = sfp.read(CHUNKLEN) + if sin: + continue + try: + relinkfile(source, tgt) + print 'Relinked %s' % f + relinked += 1 + savedbytes += sz + except OSError, inst: + print '%s: %s' % (tgt, str(inst)) + + print 'Relinked %d files (%d bytes reclaimed)' % (relinked, savedbytes) + +try: + cfg = Config(sys.argv) +except ConfigError, inst: + print str(inst) + usage() + sys.exit(1) + +src = os.path.join(cfg.src, '.hg') +dst = os.path.join(cfg.dst, '.hg') +candidates = collect(src) +targets = prune(candidates, dst) +relink(src, dst, targets) diff --git a/sys/src/cmd/hg/contrib/hg-ssh b/sys/src/cmd/hg/contrib/hg-ssh new file mode 100755 index 000000000..64a6e4c02 --- /dev/null +++ b/sys/src/cmd/hg/contrib/hg-ssh @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# +# Copyright 2005-2007 by Intevation GmbH +# +# Author(s): +# Thomas Arendsen Hein +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +""" +hg-ssh - a wrapper for ssh access to a limited set of mercurial repos + +To be used in ~/.ssh/authorized_keys with the "command" option, see sshd(8): +command="hg-ssh path/to/repo1 /path/to/repo2 ~/repo3 ~user/repo4" ssh-dss ... +(probably together with these other useful options: + no-port-forwarding,no-X11-forwarding,no-agent-forwarding) + +This allows pull/push over ssh to to the repositories given as arguments. + +If all your repositories are subdirectories of a common directory, you can +allow shorter paths with: +command="cd path/to/my/repositories && hg-ssh repo1 subdir/repo2" + +You can use pattern matching of your normal shell, e.g.: +command="cd repos && hg-ssh user/thomas/* projects/{mercurial,foo}" +""" + +# enable importing on demand to reduce startup time +from mercurial import demandimport; demandimport.enable() + +from mercurial import dispatch + +import sys, os + +cwd = os.getcwd() +allowed_paths = [os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) + for path in sys.argv[1:]] +orig_cmd = os.getenv('SSH_ORIGINAL_COMMAND', '?') + +if orig_cmd.startswith('hg -R ') and orig_cmd.endswith(' serve --stdio'): + path = orig_cmd[6:-14] + repo = os.path.normpath(os.path.join(cwd, os.path.expanduser(path))) + if repo in allowed_paths: + dispatch.dispatch(['-R', repo, 'serve', '--stdio']) + else: + sys.stderr.write("Illegal repository %r\n" % repo) + sys.exit(-1) +else: + sys.stderr.write("Illegal command %r\n" % orig_cmd) + sys.exit(-1) + diff --git a/sys/src/cmd/hg/contrib/hgdiff b/sys/src/cmd/hg/contrib/hgdiff new file mode 100755 index 000000000..c7b9aaf34 --- /dev/null +++ b/sys/src/cmd/hg/contrib/hgdiff @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +import os, sys, struct, stat +import difflib +import re +from optparse import OptionParser +from mercurial.bdiff import bdiff, blocks +from mercurial.mdiff import bunidiff, diffopts + +VERSION="0.3" +usage = "usage: %prog [options] file1 file2" +parser = OptionParser(usage=usage) + +parser.add_option("-d", "--difflib", action="store_true", default=False) +parser.add_option('-x', '--count', default=1) +parser.add_option('-c', '--context', type="int", default=3) +parser.add_option('-p', '--show-c-function', action="store_true", default=False) +parser.add_option('-w', '--ignore-all-space', action="store_true", + default=False) + +(options, args) = parser.parse_args() + +if not args: + parser.print_help() + sys.exit(1) + +# simple utility function to put all the +# files from a directory tree into a dict +def buildlist(names, top): + tlen = len(top) + for root, dirs, files in os.walk(top): + l = root[tlen + 1:] + for x in files: + p = os.path.join(root, x) + st = os.lstat(p) + if stat.S_ISREG(st.st_mode): + names[os.path.join(l, x)] = (st.st_dev, st.st_ino) + +def diff_files(file1, file2): + if file1 is None: + b = file(file2).read().splitlines(True) + l1 = "--- %s\n" % (file2) + l2 = "+++ %s\n" % (file2) + l3 = "@@ -0,0 +1,%d @@\n" % len(b) + l = [l1, l2, l3] + ["+" + e for e in b] + elif file2 is None: + a = file(file1).read().splitlines(True) + l1 = "--- %s\n" % (file1) + l2 = "+++ %s\n" % (file1) + l3 = "@@ -1,%d +0,0 @@\n" % len(a) + l = [l1, l2, l3] + ["-" + e for e in a] + else: + t1 = file(file1).read() + t2 = file(file2).read() + l1 = t1.splitlines(True) + l2 = t2.splitlines(True) + if options.difflib: + l = difflib.unified_diff(l1, l2, file1, file2) + else: + l = bunidiff(t1, t2, l1, l2, file1, file2, + diffopts(context=options.context, + showfunc=options.show_c_function, + ignorews=options.ignore_all_space)) + for x in l: + if x[-1] != '\n': + x += "\n\ No newline at end of file\n" + print x, + +file1 = args[0] +file2 = args[1] + +if os.path.isfile(file1) and os.path.isfile(file2): + diff_files(file1, file2) +elif os.path.isdir(file1): + if not os.path.isdir(file2): + sys.stderr.write("file types don't match\n") + sys.exit(1) + + d1 = {} + d2 = {} + + buildlist(d1, file1) + buildlist(d2, file2) + keys = d1.keys() + keys.sort() + for x in keys: + if x not in d2: + f2 = None + else: + f2 = os.path.join(file2, x) + st1 = d1[x] + st2 = d2[x] + del d2[x] + if st1[0] == st2[0] and st1[1] == st2[1]: + sys.stderr.write("%s is a hard link\n" % x) + continue + x = os.path.join(file1, x) + diff_files(x, f2) + keys = d2.keys() + keys.sort() + for x in keys: + f1 = None + x = os.path.join(file2, x) + diff_files(f1, x) + diff --git a/sys/src/cmd/hg/contrib/hgk b/sys/src/cmd/hg/contrib/hgk new file mode 100755 index 000000000..2031eafbf --- /dev/null +++ b/sys/src/cmd/hg/contrib/hgk @@ -0,0 +1,4001 @@ +#!/usr/bin/env wish + +# Copyright (C) 2005 Paul Mackerras. All rights reserved. +# This program is free software; it may be used, copied, modified +# and distributed under the terms of the GNU General Public Licence, +# either version 2, or (at your option) any later version. +# +# See hgk.py for extension usage and configuration. + + +# Modified version of Tip 171: +# http://www.tcl.tk/cgi-bin/tct/tip/171.html +# +# The in_mousewheel global was added to fix strange reentrancy issues. +# The whole snipped is activated only under windows, mouse wheel +# bindings working already under MacOSX and Linux. + +if {[tk windowingsystem] eq "win32"} { + +set mw_classes [list Text Listbox Table TreeCtrl] + foreach class $mw_classes { bind $class {} } + +set in_mousewheel 0 + +proc ::tk::MouseWheel {wFired X Y D {shifted 0}} { + global in_mousewheel + if { $in_mousewheel != 0 } { return } + # Set event to check based on call + set evt "<[expr {$shifted?{Shift-}:{}}]MouseWheel>" + # do not double-fire in case the class already has a binding + if {[bind [winfo class $wFired] $evt] ne ""} { return } + # obtain the window the mouse is over + set w [winfo containing $X $Y] + # if we are outside the app, try and scroll the focus widget + if {![winfo exists $w]} { catch {set w [focus]} } + if {[winfo exists $w]} { + + if {[bind $w $evt] ne ""} { + # Awkward ... this widget has a MouseWheel binding, but to + # trigger successfully in it, we must give it focus. + catch {focus} old + if {$w ne $old} { focus $w } + set in_mousewheel 1 + event generate $w $evt -rootx $X -rooty $Y -delta $D + set in_mousewheel 0 + if {$w ne $old} { focus $old } + return + } + + # aqua and x11/win32 have different delta handling + if {[tk windowingsystem] ne "aqua"} { + set delta [expr {- ($D / 30)}] + } else { + set delta [expr {- ($D)}] + } + # scrollbars have different call conventions + if {[string match "*Scrollbar" [winfo class $w]]} { + catch {tk::ScrollByUnits $w \ + [string index [$w cget -orient] 0] $delta} + } else { + set cmd [list $w [expr {$shifted ? "xview" : "yview"}] \ + scroll $delta units] + # Walking up to find the proper widget (handles cases like + # embedded widgets in a canvas) + while {[catch $cmd] && [winfo toplevel $w] ne $w} { + set w [winfo parent $w] + } + } + } +} + +bind all [list ::tk::MouseWheel %W %X %Y %D 0] + +# end of win32 section +} + + +# Unify right mouse button handling. +# See "mouse buttons on macintosh" thread on comp.lang.tcl +if {[tk windowingsystem] eq "aqua"} { + event add <> + event add <> +} else { + event add <> +} + +proc gitdir {} { + global env + if {[info exists env(GIT_DIR)]} { + return $env(GIT_DIR) + } else { + return ".hg" + } +} + +proc getcommits {rargs} { + global commits commfd phase canv mainfont env + global startmsecs nextupdate ncmupdate + global ctext maincursor textcursor leftover + + # check that we can find a .git directory somewhere... + set gitdir [gitdir] + if {![file isdirectory $gitdir]} { + error_popup "Cannot find the git directory \"$gitdir\"." + exit 1 + } + set commits {} + set phase getcommits + set startmsecs [clock clicks -milliseconds] + set nextupdate [expr $startmsecs + 100] + set ncmupdate 1 + set limit 0 + set revargs {} + for {set i 0} {$i < [llength $rargs]} {incr i} { + set opt [lindex $rargs $i] + if {$opt == "--limit"} { + incr i + set limit [lindex $rargs $i] + } else { + lappend revargs $opt + } + } + if [catch { + set parse_args [concat --default HEAD $revargs] + set parse_temp [eval exec {$env(HG)} --config ui.report_untrusted=false debug-rev-parse $parse_args] + regsub -all "\r\n" $parse_temp "\n" parse_temp + set parsed_args [split $parse_temp "\n"] + } err] { + # if git-rev-parse failed for some reason... + if {$rargs == {}} { + set revargs HEAD + } + set parsed_args $revargs + } + if {$limit > 0} { + set parsed_args [concat -n $limit $parsed_args] + } + if [catch { + set commfd [open "|{$env(HG)} --config ui.report_untrusted=false debug-rev-list --header --topo-order --parents $parsed_args" r] + } err] { + puts stderr "Error executing hg debug-rev-list: $err" + exit 1 + } + set leftover {} + fconfigure $commfd -blocking 0 -translation lf + fileevent $commfd readable [list getcommitlines $commfd] + $canv delete all + $canv create text 3 3 -anchor nw -text "Reading commits..." \ + -font $mainfont -tags textitems + . config -cursor watch + settextcursor watch +} + +proc getcommitlines {commfd} { + global commits parents cdate children + global commitlisted phase commitinfo nextupdate + global stopped redisplaying leftover + + set stuff [read $commfd] + if {$stuff == {}} { + if {![eof $commfd]} return + # set it blocking so we wait for the process to terminate + fconfigure $commfd -blocking 1 + if {![catch {close $commfd} err]} { + after idle finishcommits + return + } + if {[string range $err 0 4] == "usage"} { + set err \ +{Gitk: error reading commits: bad arguments to git-rev-list. +(Note: arguments to gitk are passed to git-rev-list +to allow selection of commits to be displayed.)} + } else { + set err "Error reading commits: $err" + } + error_popup $err + exit 1 + } + set start 0 + while 1 { + set i [string first "\0" $stuff $start] + if {$i < 0} { + append leftover [string range $stuff $start end] + return + } + set cmit [string range $stuff $start [expr {$i - 1}]] + if {$start == 0} { + set cmit "$leftover$cmit" + set leftover {} + } + set start [expr {$i + 1}] + regsub -all "\r\n" $cmit "\n" cmit + set j [string first "\n" $cmit] + set ok 0 + if {$j >= 0} { + set ids [string range $cmit 0 [expr {$j - 1}]] + set ok 1 + foreach id $ids { + if {![regexp {^[0-9a-f]{12}$} $id]} { + set ok 0 + break + } + } + } + if {!$ok} { + set shortcmit $cmit + if {[string length $shortcmit] > 80} { + set shortcmit "[string range $shortcmit 0 80]..." + } + error_popup "Can't parse hg debug-rev-list output: {$shortcmit}" + exit 1 + } + set id [lindex $ids 0] + set olds [lrange $ids 1 end] + set cmit [string range $cmit [expr {$j + 1}] end] + lappend commits $id + set commitlisted($id) 1 + parsecommit $id $cmit 1 [lrange $ids 1 end] + drawcommit $id + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate 1 + } + while {$redisplaying} { + set redisplaying 0 + if {$stopped == 1} { + set stopped 0 + set phase "getcommits" + foreach id $commits { + drawcommit $id + if {$stopped} break + if {[clock clicks -milliseconds] >= $nextupdate} { + doupdate 1 + } + } + } + } + } +} + +proc doupdate {reading} { + global commfd nextupdate numcommits ncmupdate + + if {$reading} { + fileevent $commfd readable {} + } + update + set nextupdate [expr {[clock clicks -milliseconds] + 100}] + if {$numcommits < 100} { + set ncmupdate [expr {$numcommits + 1}] + } elseif {$numcommits < 10000} { + set ncmupdate [expr {$numcommits + 10}] + } else { + set ncmupdate [expr {$numcommits + 100}] + } + if {$reading} { + fileevent $commfd readable [list getcommitlines $commfd] + } +} + +proc readcommit {id} { + global env + if [catch {set contents [exec $env(HG) --config ui.report_untrusted=false debug-cat-file commit $id]}] return + parsecommit $id $contents 0 {} +} + +proc parsecommit {id contents listed olds} { + global commitinfo children nchildren parents nparents cdate ncleft + global firstparents + + set inhdr 1 + set comment {} + set headline {} + set auname {} + set audate {} + set comname {} + set comdate {} + set rev {} + set branch {} + if {![info exists nchildren($id)]} { + set children($id) {} + set nchildren($id) 0 + set ncleft($id) 0 + } + set parents($id) $olds + set nparents($id) [llength $olds] + foreach p $olds { + if {![info exists nchildren($p)]} { + set children($p) [list $id] + set nchildren($p) 1 + set ncleft($p) 1 + } elseif {[lsearch -exact $children($p) $id] < 0} { + lappend children($p) $id + incr nchildren($p) + incr ncleft($p) + } + } + regsub -all "\r\n" $contents "\n" contents + foreach line [split $contents "\n"] { + if {$inhdr} { + set line [split $line] + if {$line == {}} { + set inhdr 0 + } else { + set tag [lindex $line 0] + if {$tag == "author"} { + set x [expr {[llength $line] - 2}] + set audate [lindex $line $x] + set auname [join [lrange $line 1 [expr {$x - 1}]]] + } elseif {$tag == "committer"} { + set x [expr {[llength $line] - 2}] + set comdate [lindex $line $x] + set comname [join [lrange $line 1 [expr {$x - 1}]]] + } elseif {$tag == "revision"} { + set rev [lindex $line 1] + } elseif {$tag == "branch"} { + set branch [join [lrange $line 1 end]] + } + } + } else { + if {$comment == {}} { + set headline [string trim $line] + } else { + append comment "\n" + } + if {!$listed} { + # git-rev-list indents the comment by 4 spaces; + # if we got this via git-cat-file, add the indentation + append comment " " + } + append comment $line + } + } + if {$audate != {}} { + set audate [clock format $audate -format "%Y-%m-%d %H:%M:%S"] + } + if {$comdate != {}} { + set cdate($id) $comdate + set comdate [clock format $comdate -format "%Y-%m-%d %H:%M:%S"] + } + set commitinfo($id) [list $headline $auname $audate \ + $comname $comdate $comment $rev $branch] + + if {[info exists firstparents]} { + set i [lsearch $firstparents $id] + if {$i != -1} { + # remove the parent from firstparents, possible building + # an empty list + set firstparents [concat \ + [lrange $firstparents 0 [expr $i - 1]] \ + [lrange $firstparents [expr $i + 1] end]] + if {$firstparents eq {}} { + # we have found all parents of the first changeset + # which means that we can safely select the first line + after idle { + selectline 0 0 + } + } + } + } else { + # this is the first changeset, save the parents + set firstparents $olds + if {$firstparents eq {}} { + # a repository with a single changeset + after idle { + selectline 0 0 + } + } + } +} + +proc readrefs {} { + global tagids idtags headids idheads tagcontents env curid + + set status [catch {exec $env(HG) --config ui.report_untrusted=false id} curid] + if { $status != 0 } { + puts $::errorInfo + if { ![string equal $::errorCode NONE] } { + exit 2 + } + } + regexp -- {[[:xdigit:]]+} $curid curid + + set status [catch {exec $env(HG) --config ui.report_untrusted=false tags} tags] + if { $status != 0 } { + puts $::errorInfo + if { ![string equal $::errorCode NONE] } { + exit 2 + } + } + regsub -all "\r\n" $tags "\n" tags + + set lines [split $tags "\n"] + foreach f $lines { + regexp {(\S+)$} $f full + regsub {\s+(\S+)$} $f "" direct + set sha [split $full ':'] + set tag [lindex $sha 1] + lappend tagids($direct) $tag + lappend idtags($tag) $direct + } + + set status [catch {exec $env(HG) --config ui.report_untrusted=false heads} heads] + if { $status != 0 } { + puts $::errorInfo + if { ![string equal $::errorCode NONE] } { + exit 2 + } + } + regsub -all "\r\n" $heads "\n" heads + + set lines [split $heads "\n"] + foreach f $lines { + set match "" + regexp {changeset:\s+(\S+):(\S+)$} $f match id sha + if {$match != ""} { + lappend idheads($sha) $id + } + } + +} + +proc readotherrefs {base dname excl} { + global otherrefids idotherrefs + + set git [gitdir] + set files [glob -nocomplain -types f [file join $git $base *]] + foreach f $files { + catch { + set fd [open $f r] + set line [read $fd 40] + if {[regexp {^[0-9a-f]{12}} $line id]} { + set name "$dname[file tail $f]" + set otherrefids($name) $id + lappend idotherrefs($id) $name + } + close $fd + } + } + set dirs [glob -nocomplain -types d [file join $git $base *]] + foreach d $dirs { + set dir [file tail $d] + if {[lsearch -exact $excl $dir] >= 0} continue + readotherrefs [file join $base $dir] "$dname$dir/" {} + } +} + +proc allcansmousewheel {delta} { + set delta [expr -5*(int($delta)/abs($delta))] + allcanvs yview scroll $delta units +} + +proc error_popup msg { + set w .error + toplevel $w + wm transient $w . + message $w.m -text $msg -justify center -aspect 400 + pack $w.m -side top -fill x -padx 20 -pady 20 + button $w.ok -text OK -command "destroy $w" + pack $w.ok -side bottom -fill x + bind $w "grab $w; focus $w" + tkwait window $w +} + +proc makewindow {} { + global canv canv2 canv3 linespc charspc ctext cflist textfont + global findtype findtypemenu findloc findstring fstring geometry + global entries sha1entry sha1string sha1but + global maincursor textcursor curtextcursor + global rowctxmenu gaudydiff mergemax + global hgvdiff bgcolor fgcolor diffremcolor diffaddcolor diffmerge1color + global diffmerge2color hunksepcolor + + menu .bar + .bar add cascade -label "File" -menu .bar.file + menu .bar.file + .bar.file add command -label "Reread references" -command rereadrefs + .bar.file add command -label "Quit" -command doquit + menu .bar.help + .bar add cascade -label "Help" -menu .bar.help + .bar.help add command -label "About gitk" -command about + . configure -menu .bar + + if {![info exists geometry(canv1)]} { + set geometry(canv1) [expr 45 * $charspc] + set geometry(canv2) [expr 30 * $charspc] + set geometry(canv3) [expr 15 * $charspc] + set geometry(canvh) [expr 25 * $linespc + 4] + set geometry(ctextw) 80 + set geometry(ctexth) 30 + set geometry(cflistw) 30 + } + panedwindow .ctop -orient vertical + if {[info exists geometry(width)]} { + .ctop conf -width $geometry(width) -height $geometry(height) + set texth [expr {$geometry(height) - $geometry(canvh) - 56}] + set geometry(ctexth) [expr {($texth - 8) / + [font metrics $textfont -linespace]}] + } + frame .ctop.top + frame .ctop.top.bar + pack .ctop.top.bar -side bottom -fill x + set cscroll .ctop.top.csb + scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0 + pack $cscroll -side right -fill y + panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4 + pack .ctop.top.clist -side top -fill both -expand 1 + .ctop add .ctop.top + set canv .ctop.top.clist.canv + canvas $canv -height $geometry(canvh) -width $geometry(canv1) \ + -bg $bgcolor -bd 0 \ + -yscrollincr $linespc -yscrollcommand "$cscroll set" -selectbackground grey + .ctop.top.clist add $canv + set canv2 .ctop.top.clist.canv2 + canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \ + -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground grey + .ctop.top.clist add $canv2 + set canv3 .ctop.top.clist.canv3 + canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \ + -bg $bgcolor -bd 0 -yscrollincr $linespc -selectbackground grey + .ctop.top.clist add $canv3 + bind .ctop.top.clist {resizeclistpanes %W %w} + + set sha1entry .ctop.top.bar.sha1 + set entries $sha1entry + set sha1but .ctop.top.bar.sha1label + button $sha1but -text "SHA1 ID: " -state disabled -relief flat \ + -command gotocommit -width 8 + $sha1but conf -disabledforeground [$sha1but cget -foreground] + pack .ctop.top.bar.sha1label -side left + entry $sha1entry -width 40 -font $textfont -textvariable sha1string + trace add variable sha1string write sha1change + pack $sha1entry -side left -pady 2 + + image create bitmap bm-left -data { + #define left_width 16 + #define left_height 16 + static unsigned char left_bits[] = { + 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00, + 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00, + 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01}; + } + image create bitmap bm-right -data { + #define right_width 16 + #define right_height 16 + static unsigned char right_bits[] = { + 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c, + 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c, + 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01}; + } + button .ctop.top.bar.leftbut -image bm-left -command goback \ + -state disabled -width 26 + pack .ctop.top.bar.leftbut -side left -fill y + button .ctop.top.bar.rightbut -image bm-right -command goforw \ + -state disabled -width 26 + pack .ctop.top.bar.rightbut -side left -fill y + + button .ctop.top.bar.findbut -text "Find" -command dofind + pack .ctop.top.bar.findbut -side left + set findstring {} + set fstring .ctop.top.bar.findstring + lappend entries $fstring + entry $fstring -width 30 -font $textfont -textvariable findstring + pack $fstring -side left -expand 1 -fill x + set findtype Exact + set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \ + findtype Exact IgnCase Regexp] + set findloc "All fields" + tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \ + Comments Author Committer Files Pickaxe + pack .ctop.top.bar.findloc -side right + pack .ctop.top.bar.findtype -side right + # for making sure type==Exact whenever loc==Pickaxe + trace add variable findloc write findlocchange + + panedwindow .ctop.cdet -orient horizontal + .ctop add .ctop.cdet + frame .ctop.cdet.left + set ctext .ctop.cdet.left.ctext + text $ctext -fg $fgcolor -bg $bgcolor -state disabled -font $textfont \ + -width $geometry(ctextw) -height $geometry(ctexth) \ + -yscrollcommand ".ctop.cdet.left.sb set" \ + -xscrollcommand ".ctop.cdet.left.hb set" -wrap none + scrollbar .ctop.cdet.left.sb -command "$ctext yview" + scrollbar .ctop.cdet.left.hb -orient horizontal -command "$ctext xview" + pack .ctop.cdet.left.sb -side right -fill y + pack .ctop.cdet.left.hb -side bottom -fill x + pack $ctext -side left -fill both -expand 1 + .ctop.cdet add .ctop.cdet.left + + $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa" + if {$gaudydiff} { + $ctext tag conf hunksep -back blue -fore white + $ctext tag conf d0 -back "#ff8080" + $ctext tag conf d1 -back green + } else { + $ctext tag conf hunksep -fore $hunksepcolor + $ctext tag conf d0 -fore $diffremcolor + $ctext tag conf d1 -fore $diffaddcolor + + # The mX colours seem to be used in merge changesets, where m0 + # is first parent, m1 is second parent and so on. Git can have + # several parents, Hg cannot, so I think the m2..mmax would be + # unused. + $ctext tag conf m0 -fore $diffmerge1color + $ctext tag conf m1 -fore $diffmerge2color + $ctext tag conf m2 -fore green + $ctext tag conf m3 -fore purple + $ctext tag conf m4 -fore brown + $ctext tag conf mmax -fore darkgrey + set mergemax 5 + $ctext tag conf mresult -font [concat $textfont bold] + $ctext tag conf msep -font [concat $textfont bold] + $ctext tag conf found -back yellow + } + + frame .ctop.cdet.right + set cflist .ctop.cdet.right.cfiles + listbox $cflist -fg $fgcolor -bg $bgcolor \ + -selectmode extended -width $geometry(cflistw) \ + -yscrollcommand ".ctop.cdet.right.sb set" + scrollbar .ctop.cdet.right.sb -command "$cflist yview" + pack .ctop.cdet.right.sb -side right -fill y + pack $cflist -side left -fill both -expand 1 + .ctop.cdet add .ctop.cdet.right + bind .ctop.cdet {resizecdetpanes %W %w} + + pack .ctop -side top -fill both -expand 1 + + bindall <1> {selcanvline %W %x %y} + #bindall {selcanvline %W %x %y} + bindall "allcansmousewheel %D" + bindall "allcanvs yview scroll -5 units" + bindall "allcanvs yview scroll 5 units" + bindall <2> "allcanvs scan mark 0 %y" + bindall "allcanvs scan dragto 0 %y" + bind . "selnextline -1" + bind . "selnextline 1" + bind . "allcanvs yview scroll -1 pages" + bind . "allcanvs yview scroll 1 pages" + bindkey "$ctext yview scroll -1 pages" + bindkey "$ctext yview scroll -1 pages" + bindkey "$ctext yview scroll 1 pages" + bindkey p "selnextline -1" + bindkey n "selnextline 1" + bindkey b "$ctext yview scroll -1 pages" + bindkey d "$ctext yview scroll 18 units" + bindkey u "$ctext yview scroll -18 units" + bindkey / {findnext 1} + bindkey {findnext 0} + bindkey ? findprev + bindkey f nextfile + bind . doquit + bind . doquit + bind . dofind + bind . {findnext 0} + bind . findprev + bind . {incrfont 1} + bind . {incrfont 1} + bind . {incrfont -1} + bind . {incrfont -1} + bind $cflist <> listboxsel + bind . {savestuff %W} + bind . "click %W" + bind $fstring dofind + bind $sha1entry gotocommit + bind $sha1entry <> clearsha1 + + set maincursor [. cget -cursor] + set textcursor [$ctext cget -cursor] + set curtextcursor $textcursor + + set rowctxmenu .rowctxmenu + menu $rowctxmenu -tearoff 0 + $rowctxmenu add command -label "Diff this -> selected" \ + -command {diffvssel 0} + $rowctxmenu add command -label "Diff selected -> this" \ + -command {diffvssel 1} + $rowctxmenu add command -label "Make patch" -command mkpatch + $rowctxmenu add command -label "Create tag" -command mktag + $rowctxmenu add command -label "Write commit to file" -command writecommit + if { $hgvdiff ne "" } { + $rowctxmenu add command -label "Visual diff with parent" \ + -command {vdiff 1} + $rowctxmenu add command -label "Visual diff with selected" \ + -command {vdiff 0} + } +} + +# when we make a key binding for the toplevel, make sure +# it doesn't get triggered when that key is pressed in the +# find string entry widget. +proc bindkey {ev script} { + global entries + bind . $ev $script + set escript [bind Entry $ev] + if {$escript == {}} { + set escript [bind Entry ] + } + foreach e $entries { + bind $e $ev "$escript; break" + } +} + +# set the focus back to the toplevel for any click outside +# the entry widgets +proc click {w} { + global entries + foreach e $entries { + if {$w == $e} return + } + focus . +} + +proc savestuff {w} { + global canv canv2 canv3 ctext cflist mainfont textfont + global stuffsaved findmergefiles gaudydiff maxgraphpct + global maxwidth authorcolors curidfont bgcolor fgcolor + global diffremcolor diffaddcolor hunksepcolor + global diffmerge1color diffmerge2color + + if {$stuffsaved} return + if {![winfo viewable .]} return + catch { + set f [open "~/.hgk-new" w] + puts $f [list set mainfont $mainfont] + puts $f [list set curidfont $curidfont] + puts $f [list set textfont $textfont] + puts $f [list set findmergefiles $findmergefiles] + puts $f [list set gaudydiff $gaudydiff] + puts $f [list set maxgraphpct $maxgraphpct] + puts $f [list set maxwidth $maxwidth] + puts $f "set geometry(width) [winfo width .ctop]" + puts $f "set geometry(height) [winfo height .ctop]" + puts $f "set geometry(canv1) [expr [winfo width $canv]-2]" + puts $f "set geometry(canv2) [expr [winfo width $canv2]-2]" + puts $f "set geometry(canv3) [expr [winfo width $canv3]-2]" + puts $f "set geometry(canvh) [expr [winfo height $canv]-2]" + set wid [expr {([winfo width $ctext] - 8) \ + / [font measure $textfont "0"]}] + puts $f "set geometry(ctextw) $wid" + set wid [expr {([winfo width $cflist] - 11) \ + / [font measure [$cflist cget -font] "0"]}] + puts $f "set geometry(cflistw) $wid" + puts $f "#" + puts $f "# authorcolors format:" + puts $f "#" + puts $f "# zero or more sublists of" + puts $f "#" + puts $f "# { regex color }" + puts $f "#" + puts $f "# followed by a list of colors" + puts $f "#" + puts $f "# If the commit author matches a regex in a sublist," + puts $f "# the commit will be colored by that color" + puts $f "# otherwise the next unused entry from the list of colors" + puts $f "# will be assigned to this commit and also all other commits" + puts $f "# of the same author. When the list of colors is exhausted," + puts $f "# the last entry will be reused." + puts $f "#" + puts $f "set authorcolors {$authorcolors}" + puts $f "#" + puts $f "# The background color in the text windows" + puts $f "set bgcolor $bgcolor" + puts $f "#" + puts $f "# The text color used in the diff and file list view" + puts $f "set fgcolor $fgcolor" + puts $f "#" + puts $f "# Color to display + lines in diffs" + puts $f "set diffaddcolor $diffaddcolor" + puts $f "#" + puts $f "# Color to display - lines in diffs" + puts $f "set diffremcolor $diffremcolor" + puts $f "#" + puts $f "# Merge diffs: Color to signal lines from first parent" + puts $f "set diffmerge1color $diffmerge1color" + puts $f "#" + puts $f "# Merge diffs: Color to signal lines from second parent" + puts $f "set diffmerge2color $diffmerge2color" + puts $f "#" + puts $f "# Hunkseparator (@@ -lineno,lines +lineno,lines @@) color" + puts $f "set hunksepcolor $hunksepcolor" + close $f + file rename -force "~/.hgk-new" "~/.hgk" + } + set stuffsaved 1 +} + +proc resizeclistpanes {win w} { + global oldwidth + if [info exists oldwidth($win)] { + set s0 [$win sash coord 0] + set s1 [$win sash coord 1] + if {$w < 60} { + set sash0 [expr {int($w/2 - 2)}] + set sash1 [expr {int($w*5/6 - 2)}] + } else { + set factor [expr {1.0 * $w / $oldwidth($win)}] + set sash0 [expr {int($factor * [lindex $s0 0])}] + set sash1 [expr {int($factor * [lindex $s1 0])}] + if {$sash0 < 30} { + set sash0 30 + } + if {$sash1 < $sash0 + 20} { + set sash1 [expr $sash0 + 20] + } + if {$sash1 > $w - 10} { + set sash1 [expr $w - 10] + if {$sash0 > $sash1 - 20} { + set sash0 [expr $sash1 - 20] + } + } + } + $win sash place 0 $sash0 [lindex $s0 1] + $win sash place 1 $sash1 [lindex $s1 1] + } + set oldwidth($win) $w +} + +proc resizecdetpanes {win w} { + global oldwidth + if [info exists oldwidth($win)] { + set s0 [$win sash coord 0] + if {$w < 60} { + set sash0 [expr {int($w*3/4 - 2)}] + } else { + set factor [expr {1.0 * $w / $oldwidth($win)}] + set sash0 [expr {int($factor * [lindex $s0 0])}] + if {$sash0 < 45} { + set sash0 45 + } + if {$sash0 > $w - 15} { + set sash0 [expr $w - 15] + } + } + $win sash place 0 $sash0 [lindex $s0 1] + } + set oldwidth($win) $w +} + +proc allcanvs args { + global canv canv2 canv3 + eval $canv $args + eval $canv2 $args + eval $canv3 $args +} + +proc bindall {event action} { + global canv canv2 canv3 + bind $canv $event $action + bind $canv2 $event $action + bind $canv3 $event $action +} + +proc about {} { + set w .about + if {[winfo exists $w]} { + raise $w + return + } + toplevel $w + wm title $w "About gitk" + message $w.m -text { +Gitk version 1.2 + +Copyright © 2005 Paul Mackerras + +Use and redistribute under the terms of the GNU General Public License} \ + -justify center -aspect 400 + pack $w.m -side top -fill x -padx 20 -pady 20 + button $w.ok -text Close -command "destroy $w" + pack $w.ok -side bottom +} + +set aunextcolor 0 +proc assignauthorcolor {name} { + global authorcolors aucolormap aunextcolor + if [info exists aucolormap($name)] return + + set randomcolors {black} + for {set i 0} {$i < [llength $authorcolors]} {incr i} { + set col [lindex $authorcolors $i] + if {[llength $col] > 1} { + set re [lindex $col 0] + set c [lindex $col 1] + if {[regexp -- $re $name]} { + set aucolormap($name) $c + return + } + } else { + set randomcolors [lrange $authorcolors $i end] + break + } + } + + set ncolors [llength $randomcolors] + set c [lindex $randomcolors $aunextcolor] + if {[incr aunextcolor] >= $ncolors} { + incr aunextcolor -1 + } + set aucolormap($name) $c +} + +proc assigncolor {id} { + global commitinfo colormap commcolors colors nextcolor + global parents nparents children nchildren + global cornercrossings crossings + + if [info exists colormap($id)] return + set ncolors [llength $colors] + if {$nparents($id) <= 1 && $nchildren($id) == 1} { + set child [lindex $children($id) 0] + if {[info exists colormap($child)] + && $nparents($child) == 1} { + set colormap($id) $colormap($child) + return + } + } + set badcolors {} + if {[info exists cornercrossings($id)]} { + foreach x $cornercrossings($id) { + if {[info exists colormap($x)] + && [lsearch -exact $badcolors $colormap($x)] < 0} { + lappend badcolors $colormap($x) + } + } + if {[llength $badcolors] >= $ncolors} { + set badcolors {} + } + } + set origbad $badcolors + if {[llength $badcolors] < $ncolors - 1} { + if {[info exists crossings($id)]} { + foreach x $crossings($id) { + if {[info exists colormap($x)] + && [lsearch -exact $badcolors $colormap($x)] < 0} { + lappend badcolors $colormap($x) + } + } + if {[llength $badcolors] >= $ncolors} { + set badcolors $origbad + } + } + set origbad $badcolors + } + if {[llength $badcolors] < $ncolors - 1} { + foreach child $children($id) { + if {[info exists colormap($child)] + && [lsearch -exact $badcolors $colormap($child)] < 0} { + lappend badcolors $colormap($child) + } + if {[info exists parents($child)]} { + foreach p $parents($child) { + if {[info exists colormap($p)] + && [lsearch -exact $badcolors $colormap($p)] < 0} { + lappend badcolors $colormap($p) + } + } + } + } + if {[llength $badcolors] >= $ncolors} { + set badcolors $origbad + } + } + for {set i 0} {$i <= $ncolors} {incr i} { + set c [lindex $colors $nextcolor] + if {[incr nextcolor] >= $ncolors} { + set nextcolor 0 + } + if {[lsearch -exact $badcolors $c]} break + } + set colormap($id) $c +} + +proc initgraph {} { + global canvy canvy0 lineno numcommits nextcolor linespc + global mainline mainlinearrow sidelines + global nchildren ncleft + global displist nhyperspace + + allcanvs delete all + set nextcolor 0 + set canvy $canvy0 + set lineno -1 + set numcommits 0 + catch {unset mainline} + catch {unset mainlinearrow} + catch {unset sidelines} + foreach id [array names nchildren] { + set ncleft($id) $nchildren($id) + } + set displist {} + set nhyperspace 0 +} + +proc bindline {t id} { + global canv + + $canv bind $t "lineenter %x %y $id" + $canv bind $t "linemotion %x %y $id" + $canv bind $t "lineleave $id" + $canv bind $t "lineclick %x %y $id 1" +} + +proc drawlines {id xtra} { + global mainline mainlinearrow sidelines lthickness colormap canv + + $canv delete lines.$id + if {[info exists mainline($id)]} { + set t [$canv create line $mainline($id) \ + -width [expr {($xtra + 1) * $lthickness}] \ + -fill $colormap($id) -tags lines.$id \ + -arrow $mainlinearrow($id)] + $canv lower $t + bindline $t $id + } + if {[info exists sidelines($id)]} { + foreach ls $sidelines($id) { + set coords [lindex $ls 0] + set thick [lindex $ls 1] + set arrow [lindex $ls 2] + set t [$canv create line $coords -fill $colormap($id) \ + -width [expr {($thick + $xtra) * $lthickness}] \ + -arrow $arrow -tags lines.$id] + $canv lower $t + bindline $t $id + } + } +} + +# level here is an index in displist +proc drawcommitline {level} { + global parents children nparents displist + global canv canv2 canv3 mainfont namefont canvy linespc + global lineid linehtag linentag linedtag commitinfo + global colormap numcommits currentparents dupparents + global idtags idline idheads idotherrefs + global lineno lthickness mainline mainlinearrow sidelines + global commitlisted rowtextx idpos lastuse displist + global oldnlines olddlevel olddisplist + global aucolormap curid curidfont + + incr numcommits + incr lineno + set id [lindex $displist $level] + set lastuse($id) $lineno + set lineid($lineno) $id + set idline($id) $lineno + set ofill [expr {[info exists commitlisted($id)]? "blue": "white"}] + if {![info exists commitinfo($id)]} { + readcommit $id + if {![info exists commitinfo($id)]} { + set commitinfo($id) {"No commit information available"} + set nparents($id) 0 + } + } + assigncolor $id + set currentparents {} + set dupparents {} + if {[info exists commitlisted($id)] && [info exists parents($id)]} { + foreach p $parents($id) { + if {[lsearch -exact $currentparents $p] < 0} { + lappend currentparents $p + } else { + # remember that this parent was listed twice + lappend dupparents $p + } + } + } + set x [xcoord $level $level $lineno] + set y1 $canvy + set canvy [expr $canvy + $linespc] + allcanvs conf -scrollregion \ + [list 0 0 0 [expr $y1 + 0.5 * $linespc + 2]] + if {[info exists mainline($id)]} { + lappend mainline($id) $x $y1 + if {$mainlinearrow($id) ne "none"} { + set mainline($id) [trimdiagstart $mainline($id)] + } + } + drawlines $id 0 + set orad [expr {$linespc / 3}] + set t [$canv create oval [expr $x - $orad] [expr $y1 - $orad] \ + [expr $x + $orad - 1] [expr $y1 + $orad - 1] \ + -fill $ofill -outline black -width 1] + $canv raise $t + $canv bind $t <1> {selcanvline {} %x %y} + set xt [xcoord [llength $displist] $level $lineno] + if {[llength $currentparents] > 2} { + set xt [expr {$xt + ([llength $currentparents] - 2) * $linespc}] + } + set rowtextx($lineno) $xt + set idpos($id) [list $x $xt $y1] + if {[info exists idtags($id)] || [info exists idheads($id)] + || [info exists idotherrefs($id)]} { + set xt [drawtags $id $x $xt $y1] + } + set headline [lindex $commitinfo($id) 0] + set name [lindex $commitinfo($id) 1] + assignauthorcolor $name + set fg $aucolormap($name) + if {$id == $curid} { + set fn $curidfont + } else { + set fn $mainfont + } + + set date [lindex $commitinfo($id) 2] + set linehtag($lineno) [$canv create text $xt $y1 -anchor w \ + -text $headline -font $fn \ + -fill $fg] + $canv bind $linehtag($lineno) <> "rowmenu %X %Y $id" + set linentag($lineno) [$canv2 create text 3 $y1 -anchor w \ + -text $name -font $namefont \ + -fill $fg] + set linedtag($lineno) [$canv3 create text 3 $y1 -anchor w \ + -text $date -font $mainfont \ + -fill $fg] + + set olddlevel $level + set olddisplist $displist + set oldnlines [llength $displist] +} + +proc drawtags {id x xt y1} { + global idtags idheads idotherrefs commitinfo + global linespc lthickness + global canv mainfont idline rowtextx + + set marks {} + set ntags 0 + set nheads 0 + if {[info exists idtags($id)]} { + set marks $idtags($id) + set ntags [llength $marks] + } + if {[info exists idheads($id)]} { + set headmark [lindex $commitinfo($id) 7] + if {$headmark ne "default"} { + lappend marks $headmark + set nheads 1 + } + } + if {[info exists idotherrefs($id)]} { + set marks [concat $marks $idotherrefs($id)] + } + if {$marks eq {}} { + return $xt + } + + set delta [expr {int(0.5 * ($linespc - $lthickness))}] + set yt [expr $y1 - 0.5 * $linespc] + set yb [expr $yt + $linespc - 1] + set xvals {} + set wvals {} + foreach tag $marks { + set wid [font measure $mainfont $tag] + lappend xvals $xt + lappend wvals $wid + set xt [expr {$xt + $delta + $wid + $lthickness + $linespc}] + } + set t [$canv create line $x $y1 [lindex $xvals end] $y1 \ + -width $lthickness -fill black -tags tag.$id] + $canv lower $t + foreach tag $marks x $xvals wid $wvals { + set xl [expr $x + $delta] + set xr [expr $x + $delta + $wid + $lthickness] + if {[incr ntags -1] >= 0} { + # draw a tag + set t [$canv create polygon $x [expr $yt + $delta] $xl $yt \ + $xr $yt $xr $yb $xl $yb $x [expr $yb - $delta] \ + -width 1 -outline black -fill yellow -tags tag.$id] + $canv bind $t <1> [list showtag $tag 1] + set rowtextx($idline($id)) [expr {$xr + $linespc}] + } else { + # draw a head or other ref + if {[incr nheads -1] >= 0} { + set col green + } else { + set col "#ddddff" + } + set xl [expr $xl - $delta/2] + $canv create polygon $x $yt $xr $yt $xr $yb $x $yb \ + -width 1 -outline black -fill $col -tags tag.$id + } + set t [$canv create text $xl $y1 -anchor w -text $tag \ + -font $mainfont -tags tag.$id] + if {$ntags >= 0} { + $canv bind $t <1> [list showtag $tag 1] + } + } + return $xt +} + +proc notecrossings {id lo hi corner} { + global olddisplist crossings cornercrossings + + for {set i $lo} {[incr i] < $hi} {} { + set p [lindex $olddisplist $i] + if {$p == {}} continue + if {$i == $corner} { + if {![info exists cornercrossings($id)] + || [lsearch -exact $cornercrossings($id) $p] < 0} { + lappend cornercrossings($id) $p + } + if {![info exists cornercrossings($p)] + || [lsearch -exact $cornercrossings($p) $id] < 0} { + lappend cornercrossings($p) $id + } + } else { + if {![info exists crossings($id)] + || [lsearch -exact $crossings($id) $p] < 0} { + lappend crossings($id) $p + } + if {![info exists crossings($p)] + || [lsearch -exact $crossings($p) $id] < 0} { + lappend crossings($p) $id + } + } + } +} + +proc xcoord {i level ln} { + global canvx0 xspc1 xspc2 + + set x [expr {$canvx0 + $i * $xspc1($ln)}] + if {$i > 0 && $i == $level} { + set x [expr {$x + 0.5 * ($xspc2 - $xspc1($ln))}] + } elseif {$i > $level} { + set x [expr {$x + $xspc2 - $xspc1($ln)}] + } + return $x +} + +# it seems Tk can't draw arrows on the end of diagonal line segments... +proc trimdiagend {line} { + while {[llength $line] > 4} { + set x1 [lindex $line end-3] + set y1 [lindex $line end-2] + set x2 [lindex $line end-1] + set y2 [lindex $line end] + if {($x1 == $x2) != ($y1 == $y2)} break + set line [lreplace $line end-1 end] + } + return $line +} + +proc trimdiagstart {line} { + while {[llength $line] > 4} { + set x1 [lindex $line 0] + set y1 [lindex $line 1] + set x2 [lindex $line 2] + set y2 [lindex $line 3] + if {($x1 == $x2) != ($y1 == $y2)} break + set line [lreplace $line 0 1] + } + return $line +} + +proc drawslants {id needonscreen nohs} { + global canv mainline mainlinearrow sidelines + global canvx0 canvy xspc1 xspc2 lthickness + global currentparents dupparents + global lthickness linespc canvy colormap lineno geometry + global maxgraphpct maxwidth + global displist onscreen lastuse + global parents commitlisted + global oldnlines olddlevel olddisplist + global nhyperspace numcommits nnewparents + + if {$lineno < 0} { + lappend displist $id + set onscreen($id) 1 + return 0 + } + + set y1 [expr {$canvy - $linespc}] + set y2 $canvy + + # work out what we need to get back on screen + set reins {} + if {$onscreen($id) < 0} { + # next to do isn't displayed, better get it on screen... + lappend reins [list $id 0] + } + # make sure all the previous commits's parents are on the screen + foreach p $currentparents { + if {$onscreen($p) < 0} { + lappend reins [list $p 0] + } + } + # bring back anything requested by caller + if {$needonscreen ne {}} { + lappend reins $needonscreen + } + + # try the shortcut + if {$currentparents == $id && $onscreen($id) == 0 && $reins eq {}} { + set dlevel $olddlevel + set x [xcoord $dlevel $dlevel $lineno] + set mainline($id) [list $x $y1] + set mainlinearrow($id) none + set lastuse($id) $lineno + set displist [lreplace $displist $dlevel $dlevel $id] + set onscreen($id) 1 + set xspc1([expr {$lineno + 1}]) $xspc1($lineno) + return $dlevel + } + + # update displist + set displist [lreplace $displist $olddlevel $olddlevel] + set j $olddlevel + foreach p $currentparents { + set lastuse($p) $lineno + if {$onscreen($p) == 0} { + set displist [linsert $displist $j $p] + set onscreen($p) 1 + incr j + } + } + if {$onscreen($id) == 0} { + lappend displist $id + set onscreen($id) 1 + } + + # remove the null entry if present + set nullentry [lsearch -exact $displist {}] + if {$nullentry >= 0} { + set displist [lreplace $displist $nullentry $nullentry] + } + + # bring back the ones we need now (if we did it earlier + # it would change displist and invalidate olddlevel) + foreach pi $reins { + # test again in case of duplicates in reins + set p [lindex $pi 0] + if {$onscreen($p) < 0} { + set onscreen($p) 1 + set lastuse($p) $lineno + set displist [linsert $displist [lindex $pi 1] $p] + incr nhyperspace -1 + } + } + + set lastuse($id) $lineno + + # see if we need to make any lines jump off into hyperspace + set displ [llength $displist] + if {$displ > $maxwidth} { + set ages {} + foreach x $displist { + lappend ages [list $lastuse($x) $x] + } + set ages [lsort -integer -index 0 $ages] + set k 0 + while {$displ > $maxwidth} { + set use [lindex $ages $k 0] + set victim [lindex $ages $k 1] + if {$use >= $lineno - 5} break + incr k + if {[lsearch -exact $nohs $victim] >= 0} continue + set i [lsearch -exact $displist $victim] + set displist [lreplace $displist $i $i] + set onscreen($victim) -1 + incr nhyperspace + incr displ -1 + if {$i < $nullentry} { + incr nullentry -1 + } + set x [lindex $mainline($victim) end-1] + lappend mainline($victim) $x $y1 + set line [trimdiagend $mainline($victim)] + set arrow "last" + if {$mainlinearrow($victim) ne "none"} { + set line [trimdiagstart $line] + set arrow "both" + } + lappend sidelines($victim) [list $line 1 $arrow] + unset mainline($victim) + } + } + + set dlevel [lsearch -exact $displist $id] + + # If we are reducing, put in a null entry + if {$displ < $oldnlines} { + # does the next line look like a merge? + # i.e. does it have > 1 new parent? + if {$nnewparents($id) > 1} { + set i [expr {$dlevel + 1}] + } elseif {$nnewparents([lindex $olddisplist $olddlevel]) == 0} { + set i $olddlevel + if {$nullentry >= 0 && $nullentry < $i} { + incr i -1 + } + } elseif {$nullentry >= 0} { + set i $nullentry + while {$i < $displ + && [lindex $olddisplist $i] == [lindex $displist $i]} { + incr i + } + } else { + set i $olddlevel + if {$dlevel >= $i} { + incr i + } + } + if {$i < $displ} { + set displist [linsert $displist $i {}] + incr displ + if {$dlevel >= $i} { + incr dlevel + } + } + } + + # decide on the line spacing for the next line + set lj [expr {$lineno + 1}] + set maxw [expr {$maxgraphpct * $geometry(canv1) / 100}] + if {$displ <= 1 || $canvx0 + $displ * $xspc2 <= $maxw} { + set xspc1($lj) $xspc2 + } else { + set xspc1($lj) [expr {($maxw - $canvx0 - $xspc2) / ($displ - 1)}] + if {$xspc1($lj) < $lthickness} { + set xspc1($lj) $lthickness + } + } + + foreach idi $reins { + set id [lindex $idi 0] + set j [lsearch -exact $displist $id] + set xj [xcoord $j $dlevel $lj] + set mainline($id) [list $xj $y2] + set mainlinearrow($id) first + } + + set i -1 + foreach id $olddisplist { + incr i + if {$id == {}} continue + if {$onscreen($id) <= 0} continue + set xi [xcoord $i $olddlevel $lineno] + if {$i == $olddlevel} { + foreach p $currentparents { + set j [lsearch -exact $displist $p] + set coords [list $xi $y1] + set xj [xcoord $j $dlevel $lj] + if {$xj < $xi - $linespc} { + lappend coords [expr {$xj + $linespc}] $y1 + notecrossings $p $j $i [expr {$j + 1}] + } elseif {$xj > $xi + $linespc} { + lappend coords [expr {$xj - $linespc}] $y1 + notecrossings $p $i $j [expr {$j - 1}] + } + if {[lsearch -exact $dupparents $p] >= 0} { + # draw a double-width line to indicate the doubled parent + lappend coords $xj $y2 + lappend sidelines($p) [list $coords 2 none] + if {![info exists mainline($p)]} { + set mainline($p) [list $xj $y2] + set mainlinearrow($p) none + } + } else { + # normal case, no parent duplicated + set yb $y2 + set dx [expr {abs($xi - $xj)}] + if {0 && $dx < $linespc} { + set yb [expr {$y1 + $dx}] + } + if {![info exists mainline($p)]} { + if {$xi != $xj} { + lappend coords $xj $yb + } + set mainline($p) $coords + set mainlinearrow($p) none + } else { + lappend coords $xj $yb + if {$yb < $y2} { + lappend coords $xj $y2 + } + lappend sidelines($p) [list $coords 1 none] + } + } + } + } else { + set j $i + if {[lindex $displist $i] != $id} { + set j [lsearch -exact $displist $id] + } + if {$j != $i || $xspc1($lineno) != $xspc1($lj) + || ($olddlevel < $i && $i < $dlevel) + || ($dlevel < $i && $i < $olddlevel)} { + set xj [xcoord $j $dlevel $lj] + lappend mainline($id) $xi $y1 $xj $y2 + } + } + } + return $dlevel +} + +# search for x in a list of lists +proc llsearch {llist x} { + set i 0 + foreach l $llist { + if {$l == $x || [lsearch -exact $l $x] >= 0} { + return $i + } + incr i + } + return -1 +} + +proc drawmore {reading} { + global displayorder numcommits ncmupdate nextupdate + global stopped nhyperspace parents commitlisted + global maxwidth onscreen displist currentparents olddlevel + + set n [llength $displayorder] + while {$numcommits < $n} { + set id [lindex $displayorder $numcommits] + set ctxend [expr {$numcommits + 10}] + if {!$reading && $ctxend > $n} { + set ctxend $n + } + set dlist {} + if {$numcommits > 0} { + set dlist [lreplace $displist $olddlevel $olddlevel] + set i $olddlevel + foreach p $currentparents { + if {$onscreen($p) == 0} { + set dlist [linsert $dlist $i $p] + incr i + } + } + } + set nohs {} + set reins {} + set isfat [expr {[llength $dlist] > $maxwidth}] + if {$nhyperspace > 0 || $isfat} { + if {$ctxend > $n} break + # work out what to bring back and + # what we want to don't want to send into hyperspace + set room 1 + for {set k $numcommits} {$k < $ctxend} {incr k} { + set x [lindex $displayorder $k] + set i [llsearch $dlist $x] + if {$i < 0} { + set i [llength $dlist] + lappend dlist $x + } + if {[lsearch -exact $nohs $x] < 0} { + lappend nohs $x + } + if {$reins eq {} && $onscreen($x) < 0 && $room} { + set reins [list $x $i] + } + set newp {} + if {[info exists commitlisted($x)]} { + set right 0 + foreach p $parents($x) { + if {[llsearch $dlist $p] < 0} { + lappend newp $p + if {[lsearch -exact $nohs $p] < 0} { + lappend nohs $p + } + if {$reins eq {} && $onscreen($p) < 0 && $room} { + set reins [list $p [expr {$i + $right}]] + } + } + set right 1 + } + } + set l [lindex $dlist $i] + if {[llength $l] == 1} { + set l $newp + } else { + set j [lsearch -exact $l $x] + set l [concat [lreplace $l $j $j] $newp] + } + set dlist [lreplace $dlist $i $i $l] + if {$room && $isfat && [llength $newp] <= 1} { + set room 0 + } + } + } + + set dlevel [drawslants $id $reins $nohs] + drawcommitline $dlevel + if {[clock clicks -milliseconds] >= $nextupdate + && $numcommits >= $ncmupdate} { + doupdate $reading + if {$stopped} break + } + } +} + +# level here is an index in todo +proc updatetodo {level noshortcut} { + global ncleft todo nnewparents + global commitlisted parents onscreen + + set id [lindex $todo $level] + set olds {} + if {[info exists commitlisted($id)]} { + foreach p $parents($id) { + if {[lsearch -exact $olds $p] < 0} { + lappend olds $p + } + } + } + if {!$noshortcut && [llength $olds] == 1} { + set p [lindex $olds 0] + if {$ncleft($p) == 1 && [lsearch -exact $todo $p] < 0} { + set ncleft($p) 0 + set todo [lreplace $todo $level $level $p] + set onscreen($p) 0 + set nnewparents($id) 1 + return 0 + } + } + + set todo [lreplace $todo $level $level] + set i $level + set n 0 + foreach p $olds { + incr ncleft($p) -1 + set k [lsearch -exact $todo $p] + if {$k < 0} { + set todo [linsert $todo $i $p] + set onscreen($p) 0 + incr i + incr n + } + } + set nnewparents($id) $n + + return 1 +} + +proc decidenext {{noread 0}} { + global ncleft todo + global datemode cdate + global commitinfo + + # choose which one to do next time around + set todol [llength $todo] + set level -1 + set latest {} + for {set k $todol} {[incr k -1] >= 0} {} { + set p [lindex $todo $k] + if {$ncleft($p) == 0} { + if {$datemode} { + if {![info exists commitinfo($p)]} { + if {$noread} { + return {} + } + readcommit $p + } + if {$latest == {} || $cdate($p) > $latest} { + set level $k + set latest $cdate($p) + } + } else { + set level $k + break + } + } + } + if {$level < 0} { + if {$todo != {}} { + puts "ERROR: none of the pending commits can be done yet:" + foreach p $todo { + puts " $p ($ncleft($p))" + } + } + return -1 + } + + return $level +} + +proc drawcommit {id} { + global phase todo nchildren datemode nextupdate + global numcommits ncmupdate displayorder todo onscreen + + if {$phase != "incrdraw"} { + set phase incrdraw + set displayorder {} + set todo {} + initgraph + } + if {$nchildren($id) == 0} { + lappend todo $id + set onscreen($id) 0 + } + set level [decidenext 1] + if {$level == {} || $id != [lindex $todo $level]} { + return + } + while 1 { + lappend displayorder [lindex $todo $level] + if {[updatetodo $level $datemode]} { + set level [decidenext 1] + if {$level == {}} break + } + set id [lindex $todo $level] + if {![info exists commitlisted($id)]} { + break + } + } + drawmore 1 +} + +proc finishcommits {} { + global phase + global canv mainfont ctext maincursor textcursor + + if {$phase != "incrdraw"} { + $canv delete all + $canv create text 3 3 -anchor nw -text "No commits selected" \ + -font $mainfont -tags textitems + set phase {} + } else { + drawrest + } + . config -cursor $maincursor + settextcursor $textcursor +} + +# Don't change the text pane cursor if it is currently the hand cursor, +# showing that we are over a sha1 ID link. +proc settextcursor {c} { + global ctext curtextcursor + + if {[$ctext cget -cursor] == $curtextcursor} { + $ctext config -cursor $c + } + set curtextcursor $c +} + +proc drawgraph {} { + global nextupdate startmsecs ncmupdate + global displayorder onscreen + + if {$displayorder == {}} return + set startmsecs [clock clicks -milliseconds] + set nextupdate [expr $startmsecs + 100] + set ncmupdate 1 + initgraph + foreach id $displayorder { + set onscreen($id) 0 + } + drawmore 0 +} + +proc drawrest {} { + global phase stopped redisplaying selectedline + global datemode todo displayorder + global numcommits ncmupdate + global nextupdate startmsecs + + set level [decidenext] + if {$level >= 0} { + set phase drawgraph + while 1 { + lappend displayorder [lindex $todo $level] + set hard [updatetodo $level $datemode] + if {$hard} { + set level [decidenext] + if {$level < 0} break + } + } + drawmore 0 + } + set phase {} + set drawmsecs [expr [clock clicks -milliseconds] - $startmsecs] + #puts "overall $drawmsecs ms for $numcommits commits" + if {$redisplaying} { + if {$stopped == 0 && [info exists selectedline]} { + selectline $selectedline 0 + } + if {$stopped == 1} { + set stopped 0 + after idle drawgraph + } else { + set redisplaying 0 + } + } +} + +proc findmatches {f} { + global findtype foundstring foundstrlen + if {$findtype == "Regexp"} { + set matches [regexp -indices -all -inline $foundstring $f] + } else { + if {$findtype == "IgnCase"} { + set str [string tolower $f] + } else { + set str $f + } + set matches {} + set i 0 + while {[set j [string first $foundstring $str $i]] >= 0} { + lappend matches [list $j [expr $j+$foundstrlen-1]] + set i [expr $j + $foundstrlen] + } + } + return $matches +} + +proc dofind {} { + global findtype findloc findstring markedmatches commitinfo + global numcommits lineid linehtag linentag linedtag + global mainfont namefont canv canv2 canv3 selectedline + global matchinglines foundstring foundstrlen + + stopfindproc + unmarkmatches + focus . + set matchinglines {} + if {$findloc == "Pickaxe"} { + findpatches + return + } + if {$findtype == "IgnCase"} { + set foundstring [string tolower $findstring] + } else { + set foundstring $findstring + } + set foundstrlen [string length $findstring] + if {$foundstrlen == 0} return + if {$findloc == "Files"} { + findfiles + return + } + if {![info exists selectedline]} { + set oldsel -1 + } else { + set oldsel $selectedline + } + set didsel 0 + set fldtypes {Headline Author Date Committer CDate Comment} + for {set l 0} {$l < $numcommits} {incr l} { + set id $lineid($l) + set info $commitinfo($id) + set doesmatch 0 + foreach f $info ty $fldtypes { + if {$findloc != "All fields" && $findloc != $ty} { + continue + } + set matches [findmatches $f] + if {$matches == {}} continue + set doesmatch 1 + if {$ty == "Headline"} { + markmatches $canv $l $f $linehtag($l) $matches $mainfont + } elseif {$ty == "Author"} { + markmatches $canv2 $l $f $linentag($l) $matches $namefont + } elseif {$ty == "Date"} { + markmatches $canv3 $l $f $linedtag($l) $matches $mainfont + } + } + if {$doesmatch} { + lappend matchinglines $l + if {!$didsel && $l > $oldsel} { + findselectline $l + set didsel 1 + } + } + } + if {$matchinglines == {}} { + bell + } elseif {!$didsel} { + findselectline [lindex $matchinglines 0] + } +} + +proc findselectline {l} { + global findloc commentend ctext + selectline $l 1 + if {$findloc == "All fields" || $findloc == "Comments"} { + # highlight the matches in the comments + set f [$ctext get 1.0 $commentend] + set matches [findmatches $f] + foreach match $matches { + set start [lindex $match 0] + set end [expr [lindex $match 1] + 1] + $ctext tag add found "1.0 + $start c" "1.0 + $end c" + } + } +} + +proc findnext {restart} { + global matchinglines selectedline + if {![info exists matchinglines]} { + if {$restart} { + dofind + } + return + } + if {![info exists selectedline]} return + foreach l $matchinglines { + if {$l > $selectedline} { + findselectline $l + return + } + } + bell +} + +proc findprev {} { + global matchinglines selectedline + if {![info exists matchinglines]} { + dofind + return + } + if {![info exists selectedline]} return + set prev {} + foreach l $matchinglines { + if {$l >= $selectedline} break + set prev $l + } + if {$prev != {}} { + findselectline $prev + } else { + bell + } +} + +proc findlocchange {name ix op} { + global findloc findtype findtypemenu + if {$findloc == "Pickaxe"} { + set findtype Exact + set state disabled + } else { + set state normal + } + $findtypemenu entryconf 1 -state $state + $findtypemenu entryconf 2 -state $state +} + +proc stopfindproc {{done 0}} { + global findprocpid findprocfile findids + global ctext findoldcursor phase maincursor textcursor + global findinprogress + + catch {unset findids} + if {[info exists findprocpid]} { + if {!$done} { + catch {exec kill $findprocpid} + } + catch {close $findprocfile} + unset findprocpid + } + if {[info exists findinprogress]} { + unset findinprogress + if {$phase != "incrdraw"} { + . config -cursor $maincursor + settextcursor $textcursor + } + } +} + +proc findpatches {} { + global findstring selectedline numcommits + global findprocpid findprocfile + global finddidsel ctext lineid findinprogress + global findinsertpos + global env + + if {$numcommits == 0} return + + # make a list of all the ids to search, starting at the one + # after the selected line (if any) + if {[info exists selectedline]} { + set l $selectedline + } else { + set l -1 + } + set inputids {} + for {set i 0} {$i < $numcommits} {incr i} { + if {[incr l] >= $numcommits} { + set l 0 + } + append inputids $lineid($l) "\n" + } + + if {[catch { + set f [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree --stdin -s -r -S$findstring << $inputids] r] + } err]} { + error_popup "Error starting search process: $err" + return + } + + set findinsertpos end + set findprocfile $f + set findprocpid [pid $f] + fconfigure $f -blocking 0 + fileevent $f readable readfindproc + set finddidsel 0 + . config -cursor watch + settextcursor watch + set findinprogress 1 +} + +proc readfindproc {} { + global findprocfile finddidsel + global idline matchinglines findinsertpos + + set n [gets $findprocfile line] + if {$n < 0} { + if {[eof $findprocfile]} { + stopfindproc 1 + if {!$finddidsel} { + bell + } + } + return + } + if {![regexp {^[0-9a-f]{12}} $line id]} { + error_popup "Can't parse git-diff-tree output: $line" + stopfindproc + return + } + if {![info exists idline($id)]} { + puts stderr "spurious id: $id" + return + } + set l $idline($id) + insertmatch $l $id +} + +proc insertmatch {l id} { + global matchinglines findinsertpos finddidsel + + if {$findinsertpos == "end"} { + if {$matchinglines != {} && $l < [lindex $matchinglines 0]} { + set matchinglines [linsert $matchinglines 0 $l] + set findinsertpos 1 + } else { + lappend matchinglines $l + } + } else { + set matchinglines [linsert $matchinglines $findinsertpos $l] + incr findinsertpos + } + markheadline $l $id + if {!$finddidsel} { + findselectline $l + set finddidsel 1 + } +} + +proc findfiles {} { + global selectedline numcommits lineid ctext + global ffileline finddidsel parents nparents + global findinprogress findstartline findinsertpos + global treediffs fdiffids fdiffsneeded fdiffpos + global findmergefiles + global env + + if {$numcommits == 0} return + + if {[info exists selectedline]} { + set l [expr {$selectedline + 1}] + } else { + set l 0 + } + set ffileline $l + set findstartline $l + set diffsneeded {} + set fdiffsneeded {} + while 1 { + set id $lineid($l) + if {$findmergefiles || $nparents($id) == 1} { + foreach p $parents($id) { + if {![info exists treediffs([list $id $p])]} { + append diffsneeded "$id $p\n" + lappend fdiffsneeded [list $id $p] + } + } + } + if {[incr l] >= $numcommits} { + set l 0 + } + if {$l == $findstartline} break + } + + # start off a git-diff-tree process if needed + if {$diffsneeded ne {}} { + if {[catch { + set df [open [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r --stdin << $diffsneeded] r] + } err ]} { + error_popup "Error starting search process: $err" + return + } + catch {unset fdiffids} + set fdiffpos 0 + fconfigure $df -blocking 0 + fileevent $df readable [list readfilediffs $df] + } + + set finddidsel 0 + set findinsertpos end + set id $lineid($l) + set p [lindex $parents($id) 0] + . config -cursor watch + settextcursor watch + set findinprogress 1 + findcont [list $id $p] + update +} + +proc readfilediffs {df} { + global findids fdiffids fdiffs + + set n [gets $df line] + if {$n < 0} { + if {[eof $df]} { + donefilediff + if {[catch {close $df} err]} { + stopfindproc + bell + error_popup "Error in hg debug-diff-tree: $err" + } elseif {[info exists findids]} { + set ids $findids + stopfindproc + bell + error_popup "Couldn't find diffs for {$ids}" + } + } + return + } + if {[regexp {^([0-9a-f]{12}) \(from ([0-9a-f]{12})\)} $line match id p]} { + # start of a new string of diffs + donefilediff + set fdiffids [list $id $p] + set fdiffs {} + } elseif {[string match ":*" $line]} { + lappend fdiffs [lindex $line 5] + } +} + +proc donefilediff {} { + global fdiffids fdiffs treediffs findids + global fdiffsneeded fdiffpos + + if {[info exists fdiffids]} { + while {[lindex $fdiffsneeded $fdiffpos] ne $fdiffids + && $fdiffpos < [llength $fdiffsneeded]} { + # git-diff-tree doesn't output anything for a commit + # which doesn't change anything + set nullids [lindex $fdiffsneeded $fdiffpos] + set treediffs($nullids) {} + if {[info exists findids] && $nullids eq $findids} { + unset findids + findcont $nullids + } + incr fdiffpos + } + incr fdiffpos + + if {![info exists treediffs($fdiffids)]} { + set treediffs($fdiffids) $fdiffs + } + if {[info exists findids] && $fdiffids eq $findids} { + unset findids + findcont $fdiffids + } + } +} + +proc findcont {ids} { + global findids treediffs parents nparents + global ffileline findstartline finddidsel + global lineid numcommits matchinglines findinprogress + global findmergefiles + + set id [lindex $ids 0] + set p [lindex $ids 1] + set pi [lsearch -exact $parents($id) $p] + set l $ffileline + while 1 { + if {$findmergefiles || $nparents($id) == 1} { + if {![info exists treediffs($ids)]} { + set findids $ids + set ffileline $l + return + } + set doesmatch 0 + foreach f $treediffs($ids) { + set x [findmatches $f] + if {$x != {}} { + set doesmatch 1 + break + } + } + if {$doesmatch} { + insertmatch $l $id + set pi $nparents($id) + } + } else { + set pi $nparents($id) + } + if {[incr pi] >= $nparents($id)} { + set pi 0 + if {[incr l] >= $numcommits} { + set l 0 + } + if {$l == $findstartline} break + set id $lineid($l) + } + set p [lindex $parents($id) $pi] + set ids [list $id $p] + } + stopfindproc + if {!$finddidsel} { + bell + } +} + +# mark a commit as matching by putting a yellow background +# behind the headline +proc markheadline {l id} { + global canv mainfont linehtag commitinfo + + set bbox [$canv bbox $linehtag($l)] + set t [$canv create rect $bbox -outline {} -tags matches -fill yellow] + $canv lower $t +} + +# mark the bits of a headline, author or date that match a find string +proc markmatches {canv l str tag matches font} { + set bbox [$canv bbox $tag] + set x0 [lindex $bbox 0] + set y0 [lindex $bbox 1] + set y1 [lindex $bbox 3] + foreach match $matches { + set start [lindex $match 0] + set end [lindex $match 1] + if {$start > $end} continue + set xoff [font measure $font [string range $str 0 [expr $start-1]]] + set xlen [font measure $font [string range $str 0 [expr $end]]] + set t [$canv create rect [expr $x0+$xoff] $y0 [expr $x0+$xlen+2] $y1 \ + -outline {} -tags matches -fill yellow] + $canv lower $t + } +} + +proc unmarkmatches {} { + global matchinglines findids + allcanvs delete matches + catch {unset matchinglines} + catch {unset findids} +} + +proc selcanvline {w x y} { + global canv canvy0 ctext linespc + global lineid linehtag linentag linedtag rowtextx + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax == {}} return + set yfrac [lindex [$canv yview] 0] + set y [expr {$y + $yfrac * $ymax}] + set l [expr {int(($y - $canvy0) / $linespc + 0.5)}] + if {$l < 0} { + set l 0 + } + if {$w eq $canv} { + if {![info exists rowtextx($l)] || $x < $rowtextx($l)} return + } + unmarkmatches + selectline $l 1 +} + +proc commit_descriptor {p} { + global commitinfo + set l "..." + if {[info exists commitinfo($p)]} { + set l [lindex $commitinfo($p) 0] + set r [lindex $commitinfo($p) 6] + } + return "$r:$p ($l)" +} + +# append some text to the ctext widget, and make any SHA1 ID +# that we know about be a clickable link. +proc appendwithlinks {text} { + global ctext idline linknum + + set start [$ctext index "end - 1c"] + $ctext insert end $text + $ctext insert end "\n" + set links [regexp -indices -all -inline {[0-9a-f]{12}} $text] + foreach l $links { + set s [lindex $l 0] + set e [lindex $l 1] + set linkid [string range $text $s $e] + if {![info exists idline($linkid)]} continue + incr e + $ctext tag add link "$start + $s c" "$start + $e c" + $ctext tag add link$linknum "$start + $s c" "$start + $e c" + $ctext tag bind link$linknum <1> [list selectline $idline($linkid) 1] + incr linknum + } + $ctext tag conf link -foreground blue -underline 1 + $ctext tag bind link { %W configure -cursor hand2 } + $ctext tag bind link { %W configure -cursor $curtextcursor } +} + +proc selectline {l isnew} { + global canv canv2 canv3 ctext commitinfo selectedline + global lineid linehtag linentag linedtag + global canvy0 linespc parents nparents children + global cflist currentid sha1entry + global commentend idtags idline linknum + + $canv delete hover + normalline + if {![info exists lineid($l)] || ![info exists linehtag($l)]} return + $canv delete secsel + set t [eval $canv create rect [$canv bbox $linehtag($l)] -outline {{}} \ + -tags secsel -fill [$canv cget -selectbackground]] + $canv lower $t + $canv2 delete secsel + set t [eval $canv2 create rect [$canv2 bbox $linentag($l)] -outline {{}} \ + -tags secsel -fill [$canv2 cget -selectbackground]] + $canv2 lower $t + $canv3 delete secsel + set t [eval $canv3 create rect [$canv3 bbox $linedtag($l)] -outline {{}} \ + -tags secsel -fill [$canv3 cget -selectbackground]] + $canv3 lower $t + set y [expr {$canvy0 + $l * $linespc}] + set ymax [lindex [$canv cget -scrollregion] 3] + set ytop [expr {$y - $linespc - 1}] + set ybot [expr {$y + $linespc + 1}] + set wnow [$canv yview] + set wtop [expr [lindex $wnow 0] * $ymax] + set wbot [expr [lindex $wnow 1] * $ymax] + set wh [expr {$wbot - $wtop}] + set newtop $wtop + if {$ytop < $wtop} { + if {$ybot < $wtop} { + set newtop [expr {$y - $wh / 2.0}] + } else { + set newtop $ytop + if {$newtop > $wtop - $linespc} { + set newtop [expr {$wtop - $linespc}] + } + } + } elseif {$ybot > $wbot} { + if {$ytop > $wbot} { + set newtop [expr {$y - $wh / 2.0}] + } else { + set newtop [expr {$ybot - $wh}] + if {$newtop < $wtop + $linespc} { + set newtop [expr {$wtop + $linespc}] + } + } + } + if {$newtop != $wtop} { + if {$newtop < 0} { + set newtop 0 + } + allcanvs yview moveto [expr $newtop * 1.0 / $ymax] + } + + if {$isnew} { + addtohistory [list selectline $l 0] + } + + set selectedline $l + + set id $lineid($l) + set currentid $id + $sha1entry delete 0 end + $sha1entry insert 0 $id + $sha1entry selection from 0 + $sha1entry selection to end + + $ctext conf -state normal + $ctext delete 0.0 end + set linknum 0 + $ctext mark set fmark.0 0.0 + $ctext mark gravity fmark.0 left + set info $commitinfo($id) + $ctext insert end "Revision: [lindex $info 6]\n" + if {[llength [lindex $info 7]] > 0} { + $ctext insert end "Branch: [lindex $info 7]\n" + } + $ctext insert end "Author: [lindex $info 1] [lindex $info 2]\n" + $ctext insert end "Committer: [lindex $info 3] [lindex $info 4]\n" + if {[info exists idtags($id)]} { + $ctext insert end "Tags:" + foreach tag $idtags($id) { + $ctext insert end " $tag" + } + $ctext insert end "\n" + } + + set comment {} + if {[info exists parents($id)]} { + foreach p $parents($id) { + append comment "Parent: [commit_descriptor $p]\n" + } + } + if {[info exists children($id)]} { + foreach c $children($id) { + append comment "Child: [commit_descriptor $c]\n" + } + } + append comment "\n" + append comment [lindex $info 5] + + # make anything that looks like a SHA1 ID be a clickable link + appendwithlinks $comment + + $ctext tag delete Comments + $ctext tag remove found 1.0 end + $ctext conf -state disabled + set commentend [$ctext index "end - 1c"] + + $cflist delete 0 end + $cflist insert end "Comments" + if {$nparents($id) <= 1} { + set parent "null" + if {$nparents($id) == 1} { + set parent $parents($id) + } + startdiff [concat $id $parent] + } elseif {$nparents($id) > 1} { + mergediff $id + } +} + +proc selnextline {dir} { + global selectedline + if {![info exists selectedline]} return + set l [expr $selectedline + $dir] + unmarkmatches + selectline $l 1 +} + +proc unselectline {} { + global selectedline + + catch {unset selectedline} + allcanvs delete secsel +} + +proc addtohistory {cmd} { + global history historyindex + + if {$historyindex > 0 + && [lindex $history [expr {$historyindex - 1}]] == $cmd} { + return + } + + if {$historyindex < [llength $history]} { + set history [lreplace $history $historyindex end $cmd] + } else { + lappend history $cmd + } + incr historyindex + if {$historyindex > 1} { + .ctop.top.bar.leftbut conf -state normal + } else { + .ctop.top.bar.leftbut conf -state disabled + } + .ctop.top.bar.rightbut conf -state disabled +} + +proc goback {} { + global history historyindex + + if {$historyindex > 1} { + incr historyindex -1 + set cmd [lindex $history [expr {$historyindex - 1}]] + eval $cmd + .ctop.top.bar.rightbut conf -state normal + } + if {$historyindex <= 1} { + .ctop.top.bar.leftbut conf -state disabled + } +} + +proc goforw {} { + global history historyindex + + if {$historyindex < [llength $history]} { + set cmd [lindex $history $historyindex] + incr historyindex + eval $cmd + .ctop.top.bar.leftbut conf -state normal + } + if {$historyindex >= [llength $history]} { + .ctop.top.bar.rightbut conf -state disabled + } +} + +proc mergediff {id} { + global parents diffmergeid diffmergegca mergefilelist diffpindex + + set diffmergeid $id + set diffpindex -1 + set diffmergegca [findgca $parents($id)] + if {[info exists mergefilelist($id)]} { + if {$mergefilelist($id) ne {}} { + showmergediff + } + } else { + contmergediff {} + } +} + +proc findgca {ids} { + global env + set gca {} + foreach id $ids { + if {$gca eq {}} { + set gca $id + } else { + if {[catch { + set gca [exec $env(HG) --config ui.report_untrusted=false debug-merge-base $gca $id] + } err]} { + return {} + } + } + } + return $gca +} + +proc contmergediff {ids} { + global diffmergeid diffpindex parents nparents diffmergegca + global treediffs mergefilelist diffids treepending + + # diff the child against each of the parents, and diff + # each of the parents against the GCA. + while 1 { + if {[lindex $ids 0] == $diffmergeid && $diffmergegca ne {}} { + set ids [list [lindex $ids 1] $diffmergegca] + } else { + if {[incr diffpindex] >= $nparents($diffmergeid)} break + set p [lindex $parents($diffmergeid) $diffpindex] + set ids [list $diffmergeid $p] + } + if {![info exists treediffs($ids)]} { + set diffids $ids + if {![info exists treepending]} { + gettreediffs $ids + } + return + } + } + + # If a file in some parent is different from the child and also + # different from the GCA, then it's interesting. + # If we don't have a GCA, then a file is interesting if it is + # different from the child in all the parents. + if {$diffmergegca ne {}} { + set files {} + foreach p $parents($diffmergeid) { + set gcadiffs $treediffs([list $p $diffmergegca]) + foreach f $treediffs([list $diffmergeid $p]) { + if {[lsearch -exact $files $f] < 0 + && [lsearch -exact $gcadiffs $f] >= 0} { + lappend files $f + } + } + } + set files [lsort $files] + } else { + set p [lindex $parents($diffmergeid) 0] + set files $treediffs([list $diffmergeid $p]) + for {set i 1} {$i < $nparents($diffmergeid) && $files ne {}} {incr i} { + set p [lindex $parents($diffmergeid) $i] + set df $treediffs([list $diffmergeid $p]) + set nf {} + foreach f $files { + if {[lsearch -exact $df $f] >= 0} { + lappend nf $f + } + } + set files $nf + } + } + + set mergefilelist($diffmergeid) $files + if {$files ne {}} { + showmergediff + } +} + +proc showmergediff {} { + global cflist diffmergeid mergefilelist parents + global diffopts diffinhunk currentfile currenthunk filelines + global diffblocked groupfilelast mergefds groupfilenum grouphunks + global env + + set files $mergefilelist($diffmergeid) + foreach f $files { + $cflist insert end $f + } + set env(GIT_DIFF_OPTS) $diffopts + set flist {} + catch {unset currentfile} + catch {unset currenthunk} + catch {unset filelines} + catch {unset groupfilenum} + catch {unset grouphunks} + set groupfilelast -1 + foreach p $parents($diffmergeid) { + set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $p $diffmergeid] + set cmd [concat $cmd $mergefilelist($diffmergeid)] + if {[catch {set f [open $cmd r]} err]} { + error_popup "Error getting diffs: $err" + foreach f $flist { + catch {close $f} + } + return + } + lappend flist $f + set ids [list $diffmergeid $p] + set mergefds($ids) $f + set diffinhunk($ids) 0 + set diffblocked($ids) 0 + fconfigure $f -blocking 0 + fileevent $f readable [list getmergediffline $f $ids $diffmergeid] + } +} + +proc getmergediffline {f ids id} { + global diffmergeid diffinhunk diffoldlines diffnewlines + global currentfile currenthunk + global diffoldstart diffnewstart diffoldlno diffnewlno + global diffblocked mergefilelist + global noldlines nnewlines difflcounts filelines + + set n [gets $f line] + if {$n < 0} { + if {![eof $f]} return + } + + if {!([info exists diffmergeid] && $diffmergeid == $id)} { + if {$n < 0} { + close $f + } + return + } + + if {$diffinhunk($ids) != 0} { + set fi $currentfile($ids) + if {$n > 0 && [regexp {^[-+ \\]} $line match]} { + # continuing an existing hunk + set line [string range $line 1 end] + set p [lindex $ids 1] + if {$match eq "-" || $match eq " "} { + set filelines($p,$fi,$diffoldlno($ids)) $line + incr diffoldlno($ids) + } + if {$match eq "+" || $match eq " "} { + set filelines($id,$fi,$diffnewlno($ids)) $line + incr diffnewlno($ids) + } + if {$match eq " "} { + if {$diffinhunk($ids) == 2} { + lappend difflcounts($ids) \ + [list $noldlines($ids) $nnewlines($ids)] + set noldlines($ids) 0 + set diffinhunk($ids) 1 + } + incr noldlines($ids) + } elseif {$match eq "-" || $match eq "+"} { + if {$diffinhunk($ids) == 1} { + lappend difflcounts($ids) [list $noldlines($ids)] + set noldlines($ids) 0 + set nnewlines($ids) 0 + set diffinhunk($ids) 2 + } + if {$match eq "-"} { + incr noldlines($ids) + } else { + incr nnewlines($ids) + } + } + # and if it's \ No newline at end of line, then what? + return + } + # end of a hunk + if {$diffinhunk($ids) == 1 && $noldlines($ids) != 0} { + lappend difflcounts($ids) [list $noldlines($ids)] + } elseif {$diffinhunk($ids) == 2 + && ($noldlines($ids) != 0 || $nnewlines($ids) != 0)} { + lappend difflcounts($ids) [list $noldlines($ids) $nnewlines($ids)] + } + set currenthunk($ids) [list $currentfile($ids) \ + $diffoldstart($ids) $diffnewstart($ids) \ + $diffoldlno($ids) $diffnewlno($ids) \ + $difflcounts($ids)] + set diffinhunk($ids) 0 + # -1 = need to block, 0 = unblocked, 1 = is blocked + set diffblocked($ids) -1 + processhunks + if {$diffblocked($ids) == -1} { + fileevent $f readable {} + set diffblocked($ids) 1 + } + } + + if {$n < 0} { + # eof + if {!$diffblocked($ids)} { + close $f + set currentfile($ids) [llength $mergefilelist($diffmergeid)] + set currenthunk($ids) [list $currentfile($ids) 0 0 0 0 {}] + processhunks + } + } elseif {[regexp {^diff --git a/(.*) b/} $line match fname]} { + # start of a new file + set currentfile($ids) \ + [lsearch -exact $mergefilelist($diffmergeid) $fname] + } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \ + $line match f1l f1c f2l f2c rest]} { + if {[info exists currentfile($ids)] && $currentfile($ids) >= 0} { + # start of a new hunk + if {$f1l == 0 && $f1c == 0} { + set f1l 1 + } + if {$f2l == 0 && $f2c == 0} { + set f2l 1 + } + set diffinhunk($ids) 1 + set diffoldstart($ids) $f1l + set diffnewstart($ids) $f2l + set diffoldlno($ids) $f1l + set diffnewlno($ids) $f2l + set difflcounts($ids) {} + set noldlines($ids) 0 + set nnewlines($ids) 0 + } + } +} + +proc processhunks {} { + global diffmergeid parents nparents currenthunk + global mergefilelist diffblocked mergefds + global grouphunks grouplinestart grouplineend groupfilenum + + set nfiles [llength $mergefilelist($diffmergeid)] + while 1 { + set fi $nfiles + set lno 0 + # look for the earliest hunk + foreach p $parents($diffmergeid) { + set ids [list $diffmergeid $p] + if {![info exists currenthunk($ids)]} return + set i [lindex $currenthunk($ids) 0] + set l [lindex $currenthunk($ids) 2] + if {$i < $fi || ($i == $fi && $l < $lno)} { + set fi $i + set lno $l + set pi $p + } + } + + if {$fi < $nfiles} { + set ids [list $diffmergeid $pi] + set hunk $currenthunk($ids) + unset currenthunk($ids) + if {$diffblocked($ids) > 0} { + fileevent $mergefds($ids) readable \ + [list getmergediffline $mergefds($ids) $ids $diffmergeid] + } + set diffblocked($ids) 0 + + if {[info exists groupfilenum] && $groupfilenum == $fi + && $lno <= $grouplineend} { + # add this hunk to the pending group + lappend grouphunks($pi) $hunk + set endln [lindex $hunk 4] + if {$endln > $grouplineend} { + set grouplineend $endln + } + continue + } + } + + # succeeding stuff doesn't belong in this group, so + # process the group now + if {[info exists groupfilenum]} { + processgroup + unset groupfilenum + unset grouphunks + } + + if {$fi >= $nfiles} break + + # start a new group + set groupfilenum $fi + set grouphunks($pi) [list $hunk] + set grouplinestart $lno + set grouplineend [lindex $hunk 4] + } +} + +proc processgroup {} { + global groupfilelast groupfilenum difffilestart + global mergefilelist diffmergeid ctext filelines + global parents diffmergeid diffoffset + global grouphunks grouplinestart grouplineend nparents + global mergemax + + $ctext conf -state normal + set id $diffmergeid + set f $groupfilenum + if {$groupfilelast != $f} { + $ctext insert end "\n" + set here [$ctext index "end - 1c"] + set difffilestart($f) $here + set mark fmark.[expr {$f + 1}] + $ctext mark set $mark $here + $ctext mark gravity $mark left + set header [lindex $mergefilelist($id) $f] + set l [expr {(78 - [string length $header]) / 2}] + set pad [string range "----------------------------------------" 1 $l] + $ctext insert end "$pad $header $pad\n" filesep + set groupfilelast $f + foreach p $parents($id) { + set diffoffset($p) 0 + } + } + + $ctext insert end "@@" msep + set nlines [expr {$grouplineend - $grouplinestart}] + set events {} + set pnum 0 + foreach p $parents($id) { + set startline [expr {$grouplinestart + $diffoffset($p)}] + set ol $startline + set nl $grouplinestart + if {[info exists grouphunks($p)]} { + foreach h $grouphunks($p) { + set l [lindex $h 2] + if {$nl < $l} { + for {} {$nl < $l} {incr nl} { + set filelines($p,$f,$ol) $filelines($id,$f,$nl) + incr ol + } + } + foreach chunk [lindex $h 5] { + if {[llength $chunk] == 2} { + set olc [lindex $chunk 0] + set nlc [lindex $chunk 1] + set nnl [expr {$nl + $nlc}] + lappend events [list $nl $nnl $pnum $olc $nlc] + incr ol $olc + set nl $nnl + } else { + incr ol [lindex $chunk 0] + incr nl [lindex $chunk 0] + } + } + } + } + if {$nl < $grouplineend} { + for {} {$nl < $grouplineend} {incr nl} { + set filelines($p,$f,$ol) $filelines($id,$f,$nl) + incr ol + } + } + set nlines [expr {$ol - $startline}] + $ctext insert end " -$startline,$nlines" msep + incr pnum + } + + set nlines [expr {$grouplineend - $grouplinestart}] + $ctext insert end " +$grouplinestart,$nlines @@\n" msep + + set events [lsort -integer -index 0 $events] + set nevents [llength $events] + set nmerge $nparents($diffmergeid) + set l $grouplinestart + for {set i 0} {$i < $nevents} {set i $j} { + set nl [lindex $events $i 0] + while {$l < $nl} { + $ctext insert end " $filelines($id,$f,$l)\n" + incr l + } + set e [lindex $events $i] + set enl [lindex $e 1] + set j $i + set active {} + while 1 { + set pnum [lindex $e 2] + set olc [lindex $e 3] + set nlc [lindex $e 4] + if {![info exists delta($pnum)]} { + set delta($pnum) [expr {$olc - $nlc}] + lappend active $pnum + } else { + incr delta($pnum) [expr {$olc - $nlc}] + } + if {[incr j] >= $nevents} break + set e [lindex $events $j] + if {[lindex $e 0] >= $enl} break + if {[lindex $e 1] > $enl} { + set enl [lindex $e 1] + } + } + set nlc [expr {$enl - $l}] + set ncol mresult + set bestpn -1 + if {[llength $active] == $nmerge - 1} { + # no diff for one of the parents, i.e. it's identical + for {set pnum 0} {$pnum < $nmerge} {incr pnum} { + if {![info exists delta($pnum)]} { + if {$pnum < $mergemax} { + lappend ncol m$pnum + } else { + lappend ncol mmax + } + break + } + } + } elseif {[llength $active] == $nmerge} { + # all parents are different, see if one is very similar + set bestsim 30 + for {set pnum 0} {$pnum < $nmerge} {incr pnum} { + set sim [similarity $pnum $l $nlc $f \ + [lrange $events $i [expr {$j-1}]]] + if {$sim > $bestsim} { + set bestsim $sim + set bestpn $pnum + } + } + if {$bestpn >= 0} { + lappend ncol m$bestpn + } + } + set pnum -1 + foreach p $parents($id) { + incr pnum + if {![info exists delta($pnum)] || $pnum == $bestpn} continue + set olc [expr {$nlc + $delta($pnum)}] + set ol [expr {$l + $diffoffset($p)}] + incr diffoffset($p) $delta($pnum) + unset delta($pnum) + for {} {$olc > 0} {incr olc -1} { + $ctext insert end "-$filelines($p,$f,$ol)\n" m$pnum + incr ol + } + } + set endl [expr {$l + $nlc}] + if {$bestpn >= 0} { + # show this pretty much as a normal diff + set p [lindex $parents($id) $bestpn] + set ol [expr {$l + $diffoffset($p)}] + incr diffoffset($p) $delta($bestpn) + unset delta($bestpn) + for {set k $i} {$k < $j} {incr k} { + set e [lindex $events $k] + if {[lindex $e 2] != $bestpn} continue + set nl [lindex $e 0] + set ol [expr {$ol + $nl - $l}] + for {} {$l < $nl} {incr l} { + $ctext insert end "+$filelines($id,$f,$l)\n" $ncol + } + set c [lindex $e 3] + for {} {$c > 0} {incr c -1} { + $ctext insert end "-$filelines($p,$f,$ol)\n" m$bestpn + incr ol + } + set nl [lindex $e 1] + for {} {$l < $nl} {incr l} { + $ctext insert end "+$filelines($id,$f,$l)\n" mresult + } + } + } + for {} {$l < $endl} {incr l} { + $ctext insert end "+$filelines($id,$f,$l)\n" $ncol + } + } + while {$l < $grouplineend} { + $ctext insert end " $filelines($id,$f,$l)\n" + incr l + } + $ctext conf -state disabled +} + +proc similarity {pnum l nlc f events} { + global diffmergeid parents diffoffset filelines + + set id $diffmergeid + set p [lindex $parents($id) $pnum] + set ol [expr {$l + $diffoffset($p)}] + set endl [expr {$l + $nlc}] + set same 0 + set diff 0 + foreach e $events { + if {[lindex $e 2] != $pnum} continue + set nl [lindex $e 0] + set ol [expr {$ol + $nl - $l}] + for {} {$l < $nl} {incr l} { + incr same [string length $filelines($id,$f,$l)] + incr same + } + set oc [lindex $e 3] + for {} {$oc > 0} {incr oc -1} { + incr diff [string length $filelines($p,$f,$ol)] + incr diff + incr ol + } + set nl [lindex $e 1] + for {} {$l < $nl} {incr l} { + incr diff [string length $filelines($id,$f,$l)] + incr diff + } + } + for {} {$l < $endl} {incr l} { + incr same [string length $filelines($id,$f,$l)] + incr same + } + if {$same == 0} { + return 0 + } + return [expr {200 * $same / (2 * $same + $diff)}] +} + +proc startdiff {ids} { + global treediffs diffids treepending diffmergeid + + set diffids $ids + catch {unset diffmergeid} + if {![info exists treediffs($ids)]} { + if {![info exists treepending]} { + gettreediffs $ids + } + } else { + addtocflist $ids + } +} + +proc addtocflist {ids} { + global treediffs cflist + foreach f $treediffs($ids) { + $cflist insert end $f + } + getblobdiffs $ids +} + +proc gettreediffs {ids} { + global treediff parents treepending env + set treepending $ids + set treediff {} + set id [lindex $ids 0] + set p [lindex $ids 1] + if [catch {set gdtf [open "|{$env(HG)} --config ui.report_untrusted=false debug-diff-tree -r $p $id" r]}] return + fconfigure $gdtf -blocking 0 + fileevent $gdtf readable [list gettreediffline $gdtf $ids] +} + +proc gettreediffline {gdtf ids} { + global treediff treediffs treepending diffids diffmergeid + + set n [gets $gdtf line] + if {$n < 0} { + if {![eof $gdtf]} return + close $gdtf + set treediffs($ids) $treediff + unset treepending + if {$ids != $diffids} { + gettreediffs $diffids + } else { + if {[info exists diffmergeid]} { + contmergediff $ids + } else { + addtocflist $ids + } + } + return + } + set tab1 [expr [string first "\t" $line] + 1] + set tab2 [expr [string first "\t" $line $tab1] - 1] + set file [string range $line $tab1 $tab2] + lappend treediff $file +} + +proc getblobdiffs {ids} { + global diffopts blobdifffd diffids env curdifftag curtagstart + global difffilestart nextupdate diffinhdr treediffs + + set id [lindex $ids 0] + set p [lindex $ids 1] + set env(GIT_DIFF_OPTS) $diffopts + set cmd [list | $env(HG) --config ui.report_untrusted=false debug-diff-tree -r -p -C $p $id] + if {[catch {set bdf [open $cmd r]} err]} { + puts "error getting diffs: $err" + return + } + set diffinhdr 0 + fconfigure $bdf -blocking 0 + set blobdifffd($ids) $bdf + set curdifftag Comments + set curtagstart 0.0 + catch {unset difffilestart} + fileevent $bdf readable [list getblobdiffline $bdf $diffids] + set nextupdate [expr {[clock clicks -milliseconds] + 100}] +} + +proc getblobdiffline {bdf ids} { + global diffids blobdifffd ctext curdifftag curtagstart + global diffnexthead diffnextnote difffilestart + global nextupdate diffinhdr treediffs + global gaudydiff + + set n [gets $bdf line] + if {$n < 0} { + if {[eof $bdf]} { + close $bdf + if {$ids == $diffids && $bdf == $blobdifffd($ids)} { + $ctext tag add $curdifftag $curtagstart end + } + } + return + } + if {$ids != $diffids || $bdf != $blobdifffd($ids)} { + return + } + regsub -all "\r" $line "" line + $ctext conf -state normal + if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} { + # start of a new file + $ctext insert end "\n" + $ctext tag add $curdifftag $curtagstart end + set curtagstart [$ctext index "end - 1c"] + set header $newname + set here [$ctext index "end - 1c"] + set i [lsearch -exact $treediffs($diffids) $fname] + if {$i >= 0} { + set difffilestart($i) $here + incr i + $ctext mark set fmark.$i $here + $ctext mark gravity fmark.$i left + } + if {$newname != $fname} { + set i [lsearch -exact $treediffs($diffids) $newname] + if {$i >= 0} { + set difffilestart($i) $here + incr i + $ctext mark set fmark.$i $here + $ctext mark gravity fmark.$i left + } + } + set curdifftag "f:$fname" + $ctext tag delete $curdifftag + set l [expr {(78 - [string length $header]) / 2}] + set pad [string range "----------------------------------------" 1 $l] + $ctext insert end "$pad $header $pad\n" filesep + set diffinhdr 1 + } elseif {[regexp {^(---|\+\+\+)} $line]} { + set diffinhdr 0 + } elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \ + $line match f1l f1c f2l f2c rest]} { + if {$gaudydiff} { + $ctext insert end "\t" hunksep + $ctext insert end " $f1l " d0 " $f2l " d1 + $ctext insert end " $rest \n" hunksep + } else { + $ctext insert end "$line\n" hunksep + } + set diffinhdr 0 + } else { + set x [string range $line 0 0] + if {$x == "-" || $x == "+"} { + set tag [expr {$x == "+"}] + if {$gaudydiff} { + set line [string range $line 1 end] + } + $ctext insert end "$line\n" d$tag + } elseif {$x == " "} { + if {$gaudydiff} { + set line [string range $line 1 end] + } + $ctext insert end "$line\n" + } elseif {$diffinhdr || $x == "\\"} { + # e.g. "\ No newline at end of file" + $ctext insert end "$line\n" filesep + } elseif {$line != ""} { + # Something else we don't recognize + if {$curdifftag != "Comments"} { + $ctext insert end "\n" + $ctext tag add $curdifftag $curtagstart end + set curtagstart [$ctext index "end - 1c"] + set curdifftag Comments + } + $ctext insert end "$line\n" filesep + } + } + $ctext conf -state disabled + if {[clock clicks -milliseconds] >= $nextupdate} { + incr nextupdate 100 + fileevent $bdf readable {} + update + fileevent $bdf readable "getblobdiffline $bdf {$ids}" + } +} + +proc nextfile {} { + global difffilestart ctext + set here [$ctext index @0,0] + for {set i 0} {[info exists difffilestart($i)]} {incr i} { + if {[$ctext compare $difffilestart($i) > $here]} { + if {![info exists pos] + || [$ctext compare $difffilestart($i) < $pos]} { + set pos $difffilestart($i) + } + } + } + if {[info exists pos]} { + $ctext yview $pos + } +} + +proc listboxsel {} { + global ctext cflist currentid + if {![info exists currentid]} return + set sel [lsort [$cflist curselection]] + if {$sel eq {}} return + set first [lindex $sel 0] + catch {$ctext yview fmark.$first} +} + +proc setcoords {} { + global linespc charspc canvx0 canvy0 mainfont + global xspc1 xspc2 lthickness + + set linespc [font metrics $mainfont -linespace] + set charspc [font measure $mainfont "m"] + set canvy0 [expr 3 + 0.5 * $linespc] + set canvx0 [expr 3 + 0.5 * $linespc] + set lthickness [expr {int($linespc / 9) + 1}] + set xspc1(0) $linespc + set xspc2 $linespc +} + +proc redisplay {} { + global stopped redisplaying phase + if {$stopped > 1} return + if {$phase == "getcommits"} return + set redisplaying 1 + if {$phase == "drawgraph" || $phase == "incrdraw"} { + set stopped 1 + } else { + drawgraph + } +} + +proc incrfont {inc} { + global mainfont namefont textfont ctext canv phase + global stopped entries curidfont + unmarkmatches + set mainfont [lreplace $mainfont 1 1 [expr {[lindex $mainfont 1] + $inc}]] + set curidfont [lreplace $curidfont 1 1 [expr {[lindex $curidfont 1] + $inc}]] + set namefont [lreplace $namefont 1 1 [expr {[lindex $namefont 1] + $inc}]] + set textfont [lreplace $textfont 1 1 [expr {[lindex $textfont 1] + $inc}]] + setcoords + $ctext conf -font $textfont + $ctext tag conf filesep -font [concat $textfont bold] + foreach e $entries { + $e conf -font $mainfont + } + if {$phase == "getcommits"} { + $canv itemconf textitems -font $mainfont + } + redisplay +} + +proc clearsha1 {} { + global sha1entry sha1string + if {[string length $sha1string] == 40} { + $sha1entry delete 0 end + } +} + +proc sha1change {n1 n2 op} { + global sha1string currentid sha1but + if {$sha1string == {} + || ([info exists currentid] && $sha1string == $currentid)} { + set state disabled + } else { + set state normal + } + if {[$sha1but cget -state] == $state} return + if {$state == "normal"} { + $sha1but conf -state normal -relief raised -text "Goto: " + } else { + $sha1but conf -state disabled -relief flat -text "SHA1 ID: " + } +} + +proc gotocommit {} { + global sha1string currentid idline tagids + global lineid numcommits + + if {$sha1string == {} + || ([info exists currentid] && $sha1string == $currentid)} return + if {[info exists tagids($sha1string)]} { + set id $tagids($sha1string) + } else { + set id [string tolower $sha1string] + if {[regexp {^[0-9a-f]{4,39}$} $id]} { + set matches {} + for {set l 0} {$l < $numcommits} {incr l} { + if {[string match $id* $lineid($l)]} { + lappend matches $lineid($l) + } + } + if {$matches ne {}} { + if {[llength $matches] > 1} { + error_popup "Short SHA1 id $id is ambiguous" + return + } + set id [lindex $matches 0] + } + } + } + if {[info exists idline($id)]} { + selectline $idline($id) 1 + return + } + if {[regexp {^[0-9a-fA-F]{4,}$} $sha1string]} { + set type "SHA1 id" + } else { + set type "Tag" + } + error_popup "$type $sha1string is not known" +} + +proc lineenter {x y id} { + global hoverx hovery hoverid hovertimer + global commitinfo canv + + if {![info exists commitinfo($id)]} return + set hoverx $x + set hovery $y + set hoverid $id + if {[info exists hovertimer]} { + after cancel $hovertimer + } + set hovertimer [after 500 linehover] + $canv delete hover +} + +proc linemotion {x y id} { + global hoverx hovery hoverid hovertimer + + if {[info exists hoverid] && $id == $hoverid} { + set hoverx $x + set hovery $y + if {[info exists hovertimer]} { + after cancel $hovertimer + } + set hovertimer [after 500 linehover] + } +} + +proc lineleave {id} { + global hoverid hovertimer canv + + if {[info exists hoverid] && $id == $hoverid} { + $canv delete hover + if {[info exists hovertimer]} { + after cancel $hovertimer + unset hovertimer + } + unset hoverid + } +} + +proc linehover {} { + global hoverx hovery hoverid hovertimer + global canv linespc lthickness + global commitinfo mainfont + + set text [lindex $commitinfo($hoverid) 0] + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax == {}} return + set yfrac [lindex [$canv yview] 0] + set x [expr {$hoverx + 2 * $linespc}] + set y [expr {$hovery + $yfrac * $ymax - $linespc / 2}] + set x0 [expr {$x - 2 * $lthickness}] + set y0 [expr {$y - 2 * $lthickness}] + set x1 [expr {$x + [font measure $mainfont $text] + 2 * $lthickness}] + set y1 [expr {$y + $linespc + 2 * $lthickness}] + set t [$canv create rectangle $x0 $y0 $x1 $y1 \ + -fill \#ffff80 -outline black -width 1 -tags hover] + $canv raise $t + set t [$canv create text $x $y -anchor nw -text $text -tags hover] + $canv raise $t +} + +proc clickisonarrow {id y} { + global mainline mainlinearrow sidelines lthickness + + set thresh [expr {2 * $lthickness + 6}] + if {[info exists mainline($id)]} { + if {$mainlinearrow($id) ne "none"} { + if {abs([lindex $mainline($id) 1] - $y) < $thresh} { + return "up" + } + } + } + if {[info exists sidelines($id)]} { + foreach ls $sidelines($id) { + set coords [lindex $ls 0] + set arrow [lindex $ls 2] + if {$arrow eq "first" || $arrow eq "both"} { + if {abs([lindex $coords 1] - $y) < $thresh} { + return "up" + } + } + if {$arrow eq "last" || $arrow eq "both"} { + if {abs([lindex $coords end] - $y) < $thresh} { + return "down" + } + } + } + } + return {} +} + +proc arrowjump {id dirn y} { + global mainline sidelines canv + + set yt {} + if {$dirn eq "down"} { + if {[info exists mainline($id)]} { + set y1 [lindex $mainline($id) 1] + if {$y1 > $y} { + set yt $y1 + } + } + if {[info exists sidelines($id)]} { + foreach ls $sidelines($id) { + set y1 [lindex $ls 0 1] + if {$y1 > $y && ($yt eq {} || $y1 < $yt)} { + set yt $y1 + } + } + } + } else { + if {[info exists sidelines($id)]} { + foreach ls $sidelines($id) { + set y1 [lindex $ls 0 end] + if {$y1 < $y && ($yt eq {} || $y1 > $yt)} { + set yt $y1 + } + } + } + } + if {$yt eq {}} return + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax eq {} || $ymax <= 0} return + set view [$canv yview] + set yspan [expr {[lindex $view 1] - [lindex $view 0]}] + set yfrac [expr {$yt / $ymax - $yspan / 2}] + if {$yfrac < 0} { + set yfrac 0 + } + $canv yview moveto $yfrac +} + +proc lineclick {x y id isnew} { + global ctext commitinfo children cflist canv thickerline + + unmarkmatches + unselectline + normalline + $canv delete hover + # draw this line thicker than normal + drawlines $id 1 + set thickerline $id + if {$isnew} { + set ymax [lindex [$canv cget -scrollregion] 3] + if {$ymax eq {}} return + set yfrac [lindex [$canv yview] 0] + set y [expr {$y + $yfrac * $ymax}] + } + set dirn [clickisonarrow $id $y] + if {$dirn ne {}} { + arrowjump $id $dirn $y + return + } + + if {$isnew} { + addtohistory [list lineclick $x $y $id 0] + } + # fill the details pane with info about this line + $ctext conf -state normal + $ctext delete 0.0 end + $ctext tag conf link -foreground blue -underline 1 + $ctext tag bind link { %W configure -cursor hand2 } + $ctext tag bind link { %W configure -cursor $curtextcursor } + $ctext insert end "Parent:\t" + $ctext insert end $id [list link link0] + $ctext tag bind link0 <1> [list selbyid $id] + set info $commitinfo($id) + $ctext insert end "\n\t[lindex $info 0]\n" + $ctext insert end "\tAuthor:\t[lindex $info 1]\n" + $ctext insert end "\tDate:\t[lindex $info 2]\n" + if {[info exists children($id)]} { + $ctext insert end "\nChildren:" + set i 0 + foreach child $children($id) { + incr i + set info $commitinfo($child) + $ctext insert end "\n\t" + $ctext insert end $child [list link link$i] + $ctext tag bind link$i <1> [list selbyid $child] + $ctext insert end "\n\t[lindex $info 0]" + $ctext insert end "\n\tAuthor:\t[lindex $info 1]" + $ctext insert end "\n\tDate:\t[lindex $info 2]\n" + } + } + $ctext conf -state disabled + + $cflist delete 0 end +} + +proc normalline {} { + global thickerline + if {[info exists thickerline]} { + drawlines $thickerline 0 + unset thickerline + } +} + +proc selbyid {id} { + global idline + if {[info exists idline($id)]} { + selectline $idline($id) 1 + } +} + +proc mstime {} { + global startmstime + if {![info exists startmstime]} { + set startmstime [clock clicks -milliseconds] + } + return [format "%.3f" [expr {([clock click -milliseconds] - $startmstime) / 1000.0}]] +} + +proc rowmenu {x y id} { + global rowctxmenu idline selectedline rowmenuid hgvdiff + + if {![info exists selectedline] || $idline($id) eq $selectedline} { + set state disabled + } else { + set state normal + } + $rowctxmenu entryconfigure 0 -state $state + $rowctxmenu entryconfigure 1 -state $state + $rowctxmenu entryconfigure 2 -state $state + if { $hgvdiff ne "" } { + $rowctxmenu entryconfigure 6 -state $state + } + set rowmenuid $id + tk_popup $rowctxmenu $x $y +} + +proc diffvssel {dirn} { + global rowmenuid selectedline lineid + + if {![info exists selectedline]} return + if {$dirn} { + set oldid $lineid($selectedline) + set newid $rowmenuid + } else { + set oldid $rowmenuid + set newid $lineid($selectedline) + } + addtohistory [list doseldiff $oldid $newid] + doseldiff $oldid $newid +} + +proc doseldiff {oldid newid} { + global ctext cflist + global commitinfo + + $ctext conf -state normal + $ctext delete 0.0 end + $ctext mark set fmark.0 0.0 + $ctext mark gravity fmark.0 left + $cflist delete 0 end + $cflist insert end "Top" + $ctext insert end "From " + $ctext tag conf link -foreground blue -underline 1 + $ctext tag bind link { %W configure -cursor hand2 } + $ctext tag bind link { %W configure -cursor $curtextcursor } + $ctext tag bind link0 <1> [list selbyid $oldid] + $ctext insert end $oldid [list link link0] + $ctext insert end "\n " + $ctext insert end [lindex $commitinfo($oldid) 0] + $ctext insert end "\n\nTo " + $ctext tag bind link1 <1> [list selbyid $newid] + $ctext insert end $newid [list link link1] + $ctext insert end "\n " + $ctext insert end [lindex $commitinfo($newid) 0] + $ctext insert end "\n" + $ctext conf -state disabled + $ctext tag delete Comments + $ctext tag remove found 1.0 end + startdiff [list $newid $oldid] +} + +proc mkpatch {} { + global rowmenuid currentid commitinfo patchtop patchnum + + if {![info exists currentid]} return + set oldid $currentid + set oldhead [lindex $commitinfo($oldid) 0] + set newid $rowmenuid + set newhead [lindex $commitinfo($newid) 0] + set top .patch + set patchtop $top + catch {destroy $top} + toplevel $top + label $top.title -text "Generate patch" + grid $top.title - -pady 10 + label $top.from -text "From:" + entry $top.fromsha1 -width 40 -relief flat + $top.fromsha1 insert 0 $oldid + $top.fromsha1 conf -state readonly + grid $top.from $top.fromsha1 -sticky w + entry $top.fromhead -width 60 -relief flat + $top.fromhead insert 0 $oldhead + $top.fromhead conf -state readonly + grid x $top.fromhead -sticky w + label $top.to -text "To:" + entry $top.tosha1 -width 40 -relief flat + $top.tosha1 insert 0 $newid + $top.tosha1 conf -state readonly + grid $top.to $top.tosha1 -sticky w + entry $top.tohead -width 60 -relief flat + $top.tohead insert 0 $newhead + $top.tohead conf -state readonly + grid x $top.tohead -sticky w + button $top.rev -text "Reverse" -command mkpatchrev -padx 5 + grid $top.rev x -pady 10 + label $top.flab -text "Output file:" + entry $top.fname -width 60 + $top.fname insert 0 [file normalize "patch$patchnum.patch"] + incr patchnum + grid $top.flab $top.fname -sticky w + frame $top.buts + button $top.buts.gen -text "Generate" -command mkpatchgo + button $top.buts.can -text "Cancel" -command mkpatchcan + grid $top.buts.gen $top.buts.can + grid columnconfigure $top.buts 0 -weight 1 -uniform a + grid columnconfigure $top.buts 1 -weight 1 -uniform a + grid $top.buts - -pady 10 -sticky ew + focus $top.fname +} + +proc mkpatchrev {} { + global patchtop + + set oldid [$patchtop.fromsha1 get] + set oldhead [$patchtop.fromhead get] + set newid [$patchtop.tosha1 get] + set newhead [$patchtop.tohead get] + foreach e [list fromsha1 fromhead tosha1 tohead] \ + v [list $newid $newhead $oldid $oldhead] { + $patchtop.$e conf -state normal + $patchtop.$e delete 0 end + $patchtop.$e insert 0 $v + $patchtop.$e conf -state readonly + } +} + +proc mkpatchgo {} { + global patchtop env + + set oldid [$patchtop.fromsha1 get] + set newid [$patchtop.tosha1 get] + set fname [$patchtop.fname get] + if {[catch {exec $env(HG) --config ui.report_untrusted=false debug-diff-tree -p $oldid $newid >$fname &} err]} { + error_popup "Error creating patch: $err" + } + catch {destroy $patchtop} + unset patchtop +} + +proc mkpatchcan {} { + global patchtop + + catch {destroy $patchtop} + unset patchtop +} + +proc mktag {} { + global rowmenuid mktagtop commitinfo + + set top .maketag + set mktagtop $top + catch {destroy $top} + toplevel $top + label $top.title -text "Create tag" + grid $top.title - -pady 10 + label $top.id -text "ID:" + entry $top.sha1 -width 40 -relief flat + $top.sha1 insert 0 $rowmenuid + $top.sha1 conf -state readonly + grid $top.id $top.sha1 -sticky w + entry $top.head -width 60 -relief flat + $top.head insert 0 [lindex $commitinfo($rowmenuid) 0] + $top.head conf -state readonly + grid x $top.head -sticky w + label $top.tlab -text "Tag name:" + entry $top.tag -width 60 + grid $top.tlab $top.tag -sticky w + frame $top.buts + button $top.buts.gen -text "Create" -command mktaggo + button $top.buts.can -text "Cancel" -command mktagcan + grid $top.buts.gen $top.buts.can + grid columnconfigure $top.buts 0 -weight 1 -uniform a + grid columnconfigure $top.buts 1 -weight 1 -uniform a + grid $top.buts - -pady 10 -sticky ew + focus $top.tag +} + +proc domktag {} { + global mktagtop env tagids idtags + + set id [$mktagtop.sha1 get] + set tag [$mktagtop.tag get] + if {$tag == {}} { + error_popup "No tag name specified" + return + } + if {[info exists tagids($tag)]} { + error_popup "Tag \"$tag\" already exists" + return + } + if {[catch { + set out [exec $env(HG) --config ui.report_untrusted=false tag -r $id $tag] + } err]} { + error_popup "Error creating tag: $err" + return + } + + set tagids($tag) $id + lappend idtags($id) $tag + redrawtags $id +} + +proc redrawtags {id} { + global canv linehtag idline idpos selectedline + + if {![info exists idline($id)]} return + $canv delete tag.$id + set xt [eval drawtags $id $idpos($id)] + $canv coords $linehtag($idline($id)) $xt [lindex $idpos($id) 2] + if {[info exists selectedline] && $selectedline == $idline($id)} { + selectline $selectedline 0 + } +} + +proc mktagcan {} { + global mktagtop + + catch {destroy $mktagtop} + unset mktagtop +} + +proc mktaggo {} { + domktag + mktagcan +} + +proc writecommit {} { + global rowmenuid wrcomtop commitinfo wrcomcmd + + set top .writecommit + set wrcomtop $top + catch {destroy $top} + toplevel $top + label $top.title -text "Write commit to file" + grid $top.title - -pady 10 + label $top.id -text "ID:" + entry $top.sha1 -width 40 -relief flat + $top.sha1 insert 0 $rowmenuid + $top.sha1 conf -state readonly + grid $top.id $top.sha1 -sticky w + entry $top.head -width 60 -relief flat + $top.head insert 0 [lindex $commitinfo($rowmenuid) 0] + $top.head conf -state readonly + grid x $top.head -sticky w + label $top.clab -text "Command:" + entry $top.cmd -width 60 -textvariable wrcomcmd + grid $top.clab $top.cmd -sticky w -pady 10 + label $top.flab -text "Output file:" + entry $top.fname -width 60 + $top.fname insert 0 [file normalize "commit-[string range $rowmenuid 0 6]"] + grid $top.flab $top.fname -sticky w + frame $top.buts + button $top.buts.gen -text "Write" -command wrcomgo + button $top.buts.can -text "Cancel" -command wrcomcan + grid $top.buts.gen $top.buts.can + grid columnconfigure $top.buts 0 -weight 1 -uniform a + grid columnconfigure $top.buts 1 -weight 1 -uniform a + grid $top.buts - -pady 10 -sticky ew + focus $top.fname +} + +proc wrcomgo {} { + global wrcomtop + + set id [$wrcomtop.sha1 get] + set cmd "echo $id | [$wrcomtop.cmd get]" + set fname [$wrcomtop.fname get] + if {[catch {exec sh -c $cmd > $fname &} err]} { + error_popup "Error writing commit: $err" + } + catch {destroy $wrcomtop} + unset wrcomtop +} + +proc wrcomcan {} { + global wrcomtop + + catch {destroy $wrcomtop} + unset wrcomtop +} + +proc listrefs {id} { + global idtags idheads idotherrefs + + set x {} + if {[info exists idtags($id)]} { + set x $idtags($id) + } + set y {} + if {[info exists idheads($id)]} { + set y $idheads($id) + } + set z {} + if {[info exists idotherrefs($id)]} { + set z $idotherrefs($id) + } + return [list $x $y $z] +} + +proc rereadrefs {} { + global idtags idheads idotherrefs + global tagids headids otherrefids + + set refids [concat [array names idtags] \ + [array names idheads] [array names idotherrefs]] + foreach id $refids { + if {![info exists ref($id)]} { + set ref($id) [listrefs $id] + } + } + foreach v {tagids idtags headids idheads otherrefids idotherrefs} { + catch {unset $v} + } + readrefs + set refids [lsort -unique [concat $refids [array names idtags] \ + [array names idheads] [array names idotherrefs]]] + foreach id $refids { + set v [listrefs $id] + if {![info exists ref($id)] || $ref($id) != $v} { + redrawtags $id + } + } +} + +proc vdiff {withparent} { + global env rowmenuid selectedline lineid hgvdiff + + if {![info exists rowmenuid]} return + set curid $rowmenuid + + if {$withparent} { + set parents [exec $env(HG) --config ui.report_untrusted=false parents --rev $curid --template "{node}\n"] + set firstparent [lindex [split $parents "\n"] 0] + set otherid $firstparent + } else { + if {![info exists selectedline]} return + set otherid $lineid($selectedline) + } + set range "$otherid:$curid" + if {[catch {exec $env(HG) --config ui.report_untrusted=false $hgvdiff -r $range} err]} { + # Ignore errors, this is just visualization + } +} + +proc showtag {tag isnew} { + global ctext cflist tagcontents tagids linknum + + if {$isnew} { + addtohistory [list showtag $tag 0] + } + $ctext conf -state normal + $ctext delete 0.0 end + set linknum 0 + if {[info exists tagcontents($tag)]} { + set text $tagcontents($tag) + } else { + set text "Tag: $tag\nId: $tagids($tag)" + } + appendwithlinks $text + $ctext conf -state disabled + $cflist delete 0 end +} + +proc doquit {} { + global stopped + set stopped 100 + destroy . +} + +proc getconfig {} { + global env + + set lines [exec $env(HG) debug-config] + regsub -all "\r\n" $lines "\n" config + set config {} + foreach line [split $lines "\n"] { + regsub "^(k|v)=" $line "" line + lappend config $line + } + return $config +} + +# defaults... +set datemode 0 +set boldnames 0 +set diffopts "-U 5 -p" +set wrcomcmd "\"\$HG\" --config ui.report_untrusted=false debug-diff-tree --stdin -p --pretty" + +set mainfont {Helvetica 9} +set curidfont {} +set textfont {Courier 9} +set findmergefiles 0 +set gaudydiff 0 +set maxgraphpct 50 +set maxwidth 16 + +set colors {green red blue magenta darkgrey brown orange} +set authorcolors { + black blue deeppink mediumorchid blue burlywood4 goldenrod slateblue red2 navy dimgrey +} +set bgcolor white + +# This color should probably be some system color (provided by tk), +# but as the bgcolor has always been set to white, I choose to ignore +set fgcolor black +set diffaddcolor "#00a000" +set diffremcolor red +set diffmerge1color red +set diffmerge2color blue +set hunksepcolor blue + +catch {source ~/.hgk} + +if {$curidfont == ""} { # initialize late based on current mainfont + set curidfont "$mainfont bold italic underline" +} + +set namefont $mainfont +if {$boldnames} { + lappend namefont bold +} + +set revtreeargs {} +foreach arg $argv { + switch -regexp -- $arg { + "^$" { } + "^-b" { set boldnames 1 } + "^-d" { set datemode 1 } + default { + lappend revtreeargs $arg + } + } +} + +set history {} +set historyindex 0 + +set stopped 0 +set redisplaying 0 +set stuffsaved 0 +set patchnum 0 + +array set config [getconfig] +set hgvdiff $config(vdiff) +setcoords +makewindow +readrefs +set hgroot [exec $env(HG) root] +wm title . "hgk $hgroot" +getcommits $revtreeargs diff --git a/sys/src/cmd/hg/contrib/hgsh/Makefile b/sys/src/cmd/hg/contrib/hgsh/Makefile new file mode 100644 index 000000000..966158f54 --- /dev/null +++ b/sys/src/cmd/hg/contrib/hgsh/Makefile @@ -0,0 +1,13 @@ +CC := gcc +CFLAGS := -g -O2 -Wall -Werror + +prefix ?= /usr/bin + +hgsh: hgsh.o + $(CC) -o $@ $< + +install: hgsh + install -m755 hgsh $(prefix) + +clean: + rm -f *.o hgsh diff --git a/sys/src/cmd/hg/contrib/hgsh/hgsh.c b/sys/src/cmd/hg/contrib/hgsh/hgsh.c new file mode 100644 index 000000000..a6ce0063a --- /dev/null +++ b/sys/src/cmd/hg/contrib/hgsh/hgsh.c @@ -0,0 +1,439 @@ +/* + * hgsh.c - restricted login shell for mercurial + * + * Copyright 2006 Vadim Gelfer + * + * This software may be used and distributed according to the terms of the + * GNU General Public License, incorporated herein by reference. + * + * this program is login shell for dedicated mercurial user account. it + * only allows few actions: + * + * 1. run hg in server mode on specific repository. no other hg commands + * are allowed. we try to verify that repo to be accessed exists under + * given top-level directory. + * + * 2. (optional) forward ssh connection from firewall/gateway machine to + * "real" mercurial host, to let users outside intranet pull and push + * changes through firewall. + * + * 3. (optional) run normal shell, to allow to "su" to mercurial user, use + * "sudo" to run programs as that user, or run cron jobs as that user. + * + * only tested on linux yet. patches for non-linux systems welcome. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE /* for asprintf */ +#endif + +#include +#include +#include +#include +#include +#include +#include + +/* + * user config. + * + * if you see a hostname below, just use first part of hostname. example, + * if you have host named foo.bar.com, use "foo". + */ + +/* + * HG_GATEWAY: hostname of gateway/firewall machine that people outside your + * intranet ssh into if they need to ssh to other machines. if you do not + * have such machine, set to NULL. + */ +#ifndef HG_GATEWAY +#define HG_GATEWAY "gateway" +#endif + +/* + * HG_HOST: hostname of mercurial server. if any machine is allowed, set to + * NULL. + */ +#ifndef HG_HOST +#define HG_HOST "mercurial" +#endif + +/* + * HG_USER: username to log in from HG_GATEWAY to HG_HOST. if gateway and + * host username are same, set to NULL. + */ +#ifndef HG_USER +#define HG_USER "hg" +#endif + +/* + * HG_ROOT: root of tree full of mercurial repos. if you do not want to + * validate location of repo when someone is try to access, set to NULL. + */ +#ifndef HG_ROOT +#define HG_ROOT "/home/hg/repos" +#endif + +/* + * HG: path to the mercurial executable to run. + */ +#ifndef HG +#define HG "/home/hg/bin/hg" +#endif + +/* + * HG_SHELL: shell to use for actions like "sudo" and "su" access to + * mercurial user, and cron jobs. if you want to make these things + * impossible, set to NULL. + */ +#ifndef HG_SHELL +#define HG_SHELL NULL +// #define HG_SHELL "/bin/bash" +#endif + +/* + * HG_HELP: some way for users to get support if they have problem. if they + * should not get helpful message, set to NULL. + */ +#ifndef HG_HELP +#define HG_HELP "please contact support@example.com for help." +#endif + +/* + * SSH: path to ssh executable to run, if forwarding from HG_GATEWAY to + * HG_HOST. if you want to use rsh instead (why?), you need to modify + * arguments it is called with. see forward_through_gateway. + */ +#ifndef SSH +#define SSH "/usr/bin/ssh" +#endif + +/* + * tell whether to print command that is to be executed. useful for + * debugging. should not interfere with mercurial operation, since + * mercurial only cares about stdin and stdout, and this prints to stderr. + */ +static const int debug = 0; + +static void print_cmdline(int argc, char **argv) +{ + FILE *fp = stderr; + int i; + + fputs("command: ", fp); + + for (i = 0; i < argc; i++) { + char *spc = strpbrk(argv[i], " \t\r\n"); + if (spc) { + fputc('\'', fp); + } + fputs(argv[i], fp); + if (spc) { + fputc('\'', fp); + } + if (i < argc - 1) { + fputc(' ', fp); + } + } + fputc('\n', fp); + fflush(fp); +} + +static void usage(const char *reason, int exitcode) +{ + char *hg_help = HG_HELP; + + if (reason) { + fprintf(stderr, "*** Error: %s.\n", reason); + } + fprintf(stderr, "*** This program has been invoked incorrectly.\n"); + if (hg_help) { + fprintf(stderr, "*** %s\n", hg_help); + } + exit(exitcode ? exitcode : EX_USAGE); +} + +/* + * run on gateway host to make another ssh connection, to "real" mercurial + * server. it sends its command line unmodified to far end. + * + * never called if HG_GATEWAY is NULL. + */ +static void forward_through_gateway(int argc, char **argv) +{ + char *ssh = SSH; + char *hg_host = HG_HOST; + char *hg_user = HG_USER; + char **nargv = alloca((10 + argc) * sizeof(char *)); + int i = 0, j; + + nargv[i++] = ssh; + nargv[i++] = "-q"; + nargv[i++] = "-T"; + nargv[i++] = "-x"; + if (hg_user) { + nargv[i++] = "-l"; + nargv[i++] = hg_user; + } + nargv[i++] = hg_host; + + /* + * sshd called us with added "-c", because it thinks we are a shell. + * drop it if we find it. + */ + j = 1; + if (j < argc && strcmp(argv[j], "-c") == 0) { + j++; + } + + for (; j < argc; i++, j++) { + nargv[i] = argv[j]; + } + nargv[i] = NULL; + + if (debug) { + print_cmdline(i, nargv); + } + + execv(ssh, nargv); + perror(ssh); + exit(EX_UNAVAILABLE); +} + +/* + * run shell. let administrator "su" to mercurial user's account to do + * administrative works. + * + * never called if HG_SHELL is NULL. + */ +static void run_shell(int argc, char **argv) +{ + char *hg_shell = HG_SHELL; + char **nargv; + char *c; + int i; + + nargv = alloca((argc + 3) * sizeof(char *)); + c = strrchr(hg_shell, '/'); + + /* tell "real" shell it is login shell, if needed. */ + + if (argv[0][0] == '-' && c) { + nargv[0] = strdup(c); + if (nargv[0] == NULL) { + perror("malloc"); + exit(EX_OSERR); + } + nargv[0][0] = '-'; + } else { + nargv[0] = hg_shell; + } + + for (i = 1; i < argc; i++) { + nargv[i] = argv[i]; + } + nargv[i] = NULL; + + if (debug) { + print_cmdline(i, nargv); + } + + execv(hg_shell, nargv); + perror(hg_shell); + exit(EX_OSFILE); +} + +enum cmdline { + hg_init, + hg_serve, +}; + + +/* + * attempt to verify that a directory is really a hg repo, by testing + * for the existence of a subdirectory. + */ +static int validate_repo(const char *repo_root, const char *subdir) +{ + char *abs_path; + struct stat st; + int ret; + + if (asprintf(&abs_path, "%s.hg/%s", repo_root, subdir) == -1) { + ret = -1; + goto bail; + } + + /* verify that we really are looking at valid repo. */ + + if (stat(abs_path, &st) == -1) { + ret = 0; + } else { + ret = 1; + } + +bail: + return ret; +} + +/* + * paranoid wrapper, runs hg executable in server mode. + */ +static void serve_data(int argc, char **argv) +{ + char *hg_root = HG_ROOT; + char *repo, *repo_root; + enum cmdline cmd; + char *nargv[6]; + size_t repolen; + int i; + + /* + * check argv for looking okay. we should be invoked with argv + * resembling like this: + * + * hgsh + * -c + * hg -R some/path serve --stdio + * + * the "-c" is added by sshd, because it thinks we are login shell. + */ + + if (argc != 3) { + goto badargs; + } + + if (strcmp(argv[1], "-c") != 0) { + goto badargs; + } + + if (sscanf(argv[2], "hg init %as", &repo) == 1) { + cmd = hg_init; + } + else if (sscanf(argv[2], "hg -R %as serve --stdio", &repo) == 1) { + cmd = hg_serve; + } else { + goto badargs; + } + + repolen = repo ? strlen(repo) : 0; + + if (repolen == 0) { + goto badargs; + } + + if (hg_root) { + if (asprintf(&repo_root, "%s/%s/", hg_root, repo) == -1) { + goto badargs; + } + + /* + * attempt to stop break out from inside the repository tree. could + * do something more clever here, because e.g. we could traverse a + * symlink that looks safe, but really breaks us out of tree. + */ + + if (strstr(repo_root, "/../") != NULL) { + goto badargs; + } + + /* only hg init expects no repo. */ + + if (cmd != hg_init) { + int valid; + + valid = validate_repo(repo_root, "data"); + + if (valid == -1) { + goto badargs; + } + + if (valid == 0) { + valid = validate_repo(repo_root, "store"); + + if (valid == -1) { + goto badargs; + } + } + + if (valid == 0) { + perror(repo); + exit(EX_DATAERR); + } + } + + if (chdir(hg_root) == -1) { + perror(hg_root); + exit(EX_SOFTWARE); + } + } + + i = 0; + + switch (cmd) { + case hg_serve: + nargv[i++] = HG; + nargv[i++] = "-R"; + nargv[i++] = repo; + nargv[i++] = "serve"; + nargv[i++] = "--stdio"; + break; + case hg_init: + nargv[i++] = HG; + nargv[i++] = "init"; + nargv[i++] = repo; + break; + } + + nargv[i] = NULL; + + if (debug) { + print_cmdline(i, nargv); + } + + execv(HG, nargv); + perror(HG); + exit(EX_UNAVAILABLE); + +badargs: + /* print useless error message. */ + + usage("invalid arguments", EX_DATAERR); +} + +int main(int argc, char **argv) +{ + char host[1024]; + char *c; + + if (gethostname(host, sizeof(host)) == -1) { + perror("gethostname"); + exit(EX_OSERR); + } + + if ((c = strchr(host, '.')) != NULL) { + *c = '\0'; + } + + if (getenv("SSH_CLIENT")) { + char *hg_gateway = HG_GATEWAY; + char *hg_host = HG_HOST; + + if (hg_gateway && strcmp(host, hg_gateway) == 0) { + forward_through_gateway(argc, argv); + } + + if (hg_host && strcmp(host, hg_host) != 0) { + usage("invoked on unexpected host", EX_USAGE); + } + + serve_data(argc, argv); + } else if (HG_SHELL) { + run_shell(argc, argv); + } else { + usage("invalid arguments", EX_DATAERR); + } + + return 0; +} diff --git a/sys/src/cmd/hg/contrib/hgwebdir.fcgi b/sys/src/cmd/hg/contrib/hgwebdir.fcgi new file mode 100644 index 000000000..e014b98cb --- /dev/null +++ b/sys/src/cmd/hg/contrib/hgwebdir.fcgi @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# An example CGI script to export multiple hgweb repos, edit as necessary + +# adjust python path if not a system-wide install: +#import sys +#sys.path.insert(0, "/path/to/python/lib") + +# enable demandloading to reduce startup time +from mercurial import demandimport; demandimport.enable() + +# Uncomment to send python tracebacks to the browser if an error occurs: +#import cgitb +#cgitb.enable() + +# If you'd like to serve pages with UTF-8 instead of your default +# locale charset, you can do so by uncommenting the following lines. +# Note that this will cause your .hgrc files to be interpreted in +# UTF-8 and all your repo files to be displayed using UTF-8. +# +#import os +#os.environ["HGENCODING"] = "UTF-8" + +from mercurial.hgweb.hgwebdir_mod import hgwebdir +from flup.server.fcgi import WSGIServer + +# The config file looks like this. You can have paths to individual +# repos, collections of repos in a directory tree, or both. +# +# [paths] +# virtual/path1 = /real/path1 +# virtual/path2 = /real/path2 +# virtual/root = /real/root/* +# / = /real/root2/* +# +# [collections] +# /prefix/to/strip/off = /root/of/tree/full/of/repos +# +# paths example: +# +# * First two lines mount one repository into one virtual path, like +# '/real/path1' into 'virtual/path1'. +# +# * The third entry tells every mercurial repository found in +# '/real/root', recursively, should be mounted in 'virtual/root'. This +# format is preferred over the [collections] one, using absolute paths +# as configuration keys is not supported on every platform (including +# Windows). +# +# * The last entry is a special case mounting all repositories in +# '/real/root2' in the root of the virtual directory. +# +# collections example: say directory tree /foo contains repos /foo/bar, +# /foo/quux/baz. Give this config section: +# [collections] +# /foo = /foo +# Then repos will list as bar and quux/baz. +# +# Alternatively you can pass a list of ('virtual/path', '/real/path') tuples +# or use a dictionary with entries like 'virtual/path': '/real/path' + +WSGIServer(hgwebdir('hgweb.config')).run() diff --git a/sys/src/cmd/hg/contrib/hgwebdir.wsgi b/sys/src/cmd/hg/contrib/hgwebdir.wsgi new file mode 100644 index 000000000..64e09b2de --- /dev/null +++ b/sys/src/cmd/hg/contrib/hgwebdir.wsgi @@ -0,0 +1,51 @@ +# An example WSGI (use with mod_wsgi) script to export multiple hgweb repos + +# adjust python path if not a system-wide install: +#import sys +#sys.path.insert(0, "/path/to/python/lib") + +# enable demandloading to reduce startup time +from mercurial import demandimport; demandimport.enable() +from mercurial.hgweb.hgwebdir_mod import hgwebdir + +# If you'd like to serve pages with UTF-8 instead of your default +# locale charset, you can do so by uncommenting the following lines. +# Note that this will cause your .hgrc files to be interpreted in +# UTF-8 and all your repo files to be displayed using UTF-8. +# +#import os +#os.environ["HGENCODING"] = "UTF-8" + +# The config file looks like this. You can have paths to individual +# repos, collections of repos in a directory tree, or both. +# +# [paths] +# virtual/path1 = /real/path1 +# virtual/path2 = /real/path2 +# virtual/root = /real/root/* +# / = /real/root2/* +# +# paths example: +# +# * First two lines mount one repository into one virtual path, like +# '/real/path1' into 'virtual/path1'. +# +# * The third entry tells every mercurial repository found in +# '/real/root', recursively, should be mounted in 'virtual/root'. This +# format is preferred over the [collections] one, using absolute paths +# as configuration keys is not supported on every platform (including +# Windows). +# +# * The last entry is a special case mounting all repositories in +# '/real/root2' in the root of the virtual directory. +# +# collections example: say directory tree /foo contains repos /foo/bar, +# /foo/quux/baz. Give this config section: +# [collections] +# /foo = /foo +# Then repos will list as bar and quux/baz. +# +# Alternatively you can pass a list of ('virtual/path', '/real/path') tuples +# or use a dictionary with entries like 'virtual/path': '/real/path' + +application = hgwebdir('hgweb.config') diff --git a/sys/src/cmd/hg/contrib/logo-droplets.svg b/sys/src/cmd/hg/contrib/logo-droplets.svg new file mode 100644 index 000000000..01f412b36 --- /dev/null +++ b/sys/src/cmd/hg/contrib/logo-droplets.svg @@ -0,0 +1,624 @@ + + +image/svg+xmlMercurial "droplets" logoCali Mastny and Matt MackallFeb 12 2008 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sys/src/cmd/hg/contrib/macosx/Readme.html b/sys/src/cmd/hg/contrib/macosx/Readme.html new file mode 100644 index 000000000..eaeec76b7 --- /dev/null +++ b/sys/src/cmd/hg/contrib/macosx/Readme.html @@ -0,0 +1,37 @@ + + + + + + + + + + +

Before you install

+


+

This is an OS X 10.5 version of Mercurial that depends on the default Python 2.5 installation.

+


+

After you install

+


+

This package installs the hg executable in /usr/local/bin and the Mercurial files in /Library/Python/2.5/site-packages/mercurial.

+


+

Documentation

+


+

Visit the Mercurial web site and wiki

+


+

There's also a free book, Distributed revision control with Mercurial

+


+

Reporting problems

+


+

If you run into any problems, please file a bug online:

+

http://mercurial.selenic.com/bts/

+ + diff --git a/sys/src/cmd/hg/contrib/macosx/Welcome.html b/sys/src/cmd/hg/contrib/macosx/Welcome.html new file mode 100644 index 000000000..61ebabc72 --- /dev/null +++ b/sys/src/cmd/hg/contrib/macosx/Welcome.html @@ -0,0 +1,20 @@ + + + + + + + + + + +

This is a prepackaged release of Mercurial for Mac OS X.

+


+
+

+Please be sure to read the latest release notes.

+ + diff --git a/sys/src/cmd/hg/contrib/macosx/macosx-build.txt b/sys/src/cmd/hg/contrib/macosx/macosx-build.txt new file mode 100644 index 000000000..f67ca5332 --- /dev/null +++ b/sys/src/cmd/hg/contrib/macosx/macosx-build.txt @@ -0,0 +1,11 @@ +to build a new macosx binary package: + +install macpython from http://www.python.org/download/mac + +install py2app from http://pythonmac.org/packages/ + +make sure /usr/local/bin is in your path + +run bdist_mpkg in top-level hg directory + +find packaged stuff in dist directory diff --git a/sys/src/cmd/hg/contrib/mercurial.el b/sys/src/cmd/hg/contrib/mercurial.el new file mode 100644 index 000000000..182fc18c4 --- /dev/null +++ b/sys/src/cmd/hg/contrib/mercurial.el @@ -0,0 +1,1294 @@ +;;; mercurial.el --- Emacs support for the Mercurial distributed SCM + +;; Copyright (C) 2005, 2006 Bryan O'Sullivan + +;; Author: Bryan O'Sullivan + +;; mercurial.el is free software; you can redistribute it and/or +;; modify it under the terms of version 2 of the GNU General Public +;; License as published by the Free Software Foundation. + +;; mercurial.el is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mercurial.el, GNU Emacs, or XEmacs; see the file COPYING +;; (`C-h C-l'). If not, write to the Free Software Foundation, Inc., +;; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; mercurial.el builds upon Emacs's VC mode to provide flexible +;; integration with the Mercurial distributed SCM tool. + +;; To get going as quickly as possible, load mercurial.el into Emacs and +;; type `C-c h h'; this runs hg-help-overview, which prints a helpful +;; usage overview. + +;; Much of the inspiration for mercurial.el comes from Rajesh +;; Vaidheeswarran's excellent p4.el, which does an admirably thorough +;; job for the commercial Perforce SCM product. In fact, substantial +;; chunks of code are adapted from p4.el. + +;; This code has been developed under XEmacs 21.5, and may not work as +;; well under GNU Emacs (albeit tested under 21.4). Patches to +;; enhance the portability of this code, fix bugs, and add features +;; are most welcome. + +;; As of version 22.3, GNU Emacs's VC mode has direct support for +;; Mercurial, so this package may not prove as useful there. + +;; Please send problem reports and suggestions to bos@serpentine.com. + + +;;; Code: + +(eval-when-compile (require 'cl)) +(require 'diff-mode) +(require 'easymenu) +(require 'executable) +(require 'vc) + +(defmacro hg-feature-cond (&rest clauses) + "Test CLAUSES for feature at compile time. +Each clause is (FEATURE BODY...)." + (dolist (x clauses) + (let ((feature (car x)) + (body (cdr x))) + (when (or (eq feature t) + (featurep feature)) + (return (cons 'progn body)))))) + + +;;; XEmacs has view-less, while GNU Emacs has view. Joy. + +(hg-feature-cond + (xemacs (require 'view-less)) + (t (require 'view))) + + +;;; Variables accessible through the custom system. + +(defgroup mercurial nil + "Mercurial distributed SCM." + :group 'tools) + +(defcustom hg-binary + (or (executable-find "hg") + (dolist (path '("~/bin/hg" "/usr/bin/hg" "/usr/local/bin/hg")) + (when (file-executable-p path) + (return path)))) + "The path to Mercurial's hg executable." + :type '(file :must-match t) + :group 'mercurial) + +(defcustom hg-mode-hook nil + "Hook run when a buffer enters hg-mode." + :type 'sexp + :group 'mercurial) + +(defcustom hg-commit-mode-hook nil + "Hook run when a buffer is created to prepare a commit." + :type 'sexp + :group 'mercurial) + +(defcustom hg-pre-commit-hook nil + "Hook run before a commit is performed. +If you want to prevent the commit from proceeding, raise an error." + :type 'sexp + :group 'mercurial) + +(defcustom hg-log-mode-hook nil + "Hook run after a buffer is filled with log information." + :type 'sexp + :group 'mercurial) + +(defcustom hg-global-prefix "\C-ch" + "The global prefix for Mercurial keymap bindings." + :type 'sexp + :group 'mercurial) + +(defcustom hg-commit-allow-empty-message nil + "Whether to allow changes to be committed with empty descriptions." + :type 'boolean + :group 'mercurial) + +(defcustom hg-commit-allow-empty-file-list nil + "Whether to allow changes to be committed without any modified files." + :type 'boolean + :group 'mercurial) + +(defcustom hg-rev-completion-limit 100 + "The maximum number of revisions that hg-read-rev will offer to complete. +This affects memory usage and performance when prompting for revisions +in a repository with a lot of history." + :type 'integer + :group 'mercurial) + +(defcustom hg-log-limit 50 + "The maximum number of revisions that hg-log will display." + :type 'integer + :group 'mercurial) + +(defcustom hg-update-modeline t + "Whether to update the modeline with the status of a file after every save. +Set this to nil on platforms with poor process management, such as Windows." + :type 'boolean + :group 'mercurial) + +(defcustom hg-incoming-repository "default" + "The repository from which changes are pulled from by default. +This should be a symbolic repository name, since it is used for all +repository-related commands." + :type 'string + :group 'mercurial) + +(defcustom hg-outgoing-repository "default-push" + "The repository to which changes are pushed to by default. +This should be a symbolic repository name, since it is used for all +repository-related commands." + :type 'string + :group 'mercurial) + + +;;; Other variables. + +(defvar hg-mode nil + "Is this file managed by Mercurial?") +(make-variable-buffer-local 'hg-mode) +(put 'hg-mode 'permanent-local t) + +(defvar hg-status nil) +(make-variable-buffer-local 'hg-status) +(put 'hg-status 'permanent-local t) + +(defvar hg-prev-buffer nil) +(make-variable-buffer-local 'hg-prev-buffer) +(put 'hg-prev-buffer 'permanent-local t) + +(defvar hg-root nil) +(make-variable-buffer-local 'hg-root) +(put 'hg-root 'permanent-local t) + +(defvar hg-view-mode nil) +(make-variable-buffer-local 'hg-view-mode) +(put 'hg-view-mode 'permanent-local t) + +(defvar hg-view-file-name nil) +(make-variable-buffer-local 'hg-view-file-name) +(put 'hg-view-file-name 'permanent-local t) + +(defvar hg-output-buffer-name "*Hg*" + "The name to use for Mercurial output buffers.") + +(defvar hg-file-history nil) +(defvar hg-repo-history nil) +(defvar hg-rev-history nil) +(defvar hg-repo-completion-table nil) ; shut up warnings + + +;;; Random constants. + +(defconst hg-commit-message-start + "--- Enter your commit message. Type `C-c C-c' to commit. ---\n") + +(defconst hg-commit-message-end + "--- Files in bold will be committed. Click to toggle selection. ---\n") + +(defconst hg-state-alist + '((?M . modified) + (?A . added) + (?R . removed) + (?! . deleted) + (?C . normal) + (?I . ignored) + (?? . nil))) + +;;; hg-mode keymap. + +(defvar hg-prefix-map + (let ((map (make-sparse-keymap))) + (hg-feature-cond (xemacs (set-keymap-name map 'hg-prefix-map))) ; XEmacs + (set-keymap-parent map vc-prefix-map) + (define-key map "=" 'hg-diff) + (define-key map "c" 'hg-undo) + (define-key map "g" 'hg-annotate) + (define-key map "i" 'hg-add) + (define-key map "l" 'hg-log) + (define-key map "n" 'hg-commit-start) + ;; (define-key map "r" 'hg-update) + (define-key map "u" 'hg-revert-buffer) + (define-key map "~" 'hg-version-other-window) + map) + "This keymap overrides some default vc-mode bindings.") + +(defvar hg-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-xv" hg-prefix-map) + map)) + +(add-minor-mode 'hg-mode 'hg-mode hg-mode-map) + + +;;; Global keymap. + +(defvar hg-global-map + (let ((map (make-sparse-keymap))) + (define-key map "," 'hg-incoming) + (define-key map "." 'hg-outgoing) + (define-key map "<" 'hg-pull) + (define-key map "=" 'hg-diff-repo) + (define-key map ">" 'hg-push) + (define-key map "?" 'hg-help-overview) + (define-key map "A" 'hg-addremove) + (define-key map "U" 'hg-revert) + (define-key map "a" 'hg-add) + (define-key map "c" 'hg-commit-start) + (define-key map "f" 'hg-forget) + (define-key map "h" 'hg-help-overview) + (define-key map "i" 'hg-init) + (define-key map "l" 'hg-log-repo) + (define-key map "r" 'hg-root) + (define-key map "s" 'hg-status) + (define-key map "u" 'hg-update) + map)) + +(global-set-key hg-global-prefix hg-global-map) + +;;; View mode keymap. + +(defvar hg-view-mode-map + (let ((map (make-sparse-keymap))) + (hg-feature-cond (xemacs (set-keymap-name map 'hg-view-mode-map))) ; XEmacs + (define-key map (hg-feature-cond (xemacs [button2]) + (t [mouse-2])) + 'hg-buffer-mouse-clicked) + map)) + +(add-minor-mode 'hg-view-mode "" hg-view-mode-map) + + +;;; Commit mode keymaps. + +(defvar hg-commit-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-c" 'hg-commit-finish) + (define-key map "\C-c\C-k" 'hg-commit-kill) + (define-key map "\C-xv=" 'hg-diff-repo) + map)) + +(defvar hg-commit-mode-file-map + (let ((map (make-sparse-keymap))) + (define-key map (hg-feature-cond (xemacs [button2]) + (t [mouse-2])) + 'hg-commit-mouse-clicked) + (define-key map " " 'hg-commit-toggle-file) + (define-key map "\r" 'hg-commit-toggle-file) + map)) + + +;;; Convenience functions. + +(defsubst hg-binary () + (if hg-binary + hg-binary + (error "No `hg' executable found!"))) + +(defsubst hg-replace-in-string (str regexp newtext &optional literal) + "Replace all matches in STR for REGEXP with NEWTEXT string. +Return the new string. Optional LITERAL non-nil means do a literal +replacement. + +This function bridges yet another pointless impedance gap between +XEmacs and GNU Emacs." + (hg-feature-cond + (xemacs (replace-in-string str regexp newtext literal)) + (t (replace-regexp-in-string regexp newtext str nil literal)))) + +(defsubst hg-strip (str) + "Strip leading and trailing blank lines from a string." + (hg-replace-in-string (hg-replace-in-string str "[\r\n][ \t\r\n]*\\'" "") + "\\`[ \t\r\n]*[\r\n]" "")) + +(defsubst hg-chomp (str) + "Strip trailing newlines from a string." + (hg-replace-in-string str "[\r\n]+\\'" "")) + +(defun hg-run-command (command &rest args) + "Run the shell command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT). +The list ARGS contains a list of arguments to pass to the command." + (let* (exit-code + (output + (with-output-to-string + (with-current-buffer + standard-output + (setq exit-code + (apply 'call-process command nil t nil args)))))) + (cons exit-code output))) + +(defun hg-run (command &rest args) + "Run the Mercurial command COMMAND, returning (EXIT-CODE . COMMAND-OUTPUT)." + (apply 'hg-run-command (hg-binary) command args)) + +(defun hg-run0 (command &rest args) + "Run the Mercurial command COMMAND, returning its output. +If the command does not exit with a zero status code, raise an error." + (let ((res (apply 'hg-run-command (hg-binary) command args))) + (if (not (eq (car res) 0)) + (error "Mercurial command failed %s - exit code %s" + (cons command args) + (car res)) + (cdr res)))) + +(defmacro hg-do-across-repo (path &rest body) + (let ((root-name (make-symbol "root-")) + (buf-name (make-symbol "buf-"))) + `(let ((,root-name (hg-root ,path))) + (save-excursion + (dolist (,buf-name (buffer-list)) + (set-buffer ,buf-name) + (when (and hg-status (equal (hg-root buffer-file-name) ,root-name)) + ,@body)))))) + +(put 'hg-do-across-repo 'lisp-indent-function 1) + +(defun hg-sync-buffers (path) + "Sync buffers visiting PATH with their on-disk copies. +If PATH is not being visited, but is under the repository root, sync +all buffers visiting files in the repository." + (let ((buf (find-buffer-visiting path))) + (if buf + (with-current-buffer buf + (vc-buffer-sync)) + (hg-do-across-repo path + (vc-buffer-sync))))) + +(defun hg-buffer-commands (pnt) + "Use the properties of a character to do something sensible." + (interactive "d") + (let ((rev (get-char-property pnt 'rev)) + (file (get-char-property pnt 'file))) + (cond + (file + (find-file-other-window file)) + (rev + (hg-diff hg-view-file-name rev rev)) + ((message "I don't know how to do that yet"))))) + +(defsubst hg-event-point (event) + "Return the character position of the mouse event EVENT." + (hg-feature-cond (xemacs (event-point event)) + (t (posn-point (event-start event))))) + +(defsubst hg-event-window (event) + "Return the window over which mouse event EVENT occurred." + (hg-feature-cond (xemacs (event-window event)) + (t (posn-window (event-start event))))) + +(defun hg-buffer-mouse-clicked (event) + "Translate the mouse clicks in a HG log buffer to character events. +These are then handed off to `hg-buffer-commands'. + +Handle frickin' frackin' gratuitous event-related incompatibilities." + (interactive "e") + (select-window (hg-event-window event)) + (hg-buffer-commands (hg-event-point event))) + +(defsubst hg-abbrev-file-name (file) + "Portable wrapper around abbreviate-file-name." + (hg-feature-cond (xemacs (abbreviate-file-name file t)) + (t (abbreviate-file-name file)))) + +(defun hg-read-file-name (&optional prompt default) + "Read a file or directory name, or a pattern, to use with a command." + (save-excursion + (while hg-prev-buffer + (set-buffer hg-prev-buffer)) + (let ((path (or default + (buffer-file-name) + (expand-file-name default-directory)))) + (if (or (not path) current-prefix-arg) + (expand-file-name + (eval (list* 'read-file-name + (format "File, directory or pattern%s: " + (or prompt "")) + (and path (file-name-directory path)) + nil nil + (and path (file-name-nondirectory path)) + (hg-feature-cond + (xemacs (cons (quote 'hg-file-history) nil)) + (t nil))))) + path)))) + +(defun hg-read-number (&optional prompt default) + "Read a integer value." + (save-excursion + (if (or (not default) current-prefix-arg) + (string-to-number + (eval (list* 'read-string + (or prompt "") + (if default (cons (format "%d" default) nil) nil)))) + default))) + +(defun hg-read-config () + "Return an alist of (key . value) pairs of Mercurial config data. +Each key is of the form (section . name)." + (let (items) + (dolist (line (split-string (hg-chomp (hg-run0 "debugconfig")) "\n") items) + (string-match "^\\([^=]*\\)=\\(.*\\)" line) + (let* ((left (substring line (match-beginning 1) (match-end 1))) + (right (substring line (match-beginning 2) (match-end 2))) + (key (split-string left "\\.")) + (value (hg-replace-in-string right "\\\\n" "\n" t))) + (setq items (cons (cons (cons (car key) (cadr key)) value) items)))))) + +(defun hg-config-section (section config) + "Return an alist of (name . value) pairs for SECTION of CONFIG." + (let (items) + (dolist (item config items) + (when (equal (caar item) section) + (setq items (cons (cons (cdar item) (cdr item)) items)))))) + +(defun hg-string-starts-with (sub str) + "Indicate whether string STR starts with the substring or character SUB." + (if (not (stringp sub)) + (and (> (length str) 0) (equal (elt str 0) sub)) + (let ((sub-len (length sub))) + (and (<= sub-len (length str)) + (string= sub (substring str 0 sub-len)))))) + +(defun hg-complete-repo (string predicate all) + "Attempt to complete a repository name. +We complete on either symbolic names from Mercurial's config or real +directory names from the file system. We do not penalise URLs." + (or (if all + (all-completions string hg-repo-completion-table predicate) + (try-completion string hg-repo-completion-table predicate)) + (let* ((str (expand-file-name string)) + (dir (file-name-directory str)) + (file (file-name-nondirectory str))) + (if all + (let (completions) + (dolist (name (delete "./" (file-name-all-completions file dir)) + completions) + (let ((path (concat dir name))) + (when (file-directory-p path) + (setq completions (cons name completions)))))) + (let ((comp (file-name-completion file dir))) + (if comp + (hg-abbrev-file-name (concat dir comp)))))))) + +(defun hg-read-repo-name (&optional prompt initial-contents default) + "Read the location of a repository." + (save-excursion + (while hg-prev-buffer + (set-buffer hg-prev-buffer)) + (let (hg-repo-completion-table) + (if current-prefix-arg + (progn + (dolist (path (hg-config-section "paths" (hg-read-config))) + (setq hg-repo-completion-table + (cons (cons (car path) t) hg-repo-completion-table)) + (unless (hg-string-starts-with (hg-feature-cond + (xemacs directory-sep-char) + (t ?/)) + (cdr path)) + (setq hg-repo-completion-table + (cons (cons (cdr path) t) hg-repo-completion-table)))) + (completing-read (format "Repository%s: " (or prompt "")) + 'hg-complete-repo + nil + nil + initial-contents + 'hg-repo-history + default)) + default)))) + +(defun hg-read-rev (&optional prompt default) + "Read a revision or tag, offering completions." + (save-excursion + (while hg-prev-buffer + (set-buffer hg-prev-buffer)) + (let ((rev (or default "tip"))) + (if current-prefix-arg + (let ((revs (split-string + (hg-chomp + (hg-run0 "-q" "log" "-l" + (format "%d" hg-rev-completion-limit))) + "[\n:]"))) + (dolist (line (split-string (hg-chomp (hg-run0 "tags")) "\n")) + (setq revs (cons (car (split-string line "\\s-")) revs))) + (completing-read (format "Revision%s (%s): " + (or prompt "") + (or default "tip")) + (mapcar (lambda (x) (cons x x)) revs) + nil + nil + nil + 'hg-rev-history + (or default "tip"))) + rev)))) + +(defun hg-parents-for-mode-line (root) + "Format the parents of the working directory for the mode line." + (let ((parents (split-string (hg-chomp + (hg-run0 "--cwd" root "parents" "--template" + "{rev}\n")) "\n"))) + (mapconcat 'identity parents "+"))) + +(defun hg-buffers-visiting-repo (&optional path) + "Return a list of buffers visiting the repository containing PATH." + (let ((root-name (hg-root (or path (buffer-file-name)))) + bufs) + (save-excursion + (dolist (buf (buffer-list) bufs) + (set-buffer buf) + (let ((name (buffer-file-name))) + (when (and hg-status name (equal (hg-root name) root-name)) + (setq bufs (cons buf bufs)))))))) + +(defun hg-update-mode-lines (path) + "Update the mode lines of all buffers visiting the same repository as PATH." + (let* ((root (hg-root path)) + (parents (hg-parents-for-mode-line root))) + (save-excursion + (dolist (info (hg-path-status + root + (mapcar + (function + (lambda (buf) + (substring (buffer-file-name buf) (length root)))) + (hg-buffers-visiting-repo root)))) + (let* ((name (car info)) + (status (cdr info)) + (buf (find-buffer-visiting (concat root name)))) + (when buf + (set-buffer buf) + (hg-mode-line-internal status parents))))))) + + +;;; View mode bits. + +(defun hg-exit-view-mode (buf) + "Exit from hg-view-mode. +We delete the current window if entering hg-view-mode split the +current frame." + (when (and (eq buf (current-buffer)) + (> (length (window-list)) 1)) + (delete-window)) + (when (buffer-live-p buf) + (kill-buffer buf))) + +(defun hg-view-mode (prev-buffer &optional file-name) + (goto-char (point-min)) + (set-buffer-modified-p nil) + (toggle-read-only t) + (hg-feature-cond (xemacs (view-minor-mode prev-buffer 'hg-exit-view-mode)) + (t (view-mode-enter nil 'hg-exit-view-mode))) + (setq hg-view-mode t) + (setq truncate-lines t) + (when file-name + (setq hg-view-file-name + (hg-abbrev-file-name file-name)))) + +(defun hg-file-status (file) + "Return status of FILE, or nil if FILE does not exist or is unmanaged." + (let* ((s (hg-run "status" file)) + (exit (car s)) + (output (cdr s))) + (if (= exit 0) + (let ((state (and (>= (length output) 2) + (= (aref output 1) ? ) + (assq (aref output 0) hg-state-alist)))) + (if state + (cdr state) + 'normal))))) + +(defun hg-path-status (root paths) + "Return status of PATHS in repo ROOT as an alist. +Each entry is a pair (FILE-NAME . STATUS)." + (let ((s (apply 'hg-run "--cwd" root "status" "-marduc" paths)) + result) + (dolist (entry (split-string (hg-chomp (cdr s)) "\n") (nreverse result)) + (let (state name) + (cond ((= (aref entry 1) ? ) + (setq state (assq (aref entry 0) hg-state-alist) + name (substring entry 2))) + ((string-match "\\(.*\\): " entry) + (setq name (match-string 1 entry)))) + (setq result (cons (cons name state) result)))))) + +(defmacro hg-view-output (args &rest body) + "Execute BODY in a clean buffer, then quickly display that buffer. +If the buffer contains one line, its contents are displayed in the +minibuffer. Otherwise, the buffer is displayed in view-mode. +ARGS is of the form (BUFFER-NAME &optional FILE), where BUFFER-NAME is +the name of the buffer to create, and FILE is the name of the file +being viewed." + (let ((prev-buf (make-symbol "prev-buf-")) + (v-b-name (car args)) + (v-m-rest (cdr args))) + `(let ((view-buf-name ,v-b-name) + (,prev-buf (current-buffer))) + (get-buffer-create view-buf-name) + (kill-buffer view-buf-name) + (get-buffer-create view-buf-name) + (set-buffer view-buf-name) + (save-excursion + ,@body) + (case (count-lines (point-min) (point-max)) + ((0) + (kill-buffer view-buf-name) + (message "(No output)")) + ((1) + (let ((msg (hg-chomp (buffer-substring (point-min) (point-max))))) + (kill-buffer view-buf-name) + (message "%s" msg))) + (t + (pop-to-buffer view-buf-name) + (setq hg-prev-buffer ,prev-buf) + (hg-view-mode ,prev-buf ,@v-m-rest)))))) + +(put 'hg-view-output 'lisp-indent-function 1) + +;;; Context save and restore across revert and other operations. + +(defun hg-position-context (pos) + "Return information to help find the given position again." + (let* ((end (min (point-max) (+ pos 98)))) + (list pos + (buffer-substring (max (point-min) (- pos 2)) end) + (- end pos)))) + +(defun hg-buffer-context () + "Return information to help restore a user's editing context. +This is useful across reverts and merges, where a context is likely +to have moved a little, but not really changed." + (let ((point-context (hg-position-context (point))) + (mark-context (let ((mark (mark-marker))) + (and mark + ;; make sure active mark + (marker-buffer mark) + (marker-position mark) + (hg-position-context mark))))) + (list point-context mark-context))) + +(defun hg-find-context (ctx) + "Attempt to find a context in the given buffer. +Always returns a valid, hopefully sane, position." + (let ((pos (nth 0 ctx)) + (str (nth 1 ctx)) + (fixup (nth 2 ctx))) + (save-excursion + (goto-char (max (point-min) (- pos 15000))) + (if (and (not (equal str "")) + (search-forward str nil t)) + (- (point) fixup) + (max pos (point-min)))))) + +(defun hg-restore-context (ctx) + "Attempt to restore the user's editing context." + (let ((point-context (nth 0 ctx)) + (mark-context (nth 1 ctx))) + (goto-char (hg-find-context point-context)) + (when mark-context + (set-mark (hg-find-context mark-context))))) + + +;;; Hooks. + +(defun hg-mode-line-internal (status parents) + (setq hg-status status + hg-mode (and status (concat " Hg:" + parents + (cdr (assq status + '((normal . "") + (removed . "r") + (added . "a") + (deleted . "!") + (modified . "m")))))))) + +(defun hg-mode-line (&optional force) + "Update the modeline with the current status of a file. +An update occurs if optional argument FORCE is non-nil, +hg-update-modeline is non-nil, or we have not yet checked the state of +the file." + (let ((root (hg-root))) + (when (and root (or force hg-update-modeline (not hg-mode))) + (let ((status (hg-file-status buffer-file-name)) + (parents (hg-parents-for-mode-line root))) + (hg-mode-line-internal status parents) + status)))) + +(defun hg-mode (&optional toggle) + "Minor mode for Mercurial distributed SCM integration. + +The Mercurial mode user interface is based on that of VC mode, so if +you're already familiar with VC, the same keybindings and functions +will generally work. + +Below is a list of many common SCM tasks. In the list, `G/L\' +indicates whether a key binding is global (G) to a repository or +local (L) to a file. Many commands take a prefix argument. + +SCM Task G/L Key Binding Command Name +-------- --- ----------- ------------ +Help overview (what you are reading) G C-c h h hg-help-overview + +Tell Mercurial to manage a file G C-c h a hg-add +Commit changes to current file only L C-x v n hg-commit-start +Undo changes to file since commit L C-x v u hg-revert-buffer + +Diff file vs last checkin L C-x v = hg-diff + +View file change history L C-x v l hg-log +View annotated file L C-x v a hg-annotate + +Diff repo vs last checkin G C-c h = hg-diff-repo +View status of files in repo G C-c h s hg-status +Commit all changes G C-c h c hg-commit-start + +Undo all changes since last commit G C-c h U hg-revert +View repo change history G C-c h l hg-log-repo + +See changes that can be pulled G C-c h , hg-incoming +Pull changes G C-c h < hg-pull +Update working directory after pull G C-c h u hg-update +See changes that can be pushed G C-c h . hg-outgoing +Push changes G C-c h > hg-push" + (unless vc-make-backup-files + (set (make-local-variable 'backup-inhibited) t)) + (run-hooks 'hg-mode-hook)) + +(defun hg-find-file-hook () + (ignore-errors + (when (hg-mode-line) + (hg-mode)))) + +(add-hook 'find-file-hooks 'hg-find-file-hook) + +(defun hg-after-save-hook () + (ignore-errors + (let ((old-status hg-status)) + (hg-mode-line) + (if (and (not old-status) hg-status) + (hg-mode))))) + +(add-hook 'after-save-hook 'hg-after-save-hook) + + +;;; User interface functions. + +(defun hg-help-overview () + "This is an overview of the Mercurial SCM mode for Emacs. + +You can find the source code, license (GPL v2), and credits for this +code by typing `M-x find-library mercurial RET'." + (interactive) + (hg-view-output ("Mercurial Help Overview") + (insert (documentation 'hg-help-overview)) + (let ((pos (point))) + (insert (documentation 'hg-mode)) + (goto-char pos) + (end-of-line 1) + (delete-region pos (point))) + (let ((hg-root-dir (hg-root))) + (if (not hg-root-dir) + (error "error: %s: directory is not part of a Mercurial repository." + default-directory) + (cd hg-root-dir))))) + +(defun hg-fix-paths () + "Fix paths reported by some Mercurial commands." + (save-excursion + (goto-char (point-min)) + (while (re-search-forward " \\.\\.." nil t) + (replace-match " " nil nil)))) + +(defun hg-add (path) + "Add PATH to the Mercurial repository on the next commit. +With a prefix argument, prompt for the path to add." + (interactive (list (hg-read-file-name " to add"))) + (let ((buf (current-buffer)) + (update (equal buffer-file-name path))) + (hg-view-output (hg-output-buffer-name) + (apply 'call-process (hg-binary) nil t nil (list "add" path)) + (hg-fix-paths) + (goto-char (point-min)) + (cd (hg-root path))) + (when update + (unless vc-make-backup-files + (set (make-local-variable 'backup-inhibited) t)) + (with-current-buffer buf + (hg-mode-line))))) + +(defun hg-addremove () + (interactive) + (error "not implemented")) + +(defun hg-annotate () + (interactive) + (error "not implemented")) + +(defun hg-commit-toggle-file (pos) + "Toggle whether or not the file at POS will be committed." + (interactive "d") + (save-excursion + (goto-char pos) + (let (face + (inhibit-read-only t) + bol) + (beginning-of-line) + (setq bol (+ (point) 4)) + (setq face (get-text-property bol 'face)) + (end-of-line) + (if (eq face 'bold) + (progn + (remove-text-properties bol (point) '(face nil)) + (message "%s will not be committed" + (buffer-substring bol (point)))) + (add-text-properties bol (point) '(face bold)) + (message "%s will be committed" + (buffer-substring bol (point))))))) + +(defun hg-commit-mouse-clicked (event) + "Toggle whether or not the file at POS will be committed." + (interactive "@e") + (hg-commit-toggle-file (hg-event-point event))) + +(defun hg-commit-kill () + "Kill the commit currently being prepared." + (interactive) + (when (or (not (buffer-modified-p)) (y-or-n-p "Really kill this commit? ")) + (let ((buf hg-prev-buffer)) + (kill-buffer nil) + (switch-to-buffer buf)))) + +(defun hg-commit-finish () + "Finish preparing a commit, and perform the actual commit. +The hook hg-pre-commit-hook is run before anything else is done. If +the commit message is empty and hg-commit-allow-empty-message is nil, +an error is raised. If the list of files to commit is empty and +hg-commit-allow-empty-file-list is nil, an error is raised." + (interactive) + (let ((root hg-root)) + (save-excursion + (run-hooks 'hg-pre-commit-hook) + (goto-char (point-min)) + (search-forward hg-commit-message-start) + (let (message files) + (let ((start (point))) + (goto-char (point-max)) + (search-backward hg-commit-message-end) + (setq message (hg-strip (buffer-substring start (point))))) + (when (and (= (length message) 0) + (not hg-commit-allow-empty-message)) + (error "Cannot proceed - commit message is empty")) + (forward-line 1) + (beginning-of-line) + (while (< (point) (point-max)) + (let ((pos (+ (point) 4))) + (end-of-line) + (when (eq (get-text-property pos 'face) 'bold) + (end-of-line) + (setq files (cons (buffer-substring pos (point)) files)))) + (forward-line 1)) + (when (and (= (length files) 0) + (not hg-commit-allow-empty-file-list)) + (error "Cannot proceed - no files to commit")) + (setq message (concat message "\n")) + (apply 'hg-run0 "--cwd" hg-root "commit" "-m" message files)) + (let ((buf hg-prev-buffer)) + (kill-buffer nil) + (switch-to-buffer buf)) + (hg-update-mode-lines root)))) + +(defun hg-commit-mode () + "Mode for describing a commit of changes to a Mercurial repository. +This involves two actions: describing the changes with a commit +message, and choosing the files to commit. + +To describe the commit, simply type some text in the designated area. + +By default, all modified, added and removed files are selected for +committing. Files that will be committed are displayed in bold face\; +those that will not are displayed in normal face. + +To toggle whether a file will be committed, move the cursor over a +particular file and hit space or return. Alternatively, middle click +on the file. + +Key bindings +------------ +\\[hg-commit-finish] proceed with commit +\\[hg-commit-kill] kill commit + +\\[hg-diff-repo] view diff of pending changes" + (interactive) + (use-local-map hg-commit-mode-map) + (set-syntax-table text-mode-syntax-table) + (setq local-abbrev-table text-mode-abbrev-table + major-mode 'hg-commit-mode + mode-name "Hg-Commit") + (set-buffer-modified-p nil) + (setq buffer-undo-list nil) + (run-hooks 'text-mode-hook 'hg-commit-mode-hook)) + +(defun hg-commit-start () + "Prepare a commit of changes to the repository containing the current file." + (interactive) + (while hg-prev-buffer + (set-buffer hg-prev-buffer)) + (let ((root (hg-root)) + (prev-buffer (current-buffer)) + modified-files) + (unless root + (error "Cannot commit outside a repository!")) + (hg-sync-buffers root) + (setq modified-files (hg-chomp (hg-run0 "--cwd" root "status" "-arm"))) + (when (and (= (length modified-files) 0) + (not hg-commit-allow-empty-file-list)) + (error "No pending changes to commit")) + (let* ((buf-name (format "*Mercurial: Commit %s*" root))) + (pop-to-buffer (get-buffer-create buf-name)) + (when (= (point-min) (point-max)) + (set (make-local-variable 'hg-root) root) + (setq hg-prev-buffer prev-buffer) + (insert "\n") + (let ((bol (point))) + (insert hg-commit-message-end) + (add-text-properties bol (point) '(face bold-italic))) + (let ((file-area (point))) + (insert modified-files) + (goto-char file-area) + (while (< (point) (point-max)) + (let ((bol (point))) + (forward-char 1) + (insert " ") + (end-of-line) + (add-text-properties (+ bol 4) (point) + '(face bold mouse-face highlight))) + (forward-line 1)) + (goto-char file-area) + (add-text-properties (point) (point-max) + `(keymap ,hg-commit-mode-file-map)) + (goto-char (point-min)) + (insert hg-commit-message-start) + (add-text-properties (point-min) (point) '(face bold-italic)) + (insert "\n\n") + (forward-line -1) + (save-excursion + (goto-char (point-max)) + (search-backward hg-commit-message-end) + (add-text-properties (match-beginning 0) (point-max) + '(read-only t)) + (goto-char (point-min)) + (search-forward hg-commit-message-start) + (add-text-properties (match-beginning 0) (match-end 0) + '(read-only t))) + (hg-commit-mode) + (cd root)))))) + +(defun hg-diff (path &optional rev1 rev2) + "Show the differences between REV1 and REV2 of PATH. +When called interactively, the default behaviour is to treat REV1 as +the \"parent\" revision, REV2 as the current edited version of the file, and +PATH as the file edited in the current buffer. +With a prefix argument, prompt for all of these." + (interactive (list (hg-read-file-name " to diff") + (let ((rev1 (hg-read-rev " to start with" 'parent))) + (and (not (eq rev1 'parent)) rev1)) + (let ((rev2 (hg-read-rev " to end with" 'working-dir))) + (and (not (eq rev2 'working-dir)) rev2)))) + (hg-sync-buffers path) + (let ((a-path (hg-abbrev-file-name path)) + ;; none revision is specified explicitly + (none (and (not rev1) (not rev2))) + ;; only one revision is specified explicitly + (one (or (and (or (equal rev1 rev2) (not rev2)) rev1) + (and (not rev1) rev2))) + diff) + (hg-view-output ((cond + (none + (format "Mercurial: Diff against parent of %s" a-path)) + (one + (format "Mercurial: Diff of rev %s of %s" one a-path)) + (t + (format "Mercurial: Diff from rev %s to %s of %s" + rev1 rev2 a-path)))) + (cond + (none + (call-process (hg-binary) nil t nil "diff" path)) + (one + (call-process (hg-binary) nil t nil "diff" "-r" one path)) + (t + (call-process (hg-binary) nil t nil "diff" "-r" rev1 "-r" rev2 path))) + (diff-mode) + (setq diff (not (= (point-min) (point-max)))) + (font-lock-fontify-buffer) + (cd (hg-root path))) + diff)) + +(defun hg-diff-repo (path &optional rev1 rev2) + "Show the differences between REV1 and REV2 of repository containing PATH. +When called interactively, the default behaviour is to treat REV1 as +the \"parent\" revision, REV2 as the current edited version of the file, and +PATH as the `hg-root' of the current buffer. +With a prefix argument, prompt for all of these." + (interactive (list (hg-read-file-name " to diff") + (let ((rev1 (hg-read-rev " to start with" 'parent))) + (and (not (eq rev1 'parent)) rev1)) + (let ((rev2 (hg-read-rev " to end with" 'working-dir))) + (and (not (eq rev2 'working-dir)) rev2)))) + (hg-diff (hg-root path) rev1 rev2)) + +(defun hg-forget (path) + "Lose track of PATH, which has been added, but not yet committed. +This will prevent the file from being incorporated into the Mercurial +repository on the next commit. +With a prefix argument, prompt for the path to forget." + (interactive (list (hg-read-file-name " to forget"))) + (let ((buf (current-buffer)) + (update (equal buffer-file-name path))) + (hg-view-output (hg-output-buffer-name) + (apply 'call-process (hg-binary) nil t nil (list "forget" path)) + ;; "hg forget" shows pathes relative NOT TO ROOT BUT TO REPOSITORY + (hg-fix-paths) + (goto-char (point-min)) + (cd (hg-root path))) + (when update + (with-current-buffer buf + (when (local-variable-p 'backup-inhibited) + (kill-local-variable 'backup-inhibited)) + (hg-mode-line))))) + +(defun hg-incoming (&optional repo) + "Display changesets present in REPO that are not present locally." + (interactive (list (hg-read-repo-name " where changes would come from"))) + (hg-view-output ((format "Mercurial: Incoming from %s to %s" + (hg-abbrev-file-name (hg-root)) + (hg-abbrev-file-name + (or repo hg-incoming-repository)))) + (call-process (hg-binary) nil t nil "incoming" + (or repo hg-incoming-repository)) + (hg-log-mode) + (cd (hg-root)))) + +(defun hg-init () + (interactive) + (error "not implemented")) + +(defun hg-log-mode () + "Mode for viewing a Mercurial change log." + (goto-char (point-min)) + (when (looking-at "^searching for changes.*$") + (delete-region (match-beginning 0) (match-end 0))) + (run-hooks 'hg-log-mode-hook)) + +(defun hg-log (path &optional rev1 rev2 log-limit) + "Display the revision history of PATH. +History is displayed between REV1 and REV2. +Number of displayed changesets is limited to LOG-LIMIT. +REV1 defaults to the tip, while REV2 defaults to 0. +LOG-LIMIT defaults to `hg-log-limit'. +With a prefix argument, prompt for each parameter." + (interactive (list (hg-read-file-name " to log") + (hg-read-rev " to start with" + "tip") + (hg-read-rev " to end with" + "0") + (hg-read-number "Output limited to: " + hg-log-limit))) + (let ((a-path (hg-abbrev-file-name path)) + (r1 (or rev1 "tip")) + (r2 (or rev2 "0")) + (limit (format "%d" (or log-limit hg-log-limit)))) + (hg-view-output ((if (equal r1 r2) + (format "Mercurial: Log of rev %s of %s" rev1 a-path) + (format + "Mercurial: at most %s log(s) from rev %s to %s of %s" + limit r1 r2 a-path))) + (eval (list* 'call-process (hg-binary) nil t nil + "log" + "-r" (format "%s:%s" r1 r2) + "-l" limit + (if (> (length path) (length (hg-root path))) + (cons path nil) + nil))) + (hg-log-mode) + (cd (hg-root path))))) + +(defun hg-log-repo (path &optional rev1 rev2 log-limit) + "Display the revision history of the repository containing PATH. +History is displayed between REV1 and REV2. +Number of displayed changesets is limited to LOG-LIMIT, +REV1 defaults to the tip, while REV2 defaults to 0. +LOG-LIMIT defaults to `hg-log-limit'. +With a prefix argument, prompt for each parameter." + (interactive (list (hg-read-file-name " to log") + (hg-read-rev " to start with" + "tip") + (hg-read-rev " to end with" + "0") + (hg-read-number "Output limited to: " + hg-log-limit))) + (hg-log (hg-root path) rev1 rev2 log-limit)) + +(defun hg-outgoing (&optional repo) + "Display changesets present locally that are not present in REPO." + (interactive (list (hg-read-repo-name " where changes would go to" nil + hg-outgoing-repository))) + (hg-view-output ((format "Mercurial: Outgoing from %s to %s" + (hg-abbrev-file-name (hg-root)) + (hg-abbrev-file-name + (or repo hg-outgoing-repository)))) + (call-process (hg-binary) nil t nil "outgoing" + (or repo hg-outgoing-repository)) + (hg-log-mode) + (cd (hg-root)))) + +(defun hg-pull (&optional repo) + "Pull changes from repository REPO. +This does not update the working directory." + (interactive (list (hg-read-repo-name " to pull from"))) + (hg-view-output ((format "Mercurial: Pull to %s from %s" + (hg-abbrev-file-name (hg-root)) + (hg-abbrev-file-name + (or repo hg-incoming-repository)))) + (call-process (hg-binary) nil t nil "pull" + (or repo hg-incoming-repository)) + (cd (hg-root)))) + +(defun hg-push (&optional repo) + "Push changes to repository REPO." + (interactive (list (hg-read-repo-name " to push to"))) + (hg-view-output ((format "Mercurial: Push from %s to %s" + (hg-abbrev-file-name (hg-root)) + (hg-abbrev-file-name + (or repo hg-outgoing-repository)))) + (call-process (hg-binary) nil t nil "push" + (or repo hg-outgoing-repository)) + (cd (hg-root)))) + +(defun hg-revert-buffer-internal () + (let ((ctx (hg-buffer-context))) + (message "Reverting %s..." buffer-file-name) + (hg-run0 "revert" buffer-file-name) + (revert-buffer t t t) + (hg-restore-context ctx) + (hg-mode-line) + (message "Reverting %s...done" buffer-file-name))) + +(defun hg-revert-buffer () + "Revert current buffer's file back to the latest committed version. +If the file has not changed, nothing happens. Otherwise, this +displays a diff and asks for confirmation before reverting." + (interactive) + (let ((vc-suppress-confirm nil) + (obuf (current-buffer)) + diff) + (vc-buffer-sync) + (unwind-protect + (setq diff (hg-diff buffer-file-name)) + (when diff + (unless (yes-or-no-p "Discard changes? ") + (error "Revert cancelled"))) + (when diff + (let ((buf (current-buffer))) + (delete-window (selected-window)) + (kill-buffer buf)))) + (set-buffer obuf) + (when diff + (hg-revert-buffer-internal)))) + +(defun hg-root (&optional path) + "Return the root of the repository that contains the given path. +If the path is outside a repository, return nil. +When called interactively, the root is printed. A prefix argument +prompts for a path to check." + (interactive (list (hg-read-file-name))) + (if (or path (not hg-root)) + (let ((root (do ((prev nil dir) + (dir (file-name-directory + (or + path + buffer-file-name + (expand-file-name default-directory))) + (file-name-directory (directory-file-name dir)))) + ((equal prev dir)) + (when (file-directory-p (concat dir ".hg")) + (return dir))))) + (when (interactive-p) + (if root + (message "The root of this repository is `%s'." root) + (message "The path `%s' is not in a Mercurial repository." + (hg-abbrev-file-name path)))) + root) + hg-root)) + +(defun hg-cwd (&optional path) + "Return the current directory of PATH within the repository." + (do ((stack nil (cons (file-name-nondirectory + (directory-file-name dir)) + stack)) + (prev nil dir) + (dir (file-name-directory (or path buffer-file-name + (expand-file-name default-directory))) + (file-name-directory (directory-file-name dir)))) + ((equal prev dir)) + (when (file-directory-p (concat dir ".hg")) + (let ((cwd (mapconcat 'identity stack "/"))) + (unless (equal cwd "") + (return (file-name-as-directory cwd))))))) + +(defun hg-status (path) + "Print revision control status of a file or directory. +With prefix argument, prompt for the path to give status for. +Names are displayed relative to the repository root." + (interactive (list (hg-read-file-name " for status" (hg-root)))) + (let ((root (hg-root))) + (hg-view-output ((format "Mercurial: Status of %s in %s" + (let ((name (substring (expand-file-name path) + (length root)))) + (if (> (length name) 0) + name + "*")) + (hg-abbrev-file-name root))) + (apply 'call-process (hg-binary) nil t nil + (list "--cwd" root "status" path)) + (cd (hg-root path))))) + +(defun hg-undo () + (interactive) + (error "not implemented")) + +(defun hg-update () + (interactive) + (error "not implemented")) + +(defun hg-version-other-window (rev) + "Visit version REV of the current file in another window. +If the current file is named `F', the version is named `F.~REV~'. +If `F.~REV~' already exists, use it instead of checking it out again." + (interactive "sVersion to visit (default is workfile version): ") + (let* ((file buffer-file-name) + (version (if (string-equal rev "") + "tip" + rev)) + (automatic-backup (vc-version-backup-file-name file version)) + (manual-backup (vc-version-backup-file-name file version 'manual))) + (unless (file-exists-p manual-backup) + (if (file-exists-p automatic-backup) + (rename-file automatic-backup manual-backup nil) + (hg-run0 "-q" "cat" "-r" version "-o" manual-backup file))) + (find-file-other-window manual-backup))) + + +(provide 'mercurial) + + +;;; Local Variables: +;;; prompt-to-byte-compile: nil +;;; end: diff --git a/sys/src/cmd/hg/contrib/mercurial.spec b/sys/src/cmd/hg/contrib/mercurial.spec new file mode 100755 index 000000000..3762f5a8e --- /dev/null +++ b/sys/src/cmd/hg/contrib/mercurial.spec @@ -0,0 +1,86 @@ +Summary: Mercurial -- a distributed SCM +Name: mercurial +Version: snapshot +Release: 0 +License: GPLv2 +Group: Development/Tools +URL: http://mercurial.selenic.com/ +Source0: http://mercurial.selenic.com/release/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root + +# From the README: +# +# Note: some distributions fails to include bits of distutils by +# default, you'll need python-dev to install. You'll also need a C +# compiler and a 3-way merge tool like merge, tkdiff, or kdiff3. +# +# python-devel provides an adequate python-dev. The merge tool is a +# run-time dependency. +# +BuildRequires: python >= 2.4, python-devel, make, gcc, asciidoc, xmlto +Provides: hg = %{version}-%{release} + +%define pythonver %(python -c 'import sys;print ".".join(map(str, sys.version_info[:2]))') +%define emacs_lispdir %{_datadir}/emacs/site-lisp + +%description +Mercurial is a fast, lightweight source control management system designed +for efficient handling of very large distributed projects. + +%prep +%setup -q + +%build +make all + +%install +rm -rf $RPM_BUILD_ROOT +python setup.py install --root $RPM_BUILD_ROOT --prefix %{_prefix} +make install-doc DESTDIR=$RPM_BUILD_ROOT MANDIR=%{_mandir} + +install contrib/hgk $RPM_BUILD_ROOT%{_bindir} +install contrib/convert-repo $RPM_BUILD_ROOT%{_bindir}/mercurial-convert-repo +install contrib/hg-ssh $RPM_BUILD_ROOT%{_bindir} +install contrib/git-viz/{hg-viz,git-rev-tree} $RPM_BUILD_ROOT%{_bindir} + +bash_completion_dir=$RPM_BUILD_ROOT%{_sysconfdir}/bash_completion.d +mkdir -p $bash_completion_dir +install -m 644 contrib/bash_completion $bash_completion_dir/mercurial.sh + +zsh_completion_dir=$RPM_BUILD_ROOT%{_datadir}/zsh/site-functions +mkdir -p $zsh_completion_dir +install -m 644 contrib/zsh_completion $zsh_completion_dir/_mercurial + +mkdir -p $RPM_BUILD_ROOT%{emacs_lispdir} +install contrib/mercurial.el $RPM_BUILD_ROOT%{emacs_lispdir} + +mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/mercurial/hgrc.d +install contrib/mergetools.hgrc $RPM_BUILD_ROOT%{_sysconfdir}/mercurial/hgrc.d/mergetools.rc + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root,-) +%doc CONTRIBUTORS COPYING doc/README doc/hg*.txt doc/hg*.html doc/ja *.cgi contrib/*.fcgi +%doc %attr(644,root,root) %{_mandir}/man?/hg*.gz +%doc %attr(644,root,root) contrib/*.svg contrib/sample.hgrc +%{_sysconfdir}/bash_completion.d/mercurial.sh +%{_datadir}/zsh/site-functions/_mercurial +%{_datadir}/emacs/site-lisp/mercurial.el +%{_bindir}/hg +%{_bindir}/hgk +%{_bindir}/hg-ssh +%{_bindir}/hg-viz +%{_bindir}/git-rev-tree +%{_bindir}/mercurial-convert-repo +%dir %{_sysconfdir}/bash_completion.d/ +%dir %{_datadir}/zsh/site-functions/ +%dir %{_sysconfdir}/mercurial +%dir %{_sysconfdir}/mercurial/hgrc.d +%config(noreplace) %{_sysconfdir}/mercurial/hgrc.d/mergetools.rc +%if "%{?pythonver}" != "2.4" +%{_libdir}/python%{pythonver}/site-packages/%{name}-*-py%{pythonver}.egg-info +%endif +%{_libdir}/python%{pythonver}/site-packages/%{name} +%{_libdir}/python%{pythonver}/site-packages/hgext diff --git a/sys/src/cmd/hg/contrib/mergetools.hgrc b/sys/src/cmd/hg/contrib/mergetools.hgrc new file mode 100644 index 000000000..6c90ab732 --- /dev/null +++ b/sys/src/cmd/hg/contrib/mergetools.hgrc @@ -0,0 +1,63 @@ +# Some default global settings for common merge tools + +[merge-tools] +kdiff3.args=--auto --L1 base --L2 local --L3 other $base $local $other -o $output +kdiff3.regkey=Software\KDiff3 +kdiff3.regappend=\kdiff3.exe +kdiff3.fixeol=True +kdiff3.gui=True + +gvimdiff.args=--nofork -d -g -O $local $other $base +gvimdiff.regkey=Software\Vim\GVim +gvimdiff.regname=path +gvimdiff.priority=-9 + +merge.checkconflicts=True +merge.priority=-10 + +gpyfm.gui=True + +meld.gui=True + +tkdiff.args=$local $other -a $base -o $output +tkdiff.gui=True +tkdiff.priority=-8 + +xxdiff.args=--show-merged-pane --exit-with-merge-status --title1 local --title2 base --title3 other --merged-filename $output --merge $local $base $other +xxdiff.gui=True +xxdiff.priority=-8 + +diffmerge.args=--nosplash --merge --title1=base --title2=local --title3=other $base $local $other +diffmerge.checkchanged=True +diffmerge.gui=True + +p4merge.args=$base $local $other $output +p4merge.regkey=Software\Perforce\Environment +p4merge.regname=P4INSTROOT +p4merge.regappend=\p4merge.exe +p4merge.gui=True +p4merge.priority=-8 + +tortoisemerge.args=/base:$base /mine:$local /theirs:$other /merged:$output +tortoisemerge.regkey=Software\TortoiseSVN +tortoisemerge.checkchanged=True +tortoisemerge.gui=True + +ecmerge.args=$base $local $other --mode=merge3 --title0=base --title1=local --title2=other --to=$output +ecmerge.regkey=Software\Elli\xc3\xa9 Computing\Merge +ecmerge.gui=True + +filemerge.executable=/Developer/Applications/Utilities/FileMerge.app/Contents/MacOS/FileMerge +filemerge.args=-left $other -right $local -ancestor $base -merge $output +filemerge.gui=True + +beyondcompare3.args=$local $other $base $output /ro /lefttitle=local /centertitle=base /righttitle=other /automerge /reviewconflicts /solo +beyondcompare3.regkey=Software\Scooter Software\Beyond Compare 3 +beyondcompare3.regname=ExePath +beyondcompare3.gui=True + +winmerge.args=/e /u /dl local /dr other /wr $local $other $output +winmerge.regkey=Software\Thingamahoochie\WinMerge +winmerge.regname=Executable +winmerge.checkchanged=True +winmerge.gui=True diff --git a/sys/src/cmd/hg/contrib/mq.el b/sys/src/cmd/hg/contrib/mq.el new file mode 100644 index 000000000..f3d9df4e4 --- /dev/null +++ b/sys/src/cmd/hg/contrib/mq.el @@ -0,0 +1,418 @@ +;;; mq.el --- Emacs support for Mercurial Queues + +;; Copyright (C) 2006 Bryan O'Sullivan + +;; Author: Bryan O'Sullivan + +;; mq.el is free software; you can redistribute it and/or modify it +;; under the terms of version 2 of the GNU General Public License as +;; published by the Free Software Foundation. + +;; mq.el is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;; General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with mq.el, GNU Emacs, or XEmacs; see the file COPYING (`C-h +;; C-l'). If not, write to the Free Software Foundation, Inc., 59 +;; Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +(eval-when-compile (require 'cl)) +(require 'mercurial) + + +(defcustom mq-mode-hook nil + "Hook run when a buffer enters mq-mode." + :type 'sexp + :group 'mercurial) + +(defcustom mq-global-prefix "\C-cq" + "The global prefix for Mercurial Queues keymap bindings." + :type 'sexp + :group 'mercurial) + +(defcustom mq-edit-mode-hook nil + "Hook run after a buffer is populated to edit a patch description." + :type 'sexp + :group 'mercurial) + +(defcustom mq-edit-finish-hook nil + "Hook run before a patch description is finished up with." + :type 'sexp + :group 'mercurial) + +(defcustom mq-signoff-address nil + "Address with which to sign off on a patch." + :type 'string + :group 'mercurial) + + +;;; Internal variables. + +(defvar mq-mode nil + "Is this file managed by MQ?") +(make-variable-buffer-local 'mq-mode) +(put 'mq-mode 'permanent-local t) + +(defvar mq-patch-history nil) + +(defvar mq-top-patch '(nil)) + +(defvar mq-prev-buffer nil) +(make-variable-buffer-local 'mq-prev-buffer) +(put 'mq-prev-buffer 'permanent-local t) + +(defvar mq-top nil) +(make-variable-buffer-local 'mq-top) +(put 'mq-top 'permanent-local t) + +;;; Global keymap. + +(defvar mq-global-map + (let ((map (make-sparse-keymap))) + (define-key map "." 'mq-push) + (define-key map ">" 'mq-push-all) + (define-key map "," 'mq-pop) + (define-key map "<" 'mq-pop-all) + (define-key map "=" 'mq-diff) + (define-key map "r" 'mq-refresh) + (define-key map "e" 'mq-refresh-edit) + (define-key map "i" 'mq-new) + (define-key map "n" 'mq-next) + (define-key map "o" 'mq-signoff) + (define-key map "p" 'mq-previous) + (define-key map "s" 'mq-edit-series) + (define-key map "t" 'mq-top) + map)) + +(global-set-key mq-global-prefix mq-global-map) + +(add-minor-mode 'mq-mode 'mq-mode) + + +;;; Refresh edit mode keymap. + +(defvar mq-edit-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-c\C-c" 'mq-edit-finish) + (define-key map "\C-c\C-k" 'mq-edit-kill) + (define-key map "\C-c\C-s" 'mq-signoff) + map)) + + +;;; Helper functions. + +(defun mq-read-patch-name (&optional source prompt force) + "Read a patch name to use with a command. +May return nil, meaning \"use the default\"." + (let ((patches (split-string + (hg-chomp (hg-run0 (or source "qseries"))) "\n"))) + (when force + (completing-read (format "Patch%s: " (or prompt "")) + (mapcar (lambda (x) (cons x x)) patches) + nil + nil + nil + 'mq-patch-history)))) + +(defun mq-refresh-buffers (root) + (save-excursion + (dolist (buf (hg-buffers-visiting-repo root)) + (when (not (verify-visited-file-modtime buf)) + (set-buffer buf) + (let ((ctx (hg-buffer-context))) + (message "Refreshing %s..." (buffer-name)) + (revert-buffer t t t) + (hg-restore-context ctx) + (message "Refreshing %s...done" (buffer-name)))))) + (hg-update-mode-lines root) + (mq-update-mode-lines root)) + +(defun mq-last-line () + (goto-char (point-max)) + (beginning-of-line) + (when (looking-at "^$") + (forward-line -1)) + (let ((bol (point))) + (end-of-line) + (let ((line (buffer-substring bol (point)))) + (when (> (length line) 0) + line)))) + +(defun mq-push (&optional patch) + "Push patches until PATCH is reached. +If PATCH is nil, push at most one patch." + (interactive (list (mq-read-patch-name "qunapplied" " to push" + current-prefix-arg))) + (let ((root (hg-root)) + (prev-buf (current-buffer)) + last-line ok) + (unless root + (error "Cannot push outside a repository!")) + (hg-sync-buffers root) + (let ((buf-name (format "MQ: Push %s" (or patch "next patch")))) + (kill-buffer (get-buffer-create buf-name)) + (split-window-vertically) + (other-window 1) + (switch-to-buffer (get-buffer-create buf-name)) + (cd root) + (message "Pushing...") + (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpush" + (if patch (list patch)))) + last-line (mq-last-line)) + (let ((lines (count-lines (point-min) (point-max)))) + (if (or (<= lines 1) + (and (equal lines 2) (string-match "Now at:" last-line))) + (progn + (kill-buffer (current-buffer)) + (delete-window)) + (hg-view-mode prev-buf)))) + (mq-refresh-buffers root) + (sit-for 0) + (when last-line + (if ok + (message "Pushing... %s" last-line) + (error "Pushing... %s" last-line))))) + +(defun mq-push-all () + "Push patches until all are applied." + (interactive) + (mq-push "-a")) + +(defun mq-pop (&optional patch) + "Pop patches until PATCH is reached. +If PATCH is nil, pop at most one patch." + (interactive (list (mq-read-patch-name "qapplied" " to pop to" + current-prefix-arg))) + (let ((root (hg-root)) + last-line ok) + (unless root + (error "Cannot pop outside a repository!")) + (hg-sync-buffers root) + (set-buffer (generate-new-buffer "qpop")) + (cd root) + (message "Popping...") + (setq ok (= 0 (apply 'call-process (hg-binary) nil t t "qpop" + (if patch (list patch)))) + last-line (mq-last-line)) + (kill-buffer (current-buffer)) + (mq-refresh-buffers root) + (sit-for 0) + (when last-line + (if ok + (message "Popping... %s" last-line) + (error "Popping... %s" last-line))))) + +(defun mq-pop-all () + "Push patches until none are applied." + (interactive) + (mq-pop "-a")) + +(defun mq-refresh-internal (root &rest args) + (hg-sync-buffers root) + (let ((patch (mq-patch-info "qtop"))) + (message "Refreshing %s..." patch) + (let ((ret (apply 'hg-run "qrefresh" args))) + (if (equal (car ret) 0) + (message "Refreshing %s... done." patch) + (error "Refreshing %s... %s" patch (hg-chomp (cdr ret))))))) + +(defun mq-refresh (&optional git) + "Refresh the topmost applied patch. +With a prefix argument, generate a git-compatible patch." + (interactive "P") + (let ((root (hg-root))) + (unless root + (error "Cannot refresh outside of a repository!")) + (apply 'mq-refresh-internal root (if git '("--git"))))) + +(defun mq-patch-info (cmd &optional msg) + (let* ((ret (hg-run cmd)) + (info (hg-chomp (cdr ret)))) + (if (equal (car ret) 0) + (if msg + (message "%s patch: %s" msg info) + info) + (error "%s" info)))) + +(defun mq-top () + "Print the name of the topmost applied patch." + (interactive) + (mq-patch-info "qtop" "Top")) + +(defun mq-next () + "Print the name of the next patch to be pushed." + (interactive) + (mq-patch-info "qnext" "Next")) + +(defun mq-previous () + "Print the name of the first patch below the topmost applied patch. +This would become the active patch if popped to." + (interactive) + (mq-patch-info "qprev" "Previous")) + +(defun mq-edit-finish () + "Finish editing the description of this patch, and refresh the patch." + (interactive) + (unless (equal (mq-patch-info "qtop") mq-top) + (error "Topmost patch has changed!")) + (hg-sync-buffers hg-root) + (run-hooks 'mq-edit-finish-hook) + (mq-refresh-internal hg-root "-m" (buffer-substring (point-min) (point-max))) + (let ((buf mq-prev-buffer)) + (kill-buffer nil) + (switch-to-buffer buf))) + +(defun mq-edit-kill () + "Kill the edit currently being prepared." + (interactive) + (when (or (not (buffer-modified-p)) (y-or-n-p "Really kill this edit? ")) + (let ((buf mq-prev-buffer)) + (kill-buffer nil) + (switch-to-buffer buf)))) + +(defun mq-get-top (root) + (let ((entry (assoc root mq-top-patch))) + (if entry + (cdr entry)))) + +(defun mq-set-top (root patch) + (let ((entry (assoc root mq-top-patch))) + (if entry + (if patch + (setcdr entry patch) + (setq mq-top-patch (delq entry mq-top-patch))) + (setq mq-top-patch (cons (cons root patch) mq-top-patch))))) + +(defun mq-update-mode-lines (root) + (let ((cwd default-directory)) + (cd root) + (condition-case nil + (mq-set-top root (mq-patch-info "qtop")) + (error (mq-set-top root nil))) + (cd cwd)) + (let ((patch (mq-get-top root))) + (save-excursion + (dolist (buf (hg-buffers-visiting-repo root)) + (set-buffer buf) + (if mq-mode + (setq mq-mode (or (and patch (concat " MQ:" patch)) " MQ"))))))) + +(defun mq-mode (&optional arg) + "Minor mode for Mercurial repositories with an MQ patch queue" + (interactive "i") + (cond ((hg-root) + (setq mq-mode (if (null arg) (not mq-mode) + arg)) + (mq-update-mode-lines (hg-root)))) + (run-hooks 'mq-mode-hook)) + +(defun mq-edit-mode () + "Mode for editing the description of a patch. + +Key bindings +------------ +\\[mq-edit-finish] use this description +\\[mq-edit-kill] abandon this description" + (interactive) + (use-local-map mq-edit-mode-map) + (set-syntax-table text-mode-syntax-table) + (setq local-abbrev-table text-mode-abbrev-table + major-mode 'mq-edit-mode + mode-name "MQ-Edit") + (set-buffer-modified-p nil) + (setq buffer-undo-list nil) + (run-hooks 'text-mode-hook 'mq-edit-mode-hook)) + +(defun mq-refresh-edit () + "Refresh the topmost applied patch, editing the patch description." + (interactive) + (while mq-prev-buffer + (set-buffer mq-prev-buffer)) + (let ((root (hg-root)) + (prev-buffer (current-buffer)) + (patch (mq-patch-info "qtop"))) + (hg-sync-buffers root) + (let ((buf-name (format "*MQ: Edit description of %s*" patch))) + (switch-to-buffer (get-buffer-create buf-name)) + (when (= (point-min) (point-max)) + (set (make-local-variable 'hg-root) root) + (set (make-local-variable 'mq-top) patch) + (setq mq-prev-buffer prev-buffer) + (insert (hg-run0 "qheader")) + (goto-char (point-min))) + (mq-edit-mode) + (cd root))) + (message "Type `C-c C-c' to finish editing and refresh the patch.")) + +(defun mq-new (name) + "Create a new empty patch named NAME. +The patch is applied on top of the current topmost patch. +With a prefix argument, forcibly create the patch even if the working +directory is modified." + (interactive (list (mq-read-patch-name "qseries" " to create" t))) + (message "Creating patch...") + (let ((ret (if current-prefix-arg + (hg-run "qnew" "-f" name) + (hg-run "qnew" name)))) + (if (equal (car ret) 0) + (progn + (hg-update-mode-lines (buffer-file-name)) + (message "Creating patch... done.")) + (error "Creating patch... %s" (hg-chomp (cdr ret)))))) + +(defun mq-edit-series () + "Edit the MQ series file directly." + (interactive) + (let ((root (hg-root))) + (unless root + (error "Not in an MQ repository!")) + (find-file (concat root ".hg/patches/series")))) + +(defun mq-diff (&optional git) + "Display a diff of the topmost applied patch. +With a prefix argument, display a git-compatible diff." + (interactive "P") + (hg-view-output ((format "MQ: Diff of %s" (mq-patch-info "qtop"))) + (if git + (call-process (hg-binary) nil t nil "qdiff" "--git") + (call-process (hg-binary) nil t nil "qdiff")) + (diff-mode) + (font-lock-fontify-buffer))) + +(defun mq-signoff () + "Sign off on the current patch, in the style used by the Linux kernel. +If the variable mq-signoff-address is non-nil, it will be used, otherwise +the value of the ui.username item from your hgrc will be used." + (interactive) + (let ((was-editing (eq major-mode 'mq-edit-mode)) + signed) + (unless was-editing + (mq-refresh-edit)) + (save-excursion + (let* ((user (or mq-signoff-address + (hg-run0 "debugconfig" "ui.username"))) + (signoff (concat "Signed-off-by: " user))) + (if (search-forward signoff nil t) + (message "You have already signed off on this patch.") + (goto-char (point-max)) + (let ((case-fold-search t)) + (if (re-search-backward "^Signed-off-by: " nil t) + (forward-line 1) + (insert "\n"))) + (insert signoff) + (message "%s" signoff) + (setq signed t)))) + (unless was-editing + (if signed + (mq-edit-finish) + (mq-edit-kill))))) + + +(provide 'mq) + + +;;; Local Variables: +;;; prompt-to-byte-compile: nil +;;; end: diff --git a/sys/src/cmd/hg/contrib/perf.py b/sys/src/cmd/hg/contrib/perf.py new file mode 100644 index 000000000..3da83d60c --- /dev/null +++ b/sys/src/cmd/hg/contrib/perf.py @@ -0,0 +1,131 @@ +# perf.py - performance test routines +'''helper extension to measure performance''' + +from mercurial import cmdutil, match, commands +import time, os, sys + +def timer(func): + results = [] + begin = time.time() + count = 0 + while 1: + ostart = os.times() + cstart = time.time() + r = func() + cstop = time.time() + ostop = os.times() + count += 1 + a, b = ostart, ostop + results.append((cstop - cstart, b[0] - a[0], b[1]-a[1])) + if cstop - begin > 3 and count >= 100: + break + if cstop - begin > 10 and count >= 3: + break + if r: + sys.stderr.write("! result: %s\n" % r) + m = min(results) + sys.stderr.write("! wall %f comb %f user %f sys %f (best of %d)\n" + % (m[0], m[1] + m[2], m[1], m[2], count)) + +def perfwalk(ui, repo, *pats): + try: + m = cmdutil.match(repo, pats, {}) + timer(lambda: len(list(repo.dirstate.walk(m, True, False)))) + except: + try: + m = cmdutil.match(repo, pats, {}) + timer(lambda: len([b for a,b,c in repo.dirstate.statwalk([], m)])) + except: + timer(lambda: len(list(cmdutil.walk(repo, pats, {})))) + +def perfstatus(ui, repo, *pats): + #m = match.always(repo.root, repo.getcwd()) + #timer(lambda: sum(map(len, repo.dirstate.status(m, False, False, False)))) + timer(lambda: sum(map(len, repo.status()))) + +def perfheads(ui, repo): + timer(lambda: len(repo.changelog.heads())) + +def perftags(ui, repo): + import mercurial.changelog, mercurial.manifest + def t(): + repo.changelog = mercurial.changelog.changelog(repo.sopener) + repo.manifest = mercurial.manifest.manifest(repo.sopener) + repo._tags = None + return len(repo.tags()) + timer(t) + +def perfdirstate(ui, repo): + "a" in repo.dirstate + def d(): + repo.dirstate.invalidate() + "a" in repo.dirstate + timer(d) + +def perfdirstatedirs(ui, repo): + "a" in repo.dirstate + def d(): + "a" in repo.dirstate._dirs + del repo.dirstate._dirs + timer(d) + +def perfmanifest(ui, repo): + def d(): + t = repo.manifest.tip() + m = repo.manifest.read(t) + repo.manifest.mapcache = None + repo.manifest._cache = None + timer(d) + +def perfindex(ui, repo): + import mercurial.changelog + def d(): + t = repo.changelog.tip() + repo.changelog = mercurial.changelog.changelog(repo.sopener) + repo.changelog._loadindexmap() + timer(d) + +def perfstartup(ui, repo): + cmd = sys.argv[0] + def d(): + os.system("HGRCPATH= %s version -q > /dev/null" % cmd) + timer(d) + +def perfparents(ui, repo): + nl = [repo.changelog.node(i) for i in xrange(1000)] + def d(): + for n in nl: + repo.changelog.parents(n) + timer(d) + +def perflookup(ui, repo, rev): + timer(lambda: len(repo.lookup(rev))) + +def perflog(ui, repo): + ui.pushbuffer() + timer(lambda: commands.log(ui, repo, rev=[], date='', user='')) + ui.popbuffer() + +def perftemplating(ui, repo): + ui.pushbuffer() + timer(lambda: commands.log(ui, repo, rev=[], date='', user='', + template='{date|shortdate} [{rev}:{node|short}]' + ' {author|person}: {desc|firstline}\n')) + ui.popbuffer() + +cmdtable = { + 'perflookup': (perflookup, []), + 'perfparents': (perfparents, []), + 'perfstartup': (perfstartup, []), + 'perfstatus': (perfstatus, []), + 'perfwalk': (perfwalk, []), + 'perfmanifest': (perfmanifest, []), + 'perfindex': (perfindex, []), + 'perfheads': (perfheads, []), + 'perftags': (perftags, []), + 'perfdirstate': (perfdirstate, []), + 'perfdirstatedirs': (perfdirstate, []), + 'perflog': (perflog, []), + 'perftemplating': (perftemplating, []), +} + diff --git a/sys/src/cmd/hg/contrib/python-hook-examples.py b/sys/src/cmd/hg/contrib/python-hook-examples.py new file mode 100644 index 000000000..54fb7d348 --- /dev/null +++ b/sys/src/cmd/hg/contrib/python-hook-examples.py @@ -0,0 +1,22 @@ +''' +Examples of useful python hooks for Mercurial. +''' +from mercurial import patch, util + +def diffstat(ui, repo, **kwargs): + '''Example usage: + + [hooks] + commit.diffstat = python:/path/to/this/file.py:diffstat + changegroup.diffstat = python:/path/to/this/file.py:diffstat + ''' + if kwargs.get('parent2'): + return + node = kwargs['node'] + first = repo[node].parents()[0].node() + if 'url' in kwargs: + last = repo['tip'].node() + else: + last = node + diff = patch.diff(repo, first, last) + ui.write(patch.diffstat(util.iterlines(diff))) diff --git a/sys/src/cmd/hg/contrib/rewrite-log b/sys/src/cmd/hg/contrib/rewrite-log new file mode 100755 index 000000000..885a32017 --- /dev/null +++ b/sys/src/cmd/hg/contrib/rewrite-log @@ -0,0 +1,23 @@ +#!/usr/bin/env python +import sys, os +from mercurial import revlog, transaction, node, util + +f = sys.argv[1] + +r1 = revlog.revlog(util.opener(os.getcwd(), audit=False), f + ".i", f + ".d") +r2 = revlog.revlog(util.opener(os.getcwd(), audit=False), f + ".i2", f + ".d2") + +tr = transaction.transaction(sys.stderr.write, open, "journal") + +for i in xrange(r1.count()): + n = r1.node(i) + p1, p2 = r1.parents(n) + l = r1.linkrev(n) + t = r1.revision(n) + n2 = r2.addrevision(t, tr, l, p1, p2) +tr.close() + +os.rename(f + ".i", f + ".i.old") +os.rename(f + ".d", f + ".d.old") +os.rename(f + ".i2", f + ".i") +os.rename(f + ".d2", f + ".d") diff --git a/sys/src/cmd/hg/contrib/sample.hgrc b/sys/src/cmd/hg/contrib/sample.hgrc new file mode 100644 index 000000000..6a0d403dc --- /dev/null +++ b/sys/src/cmd/hg/contrib/sample.hgrc @@ -0,0 +1,133 @@ +### --- User interface + +[ui] + +### show changed files and be a bit more verbose if True + +# verbose = True + +### username data to appear in comits +### it usually takes the form: Joe User + +# username = Joe User + +### --- Extensions + +[extensions] + +### each extension has its own 'extension_name=path' line +### the default python library path is used when path is left blank +### the hgext dir is used when 'hgext.extension_name=' is written + +### acl - Access control lists +### hg help acl + +# hgext.acl = + +### bisect - binary search changesets to detect bugs +### hg help bisect + +# hgext.hbisect = + +### bugzilla - update bugzilla bugs when changesets mention them +### hg help bugzilla + +# hgext.bugzilla = + +### extdiff - Use external diff application instead of builtin one + +# hgext.extdiff = + +### gpg - GPG checks and signing +### hg help gpg + +# hgext.gpg = + +### graphlog - ASCII graph log +### hg help glog + +# hgext.graphlog = + +### hgk - GUI repository browser +### hg help view + +# hgext.hgk = + +### mq - Mercurial patch queues +### hg help mq + +# hgext.mq = + +### notify - Template driven e-mail notifications +### hg help notify + +# hgext.notify = + +### patchbomb - send changesets as a series of patch emails +### hg help email + +# hgext.patchbomb = + +### churn - create a graph showing who changed the most lines +### hg help churn + +# hgext.churn = /home/user/hg/hg/contrib/churn.py + +### win32text - line ending conversion filters for the Windows platform + +# hgext.win32text = + +### --- hgk additional configuration + +[hgk] + +### set executable path + +# path = /home/user/hg/hg/contrib/hgk + +### --- Hook to Mercurial actions - See hgrc man page for avaliable hooks + +[hooks] + +### Example notify hooks (load hgext.notify extension before use) + +# incoming.notify = python:hgext.notify.hook +# changegroup.notify = python:hgext.notify.hook + +### Email configuration for the notify and patchbomb extensions + +[email] + +### Your email address + +# from = user@example.com + +### Method to send email - smtp or /usr/sbin/sendmail or other program name + +# method = smtp + +### smtp server to send email to + +[smtp] + +# host = mail +# port = 25 +# tls = false +# username = user +# password = blivet +# local_hostname = myhost + +### --- Email notification hook for server + +[notify] +### multiple sources can be specified as a whitespace or comma separated list + +# sources = serve push pull bundle + +### set this to False when you're ready for mail to start sending + +# test = True + +### path to config file with names of subscribers + +# config = /path/to/subscription/file diff --git a/sys/src/cmd/hg/contrib/simplemerge b/sys/src/cmd/hg/contrib/simplemerge new file mode 100755 index 000000000..3a0897f5a --- /dev/null +++ b/sys/src/cmd/hg/contrib/simplemerge @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +from mercurial import demandimport +demandimport.enable() + +import os, sys +from mercurial.i18n import _ +from mercurial import simplemerge, fancyopts, util, ui + +options = [('L', 'label', [], _('labels to use on conflict markers')), + ('a', 'text', None, _('treat all files as text')), + ('p', 'print', None, + _('print results instead of overwriting LOCAL')), + ('', 'no-minimal', None, + _('do not try to minimize conflict regions')), + ('h', 'help', None, _('display help and exit')), + ('q', 'quiet', None, _('suppress output'))] + +usage = _('''simplemerge [OPTS] LOCAL BASE OTHER + + Simple three-way file merge utility with a minimal feature set. + + Apply to LOCAL the changes necessary to go from BASE to OTHER. + + By default, LOCAL is overwritten with the results of this operation. +''') + +class ParseError(Exception): + """Exception raised on errors in parsing the command line.""" + +def showhelp(): + sys.stdout.write(usage) + sys.stdout.write('\noptions:\n') + + out_opts = [] + for shortopt, longopt, default, desc in options: + out_opts.append(('%2s%s' % (shortopt and '-%s' % shortopt, + longopt and ' --%s' % longopt), + '%s' % desc)) + opts_len = max([len(opt[0]) for opt in out_opts]) + for first, second in out_opts: + sys.stdout.write(' %-*s %s\n' % (opts_len, first, second)) + +try: + for fp in (sys.stdin, sys.stdout, sys.stderr): + util.set_binary(fp) + + opts = {} + try: + args = fancyopts.fancyopts(sys.argv[1:], options, opts) + except fancyopts.getopt.GetoptError, e: + raise ParseError(e) + if opts['help']: + showhelp() + sys.exit(0) + if len(args) != 3: + raise ParseError(_('wrong number of arguments')) + sys.exit(simplemerge.simplemerge(ui.ui(), *args, **opts)) +except ParseError, e: + sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) + showhelp() + sys.exit(1) +except util.Abort, e: + sys.stderr.write("abort: %s\n" % e) + sys.exit(255) +except KeyboardInterrupt: + sys.exit(255) diff --git a/sys/src/cmd/hg/contrib/tcsh_completion b/sys/src/cmd/hg/contrib/tcsh_completion new file mode 100644 index 000000000..cf4133d54 --- /dev/null +++ b/sys/src/cmd/hg/contrib/tcsh_completion @@ -0,0 +1,49 @@ +# +# tcsh completion for Mercurial +# +# This file has been auto-generated by tcsh_completion_build.sh for +# Mercurial Distributed SCM (version 1.1.2) +# +# Copyright (C) 2005 TK Soh. +# +# This is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# + +complete hg \ + 'n/--cwd/d/' 'n/-R/d/' 'n/--repository/d/' \ + 'C/-/( -R --repository \ + --cwd \ + -y --noninteractive \ + -q --quiet \ + -v --verbose \ + --config \ + --debug \ + --debugger \ + --encoding \ + --encodingmode \ + --lsprof \ + --traceback \ + --time \ + --profile \ + --version \ + -h --help)/' \ + 'p/1/(add addremove annotate blame archive \ + backout bisect branch branches bundle \ + cat clone commit ci copy \ + cp debugancestor debugcheckstate debugcomplete debugdata \ + debugdate debugfsinfo debugindex debugindexdot debuginstall \ + debugrawcommit rawcommit debugrebuildstate debugrename debugsetparents \ + debugstate debugwalk diff export grep \ + heads help identify id import \ + patch incoming in init locate \ + log history manifest merge outgoing \ + out parents paths pull push \ + recover remove rm rename mv \ + resolve revert rollback root serve \ + showconfig debugconfig status st tag \ + tags tip unbundle update up \ + checkout co verify version)/' + diff --git a/sys/src/cmd/hg/contrib/tcsh_completion_build.sh b/sys/src/cmd/hg/contrib/tcsh_completion_build.sh new file mode 100755 index 000000000..8b83f30e1 --- /dev/null +++ b/sys/src/cmd/hg/contrib/tcsh_completion_build.sh @@ -0,0 +1,73 @@ +#!/bin/sh + +# +# tcsh_completion_build.sh - script to generate tcsh completion +# +# +# Copyright (C) 2005 TK Soh. +# +# This is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# +# Description +# ----------- +# This script generates a tcsh source file to support completion +# of Mercurial commands and options. +# +# Instruction: +# ----------- +# Run this script to generate the tcsh source file, and source +# the file to add command completion support for Mercurial. +# +# tcsh% tcsh_completion.sh FILE +# tcsh% source FILE +# +# If FILE is not specified, tcsh_completion will be generated. +# +# Bugs: +# ---- +# 1. command specific options are not supported +# 2. hg commands must be specified immediately after 'hg'. +# + +tcsh_file=${1-tcsh_completion} + +hg_commands=`hg --debug help | \ + sed -e '1,/^list of commands:/d' \ + -e '/^enabled extensions:/,$d' \ + -e '/^ [^ ]/!d; s/[,:]//g;' | \ + xargs -n5 | \ + sed -e '$!s/$/ \\\\/g; 2,$s/^ */ /g'` + +hg_global_options=`hg -v help | \ + sed -e '1,/global/d;/^ *-/!d; s/ [^- ].*//' | \ + sed -e 's/ *$//; $!s/$/ \\\\/g; 2,$s/^ */ /g'` + +hg_version=`hg version | sed -e '1q'` + +script_name=`basename $0` + +cat > $tcsh_file < +" Last Change: $Date: 2002/10/01 21:34:02 $ +" Remark: Used by the cvscommand plugin. Originally written by Mathieu +" Clabaut +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +syn match cvsDate /\S\S\S \S\+ \d\+ \d\+:\d\+:\d\+ \d\+ [+-]\?\d\+/ contained +syn match cvsName /^\s*\S\+ / contained nextgroup=cvsVer +syn match cvsVer /\d\+ / contained nextgroup=cvsDate +syn region cvsHead start="^" end=":" contains=cvsVer,cvsName,cvsDate + +if !exists("did_cvsannotate_syntax_inits") +let did_cvsannotate_syntax_inits = 1 +hi link cvsText String +hi link cvsDate Comment +hi link cvsName Type +hi link cvsVer Statement +endif + +let b:current_syntax="CVSAnnotate" diff --git a/sys/src/cmd/hg/contrib/vim/hg-menu.vim b/sys/src/cmd/hg/contrib/vim/hg-menu.vim new file mode 100644 index 000000000..1664ecb10 --- /dev/null +++ b/sys/src/cmd/hg/contrib/vim/hg-menu.vim @@ -0,0 +1,93 @@ +" vim600: set foldmethod=marker: +" ============================================================================= +" Name Of File: hg-menu.vim +" Description: Interface to Mercurial Version Control. +" Author: Steve Borho (modified Jeff Lanzarotta's RCS script) +" Date: Wednesday, October 5, 2005 +" Version: 0.1.0 +" Copyright: None. +" Usage: These command and gui menu displays useful hg functions +" Configuration: Your hg executable must be in your path. +" ============================================================================= + +" Section: Init {{{1 +if exists("loaded_hg_menu") + finish +endif +let loaded_hg_menu = 1 + +" Section: Menu Options {{{1 +if has("gui") +" amenu H&G.Commit\ File,ci :!hg commit %:e! +" amenu H&G.Commit\ All,call :!hg commit:e! +" amenu H&G.-SEP1- + amenu H&G.Add\\add :!hg add % + amenu H&G.Forget\ Add\\fgt :!hg forget % + amenu H&G.Show\ Differences\\diff :call ShowResults("FileDiff", "hg\ diff") + amenu H&G.Revert\ to\ Last\ Version\\revert :!hg revert %:e! + amenu H&G.Show\ History\\log :call ShowResults("FileLog", "hg\ log") + amenu H&G.Annotate\\an :call ShowResults("annotate", "hg\ annotate") + amenu H&G.-SEP1- + amenu H&G.Repo\ Status\\stat :call ShowResults("RepoStatus", "hg\ status") + amenu H&G.Pull\\pull :!hg pull:e! + amenu H&G.Update\\upd :!hg update:e! +endif + +" Section: Mappings {{{1 +if(v:version >= 600) + " The default Leader is \ 'backslash' + map add :!hg add % + map fgt :!hg forget % + map diff :call ShowResults("FileDiff", "hg\ diff") + map revert :!hg revert %:e! + map log :call ShowResults("FileLog", "hg\ log") + map an :call ShowResults("annotate", "hg\ annotate") + map stat :call ShowResults("RepoStatus", "hg\ status") + map upd :!hg update:e! + map pull :!hg pull:e! +else + " pre 6.0, the default Leader was a comma + map ,add :!hg add % + map ,fgt :!hg forget % + map ,diff :call ShowResults("FileDiff", "hg\ diff") + map ,revert :!hg revert:e! + map ,log :call ShowResults("FileLog", "hg\ log") + map ,an :call ShowResults("annotate", "hg\ annotate") + map ,stat :call ShowResults("RepoStatus", "hg\ status") + map ,upd :!hg update:e! + map ,pull :!hg pull:e! +endif + +" Section: Functions {{{1 +" Show the log results of the current file with a revision control system. +function! ShowResults(bufferName, cmdName) + " Modify the shortmess option: + " A don't give the "ATTENTION" message when an existing swap file is + " found. + set shortmess+=A + + " Get the name of the current buffer. + let currentBuffer = bufname("%") + + " If a buffer with the name rlog exists, delete it. + if bufexists(a:bufferName) + execute 'bd! ' a:bufferName + endif + + " Create a new buffer. + execute 'new ' a:bufferName + + " Execute the command. + execute 'r!' a:cmdName ' ' currentBuffer + + " Make is so that the file can't be edited. + setlocal nomodified + setlocal nomodifiable + setlocal readonly + + " Go to the beginning of the buffer. + execute "normal 1G" + + " Restore the shortmess option. + set shortmess-=A +endfunction diff --git a/sys/src/cmd/hg/contrib/vim/hgcommand.vim b/sys/src/cmd/hg/contrib/vim/hgcommand.vim new file mode 100644 index 000000000..9cbb579c9 --- /dev/null +++ b/sys/src/cmd/hg/contrib/vim/hgcommand.vim @@ -0,0 +1,1703 @@ +" vim600: set foldmethod=marker: +" +" Vim plugin to assist in working with HG-controlled files. +" +" Last Change: 2006/02/22 +" Version: 1.77 +" Maintainer: Mathieu Clabaut +" License: This file is placed in the public domain. +" Credits: +" Bob Hiestand for the fabulous +" cvscommand.vim from which this script was directly created by +" means of sed commands and minor tweaks. +" Note: +" For Vim7 the use of Bob Hiestand's vcscommand.vim +" +" in conjunction with Vladmir Marek's Hg backend +" +" is recommended. + +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" +" Section: Documentation +"---------------------------- +" +" Documentation should be available by ":help hgcommand" command, once the +" script has been copied in you .vim/plugin directory. +" +" You still can read the documentation at the end of this file. Locate it by +" searching the "hgcommand-contents" string (and set ft=help to have +" appropriate syntaxic coloration). + +" Section: Plugin header {{{1 + +" loaded_hgcommand is set to 1 when the initialization begins, and 2 when it +" completes. This allows various actions to only be taken by functions after +" system initialization. + +if exists("g:loaded_hgcommand") + finish +endif +let g:loaded_hgcommand = 1 + +" store 'compatible' settings +let s:save_cpo = &cpo +set cpo&vim + +" run checks +let s:script_name = expand(":t:r") + +function! s:HGCleanupOnFailure(err) + echohl WarningMsg + echomsg s:script_name . ":" a:err "Plugin not loaded" + echohl None + let g:loaded_hgcommand = "no" + unlet s:save_cpo s:script_name +endfunction + +if v:version < 602 + call HGCleanupOnFailure("VIM 6.2 or later required.") + finish +endif + +if !exists("*system") + call HGCleanupOnFailure("builtin system() function required.") + finish +endif + +let s:script_version = "v0.2" + +" Section: Event group setup {{{1 + +augroup HGCommand +augroup END + +" Section: Plugin initialization {{{1 +silent do HGCommand User HGPluginInit + +" Section: Script variable initialization {{{1 + +let s:HGCommandEditFileRunning = 0 +unlet! s:vimDiffRestoreCmd +unlet! s:vimDiffSourceBuffer +unlet! s:vimDiffBufferCount +unlet! s:vimDiffScratchList + +" Section: Utility functions {{{1 + +" Function: s:HGResolveLink() {{{2 +" Fully resolve the given file name to remove shortcuts or symbolic links. + +function! s:HGResolveLink(fileName) + let resolved = resolve(a:fileName) + if resolved != a:fileName + let resolved = HGResolveLink(resolved) + endif + return resolved +endfunction + +" Function: s:HGChangeToCurrentFileDir() {{{2 +" Go to the directory in which the current HG-controlled file is located. +" If this is a HG command buffer, first switch to the original file. + +function! s:HGChangeToCurrentFileDir(fileName) + let oldCwd=getcwd() + let fileName=HGResolveLink(a:fileName) + let newCwd=fnamemodify(fileName, ':h') + if strlen(newCwd) > 0 + execute 'cd' escape(newCwd, ' ') + endif + return oldCwd +endfunction + +" Function: HGGetOption(name, default) {{{2 +" Grab a user-specified option to override the default provided. Options are +" searched in the window, buffer, then global spaces. + +function! s:HGGetOption(name, default) + if exists("s:" . a:name . "Override") + execute "return s:".a:name."Override" + elseif exists("w:" . a:name) + execute "return w:".a:name + elseif exists("b:" . a:name) + execute "return b:".a:name + elseif exists("g:" . a:name) + execute "return g:".a:name + else + return a:default + endif +endfunction + +" Function: s:HGEditFile(name, origBuffNR) {{{2 +" Wrapper around the 'edit' command to provide some helpful error text if the +" current buffer can't be abandoned. If name is provided, it is used; +" otherwise, a nameless scratch buffer is used. +" Returns: 0 if successful, -1 if an error occurs. + +function! s:HGEditFile(name, origBuffNR) + "Name parameter will be pasted into expression. + let name = escape(a:name, ' *?\') + + let editCommand = HGGetOption('HGCommandEdit', 'edit') + if editCommand != 'edit' + if HGGetOption('HGCommandSplit', 'horizontal') == 'horizontal' + if name == "" + let editCommand = 'rightbelow new' + else + let editCommand = 'rightbelow split ' . name + endif + else + if name == "" + let editCommand = 'vert rightbelow new' + else + let editCommand = 'vert rightbelow split ' . name + endif + endif + else + if name == "" + let editCommand = 'enew' + else + let editCommand = 'edit ' . name + endif + endif + + " Protect against useless buffer set-up + let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 + try + execute editCommand + finally + let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning - 1 + endtry + + let b:HGOrigBuffNR=a:origBuffNR + let b:HGCommandEdit='split' +endfunction + +" Function: s:HGCreateCommandBuffer(cmd, cmdName, statusText, filename) {{{2 +" Creates a new scratch buffer and captures the output from execution of the +" given command. The name of the scratch buffer is returned. + +function! s:HGCreateCommandBuffer(cmd, cmdName, statusText, origBuffNR) + let fileName=bufname(a:origBuffNR) + + let resultBufferName='' + + if HGGetOption("HGCommandNameResultBuffers", 0) + let nameMarker = HGGetOption("HGCommandNameMarker", '_') + if strlen(a:statusText) > 0 + let bufName=a:cmdName . ' -- ' . a:statusText + else + let bufName=a:cmdName + endif + let bufName=fileName . ' ' . nameMarker . bufName . nameMarker + let counter=0 + let resultBufferName = bufName + while buflisted(resultBufferName) + let counter=counter + 1 + let resultBufferName=bufName . ' (' . counter . ')' + endwhile + endif + + let hgCommand = HGGetOption("HGCommandHGExec", "hg") . " " . a:cmd + "echomsg "DBG :".hgCommand + let hgOut = system(hgCommand) + " HACK: diff command does not return proper error codes + if v:shell_error && a:cmdName != 'hgdiff' + if strlen(hgOut) == 0 + echoerr "HG command failed" + else + echoerr "HG command failed: " . hgOut + endif + return -1 + endif + if strlen(hgOut) == 0 + " Handle case of no output. In this case, it is important to check the + " file status, especially since hg edit/unedit may change the attributes + " of the file with no visible output. + + echomsg "No output from HG command" + checktime + return -1 + endif + + if HGEditFile(resultBufferName, a:origBuffNR) == -1 + return -1 + endif + + set buftype=nofile + set noswapfile + set filetype= + + if HGGetOption("HGCommandDeleteOnHide", 0) + set bufhidden=delete + endif + + silent 0put=hgOut + + " The last command left a blank line at the end of the buffer. If the + " last line is folded (a side effect of the 'put') then the attempt to + " remove the blank line will kill the last fold. + " + " This could be fixed by explicitly detecting whether the last line is + " within a fold, but I prefer to simply unfold the result buffer altogether. + + if has("folding") + setlocal nofoldenable + endif + + $d + 1 + + " Define the environment and execute user-defined hooks. + + let b:HGSourceFile=fileName + let b:HGCommand=a:cmdName + if a:statusText != "" + let b:HGStatusText=a:statusText + endif + + silent do HGCommand User HGBufferCreated + return bufnr("%") +endfunction + +" Function: s:HGBufferCheck(hgBuffer) {{{2 +" Attempts to locate the original file to which HG operations were applied +" for a given buffer. + +function! s:HGBufferCheck(hgBuffer) + let origBuffer = getbufvar(a:hgBuffer, "HGOrigBuffNR") + if origBuffer + if bufexists(origBuffer) + return origBuffer + else + " Original buffer no longer exists. + return -1 + endif + else + " No original buffer + return a:hgBuffer + endif +endfunction + +" Function: s:HGCurrentBufferCheck() {{{2 +" Attempts to locate the original file to which HG operations were applied +" for the current buffer. + +function! s:HGCurrentBufferCheck() + return HGBufferCheck(bufnr("%")) +endfunction + +" Function: s:HGToggleDeleteOnHide() {{{2 +" Toggles on and off the delete-on-hide behavior of HG buffers + +function! s:HGToggleDeleteOnHide() + if exists("g:HGCommandDeleteOnHide") + unlet g:HGCommandDeleteOnHide + else + let g:HGCommandDeleteOnHide=1 + endif +endfunction + +" Function: s:HGDoCommand(hgcmd, cmdName, statusText) {{{2 +" General skeleton for HG function execution. +" Returns: name of the new command buffer containing the command results + +function! s:HGDoCommand(cmd, cmdName, statusText) + let hgBufferCheck=HGCurrentBufferCheck() + if hgBufferCheck == -1 + echo "Original buffer no longer exists, aborting." + return -1 + endif + + let fileName=bufname(hgBufferCheck) + if isdirectory(fileName) + let fileName=fileName . "/" . getline(".") + endif + let realFileName = fnamemodify(HGResolveLink(fileName), ':t') + let oldCwd=HGChangeToCurrentFileDir(fileName) + try + " TODO + "if !filereadable('HG/Root') + "throw fileName . ' is not a HG-controlled file.' + "endif + let fullCmd = a:cmd . ' "' . realFileName . '"' + "echomsg "DEBUG".fullCmd + let resultBuffer=HGCreateCommandBuffer(fullCmd, a:cmdName, a:statusText, hgBufferCheck) + return resultBuffer + catch + echoerr v:exception + return -1 + finally + execute 'cd' escape(oldCwd, ' ') + endtry +endfunction + + +" Function: s:HGGetStatusVars(revision, branch, repository) {{{2 +" +" Obtains a HG revision number and branch name. The 'revisionVar', +" 'branchVar'and 'repositoryVar' arguments, if non-empty, contain the names of variables to hold +" the corresponding results. +" +" Returns: string to be exec'd that sets the multiple return values. + +function! s:HGGetStatusVars(revisionVar, branchVar, repositoryVar) + let hgBufferCheck=HGCurrentBufferCheck() + "echomsg "DBG : in HGGetStatusVars" + if hgBufferCheck == -1 + return "" + endif + let fileName=bufname(hgBufferCheck) + let fileNameWithoutLink=HGResolveLink(fileName) + let realFileName = fnamemodify(fileNameWithoutLink, ':t') + let oldCwd=HGChangeToCurrentFileDir(realFileName) + try + let hgCommand = HGGetOption("HGCommandHGExec", "hg") . " root " + let roottext=system(hgCommand) + " Suppress ending null char ! Does it work in window ? + let roottext=substitute(roottext,'^.*/\([^/\n\r]*\)\n\_.*$','\1','') + if match(getcwd()."/".fileNameWithoutLink, roottext) == -1 + return "" + endif + let returnExpression = "" + if a:repositoryVar != "" + let returnExpression=returnExpression . " | let " . a:repositoryVar . "='" . roottext . "'" + endif + let hgCommand = HGGetOption("HGCommandHGExec", "hg") . " status -mardui " . realFileName + let statustext=system(hgCommand) + if(v:shell_error) + return "" + endif + if match(statustext, '^[?I]') >= 0 + let revision="NEW" + elseif match(statustext, '^[R]') >= 0 + let revision="REMOVED" + elseif match(statustext, '^[D]') >= 0 + let revision="DELETED" + elseif match(statustext, '^[A]') >= 0 + let revision="ADDED" + else + " The file is tracked, we can try to get is revision number + let hgCommand = HGGetOption("HGCommandHGExec", "hg") . " parents " + let statustext=system(hgCommand) + if(v:shell_error) + return "" + endif + let revision=substitute(statustext, '^changeset:\s*\(\d\+\):.*\_$\_.*$', '\1', "") + + if a:branchVar != "" && match(statustext, '^\_.*\_^branch:') >= 0 + let branch=substitute(statustext, '^\_.*\_^branch:\s*\(\S\+\)\n\_.*$', '\1', "") + let returnExpression=returnExpression . " | let " . a:branchVar . "='" . branch . "'" + endif + endif + if (exists('revision')) + let returnExpression = "let " . a:revisionVar . "='" . revision . "' " . returnExpression + endif + + return returnExpression + finally + execute 'cd' escape(oldCwd, ' ') + endtry +endfunction + +" Function: s:HGSetupBuffer() {{{2 +" Attempts to set the b:HGBranch, b:HGRevision and b:HGRepository variables. + +function! s:HGSetupBuffer(...) + if (exists("b:HGBufferSetup") && b:HGBufferSetup && !exists('a:1')) + " This buffer is already set up. + return + endif + + if !HGGetOption("HGCommandEnableBufferSetup", 0) + \ || @% == "" + \ || s:HGCommandEditFileRunning > 0 + \ || exists("b:HGOrigBuffNR") + unlet! b:HGRevision + unlet! b:HGBranch + unlet! b:HGRepository + return + endif + + if !filereadable(expand("%")) + return -1 + endif + + let revision="" + let branch="" + let repository="" + + exec HGGetStatusVars('revision', 'branch', 'repository') + "echomsg "DBG ".revision."#".branch."#".repository + if revision != "" + let b:HGRevision=revision + else + unlet! b:HGRevision + endif + if branch != "" + let b:HGBranch=branch + else + unlet! b:HGBranch + endif + if repository != "" + let b:HGRepository=repository + else + unlet! b:HGRepository + endif + silent do HGCommand User HGBufferSetup + let b:HGBufferSetup=1 +endfunction + +" Function: s:HGMarkOrigBufferForSetup(hgbuffer) {{{2 +" Resets the buffer setup state of the original buffer for a given HG buffer. +" Returns: The HG buffer number in a passthrough mode. + +function! s:HGMarkOrigBufferForSetup(hgBuffer) + checktime + if a:hgBuffer != -1 + let origBuffer = HGBufferCheck(a:hgBuffer) + "This should never not work, but I'm paranoid + if origBuffer != a:hgBuffer + call setbufvar(origBuffer, "HGBufferSetup", 0) + endif + else + "We are presumably in the original buffer + let b:HGBufferSetup = 0 + "We do the setup now as now event will be triggered allowing it later. + call HGSetupBuffer() + endif + return a:hgBuffer +endfunction + +" Function: s:HGOverrideOption(option, [value]) {{{2 +" Provides a temporary override for the given HG option. If no value is +" passed, the override is disabled. + +function! s:HGOverrideOption(option, ...) + if a:0 == 0 + unlet! s:{a:option}Override + else + let s:{a:option}Override = a:1 + endif +endfunction + +" Function: s:HGWipeoutCommandBuffers() {{{2 +" Clears all current HG buffers of the specified type for a given source. + +function! s:HGWipeoutCommandBuffers(originalBuffer, hgCommand) + let buffer = 1 + while buffer <= bufnr('$') + if getbufvar(buffer, 'HGOrigBuffNR') == a:originalBuffer + if getbufvar(buffer, 'HGCommand') == a:hgCommand + execute 'bw' buffer + endif + endif + let buffer = buffer + 1 + endwhile +endfunction + +" Function: s:HGInstallDocumentation(full_name, revision) {{{2 +" Install help documentation. +" Arguments: +" full_name: Full name of this vim plugin script, including path name. +" revision: Revision of the vim script. #version# mark in the document file +" will be replaced with this string with 'v' prefix. +" Return: +" 1 if new document installed, 0 otherwise. +" Note: Cleaned and generalized by guo-peng Wen +"''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' +" Helper function to make mkdir as portable as possible +function! s:HGFlexiMkdir(dir) + if exists("*mkdir") " we can use Vim's own mkdir() + call mkdir(a:dir) + elseif !exists("+shellslash") + call system("mkdir -p '".a:dir."'") + else " M$ + let l:ssl = &shellslash + try + set shellslash + " no single quotes? + call system('mkdir "'.a:dir.'"') + finally + let &shellslash = l:ssl + endtry + endif +endfunction + +function! s:HGInstallDocumentation(full_name) + " Figure out document path based on full name of this script: + let l:vim_doc_path = fnamemodify(a:full_name, ":h:h") . "/doc" + if filewritable(l:vim_doc_path) != 2 + echomsg s:script_name . ": Trying to update docs at" l:vim_doc_path + silent! call HGFlexiMkdir(l:vim_doc_path) + if filewritable(l:vim_doc_path) != 2 + " Try first item in 'runtimepath': + let l:vim_doc_path = + \ substitute(&runtimepath, '^\([^,]*\).*', '\1/doc', 'e') + if filewritable(l:vim_doc_path) != 2 + echomsg s:script_name . ": Trying to update docs at" l:vim_doc_path + silent! call HGFlexiMkdir(l:vim_doc_path) + if filewritable(l:vim_doc_path) != 2 + " Put a warning: + echomsg "Unable to open documentation directory" + echomsg " type `:help add-local-help' for more information." + return 0 + endif + endif + endif + endif + + " Full name of documentation file: + let l:doc_file = + \ l:vim_doc_path . "/" . s:script_name . ".txt" + " Bail out if document file is still up to date: + if filereadable(l:doc_file) && + \ getftime(a:full_name) < getftime(l:doc_file) + return 0 + endif + + " temporary global settings + let l:lz = &lazyredraw + let l:hls = &hlsearch + set lazyredraw nohlsearch + " Create a new buffer & read in the plugin file (me): + 1 new + setlocal noswapfile modifiable nomodeline + if has("folding") + setlocal nofoldenable + endif + silent execute "read" escape(a:full_name, " ") + let l:doc_buf = bufnr("%") + + 1 + " Delete from first line to a line starts with + " === START_DOC + silent 1,/^=\{3,}\s\+START_DOC\C/ delete _ + " Delete from a line starts with + " === END_DOC + " to the end of the documents: + silent /^=\{3,}\s\+END_DOC\C/,$ delete _ + + " Add modeline for help doc: the modeline string is mangled intentionally + " to avoid it be recognized by VIM: + call append(line("$"), "") + call append(line("$"), " v" . "im:tw=78:ts=8:ft=help:norl:") + + " Replace revision: + silent execute "normal :1s/#version#/" . s:script_version . "/\" + " Save the help document and wipe out buffer: + silent execute "wq!" escape(l:doc_file, " ") "| bw" l:doc_buf + " Build help tags: + silent execute "helptags" l:vim_doc_path + + let &hlsearch = l:hls + let &lazyredraw = l:lz + return 1 +endfunction + +" Section: Public functions {{{1 + +" Function: HGGetRevision() {{{2 +" Global function for retrieving the current buffer's HG revision number. +" Returns: Revision number or an empty string if an error occurs. + +function! HGGetRevision() + let revision="" + exec HGGetStatusVars('revision', '', '') + return revision +endfunction + +" Function: HGDisableBufferSetup() {{{2 +" Global function for deactivating the buffer autovariables. + +function! HGDisableBufferSetup() + let g:HGCommandEnableBufferSetup=0 + silent! augroup! HGCommandPlugin +endfunction + +" Function: HGEnableBufferSetup() {{{2 +" Global function for activating the buffer autovariables. + +function! HGEnableBufferSetup() + let g:HGCommandEnableBufferSetup=1 + augroup HGCommandPlugin + au! + au BufEnter * call HGSetupBuffer() + au BufWritePost * call HGSetupBuffer() + " Force resetting up buffer on external file change (HG update) + au FileChangedShell * call HGSetupBuffer(1) + augroup END + + " Only auto-load if the plugin is fully loaded. This gives other plugins a + " chance to run. + if g:loaded_hgcommand == 2 + call HGSetupBuffer() + endif +endfunction + +" Function: HGGetStatusLine() {{{2 +" Default (sample) status line entry for HG files. This is only useful if +" HG-managed buffer mode is on (see the HGCommandEnableBufferSetup variable +" for how to do this). + +function! HGGetStatusLine() + if exists('b:HGSourceFile') + " This is a result buffer + let value='[' . b:HGCommand . ' ' . b:HGSourceFile + if exists('b:HGStatusText') + let value=value . ' ' . b:HGStatusText + endif + let value = value . ']' + return value + endif + + if exists('b:HGRevision') + \ && b:HGRevision != '' + \ && exists('b:HGRepository') + \ && b:HGRepository != '' + \ && exists('g:HGCommandEnableBufferSetup') + \ && g:HGCommandEnableBufferSetup + if !exists('b:HGBranch') + let l:branch='' + else + let l:branch=b:HGBranch + endif + return '[HG ' . b:HGRepository . '/' . l:branch .'/' . b:HGRevision . ']' + else + return '' + endif +endfunction + +" Section: HG command functions {{{1 + +" Function: s:HGAdd() {{{2 +function! s:HGAdd() + return HGMarkOrigBufferForSetup(HGDoCommand('add', 'hgadd', '')) +endfunction + +" Function: s:HGAnnotate(...) {{{2 +function! s:HGAnnotate(...) + if a:0 == 0 + if &filetype == "HGAnnotate" + " This is a HGAnnotate buffer. Perform annotation of the version + " indicated by the current line. + let revision = substitute(getline("."),'\(^[0-9]*\):.*','\1','') + if HGGetOption('HGCommandAnnotateParent', 0) != 0 && revision > 0 + let revision = revision - 1 + endif + else + let revision=HGGetRevision() + if revision == "" + echoerr "Unable to obtain HG version information." + return -1 + endif + endif + else + let revision=a:1 + endif + + if revision == "NEW" + echo "No annotatation available for new file." + return -1 + endif + + let resultBuffer=HGDoCommand('annotate -ndu -r ' . revision, 'hgannotate', revision) + "echomsg "DBG: ".resultBuffer + if resultBuffer != -1 + set filetype=HGAnnotate + endif + + return resultBuffer +endfunction + +" Function: s:HGCommit() {{{2 +function! s:HGCommit(...) + " Handle the commit message being specified. If a message is supplied, it + " is used; if bang is supplied, an empty message is used; otherwise, the + " user is provided a buffer from which to edit the commit message. + if a:2 != "" || a:1 == "!" + return HGMarkOrigBufferForSetup(HGDoCommand('commit -m "' . a:2 . '"', 'hgcommit', '')) + endif + + let hgBufferCheck=HGCurrentBufferCheck() + if hgBufferCheck == -1 + echo "Original buffer no longer exists, aborting." + return -1 + endif + + " Protect against windows' backslashes in paths. They confuse exec'd + " commands. + + let shellSlashBak = &shellslash + try + set shellslash + + let messageFileName = tempname() + + let fileName=bufname(hgBufferCheck) + let realFilePath=HGResolveLink(fileName) + let newCwd=fnamemodify(realFilePath, ':h') + if strlen(newCwd) == 0 + " Account for autochdir being in effect, which will make this blank, but + " we know we'll be in the current directory for the original file. + let newCwd = getcwd() + endif + + let realFileName=fnamemodify(realFilePath, ':t') + + if HGEditFile(messageFileName, hgBufferCheck) == -1 + return + endif + + " Protect against case and backslash issues in Windows. + let autoPattern = '\c' . messageFileName + + " Ensure existance of group + augroup HGCommit + augroup END + + execute 'au HGCommit BufDelete' autoPattern 'call delete("' . messageFileName . '")' + execute 'au HGCommit BufDelete' autoPattern 'au! HGCommit * ' autoPattern + + " Create a commit mapping. The mapping must clear all autocommands in case + " it is invoked when HGCommandCommitOnWrite is active, as well as to not + " invoke the buffer deletion autocommand. + + execute 'nnoremap HGCommit '. + \ ':au! HGCommit * ' . autoPattern . ''. + \ ':g/^HG:/d'. + \ ':update'. + \ ':call HGFinishCommit("' . messageFileName . '",' . + \ '"' . newCwd . '",' . + \ '"' . realFileName . '",' . + \ hgBufferCheck . ')' + + silent 0put ='HG: ----------------------------------------------------------------------' + silent put =\"HG: Enter Log. Lines beginning with `HG:' are removed automatically\" + silent put ='HG: Type cc (or your own HGCommit mapping)' + + if HGGetOption('HGCommandCommitOnWrite', 1) == 1 + execute 'au HGCommit BufWritePre' autoPattern 'g/^HG:/d' + execute 'au HGCommit BufWritePost' autoPattern 'call HGFinishCommit("' . messageFileName . '", "' . newCwd . '", "' . realFileName . '", ' . hgBufferCheck . ') | au! * ' autoPattern + silent put ='HG: or write this buffer' + endif + + silent put ='HG: to finish this commit operation' + silent put ='HG: ----------------------------------------------------------------------' + $ + let b:HGSourceFile=fileName + let b:HGCommand='HGCommit' + set filetype=hg + finally + let &shellslash = shellSlashBak + endtry + +endfunction + +" Function: s:HGDiff(...) {{{2 +function! s:HGDiff(...) + if a:0 == 1 + let revOptions = '-r' . a:1 + let caption = a:1 . ' -> current' + elseif a:0 == 2 + let revOptions = '-r' . a:1 . ' -r' . a:2 + let caption = a:1 . ' -> ' . a:2 + else + let revOptions = '' + let caption = '' + endif + + let hgdiffopt=HGGetOption('HGCommandDiffOpt', 'w') + + if hgdiffopt == "" + let diffoptionstring="" + else + let diffoptionstring=" -" . hgdiffopt . " " + endif + + let resultBuffer = HGDoCommand('diff ' . diffoptionstring . revOptions , 'hgdiff', caption) + if resultBuffer != -1 + set filetype=diff + endif + return resultBuffer +endfunction + + +" Function: s:HGGotoOriginal(["!]) {{{2 +function! s:HGGotoOriginal(...) + let origBuffNR = HGCurrentBufferCheck() + if origBuffNR > 0 + let origWinNR = bufwinnr(origBuffNR) + if origWinNR == -1 + execute 'buffer' origBuffNR + else + execute origWinNR . 'wincmd w' + endif + if a:0 == 1 + if a:1 == "!" + let buffnr = 1 + let buffmaxnr = bufnr("$") + while buffnr <= buffmaxnr + if getbufvar(buffnr, "HGOrigBuffNR") == origBuffNR + execute "bw" buffnr + endif + let buffnr = buffnr + 1 + endwhile + endif + endif + endif +endfunction + +" Function: s:HGFinishCommit(messageFile, targetDir, targetFile) {{{2 +function! s:HGFinishCommit(messageFile, targetDir, targetFile, origBuffNR) + if filereadable(a:messageFile) + let oldCwd=getcwd() + if strlen(a:targetDir) > 0 + execute 'cd' escape(a:targetDir, ' ') + endif + let resultBuffer=HGCreateCommandBuffer('commit -l "' . a:messageFile . '" "'. a:targetFile . '"', 'hgcommit', '', a:origBuffNR) + execute 'cd' escape(oldCwd, ' ') + execute 'bw' escape(a:messageFile, ' *?\') + silent execute 'call delete("' . a:messageFile . '")' + return HGMarkOrigBufferForSetup(resultBuffer) + else + echoerr "Can't read message file; no commit is possible." + return -1 + endif +endfunction + +" Function: s:HGLog() {{{2 +function! s:HGLog(...) + if a:0 == 0 + let versionOption = "" + let caption = '' + else + let versionOption=" -r" . a:1 + let caption = a:1 + endif + + let resultBuffer=HGDoCommand('log' . versionOption, 'hglog', caption) + if resultBuffer != "" + set filetype=rcslog + endif + return resultBuffer +endfunction + +" Function: s:HGRevert() {{{2 +function! s:HGRevert() + return HGMarkOrigBufferForSetup(HGDoCommand('revert', 'hgrevert', '')) +endfunction + +" Function: s:HGReview(...) {{{2 +function! s:HGReview(...) + if a:0 == 0 + let versiontag="" + if HGGetOption('HGCommandInteractive', 0) + let versiontag=input('Revision: ') + endif + if versiontag == "" + let versiontag="(current)" + let versionOption="" + else + let versionOption=" -r " . versiontag . " " + endif + else + let versiontag=a:1 + let versionOption=" -r " . versiontag . " " + endif + + let resultBuffer = HGDoCommand('cat' . versionOption, 'hgreview', versiontag) + if resultBuffer > 0 + let &filetype=getbufvar(b:HGOrigBuffNR, '&filetype') + endif + + return resultBuffer +endfunction + +" Function: s:HGStatus() {{{2 +function! s:HGStatus() + return HGDoCommand('status', 'hgstatus', '') +endfunction + + +" Function: s:HGUpdate() {{{2 +function! s:HGUpdate() + return HGMarkOrigBufferForSetup(HGDoCommand('update', 'update', '')) +endfunction + +" Function: s:HGVimDiff(...) {{{2 +function! s:HGVimDiff(...) + let originalBuffer = HGCurrentBufferCheck() + let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 + try + " If there's already a VimDiff'ed window, restore it. + " There may only be one HGVimDiff original window at a time. + + if exists("s:vimDiffSourceBuffer") && s:vimDiffSourceBuffer != originalBuffer + " Clear the existing vimdiff setup by removing the result buffers. + call HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') + endif + + " Split and diff + if(a:0 == 2) + " Reset the vimdiff system, as 2 explicit versions were provided. + if exists('s:vimDiffSourceBuffer') + call HGWipeoutCommandBuffers(s:vimDiffSourceBuffer, 'vimdiff') + endif + let resultBuffer = HGReview(a:1) + if resultBuffer < 0 + echomsg "Can't open HG revision " . a:1 + return resultBuffer + endif + let b:HGCommand = 'vimdiff' + diffthis + let s:vimDiffBufferCount = 1 + let s:vimDiffScratchList = '{'. resultBuffer . '}' + " If no split method is defined, cheat, and set it to vertical. + try + call HGOverrideOption('HGCommandSplit', HGGetOption('HGCommandDiffSplit', HGGetOption('HGCommandSplit', 'vertical'))) + let resultBuffer=HGReview(a:2) + finally + call HGOverrideOption('HGCommandSplit') + endtry + if resultBuffer < 0 + echomsg "Can't open HG revision " . a:1 + return resultBuffer + endif + let b:HGCommand = 'vimdiff' + diffthis + let s:vimDiffBufferCount = 2 + let s:vimDiffScratchList = s:vimDiffScratchList . '{'. resultBuffer . '}' + else + " Add new buffer + try + " Force splitting behavior, otherwise why use vimdiff? + call HGOverrideOption("HGCommandEdit", "split") + call HGOverrideOption("HGCommandSplit", HGGetOption('HGCommandDiffSplit', HGGetOption('HGCommandSplit', 'vertical'))) + if(a:0 == 0) + let resultBuffer=HGReview() + else + let resultBuffer=HGReview(a:1) + endif + finally + call HGOverrideOption("HGCommandEdit") + call HGOverrideOption("HGCommandSplit") + endtry + if resultBuffer < 0 + echomsg "Can't open current HG revision" + return resultBuffer + endif + let b:HGCommand = 'vimdiff' + diffthis + + if !exists('s:vimDiffBufferCount') + " New instance of vimdiff. + let s:vimDiffBufferCount = 2 + let s:vimDiffScratchList = '{' . resultBuffer . '}' + + " This could have been invoked on a HG result buffer, not the + " original buffer. + wincmd W + execute 'buffer' originalBuffer + " Store info for later original buffer restore + let s:vimDiffRestoreCmd = + \ "call setbufvar(".originalBuffer.", \"&diff\", ".getbufvar(originalBuffer, '&diff').")" + \ . "|call setbufvar(".originalBuffer.", \"&foldcolumn\", ".getbufvar(originalBuffer, '&foldcolumn').")" + \ . "|call setbufvar(".originalBuffer.", \"&foldenable\", ".getbufvar(originalBuffer, '&foldenable').")" + \ . "|call setbufvar(".originalBuffer.", \"&foldmethod\", '".getbufvar(originalBuffer, '&foldmethod')."')" + \ . "|call setbufvar(".originalBuffer.", \"&scrollbind\", ".getbufvar(originalBuffer, '&scrollbind').")" + \ . "|call setbufvar(".originalBuffer.", \"&wrap\", ".getbufvar(originalBuffer, '&wrap').")" + \ . "|if &foldmethod=='manual'|execute 'normal! zE'|endif" + diffthis + wincmd w + else + " Adding a window to an existing vimdiff + let s:vimDiffBufferCount = s:vimDiffBufferCount + 1 + let s:vimDiffScratchList = s:vimDiffScratchList . '{' . resultBuffer . '}' + endif + endif + + let s:vimDiffSourceBuffer = originalBuffer + + " Avoid executing the modeline in the current buffer after the autocommand. + + let currentBuffer = bufnr('%') + let saveModeline = getbufvar(currentBuffer, '&modeline') + try + call setbufvar(currentBuffer, '&modeline', 0) + silent do HGCommand User HGVimDiffFinish + finally + call setbufvar(currentBuffer, '&modeline', saveModeline) + endtry + return resultBuffer + finally + let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning - 1 + endtry +endfunction + +" Section: Command definitions {{{1 +" Section: Primary commands {{{2 +com! HGAdd call HGAdd() +com! -nargs=? HGAnnotate call HGAnnotate() +com! -bang -nargs=? HGCommit call HGCommit(, ) +com! -nargs=* HGDiff call HGDiff() +com! -bang HGGotoOriginal call HGGotoOriginal() +com! -nargs=? HGLog call HGLog() +com! HGRevert call HGRevert() +com! -nargs=? HGReview call HGReview() +com! HGStatus call HGStatus() +com! HGUpdate call HGUpdate() +com! -nargs=* HGVimDiff call HGVimDiff() + +" Section: HG buffer management commands {{{2 +com! HGDisableBufferSetup call HGDisableBufferSetup() +com! HGEnableBufferSetup call HGEnableBufferSetup() + +" Allow reloading hgcommand.vim +com! HGReload unlet! g:loaded_hgcommand | runtime plugin/hgcommand.vim + +" Section: Plugin command mappings {{{1 +nnoremap HGAdd :HGAdd +nnoremap HGAnnotate :HGAnnotate +nnoremap HGCommit :HGCommit +nnoremap HGDiff :HGDiff +nnoremap HGGotoOriginal :HGGotoOriginal +nnoremap HGClearAndGotoOriginal :HGGotoOriginal! +nnoremap HGLog :HGLog +nnoremap HGRevert :HGRevert +nnoremap HGReview :HGReview +nnoremap HGStatus :HGStatus +nnoremap HGUpdate :HGUpdate +nnoremap HGVimDiff :HGVimDiff + +" Section: Default mappings {{{1 +if !hasmapto('HGAdd') + nmap hga HGAdd +endif +if !hasmapto('HGAnnotate') + nmap hgn HGAnnotate +endif +if !hasmapto('HGClearAndGotoOriginal') + nmap hgG HGClearAndGotoOriginal +endif +if !hasmapto('HGCommit') + nmap hgc HGCommit +endif +if !hasmapto('HGDiff') + nmap hgd HGDiff +endif +if !hasmapto('HGGotoOriginal') + nmap hgg HGGotoOriginal +endif +if !hasmapto('HGLog') + nmap hgl HGLog +endif +if !hasmapto('HGRevert') + nmap hgq HGRevert +endif +if !hasmapto('HGReview') + nmap hgr HGReview +endif +if !hasmapto('HGStatus') + nmap hgs HGStatus +endif +if !hasmapto('HGUpdate') + nmap hgu HGUpdate +endif +if !hasmapto('HGVimDiff') + nmap hgv HGVimDiff +endif + +" Section: Menu items {{{1 +silent! aunmenu Plugin.HG +amenu &Plugin.HG.&Add HGAdd +amenu &Plugin.HG.A&nnotate HGAnnotate +amenu &Plugin.HG.&Commit HGCommit +amenu &Plugin.HG.&Diff HGDiff +amenu &Plugin.HG.&Log HGLog +amenu &Plugin.HG.Revert HGRevert +amenu &Plugin.HG.&Review HGReview +amenu &Plugin.HG.&Status HGStatus +amenu &Plugin.HG.&Update HGUpdate +amenu &Plugin.HG.&VimDiff HGVimDiff + +" Section: Autocommands to restore vimdiff state {{{1 +function! s:HGVimDiffRestore(vimDiffBuff) + let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning + 1 + try + if exists("s:vimDiffSourceBuffer") + if a:vimDiffBuff == s:vimDiffSourceBuffer + " Original file is being removed. + unlet! s:vimDiffSourceBuffer + unlet! s:vimDiffBufferCount + unlet! s:vimDiffRestoreCmd + unlet! s:vimDiffScratchList + elseif match(s:vimDiffScratchList, '{' . a:vimDiffBuff . '}') >= 0 + let s:vimDiffScratchList = substitute(s:vimDiffScratchList, '{' . a:vimDiffBuff . '}', '', '') + let s:vimDiffBufferCount = s:vimDiffBufferCount - 1 + if s:vimDiffBufferCount == 1 && exists('s:vimDiffRestoreCmd') + " All scratch buffers are gone, reset the original. + " Only restore if the source buffer is still in Diff mode + + let sourceWinNR=bufwinnr(s:vimDiffSourceBuffer) + if sourceWinNR != -1 + " The buffer is visible in at least one window + let currentWinNR = winnr() + while winbufnr(sourceWinNR) != -1 + if winbufnr(sourceWinNR) == s:vimDiffSourceBuffer + execute sourceWinNR . 'wincmd w' + if getwinvar('', "&diff") + execute s:vimDiffRestoreCmd + endif + endif + let sourceWinNR = sourceWinNR + 1 + endwhile + execute currentWinNR . 'wincmd w' + else + " The buffer is hidden. It must be visible in order to set the + " diff option. + let currentBufNR = bufnr('') + execute "hide buffer" s:vimDiffSourceBuffer + if getwinvar('', "&diff") + execute s:vimDiffRestoreCmd + endif + execute "hide buffer" currentBufNR + endif + + unlet s:vimDiffRestoreCmd + unlet s:vimDiffSourceBuffer + unlet s:vimDiffBufferCount + unlet s:vimDiffScratchList + elseif s:vimDiffBufferCount == 0 + " All buffers are gone. + unlet s:vimDiffSourceBuffer + unlet s:vimDiffBufferCount + unlet s:vimDiffScratchList + endif + endif + endif + finally + let s:HGCommandEditFileRunning = s:HGCommandEditFileRunning - 1 + endtry +endfunction + +augroup HGVimDiffRestore + au! + au BufUnload * call HGVimDiffRestore(expand("")) +augroup END + +" Section: Optional activation of buffer management {{{1 + +if s:HGGetOption('HGCommandEnableBufferSetup', 1) + call HGEnableBufferSetup() +endif + +" Section: Doc installation {{{1 + +if HGInstallDocumentation(expand(":p")) + echomsg s:script_name s:script_version . ": updated documentation" +endif + +" Section: Plugin completion {{{1 + +" delete one-time vars and functions +delfunction HGInstallDocumentation +delfunction HGFlexiMkdir +delfunction HGCleanupOnFailure +unlet s:script_version s:script_name + +let g:loaded_hgcommand=2 +silent do HGCommand User HGPluginFinish + +let &cpo = s:save_cpo +unlet s:save_cpo +" vim:se expandtab sts=2 sw=2: +finish + +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" Section: Documentation content {{{1 +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +=== START_DOC +*hgcommand.txt* Mercurial vim integration #version# + + + HGCOMMAND REFERENCE MANUAL~ + + +Author: Mathieu Clabaut +Credits: Bob Hiestand +Mercurial: http://mercurial.selenic.com/ + Mercurial (noted Hg) is a fast, lightweight Source Control Management + system designed for efficient handling of very large distributed projects. + +============================================================================== +1. Contents *hgcommand-contents* + + Installation : |hgcommand-install| + HGCommand Intro : |hgcommand| + HGCommand Manual : |hgcommand-manual| + Customization : |hgcommand-customize| + Bugs : |hgcommand-bugs| + +============================================================================== +2. HGCommand Installation *hgcommand-install* + + In order to install the plugin, place the hgcommand.vim file into a plugin' + directory in your runtime path (please see |add-global-plugin| and + |'runtimepath'|. + + HGCommand may be customized by setting variables, creating maps, and + specifying event handlers. Please see |hgcommand-customize| for more + details. + + *hgcommand-auto-help* + The help file is automagically generated when the |hgcommand| script is + loaded for the first time. + +============================================================================== + +3. HGCommand Intro *hgcommand* + *hgcommand-intro* + + The HGCommand plugin provides global ex commands for manipulating + HG-controlled source files. In general, each command operates on the + current buffer and accomplishes a separate hg function, such as update, + commit, log, and others (please see |hgcommand-commands| for a list of all + available commands). The results of each operation are displayed in a + scratch buffer. Several buffer variables are defined for those scratch + buffers (please see |hgcommand-buffer-variables|). + + The notion of "current file" means either the current buffer, or, in the + case of a directory buffer, the file on the current line within the buffer. + + For convenience, any HGCommand invoked on a HGCommand scratch buffer acts + as though it was invoked on the original file and splits the screen so that + the output appears in a new window. + + Many of the commands accept revisions as arguments. By default, most + operate on the most recent revision on the current branch if no revision is + specified (though see |HGCommandInteractive| to prompt instead). + + Each HGCommand is mapped to a key sequence starting with the + keystroke. The default mappings may be overridden by supplying different + mappings before the plugin is loaded, such as in the vimrc, in the standard + fashion for plugin mappings. For examples, please see + |hgcommand-mappings-override|. + + The HGCommand plugin may be configured in several ways. For more details, + please see |hgcommand-customize|. + +============================================================================== +4. HGCommand Manual *hgcommand-manual* + +4.1 HGCommand commands *hgcommand-commands* + + HGCommand defines the following commands: + + |:HGAdd| + |:HGAnnotate| + |:HGCommit| + |:HGDiff| + |:HGGotoOriginal| + |:HGLog| + |:HGRevert| + |:HGReview| + |:HGStatus| + |:HGUpdate| + |:HGVimDiff| + +:HGAdd *:HGAdd* + + This command performs "hg add" on the current file. Please note, this does + not commit the newly-added file. + +:HGAnnotate *:HGAnnotate* + + This command performs "hg annotate" on the current file. If an argument is + given, the argument is used as a revision number to display. If not given + an argument, it uses the most recent version of the file on the current + branch. Additionally, if the current buffer is a HGAnnotate buffer + already, the version number on the current line is used. + + If the |HGCommandAnnotateParent| variable is set to a non-zero value, the + version previous to the one on the current line is used instead. This + allows one to navigate back to examine the previous version of a line. + + The filetype of the HGCommand scratch buffer is set to 'HGAnnotate', to + take advantage of the bundled syntax file. + + +:HGCommit[!] *:HGCommit* + + If called with arguments, this performs "hg commit" using the arguments as + the log message. + + If '!' is used with no arguments, an empty log message is committed. + + If called with no arguments, this is a two-step command. The first step + opens a buffer to accept a log message. When that buffer is written, it is + automatically closed and the file is committed using the information from + that log message. The commit can be abandoned if the log message buffer is + deleted or wiped before being written. + + Alternatively, the mapping that is used to invoke :HGCommit (by default + hgc) can be used in the log message buffer to immediately commit. + This is useful if the |HGCommandCommitOnWrite| variable is set to 0 to + disable the normal commit-on-write behavior. + +:HGDiff *:HGDiff* + + With no arguments, this performs "hg diff" on the current file against the + current repository version. + + With one argument, "hg diff" is performed on the current file against the + specified revision. + + With two arguments, hg diff is performed between the specified revisions of + the current file. + + This command uses the 'HGCommandDiffOpt' variable to specify diff options. + If that variable does not exist, then 'wbBc' is assumed. If you wish to + have no options, then set it to the empty string. + + +:HGGotoOriginal *:HGGotoOriginal* + + This command returns the current window to the source buffer, if the + current buffer is a HG command output buffer. + +:HGGotoOriginal! + + Like ":HGGotoOriginal" but also executes :bufwipeout on all HG command + output buffers for the source buffer. + +:HGLog *:HGLog* + + Performs "hg log" on the current file. + + If an argument is given, it is passed as an argument to the "-r" option of + "hg log". + +:HGRevert *:HGRevert* + + Replaces the current file with the most recent version from the repository + in order to wipe out any undesired changes. + +:HGReview *:HGReview* + + Retrieves a particular version of the current file. If no argument is + given, the most recent version of the file on the current branch is + retrieved. Otherwise, the specified version is retrieved. + +:HGStatus *:HGStatus* + + Performs "hg status" on the current file. + +:HGUpdate *:HGUpdate* + + Performs "hg update" on the current file. This intentionally does not + automatically reload the current buffer, though vim should prompt the user + to do so if the underlying file is altered by this command. + +:HGVimDiff *:HGVimDiff* + + With no arguments, this prompts the user for a revision and then uses + vimdiff to display the differences between the current file and the + specified revision. If no revision is specified, the most recent version + of the file on the current branch is used. + + With one argument, that argument is used as the revision as above. With + two arguments, the differences between the two revisions is displayed using + vimdiff. + + With either zero or one argument, the original buffer is used to perform + the vimdiff. When the other buffer is closed, the original buffer will be + returned to normal mode. + + Once vimdiff mode is started using the above methods, additional vimdiff + buffers may be added by passing a single version argument to the command. + There may be up to 4 vimdiff buffers total. + + Using the 2-argument form of the command resets the vimdiff to only those 2 + versions. Additionally, invoking the command on a different file will + close the previous vimdiff buffers. + + +4.2 Mappings *hgcommand-mappings* + + By default, a mapping is defined for each command. These mappings execute + the default (no-argument) form of each command. + + hga HGAdd + hgn HGAnnotate + hgc HGCommit + hgd HGDiff + hgg HGGotoOriginal + hgG HGGotoOriginal! + hgl HGLog + hgr HGReview + hgs HGStatus + hgu HGUpdate + hgv HGVimDiff + + *hgcommand-mappings-override* + + The default mappings can be overriden by user-provided instead by mapping + to CommandName. This is especially useful when these mappings + collide with other existing mappings (vim will warn of this during plugin + initialization, but will not clobber the existing mappings). + + For instance, to override the default mapping for :HGAdd to set it to + '\add', add the following to the vimrc: > + + nmap \add HGAdd +< +4.3 Automatic buffer variables *hgcommand-buffer-variables* + + Several buffer variables are defined in each HGCommand result buffer. + These may be useful for additional customization in callbacks defined in + the event handlers (please see |hgcommand-events|). + + The following variables are automatically defined: + +b:hgOrigBuffNR *b:hgOrigBuffNR* + + This variable is set to the buffer number of the source file. + +b:hgcmd *b:hgcmd* + + This variable is set to the name of the hg command that created the result + buffer. +============================================================================== + +5. Configuration and customization *hgcommand-customize* + *hgcommand-config* + + The HGCommand plugin can be configured in two ways: by setting + configuration variables (see |hgcommand-options|) or by defining HGCommand + event handlers (see |hgcommand-events|). Additionally, the HGCommand + plugin provides several option for naming the HG result buffers (see + |hgcommand-naming|) and supported a customized status line (see + |hgcommand-statusline| and |hgcommand-buffer-management|). + +5.1 HGCommand configuration variables *hgcommand-options* + + Several variables affect the plugin's behavior. These variables are + checked at time of execution, and may be defined at the window, buffer, or + global level and are checked in that order of precedence. + + + The following variables are available: + + |HGCommandAnnotateParent| + |HGCommandCommitOnWrite| + |HGCommandHGExec| + |HGCommandDeleteOnHide| + |HGCommandDiffOpt| + |HGCommandDiffSplit| + |HGCommandEdit| + |HGCommandEnableBufferSetup| + |HGCommandInteractive| + |HGCommandNameMarker| + |HGCommandNameResultBuffers| + |HGCommandSplit| + +HGCommandAnnotateParent *HGCommandAnnotateParent* + + This variable, if set to a non-zero value, causes the zero-argument form of + HGAnnotate when invoked on a HGAnnotate buffer to go to the version + previous to that displayed on the current line. If not set, it defaults to + 0. + +HGCommandCommitOnWrite *HGCommandCommitOnWrite* + + This variable, if set to a non-zero value, causes the pending hg commit to + take place immediately as soon as the log message buffer is written. If + set to zero, only the HGCommit mapping will cause the pending commit to + occur. If not set, it defaults to 1. + +HGCommandHGExec *HGCommandHGExec* + + This variable controls the executable used for all HG commands. If not + set, it defaults to "hg". + +HGCommandDeleteOnHide *HGCommandDeleteOnHide* + + This variable, if set to a non-zero value, causes the temporary HG result + buffers to automatically delete themselves when hidden. + +HGCommandDiffOpt *HGCommandDiffOpt* + + This variable, if set, determines the options passed to the diff command of + HG. If not set, it defaults to 'w'. + +HGCommandDiffSplit *HGCommandDiffSplit* + + This variable overrides the |HGCommandSplit| variable, but only for buffers + created with |:HGVimDiff|. + +HGCommandEdit *HGCommandEdit* + + This variable controls whether the original buffer is replaced ('edit') or + split ('split'). If not set, it defaults to 'edit'. + +HGCommandEnableBufferSetup *HGCommandEnableBufferSetup* + + This variable, if set to a non-zero value, activates HG buffer management + mode see (|hgcommand-buffer-management|). This mode means that three + buffer variables, 'HGRepository', 'HGRevision' and 'HGBranch', are set if + the file is HG-controlled. This is useful for displaying version + information in the status bar. + +HGCommandInteractive *HGCommandInteractive* + + This variable, if set to a non-zero value, causes appropriate commands (for + the moment, only |:HGReview|) to query the user for a revision to use + instead of the current revision if none is specified. + +HGCommandNameMarker *HGCommandNameMarker* + + This variable, if set, configures the special attention-getting characters + that appear on either side of the hg buffer type in the buffer name. This + has no effect unless |HGCommandNameResultBuffers| is set to a true value. + If not set, it defaults to '_'. + +HGCommandNameResultBuffers *HGCommandNameResultBuffers* + + This variable, if set to a true value, causes the hg result buffers to be + named in the old way (' __'). If not set or + set to a false value, the result buffer is nameless. + +HGCommandSplit *HGCommandSplit* + + This variable controls the orientation of the various window splits that + may occur (such as with HGVimDiff, when using a HG command on a HG command + buffer, or when the |HGCommandEdit| variable is set to 'split'. If set to + 'horizontal', the resulting windows will be on stacked on top of one + another. If set to 'vertical', the resulting windows will be side-by-side. + If not set, it defaults to 'horizontal' for all but HGVimDiff windows. + +5.2 HGCommand events *hgcommand-events* + + For additional customization, HGCommand can trigger user-defined events. + Event handlers are provided by defining User event autocommands (see + |autocommand|, |User|) in the HGCommand group with patterns matching the + event name. + + For instance, the following could be added to the vimrc to provide a 'q' + mapping to quit a HGCommand scratch buffer: > + + augroup HGCommand + au HGCommand User HGBufferCreated silent! nmap q: + bwipeout + augroup END +< + + The following hooks are available: + +HGBufferCreated This event is fired just after a hg command result + buffer is created and filled with the result of a hg + command. It is executed within the context of the HG + command buffer. The HGCommand buffer variables may be + useful for handlers of this event (please see + |hgcommand-buffer-variables|). + +HGBufferSetup This event is fired just after HG buffer setup occurs, + if enabled. + +HGPluginInit This event is fired when the HGCommand plugin first + loads. + +HGPluginFinish This event is fired just after the HGCommand plugin + loads. + +HGVimDiffFinish This event is fired just after the HGVimDiff command + executes to allow customization of, for instance, + window placement and focus. + +5.3 HGCommand buffer naming *hgcommand-naming* + + By default, the buffers containing the result of HG commands are nameless + scratch buffers. It is intended that buffer variables of those buffers be + used to customize the statusline option so that the user may fully control + the display of result buffers. + + If the old-style naming is desired, please enable the + |HGCommandNameResultBuffers| variable. Then, each result buffer will + receive a unique name that includes the source file name, the HG command, + and any extra data (such as revision numbers) that were part of the + command. + +5.4 HGCommand status line support *hgcommand-statusline* + + It is intended that the user will customize the |'statusline'| option to + include HG result buffer attributes. A sample function that may be used in + the |'statusline'| option is provided by the plugin, HGGetStatusLine(). In + order to use that function in the status line, do something like the + following: > + + set statusline=%<%f\ %{HGGetStatusLine()}\ %h%m%r%=%l,%c%V\ %P +< + of which %{HGGetStatusLine()} is the relevant portion. + + The sample HGGetStatusLine() function handles both HG result buffers and + HG-managed files if HGCommand buffer management is enabled (please see + |hgcommand-buffer-management|). + +5.5 HGCommand buffer management *hgcommand-buffer-management* + + The HGCommand plugin can operate in buffer management mode, which means + that it attempts to set two buffer variables ('HGRevision' and 'HGBranch') + upon entry into a buffer. This is rather slow because it means that 'hg + status' will be invoked at each entry into a buffer (during the |BufEnter| + autocommand). + + This mode is enabled by default. In order to disable it, set the + |HGCommandEnableBufferSetup| variable to a false (zero) value. Enabling + this mode simply provides the buffer variables mentioned above. The user + must explicitly include those in the |'statusline'| option if they are to + appear in the status line (but see |hgcommand-statusline| for a simple way + to do that). + +============================================================================== +9. Tips *hgcommand-tips* + +9.1 Split window annotation, by Michael Anderson > + + :nmap hgN :vshhgn:vertical res 40 + \ggdddd:set scb:set nowraplgg:set scb + \:set nowrap +< + + This splits the buffer vertically, puts an annotation on the left (minus + the header) with the width set to 40. An editable/normal copy is placed on + the right. The two versions are scroll locked so they move as one. and + wrapping is turned off so that the lines line up correctly. The advantages + are... + + 1) You get a versioning on the right. + 2) You can still edit your own code. + 3) Your own code still has syntax highlighting. + +============================================================================== + +8. Known bugs *hgcommand-bugs* + + Please let me know if you run across any. + + HGVimDiff, when using the original (real) source buffer as one of the diff + buffers, uses some hacks to try to restore the state of the original buffer + when the scratch buffer containing the other version is destroyed. There + may still be bugs in here, depending on many configuration details. + +============================================================================== + +9. TODO *hgcommand-todo* + + Integrate symlink tracking once HG will support them. +============================================================================== +=== END_DOC +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +" v im:tw=78:ts=8:ft=help:norl: +" vim600: set foldmethod=marker tabstop=8 shiftwidth=2 softtabstop=2 smartindent smarttab : +"fileencoding=iso-8859-15 diff --git a/sys/src/cmd/hg/contrib/vim/patchreview.txt b/sys/src/cmd/hg/contrib/vim/patchreview.txt new file mode 100644 index 000000000..47bce4764 --- /dev/null +++ b/sys/src/cmd/hg/contrib/vim/patchreview.txt @@ -0,0 +1,97 @@ +*patchreview.txt* Vim global plugin for doing single or multipatch code reviews + + Author: Manpreet Singh (junkblocker-CAT-yahoo-DOG-com) + (Replace -CAT- and -DOG- with @ and . first) + Copyright (C) 2006 by Manpreet Singh + License : This file is placed in the public domain. + +============================================================================= + +CONTENTS *patchreview* *patchreview-contents* + + 1. Contents.........................................: |patchreview-contents| + 2. Introduction.....................................: |patchreview-intro| + 3. PatchReview options..............................: |patchreview-options| + 4. PatchReview Usage................................: |patchreview-usage| + 4.1 PatchReview Usage............................: |:PatchReview| + 4.2 PatchReview Usage............................: |:PatchReviewCleanup| + +============================================================================= + +PatchReview Introduction *patchreview-intro* + +The Patch Review plugin allows single or multipatch code review to be done in +VIM. VIM provides the |:diffpatch| command to do single file reviews but can +not handle patch files containing multiple patches as is common with software +development projects. This plugin provides that missing functionality. It also +tries to improve on |:diffpatch|'s behaviour of creating the patched files in +the same directory as original file which can lead to project workspace +pollution. + +============================================================================= + +PatchReview Options *patchreview-options* + + g:patchreview_filterdiff : Optional path to filterdiff binary. PatchReview + tries to locate filterdiff on system path + automatically. If the binary is not on system + path, this option tell PatchReview the full path + to the binary. This option, if specified, + overrides the default filterdiff binary on the + path. + + examples: + (On Windows with Cygwin) + + let g:patchreview_filterdiff = 'c:\\cygwin\\bin\\filterdiff.exe' + + (On *nix systems) + + let g:patchreview_filterdiff = '/usr/bin/filterdiff' + + g:patchreview_patch : Optional path to patch binary. PatchReview tries + to locate patch on system path automatically. If + the binary is not on system path, this option + tell PatchReview the full path to the binary. + This option, if specified, overrides the default + patch binary on the path. + + examples: + (On Windows with Cygwin) + + let g:patchreview_patch = 'c:\\cygwin\\bin\\patch.exe' + + (On *nix systems) + + let g:patchreview_patch = '/usr/bin/gpatch' + + + g:patchreview_tmpdir : Optional path where the plugin can save temporary + files. If this is not specified, the plugin tries to + use TMP, TEMP and TMPDIR environment variables in + succession. + + examples: + (On Windows) let g:patchreview_tmpdir = 'c:\\tmp' + (On *nix systems) let g:patchreview_tmpdir = '~/tmp' + +============================================================================= + +PatchReview Usage *patchreview-usage* + *:PatchReview* + + :PatchReview patchfile_path [optional_source_directory] + + Perform a patch review in the current directory based on the supplied + patchfile_path. If optional_source_directory is specified, patchreview is + done on that directory. Othewise, the current directory is assumed to be + the source directory. + *:PatchReviewCleanup* + + :PatchReviewCleanup + + After you are done using the :PatchReview command, you can cleanup the + temporary files in the temporary directory using this command. + +============================================================================= +vim: ft=help:ts=2:sts=2:sw=2:tw=78:tw=78 diff --git a/sys/src/cmd/hg/contrib/vim/patchreview.vim b/sys/src/cmd/hg/contrib/vim/patchreview.vim new file mode 100644 index 000000000..6235eeadd --- /dev/null +++ b/sys/src/cmd/hg/contrib/vim/patchreview.vim @@ -0,0 +1,332 @@ +" Vim global plugin for doing single or multipatch code reviews"{{{ + +" Version : 0.1 "{{{ +" Last Modified : Thu 25 May 2006 10:15:11 PM PDT +" Author : Manpreet Singh (junkblocker AT yahoo DOT com) +" Copyright : 2006 by Manpreet Singh +" License : This file is placed in the public domain. +" +" History : 0.1 - First released +"}}} +" Documentation: "{{{ +" =========================================================================== +" This plugin allows single or multipatch code reviews to be done in VIM. Vim +" has :diffpatch command to do single file reviews but can not handle patch +" files containing multiple patches. This plugin provides that missing +" functionality and doesn't require the original file to be open. +" +" Installing: "{{{ +" +" For a quick start... +" +" Requirements: "{{{ +" +" 1) (g)vim 7.0 or higher built with +diff option. +" 2) patch and patchutils ( http://cyberelk.net/tim/patchutils/ ) installed +" for your OS. For windows it is availble from Cygwin ( +" http://www.cygwin.com ) or GnuWin32 ( http://gnuwin32.sourceforge.net/ +" ). +""}}} +" Install: "{{{ +" +" 1) Extract this in your $VIM/vimfiles or $HOME/.vim directory and restart +" vim. +" +" 2) Make sure that you have filterdiff from patchutils and patch commands +" installed. +" +" 3) Optinally, specify the locations to filterdiff and patch commands and +" location of a temporary directory to use in your .vimrc. +" +" let g:patchreview_filterdiff = '/path/to/filterdiff' +" let g:patchreview_patch = '/path/to/patch' +" let g:patchreview_tmpdir = '/tmp/or/something' +" +" 4) Optionally, generate help tags to use help +" +" :helptags ~/.vim/doc +" or +" :helptags c:\vim\vimfiles\doc +""}}} +""}}} +" Usage: "{{{ +" +" :PatchReview path_to_submitted_patchfile [optional_source_directory] +" +" after review is done +" +" :PatchReviewCleanup +" +" See :help patchreview for details after you've created help tags. +""}}} +"}}} +" Code "{{{ + +" Enabled only during development "{{{ +" unlet! g:loaded_patchreview " DEBUG +" unlet! g:patchreview_tmpdir " DEBUG +" unlet! g:patchreview_filterdiff " DEBUG +" unlet! g:patchreview_patch " DEBUG +"}}} + +" load only once "{{{ +if exists('g:loaded_patchreview') + finish +endif +let g:loaded_patchreview=1 +let s:msgbufname = 'Patch Review Messages' +"}}} + +function! PR_wipeMsgBuf() "{{{ + let s:winnum = bufwinnr(s:msgbufname) + if s:winnum != -1 " If the window is already open, jump to it + let s:cur_winnr = winnr() + if winnr() != s:winnum + exe s:winnum . 'wincmd w' + exe 'bw' + exe s:cur_winnr . 'wincmd w' + endif + endif +endfunction +"}}} + +function! PR_echo(...) "{{{ + " Usage: PR_echo(msg, [return_to_original_window_flag]) + " default return_to_original_window_flag = 0 + " + let s:cur_winnr = winnr() + let s:winnum = bufwinnr(s:msgbufname) + if s:winnum != -1 " If the window is already open, jump to it + if winnr() != s:winnum + exe s:winnum . 'wincmd w' + endif + else + let s:bufnum = bufnr(s:msgbufname) + if s:bufnum == -1 + let s:wcmd = s:msgbufname + else + let s:wcmd = '+buffer' . s:bufnum + endif + exe 'silent! botright 5split ' . s:wcmd + endif + setlocal modifiable + setlocal buftype=nofile + setlocal bufhidden=delete + setlocal noswapfile + setlocal nowrap + setlocal nobuflisted + if a:0 != 0 + silent! $put =a:1 + endif + exe ':$' + setlocal nomodifiable + if a:0 > 1 && a:2 + exe s:cur_winnr . 'wincmd w' + endif +endfunction +"}}} + +function! PR_checkBinary(BinaryName) "{{{ + " Verify that BinaryName is specified or available + if ! exists('g:patchreview_' . a:BinaryName) + if executable(a:BinaryName) + let g:patchreview_{a:BinaryName} = a:BinaryName + return 1 + else + call s:PR_echo('g:patchreview_' . a:BinaryName . ' is not defined and could not be found on path. Please define it in your .vimrc.') + return 0 + endif + elseif ! executable(g:patchreview_{a:BinaryName}) + call s:PR_echo('Specified g:patchreview_' . a:BinaryName . ' [' . g:patchreview_{a.BinaryName} . '] is not executable.') + return 0 + else + return 1 + endif +endfunction +"}}} + +function! PR_GetTempDirLocation(Quiet) "{{{ + if exists('g:patchreview_tmpdir') + if ! isdirectory(g:patchreview_tmpdir) || ! filewritable(g:patchreview_tmpdir) + if ! a:Quiet + call s:PR_echo('Temporary directory specified by g:patchreview_tmpdir [' . g:patchreview_tmpdir . '] is not accessible.') + return 0 + endif + endif + elseif exists("$TMP") && isdirectory($TMP) && filewritable($TMP) + let g:patchreview_tmpdir = $TMP + elseif exists("$TEMP") && isdirectory($TEMP) && filewritable($TEMP) + let g:patchreview_tmpdir = $TEMP + elseif exists("$TMPDIR") && isdirectory($TMPDIR) && filewritable($TMPDIR) + let g:patchreview_tmpdir = $TMPDIR + else + if ! a:Quiet + call s:PR_echo('Could not figure out a temporary directory to use. Please specify g:patchreview_tmpdir in your .vimrc.') + return 0 + endif + endif + let g:patchreview_tmpdir = g:patchreview_tmpdir . '/' + let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '\\', '/', 'g') + let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/+$', '/', '') + if has('win32') + let g:patchreview_tmpdir = substitute(g:patchreview_tmpdir, '/', '\\', 'g') + endif + return 1 +endfunction +"}}} + +function! PatchReview(...) "{{{ + " VIM 7+ required"{{{ + if version < 700 + call s:PR_echo('This plugin needs VIM 7 or higher') + return + endif +"}}} + + let s:save_shortmess = &shortmess + set shortmess+=aW + call s:PR_wipeMsgBuf() + + " Check passed arguments "{{{ + if a:0 == 0 + call s:PR_echo('PatchReview command needs at least one argument specifying a patchfile path.') + let &shortmess = s:save_shortmess + return + endif + if a:0 >= 1 && a:0 <= 2 + let s:PatchFilePath = expand(a:1, ':p') + if ! filereadable(s:PatchFilePath) + call s:PR_echo('File [' . s:PatchFilePath . '] is not accessible.') + let &shortmess = s:save_shortmess + return + endif + if a:0 == 2 + let s:SrcDirectory = expand(a:2, ':p') + if ! isdirectory(s:SrcDirectory) + call s:PR_echo('[' . s:SrcDirectory . '] is not a directory') + let &shortmess = s:save_shortmess + return + endif + try + exe 'cd ' . s:SrcDirectory + catch /^.*E344.*/ + call s:PR_echo('Could not change to directory [' . s:SrcDirectory . ']') + let &shortmess = s:save_shortmess + return + endtry + endif + else + call s:PR_echo('PatchReview command needs at most two arguments: patchfile path and optional source directory path.') + let &shortmess = s:save_shortmess + return + endif +"}}} + + " Verify that filterdiff and patch are specified or available "{{{ + if ! s:PR_checkBinary('filterdiff') || ! s:PR_checkBinary('patch') + let &shortmess = s:save_shortmess + return + endif + + let s:retval = s:PR_GetTempDirLocation(0) + if ! s:retval + let &shortmess = s:save_shortmess + return + endif +"}}} + + " Requirements met, now execute "{{{ + let s:PatchFilePath = fnamemodify(s:PatchFilePath, ':p') + call s:PR_echo('Patch file : ' . s:PatchFilePath) + call s:PR_echo('Source directory: ' . getcwd()) + call s:PR_echo('------------------') + let s:theFilterDiffCommand = '' . g:patchreview_filterdiff . ' --list -s ' . s:PatchFilePath + let s:theFilesString = system(s:theFilterDiffCommand) + let s:theFilesList = split(s:theFilesString, '[\r\n]') + for s:filewithchangetype in s:theFilesList + if s:filewithchangetype !~ '^[!+-] ' + call s:PR_echo('*** Skipping review generation due to understood change for [' . s:filewithchangetype . ']', 1) + continue + endif + unlet! s:RelativeFilePath + let s:RelativeFilePath = substitute(s:filewithchangetype, '^. ', '', '') + let s:RelativeFilePath = substitute(s:RelativeFilePath, '^[a-z][^\\\/]*[\\\/]' , '' , '') + if s:filewithchangetype =~ '^! ' + let s:msgtype = 'Modification : ' + elseif s:filewithchangetype =~ '^+ ' + let s:msgtype = 'Addition : ' + elseif s:filewithchangetype =~ '^- ' + let s:msgtype = 'Deletion : ' + endif + let s:bufnum = bufnr(s:RelativeFilePath) + if buflisted(s:bufnum) && getbufvar(s:bufnum, '&mod') + call s:PR_echo('Old buffer for file [' . s:RelativeFilePath . '] exists in modified state. Skipping review.', 1) + continue + endif + let s:tmpname = substitute(s:RelativeFilePath, '/', '_', 'g') + let s:tmpname = substitute(s:tmpname, '\\', '_', 'g') + let s:tmpname = g:patchreview_tmpdir . 'PatchReview.' . s:tmpname . '.' . strftime('%Y%m%d%H%M%S') + if has('win32') + let s:tmpname = substitute(s:tmpname, '/', '\\', 'g') + endif + if ! exists('s:patchreview_tmpfiles') + let s:patchreview_tmpfiles = [] + endif + let s:patchreview_tmpfiles = s:patchreview_tmpfiles + [s:tmpname] + + let s:filterdiffcmd = '!' . g:patchreview_filterdiff . ' -i ' . s:RelativeFilePath . ' ' . s:PatchFilePath . ' > ' . s:tmpname + silent! exe s:filterdiffcmd + if s:filewithchangetype =~ '^+ ' + if has('win32') + let s:inputfile = 'nul' + else + let s:inputfile = '/dev/null' + endif + else + let s:inputfile = expand(s:RelativeFilePath, ':p') + endif + silent exe '!' . g:patchreview_patch . ' -o ' . s:tmpname . '.file ' . s:inputfile . ' < ' . s:tmpname + let s:origtabpagenr = tabpagenr() + silent! exe 'tabedit ' . s:RelativeFilePath + silent! exe 'vert diffsplit ' . s:tmpname . '.file' + if filereadable(s:tmpname . '.file.rej') + silent! exe 'topleft 5split ' . s:tmpname . '.file.rej' + call s:PR_echo(s:msgtype . '*** REJECTED *** ' . s:RelativeFilePath, 1) + else + call s:PR_echo(s:msgtype . ' ' . s:RelativeFilePath, 1) + endif + silent! exe 'tabn ' . s:origtabpagenr + endfor + call s:PR_echo('-----') + call s:PR_echo('Done.') + let &shortmess = s:save_shortmess +"}}} +endfunction +"}}} + +function! PatchReviewCleanup() "{{{ + let s:retval = s:PR_GetTempDirLocation(1) + if s:retval && exists('g:patchreview_tmpdir') && isdirectory(g:patchreview_tmpdir) && filewritable(g:patchreview_tmpdir) + let s:zefilestr = globpath(g:patchreview_tmpdir, 'PatchReview.*') + let s:theFilesList = split(s:zefilestr, '\m[\r\n]\+') + for s:thefile in s:theFilesList + call delete(s:thefile) + endfor + endif +endfunction +"}}} + +" Commands "{{{ +"============================================================================ +" :PatchReview +command! -nargs=* -complete=file PatchReview call s:PatchReview () + + +" :PatchReviewCleanup +command! -nargs=0 PatchReviewCleanup call s:PatchReviewCleanup () +"}}} +"}}} + +" vim: textwidth=78 nowrap tabstop=2 shiftwidth=2 softtabstop=2 expandtab +" vim: filetype=vim encoding=latin1 fileformat=unix foldlevel=0 foldmethod=marker +"}}} diff --git a/sys/src/cmd/hg/contrib/win32/ReadMe.html b/sys/src/cmd/hg/contrib/win32/ReadMe.html new file mode 100644 index 000000000..b5c6d0e2a --- /dev/null +++ b/sys/src/cmd/hg/contrib/win32/ReadMe.html @@ -0,0 +1,163 @@ + + + + Mercurial for Windows + + + + + +

Mercurial for Windows

+ +

Welcome to Mercurial for Windows!

+ +

+ Mercurial is a command-line application. You must run it from + the Windows command prompt (or if you're hard core, a MinGW shell). +

+ +

+ Note: the standard MinGW + msys startup script uses rxvt which has problems setting up + standard input and output. Running bash directly works + correctly. +

+ +

+ For documentation, please visit the Mercurial web site. + You can also download a free book, Mercurial: The Definitive + Guide. +

+ +

+ By default, Mercurial installs to C:\Program + Files\Mercurial. The Mercurial command is called + hg.exe. +

+ +

Testing Mercurial after you've installed it

+ +

+ The easiest way to check that Mercurial is installed properly is + to just type the following at the command prompt: +

+ +
+hg
+
+ +

+ This command should print a useful help message. If it does, + other Mercurial commands should work fine for you. +

+ +

Configuration notes

+

Default editor

+

+ The default editor for commit messages is 'notepad'. You can set + the EDITOR (or HGEDITOR) environment variable + to specify your preference or set it in mercurial.ini: +

+
+[ui]
+editor = whatever
+
+ +

Configuring a Merge program

+

+ It should be emphasized that Mercurial by itself doesn't attempt + to do a Merge at the file level, neither does it make any + attempt to Resolve the conflicts. +

+ +

+ By default, Mercurial will use the merge program defined by the + HGMERGE environment variable, or uses the one defined + in the mercurial.ini file. (see MergeProgram + on the Mercurial Wiki for more information) +

+ +

Reporting problems

+ +

+ Before you report any problems, please consult the Mercurial web site + and see if your question is already in our list of Frequently + Answered Questions (the "FAQ"). +

+ +

+ If you cannot find an answer to your question, please feel free + to send mail to the Mercurial mailing list, at mercurial@selenic.com. + Remember, the more useful information you include in your + report, the easier it will be for us to help you! +

+ +

+ If you are IRC-savvy, that's usually the fastest way to get + help. Go to #mercurial on irc.freenode.net. +

+ +

Author and copyright information

+ +

+ Mercurial was written by Matt + Mackall, and is maintained by Matt and a team of volunteers. +

+ +

+ The Windows installer was written by Bryan O'Sullivan. +

+ +

+ Mercurial is Copyright 2005-2009 Matt Mackall and others. See + the Contributors.txt file for a list of contributors. +

+ +

+ Mercurial is free software; you can redistribute it and/or + modify it under the terms of the GNU + General Public License version 2 as published by the Free + Software Foundation. +

+ +

+ Mercurial is distributed in the hope that it will be useful, but + without any warranty; without even the implied warranty + of merchantability or fitness for a particular + purpose. See the GNU General Public License for more + details. +

+ + diff --git a/sys/src/cmd/hg/contrib/win32/hg.bat b/sys/src/cmd/hg/contrib/win32/hg.bat new file mode 100644 index 000000000..3da573894 --- /dev/null +++ b/sys/src/cmd/hg/contrib/win32/hg.bat @@ -0,0 +1,12 @@ +@echo off +rem Windows Driver script for Mercurial + +setlocal +set HG=%~f0 + +rem Use a full path to Python (relative to this script) as the standard Python +rem install does not put python.exe on the PATH... +rem %~dp0 is the directory of this script + +%~dp0..\python "%~dp0hg" %* +endlocal diff --git a/sys/src/cmd/hg/contrib/win32/mercurial.ico b/sys/src/cmd/hg/contrib/win32/mercurial.ico new file mode 100644 index 000000000..046808d54 Binary files /dev/null and b/sys/src/cmd/hg/contrib/win32/mercurial.ico differ diff --git a/sys/src/cmd/hg/contrib/win32/mercurial.ini b/sys/src/cmd/hg/contrib/win32/mercurial.ini new file mode 100644 index 000000000..b8ec7d1b5 --- /dev/null +++ b/sys/src/cmd/hg/contrib/win32/mercurial.ini @@ -0,0 +1,124 @@ +; System-wide Mercurial config file. +; +; !!! Do Not Edit This File !!! +; +; This file will be replaced by the installer on every upgrade. +; Editing this file can cause strange side effects on Vista. +; +; http://bitbucket.org/tortoisehg/stable/issue/135 +; +; To change settings you see in this file, override (or enable) them in +; your user Mercurial.ini file, where USERNAME is your Windows user name: +; +; XP or older - C:\Documents and Settings\USERNAME\Mercurial.ini +; Vista or later - C:\Users\USERNAME\Mercurial.ini + + +[ui] +; editor used to enter commit logs, etc. Most text editors will work. +editor = notepad +; show changed files and be a bit more verbose if True +; verbose = True + +; username data to appear in commits +; it usually takes the form: Joe User +; username = Joe User + +; In order to push/pull over ssh you must specify an ssh tool +;ssh = "C:\Progra~1\TortoiseSVN\bin\TortoisePlink.exe" -ssh -2 +;ssh = C:\cygwin\bin\ssh + +; +; For more information about mercurial extensions, start here +; http://www.selenic.com/mercurial/wiki/index.cgi/UsingExtensions +; +; Extensions shipped with Mercurial +; +[extensions] +;acl = +;alias = +;bookmarks = +;bugzilla = +;children = +;churn = +;color = +;convert = +;extdiff = +;fetch = +;gpg = +;graphlog = +;hgcia = +;hgk = +;highlight = +;interhg = +;keyword = +;mq = +;notify = +;pager = +;parentrevspec = +;patchbomb = +;purge = +;rebase = +;record = +;transplant = +;win32mbcs = +;win32text = +;zeroconf = + +; To use cleverencode/cleverdecode, you must enable win32text extension + +[encode] +; Encode files that don't contain NUL characters. + +; ** = cleverencode: + +; Alternatively, you can explicitly specify each file extension that +; you want encoded (any you omit will be left untouched), like this: + +; *.txt = dumbencode: + + +[decode] +; Decode files that don't contain NUL characters. + +; ** = cleverdecode: + +; Alternatively, you can explicitly specify each file extension that +; you want decoded (any you omit will be left untouched), like this: + +; **.txt = dumbdecode: + +[patch] +; If you enable win32text filtering, you will want to enable this +; line as well to allow patching to work correctly. + +; eol = crlf + + +; +; Define external diff commands +; +[extdiff] +;cmd.bc3diff = C:\Program Files\Beyond Compare 3\BCompare.exe +;cmd.vdiff = C:\Progra~1\TortoiseSVN\bin\TortoiseMerge.exe +;cmd.vimdiff = gvim.exe +;opts.vimdiff = -f '+next' '+execute "DirDiff ".argv(0)." ".argv(1)' + + +[hgk] +; Replace the following with your path to hgk, uncomment it and +; install ActiveTcl (or another win32 port like tclkit) +; path="C:\Program Files\Mercurial\Contrib\hgk.tcl" +; vdiff=vdiff + + +; +; The git extended diff format can represent binary files, file +; permission changes, and rename information that the normal patch format +; cannot describe. However it is also not compatible with tools which +; expect normal patches. so enable git patches at your own risk. +; +[diff] +;git = false +;nodates = false + diff --git a/sys/src/cmd/hg/contrib/win32/mercurial.iss b/sys/src/cmd/hg/contrib/win32/mercurial.iss new file mode 100644 index 000000000..cd3bc1c94 --- /dev/null +++ b/sys/src/cmd/hg/contrib/win32/mercurial.iss @@ -0,0 +1,103 @@ +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! +[Setup] +AppCopyright=Copyright 2005-2009 Matt Mackall and others +AppName=Mercurial +AppVerName=Mercurial snapshot +InfoAfterFile=contrib/win32/postinstall.txt +LicenseFile=COPYING +ShowLanguageDialog=yes +AppPublisher=Matt Mackall and others +AppPublisherURL=http://mercurial.selenic.com/ +AppSupportURL=http://mercurial.selenic.com/ +AppUpdatesURL=http://mercurial.selenic.com/ +AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} +AppContact=mercurial@selenic.com +OutputBaseFilename=Mercurial-snapshot +DefaultDirName={pf}\Mercurial +SourceDir=..\.. +VersionInfoDescription=Mercurial distributed SCM +VersionInfoCopyright=Copyright 2005-2009 Matt Mackall and others +VersionInfoCompany=Matt Mackall and others +InternalCompressLevel=max +SolidCompression=true +SetupIconFile=contrib\win32\mercurial.ico +AllowNoIcons=true +DefaultGroupName=Mercurial +PrivilegesRequired=none + +[Files] +Source: contrib\mercurial.el; DestDir: {app}/Contrib +Source: contrib\vim\*.*; DestDir: {app}/Contrib/Vim +Source: contrib\zsh_completion; DestDir: {app}/Contrib +Source: contrib\hgk; DestDir: {app}/Contrib; DestName: hgk.tcl +Source: contrib\win32\ReadMe.html; DestDir: {app}; Flags: isreadme +Source: contrib\mergetools.hgrc; DestDir: {tmp}; +Source: contrib\win32\mercurial.ini; DestDir: {app}; DestName: Mercurial.ini; Check: CheckFile; AfterInstall: ConcatenateFiles; +Source: contrib\win32\postinstall.txt; DestDir: {app}; DestName: ReleaseNotes.txt +Source: dist\hg.exe; DestDir: {app}; AfterInstall: Touch('{app}\hg.exe.local') +Source: dist\python*.dll; Destdir: {app}; Flags: skipifsourcedoesntexist +Source: dist\library.zip; DestDir: {app} +Source: dist\mfc*.dll; DestDir: {app} +Source: dist\msvc*.dll; DestDir: {app} +Source: dist\Microsoft.VC*.CRT.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist +Source: dist\Microsoft.VC*.MFC.manifest; DestDir: {app}; Flags: skipifsourcedoesntexist +Source: dist\w9xpopen.exe; DestDir: {app} +Source: dist\add_path.exe; DestDir: {app} +Source: doc\*.html; DestDir: {app}\Docs +Source: locale\*.*; DestDir: {app}\locale; Flags: recursesubdirs createallsubdirs +Source: templates\*.*; DestDir: {app}\Templates; Flags: recursesubdirs createallsubdirs +Source: CONTRIBUTORS; DestDir: {app}; DestName: Contributors.txt +Source: COPYING; DestDir: {app}; DestName: Copying.txt + +[INI] +Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: http://mercurial.selenic.com/ + +[UninstallDelete] +Type: files; Name: {app}\Mercurial.url + +[Icons] +Name: {group}\Uninstall Mercurial; Filename: {uninstallexe} +Name: {group}\Mercurial Command Reference; Filename: {app}\Docs\hg.1.html +Name: {group}\Mercurial Configuration Files; Filename: {app}\Docs\hgrc.5.html +Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html +Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url + +[Run] +Filename: "{app}\add_path.exe"; Parameters: "{app}"; Flags: postinstall; Description: "Add the installation path to the search path" + +[UninstallRun] +Filename: "{app}\add_path.exe"; Parameters: "/del {app}" + +[UninstallDelete] +Type: files; Name: "{app}\hg.exe.local" +[Code] +var + WriteFile: Boolean; + CheckDone: Boolean; + +function CheckFile(): Boolean; +begin + if not CheckDone then begin + WriteFile := True; + if FileExists(ExpandConstant(CurrentFileName)) then begin + WriteFile := MsgBox('' + ExpandConstant(CurrentFileName) + '' #13#13 'The file already exists.' #13#13 'Would you like Setup to overwrite it?', mbConfirmation, MB_YESNO) = idYes; + end; + CheckDone := True; + end; + Result := WriteFile; +end; + +procedure ConcatenateFiles(); +var + MergeConfigs: TArrayOfString; +begin + if LoadStringsFromFile(ExpandConstant('{tmp}\mergetools.hgrc'),MergeConfigs) then begin + SaveStringsToFile(ExpandConstant(CurrentFileName),MergeConfigs,True); + end; +end; + +procedure Touch(fn: String); +begin + SaveStringToFile(ExpandConstant(fn), '', False); +end; diff --git a/sys/src/cmd/hg/contrib/win32/postinstall.txt b/sys/src/cmd/hg/contrib/win32/postinstall.txt new file mode 100644 index 000000000..786dc4837 --- /dev/null +++ b/sys/src/cmd/hg/contrib/win32/postinstall.txt @@ -0,0 +1,9 @@ +Welcome to Mercurial for Windows! +--------------------------------- + +For configuration and usage directions, please read the ReadMe.html +file that comes with this package. + +Also check the release notes at: + + http://mercurial.selenic.com/wiki/WhatsNew diff --git a/sys/src/cmd/hg/contrib/win32/win32-build.txt b/sys/src/cmd/hg/contrib/win32/win32-build.txt new file mode 100644 index 000000000..7402658c0 --- /dev/null +++ b/sys/src/cmd/hg/contrib/win32/win32-build.txt @@ -0,0 +1,114 @@ +The standalone Windows installer for Mercurial is built in a somewhat +jury-rigged fashion. + +It has the following prerequisites, at least as I build it: + + Python for Windows + http://www.python.org/ftp/python/2.4.3/python-2.4.3.msi + + MinGW + http://www.mingw.org/ + + Python for Windows Extensions + http://sourceforge.net/projects/pywin32/ + + mfc71.dll (just download, don't install; not needed for Python 2.6) + http://starship.python.net/crew/mhammond/win32/ + + Visual C++ 2008 redistributable package (needed for Python 2.6) + http://www.microsoft.com/downloads/details.aspx?familyid=9b2da534-3e03-4391-8a4d-074b9f2bc1bf&displaylang=en + + The py2exe distutils extension + http://sourceforge.net/projects/py2exe/ + + GnuWin32 gettext utility + http://gnuwin32.sourceforge.net/packages/gettext.htm + + Inno Setup + http://www.jrsoftware.org/isinfo.php + + ISTool - optional + http://www.istool.org/default.aspx/ + + add_path (you need only add_path.exe in the zip file) + http://www.barisione.org/apps.html#add_path + + Docutils + http://docutils.sourceforge.net/ + +And, of course, Mercurial itself. + +Once you have all this installed and built, clone a copy of the +Mercurial repository you want to package, and name the repo +C:\hg\hg-release. + +In a shell, build a standalone copy of the hg.exe program: + + python setup.py build -c mingw32 + python setup.py py2exe -b 1 + +Note: the previously suggested combined command of "python setup.py build -c +mingw32 py2exe -b 1" doesn't work correctly anymore as it doesn't include the +extensions in the mercurial subdirectory. + +If you want to create a file named setup.cfg with the contents: + +[build] +compiler=mingw32 + +you can skip the first build step. + +Copy add_path.exe into the dist directory that just got created. + +If you are using Python up to version 2.5.4, copy mfc71.dll into the dist +directory that just got created. + +If you are using Python 2.6 or later, after installing the Visual C++ 2008 +redistributable package copy into the dist directory that just got created the +following files: + - from the directory starting with + Windows/WinSxS/x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8 + the files named: msvcm90.dll, msvcp90.dll and msvcr90.dll + - from the directory starting with + Windows/WinSxS/x86_Microsoft.VC90.MFC_1fc8b3b9a1e18e3b_9.0.21022.8 + the files named: mfc90.dll, mfc90u.dll, mfcm90.dll and mfcm90u.dll + - from the directory named Windows/WinSxS/Manifests, the manifest file + starting with x86_Microsoft.VC90.CRT_1fc8b3b9a1e18e3b_9.0.21022.8 + (rename it to Microsoft.VC90.CRT.manifest) and the manifest file starting + with x86_Microsoft.VC90.MFC_1fc8b3b9a1e18e3b_9.0.21022.8 (rename it to + Microsoft.VC90.MFC.manifest) + +Before building the installer, you have to build Mercurial HTML documentation +(or fix mercurial.iss to not reference the doc directory). Docutils does not +come with a ready-made script for rst2html.py, so you will have to write your +own and put it in %PATH% like: + + @python c:\pythonXX\scripts\rst2html.py %* + +Then build the documentation with: + + cd doc + mingw32-make RST2HTML=rst2html.bat html + cd .. + +If you use ISTool, you open the C:\hg\hg-release\contrib\win32\mercurial.iss +file and type Ctrl-F9 to compile the installer file. + +Otherwise you run the Inno Setup compiler. Assuming it's on the path you run: + + iscc contrib\win32\mercurial.iss + +The actual installer will be in the C:\hg\hg-release\Output directory. + +To automate the steps above you may want to create a batchfile based on the +following: + + echo [build] > setup.cfg + echo compiler=mingw32 >> setup.cfg + python setup.py py2exe -b 1 + cd doc + mingw32-make RST2HTML=rst2html.bat html + cd .. + iscc contrib\win32\mercurial.iss + +and run it from the root of the hg repository (c:\hg\hg-release). diff --git a/sys/src/cmd/hg/contrib/zsh_completion b/sys/src/cmd/hg/contrib/zsh_completion new file mode 100644 index 000000000..ef124ef6e --- /dev/null +++ b/sys/src/cmd/hg/contrib/zsh_completion @@ -0,0 +1,946 @@ +#compdef hg + +# Zsh completion script for mercurial. Rename this file to _hg and copy +# it into your zsh function path (/usr/share/zsh/site-functions for +# instance) +# +# If you do not want to install it globally, you can copy it somewhere +# else and add that directory to $fpath. This must be done before +# compinit is called. If the file is copied to ~/.zsh.d, your ~/.zshrc +# file could look like this: +# +# fpath=("$HOME/.zsh.d" $fpath) +# autoload -U compinit +# compinit +# +# Copyright (C) 2005, 2006 Steve Borho +# Copyright (C) 2006-9 Brendan Cully +# +# Permission is hereby granted, without written agreement and without +# licence or royalty fees, to use, copy, modify, and distribute this +# software and to distribute modified versions of this software for any +# purpose, provided that the above copyright notice and the following +# two paragraphs appear in all copies of this software. +# +# In no event shall the authors be liable to any party for direct, +# indirect, special, incidental, or consequential damages arising out of +# the use of this software and its documentation, even if the authors +# have been advised of the possibility of such damage. +# +# The authors specifically disclaim any warranties, including, but not +# limited to, the implied warranties of merchantability and fitness for +# a particular purpose. The software provided hereunder is on an "as +# is" basis, and the authors have no obligation to provide maintenance, +# support, updates, enhancements, or modifications. + +emulate -LR zsh +setopt extendedglob + +local curcontext="$curcontext" state line +typeset -A _hg_cmd_globals + +_hg() { + local cmd _hg_root + integer i=2 + _hg_cmd_globals=() + + while (( i < $#words )) + do + case "$words[$i]" in + -R|--repository) + eval _hg_root="$words[$i+1]" + _hg_cmd_globals+=("$words[$i]" "$_hg_root") + (( i += 2 )) + continue + ;; + -R*) + _hg_cmd_globals+="$words[$i]" + eval _hg_root="${words[$i]#-R}" + (( i++ )) + continue + ;; + --cwd|--config) + # pass along arguments to hg completer + _hg_cmd_globals+=("$words[$i]" "$words[$i+1]") + (( i += 2 )) + continue + ;; + -*) + # skip option + (( i++ )) + continue + ;; + esac + if [[ -z "$cmd" ]] + then + cmd="$words[$i]" + words[$i]=() + (( CURRENT-- )) + fi + (( i++ )) + done + + if [[ -z "$cmd" ]] + then + _arguments -s -w : $_hg_global_opts \ + ':mercurial command:_hg_commands' + return + fi + + # resolve abbreviations and aliases + if ! (( $+functions[_hg_cmd_${cmd}] )) + then + local cmdexp + (( $#_hg_cmd_list )) || _hg_get_commands + + cmdexp=$_hg_cmd_list[(r)${cmd}*] + if [[ $cmdexp == $_hg_cmd_list[(R)${cmd}*] ]] + then + # might be nice to rewrite the command line with the expansion + cmd="$cmdexp" + fi + if [[ -n $_hg_alias_list[$cmd] ]] + then + cmd=$_hg_alias_list[$cmd] + fi + fi + + curcontext="${curcontext%:*:*}:hg-${cmd}:" + + zstyle -s ":completion:$curcontext:" cache-policy update_policy + + if [[ -z "$update_policy" ]] + then + zstyle ":completion:$curcontext:" cache-policy _hg_cache_policy + fi + + if (( $+functions[_hg_cmd_${cmd}] )) + then + _hg_cmd_${cmd} + else + # complete unknown commands normally + _arguments -s -w : $_hg_global_opts \ + '*:files:_hg_files' + fi +} + +_hg_cache_policy() { + typeset -a old + + # cache for a minute + old=( "$1"(mm+10) ) + (( $#old )) && return 0 + + return 1 +} + +_hg_get_commands() { + typeset -ga _hg_cmd_list + typeset -gA _hg_alias_list + local hline cmd cmdalias + + _call_program hg hg debugcomplete -v | while read -A hline + do + cmd=$hline[1] + _hg_cmd_list+=($cmd) + + for cmdalias in $hline[2,-1] + do + _hg_cmd_list+=($cmdalias) + _hg_alias_list+=($cmdalias $cmd) + done + done +} + +_hg_commands() { + (( $#_hg_cmd_list )) || _hg_get_commands + _describe -t commands 'mercurial command' _hg_cmd_list +} + +_hg_revrange() { + compset -P 1 '*:' + _hg_tags "$@" +} + +_hg_tags() { + typeset -a tags + local tag rev + + _hg_cmd tags | while read tag + do + tags+=(${tag/ # [0-9]#:*}) + done + (( $#tags )) && _describe -t tags 'tags' tags +} + +# likely merge candidates +_hg_mergerevs() { + typeset -a heads + local myrev + + heads=(${(f)"$(_hg_cmd heads --template '{rev}\\n')"}) + # exclude own revision + myrev=$(_hg_cmd log -r . --template '{rev}\\n') + heads=(${heads:#$myrev}) + + (( $#heads )) && _describe -t heads 'heads' heads +} + +_hg_files() { + if [[ -n "$_hg_root" ]] + then + [[ -d "$_hg_root/.hg" ]] || return + case "$_hg_root" in + /*) + _files -W $_hg_root + ;; + *) + _files -W $PWD/$_hg_root + ;; + esac + else + _files + fi +} + +_hg_status() { + [[ -d $PREFIX ]] || PREFIX=$PREFIX:h + status_files=(${(ps:\0:)"$(_hg_cmd status -0n$1 ./$PREFIX)"}) +} + +_hg_unknown() { + typeset -a status_files + _hg_status u + _wanted files expl 'unknown files' _multi_parts / status_files +} + +_hg_missing() { + typeset -a status_files + _hg_status d + _wanted files expl 'missing files' _multi_parts / status_files +} + +_hg_modified() { + typeset -a status_files + _hg_status m + _wanted files expl 'modified files' _multi_parts / status_files +} + +_hg_resolve() { + local rstate rpath + + [[ -d $PREFIX ]] || PREFIX=$PREFIX:h + + _hg_cmd resolve -l ./$PREFIX | while read rstate rpath + do + [[ $rstate == 'R' ]] && resolved_files+=($rpath) + [[ $rstate == 'U' ]] && unresolved_files+=($rpath) + done +} + +_hg_resolved() { + typeset -a resolved_files unresolved_files + _hg_resolve + _wanted files expl 'resolved files' _multi_parts / resolved_files +} + +_hg_unresolved() { + typeset -a resolved_files unresolved_files + _hg_resolve + _wanted files expl 'unresolved files' _multi_parts / unresolved_files +} + +_hg_config() { + typeset -a items + items=(${${(%f)"$(_call_program hg hg showconfig)"}%%\=*}) + (( $#items )) && _describe -t config 'config item' items +} + +_hg_addremove() { + _alternative 'files:unknown files:_hg_unknown' \ + 'files:missing files:_hg_missing' +} + +_hg_ssh_urls() { + if [[ -prefix */ ]] + then + if zstyle -T ":completion:${curcontext}:files" remote-access + then + local host=${PREFIX%%/*} + typeset -a remdirs + compset -p $(( $#host + 1 )) + local rempath=${(M)PREFIX##*/} + local cacheid="hg:${host}-${rempath//\//_}" + cacheid=${cacheid%[-_]} + compset -P '*/' + if _cache_invalid "$cacheid" || ! _retrieve_cache "$cacheid" + then + remdirs=(${${(M)${(f)"$(_call_program files ssh -a -x $host ls -1FL "${(q)rempath}")"}##*/}%/}) + _store_cache "$cacheid" remdirs + fi + _describe -t directories 'remote directory' remdirs -S/ + else + _message 'remote directory' + fi + else + if compset -P '*@' + then + _hosts -S/ + else + _alternative 'hosts:remote host name:_hosts -S/' \ + 'users:user:_users -S@' + fi + fi +} + +_hg_urls() { + if compset -P bundle:// + then + _files + elif compset -P ssh:// + then + _hg_ssh_urls + elif [[ -prefix *: ]] + then + _urls + else + local expl + compset -S '[^:]*' + _wanted url-schemas expl 'URL schema' compadd -S '' - \ + http:// https:// ssh:// bundle:// + fi +} + +_hg_paths() { + typeset -a paths pnames + _hg_cmd paths | while read -A pnames + do + paths+=($pnames[1]) + done + (( $#paths )) && _describe -t path-aliases 'repository alias' paths +} + +_hg_remote() { + _alternative 'path-aliases:repository alias:_hg_paths' \ + 'directories:directory:_files -/' \ + 'urls:URL:_hg_urls' +} + +_hg_clone_dest() { + _alternative 'directories:directory:_files -/' \ + 'urls:URL:_hg_urls' +} + +# Common options +_hg_global_opts=( + '(--repository -R)'{-R+,--repository}'[repository root directory]:repository:_files -/' + '--cwd[change working directory]:new working directory:_files -/' + '(--noninteractive -y)'{-y,--noninteractive}'[do not prompt, assume yes for any required answers]' + '(--verbose -v)'{-v,--verbose}'[enable additional output]' + '*--config[set/override config option]:defined config items:_hg_config' + '(--quiet -q)'{-q,--quiet}'[suppress output]' + '(--help -h)'{-h,--help}'[display help and exit]' + '--debug[debug mode]' + '--debugger[start debugger]' + '--encoding[set the charset encoding (default: UTF8)]' + '--encodingmode[set the charset encoding mode (default: strict)]' + '--lsprof[print improved command execution profile]' + '--traceback[print traceback on exception]' + '--time[time how long the command takes]' + '--profile[profile]' + '--version[output version information and exit]' +) + +_hg_pat_opts=( + '*'{-I+,--include}'[include names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/' + '*'{-X+,--exclude}'[exclude names matching the given patterns]:dir:_files -W $(_hg_cmd root) -/') + +_hg_diff_opts=( + '(--text -a)'{-a,--text}'[treat all files as text]' + '(--git -g)'{-g,--git}'[use git extended diff format]' + "--nodates[don't include dates in diff headers]") + +_hg_dryrun_opts=( + '(--dry-run -n)'{-n,--dry-run}'[do not perform actions, just print output]') + +_hg_style_opts=( + '--style[display using template map file]:' + '--template[display with template]:') + +_hg_commit_opts=( + '(-m --message -l --logfile --edit -e)'{-e,--edit}'[edit commit message]' + '(-e --edit -l --logfile --message -m)'{-m+,--message}'[use as commit message]:message:' + '(-e --edit -m --message --logfile -l)'{-l+,--logfile}'[read the commit message from ]:log file:_files') + +_hg_remote_opts=( + '(--ssh -e)'{-e+,--ssh}'[specify ssh command to use]:' + '--remotecmd[specify hg command to run on the remote side]:') + +_hg_cmd() { + _call_program hg hg --config ui.verbose=0 --config defaults."$1"= \ + "$_hg_cmd_globals[@]" "$@" 2> /dev/null +} + +_hg_cmd_add() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \ + '*:unknown files:_hg_unknown' +} + +_hg_cmd_addremove() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \ + '(--similarity -s)'{-s+,--similarity}'[guess renamed files by similarity (0<=s<=100)]:' \ + '*:unknown or missing files:_hg_addremove' +} + +_hg_cmd_annotate() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '(--rev -r)'{-r+,--rev}'[annotate the specified revision]:revision:_hg_tags' \ + '(--follow -f)'{-f,--follow}'[follow file copies and renames]' \ + '(--text -a)'{-a,--text}'[treat all files as text]' \ + '(--user -u)'{-u,--user}'[list the author]' \ + '(--date -d)'{-d,--date}'[list the date]' \ + '(--number -n)'{-n,--number}'[list the revision number (default)]' \ + '(--changeset -c)'{-c,--changeset}'[list the changeset]' \ + '*:files:_hg_files' +} + +_hg_cmd_archive() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '--no-decode[do not pass files through decoders]' \ + '(--prefix -p)'{-p+,--prefix}'[directory prefix for files in archive]:' \ + '(--rev -r)'{-r+,--rev}'[revision to distribute]:revision:_hg_tags' \ + '(--type -t)'{-t+,--type}'[type of distribution to create]:archive type:(files tar tbz2 tgz uzip zip)' \ + '*:destination:_files' +} + +_hg_cmd_backout() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '--merge[merge with old dirstate parent after backout]' \ + '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \ + '--parent[parent to choose when backing out merge]' \ + '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \ + '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_tags' \ + '(--message -m)'{-m+,--message}'[use as commit message]:text:' \ + '(--logfile -l)'{-l+,--logfile}'[read commit message from ]:log file:_files -g \*.txt' +} + +_hg_cmd_bisect() { + _arguments -s -w : $_hg_global_opts \ + '(-)'{-r,--reset}'[reset bisect state]' \ + '(--good -g --bad -b --skip -s --reset -r)'{-g,--good}'[mark changeset good]'::revision:_hg_tags \ + '(--good -g --bad -b --skip -s --reset -r)'{-b,--bad}'[mark changeset bad]'::revision:_hg_tags \ + '(--good -g --bad -b --skip -s --reset -r)'{-s,--skip}'[skip testing changeset]' \ + '(--command -c --noupdate -U)'{-c+,--command}'[use command to check changeset state]':commands:_command_names \ + '(--command -c --noupdate -U)'{-U,--noupdate}'[do not update to target]' +} + +_hg_cmd_branch() { + _arguments -s -w : $_hg_global_opts \ + '(--force -f)'{-f,--force}'[set branch name even if it shadows an existing branch]' \ + '(--clean -C)'{-C,--clean}'[reset branch name to parent branch name]' +} + +_hg_cmd_branches() { + _arguments -s -w : $_hg_global_opts \ + '(--active -a)'{-a,--active}'[show only branches that have unmerge heads]' +} + +_hg_cmd_bundle() { + _arguments -s -w : $_hg_global_opts $_hg_remote_opts \ + '(--force -f)'{-f,--force}'[run even when remote repository is unrelated]' \ + '(2)*--base[a base changeset to specify instead of a destination]:revision:_hg_tags' \ + ':output file:_files' \ + ':destination repository:_files -/' +} + +_hg_cmd_cat() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '(--output -o)'{-o+,--output}'[print output to file with formatted name]:filespec:' \ + '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_tags' \ + '*:file:_hg_files' +} + +_hg_cmd_clone() { + _arguments -s -w : $_hg_global_opts $_hg_remote_opts \ + '(--noupdate -U)'{-U,--noupdate}'[do not update the new working directory]' \ + '(--rev -r)'{-r+,--rev}'[a changeset you would like to have after cloning]:' \ + '--uncompressed[use uncompressed transfer (fast over LAN)]' \ + ':source repository:_hg_remote' \ + ':destination:_hg_clone_dest' +} + +_hg_cmd_commit() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '(--addremove -A)'{-A,--addremove}'[mark new/missing files as added/removed before committing]' \ + '(--message -m)'{-m+,--message}'[use as commit message]:text:' \ + '(--logfile -l)'{-l+,--logfile}'[read commit message from ]:log file:_files -g \*.txt' \ + '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \ + '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \ + '*:file:_hg_files' +} + +_hg_cmd_copy() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \ + '(--after -A)'{-A,--after}'[record a copy that has already occurred]' \ + '(--force -f)'{-f,--force}'[forcibly copy over an existing managed file]' \ + '*:file:_hg_files' +} + +_hg_cmd_diff() { + typeset -A opt_args + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_diff_opts \ + '*'{-r,--rev}'+[revision]:revision:_hg_revrange' \ + '(--show-function -p)'{-p,--show-function}'[show which function each change is in]' \ + '(--ignore-all-space -w)'{-w,--ignore-all-space}'[ignore white space when comparing lines]' \ + '(--ignore-space-change -b)'{-b,--ignore-space-change}'[ignore changes in the amount of white space]' \ + '(--ignore-blank-lines -B)'{-B,--ignore-blank-lines}'[ignore changes whose lines are all blank]' \ + '*:file:->diff_files' + + if [[ $state == 'diff_files' ]] + then + if [[ -n $opt_args[-r] ]] + then + _hg_files + else + _hg_modified + fi + fi +} + +_hg_cmd_export() { + _arguments -s -w : $_hg_global_opts $_hg_diff_opts \ + '(--outout -o)'{-o+,--output}'[print output to file with formatted name]:filespec:' \ + '--switch-parent[diff against the second parent]' \ + '*:revision:_hg_tags' +} + +_hg_cmd_grep() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '(--print0 -0)'{-0,--print0}'[end filenames with NUL]' \ + '--all[print all revisions with matches]' \ + '(--follow -f)'{-f,--follow}'[follow changeset or file history]' \ + '(--ignore-case -i)'{-i,--ignore-case}'[ignore case when matching]' \ + '(--files-with-matches -l)'{-l,--files-with-matches}'[print only filenames and revs that match]' \ + '(--line-number -n)'{-n,--line-number}'[print matching line numbers]' \ + '*'{-r+,--rev}'[search in given revision range]:revision:_hg_revrange' \ + '(--user -u)'{-u,--user}'[print user who committed change]' \ + '1:search pattern:' \ + '*:files:_hg_files' +} + +_hg_cmd_heads() { + _arguments -s -w : $_hg_global_opts $_hg_style_opts \ + '(--rev -r)'{-r+,--rev}'[show only heads which are descendants of rev]:revision:_hg_tags' +} + +_hg_cmd_help() { + _arguments -s -w : $_hg_global_opts \ + '*:mercurial command:_hg_commands' +} + +_hg_cmd_identify() { + _arguments -s -w : $_hg_global_opts \ + '(--rev -r)'{-r+,--rev}'[identify the specified rev]:revision:_hg_tags' \ + '(--num -n)'{-n+,--num}'[show local revision number]' \ + '(--id -i)'{-i+,--id}'[show global revision id]' \ + '(--branch -b)'{-b+,--branch}'[show branch]' \ + '(--tags -t)'{-t+,--tags}'[show tags]' +} + +_hg_cmd_import() { + _arguments -s -w : $_hg_global_opts \ + '(--strip -p)'{-p+,--strip}'[directory strip option for patch (default: 1)]:count:' \ + '(--message -m)'{-m+,--message}'[use as commit message]:text:' \ + '(--force -f)'{-f,--force}'[skip check for outstanding uncommitted changes]' \ + '*:patch:_files' +} + +_hg_cmd_incoming() { + _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \ + '(--no-merges -M)'{-M,--no-merges}'[do not show merge revisions]' \ + '(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \ + '(--patch -p)'{-p,--patch}'[show patch]' \ + '(--rev -r)'{-r+,--rev}'[a specific revision up to which you would like to pull]:revision:_hg_tags' \ + '(--newest-first -n)'{-n,--newest-first}'[show newest record first]' \ + '--bundle[file to store the bundles into]:bundle file:_files' \ + ':source:_hg_remote' +} + +_hg_cmd_init() { + _arguments -s -w : $_hg_global_opts $_hg_remote_opts \ + ':dir:_files -/' +} + +_hg_cmd_locate() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '(--rev -r)'{-r+,--rev}'[search repository as it stood at revision]:revision:_hg_tags' \ + '(--print0 -0)'{-0,--print0}'[end filenames with NUL, for use with xargs]' \ + '(--fullpath -f)'{-f,--fullpath}'[print complete paths]' \ + '*:search pattern:_hg_files' +} + +_hg_cmd_log() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_style_opts \ + '(--follow --follow-first -f)'{-f,--follow}'[follow changeset or history]' \ + '(-f --follow)--follow-first[only follow the first parent of merge changesets]' \ + '(--copies -C)'{-C,--copies}'[show copied files]' \ + '(--keyword -k)'{-k+,--keyword}'[search for a keyword]:' \ + '(--limit -l)'{-l+,--limit}'[limit number of changes displayed]:' \ + '*'{-r,--rev}'[show the specified revision or range]:revision:_hg_revrange' \ + '(--no-merges -M)'{-M,--no-merges}'[do not show merges]' \ + '(--only-merges -m)'{-m,--only-merges}'[show only merges]' \ + '(--patch -p)'{-p,--patch}'[show patch]' \ + '(--prune -P)'{-P+,--prune}'[do not display revision or any of its ancestors]:revision:_hg_tags' \ + '*:files:_hg_files' +} + +_hg_cmd_manifest() { + _arguments -s -w : $_hg_global_opts \ + ':revision:_hg_tags' +} + +_hg_cmd_merge() { + _arguments -s -w : $_hg_global_opts \ + '(--force -f)'{-f,--force}'[force a merge with outstanding changes]' \ + '(--rev -r 1)'{-r,--rev}'[revision to merge]:revision:_hg_mergerevs' \ + '(--preview -P)'{-P,--preview}'[review revisions to merge (no merge is performed)]' \ + ':revision:_hg_mergerevs' +} + +_hg_cmd_outgoing() { + _arguments -s -w : $_hg_global_opts $_hg_remote_opts $_hg_style_opts \ + '(--no-merges -M)'{-M,--no-merges}'[do not show merge revisions]' \ + '(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \ + '(--patch -p)'{-p,--patch}'[show patch]' \ + '(--rev -r)'{-r+,--rev}'[a specific revision you would like to push]' \ + '(--newest-first -n)'{-n,--newest-first}'[show newest record first]' \ + ':destination:_hg_remote' +} + +_hg_cmd_parents() { + _arguments -s -w : $_hg_global_opts $_hg_style_opts \ + '(--rev -r)'{-r+,--rev}'[show parents of the specified rev]:revision:_hg_tags' \ + ':last modified file:_hg_files' +} + +_hg_cmd_paths() { + _arguments -s -w : $_hg_global_opts \ + ':path:_hg_paths' +} + +_hg_cmd_pull() { + _arguments -s -w : $_hg_global_opts $_hg_remote_opts \ + '(--force -f)'{-f,--force}'[run even when the remote repository is unrelated]' \ + '(--update -u)'{-u,--update}'[update to new tip if changesets were pulled]' \ + '(--rev -r)'{-r+,--rev}'[a specific revision up to which you would like to pull]:revision:' \ + ':source:_hg_remote' +} + +_hg_cmd_push() { + _arguments -s -w : $_hg_global_opts $_hg_remote_opts \ + '(--force -f)'{-f,--force}'[force push]' \ + '(--rev -r)'{-r+,--rev}'[a specific revision you would like to push]:revision:_hg_tags' \ + ':destination:_hg_remote' +} + +_hg_cmd_remove() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '(--after -A)'{-A,--after}'[record remove that has already occurred]' \ + '(--force -f)'{-f,--force}'[remove file even if modified]' \ + '*:file:_hg_files' +} + +_hg_cmd_rename() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \ + '(--after -A)'{-A,--after}'[record a rename that has already occurred]' \ + '(--force -f)'{-f,--force}'[forcibly copy over an existing managed file]' \ + '*:file:_hg_files' +} + +_hg_cmd_resolve() { + local context state line + typeset -A opt_args + + _arguments -s -w : $_hg_global_opts \ + '(--list -l --mark -m --unmark -u)'{-l,--list}'[list state of files needing merge]:*:merged files:->resolve_files' \ + '(--mark -m --list -l --unmark -u)'{-m,--mark}'[mark files as resolved]:*:unresolved files:_hg_unresolved' \ + '(--unmark -u --list -l --mark -m)'{-u,--unmark}'[unmark files as resolved]:*:resolved files:_hg_resolved' \ + '*:file:_hg_unresolved' + + if [[ $state == 'resolve_files' ]] + then + _alternative 'files:resolved files:_hg_resolved' \ + 'files:unresolved files:_hg_unresolved' + fi +} + +_hg_cmd_revert() { + local context state line + typeset -A opt_args + + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_dryrun_opts \ + '(--all -a :)'{-a,--all}'[revert all changes when no arguments given]' \ + '(--rev -r)'{-r+,--rev}'[revision to revert to]:revision:_hg_tags' \ + '--no-backup[do not save backup copies of files]' \ + '*:file:->diff_files' + + if [[ $state == 'diff_files' ]] + then + if [[ -n $opt_args[-r] ]] + then + _hg_files + else + typeset -a status_files + _hg_status mard + _wanted files expl 'modified, added, removed or deleted file' _multi_parts / status_files + fi + fi +} + +_hg_cmd_serve() { + _arguments -s -w : $_hg_global_opts \ + '(--accesslog -A)'{-A+,--accesslog}'[name of access log file]:log file:_files' \ + '(--errorlog -E)'{-E+,--errorlog}'[name of error log file]:log file:_files' \ + '(--daemon -d)'{-d,--daemon}'[run server in background]' \ + '(--port -p)'{-p+,--port}'[listen port]:listen port:' \ + '(--address -a)'{-a+,--address}'[interface address]:interface address:' \ + '(--name -n)'{-n+,--name}'[name to show in web pages]:repository name:' \ + '(--templates -t)'{-t,--templates}'[web template directory]:template dir:_files -/' \ + '--style[web template style]:style' \ + '--stdio[for remote clients]' \ + '(--ipv6 -6)'{-6,--ipv6}'[use IPv6 in addition to IPv4]' +} + +_hg_cmd_showconfig() { + _arguments -s -w : $_hg_global_opts \ + '(--untrusted -u)'{-u+,--untrusted}'[show untrusted configuration options]' \ + ':config item:_hg_config' +} + +_hg_cmd_status() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '(--all -A)'{-A,--all}'[show status of all files]' \ + '(--modified -m)'{-m,--modified}'[show only modified files]' \ + '(--added -a)'{-a,--added}'[show only added files]' \ + '(--removed -r)'{-r,--removed}'[show only removed files]' \ + '(--deleted -d)'{-d,--deleted}'[show only deleted (but tracked) files]' \ + '(--clean -c)'{-c,--clean}'[show only files without changes]' \ + '(--unknown -u)'{-u,--unknown}'[show only unknown files]' \ + '(--ignored -i)'{-i,--ignored}'[show ignored files]' \ + '(--no-status -n)'{-n,--no-status}'[hide status prefix]' \ + '(--copies -C)'{-C,--copies}'[show source of copied files]' \ + '(--print0 -0)'{-0,--print0}'[end filenames with NUL, for use with xargs]' \ + '--rev[show difference from revision]:revision:_hg_tags' \ + '*:files:_files' +} + +_hg_cmd_tag() { + _arguments -s -w : $_hg_global_opts \ + '(--local -l)'{-l,--local}'[make the tag local]' \ + '(--message -m)'{-m+,--message}'[message for tag commit log entry]:message:' \ + '(--date -d)'{-d+,--date}'[record datecode as commit date]:date code:' \ + '(--user -u)'{-u+,--user}'[record user as commiter]:user:' \ + '(--rev -r)'{-r+,--rev}'[revision to tag]:revision:_hg_tags' \ + ':tag name:' +} + +_hg_cmd_tip() { + _arguments -s -w : $_hg_global_opts $_hg_style_opts \ + '(--patch -p)'{-p,--patch}'[show patch]' +} + +_hg_cmd_unbundle() { + _arguments -s -w : $_hg_global_opts \ + '(--update -u)'{-u,--update}'[update to new tip if changesets were unbundled]' \ + ':files:_files' +} + +_hg_cmd_update() { + _arguments -s -w : $_hg_global_opts \ + '(--clean -C)'{-C,--clean}'[overwrite locally modified files]' \ + '(--rev -r)'{-r+,--rev}'[revision]:revision:_hg_tags' \ + ':revision:_hg_tags' +} + +# HGK +_hg_cmd_view() { + _arguments -s -w : $_hg_global_opts \ + '(--limit -l)'{-l+,--limit}'[limit number of changes displayed]:' \ + ':revision range:_hg_tags' +} + +# MQ +_hg_qseries() { + typeset -a patches + patches=(${(f)"$(_hg_cmd qseries)"}) + (( $#patches )) && _describe -t hg-patches 'patches' patches +} + +_hg_qapplied() { + typeset -a patches + patches=(${(f)"$(_hg_cmd qapplied)"}) + if (( $#patches )) + then + patches+=(qbase qtip) + _describe -t hg-applied-patches 'applied patches' patches + fi +} + +_hg_qunapplied() { + typeset -a patches + patches=(${(f)"$(_hg_cmd qunapplied)"}) + (( $#patches )) && _describe -t hg-unapplied-patches 'unapplied patches' patches +} + +# unapplied, including guarded patches +_hg_qdeletable() { + typeset -a unapplied + unapplied=(${(f)"$(_hg_cmd qseries)"}) + for p in $(_hg_cmd qapplied) + do + unapplied=(${unapplied:#$p}) + done + + (( $#unapplied )) && _describe -t hg-allunapplied-patches 'all unapplied patches' unapplied +} + +_hg_qguards() { + typeset -a guards + local guard + compset -P "+|-" + _hg_cmd qselect -s | while read guard + do + guards+=(${guard#(+|-)}) + done + (( $#guards )) && _describe -t hg-guards 'guards' guards +} + +_hg_qseries_opts=( + '(--summary -s)'{-s,--summary}'[print first line of patch header]') + +_hg_cmd_qapplied() { + _arguments -s -w : $_hg_global_opts $_hg_qseries_opts +} + +_hg_cmd_qdelete() { + _arguments -s -w : $_hg_global_opts \ + '(--keep -k)'{-k,--keep}'[keep patch file]' \ + '*'{-r+,--rev}'[stop managing a revision]:applied patch:_hg_revrange' \ + '*:unapplied patch:_hg_qdeletable' +} + +_hg_cmd_qdiff() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts \ + '*:pattern:_hg_files' +} + +_hg_cmd_qfold() { + _arguments -s -w : $_hg_global_opts $_h_commit_opts \ + '(--keep,-k)'{-k,--keep}'[keep folded patch files]' \ + '*:unapplied patch:_hg_qunapplied' +} + +_hg_cmd_qgoto() { + _arguments -s -w : $_hg_global_opts \ + '(--force -f)'{-f,--force}'[overwrite any local changes]' \ + ':patch:_hg_qseries' +} + +_hg_cmd_qguard() { + _arguments -s -w : $_hg_global_opts \ + '(--list -l)'{-l,--list}'[list all patches and guards]' \ + '(--none -n)'{-n,--none}'[drop all guards]' \ + ':patch:_hg_qseries' \ + '*:guards:_hg_qguards' +} + +_hg_cmd_qheader() { + _arguments -s -w : $_hg_global_opts \ + ':patch:_hg_qseries' +} + +_hg_cmd_qimport() { + _arguments -s -w : $_hg_global_opts \ + '(--existing -e)'{-e,--existing}'[import file in patch dir]' \ + '(--name -n 2)'{-n+,--name}'[patch file name]:name:' \ + '(--force -f)'{-f,--force}'[overwrite existing files]' \ + '*'{-r+,--rev}'[place existing revisions under mq control]:revision:_hg_revrange' \ + '*:patch:_files' +} + +_hg_cmd_qnew() { + _arguments -s -w : $_hg_global_opts $_hg_commit_opts \ + '(--force -f)'{-f,--force}'[import uncommitted changes into patch]' \ + ':patch:' +} + +_hg_cmd_qnext() { + _arguments -s -w : $_hg_global_opts $_hg_qseries_opts +} + +_hg_cmd_qpop() { + _arguments -s -w : $_hg_global_opts \ + '(--all -a :)'{-a,--all}'[pop all patches]' \ + '(--name -n)'{-n+,--name}'[queue name to pop]:' \ + '(--force -f)'{-f,--force}'[forget any local changes]' \ + ':patch:_hg_qapplied' +} + +_hg_cmd_qprev() { + _arguments -s -w : $_hg_global_opts $_hg_qseries_opts +} + +_hg_cmd_qpush() { + _arguments -s -w : $_hg_global_opts \ + '(--all -a :)'{-a,--all}'[apply all patches]' \ + '(--list -l)'{-l,--list}'[list patch name in commit text]' \ + '(--merge -m)'{-m+,--merge}'[merge from another queue]:' \ + '(--name -n)'{-n+,--name}'[merge queue name]:' \ + '(--force -f)'{-f,--force}'[apply if the patch has rejects]' \ + ':patch:_hg_qunapplied' +} + +_hg_cmd_qrefresh() { + _arguments -s -w : $_hg_global_opts $_hg_pat_opts $_hg_commit_opts \ + '(--git -g)'{-g,--git}'[use git extended diff format]' \ + '(--short -s)'{-s,--short}'[short refresh]' \ + '*:files:_hg_files' +} + +_hg_cmd_qrename() { + _arguments -s -w : $_hg_global_opts \ + ':patch:_hg_qseries' \ + ':destination:' +} + +_hg_cmd_qselect() { + _arguments -s -w : $_hg_global_opts \ + '(--none -n :)'{-n,--none}'[disable all guards]' \ + '(--series -s :)'{-s,--series}'[list all guards in series file]' \ + '--pop[pop to before first guarded applied patch]' \ + '--reapply[pop and reapply patches]' \ + '*:guards:_hg_qguards' +} + +_hg_cmd_qseries() { + _arguments -s -w : $_hg_global_opts $_hg_qseries_opts \ + '(--missing -m)'{-m,--missing}'[print patches not in series]' +} + +_hg_cmd_qunapplied() { + _arguments -s -w : $_hg_global_opts $_hg_qseries_opts +} + +_hg_cmd_qtop() { + _arguments -s -w : $_hg_global_opts $_hg_qseries_opts +} + +_hg_cmd_strip() { + _arguments -s -w : $_hg_global_opts \ + '(--force -f)'{-f,--force}'[force multi-head removal]' \ + '(--backup -b)'{-b,--backup}'[bundle unrelated changesets]' \ + '(--nobackup -n)'{-n,--nobackup}'[no backups]' \ + ':revision:_hg_tags' +} + +_hg "$@" diff --git a/sys/src/cmd/hg/doc/Makefile b/sys/src/cmd/hg/doc/Makefile new file mode 100644 index 000000000..02f5fef36 --- /dev/null +++ b/sys/src/cmd/hg/doc/Makefile @@ -0,0 +1,48 @@ +SOURCES=$(wildcard *.[0-9].txt) +MAN=$(SOURCES:%.txt=%) +HTML=$(SOURCES:%.txt=%.html) +PREFIX=/usr/local +MANDIR=$(PREFIX)/share/man +INSTALL=install -c -m 644 +PYTHON=python +RST2HTML=rst2html +RST2MAN=rst2man + +all: man html + +man: $(MAN) + +html: $(HTML) + +hg.1.txt: hg.1.gendoc.txt + touch hg.1.txt + +hg.1.gendoc.txt: gendoc.py ../mercurial/commands.py ../mercurial/help.py + ${PYTHON} gendoc.py > $@ + +%: %.txt common.txt + # add newline after all literal blocks and fix backslash escape + $(RST2MAN) $*.txt \ + | sed -e 's/^\.fi$$/.fi\n/' \ + | sed -e 's/\\fB\\\\fP/\\fB\\e\\fP/' \ + > $* + +%.html: %.txt common.txt + $(RST2HTML) $*.txt > $*.html + +MANIFEST: man html + # tracked files are already in the main MANIFEST + $(RM) $@ + for i in $(MAN) $(HTML) hg.1.gendoc.txt; do \ + echo "doc/$$i" >> $@ ; \ + done + +install: man + for i in $(MAN) ; do \ + subdir=`echo $$i | sed -n 's/^.*\.\([0-9]\)$$/man\1/p'` ; \ + mkdir -p $(DESTDIR)$(MANDIR)/$$subdir ; \ + $(INSTALL) $$i $(DESTDIR)$(MANDIR)/$$subdir ; \ + done + +clean: + $(RM) $(MAN) $(MAN:%=%.html) *.[0-9].gendoc.txt MANIFEST diff --git a/sys/src/cmd/hg/doc/README b/sys/src/cmd/hg/doc/README new file mode 100644 index 000000000..d28170dac --- /dev/null +++ b/sys/src/cmd/hg/doc/README @@ -0,0 +1,17 @@ +Mercurial's documentation is kept in reStructuredText format, which is +a simple plain text format that's easy to read and edit: + + http://docutils.sourceforge.net/rst.html + +It's also convertible to a variety of other formats including standard +UNIX man page format and HTML. + +To do this, you'll need to install the rst2html and rst2man tools, +which are part of Docutils: + + http://docutils.sourceforge.net/ + +The rst2man tool is still in their so-called "sandbox". The above page +has links to tarballs of both Docutils and their sandbox. + +Use the Makefile in this directory to generate the man and HTML pages. diff --git a/sys/src/cmd/hg/doc/common.txt b/sys/src/cmd/hg/doc/common.txt new file mode 100644 index 000000000..936fc203b --- /dev/null +++ b/sys/src/cmd/hg/doc/common.txt @@ -0,0 +1,8 @@ +.. Common link and substitution definitions. + +.. |hg(1)| replace:: **hg**\ (1) +.. _hg(1): hg.1.html +.. |hgrc(5)| replace:: **hgrc**\ (5) +.. _hgrc(5): hgrc.5.html +.. |hgignore(5)| replace:: **hgignore**\ (5) +.. _hgignore(5): hgignore.5.html diff --git a/sys/src/cmd/hg/doc/gendoc.py b/sys/src/cmd/hg/doc/gendoc.py new file mode 100644 index 000000000..c0b0ec452 --- /dev/null +++ b/sys/src/cmd/hg/doc/gendoc.py @@ -0,0 +1,115 @@ +import os, sys, textwrap +# import from the live mercurial repo +sys.path.insert(0, "..") +# fall back to pure modules if required C extensions are not available +sys.path.append(os.path.join('..', 'mercurial', 'pure')) +from mercurial import demandimport; demandimport.enable() +from mercurial.commands import table, globalopts +from mercurial.i18n import _ +from mercurial.help import helptable + +def get_desc(docstr): + if not docstr: + return "", "" + # sanitize + docstr = docstr.strip("\n") + docstr = docstr.rstrip() + shortdesc = docstr.splitlines()[0].strip() + + i = docstr.find("\n") + if i != -1: + desc = docstr[i+2:] + else: + desc = " %s" % shortdesc + return (shortdesc, desc) + +def get_opts(opts): + for shortopt, longopt, default, desc in opts: + allopts = [] + if shortopt: + allopts.append("-%s" % shortopt) + if longopt: + allopts.append("--%s" % longopt) + desc += default and _(" (default: %s)") % default or "" + yield(", ".join(allopts), desc) + +def get_cmd(cmd): + d = {} + attr = table[cmd] + cmds = cmd.lstrip("^").split("|") + + d['cmd'] = cmds[0] + d['aliases'] = cmd.split("|")[1:] + d['desc'] = get_desc(attr[0].__doc__) + d['opts'] = list(get_opts(attr[1])) + + s = 'hg ' + cmds[0] + if len(attr) > 2: + if not attr[2].startswith('hg'): + s += ' ' + attr[2] + else: + s = attr[2] + d['synopsis'] = s + + return d + +def show_doc(ui): + def section(s): + ui.write("%s\n%s\n\n" % (s, "-" * len(s))) + def subsection(s): + ui.write("%s\n%s\n\n" % (s, '"' * len(s))) + + # print options + section(_("OPTIONS")) + for optstr, desc in get_opts(globalopts): + ui.write("%s\n %s\n\n" % (optstr, desc)) + + # print cmds + section(_("COMMANDS")) + h = {} + for c, attr in table.items(): + f = c.split("|")[0] + f = f.lstrip("^") + h[f] = c + cmds = h.keys() + cmds.sort() + + for f in cmds: + if f.startswith("debug"): continue + d = get_cmd(h[f]) + # synopsis + ui.write(".. _%s:\n\n" % d['cmd']) + ui.write("``%s``\n" % d['synopsis'].replace("hg ","", 1)) + # description + ui.write("%s\n\n" % d['desc'][1]) + # options + opt_output = list(d['opts']) + if opt_output: + opts_len = max([len(line[0]) for line in opt_output]) + ui.write(_(" options:\n\n")) + for optstr, desc in opt_output: + if desc: + s = "%-*s %s" % (opts_len, optstr, desc) + else: + s = optstr + s = textwrap.fill(s, initial_indent=4 * " ", + subsequent_indent=(6 + opts_len) * " ") + ui.write("%s\n" % s) + ui.write("\n") + # aliases + if d['aliases']: + ui.write(_(" aliases: %s\n\n") % " ".join(d['aliases'])) + + # print topics + for names, sec, doc in helptable: + for name in names: + ui.write(".. _%s:\n" % name) + ui.write("\n") + section(sec.upper()) + if callable(doc): + doc = doc() + ui.write(doc) + ui.write("\n") + +if __name__ == "__main__": + show_doc(sys.stdout) diff --git a/sys/src/cmd/hg/doc/hg.1.txt b/sys/src/cmd/hg/doc/hg.1.txt new file mode 100644 index 000000000..66e211217 --- /dev/null +++ b/sys/src/cmd/hg/doc/hg.1.txt @@ -0,0 +1,96 @@ +==== + hg +==== + +--------------------------------------- +Mercurial source code management system +--------------------------------------- + +:Author: Matt Mackall +:Organization: Mercurial +:Manual section: 1 +:Manual group: Mercurial Manual + + +SYNOPSIS +-------- +**hg** *command* [*option*]... [*argument*]... + +DESCRIPTION +----------- +The **hg** command provides a command line interface to the Mercurial +system. + +COMMAND ELEMENTS +---------------- + +files... + indicates one or more filename or relative path filenames; see + "FILE NAME PATTERNS" for information on pattern matching + +path + indicates a path on the local machine + +revision + indicates a changeset which can be specified as a changeset + revision number, a tag, or a unique substring of the changeset + hash value + +repository path + either the pathname of a local repository or the URI of a remote + repository. + +.. include:: hg.1.gendoc.txt + +FILES +----- + +``.hgignore`` + This file contains regular expressions (one per line) that + describe file names that should be ignored by **hg**. For details, + see |hgignore(5)|_. + +``.hgtags`` + This file contains changeset hash values and text tag names (one + of each separated by spaces) that correspond to tagged versions of + the repository contents. + +``/etc/mercurial/hgrc``, ``$HOME/.hgrc``, ``.hg/hgrc`` + This file contains defaults and configuration. Values in + ``.hg/hgrc`` override those in ``$HOME/.hgrc``, and these override + settings made in the global ``/etc/mercurial/hgrc`` configuration. + See |hgrc(5)|_ for details of the contents and format of these + files. + +Some commands (e.g. revert) produce backup files ending in ``.orig``, +if the ``.orig`` file already exists and is not tracked by Mercurial, +it will be overwritten. + +BUGS +---- +Probably lots, please post them to the mailing list (See Resources +below) when you find them. + +SEE ALSO +-------- +|hgignore(5)|_, |hgrc(5)|_ + +AUTHOR +------ +Written by Matt Mackall + +RESOURCES +--------- +Main Web Site: http://mercurial.selenic.com/ + +Source code repository: http://selenic.com/hg + +Mailing list: http://selenic.com/mailman/listinfo/mercurial + +COPYING +------- +Copyright \(C) 2005-2009 Matt Mackall. +Free use of this software is granted under the terms of the GNU General +Public License (GPL). + +.. include:: common.txt diff --git a/sys/src/cmd/hg/doc/hgignore.5.txt b/sys/src/cmd/hg/doc/hgignore.5.txt new file mode 100644 index 000000000..e98dc40d1 --- /dev/null +++ b/sys/src/cmd/hg/doc/hgignore.5.txt @@ -0,0 +1,111 @@ +========== + hgignore +========== + +--------------------------------- +syntax for Mercurial ignore files +--------------------------------- + +:Author: Vadim Gelfer +:Organization: Mercurial +:Manual section: 5 +:Manual group: Mercurial Manual + +SYNOPSIS +-------- + +The Mercurial system uses a file called ``.hgignore`` in the root +directory of a repository to control its behavior when it searches +for files that it is not currently tracking. + +DESCRIPTION +----------- + +The working directory of a Mercurial repository will often contain +files that should not be tracked by Mercurial. These include backup +files created by editors and build products created by compilers. +These files can be ignored by listing them in a ``.hgignore`` file in +the root of the working directory. The ``.hgignore`` file must be +created manually. It is typically put under version control, so that +the settings will propagate to other repositories with push and pull. + +An untracked file is ignored if its path relative to the repository +root directory, or any prefix path of that path, is matched against +any pattern in ``.hgignore``. + +For example, say we have an an untracked file, ``file.c``, at +``a/b/file.c`` inside our repository. Mercurial will ignore ``file.c`` +if any pattern in ``.hgignore`` matches ``a/b/file.c``, ``a/b`` or ``a``. + +In addition, a Mercurial configuration file can reference a set of +per-user or global ignore files. See the |hgrc(5)|_ man page for details +of how to configure these files. Look for the "ignore" entry in the +"ui" section. + +To control Mercurial's handling of files that it manages, see the +|hg(1)|_ man page. Look for the "``-I``" and "``-X``" options. + +SYNTAX +------ + +An ignore file is a plain text file consisting of a list of patterns, +with one pattern per line. Empty lines are skipped. The "``#``" +character is treated as a comment character, and the "``\``" character +is treated as an escape character. + +Mercurial supports several pattern syntaxes. The default syntax used +is Python/Perl-style regular expressions. + +To change the syntax used, use a line of the following form:: + + syntax: NAME + +where ``NAME`` is one of the following: + +``regexp`` + Regular expression, Python/Perl syntax. +``glob`` + Shell-style glob. + +The chosen syntax stays in effect when parsing all patterns that +follow, until another syntax is selected. + +Neither glob nor regexp patterns are rooted. A glob-syntax pattern of +the form "``*.c``" will match a file ending in "``.c``" in any directory, +and a regexp pattern of the form "``\.c$``" will do the same. To root a +regexp pattern, start it with "``^``". + +EXAMPLE +------- + +Here is an example ignore file. :: + + # use glob syntax. + syntax: glob + + *.elc + *.pyc + *~ + + # switch to regexp syntax. + syntax: regexp + ^\.pc/ + +AUTHOR +------ +Vadim Gelfer + +Mercurial was written by Matt Mackall . + +SEE ALSO +-------- +|hg(1)|_, |hgrc(5)|_ + +COPYING +------- +This manual page is copyright 2006 Vadim Gelfer. +Mercurial is copyright 2005-2009 Matt Mackall. +Free use of this software is granted under the terms of the GNU General +Public License (GPL). + +.. include:: common.txt diff --git a/sys/src/cmd/hg/doc/hgrc.5.txt b/sys/src/cmd/hg/doc/hgrc.5.txt new file mode 100644 index 000000000..7618cc614 --- /dev/null +++ b/sys/src/cmd/hg/doc/hgrc.5.txt @@ -0,0 +1,934 @@ +====== + hgrc +====== + +--------------------------------- +configuration files for Mercurial +--------------------------------- + +:Author: Bryan O'Sullivan +:Organization: Mercurial +:Manual section: 5 +:Manual group: Mercurial Manual + + +SYNOPSIS +-------- + +The Mercurial system uses a set of configuration files to control +aspects of its behavior. + +FILES +----- + +Mercurial reads configuration data from several files, if they exist. +The names of these files depend on the system on which Mercurial is +installed. ``*.rc`` files from a single directory are read in +alphabetical order, later ones overriding earlier ones. Where multiple +paths are given below, settings from later paths override earlier +ones. + +| (Unix) ``/etc/mercurial/hgrc.d/*.rc`` +| (Unix) ``/etc/mercurial/hgrc`` + + Per-installation configuration files, searched for in the + directory where Mercurial is installed. ```` is the + parent directory of the **hg** executable (or symlink) being run. For + example, if installed in ``/shared/tools/bin/hg``, Mercurial will look + in ``/shared/tools/etc/mercurial/hgrc``. Options in these files apply + to all Mercurial commands executed by any user in any directory. + +| (Unix) ``/etc/mercurial/hgrc.d/*.rc`` +| (Unix) ``/etc/mercurial/hgrc`` + + Per-system configuration files, for the system on which Mercurial + is running. Options in these files apply to all Mercurial commands + executed by any user in any directory. Options in these files + override per-installation options. + +| (Windows) ``\Mercurial.ini`` or else +| (Windows) ``HKEY_LOCAL_MACHINE\SOFTWARE\Mercurial`` or else +| (Windows) ``C:\Mercurial\Mercurial.ini`` + + Per-installation/system configuration files, for the system on + which Mercurial is running. Options in these files apply to all + Mercurial commands executed by any user in any directory. Registry + keys contain PATH-like strings, every part of which must reference + a ``Mercurial.ini`` file or be a directory where ``*.rc`` files will + be read. + +| (Unix) ``$HOME/.hgrc`` +| (Windows) ``%HOME%\Mercurial.ini`` +| (Windows) ``%HOME%\.hgrc`` +| (Windows) ``%USERPROFILE%\Mercurial.ini`` +| (Windows) ``%USERPROFILE%\.hgrc`` + + Per-user configuration file(s), for the user running Mercurial. On + Windows 9x, ``%HOME%`` is replaced by ``%APPDATA%``. Options in these + files apply to all Mercurial commands executed by this user in any + directory. Options in these files override per-installation and + per-system options. + +| (Unix, Windows) ``/.hg/hgrc`` + + Per-repository configuration options that only apply in a + particular repository. This file is not version-controlled, and + will not get transferred during a "clone" operation. Options in + this file override options in all other configuration files. On + Unix, most of this file will be ignored if it doesn't belong to a + trusted user or to a trusted group. See the documentation for the + trusted section below for more details. + +SYNTAX +------ + +A configuration file consists of sections, led by a "``[section]``" header +and followed by "``name: value``" entries; "``name=value``" is also accepted. + +:: + + [spam] + eggs=ham + green= + eggs + +Each line contains one entry. If the lines that follow are indented, +they are treated as continuations of that entry. + +Leading whitespace is removed from values. Empty lines are skipped. + +Lines beginning with "``#``" or "``;``" are ignored and may be used to provide +comments. + +SECTIONS +-------- + +This section describes the different sections that may appear in a +Mercurial "hgrc" file, the purpose of each section, its possible keys, +and their possible values. + +``alias`` +""""""""" +Defines command aliases. +Aliases allow you to define your own commands in terms of other +commands (or aliases), optionally including arguments. + +Alias definitions consist of lines of the form:: + + = [. = + +where is used to group arguments into authentication entries. +Example:: + + foo.prefix = hg.intevation.org/mercurial + foo.username = foo + foo.password = bar + foo.schemes = http https + + bar.prefix = secure.example.org + bar.key = path/to/file.key + bar.cert = path/to/file.cert + bar.schemes = https + +Supported arguments: + +``prefix`` + Either "``*``" or a URI prefix with or without the scheme part. + The authentication entry with the longest matching prefix is used + (where "``*``" matches everything and counts as a match of length + 1). If the prefix doesn't include a scheme, the match is performed + against the URI with its scheme stripped as well, and the schemes + argument, q.v., is then subsequently consulted. +``username`` + Optional. Username to authenticate with. If not given, and the + remote site requires basic or digest authentication, the user + will be prompted for it. +``password`` + Optional. Password to authenticate with. If not given, and the + remote site requires basic or digest authentication, the user + will be prompted for it. +``key`` + Optional. PEM encoded client certificate key file. +``cert`` + Optional. PEM encoded client certificate chain file. +``schemes`` + Optional. Space separated list of URI schemes to use this + authentication entry with. Only used if the prefix doesn't include + a scheme. Supported schemes are http and https. They will match + static-http and static-https respectively, as well. + Default: https. + +If no suitable authentication entry is found, the user is prompted +for credentials as usual if required by the remote. + + +``decode/encode`` +""""""""""""""""" +Filters for transforming files on checkout/checkin. This would +typically be used for newline processing or other +localization/canonicalization of files. + +Filters consist of a filter pattern followed by a filter command. +Filter patterns are globs by default, rooted at the repository root. +For example, to match any file ending in "``.txt``" in the root +directory only, use the pattern "``*.txt``". To match any file ending +in "``.c``" anywhere in the repository, use the pattern "``**.c``". + +The filter command can start with a specifier, either "pipe:" or +"tempfile:". If no specifier is given, "pipe:" is used by default. + +A "pipe:" command must accept data on stdin and return the transformed +data on stdout. + +Pipe example:: + + [encode] + # uncompress gzip files on checkin to improve delta compression + # note: not necessarily a good idea, just an example + *.gz = pipe: gunzip + + [decode] + # recompress gzip files when writing them to the working dir (we + # can safely omit "pipe:", because it's the default) + *.gz = gzip + +A "tempfile:" command is a template. The string INFILE is replaced +with the name of a temporary file that contains the data to be +filtered by the command. The string OUTFILE is replaced with the name +of an empty temporary file, where the filtered data must be written by +the command. + +NOTE: the tempfile mechanism is recommended for Windows systems, where +the standard shell I/O redirection operators often have strange +effects and may corrupt the contents of your files. + +The most common usage is for LF <-> CRLF translation on Windows. For +this, use the "smart" converters which check for binary files:: + + [extensions] + hgext.win32text = + [encode] + ** = cleverencode: + [decode] + ** = cleverdecode: + +or if you only want to translate certain files:: + + [extensions] + hgext.win32text = + [encode] + **.txt = dumbencode: + [decode] + **.txt = dumbdecode: + + +``defaults`` +"""""""""""" + +Use the [defaults] section to define command defaults, i.e. the +default options/arguments to pass to the specified commands. + +The following example makes 'hg log' run in verbose mode, and 'hg +status' show only the modified files, by default:: + + [defaults] + log = -v + status = -m + +The actual commands, instead of their aliases, must be used when +defining command defaults. The command defaults will also be applied +to the aliases of the commands defined. + + +``diff`` +"""""""" + +Settings used when displaying diffs. They are all Boolean and +defaults to False. + +``git`` + Use git extended diff format. +``nodates`` + Don't include dates in diff headers. +``showfunc`` + Show which function each change is in. +``ignorews`` + Ignore white space when comparing lines. +``ignorewsamount`` + Ignore changes in the amount of white space. +``ignoreblanklines`` + Ignore changes whose lines are all blank. + +``email`` +""""""""" +Settings for extensions that send email messages. + +``from`` + Optional. Email address to use in "From" header and SMTP envelope + of outgoing messages. +``to`` + Optional. Comma-separated list of recipients' email addresses. +``cc`` + Optional. Comma-separated list of carbon copy recipients' + email addresses. +``bcc`` + Optional. Comma-separated list of blind carbon copy recipients' + email addresses. Cannot be set interactively. +``method`` + Optional. Method to use to send email messages. If value is "smtp" + (default), use SMTP (see section "[smtp]" for configuration). + Otherwise, use as name of program to run that acts like sendmail + (takes "-f" option for sender, list of recipients on command line, + message on stdin). Normally, setting this to "sendmail" or + "/usr/sbin/sendmail" is enough to use sendmail to send messages. +``charsets`` + Optional. Comma-separated list of character sets considered + convenient for recipients. Addresses, headers, and parts not + containing patches of outgoing messages will be encoded in the + first character set to which conversion from local encoding + (``$HGENCODING``, ``ui.fallbackencoding``) succeeds. If correct + conversion fails, the text in question is sent as is. Defaults to + empty (explicit) list. + +Order of outgoing email character sets:: + + us-ascii always first, regardless of settings + email.charsets in order given by user + ui.fallbackencoding if not in email.charsets + $HGENCODING if not in email.charsets + utf-8 always last, regardless of settings + +Email example:: + + [email] + from = Joseph User + method = /usr/sbin/sendmail + # charsets for western Europeans + # us-ascii, utf-8 omitted, as they are tried first and last + charsets = iso-8859-1, iso-8859-15, windows-1252 + + +``extensions`` +"""""""""""""" + +Mercurial has an extension mechanism for adding new features. To +enable an extension, create an entry for it in this section. + +If you know that the extension is already in Python's search path, +you can give the name of the module, followed by "``=``", with nothing +after the "``=``". + +Otherwise, give a name that you choose, followed by "``=``", followed by +the path to the "``.py``" file (including the file name extension) that +defines the extension. + +To explicitly disable an extension that is enabled in an hgrc of +broader scope, prepend its path with "``!``", as in +"``hgext.foo = !/ext/path``" or "``hgext.foo = !``" when path is not +supplied. + +Example for ``~/.hgrc``:: + + [extensions] + # (the mq extension will get loaded from Mercurial's path) + hgext.mq = + # (this extension will get loaded from the file specified) + myfeature = ~/.hgext/myfeature.py + + +``format`` +"""""""""" + +``usestore`` + Enable or disable the "store" repository format which improves + compatibility with systems that fold case or otherwise mangle + filenames. Enabled by default. Disabling this option will allow + you to store longer filenames in some situations at the expense of + compatibility and ensures that the on-disk format of newly created + repositories will be compatible with Mercurial before version 0.9.4. + +``usefncache`` + Enable or disable the "fncache" repository format which enhances + the "store" repository format (which has to be enabled to use + fncache) to allow longer filenames and avoids using Windows + reserved names, e.g. "nul". Enabled by default. Disabling this + option ensures that the on-disk format of newly created + repositories will be compatible with Mercurial before version 1.1. + +``merge-patterns`` +"""""""""""""""""" + +This section specifies merge tools to associate with particular file +patterns. Tools matched here will take precedence over the default +merge tool. Patterns are globs by default, rooted at the repository +root. + +Example:: + + [merge-patterns] + **.c = kdiff3 + **.jpg = myimgmerge + +``merge-tools`` +""""""""""""""" + +This section configures external merge tools to use for file-level +merges. + +Example ``~/.hgrc``:: + + [merge-tools] + # Override stock tool location + kdiff3.executable = ~/bin/kdiff3 + # Specify command line + kdiff3.args = $base $local $other -o $output + # Give higher priority + kdiff3.priority = 1 + + # Define new tool + myHtmlTool.args = -m $local $other $base $output + myHtmlTool.regkey = Software\FooSoftware\HtmlMerge + myHtmlTool.priority = 1 + +Supported arguments: + +``priority`` + The priority in which to evaluate this tool. + Default: 0. +``executable`` + Either just the name of the executable or its pathname. + Default: the tool name. +``args`` + The arguments to pass to the tool executable. You can refer to the + files being merged as well as the output file through these + variables: ``$base``, ``$local``, ``$other``, ``$output``. + Default: ``$local $base $other`` +``premerge`` + Attempt to run internal non-interactive 3-way merge tool before + launching external tool. + Default: True +``binary`` + This tool can merge binary files. Defaults to False, unless tool + was selected by file pattern match. +``symlink`` + This tool can merge symlinks. Defaults to False, even if tool was + selected by file pattern match. +``checkconflicts`` + Check whether there are conflicts even though the tool reported + success. + Default: False +``checkchanged`` + Check whether outputs were written even though the tool reported + success. + Default: False +``fixeol`` + Attempt to fix up EOL changes caused by the merge tool. + Default: False +``gui`` + This tool requires a graphical interface to run. Default: False +``regkey`` + Windows registry key which describes install location of this + tool. Mercurial will search for this key first under + ``HKEY_CURRENT_USER`` and then under ``HKEY_LOCAL_MACHINE``. + Default: None +``regname`` + Name of value to read from specified registry key. Defaults to the + unnamed (default) value. +``regappend`` + String to append to the value read from the registry, typically + the executable name of the tool. + Default: None + + +``hooks`` +""""""""" +Commands or Python functions that get automatically executed by +various actions such as starting or finishing a commit. Multiple +hooks can be run for the same action by appending a suffix to the +action. Overriding a site-wide hook can be done by changing its +value or setting it to an empty string. + +Example ``.hg/hgrc``:: + + [hooks] + # do not use the site-wide hook + incoming = + incoming.email = /my/email/hook + incoming.autobuild = /my/build/hook + +Most hooks are run with environment variables set that give useful +additional information. For each hook below, the environment +variables it is passed are listed with names of the form "$HG_foo". + +``changegroup`` + Run after a changegroup has been added via push, pull or unbundle. + ID of the first new changeset is in ``$HG_NODE``. URL from which + changes came is in ``$HG_URL``. +``commit`` + Run after a changeset has been created in the local repository. ID + of the newly created changeset is in ``$HG_NODE``. Parent changeset + IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``. +``incoming`` + Run after a changeset has been pulled, pushed, or unbundled into + the local repository. The ID of the newly arrived changeset is in + ``$HG_NODE``. URL that was source of changes came is in ``$HG_URL``. +``outgoing`` + Run after sending changes from local repository to another. ID of + first changeset sent is in ``$HG_NODE``. Source of operation is in + ``$HG_SOURCE``; see "preoutgoing" hook for description. +``post-`` + Run after successful invocations of the associated command. The + contents of the command line are passed as ``$HG_ARGS`` and the result + code in ``$HG_RESULT``. Hook failure is ignored. +``pre-`` + Run before executing the associated command. The contents of the + command line are passed as ``$HG_ARGS``. If the hook returns failure, + the command doesn't execute and Mercurial returns the failure + code. +``prechangegroup`` + Run before a changegroup is added via push, pull or unbundle. Exit + status 0 allows the changegroup to proceed. Non-zero status will + cause the push, pull or unbundle to fail. URL from which changes + will come is in ``$HG_URL``. +``precommit`` + Run before starting a local commit. Exit status 0 allows the + commit to proceed. Non-zero status will cause the commit to fail. + Parent changeset IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``. +``preoutgoing`` + Run before collecting changes to send from the local repository to + another. Non-zero status will cause failure. This lets you prevent + pull over HTTP or SSH. Also prevents against local pull, push + (outbound) or bundle commands, but not effective, since you can + just copy files instead then. Source of operation is in + ``$HG_SOURCE``. If "serve", operation is happening on behalf of remote + SSH or HTTP repository. If "push", "pull" or "bundle", operation + is happening on behalf of repository on same system. +``pretag`` + Run before creating a tag. Exit status 0 allows the tag to be + created. Non-zero status will cause the tag to fail. ID of + changeset to tag is in ``$HG_NODE``. Name of tag is in ``$HG_TAG``. Tag is + local if ``$HG_LOCAL=1``, in repository if ``$HG_LOCAL=0``. +``pretxnchangegroup`` + Run after a changegroup has been added via push, pull or unbundle, + but before the transaction has been committed. Changegroup is + visible to hook program. This lets you validate incoming changes + before accepting them. Passed the ID of the first new changeset in + ``$HG_NODE``. Exit status 0 allows the transaction to commit. Non-zero + status will cause the transaction to be rolled back and the push, + pull or unbundle will fail. URL that was source of changes is in + ``$HG_URL``. +``pretxncommit`` + Run after a changeset has been created but the transaction not yet + committed. Changeset is visible to hook program. This lets you + validate commit message and changes. Exit status 0 allows the + commit to proceed. Non-zero status will cause the transaction to + be rolled back. ID of changeset is in ``$HG_NODE``. Parent changeset + IDs are in ``$HG_PARENT1`` and ``$HG_PARENT2``. +``preupdate`` + Run before updating the working directory. Exit status 0 allows + the update to proceed. Non-zero status will prevent the update. + Changeset ID of first new parent is in ``$HG_PARENT1``. If merge, ID + of second new parent is in ``$HG_PARENT2``. +``tag`` + Run after a tag is created. ID of tagged changeset is in ``$HG_NODE``. + Name of tag is in ``$HG_TAG``. Tag is local if ``$HG_LOCAL=1``, in + repository if ``$HG_LOCAL=0``. +``update`` + Run after updating the working directory. Changeset ID of first + new parent is in ``$HG_PARENT1``. If merge, ID of second new parent is + in ``$HG_PARENT2``. If the update succeeded, ``$HG_ERROR=0``. If the + update failed (e.g. because conflicts not resolved), ``$HG_ERROR=1``. + +NOTE: it is generally better to use standard hooks rather than the +generic pre- and post- command hooks as they are guaranteed to be +called in the appropriate contexts for influencing transactions. +Also, hooks like "commit" will be called in all contexts that +generate a commit (e.g. tag) and not just the commit command. + +NOTE: Environment variables with empty values may not be passed to +hooks on platforms such as Windows. As an example, ``$HG_PARENT2`` will +have an empty value under Unix-like platforms for non-merge +changesets, while it will not be available at all under Windows. + +The syntax for Python hooks is as follows:: + + hookname = python:modulename.submodule.callable + hookname = python:/path/to/python/module.py:callable + +Python hooks are run within the Mercurial process. Each hook is +called with at least three keyword arguments: a ui object (keyword +"ui"), a repository object (keyword "repo"), and a "hooktype" +keyword that tells what kind of hook is used. Arguments listed as +environment variables above are passed as keyword arguments, with no +"``HG_``" prefix, and names in lower case. + +If a Python hook returns a "true" value or raises an exception, this +is treated as a failure. + + +``http_proxy`` +"""""""""""""" +Used to access web-based Mercurial repositories through a HTTP +proxy. + +``host`` + Host name and (optional) port of the proxy server, for example + "myproxy:8000". +``no`` + Optional. Comma-separated list of host names that should bypass + the proxy. +``passwd`` + Optional. Password to authenticate with at the proxy server. +``user`` + Optional. User name to authenticate with at the proxy server. + +``smtp`` +"""""""" +Configuration for extensions that need to send email messages. + +``host`` + Host name of mail server, e.g. "mail.example.com". +``port`` + Optional. Port to connect to on mail server. Default: 25. +``tls`` + Optional. Whether to connect to mail server using TLS. True or + False. Default: False. +``username`` + Optional. User name to authenticate to SMTP server with. If + username is specified, password must also be specified. + Default: none. +``password`` + Optional. Password to authenticate to SMTP server with. If + username is specified, password must also be specified. + Default: none. +``local_hostname`` + Optional. It's the hostname that the sender can use to identify + itself to the MTA. + + +``patch`` +""""""""" +Settings used when applying patches, for instance through the 'import' +command or with Mercurial Queues extension. + +``eol`` + When set to 'strict' patch content and patched files end of lines + are preserved. When set to 'lf' or 'crlf', both files end of lines + are ignored when patching and the result line endings are + normalized to either LF (Unix) or CRLF (Windows). + Default: strict. + + +``paths`` +""""""""" +Assigns symbolic names to repositories. The left side is the +symbolic name, and the right gives the directory or URL that is the +location of the repository. Default paths can be declared by setting +the following entries. + +``default`` + Directory or URL to use when pulling if no source is specified. + Default is set to repository from which the current repository was + cloned. +``default-push`` + Optional. Directory or URL to use when pushing if no destination + is specified. + + +``profiling`` +""""""""""""" +Specifies profiling format and file output. In this section +description, 'profiling data' stands for the raw data collected +during profiling, while 'profiling report' stands for a statistical +text report generated from the profiling data. The profiling is done +using lsprof. + +``format`` + Profiling format. + Default: text. + + ``text`` + Generate a profiling report. When saving to a file, it should be + noted that only the report is saved, and the profiling data is + not kept. + ``kcachegrind`` + Format profiling data for kcachegrind use: when saving to a + file, the generated file can directly be loaded into + kcachegrind. +``output`` + File path where profiling data or report should be saved. If the + file exists, it is replaced. Default: None, data is printed on + stderr + +``server`` +"""""""""" +Controls generic server settings. + +``uncompressed`` + Whether to allow clients to clone a repository using the + uncompressed streaming protocol. This transfers about 40% more + data than a regular clone, but uses less memory and CPU on both + server and client. Over a LAN (100 Mbps or better) or a very fast + WAN, an uncompressed streaming clone is a lot faster (~10x) than a + regular clone. Over most WAN connections (anything slower than + about 6 Mbps), uncompressed streaming is slower, because of the + extra data transfer overhead. Default is False. + + +``trusted`` +""""""""""" +For security reasons, Mercurial will not use the settings in the +``.hg/hgrc`` file from a repository if it doesn't belong to a trusted +user or to a trusted group. The main exception is the web interface, +which automatically uses some safe settings, since it's common to +serve repositories from different users. + +This section specifies what users and groups are trusted. The +current user is always trusted. To trust everybody, list a user or a +group with name "``*``". + +``users`` + Comma-separated list of trusted users. +``groups`` + Comma-separated list of trusted groups. + + +``ui`` +"""""" + +User interface controls. + +``archivemeta`` + Whether to include the .hg_archival.txt file containing meta data + (hashes for the repository base and for tip) in archives created + by the hg archive command or downloaded via hgweb. + Default is true. +``askusername`` + Whether to prompt for a username when committing. If True, and + neither ``$HGUSER`` nor ``$EMAIL`` has been specified, then the user will + be prompted to enter a username. If no username is entered, the + default USER@HOST is used instead. + Default is False. +``debug`` + Print debugging information. True or False. Default is False. +``editor`` + The editor to use during a commit. Default is ``$EDITOR`` or "vi". +``fallbackencoding`` + Encoding to try if it's not possible to decode the changelog using + UTF-8. Default is ISO-8859-1. +``ignore`` + A file to read per-user ignore patterns from. This file should be + in the same format as a repository-wide .hgignore file. This + option supports hook syntax, so if you want to specify multiple + ignore files, you can do so by setting something like + "``ignore.other = ~/.hgignore2``". For details of the ignore file + format, see the |hgignore(5)|_ man page. +``interactive`` + Allow to prompt the user. True or False. Default is True. +``logtemplate`` + Template string for commands that print changesets. +``merge`` + The conflict resolution program to use during a manual merge. + There are some internal tools available: + + ``internal:local`` + keep the local version + ``internal:other`` + use the other version + ``internal:merge`` + use the internal non-interactive merge tool + ``internal:fail`` + fail to merge + +For more information on configuring merge tools see the +merge-tools section. + +``patch`` + command to use to apply patches. Look for 'gpatch' or 'patch' in + PATH if unset. +``quiet`` + Reduce the amount of output printed. True or False. Default is False. +``remotecmd`` + remote command to use for clone/push/pull operations. Default is 'hg'. +``report_untrusted`` + Warn if a ``.hg/hgrc`` file is ignored due to not being owned by a + trusted user or group. True or False. Default is True. +``slash`` + Display paths using a slash ("``/``") as the path separator. This + only makes a difference on systems where the default path + separator is not the slash character (e.g. Windows uses the + backslash character ("``\``")). + Default is False. +``ssh`` + command to use for SSH connections. Default is 'ssh'. +``strict`` + Require exact command names, instead of allowing unambiguous + abbreviations. True or False. Default is False. +``style`` + Name of style to use for command output. +``timeout`` + The timeout used when a lock is held (in seconds), a negative value + means no timeout. Default is 600. +``username`` + The committer of a changeset created when running "commit". + Typically a person's name and email address, e.g. "Fred Widget + ". Default is ``$EMAIL`` or username@hostname. If + the username in hgrc is empty, it has to be specified manually or + in a different hgrc file (e.g. ``$HOME/.hgrc``, if the admin set + "username =" in the system hgrc). +``verbose`` + Increase the amount of output printed. True or False. Default is False. + + +``web`` +""""""" +Web interface configuration. + +``accesslog`` + Where to output the access log. Default is stdout. +``address`` + Interface address to bind to. Default is all. +``allow_archive`` + List of archive format (bz2, gz, zip) allowed for downloading. + Default is empty. +``allowbz2`` + (DEPRECATED) Whether to allow .tar.bz2 downloading of repository + revisions. + Default is false. +``allowgz`` + (DEPRECATED) Whether to allow .tar.gz downloading of repository + revisions. + Default is false. +``allowpull`` + Whether to allow pulling from the repository. Default is true. +``allow_push`` + Whether to allow pushing to the repository. If empty or not set, + push is not allowed. If the special value "``*``", any remote user can + push, including unauthenticated users. Otherwise, the remote user + must have been authenticated, and the authenticated user name must + be present in this list (separated by whitespace or ","). The + contents of the allow_push list are examined after the deny_push + list. +``allow_read`` + If the user has not already been denied repository access due to + the contents of deny_read, this list determines whether to grant + repository access to the user. If this list is not empty, and the + user is unauthenticated or not present in the list (separated by + whitespace or ","), then access is denied for the user. If the + list is empty or not set, then access is permitted to all users by + default. Setting allow_read to the special value "``*``" is equivalent + to it not being set (i.e. access is permitted to all users). The + contents of the allow_read list are examined after the deny_read + list. +``allowzip`` + (DEPRECATED) Whether to allow .zip downloading of repository + revisions. Default is false. This feature creates temporary files. +``baseurl`` + Base URL to use when publishing URLs in other locations, so + third-party tools like email notification hooks can construct + URLs. Example: "http://hgserver/repos/" +``contact`` + Name or email address of the person in charge of the repository. + Defaults to ui.username or ``$EMAIL`` or "unknown" if unset or empty. +``deny_push`` + Whether to deny pushing to the repository. If empty or not set, + push is not denied. If the special value "``*``", all remote users are + denied push. Otherwise, unauthenticated users are all denied, and + any authenticated user name present in this list (separated by + whitespace or ",") is also denied. The contents of the deny_push + list are examined before the allow_push list. +``deny_read`` + Whether to deny reading/viewing of the repository. If this list is + not empty, unauthenticated users are all denied, and any + authenticated user name present in this list (separated by + whitespace or ",") is also denied access to the repository. If set + to the special value "``*``", all remote users are denied access + (rarely needed ;). If deny_read is empty or not set, the + determination of repository access depends on the presence and + content of the allow_read list (see description). If both + deny_read and allow_read are empty or not set, then access is + permitted to all users by default. If the repository is being + served via hgwebdir, denied users will not be able to see it in + the list of repositories. The contents of the deny_read list have + priority over (are examined before) the contents of the allow_read + list. +``description`` + Textual description of the repository's purpose or contents. + Default is "unknown". +``encoding`` + Character encoding name. + Example: "UTF-8" +``errorlog`` + Where to output the error log. Default is stderr. +``hidden`` + Whether to hide the repository in the hgwebdir index. + Default is false. +``ipv6`` + Whether to use IPv6. Default is false. +``name`` + Repository name to use in the web interface. Default is current + working directory. +``maxchanges`` + Maximum number of changes to list on the changelog. Default is 10. +``maxfiles`` + Maximum number of files to list per changeset. Default is 10. +``port`` + Port to listen on. Default is 8000. +``prefix`` + Prefix path to serve from. Default is '' (server root). +``push_ssl`` + Whether to require that inbound pushes be transported over SSL to + prevent password sniffing. Default is true. +``staticurl`` + Base URL to use for static files. If unset, static files (e.g. the + hgicon.png favicon) will be served by the CGI script itself. Use + this setting to serve them directly with the HTTP server. + Example: "http://hgserver/static/" +``stripes`` + How many lines a "zebra stripe" should span in multiline output. + Default is 1; set to 0 to disable. +``style`` + Which template map style to use. +``templates`` + Where to find the HTML templates. Default is install path. + + +AUTHOR +------ +Bryan O'Sullivan . + +Mercurial was written by Matt Mackall . + +SEE ALSO +-------- +|hg(1)|_, |hgignore(5)|_ + +COPYING +------- +This manual page is copyright 2005 Bryan O'Sullivan. +Mercurial is copyright 2005-2009 Matt Mackall. +Free use of this software is granted under the terms of the GNU General +Public License (GPL). + +.. include:: common.txt diff --git a/sys/src/cmd/hg/doc/ja/Makefile b/sys/src/cmd/hg/doc/ja/Makefile new file mode 100644 index 000000000..154239fb4 --- /dev/null +++ b/sys/src/cmd/hg/doc/ja/Makefile @@ -0,0 +1,21 @@ +SOURCES=$(wildcard *.[0-9].ja.txt) +MAN=$(SOURCES:%.txt=%) +HTML=$(SOURCES:%.txt=%.html) + +all: man html + +man: $(MAN) + +html: $(HTML) + +%: %.xml + xmlto -x docbook.ja.xsl man $*.xml + +%.xml: %.txt + -asciidoc -d manpage -b docbook -f docbook.ja.conf $*.txt + +%.html: %.txt + asciidoc -b html4 $*.txt + +clean: + $(RM) $(MAN:%.ja=%) $(MAN:%=%.xml) $(MAN:%=%.html) diff --git a/sys/src/cmd/hg/doc/ja/docbook.ja.conf b/sys/src/cmd/hg/doc/ja/docbook.ja.conf new file mode 100644 index 000000000..355692ab2 --- /dev/null +++ b/sys/src/cmd/hg/doc/ja/docbook.ja.conf @@ -0,0 +1,583 @@ +# +# docbook.conf +# +# Asciidoc configuration file. +# Modified docbook backend for Japanese. +# + +[miscellaneous] +outfilesuffix=.xml +# Printable page width in pts. +pagewidth=380 +pageunits=pt + +[attributes] +basebackend=docbook +basebackend-docbook= + +[replacements] +# Line break markup is dropped (there is no DocBook line break tag). +(?m)^(.*)\s\+$=\1 +# Superscripts. +\^(.+?)\^=\1 +# Subscripts. +~(.+?)~=\1 + +[ruler-blockmacro] +# Only applies to HTML so don't output anything. + +[image-inlinemacro] + + + + + {1={target}} + + +[image-blockmacro] +{title} +{title%} + + + + + {1={target}} + +{title#} +{title%} + +[indexterm-inlinemacro] +# Inline index term. +# Generate separate index entries for primary, secondary and tertiary +# descriptions. +# Primary only. +{2%} +{2%} {1} +{2%} +# Primary and secondary. +{2#}{3%} +{2#}{3%} {1}{2} +{2#}{3%} +{2#}{3%} +{2#}{3%} {2} +{2#}{3%} +# Primary, secondary and tertiary. +{3#} + {1}{2}{3} +{3#} +{3#} + {2}{3} +{3#} +{3#} + {3} +{3#} + +[indexterm2-inlinemacro] +# Inline index term. +# Single entry index term that is visible in the primary text flow. + + {1} + +{1} + +[footnote-inlinemacro] +# Inline footnote. +{0} + +[callout-inlinemacro] +# Inline callout. + + +[tags] +# Bulleted, numbered and labeled list tags. +ilist={title?{title}}| +ilistitem=| +ilisttext=| +olist={title?{title}}| +olist2=| +olistitem=| +olisttext=| +vlist={title?{title}}| +vlistentry=| +vlistterm=| +vlisttext=| +vlistitem=| +# Horizontal labeled list (implemented with two column table). +# Hardwired column widths to 30%,70% because the current crop of PDF +# generators do not auto calculate column widths. +hlist=<{title?table}{title!informaltable}{id? id="{id}"} tabstyle="{style=hlabeledlist}" pgwide="0" frame="none" colsep="0" rowsep="0">{title?{title}}|<{title?/table}{title!/informaltable}> +hlistentry=| +hlisttext=| +hlistterm=| +hlistitem=| + +# Question and Answer list. +qlist={title?{title}}| +qlistentry=| +qlistterm=| +qlistitem=| +qlisttext=| +# Bibliography list. +blist=| +blistitem=| +blisttext=| +# Glossary list. +glist=| +glistentry=| +glistterm=| +glistitem=| +glisttext=| +# Callout list. +colist={title?{title}}| +colistitem=| +colisttext=| + +# Quoted text +emphasis=| +strong=| +monospaced=| +quoted={amp}#8220;|{amp}#8221; + +# Inline macros +[http-inlinemacro] +{0={name}:{target}} +[https-inlinemacro] +{0={name}:{target}} +[ftp-inlinemacro] +{0={name}:{target}} +[file-inlinemacro] +{0={name}:{target}} +[mailto-inlinemacro] +{0={target}} +#{target} +[link-inlinemacro] +{0={target}} +# anchor:id[text] +[anchor-inlinemacro] + +# [[id,text]] +[anchor2-inlinemacro] + +# [[[id]]] +[anchor3-inlinemacro] +[{1}] +# xref:id[text] +[xref-inlinemacro] +{0} +{2%} +# <> +[xref2-inlinemacro] +{2} +{2%} + + +# Special word macros +[emphasizedwords] +{words} +[monospacedwords] +{words} +[strongwords] +{words} + +# Paragraph substitution. +[paragraph] +{title} +{title%} +| +{title%} +{title#} +{empty} + +[admonitionparagraph] +<{name}{id? id="{id}"}>| + +[literalparagraph] +# The literal block employs the same markup. +template::[literalblock] + +[verseparagraph] +template::[verseblock] + +# Delimited blocks. +[literalblock] +{title} + +| + +{title#} + +[listingblock] +{title} + +| + +{title#} + +[verseblock] +{title} +{title%} +{title#} +| + +{title#} + +[sidebarblock] + +{title} +| + + +[backendblock] +| + +[quoteblock] +# The epigraph element may be more appropriate than blockquote. + +{title} + +{attribution} +{citetitle} + +| + + +[exampleblock] +<{title?example}{title!informalexample}{id? id="{id}"}> +{title} +| + + +[admonitionblock] +<{name}{id? id="{id}"}> +{title} +| + + +# Tables. +[tabledef-default] +template=table +colspec= +bodyrow=| +bodydata=| + +[table] +<{title?table}{title!informaltable}{id? id="{id}"} pgwide="0" +frame="{frame=topbot}" +{grid%rowsep="0" colsep="0"} +{eval:\{"none":"rowsep=\"0\" colsep=\"0\"", "cols":"rowsep=\"0\" colsep=\"1\"", "all":"rowsep=\"1\" colsep=\"1\"", "rows":"rowsep=\"1\" colsep=\"0\"" \}["{grid}"]} +> +{title} + +{colspecs} +{headrows#} +{headrows} +{headrows#} +{footrows#} +{footrows} +{footrows#} + +{bodyrows} + + + + +[specialsections] +ifdef::doctype-article[] +^Abstract$=sect-abstract +endif::doctype-article[] + +ifdef::doctype-book[] +^Colophon$=sect-colophon +^Dedication$=sect-dedication +^Preface$=sect-preface +endif::doctype-book[] + +^Index$=sect-index +^(Bibliography|References)$=sect-bibliography +^Glossary$=sect-glossary +^Appendix [A-Z][:.](?P.*)$=sect-appendix + +# Special sections. +[sect-preface] +<preface{id? id="{id}"}> +<title>{title} +| + + +[sect-index] + +{title} +| + + +[sect-bibliography] + +{title} +| + + +[sect-glossary] + +{title} +| + + +[sect-appendix] + +{title} +| + + + +[header-declarations] + + + +#------------------------- +# article document type +#------------------------- +ifdef::doctype-article[] + +[header] +template::[header-declarations] + +
+{doctitle#} + {doctitle} + {date} + {authored#} + {firstname} + {middlename} + {lastname} +
{email}
+ {authored#}
+ +# If file named like source document with -revhistory.xml suffix exists +# include it as the document history, otherwise use current revision. +{revisionhistory#}{include:{docdir}/{docname}-revhistory.xml} +{revisionhistory%}{revision}{date}{revremark?{revremark}} + + {companyname} +{doctitle#}
+ +[footer] +
+ +[preamble] +# Untitled elements between header and first section title. +| + +[sect-abstract] + +| + + +[sect1] + +{title} +| + + +[sect2] + +{title} +| + + +[sect3] + +{title} +| + + +[sect4] + +{title} +| + + +endif::doctype-article[] + +#------------------------- +# manpage document type +#------------------------- +ifdef::doctype-manpage[] + +[replacements] +# The roff format does not substitute special characters so just print them as +# text. +\(C\)=(C) +\(TM\)=(TM) + +[header] +template::[header-declarations] + + +{mantitle} +{manvolnum} + + + {manname} + {manpurpose} + + +[footer] + + +# Section macros +[sect-synopsis] + +| + + +[sect1] + +{title} +| + + +[sect2] + +{title} +| + + +[sect3] + +{title} +| + + +endif::doctype-manpage[] + +#------------------------- +# book document type +#------------------------- +ifdef::doctype-book[] + +[header] +template::[header-declarations] + + +{doctitle#} + {doctitle} + {date} + {authored#} + {firstname} + {middlename} + {lastname} +
{email}
+ {authored#}
+ +# If file named like source document with -revhistory.xml suffix exists +# include it as the document history, otherwise use current revision. +{revisionhistory#}{include:{docdir}/{docname}-revhistory.xml} +{revisionhistory%}{revision}{date}{revremark?{revremark}} + + {companyname} +{doctitle#}
+ +[footer] +
+ +[preamble] +# Preamble is not allowed in DocBook book so wrap it in a preface. + +Preface +| + + +[sect-dedication] + +| + + +[sect-colophon] + +| + + +[sect0] + +{title} +| + + +[sect1] + +{title} +| + + +[sect2] + +{title} +| + + +[sect3] + +{title} +| + + +[sect4] + +{title} +| + + +endif::doctype-book[] + +ifdef::sgml[] +# +# Optional DocBook SGML. +# +# Most of the differences between DocBook XML and DocBook SGML boils +# down to the empty element syntax: SGML does not like the XML empty +# element <.../> syntax, use <...> instead. +# +[miscellaneous] +outfilesuffix=.sgml + +[header-declarations] + + +[tabledef-default] +colspec= + +[image-inlinemacro] + + + + + {1={target}} + + +[image-blockmacro] +
{title} +{title%} + + + + + {1={target}} + +{title#}
+{title%} + +# Inline macros +[xref-inlinemacro] +{0} +{2%} +[xref2-inlinemacro] +# <> +{2} +{2%} +[anchor-inlinemacro] + +[anchor2-inlinemacro] +# [[id,text]] + + +endif::sgml[] diff --git a/sys/src/cmd/hg/doc/ja/docbook.ja.xsl b/sys/src/cmd/hg/doc/ja/docbook.ja.xsl new file mode 100644 index 000000000..aba2d65c1 --- /dev/null +++ b/sys/src/cmd/hg/doc/ja/docbook.ja.xsl @@ -0,0 +1,23 @@ + + + + + + + .SH åå‰ + + + , + + + + \- + + + + + .SH "書å¼" + + + + diff --git a/sys/src/cmd/hg/doc/ja/hg.1.ja.txt b/sys/src/cmd/hg/doc/ja/hg.1.ja.txt new file mode 100644 index 000000000..889cb4b57 --- /dev/null +++ b/sys/src/cmd/hg/doc/ja/hg.1.ja.txt @@ -0,0 +1,867 @@ +HG(1) +===== +Matt Mackall + +åå‰ +-- +hg - Mercurial ソースコード管ç†ã‚·ã‚¹ãƒ†ãƒ  + +æ›¸å¼ +-- +'hg' [-v -d -q -y] [command options] [files] + +説明 +-- +hg(1) コマンド㯠Mercurial システムã¸ã®ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ã‚§ +イスをæä¾›ã—ã¾ã™ã€‚ + +オプション +---- + +-R, --repository:: + リãƒã‚¸ãƒˆãƒªã®ãƒ«ãƒ¼ãƒˆãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’指定ã—ã¾ã™ã€‚ + +--cwd:: + 作業ディレクトリを変更ã—ã¾ã™ã€‚ + +-y, --noninteractive:: + プロンプトを出ã•ãšã«ã€è¦æ±‚ã•れãŸç­”ãˆãŒå…¨ã¦ 'yes' ã§ã‚ã‚‹ã¨ä»®å®š + ã—ã¾ã™ã€‚ + +-q, --quiet:: + 出力を抑制ã—ã¾ã™ã€‚ + +-v, --verbose:: + ã•らãªã‚‹å‡ºåŠ›ã‚’å¯èƒ½ã«ã—ã¾ã™ã€‚ + +7--debug:: + デãƒãƒƒã‚°å‡ºåŠ›ã‚’å¯èƒ½ã«ã—ã¾ã™ã€‚ + +--traceback:: + 例外時ã«ãƒˆãƒ¬ãƒ¼ã‚¹ãƒãƒƒã‚¯ã‚’表示ã—ã¾ã™ã€‚ + +--time:: + コマンドã«ã©ã®ãã‚‰ã„æ™‚é–“ãŒã‹ã‹ã‚‹ã‹ã‚’表示ã—ã¾ã™ã€‚ + +--profile:: + コマンドを実行ã—ãŸã¨ãã®ãƒ—ロファイルを表示ã—ã¾ã™ã€‚ + +--version:: + ãƒãƒ¼ã‚¸ãƒ§ãƒ³æƒ…報を表示ã—ã¦çµ‚了ã—ã¾ã™ã€‚ + +-h, --help:: + ヘルプを表示ã—ã¦çµ‚了ã—ã¾ã™ã€‚ + +コマンドã®è¦ç´  +------- + +files ...:: + 1ã¤ä»¥ä¸Šã®ãƒ•ァイルåã‹ç›¸å¯¾çš„ãªãƒ‘スを表ã—ã¾ã™; パターンマッãƒãƒ³ + ã‚°ã®æƒ…å ±ã¯ã€Œãƒ•ァイルåã®ãƒ‘ターンã€ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 + +path:: + ローカルマシン上ã®ãƒ‘スを表ã—ã¾ã™ + +revision:: + ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ãƒªãƒ“ジョンナンãƒãƒ¼, ã‚¿ã‚°, ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ãƒãƒƒ + シュ値ã®ãƒ¦ãƒ‹ãƒ¼ã‚¯ãªéƒ¨åˆ†æ–‡å­—列ã«ã‚ˆã‚ŠæŒ‡å®šã§ãã‚‹ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã‚’表 + ã—ã¾ã™ + +repository path:: + ローカルã®ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ‘スåã‹ãƒªãƒ¢ãƒ¼ãƒˆã®ãƒªãƒã‚¸ãƒˆãƒªã® URI を表 + ã—ã¾ã™ã€‚URI ã®ãƒ—ロトコルã¨ã—ã¦ã¯ç¾åœ¨ 2 ã¤ãŒåˆ©ç”¨å¯èƒ½ã§ã™ã€‚ + http:// ã¯é«˜é€Ÿã§ã€static-http:// ã¯é…ã„ã§ã™ãŒã‚¦ã‚§ãƒ–ã®ãƒ›ã‚¹ãƒˆã«ç‰¹åˆ¥ + ãªã‚µãƒ¼ãƒã‚’å¿…è¦ã¨ã—ã¾ã›ã‚“。 + +コマンド +---- + +add [options] [files ...]:: + ファイルをãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ä¸‹ã«ç½®ãリãƒã‚¸ãƒˆãƒªã«è¿½åŠ ã™ã‚‹ã“ã¨ã‚’予定 + ã—ã¾ã™ã€‚ + + ãƒ•ã‚¡ã‚¤ãƒ«ã¯æ¬¡ã«ã‚³ãƒŸãƒƒãƒˆæ™‚ã«ãƒªãƒã‚¸ãƒˆãƒªã«è¿½åŠ ã•れã¾ã™ã€‚ + + ファイルåãŒä¸Žãˆã‚‰ã‚Œãªã‘れã°ã€ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¨ã‚µãƒ–ディレク + トリã®å…¨ã¦ã®ãƒ•ァイルを追加ã—ã¾ã™ã€‚ + +addremove [options] [files ...]:: + æ–°ã—ã„ファイルを全ã¦è¿½åŠ ã—ç„¡ããªã£ãŸãƒ•ァイルを全ã¦ãƒªãƒã‚¸ãƒˆãƒªã‹ + らå–り除ãã¾ã™ã€‚ + + æ–°ã—ã„ファイル㯠.hgignore 中ã®ãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸå ´åˆç„¡è¦–ã• + れã¾ã™ã€‚add ã®ã‚ˆã†ã«ã“ã®å¤‰æ›´ã¯æ¬¡ã®ã‚³ãƒŸãƒƒãƒˆæ™‚ã«åŠ¹æžœã‚’æŒã¡ã¾ã™ã€‚ + +annotate [-r -u -n -c] [files ...]:: + ファイル中ã®å¤‰æ›´ã‚’列挙ã—ã€å„行ã®åŽŸå› ã§ã‚るリビジョン id を表示 + ã—ã¾ã™ã€‚ + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã‚る変更ãŒç”Ÿã˜ãŸéš›ã«èª°ãŒãã®å¤‰æ›´ã‚’ã—ãŸã‹ã‚’発見ã™ã‚‹ + ã®ã«å½¹ã«ç«‹ã¡ã¾ã™ã€‚ + + -a オプションãŒç„¡ã„ã¨ã€annotate ã¯ãƒã‚¤ãƒŠãƒªã¨ã—ã¦æ¤œå‡ºã•れãŸãƒ•ã‚¡ + イルをé¿ã‘るよã†ã«ãªã‚Šã¾ã™ã€‚-a ãŒã‚ã‚‹ã¨ã€annotate ã¯ã¨ãã‹ã注 + 釈を生æˆã—ã€ãŠãã‚‰ãæœ›ã¾ã—ããªã„çµæžœã«ãªã‚‹ã§ã—ょã†ã€‚ + + オプション: + -a, --text å…¨ã¦ã®ãƒ•ァイルをテキストã¨ã—ã¦æ‰±ã„ã¾ã™ + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å«ã‚ + ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外 + ã—ã¾ã™ + -r, --revision 指定ã•れãŸãƒªãƒ“ã‚¸ãƒ§ãƒ³ã®æ³¨é‡ˆã‚’生æˆã—ã¾ã™ + -u, --user 著者を列挙ã—ã¾ã™ + -c, --changeset ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã‚’列挙ã—ã¾ã™ + -n, --number リビジョンナンãƒãƒ¼ã‚’列挙ã—ã¾ã™ + (デフォルト) + +bundle :: + (実験的) + + ä»–ã®ãƒªãƒã‚¸ãƒˆãƒªã«ã¯è¦‹ä»˜ã‹ã‚‰ãªã‹ã£ãŸå…¨ã¦ã®ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã‚’集ã‚ãŸã€ + 圧縮済ã¿ãƒã‚§ãƒ³ã‚¸ã‚°ãƒ«ãƒ¼ãƒ—ファイルを生æˆã—ã¾ã™ã€‚ + + ã“ã®ãƒ•ァイルã¯å¾“æ¥ã®æ–¹æ³•ã§è»¢é€ã™ã‚‹ã“ã¨ãŒã§ãã€ä»–ã®ãƒªãƒã‚¸ãƒˆãƒªã« + unbundle コマンドã§é©ç”¨ã§ãã¾ã™ã€‚ã“れ㯠push 㨠pull ãŒä½¿ãˆãª + ã„ã‹ã€ãƒªãƒã‚¸ãƒˆãƒªå…¨ä½“をエクスãƒãƒ¼ãƒˆã—ã¦ã—ã¾ã†ã“ã¨ãŒæœ›ã¾ã—ããªã„ + ã¨ãã«ä¾¿åˆ©ã§ã™ã€‚標準ã®ãƒ•ァイル拡張å­ã¯ ".hg" ã§ã™ã€‚ + + import/export ã¨é•ã£ã¦ã€ã“れã¯ãƒ‘ーミッションã€åå‰å¤‰æ›´ã®ãƒ‡ãƒ¼ã‚¿ã€ + リビジョンã®å±¥æ­´ã‚’å«ã‚ãŸãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®å†…容全ã¦ã‚’ä¿å­˜ã—ã¾ã™ã€‚ + +cat [options] :: + 指定ã•れãŸãƒ•ァイルを与ãˆã‚‰ã‚ŒãŸãƒªãƒ“ジョンã®å†…容ã§è¡¨ç¤ºã—ã¾ã™ã€‚リ + ãƒ“ã‚¸ãƒ§ãƒ³ãŒæŒ‡å®šã•れãªã‹ã£ãŸå ´åˆã¯ tip ãŒä½¿ã‚れã¾ã™ã€‚ + + 出力ã¯ãƒ•ァイルã«å¯¾ã—ã¦ã‚‚å¯èƒ½ã§ã™ã€‚ãã®å ´åˆã€ãƒ•ァイルåã¯ãƒ•ォー + マット文字列ã«ã‚ˆã‚ŠæŒ‡å®šã•れã¾ã™ã€‚フォーマットè¦å‰‡ã¯ export コマ + ンドã¨åŒã˜ã§ã™ãŒã€ã•ã‚‰ã«æ¬¡ã®ã‚‚ã®ãŒè¿½åŠ ã•れã¾ã™ã€‚ + + %s 出力ã•れるファイルã®ãƒ™ãƒ¼ã‚¹å + %d 出力ã•れるファイルã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªåã‹ã€ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ«ãƒ¼ãƒˆ + ã«ã„ã‚‹å ´åˆã¯ "." + %p 出力ã•れるファイルã®ãƒ«ãƒ¼ãƒˆã‹ã‚‰ã®ç›¸å¯¾ãƒ‘ス + + オプション: + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ + ã‚’å«ã‚ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ + を除外ã—ã¾ã™ + -o, --output æ•´å½¢ã•れãŸåå‰ã§ãƒ•ァイルã«å‡ºåŠ›ã—ã¾ + ã™ + -r, --rev 与ãˆã‚‰ã‚ŒãŸãƒªãƒ“ジョンを表示ã—ã¾ã™ + +clone [-U] [dest]:: + 既存ã®ãƒªãƒã‚¸ãƒˆãƒªã®ã‚³ãƒ”ーを新ã—ã„ディレクトリã«ä½œæˆã—ã¾ã™ + + コピー先ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªåãŒæŒ‡å®šã•れãªã‘れã°ã€ãƒ‡ãƒ•ォルトã§ã‚½ãƒ¼ã‚¹ + ã®ãƒ™ãƒ¼ã‚¹åを使用ã—ã¾ã™ã€‚ + + 今後㮠pull ã«ä½¿ãˆã‚‹ã‚ˆã†ã«ã€ã‚³ãƒ”ãƒ¼å…ƒãŒæ–°ã—ã„リãƒã‚¸ãƒˆãƒªã® + .hg/hgrc ã«è¿½åŠ ã•れã¾ã™ã€‚ + + 効率ã®ãŸã‚ã«ã€ã‚³ãƒ”ー元ã¨ã‚³ãƒ”ー先ãŒåŒã˜ãƒ•ァイルシステム上ã«ã‚ã‚‹ + å ´åˆã¯ãƒãƒ¼ãƒ‰ãƒªãƒ³ã‚¯ãŒä½¿ã‚れã¾ã™ã€‚ + + オプションン: + -U, --noupdate æ–°ã—ã„作業ディレクトリ㧠update を行ã„ã¾ã›ã‚“ + -e, --ssh 使用ã•れる ssh コマンドを指定ã—ã¾ã™ + --remotecmd リモートå´ã§å®Ÿè¡Œã™ã‚‹ hg コマンドを指定ã—ã¾ã™ + +commit [options] [files...]:: + 指定ã•れãŸãƒ•ァイルã®å¤‰æ›´ã‚’リãƒã‚¸ãƒˆãƒªã«ã‚³ãƒŸãƒƒãƒˆã—ã¾ã™ã€‚ + + ã‚‚ã—ファイルã®ãƒªã‚¹ãƒˆãŒçœç•¥ã•れãŸã‚‰ã€ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ«ãƒ¼ãƒˆã‹ã‚‰å®Ÿè¡Œ + ã—ãŸ"hg status" ã§å ±å‘Šã•れる全ã¦ã®å¤‰æ›´ãŒã‚³ãƒŸãƒƒãƒˆã•れã¾ã™ã€‚ + + HGEDITOR ã‚„ EDITOR 環境変数ã¯ã‚³ãƒŸãƒƒãƒˆæ™‚ã®ã‚³ãƒ¡ãƒ³ãƒˆã‚’追加ã™ã‚‹ã‚¨ + ディタを起動ã™ã‚‹ãŸã‚ã«ä½¿ã‚れã¾ã™ã€‚ + + オプション: + + -A, --addremove コミット中㫠addremove を実行ã—ã¾ã™ + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å«ã‚ + ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外 + ã—ã¾ã™ + -m, --message をコミットメッセージã¨ã—ã¦ä½¿ã„ã¾ + ã™ + -l, --logfile ã‹ã‚‰ã‚³ãƒŸãƒƒãƒˆãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’読ã¿è¾¼ã¿ + ã¾ã™ + -d, --date datecode をコミットã—ãŸæ—¥ä»˜ã¨ã—ã¦è¨˜éŒ²ã— + ã¾ã™ + -u, --user user をコミッタã¨ã—ã¦è¨˜éŒ²ã—ã¾ã™ã€‚ + + 別å: ci + +copy :: + コピー先ãŒã‚³ãƒ”ー元ã®ãƒ•ァイルã®ã‚³ãƒ”ーをæŒã£ã¦ã„ã‚‹ã¨å°ã‚’付ã‘ã¾ã™ã€‚ + ã‚‚ã—コピー先ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãªã‚‰ã€ã‚³ãƒ”ーã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã«ç½®ã‹ã‚Œ + ã¾ã™ã€‚ã‚‚ã—コピー先ãŒãƒ•ァイルãªã‚‰ã€ã‚³ãƒ”ー元ã¯1ã¤ã®ã¿æŒ‡å®šå¯èƒ½ã§ + ã™ã€‚ + + デフォルトã§ã¯ã€ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ãƒ•ァイルãŒãã®ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã« + ã‚ã‚‹ã‚‚ã®ã¨ã—ã¦ãã®å†…容をコピーã—ã¾ã™ã€‚ã‚‚ã— --after ã¨ä¸€ç·’ã«å‘¼ + ã³å‡ºã•れれã°ã€æ“作ã¯è¨˜éŒ²ã•れã¾ã™ãŒã€ã‚³ãƒ”ーã¯å®Ÿè¡Œã•れã¾ã›ã‚“。 + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯æ¬¡ã®ã‚³ãƒŸãƒƒãƒˆæ™‚ã«åŠ¹æžœã‚’æŒã¡ã¾ã™ã€‚ + + 注æ„: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯å®Ÿé¨“çš„ã§ã™ã€‚リãƒãƒ¼ãƒ ã•れãŸãƒ•ァイルをé©åˆ‡ã« + 記録ã§ãã¾ã™ãŒã€ã“ã®æƒ…å ±ã¯ãƒžãƒ¼ã‚¸ã«ã‚ˆã£ã¦ã¾ã å®Œå…¨ã«ã¯ä½¿ã‚れã¾ã› + ã‚“ã—ã€ãƒ­ã‚°ã§å®Œå…¨ã«å ±å‘Šã•れるã“ã¨ã‚‚ã‚りã¾ã›ã‚“。 + + オプション: + -A, --after æ—¢ã«ç™ºç”Ÿã—ãŸã‚³ãƒ”ーを記録ã—ã¾ã™ã€‚ + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å«ã‚ + ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外 + ã—ã¾ã™ + -f, --force 既存ã®å¤‰æ›´ã•れãŸãƒ•ァイルã«ç„¡ç†çŸ¢ç†ã‚³ãƒ”ー + ã—ã¾ã™ + -p, --parents コピー先ã«ã‚³ãƒ”ー元ã®ãƒ‘スを追加ã—ã¾ã™ + + 別å: cp + +diff [-a] [-r revision] [-r revision] [files ...]:: + 指定ã•れãŸãƒ•ァイルã®ãƒªãƒ“ジョン間ã®å·®åˆ†ã‚’表示ã—ã¾ã™ã€‚ + + ファイル間ã®å·®åˆ†ã¯ unified diff å½¢å¼ã§è¡¨ç¤ºã•れã¾ã™ã€‚ + + 2ã¤ã®ãƒªãƒ“ジョンãŒå¼•æ•°ã¨ã—ã¦æŒ‡å®šã•れãŸå ´åˆã€ãれらã®ãƒªãƒ“ジョン + é–“ã®å·®åˆ†ãŒè¡¨ç¤ºã•れã¾ã™ã€‚1ã¤ã®ãƒªãƒ“ジョンã—ã‹æŒ‡å®šã•れãªã‘れã°ã€ + ãã®ãƒªãƒ“ジョンã¯ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¨æ¯”較ã•れã¾ã™ã€‚ãã—㦠リビジョ + ãƒ³ãŒæŒ‡å®šã•れãªã‘れã°ã€ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ãƒ•ァイルãŒãã®è¦ªã¨æ¯”較 + ã•れã¾ã™ã€‚ + + -a オプション無ã—ã§ã¯ã€diff ã¯ãƒã‚¤ãƒŠãƒªãƒ•ァイルを検出ã—ãŸã¨ãã« + ãã®å·®åˆ†ã‚’生æˆã™ã‚‹ã®ã‚’é¿ã‘ã¾ã™ã€‚-a オプションã§ã¯ã€diff ã¯ã¨ã« + ã‹ã差分を生æˆã—ã€æã‚‰ãæœ›ã¾ã—ããªã„çµæžœã‚’ã‚‚ãŸã‚‰ã™ã§ã—ょã†ã€‚ + + オプション: + -a, --text å…¨ã¦ã®ãƒ•ァイルをテキストã¨ã—ã¦æ‰±ã„ã¾ã™ + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å«ã‚ + ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外 + ã—ã¾ã™ + +export [-o filespec] [revision] ...:: + 1ã¤ä»¥ä¸Šã®ãƒªãƒ“ジョンã®ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ãƒ˜ãƒƒãƒ€ã¨å·®åˆ†ã‚’出力ã—ã¾ã™ã€‚ + + ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ãƒ˜ãƒƒãƒ€ã«è¡¨ç¤ºã•れる情報ã¯: 著者ã€ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆ + ã®ãƒãƒƒã‚·ãƒ¥ã€è¦ªã€ã‚³ãƒŸãƒƒãƒˆæ™‚ã®ã‚³ãƒ¡ãƒ³ãƒˆã§ã™ã€‚ + + 出力ã¯ãƒ•ァイルã«å¯¾ã—ã¦ã‚‚å¯èƒ½ã§ã™ã€‚ãã®å ´åˆã€ãƒ•ァイルåã¯ãƒ•ォー + マット文字列ã«ã‚ˆã‚ŠæŒ‡å®šã•れã¾ã™ã€‚フォーマットè¦å‰‡ã¯ä¸‹è¨˜ã®é€šã‚Šã§ + ã™: + + %% ãã®ã¾ã¾ã® "%" 文字 + %H ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ãƒãƒƒã‚·ãƒ¥ (40 ãƒã‚¤ãƒˆã® 16 進数) + %N 生æˆã•れã¦ã„るパッãƒã®ç•ªå· + %R ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ãƒªãƒ“ジョンナンãƒãƒ¼ + %b エクスãƒãƒ¼ãƒˆã—ã¦ã„るリãƒã‚¸ãƒˆãƒªã®ãƒ¡ãƒ¼ã‚¹å + %h 短ã„å½¢å¼ã®ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ãƒãƒƒã‚·ãƒ¥ (12 ãƒã‚¤ãƒˆã® 16 進数) + %n 0 ã§ è©°ã‚られ㟠1 ã‹ã‚‰å§‹ã¾ã‚‹é€£ç•ª + %r 0 ã§ è©°ã‚られãŸãƒªãƒ“ジョンナンãƒãƒ¼ + + -a オプション無ã—ã§ã¯ã€diff ã¯ãƒã‚¤ãƒŠãƒªãƒ•ァイルを検出ã—ãŸã¨ãã« + ãã®å·®åˆ†ã‚’生æˆã™ã‚‹ã®ã‚’é¿ã‘ã¾ã™ã€‚-a オプションã§ã¯ã€diff ã¯ã¨ã« + ã‹ã差分を生æˆã—ã€æã‚‰ãæœ›ã¾ã—ããªã„çµæžœã‚’ã‚‚ãŸã‚‰ã™ã§ã—ょã†ã€‚ + + オプション: + -a, --text å…¨ã¦ã®ãƒ•ァイルをテキストã¨ã—ã¦æ‰±ã„ã¾ã™ + -o, --output æ•´å½¢ã•れãŸåå‰ã§ãƒ•ァイルã«å‡ºåŠ›ã—ã¾ã™ + +forget [options] [files]:: + 次ã®ã‚³ãƒŸãƒƒãƒˆæ™‚ã«äºˆå®šã•れ㟠'hg add' ã‚’å–り消ã—ã¾ã™ã€‚ + + オプション: + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å«ã‚ã¾ + -ã™X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外 + -ã—ã¾ã™ + +grep [options] pattern [files]:: + æ­£è¦è¡¨ç¾ã«ã‚ˆã‚Šãƒ•ァイルã®ãƒªãƒ“ジョンを検索ã—ã¾ã™ã€‚ + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ Unix ã® grep ã¨ã¯é•ã†æŒ¯èˆžã„ã‚’ã—ã¾ã™ã€‚ã“れ㯠+ Python/Perl ã®æ­£è¦è¡¨ç¾ã ã‘ã‚’å—ã‘ã¤ã‘ã¾ã™ã€‚ã“れã¯ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆ + リã§ã¯ãªãリãƒã‚¸ãƒˆãƒªã®å±¥æ­´ã‚’検索ã—ã¾ã™ã€‚ã“れã¯å¸¸ã«ãƒžãƒƒãƒã—ãŸã‚‚ + ã®ãŒç¾ã‚ŒãŸãƒªãƒ“ジョンナンãƒãƒ¼ã‚’表示ã—ã¾ã™ã€‚ + + デフォルトã§ã¯ã€grep ã¯ãƒžãƒƒãƒã—ãŸã‚‚ã®ãŒè¦‹ã¤ã‹ã£ãŸãƒ•ã‚¡ã‚¤ãƒ«ã®æœ€ + åˆã®ãƒªãƒ“ジョンを出力ã—ã¾ã™ã€‚マッãƒçжæ³ã®å¤‰åŒ–("-" ã¯ãƒžãƒƒãƒãŒéž + マッãƒã«ã€"+" ã¯éžãƒžãƒƒãƒãŒãƒžãƒƒãƒã«)ã‚’å«ã‚“ã å„リビジョンを表示 + ã™ã‚‹ã«ã¯ã€--all フラグを使ã£ã¦ãã ã•ã„。 + + オプション: + -0, --print0 ファイルåã‚’ NUL ã§çµ‚ãˆã¾ã™ã€‚ + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ + ã‚’å«ã‚ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ + を除外ã—ã¾ã™ + --all マッãƒã—ãŸå…¨ã¦ã®ãƒªãƒ“ジョンを表示㗠+ ã¾ã™ + -i, --ignore-case マッãƒã®ã¨ãã«è‹±å¤§æ–‡å­—ã¨å°æ–‡å­—を区 + 別ã—ãªã„よã†ã«ã—ã¾ã™ + -l, --files-with-matches マッãƒã—ãŸãƒ•ァイルåã¨ãƒªãƒ“ジョン㮠+ ã¿ã‚’表示ã—ã¾ã™ + -n, --line-number マッãƒã—ãŸè¡Œç•ªå·ã‚’表示ã—ã¾ã™ + -r, --rev 指定ã•れãŸãƒªãƒ“ジョンã®é–“ã§æ¤œç´¢ã—ã¾ + ã™ + -u, --user ãã®å¤‰æ›´ã‚’コミットã—ãŸãƒ¦ãƒ¼ã‚¶ã‚’表示 + ã—ã¾ã™ + +heads:: + リãƒã‚¸ãƒˆãƒªã®å…ˆé ­ã®ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã‚’å…¨ã¦è¡¨ç¤ºã—ã¾ã™ã€‚ + + リãƒã‚¸ãƒˆãƒªã®ã€Œå…ˆé ­ã€ã¨ã¯å­ã®ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã‚’æŒã£ã¦ã„ãªã„ãƒã‚§ãƒ³ + ジセットã§ã™ã€‚ãれらã¯å¤§æŠµé–‹ç™ºãŒè¡Œã‚れる場所ã§ã€é€šå¸¸ update 㨠+ merge æ“作ã®å¯¾è±¡ã¨ãªã‚‹ã¨ã“ã‚ã§ã™ã€‚ + +identify:: + レãƒã‚¸ãƒˆãƒªã®ç¾åœ¨ã®çŠ¶æ…‹ã®çŸ­ã„サマリを表示ã—ã¾ã™ã€‚ + + ã“ã®ã‚µãƒžãƒªã¯ãƒªãƒã‚¸ãƒˆãƒªã®çŠ¶æ…‹ã‚’1ã¤ã¾ãŸã¯2ã¤ã®è¦ªã®ãƒãƒƒã‚·ãƒ¥è­˜åˆ¥å­ + を使ã£ã¦è­˜åˆ¥ã—ã¾ã™ã€‚親ã®ãƒãƒƒã‚·ãƒ¥è­˜åˆ¥å­ã¯ã‚‚ã—作業ディレクトリ㫠+ コミットã•れã¦ã„ãªã„変更ãŒã‚れã°å¾Œã‚ã« + ãŒä»˜ãã€æ›´ã«ãã®å¾Œã« + ã“ã®ãƒªãƒ“ジョンã®ã‚¿ã‚°ã®ãƒªã‚¹ãƒˆãŒä»˜ãã¾ã™ã€‚ + + 別å: id + +import [-p -b -f] :: + 一連ã®ãƒ‘ッãƒã‚’インãƒãƒ¼ãƒˆã—ã€ãれãžã‚Œå€‹åˆ¥ã«ã‚³ãƒŸãƒƒãƒˆã—ã¾ã™ã€‚ + + ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æœªè§£æ±ºã®å¤‰æ›´ãŒã‚ã£ãŸå ´åˆã€import 㯠-f フラ + ã‚°ãŒæŒ‡å®šã•れã¦ãªã‘れã°ä¸­æ–­ã—ã¾ã™ã€‚ + + ã‚‚ã—パッãƒãŒãƒ¡ãƒ¼ãƒ«ã®ã‚ˆã†(最åˆã®è¡ŒãŒ "From " ã‹ RFC 822 ヘッダ + ã®ã‚ˆã†) ã§ã‚れã°ã€-f オプションãŒä½¿ã‚れã¦ã„ãªã„é™ã‚Šãれã¯é©ç”¨ + ã•れã¾ã›ã‚“。インãƒãƒ¼ãƒˆæ©Ÿæ§‹ã¯ãƒ¡ãƒ¼ãƒ«ã®ãƒ˜ãƒƒãƒ€ã‚’パースもã—ãªã‘れ㰠+ 破棄もã—ãªã„ã®ã§ã€æœ¬ç‰©ã®ãƒ¡ãƒ¼ãƒ«ã‚’インãƒãƒ¼ãƒˆã—ãªã„よã†ã«ã™ã‚‹ã€Œãƒ¡ãƒ¼ + ルã®ã‚ˆã†ãªã‚‚ã®ã®ã€å¥å…¨æ€§ãƒã‚§ãƒƒã‚¯ã‚’上書ãã™ã‚‹ãŸã‚ã ã‘ã« -f を使㣠+ ã¦ãã ã•ã„。 + + オプション: + -p, --strip patch 㮠ディレクトリ除去オプションã§ã™ã€‚ã“れ + ã¯é–¢é€£ã™ã‚‹ patch ã®ã‚ªãƒ—ションã¨åŒã˜æ„味をæŒã¡ + ã¾ã™ + -b パッãƒã‚’読ã¿è¾¼ã‚€ãƒ™ãƒ¼ã‚¹ã¨ãªã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’指 + 定ã—ã¾ã™ + -f, --force 未解決ã§ã¾ã ã‚³ãƒŸãƒƒãƒˆã•れã¦ã„ãªã„変更ã®ãƒã‚§ãƒƒ + クをçœç•¥ã—ã¾ã™ + + 別å: patch + +incoming [-p] [source]:: + 指定ã•れãŸãƒªãƒã‚¸ãƒˆãƒªã‹ã€ãƒ‡ãƒ•ォルト㧠pull ã™ã‚‹ãƒªãƒã‚¸ãƒˆãƒªä¸­ã«è¦‹ + ã¤ã‹ã£ãŸæ–°ã—ã„ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã‚’表示ã—ã¾ã™ã€‚ã“れら㯠pull ãŒè¦æ±‚ + ã•れãŸã¨ãã«pull ã•れるãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã§ã™ã€‚ + + ç¾åœ¨ã¯ãƒ­ãƒ¼ã‚«ãƒ«ã®ãƒªãƒã‚¸ãƒˆãƒªã®ã¿ãŒã‚µãƒãƒ¼ãƒˆã•れã¦ã„ã¾ã™ã€‚ + + オプション: + -p, --patch パッãƒã‚’表示ã—ã¾ã™ + + 別å: in + +init [dest]:: + 指定ã•れãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã«æ–°ã—ã„リãƒã‚¸ãƒˆãƒªã‚’åˆæœŸåŒ–ã—ã¾ã™ã€‚指定 + ã•れãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ä½œæˆã•れã¾ã™ã€‚ + + ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒæŒ‡å®šã•れãªã‘れã°ã€ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒä½¿ç”¨ã•れ㾠+ ã™ã€‚ + +locate [options] [files]:: + Mercurial ã®ç®¡ç†ä¸‹ã«ã‚るファイルã§åå‰ãŒæŒ‡å®šã•れãŸãƒ‘ターンã«ãƒžãƒƒ + ãƒã—ãŸã‚‚ã®ã‚’å…¨ã¦è¡¨ç¤ºã—ã¾ã™ã€‚ + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¨ã‚µãƒ–ディレクトリを検索ã—ã¾ã™ã€‚ + リãƒã‚¸ãƒˆãƒªå…¨ä½“を検索ã™ã‚‹ã«ã¯ã€ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ«ãƒ¼ãƒˆã«ç§»å‹•ã—ã¦ãã  + ã•ã„。 + + ã‚‚ã—マッãƒã™ã‚‹ãŸã‚ã®ãƒ‘ターンãŒä¸Žãˆã‚‰ã‚Œãªã‘れã°ã€ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ + å…¨ã¦ã®ãƒ•ァイルã®åå‰ã‚’表示ã—ã¾ã™ã€‚ + + ã‚‚ã—ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã®å‡ºåŠ›ã‚’ "xargs" コマンドã«é€ã‚ŠãŸã„ãªã‚‰ã€ + "-0" オプションをã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¨ "xargs" コマンドã®ä¸¡æ–¹ã§ä½¿ç”¨ã— + ã¦ãã ã•ã„。ã“れ㯠"xargs" ãŒã‚¹ãƒšãƒ¼ã‚¹ã®å…¥ã£ãŸãƒ•ァイルåを複数 + ã®ãƒ•ァイルåã¨ã—ã¦æ‰±ã‚ãªã„よã†ã«ã—ã¾ã™ã€‚ + + オプション: + + -0, --print0 xargs ã¨ä¸€ç·’ã«ä½¿ã†ãŸã‚ã«ã€ãƒ•ァイルåã‚’ + NUL ã§çµ‚ãˆã¾ã™ + -f, --fullpath ファイルシステムã®ãƒ«ãƒ¼ãƒˆã‹ã‚‰ã®å®Œå…¨ãªãƒ‘ + スを表示ã—ã¾ã™ + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å« + ã‚ã¾ã™ + -r, --rev rev ã®ã¨ãã®ãƒªãƒã‚¸ãƒˆãƒªã‚’検索ã—ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外 + ã—ã¾ã™ + +log [-r revision ...] [-p] [files]:: + 指定ã•れãŸãƒ•ァイルã‹ãƒ—ロジェクト全体ã®ãƒªãƒ“ジョンã®å±¥æ­´ã‚’表示㗠+ ã¾ã™ã€‚ + + デフォルトã§ã¯ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯æ¬¡ã®ã‚‚ã®ã‚’出力ã—ã¾ã™: ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒ + トã®id ã¨ãƒãƒƒã‚·ãƒ¥ã€ã‚¿ã‚°ã€è¦ªã€ãƒ¦ãƒ¼ã‚¶ã€æ—¥ä»˜ã€å„コミットã®ã‚µãƒž + リ。-v スイッãƒã¯å¤‰æ›´ã•れãŸãƒ•ァイルやマニフェストã®ãƒãƒƒã‚·ãƒ¥ã€ + メッセージã®ã‚·ã‚°ãƒãƒãƒ£ã¨ã„ã£ãŸã‚ˆã‚Šè©³ã—ã„æƒ…報を追加ã—ã¾ã™ã€‚ + + オプション: + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å«ã‚ + ã¾ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外 + ã—ã¾ã™ + -r, --rev 指定ã•れãŸãƒªãƒ“ジョンã¾ãŸã¯ç¯„囲を表示ã—ã¾ + ã™ + -p, --patch パッãƒã‚’表示ã—ã¾ã™ + + 別å: history + +manifest [revision]:: + 指定ã•れãŸãƒªãƒ“ジョンã§ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã•れã¦ã„るファイルã®ãƒªã‚¹ãƒˆ + を表示ã—ã¾ã™ã€‚ + + manifest ã¯ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã•れã¦ã„るファイルã®ãƒªã‚¹ãƒˆã§ã™ã€‚ã‚‚ã— + ãƒªãƒ“ã‚¸ãƒ§ãƒ³ãŒæŒ‡å®šã•れãªã‘れã°ã€tip ãŒä½¿ã‚れã¾ã™ã€‚ + +outgoing [-p] [dest]:: + 指定ã•れãŸè¡Œãå…ˆã®ãƒªãƒã‚¸ãƒˆãƒªã‹ãƒ‡ãƒ•ォルト㧠push ã™ã‚‹ãƒªãƒã‚¸ãƒˆãƒª + 中ã«è¦‹ä»˜ã‹ã‚‰ãªã‹ã£ãŸãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã‚’表示ã—ã¾ã™ã€‚ã“れら㯠push + ãŒè¦æ±‚ã•れãŸã¨ãã« push ã•れるã§ã‚ã‚ã†ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã§ã™ã€‚ + + オプション: + -p, --patch パッãƒã‚’表示ã—ã¾ã™ + + 別å: out + +parents:: + 作業ディレクトリã®è¦ªãƒªãƒ“ジョンを表示ã—ã¾ã™ã€‚ + +paths [NAME]:: + シンボルã®ãƒ‘スåã§ã‚ã‚‹ NAME ã®è¡Œã先を表示ã—ã¾ã™ã€‚ã‚‚ã—シンボル + åãŒæŒ‡å®šã•れãªã‘れã°ã€åˆ©ç”¨å¯èƒ½ãªã‚·ãƒ³ãƒœãƒ«åã®è¡Œã先を表示ã—ã¾ã™ã€‚ + + パスå㯠/etc/mercurial/hgrc 㨠$HOME/.hgrc ã® [paths] セクショ + ンã§å®šç¾©ã•れã¾ã™ã€‚ã‚‚ã—リãƒã‚¸ãƒˆãƒªã®å†…部ã§å®Ÿè¡Œã•れãŸå ´ + åˆã€.hg/hgrc も使用ã•れã¾ã™ã€‚ + +pull :: + リモートã®ãƒªãƒã‚¸ãƒˆãƒªã®å¤‰æ›´ã‚’ローカルã®ãƒªãƒã‚¸ãƒˆãƒªã« pull ã—ã¾ã™ã€‚ + + ã“ã‚Œã¯æŒ‡å®šã•れãŸãƒ‘スや URL ã«ã‚るリãƒã‚¸ãƒˆãƒªã®å…¨ã¦ã®å¤‰æ›´ã‚’見㤠+ ã‘ã¦ã€ãれらをローカルã®ãƒªãƒã‚¸ãƒˆãƒªã«è¿½åŠ ã—ã¾ã™ã€‚デフォルトã§ã¯ã€ + ã“れã¯ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ãƒ—ロジェクトã®ã‚³ãƒ”ーを更新ã—ã¾ã›ã‚“。 + + 有効㪠URL ã®æ¬¡ã®å½¢å¼ã§ã™: + + local/filesystem/path + http://[user@]host[:port][/path] + https://[user@]host[:port][/path] + ssh://[user@]host[:port][/path] + + SSH ã¯è¡Œãå…ˆã®ãƒžã‚·ãƒ³ã®ã‚·ã‚§ãƒ«ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¨ã€ãƒªãƒ¢ãƒ¼ãƒˆã®ãƒ‘スã«hg + ã®ã‚³ãƒ”ーãŒå¿…è¦ã«ãªã‚Šã¾ã™ã€‚SSH を使用ã™ã‚‹ã¨ã€ãƒ‘スã¯ãƒ‡ãƒ•ォルト㧠+ ã¯ãƒªãƒ¢ãƒ¼ãƒˆã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ›ãƒ¼ãƒ ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ç›¸å¯¾ãƒ‘スã«ãªã‚Šã¾ã™; ファ + イルシステムã®ãƒ«ãƒ¼ãƒˆã‹ã‚‰ã®ç›¸å¯¾ãƒ‘スã§ã‚ã‚‹ã“ã¨ã‚’指定ã™ã‚‹ã«ã¯ã€ãƒ‘ + ã‚¹ã®æœ€åˆã«ã‚¹ãƒ©ãƒƒã‚·ãƒ¥ã‚’ 2ã¤ä½¿ç”¨ã—ã¦ãã ã•ã„。 + + オプション: + -u, --update pull ã®å¾Œã«ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’ tip ã«æ›´æ–°ã—ã¾ã™ + -e, --ssh 使用ã™ã‚‹ ssh コマンドを指定ã—ã¾ã™ + --remotecmd リモートå´ã§ä½¿ã‚れる hg コマンドを指定ã—ã¾ã™ + +push :: + ローカルã®ãƒªãƒã‚¸ãƒˆãƒªã®å¤‰æ›´ã‚’指定ã•れãŸè¡Œã先㫠push ã—ã¾ã™ã€‚ + + ã“れ㯠pull ã¨å¯¾ç§°çš„ãªæ“作ã§ã™ã€‚ã“れã¯ç¾åœ¨ã®ãƒªãƒã‚¸ãƒˆãƒªã®å¤‰æ›´ã‚’ + ä»–ã®ãƒªãƒã‚¸ãƒˆãƒªã¸ç§»ã™ã®ã«å½¹ç«‹ã¡ã¾ã™ã€‚ã‚‚ã—行ãå…ˆãŒãƒ­ãƒ¼ã‚«ãƒ«ã§ã‚れ + ã°ã€ã“れã¯ãã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‹ã‚‰ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å¯¾ã—㦠pull + ã™ã‚‹ã®ã¨åŒã˜ã§ã™ã€‚ + + デフォルトã§ã¯ã€push ã¯å®Ÿè¡Œã—ãŸçµæžœãƒªãƒ¢ãƒ¼ãƒˆã®ãƒ˜ãƒƒãƒ‰ã®æ•°ãŒå¢—㈠+ ã‚‹ãªã‚‰ã°ã€å®Ÿè¡Œã‚’æ‹’å¦ã—ã¾ã™ã€‚ã“れã¯ãŸã„ã¦ã„クライアント㌠push + ã™ã‚‹å‰ã« sync ã¨merge を忘れã¦ã„ã‚‹ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚ + + 有効㪠URL ã¯æ¬¡ã®å½¢å¼ã§ã™: + + local/filesystem/path + ssh://[user@]host[:port][/path] + + SSH ã¯è¡Œãå…ˆã®ãƒžã‚·ãƒ³ã®ã‚·ã‚§ãƒ«ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¨ã€ãƒªãƒ¢ãƒ¼ãƒˆã®ãƒ‘ス㫠hg + ã®ã‚³ãƒ”ーãŒå¿…è¦ã«ãªã‚Šã¾ã™ã€‚ + + オプション: + + -f, --force update を強行ã—ã¾ã™ + -e, --ssh 使用ã•れる ssh コマンドを指定ã—ã¾ã™ + --remotecmd リモートå´ã§å®Ÿè¡Œã•れる hg コマンドを指定ã—ã¾ã™ + +rawcommit [-p -d -u -F -m -l]:: + 低レベルã®ã‚³ãƒŸãƒƒãƒˆã§ã€ãƒ˜ãƒ«ãƒ‘ースクリプト中ã§ä½¿ç”¨ã•れã¾ã™ã€‚ + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯é€šå¸¸ã®ãƒ¦ãƒ¼ã‚¶ã«ä½¿ã‚れるã“ã¨ã¯æƒ³å®šã—ã¦ã„ã¾ã›ã‚“。㓠+ れã¯ä¸»ã«ä»–ã® SCM ã‹ã‚‰ã‚¤ãƒ³ãƒãƒ¼ãƒˆã™ã‚‹ã¨ãã«ä¾¿åˆ©ã§ã™ã€‚ + +recover:: + 中断ã•れ㟠commit ã‚„ pull ã‹ã‚‰å¾©å¸°ã—ã¾ã™ã€‚ + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ä¸­æ–­ã•ã‚ŒãŸæ“作ã‹ã‚‰ãƒªãƒã‚¸ãƒˆãƒªã®çŠ¶æ…‹ã‚’ä¿®æ•´ã—よã†ã¨ + 試ã¿ã¾ã™ã€‚ã“れ㯠Mercurial ãŒãã†ã™ã‚‹ã‚ˆã†ææ¡ˆã—ãŸã¨ãã®ã¿å¿…è¦ + ã§ã—ょã†ã€‚ + +remove [options] [files ...]:: + 指定ã•れãŸãƒ•ァイルをリãƒã‚¸ãƒˆãƒªã‹ã‚‰å‰Šé™¤ã™ã‚‹ã“ã¨ã‚’予定ã—ã¾ã™ã€‚ + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ãƒ•ァイルを次ã®ã‚³ãƒŸãƒƒãƒˆæ™‚ã«å‰Šé™¤ã™ã‚‹ã“ã¨ã‚’予定ã—ã¾ + ã™ã€‚ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ãƒ•ァイルをç¾åœ¨ã®æžã‹ã‚‰å–り除ãã ã‘ã§ã€ãƒ—ロジェ + クトã®å±¥æ­´å…¨ä½“ã‹ã‚‰ã¯å‰Šé™¤ã—ã¾ã›ã‚“。もã—ファイルãŒä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆ + リ中ã«ã¾ã å­˜åœ¨ã—ã¦ã„れã°ã€ãれらã¯ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‹ã‚‰å‰Šé™¤ã•れ + ã¾ã™ã€‚ + + 別å: rm + +rename :: + コピー先をコピー元ã®ã‚³ãƒ”ーã®ã‚³ãƒ”ーã§ã‚ã‚‹ã¨å°ã‚’ã¤ã‘ã¾ã™; コピー + å…ƒã«å‰Šé™¤ã®å°ã‚’ã¤ã‘ã¾ã™ã€‚ã‚‚ã—コピー先ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ã‚れã°ã€ã‚³ + ピーã¯ãã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã«ç½®ã‹ã‚Œã¾ã™ã€‚ã‚‚ã—コピー先ãŒãƒ•ァイル㪠+ らã€ã‚³ãƒ”ー元㯠1 ã¤ã®ã¿æŒ‡å®šå¯èƒ½ã§ã™ã€‚ + + デフォルトã§ã¯ã€ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯ãƒ•ァイルãŒãã®ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã« + ã‚ã‚‹ã‚‚ã®ã¨ã—ã¦ãã®å†…容をコピーã—ã¾ã™ã€‚ã‚‚ã— --after ã¨ä¸€ç·’ã«å‘¼ + ã³å‡ºã•れれã°ã€æ“作ã¯è¨˜éŒ²ã•れã¾ã™ãŒã€ã‚³ãƒ”ーã¯å®Ÿè¡Œã•れã¾ã›ã‚“。 + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯æ¬¡ã®ã‚³ãƒŸãƒƒãƒˆæ™‚ã«åŠ¹æžœã‚’æŒã¡ã¾ã™ã€‚ + + 注æ„: ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯å®Ÿé¨“çš„ã§ã™ã€‚リãƒãƒ¼ãƒ ã•れãŸãƒ•ァイルをé©åˆ‡ã« + 記録ã§ãã¾ã™ãŒã€ã“ã®æƒ…å ±ã¯ãƒžãƒ¼ã‚¸ã«ã‚ˆã£ã¦ã¾ã å®Œå…¨ã«ã¯ä½¿ã‚れã¾ã› + ã‚“ã—ã€ãƒ­ã‚°ã§å®Œå…¨ã«å ±å‘Šã•れるã“ã¨ã‚‚ã‚りã¾ã›ã‚“。 + + オプション: + -A, --after æ—¢ã«ç™ºç”Ÿã—ãŸãƒªãƒãƒ¼ãƒ ã‚’記録ã—ã¾ã™ + -f, --force 既存ã®å¤‰æ›´ã•れãŸãƒ•ァイルã«ç„¡ç†çŸ¢ç†ã‚³ãƒ”ー㗠+ ã¾ã™ + -p, --parents コピー先ã«ã‚³ãƒ”ー元ã®ãƒ‘スを追加ã—ã¾ã™ + + 別å: mv + +revert [names ...]:: + 指定ã•れãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚„ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®æœªã‚³ãƒŸãƒƒãƒˆã®å¤‰æ›´ã‚’å–り消ã—ã¾ + ã™ã€‚ã“れã¯é–¢é€£ã—ãŸãƒ•ァイルã®å†…容をコミットã•れã¦ãªã„çŠ¶æ…‹ã«æˆ»ã— + ã¾ã™ã€‚ + + ã‚‚ã—ファイルãŒå‰Šé™¤ã•れã¦ã„れã°ã€å†ä½œæˆã•れã¾ã™ã€‚ã‚‚ã—ファイル㮠+ 実行モードãŒå¤‰æ›´ã•れã¦ã„れã°ã€ãƒªã‚»ãƒƒãƒˆã•れã¾ã™ã€‚ + + ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒæŒ‡å®šã•れãŸå ´åˆã€ãã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã®ã™ã¹ã¦ã®ãƒ•ã‚¡ + イルã¨ã‚µãƒ–ディレクトリãŒå…ƒã«æˆ»ã•れã¾ã™ã€‚ + + ã‚‚ã—å¼•æ•°ãŒæŒ‡å®šã•れãªã‘れã°ã€ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã®å…¨ã¦ã®ãƒ•ァイ + ルã¨ã‚µãƒ–ディレクトリãŒå…ƒã®æˆ»ã•れã¾ã™ã€‚ + + オプション: + -r, --rev å…ƒã«æˆ»ã™å…ˆã®ãƒªãƒ“ジョンを指定ã—ã¾ã™ + -n, --nonrecursive サブディレクトリをå†å¸°çš„ã«è¾¿ã‚‰ãªã„よã†ã« + ã—ã¾ã™ + +root:: + ç¾åœ¨ã®ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ«ãƒ¼ãƒˆãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’表示ã—ã¾ã™ã€‚ + +serve [options]:: + ローカル㮠HTTP リãƒã‚¸ãƒˆãƒªã¨ pull サーãƒã‚’èµ·å‹•ã—ã¾ã™ã€‚ + + デフォルトã§ã¯ã€ã‚µãƒ¼ãƒã¯ã‚¢ã‚¯ã‚»ã‚¹ãƒ­ã‚°ã‚’標準出力ã«ã€ã‚¨ãƒ©ãƒ¼ãƒ­ã‚°ã‚’ + 標準エラー出力ã«å‡ºåŠ›ã—ã¾ã™ã€‚ファイルã«ãƒ­ã‚°ã‚’å–ã‚‹ã«ã¯ "-A" 㨠+ "-E" オプションを使ã£ã¦ãã ã•ã„。 + + オプション: + -A, --accesslog アクセスログãŒå‡ºåŠ›ã•れるファイルã®åå‰ + を指定ã—ã¾ã™ + -E, --errorlog エラーログãŒå‡ºåŠ›ã•れるファイルã®åå‰ã‚’ + 指定ã—ã¾ã™ + -a, --address 使用ã™ã‚‹ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’指定ã—ã¾ã™ + -p, --port 使用ã™ã‚‹ãƒãƒ¼ãƒˆã‚’指定ã—ã¾ã™ + (デフォルト: 8000) + -n, --name ウェブページã§è¡¨ç¤ºã™ã‚‹åå‰ã‚’指定ã—ã¾ã™ + (デフォルト: working dir) + -t, --templatedir 使用ã™ã‚‹ã‚¦ã‚§ãƒ–ã®é››åž‹ã‚’指定ã—ã¾ã™ + -6, --ipv6 IPv4 ã«åŠ ãˆã¦ IPv6 も使用ã—ã¾ã™ + +status [options] [files]:: + 作業ディレクトリ中ã®å¤‰æ›´ã•れãŸãƒ•ァイルを表示ã—ã¾ã™ã€‚åå‰ãŒæŒ‡å®š + ã•れãªã‘れã°ã€å…¨ã¦ã®ãƒ•ァイルãŒè¡¨ç¤ºã•れã¾ã™ã€‚åå‰ãŒæŒ‡å®šã•れれã°ã€ + 指定ã•れãŸåå‰ã«ãƒžãƒƒãƒã—ãŸãƒ•ァイルã®ã¿ãŒè¡¨ç¤ºã•れã¾ã™ã€‚ + + ファイルã®çŠ¶æ…‹ã‚’è¡¨ç¤ºã™ã‚‹ã®ã«ä½¿ã‚れる記å·: + + M = 変更ã•れã¾ã—㟠+ A = 追加ã•れã¾ã—㟠+ R = 削除ã•れã¾ã—㟠+ ? = ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ä¸‹ã«ã‚りã¾ã›ã‚“ + + オプション: + + -m, --modified 変更ã•れãŸãƒ•ァイルã®ã¿ã‚’表示ã—ã¾ã™ + -a, --added 追加ã•れãŸãƒ•ァイルã®ã¿ã‚’表示ã—ã¾ã™ + -r, --removed 削除ã•れãŸãƒ•ァイルã®ã¿ã‚’表示ã—ã¾ã™ + -u, --unknown 䏿˜Žãª(ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ä¸‹ã«ãªã„)ファイルã®ã¿ + を表示ã—ã¾ã™ + -n, --no-status çŠ¶æ…‹ã‚’ç¤ºã™æŽ¥é ­è¾žã‚’éš ã—ã¾ã™ + -0, --print0 xargs ã¨ä¸€ç·’ã«ä½¿ã†ãŸã‚ã«ã€ãƒ•ァイルåã‚’ NUL + ã§çµ‚ãˆã¾ã™ + -I, --include 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’å«ã‚ã¾ + ã™ + -X, --exclude 与ãˆã‚‰ã‚ŒãŸãƒ‘ターンã«ãƒžãƒƒãƒã—ãŸåå‰ã‚’除外㗠+ ã¾ã™ + +tag [-l -m -d -u ] [revision]:: + 特定ã®ãƒªãƒ“ジョン㫠を使ã£ã¦åå‰ã‚’付ã‘ã¾ã™ã€‚ + + ã‚¿ã‚°ã¯ãƒªãƒã‚¸ãƒˆãƒªã®ç‰¹å®šã®ãƒªãƒ“ジョンã«åå‰ã‚’付ã‘ã‚‹ãŸã‚ã«ä½¿ã‚れ〠+ ãã—ã¦ç•°ãªã‚‹ãƒªãƒ“ジョンを比較ã—ãŸã‚Šã€é‡è¦ãªä»¥å‰ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«æˆ»ã£ + ãŸã‚Šã€ãƒªãƒªãƒ¼ã‚¹ç­‰ã®åˆ†å²ç‚¹ã«å°ã‚’ã¤ã‘ãŸã‚Šã™ã‚‹ã®ã«ä¾¿åˆ©ã§ã™ã€‚ + + ã‚‚ã—ãƒãƒ¼ã‚¸ãƒ§ãƒ³ãŒæŒ‡å®šã•れãªã‘れã°ã€tip ãŒä½¿ã‚れã¾ã™ã€‚ + + ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã€é…布ã€ã‚¿ã‚°ã®ãƒžãƒ¼ã‚¸ã‚’楽ã«ã™ã‚‹ãŸã‚ã«ã€ãれら㯠+ ".hgtags" ã¨ã„ã†åå‰ã®ãƒ•ã‚¡ã‚¤ãƒ«ã«æ ¼ç´ã•れã€ä»–ã®ãƒ—ロジェクトã®ãƒ•ã‚¡ + イルã¨åŒæ§˜ã«æ‰±ã£ãŸã‚Šã€å¿…è¦ã§ã‚ã‚Œã°æ‰‹ã§ç·¨é›†ã§ãã¾ã™ã€‚ + + オプション: + -l, --local タグをローカルã«ã—ã¾ã™ + -m, --message タグをコミットã—ãŸã¨ãã®ãƒ­ã‚°ã®ã‚¨ãƒ³ãƒˆãƒªã® + メッセージを指定ã—ã¾ã™ + -d, --date ã‚³ãƒŸãƒƒãƒˆã®æ—¥ä»˜ã‚’指定ã—ã¾ã™ + -u, --user コミットã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã‚’指定ã—ã¾ã™ + + 注æ„: ローカルã®ã‚¿ã‚°ã¯ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã‚„é…布ã•れるã“ã¨ã¯ãªãã€ã¾ + ãŸ. hg/localtags ãƒ•ã‚¡ã‚¤ãƒ«ã«æ ¼ç´ã•れã¾ã™ã€‚ã‚‚ã—åŒã˜åå‰ã®ãƒ­ãƒ¼ã‚« + ルã®ã‚¿ã‚°ã¨å…¬é–‹ã•れãŸã‚¿ã‚°ãŒã‚れã°ã€ãƒ­ãƒ¼ã‚«ãƒ«ã®ã‚¿ã‚°ãŒä½¿ã‚れã¾ã™ã€‚ + +tags:: + リãƒã‚¸ãƒˆãƒªã®ã‚¿ã‚°ã‚’列挙ã—ã¾ã™ã€‚ + + ã“れã¯é€šå¸¸ã®ã‚¿ã‚°ã¨ãƒ­ãƒ¼ã‚«ãƒ«ã®ã‚¿ã‚°ã‚’両方列挙ã—ã¾ã™ã€‚ + +tip:: + tip ã®ãƒªãƒ“ジョンを表示ã—ã¾ã™ã€‚ + +unbundle :: + (実験的) + + bundle コマンドã§ç”Ÿæˆã•れãŸã€åœ§ç¸®æ¸ˆã¿ãƒã‚§ãƒ³ã‚¸ã‚°ãƒ«ãƒ¼ãƒ—ファイル + ã‚’é©ç”¨ã—ã¾ã™ã€‚ + +undo:: + 最後㮠commit ã‚„ pull ã®å‡¦ç†ã‚’å–り消ã—ã¾ã™ã€‚ + + リãƒã‚¸ãƒˆãƒªã®æœ€å¾Œã® pull ã‚„ commit 処ç†ã‚’巻戻ã—ã€ãƒ—ロジェクトを + ãれよりå‰ã®çŠ¶æ…‹ã«æˆ»ã—ã¾ã™ã€‚ + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯æ³¨æ„ã—ã¦ä½¿ã£ã¦ãã ã•ã„。ã¾ã  1回㮠undo ã ã‘ã§ã€ + redo ã¯ã‚りã¾ã›ã‚“。 + + ã“ã®ã‚³ãƒžãƒ³ãƒ‰ã¯å…¬é–‹ã—ãŸãƒªãƒã‚¸ãƒˆãƒªã§ä½¿ã‚れるã“ã¨ã¯æƒ³å®šã—ã¦ã„ã¾ã› + ん。ã„ã£ãŸã‚“ä»–ã®ãƒ¦ãƒ¼ã‚¶ã‹ã‚‰ pull ã§å¤‰æ›´ãŒè¦‹ãˆã‚‹ã‚ˆã†ã«ãªã‚Œã°ã€ãƒ­ãƒ¼ + カルã§ãれをå–り消ã—ã¦ã‚‚æ„味ãŒã‚りã¾ã›ã‚“。 + +update [-m -C] [revision]:: + 作業ディレクトリを指定ã•れãŸãƒªãƒ“ã‚¸ãƒ§ãƒ³ã«æ›´æ–°ã—ã¾ã™ã€‚ + + デフォルトã§ã¯ã€æ›´æ–°ã«ã‚ˆã‚Šãƒ­ãƒ¼ã‚«ãƒ«ã®å¤‰æ›´ã‚’マージã—ãŸã‚Šç ´æ£„ã—㟠+ りã™ã‚‹ã“ã¨ãŒå¿…è¦ã¨ãªã‚‹ã¨ãã€update ã¯ãれを拒å¦ã—ã¾ã™ã€‚ + + -m オプションã§ã€ãƒžãƒ¼ã‚¸ãŒå®Ÿè¡Œã•れã¾ã™ã€‚ + + -C オプションã§ã€ãƒ­ãƒ¼ã‚«ãƒ«ã®å¤‰æ›´ãŒå¤±ã‚れã¾ã™ã€‚ + + オプション: + -m, --merge æžã®ãƒžãƒ¼ã‚¸ã‚’許å¯ã—ã¾ã™ + -C, --clean ローカルã§å¤‰æ›´ã•れãŸãƒ•ァイルを上書ãã—ã¾ã™ + + 別å: up checkout co + +verify:: + ç¾åœ¨ã®ãƒªãƒã‚¸ãƒˆãƒªã®æ•´åˆæ€§ã‚’検証ã—ã¾ã™ã€‚ + + ã“れã¯ãƒªãƒã‚¸ãƒˆãƒªã®æ•´åˆæ€§ã‚’å…¨é¢çš„ã«ãƒã‚§ãƒƒã‚¯ã—ã€ãƒã‚§ãƒ³ã‚¸ãƒ­ã‚°ã®å„ + エントリã€manifest, 管ç†ä¸‹ã®ãƒ•ァイルã®ãƒãƒƒã‚·ãƒ¥ã¨ãƒã‚§ãƒƒã‚¯ã‚µãƒ ã‚’ + 検証ã—ã€ã¾ãŸã‚¯ãƒ­ã‚¹ãƒªãƒ³ã‚¯ã¨ã‚¤ãƒ³ãƒ‡ã‚¯ã‚¹ã®æ•´åˆæ€§ã‚‚検証ã—ã¾ã™ã€‚ + +ファイルåã¨ãƒ‘ターン +--------- + + Mercurial ã§ã¯åŒæ™‚ã«è¤‡æ•°ã®ãƒ•ァイルを識別ã™ã‚‹ã®ã«è¤‡æ•°ã®è¨˜æ³•ãŒä½¿ + ãˆã¾ã™ã€‚ + + デフォルトã§ã¯ã€Mercurial ã¯ãƒ•ァイルåをシェルã®ã‚¹ã‚¿ã‚¤ãƒ«ã®æ‹¡å¼µ + glob パターンã¨ã—ã¦æ‰±ã„ã¾ã™ã€‚ + + 別ã®ãƒ‘ã‚¿ãƒ¼ãƒ³è¡¨è¨˜ã¯æ˜Žç¤ºçš„ã«æŒ‡å®šã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + + パターンマッãƒãƒ³ã‚°ãªã—ã®å˜ç´”ãªãƒ‘スåを使ã†ã«ã¯ã€ãƒ‘スåã‚’ + "path:" ã§å§‹ã‚ã¦ãã ã•ã„。ã“れらã®ãƒ‘スåã¯ã€ç¾åœ¨ã®ãƒªãƒã‚¸ãƒˆãƒªã® + ルートã‹ã‚‰å®Œå…¨ã«ãƒžãƒƒãƒã—ã¦ã„ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚ + + æ‹¡å¼µ glob を使ã†ã«ã¯ã€åå‰ã‚’ "glob:" ã§å§‹ã‚ã¦ãã ã•ã„。glob 㯠+ ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ã¿ã«é©ç”¨ã•れã¾ã™: "*.c" ã¨ã„ã£ãŸ glob ã¯ç¾ + 在ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã® ".c" ã§çµ‚ã‚るファイルã®ã¿ã«ãƒžãƒƒãƒã—ã¾ã™ã€‚ + + サãƒãƒ¼ãƒˆã•れã¦ã„ã‚‹ glob æ–‡æ³•ã®æ‹¡å¼µã¯ãƒ‘スã®åˆ†é›¢è¨˜å·ã‚’è¶Šãˆã¦å…¨ã¦ + ã®æ–‡å­—列ã«ãƒžãƒƒãƒã™ã‚‹ "**" ã¨ã€"a ã¾ãŸã¯ b" ã‚’æ„味ã™ã‚‹ "{a,b}" + ã§ã™ã€‚ + + Perl/Python ã®æ­£è¦è¡¨ç¾ã‚’使ã†ã«ã¯ã€åå‰ã‚’ "re:" ã§å§‹ã‚ã¦ãã ã• + ã„。正è¦è¡¨ç¾ã«ã‚ˆã‚‹ãƒžãƒƒãƒã¯ãƒªãƒã‚¸ãƒˆãƒªã®ãƒ«ãƒ¼ãƒˆã®å›ºå®šã•れã¦ã„ã¾ã™ã€‚ + + å˜ç´”ãªä¾‹: + + path:foo/bar リãƒã‚¸ãƒˆãƒªã®ãƒ«ãƒ¼ãƒˆã«ã‚ã‚‹ foo ã¨ã„ã†ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª + ã® bar ã¨ã„ã†åå‰ + path:path:name "path:name" ã¨ã„ã†åå‰ã®ãƒ•ァイルã¾ãŸã¯ãƒ‡ã‚£ãƒ¬ã‚¯ + トリ + + Glob ã®ä¾‹: + + glob:*.c ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã® ".c" ã§çµ‚ã‚ã‚‹å…¨ã¦ã®åå‰ + *.c ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã® ".c" ã§çµ‚ã‚ã‚‹å…¨ã¦ã®åå‰ + **.c ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¨å…¨ã¦ã®ã‚µãƒ–ディレクトリ中㮠+ ".c" ã§çµ‚ã‚ã‚‹å…¨ã¦ã®åå‰ + foo/*.c ディレクトリ foo 中㮠".c" ã§çµ‚ã‚ã‚‹å…¨ã¦ã®åå‰ + foo/**.c ディレクトリ foo ã¨ãã®å…¨ã¦ã®ã‚µãƒ–ディレクトリ中 + ã® ".c" ã§çµ‚ã‚ã‚‹å…¨ã¦ã®åå‰ + + æ­£è¦è¡¨ç¾ã®ä¾‹: + + re:.*\.c$ リãƒã‚¸ãƒˆãƒªå…¨ä½“ã®ä¸­ã® ".c" ã§çµ‚ã‚ã‚‹å…¨ã¦ã®åå‰ + + +å˜ä¸€ã®ãƒªãƒ“ã‚¸ãƒ§ãƒ³ã®æŒ‡å®šæ³• +----------- + + Mercurial ã§ã¯å€‹ã€…ã®ãƒªãƒ“ジョンを識別ã™ã‚‹ã®ã«è¤‡æ•°ã®è¨˜æ³•ãŒä½¿ãˆã¾ + ã™ã€‚ + + å˜ç´”ãªæ•´æ•°ã¯ãƒªãƒ“ジョンナンãƒãƒ¼ã¨ã—ã¦æ‰±ã‚れã¾ã™ã€‚è² ã®æ•´æ•°ã¯tip + ã‹ã‚‰ã®ã‚ªãƒ•セットã¨ã—ã¦æ‰±ã‚れã€-1 ㌠tip を表ã—ã¾ã™ã€‚ + + 40 æ¡ã® 16 é€²æ•°ã®æ–‡å­—列ã¯ãƒ¦ãƒ‹ãƒ¼ã‚¯ãªãƒªãƒ“ジョン識別å­ã¨ã—ã¦æ‰±ã‚ + れã¾ã™ã€‚ + + 40 æ¡ã‚ˆã‚Šå°‘ãªã„ 16 é€²æ•°ã®æ–‡å­—列ã¯ãƒ¦ãƒ‹ãƒ¼ã‚¯ãªãƒªãƒ“ジョン識別å­ã¨ + ã—ã¦æ‰±ã‚れã€çŸ­ã„å½¢å¼ã®è­˜åˆ¥å­ã¨å‘¼ã°ã‚Œã¾ã™ã€‚短ã„å½¢å¼ã®è­˜åˆ¥å­ã¯ã + れãŒå®Œå…¨ãªé•·ã•ã®è­˜åˆ¥å­ã®æŽ¥é ­èªžã§ã‚ã‚‹ã¨ãã ã‘有効ã§ã™ã€‚ + + ä»–ã®æ–‡å­—列ã¯å…¨ã¦ã‚¿ã‚°åã¨ã—ã¦æ‰±ã‚れã¾ã™ã€‚ã‚¿ã‚°ã¯ã‚るリビジョン識 + 別å­ã«é–¢é€£ä»˜ã‘られãŸã‚·ãƒ³ãƒœãƒ«åã§ã™ã€‚ã‚¿ã‚°å㯠":" 文字をå«ã‚“ã§ + ã¯ã„ã‘ã¾ã›ã‚“。 + + リビジョンå "tip" ã¯ç‰¹åˆ¥ãªã‚¿ã‚°ã§ã€å¸¸ã«ä¸€ç•ªæœ€æ–°ã®ãƒªãƒ“ジョンを + 指ã—ã¾ã™ã€‚ + +複数ã®ãƒªãƒ“ã‚¸ãƒ§ãƒ³ã®æŒ‡å®šæ³• +----------- + + Mercurial ㌠1ã¤ã‚ˆã‚Šå¤šãã®ãƒªãƒ“ジョンをå—ã‘ã„れるã¨ãã€ãれら㯠+ åˆ¥ã€…ã«æŒ‡å®šã•れるã‹ã€é€£ç¶šã—ãŸç¯„囲ã¨ã—㦠":" 文字ã§åŒºåˆ‡ã£ã¦ä¸Žãˆ + られるã‹ã‚‚れã¾ã›ã‚“。 + + ç¯„å›²è¡¨è¨˜ã®æ§‹æ–‡ã¯ [BEGIN]:[END] ã§ BEGIN 㨠END ã¯ãƒªãƒ“ジョン㮠+ 識別å­ã§ã™ã€‚BEGIN ã‚‚ END も両方ã¨ã‚‚ä»»æ„ã§ã™ã€‚ã‚‚ã— BEGIN ãŒæŒ‡å®š + ã•れãªã‘れã°ã€ãƒ‡ãƒ•ォルトã§ãƒªãƒ“ジョンナンãƒãƒ¼ 0 ã«ãªã‚Šã¾ã™ã€‚ã‚‚ + ã— END ãŒæŒ‡å®šã•れãªã‘れã°ã€ãƒ‡ãƒ•ォルト㧠tip ã«ãªã‚Šã¾ã™ã€‚従ã£ã¦ + 範囲 ":" 㯠"å…¨ã¦ã®ãƒªãƒ“ジョン" ã‚’æ„味ã—ã¾ã™ã€‚ + + ã‚‚ã— BEGIN ㌠END より大ãã‘れã°ã€ãƒªãƒ“ジョンã¯é€†ã®é †åºã¨ã—ã¦æ‰± + ã‚れã¾ã™ã€‚ + + 範囲ã¯é–‰åŒºé–“ã¨ã—ã¦å‹•作ã—ã¾ã™ã€‚ã“れã¯ç¯„囲㌠3:5 㯠3,4,5 ã«ãªã‚‹ + ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚åŒæ§˜ã«ã€ç¯„囲 4:2 㯠4,3,2 ã«ãªã‚Šã¾ã™ã€‚ + +環境変数 +---- + +HGEDITOR:: + ã“れã¯ã‚³ãƒŸãƒƒãƒæ™‚ã«ä½¿ã‚れるエディタã®åå‰ã§ã™ã€‚デフォルトã§ã¯ + EDITOR ã®å€¤ãŒä½¿ã‚れã¾ã™ã€‚ + + (廃止予定ã§ã™, .hgrc を使ã£ã¦ãã ã•ã„) + +HGMERGE:: + merge 時ã®è¡çªã‚’解決ã™ã‚‹ã®ã«ä½¿ã‚れる実行ファイルã§ã™ã€‚プログラ + ムã¯3 ã¤ã®å¼•æ•°ã§å®Ÿè¡Œã•れã¾ã™: ローカルã®ãƒ•ァイルã€ãƒªãƒ¢ãƒ¼ãƒˆã®ãƒ•ã‚¡ + イルã€1 世代å‰ã®ãƒ•ァイルã§ã™ã€‚ + + デフォルトã®ãƒ—ログラム㯠"hgmerge" ã§ã€ã“れ㯠Mercurial ã«ã‚ˆã£ + ã¦æä¾›ã•れる常識的ãªè¨­å®šã®ã‚·ã‚§ãƒ«ã‚¹ã‚¯ãƒªãƒ—トã§ã™ã€‚ + + (廃止予定ã§ã™, .hgrc を使ã£ã¦ãã ã•ã„) + +HGUSER:: + ã“れã¯ã‚³ãƒŸãƒƒãƒˆæ™‚ã®è‘—者ã¨ã—ã¦ä½¿ã‚れる文字列ã§ã™ã€‚ + + (廃止予定ã§ã™, .hgrc を使ã£ã¦ãã ã•ã„) + +EMAIL:: + ã‚‚ã— HGUSER ãŒè¨­å®šã•れã¦ã„ãªã‘れã°ã€ã“れãŒã‚³ãƒŸãƒƒãƒˆæ™‚ã®è‘—者ã¨ã— + ã¦ä½¿ã‚れã¾ã™ã€‚ + +LOGNAME:: + ã‚‚ã— HGUSER ã‚‚ EMAIL も設定ã•れã¦ã„ãªã‘れã°ã€ã‚³ãƒŸãƒƒãƒˆæ™‚ã®è‘—者 + ã¨ã—ã¦LOGNAME ãŒ('@hostname' を付ã‘ãŸå½¢ã§)使ã‚れã¾ã™ã€‚ + +EDITOR:: + ã“れ㯠hgmerge スクリプト中ã§ä½¿ã‚れるエディタã®åå‰ã§ã™ã€‚ã‚‚ã— + HGEDITOR ãŒè¨­å®šã•れã¦ã„ãªã‘れã°ã€ã‚³ãƒŸãƒƒãƒˆæ™‚ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã«ä½¿ã‚ + れã¾ã™ã€‚デフォルト㯠'vi' ã§ã™ã€‚ + +PYTHONPATH:: + ã“れã¯ã‚¤ãƒ³ãƒãƒ¼ãƒˆã•れるモジュールを見ã¤ã‘ã‚‹ãŸã‚ã« Python ã«ã‚ˆã£ + ã¦ä½¿ã‚れã€Mercurial ãŒã‚·ã‚¹ãƒ†ãƒ å…¨ä½“ã«ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•れã¦ã„ãªã‘れ + ã°ã€é©åˆ‡ã«è¨­å®šã•れる必è¦ãŒã‚ã‚‹ã§ã—ょã†ã€‚ + +ファイル +---- + .hgignore:: + ã“ã®ãƒ•ァイルã¯(1行ã”ã¨ã«) hg ã«ã‚ˆã£ã¦ç„¡è¦–ã•れるã¹ãファイルを + 記述ã—ãŸæ­£è¦è¡¨ç¾ã‚’å«ã¿ã¾ã™ã€‚ + + .hgtags:: + ã“ã®ãƒ•ァイルã¯ãƒªãƒã‚¸ãƒˆãƒªã®å†…容ã®ã‚¿ã‚°ä»˜ã‘ã•れãŸãƒãƒ¼ã‚¸ãƒ§ãƒ³ã«ä¸€è‡´ + ã—ãŸãƒãƒƒã‚·ãƒ¥å€¤ã¨ãƒ†ã‚­ã‚¹ãƒˆã®ã‚¿ã‚°å(ãれãžã‚Œã¯ç©ºç™½ã§åŒºåˆ‡ã‚‰ã‚Œã¾ã™)ã‚’ + å«ã¿ã¾ã™ã€‚ + + /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc:: + ã“ã®ãƒ•ァイルã¯ãƒ‡ãƒ•ォルトã®è¨­å®šã‚’å«ã¿ã¾ã™ã€‚.hg/hgrc ã®å€¤ã¯ + $HOME/.hgrc ã®è¨­å®šã‚’上書ãã—ã€$HOME/.hgrc ã®è¨­å®šã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«ãª + /etc/mercurial/hgrc ã®è¨­å®šã‚’上書ãã—ã¾ã™ã€‚ã“れらã®ãƒ•ァイルã®å†… + å®¹ã¨æ›¸å¼ã®è©³ç´°ã«ã¤ã„ã¦ã¯ hgrc(5) ã‚’å‚ç…§ã—ã¦ãã ã•ã„。 + +ãƒã‚° +-- +沢山ã‚ã‚‹ã§ã—ょã†ã‹ã‚‰ã€ã‚‚ã—ãƒã‚°ã‚’見ã¤ã‘ãŸã‚‰ãれをメーリングリスト +(ä¸‹ã®æƒ…å ±æºã‚’å‚ç…§)ã«é€ã£ã¦ãã ã•ã„。 + +関連項目 +---- +hgrc(5) + +著者 +-- +Matt Mackall ã«ã‚ˆã‚Šæ›¸ã‹ã‚Œã¾ã—ãŸã€‚ + +æƒ…å ±æº +--- +http://mercurial.selenic.com/[主ãªã‚¦ã‚§ãƒ–サイト] + +http://www.serpentine.com/mercurial[Wiki サイト] + +http://selenic.com/hg[ソースコードã®ãƒªãƒã‚¸ãƒˆãƒª] + +http://selenic.com/mailman/listinfo/mercurial[メーリングリスト] + +著作権情報 +----- +Copyright (C) 2005-2007 Matt Mackall. +ã“ã®ã‚½ãƒ•トウェアã®è‡ªç”±ãªä½¿ç”¨ã¯ GNU 一般公有使用許諾 (GPL) ã®ã‚‚ã¨ã§ +èªã‚られã¾ã™ã€‚ diff --git a/sys/src/cmd/hg/doc/ja/hgrc.5.ja.txt b/sys/src/cmd/hg/doc/ja/hgrc.5.ja.txt new file mode 100644 index 000000000..d775080c6 --- /dev/null +++ b/sys/src/cmd/hg/doc/ja/hgrc.5.ja.txt @@ -0,0 +1,204 @@ +HGRC(5) +======= +Bryan O'Sullivan + +åå‰ +-- +hgrc - Mercurial ã®è¨­å®šãƒ•ァイル + +æ›¸å¼ +-- + +Mercurial システムã¯ãã®æŒ¯èˆžã„ã®æ­£å¸¸ã‚’制御ã™ã‚‹ã®ã«ã€ä¸€é€£ã®è¨­å®šãƒ•ã‚¡ +イルを使用ã—ã¾ã™ã€‚ + +ファイル +---- + +Mercurial 㯠3ã¤ã®ãƒ•ァイルã‹ã‚‰è¨­å®šã‚’読ã¿ã¾ã™: + +/etc/mercurial/hgrc:: + ã“ã®ã‚°ãƒ­ãƒ¼ãƒãƒ«ã®è¨­å®šãƒ•ァイルã®ã‚ªãƒ—ションã¯å®Ÿè¡Œã—ãŸãƒ¦ãƒ¼ã‚¶ã€ãƒ‡ã‚£ + レクトリをå•ã‚ãšå…¨ã¦ã® Mercurial コマンドã«é©ç”¨ã•れã¾ã™ã€‚ + +$HOME/.hgrc:: + ユーザ毎ã®è¨­å®šã‚ªãƒ—ションã§ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’å•ã‚ãšå…¨ã¦ã® + Mercurial コマンドã«é©ç”¨ã•れã¾ã™ã€‚ã“ã®ãƒ•ァイルã®å€¤ã¯ã‚°ãƒ­ãƒ¼ãƒãƒ« + ã®è¨­å®šã‚’上書ãã—ã¾ã™ã€‚ + +/.hg/hgrc:: + リãƒã‚¸ãƒˆãƒªæ¯Žã®è¨­å®šã‚ªãƒ—ションã§ã€ãã®ãƒªãƒã‚¸ãƒˆãƒªã®ã¿ã«é©ç”¨ã•れ㾠+ ã™ã€‚ã“ã®ãƒ•ァイルã¯ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç®¡ç†ã•れãšã€ "clone" æ“作ã§è»¢é€ã• + れるã“ã¨ã‚‚ã‚りã¾ã›ã‚“。ã“ã®ãƒ•ァイルã®å€¤ã¯ã‚°ãƒ­ãƒ¼ãƒãƒ«ã®è¨­å®šã¨ãƒ¦ãƒ¼ + ザ毎ã®è¨­å®šã‚’上書ãã—ã¾ã™ã€‚ + +æ§‹æ–‡ +-- + +設定ファイル㯠"[セクション]" ヘッダã‹ã‚‰å§‹ã¾ã‚‹ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã¨ã€ãれ㫠+ç¶šã"åå‰: 値"ã®ã‚¨ãƒ³ãƒˆãƒªã‹ã‚‰æˆã‚Šã¾ã™: "åå‰=値"ã‚‚èªã‚られã¾ã™ã€‚ + + [spam] + eggs=ham + green= + eggs + +å„行ã¯1ã¤ã®ã‚¨ãƒ³ãƒˆãƒªã‚’å«ã¿ã¾ã™ã€‚ã‚‚ã—æ¬¡ã®è¡ŒãŒã‚¤ãƒ³ãƒ‡ãƒ³ãƒˆã•れã¦ã„ãŸå ´ +åˆã€ãれã¯å‰ã®è¡Œã®ç¶šãã¨ã—ã¦æ‰±ã‚れã¾ã™ã€‚ + +先行ã™ã‚‹ç©ºç™½ã¯å€¤ã‹ã‚‰å–り除ã‹ã‚Œã¾ã™ã€‚空行ã¯èª­ã¿é£›ã°ã•れã¾ã™ã€‚ + +オプションã®å€¤ã¯åŒã˜ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã‚„ã€ç‰¹åˆ¥ãª DEFAULT セクションã®åˆ¥ã® +値をå‚ç…§ã™ã‚‹ãƒ•ォーマット文字列をå«ã‚€ã“ã¨ãŒã§ãã¾ã™ã€‚ + +"#" ã‚„ ";" ã§å§‹ã¾ã‚‹è¡Œã¯ç„¡è¦–ã•れるã®ã§ã€ã‚³ãƒ¡ãƒ³ãƒˆã¨ã—ã¦ä½¿ã†ã“ã¨ãŒã§ +ãã¾ã™ã€‚ + +セクション +----- + +ã“ã®ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã¯ Merucurial ã® "hgrc" ã«ä½¿ã†ã“ã¨ãŒã§ãã‚‹ç•°ãªã£ãŸã‚» +クションã®ãれãžã‚Œã®ç›®çš„ã‚„å¯èƒ½ãªã‚­ãƒ¼ã€ãã—ã¦å–り得る値ã«ã¤ã„ã¦è¨˜è¿° +ã—ã¾ã™ã€‚ + +decode/encode:: + checkout/checkin ã§ãƒ•ァイルを転é€ã™ã‚‹ã¨ãã®ãƒ•ィルターã§ã™ã€‚ã“れ + ã¯å…¸åž‹çš„ã«ã¯æ”¹è¡Œã‚’処ç†ã—ãŸã‚Šã€ä»–ã®åœ°åŸŸåŒ–/標準化ã«ä½¿ã‚れるã§ã—ょ + ã†ã€‚ + + フィルターã¯ãƒ•ィルターパターンã¨ãれã«ç¶šãフィルターコマンドã‹ã‚‰ + ãªã‚Šã¾ã™ã€‚ã‚³ãƒžãƒ³ãƒ‰ã¯æ¨™æº–入力ã‹ã‚‰ã®ãƒ‡ãƒ¼ã‚¿ã‚’å—ã‘付ã‘ã€å¤‰æ›ã—ãŸãƒ‡ãƒ¼ + タを標準出力ã«è¿”ã™å¿…è¦ãŒã‚りã¾ã™ã€‚ + + 例: + + [encode] + # delta 圧縮を改善ã™ã‚‹ãŸã‚ã«ãƒã‚§ãƒƒã‚¯ã‚¤ãƒ³æ™‚ã« gzip ファイルを + # 伸長ã—ã¾ã™ + # 注æ„: å¿…ãšã—も良ã„アイディアã§ã¯ã‚りã¾ã›ã‚“。ãŸã ã®ä¾‹ã§ã™ + *.gz = gunzip + + [decode] + # ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ã出ã™ã¨ãã«ãƒ•ァイルを gzip ã§å†åœ§ç¸®ã—ã¾ã™ + *.gz = gzip + +hooks:: + コミットã®é–‹å§‹ã€çµ‚了時ãªã©æ§˜ã€…ãªã‚¢ã‚¯ã‚·ãƒ§ãƒ³ã§è‡ªå‹•çš„ã«å®Ÿè¡Œã•れるコ + マンドã§ã™ã€‚ + changegroup;; + push ã‚„ pull ã§ãƒã‚§ãƒ³ã‚¸ã‚°ãƒ«ãƒ¼ãƒ—ãŒåŠ ãˆã‚‰ã‚ŒãŸã‚ã¨ã«èµ·å‹•ã—ã¾ã™ã€‚ + commit;; + ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆãŒä½œæˆã•れãŸå¾Œã«èµ·å‹•ã—ã¾ã™ã€‚æ–°ã—ã作æˆã•れãŸãƒã‚§ + ンジセット㮠ID ãŒæ¸¡ã•れã¾ã™ã€‚ + precommit;; + コミットå‰ã«èµ·å‹•ã—ã¾ã™ã€‚終了ステータス 0 ã«ã‚ˆã‚Šã‚³ãƒŸãƒƒãƒˆã‚’続行 + ã—ã¾ã™ã€‚éžã‚¼ãƒ­ã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã§ã‚³ãƒŸãƒƒãƒˆã¯å¤±æ•—ã—ã¾ã™ã€‚ + +http_proxy:: + HTTP プロキシを通ã—ã¦ã‚¦ã‚§ãƒ–を使ã£ãŸ Mercurial ã®ãƒªãƒã‚¸ãƒˆãƒªã«ã‚¢ã‚¯ + セスã™ã‚‹ã®ã«ä½¿ã‚れã¾ã™ã€‚ + host;; + プロキシサーãƒã®ãƒ›ã‚¹ãƒˆåã¨(オプションã®)ãƒãƒ¼ãƒˆã§ã€ä¾‹ãˆã° + "myproxy:8000"ãªã©ã§ã™ã€‚ + no;; + オプションã§ã™ã€‚コンマã§åŒºåˆ‡ã‚‰ã‚ŒãŸãƒ—ロキシを通éŽã™ã¹ãホストå + ã®ãƒªã‚¹ãƒˆã§ã™ã€‚ + passwd;; + オプションã§ã™ã€‚プロキシサーãƒã®èªè¨¼ç”¨ã®ãƒ‘スワードã§ã™ã€‚ + user;; + オプションã§ã™ã€‚プロキシサーãƒã®èªè¨¼ç”¨ã®ãƒ¦ãƒ¼ã‚¶åã§ã™ã€‚ + +paths:: + リãƒã‚¸ãƒˆãƒªã«ã‚·ãƒ³ãƒœãƒ«åを割当ã¦ã¾ã™ã€‚å·¦å´ãŒã‚·ãƒ³ãƒœãƒ«åã§ã€å³å´ãŒãƒª + ãƒã‚¸ãƒˆãƒªã®å ´æ‰€ã‚’示ã™ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚„ URL ã§ã™ã€‚ + +ui:: + ユーザインターフェースã®è¨­å®šã§ã™ã€‚ + debug;; + デãƒãƒƒã‚°æƒ…報を表示ã—ã¾ã™ã€‚True ã‹ False ã‚’å–りã¾ã™ã€‚デフォルト + ã§ã¯ False ã§ã™ã€‚ + editor;; + コミット中ã«ä½¿ç”¨ã™ã‚‹ã‚¨ãƒ‡ã‚£ã‚¿ã§ã™ã€‚デフォルト㯠$EDITOR ã‹ + "vi" ã§ã™ã€‚ + interactive;; + ユーザã«å¯¾ã—ã¦ãƒ—ロンプトを出ã™ã‚ˆã†ã«ã—ã¾ã™ã€‚True ã‹ False ã‚’å– + りã¾ã™ã€‚デフォルトã§ã¯ True ã§ã™ã€‚ + merge;; + 手動ã§ã® merge 中ã«è¡çªã‚’解決ã™ã‚‹ãŸã‚ã«ä½¿ã‚れるプログラムã§ã™ã€‚ + デフォルト㯠"hgmerge" ã§ã™ã€‚ + quiet;; + 表示ã•れる出力ã®é‡ã‚’減らã—ã¾ã™ã€‚True ã‹ False ã‚’å–りã¾ã™ã€‚デフォ + ルト㯠False ã§ã™ã€‚ + remotecmd;; + clone/push/pull æ“作ã§ä½¿ã‚れるリモートã®ã‚³ãƒžãƒ³ãƒ‰ã§ã™ã€‚デフォル + ト㯠'hg' ã§ã™ã€‚ + ssh;; + SSH 接続ã§ä½¿ã‚れるコマンドã§ã™ã€‚デフォルト㯠'ssh' ã§ã™ã€‚ + username;; + コミットを実行ã—ãŸã¨ãã«ä½œæˆã•れるãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã®ã‚³ãƒŸãƒƒã‚¿ã§ã™ã€‚ + 一般的ã«ã¯äººåã¨é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã§ã€ä¾‹ãˆã° "Fred Widget + " ãªã©ã§ã™ã€‚デフォルト㯠$EMAIL ã‹ + username@hostname ã§ã™ã€‚ + verbose;; + 表示ã•れる出力ã®é‡ã‚’増やã—ã¾ã™ã€‚True ã‹ False ã‚’å–りã¾ã™ã€‚デフォ + ルト㯠False ã§ã™ã€‚ + +web:: + ウェブインターフェイスã®è¨­å®šã§ã™ã€‚ + accesslog;; + アクセスログã®å‡ºåŠ›å…ˆã§ã™ã€‚デフォルトã§ã¯æ¨™æº–出力ã§ã™ã€‚ + address;; + ãƒã‚¤ãƒ³ãƒ‰ã™ã‚‹ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ェイスアドレスã§ã™ã€‚デフォルトã§ã¯å…¨ã¦ã§ + ã™ã€‚ + allowbz2;; + リãƒã‚¸ãƒˆãƒªã®ãƒªãƒ“ジョンã‹ã‚‰ .tar.bz2 をダウンロードã•ã›ã‚‹ã‹ã©ã† + ã‹ã§ã™ã€‚デフォルトã§ã¯ false ã§ã™ã€‚ + allowgz;; + リãƒã‚¸ãƒˆãƒªã®ãƒªãƒ“ジョンã‹ã‚‰ .tar.gz をダウンロードã•ã›ã‚‹ã‹ã©ã† + ã‹ã§ã™ã€‚デフォルトã§ã¯ false ã§ã™ã€‚ + allowpull;; + リãƒã‚¸ãƒˆãƒªã‹ã‚‰ pull ã•ã›ã‚‹ã‹ã©ã†ã‹ã§ã™ã€‚デフォルトã§ã¯ true ã§ + ã™ã€‚ + allowzip;; + リãƒã‚¸ãƒˆãƒªã®ãƒªãƒ“ジョンã‹ã‚‰ .zip をダウンロードã•ã›ã‚‹ã‹ã©ã†ã‹ã§ + ã™ã€‚デフォルトã§ã¯ false ã§ã™ã€‚ã“ã®æ©Ÿèƒ½ã¯ä¸€æ™‚ファイルを作æˆã— + ã¾ã™ã€‚ + description;; + リãƒã‚¸ãƒˆãƒªã®ç›®çš„や内容ã«ã¤ã„ã¦ã®ãƒ†ã‚­ã‚¹ãƒˆã«ã‚ˆã‚‹èª¬æ˜Žã§ã™ã€‚デフォ + ルトã§ã¯"unknown" ã§ã™ã€‚ + errorlog;; + エラーログã®å‡ºåŠ›å…ˆã§ã™ã€‚デフォルトã§ã¯æ¨™æº–エラー出力ã§ã™ã€‚ + ipv6;; + IPv6 を使ã†ã‹ã©ã†ã‹ã§ã™ã€‚デフォルトã§ã¯ false ã§ã™ã€‚ + name;; + ウェブインターフェイスを使ã†ã¨ãã®ãƒªãƒã‚¸ãƒˆãƒªã®åå‰ã§ã™ã€‚デフォ + ルトã¯ç¾åœ¨ã®ä½œæ¥­ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ã™ã€‚ + maxchanges;; + ãƒã‚§ãƒ³ã‚¸ãƒ­ã‚°ã«è¨˜è¼‰ã™ã‚‹å¤‰æ›´ã®æœ€å¤§æ•°ã§ã™ã€‚デフォルトã§ã¯ 10 ã§ã™ã€‚ + maxfiles;; + ãƒã‚§ãƒ³ã‚¸ã‚»ãƒƒãƒˆã«è¨˜è¼‰ã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«ã®æœ€å¤§æ•°ã§ã™ã€‚デフォルトã§ã¯ + 10 ã§ã™ã€‚ + port;; + リスンã™ã‚‹ãƒãƒ¼ãƒˆã§ã™ã€‚デフォルト 㯠8000 ã§ã™ã€‚ + style;; + 使用ã™ã‚‹ãƒ†ãƒ³ãƒ—レートマップã®ã‚¹ã‚¿ã‚¤ãƒ«ã§ã™ã€‚ + templates;; + HTML テンプレートã®åœ¨å‡¦ã§ã™ã€‚デフォルトã§ã¯ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ãŸã¨ + ãã®ãƒ‘スã§ã™ã€‚ + +著者 +-- +Bryan O'Sullivan . + +Mercurial 㯠Matt Mackall ã«ã‚ˆã‚Šæ›¸ã‹ã‚Œã¾ã—ãŸã€‚ + +関連項目 +---- +hg(1) + +COPYING +------- +ã“ã®ãƒžãƒ‹ãƒ¥ã‚¢ãƒ«ã®è‘—作権㯠2005 Bryan O'Sullivan ã§ã™ã€‚ +Mercurial ã®è‘—作権㯠2005 Matt Mackall ã§ã™ã€‚ +ã“ã®ã‚½ãƒ•トウェアã®è‡ªç”±ãªä½¿ç”¨ã¯ GNU 一般公有使用許諾 (GPL) ã®ã‚‚ã¨ã§ +èªã‚られã¾ã™ã€‚ diff --git a/sys/src/cmd/hg/hg b/sys/src/cmd/hg/hg new file mode 100755 index 000000000..9e2cdb0e9 --- /dev/null +++ b/sys/src/cmd/hg/hg @@ -0,0 +1,31 @@ +#!/bin/python +# +# mercurial - scalable distributed SCM +# +# Copyright 2005-2007 Matt Mackall +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +# enable importing on demand to reduce startup time +try: + from mercurial import demandimport; demandimport.enable() +except ImportError: + import sys + sys.stderr.write("abort: couldn't find mercurial libraries in [%s]\n" % + ' '.join(sys.path)) + sys.stderr.write("(check your install and PYTHONPATH)\n") + sys.exit(-1) + +# PLAN9 hack to keep hgrc in $home/lib +import os +os.environ['HGRCPATH']=os.environ['home']+'/lib/hgrc' + +import sys +import mercurial.util +import mercurial.dispatch + +for fp in (sys.stdin, sys.stdout, sys.stderr): + mercurial.util.set_binary(fp) + +mercurial.dispatch.run() diff --git a/sys/src/cmd/hg/hg.proto b/sys/src/cmd/hg/hg.proto new file mode 100644 index 000000000..f4f32e625 --- /dev/null +++ b/sys/src/cmd/hg/hg.proto @@ -0,0 +1,14 @@ +rc - sys sys + bin - sys sys + hg - sys sys +sys - sys sys + man - sys sys + 1 - sys sys + hg - sys sys + 8 - sys sys + hgignore - sys sys + hgrc - sys sys + src - sys sys + cmd - sys sys + hg - sys sys + + - sys sys diff --git a/sys/src/cmd/hg/hgeditor b/sys/src/cmd/hg/hgeditor new file mode 100755 index 000000000..8ab51b698 --- /dev/null +++ b/sys/src/cmd/hg/hgeditor @@ -0,0 +1,56 @@ +#!/bin/sh +# +# This is an example of using HGEDITOR to create of diff to review the +# changes while commiting. + +# If you want to pass your favourite editor some other parameters +# only for Mercurial, modify this: +case "${EDITOR}" in + "") + EDITOR="vi" + ;; + emacs) + EDITOR="$EDITOR -nw" + ;; + gvim|vim) + EDITOR="$EDITOR -f -o" + ;; +esac + + +HGTMP="" +cleanup_exit() { + rm -rf "$HGTMP" +} + +# Remove temporary files even if we get interrupted +trap "cleanup_exit" 0 # normal exit +trap "exit 255" 1 2 3 6 15 # HUP INT QUIT ABRT TERM + +HGTMP="${TMPDIR-/tmp}/hgeditor.$RANDOM.$RANDOM.$RANDOM.$$" +(umask 077 && mkdir "$HGTMP") || { + echo "Could not create temporary directory! Exiting." 1>&2 + exit 1 +} + +( + grep '^HG: changed' "$1" | cut -b 13- | while read changed; do + "$HG" diff "$changed" >> "$HGTMP/diff" + done +) + +cat "$1" > "$HGTMP/msg" + +MD5=$(which md5sum 2>/dev/null) || \ + MD5=$(which md5 2>/dev/null) +[ -x "${MD5}" ] && CHECKSUM=`${MD5} "$HGTMP/msg"` +if [ -s "$HGTMP/diff" ]; then + $EDITOR "$HGTMP/msg" "$HGTMP/diff" || exit $? +else + $EDITOR "$HGTMP/msg" || exit $? +fi +[ -x "${MD5}" ] && (echo "$CHECKSUM" | ${MD5} -c >/dev/null 2>&1 && exit 13) + +mv "$HGTMP/msg" "$1" + +exit $? diff --git a/sys/src/cmd/hg/hgext/__init__.py b/sys/src/cmd/hg/hgext/__init__.py new file mode 100644 index 000000000..fdffa2a0f --- /dev/null +++ b/sys/src/cmd/hg/hgext/__init__.py @@ -0,0 +1 @@ +# placeholder diff --git a/sys/src/cmd/hg/hgext/acl.py b/sys/src/cmd/hg/hgext/acl.py new file mode 100644 index 000000000..f9b3927af --- /dev/null +++ b/sys/src/cmd/hg/hgext/acl.py @@ -0,0 +1,107 @@ +# acl.py - changeset access control for mercurial +# +# Copyright 2006 Vadim Gelfer +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. +# + +'''hooks for controlling repository access + +This hook makes it possible to allow or deny write access to portions +of a repository when receiving incoming changesets. + +The authorization is matched based on the local user name on the +system where the hook runs, and not the committer of the original +changeset (since the latter is merely informative). + +The acl hook is best used along with a restricted shell like hgsh, +preventing authenticating users from doing anything other than +pushing or pulling. The hook is not safe to use if users have +interactive shell access, as they can then disable the hook. +Nor is it safe if remote users share an account, because then there +is no way to distinguish them. + +To use this hook, configure the acl extension in your hgrc like this:: + + [extensions] + hgext.acl = + + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook + + [acl] + # Check whether the source of incoming changes is in this list + # ("serve" == ssh or http, "push", "pull", "bundle") + sources = serve + +The allow and deny sections take a subtree pattern as key (with a glob +syntax by default), and a comma separated list of users as the +corresponding value. The deny list is checked before the allow list +is. :: + + [acl.allow] + # If acl.allow is not present, all users are allowed by default. + # An empty acl.allow section means no users allowed. + docs/** = doc_writer + .hgtags = release_engineer + + [acl.deny] + # If acl.deny is not present, no users are refused by default. + # An empty acl.deny section means all users allowed. + glob pattern = user4, user5 + ** = user6 +''' + +from mercurial.i18n import _ +from mercurial import util, match +import getpass, urllib + +def buildmatch(ui, repo, user, key): + '''return tuple of (match function, list enabled).''' + if not ui.has_section(key): + ui.debug(_('acl: %s not enabled\n') % key) + return None + + pats = [pat for pat, users in ui.configitems(key) + if user in users.replace(',', ' ').split()] + ui.debug(_('acl: %s enabled, %d entries for user %s\n') % + (key, len(pats), user)) + if pats: + return match.match(repo.root, '', pats) + return match.exact(repo.root, '', []) + + +def hook(ui, repo, hooktype, node=None, source=None, **kwargs): + if hooktype != 'pretxnchangegroup': + raise util.Abort(_('config error - hook type "%s" cannot stop ' + 'incoming changesets') % hooktype) + if source not in ui.config('acl', 'sources', 'serve').split(): + ui.debug(_('acl: changes have source "%s" - skipping\n') % source) + return + + user = None + if source == 'serve' and 'url' in kwargs: + url = kwargs['url'].split(':') + if url[0] == 'remote' and url[1].startswith('http'): + user = urllib.unquote(url[3]) + + if user is None: + user = getpass.getuser() + + cfg = ui.config('acl', 'config') + if cfg: + ui.readconfig(cfg, sections = ['acl.allow', 'acl.deny']) + allow = buildmatch(ui, repo, user, 'acl.allow') + deny = buildmatch(ui, repo, user, 'acl.deny') + + for rev in xrange(repo[node], len(repo)): + ctx = repo[rev] + for f in ctx.files(): + if deny and deny(f): + ui.debug(_('acl: user %s denied on %s\n') % (user, f)) + raise util.Abort(_('acl: access denied for changeset %s') % ctx) + if allow and not allow(f): + ui.debug(_('acl: user %s not allowed on %s\n') % (user, f)) + raise util.Abort(_('acl: access denied for changeset %s') % ctx) + ui.debug(_('acl: allowing changeset %s\n') % ctx) diff --git a/sys/src/cmd/hg/hgext/bookmarks.py b/sys/src/cmd/hg/hgext/bookmarks.py new file mode 100644 index 000000000..58aaec4fa --- /dev/null +++ b/sys/src/cmd/hg/hgext/bookmarks.py @@ -0,0 +1,340 @@ +# Mercurial extension to provide the 'hg bookmark' command +# +# Copyright 2008 David Soria Parra +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''track a line of development with movable markers + +Bookmarks are local movable markers to changesets. Every bookmark +points to a changeset identified by its hash. If you commit a +changeset that is based on a changeset that has a bookmark on it, the +bookmark shifts to the new changeset. + +It is possible to use bookmark names in every revision lookup (e.g. hg +merge, hg update). + +By default, when several bookmarks point to the same changeset, they +will all move forward together. It is possible to obtain a more +git-like experience by adding the following configuration option to +your .hgrc:: + + [bookmarks] + track.current = True + +This will cause Mercurial to track the bookmark that you are currently +using, and only update it. This is similar to git's approach to +branching. +''' + +from mercurial.i18n import _ +from mercurial.node import nullid, nullrev, hex, short +from mercurial import util, commands, localrepo, repair, extensions +import os + +def parse(repo): + '''Parse .hg/bookmarks file and return a dictionary + + Bookmarks are stored as {HASH}\\s{NAME}\\n (localtags format) values + in the .hg/bookmarks file. They are read by the parse() method and + returned as a dictionary with name => hash values. + + The parsed dictionary is cached until a write() operation is done. + ''' + try: + if repo._bookmarks: + return repo._bookmarks + repo._bookmarks = {} + for line in repo.opener('bookmarks'): + sha, refspec = line.strip().split(' ', 1) + repo._bookmarks[refspec] = repo.lookup(sha) + except: + pass + return repo._bookmarks + +def write(repo, refs): + '''Write bookmarks + + Write the given bookmark => hash dictionary to the .hg/bookmarks file + in a format equal to those of localtags. + + We also store a backup of the previous state in undo.bookmarks that + can be copied back on rollback. + ''' + if os.path.exists(repo.join('bookmarks')): + util.copyfile(repo.join('bookmarks'), repo.join('undo.bookmarks')) + if current(repo) not in refs: + setcurrent(repo, None) + wlock = repo.wlock() + try: + file = repo.opener('bookmarks', 'w', atomictemp=True) + for refspec, node in refs.iteritems(): + file.write("%s %s\n" % (hex(node), refspec)) + file.rename() + finally: + wlock.release() + +def current(repo): + '''Get the current bookmark + + If we use gittishsh branches we have a current bookmark that + we are on. This function returns the name of the bookmark. It + is stored in .hg/bookmarks.current + ''' + if repo._bookmarkcurrent: + return repo._bookmarkcurrent + mark = None + if os.path.exists(repo.join('bookmarks.current')): + file = repo.opener('bookmarks.current') + # No readline() in posixfile_nt, reading everything is cheap + mark = (file.readlines() or [''])[0] + if mark == '': + mark = None + file.close() + repo._bookmarkcurrent = mark + return mark + +def setcurrent(repo, mark): + '''Set the name of the bookmark that we are currently on + + Set the name of the bookmark that we are on (hg update ). + The name is recorded in .hg/bookmarks.current + ''' + if current(repo) == mark: + return + + refs = parse(repo) + + # do not update if we do update to a rev equal to the current bookmark + if (mark and mark not in refs and + current(repo) and refs[current(repo)] == repo.changectx('.').node()): + return + if mark not in refs: + mark = '' + wlock = repo.wlock() + try: + file = repo.opener('bookmarks.current', 'w', atomictemp=True) + file.write(mark) + file.rename() + finally: + wlock.release() + repo._bookmarkcurrent = mark + +def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None): + '''track a line of development with movable markers + + Bookmarks are pointers to certain commits that move when + committing. Bookmarks are local. They can be renamed, copied and + deleted. It is possible to use bookmark names in 'hg merge' and + 'hg update' to merge and update respectively to a given bookmark. + + You can use 'hg bookmark NAME' to set a bookmark on the working + directory's parent revision with the given name. If you specify + a revision using -r REV (where REV may be an existing bookmark), + the bookmark is assigned to that revision. + ''' + hexfn = ui.debugflag and hex or short + marks = parse(repo) + cur = repo.changectx('.').node() + + if rename: + if rename not in marks: + raise util.Abort(_("a bookmark of this name does not exist")) + if mark in marks and not force: + raise util.Abort(_("a bookmark of the same name already exists")) + if mark is None: + raise util.Abort(_("new bookmark name required")) + marks[mark] = marks[rename] + del marks[rename] + if current(repo) == rename: + setcurrent(repo, mark) + write(repo, marks) + return + + if delete: + if mark is None: + raise util.Abort(_("bookmark name required")) + if mark not in marks: + raise util.Abort(_("a bookmark of this name does not exist")) + if mark == current(repo): + setcurrent(repo, None) + del marks[mark] + write(repo, marks) + return + + if mark != None: + if "\n" in mark: + raise util.Abort(_("bookmark name cannot contain newlines")) + mark = mark.strip() + if mark in marks and not force: + raise util.Abort(_("a bookmark of the same name already exists")) + if ((mark in repo.branchtags() or mark == repo.dirstate.branch()) + and not force): + raise util.Abort( + _("a bookmark cannot have the name of an existing branch")) + if rev: + marks[mark] = repo.lookup(rev) + else: + marks[mark] = repo.changectx('.').node() + setcurrent(repo, mark) + write(repo, marks) + return + + if mark is None: + if rev: + raise util.Abort(_("bookmark name required")) + if len(marks) == 0: + ui.status("no bookmarks set\n") + else: + for bmark, n in marks.iteritems(): + if ui.configbool('bookmarks', 'track.current'): + prefix = (bmark == current(repo) and n == cur) and '*' or ' ' + else: + prefix = (n == cur) and '*' or ' ' + + ui.write(" %s %-25s %d:%s\n" % ( + prefix, bmark, repo.changelog.rev(n), hexfn(n))) + return + +def _revstostrip(changelog, node): + srev = changelog.rev(node) + tostrip = [srev] + saveheads = [] + for r in xrange(srev, len(changelog)): + parents = changelog.parentrevs(r) + if parents[0] in tostrip or parents[1] in tostrip: + tostrip.append(r) + if parents[1] != nullrev: + for p in parents: + if p not in tostrip and p > srev: + saveheads.append(p) + return [r for r in tostrip if r not in saveheads] + +def strip(oldstrip, ui, repo, node, backup="all"): + """Strip bookmarks if revisions are stripped using + the mercurial.strip method. This usually happens during + qpush and qpop""" + revisions = _revstostrip(repo.changelog, node) + marks = parse(repo) + update = [] + for mark, n in marks.iteritems(): + if repo.changelog.rev(n) in revisions: + update.append(mark) + oldstrip(ui, repo, node, backup) + if len(update) > 0: + for m in update: + marks[m] = repo.changectx('.').node() + write(repo, marks) + +def reposetup(ui, repo): + if not isinstance(repo, localrepo.localrepository): + return + + # init a bookmark cache as otherwise we would get a infinite reading + # in lookup() + repo._bookmarks = None + repo._bookmarkcurrent = None + + class bookmark_repo(repo.__class__): + def rollback(self): + if os.path.exists(self.join('undo.bookmarks')): + util.rename(self.join('undo.bookmarks'), self.join('bookmarks')) + return super(bookmark_repo, self).rollback() + + def lookup(self, key): + if self._bookmarks is None: + self._bookmarks = parse(self) + if key in self._bookmarks: + key = self._bookmarks[key] + return super(bookmark_repo, self).lookup(key) + + def commitctx(self, ctx, error=False): + """Add a revision to the repository and + move the bookmark""" + wlock = self.wlock() # do both commit and bookmark with lock held + try: + node = super(bookmark_repo, self).commitctx(ctx, error) + if node is None: + return None + parents = self.changelog.parents(node) + if parents[1] == nullid: + parents = (parents[0],) + marks = parse(self) + update = False + if ui.configbool('bookmarks', 'track.current'): + mark = current(self) + if mark and marks[mark] in parents: + marks[mark] = node + update = True + else: + for mark, n in marks.items(): + if n in parents: + marks[mark] = node + update = True + if update: + write(self, marks) + return node + finally: + wlock.release() + + def addchangegroup(self, source, srctype, url, emptyok=False): + parents = self.dirstate.parents() + + result = super(bookmark_repo, self).addchangegroup( + source, srctype, url, emptyok) + if result > 1: + # We have more heads than before + return result + node = self.changelog.tip() + marks = parse(self) + update = False + if ui.configbool('bookmarks', 'track.current'): + mark = current(self) + if mark and marks[mark] in parents: + marks[mark] = node + update = True + else: + for mark, n in marks.items(): + if n in parents: + marks[mark] = node + update = True + if update: + write(self, marks) + return result + + def _findtags(self): + """Merge bookmarks with normal tags""" + (tags, tagtypes) = super(bookmark_repo, self)._findtags() + tags.update(parse(self)) + return (tags, tagtypes) + + repo.__class__ = bookmark_repo + +def uisetup(ui): + extensions.wrapfunction(repair, "strip", strip) + if ui.configbool('bookmarks', 'track.current'): + extensions.wrapcommand(commands.table, 'update', updatecurbookmark) + +def updatecurbookmark(orig, ui, repo, *args, **opts): + '''Set the current bookmark + + If the user updates to a bookmark we update the .hg/bookmarks.current + file. + ''' + res = orig(ui, repo, *args, **opts) + rev = opts['rev'] + if not rev and len(args) > 0: + rev = args[0] + setcurrent(repo, rev) + return res + +cmdtable = { + "bookmarks": + (bookmark, + [('f', 'force', False, _('force')), + ('r', 'rev', '', _('revision')), + ('d', 'delete', False, _('delete a given bookmark')), + ('m', 'rename', '', _('rename a given bookmark'))], + _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')), +} diff --git a/sys/src/cmd/hg/hgext/bugzilla.py b/sys/src/cmd/hg/hgext/bugzilla.py new file mode 100644 index 000000000..774ed3385 --- /dev/null +++ b/sys/src/cmd/hg/hgext/bugzilla.py @@ -0,0 +1,439 @@ +# bugzilla.py - bugzilla integration for mercurial +# +# Copyright 2006 Vadim Gelfer +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''hooks for integrating with the Bugzilla bug tracker + +This hook extension adds comments on bugs in Bugzilla when changesets +that refer to bugs by Bugzilla ID are seen. The hook does not change +bug status. + +The hook updates the Bugzilla database directly. Only Bugzilla +installations using MySQL are supported. + +The hook relies on a Bugzilla script to send bug change notification +emails. That script changes between Bugzilla versions; the +'processmail' script used prior to 2.18 is replaced in 2.18 and +subsequent versions by 'config/sendbugmail.pl'. Note that these will +be run by Mercurial as the user pushing the change; you will need to +ensure the Bugzilla install file permissions are set appropriately. + +The extension is configured through three different configuration +sections. These keys are recognized in the [bugzilla] section: + +host + Hostname of the MySQL server holding the Bugzilla database. + +db + Name of the Bugzilla database in MySQL. Default 'bugs'. + +user + Username to use to access MySQL server. Default 'bugs'. + +password + Password to use to access MySQL server. + +timeout + Database connection timeout (seconds). Default 5. + +version + Bugzilla version. Specify '3.0' for Bugzilla versions 3.0 and later, + '2.18' for Bugzilla versions from 2.18 and '2.16' for versions prior + to 2.18. + +bzuser + Fallback Bugzilla user name to record comments with, if changeset + committer cannot be found as a Bugzilla user. + +bzdir + Bugzilla install directory. Used by default notify. Default + '/var/www/html/bugzilla'. + +notify + The command to run to get Bugzilla to send bug change notification + emails. Substitutes from a map with 3 keys, 'bzdir', 'id' (bug id) + and 'user' (committer bugzilla email). Default depends on version; + from 2.18 it is "cd %(bzdir)s && perl -T contrib/sendbugmail.pl + %(id)s %(user)s". + +regexp + Regular expression to match bug IDs in changeset commit message. + Must contain one "()" group. The default expression matches 'Bug + 1234', 'Bug no. 1234', 'Bug number 1234', 'Bugs 1234,5678', 'Bug + 1234 and 5678' and variations thereof. Matching is case insensitive. + +style + The style file to use when formatting comments. + +template + Template to use when formatting comments. Overrides style if + specified. In addition to the usual Mercurial keywords, the + extension specifies:: + + {bug} The Bugzilla bug ID. + {root} The full pathname of the Mercurial repository. + {webroot} Stripped pathname of the Mercurial repository. + {hgweb} Base URL for browsing Mercurial repositories. + + Default 'changeset {node|short} in repo {root} refers ' + 'to bug {bug}.\\ndetails:\\n\\t{desc|tabindent}' + +strip + The number of slashes to strip from the front of {root} to produce + {webroot}. Default 0. + +usermap + Path of file containing Mercurial committer ID to Bugzilla user ID + mappings. If specified, the file should contain one mapping per + line, "committer"="Bugzilla user". See also the [usermap] section. + +The [usermap] section is used to specify mappings of Mercurial +committer ID to Bugzilla user ID. See also [bugzilla].usermap. +"committer"="Bugzilla user" + +Finally, the [web] section supports one entry: + +baseurl + Base URL for browsing Mercurial repositories. Reference from + templates as {hgweb}. + +Activating the extension:: + + [extensions] + hgext.bugzilla = + + [hooks] + # run bugzilla hook on every change pulled or pushed in here + incoming.bugzilla = python:hgext.bugzilla.hook + +Example configuration: + +This example configuration is for a collection of Mercurial +repositories in /var/local/hg/repos/ used with a local Bugzilla 3.2 +installation in /opt/bugzilla-3.2. :: + + [bugzilla] + host=localhost + password=XYZZY + version=3.0 + bzuser=unknown@domain.com + bzdir=/opt/bugzilla-3.2 + template=Changeset {node|short} in {root|basename}. + {hgweb}/{webroot}/rev/{node|short}\\n + {desc}\\n + strip=5 + + [web] + baseurl=http://dev.domain.com/hg + + [usermap] + user@emaildomain.com=user.name@bugzilladomain.com + +Commits add a comment to the Bugzilla bug record of the form:: + + Changeset 3b16791d6642 in repository-name. + http://dev.domain.com/hg/repository-name/rev/3b16791d6642 + + Changeset commit comment. Bug 1234. +''' + +from mercurial.i18n import _ +from mercurial.node import short +from mercurial import cmdutil, templater, util +import re, time + +MySQLdb = None + +def buglist(ids): + return '(' + ','.join(map(str, ids)) + ')' + +class bugzilla_2_16(object): + '''support for bugzilla version 2.16.''' + + def __init__(self, ui): + self.ui = ui + host = self.ui.config('bugzilla', 'host', 'localhost') + user = self.ui.config('bugzilla', 'user', 'bugs') + passwd = self.ui.config('bugzilla', 'password') + db = self.ui.config('bugzilla', 'db', 'bugs') + timeout = int(self.ui.config('bugzilla', 'timeout', 5)) + usermap = self.ui.config('bugzilla', 'usermap') + if usermap: + self.ui.readconfig(usermap, sections=['usermap']) + self.ui.note(_('connecting to %s:%s as %s, password %s\n') % + (host, db, user, '*' * len(passwd))) + self.conn = MySQLdb.connect(host=host, user=user, passwd=passwd, + db=db, connect_timeout=timeout) + self.cursor = self.conn.cursor() + self.longdesc_id = self.get_longdesc_id() + self.user_ids = {} + self.default_notify = "cd %(bzdir)s && ./processmail %(id)s %(user)s" + + def run(self, *args, **kwargs): + '''run a query.''' + self.ui.note(_('query: %s %s\n') % (args, kwargs)) + try: + self.cursor.execute(*args, **kwargs) + except MySQLdb.MySQLError: + self.ui.note(_('failed query: %s %s\n') % (args, kwargs)) + raise + + def get_longdesc_id(self): + '''get identity of longdesc field''' + self.run('select fieldid from fielddefs where name = "longdesc"') + ids = self.cursor.fetchall() + if len(ids) != 1: + raise util.Abort(_('unknown database schema')) + return ids[0][0] + + def filter_real_bug_ids(self, ids): + '''filter not-existing bug ids from list.''' + self.run('select bug_id from bugs where bug_id in %s' % buglist(ids)) + return sorted([c[0] for c in self.cursor.fetchall()]) + + def filter_unknown_bug_ids(self, node, ids): + '''filter bug ids from list that already refer to this changeset.''' + + self.run('''select bug_id from longdescs where + bug_id in %s and thetext like "%%%s%%"''' % + (buglist(ids), short(node))) + unknown = set(ids) + for (id,) in self.cursor.fetchall(): + self.ui.status(_('bug %d already knows about changeset %s\n') % + (id, short(node))) + unknown.discard(id) + return sorted(unknown) + + def notify(self, ids, committer): + '''tell bugzilla to send mail.''' + + self.ui.status(_('telling bugzilla to send mail:\n')) + (user, userid) = self.get_bugzilla_user(committer) + for id in ids: + self.ui.status(_(' bug %s\n') % id) + cmdfmt = self.ui.config('bugzilla', 'notify', self.default_notify) + bzdir = self.ui.config('bugzilla', 'bzdir', '/var/www/html/bugzilla') + try: + # Backwards-compatible with old notify string, which + # took one string. This will throw with a new format + # string. + cmd = cmdfmt % id + except TypeError: + cmd = cmdfmt % {'bzdir': bzdir, 'id': id, 'user': user} + self.ui.note(_('running notify command %s\n') % cmd) + fp = util.popen('(%s) 2>&1' % cmd) + out = fp.read() + ret = fp.close() + if ret: + self.ui.warn(out) + raise util.Abort(_('bugzilla notify command %s') % + util.explain_exit(ret)[0]) + self.ui.status(_('done\n')) + + def get_user_id(self, user): + '''look up numeric bugzilla user id.''' + try: + return self.user_ids[user] + except KeyError: + try: + userid = int(user) + except ValueError: + self.ui.note(_('looking up user %s\n') % user) + self.run('''select userid from profiles + where login_name like %s''', user) + all = self.cursor.fetchall() + if len(all) != 1: + raise KeyError(user) + userid = int(all[0][0]) + self.user_ids[user] = userid + return userid + + def map_committer(self, user): + '''map name of committer to bugzilla user name.''' + for committer, bzuser in self.ui.configitems('usermap'): + if committer.lower() == user.lower(): + return bzuser + return user + + def get_bugzilla_user(self, committer): + '''see if committer is a registered bugzilla user. Return + bugzilla username and userid if so. If not, return default + bugzilla username and userid.''' + user = self.map_committer(committer) + try: + userid = self.get_user_id(user) + except KeyError: + try: + defaultuser = self.ui.config('bugzilla', 'bzuser') + if not defaultuser: + raise util.Abort(_('cannot find bugzilla user id for %s') % + user) + userid = self.get_user_id(defaultuser) + user = defaultuser + except KeyError: + raise util.Abort(_('cannot find bugzilla user id for %s or %s') % + (user, defaultuser)) + return (user, userid) + + def add_comment(self, bugid, text, committer): + '''add comment to bug. try adding comment as committer of + changeset, otherwise as default bugzilla user.''' + (user, userid) = self.get_bugzilla_user(committer) + now = time.strftime('%Y-%m-%d %H:%M:%S') + self.run('''insert into longdescs + (bug_id, who, bug_when, thetext) + values (%s, %s, %s, %s)''', + (bugid, userid, now, text)) + self.run('''insert into bugs_activity (bug_id, who, bug_when, fieldid) + values (%s, %s, %s, %s)''', + (bugid, userid, now, self.longdesc_id)) + self.conn.commit() + +class bugzilla_2_18(bugzilla_2_16): + '''support for bugzilla 2.18 series.''' + + def __init__(self, ui): + bugzilla_2_16.__init__(self, ui) + self.default_notify = "cd %(bzdir)s && perl -T contrib/sendbugmail.pl %(id)s %(user)s" + +class bugzilla_3_0(bugzilla_2_18): + '''support for bugzilla 3.0 series.''' + + def __init__(self, ui): + bugzilla_2_18.__init__(self, ui) + + def get_longdesc_id(self): + '''get identity of longdesc field''' + self.run('select id from fielddefs where name = "longdesc"') + ids = self.cursor.fetchall() + if len(ids) != 1: + raise util.Abort(_('unknown database schema')) + return ids[0][0] + +class bugzilla(object): + # supported versions of bugzilla. different versions have + # different schemas. + _versions = { + '2.16': bugzilla_2_16, + '2.18': bugzilla_2_18, + '3.0': bugzilla_3_0 + } + + _default_bug_re = (r'bugs?\s*,?\s*(?:#|nos?\.?|num(?:ber)?s?)?\s*' + r'((?:\d+\s*(?:,?\s*(?:and)?)?\s*)+)') + + _bz = None + + def __init__(self, ui, repo): + self.ui = ui + self.repo = repo + + def bz(self): + '''return object that knows how to talk to bugzilla version in + use.''' + + if bugzilla._bz is None: + bzversion = self.ui.config('bugzilla', 'version') + try: + bzclass = bugzilla._versions[bzversion] + except KeyError: + raise util.Abort(_('bugzilla version %s not supported') % + bzversion) + bugzilla._bz = bzclass(self.ui) + return bugzilla._bz + + def __getattr__(self, key): + return getattr(self.bz(), key) + + _bug_re = None + _split_re = None + + def find_bug_ids(self, ctx): + '''find valid bug ids that are referred to in changeset + comments and that do not already have references to this + changeset.''' + + if bugzilla._bug_re is None: + bugzilla._bug_re = re.compile( + self.ui.config('bugzilla', 'regexp', bugzilla._default_bug_re), + re.IGNORECASE) + bugzilla._split_re = re.compile(r'\D+') + start = 0 + ids = set() + while True: + m = bugzilla._bug_re.search(ctx.description(), start) + if not m: + break + start = m.end() + for id in bugzilla._split_re.split(m.group(1)): + if not id: continue + ids.add(int(id)) + if ids: + ids = self.filter_real_bug_ids(ids) + if ids: + ids = self.filter_unknown_bug_ids(ctx.node(), ids) + return ids + + def update(self, bugid, ctx): + '''update bugzilla bug with reference to changeset.''' + + def webroot(root): + '''strip leading prefix of repo root and turn into + url-safe path.''' + count = int(self.ui.config('bugzilla', 'strip', 0)) + root = util.pconvert(root) + while count > 0: + c = root.find('/') + if c == -1: + break + root = root[c+1:] + count -= 1 + return root + + mapfile = self.ui.config('bugzilla', 'style') + tmpl = self.ui.config('bugzilla', 'template') + t = cmdutil.changeset_templater(self.ui, self.repo, + False, None, mapfile, False) + if not mapfile and not tmpl: + tmpl = _('changeset {node|short} in repo {root} refers ' + 'to bug {bug}.\ndetails:\n\t{desc|tabindent}') + if tmpl: + tmpl = templater.parsestring(tmpl, quoted=False) + t.use_template(tmpl) + self.ui.pushbuffer() + t.show(ctx, changes=ctx.changeset(), + bug=str(bugid), + hgweb=self.ui.config('web', 'baseurl'), + root=self.repo.root, + webroot=webroot(self.repo.root)) + data = self.ui.popbuffer() + self.add_comment(bugid, data, util.email(ctx.user())) + +def hook(ui, repo, hooktype, node=None, **kwargs): + '''add comment to bugzilla for each changeset that refers to a + bugzilla bug id. only add a comment once per bug, so same change + seen multiple times does not fill bug with duplicate data.''' + try: + import MySQLdb as mysql + global MySQLdb + MySQLdb = mysql + except ImportError, err: + raise util.Abort(_('python mysql support not available: %s') % err) + + if node is None: + raise util.Abort(_('hook type %s does not pass a changeset id') % + hooktype) + try: + bz = bugzilla(ui, repo) + ctx = repo[node] + ids = bz.find_bug_ids(ctx) + if ids: + for id in ids: + bz.update(id, ctx) + bz.notify(ids, util.email(ctx.user())) + except MySQLdb.MySQLError, err: + raise util.Abort(_('database error: %s') % err[1]) + diff --git a/sys/src/cmd/hg/hgext/children.py b/sys/src/cmd/hg/hgext/children.py new file mode 100644 index 000000000..35ddeca43 --- /dev/null +++ b/sys/src/cmd/hg/hgext/children.py @@ -0,0 +1,44 @@ +# Mercurial extension to provide the 'hg children' command +# +# Copyright 2007 by Intevation GmbH +# +# Author(s): +# Thomas Arendsen Hein +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''command to display child changesets''' + +from mercurial import cmdutil +from mercurial.commands import templateopts +from mercurial.i18n import _ + + +def children(ui, repo, file_=None, **opts): + """show the children of the given or working directory revision + + Print the children of the working directory's revisions. If a + revision is given via -r/--rev, the children of that revision will + be printed. If a file argument is given, revision in which the + file was last changed (after the working directory revision or the + argument to --rev if given) is printed. + """ + rev = opts.get('rev') + if file_: + ctx = repo.filectx(file_, changeid=rev) + else: + ctx = repo[rev] + + displayer = cmdutil.show_changeset(ui, repo, opts) + for cctx in ctx.children(): + displayer.show(cctx) + + +cmdtable = { + "children": + (children, + [('r', 'rev', '', _('show children of the specified revision')), + ] + templateopts, + _('hg children [-r REV] [FILE]')), +} diff --git a/sys/src/cmd/hg/hgext/churn.py b/sys/src/cmd/hg/hgext/churn.py new file mode 100644 index 000000000..930009ab3 --- /dev/null +++ b/sys/src/cmd/hg/hgext/churn.py @@ -0,0 +1,174 @@ +# churn.py - create a graph of revisions count grouped by template +# +# Copyright 2006 Josef "Jeff" Sipek +# Copyright 2008 Alexander Solovyov +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''command to display statistics about repository history''' + +from mercurial.i18n import _ +from mercurial import patch, cmdutil, util, templater +import sys, os +import time, datetime + +def maketemplater(ui, repo, tmpl): + tmpl = templater.parsestring(tmpl, quoted=False) + try: + t = cmdutil.changeset_templater(ui, repo, False, None, None, False) + except SyntaxError, inst: + raise util.Abort(inst.args[0]) + t.use_template(tmpl) + return t + +def changedlines(ui, repo, ctx1, ctx2, fns): + lines = 0 + fmatch = cmdutil.matchfiles(repo, fns) + diff = ''.join(patch.diff(repo, ctx1.node(), ctx2.node(), fmatch)) + for l in diff.split('\n'): + if (l.startswith("+") and not l.startswith("+++ ") or + l.startswith("-") and not l.startswith("--- ")): + lines += 1 + return lines + +def countrate(ui, repo, amap, *pats, **opts): + """Calculate stats""" + if opts.get('dateformat'): + def getkey(ctx): + t, tz = ctx.date() + date = datetime.datetime(*time.gmtime(float(t) - tz)[:6]) + return date.strftime(opts['dateformat']) + else: + tmpl = opts.get('template', '{author|email}') + tmpl = maketemplater(ui, repo, tmpl) + def getkey(ctx): + ui.pushbuffer() + tmpl.show(ctx) + return ui.popbuffer() + + count = pct = 0 + rate = {} + df = False + if opts.get('date'): + df = util.matchdate(opts['date']) + + get = util.cachefunc(lambda r: repo[r].changeset()) + changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts) + for st, rev, fns in changeiter: + if not st == 'add': + continue + if df and not df(get(rev)[2][0]): # doesn't match date format + continue + + ctx = repo[rev] + key = getkey(ctx) + key = amap.get(key, key) # alias remap + if opts.get('changesets'): + rate[key] = rate.get(key, 0) + 1 + else: + parents = ctx.parents() + if len(parents) > 1: + ui.note(_('Revision %d is a merge, ignoring...\n') % (rev,)) + continue + + ctx1 = parents[0] + lines = changedlines(ui, repo, ctx1, ctx, fns) + rate[key] = rate.get(key, 0) + lines + + if opts.get('progress'): + count += 1 + newpct = int(100.0 * count / max(len(repo), 1)) + if pct < newpct: + pct = newpct + ui.write("\r" + _("generating stats: %d%%") % pct) + sys.stdout.flush() + + if opts.get('progress'): + ui.write("\r") + sys.stdout.flush() + + return rate + + +def churn(ui, repo, *pats, **opts): + '''histogram of changes to the repository + + This command will display a histogram representing the number + of changed lines or revisions, grouped according to the given + template. The default template will group changes by author. + The --dateformat option may be used to group the results by + date instead. + + Statistics are based on the number of changed lines, or + alternatively the number of matching revisions if the + --changesets option is specified. + + Examples:: + + # display count of changed lines for every committer + hg churn -t '{author|email}' + + # display daily activity graph + hg churn -f '%H' -s -c + + # display activity of developers by month + hg churn -f '%Y-%m' -s -c + + # display count of lines changed in every year + hg churn -f '%Y' -s + + It is possible to map alternate email addresses to a main address + by providing a file using the following format:: + + + + Such a file may be specified with the --aliases option, otherwise + a .hgchurn file will be looked for in the working directory root. + ''' + def pad(s, l): + return (s + " " * l)[:l] + + amap = {} + aliases = opts.get('aliases') + if not aliases and os.path.exists(repo.wjoin('.hgchurn')): + aliases = repo.wjoin('.hgchurn') + if aliases: + for l in open(aliases, "r"): + l = l.strip() + alias, actual = l.split() + amap[alias] = actual + + rate = countrate(ui, repo, amap, *pats, **opts).items() + if not rate: + return + + sortkey = ((not opts.get('sort')) and (lambda x: -x[1]) or None) + rate.sort(key=sortkey) + + maxcount = float(max([v for k, v in rate])) + maxname = max([len(k) for k, v in rate]) + + ttywidth = util.termwidth() + ui.debug(_("assuming %i character terminal\n") % ttywidth) + width = ttywidth - maxname - 2 - 6 - 2 - 2 + + for date, count in rate: + print "%s %6d %s" % (pad(date, maxname), count, + "*" * int(count * width / maxcount)) + + +cmdtable = { + "churn": + (churn, + [('r', 'rev', [], _('count rate for the specified revision or range')), + ('d', 'date', '', _('count rate for revisions matching date spec')), + ('t', 'template', '{author|email}', _('template to group changesets')), + ('f', 'dateformat', '', + _('strftime-compatible format for grouping by date')), + ('c', 'changesets', False, _('count rate by number of changesets')), + ('s', 'sort', False, _('sort by key (default: sort by count)')), + ('', 'aliases', '', _('file with email aliases')), + ('', 'progress', None, _('show progress'))], + _("hg churn [-d DATE] [-r REV] [--aliases FILE] [--progress] [FILE]")), +} diff --git a/sys/src/cmd/hg/hgext/color.py b/sys/src/cmd/hg/hgext/color.py new file mode 100644 index 000000000..4a736db43 --- /dev/null +++ b/sys/src/cmd/hg/hgext/color.py @@ -0,0 +1,286 @@ +# color.py color output for the status and qseries commands +# +# Copyright (C) 2007 Kevin Christen +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +'''colorize output from some commands + +This extension modifies the status command to add color to its output +to reflect file status, the qseries command to add color to reflect +patch status (applied, unapplied, missing), and to diff-related +commands to highlight additions, removals, diff headers, and trailing +whitespace. + +Other effects in addition to color, like bold and underlined text, are +also available. Effects are rendered with the ECMA-48 SGR control +function (aka ANSI escape codes). This module also provides the +render_text function, which can be used to add effects to any text. + +Default effects may be overridden from the .hgrc file:: + + [color] + status.modified = blue bold underline red_background + status.added = green bold + status.removed = red bold blue_background + status.deleted = cyan bold underline + status.unknown = magenta bold underline + status.ignored = black bold + + # 'none' turns off all effects + status.clean = none + status.copied = none + + qseries.applied = blue bold underline + qseries.unapplied = black bold + qseries.missing = red bold + + diff.diffline = bold + diff.extended = cyan bold + diff.file_a = red bold + diff.file_b = green bold + diff.hunk = magenta + diff.deleted = red + diff.inserted = green + diff.changed = white + diff.trailingwhitespace = bold red_background +''' + +import os, sys +import itertools + +from mercurial import cmdutil, commands, extensions, error +from mercurial.i18n import _ + +# start and stop parameters for effects +_effect_params = {'none': 0, + 'black': 30, + 'red': 31, + 'green': 32, + 'yellow': 33, + 'blue': 34, + 'magenta': 35, + 'cyan': 36, + 'white': 37, + 'bold': 1, + 'italic': 3, + 'underline': 4, + 'inverse': 7, + 'black_background': 40, + 'red_background': 41, + 'green_background': 42, + 'yellow_background': 43, + 'blue_background': 44, + 'purple_background': 45, + 'cyan_background': 46, + 'white_background': 47} + +def render_effects(text, effects): + 'Wrap text in commands to turn on each effect.' + start = [str(_effect_params[e]) for e in ['none'] + effects] + start = '\033[' + ';'.join(start) + 'm' + stop = '\033[' + str(_effect_params['none']) + 'm' + return ''.join([start, text, stop]) + +def colorstatus(orig, ui, repo, *pats, **opts): + '''run the status command with colored output''' + + delimiter = opts['print0'] and '\0' or '\n' + + nostatus = opts.get('no_status') + opts['no_status'] = False + # run status and capture its output + ui.pushbuffer() + retval = orig(ui, repo, *pats, **opts) + # filter out empty strings + lines_with_status = [ line for line in ui.popbuffer().split(delimiter) if line ] + + if nostatus: + lines = [l[2:] for l in lines_with_status] + else: + lines = lines_with_status + + # apply color to output and display it + for i in xrange(len(lines)): + status = _status_abbreviations[lines_with_status[i][0]] + effects = _status_effects[status] + if effects: + lines[i] = render_effects(lines[i], effects) + ui.write(lines[i] + delimiter) + return retval + +_status_abbreviations = { 'M': 'modified', + 'A': 'added', + 'R': 'removed', + '!': 'deleted', + '?': 'unknown', + 'I': 'ignored', + 'C': 'clean', + ' ': 'copied', } + +_status_effects = { 'modified': ['blue', 'bold'], + 'added': ['green', 'bold'], + 'removed': ['red', 'bold'], + 'deleted': ['cyan', 'bold', 'underline'], + 'unknown': ['magenta', 'bold', 'underline'], + 'ignored': ['black', 'bold'], + 'clean': ['none'], + 'copied': ['none'], } + +def colorqseries(orig, ui, repo, *dummy, **opts): + '''run the qseries command with colored output''' + ui.pushbuffer() + retval = orig(ui, repo, **opts) + patchlines = ui.popbuffer().splitlines() + patchnames = repo.mq.series + + for patch, patchname in itertools.izip(patchlines, patchnames): + if opts['missing']: + effects = _patch_effects['missing'] + # Determine if patch is applied. + elif [ applied for applied in repo.mq.applied + if patchname == applied.name ]: + effects = _patch_effects['applied'] + else: + effects = _patch_effects['unapplied'] + + patch = patch.replace(patchname, render_effects(patchname, effects), 1) + ui.write(patch + '\n') + return retval + +_patch_effects = { 'applied': ['blue', 'bold', 'underline'], + 'missing': ['red', 'bold'], + 'unapplied': ['black', 'bold'], } + +def colorwrap(orig, s): + '''wrap ui.write for colored diff output''' + lines = s.split('\n') + for i, line in enumerate(lines): + stripline = line + if line and line[0] in '+-': + # highlight trailing whitespace, but only in changed lines + stripline = line.rstrip() + for prefix, style in _diff_prefixes: + if stripline.startswith(prefix): + lines[i] = render_effects(stripline, _diff_effects[style]) + break + if line != stripline: + lines[i] += render_effects( + line[len(stripline):], _diff_effects['trailingwhitespace']) + orig('\n'.join(lines)) + +def colorshowpatch(orig, self, node): + '''wrap cmdutil.changeset_printer.showpatch with colored output''' + oldwrite = extensions.wrapfunction(self.ui, 'write', colorwrap) + try: + orig(self, node) + finally: + self.ui.write = oldwrite + +def colordiff(orig, ui, repo, *pats, **opts): + '''run the diff command with colored output''' + oldwrite = extensions.wrapfunction(ui, 'write', colorwrap) + try: + orig(ui, repo, *pats, **opts) + finally: + ui.write = oldwrite + +_diff_prefixes = [('diff', 'diffline'), + ('copy', 'extended'), + ('rename', 'extended'), + ('old', 'extended'), + ('new', 'extended'), + ('deleted', 'extended'), + ('---', 'file_a'), + ('+++', 'file_b'), + ('@', 'hunk'), + ('-', 'deleted'), + ('+', 'inserted')] + +_diff_effects = {'diffline': ['bold'], + 'extended': ['cyan', 'bold'], + 'file_a': ['red', 'bold'], + 'file_b': ['green', 'bold'], + 'hunk': ['magenta'], + 'deleted': ['red'], + 'inserted': ['green'], + 'changed': ['white'], + 'trailingwhitespace': ['bold', 'red_background']} + +_ui = None + +def uisetup(ui): + '''Initialize the extension.''' + global _ui + _ui = ui + _setupcmd(ui, 'diff', commands.table, colordiff, _diff_effects) + _setupcmd(ui, 'incoming', commands.table, None, _diff_effects) + _setupcmd(ui, 'log', commands.table, None, _diff_effects) + _setupcmd(ui, 'outgoing', commands.table, None, _diff_effects) + _setupcmd(ui, 'tip', commands.table, None, _diff_effects) + _setupcmd(ui, 'status', commands.table, colorstatus, _status_effects) + +def extsetup(): + try: + mq = extensions.find('mq') + try: + # If we are loaded after mq, we must wrap commands.table + _setupcmd(_ui, 'qdiff', commands.table, colordiff, _diff_effects) + _setupcmd(_ui, 'qseries', commands.table, colorqseries, _patch_effects) + except error.UnknownCommand: + # Otherwise we wrap mq.cmdtable + _setupcmd(_ui, 'qdiff', mq.cmdtable, colordiff, _diff_effects) + _setupcmd(_ui, 'qseries', mq.cmdtable, colorqseries, _patch_effects) + except KeyError: + # The mq extension is not enabled + pass + +def _setupcmd(ui, cmd, table, func, effectsmap): + '''patch in command to command table and load effect map''' + def nocolor(orig, *args, **opts): + + if (opts['no_color'] or opts['color'] == 'never' or + (opts['color'] == 'auto' and (os.environ.get('TERM') == 'dumb' + or not sys.__stdout__.isatty()))): + return orig(*args, **opts) + + oldshowpatch = extensions.wrapfunction(cmdutil.changeset_printer, + 'showpatch', colorshowpatch) + try: + if func is not None: + return func(orig, *args, **opts) + return orig(*args, **opts) + finally: + cmdutil.changeset_printer.showpatch = oldshowpatch + + entry = extensions.wrapcommand(table, cmd, nocolor) + entry[1].extend([ + ('', 'color', 'auto', _("when to colorize (always, auto, or never)")), + ('', 'no-color', None, _("don't colorize output")), + ]) + + for status in effectsmap: + configkey = cmd + '.' + status + effects = ui.configlist('color', configkey) + if effects: + good = [] + for e in effects: + if e in _effect_params: + good.append(e) + else: + ui.warn(_("ignoring unknown color/effect %r " + "(configured in color.%s)\n") + % (e, configkey)) + effectsmap[status] = good diff --git a/sys/src/cmd/hg/hgext/convert/__init__.py b/sys/src/cmd/hg/hgext/convert/__init__.py new file mode 100644 index 000000000..2d04dc34a --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/__init__.py @@ -0,0 +1,296 @@ +# convert.py Foreign SCM converter +# +# Copyright 2005-2007 Matt Mackall +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''import revisions from foreign VCS repositories into Mercurial''' + +import convcmd +import cvsps +import subversion +from mercurial import commands +from mercurial.i18n import _ + +# Commands definition was moved elsewhere to ease demandload job. + +def convert(ui, src, dest=None, revmapfile=None, **opts): + """convert a foreign SCM repository to a Mercurial one. + + Accepted source formats [identifiers]: + + - Mercurial [hg] + - CVS [cvs] + - Darcs [darcs] + - git [git] + - Subversion [svn] + - Monotone [mtn] + - GNU Arch [gnuarch] + - Bazaar [bzr] + - Perforce [p4] + + Accepted destination formats [identifiers]: + + - Mercurial [hg] + - Subversion [svn] (history on branches is not preserved) + + If no revision is given, all revisions will be converted. + Otherwise, convert will only import up to the named revision + (given in a format understood by the source). + + If no destination directory name is specified, it defaults to the + basename of the source with '-hg' appended. If the destination + repository doesn't exist, it will be created. + + By default, all sources except Mercurial will use --branchsort. + Mercurial uses --sourcesort to preserve original revision numbers + order. Sort modes have the following effects: + + --branchsort convert from parent to child revision when possible, + which means branches are usually converted one after + the other. It generates more compact repositories. + + --datesort sort revisions by date. Converted repositories have + good-looking changelogs but are often an order of + magnitude larger than the same ones generated by + --branchsort. + + --sourcesort try to preserve source revisions order, only + supported by Mercurial sources. + + If isn't given, it will be put in a default location + (/.hg/shamap by default). The is a simple text file + that maps each source commit ID to the destination ID for that + revision, like so:: + + + + If the file doesn't exist, it's automatically created. It's + updated on each commit copied, so convert-repo can be interrupted + and can be run repeatedly to copy new commits. + + The [username mapping] file is a simple text file that maps each + source commit author to a destination commit author. It is handy + for source SCMs that use unix logins to identify authors (eg: + CVS). One line per author mapping and the line format is: + srcauthor=whatever string you want + + The filemap is a file that allows filtering and remapping of files + and directories. Comment lines start with '#'. Each line can + contain one of the following directives:: + + include path/to/file + + exclude path/to/file + + rename from/file to/file + + The 'include' directive causes a file, or all files under a + directory, to be included in the destination repository, and the + exclusion of all other files and directories not explicitly + included. The 'exclude' directive causes files or directories to + be omitted. The 'rename' directive renames a file or directory. To + rename from a subdirectory into the root of the repository, use + '.' as the path to rename to. + + The splicemap is a file that allows insertion of synthetic + history, letting you specify the parents of a revision. This is + useful if you want to e.g. give a Subversion merge two parents, or + graft two disconnected series of history together. Each entry + contains a key, followed by a space, followed by one or two + comma-separated values. The key is the revision ID in the source + revision control system whose parents should be modified (same + format as a key in .hg/shamap). The values are the revision IDs + (in either the source or destination revision control system) that + should be used as the new parents for that node. + + The branchmap is a file that allows you to rename a branch when it is + being brought in from whatever external repository. When used in + conjunction with a splicemap, it allows for a powerful combination + to help fix even the most badly mismanaged repositories and turn them + into nicely structured Mercurial repositories. The branchmap contains + lines of the form "original_branch_name new_branch_name". + "original_branch_name" is the name of the branch in the source + repository, and "new_branch_name" is the name of the branch is the + destination repository. This can be used to (for instance) move code + in one repository from "default" to a named branch. + + Mercurial Source + ---------------- + + --config convert.hg.ignoreerrors=False (boolean) + ignore integrity errors when reading. Use it to fix Mercurial + repositories with missing revlogs, by converting from and to + Mercurial. + --config convert.hg.saverev=False (boolean) + store original revision ID in changeset (forces target IDs to + change) + --config convert.hg.startrev=0 (hg revision identifier) + convert start revision and its descendants + + CVS Source + ---------- + + CVS source will use a sandbox (i.e. a checked-out copy) from CVS + to indicate the starting point of what will be converted. Direct + access to the repository files is not needed, unless of course the + repository is :local:. The conversion uses the top level directory + in the sandbox to find the CVS repository, and then uses CVS rlog + commands to find files to convert. This means that unless a + filemap is given, all files under the starting directory will be + converted, and that any directory reorganization in the CVS + sandbox is ignored. + + Because CVS does not have changesets, it is necessary to collect + individual commits to CVS and merge them into changesets. CVS + source uses its internal changeset merging code by default but can + be configured to call the external 'cvsps' program by setting:: + + --config convert.cvsps='cvsps -A -u --cvs-direct -q' + + This option is deprecated and will be removed in Mercurial 1.4. + + The options shown are the defaults. + + Internal cvsps is selected by setting :: + + --config convert.cvsps=builtin + + and has a few more configurable options: + + --config convert.cvsps.cache=True (boolean) + Set to False to disable remote log caching, for testing and + debugging purposes. + --config convert.cvsps.fuzz=60 (integer) + Specify the maximum time (in seconds) that is allowed between + commits with identical user and log message in a single + changeset. When very large files were checked in as part of a + changeset then the default may not be long enough. + --config convert.cvsps.mergeto='{{mergetobranch ([-\\w]+)}}' + Specify a regular expression to which commit log messages are + matched. If a match occurs, then the conversion process will + insert a dummy revision merging the branch on which this log + message occurs to the branch indicated in the regex. + --config convert.cvsps.mergefrom='{{mergefrombranch ([-\\w]+)}}' + Specify a regular expression to which commit log messages are + matched. If a match occurs, then the conversion process will + add the most recent revision on the branch indicated in the + regex as the second parent of the changeset. + + The hgext/convert/cvsps wrapper script allows the builtin + changeset merging code to be run without doing a conversion. Its + parameters and output are similar to that of cvsps 2.1. + + Subversion Source + ----------------- + + Subversion source detects classical trunk/branches/tags layouts. + By default, the supplied "svn://repo/path/" source URL is + converted as a single branch. If "svn://repo/path/trunk" exists it + replaces the default branch. If "svn://repo/path/branches" exists, + its subdirectories are listed as possible branches. If + "svn://repo/path/tags" exists, it is looked for tags referencing + converted branches. Default "trunk", "branches" and "tags" values + can be overridden with following options. Set them to paths + relative to the source URL, or leave them blank to disable auto + detection. + + --config convert.svn.branches=branches (directory name) + specify the directory containing branches + --config convert.svn.tags=tags (directory name) + specify the directory containing tags + --config convert.svn.trunk=trunk (directory name) + specify the name of the trunk branch + + Source history can be retrieved starting at a specific revision, + instead of being integrally converted. Only single branch + conversions are supported. + + --config convert.svn.startrev=0 (svn revision number) + specify start Subversion revision. + + Perforce Source + --------------- + + The Perforce (P4) importer can be given a p4 depot path or a + client specification as source. It will convert all files in the + source to a flat Mercurial repository, ignoring labels, branches + and integrations. Note that when a depot path is given you then + usually should specify a target directory, because otherwise the + target may be named ...-hg. + + It is possible to limit the amount of source history to be + converted by specifying an initial Perforce revision. + + --config convert.p4.startrev=0 (perforce changelist number) + specify initial Perforce revision. + + Mercurial Destination + --------------------- + + --config convert.hg.clonebranches=False (boolean) + dispatch source branches in separate clones. + --config convert.hg.tagsbranch=default (branch name) + tag revisions branch name + --config convert.hg.usebranchnames=True (boolean) + preserve branch names + + """ + return convcmd.convert(ui, src, dest, revmapfile, **opts) + +def debugsvnlog(ui, **opts): + return subversion.debugsvnlog(ui, **opts) + +def debugcvsps(ui, *args, **opts): + '''create changeset information from CVS + + This command is intended as a debugging tool for the CVS to + Mercurial converter, and can be used as a direct replacement for + cvsps. + + Hg debugcvsps reads the CVS rlog for current directory (or any + named directory) in the CVS repository, and converts the log to a + series of changesets based on matching commit log entries and + dates.''' + return cvsps.debugcvsps(ui, *args, **opts) + +commands.norepo += " convert debugsvnlog debugcvsps" + +cmdtable = { + "convert": + (convert, + [('A', 'authors', '', _('username mapping filename')), + ('d', 'dest-type', '', _('destination repository type')), + ('', 'filemap', '', _('remap file names using contents of file')), + ('r', 'rev', '', _('import up to target revision REV')), + ('s', 'source-type', '', _('source repository type')), + ('', 'splicemap', '', _('splice synthesized history into place')), + ('', 'branchmap', '', _('change branch names while converting')), + ('', 'branchsort', None, _('try to sort changesets by branches')), + ('', 'datesort', None, _('try to sort changesets by date')), + ('', 'sourcesort', None, _('preserve source changesets order'))], + _('hg convert [OPTION]... SOURCE [DEST [REVMAP]]')), + "debugsvnlog": + (debugsvnlog, + [], + 'hg debugsvnlog'), + "debugcvsps": + (debugcvsps, + [ + # Main options shared with cvsps-2.1 + ('b', 'branches', [], _('only return changes on specified branches')), + ('p', 'prefix', '', _('prefix to remove from file names')), + ('r', 'revisions', [], _('only return changes after or between specified tags')), + ('u', 'update-cache', None, _("update cvs log cache")), + ('x', 'new-cache', None, _("create new cvs log cache")), + ('z', 'fuzz', 60, _('set commit time fuzz in seconds')), + ('', 'root', '', _('specify cvsroot')), + # Options specific to builtin cvsps + ('', 'parents', '', _('show parent changesets')), + ('', 'ancestors', '', _('show current changeset in ancestor branches')), + # Options that are ignored for compatibility with cvsps-2.1 + ('A', 'cvs-direct', None, _('ignored for compatibility')), + ], + _('hg debugcvsps [OPTION]... [PATH]...')), +} diff --git a/sys/src/cmd/hg/hgext/convert/bzr.py b/sys/src/cmd/hg/hgext/convert/bzr.py new file mode 100644 index 000000000..6d2abe0bb --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/bzr.py @@ -0,0 +1,259 @@ +# bzr.py - bzr support for the convert extension +# +# Copyright 2008, 2009 Marek Kubica and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +# This module is for handling 'bzr', that was formerly known as Bazaar-NG; +# it cannot access 'bar' repositories, but they were never used very much + +import os +from mercurial import demandimport +# these do not work with demandimport, blacklist +demandimport.ignore.extend([ + 'bzrlib.transactions', + 'bzrlib.urlutils', + ]) + +from mercurial.i18n import _ +from mercurial import util +from common import NoRepo, commit, converter_source + +try: + # bazaar imports + from bzrlib import branch, revision, errors + from bzrlib.revisionspec import RevisionSpec +except ImportError: + pass + +supportedkinds = ('file', 'symlink') + +class bzr_source(converter_source): + """Reads Bazaar repositories by using the Bazaar Python libraries""" + + def __init__(self, ui, path, rev=None): + super(bzr_source, self).__init__(ui, path, rev=rev) + + if not os.path.exists(os.path.join(path, '.bzr')): + raise NoRepo('%s does not look like a Bazaar repo' % path) + + try: + # access bzrlib stuff + branch + except NameError: + raise NoRepo('Bazaar modules could not be loaded') + + path = os.path.abspath(path) + self._checkrepotype(path) + self.branch = branch.Branch.open(path) + self.sourcerepo = self.branch.repository + self._parentids = {} + + def _checkrepotype(self, path): + # Lightweight checkouts detection is informational but probably + # fragile at API level. It should not terminate the conversion. + try: + from bzrlib import bzrdir + dir = bzrdir.BzrDir.open_containing(path)[0] + try: + tree = dir.open_workingtree(recommend_upgrade=False) + branch = tree.branch + except (errors.NoWorkingTree, errors.NotLocalUrl), e: + tree = None + branch = dir.open_branch() + if (tree is not None and tree.bzrdir.root_transport.base != + branch.bzrdir.root_transport.base): + self.ui.warn(_('warning: lightweight checkouts may cause ' + 'conversion failures, try with a regular ' + 'branch instead.\n')) + except: + self.ui.note(_('bzr source type could not be determined\n')) + + def before(self): + """Before the conversion begins, acquire a read lock + for all the operations that might need it. Fortunately + read locks don't block other reads or writes to the + repository, so this shouldn't have any impact on the usage of + the source repository. + + The alternative would be locking on every operation that + needs locks (there are currently two: getting the file and + getting the parent map) and releasing immediately after, + but this approach can take even 40% longer.""" + self.sourcerepo.lock_read() + + def after(self): + self.sourcerepo.unlock() + + def getheads(self): + if not self.rev: + return [self.branch.last_revision()] + try: + r = RevisionSpec.from_string(self.rev) + info = r.in_history(self.branch) + except errors.BzrError: + raise util.Abort(_('%s is not a valid revision in current branch') + % self.rev) + return [info.rev_id] + + def getfile(self, name, rev): + revtree = self.sourcerepo.revision_tree(rev) + fileid = revtree.path2id(name.decode(self.encoding or 'utf-8')) + kind = None + if fileid is not None: + kind = revtree.kind(fileid) + if kind not in supportedkinds: + # the file is not available anymore - was deleted + raise IOError(_('%s is not available in %s anymore') % + (name, rev)) + if kind == 'symlink': + target = revtree.get_symlink_target(fileid) + if target is None: + raise util.Abort(_('%s.%s symlink has no target') + % (name, rev)) + return target + else: + sio = revtree.get_file(fileid) + return sio.read() + + def getmode(self, name, rev): + return self._modecache[(name, rev)] + + def getchanges(self, version): + # set up caches: modecache and revtree + self._modecache = {} + self._revtree = self.sourcerepo.revision_tree(version) + # get the parentids from the cache + parentids = self._parentids.pop(version) + # only diff against first parent id + prevtree = self.sourcerepo.revision_tree(parentids[0]) + return self._gettreechanges(self._revtree, prevtree) + + def getcommit(self, version): + rev = self.sourcerepo.get_revision(version) + # populate parent id cache + if not rev.parent_ids: + parents = [] + self._parentids[version] = (revision.NULL_REVISION,) + else: + parents = self._filterghosts(rev.parent_ids) + self._parentids[version] = parents + + return commit(parents=parents, + date='%d %d' % (rev.timestamp, -rev.timezone), + author=self.recode(rev.committer), + # bzr returns bytestrings or unicode, depending on the content + desc=self.recode(rev.message), + rev=version) + + def gettags(self): + if not self.branch.supports_tags(): + return {} + tagdict = self.branch.tags.get_tag_dict() + bytetags = {} + for name, rev in tagdict.iteritems(): + bytetags[self.recode(name)] = rev + return bytetags + + def getchangedfiles(self, rev, i): + self._modecache = {} + curtree = self.sourcerepo.revision_tree(rev) + if i is not None: + parentid = self._parentids[rev][i] + else: + # no parent id, get the empty revision + parentid = revision.NULL_REVISION + + prevtree = self.sourcerepo.revision_tree(parentid) + changes = [e[0] for e in self._gettreechanges(curtree, prevtree)[0]] + return changes + + def _gettreechanges(self, current, origin): + revid = current._revision_id; + changes = [] + renames = {} + for (fileid, paths, changed_content, versioned, parent, name, + kind, executable) in current.iter_changes(origin): + + if paths[0] == u'' or paths[1] == u'': + # ignore changes to tree root + continue + + # bazaar tracks directories, mercurial does not, so + # we have to rename the directory contents + if kind[1] == 'directory': + if kind[0] not in (None, 'directory'): + # Replacing 'something' with a directory, record it + # so it can be removed. + changes.append((self.recode(paths[0]), revid)) + + if None not in paths and paths[0] != paths[1]: + # neither an add nor an delete - a move + # rename all directory contents manually + subdir = origin.inventory.path2id(paths[0]) + # get all child-entries of the directory + for name, entry in origin.inventory.iter_entries(subdir): + # hg does not track directory renames + if entry.kind == 'directory': + continue + frompath = self.recode(paths[0] + '/' + name) + topath = self.recode(paths[1] + '/' + name) + # register the files as changed + changes.append((frompath, revid)) + changes.append((topath, revid)) + # add to mode cache + mode = ((entry.executable and 'x') or (entry.kind == 'symlink' and 's') + or '') + self._modecache[(topath, revid)] = mode + # register the change as move + renames[topath] = frompath + + # no futher changes, go to the next change + continue + + # we got unicode paths, need to convert them + path, topath = [self.recode(part) for part in paths] + + if topath is None: + # file deleted + changes.append((path, revid)) + continue + + # renamed + if path and path != topath: + renames[topath] = path + changes.append((path, revid)) + + # populate the mode cache + kind, executable = [e[1] for e in (kind, executable)] + mode = ((executable and 'x') or (kind == 'symlink' and 'l') + or '') + self._modecache[(topath, revid)] = mode + changes.append((topath, revid)) + + return changes, renames + + def _filterghosts(self, ids): + """Filters out ghost revisions which hg does not support, see + + """ + parentmap = self.sourcerepo.get_parent_map(ids) + parents = tuple([parent for parent in ids if parent in parentmap]) + return parents + + def recode(self, s, encoding=None): + """This version of recode tries to encode unicode to bytecode, + and preferably using the UTF-8 codec. + Other types than Unicode are silently returned, this is by + intention, e.g. the None-type is not going to be encoded but instead + just passed through + """ + if not encoding: + encoding = self.encoding or 'utf-8' + + if isinstance(s, unicode): + return s.encode(encoding) + else: + # leave it alone + return s diff --git a/sys/src/cmd/hg/hgext/convert/common.py b/sys/src/cmd/hg/hgext/convert/common.py new file mode 100644 index 000000000..0519d99a0 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/common.py @@ -0,0 +1,389 @@ +# common.py - common code for the convert extension +# +# Copyright 2005-2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import base64, errno +import os +import cPickle as pickle +from mercurial import util +from mercurial.i18n import _ + +def encodeargs(args): + def encodearg(s): + lines = base64.encodestring(s) + lines = [l.splitlines()[0] for l in lines] + return ''.join(lines) + + s = pickle.dumps(args) + return encodearg(s) + +def decodeargs(s): + s = base64.decodestring(s) + return pickle.loads(s) + +class MissingTool(Exception): pass + +def checktool(exe, name=None, abort=True): + name = name or exe + if not util.find_exe(exe): + exc = abort and util.Abort or MissingTool + raise exc(_('cannot find required "%s" tool') % name) + +class NoRepo(Exception): pass + +SKIPREV = 'SKIP' + +class commit(object): + def __init__(self, author, date, desc, parents, branch=None, rev=None, + extra={}, sortkey=None): + self.author = author or 'unknown' + self.date = date or '0 0' + self.desc = desc + self.parents = parents + self.branch = branch + self.rev = rev + self.extra = extra + self.sortkey = sortkey + +class converter_source(object): + """Conversion source interface""" + + def __init__(self, ui, path=None, rev=None): + """Initialize conversion source (or raise NoRepo("message") + exception if path is not a valid repository)""" + self.ui = ui + self.path = path + self.rev = rev + + self.encoding = 'utf-8' + + def before(self): + pass + + def after(self): + pass + + def setrevmap(self, revmap): + """set the map of already-converted revisions""" + pass + + def getheads(self): + """Return a list of this repository's heads""" + raise NotImplementedError() + + def getfile(self, name, rev): + """Return file contents as a string. rev is the identifier returned + by a previous call to getchanges(). Raise IOError to indicate that + name was deleted in rev. + """ + raise NotImplementedError() + + def getmode(self, name, rev): + """Return file mode, eg. '', 'x', or 'l'. rev is the identifier + returned by a previous call to getchanges(). + """ + raise NotImplementedError() + + def getchanges(self, version): + """Returns a tuple of (files, copies). + + files is a sorted list of (filename, id) tuples for all files + changed between version and its first parent returned by + getcommit(). id is the source revision id of the file. + + copies is a dictionary of dest: source + """ + raise NotImplementedError() + + def getcommit(self, version): + """Return the commit object for version""" + raise NotImplementedError() + + def gettags(self): + """Return the tags as a dictionary of name: revision + + Tag names must be UTF-8 strings. + """ + raise NotImplementedError() + + def recode(self, s, encoding=None): + if not encoding: + encoding = self.encoding or 'utf-8' + + if isinstance(s, unicode): + return s.encode("utf-8") + try: + return s.decode(encoding).encode("utf-8") + except: + try: + return s.decode("latin-1").encode("utf-8") + except: + return s.decode(encoding, "replace").encode("utf-8") + + def getchangedfiles(self, rev, i): + """Return the files changed by rev compared to parent[i]. + + i is an index selecting one of the parents of rev. The return + value should be the list of files that are different in rev and + this parent. + + If rev has no parents, i is None. + + This function is only needed to support --filemap + """ + raise NotImplementedError() + + def converted(self, rev, sinkrev): + '''Notify the source that a revision has been converted.''' + pass + + def hasnativeorder(self): + """Return true if this source has a meaningful, native revision + order. For instance, Mercurial revisions are store sequentially + while there is no such global ordering with Darcs. + """ + return False + + def lookuprev(self, rev): + """If rev is a meaningful revision reference in source, return + the referenced identifier in the same format used by getcommit(). + return None otherwise. + """ + return None + +class converter_sink(object): + """Conversion sink (target) interface""" + + def __init__(self, ui, path): + """Initialize conversion sink (or raise NoRepo("message") + exception if path is not a valid repository) + + created is a list of paths to remove if a fatal error occurs + later""" + self.ui = ui + self.path = path + self.created = [] + + def getheads(self): + """Return a list of this repository's heads""" + raise NotImplementedError() + + def revmapfile(self): + """Path to a file that will contain lines + source_rev_id sink_rev_id + mapping equivalent revision identifiers for each system.""" + raise NotImplementedError() + + def authorfile(self): + """Path to a file that will contain lines + srcauthor=dstauthor + mapping equivalent authors identifiers for each system.""" + return None + + def putcommit(self, files, copies, parents, commit, source, revmap): + """Create a revision with all changed files listed in 'files' + and having listed parents. 'commit' is a commit object + containing at a minimum the author, date, and message for this + changeset. 'files' is a list of (path, version) tuples, + 'copies' is a dictionary mapping destinations to sources, + 'source' is the source repository, and 'revmap' is a mapfile + of source revisions to converted revisions. Only getfile(), + getmode(), and lookuprev() should be called on 'source'. + + Note that the sink repository is not told to update itself to + a particular revision (or even what that revision would be) + before it receives the file data. + """ + raise NotImplementedError() + + def puttags(self, tags): + """Put tags into sink. + + tags: {tagname: sink_rev_id, ...} where tagname is an UTF-8 string. + """ + raise NotImplementedError() + + def setbranch(self, branch, pbranches): + """Set the current branch name. Called before the first putcommit + on the branch. + branch: branch name for subsequent commits + pbranches: (converted parent revision, parent branch) tuples""" + pass + + def setfilemapmode(self, active): + """Tell the destination that we're using a filemap + + Some converter_sources (svn in particular) can claim that a file + was changed in a revision, even if there was no change. This method + tells the destination that we're using a filemap and that it should + filter empty revisions. + """ + pass + + def before(self): + pass + + def after(self): + pass + + +class commandline(object): + def __init__(self, ui, command): + self.ui = ui + self.command = command + + def prerun(self): + pass + + def postrun(self): + pass + + def _cmdline(self, cmd, *args, **kwargs): + cmdline = [self.command, cmd] + list(args) + for k, v in kwargs.iteritems(): + if len(k) == 1: + cmdline.append('-' + k) + else: + cmdline.append('--' + k.replace('_', '-')) + try: + if len(k) == 1: + cmdline.append('' + v) + else: + cmdline[-1] += '=' + v + except TypeError: + pass + cmdline = [util.shellquote(arg) for arg in cmdline] + if not self.ui.debugflag: + cmdline += ['2>', util.nulldev] + cmdline += ['<', util.nulldev] + cmdline = ' '.join(cmdline) + return cmdline + + def _run(self, cmd, *args, **kwargs): + cmdline = self._cmdline(cmd, *args, **kwargs) + self.ui.debug(_('running: %s\n') % (cmdline,)) + self.prerun() + try: + return util.popen(cmdline) + finally: + self.postrun() + + def run(self, cmd, *args, **kwargs): + fp = self._run(cmd, *args, **kwargs) + output = fp.read() + self.ui.debug(output) + return output, fp.close() + + def runlines(self, cmd, *args, **kwargs): + fp = self._run(cmd, *args, **kwargs) + output = fp.readlines() + self.ui.debug(''.join(output)) + return output, fp.close() + + def checkexit(self, status, output=''): + if status: + if output: + self.ui.warn(_('%s error:\n') % self.command) + self.ui.warn(output) + msg = util.explain_exit(status)[0] + raise util.Abort('%s %s' % (self.command, msg)) + + def run0(self, cmd, *args, **kwargs): + output, status = self.run(cmd, *args, **kwargs) + self.checkexit(status, output) + return output + + def runlines0(self, cmd, *args, **kwargs): + output, status = self.runlines(cmd, *args, **kwargs) + self.checkexit(status, ''.join(output)) + return output + + def getargmax(self): + if '_argmax' in self.__dict__: + return self._argmax + + # POSIX requires at least 4096 bytes for ARG_MAX + self._argmax = 4096 + try: + self._argmax = os.sysconf("SC_ARG_MAX") + except: + pass + + # Windows shells impose their own limits on command line length, + # down to 2047 bytes for cmd.exe under Windows NT/2k and 2500 bytes + # for older 4nt.exe. See http://support.microsoft.com/kb/830473 for + # details about cmd.exe limitations. + + # Since ARG_MAX is for command line _and_ environment, lower our limit + # (and make happy Windows shells while doing this). + + self._argmax = self._argmax/2 - 1 + return self._argmax + + def limit_arglist(self, arglist, cmd, *args, **kwargs): + limit = self.getargmax() - len(self._cmdline(cmd, *args, **kwargs)) + bytes = 0 + fl = [] + for fn in arglist: + b = len(fn) + 3 + if bytes + b < limit or len(fl) == 0: + fl.append(fn) + bytes += b + else: + yield fl + fl = [fn] + bytes = b + if fl: + yield fl + + def xargs(self, arglist, cmd, *args, **kwargs): + for l in self.limit_arglist(arglist, cmd, *args, **kwargs): + self.run0(cmd, *(list(args) + l), **kwargs) + +class mapfile(dict): + def __init__(self, ui, path): + super(mapfile, self).__init__() + self.ui = ui + self.path = path + self.fp = None + self.order = [] + self._read() + + def _read(self): + if not self.path: + return + try: + fp = open(self.path, 'r') + except IOError, err: + if err.errno != errno.ENOENT: + raise + return + for i, line in enumerate(fp): + try: + key, value = line[:-1].rsplit(' ', 1) + except ValueError: + raise util.Abort(_('syntax error in %s(%d): key/value pair expected') + % (self.path, i+1)) + if key not in self: + self.order.append(key) + super(mapfile, self).__setitem__(key, value) + fp.close() + + def __setitem__(self, key, value): + if self.fp is None: + try: + self.fp = open(self.path, 'a') + except IOError, err: + raise util.Abort(_('could not open map file %r: %s') % + (self.path, err.strerror)) + self.fp.write('%s %s\n' % (key, value)) + self.fp.flush() + super(mapfile, self).__setitem__(key, value) + + def close(self): + if self.fp: + self.fp.close() + self.fp = None diff --git a/sys/src/cmd/hg/hgext/convert/convcmd.py b/sys/src/cmd/hg/hgext/convert/convcmd.py new file mode 100644 index 000000000..50be03af0 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/convcmd.py @@ -0,0 +1,396 @@ +# convcmd - convert extension commands definition +# +# Copyright 2005-2007 Matt Mackall +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +from common import NoRepo, MissingTool, SKIPREV, mapfile +from cvs import convert_cvs +from darcs import darcs_source +from git import convert_git +from hg import mercurial_source, mercurial_sink +from subversion import svn_source, svn_sink +from monotone import monotone_source +from gnuarch import gnuarch_source +from bzr import bzr_source +from p4 import p4_source +import filemap + +import os, shutil +from mercurial import hg, util, encoding +from mercurial.i18n import _ + +orig_encoding = 'ascii' + +def recode(s): + if isinstance(s, unicode): + return s.encode(orig_encoding, 'replace') + else: + return s.decode('utf-8').encode(orig_encoding, 'replace') + +source_converters = [ + ('cvs', convert_cvs, 'branchsort'), + ('git', convert_git, 'branchsort'), + ('svn', svn_source, 'branchsort'), + ('hg', mercurial_source, 'sourcesort'), + ('darcs', darcs_source, 'branchsort'), + ('mtn', monotone_source, 'branchsort'), + ('gnuarch', gnuarch_source, 'branchsort'), + ('bzr', bzr_source, 'branchsort'), + ('p4', p4_source, 'branchsort'), + ] + +sink_converters = [ + ('hg', mercurial_sink), + ('svn', svn_sink), + ] + +def convertsource(ui, path, type, rev): + exceptions = [] + for name, source, sortmode in source_converters: + try: + if not type or name == type: + return source(ui, path, rev), sortmode + except (NoRepo, MissingTool), inst: + exceptions.append(inst) + if not ui.quiet: + for inst in exceptions: + ui.write("%s\n" % inst) + raise util.Abort(_('%s: missing or unsupported repository') % path) + +def convertsink(ui, path, type): + for name, sink in sink_converters: + try: + if not type or name == type: + return sink(ui, path) + except NoRepo, inst: + ui.note(_("convert: %s\n") % inst) + raise util.Abort(_('%s: unknown repository type') % path) + +class converter(object): + def __init__(self, ui, source, dest, revmapfile, opts): + + self.source = source + self.dest = dest + self.ui = ui + self.opts = opts + self.commitcache = {} + self.authors = {} + self.authorfile = None + + # Record converted revisions persistently: maps source revision + # ID to target revision ID (both strings). (This is how + # incremental conversions work.) + self.map = mapfile(ui, revmapfile) + + # Read first the dst author map if any + authorfile = self.dest.authorfile() + if authorfile and os.path.exists(authorfile): + self.readauthormap(authorfile) + # Extend/Override with new author map if necessary + if opts.get('authors'): + self.readauthormap(opts.get('authors')) + self.authorfile = self.dest.authorfile() + + self.splicemap = mapfile(ui, opts.get('splicemap')) + self.branchmap = mapfile(ui, opts.get('branchmap')) + + def walktree(self, heads): + '''Return a mapping that identifies the uncommitted parents of every + uncommitted changeset.''' + visit = heads + known = set() + parents = {} + while visit: + n = visit.pop(0) + if n in known or n in self.map: continue + known.add(n) + commit = self.cachecommit(n) + parents[n] = [] + for p in commit.parents: + parents[n].append(p) + visit.append(p) + + return parents + + def toposort(self, parents, sortmode): + '''Return an ordering such that every uncommitted changeset is + preceeded by all its uncommitted ancestors.''' + + def mapchildren(parents): + """Return a (children, roots) tuple where 'children' maps parent + revision identifiers to children ones, and 'roots' is the list of + revisions without parents. 'parents' must be a mapping of revision + identifier to its parents ones. + """ + visit = parents.keys() + seen = set() + children = {} + roots = [] + + while visit: + n = visit.pop(0) + if n in seen: + continue + seen.add(n) + # Ensure that nodes without parents are present in the + # 'children' mapping. + children.setdefault(n, []) + hasparent = False + for p in parents[n]: + if not p in self.map: + visit.append(p) + hasparent = True + children.setdefault(p, []).append(n) + if not hasparent: + roots.append(n) + + return children, roots + + # Sort functions are supposed to take a list of revisions which + # can be converted immediately and pick one + + def makebranchsorter(): + """If the previously converted revision has a child in the + eligible revisions list, pick it. Return the list head + otherwise. Branch sort attempts to minimize branch + switching, which is harmful for Mercurial backend + compression. + """ + prev = [None] + def picknext(nodes): + next = nodes[0] + for n in nodes: + if prev[0] in parents[n]: + next = n + break + prev[0] = next + return next + return picknext + + def makesourcesorter(): + """Source specific sort.""" + keyfn = lambda n: self.commitcache[n].sortkey + def picknext(nodes): + return sorted(nodes, key=keyfn)[0] + return picknext + + def makedatesorter(): + """Sort revisions by date.""" + dates = {} + def getdate(n): + if n not in dates: + dates[n] = util.parsedate(self.commitcache[n].date) + return dates[n] + + def picknext(nodes): + return min([(getdate(n), n) for n in nodes])[1] + + return picknext + + if sortmode == 'branchsort': + picknext = makebranchsorter() + elif sortmode == 'datesort': + picknext = makedatesorter() + elif sortmode == 'sourcesort': + picknext = makesourcesorter() + else: + raise util.Abort(_('unknown sort mode: %s') % sortmode) + + children, actives = mapchildren(parents) + + s = [] + pendings = {} + while actives: + n = picknext(actives) + actives.remove(n) + s.append(n) + + # Update dependents list + for c in children.get(n, []): + if c not in pendings: + pendings[c] = [p for p in parents[c] if p not in self.map] + try: + pendings[c].remove(n) + except ValueError: + raise util.Abort(_('cycle detected between %s and %s') + % (recode(c), recode(n))) + if not pendings[c]: + # Parents are converted, node is eligible + actives.insert(0, c) + pendings[c] = None + + if len(s) != len(parents): + raise util.Abort(_("not all revisions were sorted")) + + return s + + def writeauthormap(self): + authorfile = self.authorfile + if authorfile: + self.ui.status(_('Writing author map file %s\n') % authorfile) + ofile = open(authorfile, 'w+') + for author in self.authors: + ofile.write("%s=%s\n" % (author, self.authors[author])) + ofile.close() + + def readauthormap(self, authorfile): + afile = open(authorfile, 'r') + for line in afile: + + line = line.strip() + if not line or line.startswith('#'): + continue + + try: + srcauthor, dstauthor = line.split('=', 1) + except ValueError: + msg = _('Ignoring bad line in author map file %s: %s\n') + self.ui.warn(msg % (authorfile, line.rstrip())) + continue + + srcauthor = srcauthor.strip() + dstauthor = dstauthor.strip() + if self.authors.get(srcauthor) in (None, dstauthor): + msg = _('mapping author %s to %s\n') + self.ui.debug(msg % (srcauthor, dstauthor)) + self.authors[srcauthor] = dstauthor + continue + + m = _('overriding mapping for author %s, was %s, will be %s\n') + self.ui.status(m % (srcauthor, self.authors[srcauthor], dstauthor)) + + afile.close() + + def cachecommit(self, rev): + commit = self.source.getcommit(rev) + commit.author = self.authors.get(commit.author, commit.author) + commit.branch = self.branchmap.get(commit.branch, commit.branch) + self.commitcache[rev] = commit + return commit + + def copy(self, rev): + commit = self.commitcache[rev] + + changes = self.source.getchanges(rev) + if isinstance(changes, basestring): + if changes == SKIPREV: + dest = SKIPREV + else: + dest = self.map[changes] + self.map[rev] = dest + return + files, copies = changes + pbranches = [] + if commit.parents: + for prev in commit.parents: + if prev not in self.commitcache: + self.cachecommit(prev) + pbranches.append((self.map[prev], + self.commitcache[prev].branch)) + self.dest.setbranch(commit.branch, pbranches) + try: + parents = self.splicemap[rev].replace(',', ' ').split() + self.ui.status(_('spliced in %s as parents of %s\n') % + (parents, rev)) + parents = [self.map.get(p, p) for p in parents] + except KeyError: + parents = [b[0] for b in pbranches] + newnode = self.dest.putcommit(files, copies, parents, commit, + self.source, self.map) + self.source.converted(rev, newnode) + self.map[rev] = newnode + + def convert(self, sortmode): + try: + self.source.before() + self.dest.before() + self.source.setrevmap(self.map) + self.ui.status(_("scanning source...\n")) + heads = self.source.getheads() + parents = self.walktree(heads) + self.ui.status(_("sorting...\n")) + t = self.toposort(parents, sortmode) + num = len(t) + c = None + + self.ui.status(_("converting...\n")) + for c in t: + num -= 1 + desc = self.commitcache[c].desc + if "\n" in desc: + desc = desc.splitlines()[0] + # convert log message to local encoding without using + # tolocal() because encoding.encoding conver() use it as + # 'utf-8' + self.ui.status("%d %s\n" % (num, recode(desc))) + self.ui.note(_("source: %s\n") % recode(c)) + self.copy(c) + + tags = self.source.gettags() + ctags = {} + for k in tags: + v = tags[k] + if self.map.get(v, SKIPREV) != SKIPREV: + ctags[k] = self.map[v] + + if c and ctags: + nrev = self.dest.puttags(ctags) + # write another hash correspondence to override the previous + # one so we don't end up with extra tag heads + if nrev: + self.map[c] = nrev + + self.writeauthormap() + finally: + self.cleanup() + + def cleanup(self): + try: + self.dest.after() + finally: + self.source.after() + self.map.close() + +def convert(ui, src, dest=None, revmapfile=None, **opts): + global orig_encoding + orig_encoding = encoding.encoding + encoding.encoding = 'UTF-8' + + if not dest: + dest = hg.defaultdest(src) + "-hg" + ui.status(_("assuming destination %s\n") % dest) + + destc = convertsink(ui, dest, opts.get('dest_type')) + + try: + srcc, defaultsort = convertsource(ui, src, opts.get('source_type'), + opts.get('rev')) + except Exception: + for path in destc.created: + shutil.rmtree(path, True) + raise + + sortmodes = ('branchsort', 'datesort', 'sourcesort') + sortmode = [m for m in sortmodes if opts.get(m)] + if len(sortmode) > 1: + raise util.Abort(_('more than one sort mode specified')) + sortmode = sortmode and sortmode[0] or defaultsort + if sortmode == 'sourcesort' and not srcc.hasnativeorder(): + raise util.Abort(_('--sourcesort is not supported by this data source')) + + fmap = opts.get('filemap') + if fmap: + srcc = filemap.filemap_source(ui, srcc, fmap) + destc.setfilemapmode(True) + + if not revmapfile: + try: + revmapfile = destc.revmapfile() + except: + revmapfile = os.path.join(destc, "map") + + c = converter(ui, srcc, destc, revmapfile, opts) + c.convert(sortmode) + diff --git a/sys/src/cmd/hg/hgext/convert/cvs.py b/sys/src/cmd/hg/hgext/convert/cvs.py new file mode 100644 index 000000000..c215747be --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/cvs.py @@ -0,0 +1,372 @@ +# cvs.py: CVS conversion code inspired by hg-cvs-import and git-cvsimport +# +# Copyright 2005-2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import os, locale, re, socket, errno +from cStringIO import StringIO +from mercurial import util +from mercurial.i18n import _ + +from common import NoRepo, commit, converter_source, checktool +import cvsps + +class convert_cvs(converter_source): + def __init__(self, ui, path, rev=None): + super(convert_cvs, self).__init__(ui, path, rev=rev) + + cvs = os.path.join(path, "CVS") + if not os.path.exists(cvs): + raise NoRepo("%s does not look like a CVS checkout" % path) + + checktool('cvs') + self.cmd = ui.config('convert', 'cvsps', 'builtin') + cvspsexe = self.cmd.split(None, 1)[0] + self.builtin = cvspsexe == 'builtin' + if not self.builtin: + ui.warn(_('warning: support for external cvsps is deprecated and ' + 'will be removed in Mercurial 1.4\n')) + + if not self.builtin: + checktool(cvspsexe) + + self.changeset = None + self.files = {} + self.tags = {} + self.lastbranch = {} + self.parent = {} + self.socket = None + self.cvsroot = open(os.path.join(cvs, "Root")).read()[:-1] + self.cvsrepo = open(os.path.join(cvs, "Repository")).read()[:-1] + self.encoding = locale.getpreferredencoding() + + self._connect() + + def _parse(self): + if self.changeset is not None: + return + self.changeset = {} + + maxrev = 0 + cmd = self.cmd + if self.rev: + # TODO: handle tags + try: + # patchset number? + maxrev = int(self.rev) + except ValueError: + try: + # date + util.parsedate(self.rev, ['%Y/%m/%d %H:%M:%S']) + cmd = '%s -d "1970/01/01 00:00:01" -d "%s"' % (cmd, self.rev) + except util.Abort: + raise util.Abort(_('revision %s is not a patchset number or date') % self.rev) + + d = os.getcwd() + try: + os.chdir(self.path) + id = None + state = 0 + filerevids = {} + + if self.builtin: + # builtin cvsps code + self.ui.status(_('using builtin cvsps\n')) + + cache = 'update' + if not self.ui.configbool('convert', 'cvsps.cache', True): + cache = None + db = cvsps.createlog(self.ui, cache=cache) + db = cvsps.createchangeset(self.ui, db, + fuzz=int(self.ui.config('convert', 'cvsps.fuzz', 60)), + mergeto=self.ui.config('convert', 'cvsps.mergeto', None), + mergefrom=self.ui.config('convert', 'cvsps.mergefrom', None)) + + for cs in db: + if maxrev and cs.id>maxrev: + break + id = str(cs.id) + cs.author = self.recode(cs.author) + self.lastbranch[cs.branch] = id + cs.comment = self.recode(cs.comment) + date = util.datestr(cs.date) + self.tags.update(dict.fromkeys(cs.tags, id)) + + files = {} + for f in cs.entries: + files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]), + ['', '(DEAD)'][f.dead]) + + # add current commit to set + c = commit(author=cs.author, date=date, + parents=[str(p.id) for p in cs.parents], + desc=cs.comment, branch=cs.branch or '') + self.changeset[id] = c + self.files[id] = files + else: + # external cvsps + for l in util.popen(cmd): + if state == 0: # header + if l.startswith("PatchSet"): + id = l[9:-2] + if maxrev and int(id) > maxrev: + # ignore everything + state = 3 + elif l.startswith("Date:"): + date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"]) + date = util.datestr(date) + elif l.startswith("Branch:"): + branch = l[8:-1] + self.parent[id] = self.lastbranch.get(branch, 'bad') + self.lastbranch[branch] = id + elif l.startswith("Ancestor branch:"): + ancestor = l[17:-1] + # figure out the parent later + self.parent[id] = self.lastbranch[ancestor] + elif l.startswith("Author:"): + author = self.recode(l[8:-1]) + elif l.startswith("Tag:") or l.startswith("Tags:"): + t = l[l.index(':')+1:] + t = [ut.strip() for ut in t.split(',')] + if (len(t) > 1) or (t[0] and (t[0] != "(none)")): + self.tags.update(dict.fromkeys(t, id)) + elif l.startswith("Log:"): + # switch to gathering log + state = 1 + log = "" + elif state == 1: # log + if l == "Members: \n": + # switch to gathering members + files = {} + oldrevs = [] + log = self.recode(log[:-1]) + state = 2 + else: + # gather log + log += l + elif state == 2: # members + if l == "\n": # start of next entry + state = 0 + p = [self.parent[id]] + if id == "1": + p = [] + if branch == "HEAD": + branch = "" + if branch: + latest = 0 + # the last changeset that contains a base + # file is our parent + for r in oldrevs: + latest = max(filerevids.get(r, 0), latest) + if latest: + p = [latest] + + # add current commit to set + c = commit(author=author, date=date, parents=p, + desc=log, branch=branch) + self.changeset[id] = c + self.files[id] = files + else: + colon = l.rfind(':') + file = l[1:colon] + rev = l[colon+1:-2] + oldrev, rev = rev.split("->") + files[file] = rev + + # save some information for identifying branch points + oldrevs.append("%s:%s" % (oldrev, file)) + filerevids["%s:%s" % (rev, file)] = id + elif state == 3: + # swallow all input + continue + + self.heads = self.lastbranch.values() + finally: + os.chdir(d) + + def _connect(self): + root = self.cvsroot + conntype = None + user, host = None, None + cmd = ['cvs', 'server'] + + self.ui.status(_("connecting to %s\n") % root) + + if root.startswith(":pserver:"): + root = root[9:] + m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)', + root) + if m: + conntype = "pserver" + user, passw, serv, port, root = m.groups() + if not user: + user = "anonymous" + if not port: + port = 2401 + else: + port = int(port) + format0 = ":pserver:%s@%s:%s" % (user, serv, root) + format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root) + + if not passw: + passw = "A" + cvspass = os.path.expanduser("~/.cvspass") + try: + pf = open(cvspass) + for line in pf.read().splitlines(): + part1, part2 = line.split(' ', 1) + if part1 == '/1': + # /1 :pserver:user@example.com:2401/cvsroot/foo Ah 0: + data = fp.read(min(count, chunksize)) + if not data: + raise util.Abort(_("%d bytes missing from remote file") % count) + count -= len(data) + output.write(data) + return output.getvalue() + + if rev.endswith("(DEAD)"): + raise IOError + + args = ("-N -P -kk -r %s --" % rev).split() + args.append(self.cvsrepo + '/' + name) + for x in args: + self.writep.write("Argument %s\n" % x) + self.writep.write("Directory .\n%s\nco\n" % self.realroot) + self.writep.flush() + + data = "" + while 1: + line = self.readp.readline() + if line.startswith("Created ") or line.startswith("Updated "): + self.readp.readline() # path + self.readp.readline() # entries + mode = self.readp.readline()[:-1] + count = int(self.readp.readline()[:-1]) + data = chunkedread(self.readp, count) + elif line.startswith(" "): + data += line[1:] + elif line.startswith("M "): + pass + elif line.startswith("Mbinary "): + count = int(self.readp.readline()[:-1]) + data = chunkedread(self.readp, count) + else: + if line == "ok\n": + return (data, "x" in mode and "x" or "") + elif line.startswith("E "): + self.ui.warn(_("cvs server: %s\n") % line[2:]) + elif line.startswith("Remove"): + self.readp.readline() + else: + raise util.Abort(_("unknown CVS response: %s") % line) + + def getfile(self, file, rev): + self._parse() + data, mode = self._getfile(file, rev) + self.modecache[(file, rev)] = mode + return data + + def getmode(self, file, rev): + return self.modecache[(file, rev)] + + def getchanges(self, rev): + self._parse() + self.modecache = {} + return sorted(self.files[rev].iteritems()), {} + + def getcommit(self, rev): + self._parse() + return self.changeset[rev] + + def gettags(self): + self._parse() + return self.tags + + def getchangedfiles(self, rev, i): + self._parse() + return sorted(self.files[rev]) diff --git a/sys/src/cmd/hg/hgext/convert/cvsps.py b/sys/src/cmd/hg/hgext/convert/cvsps.py new file mode 100644 index 000000000..02db47e25 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/cvsps.py @@ -0,0 +1,831 @@ +# +# Mercurial built-in replacement for cvsps. +# +# Copyright 2008, Frank Kingswood +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import os +import re +import cPickle as pickle +from mercurial import util +from mercurial.i18n import _ + +class logentry(object): + '''Class logentry has the following attributes: + .author - author name as CVS knows it + .branch - name of branch this revision is on + .branches - revision tuple of branches starting at this revision + .comment - commit message + .date - the commit date as a (time, tz) tuple + .dead - true if file revision is dead + .file - Name of file + .lines - a tuple (+lines, -lines) or None + .parent - Previous revision of this entry + .rcs - name of file as returned from CVS + .revision - revision number as tuple + .tags - list of tags on the file + .synthetic - is this a synthetic "file ... added on ..." revision? + .mergepoint- the branch that has been merged from + (if present in rlog output) + .branchpoints- the branches that start at the current entry + ''' + def __init__(self, **entries): + self.__dict__.update(entries) + + def __repr__(self): + return "<%s at 0x%x: %s %s>" % (self.__class__.__name__, + id(self), + self.file, + ".".join(map(str, self.revision))) + +class logerror(Exception): + pass + +def getrepopath(cvspath): + """Return the repository path from a CVS path. + + >>> getrepopath('/foo/bar') + '/foo/bar' + >>> getrepopath('c:/foo/bar') + 'c:/foo/bar' + >>> getrepopath(':pserver:10/foo/bar') + '/foo/bar' + >>> getrepopath(':pserver:10c:/foo/bar') + '/foo/bar' + >>> getrepopath(':pserver:/foo/bar') + '/foo/bar' + >>> getrepopath(':pserver:c:/foo/bar') + 'c:/foo/bar' + >>> getrepopath(':pserver:truc@foo.bar:/foo/bar') + '/foo/bar' + >>> getrepopath(':pserver:truc@foo.bar:c:/foo/bar') + 'c:/foo/bar' + """ + # According to CVS manual, CVS paths are expressed like: + # [:method:][[user][:password]@]hostname[:[port]]/path/to/repository + # + # Unfortunately, Windows absolute paths start with a drive letter + # like 'c:' making it harder to parse. Here we assume that drive + # letters are only one character long and any CVS component before + # the repository path is at least 2 characters long, and use this + # to disambiguate. + parts = cvspath.split(':') + if len(parts) == 1: + return parts[0] + # Here there is an ambiguous case if we have a port number + # immediately followed by a Windows driver letter. We assume this + # never happens and decide it must be CVS path component, + # therefore ignoring it. + if len(parts[-2]) > 1: + return parts[-1].lstrip('0123456789') + return parts[-2] + ':' + parts[-1] + +def createlog(ui, directory=None, root="", rlog=True, cache=None): + '''Collect the CVS rlog''' + + # Because we store many duplicate commit log messages, reusing strings + # saves a lot of memory and pickle storage space. + _scache = {} + def scache(s): + "return a shared version of a string" + return _scache.setdefault(s, s) + + ui.status(_('collecting CVS rlog\n')) + + log = [] # list of logentry objects containing the CVS state + + # patterns to match in CVS (r)log output, by state of use + re_00 = re.compile('RCS file: (.+)$') + re_01 = re.compile('cvs \\[r?log aborted\\]: (.+)$') + re_02 = re.compile('cvs (r?log|server): (.+)\n$') + re_03 = re.compile("(Cannot access.+CVSROOT)|" + "(can't create temporary directory.+)$") + re_10 = re.compile('Working file: (.+)$') + re_20 = re.compile('symbolic names:') + re_30 = re.compile('\t(.+): ([\\d.]+)$') + re_31 = re.compile('----------------------------$') + re_32 = re.compile('=======================================' + '======================================$') + re_50 = re.compile('revision ([\\d.]+)(\s+locked by:\s+.+;)?$') + re_60 = re.compile(r'date:\s+(.+);\s+author:\s+(.+);\s+state:\s+(.+?);' + r'(\s+lines:\s+(\+\d+)?\s+(-\d+)?;)?' + r'(.*mergepoint:\s+([^;]+);)?') + re_70 = re.compile('branches: (.+);$') + + file_added_re = re.compile(r'file [^/]+ was (initially )?added on branch') + + prefix = '' # leading path to strip of what we get from CVS + + if directory is None: + # Current working directory + + # Get the real directory in the repository + try: + prefix = open(os.path.join('CVS','Repository')).read().strip() + if prefix == ".": + prefix = "" + directory = prefix + except IOError: + raise logerror('Not a CVS sandbox') + + if prefix and not prefix.endswith(os.sep): + prefix += os.sep + + # Use the Root file in the sandbox, if it exists + try: + root = open(os.path.join('CVS','Root')).read().strip() + except IOError: + pass + + if not root: + root = os.environ.get('CVSROOT', '') + + # read log cache if one exists + oldlog = [] + date = None + + if cache: + cachedir = os.path.expanduser('~/.hg.cvsps') + if not os.path.exists(cachedir): + os.mkdir(cachedir) + + # The cvsps cache pickle needs a uniquified name, based on the + # repository location. The address may have all sort of nasties + # in it, slashes, colons and such. So here we take just the + # alphanumerics, concatenated in a way that does not mix up the + # various components, so that + # :pserver:user@server:/path + # and + # /pserver/user/server/path + # are mapped to different cache file names. + cachefile = root.split(":") + [directory, "cache"] + cachefile = ['-'.join(re.findall(r'\w+', s)) for s in cachefile if s] + cachefile = os.path.join(cachedir, + '.'.join([s for s in cachefile if s])) + + if cache == 'update': + try: + ui.note(_('reading cvs log cache %s\n') % cachefile) + oldlog = pickle.load(open(cachefile)) + ui.note(_('cache has %d log entries\n') % len(oldlog)) + except Exception, e: + ui.note(_('error reading cache: %r\n') % e) + + if oldlog: + date = oldlog[-1].date # last commit date as a (time,tz) tuple + date = util.datestr(date, '%Y/%m/%d %H:%M:%S %1%2') + + # build the CVS commandline + cmd = ['cvs', '-q'] + if root: + cmd.append('-d%s' % root) + p = util.normpath(getrepopath(root)) + if not p.endswith('/'): + p += '/' + prefix = p + util.normpath(prefix) + cmd.append(['log', 'rlog'][rlog]) + if date: + # no space between option and date string + cmd.append('-d>%s' % date) + cmd.append(directory) + + # state machine begins here + tags = {} # dictionary of revisions on current file with their tags + branchmap = {} # mapping between branch names and revision numbers + state = 0 + store = False # set when a new record can be appended + + cmd = [util.shellquote(arg) for arg in cmd] + ui.note(_("running %s\n") % (' '.join(cmd))) + ui.debug(_("prefix=%r directory=%r root=%r\n") % (prefix, directory, root)) + + pfp = util.popen(' '.join(cmd)) + peek = pfp.readline() + while True: + line = peek + if line == '': + break + peek = pfp.readline() + if line.endswith('\n'): + line = line[:-1] + #ui.debug('state=%d line=%r\n' % (state, line)) + + if state == 0: + # initial state, consume input until we see 'RCS file' + match = re_00.match(line) + if match: + rcs = match.group(1) + tags = {} + if rlog: + filename = util.normpath(rcs[:-2]) + if filename.startswith(prefix): + filename = filename[len(prefix):] + if filename.startswith('/'): + filename = filename[1:] + if filename.startswith('Attic/'): + filename = filename[6:] + else: + filename = filename.replace('/Attic/', '/') + state = 2 + continue + state = 1 + continue + match = re_01.match(line) + if match: + raise Exception(match.group(1)) + match = re_02.match(line) + if match: + raise Exception(match.group(2)) + if re_03.match(line): + raise Exception(line) + + elif state == 1: + # expect 'Working file' (only when using log instead of rlog) + match = re_10.match(line) + assert match, _('RCS file must be followed by working file') + filename = util.normpath(match.group(1)) + state = 2 + + elif state == 2: + # expect 'symbolic names' + if re_20.match(line): + branchmap = {} + state = 3 + + elif state == 3: + # read the symbolic names and store as tags + match = re_30.match(line) + if match: + rev = [int(x) for x in match.group(2).split('.')] + + # Convert magic branch number to an odd-numbered one + revn = len(rev) + if revn > 3 and (revn % 2) == 0 and rev[-2] == 0: + rev = rev[:-2] + rev[-1:] + rev = tuple(rev) + + if rev not in tags: + tags[rev] = [] + tags[rev].append(match.group(1)) + branchmap[match.group(1)] = match.group(2) + + elif re_31.match(line): + state = 5 + elif re_32.match(line): + state = 0 + + elif state == 4: + # expecting '------' separator before first revision + if re_31.match(line): + state = 5 + else: + assert not re_32.match(line), _('must have at least ' + 'some revisions') + + elif state == 5: + # expecting revision number and possibly (ignored) lock indication + # we create the logentry here from values stored in states 0 to 4, + # as this state is re-entered for subsequent revisions of a file. + match = re_50.match(line) + assert match, _('expected revision number') + e = logentry(rcs=scache(rcs), file=scache(filename), + revision=tuple([int(x) for x in match.group(1).split('.')]), + branches=[], parent=None, + synthetic=False) + state = 6 + + elif state == 6: + # expecting date, author, state, lines changed + match = re_60.match(line) + assert match, _('revision must be followed by date line') + d = match.group(1) + if d[2] == '/': + # Y2K + d = '19' + d + + if len(d.split()) != 3: + # cvs log dates always in GMT + d = d + ' UTC' + e.date = util.parsedate(d, ['%y/%m/%d %H:%M:%S', + '%Y/%m/%d %H:%M:%S', + '%Y-%m-%d %H:%M:%S']) + e.author = scache(match.group(2)) + e.dead = match.group(3).lower() == 'dead' + + if match.group(5): + if match.group(6): + e.lines = (int(match.group(5)), int(match.group(6))) + else: + e.lines = (int(match.group(5)), 0) + elif match.group(6): + e.lines = (0, int(match.group(6))) + else: + e.lines = None + + if match.group(7): # cvsnt mergepoint + myrev = match.group(8).split('.') + if len(myrev) == 2: # head + e.mergepoint = 'HEAD' + else: + myrev = '.'.join(myrev[:-2] + ['0', myrev[-2]]) + branches = [b for b in branchmap if branchmap[b] == myrev] + assert len(branches) == 1, 'unknown branch: %s' % e.mergepoint + e.mergepoint = branches[0] + else: + e.mergepoint = None + e.comment = [] + state = 7 + + elif state == 7: + # read the revision numbers of branches that start at this revision + # or store the commit log message otherwise + m = re_70.match(line) + if m: + e.branches = [tuple([int(y) for y in x.strip().split('.')]) + for x in m.group(1).split(';')] + state = 8 + elif re_31.match(line) and re_50.match(peek): + state = 5 + store = True + elif re_32.match(line): + state = 0 + store = True + else: + e.comment.append(line) + + elif state == 8: + # store commit log message + if re_31.match(line): + state = 5 + store = True + elif re_32.match(line): + state = 0 + store = True + else: + e.comment.append(line) + + # When a file is added on a branch B1, CVS creates a synthetic + # dead trunk revision 1.1 so that the branch has a root. + # Likewise, if you merge such a file to a later branch B2 (one + # that already existed when the file was added on B1), CVS + # creates a synthetic dead revision 1.1.x.1 on B2. Don't drop + # these revisions now, but mark them synthetic so + # createchangeset() can take care of them. + if (store and + e.dead and + e.revision[-1] == 1 and # 1.1 or 1.1.x.1 + len(e.comment) == 1 and + file_added_re.match(e.comment[0])): + ui.debug(_('found synthetic revision in %s: %r\n') + % (e.rcs, e.comment[0])) + e.synthetic = True + + if store: + # clean up the results and save in the log. + store = False + e.tags = sorted([scache(x) for x in tags.get(e.revision, [])]) + e.comment = scache('\n'.join(e.comment)) + + revn = len(e.revision) + if revn > 3 and (revn % 2) == 0: + e.branch = tags.get(e.revision[:-1], [None])[0] + else: + e.branch = None + + # find the branches starting from this revision + branchpoints = set() + for branch, revision in branchmap.iteritems(): + revparts = tuple([int(i) for i in revision.split('.')]) + if revparts[-2] == 0 and revparts[-1] % 2 == 0: + # normal branch + if revparts[:-2] == e.revision: + branchpoints.add(branch) + elif revparts == (1,1,1): # vendor branch + if revparts in e.branches: + branchpoints.add(branch) + e.branchpoints = branchpoints + + log.append(e) + + if len(log) % 100 == 0: + ui.status(util.ellipsis('%d %s' % (len(log), e.file), 80)+'\n') + + log.sort(key=lambda x: (x.rcs, x.revision)) + + # find parent revisions of individual files + versions = {} + for e in log: + branch = e.revision[:-1] + p = versions.get((e.rcs, branch), None) + if p is None: + p = e.revision[:-2] + e.parent = p + versions[(e.rcs, branch)] = e.revision + + # update the log cache + if cache: + if log: + # join up the old and new logs + log.sort(key=lambda x: x.date) + + if oldlog and oldlog[-1].date >= log[0].date: + raise logerror('Log cache overlaps with new log entries,' + ' re-run without cache.') + + log = oldlog + log + + # write the new cachefile + ui.note(_('writing cvs log cache %s\n') % cachefile) + pickle.dump(log, open(cachefile, 'w')) + else: + log = oldlog + + ui.status(_('%d log entries\n') % len(log)) + + return log + + +class changeset(object): + '''Class changeset has the following attributes: + .id - integer identifying this changeset (list index) + .author - author name as CVS knows it + .branch - name of branch this changeset is on, or None + .comment - commit message + .date - the commit date as a (time,tz) tuple + .entries - list of logentry objects in this changeset + .parents - list of one or two parent changesets + .tags - list of tags on this changeset + .synthetic - from synthetic revision "file ... added on branch ..." + .mergepoint- the branch that has been merged from + (if present in rlog output) + .branchpoints- the branches that start at the current entry + ''' + def __init__(self, **entries): + self.__dict__.update(entries) + + def __repr__(self): + return "<%s at 0x%x: %s>" % (self.__class__.__name__, + id(self), + getattr(self, 'id', "(no id)")) + +def createchangeset(ui, log, fuzz=60, mergefrom=None, mergeto=None): + '''Convert log into changesets.''' + + ui.status(_('creating changesets\n')) + + # Merge changesets + + log.sort(key=lambda x: (x.comment, x.author, x.branch, x.date)) + + changesets = [] + files = set() + c = None + for i, e in enumerate(log): + + # Check if log entry belongs to the current changeset or not. + + # Since CVS is file centric, two different file revisions with + # different branchpoints should be treated as belonging to two + # different changesets (and the ordering is important and not + # honoured by cvsps at this point). + # + # Consider the following case: + # foo 1.1 branchpoints: [MYBRANCH] + # bar 1.1 branchpoints: [MYBRANCH, MYBRANCH2] + # + # Here foo is part only of MYBRANCH, but not MYBRANCH2, e.g. a + # later version of foo may be in MYBRANCH2, so foo should be the + # first changeset and bar the next and MYBRANCH and MYBRANCH2 + # should both start off of the bar changeset. No provisions are + # made to ensure that this is, in fact, what happens. + if not (c and + e.comment == c.comment and + e.author == c.author and + e.branch == c.branch and + (not hasattr(e, 'branchpoints') or + not hasattr (c, 'branchpoints') or + e.branchpoints == c.branchpoints) and + ((c.date[0] + c.date[1]) <= + (e.date[0] + e.date[1]) <= + (c.date[0] + c.date[1]) + fuzz) and + e.file not in files): + c = changeset(comment=e.comment, author=e.author, + branch=e.branch, date=e.date, entries=[], + mergepoint=getattr(e, 'mergepoint', None), + branchpoints=getattr(e, 'branchpoints', set())) + changesets.append(c) + files = set() + if len(changesets) % 100 == 0: + t = '%d %s' % (len(changesets), repr(e.comment)[1:-1]) + ui.status(util.ellipsis(t, 80) + '\n') + + c.entries.append(e) + files.add(e.file) + c.date = e.date # changeset date is date of latest commit in it + + # Mark synthetic changesets + + for c in changesets: + # Synthetic revisions always get their own changeset, because + # the log message includes the filename. E.g. if you add file3 + # and file4 on a branch, you get four log entries and three + # changesets: + # "File file3 was added on branch ..." (synthetic, 1 entry) + # "File file4 was added on branch ..." (synthetic, 1 entry) + # "Add file3 and file4 to fix ..." (real, 2 entries) + # Hence the check for 1 entry here. + synth = getattr(c.entries[0], 'synthetic', None) + c.synthetic = (len(c.entries) == 1 and synth) + + # Sort files in each changeset + + for c in changesets: + def pathcompare(l, r): + 'Mimic cvsps sorting order' + l = l.split('/') + r = r.split('/') + nl = len(l) + nr = len(r) + n = min(nl, nr) + for i in range(n): + if i + 1 == nl and nl < nr: + return -1 + elif i + 1 == nr and nl > nr: + return +1 + elif l[i] < r[i]: + return -1 + elif l[i] > r[i]: + return +1 + return 0 + def entitycompare(l, r): + return pathcompare(l.file, r.file) + + c.entries.sort(entitycompare) + + # Sort changesets by date + + def cscmp(l, r): + d = sum(l.date) - sum(r.date) + if d: + return d + + # detect vendor branches and initial commits on a branch + le = {} + for e in l.entries: + le[e.rcs] = e.revision + re = {} + for e in r.entries: + re[e.rcs] = e.revision + + d = 0 + for e in l.entries: + if re.get(e.rcs, None) == e.parent: + assert not d + d = 1 + break + + for e in r.entries: + if le.get(e.rcs, None) == e.parent: + assert not d + d = -1 + break + + return d + + changesets.sort(cscmp) + + # Collect tags + + globaltags = {} + for c in changesets: + for e in c.entries: + for tag in e.tags: + # remember which is the latest changeset to have this tag + globaltags[tag] = c + + for c in changesets: + tags = set() + for e in c.entries: + tags.update(e.tags) + # remember tags only if this is the latest changeset to have it + c.tags = sorted(tag for tag in tags if globaltags[tag] is c) + + # Find parent changesets, handle {{mergetobranch BRANCHNAME}} + # by inserting dummy changesets with two parents, and handle + # {{mergefrombranch BRANCHNAME}} by setting two parents. + + if mergeto is None: + mergeto = r'{{mergetobranch ([-\w]+)}}' + if mergeto: + mergeto = re.compile(mergeto) + + if mergefrom is None: + mergefrom = r'{{mergefrombranch ([-\w]+)}}' + if mergefrom: + mergefrom = re.compile(mergefrom) + + versions = {} # changeset index where we saw any particular file version + branches = {} # changeset index where we saw a branch + n = len(changesets) + i = 0 + while i1], + ','.join(cs.tags) or '(none)')) + branchpoints = getattr(cs, 'branchpoints', None) + if branchpoints: + ui.write('Branchpoints: %s \n' % ', '.join(branchpoints)) + if opts["parents"] and cs.parents: + if len(cs.parents)>1: + ui.write('Parents: %s\n' % (','.join([str(p.id) for p in cs.parents]))) + else: + ui.write('Parent: %d\n' % cs.parents[0].id) + + if opts["ancestors"]: + b = cs.branch + r = [] + while b: + b, c = ancestors[b] + r.append('%s:%d:%d' % (b or "HEAD", c, branches[b])) + if r: + ui.write('Ancestors: %s\n' % (','.join(r))) + + ui.write('Log:\n') + ui.write('%s\n\n' % cs.comment) + ui.write('Members: \n') + for f in cs.entries: + fn = f.file + if fn.startswith(opts["prefix"]): + fn = fn[len(opts["prefix"]):] + ui.write('\t%s:%s->%s%s \n' % (fn, '.'.join([str(x) for x in f.parent]) or 'INITIAL', + '.'.join([str(x) for x in f.revision]), ['', '(DEAD)'][f.dead])) + ui.write('\n') + + # have we seen the start tag? + if revisions and off: + if revisions[0] == str(cs.id) or \ + revisions[0] in cs.tags: + off = False + + # see if we reached the end tag + if len(revisions)>1 and not off: + if revisions[1] == str(cs.id) or \ + revisions[1] in cs.tags: + break diff --git a/sys/src/cmd/hg/hgext/convert/darcs.py b/sys/src/cmd/hg/hgext/convert/darcs.py new file mode 100644 index 000000000..fd51f38bd --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/darcs.py @@ -0,0 +1,135 @@ +# darcs.py - darcs support for the convert extension +# +# Copyright 2007-2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +from common import NoRepo, checktool, commandline, commit, converter_source +from mercurial.i18n import _ +from mercurial import util +import os, shutil, tempfile + +# The naming drift of ElementTree is fun! + +try: from xml.etree.cElementTree import ElementTree +except ImportError: + try: from xml.etree.ElementTree import ElementTree + except ImportError: + try: from elementtree.cElementTree import ElementTree + except ImportError: + try: from elementtree.ElementTree import ElementTree + except ImportError: ElementTree = None + + +class darcs_source(converter_source, commandline): + def __init__(self, ui, path, rev=None): + converter_source.__init__(self, ui, path, rev=rev) + commandline.__init__(self, ui, 'darcs') + + # check for _darcs, ElementTree, _darcs/inventory so that we can + # easily skip test-convert-darcs if ElementTree is not around + if not os.path.exists(os.path.join(path, '_darcs', 'inventories')): + raise NoRepo("%s does not look like a darcs repo" % path) + + if not os.path.exists(os.path.join(path, '_darcs')): + raise NoRepo("%s does not look like a darcs repo" % path) + + checktool('darcs') + version = self.run0('--version').splitlines()[0].strip() + if version < '2.1': + raise util.Abort(_('darcs version 2.1 or newer needed (found %r)') % + version) + + if ElementTree is None: + raise util.Abort(_("Python ElementTree module is not available")) + + self.path = os.path.realpath(path) + + self.lastrev = None + self.changes = {} + self.parents = {} + self.tags = {} + + def before(self): + self.tmppath = tempfile.mkdtemp( + prefix='convert-' + os.path.basename(self.path) + '-') + output, status = self.run('init', repodir=self.tmppath) + self.checkexit(status) + + tree = self.xml('changes', xml_output=True, summary=True, + repodir=self.path) + tagname = None + child = None + for elt in tree.findall('patch'): + node = elt.get('hash') + name = elt.findtext('name', '') + if name.startswith('TAG '): + tagname = name[4:].strip() + elif tagname is not None: + self.tags[tagname] = node + tagname = None + self.changes[node] = elt + self.parents[child] = [node] + child = node + self.parents[child] = [] + + def after(self): + self.ui.debug(_('cleaning up %s\n') % self.tmppath) + shutil.rmtree(self.tmppath, ignore_errors=True) + + def xml(self, cmd, **kwargs): + etree = ElementTree() + fp = self._run(cmd, **kwargs) + etree.parse(fp) + self.checkexit(fp.close()) + return etree.getroot() + + def getheads(self): + return self.parents[None] + + def getcommit(self, rev): + elt = self.changes[rev] + date = util.strdate(elt.get('local_date'), '%a %b %d %H:%M:%S %Z %Y') + desc = elt.findtext('name') + '\n' + elt.findtext('comment', '') + return commit(author=elt.get('author'), date=util.datestr(date), + desc=desc.strip(), parents=self.parents[rev]) + + def pull(self, rev): + output, status = self.run('pull', self.path, all=True, + match='hash %s' % rev, + no_test=True, no_posthook=True, + external_merge='/bin/false', + repodir=self.tmppath) + if status: + if output.find('We have conflicts in') == -1: + self.checkexit(status, output) + output, status = self.run('revert', all=True, repodir=self.tmppath) + self.checkexit(status, output) + + def getchanges(self, rev): + self.pull(rev) + copies = {} + changes = [] + for elt in self.changes[rev].find('summary').getchildren(): + if elt.tag in ('add_directory', 'remove_directory'): + continue + if elt.tag == 'move': + changes.append((elt.get('from'), rev)) + copies[elt.get('from')] = elt.get('to') + else: + changes.append((elt.text.strip(), rev)) + self.lastrev = rev + return sorted(changes), copies + + def getfile(self, name, rev): + if rev != self.lastrev: + raise util.Abort(_('internal calling inconsistency')) + return open(os.path.join(self.tmppath, name), 'rb').read() + + def getmode(self, name, rev): + mode = os.lstat(os.path.join(self.tmppath, name)).st_mode + return (mode & 0111) and 'x' or '' + + def gettags(self): + return self.tags diff --git a/sys/src/cmd/hg/hgext/convert/filemap.py b/sys/src/cmd/hg/hgext/convert/filemap.py new file mode 100644 index 000000000..3c8307ae8 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/filemap.py @@ -0,0 +1,359 @@ +# Copyright 2007 Bryan O'Sullivan +# Copyright 2007 Alexis S. L. Carvalho +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import shlex +from mercurial.i18n import _ +from mercurial import util +from common import SKIPREV, converter_source + +def rpairs(name): + yield '.', name + e = len(name) + while e != -1: + yield name[:e], name[e+1:] + e = name.rfind('/', 0, e) + +class filemapper(object): + '''Map and filter filenames when importing. + A name can be mapped to itself, a new name, or None (omit from new + repository).''' + + def __init__(self, ui, path=None): + self.ui = ui + self.include = {} + self.exclude = {} + self.rename = {} + if path: + if self.parse(path): + raise util.Abort(_('errors in filemap')) + + def parse(self, path): + errs = 0 + def check(name, mapping, listname): + if name in mapping: + self.ui.warn(_('%s:%d: %r already in %s list\n') % + (lex.infile, lex.lineno, name, listname)) + return 1 + return 0 + lex = shlex.shlex(open(path), path, True) + lex.wordchars += '!@#$%^&*()-=+[]{}|;:,./<>?' + cmd = lex.get_token() + while cmd: + if cmd == 'include': + name = lex.get_token() + errs += check(name, self.exclude, 'exclude') + self.include[name] = name + elif cmd == 'exclude': + name = lex.get_token() + errs += check(name, self.include, 'include') + errs += check(name, self.rename, 'rename') + self.exclude[name] = name + elif cmd == 'rename': + src = lex.get_token() + dest = lex.get_token() + errs += check(src, self.exclude, 'exclude') + self.rename[src] = dest + elif cmd == 'source': + errs += self.parse(lex.get_token()) + else: + self.ui.warn(_('%s:%d: unknown directive %r\n') % + (lex.infile, lex.lineno, cmd)) + errs += 1 + cmd = lex.get_token() + return errs + + def lookup(self, name, mapping): + for pre, suf in rpairs(name): + try: + return mapping[pre], pre, suf + except KeyError: + pass + return '', name, '' + + def __call__(self, name): + if self.include: + inc = self.lookup(name, self.include)[0] + else: + inc = name + if self.exclude: + exc = self.lookup(name, self.exclude)[0] + else: + exc = '' + if not inc or exc: + return None + newpre, pre, suf = self.lookup(name, self.rename) + if newpre: + if newpre == '.': + return suf + if suf: + return newpre + '/' + suf + return newpre + return name + + def active(self): + return bool(self.include or self.exclude or self.rename) + +# This class does two additional things compared to a regular source: +# +# - Filter and rename files. This is mostly wrapped by the filemapper +# class above. We hide the original filename in the revision that is +# returned by getchanges to be able to find things later in getfile +# and getmode. +# +# - Return only revisions that matter for the files we're interested in. +# This involves rewriting the parents of the original revision to +# create a graph that is restricted to those revisions. +# +# This set of revisions includes not only revisions that directly +# touch files we're interested in, but also merges that merge two +# or more interesting revisions. + +class filemap_source(converter_source): + def __init__(self, ui, baseconverter, filemap): + super(filemap_source, self).__init__(ui) + self.base = baseconverter + self.filemapper = filemapper(ui, filemap) + self.commits = {} + # if a revision rev has parent p in the original revision graph, then + # rev will have parent self.parentmap[p] in the restricted graph. + self.parentmap = {} + # self.wantedancestors[rev] is the set of all ancestors of rev that + # are in the restricted graph. + self.wantedancestors = {} + self.convertedorder = None + self._rebuilt = False + self.origparents = {} + self.children = {} + self.seenchildren = {} + + def before(self): + self.base.before() + + def after(self): + self.base.after() + + def setrevmap(self, revmap): + # rebuild our state to make things restartable + # + # To avoid calling getcommit for every revision that has already + # been converted, we rebuild only the parentmap, delaying the + # rebuild of wantedancestors until we need it (i.e. until a + # merge). + # + # We assume the order argument lists the revisions in + # topological order, so that we can infer which revisions were + # wanted by previous runs. + self._rebuilt = not revmap + seen = {SKIPREV: SKIPREV} + dummyset = set() + converted = [] + for rev in revmap.order: + mapped = revmap[rev] + wanted = mapped not in seen + if wanted: + seen[mapped] = rev + self.parentmap[rev] = rev + else: + self.parentmap[rev] = seen[mapped] + self.wantedancestors[rev] = dummyset + arg = seen[mapped] + if arg == SKIPREV: + arg = None + converted.append((rev, wanted, arg)) + self.convertedorder = converted + return self.base.setrevmap(revmap) + + def rebuild(self): + if self._rebuilt: + return True + self._rebuilt = True + self.parentmap.clear() + self.wantedancestors.clear() + self.seenchildren.clear() + for rev, wanted, arg in self.convertedorder: + if rev not in self.origparents: + self.origparents[rev] = self.getcommit(rev).parents + if arg is not None: + self.children[arg] = self.children.get(arg, 0) + 1 + + for rev, wanted, arg in self.convertedorder: + parents = self.origparents[rev] + if wanted: + self.mark_wanted(rev, parents) + else: + self.mark_not_wanted(rev, arg) + self._discard(arg, *parents) + + return True + + def getheads(self): + return self.base.getheads() + + def getcommit(self, rev): + # We want to save a reference to the commit objects to be able + # to rewrite their parents later on. + c = self.commits[rev] = self.base.getcommit(rev) + for p in c.parents: + self.children[p] = self.children.get(p, 0) + 1 + return c + + def _discard(self, *revs): + for r in revs: + if r is None: + continue + self.seenchildren[r] = self.seenchildren.get(r, 0) + 1 + if self.seenchildren[r] == self.children[r]: + del self.wantedancestors[r] + del self.parentmap[r] + del self.seenchildren[r] + if self._rebuilt: + del self.children[r] + + def wanted(self, rev, i): + # Return True if we're directly interested in rev. + # + # i is an index selecting one of the parents of rev (if rev + # has no parents, i is None). getchangedfiles will give us + # the list of files that are different in rev and in the parent + # indicated by i. If we're interested in any of these files, + # we're interested in rev. + try: + files = self.base.getchangedfiles(rev, i) + except NotImplementedError: + raise util.Abort(_("source repository doesn't support --filemap")) + for f in files: + if self.filemapper(f): + return True + return False + + def mark_not_wanted(self, rev, p): + # Mark rev as not interesting and update data structures. + + if p is None: + # A root revision. Use SKIPREV to indicate that it doesn't + # map to any revision in the restricted graph. Put SKIPREV + # in the set of wanted ancestors to simplify code elsewhere + self.parentmap[rev] = SKIPREV + self.wantedancestors[rev] = set((SKIPREV,)) + return + + # Reuse the data from our parent. + self.parentmap[rev] = self.parentmap[p] + self.wantedancestors[rev] = self.wantedancestors[p] + + def mark_wanted(self, rev, parents): + # Mark rev ss wanted and update data structures. + + # rev will be in the restricted graph, so children of rev in + # the original graph should still have rev as a parent in the + # restricted graph. + self.parentmap[rev] = rev + + # The set of wanted ancestors of rev is the union of the sets + # of wanted ancestors of its parents. Plus rev itself. + wrev = set() + for p in parents: + wrev.update(self.wantedancestors[p]) + wrev.add(rev) + self.wantedancestors[rev] = wrev + + def getchanges(self, rev): + parents = self.commits[rev].parents + if len(parents) > 1: + self.rebuild() + + # To decide whether we're interested in rev we: + # + # - calculate what parents rev will have if it turns out we're + # interested in it. If it's going to have more than 1 parent, + # we're interested in it. + # + # - otherwise, we'll compare it with the single parent we found. + # If any of the files we're interested in is different in the + # the two revisions, we're interested in rev. + + # A parent p is interesting if its mapped version (self.parentmap[p]): + # - is not SKIPREV + # - is still not in the list of parents (we don't want duplicates) + # - is not an ancestor of the mapped versions of the other parents + mparents = [] + wp = None + for i, p1 in enumerate(parents): + mp1 = self.parentmap[p1] + if mp1 == SKIPREV or mp1 in mparents: + continue + for p2 in parents: + if p1 == p2 or mp1 == self.parentmap[p2]: + continue + if mp1 in self.wantedancestors[p2]: + break + else: + mparents.append(mp1) + wp = i + + if wp is None and parents: + wp = 0 + + self.origparents[rev] = parents + + if len(mparents) < 2 and not self.wanted(rev, wp): + # We don't want this revision. + # Update our state and tell the convert process to map this + # revision to the same revision its parent as mapped to. + p = None + if parents: + p = parents[wp] + self.mark_not_wanted(rev, p) + self.convertedorder.append((rev, False, p)) + self._discard(*parents) + return self.parentmap[rev] + + # We want this revision. + # Rewrite the parents of the commit object + self.commits[rev].parents = mparents + self.mark_wanted(rev, parents) + self.convertedorder.append((rev, True, None)) + self._discard(*parents) + + # Get the real changes and do the filtering/mapping. + # To be able to get the files later on in getfile and getmode, + # we hide the original filename in the rev part of the return + # value. + changes, copies = self.base.getchanges(rev) + newnames = {} + files = [] + for f, r in changes: + newf = self.filemapper(f) + if newf: + files.append((newf, (f, r))) + newnames[f] = newf + + ncopies = {} + for c in copies: + newc = self.filemapper(c) + if newc: + newsource = self.filemapper(copies[c]) + if newsource: + ncopies[newc] = newsource + + return files, ncopies + + def getfile(self, name, rev): + realname, realrev = rev + return self.base.getfile(realname, realrev) + + def getmode(self, name, rev): + realname, realrev = rev + return self.base.getmode(realname, realrev) + + def gettags(self): + return self.base.gettags() + + def hasnativeorder(self): + return self.base.hasnativeorder() + + def lookuprev(self, rev): + return self.base.lookuprev(rev) diff --git a/sys/src/cmd/hg/hgext/convert/git.py b/sys/src/cmd/hg/hgext/convert/git.py new file mode 100644 index 000000000..d529744ac --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/git.py @@ -0,0 +1,152 @@ +# git.py - git support for the convert extension +# +# Copyright 2005-2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import os +from mercurial import util + +from common import NoRepo, commit, converter_source, checktool + +class convert_git(converter_source): + # Windows does not support GIT_DIR= construct while other systems + # cannot remove environment variable. Just assume none have + # both issues. + if hasattr(os, 'unsetenv'): + def gitcmd(self, s): + prevgitdir = os.environ.get('GIT_DIR') + os.environ['GIT_DIR'] = self.path + try: + return util.popen(s, 'rb') + finally: + if prevgitdir is None: + del os.environ['GIT_DIR'] + else: + os.environ['GIT_DIR'] = prevgitdir + else: + def gitcmd(self, s): + return util.popen('GIT_DIR=%s %s' % (self.path, s), 'rb') + + def __init__(self, ui, path, rev=None): + super(convert_git, self).__init__(ui, path, rev=rev) + + if os.path.isdir(path + "/.git"): + path += "/.git" + if not os.path.exists(path + "/objects"): + raise NoRepo("%s does not look like a Git repo" % path) + + checktool('git', 'git') + + self.path = path + + def getheads(self): + if not self.rev: + return self.gitcmd('git rev-parse --branches --remotes').read().splitlines() + else: + fh = self.gitcmd("git rev-parse --verify %s" % self.rev) + return [fh.read()[:-1]] + + def catfile(self, rev, type): + if rev == "0" * 40: raise IOError() + fh = self.gitcmd("git cat-file %s %s" % (type, rev)) + return fh.read() + + def getfile(self, name, rev): + return self.catfile(rev, "blob") + + def getmode(self, name, rev): + return self.modecache[(name, rev)] + + def getchanges(self, version): + self.modecache = {} + fh = self.gitcmd("git diff-tree -z --root -m -r %s" % version) + changes = [] + seen = set() + entry = None + for l in fh.read().split('\x00'): + if not entry: + if not l.startswith(':'): + continue + entry = l + continue + f = l + if f not in seen: + seen.add(f) + entry = entry.split() + h = entry[3] + p = (entry[1] == "100755") + s = (entry[1] == "120000") + self.modecache[(f, h)] = (p and "x") or (s and "l") or "" + changes.append((f, h)) + entry = None + return (changes, {}) + + def getcommit(self, version): + c = self.catfile(version, "commit") # read the commit hash + end = c.find("\n\n") + message = c[end+2:] + message = self.recode(message) + l = c[:end].splitlines() + parents = [] + author = committer = None + for e in l[1:]: + n, v = e.split(" ", 1) + if n == "author": + p = v.split() + tm, tz = p[-2:] + author = " ".join(p[:-2]) + if author[0] == "<": author = author[1:-1] + author = self.recode(author) + if n == "committer": + p = v.split() + tm, tz = p[-2:] + committer = " ".join(p[:-2]) + if committer[0] == "<": committer = committer[1:-1] + committer = self.recode(committer) + if n == "parent": parents.append(v) + + if committer and committer != author: + message += "\ncommitter: %s\n" % committer + tzs, tzh, tzm = tz[-5:-4] + "1", tz[-4:-2], tz[-2:] + tz = -int(tzs) * (int(tzh) * 3600 + int(tzm)) + date = tm + " " + str(tz) + + c = commit(parents=parents, date=date, author=author, desc=message, + rev=version) + return c + + def gettags(self): + tags = {} + fh = self.gitcmd('git ls-remote --tags "%s"' % self.path) + prefix = 'refs/tags/' + for line in fh: + line = line.strip() + if not line.endswith("^{}"): + continue + node, tag = line.split(None, 1) + if not tag.startswith(prefix): + continue + tag = tag[len(prefix):-3] + tags[tag] = node + + return tags + + def getchangedfiles(self, version, i): + changes = [] + if i is None: + fh = self.gitcmd("git diff-tree --root -m -r %s" % version) + for l in fh: + if "\t" not in l: + continue + m, f = l[:-1].split("\t") + changes.append(f) + fh.close() + else: + fh = self.gitcmd('git diff-tree --name-only --root -r %s "%s^%s" --' + % (version, version, i+1)) + changes = [f.rstrip('\n') for f in fh] + fh.close() + + return changes diff --git a/sys/src/cmd/hg/hgext/convert/gnuarch.py b/sys/src/cmd/hg/hgext/convert/gnuarch.py new file mode 100644 index 000000000..8d2475e18 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/gnuarch.py @@ -0,0 +1,342 @@ +# gnuarch.py - GNU Arch support for the convert extension +# +# Copyright 2008, 2009 Aleix Conchillo Flaque +# and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +from common import NoRepo, commandline, commit, converter_source +from mercurial.i18n import _ +from mercurial import util +import os, shutil, tempfile, stat, locale +from email.Parser import Parser + +class gnuarch_source(converter_source, commandline): + + class gnuarch_rev(object): + def __init__(self, rev): + self.rev = rev + self.summary = '' + self.date = None + self.author = '' + self.continuationof = None + self.add_files = [] + self.mod_files = [] + self.del_files = [] + self.ren_files = {} + self.ren_dirs = {} + + def __init__(self, ui, path, rev=None): + super(gnuarch_source, self).__init__(ui, path, rev=rev) + + if not os.path.exists(os.path.join(path, '{arch}')): + raise NoRepo(_("%s does not look like a GNU Arch repo") % path) + + # Could use checktool, but we want to check for baz or tla. + self.execmd = None + if util.find_exe('baz'): + self.execmd = 'baz' + else: + if util.find_exe('tla'): + self.execmd = 'tla' + else: + raise util.Abort(_('cannot find a GNU Arch tool')) + + commandline.__init__(self, ui, self.execmd) + + self.path = os.path.realpath(path) + self.tmppath = None + + self.treeversion = None + self.lastrev = None + self.changes = {} + self.parents = {} + self.tags = {} + self.modecache = {} + self.catlogparser = Parser() + self.locale = locale.getpreferredencoding() + self.archives = [] + + def before(self): + # Get registered archives + self.archives = [i.rstrip('\n') + for i in self.runlines0('archives', '-n')] + + if self.execmd == 'tla': + output = self.run0('tree-version', self.path) + else: + output = self.run0('tree-version', '-d', self.path) + self.treeversion = output.strip() + + # Get name of temporary directory + version = self.treeversion.split('/') + self.tmppath = os.path.join(tempfile.gettempdir(), + 'hg-%s' % version[1]) + + # Generate parents dictionary + self.parents[None] = [] + treeversion = self.treeversion + child = None + while treeversion: + self.ui.status(_('analyzing tree version %s...\n') % treeversion) + + archive = treeversion.split('/')[0] + if archive not in self.archives: + self.ui.status(_('tree analysis stopped because it points to ' + 'an unregistered archive %s...\n') % archive) + break + + # Get the complete list of revisions for that tree version + output, status = self.runlines('revisions', '-r', '-f', treeversion) + self.checkexit(status, 'failed retrieveing revisions for %s' % treeversion) + + # No new iteration unless a revision has a continuation-of header + treeversion = None + + for l in output: + rev = l.strip() + self.changes[rev] = self.gnuarch_rev(rev) + self.parents[rev] = [] + + # Read author, date and summary + catlog, status = self.run('cat-log', '-d', self.path, rev) + if status: + catlog = self.run0('cat-archive-log', rev) + self._parsecatlog(catlog, rev) + + # Populate the parents map + self.parents[child].append(rev) + + # Keep track of the current revision as the child of the next + # revision scanned + child = rev + + # Check if we have to follow the usual incremental history + # or if we have to 'jump' to a different treeversion given + # by the continuation-of header. + if self.changes[rev].continuationof: + treeversion = '--'.join(self.changes[rev].continuationof.split('--')[:-1]) + break + + # If we reached a base-0 revision w/o any continuation-of + # header, it means the tree history ends here. + if rev[-6:] == 'base-0': + break + + def after(self): + self.ui.debug(_('cleaning up %s\n') % self.tmppath) + shutil.rmtree(self.tmppath, ignore_errors=True) + + def getheads(self): + return self.parents[None] + + def getfile(self, name, rev): + if rev != self.lastrev: + raise util.Abort(_('internal calling inconsistency')) + + # Raise IOError if necessary (i.e. deleted files). + if not os.path.exists(os.path.join(self.tmppath, name)): + raise IOError + + data, mode = self._getfile(name, rev) + self.modecache[(name, rev)] = mode + + return data + + def getmode(self, name, rev): + return self.modecache[(name, rev)] + + def getchanges(self, rev): + self.modecache = {} + self._update(rev) + changes = [] + copies = {} + + for f in self.changes[rev].add_files: + changes.append((f, rev)) + + for f in self.changes[rev].mod_files: + changes.append((f, rev)) + + for f in self.changes[rev].del_files: + changes.append((f, rev)) + + for src in self.changes[rev].ren_files: + to = self.changes[rev].ren_files[src] + changes.append((src, rev)) + changes.append((to, rev)) + copies[to] = src + + for src in self.changes[rev].ren_dirs: + to = self.changes[rev].ren_dirs[src] + chgs, cps = self._rendirchanges(src, to); + changes += [(f, rev) for f in chgs] + copies.update(cps) + + self.lastrev = rev + return sorted(set(changes)), copies + + def getcommit(self, rev): + changes = self.changes[rev] + return commit(author=changes.author, date=changes.date, + desc=changes.summary, parents=self.parents[rev], rev=rev) + + def gettags(self): + return self.tags + + def _execute(self, cmd, *args, **kwargs): + cmdline = [self.execmd, cmd] + cmdline += args + cmdline = [util.shellquote(arg) for arg in cmdline] + cmdline += ['>', util.nulldev, '2>', util.nulldev] + cmdline = util.quotecommand(' '.join(cmdline)) + self.ui.debug(cmdline, '\n') + return os.system(cmdline) + + def _update(self, rev): + self.ui.debug(_('applying revision %s...\n') % rev) + changeset, status = self.runlines('replay', '-d', self.tmppath, + rev) + if status: + # Something went wrong while merging (baz or tla + # issue?), get latest revision and try from there + shutil.rmtree(self.tmppath, ignore_errors=True) + self._obtainrevision(rev) + else: + old_rev = self.parents[rev][0] + self.ui.debug(_('computing changeset between %s and %s...\n') + % (old_rev, rev)) + self._parsechangeset(changeset, rev) + + def _getfile(self, name, rev): + mode = os.lstat(os.path.join(self.tmppath, name)).st_mode + if stat.S_ISLNK(mode): + data = os.readlink(os.path.join(self.tmppath, name)) + mode = mode and 'l' or '' + else: + data = open(os.path.join(self.tmppath, name), 'rb').read() + mode = (mode & 0111) and 'x' or '' + return data, mode + + def _exclude(self, name): + exclude = [ '{arch}', '.arch-ids', '.arch-inventory' ] + for exc in exclude: + if name.find(exc) != -1: + return True + return False + + def _readcontents(self, path): + files = [] + contents = os.listdir(path) + while len(contents) > 0: + c = contents.pop() + p = os.path.join(path, c) + # os.walk could be used, but here we avoid internal GNU + # Arch files and directories, thus saving a lot time. + if not self._exclude(p): + if os.path.isdir(p): + contents += [os.path.join(c, f) for f in os.listdir(p)] + else: + files.append(c) + return files + + def _rendirchanges(self, src, dest): + changes = [] + copies = {} + files = self._readcontents(os.path.join(self.tmppath, dest)) + for f in files: + s = os.path.join(src, f) + d = os.path.join(dest, f) + changes.append(s) + changes.append(d) + copies[d] = s + return changes, copies + + def _obtainrevision(self, rev): + self.ui.debug(_('obtaining revision %s...\n') % rev) + output = self._execute('get', rev, self.tmppath) + self.checkexit(output) + self.ui.debug(_('analyzing revision %s...\n') % rev) + files = self._readcontents(self.tmppath) + self.changes[rev].add_files += files + + def _stripbasepath(self, path): + if path.startswith('./'): + return path[2:] + return path + + def _parsecatlog(self, data, rev): + try: + catlog = self.catlogparser.parsestr(data) + + # Commit date + self.changes[rev].date = util.datestr( + util.strdate(catlog['Standard-date'], + '%Y-%m-%d %H:%M:%S')) + + # Commit author + self.changes[rev].author = self.recode(catlog['Creator']) + + # Commit description + self.changes[rev].summary = '\n\n'.join((catlog['Summary'], + catlog.get_payload())) + self.changes[rev].summary = self.recode(self.changes[rev].summary) + + # Commit revision origin when dealing with a branch or tag + if catlog.has_key('Continuation-of'): + self.changes[rev].continuationof = self.recode(catlog['Continuation-of']) + except Exception: + raise util.Abort(_('could not parse cat-log of %s') % rev) + + def _parsechangeset(self, data, rev): + for l in data: + l = l.strip() + # Added file (ignore added directory) + if l.startswith('A') and not l.startswith('A/'): + file = self._stripbasepath(l[1:].strip()) + if not self._exclude(file): + self.changes[rev].add_files.append(file) + # Deleted file (ignore deleted directory) + elif l.startswith('D') and not l.startswith('D/'): + file = self._stripbasepath(l[1:].strip()) + if not self._exclude(file): + self.changes[rev].del_files.append(file) + # Modified binary file + elif l.startswith('Mb'): + file = self._stripbasepath(l[2:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Modified link + elif l.startswith('M->'): + file = self._stripbasepath(l[3:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Modified file + elif l.startswith('M'): + file = self._stripbasepath(l[1:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Renamed file (or link) + elif l.startswith('=>'): + files = l[2:].strip().split(' ') + if len(files) == 1: + files = l[2:].strip().split('\t') + src = self._stripbasepath(files[0]) + dst = self._stripbasepath(files[1]) + if not self._exclude(src) and not self._exclude(dst): + self.changes[rev].ren_files[src] = dst + # Conversion from file to link or from link to file (modified) + elif l.startswith('ch'): + file = self._stripbasepath(l[2:].strip()) + if not self._exclude(file): + self.changes[rev].mod_files.append(file) + # Renamed directory + elif l.startswith('/>'): + dirs = l[2:].strip().split(' ') + if len(dirs) == 1: + dirs = l[2:].strip().split('\t') + src = self._stripbasepath(dirs[0]) + dst = self._stripbasepath(dirs[1]) + if not self._exclude(src) and not self._exclude(dst): + self.changes[rev].ren_dirs[src] = dst diff --git a/sys/src/cmd/hg/hgext/convert/hg.py b/sys/src/cmd/hg/hgext/convert/hg.py new file mode 100644 index 000000000..060c1430a --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/hg.py @@ -0,0 +1,363 @@ +# hg.py - hg backend for convert extension +# +# Copyright 2005-2009 Matt Mackall and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +# Notes for hg->hg conversion: +# +# * Old versions of Mercurial didn't trim the whitespace from the ends +# of commit messages, but new versions do. Changesets created by +# those older versions, then converted, may thus have different +# hashes for changesets that are otherwise identical. +# +# * Using "--config convert.hg.saverev=true" will make the source +# identifier to be stored in the converted revision. This will cause +# the converted revision to have a different identity than the +# source. + + +import os, time, cStringIO +from mercurial.i18n import _ +from mercurial.node import bin, hex, nullid +from mercurial import hg, util, context, error + +from common import NoRepo, commit, converter_source, converter_sink + +class mercurial_sink(converter_sink): + def __init__(self, ui, path): + converter_sink.__init__(self, ui, path) + self.branchnames = ui.configbool('convert', 'hg.usebranchnames', True) + self.clonebranches = ui.configbool('convert', 'hg.clonebranches', False) + self.tagsbranch = ui.config('convert', 'hg.tagsbranch', 'default') + self.lastbranch = None + if os.path.isdir(path) and len(os.listdir(path)) > 0: + try: + self.repo = hg.repository(self.ui, path) + if not self.repo.local(): + raise NoRepo(_('%s is not a local Mercurial repo') % path) + except error.RepoError, err: + ui.traceback() + raise NoRepo(err.args[0]) + else: + try: + ui.status(_('initializing destination %s repository\n') % path) + self.repo = hg.repository(self.ui, path, create=True) + if not self.repo.local(): + raise NoRepo(_('%s is not a local Mercurial repo') % path) + self.created.append(path) + except error.RepoError: + ui.traceback() + raise NoRepo("could not create hg repo %s as sink" % path) + self.lock = None + self.wlock = None + self.filemapmode = False + + def before(self): + self.ui.debug(_('run hg sink pre-conversion action\n')) + self.wlock = self.repo.wlock() + self.lock = self.repo.lock() + + def after(self): + self.ui.debug(_('run hg sink post-conversion action\n')) + self.lock.release() + self.wlock.release() + + def revmapfile(self): + return os.path.join(self.path, ".hg", "shamap") + + def authorfile(self): + return os.path.join(self.path, ".hg", "authormap") + + def getheads(self): + h = self.repo.changelog.heads() + return [ hex(x) for x in h ] + + def setbranch(self, branch, pbranches): + if not self.clonebranches: + return + + setbranch = (branch != self.lastbranch) + self.lastbranch = branch + if not branch: + branch = 'default' + pbranches = [(b[0], b[1] and b[1] or 'default') for b in pbranches] + pbranch = pbranches and pbranches[0][1] or 'default' + + branchpath = os.path.join(self.path, branch) + if setbranch: + self.after() + try: + self.repo = hg.repository(self.ui, branchpath) + except: + self.repo = hg.repository(self.ui, branchpath, create=True) + self.before() + + # pbranches may bring revisions from other branches (merge parents) + # Make sure we have them, or pull them. + missings = {} + for b in pbranches: + try: + self.repo.lookup(b[0]) + except: + missings.setdefault(b[1], []).append(b[0]) + + if missings: + self.after() + for pbranch, heads in missings.iteritems(): + pbranchpath = os.path.join(self.path, pbranch) + prepo = hg.repository(self.ui, pbranchpath) + self.ui.note(_('pulling from %s into %s\n') % (pbranch, branch)) + self.repo.pull(prepo, [prepo.lookup(h) for h in heads]) + self.before() + + def _rewritetags(self, source, revmap, data): + fp = cStringIO.StringIO() + for line in data.splitlines(): + s = line.split(' ', 1) + if len(s) != 2: + continue + revid = revmap.get(source.lookuprev(s[0])) + if not revid: + continue + fp.write('%s %s\n' % (revid, s[1])) + return fp.getvalue() + + def putcommit(self, files, copies, parents, commit, source, revmap): + + files = dict(files) + def getfilectx(repo, memctx, f): + v = files[f] + data = source.getfile(f, v) + e = source.getmode(f, v) + if f == '.hgtags': + data = self._rewritetags(source, revmap, data) + return context.memfilectx(f, data, 'l' in e, 'x' in e, copies.get(f)) + + pl = [] + for p in parents: + if p not in pl: + pl.append(p) + parents = pl + nparents = len(parents) + if self.filemapmode and nparents == 1: + m1node = self.repo.changelog.read(bin(parents[0]))[0] + parent = parents[0] + + if len(parents) < 2: parents.append(nullid) + if len(parents) < 2: parents.append(nullid) + p2 = parents.pop(0) + + text = commit.desc + extra = commit.extra.copy() + if self.branchnames and commit.branch: + extra['branch'] = commit.branch + if commit.rev: + extra['convert_revision'] = commit.rev + + while parents: + p1 = p2 + p2 = parents.pop(0) + ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), getfilectx, + commit.author, commit.date, extra) + self.repo.commitctx(ctx) + text = "(octopus merge fixup)\n" + p2 = hex(self.repo.changelog.tip()) + + if self.filemapmode and nparents == 1: + man = self.repo.manifest + mnode = self.repo.changelog.read(bin(p2))[0] + if not man.cmp(m1node, man.revision(mnode)): + self.ui.status(_("filtering out empty revision\n")) + self.repo.rollback() + return parent + return p2 + + def puttags(self, tags): + try: + parentctx = self.repo[self.tagsbranch] + tagparent = parentctx.node() + except error.RepoError: + parentctx = None + tagparent = nullid + + try: + oldlines = sorted(parentctx['.hgtags'].data().splitlines(True)) + except: + oldlines = [] + + newlines = sorted([("%s %s\n" % (tags[tag], tag)) for tag in tags]) + if newlines == oldlines: + return None + data = "".join(newlines) + def getfilectx(repo, memctx, f): + return context.memfilectx(f, data, False, False, None) + + self.ui.status(_("updating tags\n")) + date = "%s 0" % int(time.mktime(time.gmtime())) + extra = {'branch': self.tagsbranch} + ctx = context.memctx(self.repo, (tagparent, None), "update tags", + [".hgtags"], getfilectx, "convert-repo", date, + extra) + self.repo.commitctx(ctx) + return hex(self.repo.changelog.tip()) + + def setfilemapmode(self, active): + self.filemapmode = active + +class mercurial_source(converter_source): + def __init__(self, ui, path, rev=None): + converter_source.__init__(self, ui, path, rev) + self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False) + self.ignored = set() + self.saverev = ui.configbool('convert', 'hg.saverev', False) + try: + self.repo = hg.repository(self.ui, path) + # try to provoke an exception if this isn't really a hg + # repo, but some other bogus compatible-looking url + if not self.repo.local(): + raise error.RepoError() + except error.RepoError: + ui.traceback() + raise NoRepo("%s is not a local Mercurial repo" % path) + self.lastrev = None + self.lastctx = None + self._changescache = None + self.convertfp = None + # Restrict converted revisions to startrev descendants + startnode = ui.config('convert', 'hg.startrev') + if startnode is not None: + try: + startnode = self.repo.lookup(startnode) + except error.RepoError: + raise util.Abort(_('%s is not a valid start revision') + % startnode) + startrev = self.repo.changelog.rev(startnode) + children = {startnode: 1} + for rev in self.repo.changelog.descendants(startrev): + children[self.repo.changelog.node(rev)] = 1 + self.keep = children.__contains__ + else: + self.keep = util.always + + def changectx(self, rev): + if self.lastrev != rev: + self.lastctx = self.repo[rev] + self.lastrev = rev + return self.lastctx + + def parents(self, ctx): + return [p.node() for p in ctx.parents() + if p and self.keep(p.node())] + + def getheads(self): + if self.rev: + heads = [self.repo[self.rev].node()] + else: + heads = self.repo.heads() + return [hex(h) for h in heads if self.keep(h)] + + def getfile(self, name, rev): + try: + return self.changectx(rev)[name].data() + except error.LookupError, err: + raise IOError(err) + + def getmode(self, name, rev): + return self.changectx(rev).manifest().flags(name) + + def getchanges(self, rev): + ctx = self.changectx(rev) + parents = self.parents(ctx) + if not parents: + files = sorted(ctx.manifest()) + if self.ignoreerrors: + # calling getcopies() is a simple way to detect missing + # revlogs and populate self.ignored + self.getcopies(ctx, files) + return [(f, rev) for f in files if f not in self.ignored], {} + if self._changescache and self._changescache[0] == rev: + m, a, r = self._changescache[1] + else: + m, a, r = self.repo.status(parents[0], ctx.node())[:3] + # getcopies() detects missing revlogs early, run it before + # filtering the changes. + copies = self.getcopies(ctx, m + a) + changes = [(name, rev) for name in m + a + r + if name not in self.ignored] + return sorted(changes), copies + + def getcopies(self, ctx, files): + copies = {} + for name in files: + if name in self.ignored: + continue + try: + copysource, copynode = ctx.filectx(name).renamed() + if copysource in self.ignored or not self.keep(copynode): + continue + copies[name] = copysource + except TypeError: + pass + except error.LookupError, e: + if not self.ignoreerrors: + raise + self.ignored.add(name) + self.ui.warn(_('ignoring: %s\n') % e) + return copies + + def getcommit(self, rev): + ctx = self.changectx(rev) + parents = [hex(p) for p in self.parents(ctx)] + if self.saverev: + crev = rev + else: + crev = None + return commit(author=ctx.user(), date=util.datestr(ctx.date()), + desc=ctx.description(), rev=crev, parents=parents, + branch=ctx.branch(), extra=ctx.extra(), + sortkey=ctx.rev()) + + def gettags(self): + tags = [t for t in self.repo.tagslist() if t[0] != 'tip'] + return dict([(name, hex(node)) for name, node in tags + if self.keep(node)]) + + def getchangedfiles(self, rev, i): + ctx = self.changectx(rev) + parents = self.parents(ctx) + if not parents and i is None: + i = 0 + changes = [], ctx.manifest().keys(), [] + else: + i = i or 0 + changes = self.repo.status(parents[i], ctx.node())[:3] + changes = [[f for f in l if f not in self.ignored] for l in changes] + + if i == 0: + self._changescache = (rev, changes) + + return changes[0] + changes[1] + changes[2] + + def converted(self, rev, destrev): + if self.convertfp is None: + self.convertfp = open(os.path.join(self.path, '.hg', 'shamap'), + 'a') + self.convertfp.write('%s %s\n' % (destrev, rev)) + self.convertfp.flush() + + def before(self): + self.ui.debug(_('run hg source pre-conversion action\n')) + + def after(self): + self.ui.debug(_('run hg source post-conversion action\n')) + + def hasnativeorder(self): + return True + + def lookuprev(self, rev): + try: + return hex(self.repo.lookup(rev)) + except error.RepoError: + return None diff --git a/sys/src/cmd/hg/hgext/convert/monotone.py b/sys/src/cmd/hg/hgext/convert/monotone.py new file mode 100644 index 000000000..085510ce9 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/monotone.py @@ -0,0 +1,217 @@ +# monotone.py - monotone support for the convert extension +# +# Copyright 2008, 2009 Mikkel Fahnoe Jorgensen and +# others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +import os, re +from mercurial import util +from common import NoRepo, commit, converter_source, checktool +from common import commandline +from mercurial.i18n import _ + +class monotone_source(converter_source, commandline): + def __init__(self, ui, path=None, rev=None): + converter_source.__init__(self, ui, path, rev) + commandline.__init__(self, ui, 'mtn') + + self.ui = ui + self.path = path + + norepo = NoRepo (_("%s does not look like a monotone repo") % path) + if not os.path.exists(os.path.join(path, '_MTN')): + # Could be a monotone repository (SQLite db file) + try: + header = file(path, 'rb').read(16) + except: + header = '' + if header != 'SQLite format 3\x00': + raise norepo + + # regular expressions for parsing monotone output + space = r'\s*' + name = r'\s+"((?:\\"|[^"])*)"\s*' + value = name + revision = r'\s+\[(\w+)\]\s*' + lines = r'(?:.|\n)+' + + self.dir_re = re.compile(space + "dir" + name) + self.file_re = re.compile(space + "file" + name + "content" + revision) + self.add_file_re = re.compile(space + "add_file" + name + "content" + revision) + self.patch_re = re.compile(space + "patch" + name + "from" + revision + "to" + revision) + self.rename_re = re.compile(space + "rename" + name + "to" + name) + self.delete_re = re.compile(space + "delete" + name) + self.tag_re = re.compile(space + "tag" + name + "revision" + revision) + self.cert_re = re.compile(lines + space + "name" + name + "value" + value) + + attr = space + "file" + lines + space + "attr" + space + self.attr_execute_re = re.compile(attr + '"mtn:execute"' + space + '"true"') + + # cached data + self.manifest_rev = None + self.manifest = None + self.files = None + self.dirs = None + + checktool('mtn', abort=False) + + # test if there are any revisions + self.rev = None + try: + self.getheads() + except: + raise norepo + self.rev = rev + + def mtnrun(self, *args, **kwargs): + kwargs['d'] = self.path + return self.run0('automate', *args, **kwargs) + + def mtnloadmanifest(self, rev): + if self.manifest_rev == rev: + return + self.manifest = self.mtnrun("get_manifest_of", rev).split("\n\n") + self.manifest_rev = rev + self.files = {} + self.dirs = {} + + for e in self.manifest: + m = self.file_re.match(e) + if m: + attr = "" + name = m.group(1) + node = m.group(2) + if self.attr_execute_re.match(e): + attr += "x" + self.files[name] = (node, attr) + m = self.dir_re.match(e) + if m: + self.dirs[m.group(1)] = True + + def mtnisfile(self, name, rev): + # a non-file could be a directory or a deleted or renamed file + self.mtnloadmanifest(rev) + return name in self.files + + def mtnisdir(self, name, rev): + self.mtnloadmanifest(rev) + return name in self.dirs + + def mtngetcerts(self, rev): + certs = {"author":"", "date":"", + "changelog":"", "branch":""} + cert_list = self.mtnrun("certs", rev).split('\n\n key "') + for e in cert_list: + m = self.cert_re.match(e) + if m: + name, value = m.groups() + value = value.replace(r'\"', '"') + value = value.replace(r'\\', '\\') + certs[name] = value + # Monotone may have subsecond dates: 2005-02-05T09:39:12.364306 + # and all times are stored in UTC + certs["date"] = certs["date"].split('.')[0] + " UTC" + return certs + + # implement the converter_source interface: + + def getheads(self): + if not self.rev: + return self.mtnrun("leaves").splitlines() + else: + return [self.rev] + + def getchanges(self, rev): + #revision = self.mtncmd("get_revision %s" % rev).split("\n\n") + revision = self.mtnrun("get_revision", rev).split("\n\n") + files = {} + ignoremove = {} + renameddirs = [] + copies = {} + for e in revision: + m = self.add_file_re.match(e) + if m: + files[m.group(1)] = rev + ignoremove[m.group(1)] = rev + m = self.patch_re.match(e) + if m: + files[m.group(1)] = rev + # Delete/rename is handled later when the convert engine + # discovers an IOError exception from getfile, + # but only if we add the "from" file to the list of changes. + m = self.delete_re.match(e) + if m: + files[m.group(1)] = rev + m = self.rename_re.match(e) + if m: + toname = m.group(2) + fromname = m.group(1) + if self.mtnisfile(toname, rev): + ignoremove[toname] = 1 + copies[toname] = fromname + files[toname] = rev + files[fromname] = rev + elif self.mtnisdir(toname, rev): + renameddirs.append((fromname, toname)) + + # Directory renames can be handled only once we have recorded + # all new files + for fromdir, todir in renameddirs: + renamed = {} + for tofile in self.files: + if tofile in ignoremove: + continue + if tofile.startswith(todir + '/'): + renamed[tofile] = fromdir + tofile[len(todir):] + # Avoid chained moves like: + # d1(/a) => d3/d1(/a) + # d2 => d3 + ignoremove[tofile] = 1 + for tofile, fromfile in renamed.items(): + self.ui.debug (_("copying file in renamed directory " + "from '%s' to '%s'") + % (fromfile, tofile), '\n') + files[tofile] = rev + copies[tofile] = fromfile + for fromfile in renamed.values(): + files[fromfile] = rev + + return (files.items(), copies) + + def getmode(self, name, rev): + self.mtnloadmanifest(rev) + node, attr = self.files.get(name, (None, "")) + return attr + + def getfile(self, name, rev): + if not self.mtnisfile(name, rev): + raise IOError() # file was deleted or renamed + try: + return self.mtnrun("get_file_of", name, r=rev) + except: + raise IOError() # file was deleted or renamed + + def getcommit(self, rev): + certs = self.mtngetcerts(rev) + return commit( + author=certs["author"], + date=util.datestr(util.strdate(certs["date"], "%Y-%m-%dT%H:%M:%S")), + desc=certs["changelog"], + rev=rev, + parents=self.mtnrun("parents", rev).splitlines(), + branch=certs["branch"]) + + def gettags(self): + tags = {} + for e in self.mtnrun("tags").split("\n\n"): + m = self.tag_re.match(e) + if m: + tags[m.group(1)] = m.group(2) + return tags + + def getchangedfiles(self, rev, i): + # This function is only needed to support --filemap + # ... and we don't support that + raise NotImplementedError() diff --git a/sys/src/cmd/hg/hgext/convert/p4.py b/sys/src/cmd/hg/hgext/convert/p4.py new file mode 100644 index 000000000..d65867126 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/p4.py @@ -0,0 +1,205 @@ +# +# Perforce source for convert extension. +# +# Copyright 2009, Frank Kingswood +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. +# + +from mercurial import util +from mercurial.i18n import _ + +from common import commit, converter_source, checktool, NoRepo +import marshal +import re + +def loaditer(f): + "Yield the dictionary objects generated by p4" + try: + while True: + d = marshal.load(f) + if not d: + break + yield d + except EOFError: + pass + +class p4_source(converter_source): + def __init__(self, ui, path, rev=None): + super(p4_source, self).__init__(ui, path, rev=rev) + + if "/" in path and not path.startswith('//'): + raise NoRepo('%s does not look like a P4 repo' % path) + + checktool('p4', abort=False) + + self.p4changes = {} + self.heads = {} + self.changeset = {} + self.files = {} + self.tags = {} + self.lastbranch = {} + self.parent = {} + self.encoding = "latin_1" + self.depotname = {} # mapping from local name to depot name + self.modecache = {} + self.re_type = re.compile("([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)(\+\w+)?$") + self.re_keywords = re.compile(r"\$(Id|Header|Date|DateTime|Change|File|Revision|Author):[^$\n]*\$") + self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$") + + self._parse(ui, path) + + def _parse_view(self, path): + "Read changes affecting the path" + cmd = 'p4 -G changes -s submitted "%s"' % path + stdout = util.popen(cmd) + for d in loaditer(stdout): + c = d.get("change", None) + if c: + self.p4changes[c] = True + + def _parse(self, ui, path): + "Prepare list of P4 filenames and revisions to import" + ui.status(_('reading p4 views\n')) + + # read client spec or view + if "/" in path: + self._parse_view(path) + if path.startswith("//") and path.endswith("/..."): + views = {path[:-3]:""} + else: + views = {"//": ""} + else: + cmd = 'p4 -G client -o "%s"' % path + clientspec = marshal.load(util.popen(cmd)) + + views = {} + for client in clientspec: + if client.startswith("View"): + sview, cview = clientspec[client].split() + self._parse_view(sview) + if sview.endswith("...") and cview.endswith("..."): + sview = sview[:-3] + cview = cview[:-3] + cview = cview[2:] + cview = cview[cview.find("/") + 1:] + views[sview] = cview + + # list of changes that affect our source files + self.p4changes = self.p4changes.keys() + self.p4changes.sort(key=int) + + # list with depot pathnames, longest first + vieworder = views.keys() + vieworder.sort(key=len, reverse=True) + + # handle revision limiting + startrev = self.ui.config('convert', 'p4.startrev', default=0) + self.p4changes = [x for x in self.p4changes + if ((not startrev or int(x) >= int(startrev)) and + (not self.rev or int(x) <= int(self.rev)))] + + # now read the full changelists to get the list of file revisions + ui.status(_('collecting p4 changelists\n')) + lastid = None + for change in self.p4changes: + cmd = "p4 -G describe %s" % change + stdout = util.popen(cmd) + d = marshal.load(stdout) + + desc = self.recode(d["desc"]) + shortdesc = desc.split("\n", 1)[0] + t = '%s %s' % (d["change"], repr(shortdesc)[1:-1]) + ui.status(util.ellipsis(t, 80) + '\n') + + if lastid: + parents = [lastid] + else: + parents = [] + + date = (int(d["time"]), 0) # timezone not set + c = commit(author=self.recode(d["user"]), date=util.datestr(date), + parents=parents, desc=desc, branch='', extra={"p4": change}) + + files = [] + i = 0 + while ("depotFile%d" % i) in d and ("rev%d" % i) in d: + oldname = d["depotFile%d" % i] + filename = None + for v in vieworder: + if oldname.startswith(v): + filename = views[v] + oldname[len(v):] + break + if filename: + files.append((filename, d["rev%d" % i])) + self.depotname[filename] = oldname + i += 1 + self.changeset[change] = c + self.files[change] = files + lastid = change + + if lastid: + self.heads = [lastid] + + def getheads(self): + return self.heads + + def getfile(self, name, rev): + cmd = 'p4 -G print "%s#%s"' % (self.depotname[name], rev) + stdout = util.popen(cmd) + + mode = None + contents = "" + keywords = None + + for d in loaditer(stdout): + code = d["code"] + data = d.get("data") + + if code == "error": + raise IOError(d["generic"], data) + + elif code == "stat": + p4type = self.re_type.match(d["type"]) + if p4type: + mode = "" + flags = (p4type.group(1) or "") + (p4type.group(3) or "") + if "x" in flags: + mode = "x" + if p4type.group(2) == "symlink": + mode = "l" + if "ko" in flags: + keywords = self.re_keywords_old + elif "k" in flags: + keywords = self.re_keywords + + elif code == "text" or code == "binary": + contents += data + + if mode is None: + raise IOError(0, "bad stat") + + self.modecache[(name, rev)] = mode + + if keywords: + contents = keywords.sub("$\\1$", contents) + if mode == "l" and contents.endswith("\n"): + contents = contents[:-1] + + return contents + + def getmode(self, name, rev): + return self.modecache[(name, rev)] + + def getchanges(self, rev): + return self.files[rev], {} + + def getcommit(self, rev): + return self.changeset[rev] + + def gettags(self): + return self.tags + + def getchangedfiles(self, rev, i): + return sorted([x[0] for x in self.files[rev]]) diff --git a/sys/src/cmd/hg/hgext/convert/subversion.py b/sys/src/cmd/hg/hgext/convert/subversion.py new file mode 100644 index 000000000..5a0367485 --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/subversion.py @@ -0,0 +1,1136 @@ +# Subversion 1.4/1.5 Python API backend +# +# Copyright(C) 2007 Daniel Holth et al + +import os +import re +import sys +import cPickle as pickle +import tempfile +import urllib + +from mercurial import strutil, util, encoding +from mercurial.i18n import _ + +# Subversion stuff. Works best with very recent Python SVN bindings +# e.g. SVN 1.5 or backports. Thanks to the bzr folks for enhancing +# these bindings. + +from cStringIO import StringIO + +from common import NoRepo, MissingTool, commit, encodeargs, decodeargs +from common import commandline, converter_source, converter_sink, mapfile + +try: + from svn.core import SubversionException, Pool + import svn + import svn.client + import svn.core + import svn.ra + import svn.delta + import transport + import warnings + warnings.filterwarnings('ignore', + module='svn.core', + category=DeprecationWarning) + +except ImportError: + pass + +class SvnPathNotFound(Exception): + pass + +def geturl(path): + try: + return svn.client.url_from_path(svn.core.svn_path_canonicalize(path)) + except SubversionException: + pass + if os.path.isdir(path): + path = os.path.normpath(os.path.abspath(path)) + if os.name == 'nt': + path = '/' + util.normpath(path) + # Module URL is later compared with the repository URL returned + # by svn API, which is UTF-8. + path = encoding.tolocal(path) + return 'file://%s' % urllib.quote(path) + return path + +def optrev(number): + optrev = svn.core.svn_opt_revision_t() + optrev.kind = svn.core.svn_opt_revision_number + optrev.value.number = number + return optrev + +class changedpath(object): + def __init__(self, p): + self.copyfrom_path = p.copyfrom_path + self.copyfrom_rev = p.copyfrom_rev + self.action = p.action + +def get_log_child(fp, url, paths, start, end, limit=0, discover_changed_paths=True, + strict_node_history=False): + protocol = -1 + def receiver(orig_paths, revnum, author, date, message, pool): + if orig_paths is not None: + for k, v in orig_paths.iteritems(): + orig_paths[k] = changedpath(v) + pickle.dump((orig_paths, revnum, author, date, message), + fp, protocol) + + try: + # Use an ra of our own so that our parent can consume + # our results without confusing the server. + t = transport.SvnRaTransport(url=url) + svn.ra.get_log(t.ra, paths, start, end, limit, + discover_changed_paths, + strict_node_history, + receiver) + except SubversionException, (inst, num): + pickle.dump(num, fp, protocol) + except IOError: + # Caller may interrupt the iteration + pickle.dump(None, fp, protocol) + else: + pickle.dump(None, fp, protocol) + fp.close() + # With large history, cleanup process goes crazy and suddenly + # consumes *huge* amount of memory. The output file being closed, + # there is no need for clean termination. + os._exit(0) + +def debugsvnlog(ui, **opts): + """Fetch SVN log in a subprocess and channel them back to parent to + avoid memory collection issues. + """ + util.set_binary(sys.stdin) + util.set_binary(sys.stdout) + args = decodeargs(sys.stdin.read()) + get_log_child(sys.stdout, *args) + +class logstream(object): + """Interruptible revision log iterator.""" + def __init__(self, stdout): + self._stdout = stdout + + def __iter__(self): + while True: + entry = pickle.load(self._stdout) + try: + orig_paths, revnum, author, date, message = entry + except: + if entry is None: + break + raise SubversionException("child raised exception", entry) + yield entry + + def close(self): + if self._stdout: + self._stdout.close() + self._stdout = None + + +# Check to see if the given path is a local Subversion repo. Verify this by +# looking for several svn-specific files and directories in the given +# directory. +def filecheck(path, proto): + for x in ('locks', 'hooks', 'format', 'db', ): + if not os.path.exists(os.path.join(path, x)): + return False + return True + +# Check to see if a given path is the root of an svn repo over http. We verify +# this by requesting a version-controlled URL we know can't exist and looking +# for the svn-specific "not found" XML. +def httpcheck(path, proto): + return ('' in + urllib.urlopen('%s://%s/!svn/ver/0/.svn' % (proto, path)).read()) + +protomap = {'http': httpcheck, + 'https': httpcheck, + 'file': filecheck, + } +def issvnurl(url): + try: + proto, path = url.split('://', 1) + path = urllib.url2pathname(path) + except ValueError: + proto = 'file' + path = os.path.abspath(url) + path = path.replace(os.sep, '/') + check = protomap.get(proto, lambda p, p2: False) + while '/' in path: + if check(path, proto): + return True + path = path.rsplit('/', 1)[0] + return False + +# SVN conversion code stolen from bzr-svn and tailor +# +# Subversion looks like a versioned filesystem, branches structures +# are defined by conventions and not enforced by the tool. First, +# we define the potential branches (modules) as "trunk" and "branches" +# children directories. Revisions are then identified by their +# module and revision number (and a repository identifier). +# +# The revision graph is really a tree (or a forest). By default, a +# revision parent is the previous revision in the same module. If the +# module directory is copied/moved from another module then the +# revision is the module root and its parent the source revision in +# the parent module. A revision has at most one parent. +# +class svn_source(converter_source): + def __init__(self, ui, url, rev=None): + super(svn_source, self).__init__(ui, url, rev=rev) + + if not (url.startswith('svn://') or url.startswith('svn+ssh://') or + (os.path.exists(url) and + os.path.exists(os.path.join(url, '.svn'))) or + issvnurl(url)): + raise NoRepo("%s does not look like a Subversion repo" % url) + + try: + SubversionException + except NameError: + raise MissingTool(_('Subversion python bindings could not be loaded')) + + try: + version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR + if version < (1, 4): + raise MissingTool(_('Subversion python bindings %d.%d found, ' + '1.4 or later required') % version) + except AttributeError: + raise MissingTool(_('Subversion python bindings are too old, 1.4 ' + 'or later required')) + + self.lastrevs = {} + + latest = None + try: + # Support file://path@rev syntax. Useful e.g. to convert + # deleted branches. + at = url.rfind('@') + if at >= 0: + latest = int(url[at+1:]) + url = url[:at] + except ValueError: + pass + self.url = geturl(url) + self.encoding = 'UTF-8' # Subversion is always nominal UTF-8 + try: + self.transport = transport.SvnRaTransport(url=self.url) + self.ra = self.transport.ra + self.ctx = self.transport.client + self.baseurl = svn.ra.get_repos_root(self.ra) + # Module is either empty or a repository path starting with + # a slash and not ending with a slash. + self.module = urllib.unquote(self.url[len(self.baseurl):]) + self.prevmodule = None + self.rootmodule = self.module + self.commits = {} + self.paths = {} + self.uuid = svn.ra.get_uuid(self.ra) + except SubversionException: + ui.traceback() + raise NoRepo("%s does not look like a Subversion repo" % self.url) + + if rev: + try: + latest = int(rev) + except ValueError: + raise util.Abort(_('svn: revision %s is not an integer') % rev) + + self.startrev = self.ui.config('convert', 'svn.startrev', default=0) + try: + self.startrev = int(self.startrev) + if self.startrev < 0: + self.startrev = 0 + except ValueError: + raise util.Abort(_('svn: start revision %s is not an integer') + % self.startrev) + + self.head = self.latest(self.module, latest) + if not self.head: + raise util.Abort(_('no revision found in module %s') + % self.module) + self.last_changed = self.revnum(self.head) + + self._changescache = None + + if os.path.exists(os.path.join(url, '.svn/entries')): + self.wc = url + else: + self.wc = None + self.convertfp = None + + def setrevmap(self, revmap): + lastrevs = {} + for revid in revmap.iterkeys(): + uuid, module, revnum = self.revsplit(revid) + lastrevnum = lastrevs.setdefault(module, revnum) + if revnum > lastrevnum: + lastrevs[module] = revnum + self.lastrevs = lastrevs + + def exists(self, path, optrev): + try: + svn.client.ls(self.url.rstrip('/') + '/' + urllib.quote(path), + optrev, False, self.ctx) + return True + except SubversionException: + return False + + def getheads(self): + + def isdir(path, revnum): + kind = self._checkpath(path, revnum) + return kind == svn.core.svn_node_dir + + def getcfgpath(name, rev): + cfgpath = self.ui.config('convert', 'svn.' + name) + if cfgpath is not None and cfgpath.strip() == '': + return None + path = (cfgpath or name).strip('/') + if not self.exists(path, rev): + if cfgpath: + raise util.Abort(_('expected %s to be at %r, but not found') + % (name, path)) + return None + self.ui.note(_('found %s at %r\n') % (name, path)) + return path + + rev = optrev(self.last_changed) + oldmodule = '' + trunk = getcfgpath('trunk', rev) + self.tags = getcfgpath('tags', rev) + branches = getcfgpath('branches', rev) + + # If the project has a trunk or branches, we will extract heads + # from them. We keep the project root otherwise. + if trunk: + oldmodule = self.module or '' + self.module += '/' + trunk + self.head = self.latest(self.module, self.last_changed) + if not self.head: + raise util.Abort(_('no revision found in module %s') + % self.module) + + # First head in the list is the module's head + self.heads = [self.head] + if self.tags is not None: + self.tags = '%s/%s' % (oldmodule , (self.tags or 'tags')) + + # Check if branches bring a few more heads to the list + if branches: + rpath = self.url.strip('/') + branchnames = svn.client.ls(rpath + '/' + urllib.quote(branches), + rev, False, self.ctx) + for branch in branchnames.keys(): + module = '%s/%s/%s' % (oldmodule, branches, branch) + if not isdir(module, self.last_changed): + continue + brevid = self.latest(module, self.last_changed) + if not brevid: + self.ui.note(_('ignoring empty branch %s\n') % branch) + continue + self.ui.note(_('found branch %s at %d\n') % + (branch, self.revnum(brevid))) + self.heads.append(brevid) + + if self.startrev and self.heads: + if len(self.heads) > 1: + raise util.Abort(_('svn: start revision is not supported ' + 'with more than one branch')) + revnum = self.revnum(self.heads[0]) + if revnum < self.startrev: + raise util.Abort(_('svn: no revision found after start revision %d') + % self.startrev) + + return self.heads + + def getfile(self, file, rev): + data, mode = self._getfile(file, rev) + self.modecache[(file, rev)] = mode + return data + + def getmode(self, file, rev): + return self.modecache[(file, rev)] + + def getchanges(self, rev): + if self._changescache and self._changescache[0] == rev: + return self._changescache[1] + self._changescache = None + self.modecache = {} + (paths, parents) = self.paths[rev] + if parents: + files, copies = self.expandpaths(rev, paths, parents) + else: + # Perform a full checkout on roots + uuid, module, revnum = self.revsplit(rev) + entries = svn.client.ls(self.baseurl + urllib.quote(module), + optrev(revnum), True, self.ctx) + files = [n for n,e in entries.iteritems() + if e.kind == svn.core.svn_node_file] + copies = {} + + files.sort() + files = zip(files, [rev] * len(files)) + + # caller caches the result, so free it here to release memory + del self.paths[rev] + return (files, copies) + + def getchangedfiles(self, rev, i): + changes = self.getchanges(rev) + self._changescache = (rev, changes) + return [f[0] for f in changes[0]] + + def getcommit(self, rev): + if rev not in self.commits: + uuid, module, revnum = self.revsplit(rev) + self.module = module + self.reparent(module) + # We assume that: + # - requests for revisions after "stop" come from the + # revision graph backward traversal. Cache all of them + # down to stop, they will be used eventually. + # - requests for revisions before "stop" come to get + # isolated branches parents. Just fetch what is needed. + stop = self.lastrevs.get(module, 0) + if revnum < stop: + stop = revnum + 1 + self._fetch_revisions(revnum, stop) + commit = self.commits[rev] + # caller caches the result, so free it here to release memory + del self.commits[rev] + return commit + + def gettags(self): + tags = {} + if self.tags is None: + return tags + + # svn tags are just a convention, project branches left in a + # 'tags' directory. There is no other relationship than + # ancestry, which is expensive to discover and makes them hard + # to update incrementally. Worse, past revisions may be + # referenced by tags far away in the future, requiring a deep + # history traversal on every calculation. Current code + # performs a single backward traversal, tracking moves within + # the tags directory (tag renaming) and recording a new tag + # everytime a project is copied from outside the tags + # directory. It also lists deleted tags, this behaviour may + # change in the future. + pendings = [] + tagspath = self.tags + start = svn.ra.get_latest_revnum(self.ra) + try: + for entry in self._getlog([self.tags], start, self.startrev): + origpaths, revnum, author, date, message = entry + copies = [(e.copyfrom_path, e.copyfrom_rev, p) for p, e + in origpaths.iteritems() if e.copyfrom_path] + # Apply moves/copies from more specific to general + copies.sort(reverse=True) + + srctagspath = tagspath + if copies and copies[-1][2] == tagspath: + # Track tags directory moves + srctagspath = copies.pop()[0] + + for source, sourcerev, dest in copies: + if not dest.startswith(tagspath + '/'): + continue + for tag in pendings: + if tag[0].startswith(dest): + tagpath = source + tag[0][len(dest):] + tag[:2] = [tagpath, sourcerev] + break + else: + pendings.append([source, sourcerev, dest]) + + # Filter out tags with children coming from different + # parts of the repository like: + # /tags/tag.1 (from /trunk:10) + # /tags/tag.1/foo (from /branches/foo:12) + # Here/tags/tag.1 discarded as well as its children. + # It happens with tools like cvs2svn. Such tags cannot + # be represented in mercurial. + addeds = dict((p, e.copyfrom_path) for p, e + in origpaths.iteritems() + if e.action == 'A' and e.copyfrom_path) + badroots = set() + for destroot in addeds: + for source, sourcerev, dest in pendings: + if (not dest.startswith(destroot + '/') + or source.startswith(addeds[destroot] + '/')): + continue + badroots.add(destroot) + break + + for badroot in badroots: + pendings = [p for p in pendings if p[2] != badroot + and not p[2].startswith(badroot + '/')] + + # Tell tag renamings from tag creations + remainings = [] + for source, sourcerev, dest in pendings: + tagname = dest.split('/')[-1] + if source.startswith(srctagspath): + remainings.append([source, sourcerev, tagname]) + continue + if tagname in tags: + # Keep the latest tag value + continue + # From revision may be fake, get one with changes + try: + tagid = self.latest(source, sourcerev) + if tagid and tagname not in tags: + tags[tagname] = tagid + except SvnPathNotFound: + # It happens when we are following directories + # we assumed were copied with their parents + # but were really created in the tag + # directory. + pass + pendings = remainings + tagspath = srctagspath + + except SubversionException: + self.ui.note(_('no tags found at revision %d\n') % start) + return tags + + def converted(self, rev, destrev): + if not self.wc: + return + if self.convertfp is None: + self.convertfp = open(os.path.join(self.wc, '.svn', 'hg-shamap'), + 'a') + self.convertfp.write('%s %d\n' % (destrev, self.revnum(rev))) + self.convertfp.flush() + + def revid(self, revnum, module=None): + return 'svn:%s%s@%s' % (self.uuid, module or self.module, revnum) + + def revnum(self, rev): + return int(rev.split('@')[-1]) + + def revsplit(self, rev): + url, revnum = rev.rsplit('@', 1) + revnum = int(revnum) + parts = url.split('/', 1) + uuid = parts.pop(0)[4:] + mod = '' + if parts: + mod = '/' + parts[0] + return uuid, mod, revnum + + def latest(self, path, stop=0): + """Find the latest revid affecting path, up to stop. It may return + a revision in a different module, since a branch may be moved without + a change being reported. Return None if computed module does not + belong to rootmodule subtree. + """ + if not path.startswith(self.rootmodule): + # Requests on foreign branches may be forbidden at server level + self.ui.debug(_('ignoring foreign branch %r\n') % path) + return None + + if not stop: + stop = svn.ra.get_latest_revnum(self.ra) + try: + prevmodule = self.reparent('') + dirent = svn.ra.stat(self.ra, path.strip('/'), stop) + self.reparent(prevmodule) + except SubversionException: + dirent = None + if not dirent: + raise SvnPathNotFound(_('%s not found up to revision %d') % (path, stop)) + + # stat() gives us the previous revision on this line of + # development, but it might be in *another module*. Fetch the + # log and detect renames down to the latest revision. + stream = self._getlog([path], stop, dirent.created_rev) + try: + for entry in stream: + paths, revnum, author, date, message = entry + if revnum <= dirent.created_rev: + break + + for p in paths: + if not path.startswith(p) or not paths[p].copyfrom_path: + continue + newpath = paths[p].copyfrom_path + path[len(p):] + self.ui.debug(_("branch renamed from %s to %s at %d\n") % + (path, newpath, revnum)) + path = newpath + break + finally: + stream.close() + + if not path.startswith(self.rootmodule): + self.ui.debug(_('ignoring foreign branch %r\n') % path) + return None + return self.revid(dirent.created_rev, path) + + def reparent(self, module): + """Reparent the svn transport and return the previous parent.""" + if self.prevmodule == module: + return module + svnurl = self.baseurl + urllib.quote(module) + prevmodule = self.prevmodule + if prevmodule is None: + prevmodule = '' + self.ui.debug(_("reparent to %s\n") % svnurl) + svn.ra.reparent(self.ra, svnurl) + self.prevmodule = module + return prevmodule + + def expandpaths(self, rev, paths, parents): + entries = [] + # Map of entrypath, revision for finding source of deleted + # revisions. + copyfrom = {} + copies = {} + + new_module, revnum = self.revsplit(rev)[1:] + if new_module != self.module: + self.module = new_module + self.reparent(self.module) + + for path, ent in paths: + entrypath = self.getrelpath(path) + + kind = self._checkpath(entrypath, revnum) + if kind == svn.core.svn_node_file: + entries.append(self.recode(entrypath)) + if not ent.copyfrom_path or not parents: + continue + # Copy sources not in parent revisions cannot be + # represented, ignore their origin for now + pmodule, prevnum = self.revsplit(parents[0])[1:] + if ent.copyfrom_rev < prevnum: + continue + copyfrom_path = self.getrelpath(ent.copyfrom_path, pmodule) + if not copyfrom_path: + continue + self.ui.debug(_("copied to %s from %s@%s\n") % + (entrypath, copyfrom_path, ent.copyfrom_rev)) + copies[self.recode(entrypath)] = self.recode(copyfrom_path) + elif kind == 0: # gone, but had better be a deleted *file* + self.ui.debug(_("gone from %s\n") % ent.copyfrom_rev) + pmodule, prevnum = self.revsplit(parents[0])[1:] + parentpath = pmodule + "/" + entrypath + self.ui.debug(_("entry %s\n") % parentpath) + + # We can avoid the reparent calls if the module has + # not changed but it probably does not worth the pain. + prevmodule = self.reparent('') + fromkind = svn.ra.check_path(self.ra, parentpath.strip('/'), prevnum) + self.reparent(prevmodule) + + if fromkind == svn.core.svn_node_file: + entries.append(self.recode(entrypath)) + elif fromkind == svn.core.svn_node_dir: + if ent.action == 'C': + children = self._find_children(path, prevnum) + else: + oroot = parentpath.strip('/') + nroot = path.strip('/') + children = self._find_children(oroot, prevnum) + children = [s.replace(oroot,nroot) for s in children] + + for child in children: + childpath = self.getrelpath("/" + child, pmodule) + if not childpath: + continue + if childpath in copies: + del copies[childpath] + entries.append(childpath) + else: + self.ui.debug(_('unknown path in revision %d: %s\n') % \ + (revnum, path)) + elif kind == svn.core.svn_node_dir: + # If the directory just had a prop change, + # then we shouldn't need to look for its children. + if ent.action == 'M': + continue + + children = sorted(self._find_children(path, revnum)) + for child in children: + # Can we move a child directory and its + # parent in the same commit? (probably can). Could + # cause problems if instead of revnum -1, + # we have to look in (copyfrom_path, revnum - 1) + entrypath = self.getrelpath("/" + child) + if entrypath: + # Need to filter out directories here... + kind = self._checkpath(entrypath, revnum) + if kind != svn.core.svn_node_dir: + entries.append(self.recode(entrypath)) + + # Handle directory copies + if not ent.copyfrom_path or not parents: + continue + # Copy sources not in parent revisions cannot be + # represented, ignore their origin for now + pmodule, prevnum = self.revsplit(parents[0])[1:] + if ent.copyfrom_rev < prevnum: + continue + copyfrompath = self.getrelpath(ent.copyfrom_path, pmodule) + if not copyfrompath: + continue + copyfrom[path] = ent + self.ui.debug(_("mark %s came from %s:%d\n") + % (path, copyfrompath, ent.copyfrom_rev)) + children = self._find_children(ent.copyfrom_path, ent.copyfrom_rev) + children.sort() + for child in children: + entrypath = self.getrelpath("/" + child, pmodule) + if not entrypath: + continue + copytopath = path + entrypath[len(copyfrompath):] + copytopath = self.getrelpath(copytopath) + copies[self.recode(copytopath)] = self.recode(entrypath) + + return (list(set(entries)), copies) + + def _fetch_revisions(self, from_revnum, to_revnum): + if from_revnum < to_revnum: + from_revnum, to_revnum = to_revnum, from_revnum + + self.child_cset = None + + def parselogentry(orig_paths, revnum, author, date, message): + """Return the parsed commit object or None, and True if + the revision is a branch root. + """ + self.ui.debug(_("parsing revision %d (%d changes)\n") % + (revnum, len(orig_paths))) + + branched = False + rev = self.revid(revnum) + # branch log might return entries for a parent we already have + + if rev in self.commits or revnum < to_revnum: + return None, branched + + parents = [] + # check whether this revision is the start of a branch or part + # of a branch renaming + orig_paths = sorted(orig_paths.iteritems()) + root_paths = [(p,e) for p,e in orig_paths if self.module.startswith(p)] + if root_paths: + path, ent = root_paths[-1] + if ent.copyfrom_path: + branched = True + newpath = ent.copyfrom_path + self.module[len(path):] + # ent.copyfrom_rev may not be the actual last revision + previd = self.latest(newpath, ent.copyfrom_rev) + if previd is not None: + prevmodule, prevnum = self.revsplit(previd)[1:] + if prevnum >= self.startrev: + parents = [previd] + self.ui.note(_('found parent of branch %s at %d: %s\n') % + (self.module, prevnum, prevmodule)) + else: + self.ui.debug(_("no copyfrom path, don't know what to do.\n")) + + paths = [] + # filter out unrelated paths + for path, ent in orig_paths: + if self.getrelpath(path) is None: + continue + paths.append((path, ent)) + + # Example SVN datetime. Includes microseconds. + # ISO-8601 conformant + # '2007-01-04T17:35:00.902377Z' + date = util.parsedate(date[:19] + " UTC", ["%Y-%m-%dT%H:%M:%S"]) + + log = message and self.recode(message) or '' + author = author and self.recode(author) or '' + try: + branch = self.module.split("/")[-1] + if branch == 'trunk': + branch = '' + except IndexError: + branch = None + + cset = commit(author=author, + date=util.datestr(date), + desc=log, + parents=parents, + branch=branch, + rev=rev) + + self.commits[rev] = cset + # The parents list is *shared* among self.paths and the + # commit object. Both will be updated below. + self.paths[rev] = (paths, cset.parents) + if self.child_cset and not self.child_cset.parents: + self.child_cset.parents[:] = [rev] + self.child_cset = cset + return cset, branched + + self.ui.note(_('fetching revision log for "%s" from %d to %d\n') % + (self.module, from_revnum, to_revnum)) + + try: + firstcset = None + lastonbranch = False + stream = self._getlog([self.module], from_revnum, to_revnum) + try: + for entry in stream: + paths, revnum, author, date, message = entry + if revnum < self.startrev: + lastonbranch = True + break + if not paths: + self.ui.debug(_('revision %d has no entries\n') % revnum) + continue + cset, lastonbranch = parselogentry(paths, revnum, author, + date, message) + if cset: + firstcset = cset + if lastonbranch: + break + finally: + stream.close() + + if not lastonbranch and firstcset and not firstcset.parents: + # The first revision of the sequence (the last fetched one) + # has invalid parents if not a branch root. Find the parent + # revision now, if any. + try: + firstrevnum = self.revnum(firstcset.rev) + if firstrevnum > 1: + latest = self.latest(self.module, firstrevnum - 1) + if latest: + firstcset.parents.append(latest) + except SvnPathNotFound: + pass + except SubversionException, (inst, num): + if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: + raise util.Abort(_('svn: branch has no revision %s') % to_revnum) + raise + + def _getfile(self, file, rev): + # TODO: ra.get_file transmits the whole file instead of diffs. + mode = '' + try: + new_module, revnum = self.revsplit(rev)[1:] + if self.module != new_module: + self.module = new_module + self.reparent(self.module) + io = StringIO() + info = svn.ra.get_file(self.ra, file, revnum, io) + data = io.getvalue() + # ra.get_files() seems to keep a reference on the input buffer + # preventing collection. Release it explicitely. + io.close() + if isinstance(info, list): + info = info[-1] + mode = ("svn:executable" in info) and 'x' or '' + mode = ("svn:special" in info) and 'l' or mode + except SubversionException, e: + notfound = (svn.core.SVN_ERR_FS_NOT_FOUND, + svn.core.SVN_ERR_RA_DAV_PATH_NOT_FOUND) + if e.apr_err in notfound: # File not found + raise IOError() + raise + if mode == 'l': + link_prefix = "link " + if data.startswith(link_prefix): + data = data[len(link_prefix):] + return data, mode + + def _find_children(self, path, revnum): + path = path.strip('/') + pool = Pool() + rpath = '/'.join([self.baseurl, urllib.quote(path)]).strip('/') + return ['%s/%s' % (path, x) for x in + svn.client.ls(rpath, optrev(revnum), True, self.ctx, pool).keys()] + + def getrelpath(self, path, module=None): + if module is None: + module = self.module + # Given the repository url of this wc, say + # "http://server/plone/CMFPlone/branches/Plone-2_0-branch" + # extract the "entry" portion (a relative path) from what + # svn log --xml says, ie + # "/CMFPlone/branches/Plone-2_0-branch/tests/PloneTestCase.py" + # that is to say "tests/PloneTestCase.py" + if path.startswith(module): + relative = path.rstrip('/')[len(module):] + if relative.startswith('/'): + return relative[1:] + elif relative == '': + return relative + + # The path is outside our tracked tree... + self.ui.debug(_('%r is not under %r, ignoring\n') % (path, module)) + return None + + def _checkpath(self, path, revnum): + # ra.check_path does not like leading slashes very much, it leads + # to PROPFIND subversion errors + return svn.ra.check_path(self.ra, path.strip('/'), revnum) + + def _getlog(self, paths, start, end, limit=0, discover_changed_paths=True, + strict_node_history=False): + # Normalize path names, svn >= 1.5 only wants paths relative to + # supplied URL + relpaths = [] + for p in paths: + if not p.startswith('/'): + p = self.module + '/' + p + relpaths.append(p.strip('/')) + args = [self.baseurl, relpaths, start, end, limit, discover_changed_paths, + strict_node_history] + arg = encodeargs(args) + hgexe = util.hgexecutable() + cmd = '%s debugsvnlog' % util.shellquote(hgexe) + stdin, stdout = util.popen2(cmd) + stdin.write(arg) + stdin.close() + return logstream(stdout) + +pre_revprop_change = '''#!/bin/sh + +REPOS="$1" +REV="$2" +USER="$3" +PROPNAME="$4" +ACTION="$5" + +if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi +if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-branch" ]; then exit 0; fi +if [ "$ACTION" = "A" -a "$PROPNAME" = "hg:convert-rev" ]; then exit 0; fi + +echo "Changing prohibited revision property" >&2 +exit 1 +''' + +class svn_sink(converter_sink, commandline): + commit_re = re.compile(r'Committed revision (\d+).', re.M) + + def prerun(self): + if self.wc: + os.chdir(self.wc) + + def postrun(self): + if self.wc: + os.chdir(self.cwd) + + def join(self, name): + return os.path.join(self.wc, '.svn', name) + + def revmapfile(self): + return self.join('hg-shamap') + + def authorfile(self): + return self.join('hg-authormap') + + def __init__(self, ui, path): + converter_sink.__init__(self, ui, path) + commandline.__init__(self, ui, 'svn') + self.delete = [] + self.setexec = [] + self.delexec = [] + self.copies = [] + self.wc = None + self.cwd = os.getcwd() + + path = os.path.realpath(path) + + created = False + if os.path.isfile(os.path.join(path, '.svn', 'entries')): + self.wc = path + self.run0('update') + else: + wcpath = os.path.join(os.getcwd(), os.path.basename(path) + '-wc') + + if os.path.isdir(os.path.dirname(path)): + if not os.path.exists(os.path.join(path, 'db', 'fs-type')): + ui.status(_('initializing svn repo %r\n') % + os.path.basename(path)) + commandline(ui, 'svnadmin').run0('create', path) + created = path + path = util.normpath(path) + if not path.startswith('/'): + path = '/' + path + path = 'file://' + path + + ui.status(_('initializing svn wc %r\n') % os.path.basename(wcpath)) + self.run0('checkout', path, wcpath) + + self.wc = wcpath + self.opener = util.opener(self.wc) + self.wopener = util.opener(self.wc) + self.childmap = mapfile(ui, self.join('hg-childmap')) + self.is_exec = util.checkexec(self.wc) and util.is_exec or None + + if created: + hook = os.path.join(created, 'hooks', 'pre-revprop-change') + fp = open(hook, 'w') + fp.write(pre_revprop_change) + fp.close() + util.set_flags(hook, False, True) + + xport = transport.SvnRaTransport(url=geturl(path)) + self.uuid = svn.ra.get_uuid(xport.ra) + + def wjoin(self, *names): + return os.path.join(self.wc, *names) + + def putfile(self, filename, flags, data): + if 'l' in flags: + self.wopener.symlink(data, filename) + else: + try: + if os.path.islink(self.wjoin(filename)): + os.unlink(filename) + except OSError: + pass + self.wopener(filename, 'w').write(data) + + if self.is_exec: + was_exec = self.is_exec(self.wjoin(filename)) + else: + # On filesystems not supporting execute-bit, there is no way + # to know if it is set but asking subversion. Setting it + # systematically is just as expensive and much simpler. + was_exec = 'x' not in flags + + util.set_flags(self.wjoin(filename), False, 'x' in flags) + if was_exec: + if 'x' not in flags: + self.delexec.append(filename) + else: + if 'x' in flags: + self.setexec.append(filename) + + def _copyfile(self, source, dest): + # SVN's copy command pukes if the destination file exists, but + # our copyfile method expects to record a copy that has + # already occurred. Cross the semantic gap. + wdest = self.wjoin(dest) + exists = os.path.exists(wdest) + if exists: + fd, tempname = tempfile.mkstemp( + prefix='hg-copy-', dir=os.path.dirname(wdest)) + os.close(fd) + os.unlink(tempname) + os.rename(wdest, tempname) + try: + self.run0('copy', source, dest) + finally: + if exists: + try: + os.unlink(wdest) + except OSError: + pass + os.rename(tempname, wdest) + + def dirs_of(self, files): + dirs = set() + for f in files: + if os.path.isdir(self.wjoin(f)): + dirs.add(f) + for i in strutil.rfindall(f, '/'): + dirs.add(f[:i]) + return dirs + + def add_dirs(self, files): + add_dirs = [d for d in sorted(self.dirs_of(files)) + if not os.path.exists(self.wjoin(d, '.svn', 'entries'))] + if add_dirs: + self.xargs(add_dirs, 'add', non_recursive=True, quiet=True) + return add_dirs + + def add_files(self, files): + if files: + self.xargs(files, 'add', quiet=True) + return files + + def tidy_dirs(self, names): + deleted = [] + for d in sorted(self.dirs_of(names), reverse=True): + wd = self.wjoin(d) + if os.listdir(wd) == '.svn': + self.run0('delete', d) + deleted.append(d) + return deleted + + def addchild(self, parent, child): + self.childmap[parent] = child + + def revid(self, rev): + return u"svn:%s@%s" % (self.uuid, rev) + + def putcommit(self, files, copies, parents, commit, source, revmap): + # Apply changes to working copy + for f, v in files: + try: + data = source.getfile(f, v) + except IOError: + self.delete.append(f) + else: + e = source.getmode(f, v) + self.putfile(f, e, data) + if f in copies: + self.copies.append([copies[f], f]) + files = [f[0] for f in files] + + for parent in parents: + try: + return self.revid(self.childmap[parent]) + except KeyError: + pass + entries = set(self.delete) + files = frozenset(files) + entries.update(self.add_dirs(files.difference(entries))) + if self.copies: + for s, d in self.copies: + self._copyfile(s, d) + self.copies = [] + if self.delete: + self.xargs(self.delete, 'delete') + self.delete = [] + entries.update(self.add_files(files.difference(entries))) + entries.update(self.tidy_dirs(entries)) + if self.delexec: + self.xargs(self.delexec, 'propdel', 'svn:executable') + self.delexec = [] + if self.setexec: + self.xargs(self.setexec, 'propset', 'svn:executable', '*') + self.setexec = [] + + fd, messagefile = tempfile.mkstemp(prefix='hg-convert-') + fp = os.fdopen(fd, 'w') + fp.write(commit.desc) + fp.close() + try: + output = self.run0('commit', + username=util.shortuser(commit.author), + file=messagefile, + encoding='utf-8') + try: + rev = self.commit_re.search(output).group(1) + except AttributeError: + self.ui.warn(_('unexpected svn output:\n')) + self.ui.warn(output) + raise util.Abort(_('unable to cope with svn output')) + if commit.rev: + self.run('propset', 'hg:convert-rev', commit.rev, + revprop=True, revision=rev) + if commit.branch and commit.branch != 'default': + self.run('propset', 'hg:convert-branch', commit.branch, + revprop=True, revision=rev) + for parent in parents: + self.addchild(parent, rev) + return self.revid(rev) + finally: + os.unlink(messagefile) + + def puttags(self, tags): + self.ui.warn(_('XXX TAGS NOT IMPLEMENTED YET\n')) diff --git a/sys/src/cmd/hg/hgext/convert/transport.py b/sys/src/cmd/hg/hgext/convert/transport.py new file mode 100644 index 000000000..0d77cca4d --- /dev/null +++ b/sys/src/cmd/hg/hgext/convert/transport.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- + +# Copyright (C) 2007 Daniel Holth +# This is a stripped-down version of the original bzr-svn transport.py, +# Copyright (C) 2006 Jelmer Vernooij + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from svn.core import SubversionException, Pool +import svn.ra +import svn.client +import svn.core + +# Some older versions of the Python bindings need to be +# explicitly initialized. But what we want to do probably +# won't work worth a darn against those libraries anyway! +svn.ra.initialize() + +svn_config = svn.core.svn_config_get_config(None) + + +def _create_auth_baton(pool): + """Create a Subversion authentication baton. """ + import svn.client + # Give the client context baton a suite of authentication + # providers.h + providers = [ + svn.client.get_simple_provider(pool), + svn.client.get_username_provider(pool), + svn.client.get_ssl_client_cert_file_provider(pool), + svn.client.get_ssl_client_cert_pw_file_provider(pool), + svn.client.get_ssl_server_trust_file_provider(pool), + ] + # Platform-dependant authentication methods + getprovider = getattr(svn.core, 'svn_auth_get_platform_specific_provider', + None) + if getprovider: + # Available in svn >= 1.6 + for name in ('gnome_keyring', 'keychain', 'kwallet', 'windows'): + for type in ('simple', 'ssl_client_cert_pw', 'ssl_server_trust'): + p = getprovider(name, type, pool) + if p: + providers.append(p) + else: + if hasattr(svn.client, 'get_windows_simple_provider'): + providers.append(svn.client.get_windows_simple_provider(pool)) + + return svn.core.svn_auth_open(providers, pool) + +class NotBranchError(SubversionException): + pass + +class SvnRaTransport(object): + """ + Open an ra connection to a Subversion repository. + """ + def __init__(self, url="", ra=None): + self.pool = Pool() + self.svn_url = url + self.username = '' + self.password = '' + + # Only Subversion 1.4 has reparent() + if ra is None or not hasattr(svn.ra, 'reparent'): + self.client = svn.client.create_context(self.pool) + ab = _create_auth_baton(self.pool) + if False: + svn.core.svn_auth_set_parameter( + ab, svn.core.SVN_AUTH_PARAM_DEFAULT_USERNAME, self.username) + svn.core.svn_auth_set_parameter( + ab, svn.core.SVN_AUTH_PARAM_DEFAULT_PASSWORD, self.password) + self.client.auth_baton = ab + self.client.config = svn_config + try: + self.ra = svn.client.open_ra_session( + self.svn_url.encode('utf8'), + self.client, self.pool) + except SubversionException, (inst, num): + if num in (svn.core.SVN_ERR_RA_ILLEGAL_URL, + svn.core.SVN_ERR_RA_LOCAL_REPOS_OPEN_FAILED, + svn.core.SVN_ERR_BAD_URL): + raise NotBranchError(url) + raise + else: + self.ra = ra + svn.ra.reparent(self.ra, self.svn_url.encode('utf8')) + + class Reporter(object): + def __init__(self, (reporter, report_baton)): + self._reporter = reporter + self._baton = report_baton + + def set_path(self, path, revnum, start_empty, lock_token, pool=None): + svn.ra.reporter2_invoke_set_path(self._reporter, self._baton, + path, revnum, start_empty, lock_token, pool) + + def delete_path(self, path, pool=None): + svn.ra.reporter2_invoke_delete_path(self._reporter, self._baton, + path, pool) + + def link_path(self, path, url, revision, start_empty, lock_token, + pool=None): + svn.ra.reporter2_invoke_link_path(self._reporter, self._baton, + path, url, revision, start_empty, lock_token, + pool) + + def finish_report(self, pool=None): + svn.ra.reporter2_invoke_finish_report(self._reporter, + self._baton, pool) + + def abort_report(self, pool=None): + svn.ra.reporter2_invoke_abort_report(self._reporter, + self._baton, pool) + + def do_update(self, revnum, path, *args, **kwargs): + return self.Reporter(svn.ra.do_update(self.ra, revnum, path, *args, **kwargs)) diff --git a/sys/src/cmd/hg/hgext/extdiff.py b/sys/src/cmd/hg/hgext/extdiff.py new file mode 100644 index 000000000..56e29f4df --- /dev/null +++ b/sys/src/cmd/hg/hgext/extdiff.py @@ -0,0 +1,228 @@ +# extdiff.py - external diff program support for mercurial +# +# Copyright 2006 Vadim Gelfer +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''command to allow external programs to compare revisions + +The extdiff Mercurial extension allows you to use external programs +to compare revisions, or revision with working directory. The external +diff programs are called with a configurable set of options and two +non-option arguments: paths to directories containing snapshots of +files to compare. + +The extdiff extension also allows to configure new diff commands, so +you do not need to type "hg extdiff -p kdiff3" always. :: + + [extdiff] + # add new command that runs GNU diff(1) in 'context diff' mode + cdiff = gdiff -Nprc5 + ## or the old way: + #cmd.cdiff = gdiff + #opts.cdiff = -Nprc5 + + # add new command called vdiff, runs kdiff3 + vdiff = kdiff3 + + # add new command called meld, runs meld (no need to name twice) + meld = + + # add new command called vimdiff, runs gvimdiff with DirDiff plugin + # (see http://www.vim.org/scripts/script.php?script_id=102) Non + # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in + # your .vimrc + vimdiff = gvim -f '+next' '+execute "DirDiff" argv(0) argv(1)' + +You can use -I/-X and list of file or directory names like normal "hg +diff" command. The extdiff extension makes snapshots of only needed +files, so running the external diff program will actually be pretty +fast (at least faster than having to compare the entire tree). +''' + +from mercurial.i18n import _ +from mercurial.node import short +from mercurial import cmdutil, util, commands +import os, shlex, shutil, tempfile + +def snapshot(ui, repo, files, node, tmproot): + '''snapshot files as of some revision + if not using snapshot, -I/-X does not work and recursive diff + in tools like kdiff3 and meld displays too many files.''' + dirname = os.path.basename(repo.root) + if dirname == "": + dirname = "root" + if node is not None: + dirname = '%s.%s' % (dirname, short(node)) + base = os.path.join(tmproot, dirname) + os.mkdir(base) + if node is not None: + ui.note(_('making snapshot of %d files from rev %s\n') % + (len(files), short(node))) + else: + ui.note(_('making snapshot of %d files from working directory\n') % + (len(files))) + wopener = util.opener(base) + fns_and_mtime = [] + ctx = repo[node] + for fn in files: + wfn = util.pconvert(fn) + if not wfn in ctx: + # skipping new file after a merge ? + continue + ui.note(' %s\n' % wfn) + dest = os.path.join(base, wfn) + fctx = ctx[wfn] + data = repo.wwritedata(wfn, fctx.data()) + if 'l' in fctx.flags(): + wopener.symlink(data, wfn) + else: + wopener(wfn, 'w').write(data) + if 'x' in fctx.flags(): + util.set_flags(dest, False, True) + if node is None: + fns_and_mtime.append((dest, repo.wjoin(fn), os.path.getmtime(dest))) + return dirname, fns_and_mtime + +def dodiff(ui, repo, diffcmd, diffopts, pats, opts): + '''Do the actuall diff: + + - copy to a temp structure if diffing 2 internal revisions + - copy to a temp structure if diffing working revision with + another one and more than 1 file is changed + - just invoke the diff for a single file in the working dir + ''' + + revs = opts.get('rev') + change = opts.get('change') + + if revs and change: + msg = _('cannot specify --rev and --change at the same time') + raise util.Abort(msg) + elif change: + node2 = repo.lookup(change) + node1 = repo[node2].parents()[0].node() + else: + node1, node2 = cmdutil.revpair(repo, revs) + + matcher = cmdutil.match(repo, pats, opts) + modified, added, removed = repo.status(node1, node2, matcher)[:3] + if not (modified or added or removed): + return 0 + + tmproot = tempfile.mkdtemp(prefix='extdiff.') + dir2root = '' + try: + # Always make a copy of node1 + dir1 = snapshot(ui, repo, modified + removed, node1, tmproot)[0] + changes = len(modified) + len(removed) + len(added) + + # If node2 in not the wc or there is >1 change, copy it + if node2 or changes > 1: + dir2, fns_and_mtime = snapshot(ui, repo, modified + added, node2, tmproot) + else: + # This lets the diff tool open the changed file directly + dir2 = '' + dir2root = repo.root + fns_and_mtime = [] + + # If only one change, diff the files instead of the directories + if changes == 1 : + if len(modified): + dir1 = os.path.join(dir1, util.localpath(modified[0])) + dir2 = os.path.join(dir2root, dir2, util.localpath(modified[0])) + elif len(removed) : + dir1 = os.path.join(dir1, util.localpath(removed[0])) + dir2 = os.devnull + else: + dir1 = os.devnull + dir2 = os.path.join(dir2root, dir2, util.localpath(added[0])) + + cmdline = ('%s %s %s %s' % + (util.shellquote(diffcmd), ' '.join(diffopts), + util.shellquote(dir1), util.shellquote(dir2))) + ui.debug(_('running %r in %s\n') % (cmdline, tmproot)) + util.system(cmdline, cwd=tmproot) + + for copy_fn, working_fn, mtime in fns_and_mtime: + if os.path.getmtime(copy_fn) != mtime: + ui.debug(_('file changed while diffing. ' + 'Overwriting: %s (src: %s)\n') % (working_fn, copy_fn)) + util.copyfile(copy_fn, working_fn) + + return 1 + finally: + ui.note(_('cleaning up temp directory\n')) + shutil.rmtree(tmproot) + +def extdiff(ui, repo, *pats, **opts): + '''use external program to diff repository (or selected files) + + Show differences between revisions for the specified files, using + an external program. The default program used is diff, with + default options "-Npru". + + To select a different program, use the -p/--program option. The + program will be passed the names of two directories to compare. To + pass additional options to the program, use -o/--option. These + will be passed before the names of the directories to compare. + + When two revision arguments are given, then changes are shown + between those revisions. If only one revision is specified then + that revision is compared to the working directory, and, when no + revisions are specified, the working directory files are compared + to its parent.''' + program = opts['program'] or 'diff' + if opts['program']: + option = opts['option'] + else: + option = opts['option'] or ['-Npru'] + return dodiff(ui, repo, program, option, pats, opts) + +cmdtable = { + "extdiff": + (extdiff, + [('p', 'program', '', _('comparison program to run')), + ('o', 'option', [], _('pass option to comparison program')), + ('r', 'rev', [], _('revision')), + ('c', 'change', '', _('change made by revision')), + ] + commands.walkopts, + _('hg extdiff [OPT]... [FILE]...')), + } + +def uisetup(ui): + for cmd, path in ui.configitems('extdiff'): + if cmd.startswith('cmd.'): + cmd = cmd[4:] + if not path: path = cmd + diffopts = ui.config('extdiff', 'opts.' + cmd, '') + diffopts = diffopts and [diffopts] or [] + elif cmd.startswith('opts.'): + continue + else: + # command = path opts + if path: + diffopts = shlex.split(path) + path = diffopts.pop(0) + else: + path, diffopts = cmd, [] + def save(cmd, path, diffopts): + '''use closure to save diff command to use''' + def mydiff(ui, repo, *pats, **opts): + return dodiff(ui, repo, path, diffopts, pats, opts) + mydiff.__doc__ = _('''\ +use %(path)s to diff repository (or selected files) + + Show differences between revisions for the specified files, using the + %(path)s program. + + When two revision arguments are given, then changes are shown between + those revisions. If only one revision is specified then that revision is + compared to the working directory, and, when no revisions are specified, + the working directory files are compared to its parent.\ +''') % dict(path=util.uirepr(path)) + return mydiff + cmdtable[cmd] = (save(cmd, path, diffopts), + cmdtable['extdiff'][1][1:], + _('hg %s [OPTION]... [FILE]...') % cmd) diff --git a/sys/src/cmd/hg/hgext/fetch.py b/sys/src/cmd/hg/hgext/fetch.py new file mode 100644 index 000000000..05cd3fcc3 --- /dev/null +++ b/sys/src/cmd/hg/hgext/fetch.py @@ -0,0 +1,148 @@ +# fetch.py - pull and merge remote changes +# +# Copyright 2006 Vadim Gelfer +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''pull, update and merge in one command''' + +from mercurial.i18n import _ +from mercurial.node import nullid, short +from mercurial import commands, cmdutil, hg, util, url, error +from mercurial.lock import release + +def fetch(ui, repo, source='default', **opts): + '''pull changes from a remote repository, merge new changes if needed. + + This finds all changes from the repository at the specified path + or URL and adds them to the local repository. + + If the pulled changes add a new branch head, the head is + automatically merged, and the result of the merge is committed. + Otherwise, the working directory is updated to include the new + changes. + + When a merge occurs, the newly pulled changes are assumed to be + "authoritative". The head of the new changes is used as the first + parent, with local changes as the second. To switch the merge + order, use --switch-parent. + + See 'hg help dates' for a list of formats valid for -d/--date. + ''' + + date = opts.get('date') + if date: + opts['date'] = util.parsedate(date) + + parent, p2 = repo.dirstate.parents() + branch = repo.dirstate.branch() + branchnode = repo.branchtags().get(branch) + if parent != branchnode: + raise util.Abort(_('working dir not at branch tip ' + '(use "hg update" to check out branch tip)')) + + if p2 != nullid: + raise util.Abort(_('outstanding uncommitted merge')) + + wlock = lock = None + try: + wlock = repo.wlock() + lock = repo.lock() + mod, add, rem, del_ = repo.status()[:4] + + if mod or add or rem: + raise util.Abort(_('outstanding uncommitted changes')) + if del_: + raise util.Abort(_('working directory is missing some files')) + bheads = repo.branchheads(branch) + bheads = [head for head in bheads if len(repo[head].children()) == 0] + if len(bheads) > 1: + raise util.Abort(_('multiple heads in this branch ' + '(use "hg heads ." and "hg merge" to merge)')) + + other = hg.repository(cmdutil.remoteui(repo, opts), + ui.expandpath(source)) + ui.status(_('pulling from %s\n') % + url.hidepassword(ui.expandpath(source))) + revs = None + if opts['rev']: + try: + revs = [other.lookup(rev) for rev in opts['rev']] + except error.CapabilityError: + err = _("Other repository doesn't support revision lookup, " + "so a rev cannot be specified.") + raise util.Abort(err) + + # Are there any changes at all? + modheads = repo.pull(other, heads=revs) + if modheads == 0: + return 0 + + # Is this a simple fast-forward along the current branch? + newheads = repo.branchheads(branch) + newheads = [head for head in newheads if len(repo[head].children()) == 0] + newchildren = repo.changelog.nodesbetween([parent], newheads)[2] + if len(newheads) == 1: + if newchildren[0] != parent: + return hg.clean(repo, newchildren[0]) + else: + return + + # Are there more than one additional branch heads? + newchildren = [n for n in newchildren if n != parent] + newparent = parent + if newchildren: + newparent = newchildren[0] + hg.clean(repo, newparent) + newheads = [n for n in newheads if n != newparent] + if len(newheads) > 1: + ui.status(_('not merging with %d other new branch heads ' + '(use "hg heads ." and "hg merge" to merge them)\n') % + (len(newheads) - 1)) + return + + # Otherwise, let's merge. + err = False + if newheads: + # By default, we consider the repository we're pulling + # *from* as authoritative, so we merge our changes into + # theirs. + if opts['switch_parent']: + firstparent, secondparent = newparent, newheads[0] + else: + firstparent, secondparent = newheads[0], newparent + ui.status(_('updating to %d:%s\n') % + (repo.changelog.rev(firstparent), + short(firstparent))) + hg.clean(repo, firstparent) + ui.status(_('merging with %d:%s\n') % + (repo.changelog.rev(secondparent), short(secondparent))) + err = hg.merge(repo, secondparent, remind=False) + + if not err: + # we don't translate commit messages + message = (cmdutil.logmessage(opts) or + ('Automated merge with %s' % + url.removeauth(other.url()))) + editor = cmdutil.commiteditor + if opts.get('force_editor') or opts.get('edit'): + editor = cmdutil.commitforceeditor + n = repo.commit(message, opts['user'], opts['date'], editor=editor) + ui.status(_('new changeset %d:%s merges remote changes ' + 'with local\n') % (repo.changelog.rev(n), + short(n))) + + finally: + release(lock, wlock) + +cmdtable = { + 'fetch': + (fetch, + [('r', 'rev', [], _('a specific revision you would like to pull')), + ('e', 'edit', None, _('edit commit message')), + ('', 'force-editor', None, _('edit commit message (DEPRECATED)')), + ('', 'switch-parent', None, _('switch parents when merging')), + ] + commands.commitopts + commands.commitopts2 + commands.remoteopts, + _('hg fetch [SOURCE]')), +} diff --git a/sys/src/cmd/hg/hgext/gpg.py b/sys/src/cmd/hg/hgext/gpg.py new file mode 100644 index 000000000..4a2f07d8e --- /dev/null +++ b/sys/src/cmd/hg/hgext/gpg.py @@ -0,0 +1,284 @@ +# Copyright 2005, 2006 Benoit Boissinot +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''commands to sign and verify changesets''' + +import os, tempfile, binascii +from mercurial import util, commands, match +from mercurial import node as hgnode +from mercurial.i18n import _ + +class gpg(object): + def __init__(self, path, key=None): + self.path = path + self.key = (key and " --local-user \"%s\"" % key) or "" + + def sign(self, data): + gpgcmd = "%s --sign --detach-sign%s" % (self.path, self.key) + return util.filter(data, gpgcmd) + + def verify(self, data, sig): + """ returns of the good and bad signatures""" + sigfile = datafile = None + try: + # create temporary files + fd, sigfile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".sig") + fp = os.fdopen(fd, 'wb') + fp.write(sig) + fp.close() + fd, datafile = tempfile.mkstemp(prefix="hg-gpg-", suffix=".txt") + fp = os.fdopen(fd, 'wb') + fp.write(data) + fp.close() + gpgcmd = ("%s --logger-fd 1 --status-fd 1 --verify " + "\"%s\" \"%s\"" % (self.path, sigfile, datafile)) + ret = util.filter("", gpgcmd) + finally: + for f in (sigfile, datafile): + try: + if f: os.unlink(f) + except: pass + keys = [] + key, fingerprint = None, None + err = "" + for l in ret.splitlines(): + # see DETAILS in the gnupg documentation + # filter the logger output + if not l.startswith("[GNUPG:]"): + continue + l = l[9:] + if l.startswith("ERRSIG"): + err = _("error while verifying signature") + break + elif l.startswith("VALIDSIG"): + # fingerprint of the primary key + fingerprint = l.split()[10] + elif (l.startswith("GOODSIG") or + l.startswith("EXPSIG") or + l.startswith("EXPKEYSIG") or + l.startswith("BADSIG")): + if key is not None: + keys.append(key + [fingerprint]) + key = l.split(" ", 2) + fingerprint = None + if err: + return err, [] + if key is not None: + keys.append(key + [fingerprint]) + return err, keys + +def newgpg(ui, **opts): + """create a new gpg instance""" + gpgpath = ui.config("gpg", "cmd", "gpg") + gpgkey = opts.get('key') + if not gpgkey: + gpgkey = ui.config("gpg", "key", None) + return gpg(gpgpath, gpgkey) + +def sigwalk(repo): + """ + walk over every sigs, yields a couple + ((node, version, sig), (filename, linenumber)) + """ + def parsefile(fileiter, context): + ln = 1 + for l in fileiter: + if not l: + continue + yield (l.split(" ", 2), (context, ln)) + ln +=1 + + # read the heads + fl = repo.file(".hgsigs") + for r in reversed(fl.heads()): + fn = ".hgsigs|%s" % hgnode.short(r) + for item in parsefile(fl.read(r).splitlines(), fn): + yield item + try: + # read local signatures + fn = "localsigs" + for item in parsefile(repo.opener(fn), fn): + yield item + except IOError: + pass + +def getkeys(ui, repo, mygpg, sigdata, context): + """get the keys who signed a data""" + fn, ln = context + node, version, sig = sigdata + prefix = "%s:%d" % (fn, ln) + node = hgnode.bin(node) + + data = node2txt(repo, node, version) + sig = binascii.a2b_base64(sig) + err, keys = mygpg.verify(data, sig) + if err: + ui.warn("%s:%d %s\n" % (fn, ln , err)) + return None + + validkeys = [] + # warn for expired key and/or sigs + for key in keys: + if key[0] == "BADSIG": + ui.write(_("%s Bad signature from \"%s\"\n") % (prefix, key[2])) + continue + if key[0] == "EXPSIG": + ui.write(_("%s Note: Signature has expired" + " (signed by: \"%s\")\n") % (prefix, key[2])) + elif key[0] == "EXPKEYSIG": + ui.write(_("%s Note: This key has expired" + " (signed by: \"%s\")\n") % (prefix, key[2])) + validkeys.append((key[1], key[2], key[3])) + return validkeys + +def sigs(ui, repo): + """list signed changesets""" + mygpg = newgpg(ui) + revs = {} + + for data, context in sigwalk(repo): + node, version, sig = data + fn, ln = context + try: + n = repo.lookup(node) + except KeyError: + ui.warn(_("%s:%d node does not exist\n") % (fn, ln)) + continue + r = repo.changelog.rev(n) + keys = getkeys(ui, repo, mygpg, data, context) + if not keys: + continue + revs.setdefault(r, []) + revs[r].extend(keys) + for rev in sorted(revs, reverse=True): + for k in revs[rev]: + r = "%5d:%s" % (rev, hgnode.hex(repo.changelog.node(rev))) + ui.write("%-30s %s\n" % (keystr(ui, k), r)) + +def check(ui, repo, rev): + """verify all the signatures there may be for a particular revision""" + mygpg = newgpg(ui) + rev = repo.lookup(rev) + hexrev = hgnode.hex(rev) + keys = [] + + for data, context in sigwalk(repo): + node, version, sig = data + if node == hexrev: + k = getkeys(ui, repo, mygpg, data, context) + if k: + keys.extend(k) + + if not keys: + ui.write(_("No valid signature for %s\n") % hgnode.short(rev)) + return + + # print summary + ui.write("%s is signed by:\n" % hgnode.short(rev)) + for key in keys: + ui.write(" %s\n" % keystr(ui, key)) + +def keystr(ui, key): + """associate a string to a key (username, comment)""" + keyid, user, fingerprint = key + comment = ui.config("gpg", fingerprint, None) + if comment: + return "%s (%s)" % (user, comment) + else: + return user + +def sign(ui, repo, *revs, **opts): + """add a signature for the current or given revision + + If no revision is given, the parent of the working directory is used, + or tip if no revision is checked out. + + See 'hg help dates' for a list of formats valid for -d/--date. + """ + + mygpg = newgpg(ui, **opts) + sigver = "0" + sigmessage = "" + + date = opts.get('date') + if date: + opts['date'] = util.parsedate(date) + + if revs: + nodes = [repo.lookup(n) for n in revs] + else: + nodes = [node for node in repo.dirstate.parents() + if node != hgnode.nullid] + if len(nodes) > 1: + raise util.Abort(_('uncommitted merge - please provide a ' + 'specific revision')) + if not nodes: + nodes = [repo.changelog.tip()] + + for n in nodes: + hexnode = hgnode.hex(n) + ui.write("Signing %d:%s\n" % (repo.changelog.rev(n), + hgnode.short(n))) + # build data + data = node2txt(repo, n, sigver) + sig = mygpg.sign(data) + if not sig: + raise util.Abort(_("Error while signing")) + sig = binascii.b2a_base64(sig) + sig = sig.replace("\n", "") + sigmessage += "%s %s %s\n" % (hexnode, sigver, sig) + + # write it + if opts['local']: + repo.opener("localsigs", "ab").write(sigmessage) + return + + for x in repo.status(unknown=True)[:5]: + if ".hgsigs" in x and not opts["force"]: + raise util.Abort(_("working copy of .hgsigs is changed " + "(please commit .hgsigs manually " + "or use --force)")) + + repo.wfile(".hgsigs", "ab").write(sigmessage) + + if '.hgsigs' not in repo.dirstate: + repo.add([".hgsigs"]) + + if opts["no_commit"]: + return + + message = opts['message'] + if not message: + # we don't translate commit messages + message = "\n".join(["Added signature for changeset %s" + % hgnode.short(n) + for n in nodes]) + try: + m = match.exact(repo.root, '', ['.hgsigs']) + repo.commit(message, opts['user'], opts['date'], match=m) + except ValueError, inst: + raise util.Abort(str(inst)) + +def node2txt(repo, node, ver): + """map a manifest into some text""" + if ver == "0": + return "%s\n" % hgnode.hex(node) + else: + raise util.Abort(_("unknown signature version")) + +cmdtable = { + "sign": + (sign, + [('l', 'local', None, _('make the signature local')), + ('f', 'force', None, _('sign even if the sigfile is modified')), + ('', 'no-commit', None, _('do not commit the sigfile after signing')), + ('k', 'key', '', _('the key id to sign with')), + ('m', 'message', '', _('commit message')), + ] + commands.commitopts2, + _('hg sign [OPTION]... [REVISION]...')), + "sigcheck": (check, [], _('hg sigcheck REVISION')), + "sigs": (sigs, [], _('hg sigs')), +} + diff --git a/sys/src/cmd/hg/hgext/graphlog.py b/sys/src/cmd/hg/hgext/graphlog.py new file mode 100644 index 000000000..d77edf931 --- /dev/null +++ b/sys/src/cmd/hg/hgext/graphlog.py @@ -0,0 +1,378 @@ +# ASCII graph log extension for Mercurial +# +# Copyright 2007 Joel Rosdahl +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''command to view revision graphs from a shell + +This extension adds a --graph option to the incoming, outgoing and log +commands. When this options is given, an ASCII representation of the +revision graph is also shown. +''' + +import os, sys +from mercurial.cmdutil import revrange, show_changeset +from mercurial.commands import templateopts +from mercurial.i18n import _ +from mercurial.node import nullrev +from mercurial import bundlerepo, changegroup, cmdutil, commands, extensions +from mercurial import hg, url, util, graphmod + +ASCIIDATA = 'ASC' + +def asciiformat(ui, repo, revdag, opts, parentrepo=None): + """formats a changelog DAG walk for ASCII output""" + if parentrepo is None: + parentrepo = repo + showparents = [ctx.node() for ctx in parentrepo[None].parents()] + displayer = show_changeset(ui, repo, opts, buffered=True) + for (id, type, ctx, parentids) in revdag: + if type != graphmod.CHANGESET: + continue + displayer.show(ctx) + lines = displayer.hunk.pop(ctx.rev()).split('\n')[:-1] + char = ctx.node() in showparents and '@' or 'o' + yield (id, ASCIIDATA, (char, lines), parentids) + +def asciiedges(nodes): + """adds edge info to changelog DAG walk suitable for ascii()""" + seen = [] + for node, type, data, parents in nodes: + if node not in seen: + seen.append(node) + nodeidx = seen.index(node) + + knownparents = [] + newparents = [] + for parent in parents: + if parent in seen: + knownparents.append(parent) + else: + newparents.append(parent) + + ncols = len(seen) + nextseen = seen[:] + nextseen[nodeidx:nodeidx + 1] = newparents + edges = [(nodeidx, nextseen.index(p)) for p in knownparents] + + if len(newparents) > 0: + edges.append((nodeidx, nodeidx)) + if len(newparents) > 1: + edges.append((nodeidx, nodeidx + 1)) + nmorecols = len(nextseen) - ncols + seen = nextseen + yield (nodeidx, type, data, edges, ncols, nmorecols) + +def fix_long_right_edges(edges): + for (i, (start, end)) in enumerate(edges): + if end > start: + edges[i] = (start, end + 1) + +def get_nodeline_edges_tail( + node_index, p_node_index, n_columns, n_columns_diff, p_diff, fix_tail): + if fix_tail and n_columns_diff == p_diff and n_columns_diff != 0: + # Still going in the same non-vertical direction. + if n_columns_diff == -1: + start = max(node_index + 1, p_node_index) + tail = ["|", " "] * (start - node_index - 1) + tail.extend(["/", " "] * (n_columns - start)) + return tail + else: + return ["\\", " "] * (n_columns - node_index - 1) + else: + return ["|", " "] * (n_columns - node_index - 1) + +def draw_edges(edges, nodeline, interline): + for (start, end) in edges: + if start == end + 1: + interline[2 * end + 1] = "/" + elif start == end - 1: + interline[2 * start + 1] = "\\" + elif start == end: + interline[2 * start] = "|" + else: + nodeline[2 * end] = "+" + if start > end: + (start, end) = (end, start) + for i in range(2 * start + 1, 2 * end): + if nodeline[i] != "+": + nodeline[i] = "-" + +def get_padding_line(ni, n_columns, edges): + line = [] + line.extend(["|", " "] * ni) + if (ni, ni - 1) in edges or (ni, ni) in edges: + # (ni, ni - 1) (ni, ni) + # | | | | | | | | + # +---o | | o---+ + # | | c | | c | | + # | |/ / | |/ / + # | | | | | | + c = "|" + else: + c = " " + line.extend([c, " "]) + line.extend(["|", " "] * (n_columns - ni - 1)) + return line + +def ascii(ui, dag): + """prints an ASCII graph of the DAG + + dag is a generator that emits tuples with the following elements: + + - Column of the current node in the set of ongoing edges. + - Type indicator of node data == ASCIIDATA. + - Payload: (char, lines): + - Character to use as node's symbol. + - List of lines to display as the node's text. + - Edges; a list of (col, next_col) indicating the edges between + the current node and its parents. + - Number of columns (ongoing edges) in the current revision. + - The difference between the number of columns (ongoing edges) + in the next revision and the number of columns (ongoing edges) + in the current revision. That is: -1 means one column removed; + 0 means no columns added or removed; 1 means one column added. + """ + prev_n_columns_diff = 0 + prev_node_index = 0 + for (node_index, type, (node_ch, node_lines), edges, n_columns, n_columns_diff) in dag: + + assert -2 < n_columns_diff < 2 + if n_columns_diff == -1: + # Transform + # + # | | | | | | + # o | | into o---+ + # |X / |/ / + # | | | | + fix_long_right_edges(edges) + + # add_padding_line says whether to rewrite + # + # | | | | | | | | + # | o---+ into | o---+ + # | / / | | | # <--- padding line + # o | | | / / + # o | | + add_padding_line = (len(node_lines) > 2 and + n_columns_diff == -1 and + [x for (x, y) in edges if x + 1 < y]) + + # fix_nodeline_tail says whether to rewrite + # + # | | o | | | | o | | + # | | |/ / | | |/ / + # | o | | into | o / / # <--- fixed nodeline tail + # | |/ / | |/ / + # o | | o | | + fix_nodeline_tail = len(node_lines) <= 2 and not add_padding_line + + # nodeline is the line containing the node character (typically o) + nodeline = ["|", " "] * node_index + nodeline.extend([node_ch, " "]) + + nodeline.extend( + get_nodeline_edges_tail( + node_index, prev_node_index, n_columns, n_columns_diff, + prev_n_columns_diff, fix_nodeline_tail)) + + # shift_interline is the line containing the non-vertical + # edges between this entry and the next + shift_interline = ["|", " "] * node_index + if n_columns_diff == -1: + n_spaces = 1 + edge_ch = "/" + elif n_columns_diff == 0: + n_spaces = 2 + edge_ch = "|" + else: + n_spaces = 3 + edge_ch = "\\" + shift_interline.extend(n_spaces * [" "]) + shift_interline.extend([edge_ch, " "] * (n_columns - node_index - 1)) + + # draw edges from the current node to its parents + draw_edges(edges, nodeline, shift_interline) + + # lines is the list of all graph lines to print + lines = [nodeline] + if add_padding_line: + lines.append(get_padding_line(node_index, n_columns, edges)) + lines.append(shift_interline) + + # make sure that there are as many graph lines as there are + # log strings + while len(node_lines) < len(lines): + node_lines.append("") + if len(lines) < len(node_lines): + extra_interline = ["|", " "] * (n_columns + n_columns_diff) + while len(lines) < len(node_lines): + lines.append(extra_interline) + + # print lines + indentation_level = max(n_columns, n_columns + n_columns_diff) + for (line, logstr) in zip(lines, node_lines): + ln = "%-*s %s" % (2 * indentation_level, "".join(line), logstr) + ui.write(ln.rstrip() + '\n') + + # ... and start over + prev_node_index = node_index + prev_n_columns_diff = n_columns_diff + +def get_revs(repo, rev_opt): + if rev_opt: + revs = revrange(repo, rev_opt) + return (max(revs), min(revs)) + else: + return (len(repo) - 1, 0) + +def check_unsupported_flags(opts): + for op in ["follow", "follow_first", "date", "copies", "keyword", "remove", + "only_merges", "user", "only_branch", "prune", "newest_first", + "no_merges", "include", "exclude"]: + if op in opts and opts[op]: + raise util.Abort(_("--graph option is incompatible with --%s") % op) + +def graphlog(ui, repo, path=None, **opts): + """show revision history alongside an ASCII revision graph + + Print a revision history alongside a revision graph drawn with + ASCII characters. + + Nodes printed as an @ character are parents of the working + directory. + """ + + check_unsupported_flags(opts) + limit = cmdutil.loglimit(opts) + start, stop = get_revs(repo, opts["rev"]) + stop = max(stop, start - limit + 1) + if start == nullrev: + return + + if path: + path = util.canonpath(repo.root, os.getcwd(), path) + if path: # could be reset in canonpath + revdag = graphmod.filerevs(repo, path, start, stop) + else: + revdag = graphmod.revisions(repo, start, stop) + + fmtdag = asciiformat(ui, repo, revdag, opts) + ascii(ui, asciiedges(fmtdag)) + +def graphrevs(repo, nodes, opts): + limit = cmdutil.loglimit(opts) + nodes.reverse() + if limit < sys.maxint: + nodes = nodes[:limit] + return graphmod.nodes(repo, nodes) + +def goutgoing(ui, repo, dest=None, **opts): + """show the outgoing changesets alongside an ASCII revision graph + + Print the outgoing changesets alongside a revision graph drawn with + ASCII characters. + + Nodes printed as an @ character are parents of the working + directory. + """ + + check_unsupported_flags(opts) + dest, revs, checkout = hg.parseurl( + ui.expandpath(dest or 'default-push', dest or 'default'), + opts.get('rev')) + if revs: + revs = [repo.lookup(rev) for rev in revs] + other = hg.repository(cmdutil.remoteui(ui, opts), dest) + ui.status(_('comparing with %s\n') % url.hidepassword(dest)) + o = repo.findoutgoing(other, force=opts.get('force')) + if not o: + ui.status(_("no changes found\n")) + return + + o = repo.changelog.nodesbetween(o, revs)[0] + revdag = graphrevs(repo, o, opts) + fmtdag = asciiformat(ui, repo, revdag, opts) + ascii(ui, asciiedges(fmtdag)) + +def gincoming(ui, repo, source="default", **opts): + """show the incoming changesets alongside an ASCII revision graph + + Print the incoming changesets alongside a revision graph drawn with + ASCII characters. + + Nodes printed as an @ character are parents of the working + directory. + """ + + check_unsupported_flags(opts) + source, revs, checkout = hg.parseurl(ui.expandpath(source), opts.get('rev')) + other = hg.repository(cmdutil.remoteui(repo, opts), source) + ui.status(_('comparing with %s\n') % url.hidepassword(source)) + if revs: + revs = [other.lookup(rev) for rev in revs] + incoming = repo.findincoming(other, heads=revs, force=opts["force"]) + if not incoming: + try: + os.unlink(opts["bundle"]) + except: + pass + ui.status(_("no changes found\n")) + return + + cleanup = None + try: + + fname = opts["bundle"] + if fname or not other.local(): + # create a bundle (uncompressed if other repo is not local) + if revs is None: + cg = other.changegroup(incoming, "incoming") + else: + cg = other.changegroupsubset(incoming, revs, 'incoming') + bundletype = other.local() and "HG10BZ" or "HG10UN" + fname = cleanup = changegroup.writebundle(cg, fname, bundletype) + # keep written bundle? + if opts["bundle"]: + cleanup = None + if not other.local(): + # use the created uncompressed bundlerepo + other = bundlerepo.bundlerepository(ui, repo.root, fname) + + chlist = other.changelog.nodesbetween(incoming, revs)[0] + revdag = graphrevs(other, chlist, opts) + fmtdag = asciiformat(ui, other, revdag, opts, parentrepo=repo) + ascii(ui, asciiedges(fmtdag)) + + finally: + if hasattr(other, 'close'): + other.close() + if cleanup: + os.unlink(cleanup) + +def uisetup(ui): + '''Initialize the extension.''' + _wrapcmd(ui, 'log', commands.table, graphlog) + _wrapcmd(ui, 'incoming', commands.table, gincoming) + _wrapcmd(ui, 'outgoing', commands.table, goutgoing) + +def _wrapcmd(ui, cmd, table, wrapfn): + '''wrap the command''' + def graph(orig, *args, **kwargs): + if kwargs['graph']: + return wrapfn(*args, **kwargs) + return orig(*args, **kwargs) + entry = extensions.wrapcommand(table, cmd, graph) + entry[1].append(('G', 'graph', None, _("show the revision DAG"))) + +cmdtable = { + "glog": + (graphlog, + [('l', 'limit', '', _('limit number of changes displayed')), + ('p', 'patch', False, _('show patch')), + ('r', 'rev', [], _('show the specified revision or range')), + ] + templateopts, + _('hg glog [OPTION]... [FILE]')), +} diff --git a/sys/src/cmd/hg/hgext/hgcia.py b/sys/src/cmd/hg/hgext/hgcia.py new file mode 100644 index 000000000..dfae38919 --- /dev/null +++ b/sys/src/cmd/hg/hgext/hgcia.py @@ -0,0 +1,246 @@ +# Copyright (C) 2007-8 Brendan Cully +# Published under the GNU GPL + +"""hooks for integrating with the CIA.vc notification service + +This is meant to be run as a changegroup or incoming hook. To +configure it, set the following options in your hgrc:: + + [cia] + # your registered CIA user name + user = foo + # the name of the project in CIA + project = foo + # the module (subproject) (optional) + #module = foo + # Append a diffstat to the log message (optional) + #diffstat = False + # Template to use for log messages (optional) + #template = {desc}\\n{baseurl}/rev/{node}-- {diffstat} + # Style to use (optional) + #style = foo + # The URL of the CIA notification service (optional) + # You can use mailto: URLs to send by email, eg + # mailto:cia@cia.vc + # Make sure to set email.from if you do this. + #url = http://cia.vc/ + # print message instead of sending it (optional) + #test = False + + [hooks] + # one of these: + changegroup.cia = python:hgcia.hook + #incoming.cia = python:hgcia.hook + + [web] + # If you want hyperlinks (optional) + baseurl = http://server/path/to/repo +""" + +from mercurial.i18n import _ +from mercurial.node import * +from mercurial import cmdutil, patch, templater, util, mail +import email.Parser + +import xmlrpclib +from xml.sax import saxutils + +socket_timeout = 30 # seconds +try: + # set a timeout for the socket so you don't have to wait so looooong + # when cia.vc is having problems. requires python >= 2.3: + import socket + socket.setdefaulttimeout(socket_timeout) +except: + pass + +HGCIA_VERSION = '0.1' +HGCIA_URL = 'http://hg.kublai.com/mercurial/hgcia' + + +class ciamsg(object): + """ A CIA message """ + def __init__(self, cia, ctx): + self.cia = cia + self.ctx = ctx + self.url = self.cia.url + + def fileelem(self, path, uri, action): + if uri: + uri = ' uri=%s' % saxutils.quoteattr(uri) + return '%s' % ( + uri, saxutils.quoteattr(action), saxutils.escape(path)) + + def fileelems(self): + n = self.ctx.node() + f = self.cia.repo.status(self.ctx.parents()[0].node(), n) + url = self.url or '' + elems = [] + for path in f[0]: + uri = '%s/diff/%s/%s' % (url, short(n), path) + elems.append(self.fileelem(path, url and uri, 'modify')) + for path in f[1]: + # TODO: copy/rename ? + uri = '%s/file/%s/%s' % (url, short(n), path) + elems.append(self.fileelem(path, url and uri, 'add')) + for path in f[2]: + elems.append(self.fileelem(path, '', 'remove')) + + return '\n'.join(elems) + + def sourceelem(self, project, module=None, branch=None): + msg = ['', '%s' % saxutils.escape(project)] + if module: + msg.append('%s' % saxutils.escape(module)) + if branch: + msg.append('%s' % saxutils.escape(branch)) + msg.append('') + + return '\n'.join(msg) + + def diffstat(self): + class patchbuf(object): + def __init__(self): + self.lines = [] + # diffstat is stupid + self.name = 'cia' + def write(self, data): + self.lines.append(data) + def close(self): + pass + + n = self.ctx.node() + pbuf = patchbuf() + patch.export(self.cia.repo, [n], fp=pbuf) + return patch.diffstat(pbuf.lines) or '' + + def logmsg(self): + diffstat = self.cia.diffstat and self.diffstat() or '' + self.cia.ui.pushbuffer() + self.cia.templater.show(self.ctx, changes=self.ctx.changeset(), + url=self.cia.url, diffstat=diffstat) + return self.cia.ui.popbuffer() + + def xml(self): + n = short(self.ctx.node()) + src = self.sourceelem(self.cia.project, module=self.cia.module, + branch=self.ctx.branch()) + # unix timestamp + dt = self.ctx.date() + timestamp = dt[0] + + author = saxutils.escape(self.ctx.user()) + rev = '%d:%s' % (self.ctx.rev(), n) + log = saxutils.escape(self.logmsg()) + + url = self.url and '%s/rev/%s' % (saxutils.escape(self.url), + n) or '' + + msg = """ + + + Mercurial (hgcia) + %s + %s + %s + + %s + + + %s + %s + %s + %s + %s + + + %d + +""" % \ + (HGCIA_VERSION, saxutils.escape(HGCIA_URL), + saxutils.escape(self.cia.user), src, author, rev, log, url, + self.fileelems(), timestamp) + + return msg + + +class hgcia(object): + """ CIA notification class """ + + deftemplate = '{desc}' + dstemplate = '{desc}\n-- \n{diffstat}' + + def __init__(self, ui, repo): + self.ui = ui + self.repo = repo + + self.ciaurl = self.ui.config('cia', 'url', 'http://cia.vc') + self.user = self.ui.config('cia', 'user') + self.project = self.ui.config('cia', 'project') + self.module = self.ui.config('cia', 'module') + self.diffstat = self.ui.configbool('cia', 'diffstat') + self.emailfrom = self.ui.config('email', 'from') + self.dryrun = self.ui.configbool('cia', 'test') + self.url = self.ui.config('web', 'baseurl') + + style = self.ui.config('cia', 'style') + template = self.ui.config('cia', 'template') + if not template: + template = self.diffstat and self.dstemplate or self.deftemplate + template = templater.parsestring(template, quoted=False) + t = cmdutil.changeset_templater(self.ui, self.repo, False, None, + style, False) + t.use_template(template) + self.templater = t + + def sendrpc(self, msg): + srv = xmlrpclib.Server(self.ciaurl) + srv.hub.deliver(msg) + + def sendemail(self, address, data): + p = email.Parser.Parser() + msg = p.parsestr(data) + msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2") + msg['To'] = address + msg['From'] = self.emailfrom + msg['Subject'] = 'DeliverXML' + msg['Content-type'] = 'text/xml' + msgtext = msg.as_string() + + self.ui.status(_('hgcia: sending update to %s\n') % address) + mail.sendmail(self.ui, util.email(self.emailfrom), + [address], msgtext) + + +def hook(ui, repo, hooktype, node=None, url=None, **kwargs): + """ send CIA notification """ + def sendmsg(cia, ctx): + msg = ciamsg(cia, ctx).xml() + if cia.dryrun: + ui.write(msg) + elif cia.ciaurl.startswith('mailto:'): + if not cia.emailfrom: + raise util.Abort(_('email.from must be defined when ' + 'sending by email')) + cia.sendemail(cia.ciaurl[7:], msg) + else: + cia.sendrpc(msg) + + n = bin(node) + cia = hgcia(ui, repo) + if not cia.user: + ui.debug(_('cia: no user specified')) + return + if not cia.project: + ui.debug(_('cia: no project specified')) + return + if hooktype == 'changegroup': + start = repo.changelog.rev(n) + end = len(repo.changelog) + for rev in xrange(start, end): + n = repo.changelog.node(rev) + ctx = repo.changectx(n) + sendmsg(cia, ctx) + else: + ctx = repo.changectx(n) + sendmsg(cia, ctx) diff --git a/sys/src/cmd/hg/hgext/hgk.py b/sys/src/cmd/hg/hgext/hgk.py new file mode 100644 index 000000000..03441ce00 --- /dev/null +++ b/sys/src/cmd/hg/hgext/hgk.py @@ -0,0 +1,347 @@ +# Minimal support for git commands on an hg repository +# +# Copyright 2005, 2006 Chris Mason +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. + +'''browse the repository in a graphical way + +The hgk extension allows browsing the history of a repository in a +graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is not +distributed with Mercurial.) + +hgk consists of two parts: a Tcl script that does the displaying and +querying of information, and an extension to Mercurial named hgk.py, +which provides hooks for hgk to get information. hgk can be found in +the contrib directory, and the extension is shipped in the hgext +repository, and needs to be enabled. + +The hg view command will launch the hgk Tcl script. For this command +to work, hgk must be in your search path. Alternately, you can specify +the path to hgk in your .hgrc file:: + + [hgk] + path=/location/of/hgk + +hgk can make use of the extdiff extension to visualize revisions. +Assuming you had already configured extdiff vdiff command, just add:: + + [hgk] + vdiff=vdiff + +Revisions context menu will now display additional entries to fire +vdiff on hovered and selected revisions. +''' + +import os +from mercurial import commands, util, patch, revlog, cmdutil +from mercurial.node import nullid, nullrev, short +from mercurial.i18n import _ + +def difftree(ui, repo, node1=None, node2=None, *files, **opts): + """diff trees from two commits""" + def __difftree(repo, node1, node2, files=[]): + assert node2 is not None + mmap = repo[node1].manifest() + mmap2 = repo[node2].manifest() + m = cmdutil.match(repo, files) + modified, added, removed = repo.status(node1, node2, m)[:3] + empty = short(nullid) + + for f in modified: + # TODO get file permissions + ui.write(":100664 100664 %s %s M\t%s\t%s\n" % + (short(mmap[f]), short(mmap2[f]), f, f)) + for f in added: + ui.write(":000000 100664 %s %s N\t%s\t%s\n" % + (empty, short(mmap2[f]), f, f)) + for f in removed: + ui.write(":100664 000000 %s %s D\t%s\t%s\n" % + (short(mmap[f]), empty, f, f)) + ## + + while True: + if opts['stdin']: + try: + line = raw_input().split(' ') + node1 = line[0] + if len(line) > 1: + node2 = line[1] + else: + node2 = None + except EOFError: + break + node1 = repo.lookup(node1) + if node2: + node2 = repo.lookup(node2) + else: + node2 = node1 + node1 = repo.changelog.parents(node1)[0] + if opts['patch']: + if opts['pretty']: + catcommit(ui, repo, node2, "") + m = cmdutil.match(repo, files) + chunks = patch.diff(repo, node1, node2, match=m, + opts=patch.diffopts(ui, {'git': True})) + for chunk in chunks: + ui.write(chunk) + else: + __difftree(repo, node1, node2, files=files) + if not opts['stdin']: + break + +def catcommit(ui, repo, n, prefix, ctx=None): + nlprefix = '\n' + prefix; + if ctx is None: + ctx = repo[n] + ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ?? + for p in ctx.parents(): + ui.write("parent %s\n" % p) + + date = ctx.date() + description = ctx.description().replace("\0", "") + lines = description.splitlines() + if lines and lines[-1].startswith('committer:'): + committer = lines[-1].split(': ')[1].rstrip() + else: + committer = ctx.user() + + ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1])) + ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1])) + ui.write("revision %d\n" % ctx.rev()) + ui.write("branch %s\n\n" % ctx.branch()) + + if prefix != "": + ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip())) + else: + ui.write(description + "\n") + if prefix: + ui.write('\0') + +def base(ui, repo, node1, node2): + """output common ancestor information""" + node1 = repo.lookup(node1) + node2 = repo.lookup(node2) + n = repo.changelog.ancestor(node1, node2) + ui.write(short(n) + "\n") + +def catfile(ui, repo, type=None, r=None, **opts): + """cat a specific revision""" + # in stdin mode, every line except the commit is prefixed with two + # spaces. This way the our caller can find the commit without magic + # strings + # + prefix = "" + if opts['stdin']: + try: + (type, r) = raw_input().split(' '); + prefix = " " + except EOFError: + return + + else: + if not type or not r: + ui.warn(_("cat-file: type or revision not supplied\n")) + commands.help_(ui, 'cat-file') + + while r: + if type != "commit": + ui.warn(_("aborting hg cat-file only understands commits\n")) + return 1; + n = repo.lookup(r) + catcommit(ui, repo, n, prefix) + if opts['stdin']: + try: + (type, r) = raw_input().split(' '); + except EOFError: + break + else: + break + +# git rev-tree is a confusing thing. You can supply a number of +# commit sha1s on the command line, and it walks the commit history +# telling you which commits are reachable from the supplied ones via +# a bitmask based on arg position. +# you can specify a commit to stop at by starting the sha1 with ^ +def revtree(ui, args, repo, full="tree", maxnr=0, parents=False): + def chlogwalk(): + count = len(repo) + i = count + l = [0] * 100 + chunk = 100 + while True: + if chunk > i: + chunk = i + i = 0 + else: + i -= chunk + + for x in xrange(chunk): + if i + x >= count: + l[chunk - x:] = [0] * (chunk - x) + break + if full != None: + l[x] = repo[i + x] + l[x].changeset() # force reading + else: + l[x] = 1 + for x in xrange(chunk-1, -1, -1): + if l[x] != 0: + yield (i + x, full != None and l[x] or None) + if i == 0: + break + + # calculate and return the reachability bitmask for sha + def is_reachable(ar, reachable, sha): + if len(ar) == 0: + return 1 + mask = 0 + for i in xrange(len(ar)): + if sha in reachable[i]: + mask |= 1 << i + + return mask + + reachable = [] + stop_sha1 = [] + want_sha1 = [] + count = 0 + + # figure out which commits they are asking for and which ones they + # want us to stop on + for i, arg in enumerate(args): + if arg.startswith('^'): + s = repo.lookup(arg[1:]) + stop_sha1.append(s) + want_sha1.append(s) + elif arg != 'HEAD': + want_sha1.append(repo.lookup(arg)) + + # calculate the graph for the supplied commits + for i, n in enumerate(want_sha1): + reachable.append(set()); + visit = [n]; + reachable[i].add(n) + while visit: + n = visit.pop(0) + if n in stop_sha1: + continue + for p in repo.changelog.parents(n): + if p not in reachable[i]: + reachable[i].add(p) + visit.append(p) + if p in stop_sha1: + continue + + # walk the repository looking for commits that are in our + # reachability graph + for i, ctx in chlogwalk(): + n = repo.changelog.node(i) + mask = is_reachable(want_sha1, reachable, n) + if mask: + parentstr = "" + if parents: + pp = repo.changelog.parents(n) + if pp[0] != nullid: + parentstr += " " + short(pp[0]) + if pp[1] != nullid: + parentstr += " " + short(pp[1]) + if not full: + ui.write("%s%s\n" % (short(n), parentstr)) + elif full == "commit": + ui.write("%s%s\n" % (short(n), parentstr)) + catcommit(ui, repo, n, ' ', ctx) + else: + (p1, p2) = repo.changelog.parents(n) + (h, h1, h2) = map(short, (n, p1, p2)) + (i1, i2) = map(repo.changelog.rev, (p1, p2)) + + date = ctx.date()[0] + ui.write("%s %s:%s" % (date, h, mask)) + mask = is_reachable(want_sha1, reachable, p1) + if i1 != nullrev and mask > 0: + ui.write("%s:%s " % (h1, mask)), + mask = is_reachable(want_sha1, reachable, p2) + if i2 != nullrev and mask > 0: + ui.write("%s:%s " % (h2, mask)) + ui.write("\n") + if maxnr and count >= maxnr: + break + count += 1 + +def revparse(ui, repo, *revs, **opts): + """parse given revisions""" + def revstr(rev): + if rev == 'HEAD': + rev = 'tip' + return revlog.hex(repo.lookup(rev)) + + for r in revs: + revrange = r.split(':', 1) + ui.write('%s\n' % revstr(revrange[0])) + if len(revrange) == 2: + ui.write('^%s\n' % revstr(revrange[1])) + +# git rev-list tries to order things by date, and has the ability to stop +# at a given commit without walking the whole repo. TODO add the stop +# parameter +def revlist(ui, repo, *revs, **opts): + """print revisions""" + if opts['header']: + full = "commit" + else: + full = None + copy = [x for x in revs] + revtree(ui, copy, repo, full, opts['max_count'], opts['parents']) + +def config(ui, repo, **opts): + """print extension options""" + def writeopt(name, value): + ui.write('k=%s\nv=%s\n' % (name, value)) + + writeopt('vdiff', ui.config('hgk', 'vdiff', '')) + + +def view(ui, repo, *etc, **opts): + "start interactive history viewer" + os.chdir(repo.root) + optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v]) + cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc)) + ui.debug(_("running %s\n") % cmd) + util.system(cmd) + +cmdtable = { + "^view": + (view, + [('l', 'limit', '', _('limit number of changes displayed'))], + _('hg view [-l LIMIT] [REVRANGE]')), + "debug-diff-tree": + (difftree, + [('p', 'patch', None, _('generate patch')), + ('r', 'recursive', None, _('recursive')), + ('P', 'pretty', None, _('pretty')), + ('s', 'stdin', None, _('stdin')), + ('C', 'copy', None, _('detect copies')), + ('S', 'search', "", _('search'))], + _('hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...')), + "debug-cat-file": + (catfile, + [('s', 'stdin', None, _('stdin'))], + _('hg debug-cat-file [OPTION]... TYPE FILE')), + "debug-config": + (config, [], _('hg debug-config')), + "debug-merge-base": + (base, [], _('hg debug-merge-base REV REV')), + "debug-rev-parse": + (revparse, + [('', 'default', '', _('ignored'))], + _('hg debug-rev-parse REV')), + "debug-rev-list": + (revlist, + [('H', 'header', None, _('header')), + ('t', 'topo-order', None, _('topo-order')), + ('p', 'parents', None, _('parents')), + ('n', 'max-count', 0, _('max-count'))], + _('hg debug-rev-list [OPTION]... REV...')), +} diff --git a/sys/src/cmd/hg/hgext/highlight/__init__.py b/sys/src/cmd/hg/hgext/highlight/__init__.py new file mode 100644 index 000000000..65efae3c9 --- /dev/null +++ b/sys/src/cmd/hg/hgext/highlight/__init__.py @@ -0,0 +1,60 @@ +# highlight - syntax highlighting in hgweb, based on Pygments +# +# Copyright 2008, 2009 Patrick Mezard and others +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2, incorporated herein by reference. +# +# The original module was split in an interface and an implementation +# file to defer pygments loading and speedup extension setup. + +"""syntax highlighting for hgweb (requires Pygments) + +It depends on the Pygments syntax highlighting library: +http://pygments.org/ + +There is a single configuration option:: + + [web] + pygments_style = + + + +
+

Python Documentation

+ +

+ Release @RELEASE@ +
+ @DATE@ +

+
+ + + + + + + + + + + + + + + + +
+ + + +
+   + + +   + +
+   + + +   + +
+

+ +

+
+ See
About the Python Documentation + for information on suggesting changes. +
+ + diff --git a/sys/src/cmd/python/Doc/html/stdabout.dat b/sys/src/cmd/python/Doc/html/stdabout.dat new file mode 100644 index 000000000..750935490 --- /dev/null +++ b/sys/src/cmd/python/Doc/html/stdabout.dat @@ -0,0 +1,54 @@ +

This document was generated using the + LaTeX2HTML translator. +

+ +

+ LaTeX2HTML is Copyright © + 1993, 1994, 1995, 1996, 1997, Nikos + Drakos, Computer Based Learning Unit, University of + Leeds, and Copyright © 1997, 1998, Ross + Moore, Mathematics Department, Macquarie University, + Sydney. +

+ +

The application of + LaTeX2HTML to the Python + documentation has been heavily tailored by Fred L. Drake, + Jr. Original navigation icons were contributed by Christopher + Petrilli. +

+ +
+ +

Comments and Questions

+ +

General comments and questions regarding this document should + be sent by email to docs@python.org. If you find specific errors in + this document, either in the content or the presentation, please + report the bug at the Python Bug + Tracker at SourceForge. + If you are able to provide suggested text, either to replace + existing incorrect or unclear material, or additional text to + supplement what's already available, we'd appreciate the + contribution. There's no need to worry about text markup; our + documentation team will gladly take care of that. +

+ +

Questions regarding how to use the information in this + document should be sent to the Python news group, comp.lang.python, or the Python mailing list (which is gated to the newsgroup and + carries the same content). +

+ +

For any of these channels, please be sure not to send HTML email. + Thanks. +

diff --git a/sys/src/cmd/python/Doc/html/style.css b/sys/src/cmd/python/Doc/html/style.css new file mode 100644 index 000000000..06a613c2c --- /dev/null +++ b/sys/src/cmd/python/Doc/html/style.css @@ -0,0 +1,243 @@ +/* + * The first part of this is the standard CSS generated by LaTeX2HTML, + * with the "empty" declarations removed. + */ + +/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */ +.math { font-family: "Century Schoolbook", serif; } +.math i { font-family: "Century Schoolbook", serif; + font-weight: bold } +.boldmath { font-family: "Century Schoolbook", serif; + font-weight: bold } + +/* + * Implement both fixed-size and relative sizes. + * + * I think these can be safely removed, as it doesn't appear that + * LaTeX2HTML ever generates these, even though these are carried + * over from the LaTeX2HTML stylesheet. + */ +small.xtiny { font-size : xx-small; } +small.tiny { font-size : x-small; } +small.scriptsize { font-size : smaller; } +small.footnotesize { font-size : small; } +big.xlarge { font-size : large; } +big.xxlarge { font-size : x-large; } +big.huge { font-size : larger; } +big.xhuge { font-size : xx-large; } + +/* + * Document-specific styles come next; + * these are added for the Python documentation. + * + * Note that the size specifications for the H* elements are because + * Netscape on Solaris otherwise doesn't get it right; they all end up + * the normal text size. + */ + +body { color: #000000; + background-color: #ffffff; } + +a:link:active { color: #ff0000; } +a:link:hover { background-color: #bbeeff; } +a:visited:hover { background-color: #bbeeff; } +a:visited { color: #551a8b; } +a:link { color: #0000bb; } + +h1, h2, h3, h4, h5, h6 { font-family: avantgarde, sans-serif; + font-weight: bold; } +h1 { font-size: 180%; } +h2 { font-size: 150%; } +h3, h4 { font-size: 120%; } + +/* These are section titles used in navigation links, so make sure we + * match the section header font here, even it not the weight. + */ +.sectref { font-family: avantgarde, sans-serif; } +/* And the label before the titles in navigation: */ +.navlabel { font-size: 85%; } + + +/* LaTeX2HTML insists on inserting
elements into headers which + * are marked with \label. This little bit of CSS magic ensures that + * these elements don't cause spurious whitespace to be added. + */ +h1>br, h2>br, h3>br, +h4>br, h5>br, h6>br { display: none; } + +code, tt { font-family: "lucida typewriter", lucidatypewriter, + monospace; } +var { font-family: times, serif; + font-style: italic; + font-weight: normal; } + +.Unix { font-variant: small-caps; } + +.typelabel { font-family: lucida, sans-serif; } + +.navigation td { background-color: #99ccff; + font-weight: bold; + font-family: avantgarde, sans-serif; + font-size: 110%; } + +div.warning { background-color: #fffaf0; + border: thin solid black; + padding: 1em; + margin-left: 2em; + margin-right: 2em; } + +div.warning .label { font-family: sans-serif; + font-size: 110%; + margin-right: 0.5em; } + +div.note { background-color: #fffaf0; + border: thin solid black; + padding: 1em; + margin-left: 2em; + margin-right: 2em; } + +div.note .label { margin-right: 0.5em; + font-family: sans-serif; } + +address { font-size: 80%; } +.release-info { font-style: italic; + font-size: 80%; } + +.titlegraphic { vertical-align: top; } + +.verbatim pre { color: #00008b; + font-family: "lucida typewriter", lucidatypewriter, + monospace; + font-size: 90%; } +.verbatim { margin-left: 2em; } +.verbatim .footer { padding: 0.05in; + font-size: 85%; + background-color: #99ccff; + margin-right: 0.5in; } + +.grammar { background-color: #99ccff; + margin-right: 0.5in; + padding: 0.05in; } +.grammar-footer { padding: 0.05in; + font-size: 85%; } +.grammartoken { font-family: "lucida typewriter", lucidatypewriter, + monospace; } + +.productions { background-color: #bbeeff; } +.productions a:active { color: #ff0000; } +.productions a:link:hover { background-color: #99ccff; } +.productions a:visited:hover { background-color: #99ccff; } +.productions a:visited { color: #551a8b; } +.productions a:link { color: #0000bb; } +.productions table { vertical-align: baseline; + empty-cells: show; } +.productions > table td, +.productions > table th { padding: 2px; } +.productions > table td:first-child, +.productions > table td:last-child { + font-family: "lucida typewriter", + lucidatypewriter, + monospace; + } +/* same as the second selector above, but expressed differently for Opera */ +.productions > table td:first-child + td + td { + font-family: "lucida typewriter", + lucidatypewriter, + monospace; + vertical-align: baseline; + } +.productions > table td:first-child + td { + padding-left: 1em; + padding-right: 1em; + } +.productions > table tr { vertical-align: baseline; } + +.email { font-family: avantgarde, sans-serif; } +.mailheader { font-family: avantgarde, sans-serif; } +.mimetype { font-family: avantgarde, sans-serif; } +.newsgroup { font-family: avantgarde, sans-serif; } +.url { font-family: avantgarde, sans-serif; } +.file { font-family: avantgarde, sans-serif; } +.guilabel { font-family: avantgarde, sans-serif; } + +.realtable { border-collapse: collapse; + border-color: black; + border-style: solid; + border-width: 0px 0px 2px 0px; + empty-cells: show; + margin-left: auto; + margin-right: auto; + padding-left: 0.4em; + padding-right: 0.4em; + } +.realtable tbody { vertical-align: baseline; } +.realtable tfoot { display: table-footer-group; } +.realtable thead { background-color: #99ccff; + border-width: 0px 0px 2px 1px; + display: table-header-group; + font-family: avantgarde, sans-serif; + font-weight: bold; + vertical-align: baseline; + } +.realtable thead :first-child { + border-width: 0px 0px 2px 0px; + } +.realtable thead th { border-width: 0px 0px 2px 1px } +.realtable td, +.realtable th { border-color: black; + border-style: solid; + border-width: 0px 0px 1px 1px; + padding-left: 0.4em; + padding-right: 0.4em; + } +.realtable td:first-child, +.realtable th:first-child { + border-left-width: 0px; + vertical-align: baseline; + } +.center { text-align: center; } +.left { text-align: left; } +.right { text-align: right; } + +.refcount-info { font-style: italic; } +.refcount-info .value { font-weight: bold; + color: #006600; } + +/* + * Some decoration for the "See also:" blocks, in part inspired by some of + * the styling on Lars Marius Garshol's XSA pages. + * (The blue in the navigation bars is #99CCFF.) + */ +.seealso { background-color: #fffaf0; + border: thin solid black; + padding: 0pt 1em 4pt 1em; } + +.seealso > .heading { font-size: 110%; + font-weight: bold; } + +/* + * Class 'availability' is used for module availability statements at + * the top of modules. + */ +.availability .platform { font-weight: bold; } + + +/* + * Additional styles for the distutils package. + */ +.du-command { font-family: monospace; } +.du-option { font-family: avantgarde, sans-serif; } +.du-filevar { font-family: avantgarde, sans-serif; + font-style: italic; } +.du-xxx:before { content: "** "; + font-weight: bold; } +.du-xxx:after { content: " **"; + font-weight: bold; } + + +/* + * Some specialization for printed output. + */ +@media print { + .online-navigation { display: none; } + } diff --git a/sys/src/cmd/python/Doc/info/Makefile b/sys/src/cmd/python/Doc/info/Makefile new file mode 100644 index 000000000..3dbbd747b --- /dev/null +++ b/sys/src/cmd/python/Doc/info/Makefile @@ -0,0 +1,82 @@ +# Generate the Python "info" documentation. + +TOPDIR=.. +TOOLSDIR=$(TOPDIR)/tools +HTMLDIR=$(TOPDIR)/html + +# The emacs binary used to build the info docs. GNU Emacs 21 is required. +EMACS=emacs + +MKINFO=$(TOOLSDIR)/mkinfo +SCRIPTS=$(TOOLSDIR)/checkargs.pm $(TOOLSDIR)/mkinfo $(TOOLSDIR)/py2texi.el + +# set VERSION to code the VERSION number into the info file name +# allowing installation of more than one set of python info docs +# into the same directory +VERSION= + +all: check-emacs-version \ + api dist ext mac ref tut whatsnew \ + lib +# doc inst + +api: python$(VERSION)-api.info +dist: python$(VERSION)-dist.info +doc: python$(VERSION)-doc.info +ext: python$(VERSION)-ext.info +inst: python$(VERSION)-inst.info +lib: python$(VERSION)-lib.info +mac: python$(VERSION)-mac.info +ref: python$(VERSION)-ref.info +tut: python$(VERSION)-tut.info +whatsnew: $(WHATSNEW) +$(WHATSNEW): python$(VERSION)-$(WHATSNEW).info + +check-emacs-version: + @v="`$(EMACS) --version 2>&1 | egrep '^(GNU |X)Emacs [12]*'`"; \ + if `echo "$$v" | grep '^GNU Emacs 21' >/dev/null 2>&1`; then \ + echo "Using $(EMACS) to build the info docs"; \ + else \ + echo "GNU Emacs 21 is required to build the info docs"; \ + echo "Found $$v"; \ + false; \ + fi + +python$(VERSION)-api.info: ../api/api.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +python$(VERSION)-ext.info: ../ext/ext.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +python$(VERSION)-lib.info: ../lib/lib.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +python$(VERSION)-mac.info: ../mac/mac.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +python$(VERSION)-ref.info: ../ref/ref.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +python$(VERSION)-tut.info: ../tut/tut.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +# Not built by default; the conversion doesn't handle \p and \op +python$(VERSION)-doc.info: ../doc/doc.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +python$(VERSION)-dist.info: ../dist/dist.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +# Not built by default; the conversion chokes on \installscheme +python$(VERSION)-inst.info: ../inst/inst.tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +# "whatsnew20" doesn't currently work +python$(VERSION)-$(WHATSNEW).info: ../whatsnew/$(WHATSNEW).tex $(SCRIPTS) + EMACS=$(EMACS) $(MKINFO) $< $*.texi $@ + +clean: + rm -f *.texi~ *.texi + +clobber: clean + rm -f *.texi python*-*.info python*-*.info-[0-9]* diff --git a/sys/src/cmd/python/Doc/info/README b/sys/src/cmd/python/Doc/info/README new file mode 100644 index 000000000..bcee2be2b --- /dev/null +++ b/sys/src/cmd/python/Doc/info/README @@ -0,0 +1,21 @@ +This archive contains the standard Python documentation in GNU info +format. Five manuals are included: + + python-ref.info* Python Reference Manual + python-mac.info* Python Macintosh Modules + python-lib.info* Python Library Reference + python-ext.info* Extending and Embedding the Python Interpreter + python-api.info* Python/C API Reference + python-tut.info* Python Tutorial + +The file python.dir is a fragment of a "dir" file that can be used to +incorporate these documents into an existing GNU info installation: +insert the contents of this file into the "dir" or "localdir" file at +an appropriate point and copy the python-*.info* files to the same +directory. + +Thanks go to Milan Zamazal for providing this +conversion to the info format. + +Questions and comments on these documents should be directed to +docs@python.org. diff --git a/sys/src/cmd/python/Doc/info/python.dir b/sys/src/cmd/python/Doc/info/python.dir new file mode 100644 index 000000000..a215dec7c --- /dev/null +++ b/sys/src/cmd/python/Doc/info/python.dir @@ -0,0 +1,11 @@ + +Python Standard Documentation + +* What's New: (python-whatsnew25). What's New in Python 2.5? +* Python Library: (python-lib). Python Library Reference +* Python Mac Modules: (python-mac). Python Macintosh Modules +* Python Reference: (python-ref). Python Reference Manual +* Python API: (python-api). Python/C API Reference Manual +* Python Extending: (python-ext). Extending & Embedding Python +* Python Tutorial: (python-tut). Python Tutorial +* Distributing Modules: (python-dist). Distributing Python Modules diff --git a/sys/src/cmd/python/Doc/inst/inst.tex b/sys/src/cmd/python/Doc/inst/inst.tex new file mode 100644 index 000000000..6db22ac5e --- /dev/null +++ b/sys/src/cmd/python/Doc/inst/inst.tex @@ -0,0 +1,1112 @@ +\documentclass{howto} +\usepackage{distutils} + +% TODO: +% Fill in XXX comments + +\title{Installing Python Modules} + +% The audience for this document includes people who don't know anything +% about Python and aren't about to learn the language just in order to +% install and maintain it for their users, i.e. system administrators. +% Thus, I have to be sure to explain the basics at some point: +% sys.path and PYTHONPATH at least. Should probably give pointers to +% other docs on "import site", PYTHONSTARTUP, PYTHONHOME, etc. +% +% Finally, it might be useful to include all the material from my "Care +% and Feeding of a Python Installation" talk in here somewhere. Yow! + +\input{boilerplate} + +\author{Greg Ward} +\authoraddress{ + \strong{Python Software Foundation}\\ + Email: \email{distutils-sig@python.org} +} + +\makeindex + +\begin{document} + +\maketitle + +\begin{abstract} + \noindent + This document describes the Python Distribution Utilities + (``Distutils'') from the end-user's point-of-view, describing how to + extend the capabilities of a standard Python installation by building + and installing third-party Python modules and extensions. +\end{abstract} + +%\begin{abstract} +%\noindent +%Abstract this! +%\end{abstract} + + +% The ugly "%begin{latexonly}" pseudo-environment suppresses the table +% of contents for HTML generation. +% +%begin{latexonly} +\tableofcontents +%end{latexonly} + + +\section{Introduction} +\label{intro} + +Although Python's extensive standard library covers many programming +needs, there often comes a time when you need to add some new +functionality to your Python installation in the form of third-party +modules. This might be necessary to support your own programming, or to +support an application that you want to use and that happens to be +written in Python. + +In the past, there has been little support for adding third-party +modules to an existing Python installation. With the introduction of +the Python Distribution Utilities (Distutils for short) in Python 2.0, +this changed. + +This document is aimed primarily at the people who need to install +third-party Python modules: end-users and system administrators who just +need to get some Python application running, and existing Python +programmers who want to add some new goodies to their toolbox. You +don't need to know Python to read this document; there will be some +brief forays into using Python's interactive mode to explore your +installation, but that's it. If you're looking for information on how +to distribute your own Python modules so that others may use them, see +the \citetitle[../dist/dist.html]{Distributing Python Modules} manual. + + +\subsection{Best case: trivial installation} +\label{trivial-install} + +In the best case, someone will have prepared a special version of the +module distribution you want to install that is targeted specifically at +your platform and is installed just like any other software on your +platform. For example, the module developer might make an executable +installer available for Windows users, an RPM package for users of +RPM-based Linux systems (Red Hat, SuSE, Mandrake, and many others), a +Debian package for users of Debian-based Linux systems, and so forth. + +In that case, you would download the installer appropriate to your +platform and do the obvious thing with it: run it if it's an executable +installer, \code{rpm --install} it if it's an RPM, etc. You don't need +to run Python or a setup script, you don't need to compile +anything---you might not even need to read any instructions (although +it's always a good idea to do so anyways). + +Of course, things will not always be that easy. You might be interested +in a module distribution that doesn't have an easy-to-use installer for +your platform. In that case, you'll have to start with the source +distribution released by the module's author/maintainer. Installing +from a source distribution is not too hard, as long as the modules are +packaged in the standard way. The bulk of this document is about +building and installing modules from standard source distributions. + + +\subsection{The new standard: Distutils} +\label{new-standard} + +If you download a module source distribution, you can tell pretty +quickly if it was packaged and distributed in the standard way, i.e. +using the Distutils. First, the distribution's name and version number +will be featured prominently in the name of the downloaded archive, e.g. +\file{foo-1.0.tar.gz} or \file{widget-0.9.7.zip}. Next, the archive +will unpack into a similarly-named directory: \file{foo-1.0} or +\file{widget-0.9.7}. Additionally, the distribution will contain a +setup script \file{setup.py}, and a file named \file{README.txt} or possibly +just \file{README}, which should explain that building and installing the +module distribution is a simple matter of running + +\begin{verbatim} +python setup.py install +\end{verbatim} + +If all these things are true, then you already know how to build and +install the modules you've just downloaded: Run the command above. +Unless you need to install things in a non-standard way or customize the +build process, you don't really need this manual. Or rather, the above +command is everything you need to get out of this manual. + + +\section{Standard Build and Install} +\label{standard-install} + +As described in section~\ref{new-standard}, building and installing +a module distribution using the Distutils is usually one simple command: + +\begin{verbatim} +python setup.py install +\end{verbatim} + +On \UNIX, you'd run this command from a shell prompt; on Windows, you +have to open a command prompt window (``DOS box'') and do it there; on +Mac OS X, you open a \command{Terminal} window to get a shell prompt. + + +\subsection{Platform variations} +\label{platform-variations} + +You should always run the setup command from the distribution root +directory, i.e. the top-level subdirectory that the module source +distribution unpacks into. For example, if you've just downloaded a +module source distribution \file{foo-1.0.tar.gz} onto a +\UNIX{} system, the normal thing to do is: + +\begin{verbatim} +gunzip -c foo-1.0.tar.gz | tar xf - # unpacks into directory foo-1.0 +cd foo-1.0 +python setup.py install +\end{verbatim} + +On Windows, you'd probably download \file{foo-1.0.zip}. If you +downloaded the archive file to \file{C:\textbackslash{}Temp}, then it +would unpack into \file{C:\textbackslash{}Temp\textbackslash{}foo-1.0}; +you can use either a archive manipulator with a graphical user interface +(such as WinZip) or a command-line tool (such as \program{unzip} or +\program{pkunzip}) to unpack the archive. Then, open a command prompt +window (``DOS box''), and run: + +\begin{verbatim} +cd c:\Temp\foo-1.0 +python setup.py install +\end{verbatim} + +\subsection{Splitting the job up} +\label{splitting-up} + +Running \code{setup.py install} builds and installs all modules in one +run. If you prefer to work incrementally---especially useful if you +want to customize the build process, or if things are going wrong---you +can use the setup script to do one thing at a time. This is +particularly helpful when the build and install will be done by +different users---for example, you might want to build a module distribution +and hand it off to a system administrator for installation (or do it +yourself, with super-user privileges). + +For example, you can build everything in one step, and then install +everything in a second step, by invoking the setup script twice: + +\begin{verbatim} +python setup.py build +python setup.py install +\end{verbatim} + +If you do this, you will notice that running the \command{install} +command first runs the \command{build} command, which---in this +case---quickly notices that it has nothing to do, since everything in +the \file{build} directory is up-to-date. + +You may not need this ability to break things down often if all you do +is install modules downloaded off the 'net, but it's very handy for more +advanced tasks. If you get into distributing your own Python modules +and extensions, you'll run lots of individual Distutils commands on +their own. + + +\subsection{How building works} +\label{how-build-works} + +As implied above, the \command{build} command is responsible for putting +the files to install into a \emph{build directory}. By default, this is +\file{build} under the distribution root; if you're excessively +concerned with speed, or want to keep the source tree pristine, you can +change the build directory with the \longprogramopt{build-base} option. +For example: + +\begin{verbatim} +python setup.py build --build-base=/tmp/pybuild/foo-1.0 +\end{verbatim} + +(Or you could do this permanently with a directive in your system or +personal Distutils configuration file; see +section~\ref{config-files}.) Normally, this isn't necessary. + +The default layout for the build tree is as follows: + +\begin{verbatim} +--- build/ --- lib/ +or +--- build/ --- lib./ + temp./ +\end{verbatim} + +where \code{} expands to a brief description of the current +OS/hardware platform and Python version. The first form, with just a +\file{lib} directory, is used for ``pure module distributions''---that +is, module distributions that include only pure Python modules. If a +module distribution contains any extensions (modules written in C/\Cpp), +then the second form, with two \code{} directories, is used. In +that case, the \file{temp.\filevar{plat}} directory holds temporary +files generated by the compile/link process that don't actually get +installed. In either case, the \file{lib} (or +\file{lib.\filevar{plat}}) directory contains all Python modules (pure +Python and extensions) that will be installed. + +In the future, more directories will be added to handle Python scripts, +documentation, binary executables, and whatever else is needed to handle +the job of installing Python modules and applications. + + +\subsection{How installation works} +\label{how-install-works} + +After the \command{build} command runs (whether you run it explicitly, +or the \command{install} command does it for you), the work of the +\command{install} command is relatively simple: all it has to do is copy +everything under \file{build/lib} (or \file{build/lib.\filevar{plat}}) +to your chosen installation directory. + +If you don't choose an installation directory---i.e., if you just run +\code{setup.py install}---then the \command{install} command installs to +the standard location for third-party Python modules. This location +varies by platform and by how you built/installed Python itself. On +\UNIX{} (and Mac OS X, which is also \UNIX-based), +it also depends on whether the module distribution +being installed is pure Python or contains extensions (``non-pure''): +\begin{tableiv}{l|l|l|c}{textrm}% + {Platform}{Standard installation location}{Default value}{Notes} + \lineiv{\UNIX{} (pure)} + {\filenq{\filevar{prefix}/lib/python\shortversion/site-packages}} + {\filenq{/usr/local/lib/python\shortversion/site-packages}} + {(1)} + \lineiv{\UNIX{} (non-pure)} + {\filenq{\filevar{exec-prefix}/lib/python\shortversion/site-packages}} + {\filenq{/usr/local/lib/python\shortversion/site-packages}} + {(1)} + \lineiv{Windows} + {\filenq{\filevar{prefix}}} + {\filenq{C:\textbackslash{}Python}} + {(2)} +\end{tableiv} + +\noindent Notes: +\begin{description} +\item[(1)] Most Linux distributions include Python as a standard part of + the system, so \filevar{prefix} and \filevar{exec-prefix} are usually + both \file{/usr} on Linux. If you build Python yourself on Linux (or + any \UNIX-like system), the default \filevar{prefix} and + \filevar{exec-prefix} are \file{/usr/local}. +\item[(2)] The default installation directory on Windows was + \file{C:\textbackslash{}Program Files\textbackslash{}Python} under + Python 1.6a1, 1.5.2, and earlier. +\end{description} + +\filevar{prefix} and \filevar{exec-prefix} stand for the directories +that Python is installed to, and where it finds its libraries at +run-time. They are always the same under Windows, and very +often the same under \UNIX and Mac OS X. You can find out what your Python +installation uses for \filevar{prefix} and \filevar{exec-prefix} by +running Python in interactive mode and typing a few simple commands. +Under \UNIX, just type \code{python} at the shell prompt. Under +Windows, choose \menuselection{Start \sub Programs \sub Python +\shortversion \sub Python (command line)}. +Once the interpreter is started, you type Python code at the +prompt. For example, on my Linux system, I type the three Python +statements shown below, and get the output as shown, to find out my +\filevar{prefix} and \filevar{exec-prefix}: + +\begin{verbatim} +Python 2.4 (#26, Aug 7 2004, 17:19:02) +Type "help", "copyright", "credits" or "license" for more information. +>>> import sys +>>> sys.prefix +'/usr' +>>> sys.exec_prefix +'/usr' +\end{verbatim} + +If you don't want to install modules to the standard location, or if you +don't have permission to write there, then you need to read about +alternate installations in section~\ref{alt-install}. If you want to +customize your installation directories more heavily, see +section~\ref{custom-install} on custom installations. + + +% This rather nasty macro is used to generate the tables that describe +% each installation scheme. It's nasty because it takes two arguments +% for each "slot" in an installation scheme, there will soon be more +% than five of these slots, and TeX has a limit of 10 arguments to a +% macro. Uh-oh. + +\newcommand{\installscheme}[8] + {\begin{tableiii}{l|l|l}{textrm} + {Type of file} + {Installation Directory} + {Override option} + \lineiii{pure module distribution} + {\filevar{#1}\filenq{#2}} + {\longprogramopt{install-purelib}} + \lineiii{non-pure module distribution} + {\filevar{#3}\filenq{#4}} + {\longprogramopt{install-platlib}} + \lineiii{scripts} + {\filevar{#5}\filenq{#6}} + {\longprogramopt{install-scripts}} + \lineiii{data} + {\filevar{#7}\filenq{#8}} + {\longprogramopt{install-data}} + \end{tableiii}} + + +\section{Alternate Installation} +\label{alt-install} + +Often, it is necessary or desirable to install modules to a location +other than the standard location for third-party Python modules. For +example, on a \UNIX{} system you might not have permission to write to the +standard third-party module directory. Or you might wish to try out a +module before making it a standard part of your local Python +installation. This is especially true when upgrading a distribution +already present: you want to make sure your existing base of scripts +still works with the new version before actually upgrading. + +The Distutils \command{install} command is designed to make installing +module distributions to an alternate location simple and painless. The +basic idea is that you supply a base directory for the installation, and +the \command{install} command picks a set of directories (called an +\emph{installation scheme}) under this base directory in which to +install files. The details differ across platforms, so read whichever +of the following sections applies to you. + + +\subsection{Alternate installation: the home scheme} +\label{alt-install-prefix} + +The idea behind the ``home scheme'' is that you build and maintain a +personal stash of Python modules. This scheme's name is derived from +the idea of a ``home'' directory on \UNIX, since it's not unusual for +a \UNIX{} user to make their home directory have a layout similar to +\file{/usr/} or \file{/usr/local/}. This scheme can be used by +anyone, regardless of the operating system their installing for. + +Installing a new module distribution is as simple as + +\begin{verbatim} +python setup.py install --home= +\end{verbatim} + +where you can supply any directory you like for the +\longprogramopt{home} option. On \UNIX, lazy typists can just type a +tilde (\code{\textasciitilde}); the \command{install} command will +expand this to your home directory: + +\begin{verbatim} +python setup.py install --home=~ +\end{verbatim} + +The \longprogramopt{home} option defines the installation base +directory. Files are installed to the following directories under the +installation base as follows: +\installscheme{home}{/lib/python} + {home}{/lib/python} + {home}{/bin} + {home}{/share} + + +\versionchanged[The \longprogramopt{home} option used to be supported + only on \UNIX]{2.4} + + +\subsection{Alternate installation: \UNIX{} (the prefix scheme)} +\label{alt-install-home} + +The ``prefix scheme'' is useful when you wish to use one Python +installation to perform the build/install (i.e., to run the setup +script), but install modules into the third-party module directory of a +different Python installation (or something that looks like a different +Python installation). If this sounds a trifle unusual, it is---that's +why the ``home scheme'' comes first. However, there are at least two +known cases where the prefix scheme will be useful. + +First, consider that many Linux distributions put Python in \file{/usr}, +rather than the more traditional \file{/usr/local}. This is entirely +appropriate, since in those cases Python is part of ``the system'' +rather than a local add-on. However, if you are installing Python +modules from source, you probably want them to go in +\file{/usr/local/lib/python2.\filevar{X}} rather than +\file{/usr/lib/python2.\filevar{X}}. This can be done with + +\begin{verbatim} +/usr/bin/python setup.py install --prefix=/usr/local +\end{verbatim} + +Another possibility is a network filesystem where the name used to write +to a remote directory is different from the name used to read it: for +example, the Python interpreter accessed as \file{/usr/local/bin/python} +might search for modules in \file{/usr/local/lib/python2.\filevar{X}}, +but those modules would have to be installed to, say, +\file{/mnt/\filevar{@server}/export/lib/python2.\filevar{X}}. This +could be done with + +\begin{verbatim} +/usr/local/bin/python setup.py install --prefix=/mnt/@server/export +\end{verbatim} + +In either case, the \longprogramopt{prefix} option defines the +installation base, and the \longprogramopt{exec-prefix} option defines +the platform-specific installation base, which is used for +platform-specific files. (Currently, this just means non-pure module +distributions, but could be expanded to C libraries, binary executables, +etc.) If \longprogramopt{exec-prefix} is not supplied, it defaults to +\longprogramopt{prefix}. Files are installed as follows: + +\installscheme{prefix}{/lib/python2.\filevar{X}/site-packages} + {exec-prefix}{/lib/python2.\filevar{X}/site-packages} + {prefix}{/bin} + {prefix}{/share} + +There is no requirement that \longprogramopt{prefix} or +\longprogramopt{exec-prefix} actually point to an alternate Python +installation; if the directories listed above do not already exist, they +are created at installation time. + +Incidentally, the real reason the prefix scheme is important is simply +that a standard \UNIX{} installation uses the prefix scheme, but with +\longprogramopt{prefix} and \longprogramopt{exec-prefix} supplied by +Python itself as \code{sys.prefix} and \code{sys.exec\_prefix}. Thus, +you might think you'll never use the prefix scheme, but every time you +run \code{python setup.py install} without any other options, you're +using it. + +Note that installing extensions to an alternate Python installation has +no effect on how those extensions are built: in particular, the Python +header files (\file{Python.h} and friends) installed with the Python +interpreter used to run the setup script will be used in compiling +extensions. It is your responsibility to ensure that the interpreter +used to run extensions installed in this way is compatible with the +interpreter used to build them. The best way to do this is to ensure +that the two interpreters are the same version of Python (possibly +different builds, or possibly copies of the same build). (Of course, if +your \longprogramopt{prefix} and \longprogramopt{exec-prefix} don't even +point to an alternate Python installation, this is immaterial.) + + +\subsection{Alternate installation: Windows (the prefix scheme)} +\label{alt-install-windows} + +Windows has no concept of a user's home directory, and since the +standard Python installation under Windows is simpler than under +\UNIX, the \longprogramopt{prefix} option has traditionally been used +to install additional packages in separate locations on Windows. + +\begin{verbatim} +python setup.py install --prefix="\Temp\Python" +\end{verbatim} + +to install modules to the +\file{\textbackslash{}Temp\textbackslash{}Python} directory on the +current drive. + +The installation base is defined by the \longprogramopt{prefix} option; +the \longprogramopt{exec-prefix} option is not supported under Windows. +Files are installed as follows: +\installscheme{prefix}{} + {prefix}{} + {prefix}{\textbackslash{}Scripts} + {prefix}{\textbackslash{}Data} + + + +\section{Custom Installation} +\label{custom-install} + +Sometimes, the alternate installation schemes described in +section~\ref{alt-install} just don't do what you want. You might +want to tweak just one or two directories while keeping everything under +the same base directory, or you might want to completely redefine the +installation scheme. In either case, you're creating a \emph{custom +installation scheme}. + +You probably noticed the column of ``override options'' in the tables +describing the alternate installation schemes above. Those options are +how you define a custom installation scheme. These override options can +be relative, absolute, or explicitly defined in terms of one of the +installation base directories. (There are two installation base +directories, and they are normally the same---they only differ when you +use the \UNIX{} ``prefix scheme'' and supply different +\longprogramopt{prefix} and \longprogramopt{exec-prefix} options.) + +For example, say you're installing a module distribution to your home +directory under \UNIX---but you want scripts to go in +\file{\textasciitilde/scripts} rather than \file{\textasciitilde/bin}. +As you might expect, you can override this directory with the +\longprogramopt{install-scripts} option; in this case, it makes most +sense to supply a relative path, which will be interpreted relative to +the installation base directory (your home directory, in this case): + +\begin{verbatim} +python setup.py install --home=~ --install-scripts=scripts +\end{verbatim} + +Another \UNIX{} example: suppose your Python installation was built and +installed with a prefix of \file{/usr/local/python}, so under a standard +installation scripts will wind up in \file{/usr/local/python/bin}. If +you want them in \file{/usr/local/bin} instead, you would supply this +absolute directory for the \longprogramopt{install-scripts} option: + +\begin{verbatim} +python setup.py install --install-scripts=/usr/local/bin +\end{verbatim} + +(This performs an installation using the ``prefix scheme,'' where the +prefix is whatever your Python interpreter was installed with--- +\file{/usr/local/python} in this case.) + +If you maintain Python on Windows, you might want third-party modules to +live in a subdirectory of \filevar{prefix}, rather than right in +\filevar{prefix} itself. This is almost as easy as customizing the +script installation directory---you just have to remember that there are +two types of modules to worry about, pure modules and non-pure modules +(i.e., modules from a non-pure distribution). For example: + +\begin{verbatim} +python setup.py install --install-purelib=Site --install-platlib=Site +\end{verbatim} + +The specified installation directories are relative to +\filevar{prefix}. Of course, you also have to ensure that these +directories are in Python's module search path, such as by putting a +\file{.pth} file in \filevar{prefix}. See section~\ref{search-path} +to find out how to modify Python's search path. + +If you want to define an entire installation scheme, you just have to +supply all of the installation directory options. The recommended way +to do this is to supply relative paths; for example, if you want to +maintain all Python module-related files under \file{python} in your +home directory, and you want a separate directory for each platform that +you use your home directory from, you might define the following +installation scheme: + +\begin{verbatim} +python setup.py install --home=~ \ + --install-purelib=python/lib \ + --install-platlib=python/lib.$PLAT \ + --install-scripts=python/scripts + --install-data=python/data +\end{verbatim} +% $ % -- bow to font-lock + +or, equivalently, + +\begin{verbatim} +python setup.py install --home=~/python \ + --install-purelib=lib \ + --install-platlib='lib.$PLAT' \ + --install-scripts=scripts + --install-data=data +\end{verbatim} +% $ % -- bow to font-lock + +\code{\$PLAT} is not (necessarily) an environment variable---it will be +expanded by the Distutils as it parses your command line options, just +as it does when parsing your configuration file(s). + +Obviously, specifying the entire installation scheme every time you +install a new module distribution would be very tedious. Thus, you can +put these options into your Distutils config file (see +section~\ref{config-files}): + +\begin{verbatim} +[install] +install-base=$HOME +install-purelib=python/lib +install-platlib=python/lib.$PLAT +install-scripts=python/scripts +install-data=python/data +\end{verbatim} + +or, equivalently, + +\begin{verbatim} +[install] +install-base=$HOME/python +install-purelib=lib +install-platlib=lib.$PLAT +install-scripts=scripts +install-data=data +\end{verbatim} + +Note that these two are \emph{not} equivalent if you supply a different +installation base directory when you run the setup script. For example, + +\begin{verbatim} +python setup.py install --install-base=/tmp +\end{verbatim} + +would install pure modules to \filevar{/tmp/python/lib} in the first +case, and to \filevar{/tmp/lib} in the second case. (For the second +case, you probably want to supply an installation base of +\file{/tmp/python}.) + +You probably noticed the use of \code{\$HOME} and \code{\$PLAT} in the +sample configuration file input. These are Distutils configuration +variables, which bear a strong resemblance to environment variables. +In fact, you can use environment variables in config files on +platforms that have such a notion but the Distutils additionally +define a few extra variables that may not be in your environment, such +as \code{\$PLAT}. (And of course, on systems that don't have +environment variables, such as Mac OS 9, the configuration +variables supplied by the Distutils are the only ones you can use.) +See section~\ref{config-files} for details. + +% XXX need some Windows examples---when would custom +% installation schemes be needed on those platforms? + + +% XXX I'm not sure where this section should go. +\subsection{Modifying Python's Search Path} +\label{search-path} + +When the Python interpreter executes an \keyword{import} statement, it +searches for both Python code and extension modules along a search +path. A default value for the path is configured into the Python +binary when the interpreter is built. You can determine the path by +importing the \module{sys} module and printing the value of +\code{sys.path}. + +\begin{verbatim} +$ python +Python 2.2 (#11, Oct 3 2002, 13:31:27) +[GCC 2.96 20000731 (Red Hat Linux 7.3 2.96-112)] on linux2 +Type ``help'', ``copyright'', ``credits'' or ``license'' for more information. +>>> import sys +>>> sys.path +['', '/usr/local/lib/python2.3', '/usr/local/lib/python2.3/plat-linux2', + '/usr/local/lib/python2.3/lib-tk', '/usr/local/lib/python2.3/lib-dynload', + '/usr/local/lib/python2.3/site-packages'] +>>> +\end{verbatim} % $ <-- bow to font-lock + +The null string in \code{sys.path} represents the current working +directory. + +The expected convention for locally installed packages is to put them +in the \file{.../site-packages/} directory, but you may want to +install Python modules into some arbitrary directory. For example, +your site may have a convention of keeping all software related to the +web server under \file{/www}. Add-on Python modules might then belong +in \file{/www/python}, and in order to import them, this directory +must be added to \code{sys.path}. There are several different ways to +add the directory. + +The most convenient way is to add a path configuration file to a +directory that's already on Python's path, usually to the +\file{.../site-packages/} directory. Path configuration files have an +extension of \file{.pth}, and each line must contain a single path +that will be appended to \code{sys.path}. (Because the new paths are +appended to \code{sys.path}, modules in the added directories will not +override standard modules. This means you can't use this mechanism +for installing fixed versions of standard modules.) + +Paths can be absolute or relative, in which case they're relative to +the directory containing the \file{.pth} file. Any directories added +to the search path will be scanned in turn for \file{.pth} files. See +\citetitle[http://www.python.org/dev/doc/devel/lib/module-site.html] +{site module documentation} for more information. + +A slightly less convenient way is to edit the \file{site.py} file in +Python's standard library, and modify \code{sys.path}. \file{site.py} +is automatically imported when the Python interpreter is executed, +unless the \programopt{-S} switch is supplied to suppress this +behaviour. So you could simply edit \file{site.py} and add two lines to it: + +\begin{verbatim} +import sys +sys.path.append('/www/python/') +\end{verbatim} + +However, if you reinstall the same major version of Python (perhaps +when upgrading from 2.2 to 2.2.2, for example) \file{site.py} will be +overwritten by the stock version. You'd have to remember that it was +modified and save a copy before doing the installation. + +There are two environment variables that can modify \code{sys.path}. +\envvar{PYTHONHOME} sets an alternate value for the prefix of the +Python installation. For example, if \envvar{PYTHONHOME} is set to +\samp{/www/python}, the search path will be set to \code{['', +'/www/python/lib/python\shortversion/', +'/www/python/lib/python\shortversion/plat-linux2', ...]}. + +The \envvar{PYTHONPATH} variable can be set to a list of paths that +will be added to the beginning of \code{sys.path}. For example, if +\envvar{PYTHONPATH} is set to \samp{/www/python:/opt/py}, the search +path will begin with \code{['/www/python', '/opt/py']}. (Note that +directories must exist in order to be added to \code{sys.path}; the +\module{site} module removes paths that don't exist.) + +Finally, \code{sys.path} is just a regular Python list, so any Python +application can modify it by adding or removing entries. + + +\section{Distutils Configuration Files} +\label{config-files} + +As mentioned above, you can use Distutils configuration files to record +personal or site preferences for any Distutils options. That is, any +option to any command can be stored in one of two or three (depending on +your platform) configuration files, which will be consulted before the +command-line is parsed. This means that configuration files will +override default values, and the command-line will in turn override +configuration files. Furthermore, if multiple configuration files +apply, values from ``earlier'' files are overridden by ``later'' files. + + +\subsection{Location and names of config files} +\label{config-filenames} + +The names and locations of the configuration files vary slightly across +platforms. On \UNIX{} and Mac OS X, the three configuration files (in +the order they are processed) are: +\begin{tableiii}{l|l|c}{textrm} + {Type of file}{Location and filename}{Notes} + \lineiii{system}{\filenq{\filevar{prefix}/lib/python\filevar{ver}/distutils/distutils.cfg}}{(1)} + \lineiii{personal}{\filenq{\$HOME/.pydistutils.cfg}}{(2)} + \lineiii{local}{\filenq{setup.cfg}}{(3)} +\end{tableiii} + +And on Windows, the configuration files are: +\begin{tableiii}{l|l|c}{textrm} + {Type of file}{Location and filename}{Notes} + \lineiii{system}{\filenq{\filevar{prefix}\textbackslash{}Lib\textbackslash{}distutils\textbackslash{}distutils.cfg}}{(4)} + \lineiii{personal}{\filenq{\%HOME\%\textbackslash{}pydistutils.cfg}}{(5)} + \lineiii{local}{\filenq{setup.cfg}}{(3)} +\end{tableiii} + +\noindent Notes: +\begin{description} +\item[(1)] Strictly speaking, the system-wide configuration file lives + in the directory where the Distutils are installed; under Python 1.6 + and later on \UNIX, this is as shown. For Python 1.5.2, the Distutils + will normally be installed to + \file{\filevar{prefix}/lib/python1.5/site-packages/distutils}, + so the system configuration file should be put there under Python + 1.5.2. +\item[(2)] On \UNIX, if the \envvar{HOME} environment variable is not + defined, the user's home directory will be determined with the + \function{getpwuid()} function from the standard + \ulink{\module{pwd}}{../lib/module-pwd.html} module. +\item[(3)] I.e., in the current directory (usually the location of the + setup script). +\item[(4)] (See also note (1).) Under Python 1.6 and later, Python's + default ``installation prefix'' is \file{C:\textbackslash{}Python}, so + the system configuration file is normally + \file{C:\textbackslash{}Python\textbackslash{}Lib\textbackslash{}distutils\textbackslash{}distutils.cfg}. + Under Python 1.5.2, the default prefix was + \file{C:\textbackslash{}Program~Files\textbackslash{}Python}, and the + Distutils were not part of the standard library---so the system + configuration file would be + \file{C:\textbackslash{}Program~Files\textbackslash{}Python\textbackslash{}distutils\textbackslash{}distutils.cfg} + in a standard Python 1.5.2 installation under Windows. +\item[(5)] On Windows, if the \envvar{HOME} environment variable is not + defined, no personal configuration file will be found or used. (In + other words, the Distutils make no attempt to guess your home + directory on Windows.) +\end{description} + + +\subsection{Syntax of config files} +\label{config-syntax} + +The Distutils configuration files all have the same syntax. The config +files are grouped into sections. There is one section for each Distutils +command, plus a \code{global} section for global options that affect +every command. Each section consists of one option per line, specified +as \code{option=value}. + +For example, the following is a complete config file that just forces +all commands to run quietly by default: + +\begin{verbatim} +[global] +verbose=0 +\end{verbatim} + +If this is installed as the system config file, it will affect all +processing of any Python module distribution by any user on the current +system. If it is installed as your personal config file (on systems +that support them), it will affect only module distributions processed +by you. And if it is used as the \file{setup.cfg} for a particular +module distribution, it affects only that distribution. + +You could override the default ``build base'' directory and make the +\command{build*} commands always forcibly rebuild all files with the +following: + +\begin{verbatim} +[build] +build-base=blib +force=1 +\end{verbatim} + +which corresponds to the command-line arguments + +\begin{verbatim} +python setup.py build --build-base=blib --force +\end{verbatim} + +except that including the \command{build} command on the command-line +means that command will be run. Including a particular command in +config files has no such implication; it only means that if the command +is run, the options in the config file will apply. (Or if other +commands that derive values from it are run, they will use the values in +the config file.) + +You can find out the complete list of options for any command using the +\longprogramopt{help} option, e.g.: + +\begin{verbatim} +python setup.py build --help +\end{verbatim} + +and you can find out the complete list of global options by using +\longprogramopt{help} without a command: + +\begin{verbatim} +python setup.py --help +\end{verbatim} + +See also the ``Reference'' section of the ``Distributing Python +Modules'' manual. + +\section{Building Extensions: Tips and Tricks} +\label{building-ext} + +Whenever possible, the Distutils try to use the configuration +information made available by the Python interpreter used to run the +\file{setup.py} script. For example, the same compiler and linker +flags used to compile Python will also be used for compiling +extensions. Usually this will work well, but in complicated +situations this might be inappropriate. This section discusses how to +override the usual Distutils behaviour. + +\subsection{Tweaking compiler/linker flags} +\label{tweak-flags} + +Compiling a Python extension written in C or \Cpp{} will sometimes +require specifying custom flags for the compiler and linker in order +to use a particular library or produce a special kind of object code. +This is especially true if the extension hasn't been tested on your +platform, or if you're trying to cross-compile Python. + +In the most general case, the extension author might have foreseen +that compiling the extensions would be complicated, and provided a +\file{Setup} file for you to edit. This will likely only be done if +the module distribution contains many separate extension modules, or +if they often require elaborate sets of compiler flags in order to work. + +A \file{Setup} file, if present, is parsed in order to get a list of +extensions to build. Each line in a \file{Setup} describes a single +module. Lines have the following structure: + +\begin{alltt} +\var{module} ... [\var{sourcefile} ...] [\var{cpparg} ...] [\var{library} ...] +\end{alltt} + +Let's examine each of the fields in turn. + +\begin{itemize} + +\item \var{module} is the name of the extension module to be built, + and should be a valid Python identifier. You can't just change + this in order to rename a module (edits to the source code would + also be needed), so this should be left alone. + +\item \var{sourcefile} is anything that's likely to be a source code + file, at least judging by the filename. Filenames ending in + \file{.c} are assumed to be written in C, filenames ending in + \file{.C}, \file{.cc}, and \file{.c++} are assumed to be + \Cpp, and filenames ending in \file{.m} or \file{.mm} are + assumed to be in Objective C. + +\item \var{cpparg} is an argument for the C preprocessor, + and is anything starting with \programopt{-I}, \programopt{-D}, + \programopt{-U} or \programopt{-C}. + +\item \var{library} is anything ending in \file{.a} or beginning with + \programopt{-l} or \programopt{-L}. +\end{itemize} + +If a particular platform requires a special library on your platform, +you can add it by editing the \file{Setup} file and running +\code{python setup.py build}. For example, if the module defined by the line + +\begin{verbatim} +foo foomodule.c +\end{verbatim} + +must be linked with the math library \file{libm.a} on your platform, +simply add \programopt{-lm} to the line: + +\begin{verbatim} +foo foomodule.c -lm +\end{verbatim} + +Arbitrary switches intended for the compiler or the linker can be +supplied with the \programopt{-Xcompiler} \var{arg} and +\programopt{-Xlinker} \var{arg} options: + +\begin{verbatim} +foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm +\end{verbatim} + +The next option after \programopt{-Xcompiler} and +\programopt{-Xlinker} will be appended to the proper command line, so +in the above example the compiler will be passed the \programopt{-o32} +option, and the linker will be passed \programopt{-shared}. If a +compiler option requires an argument, you'll have to supply multiple +\programopt{-Xcompiler} options; for example, to pass \code{-x c++} the +\file{Setup} file would have to contain +\code{-Xcompiler -x -Xcompiler c++}. + +Compiler flags can also be supplied through setting the +\envvar{CFLAGS} environment variable. If set, the contents of +\envvar{CFLAGS} will be added to the compiler flags specified in the +\file{Setup} file. + + +\subsection{Using non-Microsoft compilers on Windows \label{non-ms-compilers}} +\sectionauthor{Rene Liebscher}{R.Liebscher@gmx.de} + +\subsubsection{Borland \Cpp} + +This subsection describes the necessary steps to use Distutils with the +Borland \Cpp{} compiler version 5.5. +%Should we mention that users have to create cfg-files for the compiler? +%see also http://community.borland.com/article/0,1410,21205,00.html + +First you have to know that Borland's object file format (OMF) is +different from the format used by the Python version you can download +from the Python or ActiveState Web site. (Python is built with +Microsoft Visual \Cpp, which uses COFF as the object file format.) +For this reason you have to convert Python's library +\file{python25.lib} into the Borland format. You can do this as +follows: + +\begin{verbatim} +coff2omf python25.lib python25_bcpp.lib +\end{verbatim} + +The \file{coff2omf} program comes with the Borland compiler. The file +\file{python25.lib} is in the \file{Libs} directory of your Python +installation. If your extension uses other libraries (zlib,...) you +have to convert them too. + +The converted files have to reside in the same directories as the +normal libraries. + +How does Distutils manage to use these libraries with their changed +names? If the extension needs a library (eg. \file{foo}) Distutils +checks first if it finds a library with suffix \file{_bcpp} +(eg. \file{foo_bcpp.lib}) and then uses this library. In the case it +doesn't find such a special library it uses the default name +(\file{foo.lib}.)\footnote{This also means you could replace all +existing COFF-libraries with OMF-libraries of the same name.} + +To let Distutils compile your extension with Borland \Cpp{} you now have +to type: + +\begin{verbatim} +python setup.py build --compiler=bcpp +\end{verbatim} + +If you want to use the Borland \Cpp{} compiler as the default, you +could specify this in your personal or system-wide configuration file +for Distutils (see section~\ref{config-files}.) + +\begin{seealso} + \seetitle[http://www.borland.com/bcppbuilder/freecompiler/] + {\Cpp{}Builder Compiler} + {Information about the free \Cpp{} compiler from Borland, + including links to the download pages.} + + \seetitle[http://www.cyberus.ca/\~{}g_will/pyExtenDL.shtml] + {Creating Python Extensions Using Borland's Free Compiler} + {Document describing how to use Borland's free command-line \Cpp + compiler to build Python.} +\end{seealso} + + +\subsubsection{GNU C / Cygwin / MinGW} + +These instructions only apply if you're using a version of Python prior +to 2.4.1 with a MinGW prior to 3.0.0 (with binutils-2.13.90-20030111-1). + +This section describes the necessary steps to use Distutils with the +GNU C/\Cpp{} compilers in their Cygwin and MinGW +distributions.\footnote{Check +\url{http://sources.redhat.com/cygwin/} and +\url{http://www.mingw.org/} for more information} +For a Python interpreter that was built with Cygwin, everything should +work without any of these following steps. + +These compilers require some special libraries. +This task is more complex than for Borland's \Cpp, because there is no +program to convert the library. +% I don't understand what the next line means. --amk +% (inclusive the references on data structures.) + +First you have to create a list of symbols which the Python DLL exports. +(You can find a good program for this task at +\url{http://starship.python.net/crew/kernr/mingw32/Notes.html}, see at +PExports 0.42h there.) + +\begin{verbatim} +pexports python25.dll >python25.def +\end{verbatim} + +The location of an installed \file{python25.dll} will depend on the +installation options and the version and language of Windows. In a +``just for me'' installation, it will appear in the root of the +installation directory. In a shared installation, it will be located +in the system directory. + +Then you can create from these information an import library for gcc. + +\begin{verbatim} +/cygwin/bin/dlltool --dllname python25.dll --def python25.def --output-lib libpython25.a +\end{verbatim} + +The resulting library has to be placed in the same directory as +\file{python25.lib}. (Should be the \file{libs} directory under your +Python installation directory.) + +If your extension uses other libraries (zlib,...) you might +have to convert them too. +The converted files have to reside in the same directories as the normal +libraries do. + +To let Distutils compile your extension with Cygwin you now have to type + +\begin{verbatim} +python setup.py build --compiler=cygwin +\end{verbatim} + +and for Cygwin in no-cygwin mode\footnote{Then you have no +\POSIX{} emulation available, but you also don't need +\file{cygwin1.dll}.} or for MinGW type: + +\begin{verbatim} +python setup.py build --compiler=mingw32 +\end{verbatim} + +If you want to use any of these options/compilers as default, you should +consider to write it in your personal or system-wide configuration file +for Distutils (see section~\ref{config-files}.) + +\begin{seealso} + \seetitle[http://www.zope.org/Members/als/tips/win32_mingw_modules] + {Building Python modules on MS Windows platform with MinGW} + {Information about building the required libraries for the MinGW + environment.} + + \seeurl{http://pyopengl.sourceforge.net/ftp/win32-stuff/} + {Converted import libraries in Cygwin/MinGW and Borland format, + and a script to create the registry entries needed for Distutils + to locate the built Python.} +\end{seealso} + + + +\end{document} diff --git a/sys/src/cmd/python/Doc/lib/archiving.tex b/sys/src/cmd/python/Doc/lib/archiving.tex new file mode 100644 index 000000000..93f5bf712 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/archiving.tex @@ -0,0 +1,8 @@ +\chapter{Data Compression and Archiving} +\label{archiving} + +The modules described in this chapter support data compression +with the zlib, gzip, and bzip2 algorithms, and +the creation of ZIP- and tar-format archives. + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/asttable.tex b/sys/src/cmd/python/Doc/lib/asttable.tex new file mode 100644 index 000000000..abba0da12 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/asttable.tex @@ -0,0 +1,283 @@ +\begin{longtableiii}{lll}{class}{Node type}{Attribute}{Value} + +\lineiii{Add}{\member{left}}{left operand} +\lineiii{}{\member{right}}{right operand} +\hline + +\lineiii{And}{\member{nodes}}{list of operands} +\hline + +\lineiii{AssAttr}{}{\emph{attribute as target of assignment}} +\lineiii{}{\member{expr}}{expression on the left-hand side of the dot} +\lineiii{}{\member{attrname}}{the attribute name, a string} +\lineiii{}{\member{flags}}{XXX} +\hline + +\lineiii{AssList}{\member{nodes}}{list of list elements being assigned to} +\hline + +\lineiii{AssName}{\member{name}}{name being assigned to} +\lineiii{}{\member{flags}}{XXX} +\hline + +\lineiii{AssTuple}{\member{nodes}}{list of tuple elements being assigned to} +\hline + +\lineiii{Assert}{\member{test}}{the expression to be tested} +\lineiii{}{\member{fail}}{the value of the \exception{AssertionError}} +\hline + +\lineiii{Assign}{\member{nodes}}{a list of assignment targets, one per equal sign} +\lineiii{}{\member{expr}}{the value being assigned} +\hline + +\lineiii{AugAssign}{\member{node}}{} +\lineiii{}{\member{op}}{} +\lineiii{}{\member{expr}}{} +\hline + +\lineiii{Backquote}{\member{expr}}{} +\hline + +\lineiii{Bitand}{\member{nodes}}{} +\hline + +\lineiii{Bitor}{\member{nodes}}{} +\hline + +\lineiii{Bitxor}{\member{nodes}}{} +\hline + +\lineiii{Break}{}{} +\hline + +\lineiii{CallFunc}{\member{node}}{expression for the callee} +\lineiii{}{\member{args}}{a list of arguments} +\lineiii{}{\member{star_args}}{the extended *-arg value} +\lineiii{}{\member{dstar_args}}{the extended **-arg value} +\hline + +\lineiii{Class}{\member{name}}{the name of the class, a string} +\lineiii{}{\member{bases}}{a list of base classes} +\lineiii{}{\member{doc}}{doc string, a string or \code{None}} +\lineiii{}{\member{code}}{the body of the class statement} +\hline + +\lineiii{Compare}{\member{expr}}{} +\lineiii{}{\member{ops}}{} +\hline + +\lineiii{Const}{\member{value}}{} +\hline + +\lineiii{Continue}{}{} +\hline + +\lineiii{Decorators}{\member{nodes}}{List of function decorator expressions} +\hline + +\lineiii{Dict}{\member{items}}{} +\hline + +\lineiii{Discard}{\member{expr}}{} +\hline + +\lineiii{Div}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{Ellipsis}{}{} +\hline + +\lineiii{Expression}{\member{node}}{} + +\lineiii{Exec}{\member{expr}}{} +\lineiii{}{\member{locals}}{} +\lineiii{}{\member{globals}}{} +\hline + +\lineiii{FloorDiv}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{For}{\member{assign}}{} +\lineiii{}{\member{list}}{} +\lineiii{}{\member{body}}{} +\lineiii{}{\member{else_}}{} +\hline + +\lineiii{From}{\member{modname}}{} +\lineiii{}{\member{names}}{} +\hline + +\lineiii{Function}{\member{decorators}}{\class{Decorators} or \code{None}} +\lineiii{}{\member{name}}{name used in def, a string} +\lineiii{}{\member{argnames}}{list of argument names, as strings} +\lineiii{}{\member{defaults}}{list of default values} +\lineiii{}{\member{flags}}{xxx} +\lineiii{}{\member{doc}}{doc string, a string or \code{None}} +\lineiii{}{\member{code}}{the body of the function} +\hline + +\lineiii{GenExpr}{\member{code}}{} +\hline + +\lineiii{GenExprFor}{\member{assign}}{} +\lineiii{}{\member{iter}}{} +\lineiii{}{\member{ifs}}{} +\hline + +\lineiii{GenExprIf}{\member{test}}{} +\hline + +\lineiii{GenExprInner}{\member{expr}}{} +\lineiii{}{\member{quals}}{} +\hline + +\lineiii{Getattr}{\member{expr}}{} +\lineiii{}{\member{attrname}}{} +\hline + +\lineiii{Global}{\member{names}}{} +\hline + +\lineiii{If}{\member{tests}}{} +\lineiii{}{\member{else_}}{} +\hline + +\lineiii{Import}{\member{names}}{} +\hline + +\lineiii{Invert}{\member{expr}}{} +\hline + +\lineiii{Keyword}{\member{name}}{} +\lineiii{}{\member{expr}}{} +\hline + +\lineiii{Lambda}{\member{argnames}}{} +\lineiii{}{\member{defaults}}{} +\lineiii{}{\member{flags}}{} +\lineiii{}{\member{code}}{} +\hline + +\lineiii{LeftShift}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{List}{\member{nodes}}{} +\hline + +\lineiii{ListComp}{\member{expr}}{} +\lineiii{}{\member{quals}}{} +\hline + +\lineiii{ListCompFor}{\member{assign}}{} +\lineiii{}{\member{list}}{} +\lineiii{}{\member{ifs}}{} +\hline + +\lineiii{ListCompIf}{\member{test}}{} +\hline + +\lineiii{Mod}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{Module}{\member{doc}}{doc string, a string or \code{None}} +\lineiii{}{\member{node}}{body of the module, a \class{Stmt}} +\hline + +\lineiii{Mul}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{Name}{\member{name}}{} +\hline + +\lineiii{Not}{\member{expr}}{} +\hline + +\lineiii{Or}{\member{nodes}}{} +\hline + +\lineiii{Pass}{}{} +\hline + +\lineiii{Power}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{Print}{\member{nodes}}{} +\lineiii{}{\member{dest}}{} +\hline + +\lineiii{Printnl}{\member{nodes}}{} +\lineiii{}{\member{dest}}{} +\hline + +\lineiii{Raise}{\member{expr1}}{} +\lineiii{}{\member{expr2}}{} +\lineiii{}{\member{expr3}}{} +\hline + +\lineiii{Return}{\member{value}}{} +\hline + +\lineiii{RightShift}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{Slice}{\member{expr}}{} +\lineiii{}{\member{flags}}{} +\lineiii{}{\member{lower}}{} +\lineiii{}{\member{upper}}{} +\hline + +\lineiii{Sliceobj}{\member{nodes}}{list of statements} +\hline + +\lineiii{Stmt}{\member{nodes}}{} +\hline + +\lineiii{Sub}{\member{left}}{} +\lineiii{}{\member{right}}{} +\hline + +\lineiii{Subscript}{\member{expr}}{} +\lineiii{}{\member{flags}}{} +\lineiii{}{\member{subs}}{} +\hline + +\lineiii{TryExcept}{\member{body}}{} +\lineiii{}{\member{handlers}}{} +\lineiii{}{\member{else_}}{} +\hline + +\lineiii{TryFinally}{\member{body}}{} +\lineiii{}{\member{final}}{} +\hline + +\lineiii{Tuple}{\member{nodes}}{} +\hline + +\lineiii{UnaryAdd}{\member{expr}}{} +\hline + +\lineiii{UnarySub}{\member{expr}}{} +\hline + +\lineiii{While}{\member{test}}{} +\lineiii{}{\member{body}}{} +\lineiii{}{\member{else_}}{} +\hline + +\lineiii{With}{\member{expr}}{} +\lineiii{}{\member{vars}}{} +\lineiii{}{\member{body}}{} +\hline + +\lineiii{Yield}{\member{value}}{} +\hline + +\end{longtableiii} diff --git a/sys/src/cmd/python/Doc/lib/caseless.py b/sys/src/cmd/python/Doc/lib/caseless.py new file mode 100755 index 000000000..cae94be91 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/caseless.py @@ -0,0 +1,60 @@ +from optparse import Option, OptionParser, _match_abbrev + +# This case-insensitive option parser relies on having a +# case-insensitive dictionary type available. Here's one +# for Python 2.2. Note that a *real* case-insensitive +# dictionary type would also have to implement __new__(), +# update(), and setdefault() -- but that's not the point +# of this exercise. + +class caseless_dict (dict): + def __setitem__ (self, key, value): + dict.__setitem__(self, key.lower(), value) + + def __getitem__ (self, key): + return dict.__getitem__(self, key.lower()) + + def get (self, key, default=None): + return dict.get(self, key.lower()) + + def has_key (self, key): + return dict.has_key(self, key.lower()) + + +class CaselessOptionParser (OptionParser): + + def _create_option_list (self): + self.option_list = [] + self._short_opt = caseless_dict() + self._long_opt = caseless_dict() + self._long_opts = [] + self.defaults = {} + + def _match_long_opt (self, opt): + return _match_abbrev(opt.lower(), self._long_opt.keys()) + + +if __name__ == "__main__": + from optik.errors import OptionConflictError + + # test 1: no options to start with + parser = CaselessOptionParser() + try: + parser.add_option("-H", dest="blah") + except OptionConflictError: + print "ok: got OptionConflictError for -H" + else: + print "not ok: no conflict between -h and -H" + + parser.add_option("-f", "--file", dest="file") + #print repr(parser.get_option("-f")) + #print repr(parser.get_option("-F")) + #print repr(parser.get_option("--file")) + #print repr(parser.get_option("--fIlE")) + (options, args) = parser.parse_args(["--FiLe", "foo"]) + assert options.file == "foo", options.file + print "ok: case insensitive long options work" + + (options, args) = parser.parse_args(["-F", "bar"]) + assert options.file == "bar", options.file + print "ok: case insensitive short options work" diff --git a/sys/src/cmd/python/Doc/lib/compiler.tex b/sys/src/cmd/python/Doc/lib/compiler.tex new file mode 100644 index 000000000..f0926e700 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/compiler.tex @@ -0,0 +1,354 @@ +\chapter{Python compiler package \label{compiler}} + +\sectionauthor{Jeremy Hylton}{jeremy@zope.com} + + +The Python compiler package is a tool for analyzing Python source code +and generating Python bytecode. The compiler contains libraries to +generate an abstract syntax tree from Python source code and to +generate Python bytecode from the tree. + +The \refmodule{compiler} package is a Python source to bytecode +translator written in Python. It uses the built-in parser and +standard \refmodule{parser} module to generated a concrete syntax +tree. This tree is used to generate an abstract syntax tree (AST) and +then Python bytecode. + +The full functionality of the package duplicates the builtin compiler +provided with the Python interpreter. It is intended to match its +behavior almost exactly. Why implement another compiler that does the +same thing? The package is useful for a variety of purposes. It can +be modified more easily than the builtin compiler. The AST it +generates is useful for analyzing Python source code. + +This chapter explains how the various components of the +\refmodule{compiler} package work. It blends reference material with +a tutorial. + +The following modules are part of the \refmodule{compiler} package: + +\localmoduletable + + +\section{The basic interface} + +\declaremodule{}{compiler} + +The top-level of the package defines four functions. If you import +\module{compiler}, you will get these functions and a collection of +modules contained in the package. + +\begin{funcdesc}{parse}{buf} +Returns an abstract syntax tree for the Python source code in \var{buf}. +The function raises \exception{SyntaxError} if there is an error in the +source code. The return value is a \class{compiler.ast.Module} instance +that contains the tree. +\end{funcdesc} + +\begin{funcdesc}{parseFile}{path} +Return an abstract syntax tree for the Python source code in the file +specified by \var{path}. It is equivalent to +\code{parse(open(\var{path}).read())}. +\end{funcdesc} + +\begin{funcdesc}{walk}{ast, visitor\optional{, verbose}} +Do a pre-order walk over the abstract syntax tree \var{ast}. Call the +appropriate method on the \var{visitor} instance for each node +encountered. +\end{funcdesc} + +\begin{funcdesc}{compile}{source, filename, mode, flags=None, + dont_inherit=None} +Compile the string \var{source}, a Python module, statement or +expression, into a code object that can be executed by the exec +statement or \function{eval()}. This function is a replacement for the +built-in \function{compile()} function. + +The \var{filename} will be used for run-time error messages. + +The \var{mode} must be 'exec' to compile a module, 'single' to compile a +single (interactive) statement, or 'eval' to compile an expression. + +The \var{flags} and \var{dont_inherit} arguments affect future-related +statements, but are not supported yet. +\end{funcdesc} + +\begin{funcdesc}{compileFile}{source} +Compiles the file \var{source} and generates a .pyc file. +\end{funcdesc} + +The \module{compiler} package contains the following modules: +\refmodule[compiler.ast]{ast}, \module{consts}, \module{future}, +\module{misc}, \module{pyassem}, \module{pycodegen}, \module{symbols}, +\module{transformer}, and \refmodule[compiler.visitor]{visitor}. + +\section{Limitations} + +There are some problems with the error checking of the compiler +package. The interpreter detects syntax errors in two distinct +phases. One set of errors is detected by the interpreter's parser, +the other set by the compiler. The compiler package relies on the +interpreter's parser, so it get the first phases of error checking for +free. It implements the second phase itself, and that implementation is +incomplete. For example, the compiler package does not raise an error +if a name appears more than once in an argument list: +\code{def f(x, x): ...} + +A future version of the compiler should fix these problems. + +\section{Python Abstract Syntax} + +The \module{compiler.ast} module defines an abstract syntax for +Python. In the abstract syntax tree, each node represents a syntactic +construct. The root of the tree is \class{Module} object. + +The abstract syntax offers a higher level interface to parsed Python +source code. The \ulink{\module{parser}} +{http://www.python.org/doc/current/lib/module-parser.html} +module and the compiler written in C for the Python interpreter use a +concrete syntax tree. The concrete syntax is tied closely to the +grammar description used for the Python parser. Instead of a single +node for a construct, there are often several levels of nested nodes +that are introduced by Python's precedence rules. + +The abstract syntax tree is created by the +\module{compiler.transformer} module. The transformer relies on the +builtin Python parser to generate a concrete syntax tree. It +generates an abstract syntax tree from the concrete tree. + +The \module{transformer} module was created by Greg +Stein\index{Stein, Greg} and Bill Tutt\index{Tutt, Bill} for an +experimental Python-to-C compiler. The current version contains a +number of modifications and improvements, but the basic form of the +abstract syntax and of the transformer are due to Stein and Tutt. + +\subsection{AST Nodes} + +\declaremodule{}{compiler.ast} + +The \module{compiler.ast} module is generated from a text file that +describes each node type and its elements. Each node type is +represented as a class that inherits from the abstract base class +\class{compiler.ast.Node} and defines a set of named attributes for +child nodes. + +\begin{classdesc}{Node}{} + + The \class{Node} instances are created automatically by the parser + generator. The recommended interface for specific \class{Node} + instances is to use the public attributes to access child nodes. A + public attribute may be bound to a single node or to a sequence of + nodes, depending on the \class{Node} type. For example, the + \member{bases} attribute of the \class{Class} node, is bound to a + list of base class nodes, and the \member{doc} attribute is bound to + a single node. + + Each \class{Node} instance has a \member{lineno} attribute which may + be \code{None}. XXX Not sure what the rules are for which nodes + will have a useful lineno. +\end{classdesc} + +All \class{Node} objects offer the following methods: + +\begin{methoddesc}{getChildren}{} + Returns a flattened list of the child nodes and objects in the + order they occur. Specifically, the order of the nodes is the + order in which they appear in the Python grammar. Not all of the + children are \class{Node} instances. The names of functions and + classes, for example, are plain strings. +\end{methoddesc} + +\begin{methoddesc}{getChildNodes}{} + Returns a flattened list of the child nodes in the order they + occur. This method is like \method{getChildren()}, except that it + only returns those children that are \class{Node} instances. +\end{methoddesc} + +Two examples illustrate the general structure of \class{Node} +classes. The \keyword{while} statement is defined by the following +grammar production: + +\begin{verbatim} +while_stmt: "while" expression ":" suite + ["else" ":" suite] +\end{verbatim} + +The \class{While} node has three attributes: \member{test}, +\member{body}, and \member{else_}. (If the natural name for an +attribute is also a Python reserved word, it can't be used as an +attribute name. An underscore is appended to the word to make it a +legal identifier, hence \member{else_} instead of \keyword{else}.) + +The \keyword{if} statement is more complicated because it can include +several tests. + +\begin{verbatim} +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +\end{verbatim} + +The \class{If} node only defines two attributes: \member{tests} and +\member{else_}. The \member{tests} attribute is a sequence of test +expression, consequent body pairs. There is one pair for each +\keyword{if}/\keyword{elif} clause. The first element of the pair is +the test expression. The second elements is a \class{Stmt} node that +contains the code to execute if the test is true. + +The \method{getChildren()} method of \class{If} returns a flat list of +child nodes. If there are three \keyword{if}/\keyword{elif} clauses +and no \keyword{else} clause, then \method{getChildren()} will return +a list of six elements: the first test expression, the first +\class{Stmt}, the second text expression, etc. + +The following table lists each of the \class{Node} subclasses defined +in \module{compiler.ast} and each of the public attributes available +on their instances. The values of most of the attributes are +themselves \class{Node} instances or sequences of instances. When the +value is something other than an instance, the type is noted in the +comment. The attributes are listed in the order in which they are +returned by \method{getChildren()} and \method{getChildNodes()}. + +\input{asttable} + + +\subsection{Assignment nodes} + +There is a collection of nodes used to represent assignments. Each +assignment statement in the source code becomes a single +\class{Assign} node in the AST. The \member{nodes} attribute is a +list that contains a node for each assignment target. This is +necessary because assignment can be chained, e.g. \code{a = b = 2}. +Each \class{Node} in the list will be one of the following classes: +\class{AssAttr}, \class{AssList}, \class{AssName}, or +\class{AssTuple}. + +Each target assignment node will describe the kind of object being +assigned to: \class{AssName} for a simple name, e.g. \code{a = 1}. +\class{AssAttr} for an attribute assigned, e.g. \code{a.x = 1}. +\class{AssList} and \class{AssTuple} for list and tuple expansion +respectively, e.g. \code{a, b, c = a_tuple}. + +The target assignment nodes also have a \member{flags} attribute that +indicates whether the node is being used for assignment or in a delete +statement. The \class{AssName} is also used to represent a delete +statement, e.g. \class{del x}. + +When an expression contains several attribute references, an +assignment or delete statement will contain only one \class{AssAttr} +node -- for the final attribute reference. The other attribute +references will be represented as \class{Getattr} nodes in the +\member{expr} attribute of the \class{AssAttr} instance. + +\subsection{Examples} + +This section shows several simple examples of ASTs for Python source +code. The examples demonstrate how to use the \function{parse()} +function, what the repr of an AST looks like, and how to access +attributes of an AST node. + +The first module defines a single function. Assume it is stored in +\file{/tmp/doublelib.py}. + +\begin{verbatim} +"""This is an example module. + +This is the docstring. +""" + +def double(x): + "Return twice the argument" + return x * 2 +\end{verbatim} + +In the interactive interpreter session below, I have reformatted the +long AST reprs for readability. The AST reprs use unqualified class +names. If you want to create an instance from a repr, you must import +the class names from the \module{compiler.ast} module. + +\begin{verbatim} +>>> import compiler +>>> mod = compiler.parseFile("/tmp/doublelib.py") +>>> mod +Module('This is an example module.\n\nThis is the docstring.\n', + Stmt([Function(None, 'double', ['x'], [], 0, + 'Return twice the argument', + Stmt([Return(Mul((Name('x'), Const(2))))]))])) +>>> from compiler.ast import * +>>> Module('This is an example module.\n\nThis is the docstring.\n', +... Stmt([Function(None, 'double', ['x'], [], 0, +... 'Return twice the argument', +... Stmt([Return(Mul((Name('x'), Const(2))))]))])) +Module('This is an example module.\n\nThis is the docstring.\n', + Stmt([Function(None, 'double', ['x'], [], 0, + 'Return twice the argument', + Stmt([Return(Mul((Name('x'), Const(2))))]))])) +>>> mod.doc +'This is an example module.\n\nThis is the docstring.\n' +>>> for node in mod.node.nodes: +... print node +... +Function(None, 'double', ['x'], [], 0, 'Return twice the argument', + Stmt([Return(Mul((Name('x'), Const(2))))])) +>>> func = mod.node.nodes[0] +>>> func.code +Stmt([Return(Mul((Name('x'), Const(2))))]) +\end{verbatim} + +\section{Using Visitors to Walk ASTs} + +\declaremodule{}{compiler.visitor} + +The visitor pattern is ... The \refmodule{compiler} package uses a +variant on the visitor pattern that takes advantage of Python's +introspection features to eliminate the need for much of the visitor's +infrastructure. + +The classes being visited do not need to be programmed to accept +visitors. The visitor need only define visit methods for classes it +is specifically interested in; a default visit method can handle the +rest. + +XXX The magic \method{visit()} method for visitors. + +\begin{funcdesc}{walk}{tree, visitor\optional{, verbose}} +\end{funcdesc} + +\begin{classdesc}{ASTVisitor}{} + +The \class{ASTVisitor} is responsible for walking over the tree in the +correct order. A walk begins with a call to \method{preorder()}. For +each node, it checks the \var{visitor} argument to \method{preorder()} +for a method named `visitNodeType,' where NodeType is the name of the +node's class, e.g. for a \class{While} node a \method{visitWhile()} +would be called. If the method exists, it is called with the node as +its first argument. + +The visitor method for a particular node type can control how child +nodes are visited during the walk. The \class{ASTVisitor} modifies +the visitor argument by adding a visit method to the visitor; this +method can be used to visit a particular child node. If no visitor is +found for a particular node type, the \method{default()} method is +called. +\end{classdesc} + +\class{ASTVisitor} objects have the following methods: + +XXX describe extra arguments + +\begin{methoddesc}{default}{node\optional{, \moreargs}} +\end{methoddesc} + +\begin{methoddesc}{dispatch}{node\optional{, \moreargs}} +\end{methoddesc} + +\begin{methoddesc}{preorder}{tree, visitor} +\end{methoddesc} + + +\section{Bytecode Generation} + +The code generator is a visitor that emits bytecodes. Each visit method +can call the \method{emit()} method to emit a new bytecode. The basic +code generator is specialized for modules, classes, and functions. An +assembler converts that emitted instructions to the low-level bytecode +format. It handles things like generator of constant lists of code +objects and calculation of jump offsets. diff --git a/sys/src/cmd/python/Doc/lib/custominterp.tex b/sys/src/cmd/python/Doc/lib/custominterp.tex new file mode 100644 index 000000000..555b888da --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/custominterp.tex @@ -0,0 +1,13 @@ +\chapter{Custom Python Interpreters} +\label{custominterp} + +The modules described in this chapter allow writing interfaces similar +to Python's interactive interpreter. If you want a Python interpreter +that supports some special feature in addition to the Python language, +you should look at the \module{code} module. (The \module{codeop} +module is lower-level, used to support compiling a possibly-incomplete +chunk of Python code.) + +The full list of modules described in this chapter is: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/datatypes.tex b/sys/src/cmd/python/Doc/lib/datatypes.tex new file mode 100644 index 000000000..0fe03c750 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/datatypes.tex @@ -0,0 +1,10 @@ +\chapter{Data Types} +\label{datatypes} + +The modules described in this chapter provide a variety of specialized +data types such as dates and times, fixed-type arrays, heap queues, +synchronized queues, and sets. + +The following modules are documented in this chapter: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/development.tex b/sys/src/cmd/python/Doc/lib/development.tex new file mode 100644 index 000000000..4b4fadcb4 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/development.tex @@ -0,0 +1,13 @@ +\chapter{Development Tools} +\label{development} + +The modules described in this chapter help you write software. For +example, the \module{pydoc} module takes a module and generates +documentation based on the module's contents. The \module{doctest} +and \module{unittest} modules contains frameworks for writing unit tests +that automatically exercise code and verify that the expected output +is produced. + +The list of modules described in this chapter is: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/distutils.tex b/sys/src/cmd/python/Doc/lib/distutils.tex new file mode 100644 index 000000000..3de9ddec9 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/distutils.tex @@ -0,0 +1,38 @@ +\section{\module{distutils} --- + Building and installing Python modules} + +\declaremodule{standard}{distutils} +\modulesynopsis{Support for building and installing Python modules + into an existing Python installation.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + + +The \module{distutils} package provides support for building and +installing additional modules into a Python installation. The new +modules may be either 100\%{}-pure Python, or may be extension modules +written in C, or may be collections of Python packages which include +modules coded in both Python and C. + +This package is discussed in two separate documents which are included +in the Python documentation package. To learn about distributing new +modules using the \module{distutils} facilities, read +\citetitle[../dist/dist.html]{Distributing Python Modules}; this +includes documentation needed to extend distutils. To learn +about installing Python modules, whether or not the author made use of +the \module{distutils} package, read +\citetitle[../inst/inst.html]{Installing Python Modules}. + + +\begin{seealso} + \seetitle[../dist/dist.html]{Distributing Python Modules}{The manual + for developers and packagers of Python modules. This + describes how to prepare \module{distutils}-based packages + so that they may be easily installed into an existing + Python installation.} + + \seetitle[../inst/inst.html]{Installing Python Modules}{An + ``administrators'' manual which includes information on + installing modules into an existing Python installation. + You do not need to be a Python programmer to read this + manual.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/email-dir.py b/sys/src/cmd/python/Doc/lib/email-dir.py new file mode 100644 index 000000000..c04f57d64 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/email-dir.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +"""Send the contents of a directory as a MIME message.""" + +import os +import sys +import smtplib +# For guessing MIME type based on file name extension +import mimetypes + +from optparse import OptionParser + +from email import encoders +from email.message import Message +from email.mime.audio import MIMEAudio +from email.mime.base import MIMEBase +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +COMMASPACE = ', ' + + +def main(): + parser = OptionParser(usage="""\ +Send the contents of a directory as a MIME message. + +Usage: %prog [options] + +Unless the -o option is given, the email is sent by forwarding to your local +SMTP server, which then does the normal delivery process. Your local machine +must be running an SMTP server. +""") + parser.add_option('-d', '--directory', + type='string', action='store', + help="""Mail the contents of the specified directory, + otherwise use the current directory. Only the regular + files in the directory are sent, and we don't recurse to + subdirectories.""") + parser.add_option('-o', '--output', + type='string', action='store', metavar='FILE', + help="""Print the composed message to FILE instead of + sending the message to the SMTP server.""") + parser.add_option('-s', '--sender', + type='string', action='store', metavar='SENDER', + help='The value of the From: header (required)') + parser.add_option('-r', '--recipient', + type='string', action='append', metavar='RECIPIENT', + default=[], dest='recipients', + help='A To: header value (at least one required)') + opts, args = parser.parse_args() + if not opts.sender or not opts.recipients: + parser.print_help() + sys.exit(1) + directory = opts.directory + if not directory: + directory = '.' + # Create the enclosing (outer) message + outer = MIMEMultipart() + outer['Subject'] = 'Contents of directory %s' % os.path.abspath(directory) + outer['To'] = COMMASPACE.join(opts.recipients) + outer['From'] = opts.sender + outer.preamble = 'You will not see this in a MIME-aware mail reader.\n' + + for filename in os.listdir(directory): + path = os.path.join(directory, filename) + if not os.path.isfile(path): + continue + # Guess the content type based on the file's extension. Encoding + # will be ignored, although we should check for simple things like + # gzip'd or compressed files. + ctype, encoding = mimetypes.guess_type(path) + if ctype is None or encoding is not None: + # No guess could be made, or the file is encoded (compressed), so + # use a generic bag-of-bits type. + ctype = 'application/octet-stream' + maintype, subtype = ctype.split('/', 1) + if maintype == 'text': + fp = open(path) + # Note: we should handle calculating the charset + msg = MIMEText(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'image': + fp = open(path, 'rb') + msg = MIMEImage(fp.read(), _subtype=subtype) + fp.close() + elif maintype == 'audio': + fp = open(path, 'rb') + msg = MIMEAudio(fp.read(), _subtype=subtype) + fp.close() + else: + fp = open(path, 'rb') + msg = MIMEBase(maintype, subtype) + msg.set_payload(fp.read()) + fp.close() + # Encode the payload using Base64 + encoders.encode_base64(msg) + # Set the filename parameter + msg.add_header('Content-Disposition', 'attachment', filename=filename) + outer.attach(msg) + # Now send or store the message + composed = outer.as_string() + if opts.output: + fp = open(opts.output, 'w') + fp.write(composed) + fp.close() + else: + s = smtplib.SMTP() + s.connect() + s.sendmail(opts.sender, opts.recipients, composed) + s.close() + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Doc/lib/email-mime.py b/sys/src/cmd/python/Doc/lib/email-mime.py new file mode 100644 index 000000000..509725374 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/email-mime.py @@ -0,0 +1,32 @@ +# Import smtplib for the actual sending function +import smtplib + +# Here are the email package modules we'll need +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart + +COMMASPACE = ', ' + +# Create the container (outer) email message. +msg = MIMEMultipart() +msg['Subject'] = 'Our family reunion' +# me == the sender's email address +# family = the list of all recipients' email addresses +msg['From'] = me +msg['To'] = COMMASPACE.join(family) +msg.preamble = 'Our family reunion' + +# Assume we know that the image files are all in PNG format +for file in pngfiles: + # Open the files in binary mode. Let the MIMEImage class automatically + # guess the specific image type. + fp = open(file, 'rb') + img = MIMEImage(fp.read()) + fp.close() + msg.attach(img) + +# Send the email via our own SMTP server. +s = smtplib.SMTP() +s.connect() +s.sendmail(me, family, msg.as_string()) +s.close() diff --git a/sys/src/cmd/python/Doc/lib/email-simple.py b/sys/src/cmd/python/Doc/lib/email-simple.py new file mode 100644 index 000000000..44152a483 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/email-simple.py @@ -0,0 +1,25 @@ +# Import smtplib for the actual sending function +import smtplib + +# Import the email modules we'll need +from email.mime.text import MIMEText + +# Open a plain text file for reading. For this example, assume that +# the text file contains only ASCII characters. +fp = open(textfile, 'rb') +# Create a text/plain message +msg = MIMEText(fp.read()) +fp.close() + +# me == the sender's email address +# you == the recipient's email address +msg['Subject'] = 'The contents of %s' % textfile +msg['From'] = me +msg['To'] = you + +# Send the message via our own SMTP server, but don't include the +# envelope header. +s = smtplib.SMTP() +s.connect() +s.sendmail(me, [you], msg.as_string()) +s.close() diff --git a/sys/src/cmd/python/Doc/lib/email-unpack.py b/sys/src/cmd/python/Doc/lib/email-unpack.py new file mode 100644 index 000000000..fc05d9910 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/email-unpack.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +"""Unpack a MIME message into a directory of files.""" + +import os +import sys +import email +import errno +import mimetypes + +from optparse import OptionParser + + +def main(): + parser = OptionParser(usage="""\ +Unpack a MIME message into a directory of files. + +Usage: %prog [options] msgfile +""") + parser.add_option('-d', '--directory', + type='string', action='store', + help="""Unpack the MIME message into the named + directory, which will be created if it doesn't already + exist.""") + opts, args = parser.parse_args() + if not opts.directory: + parser.print_help() + sys.exit(1) + + try: + msgfile = args[0] + except IndexError: + parser.print_help() + sys.exit(1) + + try: + os.mkdir(opts.directory) + except OSError, e: + # Ignore directory exists error + if e.errno <> errno.EEXIST: + raise + + fp = open(msgfile) + msg = email.message_from_file(fp) + fp.close() + + counter = 1 + for part in msg.walk(): + # multipart/* are just containers + if part.get_content_maintype() == 'multipart': + continue + # Applications should really sanitize the given filename so that an + # email message can't be used to overwrite important files + filename = part.get_filename() + if not filename: + ext = mimetypes.guess_extension(part.get_type()) + if not ext: + # Use a generic bag-of-bits extension + ext = '.bin' + filename = 'part-%03d%s' % (counter, ext) + counter += 1 + fp = open(os.path.join(opts.directory, filename), 'wb') + fp.write(part.get_payload(decode=True)) + fp.close() + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Doc/lib/email.tex b/sys/src/cmd/python/Doc/lib/email.tex new file mode 100644 index 000000000..ea12705d4 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/email.tex @@ -0,0 +1,402 @@ +% Copyright (C) 2001-2006 Python Software Foundation +% Author: barry@python.org (Barry Warsaw) + +\section{\module{email} --- + An email and MIME handling package} + +\declaremodule{standard}{email} +\modulesynopsis{Package supporting the parsing, manipulating, and + generating email messages, including MIME documents.} +\moduleauthor{Barry A. Warsaw}{barry@python.org} +\sectionauthor{Barry A. Warsaw}{barry@python.org} + +\versionadded{2.2} + +The \module{email} package is a library for managing email messages, +including MIME and other \rfc{2822}-based message documents. It +subsumes most of the functionality in several older standard modules +such as \refmodule{rfc822}, \refmodule{mimetools}, +\refmodule{multifile}, and other non-standard packages such as +\module{mimecntl}. It is specifically \emph{not} designed to do any +sending of email messages to SMTP (\rfc{2821}), NNTP, or other servers; those +are functions of modules such as \refmodule{smtplib} and \refmodule{nntplib}. +The \module{email} package attempts to be as RFC-compliant as possible, +supporting in addition to \rfc{2822}, such MIME-related RFCs as +\rfc{2045}, \rfc{2046}, \rfc{2047}, and \rfc{2231}. + +The primary distinguishing feature of the \module{email} package is +that it splits the parsing and generating of email messages from the +internal \emph{object model} representation of email. Applications +using the \module{email} package deal primarily with objects; you can +add sub-objects to messages, remove sub-objects from messages, +completely re-arrange the contents, etc. There is a separate parser +and a separate generator which handles the transformation from flat +text to the object model, and then back to flat text again. There +are also handy subclasses for some common MIME object types, and a few +miscellaneous utilities that help with such common tasks as extracting +and parsing message field values, creating RFC-compliant dates, etc. + +The following sections describe the functionality of the +\module{email} package. The ordering follows a progression that +should be common in applications: an email message is read as flat +text from a file or other source, the text is parsed to produce the +object structure of the email message, this structure is manipulated, +and finally, the object tree is rendered back into flat text. + +It is perfectly feasible to create the object structure out of whole +cloth --- i.e. completely from scratch. From there, a similar +progression can be taken as above. + +Also included are detailed specifications of all the classes and +modules that the \module{email} package provides, the exception +classes you might encounter while using the \module{email} package, +some auxiliary utilities, and a few examples. For users of the older +\module{mimelib} package, or previous versions of the \module{email} +package, a section on differences and porting is provided. + +\begin{seealso} + \seemodule{smtplib}{SMTP protocol client} + \seemodule{nntplib}{NNTP protocol client} +\end{seealso} + +\subsection{Representing an email message} +\input{emailmessage} + +\subsection{Parsing email messages} +\input{emailparser} + +\subsection{Generating MIME documents} +\input{emailgenerator} + +\subsection{Creating email and MIME objects from scratch} +\input{emailmimebase} + +\subsection{Internationalized headers} +\input{emailheaders} + +\subsection{Representing character sets} +\input{emailcharsets} + +\subsection{Encoders} +\input{emailencoders} + +\subsection{Exception and Defect classes} +\input{emailexc} + +\subsection{Miscellaneous utilities} +\input{emailutil} + +\subsection{Iterators} +\input{emailiter} + +\subsection{Package History\label{email-pkg-history}} + +This table describes the release history of the email package, corresponding +to the version of Python that the package was released with. For purposes of +this document, when you see a note about change or added versions, these refer +to the Python version the change was made it, \emph{not} the email package +version. This table also describes the Python compatibility of each version +of the package. + +\begin{tableiii}{l|l|l}{constant}{email version}{distributed with}{compatible with} +\lineiii{1.x}{Python 2.2.0 to Python 2.2.1}{\emph{no longer supported}} +\lineiii{2.5}{Python 2.2.2+ and Python 2.3}{Python 2.1 to 2.5} +\lineiii{3.0}{Python 2.4}{Python 2.3 to 2.5} +\lineiii{4.0}{Python 2.5}{Python 2.3 to 2.5} +\end{tableiii} + +Here are the major differences between \module{email} version 4 and version 3: + +\begin{itemize} +\item All modules have been renamed according to \pep{8} standards. For + example, the version 3 module \module{email.Message} was renamed to + \module{email.message} in version 4. + +\item A new subpackage \module{email.mime} was added and all the version 3 + \module{email.MIME*} modules were renamed and situated into the + \module{email.mime} subpackage. For example, the version 3 module + \module{email.MIMEText} was renamed to \module{email.mime.text}. + + \emph{Note that the version 3 names will continue to work until Python + 2.6}. + +\item The \module{email.mime.application} module was added, which contains the + \class{MIMEApplication} class. + +\item Methods that were deprecated in version 3 have been removed. These + include \method{Generator.__call__()}, \method{Message.get_type()}, + \method{Message.get_main_type()}, \method{Message.get_subtype()}. + +\item Fixes have been added for \rfc{2231} support which can change some of + the return types for \function{Message.get_param()} and friends. Under + some circumstances, values which used to return a 3-tuple now return + simple strings (specifically, if all extended parameter segments were + unencoded, there is no language and charset designation expected, so the + return type is now a simple string). Also, \%-decoding used to be done + for both encoded and unencoded segments; this decoding is now done only + for encoded segments. +\end{itemize} + +Here are the major differences between \module{email} version 3 and version 2: + +\begin{itemize} +\item The \class{FeedParser} class was introduced, and the \class{Parser} + class was implemented in terms of the \class{FeedParser}. All parsing + therefore is non-strict, and parsing will make a best effort never to + raise an exception. Problems found while parsing messages are stored in + the message's \var{defect} attribute. + +\item All aspects of the API which raised \exception{DeprecationWarning}s in + version 2 have been removed. These include the \var{_encoder} argument + to the \class{MIMEText} constructor, the \method{Message.add_payload()} + method, the \function{Utils.dump_address_pair()} function, and the + functions \function{Utils.decode()} and \function{Utils.encode()}. + +\item New \exception{DeprecationWarning}s have been added to: + \method{Generator.__call__()}, \method{Message.get_type()}, + \method{Message.get_main_type()}, \method{Message.get_subtype()}, and + the \var{strict} argument to the \class{Parser} class. These are + expected to be removed in future versions. + +\item Support for Pythons earlier than 2.3 has been removed. +\end{itemize} + +Here are the differences between \module{email} version 2 and version 1: + +\begin{itemize} +\item The \module{email.Header} and \module{email.Charset} modules + have been added. + +\item The pickle format for \class{Message} instances has changed. + Since this was never (and still isn't) formally defined, this + isn't considered a backward incompatibility. However if your + application pickles and unpickles \class{Message} instances, be + aware that in \module{email} version 2, \class{Message} + instances now have private variables \var{_charset} and + \var{_default_type}. + +\item Several methods in the \class{Message} class have been + deprecated, or their signatures changed. Also, many new methods + have been added. See the documentation for the \class{Message} + class for details. The changes should be completely backward + compatible. + +\item The object structure has changed in the face of + \mimetype{message/rfc822} content types. In \module{email} + version 1, such a type would be represented by a scalar payload, + i.e. the container message's \method{is_multipart()} returned + false, \method{get_payload()} was not a list object, but a single + \class{Message} instance. + + This structure was inconsistent with the rest of the package, so + the object representation for \mimetype{message/rfc822} content + types was changed. In \module{email} version 2, the container + \emph{does} return \code{True} from \method{is_multipart()}, and + \method{get_payload()} returns a list containing a single + \class{Message} item. + + Note that this is one place that backward compatibility could + not be completely maintained. However, if you're already + testing the return type of \method{get_payload()}, you should be + fine. You just need to make sure your code doesn't do a + \method{set_payload()} with a \class{Message} instance on a + container with a content type of \mimetype{message/rfc822}. + +\item The \class{Parser} constructor's \var{strict} argument was + added, and its \method{parse()} and \method{parsestr()} methods + grew a \var{headersonly} argument. The \var{strict} flag was + also added to functions \function{email.message_from_file()} + and \function{email.message_from_string()}. + +\item \method{Generator.__call__()} is deprecated; use + \method{Generator.flatten()} instead. The \class{Generator} + class has also grown the \method{clone()} method. + +\item The \class{DecodedGenerator} class in the + \module{email.Generator} module was added. + +\item The intermediate base classes \class{MIMENonMultipart} and + \class{MIMEMultipart} have been added, and interposed in the + class hierarchy for most of the other MIME-related derived + classes. + +\item The \var{_encoder} argument to the \class{MIMEText} constructor + has been deprecated. Encoding now happens implicitly based + on the \var{_charset} argument. + +\item The following functions in the \module{email.Utils} module have + been deprecated: \function{dump_address_pairs()}, + \function{decode()}, and \function{encode()}. The following + functions have been added to the module: + \function{make_msgid()}, \function{decode_rfc2231()}, + \function{encode_rfc2231()}, and \function{decode_params()}. + +\item The non-public function \function{email.Iterators._structure()} + was added. +\end{itemize} + +\subsection{Differences from \module{mimelib}} + +The \module{email} package was originally prototyped as a separate +library called +\ulink{\module{mimelib}}{http://mimelib.sf.net/}. +Changes have been made so that +method names are more consistent, and some methods or modules have +either been added or removed. The semantics of some of the methods +have also changed. For the most part, any functionality available in +\module{mimelib} is still available in the \refmodule{email} package, +albeit often in a different way. Backward compatibility between +the \module{mimelib} package and the \module{email} package was not a +priority. + +Here is a brief description of the differences between the +\module{mimelib} and the \refmodule{email} packages, along with hints on +how to port your applications. + +Of course, the most visible difference between the two packages is +that the package name has been changed to \refmodule{email}. In +addition, the top-level package has the following differences: + +\begin{itemize} +\item \function{messageFromString()} has been renamed to + \function{message_from_string()}. + +\item \function{messageFromFile()} has been renamed to + \function{message_from_file()}. + +\end{itemize} + +The \class{Message} class has the following differences: + +\begin{itemize} +\item The method \method{asString()} was renamed to \method{as_string()}. + +\item The method \method{ismultipart()} was renamed to + \method{is_multipart()}. + +\item The \method{get_payload()} method has grown a \var{decode} + optional argument. + +\item The method \method{getall()} was renamed to \method{get_all()}. + +\item The method \method{addheader()} was renamed to \method{add_header()}. + +\item The method \method{gettype()} was renamed to \method{get_type()}. + +\item The method \method{getmaintype()} was renamed to + \method{get_main_type()}. + +\item The method \method{getsubtype()} was renamed to + \method{get_subtype()}. + +\item The method \method{getparams()} was renamed to + \method{get_params()}. + Also, whereas \method{getparams()} returned a list of strings, + \method{get_params()} returns a list of 2-tuples, effectively + the key/value pairs of the parameters, split on the \character{=} + sign. + +\item The method \method{getparam()} was renamed to \method{get_param()}. + +\item The method \method{getcharsets()} was renamed to + \method{get_charsets()}. + +\item The method \method{getfilename()} was renamed to + \method{get_filename()}. + +\item The method \method{getboundary()} was renamed to + \method{get_boundary()}. + +\item The method \method{setboundary()} was renamed to + \method{set_boundary()}. + +\item The method \method{getdecodedpayload()} was removed. To get + similar functionality, pass the value 1 to the \var{decode} flag + of the {get_payload()} method. + +\item The method \method{getpayloadastext()} was removed. Similar + functionality + is supported by the \class{DecodedGenerator} class in the + \refmodule{email.generator} module. + +\item The method \method{getbodyastext()} was removed. You can get + similar functionality by creating an iterator with + \function{typed_subpart_iterator()} in the + \refmodule{email.iterators} module. +\end{itemize} + +The \class{Parser} class has no differences in its public interface. +It does have some additional smarts to recognize +\mimetype{message/delivery-status} type messages, which it represents as +a \class{Message} instance containing separate \class{Message} +subparts for each header block in the delivery status +notification\footnote{Delivery Status Notifications (DSN) are defined +in \rfc{1894}.}. + +The \class{Generator} class has no differences in its public +interface. There is a new class in the \refmodule{email.generator} +module though, called \class{DecodedGenerator} which provides most of +the functionality previously available in the +\method{Message.getpayloadastext()} method. + +The following modules and classes have been changed: + +\begin{itemize} +\item The \class{MIMEBase} class constructor arguments \var{_major} + and \var{_minor} have changed to \var{_maintype} and + \var{_subtype} respectively. + +\item The \code{Image} class/module has been renamed to + \code{MIMEImage}. The \var{_minor} argument has been renamed to + \var{_subtype}. + +\item The \code{Text} class/module has been renamed to + \code{MIMEText}. The \var{_minor} argument has been renamed to + \var{_subtype}. + +\item The \code{MessageRFC822} class/module has been renamed to + \code{MIMEMessage}. Note that an earlier version of + \module{mimelib} called this class/module \code{RFC822}, but + that clashed with the Python standard library module + \refmodule{rfc822} on some case-insensitive file systems. + + Also, the \class{MIMEMessage} class now represents any kind of + MIME message with main type \mimetype{message}. It takes an + optional argument \var{_subtype} which is used to set the MIME + subtype. \var{_subtype} defaults to \mimetype{rfc822}. +\end{itemize} + +\module{mimelib} provided some utility functions in its +\module{address} and \module{date} modules. All of these functions +have been moved to the \refmodule{email.utils} module. + +The \code{MsgReader} class/module has been removed. Its functionality +is most closely supported in the \function{body_line_iterator()} +function in the \refmodule{email.iterators} module. + +\subsection{Examples} + +Here are a few examples of how to use the \module{email} package to +read, write, and send simple email messages, as well as more complex +MIME messages. + +First, let's see how to create and send a simple text message: + +\verbatiminput{email-simple.py} + +Here's an example of how to send a MIME message containing a bunch of +family pictures that may be residing in a directory: + +\verbatiminput{email-mime.py} + +Here's an example of how to send the entire contents of a directory as +an email message: +\footnote{Thanks to Matthew Dixon Cowles for the original inspiration + and examples.} + +\verbatiminput{email-dir.py} + +And finally, here's an example of how to unpack a MIME message like +the one above, into a directory of files: + +\verbatiminput{email-unpack.py} diff --git a/sys/src/cmd/python/Doc/lib/emailcharsets.tex b/sys/src/cmd/python/Doc/lib/emailcharsets.tex new file mode 100644 index 000000000..e0be68ab7 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailcharsets.tex @@ -0,0 +1,244 @@ +\declaremodule{standard}{email.charset} +\modulesynopsis{Character Sets} + +This module provides a class \class{Charset} for representing +character sets and character set conversions in email messages, as +well as a character set registry and several convenience methods for +manipulating this registry. Instances of \class{Charset} are used in +several other modules within the \module{email} package. + +Import this class from the \module{email.charset} module. + +\versionadded{2.2.2} + +\begin{classdesc}{Charset}{\optional{input_charset}} +Map character sets to their email properties. + +This class provides information about the requirements imposed on +email for a specific character set. It also provides convenience +routines for converting between character sets, given the availability +of the applicable codecs. Given a character set, it will do its best +to provide information on how to use that character set in an email +message in an RFC-compliant way. + +Certain character sets must be encoded with quoted-printable or base64 +when used in email headers or bodies. Certain character sets must be +converted outright, and are not allowed in email. + +Optional \var{input_charset} is as described below; it is always +coerced to lower case. After being alias normalized it is also used +as a lookup into the registry of character sets to find out the header +encoding, body encoding, and output conversion codec to be used for +the character set. For example, if +\var{input_charset} is \code{iso-8859-1}, then headers and bodies will +be encoded using quoted-printable and no output conversion codec is +necessary. If \var{input_charset} is \code{euc-jp}, then headers will +be encoded with base64, bodies will not be encoded, but output text +will be converted from the \code{euc-jp} character set to the +\code{iso-2022-jp} character set. +\end{classdesc} + +\class{Charset} instances have the following data attributes: + +\begin{datadesc}{input_charset} +The initial character set specified. Common aliases are converted to +their \emph{official} email names (e.g. \code{latin_1} is converted to +\code{iso-8859-1}). Defaults to 7-bit \code{us-ascii}. +\end{datadesc} + +\begin{datadesc}{header_encoding} +If the character set must be encoded before it can be used in an +email header, this attribute will be set to \code{Charset.QP} (for +quoted-printable), \code{Charset.BASE64} (for base64 encoding), or +\code{Charset.SHORTEST} for the shortest of QP or BASE64 encoding. +Otherwise, it will be \code{None}. +\end{datadesc} + +\begin{datadesc}{body_encoding} +Same as \var{header_encoding}, but describes the encoding for the +mail message's body, which indeed may be different than the header +encoding. \code{Charset.SHORTEST} is not allowed for +\var{body_encoding}. +\end{datadesc} + +\begin{datadesc}{output_charset} +Some character sets must be converted before they can be used in +email headers or bodies. If the \var{input_charset} is one of +them, this attribute will contain the name of the character set +output will be converted to. Otherwise, it will be \code{None}. +\end{datadesc} + +\begin{datadesc}{input_codec} +The name of the Python codec used to convert the \var{input_charset} to +Unicode. If no conversion codec is necessary, this attribute will be +\code{None}. +\end{datadesc} + +\begin{datadesc}{output_codec} +The name of the Python codec used to convert Unicode to the +\var{output_charset}. If no conversion codec is necessary, this +attribute will have the same value as the \var{input_codec}. +\end{datadesc} + +\class{Charset} instances also have the following methods: + +\begin{methoddesc}[Charset]{get_body_encoding}{} +Return the content transfer encoding used for body encoding. + +This is either the string \samp{quoted-printable} or \samp{base64} +depending on the encoding used, or it is a function, in which case you +should call the function with a single argument, the Message object +being encoded. The function should then set the +\mailheader{Content-Transfer-Encoding} header itself to whatever is +appropriate. + +Returns the string \samp{quoted-printable} if +\var{body_encoding} is \code{QP}, returns the string +\samp{base64} if \var{body_encoding} is \code{BASE64}, and returns the +string \samp{7bit} otherwise. +\end{methoddesc} + +\begin{methoddesc}{convert}{s} +Convert the string \var{s} from the \var{input_codec} to the +\var{output_codec}. +\end{methoddesc} + +\begin{methoddesc}{to_splittable}{s} +Convert a possibly multibyte string to a safely splittable format. +\var{s} is the string to split. + +Uses the \var{input_codec} to try and convert the string to Unicode, +so it can be safely split on character boundaries (even for multibyte +characters). + +Returns the string as-is if it isn't known how to convert \var{s} to +Unicode with the \var{input_charset}. + +Characters that could not be converted to Unicode will be replaced +with the Unicode replacement character \character{U+FFFD}. +\end{methoddesc} + +\begin{methoddesc}{from_splittable}{ustr\optional{, to_output}} +Convert a splittable string back into an encoded string. \var{ustr} +is a Unicode string to ``unsplit''. + +This method uses the proper codec to try and convert the string from +Unicode back into an encoded format. Return the string as-is if it is +not Unicode, or if it could not be converted from Unicode. + +Characters that could not be converted from Unicode will be replaced +with an appropriate character (usually \character{?}). + +If \var{to_output} is \code{True} (the default), uses +\var{output_codec} to convert to an +encoded format. If \var{to_output} is \code{False}, it uses +\var{input_codec}. +\end{methoddesc} + +\begin{methoddesc}{get_output_charset}{} +Return the output character set. + +This is the \var{output_charset} attribute if that is not \code{None}, +otherwise it is \var{input_charset}. +\end{methoddesc} + +\begin{methoddesc}{encoded_header_len}{} +Return the length of the encoded header string, properly calculating +for quoted-printable or base64 encoding. +\end{methoddesc} + +\begin{methoddesc}{header_encode}{s\optional{, convert}} +Header-encode the string \var{s}. + +If \var{convert} is \code{True}, the string will be converted from the +input charset to the output charset automatically. This is not useful +for multibyte character sets, which have line length issues (multibyte +characters must be split on a character, not a byte boundary); use the +higher-level \class{Header} class to deal with these issues (see +\refmodule{email.header}). \var{convert} defaults to \code{False}. + +The type of encoding (base64 or quoted-printable) will be based on +the \var{header_encoding} attribute. +\end{methoddesc} + +\begin{methoddesc}{body_encode}{s\optional{, convert}} +Body-encode the string \var{s}. + +If \var{convert} is \code{True} (the default), the string will be +converted from the input charset to output charset automatically. +Unlike \method{header_encode()}, there are no issues with byte +boundaries and multibyte charsets in email bodies, so this is usually +pretty safe. + +The type of encoding (base64 or quoted-printable) will be based on +the \var{body_encoding} attribute. +\end{methoddesc} + +The \class{Charset} class also provides a number of methods to support +standard operations and built-in functions. + +\begin{methoddesc}[Charset]{__str__}{} +Returns \var{input_charset} as a string coerced to lower case. +\method{__repr__()} is an alias for \method{__str__()}. +\end{methoddesc} + +\begin{methoddesc}[Charset]{__eq__}{other} +This method allows you to compare two \class{Charset} instances for equality. +\end{methoddesc} + +\begin{methoddesc}[Header]{__ne__}{other} +This method allows you to compare two \class{Charset} instances for inequality. +\end{methoddesc} + +The \module{email.charset} module also provides the following +functions for adding new entries to the global character set, alias, +and codec registries: + +\begin{funcdesc}{add_charset}{charset\optional{, header_enc\optional{, + body_enc\optional{, output_charset}}}} +Add character properties to the global registry. + +\var{charset} is the input character set, and must be the canonical +name of a character set. + +Optional \var{header_enc} and \var{body_enc} is either +\code{Charset.QP} for quoted-printable, \code{Charset.BASE64} for +base64 encoding, \code{Charset.SHORTEST} for the shortest of +quoted-printable or base64 encoding, or \code{None} for no encoding. +\code{SHORTEST} is only valid for \var{header_enc}. The default is +\code{None} for no encoding. + +Optional \var{output_charset} is the character set that the output +should be in. Conversions will proceed from input charset, to +Unicode, to the output charset when the method +\method{Charset.convert()} is called. The default is to output in the +same character set as the input. + +Both \var{input_charset} and \var{output_charset} must have Unicode +codec entries in the module's character set-to-codec mapping; use +\function{add_codec()} to add codecs the module does +not know about. See the \refmodule{codecs} module's documentation for +more information. + +The global character set registry is kept in the module global +dictionary \code{CHARSETS}. +\end{funcdesc} + +\begin{funcdesc}{add_alias}{alias, canonical} +Add a character set alias. \var{alias} is the alias name, +e.g. \code{latin-1}. \var{canonical} is the character set's canonical +name, e.g. \code{iso-8859-1}. + +The global charset alias registry is kept in the module global +dictionary \code{ALIASES}. +\end{funcdesc} + +\begin{funcdesc}{add_codec}{charset, codecname} +Add a codec that map characters in the given character set to and from +Unicode. + +\var{charset} is the canonical name of a character set. +\var{codecname} is the name of a Python codec, as appropriate for the +second argument to the \function{unicode()} built-in, or to the +\method{encode()} method of a Unicode string. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/emailencoders.tex b/sys/src/cmd/python/Doc/lib/emailencoders.tex new file mode 100644 index 000000000..3d05c2ac3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailencoders.tex @@ -0,0 +1,47 @@ +\declaremodule{standard}{email.encoders} +\modulesynopsis{Encoders for email message payloads.} + +When creating \class{Message} objects from scratch, you often need to +encode the payloads for transport through compliant mail servers. +This is especially true for \mimetype{image/*} and \mimetype{text/*} +type messages containing binary data. + +The \module{email} package provides some convenient encodings in its +\module{encoders} module. These encoders are actually used by the +\class{MIMEAudio} and \class{MIMEImage} class constructors to provide default +encodings. All encoder functions take exactly one argument, the message +object to encode. They usually extract the payload, encode it, and reset the +payload to this newly encoded value. They should also set the +\mailheader{Content-Transfer-Encoding} header as appropriate. + +Here are the encoding functions provided: + +\begin{funcdesc}{encode_quopri}{msg} +Encodes the payload into quoted-printable form and sets the +\mailheader{Content-Transfer-Encoding} header to +\code{quoted-printable}\footnote{Note that encoding with +\method{encode_quopri()} also encodes all tabs and space characters in +the data.}. +This is a good encoding to use when most of your payload is normal +printable data, but contains a few unprintable characters. +\end{funcdesc} + +\begin{funcdesc}{encode_base64}{msg} +Encodes the payload into base64 form and sets the +\mailheader{Content-Transfer-Encoding} header to +\code{base64}. This is a good encoding to use when most of your payload +is unprintable data since it is a more compact form than +quoted-printable. The drawback of base64 encoding is that it +renders the text non-human readable. +\end{funcdesc} + +\begin{funcdesc}{encode_7or8bit}{msg} +This doesn't actually modify the message's payload, but it does set +the \mailheader{Content-Transfer-Encoding} header to either \code{7bit} or +\code{8bit} as appropriate, based on the payload data. +\end{funcdesc} + +\begin{funcdesc}{encode_noop}{msg} +This does nothing; it doesn't even set the +\mailheader{Content-Transfer-Encoding} header. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/emailexc.tex b/sys/src/cmd/python/Doc/lib/emailexc.tex new file mode 100644 index 000000000..3cef1d5e7 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailexc.tex @@ -0,0 +1,87 @@ +\declaremodule{standard}{email.errors} +\modulesynopsis{The exception classes used by the email package.} + +The following exception classes are defined in the +\module{email.errors} module: + +\begin{excclassdesc}{MessageError}{} +This is the base class for all exceptions that the \module{email} +package can raise. It is derived from the standard +\exception{Exception} class and defines no additional methods. +\end{excclassdesc} + +\begin{excclassdesc}{MessageParseError}{} +This is the base class for exceptions thrown by the \class{Parser} +class. It is derived from \exception{MessageError}. +\end{excclassdesc} + +\begin{excclassdesc}{HeaderParseError}{} +Raised under some error conditions when parsing the \rfc{2822} headers of +a message, this class is derived from \exception{MessageParseError}. +It can be raised from the \method{Parser.parse()} or +\method{Parser.parsestr()} methods. + +Situations where it can be raised include finding an envelope +header after the first \rfc{2822} header of the message, finding a +continuation line before the first \rfc{2822} header is found, or finding +a line in the headers which is neither a header or a continuation +line. +\end{excclassdesc} + +\begin{excclassdesc}{BoundaryError}{} +Raised under some error conditions when parsing the \rfc{2822} headers of +a message, this class is derived from \exception{MessageParseError}. +It can be raised from the \method{Parser.parse()} or +\method{Parser.parsestr()} methods. + +Situations where it can be raised include not being able to find the +starting or terminating boundary in a \mimetype{multipart/*} message +when strict parsing is used. +\end{excclassdesc} + +\begin{excclassdesc}{MultipartConversionError}{} +Raised when a payload is added to a \class{Message} object using +\method{add_payload()}, but the payload is already a scalar and the +message's \mailheader{Content-Type} main type is not either +\mimetype{multipart} or missing. \exception{MultipartConversionError} +multiply inherits from \exception{MessageError} and the built-in +\exception{TypeError}. + +Since \method{Message.add_payload()} is deprecated, this exception is +rarely raised in practice. However the exception may also be raised +if the \method{attach()} method is called on an instance of a class +derived from \class{MIMENonMultipart} (e.g. \class{MIMEImage}). +\end{excclassdesc} + +Here's the list of the defects that the \class{FeedParser} can find while +parsing messages. Note that the defects are added to the message where the +problem was found, so for example, if a message nested inside a +\mimetype{multipart/alternative} had a malformed header, that nested message +object would have a defect, but the containing messages would not. + +All defect classes are subclassed from \class{email.errors.MessageDefect}, but +this class is \emph{not} an exception! + +\versionadded[All the defect classes were added]{2.4} + +\begin{itemize} +\item \class{NoBoundaryInMultipartDefect} -- A message claimed to be a + multipart, but had no \mimetype{boundary} parameter. + +\item \class{StartBoundaryNotFoundDefect} -- The start boundary claimed in the + \mailheader{Content-Type} header was never found. + +\item \class{FirstHeaderLineIsContinuationDefect} -- The message had a + continuation line as its first header line. + +\item \class{MisplacedEnvelopeHeaderDefect} - A ``Unix From'' header was found + in the middle of a header block. + +\item \class{MalformedHeaderDefect} -- A header was found that was missing a + colon, or was otherwise malformed. + +\item \class{MultipartInvariantViolationDefect} -- A message claimed to be a + \mimetype{multipart}, but no subparts were found. Note that when a + message has this defect, its \method{is_multipart()} method may return + false even though its content type claims to be \mimetype{multipart}. +\end{itemize} diff --git a/sys/src/cmd/python/Doc/lib/emailgenerator.tex b/sys/src/cmd/python/Doc/lib/emailgenerator.tex new file mode 100644 index 000000000..7ab0a53e8 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailgenerator.tex @@ -0,0 +1,133 @@ +\declaremodule{standard}{email.generator} +\modulesynopsis{Generate flat text email messages from a message structure.} + +One of the most common tasks is to generate the flat text of the email +message represented by a message object structure. You will need to do +this if you want to send your message via the \refmodule{smtplib} +module or the \refmodule{nntplib} module, or print the message on the +console. Taking a message object structure and producing a flat text +document is the job of the \class{Generator} class. + +Again, as with the \refmodule{email.parser} module, you aren't limited +to the functionality of the bundled generator; you could write one +from scratch yourself. However the bundled generator knows how to +generate most email in a standards-compliant way, should handle MIME +and non-MIME email messages just fine, and is designed so that the +transformation from flat text, to a message structure via the +\class{Parser} class, and back to flat text, is idempotent (the input +is identical to the output). + +Here are the public methods of the \class{Generator} class, imported from the +\module{email.generator} module: + +\begin{classdesc}{Generator}{outfp\optional{, mangle_from_\optional{, + maxheaderlen}}} +The constructor for the \class{Generator} class takes a file-like +object called \var{outfp} for an argument. \var{outfp} must support +the \method{write()} method and be usable as the output file in a +Python extended print statement. + +Optional \var{mangle_from_} is a flag that, when \code{True}, puts a +\samp{>} character in front of any line in the body that starts exactly as +\samp{From }, i.e. \code{From} followed by a space at the beginning of the +line. This is the only guaranteed portable way to avoid having such +lines be mistaken for a \UNIX{} mailbox format envelope header separator (see +\ulink{WHY THE CONTENT-LENGTH FORMAT IS BAD} +{http://www.jwz.org/doc/content-length.html} +for details). \var{mangle_from_} defaults to \code{True}, but you +might want to set this to \code{False} if you are not writing \UNIX{} +mailbox format files. + +Optional \var{maxheaderlen} specifies the longest length for a +non-continued header. When a header line is longer than +\var{maxheaderlen} (in characters, with tabs expanded to 8 spaces), +the header will be split as defined in the \module{email.header.Header} +class. Set to zero to disable header wrapping. The default is 78, as +recommended (but not required) by \rfc{2822}. +\end{classdesc} + +The other public \class{Generator} methods are: + +\begin{methoddesc}[Generator]{flatten}{msg\optional{, unixfrom}} +Print the textual representation of the message object structure rooted at +\var{msg} to the output file specified when the \class{Generator} +instance was created. Subparts are visited depth-first and the +resulting text will be properly MIME encoded. + +Optional \var{unixfrom} is a flag that forces the printing of the +envelope header delimiter before the first \rfc{2822} header of the +root message object. If the root object has no envelope header, a +standard one is crafted. By default, this is set to \code{False} to +inhibit the printing of the envelope delimiter. + +Note that for subparts, no envelope header is ever printed. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Generator]{clone}{fp} +Return an independent clone of this \class{Generator} instance with +the exact same options. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Generator]{write}{s} +Write the string \var{s} to the underlying file object, +i.e. \var{outfp} passed to \class{Generator}'s constructor. This +provides just enough file-like API for \class{Generator} instances to +be used in extended print statements. +\end{methoddesc} + +As a convenience, see the methods \method{Message.as_string()} and +\code{str(aMessage)}, a.k.a. \method{Message.__str__()}, which +simplify the generation of a formatted string representation of a +message object. For more detail, see \refmodule{email.message}. + +The \module{email.generator} module also provides a derived class, +called \class{DecodedGenerator} which is like the \class{Generator} +base class, except that non-\mimetype{text} parts are substituted with +a format string representing the part. + +\begin{classdesc}{DecodedGenerator}{outfp\optional{, mangle_from_\optional{, + maxheaderlen\optional{, fmt}}}} + +This class, derived from \class{Generator} walks through all the +subparts of a message. If the subpart is of main type +\mimetype{text}, then it prints the decoded payload of the subpart. +Optional \var{_mangle_from_} and \var{maxheaderlen} are as with the +\class{Generator} base class. + +If the subpart is not of main type \mimetype{text}, optional \var{fmt} +is a format string that is used instead of the message payload. +\var{fmt} is expanded with the following keywords, \samp{\%(keyword)s} +format: + +\begin{itemize} +\item \code{type} -- Full MIME type of the non-\mimetype{text} part + +\item \code{maintype} -- Main MIME type of the non-\mimetype{text} part + +\item \code{subtype} -- Sub-MIME type of the non-\mimetype{text} part + +\item \code{filename} -- Filename of the non-\mimetype{text} part + +\item \code{description} -- Description associated with the + non-\mimetype{text} part + +\item \code{encoding} -- Content transfer encoding of the + non-\mimetype{text} part + +\end{itemize} + +The default value for \var{fmt} is \code{None}, meaning + +\begin{verbatim} +[Non-text (%(type)s) part of message omitted, filename %(filename)s] +\end{verbatim} + +\versionadded{2.2.2} +\end{classdesc} + +\versionchanged[The previously deprecated method \method{__call__()} was +removed]{2.5} diff --git a/sys/src/cmd/python/Doc/lib/emailheaders.tex b/sys/src/cmd/python/Doc/lib/emailheaders.tex new file mode 100644 index 000000000..524d08c37 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailheaders.tex @@ -0,0 +1,178 @@ +\declaremodule{standard}{email.header} +\modulesynopsis{Representing non-ASCII headers} + +\rfc{2822} is the base standard that describes the format of email +messages. It derives from the older \rfc{822} standard which came +into widespread use at a time when most email was composed of \ASCII{} +characters only. \rfc{2822} is a specification written assuming email +contains only 7-bit \ASCII{} characters. + +Of course, as email has been deployed worldwide, it has become +internationalized, such that language specific character sets can now +be used in email messages. The base standard still requires email +messages to be transferred using only 7-bit \ASCII{} characters, so a +slew of RFCs have been written describing how to encode email +containing non-\ASCII{} characters into \rfc{2822}-compliant format. +These RFCs include \rfc{2045}, \rfc{2046}, \rfc{2047}, and \rfc{2231}. +The \module{email} package supports these standards in its +\module{email.header} and \module{email.charset} modules. + +If you want to include non-\ASCII{} characters in your email headers, +say in the \mailheader{Subject} or \mailheader{To} fields, you should +use the \class{Header} class and assign the field in the +\class{Message} object to an instance of \class{Header} instead of +using a string for the header value. Import the \class{Header} class from the +\module{email.header} module. For example: + +\begin{verbatim} +>>> from email.message import Message +>>> from email.header import Header +>>> msg = Message() +>>> h = Header('p\xf6stal', 'iso-8859-1') +>>> msg['Subject'] = h +>>> print msg.as_string() +Subject: =?iso-8859-1?q?p=F6stal?= + + +\end{verbatim} + +Notice here how we wanted the \mailheader{Subject} field to contain a +non-\ASCII{} character? We did this by creating a \class{Header} +instance and passing in the character set that the byte string was +encoded in. When the subsequent \class{Message} instance was +flattened, the \mailheader{Subject} field was properly \rfc{2047} +encoded. MIME-aware mail readers would show this header using the +embedded ISO-8859-1 character. + +\versionadded{2.2.2} + +Here is the \class{Header} class description: + +\begin{classdesc}{Header}{\optional{s\optional{, charset\optional{, + maxlinelen\optional{, header_name\optional{, continuation_ws\optional{, + errors}}}}}}} +Create a MIME-compliant header that can contain strings in different +character sets. + +Optional \var{s} is the initial header value. If \code{None} (the +default), the initial header value is not set. You can later append +to the header with \method{append()} method calls. \var{s} may be a +byte string or a Unicode string, but see the \method{append()} +documentation for semantics. + +Optional \var{charset} serves two purposes: it has the same meaning as +the \var{charset} argument to the \method{append()} method. It also +sets the default character set for all subsequent \method{append()} +calls that omit the \var{charset} argument. If \var{charset} is not +provided in the constructor (the default), the \code{us-ascii} +character set is used both as \var{s}'s initial charset and as the +default for subsequent \method{append()} calls. + +The maximum line length can be specified explicit via +\var{maxlinelen}. For splitting the first line to a shorter value (to +account for the field header which isn't included in \var{s}, +e.g. \mailheader{Subject}) pass in the name of the field in +\var{header_name}. The default \var{maxlinelen} is 76, and the +default value for \var{header_name} is \code{None}, meaning it is not +taken into account for the first line of a long, split header. + +Optional \var{continuation_ws} must be \rfc{2822}-compliant folding +whitespace, and is usually either a space or a hard tab character. +This character will be prepended to continuation lines. +\end{classdesc} + +Optional \var{errors} is passed straight through to the +\method{append()} method. + +\begin{methoddesc}[Header]{append}{s\optional{, charset\optional{, errors}}} +Append the string \var{s} to the MIME header. + +Optional \var{charset}, if given, should be a \class{Charset} instance +(see \refmodule{email.charset}) or the name of a character set, which +will be converted to a \class{Charset} instance. A value of +\code{None} (the default) means that the \var{charset} given in the +constructor is used. + +\var{s} may be a byte string or a Unicode string. If it is a byte +string (i.e. \code{isinstance(s, str)} is true), then +\var{charset} is the encoding of that byte string, and a +\exception{UnicodeError} will be raised if the string cannot be +decoded with that character set. + +If \var{s} is a Unicode string, then \var{charset} is a hint +specifying the character set of the characters in the string. In this +case, when producing an \rfc{2822}-compliant header using \rfc{2047} +rules, the Unicode string will be encoded using the following charsets +in order: \code{us-ascii}, the \var{charset} hint, \code{utf-8}. The +first character set to not provoke a \exception{UnicodeError} is used. + +Optional \var{errors} is passed through to any \function{unicode()} or +\function{ustr.encode()} call, and defaults to ``strict''. +\end{methoddesc} + +\begin{methoddesc}[Header]{encode}{\optional{splitchars}} +Encode a message header into an RFC-compliant format, possibly +wrapping long lines and encapsulating non-\ASCII{} parts in base64 or +quoted-printable encodings. Optional \var{splitchars} is a string +containing characters to split long ASCII lines on, in rough support +of \rfc{2822}'s \emph{highest level syntactic breaks}. This doesn't +affect \rfc{2047} encoded lines. +\end{methoddesc} + +The \class{Header} class also provides a number of methods to support +standard operators and built-in functions. + +\begin{methoddesc}[Header]{__str__}{} +A synonym for \method{Header.encode()}. Useful for +\code{str(aHeader)}. +\end{methoddesc} + +\begin{methoddesc}[Header]{__unicode__}{} +A helper for the built-in \function{unicode()} function. Returns the +header as a Unicode string. +\end{methoddesc} + +\begin{methoddesc}[Header]{__eq__}{other} +This method allows you to compare two \class{Header} instances for equality. +\end{methoddesc} + +\begin{methoddesc}[Header]{__ne__}{other} +This method allows you to compare two \class{Header} instances for inequality. +\end{methoddesc} + +The \module{email.header} module also provides the following +convenient functions. + +\begin{funcdesc}{decode_header}{header} +Decode a message header value without converting the character set. +The header value is in \var{header}. + +This function returns a list of \code{(decoded_string, charset)} pairs +containing each of the decoded parts of the header. \var{charset} is +\code{None} for non-encoded parts of the header, otherwise a lower +case string containing the name of the character set specified in the +encoded string. + +Here's an example: + +\begin{verbatim} +>>> from email.header import decode_header +>>> decode_header('=?iso-8859-1?q?p=F6stal?=') +[('p\xf6stal', 'iso-8859-1')] +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{make_header}{decoded_seq\optional{, maxlinelen\optional{, + header_name\optional{, continuation_ws}}}} +Create a \class{Header} instance from a sequence of pairs as returned +by \function{decode_header()}. + +\function{decode_header()} takes a header value string and returns a +sequence of pairs of the format \code{(decoded_string, charset)} where +\var{charset} is the name of the character set. + +This function takes one of those sequence of pairs and returns a +\class{Header} instance. Optional \var{maxlinelen}, +\var{header_name}, and \var{continuation_ws} are as in the +\class{Header} constructor. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/emailiter.tex b/sys/src/cmd/python/Doc/lib/emailiter.tex new file mode 100644 index 000000000..ef8ef6f45 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailiter.tex @@ -0,0 +1,65 @@ +\declaremodule{standard}{email.iterators} +\modulesynopsis{Iterate over a message object tree.} + +Iterating over a message object tree is fairly easy with the +\method{Message.walk()} method. The \module{email.iterators} module +provides some useful higher level iterations over message object +trees. + +\begin{funcdesc}{body_line_iterator}{msg\optional{, decode}} +This iterates over all the payloads in all the subparts of \var{msg}, +returning the string payloads line-by-line. It skips over all the +subpart headers, and it skips over any subpart with a payload that +isn't a Python string. This is somewhat equivalent to reading the +flat text representation of the message from a file using +\method{readline()}, skipping over all the intervening headers. + +Optional \var{decode} is passed through to \method{Message.get_payload()}. +\end{funcdesc} + +\begin{funcdesc}{typed_subpart_iterator}{msg\optional{, + maintype\optional{, subtype}}} +This iterates over all the subparts of \var{msg}, returning only those +subparts that match the MIME type specified by \var{maintype} and +\var{subtype}. + +Note that \var{subtype} is optional; if omitted, then subpart MIME +type matching is done only with the main type. \var{maintype} is +optional too; it defaults to \mimetype{text}. + +Thus, by default \function{typed_subpart_iterator()} returns each +subpart that has a MIME type of \mimetype{text/*}. +\end{funcdesc} + +The following function has been added as a useful debugging tool. It +should \emph{not} be considered part of the supported public interface +for the package. + +\begin{funcdesc}{_structure}{msg\optional{, fp\optional{, level}}} +Prints an indented representation of the content types of the +message object structure. For example: + +\begin{verbatim} +>>> msg = email.message_from_file(somefile) +>>> _structure(msg) +multipart/mixed + text/plain + text/plain + multipart/digest + message/rfc822 + text/plain + message/rfc822 + text/plain + message/rfc822 + text/plain + message/rfc822 + text/plain + message/rfc822 + text/plain + text/plain +\end{verbatim} + +Optional \var{fp} is a file-like object to print the output to. It +must be suitable for Python's extended print statement. \var{level} +is used internally. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/emailmessage.tex b/sys/src/cmd/python/Doc/lib/emailmessage.tex new file mode 100644 index 000000000..7bd7dd8b3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailmessage.tex @@ -0,0 +1,561 @@ +\declaremodule{standard}{email.message} +\modulesynopsis{The base class representing email messages.} + +The central class in the \module{email} package is the +\class{Message} class, imported from the \module{email.message} module. It is +the base class for the \module{email} object model. \class{Message} provides +the core functionality for setting and querying header fields, and for +accessing message bodies. + +Conceptually, a \class{Message} object consists of \emph{headers} and +\emph{payloads}. Headers are \rfc{2822} style field names and +values where the field name and value are separated by a colon. The +colon is not part of either the field name or the field value. + +Headers are stored and returned in case-preserving form but are +matched case-insensitively. There may also be a single envelope +header, also known as the \emph{Unix-From} header or the +\code{From_} header. The payload is either a string in the case of +simple message objects or a list of \class{Message} objects for +MIME container documents (e.g. \mimetype{multipart/*} and +\mimetype{message/rfc822}). + +\class{Message} objects provide a mapping style interface for +accessing the message headers, and an explicit interface for accessing +both the headers and the payload. It provides convenience methods for +generating a flat text representation of the message object tree, for +accessing commonly used header parameters, and for recursively walking +over the object tree. + +Here are the methods of the \class{Message} class: + +\begin{classdesc}{Message}{} +The constructor takes no arguments. +\end{classdesc} + +\begin{methoddesc}[Message]{as_string}{\optional{unixfrom}} +Return the entire message flatten as a string. When optional +\var{unixfrom} is \code{True}, the envelope header is included in the +returned string. \var{unixfrom} defaults to \code{False}. + +Note that this method is provided as a convenience and may not always format +the message the way you want. For example, by default it mangles lines that +begin with \code{From }. For more flexibility, instantiate a +\class{Generator} instance and use its +\method{flatten()} method directly. For example: + +\begin{verbatim} +from cStringIO import StringIO +from email.generator import Generator +fp = StringIO() +g = Generator(fp, mangle_from_=False, maxheaderlen=60) +g.flatten(msg) +text = fp.getvalue() +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}[Message]{__str__}{} +Equivalent to \method{as_string(unixfrom=True)}. +\end{methoddesc} + +\begin{methoddesc}[Message]{is_multipart}{} +Return \code{True} if the message's payload is a list of +sub-\class{Message} objects, otherwise return \code{False}. When +\method{is_multipart()} returns False, the payload should be a string +object. +\end{methoddesc} + +\begin{methoddesc}[Message]{set_unixfrom}{unixfrom} +Set the message's envelope header to \var{unixfrom}, which should be a string. +\end{methoddesc} + +\begin{methoddesc}[Message]{get_unixfrom}{} +Return the message's envelope header. Defaults to \code{None} if the +envelope header was never set. +\end{methoddesc} + +\begin{methoddesc}[Message]{attach}{payload} +Add the given \var{payload} to the current payload, which must be +\code{None} or a list of \class{Message} objects before the call. +After the call, the payload will always be a list of \class{Message} +objects. If you want to set the payload to a scalar object (e.g. a +string), use \method{set_payload()} instead. +\end{methoddesc} + +\begin{methoddesc}[Message]{get_payload}{\optional{i\optional{, decode}}} +Return a reference the current payload, which will be a list of +\class{Message} objects when \method{is_multipart()} is \code{True}, or a +string when \method{is_multipart()} is \code{False}. If the +payload is a list and you mutate the list object, you modify the +message's payload in place. + +With optional argument \var{i}, \method{get_payload()} will return the +\var{i}-th element of the payload, counting from zero, if +\method{is_multipart()} is \code{True}. An \exception{IndexError} +will be raised if \var{i} is less than 0 or greater than or equal to +the number of items in the payload. If the payload is a string +(i.e. \method{is_multipart()} is \code{False}) and \var{i} is given, a +\exception{TypeError} is raised. + +Optional \var{decode} is a flag indicating whether the payload should be +decoded or not, according to the \mailheader{Content-Transfer-Encoding} header. +When \code{True} and the message is not a multipart, the payload will be +decoded if this header's value is \samp{quoted-printable} or +\samp{base64}. If some other encoding is used, or +\mailheader{Content-Transfer-Encoding} header is +missing, or if the payload has bogus base64 data, the payload is +returned as-is (undecoded). If the message is a multipart and the +\var{decode} flag is \code{True}, then \code{None} is returned. The +default for \var{decode} is \code{False}. +\end{methoddesc} + +\begin{methoddesc}[Message]{set_payload}{payload\optional{, charset}} +Set the entire message object's payload to \var{payload}. It is the +client's responsibility to ensure the payload invariants. Optional +\var{charset} sets the message's default character set; see +\method{set_charset()} for details. + +\versionchanged[\var{charset} argument added]{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{set_charset}{charset} +Set the character set of the payload to \var{charset}, which can +either be a \class{Charset} instance (see \refmodule{email.charset}), a +string naming a character set, +or \code{None}. If it is a string, it will be converted to a +\class{Charset} instance. If \var{charset} is \code{None}, the +\code{charset} parameter will be removed from the +\mailheader{Content-Type} header. Anything else will generate a +\exception{TypeError}. + +The message will be assumed to be of type \mimetype{text/*} encoded with +\var{charset.input_charset}. It will be converted to +\var{charset.output_charset} +and encoded properly, if needed, when generating the plain text +representation of the message. MIME headers +(\mailheader{MIME-Version}, \mailheader{Content-Type}, +\mailheader{Content-Transfer-Encoding}) will be added as needed. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_charset}{} +Return the \class{Charset} instance associated with the message's payload. +\versionadded{2.2.2} +\end{methoddesc} + +The following methods implement a mapping-like interface for accessing +the message's \rfc{2822} headers. Note that there are some +semantic differences between these methods and a normal mapping +(i.e. dictionary) interface. For example, in a dictionary there are +no duplicate keys, but here there may be duplicate message headers. Also, +in dictionaries there is no guaranteed order to the keys returned by +\method{keys()}, but in a \class{Message} object, headers are always +returned in the order they appeared in the original message, or were +added to the message later. Any header deleted and then re-added are +always appended to the end of the header list. + +These semantic differences are intentional and are biased toward +maximal convenience. + +Note that in all cases, any envelope header present in the message is +not included in the mapping interface. + +\begin{methoddesc}[Message]{__len__}{} +Return the total number of headers, including duplicates. +\end{methoddesc} + +\begin{methoddesc}[Message]{__contains__}{name} +Return true if the message object has a field named \var{name}. +Matching is done case-insensitively and \var{name} should not include the +trailing colon. Used for the \code{in} operator, +e.g.: + +\begin{verbatim} +if 'message-id' in myMessage: + print 'Message-ID:', myMessage['message-id'] +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}[Message]{__getitem__}{name} +Return the value of the named header field. \var{name} should not +include the colon field separator. If the header is missing, +\code{None} is returned; a \exception{KeyError} is never raised. + +Note that if the named field appears more than once in the message's +headers, exactly which of those field values will be returned is +undefined. Use the \method{get_all()} method to get the values of all +the extant named headers. +\end{methoddesc} + +\begin{methoddesc}[Message]{__setitem__}{name, val} +Add a header to the message with field name \var{name} and value +\var{val}. The field is appended to the end of the message's existing +fields. + +Note that this does \emph{not} overwrite or delete any existing header +with the same name. If you want to ensure that the new header is the +only one present in the message with field name +\var{name}, delete the field first, e.g.: + +\begin{verbatim} +del msg['subject'] +msg['subject'] = 'Python roolz!' +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}[Message]{__delitem__}{name} +Delete all occurrences of the field with name \var{name} from the +message's headers. No exception is raised if the named field isn't +present in the headers. +\end{methoddesc} + +\begin{methoddesc}[Message]{has_key}{name} +Return true if the message contains a header field named \var{name}, +otherwise return false. +\end{methoddesc} + +\begin{methoddesc}[Message]{keys}{} +Return a list of all the message's header field names. +\end{methoddesc} + +\begin{methoddesc}[Message]{values}{} +Return a list of all the message's field values. +\end{methoddesc} + +\begin{methoddesc}[Message]{items}{} +Return a list of 2-tuples containing all the message's field headers +and values. +\end{methoddesc} + +\begin{methoddesc}[Message]{get}{name\optional{, failobj}} +Return the value of the named header field. This is identical to +\method{__getitem__()} except that optional \var{failobj} is returned +if the named header is missing (defaults to \code{None}). +\end{methoddesc} + +Here are some additional useful methods: + +\begin{methoddesc}[Message]{get_all}{name\optional{, failobj}} +Return a list of all the values for the field named \var{name}. +If there are no such named headers in the message, \var{failobj} is +returned (defaults to \code{None}). +\end{methoddesc} + +\begin{methoddesc}[Message]{add_header}{_name, _value, **_params} +Extended header setting. This method is similar to +\method{__setitem__()} except that additional header parameters can be +provided as keyword arguments. \var{_name} is the header field to add +and \var{_value} is the \emph{primary} value for the header. + +For each item in the keyword argument dictionary \var{_params}, the +key is taken as the parameter name, with underscores converted to +dashes (since dashes are illegal in Python identifiers). Normally, +the parameter will be added as \code{key="value"} unless the value is +\code{None}, in which case only the key will be added. + +Here's an example: + +\begin{verbatim} +msg.add_header('Content-Disposition', 'attachment', filename='bud.gif') +\end{verbatim} + +This will add a header that looks like + +\begin{verbatim} +Content-Disposition: attachment; filename="bud.gif" +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}[Message]{replace_header}{_name, _value} +Replace a header. Replace the first header found in the message that +matches \var{_name}, retaining header order and field name case. If +no matching header was found, a \exception{KeyError} is raised. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_content_type}{} +Return the message's content type. The returned string is coerced to +lower case of the form \mimetype{maintype/subtype}. If there was no +\mailheader{Content-Type} header in the message the default type as +given by \method{get_default_type()} will be returned. Since +according to \rfc{2045}, messages always have a default type, +\method{get_content_type()} will always return a value. + +\rfc{2045} defines a message's default type to be +\mimetype{text/plain} unless it appears inside a +\mimetype{multipart/digest} container, in which case it would be +\mimetype{message/rfc822}. If the \mailheader{Content-Type} header +has an invalid type specification, \rfc{2045} mandates that the +default type be \mimetype{text/plain}. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_content_maintype}{} +Return the message's main content type. This is the +\mimetype{maintype} part of the string returned by +\method{get_content_type()}. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_content_subtype}{} +Return the message's sub-content type. This is the \mimetype{subtype} +part of the string returned by \method{get_content_type()}. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_default_type}{} +Return the default content type. Most messages have a default content +type of \mimetype{text/plain}, except for messages that are subparts +of \mimetype{multipart/digest} containers. Such subparts have a +default content type of \mimetype{message/rfc822}. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{set_default_type}{ctype} +Set the default content type. \var{ctype} should either be +\mimetype{text/plain} or \mimetype{message/rfc822}, although this is +not enforced. The default content type is not stored in the +\mailheader{Content-Type} header. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_params}{\optional{failobj\optional{, + header\optional{, unquote}}}} +Return the message's \mailheader{Content-Type} parameters, as a list. The +elements of the returned list are 2-tuples of key/value pairs, as +split on the \character{=} sign. The left hand side of the +\character{=} is the key, while the right hand side is the value. If +there is no \character{=} sign in the parameter the value is the empty +string, otherwise the value is as described in \method{get_param()} and is +unquoted if optional \var{unquote} is \code{True} (the default). + +Optional \var{failobj} is the object to return if there is no +\mailheader{Content-Type} header. Optional \var{header} is the header to +search instead of \mailheader{Content-Type}. + +\versionchanged[\var{unquote} argument added]{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_param}{param\optional{, + failobj\optional{, header\optional{, unquote}}}} +Return the value of the \mailheader{Content-Type} header's parameter +\var{param} as a string. If the message has no \mailheader{Content-Type} +header or if there is no such parameter, then \var{failobj} is +returned (defaults to \code{None}). + +Optional \var{header} if given, specifies the message header to use +instead of \mailheader{Content-Type}. + +Parameter keys are always compared case insensitively. The return +value can either be a string, or a 3-tuple if the parameter was +\rfc{2231} encoded. When it's a 3-tuple, the elements of the value are of +the form \code{(CHARSET, LANGUAGE, VALUE)}. Note that both \code{CHARSET} and +\code{LANGUAGE} can be \code{None}, in which case you should consider +\code{VALUE} to be encoded in the \code{us-ascii} charset. You can +usually ignore \code{LANGUAGE}. + +If your application doesn't care whether the parameter was encoded as in +\rfc{2231}, you can collapse the parameter value by calling +\function{email.Utils.collapse_rfc2231_value()}, passing in the return value +from \method{get_param()}. This will return a suitably decoded Unicode string +whn the value is a tuple, or the original string unquoted if it isn't. For +example: + +\begin{verbatim} +rawparam = msg.get_param('foo') +param = email.Utils.collapse_rfc2231_value(rawparam) +\end{verbatim} + +In any case, the parameter value (either the returned string, or the +\code{VALUE} item in the 3-tuple) is always unquoted, unless +\var{unquote} is set to \code{False}. + +\versionchanged[\var{unquote} argument added, and 3-tuple return value +possible]{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{set_param}{param, value\optional{, + header\optional{, requote\optional{, charset\optional{, language}}}}} + +Set a parameter in the \mailheader{Content-Type} header. If the +parameter already exists in the header, its value will be replaced +with \var{value}. If the \mailheader{Content-Type} header as not yet +been defined for this message, it will be set to \mimetype{text/plain} +and the new parameter value will be appended as per \rfc{2045}. + +Optional \var{header} specifies an alternative header to +\mailheader{Content-Type}, and all parameters will be quoted as +necessary unless optional \var{requote} is \code{False} (the default +is \code{True}). + +If optional \var{charset} is specified, the parameter will be encoded +according to \rfc{2231}. Optional \var{language} specifies the RFC +2231 language, defaulting to the empty string. Both \var{charset} and +\var{language} should be strings. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{del_param}{param\optional{, header\optional{, + requote}}} +Remove the given parameter completely from the +\mailheader{Content-Type} header. The header will be re-written in +place without the parameter or its value. All values will be quoted +as necessary unless \var{requote} is \code{False} (the default is +\code{True}). Optional \var{header} specifies an alternative to +\mailheader{Content-Type}. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{set_type}{type\optional{, header}\optional{, + requote}} +Set the main type and subtype for the \mailheader{Content-Type} +header. \var{type} must be a string in the form +\mimetype{maintype/subtype}, otherwise a \exception{ValueError} is +raised. + +This method replaces the \mailheader{Content-Type} header, keeping all +the parameters in place. If \var{requote} is \code{False}, this +leaves the existing header's quoting as is, otherwise the parameters +will be quoted (the default). + +An alternative header can be specified in the \var{header} argument. +When the \mailheader{Content-Type} header is set a +\mailheader{MIME-Version} header is also added. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_filename}{\optional{failobj}} +Return the value of the \code{filename} parameter of the +\mailheader{Content-Disposition} header of the message. If the header does +not have a \code{filename} parameter, this method falls back to looking for +the \code{name} parameter. If neither is found, or the header is missing, +then \var{failobj} is returned. The returned string will always be unquoted +as per \method{Utils.unquote()}. +\end{methoddesc} + +\begin{methoddesc}[Message]{get_boundary}{\optional{failobj}} +Return the value of the \code{boundary} parameter of the +\mailheader{Content-Type} header of the message, or \var{failobj} if either +the header is missing, or has no \code{boundary} parameter. The +returned string will always be unquoted as per +\method{Utils.unquote()}. +\end{methoddesc} + +\begin{methoddesc}[Message]{set_boundary}{boundary} +Set the \code{boundary} parameter of the \mailheader{Content-Type} +header to \var{boundary}. \method{set_boundary()} will always quote +\var{boundary} if necessary. A \exception{HeaderParseError} is raised +if the message object has no \mailheader{Content-Type} header. + +Note that using this method is subtly different than deleting the old +\mailheader{Content-Type} header and adding a new one with the new boundary +via \method{add_header()}, because \method{set_boundary()} preserves the +order of the \mailheader{Content-Type} header in the list of headers. +However, it does \emph{not} preserve any continuation lines which may +have been present in the original \mailheader{Content-Type} header. +\end{methoddesc} + +\begin{methoddesc}[Message]{get_content_charset}{\optional{failobj}} +Return the \code{charset} parameter of the \mailheader{Content-Type} +header, coerced to lower case. If there is no +\mailheader{Content-Type} header, or if that header has no +\code{charset} parameter, \var{failobj} is returned. + +Note that this method differs from \method{get_charset()} which +returns the \class{Charset} instance for the default encoding of the +message body. + +\versionadded{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Message]{get_charsets}{\optional{failobj}} +Return a list containing the character set names in the message. If +the message is a \mimetype{multipart}, then the list will contain one +element for each subpart in the payload, otherwise, it will be a list +of length 1. + +Each item in the list will be a string which is the value of the +\code{charset} parameter in the \mailheader{Content-Type} header for the +represented subpart. However, if the subpart has no +\mailheader{Content-Type} header, no \code{charset} parameter, or is not of +the \mimetype{text} main MIME type, then that item in the returned list +will be \var{failobj}. +\end{methoddesc} + +\begin{methoddesc}[Message]{walk}{} +The \method{walk()} method is an all-purpose generator which can be +used to iterate over all the parts and subparts of a message object +tree, in depth-first traversal order. You will typically use +\method{walk()} as the iterator in a \code{for} loop; each +iteration returns the next subpart. + +Here's an example that prints the MIME type of every part of a +multipart message structure: + +\begin{verbatim} +>>> for part in msg.walk(): +... print part.get_content_type() +multipart/report +text/plain +message/delivery-status +text/plain +text/plain +message/rfc822 +\end{verbatim} +\end{methoddesc} + +\versionchanged[The previously deprecated methods \method{get_type()}, +\method{get_main_type()}, and \method{get_subtype()} were removed]{2.5} + +\class{Message} objects can also optionally contain two instance +attributes, which can be used when generating the plain text of a MIME +message. + +\begin{datadesc}{preamble} +The format of a MIME document allows for some text between the blank +line following the headers, and the first multipart boundary string. +Normally, this text is never visible in a MIME-aware mail reader +because it falls outside the standard MIME armor. However, when +viewing the raw text of the message, or when viewing the message in a +non-MIME aware reader, this text can become visible. + +The \var{preamble} attribute contains this leading extra-armor text +for MIME documents. When the \class{Parser} discovers some text after +the headers but before the first boundary string, it assigns this text +to the message's \var{preamble} attribute. When the \class{Generator} +is writing out the plain text representation of a MIME message, and it +finds the message has a \var{preamble} attribute, it will write this +text in the area between the headers and the first boundary. See +\refmodule{email.parser} and \refmodule{email.generator} for details. + +Note that if the message object has no preamble, the +\var{preamble} attribute will be \code{None}. +\end{datadesc} + +\begin{datadesc}{epilogue} +The \var{epilogue} attribute acts the same way as the \var{preamble} +attribute, except that it contains text that appears between the last +boundary and the end of the message. + +\versionchanged[You do not need to set the epilogue to the empty string in +order for the \class{Generator} to print a newline at the end of the +file]{2.5} +\end{datadesc} + +\begin{datadesc}{defects} +The \var{defects} attribute contains a list of all the problems found when +parsing this message. See \refmodule{email.errors} for a detailed description +of the possible parsing defects. + +\versionadded{2.4} +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/emailmimebase.tex b/sys/src/cmd/python/Doc/lib/emailmimebase.tex new file mode 100644 index 000000000..4735be323 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailmimebase.tex @@ -0,0 +1,186 @@ +\declaremodule{standard}{email.mime} +\declaremodule{standard}{email.mime.base} +\declaremodule{standard}{email.mime.nonmultipart} +\declaremodule{standard}{email.mime.multipart} +\declaremodule{standard}{email.mime.audio} +\declaremodule{standard}{email.mime.image} +\declaremodule{standard}{email.mime.message} +\declaremodule{standard}{email.mime.text} +Ordinarily, you get a message object structure by passing a file or +some text to a parser, which parses the text and returns the root +message object. However you can also build a complete message +structure from scratch, or even individual \class{Message} objects by +hand. In fact, you can also take an existing structure and add new +\class{Message} objects, move them around, etc. This makes a very +convenient interface for slicing-and-dicing MIME messages. + +You can create a new object structure by creating \class{Message} instances, +adding attachments and all the appropriate headers manually. For MIME +messages though, the \module{email} package provides some convenient +subclasses to make things easier. + +Here are the classes: + +\begin{classdesc}{MIMEBase}{_maintype, _subtype, **_params} +Module: \module{email.mime.base} + +This is the base class for all the MIME-specific subclasses of +\class{Message}. Ordinarily you won't create instances specifically +of \class{MIMEBase}, although you could. \class{MIMEBase} is provided +primarily as a convenient base class for more specific MIME-aware +subclasses. + +\var{_maintype} is the \mailheader{Content-Type} major type +(e.g. \mimetype{text} or \mimetype{image}), and \var{_subtype} is the +\mailheader{Content-Type} minor type +(e.g. \mimetype{plain} or \mimetype{gif}). \var{_params} is a parameter +key/value dictionary and is passed directly to +\method{Message.add_header()}. + +The \class{MIMEBase} class always adds a \mailheader{Content-Type} header +(based on \var{_maintype}, \var{_subtype}, and \var{_params}), and a +\mailheader{MIME-Version} header (always set to \code{1.0}). +\end{classdesc} + +\begin{classdesc}{MIMENonMultipart}{} +Module: \module{email.mime.nonmultipart} + +A subclass of \class{MIMEBase}, this is an intermediate base class for +MIME messages that are not \mimetype{multipart}. The primary purpose +of this class is to prevent the use of the \method{attach()} method, +which only makes sense for \mimetype{multipart} messages. If +\method{attach()} is called, a \exception{MultipartConversionError} +exception is raised. + +\versionadded{2.2.2} +\end{classdesc} + +\begin{classdesc}{MIMEMultipart}{\optional{subtype\optional{, + boundary\optional{, _subparts\optional{, _params}}}}} +Module: \module{email.mime.multipart} + +A subclass of \class{MIMEBase}, this is an intermediate base class for +MIME messages that are \mimetype{multipart}. Optional \var{_subtype} +defaults to \mimetype{mixed}, but can be used to specify the subtype +of the message. A \mailheader{Content-Type} header of +\mimetype{multipart/}\var{_subtype} will be added to the message +object. A \mailheader{MIME-Version} header will also be added. + +Optional \var{boundary} is the multipart boundary string. When +\code{None} (the default), the boundary is calculated when needed. + +\var{_subparts} is a sequence of initial subparts for the payload. It +must be possible to convert this sequence to a list. You can always +attach new subparts to the message by using the +\method{Message.attach()} method. + +Additional parameters for the \mailheader{Content-Type} header are +taken from the keyword arguments, or passed into the \var{_params} +argument, which is a keyword dictionary. + +\versionadded{2.2.2} +\end{classdesc} + +\begin{classdesc}{MIMEApplication}{_data\optional{, _subtype\optional{, + _encoder\optional{, **_params}}}} +Module: \module{email.mime.application} + +A subclass of \class{MIMENonMultipart}, the \class{MIMEApplication} class is +used to represent MIME message objects of major type \mimetype{application}. +\var{_data} is a string containing the raw byte data. Optional \var{_subtype} +specifies the MIME subtype and defaults to \mimetype{octet-stream}. + +Optional \var{_encoder} is a callable (i.e. function) which will +perform the actual encoding of the data for transport. This +callable takes one argument, which is the \class{MIMEApplication} instance. +It should use \method{get_payload()} and \method{set_payload()} to +change the payload to encoded form. It should also add any +\mailheader{Content-Transfer-Encoding} or other headers to the message +object as necessary. The default encoding is base64. See the +\refmodule{email.encoders} module for a list of the built-in encoders. + +\var{_params} are passed straight through to the base class constructor. +\versionadded{2.5} +\end{classdesc} + +\begin{classdesc}{MIMEAudio}{_audiodata\optional{, _subtype\optional{, + _encoder\optional{, **_params}}}} +Module: \module{email.mime.audio} + +A subclass of \class{MIMENonMultipart}, the \class{MIMEAudio} class +is used to create MIME message objects of major type \mimetype{audio}. +\var{_audiodata} is a string containing the raw audio data. If this +data can be decoded by the standard Python module \refmodule{sndhdr}, +then the subtype will be automatically included in the +\mailheader{Content-Type} header. Otherwise you can explicitly specify the +audio subtype via the \var{_subtype} parameter. If the minor type could +not be guessed and \var{_subtype} was not given, then \exception{TypeError} +is raised. + +Optional \var{_encoder} is a callable (i.e. function) which will +perform the actual encoding of the audio data for transport. This +callable takes one argument, which is the \class{MIMEAudio} instance. +It should use \method{get_payload()} and \method{set_payload()} to +change the payload to encoded form. It should also add any +\mailheader{Content-Transfer-Encoding} or other headers to the message +object as necessary. The default encoding is base64. See the +\refmodule{email.encoders} module for a list of the built-in encoders. + +\var{_params} are passed straight through to the base class constructor. +\end{classdesc} + +\begin{classdesc}{MIMEImage}{_imagedata\optional{, _subtype\optional{, + _encoder\optional{, **_params}}}} +Module: \module{email.mime.image} + +A subclass of \class{MIMENonMultipart}, the \class{MIMEImage} class is +used to create MIME message objects of major type \mimetype{image}. +\var{_imagedata} is a string containing the raw image data. If this +data can be decoded by the standard Python module \refmodule{imghdr}, +then the subtype will be automatically included in the +\mailheader{Content-Type} header. Otherwise you can explicitly specify the +image subtype via the \var{_subtype} parameter. If the minor type could +not be guessed and \var{_subtype} was not given, then \exception{TypeError} +is raised. + +Optional \var{_encoder} is a callable (i.e. function) which will +perform the actual encoding of the image data for transport. This +callable takes one argument, which is the \class{MIMEImage} instance. +It should use \method{get_payload()} and \method{set_payload()} to +change the payload to encoded form. It should also add any +\mailheader{Content-Transfer-Encoding} or other headers to the message +object as necessary. The default encoding is base64. See the +\refmodule{email.encoders} module for a list of the built-in encoders. + +\var{_params} are passed straight through to the \class{MIMEBase} +constructor. +\end{classdesc} + +\begin{classdesc}{MIMEMessage}{_msg\optional{, _subtype}} +Module: \module{email.mime.message} + +A subclass of \class{MIMENonMultipart}, the \class{MIMEMessage} class +is used to create MIME objects of main type \mimetype{message}. +\var{_msg} is used as the payload, and must be an instance of class +\class{Message} (or a subclass thereof), otherwise a +\exception{TypeError} is raised. + +Optional \var{_subtype} sets the subtype of the message; it defaults +to \mimetype{rfc822}. +\end{classdesc} + +\begin{classdesc}{MIMEText}{_text\optional{, _subtype\optional{, _charset}}} +Module: \module{email.mime.text} + +A subclass of \class{MIMENonMultipart}, the \class{MIMEText} class is +used to create MIME objects of major type \mimetype{text}. +\var{_text} is the string for the payload. \var{_subtype} is the +minor type and defaults to \mimetype{plain}. \var{_charset} is the +character set of the text and is passed as a parameter to the +\class{MIMENonMultipart} constructor; it defaults to \code{us-ascii}. No +guessing or encoding is performed on the text data. + +\versionchanged[The previously deprecated \var{_encoding} argument has +been removed. Encoding happens implicitly based on the \var{_charset} +argument]{2.4} +\end{classdesc} diff --git a/sys/src/cmd/python/Doc/lib/emailparser.tex b/sys/src/cmd/python/Doc/lib/emailparser.tex new file mode 100644 index 000000000..609fa4008 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailparser.tex @@ -0,0 +1,208 @@ +\declaremodule{standard}{email.parser} +\modulesynopsis{Parse flat text email messages to produce a message + object structure.} + +Message object structures can be created in one of two ways: they can be +created from whole cloth by instantiating \class{Message} objects and +stringing them together via \method{attach()} and +\method{set_payload()} calls, or they can be created by parsing a flat text +representation of the email message. + +The \module{email} package provides a standard parser that understands +most email document structures, including MIME documents. You can +pass the parser a string or a file object, and the parser will return +to you the root \class{Message} instance of the object structure. For +simple, non-MIME messages the payload of this root object will likely +be a string containing the text of the message. For MIME +messages, the root object will return \code{True} from its +\method{is_multipart()} method, and the subparts can be accessed via +the \method{get_payload()} and \method{walk()} methods. + +There are actually two parser interfaces available for use, the classic +\class{Parser} API and the incremental \class{FeedParser} API. The classic +\class{Parser} API is fine if you have the entire text of the message in +memory as a string, or if the entire message lives in a file on the file +system. \class{FeedParser} is more appropriate for when you're reading the +message from a stream which might block waiting for more input (e.g. reading +an email message from a socket). The \class{FeedParser} can consume and parse +the message incrementally, and only returns the root object when you close the +parser\footnote{As of email package version 3.0, introduced in +Python 2.4, the classic \class{Parser} was re-implemented in terms of the +\class{FeedParser}, so the semantics and results are identical between the two +parsers.}. + +Note that the parser can be extended in limited ways, and of course +you can implement your own parser completely from scratch. There is +no magical connection between the \module{email} package's bundled +parser and the \class{Message} class, so your custom parser can create +message object trees any way it finds necessary. + +\subsubsection{FeedParser API} + +\versionadded{2.4} + +The \class{FeedParser}, imported from the \module{email.feedparser} module, +provides an API that is conducive to incremental parsing of email messages, +such as would be necessary when reading the text of an email message from a +source that can block (e.g. a socket). The +\class{FeedParser} can of course be used to parse an email message fully +contained in a string or a file, but the classic \class{Parser} API may be +more convenient for such use cases. The semantics and results of the two +parser APIs are identical. + +The \class{FeedParser}'s API is simple; you create an instance, feed it a +bunch of text until there's no more to feed it, then close the parser to +retrieve the root message object. The \class{FeedParser} is extremely +accurate when parsing standards-compliant messages, and it does a very good +job of parsing non-compliant messages, providing information about how a +message was deemed broken. It will populate a message object's \var{defects} +attribute with a list of any problems it found in a message. See the +\refmodule{email.errors} module for the list of defects that it can find. + +Here is the API for the \class{FeedParser}: + +\begin{classdesc}{FeedParser}{\optional{_factory}} +Create a \class{FeedParser} instance. Optional \var{_factory} is a +no-argument callable that will be called whenever a new message object is +needed. It defaults to the \class{email.message.Message} class. +\end{classdesc} + +\begin{methoddesc}[FeedParser]{feed}{data} +Feed the \class{FeedParser} some more data. \var{data} should be a +string containing one or more lines. The lines can be partial and the +\class{FeedParser} will stitch such partial lines together properly. The +lines in the string can have any of the common three line endings, carriage +return, newline, or carriage return and newline (they can even be mixed). +\end{methoddesc} + +\begin{methoddesc}[FeedParser]{close}{} +Closing a \class{FeedParser} completes the parsing of all previously fed data, +and returns the root message object. It is undefined what happens if you feed +more data to a closed \class{FeedParser}. +\end{methoddesc} + +\subsubsection{Parser class API} + +The \class{Parser} class, imported from the \module{email.parser} module, +provides an API that can be used to parse a message when the complete contents +of the message are available in a string or file. The +\module{email.parser} module also provides a second class, called +\class{HeaderParser} which can be used if you're only interested in +the headers of the message. \class{HeaderParser} can be much faster in +these situations, since it does not attempt to parse the message body, +instead setting the payload to the raw body as a string. +\class{HeaderParser} has the same API as the \class{Parser} class. + +\begin{classdesc}{Parser}{\optional{_class}} +The constructor for the \class{Parser} class takes an optional +argument \var{_class}. This must be a callable factory (such as a +function or a class), and it is used whenever a sub-message object +needs to be created. It defaults to \class{Message} (see +\refmodule{email.message}). The factory will be called without +arguments. + +The optional \var{strict} flag is ignored. \deprecated{2.4}{Because the +\class{Parser} class is a backward compatible API wrapper around the +new-in-Python 2.4 \class{FeedParser}, \emph{all} parsing is effectively +non-strict. You should simply stop passing a \var{strict} flag to the +\class{Parser} constructor.} + +\versionchanged[The \var{strict} flag was added]{2.2.2} +\versionchanged[The \var{strict} flag was deprecated]{2.4} +\end{classdesc} + +The other public \class{Parser} methods are: + +\begin{methoddesc}[Parser]{parse}{fp\optional{, headersonly}} +Read all the data from the file-like object \var{fp}, parse the +resulting text, and return the root message object. \var{fp} must +support both the \method{readline()} and the \method{read()} methods +on file-like objects. + +The text contained in \var{fp} must be formatted as a block of \rfc{2822} +style headers and header continuation lines, optionally preceded by a +envelope header. The header block is terminated either by the +end of the data or by a blank line. Following the header block is the +body of the message (which may contain MIME-encoded subparts). + +Optional \var{headersonly} is as with the \method{parse()} method. + +\versionchanged[The \var{headersonly} flag was added]{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[Parser]{parsestr}{text\optional{, headersonly}} +Similar to the \method{parse()} method, except it takes a string +object instead of a file-like object. Calling this method on a string +is exactly equivalent to wrapping \var{text} in a \class{StringIO} +instance first and calling \method{parse()}. + +Optional \var{headersonly} is a flag specifying whether to stop +parsing after reading the headers or not. The default is \code{False}, +meaning it parses the entire contents of the file. + +\versionchanged[The \var{headersonly} flag was added]{2.2.2} +\end{methoddesc} + +Since creating a message object structure from a string or a file +object is such a common task, two functions are provided as a +convenience. They are available in the top-level \module{email} +package namespace. + +\begin{funcdesc}{message_from_string}{s\optional{, _class\optional{, strict}}} +Return a message object structure from a string. This is exactly +equivalent to \code{Parser().parsestr(s)}. Optional \var{_class} and +\var{strict} are interpreted as with the \class{Parser} class constructor. + +\versionchanged[The \var{strict} flag was added]{2.2.2} +\end{funcdesc} + +\begin{funcdesc}{message_from_file}{fp\optional{, _class\optional{, strict}}} +Return a message object structure tree from an open file object. This +is exactly equivalent to \code{Parser().parse(fp)}. Optional +\var{_class} and \var{strict} are interpreted as with the +\class{Parser} class constructor. + +\versionchanged[The \var{strict} flag was added]{2.2.2} +\end{funcdesc} + +Here's an example of how you might use this at an interactive Python +prompt: + +\begin{verbatim} +>>> import email +>>> msg = email.message_from_string(myString) +\end{verbatim} + +\subsubsection{Additional notes} + +Here are some notes on the parsing semantics: + +\begin{itemize} +\item Most non-\mimetype{multipart} type messages are parsed as a single + message object with a string payload. These objects will return + \code{False} for \method{is_multipart()}. Their + \method{get_payload()} method will return a string object. + +\item All \mimetype{multipart} type messages will be parsed as a + container message object with a list of sub-message objects for + their payload. The outer container message will return + \code{True} for \method{is_multipart()} and their + \method{get_payload()} method will return the list of + \class{Message} subparts. + +\item Most messages with a content type of \mimetype{message/*} + (e.g. \mimetype{message/delivery-status} and + \mimetype{message/rfc822}) will also be parsed as container + object containing a list payload of length 1. Their + \method{is_multipart()} method will return \code{True}. The + single element in the list payload will be a sub-message object. + +\item Some non-standards compliant messages may not be internally consistent + about their \mimetype{multipart}-edness. Such messages may have a + \mailheader{Content-Type} header of type \mimetype{multipart}, but their + \method{is_multipart()} method may return \code{False}. If such + messages were parsed with the \class{FeedParser}, they will have an + instance of the \class{MultipartInvariantViolationDefect} class in their + \var{defects} attribute list. See \refmodule{email.errors} for + details. +\end{itemize} diff --git a/sys/src/cmd/python/Doc/lib/emailutil.tex b/sys/src/cmd/python/Doc/lib/emailutil.tex new file mode 100644 index 000000000..fe9647363 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/emailutil.tex @@ -0,0 +1,157 @@ +\declaremodule{standard}{email.utils} +\modulesynopsis{Miscellaneous email package utilities.} + +There are several useful utilities provided in the \module{email.utils} +module: + +\begin{funcdesc}{quote}{str} +Return a new string with backslashes in \var{str} replaced by two +backslashes, and double quotes replaced by backslash-double quote. +\end{funcdesc} + +\begin{funcdesc}{unquote}{str} +Return a new string which is an \emph{unquoted} version of \var{str}. +If \var{str} ends and begins with double quotes, they are stripped +off. Likewise if \var{str} ends and begins with angle brackets, they +are stripped off. +\end{funcdesc} + +\begin{funcdesc}{parseaddr}{address} +Parse address -- which should be the value of some address-containing +field such as \mailheader{To} or \mailheader{Cc} -- into its constituent +\emph{realname} and \emph{email address} parts. Returns a tuple of that +information, unless the parse fails, in which case a 2-tuple of +\code{('', '')} is returned. +\end{funcdesc} + +\begin{funcdesc}{formataddr}{pair} +The inverse of \method{parseaddr()}, this takes a 2-tuple of the form +\code{(realname, email_address)} and returns the string value suitable +for a \mailheader{To} or \mailheader{Cc} header. If the first element of +\var{pair} is false, then the second element is returned unmodified. +\end{funcdesc} + +\begin{funcdesc}{getaddresses}{fieldvalues} +This method returns a list of 2-tuples of the form returned by +\code{parseaddr()}. \var{fieldvalues} is a sequence of header field +values as might be returned by \method{Message.get_all()}. Here's a +simple example that gets all the recipients of a message: + +\begin{verbatim} +from email.utils import getaddresses + +tos = msg.get_all('to', []) +ccs = msg.get_all('cc', []) +resent_tos = msg.get_all('resent-to', []) +resent_ccs = msg.get_all('resent-cc', []) +all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs) +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{parsedate}{date} +Attempts to parse a date according to the rules in \rfc{2822}. +however, some mailers don't follow that format as specified, so +\function{parsedate()} tries to guess correctly in such cases. +\var{date} is a string containing an \rfc{2822} date, such as +\code{"Mon, 20 Nov 1995 19:12:08 -0500"}. If it succeeds in parsing +the date, \function{parsedate()} returns a 9-tuple that can be passed +directly to \function{time.mktime()}; otherwise \code{None} will be +returned. Note that fields 6, 7, and 8 of the result tuple are not +usable. +\end{funcdesc} + +\begin{funcdesc}{parsedate_tz}{date} +Performs the same function as \function{parsedate()}, but returns +either \code{None} or a 10-tuple; the first 9 elements make up a tuple +that can be passed directly to \function{time.mktime()}, and the tenth +is the offset of the date's timezone from UTC (which is the official +term for Greenwich Mean Time)\footnote{Note that the sign of the timezone +offset is the opposite of the sign of the \code{time.timezone} +variable for the same timezone; the latter variable follows the +\POSIX{} standard while this module follows \rfc{2822}.}. If the input +string has no timezone, the last element of the tuple returned is +\code{None}. Note that fields 6, 7, and 8 of the result tuple are not +usable. +\end{funcdesc} + +\begin{funcdesc}{mktime_tz}{tuple} +Turn a 10-tuple as returned by \function{parsedate_tz()} into a UTC +timestamp. It the timezone item in the tuple is \code{None}, assume +local time. Minor deficiency: \function{mktime_tz()} interprets the +first 8 elements of \var{tuple} as a local time and then compensates +for the timezone difference. This may yield a slight error around +changes in daylight savings time, though not worth worrying about for +common use. +\end{funcdesc} + +\begin{funcdesc}{formatdate}{\optional{timeval\optional{, localtime}\optional{, usegmt}}} +Returns a date string as per \rfc{2822}, e.g.: + +\begin{verbatim} +Fri, 09 Nov 2001 01:08:47 -0000 +\end{verbatim} + +Optional \var{timeval} if given is a floating point time value as +accepted by \function{time.gmtime()} and \function{time.localtime()}, +otherwise the current time is used. + +Optional \var{localtime} is a flag that when \code{True}, interprets +\var{timeval}, and returns a date relative to the local timezone +instead of UTC, properly taking daylight savings time into account. +The default is \code{False} meaning UTC is used. + +Optional \var{usegmt} is a flag that when \code{True}, outputs a +date string with the timezone as an ascii string \code{GMT}, rather +than a numeric \code{-0000}. This is needed for some protocols (such +as HTTP). This only applies when \var{localtime} is \code{False}. +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{make_msgid}{\optional{idstring}} +Returns a string suitable for an \rfc{2822}-compliant +\mailheader{Message-ID} header. Optional \var{idstring} if given, is +a string used to strengthen the uniqueness of the message id. +\end{funcdesc} + +\begin{funcdesc}{decode_rfc2231}{s} +Decode the string \var{s} according to \rfc{2231}. +\end{funcdesc} + +\begin{funcdesc}{encode_rfc2231}{s\optional{, charset\optional{, language}}} +Encode the string \var{s} according to \rfc{2231}. Optional +\var{charset} and \var{language}, if given is the character set name +and language name to use. If neither is given, \var{s} is returned +as-is. If \var{charset} is given but \var{language} is not, the +string is encoded using the empty string for \var{language}. +\end{funcdesc} + +\begin{funcdesc}{collapse_rfc2231_value}{value\optional{, errors\optional{, + fallback_charset}}} +When a header parameter is encoded in \rfc{2231} format, +\method{Message.get_param()} may return a 3-tuple containing the character +set, language, and value. \function{collapse_rfc2231_value()} turns this into +a unicode string. Optional \var{errors} is passed to the \var{errors} +argument of the built-in \function{unicode()} function; it defaults to +\code{replace}. Optional \var{fallback_charset} specifies the character set +to use if the one in the \rfc{2231} header is not known by Python; it defaults +to \code{us-ascii}. + +For convenience, if the \var{value} passed to +\function{collapse_rfc2231_value()} is not a tuple, it should be a string and +it is returned unquoted. +\end{funcdesc} + +\begin{funcdesc}{decode_params}{params} +Decode parameters list according to \rfc{2231}. \var{params} is a +sequence of 2-tuples containing elements of the form +\code{(content-type, string-value)}. +\end{funcdesc} + +\versionchanged[The \function{dump_address_pair()} function has been removed; +use \function{formataddr()} instead]{2.4} + +\versionchanged[The \function{decode()} function has been removed; use the +\method{Header.decode_header()} method instead]{2.4} + +\versionchanged[The \function{encode()} function has been removed; use the +\method{Header.encode()} method instead]{2.4} diff --git a/sys/src/cmd/python/Doc/lib/fileformats.tex b/sys/src/cmd/python/Doc/lib/fileformats.tex new file mode 100644 index 000000000..9f9c116c3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/fileformats.tex @@ -0,0 +1,7 @@ +\chapter{File Formats} +\label{fileformats} + +The modules described in this chapter parse various miscellaneous file +formats that aren't markup languages or are related to e-mail. + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/filesys.tex b/sys/src/cmd/python/Doc/lib/filesys.tex new file mode 100644 index 000000000..0c682c85c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/filesys.tex @@ -0,0 +1,18 @@ +\chapter{File and Directory Access} +\label{filesys} + +The modules described in this chapter deal with disk files and +directories. For example, there are modules for reading the +properties of files, manipulating paths in a portable way, and +creating temporary files. The full list of modules in this chapter is: + +\localmoduletable + +% XXX can this be included in the seealso environment? --amk +Also see section \ref{bltin-file-objects} for a description +of Python's built-in file objects. + +\begin{seealso} + \seemodule{os}{Operating system interfaces, including functions to + work with files at a lower level than the built-in file object.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/frameworks.tex b/sys/src/cmd/python/Doc/lib/frameworks.tex new file mode 100644 index 000000000..ffe300e5d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/frameworks.tex @@ -0,0 +1,10 @@ +\chapter{Program Frameworks} +\label{frameworks} + +The modules described in this chapter are frameworks that will largely +dictate the structure of your program. Currently the modules described +here are all oriented toward writing command-line interfaces. + +The full list of modules described in this chapter is: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/i18n.tex b/sys/src/cmd/python/Doc/lib/i18n.tex new file mode 100644 index 000000000..699a60c63 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/i18n.tex @@ -0,0 +1,11 @@ +\chapter{Internationalization} +\label{i18n} + +The modules described in this chapter help you write +software that is independent of language and locale +by providing mechanisms for selecting a language to be used in +program messages or by tailoring output to match local conventions. + +The list of modules described in this chapter is: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/internet.tex b/sys/src/cmd/python/Doc/lib/internet.tex new file mode 100644 index 000000000..72ac4b308 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/internet.tex @@ -0,0 +1,13 @@ +\chapter{Internet Protocols and Support \label{internet}} + +\index{WWW} +\index{Internet} +\index{World Wide Web} + +The modules described in this chapter implement Internet protocols and +support for related technology. They are all implemented in Python. +Most of these modules require the presence of the system-dependent +module \refmodule{socket}\refbimodindex{socket}, which is currently +supported on most popular platforms. Here is an overview: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/ipc.tex b/sys/src/cmd/python/Doc/lib/ipc.tex new file mode 100644 index 000000000..cd9505666 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/ipc.tex @@ -0,0 +1,14 @@ +\chapter{Interprocess Communication and Networking} +\label{ipc} + +The modules described in this chapter provide mechanisms for different +processes to communicate. + +Some modules only work for two processes that are on the same machine, +e.g. \module{signal} and \module{subprocess}. Other modules support +networking protocols that two or more processes can used to +communicate across machines. + +The list of modules described in this chapter is: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/language.tex b/sys/src/cmd/python/Doc/lib/language.tex new file mode 100644 index 000000000..5cdb11329 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/language.tex @@ -0,0 +1,10 @@ +\chapter{Python Language Services + \label{language}} + +Python provides a number of modules to assist in working with the +Python language. These modules support tokenizing, parsing, syntax +analysis, bytecode disassembly, and various other facilities. + +These modules include: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/lib.tex b/sys/src/cmd/python/Doc/lib/lib.tex new file mode 100644 index 000000000..837c75917 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/lib.tex @@ -0,0 +1,487 @@ +\documentclass{manual} + +% NOTE: this file controls which chapters/sections of the library +% manual are actually printed. It is easy to customize your manual +% by commenting out sections that you're not interested in. + +\title{Python Library Reference} + +\input{boilerplate} + +\makeindex % tell \index to actually write the + % .idx file +\makemodindex % ... and the module index as well. + + +\begin{document} + +\maketitle + +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +\input{copyright} + +\begin{abstract} + +\noindent +Python is an extensible, interpreted, object-oriented programming +language. It supports a wide range of applications, from simple text +processing scripts to interactive Web browsers. + +While the \citetitle[../ref/ref.html]{Python Reference Manual} +describes the exact syntax and semantics of the language, it does not +describe the standard library that is distributed with the language, +and which greatly enhances its immediate usability. This library +contains built-in modules (written in C) that provide access to system +functionality such as file I/O that would otherwise be inaccessible to +Python programmers, as well as modules written in Python that provide +standardized solutions for many problems that occur in everyday +programming. Some of these modules are explicitly designed to +encourage and enhance the portability of Python programs. + +This library reference manual documents Python's standard library, as +well as many optional library modules (which may or may not be +available, depending on whether the underlying platform supports them +and on the configuration choices made at compile time). It also +documents the standard types of the language and its built-in +functions and exceptions, many of which are not or incompletely +documented in the Reference Manual. + +This manual assumes basic knowledge about the Python language. For an +informal introduction to Python, see the +\citetitle[../tut/tut.html]{Python Tutorial}; the +\citetitle[../ref/ref.html]{Python Reference Manual} remains the +highest authority on syntactic and semantic questions. Finally, the +manual entitled \citetitle[../ext/ext.html]{Extending and Embedding +the Python Interpreter} describes how to add new extensions to Python +and how to embed it in other applications. + +\end{abstract} + +\tableofcontents + + % Chapter title: + +\input{libintro} % Introduction + + +% ============= +% BUILT-INs +% ============= + +\input{libobjs} % Built-in Exceptions and Functions +\input{libfuncs} +\input{libexcs} +\input{libconsts} + +\input{libstdtypes} % Built-in types + + +% ============= +% BASIC/GENERAL-PURPOSE OBJECTS +% ============= + +% Strings +\input{libstrings} % String Services +\input{libstring} +\input{libre} +\input{libstruct} % XXX also/better in File Formats? +\input{libdifflib} +\input{libstringio} +\input{libtextwrap} +\input{libcodecs} +\input{libunicodedata} +\input{libstringprep} +\input{libfpformat} + + +\input{datatypes} % Data types and structures +\input{libdatetime} +\input{libcalendar} +\input{libcollections} +\input{libheapq} +\input{libbisect} +\input{libarray} +\input{libsets} +\input{libsched} +\input{libmutex} +\input{libqueue} +\input{libweakref} +\input{libuserdict} + +% General object services +% XXX intro +\input{libtypes} +\input{libnew} +\input{libcopy} +\input{libpprint} +\input{librepr} + + +\input{numeric} % Numeric/Mathematical modules +\input{libmath} +\input{libcmath} +\input{libdecimal} +\input{librandom} + +% Functions, Functional, Generators and Iterators +% XXX intro functional +\input{libitertools} +\input{libfunctools} +\input{liboperator} % from runtime - better with itertools and functools + + +% ============= +% DATA FORMATS +% ============= + +% Big move - include all the markup and internet formats here + +% MIME & email stuff +\input{netdata} % Internet Data Handling +\input{email} +\input{libmailcap} +\input{libmailbox} +\input{libmhlib} +\input{libmimetools} +\input{libmimetypes} +\input{libmimewriter} +\input{libmimify} +\input{libmultifile} +\input{librfc822} + +% encoding stuff +\input{libbase64} +\input{libbinhex} +\input{libbinascii} +\input{libquopri} +\input{libuu} + +\input{markup} % Structured Markup Processing Tools +\input{libhtmlparser} +\input{libsgmllib} +\input{libhtmllib} +\input{libpyexpat} +\input{xmldom} +\input{xmldomminidom} +\input{xmldompulldom} +\input{xmlsax} +\input{xmlsaxhandler} +\input{xmlsaxutils} +\input{xmlsaxreader} +\input{libetree} +% \input{libxmllib} + +\input{fileformats} % Miscellaneous file formats +\input{libcsv} +\input{libcfgparser} +\input{librobotparser} +\input{libnetrc} +\input{libxdrlib} + +\input{libcrypto} % Cryptographic Services +\input{libhashlib} +\input{libhmac} +\input{libmd5} +\input{libsha} + +% ============= +% FILE & DATABASE STORAGE +% ============= + +\input{filesys} % File/directory support +\input{libposixpath} % os.path +\input{libfileinput} +\input{libstat} +\input{libstatvfs} +\input{libfilecmp} +\input{libtempfile} +\input{libglob} +\input{libfnmatch} +\input{liblinecache} +\input{libshutil} +\input{libdircache} + + +\input{archiving} % Data compression and archiving +\input{libzlib} +\input{libgzip} +\input{libbz2} +\input{libzipfile} +\input{libtarfile} + + +\input{persistence} % Persistent storage +\input{libpickle} +\input{libcopyreg} % really copy_reg % from runtime... +\input{libshelve} +\input{libmarshal} +\input{libanydbm} +\input{libwhichdb} +\input{libdbm} +\input{libgdbm} +\input{libdbhash} +\input{libbsddb} +\input{libdumbdbm} +\input{libsqlite3} + + +% ============= +% OS +% ============= + + +\input{liballos} % Generic Operating System Services +\input{libos} +\input{libtime} +\input{liboptparse} +\input{libgetopt} +\input{liblogging} +\input{libgetpass} +\input{libcurses} +\input{libascii} % curses.ascii +\input{libcursespanel} +\input{libplatform} +\input{liberrno} +\input{libctypes} + +\input{libsomeos} % Optional Operating System Services +\input{libselect} +\input{libthread} +\input{libthreading} +\input{libdummythread} +\input{libdummythreading} +\input{libmmap} +\input{libreadline} +\input{librlcompleter} + +\input{libunix} % UNIX Specific Services +\input{libposix} +\input{libpwd} +\input{libspwd} +\input{libgrp} +\input{libcrypt} +\input{libdl} +\input{libtermios} +\input{libtty} +\input{libpty} +\input{libfcntl} +\input{libpipes} +\input{libposixfile} +\input{libresource} +\input{libnis} +\input{libsyslog} +\input{libcommands} + + +% ============= +% NETWORK & COMMUNICATIONS +% ============= + +\input{ipc} % Interprocess communication/networking +\input{libsubprocess} +\input{libsocket} +\input{libsignal} +\input{libpopen2} +\input{libasyncore} +\input{libasynchat} + +\input{internet} % Internet Protocols +\input{libwebbrowser} +\input{libcgi} +\input{libcgitb} +\input{libwsgiref} +\input{liburllib} +\input{liburllib2} +\input{libhttplib} +\input{libftplib} +\input{libgopherlib} +\input{libpoplib} +\input{libimaplib} +\input{libnntplib} +\input{libsmtplib} +\input{libsmtpd} +\input{libtelnetlib} +\input{libuuid} +\input{liburlparse} +\input{libsocksvr} +\input{libbasehttp} +\input{libsimplehttp} +\input{libcgihttp} +\input{libcookielib} +\input{libcookie} +\input{libxmlrpclib} +\input{libsimplexmlrpc} +\input{libdocxmlrpc} + +% ============= +% MULTIMEDIA +% ============= + +\input{libmm} % Multimedia Services +\input{libaudioop} +\input{libimageop} +\input{libaifc} +\input{libsunau} +\input{libwave} +\input{libchunk} +\input{libcolorsys} +\input{librgbimg} +\input{libimghdr} +\input{libsndhdr} +\input{libossaudiodev} + +% Tkinter is a chapter in its own right. +\input{tkinter} + +% % Internationalization +\input{i18n} +\input{libgettext} +\input{liblocale} + +% ============= +% PROGRAM FRAMEWORKS +% ============= +\input{frameworks} +\input{libcmd} +\input{libshlex} + + +% ============= +% DEVELOPMENT TOOLS +% ============= +% % Software development support +\input{development} +\input{libpydoc} +\input{libdoctest} +\input{libunittest} +\input{libtest} + +\input{libpdb} % The Python Debugger + +\input{libprofile} % The Python Profiler +\input{libhotshot} % unmaintained C profiler +\input{libtimeit} +\input{libtrace} + +% ============= +% PYTHON ENGINE +% ============= + +% Runtime services +\input{libpython} % Python Runtime Services +\input{libsys} +\input{libbltin} % really __builtin__ +\input{libmain} % really __main__ +\input{libwarnings} +\input{libcontextlib} +\input{libatexit} +\input{libtraceback} +\input{libfuture} % really __future__ +\input{libgc} +\input{libinspect} +\input{libsite} +\input{libuser} +\input{libfpectl} + + +\input{custominterp} % Custom interpreter +\input{libcode} +\input{libcodeop} +\input{librestricted} % Restricted Execution +\input{librexec} +\input{libbastion} + + +\input{modules} % Importing Modules +\input{libimp} +\input{libzipimport} +\input{libpkgutil} +\input{libmodulefinder} +\input{librunpy} + + +% ============= +% PYTHON LANGUAGE & COMPILER +% ============= + +\input{language} % Python Language Services +\input{libparser} +\input{libsymbol} +\input{libtoken} +\input{libkeyword} +\input{libtokenize} +\input{libtabnanny} +\input{libpyclbr} +\input{libpycompile} % really py_compile +\input{libcompileall} +\input{libdis} +\input{libpickletools} +\input{distutils} + +\input{compiler} % compiler package +\input{libast} + +\input{libmisc} % Miscellaneous Services +\input{libformatter} + +% ============= +% OTHER PLATFORM-SPECIFIC STUFF +% ============= + +%\input{libamoeba} % AMOEBA ONLY + +%\input{libstdwin} % STDWIN ONLY + +\input{libsgi} % SGI IRIX ONLY +\input{libal} +\input{libcd} +\input{libfl} +\input{libfm} +\input{libgl} +\input{libimgfile} +\input{libjpeg} +%\input{libpanel} + +\input{libsun} % SUNOS ONLY +\input{libsunaudio} + +\input{windows} % MS Windows ONLY +\input{libmsilib} +\input{libmsvcrt} +\input{libwinreg} +\input{libwinsound} + +\appendix +\input{libundoc} + +%\chapter{Obsolete Modules} +%\input{libcmpcache} +%\input{libcmp} +%\input{libni} + +\chapter{Reporting Bugs} +\input{reportingbugs} + +\chapter{History and License} +\input{license} + +% +% The ugly "%begin{latexonly}" pseudo-environments are really just to +% keep LaTeX2HTML quiet during the \renewcommand{} macros; they're +% not really valuable. +% + +%begin{latexonly} +\renewcommand{\indexname}{Module Index} +%end{latexonly} +\input{modlib.ind} % Module Index + +%begin{latexonly} +\renewcommand{\indexname}{Index} +%end{latexonly} +\input{lib.ind} % Index + +\end{document} diff --git a/sys/src/cmd/python/Doc/lib/libaifc.tex b/sys/src/cmd/python/Doc/lib/libaifc.tex new file mode 100644 index 000000000..65abe8484 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libaifc.tex @@ -0,0 +1,202 @@ +\section{\module{aifc} --- + Read and write AIFF and AIFC files} + +\declaremodule{standard}{aifc} +\modulesynopsis{Read and write audio files in AIFF or AIFC format.} + + +This module provides support for reading and writing AIFF and AIFF-C +files. AIFF is Audio Interchange File Format, a format for storing +digital audio samples in a file. AIFF-C is a newer version of the +format that includes the ability to compress the audio data. +\index{Audio Interchange File Format} +\index{AIFF} +\index{AIFF-C} + +\strong{Caveat:} Some operations may only work under IRIX; these will +raise \exception{ImportError} when attempting to import the +\module{cl} module, which is only available on IRIX. + +Audio files have a number of parameters that describe the audio data. +The sampling rate or frame rate is the number of times per second the +sound is sampled. The number of channels indicate if the audio is +mono, stereo, or quadro. Each frame consists of one sample per +channel. The sample size is the size in bytes of each sample. Thus a +frame consists of \var{nchannels}*\var{samplesize} bytes, and a +second's worth of audio consists of +\var{nchannels}*\var{samplesize}*\var{framerate} bytes. + +For example, CD quality audio has a sample size of two bytes (16 +bits), uses two channels (stereo) and has a frame rate of 44,100 +frames/second. This gives a frame size of 4 bytes (2*2), and a +second's worth occupies 2*2*44100 bytes (176,400 bytes). + +Module \module{aifc} defines the following function: + +\begin{funcdesc}{open}{file\optional{, mode}} +Open an AIFF or AIFF-C file and return an object instance with +methods that are described below. The argument \var{file} is either a +string naming a file or a file object. \var{mode} must be \code{'r'} +or \code{'rb'} when the file must be opened for reading, or \code{'w'} +or \code{'wb'} when the file must be opened for writing. If omitted, +\code{\var{file}.mode} is used if it exists, otherwise \code{'rb'} is +used. When used for writing, the file object should be seekable, +unless you know ahead of time how many samples you are going to write +in total and use \method{writeframesraw()} and \method{setnframes()}. +\end{funcdesc} + +Objects returned by \function{open()} when a file is opened for +reading have the following methods: + +\begin{methoddesc}[aifc]{getnchannels}{} +Return the number of audio channels (1 for mono, 2 for stereo). +\end{methoddesc} + +\begin{methoddesc}[aifc]{getsampwidth}{} +Return the size in bytes of individual samples. +\end{methoddesc} + +\begin{methoddesc}[aifc]{getframerate}{} +Return the sampling rate (number of audio frames per second). +\end{methoddesc} + +\begin{methoddesc}[aifc]{getnframes}{} +Return the number of audio frames in the file. +\end{methoddesc} + +\begin{methoddesc}[aifc]{getcomptype}{} +Return a four-character string describing the type of compression used +in the audio file. For AIFF files, the returned value is +\code{'NONE'}. +\end{methoddesc} + +\begin{methoddesc}[aifc]{getcompname}{} +Return a human-readable description of the type of compression used in +the audio file. For AIFF files, the returned value is \code{'not +compressed'}. +\end{methoddesc} + +\begin{methoddesc}[aifc]{getparams}{} +Return a tuple consisting of all of the above values in the above +order. +\end{methoddesc} + +\begin{methoddesc}[aifc]{getmarkers}{} +Return a list of markers in the audio file. A marker consists of a +tuple of three elements. The first is the mark ID (an integer), the +second is the mark position in frames from the beginning of the data +(an integer), the third is the name of the mark (a string). +\end{methoddesc} + +\begin{methoddesc}[aifc]{getmark}{id} +Return the tuple as described in \method{getmarkers()} for the mark +with the given \var{id}. +\end{methoddesc} + +\begin{methoddesc}[aifc]{readframes}{nframes} +Read and return the next \var{nframes} frames from the audio file. The +returned data is a string containing for each frame the uncompressed +samples of all channels. +\end{methoddesc} + +\begin{methoddesc}[aifc]{rewind}{} +Rewind the read pointer. The next \method{readframes()} will start from +the beginning. +\end{methoddesc} + +\begin{methoddesc}[aifc]{setpos}{pos} +Seek to the specified frame number. +\end{methoddesc} + +\begin{methoddesc}[aifc]{tell}{} +Return the current frame number. +\end{methoddesc} + +\begin{methoddesc}[aifc]{close}{} +Close the AIFF file. After calling this method, the object can no +longer be used. +\end{methoddesc} + +Objects returned by \function{open()} when a file is opened for +writing have all the above methods, except for \method{readframes()} and +\method{setpos()}. In addition the following methods exist. The +\method{get*()} methods can only be called after the corresponding +\method{set*()} methods have been called. Before the first +\method{writeframes()} or \method{writeframesraw()}, all parameters +except for the number of frames must be filled in. + +\begin{methoddesc}[aifc]{aiff}{} +Create an AIFF file. The default is that an AIFF-C file is created, +unless the name of the file ends in \code{'.aiff'} in which case the +default is an AIFF file. +\end{methoddesc} + +\begin{methoddesc}[aifc]{aifc}{} +Create an AIFF-C file. The default is that an AIFF-C file is created, +unless the name of the file ends in \code{'.aiff'} in which case the +default is an AIFF file. +\end{methoddesc} + +\begin{methoddesc}[aifc]{setnchannels}{nchannels} +Specify the number of channels in the audio file. +\end{methoddesc} + +\begin{methoddesc}[aifc]{setsampwidth}{width} +Specify the size in bytes of audio samples. +\end{methoddesc} + +\begin{methoddesc}[aifc]{setframerate}{rate} +Specify the sampling frequency in frames per second. +\end{methoddesc} + +\begin{methoddesc}[aifc]{setnframes}{nframes} +Specify the number of frames that are to be written to the audio file. +If this parameter is not set, or not set correctly, the file needs to +support seeking. +\end{methoddesc} + +\begin{methoddesc}[aifc]{setcomptype}{type, name} +Specify the compression type. If not specified, the audio data will +not be compressed. In AIFF files, compression is not possible. The +name parameter should be a human-readable description of the +compression type, the type parameter should be a four-character +string. Currently the following compression types are supported: +NONE, ULAW, ALAW, G722. +\index{u-LAW} +\index{A-LAW} +\index{G.722} +\end{methoddesc} + +\begin{methoddesc}[aifc]{setparams}{nchannels, sampwidth, framerate, comptype, compname} +Set all the above parameters at once. The argument is a tuple +consisting of the various parameters. This means that it is possible +to use the result of a \method{getparams()} call as argument to +\method{setparams()}. +\end{methoddesc} + +\begin{methoddesc}[aifc]{setmark}{id, pos, name} +Add a mark with the given id (larger than 0), and the given name at +the given position. This method can be called at any time before +\method{close()}. +\end{methoddesc} + +\begin{methoddesc}[aifc]{tell}{} +Return the current write position in the output file. Useful in +combination with \method{setmark()}. +\end{methoddesc} + +\begin{methoddesc}[aifc]{writeframes}{data} +Write data to the output file. This method can only be called after +the audio file parameters have been set. +\end{methoddesc} + +\begin{methoddesc}[aifc]{writeframesraw}{data} +Like \method{writeframes()}, except that the header of the audio file +is not updated. +\end{methoddesc} + +\begin{methoddesc}[aifc]{close}{} +Close the AIFF file. The header of the file is updated to reflect the +actual size of the audio data. After calling this method, the object +can no longer be used. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libal.tex b/sys/src/cmd/python/Doc/lib/libal.tex new file mode 100644 index 000000000..e3fdc9123 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libal.tex @@ -0,0 +1,181 @@ +\section{\module{al} --- + Audio functions on the SGI} + +\declaremodule{builtin}{al} + \platform{IRIX} +\modulesynopsis{Audio functions on the SGI.} + + +This module provides access to the audio facilities of the SGI Indy +and Indigo workstations. See section 3A of the IRIX man pages for +details. You'll need to read those man pages to understand what these +functions do! Some of the functions are not available in IRIX +releases before 4.0.5. Again, see the manual to check whether a +specific function is available on your platform. + +All functions and methods defined in this module are equivalent to +the C functions with \samp{AL} prefixed to their name. + +Symbolic constants from the C header file \code{} are +defined in the standard module +\refmodule[al-constants]{AL}\refstmodindex{AL}, see below. + +\warning{The current version of the audio library may dump core +when bad argument values are passed rather than returning an error +status. Unfortunately, since the precise circumstances under which +this may happen are undocumented and hard to check, the Python +interface can provide no protection against this kind of problems. +(One example is specifying an excessive queue size --- there is no +documented upper limit.)} + +The module defines the following functions: + + +\begin{funcdesc}{openport}{name, direction\optional{, config}} +The name and direction arguments are strings. The optional +\var{config} argument is a configuration object as returned by +\function{newconfig()}. The return value is an \dfn{audio port +object}; methods of audio port objects are described below. +\end{funcdesc} + +\begin{funcdesc}{newconfig}{} +The return value is a new \dfn{audio configuration object}; methods of +audio configuration objects are described below. +\end{funcdesc} + +\begin{funcdesc}{queryparams}{device} +The device argument is an integer. The return value is a list of +integers containing the data returned by \cfunction{ALqueryparams()}. +\end{funcdesc} + +\begin{funcdesc}{getparams}{device, list} +The \var{device} argument is an integer. The list argument is a list +such as returned by \function{queryparams()}; it is modified in place +(!). +\end{funcdesc} + +\begin{funcdesc}{setparams}{device, list} +The \var{device} argument is an integer. The \var{list} argument is a +list such as returned by \function{queryparams()}. +\end{funcdesc} + + +\subsection{Configuration Objects \label{al-config-objects}} + +Configuration objects returned by \function{newconfig()} have the +following methods: + +\begin{methoddesc}[audio configuration]{getqueuesize}{} +Return the queue size. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{setqueuesize}{size} +Set the queue size. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{getwidth}{} +Get the sample width. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{setwidth}{width} +Set the sample width. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{getchannels}{} +Get the channel count. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{setchannels}{nchannels} +Set the channel count. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{getsampfmt}{} +Get the sample format. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{setsampfmt}{sampfmt} +Set the sample format. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{getfloatmax}{} +Get the maximum value for floating sample formats. +\end{methoddesc} + +\begin{methoddesc}[audio configuration]{setfloatmax}{floatmax} +Set the maximum value for floating sample formats. +\end{methoddesc} + + +\subsection{Port Objects \label{al-port-objects}} + +Port objects, as returned by \function{openport()}, have the following +methods: + +\begin{methoddesc}[audio port]{closeport}{} +Close the port. +\end{methoddesc} + +\begin{methoddesc}[audio port]{getfd}{} +Return the file descriptor as an int. +\end{methoddesc} + +\begin{methoddesc}[audio port]{getfilled}{} +Return the number of filled samples. +\end{methoddesc} + +\begin{methoddesc}[audio port]{getfillable}{} +Return the number of fillable samples. +\end{methoddesc} + +\begin{methoddesc}[audio port]{readsamps}{nsamples} +Read a number of samples from the queue, blocking if necessary. +Return the data as a string containing the raw data, (e.g., 2 bytes per +sample in big-endian byte order (high byte, low byte) if you have set +the sample width to 2 bytes). +\end{methoddesc} + +\begin{methoddesc}[audio port]{writesamps}{samples} +Write samples into the queue, blocking if necessary. The samples are +encoded as described for the \method{readsamps()} return value. +\end{methoddesc} + +\begin{methoddesc}[audio port]{getfillpoint}{} +Return the `fill point'. +\end{methoddesc} + +\begin{methoddesc}[audio port]{setfillpoint}{fillpoint} +Set the `fill point'. +\end{methoddesc} + +\begin{methoddesc}[audio port]{getconfig}{} +Return a configuration object containing the current configuration of +the port. +\end{methoddesc} + +\begin{methoddesc}[audio port]{setconfig}{config} +Set the configuration from the argument, a configuration object. +\end{methoddesc} + +\begin{methoddesc}[audio port]{getstatus}{list} +Get status information on last error. +\end{methoddesc} + + +\section{\module{AL} --- + Constants used with the \module{al} module} + +\declaremodule[al-constants]{standard}{AL} + \platform{IRIX} +\modulesynopsis{Constants used with the \module{al} module.} + + +This module defines symbolic constants needed to use the built-in +module \refmodule{al} (see above); they are equivalent to those defined +in the C header file \code{} except that the name prefix +\samp{AL_} is omitted. Read the module source for a complete list of +the defined names. Suggested use: + +\begin{verbatim} +import al +from AL import * +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/liballos.tex b/sys/src/cmd/python/Doc/lib/liballos.tex new file mode 100644 index 000000000..dd046c95b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/liballos.tex @@ -0,0 +1,9 @@ +\chapter{Generic Operating System Services \label{allos}} + +The modules described in this chapter provide interfaces to operating +system features that are available on (almost) all operating systems, +such as files and a clock. The interfaces are generally modeled +after the \UNIX{} or C interfaces, but they are available on most +other systems as well. Here's an overview: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/libamoeba.tex b/sys/src/cmd/python/Doc/lib/libamoeba.tex new file mode 100644 index 000000000..c3274db06 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libamoeba.tex @@ -0,0 +1,132 @@ +\chapter{Amoeba Specific Services} + +\section{\module{amoeba} --- + Amoeba system support} + +\declaremodule{builtin}{amoeba} + \platform{Amoeba} +\modulesynopsis{Functions for the Amoeba operating system.} + + +This module provides some object types and operations useful for +Amoeba applications. It is only available on systems that support +Amoeba operations. RPC errors and other Amoeba errors are reported as +the exception \code{amoeba.error = 'amoeba.error'}. + +The module \module{amoeba} defines the following items: + +\begin{funcdesc}{name_append}{path, cap} +Stores a capability in the Amoeba directory tree. +Arguments are the pathname (a string) and the capability (a capability +object as returned by +\function{name_lookup()}). +\end{funcdesc} + +\begin{funcdesc}{name_delete}{path} +Deletes a capability from the Amoeba directory tree. +Argument is the pathname. +\end{funcdesc} + +\begin{funcdesc}{name_lookup}{path} +Looks up a capability. +Argument is the pathname. +Returns a +\dfn{capability} +object, to which various interesting operations apply, described below. +\end{funcdesc} + +\begin{funcdesc}{name_replace}{path, cap} +Replaces a capability in the Amoeba directory tree. +Arguments are the pathname and the new capability. +(This differs from +\function{name_append()} +in the behavior when the pathname already exists: +\function{name_append()} +finds this an error while +\function{name_replace()} +allows it, as its name suggests.) +\end{funcdesc} + +\begin{datadesc}{capv} +A table representing the capability environment at the time the +interpreter was started. +(Alas, modifying this table does not affect the capability environment +of the interpreter.) +For example, +\code{amoeba.capv['ROOT']} +is the capability of your root directory, similar to +\code{getcap("ROOT")} +in C. +\end{datadesc} + +\begin{excdesc}{error} +The exception raised when an Amoeba function returns an error. +The value accompanying this exception is a pair containing the numeric +error code and the corresponding string, as returned by the C function +\cfunction{err_why()}. +\end{excdesc} + +\begin{funcdesc}{timeout}{msecs} +Sets the transaction timeout, in milliseconds. +Returns the previous timeout. +Initially, the timeout is set to 2 seconds by the Python interpreter. +\end{funcdesc} + +\subsection{Capability Operations} + +Capabilities are written in a convenient \ASCII{} format, also used by the +Amoeba utilities +\emph{c2a}(U) +and +\emph{a2c}(U). +For example: + +\begin{verbatim} +>>> amoeba.name_lookup('/profile/cap') +aa:1c:95:52:6a:fa/14(ff)/8e:ba:5b:8:11:1a +>>> +\end{verbatim} +% +The following methods are defined for capability objects. + +\setindexsubitem{(capability method)} +\begin{funcdesc}{dir_list}{} +Returns a list of the names of the entries in an Amoeba directory. +\end{funcdesc} + +\begin{funcdesc}{b_read}{offset, maxsize} +Reads (at most) +\var{maxsize} +bytes from a bullet file at offset +\var{offset.} +The data is returned as a string. +EOF is reported as an empty string. +\end{funcdesc} + +\begin{funcdesc}{b_size}{} +Returns the size of a bullet file. +\end{funcdesc} + +\begin{funcdesc}{dir_append}{} +\funcline{dir_delete}{} +\funcline{dir_lookup}{} +\funcline{dir_replace}{} +Like the corresponding +\samp{name_}* +functions, but with a path relative to the capability. +(For paths beginning with a slash the capability is ignored, since this +is the defined semantics for Amoeba.) +\end{funcdesc} + +\begin{funcdesc}{std_info}{} +Returns the standard info string of the object. +\end{funcdesc} + +\begin{funcdesc}{tod_gettime}{} +Returns the time (in seconds since the Epoch, in UCT, as for \POSIX) from +a time server. +\end{funcdesc} + +\begin{funcdesc}{tod_settime}{t} +Sets the time kept by a time server. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libanydbm.tex b/sys/src/cmd/python/Doc/lib/libanydbm.tex new file mode 100644 index 000000000..badc6ecfc --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libanydbm.tex @@ -0,0 +1,85 @@ +\section{\module{anydbm} --- + Generic access to DBM-style databases} + +\declaremodule{standard}{anydbm} +\modulesynopsis{Generic interface to DBM-style database modules.} + + +\module{anydbm} is a generic interface to variants of the DBM +database --- \refmodule{dbhash}\refstmodindex{dbhash} (requires +\refmodule{bsddb}\refbimodindex{bsddb}), +\refmodule{gdbm}\refbimodindex{gdbm}, or +\refmodule{dbm}\refbimodindex{dbm}. If none of these modules is +installed, the slow-but-simple implementation in module +\refmodule{dumbdbm}\refstmodindex{dumbdbm} will be used. + +\begin{funcdesc}{open}{filename\optional{, flag\optional{, mode}}} +Open the database file \var{filename} and return a corresponding object. + +If the database file already exists, the \refmodule{whichdb} module is +used to determine its type and the appropriate module is used; if it +does not exist, the first module listed above that can be imported is +used. + +The optional \var{flag} argument can be +\code{'r'} to open an existing database for reading only, +\code{'w'} to open an existing database for reading and writing, +\code{'c'} to create the database if it doesn't exist, or +\code{'n'}, which will always create a new empty database. If not +specified, the default value is \code{'r'}. + +The optional \var{mode} argument is the \UNIX{} mode of the file, used +only when the database has to be created. It defaults to octal +\code{0666} (and will be modified by the prevailing umask). +\end{funcdesc} + +\begin{excdesc}{error} +A tuple containing the exceptions that can be raised by each of the +supported modules, with a unique exception \exception{anydbm.error} as +the first item --- the latter is used when \exception{anydbm.error} is +raised. +\end{excdesc} + +The object returned by \function{open()} supports most of the same +functionality as dictionaries; keys and their corresponding values can +be stored, retrieved, and deleted, and the \method{has_key()} and +\method{keys()} methods are available. Keys and values must always be +strings. + +The following example records some hostnames and a corresponding title, +and then prints out the contents of the database: + +\begin{verbatim} +import anydbm + +# Open database, creating it if necessary. +db = anydbm.open('cache', 'c') + +# Record some values +db['www.python.org'] = 'Python Website' +db['www.cnn.com'] = 'Cable News Network' + +# Loop through contents. Other dictionary methods +# such as .keys(), .values() also work. +for k, v in db.iteritems(): + print k, '\t', v + +# Storing a non-string key or value will raise an exception (most +# likely a TypeError). +db['www.yahoo.com'] = 4 + +# Close when done. +db.close() +\end{verbatim} + + +\begin{seealso} + \seemodule{dbhash}{BSD \code{db} database interface.} + \seemodule{dbm}{Standard \UNIX{} database interface.} + \seemodule{dumbdbm}{Portable implementation of the \code{dbm} interface.} + \seemodule{gdbm}{GNU database interface, based on the \code{dbm} interface.} + \seemodule{shelve}{General object persistence built on top of + the Python \code{dbm} interface.} + \seemodule{whichdb}{Utility module used to determine the type of an + existing database.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libarray.tex b/sys/src/cmd/python/Doc/lib/libarray.tex new file mode 100644 index 000000000..eaf58884e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libarray.tex @@ -0,0 +1,241 @@ +\section{\module{array} --- + Efficient arrays of numeric values} + +\declaremodule{builtin}{array} +\modulesynopsis{Efficient arrays of uniformly typed numeric values.} + + +This module defines an object type which can efficiently represent +an array of basic values: characters, integers, floating point +numbers. Arrays\index{arrays} are sequence types and behave very much +like lists, except that the type of objects stored in them is +constrained. The type is specified at object creation time by using a +\dfn{type code}, which is a single character. The following type +codes are defined: + +\begin{tableiv}{c|l|l|c}{code}{Type code}{C Type}{Python Type}{Minimum size in bytes} + \lineiv{'c'}{char} {character} {1} + \lineiv{'b'}{signed char} {int} {1} + \lineiv{'B'}{unsigned char} {int} {1} + \lineiv{'u'}{Py_UNICODE} {Unicode character}{2} + \lineiv{'h'}{signed short} {int} {2} + \lineiv{'H'}{unsigned short}{int} {2} + \lineiv{'i'}{signed int} {int} {2} + \lineiv{'I'}{unsigned int} {long} {2} + \lineiv{'l'}{signed long} {int} {4} + \lineiv{'L'}{unsigned long} {long} {4} + \lineiv{'f'}{float} {float} {4} + \lineiv{'d'}{double} {float} {8} +\end{tableiv} + +The actual representation of values is determined by the machine +architecture (strictly speaking, by the C implementation). The actual +size can be accessed through the \member{itemsize} attribute. The values +stored for \code{'L'} and \code{'I'} items will be represented as +Python long integers when retrieved, because Python's plain integer +type cannot represent the full range of C's unsigned (long) integers. + + +The module defines the following type: + +\begin{funcdesc}{array}{typecode\optional{, initializer}} +Return a new array whose items are restricted by \var{typecode}, +and initialized from the optional \var{initializer} value, which +must be a list, string, or iterable over elements of the +appropriate type. +\versionchanged[Formerly, only lists or strings were accepted]{2.4} +If given a list or string, the initializer is passed to the +new array's \method{fromlist()}, \method{fromstring()}, or +\method{fromunicode()} method (see below) to add initial items to +the array. Otherwise, the iterable initializer is passed to the +\method{extend()} method. +\end{funcdesc} + +\begin{datadesc}{ArrayType} +Obsolete alias for \function{array}. +\end{datadesc} + + +Array objects support the ordinary sequence operations of +indexing, slicing, concatenation, and multiplication. When using +slice assignment, the assigned value must be an array object with the +same type code; in all other cases, \exception{TypeError} is raised. +Array objects also implement the buffer interface, and may be used +wherever buffer objects are supported. + +The following data items and methods are also supported: + +\begin{memberdesc}[array]{typecode} +The typecode character used to create the array. +\end{memberdesc} + +\begin{memberdesc}[array]{itemsize} +The length in bytes of one array item in the internal representation. +\end{memberdesc} + + +\begin{methoddesc}[array]{append}{x} +Append a new item with value \var{x} to the end of the array. +\end{methoddesc} + +\begin{methoddesc}[array]{buffer_info}{} +Return a tuple \code{(\var{address}, \var{length})} giving the current +memory address and the length in elements of the buffer used to hold +array's contents. The size of the memory buffer in bytes can be +computed as \code{\var{array}.buffer_info()[1] * +\var{array}.itemsize}. This is occasionally useful when working with +low-level (and inherently unsafe) I/O interfaces that require memory +addresses, such as certain \cfunction{ioctl()} operations. The +returned numbers are valid as long as the array exists and no +length-changing operations are applied to it. + +\note{When using array objects from code written in C or +\Cpp{} (the only way to effectively make use of this information), it +makes more sense to use the buffer interface supported by array +objects. This method is maintained for backward compatibility and +should be avoided in new code. The buffer interface is documented in +the \citetitle[../api/newTypes.html]{Python/C API Reference Manual}.} +\end{methoddesc} + +\begin{methoddesc}[array]{byteswap}{} +``Byteswap'' all items of the array. This is only supported for +values which are 1, 2, 4, or 8 bytes in size; for other types of +values, \exception{RuntimeError} is raised. It is useful when reading +data from a file written on a machine with a different byte order. +\end{methoddesc} + +\begin{methoddesc}[array]{count}{x} +Return the number of occurrences of \var{x} in the array. +\end{methoddesc} + +\begin{methoddesc}[array]{extend}{iterable} +Append items from \var{iterable} to the end of the array. If +\var{iterable} is another array, it must have \emph{exactly} the same +type code; if not, \exception{TypeError} will be raised. If +\var{iterable} is not an array, it must be iterable and its +elements must be the right type to be appended to the array. +\versionchanged[Formerly, the argument could only be another array]{2.4} +\end{methoddesc} + +\begin{methoddesc}[array]{fromfile}{f, n} +Read \var{n} items (as machine values) from the file object \var{f} +and append them to the end of the array. If less than \var{n} items +are available, \exception{EOFError} is raised, but the items that were +available are still inserted into the array. \var{f} must be a real +built-in file object; something else with a \method{read()} method won't +do. +\end{methoddesc} + +\begin{methoddesc}[array]{fromlist}{list} +Append items from the list. This is equivalent to +\samp{for x in \var{list}:\ a.append(x)} +except that if there is a type error, the array is unchanged. +\end{methoddesc} + +\begin{methoddesc}[array]{fromstring}{s} +Appends items from the string, interpreting the string as an +array of machine values (as if it had been read from a +file using the \method{fromfile()} method). +\end{methoddesc} + +\begin{methoddesc}[array]{fromunicode}{s} +Extends this array with data from the given unicode string. The array +must be a type \code{'u'} array; otherwise a \exception{ValueError} +is raised. Use \samp{array.fromstring(ustr.decode(enc))} to +append Unicode data to an array of some other type. +\end{methoddesc} + +\begin{methoddesc}[array]{index}{x} +Return the smallest \var{i} such that \var{i} is the index of +the first occurrence of \var{x} in the array. +\end{methoddesc} + +\begin{methoddesc}[array]{insert}{i, x} +Insert a new item with value \var{x} in the array before position +\var{i}. Negative values are treated as being relative to the end +of the array. +\end{methoddesc} + +\begin{methoddesc}[array]{pop}{\optional{i}} +Removes the item with the index \var{i} from the array and returns +it. The optional argument defaults to \code{-1}, so that by default +the last item is removed and returned. +\end{methoddesc} + +\begin{methoddesc}[array]{read}{f, n} +\deprecated {1.5.1} + {Use the \method{fromfile()} method.} +Read \var{n} items (as machine values) from the file object \var{f} +and append them to the end of the array. If less than \var{n} items +are available, \exception{EOFError} is raised, but the items that were +available are still inserted into the array. \var{f} must be a real +built-in file object; something else with a \method{read()} method won't +do. +\end{methoddesc} + +\begin{methoddesc}[array]{remove}{x} +Remove the first occurrence of \var{x} from the array. +\end{methoddesc} + +\begin{methoddesc}[array]{reverse}{} +Reverse the order of the items in the array. +\end{methoddesc} + +\begin{methoddesc}[array]{tofile}{f} +Write all items (as machine values) to the file object \var{f}. +\end{methoddesc} + +\begin{methoddesc}[array]{tolist}{} +Convert the array to an ordinary list with the same items. +\end{methoddesc} + +\begin{methoddesc}[array]{tostring}{} +Convert the array to an array of machine values and return the +string representation (the same sequence of bytes that would +be written to a file by the \method{tofile()} method.) +\end{methoddesc} + +\begin{methoddesc}[array]{tounicode}{} +Convert the array to a unicode string. The array must be +a type \code{'u'} array; otherwise a \exception{ValueError} is raised. +Use \samp{array.tostring().decode(enc)} to obtain a unicode string +from an array of some other type. +\end{methoddesc} + +\begin{methoddesc}[array]{write}{f} +\deprecated {1.5.1} + {Use the \method{tofile()} method.} +Write all items (as machine values) to the file object \var{f}. +\end{methoddesc} + +When an array object is printed or converted to a string, it is +represented as \code{array(\var{typecode}, \var{initializer})}. The +\var{initializer} is omitted if the array is empty, otherwise it is a +string if the \var{typecode} is \code{'c'}, otherwise it is a list of +numbers. The string is guaranteed to be able to be converted back to +an array with the same type and value using reverse quotes +(\code{``}), so long as the \function{array()} function has been +imported using \code{from array import array}. Examples: + +\begin{verbatim} +array('l') +array('c', 'hello world') +array('u', u'hello \textbackslash u2641') +array('l', [1, 2, 3, 4, 5]) +array('d', [1.0, 2.0, 3.14]) +\end{verbatim} + + +\begin{seealso} + \seemodule{struct}{Packing and unpacking of heterogeneous binary data.} + \seemodule{xdrlib}{Packing and unpacking of External Data + Representation (XDR) data as used in some remote + procedure call systems.} + \seetitle[http://numpy.sourceforge.net/numdoc/HTML/numdoc.htm]{The + Numerical Python Manual}{The Numeric Python extension + (NumPy) defines another array type; see + \url{http://numpy.sourceforge.net/} for further information + about Numerical Python. (A PDF version of the NumPy manual + is available at + \url{http://numpy.sourceforge.net/numdoc/numdoc.pdf}).} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libascii.tex b/sys/src/cmd/python/Doc/lib/libascii.tex new file mode 100644 index 000000000..003bd9544 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libascii.tex @@ -0,0 +1,175 @@ +\section{\module{curses.ascii} --- + Utilities for ASCII characters} + +\declaremodule{standard}{curses.ascii} +\modulesynopsis{Constants and set-membership functions for + \ASCII\ characters.} +\moduleauthor{Eric S. Raymond}{esr@thyrsus.com} +\sectionauthor{Eric S. Raymond}{esr@thyrsus.com} + +\versionadded{1.6} + +The \module{curses.ascii} module supplies name constants for +\ASCII{} characters and functions to test membership in various +\ASCII{} character classes. The constants supplied are names for +control characters as follows: + +\begin{tableii}{l|l}{constant}{Name}{Meaning} + \lineii{NUL}{} + \lineii{SOH}{Start of heading, console interrupt} + \lineii{STX}{Start of text} + \lineii{ETX}{End of text} + \lineii{EOT}{End of transmission} + \lineii{ENQ}{Enquiry, goes with \constant{ACK} flow control} + \lineii{ACK}{Acknowledgement} + \lineii{BEL}{Bell} + \lineii{BS}{Backspace} + \lineii{TAB}{Tab} + \lineii{HT}{Alias for \constant{TAB}: ``Horizontal tab''} + \lineii{LF}{Line feed} + \lineii{NL}{Alias for \constant{LF}: ``New line''} + \lineii{VT}{Vertical tab} + \lineii{FF}{Form feed} + \lineii{CR}{Carriage return} + \lineii{SO}{Shift-out, begin alternate character set} + \lineii{SI}{Shift-in, resume default character set} + \lineii{DLE}{Data-link escape} + \lineii{DC1}{XON, for flow control} + \lineii{DC2}{Device control 2, block-mode flow control} + \lineii{DC3}{XOFF, for flow control} + \lineii{DC4}{Device control 4} + \lineii{NAK}{Negative acknowledgement} + \lineii{SYN}{Synchronous idle} + \lineii{ETB}{End transmission block} + \lineii{CAN}{Cancel} + \lineii{EM}{End of medium} + \lineii{SUB}{Substitute} + \lineii{ESC}{Escape} + \lineii{FS}{File separator} + \lineii{GS}{Group separator} + \lineii{RS}{Record separator, block-mode terminator} + \lineii{US}{Unit separator} + \lineii{SP}{Space} + \lineii{DEL}{Delete} +\end{tableii} + +Note that many of these have little practical significance in modern +usage. The mnemonics derive from teleprinter conventions that predate +digital computers. + +The module supplies the following functions, patterned on those in the +standard C library: + + +\begin{funcdesc}{isalnum}{c} +Checks for an \ASCII{} alphanumeric character; it is equivalent to +\samp{isalpha(\var{c}) or isdigit(\var{c})}. +\end{funcdesc} + +\begin{funcdesc}{isalpha}{c} +Checks for an \ASCII{} alphabetic character; it is equivalent to +\samp{isupper(\var{c}) or islower(\var{c})}. +\end{funcdesc} + +\begin{funcdesc}{isascii}{c} +Checks for a character value that fits in the 7-bit \ASCII{} set. +\end{funcdesc} + +\begin{funcdesc}{isblank}{c} +Checks for an \ASCII{} whitespace character. +\end{funcdesc} + +\begin{funcdesc}{iscntrl}{c} +Checks for an \ASCII{} control character (in the range 0x00 to 0x1f). +\end{funcdesc} + +\begin{funcdesc}{isdigit}{c} +Checks for an \ASCII{} decimal digit, \character{0} through +\character{9}. This is equivalent to \samp{\var{c} in string.digits}. +\end{funcdesc} + +\begin{funcdesc}{isgraph}{c} +Checks for \ASCII{} any printable character except space. +\end{funcdesc} + +\begin{funcdesc}{islower}{c} +Checks for an \ASCII{} lower-case character. +\end{funcdesc} + +\begin{funcdesc}{isprint}{c} +Checks for any \ASCII{} printable character including space. +\end{funcdesc} + +\begin{funcdesc}{ispunct}{c} +Checks for any printable \ASCII{} character which is not a space or an +alphanumeric character. +\end{funcdesc} + +\begin{funcdesc}{isspace}{c} +Checks for \ASCII{} white-space characters; space, line feed, +carriage return, form feed, horizontal tab, vertical tab. +\end{funcdesc} + +\begin{funcdesc}{isupper}{c} +Checks for an \ASCII{} uppercase letter. +\end{funcdesc} + +\begin{funcdesc}{isxdigit}{c} +Checks for an \ASCII{} hexadecimal digit. This is equivalent to +\samp{\var{c} in string.hexdigits}. +\end{funcdesc} + +\begin{funcdesc}{isctrl}{c} +Checks for an \ASCII{} control character (ordinal values 0 to 31). +\end{funcdesc} + +\begin{funcdesc}{ismeta}{c} +Checks for a non-\ASCII{} character (ordinal values 0x80 and above). +\end{funcdesc} + +These functions accept either integers or strings; when the argument +is a string, it is first converted using the built-in function +\function{ord()}. + +Note that all these functions check ordinal bit values derived from the +first character of the string you pass in; they do not actually know +anything about the host machine's character encoding. For functions +that know about the character encoding (and handle +internationalization properly) see the \refmodule{string} module. + +The following two functions take either a single-character string or +integer byte value; they return a value of the same type. + +\begin{funcdesc}{ascii}{c} +Return the ASCII value corresponding to the low 7 bits of \var{c}. +\end{funcdesc} + +\begin{funcdesc}{ctrl}{c} +Return the control character corresponding to the given character +(the character bit value is bitwise-anded with 0x1f). +\end{funcdesc} + +\begin{funcdesc}{alt}{c} +Return the 8-bit character corresponding to the given ASCII character +(the character bit value is bitwise-ored with 0x80). +\end{funcdesc} + +The following function takes either a single-character string or +integer value; it returns a string. + +\begin{funcdesc}{unctrl}{c} +Return a string representation of the \ASCII{} character \var{c}. If +\var{c} is printable, this string is the character itself. If the +character is a control character (0x00-0x1f) the string consists of a +caret (\character{\^}) followed by the corresponding uppercase letter. +If the character is an \ASCII{} delete (0x7f) the string is +\code{'\^{}?'}. If the character has its meta bit (0x80) set, the meta +bit is stripped, the preceding rules applied, and +\character{!} prepended to the result. +\end{funcdesc} + +\begin{datadesc}{controlnames} +A 33-element string array that contains the \ASCII{} mnemonics for the +thirty-two \ASCII{} control characters from 0 (NUL) to 0x1f (US), in +order, plus the mnemonic \samp{SP} for the space character. +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/libast.tex b/sys/src/cmd/python/Doc/lib/libast.tex new file mode 100644 index 000000000..b2956aeb5 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libast.tex @@ -0,0 +1,57 @@ +% XXX Label can't be _ast? +% XXX Where should this section/chapter go? +\chapter{Abstract Syntax Trees\label{ast}} + +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} + +\versionadded{2.5} + +The \code{_ast} module helps Python applications to process +trees of the Python abstract syntax grammar. The Python compiler +currently provides read-only access to such trees, meaning that +applications can only create a tree for a given piece of Python +source code; generating byte code from a (potentially modified) +tree is not supported. The abstract syntax itself might change with +each Python release; this module helps to find out programmatically +what the current grammar looks like. + +An abstract syntax tree can be generated by passing \code{_ast.PyCF_ONLY_AST} +as a flag to the \function{compile} builtin function. The result will be a tree +of objects whose classes all inherit from \code{_ast.AST}. + +The actual classes are derived from the \code{Parser/Python.asdl} file, +which is reproduced below. There is one class defined for each left-hand +side symbol in the abstract grammar (for example, \code{_ast.stmt} or \code{_ast.expr}). +In addition, there is one class defined for each constructor on the +right-hand side; these classes inherit from the classes for the left-hand +side trees. For example, \code{_ast.BinOp} inherits from \code{_ast.expr}. +For production rules with alternatives (aka "sums"), the left-hand side +class is abstract: only instances of specific constructor nodes are ever +created. + +Each concrete class has an attribute \code{_fields} which gives the +names of all child nodes. + +Each instance of a concrete class has one attribute for each child node, +of the type as defined in the grammar. For example, \code{_ast.BinOp} +instances have an attribute \code{left} of type \code{_ast.expr}. +Instances of \code{_ast.expr} and \code{_ast.stmt} subclasses also +have lineno and col_offset attributes. The lineno is the line number +of source text (1 indexed so the first line is line 1) and the +col_offset is the utf8 byte offset of the first token that generated +the node. The utf8 offset is recorded because the parser uses utf8 +internally. + +If these attributes are marked as optional in the grammar (using a +question mark), the value might be \code{None}. If the attributes +can have zero-or-more values (marked with an asterisk), the +values are represented as Python lists. + +\section{Abstract Grammar} + +The module defines a string constant \code{__version__} which +is the decimal subversion revision number of the file shown below. + +The abstract grammar is currently defined as follows: + +\verbatiminput{../../Parser/Python.asdl} diff --git a/sys/src/cmd/python/Doc/lib/libasynchat.tex b/sys/src/cmd/python/Doc/lib/libasynchat.tex new file mode 100644 index 000000000..223bfed74 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libasynchat.tex @@ -0,0 +1,254 @@ +\section{\module{asynchat} --- + Asynchronous socket command/response handler} + +\declaremodule{standard}{asynchat} +\modulesynopsis{Support for asynchronous command/response protocols.} +\moduleauthor{Sam Rushing}{rushing@nightmare.com} +\sectionauthor{Steve Holden}{sholden@holdenweb.com} + +This module builds on the \refmodule{asyncore} infrastructure, +simplifying asynchronous clients and servers and making it easier to +handle protocols whose elements are terminated by arbitrary strings, or +are of variable length. \refmodule{asynchat} defines the abstract class +\class{async_chat} that you subclass, providing implementations of the +\method{collect_incoming_data()} and \method{found_terminator()} +methods. It uses the same asynchronous loop as \refmodule{asyncore}, and +the two types of channel, \class{asyncore.dispatcher} and +\class{asynchat.async_chat}, can freely be mixed in the channel map. +Typically an \class{asyncore.dispatcher} server channel generates new +\class{asynchat.async_chat} channel objects as it receives incoming +connection requests. + +\begin{classdesc}{async_chat}{} + This class is an abstract subclass of \class{asyncore.dispatcher}. To make + practical use of the code you must subclass \class{async_chat}, providing + meaningful \method{collect_incoming_data()} and \method{found_terminator()} + methods. The \class{asyncore.dispatcher} methods can be + used, although not all make sense in a message/response context. + + Like \class{asyncore.dispatcher}, \class{async_chat} defines a set of events + that are generated by an analysis of socket conditions after a + \cfunction{select()} call. Once the polling loop has been started the + \class{async_chat} object's methods are called by the event-processing + framework with no action on the part of the programmer. + + Unlike \class{asyncore.dispatcher}, \class{async_chat} allows you to define + a first-in-first-out queue (fifo) of \emph{producers}. A producer need have + only one method, \method{more()}, which should return data to be transmitted + on the channel. The producer indicates exhaustion (\emph{i.e.} that it contains + no more data) by having its \method{more()} method return the empty string. At + this point the \class{async_chat} object removes the producer from the fifo + and starts using the next producer, if any. When the producer fifo is empty + the \method{handle_write()} method does nothing. You use the channel object's + \method{set_terminator()} method to describe how to recognize the end + of, or an important breakpoint in, an incoming transmission from the + remote endpoint. + + To build a functioning \class{async_chat} subclass your + input methods \method{collect_incoming_data()} and + \method{found_terminator()} must handle the data that the channel receives + asynchronously. The methods are described below. +\end{classdesc} + +\begin{methoddesc}{close_when_done}{} + Pushes a \code{None} on to the producer fifo. When this producer is + popped off the fifo it causes the channel to be closed. +\end{methoddesc} + +\begin{methoddesc}{collect_incoming_data}{data} + Called with \var{data} holding an arbitrary amount of received data. + The default method, which must be overridden, raises a \exception{NotImplementedError} exception. +\end{methoddesc} + +\begin{methoddesc}{discard_buffers}{} + In emergencies this method will discard any data held in the input and/or + output buffers and the producer fifo. +\end{methoddesc} + +\begin{methoddesc}{found_terminator}{} + Called when the incoming data stream matches the termination condition + set by \method{set_terminator}. The default method, which must be overridden, + raises a \exception{NotImplementedError} exception. The buffered input data should + be available via an instance attribute. +\end{methoddesc} + +\begin{methoddesc}{get_terminator}{} + Returns the current terminator for the channel. +\end{methoddesc} + +\begin{methoddesc}{handle_close}{} + Called when the channel is closed. The default method silently closes + the channel's socket. +\end{methoddesc} + +\begin{methoddesc}{handle_read}{} + Called when a read event fires on the channel's socket in the + asynchronous loop. The default method checks for the termination + condition established by \method{set_terminator()}, which can be either + the appearance of a particular string in the input stream or the receipt + of a particular number of characters. When the terminator is found, + \method{handle_read} calls the \method{found_terminator()} method after + calling \method{collect_incoming_data()} with any data preceding the + terminating condition. +\end{methoddesc} + +\begin{methoddesc}{handle_write}{} + Called when the application may write data to the channel. + The default method calls the \method{initiate_send()} method, which in turn + will call \method{refill_buffer()} to collect data from the producer + fifo associated with the channel. +\end{methoddesc} + +\begin{methoddesc}{push}{data} + Creates a \class{simple_producer} object (\emph{see below}) containing the data and + pushes it on to the channel's \code{producer_fifo} to ensure its + transmission. This is all you need to do to have the channel write + the data out to the network, although it is possible to use your + own producers in more complex schemes to implement encryption and + chunking, for example. +\end{methoddesc} + +\begin{methoddesc}{push_with_producer}{producer} + Takes a producer object and adds it to the producer fifo associated with + the channel. When all currently-pushed producers have been exhausted + the channel will consume this producer's data by calling its + \method{more()} method and send the data to the remote endpoint. +\end{methoddesc} + +\begin{methoddesc}{readable}{} + Should return \code{True} for the channel to be included in the set of + channels tested by the \cfunction{select()} loop for readability. +\end{methoddesc} + +\begin{methoddesc}{refill_buffer}{} + Refills the output buffer by calling the \method{more()} method of the + producer at the head of the fifo. If it is exhausted then the + producer is popped off the fifo and the next producer is activated. + If the current producer is, or becomes, \code{None} then the channel + is closed. +\end{methoddesc} + +\begin{methoddesc}{set_terminator}{term} + Sets the terminating condition to be recognised on the channel. \code{term} + may be any of three types of value, corresponding to three different ways + to handle incoming protocol data. + + \begin{tableii}{l|l}{}{term}{Description} + \lineii{\emph{string}}{Will call \method{found_terminator()} when the + string is found in the input stream} + \lineii{\emph{integer}}{Will call \method{found_terminator()} when the + indicated number of characters have been received} + \lineii{\code{None}}{The channel continues to collect data forever} + \end{tableii} + + Note that any data following the terminator will be available for reading by + the channel after \method{found_terminator()} is called. +\end{methoddesc} + +\begin{methoddesc}{writable}{} + Should return \code{True} as long as items remain on the producer fifo, + or the channel is connected and the channel's output buffer is non-empty. +\end{methoddesc} + +\subsection{asynchat - Auxiliary Classes and Functions} + +\begin{classdesc}{simple_producer}{data\optional{, buffer_size=512}} + A \class{simple_producer} takes a chunk of data and an optional buffer size. + Repeated calls to its \method{more()} method yield successive chunks of the + data no larger than \var{buffer_size}. +\end{classdesc} + +\begin{methoddesc}{more}{} + Produces the next chunk of information from the producer, or returns the empty string. +\end{methoddesc} + +\begin{classdesc}{fifo}{\optional{list=None}} + Each channel maintains a \class{fifo} holding data which has been pushed by the + application but not yet popped for writing to the channel. + A \class{fifo} is a list used to hold data and/or producers until they are required. + If the \var{list} argument is provided then it should contain producers or + data items to be written to the channel. +\end{classdesc} + +\begin{methoddesc}{is_empty}{} + Returns \code{True} iff the fifo is empty. +\end{methoddesc} + +\begin{methoddesc}{first}{} + Returns the least-recently \method{push()}ed item from the fifo. +\end{methoddesc} + +\begin{methoddesc}{push}{data} + Adds the given data (which may be a string or a producer object) to the + producer fifo. +\end{methoddesc} + +\begin{methoddesc}{pop}{} + If the fifo is not empty, returns \code{True, first()}, deleting the popped + item. Returns \code{False, None} for an empty fifo. +\end{methoddesc} + +The \module{asynchat} module also defines one utility function, which may be +of use in network and textual analysis operations. + +\begin{funcdesc}{find_prefix_at_end}{haystack, needle} + Returns \code{True} if string \var{haystack} ends with any non-empty + prefix of string \var{needle}. +\end{funcdesc} + +\subsection{asynchat Example \label{asynchat-example}} + +The following partial example shows how HTTP requests can be read with +\class{async_chat}. A web server might create an \class{http_request_handler} object for +each incoming client connection. Notice that initially the +channel terminator is set to match the blank line at the end of the HTTP +headers, and a flag indicates that the headers are being read. + +Once the headers have been read, if the request is of type POST +(indicating that further data are present in the input stream) then the +\code{Content-Length:} header is used to set a numeric terminator to +read the right amount of data from the channel. + +The \method{handle_request()} method is called once all relevant input +has been marshalled, after setting the channel terminator to \code{None} +to ensure that any extraneous data sent by the web client are ignored. + +\begin{verbatim} +class http_request_handler(asynchat.async_chat): + + def __init__(self, conn, addr, sessions, log): + asynchat.async_chat.__init__(self, conn=conn) + self.addr = addr + self.sessions = sessions + self.ibuffer = [] + self.obuffer = "" + self.set_terminator("\r\n\r\n") + self.reading_headers = True + self.handling = False + self.cgi_data = None + self.log = log + + def collect_incoming_data(self, data): + """Buffer the data""" + self.ibuffer.append(data) + + def found_terminator(self): + if self.reading_headers: + self.reading_headers = False + self.parse_headers("".join(self.ibuffer)) + self.ibuffer = [] + if self.op.upper() == "POST": + clen = self.headers.getheader("content-length") + self.set_terminator(int(clen)) + else: + self.handling = True + self.set_terminator(None) + self.handle_request() + elif not self.handling: + self.set_terminator(None) # browsers sometimes over-send + self.cgi_data = parse(self.headers, "".join(self.ibuffer)) + self.handling = True + self.ibuffer = [] + self.handle_request() +\end{verbatim} + diff --git a/sys/src/cmd/python/Doc/lib/libasyncore.tex b/sys/src/cmd/python/Doc/lib/libasyncore.tex new file mode 100644 index 000000000..206783911 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libasyncore.tex @@ -0,0 +1,260 @@ +\section{\module{asyncore} --- + Asynchronous socket handler} + +\declaremodule{builtin}{asyncore} +\modulesynopsis{A base class for developing asynchronous socket + handling services.} +\moduleauthor{Sam Rushing}{rushing@nightmare.com} +\sectionauthor{Christopher Petrilli}{petrilli@amber.org} +\sectionauthor{Steve Holden}{sholden@holdenweb.com} +% Heavily adapted from original documentation by Sam Rushing. + +This module provides the basic infrastructure for writing asynchronous +socket service clients and servers. + +There are only two ways to have a program on a single processor do +``more than one thing at a time.'' Multi-threaded programming is the +simplest and most popular way to do it, but there is another very +different technique, that lets you have nearly all the advantages of +multi-threading, without actually using multiple threads. It's really +only practical if your program is largely I/O bound. If your program +is processor bound, then pre-emptive scheduled threads are probably what +you really need. Network servers are rarely processor bound, however. + +If your operating system supports the \cfunction{select()} system call +in its I/O library (and nearly all do), then you can use it to juggle +multiple communication channels at once; doing other work while your +I/O is taking place in the ``background.'' Although this strategy can +seem strange and complex, especially at first, it is in many ways +easier to understand and control than multi-threaded programming. +The \module{asyncore} module solves many of the difficult problems for +you, making the task of building sophisticated high-performance +network servers and clients a snap. For ``conversational'' applications +and protocols the companion \refmodule{asynchat} module is invaluable. + +The basic idea behind both modules is to create one or more network +\emph{channels}, instances of class \class{asyncore.dispatcher} and +\class{asynchat.async_chat}. Creating the channels adds them to a global +map, used by the \function{loop()} function if you do not provide it +with your own \var{map}. + +Once the initial channel(s) is(are) created, calling the \function{loop()} +function activates channel service, which continues until the last +channel (including any that have been added to the map during asynchronous +service) is closed. + +\begin{funcdesc}{loop}{\optional{timeout\optional{, use_poll\optional{, + map\optional{,count}}}}} + Enter a polling loop that terminates after count passes or all open + channels have been closed. All arguments are optional. The \var(count) + parameter defaults to None, resulting in the loop terminating only + when all channels have been closed. The \var{timeout} argument sets the + timeout parameter for the appropriate \function{select()} or + \function{poll()} call, measured in seconds; the default is 30 seconds. + The \var{use_poll} parameter, if true, indicates that \function{poll()} + should be used in preference to \function{select()} (the default is + \code{False}). + + The \var{map} parameter is a dictionary whose items are + the channels to watch. As channels are closed they are deleted from their + map. If \var{map} is omitted, a global map is used. + Channels (instances of \class{asyncore.dispatcher}, \class{asynchat.async_chat} + and subclasses thereof) can freely be mixed in the map. +\end{funcdesc} + +\begin{classdesc}{dispatcher}{} + The \class{dispatcher} class is a thin wrapper around a low-level socket object. + To make it more useful, it has a few methods for event-handling which are called + from the asynchronous loop. + Otherwise, it can be treated as a normal non-blocking socket object. + + Two class attributes can be modified, to improve performance, + or possibly even to conserve memory. + + \begin{datadesc}{ac_in_buffer_size} + The asynchronous input buffer size (default \code{4096}). + \end{datadesc} + + \begin{datadesc}{ac_out_buffer_size} + The asynchronous output buffer size (default \code{4096}). + \end{datadesc} + + The firing of low-level events at certain times or in certain connection + states tells the asynchronous loop that certain higher-level events have + taken place. For example, if we have asked for a socket to connect to + another host, we know that the connection has been made when the socket + becomes writable for the first time (at this point you know that you may + write to it with the expectation of success). The implied higher-level + events are: + + \begin{tableii}{l|l}{code}{Event}{Description} + \lineii{handle_connect()}{Implied by the first write event} + \lineii{handle_close()}{Implied by a read event with no data available} + \lineii{handle_accept()}{Implied by a read event on a listening socket} + \end{tableii} + + During asynchronous processing, each mapped channel's \method{readable()} + and \method{writable()} methods are used to determine whether the channel's + socket should be added to the list of channels \cfunction{select()}ed or + \cfunction{poll()}ed for read and write events. + +\end{classdesc} + +Thus, the set of channel events is larger than the basic socket events. +The full set of methods that can be overridden in your subclass follows: + +\begin{methoddesc}{handle_read}{} + Called when the asynchronous loop detects that a \method{read()} + call on the channel's socket will succeed. +\end{methoddesc} + +\begin{methoddesc}{handle_write}{} + Called when the asynchronous loop detects that a writable socket + can be written. + Often this method will implement the necessary buffering for + performance. For example: + +\begin{verbatim} +def handle_write(self): + sent = self.send(self.buffer) + self.buffer = self.buffer[sent:] +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{handle_expt}{} + Called when there is out of band (OOB) data for a socket + connection. This will almost never happen, as OOB is + tenuously supported and rarely used. +\end{methoddesc} + +\begin{methoddesc}{handle_connect}{} + Called when the active opener's socket actually makes a connection. + Might send a ``welcome'' banner, or initiate a protocol + negotiation with the remote endpoint, for example. +\end{methoddesc} + +\begin{methoddesc}{handle_close}{} + Called when the socket is closed. +\end{methoddesc} + +\begin{methoddesc}{handle_error}{} + Called when an exception is raised and not otherwise handled. The default + version prints a condensed traceback. +\end{methoddesc} + +\begin{methoddesc}{handle_accept}{} + Called on listening channels (passive openers) when a + connection can be established with a new remote endpoint that + has issued a \method{connect()} call for the local endpoint. +\end{methoddesc} + +\begin{methoddesc}{readable}{} + Called each time around the asynchronous loop to determine whether a + channel's socket should be added to the list on which read events can + occur. The default method simply returns \code{True}, + indicating that by default, all channels will be interested in + read events. +\end{methoddesc} + +\begin{methoddesc}{writable}{} + Called each time around the asynchronous loop to determine whether a + channel's socket should be added to the list on which write events can + occur. The default method simply returns \code{True}, + indicating that by default, all channels will be interested in + write events. +\end{methoddesc} + +In addition, each channel delegates or extends many of the socket methods. +Most of these are nearly identical to their socket partners. + +\begin{methoddesc}{create_socket}{family, type} + This is identical to the creation of a normal socket, and + will use the same options for creation. Refer to the + \refmodule{socket} documentation for information on creating + sockets. +\end{methoddesc} + +\begin{methoddesc}{connect}{address} + As with the normal socket object, \var{address} is a + tuple with the first element the host to connect to, and the + second the port number. +\end{methoddesc} + +\begin{methoddesc}{send}{data} + Send \var{data} to the remote end-point of the socket. +\end{methoddesc} + +\begin{methoddesc}{recv}{buffer_size} + Read at most \var{buffer_size} bytes from the socket's remote end-point. + An empty string implies that the channel has been closed from the other + end. +\end{methoddesc} + +\begin{methoddesc}{listen}{backlog} + Listen for connections made to the socket. The \var{backlog} + argument specifies the maximum number of queued connections + and should be at least 1; the maximum value is + system-dependent (usually 5). +\end{methoddesc} + +\begin{methoddesc}{bind}{address} + Bind the socket to \var{address}. The socket must not already be + bound. (The format of \var{address} depends on the address family + --- see above.) To mark the socket as re-usable (setting the + \constant{SO_REUSEADDR} option), call the \class{dispatcher} + object's \method{set_reuse_addr()} method. +\end{methoddesc} + +\begin{methoddesc}{accept}{} + Accept a connection. The socket must be bound to an address + and listening for connections. The return value is a pair + \code{(\var{conn}, \var{address})} where \var{conn} is a + \emph{new} socket object usable to send and receive data on + the connection, and \var{address} is the address bound to the + socket on the other end of the connection. +\end{methoddesc} + +\begin{methoddesc}{close}{} + Close the socket. All future operations on the socket object + will fail. The remote end-point will receive no more data (after + queued data is flushed). Sockets are automatically closed + when they are garbage-collected. +\end{methoddesc} + + +\subsection{asyncore Example basic HTTP client \label{asyncore-example}} + +Here is a very basic HTTP client that uses the \class{dispatcher} +class to implement its socket handling: + +\begin{verbatim} +import asyncore, socket + +class http_client(asyncore.dispatcher): + + def __init__(self, host, path): + asyncore.dispatcher.__init__(self) + self.create_socket(socket.AF_INET, socket.SOCK_STREAM) + self.connect( (host, 80) ) + self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path + + def handle_connect(self): + pass + + def handle_close(self): + self.close() + + def handle_read(self): + print self.recv(8192) + + def writable(self): + return (len(self.buffer) > 0) + + def handle_write(self): + sent = self.send(self.buffer) + self.buffer = self.buffer[sent:] + +c = http_client('www.python.org', '/') + +asyncore.loop() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libatexit.tex b/sys/src/cmd/python/Doc/lib/libatexit.tex new file mode 100644 index 000000000..33dc7ddf8 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libatexit.tex @@ -0,0 +1,94 @@ +\section{\module{atexit} --- + Exit handlers} + +\declaremodule{standard}{atexit} +\moduleauthor{Skip Montanaro}{skip@mojam.com} +\sectionauthor{Skip Montanaro}{skip@mojam.com} +\modulesynopsis{Register and execute cleanup functions.} + +\versionadded{2.0} + +The \module{atexit} module defines a single function to register +cleanup functions. Functions thus registered are automatically +executed upon normal interpreter termination. + +Note: the functions registered via this module are not called when the program is killed by a +signal, when a Python fatal internal error is detected, or when +\function{os._exit()} is called. + +This is an alternate interface to the functionality provided by the +\code{sys.exitfunc} variable. +\withsubitem{(in sys)}{\ttindex{exitfunc}} + +Note: This module is unlikely to work correctly when used with other code +that sets \code{sys.exitfunc}. In particular, other core Python modules are +free to use \module{atexit} without the programmer's knowledge. Authors who +use \code{sys.exitfunc} should convert their code to use +\module{atexit} instead. The simplest way to convert code that sets +\code{sys.exitfunc} is to import \module{atexit} and register the function +that had been bound to \code{sys.exitfunc}. + +\begin{funcdesc}{register}{func\optional{, *args\optional{, **kargs}}} +Register \var{func} as a function to be executed at termination. Any +optional arguments that are to be passed to \var{func} must be passed +as arguments to \function{register()}. + +At normal program termination (for instance, if +\function{sys.exit()} is called or the main module's execution +completes), all functions registered are called in last in, first out +order. The assumption is that lower level modules will normally be +imported before higher level modules and thus must be cleaned up +later. + +If an exception is raised during execution of the exit handlers, a +traceback is printed (unless \exception{SystemExit} is raised) and the +exception information is saved. After all exit handlers have had a +chance to run the last exception to be raised is re-raised. +\end{funcdesc} + + +\begin{seealso} + \seemodule{readline}{Useful example of \module{atexit} to read and + write \refmodule{readline} history files.} +\end{seealso} + + +\subsection{\module{atexit} Example \label{atexit-example}} + +The following simple example demonstrates how a module can initialize +a counter from a file when it is imported and save the counter's +updated value automatically when the program terminates without +relying on the application making an explicit call into this module at +termination. + +\begin{verbatim} +try: + _count = int(open("/tmp/counter").read()) +except IOError: + _count = 0 + +def incrcounter(n): + global _count + _count = _count + n + +def savecounter(): + open("/tmp/counter", "w").write("%d" % _count) + +import atexit +atexit.register(savecounter) +\end{verbatim} + +Positional and keyword arguments may also be passed to +\function{register()} to be passed along to the registered function +when it is called: + +\begin{verbatim} +def goodbye(name, adjective): + print 'Goodbye, %s, it was %s to meet you.' % (name, adjective) + +import atexit +atexit.register(goodbye, 'Donny', 'nice') + +# or: +atexit.register(goodbye, adjective='nice', name='Donny') +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libaudioop.tex b/sys/src/cmd/python/Doc/lib/libaudioop.tex new file mode 100644 index 000000000..52c6f3d79 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libaudioop.tex @@ -0,0 +1,259 @@ +\section{\module{audioop} --- + Manipulate raw audio data} + +\declaremodule{builtin}{audioop} +\modulesynopsis{Manipulate raw audio data.} + + +The \module{audioop} module contains some useful operations on sound +fragments. It operates on sound fragments consisting of signed +integer samples 8, 16 or 32 bits wide, stored in Python strings. This +is the same format as used by the \refmodule{al} and \refmodule{sunaudiodev} +modules. All scalar items are integers, unless specified otherwise. + +% This para is mostly here to provide an excuse for the index entries... +This module provides support for a-LAW, u-LAW and Intel/DVI ADPCM encodings. +\index{Intel/DVI ADPCM} +\index{ADPCM, Intel/DVI} +\index{a-LAW} +\index{u-LAW} + +A few of the more complicated operations only take 16-bit samples, +otherwise the sample size (in bytes) is always a parameter of the +operation. + +The module defines the following variables and functions: + +\begin{excdesc}{error} +This exception is raised on all errors, such as unknown number of bytes +per sample, etc. +\end{excdesc} + +\begin{funcdesc}{add}{fragment1, fragment2, width} +Return a fragment which is the addition of the two samples passed as +parameters. \var{width} is the sample width in bytes, either +\code{1}, \code{2} or \code{4}. Both fragments should have the same +length. +\end{funcdesc} + +\begin{funcdesc}{adpcm2lin}{adpcmfragment, width, state} +Decode an Intel/DVI ADPCM coded fragment to a linear fragment. See +the description of \function{lin2adpcm()} for details on ADPCM coding. +Return a tuple \code{(\var{sample}, \var{newstate})} where the sample +has the width specified in \var{width}. +\end{funcdesc} + +\begin{funcdesc}{alaw2lin}{fragment, width} +Convert sound fragments in a-LAW encoding to linearly encoded sound +fragments. a-LAW encoding always uses 8 bits samples, so \var{width} +refers only to the sample width of the output fragment here. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{avg}{fragment, width} +Return the average over all samples in the fragment. +\end{funcdesc} + +\begin{funcdesc}{avgpp}{fragment, width} +Return the average peak-peak value over all samples in the fragment. +No filtering is done, so the usefulness of this routine is +questionable. +\end{funcdesc} + +\begin{funcdesc}{bias}{fragment, width, bias} +Return a fragment that is the original fragment with a bias added to +each sample. +\end{funcdesc} + +\begin{funcdesc}{cross}{fragment, width} +Return the number of zero crossings in the fragment passed as an +argument. +\end{funcdesc} + +\begin{funcdesc}{findfactor}{fragment, reference} +Return a factor \var{F} such that +\code{rms(add(\var{fragment}, mul(\var{reference}, -\var{F})))} is +minimal, i.e., return the factor with which you should multiply +\var{reference} to make it match as well as possible to +\var{fragment}. The fragments should both contain 2-byte samples. + +The time taken by this routine is proportional to +\code{len(\var{fragment})}. +\end{funcdesc} + +\begin{funcdesc}{findfit}{fragment, reference} +Try to match \var{reference} as well as possible to a portion of +\var{fragment} (which should be the longer fragment). This is +(conceptually) done by taking slices out of \var{fragment}, using +\function{findfactor()} to compute the best match, and minimizing the +result. The fragments should both contain 2-byte samples. Return a +tuple \code{(\var{offset}, \var{factor})} where \var{offset} is the +(integer) offset into \var{fragment} where the optimal match started +and \var{factor} is the (floating-point) factor as per +\function{findfactor()}. +\end{funcdesc} + +\begin{funcdesc}{findmax}{fragment, length} +Search \var{fragment} for a slice of length \var{length} samples (not +bytes!)\ with maximum energy, i.e., return \var{i} for which +\code{rms(fragment[i*2:(i+length)*2])} is maximal. The fragments +should both contain 2-byte samples. + +The routine takes time proportional to \code{len(\var{fragment})}. +\end{funcdesc} + +\begin{funcdesc}{getsample}{fragment, width, index} +Return the value of sample \var{index} from the fragment. +\end{funcdesc} + +\begin{funcdesc}{lin2adpcm}{fragment, width, state} +Convert samples to 4 bit Intel/DVI ADPCM encoding. ADPCM coding is an +adaptive coding scheme, whereby each 4 bit number is the difference +between one sample and the next, divided by a (varying) step. The +Intel/DVI ADPCM algorithm has been selected for use by the IMA, so it +may well become a standard. + +\var{state} is a tuple containing the state of the coder. The coder +returns a tuple \code{(\var{adpcmfrag}, \var{newstate})}, and the +\var{newstate} should be passed to the next call of +\function{lin2adpcm()}. In the initial call, \code{None} can be +passed as the state. \var{adpcmfrag} is the ADPCM coded fragment +packed 2 4-bit values per byte. +\end{funcdesc} + +\begin{funcdesc}{lin2alaw}{fragment, width} +Convert samples in the audio fragment to a-LAW encoding and return +this as a Python string. a-LAW is an audio encoding format whereby +you get a dynamic range of about 13 bits using only 8 bit samples. It +is used by the Sun audio hardware, among others. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{lin2lin}{fragment, width, newwidth} +Convert samples between 1-, 2- and 4-byte formats. +\end{funcdesc} + +\begin{funcdesc}{lin2ulaw}{fragment, width} +Convert samples in the audio fragment to u-LAW encoding and return +this as a Python string. u-LAW is an audio encoding format whereby +you get a dynamic range of about 14 bits using only 8 bit samples. It +is used by the Sun audio hardware, among others. +\end{funcdesc} + +\begin{funcdesc}{minmax}{fragment, width} +Return a tuple consisting of the minimum and maximum values of all +samples in the sound fragment. +\end{funcdesc} + +\begin{funcdesc}{max}{fragment, width} +Return the maximum of the \emph{absolute value} of all samples in a +fragment. +\end{funcdesc} + +\begin{funcdesc}{maxpp}{fragment, width} +Return the maximum peak-peak value in the sound fragment. +\end{funcdesc} + +\begin{funcdesc}{mul}{fragment, width, factor} +Return a fragment that has all samples in the original fragment +multiplied by the floating-point value \var{factor}. Overflow is +silently ignored. +\end{funcdesc} + +\begin{funcdesc}{ratecv}{fragment, width, nchannels, inrate, outrate, + state\optional{, weightA\optional{, weightB}}} +Convert the frame rate of the input fragment. + +\var{state} is a tuple containing the state of the converter. The +converter returns a tuple \code{(\var{newfragment}, \var{newstate})}, +and \var{newstate} should be passed to the next call of +\function{ratecv()}. The initial call should pass \code{None} +as the state. + +The \var{weightA} and \var{weightB} arguments are parameters for a +simple digital filter and default to \code{1} and \code{0} respectively. +\end{funcdesc} + +\begin{funcdesc}{reverse}{fragment, width} +Reverse the samples in a fragment and returns the modified fragment. +\end{funcdesc} + +\begin{funcdesc}{rms}{fragment, width} +Return the root-mean-square of the fragment, i.e. +\begin{displaymath} +\catcode`_=8 +\sqrt{\frac{\sum{{S_{i}}^{2}}}{n}} +\end{displaymath} +This is a measure of the power in an audio signal. +\end{funcdesc} + +\begin{funcdesc}{tomono}{fragment, width, lfactor, rfactor} +Convert a stereo fragment to a mono fragment. The left channel is +multiplied by \var{lfactor} and the right channel by \var{rfactor} +before adding the two channels to give a mono signal. +\end{funcdesc} + +\begin{funcdesc}{tostereo}{fragment, width, lfactor, rfactor} +Generate a stereo fragment from a mono fragment. Each pair of samples +in the stereo fragment are computed from the mono sample, whereby left +channel samples are multiplied by \var{lfactor} and right channel +samples by \var{rfactor}. +\end{funcdesc} + +\begin{funcdesc}{ulaw2lin}{fragment, width} +Convert sound fragments in u-LAW encoding to linearly encoded sound +fragments. u-LAW encoding always uses 8 bits samples, so \var{width} +refers only to the sample width of the output fragment here. +\end{funcdesc} + +Note that operations such as \function{mul()} or \function{max()} make +no distinction between mono and stereo fragments, i.e.\ all samples +are treated equal. If this is a problem the stereo fragment should be +split into two mono fragments first and recombined later. Here is an +example of how to do that: + +\begin{verbatim} +def mul_stereo(sample, width, lfactor, rfactor): + lsample = audioop.tomono(sample, width, 1, 0) + rsample = audioop.tomono(sample, width, 0, 1) + lsample = audioop.mul(sample, width, lfactor) + rsample = audioop.mul(sample, width, rfactor) + lsample = audioop.tostereo(lsample, width, 1, 0) + rsample = audioop.tostereo(rsample, width, 0, 1) + return audioop.add(lsample, rsample, width) +\end{verbatim} + +If you use the ADPCM coder to build network packets and you want your +protocol to be stateless (i.e.\ to be able to tolerate packet loss) +you should not only transmit the data but also the state. Note that +you should send the \var{initial} state (the one you passed to +\function{lin2adpcm()}) along to the decoder, not the final state (as +returned by the coder). If you want to use \function{struct.struct()} +to store the state in binary you can code the first element (the +predicted value) in 16 bits and the second (the delta index) in 8. + +The ADPCM coders have never been tried against other ADPCM coders, +only against themselves. It could well be that I misinterpreted the +standards in which case they will not be interoperable with the +respective standards. + +The \function{find*()} routines might look a bit funny at first sight. +They are primarily meant to do echo cancellation. A reasonably +fast way to do this is to pick the most energetic piece of the output +sample, locate that in the input sample and subtract the whole output +sample from the input sample: + +\begin{verbatim} +def echocancel(outputdata, inputdata): + pos = audioop.findmax(outputdata, 800) # one tenth second + out_test = outputdata[pos*2:] + in_test = inputdata[pos*2:] + ipos, factor = audioop.findfit(in_test, out_test) + # Optional (for better cancellation): + # factor = audioop.findfactor(in_test[ipos*2:ipos*2+len(out_test)], + # out_test) + prefill = '\0'*(pos+ipos)*2 + postfill = '\0'*(len(inputdata)-len(prefill)-len(outputdata)) + outputdata = prefill + audioop.mul(outputdata,2,-factor) + postfill + return audioop.add(inputdata, outputdata, 2) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libbase64.tex b/sys/src/cmd/python/Doc/lib/libbase64.tex new file mode 100644 index 000000000..d7eccbdb1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbase64.tex @@ -0,0 +1,169 @@ +\section{\module{base64} --- + RFC 3548: Base16, Base32, Base64 Data Encodings} + +\declaremodule{standard}{base64} +\modulesynopsis{RFC 3548: Base16, Base32, Base64 Data Encodings} + + +\indexii{base64}{encoding} +\index{MIME!base64 encoding} + +This module provides data encoding and decoding as specified in +\rfc{3548}. This standard defines the Base16, Base32, and Base64 +algorithms for encoding and decoding arbitrary binary strings into +text strings that can be safely sent by email, used as parts of URLs, +or included as part of an HTTP POST request. The encoding algorithm is +not the same as the \program{uuencode} program. + +There are two interfaces provided by this module. The modern +interface supports encoding and decoding string objects using all +three alphabets. The legacy interface provides for encoding and +decoding to and from file-like objects as well as strings, but only +using the Base64 standard alphabet. + +The modern interface, which was introduced in Python 2.4, provides: + +\begin{funcdesc}{b64encode}{s\optional{, altchars}} +Encode a string use Base64. + +\var{s} is the string to encode. Optional \var{altchars} must be a +string of at least length 2 (additional characters are ignored) which +specifies an alternative alphabet for the \code{+} and \code{/} +characters. This allows an application to e.g. generate URL or +filesystem safe Base64 strings. The default is \code{None}, for which +the standard Base64 alphabet is used. + +The encoded string is returned. +\end{funcdesc} + +\begin{funcdesc}{b64decode}{s\optional{, altchars}} +Decode a Base64 encoded string. + +\var{s} is the string to decode. Optional \var{altchars} must be a +string of at least length 2 (additional characters are ignored) which +specifies the alternative alphabet used instead of the \code{+} and +\code{/} characters. + +The decoded string is returned. A \exception{TypeError} is raised if +\var{s} were incorrectly padded or if there are non-alphabet +characters present in the string. +\end{funcdesc} + +\begin{funcdesc}{standard_b64encode}{s} +Encode string \var{s} using the standard Base64 alphabet. +\end{funcdesc} + +\begin{funcdesc}{standard_b64decode}{s} +Decode string \var{s} using the standard Base64 alphabet. +\end{funcdesc} + +\begin{funcdesc}{urlsafe_b64encode}{s} +Encode string \var{s} using a URL-safe alphabet, which substitutes +\code{-} instead of \code{+} and \code{_} instead of \code{/} in the +standard Base64 alphabet. +\end{funcdesc} + +\begin{funcdesc}{urlsafe_b64decode}{s} +Decode string \var{s} using a URL-safe alphabet, which substitutes +\code{-} instead of \code{+} and \code{_} instead of \code{/} in the +standard Base64 alphabet. +\end{funcdesc} + +\begin{funcdesc}{b32encode}{s} +Encode a string using Base32. \var{s} is the string to encode. The +encoded string is returned. +\end{funcdesc} + +\begin{funcdesc}{b32decode}{s\optional{, casefold\optional{, map01}}} +Decode a Base32 encoded string. + +\var{s} is the string to decode. Optional \var{casefold} is a flag +specifying whether a lowercase alphabet is acceptable as input. For +security purposes, the default is \code{False}. + +\rfc{3548} allows for optional mapping of the digit 0 (zero) to the +letter O (oh), and for optional mapping of the digit 1 (one) to either +the letter I (eye) or letter L (el). The optional argument +\var{map01} when not \code{None}, specifies which letter the digit 1 should +be mapped to (when map01 is not \var{None}, the digit 0 is always +mapped to the letter O). For security purposes the default is +\code{None}, so that 0 and 1 are not allowed in the input. + +The decoded string is returned. A \exception{TypeError} is raised if +\var{s} were incorrectly padded or if there are non-alphabet characters +present in the string. +\end{funcdesc} + +\begin{funcdesc}{b16encode}{s} +Encode a string using Base16. + +\var{s} is the string to encode. The encoded string is returned. +\end{funcdesc} + +\begin{funcdesc}{b16decode}{s\optional{, casefold}} +Decode a Base16 encoded string. + +\var{s} is the string to decode. Optional \var{casefold} is a flag +specifying whether a lowercase alphabet is acceptable as input. For +security purposes, the default is \code{False}. + +The decoded string is returned. A \exception{TypeError} is raised if +\var{s} were incorrectly padded or if there are non-alphabet +characters present in the string. +\end{funcdesc} + +The legacy interface: + +\begin{funcdesc}{decode}{input, output} +Decode the contents of the \var{input} file and write the resulting +binary data to the \var{output} file. +\var{input} and \var{output} must either be file objects or objects that +mimic the file object interface. \var{input} will be read until +\code{\var{input}.read()} returns an empty string. +\end{funcdesc} + +\begin{funcdesc}{decodestring}{s} +Decode the string \var{s}, which must contain one or more lines of +base64 encoded data, and return a string containing the resulting +binary data. +\end{funcdesc} + +\begin{funcdesc}{encode}{input, output} +Encode the contents of the \var{input} file and write the resulting +base64 encoded data to the \var{output} file. +\var{input} and \var{output} must either be file objects or objects that +mimic the file object interface. \var{input} will be read until +\code{\var{input}.read()} returns an empty string. \function{encode()} +returns the encoded data plus a trailing newline character +(\code{'\e n'}). +\end{funcdesc} + +\begin{funcdesc}{encodestring}{s} +Encode the string \var{s}, which can contain arbitrary binary data, +and return a string containing one or more lines of +base64-encoded data. \function{encodestring()} returns a +string containing one or more lines of base64-encoded data +always including an extra trailing newline (\code{'\e n'}). +\end{funcdesc} + +An example usage of the module: + +\begin{verbatim} +>>> import base64 +>>> encoded = base64.b64encode('data to be encoded') +>>> encoded +'ZGF0YSB0byBiZSBlbmNvZGVk' +>>> data = base64.b64decode(encoded) +>>> data +'data to be encoded' +\end{verbatim} + +\begin{seealso} + \seemodule{binascii}{Support module containing \ASCII-to-binary + and binary-to-\ASCII{} conversions.} + \seerfc{1521}{MIME (Multipurpose Internet Mail Extensions) Part One: + Mechanisms for Specifying and Describing the Format of + Internet Message Bodies}{Section 5.2, ``Base64 + Content-Transfer-Encoding,'' provides the definition of the + base64 encoding.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libbasehttp.tex b/sys/src/cmd/python/Doc/lib/libbasehttp.tex new file mode 100644 index 000000000..64c069f07 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbasehttp.tex @@ -0,0 +1,245 @@ +\section{\module{BaseHTTPServer} --- + Basic HTTP server} + +\declaremodule{standard}{BaseHTTPServer} +\modulesynopsis{Basic HTTP server (base class for + \class{SimpleHTTPServer} and \class{CGIHTTPServer}).} + + +\indexii{WWW}{server} +\indexii{HTTP}{protocol} +\index{URL} +\index{httpd} + +This module defines two classes for implementing HTTP servers +(Web servers). Usually, this module isn't used directly, but is used +as a basis for building functioning Web servers. See the +\refmodule{SimpleHTTPServer}\refstmodindex{SimpleHTTPServer} and +\refmodule{CGIHTTPServer}\refstmodindex{CGIHTTPServer} modules. + +The first class, \class{HTTPServer}, is a +\class{SocketServer.TCPServer} subclass. It creates and listens at the +HTTP socket, dispatching the requests to a handler. Code to create and +run the server looks like this: + +\begin{verbatim} +def run(server_class=BaseHTTPServer.HTTPServer, + handler_class=BaseHTTPServer.BaseHTTPRequestHandler): + server_address = ('', 8000) + httpd = server_class(server_address, handler_class) + httpd.serve_forever() +\end{verbatim} + +\begin{classdesc}{HTTPServer}{server_address, RequestHandlerClass} +This class builds on the \class{TCPServer} class by +storing the server address as instance +variables named \member{server_name} and \member{server_port}. The +server is accessible by the handler, typically through the handler's +\member{server} instance variable. +\end{classdesc} + +\begin{classdesc}{BaseHTTPRequestHandler}{request, client_address, server} +This class is used +to handle the HTTP requests that arrive at the server. By itself, +it cannot respond to any actual HTTP requests; it must be subclassed +to handle each request method (e.g. GET or POST). +\class{BaseHTTPRequestHandler} provides a number of class and instance +variables, and methods for use by subclasses. + +The handler will parse the request and the headers, then call a +method specific to the request type. The method name is constructed +from the request. For example, for the request method \samp{SPAM}, the +\method{do_SPAM()} method will be called with no arguments. All of +the relevant information is stored in instance variables of the +handler. Subclasses should not need to override or extend the +\method{__init__()} method. +\end{classdesc} + + +\class{BaseHTTPRequestHandler} has the following instance variables: + +\begin{memberdesc}{client_address} +Contains a tuple of the form \code{(\var{host}, \var{port})} referring +to the client's address. +\end{memberdesc} + +\begin{memberdesc}{command} +Contains the command (request type). For example, \code{'GET'}. +\end{memberdesc} + +\begin{memberdesc}{path} +Contains the request path. +\end{memberdesc} + +\begin{memberdesc}{request_version} +Contains the version string from the request. For example, +\code{'HTTP/1.0'}. +\end{memberdesc} + +\begin{memberdesc}{headers} +Holds an instance of the class specified by the \member{MessageClass} +class variable. This instance parses and manages the headers in +the HTTP request. +\end{memberdesc} + +\begin{memberdesc}{rfile} +Contains an input stream, positioned at the start of the optional +input data. +\end{memberdesc} + +\begin{memberdesc}{wfile} +Contains the output stream for writing a response back to the client. +Proper adherence to the HTTP protocol must be used when writing +to this stream. +\end{memberdesc} + + +\class{BaseHTTPRequestHandler} has the following class variables: + +\begin{memberdesc}{server_version} +Specifies the server software version. You may want to override +this. +The format is multiple whitespace-separated strings, +where each string is of the form name[/version]. +For example, \code{'BaseHTTP/0.2'}. +\end{memberdesc} + +\begin{memberdesc}{sys_version} +Contains the Python system version, in a form usable by the +\member{version_string} method and the \member{server_version} class +variable. For example, \code{'Python/1.4'}. +\end{memberdesc} + +\begin{memberdesc}{error_message_format} +Specifies a format string for building an error response to the +client. It uses parenthesized, keyed format specifiers, so the +format operand must be a dictionary. The \var{code} key should +be an integer, specifying the numeric HTTP error code value. +\var{message} should be a string containing a (detailed) error +message of what occurred, and \var{explain} should be an +explanation of the error code number. Default \var{message} +and \var{explain} values can found in the \var{responses} +class variable. +\end{memberdesc} + +\begin{memberdesc}{protocol_version} +This specifies the HTTP protocol version used in responses. If set +to \code{'HTTP/1.1'}, the server will permit HTTP persistent +connections; however, your server \emph{must} then include an +accurate \code{Content-Length} header (using \method{send_header()}) +in all of its responses to clients. For backwards compatibility, +the setting defaults to \code{'HTTP/1.0'}. +\end{memberdesc} + +\begin{memberdesc}{MessageClass} +Specifies a \class{rfc822.Message}-like class to parse HTTP +headers. Typically, this is not overridden, and it defaults to +\class{mimetools.Message}. +\withsubitem{(in module mimetools)}{\ttindex{Message}} +\end{memberdesc} + +\begin{memberdesc}{responses} +This variable contains a mapping of error code integers to two-element +tuples containing a short and long message. For example, +\code{\{\var{code}: (\var{shortmessage}, \var{longmessage})\}}. The +\var{shortmessage} is usually used as the \var{message} key in an +error response, and \var{longmessage} as the \var{explain} key +(see the \member{error_message_format} class variable). +\end{memberdesc} + + +A \class{BaseHTTPRequestHandler} instance has the following methods: + +\begin{methoddesc}{handle}{} +Calls \method{handle_one_request()} once (or, if persistent connections +are enabled, multiple times) to handle incoming HTTP requests. +You should never need to override it; instead, implement appropriate +\method{do_*()} methods. +\end{methoddesc} + +\begin{methoddesc}{handle_one_request}{} +This method will parse and dispatch +the request to the appropriate \method{do_*()} method. You should +never need to override it. +\end{methoddesc} + +\begin{methoddesc}{send_error}{code\optional{, message}} +Sends and logs a complete error reply to the client. The numeric +\var{code} specifies the HTTP error code, with \var{message} as +optional, more specific text. A complete set of headers is sent, +followed by text composed using the \member{error_message_format} +class variable. +\end{methoddesc} + +\begin{methoddesc}{send_response}{code\optional{, message}} +Sends a response header and logs the accepted request. The HTTP +response line is sent, followed by \emph{Server} and \emph{Date} +headers. The values for these two headers are picked up from the +\method{version_string()} and \method{date_time_string()} methods, +respectively. +\end{methoddesc} + +\begin{methoddesc}{send_header}{keyword, value} +Writes a specific HTTP header to the output stream. \var{keyword} +should specify the header keyword, with \var{value} specifying +its value. +\end{methoddesc} + +\begin{methoddesc}{end_headers}{} +Sends a blank line, indicating the end of the HTTP headers in +the response. +\end{methoddesc} + +\begin{methoddesc}{log_request}{\optional{code\optional{, size}}} +Logs an accepted (successful) request. \var{code} should specify +the numeric HTTP code associated with the response. If a size of +the response is available, then it should be passed as the +\var{size} parameter. +\end{methoddesc} + +\begin{methoddesc}{log_error}{...} +Logs an error when a request cannot be fulfilled. By default, +it passes the message to \method{log_message()}, so it takes the +same arguments (\var{format} and additional values). +\end{methoddesc} + +\begin{methoddesc}{log_message}{format, ...} +Logs an arbitrary message to \code{sys.stderr}. This is typically +overridden to create custom error logging mechanisms. The +\var{format} argument is a standard printf-style format string, +where the additional arguments to \method{log_message()} are applied +as inputs to the formatting. The client address and current date +and time are prefixed to every message logged. +\end{methoddesc} + +\begin{methoddesc}{version_string}{} +Returns the server software's version string. This is a combination +of the \member{server_version} and \member{sys_version} class variables. +\end{methoddesc} + +\begin{methoddesc}{date_time_string}{\optional{timestamp}} +Returns the date and time given by \var{timestamp} (which must be in the +format returned by \function{time.time()}), formatted for a message header. +If \var{timestamp} is omitted, it uses the current date and time. + +The result looks like \code{'Sun, 06 Nov 1994 08:49:37 GMT'}. +\versionadded[The \var{timestamp} parameter]{2.5} +\end{methoddesc} + +\begin{methoddesc}{log_date_time_string}{} +Returns the current date and time, formatted for logging. +\end{methoddesc} + +\begin{methoddesc}{address_string}{} +Returns the client address, formatted for logging. A name lookup +is performed on the client's IP address. +\end{methoddesc} + + +\begin{seealso} + \seemodule{CGIHTTPServer}{Extended request handler that supports CGI + scripts.} + + \seemodule{SimpleHTTPServer}{Basic request handler that limits response + to files actually under the document root.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libbastion.tex b/sys/src/cmd/python/Doc/lib/libbastion.tex new file mode 100644 index 000000000..9f45c47a2 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbastion.tex @@ -0,0 +1,57 @@ +\section{\module{Bastion} --- + Restricting access to objects} + +\declaremodule{standard}{Bastion} +\modulesynopsis{Providing restricted access to objects.} +\moduleauthor{Barry Warsaw}{bwarsaw@python.org} +\versionchanged[Disabled module]{2.3} + +\begin{notice}[warning] + The documentation has been left in place to help in reading old code + that uses the module. +\end{notice} + +% I'm concerned that the word 'bastion' won't be understood by people +% for whom English is a second language, making the module name +% somewhat mysterious. Thus, the brief definition... --amk + +According to the dictionary, a bastion is ``a fortified area or +position'', or ``something that is considered a stronghold.'' It's a +suitable name for this module, which provides a way to forbid access +to certain attributes of an object. It must always be used with the +\refmodule{rexec} module, in order to allow restricted-mode programs +access to certain safe attributes of an object, while denying access +to other, unsafe attributes. + +% I've punted on the issue of documenting keyword arguments for now. + +\begin{funcdesc}{Bastion}{object\optional{, filter\optional{, + name\optional{, class}}}} +Protect the object \var{object}, returning a bastion for the +object. Any attempt to access one of the object's attributes will +have to be approved by the \var{filter} function; if the access is +denied an \exception{AttributeError} exception will be raised. + +If present, \var{filter} must be a function that accepts a string +containing an attribute name, and returns true if access to that +attribute will be permitted; if \var{filter} returns false, the access +is denied. The default filter denies access to any function beginning +with an underscore (\character{_}). The bastion's string representation +will be \samp{} if a value for +\var{name} is provided; otherwise, \samp{repr(\var{object})} will be +used. + +\var{class}, if present, should be a subclass of \class{BastionClass}; +see the code in \file{bastion.py} for the details. Overriding the +default \class{BastionClass} will rarely be required. +\end{funcdesc} + + +\begin{classdesc}{BastionClass}{getfunc, name} +Class which actually implements bastion objects. This is the default +class used by \function{Bastion()}. The \var{getfunc} parameter is a +function which returns the value of an attribute which should be +exposed to the restricted execution environment when called with the +name of the attribute as the only parameter. \var{name} is used to +construct the \function{repr()} of the \class{BastionClass} instance. +\end{classdesc} diff --git a/sys/src/cmd/python/Doc/lib/libbinascii.tex b/sys/src/cmd/python/Doc/lib/libbinascii.tex new file mode 100644 index 000000000..84d29c613 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbinascii.tex @@ -0,0 +1,147 @@ +\section{\module{binascii} --- + Convert between binary and \ASCII} + +\declaremodule{builtin}{binascii} +\modulesynopsis{Tools for converting between binary and various + \ASCII-encoded binary representations.} + + +The \module{binascii} module contains a number of methods to convert +between binary and various \ASCII-encoded binary +representations. Normally, you will not use these functions directly +but use wrapper modules like \refmodule{uu}\refstmodindex{uu}, +\refmodule{base64}\refstmodindex{base64}, or +\refmodule{binhex}\refstmodindex{binhex} instead. The \module{binascii} module +contains low-level functions written in C for greater speed +that are used by the higher-level modules. + +The \module{binascii} module defines the following functions: + +\begin{funcdesc}{a2b_uu}{string} +Convert a single line of uuencoded data back to binary and return the +binary data. Lines normally contain 45 (binary) bytes, except for the +last line. Line data may be followed by whitespace. +\end{funcdesc} + +\begin{funcdesc}{b2a_uu}{data} +Convert binary data to a line of \ASCII{} characters, the return value +is the converted line, including a newline char. The length of +\var{data} should be at most 45. +\end{funcdesc} + +\begin{funcdesc}{a2b_base64}{string} +Convert a block of base64 data back to binary and return the +binary data. More than one line may be passed at a time. +\end{funcdesc} + +\begin{funcdesc}{b2a_base64}{data} +Convert binary data to a line of \ASCII{} characters in base64 coding. +The return value is the converted line, including a newline char. +The length of \var{data} should be at most 57 to adhere to the base64 +standard. +\end{funcdesc} + +\begin{funcdesc}{a2b_qp}{string\optional{, header}} +Convert a block of quoted-printable data back to binary and return the +binary data. More than one line may be passed at a time. +If the optional argument \var{header} is present and true, underscores +will be decoded as spaces. +\end{funcdesc} + +\begin{funcdesc}{b2a_qp}{data\optional{, quotetabs, istext, header}} +Convert binary data to a line(s) of \ASCII{} characters in +quoted-printable encoding. The return value is the converted line(s). +If the optional argument \var{quotetabs} is present and true, all tabs +and spaces will be encoded. +If the optional argument \var{istext} is present and true, +newlines are not encoded but trailing whitespace will be encoded. +If the optional argument \var{header} is +present and true, spaces will be encoded as underscores per RFC1522. +If the optional argument \var{header} is present and false, newline +characters will be encoded as well; otherwise linefeed conversion might +corrupt the binary data stream. +\end{funcdesc} + +\begin{funcdesc}{a2b_hqx}{string} +Convert binhex4 formatted \ASCII{} data to binary, without doing +RLE-decompression. The string should contain a complete number of +binary bytes, or (in case of the last portion of the binhex4 data) +have the remaining bits zero. +\end{funcdesc} + +\begin{funcdesc}{rledecode_hqx}{data} +Perform RLE-decompression on the data, as per the binhex4 +standard. The algorithm uses \code{0x90} after a byte as a repeat +indicator, followed by a count. A count of \code{0} specifies a byte +value of \code{0x90}. The routine returns the decompressed data, +unless data input data ends in an orphaned repeat indicator, in which +case the \exception{Incomplete} exception is raised. +\end{funcdesc} + +\begin{funcdesc}{rlecode_hqx}{data} +Perform binhex4 style RLE-compression on \var{data} and return the +result. +\end{funcdesc} + +\begin{funcdesc}{b2a_hqx}{data} +Perform hexbin4 binary-to-\ASCII{} translation and return the +resulting string. The argument should already be RLE-coded, and have a +length divisible by 3 (except possibly the last fragment). +\end{funcdesc} + +\begin{funcdesc}{crc_hqx}{data, crc} +Compute the binhex4 crc value of \var{data}, starting with an initial +\var{crc} and returning the result. +\end{funcdesc} + +\begin{funcdesc}{crc32}{data\optional{, crc}} +Compute CRC-32, the 32-bit checksum of data, starting with an initial +crc. This is consistent with the ZIP file checksum. Since the +algorithm is designed for use as a checksum algorithm, it is not +suitable for use as a general hash algorithm. Use as follows: +\begin{verbatim} + print binascii.crc32("hello world") + # Or, in two pieces: + crc = binascii.crc32("hello") + crc = binascii.crc32(" world", crc) + print crc +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{b2a_hex}{data} +\funcline{hexlify}{data} +Return the hexadecimal representation of the binary \var{data}. Every +byte of \var{data} is converted into the corresponding 2-digit hex +representation. The resulting string is therefore twice as long as +the length of \var{data}. +\end{funcdesc} + +\begin{funcdesc}{a2b_hex}{hexstr} +\funcline{unhexlify}{hexstr} +Return the binary data represented by the hexadecimal string +\var{hexstr}. This function is the inverse of \function{b2a_hex()}. +\var{hexstr} must contain an even number of hexadecimal digits (which +can be upper or lower case), otherwise a \exception{TypeError} is +raised. +\end{funcdesc} + +\begin{excdesc}{Error} +Exception raised on errors. These are usually programming errors. +\end{excdesc} + +\begin{excdesc}{Incomplete} +Exception raised on incomplete data. These are usually not programming +errors, but may be handled by reading a little more data and trying +again. +\end{excdesc} + + +\begin{seealso} + \seemodule{base64}{Support for base64 encoding used in MIME email messages.} + + \seemodule{binhex}{Support for the binhex format used on the Macintosh.} + + \seemodule{uu}{Support for UU encoding used on \UNIX.} + + \seemodule{quopri}{Support for quoted-printable encoding used in MIME email messages. } +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libbinhex.tex b/sys/src/cmd/python/Doc/lib/libbinhex.tex new file mode 100644 index 000000000..d30f2b437 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbinhex.tex @@ -0,0 +1,55 @@ +\section{\module{binhex} --- + Encode and decode binhex4 files} + +\declaremodule{standard}{binhex} +\modulesynopsis{Encode and decode files in binhex4 format.} + + +This module encodes and decodes files in binhex4 format, a format +allowing representation of Macintosh files in \ASCII. On the Macintosh, +both forks of a file and the finder information are encoded (or +decoded), on other platforms only the data fork is handled. + +The \module{binhex} module defines the following functions: + +\begin{funcdesc}{binhex}{input, output} +Convert a binary file with filename \var{input} to binhex file +\var{output}. The \var{output} parameter can either be a filename or a +file-like object (any object supporting a \method{write()} and +\method{close()} method). +\end{funcdesc} + +\begin{funcdesc}{hexbin}{input\optional{, output}} +Decode a binhex file \var{input}. \var{input} may be a filename or a +file-like object supporting \method{read()} and \method{close()} methods. +The resulting file is written to a file named \var{output}, unless the +argument is omitted in which case the output filename is read from the +binhex file. +\end{funcdesc} + +The following exception is also defined: + +\begin{excdesc}{Error} +Exception raised when something can't be encoded using the binhex +format (for example, a filename is too long to fit in the filename +field), or when input is not properly encoded binhex data. +\end{excdesc} + + +\begin{seealso} + \seemodule{binascii}{Support module containing \ASCII-to-binary + and binary-to-\ASCII{} conversions.} +\end{seealso} + + +\subsection{Notes \label{binhex-notes}} + +There is an alternative, more powerful interface to the coder and +decoder, see the source for details. + +If you code or decode textfiles on non-Macintosh platforms they will +still use the Macintosh newline convention (carriage-return as end of +line). + +As of this writing, \function{hexbin()} appears to not work in all +cases. diff --git a/sys/src/cmd/python/Doc/lib/libbisect.tex b/sys/src/cmd/python/Doc/lib/libbisect.tex new file mode 100644 index 000000000..516e5cfa1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbisect.tex @@ -0,0 +1,84 @@ +\section{\module{bisect} --- + Array bisection algorithm} + +\declaremodule{standard}{bisect} +\modulesynopsis{Array bisection algorithms for binary searching.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +% LaTeX produced by Fred L. Drake, Jr. , with an +% example based on the PyModules FAQ entry by Aaron Watters +% . + + +This module provides support for maintaining a list in sorted order +without having to sort the list after each insertion. For long lists +of items with expensive comparison operations, this can be an +improvement over the more common approach. The module is called +\module{bisect} because it uses a basic bisection algorithm to do its +work. The source code may be most useful as a working example of the +algorithm (the boundary conditions are already right!). + +The following functions are provided: + +\begin{funcdesc}{bisect_left}{list, item\optional{, lo\optional{, hi}}} + Locate the proper insertion point for \var{item} in \var{list} to + maintain sorted order. The parameters \var{lo} and \var{hi} may be + used to specify a subset of the list which should be considered; by + default the entire list is used. If \var{item} is already present + in \var{list}, the insertion point will be before (to the left of) + any existing entries. The return value is suitable for use as the + first parameter to \code{\var{list}.insert()}. This assumes that + \var{list} is already sorted. +\versionadded{2.1} +\end{funcdesc} + +\begin{funcdesc}{bisect_right}{list, item\optional{, lo\optional{, hi}}} + Similar to \function{bisect_left()}, but returns an insertion point + which comes after (to the right of) any existing entries of + \var{item} in \var{list}. +\versionadded{2.1} +\end{funcdesc} + +\begin{funcdesc}{bisect}{\unspecified} + Alias for \function{bisect_right()}. +\end{funcdesc} + +\begin{funcdesc}{insort_left}{list, item\optional{, lo\optional{, hi}}} + Insert \var{item} in \var{list} in sorted order. This is equivalent + to \code{\var{list}.insert(bisect.bisect_left(\var{list}, \var{item}, + \var{lo}, \var{hi}), \var{item})}. This assumes that \var{list} is + already sorted. +\versionadded{2.1} +\end{funcdesc} + +\begin{funcdesc}{insort_right}{list, item\optional{, lo\optional{, hi}}} + Similar to \function{insort_left()}, but inserting \var{item} in + \var{list} after any existing entries of \var{item}. +\versionadded{2.1} +\end{funcdesc} + +\begin{funcdesc}{insort}{\unspecified} + Alias for \function{insort_right()}. +\end{funcdesc} + + +\subsection{Examples} +\nodename{bisect-example} + +The \function{bisect()} function is generally useful for categorizing +numeric data. This example uses \function{bisect()} to look up a +letter grade for an exam total (say) based on a set of ordered numeric +breakpoints: 85 and up is an `A', 75..84 is a `B', etc. + +\begin{verbatim} +>>> grades = "FEDCBA" +>>> breakpoints = [30, 44, 66, 75, 85] +>>> from bisect import bisect +>>> def grade(total): +... return grades[bisect(breakpoints, total)] +... +>>> grade(66) +'C' +>>> map(grade, [33, 99, 77, 44, 12, 88]) +['E', 'A', 'B', 'D', 'F', 'A'] + +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libbltin.tex b/sys/src/cmd/python/Doc/lib/libbltin.tex new file mode 100644 index 000000000..f6abe25af --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbltin.tex @@ -0,0 +1,44 @@ +\section{\module{__builtin__} --- + Built-in objects} + +\declaremodule[builtin]{builtin}{__builtin__} +\modulesynopsis{The module that provides the built-in namespace.} + + +This module provides direct access to all `built-in' identifiers of +Python; for example, \code{__builtin__.open} is the full name for the +built-in function \function{open()}. See chapter~\ref{builtin}, +``Built-in Objects.'' + +This module is not normally accessed explicitly by most applications, +but can be useful in modules that provide objects with the same name +as a built-in value, but in which the built-in of that name is also +needed. For example, in a module that wants to implement an +\function{open()} function that wraps the built-in \function{open()}, +this module can be used directly: + +\begin{verbatim} +import __builtin__ + +def open(path): + f = __builtin__.open(path, 'r') + return UpperCaser(f) + +class UpperCaser: + '''Wrapper around a file that converts output to upper-case.''' + + def __init__(self, f): + self._f = f + + def read(self, count=-1): + return self._f.read(count).upper() + + # ... +\end{verbatim} + +As an implementation detail, most modules have the name +\code{__builtins__} (note the \character{s}) made available as part of +their globals. The value of \code{__builtins__} is normally either +this module or the value of this modules's \member{__dict__} +attribute. Since this is an implementation detail, it may not be used +by alternate implementations of Python. diff --git a/sys/src/cmd/python/Doc/lib/libbsddb.tex b/sys/src/cmd/python/Doc/lib/libbsddb.tex new file mode 100644 index 000000000..ae4292318 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbsddb.tex @@ -0,0 +1,208 @@ +\section{\module{bsddb} --- + Interface to Berkeley DB library} + +\declaremodule{extension}{bsddb} +\modulesynopsis{Interface to Berkeley DB database library} +\sectionauthor{Skip Montanaro}{skip@mojam.com} + + +The \module{bsddb} module provides an interface to the Berkeley DB +library. Users can create hash, btree or record based library files +using the appropriate open call. Bsddb objects behave generally like +dictionaries. Keys and values must be strings, however, so to use +other objects as keys or to store other kinds of objects the user must +serialize them somehow, typically using \function{marshal.dumps()} or +\function{pickle.dumps()}. + +The \module{bsddb} module requires a Berkeley DB library version from +3.3 thru 4.5. + +\begin{seealso} + \seeurl{http://pybsddb.sourceforge.net/} + {The website with documentation for the \module{bsddb.db} + Python Berkeley DB interface that closely mirrors the object + oriented interface provided in Berkeley DB 3 and 4.} + + \seeurl{http://www.oracle.com/database/berkeley-db/} + {The Berkeley DB library.} +\end{seealso} + +A more modern DB, DBEnv and DBSequence object interface is available in the +\module{bsddb.db} module which closely matches the Berkeley DB C API +documented at the above URLs. Additional features provided by the +\module{bsddb.db} API include fine tuning, transactions, logging, and +multiprocess concurrent database access. + +The following is a description of the legacy \module{bsddb} interface +compatible with the old Python bsddb module. Starting in Python 2.5 this +interface should be safe for multithreaded access. The \module{bsddb.db} +API is recommended for threading users as it provides better control. + +The \module{bsddb} module defines the following functions that create +objects that access the appropriate type of Berkeley DB file. The +first two arguments of each function are the same. For ease of +portability, only the first two arguments should be used in most +instances. + +\begin{funcdesc}{hashopen}{filename\optional{, flag\optional{, + mode\optional{, pgsize\optional{, + ffactor\optional{, nelem\optional{, + cachesize\optional{, lorder\optional{, + hflags}}}}}}}}} +Open the hash format file named \var{filename}. Files never intended +to be preserved on disk may be created by passing \code{None} as the +\var{filename}. The optional +\var{flag} identifies the mode used to open the file. It may be +\character{r} (read only), \character{w} (read-write) , +\character{c} (read-write - create if necessary; the default) or +\character{n} (read-write - truncate to zero length). The other +arguments are rarely used and are just passed to the low-level +\cfunction{dbopen()} function. Consult the Berkeley DB documentation +for their use and interpretation. +\end{funcdesc} + +\begin{funcdesc}{btopen}{filename\optional{, flag\optional{, +mode\optional{, btflags\optional{, cachesize\optional{, maxkeypage\optional{, +minkeypage\optional{, pgsize\optional{, lorder}}}}}}}}} + +Open the btree format file named \var{filename}. Files never intended +to be preserved on disk may be created by passing \code{None} as the +\var{filename}. The optional +\var{flag} identifies the mode used to open the file. It may be +\character{r} (read only), \character{w} (read-write), +\character{c} (read-write - create if necessary; the default) or +\character{n} (read-write - truncate to zero length). The other +arguments are rarely used and are just passed to the low-level dbopen +function. Consult the Berkeley DB documentation for their use and +interpretation. +\end{funcdesc} + +\begin{funcdesc}{rnopen}{filename\optional{, flag\optional{, mode\optional{, +rnflags\optional{, cachesize\optional{, pgsize\optional{, lorder\optional{, +rlen\optional{, delim\optional{, source\optional{, pad}}}}}}}}}}} + +Open a DB record format file named \var{filename}. Files never intended +to be preserved on disk may be created by passing \code{None} as the +\var{filename}. The optional +\var{flag} identifies the mode used to open the file. It may be +\character{r} (read only), \character{w} (read-write), +\character{c} (read-write - create if necessary; the default) or +\character{n} (read-write - truncate to zero length). The other +arguments are rarely used and are just passed to the low-level dbopen +function. Consult the Berkeley DB documentation for their use and +interpretation. +\end{funcdesc} + + +\begin{notice} +Beginning in 2.3 some \UNIX{} versions of Python may have a \module{bsddb185} +module. This is present \emph{only} to allow backwards compatibility with +systems which ship with the old Berkeley DB 1.85 database library. The +\module{bsddb185} module should never be used directly in new code. +\end{notice} + + +\begin{seealso} + \seemodule{dbhash}{DBM-style interface to the \module{bsddb}} +\end{seealso} + +\subsection{Hash, BTree and Record Objects \label{bsddb-objects}} + +Once instantiated, hash, btree and record objects support +the same methods as dictionaries. In addition, they support +the methods listed below. +\versionchanged[Added dictionary methods]{2.3.1} + +\begin{methoddesc}{close}{} +Close the underlying file. The object can no longer be accessed. Since +there is no open \method{open} method for these objects, to open the file +again a new \module{bsddb} module open function must be called. +\end{methoddesc} + +\begin{methoddesc}{keys}{} +Return the list of keys contained in the DB file. The order of the list is +unspecified and should not be relied on. In particular, the order of the +list returned is different for different file formats. +\end{methoddesc} + +\begin{methoddesc}{has_key}{key} +Return \code{1} if the DB file contains the argument as a key. +\end{methoddesc} + +\begin{methoddesc}{set_location}{key} +Set the cursor to the item indicated by \var{key} and return a tuple +containing the key and its value. For binary tree databases (opened +using \function{btopen()}), if \var{key} does not actually exist in +the database, the cursor will point to the next item in sorted order +and return that key and value. For other databases, +\exception{KeyError} will be raised if \var{key} is not found in the +database. +\end{methoddesc} + +\begin{methoddesc}{first}{} +Set the cursor to the first item in the DB file and return it. The order of +keys in the file is unspecified, except in the case of B-Tree databases. +This method raises \exception{bsddb.error} if the database is empty. +\end{methoddesc} + +\begin{methoddesc}{next}{} +Set the cursor to the next item in the DB file and return it. The order of +keys in the file is unspecified, except in the case of B-Tree databases. +\end{methoddesc} + +\begin{methoddesc}{previous}{} +Set the cursor to the previous item in the DB file and return it. The +order of keys in the file is unspecified, except in the case of B-Tree +databases. This is not supported on hashtable databases (those opened +with \function{hashopen()}). +\end{methoddesc} + +\begin{methoddesc}{last}{} +Set the cursor to the last item in the DB file and return it. The +order of keys in the file is unspecified. This is not supported on +hashtable databases (those opened with \function{hashopen()}). +This method raises \exception{bsddb.error} if the database is empty. +\end{methoddesc} + +\begin{methoddesc}{sync}{} +Synchronize the database on disk. +\end{methoddesc} + +Example: + +\begin{verbatim} +>>> import bsddb +>>> db = bsddb.btopen('/tmp/spam.db', 'c') +>>> for i in range(10): db['%d'%i] = '%d'% (i*i) +... +>>> db['3'] +'9' +>>> db.keys() +['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] +>>> db.first() +('0', '0') +>>> db.next() +('1', '1') +>>> db.last() +('9', '81') +>>> db.set_location('2') +('2', '4') +>>> db.previous() +('1', '1') +>>> for k, v in db.iteritems(): +... print k, v +0 0 +1 1 +2 4 +3 9 +4 16 +5 25 +6 36 +7 49 +8 64 +9 81 +>>> '8' in db +True +>>> db.sync() +0 +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libbz2.tex b/sys/src/cmd/python/Doc/lib/libbz2.tex new file mode 100644 index 000000000..fe0e3af65 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libbz2.tex @@ -0,0 +1,174 @@ +\section{\module{bz2} --- + Compression compatible with \program{bzip2}} + +\declaremodule{builtin}{bz2} +\modulesynopsis{Interface to compression and decompression + routines compatible with \program{bzip2}.} +\moduleauthor{Gustavo Niemeyer}{niemeyer@conectiva.com} +\sectionauthor{Gustavo Niemeyer}{niemeyer@conectiva.com} + +\versionadded{2.3} + +This module provides a comprehensive interface for the bz2 compression library. +It implements a complete file interface, one-shot (de)compression functions, +and types for sequential (de)compression. + +Here is a resume of the features offered by the bz2 module: + +\begin{itemize} +\item \class{BZ2File} class implements a complete file interface, including + \method{readline()}, \method{readlines()}, + \method{writelines()}, \method{seek()}, etc; +\item \class{BZ2File} class implements emulated \method{seek()} support; +\item \class{BZ2File} class implements universal newline support; +\item \class{BZ2File} class offers an optimized line iteration using + the readahead algorithm borrowed from file objects; +\item Sequential (de)compression supported by \class{BZ2Compressor} and + \class{BZ2Decompressor} classes; +\item One-shot (de)compression supported by \function{compress()} and + \function{decompress()} functions; +\item Thread safety uses individual locking mechanism; +\item Complete inline documentation; +\end{itemize} + + +\subsection{(De)compression of files} + +Handling of compressed files is offered by the \class{BZ2File} class. + +\begin{classdesc}{BZ2File}{filename\optional{, mode\optional{, + buffering\optional{, compresslevel}}}} +Open a bz2 file. Mode can be either \code{'r'} or \code{'w'}, for reading +(default) or writing. When opened for writing, the file will be created if +it doesn't exist, and truncated otherwise. If \var{buffering} is given, +\code{0} means unbuffered, and larger numbers specify the buffer size; +the default is \code{0}. If +\var{compresslevel} is given, it must be a number between \code{1} and +\code{9}; the default is \code{9}. +Add a \character{U} to mode to open the file for input with universal newline +support. Any line ending in the input file will be seen as a +\character{\e n} in Python. Also, a file so opened gains the +attribute \member{newlines}; the value for this attribute is one of +\code{None} (no newline read yet), \code{'\e r'}, \code{'\e n'}, +\code{'\e r\e n'} or a tuple containing all the newline types +seen. Universal newlines are available only when reading. +Instances support iteration in the same way as normal \class{file} +instances. +\end{classdesc} + +\begin{methoddesc}[BZ2File]{close}{} +Close the file. Sets data attribute \member{closed} to true. A closed file +cannot be used for further I/O operations. \method{close()} may be called +more than once without error. +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{read}{\optional{size}} +Read at most \var{size} uncompressed bytes, returned as a string. If the +\var{size} argument is negative or omitted, read until EOF is reached. +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{readline}{\optional{size}} +Return the next line from the file, as a string, retaining newline. +A non-negative \var{size} argument limits the maximum number of bytes to +return (an incomplete line may be returned then). Return an empty +string at EOF. +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{readlines}{\optional{size}} +Return a list of lines read. The optional \var{size} argument, if given, +is an approximate bound on the total number of bytes in the lines returned. +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{xreadlines}{} +For backward compatibility. \class{BZ2File} objects now include the +performance optimizations previously implemented in the +\module{xreadlines} module. +\deprecated{2.3}{This exists only for compatibility with the method by + this name on \class{file} objects, which is + deprecated. Use \code{for line in file} instead.} +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{seek}{offset\optional{, whence}} +Move to new file position. Argument \var{offset} is a byte count. Optional +argument \var{whence} defaults to \code{os.SEEK_SET} or \code{0} (offset from start of file; +offset should be \code{>= 0}); other values are \code{os.SEEK_CUR} or \code{1} (move relative to +current position; offset can be positive or negative), and \code{os.SEEK_END} or \code{2} (move relative to end +of file; offset is usually negative, although many platforms allow seeking beyond +the end of a file). + +Note that seeking of bz2 files is emulated, and depending on the parameters +the operation may be extremely slow. +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{tell}{} +Return the current file position, an integer (may be a long integer). +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{write}{data} +Write string \var{data} to file. Note that due to buffering, \method{close()} +may be needed before the file on disk reflects the data written. +\end{methoddesc} + +\begin{methoddesc}[BZ2File]{writelines}{sequence_of_strings} +Write the sequence of strings to the file. Note that newlines are not added. +The sequence can be any iterable object producing strings. This is equivalent +to calling write() for each string. +\end{methoddesc} + + +\subsection{Sequential (de)compression} + +Sequential compression and decompression is done using the classes +\class{BZ2Compressor} and \class{BZ2Decompressor}. + +\begin{classdesc}{BZ2Compressor}{\optional{compresslevel}} +Create a new compressor object. This object may be used to compress +data sequentially. If you want to compress data in one shot, use the +\function{compress()} function instead. The \var{compresslevel} parameter, +if given, must be a number between \code{1} and \code{9}; the default +is \code{9}. +\end{classdesc} + +\begin{methoddesc}[BZ2Compressor]{compress}{data} +Provide more data to the compressor object. It will return chunks of compressed +data whenever possible. When you've finished providing data to compress, call +the \method{flush()} method to finish the compression process, and return what +is left in internal buffers. +\end{methoddesc} + +\begin{methoddesc}[BZ2Compressor]{flush}{} +Finish the compression process and return what is left in internal buffers. You +must not use the compressor object after calling this method. +\end{methoddesc} + +\begin{classdesc}{BZ2Decompressor}{} +Create a new decompressor object. This object may be used to decompress +data sequentially. If you want to decompress data in one shot, use the +\function{decompress()} function instead. +\end{classdesc} + +\begin{methoddesc}[BZ2Decompressor]{decompress}{data} +Provide more data to the decompressor object. It will return chunks of +decompressed data whenever possible. If you try to decompress data after the +end of stream is found, \exception{EOFError} will be raised. If any data was +found after the end of stream, it'll be ignored and saved in +\member{unused\_data} attribute. +\end{methoddesc} + + +\subsection{One-shot (de)compression} + +One-shot compression and decompression is provided through the +\function{compress()} and \function{decompress()} functions. + +\begin{funcdesc}{compress}{data\optional{, compresslevel}} +Compress \var{data} in one shot. If you want to compress data sequentially, +use an instance of \class{BZ2Compressor} instead. The \var{compresslevel} +parameter, if given, must be a number between \code{1} and \code{9}; +the default is \code{9}. +\end{funcdesc} + +\begin{funcdesc}{decompress}{data} +Decompress \var{data} in one shot. If you want to decompress data +sequentially, use an instance of \class{BZ2Decompressor} instead. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libcalendar.tex b/sys/src/cmd/python/Doc/lib/libcalendar.tex new file mode 100644 index 000000000..acfd2da7e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcalendar.tex @@ -0,0 +1,304 @@ +\section{\module{calendar} --- + General calendar-related functions} + +\declaremodule{standard}{calendar} +\modulesynopsis{Functions for working with calendars, + including some emulation of the \UNIX\ \program{cal} + program.} +\sectionauthor{Drew Csillag}{drew_csillag@geocities.com} + +This module allows you to output calendars like the \UNIX{} +\program{cal} program, and provides additional useful functions +related to the calendar. By default, these calendars have Monday as +the first day of the week, and Sunday as the last (the European +convention). Use \function{setfirstweekday()} to set the first day of the +week to Sunday (6) or to any other weekday. Parameters that specify +dates are given as integers. + +Most of these functions and classses rely on the \module{datetime} +module which uses an idealized calendar, the current Gregorian +calendar indefinitely extended in both directions. This matches +the definition of the "proleptic Gregorian" calendar in Dershowitz +and Reingold's book "Calendrical Calculations", where it's the +base calendar for all computations. + +\begin{classdesc}{Calendar}{\optional{firstweekday}} +Creates a \class{Calendar} object. \var{firstweekday} is an integer +specifying the first day of the week. \code{0} is Monday (the default), +\code{6} is Sunday. + +A \class{Calendar} object provides several methods that can +be used for preparing the calendar data for formatting. This +class doesn't do any formatting itself. This is the job of +subclasses. +\versionadded{2.5} +\end{classdesc} + +\class{Calendar} instances have the following methods: + +\begin{methoddesc}{iterweekdays}{weekday} +Return an iterator for the week day numbers that will be used +for one week. The first number from the iterator will be the +same as the number returned by \method{firstweekday()}. +\end{methoddesc} + +\begin{methoddesc}{itermonthdates}{year, month} +Return an iterator for the month \var{month} (1-12) in the +year \var{year}. This iterator will return all days (as +\class{datetime.date} objects) for the month and all days +before the start of the month or after the end of the month +that are required to get a complete week. +\end{methoddesc} + +\begin{methoddesc}{itermonthdays2}{year, month} +Return an iterator for the month \var{month} in the year +\var{year} similar to \method{itermonthdates()}. Days returned +will be tuples consisting of a day number and a week day +number. +\end{methoddesc} + +\begin{methoddesc}{itermonthdays}{year, month} +Return an iterator for the month \var{month} in the year +\var{year} similar to \method{itermonthdates()}. Days returned +will simply be day numbers. +\end{methoddesc} + +\begin{methoddesc}{monthdatescalendar}{year, month} +Return a list of the weeks in the month \var{month} of +the \var{year} as full weeks. Weeks are lists of seven +\class{datetime.date} objects. +\end{methoddesc} + +\begin{methoddesc}{monthdays2calendar}{year, month} +Return a list of the weeks in the month \var{month} of +the \var{year} as full weeks. Weeks are lists of seven +tuples of day numbers and weekday numbers. +\end{methoddesc} + +\begin{methoddesc}{monthdayscalendar}{year, month} +Return a list of the weeks in the month \var{month} of +the \var{year} as full weeks. Weeks are lists of seven +day numbers. +\end{methoddesc} + +\begin{methoddesc}{yeardatescalendar}{year, month\optional{, width}} +Return the data for the specified year ready for formatting. The return +value is a list of month rows. Each month row contains up to \var{width} +months (defaulting to 3). Each month contains between 4 and 6 weeks and +each week contains 1--7 days. Days are \class{datetime.date} objects. +\end{methoddesc} + +\begin{methoddesc}{yeardays2calendar}{year, month\optional{, width}} +Return the data for the specified year ready for formatting (similar to +\method{yeardatescalendar()}). Entries in the week lists are tuples of +day numbers and weekday numbers. Day numbers outside this month are zero. +\end{methoddesc} + +\begin{methoddesc}{yeardayscalendar}{year, month\optional{, width}} +Return the data for the specified year ready for formatting (similar to +\method{yeardatescalendar()}). Entries in the week lists are day numbers. +Day numbers outside this month are zero. +\end{methoddesc} + + +\begin{classdesc}{TextCalendar}{\optional{firstweekday}} +This class can be used to generate plain text calendars. + +\versionadded{2.5} +\end{classdesc} + +\class{TextCalendar} instances have the following methods: + +\begin{methoddesc}{formatmonth}{theyear, themonth\optional{, w\optional{, l}}} +Return a month's calendar in a multi-line string. If \var{w} is +provided, it specifies the width of the date columns, which are +centered. If \var{l} is given, it specifies the number of lines that +each week will use. Depends on the first weekday as set by +\function{setfirstweekday()}. +\end{methoddesc} + +\begin{methoddesc}{prmonth}{theyear, themonth\optional{, w\optional{, l}}} +Print a month's calendar as returned by \method{formatmonth()}. +\end{methoddesc} + +\begin{methoddesc}{formatyear}{theyear, themonth\optional{, w\optional{, + l\optional{, c\optional{, m}}}}} +Return a \var{m}-column calendar for an entire year as a multi-line string. +Optional parameters \var{w}, \var{l}, and \var{c} are for date column +width, lines per week, and number of spaces between month columns, +respectively. Depends on the first weekday as set by +\method{setfirstweekday()}. The earliest year for which a calendar can +be generated is platform-dependent. +\end{methoddesc} + +\begin{methoddesc}{pryear}{theyear\optional{, w\optional{, l\optional{, + c\optional{, m}}}}} +Print the calendar for an entire year as returned by \method{formatyear()}. +\end{methoddesc} + + +\begin{classdesc}{HTMLCalendar}{\optional{firstweekday}} +This class can be used to generate HTML calendars. + +\versionadded{2.5} +\end{classdesc} + +\class{HTMLCalendar} instances have the following methods: + +\begin{methoddesc}{formatmonth}{theyear, themonth\optional{, withyear}} +Return a month's calendar as an HTML table. If \var{withyear} is +true the year will be included in the header, otherwise just the +month name will be used. +\end{methoddesc} + +\begin{methoddesc}{formatyear}{theyear, themonth\optional{, width}} +Return a year's calendar as an HTML table. \var{width} (defaulting to 3) +specifies the number of months per row. +\end{methoddesc} + +\begin{methoddesc}{formatyearpage}{theyear, themonth\optional{, + width\optional{, css\optional{, encoding}}}} +Return a year's calendar as a complete HTML page. \var{width} +(defaulting to 3) specifies the number of months per row. \var{css} +is the name for the cascading style sheet to be used. \constant{None} +can be passed if no style sheet should be used. \var{encoding} +specifies the encoding to be used for the output (defaulting +to the system default encoding). +\end{methoddesc} + + +\begin{classdesc}{LocaleTextCalendar}{\optional{firstweekday\optional{, locale}}} +This subclass of \class{TextCalendar} can be passed a locale name in the +constructor and will return month and weekday names in the specified locale. +If this locale includes an encoding all strings containing month and weekday +names will be returned as unicode. +\versionadded{2.5} +\end{classdesc} + + +\begin{classdesc}{LocaleHTMLCalendar}{\optional{firstweekday\optional{, locale}}} +This subclass of \class{HTMLCalendar} can be passed a locale name in the +constructor and will return month and weekday names in the specified locale. +If this locale includes an encoding all strings containing month and weekday +names will be returned as unicode. +\versionadded{2.5} +\end{classdesc} + + +For simple text calendars this module provides the following functions. + +\begin{funcdesc}{setfirstweekday}{weekday} +Sets the weekday (\code{0} is Monday, \code{6} is Sunday) to start +each week. The values \constant{MONDAY}, \constant{TUESDAY}, +\constant{WEDNESDAY}, \constant{THURSDAY}, \constant{FRIDAY}, +\constant{SATURDAY}, and \constant{SUNDAY} are provided for +convenience. For example, to set the first weekday to Sunday: + +\begin{verbatim} +import calendar +calendar.setfirstweekday(calendar.SUNDAY) +\end{verbatim} +\versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{firstweekday}{} +Returns the current setting for the weekday to start each week. +\versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{isleap}{year} +Returns \constant{True} if \var{year} is a leap year, otherwise +\constant{False}. +\end{funcdesc} + +\begin{funcdesc}{leapdays}{y1, y2} +Returns the number of leap years in the range +[\var{y1}\ldots\var{y2}), where \var{y1} and \var{y2} are years. +\versionchanged[This function didn't work for ranges spanning + a century change in Python 1.5.2]{2.0} +\end{funcdesc} + +\begin{funcdesc}{weekday}{year, month, day} +Returns the day of the week (\code{0} is Monday) for \var{year} +(\code{1970}--\ldots), \var{month} (\code{1}--\code{12}), \var{day} +(\code{1}--\code{31}). +\end{funcdesc} + +\begin{funcdesc}{weekheader}{n} +Return a header containing abbreviated weekday names. \var{n} specifies +the width in characters for one weekday. +\end{funcdesc} + +\begin{funcdesc}{monthrange}{year, month} +Returns weekday of first day of the month and number of days in month, +for the specified \var{year} and \var{month}. +\end{funcdesc} + +\begin{funcdesc}{monthcalendar}{year, month} +Returns a matrix representing a month's calendar. Each row represents +a week; days outside of the month a represented by zeros. +Each week begins with Monday unless set by \function{setfirstweekday()}. +\end{funcdesc} + +\begin{funcdesc}{prmonth}{theyear, themonth\optional{, w\optional{, l}}} +Prints a month's calendar as returned by \function{month()}. +\end{funcdesc} + +\begin{funcdesc}{month}{theyear, themonth\optional{, w\optional{, l}}} +Returns a month's calendar in a multi-line string using the +\method{formatmonth} of the \class{TextCalendar} class. +\versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{prcal}{year\optional{, w\optional{, l\optional{c}}}} +Prints the calendar for an entire year as returned by +\function{calendar()}. +\end{funcdesc} + +\begin{funcdesc}{calendar}{year\optional{, w\optional{, l\optional{c}}}} +Returns a 3-column calendar for an entire year as a multi-line string +using the \method{formatyear} of the \class{TextCalendar} class. +\versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{timegm}{tuple} +An unrelated but handy function that takes a time tuple such as +returned by the \function{gmtime()} function in the \refmodule{time} +module, and returns the corresponding \UNIX{} timestamp value, assuming +an epoch of 1970, and the POSIX encoding. In fact, +\function{time.gmtime()} and \function{timegm()} are each others' inverse. +\versionadded{2.0} +\end{funcdesc} + +The \module{calendar} module exports the following data attributes: + +\begin{datadesc}{day_name} +An array that represents the days of the week in the +current locale. +\end{datadesc} + +\begin{datadesc}{day_abbr} +An array that represents the abbreviated days of the week +in the current locale. +\end{datadesc} + +\begin{datadesc}{month_name} +An array that represents the months of the year in the +current locale. This follows normal convention +of January being month number 1, so it has a length of 13 and +\code{month_name[0]} is the empty string. +\end{datadesc} + +\begin{datadesc}{month_abbr} +An array that represents the abbreviated months of the year +in the current locale. This follows normal convention +of January being month number 1, so it has a length of 13 and +\code{month_abbr[0]} is the empty string. +\end{datadesc} + +\begin{seealso} + \seemodule{datetime}{Object-oriented interface to dates and times + with similar functionality to the + \refmodule{time} module.} + \seemodule{time}{Low-level time related functions.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libcd.tex b/sys/src/cmd/python/Doc/lib/libcd.tex new file mode 100644 index 000000000..83bd2bafc --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcd.tex @@ -0,0 +1,304 @@ +\section{\module{cd} --- + CD-ROM access on SGI systems} + +\declaremodule{builtin}{cd} + \platform{IRIX} +\modulesynopsis{Interface to the CD-ROM on Silicon Graphics systems.} + + +This module provides an interface to the Silicon Graphics CD library. +It is available only on Silicon Graphics systems. + +The way the library works is as follows. A program opens the CD-ROM +device with \function{open()} and creates a parser to parse the data +from the CD with \function{createparser()}. The object returned by +\function{open()} can be used to read data from the CD, but also to get +status information for the CD-ROM device, and to get information about +the CD, such as the table of contents. Data from the CD is passed to +the parser, which parses the frames, and calls any callback +functions that have previously been added. + +An audio CD is divided into \dfn{tracks} or \dfn{programs} (the terms +are used interchangeably). Tracks can be subdivided into +\dfn{indices}. An audio CD contains a \dfn{table of contents} which +gives the starts of the tracks on the CD. Index 0 is usually the +pause before the start of a track. The start of the track as given by +the table of contents is normally the start of index 1. + +Positions on a CD can be represented in two ways. Either a frame +number or a tuple of three values, minutes, seconds and frames. Most +functions use the latter representation. Positions can be both +relative to the beginning of the CD, and to the beginning of the +track. + +Module \module{cd} defines the following functions and constants: + + +\begin{funcdesc}{createparser}{} +Create and return an opaque parser object. The methods of the parser +object are described below. +\end{funcdesc} + +\begin{funcdesc}{msftoframe}{minutes, seconds, frames} +Converts a \code{(\var{minutes}, \var{seconds}, \var{frames})} triple +representing time in absolute time code into the corresponding CD +frame number. +\end{funcdesc} + +\begin{funcdesc}{open}{\optional{device\optional{, mode}}} +Open the CD-ROM device. The return value is an opaque player object; +methods of the player object are described below. The device is the +name of the SCSI device file, e.g. \code{'/dev/scsi/sc0d4l0'}, or +\code{None}. If omitted or \code{None}, the hardware inventory is +consulted to locate a CD-ROM drive. The \var{mode}, if not omitted, +should be the string \code{'r'}. +\end{funcdesc} + +The module defines the following variables: + +\begin{excdesc}{error} +Exception raised on various errors. +\end{excdesc} + +\begin{datadesc}{DATASIZE} +The size of one frame's worth of audio data. This is the size of the +audio data as passed to the callback of type \code{audio}. +\end{datadesc} + +\begin{datadesc}{BLOCKSIZE} +The size of one uninterpreted frame of audio data. +\end{datadesc} + +The following variables are states as returned by +\function{getstatus()}: + +\begin{datadesc}{READY} +The drive is ready for operation loaded with an audio CD. +\end{datadesc} + +\begin{datadesc}{NODISC} +The drive does not have a CD loaded. +\end{datadesc} + +\begin{datadesc}{CDROM} +The drive is loaded with a CD-ROM. Subsequent play or read operations +will return I/O errors. +\end{datadesc} + +\begin{datadesc}{ERROR} +An error occurred while trying to read the disc or its table of +contents. +\end{datadesc} + +\begin{datadesc}{PLAYING} +The drive is in CD player mode playing an audio CD through its audio +jacks. +\end{datadesc} + +\begin{datadesc}{PAUSED} +The drive is in CD layer mode with play paused. +\end{datadesc} + +\begin{datadesc}{STILL} +The equivalent of \constant{PAUSED} on older (non 3301) model Toshiba +CD-ROM drives. Such drives have never been shipped by SGI. +\end{datadesc} + +\begin{datadesc}{audio} +\dataline{pnum} +\dataline{index} +\dataline{ptime} +\dataline{atime} +\dataline{catalog} +\dataline{ident} +\dataline{control} +Integer constants describing the various types of parser callbacks +that can be set by the \method{addcallback()} method of CD parser +objects (see below). +\end{datadesc} + + +\subsection{Player Objects} +\label{player-objects} + +Player objects (returned by \function{open()}) have the following +methods: + +\begin{methoddesc}[CD player]{allowremoval}{} +Unlocks the eject button on the CD-ROM drive permitting the user to +eject the caddy if desired. +\end{methoddesc} + +\begin{methoddesc}[CD player]{bestreadsize}{} +Returns the best value to use for the \var{num_frames} parameter of +the \method{readda()} method. Best is defined as the value that +permits a continuous flow of data from the CD-ROM drive. +\end{methoddesc} + +\begin{methoddesc}[CD player]{close}{} +Frees the resources associated with the player object. After calling +\method{close()}, the methods of the object should no longer be used. +\end{methoddesc} + +\begin{methoddesc}[CD player]{eject}{} +Ejects the caddy from the CD-ROM drive. +\end{methoddesc} + +\begin{methoddesc}[CD player]{getstatus}{} +Returns information pertaining to the current state of the CD-ROM +drive. The returned information is a tuple with the following values: +\var{state}, \var{track}, \var{rtime}, \var{atime}, \var{ttime}, +\var{first}, \var{last}, \var{scsi_audio}, \var{cur_block}. +\var{rtime} is the time relative to the start of the current track; +\var{atime} is the time relative to the beginning of the disc; +\var{ttime} is the total time on the disc. For more information on +the meaning of the values, see the man page \manpage{CDgetstatus}{3dm}. +The value of \var{state} is one of the following: \constant{ERROR}, +\constant{NODISC}, \constant{READY}, \constant{PLAYING}, +\constant{PAUSED}, \constant{STILL}, or \constant{CDROM}. +\end{methoddesc} + +\begin{methoddesc}[CD player]{gettrackinfo}{track} +Returns information about the specified track. The returned +information is a tuple consisting of two elements, the start time of +the track and the duration of the track. +\end{methoddesc} + +\begin{methoddesc}[CD player]{msftoblock}{min, sec, frame} +Converts a minutes, seconds, frames triple representing a time in +absolute time code into the corresponding logical block number for the +given CD-ROM drive. You should use \function{msftoframe()} rather than +\method{msftoblock()} for comparing times. The logical block number +differs from the frame number by an offset required by certain CD-ROM +drives. +\end{methoddesc} + +\begin{methoddesc}[CD player]{play}{start, play} +Starts playback of an audio CD in the CD-ROM drive at the specified +track. The audio output appears on the CD-ROM drive's headphone and +audio jacks (if fitted). Play stops at the end of the disc. +\var{start} is the number of the track at which to start playing the +CD; if \var{play} is 0, the CD will be set to an initial paused +state. The method \method{togglepause()} can then be used to commence +play. +\end{methoddesc} + +\begin{methoddesc}[CD player]{playabs}{minutes, seconds, frames, play} +Like \method{play()}, except that the start is given in minutes, +seconds, and frames instead of a track number. +\end{methoddesc} + +\begin{methoddesc}[CD player]{playtrack}{start, play} +Like \method{play()}, except that playing stops at the end of the +track. +\end{methoddesc} + +\begin{methoddesc}[CD player]{playtrackabs}{track, minutes, seconds, frames, play} +Like \method{play()}, except that playing begins at the specified +absolute time and ends at the end of the specified track. +\end{methoddesc} + +\begin{methoddesc}[CD player]{preventremoval}{} +Locks the eject button on the CD-ROM drive thus preventing the user +from arbitrarily ejecting the caddy. +\end{methoddesc} + +\begin{methoddesc}[CD player]{readda}{num_frames} +Reads the specified number of frames from an audio CD mounted in the +CD-ROM drive. The return value is a string representing the audio +frames. This string can be passed unaltered to the +\method{parseframe()} method of the parser object. +\end{methoddesc} + +\begin{methoddesc}[CD player]{seek}{minutes, seconds, frames} +Sets the pointer that indicates the starting point of the next read of +digital audio data from a CD-ROM. The pointer is set to an absolute +time code location specified in \var{minutes}, \var{seconds}, and +\var{frames}. The return value is the logical block number to which +the pointer has been set. +\end{methoddesc} + +\begin{methoddesc}[CD player]{seekblock}{block} +Sets the pointer that indicates the starting point of the next read of +digital audio data from a CD-ROM. The pointer is set to the specified +logical block number. The return value is the logical block number to +which the pointer has been set. +\end{methoddesc} + +\begin{methoddesc}[CD player]{seektrack}{track} +Sets the pointer that indicates the starting point of the next read of +digital audio data from a CD-ROM. The pointer is set to the specified +track. The return value is the logical block number to which the +pointer has been set. +\end{methoddesc} + +\begin{methoddesc}[CD player]{stop}{} +Stops the current playing operation. +\end{methoddesc} + +\begin{methoddesc}[CD player]{togglepause}{} +Pauses the CD if it is playing, and makes it play if it is paused. +\end{methoddesc} + + +\subsection{Parser Objects} +\label{cd-parser-objects} + +Parser objects (returned by \function{createparser()}) have the +following methods: + +\begin{methoddesc}[CD parser]{addcallback}{type, func, arg} +Adds a callback for the parser. The parser has callbacks for eight +different types of data in the digital audio data stream. Constants +for these types are defined at the \module{cd} module level (see above). +The callback is called as follows: \code{\var{func}(\var{arg}, type, +data)}, where \var{arg} is the user supplied argument, \var{type} is +the particular type of callback, and \var{data} is the data returned +for this \var{type} of callback. The type of the data depends on the +\var{type} of callback as follows: + +\begin{tableii}{l|p{4in}}{code}{Type}{Value} + \lineii{audio}{String which can be passed unmodified to +\function{al.writesamps()}.} + \lineii{pnum}{Integer giving the program (track) number.} + \lineii{index}{Integer giving the index number.} + \lineii{ptime}{Tuple consisting of the program time in minutes, +seconds, and frames.} + \lineii{atime}{Tuple consisting of the absolute time in minutes, +seconds, and frames.} + \lineii{catalog}{String of 13 characters, giving the catalog number +of the CD.} + \lineii{ident}{String of 12 characters, giving the ISRC +identification number of the recording. The string consists of two +characters country code, three characters owner code, two characters +giving the year, and five characters giving a serial number.} + \lineii{control}{Integer giving the control bits from the CD +subcode data} +\end{tableii} +\end{methoddesc} + +\begin{methoddesc}[CD parser]{deleteparser}{} +Deletes the parser and frees the memory it was using. The object +should not be used after this call. This call is done automatically +when the last reference to the object is removed. +\end{methoddesc} + +\begin{methoddesc}[CD parser]{parseframe}{frame} +Parses one or more frames of digital audio data from a CD such as +returned by \method{readda()}. It determines which subcodes are +present in the data. If these subcodes have changed since the last +frame, then \method{parseframe()} executes a callback of the +appropriate type passing to it the subcode data found in the frame. +Unlike the \C{} function, more than one frame of digital audio data +can be passed to this method. +\end{methoddesc} + +\begin{methoddesc}[CD parser]{removecallback}{type} +Removes the callback for the given \var{type}. +\end{methoddesc} + +\begin{methoddesc}[CD parser]{resetparser}{} +Resets the fields of the parser used for tracking subcodes to an +initial state. \method{resetparser()} should be called after the disc +has been changed. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libcfgparser.tex b/sys/src/cmd/python/Doc/lib/libcfgparser.tex new file mode 100644 index 000000000..42a362eac --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcfgparser.tex @@ -0,0 +1,313 @@ +\section{\module{ConfigParser} --- + Configuration file parser} + +\declaremodule{standard}{ConfigParser} +\modulesynopsis{Configuration file parser.} +\moduleauthor{Ken Manheimer}{klm@zope.com} +\moduleauthor{Barry Warsaw}{bwarsaw@python.org} +\moduleauthor{Eric S. Raymond}{esr@thyrsus.com} +\sectionauthor{Christopher G. Petrilli}{petrilli@amber.org} + +This module defines the class \class{ConfigParser}. +\indexii{.ini}{file}\indexii{configuration}{file}\index{ini file} +\index{Windows ini file} +The \class{ConfigParser} class implements a basic configuration file +parser language which provides a structure similar to what you would +find on Microsoft Windows INI files. You can use this to write Python +programs which can be customized by end users easily. + +\begin{notice}[warning] + This library does \emph{not} interpret or write the value-type + prefixes used in the Windows Registry extended version of INI syntax. +\end{notice} + +The configuration file consists of sections, led by a +\samp{[section]} header and followed by \samp{name: value} entries, +with continuations in the style of \rfc{822}; \samp{name=value} is +also accepted. Note that leading whitespace is removed from values. +The optional values can contain format strings which refer to other +values in the same section, or values in a special +\code{DEFAULT} section. Additional defaults can be provided on +initialization and retrieval. Lines beginning with \character{\#} or +\character{;} are ignored and may be used to provide comments. + +For example: + +\begin{verbatim} +[My Section] +foodir: %(dir)s/whatever +dir=frob +\end{verbatim} + +would resolve the \samp{\%(dir)s} to the value of +\samp{dir} (\samp{frob} in this case). All reference expansions are +done on demand. + +Default values can be specified by passing them into the +\class{ConfigParser} constructor as a dictionary. Additional defaults +may be passed into the \method{get()} method which will override all +others. + +\begin{classdesc}{RawConfigParser}{\optional{defaults}} +The basic configuration object. When \var{defaults} is given, it is +initialized into the dictionary of intrinsic defaults. This class +does not support the magical interpolation behavior. +\versionadded{2.3} +\end{classdesc} + +\begin{classdesc}{ConfigParser}{\optional{defaults}} +Derived class of \class{RawConfigParser} that implements the magical +interpolation feature and adds optional arguments to the \method{get()} +and \method{items()} methods. The values in \var{defaults} must be +appropriate for the \samp{\%()s} string interpolation. Note that +\var{__name__} is an intrinsic default; its value is the section name, +and will override any value provided in \var{defaults}. + +All option names used in interpolation will be passed through the +\method{optionxform()} method just like any other option name +reference. For example, using the default implementation of +\method{optionxform()} (which converts option names to lower case), +the values \samp{foo \%(bar)s} and \samp{foo \%(BAR)s} are +equivalent. +\end{classdesc} + +\begin{classdesc}{SafeConfigParser}{\optional{defaults}} +Derived class of \class{ConfigParser} that implements a more-sane +variant of the magical interpolation feature. This implementation is +more predictable as well. +% XXX Need to explain what's safer/more predictable about it. +New applications should prefer this version if they don't need to be +compatible with older versions of Python. +\versionadded{2.3} +\end{classdesc} + +\begin{excdesc}{NoSectionError} +Exception raised when a specified section is not found. +\end{excdesc} + +\begin{excdesc}{DuplicateSectionError} +Exception raised if \method{add_section()} is called with the name of +a section that is already present. +\end{excdesc} + +\begin{excdesc}{NoOptionError} +Exception raised when a specified option is not found in the specified +section. +\end{excdesc} + +\begin{excdesc}{InterpolationError} +Base class for exceptions raised when problems occur performing string +interpolation. +\end{excdesc} + +\begin{excdesc}{InterpolationDepthError} +Exception raised when string interpolation cannot be completed because +the number of iterations exceeds \constant{MAX_INTERPOLATION_DEPTH}. +Subclass of \exception{InterpolationError}. +\end{excdesc} + +\begin{excdesc}{InterpolationMissingOptionError} +Exception raised when an option referenced from a value does not exist. +Subclass of \exception{InterpolationError}. +\versionadded{2.3} +\end{excdesc} + +\begin{excdesc}{InterpolationSyntaxError} +Exception raised when the source text into which substitutions are +made does not conform to the required syntax. +Subclass of \exception{InterpolationError}. +\versionadded{2.3} +\end{excdesc} + +\begin{excdesc}{MissingSectionHeaderError} +Exception raised when attempting to parse a file which has no section +headers. +\end{excdesc} + +\begin{excdesc}{ParsingError} +Exception raised when errors occur attempting to parse a file. +\end{excdesc} + +\begin{datadesc}{MAX_INTERPOLATION_DEPTH} +The maximum depth for recursive interpolation for \method{get()} when +the \var{raw} parameter is false. This is relevant only for the +\class{ConfigParser} class. +\end{datadesc} + + +\begin{seealso} + \seemodule{shlex}{Support for a creating \UNIX{} shell-like + mini-languages which can be used as an alternate + format for application configuration files.} +\end{seealso} + + +\subsection{RawConfigParser Objects \label{RawConfigParser-objects}} + +\class{RawConfigParser} instances have the following methods: + +\begin{methoddesc}{defaults}{} +Return a dictionary containing the instance-wide defaults. +\end{methoddesc} + +\begin{methoddesc}{sections}{} +Return a list of the sections available; \code{DEFAULT} is not +included in the list. +\end{methoddesc} + +\begin{methoddesc}{add_section}{section} +Add a section named \var{section} to the instance. If a section by +the given name already exists, \exception{DuplicateSectionError} is +raised. +\end{methoddesc} + +\begin{methoddesc}{has_section}{section} +Indicates whether the named section is present in the +configuration. The \code{DEFAULT} section is not acknowledged. +\end{methoddesc} + +\begin{methoddesc}{options}{section} +Returns a list of options available in the specified \var{section}. +\end{methoddesc} + +\begin{methoddesc}{has_option}{section, option} +If the given section exists, and contains the given option, +return \constant{True}; otherwise return \constant{False}. +\versionadded{1.6} +\end{methoddesc} + +\begin{methoddesc}{read}{filenames} +Attempt to read and parse a list of filenames, returning a list of filenames +which were successfully parsed. If \var{filenames} is a string or +Unicode string, it is treated as a single filename. +If a file named in \var{filenames} cannot be opened, that file will be +ignored. This is designed so that you can specify a list of potential +configuration file locations (for example, the current directory, the +user's home directory, and some system-wide directory), and all +existing configuration files in the list will be read. If none of the +named files exist, the \class{ConfigParser} instance will contain an +empty dataset. An application which requires initial values to be +loaded from a file should load the required file or files using +\method{readfp()} before calling \method{read()} for any optional +files: + +\begin{verbatim} +import ConfigParser, os + +config = ConfigParser.ConfigParser() +config.readfp(open('defaults.cfg')) +config.read(['site.cfg', os.path.expanduser('~/.myapp.cfg')]) +\end{verbatim} +\versionchanged[Returns list of successfully parsed filenames]{2.4} +\end{methoddesc} + +\begin{methoddesc}{readfp}{fp\optional{, filename}} +Read and parse configuration data from the file or file-like object in +\var{fp} (only the \method{readline()} method is used). If +\var{filename} is omitted and \var{fp} has a \member{name} attribute, +that is used for \var{filename}; the default is \samp{}. +\end{methoddesc} + +\begin{methoddesc}{get}{section, option} +Get an \var{option} value for the named \var{section}. +\end{methoddesc} + +\begin{methoddesc}{getint}{section, option} +A convenience method which coerces the \var{option} in the specified +\var{section} to an integer. +\end{methoddesc} + +\begin{methoddesc}{getfloat}{section, option} +A convenience method which coerces the \var{option} in the specified +\var{section} to a floating point number. +\end{methoddesc} + +\begin{methoddesc}{getboolean}{section, option} +A convenience method which coerces the \var{option} in the specified +\var{section} to a Boolean value. Note that the accepted values +for the option are \code{"1"}, \code{"yes"}, \code{"true"}, and \code{"on"}, +which cause this method to return \code{True}, and \code{"0"}, \code{"no"}, +\code{"false"}, and \code{"off"}, which cause it to return \code{False}. These +string values are checked in a case-insensitive manner. Any other value will +cause it to raise \exception{ValueError}. +\end{methoddesc} + +\begin{methoddesc}{items}{section} +Return a list of \code{(\var{name}, \var{value})} pairs for each +option in the given \var{section}. +\end{methoddesc} + +\begin{methoddesc}{set}{section, option, value} +If the given section exists, set the given option to the specified +value; otherwise raise \exception{NoSectionError}. While it is +possible to use \class{RawConfigParser} (or \class{ConfigParser} with +\var{raw} parameters set to true) for \emph{internal} storage of +non-string values, full functionality (including interpolation and +output to files) can only be achieved using string values. +\versionadded{1.6} +\end{methoddesc} + +\begin{methoddesc}{write}{fileobject} +Write a representation of the configuration to the specified file +object. This representation can be parsed by a future \method{read()} +call. +\versionadded{1.6} +\end{methoddesc} + +\begin{methoddesc}{remove_option}{section, option} +Remove the specified \var{option} from the specified \var{section}. +If the section does not exist, raise \exception{NoSectionError}. +If the option existed to be removed, return \constant{True}; +otherwise return \constant{False}. +\versionadded{1.6} +\end{methoddesc} + +\begin{methoddesc}{remove_section}{section} +Remove the specified \var{section} from the configuration. +If the section in fact existed, return \code{True}. +Otherwise return \code{False}. +\end{methoddesc} + +\begin{methoddesc}{optionxform}{option} +Transforms the option name \var{option} as found in an input file or +as passed in by client code to the form that should be used in the +internal structures. The default implementation returns a lower-case +version of \var{option}; subclasses may override this or client code +can set an attribute of this name on instances to affect this +behavior. Setting this to \function{str()}, for example, would make +option names case sensitive. +\end{methoddesc} + + +\subsection{ConfigParser Objects \label{ConfigParser-objects}} + +The \class{ConfigParser} class extends some methods of the +\class{RawConfigParser} interface, adding some optional arguments. + +\begin{methoddesc}{get}{section, option\optional{, raw\optional{, vars}}} +Get an \var{option} value for the named \var{section}. All the +\character{\%} interpolations are expanded in the return values, based +on the defaults passed into the constructor, as well as the options +\var{vars} provided, unless the \var{raw} argument is true. +\end{methoddesc} + +\begin{methoddesc}{items}{section\optional{, raw\optional{, vars}}} +Return a list of \code{(\var{name}, \var{value})} pairs for each +option in the given \var{section}. Optional arguments have the +same meaning as for the \method{get()} method. +\versionadded{2.3} +\end{methoddesc} + + +\subsection{SafeConfigParser Objects \label{SafeConfigParser-objects}} + +The \class{SafeConfigParser} class implements the same extended +interface as \class{ConfigParser}, with the following addition: + +\begin{methoddesc}{set}{section, option, value} +If the given section exists, set the given option to the specified +value; otherwise raise \exception{NoSectionError}. \var{value} must +be a string (\class{str} or \class{unicode}); if not, +\exception{TypeError} is raised. +\versionadded{2.4} +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libcgi.tex b/sys/src/cmd/python/Doc/lib/libcgi.tex new file mode 100644 index 000000000..1dd7e03f3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcgi.tex @@ -0,0 +1,602 @@ +\section{\module{cgi} --- + Common Gateway Interface support.} +\declaremodule{standard}{cgi} + +\modulesynopsis{Common Gateway Interface support, used to interpret +forms in server-side scripts.} + +\indexii{WWW}{server} +\indexii{CGI}{protocol} +\indexii{HTTP}{protocol} +\indexii{MIME}{headers} +\index{URL} + + +Support module for Common Gateway Interface (CGI) scripts.% +\index{Common Gateway Interface} + +This module defines a number of utilities for use by CGI scripts +written in Python. + +\subsection{Introduction} +\nodename{cgi-intro} + +A CGI script is invoked by an HTTP server, usually to process user +input submitted through an HTML \code{
} or \code{} element. + +Most often, CGI scripts live in the server's special \file{cgi-bin} +directory. The HTTP server places all sorts of information about the +request (such as the client's hostname, the requested URL, the query +string, and lots of other goodies) in the script's shell environment, +executes the script, and sends the script's output back to the client. + +The script's input is connected to the client too, and sometimes the +form data is read this way; at other times the form data is passed via +the ``query string'' part of the URL. This module is intended +to take care of the different cases and provide a simpler interface to +the Python script. It also provides a number of utilities that help +in debugging scripts, and the latest addition is support for file +uploads from a form (if your browser supports it). + +The output of a CGI script should consist of two sections, separated +by a blank line. The first section contains a number of headers, +telling the client what kind of data is following. Python code to +generate a minimal header section looks like this: + +\begin{verbatim} +print "Content-Type: text/html" # HTML is following +print # blank line, end of headers +\end{verbatim} + +The second section is usually HTML, which allows the client software +to display nicely formatted text with header, in-line images, etc. +Here's Python code that prints a simple piece of HTML: + +\begin{verbatim} +print "CGI script output" +print "

This is my first CGI script

" +print "Hello, world!" +\end{verbatim} + +\subsection{Using the cgi module} +\nodename{Using the cgi module} + +Begin by writing \samp{import cgi}. Do not use \samp{from cgi import +*} --- the module defines all sorts of names for its own use or for +backward compatibility that you don't want in your namespace. + +When you write a new script, consider adding the line: + +\begin{verbatim} +import cgitb; cgitb.enable() +\end{verbatim} + +This activates a special exception handler that will display detailed +reports in the Web browser if any errors occur. If you'd rather not +show the guts of your program to users of your script, you can have +the reports saved to files instead, with a line like this: + +\begin{verbatim} +import cgitb; cgitb.enable(display=0, logdir="/tmp") +\end{verbatim} + +It's very helpful to use this feature during script development. +The reports produced by \refmodule{cgitb} provide information that +can save you a lot of time in tracking down bugs. You can always +remove the \code{cgitb} line later when you have tested your script +and are confident that it works correctly. + +To get at submitted form data, +it's best to use the \class{FieldStorage} class. The other classes +defined in this module are provided mostly for backward compatibility. +Instantiate it exactly once, without arguments. This reads the form +contents from standard input or the environment (depending on the +value of various environment variables set according to the CGI +standard). Since it may consume standard input, it should be +instantiated only once. + +The \class{FieldStorage} instance can be indexed like a Python +dictionary, and also supports the standard dictionary methods +\method{has_key()} and \method{keys()}. The built-in \function{len()} +is also supported. Form fields containing empty strings are ignored +and do not appear in the dictionary; to keep such values, provide +a true value for the optional \var{keep_blank_values} keyword +parameter when creating the \class{FieldStorage} instance. + +For instance, the following code (which assumes that the +\mailheader{Content-Type} header and blank line have already been +printed) checks that the fields \code{name} and \code{addr} are both +set to a non-empty string: + +\begin{verbatim} +form = cgi.FieldStorage() +if not (form.has_key("name") and form.has_key("addr")): + print "

Error

" + print "Please fill in the name and addr fields." + return +print "

name:", form["name"].value +print "

addr:", form["addr"].value +...further form processing here... +\end{verbatim} + +Here the fields, accessed through \samp{form[\var{key}]}, are +themselves instances of \class{FieldStorage} (or +\class{MiniFieldStorage}, depending on the form encoding). +The \member{value} attribute of the instance yields the string value +of the field. The \method{getvalue()} method returns this string value +directly; it also accepts an optional second argument as a default to +return if the requested key is not present. + +If the submitted form data contains more than one field with the same +name, the object retrieved by \samp{form[\var{key}]} is not a +\class{FieldStorage} or \class{MiniFieldStorage} +instance but a list of such instances. Similarly, in this situation, +\samp{form.getvalue(\var{key})} would return a list of strings. +If you expect this possibility +(when your HTML form contains multiple fields with the same name), use +the \function{getlist()} function, which always returns a list of values (so that you +do not need to special-case the single item case). For example, this +code concatenates any number of username fields, separated by +commas: + +\begin{verbatim} +value = form.getlist("username") +usernames = ",".join(value) +\end{verbatim} + +If a field represents an uploaded file, accessing the value via the +\member{value} attribute or the \function{getvalue()} method reads the +entire file in memory as a string. This may not be what you want. +You can test for an uploaded file by testing either the \member{filename} +attribute or the \member{file} attribute. You can then read the data at +leisure from the \member{file} attribute: + +\begin{verbatim} +fileitem = form["userfile"] +if fileitem.file: + # It's an uploaded file; count lines + linecount = 0 + while 1: + line = fileitem.file.readline() + if not line: break + linecount = linecount + 1 +\end{verbatim} + +The file upload draft standard entertains the possibility of uploading +multiple files from one field (using a recursive +\mimetype{multipart/*} encoding). When this occurs, the item will be +a dictionary-like \class{FieldStorage} item. This can be determined +by testing its \member{type} attribute, which should be +\mimetype{multipart/form-data} (or perhaps another MIME type matching +\mimetype{multipart/*}). In this case, it can be iterated over +recursively just like the top-level form object. + +When a form is submitted in the ``old'' format (as the query string or +as a single data part of type +\mimetype{application/x-www-form-urlencoded}), the items will actually +be instances of the class \class{MiniFieldStorage}. In this case, the +\member{list}, \member{file}, and \member{filename} attributes are +always \code{None}. + + +\subsection{Higher Level Interface} + +\versionadded{2.2} % XXX: Is this true ? + +The previous section explains how to read CGI form data using the +\class{FieldStorage} class. This section describes a higher level +interface which was added to this class to allow one to do it in a +more readable and intuitive way. The interface doesn't make the +techniques described in previous sections obsolete --- they are still +useful to process file uploads efficiently, for example. + +The interface consists of two simple methods. Using the methods +you can process form data in a generic way, without the need to worry +whether only one or more values were posted under one name. + +In the previous section, you learned to write following code anytime +you expected a user to post more than one value under one name: + +\begin{verbatim} +item = form.getvalue("item") +if isinstance(item, list): + # The user is requesting more than one item. +else: + # The user is requesting only one item. +\end{verbatim} + +This situation is common for example when a form contains a group of +multiple checkboxes with the same name: + +\begin{verbatim} + + +\end{verbatim} + +In most situations, however, there's only one form control with a +particular name in a form and then you expect and need only one value +associated with this name. So you write a script containing for +example this code: + +\begin{verbatim} +user = form.getvalue("user").upper() +\end{verbatim} + +The problem with the code is that you should never expect that a +client will provide valid input to your scripts. For example, if a +curious user appends another \samp{user=foo} pair to the query string, +then the script would crash, because in this situation the +\code{getvalue("user")} method call returns a list instead of a +string. Calling the \method{toupper()} method on a list is not valid +(since lists do not have a method of this name) and results in an +\exception{AttributeError} exception. + +Therefore, the appropriate way to read form data values was to always +use the code which checks whether the obtained value is a single value +or a list of values. That's annoying and leads to less readable +scripts. + +A more convenient approach is to use the methods \method{getfirst()} +and \method{getlist()} provided by this higher level interface. + +\begin{methoddesc}[FieldStorage]{getfirst}{name\optional{, default}} + This method always returns only one value associated with form field + \var{name}. The method returns only the first value in case that + more values were posted under such name. Please note that the order + in which the values are received may vary from browser to browser + and should not be counted on.\footnote{Note that some recent + versions of the HTML specification do state what order the + field values should be supplied in, but knowing whether a + request was received from a conforming browser, or even from a + browser at all, is tedious and error-prone.} If no such form + field or value exists then the method returns the value specified by + the optional parameter \var{default}. This parameter defaults to + \code{None} if not specified. +\end{methoddesc} + +\begin{methoddesc}[FieldStorage]{getlist}{name} + This method always returns a list of values associated with form + field \var{name}. The method returns an empty list if no such form + field or value exists for \var{name}. It returns a list consisting + of one item if only one such value exists. +\end{methoddesc} + +Using these methods you can write nice compact code: + +\begin{verbatim} +import cgi +form = cgi.FieldStorage() +user = form.getfirst("user", "").upper() # This way it's safe. +for item in form.getlist("item"): + do_something(item) +\end{verbatim} + + +\subsection{Old classes} + +These classes, present in earlier versions of the \module{cgi} module, +are still supported for backward compatibility. New applications +should use the \class{FieldStorage} class. + +\class{SvFormContentDict} stores single value form content as +dictionary; it assumes each field name occurs in the form only once. + +\class{FormContentDict} stores multiple value form content as a +dictionary (the form items are lists of values). Useful if your form +contains multiple fields with the same name. + +Other classes (\class{FormContent}, \class{InterpFormContentDict}) are +present for backwards compatibility with really old applications only. +If you still use these and would be inconvenienced when they +disappeared from a next version of this module, drop me a note. + + +\subsection{Functions} +\nodename{Functions in cgi module} + +These are useful if you want more control, or if you want to employ +some of the algorithms implemented in this module in other +circumstances. + +\begin{funcdesc}{parse}{fp\optional{, keep_blank_values\optional{, + strict_parsing}}} + Parse a query in the environment or from a file (the file defaults + to \code{sys.stdin}). The \var{keep_blank_values} and + \var{strict_parsing} parameters are passed to \function{parse_qs()} + unchanged. +\end{funcdesc} + +\begin{funcdesc}{parse_qs}{qs\optional{, keep_blank_values\optional{, + strict_parsing}}} +Parse a query string given as a string argument (data of type +\mimetype{application/x-www-form-urlencoded}). Data are +returned as a dictionary. The dictionary keys are the unique query +variable names and the values are lists of values for each name. + +The optional argument \var{keep_blank_values} is +a flag indicating whether blank values in +URL encoded queries should be treated as blank strings. +A true value indicates that blanks should be retained as +blank strings. The default false value indicates that +blank values are to be ignored and treated as if they were +not included. + +The optional argument \var{strict_parsing} is a flag indicating what +to do with parsing errors. If false (the default), errors +are silently ignored. If true, errors raise a \exception{ValueError} +exception. + +Use the \function{\refmodule{urllib}.urlencode()} function to convert +such dictionaries into query strings. + +\end{funcdesc} + +\begin{funcdesc}{parse_qsl}{qs\optional{, keep_blank_values\optional{, + strict_parsing}}} +Parse a query string given as a string argument (data of type +\mimetype{application/x-www-form-urlencoded}). Data are +returned as a list of name, value pairs. + +The optional argument \var{keep_blank_values} is +a flag indicating whether blank values in +URL encoded queries should be treated as blank strings. +A true value indicates that blanks should be retained as +blank strings. The default false value indicates that +blank values are to be ignored and treated as if they were +not included. + +The optional argument \var{strict_parsing} is a flag indicating what +to do with parsing errors. If false (the default), errors +are silently ignored. If true, errors raise a \exception{ValueError} +exception. + +Use the \function{\refmodule{urllib}.urlencode()} function to convert +such lists of pairs into query strings. +\end{funcdesc} + +\begin{funcdesc}{parse_multipart}{fp, pdict} +Parse input of type \mimetype{multipart/form-data} (for +file uploads). Arguments are \var{fp} for the input file and +\var{pdict} for a dictionary containing other parameters in +the \mailheader{Content-Type} header. + +Returns a dictionary just like \function{parse_qs()} keys are the +field names, each value is a list of values for that field. This is +easy to use but not much good if you are expecting megabytes to be +uploaded --- in that case, use the \class{FieldStorage} class instead +which is much more flexible. + +Note that this does not parse nested multipart parts --- use +\class{FieldStorage} for that. +\end{funcdesc} + +\begin{funcdesc}{parse_header}{string} +Parse a MIME header (such as \mailheader{Content-Type}) into a main +value and a dictionary of parameters. +\end{funcdesc} + +\begin{funcdesc}{test}{} +Robust test CGI script, usable as main program. +Writes minimal HTTP headers and formats all information provided to +the script in HTML form. +\end{funcdesc} + +\begin{funcdesc}{print_environ}{} +Format the shell environment in HTML. +\end{funcdesc} + +\begin{funcdesc}{print_form}{form} +Format a form in HTML. +\end{funcdesc} + +\begin{funcdesc}{print_directory}{} +Format the current directory in HTML. +\end{funcdesc} + +\begin{funcdesc}{print_environ_usage}{} +Print a list of useful (used by CGI) environment variables in +HTML. +\end{funcdesc} + +\begin{funcdesc}{escape}{s\optional{, quote}} +Convert the characters +\character{\&}, \character{<} and \character{>} in string \var{s} to +HTML-safe sequences. Use this if you need to display text that might +contain such characters in HTML. If the optional flag \var{quote} is +true, the quotation mark character (\character{"}) is also translated; +this helps for inclusion in an HTML attribute value, as in \code{}. If the value to be quoted might include single- or +double-quote characters, or both, consider using the +\function{quoteattr()} function in the \refmodule{xml.sax.saxutils} +module instead. +\end{funcdesc} + + +\subsection{Caring about security \label{cgi-security}} + +\indexii{CGI}{security} + +There's one important rule: if you invoke an external program (via the +\function{os.system()} or \function{os.popen()} functions. or others +with similar functionality), make very sure you don't pass arbitrary +strings received from the client to the shell. This is a well-known +security hole whereby clever hackers anywhere on the Web can exploit a +gullible CGI script to invoke arbitrary shell commands. Even parts of +the URL or field names cannot be trusted, since the request doesn't +have to come from your form! + +To be on the safe side, if you must pass a string gotten from a form +to a shell command, you should make sure the string contains only +alphanumeric characters, dashes, underscores, and periods. + + +\subsection{Installing your CGI script on a \UNIX\ system} + +Read the documentation for your HTTP server and check with your local +system administrator to find the directory where CGI scripts should be +installed; usually this is in a directory \file{cgi-bin} in the server tree. + +Make sure that your script is readable and executable by ``others''; the +\UNIX{} file mode should be \code{0755} octal (use \samp{chmod 0755 +\var{filename}}). Make sure that the first line of the script contains +\code{\#!} starting in column 1 followed by the pathname of the Python +interpreter, for instance: + +\begin{verbatim} +#!/usr/local/bin/python +\end{verbatim} + +Make sure the Python interpreter exists and is executable by ``others''. + +Make sure that any files your script needs to read or write are +readable or writable, respectively, by ``others'' --- their mode +should be \code{0644} for readable and \code{0666} for writable. This +is because, for security reasons, the HTTP server executes your script +as user ``nobody'', without any special privileges. It can only read +(write, execute) files that everybody can read (write, execute). The +current directory at execution time is also different (it is usually +the server's cgi-bin directory) and the set of environment variables +is also different from what you get when you log in. In particular, don't +count on the shell's search path for executables (\envvar{PATH}) or +the Python module search path (\envvar{PYTHONPATH}) to be set to +anything interesting. + +If you need to load modules from a directory which is not on Python's +default module search path, you can change the path in your script, +before importing other modules. For example: + +\begin{verbatim} +import sys +sys.path.insert(0, "/usr/home/joe/lib/python") +sys.path.insert(0, "/usr/local/lib/python") +\end{verbatim} + +(This way, the directory inserted last will be searched first!) + +Instructions for non-\UNIX{} systems will vary; check your HTTP server's +documentation (it will usually have a section on CGI scripts). + + +\subsection{Testing your CGI script} + +Unfortunately, a CGI script will generally not run when you try it +from the command line, and a script that works perfectly from the +command line may fail mysteriously when run from the server. There's +one reason why you should still test your script from the command +line: if it contains a syntax error, the Python interpreter won't +execute it at all, and the HTTP server will most likely send a cryptic +error to the client. + +Assuming your script has no syntax errors, yet it does not work, you +have no choice but to read the next section. + + +\subsection{Debugging CGI scripts} \indexii{CGI}{debugging} + +First of all, check for trivial installation errors --- reading the +section above on installing your CGI script carefully can save you a +lot of time. If you wonder whether you have understood the +installation procedure correctly, try installing a copy of this module +file (\file{cgi.py}) as a CGI script. When invoked as a script, the file +will dump its environment and the contents of the form in HTML form. +Give it the right mode etc, and send it a request. If it's installed +in the standard \file{cgi-bin} directory, it should be possible to send it a +request by entering a URL into your browser of the form: + +\begin{verbatim} +http://yourhostname/cgi-bin/cgi.py?name=Joe+Blow&addr=At+Home +\end{verbatim} + +If this gives an error of type 404, the server cannot find the script +-- perhaps you need to install it in a different directory. If it +gives another error, there's an installation problem that +you should fix before trying to go any further. If you get a nicely +formatted listing of the environment and form content (in this +example, the fields should be listed as ``addr'' with value ``At Home'' +and ``name'' with value ``Joe Blow''), the \file{cgi.py} script has been +installed correctly. If you follow the same procedure for your own +script, you should now be able to debug it. + +The next step could be to call the \module{cgi} module's +\function{test()} function from your script: replace its main code +with the single statement + +\begin{verbatim} +cgi.test() +\end{verbatim} + +This should produce the same results as those gotten from installing +the \file{cgi.py} file itself. + +When an ordinary Python script raises an unhandled exception (for +whatever reason: of a typo in a module name, a file that can't be +opened, etc.), the Python interpreter prints a nice traceback and +exits. While the Python interpreter will still do this when your CGI +script raises an exception, most likely the traceback will end up in +one of the HTTP server's log files, or be discarded altogether. + +Fortunately, once you have managed to get your script to execute +\emph{some} code, you can easily send tracebacks to the Web browser +using the \refmodule{cgitb} module. If you haven't done so already, +just add the line: + +\begin{verbatim} +import cgitb; cgitb.enable() +\end{verbatim} + +to the top of your script. Then try running it again; when a +problem occurs, you should see a detailed report that will +likely make apparent the cause of the crash. + +If you suspect that there may be a problem in importing the +\refmodule{cgitb} module, you can use an even more robust approach +(which only uses built-in modules): + +\begin{verbatim} +import sys +sys.stderr = sys.stdout +print "Content-Type: text/plain" +print +...your code here... +\end{verbatim} + +This relies on the Python interpreter to print the traceback. The +content type of the output is set to plain text, which disables all +HTML processing. If your script works, the raw HTML will be displayed +by your client. If it raises an exception, most likely after the +first two lines have been printed, a traceback will be displayed. +Because no HTML interpretation is going on, the traceback will be +readable. + + +\subsection{Common problems and solutions} + +\begin{itemize} +\item Most HTTP servers buffer the output from CGI scripts until the +script is completed. This means that it is not possible to display a +progress report on the client's display while the script is running. + +\item Check the installation instructions above. + +\item Check the HTTP server's log files. (\samp{tail -f logfile} in a +separate window may be useful!) + +\item Always check a script for syntax errors first, by doing something +like \samp{python script.py}. + +\item If your script does not have any syntax errors, try adding +\samp{import cgitb; cgitb.enable()} to the top of the script. + +\item When invoking external programs, make sure they can be found. +Usually, this means using absolute path names --- \envvar{PATH} is +usually not set to a very useful value in a CGI script. + +\item When reading or writing external files, make sure they can be read +or written by the userid under which your CGI script will be running: +this is typically the userid under which the web server is running, or some +explicitly specified userid for a web server's \samp{suexec} feature. + +\item Don't try to give a CGI script a set-uid mode. This doesn't work on +most systems, and is a security liability as well. +\end{itemize} + diff --git a/sys/src/cmd/python/Doc/lib/libcgihttp.tex b/sys/src/cmd/python/Doc/lib/libcgihttp.tex new file mode 100644 index 000000000..df0728e3f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcgihttp.tex @@ -0,0 +1,70 @@ +\section{\module{CGIHTTPServer} --- + CGI-capable HTTP request handler} + + +\declaremodule{standard}{CGIHTTPServer} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{This module provides a request handler for HTTP servers + which can run CGI scripts.} + + +The \module{CGIHTTPServer} module defines a request-handler class, +interface compatible with +\class{BaseHTTPServer.BaseHTTPRequestHandler} and inherits behavior +from \class{SimpleHTTPServer.SimpleHTTPRequestHandler} but can also +run CGI scripts. + +\note{This module can run CGI scripts on \UNIX{} and Windows systems; +on Mac OS it will only be able to run Python scripts within the same +process as itself.} + +\note{CGI scripts run by the \class{CGIHTTPRequestHandler} class cannot execute +redirects (HTTP code 302), because code 200 (script output follows) +is sent prior to execution of the CGI script. This pre-empts the status +code.} + +The \module{CGIHTTPServer} module defines the following class: + +\begin{classdesc}{CGIHTTPRequestHandler}{request, client_address, server} +This class is used to serve either files or output of CGI scripts from +the current directory and below. Note that mapping HTTP hierarchic +structure to local directory structure is exactly as in +\class{SimpleHTTPServer.SimpleHTTPRequestHandler}. + +The class will however, run the CGI script, instead of serving it as a +file, if it guesses it to be a CGI script. Only directory-based CGI +are used --- the other common server configuration is to treat special +extensions as denoting CGI scripts. + +The \function{do_GET()} and \function{do_HEAD()} functions are +modified to run CGI scripts and serve the output, instead of serving +files, if the request leads to somewhere below the +\code{cgi_directories} path. +\end{classdesc} + +The \class{CGIHTTPRequestHandler} defines the following data member: + +\begin{memberdesc}{cgi_directories} +This defaults to \code{['/cgi-bin', '/htbin']} and describes +directories to treat as containing CGI scripts. +\end{memberdesc} + +The \class{CGIHTTPRequestHandler} defines the following methods: + +\begin{methoddesc}{do_POST}{} +This method serves the \code{'POST'} request type, only allowed for +CGI scripts. Error 501, "Can only POST to CGI scripts", is output +when trying to POST to a non-CGI url. +\end{methoddesc} + +Note that CGI scripts will be run with UID of user nobody, for security +reasons. Problems with the CGI script will be translated to error 403. + +For example usage, see the implementation of the \function{test()} +function. + + +\begin{seealso} + \seemodule{BaseHTTPServer}{Base class implementation for Web server + and request handler.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libcgitb.tex b/sys/src/cmd/python/Doc/lib/libcgitb.tex new file mode 100644 index 000000000..c686fe6a6 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcgitb.tex @@ -0,0 +1,67 @@ +\section{\module{cgitb} --- + Traceback manager for CGI scripts} + +\declaremodule{standard}{cgitb} +\modulesynopsis{Configurable traceback handler for CGI scripts.} +\moduleauthor{Ka-Ping Yee}{ping@lfw.org} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +\versionadded{2.2} +\index{CGI!exceptions} +\index{CGI!tracebacks} +\index{exceptions!in CGI scripts} +\index{tracebacks!in CGI scripts} + +The \module{cgitb} module provides a special exception handler for Python +scripts. (Its name is a bit misleading. It was originally designed to +display extensive traceback information in HTML for CGI scripts. It was +later generalized to also display this information in plain text.) After +this module is activated, if an uncaught exception occurs, a detailed, +formatted report will be displayed. The report +includes a traceback showing excerpts of the source code for each level, +as well as the values of the arguments and local variables to currently +running functions, to help you debug the problem. Optionally, you can +save this information to a file instead of sending it to the browser. + +To enable this feature, simply add one line to the top of your CGI script: + +\begin{verbatim} +import cgitb; cgitb.enable() +\end{verbatim} + +The options to the \function{enable()} function control whether the +report is displayed in the browser and whether the report is logged +to a file for later analysis. + + +\begin{funcdesc}{enable}{\optional{display\optional{, logdir\optional{, + context\optional{, format}}}}} + This function causes the \module{cgitb} module to take over the + interpreter's default handling for exceptions by setting the + value of \code{\refmodule{sys}.excepthook}. + \withsubitem{(in module sys)}{\ttindex{excepthook()}} + + The optional argument \var{display} defaults to \code{1} and can be set + to \code{0} to suppress sending the traceback to the browser. + If the argument \var{logdir} is present, the traceback reports are + written to files. The value of \var{logdir} should be a directory + where these files will be placed. + The optional argument \var{context} is the number of lines of + context to display around the current line of source code in the + traceback; this defaults to \code{5}. + If the optional argument \var{format} is \code{"html"}, the output is + formatted as HTML. Any other value forces plain text output. The default + value is \code{"html"}. +\end{funcdesc} + +\begin{funcdesc}{handler}{\optional{info}} + This function handles an exception using the default settings + (that is, show a report in the browser, but don't log to a file). + This can be used when you've caught an exception and want to + report it using \module{cgitb}. The optional \var{info} argument + should be a 3-tuple containing an exception type, exception + value, and traceback object, exactly like the tuple returned by + \code{\refmodule{sys}.exc_info()}. If the \var{info} argument + is not supplied, the current exception is obtained from + \code{\refmodule{sys}.exc_info()}. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libchunk.tex b/sys/src/cmd/python/Doc/lib/libchunk.tex new file mode 100644 index 000000000..8e2a4947f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libchunk.tex @@ -0,0 +1,111 @@ +\section{\module{chunk} --- + Read IFF chunked data} + +\declaremodule{standard}{chunk} +\modulesynopsis{Module to read IFF chunks.} +\moduleauthor{Sjoerd Mullender}{sjoerd@acm.org} +\sectionauthor{Sjoerd Mullender}{sjoerd@acm.org} + + + +This module provides an interface for reading files that use EA IFF 85 +chunks.\footnote{``EA IFF 85'' Standard for Interchange Format Files, +Jerry Morrison, Electronic Arts, January 1985.} This format is used +in at least the Audio\index{Audio Interchange File +Format}\index{AIFF}\index{AIFF-C} Interchange File Format +(AIFF/AIFF-C) and the Real\index{Real Media File Format} Media File +Format\index{RMFF} (RMFF). The WAVE audio file format is closely +related and can also be read using this module. + +A chunk has the following structure: + +\begin{tableiii}{c|c|l}{textrm}{Offset}{Length}{Contents} + \lineiii{0}{4}{Chunk ID} + \lineiii{4}{4}{Size of chunk in big-endian byte order, not including the + header} + \lineiii{8}{\var{n}}{Data bytes, where \var{n} is the size given in + the preceding field} + \lineiii{8 + \var{n}}{0 or 1}{Pad byte needed if \var{n} is odd and + chunk alignment is used} +\end{tableiii} + +The ID is a 4-byte string which identifies the type of chunk. + +The size field (a 32-bit value, encoded using big-endian byte order) +gives the size of the chunk data, not including the 8-byte header. + +Usually an IFF-type file consists of one or more chunks. The proposed +usage of the \class{Chunk} class defined here is to instantiate an +instance at the start of each chunk and read from the instance until +it reaches the end, after which a new instance can be instantiated. +At the end of the file, creating a new instance will fail with a +\exception{EOFError} exception. + +\begin{classdesc}{Chunk}{file\optional{, align, bigendian, inclheader}} +Class which represents a chunk. The \var{file} argument is expected +to be a file-like object. An instance of this class is specifically +allowed. The only method that is needed is \method{read()}. If the +methods \method{seek()} and \method{tell()} are present and don't +raise an exception, they are also used. If these methods are present +and raise an exception, they are expected to not have altered the +object. If the optional argument \var{align} is true, chunks are +assumed to be aligned on 2-byte boundaries. If \var{align} is +false, no alignment is assumed. The default value is true. If the +optional argument \var{bigendian} is false, the chunk size is assumed +to be in little-endian order. This is needed for WAVE audio files. +The default value is true. If the optional argument \var{inclheader} +is true, the size given in the chunk header includes the size of the +header. The default value is false. +\end{classdesc} + +A \class{Chunk} object supports the following methods: + +\begin{methoddesc}{getname}{} +Returns the name (ID) of the chunk. This is the first 4 bytes of the +chunk. +\end{methoddesc} + +\begin{methoddesc}{getsize}{} +Returns the size of the chunk. +\end{methoddesc} + +\begin{methoddesc}{close}{} +Close and skip to the end of the chunk. This does not close the +underlying file. +\end{methoddesc} + +The remaining methods will raise \exception{IOError} if called after +the \method{close()} method has been called. + +\begin{methoddesc}{isatty}{} +Returns \code{False}. +\end{methoddesc} + +\begin{methoddesc}{seek}{pos\optional{, whence}} +Set the chunk's current position. The \var{whence} argument is +optional and defaults to \code{0} (absolute file positioning); other +values are \code{1} (seek relative to the current position) and +\code{2} (seek relative to the file's end). There is no return value. +If the underlying file does not allow seek, only forward seeks are +allowed. +\end{methoddesc} + +\begin{methoddesc}{tell}{} +Return the current position into the chunk. +\end{methoddesc} + +\begin{methoddesc}{read}{\optional{size}} +Read at most \var{size} bytes from the chunk (less if the read hits +the end of the chunk before obtaining \var{size} bytes). If the +\var{size} argument is negative or omitted, read all data until the +end of the chunk. The bytes are returned as a string object. An +empty string is returned when the end of the chunk is encountered +immediately. +\end{methoddesc} + +\begin{methoddesc}{skip}{} +Skip to the end of the chunk. All further calls to \method{read()} +for the chunk will return \code{''}. If you are not interested in the +contents of the chunk, this method should be called so that the file +points to the start of the next chunk. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libcmath.tex b/sys/src/cmd/python/Doc/lib/libcmath.tex new file mode 100644 index 000000000..54e0cdb1f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcmath.tex @@ -0,0 +1,142 @@ +\section{\module{cmath} --- + Mathematical functions for complex numbers} + +\declaremodule{builtin}{cmath} +\modulesynopsis{Mathematical functions for complex numbers.} + +This module is always available. It provides access to mathematical +functions for complex numbers. The functions are: + +\begin{funcdesc}{acos}{x} +Return the arc cosine of \var{x}. +There are two branch cuts: +One extends right from 1 along the real axis to \infinity, continuous +from below. +The other extends left from -1 along the real axis to -\infinity, +continuous from above. +\end{funcdesc} + +\begin{funcdesc}{acosh}{x} +Return the hyperbolic arc cosine of \var{x}. +There is one branch cut, extending left from 1 along the real axis +to -\infinity, continuous from above. +\end{funcdesc} + +\begin{funcdesc}{asin}{x} +Return the arc sine of \var{x}. +This has the same branch cuts as \function{acos()}. +\end{funcdesc} + +\begin{funcdesc}{asinh}{x} +Return the hyperbolic arc sine of \var{x}. +There are two branch cuts, extending left from \plusminus\code{1j} to +\plusminus-\infinity\code{j}, both continuous from above. +These branch cuts should be considered a bug to be corrected in a +future release. +The correct branch cuts should extend along the imaginary axis, +one from \code{1j} up to \infinity\code{j} and continuous from the +right, and one from -\code{1j} down to -\infinity\code{j} and +continuous from the left. +\end{funcdesc} + +\begin{funcdesc}{atan}{x} +Return the arc tangent of \var{x}. +There are two branch cuts: +One extends from \code{1j} along the imaginary axis to +\infinity\code{j}, continuous from the left. +The other extends from -\code{1j} along the imaginary axis to +-\infinity\code{j}, continuous from the left. +(This should probably be changed so the upper cut becomes continuous +from the other side.) +\end{funcdesc} + +\begin{funcdesc}{atanh}{x} +Return the hyperbolic arc tangent of \var{x}. +There are two branch cuts: +One extends from 1 along the real axis to \infinity, continuous +from above. +The other extends from -1 along the real axis to -\infinity, +continuous from above. +(This should probably be changed so the right cut becomes continuous from +the other side.) +\end{funcdesc} + +\begin{funcdesc}{cos}{x} +Return the cosine of \var{x}. +\end{funcdesc} + +\begin{funcdesc}{cosh}{x} +Return the hyperbolic cosine of \var{x}. +\end{funcdesc} + +\begin{funcdesc}{exp}{x} +Return the exponential value \code{e**\var{x}}. +\end{funcdesc} + +\begin{funcdesc}{log}{x\optional{, base}} +Returns the logarithm of \var{x} to the given \var{base}. +If the \var{base} is not specified, returns the natural logarithm of \var{x}. +There is one branch cut, from 0 along the negative real axis to +-\infinity, continuous from above. +\versionchanged[\var{base} argument added]{2.4} +\end{funcdesc} + +\begin{funcdesc}{log10}{x} +Return the base-10 logarithm of \var{x}. +This has the same branch cut as \function{log()}. +\end{funcdesc} + +\begin{funcdesc}{sin}{x} +Return the sine of \var{x}. +\end{funcdesc} + +\begin{funcdesc}{sinh}{x} +Return the hyperbolic sine of \var{x}. +\end{funcdesc} + +\begin{funcdesc}{sqrt}{x} +Return the square root of \var{x}. +This has the same branch cut as \function{log()}. +\end{funcdesc} + +\begin{funcdesc}{tan}{x} +Return the tangent of \var{x}. +\end{funcdesc} + +\begin{funcdesc}{tanh}{x} +Return the hyperbolic tangent of \var{x}. +\end{funcdesc} + +The module also defines two mathematical constants: + +\begin{datadesc}{pi} +The mathematical constant \emph{pi}, as a real. +\end{datadesc} + +\begin{datadesc}{e} +The mathematical constant \emph{e}, as a real. +\end{datadesc} + +Note that the selection of functions is similar, but not identical, to +that in module \refmodule{math}\refbimodindex{math}. The reason for having +two modules is that some users aren't interested in complex numbers, +and perhaps don't even know what they are. They would rather have +\code{math.sqrt(-1)} raise an exception than return a complex number. +Also note that the functions defined in \module{cmath} always return a +complex number, even if the answer can be expressed as a real number +(in which case the complex number has an imaginary part of zero). + +A note on branch cuts: They are curves along which the given function +fails to be continuous. They are a necessary feature of many complex +functions. It is assumed that if you need to compute with complex +functions, you will understand about branch cuts. Consult almost any +(not too elementary) book on complex variables for enlightenment. For +information of the proper choice of branch cuts for numerical +purposes, a good reference should be the following: + +\begin{seealso} + \seetext{Kahan, W: Branch cuts for complex elementary functions; + or, Much ado about nothing's sign bit. In Iserles, A., + and Powell, M. (eds.), \citetitle{The state of the art in + numerical analysis}. Clarendon Press (1987) pp165-211.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libcmd.tex b/sys/src/cmd/python/Doc/lib/libcmd.tex new file mode 100644 index 000000000..661eb9e45 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcmd.tex @@ -0,0 +1,198 @@ +\section{\module{cmd} --- + Support for line-oriented command interpreters} + +\declaremodule{standard}{cmd} +\sectionauthor{Eric S. Raymond}{esr@snark.thyrsus.com} +\modulesynopsis{Build line-oriented command interpreters.} + + +The \class{Cmd} class provides a simple framework for writing +line-oriented command interpreters. These are often useful for +test harnesses, administrative tools, and prototypes that will +later be wrapped in a more sophisticated interface. + +\begin{classdesc}{Cmd}{\optional{completekey\optional{, + stdin\optional{, stdout}}}} +A \class{Cmd} instance or subclass instance is a line-oriented +interpreter framework. There is no good reason to instantiate +\class{Cmd} itself; rather, it's useful as a superclass of an +interpreter class you define yourself in order to inherit +\class{Cmd}'s methods and encapsulate action methods. + +The optional argument \var{completekey} is the \refmodule{readline} name +of a completion key; it defaults to \kbd{Tab}. If \var{completekey} is +not \constant{None} and \refmodule{readline} is available, command completion +is done automatically. + +The optional arguments \var{stdin} and \var{stdout} specify the +input and output file objects that the Cmd instance or subclass +instance will use for input and output. If not specified, they +will default to \var{sys.stdin} and \var{sys.stdout}. + +\versionchanged[The \var{stdin} and \var{stdout} parameters were added]{2.3} +\end{classdesc} + +\subsection{Cmd Objects} +\label{Cmd-objects} + +A \class{Cmd} instance has the following methods: + +\begin{methoddesc}{cmdloop}{\optional{intro}} +Repeatedly issue a prompt, accept input, parse an initial prefix off +the received input, and dispatch to action methods, passing them the +remainder of the line as argument. + +The optional argument is a banner or intro string to be issued before the +first prompt (this overrides the \member{intro} class member). + +If the \refmodule{readline} module is loaded, input will automatically +inherit \program{bash}-like history-list editing (e.g. \kbd{Control-P} +scrolls back to the last command, \kbd{Control-N} forward to the next +one, \kbd{Control-F} moves the cursor to the right non-destructively, +\kbd{Control-B} moves the cursor to the left non-destructively, etc.). + +An end-of-file on input is passed back as the string \code{'EOF'}. + +An interpreter instance will recognize a command name \samp{foo} if +and only if it has a method \method{do_foo()}. As a special case, +a line beginning with the character \character{?} is dispatched to +the method \method{do_help()}. As another special case, a line +beginning with the character \character{!} is dispatched to the +method \method{do_shell()} (if such a method is defined). + +This method will return when the \method{postcmd()} method returns a +true value. The \var{stop} argument to \method{postcmd()} is the +return value from the command's corresponding \method{do_*()} method. + +If completion is enabled, completing commands will be done +automatically, and completing of commands args is done by calling +\method{complete_foo()} with arguments \var{text}, \var{line}, +\var{begidx}, and \var{endidx}. \var{text} is the string prefix we +are attempting to match: all returned matches must begin with it. +\var{line} is the current input line with leading whitespace removed, +\var{begidx} and \var{endidx} are the beginning and ending indexes +of the prefix text, which could be used to provide different +completion depending upon which position the argument is in. + +All subclasses of \class{Cmd} inherit a predefined \method{do_help()}. +This method, called with an argument \code{'bar'}, invokes the +corresponding method \method{help_bar()}. With no argument, +\method{do_help()} lists all available help topics (that is, all +commands with corresponding \method{help_*()} methods), and also lists +any undocumented commands. +\end{methoddesc} + +\begin{methoddesc}{onecmd}{str} +Interpret the argument as though it had been typed in response to the +prompt. This may be overridden, but should not normally need to be; +see the \method{precmd()} and \method{postcmd()} methods for useful +execution hooks. The return value is a flag indicating whether +interpretation of commands by the interpreter should stop. If there +is a \method{do_*()} method for the command \var{str}, the return +value of that method is returned, otherwise the return value from the +\method{default()} method is returned. +\end{methoddesc} + +\begin{methoddesc}{emptyline}{} +Method called when an empty line is entered in response to the prompt. +If this method is not overridden, it repeats the last nonempty command +entered. +\end{methoddesc} + +\begin{methoddesc}{default}{line} +Method called on an input line when the command prefix is not +recognized. If this method is not overridden, it prints an +error message and returns. +\end{methoddesc} + +\begin{methoddesc}{completedefault}{text, line, begidx, endidx} +Method called to complete an input line when no command-specific +\method{complete_*()} method is available. By default, it returns an +empty list. +\end{methoddesc} + +\begin{methoddesc}{precmd}{line} +Hook method executed just before the command line \var{line} is +interpreted, but after the input prompt is generated and issued. This +method is a stub in \class{Cmd}; it exists to be overridden by +subclasses. The return value is used as the command which will be +executed by the \method{onecmd()} method; the \method{precmd()} +implementation may re-write the command or simply return \var{line} +unchanged. +\end{methoddesc} + +\begin{methoddesc}{postcmd}{stop, line} +Hook method executed just after a command dispatch is finished. This +method is a stub in \class{Cmd}; it exists to be overridden by +subclasses. \var{line} is the command line which was executed, and +\var{stop} is a flag which indicates whether execution will be +terminated after the call to \method{postcmd()}; this will be the +return value of the \method{onecmd()} method. The return value of +this method will be used as the new value for the internal flag which +corresponds to \var{stop}; returning false will cause interpretation +to continue. +\end{methoddesc} + +\begin{methoddesc}{preloop}{} +Hook method executed once when \method{cmdloop()} is called. This +method is a stub in \class{Cmd}; it exists to be overridden by +subclasses. +\end{methoddesc} + +\begin{methoddesc}{postloop}{} +Hook method executed once when \method{cmdloop()} is about to return. +This method is a stub in \class{Cmd}; it exists to be overridden by +subclasses. +\end{methoddesc} + +Instances of \class{Cmd} subclasses have some public instance variables: + +\begin{memberdesc}{prompt} +The prompt issued to solicit input. +\end{memberdesc} + +\begin{memberdesc}{identchars} +The string of characters accepted for the command prefix. +\end{memberdesc} + +\begin{memberdesc}{lastcmd} +The last nonempty command prefix seen. +\end{memberdesc} + +\begin{memberdesc}{intro} +A string to issue as an intro or banner. May be overridden by giving +the \method{cmdloop()} method an argument. +\end{memberdesc} + +\begin{memberdesc}{doc_header} +The header to issue if the help output has a section for documented +commands. +\end{memberdesc} + +\begin{memberdesc}{misc_header} +The header to issue if the help output has a section for miscellaneous +help topics (that is, there are \method{help_*()} methods without +corresponding \method{do_*()} methods). +\end{memberdesc} + +\begin{memberdesc}{undoc_header} +The header to issue if the help output has a section for undocumented +commands (that is, there are \method{do_*()} methods without +corresponding \method{help_*()} methods). +\end{memberdesc} + +\begin{memberdesc}{ruler} +The character used to draw separator lines under the help-message +headers. If empty, no ruler line is drawn. It defaults to +\character{=}. +\end{memberdesc} + +\begin{memberdesc}{use_rawinput} +A flag, defaulting to true. If true, \method{cmdloop()} uses +\function{raw_input()} to display a prompt and read the next command; +if false, \method{sys.stdout.write()} and +\method{sys.stdin.readline()} are used. (This means that by +importing \refmodule{readline}, on systems that support it, the +interpreter will automatically support \program{Emacs}-like line editing +and command-history keystrokes.) +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/lib/libcmp.tex b/sys/src/cmd/python/Doc/lib/libcmp.tex new file mode 100644 index 000000000..489efee96 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcmp.tex @@ -0,0 +1,36 @@ +\section{\module{cmp} --- + File comparisons} + +\declaremodule{standard}{cmp} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Compare files very efficiently.} + +\deprecated{1.6}{Use the \refmodule{filecmp} module instead.} + +The \module{cmp} module defines a function to compare files, taking all +sort of short-cuts to make it a highly efficient operation. + +The \module{cmp} module defines the following function: + +\begin{funcdesc}{cmp}{f1, f2} +Compare two files given as names. The following tricks are used to +optimize the comparisons: + +\begin{itemize} + \item Files with identical type, size and mtime are assumed equal. + \item Files with different type or size are never equal. + \item The module only compares files it already compared if their + signature (type, size and mtime) changed. + \item No external programs are called. +\end{itemize} +\end{funcdesc} + +Example: + +\begin{verbatim} +>>> import cmp +>>> cmp.cmp('libundoc.tex', 'libundoc.tex') +1 +>>> cmp.cmp('libundoc.tex', 'lib.tex') +0 +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libcmpcache.tex b/sys/src/cmd/python/Doc/lib/libcmpcache.tex new file mode 100644 index 000000000..899147749 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcmpcache.tex @@ -0,0 +1,21 @@ +\section{\module{cmpcache} --- + Efficient file comparisons} + +\declaremodule{standard}{cmpcache} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Compare files very efficiently.} + +\deprecated{1.6}{Use the \refmodule{filecmp} module instead.} + +The \module{cmpcache} module provides an identical interface and similar +functionality as the \refmodule{cmp} module, but can be a bit more efficient +as it uses \function{statcache.stat()} instead of \function{os.stat()} +(see the \refmodule{statcache} module for information on the +difference). + +\note{Using the \refmodule{statcache} module to provide +\function{stat()} information results in trashing the cache +invalidation mechanism: results are not as reliable. To ensure +``current'' results, use \function{cmp.cmp()} instead of the version +defined in this module, or use \function{statcache.forget()} to +invalidate the appropriate entries.} diff --git a/sys/src/cmd/python/Doc/lib/libcode.tex b/sys/src/cmd/python/Doc/lib/libcode.tex new file mode 100644 index 000000000..dc4c717ad --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcode.tex @@ -0,0 +1,173 @@ +\section{\module{code} --- + Interpreter base classes} +\declaremodule{standard}{code} + +\modulesynopsis{Base classes for interactive Python interpreters.} + + +The \code{code} module provides facilities to implement +read-eval-print loops in Python. Two classes and convenience +functions are included which can be used to build applications which +provide an interactive interpreter prompt. + + +\begin{classdesc}{InteractiveInterpreter}{\optional{locals}} +This class deals with parsing and interpreter state (the user's +namespace); it does not deal with input buffering or prompting or +input file naming (the filename is always passed in explicitly). +The optional \var{locals} argument specifies the dictionary in +which code will be executed; it defaults to a newly created +dictionary with key \code{'__name__'} set to \code{'__console__'} +and key \code{'__doc__'} set to \code{None}. +\end{classdesc} + +\begin{classdesc}{InteractiveConsole}{\optional{locals\optional{, filename}}} +Closely emulate the behavior of the interactive Python interpreter. +This class builds on \class{InteractiveInterpreter} and adds +prompting using the familiar \code{sys.ps1} and \code{sys.ps2}, and +input buffering. +\end{classdesc} + + +\begin{funcdesc}{interact}{\optional{banner\optional{, + readfunc\optional{, local}}}} +Convenience function to run a read-eval-print loop. This creates a +new instance of \class{InteractiveConsole} and sets \var{readfunc} +to be used as the \method{raw_input()} method, if provided. If +\var{local} is provided, it is passed to the +\class{InteractiveConsole} constructor for use as the default +namespace for the interpreter loop. The \method{interact()} method +of the instance is then run with \var{banner} passed as the banner +to use, if provided. The console object is discarded after use. +\end{funcdesc} + +\begin{funcdesc}{compile_command}{source\optional{, + filename\optional{, symbol}}} +This function is useful for programs that want to emulate Python's +interpreter main loop (a.k.a. the read-eval-print loop). The tricky +part is to determine when the user has entered an incomplete command +that can be completed by entering more text (as opposed to a +complete command or a syntax error). This function +\emph{almost} always makes the same decision as the real interpreter +main loop. + +\var{source} is the source string; \var{filename} is the optional +filename from which source was read, defaulting to \code{''}; +and \var{symbol} is the optional grammar start symbol, which should +be either \code{'single'} (the default) or \code{'eval'}. + +Returns a code object (the same as \code{compile(\var{source}, +\var{filename}, \var{symbol})}) if the command is complete and +valid; \code{None} if the command is incomplete; raises +\exception{SyntaxError} if the command is complete and contains a +syntax error, or raises \exception{OverflowError} or +\exception{ValueError} if the command contains an invalid literal. +\end{funcdesc} + + +\subsection{Interactive Interpreter Objects + \label{interpreter-objects}} + +\begin{methoddesc}{runsource}{source\optional{, filename\optional{, symbol}}} +Compile and run some source in the interpreter. +Arguments are the same as for \function{compile_command()}; the +default for \var{filename} is \code{''}, and for +\var{symbol} is \code{'single'}. One several things can happen: + +\begin{itemize} +\item +The input is incorrect; \function{compile_command()} raised an +exception (\exception{SyntaxError} or \exception{OverflowError}). A +syntax traceback will be printed by calling the +\method{showsyntaxerror()} method. \method{runsource()} returns +\code{False}. + +\item +The input is incomplete, and more input is required; +\function{compile_command()} returned \code{None}. +\method{runsource()} returns \code{True}. + +\item +The input is complete; \function{compile_command()} returned a code +object. The code is executed by calling the \method{runcode()} (which +also handles run-time exceptions, except for \exception{SystemExit}). +\method{runsource()} returns \code{False}. +\end{itemize} + +The return value can be used to decide whether to use +\code{sys.ps1} or \code{sys.ps2} to prompt the next line. +\end{methoddesc} + +\begin{methoddesc}{runcode}{code} +Execute a code object. +When an exception occurs, \method{showtraceback()} is called to +display a traceback. All exceptions are caught except +\exception{SystemExit}, which is allowed to propagate. + +A note about \exception{KeyboardInterrupt}: this exception may occur +elsewhere in this code, and may not always be caught. The caller +should be prepared to deal with it. +\end{methoddesc} + +\begin{methoddesc}{showsyntaxerror}{\optional{filename}} +Display the syntax error that just occurred. This does not display +a stack trace because there isn't one for syntax errors. +If \var{filename} is given, it is stuffed into the exception instead +of the default filename provided by Python's parser, because it +always uses \code{''} when reading from a string. +The output is written by the \method{write()} method. +\end{methoddesc} + +\begin{methoddesc}{showtraceback}{} +Display the exception that just occurred. We remove the first stack +item because it is within the interpreter object implementation. +The output is written by the \method{write()} method. +\end{methoddesc} + +\begin{methoddesc}{write}{data} +Write a string to the standard error stream (\code{sys.stderr}). +Derived classes should override this to provide the appropriate output +handling as needed. +\end{methoddesc} + + +\subsection{Interactive Console Objects + \label{console-objects}} + +The \class{InteractiveConsole} class is a subclass of +\class{InteractiveInterpreter}, and so offers all the methods of the +interpreter objects as well as the following additions. + +\begin{methoddesc}{interact}{\optional{banner}} +Closely emulate the interactive Python console. +The optional banner argument specify the banner to print before the +first interaction; by default it prints a banner similar to the one +printed by the standard Python interpreter, followed by the class +name of the console object in parentheses (so as not to confuse this +with the real interpreter -- since it's so close!). +\end{methoddesc} + +\begin{methoddesc}{push}{line} +Push a line of source text to the interpreter. +The line should not have a trailing newline; it may have internal +newlines. The line is appended to a buffer and the interpreter's +\method{runsource()} method is called with the concatenated contents +of the buffer as source. If this indicates that the command was +executed or invalid, the buffer is reset; otherwise, the command is +incomplete, and the buffer is left as it was after the line was +appended. The return value is \code{True} if more input is required, +\code{False} if the line was dealt with in some way (this is the same as +\method{runsource()}). +\end{methoddesc} + +\begin{methoddesc}{resetbuffer}{} +Remove any unhandled source text from the input buffer. +\end{methoddesc} + +\begin{methoddesc}{raw_input}{\optional{prompt}} +Write a prompt and read a line. The returned line does not include +the trailing newline. When the user enters the \EOF{} key sequence, +\exception{EOFError} is raised. The base implementation uses the +built-in function \function{raw_input()}; a subclass may replace this +with a different implementation. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libcodecs.tex b/sys/src/cmd/python/Doc/lib/libcodecs.tex new file mode 100644 index 000000000..05c037501 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcodecs.tex @@ -0,0 +1,1348 @@ +\section{\module{codecs} --- + Codec registry and base classes} + +\declaremodule{standard}{codecs} +\modulesynopsis{Encode and decode data and streams.} +\moduleauthor{Marc-Andre Lemburg}{mal@lemburg.com} +\sectionauthor{Marc-Andre Lemburg}{mal@lemburg.com} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} + +\index{Unicode} +\index{Codecs} +\indexii{Codecs}{encode} +\indexii{Codecs}{decode} +\index{streams} +\indexii{stackable}{streams} + + +This module defines base classes for standard Python codecs (encoders +and decoders) and provides access to the internal Python codec +registry which manages the codec and error handling lookup process. + +It defines the following functions: + +\begin{funcdesc}{register}{search_function} +Register a codec search function. Search functions are expected to +take one argument, the encoding name in all lower case letters, and +return a \class{CodecInfo} object having the following attributes: + +\begin{itemize} + \item \code{name} The name of the encoding; + \item \code{encoder} The stateless encoding function; + \item \code{decoder} The stateless decoding function; + \item \code{incrementalencoder} An incremental encoder class or factory function; + \item \code{incrementaldecoder} An incremental decoder class or factory function; + \item \code{streamwriter} A stream writer class or factory function; + \item \code{streamreader} A stream reader class or factory function. +\end{itemize} + +The various functions or classes take the following arguments: + + \var{encoder} and \var{decoder}: These must be functions or methods + which have the same interface as the + \method{encode()}/\method{decode()} methods of Codec instances (see + Codec Interface). The functions/methods are expected to work in a + stateless mode. + + \var{incrementalencoder} and \var{incrementalencoder}: These have to be + factory functions providing the following interface: + + \code{factory(\var{errors}='strict')} + + The factory functions must return objects providing the interfaces + defined by the base classes \class{IncrementalEncoder} and + \class{IncrementalEncoder}, respectively. Incremental codecs can maintain + state. + + \var{streamreader} and \var{streamwriter}: These have to be + factory functions providing the following interface: + + \code{factory(\var{stream}, \var{errors}='strict')} + + The factory functions must return objects providing the interfaces + defined by the base classes \class{StreamWriter} and + \class{StreamReader}, respectively. Stream codecs can maintain + state. + + Possible values for errors are \code{'strict'} (raise an exception + in case of an encoding error), \code{'replace'} (replace malformed + data with a suitable replacement marker, such as \character{?}), + \code{'ignore'} (ignore malformed data and continue without further + notice), \code{'xmlcharrefreplace'} (replace with the appropriate XML + character reference (for encoding only)) and \code{'backslashreplace'} + (replace with backslashed escape sequences (for encoding only)) as + well as any other error handling name defined via + \function{register_error()}. + +In case a search function cannot find a given encoding, it should +return \code{None}. +\end{funcdesc} + +\begin{funcdesc}{lookup}{encoding} +Looks up the codec info in the Python codec registry and returns a +\class{CodecInfo} object as defined above. + +Encodings are first looked up in the registry's cache. If not found, +the list of registered search functions is scanned. If no \class{CodecInfo} +object is found, a \exception{LookupError} is raised. Otherwise, the +\class{CodecInfo} object is stored in the cache and returned to the caller. +\end{funcdesc} + +To simplify access to the various codecs, the module provides these +additional functions which use \function{lookup()} for the codec +lookup: + +\begin{funcdesc}{getencoder}{encoding} +Look up the codec for the given encoding and return its encoder +function. + +Raises a \exception{LookupError} in case the encoding cannot be found. +\end{funcdesc} + +\begin{funcdesc}{getdecoder}{encoding} +Look up the codec for the given encoding and return its decoder +function. + +Raises a \exception{LookupError} in case the encoding cannot be found. +\end{funcdesc} + +\begin{funcdesc}{getincrementalencoder}{encoding} +Look up the codec for the given encoding and return its incremental encoder +class or factory function. + +Raises a \exception{LookupError} in case the encoding cannot be found or the +codec doesn't support an incremental encoder. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{getincrementaldecoder}{encoding} +Look up the codec for the given encoding and return its incremental decoder +class or factory function. + +Raises a \exception{LookupError} in case the encoding cannot be found or the +codec doesn't support an incremental decoder. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{getreader}{encoding} +Look up the codec for the given encoding and return its StreamReader +class or factory function. + +Raises a \exception{LookupError} in case the encoding cannot be found. +\end{funcdesc} + +\begin{funcdesc}{getwriter}{encoding} +Look up the codec for the given encoding and return its StreamWriter +class or factory function. + +Raises a \exception{LookupError} in case the encoding cannot be found. +\end{funcdesc} + +\begin{funcdesc}{register_error}{name, error_handler} +Register the error handling function \var{error_handler} under the +name \var{name}. \var{error_handler} will be called during encoding +and decoding in case of an error, when \var{name} is specified as the +errors parameter. + +For encoding \var{error_handler} will be called with a +\exception{UnicodeEncodeError} instance, which contains information about +the location of the error. The error handler must either raise this or +a different exception or return a tuple with a replacement for the +unencodable part of the input and a position where encoding should +continue. The encoder will encode the replacement and continue encoding +the original input at the specified position. Negative position values +will be treated as being relative to the end of the input string. If the +resulting position is out of bound an \exception{IndexError} will be raised. + +Decoding and translating works similar, except \exception{UnicodeDecodeError} +or \exception{UnicodeTranslateError} will be passed to the handler and +that the replacement from the error handler will be put into the output +directly. +\end{funcdesc} + +\begin{funcdesc}{lookup_error}{name} +Return the error handler previously registered under the name \var{name}. + +Raises a \exception{LookupError} in case the handler cannot be found. +\end{funcdesc} + +\begin{funcdesc}{strict_errors}{exception} +Implements the \code{strict} error handling. +\end{funcdesc} + +\begin{funcdesc}{replace_errors}{exception} +Implements the \code{replace} error handling. +\end{funcdesc} + +\begin{funcdesc}{ignore_errors}{exception} +Implements the \code{ignore} error handling. +\end{funcdesc} + +\begin{funcdesc}{xmlcharrefreplace_errors_errors}{exception} +Implements the \code{xmlcharrefreplace} error handling. +\end{funcdesc} + +\begin{funcdesc}{backslashreplace_errors_errors}{exception} +Implements the \code{backslashreplace} error handling. +\end{funcdesc} + +To simplify working with encoded files or stream, the module +also defines these utility functions: + +\begin{funcdesc}{open}{filename, mode\optional{, encoding\optional{, + errors\optional{, buffering}}}} +Open an encoded file using the given \var{mode} and return +a wrapped version providing transparent encoding/decoding. + +\note{The wrapped version will only accept the object format +defined by the codecs, i.e.\ Unicode objects for most built-in +codecs. Output is also codec-dependent and will usually be Unicode as +well.} + +\var{encoding} specifies the encoding which is to be used for the +file. + +\var{errors} may be given to define the error handling. It defaults +to \code{'strict'} which causes a \exception{ValueError} to be raised +in case an encoding error occurs. + +\var{buffering} has the same meaning as for the built-in +\function{open()} function. It defaults to line buffered. +\end{funcdesc} + +\begin{funcdesc}{EncodedFile}{file, input\optional{, + output\optional{, errors}}} +Return a wrapped version of file which provides transparent +encoding translation. + +Strings written to the wrapped file are interpreted according to the +given \var{input} encoding and then written to the original file as +strings using the \var{output} encoding. The intermediate encoding will +usually be Unicode but depends on the specified codecs. + +If \var{output} is not given, it defaults to \var{input}. + +\var{errors} may be given to define the error handling. It defaults to +\code{'strict'}, which causes \exception{ValueError} to be raised in case +an encoding error occurs. +\end{funcdesc} + +\begin{funcdesc}{iterencode}{iterable, encoding\optional{, errors}} +Uses an incremental encoder to iteratively encode the input provided by +\var{iterable}. This function is a generator. \var{errors} (as well as +any other keyword argument) is passed through to the incremental encoder. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{iterdecode}{iterable, encoding\optional{, errors}} +Uses an incremental decoder to iteratively decode the input provided by +\var{iterable}. This function is a generator. \var{errors} (as well as +any other keyword argument) is passed through to the incremental encoder. +\versionadded{2.5} +\end{funcdesc} + +The module also provides the following constants which are useful +for reading and writing to platform dependent files: + +\begin{datadesc}{BOM} +\dataline{BOM_BE} +\dataline{BOM_LE} +\dataline{BOM_UTF8} +\dataline{BOM_UTF16} +\dataline{BOM_UTF16_BE} +\dataline{BOM_UTF16_LE} +\dataline{BOM_UTF32} +\dataline{BOM_UTF32_BE} +\dataline{BOM_UTF32_LE} +These constants define various encodings of the Unicode byte order mark +(BOM) used in UTF-16 and UTF-32 data streams to indicate the byte order +used in the stream or file and in UTF-8 as a Unicode signature. +\constant{BOM_UTF16} is either \constant{BOM_UTF16_BE} or +\constant{BOM_UTF16_LE} depending on the platform's native byte order, +\constant{BOM} is an alias for \constant{BOM_UTF16}, \constant{BOM_LE} +for \constant{BOM_UTF16_LE} and \constant{BOM_BE} for \constant{BOM_UTF16_BE}. +The others represent the BOM in UTF-8 and UTF-32 encodings. +\end{datadesc} + + +\subsection{Codec Base Classes \label{codec-base-classes}} + +The \module{codecs} module defines a set of base classes which define the +interface and can also be used to easily write you own codecs for use +in Python. + +Each codec has to define four interfaces to make it usable as codec in +Python: stateless encoder, stateless decoder, stream reader and stream +writer. The stream reader and writers typically reuse the stateless +encoder/decoder to implement the file protocols. + +The \class{Codec} class defines the interface for stateless +encoders/decoders. + +To simplify and standardize error handling, the \method{encode()} and +\method{decode()} methods may implement different error handling +schemes by providing the \var{errors} string argument. The following +string values are defined and implemented by all standard Python +codecs: + +\begin{tableii}{l|l}{code}{Value}{Meaning} + \lineii{'strict'}{Raise \exception{UnicodeError} (or a subclass); + this is the default.} + \lineii{'ignore'}{Ignore the character and continue with the next.} + \lineii{'replace'}{Replace with a suitable replacement character; + Python will use the official U+FFFD REPLACEMENT + CHARACTER for the built-in Unicode codecs on + decoding and '?' on encoding.} + \lineii{'xmlcharrefreplace'}{Replace with the appropriate XML + character reference (only for encoding).} + \lineii{'backslashreplace'}{Replace with backslashed escape sequences + (only for encoding).} +\end{tableii} + +The set of allowed values can be extended via \method{register_error}. + + +\subsubsection{Codec Objects \label{codec-objects}} + +The \class{Codec} class defines these methods which also define the +function interfaces of the stateless encoder and decoder: + +\begin{methoddesc}{encode}{input\optional{, errors}} + Encodes the object \var{input} and returns a tuple (output object, + length consumed). While codecs are not restricted to use with Unicode, in + a Unicode context, encoding converts a Unicode object to a plain string + using a particular character set encoding (e.g., \code{cp1252} or + \code{iso-8859-1}). + + \var{errors} defines the error handling to apply. It defaults to + \code{'strict'} handling. + + The method may not store state in the \class{Codec} instance. Use + \class{StreamCodec} for codecs which have to keep state in order to + make encoding/decoding efficient. + + The encoder must be able to handle zero length input and return an + empty object of the output object type in this situation. +\end{methoddesc} + +\begin{methoddesc}{decode}{input\optional{, errors}} + Decodes the object \var{input} and returns a tuple (output object, + length consumed). In a Unicode context, decoding converts a plain string + encoded using a particular character set encoding to a Unicode object. + + \var{input} must be an object which provides the \code{bf_getreadbuf} + buffer slot. Python strings, buffer objects and memory mapped files + are examples of objects providing this slot. + + \var{errors} defines the error handling to apply. It defaults to + \code{'strict'} handling. + + The method may not store state in the \class{Codec} instance. Use + \class{StreamCodec} for codecs which have to keep state in order to + make encoding/decoding efficient. + + The decoder must be able to handle zero length input and return an + empty object of the output object type in this situation. +\end{methoddesc} + +The \class{IncrementalEncoder} and \class{IncrementalDecoder} classes provide +the basic interface for incremental encoding and decoding. Encoding/decoding the +input isn't done with one call to the stateless encoder/decoder function, +but with multiple calls to the \method{encode}/\method{decode} method of the +incremental encoder/decoder. The incremental encoder/decoder keeps track of +the encoding/decoding process during method calls. + +The joined output of calls to the \method{encode}/\method{decode} method is the +same as if all the single inputs were joined into one, and this input was +encoded/decoded with the stateless encoder/decoder. + + +\subsubsection{IncrementalEncoder Objects \label{incremental-encoder-objects}} + +\versionadded{2.5} + +The \class{IncrementalEncoder} class is used for encoding an input in multiple +steps. It defines the following methods which every incremental encoder must +define in order to be compatible with the Python codec registry. + +\begin{classdesc}{IncrementalEncoder}{\optional{errors}} + Constructor for an \class{IncrementalEncoder} instance. + + All incremental encoders must provide this constructor interface. They are + free to add additional keyword arguments, but only the ones defined + here are used by the Python codec registry. + + The \class{IncrementalEncoder} may implement different error handling + schemes by providing the \var{errors} keyword argument. These + parameters are predefined: + + \begin{itemize} + \item \code{'strict'} Raise \exception{ValueError} (or a subclass); + this is the default. + \item \code{'ignore'} Ignore the character and continue with the next. + \item \code{'replace'} Replace with a suitable replacement character + \item \code{'xmlcharrefreplace'} Replace with the appropriate XML + character reference + \item \code{'backslashreplace'} Replace with backslashed escape sequences. + \end{itemize} + + The \var{errors} argument will be assigned to an attribute of the + same name. Assigning to this attribute makes it possible to switch + between different error handling strategies during the lifetime + of the \class{IncrementalEncoder} object. + + The set of allowed values for the \var{errors} argument can + be extended with \function{register_error()}. +\end{classdesc} + +\begin{methoddesc}{encode}{object\optional{, final}} + Encodes \var{object} (taking the current state of the encoder into account) + and returns the resulting encoded object. If this is the last call to + \method{encode} \var{final} must be true (the default is false). +\end{methoddesc} + +\begin{methoddesc}{reset}{} + Reset the encoder to the initial state. +\end{methoddesc} + + +\subsubsection{IncrementalDecoder Objects \label{incremental-decoder-objects}} + +The \class{IncrementalDecoder} class is used for decoding an input in multiple +steps. It defines the following methods which every incremental decoder must +define in order to be compatible with the Python codec registry. + +\begin{classdesc}{IncrementalDecoder}{\optional{errors}} + Constructor for an \class{IncrementalDecoder} instance. + + All incremental decoders must provide this constructor interface. They are + free to add additional keyword arguments, but only the ones defined + here are used by the Python codec registry. + + The \class{IncrementalDecoder} may implement different error handling + schemes by providing the \var{errors} keyword argument. These + parameters are predefined: + + \begin{itemize} + \item \code{'strict'} Raise \exception{ValueError} (or a subclass); + this is the default. + \item \code{'ignore'} Ignore the character and continue with the next. + \item \code{'replace'} Replace with a suitable replacement character. + \end{itemize} + + The \var{errors} argument will be assigned to an attribute of the + same name. Assigning to this attribute makes it possible to switch + between different error handling strategies during the lifetime + of the \class{IncrementalEncoder} object. + + The set of allowed values for the \var{errors} argument can + be extended with \function{register_error()}. +\end{classdesc} + +\begin{methoddesc}{decode}{object\optional{, final}} + Decodes \var{object} (taking the current state of the decoder into account) + and returns the resulting decoded object. If this is the last call to + \method{decode} \var{final} must be true (the default is false). + If \var{final} is true the decoder must decode the input completely and must + flush all buffers. If this isn't possible (e.g. because of incomplete byte + sequences at the end of the input) it must initiate error handling just like + in the stateless case (which might raise an exception). +\end{methoddesc} + +\begin{methoddesc}{reset}{} + Reset the decoder to the initial state. +\end{methoddesc} + + +The \class{StreamWriter} and \class{StreamReader} classes provide +generic working interfaces which can be used to implement new +encoding submodules very easily. See \module{encodings.utf_8} for an +example of how this is done. + + +\subsubsection{StreamWriter Objects \label{stream-writer-objects}} + +The \class{StreamWriter} class is a subclass of \class{Codec} and +defines the following methods which every stream writer must define in +order to be compatible with the Python codec registry. + +\begin{classdesc}{StreamWriter}{stream\optional{, errors}} + Constructor for a \class{StreamWriter} instance. + + All stream writers must provide this constructor interface. They are + free to add additional keyword arguments, but only the ones defined + here are used by the Python codec registry. + + \var{stream} must be a file-like object open for writing binary + data. + + The \class{StreamWriter} may implement different error handling + schemes by providing the \var{errors} keyword argument. These + parameters are predefined: + + \begin{itemize} + \item \code{'strict'} Raise \exception{ValueError} (or a subclass); + this is the default. + \item \code{'ignore'} Ignore the character and continue with the next. + \item \code{'replace'} Replace with a suitable replacement character + \item \code{'xmlcharrefreplace'} Replace with the appropriate XML + character reference + \item \code{'backslashreplace'} Replace with backslashed escape sequences. + \end{itemize} + + The \var{errors} argument will be assigned to an attribute of the + same name. Assigning to this attribute makes it possible to switch + between different error handling strategies during the lifetime + of the \class{StreamWriter} object. + + The set of allowed values for the \var{errors} argument can + be extended with \function{register_error()}. +\end{classdesc} + +\begin{methoddesc}{write}{object} + Writes the object's contents encoded to the stream. +\end{methoddesc} + +\begin{methoddesc}{writelines}{list} + Writes the concatenated list of strings to the stream (possibly by + reusing the \method{write()} method). +\end{methoddesc} + +\begin{methoddesc}{reset}{} + Flushes and resets the codec buffers used for keeping state. + + Calling this method should ensure that the data on the output is put + into a clean state that allows appending of new fresh data without + having to rescan the whole stream to recover state. +\end{methoddesc} + +In addition to the above methods, the \class{StreamWriter} must also +inherit all other methods and attributes from the underlying stream. + + +\subsubsection{StreamReader Objects \label{stream-reader-objects}} + +The \class{StreamReader} class is a subclass of \class{Codec} and +defines the following methods which every stream reader must define in +order to be compatible with the Python codec registry. + +\begin{classdesc}{StreamReader}{stream\optional{, errors}} + Constructor for a \class{StreamReader} instance. + + All stream readers must provide this constructor interface. They are + free to add additional keyword arguments, but only the ones defined + here are used by the Python codec registry. + + \var{stream} must be a file-like object open for reading (binary) + data. + + The \class{StreamReader} may implement different error handling + schemes by providing the \var{errors} keyword argument. These + parameters are defined: + + \begin{itemize} + \item \code{'strict'} Raise \exception{ValueError} (or a subclass); + this is the default. + \item \code{'ignore'} Ignore the character and continue with the next. + \item \code{'replace'} Replace with a suitable replacement character. + \end{itemize} + + The \var{errors} argument will be assigned to an attribute of the + same name. Assigning to this attribute makes it possible to switch + between different error handling strategies during the lifetime + of the \class{StreamReader} object. + + The set of allowed values for the \var{errors} argument can + be extended with \function{register_error()}. +\end{classdesc} + +\begin{methoddesc}{read}{\optional{size\optional{, chars, \optional{firstline}}}} + Decodes data from the stream and returns the resulting object. + + \var{chars} indicates the number of characters to read from the + stream. \function{read()} will never return more than \var{chars} + characters, but it might return less, if there are not enough + characters available. + + \var{size} indicates the approximate maximum number of bytes to read + from the stream for decoding purposes. The decoder can modify this + setting as appropriate. The default value -1 indicates to read and + decode as much as possible. \var{size} is intended to prevent having + to decode huge files in one step. + + \var{firstline} indicates that it would be sufficient to only return + the first line, if there are decoding errors on later lines. + + The method should use a greedy read strategy meaning that it should + read as much data as is allowed within the definition of the encoding + and the given size, e.g. if optional encoding endings or state + markers are available on the stream, these should be read too. + + \versionchanged[\var{chars} argument added]{2.4} + \versionchanged[\var{firstline} argument added]{2.4.2} +\end{methoddesc} + +\begin{methoddesc}{readline}{\optional{size\optional{, keepends}}} + Read one line from the input stream and return the + decoded data. + + \var{size}, if given, is passed as size argument to the stream's + \method{readline()} method. + + If \var{keepends} is false line-endings will be stripped from the + lines returned. + + \versionchanged[\var{keepends} argument added]{2.4} +\end{methoddesc} + +\begin{methoddesc}{readlines}{\optional{sizehint\optional{, keepends}}} + Read all lines available on the input stream and return them as a list + of lines. + + Line-endings are implemented using the codec's decoder method and are + included in the list entries if \var{keepends} is true. + + \var{sizehint}, if given, is passed as the \var{size} argument to the + stream's \method{read()} method. +\end{methoddesc} + +\begin{methoddesc}{reset}{} + Resets the codec buffers used for keeping state. + + Note that no stream repositioning should take place. This method is + primarily intended to be able to recover from decoding errors. +\end{methoddesc} + +In addition to the above methods, the \class{StreamReader} must also +inherit all other methods and attributes from the underlying stream. + +The next two base classes are included for convenience. They are not +needed by the codec registry, but may provide useful in practice. + + +\subsubsection{StreamReaderWriter Objects \label{stream-reader-writer}} + +The \class{StreamReaderWriter} allows wrapping streams which work in +both read and write modes. + +The design is such that one can use the factory functions returned by +the \function{lookup()} function to construct the instance. + +\begin{classdesc}{StreamReaderWriter}{stream, Reader, Writer, errors} + Creates a \class{StreamReaderWriter} instance. + \var{stream} must be a file-like object. + \var{Reader} and \var{Writer} must be factory functions or classes + providing the \class{StreamReader} and \class{StreamWriter} interface + resp. + Error handling is done in the same way as defined for the + stream readers and writers. +\end{classdesc} + +\class{StreamReaderWriter} instances define the combined interfaces of +\class{StreamReader} and \class{StreamWriter} classes. They inherit +all other methods and attributes from the underlying stream. + + +\subsubsection{StreamRecoder Objects \label{stream-recoder-objects}} + +The \class{StreamRecoder} provide a frontend - backend view of +encoding data which is sometimes useful when dealing with different +encoding environments. + +The design is such that one can use the factory functions returned by +the \function{lookup()} function to construct the instance. + +\begin{classdesc}{StreamRecoder}{stream, encode, decode, + Reader, Writer, errors} + Creates a \class{StreamRecoder} instance which implements a two-way + conversion: \var{encode} and \var{decode} work on the frontend (the + input to \method{read()} and output of \method{write()}) while + \var{Reader} and \var{Writer} work on the backend (reading and + writing to the stream). + + You can use these objects to do transparent direct recodings from + e.g.\ Latin-1 to UTF-8 and back. + + \var{stream} must be a file-like object. + + \var{encode}, \var{decode} must adhere to the \class{Codec} + interface. \var{Reader}, \var{Writer} must be factory functions or + classes providing objects of the \class{StreamReader} and + \class{StreamWriter} interface respectively. + + \var{encode} and \var{decode} are needed for the frontend + translation, \var{Reader} and \var{Writer} for the backend + translation. The intermediate format used is determined by the two + sets of codecs, e.g. the Unicode codecs will use Unicode as the + intermediate encoding. + + Error handling is done in the same way as defined for the + stream readers and writers. +\end{classdesc} + +\class{StreamRecoder} instances define the combined interfaces of +\class{StreamReader} and \class{StreamWriter} classes. They inherit +all other methods and attributes from the underlying stream. + +\subsection{Encodings and Unicode\label{encodings-overview}} + +Unicode strings are stored internally as sequences of codepoints (to +be precise as \ctype{Py_UNICODE} arrays). Depending on the way Python is +compiled (either via \longprogramopt{enable-unicode=ucs2} or +\longprogramopt{enable-unicode=ucs4}, with the former being the default) +\ctype{Py_UNICODE} is either a 16-bit or +32-bit data type. Once a Unicode object is used outside of CPU and +memory, CPU endianness and how these arrays are stored as bytes become +an issue. Transforming a unicode object into a sequence of bytes is +called encoding and recreating the unicode object from the sequence of +bytes is known as decoding. There are many different methods for how this +transformation can be done (these methods are also called encodings). +The simplest method is to map the codepoints 0-255 to the bytes +\code{0x0}-\code{0xff}. This means that a unicode object that contains +codepoints above \code{U+00FF} can't be encoded with this method (which +is called \code{'latin-1'} or \code{'iso-8859-1'}). +\function{unicode.encode()} will raise a \exception{UnicodeEncodeError} +that looks like this: \samp{UnicodeEncodeError: 'latin-1' codec can't +encode character u'\e u1234' in position 3: ordinal not in range(256)}. + +There's another group of encodings (the so called charmap encodings) +that choose a different subset of all unicode code points and how +these codepoints are mapped to the bytes \code{0x0}-\code{0xff.} +To see how this is done simply open e.g. \file{encodings/cp1252.py} +(which is an encoding that is used primarily on Windows). +There's a string constant with 256 characters that shows you which +character is mapped to which byte value. + +All of these encodings can only encode 256 of the 65536 (or 1114111) +codepoints defined in unicode. A simple and straightforward way that +can store each Unicode code point, is to store each codepoint as two +consecutive bytes. There are two possibilities: Store the bytes in big +endian or in little endian order. These two encodings are called +UTF-16-BE and UTF-16-LE respectively. Their disadvantage is that if +e.g. you use UTF-16-BE on a little endian machine you will always have +to swap bytes on encoding and decoding. UTF-16 avoids this problem: +Bytes will always be in natural endianness. When these bytes are read +by a CPU with a different endianness, then bytes have to be swapped +though. To be able to detect the endianness of a UTF-16 byte sequence, +there's the so called BOM (the "Byte Order Mark"). This is the Unicode +character \code{U+FEFF}. This character will be prepended to every UTF-16 +byte sequence. The byte swapped version of this character (\code{0xFFFE}) is +an illegal character that may not appear in a Unicode text. So when +the first character in an UTF-16 byte sequence appears to be a \code{U+FFFE} +the bytes have to be swapped on decoding. Unfortunately upto Unicode +4.0 the character \code{U+FEFF} had a second purpose as a \samp{ZERO WIDTH +NO-BREAK SPACE}: A character that has no width and doesn't allow a +word to be split. It can e.g. be used to give hints to a ligature +algorithm. With Unicode 4.0 using \code{U+FEFF} as a \samp{ZERO WIDTH NO-BREAK +SPACE} has been deprecated (with \code{U+2060} (\samp{WORD JOINER}) assuming +this role). Nevertheless Unicode software still must be able to handle +\code{U+FEFF} in both roles: As a BOM it's a device to determine the storage +layout of the encoded bytes, and vanishes once the byte sequence has +been decoded into a Unicode string; as a \samp{ZERO WIDTH NO-BREAK SPACE} +it's a normal character that will be decoded like any other. + +There's another encoding that is able to encoding the full range of +Unicode characters: UTF-8. UTF-8 is an 8-bit encoding, which means +there are no issues with byte order in UTF-8. Each byte in a UTF-8 +byte sequence consists of two parts: Marker bits (the most significant +bits) and payload bits. The marker bits are a sequence of zero to six +1 bits followed by a 0 bit. Unicode characters are encoded like this +(with x being payload bits, which when concatenated give the Unicode +character): + +\begin{tableii}{l|l}{textrm}{Range}{Encoding} +\lineii{\code{U-00000000} ... \code{U-0000007F}}{0xxxxxxx} +\lineii{\code{U-00000080} ... \code{U-000007FF}}{110xxxxx 10xxxxxx} +\lineii{\code{U-00000800} ... \code{U-0000FFFF}}{1110xxxx 10xxxxxx 10xxxxxx} +\lineii{\code{U-00010000} ... \code{U-001FFFFF}}{11110xxx 10xxxxxx 10xxxxxx 10xxxxxx} +\lineii{\code{U-00200000} ... \code{U-03FFFFFF}}{111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx} +\lineii{\code{U-04000000} ... \code{U-7FFFFFFF}}{1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx} +\end{tableii} + +The least significant bit of the Unicode character is the rightmost x +bit. + +As UTF-8 is an 8-bit encoding no BOM is required and any \code{U+FEFF} +character in the decoded Unicode string (even if it's the first +character) is treated as a \samp{ZERO WIDTH NO-BREAK SPACE}. + +Without external information it's impossible to reliably determine +which encoding was used for encoding a Unicode string. Each charmap +encoding can decode any random byte sequence. However that's not +possible with UTF-8, as UTF-8 byte sequences have a structure that +doesn't allow arbitrary byte sequence. To increase the reliability +with which a UTF-8 encoding can be detected, Microsoft invented a +variant of UTF-8 (that Python 2.5 calls \code{"utf-8-sig"}) for its Notepad +program: Before any of the Unicode characters is written to the file, +a UTF-8 encoded BOM (which looks like this as a byte sequence: \code{0xef}, +\code{0xbb}, \code{0xbf}) is written. As it's rather improbable that any +charmap encoded file starts with these byte values (which would e.g. map to + + LATIN SMALL LETTER I WITH DIAERESIS \\ + RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK \\ + INVERTED QUESTION MARK + +in iso-8859-1), this increases the probability that a utf-8-sig +encoding can be correctly guessed from the byte sequence. So here the +BOM is not used to be able to determine the byte order used for +generating the byte sequence, but as a signature that helps in +guessing the encoding. On encoding the utf-8-sig codec will write +\code{0xef}, \code{0xbb}, \code{0xbf} as the first three bytes to the file. +On decoding utf-8-sig will skip those three bytes if they appear as the +first three bytes in the file. + + +\subsection{Standard Encodings\label{standard-encodings}} + +Python comes with a number of codecs built-in, either implemented as C +functions or with dictionaries as mapping tables. The following table +lists the codecs by name, together with a few common aliases, and the +languages for which the encoding is likely used. Neither the list of +aliases nor the list of languages is meant to be exhaustive. Notice +that spelling alternatives that only differ in case or use a hyphen +instead of an underscore are also valid aliases. + +Many of the character sets support the same languages. They vary in +individual characters (e.g. whether the EURO SIGN is supported or +not), and in the assignment of characters to code positions. For the +European languages in particular, the following variants typically +exist: + +\begin{itemize} +\item an ISO 8859 codeset +\item a Microsoft Windows code page, which is typically derived from + a 8859 codeset, but replaces control characters with additional + graphic characters +\item an IBM EBCDIC code page +\item an IBM PC code page, which is \ASCII{} compatible +\end{itemize} + +\begin{longtableiii}{l|l|l}{textrm}{Codec}{Aliases}{Languages} + +\lineiii{ascii} + {646, us-ascii} + {English} + +\lineiii{big5} + {big5-tw, csbig5} + {Traditional Chinese} + +\lineiii{big5hkscs} + {big5-hkscs, hkscs} + {Traditional Chinese} + +\lineiii{cp037} + {IBM037, IBM039} + {English} + +\lineiii{cp424} + {EBCDIC-CP-HE, IBM424} + {Hebrew} + +\lineiii{cp437} + {437, IBM437} + {English} + +\lineiii{cp500} + {EBCDIC-CP-BE, EBCDIC-CP-CH, IBM500} + {Western Europe} + +\lineiii{cp737} + {} + {Greek} + +\lineiii{cp775} + {IBM775} + {Baltic languages} + +\lineiii{cp850} + {850, IBM850} + {Western Europe} + +\lineiii{cp852} + {852, IBM852} + {Central and Eastern Europe} + +\lineiii{cp855} + {855, IBM855} + {Bulgarian, Byelorussian, Macedonian, Russian, Serbian} + +\lineiii{cp856} + {} + {Hebrew} + +\lineiii{cp857} + {857, IBM857} + {Turkish} + +\lineiii{cp860} + {860, IBM860} + {Portuguese} + +\lineiii{cp861} + {861, CP-IS, IBM861} + {Icelandic} + +\lineiii{cp862} + {862, IBM862} + {Hebrew} + +\lineiii{cp863} + {863, IBM863} + {Canadian} + +\lineiii{cp864} + {IBM864} + {Arabic} + +\lineiii{cp865} + {865, IBM865} + {Danish, Norwegian} + +\lineiii{cp866} + {866, IBM866} + {Russian} + +\lineiii{cp869} + {869, CP-GR, IBM869} + {Greek} + +\lineiii{cp874} + {} + {Thai} + +\lineiii{cp875} + {} + {Greek} + +\lineiii{cp932} + {932, ms932, mskanji, ms-kanji} + {Japanese} + +\lineiii{cp949} + {949, ms949, uhc} + {Korean} + +\lineiii{cp950} + {950, ms950} + {Traditional Chinese} + +\lineiii{cp1006} + {} + {Urdu} + +\lineiii{cp1026} + {ibm1026} + {Turkish} + +\lineiii{cp1140} + {ibm1140} + {Western Europe} + +\lineiii{cp1250} + {windows-1250} + {Central and Eastern Europe} + +\lineiii{cp1251} + {windows-1251} + {Bulgarian, Byelorussian, Macedonian, Russian, Serbian} + +\lineiii{cp1252} + {windows-1252} + {Western Europe} + +\lineiii{cp1253} + {windows-1253} + {Greek} + +\lineiii{cp1254} + {windows-1254} + {Turkish} + +\lineiii{cp1255} + {windows-1255} + {Hebrew} + +\lineiii{cp1256} + {windows1256} + {Arabic} + +\lineiii{cp1257} + {windows-1257} + {Baltic languages} + +\lineiii{cp1258} + {windows-1258} + {Vietnamese} + +\lineiii{euc_jp} + {eucjp, ujis, u-jis} + {Japanese} + +\lineiii{euc_jis_2004} + {jisx0213, eucjis2004} + {Japanese} + +\lineiii{euc_jisx0213} + {eucjisx0213} + {Japanese} + +\lineiii{euc_kr} + {euckr, korean, ksc5601, ks_c-5601, ks_c-5601-1987, ksx1001, ks_x-1001} + {Korean} + +\lineiii{gb2312} + {chinese, csiso58gb231280, euc-cn, euccn, eucgb2312-cn, gb2312-1980, + gb2312-80, iso-ir-58} + {Simplified Chinese} + +\lineiii{gbk} + {936, cp936, ms936} + {Unified Chinese} + +\lineiii{gb18030} + {gb18030-2000} + {Unified Chinese} + +\lineiii{hz} + {hzgb, hz-gb, hz-gb-2312} + {Simplified Chinese} + +\lineiii{iso2022_jp} + {csiso2022jp, iso2022jp, iso-2022-jp} + {Japanese} + +\lineiii{iso2022_jp_1} + {iso2022jp-1, iso-2022-jp-1} + {Japanese} + +\lineiii{iso2022_jp_2} + {iso2022jp-2, iso-2022-jp-2} + {Japanese, Korean, Simplified Chinese, Western Europe, Greek} + +\lineiii{iso2022_jp_2004} + {iso2022jp-2004, iso-2022-jp-2004} + {Japanese} + +\lineiii{iso2022_jp_3} + {iso2022jp-3, iso-2022-jp-3} + {Japanese} + +\lineiii{iso2022_jp_ext} + {iso2022jp-ext, iso-2022-jp-ext} + {Japanese} + +\lineiii{iso2022_kr} + {csiso2022kr, iso2022kr, iso-2022-kr} + {Korean} + +\lineiii{latin_1} + {iso-8859-1, iso8859-1, 8859, cp819, latin, latin1, L1} + {West Europe} + +\lineiii{iso8859_2} + {iso-8859-2, latin2, L2} + {Central and Eastern Europe} + +\lineiii{iso8859_3} + {iso-8859-3, latin3, L3} + {Esperanto, Maltese} + +\lineiii{iso8859_4} + {iso-8859-4, latin4, L4} + {Baltic languagues} + +\lineiii{iso8859_5} + {iso-8859-5, cyrillic} + {Bulgarian, Byelorussian, Macedonian, Russian, Serbian} + +\lineiii{iso8859_6} + {iso-8859-6, arabic} + {Arabic} + +\lineiii{iso8859_7} + {iso-8859-7, greek, greek8} + {Greek} + +\lineiii{iso8859_8} + {iso-8859-8, hebrew} + {Hebrew} + +\lineiii{iso8859_9} + {iso-8859-9, latin5, L5} + {Turkish} + +\lineiii{iso8859_10} + {iso-8859-10, latin6, L6} + {Nordic languages} + +\lineiii{iso8859_13} + {iso-8859-13} + {Baltic languages} + +\lineiii{iso8859_14} + {iso-8859-14, latin8, L8} + {Celtic languages} + +\lineiii{iso8859_15} + {iso-8859-15} + {Western Europe} + +\lineiii{johab} + {cp1361, ms1361} + {Korean} + +\lineiii{koi8_r} + {} + {Russian} + +\lineiii{koi8_u} + {} + {Ukrainian} + +\lineiii{mac_cyrillic} + {maccyrillic} + {Bulgarian, Byelorussian, Macedonian, Russian, Serbian} + +\lineiii{mac_greek} + {macgreek} + {Greek} + +\lineiii{mac_iceland} + {maciceland} + {Icelandic} + +\lineiii{mac_latin2} + {maclatin2, maccentraleurope} + {Central and Eastern Europe} + +\lineiii{mac_roman} + {macroman} + {Western Europe} + +\lineiii{mac_turkish} + {macturkish} + {Turkish} + +\lineiii{ptcp154} + {csptcp154, pt154, cp154, cyrillic-asian} + {Kazakh} + +\lineiii{shift_jis} + {csshiftjis, shiftjis, sjis, s_jis} + {Japanese} + +\lineiii{shift_jis_2004} + {shiftjis2004, sjis_2004, sjis2004} + {Japanese} + +\lineiii{shift_jisx0213} + {shiftjisx0213, sjisx0213, s_jisx0213} + {Japanese} + +\lineiii{utf_16} + {U16, utf16} + {all languages} + +\lineiii{utf_16_be} + {UTF-16BE} + {all languages (BMP only)} + +\lineiii{utf_16_le} + {UTF-16LE} + {all languages (BMP only)} + +\lineiii{utf_7} + {U7, unicode-1-1-utf-7} + {all languages} + +\lineiii{utf_8} + {U8, UTF, utf8} + {all languages} + +\lineiii{utf_8_sig} + {} + {all languages} + +\end{longtableiii} + +A number of codecs are specific to Python, so their codec names have +no meaning outside Python. Some of them don't convert from Unicode +strings to byte strings, but instead use the property of the Python +codecs machinery that any bijective function with one argument can be +considered as an encoding. + +For the codecs listed below, the result in the ``encoding'' direction +is always a byte string. The result of the ``decoding'' direction is +listed as operand type in the table. + +\begin{tableiv}{l|l|l|l}{textrm}{Codec}{Aliases}{Operand type}{Purpose} + +\lineiv{base64_codec} + {base64, base-64} + {byte string} + {Convert operand to MIME base64} + +\lineiv{bz2_codec} + {bz2} + {byte string} + {Compress the operand using bz2} + +\lineiv{hex_codec} + {hex} + {byte string} + {Convert operand to hexadecimal representation, with two + digits per byte} + +\lineiv{idna} + {} + {Unicode string} + {Implements \rfc{3490}. + \versionadded{2.3} + See also \refmodule{encodings.idna}} + +\lineiv{mbcs} + {dbcs} + {Unicode string} + {Windows only: Encode operand according to the ANSI codepage (CP_ACP)} + +\lineiv{palmos} + {} + {Unicode string} + {Encoding of PalmOS 3.5} + +\lineiv{punycode} + {} + {Unicode string} + {Implements \rfc{3492}. + \versionadded{2.3}} + +\lineiv{quopri_codec} + {quopri, quoted-printable, quotedprintable} + {byte string} + {Convert operand to MIME quoted printable} + +\lineiv{raw_unicode_escape} + {} + {Unicode string} + {Produce a string that is suitable as raw Unicode literal in + Python source code} + +\lineiv{rot_13} + {rot13} + {Unicode string} + {Returns the Caesar-cypher encryption of the operand} + +\lineiv{string_escape} + {} + {byte string} + {Produce a string that is suitable as string literal in + Python source code} + +\lineiv{undefined} + {} + {any} + {Raise an exception for all conversions. Can be used as the + system encoding if no automatic coercion between byte and + Unicode strings is desired.} + +\lineiv{unicode_escape} + {} + {Unicode string} + {Produce a string that is suitable as Unicode literal in + Python source code} + +\lineiv{unicode_internal} + {} + {Unicode string} + {Return the internal representation of the operand} + +\lineiv{uu_codec} + {uu} + {byte string} + {Convert the operand using uuencode} + +\lineiv{zlib_codec} + {zip, zlib} + {byte string} + {Compress the operand using gzip} + +\end{tableiv} + +\subsection{\module{encodings.idna} --- + Internationalized Domain Names in Applications} + +\declaremodule{standard}{encodings.idna} +\modulesynopsis{Internationalized Domain Names implementation} +% XXX The next line triggers a formatting bug, so it's commented out +% until that can be fixed. +%\moduleauthor{Martin v. L\"owis} + +\versionadded{2.3} + +This module implements \rfc{3490} (Internationalized Domain Names in +Applications) and \rfc{3492} (Nameprep: A Stringprep Profile for +Internationalized Domain Names (IDN)). It builds upon the +\code{punycode} encoding and \refmodule{stringprep}. + +These RFCs together define a protocol to support non-\ASCII{} characters +in domain names. A domain name containing non-\ASCII{} characters (such +as ``www.Alliancefran\c caise.nu'') is converted into an +\ASCII-compatible encoding (ACE, such as +``www.xn--alliancefranaise-npb.nu''). The ACE form of the domain name +is then used in all places where arbitrary characters are not allowed +by the protocol, such as DNS queries, HTTP \mailheader{Host} fields, and so +on. This conversion is carried out in the application; if possible +invisible to the user: The application should transparently convert +Unicode domain labels to IDNA on the wire, and convert back ACE labels +to Unicode before presenting them to the user. + +Python supports this conversion in several ways: The \code{idna} codec +allows to convert between Unicode and the ACE. Furthermore, the +\refmodule{socket} module transparently converts Unicode host names to +ACE, so that applications need not be concerned about converting host +names themselves when they pass them to the socket module. On top of +that, modules that have host names as function parameters, such as +\refmodule{httplib} and \refmodule{ftplib}, accept Unicode host names +(\refmodule{httplib} then also transparently sends an IDNA hostname in +the \mailheader{Host} field if it sends that field at all). + +When receiving host names from the wire (such as in reverse name +lookup), no automatic conversion to Unicode is performed: Applications +wishing to present such host names to the user should decode them to +Unicode. + +The module \module{encodings.idna} also implements the nameprep +procedure, which performs certain normalizations on host names, to +achieve case-insensitivity of international domain names, and to unify +similar characters. The nameprep functions can be used directly if +desired. + +\begin{funcdesc}{nameprep}{label} +Return the nameprepped version of \var{label}. The implementation +currently assumes query strings, so \code{AllowUnassigned} is +true. +\end{funcdesc} + +\begin{funcdesc}{ToASCII}{label} +Convert a label to \ASCII, as specified in \rfc{3490}. +\code{UseSTD3ASCIIRules} is assumed to be false. +\end{funcdesc} + +\begin{funcdesc}{ToUnicode}{label} +Convert a label to Unicode, as specified in \rfc{3490}. +\end{funcdesc} + + \subsection{\module{encodings.utf_8_sig} --- + UTF-8 codec with BOM signature} +\declaremodule{standard}{encodings.utf-8-sig} % XXX utf_8_sig gives TeX errors +\modulesynopsis{UTF-8 codec with BOM signature} +\moduleauthor{Walter D\"orwald}{} + +\versionadded{2.5} + +This module implements a variant of the UTF-8 codec: On encoding a +UTF-8 encoded BOM will be prepended to the UTF-8 encoded bytes. For +the stateful encoder this is only done once (on the first write to the +byte stream). For decoding an optional UTF-8 encoded BOM at the start +of the data will be skipped. diff --git a/sys/src/cmd/python/Doc/lib/libcodeop.tex b/sys/src/cmd/python/Doc/lib/libcodeop.tex new file mode 100644 index 000000000..6972b6f5a --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcodeop.tex @@ -0,0 +1,103 @@ +\section{\module{codeop} --- + Compile Python code} + +% LaTeXed from excellent doc-string. + +\declaremodule{standard}{codeop} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\sectionauthor{Michael Hudson}{mwh@python.net} +\modulesynopsis{Compile (possibly incomplete) Python code.} + +The \module{codeop} module provides utilities upon which the Python +read-eval-print loop can be emulated, as is done in the +\refmodule{code} module. As a result, you probably don't want to use +the module directly; if you want to include such a loop in your +program you probably want to use the \refmodule{code} module instead. + +There are two parts to this job: + +\begin{enumerate} + \item Being able to tell if a line of input completes a Python + statement: in short, telling whether to print + `\code{>>>~}' or `\code{...~}' next. + \item Remembering which future statements the user has entered, so + subsequent input can be compiled with these in effect. +\end{enumerate} + +The \module{codeop} module provides a way of doing each of these +things, and a way of doing them both. + +To do just the former: + +\begin{funcdesc}{compile_command} + {source\optional{, filename\optional{, symbol}}} +Tries to compile \var{source}, which should be a string of Python +code and return a code object if \var{source} is valid +Python code. In that case, the filename attribute of the code object +will be \var{filename}, which defaults to \code{''}. +Returns \code{None} if \var{source} is \emph{not} valid Python +code, but is a prefix of valid Python code. + +If there is a problem with \var{source}, an exception will be raised. +\exception{SyntaxError} is raised if there is invalid Python syntax, +and \exception{OverflowError} or \exception{ValueError} if there is an +invalid literal. + +The \var{symbol} argument determines whether \var{source} is compiled +as a statement (\code{'single'}, the default) or as an expression +(\code{'eval'}). Any other value will cause \exception{ValueError} to +be raised. + +\strong{Caveat:} +It is possible (but not likely) that the parser stops parsing +with a successful outcome before reaching the end of the source; +in this case, trailing symbols may be ignored instead of causing an +error. For example, a backslash followed by two newlines may be +followed by arbitrary garbage. This will be fixed once the API +for the parser is better. +\end{funcdesc} + +\begin{classdesc}{Compile}{} +Instances of this class have \method{__call__()} methods identical in +signature to the built-in function \function{compile()}, but with the +difference that if the instance compiles program text containing a +\module{__future__} statement, the instance 'remembers' and compiles +all subsequent program texts with the statement in force. +\end{classdesc} + +\begin{classdesc}{CommandCompiler}{} +Instances of this class have \method{__call__()} methods identical in +signature to \function{compile_command()}; the difference is that if +the instance compiles program text containing a \code{__future__} +statement, the instance 'remembers' and compiles all subsequent +program texts with the statement in force. +\end{classdesc} + +A note on version compatibility: the \class{Compile} and +\class{CommandCompiler} are new in Python 2.2. If you want to enable +the future-tracking features of 2.2 but also retain compatibility with +2.1 and earlier versions of Python you can either write + +\begin{verbatim} +try: + from codeop import CommandCompiler + compile_command = CommandCompiler() + del CommandCompiler +except ImportError: + from codeop import compile_command +\end{verbatim} + +which is a low-impact change, but introduces possibly unwanted global +state into your program, or you can write: + +\begin{verbatim} +try: + from codeop import CommandCompiler +except ImportError: + def CommandCompiler(): + from codeop import compile_command + return compile_command +\end{verbatim} + +and then call \code{CommandCompiler} every time you need a fresh +compiler object. diff --git a/sys/src/cmd/python/Doc/lib/libcollections.tex b/sys/src/cmd/python/Doc/lib/libcollections.tex new file mode 100644 index 000000000..13a96958c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcollections.tex @@ -0,0 +1,341 @@ +\section{\module{collections} --- + High-performance container datatypes} + +\declaremodule{standard}{collections} +\modulesynopsis{High-performance datatypes} +\moduleauthor{Raymond Hettinger}{python@rcn.com} +\sectionauthor{Raymond Hettinger}{python@rcn.com} +\versionadded{2.4} + + +This module implements high-performance container datatypes. Currently, +there are two datatypes, deque and defaultdict. +Future additions may include balanced trees and ordered dictionaries. +\versionchanged[Added defaultdict]{2.5} + +\subsection{\class{deque} objects \label{deque-objects}} + +\begin{funcdesc}{deque}{\optional{iterable}} + Returns a new deque object initialized left-to-right (using + \method{append()}) with data from \var{iterable}. If \var{iterable} + is not specified, the new deque is empty. + + Deques are a generalization of stacks and queues (the name is pronounced + ``deck'' and is short for ``double-ended queue''). Deques support + thread-safe, memory efficient appends and pops from either side of the deque + with approximately the same \code{O(1)} performance in either direction. + + Though \class{list} objects support similar operations, they are optimized + for fast fixed-length operations and incur \code{O(n)} memory movement costs + for \samp{pop(0)} and \samp{insert(0, v)} operations which change both the + size and position of the underlying data representation. + \versionadded{2.4} +\end{funcdesc} + +Deque objects support the following methods: + +\begin{methoddesc}{append}{x} + Add \var{x} to the right side of the deque. +\end{methoddesc} + +\begin{methoddesc}{appendleft}{x} + Add \var{x} to the left side of the deque. +\end{methoddesc} + +\begin{methoddesc}{clear}{} + Remove all elements from the deque leaving it with length 0. +\end{methoddesc} + +\begin{methoddesc}{extend}{iterable} + Extend the right side of the deque by appending elements from + the iterable argument. +\end{methoddesc} + +\begin{methoddesc}{extendleft}{iterable} + Extend the left side of the deque by appending elements from + \var{iterable}. Note, the series of left appends results in + reversing the order of elements in the iterable argument. +\end{methoddesc} + +\begin{methoddesc}{pop}{} + Remove and return an element from the right side of the deque. + If no elements are present, raises an \exception{IndexError}. +\end{methoddesc} + +\begin{methoddesc}{popleft}{} + Remove and return an element from the left side of the deque. + If no elements are present, raises an \exception{IndexError}. +\end{methoddesc} + +\begin{methoddesc}{remove}{value} + Removed the first occurrence of \var{value}. If not found, + raises a \exception{ValueError}. + \versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}{rotate}{n} + Rotate the deque \var{n} steps to the right. If \var{n} is + negative, rotate to the left. Rotating one step to the right + is equivalent to: \samp{d.appendleft(d.pop())}. +\end{methoddesc} + +In addition to the above, deques support iteration, pickling, \samp{len(d)}, +\samp{reversed(d)}, \samp{copy.copy(d)}, \samp{copy.deepcopy(d)}, +membership testing with the \keyword{in} operator, and subscript references +such as \samp{d[-1]}. + +Example: + +\begin{verbatim} +>>> from collections import deque +>>> d = deque('ghi') # make a new deque with three items +>>> for elem in d: # iterate over the deque's elements +... print elem.upper() +G +H +I + +>>> d.append('j') # add a new entry to the right side +>>> d.appendleft('f') # add a new entry to the left side +>>> d # show the representation of the deque +deque(['f', 'g', 'h', 'i', 'j']) + +>>> d.pop() # return and remove the rightmost item +'j' +>>> d.popleft() # return and remove the leftmost item +'f' +>>> list(d) # list the contents of the deque +['g', 'h', 'i'] +>>> d[0] # peek at leftmost item +'g' +>>> d[-1] # peek at rightmost item +'i' + +>>> list(reversed(d)) # list the contents of a deque in reverse +['i', 'h', 'g'] +>>> 'h' in d # search the deque +True +>>> d.extend('jkl') # add multiple elements at once +>>> d +deque(['g', 'h', 'i', 'j', 'k', 'l']) +>>> d.rotate(1) # right rotation +>>> d +deque(['l', 'g', 'h', 'i', 'j', 'k']) +>>> d.rotate(-1) # left rotation +>>> d +deque(['g', 'h', 'i', 'j', 'k', 'l']) + +>>> deque(reversed(d)) # make a new deque in reverse order +deque(['l', 'k', 'j', 'i', 'h', 'g']) +>>> d.clear() # empty the deque +>>> d.pop() # cannot pop from an empty deque +Traceback (most recent call last): + File "", line 1, in -toplevel- + d.pop() +IndexError: pop from an empty deque + +>>> d.extendleft('abc') # extendleft() reverses the input order +>>> d +deque(['c', 'b', 'a']) +\end{verbatim} + +\subsubsection{Recipes \label{deque-recipes}} + +This section shows various approaches to working with deques. + +The \method{rotate()} method provides a way to implement \class{deque} +slicing and deletion. For example, a pure python implementation of +\code{del d[n]} relies on the \method{rotate()} method to position +elements to be popped: + +\begin{verbatim} +def delete_nth(d, n): + d.rotate(-n) + d.popleft() + d.rotate(n) +\end{verbatim} + +To implement \class{deque} slicing, use a similar approach applying +\method{rotate()} to bring a target element to the left side of the deque. +Remove old entries with \method{popleft()}, add new entries with +\method{extend()}, and then reverse the rotation. + +With minor variations on that approach, it is easy to implement Forth style +stack manipulations such as \code{dup}, \code{drop}, \code{swap}, \code{over}, +\code{pick}, \code{rot}, and \code{roll}. + +A roundrobin task server can be built from a \class{deque} using +\method{popleft()} to select the current task and \method{append()} +to add it back to the tasklist if the input stream is not exhausted: + +\begin{verbatim} +def roundrobin(*iterables): + pending = deque(iter(i) for i in iterables) + while pending: + task = pending.popleft() + try: + yield task.next() + except StopIteration: + continue + pending.append(task) + +>>> for value in roundrobin('abc', 'd', 'efgh'): +... print value + +a +d +e +b +f +c +g +h + +\end{verbatim} + + +Multi-pass data reduction algorithms can be succinctly expressed and +efficiently coded by extracting elements with multiple calls to +\method{popleft()}, applying the reduction function, and calling +\method{append()} to add the result back to the queue. + +For example, building a balanced binary tree of nested lists entails +reducing two adjacent nodes into one by grouping them in a list: + +\begin{verbatim} +def maketree(iterable): + d = deque(iterable) + while len(d) > 1: + pair = [d.popleft(), d.popleft()] + d.append(pair) + return list(d) + +>>> print maketree('abcdefgh') +[[[['a', 'b'], ['c', 'd']], [['e', 'f'], ['g', 'h']]]] + +\end{verbatim} + + + +\subsection{\class{defaultdict} objects \label{defaultdict-objects}} + +\begin{funcdesc}{defaultdict}{\optional{default_factory\optional{, ...}}} + Returns a new dictionary-like object. \class{defaultdict} is a subclass + of the builtin \class{dict} class. It overrides one method and adds one + writable instance variable. The remaining functionality is the same as + for the \class{dict} class and is not documented here. + + The first argument provides the initial value for the + \member{default_factory} attribute; it defaults to \code{None}. + All remaining arguments are treated the same as if they were + passed to the \class{dict} constructor, including keyword arguments. + + \versionadded{2.5} +\end{funcdesc} + +\class{defaultdict} objects support the following method in addition to +the standard \class{dict} operations: + +\begin{methoddesc}{__missing__}{key} + If the \member{default_factory} attribute is \code{None}, this raises + an \exception{KeyError} exception with the \var{key} as argument. + + If \member{default_factory} is not \code{None}, it is called without + arguments to provide a default value for the given \var{key}, this + value is inserted in the dictionary for the \var{key}, and returned. + + If calling \member{default_factory} raises an exception this exception + is propagated unchanged. + + This method is called by the \method{__getitem__} method of the + \class{dict} class when the requested key is not found; whatever it + returns or raises is then returned or raised by \method{__getitem__}. +\end{methoddesc} + +\class{defaultdict} objects support the following instance variable: + +\begin{datadesc}{default_factory} + This attribute is used by the \method{__missing__} method; it is initialized + from the first argument to the constructor, if present, or to \code{None}, + if absent. +\end{datadesc} + + +\subsubsection{\class{defaultdict} Examples \label{defaultdict-examples}} + +Using \class{list} as the \member{default_factory}, it is easy to group +a sequence of key-value pairs into a dictionary of lists: + +\begin{verbatim} +>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)] +>>> d = defaultdict(list) +>>> for k, v in s: + d[k].append(v) + +>>> d.items() +[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])] +\end{verbatim} + +When each key is encountered for the first time, it is not already in the +mapping; so an entry is automatically created using the +\member{default_factory} function which returns an empty \class{list}. The +\method{list.append()} operation then attaches the value to the new list. When +keys are encountered again, the look-up proceeds normally (returning the list +for that key) and the \method{list.append()} operation adds another value to +the list. This technique is simpler and faster than an equivalent technique +using \method{dict.setdefault()}: + +\begin{verbatim} +>>> d = {} +>>> for k, v in s: + d.setdefault(k, []).append(v) + +>>> d.items() +[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])] +\end{verbatim} + +Setting the \member{default_factory} to \class{int} makes the +\class{defaultdict} useful for counting (like a bag or multiset in other +languages): + +\begin{verbatim} +>>> s = 'mississippi' +>>> d = defaultdict(int) +>>> for k in s: + d[k] += 1 + +>>> d.items() +[('i', 4), ('p', 2), ('s', 4), ('m', 1)] +\end{verbatim} + +When a letter is first encountered, it is missing from the mapping, so the +\member{default_factory} function calls \function{int()} to supply a default +count of zero. The increment operation then builds up the count for each +letter. + +The function \function{int()} which always returns zero is just a special +case of constant functions. A faster and more flexible way to create +constant functions is to use \function{itertools.repeat()} which can supply +any constant value (not just zero): + +\begin{verbatim} +>>> def constant_factory(value): +... return itertools.repeat(value).next +>>> d = defaultdict(constant_factory('')) +>>> d.update(name='John', action='ran') +>>> '%(name)s %(action)s to %(object)s' % d +'John ran to ' +\end{verbatim} + +Setting the \member{default_factory} to \class{set} makes the +\class{defaultdict} useful for building a dictionary of sets: + +\begin{verbatim} +>>> s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)] +>>> d = defaultdict(set) +>>> for k, v in s: + d[k].add(v) + +>>> d.items() +[('blue', set([2, 4])), ('red', set([1, 3]))] +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libcolorsys.tex b/sys/src/cmd/python/Doc/lib/libcolorsys.tex new file mode 100644 index 000000000..274837733 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcolorsys.tex @@ -0,0 +1,54 @@ +\section{\module{colorsys} --- + Conversions between color systems} + +\declaremodule{standard}{colorsys} +\modulesynopsis{Conversion functions between RGB and other color systems.} +\sectionauthor{David Ascher}{da@python.net} + +The \module{colorsys} module defines bidirectional conversions of +color values between colors expressed in the RGB (Red Green Blue) +color space used in computer monitors and three other coordinate +systems: YIQ, HLS (Hue Lightness Saturation) and HSV (Hue Saturation +Value). Coordinates in all of these color spaces are floating point +values. In the YIQ space, the Y coordinate is between 0 and 1, but +the I and Q coordinates can be positive or negative. In all other +spaces, the coordinates are all between 0 and 1. + +More information about color spaces can be found at +\url{http://www.poynton.com/ColorFAQ.html}. + +The \module{colorsys} module defines the following functions: + +\begin{funcdesc}{rgb_to_yiq}{r, g, b} +Convert the color from RGB coordinates to YIQ coordinates. +\end{funcdesc} + +\begin{funcdesc}{yiq_to_rgb}{y, i, q} +Convert the color from YIQ coordinates to RGB coordinates. +\end{funcdesc} + +\begin{funcdesc}{rgb_to_hls}{r, g, b} +Convert the color from RGB coordinates to HLS coordinates. +\end{funcdesc} + +\begin{funcdesc}{hls_to_rgb}{h, l, s} +Convert the color from HLS coordinates to RGB coordinates. +\end{funcdesc} + +\begin{funcdesc}{rgb_to_hsv}{r, g, b} +Convert the color from RGB coordinates to HSV coordinates. +\end{funcdesc} + +\begin{funcdesc}{hsv_to_rgb}{h, s, v} +Convert the color from HSV coordinates to RGB coordinates. +\end{funcdesc} + +Example: + +\begin{verbatim} +>>> import colorsys +>>> colorsys.rgb_to_hsv(.3, .4, .2) +(0.25, 0.5, 0.4) +>>> colorsys.hsv_to_rgb(0.25, 0.5, 0.4) +(0.3, 0.4, 0.2) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libcommands.tex b/sys/src/cmd/python/Doc/lib/libcommands.tex new file mode 100644 index 000000000..53b8a2070 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcommands.tex @@ -0,0 +1,62 @@ +\section{\module{commands} --- + Utilities for running commands} + +\declaremodule{standard}{commands} + \platform{Unix} +\modulesynopsis{Utility functions for running external commands.} +\sectionauthor{Sue Williams}{sbw@provis.com} + + +The \module{commands} module contains wrapper functions for +\function{os.popen()} which take a system command as a string and +return any output generated by the command and, optionally, the exit +status. + +The \module{subprocess} module provides more powerful facilities for +spawning new processes and retrieving their results. Using the +\module{subprocess} module is preferable to using the \module{commands} +module. + +The \module{commands} module defines the following functions: + + +\begin{funcdesc}{getstatusoutput}{cmd} +Execute the string \var{cmd} in a shell with \function{os.popen()} and +return a 2-tuple \code{(\var{status}, \var{output})}. \var{cmd} is +actually run as \code{\{ \var{cmd} ; \} 2>\&1}, so that the returned +output will contain output or error messages. A trailing newline is +stripped from the output. The exit status for the command can be +interpreted according to the rules for the C function +\cfunction{wait()}. +\end{funcdesc} + +\begin{funcdesc}{getoutput}{cmd} +Like \function{getstatusoutput()}, except the exit status is ignored +and the return value is a string containing the command's output. +\end{funcdesc} + +\begin{funcdesc}{getstatus}{file} +Return the output of \samp{ls -ld \var{file}} as a string. This +function uses the \function{getoutput()} function, and properly +escapes backslashes and dollar signs in the argument. +\end{funcdesc} + +Example: + +\begin{verbatim} +>>> import commands +>>> commands.getstatusoutput('ls /bin/ls') +(0, '/bin/ls') +>>> commands.getstatusoutput('cat /bin/junk') +(256, 'cat: /bin/junk: No such file or directory') +>>> commands.getstatusoutput('/bin/junk') +(256, 'sh: /bin/junk: not found') +>>> commands.getoutput('ls /bin/ls') +'/bin/ls' +>>> commands.getstatus('/bin/ls') +'-rwxr-xr-x 1 root 13352 Oct 14 1994 /bin/ls' +\end{verbatim} + +\begin{seealso} + \seemodule{subprocess}{Module for spawning and managing subprocesses.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libcompileall.tex b/sys/src/cmd/python/Doc/lib/libcompileall.tex new file mode 100644 index 000000000..3e9667d9e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcompileall.tex @@ -0,0 +1,63 @@ +\section{\module{compileall} --- + Byte-compile Python libraries} + +\declaremodule{standard}{compileall} +\modulesynopsis{Tools for byte-compiling all Python source files in a + directory tree.} + + +This module provides some utility functions to support installing +Python libraries. These functions compile Python source files in a +directory tree, allowing users without permission to write to the +libraries to take advantage of cached byte-code files. + +The source file for this module may also be used as a script to +compile Python sources in directories named on the command line or in +\code{sys.path}. + + +\begin{funcdesc}{compile_dir}{dir\optional{, maxlevels\optional{, + ddir\optional{, force\optional{, + rx\optional{, quiet}}}}}} + Recursively descend the directory tree named by \var{dir}, compiling + all \file{.py} files along the way. The \var{maxlevels} parameter + is used to limit the depth of the recursion; it defaults to + \code{10}. If \var{ddir} is given, it is used as the base path from + which the filenames used in error messages will be generated. If + \var{force} is true, modules are re-compiled even if the timestamps + are up to date. + + If \var{rx} is given, it specifies a regular expression of file + names to exclude from the search; that expression is searched for in + the full path. + + If \var{quiet} is true, nothing is printed to the standard output + in normal operation. +\end{funcdesc} + +\begin{funcdesc}{compile_path}{\optional{skip_curdir\optional{, + maxlevels\optional{, force}}}} + Byte-compile all the \file{.py} files found along \code{sys.path}. + If \var{skip_curdir} is true (the default), the current directory is + not included in the search. The \var{maxlevels} and + \var{force} parameters default to \code{0} and are passed to the + \function{compile_dir()} function. +\end{funcdesc} + +To force a recompile of all the \file{.py} files in the \file{Lib/} +subdirectory and all its subdirectories: + +\begin{verbatim} +import compileall + +compileall.compile_dir('Lib/', force=True) + +# Perform same compilation, excluding files in .svn directories. +import re +compileall.compile_dir('Lib/', rx=re.compile('/[.]svn'), force=True) +\end{verbatim} + + +\begin{seealso} + \seemodule[pycompile]{py_compile}{Byte-compile a single source file.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libconsts.tex b/sys/src/cmd/python/Doc/lib/libconsts.tex new file mode 100644 index 000000000..a7b449837 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libconsts.tex @@ -0,0 +1,31 @@ +\section{Built-in Constants} + +A small number of constants live in the built-in namespace. They are: + +\begin{datadesc}{False} + The false value of the \class{bool} type. + \versionadded{2.3} +\end{datadesc} + +\begin{datadesc}{True} + The true value of the \class{bool} type. + \versionadded{2.3} +\end{datadesc} + +\begin{datadesc}{None} + The sole value of \code{\refmodule{types}.NoneType}. \code{None} is + frequently used to represent the absence of a value, as when default + arguments are not passed to a function. +\end{datadesc} + +\begin{datadesc}{NotImplemented} + Special value which can be returned by the ``rich comparison'' + special methods (\method{__eq__()}, \method{__lt__()}, and friends), + to indicate that the comparison is not implemented with respect to + the other type. +\end{datadesc} + +\begin{datadesc}{Ellipsis} + Special value used in conjunction with extended slicing syntax. + % XXX Someone who understands extended slicing should fill in here. +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/libcontextlib.tex b/sys/src/cmd/python/Doc/lib/libcontextlib.tex new file mode 100644 index 000000000..72bf53716 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcontextlib.tex @@ -0,0 +1,130 @@ +\section{\module{contextlib} --- + Utilities for \keyword{with}-statement contexts.} + +\declaremodule{standard}{contextlib} +\modulesynopsis{Utilities for \keyword{with}-statement contexts.} + +\versionadded{2.5} + +This module provides utilities for common tasks involving the +\keyword{with} statement. + +Functions provided: + +\begin{funcdesc}{contextmanager}{func} +This function is a decorator that can be used to define a factory +function for \keyword{with} statement context managers, without +needing to create a class or separate \method{__enter__()} and +\method{__exit__()} methods. + +A simple example (this is not recommended as a real way of +generating HTML!): + +\begin{verbatim} +from __future__ import with_statement +from contextlib import contextmanager + +@contextmanager +def tag(name): + print "<%s>" % name + yield + print "" % name + +>>> with tag("h1"): +... print "foo" +... +

+foo +

+\end{verbatim} + +The function being decorated must return a generator-iterator when +called. This iterator must yield exactly one value, which will be +bound to the targets in the \keyword{with} statement's \keyword{as} +clause, if any. + +At the point where the generator yields, the block nested in the +\keyword{with} statement is executed. The generator is then resumed +after the block is exited. If an unhandled exception occurs in the +block, it is reraised inside the generator at the point where the yield +occurred. Thus, you can use a +\keyword{try}...\keyword{except}...\keyword{finally} statement to trap +the error (if any), or ensure that some cleanup takes place. If an +exception is trapped merely in order to log it or to perform some +action (rather than to suppress it entirely), the generator must +reraise that exception. Otherwise the generator context manager will +indicate to the \keyword{with} statement that the exception has been +handled, and execution will resume with the statement immediately +following the \keyword{with} statement. +\end{funcdesc} + +\begin{funcdesc}{nested}{mgr1\optional{, mgr2\optional{, ...}}} +Combine multiple context managers into a single nested context manager. + +Code like this: + +\begin{verbatim} +from contextlib import nested + +with nested(A, B, C) as (X, Y, Z): + do_something() +\end{verbatim} + +is equivalent to this: + +\begin{verbatim} +with A as X: + with B as Y: + with C as Z: + do_something() +\end{verbatim} + +Note that if the \method{__exit__()} method of one of the nested +context managers indicates an exception should be suppressed, no +exception information will be passed to any remaining outer context +managers. Similarly, if the \method{__exit__()} method of one of the +nested managers raises an exception, any previous exception state will +be lost; the new exception will be passed to the +\method{__exit__()} methods of any remaining outer context managers. +In general, \method{__exit__()} methods should avoid raising +exceptions, and in particular they should not re-raise a +passed-in exception. +\end{funcdesc} + +\label{context-closing} +\begin{funcdesc}{closing}{thing} +Return a context manager that closes \var{thing} upon completion of +the block. This is basically equivalent to: + +\begin{verbatim} +from contextlib import contextmanager + +@contextmanager +def closing(thing): + try: + yield thing + finally: + thing.close() +\end{verbatim} + +And lets you write code like this: +\begin{verbatim} +from __future__ import with_statement +from contextlib import closing +import codecs + +with closing(urllib.urlopen('http://www.python.org')) as page: + for line in page: + print line +\end{verbatim} + +without needing to explicitly close \code{page}. Even if an error +occurs, \code{page.close()} will be called when the \keyword{with} +block is exited. +\end{funcdesc} + +\begin{seealso} + \seepep{0343}{The "with" statement} + {The specification, background, and examples for the + Python \keyword{with} statement.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libcookie.tex b/sys/src/cmd/python/Doc/lib/libcookie.tex new file mode 100644 index 000000000..e5d2038e2 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcookie.tex @@ -0,0 +1,260 @@ +\section{\module{Cookie} --- + HTTP state management} + +\declaremodule{standard}{Cookie} +\modulesynopsis{Support for HTTP state management (cookies).} +\moduleauthor{Timothy O'Malley}{timo@alum.mit.edu} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} + + +The \module{Cookie} module defines classes for abstracting the concept of +cookies, an HTTP state management mechanism. It supports both simple +string-only cookies, and provides an abstraction for having any serializable +data-type as cookie value. + +The module formerly strictly applied the parsing rules described in +the \rfc{2109} and \rfc{2068} specifications. It has since been discovered +that MSIE 3.0x doesn't follow the character rules outlined in those +specs. As a result, the parsing rules used are a bit less strict. + +\begin{excdesc}{CookieError} +Exception failing because of \rfc{2109} invalidity: incorrect +attributes, incorrect \mailheader{Set-Cookie} header, etc. +\end{excdesc} + +\begin{classdesc}{BaseCookie}{\optional{input}} +This class is a dictionary-like object whose keys are strings and +whose values are \class{Morsel} instances. Note that upon setting a key to +a value, the value is first converted to a \class{Morsel} containing +the key and the value. + +If \var{input} is given, it is passed to the \method{load()} method. +\end{classdesc} + +\begin{classdesc}{SimpleCookie}{\optional{input}} +This class derives from \class{BaseCookie} and overrides +\method{value_decode()} and \method{value_encode()} to be the identity +and \function{str()} respectively. +\end{classdesc} + +\begin{classdesc}{SerialCookie}{\optional{input}} +This class derives from \class{BaseCookie} and overrides +\method{value_decode()} and \method{value_encode()} to be the +\function{pickle.loads()} and \function{pickle.dumps()}. + +\deprecated{2.3}{Reading pickled values from untrusted +cookie data is a huge security hole, as pickle strings can be crafted +to cause arbitrary code to execute on your server. It is supported +for backwards compatibility only, and may eventually go away.} +\end{classdesc} + +\begin{classdesc}{SmartCookie}{\optional{input}} +This class derives from \class{BaseCookie}. It overrides +\method{value_decode()} to be \function{pickle.loads()} if it is a +valid pickle, and otherwise the value itself. It overrides +\method{value_encode()} to be \function{pickle.dumps()} unless it is a +string, in which case it returns the value itself. + +\deprecated{2.3}{The same security warning from \class{SerialCookie} +applies here.} +\end{classdesc} + +A further security note is warranted. For backwards compatibility, +the \module{Cookie} module exports a class named \class{Cookie} which +is just an alias for \class{SmartCookie}. This is probably a mistake +and will likely be removed in a future version. You should not use +the \class{Cookie} class in your applications, for the same reason why +you should not use the \class{SerialCookie} class. + + +\begin{seealso} + \seemodule{cookielib}{HTTP cookie handling for web + \emph{clients}. The \module{cookielib} and \module{Cookie} + modules do not depend on each other.} + + \seerfc{2109}{HTTP State Management Mechanism}{This is the state + management specification implemented by this module.} +\end{seealso} + + +\subsection{Cookie Objects \label{cookie-objects}} + +\begin{methoddesc}[BaseCookie]{value_decode}{val} +Return a decoded value from a string representation. Return value can +be any type. This method does nothing in \class{BaseCookie} --- it exists +so it can be overridden. +\end{methoddesc} + +\begin{methoddesc}[BaseCookie]{value_encode}{val} +Return an encoded value. \var{val} can be any type, but return value +must be a string. This method does nothing in \class{BaseCookie} --- it exists +so it can be overridden + +In general, it should be the case that \method{value_encode()} and +\method{value_decode()} are inverses on the range of \var{value_decode}. +\end{methoddesc} + +\begin{methoddesc}[BaseCookie]{output}{\optional{attrs\optional{, header\optional{, sep}}}} +Return a string representation suitable to be sent as HTTP headers. +\var{attrs} and \var{header} are sent to each \class{Morsel}'s +\method{output()} method. \var{sep} is used to join the headers +together, and is by default the combination \code{'\e r\e n'} (CRLF). +\versionchanged[The default separator has been changed from \code{'\e n'} +to match the cookie specification]{2.5} +\end{methoddesc} + +\begin{methoddesc}[BaseCookie]{js_output}{\optional{attrs}} +Return an embeddable JavaScript snippet, which, if run on a browser which +supports JavaScript, will act the same as if the HTTP headers was sent. + +The meaning for \var{attrs} is the same as in \method{output()}. +\end{methoddesc} + +\begin{methoddesc}[BaseCookie]{load}{rawdata} +If \var{rawdata} is a string, parse it as an \code{HTTP_COOKIE} and add +the values found there as \class{Morsel}s. If it is a dictionary, it +is equivalent to: + +\begin{verbatim} +for k, v in rawdata.items(): + cookie[k] = v +\end{verbatim} +\end{methoddesc} + + +\subsection{Morsel Objects \label{morsel-objects}} + +\begin{classdesc}{Morsel}{} +Abstract a key/value pair, which has some \rfc{2109} attributes. + +Morsels are dictionary-like objects, whose set of keys is constant --- +the valid \rfc{2109} attributes, which are + +\begin{itemize} +\item \code{expires} +\item \code{path} +\item \code{comment} +\item \code{domain} +\item \code{max-age} +\item \code{secure} +\item \code{version} +\end{itemize} + +The keys are case-insensitive. +\end{classdesc} + +\begin{memberdesc}[Morsel]{value} +The value of the cookie. +\end{memberdesc} + +\begin{memberdesc}[Morsel]{coded_value} +The encoded value of the cookie --- this is what should be sent. +\end{memberdesc} + +\begin{memberdesc}[Morsel]{key} +The name of the cookie. +\end{memberdesc} + +\begin{methoddesc}[Morsel]{set}{key, value, coded_value} +Set the \var{key}, \var{value} and \var{coded_value} members. +\end{methoddesc} + +\begin{methoddesc}[Morsel]{isReservedKey}{K} +Whether \var{K} is a member of the set of keys of a \class{Morsel}. +\end{methoddesc} + +\begin{methoddesc}[Morsel]{output}{\optional{attrs\optional{, header}}} +Return a string representation of the Morsel, suitable +to be sent as an HTTP header. By default, all the attributes are included, +unless \var{attrs} is given, in which case it should be a list of attributes +to use. \var{header} is by default \code{"Set-Cookie:"}. +\end{methoddesc} + +\begin{methoddesc}[Morsel]{js_output}{\optional{attrs}} +Return an embeddable JavaScript snippet, which, if run on a browser which +supports JavaScript, will act the same as if the HTTP header was sent. + +The meaning for \var{attrs} is the same as in \method{output()}. +\end{methoddesc} + +\begin{methoddesc}[Morsel]{OutputString}{\optional{attrs}} +Return a string representing the Morsel, without any surrounding HTTP +or JavaScript. + +The meaning for \var{attrs} is the same as in \method{output()}. +\end{methoddesc} + + +\subsection{Example \label{cookie-example}} + +The following example demonstrates how to use the \module{Cookie} module. + +\begin{verbatim} +>>> import Cookie +>>> C = Cookie.SimpleCookie() +>>> C = Cookie.SerialCookie() +>>> C = Cookie.SmartCookie() +>>> C["fig"] = "newton" +>>> C["sugar"] = "wafer" +>>> print C # generate HTTP headers +Set-Cookie: sugar=wafer +Set-Cookie: fig=newton +>>> print C.output() # same thing +Set-Cookie: sugar=wafer +Set-Cookie: fig=newton +>>> C = Cookie.SmartCookie() +>>> C["rocky"] = "road" +>>> C["rocky"]["path"] = "/cookie" +>>> print C.output(header="Cookie:") +Cookie: rocky=road; Path=/cookie +>>> print C.output(attrs=[], header="Cookie:") +Cookie: rocky=road +>>> C = Cookie.SmartCookie() +>>> C.load("chips=ahoy; vienna=finger") # load from a string (HTTP header) +>>> print C +Set-Cookie: vienna=finger +Set-Cookie: chips=ahoy +>>> C = Cookie.SmartCookie() +>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') +>>> print C +Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" +>>> C = Cookie.SmartCookie() +>>> C["oreo"] = "doublestuff" +>>> C["oreo"]["path"] = "/" +>>> print C +Set-Cookie: oreo=doublestuff; Path=/ +>>> C = Cookie.SmartCookie() +>>> C["twix"] = "none for you" +>>> C["twix"].value +'none for you' +>>> C = Cookie.SimpleCookie() +>>> C["number"] = 7 # equivalent to C["number"] = str(7) +>>> C["string"] = "seven" +>>> C["number"].value +'7' +>>> C["string"].value +'seven' +>>> print C +Set-Cookie: number=7 +Set-Cookie: string=seven +>>> C = Cookie.SerialCookie() +>>> C["number"] = 7 +>>> C["string"] = "seven" +>>> C["number"].value +7 +>>> C["string"].value +'seven' +>>> print C +Set-Cookie: number="I7\012." +Set-Cookie: string="S'seven'\012p1\012." +>>> C = Cookie.SmartCookie() +>>> C["number"] = 7 +>>> C["string"] = "seven" +>>> C["number"].value +7 +>>> C["string"].value +'seven' +>>> print C +Set-Cookie: number="I7\012." +Set-Cookie: string=seven +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libcookielib.tex b/sys/src/cmd/python/Doc/lib/libcookielib.tex new file mode 100644 index 000000000..01f2539f8 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcookielib.tex @@ -0,0 +1,720 @@ +\section{\module{cookielib} --- + Cookie handling for HTTP clients} + +\declaremodule{standard}{cookielib} +\moduleauthor{John J. Lee}{jjl@pobox.com} +\sectionauthor{John J. Lee}{jjl@pobox.com} + +\versionadded{2.4} + +\modulesynopsis{Cookie handling for HTTP clients} + +The \module{cookielib} module defines classes for automatic handling +of HTTP cookies. It is useful for accessing web sites that require +small pieces of data -- \dfn{cookies} -- to be set on the client +machine by an HTTP response from a web server, and then returned to +the server in later HTTP requests. + +Both the regular Netscape cookie protocol and the protocol defined by +\rfc{2965} are handled. RFC 2965 handling is switched off by default. +\rfc{2109} cookies are parsed as Netscape cookies and subsequently +treated either as Netscape or RFC 2965 cookies according to the +'policy' in effect. Note that the great majority of cookies on the +Internet are Netscape cookies. \module{cookielib} attempts to follow +the de-facto Netscape cookie protocol (which differs substantially +from that set out in the original Netscape specification), including +taking note of the \code{max-age} and \code{port} cookie-attributes +introduced with RFC 2965. \note{The various named parameters found in +\mailheader{Set-Cookie} and \mailheader{Set-Cookie2} headers +(eg. \code{domain} and \code{expires}) are conventionally referred to +as \dfn{attributes}. To distinguish them from Python attributes, the +documentation for this module uses the term \dfn{cookie-attribute} +instead}. + + +The module defines the following exception: + +\begin{excdesc}{LoadError} +Instances of \class{FileCookieJar} raise this exception on failure to +load cookies from a file. \note{For backwards-compatibility +with Python 2.4 (which raised an \exception{IOError}), +\exception{LoadError} is a subclass of \exception{IOError}}. +\end{excdesc} + + +The following classes are provided: + +\begin{classdesc}{CookieJar}{policy=\constant{None}} +\var{policy} is an object implementing the \class{CookiePolicy} +interface. + +The \class{CookieJar} class stores HTTP cookies. It extracts cookies +from HTTP requests, and returns them in HTTP responses. +\class{CookieJar} instances automatically expire contained cookies +when necessary. Subclasses are also responsible for storing and +retrieving cookies from a file or database. +\end{classdesc} + +\begin{classdesc}{FileCookieJar}{filename, delayload=\constant{None}, + policy=\constant{None}} +\var{policy} is an object implementing the \class{CookiePolicy} +interface. For the other arguments, see the documentation for the +corresponding attributes. + +A \class{CookieJar} which can load cookies from, and perhaps save +cookies to, a file on disk. Cookies are \strong{NOT} loaded from the +named file until either the \method{load()} or \method{revert()} +method is called. Subclasses of this class are documented in section +\ref{file-cookie-jar-classes}. +\end{classdesc} + +\begin{classdesc}{CookiePolicy}{} +This class is responsible for deciding whether each cookie should be +accepted from / returned to the server. +\end{classdesc} + +\begin{classdesc}{DefaultCookiePolicy}{ + blocked_domains=\constant{None}, + allowed_domains=\constant{None}, + netscape=\constant{True}, rfc2965=\constant{False}, + rfc2109_as_netscape=\constant{None}, + hide_cookie2=\constant{False}, + strict_domain=\constant{False}, + strict_rfc2965_unverifiable=\constant{True}, + strict_ns_unverifiable=\constant{False}, + strict_ns_domain=\constant{DefaultCookiePolicy.DomainLiberal}, + strict_ns_set_initial_dollar=\constant{False}, + strict_ns_set_path=\constant{False} + } + +Constructor arguments should be passed as keyword arguments only. +\var{blocked_domains} is a sequence of domain names that we never +accept cookies from, nor return cookies to. \var{allowed_domains} if +not \constant{None}, this is a sequence of the only domains for which +we accept and return cookies. For all other arguments, see the +documentation for \class{CookiePolicy} and \class{DefaultCookiePolicy} +objects. + +\class{DefaultCookiePolicy} implements the standard accept / reject +rules for Netscape and RFC 2965 cookies. By default, RFC 2109 cookies +(ie. cookies received in a \mailheader{Set-Cookie} header with a +version cookie-attribute of 1) are treated according to the RFC 2965 +rules. However, if RFC 2965 handling is turned off or +\member{rfc2109_as_netscape} is True, RFC 2109 cookies are +'downgraded' by the \class{CookieJar} instance to Netscape cookies, by +setting the \member{version} attribute of the \class{Cookie} instance +to 0. \class{DefaultCookiePolicy} also provides some parameters to +allow some fine-tuning of policy. +\end{classdesc} + +\begin{classdesc}{Cookie}{} +This class represents Netscape, RFC 2109 and RFC 2965 cookies. It is +not expected that users of \module{cookielib} construct their own +\class{Cookie} instances. Instead, if necessary, call +\method{make_cookies()} on a \class{CookieJar} instance. +\end{classdesc} + +\begin{seealso} + +\seemodule{urllib2}{URL opening with automatic cookie handling.} + +\seemodule{Cookie}{HTTP cookie classes, principally useful for +server-side code. The \module{cookielib} and \module{Cookie} modules +do not depend on each other.} + +\seeurl{http://wwwsearch.sf.net/ClientCookie/}{Extensions to this +module, including a class for reading Microsoft Internet Explorer +cookies on Windows.} + +\seeurl{http://www.netscape.com/newsref/std/cookie_spec.html}{The +specification of the original Netscape cookie protocol. Though this +is still the dominant protocol, the 'Netscape cookie protocol' +implemented by all the major browsers (and \module{cookielib}) only +bears a passing resemblance to the one sketched out in +\code{cookie_spec.html}.} + +\seerfc{2109}{HTTP State Management Mechanism}{Obsoleted by RFC 2965. +Uses \mailheader{Set-Cookie} with version=1.} + +\seerfc{2965}{HTTP State Management Mechanism}{The Netscape protocol +with the bugs fixed. Uses \mailheader{Set-Cookie2} in place of +\mailheader{Set-Cookie}. Not widely used.} + +\seeurl{http://kristol.org/cookie/errata.html}{Unfinished errata to +RFC 2965.} + +\seerfc{2964}{Use of HTTP State Management}{} + +\end{seealso} + + +\subsection{CookieJar and FileCookieJar Objects \label{cookie-jar-objects}} + +\class{CookieJar} objects support the iterator protocol for iterating +over contained \class{Cookie} objects. + +\class{CookieJar} has the following methods: + +\begin{methoddesc}[CookieJar]{add_cookie_header}{request} +Add correct \mailheader{Cookie} header to \var{request}. + +If policy allows (ie. the \member{rfc2965} and \member{hide_cookie2} +attributes of the \class{CookieJar}'s \class{CookiePolicy} instance +are true and false respectively), the \mailheader{Cookie2} header is +also added when appropriate. + +The \var{request} object (usually a \class{urllib2.Request} instance) +must support the methods \method{get_full_url()}, \method{get_host()}, +\method{get_type()}, \method{unverifiable()}, +\method{get_origin_req_host()}, \method{has_header()}, +\method{get_header()}, \method{header_items()}, and +\method{add_unredirected_header()},as documented by \module{urllib2}. +\end{methoddesc} + +\begin{methoddesc}[CookieJar]{extract_cookies}{response, request} +Extract cookies from HTTP \var{response} and store them in the +\class{CookieJar}, where allowed by policy. + +The \class{CookieJar} will look for allowable \mailheader{Set-Cookie} +and \mailheader{Set-Cookie2} headers in the \var{response} argument, +and store cookies as appropriate (subject to the +\method{CookiePolicy.set_ok()} method's approval). + +The \var{response} object (usually the result of a call to +\method{urllib2.urlopen()}, or similar) should support an +\method{info()} method, which returns an object with a +\method{getallmatchingheaders()} method (usually a +\class{mimetools.Message} instance). + +The \var{request} object (usually a \class{urllib2.Request} instance) +must support the methods \method{get_full_url()}, \method{get_host()}, +\method{unverifiable()}, and \method{get_origin_req_host()}, as +documented by \module{urllib2}. The request is used to set default +values for cookie-attributes as well as for checking that the cookie +is allowed to be set. +\end{methoddesc} + +\begin{methoddesc}[CookieJar]{set_policy}{policy} +Set the \class{CookiePolicy} instance to be used. +\end{methoddesc} + +\begin{methoddesc}[CookieJar]{make_cookies}{response, request} +Return sequence of \class{Cookie} objects extracted from +\var{response} object. + +See the documentation for \method{extract_cookies} for the interfaces +required of the \var{response} and \var{request} arguments. +\end{methoddesc} + +\begin{methoddesc}[CookieJar]{set_cookie_if_ok}{cookie, request} +Set a \class{Cookie} if policy says it's OK to do so. +\end{methoddesc} + +\begin{methoddesc}[CookieJar]{set_cookie}{cookie} +Set a \class{Cookie}, without checking with policy to see whether or +not it should be set. +\end{methoddesc} + +\begin{methoddesc}[CookieJar]{clear}{\optional{domain\optional{, + path\optional{, name}}}} +Clear some cookies. + +If invoked without arguments, clear all cookies. If given a single +argument, only cookies belonging to that \var{domain} will be removed. +If given two arguments, cookies belonging to the specified +\var{domain} and URL \var{path} are removed. If given three +arguments, then the cookie with the specified \var{domain}, \var{path} +and \var{name} is removed. + +Raises \exception{KeyError} if no matching cookie exists. +\end{methoddesc} + +\begin{methoddesc}[CookieJar]{clear_session_cookies}{} +Discard all session cookies. + +Discards all contained cookies that have a true \member{discard} +attribute (usually because they had either no \code{max-age} or +\code{expires} cookie-attribute, or an explicit \code{discard} +cookie-attribute). For interactive browsers, the end of a session +usually corresponds to closing the browser window. + +Note that the \method{save()} method won't save session cookies +anyway, unless you ask otherwise by passing a true +\var{ignore_discard} argument. +\end{methoddesc} + +\class{FileCookieJar} implements the following additional methods: + +\begin{methoddesc}[FileCookieJar]{save}{filename=\constant{None}, + ignore_discard=\constant{False}, ignore_expires=\constant{False}} +Save cookies to a file. + +This base class raises \exception{NotImplementedError}. Subclasses may +leave this method unimplemented. + +\var{filename} is the name of file in which to save cookies. If +\var{filename} is not specified, \member{self.filename} is used (whose +default is the value passed to the constructor, if any); if +\member{self.filename} is \constant{None}, \exception{ValueError} is +raised. + +\var{ignore_discard}: save even cookies set to be discarded. +\var{ignore_expires}: save even cookies that have expired + +The file is overwritten if it already exists, thus wiping all the +cookies it contains. Saved cookies can be restored later using the +\method{load()} or \method{revert()} methods. +\end{methoddesc} + +\begin{methoddesc}[FileCookieJar]{load}{filename=\constant{None}, + ignore_discard=\constant{False}, ignore_expires=\constant{False}} +Load cookies from a file. + +Old cookies are kept unless overwritten by newly loaded ones. + +Arguments are as for \method{save()}. + +The named file must be in the format understood by the class, or +\exception{LoadError} will be raised. Also, \exception{IOError} may +be raised, for example if the file does not exist. \note{For +backwards-compatibility with Python 2.4 (which raised +an \exception{IOError}), \exception{LoadError} is a subclass +of \exception{IOError}.} +\end{methoddesc} + +\begin{methoddesc}[FileCookieJar]{revert}{filename=\constant{None}, + ignore_discard=\constant{False}, ignore_expires=\constant{False}} +Clear all cookies and reload cookies from a saved file. + +\method{revert()} can raise the same exceptions as \method{load()}. +If there is a failure, the object's state will not be altered. +\end{methoddesc} + +\class{FileCookieJar} instances have the following public attributes: + +\begin{memberdesc}{filename} +Filename of default file in which to keep cookies. This attribute may +be assigned to. +\end{memberdesc} + +\begin{memberdesc}{delayload} +If true, load cookies lazily from disk. This attribute should not be +assigned to. This is only a hint, since this only affects +performance, not behaviour (unless the cookies on disk are changing). +A \class{CookieJar} object may ignore it. None of the +\class{FileCookieJar} classes included in the standard library lazily +loads cookies. +\end{memberdesc} + + +\subsection{FileCookieJar subclasses and co-operation with web browsers + \label{file-cookie-jar-classes}} + +The following \class{CookieJar} subclasses are provided for reading +and writing . Further \class{CookieJar} subclasses, including one +that reads Microsoft Internet Explorer cookies, are available at +\url{http://wwwsearch.sf.net/ClientCookie/}. + +\begin{classdesc}{MozillaCookieJar}{filename, delayload=\constant{None}, + policy=\constant{None}} +A \class{FileCookieJar} that can load from and save cookies to disk in +the Mozilla \code{cookies.txt} file format (which is also used by the +Lynx and Netscape browsers). \note{This loses information about RFC +2965 cookies, and also about newer or non-standard cookie-attributes +such as \code{port}.} + +\warning{Back up your cookies before saving if you have cookies whose +loss / corruption would be inconvenient (there are some subtleties +which may lead to slight changes in the file over a load / save +round-trip).} + +Also note that cookies saved while Mozilla is running will get +clobbered by Mozilla. +\end{classdesc} + +\begin{classdesc}{LWPCookieJar}{filename, delayload=\constant{None}, + policy=\constant{None}} +A \class{FileCookieJar} that can load from and save cookies to disk in +format compatible with the libwww-perl library's \code{Set-Cookie3} +file format. This is convenient if you want to store cookies in a +human-readable file. +\end{classdesc} + + +\subsection{CookiePolicy Objects \label{cookie-policy-objects}} + +Objects implementing the \class{CookiePolicy} interface have the +following methods: + +\begin{methoddesc}[CookiePolicy]{set_ok}{cookie, request} +Return boolean value indicating whether cookie should be accepted from server. + +\var{cookie} is a \class{cookielib.Cookie} instance. \var{request} is +an object implementing the interface defined by the documentation for +\method{CookieJar.extract_cookies()}. +\end{methoddesc} + +\begin{methoddesc}[CookiePolicy]{return_ok}{cookie, request} +Return boolean value indicating whether cookie should be returned to server. + +\var{cookie} is a \class{cookielib.Cookie} instance. \var{request} is +an object implementing the interface defined by the documentation for +\method{CookieJar.add_cookie_header()}. +\end{methoddesc} + +\begin{methoddesc}[CookiePolicy]{domain_return_ok}{domain, request} +Return false if cookies should not be returned, given cookie domain. + +This method is an optimization. It removes the need for checking +every cookie with a particular domain (which might involve reading +many files). Returning true from \method{domain_return_ok()} and +\method{path_return_ok()} leaves all the work to \method{return_ok()}. + +If \method{domain_return_ok()} returns true for the cookie domain, +\method{path_return_ok()} is called for the cookie path. Otherwise, +\method{path_return_ok()} and \method{return_ok()} are never called +for that cookie domain. If \method{path_return_ok()} returns true, +\method{return_ok()} is called with the \class{Cookie} object itself +for a full check. Otherwise, \method{return_ok()} is never called for +that cookie path. + +Note that \method{domain_return_ok()} is called for every +\emph{cookie} domain, not just for the \emph{request} domain. For +example, the function might be called with both \code{".example.com"} +and \code{"www.example.com"} if the request domain is +\code{"www.example.com"}. The same goes for +\method{path_return_ok()}. + +The \var{request} argument is as documented for \method{return_ok()}. +\end{methoddesc} + +\begin{methoddesc}[CookiePolicy]{path_return_ok}{path, request} +Return false if cookies should not be returned, given cookie path. + +See the documentation for \method{domain_return_ok()}. +\end{methoddesc} + + +In addition to implementing the methods above, implementations of the +\class{CookiePolicy} interface must also supply the following +attributes, indicating which protocols should be used, and how. All +of these attributes may be assigned to. + +\begin{memberdesc}{netscape} +Implement Netscape protocol. +\end{memberdesc} +\begin{memberdesc}{rfc2965} +Implement RFC 2965 protocol. +\end{memberdesc} +\begin{memberdesc}{hide_cookie2} +Don't add \mailheader{Cookie2} header to requests (the presence of +this header indicates to the server that we understand RFC 2965 +cookies). +\end{memberdesc} + +The most useful way to define a \class{CookiePolicy} class is by +subclassing from \class{DefaultCookiePolicy} and overriding some or +all of the methods above. \class{CookiePolicy} itself may be used as +a 'null policy' to allow setting and receiving any and all cookies +(this is unlikely to be useful). + + +\subsection{DefaultCookiePolicy Objects \label{default-cookie-policy-objects}} + +Implements the standard rules for accepting and returning cookies. + +Both RFC 2965 and Netscape cookies are covered. RFC 2965 handling is +switched off by default. + +The easiest way to provide your own policy is to override this class +and call its methods in your overridden implementations before adding +your own additional checks: + +\begin{verbatim} +import cookielib +class MyCookiePolicy(cookielib.DefaultCookiePolicy): + def set_ok(self, cookie, request): + if not cookielib.DefaultCookiePolicy.set_ok(self, cookie, request): + return False + if i_dont_want_to_store_this_cookie(cookie): + return False + return True +\end{verbatim} + +In addition to the features required to implement the +\class{CookiePolicy} interface, this class allows you to block and +allow domains from setting and receiving cookies. There are also some +strictness switches that allow you to tighten up the rather loose +Netscape protocol rules a little bit (at the cost of blocking some +benign cookies). + +A domain blacklist and whitelist is provided (both off by default). +Only domains not in the blacklist and present in the whitelist (if the +whitelist is active) participate in cookie setting and returning. Use +the \var{blocked_domains} constructor argument, and +\method{blocked_domains()} and \method{set_blocked_domains()} methods +(and the corresponding argument and methods for +\var{allowed_domains}). If you set a whitelist, you can turn it off +again by setting it to \constant{None}. + +Domains in block or allow lists that do not start with a dot must +equal the cookie domain to be matched. For example, +\code{"example.com"} matches a blacklist entry of +\code{"example.com"}, but \code{"www.example.com"} does not. Domains +that do start with a dot are matched by more specific domains too. +For example, both \code{"www.example.com"} and +\code{"www.coyote.example.com"} match \code{".example.com"} (but +\code{"example.com"} itself does not). IP addresses are an exception, +and must match exactly. For example, if blocked_domains contains +\code{"192.168.1.2"} and \code{".168.1.2"}, 192.168.1.2 is blocked, +but 193.168.1.2 is not. + +\class{DefaultCookiePolicy} implements the following additional +methods: + +\begin{methoddesc}[DefaultCookiePolicy]{blocked_domains}{} +Return the sequence of blocked domains (as a tuple). +\end{methoddesc} + +\begin{methoddesc}[DefaultCookiePolicy]{set_blocked_domains} + {blocked_domains} +Set the sequence of blocked domains. +\end{methoddesc} + +\begin{methoddesc}[DefaultCookiePolicy]{is_blocked}{domain} +Return whether \var{domain} is on the blacklist for setting or +receiving cookies. +\end{methoddesc} + +\begin{methoddesc}[DefaultCookiePolicy]{allowed_domains}{} +Return \constant{None}, or the sequence of allowed domains (as a tuple). +\end{methoddesc} + +\begin{methoddesc}[DefaultCookiePolicy]{set_allowed_domains} + {allowed_domains} +Set the sequence of allowed domains, or \constant{None}. +\end{methoddesc} + +\begin{methoddesc}[DefaultCookiePolicy]{is_not_allowed}{domain} +Return whether \var{domain} is not on the whitelist for setting or +receiving cookies. +\end{methoddesc} + +\class{DefaultCookiePolicy} instances have the following attributes, +which are all initialised from the constructor arguments of the same +name, and which may all be assigned to. + +\begin{memberdesc}{rfc2109_as_netscape} +If true, request that the \class{CookieJar} instance downgrade RFC +2109 cookies (ie. cookies received in a \mailheader{Set-Cookie} header +with a version cookie-attribute of 1) to Netscape cookies by setting +the version attribute of the \class{Cookie} instance to 0. The +default value is \constant{None}, in which case RFC 2109 cookies are +downgraded if and only if RFC 2965 handling is turned off. Therefore, +RFC 2109 cookies are downgraded by default. +\versionadded{2.5} +\end{memberdesc} + +General strictness switches: + +\begin{memberdesc}{strict_domain} +Don't allow sites to set two-component domains with country-code +top-level domains like \code{.co.uk}, \code{.gov.uk}, +\code{.co.nz}.etc. This is far from perfect and isn't guaranteed to +work! +\end{memberdesc} + +RFC 2965 protocol strictness switches: + +\begin{memberdesc}{strict_rfc2965_unverifiable} +Follow RFC 2965 rules on unverifiable transactions (usually, an +unverifiable transaction is one resulting from a redirect or a request +for an image hosted on another site). If this is false, cookies are +\emph{never} blocked on the basis of verifiability +\end{memberdesc} + +Netscape protocol strictness switches: + +\begin{memberdesc}{strict_ns_unverifiable} +apply RFC 2965 rules on unverifiable transactions even to Netscape +cookies +\end{memberdesc} +\begin{memberdesc}{strict_ns_domain} +Flags indicating how strict to be with domain-matching rules for +Netscape cookies. See below for acceptable values. +\end{memberdesc} +\begin{memberdesc}{strict_ns_set_initial_dollar} +Ignore cookies in Set-Cookie: headers that have names starting with +\code{'\$'}. +\end{memberdesc} +\begin{memberdesc}{strict_ns_set_path} +Don't allow setting cookies whose path doesn't path-match request URI. +\end{memberdesc} + +\member{strict_ns_domain} is a collection of flags. Its value is +constructed by or-ing together (for example, +\code{DomainStrictNoDots|DomainStrictNonDomain} means both flags are +set). + +\begin{memberdesc}{DomainStrictNoDots} +When setting cookies, the 'host prefix' must not contain a dot +(eg. \code{www.foo.bar.com} can't set a cookie for \code{.bar.com}, +because \code{www.foo} contains a dot). +\end{memberdesc} +\begin{memberdesc}{DomainStrictNonDomain} +Cookies that did not explicitly specify a \code{domain} +cookie-attribute can only be returned to a domain equal to the domain +that set the cookie (eg. \code{spam.example.com} won't be returned +cookies from \code{example.com} that had no \code{domain} +cookie-attribute). +\end{memberdesc} +\begin{memberdesc}{DomainRFC2965Match} +When setting cookies, require a full RFC 2965 domain-match. +\end{memberdesc} + +The following attributes are provided for convenience, and are the +most useful combinations of the above flags: + +\begin{memberdesc}{DomainLiberal} +Equivalent to 0 (ie. all of the above Netscape domain strictness flags +switched off). +\end{memberdesc} +\begin{memberdesc}{DomainStrict} +Equivalent to \code{DomainStrictNoDots|DomainStrictNonDomain}. +\end{memberdesc} + + +\subsection{Cookie Objects \label{cookie-objects}} + +\class{Cookie} instances have Python attributes roughly corresponding +to the standard cookie-attributes specified in the various cookie +standards. The correspondence is not one-to-one, because there are +complicated rules for assigning default values, because the +\code{max-age} and \code{expires} cookie-attributes contain equivalent +information, and because RFC 2109 cookies may be 'downgraded' by +\module{cookielib} from version 1 to version 0 (Netscape) cookies. + +Assignment to these attributes should not be necessary other than in +rare circumstances in a \class{CookiePolicy} method. The class does +not enforce internal consistency, so you should know what you're +doing if you do that. + +\begin{memberdesc}[Cookie]{version} +Integer or \constant{None}. Netscape cookies have \member{version} 0. +RFC 2965 and RFC 2109 cookies have a \code{version} cookie-attribute +of 1. However, note that \module{cookielib} may 'downgrade' RFC 2109 +cookies to Netscape cookies, in which case \member{version} is 0. +\end{memberdesc} +\begin{memberdesc}[Cookie]{name} +Cookie name (a string). +\end{memberdesc} +\begin{memberdesc}[Cookie]{value} +Cookie value (a string), or \constant{None}. +\end{memberdesc} +\begin{memberdesc}[Cookie]{port} +String representing a port or a set of ports (eg. '80', or '80,8080'), +or \constant{None}. +\end{memberdesc} +\begin{memberdesc}[Cookie]{path} +Cookie path (a string, eg. \code{'/acme/rocket_launchers'}). +\end{memberdesc} +\begin{memberdesc}[Cookie]{secure} +True if cookie should only be returned over a secure connection. +\end{memberdesc} +\begin{memberdesc}[Cookie]{expires} +Integer expiry date in seconds since epoch, or \constant{None}. See +also the \method{is_expired()} method. +\end{memberdesc} +\begin{memberdesc}[Cookie]{discard} +True if this is a session cookie. +\end{memberdesc} +\begin{memberdesc}[Cookie]{comment} +String comment from the server explaining the function of this cookie, +or \constant{None}. +\end{memberdesc} +\begin{memberdesc}[Cookie]{comment_url} +URL linking to a comment from the server explaining the function of +this cookie, or \constant{None}. +\end{memberdesc} +\begin{memberdesc}[Cookie]{rfc2109} +True if this cookie was received as an RFC 2109 cookie (ie. the cookie +arrived in a \mailheader{Set-Cookie} header, and the value of the +Version cookie-attribute in that header was 1). This attribute is +provided because \module{cookielib} may 'downgrade' RFC 2109 cookies +to Netscape cookies, in which case \member{version} is 0. +\versionadded{2.5} +\end{memberdesc} + +\begin{memberdesc}[Cookie]{port_specified} +True if a port or set of ports was explicitly specified by the server +(in the \mailheader{Set-Cookie} / \mailheader{Set-Cookie2} header). +\end{memberdesc} +\begin{memberdesc}[Cookie]{domain_specified} +True if a domain was explicitly specified by the server. +\end{memberdesc} +\begin{memberdesc}[Cookie]{domain_initial_dot} +True if the domain explicitly specified by the server began with a +dot (\code{'.'}). +\end{memberdesc} + +Cookies may have additional non-standard cookie-attributes. These may +be accessed using the following methods: + +\begin{methoddesc}[Cookie]{has_nonstandard_attr}{name} +Return true if cookie has the named cookie-attribute. +\end{methoddesc} +\begin{methoddesc}[Cookie]{get_nonstandard_attr}{name, default=\constant{None}} +If cookie has the named cookie-attribute, return its value. +Otherwise, return \var{default}. +\end{methoddesc} +\begin{methoddesc}[Cookie]{set_nonstandard_attr}{name, value} +Set the value of the named cookie-attribute. +\end{methoddesc} + +The \class{Cookie} class also defines the following method: + +\begin{methoddesc}[Cookie]{is_expired}{\optional{now=\constant{None}}} +True if cookie has passed the time at which the server requested it +should expire. If \var{now} is given (in seconds since the epoch), +return whether the cookie has expired at the specified time. +\end{methoddesc} + + +\subsection{Examples \label{cookielib-examples}} + +The first example shows the most common usage of \module{cookielib}: + +\begin{verbatim} +import cookielib, urllib2 +cj = cookielib.CookieJar() +opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) +r = opener.open("http://example.com/") +\end{verbatim} + +This example illustrates how to open a URL using your Netscape, +Mozilla, or Lynx cookies (assumes \UNIX{}/Netscape convention for +location of the cookies file): + +\begin{verbatim} +import os, cookielib, urllib2 +cj = cookielib.MozillaCookieJar() +cj.load(os.path.join(os.environ["HOME"], ".netscape/cookies.txt")) +opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) +r = opener.open("http://example.com/") +\end{verbatim} + +The next example illustrates the use of \class{DefaultCookiePolicy}. +Turn on RFC 2965 cookies, be more strict about domains when setting +and returning Netscape cookies, and block some domains from setting +cookies or having them returned: + +\begin{verbatim} +import urllib2 +from cookielib import CookieJar, DefaultCookiePolicy +policy = DefaultCookiePolicy( + rfc2965=True, strict_ns_domain=Policy.DomainStrict, + blocked_domains=["ads.net", ".ads.net"]) +cj = CookieJar(policy) +opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj)) +r = opener.open("http://example.com/") +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libcopy.tex b/sys/src/cmd/python/Doc/lib/libcopy.tex new file mode 100644 index 000000000..59641879d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcopy.tex @@ -0,0 +1,97 @@ +\section{\module{copy} --- + Shallow and deep copy operations} + +\declaremodule{standard}{copy} +\modulesynopsis{Shallow and deep copy operations.} + + +This module provides generic (shallow and deep) copying operations. +\withsubitem{(in copy)}{\ttindex{copy()}\ttindex{deepcopy()}} + +Interface summary: + +\begin{verbatim} +import copy + +x = copy.copy(y) # make a shallow copy of y +x = copy.deepcopy(y) # make a deep copy of y +\end{verbatim} +% +For module specific errors, \exception{copy.error} is raised. + +The difference between shallow and deep copying is only relevant for +compound objects (objects that contain other objects, like lists or +class instances): + +\begin{itemize} + +\item +A \emph{shallow copy} constructs a new compound object and then (to the +extent possible) inserts \emph{references} into it to the objects found +in the original. + +\item +A \emph{deep copy} constructs a new compound object and then, +recursively, inserts \emph{copies} into it of the objects found in the +original. + +\end{itemize} + +Two problems often exist with deep copy operations that don't exist +with shallow copy operations: + +\begin{itemize} + +\item +Recursive objects (compound objects that, directly or indirectly, +contain a reference to themselves) may cause a recursive loop. + +\item +Because deep copy copies \emph{everything} it may copy too much, +e.g., administrative data structures that should be shared even +between copies. + +\end{itemize} + +The \function{deepcopy()} function avoids these problems by: + +\begin{itemize} + +\item +keeping a ``memo'' dictionary of objects already copied during the current +copying pass; and + +\item +letting user-defined classes override the copying operation or the +set of components copied. + +\end{itemize} + +This module does not copy types like module, method, +stack trace, stack frame, file, socket, window, array, or any similar +types. It does ``copy'' functions and classes (shallow and deeply), +by returning the original object unchanged; this is compatible with +the way these are treated by the \module{pickle} module. +\versionchanged[Added copying functions]{2.5} + +Classes can use the same interfaces to control copying that they use +to control pickling. See the description of module +\refmodule{pickle}\refstmodindex{pickle} for information on these +methods. The \module{copy} module does not use the +\refmodule[copyreg]{copy_reg} registration module. + +In order for a class to define its own copy implementation, it can +define special methods \method{__copy__()} and +\method{__deepcopy__()}. The former is called to implement the +shallow copy operation; no additional arguments are passed. The +latter is called to implement the deep copy operation; it is passed +one argument, the memo dictionary. If the \method{__deepcopy__()} +implementation needs to make a deep copy of a component, it should +call the \function{deepcopy()} function with the component as first +argument and the memo dictionary as second argument. +\withsubitem{(copy protocol)}{\ttindex{__copy__()}\ttindex{__deepcopy__()}} + +\begin{seealso} +\seemodule{pickle}{Discussion of the special methods used to +support object state retrieval and restoration.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libcopyreg.tex b/sys/src/cmd/python/Doc/lib/libcopyreg.tex new file mode 100644 index 000000000..594978cdf --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcopyreg.tex @@ -0,0 +1,40 @@ +\section{\module{copy_reg} --- + Register \module{pickle} support functions} + +\declaremodule[copyreg]{standard}{copy_reg} +\modulesynopsis{Register \module{pickle} support functions.} + + +The \module{copy_reg} module provides support for the +\refmodule{pickle}\refstmodindex{pickle}\ and +\refmodule{cPickle}\refbimodindex{cPickle}\ modules. The +\refmodule{copy}\refstmodindex{copy}\ module is likely to use this in the +future as well. It provides configuration information about object +constructors which are not classes. Such constructors may be factory +functions or class instances. + + +\begin{funcdesc}{constructor}{object} + Declares \var{object} to be a valid constructor. If \var{object} is + not callable (and hence not valid as a constructor), raises + \exception{TypeError}. +\end{funcdesc} + +\begin{funcdesc}{pickle}{type, function\optional{, constructor}} + Declares that \var{function} should be used as a ``reduction'' + function for objects of type \var{type}; \var{type} must not be a + ``classic'' class object. (Classic classes are handled differently; + see the documentation for the \refmodule{pickle} module for + details.) \var{function} should return either a string or a tuple + containing two or three elements. + + The optional \var{constructor} parameter, if provided, is a + callable object which can be used to reconstruct the object when + called with the tuple of arguments returned by \var{function} at + pickling time. \exception{TypeError} will be raised if + \var{object} is a class or \var{constructor} is not callable. + + See the \refmodule{pickle} module for more + details on the interface expected of \var{function} and + \var{constructor}. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libcrypt.tex b/sys/src/cmd/python/Doc/lib/libcrypt.tex new file mode 100644 index 000000000..b6a14635b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcrypt.tex @@ -0,0 +1,54 @@ +\section{\module{crypt} --- + Function to check \UNIX{} passwords} + +\declaremodule{builtin}{crypt} + \platform{Unix} +\modulesynopsis{The \cfunction{crypt()} function used to check + \UNIX\ passwords.} +\moduleauthor{Steven D. Majewski}{sdm7g@virginia.edu} +\sectionauthor{Steven D. Majewski}{sdm7g@virginia.edu} +\sectionauthor{Peter Funk}{pf@artcom-gmbh.de} + + +This module implements an interface to the +\manpage{crypt}{3}\index{crypt(3)} routine, which is a one-way hash +function based upon a modified DES\indexii{cipher}{DES} algorithm; see +the \UNIX{} man page for further details. Possible uses include +allowing Python scripts to accept typed passwords from the user, or +attempting to crack \UNIX{} passwords with a dictionary. + +Notice that the behavior of this module depends on the actual implementation +of the \manpage{crypt}{3}\index{crypt(3)} routine in the running system. +Therefore, any extensions available on the current implementation will also +be available on this module. +\begin{funcdesc}{crypt}{word, salt} + \var{word} will usually be a user's password as typed at a prompt or + in a graphical interface. \var{salt} is usually a random + two-character string which will be used to perturb the DES algorithm + in one of 4096 ways. The characters in \var{salt} must be in the + set \regexp{[./a-zA-Z0-9]}. Returns the hashed password as a + string, which will be composed of characters from the same alphabet + as the salt (the first two characters represent the salt itself). + + Since a few \manpage{crypt}{3}\index{crypt(3)} extensions allow different + values, with different sizes in the \var{salt}, it is recommended to use + the full crypted password as salt when checking for a password. +\end{funcdesc} + + +A simple example illustrating typical use: + +\begin{verbatim} +import crypt, getpass, pwd + +def login(): + username = raw_input('Python login:') + cryptedpasswd = pwd.getpwnam(username)[1] + if cryptedpasswd: + if cryptedpasswd == 'x' or cryptedpasswd == '*': + raise "Sorry, currently no support for shadow passwords" + cleartext = getpass.getpass() + return crypt.crypt(cleartext, cryptedpasswd) == cryptedpasswd + else: + return 1 +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libcrypto.tex b/sys/src/cmd/python/Doc/lib/libcrypto.tex new file mode 100644 index 000000000..75987bf34 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcrypto.tex @@ -0,0 +1,19 @@ +\chapter{Cryptographic Services} +\label{crypto} +\index{cryptography} + +The modules described in this chapter implement various algorithms of +a cryptographic nature. They are available at the discretion of the +installation. Here's an overview: + +\localmoduletable + +Hardcore cypherpunks will probably find the cryptographic modules +written by A.M. Kuchling of further interest; the package contains +modules for various encryption algorithms, most notably AES. These modules +are not distributed with Python but available separately. See the URL +\url{http://www.amk.ca/python/code/crypto.html} +for more information. +\indexii{AES}{algorithm} +\index{cryptography} +\index{Kuchling, Andrew} diff --git a/sys/src/cmd/python/Doc/lib/libcsv.tex b/sys/src/cmd/python/Doc/lib/libcsv.tex new file mode 100644 index 000000000..e965e316f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcsv.tex @@ -0,0 +1,538 @@ +\section{\module{csv} --- CSV File Reading and Writing} + +\declaremodule{standard}{csv} +\modulesynopsis{Write and read tabular data to and from delimited files.} +\sectionauthor{Skip Montanaro}{skip@pobox.com} + +\versionadded{2.3} +\index{csv} +\indexii{data}{tabular} + +The so-called CSV (Comma Separated Values) format is the most common import +and export format for spreadsheets and databases. There is no ``CSV +standard'', so the format is operationally defined by the many applications +which read and write it. The lack of a standard means that subtle +differences often exist in the data produced and consumed by different +applications. These differences can make it annoying to process CSV files +from multiple sources. Still, while the delimiters and quoting characters +vary, the overall format is similar enough that it is possible to write a +single module which can efficiently manipulate such data, hiding the details +of reading and writing the data from the programmer. + +The \module{csv} module implements classes to read and write tabular data in +CSV format. It allows programmers to say, ``write this data in the format +preferred by Excel,'' or ``read data from this file which was generated by +Excel,'' without knowing the precise details of the CSV format used by +Excel. Programmers can also describe the CSV formats understood by other +applications or define their own special-purpose CSV formats. + +The \module{csv} module's \class{reader} and \class{writer} objects read and +write sequences. Programmers can also read and write data in dictionary +form using the \class{DictReader} and \class{DictWriter} classes. + +\begin{notice} + This version of the \module{csv} module doesn't support Unicode + input. Also, there are currently some issues regarding \ASCII{} NUL + characters. Accordingly, all input should be UTF-8 or printable + \ASCII{} to be safe; see the examples in section~\ref{csv-examples}. + These restrictions will be removed in the future. +\end{notice} + +\begin{seealso} +% \seemodule{array}{Arrays of uniformly types numeric values.} + \seepep{305}{CSV File API} + {The Python Enhancement Proposal which proposed this addition + to Python.} +\end{seealso} + + +\subsection{Module Contents \label{csv-contents}} + +The \module{csv} module defines the following functions: + +\begin{funcdesc}{reader}{csvfile\optional{, + dialect=\code{'excel'}}\optional{, fmtparam}} +Return a reader object which will iterate over lines in the given +{}\var{csvfile}. \var{csvfile} can be any object which supports the +iterator protocol and returns a string each time its \method{next} +method is called --- file objects and list objects are both suitable. +If \var{csvfile} is a file object, it must be opened with +the 'b' flag on platforms where that makes a difference. An optional +{}\var{dialect} parameter can be given +which is used to define a set of parameters specific to a particular CSV +dialect. It may be an instance of a subclass of the \class{Dialect} +class or one of the strings returned by the \function{list_dialects} +function. The other optional {}\var{fmtparam} keyword arguments can be +given to override individual formatting parameters in the current +dialect. For full details about the dialect and formatting +parameters, see section~\ref{csv-fmt-params}, ``Dialects and Formatting +Parameters''. + +All data read are returned as strings. No automatic data type +conversion is performed. + +\versionchanged[ +The parser is now stricter with respect to multi-line quoted +fields. Previously, if a line ended within a quoted field without a +terminating newline character, a newline would be inserted into the +returned field. This behavior caused problems when reading files +which contained carriage return characters within fields. The +behavior was changed to return the field without inserting newlines. As +a consequence, if newlines embedded within fields are important, the +input should be split into lines in a manner which preserves the newline +characters]{2.5} + +\end{funcdesc} + +\begin{funcdesc}{writer}{csvfile\optional{, + dialect=\code{'excel'}}\optional{, fmtparam}} +Return a writer object responsible for converting the user's data into +delimited strings on the given file-like object. \var{csvfile} can be any +object with a \function{write} method. If \var{csvfile} is a file object, +it must be opened with the 'b' flag on platforms where that makes a +difference. An optional +{}\var{dialect} parameter can be given which is used to define a set of +parameters specific to a particular CSV dialect. It may be an instance +of a subclass of the \class{Dialect} class or one of the strings +returned by the \function{list_dialects} function. The other optional +{}\var{fmtparam} keyword arguments can be given to override individual +formatting parameters in the current dialect. For full details +about the dialect and formatting parameters, see +section~\ref{csv-fmt-params}, ``Dialects and Formatting Parameters''. +To make it as easy as possible to +interface with modules which implement the DB API, the value +\constant{None} is written as the empty string. While this isn't a +reversible transformation, it makes it easier to dump SQL NULL data values +to CSV files without preprocessing the data returned from a +\code{cursor.fetch*()} call. All other non-string data are stringified +with \function{str()} before being written. +\end{funcdesc} + +\begin{funcdesc}{register_dialect}{name\optional{, dialect}\optional{, fmtparam}} +Associate \var{dialect} with \var{name}. \var{name} must be a string +or Unicode object. The dialect can be specified either by passing a +sub-class of \class{Dialect}, or by \var{fmtparam} keyword arguments, +or both, with keyword arguments overriding parameters of the dialect. +For full details about the dialect and formatting parameters, see +section~\ref{csv-fmt-params}, ``Dialects and Formatting Parameters''. +\end{funcdesc} + +\begin{funcdesc}{unregister_dialect}{name} +Delete the dialect associated with \var{name} from the dialect registry. An +\exception{Error} is raised if \var{name} is not a registered dialect +name. +\end{funcdesc} + +\begin{funcdesc}{get_dialect}{name} +Return the dialect associated with \var{name}. An \exception{Error} is +raised if \var{name} is not a registered dialect name. +\end{funcdesc} + +\begin{funcdesc}{list_dialects}{} +Return the names of all registered dialects. +\end{funcdesc} + +\begin{funcdesc}{field_size_limit}{\optional{new_limit}} + Returns the current maximum field size allowed by the parser. If + \var{new_limit} is given, this becomes the new limit. + \versionadded{2.5} +\end{funcdesc} + + +The \module{csv} module defines the following classes: + +\begin{classdesc}{DictReader}{csvfile\optional{, + fieldnames=\constant{None},\optional{, + restkey=\constant{None}\optional{, + restval=\constant{None}\optional{, + dialect=\code{'excel'}\optional{, + *args, **kwds}}}}}} +Create an object which operates like a regular reader but maps the +information read into a dict whose keys are given by the optional +{} \var{fieldnames} +parameter. If the \var{fieldnames} parameter is omitted, the values in +the first row of the \var{csvfile} will be used as the fieldnames. +If the row read has fewer fields than the fieldnames sequence, +the value of \var{restval} will be used as the default value. If the row +read has more fields than the fieldnames sequence, the remaining data is +added as a sequence keyed by the value of \var{restkey}. If the row read +has fewer fields than the fieldnames sequence, the remaining keys take the +value of the optional \var{restval} parameter. Any other optional or +keyword arguments are passed to the underlying \class{reader} instance. +\end{classdesc} + + +\begin{classdesc}{DictWriter}{csvfile, fieldnames\optional{, + restval=""\optional{, + extrasaction=\code{'raise'}\optional{, + dialect=\code{'excel'}\optional{, + *args, **kwds}}}}} +Create an object which operates like a regular writer but maps dictionaries +onto output rows. The \var{fieldnames} parameter identifies the order in +which values in the dictionary passed to the \method{writerow()} method are +written to the \var{csvfile}. The optional \var{restval} parameter +specifies the value to be written if the dictionary is missing a key in +\var{fieldnames}. If the dictionary passed to the \method{writerow()} +method contains a key not found in \var{fieldnames}, the optional +\var{extrasaction} parameter indicates what action to take. If it is set +to \code{'raise'} a \exception{ValueError} is raised. If it is set to +\code{'ignore'}, extra values in the dictionary are ignored. Any other +optional or keyword arguments are passed to the underlying \class{writer} +instance. + +Note that unlike the \class{DictReader} class, the \var{fieldnames} +parameter of the \class{DictWriter} is not optional. Since Python's +\class{dict} objects are not ordered, there is not enough information +available to deduce the order in which the row should be written to the +\var{csvfile}. + +\end{classdesc} + +\begin{classdesc*}{Dialect}{} +The \class{Dialect} class is a container class relied on primarily for its +attributes, which are used to define the parameters for a specific +\class{reader} or \class{writer} instance. +\end{classdesc*} + +\begin{classdesc}{excel}{} +The \class{excel} class defines the usual properties of an Excel-generated +CSV file. It is registered with the dialect name \code{'excel'}. +\end{classdesc} + +\begin{classdesc}{excel_tab}{} +The \class{excel_tab} class defines the usual properties of an +Excel-generated TAB-delimited file. It is registered with the dialect name +\code{'excel-tab'}. +\end{classdesc} + +\begin{classdesc}{Sniffer}{} +The \class{Sniffer} class is used to deduce the format of a CSV file. +\end{classdesc} + +The \class{Sniffer} class provides two methods: + +\begin{methoddesc}{sniff}{sample\optional{,delimiters=None}} +Analyze the given \var{sample} and return a \class{Dialect} subclass +reflecting the parameters found. If the optional \var{delimiters} parameter +is given, it is interpreted as a string containing possible valid delimiter +characters. +\end{methoddesc} + +\begin{methoddesc}{has_header}{sample} +Analyze the sample text (presumed to be in CSV format) and return +\constant{True} if the first row appears to be a series of column +headers. +\end{methoddesc} + + +The \module{csv} module defines the following constants: + +\begin{datadesc}{QUOTE_ALL} +Instructs \class{writer} objects to quote all fields. +\end{datadesc} + +\begin{datadesc}{QUOTE_MINIMAL} +Instructs \class{writer} objects to only quote those fields which contain +special characters such as \var{delimiter}, \var{quotechar} or any of the +characters in \var{lineterminator}. +\end{datadesc} + +\begin{datadesc}{QUOTE_NONNUMERIC} +Instructs \class{writer} objects to quote all non-numeric +fields. + +Instructs the reader to convert all non-quoted fields to type \var{float}. +\end{datadesc} + +\begin{datadesc}{QUOTE_NONE} +Instructs \class{writer} objects to never quote fields. When the current +\var{delimiter} occurs in output data it is preceded by the current +\var{escapechar} character. If \var{escapechar} is not set, the writer +will raise \exception{Error} if any characters that require escaping +are encountered. + +Instructs \class{reader} to perform no special processing of quote characters. +\end{datadesc} + + +The \module{csv} module defines the following exception: + +\begin{excdesc}{Error} +Raised by any of the functions when an error is detected. +\end{excdesc} + + +\subsection{Dialects and Formatting Parameters\label{csv-fmt-params}} + +To make it easier to specify the format of input and output records, +specific formatting parameters are grouped together into dialects. A +dialect is a subclass of the \class{Dialect} class having a set of specific +methods and a single \method{validate()} method. When creating \class{reader} +or \class{writer} objects, the programmer can specify a string or a subclass +of the \class{Dialect} class as the dialect parameter. In addition to, or +instead of, the \var{dialect} parameter, the programmer can also specify +individual formatting parameters, which have the same names as the +attributes defined below for the \class{Dialect} class. + +Dialects support the following attributes: + +\begin{memberdesc}[Dialect]{delimiter} +A one-character string used to separate fields. It defaults to \code{','}. +\end{memberdesc} + +\begin{memberdesc}[Dialect]{doublequote} +Controls how instances of \var{quotechar} appearing inside a field should +be themselves be quoted. When \constant{True}, the character is doubled. +When \constant{False}, the \var{escapechar} is used as a prefix to the +\var{quotechar}. It defaults to \constant{True}. + +On output, if \var{doublequote} is \constant{False} and no +\var{escapechar} is set, \exception{Error} is raised if a \var{quotechar} +is found in a field. +\end{memberdesc} + +\begin{memberdesc}[Dialect]{escapechar} +A one-character string used by the writer to escape the \var{delimiter} if +\var{quoting} is set to \constant{QUOTE_NONE} and the \var{quotechar} +if \var{doublequote} is \constant{False}. On reading, the \var{escapechar} +removes any special meaning from the following character. It defaults +to \constant{None}, which disables escaping. +\end{memberdesc} + +\begin{memberdesc}[Dialect]{lineterminator} +The string used to terminate lines produced by the \class{writer}. +It defaults to \code{'\e r\e n'}. + +\note{The \class{reader} is hard-coded to recognise either \code{'\e r'} +or \code{'\e n'} as end-of-line, and ignores \var{lineterminator}. This +behavior may change in the future.} +\end{memberdesc} + +\begin{memberdesc}[Dialect]{quotechar} +A one-character string used to quote fields containing special characters, +such as the \var{delimiter} or \var{quotechar}, or which contain new-line +characters. It defaults to \code{'"'}. +\end{memberdesc} + +\begin{memberdesc}[Dialect]{quoting} +Controls when quotes should be generated by the writer and recognised +by the reader. It can take on any of the \constant{QUOTE_*} constants +(see section~\ref{csv-contents}) and defaults to \constant{QUOTE_MINIMAL}. +\end{memberdesc} + +\begin{memberdesc}[Dialect]{skipinitialspace} +When \constant{True}, whitespace immediately following the \var{delimiter} +is ignored. The default is \constant{False}. +\end{memberdesc} + + +\subsection{Reader Objects} + +Reader objects (\class{DictReader} instances and objects returned by +the \function{reader()} function) have the following public methods: + +\begin{methoddesc}[csv reader]{next}{} +Return the next row of the reader's iterable object as a list, parsed +according to the current dialect. +\end{methoddesc} + +Reader objects have the following public attributes: + +\begin{memberdesc}[csv reader]{dialect} +A read-only description of the dialect in use by the parser. +\end{memberdesc} + +\begin{memberdesc}[csv reader]{line_num} + The number of lines read from the source iterator. This is not the same + as the number of records returned, as records can span multiple lines. + \versionadded{2.5} +\end{memberdesc} + + +\subsection{Writer Objects} + +\class{Writer} objects (\class{DictWriter} instances and objects returned by +the \function{writer()} function) have the following public methods. A +{}\var{row} must be a sequence of strings or numbers for \class{Writer} +objects and a dictionary mapping fieldnames to strings or numbers (by +passing them through \function{str()} first) for {}\class{DictWriter} +objects. Note that complex numbers are written out surrounded by parens. +This may cause some problems for other programs which read CSV files +(assuming they support complex numbers at all). + +\begin{methoddesc}[csv writer]{writerow}{row} +Write the \var{row} parameter to the writer's file object, formatted +according to the current dialect. +\end{methoddesc} + +\begin{methoddesc}[csv writer]{writerows}{rows} +Write all the \var{rows} parameters (a list of \var{row} objects as +described above) to the writer's file object, formatted +according to the current dialect. +\end{methoddesc} + +Writer objects have the following public attribute: + +\begin{memberdesc}[csv writer]{dialect} +A read-only description of the dialect in use by the writer. +\end{memberdesc} + + + +\subsection{Examples\label{csv-examples}} + +The simplest example of reading a CSV file: + +\begin{verbatim} +import csv +reader = csv.reader(open("some.csv", "rb")) +for row in reader: + print row +\end{verbatim} + +Reading a file with an alternate format: + +\begin{verbatim} +import csv +reader = csv.reader(open("passwd", "rb"), delimiter=':', quoting=csv.QUOTE_NONE) +for row in reader: + print row +\end{verbatim} + +The corresponding simplest possible writing example is: + +\begin{verbatim} +import csv +writer = csv.writer(open("some.csv", "wb")) +writer.writerows(someiterable) +\end{verbatim} + +Registering a new dialect: + +\begin{verbatim} +import csv + +csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE) + +reader = csv.reader(open("passwd", "rb"), 'unixpwd') +\end{verbatim} + +A slightly more advanced use of the reader --- catching and reporting errors: + +\begin{verbatim} +import csv, sys +filename = "some.csv" +reader = csv.reader(open(filename, "rb")) +try: + for row in reader: + print row +except csv.Error, e: + sys.exit('file %s, line %d: %s' % (filename, reader.line_num, e)) +\end{verbatim} + +And while the module doesn't directly support parsing strings, it can +easily be done: + +\begin{verbatim} +import csv +for row in csv.reader(['one,two,three']): + print row +\end{verbatim} + +The \module{csv} module doesn't directly support reading and writing +Unicode, but it is 8-bit-clean save for some problems with \ASCII{} NUL +characters. So you can write functions or classes that handle the +encoding and decoding for you as long as you avoid encodings like +UTF-16 that use NULs. UTF-8 is recommended. + +\function{unicode_csv_reader} below is a generator that wraps +\class{csv.reader} to handle Unicode CSV data (a list of Unicode +strings). \function{utf_8_encoder} is a generator that encodes the +Unicode strings as UTF-8, one string (or row) at a time. The encoded +strings are parsed by the CSV reader, and +\function{unicode_csv_reader} decodes the UTF-8-encoded cells back +into Unicode: + +\begin{verbatim} +import csv + +def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs): + # csv.py doesn't do Unicode; encode temporarily as UTF-8: + csv_reader = csv.reader(utf_8_encoder(unicode_csv_data), + dialect=dialect, **kwargs) + for row in csv_reader: + # decode UTF-8 back to Unicode, cell by cell: + yield [unicode(cell, 'utf-8') for cell in row] + +def utf_8_encoder(unicode_csv_data): + for line in unicode_csv_data: + yield line.encode('utf-8') +\end{verbatim} + +For all other encodings the following \class{UnicodeReader} and +\class{UnicodeWriter} classes can be used. They take an additional +\var{encoding} parameter in their constructor and make sure that the data +passes the real reader or writer encoded as UTF-8: + +\begin{verbatim} +import csv, codecs, cStringIO + +class UTF8Recoder: + """ + Iterator that reads an encoded stream and reencodes the input to UTF-8 + """ + def __init__(self, f, encoding): + self.reader = codecs.getreader(encoding)(f) + + def __iter__(self): + return self + + def next(self): + return self.reader.next().encode("utf-8") + +class UnicodeReader: + """ + A CSV reader which will iterate over lines in the CSV file "f", + which is encoded in the given encoding. + """ + + def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): + f = UTF8Recoder(f, encoding) + self.reader = csv.reader(f, dialect=dialect, **kwds) + + def next(self): + row = self.reader.next() + return [unicode(s, "utf-8") for s in row] + + def __iter__(self): + return self + +class UnicodeWriter: + """ + A CSV writer which will write rows to CSV file "f", + which is encoded in the given encoding. + """ + + def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): + # Redirect output to a queue + self.queue = cStringIO.StringIO() + self.writer = csv.writer(self.queue, dialect=dialect, **kwds) + self.stream = f + self.encoder = codecs.getincrementalencoder(encoding)() + + def writerow(self, row): + self.writer.writerow([s.encode("utf-8") for s in row]) + # Fetch UTF-8 output from the queue ... + data = self.queue.getvalue() + data = data.decode("utf-8") + # ... and reencode it into the target encoding + data = self.encoder.encode(data) + # write to the target stream + self.stream.write(data) + # empty queue + self.queue.truncate(0) + + def writerows(self, rows): + for row in rows: + self.writerow(row) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libctypes.tex b/sys/src/cmd/python/Doc/lib/libctypes.tex new file mode 100755 index 000000000..184875f1b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libctypes.tex @@ -0,0 +1,2443 @@ +\ifx\locallinewidth\undefined\newlength{\locallinewidth}\fi +\setlength{\locallinewidth}{\linewidth} +\section{\module{ctypes} --- A foreign function library for Python.} +\declaremodule{standard}{ctypes} +\moduleauthor{Thomas Heller}{theller@python.net} +\modulesynopsis{A foreign function library for Python.} +\versionadded{2.5} + +\code{ctypes} is a foreign function library for Python. It provides C +compatible data types, and allows to call functions in dlls/shared +libraries. It can be used to wrap these libraries in pure Python. + + +\subsection{ctypes tutorial\label{ctypes-ctypes-tutorial}} + +Note: The code samples in this tutorial uses \code{doctest} to make sure +that they actually work. Since some code samples behave differently +under Linux, Windows, or Mac OS X, they contain doctest directives in +comments. + +Note: Quite some code samples references the ctypes \class{c{\_}int} type. +This type is an alias to the \class{c{\_}long} type on 32-bit systems. So, +you should not be confused if \class{c{\_}long} is printed if you would +expect \class{c{\_}int} - they are actually the same type. + + +\subsubsection{Loading dynamic link libraries\label{ctypes-loading-dynamic-link-libraries}} + +\code{ctypes} exports the \var{cdll}, and on Windows also \var{windll} and +\var{oledll} objects to load dynamic link libraries. + +You load libraries by accessing them as attributes of these objects. +\var{cdll} loads libraries which export functions using the standard +\code{cdecl} calling convention, while \var{windll} libraries call +functions using the \code{stdcall} calling convention. \var{oledll} also +uses the \code{stdcall} calling convention, and assumes the functions +return a Windows \class{HRESULT} error code. The error code is used to +automatically raise \class{WindowsError} Python exceptions when the +function call fails. + +Here are some examples for Windows, note that \code{msvcrt} is the MS +standard C library containing most standard C functions, and uses the +cdecl calling convention: +\begin{verbatim} +>>> from ctypes import * +>>> print windll.kernel32 # doctest: +WINDOWS + +>>> print cdll.msvcrt # doctest: +WINDOWS + +>>> libc = cdll.msvcrt # doctest: +WINDOWS +>>> +\end{verbatim} + +Windows appends the usual '.dll' file suffix automatically. + +On Linux, it is required to specify the filename \emph{including} the +extension to load a library, so attribute access does not work. +Either the \method{LoadLibrary} method of the dll loaders should be used, +or you should load the library by creating an instance of CDLL by +calling the constructor: +\begin{verbatim} +>>> cdll.LoadLibrary("libc.so.6") # doctest: +LINUX + +>>> libc = CDLL("libc.so.6") # doctest: +LINUX +>>> libc # doctest: +LINUX + +>>> +\end{verbatim} +% XXX Add section for Mac OS X. + + +\subsubsection{Accessing functions from loaded dlls\label{ctypes-accessing-functions-from-loaded-dlls}} + +Functions are accessed as attributes of dll objects: +\begin{verbatim} +>>> from ctypes import * +>>> libc.printf +<_FuncPtr object at 0x...> +>>> print windll.kernel32.GetModuleHandleA # doctest: +WINDOWS +<_FuncPtr object at 0x...> +>>> print windll.kernel32.MyOwnFunction # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? + File "ctypes.py", line 239, in __getattr__ + func = _StdcallFuncPtr(name, self) +AttributeError: function 'MyOwnFunction' not found +>>> +\end{verbatim} + +Note that win32 system dlls like \code{kernel32} and \code{user32} often +export ANSI as well as UNICODE versions of a function. The UNICODE +version is exported with an \code{W} appended to the name, while the ANSI +version is exported with an \code{A} appended to the name. The win32 +\code{GetModuleHandle} function, which returns a \emph{module handle} for a +given module name, has the following C prototype, and a macro is used +to expose one of them as \code{GetModuleHandle} depending on whether +UNICODE is defined or not: +\begin{verbatim} +/* ANSI version */ +HMODULE GetModuleHandleA(LPCSTR lpModuleName); +/* UNICODE version */ +HMODULE GetModuleHandleW(LPCWSTR lpModuleName); +\end{verbatim} + +\var{windll} does not try to select one of them by magic, you must +access the version you need by specifying \code{GetModuleHandleA} or +\code{GetModuleHandleW} explicitely, and then call it with normal strings +or unicode strings respectively. + +Sometimes, dlls export functions with names which aren't valid Python +identifiers, like \code{"??2@YAPAXI@Z"}. In this case you have to use +\code{getattr} to retrieve the function: +\begin{verbatim} +>>> getattr(cdll.msvcrt, "??2@YAPAXI@Z") # doctest: +WINDOWS +<_FuncPtr object at 0x...> +>>> +\end{verbatim} + +On Windows, some dlls export functions not by name but by ordinal. +These functions can be accessed by indexing the dll object with the +ordinal number: +\begin{verbatim} +>>> cdll.kernel32[1] # doctest: +WINDOWS +<_FuncPtr object at 0x...> +>>> cdll.kernel32[0] # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? + File "ctypes.py", line 310, in __getitem__ + func = _StdcallFuncPtr(name, self) +AttributeError: function ordinal 0 not found +>>> +\end{verbatim} + + +\subsubsection{Calling functions\label{ctypes-calling-functions}} + +You can call these functions like any other Python callable. This +example uses the \code{time()} function, which returns system time in +seconds since the \UNIX{} epoch, and the \code{GetModuleHandleA()} function, +which returns a win32 module handle. + +This example calls both functions with a NULL pointer (\code{None} should +be used as the NULL pointer): +\begin{verbatim} +>>> print libc.time(None) # doctest: +SKIP +1150640792 +>>> print hex(windll.kernel32.GetModuleHandleA(None)) # doctest: +WINDOWS +0x1d000000 +>>> +\end{verbatim} + +\code{ctypes} tries to protect you from calling functions with the wrong +number of arguments or the wrong calling convention. Unfortunately +this only works on Windows. It does this by examining the stack after +the function returns, so although an error is raised the function +\emph{has} been called: +\begin{verbatim} +>>> windll.kernel32.GetModuleHandleA() # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? +ValueError: Procedure probably called with not enough arguments (4 bytes missing) +>>> windll.kernel32.GetModuleHandleA(0, 0) # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? +ValueError: Procedure probably called with too many arguments (4 bytes in excess) +>>> +\end{verbatim} + +The same exception is raised when you call an \code{stdcall} function +with the \code{cdecl} calling convention, or vice versa: +\begin{verbatim} +>>> cdll.kernel32.GetModuleHandleA(None) # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? +ValueError: Procedure probably called with not enough arguments (4 bytes missing) +>>> + +>>> windll.msvcrt.printf("spam") # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? +ValueError: Procedure probably called with too many arguments (4 bytes in excess) +>>> +\end{verbatim} + +To find out the correct calling convention you have to look into the C +header file or the documentation for the function you want to call. + +On Windows, \code{ctypes} uses win32 structured exception handling to +prevent crashes from general protection faults when functions are +called with invalid argument values: +\begin{verbatim} +>>> windll.kernel32.GetModuleHandleA(32) # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? +WindowsError: exception: access violation reading 0x00000020 +>>> +\end{verbatim} + +There are, however, enough ways to crash Python with \code{ctypes}, so +you should be careful anyway. + +\code{None}, integers, longs, byte strings and unicode strings are the +only native Python objects that can directly be used as parameters in +these function calls. \code{None} is passed as a C \code{NULL} pointer, +byte strings and unicode strings are passed as pointer to the memory +block that contains their data (\code{char *} or \code{wchar{\_}t *}). Python +integers and Python longs are passed as the platforms default C +\code{int} type, their value is masked to fit into the C type. + +Before we move on calling functions with other parameter types, we +have to learn more about \code{ctypes} data types. + + +\subsubsection{Fundamental data types\label{ctypes-fundamental-data-types}} + +\code{ctypes} defines a number of primitive C compatible data types : +\begin{quote} +\begin{tableiii}{l|l|l}{textrm} +{ +ctypes type +} +{ +C type +} +{ +Python type +} +\lineiii{ +\class{c{\_}char} +} +{ +\code{char} +} +{ +1-character +string +} +\lineiii{ +\class{c{\_}wchar} +} +{ +\code{wchar{\_}t} +} +{ +1-character +unicode string +} +\lineiii{ +\class{c{\_}byte} +} +{ +\code{char} +} +{ +int/long +} +\lineiii{ +\class{c{\_}ubyte} +} +{ +\code{unsigned char} +} +{ +int/long +} +\lineiii{ +\class{c{\_}short} +} +{ +\code{short} +} +{ +int/long +} +\lineiii{ +\class{c{\_}ushort} +} +{ +\code{unsigned short} +} +{ +int/long +} +\lineiii{ +\class{c{\_}int} +} +{ +\code{int} +} +{ +int/long +} +\lineiii{ +\class{c{\_}uint} +} +{ +\code{unsigned int} +} +{ +int/long +} +\lineiii{ +\class{c{\_}long} +} +{ +\code{long} +} +{ +int/long +} +\lineiii{ +\class{c{\_}ulong} +} +{ +\code{unsigned long} +} +{ +int/long +} +\lineiii{ +\class{c{\_}longlong} +} +{ +\code{{\_}{\_}int64} or +\code{long long} +} +{ +int/long +} +\lineiii{ +\class{c{\_}ulonglong} +} +{ +\code{unsigned {\_}{\_}int64} or +\code{unsigned long long} +} +{ +int/long +} +\lineiii{ +\class{c{\_}float} +} +{ +\code{float} +} +{ +float +} +\lineiii{ +\class{c{\_}double} +} +{ +\code{double} +} +{ +float +} +\lineiii{ +\class{c{\_}char{\_}p} +} +{ +\code{char *} +(NUL terminated) +} +{ +string or +\code{None} +} +\lineiii{ +\class{c{\_}wchar{\_}p} +} +{ +\code{wchar{\_}t *} +(NUL terminated) +} +{ +unicode or +\code{None} +} +\lineiii{ +\class{c{\_}void{\_}p} +} +{ +\code{void *} +} +{ +int/long +or \code{None} +} +\end{tableiii} +\end{quote} + +All these types can be created by calling them with an optional +initializer of the correct type and value: +\begin{verbatim} +>>> c_int() +c_long(0) +>>> c_char_p("Hello, World") +c_char_p('Hello, World') +>>> c_ushort(-3) +c_ushort(65533) +>>> +\end{verbatim} + +Since these types are mutable, their value can also be changed +afterwards: +\begin{verbatim} +>>> i = c_int(42) +>>> print i +c_long(42) +>>> print i.value +42 +>>> i.value = -99 +>>> print i.value +-99 +>>> +\end{verbatim} + +Assigning a new value to instances of the pointer types \class{c{\_}char{\_}p}, +\class{c{\_}wchar{\_}p}, and \class{c{\_}void{\_}p} changes the \emph{memory location} they +point to, \emph{not the contents} of the memory block (of course not, +because Python strings are immutable): +\begin{verbatim} +>>> s = "Hello, World" +>>> c_s = c_char_p(s) +>>> print c_s +c_char_p('Hello, World') +>>> c_s.value = "Hi, there" +>>> print c_s +c_char_p('Hi, there') +>>> print s # first string is unchanged +Hello, World +>>> +\end{verbatim} + +You should be careful, however, not to pass them to functions +expecting pointers to mutable memory. If you need mutable memory +blocks, ctypes has a \code{create{\_}string{\_}buffer} function which creates +these in various ways. The current memory block contents can be +accessed (or changed) with the \code{raw} property, if you want to access +it as NUL terminated string, use the \code{string} property: +\begin{verbatim} +>>> from ctypes import * +>>> p = create_string_buffer(3) # create a 3 byte buffer, initialized to NUL bytes +>>> print sizeof(p), repr(p.raw) +3 '\x00\x00\x00' +>>> p = create_string_buffer("Hello") # create a buffer containing a NUL terminated string +>>> print sizeof(p), repr(p.raw) +6 'Hello\x00' +>>> print repr(p.value) +'Hello' +>>> p = create_string_buffer("Hello", 10) # create a 10 byte buffer +>>> print sizeof(p), repr(p.raw) +10 'Hello\x00\x00\x00\x00\x00' +>>> p.value = "Hi" +>>> print sizeof(p), repr(p.raw) +10 'Hi\x00lo\x00\x00\x00\x00\x00' +>>> +\end{verbatim} + +The \code{create{\_}string{\_}buffer} function replaces the \code{c{\_}buffer} +function (which is still available as an alias), as well as the +\code{c{\_}string} function from earlier ctypes releases. To create a +mutable memory block containing unicode characters of the C type +\code{wchar{\_}t} use the \code{create{\_}unicode{\_}buffer} function. + + +\subsubsection{Calling functions, continued\label{ctypes-calling-functions-continued}} + +Note that printf prints to the real standard output channel, \emph{not} to +\code{sys.stdout}, so these examples will only work at the console +prompt, not from within \emph{IDLE} or \emph{PythonWin}: +\begin{verbatim} +>>> printf = libc.printf +>>> printf("Hello, %s\n", "World!") +Hello, World! +14 +>>> printf("Hello, %S", u"World!") +Hello, World! +13 +>>> printf("%d bottles of beer\n", 42) +42 bottles of beer +19 +>>> printf("%f bottles of beer\n", 42.5) +Traceback (most recent call last): + File "", line 1, in ? +ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2 +>>> +\end{verbatim} + +As has been mentioned before, all Python types except integers, +strings, and unicode strings have to be wrapped in their corresponding +\code{ctypes} type, so that they can be converted to the required C data +type: +\begin{verbatim} +>>> printf("An int %d, a double %f\n", 1234, c_double(3.14)) +Integer 1234, double 3.1400001049 +31 +>>> +\end{verbatim} + + +\subsubsection{Calling functions with your own custom data types\label{ctypes-calling-functions-with-own-custom-data-types}} + +You can also customize \code{ctypes} argument conversion to allow +instances of your own classes be used as function arguments. +\code{ctypes} looks for an \member{{\_}as{\_}parameter{\_}} attribute and uses this as +the function argument. Of course, it must be one of integer, string, +or unicode: +\begin{verbatim} +>>> class Bottles(object): +... def __init__(self, number): +... self._as_parameter_ = number +... +>>> bottles = Bottles(42) +>>> printf("%d bottles of beer\n", bottles) +42 bottles of beer +19 +>>> +\end{verbatim} + +If you don't want to store the instance's data in the +\member{{\_}as{\_}parameter{\_}} instance variable, you could define a \code{property} +which makes the data avaiblable. + + +\subsubsection{Specifying the required argument types (function prototypes)\label{ctypes-specifying-required-argument-types}} + +It is possible to specify the required argument types of functions +exported from DLLs by setting the \member{argtypes} attribute. + +\member{argtypes} must be a sequence of C data types (the \code{printf} +function is probably not a good example here, because it takes a +variable number and different types of parameters depending on the +format string, on the other hand this is quite handy to experiment +with this feature): +\begin{verbatim} +>>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double] +>>> printf("String '%s', Int %d, Double %f\n", "Hi", 10, 2.2) +String 'Hi', Int 10, Double 2.200000 +37 +>>> +\end{verbatim} + +Specifying a format protects against incompatible argument types (just +as a prototype for a C function), and tries to convert the arguments +to valid types: +\begin{verbatim} +>>> printf("%d %d %d", 1, 2, 3) +Traceback (most recent call last): + File "", line 1, in ? +ArgumentError: argument 2: exceptions.TypeError: wrong type +>>> printf("%s %d %f", "X", 2, 3) +X 2 3.00000012 +12 +>>> +\end{verbatim} + +If you have defined your own classes which you pass to function calls, +you have to implement a \method{from{\_}param} class method for them to be +able to use them in the \member{argtypes} sequence. The \method{from{\_}param} +class method receives the Python object passed to the function call, +it should do a typecheck or whatever is needed to make sure this +object is acceptable, and then return the object itself, it's +\member{{\_}as{\_}parameter{\_}} attribute, or whatever you want to pass as the C +function argument in this case. Again, the result should be an +integer, string, unicode, a \code{ctypes} instance, or something having +the \member{{\_}as{\_}parameter{\_}} attribute. + + +\subsubsection{Return types\label{ctypes-return-types}} + +By default functions are assumed to return the C \code{int} type. Other +return types can be specified by setting the \member{restype} attribute of +the function object. + +Here is a more advanced example, it uses the \code{strchr} function, which +expects a string pointer and a char, and returns a pointer to a +string: +\begin{verbatim} +>>> strchr = libc.strchr +>>> strchr("abcdef", ord("d")) # doctest: +SKIP +8059983 +>>> strchr.restype = c_char_p # c_char_p is a pointer to a string +>>> strchr("abcdef", ord("d")) +'def' +>>> print strchr("abcdef", ord("x")) +None +>>> +\end{verbatim} + +If you want to avoid the \code{ord("x")} calls above, you can set the +\member{argtypes} attribute, and the second argument will be converted from +a single character Python string into a C char: +\begin{verbatim} +>>> strchr.restype = c_char_p +>>> strchr.argtypes = [c_char_p, c_char] +>>> strchr("abcdef", "d") +'def' +>>> strchr("abcdef", "def") +Traceback (most recent call last): + File "", line 1, in ? +ArgumentError: argument 2: exceptions.TypeError: one character string expected +>>> print strchr("abcdef", "x") +None +>>> strchr("abcdef", "d") +'def' +>>> +\end{verbatim} + +You can also use a callable Python object (a function or a class for +example) as the \member{restype} attribute, if the foreign function returns +an integer. The callable will be called with the \code{integer} the C +function returns, and the result of this call will be used as the +result of your function call. This is useful to check for error return +values and automatically raise an exception: +\begin{verbatim} +>>> GetModuleHandle = windll.kernel32.GetModuleHandleA # doctest: +WINDOWS +>>> def ValidHandle(value): +... if value == 0: +... raise WinError() +... return value +... +>>> +>>> GetModuleHandle.restype = ValidHandle # doctest: +WINDOWS +>>> GetModuleHandle(None) # doctest: +WINDOWS +486539264 +>>> GetModuleHandle("something silly") # doctest: +WINDOWS +Traceback (most recent call last): + File "", line 1, in ? + File "", line 3, in ValidHandle +WindowsError: [Errno 126] The specified module could not be found. +>>> +\end{verbatim} + +\code{WinError} is a function which will call Windows \code{FormatMessage()} +api to get the string representation of an error code, and \emph{returns} +an exception. \code{WinError} takes an optional error code parameter, if +no one is used, it calls \function{GetLastError()} to retrieve it. + +Please note that a much more powerful error checking mechanism is +available through the \member{errcheck} attribute; see the reference manual +for details. + + +\subsubsection{Passing pointers (or: passing parameters by reference)\label{ctypes-passing-pointers}} + +Sometimes a C api function expects a \emph{pointer} to a data type as +parameter, probably to write into the corresponding location, or if +the data is too large to be passed by value. This is also known as +\emph{passing parameters by reference}. + +\code{ctypes} exports the \function{byref} function which is used to pass +parameters by reference. The same effect can be achieved with the +\code{pointer} function, although \code{pointer} does a lot more work since +it constructs a real pointer object, so it is faster to use \function{byref} +if you don't need the pointer object in Python itself: +\begin{verbatim} +>>> i = c_int() +>>> f = c_float() +>>> s = create_string_buffer('\000' * 32) +>>> print i.value, f.value, repr(s.value) +0 0.0 '' +>>> libc.sscanf("1 3.14 Hello", "%d %f %s", +... byref(i), byref(f), s) +3 +>>> print i.value, f.value, repr(s.value) +1 3.1400001049 'Hello' +>>> +\end{verbatim} + + +\subsubsection{Structures and unions\label{ctypes-structures-unions}} + +Structures and unions must derive from the \class{Structure} and \class{Union} +base classes which are defined in the \code{ctypes} module. Each subclass +must define a \member{{\_}fields{\_}} attribute. \member{{\_}fields{\_}} must be a list of +\emph{2-tuples}, containing a \emph{field name} and a \emph{field type}. + +The field type must be a \code{ctypes} type like \class{c{\_}int}, or any other +derived \code{ctypes} type: structure, union, array, pointer. + +Here is a simple example of a POINT structure, which contains two +integers named \code{x} and \code{y}, and also shows how to initialize a +structure in the constructor: +\begin{verbatim} +>>> from ctypes import * +>>> class POINT(Structure): +... _fields_ = [("x", c_int), +... ("y", c_int)] +... +>>> point = POINT(10, 20) +>>> print point.x, point.y +10 20 +>>> point = POINT(y=5) +>>> print point.x, point.y +0 5 +>>> POINT(1, 2, 3) +Traceback (most recent call last): + File "", line 1, in ? +ValueError: too many initializers +>>> +\end{verbatim} + +You can, however, build much more complicated structures. Structures +can itself contain other structures by using a structure as a field +type. + +Here is a RECT structure which contains two POINTs named \code{upperleft} +and \code{lowerright} +\begin{verbatim} +>>> class RECT(Structure): +... _fields_ = [("upperleft", POINT), +... ("lowerright", POINT)] +... +>>> rc = RECT(point) +>>> print rc.upperleft.x, rc.upperleft.y +0 5 +>>> print rc.lowerright.x, rc.lowerright.y +0 0 +>>> +\end{verbatim} + +Nested structures can also be initialized in the constructor in +several ways: +\begin{verbatim} +>>> r = RECT(POINT(1, 2), POINT(3, 4)) +>>> r = RECT((1, 2), (3, 4)) +\end{verbatim} + +Fields descriptors can be retrieved from the \emph{class}, they are useful +for debugging because they can provide useful information: +\begin{verbatim} +>>> print POINT.x + +>>> print POINT.y + +>>> +\end{verbatim} + + +\subsubsection{Structure/union alignment and byte order\label{ctypes-structureunion-alignment-byte-order}} + +By default, Structure and Union fields are aligned in the same way the +C compiler does it. It is possible to override this behaviour be +specifying a \member{{\_}pack{\_}} class attribute in the subclass +definition. This must be set to a positive integer and specifies the +maximum alignment for the fields. This is what \code{{\#}pragma pack(n)} +also does in MSVC. + +\code{ctypes} uses the native byte order for Structures and Unions. To +build structures with non-native byte order, you can use one of the +BigEndianStructure, LittleEndianStructure, BigEndianUnion, and +LittleEndianUnion base classes. These classes cannot contain pointer +fields. + + +\subsubsection{Bit fields in structures and unions\label{ctypes-bit-fields-in-structures-unions}} + +It is possible to create structures and unions containing bit fields. +Bit fields are only possible for integer fields, the bit width is +specified as the third item in the \member{{\_}fields{\_}} tuples: +\begin{verbatim} +>>> class Int(Structure): +... _fields_ = [("first_16", c_int, 16), +... ("second_16", c_int, 16)] +... +>>> print Int.first_16 + +>>> print Int.second_16 + +>>> +\end{verbatim} + + +\subsubsection{Arrays\label{ctypes-arrays}} + +Arrays are sequences, containing a fixed number of instances of the +same type. + +The recommended way to create array types is by multiplying a data +type with a positive integer: +\begin{verbatim} +TenPointsArrayType = POINT * 10 +\end{verbatim} + +Here is an example of an somewhat artifical data type, a structure +containing 4 POINTs among other stuff: +\begin{verbatim} +>>> from ctypes import * +>>> class POINT(Structure): +... _fields_ = ("x", c_int), ("y", c_int) +... +>>> class MyStruct(Structure): +... _fields_ = [("a", c_int), +... ("b", c_float), +... ("point_array", POINT * 4)] +>>> +>>> print len(MyStruct().point_array) +4 +>>> +\end{verbatim} + +Instances are created in the usual way, by calling the class: +\begin{verbatim} +arr = TenPointsArrayType() +for pt in arr: + print pt.x, pt.y +\end{verbatim} + +The above code print a series of \code{0 0} lines, because the array +contents is initialized to zeros. + +Initializers of the correct type can also be specified: +\begin{verbatim} +>>> from ctypes import * +>>> TenIntegers = c_int * 10 +>>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) +>>> print ii + +>>> for i in ii: print i, +... +1 2 3 4 5 6 7 8 9 10 +>>> +\end{verbatim} + + +\subsubsection{Pointers\label{ctypes-pointers}} + +Pointer instances are created by calling the \code{pointer} function on a +\code{ctypes} type: +\begin{verbatim} +>>> from ctypes import * +>>> i = c_int(42) +>>> pi = pointer(i) +>>> +\end{verbatim} + +Pointer instances have a \code{contents} attribute which returns the +object to which the pointer points, the \code{i} object above: +\begin{verbatim} +>>> pi.contents +c_long(42) +>>> +\end{verbatim} + +Note that \code{ctypes} does not have OOR (original object return), it +constructs a new, equivalent object each time you retrieve an +attribute: +\begin{verbatim} +>>> pi.contents is i +False +>>> pi.contents is pi.contents +False +>>> +\end{verbatim} + +Assigning another \class{c{\_}int} instance to the pointer's contents +attribute would cause the pointer to point to the memory location +where this is stored: +\begin{verbatim} +>>> i = c_int(99) +>>> pi.contents = i +>>> pi.contents +c_long(99) +>>> +\end{verbatim} + +Pointer instances can also be indexed with integers: +\begin{verbatim} +>>> pi[0] +99 +>>> +\end{verbatim} + +Assigning to an integer index changes the pointed to value: +\begin{verbatim} +>>> print i +c_long(99) +>>> pi[0] = 22 +>>> print i +c_long(22) +>>> +\end{verbatim} + +It is also possible to use indexes different from 0, but you must know +what you're doing, just as in C: You can access or change arbitrary +memory locations. Generally you only use this feature if you receive a +pointer from a C function, and you \emph{know} that the pointer actually +points to an array instead of a single item. + +Behind the scenes, the \code{pointer} function does more than simply +create pointer instances, it has to create pointer \emph{types} first. +This is done with the \code{POINTER} function, which accepts any +\code{ctypes} type, and returns a new type: +\begin{verbatim} +>>> PI = POINTER(c_int) +>>> PI + +>>> PI(42) +Traceback (most recent call last): + File "", line 1, in ? +TypeError: expected c_long instead of int +>>> PI(c_int(42)) + +>>> +\end{verbatim} + +Calling the pointer type without an argument creates a \code{NULL} +pointer. \code{NULL} pointers have a \code{False} boolean value: +\begin{verbatim} +>>> null_ptr = POINTER(c_int)() +>>> print bool(null_ptr) +False +>>> +\end{verbatim} + +\code{ctypes} checks for \code{NULL} when dereferencing pointers (but +dereferencing non-\code{NULL} pointers would crash Python): +\begin{verbatim} +>>> null_ptr[0] +Traceback (most recent call last): + .... +ValueError: NULL pointer access +>>> + +>>> null_ptr[0] = 1234 +Traceback (most recent call last): + .... +ValueError: NULL pointer access +>>> +\end{verbatim} + + +\subsubsection{Type conversions\label{ctypes-type-conversions}} + +Usually, ctypes does strict type checking. This means, if you have +\code{POINTER(c{\_}int)} in the \member{argtypes} list of a function or as the +type of a member field in a structure definition, only instances of +exactly the same type are accepted. There are some exceptions to this +rule, where ctypes accepts other objects. For example, you can pass +compatible array instances instead of pointer types. So, for +\code{POINTER(c{\_}int)}, ctypes accepts an array of c{\_}int: +\begin{verbatim} +>>> class Bar(Structure): +... _fields_ = [("count", c_int), ("values", POINTER(c_int))] +... +>>> bar = Bar() +>>> bar.values = (c_int * 3)(1, 2, 3) +>>> bar.count = 3 +>>> for i in range(bar.count): +... print bar.values[i] +... +1 +2 +3 +>>> +\end{verbatim} + +To set a POINTER type field to \code{NULL}, you can assign \code{None}: +\begin{verbatim} +>>> bar.values = None +>>> +\end{verbatim} + +XXX list other conversions... + +Sometimes you have instances of incompatible types. In \code{C}, you can +cast one type into another type. \code{ctypes} provides a \code{cast} +function which can be used in the same way. The \code{Bar} structure +defined above accepts \code{POINTER(c{\_}int)} pointers or \class{c{\_}int} arrays +for its \code{values} field, but not instances of other types: +\begin{verbatim} +>>> bar.values = (c_byte * 4)() +Traceback (most recent call last): + File "", line 1, in ? +TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance +>>> +\end{verbatim} + +For these cases, the \code{cast} function is handy. + +The \code{cast} function can be used to cast a ctypes instance into a +pointer to a different ctypes data type. \code{cast} takes two +parameters, a ctypes object that is or can be converted to a pointer +of some kind, and a ctypes pointer type. It returns an instance of +the second argument, which references the same memory block as the +first argument: +\begin{verbatim} +>>> a = (c_byte * 4)() +>>> cast(a, POINTER(c_int)) + +>>> +\end{verbatim} + +So, \code{cast} can be used to assign to the \code{values} field of \code{Bar} +the structure: +\begin{verbatim} +>>> bar = Bar() +>>> bar.values = cast((c_byte * 4)(), POINTER(c_int)) +>>> print bar.values[0] +0 +>>> +\end{verbatim} + + +\subsubsection{Incomplete Types\label{ctypes-incomplete-types}} + +\emph{Incomplete Types} are structures, unions or arrays whose members are +not yet specified. In C, they are specified by forward declarations, which +are defined later: +\begin{verbatim} +struct cell; /* forward declaration */ + +struct { + char *name; + struct cell *next; +} cell; +\end{verbatim} + +The straightforward translation into ctypes code would be this, but it +does not work: +\begin{verbatim} +>>> class cell(Structure): +... _fields_ = [("name", c_char_p), +... ("next", POINTER(cell))] +... +Traceback (most recent call last): + File "", line 1, in ? + File "", line 2, in cell +NameError: name 'cell' is not defined +>>> +\end{verbatim} + +because the new \code{class cell} is not available in the class statement +itself. In \code{ctypes}, we can define the \code{cell} class and set the +\member{{\_}fields{\_}} attribute later, after the class statement: +\begin{verbatim} +>>> from ctypes import * +>>> class cell(Structure): +... pass +... +>>> cell._fields_ = [("name", c_char_p), +... ("next", POINTER(cell))] +>>> +\end{verbatim} + +Lets try it. We create two instances of \code{cell}, and let them point +to each other, and finally follow the pointer chain a few times: +\begin{verbatim} +>>> c1 = cell() +>>> c1.name = "foo" +>>> c2 = cell() +>>> c2.name = "bar" +>>> c1.next = pointer(c2) +>>> c2.next = pointer(c1) +>>> p = c1 +>>> for i in range(8): +... print p.name, +... p = p.next[0] +... +foo bar foo bar foo bar foo bar +>>> +\end{verbatim} + + +\subsubsection{Callback functions\label{ctypes-callback-functions}} + +\code{ctypes} allows to create C callable function pointers from Python +callables. These are sometimes called \emph{callback functions}. + +First, you must create a class for the callback function, the class +knows the calling convention, the return type, and the number and +types of arguments this function will receive. + +The CFUNCTYPE factory function creates types for callback functions +using the normal cdecl calling convention, and, on Windows, the +WINFUNCTYPE factory function creates types for callback functions +using the stdcall calling convention. + +Both of these factory functions are called with the result type as +first argument, and the callback functions expected argument types as +the remaining arguments. + +I will present an example here which uses the standard C library's +\function{qsort} function, this is used to sort items with the help of a +callback function. \function{qsort} will be used to sort an array of +integers: +\begin{verbatim} +>>> IntArray5 = c_int * 5 +>>> ia = IntArray5(5, 1, 7, 33, 99) +>>> qsort = libc.qsort +>>> qsort.restype = None +>>> +\end{verbatim} + +\function{qsort} must be called with a pointer to the data to sort, the +number of items in the data array, the size of one item, and a pointer +to the comparison function, the callback. The callback will then be +called with two pointers to items, and it must return a negative +integer if the first item is smaller than the second, a zero if they +are equal, and a positive integer else. + +So our callback function receives pointers to integers, and must +return an integer. First we create the \code{type} for the callback +function: +\begin{verbatim} +>>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int)) +>>> +\end{verbatim} + +For the first implementation of the callback function, we simply print +the arguments we get, and return 0 (incremental development ;-): +\begin{verbatim} +>>> def py_cmp_func(a, b): +... print "py_cmp_func", a, b +... return 0 +... +>>> +\end{verbatim} + +Create the C callable callback: +\begin{verbatim} +>>> cmp_func = CMPFUNC(py_cmp_func) +>>> +\end{verbatim} + +And we're ready to go: +\begin{verbatim} +>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +WINDOWS +py_cmp_func +py_cmp_func +py_cmp_func +py_cmp_func +py_cmp_func +py_cmp_func +py_cmp_func +py_cmp_func +py_cmp_func +py_cmp_func +>>> +\end{verbatim} + +We know how to access the contents of a pointer, so lets redefine our callback: +\begin{verbatim} +>>> def py_cmp_func(a, b): +... print "py_cmp_func", a[0], b[0] +... return 0 +... +>>> cmp_func = CMPFUNC(py_cmp_func) +>>> +\end{verbatim} + +Here is what we get on Windows: +\begin{verbatim} +>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +WINDOWS +py_cmp_func 7 1 +py_cmp_func 33 1 +py_cmp_func 99 1 +py_cmp_func 5 1 +py_cmp_func 7 5 +py_cmp_func 33 5 +py_cmp_func 99 5 +py_cmp_func 7 99 +py_cmp_func 33 99 +py_cmp_func 7 33 +>>> +\end{verbatim} + +It is funny to see that on linux the sort function seems to work much +more efficient, it is doing less comparisons: +\begin{verbatim} +>>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +LINUX +py_cmp_func 5 1 +py_cmp_func 33 99 +py_cmp_func 7 33 +py_cmp_func 5 7 +py_cmp_func 1 7 +>>> +\end{verbatim} + +Ah, we're nearly done! The last step is to actually compare the two +items and return a useful result: +\begin{verbatim} +>>> def py_cmp_func(a, b): +... print "py_cmp_func", a[0], b[0] +... return a[0] - b[0] +... +>>> +\end{verbatim} + +Final run on Windows: +\begin{verbatim} +>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +WINDOWS +py_cmp_func 33 7 +py_cmp_func 99 33 +py_cmp_func 5 99 +py_cmp_func 1 99 +py_cmp_func 33 7 +py_cmp_func 1 33 +py_cmp_func 5 33 +py_cmp_func 5 7 +py_cmp_func 1 7 +py_cmp_func 5 1 +>>> +\end{verbatim} + +and on Linux: +\begin{verbatim} +>>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +LINUX +py_cmp_func 5 1 +py_cmp_func 33 99 +py_cmp_func 7 33 +py_cmp_func 1 7 +py_cmp_func 5 7 +>>> +\end{verbatim} + +It is quite interesting to see that the Windows \function{qsort} function +needs more comparisons than the linux version! + +As we can easily check, our array is sorted now: +\begin{verbatim} +>>> for i in ia: print i, +... +1 5 7 33 99 +>>> +\end{verbatim} + +\textbf{Important note for callback functions:} + +Make sure you keep references to CFUNCTYPE objects as long as they are +used from C code. \code{ctypes} doesn't, and if you don't, they may be +garbage collected, crashing your program when a callback is made. + + +\subsubsection{Accessing values exported from dlls\label{ctypes-accessing-values-exported-from-dlls}} + +Sometimes, a dll not only exports functions, it also exports +variables. An example in the Python library itself is the +\code{Py{\_}OptimizeFlag}, an integer set to 0, 1, or 2, depending on the +\programopt{-O} or \programopt{-OO} flag given on startup. + +\code{ctypes} can access values like this with the \method{in{\_}dll} class +methods of the type. \var{pythonapi} ìs a predefined symbol giving +access to the Python C api: +\begin{verbatim} +>>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag") +>>> print opt_flag +c_long(0) +>>> +\end{verbatim} + +If the interpreter would have been started with \programopt{-O}, the sample +would have printed \code{c{\_}long(1)}, or \code{c{\_}long(2)} if \programopt{-OO} would have +been specified. + +An extended example which also demonstrates the use of pointers +accesses the \code{PyImport{\_}FrozenModules} pointer exported by Python. + +Quoting the Python docs: \emph{This pointer is initialized to point to an +array of ``struct {\_}frozen`` records, terminated by one whose members +are all NULL or zero. When a frozen module is imported, it is searched +in this table. Third-party code could play tricks with this to provide +a dynamically created collection of frozen modules.} + +So manipulating this pointer could even prove useful. To restrict the +example size, we show only how this table can be read with +\code{ctypes}: +\begin{verbatim} +>>> from ctypes import * +>>> +>>> class struct_frozen(Structure): +... _fields_ = [("name", c_char_p), +... ("code", POINTER(c_ubyte)), +... ("size", c_int)] +... +>>> +\end{verbatim} + +We have defined the \code{struct {\_}frozen} data type, so we can get the +pointer to the table: +\begin{verbatim} +>>> FrozenTable = POINTER(struct_frozen) +>>> table = FrozenTable.in_dll(pythonapi, "PyImport_FrozenModules") +>>> +\end{verbatim} + +Since \code{table} is a \code{pointer} to the array of \code{struct{\_}frozen} +records, we can iterate over it, but we just have to make sure that +our loop terminates, because pointers have no size. Sooner or later it +would probably crash with an access violation or whatever, so it's +better to break out of the loop when we hit the NULL entry: +\begin{verbatim} +>>> for item in table: +... print item.name, item.size +... if item.name is None: +... break +... +__hello__ 104 +__phello__ -104 +__phello__.spam 104 +None 0 +>>> +\end{verbatim} + +The fact that standard Python has a frozen module and a frozen package +(indicated by the negative size member) is not wellknown, it is only +used for testing. Try it out with \code{import {\_}{\_}hello{\_}{\_}} for example. + + +\subsubsection{Surprises\label{ctypes-surprises}} + +There are some edges in \code{ctypes} where you may be expect something +else than what actually happens. + +Consider the following example: +\begin{verbatim} +>>> from ctypes import * +>>> class POINT(Structure): +... _fields_ = ("x", c_int), ("y", c_int) +... +>>> class RECT(Structure): +... _fields_ = ("a", POINT), ("b", POINT) +... +>>> p1 = POINT(1, 2) +>>> p2 = POINT(3, 4) +>>> rc = RECT(p1, p2) +>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y +1 2 3 4 +>>> # now swap the two points +>>> rc.a, rc.b = rc.b, rc.a +>>> print rc.a.x, rc.a.y, rc.b.x, rc.b.y +3 4 3 4 +>>> +\end{verbatim} + +Hm. We certainly expected the last statement to print \code{3 4 1 2}. +What happended? Here are the steps of the \code{rc.a, rc.b = rc.b, rc.a} +line above: +\begin{verbatim} +>>> temp0, temp1 = rc.b, rc.a +>>> rc.a = temp0 +>>> rc.b = temp1 +>>> +\end{verbatim} + +Note that \code{temp0} and \code{temp1} are objects still using the internal +buffer of the \code{rc} object above. So executing \code{rc.a = temp0} +copies the buffer contents of \code{temp0} into \code{rc} 's buffer. This, +in turn, changes the contents of \code{temp1}. So, the last assignment +\code{rc.b = temp1}, doesn't have the expected effect. + +Keep in mind that retrieving subobjects from Structure, Unions, and +Arrays doesn't \emph{copy} the subobject, instead it retrieves a wrapper +object accessing the root-object's underlying buffer. + +Another example that may behave different from what one would expect is this: +\begin{verbatim} +>>> s = c_char_p() +>>> s.value = "abc def ghi" +>>> s.value +'abc def ghi' +>>> s.value is s.value +False +>>> +\end{verbatim} + +Why is it printing \code{False}? ctypes instances are objects containing +a memory block plus some descriptors accessing the contents of the +memory. Storing a Python object in the memory block does not store +the object itself, instead the \code{contents} of the object is stored. +Accessing the contents again constructs a new Python each time! + + +\subsubsection{Variable-sized data types\label{ctypes-variable-sized-data-types}} + +\code{ctypes} provides some support for variable-sized arrays and +structures (this was added in version 0.9.9.7). + +The \code{resize} function can be used to resize the memory buffer of an +existing ctypes object. The function takes the object as first +argument, and the requested size in bytes as the second argument. The +memory block cannot be made smaller than the natural memory block +specified by the objects type, a \code{ValueError} is raised if this is +tried: +\begin{verbatim} +>>> short_array = (c_short * 4)() +>>> print sizeof(short_array) +8 +>>> resize(short_array, 4) +Traceback (most recent call last): + ... +ValueError: minimum size is 8 +>>> resize(short_array, 32) +>>> sizeof(short_array) +32 +>>> sizeof(type(short_array)) +8 +>>> +\end{verbatim} + +This is nice and fine, but how would one access the additional +elements contained in this array? Since the type still only knows +about 4 elements, we get errors accessing other elements: +\begin{verbatim} +>>> short_array[:] +[0, 0, 0, 0] +>>> short_array[7] +Traceback (most recent call last): + ... +IndexError: invalid index +>>> +\end{verbatim} + +Another way to use variable-sized data types with \code{ctypes} is to use +the dynamic nature of Python, and (re-)define the data type after the +required size is already known, on a case by case basis. + + +\subsubsection{Bugs, ToDo and non-implemented things\label{ctypes-bugs-todo-non-implemented-things}} + +Enumeration types are not implemented. You can do it easily yourself, +using \class{c{\_}int} as the base class. + +\code{long double} is not implemented. +% Local Variables: +% compile-command: "make.bat" +% End: + + +\subsection{ctypes reference\label{ctypes-ctypes-reference}} + + +\subsubsection{Finding shared libraries\label{ctypes-finding-shared-libraries}} + +When programming in a compiled language, shared libraries are accessed +when compiling/linking a program, and when the program is run. + +The purpose of the \code{find{\_}library} function is to locate a library in +a way similar to what the compiler does (on platforms with several +versions of a shared library the most recent should be loaded), while +the ctypes library loaders act like when a program is run, and call +the runtime loader directly. + +The \code{ctypes.util} module provides a function which can help to +determine the library to load. + +\begin{datadescni}{find_library(name)} +Try to find a library and return a pathname. \var{name} is the +library name without any prefix like \var{lib}, suffix like \code{.so}, +\code{.dylib} or version number (this is the form used for the posix +linker option \programopt{-l}). If no library can be found, returns +\code{None}. +\end{datadescni} + +The exact functionality is system dependend. + +On Linux, \code{find{\_}library} tries to run external programs +(/sbin/ldconfig, gcc, and objdump) to find the library file. It +returns the filename of the library file. Here are sone examples: +\begin{verbatim} +>>> from ctypes.util import find_library +>>> find_library("m") +'libm.so.6' +>>> find_library("c") +'libc.so.6' +>>> find_library("bz2") +'libbz2.so.1.0' +>>> +\end{verbatim} + +On OS X, \code{find{\_}library} tries several predefined naming schemes and +paths to locate the library, and returns a full pathname if successfull: +\begin{verbatim} +>>> from ctypes.util import find_library +>>> find_library("c") +'/usr/lib/libc.dylib' +>>> find_library("m") +'/usr/lib/libm.dylib' +>>> find_library("bz2") +'/usr/lib/libbz2.dylib' +>>> find_library("AGL") +'/System/Library/Frameworks/AGL.framework/AGL' +>>> +\end{verbatim} + +On Windows, \code{find{\_}library} searches along the system search path, +and returns the full pathname, but since there is no predefined naming +scheme a call like \code{find{\_}library("c")} will fail and return +\code{None}. + +If wrapping a shared library with \code{ctypes}, it \emph{may} be better to +determine the shared library name at development type, and hardcode +that into the wrapper module instead of using \code{find{\_}library} to +locate the library at runtime. + + +\subsubsection{Loading shared libraries\label{ctypes-loading-shared-libraries}} + +There are several ways to loaded shared libraries into the Python +process. One way is to instantiate one of the following classes: + +\begin{classdesc}{CDLL}{name, mode=DEFAULT_MODE, handle=None} +Instances of this class represent loaded shared libraries. +Functions in these libraries use the standard C calling +convention, and are assumed to return \code{int}. +\end{classdesc} + +\begin{classdesc}{OleDLL}{name, mode=DEFAULT_MODE, handle=None} +Windows only: Instances of this class represent loaded shared +libraries, functions in these libraries use the \code{stdcall} +calling convention, and are assumed to return the windows specific +\class{HRESULT} code. \class{HRESULT} values contain information +specifying whether the function call failed or succeeded, together +with additional error code. If the return value signals a +failure, an \class{WindowsError} is automatically raised. +\end{classdesc} + +\begin{classdesc}{WinDLL}{name, mode=DEFAULT_MODE, handle=None} +Windows only: Instances of this class represent loaded shared +libraries, functions in these libraries use the \code{stdcall} +calling convention, and are assumed to return \code{int} by default. + +On Windows CE only the standard calling convention is used, for +convenience the \class{WinDLL} and \class{OleDLL} use the standard calling +convention on this platform. +\end{classdesc} + +The Python GIL is released before calling any function exported by +these libraries, and reaquired afterwards. + +\begin{classdesc}{PyDLL}{name, mode=DEFAULT_MODE, handle=None} +Instances of this class behave like \class{CDLL} instances, except +that the Python GIL is \emph{not} released during the function call, +and after the function execution the Python error flag is checked. +If the error flag is set, a Python exception is raised. + +Thus, this is only useful to call Python C api functions directly. +\end{classdesc} + +All these classes can be instantiated by calling them with at least +one argument, the pathname of the shared library. If you have an +existing handle to an already loaded shard library, it can be passed +as the \code{handle} named parameter, otherwise the underlying platforms +\code{dlopen} or \method{LoadLibrary} function is used to load the library +into the process, and to get a handle to it. + +The \var{mode} parameter can be used to specify how the library is +loaded. For details, consult the \code{dlopen(3)} manpage, on Windows, +\var{mode} is ignored. + +\begin{datadescni}{RTLD_GLOBAL} +Flag to use as \var{mode} parameter. On platforms where this flag +is not available, it is defined as the integer zero. +\end{datadescni} + +\begin{datadescni}{RTLD_LOCAL} +Flag to use as \var{mode} parameter. On platforms where this is not +available, it is the same as \var{RTLD{\_}GLOBAL}. +\end{datadescni} + +\begin{datadescni}{DEFAULT_MODE} +The default mode which is used to load shared libraries. On OSX +10.3, this is \var{RTLD{\_}GLOBAL}, otherwise it is the same as +\var{RTLD{\_}LOCAL}. +\end{datadescni} + +Instances of these classes have no public methods, however +\method{{\_}{\_}getattr{\_}{\_}} and \method{{\_}{\_}getitem{\_}{\_}} have special behaviour: functions +exported by the shared library can be accessed as attributes of by +index. Please note that both \method{{\_}{\_}getattr{\_}{\_}} and \method{{\_}{\_}getitem{\_}{\_}} +cache their result, so calling them repeatedly returns the same object +each time. + +The following public attributes are available, their name starts with +an underscore to not clash with exported function names: + +\begin{memberdesc}{_handle} +The system handle used to access the library. +\end{memberdesc} + +\begin{memberdesc}{_name} +The name of the library passed in the contructor. +\end{memberdesc} + +Shared libraries can also be loaded by using one of the prefabricated +objects, which are instances of the \class{LibraryLoader} class, either by +calling the \method{LoadLibrary} method, or by retrieving the library as +attribute of the loader instance. + +\begin{classdesc}{LibraryLoader}{dlltype} +Class which loads shared libraries. \code{dlltype} should be one +of the \class{CDLL}, \class{PyDLL}, \class{WinDLL}, or \class{OleDLL} types. + +\method{{\_}{\_}getattr{\_}{\_}} has special behaviour: It allows to load a shared +library by accessing it as attribute of a library loader +instance. The result is cached, so repeated attribute accesses +return the same library each time. +\end{classdesc} + +\begin{methoddesc}{LoadLibrary}{name} +Load a shared library into the process and return it. This method +always returns a new instance of the library. +\end{methoddesc} + +These prefabricated library loaders are available: + +\begin{datadescni}{cdll} +Creates \class{CDLL} instances. +\end{datadescni} + +\begin{datadescni}{windll} +Windows only: Creates \class{WinDLL} instances. +\end{datadescni} + +\begin{datadescni}{oledll} +Windows only: Creates \class{OleDLL} instances. +\end{datadescni} + +\begin{datadescni}{pydll} +Creates \class{PyDLL} instances. +\end{datadescni} + +For accessing the C Python api directly, a ready-to-use Python shared +library object is available: + +\begin{datadescni}{pythonapi} +An instance of \class{PyDLL} that exposes Python C api functions as +attributes. Note that all these functions are assumed to return C +\code{int}, which is of course not always the truth, so you have to +assign the correct \member{restype} attribute to use these functions. +\end{datadescni} + + +\subsubsection{Foreign functions\label{ctypes-foreign-functions}} + +As explained in the previous section, foreign functions can be +accessed as attributes of loaded shared libraries. The function +objects created in this way by default accept any number of arguments, +accept any ctypes data instances as arguments, and return the default +result type specified by the library loader. They are instances of a +private class: + +\begin{classdesc*}{_FuncPtr} +Base class for C callable foreign functions. +\end{classdesc*} + +Instances of foreign functions are also C compatible data types; they +represent C function pointers. + +This behaviour can be customized by assigning to special attributes of +the foreign function object. + +\begin{memberdesc}{restype} +Assign a ctypes type to specify the result type of the foreign +function. Use \code{None} for \code{void} a function not returning +anything. + +It is possible to assign a callable Python object that is not a +ctypes type, in this case the function is assumed to return a +C \code{int}, and the callable will be called with this integer, +allowing to do further processing or error checking. Using this +is deprecated, for more flexible postprocessing or error checking +use a ctypes data type as \member{restype} and assign a callable to the +\member{errcheck} attribute. +\end{memberdesc} + +\begin{memberdesc}{argtypes} +Assign a tuple of ctypes types to specify the argument types that +the function accepts. Functions using the \code{stdcall} calling +convention can only be called with the same number of arguments as +the length of this tuple; functions using the C calling convention +accept additional, unspecified arguments as well. + +When a foreign function is called, each actual argument is passed +to the \method{from{\_}param} class method of the items in the +\member{argtypes} tuple, this method allows to adapt the actual +argument to an object that the foreign function accepts. For +example, a \class{c{\_}char{\_}p} item in the \member{argtypes} tuple will +convert a unicode string passed as argument into an byte string +using ctypes conversion rules. + +New: It is now possible to put items in argtypes which are not +ctypes types, but each item must have a \method{from{\_}param} method +which returns a value usable as argument (integer, string, ctypes +instance). This allows to define adapters that can adapt custom +objects as function parameters. +\end{memberdesc} + +\begin{memberdesc}{errcheck} +Assign a Python function or another callable to this attribute. +The callable will be called with three or more arguments: +\end{memberdesc} + +\begin{funcdescni}{callable}{result, func, arguments} +\code{result} is what the foreign function returns, as specified by the +\member{restype} attribute. + +\code{func} is the foreign function object itself, this allows to +reuse the same callable object to check or postprocess the results +of several functions. + +\code{arguments} is a tuple containing the parameters originally +passed to the function call, this allows to specialize the +behaviour on the arguments used. + +The object that this function returns will be returned from the +foreign function call, but it can also check the result value and +raise an exception if the foreign function call failed. +\end{funcdescni} + +\begin{excdesc}{ArgumentError()} +This exception is raised when a foreign function call cannot +convert one of the passed arguments. +\end{excdesc} + + +\subsubsection{Function prototypes\label{ctypes-function-prototypes}} + +Foreign functions can also be created by instantiating function +prototypes. Function prototypes are similar to function prototypes in +C; they describe a function (return type, argument types, calling +convention) without defining an implementation. The factory +functions must be called with the desired result type and the argument +types of the function. + +\begin{funcdesc}{CFUNCTYPE}{restype, *argtypes} +The returned function prototype creates functions that use the +standard C calling convention. The function will release the GIL +during the call. +\end{funcdesc} + +\begin{funcdesc}{WINFUNCTYPE}{restype, *argtypes} +Windows only: The returned function prototype creates functions +that use the \code{stdcall} calling convention, except on Windows CE +where \function{WINFUNCTYPE} is the same as \function{CFUNCTYPE}. The function +will release the GIL during the call. +\end{funcdesc} + +\begin{funcdesc}{PYFUNCTYPE}{restype, *argtypes} +The returned function prototype creates functions that use the +Python calling convention. The function will \emph{not} release the +GIL during the call. +\end{funcdesc} + +Function prototypes created by the factory functions can be +instantiated in different ways, depending on the type and number of +the parameters in the call. + +\begin{funcdescni}{prototype}{address} +Returns a foreign function at the specified address. +\end{funcdescni} + +\begin{funcdescni}{prototype}{callable} +Create a C callable function (a callback function) from a Python +\code{callable}. +\end{funcdescni} + +\begin{funcdescni}{prototype}{func_spec\optional{, paramflags}} +Returns a foreign function exported by a shared library. +\code{func{\_}spec} must be a 2-tuple \code{(name{\_}or{\_}ordinal, library)}. +The first item is the name of the exported function as string, or +the ordinal of the exported function as small integer. The second +item is the shared library instance. +\end{funcdescni} + +\begin{funcdescni}{prototype}{vtbl_index, name\optional{, paramflags\optional{, iid}}} +Returns a foreign function that will call a COM method. +\code{vtbl{\_}index} is the index into the virtual function table, a +small nonnegative integer. \var{name} is name of the COM method. +\var{iid} is an optional pointer to the interface identifier which +is used in extended error reporting. + +COM methods use a special calling convention: They require a +pointer to the COM interface as first argument, in addition to +those parameters that are specified in the \member{argtypes} tuple. +\end{funcdescni} + +The optional \var{paramflags} parameter creates foreign function +wrappers with much more functionality than the features described +above. + +\var{paramflags} must be a tuple of the same length as \member{argtypes}. + +Each item in this tuple contains further information about a +parameter, it must be a tuple containing 1, 2, or 3 items. + +The first item is an integer containing flags for the parameter: + +\begin{datadescni}{1} +Specifies an input parameter to the function. +\end{datadescni} + +\begin{datadescni}{2} +Output parameter. The foreign function fills in a value. +\end{datadescni} + +\begin{datadescni}{4} +Input parameter which defaults to the integer zero. +\end{datadescni} + +The optional second item is the parameter name as string. If this is +specified, the foreign function can be called with named parameters. + +The optional third item is the default value for this parameter. + +This example demonstrates how to wrap the Windows \code{MessageBoxA} +function so that it supports default parameters and named arguments. +The C declaration from the windows header file is this: +\begin{verbatim} +WINUSERAPI int WINAPI +MessageBoxA( + HWND hWnd , + LPCSTR lpText, + LPCSTR lpCaption, + UINT uType); +\end{verbatim} + +Here is the wrapping with \code{ctypes}: +\begin{quote} +\begin{verbatim}>>> from ctypes import c_int, WINFUNCTYPE, windll +>>> from ctypes.wintypes import HWND, LPCSTR, UINT +>>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT) +>>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0) +>>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags) +>>>\end{verbatim} +\end{quote} + +The MessageBox foreign function can now be called in these ways: +\begin{verbatim} +>>> MessageBox() +>>> MessageBox(text="Spam, spam, spam") +>>> MessageBox(flags=2, text="foo bar") +>>> +\end{verbatim} + +A second example demonstrates output parameters. The win32 +\code{GetWindowRect} function retrieves the dimensions of a specified +window by copying them into \code{RECT} structure that the caller has to +supply. Here is the C declaration: +\begin{verbatim} +WINUSERAPI BOOL WINAPI +GetWindowRect( + HWND hWnd, + LPRECT lpRect); +\end{verbatim} + +Here is the wrapping with \code{ctypes}: +\begin{quote} +\begin{verbatim}>>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError +>>> from ctypes.wintypes import BOOL, HWND, RECT +>>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT)) +>>> paramflags = (1, "hwnd"), (2, "lprect") +>>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags) +>>>\end{verbatim} +\end{quote} + +Functions with output parameters will automatically return the output +parameter value if there is a single one, or a tuple containing the +output parameter values when there are more than one, so the +GetWindowRect function now returns a RECT instance, when called. + +Output parameters can be combined with the \member{errcheck} protocol to do +further output processing and error checking. The win32 +\code{GetWindowRect} api function returns a \code{BOOL} to signal success or +failure, so this function could do the error checking, and raises an +exception when the api call failed: +\begin{verbatim} +>>> def errcheck(result, func, args): +... if not result: +... raise WinError() +... return args +>>> GetWindowRect.errcheck = errcheck +>>> +\end{verbatim} + +If the \member{errcheck} function returns the argument tuple it receives +unchanged, \code{ctypes} continues the normal processing it does on the +output parameters. If you want to return a tuple of window +coordinates instead of a \code{RECT} instance, you can retrieve the +fields in the function and return them instead, the normal processing +will no longer take place: +\begin{verbatim} +>>> def errcheck(result, func, args): +... if not result: +... raise WinError() +... rc = args[1] +... return rc.left, rc.top, rc.bottom, rc.right +>>> +>>> GetWindowRect.errcheck = errcheck +>>> +\end{verbatim} + + +\subsubsection{Utility functions\label{ctypes-utility-functions}} + +\begin{funcdesc}{addressof}{obj} +Returns the address of the memory buffer as integer. \code{obj} must +be an instance of a ctypes type. +\end{funcdesc} + +\begin{funcdesc}{alignment}{obj_or_type} +Returns the alignment requirements of a ctypes type. +\code{obj{\_}or{\_}type} must be a ctypes type or instance. +\end{funcdesc} + +\begin{funcdesc}{byref}{obj} +Returns a light-weight pointer to \code{obj}, which must be an +instance of a ctypes type. The returned object can only be used as +a foreign function call parameter. It behaves similar to +\code{pointer(obj)}, but the construction is a lot faster. +\end{funcdesc} + +\begin{funcdesc}{cast}{obj, type} +This function is similar to the cast operator in C. It returns a +new instance of \code{type} which points to the same memory block as +\code{obj}. \code{type} must be a pointer type, and \code{obj} must be an +object that can be interpreted as a pointer. +\end{funcdesc} + +\begin{funcdesc}{create_string_buffer}{init_or_size\optional{, size}} +This function creates a mutable character buffer. The returned +object is a ctypes array of \class{c{\_}char}. + +\code{init{\_}or{\_}size} must be an integer which specifies the size of +the array, or a string which will be used to initialize the array +items. + +If a string is specified as first argument, the buffer is made one +item larger than the length of the string so that the last element +in the array is a NUL termination character. An integer can be +passed as second argument which allows to specify the size of the +array if the length of the string should not be used. + +If the first parameter is a unicode string, it is converted into +an 8-bit string according to ctypes conversion rules. +\end{funcdesc} + +\begin{funcdesc}{create_unicode_buffer}{init_or_size\optional{, size}} +This function creates a mutable unicode character buffer. The +returned object is a ctypes array of \class{c{\_}wchar}. + +\code{init{\_}or{\_}size} must be an integer which specifies the size of +the array, or a unicode string which will be used to initialize +the array items. + +If a unicode string is specified as first argument, the buffer is +made one item larger than the length of the string so that the +last element in the array is a NUL termination character. An +integer can be passed as second argument which allows to specify +the size of the array if the length of the string should not be +used. + +If the first parameter is a 8-bit string, it is converted into an +unicode string according to ctypes conversion rules. +\end{funcdesc} + +\begin{funcdesc}{DllCanUnloadNow}{} +Windows only: This function is a hook which allows to implement +inprocess COM servers with ctypes. It is called from the +DllCanUnloadNow function that the {\_}ctypes extension dll exports. +\end{funcdesc} + +\begin{funcdesc}{DllGetClassObject}{} +Windows only: This function is a hook which allows to implement +inprocess COM servers with ctypes. It is called from the +DllGetClassObject function that the \code{{\_}ctypes} extension dll exports. +\end{funcdesc} + +\begin{funcdesc}{FormatError}{\optional{code}} +Windows only: Returns a textual description of the error code. If +no error code is specified, the last error code is used by calling +the Windows api function GetLastError. +\end{funcdesc} + +\begin{funcdesc}{GetLastError}{} +Windows only: Returns the last error code set by Windows in the +calling thread. +\end{funcdesc} + +\begin{funcdesc}{memmove}{dst, src, count} +Same as the standard C memmove library function: copies \var{count} +bytes from \code{src} to \var{dst}. \var{dst} and \code{src} must be +integers or ctypes instances that can be converted to pointers. +\end{funcdesc} + +\begin{funcdesc}{memset}{dst, c, count} +Same as the standard C memset library function: fills the memory +block at address \var{dst} with \var{count} bytes of value +\var{c}. \var{dst} must be an integer specifying an address, or a +ctypes instance. +\end{funcdesc} + +\begin{funcdesc}{POINTER}{type} +This factory function creates and returns a new ctypes pointer +type. Pointer types are cached an reused internally, so calling +this function repeatedly is cheap. type must be a ctypes type. +\end{funcdesc} + +\begin{funcdesc}{pointer}{obj} +This function creates a new pointer instance, pointing to +\code{obj}. The returned object is of the type POINTER(type(obj)). + +Note: If you just want to pass a pointer to an object to a foreign +function call, you should use \code{byref(obj)} which is much faster. +\end{funcdesc} + +\begin{funcdesc}{resize}{obj, size} +This function resizes the internal memory buffer of obj, which +must be an instance of a ctypes type. It is not possible to make +the buffer smaller than the native size of the objects type, as +given by sizeof(type(obj)), but it is possible to enlarge the +buffer. +\end{funcdesc} + +\begin{funcdesc}{set_conversion_mode}{encoding, errors} +This function sets the rules that ctypes objects use when +converting between 8-bit strings and unicode strings. encoding +must be a string specifying an encoding, like \code{'utf-8'} or +\code{'mbcs'}, errors must be a string specifying the error handling +on encoding/decoding errors. Examples of possible values are +\code{"strict"}, \code{"replace"}, or \code{"ignore"}. + +\code{set{\_}conversion{\_}mode} returns a 2-tuple containing the previous +conversion rules. On windows, the initial conversion rules are +\code{('mbcs', 'ignore')}, on other systems \code{('ascii', 'strict')}. +\end{funcdesc} + +\begin{funcdesc}{sizeof}{obj_or_type} +Returns the size in bytes of a ctypes type or instance memory +buffer. Does the same as the C \code{sizeof()} function. +\end{funcdesc} + +\begin{funcdesc}{string_at}{address\optional{, size}} +This function returns the string starting at memory address +address. If size is specified, it is used as size, otherwise the +string is assumed to be zero-terminated. +\end{funcdesc} + +\begin{funcdesc}{WinError}{code=None, descr=None} +Windows only: this function is probably the worst-named thing in +ctypes. It creates an instance of WindowsError. If \var{code} is not +specified, \code{GetLastError} is called to determine the error +code. If \code{descr} is not spcified, \function{FormatError} is called to +get a textual description of the error. +\end{funcdesc} + +\begin{funcdesc}{wstring_at}{address} +This function returns the wide character string starting at memory +address \code{address} as unicode string. If \code{size} is specified, +it is used as the number of characters of the string, otherwise +the string is assumed to be zero-terminated. +\end{funcdesc} + + +\subsubsection{Data types\label{ctypes-data-types}} + +\begin{classdesc*}{_CData} +This non-public class is the common base class of all ctypes data +types. Among other things, all ctypes type instances contain a +memory block that hold C compatible data; the address of the +memory block is returned by the \code{addressof()} helper function. +Another instance variable is exposed as \member{{\_}objects}; this +contains other Python objects that need to be kept alive in case +the memory block contains pointers. +\end{classdesc*} + +Common methods of ctypes data types, these are all class methods (to +be exact, they are methods of the metaclass): + +\begin{methoddesc}{from_address}{address} +This method returns a ctypes type instance using the memory +specified by address which must be an integer. +\end{methoddesc} + +\begin{methoddesc}{from_param}{obj} +This method adapts obj to a ctypes type. It is called with the +actual object used in a foreign function call, when the type is +present in the foreign functions \member{argtypes} tuple; it must +return an object that can be used as function call parameter. + +All ctypes data types have a default implementation of this +classmethod, normally it returns \code{obj} if that is an instance of +the type. Some types accept other objects as well. +\end{methoddesc} + +\begin{methoddesc}{in_dll}{library, name} +This method returns a ctypes type instance exported by a shared +library. \var{name} is the name of the symbol that exports the data, +\var{library} is the loaded shared library. +\end{methoddesc} + +Common instance variables of ctypes data types: + +\begin{memberdesc}{_b_base_} +Sometimes ctypes data instances do not own the memory block they +contain, instead they share part of the memory block of a base +object. The \member{{\_}b{\_}base{\_}} readonly member is the root ctypes +object that owns the memory block. +\end{memberdesc} + +\begin{memberdesc}{_b_needsfree_} +This readonly variable is true when the ctypes data instance has +allocated the memory block itself, false otherwise. +\end{memberdesc} + +\begin{memberdesc}{_objects} +This member is either \code{None} or a dictionary containing Python +objects that need to be kept alive so that the memory block +contents is kept valid. This object is only exposed for +debugging; never modify the contents of this dictionary. +\end{memberdesc} + + +\subsubsection{Fundamental data types\label{ctypes-fundamental-data-types}} + +\begin{classdesc*}{_SimpleCData} +This non-public class is the base class of all fundamental ctypes +data types. It is mentioned here because it contains the common +attributes of the fundamental ctypes data types. \code{{\_}SimpleCData} +is a subclass of \code{{\_}CData}, so it inherits their methods and +attributes. +\end{classdesc*} + +Instances have a single attribute: + +\begin{memberdesc}{value} +This attribute contains the actual value of the instance. For +integer and pointer types, it is an integer, for character types, +it is a single character string, for character pointer types it +is a Python string or unicode string. + +When the \code{value} attribute is retrieved from a ctypes instance, +usually a new object is returned each time. \code{ctypes} does \emph{not} +implement original object return, always a new object is +constructed. The same is true for all other ctypes object +instances. +\end{memberdesc} + +Fundamental data types, when returned as foreign function call +results, or, for example, by retrieving structure field members or +array items, are transparently converted to native Python types. In +other words, if a foreign function has a \member{restype} of \class{c{\_}char{\_}p}, +you will always receive a Python string, \emph{not} a \class{c{\_}char{\_}p} +instance. + +Subclasses of fundamental data types do \emph{not} inherit this behaviour. +So, if a foreign functions \member{restype} is a subclass of \class{c{\_}void{\_}p}, +you will receive an instance of this subclass from the function call. +Of course, you can get the value of the pointer by accessing the +\code{value} attribute. + +These are the fundamental ctypes data types: + +\begin{classdesc*}{c_byte} +Represents the C signed char datatype, and interprets the value as +small integer. The constructor accepts an optional integer +initializer; no overflow checking is done. +\end{classdesc*} + +\begin{classdesc*}{c_char} +Represents the C char datatype, and interprets the value as a single +character. The constructor accepts an optional string initializer, +the length of the string must be exactly one character. +\end{classdesc*} + +\begin{classdesc*}{c_char_p} +Represents the C char * datatype, which must be a pointer to a +zero-terminated string. The constructor accepts an integer +address, or a string. +\end{classdesc*} + +\begin{classdesc*}{c_double} +Represents the C double datatype. The constructor accepts an +optional float initializer. +\end{classdesc*} + +\begin{classdesc*}{c_float} +Represents the C double datatype. The constructor accepts an +optional float initializer. +\end{classdesc*} + +\begin{classdesc*}{c_int} +Represents the C signed int datatype. The constructor accepts an +optional integer initializer; no overflow checking is done. On +platforms where \code{sizeof(int) == sizeof(long)} it is an alias to +\class{c{\_}long}. +\end{classdesc*} + +\begin{classdesc*}{c_int8} +Represents the C 8-bit \code{signed int} datatype. Usually an alias for +\class{c{\_}byte}. +\end{classdesc*} + +\begin{classdesc*}{c_int16} +Represents the C 16-bit signed int datatype. Usually an alias for +\class{c{\_}short}. +\end{classdesc*} + +\begin{classdesc*}{c_int32} +Represents the C 32-bit signed int datatype. Usually an alias for +\class{c{\_}int}. +\end{classdesc*} + +\begin{classdesc*}{c_int64} +Represents the C 64-bit \code{signed int} datatype. Usually an alias +for \class{c{\_}longlong}. +\end{classdesc*} + +\begin{classdesc*}{c_long} +Represents the C \code{signed long} datatype. The constructor accepts an +optional integer initializer; no overflow checking is done. +\end{classdesc*} + +\begin{classdesc*}{c_longlong} +Represents the C \code{signed long long} datatype. The constructor accepts +an optional integer initializer; no overflow checking is done. +\end{classdesc*} + +\begin{classdesc*}{c_short} +Represents the C \code{signed short} datatype. The constructor accepts an +optional integer initializer; no overflow checking is done. +\end{classdesc*} + +\begin{classdesc*}{c_size_t} +Represents the C \code{size{\_}t} datatype. +\end{classdesc*} + +\begin{classdesc*}{c_ubyte} +Represents the C \code{unsigned char} datatype, it interprets the +value as small integer. The constructor accepts an optional +integer initializer; no overflow checking is done. +\end{classdesc*} + +\begin{classdesc*}{c_uint} +Represents the C \code{unsigned int} datatype. The constructor accepts an +optional integer initializer; no overflow checking is done. On +platforms where \code{sizeof(int) == sizeof(long)} it is an alias for +\class{c{\_}ulong}. +\end{classdesc*} + +\begin{classdesc*}{c_uint8} +Represents the C 8-bit unsigned int datatype. Usually an alias for +\class{c{\_}ubyte}. +\end{classdesc*} + +\begin{classdesc*}{c_uint16} +Represents the C 16-bit unsigned int datatype. Usually an alias for +\class{c{\_}ushort}. +\end{classdesc*} + +\begin{classdesc*}{c_uint32} +Represents the C 32-bit unsigned int datatype. Usually an alias for +\class{c{\_}uint}. +\end{classdesc*} + +\begin{classdesc*}{c_uint64} +Represents the C 64-bit unsigned int datatype. Usually an alias for +\class{c{\_}ulonglong}. +\end{classdesc*} + +\begin{classdesc*}{c_ulong} +Represents the C \code{unsigned long} datatype. The constructor accepts an +optional integer initializer; no overflow checking is done. +\end{classdesc*} + +\begin{classdesc*}{c_ulonglong} +Represents the C \code{unsigned long long} datatype. The constructor +accepts an optional integer initializer; no overflow checking is +done. +\end{classdesc*} + +\begin{classdesc*}{c_ushort} +Represents the C \code{unsigned short} datatype. The constructor accepts an +optional integer initializer; no overflow checking is done. +\end{classdesc*} + +\begin{classdesc*}{c_void_p} +Represents the C \code{void *} type. The value is represented as +integer. The constructor accepts an optional integer initializer. +\end{classdesc*} + +\begin{classdesc*}{c_wchar} +Represents the C \code{wchar{\_}t} datatype, and interprets the value as a +single character unicode string. The constructor accepts an +optional string initializer, the length of the string must be +exactly one character. +\end{classdesc*} + +\begin{classdesc*}{c_wchar_p} +Represents the C \code{wchar{\_}t *} datatype, which must be a pointer to +a zero-terminated wide character string. The constructor accepts +an integer address, or a string. +\end{classdesc*} + +\begin{classdesc*}{HRESULT} +Windows only: Represents a \class{HRESULT} value, which contains success +or error information for a function or method call. +\end{classdesc*} + +\begin{classdesc*}{py_object} +Represents the C \code{PyObject *} datatype. Calling this without an +argument creates a \code{NULL} \code{PyObject *} pointer. +\end{classdesc*} + +The \code{ctypes.wintypes} module provides quite some other Windows +specific data types, for example \code{HWND}, \code{WPARAM}, or \code{DWORD}. +Some useful structures like \code{MSG} or \code{RECT} are also defined. + + +\subsubsection{Structured data types\label{ctypes-structured-data-types}} + +\begin{classdesc}{Union}{*args, **kw} +Abstract base class for unions in native byte order. +\end{classdesc} + +\begin{classdesc}{BigEndianStructure}{*args, **kw} +Abstract base class for structures in \emph{big endian} byte order. +\end{classdesc} + +\begin{classdesc}{LittleEndianStructure}{*args, **kw} +Abstract base class for structures in \emph{little endian} byte order. +\end{classdesc} + +Structures with non-native byte order cannot contain pointer type +fields, or any other data types containing pointer type fields. + +\begin{classdesc}{Structure}{*args, **kw} +Abstract base class for structures in \emph{native} byte order. +\end{classdesc} + +Concrete structure and union types must be created by subclassing one +of these types, and at least define a \member{{\_}fields{\_}} class variable. +\code{ctypes} will create descriptors which allow reading and writing the +fields by direct attribute accesses. These are the + +\begin{memberdesc}{_fields_} +A sequence defining the structure fields. The items must be +2-tuples or 3-tuples. The first item is the name of the field, +the second item specifies the type of the field; it can be any +ctypes data type. + +For integer type fields like \class{c{\_}int}, a third optional item can +be given. It must be a small positive integer defining the bit +width of the field. + +Field names must be unique within one structure or union. This is +not checked, only one field can be accessed when names are +repeated. + +It is possible to define the \member{{\_}fields{\_}} class variable \emph{after} +the class statement that defines the Structure subclass, this +allows to create data types that directly or indirectly reference +themselves: +\begin{verbatim} +class List(Structure): + pass +List._fields_ = [("pnext", POINTER(List)), + ... + ] +\end{verbatim} + +The \member{{\_}fields{\_}} class variable must, however, be defined before +the type is first used (an instance is created, \code{sizeof()} is +called on it, and so on). Later assignments to the \member{{\_}fields{\_}} +class variable will raise an AttributeError. + +Structure and union subclass constructors accept both positional +and named arguments. Positional arguments are used to initialize +the fields in the same order as they appear in the \member{{\_}fields{\_}} +definition, named arguments are used to initialize the fields with +the corresponding name. + +It is possible to defined sub-subclasses of structure types, they +inherit the fields of the base class plus the \member{{\_}fields{\_}} defined +in the sub-subclass, if any. +\end{memberdesc} + +\begin{memberdesc}{_pack_} +An optional small integer that allows to override the alignment of +structure fields in the instance. \member{{\_}pack{\_}} must already be +defined when \member{{\_}fields{\_}} is assigned, otherwise it will have no +effect. +\end{memberdesc} + +\begin{memberdesc}{_anonymous_} +An optional sequence that lists the names of unnamed (anonymous) +fields. \code{{\_}anonymous{\_}} must be already defined when \member{{\_}fields{\_}} +is assigned, otherwise it will have no effect. + +The fields listed in this variable must be structure or union type +fields. \code{ctypes} will create descriptors in the structure type +that allows to access the nested fields directly, without the need +to create the structure or union field. + +Here is an example type (Windows): +\begin{verbatim} +class _U(Union): + _fields_ = [("lptdesc", POINTER(TYPEDESC)), + ("lpadesc", POINTER(ARRAYDESC)), + ("hreftype", HREFTYPE)] + +class TYPEDESC(Structure): + _fields_ = [("u", _U), + ("vt", VARTYPE)] + + _anonymous_ = ("u",) +\end{verbatim} + +The \code{TYPEDESC} structure describes a COM data type, the \code{vt} +field specifies which one of the union fields is valid. Since the +\code{u} field is defined as anonymous field, it is now possible to +access the members directly off the TYPEDESC instance. +\code{td.lptdesc} and \code{td.u.lptdesc} are equivalent, but the former +is faster since it does not need to create a temporary union +instance: +\begin{verbatim} +td = TYPEDESC() +td.vt = VT_PTR +td.lptdesc = POINTER(some_type) +td.u.lptdesc = POINTER(some_type) +\end{verbatim} +\end{memberdesc} + +It is possible to defined sub-subclasses of structures, they inherit +the fields of the base class. If the subclass definition has a +separate \member{{\_}fields{\_}} variable, the fields specified in this are +appended to the fields of the base class. + +Structure and union constructors accept both positional and +keyword arguments. Positional arguments are used to initialize member +fields in the same order as they are appear in \member{{\_}fields{\_}}. Keyword +arguments in the constructor are interpreted as attribute assignments, +so they will initialize \member{{\_}fields{\_}} with the same name, or create new +attributes for names not present in \member{{\_}fields{\_}}. + + +\subsubsection{Arrays and pointers\label{ctypes-arrays-pointers}} + +Not yet written - please see section~\ref{ctypes-pointers}, pointers and +section~\ref{ctypes-arrays}, arrays in the tutorial. + diff --git a/sys/src/cmd/python/Doc/lib/libcurses.tex b/sys/src/cmd/python/Doc/lib/libcurses.tex new file mode 100644 index 000000000..3fe98760a --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcurses.tex @@ -0,0 +1,1395 @@ +\section{\module{curses} --- + Terminal handling for character-cell displays} + +\declaremodule{standard}{curses} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\sectionauthor{Eric Raymond}{esr@thyrsus.com} +\modulesynopsis{An interface to the curses library, providing portable + terminal handling.} + +\versionchanged[Added support for the \code{ncurses} library and + converted to a package]{1.6} + +The \module{curses} module provides an interface to the curses +library, the de-facto standard for portable advanced terminal +handling. + +While curses is most widely used in the \UNIX{} environment, versions +are available for DOS, OS/2, and possibly other systems as well. This +extension module is designed to match the API of ncurses, an +open-source curses library hosted on Linux and the BSD variants of +\UNIX. + +\begin{seealso} + \seemodule{curses.ascii}{Utilities for working with \ASCII{} + characters, regardless of your locale + settings.} + \seemodule{curses.panel}{A panel stack extension that adds depth to + curses windows.} + \seemodule{curses.textpad}{Editable text widget for curses supporting + \program{Emacs}-like bindings.} + \seemodule{curses.wrapper}{Convenience function to ensure proper + terminal setup and resetting on + application entry and exit.} + \seetitle[http://www.python.org/doc/howto/curses/curses.html]{Curses + Programming with Python}{Tutorial material on using curses + with Python, by Andrew Kuchling and Eric Raymond, is + available on the Python Web site.} + \seetext{The \file{Demo/curses/} directory in the Python source + distribution contains some example programs using the + curses bindings provided by this module.} +\end{seealso} + + +\subsection{Functions \label{curses-functions}} + +The module \module{curses} defines the following exception: + +\begin{excdesc}{error} +Exception raised when a curses library function returns an error. +\end{excdesc} + +\note{Whenever \var{x} or \var{y} arguments to a function +or a method are optional, they default to the current cursor location. +Whenever \var{attr} is optional, it defaults to \constant{A_NORMAL}.} + +The module \module{curses} defines the following functions: + +\begin{funcdesc}{baudrate}{} +Returns the output speed of the terminal in bits per second. On +software terminal emulators it will have a fixed high value. +Included for historical reasons; in former times, it was used to +write output loops for time delays and occasionally to change +interfaces depending on the line speed. +\end{funcdesc} + +\begin{funcdesc}{beep}{} +Emit a short attention sound. +\end{funcdesc} + +\begin{funcdesc}{can_change_color}{} +Returns true or false, depending on whether the programmer can change +the colors displayed by the terminal. +\end{funcdesc} + +\begin{funcdesc}{cbreak}{} +Enter cbreak mode. In cbreak mode (sometimes called ``rare'' mode) +normal tty line buffering is turned off and characters are available +to be read one by one. However, unlike raw mode, special characters +(interrupt, quit, suspend, and flow control) retain their effects on +the tty driver and calling program. Calling first \function{raw()} +then \function{cbreak()} leaves the terminal in cbreak mode. +\end{funcdesc} + +\begin{funcdesc}{color_content}{color_number} +Returns the intensity of the red, green, and blue (RGB) components in +the color \var{color_number}, which must be between \code{0} and +\constant{COLORS}. A 3-tuple is returned, containing the R,G,B values +for the given color, which will be between \code{0} (no component) and +\code{1000} (maximum amount of component). +\end{funcdesc} + +\begin{funcdesc}{color_pair}{color_number} +Returns the attribute value for displaying text in the specified +color. This attribute value can be combined with +\constant{A_STANDOUT}, \constant{A_REVERSE}, and the other +\constant{A_*} attributes. \function{pair_number()} is the +counterpart to this function. +\end{funcdesc} + +\begin{funcdesc}{curs_set}{visibility} +Sets the cursor state. \var{visibility} can be set to 0, 1, or 2, for +invisible, normal, or very visible. If the terminal supports the +visibility requested, the previous cursor state is returned; +otherwise, an exception is raised. On many terminals, the ``visible'' +mode is an underline cursor and the ``very visible'' mode is a block cursor. +\end{funcdesc} + +\begin{funcdesc}{def_prog_mode}{} +Saves the current terminal mode as the ``program'' mode, the mode when +the running program is using curses. (Its counterpart is the +``shell'' mode, for when the program is not in curses.) Subsequent calls +to \function{reset_prog_mode()} will restore this mode. +\end{funcdesc} + +\begin{funcdesc}{def_shell_mode}{} +Saves the current terminal mode as the ``shell'' mode, the mode when +the running program is not using curses. (Its counterpart is the +``program'' mode, when the program is using curses capabilities.) +Subsequent calls +to \function{reset_shell_mode()} will restore this mode. +\end{funcdesc} + +\begin{funcdesc}{delay_output}{ms} +Inserts an \var{ms} millisecond pause in output. +\end{funcdesc} + +\begin{funcdesc}{doupdate}{} +Update the physical screen. The curses library keeps two data +structures, one representing the current physical screen contents +and a virtual screen representing the desired next state. The +\function{doupdate()} ground updates the physical screen to match the +virtual screen. + +The virtual screen may be updated by a \method{noutrefresh()} call +after write operations such as \method{addstr()} have been performed +on a window. The normal \method{refresh()} call is simply +\method{noutrefresh()} followed by \function{doupdate()}; if you have +to update multiple windows, you can speed performance and perhaps +reduce screen flicker by issuing \method{noutrefresh()} calls on +all windows, followed by a single \function{doupdate()}. +\end{funcdesc} + +\begin{funcdesc}{echo}{} +Enter echo mode. In echo mode, each character input is echoed to the +screen as it is entered. +\end{funcdesc} + +\begin{funcdesc}{endwin}{} +De-initialize the library, and return terminal to normal status. +\end{funcdesc} + +\begin{funcdesc}{erasechar}{} +Returns the user's current erase character. Under \UNIX{} operating +systems this is a property of the controlling tty of the curses +program, and is not set by the curses library itself. +\end{funcdesc} + +\begin{funcdesc}{filter}{} +The \function{filter()} routine, if used, must be called before +\function{initscr()} is called. The effect is that, during those +calls, LINES is set to 1; the capabilities clear, cup, cud, cud1, +cuu1, cuu, vpa are disabled; and the home string is set to the value of cr. +The effect is that the cursor is confined to the current line, and so +are screen updates. This may be used for enabling character-at-a-time +line editing without touching the rest of the screen. +\end{funcdesc} + +\begin{funcdesc}{flash}{} +Flash the screen. That is, change it to reverse-video and then change +it back in a short interval. Some people prefer such as `visible bell' +to the audible attention signal produced by \function{beep()}. +\end{funcdesc} + +\begin{funcdesc}{flushinp}{} +Flush all input buffers. This throws away any typeahead that has +been typed by the user and has not yet been processed by the program. +\end{funcdesc} + +\begin{funcdesc}{getmouse}{} +After \method{getch()} returns \constant{KEY_MOUSE} to signal a mouse +event, this method should be call to retrieve the queued mouse event, +represented as a 5-tuple +\code{(\var{id}, \var{x}, \var{y}, \var{z}, \var{bstate})}. +\var{id} is an ID value used to distinguish multiple devices, +and \var{x}, \var{y}, \var{z} are the event's coordinates. (\var{z} +is currently unused.). \var{bstate} is an integer value whose bits +will be set to indicate the type of event, and will be the bitwise OR +of one or more of the following constants, where \var{n} is the button +number from 1 to 4: +\constant{BUTTON\var{n}_PRESSED}, +\constant{BUTTON\var{n}_RELEASED}, +\constant{BUTTON\var{n}_CLICKED}, +\constant{BUTTON\var{n}_DOUBLE_CLICKED}, +\constant{BUTTON\var{n}_TRIPLE_CLICKED}, +\constant{BUTTON_SHIFT}, +\constant{BUTTON_CTRL}, +\constant{BUTTON_ALT}. +\end{funcdesc} + +\begin{funcdesc}{getsyx}{} +Returns the current coordinates of the virtual screen cursor in y and +x. If leaveok is currently true, then -1,-1 is returned. +\end{funcdesc} + +\begin{funcdesc}{getwin}{file} +Reads window related data stored in the file by an earlier +\function{putwin()} call. The routine then creates and initializes a +new window using that data, returning the new window object. +\end{funcdesc} + +\begin{funcdesc}{has_colors}{} +Returns true if the terminal can display colors; otherwise, it +returns false. +\end{funcdesc} + +\begin{funcdesc}{has_ic}{} +Returns true if the terminal has insert- and delete- character +capabilities. This function is included for historical reasons only, +as all modern software terminal emulators have such capabilities. +\end{funcdesc} + +\begin{funcdesc}{has_il}{} +Returns true if the terminal has insert- and +delete-line capabilities, or can simulate them using +scrolling regions. This function is included for historical reasons only, +as all modern software terminal emulators have such capabilities. +\end{funcdesc} + +\begin{funcdesc}{has_key}{ch} +Takes a key value \var{ch}, and returns true if the current terminal +type recognizes a key with that value. +\end{funcdesc} + +\begin{funcdesc}{halfdelay}{tenths} +Used for half-delay mode, which is similar to cbreak mode in that +characters typed by the user are immediately available to the program. +However, after blocking for \var{tenths} tenths of seconds, an +exception is raised if nothing has been typed. The value of +\var{tenths} must be a number between 1 and 255. Use +\function{nocbreak()} to leave half-delay mode. +\end{funcdesc} + +\begin{funcdesc}{init_color}{color_number, r, g, b} +Changes the definition of a color, taking the number of the color to +be changed followed by three RGB values (for the amounts of red, +green, and blue components). The value of \var{color_number} must be +between \code{0} and \constant{COLORS}. Each of \var{r}, \var{g}, +\var{b}, must be a value between \code{0} and \code{1000}. When +\function{init_color()} is used, all occurrences of that color on the +screen immediately change to the new definition. This function is a +no-op on most terminals; it is active only if +\function{can_change_color()} returns \code{1}. +\end{funcdesc} + +\begin{funcdesc}{init_pair}{pair_number, fg, bg} +Changes the definition of a color-pair. It takes three arguments: the +number of the color-pair to be changed, the foreground color number, +and the background color number. The value of \var{pair_number} must +be between \code{1} and \code{COLOR_PAIRS - 1} (the \code{0} color +pair is wired to white on black and cannot be changed). The value of +\var{fg} and \var{bg} arguments must be between \code{0} and +\constant{COLORS}. If the color-pair was previously initialized, the +screen is refreshed and all occurrences of that color-pair are changed +to the new definition. +\end{funcdesc} + +\begin{funcdesc}{initscr}{} +Initialize the library. Returns a \class{WindowObject} which represents +the whole screen. \note{If there is an error opening the terminal, +the underlying curses library may cause the interpreter to exit.} +\end{funcdesc} + +\begin{funcdesc}{isendwin}{} +Returns true if \function{endwin()} has been called (that is, the +curses library has been deinitialized). +\end{funcdesc} + +\begin{funcdesc}{keyname}{k} +Return the name of the key numbered \var{k}. The name of a key +generating printable ASCII character is the key's character. The name +of a control-key combination is a two-character string consisting of a +caret followed by the corresponding printable ASCII character. The +name of an alt-key combination (128-255) is a string consisting of the +prefix `M-' followed by the name of the corresponding ASCII character. +\end{funcdesc} + +\begin{funcdesc}{killchar}{} +Returns the user's current line kill character. Under \UNIX{} operating +systems this is a property of the controlling tty of the curses +program, and is not set by the curses library itself. +\end{funcdesc} + +\begin{funcdesc}{longname}{} +Returns a string containing the terminfo long name field describing the current +terminal. The maximum length of a verbose description is 128 +characters. It is defined only after the call to +\function{initscr()}. +\end{funcdesc} + +\begin{funcdesc}{meta}{yes} +If \var{yes} is 1, allow 8-bit characters to be input. If \var{yes} is 0, +allow only 7-bit chars. +\end{funcdesc} + +\begin{funcdesc}{mouseinterval}{interval} +Sets the maximum time in milliseconds that can elapse between press and +release events in order for them to be recognized as a click, and +returns the previous interval value. The default value is 200 msec, +or one fifth of a second. +\end{funcdesc} + +\begin{funcdesc}{mousemask}{mousemask} +Sets the mouse events to be reported, and returns a tuple +\code{(\var{availmask}, \var{oldmask})}. +\var{availmask} indicates which of the +specified mouse events can be reported; on complete failure it returns +0. \var{oldmask} is the previous value of the given window's mouse +event mask. If this function is never called, no mouse events are +ever reported. +\end{funcdesc} + +\begin{funcdesc}{napms}{ms} +Sleep for \var{ms} milliseconds. +\end{funcdesc} + +\begin{funcdesc}{newpad}{nlines, ncols} +Creates and returns a pointer to a new pad data structure with the +given number of lines and columns. A pad is returned as a +window object. + +A pad is like a window, except that it is not restricted by the screen +size, and is not necessarily associated with a particular part of the +screen. Pads can be used when a large window is needed, and only a +part of the window will be on the screen at one time. Automatic +refreshes of pads (such as from scrolling or echoing of input) do not +occur. The \method{refresh()} and \method{noutrefresh()} methods of a +pad require 6 arguments to specify the part of the pad to be +displayed and the location on the screen to be used for the display. +The arguments are pminrow, pmincol, sminrow, smincol, smaxrow, +smaxcol; the p arguments refer to the upper left corner of the pad +region to be displayed and the s arguments define a clipping box on +the screen within which the pad region is to be displayed. +\end{funcdesc} + +\begin{funcdesc}{newwin}{\optional{nlines, ncols,} begin_y, begin_x} +Return a new window, whose left-upper corner is at +\code{(\var{begin_y}, \var{begin_x})}, and whose height/width is +\var{nlines}/\var{ncols}. + +By default, the window will extend from the +specified position to the lower right corner of the screen. +\end{funcdesc} + +\begin{funcdesc}{nl}{} +Enter newline mode. This mode translates the return key into newline +on input, and translates newline into return and line-feed on output. +Newline mode is initially on. +\end{funcdesc} + +\begin{funcdesc}{nocbreak}{} +Leave cbreak mode. Return to normal ``cooked'' mode with line buffering. +\end{funcdesc} + +\begin{funcdesc}{noecho}{} +Leave echo mode. Echoing of input characters is turned off. +\end{funcdesc} + +\begin{funcdesc}{nonl}{} +Leave newline mode. Disable translation of return into newline on +input, and disable low-level translation of newline into +newline/return on output (but this does not change the behavior of +\code{addch('\e n')}, which always does the equivalent of return and +line feed on the virtual screen). With translation off, curses can +sometimes speed up vertical motion a little; also, it will be able to +detect the return key on input. +\end{funcdesc} + +\begin{funcdesc}{noqiflush}{} +When the noqiflush routine is used, normal flush of input and +output queues associated with the INTR, QUIT and SUSP +characters will not be done. You may want to call +\function{noqiflush()} in a signal handler if you want output +to continue as though the interrupt had not occurred, after the +handler exits. +\end{funcdesc} + +\begin{funcdesc}{noraw}{} +Leave raw mode. Return to normal ``cooked'' mode with line buffering. +\end{funcdesc} + +\begin{funcdesc}{pair_content}{pair_number} +Returns a tuple \code{(\var{fg}, \var{bg})} containing the colors for +the requested color pair. The value of \var{pair_number} must be +between \code{1} and \code{\constant{COLOR_PAIRS} - 1}. +\end{funcdesc} + +\begin{funcdesc}{pair_number}{attr} +Returns the number of the color-pair set by the attribute value +\var{attr}. \function{color_pair()} is the counterpart to this +function. +\end{funcdesc} + +\begin{funcdesc}{putp}{string} +Equivalent to \code{tputs(str, 1, putchar)}; emits the value of a +specified terminfo capability for the current terminal. Note that the +output of putp always goes to standard output. +\end{funcdesc} + +\begin{funcdesc}{qiflush}{ \optional{flag} } +If \var{flag} is false, the effect is the same as calling +\function{noqiflush()}. If \var{flag} is true, or no argument is +provided, the queues will be flushed when these control characters are +read. +\end{funcdesc} + +\begin{funcdesc}{raw}{} +Enter raw mode. In raw mode, normal line buffering and +processing of interrupt, quit, suspend, and flow control keys are +turned off; characters are presented to curses input functions one +by one. +\end{funcdesc} + +\begin{funcdesc}{reset_prog_mode}{} +Restores the terminal to ``program'' mode, as previously saved +by \function{def_prog_mode()}. +\end{funcdesc} + +\begin{funcdesc}{reset_shell_mode}{} +Restores the terminal to ``shell'' mode, as previously saved +by \function{def_shell_mode()}. +\end{funcdesc} + +\begin{funcdesc}{setsyx}{y, x} +Sets the virtual screen cursor to \var{y}, \var{x}. +If \var{y} and \var{x} are both -1, then leaveok is set. +\end{funcdesc} + +\begin{funcdesc}{setupterm}{\optional{termstr, fd}} +Initializes the terminal. \var{termstr} is a string giving the +terminal name; if omitted, the value of the TERM environment variable +will be used. \var{fd} is the file descriptor to which any +initialization sequences will be sent; if not supplied, the file +descriptor for \code{sys.stdout} will be used. +\end{funcdesc} + +\begin{funcdesc}{start_color}{} +Must be called if the programmer wants to use colors, and before any +other color manipulation routine is called. It is good +practice to call this routine right after \function{initscr()}. + +\function{start_color()} initializes eight basic colors (black, red, +green, yellow, blue, magenta, cyan, and white), and two global +variables in the \module{curses} module, \constant{COLORS} and +\constant{COLOR_PAIRS}, containing the maximum number of colors and +color-pairs the terminal can support. It also restores the colors on +the terminal to the values they had when the terminal was just turned +on. +\end{funcdesc} + +\begin{funcdesc}{termattrs}{} +Returns a logical OR of all video attributes supported by the +terminal. This information is useful when a curses program needs +complete control over the appearance of the screen. +\end{funcdesc} + +\begin{funcdesc}{termname}{} +Returns the value of the environment variable TERM, truncated to 14 +characters. +\end{funcdesc} + +\begin{funcdesc}{tigetflag}{capname} +Returns the value of the Boolean capability corresponding to the +terminfo capability name \var{capname}. The value \code{-1} is +returned if \var{capname} is not a Boolean capability, or \code{0} if +it is canceled or absent from the terminal description. +\end{funcdesc} + +\begin{funcdesc}{tigetnum}{capname} +Returns the value of the numeric capability corresponding to the +terminfo capability name \var{capname}. The value \code{-2} is +returned if \var{capname} is not a numeric capability, or \code{-1} if +it is canceled or absent from the terminal description. +\end{funcdesc} + +\begin{funcdesc}{tigetstr}{capname} +Returns the value of the string capability corresponding to the +terminfo capability name \var{capname}. \code{None} is returned if +\var{capname} is not a string capability, or is canceled or absent +from the terminal description. +\end{funcdesc} + +\begin{funcdesc}{tparm}{str\optional{,...}} +Instantiates the string \var{str} with the supplied parameters, where +\var{str} should be a parameterized string obtained from the terminfo +database. E.g. \code{tparm(tigetstr("cup"), 5, 3)} could result in +\code{'\e{}033[6;4H'}, the exact result depending on terminal type. +\end{funcdesc} + +\begin{funcdesc}{typeahead}{fd} +Specifies that the file descriptor \var{fd} be used for typeahead +checking. If \var{fd} is \code{-1}, then no typeahead checking is +done. + +The curses library does ``line-breakout optimization'' by looking for +typeahead periodically while updating the screen. If input is found, +and it is coming from a tty, the current update is postponed until +refresh or doupdate is called again, allowing faster response to +commands typed in advance. This function allows specifying a different +file descriptor for typeahead checking. +\end{funcdesc} + +\begin{funcdesc}{unctrl}{ch} +Returns a string which is a printable representation of the character +\var{ch}. Control characters are displayed as a caret followed by the +character, for example as \code{\textasciicircum C}. Printing +characters are left as they are. +\end{funcdesc} + +\begin{funcdesc}{ungetch}{ch} +Push \var{ch} so the next \method{getch()} will return it. +\note{Only one \var{ch} can be pushed before \method{getch()} +is called.} +\end{funcdesc} + +\begin{funcdesc}{ungetmouse}{id, x, y, z, bstate} +Push a \constant{KEY_MOUSE} event onto the input queue, associating +the given state data with it. +\end{funcdesc} + +\begin{funcdesc}{use_env}{flag} +If used, this function should be called before \function{initscr()} or +newterm are called. When \var{flag} is false, the values of +lines and columns specified in the terminfo database will be +used, even if environment variables \envvar{LINES} and +\envvar{COLUMNS} (used by default) are set, or if curses is running in +a window (in which case default behavior would be to use the window +size if \envvar{LINES} and \envvar{COLUMNS} are not set). +\end{funcdesc} + +\begin{funcdesc}{use_default_colors}{} +Allow use of default values for colors on terminals supporting this +feature. Use this to support transparency in your +application. The default color is assigned to the color number -1. +After calling this function, +\code{init_pair(x, curses.COLOR_RED, -1)} initializes, for instance, +color pair \var{x} to a red foreground color on the default background. +\end{funcdesc} + +\subsection{Window Objects \label{curses-window-objects}} + +Window objects, as returned by \function{initscr()} and +\function{newwin()} above, have the +following methods: + +\begin{methoddesc}[window]{addch}{\optional{y, x,} ch\optional{, attr}} +\note{A \emph{character} means a C character (an +\ASCII{} code), rather then a Python character (a string of length 1). +(This note is true whenever the documentation mentions a character.) +The builtin \function{ord()} is handy for conveying strings to codes.} + +Paint character \var{ch} at \code{(\var{y}, \var{x})} with attributes +\var{attr}, overwriting any character previously painter at that +location. By default, the character position and attributes are the +current settings for the window object. +\end{methoddesc} + +\begin{methoddesc}[window]{addnstr}{\optional{y, x,} str, n\optional{, attr}} +Paint at most \var{n} characters of the +string \var{str} at \code{(\var{y}, \var{x})} with attributes +\var{attr}, overwriting anything previously on the display. +\end{methoddesc} + +\begin{methoddesc}[window]{addstr}{\optional{y, x,} str\optional{, attr}} +Paint the string \var{str} at \code{(\var{y}, \var{x})} with attributes +\var{attr}, overwriting anything previously on the display. +\end{methoddesc} + +\begin{methoddesc}[window]{attroff}{attr} +Remove attribute \var{attr} from the ``background'' set applied to all +writes to the current window. +\end{methoddesc} + +\begin{methoddesc}[window]{attron}{attr} +Add attribute \var{attr} from the ``background'' set applied to all +writes to the current window. +\end{methoddesc} + +\begin{methoddesc}[window]{attrset}{attr} +Set the ``background'' set of attributes to \var{attr}. This set is +initially 0 (no attributes). +\end{methoddesc} + +\begin{methoddesc}[window]{bkgd}{ch\optional{, attr}} +Sets the background property of the window to the character \var{ch}, +with attributes \var{attr}. The change is then applied to every +character position in that window: +\begin{itemize} +\item +The attribute of every character in the window is +changed to the new background attribute. +\item +Wherever the former background character appears, +it is changed to the new background character. +\end{itemize} + +\end{methoddesc} + +\begin{methoddesc}[window]{bkgdset}{ch\optional{, attr}} +Sets the window's background. A window's background consists of a +character and any combination of attributes. The attribute part of +the background is combined (OR'ed) with all non-blank characters that +are written into the window. Both the character and attribute parts +of the background are combined with the blank characters. The +background becomes a property of the character and moves with the +character through any scrolling and insert/delete line/character +operations. +\end{methoddesc} + +\begin{methoddesc}[window]{border}{\optional{ls\optional{, rs\optional{, + ts\optional{, bs\optional{, tl\optional{, + tr\optional{, bl\optional{, br}}}}}}}}} +Draw a border around the edges of the window. Each parameter specifies +the character to use for a specific part of the border; see the table +below for more details. The characters can be specified as integers +or as one-character strings. + +\note{A \code{0} value for any parameter will cause the +default character to be used for that parameter. Keyword parameters +can \emph{not} be used. The defaults are listed in this table:} + +\begin{tableiii}{l|l|l}{var}{Parameter}{Description}{Default value} + \lineiii{ls}{Left side}{\constant{ACS_VLINE}} + \lineiii{rs}{Right side}{\constant{ACS_VLINE}} + \lineiii{ts}{Top}{\constant{ACS_HLINE}} + \lineiii{bs}{Bottom}{\constant{ACS_HLINE}} + \lineiii{tl}{Upper-left corner}{\constant{ACS_ULCORNER}} + \lineiii{tr}{Upper-right corner}{\constant{ACS_URCORNER}} + \lineiii{bl}{Bottom-left corner}{\constant{ACS_LLCORNER}} + \lineiii{br}{Bottom-right corner}{\constant{ACS_LRCORNER}} +\end{tableiii} +\end{methoddesc} + +\begin{methoddesc}[window]{box}{\optional{vertch, horch}} +Similar to \method{border()}, but both \var{ls} and \var{rs} are +\var{vertch} and both \var{ts} and {bs} are \var{horch}. The default +corner characters are always used by this function. +\end{methoddesc} + +\begin{methoddesc}[window]{clear}{} +Like \method{erase()}, but also causes the whole window to be repainted +upon next call to \method{refresh()}. +\end{methoddesc} + +\begin{methoddesc}[window]{clearok}{yes} +If \var{yes} is 1, the next call to \method{refresh()} +will clear the window completely. +\end{methoddesc} + +\begin{methoddesc}[window]{clrtobot}{} +Erase from cursor to the end of the window: all lines below the cursor +are deleted, and then the equivalent of \method{clrtoeol()} is performed. +\end{methoddesc} + +\begin{methoddesc}[window]{clrtoeol}{} +Erase from cursor to the end of the line. +\end{methoddesc} + +\begin{methoddesc}[window]{cursyncup}{} +Updates the current cursor position of all the ancestors of the window +to reflect the current cursor position of the window. +\end{methoddesc} + +\begin{methoddesc}[window]{delch}{\optional{y, x}} +Delete any character at \code{(\var{y}, \var{x})}. +\end{methoddesc} + +\begin{methoddesc}[window]{deleteln}{} +Delete the line under the cursor. All following lines are moved up +by 1 line. +\end{methoddesc} + +\begin{methoddesc}[window]{derwin}{\optional{nlines, ncols,} begin_y, begin_x} +An abbreviation for ``derive window'', \method{derwin()} is the same +as calling \method{subwin()}, except that \var{begin_y} and +\var{begin_x} are relative to the origin of the window, rather than +relative to the entire screen. Returns a window object for the +derived window. +\end{methoddesc} + +\begin{methoddesc}[window]{echochar}{ch\optional{, attr}} +Add character \var{ch} with attribute \var{attr}, and immediately +call \method{refresh()} on the window. +\end{methoddesc} + +\begin{methoddesc}[window]{enclose}{y, x} +Tests whether the given pair of screen-relative character-cell +coordinates are enclosed by the given window, returning true or +false. It is useful for determining what subset of the screen +windows enclose the location of a mouse event. +\end{methoddesc} + +\begin{methoddesc}[window]{erase}{} +Clear the window. +\end{methoddesc} + +\begin{methoddesc}[window]{getbegyx}{} +Return a tuple \code{(\var{y}, \var{x})} of co-ordinates of upper-left +corner. +\end{methoddesc} + +\begin{methoddesc}[window]{getch}{\optional{y, x}} +Get a character. Note that the integer returned does \emph{not} have to +be in \ASCII{} range: function keys, keypad keys and so on return numbers +higher than 256. In no-delay mode, -1 is returned if there is +no input. +\end{methoddesc} + +\begin{methoddesc}[window]{getkey}{\optional{y, x}} +Get a character, returning a string instead of an integer, as +\method{getch()} does. Function keys, keypad keys and so on return a +multibyte string containing the key name. In no-delay mode, an +exception is raised if there is no input. +\end{methoddesc} + +\begin{methoddesc}[window]{getmaxyx}{} +Return a tuple \code{(\var{y}, \var{x})} of the height and width of +the window. +\end{methoddesc} + +\begin{methoddesc}[window]{getparyx}{} +Returns the beginning coordinates of this window relative to its +parent window into two integer variables y and x. Returns +\code{-1,-1} if this window has no parent. +\end{methoddesc} + +\begin{methoddesc}[window]{getstr}{\optional{y, x}} +Read a string from the user, with primitive line editing capacity. +\end{methoddesc} + +\begin{methoddesc}[window]{getyx}{} +Return a tuple \code{(\var{y}, \var{x})} of current cursor position +relative to the window's upper-left corner. +\end{methoddesc} + +\begin{methoddesc}[window]{hline}{\optional{y, x,} ch, n} +Display a horizontal line starting at \code{(\var{y}, \var{x})} with +length \var{n} consisting of the character \var{ch}. +\end{methoddesc} + +\begin{methoddesc}[window]{idcok}{flag} +If \var{flag} is false, curses no longer considers using the hardware +insert/delete character feature of the terminal; if \var{flag} is +true, use of character insertion and deletion is enabled. When curses +is first initialized, use of character insert/delete is enabled by +default. +\end{methoddesc} + +\begin{methoddesc}[window]{idlok}{yes} +If called with \var{yes} equal to 1, \module{curses} will try and use +hardware line editing facilities. Otherwise, line insertion/deletion +are disabled. +\end{methoddesc} + +\begin{methoddesc}[window]{immedok}{flag} +If \var{flag} is true, any change in the window image +automatically causes the window to be refreshed; you no longer +have to call \method{refresh()} yourself. However, it may +degrade performance considerably, due to repeated calls to +wrefresh. This option is disabled by default. +\end{methoddesc} + +\begin{methoddesc}[window]{inch}{\optional{y, x}} +Return the character at the given position in the window. The bottom +8 bits are the character proper, and upper bits are the attributes. +\end{methoddesc} + +\begin{methoddesc}[window]{insch}{\optional{y, x,} ch\optional{, attr}} +Paint character \var{ch} at \code{(\var{y}, \var{x})} with attributes +\var{attr}, moving the line from position \var{x} right by one +character. +\end{methoddesc} + +\begin{methoddesc}[window]{insdelln}{nlines} +Inserts \var{nlines} lines into the specified window above the current +line. The \var{nlines} bottom lines are lost. For negative +\var{nlines}, delete \var{nlines} lines starting with the one under +the cursor, and move the remaining lines up. The bottom \var{nlines} +lines are cleared. The current cursor position remains the same. +\end{methoddesc} + +\begin{methoddesc}[window]{insertln}{} +Insert a blank line under the cursor. All following lines are moved +down by 1 line. +\end{methoddesc} + +\begin{methoddesc}[window]{insnstr}{\optional{y, x,} str, n \optional{, attr}} +Insert a character string (as many characters as will fit on the line) +before the character under the cursor, up to \var{n} characters. +If \var{n} is zero or negative, +the entire string is inserted. +All characters to the right of +the cursor are shifted right, with the rightmost characters on the +line being lost. The cursor position does not change (after moving to +\var{y}, \var{x}, if specified). +\end{methoddesc} + +\begin{methoddesc}[window]{insstr}{\optional{y, x, } str \optional{, attr}} +Insert a character string (as many characters as will fit on the line) +before the character under the cursor. All characters to the right of +the cursor are shifted right, with the rightmost characters on the +line being lost. The cursor position does not change (after moving to +\var{y}, \var{x}, if specified). +\end{methoddesc} + +\begin{methoddesc}[window]{instr}{\optional{y, x} \optional{, n}} +Returns a string of characters, extracted from the window starting at +the current cursor position, or at \var{y}, \var{x} if specified. +Attributes are stripped from the characters. If \var{n} is specified, +\method{instr()} returns return a string at most \var{n} characters +long (exclusive of the trailing NUL). +\end{methoddesc} + +\begin{methoddesc}[window]{is_linetouched}{\var{line}} +Returns true if the specified line was modified since the last call to +\method{refresh()}; otherwise returns false. Raises a +\exception{curses.error} exception if \var{line} is not valid +for the given window. +\end{methoddesc} + +\begin{methoddesc}[window]{is_wintouched}{} +Returns true if the specified window was modified since the last call to +\method{refresh()}; otherwise returns false. +\end{methoddesc} + +\begin{methoddesc}[window]{keypad}{yes} +If \var{yes} is 1, escape sequences generated by some keys (keypad, +function keys) will be interpreted by \module{curses}. +If \var{yes} is 0, escape sequences will be left as is in the input +stream. +\end{methoddesc} + +\begin{methoddesc}[window]{leaveok}{yes} +If \var{yes} is 1, cursor is left where it is on update, instead of +being at ``cursor position.'' This reduces cursor movement where +possible. If possible the cursor will be made invisible. + +If \var{yes} is 0, cursor will always be at ``cursor position'' after +an update. +\end{methoddesc} + +\begin{methoddesc}[window]{move}{new_y, new_x} +Move cursor to \code{(\var{new_y}, \var{new_x})}. +\end{methoddesc} + +\begin{methoddesc}[window]{mvderwin}{y, x} +Moves the window inside its parent window. The screen-relative +parameters of the window are not changed. This routine is used to +display different parts of the parent window at the same physical +position on the screen. +\end{methoddesc} + +\begin{methoddesc}[window]{mvwin}{new_y, new_x} +Move the window so its upper-left corner is at +\code{(\var{new_y}, \var{new_x})}. +\end{methoddesc} + +\begin{methoddesc}[window]{nodelay}{yes} +If \var{yes} is \code{1}, \method{getch()} will be non-blocking. +\end{methoddesc} + +\begin{methoddesc}[window]{notimeout}{yes} +If \var{yes} is \code{1}, escape sequences will not be timed out. + +If \var{yes} is \code{0}, after a few milliseconds, an escape sequence +will not be interpreted, and will be left in the input stream as is. +\end{methoddesc} + +\begin{methoddesc}[window]{noutrefresh}{} +Mark for refresh but wait. This function updates the data structure +representing the desired state of the window, but does not force +an update of the physical screen. To accomplish that, call +\function{doupdate()}. +\end{methoddesc} + +\begin{methoddesc}[window]{overlay}{destwin\optional{, sminrow, smincol, + dminrow, dmincol, dmaxrow, dmaxcol}} +Overlay the window on top of \var{destwin}. The windows need not be +the same size, only the overlapping region is copied. This copy is +non-destructive, which means that the current background character +does not overwrite the old contents of \var{destwin}. + +To get fine-grained control over the copied region, the second form +of \method{overlay()} can be used. \var{sminrow} and \var{smincol} are +the upper-left coordinates of the source window, and the other variables +mark a rectangle in the destination window. +\end{methoddesc} + +\begin{methoddesc}[window]{overwrite}{destwin\optional{, sminrow, smincol, + dminrow, dmincol, dmaxrow, dmaxcol}} +Overwrite the window on top of \var{destwin}. The windows need not be +the same size, in which case only the overlapping region is +copied. This copy is destructive, which means that the current +background character overwrites the old contents of \var{destwin}. + +To get fine-grained control over the copied region, the second form +of \method{overwrite()} can be used. \var{sminrow} and \var{smincol} are +the upper-left coordinates of the source window, the other variables +mark a rectangle in the destination window. +\end{methoddesc} + +\begin{methoddesc}[window]{putwin}{file} +Writes all data associated with the window into the provided file +object. This information can be later retrieved using the +\function{getwin()} function. +\end{methoddesc} + +\begin{methoddesc}[window]{redrawln}{beg, num} +Indicates that the \var{num} screen lines, starting at line \var{beg}, +are corrupted and should be completely redrawn on the next +\method{refresh()} call. +\end{methoddesc} + +\begin{methoddesc}[window]{redrawwin}{} +Touches the entire window, causing it to be completely redrawn on the +next \method{refresh()} call. +\end{methoddesc} + +\begin{methoddesc}[window]{refresh}{\optional{pminrow, pmincol, sminrow, + smincol, smaxrow, smaxcol}} +Update the display immediately (sync actual screen with previous +drawing/deleting methods). + +The 6 optional arguments can only be specified when the window is a +pad created with \function{newpad()}. The additional parameters are +needed to indicate what part of the pad and screen are involved. +\var{pminrow} and \var{pmincol} specify the upper left-hand corner of the +rectangle to be displayed in the pad. \var{sminrow}, \var{smincol}, +\var{smaxrow}, and \var{smaxcol} specify the edges of the rectangle to +be displayed on the screen. The lower right-hand corner of the +rectangle to be displayed in the pad is calculated from the screen +coordinates, since the rectangles must be the same size. Both +rectangles must be entirely contained within their respective +structures. Negative values of \var{pminrow}, \var{pmincol}, +\var{sminrow}, or \var{smincol} are treated as if they were zero. +\end{methoddesc} + +\begin{methoddesc}[window]{scroll}{\optional{lines\code{ = 1}}} +Scroll the screen or scrolling region upward by \var{lines} lines. +\end{methoddesc} + +\begin{methoddesc}[window]{scrollok}{flag} +Controls what happens when the cursor of a window is moved off the +edge of the window or scrolling region, either as a result of a +newline action on the bottom line, or typing the last character +of the last line. If \var{flag} is false, the cursor is left +on the bottom line. If \var{flag} is true, the window is +scrolled up one line. Note that in order to get the physical +scrolling effect on the terminal, it is also necessary to call +\method{idlok()}. +\end{methoddesc} + +\begin{methoddesc}[window]{setscrreg}{top, bottom} +Set the scrolling region from line \var{top} to line \var{bottom}. All +scrolling actions will take place in this region. +\end{methoddesc} + +\begin{methoddesc}[window]{standend}{} +Turn off the standout attribute. On some terminals this has the +side effect of turning off all attributes. +\end{methoddesc} + +\begin{methoddesc}[window]{standout}{} +Turn on attribute \var{A_STANDOUT}. +\end{methoddesc} + +\begin{methoddesc}[window]{subpad}{\optional{nlines, ncols,} begin_y, begin_x} +Return a sub-window, whose upper-left corner is at +\code{(\var{begin_y}, \var{begin_x})}, and whose width/height is +\var{ncols}/\var{nlines}. +\end{methoddesc} + +\begin{methoddesc}[window]{subwin}{\optional{nlines, ncols,} begin_y, begin_x} +Return a sub-window, whose upper-left corner is at +\code{(\var{begin_y}, \var{begin_x})}, and whose width/height is +\var{ncols}/\var{nlines}. + +By default, the sub-window will extend from the +specified position to the lower right corner of the window. +\end{methoddesc} + +\begin{methoddesc}[window]{syncdown}{} +Touches each location in the window that has been touched in any of +its ancestor windows. This routine is called by \method{refresh()}, +so it should almost never be necessary to call it manually. +\end{methoddesc} + +\begin{methoddesc}[window]{syncok}{flag} +If called with \var{flag} set to true, then \method{syncup()} is +called automatically whenever there is a change in the window. +\end{methoddesc} + +\begin{methoddesc}[window]{syncup}{} +Touches all locations in ancestors of the window that have been changed in +the window. +\end{methoddesc} + +\begin{methoddesc}[window]{timeout}{delay} +Sets blocking or non-blocking read behavior for the window. If +\var{delay} is negative, blocking read is used (which will wait +indefinitely for input). If \var{delay} is zero, then non-blocking +read is used, and -1 will be returned by \method{getch()} if no input +is waiting. If \var{delay} is positive, then \method{getch()} will +block for \var{delay} milliseconds, and return -1 if there is still no +input at the end of that time. +\end{methoddesc} + +\begin{methoddesc}[window]{touchline}{start, count\optional{, changed}} +Pretend \var{count} lines have been changed, starting with line +\var{start}. If \var{changed} is supplied, it specifies +whether the affected lines are marked as +having been changed (\var{changed}=1) or unchanged (\var{changed}=0). +\end{methoddesc} + +\begin{methoddesc}[window]{touchwin}{} +Pretend the whole window has been changed, for purposes of drawing +optimizations. +\end{methoddesc} + +\begin{methoddesc}[window]{untouchwin}{} +Marks all lines in the window as unchanged since the last call to +\method{refresh()}. +\end{methoddesc} + +\begin{methoddesc}[window]{vline}{\optional{y, x,} ch, n} +Display a vertical line starting at \code{(\var{y}, \var{x})} with +length \var{n} consisting of the character \var{ch}. +\end{methoddesc} + +\subsection{Constants} + +The \module{curses} module defines the following data members: + +\begin{datadesc}{ERR} +Some curses routines that return an integer, such as +\function{getch()}, return \constant{ERR} upon failure. +\end{datadesc} + +\begin{datadesc}{OK} +Some curses routines that return an integer, such as +\function{napms()}, return \constant{OK} upon success. +\end{datadesc} + +\begin{datadesc}{version} +A string representing the current version of the module. +Also available as \constant{__version__}. +\end{datadesc} + +Several constants are available to specify character cell attributes: + +\begin{tableii}{l|l}{code}{Attribute}{Meaning} + \lineii{A_ALTCHARSET}{Alternate character set mode.} + \lineii{A_BLINK}{Blink mode.} + \lineii{A_BOLD}{Bold mode.} + \lineii{A_DIM}{Dim mode.} + \lineii{A_NORMAL}{Normal attribute.} + \lineii{A_STANDOUT}{Standout mode.} + \lineii{A_UNDERLINE}{Underline mode.} +\end{tableii} + +Keys are referred to by integer constants with names starting with +\samp{KEY_}. The exact keycaps available are system dependent. + +% XXX this table is far too large! +% XXX should this table be alphabetized? + +\begin{longtableii}{l|l}{code}{Key constant}{Key} + \lineii{KEY_MIN}{Minimum key value} + \lineii{KEY_BREAK}{ Break key (unreliable) } + \lineii{KEY_DOWN}{ Down-arrow } + \lineii{KEY_UP}{ Up-arrow } + \lineii{KEY_LEFT}{ Left-arrow } + \lineii{KEY_RIGHT}{ Right-arrow } + \lineii{KEY_HOME}{ Home key (upward+left arrow) } + \lineii{KEY_BACKSPACE}{ Backspace (unreliable) } + \lineii{KEY_F0}{ Function keys. Up to 64 function keys are supported. } + \lineii{KEY_F\var{n}}{ Value of function key \var{n} } + \lineii{KEY_DL}{ Delete line } + \lineii{KEY_IL}{ Insert line } + \lineii{KEY_DC}{ Delete character } + \lineii{KEY_IC}{ Insert char or enter insert mode } + \lineii{KEY_EIC}{ Exit insert char mode } + \lineii{KEY_CLEAR}{ Clear screen } + \lineii{KEY_EOS}{ Clear to end of screen } + \lineii{KEY_EOL}{ Clear to end of line } + \lineii{KEY_SF}{ Scroll 1 line forward } + \lineii{KEY_SR}{ Scroll 1 line backward (reverse) } + \lineii{KEY_NPAGE}{ Next page } + \lineii{KEY_PPAGE}{ Previous page } + \lineii{KEY_STAB}{ Set tab } + \lineii{KEY_CTAB}{ Clear tab } + \lineii{KEY_CATAB}{ Clear all tabs } + \lineii{KEY_ENTER}{ Enter or send (unreliable) } + \lineii{KEY_SRESET}{ Soft (partial) reset (unreliable) } + \lineii{KEY_RESET}{ Reset or hard reset (unreliable) } + \lineii{KEY_PRINT}{ Print } + \lineii{KEY_LL}{ Home down or bottom (lower left) } + \lineii{KEY_A1}{ Upper left of keypad } + \lineii{KEY_A3}{ Upper right of keypad } + \lineii{KEY_B2}{ Center of keypad } + \lineii{KEY_C1}{ Lower left of keypad } + \lineii{KEY_C3}{ Lower right of keypad } + \lineii{KEY_BTAB}{ Back tab } + \lineii{KEY_BEG}{ Beg (beginning) } + \lineii{KEY_CANCEL}{ Cancel } + \lineii{KEY_CLOSE}{ Close } + \lineii{KEY_COMMAND}{ Cmd (command) } + \lineii{KEY_COPY}{ Copy } + \lineii{KEY_CREATE}{ Create } + \lineii{KEY_END}{ End } + \lineii{KEY_EXIT}{ Exit } + \lineii{KEY_FIND}{ Find } + \lineii{KEY_HELP}{ Help } + \lineii{KEY_MARK}{ Mark } + \lineii{KEY_MESSAGE}{ Message } + \lineii{KEY_MOVE}{ Move } + \lineii{KEY_NEXT}{ Next } + \lineii{KEY_OPEN}{ Open } + \lineii{KEY_OPTIONS}{ Options } + \lineii{KEY_PREVIOUS}{ Prev (previous) } + \lineii{KEY_REDO}{ Redo } + \lineii{KEY_REFERENCE}{ Ref (reference) } + \lineii{KEY_REFRESH}{ Refresh } + \lineii{KEY_REPLACE}{ Replace } + \lineii{KEY_RESTART}{ Restart } + \lineii{KEY_RESUME}{ Resume } + \lineii{KEY_SAVE}{ Save } + \lineii{KEY_SBEG}{ Shifted Beg (beginning) } + \lineii{KEY_SCANCEL}{ Shifted Cancel } + \lineii{KEY_SCOMMAND}{ Shifted Command } + \lineii{KEY_SCOPY}{ Shifted Copy } + \lineii{KEY_SCREATE}{ Shifted Create } + \lineii{KEY_SDC}{ Shifted Delete char } + \lineii{KEY_SDL}{ Shifted Delete line } + \lineii{KEY_SELECT}{ Select } + \lineii{KEY_SEND}{ Shifted End } + \lineii{KEY_SEOL}{ Shifted Clear line } + \lineii{KEY_SEXIT}{ Shifted Dxit } + \lineii{KEY_SFIND}{ Shifted Find } + \lineii{KEY_SHELP}{ Shifted Help } + \lineii{KEY_SHOME}{ Shifted Home } + \lineii{KEY_SIC}{ Shifted Input } + \lineii{KEY_SLEFT}{ Shifted Left arrow } + \lineii{KEY_SMESSAGE}{ Shifted Message } + \lineii{KEY_SMOVE}{ Shifted Move } + \lineii{KEY_SNEXT}{ Shifted Next } + \lineii{KEY_SOPTIONS}{ Shifted Options } + \lineii{KEY_SPREVIOUS}{ Shifted Prev } + \lineii{KEY_SPRINT}{ Shifted Print } + \lineii{KEY_SREDO}{ Shifted Redo } + \lineii{KEY_SREPLACE}{ Shifted Replace } + \lineii{KEY_SRIGHT}{ Shifted Right arrow } + \lineii{KEY_SRSUME}{ Shifted Resume } + \lineii{KEY_SSAVE}{ Shifted Save } + \lineii{KEY_SSUSPEND}{ Shifted Suspend } + \lineii{KEY_SUNDO}{ Shifted Undo } + \lineii{KEY_SUSPEND}{ Suspend } + \lineii{KEY_UNDO}{ Undo } + \lineii{KEY_MOUSE}{ Mouse event has occurred } + \lineii{KEY_RESIZE}{ Terminal resize event } + \lineii{KEY_MAX}{Maximum key value} +\end{longtableii} + +On VT100s and their software emulations, such as X terminal emulators, +there are normally at least four function keys (\constant{KEY_F1}, +\constant{KEY_F2}, \constant{KEY_F3}, \constant{KEY_F4}) available, +and the arrow keys mapped to \constant{KEY_UP}, \constant{KEY_DOWN}, +\constant{KEY_LEFT} and \constant{KEY_RIGHT} in the obvious way. If +your machine has a PC keyboard, it is safe to expect arrow keys and +twelve function keys (older PC keyboards may have only ten function +keys); also, the following keypad mappings are standard: + +\begin{tableii}{l|l}{kbd}{Keycap}{Constant} + \lineii{Insert}{KEY_IC} + \lineii{Delete}{KEY_DC} + \lineii{Home}{KEY_HOME} + \lineii{End}{KEY_END} + \lineii{Page Up}{KEY_NPAGE} + \lineii{Page Down}{KEY_PPAGE} +\end{tableii} + +The following table lists characters from the alternate character set. +These are inherited from the VT100 terminal, and will generally be +available on software emulations such as X terminals. When there +is no graphic available, curses falls back on a crude printable ASCII +approximation. +\note{These are available only after \function{initscr()} has +been called.} + +\begin{longtableii}{l|l}{code}{ACS code}{Meaning} + \lineii{ACS_BBSS}{alternate name for upper right corner} + \lineii{ACS_BLOCK}{solid square block} + \lineii{ACS_BOARD}{board of squares} + \lineii{ACS_BSBS}{alternate name for horizontal line} + \lineii{ACS_BSSB}{alternate name for upper left corner} + \lineii{ACS_BSSS}{alternate name for top tee} + \lineii{ACS_BTEE}{bottom tee} + \lineii{ACS_BULLET}{bullet} + \lineii{ACS_CKBOARD}{checker board (stipple)} + \lineii{ACS_DARROW}{arrow pointing down} + \lineii{ACS_DEGREE}{degree symbol} + \lineii{ACS_DIAMOND}{diamond} + \lineii{ACS_GEQUAL}{greater-than-or-equal-to} + \lineii{ACS_HLINE}{horizontal line} + \lineii{ACS_LANTERN}{lantern symbol} + \lineii{ACS_LARROW}{left arrow} + \lineii{ACS_LEQUAL}{less-than-or-equal-to} + \lineii{ACS_LLCORNER}{lower left-hand corner} + \lineii{ACS_LRCORNER}{lower right-hand corner} + \lineii{ACS_LTEE}{left tee} + \lineii{ACS_NEQUAL}{not-equal sign} + \lineii{ACS_PI}{letter pi} + \lineii{ACS_PLMINUS}{plus-or-minus sign} + \lineii{ACS_PLUS}{big plus sign} + \lineii{ACS_RARROW}{right arrow} + \lineii{ACS_RTEE}{right tee} + \lineii{ACS_S1}{scan line 1} + \lineii{ACS_S3}{scan line 3} + \lineii{ACS_S7}{scan line 7} + \lineii{ACS_S9}{scan line 9} + \lineii{ACS_SBBS}{alternate name for lower right corner} + \lineii{ACS_SBSB}{alternate name for vertical line} + \lineii{ACS_SBSS}{alternate name for right tee} + \lineii{ACS_SSBB}{alternate name for lower left corner} + \lineii{ACS_SSBS}{alternate name for bottom tee} + \lineii{ACS_SSSB}{alternate name for left tee} + \lineii{ACS_SSSS}{alternate name for crossover or big plus} + \lineii{ACS_STERLING}{pound sterling} + \lineii{ACS_TTEE}{top tee} + \lineii{ACS_UARROW}{up arrow} + \lineii{ACS_ULCORNER}{upper left corner} + \lineii{ACS_URCORNER}{upper right corner} + \lineii{ACS_VLINE}{vertical line} +\end{longtableii} + +The following table lists the predefined colors: + +\begin{tableii}{l|l}{code}{Constant}{Color} + \lineii{COLOR_BLACK}{Black} + \lineii{COLOR_BLUE}{Blue} + \lineii{COLOR_CYAN}{Cyan (light greenish blue)} + \lineii{COLOR_GREEN}{Green} + \lineii{COLOR_MAGENTA}{Magenta (purplish red)} + \lineii{COLOR_RED}{Red} + \lineii{COLOR_WHITE}{White} + \lineii{COLOR_YELLOW}{Yellow} +\end{tableii} + +\section{\module{curses.textpad} --- + Text input widget for curses programs} + +\declaremodule{standard}{curses.textpad} +\sectionauthor{Eric Raymond}{esr@thyrsus.com} +\moduleauthor{Eric Raymond}{esr@thyrsus.com} +\modulesynopsis{Emacs-like input editing in a curses window.} +\versionadded{1.6} + +The \module{curses.textpad} module provides a \class{Textbox} class +that handles elementary text editing in a curses window, supporting a +set of keybindings resembling those of Emacs (thus, also of Netscape +Navigator, BBedit 6.x, FrameMaker, and many other programs). The +module also provides a rectangle-drawing function useful for framing +text boxes or for other purposes. + +The module \module{curses.textpad} defines the following function: + +\begin{funcdesc}{rectangle}{win, uly, ulx, lry, lrx} +Draw a rectangle. The first argument must be a window object; the +remaining arguments are coordinates relative to that window. The +second and third arguments are the y and x coordinates of the upper +left hand corner of the rectangle to be drawn; the fourth and fifth +arguments are the y and x coordinates of the lower right hand corner. +The rectangle will be drawn using VT100/IBM PC forms characters on +terminals that make this possible (including xterm and most other +software terminal emulators). Otherwise it will be drawn with ASCII +dashes, vertical bars, and plus signs. +\end{funcdesc} + + +\subsection{Textbox objects \label{curses-textpad-objects}} + +You can instantiate a \class{Textbox} object as follows: + +\begin{classdesc}{Textbox}{win} +Return a textbox widget object. The \var{win} argument should be a +curses \class{WindowObject} in which the textbox is to be contained. +The edit cursor of the textbox is initially located at the upper left +hand corner of the containing window, with coordinates \code{(0, 0)}. +The instance's \member{stripspaces} flag is initially on. +\end{classdesc} + +\class{Textbox} objects have the following methods: + +\begin{methoddesc}{edit}{\optional{validator}} +This is the entry point you will normally use. It accepts editing +keystrokes until one of the termination keystrokes is entered. If +\var{validator} is supplied, it must be a function. It will be called +for each keystroke entered with the keystroke as a parameter; command +dispatch is done on the result. This method returns the window +contents as a string; whether blanks in the window are included is +affected by the \member{stripspaces} member. +\end{methoddesc} + +\begin{methoddesc}{do_command}{ch} +Process a single command keystroke. Here are the supported special +keystrokes: + +\begin{tableii}{l|l}{kbd}{Keystroke}{Action} + \lineii{Control-A}{Go to left edge of window.} + \lineii{Control-B}{Cursor left, wrapping to previous line if appropriate.} + \lineii{Control-D}{Delete character under cursor.} + \lineii{Control-E}{Go to right edge (stripspaces off) or end of line + (stripspaces on).} + \lineii{Control-F}{Cursor right, wrapping to next line when appropriate.} + \lineii{Control-G}{Terminate, returning the window contents.} + \lineii{Control-H}{Delete character backward.} + \lineii{Control-J}{Terminate if the window is 1 line, otherwise + insert newline.} + \lineii{Control-K}{If line is blank, delete it, otherwise clear to + end of line.} + \lineii{Control-L}{Refresh screen.} + \lineii{Control-N}{Cursor down; move down one line.} + \lineii{Control-O}{Insert a blank line at cursor location.} + \lineii{Control-P}{Cursor up; move up one line.} +\end{tableii} + +Move operations do nothing if the cursor is at an edge where the +movement is not possible. The following synonyms are supported where +possible: + +\begin{tableii}{l|l}{constant}{Constant}{Keystroke} + \lineii{KEY_LEFT}{\kbd{Control-B}} + \lineii{KEY_RIGHT}{\kbd{Control-F}} + \lineii{KEY_UP}{\kbd{Control-P}} + \lineii{KEY_DOWN}{\kbd{Control-N}} + \lineii{KEY_BACKSPACE}{\kbd{Control-h}} +\end{tableii} + +All other keystrokes are treated as a command to insert the given +character and move right (with line wrapping). +\end{methoddesc} + +\begin{methoddesc}{gather}{} +This method returns the window contents as a string; whether blanks in +the window are included is affected by the \member{stripspaces} +member. +\end{methoddesc} + +\begin{memberdesc}{stripspaces} +This data member is a flag which controls the interpretation of blanks in +the window. When it is on, trailing blanks on each line are ignored; +any cursor motion that would land the cursor on a trailing blank goes +to the end of that line instead, and trailing blanks are stripped when +the window contents are gathered. +\end{memberdesc} + + +\section{\module{curses.wrapper} --- + Terminal handler for curses programs} + +\declaremodule{standard}{curses.wrapper} +\sectionauthor{Eric Raymond}{esr@thyrsus.com} +\moduleauthor{Eric Raymond}{esr@thyrsus.com} +\modulesynopsis{Terminal configuration wrapper for curses programs.} +\versionadded{1.6} + +This module supplies one function, \function{wrapper()}, which runs +another function which should be the rest of your curses-using +application. If the application raises an exception, +\function{wrapper()} will restore the terminal to a sane state before +re-raising the exception and generating a traceback. + +\begin{funcdesc}{wrapper}{func, \moreargs} +Wrapper function that initializes curses and calls another function, +\var{func}, restoring normal keyboard/screen behavior on error. +The callable object \var{func} is then passed the main window 'stdscr' +as its first argument, followed by any other arguments passed to +\function{wrapper()}. +\end{funcdesc} + +Before calling the hook function, \function{wrapper()} turns on cbreak +mode, turns off echo, enables the terminal keypad, and initializes +colors if the terminal has color support. On exit (whether normally +or by exception) it restores cooked mode, turns on echo, and disables +the terminal keypad. + diff --git a/sys/src/cmd/python/Doc/lib/libcursespanel.tex b/sys/src/cmd/python/Doc/lib/libcursespanel.tex new file mode 100644 index 000000000..1f96717fc --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libcursespanel.tex @@ -0,0 +1,96 @@ +\section{\module{curses.panel} --- + A panel stack extension for curses.} + +\declaremodule{standard}{curses.panel} +\sectionauthor{A.M. Kuchling}{amk@amk.ca} +\modulesynopsis{A panel stack extension that adds depth to + curses windows.} + +Panels are windows with the added feature of depth, so they can be +stacked on top of each other, and only the visible portions of +each window will be displayed. Panels can be added, moved up +or down in the stack, and removed. + +\subsection{Functions \label{cursespanel-functions}} + +The module \module{curses.panel} defines the following functions: + + +\begin{funcdesc}{bottom_panel}{} +Returns the bottom panel in the panel stack. +\end{funcdesc} + +\begin{funcdesc}{new_panel}{win} +Returns a panel object, associating it with the given window \var{win}. +Be aware that you need to keep the returned panel object referenced +explicitly. If you don't, the panel object is garbage collected and +removed from the panel stack. +\end{funcdesc} + +\begin{funcdesc}{top_panel}{} +Returns the top panel in the panel stack. +\end{funcdesc} + +\begin{funcdesc}{update_panels}{} +Updates the virtual screen after changes in the panel stack. This does +not call \function{curses.doupdate()}, so you'll have to do this yourself. +\end{funcdesc} + +\subsection{Panel Objects \label{curses-panel-objects}} + +Panel objects, as returned by \function{new_panel()} above, are windows +with a stacking order. There's always a window associated with a +panel which determines the content, while the panel methods are +responsible for the window's depth in the panel stack. + +Panel objects have the following methods: + +\begin{methoddesc}{above}{} +Returns the panel above the current panel. +\end{methoddesc} + +\begin{methoddesc}{below}{} +Returns the panel below the current panel. +\end{methoddesc} + +\begin{methoddesc}{bottom}{} +Push the panel to the bottom of the stack. +\end{methoddesc} + +\begin{methoddesc}{hidden}{} +Returns true if the panel is hidden (not visible), false otherwise. +\end{methoddesc} + +\begin{methoddesc}{hide}{} +Hide the panel. This does not delete the object, it just makes the +window on screen invisible. +\end{methoddesc} + +\begin{methoddesc}{move}{y, x} +Move the panel to the screen coordinates \code{(\var{y}, \var{x})}. +\end{methoddesc} + +\begin{methoddesc}{replace}{win} +Change the window associated with the panel to the window \var{win}. +\end{methoddesc} + +\begin{methoddesc}{set_userptr}{obj} +Set the panel's user pointer to \var{obj}. This is used to associate an +arbitrary piece of data with the panel, and can be any Python object. +\end{methoddesc} + +\begin{methoddesc}{show}{} +Display the panel (which might have been hidden). +\end{methoddesc} + +\begin{methoddesc}{top}{} +Push panel to the top of the stack. +\end{methoddesc} + +\begin{methoddesc}{userptr}{} +Returns the user pointer for the panel. This might be any Python object. +\end{methoddesc} + +\begin{methoddesc}{window}{} +Returns the window object associated with the panel. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libdatetime.tex b/sys/src/cmd/python/Doc/lib/libdatetime.tex new file mode 100644 index 000000000..0d2b5bb64 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdatetime.tex @@ -0,0 +1,1441 @@ +% XXX what order should the types be discussed in? + +\section{\module{datetime} --- + Basic date and time types} + +\declaremodule{builtin}{datetime} +\modulesynopsis{Basic date and time types.} +\moduleauthor{Tim Peters}{tim@zope.com} +\sectionauthor{Tim Peters}{tim@zope.com} +\sectionauthor{A.M. Kuchling}{amk@amk.ca} + +\versionadded{2.3} + + +The \module{datetime} module supplies classes for manipulating dates +and times in both simple and complex ways. While date and time +arithmetic is supported, the focus of the implementation is on +efficient member extraction for output formatting and manipulation. + +There are two kinds of date and time objects: ``naive'' and ``aware''. +This distinction refers to whether the object has any notion of time +zone, daylight saving time, or other kind of algorithmic or political +time adjustment. Whether a naive \class{datetime} object represents +Coordinated Universal Time (UTC), local time, or time in some other +timezone is purely up to the program, just like it's up to the program +whether a particular number represents metres, miles, or mass. Naive +\class{datetime} objects are easy to understand and to work with, at +the cost of ignoring some aspects of reality. + +For applications requiring more, \class{datetime} and \class{time} +objects have an optional time zone information member, +\member{tzinfo}, that can contain an instance of a subclass of +the abstract \class{tzinfo} class. These \class{tzinfo} objects +capture information about the offset from UTC time, the time zone +name, and whether Daylight Saving Time is in effect. Note that no +concrete \class{tzinfo} classes are supplied by the \module{datetime} +module. Supporting timezones at whatever level of detail is required +is up to the application. The rules for time adjustment across the +world are more political than rational, and there is no standard +suitable for every application. + +The \module{datetime} module exports the following constants: + +\begin{datadesc}{MINYEAR} + The smallest year number allowed in a \class{date} or + \class{datetime} object. \constant{MINYEAR} + is \code{1}. +\end{datadesc} + +\begin{datadesc}{MAXYEAR} + The largest year number allowed in a \class{date} or \class{datetime} + object. \constant{MAXYEAR} is \code{9999}. +\end{datadesc} + +\begin{seealso} + \seemodule{calendar}{General calendar related functions.} + \seemodule{time}{Time access and conversions.} +\end{seealso} + +\subsection{Available Types} + +\begin{classdesc*}{date} + An idealized naive date, assuming the current Gregorian calendar + always was, and always will be, in effect. + Attributes: \member{year}, \member{month}, and \member{day}. +\end{classdesc*} + +\begin{classdesc*}{time} + An idealized time, independent of any particular day, assuming + that every day has exactly 24*60*60 seconds (there is no notion + of "leap seconds" here). + Attributes: \member{hour}, \member{minute}, \member{second}, + \member{microsecond}, and \member{tzinfo}. +\end{classdesc*} + +\begin{classdesc*}{datetime} + A combination of a date and a time. + Attributes: \member{year}, \member{month}, \member{day}, + \member{hour}, \member{minute}, \member{second}, + \member{microsecond}, and \member{tzinfo}. +\end{classdesc*} + +\begin{classdesc*}{timedelta} + A duration expressing the difference between two \class{date}, + \class{time}, or \class{datetime} instances to microsecond + resolution. +\end{classdesc*} + +\begin{classdesc*}{tzinfo} + An abstract base class for time zone information objects. These + are used by the \class{datetime} and \class{time} classes to + provide a customizable notion of time adjustment (for example, to + account for time zone and/or daylight saving time). +\end{classdesc*} + +Objects of these types are immutable. + +Objects of the \class{date} type are always naive. + +An object \var{d} of type \class{time} or \class{datetime} may be +naive or aware. \var{d} is aware if \code{\var{d}.tzinfo} is not +\code{None} and \code{\var{d}.tzinfo.utcoffset(\var{d})} does not return +\code{None}. If \code{\var{d}.tzinfo} is \code{None}, or if +\code{\var{d}.tzinfo} is not \code{None} but +\code{\var{d}.tzinfo.utcoffset(\var{d})} returns \code{None}, \var{d} +is naive. + +The distinction between naive and aware doesn't apply to +\class{timedelta} objects. + +Subclass relationships: + +\begin{verbatim} +object + timedelta + tzinfo + time + date + datetime +\end{verbatim} + +\subsection{\class{timedelta} Objects \label{datetime-timedelta}} + +A \class{timedelta} object represents a duration, the difference +between two dates or times. + +\begin{classdesc}{timedelta}{\optional{days\optional{, seconds\optional{, + microseconds\optional{, milliseconds\optional{, + minutes\optional{, hours\optional{, weeks}}}}}}}} + All arguments are optional and default to \code{0}. Arguments may + be ints, longs, or floats, and may be positive or negative. + + Only \var{days}, \var{seconds} and \var{microseconds} are stored + internally. Arguments are converted to those units: + +\begin{itemize} + \item A millisecond is converted to 1000 microseconds. + \item A minute is converted to 60 seconds. + \item An hour is converted to 3600 seconds. + \item A week is converted to 7 days. +\end{itemize} + + and days, seconds and microseconds are then normalized so that the + representation is unique, with + +\begin{itemize} + \item \code{0 <= \var{microseconds} < 1000000} + \item \code{0 <= \var{seconds} < 3600*24} (the number of seconds in one day) + \item \code{-999999999 <= \var{days} <= 999999999} +\end{itemize} + + If any argument is a float and there are fractional microseconds, + the fractional microseconds left over from all arguments are combined + and their sum is rounded to the nearest microsecond. If no + argument is a float, the conversion and normalization processes + are exact (no information is lost). + + If the normalized value of days lies outside the indicated range, + \exception{OverflowError} is raised. + + Note that normalization of negative values may be surprising at first. + For example, + +\begin{verbatim} +>>> d = timedelta(microseconds=-1) +>>> (d.days, d.seconds, d.microseconds) +(-1, 86399, 999999) +\end{verbatim} +\end{classdesc} + +Class attributes are: + +\begin{memberdesc}{min} + The most negative \class{timedelta} object, + \code{timedelta(-999999999)}. +\end{memberdesc} + +\begin{memberdesc}{max} + The most positive \class{timedelta} object, + \code{timedelta(days=999999999, hours=23, minutes=59, seconds=59, + microseconds=999999)}. +\end{memberdesc} + +\begin{memberdesc}{resolution} + The smallest possible difference between non-equal + \class{timedelta} objects, \code{timedelta(microseconds=1)}. +\end{memberdesc} + +Note that, because of normalization, \code{timedelta.max} \textgreater +\code{-timedelta.min}. \code{-timedelta.max} is not representable as +a \class{timedelta} object. + +Instance attributes (read-only): + +\begin{tableii}{c|l}{code}{Attribute}{Value} + \lineii{days}{Between -999999999 and 999999999 inclusive} + \lineii{seconds}{Between 0 and 86399 inclusive} + \lineii{microseconds}{Between 0 and 999999 inclusive} +\end{tableii} + +Supported operations: + +% XXX this table is too wide! +\begin{tableii}{c|l}{code}{Operation}{Result} + \lineii{\var{t1} = \var{t2} + \var{t3}} + {Sum of \var{t2} and \var{t3}. + Afterwards \var{t1}-\var{t2} == \var{t3} and \var{t1}-\var{t3} + == \var{t2} are true. + (1)} + \lineii{\var{t1} = \var{t2} - \var{t3}} + {Difference of \var{t2} and \var{t3}. + Afterwards \var{t1} == \var{t2} - \var{t3} and + \var{t2} == \var{t1} + \var{t3} are true. + (1)} + \lineii{\var{t1} = \var{t2} * \var{i} or \var{t1} = \var{i} * \var{t2}} + {Delta multiplied by an integer or long. + Afterwards \var{t1} // i == \var{t2} is true, + provided \code{i != 0}.} + \lineii{}{In general, \var{t1} * i == \var{t1} * (i-1) + \var{t1} is true. + (1)} + \lineii{\var{t1} = \var{t2} // \var{i}} + {The floor is computed and the remainder (if any) is thrown away. + (3)} + \lineii{+\var{t1}} + {Returns a \class{timedelta} object with the same value. + (2)} + \lineii{-\var{t1}} + {equivalent to \class{timedelta}(-\var{t1.days}, -\var{t1.seconds}, + -\var{t1.microseconds}), and to \var{t1}* -1. + (1)(4)} + \lineii{abs(\var{t})} + {equivalent to +\var{t} when \code{t.days >= 0}, and to + -\var{t} when \code{t.days < 0}. + (2)} +\end{tableii} +\noindent +Notes: + +\begin{description} +\item[(1)] + This is exact, but may overflow. + +\item[(2)] + This is exact, and cannot overflow. + +\item[(3)] + Division by 0 raises \exception{ZeroDivisionError}. + +\item[(4)] + -\var{timedelta.max} is not representable as a \class{timedelta} object. +\end{description} + +In addition to the operations listed above \class{timedelta} objects +support certain additions and subtractions with \class{date} and +\class{datetime} objects (see below). + +Comparisons of \class{timedelta} objects are supported with the +\class{timedelta} object representing the smaller duration considered +to be the smaller timedelta. +In order to stop mixed-type comparisons from falling back to the +default comparison by object address, when a \class{timedelta} object is +compared to an object of a different type, \exception{TypeError} is +raised unless the comparison is \code{==} or \code{!=}. The latter +cases return \constant{False} or \constant{True}, respectively. + +\class{timedelta} objects are hashable (usable as dictionary keys), +support efficient pickling, and in Boolean contexts, a \class{timedelta} +object is considered to be true if and only if it isn't equal to +\code{timedelta(0)}. + + +\subsection{\class{date} Objects \label{datetime-date}} + +A \class{date} object represents a date (year, month and day) in an idealized +calendar, the current Gregorian calendar indefinitely extended in both +directions. January 1 of year 1 is called day number 1, January 2 of year +1 is called day number 2, and so on. This matches the definition of the +"proleptic Gregorian" calendar in Dershowitz and Reingold's book +\citetitle{Calendrical Calculations}, where it's the base calendar for all +computations. See the book for algorithms for converting between +proleptic Gregorian ordinals and many other calendar systems. + +\begin{classdesc}{date}{year, month, day} + All arguments are required. Arguments may be ints or longs, in the + following ranges: + + \begin{itemize} + \item \code{MINYEAR <= \var{year} <= MAXYEAR} + \item \code{1 <= \var{month} <= 12} + \item \code{1 <= \var{day} <= number of days in the given month and year} + \end{itemize} + + If an argument outside those ranges is given, \exception{ValueError} + is raised. +\end{classdesc} + +Other constructors, all class methods: + +\begin{methoddesc}{today}{} + Return the current local date. This is equivalent to + \code{date.fromtimestamp(time.time())}. +\end{methoddesc} + +\begin{methoddesc}{fromtimestamp}{timestamp} + Return the local date corresponding to the POSIX timestamp, such + as is returned by \function{time.time()}. This may raise + \exception{ValueError}, if the timestamp is out of the range of + values supported by the platform C \cfunction{localtime()} + function. It's common for this to be restricted to years from 1970 + through 2038. Note that on non-POSIX systems that include leap + seconds in their notion of a timestamp, leap seconds are ignored by + \method{fromtimestamp()}. +\end{methoddesc} + +\begin{methoddesc}{fromordinal}{ordinal} + Return the date corresponding to the proleptic Gregorian ordinal, + where January 1 of year 1 has ordinal 1. \exception{ValueError} is + raised unless \code{1 <= \var{ordinal} <= date.max.toordinal()}. + For any date \var{d}, \code{date.fromordinal(\var{d}.toordinal()) == + \var{d}}. +\end{methoddesc} + +Class attributes: + +\begin{memberdesc}{min} + The earliest representable date, \code{date(MINYEAR, 1, 1)}. +\end{memberdesc} + +\begin{memberdesc}{max} + The latest representable date, \code{date(MAXYEAR, 12, 31)}. +\end{memberdesc} + +\begin{memberdesc}{resolution} + The smallest possible difference between non-equal date + objects, \code{timedelta(days=1)}. +\end{memberdesc} + +Instance attributes (read-only): + +\begin{memberdesc}{year} + Between \constant{MINYEAR} and \constant{MAXYEAR} inclusive. +\end{memberdesc} + +\begin{memberdesc}{month} + Between 1 and 12 inclusive. +\end{memberdesc} + +\begin{memberdesc}{day} + Between 1 and the number of days in the given month of the given + year. +\end{memberdesc} + +Supported operations: + +\begin{tableii}{c|l}{code}{Operation}{Result} + \lineii{\var{date2} = \var{date1} + \var{timedelta}} + {\var{date2} is \code{\var{timedelta}.days} days removed from + \var{date1}. (1)} + + + \lineii{\var{date2} = \var{date1} - \var{timedelta}} + {Computes \var{date2} such that \code{\var{date2} + \var{timedelta} + == \var{date1}}. (2)} + + \lineii{\var{timedelta} = \var{date1} - \var{date2}} + {(3)} + + \lineii{\var{date1} < \var{date2}} + {\var{date1} is considered less than \var{date2} when \var{date1} + precedes \var{date2} in time. (4)} + +\end{tableii} + +Notes: +\begin{description} + +\item[(1)] + \var{date2} is moved forward in time if \code{\var{timedelta}.days + > 0}, or backward if \code{\var{timedelta}.days < 0}. Afterward + \code{\var{date2} - \var{date1} == \var{timedelta}.days}. + \code{\var{timedelta}.seconds} and + \code{\var{timedelta}.microseconds} are ignored. + \exception{OverflowError} is raised if \code{\var{date2}.year} + would be smaller than \constant{MINYEAR} or larger than + \constant{MAXYEAR}. + +\item[(2)] + This isn't quite equivalent to date1 + + (-timedelta), because -timedelta in isolation can overflow in cases + where date1 - timedelta does not. \code{\var{timedelta}.seconds} + and \code{\var{timedelta}.microseconds} are ignored. + +\item[(3)] +This is exact, and cannot overflow. timedelta.seconds and + timedelta.microseconds are 0, and date2 + timedelta == date1 + after. + +\item[(4)] +In other words, \code{date1 < date2} + if and only if \code{\var{date1}.toordinal() < + \var{date2}.toordinal()}. +In order to stop comparison from falling back to the default +scheme of comparing object addresses, date comparison +normally raises \exception{TypeError} if the other comparand +isn't also a \class{date} object. However, \code{NotImplemented} +is returned instead if the other comparand has a +\method{timetuple} attribute. This hook gives other kinds of +date objects a chance at implementing mixed-type comparison. +If not, when a \class{date} object is +compared to an object of a different type, \exception{TypeError} is +raised unless the comparison is \code{==} or \code{!=}. The latter +cases return \constant{False} or \constant{True}, respectively. + +\end{description} + + +Dates can be used as dictionary keys. In Boolean contexts, all +\class{date} objects are considered to be true. + +Instance methods: + +\begin{methoddesc}{replace}{year, month, day} + Return a date with the same value, except for those members given + new values by whichever keyword arguments are specified. For + example, if \code{d == date(2002, 12, 31)}, then + \code{d.replace(day=26) == date(2002, 12, 26)}. +\end{methoddesc} + +\begin{methoddesc}{timetuple}{} + Return a \class{time.struct_time} such as returned by + \function{time.localtime()}. The hours, minutes and seconds are + 0, and the DST flag is -1. + \code{\var{d}.timetuple()} is equivalent to + \code{time.struct_time((\var{d}.year, \var{d}.month, \var{d}.day, + 0, 0, 0, + \var{d}.weekday(), + \var{d}.toordinal() - date(\var{d}.year, 1, 1).toordinal() + 1, + -1))} +\end{methoddesc} + +\begin{methoddesc}{toordinal}{} + Return the proleptic Gregorian ordinal of the date, where January 1 + of year 1 has ordinal 1. For any \class{date} object \var{d}, + \code{date.fromordinal(\var{d}.toordinal()) == \var{d}}. +\end{methoddesc} + +\begin{methoddesc}{weekday}{} + Return the day of the week as an integer, where Monday is 0 and + Sunday is 6. For example, \code{date(2002, 12, 4).weekday() == 2}, a + Wednesday. + See also \method{isoweekday()}. +\end{methoddesc} + +\begin{methoddesc}{isoweekday}{} + Return the day of the week as an integer, where Monday is 1 and + Sunday is 7. For example, \code{date(2002, 12, 4).isoweekday() == 3}, a + Wednesday. + See also \method{weekday()}, \method{isocalendar()}. +\end{methoddesc} + +\begin{methoddesc}{isocalendar}{} + Return a 3-tuple, (ISO year, ISO week number, ISO weekday). + + The ISO calendar is a widely used variant of the Gregorian calendar. + See \url{http://www.phys.uu.nl/~vgent/calendar/isocalendar.htm} + for a good explanation. + + The ISO year consists of 52 or 53 full weeks, and where a week starts + on a Monday and ends on a Sunday. The first week of an ISO year is + the first (Gregorian) calendar week of a year containing a Thursday. + This is called week number 1, and the ISO year of that Thursday is + the same as its Gregorian year. + + For example, 2004 begins on a Thursday, so the first week of ISO + year 2004 begins on Monday, 29 Dec 2003 and ends on Sunday, 4 Jan + 2004, so that + \code{date(2003, 12, 29).isocalendar() == (2004, 1, 1)} + and + \code{date(2004, 1, 4).isocalendar() == (2004, 1, 7)}. +\end{methoddesc} + +\begin{methoddesc}{isoformat}{} + Return a string representing the date in ISO 8601 format, + 'YYYY-MM-DD'. For example, + \code{date(2002, 12, 4).isoformat() == '2002-12-04'}. +\end{methoddesc} + +\begin{methoddesc}{__str__}{} + For a date \var{d}, \code{str(\var{d})} is equivalent to + \code{\var{d}.isoformat()}. +\end{methoddesc} + +\begin{methoddesc}{ctime}{} + Return a string representing the date, for example + date(2002, 12, 4).ctime() == 'Wed Dec 4 00:00:00 2002'. + \code{\var{d}.ctime()} is equivalent to + \code{time.ctime(time.mktime(\var{d}.timetuple()))} + on platforms where the native C \cfunction{ctime()} function + (which \function{time.ctime()} invokes, but which + \method{date.ctime()} does not invoke) conforms to the C standard. +\end{methoddesc} + +\begin{methoddesc}{strftime}{format} + Return a string representing the date, controlled by an explicit + format string. Format codes referring to hours, minutes or seconds + will see 0 values. + See section~\ref{strftime-behavior} -- \method{strftime()} behavior. +\end{methoddesc} + + +\subsection{\class{datetime} Objects \label{datetime-datetime}} + +A \class{datetime} object is a single object containing all the +information from a \class{date} object and a \class{time} object. Like a +\class{date} object, \class{datetime} assumes the current Gregorian +calendar extended in both directions; like a time object, +\class{datetime} assumes there are exactly 3600*24 seconds in every +day. + +Constructor: + +\begin{classdesc}{datetime}{year, month, day\optional{, + hour\optional{, minute\optional{, + second\optional{, microsecond\optional{, + tzinfo}}}}}} + The year, month and day arguments are required. \var{tzinfo} may + be \code{None}, or an instance of a \class{tzinfo} subclass. The + remaining arguments may be ints or longs, in the following ranges: + + \begin{itemize} + \item \code{MINYEAR <= \var{year} <= MAXYEAR} + \item \code{1 <= \var{month} <= 12} + \item \code{1 <= \var{day} <= number of days in the given month and year} + \item \code{0 <= \var{hour} < 24} + \item \code{0 <= \var{minute} < 60} + \item \code{0 <= \var{second} < 60} + \item \code{0 <= \var{microsecond} < 1000000} + \end{itemize} + + If an argument outside those ranges is given, + \exception{ValueError} is raised. +\end{classdesc} + +Other constructors, all class methods: + +\begin{methoddesc}{today}{} + Return the current local datetime, with \member{tzinfo} \code{None}. + This is equivalent to + \code{datetime.fromtimestamp(time.time())}. + See also \method{now()}, \method{fromtimestamp()}. +\end{methoddesc} + +\begin{methoddesc}{now}{\optional{tz}} + Return the current local date and time. If optional argument + \var{tz} is \code{None} or not specified, this is like + \method{today()}, but, if possible, supplies more precision than can + be gotten from going through a \function{time.time()} timestamp (for + example, this may be possible on platforms supplying the C + \cfunction{gettimeofday()} function). + + Else \var{tz} must be an instance of a class \class{tzinfo} subclass, + and the current date and time are converted to \var{tz}'s time + zone. In this case the result is equivalent to + \code{\var{tz}.fromutc(datetime.utcnow().replace(tzinfo=\var{tz}))}. + See also \method{today()}, \method{utcnow()}. +\end{methoddesc} + +\begin{methoddesc}{utcnow}{} + Return the current UTC date and time, with \member{tzinfo} \code{None}. + This is like \method{now()}, but returns the current UTC date and time, + as a naive \class{datetime} object. + See also \method{now()}. +\end{methoddesc} + +\begin{methoddesc}{fromtimestamp}{timestamp\optional{, tz}} + Return the local date and time corresponding to the \POSIX{} + timestamp, such as is returned by \function{time.time()}. + If optional argument \var{tz} is \code{None} or not specified, the + timestamp is converted to the platform's local date and time, and + the returned \class{datetime} object is naive. + + Else \var{tz} must be an instance of a class \class{tzinfo} subclass, + and the timestamp is converted to \var{tz}'s time zone. In this case + the result is equivalent to + \code{\var{tz}.fromutc(datetime.utcfromtimestamp(\var{timestamp}).replace(tzinfo=\var{tz}))}. + + \method{fromtimestamp()} may raise \exception{ValueError}, if the + timestamp is out of the range of values supported by the platform C + \cfunction{localtime()} or \cfunction{gmtime()} functions. It's common + for this to be restricted to years in 1970 through 2038. + Note that on non-POSIX systems that include leap seconds in their + notion of a timestamp, leap seconds are ignored by + \method{fromtimestamp()}, and then it's possible to have two timestamps + differing by a second that yield identical \class{datetime} objects. + See also \method{utcfromtimestamp()}. +\end{methoddesc} + +\begin{methoddesc}{utcfromtimestamp}{timestamp} + Return the UTC \class{datetime} corresponding to the \POSIX{} + timestamp, with \member{tzinfo} \code{None}. + This may raise \exception{ValueError}, if the + timestamp is out of the range of values supported by the platform + C \cfunction{gmtime()} function. It's common for this to be + restricted to years in 1970 through 2038. + See also \method{fromtimestamp()}. +\end{methoddesc} + +\begin{methoddesc}{fromordinal}{ordinal} + Return the \class{datetime} corresponding to the proleptic + Gregorian ordinal, where January 1 of year 1 has ordinal 1. + \exception{ValueError} is raised unless \code{1 <= ordinal <= + datetime.max.toordinal()}. The hour, minute, second and + microsecond of the result are all 0, + and \member{tzinfo} is \code{None}. +\end{methoddesc} + +\begin{methoddesc}{combine}{date, time} + Return a new \class{datetime} object whose date members are + equal to the given \class{date} object's, and whose time + and \member{tzinfo} members are equal to the given \class{time} object's. + For any \class{datetime} object \var{d}, \code{\var{d} == + datetime.combine(\var{d}.date(), \var{d}.timetz())}. If date is a + \class{datetime} object, its time and \member{tzinfo} members are + ignored. + \end{methoddesc} + +\begin{methoddesc}{strptime}{date_string, format} + Return a \class{datetime} corresponding to \var{date_string}, parsed + according to \var{format}. This is equivalent to + \code{datetime(*(time.strptime(date_string, + format)[0:6]))}. \exception{ValueError} is raised if the date_string and + format can't be parsed by \function{time.strptime()} or if it returns a + value which isn't a time tuple. + + \versionadded{2.5} +\end{methoddesc} + +Class attributes: + +\begin{memberdesc}{min} + The earliest representable \class{datetime}, + \code{datetime(MINYEAR, 1, 1, tzinfo=None)}. +\end{memberdesc} + +\begin{memberdesc}{max} + The latest representable \class{datetime}, + \code{datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, tzinfo=None)}. +\end{memberdesc} + +\begin{memberdesc}{resolution} + The smallest possible difference between non-equal \class{datetime} + objects, \code{timedelta(microseconds=1)}. +\end{memberdesc} + +Instance attributes (read-only): + +\begin{memberdesc}{year} + Between \constant{MINYEAR} and \constant{MAXYEAR} inclusive. +\end{memberdesc} + +\begin{memberdesc}{month} + Between 1 and 12 inclusive. +\end{memberdesc} + +\begin{memberdesc}{day} + Between 1 and the number of days in the given month of the given + year. +\end{memberdesc} + +\begin{memberdesc}{hour} + In \code{range(24)}. +\end{memberdesc} + +\begin{memberdesc}{minute} + In \code{range(60)}. +\end{memberdesc} + +\begin{memberdesc}{second} + In \code{range(60)}. +\end{memberdesc} + +\begin{memberdesc}{microsecond} + In \code{range(1000000)}. +\end{memberdesc} + +\begin{memberdesc}{tzinfo} + The object passed as the \var{tzinfo} argument to the + \class{datetime} constructor, or \code{None} if none was passed. +\end{memberdesc} + +Supported operations: + +\begin{tableii}{c|l}{code}{Operation}{Result} + \lineii{\var{datetime2} = \var{datetime1} + \var{timedelta}}{(1)} + + \lineii{\var{datetime2} = \var{datetime1} - \var{timedelta}}{(2)} + + \lineii{\var{timedelta} = \var{datetime1} - \var{datetime2}}{(3)} + + \lineii{\var{datetime1} < \var{datetime2}} + {Compares \class{datetime} to \class{datetime}. + (4)} + +\end{tableii} + +\begin{description} + +\item[(1)] + + datetime2 is a duration of timedelta removed from datetime1, moving + forward in time if \code{\var{timedelta}.days} > 0, or backward if + \code{\var{timedelta}.days} < 0. The result has the same \member{tzinfo} member + as the input datetime, and datetime2 - datetime1 == timedelta after. + \exception{OverflowError} is raised if datetime2.year would be + smaller than \constant{MINYEAR} or larger than \constant{MAXYEAR}. + Note that no time zone adjustments are done even if the input is an + aware object. + +\item[(2)] + Computes the datetime2 such that datetime2 + timedelta == datetime1. + As for addition, the result has the same \member{tzinfo} member + as the input datetime, and no time zone adjustments are done even + if the input is aware. + This isn't quite equivalent to datetime1 + (-timedelta), because + -timedelta in isolation can overflow in cases where + datetime1 - timedelta does not. + +\item[(3)] + Subtraction of a \class{datetime} from a + \class{datetime} is defined only if both + operands are naive, or if both are aware. If one is aware and the + other is naive, \exception{TypeError} is raised. + + If both are naive, or both are aware and have the same \member{tzinfo} + member, the \member{tzinfo} members are ignored, and the result is + a \class{timedelta} object \var{t} such that + \code{\var{datetime2} + \var{t} == \var{datetime1}}. No time zone + adjustments are done in this case. + + If both are aware and have different \member{tzinfo} members, + \code{a-b} acts as if \var{a} and \var{b} were first converted to + naive UTC datetimes first. The result is + \code{(\var{a}.replace(tzinfo=None) - \var{a}.utcoffset()) - + (\var{b}.replace(tzinfo=None) - \var{b}.utcoffset())} + except that the implementation never overflows. + +\item[(4)] + +\var{datetime1} is considered less than \var{datetime2} +when \var{datetime1} precedes \var{datetime2} in time. + +If one comparand is naive and +the other is aware, \exception{TypeError} is raised. If both + comparands are aware, and have the same \member{tzinfo} member, + the common \member{tzinfo} member is ignored and the base datetimes + are compared. If both comparands are aware and have different + \member{tzinfo} members, the comparands are first adjusted by + subtracting their UTC offsets (obtained from \code{self.utcoffset()}). + \note{In order to stop comparison from falling back to the default + scheme of comparing object addresses, datetime comparison + normally raises \exception{TypeError} if the other comparand + isn't also a \class{datetime} object. However, + \code{NotImplemented} is returned instead if the other comparand + has a \method{timetuple} attribute. This hook gives other + kinds of date objects a chance at implementing mixed-type + comparison. If not, when a \class{datetime} object is + compared to an object of a different type, \exception{TypeError} + is raised unless the comparison is \code{==} or \code{!=}. The + latter cases return \constant{False} or \constant{True}, + respectively.} + +\end{description} + +\class{datetime} objects can be used as dictionary keys. In Boolean +contexts, all \class{datetime} objects are considered to be true. + + +Instance methods: + +\begin{methoddesc}{date}{} + Return \class{date} object with same year, month and day. +\end{methoddesc} + +\begin{methoddesc}{time}{} + Return \class{time} object with same hour, minute, second and microsecond. + \member{tzinfo} is \code{None}. See also method \method{timetz()}. +\end{methoddesc} + +\begin{methoddesc}{timetz}{} + Return \class{time} object with same hour, minute, second, microsecond, + and tzinfo members. See also method \method{time()}. +\end{methoddesc} + +\begin{methoddesc}{replace}{\optional{year\optional{, month\optional{, + day\optional{, hour\optional{, minute\optional{, + second\optional{, microsecond\optional{, + tzinfo}}}}}}}}} + Return a datetime with the same members, except for those members given + new values by whichever keyword arguments are specified. Note that + \code{tzinfo=None} can be specified to create a naive datetime from + an aware datetime with no conversion of date and time members. +\end{methoddesc} + +\begin{methoddesc}{astimezone}{tz} + Return a \class{datetime} object with new \member{tzinfo} member + \var{tz}, adjusting the date and time members so the result is the + same UTC time as \var{self}, but in \var{tz}'s local time. + + \var{tz} must be an instance of a \class{tzinfo} subclass, and its + \method{utcoffset()} and \method{dst()} methods must not return + \code{None}. \var{self} must be aware (\code{\var{self}.tzinfo} must + not be \code{None}, and \code{\var{self}.utcoffset()} must not return + \code{None}). + + If \code{\var{self}.tzinfo} is \var{tz}, + \code{\var{self}.astimezone(\var{tz})} is equal to \var{self}: no + adjustment of date or time members is performed. + Else the result is local time in time zone \var{tz}, representing the + same UTC time as \var{self}: after \code{\var{astz} = + \var{dt}.astimezone(\var{tz})}, + \code{\var{astz} - \var{astz}.utcoffset()} will usually have the same + date and time members as \code{\var{dt} - \var{dt}.utcoffset()}. + The discussion of class \class{tzinfo} explains the cases at Daylight + Saving Time transition boundaries where this cannot be achieved (an issue + only if \var{tz} models both standard and daylight time). + + If you merely want to attach a time zone object \var{tz} to a + datetime \var{dt} without adjustment of date and time members, + use \code{\var{dt}.replace(tzinfo=\var{tz})}. If + you merely want to remove the time zone object from an aware datetime + \var{dt} without conversion of date and time members, use + \code{\var{dt}.replace(tzinfo=None)}. + + Note that the default \method{tzinfo.fromutc()} method can be overridden + in a \class{tzinfo} subclass to affect the result returned by + \method{astimezone()}. Ignoring error cases, \method{astimezone()} + acts like: + + \begin{verbatim} + def astimezone(self, tz): + if self.tzinfo is tz: + return self + # Convert self to UTC, and attach the new time zone object. + utc = (self - self.utcoffset()).replace(tzinfo=tz) + # Convert from UTC to tz's local time. + return tz.fromutc(utc) + \end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{utcoffset}{} + If \member{tzinfo} is \code{None}, returns \code{None}, else + returns \code{\var{self}.tzinfo.utcoffset(\var{self})}, and + raises an exception if the latter doesn't return \code{None}, or + a \class{timedelta} object representing a whole number of minutes + with magnitude less than one day. +\end{methoddesc} + +\begin{methoddesc}{dst}{} + If \member{tzinfo} is \code{None}, returns \code{None}, else + returns \code{\var{self}.tzinfo.dst(\var{self})}, and + raises an exception if the latter doesn't return \code{None}, or + a \class{timedelta} object representing a whole number of minutes + with magnitude less than one day. +\end{methoddesc} + +\begin{methoddesc}{tzname}{} + If \member{tzinfo} is \code{None}, returns \code{None}, else + returns \code{\var{self}.tzinfo.tzname(\var{self})}, + raises an exception if the latter doesn't return \code{None} or + a string object, +\end{methoddesc} + +\begin{methoddesc}{timetuple}{} + Return a \class{time.struct_time} such as returned by + \function{time.localtime()}. + \code{\var{d}.timetuple()} is equivalent to + \code{time.struct_time((\var{d}.year, \var{d}.month, \var{d}.day, + \var{d}.hour, \var{d}.minute, \var{d}.second, + \var{d}.weekday(), + \var{d}.toordinal() - date(\var{d}.year, 1, 1).toordinal() + 1, + dst))} + The \member{tm_isdst} flag of the result is set according to + the \method{dst()} method: \member{tzinfo} is \code{None} or + \method{dst()} returns \code{None}, + \member{tm_isdst} is set to \code{-1}; else if \method{dst()} returns + a non-zero value, \member{tm_isdst} is set to \code{1}; + else \code{tm_isdst} is set to \code{0}. +\end{methoddesc} + +\begin{methoddesc}{utctimetuple}{} + If \class{datetime} instance \var{d} is naive, this is the same as + \code{\var{d}.timetuple()} except that \member{tm_isdst} is forced to 0 + regardless of what \code{d.dst()} returns. DST is never in effect + for a UTC time. + + If \var{d} is aware, \var{d} is normalized to UTC time, by subtracting + \code{\var{d}.utcoffset()}, and a \class{time.struct_time} for the + normalized time is returned. \member{tm_isdst} is forced to 0. + Note that the result's \member{tm_year} member may be + \constant{MINYEAR}-1 or \constant{MAXYEAR}+1, if \var{d}.year was + \code{MINYEAR} or \code{MAXYEAR} and UTC adjustment spills over a + year boundary. +\end{methoddesc} + +\begin{methoddesc}{toordinal}{} + Return the proleptic Gregorian ordinal of the date. The same as + \code{self.date().toordinal()}. +\end{methoddesc} + +\begin{methoddesc}{weekday}{} + Return the day of the week as an integer, where Monday is 0 and + Sunday is 6. The same as \code{self.date().weekday()}. + See also \method{isoweekday()}. +\end{methoddesc} + +\begin{methoddesc}{isoweekday}{} + Return the day of the week as an integer, where Monday is 1 and + Sunday is 7. The same as \code{self.date().isoweekday()}. + See also \method{weekday()}, \method{isocalendar()}. +\end{methoddesc} + +\begin{methoddesc}{isocalendar}{} + Return a 3-tuple, (ISO year, ISO week number, ISO weekday). The + same as \code{self.date().isocalendar()}. +\end{methoddesc} + +\begin{methoddesc}{isoformat}{\optional{sep}} + Return a string representing the date and time in ISO 8601 format, + YYYY-MM-DDTHH:MM:SS.mmmmmm + or, if \member{microsecond} is 0, + YYYY-MM-DDTHH:MM:SS + + If \method{utcoffset()} does not return \code{None}, a 6-character + string is appended, giving the UTC offset in (signed) hours and + minutes: + YYYY-MM-DDTHH:MM:SS.mmmmmm+HH:MM + or, if \member{microsecond} is 0 + YYYY-MM-DDTHH:MM:SS+HH:MM + + The optional argument \var{sep} (default \code{'T'}) is a + one-character separator, placed between the date and time portions + of the result. For example, + +\begin{verbatim} +>>> from datetime import tzinfo, timedelta, datetime +>>> class TZ(tzinfo): +... def utcoffset(self, dt): return timedelta(minutes=-399) +... +>>> datetime(2002, 12, 25, tzinfo=TZ()).isoformat(' ') +'2002-12-25 00:00:00-06:39' +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{__str__}{} + For a \class{datetime} instance \var{d}, \code{str(\var{d})} is + equivalent to \code{\var{d}.isoformat(' ')}. +\end{methoddesc} + +\begin{methoddesc}{ctime}{} + Return a string representing the date and time, for example + \code{datetime(2002, 12, 4, 20, 30, 40).ctime() == + 'Wed Dec 4 20:30:40 2002'}. + \code{d.ctime()} is equivalent to + \code{time.ctime(time.mktime(d.timetuple()))} on platforms where + the native C \cfunction{ctime()} function (which + \function{time.ctime()} invokes, but which + \method{datetime.ctime()} does not invoke) conforms to the C + standard. +\end{methoddesc} + +\begin{methoddesc}{strftime}{format} + Return a string representing the date and time, controlled by an + explicit format string. See section~\ref{strftime-behavior} -- + \method{strftime()} behavior. +\end{methoddesc} + + +\subsection{\class{time} Objects \label{datetime-time}} + +A time object represents a (local) time of day, independent of any +particular day, and subject to adjustment via a \class{tzinfo} object. + +\begin{classdesc}{time}{hour\optional{, minute\optional{, second\optional{, + microsecond\optional{, tzinfo}}}}} + All arguments are optional. \var{tzinfo} may be \code{None}, or + an instance of a \class{tzinfo} subclass. The remaining arguments + may be ints or longs, in the following ranges: + + \begin{itemize} + \item \code{0 <= \var{hour} < 24} + \item \code{0 <= \var{minute} < 60} + \item \code{0 <= \var{second} < 60} + \item \code{0 <= \var{microsecond} < 1000000}. + \end{itemize} + + If an argument outside those ranges is given, + \exception{ValueError} is raised. All default to \code{0} except + \var{tzinfo}, which defaults to \constant{None}. +\end{classdesc} + +Class attributes: + +\begin{memberdesc}{min} + The earliest representable \class{time}, \code{time(0, 0, 0, 0)}. +\end{memberdesc} + +\begin{memberdesc}{max} + The latest representable \class{time}, \code{time(23, 59, 59, 999999)}. +\end{memberdesc} + +\begin{memberdesc}{resolution} + The smallest possible difference between non-equal \class{time} + objects, \code{timedelta(microseconds=1)}, although note that + arithmetic on \class{time} objects is not supported. +\end{memberdesc} + +Instance attributes (read-only): + +\begin{memberdesc}{hour} + In \code{range(24)}. +\end{memberdesc} + +\begin{memberdesc}{minute} + In \code{range(60)}. +\end{memberdesc} + +\begin{memberdesc}{second} + In \code{range(60)}. +\end{memberdesc} + +\begin{memberdesc}{microsecond} + In \code{range(1000000)}. +\end{memberdesc} + +\begin{memberdesc}{tzinfo} + The object passed as the tzinfo argument to the \class{time} + constructor, or \code{None} if none was passed. +\end{memberdesc} + +Supported operations: + +\begin{itemize} + \item + comparison of \class{time} to \class{time}, + where \var{a} is considered less than \var{b} when \var{a} precedes + \var{b} in time. If one comparand is naive and the other is aware, + \exception{TypeError} is raised. If both comparands are aware, and + have the same \member{tzinfo} member, the common \member{tzinfo} + member is ignored and the base times are compared. If both + comparands are aware and have different \member{tzinfo} members, + the comparands are first adjusted by subtracting their UTC offsets + (obtained from \code{self.utcoffset()}). + In order to stop mixed-type comparisons from falling back to the + default comparison by object address, when a \class{time} object is + compared to an object of a different type, \exception{TypeError} is + raised unless the comparison is \code{==} or \code{!=}. The latter + cases return \constant{False} or \constant{True}, respectively. + + \item + hash, use as dict key + + \item + efficient pickling + + \item + in Boolean contexts, a \class{time} object is considered to be + true if and only if, after converting it to minutes and + subtracting \method{utcoffset()} (or \code{0} if that's + \code{None}), the result is non-zero. +\end{itemize} + +Instance methods: + +\begin{methoddesc}{replace}{\optional{hour\optional{, minute\optional{, + second\optional{, microsecond\optional{, + tzinfo}}}}}} + Return a \class{time} with the same value, except for those members given + new values by whichever keyword arguments are specified. Note that + \code{tzinfo=None} can be specified to create a naive \class{time} from + an aware \class{time}, without conversion of the time members. +\end{methoddesc} + +\begin{methoddesc}{isoformat}{} + Return a string representing the time in ISO 8601 format, + HH:MM:SS.mmmmmm + or, if self.microsecond is 0, + HH:MM:SS + If \method{utcoffset()} does not return \code{None}, a 6-character + string is appended, giving the UTC offset in (signed) hours and + minutes: + HH:MM:SS.mmmmmm+HH:MM + or, if self.microsecond is 0, + HH:MM:SS+HH:MM +\end{methoddesc} + +\begin{methoddesc}{__str__}{} + For a time \var{t}, \code{str(\var{t})} is equivalent to + \code{\var{t}.isoformat()}. +\end{methoddesc} + +\begin{methoddesc}{strftime}{format} + Return a string representing the time, controlled by an explicit + format string. See section~\ref{strftime-behavior} -- + \method{strftime()} behavior. +\end{methoddesc} + +\begin{methoddesc}{utcoffset}{} + If \member{tzinfo} is \code{None}, returns \code{None}, else + returns \code{\var{self}.tzinfo.utcoffset(None)}, and + raises an exception if the latter doesn't return \code{None} or + a \class{timedelta} object representing a whole number of minutes + with magnitude less than one day. +\end{methoddesc} + +\begin{methoddesc}{dst}{} + If \member{tzinfo} is \code{None}, returns \code{None}, else + returns \code{\var{self}.tzinfo.dst(None)}, and + raises an exception if the latter doesn't return \code{None}, or + a \class{timedelta} object representing a whole number of minutes + with magnitude less than one day. +\end{methoddesc} + +\begin{methoddesc}{tzname}{} + If \member{tzinfo} is \code{None}, returns \code{None}, else + returns \code{\var{self}.tzinfo.tzname(None)}, or + raises an exception if the latter doesn't return \code{None} or + a string object. +\end{methoddesc} + + +\subsection{\class{tzinfo} Objects \label{datetime-tzinfo}} + +\class{tzinfo} is an abstract base clase, meaning that this class +should not be instantiated directly. You need to derive a concrete +subclass, and (at least) supply implementations of the standard +\class{tzinfo} methods needed by the \class{datetime} methods you +use. The \module{datetime} module does not supply any concrete +subclasses of \class{tzinfo}. + +An instance of (a concrete subclass of) \class{tzinfo} can be passed +to the constructors for \class{datetime} and \class{time} objects. +The latter objects view their members as being in local time, and the +\class{tzinfo} object supports methods revealing offset of local time +from UTC, the name of the time zone, and DST offset, all relative to a +date or time object passed to them. + +Special requirement for pickling: A \class{tzinfo} subclass must have an +\method{__init__} method that can be called with no arguments, else it +can be pickled but possibly not unpickled again. This is a technical +requirement that may be relaxed in the future. + +A concrete subclass of \class{tzinfo} may need to implement the +following methods. Exactly which methods are needed depends on the +uses made of aware \module{datetime} objects. If in doubt, simply +implement all of them. + +\begin{methoddesc}{utcoffset}{self, dt} + Return offset of local time from UTC, in minutes east of UTC. If + local time is west of UTC, this should be negative. Note that this + is intended to be the total offset from UTC; for example, if a + \class{tzinfo} object represents both time zone and DST adjustments, + \method{utcoffset()} should return their sum. If the UTC offset + isn't known, return \code{None}. Else the value returned must be + a \class{timedelta} object specifying a whole number of minutes in the + range -1439 to 1439 inclusive (1440 = 24*60; the magnitude of the offset + must be less than one day). Most implementations of + \method{utcoffset()} will probably look like one of these two: + +\begin{verbatim} + return CONSTANT # fixed-offset class + return CONSTANT + self.dst(dt) # daylight-aware class +\end{verbatim} + + If \method{utcoffset()} does not return \code{None}, + \method{dst()} should not return \code{None} either. + + The default implementation of \method{utcoffset()} raises + \exception{NotImplementedError}. +\end{methoddesc} + +\begin{methoddesc}{dst}{self, dt} + Return the daylight saving time (DST) adjustment, in minutes east of + UTC, or \code{None} if DST information isn't known. Return + \code{timedelta(0)} if DST is not in effect. + If DST is in effect, return the offset as a + \class{timedelta} object (see \method{utcoffset()} for details). + Note that DST offset, if applicable, has + already been added to the UTC offset returned by + \method{utcoffset()}, so there's no need to consult \method{dst()} + unless you're interested in obtaining DST info separately. For + example, \method{datetime.timetuple()} calls its \member{tzinfo} + member's \method{dst()} method to determine how the + \member{tm_isdst} flag should be set, and + \method{tzinfo.fromutc()} calls \method{dst()} to account for + DST changes when crossing time zones. + + An instance \var{tz} of a \class{tzinfo} subclass that models both + standard and daylight times must be consistent in this sense: + + \code{\var{tz}.utcoffset(\var{dt}) - \var{tz}.dst(\var{dt})} + + must return the same result for every \class{datetime} \var{dt} + with \code{\var{dt}.tzinfo == \var{tz}} For sane \class{tzinfo} + subclasses, this expression yields the time zone's "standard offset", + which should not depend on the date or the time, but only on geographic + location. The implementation of \method{datetime.astimezone()} relies + on this, but cannot detect violations; it's the programmer's + responsibility to ensure it. If a \class{tzinfo} subclass cannot + guarantee this, it may be able to override the default implementation + of \method{tzinfo.fromutc()} to work correctly with \method{astimezone()} + regardless. + + Most implementations of \method{dst()} will probably look like one + of these two: + +\begin{verbatim} + def dst(self): + # a fixed-offset class: doesn't account for DST + return timedelta(0) +\end{verbatim} + + or + +\begin{verbatim} + def dst(self): + # Code to set dston and dstoff to the time zone's DST + # transition times based on the input dt.year, and expressed + # in standard local time. Then + + if dston <= dt.replace(tzinfo=None) < dstoff: + return timedelta(hours=1) + else: + return timedelta(0) +\end{verbatim} + + The default implementation of \method{dst()} raises + \exception{NotImplementedError}. +\end{methoddesc} + +\begin{methoddesc}{tzname}{self, dt} + Return the time zone name corresponding to the \class{datetime} + object \var{dt}, as a string. + Nothing about string names is defined by the + \module{datetime} module, and there's no requirement that it mean + anything in particular. For example, "GMT", "UTC", "-500", "-5:00", + "EDT", "US/Eastern", "America/New York" are all valid replies. Return + \code{None} if a string name isn't known. Note that this is a method + rather than a fixed string primarily because some \class{tzinfo} + subclasses will wish to return different names depending on the specific + value of \var{dt} passed, especially if the \class{tzinfo} class is + accounting for daylight time. + + The default implementation of \method{tzname()} raises + \exception{NotImplementedError}. +\end{methoddesc} + +These methods are called by a \class{datetime} or \class{time} object, +in response to their methods of the same names. A \class{datetime} +object passes itself as the argument, and a \class{time} object passes +\code{None} as the argument. A \class{tzinfo} subclass's methods should +therefore be prepared to accept a \var{dt} argument of \code{None}, or of +class \class{datetime}. + +When \code{None} is passed, it's up to the class designer to decide the +best response. For example, returning \code{None} is appropriate if the +class wishes to say that time objects don't participate in the +\class{tzinfo} protocols. It may be more useful for \code{utcoffset(None)} +to return the standard UTC offset, as there is no other convention for +discovering the standard offset. + +When a \class{datetime} object is passed in response to a +\class{datetime} method, \code{dt.tzinfo} is the same object as +\var{self}. \class{tzinfo} methods can rely on this, unless +user code calls \class{tzinfo} methods directly. The intent is that +the \class{tzinfo} methods interpret \var{dt} as being in local time, +and not need worry about objects in other timezones. + +There is one more \class{tzinfo} method that a subclass may wish to +override: + +\begin{methoddesc}{fromutc}{self, dt} + This is called from the default \class{datetime.astimezone()} + implementation. When called from that, \code{\var{dt}.tzinfo} is + \var{self}, and \var{dt}'s date and time members are to be viewed as + expressing a UTC time. The purpose of \method{fromutc()} is to + adjust the date and time members, returning an equivalent datetime in + \var{self}'s local time. + + Most \class{tzinfo} subclasses should be able to inherit the default + \method{fromutc()} implementation without problems. It's strong enough + to handle fixed-offset time zones, and time zones accounting for both + standard and daylight time, and the latter even if the DST transition + times differ in different years. An example of a time zone the default + \method{fromutc()} implementation may not handle correctly in all cases + is one where the standard offset (from UTC) depends on the specific date + and time passed, which can happen for political reasons. + The default implementations of \method{astimezone()} and + \method{fromutc()} may not produce the result you want if the result is + one of the hours straddling the moment the standard offset changes. + + Skipping code for error cases, the default \method{fromutc()} + implementation acts like: + + \begin{verbatim} + def fromutc(self, dt): + # raise ValueError error if dt.tzinfo is not self + dtoff = dt.utcoffset() + dtdst = dt.dst() + # raise ValueError if dtoff is None or dtdst is None + delta = dtoff - dtdst # this is self's standard offset + if delta: + dt += delta # convert to standard local time + dtdst = dt.dst() + # raise ValueError if dtdst is None + if dtdst: + return dt + dtdst + else: + return dt + \end{verbatim} +\end{methoddesc} + +Example \class{tzinfo} classes: + +\verbatiminput{tzinfo-examples.py} + +Note that there are unavoidable subtleties twice per year in a +\class{tzinfo} +subclass accounting for both standard and daylight time, at the DST +transition points. For concreteness, consider US Eastern (UTC -0500), +where EDT begins the minute after 1:59 (EST) on the first Sunday in +April, and ends the minute after 1:59 (EDT) on the last Sunday in October: + +\begin{verbatim} + UTC 3:MM 4:MM 5:MM 6:MM 7:MM 8:MM + EST 22:MM 23:MM 0:MM 1:MM 2:MM 3:MM + EDT 23:MM 0:MM 1:MM 2:MM 3:MM 4:MM + + start 22:MM 23:MM 0:MM 1:MM 3:MM 4:MM + + end 23:MM 0:MM 1:MM 1:MM 2:MM 3:MM +\end{verbatim} + +When DST starts (the "start" line), the local wall clock leaps from 1:59 +to 3:00. A wall time of the form 2:MM doesn't really make sense on that +day, so \code{astimezone(Eastern)} won't deliver a result with +\code{hour == 2} on the +day DST begins. In order for \method{astimezone()} to make this +guarantee, the \method{rzinfo.dst()} method must consider times +in the "missing hour" (2:MM for Eastern) to be in daylight time. + +When DST ends (the "end" line), there's a potentially worse problem: +there's an hour that can't be spelled unambiguously in local wall time: +the last hour of daylight time. In Eastern, that's times of +the form 5:MM UTC on the day daylight time ends. The local wall clock +leaps from 1:59 (daylight time) back to 1:00 (standard time) again. +Local times of the form 1:MM are ambiguous. \method{astimezone()} mimics +the local clock's behavior by mapping two adjacent UTC hours into the +same local hour then. In the Eastern example, UTC times of the form +5:MM and 6:MM both map to 1:MM when converted to Eastern. In order for +\method{astimezone()} to make this guarantee, the \method{tzinfo.dst()} +method must consider times in the "repeated hour" to be in +standard time. This is easily arranged, as in the example, by expressing +DST switch times in the time zone's standard local time. + +Applications that can't bear such ambiguities should avoid using hybrid +\class{tzinfo} subclasses; there are no ambiguities when using UTC, or +any other fixed-offset \class{tzinfo} subclass (such as a class +representing only EST (fixed offset -5 hours), or only EDT (fixed offset +-4 hours)). + + +\subsection{\method{strftime()} Behavior\label{strftime-behavior}} + +\class{date}, \class{datetime}, and \class{time} +objects all support a \code{strftime(\var{format})} +method, to create a string representing the time under the control of +an explicit format string. Broadly speaking, +\code{d.strftime(fmt)} +acts like the \refmodule{time} module's +\code{time.strftime(fmt, d.timetuple())} +although not all objects support a \method{timetuple()} method. + +For \class{time} objects, the format codes for +year, month, and day should not be used, as time objects have no such +values. If they're used anyway, \code{1900} is substituted for the +year, and \code{0} for the month and day. + +For \class{date} objects, the format codes for hours, minutes, and +seconds should not be used, as \class{date} objects have no such +values. If they're used anyway, \code{0} is substituted for them. + +For a naive object, the \code{\%z} and \code{\%Z} format codes are +replaced by empty strings. + +For an aware object: + +\begin{itemize} + \item[\code{\%z}] + \method{utcoffset()} is transformed into a 5-character string of + the form +HHMM or -HHMM, where HH is a 2-digit string giving the + number of UTC offset hours, and MM is a 2-digit string giving the + number of UTC offset minutes. For example, if + \method{utcoffset()} returns \code{timedelta(hours=-3, minutes=-30)}, + \code{\%z} is replaced with the string \code{'-0330'}. + + \item[\code{\%Z}] + If \method{tzname()} returns \code{None}, \code{\%Z} is replaced + by an empty string. Otherwise \code{\%Z} is replaced by the returned + value, which must be a string. +\end{itemize} + +The full set of format codes supported varies across platforms, +because Python calls the platform C library's \function{strftime()} +function, and platform variations are common. The documentation for +Python's \refmodule{time} module lists the format codes that the C +standard (1989 version) requires, and those work on all platforms +with a standard C implementation. Note that the 1999 version of the +C standard added additional format codes. + +The exact range of years for which \method{strftime()} works also +varies across platforms. Regardless of platform, years before 1900 +cannot be used. + +%%% This example is obsolete, since strptime is now supported by datetime. +% +% \subsection{Examples} +% +% \subsubsection{Creating Datetime Objects from Formatted Strings} +% +% The \class{datetime} class does not directly support parsing formatted time +% strings. You can use \function{time.strptime} to do the parsing and create +% a \class{datetime} object from the tuple it returns: +% +% \begin{verbatim} +% >>> s = "2005-12-06T12:13:14" +% >>> from datetime import datetime +% >>> from time import strptime +% >>> datetime(*strptime(s, "%Y-%m-%dT%H:%M:%S")[0:6]) +% datetime.datetime(2005, 12, 6, 12, 13, 14) +% \end{verbatim} +% diff --git a/sys/src/cmd/python/Doc/lib/libdbhash.tex b/sys/src/cmd/python/Doc/lib/libdbhash.tex new file mode 100644 index 000000000..cf4470721 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdbhash.tex @@ -0,0 +1,88 @@ +\section{\module{dbhash} --- + DBM-style interface to the BSD database library} + +\declaremodule{standard}{dbhash} +\modulesynopsis{DBM-style interface to the BSD database library.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + + +The \module{dbhash} module provides a function to open databases using +the BSD \code{db} library. This module mirrors the interface of the +other Python database modules that provide access to DBM-style +databases. The \refmodule{bsddb}\refbimodindex{bsddb} module is required +to use \module{dbhash}. + +This module provides an exception and a function: + + +\begin{excdesc}{error} + Exception raised on database errors other than + \exception{KeyError}. It is a synonym for \exception{bsddb.error}. +\end{excdesc} + +\begin{funcdesc}{open}{path\optional{, flag\optional{, mode}}} + Open a \code{db} database and return the database object. The + \var{path} argument is the name of the database file. + + The \var{flag} argument can be + \code{'r'} (the default), \code{'w'}, + \code{'c'} (which creates the database if it doesn't exist), or + \code{'n'} (which always creates a new empty database). + For platforms on which the BSD \code{db} library supports locking, + an \character{l} can be appended to indicate that locking should be + used. + + The optional \var{mode} parameter is used to indicate the \UNIX{} + permission bits that should be set if a new database must be + created; this will be masked by the current umask value for the + process. +\end{funcdesc} + + +\begin{seealso} + \seemodule{anydbm}{Generic interface to \code{dbm}-style databases.} + \seemodule{bsddb}{Lower-level interface to the BSD \code{db} library.} + \seemodule{whichdb}{Utility module used to determine the type of an + existing database.} +\end{seealso} + + +\subsection{Database Objects \label{dbhash-objects}} + +The database objects returned by \function{open()} provide the methods +common to all the DBM-style databases and mapping objects. The following +methods are available in addition to the standard methods. + +\begin{methoddesc}[dbhash]{first}{} + It's possible to loop over every key/value pair in the database using + this method and the \method{next()} method. The traversal is ordered by + the databases internal hash values, and won't be sorted by the key + values. This method returns the starting key. +\end{methoddesc} + +\begin{methoddesc}[dbhash]{last}{} + Return the last key/value pair in a database traversal. This may be used to + begin a reverse-order traversal; see \method{previous()}. +\end{methoddesc} + +\begin{methoddesc}[dbhash]{next}{} + Returns the key next key/value pair in a database traversal. The + following code prints every key in the database \code{db}, without + having to create a list in memory that contains them all: + +\begin{verbatim} +print db.first() +for i in xrange(1, len(db)): + print db.next() +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}[dbhash]{previous}{} + Returns the previous key/value pair in a forward-traversal of the database. + In conjunction with \method{last()}, this may be used to implement + a reverse-order traversal. +\end{methoddesc} + +\begin{methoddesc}[dbhash]{sync}{} + This method forces any unwritten data to be written to the disk. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libdbm.tex b/sys/src/cmd/python/Doc/lib/libdbm.tex new file mode 100644 index 000000000..e08af9989 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdbm.tex @@ -0,0 +1,61 @@ +\section{\module{dbm} --- + Simple ``database'' interface} + +\declaremodule{builtin}{dbm} + \platform{Unix} +\modulesynopsis{The standard ``database'' interface, based on ndbm.} + + +The \module{dbm} module provides an interface to the \UNIX{} +(\code{n})\code{dbm} library. Dbm objects behave like mappings +(dictionaries), except that keys and values are always strings. +Printing a dbm object doesn't print the keys and values, and the +\method{items()} and \method{values()} methods are not supported. + +This module can be used with the ``classic'' ndbm interface, the BSD +DB compatibility interface, or the GNU GDBM compatibility interface. +On \UNIX, the \program{configure} script will attempt to locate the +appropriate header file to simplify building this module. + +The module defines the following: + +\begin{excdesc}{error} +Raised on dbm-specific errors, such as I/O errors. +\exception{KeyError} is raised for general mapping errors like +specifying an incorrect key. +\end{excdesc} + +\begin{datadesc}{library} +Name of the \code{ndbm} implementation library used. +\end{datadesc} + +\begin{funcdesc}{open}{filename\optional{, flag\optional{, mode}}} +Open a dbm database and return a dbm object. The \var{filename} +argument is the name of the database file (without the \file{.dir} or +\file{.pag} extensions; note that the BSD DB implementation of the +interface will append the extension \file{.db} and only create one +file). + +The optional \var{flag} argument must be one of these values: + +\begin{tableii}{c|l}{code}{Value}{Meaning} + \lineii{'r'}{Open existing database for reading only (default)} + \lineii{'w'}{Open existing database for reading and writing} + \lineii{'c'}{Open database for reading and writing, creating it if + it doesn't exist} + \lineii{'n'}{Always create a new, empty database, open for reading + and writing} +\end{tableii} + +The optional \var{mode} argument is the \UNIX{} mode of the file, used +only when the database has to be created. It defaults to octal +\code{0666}. +\end{funcdesc} + + +\begin{seealso} + \seemodule{anydbm}{Generic interface to \code{dbm}-style databases.} + \seemodule{gdbm}{Similar interface to the GNU GDBM library.} + \seemodule{whichdb}{Utility module used to determine the type of an + existing database.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libdecimal.tex b/sys/src/cmd/python/Doc/lib/libdecimal.tex new file mode 100644 index 000000000..127eb1d47 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdecimal.tex @@ -0,0 +1,1313 @@ +\section{\module{decimal} --- + Decimal floating point arithmetic} + +\declaremodule{standard}{decimal} +\modulesynopsis{Implementation of the General Decimal Arithmetic +Specification.} + +\moduleauthor{Eric Price}{eprice at tjhsst.edu} +\moduleauthor{Facundo Batista}{facundo at taniquetil.com.ar} +\moduleauthor{Raymond Hettinger}{python at rcn.com} +\moduleauthor{Aahz}{aahz at pobox.com} +\moduleauthor{Tim Peters}{tim.one at comcast.net} + +\sectionauthor{Raymond D. Hettinger}{python at rcn.com} + +\versionadded{2.4} + +The \module{decimal} module provides support for decimal floating point +arithmetic. It offers several advantages over the \class{float()} datatype: + +\begin{itemize} + +\item Decimal numbers can be represented exactly. In contrast, numbers like +\constant{1.1} do not have an exact representation in binary floating point. +End users typically would not expect \constant{1.1} to display as +\constant{1.1000000000000001} as it does with binary floating point. + +\item The exactness carries over into arithmetic. In decimal floating point, +\samp{0.1 + 0.1 + 0.1 - 0.3} is exactly equal to zero. In binary floating +point, result is \constant{5.5511151231257827e-017}. While near to zero, the +differences prevent reliable equality testing and differences can accumulate. +For this reason, decimal would be preferred in accounting applications which +have strict equality invariants. + +\item The decimal module incorporates a notion of significant places so that +\samp{1.30 + 1.20} is \constant{2.50}. The trailing zero is kept to indicate +significance. This is the customary presentation for monetary applications. For +multiplication, the ``schoolbook'' approach uses all the figures in the +multiplicands. For instance, \samp{1.3 * 1.2} gives \constant{1.56} while +\samp{1.30 * 1.20} gives \constant{1.5600}. + +\item Unlike hardware based binary floating point, the decimal module has a user +settable precision (defaulting to 28 places) which can be as large as needed for +a given problem: + +\begin{verbatim} +>>> getcontext().prec = 6 +>>> Decimal(1) / Decimal(7) +Decimal("0.142857") +>>> getcontext().prec = 28 +>>> Decimal(1) / Decimal(7) +Decimal("0.1428571428571428571428571429") +\end{verbatim} + +\item Both binary and decimal floating point are implemented in terms of published +standards. While the built-in float type exposes only a modest portion of its +capabilities, the decimal module exposes all required parts of the standard. +When needed, the programmer has full control over rounding and signal handling. + +\end{itemize} + + +The module design is centered around three concepts: the decimal number, the +context for arithmetic, and signals. + +A decimal number is immutable. It has a sign, coefficient digits, and an +exponent. To preserve significance, the coefficient digits do not truncate +trailing zeroes. Decimals also include special values such as +\constant{Infinity}, \constant{-Infinity}, and \constant{NaN}. The standard +also differentiates \constant{-0} from \constant{+0}. + +The context for arithmetic is an environment specifying precision, rounding +rules, limits on exponents, flags indicating the results of operations, +and trap enablers which determine whether signals are treated as +exceptions. Rounding options include \constant{ROUND_CEILING}, +\constant{ROUND_DOWN}, \constant{ROUND_FLOOR}, \constant{ROUND_HALF_DOWN}, +\constant{ROUND_HALF_EVEN}, \constant{ROUND_HALF_UP}, and \constant{ROUND_UP}. + +Signals are groups of exceptional conditions arising during the course of +computation. Depending on the needs of the application, signals may be +ignored, considered as informational, or treated as exceptions. The signals in +the decimal module are: \constant{Clamped}, \constant{InvalidOperation}, +\constant{DivisionByZero}, \constant{Inexact}, \constant{Rounded}, +\constant{Subnormal}, \constant{Overflow}, and \constant{Underflow}. + +For each signal there is a flag and a trap enabler. When a signal is +encountered, its flag is incremented from zero and, then, if the trap enabler +is set to one, an exception is raised. Flags are sticky, so the user +needs to reset them before monitoring a calculation. + + +\begin{seealso} + \seetext{IBM's General Decimal Arithmetic Specification, + \citetitle[http://www2.hursley.ibm.com/decimal/decarith.html] + {The General Decimal Arithmetic Specification}.} + + \seetext{IEEE standard 854-1987, + \citetitle[http://www.cs.berkeley.edu/\textasciitilde ejr/projects/754/private/drafts/854-1987/dir.html] + {Unofficial IEEE 854 Text}.} +\end{seealso} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Quick-start Tutorial \label{decimal-tutorial}} + +The usual start to using decimals is importing the module, viewing the current +context with \function{getcontext()} and, if necessary, setting new values +for precision, rounding, or enabled traps: + +\begin{verbatim} +>>> from decimal import * +>>> getcontext() +Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + capitals=1, flags=[], traps=[Overflow, InvalidOperation, + DivisionByZero]) + +>>> getcontext().prec = 7 # Set a new precision +\end{verbatim} + + +Decimal instances can be constructed from integers, strings, or tuples. To +create a Decimal from a \class{float}, first convert it to a string. This +serves as an explicit reminder of the details of the conversion (including +representation error). Decimal numbers include special values such as +\constant{NaN} which stands for ``Not a number'', positive and negative +\constant{Infinity}, and \constant{-0}. + +\begin{verbatim} +>>> Decimal(10) +Decimal("10") +>>> Decimal("3.14") +Decimal("3.14") +>>> Decimal((0, (3, 1, 4), -2)) +Decimal("3.14") +>>> Decimal(str(2.0 ** 0.5)) +Decimal("1.41421356237") +>>> Decimal("NaN") +Decimal("NaN") +>>> Decimal("-Infinity") +Decimal("-Infinity") +\end{verbatim} + + +The significance of a new Decimal is determined solely by the number +of digits input. Context precision and rounding only come into play during +arithmetic operations. + +\begin{verbatim} +>>> getcontext().prec = 6 +>>> Decimal('3.0') +Decimal("3.0") +>>> Decimal('3.1415926535') +Decimal("3.1415926535") +>>> Decimal('3.1415926535') + Decimal('2.7182818285') +Decimal("5.85987") +>>> getcontext().rounding = ROUND_UP +>>> Decimal('3.1415926535') + Decimal('2.7182818285') +Decimal("5.85988") +\end{verbatim} + + +Decimals interact well with much of the rest of Python. Here is a small +decimal floating point flying circus: + +\begin{verbatim} +>>> data = map(Decimal, '1.34 1.87 3.45 2.35 1.00 0.03 9.25'.split()) +>>> max(data) +Decimal("9.25") +>>> min(data) +Decimal("0.03") +>>> sorted(data) +[Decimal("0.03"), Decimal("1.00"), Decimal("1.34"), Decimal("1.87"), + Decimal("2.35"), Decimal("3.45"), Decimal("9.25")] +>>> sum(data) +Decimal("19.29") +>>> a,b,c = data[:3] +>>> str(a) +'1.34' +>>> float(a) +1.3400000000000001 +>>> round(a, 1) # round() first converts to binary floating point +1.3 +>>> int(a) +1 +>>> a * 5 +Decimal("6.70") +>>> a * b +Decimal("2.5058") +>>> c % a +Decimal("0.77") +\end{verbatim} + +The \method{quantize()} method rounds a number to a fixed exponent. This +method is useful for monetary applications that often round results to a fixed +number of places: + +\begin{verbatim} +>>> Decimal('7.325').quantize(Decimal('.01'), rounding=ROUND_DOWN) +Decimal("7.32") +>>> Decimal('7.325').quantize(Decimal('1.'), rounding=ROUND_UP) +Decimal("8") +\end{verbatim} + +As shown above, the \function{getcontext()} function accesses the current +context and allows the settings to be changed. This approach meets the +needs of most applications. + +For more advanced work, it may be useful to create alternate contexts using +the Context() constructor. To make an alternate active, use the +\function{setcontext()} function. + +In accordance with the standard, the \module{Decimal} module provides two +ready to use standard contexts, \constant{BasicContext} and +\constant{ExtendedContext}. The former is especially useful for debugging +because many of the traps are enabled: + +\begin{verbatim} +>>> myothercontext = Context(prec=60, rounding=ROUND_HALF_DOWN) +>>> setcontext(myothercontext) +>>> Decimal(1) / Decimal(7) +Decimal("0.142857142857142857142857142857142857142857142857142857142857") + +>>> ExtendedContext +Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + capitals=1, flags=[], traps=[]) +>>> setcontext(ExtendedContext) +>>> Decimal(1) / Decimal(7) +Decimal("0.142857143") +>>> Decimal(42) / Decimal(0) +Decimal("Infinity") + +>>> setcontext(BasicContext) +>>> Decimal(42) / Decimal(0) +Traceback (most recent call last): + File "", line 1, in -toplevel- + Decimal(42) / Decimal(0) +DivisionByZero: x / 0 +\end{verbatim} + + +Contexts also have signal flags for monitoring exceptional conditions +encountered during computations. The flags remain set until explicitly +cleared, so it is best to clear the flags before each set of monitored +computations by using the \method{clear_flags()} method. + +\begin{verbatim} +>>> setcontext(ExtendedContext) +>>> getcontext().clear_flags() +>>> Decimal(355) / Decimal(113) +Decimal("3.14159292") +>>> getcontext() +Context(prec=9, rounding=ROUND_HALF_EVEN, Emin=-999999999, Emax=999999999, + capitals=1, flags=[Inexact, Rounded], traps=[]) +\end{verbatim} + +The \var{flags} entry shows that the rational approximation to \constant{Pi} +was rounded (digits beyond the context precision were thrown away) and that +the result is inexact (some of the discarded digits were non-zero). + +Individual traps are set using the dictionary in the \member{traps} +field of a context: + +\begin{verbatim} +>>> Decimal(1) / Decimal(0) +Decimal("Infinity") +>>> getcontext().traps[DivisionByZero] = 1 +>>> Decimal(1) / Decimal(0) +Traceback (most recent call last): + File "", line 1, in -toplevel- + Decimal(1) / Decimal(0) +DivisionByZero: x / 0 +\end{verbatim} + +Most programs adjust the current context only once, at the beginning of the +program. And, in many applications, data is converted to \class{Decimal} with +a single cast inside a loop. With context set and decimals created, the bulk +of the program manipulates the data no differently than with other Python +numeric types. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Decimal objects \label{decimal-decimal}} + +\begin{classdesc}{Decimal}{\optional{value \optional{, context}}} + Constructs a new \class{Decimal} object based from \var{value}. + + \var{value} can be an integer, string, tuple, or another \class{Decimal} + object. If no \var{value} is given, returns \code{Decimal("0")}. If + \var{value} is a string, it should conform to the decimal numeric string + syntax: + + \begin{verbatim} + sign ::= '+' | '-' + digit ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' + indicator ::= 'e' | 'E' + digits ::= digit [digit]... + decimal-part ::= digits '.' [digits] | ['.'] digits + exponent-part ::= indicator [sign] digits + infinity ::= 'Infinity' | 'Inf' + nan ::= 'NaN' [digits] | 'sNaN' [digits] + numeric-value ::= decimal-part [exponent-part] | infinity + numeric-string ::= [sign] numeric-value | [sign] nan + \end{verbatim} + + If \var{value} is a \class{tuple}, it should have three components, + a sign (\constant{0} for positive or \constant{1} for negative), + a \class{tuple} of digits, and an integer exponent. For example, + \samp{Decimal((0, (1, 4, 1, 4), -3))} returns \code{Decimal("1.414")}. + + The \var{context} precision does not affect how many digits are stored. + That is determined exclusively by the number of digits in \var{value}. For + example, \samp{Decimal("3.00000")} records all five zeroes even if the + context precision is only three. + + The purpose of the \var{context} argument is determining what to do if + \var{value} is a malformed string. If the context traps + \constant{InvalidOperation}, an exception is raised; otherwise, the + constructor returns a new Decimal with the value of \constant{NaN}. + + Once constructed, \class{Decimal} objects are immutable. +\end{classdesc} + +Decimal floating point objects share many properties with the other builtin +numeric types such as \class{float} and \class{int}. All of the usual +math operations and special methods apply. Likewise, decimal objects can +be copied, pickled, printed, used as dictionary keys, used as set elements, +compared, sorted, and coerced to another type (such as \class{float} +or \class{long}). + +In addition to the standard numeric properties, decimal floating point objects +also have a number of specialized methods: + +\begin{methoddesc}{adjusted}{} + Return the adjusted exponent after shifting out the coefficient's rightmost + digits until only the lead digit remains: \code{Decimal("321e+5").adjusted()} + returns seven. Used for determining the position of the most significant + digit with respect to the decimal point. +\end{methoddesc} + +\begin{methoddesc}{as_tuple}{} + Returns a tuple representation of the number: + \samp{(sign, digittuple, exponent)}. +\end{methoddesc} + +\begin{methoddesc}{compare}{other\optional{, context}} + Compares like \method{__cmp__()} but returns a decimal instance: + \begin{verbatim} + a or b is a NaN ==> Decimal("NaN") + a < b ==> Decimal("-1") + a == b ==> Decimal("0") + a > b ==> Decimal("1") + \end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{max}{other\optional{, context}} + Like \samp{max(self, other)} except that the context rounding rule + is applied before returning and that \constant{NaN} values are + either signalled or ignored (depending on the context and whether + they are signaling or quiet). +\end{methoddesc} + +\begin{methoddesc}{min}{other\optional{, context}} + Like \samp{min(self, other)} except that the context rounding rule + is applied before returning and that \constant{NaN} values are + either signalled or ignored (depending on the context and whether + they are signaling or quiet). +\end{methoddesc} + +\begin{methoddesc}{normalize}{\optional{context}} + Normalize the number by stripping the rightmost trailing zeroes and + converting any result equal to \constant{Decimal("0")} to + \constant{Decimal("0e0")}. Used for producing canonical values for members + of an equivalence class. For example, \code{Decimal("32.100")} and + \code{Decimal("0.321000e+2")} both normalize to the equivalent value + \code{Decimal("32.1")}. +\end{methoddesc} + +\begin{methoddesc}{quantize} + {exp \optional{, rounding\optional{, context\optional{, watchexp}}}} + Quantize makes the exponent the same as \var{exp}. Searches for a + rounding method in \var{rounding}, then in \var{context}, and then + in the current context. + + If \var{watchexp} is set (default), then an error is returned whenever + the resulting exponent is greater than \member{Emax} or less than + \member{Etiny}. +\end{methoddesc} + +\begin{methoddesc}{remainder_near}{other\optional{, context}} + Computes the modulo as either a positive or negative value depending + on which is closest to zero. For instance, + \samp{Decimal(10).remainder_near(6)} returns \code{Decimal("-2")} + which is closer to zero than \code{Decimal("4")}. + + If both are equally close, the one chosen will have the same sign + as \var{self}. +\end{methoddesc} + +\begin{methoddesc}{same_quantum}{other\optional{, context}} + Test whether self and other have the same exponent or whether both + are \constant{NaN}. +\end{methoddesc} + +\begin{methoddesc}{sqrt}{\optional{context}} + Return the square root to full precision. +\end{methoddesc} + +\begin{methoddesc}{to_eng_string}{\optional{context}} + Convert to an engineering-type string. + + Engineering notation has an exponent which is a multiple of 3, so there + are up to 3 digits left of the decimal place. For example, converts + \code{Decimal('123E+1')} to \code{Decimal("1.23E+3")} +\end{methoddesc} + +\begin{methoddesc}{to_integral}{\optional{rounding\optional{, context}}} + Rounds to the nearest integer without signaling \constant{Inexact} + or \constant{Rounded}. If given, applies \var{rounding}; otherwise, + uses the rounding method in either the supplied \var{context} or the + current context. +\end{methoddesc} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Context objects \label{decimal-decimal}} + +Contexts are environments for arithmetic operations. They govern precision, +set rules for rounding, determine which signals are treated as exceptions, and +limit the range for exponents. + +Each thread has its own current context which is accessed or changed using +the \function{getcontext()} and \function{setcontext()} functions: + +\begin{funcdesc}{getcontext}{} + Return the current context for the active thread. +\end{funcdesc} + +\begin{funcdesc}{setcontext}{c} + Set the current context for the active thread to \var{c}. +\end{funcdesc} + +Beginning with Python 2.5, you can also use the \keyword{with} statement +and the \function{localcontext()} function to temporarily change the +active context. + +\begin{funcdesc}{localcontext}{\optional{c}} + Return a context manager that will set the current context for + the active thread to a copy of \var{c} on entry to the with-statement + and restore the previous context when exiting the with-statement. If + no context is specified, a copy of the current context is used. + \versionadded{2.5} + + For example, the following code sets the current decimal precision + to 42 places, performs a calculation, and then automatically restores + the previous context: +\begin{verbatim} + from __future__ import with_statement + from decimal import localcontext + + with localcontext() as ctx: + ctx.prec = 42 # Perform a high precision calculation + s = calculate_something() + s = +s # Round the final result back to the default precision +\end{verbatim} +\end{funcdesc} + +New contexts can also be created using the \class{Context} constructor +described below. In addition, the module provides three pre-made +contexts: + +\begin{classdesc*}{BasicContext} + This is a standard context defined by the General Decimal Arithmetic + Specification. Precision is set to nine. Rounding is set to + \constant{ROUND_HALF_UP}. All flags are cleared. All traps are enabled + (treated as exceptions) except \constant{Inexact}, \constant{Rounded}, and + \constant{Subnormal}. + + Because many of the traps are enabled, this context is useful for debugging. +\end{classdesc*} + +\begin{classdesc*}{ExtendedContext} + This is a standard context defined by the General Decimal Arithmetic + Specification. Precision is set to nine. Rounding is set to + \constant{ROUND_HALF_EVEN}. All flags are cleared. No traps are enabled + (so that exceptions are not raised during computations). + + Because the trapped are disabled, this context is useful for applications + that prefer to have result value of \constant{NaN} or \constant{Infinity} + instead of raising exceptions. This allows an application to complete a + run in the presence of conditions that would otherwise halt the program. +\end{classdesc*} + +\begin{classdesc*}{DefaultContext} + This context is used by the \class{Context} constructor as a prototype for + new contexts. Changing a field (such a precision) has the effect of + changing the default for new contexts creating by the \class{Context} + constructor. + + This context is most useful in multi-threaded environments. Changing one of + the fields before threads are started has the effect of setting system-wide + defaults. Changing the fields after threads have started is not recommended + as it would require thread synchronization to prevent race conditions. + + In single threaded environments, it is preferable to not use this context + at all. Instead, simply create contexts explicitly as described below. + + The default values are precision=28, rounding=ROUND_HALF_EVEN, and enabled + traps for Overflow, InvalidOperation, and DivisionByZero. +\end{classdesc*} + + +In addition to the three supplied contexts, new contexts can be created +with the \class{Context} constructor. + +\begin{classdesc}{Context}{prec=None, rounding=None, traps=None, + flags=None, Emin=None, Emax=None, capitals=1} + Creates a new context. If a field is not specified or is \constant{None}, + the default values are copied from the \constant{DefaultContext}. If the + \var{flags} field is not specified or is \constant{None}, all flags are + cleared. + + The \var{prec} field is a positive integer that sets the precision for + arithmetic operations in the context. + + The \var{rounding} option is one of: + \begin{itemize} + \item \constant{ROUND_CEILING} (towards \constant{Infinity}), + \item \constant{ROUND_DOWN} (towards zero), + \item \constant{ROUND_FLOOR} (towards \constant{-Infinity}), + \item \constant{ROUND_HALF_DOWN} (to nearest with ties going towards zero), + \item \constant{ROUND_HALF_EVEN} (to nearest with ties going to nearest even integer), + \item \constant{ROUND_HALF_UP} (to nearest with ties going away from zero), or + \item \constant{ROUND_UP} (away from zero). + \end{itemize} + + The \var{traps} and \var{flags} fields list any signals to be set. + Generally, new contexts should only set traps and leave the flags clear. + + The \var{Emin} and \var{Emax} fields are integers specifying the outer + limits allowable for exponents. + + The \var{capitals} field is either \constant{0} or \constant{1} (the + default). If set to \constant{1}, exponents are printed with a capital + \constant{E}; otherwise, a lowercase \constant{e} is used: + \constant{Decimal('6.02e+23')}. +\end{classdesc} + +The \class{Context} class defines several general purpose methods as well as a +large number of methods for doing arithmetic directly in a given context. + +\begin{methoddesc}{clear_flags}{} + Resets all of the flags to \constant{0}. +\end{methoddesc} + +\begin{methoddesc}{copy}{} + Return a duplicate of the context. +\end{methoddesc} + +\begin{methoddesc}{create_decimal}{num} + Creates a new Decimal instance from \var{num} but using \var{self} as + context. Unlike the \class{Decimal} constructor, the context precision, + rounding method, flags, and traps are applied to the conversion. + + This is useful because constants are often given to a greater precision than + is needed by the application. Another benefit is that rounding immediately + eliminates unintended effects from digits beyond the current precision. + In the following example, using unrounded inputs means that adding zero + to a sum can change the result: + + \begin{verbatim} + >>> getcontext().prec = 3 + >>> Decimal("3.4445") + Decimal("1.0023") + Decimal("4.45") + >>> Decimal("3.4445") + Decimal(0) + Decimal("1.0023") + Decimal("4.44") + \end{verbatim} + +\end{methoddesc} + +\begin{methoddesc}{Etiny}{} + Returns a value equal to \samp{Emin - prec + 1} which is the minimum + exponent value for subnormal results. When underflow occurs, the + exponent is set to \constant{Etiny}. +\end{methoddesc} + +\begin{methoddesc}{Etop}{} + Returns a value equal to \samp{Emax - prec + 1}. +\end{methoddesc} + + +The usual approach to working with decimals is to create \class{Decimal} +instances and then apply arithmetic operations which take place within the +current context for the active thread. An alternate approach is to use +context methods for calculating within a specific context. The methods are +similar to those for the \class{Decimal} class and are only briefly recounted +here. + +\begin{methoddesc}{abs}{x} + Returns the absolute value of \var{x}. +\end{methoddesc} + +\begin{methoddesc}{add}{x, y} + Return the sum of \var{x} and \var{y}. +\end{methoddesc} + +\begin{methoddesc}{compare}{x, y} + Compares values numerically. + + Like \method{__cmp__()} but returns a decimal instance: + \begin{verbatim} + a or b is a NaN ==> Decimal("NaN") + a < b ==> Decimal("-1") + a == b ==> Decimal("0") + a > b ==> Decimal("1") + \end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{divide}{x, y} + Return \var{x} divided by \var{y}. +\end{methoddesc} + +\begin{methoddesc}{divmod}{x, y} + Divides two numbers and returns the integer part of the result. +\end{methoddesc} + +\begin{methoddesc}{max}{x, y} + Compare two values numerically and return the maximum. + + If they are numerically equal then the left-hand operand is chosen as the + result. +\end{methoddesc} + +\begin{methoddesc}{min}{x, y} + Compare two values numerically and return the minimum. + + If they are numerically equal then the left-hand operand is chosen as the + result. +\end{methoddesc} + +\begin{methoddesc}{minus}{x} + Minus corresponds to the unary prefix minus operator in Python. +\end{methoddesc} + +\begin{methoddesc}{multiply}{x, y} + Return the product of \var{x} and \var{y}. +\end{methoddesc} + +\begin{methoddesc}{normalize}{x} + Normalize reduces an operand to its simplest form. + + Essentially a \method{plus} operation with all trailing zeros removed from + the result. +\end{methoddesc} + +\begin{methoddesc}{plus}{x} + Plus corresponds to the unary prefix plus operator in Python. This + operation applies the context precision and rounding, so it is + \emph{not} an identity operation. +\end{methoddesc} + +\begin{methoddesc}{power}{x, y\optional{, modulo}} + Return \samp{x ** y} to the \var{modulo} if given. + + The right-hand operand must be a whole number whose integer part (after any + exponent has been applied) has no more than 9 digits and whose fractional + part (if any) is all zeros before any rounding. The operand may be positive, + negative, or zero; if negative, the absolute value of the power is used, and + the left-hand operand is inverted (divided into 1) before use. + + If the increased precision needed for the intermediate calculations exceeds + the capabilities of the implementation then an \constant{InvalidOperation} + condition is signaled. + + If, when raising to a negative power, an underflow occurs during the + division into 1, the operation is not halted at that point but continues. +\end{methoddesc} + +\begin{methoddesc}{quantize}{x, y} + Returns a value equal to \var{x} after rounding and having the exponent of + \var{y}. + + Unlike other operations, if the length of the coefficient after the quantize + operation would be greater than precision, then an + \constant{InvalidOperation} is signaled. This guarantees that, unless there + is an error condition, the quantized exponent is always equal to that of the + right-hand operand. + + Also unlike other operations, quantize never signals Underflow, even + if the result is subnormal and inexact. +\end{methoddesc} + +\begin{methoddesc}{remainder}{x, y} + Returns the remainder from integer division. + + The sign of the result, if non-zero, is the same as that of the original + dividend. +\end{methoddesc} + +\begin{methoddesc}{remainder_near}{x, y} + Computed the modulo as either a positive or negative value depending + on which is closest to zero. For instance, + \samp{Decimal(10).remainder_near(6)} returns \code{Decimal("-2")} + which is closer to zero than \code{Decimal("4")}. + + If both are equally close, the one chosen will have the same sign + as \var{self}. +\end{methoddesc} + +\begin{methoddesc}{same_quantum}{x, y} + Test whether \var{x} and \var{y} have the same exponent or whether both are + \constant{NaN}. +\end{methoddesc} + +\begin{methoddesc}{sqrt}{x} + Return the square root of \var{x} to full precision. +\end{methoddesc} + +\begin{methoddesc}{subtract}{x, y} + Return the difference between \var{x} and \var{y}. +\end{methoddesc} + +\begin{methoddesc}{to_eng_string}{} + Convert to engineering-type string. + + Engineering notation has an exponent which is a multiple of 3, so there + are up to 3 digits left of the decimal place. For example, converts + \code{Decimal('123E+1')} to \code{Decimal("1.23E+3")} +\end{methoddesc} + +\begin{methoddesc}{to_integral}{x} + Rounds to the nearest integer without signaling \constant{Inexact} + or \constant{Rounded}. +\end{methoddesc} + +\begin{methoddesc}{to_sci_string}{x} + Converts a number to a string using scientific notation. +\end{methoddesc} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Signals \label{decimal-signals}} + +Signals represent conditions that arise during computation. +Each corresponds to one context flag and one context trap enabler. + +The context flag is incremented whenever the condition is encountered. +After the computation, flags may be checked for informational +purposes (for instance, to determine whether a computation was exact). +After checking the flags, be sure to clear all flags before starting +the next computation. + +If the context's trap enabler is set for the signal, then the condition +causes a Python exception to be raised. For example, if the +\class{DivisionByZero} trap is set, then a \exception{DivisionByZero} +exception is raised upon encountering the condition. + + +\begin{classdesc*}{Clamped} + Altered an exponent to fit representation constraints. + + Typically, clamping occurs when an exponent falls outside the context's + \member{Emin} and \member{Emax} limits. If possible, the exponent is + reduced to fit by adding zeroes to the coefficient. +\end{classdesc*} + +\begin{classdesc*}{DecimalException} + Base class for other signals and a subclass of + \exception{ArithmeticError}. +\end{classdesc*} + +\begin{classdesc*}{DivisionByZero} + Signals the division of a non-infinite number by zero. + + Can occur with division, modulo division, or when raising a number to a + negative power. If this signal is not trapped, returns + \constant{Infinity} or \constant{-Infinity} with the sign determined by + the inputs to the calculation. +\end{classdesc*} + +\begin{classdesc*}{Inexact} + Indicates that rounding occurred and the result is not exact. + + Signals when non-zero digits were discarded during rounding. The rounded + result is returned. The signal flag or trap is used to detect when + results are inexact. +\end{classdesc*} + +\begin{classdesc*}{InvalidOperation} + An invalid operation was performed. + + Indicates that an operation was requested that does not make sense. + If not trapped, returns \constant{NaN}. Possible causes include: + + \begin{verbatim} + Infinity - Infinity + 0 * Infinity + Infinity / Infinity + x % 0 + Infinity % x + x._rescale( non-integer ) + sqrt(-x) and x > 0 + 0 ** 0 + x ** (non-integer) + x ** Infinity + \end{verbatim} +\end{classdesc*} + +\begin{classdesc*}{Overflow} + Numerical overflow. + + Indicates the exponent is larger than \member{Emax} after rounding has + occurred. If not trapped, the result depends on the rounding mode, either + pulling inward to the largest representable finite number or rounding + outward to \constant{Infinity}. In either case, \class{Inexact} and + \class{Rounded} are also signaled. +\end{classdesc*} + +\begin{classdesc*}{Rounded} + Rounding occurred though possibly no information was lost. + + Signaled whenever rounding discards digits; even if those digits are + zero (such as rounding \constant{5.00} to \constant{5.0}). If not + trapped, returns the result unchanged. This signal is used to detect + loss of significant digits. +\end{classdesc*} + +\begin{classdesc*}{Subnormal} + Exponent was lower than \member{Emin} prior to rounding. + + Occurs when an operation result is subnormal (the exponent is too small). + If not trapped, returns the result unchanged. +\end{classdesc*} + +\begin{classdesc*}{Underflow} + Numerical underflow with result rounded to zero. + + Occurs when a subnormal result is pushed to zero by rounding. + \class{Inexact} and \class{Subnormal} are also signaled. +\end{classdesc*} + +The following table summarizes the hierarchy of signals: + +\begin{verbatim} + exceptions.ArithmeticError(exceptions.StandardError) + DecimalException + Clamped + DivisionByZero(DecimalException, exceptions.ZeroDivisionError) + Inexact + Overflow(Inexact, Rounded) + Underflow(Inexact, Rounded, Subnormal) + InvalidOperation + Rounded + Subnormal +\end{verbatim} + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Floating Point Notes \label{decimal-notes}} + +\subsubsection{Mitigating round-off error with increased precision} + +The use of decimal floating point eliminates decimal representation error +(making it possible to represent \constant{0.1} exactly); however, some +operations can still incur round-off error when non-zero digits exceed the +fixed precision. + +The effects of round-off error can be amplified by the addition or subtraction +of nearly offsetting quantities resulting in loss of significance. Knuth +provides two instructive examples where rounded floating point arithmetic with +insufficient precision causes the breakdown of the associative and +distributive properties of addition: + +\begin{verbatim} +# Examples from Seminumerical Algorithms, Section 4.2.2. +>>> from decimal import Decimal, getcontext +>>> getcontext().prec = 8 + +>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111') +>>> (u + v) + w +Decimal("9.5111111") +>>> u + (v + w) +Decimal("10") + +>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003') +>>> (u*v) + (u*w) +Decimal("0.01") +>>> u * (v+w) +Decimal("0.0060000") +\end{verbatim} + +The \module{decimal} module makes it possible to restore the identities +by expanding the precision sufficiently to avoid loss of significance: + +\begin{verbatim} +>>> getcontext().prec = 20 +>>> u, v, w = Decimal(11111113), Decimal(-11111111), Decimal('7.51111111') +>>> (u + v) + w +Decimal("9.51111111") +>>> u + (v + w) +Decimal("9.51111111") +>>> +>>> u, v, w = Decimal(20000), Decimal(-6), Decimal('6.0000003') +>>> (u*v) + (u*w) +Decimal("0.0060000") +>>> u * (v+w) +Decimal("0.0060000") +\end{verbatim} + +\subsubsection{Special values} + +The number system for the \module{decimal} module provides special +values including \constant{NaN}, \constant{sNaN}, \constant{-Infinity}, +\constant{Infinity}, and two zeroes, \constant{+0} and \constant{-0}. + +Infinities can be constructed directly with: \code{Decimal('Infinity')}. Also, +they can arise from dividing by zero when the \exception{DivisionByZero} +signal is not trapped. Likewise, when the \exception{Overflow} signal is not +trapped, infinity can result from rounding beyond the limits of the largest +representable number. + +The infinities are signed (affine) and can be used in arithmetic operations +where they get treated as very large, indeterminate numbers. For instance, +adding a constant to infinity gives another infinite result. + +Some operations are indeterminate and return \constant{NaN}, or if the +\exception{InvalidOperation} signal is trapped, raise an exception. For +example, \code{0/0} returns \constant{NaN} which means ``not a number''. This +variety of \constant{NaN} is quiet and, once created, will flow through other +computations always resulting in another \constant{NaN}. This behavior can be +useful for a series of computations that occasionally have missing inputs --- +it allows the calculation to proceed while flagging specific results as +invalid. + +A variant is \constant{sNaN} which signals rather than remaining quiet +after every operation. This is a useful return value when an invalid +result needs to interrupt a calculation for special handling. + +The signed zeros can result from calculations that underflow. +They keep the sign that would have resulted if the calculation had +been carried out to greater precision. Since their magnitude is +zero, both positive and negative zeros are treated as equal and their +sign is informational. + +In addition to the two signed zeros which are distinct yet equal, +there are various representations of zero with differing precisions +yet equivalent in value. This takes a bit of getting used to. For +an eye accustomed to normalized floating point representations, it +is not immediately obvious that the following calculation returns +a value equal to zero: + +\begin{verbatim} +>>> 1 / Decimal('Infinity') +Decimal("0E-1000000026") +\end{verbatim} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Working with threads \label{decimal-threads}} + +The \function{getcontext()} function accesses a different \class{Context} +object for each thread. Having separate thread contexts means that threads +may make changes (such as \code{getcontext.prec=10}) without interfering with +other threads. + +Likewise, the \function{setcontext()} function automatically assigns its target +to the current thread. + +If \function{setcontext()} has not been called before \function{getcontext()}, +then \function{getcontext()} will automatically create a new context for use +in the current thread. + +The new context is copied from a prototype context called +\var{DefaultContext}. To control the defaults so that each thread will use the +same values throughout the application, directly modify the +\var{DefaultContext} object. This should be done \emph{before} any threads are +started so that there won't be a race condition between threads calling +\function{getcontext()}. For example: + +\begin{verbatim} +# Set applicationwide defaults for all threads about to be launched +DefaultContext.prec = 12 +DefaultContext.rounding = ROUND_DOWN +DefaultContext.traps = ExtendedContext.traps.copy() +DefaultContext.traps[InvalidOperation] = 1 +setcontext(DefaultContext) + +# Afterwards, the threads can be started +t1.start() +t2.start() +t3.start() + . . . +\end{verbatim} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Recipes \label{decimal-recipes}} + +Here are a few recipes that serve as utility functions and that demonstrate +ways to work with the \class{Decimal} class: + +\begin{verbatim} +def moneyfmt(value, places=2, curr='', sep=',', dp='.', + pos='', neg='-', trailneg=''): + """Convert Decimal to a money formatted string. + + places: required number of places after the decimal point + curr: optional currency symbol before the sign (may be blank) + sep: optional grouping separator (comma, period, space, or blank) + dp: decimal point indicator (comma or period) + only specify as blank when places is zero + pos: optional sign for positive numbers: '+', space or blank + neg: optional sign for negative numbers: '-', '(', space or blank + trailneg:optional trailing minus indicator: '-', ')', space or blank + + >>> d = Decimal('-1234567.8901') + >>> moneyfmt(d, curr='$') + '-$1,234,567.89' + >>> moneyfmt(d, places=0, sep='.', dp='', neg='', trailneg='-') + '1.234.568-' + >>> moneyfmt(d, curr='$', neg='(', trailneg=')') + '($1,234,567.89)' + >>> moneyfmt(Decimal(123456789), sep=' ') + '123 456 789.00' + >>> moneyfmt(Decimal('-0.02'), neg='<', trailneg='>') + '<.02>' + + """ + q = Decimal((0, (1,), -places)) # 2 places --> '0.01' + sign, digits, exp = value.quantize(q).as_tuple() + assert exp == -places + result = [] + digits = map(str, digits) + build, next = result.append, digits.pop + if sign: + build(trailneg) + for i in range(places): + if digits: + build(next()) + else: + build('0') + build(dp) + i = 0 + while digits: + build(next()) + i += 1 + if i == 3 and digits: + i = 0 + build(sep) + build(curr) + if sign: + build(neg) + else: + build(pos) + result.reverse() + return ''.join(result) + +def pi(): + """Compute Pi to the current precision. + + >>> print pi() + 3.141592653589793238462643383 + + """ + getcontext().prec += 2 # extra digits for intermediate steps + three = Decimal(3) # substitute "three=3.0" for regular floats + lasts, t, s, n, na, d, da = 0, three, 3, 1, 0, 0, 24 + while s != lasts: + lasts = s + n, na = n+na, na+8 + d, da = d+da, da+32 + t = (t * n) / d + s += t + getcontext().prec -= 2 + return +s # unary plus applies the new precision + +def exp(x): + """Return e raised to the power of x. Result type matches input type. + + >>> print exp(Decimal(1)) + 2.718281828459045235360287471 + >>> print exp(Decimal(2)) + 7.389056098930650227230427461 + >>> print exp(2.0) + 7.38905609893 + >>> print exp(2+0j) + (7.38905609893+0j) + + """ + getcontext().prec += 2 + i, lasts, s, fact, num = 0, 0, 1, 1, 1 + while s != lasts: + lasts = s + i += 1 + fact *= i + num *= x + s += num / fact + getcontext().prec -= 2 + return +s + +def cos(x): + """Return the cosine of x as measured in radians. + + >>> print cos(Decimal('0.5')) + 0.8775825618903727161162815826 + >>> print cos(0.5) + 0.87758256189 + >>> print cos(0.5+0j) + (0.87758256189+0j) + + """ + getcontext().prec += 2 + i, lasts, s, fact, num, sign = 0, 0, 1, 1, 1, 1 + while s != lasts: + lasts = s + i += 2 + fact *= i * (i-1) + num *= x * x + sign *= -1 + s += num / fact * sign + getcontext().prec -= 2 + return +s + +def sin(x): + """Return the sine of x as measured in radians. + + >>> print sin(Decimal('0.5')) + 0.4794255386042030002732879352 + >>> print sin(0.5) + 0.479425538604 + >>> print sin(0.5+0j) + (0.479425538604+0j) + + """ + getcontext().prec += 2 + i, lasts, s, fact, num, sign = 1, 0, x, 1, x, 1 + while s != lasts: + lasts = s + i += 2 + fact *= i * (i-1) + num *= x * x + sign *= -1 + s += num / fact * sign + getcontext().prec -= 2 + return +s + +\end{verbatim} + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\subsection{Decimal FAQ \label{decimal-faq}} + +Q. It is cumbersome to type \code{decimal.Decimal('1234.5')}. Is there a way +to minimize typing when using the interactive interpreter? + +A. Some users abbreviate the constructor to just a single letter: + +\begin{verbatim} +>>> D = decimal.Decimal +>>> D('1.23') + D('3.45') +Decimal("4.68") +\end{verbatim} + + +Q. In a fixed-point application with two decimal places, some inputs +have many places and need to be rounded. Others are not supposed to have +excess digits and need to be validated. What methods should be used? + +A. The \method{quantize()} method rounds to a fixed number of decimal places. +If the \constant{Inexact} trap is set, it is also useful for validation: + +\begin{verbatim} +>>> TWOPLACES = Decimal(10) ** -2 # same as Decimal('0.01') + +>>> # Round to two places +>>> Decimal("3.214").quantize(TWOPLACES) +Decimal("3.21") + +>>> # Validate that a number does not exceed two places +>>> Decimal("3.21").quantize(TWOPLACES, context=Context(traps=[Inexact])) +Decimal("3.21") + +>>> Decimal("3.214").quantize(TWOPLACES, context=Context(traps=[Inexact])) +Traceback (most recent call last): + ... +Inexact: Changed in rounding +\end{verbatim} + + +Q. Once I have valid two place inputs, how do I maintain that invariant +throughout an application? + +A. Some operations like addition and subtraction automatically preserve fixed +point. Others, like multiplication and division, change the number of decimal +places and need to be followed-up with a \method{quantize()} step. + + +Q. There are many ways to express the same value. The numbers +\constant{200}, \constant{200.000}, \constant{2E2}, and \constant{.02E+4} all +have the same value at various precisions. Is there a way to transform them to +a single recognizable canonical value? + +A. The \method{normalize()} method maps all equivalent values to a single +representative: + +\begin{verbatim} +>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split()) +>>> [v.normalize() for v in values] +[Decimal("2E+2"), Decimal("2E+2"), Decimal("2E+2"), Decimal("2E+2")] +\end{verbatim} + + +Q. Some decimal values always print with exponential notation. Is there +a way to get a non-exponential representation? + +A. For some values, exponential notation is the only way to express +the number of significant places in the coefficient. For example, +expressing \constant{5.0E+3} as \constant{5000} keeps the value +constant but cannot show the original's two-place significance. + + +Q. Is there a way to convert a regular float to a \class{Decimal}? + +A. Yes, all binary floating point numbers can be exactly expressed as a +Decimal. An exact conversion may take more precision than intuition would +suggest, so trapping \constant{Inexact} will signal a need for more precision: + +\begin{verbatim} +def floatToDecimal(f): + "Convert a floating point number to a Decimal with no loss of information" + # Transform (exactly) a float to a mantissa (0.5 <= abs(m) < 1.0) and an + # exponent. Double the mantissa until it is an integer. Use the integer + # mantissa and exponent to compute an equivalent Decimal. If this cannot + # be done exactly, then retry with more precision. + + mantissa, exponent = math.frexp(f) + while mantissa != int(mantissa): + mantissa *= 2.0 + exponent -= 1 + mantissa = int(mantissa) + + oldcontext = getcontext() + setcontext(Context(traps=[Inexact])) + try: + while True: + try: + return mantissa * Decimal(2) ** exponent + except Inexact: + getcontext().prec += 1 + finally: + setcontext(oldcontext) +\end{verbatim} + + +Q. Why isn't the \function{floatToDecimal()} routine included in the module? + +A. There is some question about whether it is advisable to mix binary and +decimal floating point. Also, its use requires some care to avoid the +representation issues associated with binary floating point: + +\begin{verbatim} +>>> floatToDecimal(1.1) +Decimal("1.100000000000000088817841970012523233890533447265625") +\end{verbatim} + + +Q. Within a complex calculation, how can I make sure that I haven't gotten a +spurious result because of insufficient precision or rounding anomalies. + +A. The decimal module makes it easy to test results. A best practice is to +re-run calculations using greater precision and with various rounding modes. +Widely differing results indicate insufficient precision, rounding mode +issues, ill-conditioned inputs, or a numerically unstable algorithm. + + +Q. I noticed that context precision is applied to the results of operations +but not to the inputs. Is there anything to watch out for when mixing +values of different precisions? + +A. Yes. The principle is that all values are considered to be exact and so +is the arithmetic on those values. Only the results are rounded. The +advantage for inputs is that ``what you type is what you get''. A +disadvantage is that the results can look odd if you forget that the inputs +haven't been rounded: + +\begin{verbatim} +>>> getcontext().prec = 3 +>>> Decimal('3.104') + D('2.104') +Decimal("5.21") +>>> Decimal('3.104') + D('0.000') + D('2.104') +Decimal("5.20") +\end{verbatim} + +The solution is either to increase precision or to force rounding of inputs +using the unary plus operation: + +\begin{verbatim} +>>> getcontext().prec = 3 +>>> +Decimal('1.23456789') # unary plus triggers rounding +Decimal("1.23") +\end{verbatim} + +Alternatively, inputs can be rounded upon creation using the +\method{Context.create_decimal()} method: + +\begin{verbatim} +>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678') +Decimal("1.2345") +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libdifflib.tex b/sys/src/cmd/python/Doc/lib/libdifflib.tex new file mode 100644 index 000000000..acb5ed1c3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdifflib.tex @@ -0,0 +1,704 @@ +\section{\module{difflib} --- + Helpers for computing deltas} + +\declaremodule{standard}{difflib} +\modulesynopsis{Helpers for computing differences between objects.} +\moduleauthor{Tim Peters}{tim_one@users.sourceforge.net} +\sectionauthor{Tim Peters}{tim_one@users.sourceforge.net} +% LaTeXification by Fred L. Drake, Jr. . + +\versionadded{2.1} + + +\begin{classdesc*}{SequenceMatcher} + This is a flexible class for comparing pairs of sequences of any + type, so long as the sequence elements are hashable. The basic + algorithm predates, and is a little fancier than, an algorithm + published in the late 1980's by Ratcliff and Obershelp under the + hyperbolic name ``gestalt pattern matching.'' The idea is to find + the longest contiguous matching subsequence that contains no + ``junk'' elements (the Ratcliff and Obershelp algorithm doesn't + address junk). The same idea is then applied recursively to the + pieces of the sequences to the left and to the right of the matching + subsequence. This does not yield minimal edit sequences, but does + tend to yield matches that ``look right'' to people. + + \strong{Timing:} The basic Ratcliff-Obershelp algorithm is cubic + time in the worst case and quadratic time in the expected case. + \class{SequenceMatcher} is quadratic time for the worst case and has + expected-case behavior dependent in a complicated way on how many + elements the sequences have in common; best case time is linear. +\end{classdesc*} + +\begin{classdesc*}{Differ} + This is a class for comparing sequences of lines of text, and + producing human-readable differences or deltas. Differ uses + \class{SequenceMatcher} both to compare sequences of lines, and to + compare sequences of characters within similar (near-matching) + lines. + + Each line of a \class{Differ} delta begins with a two-letter code: + +\begin{tableii}{l|l}{code}{Code}{Meaning} + \lineii{'- '}{line unique to sequence 1} + \lineii{'+ '}{line unique to sequence 2} + \lineii{' '}{line common to both sequences} + \lineii{'? '}{line not present in either input sequence} +\end{tableii} + + Lines beginning with `\code{?~}' attempt to guide the eye to + intraline differences, and were not present in either input + sequence. These lines can be confusing if the sequences contain tab + characters. +\end{classdesc*} + +\begin{classdesc*}{HtmlDiff} + + This class can be used to create an HTML table (or a complete HTML file + containing the table) showing a side by side, line by line comparison + of text with inter-line and intra-line change highlights. The table can + be generated in either full or contextual difference mode. + + The constructor for this class is: + + \begin{funcdesc}{__init__}{\optional{tabsize}\optional{, + wrapcolumn}\optional{, linejunk}\optional{, charjunk}} + + Initializes instance of \class{HtmlDiff}. + + \var{tabsize} is an optional keyword argument to specify tab stop spacing + and defaults to \code{8}. + + \var{wrapcolumn} is an optional keyword to specify column number where + lines are broken and wrapped, defaults to \code{None} where lines are not + wrapped. + + \var{linejunk} and \var{charjunk} are optional keyword arguments passed + into \code{ndiff()} (used by \class{HtmlDiff} to generate the + side by side HTML differences). See \code{ndiff()} documentation for + argument default values and descriptions. + + \end{funcdesc} + + The following methods are public: + + \begin{funcdesc}{make_file}{fromlines, tolines + \optional{, fromdesc}\optional{, todesc}\optional{, context}\optional{, + numlines}} + Compares \var{fromlines} and \var{tolines} (lists of strings) and returns + a string which is a complete HTML file containing a table showing line by + line differences with inter-line and intra-line changes highlighted. + + \var{fromdesc} and \var{todesc} are optional keyword arguments to specify + from/to file column header strings (both default to an empty string). + + \var{context} and \var{numlines} are both optional keyword arguments. + Set \var{context} to \code{True} when contextual differences are to be + shown, else the default is \code{False} to show the full files. + \var{numlines} defaults to \code{5}. When \var{context} is \code{True} + \var{numlines} controls the number of context lines which surround the + difference highlights. When \var{context} is \code{False} \var{numlines} + controls the number of lines which are shown before a difference + highlight when using the "next" hyperlinks (setting to zero would cause + the "next" hyperlinks to place the next difference highlight at the top of + the browser without any leading context). + \end{funcdesc} + + \begin{funcdesc}{make_table}{fromlines, tolines + \optional{, fromdesc}\optional{, todesc}\optional{, context}\optional{, + numlines}} + Compares \var{fromlines} and \var{tolines} (lists of strings) and returns + a string which is a complete HTML table showing line by line differences + with inter-line and intra-line changes highlighted. + + The arguments for this method are the same as those for the + \method{make_file()} method. + \end{funcdesc} + + \file{Tools/scripts/diff.py} is a command-line front-end to this class + and contains a good example of its use. + + \versionadded{2.4} +\end{classdesc*} + +\begin{funcdesc}{context_diff}{a, b\optional{, fromfile}\optional{, + tofile}\optional{, fromfiledate}\optional{, tofiledate}\optional{, + n}\optional{, lineterm}} + Compare \var{a} and \var{b} (lists of strings); return a + delta (a generator generating the delta lines) in context diff + format. + + Context diffs are a compact way of showing just the lines that have + changed plus a few lines of context. The changes are shown in a + before/after style. The number of context lines is set by \var{n} + which defaults to three. + + By default, the diff control lines (those with \code{***} or \code{---}) + are created with a trailing newline. This is helpful so that inputs created + from \function{file.readlines()} result in diffs that are suitable for use + with \function{file.writelines()} since both the inputs and outputs have + trailing newlines. + + For inputs that do not have trailing newlines, set the \var{lineterm} + argument to \code{""} so that the output will be uniformly newline free. + + The context diff format normally has a header for filenames and + modification times. Any or all of these may be specified using strings for + \var{fromfile}, \var{tofile}, \var{fromfiledate}, and \var{tofiledate}. + The modification times are normally expressed in the format returned by + \function{time.ctime()}. If not specified, the strings default to blanks. + + \file{Tools/scripts/diff.py} is a command-line front-end for this + function. + + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{get_close_matches}{word, possibilities\optional{, + n}\optional{, cutoff}} + Return a list of the best ``good enough'' matches. \var{word} is a + sequence for which close matches are desired (typically a string), + and \var{possibilities} is a list of sequences against which to + match \var{word} (typically a list of strings). + + Optional argument \var{n} (default \code{3}) is the maximum number + of close matches to return; \var{n} must be greater than \code{0}. + + Optional argument \var{cutoff} (default \code{0.6}) is a float in + the range [0, 1]. Possibilities that don't score at least that + similar to \var{word} are ignored. + + The best (no more than \var{n}) matches among the possibilities are + returned in a list, sorted by similarity score, most similar first. + +\begin{verbatim} +>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy']) +['apple', 'ape'] +>>> import keyword +>>> get_close_matches('wheel', keyword.kwlist) +['while'] +>>> get_close_matches('apple', keyword.kwlist) +[] +>>> get_close_matches('accept', keyword.kwlist) +['except'] +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{ndiff}{a, b\optional{, linejunk}\optional{, charjunk}} + Compare \var{a} and \var{b} (lists of strings); return a + \class{Differ}-style delta (a generator generating the delta lines). + + Optional keyword parameters \var{linejunk} and \var{charjunk} are + for filter functions (or \code{None}): + + \var{linejunk}: A function that accepts a single string + argument, and returns true if the string is junk, or false if not. + The default is (\code{None}), starting with Python 2.3. Before then, + the default was the module-level function + \function{IS_LINE_JUNK()}, which filters out lines without visible + characters, except for at most one pound character (\character{\#}). + As of Python 2.3, the underlying \class{SequenceMatcher} class + does a dynamic analysis of which lines are so frequent as to + constitute noise, and this usually works better than the pre-2.3 + default. + + \var{charjunk}: A function that accepts a character (a string of + length 1), and returns if the character is junk, or false if not. + The default is module-level function \function{IS_CHARACTER_JUNK()}, + which filters out whitespace characters (a blank or tab; note: bad + idea to include newline in this!). + + \file{Tools/scripts/ndiff.py} is a command-line front-end to this + function. + +\begin{verbatim} +>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1), +... 'ore\ntree\nemu\n'.splitlines(1)) +>>> print ''.join(diff), +- one +? ^ ++ ore +? ^ +- two +- three +? - ++ tree ++ emu +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{restore}{sequence, which} + Return one of the two sequences that generated a delta. + + Given a \var{sequence} produced by \method{Differ.compare()} or + \function{ndiff()}, extract lines originating from file 1 or 2 + (parameter \var{which}), stripping off line prefixes. + + Example: + +\begin{verbatim} +>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(1), +... 'ore\ntree\nemu\n'.splitlines(1)) +>>> diff = list(diff) # materialize the generated delta into a list +>>> print ''.join(restore(diff, 1)), +one +two +three +>>> print ''.join(restore(diff, 2)), +ore +tree +emu +\end{verbatim} + +\end{funcdesc} + +\begin{funcdesc}{unified_diff}{a, b\optional{, fromfile}\optional{, + tofile}\optional{, fromfiledate}\optional{, tofiledate}\optional{, + n}\optional{, lineterm}} + Compare \var{a} and \var{b} (lists of strings); return a + delta (a generator generating the delta lines) in unified diff + format. + + Unified diffs are a compact way of showing just the lines that have + changed plus a few lines of context. The changes are shown in a + inline style (instead of separate before/after blocks). The number + of context lines is set by \var{n} which defaults to three. + + By default, the diff control lines (those with \code{---}, \code{+++}, + or \code{@@}) are created with a trailing newline. This is helpful so + that inputs created from \function{file.readlines()} result in diffs + that are suitable for use with \function{file.writelines()} since both + the inputs and outputs have trailing newlines. + + For inputs that do not have trailing newlines, set the \var{lineterm} + argument to \code{""} so that the output will be uniformly newline free. + + The context diff format normally has a header for filenames and + modification times. Any or all of these may be specified using strings for + \var{fromfile}, \var{tofile}, \var{fromfiledate}, and \var{tofiledate}. + The modification times are normally expressed in the format returned by + \function{time.ctime()}. If not specified, the strings default to blanks. + + \file{Tools/scripts/diff.py} is a command-line front-end for this + function. + + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{IS_LINE_JUNK}{line} + Return true for ignorable lines. The line \var{line} is ignorable + if \var{line} is blank or contains a single \character{\#}, + otherwise it is not ignorable. Used as a default for parameter + \var{linejunk} in \function{ndiff()} before Python 2.3. +\end{funcdesc} + + +\begin{funcdesc}{IS_CHARACTER_JUNK}{ch} + Return true for ignorable characters. The character \var{ch} is + ignorable if \var{ch} is a space or tab, otherwise it is not + ignorable. Used as a default for parameter \var{charjunk} in + \function{ndiff()}. +\end{funcdesc} + + +\begin{seealso} + \seetitle[http://www.ddj.com/documents/s=1103/ddj8807c/] + {Pattern Matching: The Gestalt Approach}{Discussion of a + similar algorithm by John W. Ratcliff and D. E. Metzener. + This was published in + \citetitle[http://www.ddj.com/]{Dr. Dobb's Journal} in + July, 1988.} +\end{seealso} + + +\subsection{SequenceMatcher Objects \label{sequence-matcher}} + +The \class{SequenceMatcher} class has this constructor: + +\begin{classdesc}{SequenceMatcher}{\optional{isjunk\optional{, + a\optional{, b}}}} + Optional argument \var{isjunk} must be \code{None} (the default) or + a one-argument function that takes a sequence element and returns + true if and only if the element is ``junk'' and should be ignored. + Passing \code{None} for \var{isjunk} is equivalent to passing + \code{lambda x: 0}; in other words, no elements are ignored. For + example, pass: + +\begin{verbatim} +lambda x: x in " \t" +\end{verbatim} + + if you're comparing lines as sequences of characters, and don't want + to synch up on blanks or hard tabs. + + The optional arguments \var{a} and \var{b} are sequences to be + compared; both default to empty strings. The elements of both + sequences must be hashable. +\end{classdesc} + + +\class{SequenceMatcher} objects have the following methods: + +\begin{methoddesc}{set_seqs}{a, b} + Set the two sequences to be compared. +\end{methoddesc} + +\class{SequenceMatcher} computes and caches detailed information about +the second sequence, so if you want to compare one sequence against +many sequences, use \method{set_seq2()} to set the commonly used +sequence once and call \method{set_seq1()} repeatedly, once for each +of the other sequences. + +\begin{methoddesc}{set_seq1}{a} + Set the first sequence to be compared. The second sequence to be + compared is not changed. +\end{methoddesc} + +\begin{methoddesc}{set_seq2}{b} + Set the second sequence to be compared. The first sequence to be + compared is not changed. +\end{methoddesc} + +\begin{methoddesc}{find_longest_match}{alo, ahi, blo, bhi} + Find longest matching block in \code{\var{a}[\var{alo}:\var{ahi}]} + and \code{\var{b}[\var{blo}:\var{bhi}]}. + + If \var{isjunk} was omitted or \code{None}, + \method{get_longest_match()} returns \code{(\var{i}, \var{j}, + \var{k})} such that \code{\var{a}[\var{i}:\var{i}+\var{k}]} is equal + to \code{\var{b}[\var{j}:\var{j}+\var{k}]}, where + \code{\var{alo} <= \var{i} <= \var{i}+\var{k} <= \var{ahi}} and + \code{\var{blo} <= \var{j} <= \var{j}+\var{k} <= \var{bhi}}. + For all \code{(\var{i'}, \var{j'}, \var{k'})} meeting those + conditions, the additional conditions + \code{\var{k} >= \var{k'}}, + \code{\var{i} <= \var{i'}}, + and if \code{\var{i} == \var{i'}}, \code{\var{j} <= \var{j'}} + are also met. + In other words, of all maximal matching blocks, return one that + starts earliest in \var{a}, and of all those maximal matching blocks + that start earliest in \var{a}, return the one that starts earliest + in \var{b}. + +\begin{verbatim} +>>> s = SequenceMatcher(None, " abcd", "abcd abcd") +>>> s.find_longest_match(0, 5, 0, 9) +(0, 4, 5) +\end{verbatim} + + If \var{isjunk} was provided, first the longest matching block is + determined as above, but with the additional restriction that no + junk element appears in the block. Then that block is extended as + far as possible by matching (only) junk elements on both sides. + So the resulting block never matches on junk except as identical + junk happens to be adjacent to an interesting match. + + Here's the same example as before, but considering blanks to be junk. + That prevents \code{' abcd'} from matching the \code{' abcd'} at the + tail end of the second sequence directly. Instead only the + \code{'abcd'} can match, and matches the leftmost \code{'abcd'} in + the second sequence: + +\begin{verbatim} +>>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd") +>>> s.find_longest_match(0, 5, 0, 9) +(1, 0, 4) +\end{verbatim} + + If no blocks match, this returns \code{(\var{alo}, \var{blo}, 0)}. +\end{methoddesc} + +\begin{methoddesc}{get_matching_blocks}{} + Return list of triples describing matching subsequences. + Each triple is of the form \code{(\var{i}, \var{j}, \var{n})}, and + means that \code{\var{a}[\var{i}:\var{i}+\var{n}] == + \var{b}[\var{j}:\var{j}+\var{n}]}. The triples are monotonically + increasing in \var{i} and \var{j}. + + The last triple is a dummy, and has the value \code{(len(\var{a}), + len(\var{b}), 0)}. It is the only triple with \code{\var{n} == 0}. + % Explain why a dummy is used! + + If + \code{(\var{i}, \var{j}, \var{n})} and + \code{(\var{i'}, \var{j'}, \var{n'})} are adjacent triples in the list, + and the second is not the last triple in the list, then + \code{\var{i}+\var{n} != \var{i'}} or + \code{\var{j}+\var{n} != \var{j'}}; in other words, adjacent triples + always describe non-adjacent equal blocks. + \versionchanged[The guarantee that adjacent triples always describe + non-adjacent blocks was implemented]{2.5} + +\begin{verbatim} +>>> s = SequenceMatcher(None, "abxcd", "abcd") +>>> s.get_matching_blocks() +[(0, 0, 2), (3, 2, 2), (5, 4, 0)] +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{get_opcodes}{} + Return list of 5-tuples describing how to turn \var{a} into \var{b}. + Each tuple is of the form \code{(\var{tag}, \var{i1}, \var{i2}, + \var{j1}, \var{j2})}. The first tuple has \code{\var{i1} == + \var{j1} == 0}, and remaining tuples have \var{i1} equal to the + \var{i2} from the preceding tuple, and, likewise, \var{j1} equal to + the previous \var{j2}. + + The \var{tag} values are strings, with these meanings: + +\begin{tableii}{l|l}{code}{Value}{Meaning} + \lineii{'replace'}{\code{\var{a}[\var{i1}:\var{i2}]} should be + replaced by \code{\var{b}[\var{j1}:\var{j2}]}.} + \lineii{'delete'}{\code{\var{a}[\var{i1}:\var{i2}]} should be + deleted. Note that \code{\var{j1} == \var{j2}} in + this case.} + \lineii{'insert'}{\code{\var{b}[\var{j1}:\var{j2}]} should be + inserted at \code{\var{a}[\var{i1}:\var{i1}]}. + Note that \code{\var{i1} == \var{i2}} in this + case.} + \lineii{'equal'}{\code{\var{a}[\var{i1}:\var{i2}] == + \var{b}[\var{j1}:\var{j2}]} (the sub-sequences are + equal).} +\end{tableii} + +For example: + +\begin{verbatim} +>>> a = "qabxcd" +>>> b = "abycdf" +>>> s = SequenceMatcher(None, a, b) +>>> for tag, i1, i2, j1, j2 in s.get_opcodes(): +... print ("%7s a[%d:%d] (%s) b[%d:%d] (%s)" % +... (tag, i1, i2, a[i1:i2], j1, j2, b[j1:j2])) + delete a[0:1] (q) b[0:0] () + equal a[1:3] (ab) b[0:2] (ab) +replace a[3:4] (x) b[2:3] (y) + equal a[4:6] (cd) b[3:5] (cd) + insert a[6:6] () b[5:6] (f) +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{get_grouped_opcodes}{\optional{n}} + Return a generator of groups with up to \var{n} lines of context. + + Starting with the groups returned by \method{get_opcodes()}, + this method splits out smaller change clusters and eliminates + intervening ranges which have no changes. + + The groups are returned in the same format as \method{get_opcodes()}. + \versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}{ratio}{} + Return a measure of the sequences' similarity as a float in the + range [0, 1]. + + Where T is the total number of elements in both sequences, and M is + the number of matches, this is 2.0*M / T. Note that this is + \code{1.0} if the sequences are identical, and \code{0.0} if they + have nothing in common. + + This is expensive to compute if \method{get_matching_blocks()} or + \method{get_opcodes()} hasn't already been called, in which case you + may want to try \method{quick_ratio()} or + \method{real_quick_ratio()} first to get an upper bound. +\end{methoddesc} + +\begin{methoddesc}{quick_ratio}{} + Return an upper bound on \method{ratio()} relatively quickly. + + This isn't defined beyond that it is an upper bound on + \method{ratio()}, and is faster to compute. +\end{methoddesc} + +\begin{methoddesc}{real_quick_ratio}{} + Return an upper bound on \method{ratio()} very quickly. + + This isn't defined beyond that it is an upper bound on + \method{ratio()}, and is faster to compute than either + \method{ratio()} or \method{quick_ratio()}. +\end{methoddesc} + +The three methods that return the ratio of matching to total characters +can give different results due to differing levels of approximation, +although \method{quick_ratio()} and \method{real_quick_ratio()} are always +at least as large as \method{ratio()}: + +\begin{verbatim} +>>> s = SequenceMatcher(None, "abcd", "bcde") +>>> s.ratio() +0.75 +>>> s.quick_ratio() +0.75 +>>> s.real_quick_ratio() +1.0 +\end{verbatim} + + +\subsection{SequenceMatcher Examples \label{sequencematcher-examples}} + + +This example compares two strings, considering blanks to be ``junk:'' + +\begin{verbatim} +>>> s = SequenceMatcher(lambda x: x == " ", +... "private Thread currentThread;", +... "private volatile Thread currentThread;") +\end{verbatim} + +\method{ratio()} returns a float in [0, 1], measuring the similarity +of the sequences. As a rule of thumb, a \method{ratio()} value over +0.6 means the sequences are close matches: + +\begin{verbatim} +>>> print round(s.ratio(), 3) +0.866 +\end{verbatim} + +If you're only interested in where the sequences match, +\method{get_matching_blocks()} is handy: + +\begin{verbatim} +>>> for block in s.get_matching_blocks(): +... print "a[%d] and b[%d] match for %d elements" % block +a[0] and b[0] match for 8 elements +a[8] and b[17] match for 6 elements +a[14] and b[23] match for 15 elements +a[29] and b[38] match for 0 elements +\end{verbatim} + +Note that the last tuple returned by \method{get_matching_blocks()} is +always a dummy, \code{(len(\var{a}), len(\var{b}), 0)}, and this is +the only case in which the last tuple element (number of elements +matched) is \code{0}. + +If you want to know how to change the first sequence into the second, +use \method{get_opcodes()}: + +\begin{verbatim} +>>> for opcode in s.get_opcodes(): +... print "%6s a[%d:%d] b[%d:%d]" % opcode + equal a[0:8] b[0:8] +insert a[8:8] b[8:17] + equal a[8:14] b[17:23] + equal a[14:29] b[23:38] +\end{verbatim} + +See also the function \function{get_close_matches()} in this module, +which shows how simple code building on \class{SequenceMatcher} can be +used to do useful work. + + +\subsection{Differ Objects \label{differ-objects}} + +Note that \class{Differ}-generated deltas make no claim to be +\strong{minimal} diffs. To the contrary, minimal diffs are often +counter-intuitive, because they synch up anywhere possible, sometimes +accidental matches 100 pages apart. Restricting synch points to +contiguous matches preserves some notion of locality, at the +occasional cost of producing a longer diff. + +The \class{Differ} class has this constructor: + +\begin{classdesc}{Differ}{\optional{linejunk\optional{, charjunk}}} + Optional keyword parameters \var{linejunk} and \var{charjunk} are + for filter functions (or \code{None}): + + \var{linejunk}: A function that accepts a single string + argument, and returns true if the string is junk. The default is + \code{None}, meaning that no line is considered junk. + + \var{charjunk}: A function that accepts a single character argument + (a string of length 1), and returns true if the character is junk. + The default is \code{None}, meaning that no character is + considered junk. +\end{classdesc} + +\class{Differ} objects are used (deltas generated) via a single +method: + +\begin{methoddesc}{compare}{a, b} + Compare two sequences of lines, and generate the delta (a sequence + of lines). + + Each sequence must contain individual single-line strings ending + with newlines. Such sequences can be obtained from the + \method{readlines()} method of file-like objects. The delta generated + also consists of newline-terminated strings, ready to be printed as-is + via the \method{writelines()} method of a file-like object. +\end{methoddesc} + + +\subsection{Differ Example \label{differ-examples}} + +This example compares two texts. First we set up the texts, sequences +of individual single-line strings ending with newlines (such sequences +can also be obtained from the \method{readlines()} method of file-like +objects): + +\begin{verbatim} +>>> text1 = ''' 1. Beautiful is better than ugly. +... 2. Explicit is better than implicit. +... 3. Simple is better than complex. +... 4. Complex is better than complicated. +... '''.splitlines(1) +>>> len(text1) +4 +>>> text1[0][-1] +'\n' +>>> text2 = ''' 1. Beautiful is better than ugly. +... 3. Simple is better than complex. +... 4. Complicated is better than complex. +... 5. Flat is better than nested. +... '''.splitlines(1) +\end{verbatim} + +Next we instantiate a Differ object: + +\begin{verbatim} +>>> d = Differ() +\end{verbatim} + +Note that when instantiating a \class{Differ} object we may pass +functions to filter out line and character ``junk.'' See the +\method{Differ()} constructor for details. + +Finally, we compare the two: + +\begin{verbatim} +>>> result = list(d.compare(text1, text2)) +\end{verbatim} + +\code{result} is a list of strings, so let's pretty-print it: + +\begin{verbatim} +>>> from pprint import pprint +>>> pprint(result) +[' 1. Beautiful is better than ugly.\n', + '- 2. Explicit is better than implicit.\n', + '- 3. Simple is better than complex.\n', + '+ 3. Simple is better than complex.\n', + '? ++ \n', + '- 4. Complex is better than complicated.\n', + '? ^ ---- ^ \n', + '+ 4. Complicated is better than complex.\n', + '? ++++ ^ ^ \n', + '+ 5. Flat is better than nested.\n'] +\end{verbatim} + +As a single multi-line string it looks like this: + +\begin{verbatim} +>>> import sys +>>> sys.stdout.writelines(result) + 1. Beautiful is better than ugly. +- 2. Explicit is better than implicit. +- 3. Simple is better than complex. ++ 3. Simple is better than complex. +? ++ +- 4. Complex is better than complicated. +? ^ ---- ^ ++ 4. Complicated is better than complex. +? ++++ ^ ^ ++ 5. Flat is better than nested. +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libdircache.tex b/sys/src/cmd/python/Doc/lib/libdircache.tex new file mode 100644 index 000000000..58845493b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdircache.tex @@ -0,0 +1,49 @@ +\section{\module{dircache} --- + Cached directory listings} + +\declaremodule{standard}{dircache} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Return directory listing, with cache mechanism.} + +The \module{dircache} module defines a function for reading directory listing +using a cache, and cache invalidation using the \var{mtime} of the directory. +Additionally, it defines a function to annotate directories by appending +a slash. + +The \module{dircache} module defines the following functions: + +\begin{funcdesc}{reset}{} +Resets the directory cache. +\end{funcdesc} + +\begin{funcdesc}{listdir}{path} +Return a directory listing of \var{path}, as gotten from +\function{os.listdir()}. Note that unless \var{path} changes, further call +to \function{listdir()} will not re-read the directory structure. + +Note that the list returned should be regarded as read-only. (Perhaps +a future version should change it to return a tuple?) +\end{funcdesc} + +\begin{funcdesc}{opendir}{path} +Same as \function{listdir()}. Defined for backwards compatibility. +\end{funcdesc} + +\begin{funcdesc}{annotate}{head, list} +Assume \var{list} is a list of paths relative to \var{head}, and append, +in place, a \character{/} to each path which points to a directory. +\end{funcdesc} + +\begin{verbatim} +>>> import dircache +>>> a = dircache.listdir('/') +>>> a = a[:] # Copy the return value so we can change 'a' +>>> a +['bin', 'boot', 'cdrom', 'dev', 'etc', 'floppy', 'home', 'initrd', 'lib', 'lost+ +found', 'mnt', 'proc', 'root', 'sbin', 'tmp', 'usr', 'var', 'vmlinuz'] +>>> dircache.annotate('/', a) +>>> a +['bin/', 'boot/', 'cdrom/', 'dev/', 'etc/', 'floppy/', 'home/', 'initrd/', 'lib/ +', 'lost+found/', 'mnt/', 'proc/', 'root/', 'sbin/', 'tmp/', 'usr/', 'var/', 'vm +linuz'] +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libdis.tex b/sys/src/cmd/python/Doc/lib/libdis.tex new file mode 100644 index 000000000..560cc27b4 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdis.tex @@ -0,0 +1,706 @@ +\section{\module{dis} --- + Disassembler for Python byte code} + +\declaremodule{standard}{dis} +\modulesynopsis{Disassembler for Python byte code.} + + +The \module{dis} module supports the analysis of Python byte code by +disassembling it. Since there is no Python assembler, this module +defines the Python assembly language. The Python byte code which +this module takes as an input is defined in the file +\file{Include/opcode.h} and used by the compiler and the interpreter. + +Example: Given the function \function{myfunc}: + +\begin{verbatim} +def myfunc(alist): + return len(alist) +\end{verbatim} + +the following command can be used to get the disassembly of +\function{myfunc()}: + +\begin{verbatim} +>>> dis.dis(myfunc) + 2 0 LOAD_GLOBAL 0 (len) + 3 LOAD_FAST 0 (alist) + 6 CALL_FUNCTION 1 + 9 RETURN_VALUE +\end{verbatim} + +(The ``2'' is a line number). + +The \module{dis} module defines the following functions and constants: + +\begin{funcdesc}{dis}{\optional{bytesource}} +Disassemble the \var{bytesource} object. \var{bytesource} can denote +either a module, a class, a method, a function, or a code object. +For a module, it disassembles all functions. For a class, +it disassembles all methods. For a single code sequence, it prints +one line per byte code instruction. If no object is provided, it +disassembles the last traceback. +\end{funcdesc} + +\begin{funcdesc}{distb}{\optional{tb}} +Disassembles the top-of-stack function of a traceback, using the last +traceback if none was passed. The instruction causing the exception +is indicated. +\end{funcdesc} + +\begin{funcdesc}{disassemble}{code\optional{, lasti}} +Disassembles a code object, indicating the last instruction if \var{lasti} +was provided. The output is divided in the following columns: + +\begin{enumerate} +\item the line number, for the first instruction of each line +\item the current instruction, indicated as \samp{-->}, +\item a labelled instruction, indicated with \samp{>>}, +\item the address of the instruction, +\item the operation code name, +\item operation parameters, and +\item interpretation of the parameters in parentheses. +\end{enumerate} + +The parameter interpretation recognizes local and global +variable names, constant values, branch targets, and compare +operators. +\end{funcdesc} + +\begin{funcdesc}{disco}{code\optional{, lasti}} +A synonym for disassemble. It is more convenient to type, and kept +for compatibility with earlier Python releases. +\end{funcdesc} + +\begin{datadesc}{opname} +Sequence of operation names, indexable using the byte code. +\end{datadesc} + +\begin{datadesc}{opmap} +Dictionary mapping byte codes to operation names. +\end{datadesc} + +\begin{datadesc}{cmp_op} +Sequence of all compare operation names. +\end{datadesc} + +\begin{datadesc}{hasconst} +Sequence of byte codes that have a constant parameter. +\end{datadesc} + +\begin{datadesc}{hasfree} +Sequence of byte codes that access a free variable. +\end{datadesc} + +\begin{datadesc}{hasname} +Sequence of byte codes that access an attribute by name. +\end{datadesc} + +\begin{datadesc}{hasjrel} +Sequence of byte codes that have a relative jump target. +\end{datadesc} + +\begin{datadesc}{hasjabs} +Sequence of byte codes that have an absolute jump target. +\end{datadesc} + +\begin{datadesc}{haslocal} +Sequence of byte codes that access a local variable. +\end{datadesc} + +\begin{datadesc}{hascompare} +Sequence of byte codes of Boolean operations. +\end{datadesc} + +\subsection{Python Byte Code Instructions} +\label{bytecodes} + +The Python compiler currently generates the following byte code +instructions. + +\setindexsubitem{(byte code insns)} + +\begin{opcodedesc}{STOP_CODE}{} +Indicates end-of-code to the compiler, not used by the interpreter. +\end{opcodedesc} + +\begin{opcodedesc}{NOP}{} +Do nothing code. Used as a placeholder by the bytecode optimizer. +\end{opcodedesc} + +\begin{opcodedesc}{POP_TOP}{} +Removes the top-of-stack (TOS) item. +\end{opcodedesc} + +\begin{opcodedesc}{ROT_TWO}{} +Swaps the two top-most stack items. +\end{opcodedesc} + +\begin{opcodedesc}{ROT_THREE}{} +Lifts second and third stack item one position up, moves top down +to position three. +\end{opcodedesc} + +\begin{opcodedesc}{ROT_FOUR}{} +Lifts second, third and forth stack item one position up, moves top down to +position four. +\end{opcodedesc} + +\begin{opcodedesc}{DUP_TOP}{} +Duplicates the reference on top of the stack. +\end{opcodedesc} + +Unary Operations take the top of the stack, apply the operation, and +push the result back on the stack. + +\begin{opcodedesc}{UNARY_POSITIVE}{} +Implements \code{TOS = +TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{UNARY_NEGATIVE}{} +Implements \code{TOS = -TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{UNARY_NOT}{} +Implements \code{TOS = not TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{UNARY_CONVERT}{} +Implements \code{TOS = `TOS`}. +\end{opcodedesc} + +\begin{opcodedesc}{UNARY_INVERT}{} +Implements \code{TOS = \~{}TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{GET_ITER}{} +Implements \code{TOS = iter(TOS)}. +\end{opcodedesc} + +Binary operations remove the top of the stack (TOS) and the second top-most +stack item (TOS1) from the stack. They perform the operation, and put the +result back on the stack. + +\begin{opcodedesc}{BINARY_POWER}{} +Implements \code{TOS = TOS1 ** TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_MULTIPLY}{} +Implements \code{TOS = TOS1 * TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_DIVIDE}{} +Implements \code{TOS = TOS1 / TOS} when +\code{from __future__ import division} is not in effect. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_FLOOR_DIVIDE}{} +Implements \code{TOS = TOS1 // TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_TRUE_DIVIDE}{} +Implements \code{TOS = TOS1 / TOS} when +\code{from __future__ import division} is in effect. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_MODULO}{} +Implements \code{TOS = TOS1 \%{} TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_ADD}{} +Implements \code{TOS = TOS1 + TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_SUBTRACT}{} +Implements \code{TOS = TOS1 - TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_SUBSCR}{} +Implements \code{TOS = TOS1[TOS]}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_LSHIFT}{} +Implements \code{TOS = TOS1 <\code{}< TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_RSHIFT}{} +Implements \code{TOS = TOS1 >\code{}> TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_AND}{} +Implements \code{TOS = TOS1 \&\ TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_XOR}{} +Implements \code{TOS = TOS1 \^\ TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{BINARY_OR}{} +Implements \code{TOS = TOS1 | TOS}. +\end{opcodedesc} + +In-place operations are like binary operations, in that they remove TOS and +TOS1, and push the result back on the stack, but the operation is done +in-place when TOS1 supports it, and the resulting TOS may be (but does not +have to be) the original TOS1. + +\begin{opcodedesc}{INPLACE_POWER}{} +Implements in-place \code{TOS = TOS1 ** TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_MULTIPLY}{} +Implements in-place \code{TOS = TOS1 * TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_DIVIDE}{} +Implements in-place \code{TOS = TOS1 / TOS} when +\code{from __future__ import division} is not in effect. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_FLOOR_DIVIDE}{} +Implements in-place \code{TOS = TOS1 // TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_TRUE_DIVIDE}{} +Implements in-place \code{TOS = TOS1 / TOS} when +\code{from __future__ import division} is in effect. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_MODULO}{} +Implements in-place \code{TOS = TOS1 \%{} TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_ADD}{} +Implements in-place \code{TOS = TOS1 + TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_SUBTRACT}{} +Implements in-place \code{TOS = TOS1 - TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_LSHIFT}{} +Implements in-place \code{TOS = TOS1 <\code{}< TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_RSHIFT}{} +Implements in-place \code{TOS = TOS1 >\code{}> TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_AND}{} +Implements in-place \code{TOS = TOS1 \&\ TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_XOR}{} +Implements in-place \code{TOS = TOS1 \^\ TOS}. +\end{opcodedesc} + +\begin{opcodedesc}{INPLACE_OR}{} +Implements in-place \code{TOS = TOS1 | TOS}. +\end{opcodedesc} + +The slice opcodes take up to three parameters. + +\begin{opcodedesc}{SLICE+0}{} +Implements \code{TOS = TOS[:]}. +\end{opcodedesc} + +\begin{opcodedesc}{SLICE+1}{} +Implements \code{TOS = TOS1[TOS:]}. +\end{opcodedesc} + +\begin{opcodedesc}{SLICE+2}{} +Implements \code{TOS = TOS1[:TOS]}. +\end{opcodedesc} + +\begin{opcodedesc}{SLICE+3}{} +Implements \code{TOS = TOS2[TOS1:TOS]}. +\end{opcodedesc} + +Slice assignment needs even an additional parameter. As any statement, +they put nothing on the stack. + +\begin{opcodedesc}{STORE_SLICE+0}{} +Implements \code{TOS[:] = TOS1}. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_SLICE+1}{} +Implements \code{TOS1[TOS:] = TOS2}. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_SLICE+2}{} +Implements \code{TOS1[:TOS] = TOS2}. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_SLICE+3}{} +Implements \code{TOS2[TOS1:TOS] = TOS3}. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_SLICE+0}{} +Implements \code{del TOS[:]}. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_SLICE+1}{} +Implements \code{del TOS1[TOS:]}. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_SLICE+2}{} +Implements \code{del TOS1[:TOS]}. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_SLICE+3}{} +Implements \code{del TOS2[TOS1:TOS]}. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_SUBSCR}{} +Implements \code{TOS1[TOS] = TOS2}. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_SUBSCR}{} +Implements \code{del TOS1[TOS]}. +\end{opcodedesc} + +Miscellaneous opcodes. + +\begin{opcodedesc}{PRINT_EXPR}{} +Implements the expression statement for the interactive mode. TOS is +removed from the stack and printed. In non-interactive mode, an +expression statement is terminated with \code{POP_STACK}. +\end{opcodedesc} + +\begin{opcodedesc}{PRINT_ITEM}{} +Prints TOS to the file-like object bound to \code{sys.stdout}. There +is one such instruction for each item in the \keyword{print} statement. +\end{opcodedesc} + +\begin{opcodedesc}{PRINT_ITEM_TO}{} +Like \code{PRINT_ITEM}, but prints the item second from TOS to the +file-like object at TOS. This is used by the extended print statement. +\end{opcodedesc} + +\begin{opcodedesc}{PRINT_NEWLINE}{} +Prints a new line on \code{sys.stdout}. This is generated as the +last operation of a \keyword{print} statement, unless the statement +ends with a comma. +\end{opcodedesc} + +\begin{opcodedesc}{PRINT_NEWLINE_TO}{} +Like \code{PRINT_NEWLINE}, but prints the new line on the file-like +object on the TOS. This is used by the extended print statement. +\end{opcodedesc} + +\begin{opcodedesc}{BREAK_LOOP}{} +Terminates a loop due to a \keyword{break} statement. +\end{opcodedesc} + +\begin{opcodedesc}{CONTINUE_LOOP}{target} +Continues a loop due to a \keyword{continue} statement. \var{target} +is the address to jump to (which should be a \code{FOR_ITER} +instruction). +\end{opcodedesc} + +\begin{opcodedesc}{LIST_APPEND}{} +Calls \code{list.append(TOS1, TOS)}. Used to implement list comprehensions. +\end{opcodedesc} + +\begin{opcodedesc}{LOAD_LOCALS}{} +Pushes a reference to the locals of the current scope on the stack. +This is used in the code for a class definition: After the class body +is evaluated, the locals are passed to the class definition. +\end{opcodedesc} + +\begin{opcodedesc}{RETURN_VALUE}{} +Returns with TOS to the caller of the function. +\end{opcodedesc} + +\begin{opcodedesc}{YIELD_VALUE}{} +Pops \code{TOS} and yields it from a generator. +\end{opcodedesc} + +\begin{opcodedesc}{IMPORT_STAR}{} +Loads all symbols not starting with \character{_} directly from the module TOS +to the local namespace. The module is popped after loading all names. +This opcode implements \code{from module import *}. +\end{opcodedesc} + +\begin{opcodedesc}{EXEC_STMT}{} +Implements \code{exec TOS2,TOS1,TOS}. The compiler fills +missing optional parameters with \code{None}. +\end{opcodedesc} + +\begin{opcodedesc}{POP_BLOCK}{} +Removes one block from the block stack. Per frame, there is a +stack of blocks, denoting nested loops, try statements, and such. +\end{opcodedesc} + +\begin{opcodedesc}{END_FINALLY}{} +Terminates a \keyword{finally} clause. The interpreter recalls +whether the exception has to be re-raised, or whether the function +returns, and continues with the outer-next block. +\end{opcodedesc} + +\begin{opcodedesc}{BUILD_CLASS}{} +Creates a new class object. TOS is the methods dictionary, TOS1 +the tuple of the names of the base classes, and TOS2 the class name. +\end{opcodedesc} + +All of the following opcodes expect arguments. An argument is two +bytes, with the more significant byte last. + +\begin{opcodedesc}{STORE_NAME}{namei} +Implements \code{name = TOS}. \var{namei} is the index of \var{name} +in the attribute \member{co_names} of the code object. +The compiler tries to use \code{STORE_LOCAL} or \code{STORE_GLOBAL} +if possible. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_NAME}{namei} +Implements \code{del name}, where \var{namei} is the index into +\member{co_names} attribute of the code object. +\end{opcodedesc} + +\begin{opcodedesc}{UNPACK_SEQUENCE}{count} +Unpacks TOS into \var{count} individual values, which are put onto +the stack right-to-left. +\end{opcodedesc} + +%\begin{opcodedesc}{UNPACK_LIST}{count} +%This opcode is obsolete. +%\end{opcodedesc} + +%\begin{opcodedesc}{UNPACK_ARG}{count} +%This opcode is obsolete. +%\end{opcodedesc} + +\begin{opcodedesc}{DUP_TOPX}{count} +Duplicate \var{count} items, keeping them in the same order. Due to +implementation limits, \var{count} should be between 1 and 5 inclusive. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_ATTR}{namei} +Implements \code{TOS.name = TOS1}, where \var{namei} is the index +of name in \member{co_names}. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_ATTR}{namei} +Implements \code{del TOS.name}, using \var{namei} as index into +\member{co_names}. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_GLOBAL}{namei} +Works as \code{STORE_NAME}, but stores the name as a global. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_GLOBAL}{namei} +Works as \code{DELETE_NAME}, but deletes a global name. +\end{opcodedesc} + +%\begin{opcodedesc}{UNPACK_VARARG}{argc} +%This opcode is obsolete. +%\end{opcodedesc} + +\begin{opcodedesc}{LOAD_CONST}{consti} +Pushes \samp{co_consts[\var{consti}]} onto the stack. +\end{opcodedesc} + +\begin{opcodedesc}{LOAD_NAME}{namei} +Pushes the value associated with \samp{co_names[\var{namei}]} onto the stack. +\end{opcodedesc} + +\begin{opcodedesc}{BUILD_TUPLE}{count} +Creates a tuple consuming \var{count} items from the stack, and pushes +the resulting tuple onto the stack. +\end{opcodedesc} + +\begin{opcodedesc}{BUILD_LIST}{count} +Works as \code{BUILD_TUPLE}, but creates a list. +\end{opcodedesc} + +\begin{opcodedesc}{BUILD_MAP}{zero} +Pushes a new empty dictionary object onto the stack. The argument is +ignored and set to zero by the compiler. +\end{opcodedesc} + +\begin{opcodedesc}{LOAD_ATTR}{namei} +Replaces TOS with \code{getattr(TOS, co_names[\var{namei}])}. +\end{opcodedesc} + +\begin{opcodedesc}{COMPARE_OP}{opname} +Performs a Boolean operation. The operation name can be found +in \code{cmp_op[\var{opname}]}. +\end{opcodedesc} + +\begin{opcodedesc}{IMPORT_NAME}{namei} +Imports the module \code{co_names[\var{namei}]}. The module object is +pushed onto the stack. The current namespace is not affected: for a +proper import statement, a subsequent \code{STORE_FAST} instruction +modifies the namespace. +\end{opcodedesc} + +\begin{opcodedesc}{IMPORT_FROM}{namei} +Loads the attribute \code{co_names[\var{namei}]} from the module found in +TOS. The resulting object is pushed onto the stack, to be subsequently +stored by a \code{STORE_FAST} instruction. +\end{opcodedesc} + +\begin{opcodedesc}{JUMP_FORWARD}{delta} +Increments byte code counter by \var{delta}. +\end{opcodedesc} + +\begin{opcodedesc}{JUMP_IF_TRUE}{delta} +If TOS is true, increment the byte code counter by \var{delta}. TOS is +left on the stack. +\end{opcodedesc} + +\begin{opcodedesc}{JUMP_IF_FALSE}{delta} +If TOS is false, increment the byte code counter by \var{delta}. TOS +is not changed. +\end{opcodedesc} + +\begin{opcodedesc}{JUMP_ABSOLUTE}{target} +Set byte code counter to \var{target}. +\end{opcodedesc} + +\begin{opcodedesc}{FOR_ITER}{delta} +\code{TOS} is an iterator. Call its \method{next()} method. If this +yields a new value, push it on the stack (leaving the iterator below +it). If the iterator indicates it is exhausted \code{TOS} is +popped, and the byte code counter is incremented by \var{delta}. +\end{opcodedesc} + +%\begin{opcodedesc}{FOR_LOOP}{delta} +%This opcode is obsolete. +%\end{opcodedesc} + +%\begin{opcodedesc}{LOAD_LOCAL}{namei} +%This opcode is obsolete. +%\end{opcodedesc} + +\begin{opcodedesc}{LOAD_GLOBAL}{namei} +Loads the global named \code{co_names[\var{namei}]} onto the stack. +\end{opcodedesc} + +%\begin{opcodedesc}{SET_FUNC_ARGS}{argc} +%This opcode is obsolete. +%\end{opcodedesc} + +\begin{opcodedesc}{SETUP_LOOP}{delta} +Pushes a block for a loop onto the block stack. The block spans +from the current instruction with a size of \var{delta} bytes. +\end{opcodedesc} + +\begin{opcodedesc}{SETUP_EXCEPT}{delta} +Pushes a try block from a try-except clause onto the block stack. +\var{delta} points to the first except block. +\end{opcodedesc} + +\begin{opcodedesc}{SETUP_FINALLY}{delta} +Pushes a try block from a try-except clause onto the block stack. +\var{delta} points to the finally block. +\end{opcodedesc} + +\begin{opcodedesc}{LOAD_FAST}{var_num} +Pushes a reference to the local \code{co_varnames[\var{var_num}]} onto +the stack. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_FAST}{var_num} +Stores TOS into the local \code{co_varnames[\var{var_num}]}. +\end{opcodedesc} + +\begin{opcodedesc}{DELETE_FAST}{var_num} +Deletes local \code{co_varnames[\var{var_num}]}. +\end{opcodedesc} + +\begin{opcodedesc}{LOAD_CLOSURE}{i} +Pushes a reference to the cell contained in slot \var{i} of the +cell and free variable storage. The name of the variable is +\code{co_cellvars[\var{i}]} if \var{i} is less than the length of +\var{co_cellvars}. Otherwise it is +\code{co_freevars[\var{i} - len(co_cellvars)]}. +\end{opcodedesc} + +\begin{opcodedesc}{LOAD_DEREF}{i} +Loads the cell contained in slot \var{i} of the cell and free variable +storage. Pushes a reference to the object the cell contains on the +stack. +\end{opcodedesc} + +\begin{opcodedesc}{STORE_DEREF}{i} +Stores TOS into the cell contained in slot \var{i} of the cell and +free variable storage. +\end{opcodedesc} + +\begin{opcodedesc}{SET_LINENO}{lineno} +This opcode is obsolete. +\end{opcodedesc} + +\begin{opcodedesc}{RAISE_VARARGS}{argc} +Raises an exception. \var{argc} indicates the number of parameters +to the raise statement, ranging from 0 to 3. The handler will find +the traceback as TOS2, the parameter as TOS1, and the exception +as TOS. +\end{opcodedesc} + +\begin{opcodedesc}{CALL_FUNCTION}{argc} +Calls a function. The low byte of \var{argc} indicates the number of +positional parameters, the high byte the number of keyword parameters. +On the stack, the opcode finds the keyword parameters first. For each +keyword argument, the value is on top of the key. Below the keyword +parameters, the positional parameters are on the stack, with the +right-most parameter on top. Below the parameters, the function object +to call is on the stack. +\end{opcodedesc} + +\begin{opcodedesc}{MAKE_FUNCTION}{argc} +Pushes a new function object on the stack. TOS is the code associated +with the function. The function object is defined to have \var{argc} +default parameters, which are found below TOS. +\end{opcodedesc} + +\begin{opcodedesc}{MAKE_CLOSURE}{argc} +Creates a new function object, sets its \var{func_closure} slot, and +pushes it on the stack. TOS is the code associated with the function. +If the code object has N free variables, the next N items on the stack +are the cells for these variables. The function also has \var{argc} +default parameters, where are found before the cells. +\end{opcodedesc} + +\begin{opcodedesc}{BUILD_SLICE}{argc} +Pushes a slice object on the stack. \var{argc} must be 2 or 3. If it +is 2, \code{slice(TOS1, TOS)} is pushed; if it is 3, +\code{slice(TOS2, TOS1, TOS)} is pushed. +See the \code{slice()}\bifuncindex{slice} built-in function for more +information. +\end{opcodedesc} + +\begin{opcodedesc}{EXTENDED_ARG}{ext} +Prefixes any opcode which has an argument too big to fit into the +default two bytes. \var{ext} holds two additional bytes which, taken +together with the subsequent opcode's argument, comprise a four-byte +argument, \var{ext} being the two most-significant bytes. +\end{opcodedesc} + +\begin{opcodedesc}{CALL_FUNCTION_VAR}{argc} +Calls a function. \var{argc} is interpreted as in \code{CALL_FUNCTION}. +The top element on the stack contains the variable argument list, followed +by keyword and positional arguments. +\end{opcodedesc} + +\begin{opcodedesc}{CALL_FUNCTION_KW}{argc} +Calls a function. \var{argc} is interpreted as in \code{CALL_FUNCTION}. +The top element on the stack contains the keyword arguments dictionary, +followed by explicit keyword and positional arguments. +\end{opcodedesc} + +\begin{opcodedesc}{CALL_FUNCTION_VAR_KW}{argc} +Calls a function. \var{argc} is interpreted as in +\code{CALL_FUNCTION}. The top element on the stack contains the +keyword arguments dictionary, followed by the variable-arguments +tuple, followed by explicit keyword and positional arguments. +\end{opcodedesc} + +\begin{opcodedesc}{HAVE_ARGUMENT}{} +This is not really an opcode. It identifies the dividing line between +opcodes which don't take arguments \code{< HAVE_ARGUMENT} and those which do +\code{>= HAVE_ARGUMENT}. +\end{opcodedesc} diff --git a/sys/src/cmd/python/Doc/lib/libdl.tex b/sys/src/cmd/python/Doc/lib/libdl.tex new file mode 100644 index 000000000..325724c84 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdl.tex @@ -0,0 +1,101 @@ +\section{\module{dl} --- + Call C functions in shared objects} +\declaremodule{extension}{dl} + \platform{Unix} %?????????? Anyone???????????? +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Call C functions in shared objects.} + +The \module{dl} module defines an interface to the +\cfunction{dlopen()} function, which is the most common interface on +\UNIX{} platforms for handling dynamically linked libraries. It allows +the program to call arbitrary functions in such a library. + +\warning{The \module{dl} module bypasses the Python type system and +error handling. If used incorrectly it may cause segmentation faults, +crashes or other incorrect behaviour.} + +\note{This module will not work unless +\code{sizeof(int) == sizeof(long) == sizeof(char *)} +If this is not the case, \exception{SystemError} will be raised on +import.} + +The \module{dl} module defines the following function: + +\begin{funcdesc}{open}{name\optional{, mode\code{ = RTLD_LAZY}}} +Open a shared object file, and return a handle. Mode +signifies late binding (\constant{RTLD_LAZY}) or immediate binding +(\constant{RTLD_NOW}). Default is \constant{RTLD_LAZY}. Note that some +systems do not support \constant{RTLD_NOW}. + +Return value is a \class{dlobject}. +\end{funcdesc} + +The \module{dl} module defines the following constants: + +\begin{datadesc}{RTLD_LAZY} +Useful as an argument to \function{open()}. +\end{datadesc} + +\begin{datadesc}{RTLD_NOW} +Useful as an argument to \function{open()}. Note that on systems +which do not support immediate binding, this constant will not appear +in the module. For maximum portability, use \function{hasattr()} to +determine if the system supports immediate binding. +\end{datadesc} + +The \module{dl} module defines the following exception: + +\begin{excdesc}{error} +Exception raised when an error has occurred inside the dynamic loading +and linking routines. +\end{excdesc} + +Example: + +\begin{verbatim} +>>> import dl, time +>>> a=dl.open('/lib/libc.so.6') +>>> a.call('time'), time.time() +(929723914, 929723914.498) +\end{verbatim} + +This example was tried on a Debian GNU/Linux system, and is a good +example of the fact that using this module is usually a bad alternative. + +\subsection{Dl Objects \label{dl-objects}} + +Dl objects, as returned by \function{open()} above, have the +following methods: + +\begin{methoddesc}{close}{} +Free all resources, except the memory. +\end{methoddesc} + +\begin{methoddesc}{sym}{name} +Return the pointer for the function named \var{name}, as a number, if +it exists in the referenced shared object, otherwise \code{None}. This +is useful in code like: + +\begin{verbatim} +>>> if a.sym('time'): +... a.call('time') +... else: +... time.time() +\end{verbatim} + +(Note that this function will return a non-zero number, as zero is the +\NULL{} pointer) +\end{methoddesc} + +\begin{methoddesc}{call}{name\optional{, arg1\optional{, arg2\ldots}}} +Call the function named \var{name} in the referenced shared object. +The arguments must be either Python integers, which will be +passed as is, Python strings, to which a pointer will be passed, +or \code{None}, which will be passed as \NULL. Note that +strings should only be passed to functions as \ctype{const char*}, as +Python will not like its string mutated. + +There must be at most 10 arguments, and arguments not given will be +treated as \code{None}. The function's return value must be a C +\ctype{long}, which is a Python integer. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libdoctest.tex b/sys/src/cmd/python/Doc/lib/libdoctest.tex new file mode 100644 index 000000000..957ecf48c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdoctest.tex @@ -0,0 +1,1949 @@ +\section{\module{doctest} --- + Test interactive Python examples} + +\declaremodule{standard}{doctest} +\moduleauthor{Tim Peters}{tim@python.org} +\sectionauthor{Tim Peters}{tim@python.org} +\sectionauthor{Moshe Zadka}{moshez@debian.org} +\sectionauthor{Edward Loper}{edloper@users.sourceforge.net} + +\modulesynopsis{A framework for verifying interactive Python examples.} + +The \refmodule{doctest} module searches for pieces of text that look like +interactive Python sessions, and then executes those sessions to +verify that they work exactly as shown. There are several common ways to +use doctest: + +\begin{itemize} +\item To check that a module's docstrings are up-to-date by verifying + that all interactive examples still work as documented. +\item To perform regression testing by verifying that interactive + examples from a test file or a test object work as expected. +\item To write tutorial documentation for a package, liberally + illustrated with input-output examples. Depending on whether + the examples or the expository text are emphasized, this has + the flavor of "literate testing" or "executable documentation". +\end{itemize} + +Here's a complete but small example module: + +\begin{verbatim} +""" +This is the "example" module. + +The example module supplies one function, factorial(). For example, + +>>> factorial(5) +120 +""" + +def factorial(n): + """Return the factorial of n, an exact integer >= 0. + + If the result is small enough to fit in an int, return an int. + Else return a long. + + >>> [factorial(n) for n in range(6)] + [1, 1, 2, 6, 24, 120] + >>> [factorial(long(n)) for n in range(6)] + [1, 1, 2, 6, 24, 120] + >>> factorial(30) + 265252859812191058636308480000000L + >>> factorial(30L) + 265252859812191058636308480000000L + >>> factorial(-1) + Traceback (most recent call last): + ... + ValueError: n must be >= 0 + + Factorials of floats are OK, but the float must be an exact integer: + >>> factorial(30.1) + Traceback (most recent call last): + ... + ValueError: n must be exact integer + >>> factorial(30.0) + 265252859812191058636308480000000L + + It must also not be ridiculously large: + >>> factorial(1e100) + Traceback (most recent call last): + ... + OverflowError: n too large + """ + +\end{verbatim} +% allow LaTeX to break here. +\begin{verbatim} + + import math + if not n >= 0: + raise ValueError("n must be >= 0") + if math.floor(n) != n: + raise ValueError("n must be exact integer") + if n+1 == n: # catch a value like 1e300 + raise OverflowError("n too large") + result = 1 + factor = 2 + while factor <= n: + result *= factor + factor += 1 + return result + +def _test(): + import doctest + doctest.testmod() + +if __name__ == "__main__": + _test() +\end{verbatim} + +If you run \file{example.py} directly from the command line, +\refmodule{doctest} works its magic: + +\begin{verbatim} +$ python example.py +$ +\end{verbatim} + +There's no output! That's normal, and it means all the examples +worked. Pass \programopt{-v} to the script, and \refmodule{doctest} +prints a detailed log of what it's trying, and prints a summary at the +end: + +\begin{verbatim} +$ python example.py -v +Trying: + factorial(5) +Expecting: + 120 +ok +Trying: + [factorial(n) for n in range(6)] +Expecting: + [1, 1, 2, 6, 24, 120] +ok +Trying: + [factorial(long(n)) for n in range(6)] +Expecting: + [1, 1, 2, 6, 24, 120] +ok +\end{verbatim} + +And so on, eventually ending with: + +\begin{verbatim} +Trying: + factorial(1e100) +Expecting: + Traceback (most recent call last): + ... + OverflowError: n too large +ok +1 items had no tests: + __main__._test +2 items passed all tests: + 1 tests in __main__ + 8 tests in __main__.factorial +9 tests in 3 items. +9 passed and 0 failed. +Test passed. +$ +\end{verbatim} + +That's all you need to know to start making productive use of +\refmodule{doctest}! Jump in. The following sections provide full +details. Note that there are many examples of doctests in +the standard Python test suite and libraries. Especially useful examples +can be found in the standard test file \file{Lib/test/test_doctest.py}. + +\subsection{Simple Usage: Checking Examples in + Docstrings\label{doctest-simple-testmod}} + +The simplest way to start using doctest (but not necessarily the way +you'll continue to do it) is to end each module \module{M} with: + +\begin{verbatim} +def _test(): + import doctest + doctest.testmod() + +if __name__ == "__main__": + _test() +\end{verbatim} + +\refmodule{doctest} then examines docstrings in module \module{M}. + +Running the module as a script causes the examples in the docstrings +to get executed and verified: + +\begin{verbatim} +python M.py +\end{verbatim} + +This won't display anything unless an example fails, in which case the +failing example(s) and the cause(s) of the failure(s) are printed to stdout, +and the final line of output is +\samp{***Test Failed*** \var{N} failures.}, where \var{N} is the +number of examples that failed. + +Run it with the \programopt{-v} switch instead: + +\begin{verbatim} +python M.py -v +\end{verbatim} + +and a detailed report of all examples tried is printed to standard +output, along with assorted summaries at the end. + +You can force verbose mode by passing \code{verbose=True} to +\function{testmod()}, or +prohibit it by passing \code{verbose=False}. In either of those cases, +\code{sys.argv} is not examined by \function{testmod()} (so passing +\programopt{-v} or not has no effect). + +For more information on \function{testmod()}, see +section~\ref{doctest-basic-api}. + +\subsection{Simple Usage: Checking Examples in a Text + File\label{doctest-simple-testfile}} + +Another simple application of doctest is testing interactive examples +in a text file. This can be done with the \function{testfile()} +function: + +\begin{verbatim} +import doctest +doctest.testfile("example.txt") +\end{verbatim} + +That short script executes and verifies any interactive Python +examples contained in the file \file{example.txt}. The file content +is treated as if it were a single giant docstring; the file doesn't +need to contain a Python program! For example, perhaps \file{example.txt} +contains this: + +\begin{verbatim} +The ``example`` module +====================== + +Using ``factorial`` +------------------- + +This is an example text file in reStructuredText format. First import +``factorial`` from the ``example`` module: + + >>> from example import factorial + +Now use it: + + >>> factorial(6) + 120 +\end{verbatim} + +Running \code{doctest.testfile("example.txt")} then finds the error +in this documentation: + +\begin{verbatim} +File "./example.txt", line 14, in example.txt +Failed example: + factorial(6) +Expected: + 120 +Got: + 720 +\end{verbatim} + +As with \function{testmod()}, \function{testfile()} won't display anything +unless an example fails. If an example does fail, then the failing +example(s) and the cause(s) of the failure(s) are printed to stdout, using +the same format as \function{testmod()}. + +By default, \function{testfile()} looks for files in the calling +module's directory. See section~\ref{doctest-basic-api} for a +description of the optional arguments that can be used to tell it to +look for files in other locations. + +Like \function{testmod()}, \function{testfile()}'s verbosity can be +set with the \programopt{-v} command-line switch or with the optional +keyword argument \var{verbose}. + +For more information on \function{testfile()}, see +section~\ref{doctest-basic-api}. + +\subsection{How It Works\label{doctest-how-it-works}} + +This section examines in detail how doctest works: which docstrings it +looks at, how it finds interactive examples, what execution context it +uses, how it handles exceptions, and how option flags can be used to +control its behavior. This is the information that you need to know +to write doctest examples; for information about actually running +doctest on these examples, see the following sections. + +\subsubsection{Which Docstrings Are Examined?\label{doctest-which-docstrings}} + +The module docstring, and all function, class and method docstrings are +searched. Objects imported into the module are not searched. + +In addition, if \code{M.__test__} exists and "is true", it must be a +dict, and each entry maps a (string) name to a function object, class +object, or string. Function and class object docstrings found from +\code{M.__test__} are searched, and strings are treated as if they +were docstrings. In output, a key \code{K} in \code{M.__test__} appears +with name + +\begin{verbatim} +.__test__.K +\end{verbatim} + +Any classes found are recursively searched similarly, to test docstrings in +their contained methods and nested classes. + +\versionchanged[A "private name" concept is deprecated and no longer + documented]{2.4} + +\subsubsection{How are Docstring Examples + Recognized?\label{doctest-finding-examples}} + +In most cases a copy-and-paste of an interactive console session works +fine, but doctest isn't trying to do an exact emulation of any specific +Python shell. All hard tab characters are expanded to spaces, using +8-column tab stops. If you don't believe tabs should mean that, too +bad: don't use hard tabs, or write your own \class{DocTestParser} +class. + +\versionchanged[Expanding tabs to spaces is new; previous versions + tried to preserve hard tabs, with confusing results]{2.4} + +\begin{verbatim} +>>> # comments are ignored +>>> x = 12 +>>> x +12 +>>> if x == 13: +... print "yes" +... else: +... print "no" +... print "NO" +... print "NO!!!" +... +no +NO +NO!!! +>>> +\end{verbatim} + +Any expected output must immediately follow the final +\code{'>>>~'} or \code{'...~'} line containing the code, and +the expected output (if any) extends to the next \code{'>>>~'} +or all-whitespace line. + +The fine print: + +\begin{itemize} + +\item Expected output cannot contain an all-whitespace line, since such a + line is taken to signal the end of expected output. If expected + output does contain a blank line, put \code{} in your + doctest example each place a blank line is expected. + \versionchanged[\code{} was added; there was no way to + use expected output containing empty lines in + previous versions]{2.4} + +\item Output to stdout is captured, but not output to stderr (exception + tracebacks are captured via a different means). + +\item If you continue a line via backslashing in an interactive session, + or for any other reason use a backslash, you should use a raw + docstring, which will preserve your backslashes exactly as you type + them: + +\begin{verbatim} +>>> def f(x): +... r'''Backslashes in a raw docstring: m\n''' +>>> print f.__doc__ +Backslashes in a raw docstring: m\n +\end{verbatim} + + Otherwise, the backslash will be interpreted as part of the string. + For example, the "{\textbackslash}" above would be interpreted as a + newline character. Alternatively, you can double each backslash in the + doctest version (and not use a raw string): + +\begin{verbatim} +>>> def f(x): +... '''Backslashes in a raw docstring: m\\n''' +>>> print f.__doc__ +Backslashes in a raw docstring: m\n +\end{verbatim} + +\item The starting column doesn't matter: + +\begin{verbatim} + >>> assert "Easy!" + >>> import math + >>> math.floor(1.9) + 1.0 +\end{verbatim} + +and as many leading whitespace characters are stripped from the +expected output as appeared in the initial \code{'>>>~'} line +that started the example. +\end{itemize} + +\subsubsection{What's the Execution Context?\label{doctest-execution-context}} + +By default, each time \refmodule{doctest} finds a docstring to test, it +uses a \emph{shallow copy} of \module{M}'s globals, so that running tests +doesn't change the module's real globals, and so that one test in +\module{M} can't leave behind crumbs that accidentally allow another test +to work. This means examples can freely use any names defined at top-level +in \module{M}, and names defined earlier in the docstring being run. +Examples cannot see names defined in other docstrings. + +You can force use of your own dict as the execution context by passing +\code{globs=your_dict} to \function{testmod()} or +\function{testfile()} instead. + +\subsubsection{What About Exceptions?\label{doctest-exceptions}} + +No problem, provided that the traceback is the only output produced by +the example: just paste in the traceback.\footnote{Examples containing + both expected output and an exception are not supported. Trying + to guess where one ends and the other begins is too error-prone, + and that also makes for a confusing test.} +Since tracebacks contain details that are likely to change rapidly (for +example, exact file paths and line numbers), this is one case where doctest +works hard to be flexible in what it accepts. + +Simple example: + +\begin{verbatim} +>>> [1, 2, 3].remove(42) +Traceback (most recent call last): + File "", line 1, in ? +ValueError: list.remove(x): x not in list +\end{verbatim} + +That doctest succeeds if \exception{ValueError} is raised, with the +\samp{list.remove(x): x not in list} detail as shown. + +The expected output for an exception must start with a traceback +header, which may be either of the following two lines, indented the +same as the first line of the example: + +\begin{verbatim} +Traceback (most recent call last): +Traceback (innermost last): +\end{verbatim} + +The traceback header is followed by an optional traceback stack, whose +contents are ignored by doctest. The traceback stack is typically +omitted, or copied verbatim from an interactive session. + +The traceback stack is followed by the most interesting part: the +line(s) containing the exception type and detail. This is usually the +last line of a traceback, but can extend across multiple lines if the +exception has a multi-line detail: + +\begin{verbatim} +>>> raise ValueError('multi\n line\ndetail') +Traceback (most recent call last): + File "", line 1, in ? +ValueError: multi + line +detail +\end{verbatim} + +The last three lines (starting with \exception{ValueError}) are +compared against the exception's type and detail, and the rest are +ignored. + +Best practice is to omit the traceback stack, unless it adds +significant documentation value to the example. So the last example +is probably better as: + +\begin{verbatim} +>>> raise ValueError('multi\n line\ndetail') +Traceback (most recent call last): + ... +ValueError: multi + line +detail +\end{verbatim} + +Note that tracebacks are treated very specially. In particular, in the +rewritten example, the use of \samp{...} is independent of doctest's +\constant{ELLIPSIS} option. The ellipsis in that example could be left +out, or could just as well be three (or three hundred) commas or digits, +or an indented transcript of a Monty Python skit. + +Some details you should read once, but won't need to remember: + +\begin{itemize} + +\item Doctest can't guess whether your expected output came from an + exception traceback or from ordinary printing. So, e.g., an example + that expects \samp{ValueError: 42 is prime} will pass whether + \exception{ValueError} is actually raised or if the example merely + prints that traceback text. In practice, ordinary output rarely begins + with a traceback header line, so this doesn't create real problems. + +\item Each line of the traceback stack (if present) must be indented + further than the first line of the example, \emph{or} start with a + non-alphanumeric character. The first line following the traceback + header indented the same and starting with an alphanumeric is taken + to be the start of the exception detail. Of course this does the + right thing for genuine tracebacks. + +\item When the \constant{IGNORE_EXCEPTION_DETAIL} doctest option is + is specified, everything following the leftmost colon is ignored. + +\item The interactive shell omits the traceback header line for some + \exception{SyntaxError}s. But doctest uses the traceback header + line to distinguish exceptions from non-exceptions. So in the rare + case where you need to test a \exception{SyntaxError} that omits the + traceback header, you will need to manually add the traceback header + line to your test example. + +\item For some \exception{SyntaxError}s, Python displays the character + position of the syntax error, using a \code{\^} marker: + +\begin{verbatim} +>>> 1 1 + File "", line 1 + 1 1 + ^ +SyntaxError: invalid syntax +\end{verbatim} + + Since the lines showing the position of the error come before the + exception type and detail, they are not checked by doctest. For + example, the following test would pass, even though it puts the + \code{\^} marker in the wrong location: + +\begin{verbatim} +>>> 1 1 +Traceback (most recent call last): + File "", line 1 + 1 1 + ^ +SyntaxError: invalid syntax +\end{verbatim} + +\end{itemize} + +\versionchanged[The ability to handle a multi-line exception detail, + and the \constant{IGNORE_EXCEPTION_DETAIL} doctest option, + were added]{2.4} + +\subsubsection{Option Flags and Directives\label{doctest-options}} + +A number of option flags control various aspects of doctest's +behavior. Symbolic names for the flags are supplied as module constants, +which can be or'ed together and passed to various functions. The names +can also be used in doctest directives (see below). + +The first group of options define test semantics, controlling +aspects of how doctest decides whether actual output matches an +example's expected output: + +\begin{datadesc}{DONT_ACCEPT_TRUE_FOR_1} + By default, if an expected output block contains just \code{1}, + an actual output block containing just \code{1} or just + \code{True} is considered to be a match, and similarly for \code{0} + versus \code{False}. When \constant{DONT_ACCEPT_TRUE_FOR_1} is + specified, neither substitution is allowed. The default behavior + caters to that Python changed the return type of many functions + from integer to boolean; doctests expecting "little integer" + output still work in these cases. This option will probably go + away, but not for several years. +\end{datadesc} + +\begin{datadesc}{DONT_ACCEPT_BLANKLINE} + By default, if an expected output block contains a line + containing only the string \code{}, then that line + will match a blank line in the actual output. Because a + genuinely blank line delimits the expected output, this is + the only way to communicate that a blank line is expected. When + \constant{DONT_ACCEPT_BLANKLINE} is specified, this substitution + is not allowed. +\end{datadesc} + +\begin{datadesc}{NORMALIZE_WHITESPACE} + When specified, all sequences of whitespace (blanks and newlines) are + treated as equal. Any sequence of whitespace within the expected + output will match any sequence of whitespace within the actual output. + By default, whitespace must match exactly. + \constant{NORMALIZE_WHITESPACE} is especially useful when a line + of expected output is very long, and you want to wrap it across + multiple lines in your source. +\end{datadesc} + +\begin{datadesc}{ELLIPSIS} + When specified, an ellipsis marker (\code{...}) in the expected output + can match any substring in the actual output. This includes + substrings that span line boundaries, and empty substrings, so it's + best to keep usage of this simple. Complicated uses can lead to the + same kinds of "oops, it matched too much!" surprises that \regexp{.*} + is prone to in regular expressions. +\end{datadesc} + +\begin{datadesc}{IGNORE_EXCEPTION_DETAIL} + When specified, an example that expects an exception passes if + an exception of the expected type is raised, even if the exception + detail does not match. For example, an example expecting + \samp{ValueError: 42} will pass if the actual exception raised is + \samp{ValueError: 3*14}, but will fail, e.g., if + \exception{TypeError} is raised. + + Note that a similar effect can be obtained using \constant{ELLIPSIS}, + and \constant{IGNORE_EXCEPTION_DETAIL} may go away when Python releases + prior to 2.4 become uninteresting. Until then, + \constant{IGNORE_EXCEPTION_DETAIL} is the only clear way to write a + doctest that doesn't care about the exception detail yet continues + to pass under Python releases prior to 2.4 (doctest directives + appear to be comments to them). For example, + +\begin{verbatim} +>>> (1, 2)[3] = 'moo' #doctest: +IGNORE_EXCEPTION_DETAIL +Traceback (most recent call last): + File "", line 1, in ? +TypeError: object doesn't support item assignment +\end{verbatim} + + passes under Python 2.4 and Python 2.3. The detail changed in 2.4, + to say "does not" instead of "doesn't". + +\end{datadesc} + +\begin{datadesc}{SKIP} + + When specified, do not run the example at all. This can be useful + in contexts where doctest examples serve as both documentation and + test cases, and an example should be included for documentation + purposes, but should not be checked. E.g., the example's output + might be random; or the example might depend on resources which + would be unavailable to the test driver. + + The SKIP flag can also be used for temporarily "commenting out" + examples. + +\end{datadesc} + +\begin{datadesc}{COMPARISON_FLAGS} + A bitmask or'ing together all the comparison flags above. +\end{datadesc} + +The second group of options controls how test failures are reported: + +\begin{datadesc}{REPORT_UDIFF} + When specified, failures that involve multi-line expected and + actual outputs are displayed using a unified diff. +\end{datadesc} + +\begin{datadesc}{REPORT_CDIFF} + When specified, failures that involve multi-line expected and + actual outputs will be displayed using a context diff. +\end{datadesc} + +\begin{datadesc}{REPORT_NDIFF} + When specified, differences are computed by \code{difflib.Differ}, + using the same algorithm as the popular \file{ndiff.py} utility. + This is the only method that marks differences within lines as + well as across lines. For example, if a line of expected output + contains digit \code{1} where actual output contains letter \code{l}, + a line is inserted with a caret marking the mismatching column + positions. +\end{datadesc} + +\begin{datadesc}{REPORT_ONLY_FIRST_FAILURE} + When specified, display the first failing example in each doctest, + but suppress output for all remaining examples. This will prevent + doctest from reporting correct examples that break because of + earlier failures; but it might also hide incorrect examples that + fail independently of the first failure. When + \constant{REPORT_ONLY_FIRST_FAILURE} is specified, the remaining + examples are still run, and still count towards the total number of + failures reported; only the output is suppressed. +\end{datadesc} + +\begin{datadesc}{REPORTING_FLAGS} + A bitmask or'ing together all the reporting flags above. +\end{datadesc} + +"Doctest directives" may be used to modify the option flags for +individual examples. Doctest directives are expressed as a special +Python comment following an example's source code: + +\begin{productionlist}[doctest] + \production{directive} + {"\#" "doctest:" \token{directive_options}} + \production{directive_options} + {\token{directive_option} ("," \token{directive_option})*} + \production{directive_option} + {\token{on_or_off} \token{directive_option_name}} + \production{on_or_off} + {"+" | "-"} + \production{directive_option_name} + {"DONT_ACCEPT_BLANKLINE" | "NORMALIZE_WHITESPACE" | ...} +\end{productionlist} + +Whitespace is not allowed between the \code{+} or \code{-} and the +directive option name. The directive option name can be any of the +option flag names explained above. + +An example's doctest directives modify doctest's behavior for that +single example. Use \code{+} to enable the named behavior, or +\code{-} to disable it. + +For example, this test passes: + +\begin{verbatim} +>>> print range(20) #doctest: +NORMALIZE_WHITESPACE +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +10, 11, 12, 13, 14, 15, 16, 17, 18, 19] +\end{verbatim} + +Without the directive it would fail, both because the actual output +doesn't have two blanks before the single-digit list elements, and +because the actual output is on a single line. This test also passes, +and also requires a directive to do so: + +\begin{verbatim} +>>> print range(20) # doctest:+ELLIPSIS +[0, 1, ..., 18, 19] +\end{verbatim} + +Multiple directives can be used on a single physical line, separated +by commas: + +\begin{verbatim} +>>> print range(20) # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE +[0, 1, ..., 18, 19] +\end{verbatim} + +If multiple directive comments are used for a single example, then +they are combined: + +\begin{verbatim} +>>> print range(20) # doctest: +ELLIPSIS +... # doctest: +NORMALIZE_WHITESPACE +[0, 1, ..., 18, 19] +\end{verbatim} + +As the previous example shows, you can add \samp{...} lines to your +example containing only directives. This can be useful when an +example is too long for a directive to comfortably fit on the same +line: + +\begin{verbatim} +>>> print range(5) + range(10,20) + range(30,40) + range(50,60) +... # doctest: +ELLIPSIS +[0, ..., 4, 10, ..., 19, 30, ..., 39, 50, ..., 59] +\end{verbatim} + +Note that since all options are disabled by default, and directives apply +only to the example they appear in, enabling options (via \code{+} in a +directive) is usually the only meaningful choice. However, option flags +can also be passed to functions that run doctests, establishing different +defaults. In such cases, disabling an option via \code{-} in a directive +can be useful. + +\versionchanged[Constants \constant{DONT_ACCEPT_BLANKLINE}, + \constant{NORMALIZE_WHITESPACE}, \constant{ELLIPSIS}, + \constant{IGNORE_EXCEPTION_DETAIL}, + \constant{REPORT_UDIFF}, \constant{REPORT_CDIFF}, + \constant{REPORT_NDIFF}, \constant{REPORT_ONLY_FIRST_FAILURE}, + \constant{COMPARISON_FLAGS} and \constant{REPORTING_FLAGS} + were added; by default \code{} in expected output + matches an empty line in actual output; and doctest directives + were added]{2.4} +\versionchanged[Constant \constant{SKIP} was added]{2.5} + +There's also a way to register new option flag names, although this +isn't useful unless you intend to extend \refmodule{doctest} internals +via subclassing: + +\begin{funcdesc}{register_optionflag}{name} + Create a new option flag with a given name, and return the new + flag's integer value. \function{register_optionflag()} can be + used when subclassing \class{OutputChecker} or + \class{DocTestRunner} to create new options that are supported by + your subclasses. \function{register_optionflag} should always be + called using the following idiom: + +\begin{verbatim} + MY_FLAG = register_optionflag('MY_FLAG') +\end{verbatim} + + \versionadded{2.4} +\end{funcdesc} + +\subsubsection{Warnings\label{doctest-warnings}} + +\refmodule{doctest} is serious about requiring exact matches in expected +output. If even a single character doesn't match, the test fails. This +will probably surprise you a few times, as you learn exactly what Python +does and doesn't guarantee about output. For example, when printing a +dict, Python doesn't guarantee that the key-value pairs will be printed +in any particular order, so a test like + +% Hey! What happened to Monty Python examples? +% Tim: ask Guido -- it's his example! +\begin{verbatim} +>>> foo() +{"Hermione": "hippogryph", "Harry": "broomstick"} +\end{verbatim} + +is vulnerable! One workaround is to do + +\begin{verbatim} +>>> foo() == {"Hermione": "hippogryph", "Harry": "broomstick"} +True +\end{verbatim} + +instead. Another is to do + +\begin{verbatim} +>>> d = foo().items() +>>> d.sort() +>>> d +[('Harry', 'broomstick'), ('Hermione', 'hippogryph')] +\end{verbatim} + +There are others, but you get the idea. + +Another bad idea is to print things that embed an object address, like + +\begin{verbatim} +>>> id(1.0) # certain to fail some of the time +7948648 +>>> class C: pass +>>> C() # the default repr() for instances embeds an address +<__main__.C instance at 0x00AC18F0> +\end{verbatim} + +The \constant{ELLIPSIS} directive gives a nice approach for the last +example: + +\begin{verbatim} +>>> C() #doctest: +ELLIPSIS +<__main__.C instance at 0x...> +\end{verbatim} + +Floating-point numbers are also subject to small output variations across +platforms, because Python defers to the platform C library for float +formatting, and C libraries vary widely in quality here. + +\begin{verbatim} +>>> 1./7 # risky +0.14285714285714285 +>>> print 1./7 # safer +0.142857142857 +>>> print round(1./7, 6) # much safer +0.142857 +\end{verbatim} + +Numbers of the form \code{I/2.**J} are safe across all platforms, and I +often contrive doctest examples to produce numbers of that form: + +\begin{verbatim} +>>> 3./4 # utterly safe +0.75 +\end{verbatim} + +Simple fractions are also easier for people to understand, and that makes +for better documentation. + +\subsection{Basic API\label{doctest-basic-api}} + +The functions \function{testmod()} and \function{testfile()} provide a +simple interface to doctest that should be sufficient for most basic +uses. For a less formal introduction to these two functions, see +sections \ref{doctest-simple-testmod} and +\ref{doctest-simple-testfile}. + +\begin{funcdesc}{testfile}{filename\optional{, module_relative}\optional{, + name}\optional{, package}\optional{, + globs}\optional{, verbose}\optional{, + report}\optional{, optionflags}\optional{, + extraglobs}\optional{, raise_on_error}\optional{, + parser}\optional{, encoding}} + + All arguments except \var{filename} are optional, and should be + specified in keyword form. + + Test examples in the file named \var{filename}. Return + \samp{(\var{failure_count}, \var{test_count})}. + + Optional argument \var{module_relative} specifies how the filename + should be interpreted: + + \begin{itemize} + \item If \var{module_relative} is \code{True} (the default), then + \var{filename} specifies an OS-independent module-relative + path. By default, this path is relative to the calling + module's directory; but if the \var{package} argument is + specified, then it is relative to that package. To ensure + OS-independence, \var{filename} should use \code{/} characters + to separate path segments, and may not be an absolute path + (i.e., it may not begin with \code{/}). + \item If \var{module_relative} is \code{False}, then \var{filename} + specifies an OS-specific path. The path may be absolute or + relative; relative paths are resolved with respect to the + current working directory. + \end{itemize} + + Optional argument \var{name} gives the name of the test; by default, + or if \code{None}, \code{os.path.basename(\var{filename})} is used. + + Optional argument \var{package} is a Python package or the name of a + Python package whose directory should be used as the base directory + for a module-relative filename. If no package is specified, then + the calling module's directory is used as the base directory for + module-relative filenames. It is an error to specify \var{package} + if \var{module_relative} is \code{False}. + + Optional argument \var{globs} gives a dict to be used as the globals + when executing examples. A new shallow copy of this dict is + created for the doctest, so its examples start with a clean slate. + By default, or if \code{None}, a new empty dict is used. + + Optional argument \var{extraglobs} gives a dict merged into the + globals used to execute examples. This works like + \method{dict.update()}: if \var{globs} and \var{extraglobs} have a + common key, the associated value in \var{extraglobs} appears in the + combined dict. By default, or if \code{None}, no extra globals are + used. This is an advanced feature that allows parameterization of + doctests. For example, a doctest can be written for a base class, using + a generic name for the class, then reused to test any number of + subclasses by passing an \var{extraglobs} dict mapping the generic + name to the subclass to be tested. + + Optional argument \var{verbose} prints lots of stuff if true, and prints + only failures if false; by default, or if \code{None}, it's true + if and only if \code{'-v'} is in \code{sys.argv}. + + Optional argument \var{report} prints a summary at the end when true, + else prints nothing at the end. In verbose mode, the summary is + detailed, else the summary is very brief (in fact, empty if all tests + passed). + + Optional argument \var{optionflags} or's together option flags. See + section~\ref{doctest-options}. + + Optional argument \var{raise_on_error} defaults to false. If true, + an exception is raised upon the first failure or unexpected exception + in an example. This allows failures to be post-mortem debugged. + Default behavior is to continue running examples. + + Optional argument \var{parser} specifies a \class{DocTestParser} (or + subclass) that should be used to extract tests from the files. It + defaults to a normal parser (i.e., \code{\class{DocTestParser}()}). + + Optional argument \var{encoding} specifies an encoding that should + be used to convert the file to unicode. + + \versionadded{2.4} + + \versionchanged[The parameter \var{encoding} was added]{2.5} + +\end{funcdesc} + +\begin{funcdesc}{testmod}{\optional{m}\optional{, name}\optional{, + globs}\optional{, verbose}\optional{, + report}\optional{, + optionflags}\optional{, extraglobs}\optional{, + raise_on_error}\optional{, exclude_empty}} + + All arguments are optional, and all except for \var{m} should be + specified in keyword form. + + Test examples in docstrings in functions and classes reachable + from module \var{m} (or module \module{__main__} if \var{m} is not + supplied or is \code{None}), starting with \code{\var{m}.__doc__}. + + Also test examples reachable from dict \code{\var{m}.__test__}, if it + exists and is not \code{None}. \code{\var{m}.__test__} maps + names (strings) to functions, classes and strings; function and class + docstrings are searched for examples; strings are searched directly, + as if they were docstrings. + + Only docstrings attached to objects belonging to module \var{m} are + searched. + + Return \samp{(\var{failure_count}, \var{test_count})}. + + Optional argument \var{name} gives the name of the module; by default, + or if \code{None}, \code{\var{m}.__name__} is used. + + Optional argument \var{exclude_empty} defaults to false. If true, + objects for which no doctests are found are excluded from consideration. + The default is a backward compatibility hack, so that code still + using \method{doctest.master.summarize()} in conjunction with + \function{testmod()} continues to get output for objects with no tests. + The \var{exclude_empty} argument to the newer \class{DocTestFinder} + constructor defaults to true. + + Optional arguments \var{extraglobs}, \var{verbose}, \var{report}, + \var{optionflags}, \var{raise_on_error}, and \var{globs} are the same as + for function \function{testfile()} above, except that \var{globs} + defaults to \code{\var{m}.__dict__}. + + \versionchanged[The parameter \var{optionflags} was added]{2.3} + + \versionchanged[The parameters \var{extraglobs}, \var{raise_on_error} + and \var{exclude_empty} were added]{2.4} + + \versionchanged[The optional argument \var{isprivate}, deprecated + in 2.4, was removed]{2.5} + +\end{funcdesc} + +There's also a function to run the doctests associated with a single object. +This function is provided for backward compatibility. There are no plans +to deprecate it, but it's rarely useful: + +\begin{funcdesc}{run_docstring_examples}{f, globs\optional{, + verbose}\optional{, name}\optional{, + compileflags}\optional{, optionflags}} + + Test examples associated with object \var{f}; for example, \var{f} may + be a module, function, or class object. + + A shallow copy of dictionary argument \var{globs} is used for the + execution context. + + Optional argument \var{name} is used in failure messages, and defaults + to \code{"NoName"}. + + If optional argument \var{verbose} is true, output is generated even + if there are no failures. By default, output is generated only in case + of an example failure. + + Optional argument \var{compileflags} gives the set of flags that should + be used by the Python compiler when running the examples. By default, or + if \code{None}, flags are deduced corresponding to the set of future + features found in \var{globs}. + + Optional argument \var{optionflags} works as for function + \function{testfile()} above. +\end{funcdesc} + +\subsection{Unittest API\label{doctest-unittest-api}} + +As your collection of doctest'ed modules grows, you'll want a way to run +all their doctests systematically. Prior to Python 2.4, \refmodule{doctest} +had a barely documented \class{Tester} class that supplied a rudimentary +way to combine doctests from multiple modules. \class{Tester} was feeble, +and in practice most serious Python testing frameworks build on the +\refmodule{unittest} module, which supplies many flexible ways to combine +tests from multiple sources. So, in Python 2.4, \refmodule{doctest}'s +\class{Tester} class is deprecated, and \refmodule{doctest} provides two +functions that can be used to create \refmodule{unittest} test suites from +modules and text files containing doctests. These test suites can then be +run using \refmodule{unittest} test runners: + +\begin{verbatim} +import unittest +import doctest +import my_module_with_doctests, and_another + +suite = unittest.TestSuite() +for mod in my_module_with_doctests, and_another: + suite.addTest(doctest.DocTestSuite(mod)) +runner = unittest.TextTestRunner() +runner.run(suite) +\end{verbatim} + +There are two main functions for creating \class{\refmodule{unittest}.TestSuite} +instances from text files and modules with doctests: + +\begin{funcdesc}{DocFileSuite}{\optional{module_relative}\optional{, + package}\optional{, setUp}\optional{, + tearDown}\optional{, globs}\optional{, + optionflags}\optional{, parser}\optional{, + encoding}} + + Convert doctest tests from one or more text files to a + \class{\refmodule{unittest}.TestSuite}. + + The returned \class{\refmodule{unittest}.TestSuite} is to be run by the + unittest framework and runs the interactive examples in each file. If an + example in any file fails, then the synthesized unit test fails, and a + \exception{failureException} exception is raised showing the name of the + file containing the test and a (sometimes approximate) line number. + + Pass one or more paths (as strings) to text files to be examined. + + Options may be provided as keyword arguments: + + Optional argument \var{module_relative} specifies how + the filenames in \var{paths} should be interpreted: + + \begin{itemize} + \item If \var{module_relative} is \code{True} (the default), then + each filename specifies an OS-independent module-relative + path. By default, this path is relative to the calling + module's directory; but if the \var{package} argument is + specified, then it is relative to that package. To ensure + OS-independence, each filename should use \code{/} characters + to separate path segments, and may not be an absolute path + (i.e., it may not begin with \code{/}). + \item If \var{module_relative} is \code{False}, then each filename + specifies an OS-specific path. The path may be absolute or + relative; relative paths are resolved with respect to the + current working directory. + \end{itemize} + + Optional argument \var{package} is a Python package or the name + of a Python package whose directory should be used as the base + directory for module-relative filenames. If no package is + specified, then the calling module's directory is used as the base + directory for module-relative filenames. It is an error to specify + \var{package} if \var{module_relative} is \code{False}. + + Optional argument \var{setUp} specifies a set-up function for + the test suite. This is called before running the tests in each + file. The \var{setUp} function will be passed a \class{DocTest} + object. The setUp function can access the test globals as the + \var{globs} attribute of the test passed. + + Optional argument \var{tearDown} specifies a tear-down function + for the test suite. This is called after running the tests in each + file. The \var{tearDown} function will be passed a \class{DocTest} + object. The setUp function can access the test globals as the + \var{globs} attribute of the test passed. + + Optional argument \var{globs} is a dictionary containing the + initial global variables for the tests. A new copy of this + dictionary is created for each test. By default, \var{globs} is + a new empty dictionary. + + Optional argument \var{optionflags} specifies the default + doctest options for the tests, created by or-ing together + individual option flags. See section~\ref{doctest-options}. + See function \function{set_unittest_reportflags()} below for + a better way to set reporting options. + + Optional argument \var{parser} specifies a \class{DocTestParser} (or + subclass) that should be used to extract tests from the files. It + defaults to a normal parser (i.e., \code{\class{DocTestParser}()}). + + Optional argument \var{encoding} specifies an encoding that should + be used to convert the file to unicode. + + \versionadded{2.4} + + \versionchanged[The global \code{__file__} was added to the + globals provided to doctests loaded from a text file using + \function{DocFileSuite()}]{2.5} + + \versionchanged[The parameter \var{encoding} was added]{2.5} + +\end{funcdesc} + +\begin{funcdesc}{DocTestSuite}{\optional{module}\optional{, + globs}\optional{, extraglobs}\optional{, + test_finder}\optional{, setUp}\optional{, + tearDown}\optional{, checker}} + Convert doctest tests for a module to a + \class{\refmodule{unittest}.TestSuite}. + + The returned \class{\refmodule{unittest}.TestSuite} is to be run by the + unittest framework and runs each doctest in the module. If any of the + doctests fail, then the synthesized unit test fails, and a + \exception{failureException} exception is raised showing the name of the + file containing the test and a (sometimes approximate) line number. + + Optional argument \var{module} provides the module to be tested. It + can be a module object or a (possibly dotted) module name. If not + specified, the module calling this function is used. + + Optional argument \var{globs} is a dictionary containing the + initial global variables for the tests. A new copy of this + dictionary is created for each test. By default, \var{globs} is + a new empty dictionary. + + Optional argument \var{extraglobs} specifies an extra set of + global variables, which is merged into \var{globs}. By default, no + extra globals are used. + + Optional argument \var{test_finder} is the \class{DocTestFinder} + object (or a drop-in replacement) that is used to extract doctests + from the module. + + Optional arguments \var{setUp}, \var{tearDown}, and \var{optionflags} + are the same as for function \function{DocFileSuite()} above. + + \versionadded{2.3} + + \versionchanged[The parameters \var{globs}, \var{extraglobs}, + \var{test_finder}, \var{setUp}, \var{tearDown}, and + \var{optionflags} were added; this function now uses the same search + technique as \function{testmod()}]{2.4} +\end{funcdesc} + +Under the covers, \function{DocTestSuite()} creates a +\class{\refmodule{unittest}.TestSuite} out of \class{doctest.DocTestCase} +instances, and \class{DocTestCase} is a subclass of +\class{\refmodule{unittest}.TestCase}. \class{DocTestCase} isn't documented +here (it's an internal detail), but studying its code can answer questions +about the exact details of \refmodule{unittest} integration. + +Similarly, \function{DocFileSuite()} creates a +\class{\refmodule{unittest}.TestSuite} out of \class{doctest.DocFileCase} +instances, and \class{DocFileCase} is a subclass of \class{DocTestCase}. + +So both ways of creating a \class{\refmodule{unittest}.TestSuite} run +instances of \class{DocTestCase}. This is important for a subtle reason: +when you run \refmodule{doctest} functions yourself, you can control the +\refmodule{doctest} options in use directly, by passing option flags to +\refmodule{doctest} functions. However, if you're writing a +\refmodule{unittest} framework, \refmodule{unittest} ultimately controls +when and how tests get run. The framework author typically wants to +control \refmodule{doctest} reporting options (perhaps, e.g., specified by +command line options), but there's no way to pass options through +\refmodule{unittest} to \refmodule{doctest} test runners. + +For this reason, \refmodule{doctest} also supports a notion of +\refmodule{doctest} reporting flags specific to \refmodule{unittest} +support, via this function: + +\begin{funcdesc}{set_unittest_reportflags}{flags} + Set the \refmodule{doctest} reporting flags to use. + + Argument \var{flags} or's together option flags. See + section~\ref{doctest-options}. Only "reporting flags" can be used. + + This is a module-global setting, and affects all future doctests run by + module \refmodule{unittest}: the \method{runTest()} method of + \class{DocTestCase} looks at the option flags specified for the test case + when the \class{DocTestCase} instance was constructed. If no reporting + flags were specified (which is the typical and expected case), + \refmodule{doctest}'s \refmodule{unittest} reporting flags are or'ed into + the option flags, and the option flags so augmented are passed to the + \class{DocTestRunner} instance created to run the doctest. If any + reporting flags were specified when the \class{DocTestCase} instance was + constructed, \refmodule{doctest}'s \refmodule{unittest} reporting flags + are ignored. + + The value of the \refmodule{unittest} reporting flags in effect before the + function was called is returned by the function. + + \versionadded{2.4} +\end{funcdesc} + + +\subsection{Advanced API\label{doctest-advanced-api}} + +The basic API is a simple wrapper that's intended to make doctest easy +to use. It is fairly flexible, and should meet most users' needs; +however, if you require more fine-grained control over testing, or +wish to extend doctest's capabilities, then you should use the +advanced API. + +The advanced API revolves around two container classes, which are used +to store the interactive examples extracted from doctest cases: + +\begin{itemize} +\item \class{Example}: A single python statement, paired with its + expected output. +\item \class{DocTest}: A collection of \class{Example}s, typically + extracted from a single docstring or text file. +\end{itemize} + +Additional processing classes are defined to find, parse, and run, and +check doctest examples: + +\begin{itemize} +\item \class{DocTestFinder}: Finds all docstrings in a given module, + and uses a \class{DocTestParser} to create a \class{DocTest} + from every docstring that contains interactive examples. +\item \class{DocTestParser}: Creates a \class{DocTest} object from + a string (such as an object's docstring). +\item \class{DocTestRunner}: Executes the examples in a + \class{DocTest}, and uses an \class{OutputChecker} to verify + their output. +\item \class{OutputChecker}: Compares the actual output from a + doctest example with the expected output, and decides whether + they match. +\end{itemize} + +The relationships among these processing classes are summarized in the +following diagram: + +\begin{verbatim} + list of: ++------+ +---------+ +|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results ++------+ | ^ +---------+ | ^ (printed) + | | | Example | | | + v | | ... | v | + DocTestParser | Example | OutputChecker + +---------+ +\end{verbatim} + +\subsubsection{DocTest Objects\label{doctest-DocTest}} +\begin{classdesc}{DocTest}{examples, globs, name, filename, lineno, + docstring} + A collection of doctest examples that should be run in a single + namespace. The constructor arguments are used to initialize the + member variables of the same names. + \versionadded{2.4} +\end{classdesc} + +\class{DocTest} defines the following member variables. They are +initialized by the constructor, and should not be modified directly. + +\begin{memberdesc}{examples} + A list of \class{Example} objects encoding the individual + interactive Python examples that should be run by this test. +\end{memberdesc} + +\begin{memberdesc}{globs} + The namespace (aka globals) that the examples should be run in. + This is a dictionary mapping names to values. Any changes to the + namespace made by the examples (such as binding new variables) + will be reflected in \member{globs} after the test is run. +\end{memberdesc} + +\begin{memberdesc}{name} + A string name identifying the \class{DocTest}. Typically, this is + the name of the object or file that the test was extracted from. +\end{memberdesc} + +\begin{memberdesc}{filename} + The name of the file that this \class{DocTest} was extracted from; + or \code{None} if the filename is unknown, or if the + \class{DocTest} was not extracted from a file. +\end{memberdesc} + +\begin{memberdesc}{lineno} + The line number within \member{filename} where this + \class{DocTest} begins, or \code{None} if the line number is + unavailable. This line number is zero-based with respect to the + beginning of the file. +\end{memberdesc} + +\begin{memberdesc}{docstring} + The string that the test was extracted from, or `None` if the + string is unavailable, or if the test was not extracted from a + string. +\end{memberdesc} + +\subsubsection{Example Objects\label{doctest-Example}} +\begin{classdesc}{Example}{source, want\optional{, + exc_msg}\optional{, lineno}\optional{, + indent}\optional{, options}} + A single interactive example, consisting of a Python statement and + its expected output. The constructor arguments are used to + initialize the member variables of the same names. + \versionadded{2.4} +\end{classdesc} + +\class{Example} defines the following member variables. They are +initialized by the constructor, and should not be modified directly. + +\begin{memberdesc}{source} + A string containing the example's source code. This source code + consists of a single Python statement, and always ends with a + newline; the constructor adds a newline when necessary. +\end{memberdesc} + +\begin{memberdesc}{want} + The expected output from running the example's source code (either + from stdout, or a traceback in case of exception). \member{want} + ends with a newline unless no output is expected, in which case + it's an empty string. The constructor adds a newline when + necessary. +\end{memberdesc} + +\begin{memberdesc}{exc_msg} + The exception message generated by the example, if the example is + expected to generate an exception; or \code{None} if it is not + expected to generate an exception. This exception message is + compared against the return value of + \function{traceback.format_exception_only()}. \member{exc_msg} + ends with a newline unless it's \code{None}. The constructor adds + a newline if needed. +\end{memberdesc} + +\begin{memberdesc}{lineno} + The line number within the string containing this example where + the example begins. This line number is zero-based with respect + to the beginning of the containing string. +\end{memberdesc} + +\begin{memberdesc}{indent} + The example's indentation in the containing string, i.e., the + number of space characters that precede the example's first + prompt. +\end{memberdesc} + +\begin{memberdesc}{options} + A dictionary mapping from option flags to \code{True} or + \code{False}, which is used to override default options for this + example. Any option flags not contained in this dictionary are + left at their default value (as specified by the + \class{DocTestRunner}'s \member{optionflags}). + By default, no options are set. +\end{memberdesc} + +\subsubsection{DocTestFinder objects\label{doctest-DocTestFinder}} +\begin{classdesc}{DocTestFinder}{\optional{verbose}\optional{, + parser}\optional{, recurse}\optional{, + exclude_empty}} + A processing class used to extract the \class{DocTest}s that are + relevant to a given object, from its docstring and the docstrings + of its contained objects. \class{DocTest}s can currently be + extracted from the following object types: modules, functions, + classes, methods, staticmethods, classmethods, and properties. + + The optional argument \var{verbose} can be used to display the + objects searched by the finder. It defaults to \code{False} (no + output). + + The optional argument \var{parser} specifies the + \class{DocTestParser} object (or a drop-in replacement) that is + used to extract doctests from docstrings. + + If the optional argument \var{recurse} is false, then + \method{DocTestFinder.find()} will only examine the given object, + and not any contained objects. + + If the optional argument \var{exclude_empty} is false, then + \method{DocTestFinder.find()} will include tests for objects with + empty docstrings. + + \versionadded{2.4} +\end{classdesc} + +\class{DocTestFinder} defines the following method: + +\begin{methoddesc}{find}{obj\optional{, name}\optional{, + module}\optional{, globs}\optional{, extraglobs}} + Return a list of the \class{DocTest}s that are defined by + \var{obj}'s docstring, or by any of its contained objects' + docstrings. + + The optional argument \var{name} specifies the object's name; this + name will be used to construct names for the returned + \class{DocTest}s. If \var{name} is not specified, then + \code{\var{obj}.__name__} is used. + + The optional parameter \var{module} is the module that contains + the given object. If the module is not specified or is None, then + the test finder will attempt to automatically determine the + correct module. The object's module is used: + + \begin{itemize} + \item As a default namespace, if \var{globs} is not specified. + \item To prevent the DocTestFinder from extracting DocTests + from objects that are imported from other modules. (Contained + objects with modules other than \var{module} are ignored.) + \item To find the name of the file containing the object. + \item To help find the line number of the object within its file. + \end{itemize} + + If \var{module} is \code{False}, no attempt to find the module + will be made. This is obscure, of use mostly in testing doctest + itself: if \var{module} is \code{False}, or is \code{None} but + cannot be found automatically, then all objects are considered to + belong to the (non-existent) module, so all contained objects will + (recursively) be searched for doctests. + + The globals for each \class{DocTest} is formed by combining + \var{globs} and \var{extraglobs} (bindings in \var{extraglobs} + override bindings in \var{globs}). A new shallow copy of the globals + dictionary is created for each \class{DocTest}. If \var{globs} is + not specified, then it defaults to the module's \var{__dict__}, if + specified, or \code{\{\}} otherwise. If \var{extraglobs} is not + specified, then it defaults to \code{\{\}}. +\end{methoddesc} + +\subsubsection{DocTestParser objects\label{doctest-DocTestParser}} +\begin{classdesc}{DocTestParser}{} + A processing class used to extract interactive examples from a + string, and use them to create a \class{DocTest} object. + \versionadded{2.4} +\end{classdesc} + +\class{DocTestParser} defines the following methods: + +\begin{methoddesc}{get_doctest}{string, globs, name, filename, lineno} + Extract all doctest examples from the given string, and collect + them into a \class{DocTest} object. + + \var{globs}, \var{name}, \var{filename}, and \var{lineno} are + attributes for the new \class{DocTest} object. See the + documentation for \class{DocTest} for more information. +\end{methoddesc} + +\begin{methoddesc}{get_examples}{string\optional{, name}} + Extract all doctest examples from the given string, and return + them as a list of \class{Example} objects. Line numbers are + 0-based. The optional argument \var{name} is a name identifying + this string, and is only used for error messages. +\end{methoddesc} + +\begin{methoddesc}{parse}{string\optional{, name}} + Divide the given string into examples and intervening text, and + return them as a list of alternating \class{Example}s and strings. + Line numbers for the \class{Example}s are 0-based. The optional + argument \var{name} is a name identifying this string, and is only + used for error messages. +\end{methoddesc} + +\subsubsection{DocTestRunner objects\label{doctest-DocTestRunner}} +\begin{classdesc}{DocTestRunner}{\optional{checker}\optional{, + verbose}\optional{, optionflags}} + A processing class used to execute and verify the interactive + examples in a \class{DocTest}. + + The comparison between expected outputs and actual outputs is done + by an \class{OutputChecker}. This comparison may be customized + with a number of option flags; see section~\ref{doctest-options} + for more information. If the option flags are insufficient, then + the comparison may also be customized by passing a subclass of + \class{OutputChecker} to the constructor. + + The test runner's display output can be controlled in two ways. + First, an output function can be passed to + \method{TestRunner.run()}; this function will be called with + strings that should be displayed. It defaults to + \code{sys.stdout.write}. If capturing the output is not + sufficient, then the display output can be also customized by + subclassing DocTestRunner, and overriding the methods + \method{report_start}, \method{report_success}, + \method{report_unexpected_exception}, and \method{report_failure}. + + The optional keyword argument \var{checker} specifies the + \class{OutputChecker} object (or drop-in replacement) that should + be used to compare the expected outputs to the actual outputs of + doctest examples. + + The optional keyword argument \var{verbose} controls the + \class{DocTestRunner}'s verbosity. If \var{verbose} is + \code{True}, then information is printed about each example, as it + is run. If \var{verbose} is \code{False}, then only failures are + printed. If \var{verbose} is unspecified, or \code{None}, then + verbose output is used iff the command-line switch \programopt{-v} + is used. + + The optional keyword argument \var{optionflags} can be used to + control how the test runner compares expected output to actual + output, and how it displays failures. For more information, see + section~\ref{doctest-options}. + + \versionadded{2.4} +\end{classdesc} + +\class{DocTestParser} defines the following methods: + +\begin{methoddesc}{report_start}{out, test, example} + Report that the test runner is about to process the given example. + This method is provided to allow subclasses of + \class{DocTestRunner} to customize their output; it should not be + called directly. + + \var{example} is the example about to be processed. \var{test} is + the test containing \var{example}. \var{out} is the output + function that was passed to \method{DocTestRunner.run()}. +\end{methoddesc} + +\begin{methoddesc}{report_success}{out, test, example, got} + Report that the given example ran successfully. This method is + provided to allow subclasses of \class{DocTestRunner} to customize + their output; it should not be called directly. + + \var{example} is the example about to be processed. \var{got} is + the actual output from the example. \var{test} is the test + containing \var{example}. \var{out} is the output function that + was passed to \method{DocTestRunner.run()}. +\end{methoddesc} + +\begin{methoddesc}{report_failure}{out, test, example, got} + Report that the given example failed. This method is provided to + allow subclasses of \class{DocTestRunner} to customize their + output; it should not be called directly. + + \var{example} is the example about to be processed. \var{got} is + the actual output from the example. \var{test} is the test + containing \var{example}. \var{out} is the output function that + was passed to \method{DocTestRunner.run()}. +\end{methoddesc} + +\begin{methoddesc}{report_unexpected_exception}{out, test, example, exc_info} + Report that the given example raised an unexpected exception. + This method is provided to allow subclasses of + \class{DocTestRunner} to customize their output; it should not be + called directly. + + \var{example} is the example about to be processed. + \var{exc_info} is a tuple containing information about the + unexpected exception (as returned by \function{sys.exc_info()}). + \var{test} is the test containing \var{example}. \var{out} is the + output function that was passed to \method{DocTestRunner.run()}. +\end{methoddesc} + +\begin{methoddesc}{run}{test\optional{, compileflags}\optional{, + out}\optional{, clear_globs}} + Run the examples in \var{test} (a \class{DocTest} object), and + display the results using the writer function \var{out}. + + The examples are run in the namespace \code{test.globs}. If + \var{clear_globs} is true (the default), then this namespace will + be cleared after the test runs, to help with garbage collection. + If you would like to examine the namespace after the test + completes, then use \var{clear_globs=False}. + + \var{compileflags} gives the set of flags that should be used by + the Python compiler when running the examples. If not specified, + then it will default to the set of future-import flags that apply + to \var{globs}. + + The output of each example is checked using the + \class{DocTestRunner}'s output checker, and the results are + formatted by the \method{DocTestRunner.report_*} methods. +\end{methoddesc} + +\begin{methoddesc}{summarize}{\optional{verbose}} + Print a summary of all the test cases that have been run by this + DocTestRunner, and return a tuple \samp{(\var{failure_count}, + \var{test_count})}. + + The optional \var{verbose} argument controls how detailed the + summary is. If the verbosity is not specified, then the + \class{DocTestRunner}'s verbosity is used. +\end{methoddesc} + +\subsubsection{OutputChecker objects\label{doctest-OutputChecker}} + +\begin{classdesc}{OutputChecker}{} + A class used to check the whether the actual output from a doctest + example matches the expected output. \class{OutputChecker} + defines two methods: \method{check_output}, which compares a given + pair of outputs, and returns true if they match; and + \method{output_difference}, which returns a string describing the + differences between two outputs. + \versionadded{2.4} +\end{classdesc} + +\class{OutputChecker} defines the following methods: + +\begin{methoddesc}{check_output}{want, got, optionflags} + Return \code{True} iff the actual output from an example + (\var{got}) matches the expected output (\var{want}). These + strings are always considered to match if they are identical; but + depending on what option flags the test runner is using, several + non-exact match types are also possible. See + section~\ref{doctest-options} for more information about option + flags. +\end{methoddesc} + +\begin{methoddesc}{output_difference}{example, got, optionflags} + Return a string describing the differences between the expected + output for a given example (\var{example}) and the actual output + (\var{got}). \var{optionflags} is the set of option flags used to + compare \var{want} and \var{got}. +\end{methoddesc} + +\subsection{Debugging\label{doctest-debugging}} + +Doctest provides several mechanisms for debugging doctest examples: + +\begin{itemize} +\item Several functions convert doctests to executable Python + programs, which can be run under the Python debugger, \refmodule{pdb}. +\item The \class{DebugRunner} class is a subclass of + \class{DocTestRunner} that raises an exception for the first + failing example, containing information about that example. + This information can be used to perform post-mortem debugging on + the example. +\item The \refmodule{unittest} cases generated by \function{DocTestSuite()} + support the \method{debug()} method defined by + \class{\refmodule{unittest}.TestCase}. +\item You can add a call to \function{\refmodule{pdb}.set_trace()} in a + doctest example, and you'll drop into the Python debugger when that + line is executed. Then you can inspect current values of variables, + and so on. For example, suppose \file{a.py} contains just this + module docstring: + +\begin{verbatim} +""" +>>> def f(x): +... g(x*2) +>>> def g(x): +... print x+3 +... import pdb; pdb.set_trace() +>>> f(3) +9 +""" +\end{verbatim} + + Then an interactive Python session may look like this: + +\begin{verbatim} +>>> import a, doctest +>>> doctest.testmod(a) +--Return-- +> (3)g()->None +-> import pdb; pdb.set_trace() +(Pdb) list + 1 def g(x): + 2 print x+3 + 3 -> import pdb; pdb.set_trace() +[EOF] +(Pdb) print x +6 +(Pdb) step +--Return-- +> (2)f()->None +-> g(x*2) +(Pdb) list + 1 def f(x): + 2 -> g(x*2) +[EOF] +(Pdb) print x +3 +(Pdb) step +--Return-- +> (1)?()->None +-> f(3) +(Pdb) cont +(0, 3) +>>> +\end{verbatim} + + \versionchanged[The ability to use \code{\refmodule{pdb}.set_trace()} + usefully inside doctests was added]{2.4} +\end{itemize} + +Functions that convert doctests to Python code, and possibly run +the synthesized code under the debugger: + +\begin{funcdesc}{script_from_examples}{s} + Convert text with examples to a script. + + Argument \var{s} is a string containing doctest examples. The string + is converted to a Python script, where doctest examples in \var{s} + are converted to regular code, and everything else is converted to + Python comments. The generated script is returned as a string. + For example, + + \begin{verbatim} + import doctest + print doctest.script_from_examples(r""" + Set x and y to 1 and 2. + >>> x, y = 1, 2 + + Print their sum: + >>> print x+y + 3 + """) + \end{verbatim} + + displays: + + \begin{verbatim} + # Set x and y to 1 and 2. + x, y = 1, 2 + # + # Print their sum: + print x+y + # Expected: + ## 3 + \end{verbatim} + + This function is used internally by other functions (see below), but + can also be useful when you want to transform an interactive Python + session into a Python script. + + \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{testsource}{module, name} + Convert the doctest for an object to a script. + + Argument \var{module} is a module object, or dotted name of a module, + containing the object whose doctests are of interest. Argument + \var{name} is the name (within the module) of the object with the + doctests of interest. The result is a string, containing the + object's docstring converted to a Python script, as described for + \function{script_from_examples()} above. For example, if module + \file{a.py} contains a top-level function \function{f()}, then + +\begin{verbatim} +import a, doctest +print doctest.testsource(a, "a.f") +\end{verbatim} + + prints a script version of function \function{f()}'s docstring, + with doctests converted to code, and the rest placed in comments. + + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{debug}{module, name\optional{, pm}} + Debug the doctests for an object. + + The \var{module} and \var{name} arguments are the same as for function + \function{testsource()} above. The synthesized Python script for the + named object's docstring is written to a temporary file, and then that + file is run under the control of the Python debugger, \refmodule{pdb}. + + A shallow copy of \code{\var{module}.__dict__} is used for both local + and global execution context. + + Optional argument \var{pm} controls whether post-mortem debugging is + used. If \var{pm} has a true value, the script file is run directly, and + the debugger gets involved only if the script terminates via raising an + unhandled exception. If it does, then post-mortem debugging is invoked, + via \code{\refmodule{pdb}.post_mortem()}, passing the traceback object + from the unhandled exception. If \var{pm} is not specified, or is false, + the script is run under the debugger from the start, via passing an + appropriate \function{execfile()} call to \code{\refmodule{pdb}.run()}. + + \versionadded{2.3} + + \versionchanged[The \var{pm} argument was added]{2.4} +\end{funcdesc} + +\begin{funcdesc}{debug_src}{src\optional{, pm}\optional{, globs}} + Debug the doctests in a string. + + This is like function \function{debug()} above, except that + a string containing doctest examples is specified directly, via + the \var{src} argument. + + Optional argument \var{pm} has the same meaning as in function + \function{debug()} above. + + Optional argument \var{globs} gives a dictionary to use as both + local and global execution context. If not specified, or \code{None}, + an empty dictionary is used. If specified, a shallow copy of the + dictionary is used. + + \versionadded{2.4} +\end{funcdesc} + +The \class{DebugRunner} class, and the special exceptions it may raise, +are of most interest to testing framework authors, and will only be +sketched here. See the source code, and especially \class{DebugRunner}'s +docstring (which is a doctest!) for more details: + +\begin{classdesc}{DebugRunner}{\optional{checker}\optional{, + verbose}\optional{, optionflags}} + + A subclass of \class{DocTestRunner} that raises an exception as + soon as a failure is encountered. If an unexpected exception + occurs, an \exception{UnexpectedException} exception is raised, + containing the test, the example, and the original exception. If + the output doesn't match, then a \exception{DocTestFailure} + exception is raised, containing the test, the example, and the + actual output. + + For information about the constructor parameters and methods, see + the documentation for \class{DocTestRunner} in + section~\ref{doctest-advanced-api}. +\end{classdesc} + +There are two exceptions that may be raised by \class{DebugRunner} +instances: + +\begin{excclassdesc}{DocTestFailure}{test, example, got} + An exception thrown by \class{DocTestRunner} to signal that a + doctest example's actual output did not match its expected output. + The constructor arguments are used to initialize the member + variables of the same names. +\end{excclassdesc} +\exception{DocTestFailure} defines the following member variables: +\begin{memberdesc}{test} + The \class{DocTest} object that was being run when the example failed. +\end{memberdesc} +\begin{memberdesc}{example} + The \class{Example} that failed. +\end{memberdesc} +\begin{memberdesc}{got} + The example's actual output. +\end{memberdesc} + +\begin{excclassdesc}{UnexpectedException}{test, example, exc_info} + An exception thrown by \class{DocTestRunner} to signal that a + doctest example raised an unexpected exception. The constructor + arguments are used to initialize the member variables of the same + names. +\end{excclassdesc} +\exception{UnexpectedException} defines the following member variables: +\begin{memberdesc}{test} + The \class{DocTest} object that was being run when the example failed. +\end{memberdesc} +\begin{memberdesc}{example} + The \class{Example} that failed. +\end{memberdesc} +\begin{memberdesc}{exc_info} + A tuple containing information about the unexpected exception, as + returned by \function{sys.exc_info()}. +\end{memberdesc} + +\subsection{Soapbox\label{doctest-soapbox}} + +As mentioned in the introduction, \refmodule{doctest} has grown to have +three primary uses: + +\begin{enumerate} +\item Checking examples in docstrings. +\item Regression testing. +\item Executable documentation / literate testing. +\end{enumerate} + +These uses have different requirements, and it is important to +distinguish them. In particular, filling your docstrings with obscure +test cases makes for bad documentation. + +When writing a docstring, choose docstring examples with care. +There's an art to this that needs to be learned---it may not be +natural at first. Examples should add genuine value to the +documentation. A good example can often be worth many words. +If done with care, the examples will be invaluable for your users, and +will pay back the time it takes to collect them many times over as the +years go by and things change. I'm still amazed at how often one of +my \refmodule{doctest} examples stops working after a "harmless" +change. + +Doctest also makes an excellent tool for regression testing, especially if +you don't skimp on explanatory text. By interleaving prose and examples, +it becomes much easier to keep track of what's actually being tested, and +why. When a test fails, good prose can make it much easier to figure out +what the problem is, and how it should be fixed. It's true that you could +write extensive comments in code-based testing, but few programmers do. +Many have found that using doctest approaches instead leads to much clearer +tests. Perhaps this is simply because doctest makes writing prose a little +easier than writing code, while writing comments in code is a little +harder. I think it goes deeper than just that: the natural attitude +when writing a doctest-based test is that you want to explain the fine +points of your software, and illustrate them with examples. This in +turn naturally leads to test files that start with the simplest features, +and logically progress to complications and edge cases. A coherent +narrative is the result, instead of a collection of isolated functions +that test isolated bits of functionality seemingly at random. It's +a different attitude, and produces different results, blurring the +distinction between testing and explaining. + +Regression testing is best confined to dedicated objects or files. There +are several options for organizing tests: + +\begin{itemize} +\item Write text files containing test cases as interactive examples, + and test the files using \function{testfile()} or + \function{DocFileSuite()}. This is recommended, although is + easiest to do for new projects, designed from the start to use + doctest. +\item Define functions named \code{_regrtest_\textit{topic}} that + consist of single docstrings, containing test cases for the + named topics. These functions can be included in the same file + as the module, or separated out into a separate test file. +\item Define a \code{__test__} dictionary mapping from regression test + topics to docstrings containing test cases. +\end{itemize} diff --git a/sys/src/cmd/python/Doc/lib/libdocxmlrpc.tex b/sys/src/cmd/python/Doc/lib/libdocxmlrpc.tex new file mode 100644 index 000000000..2f1e6caa5 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdocxmlrpc.tex @@ -0,0 +1,105 @@ +\section{\module{DocXMLRPCServer} --- + Self-documenting XML-RPC server} + +\declaremodule{standard}{DocXMLRPCServer} +\modulesynopsis{Self-documenting XML-RPC server implementation.} +\moduleauthor{Brian Quinlan}{brianq@activestate.com} +\sectionauthor{Brian Quinlan}{brianq@activestate.com} + +\versionadded{2.3} + +The \module{DocXMLRPCServer} module extends the classes found in +\module{SimpleXMLRPCServer} to serve HTML documentation in response to +HTTP GET requests. Servers can either be free standing, using +\class{DocXMLRPCServer}, or embedded in a CGI environment, using +\class{DocCGIXMLRPCRequestHandler}. + +\begin{classdesc}{DocXMLRPCServer}{addr\optional{, + requestHandler\optional{, logRequests}}} + +Create a new server instance. All parameters have the same meaning as +for \class{SimpleXMLRPCServer.SimpleXMLRPCServer}; +\var{requestHandler} defaults to \class{DocXMLRPCRequestHandler}. + +\end{classdesc} + +\begin{classdesc}{DocCGIXMLRPCRequestHandler}{} + +Create a new instance to handle XML-RPC requests in a CGI environment. + +\end{classdesc} + +\begin{classdesc}{DocXMLRPCRequestHandler}{} + +Create a new request handler instance. This request handler supports +XML-RPC POST requests, documentation GET requests, and modifies +logging so that the \var{logRequests} parameter to the +\class{DocXMLRPCServer} constructor parameter is honored. + +\end{classdesc} + +\subsection{DocXMLRPCServer Objects \label{doc-xmlrpc-servers}} + +The \class{DocXMLRPCServer} class is derived from +\class{SimpleXMLRPCServer.SimpleXMLRPCServer} and provides a means of +creating self-documenting, stand alone XML-RPC servers. HTTP POST +requests are handled as XML-RPC method calls. HTTP GET requests are +handled by generating pydoc-style HTML documentation. This allows a +server to provide its own web-based documentation. + +\begin{methoddesc}{set_server_title}{server_title} + +Set the title used in the generated HTML documentation. This title +will be used inside the HTML "title" element. + +\end{methoddesc} + +\begin{methoddesc}{set_server_name}{server_name} + +Set the name used in the generated HTML documentation. This name will +appear at the top of the generated documentation inside a "h1" +element. + +\end{methoddesc} + + +\begin{methoddesc}{set_server_documentation}{server_documentation} + +Set the description used in the generated HTML documentation. This +description will appear as a paragraph, below the server name, in the +documentation. + +\end{methoddesc} + +\subsection{DocCGIXMLRPCRequestHandler} + +The \class{DocCGIXMLRPCRequestHandler} class is derived from +\class{SimpleXMLRPCServer.CGIXMLRPCRequestHandler} and provides a means +of creating self-documenting, XML-RPC CGI scripts. HTTP POST requests +are handled as XML-RPC method calls. HTTP GET requests are handled by +generating pydoc-style HTML documentation. This allows a server to +provide its own web-based documentation. + +\begin{methoddesc}{set_server_title}{server_title} + +Set the title used in the generated HTML documentation. This title +will be used inside the HTML "title" element. + +\end{methoddesc} + +\begin{methoddesc}{set_server_name}{server_name} + +Set the name used in the generated HTML documentation. This name will +appear at the top of the generated documentation inside a "h1" +element. + +\end{methoddesc} + + +\begin{methoddesc}{set_server_documentation}{server_documentation} + +Set the description used in the generated HTML documentation. This +description will appear as a paragraph, below the server name, in the +documentation. + +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libdumbdbm.tex b/sys/src/cmd/python/Doc/lib/libdumbdbm.tex new file mode 100644 index 000000000..44957748f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdumbdbm.tex @@ -0,0 +1,63 @@ +\section{\module{dumbdbm} --- + Portable DBM implementation} + +\declaremodule{standard}{dumbdbm} +\modulesynopsis{Portable implementation of the simple DBM interface.} + +\index{databases} + +\begin{notice} +The \module{dumbdbm} module is intended as a last resort fallback for +the \refmodule{anydbm} module when no more robust module is available. +The \module{dumbdbm} module is not written for speed and is not nearly as +heavily used as the other database modules. +\end{notice} + +The \module{dumbdbm} module provides a persistent dictionary-like interface +which is written entirely in Python. Unlike other modules such as +\refmodule{gdbm} and \refmodule{bsddb}, no external library is required. As +with other persistent mappings, the keys and values must always be strings. + +The module defines the following: + +\begin{excdesc}{error} +Raised on dumbdbm-specific errors, such as I/O errors. \exception{KeyError} +is raised for general mapping errors like specifying an incorrect key. +\end{excdesc} + +\begin{funcdesc}{open}{filename\optional{, flag\optional{, mode}}} +Open a dumbdbm database and return a dumbdbm object. The \var{filename} +argument is the basename of the database file (without any specific +extensions). When a dumbdbm database is created, files with \file{.dat} and +\file{.dir} extensions are created. + +The optional \var{flag} argument is currently ignored; the database is +always opened for update, and will be created if it does not exist. + +The optional \var{mode} argument is the \UNIX{} mode of the file, used +only when the database has to be created. It defaults to octal +\code{0666} (and will be modified by the prevailing umask). +\versionchanged[The \var{mode} argument was ignored in earlier + versions]{2.2} +\end{funcdesc} + + +\begin{seealso} + \seemodule{anydbm}{Generic interface to \code{dbm}-style databases.} + \seemodule{dbm}{Similar interface to the DBM/NDBM library.} + \seemodule{gdbm}{Similar interface to the GNU GDBM library.} + \seemodule{shelve}{Persistence module which stores non-string data.} + \seemodule{whichdb}{Utility module used to determine the type of an + existing database.} +\end{seealso} + + +\subsection{Dumbdbm Objects \label{dumbdbm-objects}} + +In addition to the methods provided by the \class{UserDict.DictMixin} class, +\class{dumbdbm} objects provide the following methods. + +\begin{methoddesc}{sync}{} +Synchronize the on-disk directory and data files. This method is called by +the \method{sync} method of \class{Shelve} objects. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libdummythread.tex b/sys/src/cmd/python/Doc/lib/libdummythread.tex new file mode 100644 index 000000000..f6b4c5663 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdummythread.tex @@ -0,0 +1,22 @@ +\section{\module{dummy_thread} --- + Drop-in replacement for the \module{thread} module} + +\declaremodule[dummythread]{standard}{dummy_thread} +\modulesynopsis{Drop-in replacement for the \refmodule{thread} module.} + +This module provides a duplicate interface to the \refmodule{thread} +module. It is meant to be imported when the \refmodule{thread} module +is not provided on a platform. + +Suggested usage is: + +\begin{verbatim} +try: + import thread as _thread +except ImportError: + import dummy_thread as _thread +\end{verbatim} + +Be careful to not use this module where deadlock might occur from a thread +being created that blocks waiting for another thread to be created. This +often occurs with blocking I/O. diff --git a/sys/src/cmd/python/Doc/lib/libdummythreading.tex b/sys/src/cmd/python/Doc/lib/libdummythreading.tex new file mode 100644 index 000000000..874f596b8 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libdummythreading.tex @@ -0,0 +1,22 @@ +\section{\module{dummy_threading} --- + Drop-in replacement for the \module{threading} module} + +\declaremodule[dummythreading]{standard}{dummy_threading} +\modulesynopsis{Drop-in replacement for the \refmodule{threading} module.} + +This module provides a duplicate interface to the +\refmodule{threading} module. It is meant to be imported when the +\refmodule{thread} module is not provided on a platform. + +Suggested usage is: + +\begin{verbatim} +try: + import threading as _threading +except ImportError: + import dummy_threading as _threading +\end{verbatim} + +Be careful to not use this module where deadlock might occur from a thread +being created that blocks waiting for another thread to be created. This +often occurs with blocking I/O. diff --git a/sys/src/cmd/python/Doc/lib/liberrno.tex b/sys/src/cmd/python/Doc/lib/liberrno.tex new file mode 100644 index 000000000..c0ce6e8b3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/liberrno.tex @@ -0,0 +1,149 @@ +\section{\module{errno} --- + Standard errno system symbols} + +\declaremodule{standard}{errno} +\modulesynopsis{Standard errno system symbols.} + + +This module makes available standard \code{errno} system symbols. +The value of each symbol is the corresponding integer value. +The names and descriptions are borrowed from \file{linux/include/errno.h}, +which should be pretty all-inclusive. + +\begin{datadesc}{errorcode} + Dictionary providing a mapping from the errno value to the string + name in the underlying system. For instance, + \code{errno.errorcode[errno.EPERM]} maps to \code{'EPERM'}. +\end{datadesc} + +To translate a numeric error code to an error message, use +\function{os.strerror()}. + +Of the following list, symbols that are not used on the current +platform are not defined by the module. The specific list of defined +symbols is available as \code{errno.errorcode.keys()}. Symbols +available can include: + +\begin{datadesc}{EPERM} Operation not permitted \end{datadesc} +\begin{datadesc}{ENOENT} No such file or directory \end{datadesc} +\begin{datadesc}{ESRCH} No such process \end{datadesc} +\begin{datadesc}{EINTR} Interrupted system call \end{datadesc} +\begin{datadesc}{EIO} I/O error \end{datadesc} +\begin{datadesc}{ENXIO} No such device or address \end{datadesc} +\begin{datadesc}{E2BIG} Arg list too long \end{datadesc} +\begin{datadesc}{ENOEXEC} Exec format error \end{datadesc} +\begin{datadesc}{EBADF} Bad file number \end{datadesc} +\begin{datadesc}{ECHILD} No child processes \end{datadesc} +\begin{datadesc}{EAGAIN} Try again \end{datadesc} +\begin{datadesc}{ENOMEM} Out of memory \end{datadesc} +\begin{datadesc}{EACCES} Permission denied \end{datadesc} +\begin{datadesc}{EFAULT} Bad address \end{datadesc} +\begin{datadesc}{ENOTBLK} Block device required \end{datadesc} +\begin{datadesc}{EBUSY} Device or resource busy \end{datadesc} +\begin{datadesc}{EEXIST} File exists \end{datadesc} +\begin{datadesc}{EXDEV} Cross-device link \end{datadesc} +\begin{datadesc}{ENODEV} No such device \end{datadesc} +\begin{datadesc}{ENOTDIR} Not a directory \end{datadesc} +\begin{datadesc}{EISDIR} Is a directory \end{datadesc} +\begin{datadesc}{EINVAL} Invalid argument \end{datadesc} +\begin{datadesc}{ENFILE} File table overflow \end{datadesc} +\begin{datadesc}{EMFILE} Too many open files \end{datadesc} +\begin{datadesc}{ENOTTY} Not a typewriter \end{datadesc} +\begin{datadesc}{ETXTBSY} Text file busy \end{datadesc} +\begin{datadesc}{EFBIG} File too large \end{datadesc} +\begin{datadesc}{ENOSPC} No space left on device \end{datadesc} +\begin{datadesc}{ESPIPE} Illegal seek \end{datadesc} +\begin{datadesc}{EROFS} Read-only file system \end{datadesc} +\begin{datadesc}{EMLINK} Too many links \end{datadesc} +\begin{datadesc}{EPIPE} Broken pipe \end{datadesc} +\begin{datadesc}{EDOM} Math argument out of domain of func \end{datadesc} +\begin{datadesc}{ERANGE} Math result not representable \end{datadesc} +\begin{datadesc}{EDEADLK} Resource deadlock would occur \end{datadesc} +\begin{datadesc}{ENAMETOOLONG} File name too long \end{datadesc} +\begin{datadesc}{ENOLCK} No record locks available \end{datadesc} +\begin{datadesc}{ENOSYS} Function not implemented \end{datadesc} +\begin{datadesc}{ENOTEMPTY} Directory not empty \end{datadesc} +\begin{datadesc}{ELOOP} Too many symbolic links encountered \end{datadesc} +\begin{datadesc}{EWOULDBLOCK} Operation would block \end{datadesc} +\begin{datadesc}{ENOMSG} No message of desired type \end{datadesc} +\begin{datadesc}{EIDRM} Identifier removed \end{datadesc} +\begin{datadesc}{ECHRNG} Channel number out of range \end{datadesc} +\begin{datadesc}{EL2NSYNC} Level 2 not synchronized \end{datadesc} +\begin{datadesc}{EL3HLT} Level 3 halted \end{datadesc} +\begin{datadesc}{EL3RST} Level 3 reset \end{datadesc} +\begin{datadesc}{ELNRNG} Link number out of range \end{datadesc} +\begin{datadesc}{EUNATCH} Protocol driver not attached \end{datadesc} +\begin{datadesc}{ENOCSI} No CSI structure available \end{datadesc} +\begin{datadesc}{EL2HLT} Level 2 halted \end{datadesc} +\begin{datadesc}{EBADE} Invalid exchange \end{datadesc} +\begin{datadesc}{EBADR} Invalid request descriptor \end{datadesc} +\begin{datadesc}{EXFULL} Exchange full \end{datadesc} +\begin{datadesc}{ENOANO} No anode \end{datadesc} +\begin{datadesc}{EBADRQC} Invalid request code \end{datadesc} +\begin{datadesc}{EBADSLT} Invalid slot \end{datadesc} +\begin{datadesc}{EDEADLOCK} File locking deadlock error \end{datadesc} +\begin{datadesc}{EBFONT} Bad font file format \end{datadesc} +\begin{datadesc}{ENOSTR} Device not a stream \end{datadesc} +\begin{datadesc}{ENODATA} No data available \end{datadesc} +\begin{datadesc}{ETIME} Timer expired \end{datadesc} +\begin{datadesc}{ENOSR} Out of streams resources \end{datadesc} +\begin{datadesc}{ENONET} Machine is not on the network \end{datadesc} +\begin{datadesc}{ENOPKG} Package not installed \end{datadesc} +\begin{datadesc}{EREMOTE} Object is remote \end{datadesc} +\begin{datadesc}{ENOLINK} Link has been severed \end{datadesc} +\begin{datadesc}{EADV} Advertise error \end{datadesc} +\begin{datadesc}{ESRMNT} Srmount error \end{datadesc} +\begin{datadesc}{ECOMM} Communication error on send \end{datadesc} +\begin{datadesc}{EPROTO} Protocol error \end{datadesc} +\begin{datadesc}{EMULTIHOP} Multihop attempted \end{datadesc} +\begin{datadesc}{EDOTDOT} RFS specific error \end{datadesc} +\begin{datadesc}{EBADMSG} Not a data message \end{datadesc} +\begin{datadesc}{EOVERFLOW} Value too large for defined data type \end{datadesc} +\begin{datadesc}{ENOTUNIQ} Name not unique on network \end{datadesc} +\begin{datadesc}{EBADFD} File descriptor in bad state \end{datadesc} +\begin{datadesc}{EREMCHG} Remote address changed \end{datadesc} +\begin{datadesc}{ELIBACC} Can not access a needed shared library \end{datadesc} +\begin{datadesc}{ELIBBAD} Accessing a corrupted shared library \end{datadesc} +\begin{datadesc}{ELIBSCN} .lib section in a.out corrupted \end{datadesc} +\begin{datadesc}{ELIBMAX} Attempting to link in too many shared libraries \end{datadesc} +\begin{datadesc}{ELIBEXEC} Cannot exec a shared library directly \end{datadesc} +\begin{datadesc}{EILSEQ} Illegal byte sequence \end{datadesc} +\begin{datadesc}{ERESTART} Interrupted system call should be restarted \end{datadesc} +\begin{datadesc}{ESTRPIPE} Streams pipe error \end{datadesc} +\begin{datadesc}{EUSERS} Too many users \end{datadesc} +\begin{datadesc}{ENOTSOCK} Socket operation on non-socket \end{datadesc} +\begin{datadesc}{EDESTADDRREQ} Destination address required \end{datadesc} +\begin{datadesc}{EMSGSIZE} Message too long \end{datadesc} +\begin{datadesc}{EPROTOTYPE} Protocol wrong type for socket \end{datadesc} +\begin{datadesc}{ENOPROTOOPT} Protocol not available \end{datadesc} +\begin{datadesc}{EPROTONOSUPPORT} Protocol not supported \end{datadesc} +\begin{datadesc}{ESOCKTNOSUPPORT} Socket type not supported \end{datadesc} +\begin{datadesc}{EOPNOTSUPP} Operation not supported on transport endpoint \end{datadesc} +\begin{datadesc}{EPFNOSUPPORT} Protocol family not supported \end{datadesc} +\begin{datadesc}{EAFNOSUPPORT} Address family not supported by protocol \end{datadesc} +\begin{datadesc}{EADDRINUSE} Address already in use \end{datadesc} +\begin{datadesc}{EADDRNOTAVAIL} Cannot assign requested address \end{datadesc} +\begin{datadesc}{ENETDOWN} Network is down \end{datadesc} +\begin{datadesc}{ENETUNREACH} Network is unreachable \end{datadesc} +\begin{datadesc}{ENETRESET} Network dropped connection because of reset \end{datadesc} +\begin{datadesc}{ECONNABORTED} Software caused connection abort \end{datadesc} +\begin{datadesc}{ECONNRESET} Connection reset by peer \end{datadesc} +\begin{datadesc}{ENOBUFS} No buffer space available \end{datadesc} +\begin{datadesc}{EISCONN} Transport endpoint is already connected \end{datadesc} +\begin{datadesc}{ENOTCONN} Transport endpoint is not connected \end{datadesc} +\begin{datadesc}{ESHUTDOWN} Cannot send after transport endpoint shutdown \end{datadesc} +\begin{datadesc}{ETOOMANYREFS} Too many references: cannot splice \end{datadesc} +\begin{datadesc}{ETIMEDOUT} Connection timed out \end{datadesc} +\begin{datadesc}{ECONNREFUSED} Connection refused \end{datadesc} +\begin{datadesc}{EHOSTDOWN} Host is down \end{datadesc} +\begin{datadesc}{EHOSTUNREACH} No route to host \end{datadesc} +\begin{datadesc}{EALREADY} Operation already in progress \end{datadesc} +\begin{datadesc}{EINPROGRESS} Operation now in progress \end{datadesc} +\begin{datadesc}{ESTALE} Stale NFS file handle \end{datadesc} +\begin{datadesc}{EUCLEAN} Structure needs cleaning \end{datadesc} +\begin{datadesc}{ENOTNAM} Not a XENIX named type file \end{datadesc} +\begin{datadesc}{ENAVAIL} No XENIX semaphores available \end{datadesc} +\begin{datadesc}{EISNAM} Is a named type file \end{datadesc} +\begin{datadesc}{EREMOTEIO} Remote I/O error \end{datadesc} +\begin{datadesc}{EDQUOT} Quota exceeded \end{datadesc} + diff --git a/sys/src/cmd/python/Doc/lib/libetree.tex b/sys/src/cmd/python/Doc/lib/libetree.tex new file mode 100644 index 000000000..ffa19435c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libetree.tex @@ -0,0 +1,356 @@ +\section{\module{xml.etree.ElementTree} --- The ElementTree XML API} +\declaremodule{standard}{xml.etree.ElementTree} +\moduleauthor{Fredrik Lundh}{fredrik@pythonware.com} +\modulesynopsis{Implementation of the ElementTree API.} + +\versionadded{2.5} + +The Element type is a flexible container object, designed to store +hierarchical data structures in memory. The type can be described as a +cross between a list and a dictionary. + +Each element has a number of properties associated with it: + +\begin{itemize} + \item a tag which is a string identifying what kind of data + this element represents (the element type, in other words). + \item a number of attributes, stored in a Python dictionary. + \item a text string. + \item an optional tail string. + \item a number of child elements, stored in a Python sequence +\end{itemize} + +To create an element instance, use the Element or SubElement factory +functions. + +The \class{ElementTree} class can be used to wrap an element +structure, and convert it from and to XML. + +A C implementation of this API is available as +\module{xml.etree.cElementTree}. + + +\subsection{Functions\label{elementtree-functions}} + +\begin{funcdesc}{Comment}{\optional{text}} +Comment element factory. This factory function creates a special +element that will be serialized as an XML comment. +The comment string can be either an 8-bit ASCII string or a Unicode +string. +\var{text} is a string containing the comment string. + +\begin{datadescni}{Returns:} +An element instance, representing a comment. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{dump}{elem} +Writes an element tree or element structure to sys.stdout. This +function should be used for debugging only. + +The exact output format is implementation dependent. In this +version, it's written as an ordinary XML file. + +\var{elem} is an element tree or an individual element. +\end{funcdesc} + +\begin{funcdesc}{Element}{tag\optional{, attrib}\optional{, **extra}} +Element factory. This function returns an object implementing the +standard Element interface. The exact class or type of that object +is implementation dependent, but it will always be compatible with +the {\_}ElementInterface class in this module. + +The element name, attribute names, and attribute values can be +either 8-bit ASCII strings or Unicode strings. +\var{tag} is the element name. +\var{attrib} is an optional dictionary, containing element attributes. +\var{extra} contains additional attributes, given as keyword arguments. + +\begin{datadescni}{Returns:} +An element instance. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{fromstring}{text} +Parses an XML section from a string constant. Same as XML. +\var{text} is a string containing XML data. + +\begin{datadescni}{Returns:} +An Element instance. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{iselement}{element} +Checks if an object appears to be a valid element object. +\var{element} is an element instance. + +\begin{datadescni}{Returns:} +A true value if this is an element object. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{iterparse}{source\optional{, events}} +Parses an XML section into an element tree incrementally, and reports +what's going on to the user. +\var{source} is a filename or file object containing XML data. +\var{events} is a list of events to report back. If omitted, only ``end'' +events are reported. + +\begin{datadescni}{Returns:} +A (event, elem) iterator. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{parse}{source\optional{, parser}} +Parses an XML section into an element tree. +\var{source} is a filename or file object containing XML data. +\var{parser} is an optional parser instance. If not given, the +standard XMLTreeBuilder parser is used. + +\begin{datadescni}{Returns:} +An ElementTree instance +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{ProcessingInstruction}{target\optional{, text}} +PI element factory. This factory function creates a special element +that will be serialized as an XML processing instruction. +\var{target} is a string containing the PI target. +\var{text} is a string containing the PI contents, if given. + +\begin{datadescni}{Returns:} +An element instance, representing a PI. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{SubElement}{parent, tag\optional{, attrib} \optional{, **extra}} +Subelement factory. This function creates an element instance, and +appends it to an existing element. + +The element name, attribute names, and attribute values can be +either 8-bit ASCII strings or Unicode strings. +\var{parent} is the parent element. +\var{tag} is the subelement name. +\var{attrib} is an optional dictionary, containing element attributes. +\var{extra} contains additional attributes, given as keyword arguments. + +\begin{datadescni}{Returns:} +An element instance. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{tostring}{element\optional{, encoding}} +Generates a string representation of an XML element, including all +subelements. +\var{element} is an Element instance. +\var{encoding} is the output encoding (default is US-ASCII). + +\begin{datadescni}{Returns:} +An encoded string containing the XML data. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{XML}{text} +Parses an XML section from a string constant. This function can +be used to embed ``XML literals'' in Python code. +\var{text} is a string containing XML data. + +\begin{datadescni}{Returns:} +An Element instance. +\end{datadescni} +\end{funcdesc} + +\begin{funcdesc}{XMLID}{text} +Parses an XML section from a string constant, and also returns +a dictionary which maps from element id:s to elements. +\var{text} is a string containing XML data. + +\begin{datadescni}{Returns:} +A tuple containing an Element instance and a dictionary. +\end{datadescni} +\end{funcdesc} + + +\subsection{ElementTree Objects\label{elementtree-elementtree-objects}} + +\begin{classdesc}{ElementTree}{\optional{element,} \optional{file}} +ElementTree wrapper class. This class represents an entire element +hierarchy, and adds some extra support for serialization to and from +standard XML. + +\var{element} is the root element. +The tree is initialized with the contents of the XML \var{file} if given. +\end{classdesc} + +\begin{methoddesc}{_setroot}{element} +Replaces the root element for this tree. This discards the +current contents of the tree, and replaces it with the given +element. Use with care. +\var{element} is an element instance. +\end{methoddesc} + +\begin{methoddesc}{find}{path} +Finds the first toplevel element with given tag. +Same as getroot().find(path). +\var{path} is the element to look for. + +\begin{datadescni}{Returns:} +The first matching element, or None if no element was found. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{findall}{path} +Finds all toplevel elements with the given tag. +Same as getroot().findall(path). +\var{path} is the element to look for. + +\begin{datadescni}{Returns:} +A list or iterator containing all matching elements, +in section order. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{findtext}{path\optional{, default}} +Finds the element text for the first toplevel element with given +tag. Same as getroot().findtext(path). +\var{path} is the toplevel element to look for. +\var{default} is the value to return if the element was not found. + +\begin{datadescni}{Returns:} +The text content of the first matching element, or the +default value no element was found. Note that if the element +has is found, but has no text content, this method returns an +empty string. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{getiterator}{\optional{tag}} +Creates a tree iterator for the root element. The iterator loops +over all elements in this tree, in section order. +\var{tag} is the tag to look for (default is to return all elements) + +\begin{datadescni}{Returns:} +An iterator. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{getroot}{} +Gets the root element for this tree. + +\begin{datadescni}{Returns:} +An element instance. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{parse}{source\optional{, parser}} +Loads an external XML section into this element tree. +\var{source} is a file name or file object. +\var{parser} is an optional parser instance. If not given, the +standard XMLTreeBuilder parser is used. + +\begin{datadescni}{Returns:} +The section root element. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{write}{file\optional{, encoding}} +Writes the element tree to a file, as XML. +\var{file} is a file name, or a file object opened for writing. +\var{encoding} is the output encoding (default is US-ASCII). +\end{methoddesc} + + +\subsection{QName Objects\label{elementtree-qname-objects}} + +\begin{classdesc}{QName}{text_or_uri\optional{, tag}} +QName wrapper. This can be used to wrap a QName attribute value, in +order to get proper namespace handling on output. +\var{text_or_uri} is a string containing the QName value, +in the form {\{}uri{\}}local, or, if the tag argument is given, +the URI part of a QName. +If \var{tag} is given, the first argument is interpreted as +an URI, and this argument is interpreted as a local name. + +\begin{datadescni}{Returns:} +An opaque object, representing the QName. +\end{datadescni} +\end{classdesc} + + +\subsection{TreeBuilder Objects\label{elementtree-treebuilder-objects}} + +\begin{classdesc}{TreeBuilder}{\optional{element_factory}} +Generic element structure builder. This builder converts a sequence +of start, data, and end method calls to a well-formed element structure. +You can use this class to build an element structure using a custom XML +parser, or a parser for some other XML-like format. +The \var{element_factory} is called to create new Element instances when +given. +\end{classdesc} + +\begin{methoddesc}{close}{} +Flushes the parser buffers, and returns the toplevel documen +element. + +\begin{datadescni}{Returns:} +An Element instance. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{data}{data} +Adds text to the current element. +\var{data} is a string. This should be either an 8-bit string +containing ASCII text, or a Unicode string. +\end{methoddesc} + +\begin{methoddesc}{end}{tag} +Closes the current element. +\var{tag} is the element name. + +\begin{datadescni}{Returns:} +The closed element. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{start}{tag, attrs} +Opens a new element. +\var{tag} is the element name. +\var{attrs} is a dictionary containing element attributes. + +\begin{datadescni}{Returns:} +The opened element. +\end{datadescni} +\end{methoddesc} + + +\subsection{XMLTreeBuilder Objects\label{elementtree-xmltreebuilder-objects}} + +\begin{classdesc}{XMLTreeBuilder}{\optional{html,} \optional{target}} +Element structure builder for XML source data, based on the +expat parser. +\var{html} are predefined HTML entities. This flag is not supported +by the current implementation. +\var{target} is the target object. If omitted, the builder uses an +instance of the standard TreeBuilder class. +\end{classdesc} + +\begin{methoddesc}{close}{} +Finishes feeding data to the parser. + +\begin{datadescni}{Returns:} +An element structure. +\end{datadescni} +\end{methoddesc} + +\begin{methoddesc}{doctype}{name, pubid, system} +Handles a doctype declaration. +\var{name} is the doctype name. +\var{pubid} is the public identifier. +\var{system} is the system identifier. +\end{methoddesc} + +\begin{methoddesc}{feed}{data} +Feeds data to the parser. + +\var{data} is encoded data. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libexcs.tex b/sys/src/cmd/python/Doc/lib/libexcs.tex new file mode 100644 index 000000000..6d2a3c5d2 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libexcs.tex @@ -0,0 +1,466 @@ +\section{Built-in Exceptions} + +\declaremodule{standard}{exceptions} +\modulesynopsis{Standard exception classes.} + + +Exceptions should be class objects. +The exceptions are defined in the module \module{exceptions}. This +module never needs to be imported explicitly: the exceptions are +provided in the built-in namespace as well as the \module{exceptions} +module. + +\begin{notice} +In past versions of Python string exceptions were supported. In +Python 1.5 and newer versions, all standard exceptions have been +converted to class objects and users are encouraged to do the same. +String exceptions will raise a \code{DeprecationWarning} in Python 2.5 and +newer. +In future versions, support for string exceptions will be removed. + +Two distinct string objects with the same value are considered different +exceptions. This is done to force programmers to use exception names +rather than their string value when specifying exception handlers. +The string value of all built-in exceptions is their name, but this is +not a requirement for user-defined exceptions or exceptions defined by +library modules. +\end{notice} + +For class exceptions, in a \keyword{try}\stindex{try} statement with +an \keyword{except}\stindex{except} clause that mentions a particular +class, that clause also handles any exception classes derived from +that class (but not exception classes from which \emph{it} is +derived). Two exception classes that are not related via subclassing +are never equivalent, even if they have the same name. + +The built-in exceptions listed below can be generated by the +interpreter or built-in functions. Except where mentioned, they have +an ``associated value'' indicating the detailed cause of the error. +This may be a string or a tuple containing several items of +information (e.g., an error code and a string explaining the code). +The associated value is the second argument to the +\keyword{raise}\stindex{raise} statement. For string exceptions, the +associated value itself will be stored in the variable named as the +second argument of the \keyword{except} clause (if any). For class +exceptions, that variable receives the exception instance. If the +exception class is derived from the standard root class +\exception{BaseException}, the associated value is present as the +exception instance's \member{args} attribute. If there is a single argument +(as is preferred), it is bound to the \member{message} attribute. + +User code can raise built-in exceptions. This can be used to test an +exception handler or to report an error condition ``just like'' the +situation in which the interpreter raises the same exception; but +beware that there is nothing to prevent user code from raising an +inappropriate error. + +The built-in exception classes can be sub-classed to define new +exceptions; programmers are encouraged to at least derive new +exceptions from the \exception{Exception} class and not +\exception{BaseException}. More +information on defining exceptions is available in the +\citetitle[../tut/tut.html]{Python Tutorial} under the heading +``User-defined Exceptions.'' + +\setindexsubitem{(built-in exception base class)} + +The following exceptions are only used as base classes for other +exceptions. + +\begin{excdesc}{BaseException} +The base class for all built-in exceptions. It is not meant to be directly +inherited by user-defined classes (for that use \exception{Exception}). If +\function{str()} or \function{unicode()} is called on an instance of this +class, the representation of the argument(s) to the instance are returned or +the emptry string when there were no arguments. If only a single argument is +passed in, it is stored in the \member{message} attribute. If more than one +argument is passed in, \member{message} is set to the empty string. These +semantics are meant to reflect the fact that \member{message} is to store a +text message explaining why the exception had been raised. If more data needs +to be attached to the exception, attach it through arbitrary attributes on the +instance. All arguments are also stored in \member{args} as a tuple, but it will +eventually be deprecated and thus its use is discouraged. +\versionadded{2.5} +\end{excdesc} + +\begin{excdesc}{Exception} +All built-in, non-system-exiting exceptions are derived +from this class. All user-defined exceptions should also be derived +from this class. +\versionchanged[Changed to inherit from \exception{BaseException}]{2.5} +\end{excdesc} + +\begin{excdesc}{StandardError} +The base class for all built-in exceptions except +\exception{StopIteration}, \exception{GeneratorExit}, +\exception{KeyboardInterrupt} and \exception{SystemExit}. +\exception{StandardError} itself is derived from \exception{Exception}. +\end{excdesc} + +\begin{excdesc}{ArithmeticError} +The base class for those built-in exceptions that are raised for +various arithmetic errors: \exception{OverflowError}, +\exception{ZeroDivisionError}, \exception{FloatingPointError}. +\end{excdesc} + +\begin{excdesc}{LookupError} +The base class for the exceptions that are raised when a key or +index used on a mapping or sequence is invalid: \exception{IndexError}, +\exception{KeyError}. This can be raised directly by +\function{sys.setdefaultencoding()}. +\end{excdesc} + +\begin{excdesc}{EnvironmentError} +The base class for exceptions that +can occur outside the Python system: \exception{IOError}, +\exception{OSError}. When exceptions of this type are created with a +2-tuple, the first item is available on the instance's \member{errno} +attribute (it is assumed to be an error number), and the second item +is available on the \member{strerror} attribute (it is usually the +associated error message). The tuple itself is also available on the +\member{args} attribute. +\versionadded{1.5.2} + +When an \exception{EnvironmentError} exception is instantiated with a +3-tuple, the first two items are available as above, while the third +item is available on the \member{filename} attribute. However, for +backwards compatibility, the \member{args} attribute contains only a +2-tuple of the first two constructor arguments. + +The \member{filename} attribute is \code{None} when this exception is +created with other than 3 arguments. The \member{errno} and +\member{strerror} attributes are also \code{None} when the instance was +created with other than 2 or 3 arguments. In this last case, +\member{args} contains the verbatim constructor arguments as a tuple. +\end{excdesc} + + +\setindexsubitem{(built-in exception)} + +The following exceptions are the exceptions that are actually raised. + +\begin{excdesc}{AssertionError} +\stindex{assert} +Raised when an \keyword{assert} statement fails. +\end{excdesc} + +\begin{excdesc}{AttributeError} +% xref to attribute reference? + Raised when an attribute reference or assignment fails. (When an + object does not support attribute references or attribute assignments + at all, \exception{TypeError} is raised.) +\end{excdesc} + +\begin{excdesc}{EOFError} +% XXXJH xrefs here + Raised when one of the built-in functions (\function{input()} or + \function{raw_input()}) hits an end-of-file condition (\EOF) without + reading any data. +% XXXJH xrefs here + (N.B.: the \method{read()} and \method{readline()} methods of file + objects return an empty string when they hit \EOF.) +\end{excdesc} + +\begin{excdesc}{FloatingPointError} + Raised when a floating point operation fails. This exception is + always defined, but can only be raised when Python is configured + with the \longprogramopt{with-fpectl} option, or the + \constant{WANT_SIGFPE_HANDLER} symbol is defined in the + \file{pyconfig.h} file. +\end{excdesc} + +\begin{excdesc}{GeneratorExit} + Raise when a generator's \method{close()} method is called. + It directly inherits from \exception{Exception} instead of + \exception{StandardError} since it is technically not an error. + \versionadded{2.5} +\end{excdesc} + +\begin{excdesc}{IOError} +% XXXJH xrefs here + Raised when an I/O operation (such as a \keyword{print} statement, + the built-in \function{open()} function or a method of a file + object) fails for an I/O-related reason, e.g., ``file not found'' or + ``disk full''. + + This class is derived from \exception{EnvironmentError}. See the + discussion above for more information on exception instance + attributes. +\end{excdesc} + +\begin{excdesc}{ImportError} +% XXXJH xref to import statement? + Raised when an \keyword{import} statement fails to find the module + definition or when a \code{from \textrm{\ldots} import} fails to find a + name that is to be imported. +\end{excdesc} + +\begin{excdesc}{IndexError} +% XXXJH xref to sequences + Raised when a sequence subscript is out of range. (Slice indices are + silently truncated to fall in the allowed range; if an index is not a + plain integer, \exception{TypeError} is raised.) +\end{excdesc} + +\begin{excdesc}{KeyError} +% XXXJH xref to mapping objects? + Raised when a mapping (dictionary) key is not found in the set of + existing keys. +\end{excdesc} + +\begin{excdesc}{KeyboardInterrupt} + Raised when the user hits the interrupt key (normally + \kbd{Control-C} or \kbd{Delete}). During execution, a check for + interrupts is made regularly. +% XXX(hylton) xrefs here + Interrupts typed when a built-in function \function{input()} or + \function{raw_input()} is waiting for input also raise this + exception. + The exception inherits from \exception{BaseException} so as to not be + accidentally caught by code that catches \exception{Exception} and thus + prevent the interpreter from exiting. + \versionchanged[Changed to inherit from \exception{BaseException}]{2.5} +\end{excdesc} + +\begin{excdesc}{MemoryError} + Raised when an operation runs out of memory but the situation may + still be rescued (by deleting some objects). The associated value is + a string indicating what kind of (internal) operation ran out of memory. + Note that because of the underlying memory management architecture + (C's \cfunction{malloc()} function), the interpreter may not + always be able to completely recover from this situation; it + nevertheless raises an exception so that a stack traceback can be + printed, in case a run-away program was the cause. +\end{excdesc} + +\begin{excdesc}{NameError} + Raised when a local or global name is not found. This applies only + to unqualified names. The associated value is an error message that + includes the name that could not be found. +\end{excdesc} + +\begin{excdesc}{NotImplementedError} + This exception is derived from \exception{RuntimeError}. In user + defined base classes, abstract methods should raise this exception + when they require derived classes to override the method. + \versionadded{1.5.2} +\end{excdesc} + +\begin{excdesc}{OSError} + %xref for os module + This class is derived from \exception{EnvironmentError} and is used + primarily as the \refmodule{os} module's \code{os.error} exception. + See \exception{EnvironmentError} above for a description of the + possible associated values. + \versionadded{1.5.2} +\end{excdesc} + +\begin{excdesc}{OverflowError} +% XXXJH reference to long's and/or int's? + Raised when the result of an arithmetic operation is too large to be + represented. This cannot occur for long integers (which would rather + raise \exception{MemoryError} than give up). Because of the lack of + standardization of floating point exception handling in C, most + floating point operations also aren't checked. For plain integers, + all operations that can overflow are checked except left shift, where + typical applications prefer to drop bits than raise an exception. +\end{excdesc} + +\begin{excdesc}{ReferenceError} + This exception is raised when a weak reference proxy, created by the + \function{\refmodule{weakref}.proxy()} function, is used to access + an attribute of the referent after it has been garbage collected. + For more information on weak references, see the \refmodule{weakref} + module. + \versionadded[Previously known as the + \exception{\refmodule{weakref}.ReferenceError} + exception]{2.2} +\end{excdesc} + +\begin{excdesc}{RuntimeError} + Raised when an error is detected that doesn't fall in any of the + other categories. The associated value is a string indicating what + precisely went wrong. (This exception is mostly a relic from a + previous version of the interpreter; it is not used very much any + more.) +\end{excdesc} + +\begin{excdesc}{StopIteration} + Raised by an iterator's \method{next()} method to signal that there + are no further values. + This is derived from \exception{Exception} rather than + \exception{StandardError}, since this is not considered an error in + its normal application. + \versionadded{2.2} +\end{excdesc} + + +\begin{excdesc}{SyntaxError} +% XXXJH xref to these functions? + Raised when the parser encounters a syntax error. This may occur in + an \keyword{import} statement, in an \keyword{exec} statement, in a call + to the built-in function \function{eval()} or \function{input()}, or + when reading the initial script or standard input (also + interactively). + + Instances of this class have attributes \member{filename}, + \member{lineno}, \member{offset} and \member{text} for easier access + to the details. \function{str()} of the exception instance returns + only the message. +\end{excdesc} + +\begin{excdesc}{SystemError} + Raised when the interpreter finds an internal error, but the + situation does not look so serious to cause it to abandon all hope. + The associated value is a string indicating what went wrong (in + low-level terms). + + You should report this to the author or maintainer of your Python + interpreter. Be sure to report the version of the Python + interpreter (\code{sys.version}; it is also printed at the start of an + interactive Python session), the exact error message (the exception's + associated value) and if possible the source of the program that + triggered the error. +\end{excdesc} + +\begin{excdesc}{SystemExit} +% XXX(hylton) xref to module sys? + This exception is raised by the \function{sys.exit()} function. When it + is not handled, the Python interpreter exits; no stack traceback is + printed. If the associated value is a plain integer, it specifies the + system exit status (passed to C's \cfunction{exit()} function); if it is + \code{None}, the exit status is zero; if it has another type (such as + a string), the object's value is printed and the exit status is one. + + Instances have an attribute \member{code} which is set to the + proposed exit status or error message (defaulting to \code{None}). + Also, this exception derives directly from \exception{BaseException} and + not \exception{StandardError}, since it is not technically an error. + + A call to \function{sys.exit()} is translated into an exception so that + clean-up handlers (\keyword{finally} clauses of \keyword{try} statements) + can be executed, and so that a debugger can execute a script without + running the risk of losing control. The \function{os._exit()} function + can be used if it is absolutely positively necessary to exit + immediately (for example, in the child process after a call to + \function{fork()}). + + The exception inherits from \exception{BaseException} instead of + \exception{StandardError} or \exception{Exception} so that it is not + accidentally caught by code that catches \exception{Exception}. This allows + the exception to properly propagate up and cause the interpreter to exit. + \versionchanged[Changed to inherit from \exception{BaseException}]{2.5} +\end{excdesc} + +\begin{excdesc}{TypeError} + Raised when an operation or function is applied to an object + of inappropriate type. The associated value is a string giving + details about the type mismatch. +\end{excdesc} + +\begin{excdesc}{UnboundLocalError} + Raised when a reference is made to a local variable in a function or + method, but no value has been bound to that variable. This is a + subclass of \exception{NameError}. +\versionadded{2.0} +\end{excdesc} + +\begin{excdesc}{UnicodeError} + Raised when a Unicode-related encoding or decoding error occurs. It + is a subclass of \exception{ValueError}. +\versionadded{2.0} +\end{excdesc} + +\begin{excdesc}{UnicodeEncodeError} + Raised when a Unicode-related error occurs during encoding. It + is a subclass of \exception{UnicodeError}. +\versionadded{2.3} +\end{excdesc} + +\begin{excdesc}{UnicodeDecodeError} + Raised when a Unicode-related error occurs during decoding. It + is a subclass of \exception{UnicodeError}. +\versionadded{2.3} +\end{excdesc} + +\begin{excdesc}{UnicodeTranslateError} + Raised when a Unicode-related error occurs during translating. It + is a subclass of \exception{UnicodeError}. +\versionadded{2.3} +\end{excdesc} + +\begin{excdesc}{ValueError} + Raised when a built-in operation or function receives an argument + that has the right type but an inappropriate value, and the + situation is not described by a more precise exception such as + \exception{IndexError}. +\end{excdesc} + +\begin{excdesc}{WindowsError} + Raised when a Windows-specific error occurs or when the error number + does not correspond to an \cdata{errno} value. The + \member{winerror} and \member{strerror} values are created from the + return values of the \cfunction{GetLastError()} and + \cfunction{FormatMessage()} functions from the Windows Platform API. + The \member{errno} value maps the \member{winerror} value to + corresponding \code{errno.h} values. + This is a subclass of \exception{OSError}. +\versionadded{2.0} +\versionchanged[Previous versions put the \cfunction{GetLastError()} +codes into \member{errno}]{2.5} +\end{excdesc} + +\begin{excdesc}{ZeroDivisionError} + Raised when the second argument of a division or modulo operation is + zero. The associated value is a string indicating the type of the + operands and the operation. +\end{excdesc} + + +\setindexsubitem{(built-in warning)} + +The following exceptions are used as warning categories; see the +\refmodule{warnings} module for more information. + +\begin{excdesc}{Warning} +Base class for warning categories. +\end{excdesc} + +\begin{excdesc}{UserWarning} +Base class for warnings generated by user code. +\end{excdesc} + +\begin{excdesc}{DeprecationWarning} +Base class for warnings about deprecated features. +\end{excdesc} + +\begin{excdesc}{PendingDeprecationWarning} +Base class for warnings about features which will be deprecated in the future. +\end{excdesc} + +\begin{excdesc}{SyntaxWarning} +Base class for warnings about dubious syntax +\end{excdesc} + +\begin{excdesc}{RuntimeWarning} +Base class for warnings about dubious runtime behavior. +\end{excdesc} + +\begin{excdesc}{FutureWarning} +Base class for warnings about constructs that will change semantically +in the future. +\end{excdesc} + +\begin{excdesc}{ImportWarning} +Base class for warnings about probable mistakes in module imports. +\versionadded{2.5} +\end{excdesc} + +\begin{excdesc}{UnicodeWarning} +Base class for warnings related to Unicode. +\versionadded{2.5} +\end{excdesc} + +The class hierarchy for built-in exceptions is: + +\verbatiminput{../../Lib/test/exception_hierarchy.txt} diff --git a/sys/src/cmd/python/Doc/lib/libfcntl.tex b/sys/src/cmd/python/Doc/lib/libfcntl.tex new file mode 100644 index 000000000..dc76da3cc --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfcntl.tex @@ -0,0 +1,174 @@ +\section{\module{fcntl} --- + The \function{fcntl()} and \function{ioctl()} system calls} + +\declaremodule{builtin}{fcntl} + \platform{Unix} +\modulesynopsis{The \function{fcntl()} and \function{ioctl()} system calls.} +\sectionauthor{Jaap Vermeulen}{} + +\indexii{UNIX@\UNIX}{file control} +\indexii{UNIX@\UNIX}{I/O control} + +This module performs file control and I/O control on file descriptors. +It is an interface to the \cfunction{fcntl()} and \cfunction{ioctl()} +\UNIX{} routines. + +All functions in this module take a file descriptor \var{fd} as their +first argument. This can be an integer file descriptor, such as +returned by \code{sys.stdin.fileno()}, or a file object, such as +\code{sys.stdin} itself, which provides a \method{fileno()} which +returns a genuine file descriptor. + +The module defines the following functions: + + +\begin{funcdesc}{fcntl}{fd, op\optional{, arg}} + Perform the requested operation on file descriptor \var{fd} (file + objects providing a \method{fileno()} method are accepted as well). + The operation is defined by \var{op} and is operating system + dependent. These codes are also found in the \module{fcntl} + module. The argument \var{arg} is optional, and defaults to the + integer value \code{0}. When present, it can either be an integer + value, or a string. With the argument missing or an integer value, + the return value of this function is the integer return value of the + C \cfunction{fcntl()} call. When the argument is a string it + represents a binary structure, e.g.\ created by + \function{\refmodule{struct}.pack()}. The binary data is copied to a buffer + whose address is passed to the C \cfunction{fcntl()} call. The + return value after a successful call is the contents of the buffer, + converted to a string object. The length of the returned string + will be the same as the length of the \var{arg} argument. This is + limited to 1024 bytes. If the information returned in the buffer by + the operating system is larger than 1024 bytes, this is most likely + to result in a segmentation violation or a more subtle data + corruption. + + If the \cfunction{fcntl()} fails, an \exception{IOError} is + raised. +\end{funcdesc} + +\begin{funcdesc}{ioctl}{fd, op\optional{, arg\optional{, mutate_flag}}} + This function is identical to the \function{fcntl()} function, + except that the operations are typically defined in the library + module \refmodule{termios} and the argument handling is even more + complicated. + + The parameter \var{arg} can be one of an integer, absent (treated + identically to the integer \code{0}), an object supporting the + read-only buffer interface (most likely a plain Python string) or an + object supporting the read-write buffer interface. + + In all but the last case, behaviour is as for the \function{fcntl()} + function. + + If a mutable buffer is passed, then the behaviour is determined by + the value of the \var{mutate_flag} parameter. + + If it is false, the buffer's mutability is ignored and behaviour is + as for a read-only buffer, except that the 1024 byte limit mentioned + above is avoided -- so long as the buffer you pass is as least as + long as what the operating system wants to put there, things should + work. + + If \var{mutate_flag} is true, then the buffer is (in effect) passed + to the underlying \function{ioctl()} system call, the latter's + return code is passed back to the calling Python, and the buffer's + new contents reflect the action of the \function{ioctl()}. This is a + slight simplification, because if the supplied buffer is less than + 1024 bytes long it is first copied into a static buffer 1024 bytes + long which is then passed to \function{ioctl()} and copied back into + the supplied buffer. + + If \var{mutate_flag} is not supplied, then from Python 2.5 it + defaults to true, which is a change from versions 2.3 and 2.4. + Supply the argument explicitly if version portability is a priority. + + An example: + +\begin{verbatim} +>>> import array, fcntl, struct, termios, os +>>> os.getpgrp() +13341 +>>> struct.unpack('h', fcntl.ioctl(0, termios.TIOCGPGRP, " "))[0] +13341 +>>> buf = array.array('h', [0]) +>>> fcntl.ioctl(0, termios.TIOCGPGRP, buf, 1) +0 +>>> buf +array('h', [13341]) +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{flock}{fd, op} +Perform the lock operation \var{op} on file descriptor \var{fd} (file + objects providing a \method{fileno()} method are accepted as well). +See the \UNIX{} manual \manpage{flock}{3} for details. (On some +systems, this function is emulated using \cfunction{fcntl()}.) +\end{funcdesc} + +\begin{funcdesc}{lockf}{fd, operation, + \optional{length, \optional{start, \optional{whence}}}} +This is essentially a wrapper around the \function{fcntl()} locking +calls. \var{fd} is the file descriptor of the file to lock or unlock, +and \var{operation} is one of the following values: + +\begin{itemize} +\item \constant{LOCK_UN} -- unlock +\item \constant{LOCK_SH} -- acquire a shared lock +\item \constant{LOCK_EX} -- acquire an exclusive lock +\end{itemize} + +When \var{operation} is \constant{LOCK_SH} or \constant{LOCK_EX}, it +can also be bit-wise OR'd with \constant{LOCK_NB} to avoid blocking on +lock acquisition. If \constant{LOCK_NB} is used and the lock cannot +be acquired, an \exception{IOError} will be raised and the exception +will have an \var{errno} attribute set to \constant{EACCES} or +\constant{EAGAIN} (depending on the operating system; for portability, +check for both values). On at least some systems, \constant{LOCK_EX} +can only be used if the file descriptor refers to a file opened for +writing. + +\var{length} is the number of bytes to lock, \var{start} is the byte +offset at which the lock starts, relative to \var{whence}, and +\var{whence} is as with \function{fileobj.seek()}, specifically: + +\begin{itemize} +\item \constant{0} -- relative to the start of the file + (\constant{SEEK_SET}) +\item \constant{1} -- relative to the current buffer position + (\constant{SEEK_CUR}) +\item \constant{2} -- relative to the end of the file + (\constant{SEEK_END}) +\end{itemize} + +The default for \var{start} is 0, which means to start at the +beginning of the file. The default for \var{length} is 0 which means +to lock to the end of the file. The default for \var{whence} is also +0. +\end{funcdesc} + +Examples (all on a SVR4 compliant system): + +\begin{verbatim} +import struct, fcntl, os + +f = open(...) +rv = fcntl.fcntl(f, fcntl.F_SETFL, os.O_NDELAY) + +lockdata = struct.pack('hhllhh', fcntl.F_WRLCK, 0, 0, 0, 0, 0) +rv = fcntl.fcntl(f, fcntl.F_SETLKW, lockdata) +\end{verbatim} + +Note that in the first example the return value variable \var{rv} will +hold an integer value; in the second example it will hold a string +value. The structure lay-out for the \var{lockdata} variable is +system dependent --- therefore using the \function{flock()} call may be +better. + +\begin{seealso} + \seemodule{os}{If the locking flags \constant{O_SHLOCK} and + \constant{O_EXLOCK} are present in the \module{os} module, + the \function{os.open()} function provides a more + platform-independent alternative to the \function{lockf()} + and \function{flock()} functions.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libfilecmp.tex b/sys/src/cmd/python/Doc/lib/libfilecmp.tex new file mode 100644 index 000000000..42b4b8c42 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfilecmp.tex @@ -0,0 +1,142 @@ +\section{\module{filecmp} --- + File and Directory Comparisons} + +\declaremodule{standard}{filecmp} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Compare files efficiently.} + + +The \module{filecmp} module defines functions to compare files and +directories, with various optional time/correctness trade-offs. + +The \module{filecmp} module defines the following functions: + +\begin{funcdesc}{cmp}{f1, f2\optional{, shallow}} +Compare the files named \var{f1} and \var{f2}, returning \code{True} if +they seem equal, \code{False} otherwise. + +Unless \var{shallow} is given and is false, files with identical +\function{os.stat()} signatures are taken to be equal. + +Files that were compared using this function will not be compared again +unless their \function{os.stat()} signature changes. + +Note that no external programs are called from this function, giving it +portability and efficiency. +\end{funcdesc} + +\begin{funcdesc}{cmpfiles}{dir1, dir2, common\optional{, + shallow}} +Returns three lists of file names: \var{match}, \var{mismatch}, +\var{errors}. \var{match} contains the list of files match in both +directories, \var{mismatch} includes the names of those that don't, +and \var{errros} lists the names of files which could not be +compared. Files may be listed in \var{errors} because the user may +lack permission to read them or many other reasons, but always that +the comparison could not be done for some reason. + +The \var{common} parameter is a list of file names found in both directories. +The \var{shallow} parameter has the same +meaning and default value as for \function{filecmp.cmp()}. +\end{funcdesc} + +Example: + +\begin{verbatim} +>>> import filecmp +>>> filecmp.cmp('libundoc.tex', 'libundoc.tex') +True +>>> filecmp.cmp('libundoc.tex', 'lib.tex') +False +\end{verbatim} + + +\subsection{The \protect\class{dircmp} class \label{dircmp-objects}} + +\class{dircmp} instances are built using this constructor: + +\begin{classdesc}{dircmp}{a, b\optional{, ignore\optional{, hide}}} +Construct a new directory comparison object, to compare the +directories \var{a} and \var{b}. \var{ignore} is a list of names to +ignore, and defaults to \code{['RCS', 'CVS', 'tags']}. \var{hide} is a +list of names to hide, and defaults to \code{[os.curdir, os.pardir]}. +\end{classdesc} + +The \class{dircmp} class provides the following methods: + +\begin{methoddesc}[dircmp]{report}{} +Print (to \code{sys.stdout}) a comparison between \var{a} and \var{b}. +\end{methoddesc} + +\begin{methoddesc}[dircmp]{report_partial_closure}{} +Print a comparison between \var{a} and \var{b} and common immediate +subdirectories. +\end{methoddesc} + +\begin{methoddesc}[dircmp]{report_full_closure}{} +Print a comparison between \var{a} and \var{b} and common +subdirectories (recursively). +\end{methoddesc} + + +The \class{dircmp} offers a number of interesting attributes that may +be used to get various bits of information about the directory trees +being compared. + +Note that via \method{__getattr__()} hooks, all attributes are +computed lazily, so there is no speed penalty if only those +attributes which are lightweight to compute are used. + +\begin{memberdesc}[dircmp]{left_list} +Files and subdirectories in \var{a}, filtered by \var{hide} and +\var{ignore}. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{right_list} +Files and subdirectories in \var{b}, filtered by \var{hide} and +\var{ignore}. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{common} +Files and subdirectories in both \var{a} and \var{b}. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{left_only} +Files and subdirectories only in \var{a}. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{right_only} +Files and subdirectories only in \var{b}. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{common_dirs} +Subdirectories in both \var{a} and \var{b}. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{common_files} +Files in both \var{a} and \var{b} +\end{memberdesc} + +\begin{memberdesc}[dircmp]{common_funny} +Names in both \var{a} and \var{b}, such that the type differs between +the directories, or names for which \function{os.stat()} reports an +error. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{same_files} +Files which are identical in both \var{a} and \var{b}. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{diff_files} +Files which are in both \var{a} and \var{b}, whose contents differ. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{funny_files} +Files which are in both \var{a} and \var{b}, but could not be +compared. +\end{memberdesc} + +\begin{memberdesc}[dircmp]{subdirs} +A dictionary mapping names in \member{common_dirs} to +\class{dircmp} objects. +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/lib/libfileinput.tex b/sys/src/cmd/python/Doc/lib/libfileinput.tex new file mode 100644 index 000000000..3cfb7bc4e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfileinput.tex @@ -0,0 +1,192 @@ +\section{\module{fileinput} --- + Iterate over lines from multiple input streams} +\declaremodule{standard}{fileinput} +\moduleauthor{Guido van Rossum}{guido@python.org} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +\modulesynopsis{Perl-like iteration over lines from multiple input +streams, with ``save in place'' capability.} + + +This module implements a helper class and functions to quickly write a +loop over standard input or a list of files. + +The typical use is: + +\begin{verbatim} +import fileinput +for line in fileinput.input(): + process(line) +\end{verbatim} + +This iterates over the lines of all files listed in +\code{sys.argv[1:]}, defaulting to \code{sys.stdin} if the list is +empty. If a filename is \code{'-'}, it is also replaced by +\code{sys.stdin}. To specify an alternative list of filenames, pass +it as the first argument to \function{input()}. A single file name is +also allowed. + +All files are opened in text mode by default, but you can override this by +specifying the \var{mode} parameter in the call to \function{input()} +or \class{FileInput()}. If an I/O error occurs during opening or reading +a file, \exception{IOError} is raised. + +If \code{sys.stdin} is used more than once, the second and further use +will return no lines, except perhaps for interactive use, or if it has +been explicitly reset (e.g. using \code{sys.stdin.seek(0)}). + +Empty files are opened and immediately closed; the only time their +presence in the list of filenames is noticeable at all is when the +last file opened is empty. + +It is possible that the last line of a file does not end in a newline +character; lines are returned including the trailing newline when it +is present. + +You can control how files are opened by providing an opening hook via the +\var{openhook} parameter to \function{input()} or \class{FileInput()}. +The hook must be a function that takes two arguments, \var{filename} +and \var{mode}, and returns an accordingly opened file-like object. +Two useful hooks are already provided by this module. + +The following function is the primary interface of this module: + +\begin{funcdesc}{input}{\optional{files\optional{, inplace\optional{, + backup\optional{, mode\optional{, openhook}}}}}} + Create an instance of the \class{FileInput} class. The instance + will be used as global state for the functions of this module, and + is also returned to use during iteration. The parameters to this + function will be passed along to the constructor of the + \class{FileInput} class. + + \versionchanged[Added the \var{mode} and \var{openhook} parameters]{2.5} +\end{funcdesc} + + +The following functions use the global state created by +\function{input()}; if there is no active state, +\exception{RuntimeError} is raised. + +\begin{funcdesc}{filename}{} + Return the name of the file currently being read. Before the first + line has been read, returns \code{None}. +\end{funcdesc} + +\begin{funcdesc}{fileno}{} + Return the integer ``file descriptor'' for the current file. When no + file is opened (before the first line and between files), returns + \code{-1}. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{lineno}{} + Return the cumulative line number of the line that has just been + read. Before the first line has been read, returns \code{0}. After + the last line of the last file has been read, returns the line + number of that line. +\end{funcdesc} + +\begin{funcdesc}{filelineno}{} + Return the line number in the current file. Before the first line + has been read, returns \code{0}. After the last line of the last + file has been read, returns the line number of that line within the + file. +\end{funcdesc} + +\begin{funcdesc}{isfirstline}{} + Returns true if the line just read is the first line of its file, + otherwise returns false. +\end{funcdesc} + +\begin{funcdesc}{isstdin}{} + Returns true if the last line was read from \code{sys.stdin}, + otherwise returns false. +\end{funcdesc} + +\begin{funcdesc}{nextfile}{} + Close the current file so that the next iteration will read the + first line from the next file (if any); lines not read from the file + will not count towards the cumulative line count. The filename is + not changed until after the first line of the next file has been + read. Before the first line has been read, this function has no + effect; it cannot be used to skip the first file. After the last + line of the last file has been read, this function has no effect. +\end{funcdesc} + +\begin{funcdesc}{close}{} + Close the sequence. +\end{funcdesc} + + +The class which implements the sequence behavior provided by the +module is available for subclassing as well: + +\begin{classdesc}{FileInput}{\optional{files\optional{, + inplace\optional{, backup\optional{, + mode\optional{, openhook}}}}}} + Class \class{FileInput} is the implementation; its methods + \method{filename()}, \method{fileno()}, \method{lineno()}, + \method{fileline()}, \method{isfirstline()}, \method{isstdin()}, + \method{nextfile()} and \method{close()} correspond to the functions + of the same name in the module. + In addition it has a \method{readline()} method which + returns the next input line, and a \method{__getitem__()} method + which implements the sequence behavior. The sequence must be + accessed in strictly sequential order; random access and + \method{readline()} cannot be mixed. + + With \var{mode} you can specify which file mode will be passed to + \function{open()}. It must be one of \code{'r'}, \code{'rU'}, + \code{'U'} and \code{'rb'}. + + The \var{openhook}, when given, must be a function that takes two arguments, + \var{filename} and \var{mode}, and returns an accordingly opened + file-like object. + You cannot use \var{inplace} and \var{openhook} together. + + \versionchanged[Added the \var{mode} and \var{openhook} parameters]{2.5} +\end{classdesc} + +\strong{Optional in-place filtering:} if the keyword argument +\code{\var{inplace}=1} is passed to \function{input()} or to the +\class{FileInput} constructor, the file is moved to a backup file and +standard output is directed to the input file (if a file of the same +name as the backup file already exists, it will be replaced silently). +This makes it possible to write a filter that rewrites its input file +in place. If the keyword argument \code{\var{backup}='.'} is also given, it specifies the extension for the backup +file, and the backup file remains around; by default, the extension is +\code{'.bak'} and it is deleted when the output file is closed. In-place +filtering is disabled when standard input is read. + +\strong{Caveat:} The current implementation does not work for MS-DOS +8+3 filesystems. + + +The two following opening hooks are provided by this module: + +\begin{funcdesc}{hook_compressed}{filename, mode} + Transparently opens files compressed with gzip and bzip2 (recognized + by the extensions \code{'.gz'} and \code{'.bz2'}) using the \module{gzip} + and \module{bz2} modules. If the filename extension is not \code{'.gz'} + or \code{'.bz2'}, the file is opened normally (ie, + using \function{open()} without any decompression). + + Usage example: + \samp{fi = fileinput.FileInput(openhook=fileinput.hook_compressed)} + + \versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{hook_encoded}{encoding} + Returns a hook which opens each file with \function{codecs.open()}, + using the given \var{encoding} to read the file. + + Usage example: + \samp{fi = fileinput.FileInput(openhook=fileinput.hook_encoded("iso-8859-1"))} + + \note{With this hook, \class{FileInput} might return Unicode strings + depending on the specified \var{encoding}.} + \versionadded{2.5} +\end{funcdesc} + diff --git a/sys/src/cmd/python/Doc/lib/libfl.tex b/sys/src/cmd/python/Doc/lib/libfl.tex new file mode 100644 index 000000000..bafb8e49b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfl.tex @@ -0,0 +1,507 @@ +\section{\module{fl} --- + FORMS library for graphical user interfaces} + +\declaremodule{builtin}{fl} + \platform{IRIX} +\modulesynopsis{FORMS library for applications with graphical user + interfaces.} + + +This module provides an interface to the FORMS Library\index{FORMS +Library} by Mark Overmars\index{Overmars, Mark}. The source for the +library can be retrieved by anonymous ftp from host +\samp{ftp.cs.ruu.nl}, directory \file{SGI/FORMS}. It was last tested +with version 2.0b. + +Most functions are literal translations of their C equivalents, +dropping the initial \samp{fl_} from their name. Constants used by +the library are defined in module \refmodule[fl-constants]{FL} +described below. + +The creation of objects is a little different in Python than in C: +instead of the `current form' maintained by the library to which new +FORMS objects are added, all functions that add a FORMS object to a +form are methods of the Python object representing the form. +Consequently, there are no Python equivalents for the C functions +\cfunction{fl_addto_form()} and \cfunction{fl_end_form()}, and the +equivalent of \cfunction{fl_bgn_form()} is called +\function{fl.make_form()}. + +Watch out for the somewhat confusing terminology: FORMS uses the word +\dfn{object} for the buttons, sliders etc. that you can place in a form. +In Python, `object' means any value. The Python interface to FORMS +introduces two new Python object types: form objects (representing an +entire form) and FORMS objects (representing one button, slider etc.). +Hopefully this isn't too confusing. + +There are no `free objects' in the Python interface to FORMS, nor is +there an easy way to add object classes written in Python. The FORMS +interface to GL event handling is available, though, so you can mix +FORMS with pure GL windows. + +\strong{Please note:} importing \module{fl} implies a call to the GL +function \cfunction{foreground()} and to the FORMS routine +\cfunction{fl_init()}. + +\subsection{Functions Defined in Module \module{fl}} +\nodename{FL Functions} + +Module \module{fl} defines the following functions. For more +information about what they do, see the description of the equivalent +C function in the FORMS documentation: + +\begin{funcdesc}{make_form}{type, width, height} +Create a form with given type, width and height. This returns a +\dfn{form} object, whose methods are described below. +\end{funcdesc} + +\begin{funcdesc}{do_forms}{} +The standard FORMS main loop. Returns a Python object representing +the FORMS object needing interaction, or the special value +\constant{FL.EVENT}. +\end{funcdesc} + +\begin{funcdesc}{check_forms}{} +Check for FORMS events. Returns what \function{do_forms()} above +returns, or \code{None} if there is no event that immediately needs +interaction. +\end{funcdesc} + +\begin{funcdesc}{set_event_call_back}{function} +Set the event callback function. +\end{funcdesc} + +\begin{funcdesc}{set_graphics_mode}{rgbmode, doublebuffering} +Set the graphics modes. +\end{funcdesc} + +\begin{funcdesc}{get_rgbmode}{} +Return the current rgb mode. This is the value of the C global +variable \cdata{fl_rgbmode}. +\end{funcdesc} + +\begin{funcdesc}{show_message}{str1, str2, str3} +Show a dialog box with a three-line message and an OK button. +\end{funcdesc} + +\begin{funcdesc}{show_question}{str1, str2, str3} +Show a dialog box with a three-line message and YES and NO buttons. +It returns \code{1} if the user pressed YES, \code{0} if NO. +\end{funcdesc} + +\begin{funcdesc}{show_choice}{str1, str2, str3, but1\optional{, + but2\optional{, but3}}} +Show a dialog box with a three-line message and up to three buttons. +It returns the number of the button clicked by the user +(\code{1}, \code{2} or \code{3}). +\end{funcdesc} + +\begin{funcdesc}{show_input}{prompt, default} +Show a dialog box with a one-line prompt message and text field in +which the user can enter a string. The second argument is the default +input string. It returns the string value as edited by the user. +\end{funcdesc} + +\begin{funcdesc}{show_file_selector}{message, directory, pattern, default} +Show a dialog box in which the user can select a file. It returns +the absolute filename selected by the user, or \code{None} if the user +presses Cancel. +\end{funcdesc} + +\begin{funcdesc}{get_directory}{} +\funcline{get_pattern}{} +\funcline{get_filename}{} +These functions return the directory, pattern and filename (the tail +part only) selected by the user in the last +\function{show_file_selector()} call. +\end{funcdesc} + +\begin{funcdesc}{qdevice}{dev} +\funcline{unqdevice}{dev} +\funcline{isqueued}{dev} +\funcline{qtest}{} +\funcline{qread}{} +%\funcline{blkqread}{?} +\funcline{qreset}{} +\funcline{qenter}{dev, val} +\funcline{get_mouse}{} +\funcline{tie}{button, valuator1, valuator2} +These functions are the FORMS interfaces to the corresponding GL +functions. Use these if you want to handle some GL events yourself +when using \function{fl.do_events()}. When a GL event is detected that +FORMS cannot handle, \function{fl.do_forms()} returns the special value +\constant{FL.EVENT} and you should call \function{fl.qread()} to read +the event from the queue. Don't use the equivalent GL functions! +\end{funcdesc} + +\begin{funcdesc}{color}{} +\funcline{mapcolor}{} +\funcline{getmcolor}{} +See the description in the FORMS documentation of +\cfunction{fl_color()}, \cfunction{fl_mapcolor()} and +\cfunction{fl_getmcolor()}. +\end{funcdesc} + +\subsection{Form Objects} +\label{form-objects} + +Form objects (returned by \function{make_form()} above) have the +following methods. Each method corresponds to a C function whose +name is prefixed with \samp{fl_}; and whose first argument is a form +pointer; please refer to the official FORMS documentation for +descriptions. + +All the \method{add_*()} methods return a Python object representing +the FORMS object. Methods of FORMS objects are described below. Most +kinds of FORMS object also have some methods specific to that kind; +these methods are listed here. + +\begin{flushleft} + +\begin{methoddesc}[form]{show_form}{placement, bordertype, name} + Show the form. +\end{methoddesc} + +\begin{methoddesc}[form]{hide_form}{} + Hide the form. +\end{methoddesc} + +\begin{methoddesc}[form]{redraw_form}{} + Redraw the form. +\end{methoddesc} + +\begin{methoddesc}[form]{set_form_position}{x, y} +Set the form's position. +\end{methoddesc} + +\begin{methoddesc}[form]{freeze_form}{} +Freeze the form. +\end{methoddesc} + +\begin{methoddesc}[form]{unfreeze_form}{} + Unfreeze the form. +\end{methoddesc} + +\begin{methoddesc}[form]{activate_form}{} + Activate the form. +\end{methoddesc} + +\begin{methoddesc}[form]{deactivate_form}{} + Deactivate the form. +\end{methoddesc} + +\begin{methoddesc}[form]{bgn_group}{} + Begin a new group of objects; return a group object. +\end{methoddesc} + +\begin{methoddesc}[form]{end_group}{} + End the current group of objects. +\end{methoddesc} + +\begin{methoddesc}[form]{find_first}{} + Find the first object in the form. +\end{methoddesc} + +\begin{methoddesc}[form]{find_last}{} + Find the last object in the form. +\end{methoddesc} + +%--- + +\begin{methoddesc}[form]{add_box}{type, x, y, w, h, name} +Add a box object to the form. +No extra methods. +\end{methoddesc} + +\begin{methoddesc}[form]{add_text}{type, x, y, w, h, name} +Add a text object to the form. +No extra methods. +\end{methoddesc} + +%\begin{methoddesc}[form]{add_bitmap}{type, x, y, w, h, name} +%Add a bitmap object to the form. +%\end{methoddesc} + +\begin{methoddesc}[form]{add_clock}{type, x, y, w, h, name} +Add a clock object to the form. \\ +Method: +\method{get_clock()}. +\end{methoddesc} + +%--- + +\begin{methoddesc}[form]{add_button}{type, x, y, w, h, name} +Add a button object to the form. \\ +Methods: +\method{get_button()}, +\method{set_button()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_lightbutton}{type, x, y, w, h, name} +Add a lightbutton object to the form. \\ +Methods: +\method{get_button()}, +\method{set_button()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_roundbutton}{type, x, y, w, h, name} +Add a roundbutton object to the form. \\ +Methods: +\method{get_button()}, +\method{set_button()}. +\end{methoddesc} + +%--- + +\begin{methoddesc}[form]{add_slider}{type, x, y, w, h, name} +Add a slider object to the form. \\ +Methods: +\method{set_slider_value()}, +\method{get_slider_value()}, +\method{set_slider_bounds()}, +\method{get_slider_bounds()}, +\method{set_slider_return()}, +\method{set_slider_size()}, +\method{set_slider_precision()}, +\method{set_slider_step()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_valslider}{type, x, y, w, h, name} +Add a valslider object to the form. \\ +Methods: +\method{set_slider_value()}, +\method{get_slider_value()}, +\method{set_slider_bounds()}, +\method{get_slider_bounds()}, +\method{set_slider_return()}, +\method{set_slider_size()}, +\method{set_slider_precision()}, +\method{set_slider_step()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_dial}{type, x, y, w, h, name} +Add a dial object to the form. \\ +Methods: +\method{set_dial_value()}, +\method{get_dial_value()}, +\method{set_dial_bounds()}, +\method{get_dial_bounds()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_positioner}{type, x, y, w, h, name} +Add a positioner object to the form. \\ +Methods: +\method{set_positioner_xvalue()}, +\method{set_positioner_yvalue()}, +\method{set_positioner_xbounds()}, +\method{set_positioner_ybounds()}, +\method{get_positioner_xvalue()}, +\method{get_positioner_yvalue()}, +\method{get_positioner_xbounds()}, +\method{get_positioner_ybounds()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_counter}{type, x, y, w, h, name} +Add a counter object to the form. \\ +Methods: +\method{set_counter_value()}, +\method{get_counter_value()}, +\method{set_counter_bounds()}, +\method{set_counter_step()}, +\method{set_counter_precision()}, +\method{set_counter_return()}. +\end{methoddesc} + +%--- + +\begin{methoddesc}[form]{add_input}{type, x, y, w, h, name} +Add a input object to the form. \\ +Methods: +\method{set_input()}, +\method{get_input()}, +\method{set_input_color()}, +\method{set_input_return()}. +\end{methoddesc} + +%--- + +\begin{methoddesc}[form]{add_menu}{type, x, y, w, h, name} +Add a menu object to the form. \\ +Methods: +\method{set_menu()}, +\method{get_menu()}, +\method{addto_menu()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_choice}{type, x, y, w, h, name} +Add a choice object to the form. \\ +Methods: +\method{set_choice()}, +\method{get_choice()}, +\method{clear_choice()}, +\method{addto_choice()}, +\method{replace_choice()}, +\method{delete_choice()}, +\method{get_choice_text()}, +\method{set_choice_fontsize()}, +\method{set_choice_fontstyle()}. +\end{methoddesc} + +\begin{methoddesc}[form]{add_browser}{type, x, y, w, h, name} +Add a browser object to the form. \\ +Methods: +\method{set_browser_topline()}, +\method{clear_browser()}, +\method{add_browser_line()}, +\method{addto_browser()}, +\method{insert_browser_line()}, +\method{delete_browser_line()}, +\method{replace_browser_line()}, +\method{get_browser_line()}, +\method{load_browser()}, +\method{get_browser_maxline()}, +\method{select_browser_line()}, +\method{deselect_browser_line()}, +\method{deselect_browser()}, +\method{isselected_browser_line()}, +\method{get_browser()}, +\method{set_browser_fontsize()}, +\method{set_browser_fontstyle()}, +\method{set_browser_specialkey()}. +\end{methoddesc} + +%--- + +\begin{methoddesc}[form]{add_timer}{type, x, y, w, h, name} +Add a timer object to the form. \\ +Methods: +\method{set_timer()}, +\method{get_timer()}. +\end{methoddesc} +\end{flushleft} + +Form objects have the following data attributes; see the FORMS +documentation: + +\begin{tableiii}{l|l|l}{member}{Name}{C Type}{Meaning} + \lineiii{window}{int (read-only)}{GL window id} + \lineiii{w}{float}{form width} + \lineiii{h}{float}{form height} + \lineiii{x}{float}{form x origin} + \lineiii{y}{float}{form y origin} + \lineiii{deactivated}{int}{nonzero if form is deactivated} + \lineiii{visible}{int}{nonzero if form is visible} + \lineiii{frozen}{int}{nonzero if form is frozen} + \lineiii{doublebuf}{int}{nonzero if double buffering on} +\end{tableiii} + +\subsection{FORMS Objects} +\label{forms-objects} + +Besides methods specific to particular kinds of FORMS objects, all +FORMS objects also have the following methods: + +\begin{methoddesc}[FORMS object]{set_call_back}{function, argument} +Set the object's callback function and argument. When the object +needs interaction, the callback function will be called with two +arguments: the object, and the callback argument. (FORMS objects +without a callback function are returned by \function{fl.do_forms()} +or \function{fl.check_forms()} when they need interaction.) Call this +method without arguments to remove the callback function. +\end{methoddesc} + +\begin{methoddesc}[FORMS object]{delete_object}{} + Delete the object. +\end{methoddesc} + +\begin{methoddesc}[FORMS object]{show_object}{} + Show the object. +\end{methoddesc} + +\begin{methoddesc}[FORMS object]{hide_object}{} + Hide the object. +\end{methoddesc} + +\begin{methoddesc}[FORMS object]{redraw_object}{} + Redraw the object. +\end{methoddesc} + +\begin{methoddesc}[FORMS object]{freeze_object}{} + Freeze the object. +\end{methoddesc} + +\begin{methoddesc}[FORMS object]{unfreeze_object}{} + Unfreeze the object. +\end{methoddesc} + +%\begin{methoddesc}[FORMS object]{handle_object}{} XXX +%\end{methoddesc} + +%\begin{methoddesc}[FORMS object]{handle_object_direct}{} XXX +%\end{methoddesc} + +FORMS objects have these data attributes; see the FORMS documentation: + +\begin{tableiii}{l|l|l}{member}{Name}{C Type}{Meaning} + \lineiii{objclass}{int (read-only)}{object class} + \lineiii{type}{int (read-only)}{object type} + \lineiii{boxtype}{int}{box type} + \lineiii{x}{float}{x origin} + \lineiii{y}{float}{y origin} + \lineiii{w}{float}{width} + \lineiii{h}{float}{height} + \lineiii{col1}{int}{primary color} + \lineiii{col2}{int}{secondary color} + \lineiii{align}{int}{alignment} + \lineiii{lcol}{int}{label color} + \lineiii{lsize}{float}{label font size} + \lineiii{label}{string}{label string} + \lineiii{lstyle}{int}{label style} + \lineiii{pushed}{int (read-only)}{(see FORMS docs)} + \lineiii{focus}{int (read-only)}{(see FORMS docs)} + \lineiii{belowmouse}{int (read-only)}{(see FORMS docs)} + \lineiii{frozen}{int (read-only)}{(see FORMS docs)} + \lineiii{active}{int (read-only)}{(see FORMS docs)} + \lineiii{input}{int (read-only)}{(see FORMS docs)} + \lineiii{visible}{int (read-only)}{(see FORMS docs)} + \lineiii{radio}{int (read-only)}{(see FORMS docs)} + \lineiii{automatic}{int (read-only)}{(see FORMS docs)} +\end{tableiii} + + +\section{\module{FL} --- + Constants used with the \module{fl} module} + +\declaremodule[fl-constants]{standard}{FL} + \platform{IRIX} +\modulesynopsis{Constants used with the \module{fl} module.} + + +This module defines symbolic constants needed to use the built-in +module \refmodule{fl} (see above); they are equivalent to those defined in +the C header file \code{} except that the name prefix +\samp{FL_} is omitted. Read the module source for a complete list of +the defined names. Suggested use: + +\begin{verbatim} +import fl +from FL import * +\end{verbatim} + + +\section{\module{flp} --- + Functions for loading stored FORMS designs} + +\declaremodule{standard}{flp} + \platform{IRIX} +\modulesynopsis{Functions for loading stored FORMS designs.} + + +This module defines functions that can read form definitions created +by the `form designer' (\program{fdesign}) program that comes with the +FORMS library (see module \refmodule{fl} above). + +For now, see the file \file{flp.doc} in the Python library source +directory for a description. + +XXX A complete description should be inserted here! diff --git a/sys/src/cmd/python/Doc/lib/libfm.tex b/sys/src/cmd/python/Doc/lib/libfm.tex new file mode 100644 index 000000000..0b429e063 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfm.tex @@ -0,0 +1,94 @@ +\section{\module{fm} --- + \emph{Font Manager} interface} + +\declaremodule{builtin}{fm} + \platform{IRIX} +\modulesynopsis{\emph{Font Manager} interface for SGI workstations.} + + +This module provides access to the IRIS \emph{Font Manager} library. +\index{Font Manager, IRIS} +\index{IRIS Font Manager} +It is available only on Silicon Graphics machines. +See also: \emph{4Sight User's Guide}, section 1, chapter 5: ``Using +the IRIS Font Manager.'' + +This is not yet a full interface to the IRIS Font Manager. +Among the unsupported features are: matrix operations; cache +operations; character operations (use string operations instead); some +details of font info; individual glyph metrics; and printer matching. + +It supports the following operations: + +\begin{funcdesc}{init}{} +Initialization function. +Calls \cfunction{fminit()}. +It is normally not necessary to call this function, since it is called +automatically the first time the \module{fm} module is imported. +\end{funcdesc} + +\begin{funcdesc}{findfont}{fontname} +Return a font handle object. +Calls \code{fmfindfont(\var{fontname})}. +\end{funcdesc} + +\begin{funcdesc}{enumerate}{} +Returns a list of available font names. +This is an interface to \cfunction{fmenumerate()}. +\end{funcdesc} + +\begin{funcdesc}{prstr}{string} +Render a string using the current font (see the \function{setfont()} font +handle method below). +Calls \code{fmprstr(\var{string})}. +\end{funcdesc} + +\begin{funcdesc}{setpath}{string} +Sets the font search path. +Calls \code{fmsetpath(\var{string})}. +(XXX Does not work!?!) +\end{funcdesc} + +\begin{funcdesc}{fontpath}{} +Returns the current font search path. +\end{funcdesc} + +Font handle objects support the following operations: + +\setindexsubitem{(font handle method)} +\begin{funcdesc}{scalefont}{factor} +Returns a handle for a scaled version of this font. +Calls \code{fmscalefont(\var{fh}, \var{factor})}. +\end{funcdesc} + +\begin{funcdesc}{setfont}{} +Makes this font the current font. +Note: the effect is undone silently when the font handle object is +deleted. +Calls \code{fmsetfont(\var{fh})}. +\end{funcdesc} + +\begin{funcdesc}{getfontname}{} +Returns this font's name. +Calls \code{fmgetfontname(\var{fh})}. +\end{funcdesc} + +\begin{funcdesc}{getcomment}{} +Returns the comment string associated with this font. +Raises an exception if there is none. +Calls \code{fmgetcomment(\var{fh})}. +\end{funcdesc} + +\begin{funcdesc}{getfontinfo}{} +Returns a tuple giving some pertinent data about this font. +This is an interface to \code{fmgetfontinfo()}. +The returned tuple contains the following numbers: +\code{(}\var{printermatched}, \var{fixed_width}, \var{xorig}, +\var{yorig}, \var{xsize}, \var{ysize}, \var{height}, +\var{nglyphs}\code{)}. +\end{funcdesc} + +\begin{funcdesc}{getstrwidth}{string} +Returns the width, in pixels, of \var{string} when drawn in this font. +Calls \code{fmgetstrwidth(\var{fh}, \var{string})}. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libfnmatch.tex b/sys/src/cmd/python/Doc/lib/libfnmatch.tex new file mode 100644 index 000000000..1ac46bdd4 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfnmatch.tex @@ -0,0 +1,86 @@ +\section{\module{fnmatch} --- + \UNIX{} filename pattern matching} + +\declaremodule{standard}{fnmatch} +\modulesynopsis{\UNIX\ shell style filename pattern matching.} + + +\index{filenames!wildcard expansion} + +This module provides support for \UNIX{} shell-style wildcards, which +are \emph{not} the same as regular expressions (which are documented +in the \refmodule{re}\refstmodindex{re} module). The special +characters used in shell-style wildcards are: + +\begin{tableii}{c|l}{code}{Pattern}{Meaning} + \lineii{*}{matches everything} + \lineii{?}{matches any single character} + \lineii{[\var{seq}]}{matches any character in \var{seq}} + \lineii{[!\var{seq}]}{matches any character not in \var{seq}} +\end{tableii} + +Note that the filename separator (\code{'/'} on \UNIX) is \emph{not} +special to this module. See module +\refmodule{glob}\refstmodindex{glob} for pathname expansion +(\refmodule{glob} uses \function{fnmatch()} to match pathname +segments). Similarly, filenames starting with a period are +not special for this module, and are matched by the \code{*} and +\code{?} patterns. + + +\begin{funcdesc}{fnmatch}{filename, pattern} +Test whether the \var{filename} string matches the \var{pattern} +string, returning true or false. If the operating system is +case-insensitive, then both parameters will be normalized to all +lower- or upper-case before the comparison is performed. If you +require a case-sensitive comparison regardless of whether that's +standard for your operating system, use \function{fnmatchcase()} +instead. + +This example will print all file names in the current directory with the +extension \code{.txt}: + +\begin{verbatim} +import fnmatch +import os + +for file in os.listdir('.'): + if fnmatch.fnmatch(file, '*.txt'): + print file +\end{verbatim} + +\end{funcdesc} + +\begin{funcdesc}{fnmatchcase}{filename, pattern} +Test whether \var{filename} matches \var{pattern}, returning true or +false; the comparison is case-sensitive. +\end{funcdesc} + +\begin{funcdesc}{filter}{names, pattern} +Return the subset of the list of \var{names} that match \var{pattern}. +It is the same as \code{[n for n in names if fnmatch(n, pattern)]}, but +implemented more efficiently. +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{translate}{pattern} +Return the shell-style \var{pattern} converted to a regular +expression. + +Example: + +\begin{verbatim} +>>> import fnmatch, re +>>> +>>> regex = fnmatch.translate('*.txt') +>>> regex +'.*\\.txt$' +>>> reobj = re.compile(regex) +>>> print reobj.match('foobar.txt') +<_sre.SRE_Match object at 0x...> +\end{verbatim} +\end{funcdesc} + +\begin{seealso} + \seemodule{glob}{\UNIX{} shell-style path expansion.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libformatter.tex b/sys/src/cmd/python/Doc/lib/libformatter.tex new file mode 100644 index 000000000..d7c5a6b83 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libformatter.tex @@ -0,0 +1,329 @@ +\section{\module{formatter} --- + Generic output formatting} + +\declaremodule{standard}{formatter} +\modulesynopsis{Generic output formatter and device interface.} + + + +This module supports two interface definitions, each with multiple +implementations. The \emph{formatter} interface is used by the +\class{HTMLParser} class of the \refmodule{htmllib} module, and the +\emph{writer} interface is required by the formatter interface. +\withsubitem{(class in htmllib)}{\ttindex{HTMLParser}} + +Formatter objects transform an abstract flow of formatting events into +specific output events on writer objects. Formatters manage several +stack structures to allow various properties of a writer object to be +changed and restored; writers need not be able to handle relative +changes nor any sort of ``change back'' operation. Specific writer +properties which may be controlled via formatter objects are +horizontal alignment, font, and left margin indentations. A mechanism +is provided which supports providing arbitrary, non-exclusive style +settings to a writer as well. Additional interfaces facilitate +formatting events which are not reversible, such as paragraph +separation. + +Writer objects encapsulate device interfaces. Abstract devices, such +as file formats, are supported as well as physical devices. The +provided implementations all work with abstract devices. The +interface makes available mechanisms for setting the properties which +formatter objects manage and inserting data into the output. + + +\subsection{The Formatter Interface \label{formatter-interface}} + +Interfaces to create formatters are dependent on the specific +formatter class being instantiated. The interfaces described below +are the required interfaces which all formatters must support once +initialized. + +One data element is defined at the module level: + + +\begin{datadesc}{AS_IS} +Value which can be used in the font specification passed to the +\code{push_font()} method described below, or as the new value to any +other \code{push_\var{property}()} method. Pushing the \code{AS_IS} +value allows the corresponding \code{pop_\var{property}()} method to +be called without having to track whether the property was changed. +\end{datadesc} + +The following attributes are defined for formatter instance objects: + + +\begin{memberdesc}[formatter]{writer} +The writer instance with which the formatter interacts. +\end{memberdesc} + + +\begin{methoddesc}[formatter]{end_paragraph}{blanklines} +Close any open paragraphs and insert at least \var{blanklines} +before the next paragraph. +\end{methoddesc} + +\begin{methoddesc}[formatter]{add_line_break}{} +Add a hard line break if one does not already exist. This does not +break the logical paragraph. +\end{methoddesc} + +\begin{methoddesc}[formatter]{add_hor_rule}{*args, **kw} +Insert a horizontal rule in the output. A hard break is inserted if +there is data in the current paragraph, but the logical paragraph is +not broken. The arguments and keywords are passed on to the writer's +\method{send_line_break()} method. +\end{methoddesc} + +\begin{methoddesc}[formatter]{add_flowing_data}{data} +Provide data which should be formatted with collapsed whitespace. +Whitespace from preceding and successive calls to +\method{add_flowing_data()} is considered as well when the whitespace +collapse is performed. The data which is passed to this method is +expected to be word-wrapped by the output device. Note that any +word-wrapping still must be performed by the writer object due to the +need to rely on device and font information. +\end{methoddesc} + +\begin{methoddesc}[formatter]{add_literal_data}{data} +Provide data which should be passed to the writer unchanged. +Whitespace, including newline and tab characters, are considered legal +in the value of \var{data}. +\end{methoddesc} + +\begin{methoddesc}[formatter]{add_label_data}{format, counter} +Insert a label which should be placed to the left of the current left +margin. This should be used for constructing bulleted or numbered +lists. If the \var{format} value is a string, it is interpreted as a +format specification for \var{counter}, which should be an integer. +The result of this formatting becomes the value of the label; if +\var{format} is not a string it is used as the label value directly. +The label value is passed as the only argument to the writer's +\method{send_label_data()} method. Interpretation of non-string label +values is dependent on the associated writer. + +Format specifications are strings which, in combination with a counter +value, are used to compute label values. Each character in the format +string is copied to the label value, with some characters recognized +to indicate a transform on the counter value. Specifically, the +character \character{1} represents the counter value formatter as an +Arabic number, the characters \character{A} and \character{a} +represent alphabetic representations of the counter value in upper and +lower case, respectively, and \character{I} and \character{i} +represent the counter value in Roman numerals, in upper and lower +case. Note that the alphabetic and roman transforms require that the +counter value be greater than zero. +\end{methoddesc} + +\begin{methoddesc}[formatter]{flush_softspace}{} +Send any pending whitespace buffered from a previous call to +\method{add_flowing_data()} to the associated writer object. This +should be called before any direct manipulation of the writer object. +\end{methoddesc} + +\begin{methoddesc}[formatter]{push_alignment}{align} +Push a new alignment setting onto the alignment stack. This may be +\constant{AS_IS} if no change is desired. If the alignment value is +changed from the previous setting, the writer's \method{new_alignment()} +method is called with the \var{align} value. +\end{methoddesc} + +\begin{methoddesc}[formatter]{pop_alignment}{} +Restore the previous alignment. +\end{methoddesc} + +\begin{methoddesc}[formatter]{push_font}{\code{(}size, italic, bold, teletype\code{)}} +Change some or all font properties of the writer object. Properties +which are not set to \constant{AS_IS} are set to the values passed in +while others are maintained at their current settings. The writer's +\method{new_font()} method is called with the fully resolved font +specification. +\end{methoddesc} + +\begin{methoddesc}[formatter]{pop_font}{} +Restore the previous font. +\end{methoddesc} + +\begin{methoddesc}[formatter]{push_margin}{margin} +Increase the number of left margin indentations by one, associating +the logical tag \var{margin} with the new indentation. The initial +margin level is \code{0}. Changed values of the logical tag must be +true values; false values other than \constant{AS_IS} are not +sufficient to change the margin. +\end{methoddesc} + +\begin{methoddesc}[formatter]{pop_margin}{} +Restore the previous margin. +\end{methoddesc} + +\begin{methoddesc}[formatter]{push_style}{*styles} +Push any number of arbitrary style specifications. All styles are +pushed onto the styles stack in order. A tuple representing the +entire stack, including \constant{AS_IS} values, is passed to the +writer's \method{new_styles()} method. +\end{methoddesc} + +\begin{methoddesc}[formatter]{pop_style}{\optional{n\code{ = 1}}} +Pop the last \var{n} style specifications passed to +\method{push_style()}. A tuple representing the revised stack, +including \constant{AS_IS} values, is passed to the writer's +\method{new_styles()} method. +\end{methoddesc} + +\begin{methoddesc}[formatter]{set_spacing}{spacing} +Set the spacing style for the writer. +\end{methoddesc} + +\begin{methoddesc}[formatter]{assert_line_data}{\optional{flag\code{ = 1}}} +Inform the formatter that data has been added to the current paragraph +out-of-band. This should be used when the writer has been manipulated +directly. The optional \var{flag} argument can be set to false if +the writer manipulations produced a hard line break at the end of the +output. +\end{methoddesc} + + +\subsection{Formatter Implementations \label{formatter-impls}} + +Two implementations of formatter objects are provided by this module. +Most applications may use one of these classes without modification or +subclassing. + +\begin{classdesc}{NullFormatter}{\optional{writer}} +A formatter which does nothing. If \var{writer} is omitted, a +\class{NullWriter} instance is created. No methods of the writer are +called by \class{NullFormatter} instances. Implementations should +inherit from this class if implementing a writer interface but don't +need to inherit any implementation. +\end{classdesc} + +\begin{classdesc}{AbstractFormatter}{writer} +The standard formatter. This implementation has demonstrated wide +applicability to many writers, and may be used directly in most +circumstances. It has been used to implement a full-featured +World Wide Web browser. +\end{classdesc} + + + +\subsection{The Writer Interface \label{writer-interface}} + +Interfaces to create writers are dependent on the specific writer +class being instantiated. The interfaces described below are the +required interfaces which all writers must support once initialized. +Note that while most applications can use the +\class{AbstractFormatter} class as a formatter, the writer must +typically be provided by the application. + + +\begin{methoddesc}[writer]{flush}{} +Flush any buffered output or device control events. +\end{methoddesc} + +\begin{methoddesc}[writer]{new_alignment}{align} +Set the alignment style. The \var{align} value can be any object, +but by convention is a string or \code{None}, where \code{None} +indicates that the writer's ``preferred'' alignment should be used. +Conventional \var{align} values are \code{'left'}, \code{'center'}, +\code{'right'}, and \code{'justify'}. +\end{methoddesc} + +\begin{methoddesc}[writer]{new_font}{font} +Set the font style. The value of \var{font} will be \code{None}, +indicating that the device's default font should be used, or a tuple +of the form \code{(}\var{size}, \var{italic}, \var{bold}, +\var{teletype}\code{)}. Size will be a string indicating the size of +font that should be used; specific strings and their interpretation +must be defined by the application. The \var{italic}, \var{bold}, and +\var{teletype} values are Boolean values specifying which of those +font attributes should be used. +\end{methoddesc} + +\begin{methoddesc}[writer]{new_margin}{margin, level} +Set the margin level to the integer \var{level} and the logical tag +to \var{margin}. Interpretation of the logical tag is at the +writer's discretion; the only restriction on the value of the logical +tag is that it not be a false value for non-zero values of +\var{level}. +\end{methoddesc} + +\begin{methoddesc}[writer]{new_spacing}{spacing} +Set the spacing style to \var{spacing}. +\end{methoddesc} + +\begin{methoddesc}[writer]{new_styles}{styles} +Set additional styles. The \var{styles} value is a tuple of +arbitrary values; the value \constant{AS_IS} should be ignored. The +\var{styles} tuple may be interpreted either as a set or as a stack +depending on the requirements of the application and writer +implementation. +\end{methoddesc} + +\begin{methoddesc}[writer]{send_line_break}{} +Break the current line. +\end{methoddesc} + +\begin{methoddesc}[writer]{send_paragraph}{blankline} +Produce a paragraph separation of at least \var{blankline} blank +lines, or the equivalent. The \var{blankline} value will be an +integer. Note that the implementation will receive a call to +\method{send_line_break()} before this call if a line break is needed; +this method should not include ending the last line of the paragraph. +It is only responsible for vertical spacing between paragraphs. +\end{methoddesc} + +\begin{methoddesc}[writer]{send_hor_rule}{*args, **kw} +Display a horizontal rule on the output device. The arguments to this +method are entirely application- and writer-specific, and should be +interpreted with care. The method implementation may assume that a +line break has already been issued via \method{send_line_break()}. +\end{methoddesc} + +\begin{methoddesc}[writer]{send_flowing_data}{data} +Output character data which may be word-wrapped and re-flowed as +needed. Within any sequence of calls to this method, the writer may +assume that spans of multiple whitespace characters have been +collapsed to single space characters. +\end{methoddesc} + +\begin{methoddesc}[writer]{send_literal_data}{data} +Output character data which has already been formatted +for display. Generally, this should be interpreted to mean that line +breaks indicated by newline characters should be preserved and no new +line breaks should be introduced. The data may contain embedded +newline and tab characters, unlike data provided to the +\method{send_formatted_data()} interface. +\end{methoddesc} + +\begin{methoddesc}[writer]{send_label_data}{data} +Set \var{data} to the left of the current left margin, if possible. +The value of \var{data} is not restricted; treatment of non-string +values is entirely application- and writer-dependent. This method +will only be called at the beginning of a line. +\end{methoddesc} + + +\subsection{Writer Implementations \label{writer-impls}} + +Three implementations of the writer object interface are provided as +examples by this module. Most applications will need to derive new +writer classes from the \class{NullWriter} class. + +\begin{classdesc}{NullWriter}{} +A writer which only provides the interface definition; no actions are +taken on any methods. This should be the base class for all writers +which do not need to inherit any implementation methods. +\end{classdesc} + +\begin{classdesc}{AbstractWriter}{} +A writer which can be used in debugging formatters, but not much +else. Each method simply announces itself by printing its name and +arguments on standard output. +\end{classdesc} + +\begin{classdesc}{DumbWriter}{\optional{file\optional{, maxcol\code{ = 72}}}} +Simple writer class which writes output on the file object passed in +as \var{file} or, if \var{file} is omitted, on standard output. The +output is simply word-wrapped to the number of columns specified by +\var{maxcol}. This class is suitable for reflowing a sequence of +paragraphs. +\end{classdesc} diff --git a/sys/src/cmd/python/Doc/lib/libfpectl.tex b/sys/src/cmd/python/Doc/lib/libfpectl.tex new file mode 100644 index 000000000..cca231476 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfpectl.tex @@ -0,0 +1,127 @@ +\section{\module{fpectl} --- + Floating point exception control} + +\declaremodule{extension}{fpectl} + \platform{Unix} +\moduleauthor{Lee Busby}{busby1@llnl.gov} +\sectionauthor{Lee Busby}{busby1@llnl.gov} +\modulesynopsis{Provide control for floating point exception handling.} + +\note{The \module{fpectl} module is not built by default, and its usage + is discouraged and may be dangerous except in the hands of + experts. See also the section \ref{fpectl-limitations} on + limitations for more details.} + +Most computers carry out floating point operations\index{IEEE-754} +in conformance with the so-called IEEE-754 standard. +On any real computer, +some floating point operations produce results that cannot +be expressed as a normal floating point value. +For example, try + +\begin{verbatim} +>>> import math +>>> math.exp(1000) +inf +>>> math.exp(1000) / math.exp(1000) +nan +\end{verbatim} + +(The example above will work on many platforms. +DEC Alpha may be one exception.) +"Inf" is a special, non-numeric value in IEEE-754 that +stands for "infinity", and "nan" means "not a number." +Note that, +other than the non-numeric results, +nothing special happened when you asked Python +to carry out those calculations. +That is in fact the default behaviour prescribed in the IEEE-754 standard, +and if it works for you, +stop reading now. + +In some circumstances, +it would be better to raise an exception and stop processing +at the point where the faulty operation was attempted. +The \module{fpectl} module +is for use in that situation. +It provides control over floating point +units from several hardware manufacturers, +allowing the user to turn on the generation +of \constant{SIGFPE} whenever any of the +IEEE-754 exceptions Division by Zero, Overflow, or +Invalid Operation occurs. +In tandem with a pair of wrapper macros that are inserted +into the C code comprising your python system, +\constant{SIGFPE} is trapped and converted into the Python +\exception{FloatingPointError} exception. + +The \module{fpectl} module defines the following functions and +may raise the given exception: + +\begin{funcdesc}{turnon_sigfpe}{} +Turn on the generation of \constant{SIGFPE}, +and set up an appropriate signal handler. +\end{funcdesc} + +\begin{funcdesc}{turnoff_sigfpe}{} +Reset default handling of floating point exceptions. +\end{funcdesc} + +\begin{excdesc}{FloatingPointError} +After \function{turnon_sigfpe()} has been executed, +a floating point operation that raises one of the +IEEE-754 exceptions +Division by Zero, Overflow, or Invalid operation +will in turn raise this standard Python exception. +\end{excdesc} + + +\subsection{Example \label{fpectl-example}} + +The following example demonstrates how to start up and test operation of +the \module{fpectl} module. + +\begin{verbatim} +>>> import fpectl +>>> import fpetest +>>> fpectl.turnon_sigfpe() +>>> fpetest.test() +overflow PASS +FloatingPointError: Overflow + +div by 0 PASS +FloatingPointError: Division by zero + [ more output from test elided ] +>>> import math +>>> math.exp(1000) +Traceback (most recent call last): + File "", line 1, in ? +FloatingPointError: in math_1 +\end{verbatim} + + +\subsection{Limitations and other considerations \label{fpectl-limitations}} + +Setting up a given processor to trap IEEE-754 floating point +errors currently requires custom code on a per-architecture basis. +You may have to modify \module{fpectl} to control your particular hardware. + +Conversion of an IEEE-754 exception to a Python exception requires +that the wrapper macros \code{PyFPE_START_PROTECT} and +\code{PyFPE_END_PROTECT} be inserted into your code in an appropriate +fashion. Python itself has been modified to support the +\module{fpectl} module, but many other codes of interest to numerical +analysts have not. + +The \module{fpectl} module is not thread-safe. + +\begin{seealso} + \seetext{Some files in the source distribution may be interesting in + learning more about how this module operates. + The include file \file{Include/pyfpe.h} discusses the + implementation of this module at some length. + \file{Modules/fpetestmodule.c} gives several examples of + use. + Many additional examples can be found in + \file{Objects/floatobject.c}.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libfpformat.tex b/sys/src/cmd/python/Doc/lib/libfpformat.tex new file mode 100644 index 000000000..a3a628223 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfpformat.tex @@ -0,0 +1,54 @@ +\section{\module{fpformat} --- + Floating point conversions} + +\declaremodule{standard}{fpformat} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{General floating point formatting functions.} + + +The \module{fpformat} module defines functions for dealing with +floating point numbers representations in 100\% pure +Python. \note{This module is unneeded: everything here could +be done via the \code{\%} string interpolation operator.} + +The \module{fpformat} module defines the following functions and an +exception: + + +\begin{funcdesc}{fix}{x, digs} +Format \var{x} as \code{[-]ddd.ddd} with \var{digs} digits after the +point and at least one digit before. +If \code{\var{digs} <= 0}, the decimal point is suppressed. + +\var{x} can be either a number or a string that looks like +one. \var{digs} is an integer. + +Return value is a string. +\end{funcdesc} + +\begin{funcdesc}{sci}{x, digs} +Format \var{x} as \code{[-]d.dddE[+-]ddd} with \var{digs} digits after the +point and exactly one digit before. +If \code{\var{digs} <= 0}, one digit is kept and the point is suppressed. + +\var{x} can be either a real number, or a string that looks like +one. \var{digs} is an integer. + +Return value is a string. +\end{funcdesc} + +\begin{excdesc}{NotANumber} +Exception raised when a string passed to \function{fix()} or +\function{sci()} as the \var{x} parameter does not look like a number. +This is a subclass of \exception{ValueError} when the standard +exceptions are strings. The exception value is the improperly +formatted string that caused the exception to be raised. +\end{excdesc} + +Example: + +\begin{verbatim} +>>> import fpformat +>>> fpformat.fix(1.23, 1) +'1.2' +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libftplib.tex b/sys/src/cmd/python/Doc/lib/libftplib.tex new file mode 100644 index 000000000..58d16cb10 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libftplib.tex @@ -0,0 +1,288 @@ +\section{\module{ftplib} --- + FTP protocol client} + +\declaremodule{standard}{ftplib} +\modulesynopsis{FTP protocol client (requires sockets).} + +\indexii{FTP}{protocol} +\index{FTP!\module{ftplib} (standard module)} + +This module defines the class \class{FTP} and a few related items. +The \class{FTP} class implements the client side of the FTP +protocol. You can use this to write Python +programs that perform a variety of automated FTP jobs, such as +mirroring other ftp servers. It is also used by the module +\refmodule{urllib} to handle URLs that use FTP. For more information +on FTP (File Transfer Protocol), see Internet \rfc{959}. + +Here's a sample session using the \module{ftplib} module: + +\begin{verbatim} +>>> from ftplib import FTP +>>> ftp = FTP('ftp.cwi.nl') # connect to host, default port +>>> ftp.login() # user anonymous, passwd anonymous@ +>>> ftp.retrlines('LIST') # list directory contents +total 24418 +drwxrwsr-x 5 ftp-usr pdmaint 1536 Mar 20 09:48 . +dr-xr-srwt 105 ftp-usr pdmaint 1536 Mar 21 14:32 .. +-rw-r--r-- 1 ftp-usr pdmaint 5305 Mar 20 09:48 INDEX + . + . + . +>>> ftp.retrbinary('RETR README', open('README', 'wb').write) +'226 Transfer complete.' +>>> ftp.quit() +\end{verbatim} + +The module defines the following items: + +\begin{classdesc}{FTP}{\optional{host\optional{, user\optional{, + passwd\optional{, acct}}}}} +Return a new instance of the \class{FTP} class. When +\var{host} is given, the method call \code{connect(\var{host})} is +made. When \var{user} is given, additionally the method call +\code{login(\var{user}, \var{passwd}, \var{acct})} is made (where +\var{passwd} and \var{acct} default to the empty string when not given). +\end{classdesc} + +\begin{datadesc}{all_errors} +The set of all exceptions (as a tuple) that methods of \class{FTP} +instances may raise as a result of problems with the FTP connection +(as opposed to programming errors made by the caller). This set +includes the four exceptions listed below as well as +\exception{socket.error} and \exception{IOError}. +\end{datadesc} + +\begin{excdesc}{error_reply} +Exception raised when an unexpected reply is received from the server. +\end{excdesc} + +\begin{excdesc}{error_temp} +Exception raised when an error code in the range 400--499 is received. +\end{excdesc} + +\begin{excdesc}{error_perm} +Exception raised when an error code in the range 500--599 is received. +\end{excdesc} + +\begin{excdesc}{error_proto} +Exception raised when a reply is received from the server that does +not begin with a digit in the range 1--5. +\end{excdesc} + + +\begin{seealso} + \seemodule{netrc}{Parser for the \file{.netrc} file format. The file + \file{.netrc} is typically used by FTP clients to + load user authentication information before prompting + the user.} + \seetext{The file \file{Tools/scripts/ftpmirror.py}\index{ftpmirror.py} + in the Python source distribution is a script that can mirror + FTP sites, or portions thereof, using the \module{ftplib} module. + It can be used as an extended example that applies this module.} +\end{seealso} + + +\subsection{FTP Objects \label{ftp-objects}} + +Several methods are available in two flavors: one for handling text +files and another for binary files. These are named for the command +which is used followed by \samp{lines} for the text version or +\samp{binary} for the binary version. + +\class{FTP} instances have the following methods: + +\begin{methoddesc}{set_debuglevel}{level} +Set the instance's debugging level. This controls the amount of +debugging output printed. The default, \code{0}, produces no +debugging output. A value of \code{1} produces a moderate amount of +debugging output, generally a single line per request. A value of +\code{2} or higher produces the maximum amount of debugging output, +logging each line sent and received on the control connection. +\end{methoddesc} + +\begin{methoddesc}{connect}{host\optional{, port}} +Connect to the given host and port. The default port number is \code{21}, as +specified by the FTP protocol specification. It is rarely needed to +specify a different port number. This function should be called only +once for each instance; it should not be called at all if a host was +given when the instance was created. All other methods can only be +used after a connection has been made. +\end{methoddesc} + +\begin{methoddesc}{getwelcome}{} +Return the welcome message sent by the server in reply to the initial +connection. (This message sometimes contains disclaimers or help +information that may be relevant to the user.) +\end{methoddesc} + +\begin{methoddesc}{login}{\optional{user\optional{, passwd\optional{, acct}}}} +Log in as the given \var{user}. The \var{passwd} and \var{acct} +parameters are optional and default to the empty string. If no +\var{user} is specified, it defaults to \code{'anonymous'}. If +\var{user} is \code{'anonymous'}, the default \var{passwd} is +\code{'anonymous@'}. This function should be called only +once for each instance, after a connection has been established; it +should not be called at all if a host and user were given when the +instance was created. Most FTP commands are only allowed after the +client has logged in. +\end{methoddesc} + +\begin{methoddesc}{abort}{} +Abort a file transfer that is in progress. Using this does not always +work, but it's worth a try. +\end{methoddesc} + +\begin{methoddesc}{sendcmd}{command} +Send a simple command string to the server and return the response +string. +\end{methoddesc} + +\begin{methoddesc}{voidcmd}{command} +Send a simple command string to the server and handle the response. +Return nothing if a response code in the range 200--299 is received. +Raise an exception otherwise. +\end{methoddesc} + +\begin{methoddesc}{retrbinary}{command, + callback\optional{, maxblocksize\optional{, rest}}} +Retrieve a file in binary transfer mode. \var{command} should be an +appropriate \samp{RETR} command: \code{'RETR \var{filename}'}. +The \var{callback} function is called for each block of data received, +with a single string argument giving the data block. +The optional \var{maxblocksize} argument specifies the maximum chunk size to +read on the low-level socket object created to do the actual transfer +(which will also be the largest size of the data blocks passed to +\var{callback}). A reasonable default is chosen. \var{rest} means the +same thing as in the \method{transfercmd()} method. +\end{methoddesc} + +\begin{methoddesc}{retrlines}{command\optional{, callback}} +Retrieve a file or directory listing in \ASCII{} transfer mode. +\var{command} should be an appropriate \samp{RETR} command (see +\method{retrbinary()}) or a \samp{LIST} command (usually just the string +\code{'LIST'}). The \var{callback} function is called for each line, +with the trailing CRLF stripped. The default \var{callback} prints +the line to \code{sys.stdout}. +\end{methoddesc} + +\begin{methoddesc}{set_pasv}{boolean} +Enable ``passive'' mode if \var{boolean} is true, other disable +passive mode. (In Python 2.0 and before, passive mode was off by +default; in Python 2.1 and later, it is on by default.) +\end{methoddesc} + +\begin{methoddesc}{storbinary}{command, file\optional{, blocksize}} +Store a file in binary transfer mode. \var{command} should be an +appropriate \samp{STOR} command: \code{"STOR \var{filename}"}. +\var{file} is an open file object which is read until \EOF{} using its +\method{read()} method in blocks of size \var{blocksize} to provide the +data to be stored. The \var{blocksize} argument defaults to 8192. +\versionchanged[default for \var{blocksize} added]{2.1} +\end{methoddesc} + +\begin{methoddesc}{storlines}{command, file} +Store a file in \ASCII{} transfer mode. \var{command} should be an +appropriate \samp{STOR} command (see \method{storbinary()}). Lines are +read until \EOF{} from the open file object \var{file} using its +\method{readline()} method to provide the data to be stored. +\end{methoddesc} + +\begin{methoddesc}{transfercmd}{cmd\optional{, rest}} +Initiate a transfer over the data connection. If the transfer is +active, send a \samp{EPRT} or \samp{PORT} command and the transfer command specified +by \var{cmd}, and accept the connection. If the server is passive, +send a \samp{EPSV} or \samp{PASV} command, connect to it, and start the transfer +command. Either way, return the socket for the connection. + +If optional \var{rest} is given, a \samp{REST} command is +sent to the server, passing \var{rest} as an argument. \var{rest} is +usually a byte offset into the requested file, telling the server to +restart sending the file's bytes at the requested offset, skipping +over the initial bytes. Note however that RFC +959 requires only that \var{rest} be a string containing characters +in the printable range from ASCII code 33 to ASCII code 126. The +\method{transfercmd()} method, therefore, converts +\var{rest} to a string, but no check is +performed on the string's contents. If the server does +not recognize the \samp{REST} command, an +\exception{error_reply} exception will be raised. If this happens, +simply call \method{transfercmd()} without a \var{rest} argument. +\end{methoddesc} + +\begin{methoddesc}{ntransfercmd}{cmd\optional{, rest}} +Like \method{transfercmd()}, but returns a tuple of the data +connection and the expected size of the data. If the expected size +could not be computed, \code{None} will be returned as the expected +size. \var{cmd} and \var{rest} means the same thing as in +\method{transfercmd()}. +\end{methoddesc} + +\begin{methoddesc}{nlst}{argument\optional{, \ldots}} +Return a list of files as returned by the \samp{NLST} command. The +optional \var{argument} is a directory to list (default is the current +server directory). Multiple arguments can be used to pass +non-standard options to the \samp{NLST} command. +\end{methoddesc} + +\begin{methoddesc}{dir}{argument\optional{, \ldots}} +Produce a directory listing as returned by the \samp{LIST} command, +printing it to standard output. The optional \var{argument} is a +directory to list (default is the current server directory). Multiple +arguments can be used to pass non-standard options to the \samp{LIST} +command. If the last argument is a function, it is used as a +\var{callback} function as for \method{retrlines()}; the default +prints to \code{sys.stdout}. This method returns \code{None}. +\end{methoddesc} + +\begin{methoddesc}{rename}{fromname, toname} +Rename file \var{fromname} on the server to \var{toname}. +\end{methoddesc} + +\begin{methoddesc}{delete}{filename} +Remove the file named \var{filename} from the server. If successful, +returns the text of the response, otherwise raises +\exception{error_perm} on permission errors or +\exception{error_reply} on other errors. +\end{methoddesc} + +\begin{methoddesc}{cwd}{pathname} +Set the current directory on the server. +\end{methoddesc} + +\begin{methoddesc}{mkd}{pathname} +Create a new directory on the server. +\end{methoddesc} + +\begin{methoddesc}{pwd}{} +Return the pathname of the current directory on the server. +\end{methoddesc} + +\begin{methoddesc}{rmd}{dirname} +Remove the directory named \var{dirname} on the server. +\end{methoddesc} + +\begin{methoddesc}{size}{filename} +Request the size of the file named \var{filename} on the server. On +success, the size of the file is returned as an integer, otherwise +\code{None} is returned. Note that the \samp{SIZE} command is not +standardized, but is supported by many common server implementations. +\end{methoddesc} + +\begin{methoddesc}{quit}{} +Send a \samp{QUIT} command to the server and close the connection. +This is the ``polite'' way to close a connection, but it may raise an +exception of the server reponds with an error to the +\samp{QUIT} command. This implies a call to the \method{close()} +method which renders the \class{FTP} instance useless for subsequent +calls (see below). +\end{methoddesc} + +\begin{methoddesc}{close}{} +Close the connection unilaterally. This should not be applied to an +already closed connection such as after a successful call to +\method{quit()}. After this call the \class{FTP} instance should not +be used any more (after a call to \method{close()} or +\method{quit()} you cannot reopen the connection by issuing another +\method{login()} method). +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libfuncs.tex b/sys/src/cmd/python/Doc/lib/libfuncs.tex new file mode 100644 index 000000000..84f56d873 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfuncs.tex @@ -0,0 +1,1321 @@ +\section{Built-in Functions \label{built-in-funcs}} + +The Python interpreter has a number of functions built into it that +are always available. They are listed here in alphabetical order. + + +\setindexsubitem{(built-in function)} + +\begin{funcdesc}{__import__}{name\optional{, globals\optional{, locals\optional{, fromlist\optional{, level}}}}} + This function is invoked by the \keyword{import}\stindex{import} + statement. It mainly exists so that you can replace it with another + function that has a compatible interface, in order to change the + semantics of the \keyword{import} statement. For examples of why + and how you would do this, see the standard library modules + \module{ihooks}\refstmodindex{ihooks} and + \refmodule{rexec}\refstmodindex{rexec}. See also the built-in + module \refmodule{imp}\refbimodindex{imp}, which defines some useful + operations out of which you can build your own + \function{__import__()} function. + + For example, the statement \samp{import spam} results in the + following call: \code{__import__('spam',} \code{globals(),} + \code{locals(), [], -1)}; the statement \samp{from spam.ham import eggs} + results in \samp{__import__('spam.ham', globals(), locals(), + ['eggs'], -1)}. Note that even though \code{locals()} and + \code{['eggs']} are passed in as arguments, the + \function{__import__()} function does not set the local variable + named \code{eggs}; this is done by subsequent code that is generated + for the import statement. (In fact, the standard implementation + does not use its \var{locals} argument at all, and uses its + \var{globals} only to determine the package context of the + \keyword{import} statement.) + + When the \var{name} variable is of the form \code{package.module}, + normally, the top-level package (the name up till the first dot) is + returned, \emph{not} the module named by \var{name}. However, when + a non-empty \var{fromlist} argument is given, the module named by + \var{name} is returned. This is done for compatibility with the + bytecode generated for the different kinds of import statement; when + using \samp{import spam.ham.eggs}, the top-level package \module{spam} + must be placed in the importing namespace, but when using \samp{from + spam.ham import eggs}, the \code{spam.ham} subpackage must be used + to find the \code{eggs} variable. As a workaround for this + behavior, use \function{getattr()} to extract the desired + components. For example, you could define the following helper: + +\begin{verbatim} +def my_import(name): + mod = __import__(name) + components = name.split('.') + for comp in components[1:]: + mod = getattr(mod, comp) + return mod +\end{verbatim} + + \var{level} specifies whether to use absolute or relative imports. + The default is \code{-1} which indicates both absolute and relative + imports will be attempted. \code{0} means only perform absolute imports. + Positive values for \var{level} indicate the number of parent directories + to search relative to the directory of the module calling + \function{__import__}. +\versionchanged[The level parameter was added]{2.5} +\versionchanged[Keyword support for parameters was added]{2.5} +\end{funcdesc} + +\begin{funcdesc}{abs}{x} + Return the absolute value of a number. The argument may be a plain + or long integer or a floating point number. If the argument is a + complex number, its magnitude is returned. +\end{funcdesc} + +\begin{funcdesc}{all}{iterable} + Return True if all elements of the \var{iterable} are true. + Equivalent to: + \begin{verbatim} + def all(iterable): + for element in iterable: + if not element: + return False + return True + \end{verbatim} + \versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{any}{iterable} + Return True if any element of the \var{iterable} is true. + Equivalent to: + \begin{verbatim} + def any(iterable): + for element in iterable: + if element: + return True + return False + \end{verbatim} + \versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{basestring}{} + This abstract type is the superclass for \class{str} and \class{unicode}. + It cannot be called or instantiated, but it can be used to test whether + an object is an instance of \class{str} or \class{unicode}. + \code{isinstance(obj, basestring)} is equivalent to + \code{isinstance(obj, (str, unicode))}. + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{bool}{\optional{x}} + Convert a value to a Boolean, using the standard truth testing + procedure. If \var{x} is false or omitted, this returns + \constant{False}; otherwise it returns \constant{True}. + \class{bool} is also a class, which is a subclass of \class{int}. + Class \class{bool} cannot be subclassed further. Its only instances + are \constant{False} and \constant{True}. + + \indexii{Boolean}{type} + \versionadded{2.2.1} + \versionchanged[If no argument is given, this function returns + \constant{False}]{2.3} +\end{funcdesc} + +\begin{funcdesc}{callable}{object} + Return true if the \var{object} argument appears callable, false if + not. If this returns true, it is still possible that a call fails, + but if it is false, calling \var{object} will never succeed. Note + that classes are callable (calling a class returns a new instance); + class instances are callable if they have a \method{__call__()} + method. +\end{funcdesc} + +\begin{funcdesc}{chr}{i} + Return a string of one character whose \ASCII{} code is the integer + \var{i}. For example, \code{chr(97)} returns the string \code{'a'}. + This is the inverse of \function{ord()}. The argument must be in + the range [0..255], inclusive; \exception{ValueError} will be raised + if \var{i} is outside that range. +\end{funcdesc} + +\begin{funcdesc}{classmethod}{function} + Return a class method for \var{function}. + + A class method receives the class as implicit first argument, + just like an instance method receives the instance. + To declare a class method, use this idiom: + +\begin{verbatim} +class C: + @classmethod + def f(cls, arg1, arg2, ...): ... +\end{verbatim} + + The \code{@classmethod} form is a function decorator -- see the description + of function definitions in chapter 7 of the + \citetitle[../ref/ref.html]{Python Reference Manual} for details. + + It can be called either on the class (such as \code{C.f()}) or on an + instance (such as \code{C().f()}). The instance is ignored except for + its class. + If a class method is called for a derived class, the derived class + object is passed as the implied first argument. + + Class methods are different than \Cpp{} or Java static methods. + If you want those, see \function{staticmethod()} in this section. + + For more information on class methods, consult the documentation on the + standard type hierarchy in chapter 3 of the + \citetitle[../ref/types.html]{Python Reference Manual} (at the bottom). + \versionadded{2.2} + \versionchanged[Function decorator syntax added]{2.4} +\end{funcdesc} + +\begin{funcdesc}{cmp}{x, y} + Compare the two objects \var{x} and \var{y} and return an integer + according to the outcome. The return value is negative if \code{\var{x} + < \var{y}}, zero if \code{\var{x} == \var{y}} and strictly positive if + \code{\var{x} > \var{y}}. +\end{funcdesc} + +\begin{funcdesc}{compile}{string, filename, kind\optional{, + flags\optional{, dont_inherit}}} + Compile the \var{string} into a code object. Code objects can be + executed by an \keyword{exec} statement or evaluated by a call to + \function{eval()}. The \var{filename} argument should + give the file from which the code was read; pass some recognizable value + if it wasn't read from a file (\code{''} is commonly used). + The \var{kind} argument specifies what kind of code must be + compiled; it can be \code{'exec'} if \var{string} consists of a + sequence of statements, \code{'eval'} if it consists of a single + expression, or \code{'single'} if it consists of a single + interactive statement (in the latter case, expression statements + that evaluate to something else than \code{None} will be printed). + + When compiling multi-line statements, two caveats apply: line + endings must be represented by a single newline character + (\code{'\e n'}), and the input must be terminated by at least one + newline character. If line endings are represented by + \code{'\e r\e n'}, use the string \method{replace()} method to + change them into \code{'\e n'}. + + The optional arguments \var{flags} and \var{dont_inherit} + (which are new in Python 2.2) control which future statements (see + \pep{236}) affect the compilation of \var{string}. If neither is + present (or both are zero) the code is compiled with those future + statements that are in effect in the code that is calling compile. + If the \var{flags} argument is given and \var{dont_inherit} is not + (or is zero) then the future statements specified by the \var{flags} + argument are used in addition to those that would be used anyway. + If \var{dont_inherit} is a non-zero integer then the \var{flags} + argument is it -- the future statements in effect around the call to + compile are ignored. + + Future statements are specified by bits which can be bitwise or-ed + together to specify multiple statements. The bitfield required to + specify a given feature can be found as the \member{compiler_flag} + attribute on the \class{_Feature} instance in the + \module{__future__} module. +\end{funcdesc} + +\begin{funcdesc}{complex}{\optional{real\optional{, imag}}} + Create a complex number with the value \var{real} + \var{imag}*j or + convert a string or number to a complex number. If the first + parameter is a string, it will be interpreted as a complex number + and the function must be called without a second parameter. The + second parameter can never be a string. + Each argument may be any numeric type (including complex). + If \var{imag} is omitted, it defaults to zero and the function + serves as a numeric conversion function like \function{int()}, + \function{long()} and \function{float()}. If both arguments + are omitted, returns \code{0j}. +\end{funcdesc} + +\begin{funcdesc}{delattr}{object, name} + This is a relative of \function{setattr()}. The arguments are an + object and a string. The string must be the name + of one of the object's attributes. The function deletes + the named attribute, provided the object allows it. For example, + \code{delattr(\var{x}, '\var{foobar}')} is equivalent to + \code{del \var{x}.\var{foobar}}. +\end{funcdesc} + +\begin{funcdesc}{dict}{\optional{arg}} + Return a new dictionary initialized from an optional positional + argument or from a set of keyword arguments. + If no arguments are given, return a new empty dictionary. + If the positional argument \var{arg} is a mapping object, return a dictionary + mapping the same keys to the same values as does the mapping object. + Otherwise the positional argument must be a sequence, a container that + supports iteration, or an iterator object. The elements of the argument + must each also be of one of those kinds, and each must in turn contain + exactly two objects. The first is used as a key in the new dictionary, + and the second as the key's value. If a given key is seen more than + once, the last value associated with it is retained in the new + dictionary. + + If keyword arguments are given, the keywords themselves with their + associated values are added as items to the dictionary. If a key + is specified both in the positional argument and as a keyword argument, + the value associated with the keyword is retained in the dictionary. + For example, these all return a dictionary equal to + \code{\{"one": 2, "two": 3\}}: + + \begin{itemize} + \item \code{dict(\{'one': 2, 'two': 3\})} + \item \code{dict(\{'one': 2, 'two': 3\}.items())} + \item \code{dict(\{'one': 2, 'two': 3\}.iteritems())} + \item \code{dict(zip(('one', 'two'), (2, 3)))} + \item \code{dict([['two', 3], ['one', 2]])} + \item \code{dict(one=2, two=3)} + \item \code{dict([(['one', 'two'][i-2], i) for i in (2, 3)])} + \end{itemize} + + \versionadded{2.2} + \versionchanged[Support for building a dictionary from keyword + arguments added]{2.3} +\end{funcdesc} + +\begin{funcdesc}{dir}{\optional{object}} + Without arguments, return the list of names in the current local + symbol table. With an argument, attempts to return a list of valid + attributes for that object. This information is gleaned from the + object's \member{__dict__} attribute, if defined, and from the class + or type object. The list is not necessarily complete. + If the object is a module object, the list contains the names of the + module's attributes. + If the object is a type or class object, + the list contains the names of its attributes, + and recursively of the attributes of its bases. + Otherwise, the list contains the object's attributes' names, + the names of its class's attributes, + and recursively of the attributes of its class's base classes. + The resulting list is sorted alphabetically. + For example: + +\begin{verbatim} +>>> import struct +>>> dir() +['__builtins__', '__doc__', '__name__', 'struct'] +>>> dir(struct) +['__doc__', '__name__', 'calcsize', 'error', 'pack', 'unpack'] +\end{verbatim} + + \note{Because \function{dir()} is supplied primarily as a convenience + for use at an interactive prompt, + it tries to supply an interesting set of names more than it tries to + supply a rigorously or consistently defined set of names, + and its detailed behavior may change across releases.} +\end{funcdesc} + +\begin{funcdesc}{divmod}{a, b} + Take two (non complex) numbers as arguments and return a pair of numbers + consisting of their quotient and remainder when using long division. With + mixed operand types, the rules for binary arithmetic operators apply. For + plain and long integers, the result is the same as + \code{(\var{a} // \var{b}, \var{a} \%{} \var{b})}. + For floating point numbers the result is \code{(\var{q}, \var{a} \%{} + \var{b})}, where \var{q} is usually \code{math.floor(\var{a} / + \var{b})} but may be 1 less than that. In any case \code{\var{q} * + \var{b} + \var{a} \%{} \var{b}} is very close to \var{a}, if + \code{\var{a} \%{} \var{b}} is non-zero it has the same sign as + \var{b}, and \code{0 <= abs(\var{a} \%{} \var{b}) < abs(\var{b})}. + + \versionchanged[Using \function{divmod()} with complex numbers is + deprecated]{2.3} +\end{funcdesc} + +\begin{funcdesc}{enumerate}{iterable} + Return an enumerate object. \var{iterable} must be a sequence, an + iterator, or some other object which supports iteration. The + \method{next()} method of the iterator returned by + \function{enumerate()} returns a tuple containing a count (from + zero) and the corresponding value obtained from iterating over + \var{iterable}. \function{enumerate()} is useful for obtaining an + indexed series: \code{(0, seq[0])}, \code{(1, seq[1])}, \code{(2, + seq[2])}, \ldots. + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{eval}{expression\optional{, globals\optional{, locals}}} + The arguments are a string and optional globals and locals. If provided, + \var{globals} must be a dictionary. If provided, \var{locals} can be + any mapping object. \versionchanged[formerly \var{locals} was required + to be a dictionary]{2.4} + + The \var{expression} argument is parsed and evaluated as a Python + expression (technically speaking, a condition list) using the + \var{globals} and \var{locals} dictionaries as global and local name + space. If the \var{globals} dictionary is present and lacks + '__builtins__', the current globals are copied into \var{globals} before + \var{expression} is parsed. This means that \var{expression} + normally has full access to the standard + \refmodule[builtin]{__builtin__} module and restricted environments + are propagated. If the \var{locals} dictionary is omitted it defaults to + the \var{globals} dictionary. If both dictionaries are omitted, the + expression is executed in the environment where \keyword{eval} is + called. The return value is the result of the evaluated expression. + Syntax errors are reported as exceptions. Example: + +\begin{verbatim} +>>> x = 1 +>>> print eval('x+1') +2 +\end{verbatim} + + This function can also be used to execute arbitrary code objects + (such as those created by \function{compile()}). In this case pass + a code object instead of a string. The code object must have been + compiled passing \code{'eval'} as the \var{kind} argument. + + Hints: dynamic execution of statements is supported by the + \keyword{exec} statement. Execution of statements from a file is + supported by the \function{execfile()} function. The + \function{globals()} and \function{locals()} functions returns the + current global and local dictionary, respectively, which may be + useful to pass around for use by \function{eval()} or + \function{execfile()}. +\end{funcdesc} + +\begin{funcdesc}{execfile}{filename\optional{, globals\optional{, locals}}} + This function is similar to the + \keyword{exec} statement, but parses a file instead of a string. It + is different from the \keyword{import} statement in that it does not + use the module administration --- it reads the file unconditionally + and does not create a new module.\footnote{It is used relatively + rarely so does not warrant being made into a statement.} + + The arguments are a file name and two optional dictionaries. The file is + parsed and evaluated as a sequence of Python statements (similarly to a + module) using the \var{globals} and \var{locals} dictionaries as global and + local namespace. If provided, \var{locals} can be any mapping object. + \versionchanged[formerly \var{locals} was required to be a dictionary]{2.4} + If the \var{locals} dictionary is omitted it defaults to the \var{globals} + dictionary. If both dictionaries are omitted, the expression is executed in + the environment where \function{execfile()} is called. The return value is + \code{None}. + + \warning{The default \var{locals} act as described for function + \function{locals()} below: modifications to the default \var{locals} + dictionary should not be attempted. Pass an explicit \var{locals} + dictionary if you need to see effects of the code on \var{locals} after + function \function{execfile()} returns. \function{execfile()} cannot + be used reliably to modify a function's locals.} +\end{funcdesc} + +\begin{funcdesc}{file}{filename\optional{, mode\optional{, bufsize}}} + Constructor function for the \class{file} type, described further + in section~\ref{bltin-file-objects}, ``\ulink{File + Objects}{bltin-file-objects.html}''. The constructor's arguments + are the same as those of the \function{open()} built-in function + described below. + + When opening a file, it's preferable to use \function{open()} instead of + invoking this constructor directly. \class{file} is more suited to + type testing (for example, writing \samp{isinstance(f, file)}). + + \versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{filter}{function, iterable} + Construct a list from those elements of \var{iterable} for which + \var{function} returns true. \var{iterable} may be either a sequence, a + container which supports iteration, or an iterator, If \var{iterable} + is a string or a tuple, the result + also has that type; otherwise it is always a list. If \var{function} is + \code{None}, the identity function is assumed, that is, all elements of + \var{iterable} that are false are removed. + + Note that \code{filter(function, \var{iterable})} is equivalent to + \code{[item for item in \var{iterable} if function(item)]} if function is + not \code{None} and \code{[item for item in \var{iterable} if item]} if + function is \code{None}. +\end{funcdesc} + +\begin{funcdesc}{float}{\optional{x}} + Convert a string or a number to floating point. If the argument is a + string, it must contain a possibly signed decimal or floating point + number, possibly embedded in whitespace. Otherwise, the argument may be a plain + or long integer or a floating point number, and a floating point + number with the same value (within Python's floating point + precision) is returned. If no argument is given, returns \code{0.0}. + + \note{When passing in a string, values for NaN\index{NaN} + and Infinity\index{Infinity} may be returned, depending on the + underlying C library. The specific set of strings accepted which + cause these values to be returned depends entirely on the C library + and is known to vary.} +\end{funcdesc} + +\begin{funcdesc}{frozenset}{\optional{iterable}} + Return a frozenset object whose elements are taken from \var{iterable}. + Frozensets are sets that have no update methods but can be hashed and + used as members of other sets or as dictionary keys. The elements of + a frozenset must be immutable themselves. To represent sets of sets, + the inner sets should also be \class{frozenset} objects. If + \var{iterable} is not specified, returns a new empty set, + \code{frozenset([])}. + \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{getattr}{object, name\optional{, default}} + Return the value of the named attributed of \var{object}. \var{name} + must be a string. If the string is the name of one of the object's + attributes, the result is the value of that attribute. For example, + \code{getattr(x, 'foobar')} is equivalent to \code{x.foobar}. If the + named attribute does not exist, \var{default} is returned if provided, + otherwise \exception{AttributeError} is raised. +\end{funcdesc} + +\begin{funcdesc}{globals}{} + Return a dictionary representing the current global symbol table. + This is always the dictionary of the current module (inside a + function or method, this is the module where it is defined, not the + module from which it is called). +\end{funcdesc} + +\begin{funcdesc}{hasattr}{object, name} + The arguments are an object and a string. The result is \code{True} if the + string is the name of one of the object's attributes, \code{False} if not. + (This is implemented by calling \code{getattr(\var{object}, + \var{name})} and seeing whether it raises an exception or not.) +\end{funcdesc} + +\begin{funcdesc}{hash}{object} + Return the hash value of the object (if it has one). Hash values + are integers. They are used to quickly compare dictionary + keys during a dictionary lookup. Numeric values that compare equal + have the same hash value (even if they are of different types, as is + the case for 1 and 1.0). +\end{funcdesc} + +\begin{funcdesc}{help}{\optional{object}} + Invoke the built-in help system. (This function is intended for + interactive use.) If no argument is given, the interactive help + system starts on the interpreter console. If the argument is a + string, then the string is looked up as the name of a module, + function, class, method, keyword, or documentation topic, and a + help page is printed on the console. If the argument is any other + kind of object, a help page on the object is generated. + \versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{hex}{x} + Convert an integer number (of any size) to a hexadecimal string. + The result is a valid Python expression. + \versionchanged[Formerly only returned an unsigned literal]{2.4} +\end{funcdesc} + +\begin{funcdesc}{id}{object} + Return the ``identity'' of an object. This is an integer (or long + integer) which is guaranteed to be unique and constant for this + object during its lifetime. Two objects with non-overlapping lifetimes + may have the same \function{id()} value. (Implementation + note: this is the address of the object.) +\end{funcdesc} + +\begin{funcdesc}{input}{\optional{prompt}} + Equivalent to \code{eval(raw_input(\var{prompt}))}. + \warning{This function is not safe from user errors! It + expects a valid Python expression as input; if the input is not + syntactically valid, a \exception{SyntaxError} will be raised. + Other exceptions may be raised if there is an error during + evaluation. (On the other hand, sometimes this is exactly what you + need when writing a quick script for expert use.)} + + If the \refmodule{readline} module was loaded, then + \function{input()} will use it to provide elaborate line editing and + history features. + + Consider using the \function{raw_input()} function for general input + from users. +\end{funcdesc} + +\begin{funcdesc}{int}{\optional{x\optional{, radix}}} + Convert a string or number to a plain integer. If the argument is a + string, it must contain a possibly signed decimal number + representable as a Python integer, possibly embedded in whitespace. + The \var{radix} parameter gives the base for the + conversion and may be any integer in the range [2, 36], or zero. If + \var{radix} is zero, the proper radix is guessed based on the + contents of string; the interpretation is the same as for integer + literals. If \var{radix} is specified and \var{x} is not a string, + \exception{TypeError} is raised. + Otherwise, the argument may be a plain or + long integer or a floating point number. Conversion of floating + point numbers to integers truncates (towards zero). + If the argument is outside the integer range a long object will + be returned instead. If no arguments are given, returns \code{0}. +\end{funcdesc} + +\begin{funcdesc}{isinstance}{object, classinfo} + Return true if the \var{object} argument is an instance of the + \var{classinfo} argument, or of a (direct or indirect) subclass + thereof. Also return true if \var{classinfo} is a type object + (new-style class) and \var{object} is an object of that type or of a + (direct or indirect) subclass thereof. If \var{object} is not a + class instance or an object of the given type, the function always + returns false. If \var{classinfo} is neither a class object nor a + type object, it may be a tuple of class or type objects, or may + recursively contain other such tuples (other sequence types are not + accepted). If \var{classinfo} is not a class, type, or tuple of + classes, types, and such tuples, a \exception{TypeError} exception + is raised. + \versionchanged[Support for a tuple of type information was added]{2.2} +\end{funcdesc} + +\begin{funcdesc}{issubclass}{class, classinfo} + Return true if \var{class} is a subclass (direct or indirect) of + \var{classinfo}. A class is considered a subclass of itself. + \var{classinfo} may be a tuple of class objects, in which case every + entry in \var{classinfo} will be checked. In any other case, a + \exception{TypeError} exception is raised. + \versionchanged[Support for a tuple of type information was added]{2.3} +\end{funcdesc} + +\begin{funcdesc}{iter}{o\optional{, sentinel}} + Return an iterator object. The first argument is interpreted very + differently depending on the presence of the second argument. + Without a second argument, \var{o} must be a collection object which + supports the iteration protocol (the \method{__iter__()} method), or + it must support the sequence protocol (the \method{__getitem__()} + method with integer arguments starting at \code{0}). If it does not + support either of those protocols, \exception{TypeError} is raised. + If the second argument, \var{sentinel}, is given, then \var{o} must + be a callable object. The iterator created in this case will call + \var{o} with no arguments for each call to its \method{next()} + method; if the value returned is equal to \var{sentinel}, + \exception{StopIteration} will be raised, otherwise the value will + be returned. + \versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{len}{s} + Return the length (the number of items) of an object. The argument + may be a sequence (string, tuple or list) or a mapping (dictionary). +\end{funcdesc} + +\begin{funcdesc}{list}{\optional{iterable}} + Return a list whose items are the same and in the same order as + \var{iterable}'s items. \var{iterable} may be either a sequence, a + container that supports iteration, or an iterator object. If + \var{iterable} is already a list, a copy is made and returned, + similar to \code{\var{iterable}[:]}. For instance, + \code{list('abc')} returns \code{['a', 'b', 'c']} and \code{list( + (1, 2, 3) )} returns \code{[1, 2, 3]}. If no argument is given, + returns a new empty list, \code{[]}. +\end{funcdesc} + +\begin{funcdesc}{locals}{} + Update and return a dictionary representing the current local symbol table. + \warning{The contents of this dictionary should not be modified; + changes may not affect the values of local variables used by the + interpreter.} +\end{funcdesc} + +\begin{funcdesc}{long}{\optional{x\optional{, radix}}} + Convert a string or number to a long integer. If the argument is a + string, it must contain a possibly signed number of + arbitrary size, possibly embedded in whitespace. The + \var{radix} argument is interpreted in the same way as for + \function{int()}, and may only be given when \var{x} is a string. + Otherwise, the argument may be a plain or + long integer or a floating point number, and a long integer with + the same value is returned. Conversion of floating + point numbers to integers truncates (towards zero). If no arguments + are given, returns \code{0L}. +\end{funcdesc} + +\begin{funcdesc}{map}{function, iterable, ...} + Apply \var{function} to every item of \var{iterable} and return a list + of the results. If additional \var{iterable} arguments are passed, + \var{function} must take that many arguments and is applied to the + items from all iterables in parallel. If one iterable is shorter than another it + is assumed to be extended with \code{None} items. If \var{function} + is \code{None}, the identity function is assumed; if there are + multiple arguments, \function{map()} returns a list consisting + of tuples containing the corresponding items from all iterables (a kind + of transpose operation). The \var{iterable} arguments may be a sequence + or any iterable object; the result is always a list. +\end{funcdesc} + +\begin{funcdesc}{max}{iterable\optional{, args...}\optional{key}} + With a single argument \var{iterable}, return the largest item of a + non-empty iterable (such as a string, tuple or list). With more + than one argument, return the largest of the arguments. + + The optional \var{key} argument specifies a one-argument ordering + function like that used for \method{list.sort()}. The \var{key} + argument, if supplied, must be in keyword form (for example, + \samp{max(a,b,c,key=func)}). + \versionchanged[Added support for the optional \var{key} argument]{2.5} +\end{funcdesc} + +\begin{funcdesc}{min}{iterable\optional{, args...}\optional{key}} + With a single argument \var{iterable}, return the smallest item of a + non-empty iterable (such as a string, tuple or list). With more + than one argument, return the smallest of the arguments. + + The optional \var{key} argument specifies a one-argument ordering + function like that used for \method{list.sort()}. The \var{key} + argument, if supplied, must be in keyword form (for example, + \samp{min(a,b,c,key=func)}). + \versionchanged[Added support for the optional \var{key} argument]{2.5} +\end{funcdesc} + +\begin{funcdesc}{object}{} + Return a new featureless object. \class{object} is a base + for all new style classes. It has the methods that are common + to all instances of new style classes. + \versionadded{2.2} + + \versionchanged[This function does not accept any arguments. + Formerly, it accepted arguments but ignored them]{2.3} +\end{funcdesc} + +\begin{funcdesc}{oct}{x} + Convert an integer number (of any size) to an octal string. The + result is a valid Python expression. + \versionchanged[Formerly only returned an unsigned literal]{2.4} +\end{funcdesc} + +\begin{funcdesc}{open}{filename\optional{, mode\optional{, bufsize}}} + Open a file, returning an object of the \class{file} type described + in section~\ref{bltin-file-objects}, ``\ulink{File + Objects}{bltin-file-objects.html}''. If the file cannot be opened, + \exception{IOError} is raised. When opening a file, it's + preferable to use \function{open()} instead of invoking the + \class{file} constructor directly. + + The first two arguments are the same as for \code{stdio}'s + \cfunction{fopen()}: \var{filename} is the file name to be opened, + and \var{mode} is a string indicating how the file is to be opened. + + The most commonly-used values of \var{mode} are \code{'r'} for + reading, \code{'w'} for writing (truncating the file if it already + exists), and \code{'a'} for appending (which on \emph{some} \UNIX{} + systems means that \emph{all} writes append to the end of the file + regardless of the current seek position). If \var{mode} is omitted, + it defaults to \code{'r'}. When opening a binary file, you should + append \code{'b'} to the \var{mode} value to open the file in binary + mode, which will improve portability. (Appending \code{'b'} is + useful even on systems that don't treat binary and text files + differently, where it serves as documentation.) See below for more + possible values of \var{mode}. + + \index{line-buffered I/O}\index{unbuffered I/O}\index{buffer size, I/O} + \index{I/O control!buffering} + The optional \var{bufsize} argument specifies the + file's desired buffer size: 0 means unbuffered, 1 means line + buffered, any other positive value means use a buffer of + (approximately) that size. A negative \var{bufsize} means to use + the system default, which is usually line buffered for tty + devices and fully buffered for other files. If omitted, the system + default is used.\footnote{ + Specifying a buffer size currently has no effect on systems that + don't have \cfunction{setvbuf()}. The interface to specify the + buffer size is not done using a method that calls + \cfunction{setvbuf()}, because that may dump core when called + after any I/O has been performed, and there's no reliable way to + determine whether this is the case.} + + Modes \code{'r+'}, \code{'w+'} and \code{'a+'} open the file for + updating (note that \code{'w+'} truncates the file). Append + \code{'b'} to the mode to open the file in binary mode, on systems + that differentiate between binary and text files; on systems + that don't have this distinction, adding the \code{'b'} has no effect. + + In addition to the standard \cfunction{fopen()} values \var{mode} + may be \code{'U'} or \code{'rU'}. Python is usually built with universal + newline support; supplying \code{'U'} opens the file as a text file, but + lines may be terminated by any of the following: the \UNIX{} end-of-line + convention \code{'\e n'}, + the Macintosh convention \code{'\e r'}, or the Windows + convention \code{'\e r\e n'}. All of these external representations are seen as + \code{'\e n'} + by the Python program. If Python is built without universal newline support + a \var{mode} with \code{'U'} is the same as normal text mode. Note that + file objects so opened also have an attribute called + \member{newlines} which has a value of \code{None} (if no newlines + have yet been seen), \code{'\e n'}, \code{'\e r'}, \code{'\e r\e n'}, + or a tuple containing all the newline types seen. + + Python enforces that the mode, after stripping \code{'U'}, begins with + \code{'r'}, \code{'w'} or \code{'a'}. + + \versionchanged[Restriction on first letter of mode string + introduced]{2.5} +\end{funcdesc} + +\begin{funcdesc}{ord}{c} + Given a string of length one, return an integer representing the + Unicode code point of the character when the argument is a unicode object, + or the value of the byte when the argument is an 8-bit string. + For example, \code{ord('a')} returns the integer \code{97}, + \code{ord(u'\e u2020')} returns \code{8224}. This is the inverse of + \function{chr()} for 8-bit strings and of \function{unichr()} for unicode + objects. If a unicode argument is given and Python was built with + UCS2 Unicode, then the character's code point must be in the range + [0..65535] inclusive; otherwise the string length is two, and a + \exception{TypeError} will be raised. +\end{funcdesc} + +\begin{funcdesc}{pow}{x, y\optional{, z}} + Return \var{x} to the power \var{y}; if \var{z} is present, return + \var{x} to the power \var{y}, modulo \var{z} (computed more + efficiently than \code{pow(\var{x}, \var{y}) \%\ \var{z}}). + The two-argument form \code{pow(\var{x}, \var{y})} is equivalent to using + the power operator: \code{\var{x}**\var{y}}. + + The arguments must have numeric types. With mixed operand types, the + coercion rules for binary arithmetic operators apply. For int and + long int operands, the result has the same type as the operands + (after coercion) unless the second argument is negative; in that + case, all arguments are converted to float and a float result is + delivered. For example, \code{10**2} returns \code{100}, but + \code{10**-2} returns \code{0.01}. (This last feature was added in + Python 2.2. In Python 2.1 and before, if both arguments were of integer + types and the second argument was negative, an exception was raised.) + If the second argument is negative, the third argument must be omitted. + If \var{z} is present, \var{x} and \var{y} must be of integer types, + and \var{y} must be non-negative. (This restriction was added in + Python 2.2. In Python 2.1 and before, floating 3-argument \code{pow()} + returned platform-dependent results depending on floating-point + rounding accidents.) +\end{funcdesc} + +\begin{funcdesc}{property}{\optional{fget\optional{, fset\optional{, + fdel\optional{, doc}}}}} + Return a property attribute for new-style classes (classes that + derive from \class{object}). + + \var{fget} is a function for getting an attribute value, likewise + \var{fset} is a function for setting, and \var{fdel} a function + for del'ing, an attribute. Typical use is to define a managed attribute x: + +\begin{verbatim} +class C(object): + def __init__(self): self._x = None + def getx(self): return self._x + def setx(self, value): self._x = value + def delx(self): del self._x + x = property(getx, setx, delx, "I'm the 'x' property.") +\end{verbatim} + + If given, \var{doc} will be the docstring of the property attribute. + Otherwise, the property will copy \var{fget}'s docstring (if it + exists). This makes it possible to create read-only properties + easily using \function{property()} as a decorator: + +\begin{verbatim} +class Parrot(object): + def __init__(self): + self._voltage = 100000 + + @property + def voltage(self): + """Get the current voltage.""" + return self._voltage +\end{verbatim} + + turns the \method{voltage()} method into a ``getter'' for a read-only + attribute with the same name. + + \versionadded{2.2} + \versionchanged[Use \var{fget}'s docstring if no \var{doc} given]{2.5} +\end{funcdesc} + +\begin{funcdesc}{range}{\optional{start,} stop\optional{, step}} + This is a versatile function to create lists containing arithmetic + progressions. It is most often used in \keyword{for} loops. The + arguments must be plain integers. If the \var{step} argument is + omitted, it defaults to \code{1}. If the \var{start} argument is + omitted, it defaults to \code{0}. The full form returns a list of + plain integers \code{[\var{start}, \var{start} + \var{step}, + \var{start} + 2 * \var{step}, \ldots]}. If \var{step} is positive, + the last element is the largest \code{\var{start} + \var{i} * + \var{step}} less than \var{stop}; if \var{step} is negative, the last + element is the smallest \code{\var{start} + \var{i} * \var{step}} + greater than \var{stop}. \var{step} must not be zero (or else + \exception{ValueError} is raised). Example: + +\begin{verbatim} +>>> range(10) +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +>>> range(1, 11) +[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +>>> range(0, 30, 5) +[0, 5, 10, 15, 20, 25] +>>> range(0, 10, 3) +[0, 3, 6, 9] +>>> range(0, -10, -1) +[0, -1, -2, -3, -4, -5, -6, -7, -8, -9] +>>> range(0) +[] +>>> range(1, 0) +[] +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{raw_input}{\optional{prompt}} + If the \var{prompt} argument is present, it is written to standard output + without a trailing newline. The function then reads a line from input, + converts it to a string (stripping a trailing newline), and returns that. + When \EOF{} is read, \exception{EOFError} is raised. Example: + +\begin{verbatim} +>>> s = raw_input('--> ') +--> Monty Python's Flying Circus +>>> s +"Monty Python's Flying Circus" +\end{verbatim} + + If the \refmodule{readline} module was loaded, then + \function{raw_input()} will use it to provide elaborate + line editing and history features. +\end{funcdesc} + +\begin{funcdesc}{reduce}{function, iterable\optional{, initializer}} + Apply \var{function} of two arguments cumulatively to the items of + \var{iterable}, from left to right, so as to reduce the iterable to + a single value. For example, \code{reduce(lambda x, y: x+y, [1, 2, + 3, 4, 5])} calculates \code{((((1+2)+3)+4)+5)}. The left argument, + \var{x}, is the accumulated value and the right argument, \var{y}, + is the update value from the \var{iterable}. If the optional + \var{initializer} is present, it is placed before the items of the + iterable in the calculation, and serves as a default when the + iterable is empty. If \var{initializer} is not given and + \var{iterable} contains only one item, the first item is returned. +\end{funcdesc} + +\begin{funcdesc}{reload}{module} + Reload a previously imported \var{module}. The + argument must be a module object, so it must have been successfully + imported before. This is useful if you have edited the module + source file using an external editor and want to try out the new + version without leaving the Python interpreter. The return value is + the module object (the same as the \var{module} argument). + + When \code{reload(module)} is executed: + +\begin{itemize} + + \item Python modules' code is recompiled and the module-level code + reexecuted, defining a new set of objects which are bound to names in + the module's dictionary. The \code{init} function of extension + modules is not called a second time. + + \item As with all other objects in Python the old objects are only + reclaimed after their reference counts drop to zero. + + \item The names in the module namespace are updated to point to + any new or changed objects. + + \item Other references to the old objects (such as names external + to the module) are not rebound to refer to the new objects and + must be updated in each namespace where they occur if that is + desired. + +\end{itemize} + + There are a number of other caveats: + + If a module is syntactically correct but its initialization fails, + the first \keyword{import} statement for it does not bind its name + locally, but does store a (partially initialized) module object in + \code{sys.modules}. To reload the module you must first + \keyword{import} it again (this will bind the name to the partially + initialized module object) before you can \function{reload()} it. + + When a module is reloaded, its dictionary (containing the module's + global variables) is retained. Redefinitions of names will override + the old definitions, so this is generally not a problem. If the new + version of a module does not define a name that was defined by the + old version, the old definition remains. This feature can be used + to the module's advantage if it maintains a global table or cache of + objects --- with a \keyword{try} statement it can test for the + table's presence and skip its initialization if desired: + +\begin{verbatim} +try: + cache +except NameError: + cache = {} +\end{verbatim} + + + It is legal though generally not very useful to reload built-in or + dynamically loaded modules, except for \refmodule{sys}, + \refmodule[main]{__main__} and \refmodule[builtin]{__builtin__}. In + many cases, however, extension modules are not designed to be + initialized more than once, and may fail in arbitrary ways when + reloaded. + + If a module imports objects from another module using \keyword{from} + \ldots{} \keyword{import} \ldots{}, calling \function{reload()} for + the other module does not redefine the objects imported from it --- + one way around this is to re-execute the \keyword{from} statement, + another is to use \keyword{import} and qualified names + (\var{module}.\var{name}) instead. + + If a module instantiates instances of a class, reloading the module + that defines the class does not affect the method definitions of the + instances --- they continue to use the old class definition. The + same is true for derived classes. +\end{funcdesc} + +\begin{funcdesc}{repr}{object} + Return a string containing a printable representation of an object. + This is the same value yielded by conversions (reverse quotes). + It is sometimes useful to be able to access this operation as an + ordinary function. For many types, this function makes an attempt + to return a string that would yield an object with the same value + when passed to \function{eval()}. +\end{funcdesc} + +\begin{funcdesc}{reversed}{seq} + Return a reverse iterator. \var{seq} must be an object which + supports the sequence protocol (the __len__() method and the + \method{__getitem__()} method with integer arguments starting at + \code{0}). + \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{round}{x\optional{, n}} + Return the floating point value \var{x} rounded to \var{n} digits + after the decimal point. If \var{n} is omitted, it defaults to zero. + The result is a floating point number. Values are rounded to the + closest multiple of 10 to the power minus \var{n}; if two multiples + are equally close, rounding is done away from 0 (so. for example, + \code{round(0.5)} is \code{1.0} and \code{round(-0.5)} is \code{-1.0}). +\end{funcdesc} + +\begin{funcdesc}{set}{\optional{iterable}} + Return a set whose elements are taken from \var{iterable}. The elements + must be immutable. To represent sets of sets, the inner sets should + be \class{frozenset} objects. If \var{iterable} is not specified, + returns a new empty set, \code{set([])}. + \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{setattr}{object, name, value} + This is the counterpart of \function{getattr()}. The arguments are an + object, a string and an arbitrary value. The string may name an + existing attribute or a new attribute. The function assigns the + value to the attribute, provided the object allows it. For example, + \code{setattr(\var{x}, '\var{foobar}', 123)} is equivalent to + \code{\var{x}.\var{foobar} = 123}. +\end{funcdesc} + +\begin{funcdesc}{slice}{\optional{start,} stop\optional{, step}} + Return a slice object representing the set of indices specified by + \code{range(\var{start}, \var{stop}, \var{step})}. The \var{start} + and \var{step} arguments default to \code{None}. Slice objects have + read-only data attributes \member{start}, \member{stop} and + \member{step} which merely return the argument values (or their + default). They have no other explicit functionality; however they + are used by Numerical Python\index{Numerical Python} and other third + party extensions. Slice objects are also generated when extended + indexing syntax is used. For example: \samp{a[start:stop:step]} or + \samp{a[start:stop, i]}. +\end{funcdesc} + +\begin{funcdesc}{sorted}{iterable\optional{, cmp\optional{, + key\optional{, reverse}}}} + Return a new sorted list from the items in \var{iterable}. + + The optional arguments \var{cmp}, \var{key}, and \var{reverse} have + the same meaning as those for the \method{list.sort()} method + (described in section~\ref{typesseq-mutable}). + + \var{cmp} specifies a custom comparison function of two arguments + (iterable elements) which should return a negative, zero or positive + number depending on whether the first argument is considered smaller + than, equal to, or larger than the second argument: + \samp{\var{cmp}=\keyword{lambda} \var{x},\var{y}: + \function{cmp}(x.lower(), y.lower())} + + \var{key} specifies a function of one argument that is used to + extract a comparison key from each list element: + \samp{\var{key}=\function{str.lower}} + + \var{reverse} is a boolean value. If set to \code{True}, then the + list elements are sorted as if each comparison were reversed. + + In general, the \var{key} and \var{reverse} conversion processes are + much faster than specifying an equivalent \var{cmp} function. This is + because \var{cmp} is called multiple times for each list element while + \var{key} and \var{reverse} touch each element only once. + + \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{staticmethod}{function} + Return a static method for \var{function}. + + A static method does not receive an implicit first argument. + To declare a static method, use this idiom: + +\begin{verbatim} +class C: + @staticmethod + def f(arg1, arg2, ...): ... +\end{verbatim} + + The \code{@staticmethod} form is a function decorator -- see the description + of function definitions in chapter 7 of the + \citetitle[../ref/function.html]{Python Reference Manual} for details. + + It can be called either on the class (such as \code{C.f()}) or on an + instance (such as \code{C().f()}). The instance is ignored except + for its class. + + Static methods in Python are similar to those found in Java or \Cpp. + For a more advanced concept, see \function{classmethod()} in this + section. + + For more information on static methods, consult the documentation on the + standard type hierarchy in chapter 3 of the + \citetitle[../ref/types.html]{Python Reference Manual} (at the bottom). + \versionadded{2.2} + \versionchanged[Function decorator syntax added]{2.4} +\end{funcdesc} + +\begin{funcdesc}{str}{\optional{object}} + Return a string containing a nicely printable representation of an + object. For strings, this returns the string itself. The + difference with \code{repr(\var{object})} is that + \code{str(\var{object})} does not always attempt to return a string + that is acceptable to \function{eval()}; its goal is to return a + printable string. If no argument is given, returns the empty + string, \code{''}. +\end{funcdesc} + +\begin{funcdesc}{sum}{iterable\optional{, start}} + Sums \var{start} and the items of an \var{iterable} from left to + right and returns the total. \var{start} defaults to \code{0}. + The \var{iterable}'s items are normally numbers, and are not allowed + to be strings. The fast, correct way to concatenate a sequence of + strings is by calling \code{''.join(\var{sequence})}. + Note that \code{sum(range(\var{n}), \var{m})} is equivalent to + \code{reduce(operator.add, range(\var{n}), \var{m})} + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{super}{type\optional{, object-or-type}} + Return the superclass of \var{type}. If the second argument is omitted + the super object returned is unbound. If the second argument is an + object, \code{isinstance(\var{obj}, \var{type})} must be true. If + the second argument is a type, \code{issubclass(\var{type2}, + \var{type})} must be true. + \function{super()} only works for new-style classes. + + A typical use for calling a cooperative superclass method is: +\begin{verbatim} +class C(B): + def meth(self, arg): + super(C, self).meth(arg) +\end{verbatim} + + Note that \function{super} is implemented as part of the binding process for + explicit dotted attribute lookups such as + \samp{super(C, self).__getitem__(name)}. Accordingly, \function{super} is + undefined for implicit lookups using statements or operators such as + \samp{super(C, self)[name]}. +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{tuple}{\optional{iterable}} + Return a tuple whose items are the same and in the same order as + \var{iterable}'s items. \var{iterable} may be a sequence, a + container that supports iteration, or an iterator object. + If \var{iterable} is already a tuple, it + is returned unchanged. For instance, \code{tuple('abc')} returns + \code{('a', 'b', 'c')} and \code{tuple([1, 2, 3])} returns + \code{(1, 2, 3)}. If no argument is given, returns a new empty + tuple, \code{()}. +\end{funcdesc} + +\begin{funcdesc}{type}{object} + Return the type of an \var{object}. The return value is a + type\obindex{type} object. The \function{isinstance()} built-in + function is recommended for testing the type of an object. + + With three arguments, \function{type} functions as a constructor + as detailed below. +\end{funcdesc} + +\begin{funcdesc}{type}{name, bases, dict} + Return a new type object. This is essentially a dynamic form of the + \keyword{class} statement. The \var{name} string is the class name + and becomes the \member{__name__} attribute; the \var{bases} tuple + itemizes the base classes and becomes the \member{__bases__} + attribute; and the \var{dict} dictionary is the namespace containing + definitions for class body and becomes the \member{__dict__} + attribute. For example, the following two statements create + identical \class{type} objects: + +\begin{verbatim} + >>> class X(object): + ... a = 1 + ... + >>> X = type('X', (object,), dict(a=1)) +\end{verbatim} +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{unichr}{i} + Return the Unicode string of one character whose Unicode code is the + integer \var{i}. For example, \code{unichr(97)} returns the string + \code{u'a'}. This is the inverse of \function{ord()} for Unicode + strings. The valid range for the argument depends how Python was + configured -- it may be either UCS2 [0..0xFFFF] or UCS4 [0..0x10FFFF]. + \exception{ValueError} is raised otherwise. + \versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{unicode}{\optional{object\optional{, encoding + \optional{, errors}}}} + Return the Unicode string version of \var{object} using one of the + following modes: + + If \var{encoding} and/or \var{errors} are given, \code{unicode()} + will decode the object which can either be an 8-bit string or a + character buffer using the codec for \var{encoding}. The + \var{encoding} parameter is a string giving the name of an encoding; + if the encoding is not known, \exception{LookupError} is raised. + Error handling is done according to \var{errors}; this specifies the + treatment of characters which are invalid in the input encoding. If + \var{errors} is \code{'strict'} (the default), a + \exception{ValueError} is raised on errors, while a value of + \code{'ignore'} causes errors to be silently ignored, and a value of + \code{'replace'} causes the official Unicode replacement character, + \code{U+FFFD}, to be used to replace input characters which cannot + be decoded. See also the \refmodule{codecs} module. + + If no optional parameters are given, \code{unicode()} will mimic the + behaviour of \code{str()} except that it returns Unicode strings + instead of 8-bit strings. More precisely, if \var{object} is a + Unicode string or subclass it will return that Unicode string without + any additional decoding applied. + + For objects which provide a \method{__unicode__()} method, it will + call this method without arguments to create a Unicode string. For + all other objects, the 8-bit string version or representation is + requested and then converted to a Unicode string using the codec for + the default encoding in \code{'strict'} mode. + + \versionadded{2.0} + \versionchanged[Support for \method{__unicode__()} added]{2.2} +\end{funcdesc} + +\begin{funcdesc}{vars}{\optional{object}} + Without arguments, return a dictionary corresponding to the current + local symbol table. With a module, class or class instance object + as argument (or anything else that has a \member{__dict__} + attribute), returns a dictionary corresponding to the object's + symbol table. The returned dictionary should not be modified: the + effects on the corresponding symbol table are undefined.\footnote{ + In the current implementation, local variable bindings cannot + normally be affected this way, but variables retrieved from + other scopes (such as modules) can be. This may change.} +\end{funcdesc} + +\begin{funcdesc}{xrange}{\optional{start,} stop\optional{, step}} + This function is very similar to \function{range()}, but returns an + ``xrange object'' instead of a list. This is an opaque sequence + type which yields the same values as the corresponding list, without + actually storing them all simultaneously. The advantage of + \function{xrange()} over \function{range()} is minimal (since + \function{xrange()} still has to create the values when asked for + them) except when a very large range is used on a memory-starved + machine or when all of the range's elements are never used (such as + when the loop is usually terminated with \keyword{break}). + + \note{\function{xrange()} is intended to be simple and fast. + Implementations may impose restrictions to achieve this. + The C implementation of Python restricts all arguments to + native C longs ("short" Python integers), and also requires + that the number of elements fit in a native C long.} +\end{funcdesc} + +\begin{funcdesc}{zip}{\optional{iterable, \moreargs}} + This function returns a list of tuples, where the \var{i}-th tuple contains + the \var{i}-th element from each of the argument sequences or iterables. + The returned list is truncated in length to the length of + the shortest argument sequence. When there are multiple arguments + which are all of the same length, \function{zip()} is + similar to \function{map()} with an initial argument of \code{None}. + With a single sequence argument, it returns a list of 1-tuples. + With no arguments, it returns an empty list. + \versionadded{2.0} + + \versionchanged[Formerly, \function{zip()} required at least one argument + and \code{zip()} raised a \exception{TypeError} instead of returning + an empty list]{2.4} +\end{funcdesc} + + +% --------------------------------------------------------------------------- + + +\section{Non-essential Built-in Functions \label{non-essential-built-in-funcs}} + +There are several built-in functions that are no longer essential to learn, +know or use in modern Python programming. They have been kept here to +maintain backwards compatibility with programs written for older versions +of Python. + +Python programmers, trainers, students and bookwriters should feel free to +bypass these functions without concerns about missing something important. + + +\setindexsubitem{(non-essential built-in functions)} + +\begin{funcdesc}{apply}{function, args\optional{, keywords}} + The \var{function} argument must be a callable object (a + user-defined or built-in function or method, or a class object) and + the \var{args} argument must be a sequence. The \var{function} is + called with \var{args} as the argument list; the number of arguments + is the length of the tuple. + If the optional \var{keywords} argument is present, it must be a + dictionary whose keys are strings. It specifies keyword arguments + to be added to the end of the argument list. + Calling \function{apply()} is different from just calling + \code{\var{function}(\var{args})}, since in that case there is always + exactly one argument. The use of \function{apply()} is equivalent + to \code{\var{function}(*\var{args}, **\var{keywords})}. + Use of \function{apply()} is not necessary since the ``extended call + syntax,'' as used in the last example, is completely equivalent. + + \deprecated{2.3}{Use the extended call syntax instead, as described + above.} +\end{funcdesc} + +\begin{funcdesc}{buffer}{object\optional{, offset\optional{, size}}} + The \var{object} argument must be an object that supports the buffer + call interface (such as strings, arrays, and buffers). A new buffer + object will be created which references the \var{object} argument. + The buffer object will be a slice from the beginning of \var{object} + (or from the specified \var{offset}). The slice will extend to the + end of \var{object} (or will have a length given by the \var{size} + argument). +\end{funcdesc} + +\begin{funcdesc}{coerce}{x, y} + Return a tuple consisting of the two numeric arguments converted to + a common type, using the same rules as used by arithmetic + operations. If coercion is not possible, raise \exception{TypeError}. +\end{funcdesc} + +\begin{funcdesc}{intern}{string} + Enter \var{string} in the table of ``interned'' strings and return + the interned string -- which is \var{string} itself or a copy. + Interning strings is useful to gain a little performance on + dictionary lookup -- if the keys in a dictionary are interned, and + the lookup key is interned, the key comparisons (after hashing) can + be done by a pointer compare instead of a string compare. Normally, + the names used in Python programs are automatically interned, and + the dictionaries used to hold module, class or instance attributes + have interned keys. \versionchanged[Interned strings are not + immortal (like they used to be in Python 2.2 and before); + you must keep a reference to the return value of \function{intern()} + around to benefit from it]{2.3} +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libfunctools.tex b/sys/src/cmd/python/Doc/lib/libfunctools.tex new file mode 100644 index 000000000..9404fca36 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfunctools.tex @@ -0,0 +1,132 @@ +\section{\module{functools} --- + Higher order functions and operations on callable objects.} + +\declaremodule{standard}{functools} % standard library, in Python + +\moduleauthor{Peter Harris}{scav@blueyonder.co.uk} +\moduleauthor{Raymond Hettinger}{python@rcn.com} +\moduleauthor{Nick Coghlan}{ncoghlan@gmail.com} +\sectionauthor{Peter Harris}{scav@blueyonder.co.uk} + +\modulesynopsis{Higher-order functions and operations on callable objects.} + +\versionadded{2.5} + +The \module{functools} module is for higher-order functions: functions +that act on or return other functions. In general, any callable object can +be treated as a function for the purposes of this module. + + +The \module{functools} module defines the following function: + +\begin{funcdesc}{partial}{func\optional{,*args}\optional{, **keywords}} +Return a new \class{partial} object which when called will behave like +\var{func} called with the positional arguments \var{args} and keyword +arguments \var{keywords}. If more arguments are supplied to the call, they +are appended to \var{args}. If additional keyword arguments are supplied, +they extend and override \var{keywords}. Roughly equivalent to: + \begin{verbatim} + def partial(func, *args, **keywords): + def newfunc(*fargs, **fkeywords): + newkeywords = keywords.copy() + newkeywords.update(fkeywords) + return func(*(args + fargs), **newkeywords) + newfunc.func = func + newfunc.args = args + newfunc.keywords = keywords + return newfunc + \end{verbatim} + +The \function{partial} is used for partial function application which +``freezes'' some portion of a function's arguments and/or keywords +resulting in a new object with a simplified signature. For example, +\function{partial} can be used to create a callable that behaves like +the \function{int} function where the \var{base} argument defaults to +two: + \begin{verbatim} + >>> basetwo = partial(int, base=2) + >>> basetwo.__doc__ = 'Convert base 2 string to an int.' + >>> basetwo('10010') + 18 + \end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{update_wrapper} +{wrapper, wrapped\optional{, assigned}\optional{, updated}} +Update a \var{wrapper} function to look like the \var{wrapped} function. +The optional arguments are tuples to specify which attributes of the original +function are assigned directly to the matching attributes on the wrapper +function and which attributes of the wrapper function are updated with +the corresponding attributes from the original function. The default +values for these arguments are the module level constants +\var{WRAPPER_ASSIGNMENTS} (which assigns to the wrapper function's +\var{__name__}, \var{__module__} and \var{__doc__}, the documentation string) +and \var{WRAPPER_UPDATES} (which updates the wrapper function's \var{__dict__}, +i.e. the instance dictionary). + +The main intended use for this function is in decorator functions +which wrap the decorated function and return the wrapper. If the +wrapper function is not updated, the metadata of the returned function +will reflect the wrapper definition rather than the original function +definition, which is typically less than helpful. +\end{funcdesc} + +\begin{funcdesc}{wraps} +{wrapped\optional{, assigned}\optional{, updated}} +This is a convenience function for invoking +\code{partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)} +as a function decorator when defining a wrapper function. For example: + \begin{verbatim} + >>> def my_decorator(f): + ... @wraps(f) + ... def wrapper(*args, **kwds): + ... print 'Calling decorated function' + ... return f(*args, **kwds) + ... return wrapper + ... + >>> @my_decorator + ... def example(): + ... """Docstring""" + ... print 'Called example function' + ... + >>> example() + Calling decorated function + Called example function + >>> example.__name__ + 'example' + >>> example.__doc__ + 'Docstring' + \end{verbatim} +Without the use of this decorator factory, the name of the example +function would have been \code{'wrapper'}, and the docstring of the +original \function{example()} would have been lost. +\end{funcdesc} + + +\subsection{\class{partial} Objects \label{partial-objects}} + + +\class{partial} objects are callable objects created by \function{partial()}. +They have three read-only attributes: + +\begin{memberdesc}[callable]{func}{} +A callable object or function. Calls to the \class{partial} object will +be forwarded to \member{func} with new arguments and keywords. +\end{memberdesc} + +\begin{memberdesc}[tuple]{args}{} +The leftmost positional arguments that will be prepended to the +positional arguments provided to a \class{partial} object call. +\end{memberdesc} + +\begin{memberdesc}[dict]{keywords}{} +The keyword arguments that will be supplied when the \class{partial} object +is called. +\end{memberdesc} + +\class{partial} objects are like \class{function} objects in that they are +callable, weak referencable, and can have attributes. There are some +important differences. For instance, the \member{__name__} and +\member{__doc__} attributes are not created automatically. Also, +\class{partial} objects defined in classes behave like static methods and +do not transform into bound methods during instance attribute look-up. diff --git a/sys/src/cmd/python/Doc/lib/libfuture.tex b/sys/src/cmd/python/Doc/lib/libfuture.tex new file mode 100644 index 000000000..f1ba064a3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libfuture.tex @@ -0,0 +1,69 @@ +\section{\module{__future__} --- + Future statement definitions} + +\declaremodule[future]{standard}{__future__} +\modulesynopsis{Future statement definitions} + +\module{__future__} is a real module, and serves three purposes: + +\begin{itemize} + +\item To avoid confusing existing tools that analyze import statements + and expect to find the modules they're importing. + +\item To ensure that future_statements run under releases prior to 2.1 + at least yield runtime exceptions (the import of + \module{__future__} will fail, because there was no module of + that name prior to 2.1). + +\item To document when incompatible changes were introduced, and when they + will be --- or were --- made mandatory. This is a form of executable + documentation, and can be inspected programatically via importing + \module{__future__} and examining its contents. + +\end{itemize} + +Each statement in \file{__future__.py} is of the form: + +\begin{alltt} +FeatureName = "_Feature(" \var{OptionalRelease} "," \var{MandatoryRelease} "," + \var{CompilerFlag} ")" +\end{alltt} + +where, normally, \var{OptionalRelease} is less than +\var{MandatoryRelease}, and both are 5-tuples of the same form as +\code{sys.version_info}: + +\begin{verbatim} + (PY_MAJOR_VERSION, # the 2 in 2.1.0a3; an int + PY_MINOR_VERSION, # the 1; an int + PY_MICRO_VERSION, # the 0; an int + PY_RELEASE_LEVEL, # "alpha", "beta", "candidate" or "final"; string + PY_RELEASE_SERIAL # the 3; an int + ) +\end{verbatim} + +\var{OptionalRelease} records the first release in which the feature +was accepted. + +In the case of a \var{MandatoryRelease} that has not yet occurred, +\var{MandatoryRelease} predicts the release in which the feature will +become part of the language. + +Else \var{MandatoryRelease} records when the feature became part of +the language; in releases at or after that, modules no longer need a +future statement to use the feature in question, but may continue to +use such imports. + +\var{MandatoryRelease} may also be \code{None}, meaning that a planned +feature got dropped. + +Instances of class \class{_Feature} have two corresponding methods, +\method{getOptionalRelease()} and \method{getMandatoryRelease()}. + +\var{CompilerFlag} is the (bitfield) flag that should be passed in the +fourth argument to the builtin function \function{compile()} to enable +the feature in dynamically compiled code. This flag is stored in the +\member{compiler_flag} attribute on \class{_Feature} instances. + +No feature description will ever be deleted from \module{__future__}. diff --git a/sys/src/cmd/python/Doc/lib/libgc.tex b/sys/src/cmd/python/Doc/lib/libgc.tex new file mode 100644 index 000000000..0d3408bf8 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgc.tex @@ -0,0 +1,196 @@ +\section{\module{gc} --- + Garbage Collector interface} + +\declaremodule{extension}{gc} +\modulesynopsis{Interface to the cycle-detecting garbage collector.} +\moduleauthor{Neil Schemenauer}{nas@arctrix.com} +\sectionauthor{Neil Schemenauer}{nas@arctrix.com} + +This module provides an interface to the optional garbage collector. It +provides the ability to disable the collector, tune the collection +frequency, and set debugging options. It also provides access to +unreachable objects that the collector found but cannot free. Since the +collector supplements the reference counting already used in Python, you +can disable the collector if you are sure your program does not create +reference cycles. Automatic collection can be disabled by calling +\code{gc.disable()}. To debug a leaking program call +\code{gc.set_debug(gc.DEBUG_LEAK)}. Notice that this includes +\code{gc.DEBUG_SAVEALL}, causing garbage-collected objects to be +saved in gc.garbage for inspection. + +The \module{gc} module provides the following functions: + +\begin{funcdesc}{enable}{} +Enable automatic garbage collection. +\end{funcdesc} + +\begin{funcdesc}{disable}{} +Disable automatic garbage collection. +\end{funcdesc} + +\begin{funcdesc}{isenabled}{} +Returns true if automatic collection is enabled. +\end{funcdesc} + +\begin{funcdesc}{collect}{\optional{generation}} +With no arguments, run a full collection. The optional argument +\var{generation} may be an integer specifying which generation to collect +(from 0 to 2). A \exception{ValueError} is raised if the generation number +is invalid. +The number of unreachable objects found is returned. + +\versionchanged[The optional \var{generation} argument was added]{2.5} +\end{funcdesc} + +\begin{funcdesc}{set_debug}{flags} +Set the garbage collection debugging flags. +Debugging information will be written to \code{sys.stderr}. See below +for a list of debugging flags which can be combined using bit +operations to control debugging. +\end{funcdesc} + +\begin{funcdesc}{get_debug}{} +Return the debugging flags currently set. +\end{funcdesc} + +\begin{funcdesc}{get_objects}{} +Returns a list of all objects tracked by the collector, excluding the +list returned. +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{set_threshold}{threshold0\optional{, + threshold1\optional{, threshold2}}} +Set the garbage collection thresholds (the collection frequency). +Setting \var{threshold0} to zero disables collection. + +The GC classifies objects into three generations depending on how many +collection sweeps they have survived. New objects are placed in the +youngest generation (generation \code{0}). If an object survives a +collection it is moved into the next older generation. Since +generation \code{2} is the oldest generation, objects in that +generation remain there after a collection. In order to decide when +to run, the collector keeps track of the number object allocations and +deallocations since the last collection. When the number of +allocations minus the number of deallocations exceeds +\var{threshold0}, collection starts. Initially only generation +\code{0} is examined. If generation \code{0} has been examined more +than \var{threshold1} times since generation \code{1} has been +examined, then generation \code{1} is examined as well. Similarly, +\var{threshold2} controls the number of collections of generation +\code{1} before collecting generation \code{2}. +\end{funcdesc} + +\begin{funcdesc}{get_count}{} +Return the current collection counts as a tuple of +\code{(\var{count0}, \var{count1}, \var{count2})}. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{get_threshold}{} +Return the current collection thresholds as a tuple of +\code{(\var{threshold0}, \var{threshold1}, \var{threshold2})}. +\end{funcdesc} + +\begin{funcdesc}{get_referrers}{*objs} +Return the list of objects that directly refer to any of objs. This +function will only locate those containers which support garbage +collection; extension types which do refer to other objects but do not +support garbage collection will not be found. + +Note that objects which have already been dereferenced, but which live +in cycles and have not yet been collected by the garbage collector can +be listed among the resulting referrers. To get only currently live +objects, call \function{collect()} before calling +\function{get_referrers()}. + +Care must be taken when using objects returned by +\function{get_referrers()} because some of them could still be under +construction and hence in a temporarily invalid state. Avoid using +\function{get_referrers()} for any purpose other than debugging. + +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{get_referents}{*objs} +Return a list of objects directly referred to by any of the arguments. +The referents returned are those objects visited by the arguments' +C-level \member{tp_traverse} methods (if any), and may not be all +objects actually directly reachable. \member{tp_traverse} methods +are supported only by objects that support garbage collection, and are +only required to visit objects that may be involved in a cycle. So, +for example, if an integer is directly reachable from an argument, that +integer object may or may not appear in the result list. + +\versionadded{2.3} +\end{funcdesc} + +The following variable is provided for read-only access (you can +mutate its value but should not rebind it): + +\begin{datadesc}{garbage} +A list of objects which the collector found to be unreachable +but could not be freed (uncollectable objects). By default, this list +contains only objects with \method{__del__()} methods.\footnote{Prior to + Python 2.2, the list contained all instance objects in unreachable + cycles, not only those with \method{__del__()} methods.} +Objects that have +\method{__del__()} methods and are part of a reference cycle cause +the entire reference cycle to be uncollectable, including objects +not necessarily in the cycle but reachable only from it. Python doesn't +collect such cycles automatically because, in general, it isn't possible +for Python to guess a safe order in which to run the \method{__del__()} +methods. If you know a safe order, you can force the issue by examining +the \var{garbage} list, and explicitly breaking cycles due to your +objects within the list. Note that these objects are kept alive even +so by virtue of being in the \var{garbage} list, so they should be +removed from \var{garbage} too. For example, after breaking cycles, do +\code{del gc.garbage[:]} to empty the list. It's generally better +to avoid the issue by not creating cycles containing objects with +\method{__del__()} methods, and \var{garbage} can be examined in that +case to verify that no such cycles are being created. + +If \constant{DEBUG_SAVEALL} is set, then all unreachable objects will +be added to this list rather than freed. +\end{datadesc} + + +The following constants are provided for use with +\function{set_debug()}: + +\begin{datadesc}{DEBUG_STATS} +Print statistics during collection. This information can +be useful when tuning the collection frequency. +\end{datadesc} + +\begin{datadesc}{DEBUG_COLLECTABLE} +Print information on collectable objects found. +\end{datadesc} + +\begin{datadesc}{DEBUG_UNCOLLECTABLE} +Print information of uncollectable objects found (objects which are +not reachable but cannot be freed by the collector). These objects +will be added to the \code{garbage} list. +\end{datadesc} + +\begin{datadesc}{DEBUG_INSTANCES} +When \constant{DEBUG_COLLECTABLE} or \constant{DEBUG_UNCOLLECTABLE} is +set, print information about instance objects found. +\end{datadesc} + +\begin{datadesc}{DEBUG_OBJECTS} +When \constant{DEBUG_COLLECTABLE} or \constant{DEBUG_UNCOLLECTABLE} is +set, print information about objects other than instance objects found. +\end{datadesc} + +\begin{datadesc}{DEBUG_SAVEALL} +When set, all unreachable objects found will be appended to +\var{garbage} rather than being freed. This can be useful for debugging +a leaking program. +\end{datadesc} + +\begin{datadesc}{DEBUG_LEAK} +The debugging flags necessary for the collector to print +information about a leaking program (equal to \code{DEBUG_COLLECTABLE | +DEBUG_UNCOLLECTABLE | DEBUG_INSTANCES | DEBUG_OBJECTS | DEBUG_SAVEALL}). +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/libgdbm.tex b/sys/src/cmd/python/Doc/lib/libgdbm.tex new file mode 100644 index 000000000..0c36677fd --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgdbm.tex @@ -0,0 +1,100 @@ +\section{\module{gdbm} --- + GNU's reinterpretation of dbm} + +\declaremodule{builtin}{gdbm} + \platform{Unix} +\modulesynopsis{GNU's reinterpretation of dbm.} + + +This module is quite similar to the \refmodule{dbm}\refbimodindex{dbm} +module, but uses \code{gdbm} instead to provide some additional +functionality. Please note that the file formats created by +\code{gdbm} and \code{dbm} are incompatible. + +The \module{gdbm} module provides an interface to the GNU DBM +library. \code{gdbm} objects behave like mappings +(dictionaries), except that keys and values are always strings. +Printing a \code{gdbm} object doesn't print the keys and values, and +the \method{items()} and \method{values()} methods are not supported. + +The module defines the following constant and functions: + +\begin{excdesc}{error} +Raised on \code{gdbm}-specific errors, such as I/O errors. +\exception{KeyError} is raised for general mapping errors like +specifying an incorrect key. +\end{excdesc} + +\begin{funcdesc}{open}{filename, \optional{flag, \optional{mode}}} +Open a \code{gdbm} database and return a \code{gdbm} object. The +\var{filename} argument is the name of the database file. + +The optional \var{flag} argument can be +\code{'r'} (to open an existing database for reading only --- default), +\code{'w'} (to open an existing database for reading and writing), +\code{'c'} (which creates the database if it doesn't exist), or +\code{'n'} (which always creates a new empty database). + +The following additional characters may be appended to the flag to +control how the database is opened: + +\begin{itemize} +\item \code{'f'} --- Open the database in fast mode. Writes to the database + will not be synchronized. +\item \code{'s'} --- Synchronized mode. This will cause changes to the database + will be immediately written to the file. +\item \code{'u'} --- Do not lock database. +\end{itemize} + +Not all flags are valid for all versions of \code{gdbm}. The +module constant \code{open_flags} is a string of supported flag +characters. The exception \exception{error} is raised if an invalid +flag is specified. + +The optional \var{mode} argument is the \UNIX{} mode of the file, used +only when the database has to be created. It defaults to octal +\code{0666}. +\end{funcdesc} + +In addition to the dictionary-like methods, \code{gdbm} objects have the +following methods: + +\begin{funcdesc}{firstkey}{} +It's possible to loop over every key in the database using this method +and the \method{nextkey()} method. The traversal is ordered by +\code{gdbm}'s internal hash values, and won't be sorted by the key +values. This method returns the starting key. +\end{funcdesc} + +\begin{funcdesc}{nextkey}{key} +Returns the key that follows \var{key} in the traversal. The +following code prints every key in the database \code{db}, without +having to create a list in memory that contains them all: + +\begin{verbatim} +k = db.firstkey() +while k != None: + print k + k = db.nextkey(k) +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{reorganize}{} +If you have carried out a lot of deletions and would like to shrink +the space used by the \code{gdbm} file, this routine will reorganize +the database. \code{gdbm} will not shorten the length of a database +file except by using this reorganization; otherwise, deleted file +space will be kept and reused as new (key, value) pairs are added. +\end{funcdesc} + +\begin{funcdesc}{sync}{} +When the database has been opened in fast mode, this method forces any +unwritten data to be written to the disk. +\end{funcdesc} + + +\begin{seealso} + \seemodule{anydbm}{Generic interface to \code{dbm}-style databases.} + \seemodule{whichdb}{Utility module used to determine the type of an + existing database.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libgetopt.tex b/sys/src/cmd/python/Doc/lib/libgetopt.tex new file mode 100644 index 000000000..b38fcd8df --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgetopt.tex @@ -0,0 +1,154 @@ +\section{\module{getopt} --- + Parser for command line options} + +\declaremodule{standard}{getopt} +\modulesynopsis{Portable parser for command line options; support both + short and long option names.} + + +This module helps scripts to parse the command line arguments in +\code{sys.argv}. +It supports the same conventions as the \UNIX{} \cfunction{getopt()} +function (including the special meanings of arguments of the form +`\code{-}' and `\code{-}\code{-}'). +% That's to fool latex2html into leaving the two hyphens alone! +Long options similar to those supported by +GNU software may be used as well via an optional third argument. +This module provides a single function and an exception: + +\begin{funcdesc}{getopt}{args, options\optional{, long_options}} +Parses command line options and parameter list. \var{args} is the +argument list to be parsed, without the leading reference to the +running program. Typically, this means \samp{sys.argv[1:]}. +\var{options} is the string of option letters that the script wants to +recognize, with options that require an argument followed by a colon +(\character{:}; i.e., the same format that \UNIX{} +\cfunction{getopt()} uses). + +\note{Unlike GNU \cfunction{getopt()}, after a non-option +argument, all further arguments are considered also non-options. +This is similar to the way non-GNU \UNIX{} systems work.} + +\var{long_options}, if specified, must be a list of strings with the +names of the long options which should be supported. The leading +\code{'-}\code{-'} characters should not be included in the option +name. Long options which require an argument should be followed by an +equal sign (\character{=}). To accept only long options, +\var{options} should be an empty string. Long options on the command +line can be recognized so long as they provide a prefix of the option +name that matches exactly one of the accepted options. For example, +if \var{long_options} is \code{['foo', 'frob']}, the option +\longprogramopt{fo} will match as \longprogramopt{foo}, but +\longprogramopt{f} will not match uniquely, so \exception{GetoptError} +will be raised. + +The return value consists of two elements: the first is a list of +\code{(\var{option}, \var{value})} pairs; the second is the list of +program arguments left after the option list was stripped (this is a +trailing slice of \var{args}). Each option-and-value pair returned +has the option as its first element, prefixed with a hyphen for short +options (e.g., \code{'-x'}) or two hyphens for long options (e.g., +\code{'-}\code{-long-option'}), and the option argument as its second +element, or an empty string if the option has no argument. The +options occur in the list in the same order in which they were found, +thus allowing multiple occurrences. Long and short options may be +mixed. +\end{funcdesc} + +\begin{funcdesc}{gnu_getopt}{args, options\optional{, long_options}} +This function works like \function{getopt()}, except that GNU style +scanning mode is used by default. This means that option and +non-option arguments may be intermixed. The \function{getopt()} +function stops processing options as soon as a non-option argument is +encountered. + +If the first character of the option string is `+', or if the +environment variable POSIXLY_CORRECT is set, then option processing +stops as soon as a non-option argument is encountered. + +\versionadded{2.3} +\end{funcdesc} + +\begin{excdesc}{GetoptError} +This is raised when an unrecognized option is found in the argument +list or when an option requiring an argument is given none. +The argument to the exception is a string indicating the cause of the +error. For long options, an argument given to an option which does +not require one will also cause this exception to be raised. The +attributes \member{msg} and \member{opt} give the error message and +related option; if there is no specific option to which the exception +relates, \member{opt} is an empty string. + +\versionchanged[Introduced \exception{GetoptError} as a synonym for + \exception{error}]{1.6} +\end{excdesc} + +\begin{excdesc}{error} +Alias for \exception{GetoptError}; for backward compatibility. +\end{excdesc} + + +An example using only \UNIX{} style options: + +\begin{verbatim} +>>> import getopt +>>> args = '-a -b -cfoo -d bar a1 a2'.split() +>>> args +['-a', '-b', '-cfoo', '-d', 'bar', 'a1', 'a2'] +>>> optlist, args = getopt.getopt(args, 'abc:d:') +>>> optlist +[('-a', ''), ('-b', ''), ('-c', 'foo'), ('-d', 'bar')] +>>> args +['a1', 'a2'] +\end{verbatim} + +Using long option names is equally easy: + +\begin{verbatim} +>>> s = '--condition=foo --testing --output-file abc.def -x a1 a2' +>>> args = s.split() +>>> args +['--condition=foo', '--testing', '--output-file', 'abc.def', '-x', 'a1', 'a2'] +>>> optlist, args = getopt.getopt(args, 'x', [ +... 'condition=', 'output-file=', 'testing']) +>>> optlist +[('--condition', 'foo'), ('--testing', ''), ('--output-file', 'abc.def'), ('-x', + '')] +>>> args +['a1', 'a2'] +\end{verbatim} + +In a script, typical usage is something like this: + +\begin{verbatim} +import getopt, sys + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="]) + except getopt.GetoptError, err: + # print help information and exit: + print str(err) # will print something like "option -a not recognized" + usage() + sys.exit(2) + output = None + verbose = False + for o, a in opts: + if o == "-v": + verbose = True + elif o in ("-h", "--help"): + usage() + sys.exit() + elif o in ("-o", "--output"): + output = a + else: + assert False, "unhandled option" + # ... + +if __name__ == "__main__": + main() +\end{verbatim} + +\begin{seealso} + \seemodule{optparse}{More object-oriented command line option parsing.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libgetpass.tex b/sys/src/cmd/python/Doc/lib/libgetpass.tex new file mode 100644 index 000000000..a7424390d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgetpass.tex @@ -0,0 +1,36 @@ +\section{\module{getpass} + --- Portable password input} + +\declaremodule{standard}{getpass} +\modulesynopsis{Portable reading of passwords and retrieval of the userid.} +\moduleauthor{Piers Lauder}{piers@cs.su.oz.au} +% Windows (& Mac?) support by Guido van Rossum. +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + + +The \module{getpass} module provides two functions: + + +\begin{funcdesc}{getpass}{\optional{prompt\optional{, stream}}} + Prompt the user for a password without echoing. The user is + prompted using the string \var{prompt}, which defaults to + \code{'Password: '}. On \UNIX, the prompt is written to the + file-like object \var{stream}, which defaults to + \code{sys.stdout} (this argument is ignored on Windows). + + Availability: Macintosh, \UNIX, Windows. + \versionchanged[The \var{stream} parameter was added]{2.5} +\end{funcdesc} + + +\begin{funcdesc}{getuser}{} + Return the ``login name'' of the user. + Availability: \UNIX, Windows. + + This function checks the environment variables \envvar{LOGNAME}, + \envvar{USER}, \envvar{LNAME} and \envvar{USERNAME}, in order, and + returns the value of the first one which is set to a non-empty + string. If none are set, the login name from the password database + is returned on systems which support the \refmodule{pwd} module, + otherwise, an exception is raised. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libgettext.tex b/sys/src/cmd/python/Doc/lib/libgettext.tex new file mode 100644 index 000000000..6aee255ca --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgettext.tex @@ -0,0 +1,773 @@ +\section{\module{gettext} --- + Multilingual internationalization services} + +\declaremodule{standard}{gettext} +\modulesynopsis{Multilingual internationalization services.} +\moduleauthor{Barry A. Warsaw}{barry@zope.com} +\sectionauthor{Barry A. Warsaw}{barry@zope.com} + + +The \module{gettext} module provides internationalization (I18N) and +localization (L10N) services for your Python modules and applications. +It supports both the GNU \code{gettext} message catalog API and a +higher level, class-based API that may be more appropriate for Python +files. The interface described below allows you to write your +module and application messages in one natural language, and provide a +catalog of translated messages for running under different natural +languages. + +Some hints on localizing your Python modules and applications are also +given. + +\subsection{GNU \program{gettext} API} + +The \module{gettext} module defines the following API, which is very +similar to the GNU \program{gettext} API. If you use this API you +will affect the translation of your entire application globally. Often +this is what you want if your application is monolingual, with the choice +of language dependent on the locale of your user. If you are +localizing a Python module, or if your application needs to switch +languages on the fly, you probably want to use the class-based API +instead. + +\begin{funcdesc}{bindtextdomain}{domain\optional{, localedir}} +Bind the \var{domain} to the locale directory +\var{localedir}. More concretely, \module{gettext} will look for +binary \file{.mo} files for the given domain using the path (on \UNIX): +\file{\var{localedir}/\var{language}/LC_MESSAGES/\var{domain}.mo}, +where \var{languages} is searched for in the environment variables +\envvar{LANGUAGE}, \envvar{LC_ALL}, \envvar{LC_MESSAGES}, and +\envvar{LANG} respectively. + +If \var{localedir} is omitted or \code{None}, then the current binding +for \var{domain} is returned.\footnote{ + The default locale directory is system dependent; for example, + on RedHat Linux it is \file{/usr/share/locale}, but on Solaris + it is \file{/usr/lib/locale}. The \module{gettext} module + does not try to support these system dependent defaults; + instead its default is \file{\code{sys.prefix}/share/locale}. + For this reason, it is always best to call + \function{bindtextdomain()} with an explicit absolute path at + the start of your application.} +\end{funcdesc} + +\begin{funcdesc}{bind_textdomain_codeset}{domain\optional{, codeset}} +Bind the \var{domain} to \var{codeset}, changing the encoding of +strings returned by the \function{gettext()} family of functions. +If \var{codeset} is omitted, then the current binding is returned. + +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{textdomain}{\optional{domain}} +Change or query the current global domain. If \var{domain} is +\code{None}, then the current global domain is returned, otherwise the +global domain is set to \var{domain}, which is returned. +\end{funcdesc} + +\begin{funcdesc}{gettext}{message} +Return the localized translation of \var{message}, based on the +current global domain, language, and locale directory. This function +is usually aliased as \function{_} in the local namespace (see +examples below). +\end{funcdesc} + +\begin{funcdesc}{lgettext}{message} +Equivalent to \function{gettext()}, but the translation is returned +in the preferred system encoding, if no other encoding was explicitly +set with \function{bind_textdomain_codeset()}. + +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{dgettext}{domain, message} +Like \function{gettext()}, but look the message up in the specified +\var{domain}. +\end{funcdesc} + +\begin{funcdesc}{ldgettext}{domain, message} +Equivalent to \function{dgettext()}, but the translation is returned +in the preferred system encoding, if no other encoding was explicitly +set with \function{bind_textdomain_codeset()}. + +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{ngettext}{singular, plural, n} + +Like \function{gettext()}, but consider plural forms. If a translation +is found, apply the plural formula to \var{n}, and return the +resulting message (some languages have more than two plural forms). +If no translation is found, return \var{singular} if \var{n} is 1; +return \var{plural} otherwise. + +The Plural formula is taken from the catalog header. It is a C or +Python expression that has a free variable \var{n}; the expression evaluates +to the index of the plural in the catalog. See the GNU gettext +documentation for the precise syntax to be used in \file{.po} files and the +formulas for a variety of languages. + +\versionadded{2.3} + +\end{funcdesc} + +\begin{funcdesc}{lngettext}{singular, plural, n} +Equivalent to \function{ngettext()}, but the translation is returned +in the preferred system encoding, if no other encoding was explicitly +set with \function{bind_textdomain_codeset()}. + +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{dngettext}{domain, singular, plural, n} +Like \function{ngettext()}, but look the message up in the specified +\var{domain}. + +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{ldngettext}{domain, singular, plural, n} +Equivalent to \function{dngettext()}, but the translation is returned +in the preferred system encoding, if no other encoding was explicitly +set with \function{bind_textdomain_codeset()}. + +\versionadded{2.4} +\end{funcdesc} + + + +Note that GNU \program{gettext} also defines a \function{dcgettext()} +method, but this was deemed not useful and so it is currently +unimplemented. + +Here's an example of typical usage for this API: + +\begin{verbatim} +import gettext +gettext.bindtextdomain('myapplication', '/path/to/my/language/directory') +gettext.textdomain('myapplication') +_ = gettext.gettext +# ... +print _('This is a translatable string.') +\end{verbatim} + +\subsection{Class-based API} + +The class-based API of the \module{gettext} module gives you more +flexibility and greater convenience than the GNU \program{gettext} +API. It is the recommended way of localizing your Python applications and +modules. \module{gettext} defines a ``translations'' class which +implements the parsing of GNU \file{.mo} format files, and has methods +for returning either standard 8-bit strings or Unicode strings. +Instances of this ``translations'' class can also install themselves +in the built-in namespace as the function \function{_()}. + +\begin{funcdesc}{find}{domain\optional{, localedir\optional{, + languages\optional{, all}}}} +This function implements the standard \file{.mo} file search +algorithm. It takes a \var{domain}, identical to what +\function{textdomain()} takes. Optional \var{localedir} is as in +\function{bindtextdomain()} Optional \var{languages} is a list of +strings, where each string is a language code. + +If \var{localedir} is not given, then the default system locale +directory is used.\footnote{See the footnote for +\function{bindtextdomain()} above.} If \var{languages} is not given, +then the following environment variables are searched: \envvar{LANGUAGE}, +\envvar{LC_ALL}, \envvar{LC_MESSAGES}, and \envvar{LANG}. The first one +returning a non-empty value is used for the \var{languages} variable. +The environment variables should contain a colon separated list of +languages, which will be split on the colon to produce the expected +list of language code strings. + +\function{find()} then expands and normalizes the languages, and then +iterates through them, searching for an existing file built of these +components: + +\file{\var{localedir}/\var{language}/LC_MESSAGES/\var{domain}.mo} + +The first such file name that exists is returned by \function{find()}. +If no such file is found, then \code{None} is returned. If \var{all} +is given, it returns a list of all file names, in the order in which +they appear in the languages list or the environment variables. +\end{funcdesc} + +\begin{funcdesc}{translation}{domain\optional{, localedir\optional{, + languages\optional{, class_\optional{, + fallback\optional{, codeset}}}}}} +Return a \class{Translations} instance based on the \var{domain}, +\var{localedir}, and \var{languages}, which are first passed to +\function{find()} to get a list of the +associated \file{.mo} file paths. Instances with +identical \file{.mo} file names are cached. The actual class instantiated +is either \var{class_} if provided, otherwise +\class{GNUTranslations}. The class's constructor must take a single +file object argument. If provided, \var{codeset} will change the +charset used to encode translated strings. + +If multiple files are found, later files are used as fallbacks for +earlier ones. To allow setting the fallback, \function{copy.copy} +is used to clone each translation object from the cache; the actual +instance data is still shared with the cache. + +If no \file{.mo} file is found, this function raises +\exception{IOError} if \var{fallback} is false (which is the default), +and returns a \class{NullTranslations} instance if \var{fallback} is +true. + +\versionchanged[Added the \var{codeset} parameter]{2.4} +\end{funcdesc} + +\begin{funcdesc}{install}{domain\optional{, localedir\optional{, unicode + \optional{, codeset\optional{, names}}}}} +This installs the function \function{_} in Python's builtin namespace, +based on \var{domain}, \var{localedir}, and \var{codeset} which are +passed to the function \function{translation()}. The \var{unicode} +flag is passed to the resulting translation object's \method{install} +method. + +For the \var{names} parameter, please see the description of the +translation object's \method{install} method. + +As seen below, you usually mark the strings in your application that are +candidates for translation, by wrapping them in a call to the +\function{_()} function, like this: + +\begin{verbatim} +print _('This string will be translated.') +\end{verbatim} + +For convenience, you want the \function{_()} function to be installed in +Python's builtin namespace, so it is easily accessible in all modules +of your application. + +\versionchanged[Added the \var{codeset} parameter]{2.4} +\versionchanged[Added the \var{names} parameter]{2.5} +\end{funcdesc} + +\subsubsection{The \class{NullTranslations} class} +Translation classes are what actually implement the translation of +original source file message strings to translated message strings. +The base class used by all translation classes is +\class{NullTranslations}; this provides the basic interface you can use +to write your own specialized translation classes. Here are the +methods of \class{NullTranslations}: + +\begin{methoddesc}[NullTranslations]{__init__}{\optional{fp}} +Takes an optional file object \var{fp}, which is ignored by the base +class. Initializes ``protected'' instance variables \var{_info} and +\var{_charset} which are set by derived classes, as well as \var{_fallback}, +which is set through \method{add_fallback}. It then calls +\code{self._parse(fp)} if \var{fp} is not \code{None}. +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{_parse}{fp} +No-op'd in the base class, this method takes file object \var{fp}, and +reads the data from the file, initializing its message catalog. If +you have an unsupported message catalog file format, you should +override this method to parse your format. +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{add_fallback}{fallback} +Add \var{fallback} as the fallback object for the current translation +object. A translation object should consult the fallback if it cannot +provide a translation for a given message. +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{gettext}{message} +If a fallback has been set, forward \method{gettext()} to the fallback. +Otherwise, return the translated message. Overridden in derived classes. +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{lgettext}{message} +If a fallback has been set, forward \method{lgettext()} to the fallback. +Otherwise, return the translated message. Overridden in derived classes. + +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{ugettext}{message} +If a fallback has been set, forward \method{ugettext()} to the fallback. +Otherwise, return the translated message as a Unicode string. +Overridden in derived classes. +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{ngettext}{singular, plural, n} +If a fallback has been set, forward \method{ngettext()} to the fallback. +Otherwise, return the translated message. Overridden in derived classes. + +\versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{lngettext}{singular, plural, n} +If a fallback has been set, forward \method{ngettext()} to the fallback. +Otherwise, return the translated message. Overridden in derived classes. + +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{ungettext}{singular, plural, n} +If a fallback has been set, forward \method{ungettext()} to the fallback. +Otherwise, return the translated message as a Unicode string. +Overridden in derived classes. + +\versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{info}{} +Return the ``protected'' \member{_info} variable. +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{charset}{} +Return the ``protected'' \member{_charset} variable. +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{output_charset}{} +Return the ``protected'' \member{_output_charset} variable, which +defines the encoding used to return translated messages. + +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{set_output_charset}{charset} +Change the ``protected'' \member{_output_charset} variable, which +defines the encoding used to return translated messages. + +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[NullTranslations]{install}{\optional{unicode + \optional{, names}}} +If the \var{unicode} flag is false, this method installs +\method{self.gettext()} into the built-in namespace, binding it to +\samp{_}. If \var{unicode} is true, it binds \method{self.ugettext()} +instead. By default, \var{unicode} is false. + +If the \var{names} parameter is given, it must be a sequence containing +the names of functions you want to install in the builtin namespace in +addition to \function{_()}. Supported names are \code{'gettext'} (bound +to \method{self.gettext()} or \method{self.ugettext()} according to the +\var{unicode} flag), \code{'ngettext'} (bound to \method{self.ngettext()} +or \method{self.ungettext()} according to the \var{unicode} flag), +\code{'lgettext'} and \code{'lngettext'}. + +Note that this is only one way, albeit the most convenient way, to +make the \function{_} function available to your application. Because it +affects the entire application globally, and specifically the built-in +namespace, localized modules should never install \function{_}. +Instead, they should use this code to make \function{_} available to +their module: + +\begin{verbatim} +import gettext +t = gettext.translation('mymodule', ...) +_ = t.gettext +\end{verbatim} + +This puts \function{_} only in the module's global namespace and so +only affects calls within this module. + +\versionchanged[Added the \var{names} parameter]{2.5} +\end{methoddesc} + +\subsubsection{The \class{GNUTranslations} class} + +The \module{gettext} module provides one additional class derived from +\class{NullTranslations}: \class{GNUTranslations}. This class +overrides \method{_parse()} to enable reading GNU \program{gettext} +format \file{.mo} files in both big-endian and little-endian format. +It also coerces both message ids and message strings to Unicode. + +\class{GNUTranslations} parses optional meta-data out of the +translation catalog. It is convention with GNU \program{gettext} to +include meta-data as the translation for the empty string. This +meta-data is in \rfc{822}-style \code{key: value} pairs, and should +contain the \code{Project-Id-Version} key. If the key +\code{Content-Type} is found, then the \code{charset} property is used +to initialize the ``protected'' \member{_charset} instance variable, +defaulting to \code{None} if not found. If the charset encoding is +specified, then all message ids and message strings read from the +catalog are converted to Unicode using this encoding. The +\method{ugettext()} method always returns a Unicode, while the +\method{gettext()} returns an encoded 8-bit string. For the message +id arguments of both methods, either Unicode strings or 8-bit strings +containing only US-ASCII characters are acceptable. Note that the +Unicode version of the methods (i.e. \method{ugettext()} and +\method{ungettext()}) are the recommended interface to use for +internationalized Python programs. + +The entire set of key/value pairs are placed into a dictionary and set +as the ``protected'' \member{_info} instance variable. + +If the \file{.mo} file's magic number is invalid, or if other problems +occur while reading the file, instantiating a \class{GNUTranslations} class +can raise \exception{IOError}. + +The following methods are overridden from the base class implementation: + +\begin{methoddesc}[GNUTranslations]{gettext}{message} +Look up the \var{message} id in the catalog and return the +corresponding message string, as an 8-bit string encoded with the +catalog's charset encoding, if known. If there is no entry in the +catalog for the \var{message} id, and a fallback has been set, the +look up is forwarded to the fallback's \method{gettext()} method. +Otherwise, the \var{message} id is returned. +\end{methoddesc} + +\begin{methoddesc}[GNUTranslations]{lgettext}{message} +Equivalent to \method{gettext()}, but the translation is returned +in the preferred system encoding, if no other encoding was explicitly +set with \method{set_output_charset()}. + +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[GNUTranslations]{ugettext}{message} +Look up the \var{message} id in the catalog and return the +corresponding message string, as a Unicode string. If there is no +entry in the catalog for the \var{message} id, and a fallback has been +set, the look up is forwarded to the fallback's \method{ugettext()} +method. Otherwise, the \var{message} id is returned. +\end{methoddesc} + +\begin{methoddesc}[GNUTranslations]{ngettext}{singular, plural, n} +Do a plural-forms lookup of a message id. \var{singular} is used as +the message id for purposes of lookup in the catalog, while \var{n} is +used to determine which plural form to use. The returned message +string is an 8-bit string encoded with the catalog's charset encoding, +if known. + +If the message id is not found in the catalog, and a fallback is +specified, the request is forwarded to the fallback's +\method{ngettext()} method. Otherwise, when \var{n} is 1 \var{singular} is +returned, and \var{plural} is returned in all other cases. + +\versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}[GNUTranslations]{lngettext}{singular, plural, n} +Equivalent to \method{gettext()}, but the translation is returned +in the preferred system encoding, if no other encoding was explicitly +set with \method{set_output_charset()}. + +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[GNUTranslations]{ungettext}{singular, plural, n} +Do a plural-forms lookup of a message id. \var{singular} is used as +the message id for purposes of lookup in the catalog, while \var{n} is +used to determine which plural form to use. The returned message +string is a Unicode string. + +If the message id is not found in the catalog, and a fallback is +specified, the request is forwarded to the fallback's +\method{ungettext()} method. Otherwise, when \var{n} is 1 \var{singular} is +returned, and \var{plural} is returned in all other cases. + +Here is an example: + +\begin{verbatim} +n = len(os.listdir('.')) +cat = GNUTranslations(somefile) +message = cat.ungettext( + 'There is %(num)d file in this directory', + 'There are %(num)d files in this directory', + n) % {'num': n} +\end{verbatim} + +\versionadded{2.3} +\end{methoddesc} + +\subsubsection{Solaris message catalog support} + +The Solaris operating system defines its own binary +\file{.mo} file format, but since no documentation can be found on +this format, it is not supported at this time. + +\subsubsection{The Catalog constructor} + +GNOME\index{GNOME} uses a version of the \module{gettext} module by +James Henstridge, but this version has a slightly different API. Its +documented usage was: + +\begin{verbatim} +import gettext +cat = gettext.Catalog(domain, localedir) +_ = cat.gettext +print _('hello world') +\end{verbatim} + +For compatibility with this older module, the function +\function{Catalog()} is an alias for the \function{translation()} +function described above. + +One difference between this module and Henstridge's: his catalog +objects supported access through a mapping API, but this appears to be +unused and so is not currently supported. + +\subsection{Internationalizing your programs and modules} +Internationalization (I18N) refers to the operation by which a program +is made aware of multiple languages. Localization (L10N) refers to +the adaptation of your program, once internationalized, to the local +language and cultural habits. In order to provide multilingual +messages for your Python programs, you need to take the following +steps: + +\begin{enumerate} + \item prepare your program or module by specially marking + translatable strings + \item run a suite of tools over your marked files to generate raw + messages catalogs + \item create language specific translations of the message catalogs + \item use the \module{gettext} module so that message strings are + properly translated +\end{enumerate} + +In order to prepare your code for I18N, you need to look at all the +strings in your files. Any string that needs to be translated +should be marked by wrapping it in \code{_('...')} --- that is, a call +to the function \function{_()}. For example: + +\begin{verbatim} +filename = 'mylog.txt' +message = _('writing a log message') +fp = open(filename, 'w') +fp.write(message) +fp.close() +\end{verbatim} + +In this example, the string \code{'writing a log message'} is marked as +a candidate for translation, while the strings \code{'mylog.txt'} and +\code{'w'} are not. + +The Python distribution comes with two tools which help you generate +the message catalogs once you've prepared your source code. These may +or may not be available from a binary distribution, but they can be +found in a source distribution, in the \file{Tools/i18n} directory. + +The \program{pygettext}\footnote{Fran\c cois Pinard has +written a program called +\program{xpot} which does a similar job. It is available as part of +his \program{po-utils} package at +\url{http://po-utils.progiciels-bpi.ca/}.} program +scans all your Python source code looking for the strings you +previously marked as translatable. It is similar to the GNU +\program{gettext} program except that it understands all the +intricacies of Python source code, but knows nothing about C or \Cpp +source code. You don't need GNU \code{gettext} unless you're also +going to be translating C code (such as C extension modules). + +\program{pygettext} generates textual Uniforum-style human readable +message catalog \file{.pot} files, essentially structured human +readable files which contain every marked string in the source code, +along with a placeholder for the translation strings. +\program{pygettext} is a command line script that supports a similar +command line interface as \program{xgettext}; for details on its use, +run: + +\begin{verbatim} +pygettext.py --help +\end{verbatim} + +Copies of these \file{.pot} files are then handed over to the +individual human translators who write language-specific versions for +every supported natural language. They send you back the filled in +language-specific versions as a \file{.po} file. Using the +\program{msgfmt.py}\footnote{\program{msgfmt.py} is binary +compatible with GNU \program{msgfmt} except that it provides a +simpler, all-Python implementation. With this and +\program{pygettext.py}, you generally won't need to install the GNU +\program{gettext} package to internationalize your Python +applications.} program (in the \file{Tools/i18n} directory), you take the +\file{.po} files from your translators and generate the +machine-readable \file{.mo} binary catalog files. The \file{.mo} +files are what the \module{gettext} module uses for the actual +translation processing during run-time. + +How you use the \module{gettext} module in your code depends on +whether you are internationalizing a single module or your entire application. +The next two sections will discuss each case. + +\subsubsection{Localizing your module} + +If you are localizing your module, you must take care not to make +global changes, e.g. to the built-in namespace. You should not use +the GNU \code{gettext} API but instead the class-based API. + +Let's say your module is called ``spam'' and the module's various +natural language translation \file{.mo} files reside in +\file{/usr/share/locale} in GNU \program{gettext} format. Here's what +you would put at the top of your module: + +\begin{verbatim} +import gettext +t = gettext.translation('spam', '/usr/share/locale') +_ = t.lgettext +\end{verbatim} + +If your translators were providing you with Unicode strings in their +\file{.po} files, you'd instead do: + +\begin{verbatim} +import gettext +t = gettext.translation('spam', '/usr/share/locale') +_ = t.ugettext +\end{verbatim} + +\subsubsection{Localizing your application} + +If you are localizing your application, you can install the \function{_()} +function globally into the built-in namespace, usually in the main driver file +of your application. This will let all your application-specific +files just use \code{_('...')} without having to explicitly install it in +each file. + +In the simple case then, you need only add the following bit of code +to the main driver file of your application: + +\begin{verbatim} +import gettext +gettext.install('myapplication') +\end{verbatim} + +If you need to set the locale directory or the \var{unicode} flag, +you can pass these into the \function{install()} function: + +\begin{verbatim} +import gettext +gettext.install('myapplication', '/usr/share/locale', unicode=1) +\end{verbatim} + +\subsubsection{Changing languages on the fly} + +If your program needs to support many languages at the same time, you +may want to create multiple translation instances and then switch +between them explicitly, like so: + +\begin{verbatim} +import gettext + +lang1 = gettext.translation('myapplication', languages=['en']) +lang2 = gettext.translation('myapplication', languages=['fr']) +lang3 = gettext.translation('myapplication', languages=['de']) + +# start by using language1 +lang1.install() + +# ... time goes by, user selects language 2 +lang2.install() + +# ... more time goes by, user selects language 3 +lang3.install() +\end{verbatim} + +\subsubsection{Deferred translations} + +In most coding situations, strings are translated where they are coded. +Occasionally however, you need to mark strings for translation, but +defer actual translation until later. A classic example is: + +\begin{verbatim} +animals = ['mollusk', + 'albatross', + 'rat', + 'penguin', + 'python', + ] +# ... +for a in animals: + print a +\end{verbatim} + +Here, you want to mark the strings in the \code{animals} list as being +translatable, but you don't actually want to translate them until they +are printed. + +Here is one way you can handle this situation: + +\begin{verbatim} +def _(message): return message + +animals = [_('mollusk'), + _('albatross'), + _('rat'), + _('penguin'), + _('python'), + ] + +del _ + +# ... +for a in animals: + print _(a) +\end{verbatim} + +This works because the dummy definition of \function{_()} simply returns +the string unchanged. And this dummy definition will temporarily +override any definition of \function{_()} in the built-in namespace +(until the \keyword{del} command). +Take care, though if you have a previous definition of \function{_} in +the local namespace. + +Note that the second use of \function{_()} will not identify ``a'' as +being translatable to the \program{pygettext} program, since it is not +a string. + +Another way to handle this is with the following example: + +\begin{verbatim} +def N_(message): return message + +animals = [N_('mollusk'), + N_('albatross'), + N_('rat'), + N_('penguin'), + N_('python'), + ] + +# ... +for a in animals: + print _(a) +\end{verbatim} + +In this case, you are marking translatable strings with the function +\function{N_()},\footnote{The choice of \function{N_()} here is totally +arbitrary; it could have just as easily been +\function{MarkThisStringForTranslation()}. +} which won't conflict with any definition of +\function{_()}. However, you will need to teach your message extraction +program to look for translatable strings marked with \function{N_()}. +\program{pygettext} and \program{xpot} both support this through the +use of command line switches. + +\subsubsection{\function{gettext()} vs. \function{lgettext()}} +In Python 2.4 the \function{lgettext()} family of functions were +introduced. The intention of these functions is to provide an +alternative which is more compliant with the current +implementation of GNU gettext. Unlike \function{gettext()}, which +returns strings encoded with the same codeset used in the +translation file, \function{lgettext()} will return strings +encoded with the preferred system encoding, as returned by +\function{locale.getpreferredencoding()}. Also notice that +Python 2.4 introduces new functions to explicitly choose +the codeset used in translated strings. If a codeset is explicitly +set, even \function{lgettext()} will return translated strings in +the requested codeset, as would be expected in the GNU gettext +implementation. + +\subsection{Acknowledgements} + +The following people contributed code, feedback, design suggestions, +previous implementations, and valuable experience to the creation of +this module: + +\begin{itemize} + \item Peter Funk + \item James Henstridge + \item Juan David Ib\'a\~nez Palomar + \item Marc-Andr\'e Lemburg + \item Martin von L\"owis + \item Fran\c cois Pinard + \item Barry Warsaw + \item Gustavo Niemeyer +\end{itemize} diff --git a/sys/src/cmd/python/Doc/lib/libgl.tex b/sys/src/cmd/python/Doc/lib/libgl.tex new file mode 100644 index 000000000..ecf4c3677 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgl.tex @@ -0,0 +1,224 @@ +\section{\module{gl} --- + \emph{Graphics Library} interface} + +\declaremodule{builtin}{gl} + \platform{IRIX} +\modulesynopsis{Functions from the Silicon Graphics \emph{Graphics Library}.} + + +This module provides access to the Silicon Graphics +\emph{Graphics Library}. +It is available only on Silicon Graphics machines. + +\warning{Some illegal calls to the GL library cause the Python +interpreter to dump core. +In particular, the use of most GL calls is unsafe before the first +window is opened.} + +The module is too large to document here in its entirety, but the +following should help you to get started. +The parameter conventions for the C functions are translated to Python as +follows: + +\begin{itemize} +\item +All (short, long, unsigned) int values are represented by Python +integers. +\item +All float and double values are represented by Python floating point +numbers. +In most cases, Python integers are also allowed. +\item +All arrays are represented by one-dimensional Python lists. +In most cases, tuples are also allowed. +\item +\begin{sloppypar} +All string and character arguments are represented by Python strings, +for instance, +\code{winopen('Hi There!')} +and +\code{rotate(900, 'z')}. +\end{sloppypar} +\item +All (short, long, unsigned) integer arguments or return values that are +only used to specify the length of an array argument are omitted. +For example, the C call + +\begin{verbatim} +lmdef(deftype, index, np, props) +\end{verbatim} + +is translated to Python as + +\begin{verbatim} +lmdef(deftype, index, props) +\end{verbatim} + +\item +Output arguments are omitted from the argument list; they are +transmitted as function return values instead. +If more than one value must be returned, the return value is a tuple. +If the C function has both a regular return value (that is not omitted +because of the previous rule) and an output argument, the return value +comes first in the tuple. +Examples: the C call + +\begin{verbatim} +getmcolor(i, &red, &green, &blue) +\end{verbatim} + +is translated to Python as + +\begin{verbatim} +red, green, blue = getmcolor(i) +\end{verbatim} + +\end{itemize} + +The following functions are non-standard or have special argument +conventions: + +\begin{funcdesc}{varray}{argument} +%JHXXX the argument-argument added +Equivalent to but faster than a number of +\code{v3d()} +calls. +The \var{argument} is a list (or tuple) of points. +Each point must be a tuple of coordinates +\code{(\var{x}, \var{y}, \var{z})} or \code{(\var{x}, \var{y})}. +The points may be 2- or 3-dimensional but must all have the +same dimension. +Float and int values may be mixed however. +The points are always converted to 3D double precision points +by assuming \code{\var{z} = 0.0} if necessary (as indicated in the man page), +and for each point +\code{v3d()} +is called. +\end{funcdesc} + +\begin{funcdesc}{nvarray}{} +Equivalent to but faster than a number of +\code{n3f} +and +\code{v3f} +calls. +The argument is an array (list or tuple) of pairs of normals and points. +Each pair is a tuple of a point and a normal for that point. +Each point or normal must be a tuple of coordinates +\code{(\var{x}, \var{y}, \var{z})}. +Three coordinates must be given. +Float and int values may be mixed. +For each pair, +\code{n3f()} +is called for the normal, and then +\code{v3f()} +is called for the point. +\end{funcdesc} + +\begin{funcdesc}{vnarray}{} +Similar to +\code{nvarray()} +but the pairs have the point first and the normal second. +\end{funcdesc} + +\begin{funcdesc}{nurbssurface}{s_k, t_k, ctl, s_ord, t_ord, type} +% XXX s_k[], t_k[], ctl[][] +Defines a nurbs surface. +The dimensions of +\code{\var{ctl}[][]} +are computed as follows: +\code{[len(\var{s_k}) - \var{s_ord}]}, +\code{[len(\var{t_k}) - \var{t_ord}]}. +\end{funcdesc} + +\begin{funcdesc}{nurbscurve}{knots, ctlpoints, order, type} +Defines a nurbs curve. +The length of ctlpoints is +\code{len(\var{knots}) - \var{order}}. +\end{funcdesc} + +\begin{funcdesc}{pwlcurve}{points, type} +Defines a piecewise-linear curve. +\var{points} +is a list of points. +\var{type} +must be +\code{N_ST}. +\end{funcdesc} + +\begin{funcdesc}{pick}{n} +\funcline{select}{n} +The only argument to these functions specifies the desired size of the +pick or select buffer. +\end{funcdesc} + +\begin{funcdesc}{endpick}{} +\funcline{endselect}{} +These functions have no arguments. +They return a list of integers representing the used part of the +pick/select buffer. +No method is provided to detect buffer overrun. +\end{funcdesc} + +Here is a tiny but complete example GL program in Python: + +\begin{verbatim} +import gl, GL, time + +def main(): + gl.foreground() + gl.prefposition(500, 900, 500, 900) + w = gl.winopen('CrissCross') + gl.ortho2(0.0, 400.0, 0.0, 400.0) + gl.color(GL.WHITE) + gl.clear() + gl.color(GL.RED) + gl.bgnline() + gl.v2f(0.0, 0.0) + gl.v2f(400.0, 400.0) + gl.endline() + gl.bgnline() + gl.v2f(400.0, 0.0) + gl.v2f(0.0, 400.0) + gl.endline() + time.sleep(5) + +main() +\end{verbatim} + + +\begin{seealso} + \seetitle[http://pyopengl.sourceforge.net/] + {PyOpenGL: The Python OpenGL Binding} + {An interface to OpenGL\index{OpenGL} is also available; + see information about the + \strong{PyOpenGL}\index{PyOpenGL} project online at + \url{http://pyopengl.sourceforge.net/}. This may be a + better option if support for SGI hardware from before + about 1996 is not required.} +\end{seealso} + + +\section{\module{DEVICE} --- + Constants used with the \module{gl} module} + +\declaremodule{standard}{DEVICE} + \platform{IRIX} +\modulesynopsis{Constants used with the \module{gl} module.} + +This modules defines the constants used by the Silicon Graphics +\emph{Graphics Library} that C programmers find in the header file +\code{}. +Read the module source file for details. + + +\section{\module{GL} --- + Constants used with the \module{gl} module} + +\declaremodule[gl-constants]{standard}{GL} + \platform{IRIX} +\modulesynopsis{Constants used with the \module{gl} module.} + +This module contains constants used by the Silicon Graphics +\emph{Graphics Library} from the C header file \code{}. +Read the module source file for details. diff --git a/sys/src/cmd/python/Doc/lib/libglob.tex b/sys/src/cmd/python/Doc/lib/libglob.tex new file mode 100644 index 000000000..f3f4fb7e5 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libglob.tex @@ -0,0 +1,51 @@ +\section{\module{glob} --- + \UNIX{} style pathname pattern expansion} + +\declaremodule{standard}{glob} +\modulesynopsis{\UNIX\ shell style pathname pattern expansion.} + + +The \module{glob} module finds all the pathnames matching a specified +pattern according to the rules used by the \UNIX{} shell. No tilde +expansion is done, but \code{*}, \code{?}, and character ranges +expressed with \code{[]} will be correctly matched. This is done by +using the \function{os.listdir()} and \function{fnmatch.fnmatch()} +functions in concert, and not by actually invoking a subshell. (For +tilde and shell variable expansion, use \function{os.path.expanduser()} +and \function{os.path.expandvars()}.) +\index{filenames!pathname expansion} + +\begin{funcdesc}{glob}{pathname} +Return a possibly-empty list of path names that match \var{pathname}, +which must be a string containing a path specification. +\var{pathname} can be either absolute (like +\file{/usr/src/Python-1.5/Makefile}) or relative (like +\file{../../Tools/*/*.gif}), and can contain shell-style wildcards. +Broken symlinks are included in the results (as in the shell). +\end{funcdesc} + +\begin{funcdesc}{iglob}{pathname} +Return an iterator which yields the same values as \function{glob()} +without actually storing them all simultaneously. +\versionadded{2.5} +\end{funcdesc} + +For example, consider a directory containing only the following files: +\file{1.gif}, \file{2.txt}, and \file{card.gif}. \function{glob()} +will produce the following results. Notice how any leading components +of the path are preserved. + +\begin{verbatim} +>>> import glob +>>> glob.glob('./[0-9].*') +['./1.gif', './2.txt'] +>>> glob.glob('*.gif') +['1.gif', 'card.gif'] +>>> glob.glob('?.gif') +['1.gif'] +\end{verbatim} + + +\begin{seealso} + \seemodule{fnmatch}{Shell-style filename (not path) expansion} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libgopherlib.tex b/sys/src/cmd/python/Doc/lib/libgopherlib.tex new file mode 100644 index 000000000..4b2260531 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgopherlib.tex @@ -0,0 +1,36 @@ +\section{\module{gopherlib} --- + Gopher protocol client} + +\declaremodule{standard}{gopherlib} +\modulesynopsis{Gopher protocol client (requires sockets).} + +\deprecated{2.5}{The \code{gopher} protocol is not in active use + anymore.} + +\indexii{Gopher}{protocol} + +This module provides a minimal implementation of client side of the +Gopher protocol. It is used by the module \refmodule{urllib} to +handle URLs that use the Gopher protocol. + +The module defines the following functions: + +\begin{funcdesc}{send_selector}{selector, host\optional{, port}} +Send a \var{selector} string to the gopher server at \var{host} and +\var{port} (default \code{70}). Returns an open file object from +which the returned document can be read. +\end{funcdesc} + +\begin{funcdesc}{send_query}{selector, query, host\optional{, port}} +Send a \var{selector} string and a \var{query} string to a gopher +server at \var{host} and \var{port} (default \code{70}). Returns an +open file object from which the returned document can be read. +\end{funcdesc} + +Note that the data returned by the Gopher server can be of any type, +depending on the first character of the selector string. If the data +is text (first character of the selector is \samp{0}), lines are +terminated by CRLF, and the data is terminated by a line consisting of +a single \samp{.}, and a leading \samp{.} should be stripped from +lines that begin with \samp{..}. Directory listings (first character +of the selector is \samp{1}) are transferred using the same protocol. diff --git a/sys/src/cmd/python/Doc/lib/libgrp.tex b/sys/src/cmd/python/Doc/lib/libgrp.tex new file mode 100644 index 000000000..3eed7d086 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgrp.tex @@ -0,0 +1,49 @@ +\section{\module{grp} --- + The group database} + +\declaremodule{builtin}{grp} + \platform{Unix} +\modulesynopsis{The group database (\function{getgrnam()} and friends).} + + +This module provides access to the \UNIX{} group database. +It is available on all \UNIX{} versions. + +Group database entries are reported as a tuple-like object, whose +attributes correspond to the members of the \code{group} structure +(Attribute field below, see \code{}): + +\begin{tableiii}{r|l|l}{textrm}{Index}{Attribute}{Meaning} + \lineiii{0}{gr_name}{the name of the group} + \lineiii{1}{gr_passwd}{the (encrypted) group password; often empty} + \lineiii{2}{gr_gid}{the numerical group ID} + \lineiii{3}{gr_mem}{all the group member's user names} +\end{tableiii} + +The gid is an integer, name and password are strings, and the member +list is a list of strings. +(Note that most users are not explicitly listed as members of the +group they are in according to the password database. Check both +databases to get complete membership information.) + +It defines the following items: + +\begin{funcdesc}{getgrgid}{gid} +Return the group database entry for the given numeric group ID. +\exception{KeyError} is raised if the entry asked for cannot be found. +\end{funcdesc} + +\begin{funcdesc}{getgrnam}{name} +Return the group database entry for the given group name. +\exception{KeyError} is raised if the entry asked for cannot be found. +\end{funcdesc} + +\begin{funcdesc}{getgrall}{} +Return a list of all available group entries, in arbitrary order. +\end{funcdesc} + + +\begin{seealso} + \seemodule{pwd}{An interface to the user database, similar to this.} + \seemodule{spwd}{An interface to the shadow password database, similar to this.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libgzip.tex b/sys/src/cmd/python/Doc/lib/libgzip.tex new file mode 100644 index 000000000..b4cc65944 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libgzip.tex @@ -0,0 +1,70 @@ +\section{\module{gzip} --- + Support for \program{gzip} files} + +\declaremodule{standard}{gzip} +\modulesynopsis{Interfaces for \program{gzip} compression and +decompression using file objects.} + + +The data compression provided by the \code{zlib} module is compatible +with that used by the GNU compression program \program{gzip}. +Accordingly, the \module{gzip} module provides the \class{GzipFile} +class to read and write \program{gzip}-format files, automatically +compressing or decompressing the data so it looks like an ordinary +file object. Note that additional file formats which can be +decompressed by the \program{gzip} and \program{gunzip} programs, such +as those produced by \program{compress} and \program{pack}, are not +supported by this module. + +The module defines the following items: + +\begin{classdesc}{GzipFile}{\optional{filename\optional{, mode\optional{, + compresslevel\optional{, fileobj}}}}} +Constructor for the \class{GzipFile} class, which simulates most of +the methods of a file object, with the exception of the \method{readinto()} +and \method{truncate()} methods. At least one of +\var{fileobj} and \var{filename} must be given a non-trivial value. + +The new class instance is based on \var{fileobj}, which can be a +regular file, a \class{StringIO} object, or any other object which +simulates a file. It defaults to \code{None}, in which case +\var{filename} is opened to provide a file object. + +When \var{fileobj} is not \code{None}, the \var{filename} argument is +only used to be included in the \program{gzip} file header, which may +includes the original filename of the uncompressed file. It defaults +to the filename of \var{fileobj}, if discernible; otherwise, it +defaults to the empty string, and in this case the original filename +is not included in the header. + +The \var{mode} argument can be any of \code{'r'}, \code{'rb'}, +\code{'a'}, \code{'ab'}, \code{'w'}, or \code{'wb'}, depending on +whether the file will be read or written. The default is the mode of +\var{fileobj} if discernible; otherwise, the default is \code{'rb'}. +If not given, the 'b' flag will be added to the mode to ensure the +file is opened in binary mode for cross-platform portability. + +The \var{compresslevel} argument is an integer from \code{1} to +\code{9} controlling the level of compression; \code{1} is fastest and +produces the least compression, and \code{9} is slowest and produces +the most compression. The default is \code{9}. + +Calling a \class{GzipFile} object's \method{close()} method does not +close \var{fileobj}, since you might wish to append more material +after the compressed data. This also allows you to pass a +\class{StringIO} object opened for writing as \var{fileobj}, and +retrieve the resulting memory buffer using the \class{StringIO} +object's \method{getvalue()} method. +\end{classdesc} + +\begin{funcdesc}{open}{filename\optional{, mode\optional{, compresslevel}}} +This is a shorthand for \code{GzipFile(\var{filename},} +\code{\var{mode},} \code{\var{compresslevel})}. The \var{filename} +argument is required; \var{mode} defaults to \code{'rb'} and +\var{compresslevel} defaults to \code{9}. +\end{funcdesc} + +\begin{seealso} + \seemodule{zlib}{The basic data compression module needed to support + the \program{gzip} file format.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libhashlib.tex b/sys/src/cmd/python/Doc/lib/libhashlib.tex new file mode 100644 index 000000000..17f517930 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libhashlib.tex @@ -0,0 +1,114 @@ +\section{\module{hashlib} --- + Secure hashes and message digests} + +\declaremodule{builtin}{hashlib} +\modulesynopsis{Secure hash and message digest algorithms.} +\moduleauthor{Gregory P. Smith}{greg@users.sourceforge.net} +\sectionauthor{Gregory P. Smith}{greg@users.sourceforge.net} + +\versionadded{2.5} + +\index{message digest, MD5} +\index{secure hash algorithm, SHA1, SHA224, SHA256, SHA384, SHA512} + +This module implements a common interface to many different secure hash and +message digest algorithms. Included are the FIPS secure hash algorithms SHA1, +SHA224, SHA256, SHA384, and SHA512 (defined in FIPS 180-2) as well as RSA's MD5 +algorithm (defined in Internet \rfc{1321}). +The terms secure hash and message digest are interchangeable. Older +algorithms were called message digests. The modern term is secure hash. + +\warning{Some algorithms have known hash collision weaknesses, see the FAQ at the end.} + +There is one constructor method named for each type of \dfn{hash}. All return +a hash object with the same simple interface. +For example: use \function{sha1()} to create a SHA1 hash object. +You can now feed this object with arbitrary strings using the \method{update()} +method. At any point you can ask it for the \dfn{digest} of the concatenation +of the strings fed to it so far using the \method{digest()} or +\method{hexdigest()} methods. + +Constructors for hash algorithms that are always present in this module are +\function{md5()}, \function{sha1()}, \function{sha224()}, \function{sha256()}, +\function{sha384()}, and \function{sha512()}. Additional algorithms may also +be available depending upon the OpenSSL library that Python uses on your platform. +\index{OpenSSL} + +For example, to obtain the digest of the string \code{'Nobody inspects +the spammish repetition'}: + +\begin{verbatim} +>>> import hashlib +>>> m = hashlib.md5() +>>> m.update("Nobody inspects") +>>> m.update(" the spammish repetition") +>>> m.digest() +'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9' +\end{verbatim} + +More condensed: + +\begin{verbatim} +>>> hashlib.sha224("Nobody inspects the spammish repetition").hexdigest() +'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2' +\end{verbatim} + +A generic \function{new()} constructor that takes the string name of the +desired algorithm as its first parameter also exists to allow access to the +above listed hashes as well as any other algorithms that your OpenSSL library +may offer. The named constructors are much faster than \function{new()} and +should be preferred. + +Using \function{new()} with an algorithm provided by OpenSSL: + +\begin{verbatim} +>>> h = hashlib.new('ripemd160') +>>> h.update("Nobody inspects the spammish repetition") +>>> h.hexdigest() +'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc' +\end{verbatim} + +The following values are provided as constant attributes of the hash objects +returned by the constructors: + +\begin{datadesc}{digest_size} + The size of the resulting digest in bytes. +\end{datadesc} + +A hash object has the following methods: + +\begin{methoddesc}[hash]{update}{arg} +Update the hash object with the string \var{arg}. Repeated calls are +equivalent to a single call with the concatenation of all the +arguments: \code{m.update(a); m.update(b)} is equivalent to +\code{m.update(a+b)}. +\end{methoddesc} + +\begin{methoddesc}[hash]{digest}{} +Return the digest of the strings passed to the \method{update()} +method so far. This is a string of \member{digest_size} bytes which may +contain non-\ASCII{} characters, including null bytes. +\end{methoddesc} + +\begin{methoddesc}[hash]{hexdigest}{} +Like \method{digest()} except the digest is returned as a string of +double length, containing only hexadecimal digits. This may +be used to exchange the value safely in email or other non-binary +environments. +\end{methoddesc} + +\begin{methoddesc}[hash]{copy}{} +Return a copy (``clone'') of the hash object. This can be used to +efficiently compute the digests of strings that share a common initial +substring. +\end{methoddesc} + +\begin{seealso} + \seemodule{hmac}{A module to generate message authentication codes using hashes.} + \seemodule{base64}{Another way to encode binary hashes for non-binary environments.} + \seeurl{http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf} + {The FIPS 180-2 publication on Secure Hash Algorithms.} + \seeurl{http://www.cryptography.com/cnews/hash.html} + {Hash Collision FAQ with information on which algorithms have known issues and + what that means regarding their use.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libheapq.tex b/sys/src/cmd/python/Doc/lib/libheapq.tex new file mode 100644 index 000000000..5f3d8c598 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libheapq.tex @@ -0,0 +1,214 @@ +\section{\module{heapq} --- + Heap queue algorithm} + +\declaremodule{standard}{heapq} +\modulesynopsis{Heap queue algorithm (a.k.a. priority queue).} +\moduleauthor{Kevin O'Connor}{} +\sectionauthor{Guido van Rossum}{guido@python.org} +% Theoretical explanation: +\sectionauthor{Fran\c cois Pinard}{} +\versionadded{2.3} + + +This module provides an implementation of the heap queue algorithm, +also known as the priority queue algorithm. + +Heaps are arrays for which +\code{\var{heap}[\var{k}] <= \var{heap}[2*\var{k}+1]} and +\code{\var{heap}[\var{k}] <= \var{heap}[2*\var{k}+2]} +for all \var{k}, counting elements from zero. For the sake of +comparison, non-existing elements are considered to be infinite. The +interesting property of a heap is that \code{\var{heap}[0]} is always +its smallest element. + +The API below differs from textbook heap algorithms in two aspects: +(a) We use zero-based indexing. This makes the relationship between the +index for a node and the indexes for its children slightly less +obvious, but is more suitable since Python uses zero-based indexing. +(b) Our pop method returns the smallest item, not the largest (called a +"min heap" in textbooks; a "max heap" is more common in texts because +of its suitability for in-place sorting). + +These two make it possible to view the heap as a regular Python list +without surprises: \code{\var{heap}[0]} is the smallest item, and +\code{\var{heap}.sort()} maintains the heap invariant! + +To create a heap, use a list initialized to \code{[]}, or you can +transform a populated list into a heap via function \function{heapify()}. + +The following functions are provided: + +\begin{funcdesc}{heappush}{heap, item} +Push the value \var{item} onto the \var{heap}, maintaining the +heap invariant. +\end{funcdesc} + +\begin{funcdesc}{heappop}{heap} +Pop and return the smallest item from the \var{heap}, maintaining the +heap invariant. If the heap is empty, \exception{IndexError} is raised. +\end{funcdesc} + +\begin{funcdesc}{heapify}{x} +Transform list \var{x} into a heap, in-place, in linear time. +\end{funcdesc} + +\begin{funcdesc}{heapreplace}{heap, item} +Pop and return the smallest item from the \var{heap}, and also push +the new \var{item}. The heap size doesn't change. +If the heap is empty, \exception{IndexError} is raised. +This is more efficient than \function{heappop()} followed +by \function{heappush()}, and can be more appropriate when using +a fixed-size heap. Note that the value returned may be larger +than \var{item}! That constrains reasonable uses of this routine +unless written as part of a conditional replacement: +\begin{verbatim} + if item > heap[0]: + item = heapreplace(heap, item) +\end{verbatim} +\end{funcdesc} + +Example of use: + +\begin{verbatim} +>>> from heapq import heappush, heappop +>>> heap = [] +>>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] +>>> for item in data: +... heappush(heap, item) +... +>>> ordered = [] +>>> while heap: +... ordered.append(heappop(heap)) +... +>>> print ordered +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +>>> data.sort() +>>> print data == ordered +True +>>> +\end{verbatim} + +The module also offers two general purpose functions based on heaps. + +\begin{funcdesc}{nlargest}{n, iterable\optional{, key}} +Return a list with the \var{n} largest elements from the dataset defined +by \var{iterable}. \var{key}, if provided, specifies a function of one +argument that is used to extract a comparison key from each element +in the iterable: \samp{\var{key}=\function{str.lower}} +Equivalent to: \samp{sorted(iterable, key=key, reverse=True)[:n]} +\versionadded{2.4} +\versionchanged[Added the optional \var{key} argument]{2.5} +\end{funcdesc} + +\begin{funcdesc}{nsmallest}{n, iterable\optional{, key}} +Return a list with the \var{n} smallest elements from the dataset defined +by \var{iterable}. \var{key}, if provided, specifies a function of one +argument that is used to extract a comparison key from each element +in the iterable: \samp{\var{key}=\function{str.lower}} +Equivalent to: \samp{sorted(iterable, key=key)[:n]} +\versionadded{2.4} +\versionchanged[Added the optional \var{key} argument]{2.5} +\end{funcdesc} + +Both functions perform best for smaller values of \var{n}. For larger +values, it is more efficient to use the \function{sorted()} function. Also, +when \code{n==1}, it is more efficient to use the builtin \function{min()} +and \function{max()} functions. + + +\subsection{Theory} + +(This explanation is due to François Pinard. The Python +code for this module was contributed by Kevin O'Connor.) + +Heaps are arrays for which \code{a[\var{k}] <= a[2*\var{k}+1]} and +\code{a[\var{k}] <= a[2*\var{k}+2]} +for all \var{k}, counting elements from 0. For the sake of comparison, +non-existing elements are considered to be infinite. The interesting +property of a heap is that \code{a[0]} is always its smallest element. + +The strange invariant above is meant to be an efficient memory +representation for a tournament. The numbers below are \var{k}, not +\code{a[\var{k}]}: + +\begin{verbatim} + 0 + + 1 2 + + 3 4 5 6 + + 7 8 9 10 11 12 13 14 + + 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 +\end{verbatim} + +In the tree above, each cell \var{k} is topping \code{2*\var{k}+1} and +\code{2*\var{k}+2}. +In an usual binary tournament we see in sports, each cell is the winner +over the two cells it tops, and we can trace the winner down the tree +to see all opponents s/he had. However, in many computer applications +of such tournaments, we do not need to trace the history of a winner. +To be more memory efficient, when a winner is promoted, we try to +replace it by something else at a lower level, and the rule becomes +that a cell and the two cells it tops contain three different items, +but the top cell "wins" over the two topped cells. + +If this heap invariant is protected at all time, index 0 is clearly +the overall winner. The simplest algorithmic way to remove it and +find the "next" winner is to move some loser (let's say cell 30 in the +diagram above) into the 0 position, and then percolate this new 0 down +the tree, exchanging values, until the invariant is re-established. +This is clearly logarithmic on the total number of items in the tree. +By iterating over all items, you get an O(n log n) sort. + +A nice feature of this sort is that you can efficiently insert new +items while the sort is going on, provided that the inserted items are +not "better" than the last 0'th element you extracted. This is +especially useful in simulation contexts, where the tree holds all +incoming events, and the "win" condition means the smallest scheduled +time. When an event schedule other events for execution, they are +scheduled into the future, so they can easily go into the heap. So, a +heap is a good structure for implementing schedulers (this is what I +used for my MIDI sequencer :-). + +Various structures for implementing schedulers have been extensively +studied, and heaps are good for this, as they are reasonably speedy, +the speed is almost constant, and the worst case is not much different +than the average case. However, there are other representations which +are more efficient overall, yet the worst cases might be terrible. + +Heaps are also very useful in big disk sorts. You most probably all +know that a big sort implies producing "runs" (which are pre-sorted +sequences, which size is usually related to the amount of CPU memory), +followed by a merging passes for these runs, which merging is often +very cleverly organised\footnote{The disk balancing algorithms which +are current, nowadays, are +more annoying than clever, and this is a consequence of the seeking +capabilities of the disks. On devices which cannot seek, like big +tape drives, the story was quite different, and one had to be very +clever to ensure (far in advance) that each tape movement will be the +most effective possible (that is, will best participate at +"progressing" the merge). Some tapes were even able to read +backwards, and this was also used to avoid the rewinding time. +Believe me, real good tape sorts were quite spectacular to watch! +From all times, sorting has always been a Great Art! :-)}. +It is very important that the initial +sort produces the longest runs possible. Tournaments are a good way +to that. If, using all the memory available to hold a tournament, you +replace and percolate items that happen to fit the current run, you'll +produce runs which are twice the size of the memory for random input, +and much better for input fuzzily ordered. + +Moreover, if you output the 0'th item on disk and get an input which +may not fit in the current tournament (because the value "wins" over +the last output value), it cannot fit in the heap, so the size of the +heap decreases. The freed memory could be cleverly reused immediately +for progressively building a second heap, which grows at exactly the +same rate the first heap is melting. When the first heap completely +vanishes, you switch heaps and start a new run. Clever and quite +effective! + +In a word, heaps are useful memory structures to know. I use them in +a few applications, and I think it is good to keep a `heap' module +around. :-) diff --git a/sys/src/cmd/python/Doc/lib/libhmac.tex b/sys/src/cmd/python/Doc/lib/libhmac.tex new file mode 100644 index 000000000..5ca24d1c2 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libhmac.tex @@ -0,0 +1,54 @@ +\section{\module{hmac} --- + Keyed-Hashing for Message Authentication} + +\declaremodule{standard}{hmac} +\modulesynopsis{Keyed-Hashing for Message Authentication (HMAC) + implementation for Python.} +\moduleauthor{Gerhard H{\"a}ring}{ghaering@users.sourceforge.net} +\sectionauthor{Gerhard H{\"a}ring}{ghaering@users.sourceforge.net} + +\versionadded{2.2} + +This module implements the HMAC algorithm as described by \rfc{2104}. + +\begin{funcdesc}{new}{key\optional{, msg\optional{, digestmod}}} + Return a new hmac object. If \var{msg} is present, the method call + \code{update(\var{msg})} is made. \var{digestmod} is the digest + constructor or module for the HMAC object to use. It defaults to + the \code{\refmodule{hashlib}.md5} constructor. \note{The md5 hash + has known weaknesses but remains the default for backwards compatibility. + Choose a better one for your application.} +\end{funcdesc} + +An HMAC object has the following methods: + +\begin{methoddesc}[hmac]{update}{msg} + Update the hmac object with the string \var{msg}. Repeated calls + are equivalent to a single call with the concatenation of all the + arguments: \code{m.update(a); m.update(b)} is equivalent to + \code{m.update(a + b)}. +\end{methoddesc} + +\begin{methoddesc}[hmac]{digest}{} + Return the digest of the strings passed to the \method{update()} + method so far. This string will be the same length as the + \var{digest_size} of the digest given to the constructor. It + may contain non-\ASCII{} characters, including NUL bytes. +\end{methoddesc} + +\begin{methoddesc}[hmac]{hexdigest}{} + Like \method{digest()} except the digest is returned as a string + twice the length containing + only hexadecimal digits. This may be used to exchange the value + safely in email or other non-binary environments. +\end{methoddesc} + +\begin{methoddesc}[hmac]{copy}{} + Return a copy (``clone'') of the hmac object. This can be used to + efficiently compute the digests of strings that share a common + initial substring. +\end{methoddesc} + +\begin{seealso} + \seemodule{hashlib}{The python module providing secure hash functions.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libhotshot.tex b/sys/src/cmd/python/Doc/lib/libhotshot.tex new file mode 100644 index 000000000..98e0b6dcc --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libhotshot.tex @@ -0,0 +1,137 @@ +\section{\module{hotshot} --- + High performance logging profiler} + +\declaremodule{standard}{hotshot} +\modulesynopsis{High performance logging profiler, mostly written in C.} +\moduleauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +\sectionauthor{Anthony Baxter}{anthony@interlink.com.au} + +\versionadded{2.2} + + +This module provides a nicer interface to the \module{_hotshot} C module. +Hotshot is a replacement for the existing \refmodule{profile} module. As it's +written mostly in C, it should result in a much smaller performance impact +than the existing \refmodule{profile} module. + +\begin{notice}[note] + The \module{hotshot} module focuses on minimizing the overhead + while profiling, at the expense of long data post-processing times. + For common usages it is recommended to use \module{cProfile} instead. + \module{hotshot} is not maintained and might be removed from the + standard library in the future. +\end{notice} + +\versionchanged[the results should be more meaningful than in the +past: the timing core contained a critical bug]{2.5} + +\begin{notice}[warning] + The \module{hotshot} profiler does not yet work well with threads. + It is useful to use an unthreaded script to run the profiler over + the code you're interested in measuring if at all possible. +\end{notice} + + +\begin{classdesc}{Profile}{logfile\optional{, lineevents\optional{, + linetimings}}} +The profiler object. The argument \var{logfile} is the name of a log +file to use for logged profile data. The argument \var{lineevents} +specifies whether to generate events for every source line, or just on +function call/return. It defaults to \code{0} (only log function +call/return). The argument \var{linetimings} specifies whether to +record timing information. It defaults to \code{1} (store timing +information). +\end{classdesc} + + +\subsection{Profile Objects \label{hotshot-objects}} + +Profile objects have the following methods: + +\begin{methoddesc}{addinfo}{key, value} +Add an arbitrary labelled value to the profile output. +\end{methoddesc} + +\begin{methoddesc}{close}{} +Close the logfile and terminate the profiler. +\end{methoddesc} + +\begin{methoddesc}{fileno}{} +Return the file descriptor of the profiler's log file. +\end{methoddesc} + +\begin{methoddesc}{run}{cmd} +Profile an \keyword{exec}-compatible string in the script environment. +The globals from the \refmodule[main]{__main__} module are used as +both the globals and locals for the script. +\end{methoddesc} + +\begin{methoddesc}{runcall}{func, *args, **keywords} +Profile a single call of a callable. +Additional positional and keyword arguments may be passed +along; the result of the call is returned, and exceptions are +allowed to propagate cleanly, while ensuring that profiling is +disabled on the way out. +\end{methoddesc} + + +\begin{methoddesc}{runctx}{cmd, globals, locals} +Evaluate an \keyword{exec}-compatible string in a specific environment. +The string is compiled before profiling begins. +\end{methoddesc} + +\begin{methoddesc}{start}{} +Start the profiler. +\end{methoddesc} + +\begin{methoddesc}{stop}{} +Stop the profiler. +\end{methoddesc} + + +\subsection{Using hotshot data} + +\declaremodule{standard}{hotshot.stats} +\modulesynopsis{Statistical analysis for Hotshot} + +\versionadded{2.2} + +This module loads hotshot profiling data into the standard \module{pstats} +Stats objects. + +\begin{funcdesc}{load}{filename} +Load hotshot data from \var{filename}. Returns an instance +of the \class{pstats.Stats} class. +\end{funcdesc} + +\begin{seealso} + \seemodule{profile}{The \module{profile} module's \class{Stats} class} +\end{seealso} + + +\subsection{Example Usage \label{hotshot-example}} + +Note that this example runs the python ``benchmark'' pystones. It can +take some time to run, and will produce large output files. + +\begin{verbatim} +>>> import hotshot, hotshot.stats, test.pystone +>>> prof = hotshot.Profile("stones.prof") +>>> benchtime, stones = prof.runcall(test.pystone.pystones) +>>> prof.close() +>>> stats = hotshot.stats.load("stones.prof") +>>> stats.strip_dirs() +>>> stats.sort_stats('time', 'calls') +>>> stats.print_stats(20) + 850004 function calls in 10.090 CPU seconds + + Ordered by: internal time, call count + + ncalls tottime percall cumtime percall filename:lineno(function) + 1 3.295 3.295 10.090 10.090 pystone.py:79(Proc0) + 150000 1.315 0.000 1.315 0.000 pystone.py:203(Proc7) + 50000 1.313 0.000 1.463 0.000 pystone.py:229(Func2) + . + . + . +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libhtmllib.tex b/sys/src/cmd/python/Doc/lib/libhtmllib.tex new file mode 100644 index 000000000..a84dd856d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libhtmllib.tex @@ -0,0 +1,181 @@ +\section{\module{htmllib} --- + A parser for HTML documents} + +\declaremodule{standard}{htmllib} +\modulesynopsis{A parser for HTML documents.} + +\index{HTML} +\index{hypertext} + + +This module defines a class which can serve as a base for parsing text +files formatted in the HyperText Mark-up Language (HTML). The class +is not directly concerned with I/O --- it must be provided with input +in string form via a method, and makes calls to methods of a +``formatter'' object in order to produce output. The +\class{HTMLParser} class is designed to be used as a base class for +other classes in order to add functionality, and allows most of its +methods to be extended or overridden. In turn, this class is derived +from and extends the \class{SGMLParser} class defined in module +\refmodule{sgmllib}\refstmodindex{sgmllib}. The \class{HTMLParser} +implementation supports the HTML 2.0 language as described in +\rfc{1866}. Two implementations of formatter objects are provided in +the \refmodule{formatter}\refstmodindex{formatter}\ module; refer to the +documentation for that module for information on the formatter +interface. +\withsubitem{(in module sgmllib)}{\ttindex{SGMLParser}} + +The following is a summary of the interface defined by +\class{sgmllib.SGMLParser}: + +\begin{itemize} + +\item +The interface to feed data to an instance is through the \method{feed()} +method, which takes a string argument. This can be called with as +little or as much text at a time as desired; \samp{p.feed(a); +p.feed(b)} has the same effect as \samp{p.feed(a+b)}. When the data +contains complete HTML markup constructs, these are processed immediately; +incomplete constructs are saved in a buffer. To force processing of all +unprocessed data, call the \method{close()} method. + +For example, to parse the entire contents of a file, use: +\begin{verbatim} +parser.feed(open('myfile.html').read()) +parser.close() +\end{verbatim} + +\item +The interface to define semantics for HTML tags is very simple: derive +a class and define methods called \method{start_\var{tag}()}, +\method{end_\var{tag}()}, or \method{do_\var{tag}()}. The parser will +call these at appropriate moments: \method{start_\var{tag}} or +\method{do_\var{tag}()} is called when an opening tag of the form +\code{<\var{tag} ...>} is encountered; \method{end_\var{tag}()} is called +when a closing tag of the form \code{<\var{tag}>} is encountered. If +an opening tag requires a corresponding closing tag, like \code{

} +... \code{

}, the class should define the \method{start_\var{tag}()} +method; if a tag requires no closing tag, like \code{

}, the class +should define the \method{do_\var{tag}()} method. + +\end{itemize} + +The module defines a parser class and an exception: + +\begin{classdesc}{HTMLParser}{formatter} +This is the basic HTML parser class. It supports all entity names +required by the XHTML 1.0 Recommendation (\url{http://www.w3.org/TR/xhtml1}). +It also defines handlers for all HTML 2.0 and many HTML 3.0 and 3.2 elements. +\end{classdesc} + +\begin{excdesc}{HTMLParseError} +Exception raised by the \class{HTMLParser} class when it encounters an +error while parsing. +\versionadded{2.4} +\end{excdesc} + + +\begin{seealso} + \seemodule{formatter}{Interface definition for transforming an + abstract flow of formatting events into + specific output events on writer objects.} + \seemodule{HTMLParser}{Alternate HTML parser that offers a slightly + lower-level view of the input, but is + designed to work with XHTML, and does not + implement some of the SGML syntax not used in + ``HTML as deployed'' and which isn't legal + for XHTML.} + \seemodule{htmlentitydefs}{Definition of replacement text for XHTML 1.0 + entities.} + \seemodule{sgmllib}{Base class for \class{HTMLParser}.} +\end{seealso} + + +\subsection{HTMLParser Objects \label{html-parser-objects}} + +In addition to tag methods, the \class{HTMLParser} class provides some +additional methods and instance variables for use within tag methods. + +\begin{memberdesc}{formatter} +This is the formatter instance associated with the parser. +\end{memberdesc} + +\begin{memberdesc}{nofill} +Boolean flag which should be true when whitespace should not be +collapsed, or false when it should be. In general, this should only +be true when character data is to be treated as ``preformatted'' text, +as within a \code{

} element.  The default value is false.  This
+affects the operation of \method{handle_data()} and \method{save_end()}.
+\end{memberdesc}
+
+
+\begin{methoddesc}{anchor_bgn}{href, name, type}
+This method is called at the start of an anchor region.  The arguments
+correspond to the attributes of the \code{} tag with the same
+names.  The default implementation maintains a list of hyperlinks
+(defined by the \code{HREF} attribute for \code{} tags) within the
+document.  The list of hyperlinks is available as the data attribute
+\member{anchorlist}.
+\end{methoddesc}
+
+\begin{methoddesc}{anchor_end}{}
+This method is called at the end of an anchor region.  The default
+implementation adds a textual footnote marker using an index into the
+list of hyperlinks created by \method{anchor_bgn()}.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_image}{source, alt\optional{, ismap\optional{,
+                                 align\optional{, width\optional{, height}}}}}
+This method is called to handle images.  The default implementation
+simply passes the \var{alt} value to the \method{handle_data()}
+method.
+\end{methoddesc}
+
+\begin{methoddesc}{save_bgn}{}
+Begins saving character data in a buffer instead of sending it to the
+formatter object.  Retrieve the stored data via \method{save_end()}.
+Use of the \method{save_bgn()} / \method{save_end()} pair may not be
+nested.
+\end{methoddesc}
+
+\begin{methoddesc}{save_end}{}
+Ends buffering character data and returns all data saved since the
+preceding call to \method{save_bgn()}.  If the \member{nofill} flag is
+false, whitespace is collapsed to single spaces.  A call to this
+method without a preceding call to \method{save_bgn()} will raise a
+\exception{TypeError} exception.
+\end{methoddesc}
+
+
+
+\section{\module{htmlentitydefs} ---
+         Definitions of HTML general entities}
+
+\declaremodule{standard}{htmlentitydefs}
+\modulesynopsis{Definitions of HTML general entities.}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+This module defines three dictionaries, \code{name2codepoint},
+\code{codepoint2name}, and \code{entitydefs}. \code{entitydefs} is
+used by the \refmodule{htmllib} module to provide the
+\member{entitydefs} member of the \class{HTMLParser} class.  The
+definition provided here contains all the entities defined by XHTML 1.0 
+that can be handled using simple textual substitution in the Latin-1
+character set (ISO-8859-1).
+
+
+\begin{datadesc}{entitydefs}
+  A dictionary mapping XHTML 1.0 entity definitions to their
+  replacement text in ISO Latin-1.
+
+\end{datadesc}
+
+\begin{datadesc}{name2codepoint}
+  A dictionary that maps HTML entity names to the Unicode codepoints.
+  \versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{codepoint2name}
+  A dictionary that maps Unicode codepoints to HTML entity names.
+  \versionadded{2.3}
+\end{datadesc}
diff --git a/sys/src/cmd/python/Doc/lib/libhtmlparser.tex b/sys/src/cmd/python/Doc/lib/libhtmlparser.tex
new file mode 100644
index 000000000..52f8409a4
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libhtmlparser.tex
@@ -0,0 +1,169 @@
+\section{\module{HTMLParser} ---
+         Simple HTML and XHTML parser}
+
+\declaremodule{standard}{HTMLParser}
+\modulesynopsis{A simple parser that can handle HTML and XHTML.}
+
+\versionadded{2.2}
+
+This module defines a class \class{HTMLParser} which serves as the
+basis for parsing text files formatted in HTML\index{HTML} (HyperText
+Mark-up Language) and XHTML.\index{XHTML}  Unlike the parser in
+\refmodule{htmllib}, this parser is not based on the SGML parser in
+\refmodule{sgmllib}.
+
+
+\begin{classdesc}{HTMLParser}{}
+The \class{HTMLParser} class is instantiated without arguments.
+
+An HTMLParser instance is fed HTML data and calls handler functions
+when tags begin and end.  The \class{HTMLParser} class is meant to be
+overridden by the user to provide a desired behavior.
+
+Unlike the parser in \refmodule{htmllib}, this parser does not check
+that end tags match start tags or call the end-tag handler for
+elements which are closed implicitly by closing an outer element.
+\end{classdesc}
+
+An exception is defined as well:
+
+\begin{excdesc}{HTMLParseError}
+Exception raised by the \class{HTMLParser} class when it encounters an
+error while parsing.  This exception provides three attributes:
+\member{msg} is a brief message explaining the error, \member{lineno}
+is the number of the line on which the broken construct was detected,
+and \member{offset} is the number of characters into the line at which
+the construct starts.
+\end{excdesc}
+
+
+\class{HTMLParser} instances have the following methods:
+
+\begin{methoddesc}{reset}{}
+Reset the instance.  Loses all unprocessed data.  This is called
+implicitly at instantiation time.
+\end{methoddesc}
+
+\begin{methoddesc}{feed}{data}
+Feed some text to the parser.  It is processed insofar as it consists
+of complete elements; incomplete data is buffered until more data is
+fed or \method{close()} is called.
+\end{methoddesc}
+
+\begin{methoddesc}{close}{}
+Force processing of all buffered data as if it were followed by an
+end-of-file mark.  This method may be redefined by a derived class to
+define additional processing at the end of the input, but the
+redefined version should always call the \class{HTMLParser} base class
+method \method{close()}.
+\end{methoddesc}
+
+\begin{methoddesc}{getpos}{}
+Return current line number and offset.
+\end{methoddesc}
+
+\begin{methoddesc}{get_starttag_text}{}
+Return the text of the most recently opened start tag.  This should
+not normally be needed for structured processing, but may be useful in
+dealing with HTML ``as deployed'' or for re-generating input with
+minimal changes (whitespace between attributes can be preserved,
+etc.).
+\end{methoddesc}
+
+\begin{methoddesc}{handle_starttag}{tag, attrs} 
+This method is called to handle the start of a tag.  It is intended to
+be overridden by a derived class; the base class implementation does
+nothing.  
+
+The \var{tag} argument is the name of the tag converted to
+lower case.  The \var{attrs} argument is a list of \code{(\var{name},
+\var{value})} pairs containing the attributes found inside the tag's
+\code{<>} brackets.  The \var{name} will be translated to lower case
+and double quotes and backslashes in the \var{value} have been
+interpreted.  For instance, for the tag \code{}, this method would be called as
+\samp{handle_starttag('a', [('href', 'http://www.cwi.nl/')])}.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_startendtag}{tag, attrs}
+Similar to \method{handle_starttag()}, but called when the parser
+encounters an XHTML-style empty tag (\code{}).  This method
+may be overridden by subclasses which require this particular lexical
+information; the default implementation simple calls
+\method{handle_starttag()} and \method{handle_endtag()}.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_endtag}{tag}
+This method is called to handle the end tag of an element.  It is
+intended to be overridden by a derived class; the base class
+implementation does nothing.  The \var{tag} argument is the name of
+the tag converted to lower case.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_data}{data}
+This method is called to process arbitrary data.  It is intended to be
+overridden by a derived class; the base class implementation does
+nothing.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_charref}{name} This method is called to
+process a character reference of the form \samp{\&\#\var{ref};}.  It
+is intended to be overridden by a derived class; the base class
+implementation does nothing.  
+\end{methoddesc}
+
+\begin{methoddesc}{handle_entityref}{name} 
+This method is called to process a general entity reference of the
+form \samp{\&\var{name};} where \var{name} is an general entity
+reference.  It is intended to be overridden by a derived class; the
+base class implementation does nothing.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_comment}{data}
+This method is called when a comment is encountered.  The
+\var{comment} argument is a string containing the text between the
+\samp{--} and \samp{--} delimiters, but not the delimiters
+themselves.  For example, the comment \samp{} will
+cause this method to be called with the argument \code{'text'}.  It is
+intended to be overridden by a derived class; the base class
+implementation does nothing.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_decl}{decl}
+Method called when an SGML declaration is read by the parser.  The
+\var{decl} parameter will be the entire contents of the declaration
+inside the \code{} markup.  It is intended to be overridden
+by a derived class; the base class implementation does nothing.
+\end{methoddesc}
+
+\begin{methoddesc}{handle_pi}{data}
+Method called when a processing instruction is encountered.  The
+\var{data} parameter will contain the entire processing instruction.
+For example, for the processing instruction \code{},
+this method would be called as \code{handle_pi("proc color='red'")}.  It
+is intended to be overridden by a derived class; the base class
+implementation does nothing.
+
+\note{The \class{HTMLParser} class uses the SGML syntactic rules for
+processing instructions.  An XHTML processing instruction using the
+trailing \character{?} will cause the \character{?} to be included in
+\var{data}.}
+\end{methoddesc}
+
+
+\subsection{Example HTML Parser Application \label{htmlparser-example}}
+
+As a basic example, below is a very basic HTML parser that uses the
+\class{HTMLParser} class to print out tags as they are encountered:
+
+\begin{verbatim}
+from HTMLParser import HTMLParser
+
+class MyHTMLParser(HTMLParser):
+
+    def handle_starttag(self, tag, attrs):
+        print "Encountered the beginning of a %s tag" % tag
+
+    def handle_endtag(self, tag):
+        print "Encountered the end of a %s tag" % tag
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libhttplib.tex b/sys/src/cmd/python/Doc/lib/libhttplib.tex
new file mode 100644
index 000000000..049f6c480
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libhttplib.tex
@@ -0,0 +1,434 @@
+\section{\module{httplib} ---
+         HTTP protocol client}
+
+\declaremodule{standard}{httplib}
+\modulesynopsis{HTTP and HTTPS protocol client (requires sockets).}
+
+\indexii{HTTP}{protocol}
+\index{HTTP!\module{httplib} (standard module)}
+
+This module defines classes which implement the client side of the
+HTTP and HTTPS protocols.  It is normally not used directly --- the
+module \refmodule{urllib}\refstmodindex{urllib} uses it to handle URLs
+that use HTTP and HTTPS.
+
+\begin{notice}
+  HTTPS support is only available if the \refmodule{socket} module was
+  compiled with SSL support.
+\end{notice}
+
+\begin{notice}
+  The public interface for this module changed substantially in Python
+  2.0.  The \class{HTTP} class is retained only for backward
+  compatibility with 1.5.2.  It should not be used in new code.  Refer
+  to the online docstrings for usage.
+\end{notice}
+
+The module provides the following classes:
+
+\begin{classdesc}{HTTPConnection}{host\optional{, port}}
+An \class{HTTPConnection} instance represents one transaction with an HTTP
+server.  It should be instantiated passing it a host and optional port number.
+If no port number is passed, the port is extracted from the host string if it
+has the form \code{\var{host}:\var{port}}, else the default HTTP port (80) is
+used.  For example, the following calls all create instances that connect to
+the server at the same host and port:
+
+\begin{verbatim}
+>>> h1 = httplib.HTTPConnection('www.cwi.nl')
+>>> h2 = httplib.HTTPConnection('www.cwi.nl:80')
+>>> h3 = httplib.HTTPConnection('www.cwi.nl', 80)
+\end{verbatim}
+\versionadded{2.0}
+\end{classdesc}
+
+\begin{classdesc}{HTTPSConnection}{host\optional{, port, key_file, cert_file}}
+A subclass of \class{HTTPConnection} that uses SSL for communication with
+secure servers.  Default port is \code{443}.
+\var{key_file} is
+the name of a PEM formatted file that contains your private
+key. \var{cert_file} is a PEM formatted certificate chain file.
+
+\warning{This does not do any certificate verification!}
+
+\versionadded{2.0}
+\end{classdesc}
+
+\begin{classdesc}{HTTPResponse}{sock\optional{, debuglevel=0}\optional{, strict=0}}
+Class whose instances are returned upon successful connection.  Not
+instantiated directly by user.
+\versionadded{2.0}
+\end{classdesc}
+
+The following exceptions are raised as appropriate:
+
+\begin{excdesc}{HTTPException}
+The base class of the other exceptions in this module.  It is a
+subclass of \exception{Exception}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{NotConnected}
+A subclass of \exception{HTTPException}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{InvalidURL}
+A subclass of \exception{HTTPException}, raised if a port is given and is
+either non-numeric or empty.
+\versionadded{2.3}
+\end{excdesc}
+
+\begin{excdesc}{UnknownProtocol}
+A subclass of \exception{HTTPException}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{UnknownTransferEncoding}
+A subclass of \exception{HTTPException}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{UnimplementedFileMode}
+A subclass of \exception{HTTPException}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{IncompleteRead}
+A subclass of \exception{HTTPException}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{ImproperConnectionState}
+A subclass of \exception{HTTPException}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{CannotSendRequest}
+A subclass of \exception{ImproperConnectionState}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{CannotSendHeader}
+A subclass of \exception{ImproperConnectionState}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{ResponseNotReady}
+A subclass of \exception{ImproperConnectionState}.
+\versionadded{2.0}
+\end{excdesc}
+
+\begin{excdesc}{BadStatusLine}
+A subclass of \exception{HTTPException}.  Raised if a server responds with a
+HTTP status code that we don't understand.
+\versionadded{2.0}
+\end{excdesc}
+
+The constants defined in this module are:
+
+\begin{datadesc}{HTTP_PORT}
+  The default port for the HTTP protocol (always \code{80}).
+\end{datadesc}
+
+\begin{datadesc}{HTTPS_PORT}
+  The default port for the HTTPS protocol (always \code{443}).
+\end{datadesc}
+
+and also the following constants for integer status codes:
+
+\begin{tableiii}{l|c|l}{constant}{Constant}{Value}{Definition}
+  \lineiii{CONTINUE}{\code{100}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.1.1}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1.1}}
+  \lineiii{SWITCHING_PROTOCOLS}{\code{101}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.1.2}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1.2}}
+  \lineiii{PROCESSING}{\code{102}}
+    {WEBDAV, \ulink{RFC 2518, Section 10.1}
+      {http://www.webdav.org/specs/rfc2518.html#STATUS_102}}
+
+  \lineiii{OK}{\code{200}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.2.1}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.1}}
+  \lineiii{CREATED}{\code{201}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.2.2}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.2}}
+  \lineiii{ACCEPTED}{\code{202}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.2.3}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.3}}
+  \lineiii{NON_AUTHORITATIVE_INFORMATION}{\code{203}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.2.4}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.4}}
+  \lineiii{NO_CONTENT}{\code{204}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.2.5}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5}}
+  \lineiii{RESET_CONTENT}{\code{205}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.2.6}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.6}}
+  \lineiii{PARTIAL_CONTENT}{\code{206}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.2.7}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.7}}
+  \lineiii{MULTI_STATUS}{\code{207}}
+    {WEBDAV \ulink{RFC 2518, Section 10.2}
+      {http://www.webdav.org/specs/rfc2518.html#STATUS_207}}
+  \lineiii{IM_USED}{\code{226}}
+    {Delta encoding in HTTP, \rfc{3229}, Section 10.4.1}
+
+  \lineiii{MULTIPLE_CHOICES}{\code{300}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.3.1}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1}}
+  \lineiii{MOVED_PERMANENTLY}{\code{301}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.3.2}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.2}}
+  \lineiii{FOUND}{\code{302}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.3.3}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.3}}
+  \lineiii{SEE_OTHER}{\code{303}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.3.4}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4}}
+  \lineiii{NOT_MODIFIED}{\code{304}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.3.5}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5}}
+  \lineiii{USE_PROXY}{\code{305}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.3.6}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.6}}
+  \lineiii{TEMPORARY_REDIRECT}{\code{307}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.3.8}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.8}}
+
+  \lineiii{BAD_REQUEST}{\code{400}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.1}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1}}
+  \lineiii{UNAUTHORIZED}{\code{401}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.2}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2}}
+  \lineiii{PAYMENT_REQUIRED}{\code{402}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.3}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.3}}
+  \lineiii{FORBIDDEN}{\code{403}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.4}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4}}
+  \lineiii{NOT_FOUND}{\code{404}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.5}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5}}
+  \lineiii{METHOD_NOT_ALLOWED}{\code{405}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.6}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.6}}
+  \lineiii{NOT_ACCEPTABLE}{\code{406}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.7}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.7}}
+  \lineiii{PROXY_AUTHENTICATION_REQUIRED}
+    {\code{407}}{HTTP/1.1, \ulink{RFC 2616, Section 10.4.8}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.8}}
+  \lineiii{REQUEST_TIMEOUT}{\code{408}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.9}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.9}}
+  \lineiii{CONFLICT}{\code{409}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.10}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.10}}
+  \lineiii{GONE}{\code{410}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.11}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.11}}
+  \lineiii{LENGTH_REQUIRED}{\code{411}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.12}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.12}}
+  \lineiii{PRECONDITION_FAILED}{\code{412}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.13}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.13}}
+  \lineiii{REQUEST_ENTITY_TOO_LARGE}
+    {\code{413}}{HTTP/1.1, \ulink{RFC 2616, Section 10.4.14}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.14}}
+  \lineiii{REQUEST_URI_TOO_LONG}{\code{414}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.15}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.15}}
+  \lineiii{UNSUPPORTED_MEDIA_TYPE}{\code{415}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.16}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.16}}
+  \lineiii{REQUESTED_RANGE_NOT_SATISFIABLE}{\code{416}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.17}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.17}}
+  \lineiii{EXPECTATION_FAILED}{\code{417}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.4.18}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.18}}
+  \lineiii{UNPROCESSABLE_ENTITY}{\code{422}}
+    {WEBDAV, \ulink{RFC 2518, Section 10.3}
+      {http://www.webdav.org/specs/rfc2518.html#STATUS_422}}
+  \lineiii{LOCKED}{\code{423}}
+    {WEBDAV \ulink{RFC 2518, Section 10.4}
+      {http://www.webdav.org/specs/rfc2518.html#STATUS_423}}
+  \lineiii{FAILED_DEPENDENCY}{\code{424}}
+    {WEBDAV, \ulink{RFC 2518, Section 10.5}
+      {http://www.webdav.org/specs/rfc2518.html#STATUS_424}}
+  \lineiii{UPGRADE_REQUIRED}{\code{426}}
+    {HTTP Upgrade to TLS, \rfc{2817}, Section 6}
+
+  \lineiii{INTERNAL_SERVER_ERROR}{\code{500}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.5.1}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.1}}
+  \lineiii{NOT_IMPLEMENTED}{\code{501}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.5.2}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.2}}
+  \lineiii{BAD_GATEWAY}{\code{502}}
+    {HTTP/1.1 \ulink{RFC 2616, Section 10.5.3}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.3}}
+  \lineiii{SERVICE_UNAVAILABLE}{\code{503}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.5.4}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.4}}
+  \lineiii{GATEWAY_TIMEOUT}{\code{504}}
+    {HTTP/1.1 \ulink{RFC 2616, Section 10.5.5}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.5}}
+  \lineiii{HTTP_VERSION_NOT_SUPPORTED}{\code{505}}
+    {HTTP/1.1, \ulink{RFC 2616, Section 10.5.6}
+      {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.6}}
+  \lineiii{INSUFFICIENT_STORAGE}{\code{507}}
+    {WEBDAV, \ulink{RFC 2518, Section 10.6}
+      {http://www.webdav.org/specs/rfc2518.html#STATUS_507}}
+  \lineiii{NOT_EXTENDED}{\code{510}}
+    {An HTTP Extension Framework, \rfc{2774}, Section 7}
+\end{tableiii}
+
+\begin{datadesc}{responses}
+This dictionary maps the HTTP 1.1 status codes to the W3C names.
+
+Example: \code{httplib.responses[httplib.NOT_FOUND]} is \code{'Not Found'}.
+\versionadded{2.5}
+\end{datadesc}
+
+
+\subsection{HTTPConnection Objects \label{httpconnection-objects}}
+
+\class{HTTPConnection} instances have the following methods:
+
+\begin{methoddesc}{request}{method, url\optional{, body\optional{, headers}}}
+This will send a request to the server using the HTTP request method
+\var{method} and the selector \var{url}.  If the \var{body} argument is
+present, it should be a string of data to send after the headers are finished.
+The header Content-Length is automatically set to the correct value.
+The \var{headers} argument should be a mapping of extra HTTP headers to send
+with the request.
+\end{methoddesc}
+
+\begin{methoddesc}{getresponse}{}
+Should be called after a request is sent to get the response from the server.
+Returns an \class{HTTPResponse} instance.
+\note{Note that you must have read the whole response before you can send a new
+request to the server.}
+\end{methoddesc}
+
+\begin{methoddesc}{set_debuglevel}{level}
+Set the debugging level (the amount of debugging output printed).
+The default debug level is \code{0}, meaning no debugging output is
+printed.
+\end{methoddesc}
+
+\begin{methoddesc}{connect}{}
+Connect to the server specified when the object was created.
+\end{methoddesc}
+
+\begin{methoddesc}{close}{}
+Close the connection to the server.
+\end{methoddesc}
+
+As an alternative to using the \method{request()} method described above,
+you can also send your request step by step, by using the four functions
+below.
+
+\begin{methoddesc}{putrequest}{request, selector\optional{,
+skip\_host\optional{, skip_accept_encoding}}}
+This should be the first call after the connection to the server has
+been made.  It sends a line to the server consisting of the
+\var{request} string, the \var{selector} string, and the HTTP version
+(\code{HTTP/1.1}).  To disable automatic sending of \code{Host:} or
+\code{Accept-Encoding:} headers (for example to accept additional
+content encodings), specify \var{skip_host} or \var{skip_accept_encoding}
+with non-False values.
+\versionchanged[\var{skip_accept_encoding} argument added]{2.4}
+\end{methoddesc}
+
+\begin{methoddesc}{putheader}{header, argument\optional{, ...}}
+Send an \rfc{822}-style header to the server.  It sends a line to the
+server consisting of the header, a colon and a space, and the first
+argument.  If more arguments are given, continuation lines are sent,
+each consisting of a tab and an argument.
+\end{methoddesc}
+
+\begin{methoddesc}{endheaders}{}
+Send a blank line to the server, signalling the end of the headers.
+\end{methoddesc}
+
+\begin{methoddesc}{send}{data}
+Send data to the server.  This should be used directly only after the
+\method{endheaders()} method has been called and before
+\method{getresponse()} is called.
+\end{methoddesc}
+
+\subsection{HTTPResponse Objects \label{httpresponse-objects}}
+
+\class{HTTPResponse} instances have the following methods and attributes:
+
+\begin{methoddesc}{read}{\optional{amt}}
+Reads and returns the response body, or up to the next \var{amt} bytes.
+\end{methoddesc}
+
+\begin{methoddesc}{getheader}{name\optional{, default}}
+Get the contents of the header \var{name}, or \var{default} if there is no
+matching header.
+\end{methoddesc}
+
+\begin{methoddesc}{getheaders}{}
+Return a list of (header, value) tuples. \versionadded{2.4}
+\end{methoddesc}
+
+\begin{datadesc}{msg}
+  A \class{mimetools.Message} instance containing the response headers.
+\end{datadesc}
+
+\begin{datadesc}{version}
+  HTTP protocol version used by server.  10 for HTTP/1.0, 11 for HTTP/1.1.
+\end{datadesc}
+
+\begin{datadesc}{status}
+  Status code returned by server.
+\end{datadesc}
+
+\begin{datadesc}{reason}
+  Reason phrase returned by server.
+\end{datadesc}
+
+
+\subsection{Examples \label{httplib-examples}}
+
+Here is an example session that uses the \samp{GET} method:
+
+\begin{verbatim}
+>>> import httplib
+>>> conn = httplib.HTTPConnection("www.python.org")
+>>> conn.request("GET", "/index.html")
+>>> r1 = conn.getresponse()
+>>> print r1.status, r1.reason
+200 OK
+>>> data1 = r1.read()
+>>> conn.request("GET", "/parrot.spam")
+>>> r2 = conn.getresponse()
+>>> print r2.status, r2.reason
+404 Not Found
+>>> data2 = r2.read()
+>>> conn.close()
+\end{verbatim}
+
+Here is an example session that shows how to \samp{POST} requests:
+
+\begin{verbatim}
+>>> import httplib, urllib
+>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0})
+>>> headers = {"Content-type": "application/x-www-form-urlencoded",
+...            "Accept": "text/plain"}
+>>> conn = httplib.HTTPConnection("musi-cal.mojam.com:80")
+>>> conn.request("POST", "/cgi-bin/query", params, headers)
+>>> response = conn.getresponse()
+>>> print response.status, response.reason
+200 OK
+>>> data = response.read()
+>>> conn.close()
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libimageop.tex b/sys/src/cmd/python/Doc/lib/libimageop.tex
new file mode 100644
index 000000000..0f732bf67
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libimageop.tex
@@ -0,0 +1,100 @@
+\section{\module{imageop} ---
+         Manipulate raw image data}
+
+\declaremodule{builtin}{imageop}
+\modulesynopsis{Manipulate raw image data.}
+
+
+The \module{imageop} module contains some useful operations on images.
+It operates on images consisting of 8 or 32 bit pixels stored in
+Python strings.  This is the same format as used by
+\function{gl.lrectwrite()} and the \refmodule{imgfile} module.
+
+The module defines the following variables and functions:
+
+\begin{excdesc}{error}
+This exception is raised on all errors, such as unknown number of bits
+per pixel, etc.
+\end{excdesc}
+
+
+\begin{funcdesc}{crop}{image, psize, width, height, x0, y0, x1, y1}
+Return the selected part of \var{image}, which should be
+\var{width} by \var{height} in size and consist of pixels of
+\var{psize} bytes. \var{x0}, \var{y0}, \var{x1} and \var{y1} are like
+the \function{gl.lrectread()} parameters, i.e.\ the boundary is
+included in the new image.  The new boundaries need not be inside the
+picture.  Pixels that fall outside the old image will have their value
+set to zero.  If \var{x0} is bigger than \var{x1} the new image is
+mirrored.  The same holds for the y coordinates.
+\end{funcdesc}
+
+\begin{funcdesc}{scale}{image, psize, width, height, newwidth, newheight}
+Return \var{image} scaled to size \var{newwidth} by \var{newheight}.
+No interpolation is done, scaling is done by simple-minded pixel
+duplication or removal.  Therefore, computer-generated images or
+dithered images will not look nice after scaling.
+\end{funcdesc}
+
+\begin{funcdesc}{tovideo}{image, psize, width, height}
+Run a vertical low-pass filter over an image.  It does so by computing
+each destination pixel as the average of two vertically-aligned source
+pixels.  The main use of this routine is to forestall excessive
+flicker if the image is displayed on a video device that uses
+interlacing, hence the name.
+\end{funcdesc}
+
+\begin{funcdesc}{grey2mono}{image, width, height, threshold}
+Convert a 8-bit deep greyscale image to a 1-bit deep image by
+thresholding all the pixels.  The resulting image is tightly packed and
+is probably only useful as an argument to \function{mono2grey()}.
+\end{funcdesc}
+
+\begin{funcdesc}{dither2mono}{image, width, height}
+Convert an 8-bit greyscale image to a 1-bit monochrome image using a
+(simple-minded) dithering algorithm.
+\end{funcdesc}
+
+\begin{funcdesc}{mono2grey}{image, width, height, p0, p1}
+Convert a 1-bit monochrome image to an 8 bit greyscale or color image.
+All pixels that are zero-valued on input get value \var{p0} on output
+and all one-value input pixels get value \var{p1} on output.  To
+convert a monochrome black-and-white image to greyscale pass the
+values \code{0} and \code{255} respectively.
+\end{funcdesc}
+
+\begin{funcdesc}{grey2grey4}{image, width, height}
+Convert an 8-bit greyscale image to a 4-bit greyscale image without
+dithering.
+\end{funcdesc}
+
+\begin{funcdesc}{grey2grey2}{image, width, height}
+Convert an 8-bit greyscale image to a 2-bit greyscale image without
+dithering.
+\end{funcdesc}
+
+\begin{funcdesc}{dither2grey2}{image, width, height}
+Convert an 8-bit greyscale image to a 2-bit greyscale image with
+dithering.  As for \function{dither2mono()}, the dithering algorithm
+is currently very simple.
+\end{funcdesc}
+
+\begin{funcdesc}{grey42grey}{image, width, height}
+Convert a 4-bit greyscale image to an 8-bit greyscale image.
+\end{funcdesc}
+
+\begin{funcdesc}{grey22grey}{image, width, height}
+Convert a 2-bit greyscale image to an 8-bit greyscale image.
+\end{funcdesc}
+
+\begin{datadesc}{backward_compatible}
+If set to 0, the functions in this module use a non-backward
+compatible way of representing multi-byte pixels on little-endian
+systems.  The SGI for which this module was originally written is a
+big-endian system, so setting this variable will have no effect.
+However, the code wasn't originally intended to run on anything else,
+so it made assumptions about byte order which are not universal.
+Setting this variable to 0 will cause the byte order to be reversed on
+little-endian systems, so that it then is the same as on big-endian
+systems.
+\end{datadesc}
diff --git a/sys/src/cmd/python/Doc/lib/libimaplib.tex b/sys/src/cmd/python/Doc/lib/libimaplib.tex
new file mode 100644
index 000000000..7658bc965
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libimaplib.tex
@@ -0,0 +1,507 @@
+\section{\module{imaplib} ---
+         IMAP4 protocol client}
+
+\declaremodule{standard}{imaplib}
+\modulesynopsis{IMAP4 protocol client (requires sockets).}
+\moduleauthor{Piers Lauder}{piers@communitysolutions.com.au}
+\sectionauthor{Piers Lauder}{piers@communitysolutions.com.au}
+
+% Based on HTML documentation by Piers Lauder
+% ;
+% converted by Fred L. Drake, Jr. .
+% Revised by ESR, January 2000.
+% Changes for IMAP4_SSL by Tino Lange , March 2002 
+% Changes for IMAP4_stream by Piers Lauder
+% , November 2002
+
+\indexii{IMAP4}{protocol}
+\indexii{IMAP4_SSL}{protocol}
+\indexii{IMAP4_stream}{protocol}
+
+This module defines three classes, \class{IMAP4}, \class{IMAP4_SSL}
+and \class{IMAP4_stream}, which encapsulate a
+connection to an IMAP4 server and implement a large subset of the
+IMAP4rev1 client protocol as defined in \rfc{2060}. It is backward
+compatible with IMAP4 (\rfc{1730}) servers, but note that the
+\samp{STATUS} command is not supported in IMAP4.
+
+Three classes are provided by the \module{imaplib} module,
+\class{IMAP4} is the base class:
+
+\begin{classdesc}{IMAP4}{\optional{host\optional{, port}}}
+This class implements the actual IMAP4 protocol.  The connection is
+created and protocol version (IMAP4 or IMAP4rev1) is determined when
+the instance is initialized.
+If \var{host} is not specified, \code{''} (the local host) is used.
+If \var{port} is omitted, the standard IMAP4 port (143) is used.
+\end{classdesc}
+
+Three exceptions are defined as attributes of the \class{IMAP4} class:
+
+\begin{excdesc}{IMAP4.error}
+Exception raised on any errors.  The reason for the exception is
+passed to the constructor as a string.
+\end{excdesc}
+
+\begin{excdesc}{IMAP4.abort}
+IMAP4 server errors cause this exception to be raised.  This is a
+sub-class of \exception{IMAP4.error}.  Note that closing the instance
+and instantiating a new one will usually allow recovery from this
+exception.
+\end{excdesc}
+
+\begin{excdesc}{IMAP4.readonly}
+This exception is raised when a writable mailbox has its status
+changed by the server.  This is a sub-class of
+\exception{IMAP4.error}.  Some other client now has write permission,
+and the mailbox will need to be re-opened to re-obtain write
+permission.
+\end{excdesc}
+
+There's also a subclass for secure connections:
+
+\begin{classdesc}{IMAP4_SSL}{\optional{host\optional{, port\optional{,
+                             keyfile\optional{, certfile}}}}}
+This is a subclass derived from \class{IMAP4} that connects over an
+SSL encrypted socket (to use this class you need a socket module that
+was compiled with SSL support).  If \var{host} is not specified,
+\code{''} (the local host) is used.  If \var{port} is omitted, the
+standard IMAP4-over-SSL port (993) is used.  \var{keyfile} and
+\var{certfile} are also optional - they can contain a PEM formatted
+private key and certificate chain file for the SSL connection.
+\end{classdesc}
+
+The second subclass allows for connections created by a child process:
+
+\begin{classdesc}{IMAP4_stream}{command}
+This is a subclass derived from \class{IMAP4} that connects
+to the \code{stdin/stdout} file descriptors created by passing
+\var{command} to \code{os.popen2()}.
+\versionadded{2.3}
+\end{classdesc}
+
+The following utility functions are defined:
+
+\begin{funcdesc}{Internaldate2tuple}{datestr}
+  Converts an IMAP4 INTERNALDATE string to Coordinated Universal
+  Time. Returns a \refmodule{time} module tuple.
+\end{funcdesc}
+
+\begin{funcdesc}{Int2AP}{num}
+  Converts an integer into a string representation using characters
+  from the set [\code{A} .. \code{P}].
+\end{funcdesc}
+
+\begin{funcdesc}{ParseFlags}{flagstr}
+  Converts an IMAP4 \samp{FLAGS} response to a tuple of individual
+  flags.
+\end{funcdesc}
+
+\begin{funcdesc}{Time2Internaldate}{date_time}
+  Converts a \refmodule{time} module tuple to an IMAP4
+  \samp{INTERNALDATE} representation.  Returns a string in the form:
+  \code{"DD-Mmm-YYYY HH:MM:SS +HHMM"} (including double-quotes).
+\end{funcdesc}
+
+
+Note that IMAP4 message numbers change as the mailbox changes; in
+particular, after an \samp{EXPUNGE} command performs deletions the
+remaining messages are renumbered. So it is highly advisable to use
+UIDs instead, with the UID command.
+
+At the end of the module, there is a test section that contains a more
+extensive example of usage.
+
+\begin{seealso}
+  \seetext{Documents describing the protocol, and sources and binaries 
+           for servers implementing it, can all be found at the
+           University of Washington's \emph{IMAP Information Center}
+           (\url{http://www.cac.washington.edu/imap/}).}
+\end{seealso}
+
+
+\subsection{IMAP4 Objects \label{imap4-objects}}
+
+All IMAP4rev1 commands are represented by methods of the same name,
+either upper-case or lower-case.
+
+All arguments to commands are converted to strings, except for
+\samp{AUTHENTICATE}, and the last argument to \samp{APPEND} which is
+passed as an IMAP4 literal.  If necessary (the string contains IMAP4
+protocol-sensitive characters and isn't enclosed with either
+parentheses or double quotes) each string is quoted. However, the
+\var{password} argument to the \samp{LOGIN} command is always quoted.
+If you want to avoid having an argument string quoted
+(eg: the \var{flags} argument to \samp{STORE}) then enclose the string in
+parentheses (eg: \code{r'(\e Deleted)'}).
+
+Each command returns a tuple: \code{(\var{type}, [\var{data},
+...])} where \var{type} is usually \code{'OK'} or \code{'NO'},
+and \var{data} is either the text from the command response, or
+mandated results from the command. Each \var{data}
+is either a string, or a tuple. If a tuple, then the first part
+is the header of the response, and the second part contains
+the data (ie: 'literal' value).
+
+The \var{message_set} options to commands below is a string specifying one
+or more messages to be acted upon.  It may be a simple message number
+(\code{'1'}), a range of message numbers (\code{'2:4'}), or a group of
+non-contiguous ranges separated by commas (\code{'1:3,6:9'}).  A range
+can contain an asterisk to indicate an infinite upper bound
+(\code{'3:*'}).
+
+An \class{IMAP4} instance has the following methods:
+
+
+\begin{methoddesc}{append}{mailbox, flags, date_time, message}
+  Append \var{message} to named mailbox. 
+\end{methoddesc}
+
+\begin{methoddesc}{authenticate}{mechanism, authobject}
+  Authenticate command --- requires response processing.
+
+  \var{mechanism} specifies which authentication mechanism is to be
+  used - it should appear in the instance variable \code{capabilities}
+  in the form \code{AUTH=mechanism}.
+
+  \var{authobject} must be a callable object:
+
+\begin{verbatim}
+data = authobject(response)
+\end{verbatim}
+
+  It will be called to process server continuation responses.
+  It should return \code{data} that will be encoded and sent to server.
+  It should return \code{None} if the client abort response \samp{*} should
+  be sent instead.
+\end{methoddesc}
+
+\begin{methoddesc}{check}{}
+  Checkpoint mailbox on server. 
+\end{methoddesc}
+
+\begin{methoddesc}{close}{}
+  Close currently selected mailbox. Deleted messages are removed from
+  writable mailbox. This is the recommended command before
+  \samp{LOGOUT}.
+\end{methoddesc}
+
+\begin{methoddesc}{copy}{message_set, new_mailbox}
+  Copy \var{message_set} messages onto end of \var{new_mailbox}. 
+\end{methoddesc}
+
+\begin{methoddesc}{create}{mailbox}
+  Create new mailbox named \var{mailbox}.
+\end{methoddesc}
+
+\begin{methoddesc}{delete}{mailbox}
+  Delete old mailbox named \var{mailbox}.
+\end{methoddesc}
+
+\begin{methoddesc}{deleteacl}{mailbox, who}
+  Delete the ACLs (remove any rights) set for who on mailbox.
+\versionadded{2.4}
+\end{methoddesc}
+
+\begin{methoddesc}{expunge}{}
+  Permanently remove deleted items from selected mailbox. Generates an
+  \samp{EXPUNGE} response for each deleted message. Returned data
+  contains a list of \samp{EXPUNGE} message numbers in order
+  received.
+\end{methoddesc}
+
+\begin{methoddesc}{fetch}{message_set, message_parts}
+  Fetch (parts of) messages.  \var{message_parts} should be
+  a string of message part names enclosed within parentheses,
+  eg: \samp{"(UID BODY[TEXT])"}.  Returned data are tuples
+  of message part envelope and data.
+\end{methoddesc}
+
+\begin{methoddesc}{getacl}{mailbox}
+  Get the \samp{ACL}s for \var{mailbox}.
+  The method is non-standard, but is supported by the \samp{Cyrus} server.
+\end{methoddesc}
+
+\begin{methoddesc}{getannotation}{mailbox, entry, attribute}
+  Retrieve the specified \samp{ANNOTATION}s for \var{mailbox}.
+  The method is non-standard, but is supported by the \samp{Cyrus} server.
+\versionadded{2.5}
+\end{methoddesc}
+
+\begin{methoddesc}{getquota}{root}
+  Get the \samp{quota} \var{root}'s resource usage and limits.
+  This method is part of the IMAP4 QUOTA extension defined in rfc2087.
+\versionadded{2.3}
+\end{methoddesc}
+
+\begin{methoddesc}{getquotaroot}{mailbox}
+  Get the list of \samp{quota} \samp{roots} for the named \var{mailbox}.
+  This method is part of the IMAP4 QUOTA extension defined in rfc2087.
+\versionadded{2.3}
+\end{methoddesc}
+
+\begin{methoddesc}{list}{\optional{directory\optional{, pattern}}}
+  List mailbox names in \var{directory} matching
+  \var{pattern}.  \var{directory} defaults to the top-level mail
+  folder, and \var{pattern} defaults to match anything.  Returned data
+  contains a list of \samp{LIST} responses.
+\end{methoddesc}
+
+\begin{methoddesc}{login}{user, password}
+  Identify the client using a plaintext password.
+  The \var{password} will be quoted.
+\end{methoddesc}
+
+\begin{methoddesc}{login_cram_md5}{user, password}
+  Force use of \samp{CRAM-MD5} authentication when identifying the
+  client to protect the password.  Will only work if the server
+  \samp{CAPABILITY} response includes the phrase \samp{AUTH=CRAM-MD5}.
+\versionadded{2.3}
+\end{methoddesc}
+
+\begin{methoddesc}{logout}{}
+  Shutdown connection to server. Returns server \samp{BYE} response.
+\end{methoddesc}
+
+\begin{methoddesc}{lsub}{\optional{directory\optional{, pattern}}}
+  List subscribed mailbox names in directory matching pattern.
+  \var{directory} defaults to the top level directory and
+  \var{pattern} defaults to match any mailbox.
+  Returned data are tuples of message part envelope and data.
+\end{methoddesc}
+
+\begin{methoddesc}{myrights}{mailbox}
+  Show my ACLs for a mailbox (i.e. the rights that I have on mailbox).
+\versionadded{2.4}
+\end{methoddesc}
+
+\begin{methoddesc}{namespace}{}
+  Returns IMAP namespaces as defined in RFC2342.
+\versionadded{2.3}
+\end{methoddesc}
+
+\begin{methoddesc}{noop}{}
+  Send \samp{NOOP} to server.
+\end{methoddesc}
+
+\begin{methoddesc}{open}{host, port}
+  Opens socket to \var{port} at \var{host}.
+  The connection objects established by this method
+  will be used in the \code{read}, \code{readline}, \code{send}, and
+  \code{shutdown} methods.
+  You may override this method.
+\end{methoddesc}
+
+\begin{methoddesc}{partial}{message_num, message_part, start, length}
+  Fetch truncated part of a message.
+  Returned data is a tuple of message part envelope and data.
+\end{methoddesc}
+
+\begin{methoddesc}{proxyauth}{user}
+  Assume authentication as \var{user}.
+  Allows an authorised administrator to proxy into any user's mailbox.
+\versionadded{2.3}
+\end{methoddesc}
+
+\begin{methoddesc}{read}{size}
+  Reads \var{size} bytes from the remote server.
+  You may override this method.
+\end{methoddesc}
+
+\begin{methoddesc}{readline}{}
+  Reads one line from the remote server.
+  You may override this method.
+\end{methoddesc}
+
+\begin{methoddesc}{recent}{}
+  Prompt server for an update. Returned data is \code{None} if no new
+  messages, else value of \samp{RECENT} response.
+\end{methoddesc}
+
+\begin{methoddesc}{rename}{oldmailbox, newmailbox}
+  Rename mailbox named \var{oldmailbox} to \var{newmailbox}.
+\end{methoddesc}
+
+\begin{methoddesc}{response}{code}
+  Return data for response \var{code} if received, or
+  \code{None}. Returns the given code, instead of the usual type.
+\end{methoddesc}
+
+\begin{methoddesc}{search}{charset, criterion\optional{, ...}}
+  Search mailbox for matching messages.  \var{charset} may be
+  \code{None}, in which case no \samp{CHARSET} will be specified in the
+  request to the server.  The IMAP protocol requires that at least one
+  criterion be specified; an exception will be raised when the server
+  returns an error.
+
+  Example:
+
+\begin{verbatim}
+# M is a connected IMAP4 instance...
+typ, msgnums = M.search(None, 'FROM', '"LDJ"')
+
+# or:
+typ, msgnums = M.search(None, '(FROM "LDJ")')
+\end{verbatim}
+\end{methoddesc}
+
+\begin{methoddesc}{select}{\optional{mailbox\optional{, readonly}}}
+  Select a mailbox. Returned data is the count of messages in
+  \var{mailbox} (\samp{EXISTS} response).  The default \var{mailbox}
+  is \code{'INBOX'}.  If the \var{readonly} flag is set, modifications
+  to the mailbox are not allowed.
+\end{methoddesc}
+
+\begin{methoddesc}{send}{data}
+  Sends \code{data} to the remote server.
+  You may override this method.
+\end{methoddesc}
+
+\begin{methoddesc}{setacl}{mailbox, who, what}
+  Set an \samp{ACL} for \var{mailbox}.
+  The method is non-standard, but is supported by the \samp{Cyrus} server.
+\end{methoddesc}
+
+\begin{methoddesc}{setannotation}{mailbox, entry, attribute\optional{, ...}}
+  Set \samp{ANNOTATION}s for \var{mailbox}.
+  The method is non-standard, but is supported by the \samp{Cyrus} server.
+\versionadded{2.5}
+\end{methoddesc}
+
+\begin{methoddesc}{setquota}{root, limits}
+  Set the \samp{quota} \var{root}'s resource \var{limits}.
+  This method is part of the IMAP4 QUOTA extension defined in rfc2087.
+\versionadded{2.3}
+\end{methoddesc}
+
+\begin{methoddesc}{shutdown}{}
+  Close connection established in \code{open}.
+  You may override this method.
+\end{methoddesc}
+
+\begin{methoddesc}{socket}{}
+  Returns socket instance used to connect to server.
+\end{methoddesc}
+
+\begin{methoddesc}{sort}{sort_criteria, charset, search_criterion\optional{, ...}}
+  The \code{sort} command is a variant of \code{search} with sorting
+  semantics for the results.  Returned data contains a space separated
+  list of matching message numbers.
+
+  Sort has two arguments before the \var{search_criterion}
+  argument(s); a parenthesized list of \var{sort_criteria}, and the
+  searching \var{charset}.  Note that unlike \code{search}, the
+  searching \var{charset} argument is mandatory.  There is also a
+  \code{uid sort} command which corresponds to \code{sort} the way
+  that \code{uid search} corresponds to \code{search}.  The
+  \code{sort} command first searches the mailbox for messages that
+  match the given searching criteria using the charset argument for
+  the interpretation of strings in the searching criteria.  It then
+  returns the numbers of matching messages.
+
+  This is an \samp{IMAP4rev1} extension command.
+\end{methoddesc}
+
+\begin{methoddesc}{status}{mailbox, names}
+  Request named status conditions for \var{mailbox}. 
+\end{methoddesc}
+
+\begin{methoddesc}{store}{message_set, command, flag_list}
+  Alters flag dispositions for messages in mailbox.  \var{command} is
+  specified by section 6.4.6 of \rfc{2060} as being one of "FLAGS", "+FLAGS",
+  or "-FLAGS", optionally with a suffix of ".SILENT".
+
+  For example, to set the delete flag on all messages:
+
+\begin{verbatim}
+typ, data = M.search(None, 'ALL')
+for num in data[0].split():
+   M.store(num, '+FLAGS', '\\Deleted')
+M.expunge()
+\end{verbatim}
+\end{methoddesc}
+
+\begin{methoddesc}{subscribe}{mailbox}
+  Subscribe to new mailbox.
+\end{methoddesc}
+
+\begin{methoddesc}{thread}{threading_algorithm, charset,
+                           search_criterion\optional{, ...}}
+  The \code{thread} command is a variant of \code{search} with
+  threading semantics for the results.  Returned data contains a space
+  separated list of thread members.
+
+  Thread members consist of zero or more messages numbers, delimited
+  by spaces, indicating successive parent and child.
+
+  Thread has two arguments before the \var{search_criterion}
+  argument(s); a \var{threading_algorithm}, and the searching
+  \var{charset}.  Note that unlike \code{search}, the searching
+  \var{charset} argument is mandatory.  There is also a \code{uid
+  thread} command which corresponds to \code{thread} the way that
+  \code{uid search} corresponds to \code{search}.  The \code{thread}
+  command first searches the mailbox for messages that match the given
+  searching criteria using the charset argument for the interpretation
+  of strings in the searching criteria. It then returns the matching
+  messages threaded according to the specified threading algorithm.
+
+  This is an \samp{IMAP4rev1} extension command. \versionadded{2.4}
+\end{methoddesc}
+
+\begin{methoddesc}{uid}{command, arg\optional{, ...}}
+  Execute command args with messages identified by UID, rather than
+  message number.  Returns response appropriate to command.  At least
+  one argument must be supplied; if none are provided, the server will
+  return an error and an exception will be raised.
+\end{methoddesc}
+
+\begin{methoddesc}{unsubscribe}{mailbox}
+  Unsubscribe from old mailbox.
+\end{methoddesc}
+
+\begin{methoddesc}{xatom}{name\optional{, arg\optional{, ...}}}
+  Allow simple extension commands notified by server in
+  \samp{CAPABILITY} response.
+\end{methoddesc}
+
+
+Instances of \class{IMAP4_SSL} have just one additional method:
+
+\begin{methoddesc}{ssl}{}
+  Returns SSLObject instance used for the secure connection with the server.
+\end{methoddesc}
+
+
+The following attributes are defined on instances of \class{IMAP4}:
+
+
+\begin{memberdesc}{PROTOCOL_VERSION}
+The most recent supported protocol in the
+\samp{CAPABILITY} response from the server.
+\end{memberdesc}
+
+\begin{memberdesc}{debug}
+Integer value to control debugging output.  The initialize value is
+taken from the module variable \code{Debug}.  Values greater than
+three trace each command.
+\end{memberdesc}
+
+
+\subsection{IMAP4 Example \label{imap4-example}}
+
+Here is a minimal example (without error checking) that opens a
+mailbox and retrieves and prints all messages:
+
+\begin{verbatim}
+import getpass, imaplib
+
+M = imaplib.IMAP4()
+M.login(getpass.getuser(), getpass.getpass())
+M.select()
+typ, data = M.search(None, 'ALL')
+for num in data[0].split():
+    typ, data = M.fetch(num, '(RFC822)')
+    print 'Message %s\n%s\n' % (num, data[0][1])
+M.close()
+M.logout()
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libimgfile.tex b/sys/src/cmd/python/Doc/lib/libimgfile.tex
new file mode 100644
index 000000000..1aad96557
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libimgfile.tex
@@ -0,0 +1,66 @@
+\section{\module{imgfile} ---
+         Support for SGI imglib files}
+
+\declaremodule{builtin}{imgfile}
+  \platform{IRIX}
+\modulesynopsis{Support for SGI imglib files.}
+
+
+The \module{imgfile} module allows Python programs to access SGI imglib image
+files (also known as \file{.rgb} files).  The module is far from
+complete, but is provided anyway since the functionality that there is
+enough in some cases.  Currently, colormap files are not supported.
+
+The module defines the following variables and functions:
+
+\begin{excdesc}{error}
+This exception is raised on all errors, such as unsupported file type, etc.
+\end{excdesc}
+
+\begin{funcdesc}{getsizes}{file}
+This function returns a tuple \code{(\var{x}, \var{y}, \var{z})} where
+\var{x} and \var{y} are the size of the image in pixels and
+\var{z} is the number of
+bytes per pixel. Only 3 byte RGB pixels and 1 byte greyscale pixels
+are currently supported.
+\end{funcdesc}
+
+\begin{funcdesc}{read}{file}
+This function reads and decodes the image on the specified file, and
+returns it as a Python string. The string has either 1 byte greyscale
+pixels or 4 byte RGBA pixels. The bottom left pixel is the first in
+the string. This format is suitable to pass to \function{gl.lrectwrite()},
+for instance.
+\end{funcdesc}
+
+\begin{funcdesc}{readscaled}{file, x, y, filter\optional{, blur}}
+This function is identical to read but it returns an image that is
+scaled to the given \var{x} and \var{y} sizes. If the \var{filter} and
+\var{blur} parameters are omitted scaling is done by
+simply dropping or duplicating pixels, so the result will be less than
+perfect, especially for computer-generated images.
+
+Alternatively, you can specify a filter to use to smooth the image
+after scaling. The filter forms supported are \code{'impulse'},
+\code{'box'}, \code{'triangle'}, \code{'quadratic'} and
+\code{'gaussian'}. If a filter is specified \var{blur} is an optional
+parameter specifying the blurriness of the filter. It defaults to \code{1.0}.
+
+\function{readscaled()} makes no attempt to keep the aspect ratio
+correct, so that is the users' responsibility.
+\end{funcdesc}
+
+\begin{funcdesc}{ttob}{flag}
+This function sets a global flag which defines whether the scan lines
+of the image are read or written from bottom to top (flag is zero,
+compatible with SGI GL) or from top to bottom(flag is one,
+compatible with X).  The default is zero.
+\end{funcdesc}
+
+\begin{funcdesc}{write}{file, data, x, y, z}
+This function writes the RGB or greyscale data in \var{data} to image
+file \var{file}. \var{x} and \var{y} give the size of the image,
+\var{z} is 1 for 1 byte greyscale images or 3 for RGB images (which are
+stored as 4 byte values of which only the lower three bytes are used).
+These are the formats returned by \function{gl.lrectread()}.
+\end{funcdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libimghdr.tex b/sys/src/cmd/python/Doc/lib/libimghdr.tex
new file mode 100644
index 000000000..4a4f36855
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libimghdr.tex
@@ -0,0 +1,60 @@
+\section{\module{imghdr} ---
+         Determine the type of an image}
+
+\declaremodule{standard}{imghdr}
+\modulesynopsis{Determine the type of image contained in a file or
+                byte stream.}
+
+
+The \module{imghdr} module determines the type of image contained in a
+file or byte stream.
+
+The \module{imghdr} module defines the following function:
+
+
+\begin{funcdesc}{what}{filename\optional{, h}}
+Tests the image data contained in the file named by \var{filename},
+and returns a string describing the image type.  If optional \var{h}
+is provided, the \var{filename} is ignored and \var{h} is assumed to
+contain the byte stream to test.
+\end{funcdesc}
+
+The following image types are recognized, as listed below with the
+return value from \function{what()}:
+
+\begin{tableii}{l|l}{code}{Value}{Image format}
+  \lineii{'rgb'}{SGI ImgLib Files}
+  \lineii{'gif'}{GIF 87a and 89a Files}
+  \lineii{'pbm'}{Portable Bitmap Files}
+  \lineii{'pgm'}{Portable Graymap Files}
+  \lineii{'ppm'}{Portable Pixmap Files}
+  \lineii{'tiff'}{TIFF Files}
+  \lineii{'rast'}{Sun Raster Files}
+  \lineii{'xbm'}{X Bitmap Files}
+  \lineii{'jpeg'}{JPEG data in JFIF or Exif formats}
+  \lineii{'bmp'}{BMP files}
+  \lineii{'png'}{Portable Network Graphics}
+\end{tableii}
+
+\versionadded[Exif detection]{2.5}
+
+You can extend the list of file types \module{imghdr} can recognize by
+appending to this variable:
+
+\begin{datadesc}{tests}
+A list of functions performing the individual tests.  Each function
+takes two arguments: the byte-stream and an open file-like object.
+When \function{what()} is called with a byte-stream, the file-like
+object will be \code{None}.
+
+The test function should return a string describing the image type if
+the test succeeded, or \code{None} if it failed.
+\end{datadesc}
+
+Example:
+
+\begin{verbatim}
+>>> import imghdr
+>>> imghdr.what('/tmp/bass.gif')
+'gif'
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libimp.tex b/sys/src/cmd/python/Doc/lib/libimp.tex
new file mode 100644
index 000000000..598d35182
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libimp.tex
@@ -0,0 +1,291 @@
+\section{\module{imp} ---
+         Access the \keyword{import} internals}
+
+\declaremodule{builtin}{imp}
+\modulesynopsis{Access the implementation of the \keyword{import} statement.}
+
+
+This\stindex{import} module provides an interface to the mechanisms
+used to implement the \keyword{import} statement.  It defines the
+following constants and functions:
+
+
+\begin{funcdesc}{get_magic}{}
+\indexii{file}{byte-code}
+Return the magic string value used to recognize byte-compiled code
+files (\file{.pyc} files).  (This value may be different for each
+Python version.)
+\end{funcdesc}
+
+\begin{funcdesc}{get_suffixes}{}
+Return a list of triples, each describing a particular type of module.
+Each triple has the form \code{(\var{suffix}, \var{mode},
+\var{type})}, where \var{suffix} is a string to be appended to the
+module name to form the filename to search for, \var{mode} is the mode
+string to pass to the built-in \function{open()} function to open the
+file (this can be \code{'r'} for text files or \code{'rb'} for binary
+files), and \var{type} is the file type, which has one of the values
+\constant{PY_SOURCE}, \constant{PY_COMPILED}, or
+\constant{C_EXTENSION}, described below.
+\end{funcdesc}
+
+\begin{funcdesc}{find_module}{name\optional{, path}}
+Try to find the module \var{name} on the search path \var{path}.  If
+\var{path} is a list of directory names, each directory is searched
+for files with any of the suffixes returned by \function{get_suffixes()}
+above.  Invalid names in the list are silently ignored (but all list
+items must be strings).  If \var{path} is omitted or \code{None}, the
+list of directory names given by \code{sys.path} is searched, but
+first it searches a few special places: it tries to find a built-in
+module with the given name (\constant{C_BUILTIN}), then a frozen module
+(\constant{PY_FROZEN}), and on some systems some other places are looked
+in as well (on the Mac, it looks for a resource (\constant{PY_RESOURCE});
+on Windows, it looks in the registry which may point to a specific
+file).
+
+If search is successful, the return value is a triple
+\code{(\var{file}, \var{pathname}, \var{description})} where
+\var{file} is an open file object positioned at the beginning,
+\var{pathname} is the pathname of the
+file found, and \var{description} is a triple as contained in the list
+returned by \function{get_suffixes()} describing the kind of module found.
+If the module does not live in a file, the returned \var{file} is
+\code{None}, \var{filename} is the empty string, and the
+\var{description} tuple contains empty strings for its suffix and
+mode; the module type is as indicate in parentheses above.  If the
+search is unsuccessful, \exception{ImportError} is raised.  Other
+exceptions indicate problems with the arguments or environment.
+
+This function does not handle hierarchical module names (names
+containing dots).  In order to find \var{P}.\var{M}, that is, submodule
+\var{M} of package \var{P}, use \function{find_module()} and
+\function{load_module()} to find and load package \var{P}, and then use
+\function{find_module()} with the \var{path} argument set to
+\code{\var{P}.__path__}.  When \var{P} itself has a dotted name, apply
+this recipe recursively.
+\end{funcdesc}
+
+\begin{funcdesc}{load_module}{name, file, filename, description}
+Load a module that was previously found by \function{find_module()} (or by
+an otherwise conducted search yielding compatible results).  This
+function does more than importing the module: if the module was
+already imported, it is equivalent to a
+\function{reload()}\bifuncindex{reload}!  The \var{name} argument
+indicates the full module name (including the package name, if this is
+a submodule of a package).  The \var{file} argument is an open file,
+and \var{filename} is the corresponding file name; these can be
+\code{None} and \code{''}, respectively, when the module is not being
+loaded from a file.  The \var{description} argument is a tuple, as
+would be returned by \function{get_suffixes()}, describing what kind
+of module must be loaded.
+
+If the load is successful, the return value is the module object;
+otherwise, an exception (usually \exception{ImportError}) is raised.
+
+\strong{Important:} the caller is responsible for closing the
+\var{file} argument, if it was not \code{None}, even when an exception
+is raised.  This is best done using a \keyword{try}
+... \keyword{finally} statement.
+\end{funcdesc}
+
+\begin{funcdesc}{new_module}{name}
+Return a new empty module object called \var{name}.  This object is
+\emph{not} inserted in \code{sys.modules}.
+\end{funcdesc}
+
+\begin{funcdesc}{lock_held}{}
+Return \code{True} if the import lock is currently held, else \code{False}.
+On platforms without threads, always return \code{False}.
+
+On platforms with threads, a thread executing an import holds an internal
+lock until the import is complete.
+This lock blocks other threads from doing an import until the original
+import completes, which in turn prevents other threads from seeing
+incomplete module objects constructed by the original thread while in
+the process of completing its import (and the imports, if any,
+triggered by that).
+\end{funcdesc}
+
+\begin{funcdesc}{acquire_lock}{}
+Acquires the interpreter's import lock for the current thread.  This lock
+should be used by import hooks to ensure thread-safety when importing modules.
+On platforms without threads, this function does nothing.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{release_lock}{}
+Release the interpreter's import lock.
+On platforms without threads, this function does nothing.
+\versionadded{2.3}
+\end{funcdesc}
+
+The following constants with integer values, defined in this module,
+are used to indicate the search result of \function{find_module()}.
+
+\begin{datadesc}{PY_SOURCE}
+The module was found as a source file.
+\end{datadesc}
+
+\begin{datadesc}{PY_COMPILED}
+The module was found as a compiled code object file.
+\end{datadesc}
+
+\begin{datadesc}{C_EXTENSION}
+The module was found as dynamically loadable shared library.
+\end{datadesc}
+
+\begin{datadesc}{PY_RESOURCE}
+The module was found as a Mac OS 9 resource.  This value can only be
+returned on a Mac OS 9 or earlier Macintosh.
+\end{datadesc}
+
+\begin{datadesc}{PKG_DIRECTORY}
+The module was found as a package directory.
+\end{datadesc}
+
+\begin{datadesc}{C_BUILTIN}
+The module was found as a built-in module.
+\end{datadesc}
+
+\begin{datadesc}{PY_FROZEN}
+The module was found as a frozen module (see \function{init_frozen()}).
+\end{datadesc}
+
+The following constant and functions are obsolete; their functionality
+is available through \function{find_module()} or \function{load_module()}.
+They are kept around for backward compatibility:
+
+\begin{datadesc}{SEARCH_ERROR}
+Unused.
+\end{datadesc}
+
+\begin{funcdesc}{init_builtin}{name}
+Initialize the built-in module called \var{name} and return its module
+object.  If the module was already initialized, it will be initialized
+\emph{again}.  A few modules cannot be initialized twice --- attempting
+to initialize these again will raise an \exception{ImportError}
+exception.  If there is no
+built-in module called \var{name}, \code{None} is returned.
+\end{funcdesc}
+
+\begin{funcdesc}{init_frozen}{name}
+Initialize the frozen module called \var{name} and return its module
+object.  If the module was already initialized, it will be initialized
+\emph{again}.  If there is no frozen module called \var{name},
+\code{None} is returned.  (Frozen modules are modules written in
+Python whose compiled byte-code object is incorporated into a
+custom-built Python interpreter by Python's \program{freeze} utility.
+See \file{Tools/freeze/} for now.)
+\end{funcdesc}
+
+\begin{funcdesc}{is_builtin}{name}
+Return \code{1} if there is a built-in module called \var{name} which
+can be initialized again.  Return \code{-1} if there is a built-in
+module called \var{name} which cannot be initialized again (see
+\function{init_builtin()}).  Return \code{0} if there is no built-in
+module called \var{name}.
+\end{funcdesc}
+
+\begin{funcdesc}{is_frozen}{name}
+Return \code{True} if there is a frozen module (see
+\function{init_frozen()}) called \var{name}, or \code{False} if there is
+no such module.
+\end{funcdesc}
+
+\begin{funcdesc}{load_compiled}{name, pathname, \optional{file}}
+\indexii{file}{byte-code}
+Load and initialize a module implemented as a byte-compiled code file
+and return its module object.  If the module was already initialized,
+it will be initialized \emph{again}.  The \var{name} argument is used
+to create or access a module object.  The \var{pathname} argument
+points to the byte-compiled code file.  The \var{file}
+argument is the byte-compiled code file, open for reading in binary
+mode, from the beginning.
+It must currently be a real file object, not a
+user-defined class emulating a file.
+\end{funcdesc}
+
+\begin{funcdesc}{load_dynamic}{name, pathname\optional{, file}}
+Load and initialize a module implemented as a dynamically loadable
+shared library and return its module object.  If the module was
+already initialized, it will be initialized \emph{again}.  Some modules
+don't like that and may raise an exception.  The \var{pathname}
+argument must point to the shared library.  The \var{name} argument is
+used to construct the name of the initialization function: an external
+C function called \samp{init\var{name}()} in the shared library is
+called.  The optional \var{file} argument is ignored.  (Note: using
+shared libraries is highly system dependent, and not all systems
+support it.)
+\end{funcdesc}
+
+\begin{funcdesc}{load_source}{name, pathname\optional{, file}}
+Load and initialize a module implemented as a Python source file and
+return its module object.  If the module was already initialized, it
+will be initialized \emph{again}.  The \var{name} argument is used to
+create or access a module object.  The \var{pathname} argument points
+to the source file.  The \var{file} argument is the source
+file, open for reading as text, from the beginning.
+It must currently be a real file
+object, not a user-defined class emulating a file.  Note that if a
+properly matching byte-compiled file (with suffix \file{.pyc} or
+\file{.pyo}) exists, it will be used instead of parsing the given
+source file.
+\end{funcdesc}
+
+\begin{classdesc}{NullImporter}{path_string}
+The \class{NullImporter} type is a \pep{302} import hook that handles
+non-directory path strings by failing to find any modules.  Calling this
+type with an existing directory or empty string raises
+\exception{ImportError}.  Otherwise, a \class{NullImporter} instance is
+returned.
+
+Python adds instances of this type to \code{sys.path_importer_cache} for
+any path entries that are not directories and are not handled by any other
+path hooks on \code{sys.path_hooks}.  Instances have only one method:
+
+\begin{methoddesc}{find_module}{fullname \optional{, path}}
+This method always returns \code{None}, indicating that the requested
+module could not be found.
+\end{methoddesc}
+
+\versionadded{2.5}
+\end{classdesc}
+
+\subsection{Examples}
+\label{examples-imp}
+
+The following function emulates what was the standard import statement
+up to Python 1.4 (no hierarchical module names).  (This
+\emph{implementation} wouldn't work in that version, since
+\function{find_module()} has been extended and
+\function{load_module()} has been added in 1.4.)
+
+\begin{verbatim}
+import imp
+import sys
+
+def __import__(name, globals=None, locals=None, fromlist=None):
+    # Fast path: see if the module has already been imported.
+    try:
+        return sys.modules[name]
+    except KeyError:
+        pass
+
+    # If any of the following calls raises an exception,
+    # there's a problem we can't handle -- let the caller handle it.
+
+    fp, pathname, description = imp.find_module(name)
+
+    try:
+        return imp.load_module(name, fp, pathname, description)
+    finally:
+        # Since we may exit via an exception, close fp explicitly.
+        if fp:
+            fp.close()
+\end{verbatim}
+
+A more complete example that implements hierarchical module names and
+includes a \function{reload()}\bifuncindex{reload} function can be
+found in the module \module{knee}\refmodindex{knee}.  The
+\module{knee} module can be found in \file{Demo/imputil/} in the
+Python source distribution.
diff --git a/sys/src/cmd/python/Doc/lib/libinspect.tex b/sys/src/cmd/python/Doc/lib/libinspect.tex
new file mode 100644
index 000000000..85651f060
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libinspect.tex
@@ -0,0 +1,393 @@
+\section{\module{inspect} ---
+         Inspect live objects}
+
+\declaremodule{standard}{inspect}
+\modulesynopsis{Extract information and source code from live objects.}
+\moduleauthor{Ka-Ping Yee}{ping@lfw.org}
+\sectionauthor{Ka-Ping Yee}{ping@lfw.org}
+
+\versionadded{2.1}
+
+The \module{inspect} module provides several useful functions
+to help get information about live objects such as modules,
+classes, methods, functions, tracebacks, frame objects, and
+code objects.  For example, it can help you examine the
+contents of a class, retrieve the source code of a method,
+extract and format the argument list for a function, or
+get all the information you need to display a detailed traceback.
+
+There are four main kinds of services provided by this module:
+type checking, getting source code, inspecting classes
+and functions, and examining the interpreter stack.
+
+\subsection{Types and members
+            \label{inspect-types}}
+
+The \function{getmembers()} function retrieves the members
+of an object such as a class or module.
+The eleven functions whose names begin with ``is'' are mainly
+provided as convenient choices for the second argument to
+\function{getmembers()}.  They also help you determine when
+you can expect to find the following special attributes:
+
+\begin{tableiv}{c|l|l|c}{}{Type}{Attribute}{Description}{Notes}
+  \lineiv{module}{__doc__}{documentation string}{}
+  \lineiv{}{__file__}{filename (missing for built-in modules)}{}
+  \hline
+  \lineiv{class}{__doc__}{documentation string}{}
+  \lineiv{}{__module__}{name of module in which this class was defined}{}
+  \hline
+  \lineiv{method}{__doc__}{documentation string}{}
+  \lineiv{}{__name__}{name with which this method was defined}{}
+  \lineiv{}{im_class}{class object that asked for this method}{(1)}
+  \lineiv{}{im_func}{function object containing implementation of method}{}
+  \lineiv{}{im_self}{instance to which this method is bound, or \code{None}}{}
+  \hline
+  \lineiv{function}{__doc__}{documentation string}{}
+  \lineiv{}{__name__}{name with which this function was defined}{}
+  \lineiv{}{func_code}{code object containing compiled function bytecode}{}
+  \lineiv{}{func_defaults}{tuple of any default values for arguments}{}
+  \lineiv{}{func_doc}{(same as __doc__)}{}
+  \lineiv{}{func_globals}{global namespace in which this function was defined}{}
+  \lineiv{}{func_name}{(same as __name__)}{}
+  \hline
+  \lineiv{traceback}{tb_frame}{frame object at this level}{}
+  \lineiv{}{tb_lasti}{index of last attempted instruction in bytecode}{}
+  \lineiv{}{tb_lineno}{current line number in Python source code}{}
+  \lineiv{}{tb_next}{next inner traceback object (called by this level)}{}
+  \hline
+  \lineiv{frame}{f_back}{next outer frame object (this frame's caller)}{}
+  \lineiv{}{f_builtins}{built-in namespace seen by this frame}{}
+  \lineiv{}{f_code}{code object being executed in this frame}{}
+  \lineiv{}{f_exc_traceback}{traceback if raised in this frame, or \code{None}}{}
+  \lineiv{}{f_exc_type}{exception type if raised in this frame, or \code{None}}{}
+  \lineiv{}{f_exc_value}{exception value if raised in this frame, or \code{None}}{}
+  \lineiv{}{f_globals}{global namespace seen by this frame}{}
+  \lineiv{}{f_lasti}{index of last attempted instruction in bytecode}{}
+  \lineiv{}{f_lineno}{current line number in Python source code}{}
+  \lineiv{}{f_locals}{local namespace seen by this frame}{}
+  \lineiv{}{f_restricted}{0 or 1 if frame is in restricted execution mode}{}
+  \lineiv{}{f_trace}{tracing function for this frame, or \code{None}}{}
+  \hline
+  \lineiv{code}{co_argcount}{number of arguments (not including * or ** args)}{}
+  \lineiv{}{co_code}{string of raw compiled bytecode}{}
+  \lineiv{}{co_consts}{tuple of constants used in the bytecode}{}
+  \lineiv{}{co_filename}{name of file in which this code object was created}{}
+  \lineiv{}{co_firstlineno}{number of first line in Python source code}{}
+  \lineiv{}{co_flags}{bitmap: 1=optimized \code{|} 2=newlocals \code{|} 4=*arg \code{|} 8=**arg}{}
+  \lineiv{}{co_lnotab}{encoded mapping of line numbers to bytecode indices}{}
+  \lineiv{}{co_name}{name with which this code object was defined}{}
+  \lineiv{}{co_names}{tuple of names of local variables}{}
+  \lineiv{}{co_nlocals}{number of local variables}{}
+  \lineiv{}{co_stacksize}{virtual machine stack space required}{}
+  \lineiv{}{co_varnames}{tuple of names of arguments and local variables}{}
+  \hline
+  \lineiv{builtin}{__doc__}{documentation string}{}
+  \lineiv{}{__name__}{original name of this function or method}{}
+  \lineiv{}{__self__}{instance to which a method is bound, or \code{None}}{}
+\end{tableiv}
+
+\noindent
+Note:
+\begin{description}
+\item[(1)]
+\versionchanged[\member{im_class} used to refer to the class that
+                defined the method]{2.2}
+\end{description}
+
+
+\begin{funcdesc}{getmembers}{object\optional{, predicate}}
+  Return all the members of an object in a list of (name, value) pairs
+  sorted by name.  If the optional \var{predicate} argument is supplied,
+  only members for which the predicate returns a true value are included.
+\end{funcdesc}
+
+\begin{funcdesc}{getmoduleinfo}{path}
+  Return a tuple of values that describe how Python will interpret the
+  file identified by \var{path} if it is a module, or \code{None} if
+  it would not be identified as a module.  The return tuple is
+  \code{(\var{name}, \var{suffix}, \var{mode}, \var{mtype})}, where
+  \var{name} is the name of the module without the name of any
+  enclosing package, \var{suffix} is the trailing part of the file
+  name (which may not be a dot-delimited extension), \var{mode} is the
+  \function{open()} mode that would be used (\code{'r'} or
+  \code{'rb'}), and \var{mtype} is an integer giving the type of the
+  module.  \var{mtype} will have a value which can be compared to the
+  constants defined in the \refmodule{imp} module; see the
+  documentation for that module for more information on module types.
+\end{funcdesc}
+
+\begin{funcdesc}{getmodulename}{path}
+  Return the name of the module named by the file \var{path}, without
+  including the names of enclosing packages.  This uses the same
+  algorithm as the interpreter uses when searching for modules.  If
+  the name cannot be matched according to the interpreter's rules,
+  \code{None} is returned.
+\end{funcdesc}
+
+\begin{funcdesc}{ismodule}{object}
+  Return true if the object is a module.
+\end{funcdesc}
+
+\begin{funcdesc}{isclass}{object}
+  Return true if the object is a class.
+\end{funcdesc}
+
+\begin{funcdesc}{ismethod}{object}
+  Return true if the object is a method.
+\end{funcdesc}
+
+\begin{funcdesc}{isfunction}{object}
+  Return true if the object is a Python function or unnamed (lambda) function.
+\end{funcdesc}
+
+\begin{funcdesc}{istraceback}{object}
+  Return true if the object is a traceback.
+\end{funcdesc}
+
+\begin{funcdesc}{isframe}{object}
+  Return true if the object is a frame.
+\end{funcdesc}
+
+\begin{funcdesc}{iscode}{object}
+  Return true if the object is a code.
+\end{funcdesc}
+
+\begin{funcdesc}{isbuiltin}{object}
+  Return true if the object is a built-in function.
+\end{funcdesc}
+
+\begin{funcdesc}{isroutine}{object}
+  Return true if the object is a user-defined or built-in function or method.
+\end{funcdesc}
+
+\begin{funcdesc}{ismethoddescriptor}{object}
+  Return true if the object is a method descriptor, but not if ismethod() or 
+  isclass() or isfunction() are true.
+
+  This is new as of Python 2.2, and, for example, is true of int.__add__.
+  An object passing this test has a __get__ attribute but not a __set__
+  attribute, but beyond that the set of attributes varies.  __name__ is
+  usually sensible, and __doc__ often is.
+
+  Methods implemented via descriptors that also pass one of the other
+  tests return false from the ismethoddescriptor() test, simply because
+  the other tests promise more -- you can, e.g., count on having the
+  im_func attribute (etc) when an object passes ismethod().
+\end{funcdesc}
+
+\begin{funcdesc}{isdatadescriptor}{object}
+  Return true if the object is a data descriptor.
+
+  Data descriptors have both a __get__ and a __set__ attribute.  Examples are
+  properties (defined in Python), getsets, and members.  The latter two are
+  defined in C and there are more specific tests available for those types,
+  which is robust across Python implementations.  Typically, data descriptors
+  will also have __name__ and __doc__ attributes (properties, getsets, and
+  members have both of these attributes), but this is not guaranteed.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{isgetsetdescriptor}{object}
+  Return true if the object is a getset descriptor.
+
+  getsets are attributes defined in extension modules via \code{PyGetSetDef}
+  structures.  For Python implementations without such types, this method will
+  always return \code{False}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{ismemberdescriptor}{object}
+  Return true if the object is a member descriptor.
+
+  Member descriptors are attributes defined in extension modules via
+  \code{PyMemberDef} structures.  For Python implementations without such
+  types, this method will always return \code{False}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\subsection{Retrieving source code
+            \label{inspect-source}}
+
+\begin{funcdesc}{getdoc}{object}
+  Get the documentation string for an object.
+  All tabs are expanded to spaces.  To clean up docstrings that are
+  indented to line up with blocks of code, any whitespace than can be
+  uniformly removed from the second line onwards is removed.
+\end{funcdesc}
+
+\begin{funcdesc}{getcomments}{object}
+  Return in a single string any lines of comments immediately preceding
+  the object's source code (for a class, function, or method), or at the
+  top of the Python source file (if the object is a module).
+\end{funcdesc}
+
+\begin{funcdesc}{getfile}{object}
+  Return the name of the (text or binary) file in which an object was
+  defined.  This will fail with a \exception{TypeError} if the object
+  is a built-in module, class, or function.
+\end{funcdesc}
+
+\begin{funcdesc}{getmodule}{object}
+  Try to guess which module an object was defined in.
+\end{funcdesc}
+
+\begin{funcdesc}{getsourcefile}{object}
+  Return the name of the Python source file in which an object was
+  defined.  This will fail with a \exception{TypeError} if the object
+  is a built-in module, class, or function.
+\end{funcdesc}
+
+\begin{funcdesc}{getsourcelines}{object}
+  Return a list of source lines and starting line number for an object.
+  The argument may be a module, class, method, function, traceback, frame,
+  or code object.  The source code is returned as a list of the lines
+  corresponding to the object and the line number indicates where in the
+  original source file the first line of code was found.  An
+  \exception{IOError} is raised if the source code cannot be retrieved.
+\end{funcdesc}
+
+\begin{funcdesc}{getsource}{object}
+  Return the text of the source code for an object.
+  The argument may be a module, class, method, function, traceback, frame,
+  or code object.  The source code is returned as a single string.  An
+  \exception{IOError} is raised if the source code cannot be retrieved.
+\end{funcdesc}
+
+\subsection{Classes and functions
+            \label{inspect-classes-functions}}
+
+\begin{funcdesc}{getclasstree}{classes\optional{, unique}}
+  Arrange the given list of classes into a hierarchy of nested lists.
+  Where a nested list appears, it contains classes derived from the class
+  whose entry immediately precedes the list.  Each entry is a 2-tuple
+  containing a class and a tuple of its base classes.  If the \var{unique}
+  argument is true, exactly one entry appears in the returned structure
+  for each class in the given list.  Otherwise, classes using multiple
+  inheritance and their descendants will appear multiple times.
+\end{funcdesc}
+
+\begin{funcdesc}{getargspec}{func}
+  Get the names and default values of a function's arguments.
+  A tuple of four things is returned: \code{(\var{args},
+    \var{varargs}, \var{varkw}, \var{defaults})}.
+  \var{args} is a list of the argument names (it may contain nested lists).
+  \var{varargs} and \var{varkw} are the names of the \code{*} and
+  \code{**} arguments or \code{None}.
+  \var{defaults} is a tuple of default argument values or None if there are no
+  default arguments; if this tuple has \var{n} elements, they correspond to
+  the last \var{n} elements listed in \var{args}.
+\end{funcdesc}
+
+\begin{funcdesc}{getargvalues}{frame}
+  Get information about arguments passed into a particular frame.
+  A tuple of four things is returned: \code{(\var{args},
+    \var{varargs}, \var{varkw}, \var{locals})}.
+  \var{args} is a list of the argument names (it may contain nested
+  lists).
+  \var{varargs} and \var{varkw} are the names of the \code{*} and
+  \code{**} arguments or \code{None}.
+  \var{locals} is the locals dictionary of the given frame.
+\end{funcdesc}
+
+\begin{funcdesc}{formatargspec}{args\optional{, varargs, varkw, defaults,
+      formatarg, formatvarargs, formatvarkw, formatvalue, join}}
+
+  Format a pretty argument spec from the four values returned by
+  \function{getargspec()}.  The format* arguments are the
+  corresponding optional formatting functions that are called to turn
+  names and values into strings.
+\end{funcdesc}
+
+\begin{funcdesc}{formatargvalues}{args\optional{, varargs, varkw, locals,
+      formatarg, formatvarargs, formatvarkw, formatvalue, join}}
+  Format a pretty argument spec from the four values returned by
+  \function{getargvalues()}.  The format* arguments are the
+  corresponding optional formatting functions that are called to turn
+  names and values into strings.
+\end{funcdesc}
+
+\begin{funcdesc}{getmro}{cls}
+  Return a tuple of class cls's base classes, including cls, in
+  method resolution order.  No class appears more than once in this tuple.
+  Note that the method resolution order depends on cls's type.  Unless a
+  very peculiar user-defined metatype is in use, cls will be the first
+  element of the tuple.
+\end{funcdesc}
+
+\subsection{The interpreter stack
+            \label{inspect-stack}}
+
+When the following functions return ``frame records,'' each record
+is a tuple of six items: the frame object, the filename,
+the line number of the current line, the function name, a list of
+lines of context from the source code, and the index of the current
+line within that list.
+
+\begin{notice}[warning]
+Keeping references to frame objects, as found in
+the first element of the frame records these functions return, can
+cause your program to create reference cycles.  Once a reference cycle
+has been created, the lifespan of all objects which can be accessed
+from the objects which form the cycle can become much longer even if
+Python's optional cycle detector is enabled.  If such cycles must be
+created, it is important to ensure they are explicitly broken to avoid
+the delayed destruction of objects and increased memory consumption
+which occurs.
+
+Though the cycle detector will catch these, destruction of the frames
+(and local variables) can be made deterministic by removing the cycle
+in a \keyword{finally} clause.  This is also important if the cycle
+detector was disabled when Python was compiled or using
+\function{\refmodule{gc}.disable()}.  For example:
+
+\begin{verbatim}
+def handle_stackframe_without_leak():
+    frame = inspect.currentframe()
+    try:
+        # do something with the frame
+    finally:
+        del frame
+\end{verbatim}
+\end{notice}
+
+The optional \var{context} argument supported by most of these
+functions specifies the number of lines of context to return, which
+are centered around the current line.
+
+\begin{funcdesc}{getframeinfo}{frame\optional{, context}}
+  Get information about a frame or traceback object.  A 5-tuple
+  is returned, the last five elements of the frame's frame record.
+\end{funcdesc}
+
+\begin{funcdesc}{getouterframes}{frame\optional{, context}}
+  Get a list of frame records for a frame and all outer frames.  These
+  frames represent the calls that lead to the creation of \var{frame}.
+  The first entry in the returned list represents \var{frame}; the
+  last entry represents the outermost call on \var{frame}'s stack.
+\end{funcdesc}
+
+\begin{funcdesc}{getinnerframes}{traceback\optional{, context}}
+  Get a list of frame records for a traceback's frame and all inner
+  frames.  These frames represent calls made as a consequence of
+  \var{frame}.  The first entry in the list represents
+  \var{traceback}; the last entry represents where the exception was
+  raised.
+\end{funcdesc}
+
+\begin{funcdesc}{currentframe}{}
+  Return the frame object for the caller's stack frame.
+\end{funcdesc}
+
+\begin{funcdesc}{stack}{\optional{context}}
+  Return a list of frame records for the caller's stack.  The first
+  entry in the returned list represents the caller; the last entry
+  represents the outermost call on the stack.
+\end{funcdesc}
+
+\begin{funcdesc}{trace}{\optional{context}}
+  Return a list of frame records for the stack between the current
+  frame and the frame in which an exception currently being handled
+  was raised in.  The first entry in the list represents the caller;
+  the last entry represents where the exception was raised.
+\end{funcdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libintro.tex b/sys/src/cmd/python/Doc/lib/libintro.tex
new file mode 100644
index 000000000..62434cd6b
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libintro.tex
@@ -0,0 +1,53 @@
+\chapter{Introduction}
+\label{intro}
+
+The ``Python library'' contains several different kinds of components.
+
+It contains data types that would normally be considered part of the
+``core'' of a language, such as numbers and lists.  For these types,
+the Python language core defines the form of literals and places some
+constraints on their semantics, but does not fully define the
+semantics.  (On the other hand, the language core does define
+syntactic properties like the spelling and priorities of operators.)
+
+The library also contains built-in functions and exceptions ---
+objects that can be used by all Python code without the need of an
+\keyword{import} statement.  Some of these are defined by the core
+language, but many are not essential for the core semantics and are
+only described here.
+
+The bulk of the library, however, consists of a collection of modules.
+There are many ways to dissect this collection.  Some modules are
+written in C and built in to the Python interpreter; others are
+written in Python and imported in source form.  Some modules provide
+interfaces that are highly specific to Python, like printing a stack
+trace; some provide interfaces that are specific to particular
+operating systems, such as access to specific hardware; others provide
+interfaces that are
+specific to a particular application domain, like the World Wide Web.
+Some modules are available in all versions and ports of Python; others
+are only available when the underlying system supports or requires
+them; yet others are available only when a particular configuration
+option was chosen at the time when Python was compiled and installed.
+
+This manual is organized ``from the inside out:'' it first describes
+the built-in data types, then the built-in functions and exceptions,
+and finally the modules, grouped in chapters of related modules.  The
+ordering of the chapters as well as the ordering of the modules within
+each chapter is roughly from most relevant to least important.
+
+This means that if you start reading this manual from the start, and
+skip to the next chapter when you get bored, you will get a reasonable
+overview of the available modules and application areas that are
+supported by the Python library.  Of course, you don't \emph{have} to
+read it like a novel --- you can also browse the table of contents (in
+front of the manual), or look for a specific function, module or term
+in the index (in the back).  And finally, if you enjoy learning about
+random subjects, you choose a random page number (see module
+\refmodule{random}) and read a section or two.  Regardless of the
+order in which you read the sections of this manual, it helps to start 
+with chapter \ref{builtin}, ``Built-in Types, Exceptions and
+Functions,'' as the remainder of the manual assumes familiarity with
+this material.
+
+Let the show begin!
diff --git a/sys/src/cmd/python/Doc/lib/libitertools.tex b/sys/src/cmd/python/Doc/lib/libitertools.tex
new file mode 100644
index 000000000..f39cde6f0
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libitertools.tex
@@ -0,0 +1,546 @@
+\section{\module{itertools} ---
+         Functions creating iterators for efficient looping}
+
+\declaremodule{standard}{itertools}
+\modulesynopsis{Functions creating iterators for efficient looping.}
+\moduleauthor{Raymond Hettinger}{python@rcn.com}
+\sectionauthor{Raymond Hettinger}{python@rcn.com}
+\versionadded{2.3}
+
+
+This module implements a number of iterator building blocks inspired
+by constructs from the Haskell and SML programming languages.  Each
+has been recast in a form suitable for Python.
+
+The module standardizes a core set of fast, memory efficient tools
+that are useful by themselves or in combination.  Standardization helps
+avoid the readability and reliability problems which arise when many
+different individuals create their own slightly varying implementations,
+each with their own quirks and naming conventions.
+
+The tools are designed to combine readily with one another.  This makes
+it easy to construct more specialized tools succinctly and efficiently
+in pure Python.
+
+For instance, SML provides a tabulation tool: \code{tabulate(f)}
+which produces a sequence \code{f(0), f(1), ...}.  This toolbox
+provides \function{imap()} and \function{count()} which can be combined
+to form \code{imap(f, count())} and produce an equivalent result.
+
+Likewise, the functional tools are designed to work well with the
+high-speed functions provided by the \refmodule{operator} module.
+
+The module author welcomes suggestions for other basic building blocks
+to be added to future versions of the module.
+
+Whether cast in pure python form or compiled code, tools that use iterators
+are more memory efficient (and faster) than their list based counterparts.
+Adopting the principles of just-in-time manufacturing, they create
+data when and where needed instead of consuming memory with the
+computer equivalent of ``inventory''.
+
+The performance advantage of iterators becomes more acute as the number
+of elements increases -- at some point, lists grow large enough to
+severely impact memory cache performance and start running slowly.
+
+\begin{seealso}
+  \seetext{The Standard ML Basis Library,
+           \citetitle[http://www.standardml.org/Basis/]
+           {The Standard ML Basis Library}.}
+
+  \seetext{Haskell, A Purely Functional Language,
+           \citetitle[http://www.haskell.org/definition/]
+           {Definition of Haskell and the Standard Libraries}.}
+\end{seealso}
+
+
+\subsection{Itertool functions \label{itertools-functions}}
+
+The following module functions all construct and return iterators.
+Some provide streams of infinite length, so they should only be accessed
+by functions or loops that truncate the stream.
+
+\begin{funcdesc}{chain}{*iterables}
+  Make an iterator that returns elements from the first iterable until
+  it is exhausted, then proceeds to the next iterable, until all of the
+  iterables are exhausted.  Used for treating consecutive sequences as
+  a single sequence.  Equivalent to:
+
+  \begin{verbatim}
+     def chain(*iterables):
+         for it in iterables:
+             for element in it:
+                 yield element
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{count}{\optional{n}}
+  Make an iterator that returns consecutive integers starting with \var{n}.
+  If not specified \var{n} defaults to zero.  
+  Does not currently support python long integers.  Often used as an
+  argument to \function{imap()} to generate consecutive data points.
+  Also, used with \function{izip()} to add sequence numbers.  Equivalent to:
+
+  \begin{verbatim}
+     def count(n=0):
+         while True:
+             yield n
+             n += 1
+  \end{verbatim}
+
+  Note, \function{count()} does not check for overflow and will return
+  negative numbers after exceeding \code{sys.maxint}.  This behavior
+  may change in the future.
+\end{funcdesc}
+
+\begin{funcdesc}{cycle}{iterable}
+  Make an iterator returning elements from the iterable and saving a
+  copy of each.  When the iterable is exhausted, return elements from
+  the saved copy.  Repeats indefinitely.  Equivalent to:
+
+  \begin{verbatim}
+     def cycle(iterable):
+         saved = []
+         for element in iterable:
+             yield element
+             saved.append(element)
+         while saved:
+             for element in saved:
+                   yield element
+  \end{verbatim}
+
+  Note, this member of the toolkit may require significant
+  auxiliary storage (depending on the length of the iterable).
+\end{funcdesc}
+
+\begin{funcdesc}{dropwhile}{predicate, iterable}
+  Make an iterator that drops elements from the iterable as long as
+  the predicate is true; afterwards, returns every element.  Note,
+  the iterator does not produce \emph{any} output until the predicate
+  is true, so it may have a lengthy start-up time.  Equivalent to:
+
+  \begin{verbatim}
+     def dropwhile(predicate, iterable):
+         iterable = iter(iterable)
+         for x in iterable:
+             if not predicate(x):
+                 yield x
+                 break
+         for x in iterable:
+             yield x
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{groupby}{iterable\optional{, key}}
+  Make an iterator that returns consecutive keys and groups from the
+  \var{iterable}. The \var{key} is a function computing a key value for each
+  element.  If not specified or is \code{None}, \var{key} defaults to an
+  identity function and returns  the element unchanged.  Generally, the
+  iterable needs to already be sorted on the same key function.
+
+  The returned group is itself an iterator that shares the underlying
+  iterable with \function{groupby()}.  Because the source is shared, when
+  the \function{groupby} object is advanced, the previous group is no
+  longer visible.  So, if that data is needed later, it should be stored
+  as a list:
+
+  \begin{verbatim}
+    groups = []
+    uniquekeys = []
+    for k, g in groupby(data, keyfunc):
+        groups.append(list(g))      # Store group iterator as a list
+        uniquekeys.append(k)
+  \end{verbatim}
+
+  \function{groupby()} is equivalent to:
+
+  \begin{verbatim}
+    class groupby(object):
+        def __init__(self, iterable, key=None):
+            if key is None:
+                key = lambda x: x
+            self.keyfunc = key
+            self.it = iter(iterable)
+            self.tgtkey = self.currkey = self.currvalue = xrange(0)
+        def __iter__(self):
+            return self
+        def next(self):
+            while self.currkey == self.tgtkey:
+                self.currvalue = self.it.next() # Exit on StopIteration
+                self.currkey = self.keyfunc(self.currvalue)
+            self.tgtkey = self.currkey
+            return (self.currkey, self._grouper(self.tgtkey))
+        def _grouper(self, tgtkey):
+            while self.currkey == tgtkey:
+                yield self.currvalue
+                self.currvalue = self.it.next() # Exit on StopIteration
+                self.currkey = self.keyfunc(self.currvalue)
+  \end{verbatim}
+  \versionadded{2.4}
+\end{funcdesc}
+
+\begin{funcdesc}{ifilter}{predicate, iterable}
+  Make an iterator that filters elements from iterable returning only
+  those for which the predicate is \code{True}.
+  If \var{predicate} is \code{None}, return the items that are true.
+  Equivalent to:
+
+  \begin{verbatim}
+     def ifilter(predicate, iterable):
+         if predicate is None:
+             predicate = bool
+         for x in iterable:
+             if predicate(x):
+                 yield x
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{ifilterfalse}{predicate, iterable}
+  Make an iterator that filters elements from iterable returning only
+  those for which the predicate is \code{False}.
+  If \var{predicate} is \code{None}, return the items that are false.
+  Equivalent to:
+
+  \begin{verbatim}
+     def ifilterfalse(predicate, iterable):
+         if predicate is None:
+             predicate = bool
+         for x in iterable:
+             if not predicate(x):
+                 yield x
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{imap}{function, *iterables}
+  Make an iterator that computes the function using arguments from
+  each of the iterables.  If \var{function} is set to \code{None}, then
+  \function{imap()} returns the arguments as a tuple.  Like
+  \function{map()} but stops when the shortest iterable is exhausted
+  instead of filling in \code{None} for shorter iterables.  The reason
+  for the difference is that infinite iterator arguments are typically
+  an error for \function{map()} (because the output is fully evaluated)
+  but represent a common and useful way of supplying arguments to
+  \function{imap()}.
+  Equivalent to:
+
+  \begin{verbatim}
+     def imap(function, *iterables):
+         iterables = map(iter, iterables)
+         while True:
+             args = [i.next() for i in iterables]
+             if function is None:
+                 yield tuple(args)
+             else:
+                 yield function(*args)
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{islice}{iterable, \optional{start,} stop \optional{, step}}
+  Make an iterator that returns selected elements from the iterable.
+  If \var{start} is non-zero, then elements from the iterable are skipped
+  until start is reached.  Afterward, elements are returned consecutively
+  unless \var{step} is set higher than one which results in items being
+  skipped.  If \var{stop} is \code{None}, then iteration continues until
+  the iterator is exhausted, if at all; otherwise, it stops at the specified
+  position.  Unlike regular slicing,
+  \function{islice()} does not support negative values for \var{start},
+  \var{stop}, or \var{step}.  Can be used to extract related fields
+  from data where the internal structure has been flattened (for
+  example, a multi-line report may list a name field on every
+  third line).  Equivalent to:
+
+  \begin{verbatim}
+     def islice(iterable, *args):
+         s = slice(*args)
+         it = iter(xrange(s.start or 0, s.stop or sys.maxint, s.step or 1))
+         nexti = it.next()
+         for i, element in enumerate(iterable):
+             if i == nexti:
+                 yield element
+                 nexti = it.next()          
+  \end{verbatim}
+
+  If \var{start} is \code{None}, then iteration starts at zero.
+  If \var{step} is \code{None}, then the step defaults to one.
+  \versionchanged[accept \code{None} values for default \var{start} and
+                  \var{step}]{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{izip}{*iterables}
+  Make an iterator that aggregates elements from each of the iterables.
+  Like \function{zip()} except that it returns an iterator instead of
+  a list.  Used for lock-step iteration over several iterables at a
+  time.  Equivalent to:
+
+  \begin{verbatim}
+     def izip(*iterables):
+         iterables = map(iter, iterables)
+         while iterables:
+             result = [it.next() for it in iterables]
+             yield tuple(result)
+  \end{verbatim}
+
+  \versionchanged[When no iterables are specified, returns a zero length
+                  iterator instead of raising a \exception{TypeError}
+		  exception]{2.4}
+
+  Note, the left-to-right evaluation order of the iterables is guaranteed.
+  This makes possible an idiom for clustering a data series into n-length
+  groups using \samp{izip(*[iter(s)]*n)}.  For data that doesn't fit
+  n-length groups exactly, the last tuple can be pre-padded with fill
+  values using \samp{izip(*[chain(s, [None]*(n-1))]*n)}.
+         
+  Note, when \function{izip()} is used with unequal length inputs, subsequent
+  iteration over the longer iterables cannot reliably be continued after
+  \function{izip()} terminates.  Potentially, up to one entry will be missing
+  from each of the left-over iterables. This occurs because a value is fetched
+  from each iterator in-turn, but the process ends when one of the iterators
+  terminates.  This leaves the last fetched values in limbo (they cannot be
+  returned in a final, incomplete tuple and they are cannot be pushed back
+  into the iterator for retrieval with \code{it.next()}).  In general,
+  \function{izip()} should only be used with unequal length inputs when you
+  don't care about trailing, unmatched values from the longer iterables.
+\end{funcdesc}
+
+\begin{funcdesc}{repeat}{object\optional{, times}}
+  Make an iterator that returns \var{object} over and over again.
+  Runs indefinitely unless the \var{times} argument is specified.
+  Used as argument to \function{imap()} for invariant parameters
+  to the called function.  Also used with \function{izip()} to create
+  an invariant part of a tuple record.  Equivalent to:
+
+  \begin{verbatim}
+     def repeat(object, times=None):
+         if times is None:
+             while True:
+                 yield object
+         else:
+             for i in xrange(times):
+                 yield object
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{starmap}{function, iterable}
+  Make an iterator that computes the function using arguments tuples
+  obtained from the iterable.  Used instead of \function{imap()} when
+  argument parameters are already grouped in tuples from a single iterable
+  (the data has been ``pre-zipped'').  The difference between
+  \function{imap()} and \function{starmap()} parallels the distinction
+  between \code{function(a,b)} and \code{function(*c)}.
+  Equivalent to:
+
+  \begin{verbatim}
+     def starmap(function, iterable):
+         iterable = iter(iterable)
+         while True:
+             yield function(*iterable.next())
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{takewhile}{predicate, iterable}
+  Make an iterator that returns elements from the iterable as long as
+  the predicate is true.  Equivalent to:
+
+  \begin{verbatim}
+     def takewhile(predicate, iterable):
+         for x in iterable:
+             if predicate(x):
+                 yield x
+             else:
+                 break
+  \end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{tee}{iterable\optional{, n=2}}
+  Return \var{n} independent iterators from a single iterable.
+  The case where \code{n==2} is equivalent to:
+
+  \begin{verbatim}
+     def tee(iterable):
+         def gen(next, data={}, cnt=[0]):
+             for i in count():
+                 if i == cnt[0]:
+                     item = data[i] = next()
+                     cnt[0] += 1
+                 else:
+                     item = data.pop(i)
+                 yield item
+         it = iter(iterable)
+         return (gen(it.next), gen(it.next))
+  \end{verbatim}
+
+  Note, once \function{tee()} has made a split, the original \var{iterable}
+  should not be used anywhere else; otherwise, the \var{iterable} could get
+  advanced without the tee objects being informed.
+
+  Note, this member of the toolkit may require significant auxiliary
+  storage (depending on how much temporary data needs to be stored).
+  In general, if one iterator is going to use most or all of the data before
+  the other iterator, it is faster to use \function{list()} instead of
+  \function{tee()}.
+  \versionadded{2.4}
+\end{funcdesc}
+
+
+\subsection{Examples \label{itertools-example}}
+
+The following examples show common uses for each tool and
+demonstrate ways they can be combined.
+
+\begin{verbatim}
+
+>>> amounts = [120.15, 764.05, 823.14]
+>>> for checknum, amount in izip(count(1200), amounts):
+...     print 'Check %d is for $%.2f' % (checknum, amount)
+...
+Check 1200 is for $120.15
+Check 1201 is for $764.05
+Check 1202 is for $823.14
+
+>>> import operator
+>>> for cube in imap(operator.pow, xrange(1,5), repeat(3)):
+...    print cube
+...
+1
+8
+27
+64
+
+>>> reportlines = ['EuroPython', 'Roster', '', 'alex', '', 'laura',
+                  '', 'martin', '', 'walter', '', 'mark']
+>>> for name in islice(reportlines, 3, None, 2):
+...    print name.title()
+...
+Alex
+Laura
+Martin
+Walter
+Mark
+
+# Show a dictionary sorted and grouped by value
+>>> from operator import itemgetter
+>>> d = dict(a=1, b=2, c=1, d=2, e=1, f=2, g=3)
+>>> di = sorted(d.iteritems(), key=itemgetter(1))
+>>> for k, g in groupby(di, key=itemgetter(1)):
+...     print k, map(itemgetter(0), g)
+...
+1 ['a', 'c', 'e']
+2 ['b', 'd', 'f']
+3 ['g']
+
+# Find runs of consecutive numbers using groupby.  The key to the solution
+# is differencing with a range so that consecutive numbers all appear in
+# same group.
+>>> data = [ 1,  4,5,6, 10, 15,16,17,18, 22, 25,26,27,28]
+>>> for k, g in groupby(enumerate(data), lambda (i,x):i-x):
+...     print map(operator.itemgetter(1), g)
+... 
+[1]
+[4, 5, 6]
+[10]
+[15, 16, 17, 18]
+[22]
+[25, 26, 27, 28]
+
+\end{verbatim}
+
+
+\subsection{Recipes \label{itertools-recipes}}
+
+This section shows recipes for creating an extended toolset using the
+existing itertools as building blocks.
+
+The extended tools offer the same high performance as the underlying
+toolset.  The superior memory performance is kept by processing elements one
+at a time rather than bringing the whole iterable into memory all at once.
+Code volume is kept small by linking the tools together in a functional style
+which helps eliminate temporary variables.  High speed is retained by
+preferring ``vectorized'' building blocks over the use of for-loops and
+generators which incur interpreter overhead.
+
+
+\begin{verbatim}
+def take(n, seq):
+    return list(islice(seq, n))
+
+def enumerate(iterable):
+    return izip(count(), iterable)
+
+def tabulate(function):
+    "Return function(0), function(1), ..."
+    return imap(function, count())
+
+def iteritems(mapping):
+    return izip(mapping.iterkeys(), mapping.itervalues())
+
+def nth(iterable, n):
+    "Returns the nth item or raise IndexError"
+    return list(islice(iterable, n, n+1))[0]
+
+def all(seq, pred=None):
+    "Returns True if pred(x) is true for every element in the iterable"
+    for elem in ifilterfalse(pred, seq):
+        return False
+    return True
+
+def any(seq, pred=None):
+    "Returns True if pred(x) is true for at least one element in the iterable"
+    for elem in ifilter(pred, seq):
+        return True
+    return False
+
+def no(seq, pred=None):
+    "Returns True if pred(x) is false for every element in the iterable"
+    for elem in ifilter(pred, seq):
+        return False
+    return True
+
+def quantify(seq, pred=None):
+    "Count how many times the predicate is true in the sequence"
+    return sum(imap(pred, seq))
+
+def padnone(seq):
+    """Returns the sequence elements and then returns None indefinitely.
+
+    Useful for emulating the behavior of the built-in map() function.
+    """
+    return chain(seq, repeat(None))
+
+def ncycles(seq, n):
+    "Returns the sequence elements n times"
+    return chain(*repeat(seq, n))
+
+def dotproduct(vec1, vec2):
+    return sum(imap(operator.mul, vec1, vec2))
+
+def flatten(listOfLists):
+    return list(chain(*listOfLists))
+
+def repeatfunc(func, times=None, *args):
+    """Repeat calls to func with specified arguments.
+    
+    Example:  repeatfunc(random.random)
+    """
+    if times is None:
+        return starmap(func, repeat(args))
+    else:
+        return starmap(func, repeat(args, times))
+
+def pairwise(iterable):
+    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
+    a, b = tee(iterable)
+    try:
+        b.next()
+    except StopIteration:
+        pass
+    return izip(a, b)
+
+def grouper(n, iterable, padvalue=None):
+    "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
+    return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
+
+def reverse_map(d):
+    "Return a new dict with swapped keys and values"
+    return dict(izip(d.itervalues(), d))
+
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libjpeg.tex b/sys/src/cmd/python/Doc/lib/libjpeg.tex
new file mode 100644
index 000000000..a10e06c2c
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libjpeg.tex
@@ -0,0 +1,80 @@
+\section{\module{jpeg} ---
+         Read and write JPEG files}
+
+\declaremodule{builtin}{jpeg}
+  \platform{IRIX}
+\modulesynopsis{Read and write image files in compressed JPEG format.}
+
+
+The module \module{jpeg} provides access to the jpeg compressor and
+decompressor written by the Independent JPEG Group
+\index{Independent JPEG Group}(IJG). JPEG is a standard for
+compressing pictures; it is defined in ISO 10918.  For details on JPEG
+or the Independent JPEG Group software refer to the JPEG standard or
+the documentation provided with the software.
+
+A portable interface to JPEG image files is available with the Python
+Imaging Library (PIL) by Fredrik Lundh.  Information on PIL is
+available at \url{http://www.pythonware.com/products/pil/}.
+\index{Python Imaging Library}
+\index{PIL (the Python Imaging Library)}
+\index{Lundh, Fredrik}
+
+The \module{jpeg} module defines an exception and some functions.
+
+\begin{excdesc}{error}
+Exception raised by \function{compress()} and \function{decompress()}
+in case of errors.
+\end{excdesc}
+
+\begin{funcdesc}{compress}{data, w, h, b}
+Treat data as a pixmap of width \var{w} and height \var{h}, with
+\var{b} bytes per pixel.  The data is in SGI GL order, so the first
+pixel is in the lower-left corner. This means that \function{gl.lrectread()}
+return data can immediately be passed to \function{compress()}.
+Currently only 1 byte and 4 byte pixels are allowed, the former being
+treated as greyscale and the latter as RGB color.
+\function{compress()} returns a string that contains the compressed
+picture, in JFIF\index{JFIF} format.
+\end{funcdesc}
+
+\begin{funcdesc}{decompress}{data}
+Data is a string containing a picture in JFIF\index{JFIF} format. It
+returns a tuple \code{(\var{data}, \var{width}, \var{height},
+\var{bytesperpixel})}.  Again, the data is suitable to pass to
+\function{gl.lrectwrite()}.
+\end{funcdesc}
+
+\begin{funcdesc}{setoption}{name, value}
+Set various options.  Subsequent \function{compress()} and
+\function{decompress()} calls will use these options.  The following
+options are available:
+
+\begin{tableii}{l|p{3in}}{code}{Option}{Effect}
+  \lineii{'forcegray'}{%
+    Force output to be grayscale, even if input is RGB.}
+  \lineii{'quality'}{%
+    Set the quality of the compressed image to a value between
+    \code{0} and \code{100} (default is \code{75}).  This only affects
+    compression.}
+  \lineii{'optimize'}{%
+    Perform Huffman table optimization.  Takes longer, but results in
+    smaller compressed image.  This only affects compression.}
+  \lineii{'smooth'}{%
+    Perform inter-block smoothing on uncompressed image.  Only useful
+    for low-quality images.  This only affects decompression.}
+\end{tableii}
+\end{funcdesc}
+
+
+\begin{seealso}
+  \seetitle{JPEG Still Image Data Compression Standard}{The 
+            canonical reference for the JPEG image format, by
+            Pennebaker and Mitchell.}
+
+  \seetitle[http://www.w3.org/Graphics/JPEG/itu-t81.pdf]{Information
+            Technology - Digital Compression and Coding of
+            Continuous-tone Still Images - Requirements and
+            Guidelines}{The ISO standard for JPEG is also published as
+            ITU T.81.  This is available online in PDF form.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libkeyword.tex b/sys/src/cmd/python/Doc/lib/libkeyword.tex
new file mode 100644
index 000000000..0c07cec2f
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libkeyword.tex
@@ -0,0 +1,20 @@
+\section{\module{keyword} ---
+         Testing for Python keywords}
+
+\declaremodule{standard}{keyword}
+\modulesynopsis{Test whether a string is a keyword in Python.}
+
+
+This module allows a Python program to determine if a string is a
+keyword.
+
+\begin{funcdesc}{iskeyword}{s}
+Return true if \var{s} is a Python keyword.
+\end{funcdesc}
+
+\begin{datadesc}{kwlist}
+Sequence containing all the keywords defined for the interpreter.  If
+any keywords are defined to only be active when particular
+\module{__future__} statements are in effect, these will be included
+as well.
+\end{datadesc}
diff --git a/sys/src/cmd/python/Doc/lib/liblinecache.tex b/sys/src/cmd/python/Doc/lib/liblinecache.tex
new file mode 100644
index 000000000..72c774341
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/liblinecache.tex
@@ -0,0 +1,50 @@
+\section{\module{linecache} ---
+         Random access to text lines}
+
+\declaremodule{standard}{linecache}
+\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il}
+\modulesynopsis{This module provides random access to individual lines
+                from text files.}
+
+
+The \module{linecache} module allows one to get any line from any file,
+while attempting to optimize internally, using a cache, the common case
+where many lines are read from a single file.  This is used by the
+\refmodule{traceback} module to retrieve source lines for inclusion in 
+the formatted traceback.
+
+The \module{linecache} module defines the following functions:
+
+\begin{funcdesc}{getline}{filename, lineno\optional{, module_globals}}
+Get line \var{lineno} from file named \var{filename}. This function
+will never throw an exception --- it will return \code{''} on errors
+(the terminating newline character will be included for lines that are
+found).
+
+If a file named \var{filename} is not found, the function will look
+for it in the module\indexiii{module}{search}{path} search path,
+\code{sys.path}, after first checking for a \pep{302} \code{__loader__}
+in \var{module_globals}, in case the module was imported from a zipfile
+or other non-filesystem import source. 
+
+\versionadded[The \var{module_globals} parameter was added]{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{clearcache}{}
+Clear the cache.  Use this function if you no longer need lines from
+files previously read using \function{getline()}.
+\end{funcdesc}
+
+\begin{funcdesc}{checkcache}{\optional{filename}}
+Check the cache for validity.  Use this function if files in the cache 
+may have changed on disk, and you require the updated version.  If
+\var{filename} is omitted, it will check all the entries in the cache.
+\end{funcdesc}
+
+Example:
+
+\begin{verbatim}
+>>> import linecache
+>>> linecache.getline('/etc/passwd', 4)
+'sys:x:3:3:sys:/dev:/bin/sh\n'
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/liblocale.tex b/sys/src/cmd/python/Doc/lib/liblocale.tex
new file mode 100644
index 000000000..319d893ec
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/liblocale.tex
@@ -0,0 +1,527 @@
+\section{\module{locale} ---
+         Internationalization services}
+
+\declaremodule{standard}{locale}
+\modulesynopsis{Internationalization services.}
+\moduleauthor{Martin von L\"owis}{martin@v.loewis.de}
+\sectionauthor{Martin von L\"owis}{martin@v.loewis.de}
+
+
+The \module{locale} module opens access to the \POSIX{} locale
+database and functionality. The \POSIX{} locale mechanism allows
+programmers to deal with certain cultural issues in an application,
+without requiring the programmer to know all the specifics of each
+country where the software is executed.
+
+The \module{locale} module is implemented on top of the
+\module{_locale}\refbimodindex{_locale} module, which in turn uses an
+ANSI C locale implementation if available.
+
+The \module{locale} module defines the following exception and
+functions:
+
+
+\begin{excdesc}{Error}
+  Exception raised when \function{setlocale()} fails.
+\end{excdesc}
+
+\begin{funcdesc}{setlocale}{category\optional{, locale}}
+  If \var{locale} is specified, it may be a string, a tuple of the
+  form \code{(\var{language code}, \var{encoding})}, or \code{None}.
+  If it is a tuple, it is converted to a string using the locale
+  aliasing engine.  If \var{locale} is given and not \code{None},
+  \function{setlocale()} modifies the locale setting for the
+  \var{category}.  The available categories are listed in the data
+  description below.  The value is the name of a locale.  An empty
+  string specifies the user's default settings. If the modification of
+  the locale fails, the exception \exception{Error} is raised.  If
+  successful, the new locale setting is returned.
+
+  If \var{locale} is omitted or \code{None}, the current setting for
+  \var{category} is returned.
+
+  \function{setlocale()} is not thread safe on most systems.
+  Applications typically start with a call of
+
+\begin{verbatim}
+import locale
+locale.setlocale(locale.LC_ALL, '')
+\end{verbatim}
+
+  This sets the locale for all categories to the user's default
+  setting (typically specified in the \envvar{LANG} environment
+  variable).  If the locale is not changed thereafter, using
+  multithreading should not cause problems.
+
+  \versionchanged[Added support for tuple values of the \var{locale}
+                  parameter]{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{localeconv}{}
+  Returns the database of the local conventions as a dictionary.
+  This dictionary has the following strings as keys:
+
+  \begin{tableiii}{l|l|p{3in}}{constant}{Category}{Key}{Meaning}
+    \lineiii{LC_NUMERIC}{\code{'decimal_point'}}
+            {Decimal point character.}
+    \lineiii{}{\code{'grouping'}}
+            {Sequence of numbers specifying which relative positions
+             the \code{'thousands_sep'} is expected.  If the sequence is
+             terminated with \constant{CHAR_MAX}, no further grouping
+             is performed. If the sequence terminates with a \code{0}, 
+             the last group size is repeatedly used.}
+    \lineiii{}{\code{'thousands_sep'}}
+            {Character used between groups.}\hline
+    \lineiii{LC_MONETARY}{\code{'int_curr_symbol'}}
+            {International currency symbol.}
+    \lineiii{}{\code{'currency_symbol'}}
+            {Local currency symbol.}
+    \lineiii{}{\code{'p_cs_precedes/n_cs_precedes'}}
+            {Whether the currency symbol precedes the value (for positive resp.
+             negative values).}
+    \lineiii{}{\code{'p_sep_by_space/n_sep_by_space'}}
+            {Whether the currency symbol is separated from the value 
+             by a space (for positive resp. negative values).}
+    \lineiii{}{\code{'mon_decimal_point'}}
+            {Decimal point used for monetary values.}
+    \lineiii{}{\code{'frac_digits'}}
+            {Number of fractional digits used in local formatting
+             of monetary values.}
+    \lineiii{}{\code{'int_frac_digits'}}
+            {Number of fractional digits used in international
+             formatting of monetary values.}
+    \lineiii{}{\code{'mon_thousands_sep'}}
+            {Group separator used for monetary values.}
+    \lineiii{}{\code{'mon_grouping'}}
+            {Equivalent to \code{'grouping'}, used for monetary
+             values.}
+    \lineiii{}{\code{'positive_sign'}}
+            {Symbol used to annotate a positive monetary value.}
+    \lineiii{}{\code{'negative_sign'}}
+            {Symbol used to annotate a negative monetary value.}
+    \lineiii{}{\code{'p_sign_posn/n_sign_posn'}}
+            {The position of the sign (for positive resp. negative values), see below.}
+  \end{tableiii}
+  
+  All numeric values can be set to \constant{CHAR_MAX} to indicate that
+  there is no value specified in this locale.
+
+  The possible values for \code{'p_sign_posn'} and
+  \code{'n_sign_posn'} are given below.
+
+  \begin{tableii}{c|l}{code}{Value}{Explanation}
+    \lineii{0}{Currency and value are surrounded by parentheses.}
+    \lineii{1}{The sign should precede the value and currency symbol.}
+    \lineii{2}{The sign should follow the value and currency symbol.}
+    \lineii{3}{The sign should immediately precede the value.}
+    \lineii{4}{The sign should immediately follow the value.}
+    \lineii{\constant{CHAR_MAX}}{Nothing is specified in this locale.}
+  \end{tableii}
+\end{funcdesc}
+
+\begin{funcdesc}{nl_langinfo}{option}
+
+Return some locale-specific information as a string. This function is
+not available on all systems, and the set of possible options might
+also vary across platforms. The possible argument values are numbers,
+for which symbolic constants are available in the locale module.
+
+\end{funcdesc}
+
+\begin{funcdesc}{getdefaultlocale}{\optional{envvars}}
+  Tries to determine the default locale settings and returns
+  them as a tuple of the form \code{(\var{language code},
+  \var{encoding})}.
+
+  According to \POSIX, a program which has not called
+  \code{setlocale(LC_ALL, '')} runs using the portable \code{'C'}
+  locale.  Calling \code{setlocale(LC_ALL, '')} lets it use the
+  default locale as defined by the \envvar{LANG} variable.  Since we
+  do not want to interfere with the current locale setting we thus
+  emulate the behavior in the way described above.
+
+  To maintain compatibility with other platforms, not only the
+  \envvar{LANG} variable is tested, but a list of variables given as
+  envvars parameter.  The first found to be defined will be
+  used.  \var{envvars} defaults to the search path used in GNU gettext;
+  it must always contain the variable name \samp{LANG}.  The GNU
+  gettext search path contains \code{'LANGUAGE'}, \code{'LC_ALL'},
+  \code{'LC_CTYPE'}, and \code{'LANG'}, in that order.
+
+  Except for the code \code{'C'}, the language code corresponds to
+  \rfc{1766}.  \var{language code} and \var{encoding} may be
+  \code{None} if their values cannot be determined.
+  \versionadded{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{getlocale}{\optional{category}}
+  Returns the current setting for the given locale category as
+  sequence containing \var{language code}, \var{encoding}.
+  \var{category} may be one of the \constant{LC_*} values except
+  \constant{LC_ALL}.  It defaults to \constant{LC_CTYPE}.
+
+  Except for the code \code{'C'}, the language code corresponds to
+  \rfc{1766}.  \var{language code} and \var{encoding} may be
+  \code{None} if their values cannot be determined.
+  \versionadded{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{getpreferredencoding}{\optional{do_setlocale}}
+  Return the encoding used for text data, according to user
+  preferences.  User preferences are expressed differently on
+  different systems, and might not be available programmatically on
+  some systems, so this function only returns a guess.
+
+  On some systems, it is necessary to invoke \function{setlocale}
+  to obtain the user preferences, so this function is not thread-safe.
+  If invoking setlocale is not necessary or desired, \var{do_setlocale}
+  should be set to \code{False}.
+
+  \versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{normalize}{localename}
+  Returns a normalized locale code for the given locale name.  The
+  returned locale code is formatted for use with
+  \function{setlocale()}.  If normalization fails, the original name
+  is returned unchanged.
+
+  If the given encoding is not known, the function defaults to
+  the default encoding for the locale code just like
+  \function{setlocale()}.
+  \versionadded{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{resetlocale}{\optional{category}}
+  Sets the locale for \var{category} to the default setting.
+
+  The default setting is determined by calling
+  \function{getdefaultlocale()}.  \var{category} defaults to
+  \constant{LC_ALL}.
+  \versionadded{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{strcoll}{string1, string2}
+  Compares two strings according to the current
+  \constant{LC_COLLATE} setting. As any other compare function,
+  returns a negative, or a positive value, or \code{0}, depending on
+  whether \var{string1} collates before or after \var{string2} or is
+  equal to it.
+\end{funcdesc}
+
+\begin{funcdesc}{strxfrm}{string}
+  Transforms a string to one that can be used for the built-in
+  function \function{cmp()}\bifuncindex{cmp}, and still returns
+  locale-aware results.  This function can be used when the same
+  string is compared repeatedly, e.g. when collating a sequence of
+  strings.
+\end{funcdesc}
+
+\begin{funcdesc}{format}{format, val\optional{, grouping\optional{, monetary}}}
+  Formats a number \var{val} according to the current
+  \constant{LC_NUMERIC} setting.  The format follows the conventions
+  of the \code{\%} operator.  For floating point values, the decimal
+  point is modified if appropriate.  If \var{grouping} is true, also
+  takes the grouping into account.
+
+  If \var{monetary} is true, the conversion uses monetary thousands
+  separator and grouping strings.
+
+  Please note that this function will only work for exactly one \%char
+  specifier. For whole format strings, use \function{format_string()}.
+
+  \versionchanged[Added the \var{monetary} parameter]{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{format_string}{format, val\optional{, grouping}}
+  Processes formatting specifiers as in \code{format \% val},
+  but takes the current locale settings into account.
+
+  \versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{currency}{val\optional{, symbol\optional{, grouping\optional{, international}}}}
+  Formats a number \var{val} according to the current \constant{LC_MONETARY}
+  settings. 
+  
+  The returned string includes the currency symbol if \var{symbol} is true,
+  which is the default.
+  If \var{grouping} is true (which is not the default), grouping is done with
+  the value.
+  If \var{international} is true (which is not the default), the international
+  currency symbol is used.
+
+  Note that this function will not work with the `C' locale, so you have to set
+  a locale via \function{setlocale()} first.
+
+  \versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{str}{float}
+  Formats a floating point number using the same format as the
+  built-in function \code{str(\var{float})}, but takes the decimal
+  point into account.
+\end{funcdesc}
+
+\begin{funcdesc}{atof}{string}
+  Converts a string to a floating point number, following the
+  \constant{LC_NUMERIC} settings.
+\end{funcdesc}
+
+\begin{funcdesc}{atoi}{string}
+  Converts a string to an integer, following the
+  \constant{LC_NUMERIC} conventions.
+\end{funcdesc}
+
+\begin{datadesc}{LC_CTYPE}
+\refstmodindex{string}
+  Locale category for the character type functions.  Depending on the
+  settings of this category, the functions of module
+  \refmodule{string} dealing with case change their behaviour.
+\end{datadesc}
+
+\begin{datadesc}{LC_COLLATE}
+  Locale category for sorting strings.  The functions
+  \function{strcoll()} and \function{strxfrm()} of the
+  \module{locale} module are affected.
+\end{datadesc}
+
+\begin{datadesc}{LC_TIME}
+  Locale category for the formatting of time.  The function
+  \function{time.strftime()} follows these conventions.
+\end{datadesc}
+
+\begin{datadesc}{LC_MONETARY}
+  Locale category for formatting of monetary values.  The available
+  options are available from the \function{localeconv()} function.
+\end{datadesc}
+
+\begin{datadesc}{LC_MESSAGES}
+  Locale category for message display. Python currently does not
+  support application specific locale-aware messages.  Messages
+  displayed by the operating system, like those returned by
+  \function{os.strerror()} might be affected by this category.
+\end{datadesc}
+
+\begin{datadesc}{LC_NUMERIC}
+  Locale category for formatting numbers.  The functions
+  \function{format()}, \function{atoi()}, \function{atof()} and
+  \function{str()} of the \module{locale} module are affected by that
+  category.  All other numeric formatting operations are not
+  affected.
+\end{datadesc}
+
+\begin{datadesc}{LC_ALL}
+  Combination of all locale settings.  If this flag is used when the
+  locale is changed, setting the locale for all categories is
+  attempted. If that fails for any category, no category is changed at
+  all.  When the locale is retrieved using this flag, a string
+  indicating the setting for all categories is returned. This string
+  can be later used to restore the settings.
+\end{datadesc}
+
+\begin{datadesc}{CHAR_MAX}
+  This is a symbolic constant used for different values returned by
+  \function{localeconv()}.
+\end{datadesc}
+
+The \function{nl_langinfo} function accepts one of the following keys.
+Most descriptions are taken from the corresponding description in the
+GNU C library.
+
+\begin{datadesc}{CODESET}
+Return a string with the name of the character encoding used in the
+selected locale.
+\end{datadesc}
+
+\begin{datadesc}{D_T_FMT}
+Return a string that can be used as a format string for strftime(3) to
+represent time and date in a locale-specific way.
+\end{datadesc}
+
+\begin{datadesc}{D_FMT}
+Return a string that can be used as a format string for strftime(3) to
+represent a date in a locale-specific way.
+\end{datadesc}
+
+\begin{datadesc}{T_FMT}
+Return a string that can be used as a format string for strftime(3) to
+represent a time in a locale-specific way.
+\end{datadesc}
+
+\begin{datadesc}{T_FMT_AMPM}
+The return value can be used as a format string for `strftime' to
+represent time in the am/pm format.
+\end{datadesc}
+
+\begin{datadesc}{DAY_1 ... DAY_7}
+Return name of the n-th day of the week. \warning{This
+follows the US convention of \constant{DAY_1} being Sunday, not the
+international convention (ISO 8601) that Monday is the first day of
+the week.}
+\end{datadesc}
+
+\begin{datadesc}{ABDAY_1 ... ABDAY_7}
+Return abbreviated name of the n-th day of the week.
+\end{datadesc}
+
+\begin{datadesc}{MON_1 ... MON_12}
+Return name of the n-th month.
+\end{datadesc}
+
+\begin{datadesc}{ABMON_1 ... ABMON_12}
+Return abbreviated name of the n-th month.
+\end{datadesc}
+
+\begin{datadesc}{RADIXCHAR}
+Return radix character (decimal dot, decimal comma, etc.)
+\end{datadesc}
+
+\begin{datadesc}{THOUSEP}
+Return separator character for thousands (groups of three digits).
+\end{datadesc}
+
+\begin{datadesc}{YESEXPR}
+Return a regular expression that can be used with the regex
+function to recognize a positive response to a yes/no question.
+\warning{The expression is in the syntax suitable for the
+\cfunction{regex()} function from the C library, which might differ
+from the syntax used in \refmodule{re}.}
+\end{datadesc}
+
+\begin{datadesc}{NOEXPR}
+Return a regular expression that can be used with the regex(3)
+function to recognize a negative response to a yes/no question.
+\end{datadesc}
+
+\begin{datadesc}{CRNCYSTR}
+Return the currency symbol, preceded by "-" if the symbol should
+appear before the value, "+" if the symbol should appear after the
+value, or "." if the symbol should replace the radix character.
+\end{datadesc}
+
+\begin{datadesc}{ERA}
+The return value represents the era used in the current locale.
+
+Most locales do not define this value.  An example of a locale which
+does define this value is the Japanese one.  In Japan, the traditional
+representation of dates includes the name of the era corresponding to
+the then-emperor's reign.
+
+Normally it should not be necessary to use this value directly.
+Specifying the \code{E} modifier in their format strings causes the
+\function{strftime} function to use this information.  The format of the
+returned string is not specified, and therefore you should not assume
+knowledge of it on different systems.
+\end{datadesc}
+
+\begin{datadesc}{ERA_YEAR}
+The return value gives the year in the relevant era of the locale.
+\end{datadesc}
+
+\begin{datadesc}{ERA_D_T_FMT}
+This return value can be used as a format string for
+\function{strftime} to represent dates and times in a locale-specific
+era-based way.
+\end{datadesc}
+
+\begin{datadesc}{ERA_D_FMT}
+This return value can be used as a format string for
+\function{strftime} to represent time in a locale-specific era-based
+way.
+\end{datadesc}
+
+\begin{datadesc}{ALT_DIGITS}
+The return value is a representation of up to 100 values used to
+represent the values 0 to 99.
+\end{datadesc}
+
+Example:
+
+\begin{verbatim}
+>>> import locale
+>>> loc = locale.getlocale(locale.LC_ALL) # get current locale
+>>> locale.setlocale(locale.LC_ALL, 'de_DE') # use German locale; name might vary with platform
+>>> locale.strcoll('f\xe4n', 'foo') # compare a string containing an umlaut 
+>>> locale.setlocale(locale.LC_ALL, '') # use user's preferred locale
+>>> locale.setlocale(locale.LC_ALL, 'C') # use default (C) locale
+>>> locale.setlocale(locale.LC_ALL, loc) # restore saved locale
+\end{verbatim}
+
+
+\subsection{Background, details, hints, tips and caveats}
+
+The C standard defines the locale as a program-wide property that may
+be relatively expensive to change.  On top of that, some
+implementation are broken in such a way that frequent locale changes
+may cause core dumps.  This makes the locale somewhat painful to use
+correctly.
+
+Initially, when a program is started, the locale is the \samp{C} locale, no
+matter what the user's preferred locale is.  The program must
+explicitly say that it wants the user's preferred locale settings by
+calling \code{setlocale(LC_ALL, '')}.
+
+It is generally a bad idea to call \function{setlocale()} in some library
+routine, since as a side effect it affects the entire program.  Saving
+and restoring it is almost as bad: it is expensive and affects other
+threads that happen to run before the settings have been restored.
+
+If, when coding a module for general use, you need a locale
+independent version of an operation that is affected by the locale
+(such as \function{string.lower()}, or certain formats used with
+\function{time.strftime()}), you will have to find a way to do it
+without using the standard library routine.  Even better is convincing
+yourself that using locale settings is okay.  Only as a last resort
+should you document that your module is not compatible with
+non-\samp{C} locale settings.
+
+The case conversion functions in the
+\refmodule{string}\refstmodindex{string} module are affected by the
+locale settings.  When a call to the \function{setlocale()} function
+changes the \constant{LC_CTYPE} settings, the variables
+\code{string.lowercase}, \code{string.uppercase} and
+\code{string.letters} are recalculated.  Note that code that uses
+these variable through `\keyword{from} ... \keyword{import} ...',
+e.g.\ \code{from string import letters}, is not affected by subsequent
+\function{setlocale()} calls.
+
+The only way to perform numeric operations according to the locale
+is to use the special functions defined by this module:
+\function{atof()}, \function{atoi()}, \function{format()},
+\function{str()}.
+
+\subsection{For extension writers and programs that embed Python
+            \label{embedding-locale}}
+
+Extension modules should never call \function{setlocale()}, except to
+find out what the current locale is.  But since the return value can
+only be used portably to restore it, that is not very useful (except
+perhaps to find out whether or not the locale is \samp{C}).
+
+When Python code uses the \module{locale} module to change the locale,
+this also affects the embedding application.  If the embedding
+application doesn't want this to happen, it should remove the
+\module{_locale} extension module (which does all the work) from the
+table of built-in modules in the \file{config.c} file, and make sure
+that the \module{_locale} module is not accessible as a shared library.
+
+
+\subsection{Access to message catalogs \label{locale-gettext}}
+
+The locale module exposes the C library's gettext interface on systems
+that provide this interface.  It consists of the functions
+\function{gettext()}, \function{dgettext()}, \function{dcgettext()},
+\function{textdomain()}, \function{bindtextdomain()}, and
+\function{bind_textdomain_codeset()}.  These are similar to the same
+functions in the \refmodule{gettext} module, but use the C library's
+binary format for message catalogs, and the C library's search
+algorithms for locating message catalogs. 
+
+Python applications should normally find no need to invoke these
+functions, and should use \refmodule{gettext} instead.  A known
+exception to this rule are applications that link use additional C
+libraries which internally invoke \cfunction{gettext()} or
+\function{dcgettext()}.  For these applications, it may be necessary to
+bind the text domain, so that the libraries can properly locate their
+message catalogs.
diff --git a/sys/src/cmd/python/Doc/lib/liblogging.tex b/sys/src/cmd/python/Doc/lib/liblogging.tex
new file mode 100644
index 000000000..b97854d4e
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/liblogging.tex
@@ -0,0 +1,1729 @@
+\section{\module{logging} ---
+         Logging facility for Python}
+
+\declaremodule{standard}{logging}
+
+% These apply to all modules, and may be given more than once:
+
+\moduleauthor{Vinay Sajip}{vinay_sajip@red-dove.com}
+\sectionauthor{Vinay Sajip}{vinay_sajip@red-dove.com}
+
+\modulesynopsis{Logging module for Python based on \pep{282}.}
+
+\indexii{Errors}{logging}
+
+\versionadded{2.3}
+This module defines functions and classes which implement a flexible
+error logging system for applications.
+
+Logging is performed by calling methods on instances of the
+\class{Logger} class (hereafter called \dfn{loggers}). Each instance has a
+name, and they are conceptually arranged in a name space hierarchy
+using dots (periods) as separators. For example, a logger named
+"scan" is the parent of loggers "scan.text", "scan.html" and "scan.pdf".
+Logger names can be anything you want, and indicate the area of an
+application in which a logged message originates.
+
+Logged messages also have levels of importance associated with them.
+The default levels provided are \constant{DEBUG}, \constant{INFO},
+\constant{WARNING}, \constant{ERROR} and \constant{CRITICAL}. As a
+convenience, you indicate the importance of a logged message by calling
+an appropriate method of \class{Logger}. The methods are
+\method{debug()}, \method{info()}, \method{warning()}, \method{error()} and
+\method{critical()}, which mirror the default levels. You are not
+constrained to use these levels: you can specify your own and use a
+more general \class{Logger} method, \method{log()}, which takes an
+explicit level argument.
+
+The numeric values of logging levels are given in the following table. These
+are primarily of interest if you want to define your own levels, and need
+them to have specific values relative to the predefined levels. If you
+define a level with the same numeric value, it overwrites the predefined
+value; the predefined name is lost.
+
+\begin{tableii}{l|l}{code}{Level}{Numeric value}
+  \lineii{CRITICAL}{50}
+  \lineii{ERROR}{40}
+  \lineii{WARNING}{30}
+  \lineii{INFO}{20}
+  \lineii{DEBUG}{10}
+  \lineii{NOTSET}{0}
+\end{tableii}
+
+Levels can also be associated with loggers, being set either by the
+developer or through loading a saved logging configuration. When a
+logging method is called on a logger, the logger compares its own
+level with the level associated with the method call. If the logger's
+level is higher than the method call's, no logging message is actually
+generated. This is the basic mechanism controlling the verbosity of
+logging output.
+
+Logging messages are encoded as instances of the \class{LogRecord} class.
+When a logger decides to actually log an event, a \class{LogRecord}
+instance is created from the logging message.
+
+Logging messages are subjected to a dispatch mechanism through the
+use of \dfn{handlers}, which are instances of subclasses of the
+\class{Handler} class. Handlers are responsible for ensuring that a logged
+message (in the form of a \class{LogRecord}) ends up in a particular
+location (or set of locations) which is useful for the target audience for
+that message (such as end users, support desk staff, system administrators,
+developers). Handlers are passed \class{LogRecord} instances intended for
+particular destinations. Each logger can have zero, one or more handlers
+associated with it (via the \method{addHandler()} method of \class{Logger}).
+In addition to any handlers directly associated with a logger,
+\emph{all handlers associated with all ancestors of the logger} are
+called to dispatch the message.
+
+Just as for loggers, handlers can have levels associated with them.
+A handler's level acts as a filter in the same way as a logger's level does.
+If a handler decides to actually dispatch an event, the \method{emit()} method
+is used to send the message to its destination. Most user-defined subclasses
+of \class{Handler} will need to override this \method{emit()}.
+
+In addition to the base \class{Handler} class, many useful subclasses
+are provided:
+
+\begin{enumerate}
+
+\item \class{StreamHandler} instances send error messages to
+streams (file-like objects).
+
+\item \class{FileHandler} instances send error messages to disk
+files.
+
+\item \class{BaseRotatingHandler} is the base class for handlers that
+rotate log files at a certain point. It is not meant to be  instantiated
+directly. Instead, use \class{RotatingFileHandler} or
+\class{TimedRotatingFileHandler}.
+
+\item \class{RotatingFileHandler} instances send error messages to disk
+files, with support for maximum log file sizes and log file rotation.
+
+\item \class{TimedRotatingFileHandler} instances send error messages to
+disk files rotating the log file at certain timed intervals.
+
+\item \class{SocketHandler} instances send error messages to
+TCP/IP sockets.
+
+\item \class{DatagramHandler} instances send error messages to UDP
+sockets.
+
+\item \class{SMTPHandler} instances send error messages to a
+designated email address.
+
+\item \class{SysLogHandler} instances send error messages to a
+\UNIX{} syslog daemon, possibly on a remote machine.
+
+\item \class{NTEventLogHandler} instances send error messages to a
+Windows NT/2000/XP event log.
+
+\item \class{MemoryHandler} instances send error messages to a
+buffer in memory, which is flushed whenever specific criteria are
+met.
+
+\item \class{HTTPHandler} instances send error messages to an
+HTTP server using either \samp{GET} or \samp{POST} semantics.
+
+\end{enumerate}
+
+The \class{StreamHandler} and \class{FileHandler} classes are defined
+in the core logging package. The other handlers are defined in a sub-
+module, \module{logging.handlers}. (There is also another sub-module,
+\module{logging.config}, for configuration functionality.)
+
+Logged messages are formatted for presentation through instances of the
+\class{Formatter} class. They are initialized with a format string
+suitable for use with the \% operator and a dictionary.
+
+For formatting multiple messages in a batch, instances of
+\class{BufferingFormatter} can be used. In addition to the format string
+(which is applied to each message in the batch), there is provision for
+header and trailer format strings.
+
+When filtering based on logger level and/or handler level is not enough,
+instances of \class{Filter} can be added to both \class{Logger} and
+\class{Handler} instances (through their \method{addFilter()} method).
+Before deciding to process a message further, both loggers and handlers
+consult all their filters for permission. If any filter returns a false
+value, the message is not processed further.
+
+The basic \class{Filter} functionality allows filtering by specific logger
+name. If this feature is used, messages sent to the named logger and its
+children are allowed through the filter, and all others dropped.
+
+In addition to the classes described above, there are a number of module-
+level functions.
+
+\begin{funcdesc}{getLogger}{\optional{name}}
+Return a logger with the specified name or, if no name is specified, return
+a logger which is the root logger of the hierarchy. If specified, the name
+is typically a dot-separated hierarchical name like \var{"a"}, \var{"a.b"}
+or \var{"a.b.c.d"}. Choice of these names is entirely up to the developer
+who is using logging.
+
+All calls to this function with a given name return the same logger instance.
+This means that logger instances never need to be passed between different
+parts of an application.
+\end{funcdesc}
+
+\begin{funcdesc}{getLoggerClass}{}
+Return either the standard \class{Logger} class, or the last class passed to
+\function{setLoggerClass()}. This function may be called from within a new
+class definition, to ensure that installing a customised \class{Logger} class
+will not undo customisations already applied by other code. For example:
+
+\begin{verbatim}
+ class MyLogger(logging.getLoggerClass()):
+     # ... override behaviour here
+\end{verbatim}
+
+\end{funcdesc}
+
+\begin{funcdesc}{debug}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{DEBUG} on the root logger.
+The \var{msg} is the message format string, and the \var{args} are the
+arguments which are merged into \var{msg} using the string formatting
+operator. (Note that this means that you can use keywords in the
+format string, together with a single dictionary argument.)
+
+There are two keyword arguments in \var{kwargs} which are inspected:
+\var{exc_info} which, if it does not evaluate as false, causes exception
+information to be added to the logging message. If an exception tuple (in the
+format returned by \function{sys.exc_info()}) is provided, it is used;
+otherwise, \function{sys.exc_info()} is called to get the exception
+information.
+
+The other optional keyword argument is \var{extra} which can be used to pass
+a dictionary which is used to populate the __dict__ of the LogRecord created
+for the logging event with user-defined attributes. These custom attributes
+can then be used as you like. For example, they could be incorporated into
+logged messages. For example:
+
+\begin{verbatim}
+ FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
+ logging.basicConfig(format=FORMAT)
+ dict = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' }
+ logging.warning("Protocol problem: %s", "connection reset", extra=d)
+\end{verbatim}
+
+would print something like
+\begin{verbatim}
+2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset
+\end{verbatim}
+
+The keys in the dictionary passed in \var{extra} should not clash with the keys
+used by the logging system. (See the \class{Formatter} documentation for more
+information on which keys are used by the logging system.)
+
+If you choose to use these attributes in logged messages, you need to exercise
+some care. In the above example, for instance, the \class{Formatter} has been
+set up with a format string which expects 'clientip' and 'user' in the
+attribute dictionary of the LogRecord. If these are missing, the message will
+not be logged because a string formatting exception will occur. So in this
+case, you always need to pass the \var{extra} dictionary with these keys.
+
+While this might be annoying, this feature is intended for use in specialized
+circumstances, such as multi-threaded servers where the same code executes
+in many contexts, and interesting conditions which arise are dependent on this
+context (such as remote client IP address and authenticated user name, in the
+above example). In such circumstances, it is likely that specialized
+\class{Formatter}s would be used with particular \class{Handler}s.
+
+\versionchanged[\var{extra} was added]{2.5}
+
+\end{funcdesc}
+
+\begin{funcdesc}{info}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{INFO} on the root logger.
+The arguments are interpreted as for \function{debug()}.
+\end{funcdesc}
+
+\begin{funcdesc}{warning}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{WARNING} on the root logger.
+The arguments are interpreted as for \function{debug()}.
+\end{funcdesc}
+
+\begin{funcdesc}{error}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{ERROR} on the root logger.
+The arguments are interpreted as for \function{debug()}.
+\end{funcdesc}
+
+\begin{funcdesc}{critical}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{CRITICAL} on the root logger.
+The arguments are interpreted as for \function{debug()}.
+\end{funcdesc}
+
+\begin{funcdesc}{exception}{msg\optional{, *args}}
+Logs a message with level \constant{ERROR} on the root logger.
+The arguments are interpreted as for \function{debug()}. Exception info
+is added to the logging message. This function should only be called
+from an exception handler.
+\end{funcdesc}
+
+\begin{funcdesc}{log}{level, msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \var{level} on the root logger.
+The other arguments are interpreted as for \function{debug()}.
+\end{funcdesc}
+
+\begin{funcdesc}{disable}{lvl}
+Provides an overriding level \var{lvl} for all loggers which takes
+precedence over the logger's own level. When the need arises to
+temporarily throttle logging output down across the whole application,
+this function can be useful.
+\end{funcdesc}
+
+\begin{funcdesc}{addLevelName}{lvl, levelName}
+Associates level \var{lvl} with text \var{levelName} in an internal
+dictionary, which is used to map numeric levels to a textual
+representation, for example when a \class{Formatter} formats a message.
+This function can also be used to define your own levels. The only
+constraints are that all levels used must be registered using this
+function, levels should be positive integers and they should increase
+in increasing order of severity.
+\end{funcdesc}
+
+\begin{funcdesc}{getLevelName}{lvl}
+Returns the textual representation of logging level \var{lvl}. If the
+level is one of the predefined levels \constant{CRITICAL},
+\constant{ERROR}, \constant{WARNING}, \constant{INFO} or \constant{DEBUG}
+then you get the corresponding string. If you have associated levels
+with names using \function{addLevelName()} then the name you have associated
+with \var{lvl} is returned. If a numeric value corresponding to one of the
+defined levels is passed in, the corresponding string representation is
+returned. Otherwise, the string "Level \%s" \% lvl is returned.
+\end{funcdesc}
+
+\begin{funcdesc}{makeLogRecord}{attrdict}
+Creates and returns a new \class{LogRecord} instance whose attributes are
+defined by \var{attrdict}. This function is useful for taking a pickled
+\class{LogRecord} attribute dictionary, sent over a socket, and reconstituting
+it as a \class{LogRecord} instance at the receiving end.
+\end{funcdesc}
+
+\begin{funcdesc}{basicConfig}{\optional{**kwargs}}
+Does basic configuration for the logging system by creating a
+\class{StreamHandler} with a default \class{Formatter} and adding it to
+the root logger. The functions \function{debug()}, \function{info()},
+\function{warning()}, \function{error()} and \function{critical()} will call
+\function{basicConfig()} automatically if no handlers are defined for the
+root logger.
+
+\versionchanged[Formerly, \function{basicConfig} did not take any keyword
+arguments]{2.4}
+
+The following keyword arguments are supported.
+
+\begin{tableii}{l|l}{code}{Format}{Description}
+\lineii{filename}{Specifies that a FileHandler be created, using the
+specified filename, rather than a StreamHandler.}
+\lineii{filemode}{Specifies the mode to open the file, if filename is
+specified (if filemode is unspecified, it defaults to 'a').}
+\lineii{format}{Use the specified format string for the handler.}
+\lineii{datefmt}{Use the specified date/time format.}
+\lineii{level}{Set the root logger level to the specified level.}
+\lineii{stream}{Use the specified stream to initialize the StreamHandler.
+Note that this argument is incompatible with 'filename' - if both
+are present, 'stream' is ignored.}
+\end{tableii}
+
+\end{funcdesc}
+
+\begin{funcdesc}{shutdown}{}
+Informs the logging system to perform an orderly shutdown by flushing and
+closing all handlers.
+\end{funcdesc}
+
+\begin{funcdesc}{setLoggerClass}{klass}
+Tells the logging system to use the class \var{klass} when instantiating a
+logger. The class should define \method{__init__()} such that only a name
+argument is required, and the \method{__init__()} should call
+\method{Logger.__init__()}. This function is typically called before any
+loggers are instantiated by applications which need to use custom logger
+behavior.
+\end{funcdesc}
+
+
+\begin{seealso}
+  \seepep{282}{A Logging System}
+         {The proposal which described this feature for inclusion in
+          the Python standard library.}
+  \seelink{http://www.red-dove.com/python_logging.html}
+          {Original Python \module{logging} package}
+          {This is the original source for the \module{logging}
+           package.  The version of the package available from this
+           site is suitable for use with Python 1.5.2, 2.1.x and 2.2.x,
+           which do not include the \module{logging} package in the standard
+           library.}
+\end{seealso}
+
+
+\subsection{Logger Objects}
+
+Loggers have the following attributes and methods. Note that Loggers are
+never instantiated directly, but always through the module-level function
+\function{logging.getLogger(name)}.
+
+\begin{datadesc}{propagate}
+If this evaluates to false, logging messages are not passed by this
+logger or by child loggers to higher level (ancestor) loggers. The
+constructor sets this attribute to 1.
+\end{datadesc}
+
+\begin{methoddesc}{setLevel}{lvl}
+Sets the threshold for this logger to \var{lvl}. Logging messages
+which are less severe than \var{lvl} will be ignored. When a logger is
+created, the level is set to \constant{NOTSET} (which causes all messages
+to be processed when the logger is the root logger, or delegation to the
+parent when the logger is a non-root logger). Note that the root logger
+is created with level \constant{WARNING}.
+
+The term "delegation to the parent" means that if a logger has a level
+of NOTSET, its chain of ancestor loggers is traversed until either an
+ancestor with a level other than NOTSET is found, or the root is
+reached.
+
+If an ancestor is found with a level other than NOTSET, then that
+ancestor's level is treated as the effective level of the logger where
+the ancestor search began, and is used to determine how a logging
+event is handled.
+
+If the root is reached, and it has a level of NOTSET, then all
+messages will be processed. Otherwise, the root's level will be used
+as the effective level.
+\end{methoddesc}
+
+\begin{methoddesc}{isEnabledFor}{lvl}
+Indicates if a message of severity \var{lvl} would be processed by
+this logger.  This method checks first the module-level level set by
+\function{logging.disable(lvl)} and then the logger's effective level as
+determined by \method{getEffectiveLevel()}.
+\end{methoddesc}
+
+\begin{methoddesc}{getEffectiveLevel}{}
+Indicates the effective level for this logger. If a value other than
+\constant{NOTSET} has been set using \method{setLevel()}, it is returned.
+Otherwise, the hierarchy is traversed towards the root until a value
+other than \constant{NOTSET} is found, and that value is returned.
+\end{methoddesc}
+
+\begin{methoddesc}{debug}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{DEBUG} on this logger.
+The \var{msg} is the message format string, and the \var{args} are the
+arguments which are merged into \var{msg} using the string formatting
+operator. (Note that this means that you can use keywords in the
+format string, together with a single dictionary argument.)
+
+There are two keyword arguments in \var{kwargs} which are inspected:
+\var{exc_info} which, if it does not evaluate as false, causes exception
+information to be added to the logging message. If an exception tuple (in the
+format returned by \function{sys.exc_info()}) is provided, it is used;
+otherwise, \function{sys.exc_info()} is called to get the exception
+information.
+
+The other optional keyword argument is \var{extra} which can be used to pass
+a dictionary which is used to populate the __dict__ of the LogRecord created
+for the logging event with user-defined attributes. These custom attributes
+can then be used as you like. For example, they could be incorporated into
+logged messages. For example:
+
+\begin{verbatim}
+ FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
+ logging.basicConfig(format=FORMAT)
+ dict = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' }
+ logger = logging.getLogger("tcpserver")
+ logger.warning("Protocol problem: %s", "connection reset", extra=d)
+\end{verbatim}
+
+would print something like
+\begin{verbatim}
+2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset
+\end{verbatim}
+
+The keys in the dictionary passed in \var{extra} should not clash with the keys
+used by the logging system. (See the \class{Formatter} documentation for more
+information on which keys are used by the logging system.)
+
+If you choose to use these attributes in logged messages, you need to exercise
+some care. In the above example, for instance, the \class{Formatter} has been
+set up with a format string which expects 'clientip' and 'user' in the
+attribute dictionary of the LogRecord. If these are missing, the message will
+not be logged because a string formatting exception will occur. So in this
+case, you always need to pass the \var{extra} dictionary with these keys.
+
+While this might be annoying, this feature is intended for use in specialized
+circumstances, such as multi-threaded servers where the same code executes
+in many contexts, and interesting conditions which arise are dependent on this
+context (such as remote client IP address and authenticated user name, in the
+above example). In such circumstances, it is likely that specialized
+\class{Formatter}s would be used with particular \class{Handler}s.
+
+\versionchanged[\var{extra} was added]{2.5}
+
+\end{methoddesc}
+
+\begin{methoddesc}{info}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{INFO} on this logger.
+The arguments are interpreted as for \method{debug()}.
+\end{methoddesc}
+
+\begin{methoddesc}{warning}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{WARNING} on this logger.
+The arguments are interpreted as for \method{debug()}.
+\end{methoddesc}
+
+\begin{methoddesc}{error}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{ERROR} on this logger.
+The arguments are interpreted as for \method{debug()}.
+\end{methoddesc}
+
+\begin{methoddesc}{critical}{msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with level \constant{CRITICAL} on this logger.
+The arguments are interpreted as for \method{debug()}.
+\end{methoddesc}
+
+\begin{methoddesc}{log}{lvl, msg\optional{, *args\optional{, **kwargs}}}
+Logs a message with integer level \var{lvl} on this logger.
+The other arguments are interpreted as for \method{debug()}.
+\end{methoddesc}
+
+\begin{methoddesc}{exception}{msg\optional{, *args}}
+Logs a message with level \constant{ERROR} on this logger.
+The arguments are interpreted as for \method{debug()}. Exception info
+is added to the logging message. This method should only be called
+from an exception handler.
+\end{methoddesc}
+
+\begin{methoddesc}{addFilter}{filt}
+Adds the specified filter \var{filt} to this logger.
+\end{methoddesc}
+
+\begin{methoddesc}{removeFilter}{filt}
+Removes the specified filter \var{filt} from this logger.
+\end{methoddesc}
+
+\begin{methoddesc}{filter}{record}
+Applies this logger's filters to the record and returns a true value if
+the record is to be processed.
+\end{methoddesc}
+
+\begin{methoddesc}{addHandler}{hdlr}
+Adds the specified handler \var{hdlr} to this logger.
+\end{methoddesc}
+
+\begin{methoddesc}{removeHandler}{hdlr}
+Removes the specified handler \var{hdlr} from this logger.
+\end{methoddesc}
+
+\begin{methoddesc}{findCaller}{}
+Finds the caller's source filename and line number. Returns the filename,
+line number and function name as a 3-element tuple.
+\versionchanged[The function name was added. In earlier versions, the
+filename and line number were returned as a 2-element tuple.]{2.5}
+\end{methoddesc}
+
+\begin{methoddesc}{handle}{record}
+Handles a record by passing it to all handlers associated with this logger
+and its ancestors (until a false value of \var{propagate} is found).
+This method is used for unpickled records received from a socket, as well
+as those created locally. Logger-level filtering is applied using
+\method{filter()}.
+\end{methoddesc}
+
+\begin{methoddesc}{makeRecord}{name, lvl, fn, lno, msg, args, exc_info
+                               \optional{, func, extra}}
+This is a factory method which can be overridden in subclasses to create
+specialized \class{LogRecord} instances.
+\versionchanged[\var{func} and \var{extra} were added]{2.5}
+\end{methoddesc}
+
+\subsection{Basic example \label{minimal-example}}
+
+\versionchanged[formerly \function{basicConfig} did not take any keyword
+arguments]{2.4}
+
+The \module{logging} package provides a lot of flexibility, and its
+configuration can appear daunting.  This section demonstrates that simple
+use of the logging package is possible.
+
+The simplest example shows logging to the console:
+
+\begin{verbatim}
+import logging
+
+logging.debug('A debug message')
+logging.info('Some information')
+logging.warning('A shot across the bows')
+\end{verbatim}
+
+If you run the above script, you'll see this:
+\begin{verbatim}
+WARNING:root:A shot across the bows
+\end{verbatim}
+
+Because no particular logger was specified, the system used the root logger.
+The debug and info messages didn't appear because by default, the root
+logger is configured to only handle messages with a severity of WARNING
+or above. The message format is also a configuration default, as is the output
+destination of the messages - \code{sys.stderr}. The severity level,
+the message format and destination can be easily changed, as shown in
+the example below:
+
+\begin{verbatim}
+import logging
+
+logging.basicConfig(level=logging.DEBUG,
+                    format='%(asctime)s %(levelname)s %(message)s',
+                    filename='/tmp/myapp.log',
+                    filemode='w')
+logging.debug('A debug message')
+logging.info('Some information')
+logging.warning('A shot across the bows')
+\end{verbatim}
+
+The \method{basicConfig()} method is used to change the configuration
+defaults, which results in output (written to \code{/tmp/myapp.log})
+which should look something like the following:
+
+\begin{verbatim}
+2004-07-02 13:00:08,743 DEBUG A debug message
+2004-07-02 13:00:08,743 INFO Some information
+2004-07-02 13:00:08,743 WARNING A shot across the bows
+\end{verbatim}
+
+This time, all messages with a severity of DEBUG or above were handled,
+and the format of the messages was also changed, and output went to the
+specified file rather than the console.
+
+Formatting uses standard Python string formatting - see section
+\ref{typesseq-strings}. The format string takes the following
+common specifiers. For a complete list of specifiers, consult the
+\class{Formatter} documentation.
+
+\begin{tableii}{l|l}{code}{Format}{Description}
+\lineii{\%(name)s}     {Name of the logger (logging channel).}
+\lineii{\%(levelname)s}{Text logging level for the message
+                        (\code{'DEBUG'}, \code{'INFO'},
+                        \code{'WARNING'}, \code{'ERROR'},
+                        \code{'CRITICAL'}).}
+\lineii{\%(asctime)s}  {Human-readable time when the \class{LogRecord}
+                        was created.  By default this is of the form
+                        ``2003-07-08 16:49:45,896'' (the numbers after the
+                        comma are millisecond portion of the time).}
+\lineii{\%(message)s}  {The logged message.}
+\end{tableii}
+
+To change the date/time format, you can pass an additional keyword parameter,
+\var{datefmt}, as in the following:
+
+\begin{verbatim}
+import logging
+
+logging.basicConfig(level=logging.DEBUG,
+                    format='%(asctime)s %(levelname)-8s %(message)s',
+                    datefmt='%a, %d %b %Y %H:%M:%S',
+                    filename='/temp/myapp.log',
+                    filemode='w')
+logging.debug('A debug message')
+logging.info('Some information')
+logging.warning('A shot across the bows')
+\end{verbatim}
+
+which would result in output like
+
+\begin{verbatim}
+Fri, 02 Jul 2004 13:06:18 DEBUG    A debug message
+Fri, 02 Jul 2004 13:06:18 INFO     Some information
+Fri, 02 Jul 2004 13:06:18 WARNING  A shot across the bows
+\end{verbatim}
+
+The date format string follows the requirements of \function{strftime()} -
+see the documentation for the \refmodule{time} module.
+
+If, instead of sending logging output to the console or a file, you'd rather
+use a file-like object which you have created separately, you can pass it
+to \function{basicConfig()} using the \var{stream} keyword argument. Note
+that if both \var{stream} and \var{filename} keyword arguments are passed,
+the \var{stream} argument is ignored.
+
+Of course, you can put variable information in your output. To do this,
+simply have the message be a format string and pass in additional arguments
+containing the variable information, as in the following example:
+
+\begin{verbatim}
+import logging
+
+logging.basicConfig(level=logging.DEBUG,
+                    format='%(asctime)s %(levelname)-8s %(message)s',
+                    datefmt='%a, %d %b %Y %H:%M:%S',
+                    filename='/temp/myapp.log',
+                    filemode='w')
+logging.error('Pack my box with %d dozen %s', 5, 'liquor jugs')
+\end{verbatim}
+
+which would result in
+
+\begin{verbatim}
+Wed, 21 Jul 2004 15:35:16 ERROR    Pack my box with 5 dozen liquor jugs
+\end{verbatim}
+
+\subsection{Logging to multiple destinations \label{multiple-destinations}}
+
+Let's say you want to log to console and file with different message formats
+and in differing circumstances. Say you want to log messages with levels
+of DEBUG and higher to file, and those messages at level INFO and higher to
+the console. Let's also assume that the file should contain timestamps, but
+the console messages should not. Here's how you can achieve this:
+
+\begin{verbatim}
+import logging
+
+# set up logging to file - see previous section for more details
+logging.basicConfig(level=logging.DEBUG,
+                    format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
+                    datefmt='%m-%d %H:%M',
+                    filename='/temp/myapp.log',
+                    filemode='w')
+# define a Handler which writes INFO messages or higher to the sys.stderr
+console = logging.StreamHandler()
+console.setLevel(logging.INFO)
+# set a format which is simpler for console use
+formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
+# tell the handler to use this format
+console.setFormatter(formatter)
+# add the handler to the root logger
+logging.getLogger('').addHandler(console)
+
+# Now, we can log to the root logger, or any other logger. First the root...
+logging.info('Jackdaws love my big sphinx of quartz.')
+
+# Now, define a couple of other loggers which might represent areas in your
+# application:
+
+logger1 = logging.getLogger('myapp.area1')
+logger2 = logging.getLogger('myapp.area2')
+
+logger1.debug('Quick zephyrs blow, vexing daft Jim.')
+logger1.info('How quickly daft jumping zebras vex.')
+logger2.warning('Jail zesty vixen who grabbed pay from quack.')
+logger2.error('The five boxing wizards jump quickly.')
+\end{verbatim}
+
+When you run this, on the console you will see
+
+\begin{verbatim}
+root        : INFO     Jackdaws love my big sphinx of quartz.
+myapp.area1 : INFO     How quickly daft jumping zebras vex.
+myapp.area2 : WARNING  Jail zesty vixen who grabbed pay from quack.
+myapp.area2 : ERROR    The five boxing wizards jump quickly.
+\end{verbatim}
+
+and in the file you will see something like
+
+\begin{verbatim}
+10-22 22:19 root         INFO     Jackdaws love my big sphinx of quartz.
+10-22 22:19 myapp.area1  DEBUG    Quick zephyrs blow, vexing daft Jim.
+10-22 22:19 myapp.area1  INFO     How quickly daft jumping zebras vex.
+10-22 22:19 myapp.area2  WARNING  Jail zesty vixen who grabbed pay from quack.
+10-22 22:19 myapp.area2  ERROR    The five boxing wizards jump quickly.
+\end{verbatim}
+
+As you can see, the DEBUG message only shows up in the file. The other
+messages are sent to both destinations.
+
+This example uses console and file handlers, but you can use any number and
+combination of handlers you choose.
+
+\subsection{Sending and receiving logging events across a network
+\label{network-logging}}
+
+Let's say you want to send logging events across a network, and handle them
+at the receiving end. A simple way of doing this is attaching a
+\class{SocketHandler} instance to the root logger at the sending end:
+
+\begin{verbatim}
+import logging, logging.handlers
+
+rootLogger = logging.getLogger('')
+rootLogger.setLevel(logging.DEBUG)
+socketHandler = logging.handlers.SocketHandler('localhost',
+                    logging.handlers.DEFAULT_TCP_LOGGING_PORT)
+# don't bother with a formatter, since a socket handler sends the event as
+# an unformatted pickle
+rootLogger.addHandler(socketHandler)
+
+# Now, we can log to the root logger, or any other logger. First the root...
+logging.info('Jackdaws love my big sphinx of quartz.')
+
+# Now, define a couple of other loggers which might represent areas in your
+# application:
+
+logger1 = logging.getLogger('myapp.area1')
+logger2 = logging.getLogger('myapp.area2')
+
+logger1.debug('Quick zephyrs blow, vexing daft Jim.')
+logger1.info('How quickly daft jumping zebras vex.')
+logger2.warning('Jail zesty vixen who grabbed pay from quack.')
+logger2.error('The five boxing wizards jump quickly.')
+\end{verbatim}
+
+At the receiving end, you can set up a receiver using the
+\module{SocketServer} module. Here is a basic working example:
+
+\begin{verbatim}
+import cPickle
+import logging
+import logging.handlers
+import SocketServer
+import struct
+
+
+class LogRecordStreamHandler(SocketServer.StreamRequestHandler):
+    """Handler for a streaming logging request.
+
+    This basically logs the record using whatever logging policy is
+    configured locally.
+    """
+
+    def handle(self):
+        """
+        Handle multiple requests - each expected to be a 4-byte length,
+        followed by the LogRecord in pickle format. Logs the record
+        according to whatever policy is configured locally.
+        """
+        while 1:
+            chunk = self.connection.recv(4)
+            if len(chunk) < 4:
+                break
+            slen = struct.unpack(">L", chunk)[0]
+            chunk = self.connection.recv(slen)
+            while len(chunk) < slen:
+                chunk = chunk + self.connection.recv(slen - len(chunk))
+            obj = self.unPickle(chunk)
+            record = logging.makeLogRecord(obj)
+            self.handleLogRecord(record)
+
+    def unPickle(self, data):
+        return cPickle.loads(data)
+
+    def handleLogRecord(self, record):
+        # if a name is specified, we use the named logger rather than the one
+        # implied by the record.
+        if self.server.logname is not None:
+            name = self.server.logname
+        else:
+            name = record.name
+        logger = logging.getLogger(name)
+        # N.B. EVERY record gets logged. This is because Logger.handle
+        # is normally called AFTER logger-level filtering. If you want
+        # to do filtering, do it at the client end to save wasting
+        # cycles and network bandwidth!
+        logger.handle(record)
+
+class LogRecordSocketReceiver(SocketServer.ThreadingTCPServer):
+    """simple TCP socket-based logging receiver suitable for testing.
+    """
+
+    allow_reuse_address = 1
+
+    def __init__(self, host='localhost',
+                 port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
+                 handler=LogRecordStreamHandler):
+        SocketServer.ThreadingTCPServer.__init__(self, (host, port), handler)
+        self.abort = 0
+        self.timeout = 1
+        self.logname = None
+
+    def serve_until_stopped(self):
+        import select
+        abort = 0
+        while not abort:
+            rd, wr, ex = select.select([self.socket.fileno()],
+                                       [], [],
+                                       self.timeout)
+            if rd:
+                self.handle_request()
+            abort = self.abort
+
+def main():
+    logging.basicConfig(
+        format="%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s")
+    tcpserver = LogRecordSocketReceiver()
+    print "About to start TCP server..."
+    tcpserver.serve_until_stopped()
+
+if __name__ == "__main__":
+    main()
+\end{verbatim}
+
+First run the server, and then the client. On the client side, nothing is
+printed on the console; on the server side, you should see something like:
+
+\begin{verbatim}
+About to start TCP server...
+   59 root            INFO     Jackdaws love my big sphinx of quartz.
+   59 myapp.area1     DEBUG    Quick zephyrs blow, vexing daft Jim.
+   69 myapp.area1     INFO     How quickly daft jumping zebras vex.
+   69 myapp.area2     WARNING  Jail zesty vixen who grabbed pay from quack.
+   69 myapp.area2     ERROR    The five boxing wizards jump quickly.
+\end{verbatim}
+
+\subsection{Handler Objects}
+
+Handlers have the following attributes and methods. Note that
+\class{Handler} is never instantiated directly; this class acts as a
+base for more useful subclasses. However, the \method{__init__()}
+method in subclasses needs to call \method{Handler.__init__()}.
+
+\begin{methoddesc}{__init__}{level=\constant{NOTSET}}
+Initializes the \class{Handler} instance by setting its level, setting
+the list of filters to the empty list and creating a lock (using
+\method{createLock()}) for serializing access to an I/O mechanism.
+\end{methoddesc}
+
+\begin{methoddesc}{createLock}{}
+Initializes a thread lock which can be used to serialize access to
+underlying I/O functionality which may not be threadsafe.
+\end{methoddesc}
+
+\begin{methoddesc}{acquire}{}
+Acquires the thread lock created with \method{createLock()}.
+\end{methoddesc}
+
+\begin{methoddesc}{release}{}
+Releases the thread lock acquired with \method{acquire()}.
+\end{methoddesc}
+
+\begin{methoddesc}{setLevel}{lvl}
+Sets the threshold for this handler to \var{lvl}. Logging messages which are
+less severe than \var{lvl} will be ignored. When a handler is created, the
+level is set to \constant{NOTSET} (which causes all messages to be processed).
+\end{methoddesc}
+
+\begin{methoddesc}{setFormatter}{form}
+Sets the \class{Formatter} for this handler to \var{form}.
+\end{methoddesc}
+
+\begin{methoddesc}{addFilter}{filt}
+Adds the specified filter \var{filt} to this handler.
+\end{methoddesc}
+
+\begin{methoddesc}{removeFilter}{filt}
+Removes the specified filter \var{filt} from this handler.
+\end{methoddesc}
+
+\begin{methoddesc}{filter}{record}
+Applies this handler's filters to the record and returns a true value if
+the record is to be processed.
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{}
+Ensure all logging output has been flushed. This version does
+nothing and is intended to be implemented by subclasses.
+\end{methoddesc}
+
+\begin{methoddesc}{close}{}
+Tidy up any resources used by the handler. This version does
+nothing and is intended to be implemented by subclasses.
+\end{methoddesc}
+
+\begin{methoddesc}{handle}{record}
+Conditionally emits the specified logging record, depending on
+filters which may have been added to the handler. Wraps the actual
+emission of the record with acquisition/release of the I/O thread
+lock.
+\end{methoddesc}
+
+\begin{methoddesc}{handleError}{record}
+This method should be called from handlers when an exception is
+encountered during an \method{emit()} call. By default it does nothing,
+which means that exceptions get silently ignored. This is what is
+mostly wanted for a logging system - most users will not care
+about errors in the logging system, they are more interested in
+application errors. You could, however, replace this with a custom
+handler if you wish. The specified record is the one which was being
+processed when the exception occurred.
+\end{methoddesc}
+
+\begin{methoddesc}{format}{record}
+Do formatting for a record - if a formatter is set, use it.
+Otherwise, use the default formatter for the module.
+\end{methoddesc}
+
+\begin{methoddesc}{emit}{record}
+Do whatever it takes to actually log the specified logging record.
+This version is intended to be implemented by subclasses and so
+raises a \exception{NotImplementedError}.
+\end{methoddesc}
+
+\subsubsection{StreamHandler}
+
+The \class{StreamHandler} class, located in the core \module{logging}
+package, sends logging output to streams such as \var{sys.stdout},
+\var{sys.stderr} or any file-like object (or, more precisely, any
+object which supports \method{write()} and \method{flush()} methods).
+
+\begin{classdesc}{StreamHandler}{\optional{strm}}
+Returns a new instance of the \class{StreamHandler} class. If \var{strm} is
+specified, the instance will use it for logging output; otherwise,
+\var{sys.stderr} will be used.
+\end{classdesc}
+
+\begin{methoddesc}{emit}{record}
+If a formatter is specified, it is used to format the record.
+The record is then written to the stream with a trailing newline.
+If exception information is present, it is formatted using
+\function{traceback.print_exception()} and appended to the stream.
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{}
+Flushes the stream by calling its \method{flush()} method. Note that
+the \method{close()} method is inherited from \class{Handler} and
+so does nothing, so an explicit \method{flush()} call may be needed
+at times.
+\end{methoddesc}
+
+\subsubsection{FileHandler}
+
+The \class{FileHandler} class, located in the core \module{logging}
+package, sends logging output to a disk file.  It inherits the output
+functionality from \class{StreamHandler}.
+
+\begin{classdesc}{FileHandler}{filename\optional{, mode}}
+Returns a new instance of the \class{FileHandler} class. The specified
+file is opened and used as the stream for logging. If \var{mode} is
+not specified, \constant{'a'} is used. By default, the file grows
+indefinitely.
+\end{classdesc}
+
+\begin{methoddesc}{close}{}
+Closes the file.
+\end{methoddesc}
+
+\begin{methoddesc}{emit}{record}
+Outputs the record to the file.
+\end{methoddesc}
+
+\subsubsection{RotatingFileHandler}
+
+The \class{RotatingFileHandler} class, located in the \module{logging.handlers}
+module, supports rotation of disk log files.
+
+\begin{classdesc}{RotatingFileHandler}{filename\optional{, mode\optional{,
+                                       maxBytes\optional{, backupCount}}}}
+Returns a new instance of the \class{RotatingFileHandler} class. The
+specified file is opened and used as the stream for logging. If
+\var{mode} is not specified, \code{'a'} is used. By default, the
+file grows indefinitely.
+
+You can use the \var{maxBytes} and
+\var{backupCount} values to allow the file to \dfn{rollover} at a
+predetermined size. When the size is about to be exceeded, the file is
+closed and a new file is silently opened for output. Rollover occurs
+whenever the current log file is nearly \var{maxBytes} in length; if
+\var{maxBytes} is zero, rollover never occurs.  If \var{backupCount}
+is non-zero, the system will save old log files by appending the
+extensions ".1", ".2" etc., to the filename. For example, with
+a \var{backupCount} of 5 and a base file name of
+\file{app.log}, you would get \file{app.log},
+\file{app.log.1}, \file{app.log.2}, up to \file{app.log.5}. The file being
+written to is always \file{app.log}.  When this file is filled, it is
+closed and renamed to \file{app.log.1}, and if files \file{app.log.1},
+\file{app.log.2}, etc.  exist, then they are renamed to \file{app.log.2},
+\file{app.log.3} etc.  respectively.
+\end{classdesc}
+
+\begin{methoddesc}{doRollover}{}
+Does a rollover, as described above.
+\end{methoddesc}
+
+\begin{methoddesc}{emit}{record}
+Outputs the record to the file, catering for rollover as described previously.
+\end{methoddesc}
+
+\subsubsection{TimedRotatingFileHandler}
+
+The \class{TimedRotatingFileHandler} class, located in the
+\module{logging.handlers} module, supports rotation of disk log files
+at certain timed intervals.
+
+\begin{classdesc}{TimedRotatingFileHandler}{filename
+                                            \optional{,when
+                                            \optional{,interval
+                                            \optional{,backupCount}}}}
+
+Returns a new instance of the \class{TimedRotatingFileHandler} class. The
+specified file is opened and used as the stream for logging. On rotating
+it also sets the filename suffix. Rotating happens based on the product
+of \var{when} and \var{interval}.
+
+You can use the \var{when} to specify the type of \var{interval}. The
+list of possible values is, note that they are not case sensitive:
+
+\begin{tableii}{l|l}{}{Value}{Type of interval}
+  \lineii{S}{Seconds}
+  \lineii{M}{Minutes}
+  \lineii{H}{Hours}
+  \lineii{D}{Days}
+  \lineii{W}{Week day (0=Monday)}
+  \lineii{midnight}{Roll over at midnight}
+\end{tableii}
+
+If \var{backupCount} is non-zero, the system will save old log files by
+appending extensions to the filename. The extensions are date-and-time
+based, using the strftime format \code{\%Y-\%m-\%d_\%H-\%M-\%S} or a leading
+portion thereof, depending on the rollover interval. At most \var{backupCount}
+files will be kept, and if more would be created when rollover occurs, the
+oldest one is deleted.
+\end{classdesc}
+
+\begin{methoddesc}{doRollover}{}
+Does a rollover, as described above.
+\end{methoddesc}
+
+\begin{methoddesc}{emit}{record}
+Outputs the record to the file, catering for rollover as described
+above.
+\end{methoddesc}
+
+\subsubsection{SocketHandler}
+
+The \class{SocketHandler} class, located in the
+\module{logging.handlers} module, sends logging output to a network
+socket. The base class uses a TCP socket.
+
+\begin{classdesc}{SocketHandler}{host, port}
+Returns a new instance of the \class{SocketHandler} class intended to
+communicate with a remote machine whose address is given by \var{host}
+and \var{port}.
+\end{classdesc}
+
+\begin{methoddesc}{close}{}
+Closes the socket.
+\end{methoddesc}
+
+\begin{methoddesc}{handleError}{}
+\end{methoddesc}
+
+\begin{methoddesc}{emit}{}
+Pickles the record's attribute dictionary and writes it to the socket in
+binary format. If there is an error with the socket, silently drops the
+packet. If the connection was previously lost, re-establishes the connection.
+To unpickle the record at the receiving end into a \class{LogRecord}, use the
+\function{makeLogRecord()} function.
+\end{methoddesc}
+
+\begin{methoddesc}{handleError}{}
+Handles an error which has occurred during \method{emit()}. The
+most likely cause is a lost connection. Closes the socket so that
+we can retry on the next event.
+\end{methoddesc}
+
+\begin{methoddesc}{makeSocket}{}
+This is a factory method which allows subclasses to define the precise
+type of socket they want. The default implementation creates a TCP
+socket (\constant{socket.SOCK_STREAM}).
+\end{methoddesc}
+
+\begin{methoddesc}{makePickle}{record}
+Pickles the record's attribute dictionary in binary format with a length
+prefix, and returns it ready for transmission across the socket.
+\end{methoddesc}
+
+\begin{methoddesc}{send}{packet}
+Send a pickled string \var{packet} to the socket. This function allows
+for partial sends which can happen when the network is busy.
+\end{methoddesc}
+
+\subsubsection{DatagramHandler}
+
+The \class{DatagramHandler} class, located in the
+\module{logging.handlers} module, inherits from \class{SocketHandler}
+to support sending logging messages over UDP sockets.
+
+\begin{classdesc}{DatagramHandler}{host, port}
+Returns a new instance of the \class{DatagramHandler} class intended to
+communicate with a remote machine whose address is given by \var{host}
+and \var{port}.
+\end{classdesc}
+
+\begin{methoddesc}{emit}{}
+Pickles the record's attribute dictionary and writes it to the socket in
+binary format. If there is an error with the socket, silently drops the
+packet.
+To unpickle the record at the receiving end into a \class{LogRecord}, use the
+\function{makeLogRecord()} function.
+\end{methoddesc}
+
+\begin{methoddesc}{makeSocket}{}
+The factory method of \class{SocketHandler} is here overridden to create
+a UDP socket (\constant{socket.SOCK_DGRAM}).
+\end{methoddesc}
+
+\begin{methoddesc}{send}{s}
+Send a pickled string to a socket.
+\end{methoddesc}
+
+\subsubsection{SysLogHandler}
+
+The \class{SysLogHandler} class, located in the
+\module{logging.handlers} module, supports sending logging messages to
+a remote or local \UNIX{} syslog.
+
+\begin{classdesc}{SysLogHandler}{\optional{address\optional{, facility}}}
+Returns a new instance of the \class{SysLogHandler} class intended to
+communicate with a remote \UNIX{} machine whose address is given by
+\var{address} in the form of a \code{(\var{host}, \var{port})}
+tuple.  If \var{address} is not specified, \code{('localhost', 514)} is
+used.  The address is used to open a UDP socket.  If \var{facility} is
+not specified, \constant{LOG_USER} is used.
+\end{classdesc}
+
+\begin{methoddesc}{close}{}
+Closes the socket to the remote host.
+\end{methoddesc}
+
+\begin{methoddesc}{emit}{record}
+The record is formatted, and then sent to the syslog server. If
+exception information is present, it is \emph{not} sent to the server.
+\end{methoddesc}
+
+\begin{methoddesc}{encodePriority}{facility, priority}
+Encodes the facility and priority into an integer. You can pass in strings
+or integers - if strings are passed, internal mapping dictionaries are used
+to convert them to integers.
+\end{methoddesc}
+
+\subsubsection{NTEventLogHandler}
+
+The \class{NTEventLogHandler} class, located in the
+\module{logging.handlers} module, supports sending logging messages to
+a local Windows NT, Windows 2000 or Windows XP event log. Before you
+can use it, you need Mark Hammond's Win32 extensions for Python
+installed.
+
+\begin{classdesc}{NTEventLogHandler}{appname\optional{,
+                                     dllname\optional{, logtype}}}
+Returns a new instance of the \class{NTEventLogHandler} class. The
+\var{appname} is used to define the application name as it appears in the
+event log. An appropriate registry entry is created using this name.
+The \var{dllname} should give the fully qualified pathname of a .dll or .exe
+which contains message definitions to hold in the log (if not specified,
+\code{'win32service.pyd'} is used - this is installed with the Win32
+extensions and contains some basic placeholder message definitions.
+Note that use of these placeholders will make your event logs big, as the
+entire message source is held in the log. If you want slimmer logs, you have
+to pass in the name of your own .dll or .exe which contains the message
+definitions you want to use in the event log). The \var{logtype} is one of
+\code{'Application'}, \code{'System'} or \code{'Security'}, and
+defaults to \code{'Application'}.
+\end{classdesc}
+
+\begin{methoddesc}{close}{}
+At this point, you can remove the application name from the registry as a
+source of event log entries. However, if you do this, you will not be able
+to see the events as you intended in the Event Log Viewer - it needs to be
+able to access the registry to get the .dll name. The current version does
+not do this (in fact it doesn't do anything).
+\end{methoddesc}
+
+\begin{methoddesc}{emit}{record}
+Determines the message ID, event category and event type, and then logs the
+message in the NT event log.
+\end{methoddesc}
+
+\begin{methoddesc}{getEventCategory}{record}
+Returns the event category for the record. Override this if you
+want to specify your own categories. This version returns 0.
+\end{methoddesc}
+
+\begin{methoddesc}{getEventType}{record}
+Returns the event type for the record. Override this if you want
+to specify your own types. This version does a mapping using the
+handler's typemap attribute, which is set up in \method{__init__()}
+to a dictionary which contains mappings for \constant{DEBUG},
+\constant{INFO}, \constant{WARNING}, \constant{ERROR} and
+\constant{CRITICAL}. If you are using your own levels, you will either need
+to override this method or place a suitable dictionary in the
+handler's \var{typemap} attribute.
+\end{methoddesc}
+
+\begin{methoddesc}{getMessageID}{record}
+Returns the message ID for the record. If you are using your
+own messages, you could do this by having the \var{msg} passed to the
+logger being an ID rather than a format string. Then, in here,
+you could use a dictionary lookup to get the message ID. This
+version returns 1, which is the base message ID in
+\file{win32service.pyd}.
+\end{methoddesc}
+
+\subsubsection{SMTPHandler}
+
+The \class{SMTPHandler} class, located in the
+\module{logging.handlers} module, supports sending logging messages to
+an email address via SMTP.
+
+\begin{classdesc}{SMTPHandler}{mailhost, fromaddr, toaddrs, subject}
+Returns a new instance of the \class{SMTPHandler} class. The
+instance is initialized with the from and to addresses and subject
+line of the email. The \var{toaddrs} should be a list of strings. To specify a
+non-standard SMTP port, use the (host, port) tuple format for the
+\var{mailhost} argument. If you use a string, the standard SMTP port
+is used.
+\end{classdesc}
+
+\begin{methoddesc}{emit}{record}
+Formats the record and sends it to the specified addressees.
+\end{methoddesc}
+
+\begin{methoddesc}{getSubject}{record}
+If you want to specify a subject line which is record-dependent,
+override this method.
+\end{methoddesc}
+
+\subsubsection{MemoryHandler}
+
+The \class{MemoryHandler} class, located in the
+\module{logging.handlers} module, supports buffering of logging
+records in memory, periodically flushing them to a \dfn{target}
+handler. Flushing occurs whenever the buffer is full, or when an event
+of a certain severity or greater is seen.
+
+\class{MemoryHandler} is a subclass of the more general
+\class{BufferingHandler}, which is an abstract class. This buffers logging
+records in memory. Whenever each record is added to the buffer, a
+check is made by calling \method{shouldFlush()} to see if the buffer
+should be flushed.  If it should, then \method{flush()} is expected to
+do the needful.
+
+\begin{classdesc}{BufferingHandler}{capacity}
+Initializes the handler with a buffer of the specified capacity.
+\end{classdesc}
+
+\begin{methoddesc}{emit}{record}
+Appends the record to the buffer. If \method{shouldFlush()} returns true,
+calls \method{flush()} to process the buffer.
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{}
+You can override this to implement custom flushing behavior. This version
+just zaps the buffer to empty.
+\end{methoddesc}
+
+\begin{methoddesc}{shouldFlush}{record}
+Returns true if the buffer is up to capacity. This method can be
+overridden to implement custom flushing strategies.
+\end{methoddesc}
+
+\begin{classdesc}{MemoryHandler}{capacity\optional{, flushLevel
+\optional{, target}}}
+Returns a new instance of the \class{MemoryHandler} class. The
+instance is initialized with a buffer size of \var{capacity}. If
+\var{flushLevel} is not specified, \constant{ERROR} is used. If no
+\var{target} is specified, the target will need to be set using
+\method{setTarget()} before this handler does anything useful.
+\end{classdesc}
+
+\begin{methoddesc}{close}{}
+Calls \method{flush()}, sets the target to \constant{None} and
+clears the buffer.
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{}
+For a \class{MemoryHandler}, flushing means just sending the buffered
+records to the target, if there is one. Override if you want
+different behavior.
+\end{methoddesc}
+
+\begin{methoddesc}{setTarget}{target}
+Sets the target handler for this handler.
+\end{methoddesc}
+
+\begin{methoddesc}{shouldFlush}{record}
+Checks for buffer full or a record at the \var{flushLevel} or higher.
+\end{methoddesc}
+
+\subsubsection{HTTPHandler}
+
+The \class{HTTPHandler} class, located in the
+\module{logging.handlers} module, supports sending logging messages to
+a Web server, using either \samp{GET} or \samp{POST} semantics.
+
+\begin{classdesc}{HTTPHandler}{host, url\optional{, method}}
+Returns a new instance of the \class{HTTPHandler} class. The
+instance is initialized with a host address, url and HTTP method.
+The \var{host} can be of the form \code{host:port}, should you need to
+use a specific port number. If no \var{method} is specified, \samp{GET}
+is used.
+\end{classdesc}
+
+\begin{methoddesc}{emit}{record}
+Sends the record to the Web server as an URL-encoded dictionary.
+\end{methoddesc}
+
+\subsection{Formatter Objects}
+
+\class{Formatter}s have the following attributes and methods. They are
+responsible for converting a \class{LogRecord} to (usually) a string
+which can be interpreted by either a human or an external system. The
+base
+\class{Formatter} allows a formatting string to be specified. If none is
+supplied, the default value of \code{'\%(message)s'} is used.
+
+A Formatter can be initialized with a format string which makes use of
+knowledge of the \class{LogRecord} attributes - such as the default value
+mentioned above making use of the fact that the user's message and
+arguments are pre-formatted into a \class{LogRecord}'s \var{message}
+attribute.  This format string contains standard python \%-style
+mapping keys. See section \ref{typesseq-strings}, ``String Formatting
+Operations,'' for more information on string formatting.
+
+Currently, the useful mapping keys in a \class{LogRecord} are:
+
+\begin{tableii}{l|l}{code}{Format}{Description}
+\lineii{\%(name)s}     {Name of the logger (logging channel).}
+\lineii{\%(levelno)s}  {Numeric logging level for the message
+                        (\constant{DEBUG}, \constant{INFO},
+                        \constant{WARNING}, \constant{ERROR},
+                        \constant{CRITICAL}).}
+\lineii{\%(levelname)s}{Text logging level for the message
+                        (\code{'DEBUG'}, \code{'INFO'},
+                        \code{'WARNING'}, \code{'ERROR'},
+                        \code{'CRITICAL'}).}
+\lineii{\%(pathname)s} {Full pathname of the source file where the logging
+                        call was issued (if available).}
+\lineii{\%(filename)s} {Filename portion of pathname.}
+\lineii{\%(module)s}   {Module (name portion of filename).}
+\lineii{\%(funcName)s} {Name of function containing the logging call.}
+\lineii{\%(lineno)d}   {Source line number where the logging call was issued
+                        (if available).}
+\lineii{\%(created)f}  {Time when the \class{LogRecord} was created (as
+                        returned by \function{time.time()}).}
+\lineii{\%(relativeCreated)d}  {Time in milliseconds when the LogRecord was
+                        created, relative to the time the logging module was
+                        loaded.}
+\lineii{\%(asctime)s}  {Human-readable time when the \class{LogRecord}
+                        was created.  By default this is of the form
+                        ``2003-07-08 16:49:45,896'' (the numbers after the
+                        comma are millisecond portion of the time).}
+\lineii{\%(msecs)d}    {Millisecond portion of the time when the
+                        \class{LogRecord} was created.}
+\lineii{\%(thread)d}   {Thread ID (if available).}
+\lineii{\%(threadName)s}   {Thread name (if available).}
+\lineii{\%(process)d}  {Process ID (if available).}
+\lineii{\%(message)s}  {The logged message, computed as \code{msg \% args}.}
+\end{tableii}
+
+\versionchanged[\var{funcName} was added]{2.5}
+
+\begin{classdesc}{Formatter}{\optional{fmt\optional{, datefmt}}}
+Returns a new instance of the \class{Formatter} class. The
+instance is initialized with a format string for the message as a whole,
+as well as a format string for the date/time portion of a message. If
+no \var{fmt} is specified, \code{'\%(message)s'} is used. If no \var{datefmt}
+is specified, the ISO8601 date format is used.
+\end{classdesc}
+
+\begin{methoddesc}{format}{record}
+The record's attribute dictionary is used as the operand to a
+string formatting operation. Returns the resulting string.
+Before formatting the dictionary, a couple of preparatory steps
+are carried out. The \var{message} attribute of the record is computed
+using \var{msg} \% \var{args}. If the formatting string contains
+\code{'(asctime)'}, \method{formatTime()} is called to format the
+event time. If there is exception information, it is formatted using
+\method{formatException()} and appended to the message.
+\end{methoddesc}
+
+\begin{methoddesc}{formatTime}{record\optional{, datefmt}}
+This method should be called from \method{format()} by a formatter which
+wants to make use of a formatted time. This method can be overridden
+in formatters to provide for any specific requirement, but the
+basic behavior is as follows: if \var{datefmt} (a string) is specified,
+it is used with \function{time.strftime()} to format the creation time of the
+record. Otherwise, the ISO8601 format is used. The resulting
+string is returned.
+\end{methoddesc}
+
+\begin{methoddesc}{formatException}{exc_info}
+Formats the specified exception information (a standard exception tuple
+as returned by \function{sys.exc_info()}) as a string. This default
+implementation just uses \function{traceback.print_exception()}.
+The resulting string is returned.
+\end{methoddesc}
+
+\subsection{Filter Objects}
+
+\class{Filter}s can be used by \class{Handler}s and \class{Logger}s for
+more sophisticated filtering than is provided by levels. The base filter
+class only allows events which are below a certain point in the logger
+hierarchy. For example, a filter initialized with "A.B" will allow events
+logged by loggers "A.B", "A.B.C", "A.B.C.D", "A.B.D" etc. but not "A.BB",
+"B.A.B" etc. If initialized with the empty string, all events are passed.
+
+\begin{classdesc}{Filter}{\optional{name}}
+Returns an instance of the \class{Filter} class. If \var{name} is specified,
+it names a logger which, together with its children, will have its events
+allowed through the filter. If no name is specified, allows every event.
+\end{classdesc}
+
+\begin{methoddesc}{filter}{record}
+Is the specified record to be logged? Returns zero for no, nonzero for
+yes. If deemed appropriate, the record may be modified in-place by this
+method.
+\end{methoddesc}
+
+\subsection{LogRecord Objects}
+
+\class{LogRecord} instances are created every time something is logged. They
+contain all the information pertinent to the event being logged. The
+main information passed in is in msg and args, which are combined
+using msg \% args to create the message field of the record. The record
+also includes information such as when the record was created, the
+source line where the logging call was made, and any exception
+information to be logged.
+
+\begin{classdesc}{LogRecord}{name, lvl, pathname, lineno, msg, args,
+                             exc_info \optional{, func}}
+Returns an instance of \class{LogRecord} initialized with interesting
+information. The \var{name} is the logger name; \var{lvl} is the
+numeric level; \var{pathname} is the absolute pathname of the source
+file in which the logging call was made; \var{lineno} is the line
+number in that file where the logging call is found; \var{msg} is the
+user-supplied message (a format string); \var{args} is the tuple
+which, together with \var{msg}, makes up the user message; and
+\var{exc_info} is the exception tuple obtained by calling
+\function{sys.exc_info() }(or \constant{None}, if no exception information
+is available). The \var{func} is the name of the function from which the
+logging call was made. If not specified, it defaults to \var{None}.
+\versionchanged[\var{func} was added]{2.5}
+\end{classdesc}
+
+\begin{methoddesc}{getMessage}{}
+Returns the message for this \class{LogRecord} instance after merging any
+user-supplied arguments with the message.
+\end{methoddesc}
+
+\subsection{Thread Safety}
+
+The logging module is intended to be thread-safe without any special work
+needing to be done by its clients. It achieves this though using threading
+locks; there is one lock to serialize access to the module's shared data,
+and each handler also creates a lock to serialize access to its underlying
+I/O.
+
+\subsection{Configuration}
+
+
+\subsubsection{Configuration functions%
+               \label{logging-config-api}}
+
+The following functions configure the logging module. They are located in the
+\module{logging.config} module.  Their use is optional --- you can configure
+the logging module using these functions or by making calls to the
+main API (defined in \module{logging} itself) and defining handlers
+which are declared either in \module{logging} or
+\module{logging.handlers}.
+
+\begin{funcdesc}{fileConfig}{fname\optional{, defaults}}
+Reads the logging configuration from a ConfigParser-format file named
+\var{fname}. This function can be called several times from an application,
+allowing an end user the ability to select from various pre-canned
+configurations (if the developer provides a mechanism to present the
+choices and load the chosen configuration). Defaults to be passed to
+ConfigParser can be specified in the \var{defaults} argument.
+\end{funcdesc}
+
+\begin{funcdesc}{listen}{\optional{port}}
+Starts up a socket server on the specified port, and listens for new
+configurations. If no port is specified, the module's default
+\constant{DEFAULT_LOGGING_CONFIG_PORT} is used. Logging configurations
+will be sent as a file suitable for processing by \function{fileConfig()}.
+Returns a \class{Thread} instance on which you can call \method{start()}
+to start the server, and which you can \method{join()} when appropriate.
+To stop the server, call \function{stopListening()}. To send a configuration
+to the socket, read in the configuration file and send it to the socket
+as a string of bytes preceded by a four-byte length packed in binary using
+struct.\code{pack('>L', n)}.
+\end{funcdesc}
+
+\begin{funcdesc}{stopListening}{}
+Stops the listening server which was created with a call to
+\function{listen()}. This is typically called before calling \method{join()}
+on the return value from \function{listen()}.
+\end{funcdesc}
+
+\subsubsection{Configuration file format%
+               \label{logging-config-fileformat}}
+
+The configuration file format understood by \function{fileConfig()} is
+based on ConfigParser functionality. The file must contain sections
+called \code{[loggers]}, \code{[handlers]} and \code{[formatters]}
+which identify by name the entities of each type which are defined in
+the file. For each such entity, there is a separate section which
+identified how that entity is configured. Thus, for a logger named
+\code{log01} in the \code{[loggers]} section, the relevant
+configuration details are held in a section
+\code{[logger_log01]}. Similarly, a handler called \code{hand01} in
+the \code{[handlers]} section will have its configuration held in a
+section called \code{[handler_hand01]}, while a formatter called
+\code{form01} in the \code{[formatters]} section will have its
+configuration specified in a section called
+\code{[formatter_form01]}. The root logger configuration must be
+specified in a section called \code{[logger_root]}.
+
+Examples of these sections in the file are given below.
+
+\begin{verbatim}
+[loggers]
+keys=root,log02,log03,log04,log05,log06,log07
+
+[handlers]
+keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
+
+[formatters]
+keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
+\end{verbatim}
+
+The root logger must specify a level and a list of handlers. An
+example of a root logger section is given below.
+
+\begin{verbatim}
+[logger_root]
+level=NOTSET
+handlers=hand01
+\end{verbatim}
+
+The \code{level} entry can be one of \code{DEBUG, INFO, WARNING,
+ERROR, CRITICAL} or \code{NOTSET}. For the root logger only,
+\code{NOTSET} means that all messages will be logged. Level values are
+\function{eval()}uated in the context of the \code{logging} package's
+namespace.
+
+The \code{handlers} entry is a comma-separated list of handler names,
+which must appear in the \code{[handlers]} section. These names must
+appear in the \code{[handlers]} section and have corresponding
+sections in the configuration file.
+
+For loggers other than the root logger, some additional information is
+required. This is illustrated by the following example.
+
+\begin{verbatim}
+[logger_parser]
+level=DEBUG
+handlers=hand01
+propagate=1
+qualname=compiler.parser
+\end{verbatim}
+
+The \code{level} and \code{handlers} entries are interpreted as for
+the root logger, except that if a non-root logger's level is specified
+as \code{NOTSET}, the system consults loggers higher up the hierarchy
+to determine the effective level of the logger. The \code{propagate}
+entry is set to 1 to indicate that messages must propagate to handlers
+higher up the logger hierarchy from this logger, or 0 to indicate that
+messages are \strong{not} propagated to handlers up the hierarchy. The
+\code{qualname} entry is the hierarchical channel name of the logger,
+that is to say the name used by the application to get the logger.
+
+Sections which specify handler configuration are exemplified by the
+following.
+
+\begin{verbatim}
+[handler_hand01]
+class=StreamHandler
+level=NOTSET
+formatter=form01
+args=(sys.stdout,)
+\end{verbatim}
+
+The \code{class} entry indicates the handler's class (as determined by
+\function{eval()} in the \code{logging} package's namespace). The
+\code{level} is interpreted as for loggers, and \code{NOTSET} is taken
+to mean "log everything".
+
+The \code{formatter} entry indicates the key name of the formatter for
+this handler. If blank, a default formatter
+(\code{logging._defaultFormatter}) is used. If a name is specified, it
+must appear in the \code{[formatters]} section and have a
+corresponding section in the configuration file.
+
+The \code{args} entry, when \function{eval()}uated in the context of
+the \code{logging} package's namespace, is the list of arguments to
+the constructor for the handler class. Refer to the constructors for
+the relevant handlers, or to the examples below, to see how typical
+entries are constructed.
+
+\begin{verbatim}
+[handler_hand02]
+class=FileHandler
+level=DEBUG
+formatter=form02
+args=('python.log', 'w')
+
+[handler_hand03]
+class=handlers.SocketHandler
+level=INFO
+formatter=form03
+args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
+
+[handler_hand04]
+class=handlers.DatagramHandler
+level=WARN
+formatter=form04
+args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
+
+[handler_hand05]
+class=handlers.SysLogHandler
+level=ERROR
+formatter=form05
+args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
+
+[handler_hand06]
+class=handlers.NTEventLogHandler
+level=CRITICAL
+formatter=form06
+args=('Python Application', '', 'Application')
+
+[handler_hand07]
+class=handlers.SMTPHandler
+level=WARN
+formatter=form07
+args=('localhost', 'from@abc', ['user1@abc', 'user2@xyz'], 'Logger Subject')
+
+[handler_hand08]
+class=handlers.MemoryHandler
+level=NOTSET
+formatter=form08
+target=
+args=(10, ERROR)
+
+[handler_hand09]
+class=handlers.HTTPHandler
+level=NOTSET
+formatter=form09
+args=('localhost:9022', '/log', 'GET')
+\end{verbatim}
+
+Sections which specify formatter configuration are typified by the following.
+
+\begin{verbatim}
+[formatter_form01]
+format=F1 %(asctime)s %(levelname)s %(message)s
+datefmt=
+class=logging.Formatter
+\end{verbatim}
+
+The \code{format} entry is the overall format string, and the
+\code{datefmt} entry is the \function{strftime()}-compatible date/time format
+string. If empty, the package substitutes ISO8601 format date/times, which
+is almost equivalent to specifying the date format string "%Y-%m-%d %H:%M:%S".
+The ISO8601 format also specifies milliseconds, which are appended to the
+result of using the above format string, with a comma separator. An example
+time in ISO8601 format is \code{2003-01-23 00:29:50,411}.
+
+The \code{class} entry is optional.  It indicates the name of the
+formatter's class (as a dotted module and class name.)  This option is
+useful for instantiating a \class{Formatter} subclass.  Subclasses of
+\class{Formatter} can present exception tracebacks in an expanded or
+condensed format.
diff --git a/sys/src/cmd/python/Doc/lib/libmailbox.tex b/sys/src/cmd/python/Doc/lib/libmailbox.tex
new file mode 100644
index 000000000..24765c8d3
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmailbox.tex
@@ -0,0 +1,1444 @@
+\section{\module{mailbox} ---
+          Manipulate mailboxes in various formats}
+
+\declaremodule{}{mailbox}
+\moduleauthor{Gregory K.~Johnson}{gkj@gregorykjohnson.com}
+\sectionauthor{Gregory K.~Johnson}{gkj@gregorykjohnson.com}
+\modulesynopsis{Manipulate mailboxes in various formats}
+
+
+This module defines two classes, \class{Mailbox} and \class{Message}, for
+accessing and manipulating on-disk mailboxes and the messages they contain.
+\class{Mailbox} offers a dictionary-like mapping from keys to messages.
+\class{Message} extends the \module{email.Message} module's \class{Message}
+class with format-specific state and behavior. Supported mailbox formats are
+Maildir, mbox, MH, Babyl, and MMDF.
+
+\begin{seealso}
+    \seemodule{email}{Represent and manipulate messages.}
+\end{seealso}
+
+\subsection{\class{Mailbox} objects}
+\label{mailbox-objects}
+
+\begin{classdesc*}{Mailbox}
+A mailbox, which may be inspected and modified.
+\end{classdesc*}
+
+The \class{Mailbox} class defines an interface and
+is not intended to be instantiated.  Instead, format-specific
+subclasses should inherit from \class{Mailbox} and your code
+should instantiate a particular subclass.
+
+The \class{Mailbox} interface is dictionary-like, with small keys
+corresponding to messages. Keys are issued by the \class{Mailbox}
+instance with which they will be used and are only meaningful to that
+\class{Mailbox} instance. A key continues to identify a message even
+if the corresponding message is modified, such as by replacing it with
+another message.
+
+Messages may be added to a \class{Mailbox} instance using the set-like
+method \method{add()} and removed using a \code{del} statement or the
+set-like methods \method{remove()} and \method{discard()}.
+
+\class{Mailbox} interface semantics differ from dictionary semantics in some
+noteworthy ways. Each time a message is requested, a new
+representation (typically a \class{Message} instance) is generated
+based upon the current state of the mailbox. Similarly, when a message
+is added to a \class{Mailbox} instance, the provided message
+representation's contents are copied. In neither case is a reference
+to the message representation kept by the \class{Mailbox} instance.
+
+The default \class{Mailbox} iterator iterates over message representations, not
+keys as the default dictionary iterator does. Moreover, modification of a
+mailbox during iteration is safe and well-defined. Messages added to the
+mailbox after an iterator is created will not be seen by the iterator. Messages
+removed from the mailbox before the iterator yields them will be silently
+skipped, though using a key from an iterator may result in a
+\exception{KeyError} exception if the corresponding message is subsequently
+removed.
+
+\begin{notice}[warning]
+Be very cautious when modifying mailboxes that might be
+simultaneously changed by some other process.  The safest mailbox
+format to use for such tasks is Maildir; try to avoid using
+single-file formats such as mbox for concurrent writing.  If you're
+modifying a mailbox, you
+\emph{must} lock it by calling the \method{lock()} and
+\method{unlock()} methods \emph{before} reading any messages in the file
+or making any changes by adding or deleting a message.  Failing to
+lock the mailbox runs the risk of losing messages or corrupting the entire
+mailbox.
+\end{notice}
+
+\class{Mailbox} instances have the following methods:
+
+\begin{methoddesc}{add}{message}
+Add \var{message} to the mailbox and return the key that has been assigned to
+it.
+
+Parameter \var{message} may be a \class{Message} instance, an
+\class{email.Message.Message} instance, a string, or a file-like object (which
+should be open in text mode). If \var{message} is an instance of the
+appropriate format-specific \class{Message} subclass (e.g., if it's an
+\class{mboxMessage} instance and this is an \class{mbox} instance), its
+format-specific information is used. Otherwise, reasonable defaults for
+format-specific information are used.
+\end{methoddesc}
+
+\begin{methoddesc}{remove}{key}
+\methodline{__delitem__}{key}
+\methodline{discard}{key}
+Delete the message corresponding to \var{key} from the mailbox.
+
+If no such message exists, a \exception{KeyError} exception is raised if the
+method was called as \method{remove()} or \method{__delitem__()} but no
+exception is raised if the method was called as \method{discard()}. The
+behavior of \method{discard()} may be preferred if the underlying mailbox
+format supports concurrent modification by other processes.
+\end{methoddesc}
+
+\begin{methoddesc}{__setitem__}{key, message}
+Replace the message corresponding to \var{key} with \var{message}. Raise a
+\exception{KeyError} exception if no message already corresponds to \var{key}.
+
+As with \method{add()}, parameter \var{message} may be a \class{Message}
+instance, an \class{email.Message.Message} instance, a string, or a file-like
+object (which should be open in text mode). If \var{message} is an instance of
+the appropriate format-specific \class{Message} subclass (e.g., if it's an
+\class{mboxMessage} instance and this is an \class{mbox} instance), its
+format-specific information is used. Otherwise, the format-specific information
+of the message that currently corresponds to \var{key} is left unchanged. 
+\end{methoddesc}
+
+\begin{methoddesc}{iterkeys}{}
+\methodline{keys}{}
+Return an iterator over all keys if called as \method{iterkeys()} or return a
+list of keys if called as \method{keys()}.
+\end{methoddesc}
+
+\begin{methoddesc}{itervalues}{}
+\methodline{__iter__}{}
+\methodline{values}{}
+Return an iterator over representations of all messages if called as
+\method{itervalues()} or \method{__iter__()} or return a list of such
+representations if called as \method{values()}. The messages are represented as
+instances of the appropriate format-specific \class{Message} subclass unless a
+custom message factory was specified when the \class{Mailbox} instance was
+initialized. \note{The behavior of \method{__iter__()} is unlike that of
+dictionaries, which iterate over keys.}
+\end{methoddesc}
+
+\begin{methoddesc}{iteritems}{}
+\methodline{items}{}
+Return an iterator over (\var{key}, \var{message}) pairs, where \var{key} is a
+key and \var{message} is a message representation, if called as
+\method{iteritems()} or return a list of such pairs if called as
+\method{items()}. The messages are represented as instances of the appropriate
+format-specific \class{Message} subclass unless a custom message factory was
+specified when the \class{Mailbox} instance was initialized.
+\end{methoddesc}
+
+\begin{methoddesc}{get}{key\optional{, default=None}}
+\methodline{__getitem__}{key}
+Return a representation of the message corresponding to \var{key}. If no such
+message exists, \var{default} is returned if the method was called as
+\method{get()} and a \exception{KeyError} exception is raised if the method was
+called as \method{__getitem__()}. The message is represented as an instance of
+the appropriate format-specific \class{Message} subclass unless a custom
+message factory was specified when the \class{Mailbox} instance was
+initialized.
+\end{methoddesc}
+
+\begin{methoddesc}{get_message}{key}
+Return a representation of the message corresponding to \var{key} as an
+instance of the appropriate format-specific \class{Message} subclass, or raise
+a \exception{KeyError} exception if no such message exists.
+\end{methoddesc}
+
+\begin{methoddesc}{get_string}{key}
+Return a string representation of the message corresponding to \var{key}, or
+raise a \exception{KeyError} exception if no such message exists.
+\end{methoddesc}
+
+\begin{methoddesc}{get_file}{key}
+Return a file-like representation of the message corresponding to \var{key},
+or raise a \exception{KeyError} exception if no such message exists. The
+file-like object behaves as if open in binary mode. This file should be closed
+once it is no longer needed.
+
+\note{Unlike other representations of messages, file-like representations are
+not necessarily independent of the \class{Mailbox} instance that created them
+or of the underlying mailbox. More specific documentation is provided by each
+subclass.}
+\end{methoddesc}
+
+\begin{methoddesc}{has_key}{key}
+\methodline{__contains__}{key}
+Return \code{True} if \var{key} corresponds to a message, \code{False}
+otherwise.
+\end{methoddesc}
+
+\begin{methoddesc}{__len__}{}
+Return a count of messages in the mailbox.
+\end{methoddesc}
+
+\begin{methoddesc}{clear}{}
+Delete all messages from the mailbox.
+\end{methoddesc}
+
+\begin{methoddesc}{pop}{key\optional{, default}}
+Return a representation of the message corresponding to \var{key} and delete
+the message. If no such message exists, return \var{default} if it was supplied
+or else raise a \exception{KeyError} exception. The message is represented as
+an instance of the appropriate format-specific \class{Message} subclass unless
+a custom message factory was specified when the \class{Mailbox} instance was
+initialized.
+\end{methoddesc}
+
+\begin{methoddesc}{popitem}{}
+Return an arbitrary (\var{key}, \var{message}) pair, where \var{key} is a key
+and \var{message} is a message representation, and delete the corresponding
+message. If the mailbox is empty, raise a \exception{KeyError} exception. The
+message is represented as an instance of the appropriate format-specific
+\class{Message} subclass unless a custom message factory was specified when the
+\class{Mailbox} instance was initialized.
+\end{methoddesc}
+
+\begin{methoddesc}{update}{arg}
+Parameter \var{arg} should be a \var{key}-to-\var{message} mapping or an
+iterable of (\var{key}, \var{message}) pairs. Updates the mailbox so that, for
+each given \var{key} and \var{message}, the message corresponding to \var{key}
+is set to \var{message} as if by using \method{__setitem__()}. As with
+\method{__setitem__()}, each \var{key} must already correspond to a message in
+the mailbox or else a \exception{KeyError} exception will be raised, so in
+general it is incorrect for \var{arg} to be a \class{Mailbox} instance.
+\note{Unlike with dictionaries, keyword arguments are not supported.}
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{}
+Write any pending changes to the filesystem. For some \class{Mailbox}
+subclasses, changes are always written immediately and \method{flush()} does
+nothing, but you should still make a habit of calling this method.
+\end{methoddesc}
+
+\begin{methoddesc}{lock}{}
+Acquire an exclusive advisory lock on the mailbox so that other processes know
+not to modify it. An \exception{ExternalClashError} is raised if the lock is
+not available. The particular locking mechanisms used depend upon the mailbox
+format.  You should \emph{always} lock the mailbox before making any 
+modifications to its contents.
+\end{methoddesc}
+
+\begin{methoddesc}{unlock}{}
+Release the lock on the mailbox, if any.
+\end{methoddesc}
+
+\begin{methoddesc}{close}{}
+Flush the mailbox, unlock it if necessary, and close any open files. For some
+\class{Mailbox} subclasses, this method does nothing.
+\end{methoddesc}
+
+
+\subsubsection{\class{Maildir}}
+\label{mailbox-maildir}
+
+\begin{classdesc}{Maildir}{dirname\optional{, factory=rfc822.Message\optional{,
+create=True}}}
+A subclass of \class{Mailbox} for mailboxes in Maildir format. Parameter
+\var{factory} is a callable object that accepts a file-like message
+representation (which behaves as if opened in binary mode) and returns a custom
+representation. If \var{factory} is \code{None}, \class{MaildirMessage} is used
+as the default message representation. If \var{create} is \code{True}, the
+mailbox is created if it does not exist.
+
+It is for historical reasons that \var{factory} defaults to
+\class{rfc822.Message} and that \var{dirname} is named as such rather than
+\var{path}. For a \class{Maildir} instance that behaves like instances of other
+\class{Mailbox} subclasses, set \var{factory} to \code{None}.
+\end{classdesc}
+
+Maildir is a directory-based mailbox format invented for the qmail mail
+transfer agent and now widely supported by other programs. Messages in a
+Maildir mailbox are stored in separate files within a common directory
+structure. This design allows Maildir mailboxes to be accessed and modified by
+multiple unrelated programs without data corruption, so file locking is
+unnecessary.
+
+Maildir mailboxes contain three subdirectories, namely: \file{tmp}, \file{new},
+and \file{cur}. Messages are created momentarily in the \file{tmp} subdirectory
+and then moved to the \file{new} subdirectory to finalize delivery. A mail user
+agent may subsequently move the message to the \file{cur} subdirectory and
+store information about the state of the message in a special "info" section
+appended to its file name.
+
+Folders of the style introduced by the Courier mail transfer agent are also
+supported. Any subdirectory of the main mailbox is considered a folder if
+\character{.} is the first character in its name. Folder names are represented
+by \class{Maildir} without the leading \character{.}. Each folder is itself a
+Maildir mailbox but should not contain other folders. Instead, a logical
+nesting is indicated using \character{.} to delimit levels, e.g.,
+"Archived.2005.07".
+
+\begin{notice}
+The Maildir specification requires the use of a colon (\character{:}) in
+certain message file names. However, some operating systems do not permit this
+character in file names, If you wish to use a Maildir-like format on such an
+operating system, you should specify another character to use instead. The
+exclamation point (\character{!}) is a popular choice. For example:
+\begin{verbatim}
+import mailbox
+mailbox.Maildir.colon = '!'
+\end{verbatim}
+The \member{colon} attribute may also be set on a per-instance basis.
+\end{notice}
+
+\class{Maildir} instances have all of the methods of \class{Mailbox} in
+addition to the following:
+
+\begin{methoddesc}{list_folders}{}
+Return a list of the names of all folders.
+\end{methoddesc}
+
+\begin{methoddesc}{get_folder}{folder}
+Return a \class{Maildir} instance representing the folder whose name is
+\var{folder}. A \exception{NoSuchMailboxError} exception is raised if the
+folder does not exist.
+\end{methoddesc}
+
+\begin{methoddesc}{add_folder}{folder}
+Create a folder whose name is \var{folder} and return a \class{Maildir}
+instance representing it.
+\end{methoddesc}
+
+\begin{methoddesc}{remove_folder}{folder}
+Delete the folder whose name is \var{folder}. If the folder contains any
+messages, a \exception{NotEmptyError} exception will be raised and the folder
+will not be deleted.
+\end{methoddesc}
+
+\begin{methoddesc}{clean}{}
+Delete temporary files from the mailbox that have not been accessed in the
+last 36 hours. The Maildir specification says that mail-reading programs
+should do this occasionally.
+\end{methoddesc}
+
+Some \class{Mailbox} methods implemented by \class{Maildir} deserve special
+remarks:
+
+\begin{methoddesc}{add}{message}
+\methodline[Maildir]{__setitem__}{key, message}
+\methodline[Maildir]{update}{arg}
+\warning{These methods generate unique file names based upon the current
+process ID. When using multiple threads, undetected name clashes may occur and
+cause corruption of the mailbox unless threads are coordinated to avoid using
+these methods to manipulate the same mailbox simultaneously.}
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{}
+All changes to Maildir mailboxes are immediately applied, so this method does
+nothing.
+\end{methoddesc}
+
+\begin{methoddesc}{lock}{}
+\methodline{unlock}{}
+Maildir mailboxes do not support (or require) locking, so these methods do
+nothing. 
+\end{methoddesc}
+
+\begin{methoddesc}{close}{}
+\class{Maildir} instances do not keep any open files and the underlying
+mailboxes do not support locking, so this method does nothing.
+\end{methoddesc}
+
+\begin{methoddesc}{get_file}{key}
+Depending upon the host platform, it may not be possible to modify or remove
+the underlying message while the returned file remains open.
+\end{methoddesc}
+
+\begin{seealso}
+    \seelink{http://www.qmail.org/man/man5/maildir.html}{maildir man page from
+    qmail}{The original specification of the format.}
+    \seelink{http://cr.yp.to/proto/maildir.html}{Using maildir format}{Notes
+    on Maildir by its inventor. Includes an updated name-creation scheme and
+    details on "info" semantics.}
+    \seelink{http://www.courier-mta.org/?maildir.html}{maildir man page from
+    Courier}{Another specification of the format. Describes a common extension
+    for supporting folders.}
+\end{seealso}
+
+\subsubsection{\class{mbox}}
+\label{mailbox-mbox}
+
+\begin{classdesc}{mbox}{path\optional{, factory=None\optional{, create=True}}}
+A subclass of \class{Mailbox} for mailboxes in mbox format. Parameter
+\var{factory} is a callable object that accepts a file-like message
+representation (which behaves as if opened in binary mode) and returns a custom
+representation. If \var{factory} is \code{None}, \class{mboxMessage} is used as
+the default message representation. If \var{create} is \code{True}, the mailbox
+is created if it does not exist.
+\end{classdesc}
+
+The mbox format is the classic format for storing mail on \UNIX{} systems. All
+messages in an mbox mailbox are stored in a single file with the beginning of
+each message indicated by a line whose first five characters are "From~".
+
+Several variations of the mbox format exist to address perceived shortcomings
+in the original. In the interest of compatibility, \class{mbox} implements the
+original format, which is sometimes referred to as \dfn{mboxo}. This means that
+the \mailheader{Content-Length} header, if present, is ignored and that any
+occurrences of "From~" at the beginning of a line in a message body are
+transformed to ">From~" when storing the message, although occurences of
+">From~" are not transformed to "From~" when reading the message.
+
+Some \class{Mailbox} methods implemented by \class{mbox} deserve special
+remarks:
+
+\begin{methoddesc}{get_file}{key}
+Using the file after calling \method{flush()} or \method{close()} on the
+\class{mbox} instance may yield unpredictable results or raise an exception.
+\end{methoddesc}
+
+\begin{methoddesc}{lock}{}
+\methodline{unlock}{}
+Three locking mechanisms are used---dot locking and, if available, the
+\cfunction{flock()} and \cfunction{lockf()} system calls.
+\end{methoddesc}
+
+\begin{seealso}
+    \seelink{http://www.qmail.org/man/man5/mbox.html}{mbox man page from
+    qmail}{A specification of the format and its variations.}
+    \seelink{http://www.tin.org/bin/man.cgi?section=5\&topic=mbox}{mbox man
+    page from tin}{Another specification of the format, with details on
+    locking.}
+    \seelink{http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html}
+    {Configuring Netscape Mail on \UNIX{}: Why The Content-Length Format is
+    Bad}{An argument for using the original mbox format rather than a
+    variation.}
+    \seelink{http://homepages.tesco.net./\tilde{}J.deBoynePollard/FGA/mail-mbox-formats.html}
+    {"mbox" is a family of several mutually incompatible mailbox formats}{A
+    history of mbox variations.}
+\end{seealso}
+
+\subsubsection{\class{MH}}
+\label{mailbox-mh}
+
+\begin{classdesc}{MH}{path\optional{, factory=None\optional{, create=True}}}
+A subclass of \class{Mailbox} for mailboxes in MH format. Parameter
+\var{factory} is a callable object that accepts a file-like message
+representation (which behaves as if opened in binary mode) and returns a custom
+representation. If \var{factory} is \code{None}, \class{MHMessage} is used as
+the default message representation. If \var{create} is \code{True}, the mailbox
+is created if it does not exist.
+\end{classdesc}
+
+MH is a directory-based mailbox format invented for the MH Message Handling
+System, a mail user agent. Each message in an MH mailbox resides in its own
+file. An MH mailbox may contain other MH mailboxes (called \dfn{folders}) in
+addition to messages. Folders may be nested indefinitely. MH mailboxes also
+support \dfn{sequences}, which are named lists used to logically group messages
+without moving them to sub-folders. Sequences are defined in a file called
+\file{.mh_sequences} in each folder.
+
+The \class{MH} class manipulates MH mailboxes, but it does not attempt to
+emulate all of \program{mh}'s behaviors. In particular, it does not modify and
+is not affected by the \file{context} or \file{.mh_profile} files that are used
+by \program{mh} to store its state and configuration.
+
+\class{MH} instances have all of the methods of \class{Mailbox} in addition to
+the following:
+
+\begin{methoddesc}{list_folders}{}
+Return a list of the names of all folders.
+\end{methoddesc}
+
+\begin{methoddesc}{get_folder}{folder}
+Return an \class{MH} instance representing the folder whose name is
+\var{folder}. A \exception{NoSuchMailboxError} exception is raised if the
+folder does not exist.
+\end{methoddesc}
+
+\begin{methoddesc}{add_folder}{folder}
+Create a folder whose name is \var{folder} and return an \class{MH} instance
+representing it.
+\end{methoddesc}
+
+\begin{methoddesc}{remove_folder}{folder}
+Delete the folder whose name is \var{folder}. If the folder contains any
+messages, a \exception{NotEmptyError} exception will be raised and the folder
+will not be deleted.
+\end{methoddesc}
+
+\begin{methoddesc}{get_sequences}{}
+Return a dictionary of sequence names mapped to key lists. If there are no
+sequences, the empty dictionary is returned.
+\end{methoddesc}
+
+\begin{methoddesc}{set_sequences}{sequences}
+Re-define the sequences that exist in the mailbox based upon \var{sequences}, a
+dictionary of names mapped to key lists, like returned by
+\method{get_sequences()}.
+\end{methoddesc}
+
+\begin{methoddesc}{pack}{}
+Rename messages in the mailbox as necessary to eliminate gaps in numbering.
+Entries in the sequences list are updated correspondingly. \note{Already-issued
+keys are invalidated by this operation and should not be subsequently used.}
+\end{methoddesc}
+
+Some \class{Mailbox} methods implemented by \class{MH} deserve special remarks:
+
+\begin{methoddesc}{remove}{key}
+\methodline{__delitem__}{key}
+\methodline{discard}{key}
+These methods immediately delete the message. The MH convention of marking a
+message for deletion by prepending a comma to its name is not used.
+\end{methoddesc}
+
+\begin{methoddesc}{lock}{}
+\methodline{unlock}{}
+Three locking mechanisms are used---dot locking and, if available, the
+\cfunction{flock()} and \cfunction{lockf()} system calls. For MH mailboxes,
+locking the mailbox means locking the \file{.mh_sequences} file and, only for
+the duration of any operations that affect them, locking individual message
+files.
+\end{methoddesc}
+
+\begin{methoddesc}{get_file}{key}
+Depending upon the host platform, it may not be possible to remove the
+underlying message while the returned file remains open.
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{}
+All changes to MH mailboxes are immediately applied, so this method does
+nothing.
+\end{methoddesc}
+
+\begin{methoddesc}{close}{}
+\class{MH} instances do not keep any open files, so this method is equivelant
+to \method{unlock()}.
+\end{methoddesc}
+
+\begin{seealso}
+\seelink{http://www.nongnu.org/nmh/}{nmh - Message Handling System}{Home page
+of \program{nmh}, an updated version of the original \program{mh}.}
+\seelink{http://www.ics.uci.edu/\tilde{}mh/book/}{MH \& nmh: Email for Users \&
+Programmers}{A GPL-licensed book on \program{mh} and \program{nmh}, with some
+information on the mailbox format.}
+\end{seealso}
+
+\subsubsection{\class{Babyl}}
+\label{mailbox-babyl}
+
+\begin{classdesc}{Babyl}{path\optional{, factory=None\optional{, create=True}}}
+A subclass of \class{Mailbox} for mailboxes in Babyl format. Parameter
+\var{factory} is a callable object that accepts a file-like message
+representation (which behaves as if opened in binary mode) and returns a custom
+representation. If \var{factory} is \code{None}, \class{BabylMessage} is used
+as the default message representation. If \var{create} is \code{True}, the
+mailbox is created if it does not exist.
+\end{classdesc}
+
+Babyl is a single-file mailbox format used by the Rmail mail user agent
+included with Emacs. The beginning of a message is indicated by a line
+containing the two characters Control-Underscore
+(\character{\textbackslash037}) and Control-L (\character{\textbackslash014}).
+The end of a message is indicated by the start of the next message or, in the
+case of the last message, a line containing a Control-Underscore
+(\character{\textbackslash037}) character.
+
+Messages in a Babyl mailbox have two sets of headers, original headers and
+so-called visible headers. Visible headers are typically a subset of the
+original headers that have been reformatted or abridged to be more attractive.
+Each message in a Babyl mailbox also has an accompanying list of \dfn{labels},
+or short strings that record extra information about the message, and a list of
+all user-defined labels found in the mailbox is kept in the Babyl options
+section.
+
+\class{Babyl} instances have all of the methods of \class{Mailbox} in addition
+to the following:
+
+\begin{methoddesc}{get_labels}{}
+Return a list of the names of all user-defined labels used in the mailbox.
+\note{The actual messages are inspected to determine which labels exist in the
+mailbox rather than consulting the list of labels in the Babyl options section,
+but the Babyl section is updated whenever the mailbox is modified.}
+\end{methoddesc}
+
+Some \class{Mailbox} methods implemented by \class{Babyl} deserve special
+remarks:
+
+\begin{methoddesc}{get_file}{key}
+In Babyl mailboxes, the headers of a message are not stored contiguously with
+the body of the message. To generate a file-like representation, the headers
+and body are copied together into a \class{StringIO} instance (from the
+\module{StringIO} module), which has an API identical to that of a file. As a
+result, the file-like object is truly independent of the underlying mailbox but
+does not save memory compared to a string representation.
+\end{methoddesc}
+
+\begin{methoddesc}{lock}{}
+\methodline{unlock}{}
+Three locking mechanisms are used---dot locking and, if available, the
+\cfunction{flock()} and \cfunction{lockf()} system calls.
+\end{methoddesc}
+
+\begin{seealso}
+\seelink{http://quimby.gnus.org/notes/BABYL}{Format of Version 5 Babyl Files}{A
+specification of the Babyl format.}
+\seelink{http://www.gnu.org/software/emacs/manual/html_node/Rmail.html}{Reading
+Mail with Rmail}{The Rmail manual, with some information on Babyl semantics.}
+\end{seealso}
+
+\subsubsection{\class{MMDF}}
+\label{mailbox-mmdf}
+
+\begin{classdesc}{MMDF}{path\optional{, factory=None\optional{, create=True}}}
+A subclass of \class{Mailbox} for mailboxes in MMDF format. Parameter
+\var{factory} is a callable object that accepts a file-like message
+representation (which behaves as if opened in binary mode) and returns a custom
+representation. If \var{factory} is \code{None}, \class{MMDFMessage} is used as
+the default message representation. If \var{create} is \code{True}, the mailbox
+is created if it does not exist.
+\end{classdesc}
+
+MMDF is a single-file mailbox format invented for the Multichannel Memorandum
+Distribution Facility, a mail transfer agent. Each message is in the same form
+as an mbox message but is bracketed before and after by lines containing four
+Control-A (\character{\textbackslash001}) characters. As with the mbox format,
+the beginning of each message is indicated by a line whose first five
+characters are "From~", but additional occurrences of "From~" are not
+transformed to ">From~" when storing messages because the extra message
+separator lines prevent mistaking such occurrences for the starts of subsequent
+messages.
+
+Some \class{Mailbox} methods implemented by \class{MMDF} deserve special
+remarks:
+
+\begin{methoddesc}{get_file}{key}
+Using the file after calling \method{flush()} or \method{close()} on the
+\class{MMDF} instance may yield unpredictable results or raise an exception.
+\end{methoddesc}
+
+\begin{methoddesc}{lock}{}
+\methodline{unlock}{}
+Three locking mechanisms are used---dot locking and, if available, the
+\cfunction{flock()} and \cfunction{lockf()} system calls.
+\end{methoddesc}
+
+\begin{seealso}
+\seelink{http://www.tin.org/bin/man.cgi?section=5\&topic=mmdf}{mmdf man page
+from tin}{A specification of MMDF format from the documentation of tin, a
+newsreader.}
+\seelink{http://en.wikipedia.org/wiki/MMDF}{MMDF}{A Wikipedia article
+describing the Multichannel Memorandum Distribution Facility.}
+\end{seealso}
+
+\subsection{\class{Message} objects}
+\label{mailbox-message-objects}
+
+\begin{classdesc}{Message}{\optional{message}}
+A subclass of the \module{email.Message} module's \class{Message}. Subclasses
+of \class{mailbox.Message} add mailbox-format-specific state and behavior.
+
+If \var{message} is omitted, the new instance is created in a default, empty
+state. If \var{message} is an \class{email.Message.Message} instance, its
+contents are copied; furthermore, any format-specific information is converted
+insofar as possible if \var{message} is a \class{Message} instance. If
+\var{message} is a string or a file, it should contain an \rfc{2822}-compliant
+message, which is read and parsed.
+\end{classdesc}
+
+The format-specific state and behaviors offered by subclasses vary, but in
+general it is only the properties that are not specific to a particular mailbox
+that are supported (although presumably the properties are specific to a
+particular mailbox format). For example, file offsets for single-file mailbox
+formats and file names for directory-based mailbox formats are not retained,
+because they are only applicable to the original mailbox. But state such as
+whether a message has been read by the user or marked as important is retained,
+because it applies to the message itself.
+
+There is no requirement that \class{Message} instances be used to represent
+messages retrieved using \class{Mailbox} instances. In some situations, the
+time and memory required to generate \class{Message} representations might not
+not acceptable. For such situations, \class{Mailbox} instances also offer
+string and file-like representations, and a custom message factory may be
+specified when a \class{Mailbox} instance is initialized. 
+
+\subsubsection{\class{MaildirMessage}}
+\label{mailbox-maildirmessage}
+
+\begin{classdesc}{MaildirMessage}{\optional{message}}
+A message with Maildir-specific behaviors. Parameter \var{message}
+has the same meaning as with the \class{Message} constructor.
+\end{classdesc}
+
+Typically, a mail user agent application moves all of the messages in the
+\file{new} subdirectory to the \file{cur} subdirectory after the first time the
+user opens and closes the mailbox, recording that the messages are old whether
+or not they've actually been read. Each message in \file{cur} has an "info"
+section added to its file name to store information about its state. (Some mail
+readers may also add an "info" section to messages in \file{new}.) The "info"
+section may take one of two forms: it may contain "2," followed by a list of
+standardized flags (e.g., "2,FR") or it may contain "1," followed by so-called
+experimental information. Standard flags for Maildir messages are as follows:
+
+\begin{tableiii}{l|l|l}{textrm}{Flag}{Meaning}{Explanation}
+\lineiii{D}{Draft}{Under composition}
+\lineiii{F}{Flagged}{Marked as important}
+\lineiii{P}{Passed}{Forwarded, resent, or bounced}
+\lineiii{R}{Replied}{Replied to}
+\lineiii{S}{Seen}{Read}
+\lineiii{T}{Trashed}{Marked for subsequent deletion}
+\end{tableiii}
+
+\class{MaildirMessage} instances offer the following methods:
+
+\begin{methoddesc}{get_subdir}{}
+Return either "new" (if the message should be stored in the \file{new}
+subdirectory) or "cur" (if the message should be stored in the \file{cur}
+subdirectory). \note{A message is typically moved from \file{new} to \file{cur}
+after its mailbox has been accessed, whether or not the message is has been
+read. A message \code{msg} has been read if \code{"S" not in msg.get_flags()}
+is \code{True}.}
+\end{methoddesc}
+
+\begin{methoddesc}{set_subdir}{subdir}
+Set the subdirectory the message should be stored in. Parameter \var{subdir}
+must be either "new" or "cur".
+\end{methoddesc}
+
+\begin{methoddesc}{get_flags}{}
+Return a string specifying the flags that are currently set. If the message
+complies with the standard Maildir format, the result is the concatenation in
+alphabetical order of zero or one occurrence of each of \character{D},
+\character{F}, \character{P}, \character{R}, \character{S}, and \character{T}.
+The empty string is returned if no flags are set or if "info" contains
+experimental semantics.
+\end{methoddesc}
+
+\begin{methoddesc}{set_flags}{flags}
+Set the flags specified by \var{flags} and unset all others.
+\end{methoddesc}
+
+\begin{methoddesc}{add_flag}{flag}
+Set the flag(s) specified by \var{flag} without changing other flags. To add
+more than one flag at a time, \var{flag} may be a string of more than one
+character. The current "info" is overwritten whether or not it contains
+experimental information rather than
+flags.
+\end{methoddesc}
+
+\begin{methoddesc}{remove_flag}{flag}
+Unset the flag(s) specified by \var{flag} without changing other flags. To
+remove more than one flag at a time, \var{flag} maybe a string of more than one
+character. If "info" contains experimental information rather than flags, the
+current "info" is not modified.
+\end{methoddesc}
+
+\begin{methoddesc}{get_date}{}
+Return the delivery date of the message as a floating-point number representing
+seconds since the epoch.
+\end{methoddesc}
+
+\begin{methoddesc}{set_date}{date}
+Set the delivery date of the message to \var{date}, a floating-point number
+representing seconds since the epoch.
+\end{methoddesc}
+
+\begin{methoddesc}{get_info}{}
+Return a string containing the "info" for a message. This is useful for
+accessing and modifying "info" that is experimental (i.e., not a list of
+flags).
+\end{methoddesc}
+
+\begin{methoddesc}{set_info}{info}
+Set "info" to \var{info}, which should be a string.
+\end{methoddesc}
+
+When a \class{MaildirMessage} instance is created based upon an
+\class{mboxMessage} or \class{MMDFMessage} instance, the \mailheader{Status}
+and \mailheader{X-Status} headers are omitted and the following conversions
+take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{mboxMessage} or \class{MMDFMessage} state}
+\lineii{"cur" subdirectory}{O flag}
+\lineii{F flag}{F flag}
+\lineii{R flag}{A flag}
+\lineii{S flag}{R flag}
+\lineii{T flag}{D flag}
+\end{tableii}
+
+When a \class{MaildirMessage} instance is created based upon an
+\class{MHMessage} instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MHMessage} state}
+\lineii{"cur" subdirectory}{"unseen" sequence}
+\lineii{"cur" subdirectory and S flag}{no "unseen" sequence}
+\lineii{F flag}{"flagged" sequence}
+\lineii{R flag}{"replied" sequence}
+\end{tableii}
+
+When a \class{MaildirMessage} instance is created based upon a
+\class{BabylMessage} instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{BabylMessage} state}
+\lineii{"cur" subdirectory}{"unseen" label}
+\lineii{"cur" subdirectory and S flag}{no "unseen" label}
+\lineii{P flag}{"forwarded" or "resent" label}
+\lineii{R flag}{"answered" label}
+\lineii{T flag}{"deleted" label}
+\end{tableii}
+
+\subsubsection{\class{mboxMessage}}
+\label{mailbox-mboxmessage}
+
+\begin{classdesc}{mboxMessage}{\optional{message}}
+A message with mbox-specific behaviors. Parameter \var{message} has the same
+meaning as with the \class{Message} constructor.
+\end{classdesc}
+
+Messages in an mbox mailbox are stored together in a single file. The sender's
+envelope address and the time of delivery are typically stored in a line
+beginning with "From~" that is used to indicate the start of a message, though
+there is considerable variation in the exact format of this data among mbox
+implementations. Flags that indicate the state of the message, such as whether
+it has been read or marked as important, are typically stored in
+\mailheader{Status} and \mailheader{X-Status} headers.
+
+Conventional flags for mbox messages are as follows:
+
+\begin{tableiii}{l|l|l}{textrm}{Flag}{Meaning}{Explanation}
+\lineiii{R}{Read}{Read}
+\lineiii{O}{Old}{Previously detected by MUA}
+\lineiii{D}{Deleted}{Marked for subsequent deletion}
+\lineiii{F}{Flagged}{Marked as important}
+\lineiii{A}{Answered}{Replied to}
+\end{tableiii}
+
+The "R" and "O" flags are stored in the \mailheader{Status} header, and the
+"D", "F", and "A" flags are stored in the \mailheader{X-Status} header. The
+flags and headers typically appear in the order mentioned.
+
+\class{mboxMessage} instances offer the following methods:
+
+\begin{methoddesc}{get_from}{}
+Return a string representing the "From~" line that marks the start of the
+message in an mbox mailbox. The leading "From~" and the trailing newline are
+excluded.
+\end{methoddesc}
+
+\begin{methoddesc}{set_from}{from_\optional{, time_=None}}
+Set the "From~" line to \var{from_}, which should be specified without a
+leading "From~" or trailing newline. For convenience, \var{time_} may be
+specified and will be formatted appropriately and appended to \var{from_}. If
+\var{time_} is specified, it should be a \class{struct_time} instance, a tuple
+suitable for passing to \method{time.strftime()}, or \code{True} (to use
+\method{time.gmtime()}).
+\end{methoddesc}
+
+\begin{methoddesc}{get_flags}{}
+Return a string specifying the flags that are currently set. If the message
+complies with the conventional format, the result is the concatenation in the
+following order of zero or one occurrence of each of \character{R},
+\character{O}, \character{D}, \character{F}, and \character{A}.
+\end{methoddesc}
+
+\begin{methoddesc}{set_flags}{flags}
+Set the flags specified by \var{flags} and unset all others. Parameter
+\var{flags} should be the concatenation in any order of zero or more
+occurrences of each of \character{R}, \character{O}, \character{D},
+\character{F}, and \character{A}.
+\end{methoddesc}
+
+\begin{methoddesc}{add_flag}{flag}
+Set the flag(s) specified by \var{flag} without changing other flags. To add
+more than one flag at a time, \var{flag} may be a string of more than one
+character.
+\end{methoddesc}
+
+\begin{methoddesc}{remove_flag}{flag}
+Unset the flag(s) specified by \var{flag} without changing other flags. To
+remove more than one flag at a time, \var{flag} maybe a string of more than one
+character.
+\end{methoddesc}
+
+When an \class{mboxMessage} instance is created based upon a
+\class{MaildirMessage} instance, a "From~" line is generated based upon the
+\class{MaildirMessage} instance's delivery date, and the following conversions
+take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MaildirMessage} state}
+\lineii{R flag}{S flag}
+\lineii{O flag}{"cur" subdirectory}
+\lineii{D flag}{T flag}
+\lineii{F flag}{F flag}
+\lineii{A flag}{R flag}
+\end{tableii}
+
+When an \class{mboxMessage} instance is created based upon an \class{MHMessage}
+instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MHMessage} state}
+\lineii{R flag and O flag}{no "unseen" sequence}
+\lineii{O flag}{"unseen" sequence}
+\lineii{F flag}{"flagged" sequence}
+\lineii{A flag}{"replied" sequence}
+\end{tableii}
+
+When an \class{mboxMessage} instance is created based upon a
+\class{BabylMessage} instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{BabylMessage} state}
+\lineii{R flag and O flag}{no "unseen" label}
+\lineii{O flag}{"unseen" label}
+\lineii{D flag}{"deleted" label}
+\lineii{A flag}{"answered" label}
+\end{tableii}
+
+When a \class{Message} instance is created based upon an \class{MMDFMessage}
+instance, the "From~" line is copied and all flags directly correspond:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MMDFMessage} state}
+\lineii{R flag}{R flag}
+\lineii{O flag}{O flag}
+\lineii{D flag}{D flag}
+\lineii{F flag}{F flag}
+\lineii{A flag}{A flag}
+\end{tableii}
+
+\subsubsection{\class{MHMessage}}
+\label{mailbox-mhmessage}
+
+\begin{classdesc}{MHMessage}{\optional{message}}
+A message with MH-specific behaviors. Parameter \var{message} has the same
+meaning as with the \class{Message} constructor.
+\end{classdesc}
+
+MH messages do not support marks or flags in the traditional sense, but they do
+support sequences, which are logical groupings of arbitrary messages. Some mail
+reading programs (although not the standard \program{mh} and \program{nmh}) use
+sequences in much the same way flags are used with other formats, as follows:
+
+\begin{tableii}{l|l}{textrm}{Sequence}{Explanation}
+\lineii{unseen}{Not read, but previously detected by MUA}
+\lineii{replied}{Replied to}
+\lineii{flagged}{Marked as important}
+\end{tableii}
+
+\class{MHMessage} instances offer the following methods:
+
+\begin{methoddesc}{get_sequences}{}
+Return a list of the names of sequences that include this message.
+\end{methoddesc}
+
+\begin{methoddesc}{set_sequences}{sequences}
+Set the list of sequences that include this message.
+\end{methoddesc}
+
+\begin{methoddesc}{add_sequence}{sequence}
+Add \var{sequence} to the list of sequences that include this message.
+\end{methoddesc}
+
+\begin{methoddesc}{remove_sequence}{sequence}
+Remove \var{sequence} from the list of sequences that include this message.
+\end{methoddesc}
+
+When an \class{MHMessage} instance is created based upon a
+\class{MaildirMessage} instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MaildirMessage} state}
+\lineii{"unseen" sequence}{no S flag}
+\lineii{"replied" sequence}{R flag}
+\lineii{"flagged" sequence}{F flag}
+\end{tableii}
+
+When an \class{MHMessage} instance is created based upon an \class{mboxMessage}
+or \class{MMDFMessage} instance, the \mailheader{Status} and
+\mailheader{X-Status} headers are omitted and the following conversions take
+place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{mboxMessage} or \class{MMDFMessage} state}
+\lineii{"unseen" sequence}{no R flag}
+\lineii{"replied" sequence}{A flag}
+\lineii{"flagged" sequence}{F flag}
+\end{tableii}
+
+When an \class{MHMessage} instance is created based upon a \class{BabylMessage}
+instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{BabylMessage} state}
+\lineii{"unseen" sequence}{"unseen" label}
+\lineii{"replied" sequence}{"answered" label}
+\end{tableii}
+
+\subsubsection{\class{BabylMessage}}
+\label{mailbox-babylmessage}
+
+\begin{classdesc}{BabylMessage}{\optional{message}}
+A message with Babyl-specific behaviors. Parameter \var{message} has the same
+meaning as with the \class{Message} constructor.
+\end{classdesc}
+
+Certain message labels, called \dfn{attributes}, are defined by convention to
+have special meanings. The attributes are as follows:
+
+\begin{tableii}{l|l}{textrm}{Label}{Explanation}
+\lineii{unseen}{Not read, but previously detected by MUA}
+\lineii{deleted}{Marked for subsequent deletion}
+\lineii{filed}{Copied to another file or mailbox}
+\lineii{answered}{Replied to}
+\lineii{forwarded}{Forwarded}
+\lineii{edited}{Modified by the user}
+\lineii{resent}{Resent}
+\end{tableii}
+
+By default, Rmail displays only
+visible headers. The \class{BabylMessage} class, though, uses the original
+headers because they are more complete. Visible headers may be accessed
+explicitly if desired.
+
+\class{BabylMessage} instances offer the following methods:
+
+\begin{methoddesc}{get_labels}{}
+Return a list of labels on the message.
+\end{methoddesc}
+
+\begin{methoddesc}{set_labels}{labels}
+Set the list of labels on the message to \var{labels}.
+\end{methoddesc}
+
+\begin{methoddesc}{add_label}{label}
+Add \var{label} to the list of labels on the message.
+\end{methoddesc}
+
+\begin{methoddesc}{remove_label}{label}
+Remove \var{label} from the list of labels on the message.
+\end{methoddesc}
+
+\begin{methoddesc}{get_visible}{}
+Return an \class{Message} instance whose headers are the message's visible
+headers and whose body is empty.
+\end{methoddesc}
+
+\begin{methoddesc}{set_visible}{visible}
+Set the message's visible headers to be the same as the headers in
+\var{message}. Parameter \var{visible} should be a \class{Message} instance, an
+\class{email.Message.Message} instance, a string, or a file-like object (which
+should be open in text mode).
+\end{methoddesc}
+
+\begin{methoddesc}{update_visible}{}
+When a \class{BabylMessage} instance's original headers are modified, the
+visible headers are not automatically modified to correspond. This method
+updates the visible headers as follows: each visible header with a
+corresponding original header is set to the value of the original header, each
+visible header without a corresponding original header is removed, and any of
+\mailheader{Date}, \mailheader{From}, \mailheader{Reply-To}, \mailheader{To},
+\mailheader{CC}, and \mailheader{Subject} that are present in the original
+headers but not the visible headers are added to the visible headers.
+\end{methoddesc}
+
+When a \class{BabylMessage} instance is created based upon a
+\class{MaildirMessage} instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MaildirMessage} state}
+\lineii{"unseen" label}{no S flag}
+\lineii{"deleted" label}{T flag}
+\lineii{"answered" label}{R flag}
+\lineii{"forwarded" label}{P flag}
+\end{tableii}
+
+When a \class{BabylMessage} instance is created based upon an
+\class{mboxMessage} or \class{MMDFMessage} instance, the \mailheader{Status}
+and \mailheader{X-Status} headers are omitted and the following conversions
+take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{mboxMessage} or \class{MMDFMessage} state}
+\lineii{"unseen" label}{no R flag}
+\lineii{"deleted" label}{D flag}
+\lineii{"answered" label}{A flag}
+\end{tableii}
+
+When a \class{BabylMessage} instance is created based upon an \class{MHMessage}
+instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MHMessage} state}
+\lineii{"unseen" label}{"unseen" sequence}
+\lineii{"answered" label}{"replied" sequence}
+\end{tableii}
+
+\subsubsection{\class{MMDFMessage}}
+\label{mailbox-mmdfmessage}
+
+\begin{classdesc}{MMDFMessage}{\optional{message}}
+A message with MMDF-specific behaviors. Parameter \var{message} has the same
+meaning as with the \class{Message} constructor.
+\end{classdesc}
+
+As with message in an mbox mailbox, MMDF messages are stored with the sender's
+address and the delivery date in an initial line beginning with "From ".
+Likewise, flags that indicate the state of the message are typically stored in
+\mailheader{Status} and \mailheader{X-Status} headers.
+
+Conventional flags for MMDF messages are identical to those of mbox message and
+are as follows:
+
+\begin{tableiii}{l|l|l}{textrm}{Flag}{Meaning}{Explanation}
+\lineiii{R}{Read}{Read}
+\lineiii{O}{Old}{Previously detected by MUA}
+\lineiii{D}{Deleted}{Marked for subsequent deletion}
+\lineiii{F}{Flagged}{Marked as important}
+\lineiii{A}{Answered}{Replied to}
+\end{tableiii}
+
+The "R" and "O" flags are stored in the \mailheader{Status} header, and the
+"D", "F", and "A" flags are stored in the \mailheader{X-Status} header. The
+flags and headers typically appear in the order mentioned.
+
+\class{MMDFMessage} instances offer the following methods, which are identical
+to those offered by \class{mboxMessage}:
+
+\begin{methoddesc}{get_from}{}
+Return a string representing the "From~" line that marks the start of the
+message in an mbox mailbox. The leading "From~" and the trailing newline are
+excluded.
+\end{methoddesc}
+
+\begin{methoddesc}{set_from}{from_\optional{, time_=None}}
+Set the "From~" line to \var{from_}, which should be specified without a
+leading "From~" or trailing newline. For convenience, \var{time_} may be
+specified and will be formatted appropriately and appended to \var{from_}. If
+\var{time_} is specified, it should be a \class{struct_time} instance, a tuple
+suitable for passing to \method{time.strftime()}, or \code{True} (to use
+\method{time.gmtime()}).
+\end{methoddesc}
+
+\begin{methoddesc}{get_flags}{}
+Return a string specifying the flags that are currently set. If the message
+complies with the conventional format, the result is the concatenation in the
+following order of zero or one occurrence of each of \character{R},
+\character{O}, \character{D}, \character{F}, and \character{A}.
+\end{methoddesc}
+
+\begin{methoddesc}{set_flags}{flags}
+Set the flags specified by \var{flags} and unset all others. Parameter
+\var{flags} should be the concatenation in any order of zero or more
+occurrences of each of \character{R}, \character{O}, \character{D},
+\character{F}, and \character{A}.
+\end{methoddesc}
+
+\begin{methoddesc}{add_flag}{flag}
+Set the flag(s) specified by \var{flag} without changing other flags. To add
+more than one flag at a time, \var{flag} may be a string of more than one
+character.
+\end{methoddesc}
+
+\begin{methoddesc}{remove_flag}{flag}
+Unset the flag(s) specified by \var{flag} without changing other flags. To
+remove more than one flag at a time, \var{flag} maybe a string of more than one
+character.
+\end{methoddesc}
+
+When an \class{MMDFMessage} instance is created based upon a
+\class{MaildirMessage} instance, a "From~" line is generated based upon the
+\class{MaildirMessage} instance's delivery date, and the following conversions
+take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MaildirMessage} state}
+\lineii{R flag}{S flag}
+\lineii{O flag}{"cur" subdirectory}
+\lineii{D flag}{T flag}
+\lineii{F flag}{F flag}
+\lineii{A flag}{R flag}
+\end{tableii}
+
+When an \class{MMDFMessage} instance is created based upon an \class{MHMessage}
+instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{MHMessage} state}
+\lineii{R flag and O flag}{no "unseen" sequence}
+\lineii{O flag}{"unseen" sequence}
+\lineii{F flag}{"flagged" sequence}
+\lineii{A flag}{"replied" sequence}
+\end{tableii}
+
+When an \class{MMDFMessage} instance is created based upon a
+\class{BabylMessage} instance, the following conversions take place:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{BabylMessage} state}
+\lineii{R flag and O flag}{no "unseen" label}
+\lineii{O flag}{"unseen" label}
+\lineii{D flag}{"deleted" label}
+\lineii{A flag}{"answered" label}
+\end{tableii}
+
+When an \class{MMDFMessage} instance is created based upon an
+\class{mboxMessage} instance, the "From~" line is copied and all flags directly
+correspond:
+
+\begin{tableii}{l|l}{textrm}
+    {Resulting state}{\class{mboxMessage} state}
+\lineii{R flag}{R flag}
+\lineii{O flag}{O flag}
+\lineii{D flag}{D flag}
+\lineii{F flag}{F flag}
+\lineii{A flag}{A flag}
+\end{tableii}
+
+\subsection{Exceptions}
+\label{mailbox-deprecated}
+
+The following exception classes are defined in the \module{mailbox} module:
+
+\begin{classdesc}{Error}{}
+The based class for all other module-specific exceptions.
+\end{classdesc}
+
+\begin{classdesc}{NoSuchMailboxError}{}
+Raised when a mailbox is expected but is not found, such as when instantiating
+a \class{Mailbox} subclass with a path that does not exist (and with the
+\var{create} parameter set to \code{False}), or when opening a folder that does
+not exist.
+\end{classdesc}
+
+\begin{classdesc}{NotEmptyErrorError}{}
+Raised when a mailbox is not empty but is expected to be, such as when deleting
+a folder that contains messages.
+\end{classdesc}
+
+\begin{classdesc}{ExternalClashError}{}
+Raised when some mailbox-related condition beyond the control of the program
+causes it to be unable to proceed, such as when failing to acquire a lock that
+another program already holds a lock, or when a uniquely-generated file name
+already exists.
+\end{classdesc}
+
+\begin{classdesc}{FormatError}{}
+Raised when the data in a file cannot be parsed, such as when an \class{MH}
+instance attempts to read a corrupted \file{.mh_sequences} file.
+\end{classdesc}
+
+\subsection{Deprecated classes and methods}
+\label{mailbox-deprecated}
+
+Older versions of the \module{mailbox} module do not support modification of
+mailboxes, such as adding or removing message, and do not provide classes to
+represent format-specific message properties. For backward compatibility, the
+older mailbox classes are still available, but the newer classes should be used
+in preference to them.
+
+Older mailbox objects support only iteration and provide a single public
+method:
+
+\begin{methoddesc}{next}{}
+Return the next message in the mailbox, created with the optional \var{factory}
+argument passed into the mailbox object's constructor. By default this is an
+\class{rfc822.Message} object (see the \refmodule{rfc822} module).  Depending
+on the mailbox implementation the \var{fp} attribute of this object may be a
+true file object or a class instance simulating a file object, taking care of
+things like message boundaries if multiple mail messages are contained in a
+single file, etc.  If no more messages are available, this method returns
+\code{None}.
+\end{methoddesc}
+
+Most of the older mailbox classes have names that differ from the current
+mailbox class names, except for \class{Maildir}. For this reason, the new
+\class{Maildir} class defines a \method{next()} method and its constructor
+differs slightly from those of the other new mailbox classes.
+
+The older mailbox classes whose names are not the same as their newer
+counterparts are as follows:
+
+\begin{classdesc}{UnixMailbox}{fp\optional{, factory}}
+Access to a classic \UNIX-style mailbox, where all messages are
+contained in a single file and separated by \samp{From }
+(a.k.a.\ \samp{From_}) lines.  The file object \var{fp} points to the
+mailbox file.  The optional \var{factory} parameter is a callable that
+should create new message objects.  \var{factory} is called with one
+argument, \var{fp} by the \method{next()} method of the mailbox
+object.  The default is the \class{rfc822.Message} class (see the
+\refmodule{rfc822} module -- and the note below).
+
+\begin{notice}
+  For reasons of this module's internal implementation, you will
+  probably want to open the \var{fp} object in binary mode.  This is
+  especially important on Windows.
+\end{notice}
+
+For maximum portability, messages in a \UNIX-style mailbox are
+separated by any line that begins exactly with the string \code{'From
+'} (note the trailing space) if preceded by exactly two newlines.
+Because of the wide-range of variations in practice, nothing else on
+the From_ line should be considered.  However, the current
+implementation doesn't check for the leading two newlines.  This is
+usually fine for most applications.
+
+The \class{UnixMailbox} class implements a more strict version of
+From_ line checking, using a regular expression that usually correctly
+matched From_ delimiters.  It considers delimiter line to be separated
+by \samp{From \var{name} \var{time}} lines.  For maximum portability,
+use the \class{PortableUnixMailbox} class instead.  This class is
+identical to \class{UnixMailbox} except that individual messages are
+separated by only \samp{From } lines.
+
+For more information, see
+\citetitle[http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html]{Configuring
+Netscape Mail on \UNIX: Why the Content-Length Format is Bad}.
+\end{classdesc}
+
+\begin{classdesc}{PortableUnixMailbox}{fp\optional{, factory}}
+A less-strict version of \class{UnixMailbox}, which considers only the
+\samp{From } at the beginning of the line separating messages.  The
+``\var{name} \var{time}'' portion of the From line is ignored, to
+protect against some variations that are observed in practice.  This
+works since lines in the message which begin with \code{'From '} are
+quoted by mail handling software at delivery-time.
+\end{classdesc}
+
+\begin{classdesc}{MmdfMailbox}{fp\optional{, factory}}
+Access an MMDF-style mailbox, where all messages are contained
+in a single file and separated by lines consisting of 4 control-A
+characters.  The file object \var{fp} points to the mailbox file.
+Optional \var{factory} is as with the \class{UnixMailbox} class.
+\end{classdesc}
+
+\begin{classdesc}{MHMailbox}{dirname\optional{, factory}}
+Access an MH mailbox, a directory with each message in a separate
+file with a numeric name.
+The name of the mailbox directory is passed in \var{dirname}.
+\var{factory} is as with the \class{UnixMailbox} class.
+\end{classdesc}
+
+\begin{classdesc}{BabylMailbox}{fp\optional{, factory}}
+Access a Babyl mailbox, which is similar to an MMDF mailbox.  In
+Babyl format, each message has two sets of headers, the
+\emph{original} headers and the \emph{visible} headers.  The original
+headers appear before a line containing only \code{'*** EOOH ***'}
+(End-Of-Original-Headers) and the visible headers appear after the
+\code{EOOH} line.  Babyl-compliant mail readers will show you only the
+visible headers, and \class{BabylMailbox} objects will return messages
+containing only the visible headers.  You'll have to do your own
+parsing of the mailbox file to get at the original headers.  Mail
+messages start with the EOOH line and end with a line containing only
+\code{'\e{}037\e{}014'}.  \var{factory} is as with the
+\class{UnixMailbox} class.
+\end{classdesc}
+
+If you wish to use the older mailbox classes with the \module{email} module
+rather than the deprecated \module{rfc822} module, you can do so as follows:
+
+\begin{verbatim}
+import email
+import email.Errors
+import mailbox
+
+def msgfactory(fp):
+    try:
+        return email.message_from_file(fp)
+    except email.Errors.MessageParseError:
+        # Don't return None since that will
+        # stop the mailbox iterator
+        return ''
+
+mbox = mailbox.UnixMailbox(fp, msgfactory)
+\end{verbatim}
+
+Alternatively, if you know your mailbox contains only well-formed MIME
+messages, you can simplify this to:
+
+\begin{verbatim}
+import email
+import mailbox
+
+mbox = mailbox.UnixMailbox(fp, email.message_from_file)
+\end{verbatim}
+
+\subsection{Examples}
+\label{mailbox-examples}
+
+A simple example of printing the subjects of all messages in a mailbox that
+seem interesting:
+
+\begin{verbatim}
+import mailbox
+for message in mailbox.mbox('~/mbox'):
+    subject = message['subject']       # Could possibly be None.
+    if subject and 'python' in subject.lower():
+        print subject
+\end{verbatim}
+
+To copy all mail from a Babyl mailbox to an MH mailbox, converting all
+of the format-specific information that can be converted:
+
+\begin{verbatim}
+import mailbox
+destination = mailbox.MH('~/Mail')
+destination.lock()
+for message in mailbox.Babyl('~/RMAIL'):
+    destination.add(MHMessage(message))
+destination.flush()
+destination.unlock()
+\end{verbatim}
+
+This example sorts mail from several mailing lists into different
+mailboxes, being careful to avoid mail corruption due to concurrent
+modification by other programs, mail loss due to interruption of the
+program, or premature termination due to malformed messages in the
+mailbox:
+
+\begin{verbatim}
+import mailbox
+import email.Errors
+
+list_names = ('python-list', 'python-dev', 'python-bugs')
+
+boxes = dict((name, mailbox.mbox('~/email/%s' % name)) for name in list_names)
+inbox = mailbox.Maildir('~/Maildir', factory=None)
+
+for key in inbox.iterkeys():
+    try:
+        message = inbox[key]
+    except email.Errors.MessageParseError:
+        continue                # The message is malformed. Just leave it.
+
+    for name in list_names:
+        list_id = message['list-id']
+        if list_id and name in list_id:
+            # Get mailbox to use
+            box = boxes[name]
+
+            # Write copy to disk before removing original.
+            # If there's a crash, you might duplicate a message, but
+            # that's better than losing a message completely.
+            box.lock()
+            box.add(message)
+            box.flush()         
+            box.unlock()
+
+            # Remove original message
+            inbox.lock()
+            inbox.discard(key)
+            inbox.flush()
+            inbox.unlock()
+            break               # Found destination, so stop looking.
+
+for box in boxes.itervalues():
+    box.close()
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libmailcap.tex b/sys/src/cmd/python/Doc/lib/libmailcap.tex
new file mode 100644
index 000000000..b221bb34a
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmailcap.tex
@@ -0,0 +1,82 @@
+\section{\module{mailcap} ---
+         Mailcap file handling.}
+\declaremodule{standard}{mailcap}
+
+\modulesynopsis{Mailcap file handling.}
+
+
+Mailcap files are used to configure how MIME-aware applications such
+as mail readers and Web browsers react to files with different MIME
+types. (The name ``mailcap'' is derived from the phrase ``mail
+capability''.)  For example, a mailcap file might contain a line like
+\samp{video/mpeg; xmpeg \%s}.  Then, if the user encounters an email
+message or Web document with the MIME type \mimetype{video/mpeg},
+\samp{\%s} will be replaced by a filename (usually one belonging to a
+temporary file) and the \program{xmpeg} program can be automatically
+started to view the file.
+
+The mailcap format is documented in \rfc{1524}, ``A User Agent
+Configuration Mechanism For Multimedia Mail Format Information,'' but
+is not an Internet standard.  However, mailcap files are supported on
+most \UNIX{} systems.
+
+\begin{funcdesc}{findmatch}{caps, MIMEtype%
+                            \optional{, key\optional{,
+                            filename\optional{, plist}}}}
+Return a 2-tuple; the first element is a string containing the command
+line to be executed
+(which can be passed to \function{os.system()}), and the second element is
+the mailcap entry for a given MIME type.  If no matching MIME
+type can be found, \code{(None, None)} is returned.
+
+\var{key} is the name of the field desired, which represents the type
+of activity to be performed; the default value is 'view', since in the 
+most common case you simply want to view the body of the MIME-typed
+data.  Other possible values might be 'compose' and 'edit', if you
+wanted to create a new body of the given MIME type or alter the
+existing body data.  See \rfc{1524} for a complete list of these
+fields.
+
+\var{filename} is the filename to be substituted for \samp{\%s} in the
+command line; the default value is
+\code{'/dev/null'} which is almost certainly not what you want, so
+usually you'll override it by specifying a filename.
+
+\var{plist} can be a list containing named parameters; the default
+value is simply an empty list.  Each entry in the list must be a
+string containing the parameter name, an equals sign (\character{=}),
+and the parameter's value.  Mailcap entries can contain 
+named parameters like \code{\%\{foo\}}, which will be replaced by the
+value of the parameter named 'foo'.  For example, if the command line
+\samp{showpartial \%\{id\}\ \%\{number\}\ \%\{total\}}
+was in a mailcap file, and \var{plist} was set to \code{['id=1',
+'number=2', 'total=3']}, the resulting command line would be 
+\code{'showpartial 1 2 3'}.  
+
+In a mailcap file, the ``test'' field can optionally be specified to
+test some external condition (such as the machine architecture, or the
+window system in use) to determine whether or not the mailcap line
+applies.  \function{findmatch()} will automatically check such
+conditions and skip the entry if the check fails.
+\end{funcdesc}
+
+\begin{funcdesc}{getcaps}{}
+Returns a dictionary mapping MIME types to a list of mailcap file
+entries. This dictionary must be passed to the \function{findmatch()}
+function.  An entry is stored as a list of dictionaries, but it
+shouldn't be necessary to know the details of this representation.
+
+The information is derived from all of the mailcap files found on the
+system. Settings in the user's mailcap file \file{\$HOME/.mailcap}
+will override settings in the system mailcap files
+\file{/etc/mailcap}, \file{/usr/etc/mailcap}, and
+\file{/usr/local/etc/mailcap}.
+\end{funcdesc}
+
+An example usage:
+\begin{verbatim}
+>>> import mailcap
+>>> d=mailcap.getcaps()
+>>> mailcap.findmatch(d, 'video/mpeg', filename='/tmp/tmp1223')
+('xmpeg /tmp/tmp1223', {'view': 'xmpeg %s'})
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libmain.tex b/sys/src/cmd/python/Doc/lib/libmain.tex
new file mode 100644
index 000000000..00c7426fb
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmain.tex
@@ -0,0 +1,16 @@
+\section{\module{__main__} ---
+         Top-level script environment}
+
+\declaremodule[main]{builtin}{__main__}
+\modulesynopsis{The environment where the top-level script is run.}
+
+This module represents the (otherwise anonymous) scope in which the
+interpreter's main program executes --- commands read either from
+standard input, from a script file, or from an interactive prompt.  It
+is this environment in which the idiomatic ``conditional script''
+stanza causes a script to run:
+
+\begin{verbatim}
+if __name__ == "__main__":
+    main()
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libmarshal.tex b/sys/src/cmd/python/Doc/lib/libmarshal.tex
new file mode 100644
index 000000000..63ff39261
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmarshal.tex
@@ -0,0 +1,117 @@
+\section{\module{marshal} ---
+         Internal Python object serialization}
+
+\declaremodule{builtin}{marshal}
+\modulesynopsis{Convert Python objects to streams of bytes and back
+                (with different constraints).}
+
+
+This module contains functions that can read and write Python
+values in a binary format.  The format is specific to Python, but
+independent of machine architecture issues (e.g., you can write a
+Python value to a file on a PC, transport the file to a Sun, and read
+it back there).  Details of the format are undocumented on purpose;
+it may change between Python versions (although it rarely
+does).\footnote{The name of this module stems from a bit of
+  terminology used by the designers of Modula-3 (amongst others), who
+  use the term ``marshalling'' for shipping of data around in a
+  self-contained form. Strictly speaking, ``to marshal'' means to
+  convert some data from internal to external form (in an RPC buffer for
+  instance) and ``unmarshalling'' for the reverse process.}
+
+This is not a general ``persistence'' module.  For general persistence
+and transfer of Python objects through RPC calls, see the modules
+\refmodule{pickle} and \refmodule{shelve}.  The \module{marshal} module exists
+mainly to support reading and writing the ``pseudo-compiled'' code for
+Python modules of \file{.pyc} files.  Therefore, the Python
+maintainers reserve the right to modify the marshal format in backward
+incompatible ways should the need arise.  If you're serializing and
+de-serializing Python objects, use the \module{pickle} module instead.  
+\refstmodindex{pickle}
+\refstmodindex{shelve}
+\obindex{code}
+
+\begin{notice}[warning]
+The \module{marshal} module is not intended to be secure against
+erroneous or maliciously constructed data.  Never unmarshal data
+received from an untrusted or unauthenticated source.
+\end{notice}
+
+Not all Python object types are supported; in general, only objects
+whose value is independent from a particular invocation of Python can
+be written and read by this module.  The following types are supported:
+\code{None}, integers, long integers, floating point numbers,
+strings, Unicode objects, tuples, lists, dictionaries, and code
+objects, where it should be understood that tuples, lists and
+dictionaries are only supported as long as the values contained
+therein are themselves supported; and recursive lists and dictionaries
+should not be written (they will cause infinite loops).
+
+\strong{Caveat:} On machines where C's \code{long int} type has more than
+32 bits (such as the DEC Alpha), it is possible to create plain Python
+integers that are longer than 32 bits.
+If such an integer is marshaled and read back in on a machine where
+C's \code{long int} type has only 32 bits, a Python long integer object
+is returned instead.  While of a different type, the numeric value is
+the same.  (This behavior is new in Python 2.2.  In earlier versions,
+all but the least-significant 32 bits of the value were lost, and a
+warning message was printed.)
+
+There are functions that read/write files as well as functions
+operating on strings.
+
+The module defines these functions:
+
+\begin{funcdesc}{dump}{value, file\optional{, version}}
+  Write the value on the open file.  The value must be a supported
+  type.  The file must be an open file object such as
+  \code{sys.stdout} or returned by \function{open()} or
+  \function{posix.popen()}.  It must be opened in binary mode
+  (\code{'wb'} or \code{'w+b'}).
+
+  If the value has (or contains an object that has) an unsupported type,
+  a \exception{ValueError} exception is raised --- but garbage data
+  will also be written to the file.  The object will not be properly
+  read back by \function{load()}.
+
+  \versionadded[The \var{version} argument indicates the data
+  format that \code{dump} should use (see below)]{2.4}
+\end{funcdesc}
+
+\begin{funcdesc}{load}{file}
+  Read one value from the open file and return it.  If no valid value
+  is read, raise \exception{EOFError}, \exception{ValueError} or
+  \exception{TypeError}.  The file must be an open file object opened
+  in binary mode (\code{'rb'} or \code{'r+b'}).
+
+  \warning{If an object containing an unsupported type was
+  marshalled with \function{dump()}, \function{load()} will substitute
+  \code{None} for the unmarshallable type.}
+\end{funcdesc}
+
+\begin{funcdesc}{dumps}{value\optional{, version}}
+  Return the string that would be written to a file by
+  \code{dump(\var{value}, \var{file})}.  The value must be a supported
+  type.  Raise a \exception{ValueError} exception if value has (or
+  contains an object that has) an unsupported type.
+
+  \versionadded[The \var{version} argument indicates the data
+  format that \code{dumps} should use (see below)]{2.4}
+\end{funcdesc}
+
+\begin{funcdesc}{loads}{string}
+  Convert the string to a value.  If no valid value is found, raise
+  \exception{EOFError}, \exception{ValueError} or
+  \exception{TypeError}.  Extra characters in the string are ignored.
+\end{funcdesc}
+
+In addition, the following constants are defined:
+
+\begin{datadesc}{version}
+  Indicates the format that the module uses. Version 0 is the
+  historical format, version 1 (added in Python 2.4) shares interned
+  strings and version 2 (added in Python 2.5) uses a binary format for
+  floating point numbers. The current version is 2.
+
+  \versionadded{2.4}
+\end{datadesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmath.tex b/sys/src/cmd/python/Doc/lib/libmath.tex
new file mode 100644
index 000000000..e52f8f96f
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmath.tex
@@ -0,0 +1,209 @@
+\section{\module{math} ---
+         Mathematical functions}
+
+\declaremodule{builtin}{math}
+\modulesynopsis{Mathematical functions (\function{sin()} etc.).}
+
+This module is always available.  It provides access to the
+mathematical functions defined by the C standard.
+
+These functions cannot be used with complex numbers; use the functions
+of the same name from the \refmodule{cmath} module if you require
+support for complex numbers.  The distinction between functions which
+support complex numbers and those which don't is made since most users
+do not want to learn quite as much mathematics as required to
+understand complex numbers.  Receiving an exception instead of a
+complex result allows earlier detection of the unexpected complex
+number used as a parameter, so that the programmer can determine how
+and why it was generated in the first place.
+
+The following functions are provided by this module.  Except
+when explicitly noted otherwise, all return values are floats.
+
+Number-theoretic and representation functions:
+
+\begin{funcdesc}{ceil}{x}
+Return the ceiling of \var{x} as a float, the smallest integer value
+greater than or equal to \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{fabs}{x}
+Return the absolute value of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{floor}{x}
+Return the floor of \var{x} as a float, the largest integer value
+less than or equal to \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{fmod}{x, y}
+Return \code{fmod(\var{x}, \var{y})}, as defined by the platform C library.
+Note that the Python expression \code{\var{x} \%\ \var{y}} may not return
+the same result.  The intent of the C standard is that
+\code{fmod(\var{x}, \var{y})} be exactly (mathematically; to infinite
+precision) equal to \code{\var{x} - \var{n}*\var{y}} for some integer
+\var{n} such that the result has the same sign as \var{x} and
+magnitude less than \code{abs(\var{y})}.  Python's
+\code{\var{x} \%\ \var{y}} returns a result with the sign of
+\var{y} instead, and may not be exactly computable for float arguments.
+For example, \code{fmod(-1e-100, 1e100)} is \code{-1e-100}, but the
+result of Python's \code{-1e-100 \%\ 1e100} is \code{1e100-1e-100}, which
+cannot be represented exactly as a float, and rounds to the surprising
+\code{1e100}.  For this reason, function \function{fmod()} is generally
+preferred when working with floats, while Python's
+\code{\var{x} \%\ \var{y}} is preferred when working with integers.
+\end{funcdesc}
+
+\begin{funcdesc}{frexp}{x}
+Return the mantissa and exponent of \var{x} as the pair
+\code{(\var{m}, \var{e})}.  \var{m} is a float and \var{e} is an
+integer such that \code{\var{x} == \var{m} * 2**\var{e}} exactly.
+If \var{x} is zero, returns \code{(0.0, 0)}, otherwise
+\code{0.5 <= abs(\var{m}) < 1}.  This is used to "pick apart" the
+internal representation of a float in a portable way.
+\end{funcdesc}
+
+\begin{funcdesc}{ldexp}{x, i}
+Return \code{\var{x} * (2**\var{i})}.  This is essentially the inverse of
+function \function{frexp()}.
+\end{funcdesc}
+
+\begin{funcdesc}{modf}{x}
+Return the fractional and integer parts of \var{x}.  Both results
+carry the sign of \var{x}, and both are floats.
+\end{funcdesc}
+
+Note that \function{frexp()} and \function{modf()} have a different
+call/return pattern than their C equivalents: they take a single
+argument and return a pair of values, rather than returning their
+second return value through an `output parameter' (there is no such
+thing in Python).
+
+For the \function{ceil()}, \function{floor()}, and \function{modf()}
+functions, note that \emph{all} floating-point numbers of sufficiently
+large magnitude are exact integers.  Python floats typically carry no more
+than 53 bits of precision (the same as the platform C double type), in
+which case any float \var{x} with \code{abs(\var{x}) >= 2**52}
+necessarily has no fractional bits.
+
+
+Power and logarithmic functions:
+
+\begin{funcdesc}{exp}{x}
+Return \code{e**\var{x}}.
+\end{funcdesc}
+
+\begin{funcdesc}{log}{x\optional{, base}}
+Return the logarithm of \var{x} to the given \var{base}.
+If the \var{base} is not specified, return the natural logarithm of \var{x}
+(that is, the logarithm to base \emph{e}).
+\versionchanged[\var{base} argument added]{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{log10}{x}
+Return the base-10 logarithm of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{pow}{x, y}
+Return \code{\var{x}**\var{y}}.
+\end{funcdesc}
+
+\begin{funcdesc}{sqrt}{x}
+Return the square root of \var{x}.
+\end{funcdesc}
+
+Trigonometric functions:
+
+\begin{funcdesc}{acos}{x}
+Return the arc cosine of \var{x}, in radians.
+\end{funcdesc}
+
+\begin{funcdesc}{asin}{x}
+Return the arc sine of \var{x}, in radians.
+\end{funcdesc}
+
+\begin{funcdesc}{atan}{x}
+Return the arc tangent of \var{x}, in radians.
+\end{funcdesc}
+
+\begin{funcdesc}{atan2}{y, x}
+Return \code{atan(\var{y} / \var{x})}, in radians.
+The result is between \code{-pi} and \code{pi}.
+The vector in the plane from the origin to point \code{(\var{x}, \var{y})}
+makes this angle with the positive X axis.
+The point of \function{atan2()} is that the signs of both inputs are
+known to it, so it can compute the correct quadrant for the angle.
+For example, \code{atan(1}) and \code{atan2(1, 1)} are both \code{pi/4},
+but \code{atan2(-1, -1)} is \code{-3*pi/4}.
+\end{funcdesc}
+
+\begin{funcdesc}{cos}{x}
+Return the cosine of \var{x} radians.
+\end{funcdesc}
+
+\begin{funcdesc}{hypot}{x, y}
+Return the Euclidean norm, \code{sqrt(\var{x}*\var{x} + \var{y}*\var{y})}.
+This is the length of the vector from the origin to point
+\code{(\var{x}, \var{y})}.
+\end{funcdesc}
+
+\begin{funcdesc}{sin}{x}
+Return the sine of \var{x} radians.
+\end{funcdesc}
+
+\begin{funcdesc}{tan}{x}
+Return the tangent of \var{x} radians.
+\end{funcdesc}
+
+Angular conversion:
+
+\begin{funcdesc}{degrees}{x}
+Converts angle \var{x} from radians to degrees.
+\end{funcdesc}
+
+\begin{funcdesc}{radians}{x}
+Converts angle \var{x} from degrees to radians.
+\end{funcdesc}
+
+Hyperbolic functions:
+
+\begin{funcdesc}{cosh}{x}
+Return the hyperbolic cosine of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{sinh}{x}
+Return the hyperbolic sine of \var{x}.
+\end{funcdesc}
+
+\begin{funcdesc}{tanh}{x}
+Return the hyperbolic tangent of \var{x}.
+\end{funcdesc}
+
+The module also defines two mathematical constants:
+
+\begin{datadesc}{pi}
+The mathematical constant \emph{pi}.
+\end{datadesc}
+
+\begin{datadesc}{e}
+The mathematical constant \emph{e}.
+\end{datadesc}
+
+\begin{notice}
+  The \module{math} module consists mostly of thin wrappers around
+  the platform C math library functions.  Behavior in exceptional cases is
+  loosely specified by the C standards, and Python inherits much of its
+  math-function error-reporting behavior from the platform C
+  implementation.  As a result,
+  the specific exceptions raised in error cases (and even whether some
+  arguments are considered to be exceptional at all) are not defined in any
+  useful cross-platform or cross-release way.  For example, whether
+  \code{math.log(0)} returns \code{-Inf} or raises \exception{ValueError} or
+  \exception{OverflowError} isn't defined, and in
+  cases where \code{math.log(0)} raises \exception{OverflowError},
+  \code{math.log(0L)} may raise \exception{ValueError} instead.
+\end{notice}
+
+\begin{seealso}
+  \seemodule{cmath}{Complex number versions of many of these functions.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libmd5.tex b/sys/src/cmd/python/Doc/lib/libmd5.tex
new file mode 100644
index 000000000..38105ae87
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmd5.tex
@@ -0,0 +1,92 @@
+\section{\module{md5} ---
+         MD5 message digest algorithm}
+
+\declaremodule{builtin}{md5}
+\modulesynopsis{RSA's MD5 message digest algorithm.}
+
+\deprecated{2.5}{Use the \refmodule{hashlib} module instead.}
+
+This module implements the interface to RSA's MD5 message digest
+\index{message digest, MD5}
+algorithm (see also Internet \rfc{1321}).  Its use is quite
+straightforward:\ use \function{new()} to create an md5 object.
+You can now feed this object with arbitrary strings using the
+\method{update()} method, and at any point you can ask it for the
+\dfn{digest} (a strong kind of 128-bit checksum,
+a.k.a. ``fingerprint'') of the concatenation of the strings fed to it
+so far using the \method{digest()} method.
+\index{checksum!MD5}
+
+For example, to obtain the digest of the string \code{'Nobody inspects
+the spammish repetition'}:
+
+\begin{verbatim}
+>>> import md5
+>>> m = md5.new()
+>>> m.update("Nobody inspects")
+>>> m.update(" the spammish repetition")
+>>> m.digest()
+'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
+\end{verbatim}
+
+More condensed:
+
+\begin{verbatim}
+>>> md5.new("Nobody inspects the spammish repetition").digest()
+'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
+\end{verbatim}
+
+The following values are provided as constants in the module and as
+attributes of the md5 objects returned by \function{new()}:
+
+\begin{datadesc}{digest_size}
+  The size of the resulting digest in bytes.  This is always
+  \code{16}.
+\end{datadesc}
+
+The md5 module provides the following functions:
+
+\begin{funcdesc}{new}{\optional{arg}}
+Return a new md5 object.  If \var{arg} is present, the method call
+\code{update(\var{arg})} is made.
+\end{funcdesc}
+
+\begin{funcdesc}{md5}{\optional{arg}}
+For backward compatibility reasons, this is an alternative name for the
+\function{new()} function.
+\end{funcdesc}
+
+An md5 object has the following methods:
+
+\begin{methoddesc}[md5]{update}{arg}
+Update the md5 object with the string \var{arg}.  Repeated calls are
+equivalent to a single call with the concatenation of all the
+arguments: \code{m.update(a); m.update(b)} is equivalent to
+\code{m.update(a+b)}.
+\end{methoddesc}
+
+\begin{methoddesc}[md5]{digest}{}
+Return the digest of the strings passed to the \method{update()}
+method so far.  This is a 16-byte string which may contain
+non-\ASCII{} characters, including null bytes.
+\end{methoddesc}
+
+\begin{methoddesc}[md5]{hexdigest}{}
+Like \method{digest()} except the digest is returned as a string of
+length 32, containing only hexadecimal digits.  This may 
+be used to exchange the value safely in email or other non-binary
+environments.
+\end{methoddesc}
+
+\begin{methoddesc}[md5]{copy}{}
+Return a copy (``clone'') of the md5 object.  This can be used to
+efficiently compute the digests of strings that share a common initial
+substring.
+\end{methoddesc}
+
+
+\begin{seealso}
+  \seemodule{sha}{Similar module implementing the Secure Hash
+                  Algorithm (SHA).  The SHA algorithm is considered a
+                  more secure hash.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libmhlib.tex b/sys/src/cmd/python/Doc/lib/libmhlib.tex
new file mode 100644
index 000000000..3e706634b
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmhlib.tex
@@ -0,0 +1,168 @@
+\section{\module{mhlib} ---
+         Access to MH mailboxes}
+
+% LaTeX'ized from the comments in the module by Skip Montanaro
+% .
+
+\declaremodule{standard}{mhlib}
+\modulesynopsis{Manipulate MH mailboxes from Python.}
+
+
+The \module{mhlib} module provides a Python interface to MH folders and
+their contents.
+
+The module contains three basic classes, \class{MH}, which represents a
+particular collection of folders, \class{Folder}, which represents a single
+folder, and \class{Message}, which represents a single message.
+
+
+\begin{classdesc}{MH}{\optional{path\optional{, profile}}}
+\class{MH} represents a collection of MH folders.
+\end{classdesc}
+
+\begin{classdesc}{Folder}{mh, name}
+The \class{Folder} class represents a single folder and its messages.
+\end{classdesc}
+
+\begin{classdesc}{Message}{folder, number\optional{, name}}
+\class{Message} objects represent individual messages in a folder.  The
+Message class is derived from \class{mimetools.Message}.
+\end{classdesc}
+
+
+\subsection{MH Objects \label{mh-objects}}
+
+\class{MH} instances have the following methods:
+
+
+\begin{methoddesc}[MH]{error}{format\optional{, ...}}
+Print an error message -- can be overridden.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{getprofile}{key}
+Return a profile entry (\code{None} if not set).
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{getpath}{}
+Return the mailbox pathname.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{getcontext}{}
+Return the current folder name.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{setcontext}{name}
+Set the current folder name.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{listfolders}{}
+Return a list of top-level folders.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{listallfolders}{}
+Return a list of all folders.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{listsubfolders}{name}
+Return a list of direct subfolders of the given folder.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{listallsubfolders}{name}
+Return a list of all subfolders of the given folder.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{makefolder}{name}
+Create a new folder.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{deletefolder}{name}
+Delete a folder -- must have no subfolders.
+\end{methoddesc}
+
+\begin{methoddesc}[MH]{openfolder}{name}
+Return a new open folder object.
+\end{methoddesc}
+
+
+
+\subsection{Folder Objects \label{mh-folder-objects}}
+
+\class{Folder} instances represent open folders and have the following
+methods:
+
+
+\begin{methoddesc}[Folder]{error}{format\optional{, ...}}
+Print an error message -- can be overridden.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{getfullname}{}
+Return the folder's full pathname.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{getsequencesfilename}{}
+Return the full pathname of the folder's sequences file.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{getmessagefilename}{n}
+Return the full pathname of message \var{n} of the folder.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{listmessages}{}
+Return a list of messages in the folder (as numbers).
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{getcurrent}{}
+Return the current message number.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{setcurrent}{n}
+Set the current message number to \var{n}.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{parsesequence}{seq}
+Parse msgs syntax into list of messages.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{getlast}{}
+Get last message, or \code{0} if no messages are in the folder.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{setlast}{n}
+Set last message (internal use only).
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{getsequences}{}
+Return dictionary of sequences in folder.  The sequence names are used 
+as keys, and the values are the lists of message numbers in the
+sequences.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{putsequences}{dict}
+Return dictionary of sequences in folder {name: list}.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{removemessages}{list}
+Remove messages in list from folder.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{refilemessages}{list, tofolder}
+Move messages in list to other folder.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{movemessage}{n, tofolder, ton}
+Move one message to a given destination in another folder.
+\end{methoddesc}
+
+\begin{methoddesc}[Folder]{copymessage}{n, tofolder, ton}
+Copy one message to a given destination in another folder.
+\end{methoddesc}
+
+
+\subsection{Message Objects \label{mh-message-objects}}
+
+The \class{Message} class adds one method to those of
+\class{mimetools.Message}:
+
+\begin{methoddesc}[Message]{openmessage}{n}
+Return a new open message object (costs a file descriptor).
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmimetools.tex b/sys/src/cmd/python/Doc/lib/libmimetools.tex
new file mode 100644
index 000000000..5e800af17
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmimetools.tex
@@ -0,0 +1,120 @@
+\section{\module{mimetools} ---
+         Tools for parsing MIME messages}
+
+\declaremodule{standard}{mimetools}
+\modulesynopsis{Tools for parsing MIME-style message bodies.}
+
+\deprecated{2.3}{The \refmodule{email} package should be used in
+                 preference to the \module{mimetools} module.  This
+                 module is present only to maintain backward
+                 compatibility.}
+
+This module defines a subclass of the
+\refmodule{rfc822}\refstmodindex{rfc822} module's
+\class{Message} class and a number of utility functions that are
+useful for the manipulation for MIME multipart or encoded message.
+
+It defines the following items:
+
+\begin{classdesc}{Message}{fp\optional{, seekable}}
+Return a new instance of the \class{Message} class.  This is a
+subclass of the \class{rfc822.Message} class, with some additional
+methods (see below).  The \var{seekable} argument has the same meaning
+as for \class{rfc822.Message}.
+\end{classdesc}
+
+\begin{funcdesc}{choose_boundary}{}
+Return a unique string that has a high likelihood of being usable as a
+part boundary.  The string has the form
+\code{'\var{hostipaddr}.\var{uid}.\var{pid}.\var{timestamp}.\var{random}'}.
+\end{funcdesc}
+
+\begin{funcdesc}{decode}{input, output, encoding}
+Read data encoded using the allowed MIME \var{encoding} from open file
+object \var{input} and write the decoded data to open file object
+\var{output}.  Valid values for \var{encoding} include
+\code{'base64'}, \code{'quoted-printable'}, \code{'uuencode'},
+\code{'x-uuencode'}, \code{'uue'}, \code{'x-uue'}, \code{'7bit'}, and 
+\code{'8bit'}.  Decoding messages encoded in \code{'7bit'} or \code{'8bit'}
+has no effect.  The input is simply copied to the output.
+\end{funcdesc}
+
+\begin{funcdesc}{encode}{input, output, encoding}
+Read data from open file object \var{input} and write it encoded using
+the allowed MIME \var{encoding} to open file object \var{output}.
+Valid values for \var{encoding} are the same as for \method{decode()}.
+\end{funcdesc}
+
+\begin{funcdesc}{copyliteral}{input, output}
+Read lines from open file \var{input} until \EOF{} and write them to
+open file \var{output}.
+\end{funcdesc}
+
+\begin{funcdesc}{copybinary}{input, output}
+Read blocks until \EOF{} from open file \var{input} and write them to
+open file \var{output}.  The block size is currently fixed at 8192.
+\end{funcdesc}
+
+
+\begin{seealso}
+  \seemodule{email}{Comprehensive email handling package; supersedes
+                    the \module{mimetools} module.}
+  \seemodule{rfc822}{Provides the base class for
+                     \class{mimetools.Message}.}
+  \seemodule{multifile}{Support for reading files which contain
+                        distinct parts, such as MIME data.}
+  \seeurl{http://www.cs.uu.nl/wais/html/na-dir/mail/mime-faq/.html}{
+          The MIME Frequently Asked Questions document.  For an
+          overview of MIME, see the answer to question 1.1 in Part 1
+          of this document.}
+\end{seealso}
+
+
+\subsection{Additional Methods of Message Objects
+            \label{mimetools-message-objects}}
+
+The \class{Message} class defines the following methods in
+addition to the \class{rfc822.Message} methods:
+
+\begin{methoddesc}{getplist}{}
+Return the parameter list of the \mailheader{Content-Type} header.
+This is a list of strings.  For parameters of the form
+\samp{\var{key}=\var{value}}, \var{key} is converted to lower case but
+\var{value} is not.  For example, if the message contains the header
+\samp{Content-type: text/html; spam=1; Spam=2; Spam} then
+\method{getplist()} will return the Python list \code{['spam=1',
+'spam=2', 'Spam']}.
+\end{methoddesc}
+
+\begin{methoddesc}{getparam}{name}
+Return the \var{value} of the first parameter (as returned by
+\method{getplist()}) of the form \samp{\var{name}=\var{value}} for the
+given \var{name}.  If \var{value} is surrounded by quotes of the form
+`\code{<}...\code{>}' or `\code{"}...\code{"}', these are removed.
+\end{methoddesc}
+
+\begin{methoddesc}{getencoding}{}
+Return the encoding specified in the
+\mailheader{Content-Transfer-Encoding} message header.  If no such
+header exists, return \code{'7bit'}.  The encoding is converted to
+lower case.
+\end{methoddesc}
+
+\begin{methoddesc}{gettype}{}
+Return the message type (of the form \samp{\var{type}/\var{subtype}})
+as specified in the \mailheader{Content-Type} header.  If no such
+header exists, return \code{'text/plain'}.  The type is converted to
+lower case.
+\end{methoddesc}
+
+\begin{methoddesc}{getmaintype}{}
+Return the main type as specified in the \mailheader{Content-Type}
+header.  If no such header exists, return \code{'text'}.  The main
+type is converted to lower case.
+\end{methoddesc}
+
+\begin{methoddesc}{getsubtype}{}
+Return the subtype as specified in the \mailheader{Content-Type}
+header.  If no such header exists, return \code{'plain'}.  The subtype
+is converted to lower case.
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmimetypes.tex b/sys/src/cmd/python/Doc/lib/libmimetypes.tex
new file mode 100644
index 000000000..6c46d6f2b
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmimetypes.tex
@@ -0,0 +1,226 @@
+\section{\module{mimetypes} ---
+         Map filenames to MIME types}
+
+\declaremodule{standard}{mimetypes}
+\modulesynopsis{Mapping of filename extensions to MIME types.}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+
+\indexii{MIME}{content type}
+
+The \module{mimetypes} module converts between a filename or URL and
+the MIME type associated with the filename extension.  Conversions are
+provided from filename to MIME type and from MIME type to filename
+extension; encodings are not supported for the latter conversion.
+
+The module provides one class and a number of convenience functions.
+The functions are the normal interface to this module, but some
+applications may be interested in the class as well.
+
+The functions described below provide the primary interface for this
+module.  If the module has not been initialized, they will call
+\function{init()} if they rely on the information \function{init()}
+sets up.
+
+
+\begin{funcdesc}{guess_type}{filename\optional{, strict}}
+Guess the type of a file based on its filename or URL, given by
+\var{filename}.  The return value is a tuple \code{(\var{type},
+\var{encoding})} where \var{type} is \code{None} if the type can't be
+guessed (missing or unknown suffix) or a string of the form
+\code{'\var{type}/\var{subtype}'}, usable for a MIME
+\mailheader{content-type} header\indexii{MIME}{headers}.
+
+\var{encoding} is \code{None} for no encoding or the name of the
+program used to encode (e.g. \program{compress} or \program{gzip}).
+The encoding is suitable for use as a \mailheader{Content-Encoding}
+header, \emph{not} as a \mailheader{Content-Transfer-Encoding} header.
+The mappings are table driven.  Encoding suffixes are case sensitive;
+type suffixes are first tried case sensitively, then case
+insensitively.
+
+Optional \var{strict} is a flag specifying whether the list of known
+MIME types is limited to only the official types \ulink{registered
+with IANA}{http://www.isi.edu/in-notes/iana/assignments/media-types}
+are recognized.  When \var{strict} is true (the default), only the
+IANA types are supported; when \var{strict} is false, some additional
+non-standard but commonly used MIME types are also recognized.
+\end{funcdesc}
+
+\begin{funcdesc}{guess_all_extensions}{type\optional{, strict}}
+Guess the extensions for a file based on its MIME type, given by
+\var{type}.
+The return value is a list of strings giving all possible filename extensions,
+including the leading dot (\character{.}).  The extensions are not guaranteed
+to have been associated with any particular data stream, but would be mapped
+to the MIME type \var{type} by \function{guess_type()}.
+
+Optional \var{strict} has the same meaning as with the
+\function{guess_type()} function.
+\end{funcdesc}
+
+
+\begin{funcdesc}{guess_extension}{type\optional{, strict}}
+Guess the extension for a file based on its MIME type, given by
+\var{type}.
+The return value is a string giving a filename extension, including the
+leading dot (\character{.}).  The extension is not guaranteed to have been
+associated with any particular data stream, but would be mapped to the 
+MIME type \var{type} by \function{guess_type()}.  If no extension can
+be guessed for \var{type}, \code{None} is returned.
+
+Optional \var{strict} has the same meaning as with the
+\function{guess_type()} function.
+\end{funcdesc}
+
+
+Some additional functions and data items are available for controlling
+the behavior of the module.
+
+
+\begin{funcdesc}{init}{\optional{files}}
+Initialize the internal data structures.  If given, \var{files} must
+be a sequence of file names which should be used to augment the
+default type map.  If omitted, the file names to use are taken from
+\constant{knownfiles}.  Each file named in \var{files} or
+\constant{knownfiles} takes precedence over those named before it.
+Calling \function{init()} repeatedly is allowed.
+\end{funcdesc}
+
+\begin{funcdesc}{read_mime_types}{filename}
+Load the type map given in the file \var{filename}, if it exists.  The 
+type map is returned as a dictionary mapping filename extensions,
+including the leading dot (\character{.}), to strings of the form
+\code{'\var{type}/\var{subtype}'}.  If the file \var{filename} does
+not exist or cannot be read, \code{None} is returned.
+\end{funcdesc}
+
+
+\begin{funcdesc}{add_type}{type, ext\optional{, strict}}
+Add a mapping from the mimetype \var{type} to the extension \var{ext}.
+When the extension is already known, the new type will replace the old
+one. When the type is already known the extension will be added
+to the list of known extensions.
+
+When \var{strict} is the mapping will added to the official
+MIME types, otherwise to the non-standard ones.
+\end{funcdesc}
+
+
+\begin{datadesc}{inited}
+Flag indicating whether or not the global data structures have been
+initialized.  This is set to true by \function{init()}.
+\end{datadesc}
+
+\begin{datadesc}{knownfiles}
+List of type map file names commonly installed.  These files are
+typically named \file{mime.types} and are installed in different
+locations by different packages.\index{file!mime.types}
+\end{datadesc}
+
+\begin{datadesc}{suffix_map}
+Dictionary mapping suffixes to suffixes.  This is used to allow
+recognition of encoded files for which the encoding and the type are
+indicated by the same extension.  For example, the \file{.tgz}
+extension is mapped to \file{.tar.gz} to allow the encoding and type
+to be recognized separately.
+\end{datadesc}
+
+\begin{datadesc}{encodings_map}
+Dictionary mapping filename extensions to encoding types.
+\end{datadesc}
+
+\begin{datadesc}{types_map}
+Dictionary mapping filename extensions to MIME types.
+\end{datadesc}
+
+\begin{datadesc}{common_types}
+Dictionary mapping filename extensions to non-standard, but commonly
+found MIME types.
+\end{datadesc}
+
+
+The \class{MimeTypes} class may be useful for applications which may
+want more than one MIME-type database:
+
+\begin{classdesc}{MimeTypes}{\optional{filenames}}
+  This class represents a MIME-types database.  By default, it
+  provides access to the same database as the rest of this module.
+  The initial database is a copy of that provided by the module, and
+  may be extended by loading additional \file{mime.types}-style files
+  into the database using the \method{read()} or \method{readfp()}
+  methods.  The mapping dictionaries may also be cleared before
+  loading additional data if the default data is not desired.
+
+  The optional \var{filenames} parameter can be used to cause
+  additional files to be loaded ``on top'' of the default database.
+
+  \versionadded{2.2}
+\end{classdesc}
+
+An example usage of the module:
+
+\begin{verbatim}
+>>> import mimetypes
+>>> mimetypes.init()
+>>> mimetypes.knownfiles
+['/etc/mime.types', '/etc/httpd/mime.types', ... ]
+>>> mimetypes.suffix_map['.tgz']
+'.tar.gz'
+>>> mimetypes.encodings_map['.gz']
+'gzip'
+>>> mimetypes.types_map['.tgz']
+'application/x-tar-gz'
+\end{verbatim}
+
+\subsection{MimeTypes Objects \label{mimetypes-objects}}
+
+\class{MimeTypes} instances provide an interface which is very like
+that of the \refmodule{mimetypes} module.
+
+\begin{datadesc}{suffix_map}
+  Dictionary mapping suffixes to suffixes.  This is used to allow
+  recognition of encoded files for which the encoding and the type are
+  indicated by the same extension.  For example, the \file{.tgz}
+  extension is mapped to \file{.tar.gz} to allow the encoding and type
+  to be recognized separately.  This is initially a copy of the global
+  \code{suffix_map} defined in the module.
+\end{datadesc}
+
+\begin{datadesc}{encodings_map}
+  Dictionary mapping filename extensions to encoding types.  This is
+  initially a copy of the global \code{encodings_map} defined in the
+  module.
+\end{datadesc}
+
+\begin{datadesc}{types_map}
+  Dictionary mapping filename extensions to MIME types.  This is
+  initially a copy of the global \code{types_map} defined in the
+  module.
+\end{datadesc}
+
+\begin{datadesc}{common_types}
+  Dictionary mapping filename extensions to non-standard, but commonly
+  found MIME types.  This is initially a copy of the global
+  \code{common_types} defined in the module.
+\end{datadesc}
+
+\begin{methoddesc}{guess_extension}{type\optional{, strict}}
+  Similar to the \function{guess_extension()} function, using the
+  tables stored as part of the object.
+\end{methoddesc}
+
+\begin{methoddesc}{guess_type}{url\optional{, strict}}
+  Similar to the \function{guess_type()} function, using the tables
+  stored as part of the object.
+\end{methoddesc}
+
+\begin{methoddesc}{read}{path}
+  Load MIME information from a file named \var{path}.  This uses
+  \method{readfp()} to parse the file.
+\end{methoddesc}
+
+\begin{methoddesc}{readfp}{file}
+  Load MIME type information from an open file.  The file must have
+  the format of the standard \file{mime.types} files.
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmimewriter.tex b/sys/src/cmd/python/Doc/lib/libmimewriter.tex
new file mode 100644
index 000000000..a9cc09f90
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmimewriter.tex
@@ -0,0 +1,80 @@
+\section{\module{MimeWriter} ---
+         Generic MIME file writer}
+
+\declaremodule{standard}{MimeWriter}
+
+\modulesynopsis{Generic MIME file writer.}
+\sectionauthor{Christopher G. Petrilli}{petrilli@amber.org}
+
+\deprecated{2.3}{The \refmodule{email} package should be used in
+                 preference to the \module{MimeWriter} module.  This
+                 module is present only to maintain backward
+                 compatibility.}
+
+This module defines the class \class{MimeWriter}.  The
+\class{MimeWriter} class implements a basic formatter for creating
+MIME multi-part files.  It doesn't seek around the output file nor
+does it use large amounts of buffer space. You must write the parts
+out in the order that they should occur in the final
+file. \class{MimeWriter} does buffer the headers you add, allowing you 
+to rearrange their order.
+
+\begin{classdesc}{MimeWriter}{fp}
+Return a new instance of the \class{MimeWriter} class.  The only
+argument passed, \var{fp}, is a file object to be used for
+writing. Note that a \class{StringIO} object could also be used.
+\end{classdesc}
+
+
+\subsection{MimeWriter Objects \label{MimeWriter-objects}}
+
+
+\class{MimeWriter} instances have the following methods:
+
+\begin{methoddesc}{addheader}{key, value\optional{, prefix}}
+Add a header line to the MIME message. The \var{key} is the name of
+the header, where the \var{value} obviously provides the value of the
+header. The optional argument \var{prefix} determines where the header 
+is inserted; \samp{0} means append at the end, \samp{1} is insert at
+the start. The default is to append.
+\end{methoddesc}
+
+\begin{methoddesc}{flushheaders}{}
+Causes all headers accumulated so far to be written out (and
+forgotten). This is useful if you don't need a body part at all,
+e.g.\ for a subpart of type \mimetype{message/rfc822} that's (mis)used
+to store some header-like information.
+\end{methoddesc}
+
+\begin{methoddesc}{startbody}{ctype\optional{, plist\optional{, prefix}}}
+Returns a file-like object which can be used to write to the
+body of the message.  The content-type is set to the provided
+\var{ctype}, and the optional parameter \var{plist} provides
+additional parameters for the content-type declaration. \var{prefix}
+functions as in \method{addheader()} except that the default is to
+insert at the start.
+\end{methoddesc}
+
+\begin{methoddesc}{startmultipartbody}{subtype\optional{,
+                   boundary\optional{, plist\optional{, prefix}}}}
+Returns a file-like object which can be used to write to the
+body of the message.  Additionally, this method initializes the
+multi-part code, where \var{subtype} provides the multipart subtype,
+\var{boundary} may provide a user-defined boundary specification, and
+\var{plist} provides optional parameters for the subtype.
+\var{prefix} functions as in \method{startbody()}.  Subparts should be
+created using \method{nextpart()}.
+\end{methoddesc}
+
+\begin{methoddesc}{nextpart}{}
+Returns a new instance of \class{MimeWriter} which represents an
+individual part in a multipart message.  This may be used to write the 
+part as well as used for creating recursively complex multipart
+messages. The message must first be initialized with
+\method{startmultipartbody()} before using \method{nextpart()}.
+\end{methoddesc}
+
+\begin{methoddesc}{lastpart}{}
+This is used to designate the last part of a multipart message, and
+should \emph{always} be used when writing multipart messages.
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmimify.tex b/sys/src/cmd/python/Doc/lib/libmimify.tex
new file mode 100644
index 000000000..d99567ab3
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmimify.tex
@@ -0,0 +1,94 @@
+\section{\module{mimify} ---
+         MIME processing of mail messages}
+
+\declaremodule{standard}{mimify}
+\modulesynopsis{Mimification and unmimification of mail messages.}
+
+\deprecated{2.3}{The \refmodule{email} package should be used in
+                 preference to the \module{mimify} module.  This
+                 module is present only to maintain backward
+                 compatibility.}
+
+The \module{mimify} module defines two functions to convert mail messages to
+and from MIME format.  The mail message can be either a simple message
+or a so-called multipart message.  Each part is treated separately.
+Mimifying (a part of) a message entails encoding the message as
+quoted-printable if it contains any characters that cannot be
+represented using 7-bit \ASCII.  Unmimifying (a part of) a message
+entails undoing the quoted-printable encoding.  Mimify and unmimify
+are especially useful when a message has to be edited before being
+sent.  Typical use would be:
+
+\begin{verbatim}
+unmimify message
+edit message
+mimify message
+send message
+\end{verbatim}
+
+The modules defines the following user-callable functions and
+user-settable variables:
+
+\begin{funcdesc}{mimify}{infile, outfile}
+Copy the message in \var{infile} to \var{outfile}, converting parts to
+quoted-printable and adding MIME mail headers when necessary.
+\var{infile} and \var{outfile} can be file objects (actually, any
+object that has a \method{readline()} method (for \var{infile}) or a
+\method{write()} method (for \var{outfile})) or strings naming the files.
+If \var{infile} and \var{outfile} are both strings, they may have the
+same value.
+\end{funcdesc}
+
+\begin{funcdesc}{unmimify}{infile, outfile\optional{, decode_base64}}
+Copy the message in \var{infile} to \var{outfile}, decoding all
+quoted-printable parts.  \var{infile} and \var{outfile} can be file
+objects (actually, any object that has a \method{readline()} method (for
+\var{infile}) or a \method{write()} method (for \var{outfile})) or strings
+naming the files.  If \var{infile} and \var{outfile} are both strings,
+they may have the same value.
+If the \var{decode_base64} argument is provided and tests true, any
+parts that are coded in the base64 encoding are decoded as well.
+\end{funcdesc}
+
+\begin{funcdesc}{mime_decode_header}{line}
+Return a decoded version of the encoded header line in \var{line}.
+This only supports the ISO 8859-1 charset (Latin-1).
+\end{funcdesc}
+
+\begin{funcdesc}{mime_encode_header}{line}
+Return a MIME-encoded version of the header line in \var{line}.
+\end{funcdesc}
+
+\begin{datadesc}{MAXLEN}
+By default, a part will be encoded as quoted-printable when it
+contains any non-\ASCII{} characters (characters with the 8th bit
+set), or if there are any lines longer than \constant{MAXLEN} characters
+(default value 200).  
+\end{datadesc}
+
+\begin{datadesc}{CHARSET}
+When not specified in the mail headers, a character set must be filled
+in.  The string used is stored in \constant{CHARSET}, and the default
+value is ISO-8859-1 (also known as Latin1 (latin-one)).
+\end{datadesc}
+
+This module can also be used from the command line.  Usage is as
+follows:
+\begin{verbatim}
+mimify.py -e [-l length] [infile [outfile]]
+mimify.py -d [-b] [infile [outfile]]
+\end{verbatim}
+to encode (mimify) and decode (unmimify) respectively.  \var{infile}
+defaults to standard input, \var{outfile} defaults to standard output.
+The same file can be specified for input and output.
+
+If the \strong{-l} option is given when encoding, if there are any lines
+longer than the specified \var{length}, the containing part will be
+encoded.
+
+If the \strong{-b} option is given when decoding, any base64 parts will
+be decoded as well.
+
+\begin{seealso}
+  \seemodule{quopri}{Encode and decode MIME quoted-printable files.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libmisc.tex b/sys/src/cmd/python/Doc/lib/libmisc.tex
new file mode 100644
index 000000000..6f79eda5e
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmisc.tex
@@ -0,0 +1,7 @@
+\chapter{Miscellaneous Services}
+\label{misc}
+
+The modules described in this chapter provide miscellaneous services
+that are available in all Python versions.  Here's an overview:
+
+\localmoduletable
diff --git a/sys/src/cmd/python/Doc/lib/libmm.tex b/sys/src/cmd/python/Doc/lib/libmm.tex
new file mode 100644
index 000000000..22c14b4d7
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmm.tex
@@ -0,0 +1,8 @@
+\chapter{Multimedia Services}
+\label{mmedia}
+
+The modules described in this chapter implement various algorithms or
+interfaces that are mainly useful for multimedia applications.  They
+are available at the discretion of the installation.  Here's an overview:
+
+\localmoduletable
diff --git a/sys/src/cmd/python/Doc/lib/libmmap.tex b/sys/src/cmd/python/Doc/lib/libmmap.tex
new file mode 100644
index 000000000..3763d4f84
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmmap.tex
@@ -0,0 +1,171 @@
+\section{\module{mmap} ---
+Memory-mapped file support}
+
+\declaremodule{builtin}{mmap}
+\modulesynopsis{Interface to memory-mapped files for \UNIX\ and Windows.}
+
+Memory-mapped file objects behave like both strings and like
+file objects.  Unlike normal string objects, however, these are
+mutable.  You can use mmap objects in most places where strings
+are expected; for example, you can use the \module{re} module to
+search through a memory-mapped file.  Since they're mutable, you can
+change a single character by doing \code{obj[\var{index}] = 'a'}, or
+change a substring by assigning to a slice:
+\code{obj[\var{i1}:\var{i2}] = '...'}.  You can also read and write
+data starting at the current file position, and \method{seek()}
+through the file to different positions.
+
+A memory-mapped file is created by the \function{mmap()} function,
+which is different on \UNIX{} and on Windows.  In either case you must
+provide a file descriptor for a file opened for update.
+If you wish to map an existing Python file object, use its
+\method{fileno()} method to obtain the correct value for the
+\var{fileno} parameter.  Otherwise, you can open the file using the
+\function{os.open()} function, which returns a file descriptor
+directly (the file still needs to be closed when done).
+
+For both the \UNIX{} and Windows versions of the function,
+\var{access} may be specified as an optional keyword parameter.
+\var{access} accepts one of three values: \constant{ACCESS_READ},
+\constant{ACCESS_WRITE}, or \constant{ACCESS_COPY} to specify
+readonly, write-through or copy-on-write memory respectively.
+\var{access} can be used on both \UNIX{} and Windows.  If
+\var{access} is not specified, Windows mmap returns a write-through
+mapping.  The initial memory values for all three access types are
+taken from the specified file.  Assignment to an
+\constant{ACCESS_READ} memory map raises a \exception{TypeError}
+exception.  Assignment to an \constant{ACCESS_WRITE} memory map
+affects both memory and the underlying file.  Assignment to an
+\constant{ACCESS_COPY} memory map affects memory but does not update
+the underlying file.  \versionchanged[To map anonymous memory,
+-1 should be passed as the fileno along with the length]{2.5}
+
+\begin{funcdesc}{mmap}{fileno, length\optional{, tagname\optional{, access}}}
+  \strong{(Windows version)} Maps \var{length} bytes from the file
+  specified by the file handle \var{fileno}, and returns a mmap
+  object.  If \var{length} is larger than the current size of the file,
+  the file is extended to contain \var{length} bytes.  If \var{length}
+  is \code{0}, the maximum length of the map is the current size
+  of the file, except that if the file is empty Windows raises an
+  exception (you cannot create an empty mapping on Windows).
+
+  \var{tagname}, if specified and not \code{None}, is a string giving
+  a tag name for the mapping.  Windows allows you to have many
+  different mappings against the same file.  If you specify the name
+  of an existing tag, that tag is opened, otherwise a new tag of this
+  name is created.  If this parameter is omitted or \code{None}, the
+  mapping is created without a name.  Avoiding the use of the tag
+  parameter will assist in keeping your code portable between \UNIX{}
+  and Windows.
+\end{funcdesc}
+
+\begin{funcdescni}{mmap}{fileno, length\optional{, flags\optional{,
+                         prot\optional{, access}}}}
+  \strong{(\UNIX{} version)} Maps \var{length} bytes from the file
+  specified by the file descriptor \var{fileno}, and returns a mmap
+  object.  If \var{length} is \code{0}, the maximum length of the map
+  will be the current size of the file when \function{mmap()} is
+  called.
+  
+  \var{flags} specifies the nature of the mapping.
+  \constant{MAP_PRIVATE} creates a private copy-on-write mapping, so
+  changes to the contents of the mmap object will be private to this
+  process, and \constant{MAP_SHARED} creates a mapping that's shared
+  with all other processes mapping the same areas of the file.  The
+  default value is \constant{MAP_SHARED}.
+
+  \var{prot}, if specified, gives the desired memory protection; the
+  two most useful values are \constant{PROT_READ} and
+  \constant{PROT_WRITE}, to specify that the pages may be read or
+  written.  \var{prot} defaults to \constant{PROT_READ | PROT_WRITE}.
+
+  \var{access} may be specified in lieu of \var{flags} and \var{prot}
+  as an optional keyword parameter.  It is an error to specify both
+  \var{flags}, \var{prot} and \var{access}.  See the description of
+  \var{access} above for information on how to use this parameter.
+\end{funcdescni}
+
+
+Memory-mapped file objects support the following methods:
+
+
+\begin{methoddesc}{close}{}
+  Close the file.  Subsequent calls to other methods of the object
+  will result in an exception being raised.
+\end{methoddesc}
+
+\begin{methoddesc}{find}{string\optional{, start}}
+  Returns the lowest index in the object where the substring
+  \var{string} is found.  Returns \code{-1} on failure.  \var{start}
+  is the index at which the search begins, and defaults to zero.
+\end{methoddesc}
+
+\begin{methoddesc}{flush}{\optional{offset, size}}
+  Flushes changes made to the in-memory copy of a file back to disk.
+  Without use of this call there is no guarantee that changes are
+  written back before the object is destroyed.  If \var{offset} and
+  \var{size} are specified, only changes to the given range of bytes
+  will be flushed to disk; otherwise, the whole extent of the mapping
+  is flushed.
+\end{methoddesc}
+
+\begin{methoddesc}{move}{\var{dest}, \var{src}, \var{count}}
+  Copy the \var{count} bytes starting at offset \var{src} to the
+  destination index \var{dest}.  If the mmap was created with
+  \constant{ACCESS_READ}, then calls to move will throw a
+  \exception{TypeError} exception.
+\end{methoddesc}
+
+\begin{methoddesc}{read}{\var{num}}
+  Return a string containing up to \var{num} bytes starting from the
+  current file position; the file position is updated to point after the
+  bytes that were returned.
+\end{methoddesc}
+
+\begin{methoddesc}{read_byte}{}
+  Returns a string of length 1 containing the character at the current
+  file position, and advances the file position by 1.
+\end{methoddesc}
+
+\begin{methoddesc}{readline}{}
+  Returns a single line, starting at the current file position and up to
+  the next newline.
+\end{methoddesc}
+
+\begin{methoddesc}{resize}{\var{newsize}}
+  Resizes the map and the underlying file, if any.
+  If the mmap was created with \constant{ACCESS_READ} or
+  \constant{ACCESS_COPY}, resizing the map will throw a \exception{TypeError} exception.
+\end{methoddesc}
+
+\begin{methoddesc}{seek}{pos\optional{, whence}}
+  Set the file's current position.  \var{whence} argument is optional
+  and defaults to \code{os.SEEK_SET} or \code{0} (absolute file
+  positioning); other values are \code{os.SEEK_CUR} or \code{1} (seek
+  relative to the current position) and \code{os.SEEK_END} or \code{2}
+  (seek relative to the file's end).
+\end{methoddesc}
+
+\begin{methoddesc}{size}{}
+  Return the length of the file, which can be larger than the size of
+  the memory-mapped area.
+\end{methoddesc}
+
+\begin{methoddesc}{tell}{}
+  Returns the current position of the file pointer.
+\end{methoddesc}
+
+\begin{methoddesc}{write}{\var{string}}
+  Write the bytes in \var{string} into memory at the current position
+  of the file pointer; the file position is updated to point after the
+  bytes that were written. If the mmap was created with
+  \constant{ACCESS_READ}, then writing to it will throw a
+  \exception{TypeError} exception.
+\end{methoddesc}
+
+\begin{methoddesc}{write_byte}{\var{byte}}
+  Write the single-character string \var{byte} into memory at the
+  current position of the file pointer; the file position is advanced
+  by \code{1}. If the mmap was created with \constant{ACCESS_READ},
+  then writing to it will throw a \exception{TypeError} exception.
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmodulefinder.tex b/sys/src/cmd/python/Doc/lib/libmodulefinder.tex
new file mode 100644
index 000000000..5fb9e8e27
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmodulefinder.tex
@@ -0,0 +1,51 @@
+\section{\module{modulefinder} ---
+         Find modules used by a script}
+\sectionauthor{A.M. Kuchling}{amk@amk.ca}
+
+\declaremodule{standard}{modulefinder}
+\modulesynopsis{Find modules used by a script.}
+
+\versionadded{2.3}
+
+This module provides a \class{ModuleFinder} class that can be used to
+determine the set of modules imported by a script.
+\code{modulefinder.py} can also be run as a script, giving the
+filename of a Python script as its argument, after which a report of
+the imported modules will be printed.
+
+\begin{funcdesc}{AddPackagePath}{pkg_name, path}
+Record that the package named \var{pkg_name} can be found in the specified \var{path}.
+\end{funcdesc}
+
+\begin{funcdesc}{ReplacePackage}{oldname, newname}
+Allows specifying that the module named \var{oldname} is in fact
+the package named \var{newname}.  The most common usage would be 
+to handle how the \module{_xmlplus} package replaces the \module{xml}
+package.
+\end{funcdesc}
+
+\begin{classdesc}{ModuleFinder}{\optional{path=None, debug=0, excludes=[], replace_paths=[]}}
+
+This class provides \method{run_script()} and \method{report()}
+methods to determine the set of modules imported by a script.
+\var{path} can be a list of directories to search for modules; if not
+specified, \code{sys.path} is used. 
+\var{debug} sets the debugging level; higher values make the class print 
+debugging messages about what it's doing.
+\var{excludes} is a list of module names to exclude from the analysis.
+\var{replace_paths} is a list of \code{(\var{oldpath}, \var{newpath})}
+tuples that will be replaced in module paths.
+\end{classdesc}
+
+\begin{methoddesc}[ModuleFinder]{report}{}
+Print a report to standard output that lists the modules imported by the script
+and their
+paths, as well as modules that are missing or seem to be missing.
+\end{methoddesc}
+
+\begin{methoddesc}[ModuleFinder]{run_script}{pathname}
+Analyze the contents of the \var{pathname} file, which must contain 
+Python code.
+\end{methoddesc}
+ 
+
diff --git a/sys/src/cmd/python/Doc/lib/libmsilib.tex b/sys/src/cmd/python/Doc/lib/libmsilib.tex
new file mode 100644
index 000000000..13d5556cd
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmsilib.tex
@@ -0,0 +1,485 @@
+\section{\module{msilib} ---
+         Read and write Microsoft Installer files}
+
+\declaremodule{standard}{msilib}
+  \platform{Windows}
+\modulesynopsis{Creation of Microsoft Installer files, and CAB files.}
+\moduleauthor{Martin v. L\"owis}{martin@v.loewis.de}
+\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de}
+
+\index{msi}
+
+\versionadded{2.5}
+
+The \module{msilib} supports the creation of Microsoft Installer
+(\code{.msi}) files.  Because these files often contain an embedded
+``cabinet'' file (\code{.cab}), it also exposes an API to create
+CAB files. Support for reading \code{.cab} files is currently not
+implemented; read support for the \code{.msi} database is possible.
+
+This package aims to provide complete access to all tables in an
+\code{.msi} file, therefore, it is a fairly low-level API. Two
+primary applications of this package are the \module{distutils}
+command \code{bdist_msi}, and the creation of Python installer
+package itself (although that currently uses a different version
+of \code{msilib}).
+
+The package contents can be roughly split into four parts:
+low-level CAB routines, low-level MSI routines, higher-level
+MSI routines, and standard table structures.
+
+\begin{funcdesc}{FCICreate}{cabname, files}
+  Create a new CAB file named \var{cabname}. \var{files} must
+  be a list of tuples, each containing the name of the file on
+  disk, and the name of the file inside the CAB file.
+
+  The files are added to the CAB file in the order they appear
+  in the list. All files are added into a single CAB file,
+  using the MSZIP compression algorithm.
+
+  Callbacks to Python for the various steps of MSI creation
+  are currently not exposed.
+\end{funcdesc}
+
+\begin{funcdesc}{UUIDCreate}{}
+  Return the string representation of a new unique identifier.
+  This wraps the Windows API functions \cfunction{UuidCreate} and
+  \cfunction{UuidToString}.
+\end{funcdesc}
+
+\begin{funcdesc}{OpenDatabase}{path, persist}
+  Return a new database object by calling MsiOpenDatabase.  
+  \var{path} is the file name of the
+  MSI file; \var{persist} can be one of the constants 
+  \code{MSIDBOPEN_CREATEDIRECT}, \code{MSIDBOPEN_CREATE},
+  \code{MSIDBOPEN_DIRECT}, \code{MSIDBOPEN_READONLY}, or
+  \code{MSIDBOPEN_TRANSACT}, and may include the flag
+  \code{MSIDBOPEN_PATCHFILE}. See the Microsoft documentation for
+  the meaning of these flags; depending on the flags,
+  an existing database is opened, or a new one created.
+\end{funcdesc}
+
+\begin{funcdesc}{CreateRecord}{count}
+  Return a new record object by calling \cfunction{MSICreateRecord}.
+  \var{count} is the number of fields of the record.
+\end{funcdesc}
+
+\begin{funcdesc}{init_database}{name, schema, ProductName, ProductCode, ProductVersion, Manufacturer}
+  Create and return a new database \var{name}, initialize it 
+  with \var{schema},  and set the properties \var{ProductName},
+  \var{ProductCode}, \var{ProductVersion}, and \var{Manufacturer}.
+
+  \var{schema} must be a module object containing \code{tables} and
+  \code{_Validation_records} attributes; typically,
+  \module{msilib.schema} should be used.
+
+  The database will contain just the schema and the validation
+  records when this function returns.
+\end{funcdesc}
+
+\begin{funcdesc}{add_data}{database, records}
+  Add all \var{records} to \var{database}.  \var{records} should
+  be a list of tuples, each one containing all fields of a record
+  according to the schema of the table.  For optional fields,
+  \code{None} can be passed.
+
+  Field values can be int or long numbers, strings, or instances
+  of the Binary class.
+\end{funcdesc}
+
+\begin{classdesc}{Binary}{filename}
+  Represents entries in the Binary table; inserting such
+  an object using \function{add_data} reads the file named
+  \var{filename} into the table.
+\end{classdesc}
+
+\begin{funcdesc}{add_tables}{database, module}
+  Add all table content from \var{module} to \var{database}.
+  \var{module} must contain an attribute \var{tables}
+  listing all tables for which content should be added,
+  and one attribute per table that has the actual content.
+
+  This is typically used to install the sequence tables.
+\end{funcdesc}
+
+\begin{funcdesc}{add_stream}{database, name, path}
+  Add the file \var{path} into the \code{_Stream} table
+  of \var{database}, with the stream name \var{name}.
+\end{funcdesc}
+
+\begin{funcdesc}{gen_uuid}{}
+  Return a new UUID, in the format that MSI typically
+  requires (i.e. in curly braces, and with all hexdigits
+  in upper-case).
+\end{funcdesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/devnotes/winprog/fcicreate.asp]{FCICreateFile}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/uuidcreate.asp]{UuidCreate}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rpc/rpc/uuidtostring.asp]{UuidToString}{}
+\end{seealso}
+
+\subsection{Database Objects\label{database-objects}}
+
+\begin{methoddesc}{OpenView}{sql}
+  Return a view object, by calling \cfunction{MSIDatabaseOpenView}.
+  \var{sql} is the SQL statement to execute.
+\end{methoddesc}
+
+\begin{methoddesc}{Commit}{}
+  Commit the changes pending in the current transaction,
+  by calling \cfunction{MSIDatabaseCommit}.
+\end{methoddesc}
+
+\begin{methoddesc}{GetSummaryInformation}{count}
+  Return a new summary information object, by calling
+  \cfunction{MsiGetSummaryInformation}.  \var{count} is the maximum number of
+  updated values.
+\end{methoddesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiopenview.asp]{MSIOpenView}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msidatabasecommit.asp]{MSIDatabaseCommit}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msigetsummaryinformation.asp]{MSIGetSummaryInformation}{}
+\end{seealso}
+
+\subsection{View Objects\label{view-objects}}
+
+\begin{methoddesc}{Execute}{\optional{params=None}}
+  Execute the SQL query of the view, through \cfunction{MSIViewExecute}.
+  \var{params} is an optional record describing actual values
+  of the parameter tokens in the query.
+\end{methoddesc}
+
+\begin{methoddesc}{GetColumnInfo}{kind}
+  Return a record describing the columns of the view, through
+  calling \cfunction{MsiViewGetColumnInfo}. \var{kind} can be either
+  \code{MSICOLINFO_NAMES} or \code{MSICOLINFO_TYPES}.
+\end{methoddesc}
+
+\begin{methoddesc}{Fetch}{}
+  Return a result record of the query, through calling
+  \cfunction{MsiViewFetch}.
+\end{methoddesc}
+
+\begin{methoddesc}{Modify}{kind, data}
+  Modify the view, by calling \cfunction{MsiViewModify}. \var{kind}
+  can be one of  \code{MSIMODIFY_SEEK}, \code{MSIMODIFY_REFRESH},
+  \code{MSIMODIFY_INSERT}, \code{MSIMODIFY_UPDATE}, \code{MSIMODIFY_ASSIGN},
+  \code{MSIMODIFY_REPLACE}, \code{MSIMODIFY_MERGE}, \code{MSIMODIFY_DELETE},
+  \code{MSIMODIFY_INSERT_TEMPORARY}, \code{MSIMODIFY_VALIDATE},
+  \code{MSIMODIFY_VALIDATE_NEW}, \code{MSIMODIFY_VALIDATE_FIELD}, or
+  \code{MSIMODIFY_VALIDATE_DELETE}.
+
+  \var{data} must be a record describing the new data.
+\end{methoddesc}
+
+\begin{methoddesc}{Close}{}
+  Close the view, through \cfunction{MsiViewClose}.
+\end{methoddesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiviewexecute.asp]{MsiViewExecute}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiviewgetcolumninfo.asp]{MSIViewGetColumnInfo}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiviewfetch.asp]{MsiViewFetch}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiviewmodify.asp]{MsiViewModify}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msiviewclose.asp]{MsiViewClose}{}
+\end{seealso}
+
+\subsection{Summary Information Objects\label{summary-objects}}
+
+\begin{methoddesc}{GetProperty}{field}
+  Return a property of the summary, through \cfunction{MsiSummaryInfoGetProperty}.
+  \var{field} is the name of the property, and can be one of the
+  constants
+  \code{PID_CODEPAGE}, \code{PID_TITLE}, \code{PID_SUBJECT},
+  \code{PID_AUTHOR}, \code{PID_KEYWORDS}, \code{PID_COMMENTS},
+  \code{PID_TEMPLATE}, \code{PID_LASTAUTHOR}, \code{PID_REVNUMBER},
+  \code{PID_LASTPRINTED}, \code{PID_CREATE_DTM}, \code{PID_LASTSAVE_DTM},
+  \code{PID_PAGECOUNT}, \code{PID_WORDCOUNT}, \code{PID_CHARCOUNT},
+  \code{PID_APPNAME}, or \code{PID_SECURITY}.
+\end{methoddesc}
+
+\begin{methoddesc}{GetPropertyCount}{}
+  Return the number of summary properties, through
+  \cfunction{MsiSummaryInfoGetPropertyCount}.
+\end{methoddesc}
+
+\begin{methoddesc}{SetProperty}{field, value}
+  Set a property through \cfunction{MsiSummaryInfoSetProperty}. \var{field}
+  can have the same values as in \method{GetProperty}, \var{value}
+  is the new value of the property. Possible value types are integer
+  and string.
+\end{methoddesc}
+
+\begin{methoddesc}{Persist}{}
+  Write the modified properties to the summary information stream,
+  using \cfunction{MsiSummaryInfoPersist}.
+\end{methoddesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msisummaryinfogetproperty.asp]{MsiSummaryInfoGetProperty}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msisummaryinfogetpropertycount.asp]{MsiSummaryInfoGetPropertyCount}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msisummaryinfosetproperty.asp]{MsiSummaryInfoSetProperty}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msisummaryinfopersist.asp]{MsiSummaryInfoPersist}{}
+\end{seealso}
+
+\subsection{Record Objects\label{record-objects}}
+
+\begin{methoddesc}{GetFieldCount}{}
+  Return the number of fields of the record, through \cfunction{MsiRecordGetFieldCount}.
+\end{methoddesc}
+
+\begin{methoddesc}{SetString}{field, value}
+  Set \var{field} to \var{value} through \cfunction{MsiRecordSetString}.
+  \var{field} must be an integer; \var{value} a string.
+\end{methoddesc}
+
+\begin{methoddesc}{SetStream}{field, value}
+  Set \var{field} to the contents of the file named \var{value},
+  through \cfunction{MsiRecordSetStream}.
+  \var{field} must be an integer; \var{value} a string.
+\end{methoddesc}
+
+\begin{methoddesc}{SetInteger}{field, value}
+  Set \var{field} to \var{value} through \cfunction{MsiRecordSetInteger}.
+  Both \var{field} and \var{value} must be an integer.
+\end{methoddesc}
+
+\begin{methoddesc}{ClearData}{}
+  Set all fields of the record to 0, through \cfunction{MsiRecordClearData}.
+\end{methoddesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msirecordgetfieldcount.asp]{MsiRecordGetFieldCount}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msirecordsetstring.asp]{MsiRecordSetString}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msirecordsetstream.asp]{MsiRecordSetStream}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msirecordsetinteger.asp]{MsiRecordSetInteger}{}
+  \seetitle[http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/msirecordclear.asp]{MsiRecordClear}{}
+\end{seealso}
+
+\subsection{Errors\label{msi-errors}}
+
+All wrappers around MSI functions raise \exception{MsiError};
+the string inside the exception will contain more detail.
+
+\subsection{CAB Objects\label{cab}}
+
+\begin{classdesc}{CAB}{name}
+  The class \class{CAB} represents a CAB file. During MSI construction,
+  files will be added simultaneously to the \code{Files} table, and
+  to a CAB file. Then, when all files have been added, the CAB file
+  can be written, then added to the MSI file.
+
+  \var{name} is the name of the CAB file in the MSI file.
+\end{classdesc}
+
+\begin{methoddesc}[CAB]{append}{full, logical}
+  Add the file with the pathname \var{full} to the CAB file,
+  under the name \var{logical}. If there is already a file
+  named \var{logical}, a new file name is created.
+
+  Return the index of the file in the CAB file, and the
+  new name of the file inside the CAB file.
+\end{methoddesc}
+
+\begin{methoddesc}[CAB]{append}{database}
+  Generate a CAB file, add it as a stream to the MSI file,
+  put it into the \code{Media} table, and remove the generated
+  file from the disk.
+\end{methoddesc}
+
+\subsection{Directory Objects\label{msi-directory}}
+
+\begin{classdesc}{Directory}{database, cab, basedir, physical, 
+                  logical, default, component, \optional{componentflags}}
+  Create a new directory in the Directory table. There is a current
+  component at each point in time for the directory, which is either
+  explicitly created through \method{start_component}, or implicitly when files
+  are added for the first time. Files are added into the current
+  component, and into the cab file.  To create a directory, a base
+  directory object needs to be specified (can be \code{None}), the path to
+  the physical directory, and a logical directory name.  \var{default}
+  specifies the DefaultDir slot in the directory table. \var{componentflags}
+  specifies the default flags that new components get.
+\end{classdesc}
+
+\begin{methoddesc}[Directory]{start_component}{\optional{component\optional{,
+      feature\optional{, flags\optional{, keyfile\optional{, uuid}}}}}}
+  Add an entry to the Component table, and make this component the
+  current component for this directory. If no component name is given, the
+  directory name is used. If no \var{feature} is given, the current feature
+  is used. If no \var{flags} are given, the directory's default flags are
+  used. If no \var{keyfile} is given, the KeyPath is left null in the
+  Component table.
+\end{methoddesc}
+
+\begin{methoddesc}[Directory]{add_file}{file\optional{, src\optional{,
+      version\optional{, language}}}}
+  Add a file to the current component of the directory, starting a new
+  one if there is no current component. By default, the file name
+  in the source and the file table will be identical. If the \var{src} file
+  is specified, it is interpreted relative to the current
+  directory. Optionally, a \var{version} and a \var{language} can be specified for
+  the entry in the File table.
+\end{methoddesc}
+
+\begin{methoddesc}[Directory]{glob}{pattern\optional{, exclude}}
+  Add a list of files to the current component as specified in the glob
+  pattern. Individual files can be excluded in the \var{exclude} list.
+\end{methoddesc}
+
+\begin{methoddesc}[Directory]{remove_pyc}{}
+  Remove \code{.pyc}/\code{.pyo} files on uninstall.
+\end{methoddesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/directory_table.asp]{Directory Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/file_table.asp]{File Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/component_table.asp]{Component Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/featurecomponents_table.asp]{FeatureComponents Table}{}
+\end{seealso}
+
+
+\subsection{Features\label{features}}
+
+\begin{classdesc}{Feature}{database, id, title, desc, display\optional{,
+    level=1\optional{, parent\optional{, directory\optional{, 
+    attributes=0}}}}}
+
+  Add a new record to the \code{Feature} table, using the values
+  \var{id}, \var{parent.id}, \var{title}, \var{desc}, \var{display},
+  \var{level}, \var{directory}, and \var{attributes}. The resulting
+  feature object can be passed to the \method{start_component} method
+  of \class{Directory}.
+\end{classdesc}
+
+\begin{methoddesc}[Feature]{set_current}{}
+  Make this feature the current feature of \module{msilib}.
+  New components are automatically added to the default feature,
+  unless a feature is explicitly specified.
+\end{methoddesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/feature_table.asp]{Feature Table}{}
+\end{seealso}
+
+\subsection{GUI classes\label{msi-gui}}
+
+\module{msilib} provides several classes that wrap the GUI tables in
+an MSI database. However, no standard user interface is provided; use
+\module{bdist_msi} to create MSI files with a user-interface for
+installing Python packages.
+
+\begin{classdesc}{Control}{dlg, name}
+  Base class of the dialog controls. \var{dlg} is the dialog object
+  the control belongs to, and \var{name} is the control's name.
+\end{classdesc}
+
+\begin{methoddesc}[Control]{event}{event, argument\optional{, 
+   condition = ``1''\optional{, ordering}}}
+
+  Make an entry into the \code{ControlEvent} table for this control.
+\end{methoddesc}
+
+\begin{methoddesc}[Control]{mapping}{event, attribute}
+  Make an entry into the \code{EventMapping} table for this control.
+\end{methoddesc}
+
+\begin{methoddesc}[Control]{condition}{action, condition}
+  Make an entry into the \code{ControlCondition} table for this control.
+\end{methoddesc}
+
+
+\begin{classdesc}{RadioButtonGroup}{dlg, name, property}
+  Create a radio button control named \var{name}. \var{property}
+  is the installer property that gets set when a radio button
+  is selected.
+\end{classdesc}
+
+\begin{methoddesc}[RadioButtonGroup]{add}{name, x, y, width, height, text
+                                          \optional{, value}}
+  Add a radio button named \var{name} to the group, at the
+  coordinates \var{x}, \var{y}, \var{width}, \var{height}, and
+  with the label \var{text}. If \var{value} is omitted, it
+  defaults to \var{name}.
+\end{methoddesc}
+           
+\begin{classdesc}{Dialog}{db, name, x, y, w, h, attr, title, first, 
+    default, cancel}
+  Return a new \class{Dialog} object. An entry in the \code{Dialog} table
+  is made, with the specified coordinates, dialog attributes, title,
+  name of the first, default, and cancel controls.
+\end{classdesc}
+
+\begin{methoddesc}[Dialog]{control}{name, type, x, y, width, height, 
+                  attributes, property, text, control_next, help}
+  Return a new \class{Control} object. An entry in the \code{Control} table
+  is made with the specified parameters.
+
+  This is a generic method; for specific types, specialized methods
+  are provided.
+\end{methoddesc}
+
+
+\begin{methoddesc}[Dialog]{text}{name, x, y, width, height, attributes, text}
+  Add and return a \code{Text} control.
+\end{methoddesc}
+
+\begin{methoddesc}[Dialog]{bitmap}{name, x, y, width, height, text}
+  Add and return a \code{Bitmap} control.
+\end{methoddesc}
+
+\begin{methoddesc}[Dialog]{line}{name, x, y, width, height}
+  Add and return a \code{Line} control.
+\end{methoddesc}
+
+\begin{methoddesc}[Dialog]{pushbutton}{name, x, y, width, height, attributes, 
+                                 text, next_control}
+  Add and return a \code{PushButton} control.
+\end{methoddesc}
+
+\begin{methoddesc}[Dialog]{radiogroup}{name, x, y, width, height, 
+                                 attributes, property, text, next_control}
+  Add and return a \code{RadioButtonGroup} control.
+\end{methoddesc}
+
+\begin{methoddesc}[Dialog]{checkbox}{name, x, y, width, height, 
+                                 attributes, property, text, next_control}
+  Add and return a \code{CheckBox} control.
+\end{methoddesc}
+
+\begin{seealso}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/dialog_table.asp]{Dialog Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/control_table.asp]{Control Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/controls.asp]{Control Types}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/controlcondition_table.asp]{ControlCondition Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/controlevent_table.asp]{ControlEvent Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/eventmapping_table.asp]{EventMapping Table}{}
+  \seetitle[http://msdn.microsoft.com/library/en-us/msi/setup/radiobutton_table.asp]{RadioButton Table}{}
+\end{seealso}
+
+\subsection{Precomputed tables\label{msi-tables}}
+
+\module{msilib} provides a few subpackages that contain
+only schema and table definitions. Currently, these definitions
+are based on MSI version 2.0.
+
+\begin{datadesc}{schema}
+  This is the standard MSI schema for MSI 2.0, with the
+  \var{tables} variable providing a list of table definitions,
+  and \var{_Validation_records} providing the data for
+  MSI validation.
+\end{datadesc}
+
+\begin{datadesc}{sequence}
+  This module contains table contents for the standard sequence
+  tables: \var{AdminExecuteSequence}, \var{AdminUISequence},
+  \var{AdvtExecuteSequence}, \var{InstallExecuteSequence}, and
+  \var{InstallUISequence}.
+\end{datadesc}
+
+\begin{datadesc}{text}
+  This module contains definitions for the UIText and ActionText
+  tables, for the standard installer actions.
+\end{datadesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmsvcrt.tex b/sys/src/cmd/python/Doc/lib/libmsvcrt.tex
new file mode 100644
index 000000000..3e4ce5a6c
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmsvcrt.tex
@@ -0,0 +1,109 @@
+\section{\module{msvcrt} --
+         Useful routines from the MS V\Cpp\ runtime}
+
+\declaremodule{builtin}{msvcrt}
+  \platform{Windows}
+\modulesynopsis{Miscellaneous useful routines from the MS V\Cpp\ runtime.}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+
+These functions provide access to some useful capabilities on Windows
+platforms.  Some higher-level modules use these functions to build the 
+Windows implementations of their services.  For example, the
+\refmodule{getpass} module uses this in the implementation of the
+\function{getpass()} function.
+
+Further documentation on these functions can be found in the Platform
+API documentation.
+
+
+\subsection{File Operations \label{msvcrt-files}}
+
+\begin{funcdesc}{locking}{fd, mode, nbytes}
+  Lock part of a file based on file descriptor \var{fd} from the C
+  runtime.  Raises \exception{IOError} on failure.  The locked region
+  of the file extends from the current file position for \var{nbytes}
+  bytes, and may continue beyond the end of the file.  \var{mode} must
+  be one of the \constant{LK_\var{*}} constants listed below.
+  Multiple regions in a file may be locked at the same time, but may
+  not overlap.  Adjacent regions are not merged; they must be unlocked
+  individually.
+\end{funcdesc}
+
+\begin{datadesc}{LK_LOCK}
+\dataline{LK_RLCK}
+  Locks the specified bytes. If the bytes cannot be locked, the
+  program immediately tries again after 1 second.  If, after 10
+  attempts, the bytes cannot be locked, \exception{IOError} is
+  raised.
+\end{datadesc}
+
+\begin{datadesc}{LK_NBLCK}
+\dataline{LK_NBRLCK}
+  Locks the specified bytes. If the bytes cannot be locked,
+  \exception{IOError} is raised.
+\end{datadesc}
+
+\begin{datadesc}{LK_UNLCK}
+  Unlocks the specified bytes, which must have been previously locked. 
+\end{datadesc}
+
+\begin{funcdesc}{setmode}{fd, flags}
+  Set the line-end translation mode for the file descriptor \var{fd}.
+  To set it to text mode, \var{flags} should be \constant{os.O_TEXT};
+  for binary, it should be \constant{os.O_BINARY}.
+\end{funcdesc}
+
+\begin{funcdesc}{open_osfhandle}{handle, flags}
+  Create a C runtime file descriptor from the file handle
+  \var{handle}.  The \var{flags} parameter should be a bit-wise OR of
+  \constant{os.O_APPEND}, \constant{os.O_RDONLY}, and
+  \constant{os.O_TEXT}.  The returned file descriptor may be used as a
+  parameter to \function{os.fdopen()} to create a file object.
+\end{funcdesc}
+
+\begin{funcdesc}{get_osfhandle}{fd}
+  Return the file handle for the file descriptor \var{fd}.  Raises
+  \exception{IOError} if \var{fd} is not recognized.
+\end{funcdesc}
+
+
+\subsection{Console I/O \label{msvcrt-console}}
+
+\begin{funcdesc}{kbhit}{}
+  Return true if a keypress is waiting to be read.
+\end{funcdesc}
+
+\begin{funcdesc}{getch}{}
+  Read a keypress and return the resulting character.  Nothing is
+  echoed to the console.  This call will block if a keypress is not
+  already available, but will not wait for \kbd{Enter} to be pressed.
+  If the pressed key was a special function key, this will return
+  \code{'\e000'} or \code{'\e xe0'}; the next call will return the
+  keycode.  The \kbd{Control-C} keypress cannot be read with this
+  function.
+\end{funcdesc}
+
+\begin{funcdesc}{getche}{}
+  Similar to \function{getch()}, but the keypress will be echoed if it 
+  represents a printable character.
+\end{funcdesc}
+
+\begin{funcdesc}{putch}{char}
+  Print the character \var{char} to the console without buffering.
+\end{funcdesc}
+
+\begin{funcdesc}{ungetch}{char}
+  Cause the character \var{char} to be ``pushed back'' into the
+  console buffer; it will be the next character read by
+  \function{getch()} or \function{getche()}.
+\end{funcdesc}
+
+
+\subsection{Other Functions \label{msvcrt-other}}
+
+\begin{funcdesc}{heapmin}{}
+  Force the \cfunction{malloc()} heap to clean itself up and return
+  unused blocks to the operating system.  This only works on Windows
+  NT.  On failure, this raises \exception{IOError}.
+\end{funcdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libmultifile.tex b/sys/src/cmd/python/Doc/lib/libmultifile.tex
new file mode 100644
index 000000000..434832769
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmultifile.tex
@@ -0,0 +1,175 @@
+\section{\module{multifile} ---
+         Support for files containing distinct parts}
+
+\declaremodule{standard}{multifile}
+\modulesynopsis{Support for reading files which contain distinct
+                parts, such as some MIME data.}
+\sectionauthor{Eric S. Raymond}{esr@snark.thyrsus.com}
+
+\deprecated{2.5}{The \refmodule{email} package should be used in
+                 preference to the \module{multifile} module.
+                 This module is present only to maintain backward
+                 compatibility.}
+
+The \class{MultiFile} object enables you to treat sections of a text
+file as file-like input objects, with \code{''} being returned by
+\method{readline()} when a given delimiter pattern is encountered.  The
+defaults of this class are designed to make it useful for parsing
+MIME multipart messages, but by subclassing it and overriding methods 
+it can be easily adapted for more general use.
+
+\begin{classdesc}{MultiFile}{fp\optional{, seekable}}
+Create a multi-file.  You must instantiate this class with an input
+object argument for the \class{MultiFile} instance to get lines from,
+such as a file object returned by \function{open()}.
+
+\class{MultiFile} only ever looks at the input object's
+\method{readline()}, \method{seek()} and \method{tell()} methods, and
+the latter two are only needed if you want random access to the
+individual MIME parts. To use \class{MultiFile} on a non-seekable
+stream object, set the optional \var{seekable} argument to false; this
+will prevent using the input object's \method{seek()} and
+\method{tell()} methods.
+\end{classdesc}
+
+It will be useful to know that in \class{MultiFile}'s view of the world, text
+is composed of three kinds of lines: data, section-dividers, and
+end-markers.  MultiFile is designed to support parsing of
+messages that may have multiple nested message parts, each with its
+own pattern for section-divider and end-marker lines.
+
+\begin{seealso}
+  \seemodule{email}{Comprehensive email handling package; supersedes
+                    the \module{multifile} module.}
+\end{seealso}
+
+
+\subsection{MultiFile Objects \label{MultiFile-objects}}
+
+A \class{MultiFile} instance has the following methods:
+
+\begin{methoddesc}{readline}{str}
+Read a line.  If the line is data (not a section-divider or end-marker
+or real EOF) return it.  If the line matches the most-recently-stacked
+boundary, return \code{''} and set \code{self.last} to 1 or 0 according as
+the match is or is not an end-marker.  If the line matches any other
+stacked boundary, raise an error.  On encountering end-of-file on the
+underlying stream object, the method raises \exception{Error} unless
+all boundaries have been popped.
+\end{methoddesc}
+
+\begin{methoddesc}{readlines}{str}
+Return all lines remaining in this part as a list of strings.
+\end{methoddesc}
+
+\begin{methoddesc}{read}{}
+Read all lines, up to the next section.  Return them as a single
+(multiline) string.  Note that this doesn't take a size argument!
+\end{methoddesc}
+
+\begin{methoddesc}{seek}{pos\optional{, whence}}
+Seek.  Seek indices are relative to the start of the current section.
+The \var{pos} and \var{whence} arguments are interpreted as for a file
+seek.
+\end{methoddesc}
+
+\begin{methoddesc}{tell}{}
+Return the file position relative to the start of the current section.
+\end{methoddesc}
+
+\begin{methoddesc}{next}{}
+Skip lines to the next section (that is, read lines until a
+section-divider or end-marker has been consumed).  Return true if
+there is such a section, false if an end-marker is seen.  Re-enable
+the most-recently-pushed boundary.
+\end{methoddesc}
+
+\begin{methoddesc}{is_data}{str}
+Return true if \var{str} is data and false if it might be a section
+boundary.  As written, it tests for a prefix other than \code{'-}\code{-'} at
+start of line (which all MIME boundaries have) but it is declared so
+it can be overridden in derived classes.
+
+Note that this test is used intended as a fast guard for the real
+boundary tests; if it always returns false it will merely slow
+processing, not cause it to fail.
+\end{methoddesc}
+
+\begin{methoddesc}{push}{str}
+Push a boundary string.  When a decorated version of this boundary 
+is found as an input line, it will be interpreted as a section-divider 
+or end-marker (depending on the decoration, see \rfc{2045}).  All subsequent
+reads will return the empty string to indicate end-of-file, until a
+call to \method{pop()} removes the boundary a or \method{next()} call
+reenables it.
+
+It is possible to push more than one boundary.  Encountering the
+most-recently-pushed boundary will return EOF; encountering any other
+boundary will raise an error.
+\end{methoddesc}
+
+\begin{methoddesc}{pop}{}
+Pop a section boundary.  This boundary will no longer be interpreted
+as EOF.
+\end{methoddesc}
+
+\begin{methoddesc}{section_divider}{str}
+Turn a boundary into a section-divider line.  By default, this
+method prepends \code{'-}\code{-'} (which MIME section boundaries have) but
+it is declared so it can be overridden in derived classes.  This
+method need not append LF or CR-LF, as comparison with the result
+ignores trailing whitespace. 
+\end{methoddesc}
+
+\begin{methoddesc}{end_marker}{str}
+Turn a boundary string into an end-marker line.  By default, this
+method prepends \code{'-}\code{-'} and appends \code{'-}\code{-'} (like a
+MIME-multipart end-of-message marker) but it is declared so it can be
+overridden in derived classes.  This method need not append LF or
+CR-LF, as comparison with the result ignores trailing whitespace.
+\end{methoddesc}
+
+Finally, \class{MultiFile} instances have two public instance variables:
+
+\begin{memberdesc}{level}
+Nesting depth of the current part.
+\end{memberdesc}
+
+\begin{memberdesc}{last}
+True if the last end-of-file was for an end-of-message marker. 
+\end{memberdesc}
+
+
+\subsection{\class{MultiFile} Example \label{multifile-example}}
+\sectionauthor{Skip Montanaro}{skip@mojam.com}
+
+\begin{verbatim}
+import mimetools
+import multifile
+import StringIO
+
+def extract_mime_part_matching(stream, mimetype):
+    """Return the first element in a multipart MIME message on stream
+    matching mimetype."""
+
+    msg = mimetools.Message(stream)
+    msgtype = msg.gettype()
+    params = msg.getplist()
+
+    data = StringIO.StringIO()
+    if msgtype[:10] == "multipart/":
+
+        file = multifile.MultiFile(stream)
+        file.push(msg.getparam("boundary"))
+        while file.next():
+            submsg = mimetools.Message(file)
+            try:
+                data = StringIO.StringIO()
+                mimetools.decode(file, data, submsg.getencoding())
+            except ValueError:
+                continue
+            if submsg.gettype() == mimetype:
+                break
+        file.pop()
+    return data.getvalue()
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libmutex.tex b/sys/src/cmd/python/Doc/lib/libmutex.tex
new file mode 100644
index 000000000..48936904e
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libmutex.tex
@@ -0,0 +1,57 @@
+\section{\module{mutex} ---
+         Mutual exclusion support}
+
+\declaremodule{standard}{mutex}
+\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il}
+\modulesynopsis{Lock and queue for mutual exclusion.}
+
+The \module{mutex} module defines a class that allows mutual-exclusion
+via acquiring and releasing locks. It does not require (or imply)
+threading or multi-tasking, though it could be useful for
+those purposes.
+
+The \module{mutex} module defines the following class:
+
+\begin{classdesc}{mutex}{}
+Create a new (unlocked) mutex.
+
+A mutex has two pieces of state --- a ``locked'' bit and a queue.
+When the mutex is not locked, the queue is empty.
+Otherwise, the queue contains zero or more 
+\code{(\var{function}, \var{argument})} pairs
+representing functions (or methods) waiting to acquire the lock.
+When the mutex is unlocked while the queue is not empty,
+the first queue entry is removed and its 
+\code{\var{function}(\var{argument})} pair called,
+implying it now has the lock.
+
+Of course, no multi-threading is implied -- hence the funny interface
+for \method{lock()}, where a function is called once the lock is
+acquired.
+\end{classdesc}
+
+
+\subsection{Mutex Objects \label{mutex-objects}}
+
+\class{mutex} objects have following methods:
+
+\begin{methoddesc}{test}{}
+Check whether the mutex is locked.
+\end{methoddesc}
+
+\begin{methoddesc}{testandset}{}
+``Atomic'' test-and-set, grab the lock if it is not set,
+and return \code{True}, otherwise, return \code{False}.
+\end{methoddesc}
+
+\begin{methoddesc}{lock}{function, argument}
+Execute \code{\var{function}(\var{argument})}, unless the mutex is locked.
+In the case it is locked, place the function and argument on the queue.
+See \method{unlock} for explanation of when
+\code{\var{function}(\var{argument})} is executed in that case.
+\end{methoddesc}
+
+\begin{methoddesc}{unlock}{}
+Unlock the mutex if queue is empty, otherwise execute the first element
+in the queue.
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libnetrc.tex b/sys/src/cmd/python/Doc/lib/libnetrc.tex
new file mode 100644
index 000000000..f2a0c1cf3
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libnetrc.tex
@@ -0,0 +1,68 @@
+\section{\module{netrc} ---
+         netrc file processing}
+
+\declaremodule{standard}{netrc}
+% Note the \protect needed for \file... ;-(
+\modulesynopsis{Loading of \protect\file{.netrc} files.}
+\moduleauthor{Eric S. Raymond}{esr@snark.thyrsus.com}
+\sectionauthor{Eric S. Raymond}{esr@snark.thyrsus.com}
+
+
+\versionadded{1.5.2}
+
+The \class{netrc} class parses and encapsulates the netrc file format
+used by the \UNIX{} \program{ftp} program and other FTP clients.
+
+\begin{classdesc}{netrc}{\optional{file}}
+A \class{netrc} instance or subclass instance encapsulates data from 
+a netrc file.  The initialization argument, if present, specifies the
+file to parse.  If no argument is given, the file \file{.netrc} in the
+user's home directory will be read.  Parse errors will raise
+\exception{NetrcParseError} with diagnostic information including the
+file name, line number, and terminating token.
+\end{classdesc}
+
+\begin{excdesc}{NetrcParseError}
+Exception raised by the \class{netrc} class when syntactical errors
+are encountered in source text.  Instances of this exception provide
+three interesting attributes:  \member{msg} is a textual explanation
+of the error, \member{filename} is the name of the source file, and
+\member{lineno} gives the line number on which the error was found.
+\end{excdesc}
+
+
+\subsection{netrc Objects \label{netrc-objects}}
+
+A \class{netrc} instance has the following methods:
+
+\begin{methoddesc}{authenticators}{host}
+Return a 3-tuple \code{(\var{login}, \var{account}, \var{password})}
+of authenticators for \var{host}.  If the netrc file did not
+contain an entry for the given host, return the tuple associated with
+the `default' entry.  If neither matching host nor default entry is
+available, return \code{None}.
+\end{methoddesc}
+
+\begin{methoddesc}{__repr__}{}
+Dump the class data as a string in the format of a netrc file.
+(This discards comments and may reorder the entries.)
+\end{methoddesc}
+
+Instances of \class{netrc} have public instance variables:
+
+\begin{memberdesc}{hosts}
+Dictionary mapping host names to \code{(\var{login}, \var{account},
+\var{password})} tuples.  The `default' entry, if any, is represented
+as a pseudo-host by that name.
+\end{memberdesc}
+
+\begin{memberdesc}{macros}
+Dictionary mapping macro names to string lists.
+\end{memberdesc}
+
+\note{Passwords are limited to a subset of the ASCII character set.
+Versions of this module prior to 2.3 were extremely limited.  Starting with
+2.3, all ASCII punctuation is allowed in passwords.  However, note that
+whitespace and non-printable characters are not allowed in passwords.  This
+is a limitation of the way the .netrc file is parsed and may be removed in
+the future.}
diff --git a/sys/src/cmd/python/Doc/lib/libnew.tex b/sys/src/cmd/python/Doc/lib/libnew.tex
new file mode 100644
index 000000000..d0394d108
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libnew.tex
@@ -0,0 +1,63 @@
+\section{\module{new} ---
+         Creation of runtime internal objects}
+
+\declaremodule{builtin}{new}
+\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il}
+\modulesynopsis{Interface to the creation of runtime implementation objects.}
+
+
+The \module{new} module allows an interface to the interpreter object
+creation functions. This is for use primarily in marshal-type functions,
+when a new object needs to be created ``magically'' and not by using the
+regular creation functions. This module provides a low-level interface
+to the interpreter, so care must be exercised when using this module.
+It is possible to supply non-sensical arguments which crash the
+interpreter when the object is used.
+
+The \module{new} module defines the following functions:
+
+\begin{funcdesc}{instance}{class\optional{, dict}}
+This function creates an instance of \var{class} with dictionary
+\var{dict} without calling the \method{__init__()} constructor.  If
+\var{dict} is omitted or \code{None}, a new, empty dictionary is
+created for the new instance.  Note that there are no guarantees that
+the object will be in a consistent state.
+\end{funcdesc}
+
+\begin{funcdesc}{instancemethod}{function, instance, class}
+This function will return a method object, bound to \var{instance}, or
+unbound if \var{instance} is \code{None}.  \var{function} must be
+callable.
+\end{funcdesc}
+
+\begin{funcdesc}{function}{code, globals\optional{, name\optional{,
+                           argdefs\optional{, closure}}}}
+Returns a (Python) function with the given code and globals. If
+\var{name} is given, it must be a string or \code{None}.  If it is a
+string, the function will have the given name, otherwise the function
+name will be taken from \code{\var{code}.co_name}.  If
+\var{argdefs} is given, it must be a tuple and will be used to
+determine the default values of parameters.  If \var{closure} is given,
+it must be \code{None} or a tuple of cell objects containing objects
+to bind to the names in \code{\var{code}.co_freevars}.
+\end{funcdesc}
+
+\begin{funcdesc}{code}{argcount, nlocals, stacksize, flags, codestring,
+                       constants, names, varnames, filename, name, firstlineno,
+                       lnotab}
+This function is an interface to the \cfunction{PyCode_New()} C
+function.
+%XXX This is still undocumented!!!!!!!!!!!
+\end{funcdesc}
+
+\begin{funcdesc}{module}{name[, doc]}
+This function returns a new module object with name \var{name}.
+\var{name} must be a string.
+The optional \var{doc} argument can have any type.
+\end{funcdesc}
+
+\begin{funcdesc}{classobj}{name, baseclasses, dict}
+This function returns a new class object, with name \var{name}, derived
+from \var{baseclasses} (which should be a tuple of classes) and with
+namespace \var{dict}.
+\end{funcdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libni.tex b/sys/src/cmd/python/Doc/lib/libni.tex
new file mode 100644
index 000000000..fa2b3eebf
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libni.tex
@@ -0,0 +1,63 @@
+\section{\module{ni} ---
+         None}
+\declaremodule{standard}{ni}
+
+\modulesynopsis{None}
+
+
+\strong{Warning: This module is obsolete.}  As of Python 1.5a4,
+package support (with different semantics for \code{__init__} and no
+support for \code{__domain__} or \code{__}) is built in the
+interpreter.  The ni module is retained only for backward
+compatibility.  As of Python 1.5b2, it has been renamed to \code{ni1}; 
+if you really need it, you can use \code{import ni1}, but the
+recommended approach is to rely on the built-in package support,
+converting existing packages if needed.  Note that mixing \code{ni}
+and the built-in package support doesn't work: once you import
+\code{ni}, all packages use it.
+
+The \code{ni} module defines a new importing scheme, which supports
+packages containing several Python modules.  To enable package
+support, execute \code{import ni} before importing any packages.  Importing
+this module automatically installs the relevant import hooks.  There
+are no publicly-usable functions or variables in the \code{ni} module.
+
+To create a package named \code{spam} containing sub-modules \code{ham}, \code{bacon} and
+\code{eggs}, create a directory \file{spam} somewhere on Python's module search
+path, as given in \code{sys.path}.  Then, create files called \file{ham.py}, \file{bacon.py} and
+\file{eggs.py} inside \file{spam}.
+
+To import module \code{ham} from package \code{spam} and use function
+\code{hamneggs()} from that module, you can use any of the following
+possibilities:
+
+\begin{verbatim}
+import spam.ham		# *not* "import spam" !!!
+spam.ham.hamneggs()
+\end{verbatim}
+%
+\begin{verbatim}
+from spam import ham
+ham.hamneggs()
+\end{verbatim}
+%
+\begin{verbatim}
+from spam.ham import hamneggs
+hamneggs()
+\end{verbatim}
+%
+\code{import spam} creates an
+empty package named \code{spam} if one does not already exist, but it does
+\emph{not} automatically import \code{spam}'s submodules.  
+The only submodule that is guaranteed to be imported is
+\code{spam.__init__}, if it exists; it would be in a file named
+\file{__init__.py} in the \file{spam} directory.  Note that
+\code{spam.__init__} is a submodule of package spam.  It can refer to
+spam's namespace as \code{__} (two underscores):
+
+\begin{verbatim}
+__.spam_inited = 1		# Set a package-level variable
+\end{verbatim}
+%
+Additional initialization code (setting up variables, importing other
+submodules) can be performed in \file{spam/__init__.py}.
diff --git a/sys/src/cmd/python/Doc/lib/libnis.tex b/sys/src/cmd/python/Doc/lib/libnis.tex
new file mode 100644
index 000000000..cc1482db5
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libnis.tex
@@ -0,0 +1,63 @@
+\section{\module{nis} ---
+         Interface to Sun's NIS (Yellow Pages)}
+
+\declaremodule{extension}{nis}
+  \platform{UNIX}
+\moduleauthor{Fred Gansevles}{Fred.Gansevles@cs.utwente.nl}
+\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il}
+\modulesynopsis{Interface to Sun's NIS (Yellow Pages) library.}
+
+The \module{nis} module gives a thin wrapper around the NIS library, useful
+for central administration of several hosts.
+
+Because NIS exists only on \UNIX{} systems, this module is
+only available for \UNIX.
+
+The \module{nis} module defines the following functions:
+
+\begin{funcdesc}{match}{key, mapname[, domain=default_domain]}
+Return the match for \var{key} in map \var{mapname}, or raise an
+error (\exception{nis.error}) if there is none.
+Both should be strings, \var{key} is 8-bit clean.
+Return value is an arbitrary array of bytes (may contain \code{NULL}
+and other joys).
+
+Note that \var{mapname} is first checked if it is an alias to another
+name.
+
+\versionchanged[The \var{domain} argument allows to override
+the NIS domain used for the lookup. If unspecified, lookup is in the
+default NIS domain]{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{cat}{mapname[, domain=default_domain]}
+Return a dictionary mapping \var{key} to \var{value} such that
+\code{match(\var{key}, \var{mapname})==\var{value}}.
+Note that both keys and values of the dictionary are arbitrary
+arrays of bytes.
+
+Note that \var{mapname} is first checked if it is an alias to another
+name.
+
+\versionchanged[The \var{domain} argument allows to override
+the NIS domain used for the lookup. If unspecified, lookup is in the
+default NIS domain]{2.5}
+\end{funcdesc}
+
+ \begin{funcdesc}{maps}{[domain=default_domain]}
+Return a list of all valid maps.
+
+\versionchanged[The \var{domain} argument allows to override
+the NIS domain used for the lookup. If unspecified, lookup is in the
+default NIS domain]{2.5}
+\end{funcdesc}
+
+ \begin{funcdesc}{get_default_domain}{}
+Return the system default NIS domain. \versionadded{2.5}
+\end{funcdesc}
+
+The \module{nis} module defines the following exception:
+
+\begin{excdesc}{error}
+An error raised when a NIS function returns an error code.
+\end{excdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libnntplib.tex b/sys/src/cmd/python/Doc/lib/libnntplib.tex
new file mode 100644
index 000000000..10330ed9b
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libnntplib.tex
@@ -0,0 +1,355 @@
+\section{\module{nntplib} ---
+         NNTP protocol client}
+
+\declaremodule{standard}{nntplib}
+\modulesynopsis{NNTP protocol client (requires sockets).}
+
+\indexii{NNTP}{protocol}
+\index{Network News Transfer Protocol}
+
+This module defines the class \class{NNTP} which implements the client
+side of the NNTP protocol.  It can be used to implement a news reader
+or poster, or automated news processors.  For more information on NNTP
+(Network News Transfer Protocol), see Internet \rfc{977}.
+
+Here are two small examples of how it can be used.  To list some
+statistics about a newsgroup and print the subjects of the last 10
+articles:
+
+\begin{verbatim}
+>>> s = NNTP('news.cwi.nl')
+>>> resp, count, first, last, name = s.group('comp.lang.python')
+>>> print 'Group', name, 'has', count, 'articles, range', first, 'to', last
+Group comp.lang.python has 59 articles, range 3742 to 3803
+>>> resp, subs = s.xhdr('subject', first + '-' + last)
+>>> for id, sub in subs[-10:]: print id, sub
+... 
+3792 Re: Removing elements from a list while iterating...
+3793 Re: Who likes Info files?
+3794 Emacs and doc strings
+3795 a few questions about the Mac implementation
+3796 Re: executable python scripts
+3797 Re: executable python scripts
+3798 Re: a few questions about the Mac implementation 
+3799 Re: PROPOSAL: A Generic Python Object Interface for Python C Modules
+3802 Re: executable python scripts 
+3803 Re: \POSIX{} wait and SIGCHLD
+>>> s.quit()
+'205 news.cwi.nl closing connection.  Goodbye.'
+\end{verbatim}
+
+To post an article from a file (this assumes that the article has
+valid headers):
+
+\begin{verbatim}
+>>> s = NNTP('news.cwi.nl')
+>>> f = open('/tmp/article')
+>>> s.post(f)
+'240 Article posted successfully.'
+>>> s.quit()
+'205 news.cwi.nl closing connection.  Goodbye.'
+\end{verbatim}
+
+The module itself defines the following items:
+
+\begin{classdesc}{NNTP}{host\optional{, port
+                        \optional{, user\optional{, password
+			\optional{, readermode}
+			\optional{, usenetrc}}}}}
+Return a new instance of the \class{NNTP} class, representing a
+connection to the NNTP server running on host \var{host}, listening at
+port \var{port}.  The default \var{port} is 119.  If the optional
+\var{user} and \var{password} are provided, 
+or if suitable credentials are present in \file{~/.netrc} and the
+optional flag \var{usenetrc} is true (the default),
+the \samp{AUTHINFO USER} and \samp{AUTHINFO PASS} commands are used to
+identify and authenticate the user to the server.  If the optional
+flag \var{readermode} is true, then a \samp{mode reader} command is
+sent before authentication is performed.  Reader mode is sometimes
+necessary if you are connecting to an NNTP server on the local machine
+and intend to call reader-specific commands, such as \samp{group}.  If
+you get unexpected \exception{NNTPPermanentError}s, you might need to set
+\var{readermode}.  \var{readermode} defaults to \code{None}.
+\var{usenetrc} defaults to \code{True}.
+
+\versionchanged[\var{usenetrc} argument added]{2.4}
+\end{classdesc}
+
+\begin{excdesc}{NNTPError}
+Derived from the standard exception \exception{Exception}, this is the
+base class for all exceptions raised by the \module{nntplib} module.
+\end{excdesc}
+
+\begin{excdesc}{NNTPReplyError}
+Exception raised when an unexpected reply is received from the
+server.  For backwards compatibility, the exception \code{error_reply}
+is equivalent to this class.
+\end{excdesc}
+
+\begin{excdesc}{NNTPTemporaryError}
+Exception raised when an error code in the range 400--499 is
+received.  For backwards compatibility, the exception
+\code{error_temp} is equivalent to this class.
+\end{excdesc}
+
+\begin{excdesc}{NNTPPermanentError}
+Exception raised when an error code in the range 500--599 is
+received.  For backwards compatibility, the exception
+\code{error_perm} is equivalent to this class.
+\end{excdesc}
+
+\begin{excdesc}{NNTPProtocolError}
+Exception raised when a reply is received from the server that does
+not begin with a digit in the range 1--5.  For backwards
+compatibility, the exception \code{error_proto} is equivalent to this
+class.
+\end{excdesc}
+
+\begin{excdesc}{NNTPDataError}
+Exception raised when there is some error in the response data.  For
+backwards compatibility, the exception \code{error_data} is
+equivalent to this class.
+\end{excdesc}
+
+
+\subsection{NNTP Objects \label{nntp-objects}}
+
+NNTP instances have the following methods.  The \var{response} that is
+returned as the first item in the return tuple of almost all methods
+is the server's response: a string beginning with a three-digit code.
+If the server's response indicates an error, the method raises one of
+the above exceptions.
+
+
+\begin{methoddesc}{getwelcome}{}
+Return the welcome message sent by the server in reply to the initial
+connection.  (This message sometimes contains disclaimers or help
+information that may be relevant to the user.)
+\end{methoddesc}
+
+\begin{methoddesc}{set_debuglevel}{level}
+Set the instance's debugging level.  This controls the amount of
+debugging output printed.  The default, \code{0}, produces no debugging
+output.  A value of \code{1} produces a moderate amount of debugging
+output, generally a single line per request or response.  A value of
+\code{2} or higher produces the maximum amount of debugging output,
+logging each line sent and received on the connection (including
+message text).
+\end{methoddesc}
+
+\begin{methoddesc}{newgroups}{date, time, \optional{file}}
+Send a \samp{NEWGROUPS} command.  The \var{date} argument should be a
+string of the form \code{'\var{yy}\var{mm}\var{dd}'} indicating the
+date, and \var{time} should be a string of the form
+\code{'\var{hh}\var{mm}\var{ss}'} indicating the time.  Return a pair
+\code{(\var{response}, \var{groups})} where \var{groups} is a list of
+group names that are new since the given date and time.
+If the \var{file} parameter is supplied, then the output of the 
+\samp{NEWGROUPS} command is stored in a file.  If \var{file} is a string, 
+then the method will open a file object with that name, write to it 
+then close it.  If \var{file} is a file object, then it will start
+calling \method{write()} on it to store the lines of the command output.
+If \var{file} is supplied, then the returned \var{list} is an empty list.
+\end{methoddesc}
+
+\begin{methoddesc}{newnews}{group, date, time, \optional{file}}
+Send a \samp{NEWNEWS} command.  Here, \var{group} is a group name or
+\code{'*'}, and \var{date} and \var{time} have the same meaning as for
+\method{newgroups()}.  Return a pair \code{(\var{response},
+\var{articles})} where \var{articles} is a list of message ids.
+If the \var{file} parameter is supplied, then the output of the 
+\samp{NEWNEWS} command is stored in a file.  If \var{file} is a string, 
+then the method will open a file object with that name, write to it 
+then close it.  If \var{file} is a file object, then it will start
+calling \method{write()} on it to store the lines of the command output.
+If \var{file} is supplied, then the returned \var{list} is an empty list.
+\end{methoddesc}
+
+\begin{methoddesc}{list}{\optional{file}}
+Send a \samp{LIST} command.  Return a pair \code{(\var{response},
+\var{list})} where \var{list} is a list of tuples.  Each tuple has the
+form \code{(\var{group}, \var{last}, \var{first}, \var{flag})}, where
+\var{group} is a group name, \var{last} and \var{first} are the last
+and first article numbers (as strings), and \var{flag} is
+\code{'y'} if posting is allowed, \code{'n'} if not, and \code{'m'} if
+the newsgroup is moderated.  (Note the ordering: \var{last},
+\var{first}.)
+If the \var{file} parameter is supplied, then the output of the 
+\samp{LIST} command is stored in a file.  If \var{file} is a string, 
+then the method will open a file object with that name, write to it 
+then close it.  If \var{file} is a file object, then it will start
+calling \method{write()} on it to store the lines of the command output.
+If \var{file} is supplied, then the returned \var{list} is an empty list.
+\end{methoddesc}
+
+\begin{methoddesc}{descriptions}{grouppattern}
+Send a \samp{LIST NEWSGROUPS} command, where \var{grouppattern} is a wildmat
+string as specified in RFC2980 (it's essentially the same as DOS or UNIX
+shell wildcard strings).  Return a pair \code{(\var{response},
+\var{list})}, where \var{list} is a list of tuples containing
+\code{(\var{name}, \var{title})}.
+
+\versionadded{2.4}
+\end{methoddesc}
+
+\begin{methoddesc}{description}{group}
+Get a description for a single group \var{group}.  If more than one group
+matches (if 'group' is a real wildmat string), return the first match.  
+If no group matches, return an empty string.
+
+This elides the response code from the server.  If the response code is
+needed, use \method{descriptions()}.
+
+\versionadded{2.4}
+\end{methoddesc}
+
+\begin{methoddesc}{group}{name}
+Send a \samp{GROUP} command, where \var{name} is the group name.
+Return a tuple \code{(\var{response}, \var{count}, \var{first},
+\var{last}, \var{name})} where \var{count} is the (estimated) number
+of articles in the group, \var{first} is the first article number in
+the group, \var{last} is the last article number in the group, and
+\var{name} is the group name.  The numbers are returned as strings.
+\end{methoddesc}
+
+\begin{methoddesc}{help}{\optional{file}}
+Send a \samp{HELP} command.  Return a pair \code{(\var{response},
+\var{list})} where \var{list} is a list of help strings.
+If the \var{file} parameter is supplied, then the output of the 
+\samp{HELP} command is stored in a file.  If \var{file} is a string, 
+then the method will open a file object with that name, write to it 
+then close it.  If \var{file} is a file object, then it will start
+calling \method{write()} on it to store the lines of the command output.
+If \var{file} is supplied, then the returned \var{list} is an empty list.
+\end{methoddesc}
+
+\begin{methoddesc}{stat}{id}
+Send a \samp{STAT} command, where \var{id} is the message id (enclosed
+in \character{<} and \character{>}) or an article number (as a string).
+Return a triple \code{(\var{response}, \var{number}, \var{id})} where
+\var{number} is the article number (as a string) and \var{id} is the
+message id  (enclosed in \character{<} and \character{>}).
+\end{methoddesc}
+
+\begin{methoddesc}{next}{}
+Send a \samp{NEXT} command.  Return as for \method{stat()}.
+\end{methoddesc}
+
+\begin{methoddesc}{last}{}
+Send a \samp{LAST} command.  Return as for \method{stat()}.
+\end{methoddesc}
+
+\begin{methoddesc}{head}{id}
+Send a \samp{HEAD} command, where \var{id} has the same meaning as for
+\method{stat()}.  Return a tuple
+\code{(\var{response}, \var{number}, \var{id}, \var{list})}
+where the first three are the same as for \method{stat()},
+and \var{list} is a list of the article's headers (an uninterpreted
+list of lines, without trailing newlines).
+\end{methoddesc}
+
+\begin{methoddesc}{body}{id,\optional{file}}
+Send a \samp{BODY} command, where \var{id} has the same meaning as for
+\method{stat()}.  If the \var{file} parameter is supplied, then
+the body is stored in a file.  If \var{file} is a string, then
+the method will open a file object with that name, write to it then close it.
+If \var{file} is a file object, then it will start calling
+\method{write()} on it to store the lines of the body.
+Return as for \method{head()}.  If \var{file} is supplied, then
+the returned \var{list} is an empty list.
+\end{methoddesc}
+
+\begin{methoddesc}{article}{id}
+Send an \samp{ARTICLE} command, where \var{id} has the same meaning as
+for \method{stat()}.  Return as for \method{head()}.
+\end{methoddesc}
+
+\begin{methoddesc}{slave}{}
+Send a \samp{SLAVE} command.  Return the server's \var{response}.
+\end{methoddesc}
+
+\begin{methoddesc}{xhdr}{header, string, \optional{file}}
+Send an \samp{XHDR} command.  This command is not defined in the RFC
+but is a common extension.  The \var{header} argument is a header
+keyword, e.g. \code{'subject'}.  The \var{string} argument should have
+the form \code{'\var{first}-\var{last}'} where \var{first} and
+\var{last} are the first and last article numbers to search.  Return a
+pair \code{(\var{response}, \var{list})}, where \var{list} is a list of
+pairs \code{(\var{id}, \var{text})}, where \var{id} is an article number
+(as a string) and \var{text} is the text of the requested header for
+that article.
+If the \var{file} parameter is supplied, then the output of the 
+\samp{XHDR} command is stored in a file.  If \var{file} is a string, 
+then the method will open a file object with that name, write to it 
+then close it.  If \var{file} is a file object, then it will start
+calling \method{write()} on it to store the lines of the command output.
+If \var{file} is supplied, then the returned \var{list} is an empty list.
+\end{methoddesc}
+
+\begin{methoddesc}{post}{file}
+Post an article using the \samp{POST} command.  The \var{file}
+argument is an open file object which is read until EOF using its
+\method{readline()} method.  It should be a well-formed news article,
+including the required headers.  The \method{post()} method
+automatically escapes lines beginning with \samp{.}.
+\end{methoddesc}
+
+\begin{methoddesc}{ihave}{id, file}
+Send an \samp{IHAVE} command. \var{id} is a message id (enclosed in 
+\character{<} and \character{>}).
+If the response is not an error, treat
+\var{file} exactly as for the \method{post()} method.
+\end{methoddesc}
+
+\begin{methoddesc}{date}{}
+Return a triple \code{(\var{response}, \var{date}, \var{time})},
+containing the current date and time in a form suitable for the
+\method{newnews()} and \method{newgroups()} methods.
+This is an optional NNTP extension, and may not be supported by all
+servers.
+\end{methoddesc}
+
+\begin{methoddesc}{xgtitle}{name, \optional{file}}
+Process an \samp{XGTITLE} command, returning a pair \code{(\var{response},
+\var{list})}, where \var{list} is a list of tuples containing
+\code{(\var{name}, \var{title})}.
+% XXX huh?  Should that be name, description?
+If the \var{file} parameter is supplied, then the output of the 
+\samp{XGTITLE} command is stored in a file.  If \var{file} is a string, 
+then the method will open a file object with that name, write to it 
+then close it.  If \var{file} is a file object, then it will start
+calling \method{write()} on it to store the lines of the command output.
+If \var{file} is supplied, then the returned \var{list} is an empty list.
+This is an optional NNTP extension, and may not be supported by all
+servers.
+
+RFC2980 says ``It is suggested that this extension be deprecated''.  Use
+\method{descriptions()} or \method{description()} instead.
+\end{methoddesc}
+
+\begin{methoddesc}{xover}{start, end, \optional{file}}
+Return a pair \code{(\var{resp}, \var{list})}.  \var{list} is a list
+of tuples, one for each article in the range delimited by the \var{start}
+and \var{end} article numbers.  Each tuple is of the form
+\code{(\var{article number}, \var{subject}, \var{poster}, \var{date},
+\var{id}, \var{references}, \var{size}, \var{lines})}.
+If the \var{file} parameter is supplied, then the output of the 
+\samp{XOVER} command is stored in a file.  If \var{file} is a string, 
+then the method will open a file object with that name, write to it 
+then close it.  If \var{file} is a file object, then it will start
+calling \method{write()} on it to store the lines of the command output.
+If \var{file} is supplied, then the returned \var{list} is an empty list.
+This is an optional NNTP extension, and may not be supported by all
+servers.
+\end{methoddesc}
+
+\begin{methoddesc}{xpath}{id}
+Return a pair \code{(\var{resp}, \var{path})}, where \var{path} is the
+directory path to the article with message ID \var{id}.  This is an
+optional NNTP extension, and may not be supported by all servers.
+\end{methoddesc}
+
+\begin{methoddesc}{quit}{}
+Send a \samp{QUIT} command and close the connection.  Once this method
+has been called, no other methods of the NNTP object should be called.
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libobjs.tex b/sys/src/cmd/python/Doc/lib/libobjs.tex
new file mode 100644
index 000000000..3c7d79808
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libobjs.tex
@@ -0,0 +1,24 @@
+\chapter{Built-in Objects \label{builtin}}
+
+Names for built-in exceptions and functions and a number of constants are
+found in a separate 
+symbol table.  This table is searched last when the interpreter looks
+up the meaning of a name, so local and global
+user-defined names can override built-in names.  Built-in types are
+described together here for easy reference.\footnote{
+	Most descriptions sorely lack explanations of the exceptions
+	that may be raised --- this will be fixed in a future version of
+	this manual.}
+\indexii{built-in}{types}
+\indexii{built-in}{exceptions}
+\indexii{built-in}{functions}
+\indexii{built-in}{constants}
+\index{symbol table}
+
+The tables in this chapter document the priorities of operators by
+listing them in order of ascending priority (within a table) and
+grouping operators that have the same priority in the same box.
+Binary operators of the same priority group from left to right.
+(Unary operators group from right to left, but there you have no real
+choice.)  See chapter 5 of the \citetitle[../ref/ref.html]{Python
+Reference Manual} for the complete picture on operator priorities.
diff --git a/sys/src/cmd/python/Doc/lib/liboperator.tex b/sys/src/cmd/python/Doc/lib/liboperator.tex
new file mode 100644
index 000000000..5ba3209be
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/liboperator.tex
@@ -0,0 +1,530 @@
+\section{\module{operator} ---
+         Standard operators as functions.}
+\declaremodule{builtin}{operator}
+\sectionauthor{Skip Montanaro}{skip@automatrix.com}
+
+\modulesynopsis{All Python's standard operators as built-in functions.}
+
+
+The \module{operator} module exports a set of functions implemented in C
+corresponding to the intrinsic operators of Python.  For example,
+\code{operator.add(x, y)} is equivalent to the expression \code{x+y}.  The
+function names are those used for special class methods; variants without
+leading and trailing \samp{__} are also provided for convenience.
+
+The functions fall into categories that perform object comparisons,
+logical operations, mathematical operations, sequence operations, and
+abstract type tests.
+
+The object comparison functions are useful for all objects, and are
+named after the rich comparison operators they support:
+
+\begin{funcdesc}{lt}{a, b}
+\funcline{le}{a, b}
+\funcline{eq}{a, b}
+\funcline{ne}{a, b}
+\funcline{ge}{a, b}
+\funcline{gt}{a, b}
+\funcline{__lt__}{a, b}
+\funcline{__le__}{a, b}
+\funcline{__eq__}{a, b}
+\funcline{__ne__}{a, b}
+\funcline{__ge__}{a, b}
+\funcline{__gt__}{a, b}
+Perform ``rich comparisons'' between \var{a} and \var{b}. Specifically,
+\code{lt(\var{a}, \var{b})} is equivalent to \code{\var{a} < \var{b}},
+\code{le(\var{a}, \var{b})} is equivalent to \code{\var{a} <= \var{b}},
+\code{eq(\var{a}, \var{b})} is equivalent to \code{\var{a} == \var{b}},
+\code{ne(\var{a}, \var{b})} is equivalent to \code{\var{a} != \var{b}},
+\code{gt(\var{a}, \var{b})} is equivalent to \code{\var{a} > \var{b}}
+and
+\code{ge(\var{a}, \var{b})} is equivalent to \code{\var{a} >= \var{b}}.
+Note that unlike the built-in \function{cmp()}, these functions can
+return any value, which may or may not be interpretable as a Boolean
+value.  See the \citetitle[../ref/ref.html]{Python Reference Manual}
+for more information about rich comparisons.
+\versionadded{2.2}
+\end{funcdesc}
+
+
+The logical operations are also generally applicable to all objects,
+and support truth tests, identity tests, and boolean operations:
+
+\begin{funcdesc}{not_}{o}
+\funcline{__not__}{o}
+Return the outcome of \keyword{not} \var{o}.  (Note that there is no
+\method{__not__()} method for object instances; only the interpreter
+core defines this operation.  The result is affected by the
+\method{__nonzero__()} and \method{__len__()} methods.)
+\end{funcdesc}
+
+\begin{funcdesc}{truth}{o}
+Return \constant{True} if \var{o} is true, and \constant{False}
+otherwise.  This is equivalent to using the \class{bool}
+constructor.
+\end{funcdesc}
+
+\begin{funcdesc}{is_}{a, b}
+Return \code{\var{a} is \var{b}}.  Tests object identity.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{is_not}{a, b}
+Return \code{\var{a} is not \var{b}}.  Tests object identity.
+\versionadded{2.3}
+\end{funcdesc}
+
+
+The mathematical and bitwise operations are the most numerous:
+
+\begin{funcdesc}{abs}{o}
+\funcline{__abs__}{o}
+Return the absolute value of \var{o}.
+\end{funcdesc}
+
+\begin{funcdesc}{add}{a, b}
+\funcline{__add__}{a, b}
+Return \var{a} \code{+} \var{b}, for \var{a} and \var{b} numbers.
+\end{funcdesc}
+
+\begin{funcdesc}{and_}{a, b}
+\funcline{__and__}{a, b}
+Return the bitwise and of \var{a} and \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{div}{a, b}
+\funcline{__div__}{a, b}
+Return \var{a} \code{/} \var{b} when \code{__future__.division} is not
+in effect.  This is also known as ``classic'' division.
+\end{funcdesc}
+
+\begin{funcdesc}{floordiv}{a, b}
+\funcline{__floordiv__}{a, b}
+Return \var{a} \code{//} \var{b}.
+\versionadded{2.2}
+\end{funcdesc}
+
+\begin{funcdesc}{inv}{o}
+\funcline{invert}{o}
+\funcline{__inv__}{o}
+\funcline{__invert__}{o}
+Return the bitwise inverse of the number \var{o}.  This is equivalent
+to \code{\textasciitilde}\var{o}.  The names \function{invert()} and
+\function{__invert__()} were added in Python 2.0.
+\end{funcdesc}
+
+\begin{funcdesc}{lshift}{a, b}
+\funcline{__lshift__}{a, b}
+Return \var{a} shifted left by \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{mod}{a, b}
+\funcline{__mod__}{a, b}
+Return \var{a} \code{\%} \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{mul}{a, b}
+\funcline{__mul__}{a, b}
+Return \var{a} \code{*} \var{b}, for \var{a} and \var{b} numbers.
+\end{funcdesc}
+
+\begin{funcdesc}{neg}{o}
+\funcline{__neg__}{o}
+Return \var{o} negated.
+\end{funcdesc}
+
+\begin{funcdesc}{or_}{a, b}
+\funcline{__or__}{a, b}
+Return the bitwise or of \var{a} and \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{pos}{o}
+\funcline{__pos__}{o}
+Return \var{o} positive.
+\end{funcdesc}
+
+\begin{funcdesc}{pow}{a, b}
+\funcline{__pow__}{a, b}
+Return \var{a} \code{**} \var{b}, for \var{a} and \var{b} numbers.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{rshift}{a, b}
+\funcline{__rshift__}{a, b}
+Return \var{a} shifted right by \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{sub}{a, b}
+\funcline{__sub__}{a, b}
+Return \var{a} \code{-} \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{truediv}{a, b}
+\funcline{__truediv__}{a, b}
+Return \var{a} \code{/} \var{b} when \code{__future__.division} is in
+effect.  This is also known as ``true'' division.
+\versionadded{2.2}
+\end{funcdesc}
+
+\begin{funcdesc}{xor}{a, b}
+\funcline{__xor__}{a, b}
+Return the bitwise exclusive or of \var{a} and \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{index}{a}
+\funcline{__index__}{a}
+Return \var{a} converted to an integer.  Equivalent to \var{a}\code{.__index__()}.
+\versionadded{2.5}
+\end{funcdesc}
+
+Operations which work with sequences include:
+
+\begin{funcdesc}{concat}{a, b}
+\funcline{__concat__}{a, b}
+Return \var{a} \code{+} \var{b} for \var{a} and \var{b} sequences.
+\end{funcdesc}
+
+\begin{funcdesc}{contains}{a, b}
+\funcline{__contains__}{a, b}
+Return the outcome of the test \var{b} \code{in} \var{a}.
+Note the reversed operands.  The name \function{__contains__()} was
+added in Python 2.0.
+\end{funcdesc}
+
+\begin{funcdesc}{countOf}{a, b}
+Return the number of occurrences of \var{b} in \var{a}.
+\end{funcdesc}
+
+\begin{funcdesc}{delitem}{a, b}
+\funcline{__delitem__}{a, b}
+Remove the value of \var{a} at index \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{delslice}{a, b, c}
+\funcline{__delslice__}{a, b, c}
+Delete the slice of \var{a} from index \var{b} to index \var{c}\code{-1}.
+\end{funcdesc}
+
+\begin{funcdesc}{getitem}{a, b}
+\funcline{__getitem__}{a, b}
+Return the value of \var{a} at index \var{b}.
+\end{funcdesc}
+
+\begin{funcdesc}{getslice}{a, b, c}
+\funcline{__getslice__}{a, b, c}
+Return the slice of \var{a} from index \var{b} to index \var{c}\code{-1}.
+\end{funcdesc}
+
+\begin{funcdesc}{indexOf}{a, b}
+Return the index of the first of occurrence of \var{b} in \var{a}.
+\end{funcdesc}
+
+\begin{funcdesc}{repeat}{a, b}
+\funcline{__repeat__}{a, b}
+Return \var{a} \code{*} \var{b} where \var{a} is a sequence and
+\var{b} is an integer.
+\end{funcdesc}
+
+\begin{funcdesc}{sequenceIncludes}{\unspecified}
+\deprecated{2.0}{Use \function{contains()} instead.}
+Alias for \function{contains()}.
+\end{funcdesc}
+
+\begin{funcdesc}{setitem}{a, b, c}
+\funcline{__setitem__}{a, b, c}
+Set the value of \var{a} at index \var{b} to \var{c}.
+\end{funcdesc}
+
+\begin{funcdesc}{setslice}{a, b, c, v}
+\funcline{__setslice__}{a, b, c, v}
+Set the slice of \var{a} from index \var{b} to index \var{c}\code{-1} to the
+sequence \var{v}.
+\end{funcdesc}
+
+
+Many operations have an ``in-place'' version.  The following functions
+provide a more primitive access to in-place operators than the usual
+syntax does; for example, the statement \code{x += y} is equivalent to
+\code{x = operator.iadd(x, y)}.  Another way to put it is to say that
+\code{z = operator.iadd(x, y)} is equivalent to the compound statement
+\code{z = x; z += y}.
+
+\begin{funcdesc}{iadd}{a, b}
+\funcline{__iadd__}{a, b}
+\code{a = iadd(a, b)} is equivalent to \code{a += b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{iand}{a, b}
+\funcline{__iand__}{a, b}
+\code{a = iand(a, b)} is equivalent to \code{a \&= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{iconcat}{a, b}
+\funcline{__iconcat__}{a, b}
+\code{a = iconcat(a, b)} is equivalent to \code{a += b} for \var{a}
+and \var{b} sequences.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{idiv}{a, b}
+\funcline{__idiv__}{a, b}
+\code{a = idiv(a, b)} is equivalent to \code{a /= b} when
+\code{__future__.division} is not in effect.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{ifloordiv}{a, b}
+\funcline{__ifloordiv__}{a, b}
+\code{a = ifloordiv(a, b)} is equivalent to \code{a //= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{ilshift}{a, b}
+\funcline{__ilshift__}{a, b}
+\code{a = ilshift(a, b)} is equivalent to \code{a <}\code{<= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{imod}{a, b}
+\funcline{__imod__}{a, b}
+\code{a = imod(a, b)} is equivalent to \code{a \%= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{imul}{a, b}
+\funcline{__imul__}{a, b}
+\code{a = imul(a, b)} is equivalent to \code{a *= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{ior}{a, b}
+\funcline{__ior__}{a, b}
+\code{a = ior(a, b)} is equivalent to \code{a |= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{ipow}{a, b}
+\funcline{__ipow__}{a, b}
+\code{a = ipow(a, b)} is equivalent to \code{a **= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{irepeat}{a, b}
+\funcline{__irepeat__}{a, b}
+\code{a = irepeat(a, b)} is equivalent to \code{a *= b} where
+\var{a} is a sequence and \var{b} is an integer.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{irshift}{a, b}
+\funcline{__irshift__}{a, b}
+\code{a = irshift(a, b)} is equivalent to \code{a >>= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{isub}{a, b}
+\funcline{__isub__}{a, b}
+\code{a = isub(a, b)} is equivalent to \code{a -= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{itruediv}{a, b}
+\funcline{__itruediv__}{a, b}
+\code{a = itruediv(a, b)} is equivalent to \code{a /= b} when
+\code{__future__.division} is in effect.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{ixor}{a, b}
+\funcline{__ixor__}{a, b}
+\code{a = ixor(a, b)} is equivalent to \code{a \textasciicircum= b}.
+\versionadded{2.5}
+\end{funcdesc}
+
+
+The \module{operator} module also defines a few predicates to test the
+type of objects.  \note{Be careful not to misinterpret the
+results of these functions; only \function{isCallable()} has any
+measure of reliability with instance objects.  For example:}
+
+\begin{verbatim}
+>>> class C:
+...     pass
+... 
+>>> import operator
+>>> o = C()
+>>> operator.isMappingType(o)
+True
+\end{verbatim}
+
+\begin{funcdesc}{isCallable}{o}
+\deprecated{2.0}{Use the \function{callable()} built-in function instead.}
+Returns true if the object \var{o} can be called like a function,
+otherwise it returns false.  True is returned for functions, bound and
+unbound methods, class objects, and instance objects which support the
+\method{__call__()} method.
+\end{funcdesc}
+
+\begin{funcdesc}{isMappingType}{o}
+Returns true if the object \var{o} supports the mapping interface.
+This is true for dictionaries and all instance objects defining
+\method{__getitem__}.
+\warning{There is no reliable way to test if an instance
+supports the complete mapping protocol since the interface itself is
+ill-defined.  This makes this test less useful than it otherwise might
+be.}
+\end{funcdesc}
+
+\begin{funcdesc}{isNumberType}{o}
+Returns true if the object \var{o} represents a number.  This is true
+for all numeric types implemented in C.
+\warning{There is no reliable way to test if an instance
+supports the complete numeric interface since the interface itself is
+ill-defined.  This makes this test less useful than it otherwise might
+be.}
+\end{funcdesc}
+
+\begin{funcdesc}{isSequenceType}{o}
+Returns true if the object \var{o} supports the sequence protocol.
+This returns true for all objects which define sequence methods in C,
+and for all instance objects defining \method{__getitem__}.
+\warning{There is no reliable
+way to test if an instance supports the complete sequence interface
+since the interface itself is ill-defined.  This makes this test less
+useful than it otherwise might be.}
+\end{funcdesc}
+
+
+Example: Build a dictionary that maps the ordinals from \code{0} to
+\code{255} to their character equivalents.
+
+\begin{verbatim}
+>>> import operator
+>>> d = {}
+>>> keys = range(256)
+>>> vals = map(chr, keys)
+>>> map(operator.setitem, [d]*len(keys), keys, vals)
+\end{verbatim}
+
+
+The \module{operator} module also defines tools for generalized attribute
+and item lookups.  These are useful for making fast field extractors
+as arguments for \function{map()}, \function{sorted()},
+\method{itertools.groupby()}, or other functions that expect a
+function argument.
+
+\begin{funcdesc}{attrgetter}{attr\optional{, args...}}
+Return a callable object that fetches \var{attr} from its operand.
+If more than one attribute is requested, returns a tuple of attributes.
+After, \samp{f=attrgetter('name')}, the call \samp{f(b)} returns
+\samp{b.name}.  After, \samp{f=attrgetter('name', 'date')}, the call
+\samp{f(b)} returns \samp{(b.name, b.date)}. 
+\versionadded{2.4}
+\versionchanged[Added support for multiple attributes]{2.5}
+\end{funcdesc}
+    
+\begin{funcdesc}{itemgetter}{item\optional{, args...}}
+Return a callable object that fetches \var{item} from its operand.
+If more than one item is requested, returns a tuple of items.
+After, \samp{f=itemgetter(2)}, the call \samp{f(b)} returns
+\samp{b[2]}.
+After, \samp{f=itemgetter(2,5,3)}, the call \samp{f(b)} returns
+\samp{(b[2], b[5], b[3])}.		
+\versionadded{2.4}
+\versionchanged[Added support for multiple item extraction]{2.5}		
+\end{funcdesc}
+
+Examples:
+                
+\begin{verbatim}
+>>> from operator import itemgetter
+>>> inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)]
+>>> getcount = itemgetter(1)
+>>> map(getcount, inventory)
+[3, 2, 5, 1]
+>>> sorted(inventory, key=getcount)
+[('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]
+\end{verbatim}
+                
+
+\subsection{Mapping Operators to Functions \label{operator-map}}
+
+This table shows how abstract operations correspond to operator
+symbols in the Python syntax and the functions in the
+\refmodule{operator} module.
+
+
+\begin{tableiii}{l|c|l}{textrm}{Operation}{Syntax}{Function}
+  \lineiii{Addition}{\code{\var{a} + \var{b}}}
+          {\code{add(\var{a}, \var{b})}}
+  \lineiii{Concatenation}{\code{\var{seq1} + \var{seq2}}}
+          {\code{concat(\var{seq1}, \var{seq2})}}
+  \lineiii{Containment Test}{\code{\var{o} in \var{seq}}}
+          {\code{contains(\var{seq}, \var{o})}}
+  \lineiii{Division}{\code{\var{a} / \var{b}}}
+          {\code{div(\var{a}, \var{b}) \#} without \code{__future__.division}}
+  \lineiii{Division}{\code{\var{a} / \var{b}}}
+          {\code{truediv(\var{a}, \var{b}) \#} with \code{__future__.division}}
+  \lineiii{Division}{\code{\var{a} // \var{b}}}
+          {\code{floordiv(\var{a}, \var{b})}}
+  \lineiii{Bitwise And}{\code{\var{a} \&\ \var{b}}}
+          {\code{and_(\var{a}, \var{b})}}
+  \lineiii{Bitwise Exclusive Or}{\code{\var{a} \^\ \var{b}}}
+          {\code{xor(\var{a}, \var{b})}}
+  \lineiii{Bitwise Inversion}{\code{\~{} \var{a}}}
+          {\code{invert(\var{a})}}
+  \lineiii{Bitwise Or}{\code{\var{a} | \var{b}}}
+          {\code{or_(\var{a}, \var{b})}}
+  \lineiii{Exponentiation}{\code{\var{a} ** \var{b}}}
+          {\code{pow(\var{a}, \var{b})}}
+  \lineiii{Identity}{\code{\var{a} is \var{b}}}
+          {\code{is_(\var{a}, \var{b})}}
+  \lineiii{Identity}{\code{\var{a} is not \var{b}}}
+          {\code{is_not(\var{a}, \var{b})}}
+  \lineiii{Indexed Assignment}{\code{\var{o}[\var{k}] = \var{v}}}
+          {\code{setitem(\var{o}, \var{k}, \var{v})}}
+  \lineiii{Indexed Deletion}{\code{del \var{o}[\var{k}]}}
+          {\code{delitem(\var{o}, \var{k})}}
+  \lineiii{Indexing}{\code{\var{o}[\var{k}]}}
+          {\code{getitem(\var{o}, \var{k})}}
+  \lineiii{Left Shift}{\code{\var{a} <\code{<} \var{b}}}
+          {\code{lshift(\var{a}, \var{b})}}
+  \lineiii{Modulo}{\code{\var{a} \%\ \var{b}}}
+          {\code{mod(\var{a}, \var{b})}}
+  \lineiii{Multiplication}{\code{\var{a} * \var{b}}}
+          {\code{mul(\var{a}, \var{b})}}
+  \lineiii{Negation (Arithmetic)}{\code{- \var{a}}}
+          {\code{neg(\var{a})}}
+  \lineiii{Negation (Logical)}{\code{not \var{a}}}
+          {\code{not_(\var{a})}}
+  \lineiii{Right Shift}{\code{\var{a} >> \var{b}}}
+          {\code{rshift(\var{a}, \var{b})}}
+  \lineiii{Sequence Repitition}{\code{\var{seq} * \var{i}}}
+          {\code{repeat(\var{seq}, \var{i})}}
+  \lineiii{Slice Assignment}{\code{\var{seq}[\var{i}:\var{j}]} = \var{values}}
+          {\code{setslice(\var{seq}, \var{i}, \var{j}, \var{values})}}
+  \lineiii{Slice Deletion}{\code{del \var{seq}[\var{i}:\var{j}]}}
+          {\code{delslice(\var{seq}, \var{i}, \var{j})}}
+  \lineiii{Slicing}{\code{\var{seq}[\var{i}:\var{j}]}}
+          {\code{getslice(\var{seq}, \var{i}, \var{j})}}
+  \lineiii{String Formatting}{\code{\var{s} \%\ \var{o}}}
+          {\code{mod(\var{s}, \var{o})}}
+  \lineiii{Subtraction}{\code{\var{a} - \var{b}}}
+          {\code{sub(\var{a}, \var{b})}}
+  \lineiii{Truth Test}{\code{\var{o}}}
+          {\code{truth(\var{o})}}
+  \lineiii{Ordering}{\code{\var{a} < \var{b}}}
+          {\code{lt(\var{a}, \var{b})}}
+  \lineiii{Ordering}{\code{\var{a} <= \var{b}}}
+          {\code{le(\var{a}, \var{b})}}
+  \lineiii{Equality}{\code{\var{a} == \var{b}}}
+          {\code{eq(\var{a}, \var{b})}}
+  \lineiii{Difference}{\code{\var{a} != \var{b}}}
+          {\code{ne(\var{a}, \var{b})}}
+  \lineiii{Ordering}{\code{\var{a} >= \var{b}}}
+          {\code{ge(\var{a}, \var{b})}}
+  \lineiii{Ordering}{\code{\var{a} > \var{b}}}
+          {\code{gt(\var{a}, \var{b})}}
+\end{tableiii}
diff --git a/sys/src/cmd/python/Doc/lib/liboptparse.tex b/sys/src/cmd/python/Doc/lib/liboptparse.tex
new file mode 100644
index 000000000..df96dd4ae
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/liboptparse.tex
@@ -0,0 +1,1888 @@
+% THIS FILE IS AUTO-GENERATED!  DO NOT EDIT!
+% (Your changes will be lost the next time it is generated.)
+\section{\module{optparse} --- More powerful command line option parser}
+\declaremodule{standard}{optparse}
+\moduleauthor{Greg Ward}{gward@python.net}
+\modulesynopsis{More convenient, flexible, and powerful command-line parsing library.}
+\versionadded{2.3}
+\sectionauthor{Greg Ward}{gward@python.net}
+% An intro blurb used only when generating LaTeX docs for the Python
+% manual (based on README.txt). 
+
+\code{optparse} is a more convenient, flexible, and powerful library for
+parsing command-line options than \code{getopt}.  \code{optparse} uses a more
+declarative style of command-line parsing: you create an instance of
+\class{OptionParser}, populate it with options, and parse the command line.
+\code{optparse} allows users to specify options in the conventional GNU/POSIX
+syntax, and additionally generates usage and help messages for you.
+
+Here's an example of using \code{optparse} in a simple script:
+\begin{verbatim}
+from optparse import OptionParser
+[...]
+parser = OptionParser()
+parser.add_option("-f", "--file", dest="filename",
+                  help="write report to FILE", metavar="FILE")
+parser.add_option("-q", "--quiet",
+                  action="store_false", dest="verbose", default=True,
+                  help="don't print status messages to stdout")
+
+(options, args) = parser.parse_args()
+\end{verbatim}
+
+With these few lines of code, users of your script can now do the
+``usual thing'' on the command-line, for example:
+\begin{verbatim}
+ --file=outfile -q
+\end{verbatim}
+
+As it parses the command line, \code{optparse} sets attributes of the
+\code{options} object returned by \method{parse{\_}args()} based on user-supplied
+command-line values.  When \method{parse{\_}args()} returns from parsing this
+command line, \code{options.filename} will be \code{"outfile"} and
+\code{options.verbose} will be \code{False}.  \code{optparse} supports both long
+and short options, allows short options to be merged together, and
+allows options to be associated with their arguments in a variety of
+ways.  Thus, the following command lines are all equivalent to the above
+example:
+\begin{verbatim}
+ -f outfile --quiet
+ --quiet --file outfile
+ -q -foutfile
+ -qfoutfile
+\end{verbatim}
+
+Additionally, users can run one of
+\begin{verbatim}
+ -h
+ --help
+\end{verbatim}
+
+and \code{optparse} will print out a brief summary of your script's
+options:
+\begin{verbatim}
+usage:  [options]
+
+options:
+  -h, --help            show this help message and exit
+  -f FILE, --file=FILE  write report to FILE
+  -q, --quiet           don't print status messages to stdout
+\end{verbatim}
+
+where the value of \emph{yourscript} is determined at runtime (normally
+from \code{sys.argv{[}0]}).
+% $Id: intro.txt 413 2004-09-28 00:59:13Z greg $ 
+
+
+\subsection{Background\label{optparse-background}}
+
+\module{optparse} was explicitly designed to encourage the creation of programs with
+straightforward, conventional command-line interfaces.  To that end, it
+supports only the most common command-line syntax and semantics
+conventionally used under \UNIX{}.  If you are unfamiliar with these
+conventions, read this section to acquaint yourself with them.
+
+
+\subsubsection{Terminology\label{optparse-terminology}}
+\begin{description}
+\item[argument]
+a string entered on the command-line, and passed by the shell to
+\code{execl()} or \code{execv()}.  In Python, arguments are elements of
+\code{sys.argv{[}1:]} (\code{sys.argv{[}0]} is the name of the program being
+executed).  \UNIX{} shells also use the term ``word''.
+
+It is occasionally desirable to substitute an argument list other
+than \code{sys.argv{[}1:]}, so you should read ``argument'' as ``an element of
+\code{sys.argv{[}1:]}, or of some other list provided as a substitute for
+\code{sys.argv{[}1:]}''.
+\item[option   ]
+an argument used to supply extra information to guide or customize the
+execution of a program.  There are many different syntaxes for
+options; the traditional \UNIX{} syntax is a hyphen (``-'') followed by a
+single letter, e.g. \code{"-x"} or \code{"-F"}.  Also, traditional \UNIX{}
+syntax allows multiple options to be merged into a single argument,
+e.g.  \code{"-x -F"} is equivalent to \code{"-xF"}.  The GNU project
+introduced \code{"-{}-"} followed by a series of hyphen-separated words,
+e.g. \code{"-{}-file"} or \code{"-{}-dry-run"}.  These are the only two option
+syntaxes provided by \module{optparse}.
+
+Some other option syntaxes that the world has seen include:
+\begin{itemize}
+\item {} 
+a hyphen followed by a few letters, e.g. \code{"-pf"} (this is
+\emph{not} the same as multiple options merged into a single argument)
+
+\item {} 
+a hyphen followed by a whole word, e.g. \code{"-file"} (this is
+technically equivalent to the previous syntax, but they aren't
+usually seen in the same program)
+
+\item {} 
+a plus sign followed by a single letter, or a few letters,
+or a word, e.g. \code{"+f"}, \code{"+rgb"}
+
+\item {} 
+a slash followed by a letter, or a few letters, or a word, e.g.
+\code{"/f"}, \code{"/file"}
+
+\end{itemize}
+
+These option syntaxes are not supported by \module{optparse}, and they never will
+be.  This is deliberate: the first three are non-standard on any
+environment, and the last only makes sense if you're exclusively
+targeting VMS, MS-DOS, and/or Windows.
+\item[option argument]
+an argument that follows an option, is closely associated with that
+option, and is consumed from the argument list when that option is.
+With \module{optparse}, option arguments may either be in a separate argument
+from their option:
+\begin{verbatim}
+-f foo
+--file foo
+\end{verbatim}
+
+or included in the same argument:
+\begin{verbatim}
+-ffoo
+--file=foo
+\end{verbatim}
+
+Typically, a given option either takes an argument or it doesn't.
+Lots of people want an ``optional option arguments'' feature, meaning
+that some options will take an argument if they see it, and won't if
+they don't.  This is somewhat controversial, because it makes parsing
+ambiguous: if \code{"-a"} takes an optional argument and \code{"-b"} is
+another option entirely, how do we interpret \code{"-ab"}?  Because of
+this ambiguity, \module{optparse} does not support this feature.
+\item[positional argument]
+something leftover in the argument list after options have been
+parsed, i.e. after options and their arguments have been parsed and
+removed from the argument list.
+\item[required option]
+an option that must be supplied on the command-line; note that the
+phrase ``required option'' is self-contradictory in English.  \module{optparse}
+doesn't prevent you from implementing required options, but doesn't
+give you much help at it either.  See \code{examples/required{\_}1.py} and
+\code{examples/required{\_}2.py} in the \module{optparse} source distribution for two
+ways to implement required options with \module{optparse}.
+\end{description}
+
+For example, consider this hypothetical command-line:
+\begin{verbatim}
+prog -v --report /tmp/report.txt foo bar
+\end{verbatim}
+
+\code{"-v"} and \code{"-{}-report"} are both options.  Assuming that
+\longprogramopt{report} takes one argument, \code{"/tmp/report.txt"} is an option
+argument.  \code{"foo"} and \code{"bar"} are positional arguments.
+
+
+\subsubsection{What are options for?\label{optparse-what-options-for}}
+
+Options are used to provide extra information to tune or customize the
+execution of a program.  In case it wasn't clear, options are usually
+\emph{optional}.  A program should be able to run just fine with no options
+whatsoever.  (Pick a random program from the \UNIX{} or GNU toolsets.  Can
+it run without any options at all and still make sense?  The main
+exceptions are \code{find}, \code{tar}, and \code{dd}{---}all of which are mutant
+oddballs that have been rightly criticized for their non-standard syntax
+and confusing interfaces.)
+
+Lots of people want their programs to have ``required options''.  Think
+about it.  If it's required, then it's \emph{not optional}!  If there is a
+piece of information that your program absolutely requires in order to
+run successfully, that's what positional arguments are for.
+
+As an example of good command-line interface design, consider the humble
+\code{cp} utility, for copying files.  It doesn't make much sense to try to
+copy files without supplying a destination and at least one source.
+Hence, \code{cp} fails if you run it with no arguments.  However, it has a
+flexible, useful syntax that does not require any options at all:
+\begin{verbatim}
+cp SOURCE DEST
+cp SOURCE ... DEST-DIR
+\end{verbatim}
+
+You can get pretty far with just that.  Most \code{cp} implementations
+provide a bunch of options to tweak exactly how the files are copied:
+you can preserve mode and modification time, avoid following symlinks,
+ask before clobbering existing files, etc.  But none of this distracts
+from the core mission of \code{cp}, which is to copy either one file to
+another, or several files to another directory.
+
+
+\subsubsection{What are positional arguments for?\label{optparse-what-positional-arguments-for}}
+
+Positional arguments are for those pieces of information that your
+program absolutely, positively requires to run.
+
+A good user interface should have as few absolute requirements as
+possible.  If your program requires 17 distinct pieces of information in
+order to run successfully, it doesn't much matter \emph{how} you get that
+information from the user{---}most people will give up and walk away
+before they successfully run the program.  This applies whether the user
+interface is a command-line, a configuration file, or a GUI: if you make
+that many demands on your users, most of them will simply give up.
+
+In short, try to minimize the amount of information that users are
+absolutely required to supply{---}use sensible defaults whenever
+possible.  Of course, you also want to make your programs reasonably
+flexible.  That's what options are for.  Again, it doesn't matter if
+they are entries in a config file, widgets in the ``Preferences'' dialog
+of a GUI, or command-line options{---}the more options you implement, the
+more flexible your program is, and the more complicated its
+implementation becomes.  Too much flexibility has drawbacks as well, of
+course; too many options can overwhelm users and make your code much
+harder to maintain.
+% $Id: tao.txt 413 2004-09-28 00:59:13Z greg $ 
+
+
+\subsection{Tutorial\label{optparse-tutorial}}
+
+While \module{optparse} is quite flexible and powerful, it's also straightforward to
+use in most cases.  This section covers the code patterns that are
+common to any \module{optparse}-based program.
+
+First, you need to import the OptionParser class; then, early in the
+main program, create an OptionParser instance:
+\begin{verbatim}
+from optparse import OptionParser
+[...]
+parser = OptionParser()
+\end{verbatim}
+
+Then you can start defining options.  The basic syntax is:
+\begin{verbatim}
+parser.add_option(opt_str, ...,
+                  attr=value, ...)
+\end{verbatim}
+
+Each option has one or more option strings, such as \code{"-f"} or
+\code{"-{}-file"}, and several option attributes that tell \module{optparse} what to
+expect and what to do when it encounters that option on the command
+line.
+
+Typically, each option will have one short option string and one long
+option string, e.g.:
+\begin{verbatim}
+parser.add_option("-f", "--file", ...)
+\end{verbatim}
+
+You're free to define as many short option strings and as many long
+option strings as you like (including zero), as long as there is at
+least one option string overall.
+
+The option strings passed to \method{add{\_}option()} are effectively labels for
+the option defined by that call.  For brevity, we will frequently refer
+to \emph{encountering an option} on the command line; in reality, \module{optparse}
+encounters \emph{option strings} and looks up options from them.
+
+Once all of your options are defined, instruct \module{optparse} to parse your
+program's command line:
+\begin{verbatim}
+(options, args) = parser.parse_args()
+\end{verbatim}
+
+(If you like, you can pass a custom argument list to \method{parse{\_}args()},
+but that's rarely necessary: by default it uses \code{sys.argv{[}1:]}.)
+
+\method{parse{\_}args()} returns two values:
+\begin{itemize}
+\item {} 
+\code{options}, an object containing values for all of your options{---}e.g. if \code{"-{}-file"} takes a single string argument, then
+\code{options.file} will be the filename supplied by the user, or
+\code{None} if the user did not supply that option
+
+\item {} 
+\code{args}, the list of positional arguments leftover after parsing
+options
+
+\end{itemize}
+
+This tutorial section only covers the four most important option
+attributes: \member{action}, \member{type}, \member{dest} (destination), and \member{help}.
+Of these, \member{action} is the most fundamental.
+
+
+\subsubsection{Understanding option actions\label{optparse-understanding-option-actions}}
+
+Actions tell \module{optparse} what to do when it encounters an option on the
+command line.  There is a fixed set of actions hard-coded into \module{optparse};
+adding new actions is an advanced topic covered in section~\ref{optparse-extending-optparse}, Extending \module{optparse}.
+Most actions tell \module{optparse} to store a value in some variable{---}for
+example, take a string from the command line and store it in an
+attribute of \code{options}.
+
+If you don't specify an option action, \module{optparse} defaults to \code{store}.
+
+
+\subsubsection{The store action\label{optparse-store-action}}
+
+The most common option action is \code{store}, which tells \module{optparse} to take
+the next argument (or the remainder of the current argument), ensure
+that it is of the correct type, and store it to your chosen destination.
+
+For example:
+\begin{verbatim}
+parser.add_option("-f", "--file",
+                  action="store", type="string", dest="filename")
+\end{verbatim}
+
+Now let's make up a fake command line and ask \module{optparse} to parse it:
+\begin{verbatim}
+args = ["-f", "foo.txt"]
+(options, args) = parser.parse_args(args)
+\end{verbatim}
+
+When \module{optparse} sees the option string \code{"-f"}, it consumes the next
+argument, \code{"foo.txt"}, and stores it in \code{options.filename}.  So,
+after this call to \method{parse{\_}args()}, \code{options.filename} is
+\code{"foo.txt"}.
+
+Some other option types supported by \module{optparse} are \code{int} and \code{float}.
+Here's an option that expects an integer argument:
+\begin{verbatim}
+parser.add_option("-n", type="int", dest="num")
+\end{verbatim}
+
+Note that this option has no long option string, which is perfectly
+acceptable.  Also, there's no explicit action, since the default is
+\code{store}.
+
+Let's parse another fake command-line.  This time, we'll jam the option
+argument right up against the option: since \code{"-n42"} (one argument) is
+equivalent to \code{"-n 42"} (two arguments), the code
+\begin{verbatim}
+(options, args) = parser.parse_args(["-n42"])
+print options.num
+\end{verbatim}
+
+will print \code{"42"}.
+
+If you don't specify a type, \module{optparse} assumes \code{string}.  Combined with the
+fact that the default action is \code{store}, that means our first example
+can be a lot shorter:
+\begin{verbatim}
+parser.add_option("-f", "--file", dest="filename")
+\end{verbatim}
+
+If you don't supply a destination, \module{optparse} figures out a sensible default
+from the option strings: if the first long option string is
+\code{"-{}-foo-bar"}, then the default destination is \code{foo{\_}bar}.  If there
+are no long option strings, \module{optparse} looks at the first short option
+string: the default destination for \code{"-f"} is \code{f}.
+
+\module{optparse} also includes built-in \code{long} and \code{complex} types.  Adding
+types is covered in section~\ref{optparse-extending-optparse}, Extending \module{optparse}.
+
+
+\subsubsection{Handling boolean (flag) options\label{optparse-handling-boolean-options}}
+
+Flag options{---}set a variable to true or false when a particular option
+is seen{---}are quite common.  \module{optparse} supports them with two separate
+actions, \code{store{\_}true} and \code{store{\_}false}.  For example, you might have a
+\code{verbose} flag that is turned on with \code{"-v"} and off with \code{"-q"}:
+\begin{verbatim}
+parser.add_option("-v", action="store_true", dest="verbose")
+parser.add_option("-q", action="store_false", dest="verbose")
+\end{verbatim}
+
+Here we have two different options with the same destination, which is
+perfectly OK.  (It just means you have to be a bit careful when setting
+default values{---}see below.)
+
+When \module{optparse} encounters \code{"-v"} on the command line, it sets
+\code{options.verbose} to \code{True}; when it encounters \code{"-q"},
+\code{options.verbose} is set to \code{False}.
+
+
+\subsubsection{Other actions\label{optparse-other-actions}}
+
+Some other actions supported by \module{optparse} are:
+\begin{description}
+\item[\code{store{\_}const}]
+store a constant value
+\item[\code{append}]
+append this option's argument to a list
+\item[\code{count}]
+increment a counter by one
+\item[\code{callback}]
+call a specified function
+\end{description}
+
+These are covered in section~\ref{optparse-reference-guide}, Reference Guide and section~\ref{optparse-option-callbacks}, Option Callbacks.
+
+
+\subsubsection{Default values\label{optparse-default-values}}
+
+All of the above examples involve setting some variable (the
+``destination'') when certain command-line options are seen.  What happens
+if those options are never seen?  Since we didn't supply any defaults,
+they are all set to \code{None}.  This is usually fine, but sometimes you
+want more control.  \module{optparse} lets you supply a default value for each
+destination, which is assigned before the command line is parsed.
+
+First, consider the verbose/quiet example.  If we want \module{optparse} to set
+\code{verbose} to \code{True} unless \code{"-q"} is seen, then we can do this:
+\begin{verbatim}
+parser.add_option("-v", action="store_true", dest="verbose", default=True)
+parser.add_option("-q", action="store_false", dest="verbose")
+\end{verbatim}
+
+Since default values apply to the \emph{destination} rather than to any
+particular option, and these two options happen to have the same
+destination, this is exactly equivalent:
+\begin{verbatim}
+parser.add_option("-v", action="store_true", dest="verbose")
+parser.add_option("-q", action="store_false", dest="verbose", default=True)
+\end{verbatim}
+
+Consider this:
+\begin{verbatim}
+parser.add_option("-v", action="store_true", dest="verbose", default=False)
+parser.add_option("-q", action="store_false", dest="verbose", default=True)
+\end{verbatim}
+
+Again, the default value for \code{verbose} will be \code{True}: the last
+default value supplied for any particular destination is the one that
+counts.
+
+A clearer way to specify default values is the \method{set{\_}defaults()}
+method of OptionParser, which you can call at any time before calling
+\method{parse{\_}args()}:
+\begin{verbatim}
+parser.set_defaults(verbose=True)
+parser.add_option(...)
+(options, args) = parser.parse_args()
+\end{verbatim}
+
+As before, the last value specified for a given option destination is
+the one that counts.  For clarity, try to use one method or the other of
+setting default values, not both.
+
+
+\subsubsection{Generating help\label{optparse-generating-help}}
+
+\module{optparse}'s ability to generate help and usage text automatically is useful
+for creating user-friendly command-line interfaces.  All you have to do
+is supply a \member{help} value for each option, and optionally a short usage
+message for your whole program.  Here's an OptionParser populated with
+user-friendly (documented) options:
+\begin{verbatim}
+usage = "usage: %prog [options] arg1 arg2"
+parser = OptionParser(usage=usage)
+parser.add_option("-v", "--verbose",
+                  action="store_true", dest="verbose", default=True,
+                  help="make lots of noise [default]")
+parser.add_option("-q", "--quiet",
+                  action="store_false", dest="verbose", 
+                  help="be vewwy quiet (I'm hunting wabbits)")
+parser.add_option("-f", "--filename",
+                  metavar="FILE", help="write output to FILE"),
+parser.add_option("-m", "--mode",
+                  default="intermediate",
+                  help="interaction mode: novice, intermediate, "
+                       "or expert [default: %default]")
+\end{verbatim}
+
+If \module{optparse} encounters either \code{"-h"} or \code{"-{}-help"} on the command-line,
+or if you just call \method{parser.print{\_}help()}, it prints the following to
+standard output:
+\begin{verbatim}
+usage:  [options] arg1 arg2
+
+options:
+  -h, --help            show this help message and exit
+  -v, --verbose         make lots of noise [default]
+  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
+  -f FILE, --filename=FILE
+                        write output to FILE
+  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
+                        expert [default: intermediate]
+\end{verbatim}
+
+(If the help output is triggered by a help option, \module{optparse} exits after
+printing the help text.)
+
+There's a lot going on here to help \module{optparse} generate the best possible
+help message:
+\begin{itemize}
+\item {} 
+the script defines its own usage message:
+\begin{verbatim}
+usage = "usage: %prog [options] arg1 arg2"
+\end{verbatim}
+
+\module{optparse} expands \code{"{\%}prog"} in the usage string to the name of the current
+program, i.e. \code{os.path.basename(sys.argv{[}0])}.  The expanded string
+is then printed before the detailed option help.
+
+If you don't supply a usage string, \module{optparse} uses a bland but sensible
+default: ``\code{usage: {\%}prog {[}options]"}, which is fine if your script
+doesn't take any positional arguments.
+
+\item {} 
+every option defines a help string, and doesn't worry about line-
+wrapping{---}\module{optparse} takes care of wrapping lines and making the
+help output look good.
+
+\item {} 
+options that take a value indicate this fact in their
+automatically-generated help message, e.g. for the ``mode'' option:
+\begin{verbatim}
+-m MODE, --mode=MODE
+\end{verbatim}
+
+Here, ``MODE'' is called the meta-variable: it stands for the argument
+that the user is expected to supply to \programopt{-m}/\longprogramopt{mode}.  By default,
+\module{optparse} converts the destination variable name to uppercase and uses
+that for the meta-variable.  Sometimes, that's not what you want{---}for example, the \longprogramopt{filename} option explicitly sets
+\code{metavar="FILE"}, resulting in this automatically-generated option
+description:
+\begin{verbatim}
+-f FILE, --filename=FILE
+\end{verbatim}
+
+This is important for more than just saving space, though: the
+manually written help text uses the meta-variable ``FILE'' to clue the
+user in that there's a connection between the semi-formal syntax ``-f
+FILE'' and the informal semantic description ``write output to FILE''.
+This is a simple but effective way to make your help text a lot
+clearer and more useful for end users.
+
+\item {} 
+options that have a default value can include \code{{\%}default} in
+the help string{---}\module{optparse} will replace it with \function{str()} of the
+option's default value.  If an option has no default value (or the
+default value is \code{None}), \code{{\%}default} expands to \code{none}.
+
+\end{itemize}
+
+
+\subsubsection{Printing a version string\label{optparse-printing-version-string}}
+
+Similar to the brief usage string, \module{optparse} can also print a version string
+for your program.  You have to supply the string as the \code{version}
+argument to OptionParser:
+\begin{verbatim}
+parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.0")
+\end{verbatim}
+
+\code{"{\%}prog"} is expanded just like it is in \code{usage}.  Apart
+from that, \code{version} can contain anything you like.  When you supply
+it, \module{optparse} automatically adds a \code{"-{}-version"} option to your parser.
+If it encounters this option on the command line, it expands your
+\code{version} string (by replacing \code{"{\%}prog"}), prints it to stdout, and
+exits.
+
+For example, if your script is called \code{/usr/bin/foo}:
+\begin{verbatim}
+$ /usr/bin/foo --version
+foo 1.0
+\end{verbatim}
+
+
+\subsubsection{How \module{optparse} handles errors\label{optparse-how-optparse-handles-errors}}
+
+There are two broad classes of errors that \module{optparse} has to worry about:
+programmer errors and user errors.  Programmer errors are usually
+erroneous calls to \code{parser.add{\_}option()}, e.g. invalid option strings,
+unknown option attributes, missing option attributes, etc.  These are
+dealt with in the usual way: raise an exception (either
+\code{optparse.OptionError} or \code{TypeError}) and let the program crash.
+
+Handling user errors is much more important, since they are guaranteed
+to happen no matter how stable your code is.  \module{optparse} can automatically
+detect some user errors, such as bad option arguments (passing \code{"-n
+4x"} where \programopt{-n} takes an integer argument), missing arguments
+(\code{"-n"} at the end of the command line, where \programopt{-n} takes an argument
+of any type).  Also, you can call \code{parser.error()} to signal an
+application-defined error condition:
+\begin{verbatim}
+(options, args) = parser.parse_args()
+[...]
+if options.a and options.b:
+    parser.error("options -a and -b are mutually exclusive")
+\end{verbatim}
+
+In either case, \module{optparse} handles the error the same way: it prints the
+program's usage message and an error message to standard error and
+exits with error status 2.
+
+Consider the first example above, where the user passes \code{"4x"} to an
+option that takes an integer:
+\begin{verbatim}
+$ /usr/bin/foo -n 4x
+usage: foo [options]
+
+foo: error: option -n: invalid integer value: '4x'
+\end{verbatim}
+
+Or, where the user fails to pass a value at all:
+\begin{verbatim}
+$ /usr/bin/foo -n
+usage: foo [options]
+
+foo: error: -n option requires an argument
+\end{verbatim}
+
+\module{optparse}-generated error messages take care always to mention the option
+involved in the error; be sure to do the same when calling
+\code{parser.error()} from your application code.
+
+If \module{optparse}'s default error-handling behaviour does not suite your needs,
+you'll need to subclass OptionParser and override \code{exit()} and/or
+\method{error()}.
+
+
+\subsubsection{Putting it all together\label{optparse-putting-it-all-together}}
+
+Here's what \module{optparse}-based scripts usually look like:
+\begin{verbatim}
+from optparse import OptionParser
+[...]
+def main():
+    usage = "usage: %prog [options] arg"
+    parser = OptionParser(usage)
+    parser.add_option("-f", "--file", dest="filename",
+                      help="read data from FILENAME")
+    parser.add_option("-v", "--verbose",
+                      action="store_true", dest="verbose")
+    parser.add_option("-q", "--quiet",
+                      action="store_false", dest="verbose")
+    [...]
+    (options, args) = parser.parse_args()
+    if len(args) != 1:
+        parser.error("incorrect number of arguments")
+    if options.verbose:
+        print "reading %s..." % options.filename
+    [...]
+
+if __name__ == "__main__":
+    main()
+\end{verbatim}
+% $Id: tutorial.txt 515 2006-06-10 15:37:45Z gward $ 
+
+
+\subsection{Reference Guide\label{optparse-reference-guide}}
+
+
+\subsubsection{Creating the parser\label{optparse-creating-parser}}
+
+The first step in using \module{optparse} is to create an OptionParser instance:
+\begin{verbatim}
+parser = OptionParser(...)
+\end{verbatim}
+
+The OptionParser constructor has no required arguments, but a number of
+optional keyword arguments.  You should always pass them as keyword
+arguments, i.e. do not rely on the order in which the arguments are
+declared.
+\begin{quote}
+\begin{description}
+\item[\code{usage} (default: \code{"{\%}prog {[}options]"})]
+The usage summary to print when your program is run incorrectly or
+with a help option.  When \module{optparse} prints the usage string, it expands
+\code{{\%}prog} to \code{os.path.basename(sys.argv{[}0])} (or to \code{prog} if
+you passed that keyword argument).  To suppress a usage message,
+pass the special value \code{optparse.SUPPRESS{\_}USAGE}.
+\item[\code{option{\_}list} (default: \code{{[}]})]
+A list of Option objects to populate the parser with.  The options
+in \code{option{\_}list} are added after any options in
+\code{standard{\_}option{\_}list} (a class attribute that may be set by
+OptionParser subclasses), but before any version or help options.
+Deprecated; use \method{add{\_}option()} after creating the parser instead.
+\item[\code{option{\_}class} (default: optparse.Option)]
+Class to use when adding options to the parser in \method{add{\_}option()}.
+\item[\code{version} (default: \code{None})]
+A version string to print when the user supplies a version option.
+If you supply a true value for \code{version}, \module{optparse} automatically adds
+a version option with the single option string \code{"-{}-version"}.  The
+substring \code{"{\%}prog"} is expanded the same as for \code{usage}.
+\item[\code{conflict{\_}handler} (default: \code{"error"})]
+Specifies what to do when options with conflicting option strings
+are added to the parser; see section~\ref{optparse-conflicts-between-options}, Conflicts between options.
+\item[\code{description} (default: \code{None})]
+A paragraph of text giving a brief overview of your program.  \module{optparse}
+reformats this paragraph to fit the current terminal width and
+prints it when the user requests help (after \code{usage}, but before
+the list of options).
+\item[\code{formatter} (default: a new IndentedHelpFormatter)]
+An instance of optparse.HelpFormatter that will be used for
+printing help text.  \module{optparse} provides two concrete classes for this
+purpose: IndentedHelpFormatter and TitledHelpFormatter.
+\item[\code{add{\_}help{\_}option} (default: \code{True})]
+If true, \module{optparse} will add a help option (with option strings \code{"-h"}
+and \code{"-{}-help"}) to the parser.
+\item[\code{prog}]
+The string to use when expanding \code{"{\%}prog"} in \code{usage} and
+\code{version} instead of \code{os.path.basename(sys.argv{[}0])}.
+\end{description}
+\end{quote}
+
+
+\subsubsection{Populating the parser\label{optparse-populating-parser}}
+
+There are several ways to populate the parser with options.  The
+preferred way is by using \code{OptionParser.add{\_}option()}, as shown in
+section~\ref{optparse-tutorial}, the tutorial.  \method{add{\_}option()} can be called in one of two
+ways:
+\begin{itemize}
+\item {} 
+pass it an Option instance (as returned by \function{make{\_}option()})
+
+\item {} 
+pass it any combination of positional and keyword arguments that are
+acceptable to \function{make{\_}option()} (i.e., to the Option constructor),
+and it will create the Option instance for you
+
+\end{itemize}
+
+The other alternative is to pass a list of pre-constructed Option
+instances to the OptionParser constructor, as in:
+\begin{verbatim}
+option_list = [
+    make_option("-f", "--filename",
+                action="store", type="string", dest="filename"),
+    make_option("-q", "--quiet",
+                action="store_false", dest="verbose"),
+    ]
+parser = OptionParser(option_list=option_list)
+\end{verbatim}
+
+(\function{make{\_}option()} is a factory function for creating Option instances;
+currently it is an alias for the Option constructor.  A future version
+of \module{optparse} may split Option into several classes, and \function{make{\_}option()}
+will pick the right class to instantiate.  Do not instantiate Option
+directly.)
+
+
+\subsubsection{Defining options\label{optparse-defining-options}}
+
+Each Option instance represents a set of synonymous command-line option
+strings, e.g. \programopt{-f} and \longprogramopt{file}.  You can
+specify any number of short or long option strings, but you must specify
+at least one overall option string.
+
+The canonical way to create an Option instance is with the
+\method{add{\_}option()} method of \class{OptionParser}:
+\begin{verbatim}
+parser.add_option(opt_str[, ...], attr=value, ...)
+\end{verbatim}
+
+To define an option with only a short option string:
+\begin{verbatim}
+parser.add_option("-f", attr=value, ...)
+\end{verbatim}
+
+And to define an option with only a long option string:
+\begin{verbatim}
+parser.add_option("--foo", attr=value, ...)
+\end{verbatim}
+
+The keyword arguments define attributes of the new Option object.  The
+most important option attribute is \member{action}, and it largely determines
+which other attributes are relevant or required.  If you pass irrelevant
+option attributes, or fail to pass required ones, \module{optparse} raises an
+OptionError exception explaining your mistake.
+
+An options's \emph{action} determines what \module{optparse} does when it encounters this
+option on the command-line.  The standard option actions hard-coded into
+\module{optparse} are:
+\begin{description}
+\item[\code{store}]
+store this option's argument (default)
+\item[\code{store{\_}const}]
+store a constant value
+\item[\code{store{\_}true}]
+store a true value
+\item[\code{store{\_}false}]
+store a false value
+\item[\code{append}]
+append this option's argument to a list
+\item[\code{append{\_}const}]
+append a constant value to a list
+\item[\code{count}]
+increment a counter by one
+\item[\code{callback}]
+call a specified function
+\item[\member{help}]
+print a usage message including all options and the
+documentation for them
+\end{description}
+
+(If you don't supply an action, the default is \code{store}.  For this
+action, you may also supply \member{type} and \member{dest} option attributes; see
+below.)
+
+As you can see, most actions involve storing or updating a value
+somewhere.  \module{optparse} always creates a special object for this,
+conventionally called \code{options} (it happens to be an instance of
+\code{optparse.Values}).  Option arguments (and various other values) are
+stored as attributes of this object, according to the \member{dest}
+(destination) option attribute.
+
+For example, when you call
+\begin{verbatim}
+parser.parse_args()
+\end{verbatim}
+
+one of the first things \module{optparse} does is create the \code{options} object:
+\begin{verbatim}
+options = Values()
+\end{verbatim}
+
+If one of the options in this parser is defined with
+\begin{verbatim}
+parser.add_option("-f", "--file", action="store", type="string", dest="filename")
+\end{verbatim}
+
+and the command-line being parsed includes any of the following:
+\begin{verbatim}
+-ffoo
+-f foo
+--file=foo
+--file foo
+\end{verbatim}
+
+then \module{optparse}, on seeing this option, will do the equivalent of
+\begin{verbatim}
+options.filename = "foo"
+\end{verbatim}
+
+The \member{type} and \member{dest} option attributes are almost as important as
+\member{action}, but \member{action} is the only one that makes sense for \emph{all}
+options.
+
+
+\subsubsection{Standard option actions\label{optparse-standard-option-actions}}
+
+The various option actions all have slightly different requirements and
+effects.  Most actions have several relevant option attributes which you
+may specify to guide \module{optparse}'s behaviour; a few have required attributes,
+which you must specify for any option using that action.
+\begin{itemize}
+\item {} 
+\code{store} {[}relevant: \member{type}, \member{dest}, \code{nargs}, \code{choices}]
+
+The option must be followed by an argument, which is
+converted to a value according to \member{type} and stored in
+\member{dest}.  If \code{nargs} {\textgreater} 1, multiple arguments will be consumed
+from the command line; all will be converted according to
+\member{type} and stored to \member{dest} as a tuple.  See the ``Option
+types'' section below.
+
+If \code{choices} is supplied (a list or tuple of strings), the type
+defaults to \code{choice}.
+
+If \member{type} is not supplied, it defaults to \code{string}.
+
+If \member{dest} is not supplied, \module{optparse} derives a destination from the
+first long option string (e.g., \code{"-{}-foo-bar"} implies \code{foo{\_}bar}).
+If there are no long option strings, \module{optparse} derives a destination from
+the first short option string (e.g., \code{"-f"} implies \code{f}).
+
+Example:
+\begin{verbatim}
+parser.add_option("-f")
+parser.add_option("-p", type="float", nargs=3, dest="point")
+\end{verbatim}
+
+As it parses the command line
+\begin{verbatim}
+-f foo.txt -p 1 -3.5 4 -fbar.txt
+\end{verbatim}
+
+\module{optparse} will set
+\begin{verbatim}
+options.f = "foo.txt"
+options.point = (1.0, -3.5, 4.0)
+options.f = "bar.txt"
+\end{verbatim}
+
+\item {} 
+\code{store{\_}const} {[}required: \code{const}; relevant: \member{dest}]
+
+The value \code{const} is stored in \member{dest}.
+
+Example:
+\begin{verbatim}
+parser.add_option("-q", "--quiet",
+                  action="store_const", const=0, dest="verbose")
+parser.add_option("-v", "--verbose",
+                  action="store_const", const=1, dest="verbose")
+parser.add_option("--noisy",
+                  action="store_const", const=2, dest="verbose")
+\end{verbatim}
+
+If \code{"-{}-noisy"} is seen, \module{optparse} will set
+\begin{verbatim}
+options.verbose = 2
+\end{verbatim}
+
+\item {} 
+\code{store{\_}true} {[}relevant: \member{dest}]
+
+A special case of \code{store{\_}const} that stores a true value
+to \member{dest}.
+
+\item {} 
+\code{store{\_}false} {[}relevant: \member{dest}]
+
+Like \code{store{\_}true}, but stores a false value.
+
+Example:
+\begin{verbatim}
+parser.add_option("--clobber", action="store_true", dest="clobber")
+parser.add_option("--no-clobber", action="store_false", dest="clobber")
+\end{verbatim}
+
+\item {} 
+\code{append} {[}relevant: \member{type}, \member{dest}, \code{nargs}, \code{choices}]
+
+The option must be followed by an argument, which is appended to the
+list in \member{dest}.  If no default value for \member{dest} is supplied, an
+empty list is automatically created when \module{optparse} first encounters this
+option on the command-line.  If \code{nargs} {\textgreater} 1, multiple arguments are
+consumed, and a tuple of length \code{nargs} is appended to \member{dest}.
+
+The defaults for \member{type} and \member{dest} are the same as for the
+\code{store} action.
+
+Example:
+\begin{verbatim}
+parser.add_option("-t", "--tracks", action="append", type="int")
+\end{verbatim}
+
+If \code{"-t3"} is seen on the command-line, \module{optparse} does the equivalent of:
+\begin{verbatim}
+options.tracks = []
+options.tracks.append(int("3"))
+\end{verbatim}
+
+If, a little later on, \code{"-{}-tracks=4"} is seen, it does:
+\begin{verbatim}
+options.tracks.append(int("4"))
+\end{verbatim}
+
+\item {} 
+\code{append{\_}const} {[}required: \code{const}; relevant: \member{dest}]
+
+Like \code{store{\_}const}, but the value \code{const} is appended to \member{dest};
+as with \code{append}, \member{dest} defaults to \code{None}, and an an empty list is
+automatically created the first time the option is encountered.
+
+\item {} 
+\code{count} {[}relevant: \member{dest}]
+
+Increment the integer stored at \member{dest}.  If no default value is
+supplied, \member{dest} is set to zero before being incremented the first
+time.
+
+Example:
+\begin{verbatim}
+parser.add_option("-v", action="count", dest="verbosity")
+\end{verbatim}
+
+The first time \code{"-v"} is seen on the command line, \module{optparse} does the
+equivalent of:
+\begin{verbatim}
+options.verbosity = 0
+options.verbosity += 1
+\end{verbatim}
+
+Every subsequent occurrence of \code{"-v"} results in
+\begin{verbatim}
+options.verbosity += 1
+\end{verbatim}
+
+\item {} 
+\code{callback} {[}required: \code{callback};
+relevant: \member{type}, \code{nargs}, \code{callback{\_}args}, \code{callback{\_}kwargs}]
+
+Call the function specified by \code{callback}, which is called as
+\begin{verbatim}
+func(option, opt_str, value, parser, *args, **kwargs)
+\end{verbatim}
+
+See section~\ref{optparse-option-callbacks}, Option Callbacks for more detail.
+
+\item {} 
+\member{help}
+
+Prints a complete help message for all the options in the
+current option parser.  The help message is constructed from
+the \code{usage} string passed to OptionParser's constructor and
+the \member{help} string passed to every option.
+
+If no \member{help} string is supplied for an option, it will still be
+listed in the help message.  To omit an option entirely, use
+the special value \code{optparse.SUPPRESS{\_}HELP}.
+
+\module{optparse} automatically adds a \member{help} option to all OptionParsers, so
+you do not normally need to create one.
+
+Example:
+\begin{verbatim}
+from optparse import OptionParser, SUPPRESS_HELP
+
+parser = OptionParser()
+parser.add_option("-h", "--help", action="help"),
+parser.add_option("-v", action="store_true", dest="verbose",
+                  help="Be moderately verbose")
+parser.add_option("--file", dest="filename",
+                  help="Input file to read data from"),
+parser.add_option("--secret", help=SUPPRESS_HELP)
+\end{verbatim}
+
+If \module{optparse} sees either \code{"-h"} or \code{"-{}-help"} on the command line, it
+will print something like the following help message to stdout
+(assuming \code{sys.argv{[}0]} is \code{"foo.py"}):
+\begin{verbatim}
+usage: foo.py [options]
+
+options:
+  -h, --help        Show this help message and exit
+  -v                Be moderately verbose
+  --file=FILENAME   Input file to read data from
+\end{verbatim}
+
+After printing the help message, \module{optparse} terminates your process
+with \code{sys.exit(0)}.
+
+\item {} 
+\code{version}
+
+Prints the version number supplied to the OptionParser to stdout and
+exits.  The version number is actually formatted and printed by the
+\code{print{\_}version()} method of OptionParser.  Generally only relevant
+if the \code{version} argument is supplied to the OptionParser
+constructor.  As with \member{help} options, you will rarely create
+\code{version} options, since \module{optparse} automatically adds them when needed.
+
+\end{itemize}
+
+
+\subsubsection{Option attributes\label{optparse-option-attributes}}
+
+The following option attributes may be passed as keyword arguments
+to \code{parser.add{\_}option()}.  If you pass an option attribute
+that is not relevant to a particular option, or fail to pass a required
+option attribute, \module{optparse} raises OptionError.
+\begin{itemize}
+\item {} 
+\member{action} (default: \code{"store"})
+
+Determines \module{optparse}'s behaviour when this option is seen on the command
+line; the available options are documented above.
+
+\item {} 
+\member{type} (default: \code{"string"})
+
+The argument type expected by this option (e.g., \code{"string"} or
+\code{"int"}); the available option types are documented below.
+
+\item {} 
+\member{dest} (default: derived from option strings)
+
+If the option's action implies writing or modifying a value somewhere,
+this tells \module{optparse} where to write it: \member{dest} names an attribute of the
+\code{options} object that \module{optparse} builds as it parses the command line.
+
+\item {} 
+\code{default} (deprecated)
+
+The value to use for this option's destination if the option is not
+seen on the command line.  Deprecated; use \code{parser.set{\_}defaults()}
+instead.
+
+\item {} 
+\code{nargs} (default: 1)
+
+How many arguments of type \member{type} should be consumed when this
+option is seen.  If {\textgreater} 1, \module{optparse} will store a tuple of values to
+\member{dest}.
+
+\item {} 
+\code{const}
+
+For actions that store a constant value, the constant value to store.
+
+\item {} 
+\code{choices}
+
+For options of type \code{"choice"}, the list of strings the user
+may choose from.
+
+\item {} 
+\code{callback}
+
+For options with action \code{"callback"}, the callable to call when this
+option is seen.  See section~\ref{optparse-option-callbacks}, Option Callbacks for detail on the arguments
+passed to \code{callable}.
+
+\item {} 
+\code{callback{\_}args}, \code{callback{\_}kwargs}
+
+Additional positional and keyword arguments to pass to \code{callback}
+after the four standard callback arguments.
+
+\item {} 
+\member{help}
+
+Help text to print for this option when listing all available options
+after the user supplies a \member{help} option (such as \code{"-{}-help"}).
+If no help text is supplied, the option will be listed without help
+text.  To hide this option, use the special value \code{SUPPRESS{\_}HELP}.
+
+\item {} 
+\code{metavar} (default: derived from option strings)
+
+Stand-in for the option argument(s) to use when printing help text.
+See section~\ref{optparse-tutorial}, the tutorial for an example.
+
+\end{itemize}
+
+
+\subsubsection{Standard option types\label{optparse-standard-option-types}}
+
+\module{optparse} has six built-in option types: \code{string}, \code{int}, \code{long},
+\code{choice}, \code{float} and \code{complex}.  If you need to add new option
+types, see section~\ref{optparse-extending-optparse}, Extending \module{optparse}.
+
+Arguments to string options are not checked or converted in any way: the
+text on the command line is stored in the destination (or passed to the
+callback) as-is.
+
+Integer arguments (type \code{int} or \code{long}) are parsed as follows:
+\begin{quote}
+\begin{itemize}
+\item {} 
+if the number starts with \code{0x}, it is parsed as a hexadecimal number
+
+\item {} 
+if the number starts with \code{0}, it is parsed as an octal number
+
+\item {} 
+if the number starts with \code{0b}, is is parsed as a binary number
+
+\item {} 
+otherwise, the number is parsed as a decimal number
+
+\end{itemize}
+\end{quote}
+
+The conversion is done by calling either \code{int()} or \code{long()} with
+the appropriate base (2, 8, 10, or 16).  If this fails, so will \module{optparse},
+although with a more useful error message.
+
+\code{float} and \code{complex} option arguments are converted directly with
+\code{float()} and \code{complex()}, with similar error-handling.
+
+\code{choice} options are a subtype of \code{string} options.  The \code{choices}
+option attribute (a sequence of strings) defines the set of allowed
+option arguments.  \code{optparse.check{\_}choice()} compares
+user-supplied option arguments against this master list and raises
+OptionValueError if an invalid string is given.
+
+
+\subsubsection{Parsing arguments\label{optparse-parsing-arguments}}
+
+The whole point of creating and populating an OptionParser is to call
+its \method{parse{\_}args()} method:
+\begin{verbatim}
+(options, args) = parser.parse_args(args=None, options=None)
+\end{verbatim}
+
+where the input parameters are
+\begin{description}
+\item[\code{args}]
+the list of arguments to process (default: \code{sys.argv{[}1:]})
+\item[\code{options}]
+object to store option arguments in (default: a new instance of
+optparse.Values)
+\end{description}
+
+and the return values are
+\begin{description}
+\item[\code{options}]
+the same object that was passed in as \code{options}, or the
+optparse.Values instance created by \module{optparse}
+\item[\code{args}]
+the leftover positional arguments after all options have been
+processed
+\end{description}
+
+The most common usage is to supply neither keyword argument.  If you
+supply \code{options}, it will be modified with repeated \code{setattr()}
+calls (roughly one for every option argument stored to an option
+destination) and returned by \method{parse{\_}args()}.
+
+If \method{parse{\_}args()} encounters any errors in the argument list, it calls
+the OptionParser's \method{error()} method with an appropriate end-user error
+message.  This ultimately terminates your process with an exit status of
+2 (the traditional \UNIX{} exit status for command-line errors).
+
+
+\subsubsection{Querying and manipulating your option parser\label{optparse-querying-manipulating-option-parser}}
+
+Sometimes, it's useful to poke around your option parser and see what's
+there.  OptionParser provides a couple of methods to help you out:
+\begin{description}
+\item[\code{has{\_}option(opt{\_}str)}]
+Return true if the OptionParser has an option with 
+option string \code{opt{\_}str} (e.g., \code{"-q"} or \code{"-{}-verbose"}).
+\item[\code{get{\_}option(opt{\_}str)}]
+Returns the Option instance with the option string \code{opt{\_}str}, or
+\code{None} if no options have that option string.
+\item[\code{remove{\_}option(opt{\_}str)}]
+If the OptionParser has an option corresponding to \code{opt{\_}str},
+that option is removed.  If that option provided any other
+option strings, all of those option strings become invalid.
+If \code{opt{\_}str} does not occur in any option belonging to this
+OptionParser, raises ValueError.
+\end{description}
+
+
+\subsubsection{Conflicts between options\label{optparse-conflicts-between-options}}
+
+If you're not careful, it's easy to define options with conflicting
+option strings:
+\begin{verbatim}
+parser.add_option("-n", "--dry-run", ...)
+[...]
+parser.add_option("-n", "--noisy", ...)
+\end{verbatim}
+
+(This is particularly true if you've defined your own OptionParser
+subclass with some standard options.)
+
+Every time you add an option, \module{optparse} checks for conflicts with existing
+options.  If it finds any, it invokes the current conflict-handling
+mechanism.  You can set the conflict-handling mechanism either in the
+constructor:
+\begin{verbatim}
+parser = OptionParser(..., conflict_handler=handler)
+\end{verbatim}
+
+or with a separate call:
+\begin{verbatim}
+parser.set_conflict_handler(handler)
+\end{verbatim}
+
+The available conflict handlers are:
+\begin{quote}
+\begin{description}
+\item[\code{error} (default)]
+assume option conflicts are a programming error and raise 
+OptionConflictError
+\item[\code{resolve}]
+resolve option conflicts intelligently (see below)
+\end{description}
+\end{quote}
+
+As an example, let's define an OptionParser that resolves conflicts
+intelligently and add conflicting options to it:
+\begin{verbatim}
+parser = OptionParser(conflict_handler="resolve")
+parser.add_option("-n", "--dry-run", ..., help="do no harm")
+parser.add_option("-n", "--noisy", ..., help="be noisy")
+\end{verbatim}
+
+At this point, \module{optparse} detects that a previously-added option is already
+using the \code{"-n"} option string.  Since \code{conflict{\_}handler} is
+\code{"resolve"}, it resolves the situation by removing \code{"-n"} from the
+earlier option's list of option strings.  Now \code{"-{}-dry-run"} is the
+only way for the user to activate that option.  If the user asks for
+help, the help message will reflect that:
+\begin{verbatim}
+options:
+  --dry-run     do no harm
+  [...]
+  -n, --noisy   be noisy
+\end{verbatim}
+
+It's possible to whittle away the option strings for a previously-added
+option until there are none left, and the user has no way of invoking
+that option from the command-line.  In that case, \module{optparse} removes that
+option completely, so it doesn't show up in help text or anywhere else.
+Carrying on with our existing OptionParser:
+\begin{verbatim}
+parser.add_option("--dry-run", ..., help="new dry-run option")
+\end{verbatim}
+
+At this point, the original \programopt{-n/-{}-dry-run} option is no longer
+accessible, so \module{optparse} removes it, leaving this help text:
+\begin{verbatim}
+options:
+  [...]
+  -n, --noisy   be noisy
+  --dry-run     new dry-run option
+\end{verbatim}
+
+
+\subsubsection{Cleanup\label{optparse-cleanup}}
+
+OptionParser instances have several cyclic references.  This should not
+be a problem for Python's garbage collector, but you may wish to break
+the cyclic references explicitly by calling \code{destroy()} on your
+OptionParser once you are done with it.  This is particularly useful in
+long-running applications where large object graphs are reachable from
+your OptionParser.
+
+
+\subsubsection{Other methods\label{optparse-other-methods}}
+
+OptionParser supports several other public methods:
+\begin{itemize}
+\item {} 
+\code{set{\_}usage(usage)}
+
+Set the usage string according to the rules described above for the
+\code{usage} constructor keyword argument.  Passing \code{None} sets the
+default usage string; use \code{SUPPRESS{\_}USAGE} to suppress a usage
+message.
+
+\item {} 
+\code{enable{\_}interspersed{\_}args()}, \code{disable{\_}interspersed{\_}args()}
+
+Enable/disable positional arguments interspersed with options, similar
+to GNU getopt (enabled by default).  For example, if \code{"-a"} and
+\code{"-b"} are both simple options that take no arguments, \module{optparse}
+normally accepts this syntax:
+\begin{verbatim}
+prog -a arg1 -b arg2
+\end{verbatim}
+
+and treats it as equivalent to
+\begin{verbatim}
+prog -a -b arg1 arg2
+\end{verbatim}
+
+To disable this feature, call \code{disable{\_}interspersed{\_}args()}.  This
+restores traditional \UNIX{} syntax, where option parsing stops with the
+first non-option argument.
+
+\item {} 
+\code{set{\_}defaults(dest=value, ...)}
+
+Set default values for several option destinations at once.  Using
+\method{set{\_}defaults()} is the preferred way to set default values for
+options, since multiple options can share the same destination.  For
+example, if several ``mode'' options all set the same destination, any
+one of them can set the default, and the last one wins:
+\begin{verbatim}
+parser.add_option("--advanced", action="store_const",
+                  dest="mode", const="advanced",
+                  default="novice")    # overridden below
+parser.add_option("--novice", action="store_const",
+                  dest="mode", const="novice",
+                  default="advanced")  # overrides above setting
+\end{verbatim}
+
+To avoid this confusion, use \method{set{\_}defaults()}:
+\begin{verbatim}
+parser.set_defaults(mode="advanced")
+parser.add_option("--advanced", action="store_const",
+                  dest="mode", const="advanced")
+parser.add_option("--novice", action="store_const",
+                  dest="mode", const="novice")
+\end{verbatim}
+
+\end{itemize}
+% $Id: reference.txt 519 2006-06-11 14:39:11Z gward $ 
+
+
+\subsection{Option Callbacks\label{optparse-option-callbacks}}
+
+When \module{optparse}'s built-in actions and types aren't quite enough for your
+needs, you have two choices: extend \module{optparse} or define a callback option.
+Extending \module{optparse} is more general, but overkill for a lot of simple
+cases.  Quite often a simple callback is all you need.
+
+There are two steps to defining a callback option:
+\begin{itemize}
+\item {} 
+define the option itself using the \code{callback} action
+
+\item {} 
+write the callback; this is a function (or method) that
+takes at least four arguments, as described below
+
+\end{itemize}
+
+
+\subsubsection{Defining a callback option\label{optparse-defining-callback-option}}
+
+As always, the easiest way to define a callback option is by using the
+\code{parser.add{\_}option()} method.  Apart from \member{action}, the only option
+attribute you must specify is \code{callback}, the function to call:
+\begin{verbatim}
+parser.add_option("-c", action="callback", callback=my_callback)
+\end{verbatim}
+
+\code{callback} is a function (or other callable object), so you must have
+already defined \code{my{\_}callback()} when you create this callback option.
+In this simple case, \module{optparse} doesn't even know if \programopt{-c} takes any
+arguments, which usually means that the option takes no arguments{---}the
+mere presence of \programopt{-c} on the command-line is all it needs to know.  In
+some circumstances, though, you might want your callback to consume an
+arbitrary number of command-line arguments.  This is where writing
+callbacks gets tricky; it's covered later in this section.
+
+\module{optparse} always passes four particular arguments to your callback, and it
+will only pass additional arguments if you specify them via
+\code{callback{\_}args} and \code{callback{\_}kwargs}.  Thus, the minimal callback
+function signature is:
+\begin{verbatim}
+def my_callback(option, opt, value, parser):
+\end{verbatim}
+
+The four arguments to a callback are described below.
+
+There are several other option attributes that you can supply when you
+define a callback option:
+\begin{description}
+\item[\member{type}]
+has its usual meaning: as with the \code{store} or \code{append} actions,
+it instructs \module{optparse} to consume one argument and convert it to
+\member{type}.  Rather than storing the converted value(s) anywhere,
+though, \module{optparse} passes it to your callback function.
+\item[\code{nargs}]
+also has its usual meaning: if it is supplied and {\textgreater} 1, \module{optparse} will
+consume \code{nargs} arguments, each of which must be convertible to
+\member{type}.  It then passes a tuple of converted values to your
+callback.
+\item[\code{callback{\_}args}]
+a tuple of extra positional arguments to pass to the callback
+\item[\code{callback{\_}kwargs}]
+a dictionary of extra keyword arguments to pass to the callback
+\end{description}
+
+
+\subsubsection{How callbacks are called\label{optparse-how-callbacks-called}}
+
+All callbacks are called as follows:
+\begin{verbatim}
+func(option, opt_str, value, parser, *args, **kwargs)
+\end{verbatim}
+
+where
+\begin{description}
+\item[\code{option}]
+is the Option instance that's calling the callback
+\item[\code{opt{\_}str}]
+is the option string seen on the command-line that's triggering the
+callback.  (If an abbreviated long option was used, \code{opt{\_}str} will
+be the full, canonical option string{---}e.g. if the user puts
+\code{"-{}-foo"} on the command-line as an abbreviation for
+\code{"-{}-foobar"}, then \code{opt{\_}str} will be \code{"-{}-foobar"}.)
+\item[\code{value}]
+is the argument to this option seen on the command-line.  \module{optparse} will
+only expect an argument if \member{type} is set; the type of \code{value}
+will be the type implied by the option's type.  If \member{type} for this
+option is \code{None} (no argument expected), then \code{value} will be
+\code{None}.  If \code{nargs} {\textgreater} 1, \code{value} will be a tuple of values of
+the appropriate type.
+\item[\code{parser}]
+is the OptionParser instance driving the whole thing, mainly
+useful because you can access some other interesting data through
+its instance attributes:
+\begin{description}
+\item[\code{parser.largs}]
+the current list of leftover arguments, ie. arguments that have
+been consumed but are neither options nor option arguments.
+Feel free to modify \code{parser.largs}, e.g. by adding more
+arguments to it.  (This list will become \code{args}, the second
+return value of \method{parse{\_}args()}.)
+\item[\code{parser.rargs}]
+the current list of remaining arguments, ie. with \code{opt{\_}str} and
+\code{value} (if applicable) removed, and only the arguments
+following them still there.  Feel free to modify
+\code{parser.rargs}, e.g. by consuming more arguments.
+\item[\code{parser.values}]
+the object where option values are by default stored (an
+instance of optparse.OptionValues).  This lets callbacks use the
+same mechanism as the rest of \module{optparse} for storing option values;
+you don't need to mess around with globals or closures.  You can
+also access or modify the value(s) of any options already
+encountered on the command-line.
+\end{description}
+\item[\code{args}]
+is a tuple of arbitrary positional arguments supplied via the
+\code{callback{\_}args} option attribute.
+\item[\code{kwargs}]
+is a dictionary of arbitrary keyword arguments supplied via
+\code{callback{\_}kwargs}.
+\end{description}
+
+
+\subsubsection{Raising errors in a callback\label{optparse-raising-errors-in-callback}}
+
+The callback function should raise OptionValueError if there are any
+problems with the option or its argument(s).  \module{optparse} catches this and
+terminates the program, printing the error message you supply to
+stderr.  Your message should be clear, concise, accurate, and mention
+the option at fault.  Otherwise, the user will have a hard time
+figuring out what he did wrong.
+
+
+\subsubsection{Callback example 1: trivial callback\label{optparse-callback-example-1}}
+
+Here's an example of a callback option that takes no arguments, and
+simply records that the option was seen:
+\begin{verbatim}
+def record_foo_seen(option, opt_str, value, parser):
+    parser.saw_foo = True
+
+parser.add_option("--foo", action="callback", callback=record_foo_seen)
+\end{verbatim}
+
+Of course, you could do that with the \code{store{\_}true} action.
+
+
+\subsubsection{Callback example 2: check option order\label{optparse-callback-example-2}}
+
+Here's a slightly more interesting example: record the fact that
+\code{"-a"} is seen, but blow up if it comes after \code{"-b"} in the
+command-line.
+\begin{verbatim}
+def check_order(option, opt_str, value, parser):
+    if parser.values.b:
+        raise OptionValueError("can't use -a after -b")
+    parser.values.a = 1
+[...]
+parser.add_option("-a", action="callback", callback=check_order)
+parser.add_option("-b", action="store_true", dest="b")
+\end{verbatim}
+
+
+\subsubsection{Callback example 3: check option order (generalized)\label{optparse-callback-example-3}}
+
+If you want to re-use this callback for several similar options (set a
+flag, but blow up if \code{"-b"} has already been seen), it needs a bit of
+work: the error message and the flag that it sets must be
+generalized.
+\begin{verbatim}
+def check_order(option, opt_str, value, parser):
+    if parser.values.b:
+        raise OptionValueError("can't use %s after -b" % opt_str)
+    setattr(parser.values, option.dest, 1)
+[...]
+parser.add_option("-a", action="callback", callback=check_order, dest='a')
+parser.add_option("-b", action="store_true", dest="b")
+parser.add_option("-c", action="callback", callback=check_order, dest='c')
+\end{verbatim}
+
+
+\subsubsection{Callback example 4: check arbitrary condition\label{optparse-callback-example-4}}
+
+Of course, you could put any condition in there{---}you're not limited
+to checking the values of already-defined options.  For example, if
+you have options that should not be called when the moon is full, all
+you have to do is this:
+\begin{verbatim}
+def check_moon(option, opt_str, value, parser):
+    if is_moon_full():
+        raise OptionValueError("%s option invalid when moon is full"
+                               % opt_str)
+    setattr(parser.values, option.dest, 1)
+[...]
+parser.add_option("--foo",
+                  action="callback", callback=check_moon, dest="foo")
+\end{verbatim}
+
+(The definition of \code{is{\_}moon{\_}full()} is left as an exercise for the
+reader.)
+
+
+\subsubsection{Callback example 5: fixed arguments\label{optparse-callback-example-5}}
+
+Things get slightly more interesting when you define callback options
+that take a fixed number of arguments.  Specifying that a callback
+option takes arguments is similar to defining a \code{store} or \code{append}
+option: if you define \member{type}, then the option takes one argument that
+must be convertible to that type; if you further define \code{nargs}, then
+the option takes \code{nargs} arguments.
+
+Here's an example that just emulates the standard \code{store} action:
+\begin{verbatim}
+def store_value(option, opt_str, value, parser):
+    setattr(parser.values, option.dest, value)
+[...]
+parser.add_option("--foo",
+                  action="callback", callback=store_value,
+                  type="int", nargs=3, dest="foo")
+\end{verbatim}
+
+Note that \module{optparse} takes care of consuming 3 arguments and converting them
+to integers for you; all you have to do is store them.  (Or whatever;
+obviously you don't need a callback for this example.)
+
+
+\subsubsection{Callback example 6: variable arguments\label{optparse-callback-example-6}}
+
+Things get hairy when you want an option to take a variable number of
+arguments.  For this case, you must write a callback, as \module{optparse} doesn't
+provide any built-in capabilities for it.  And you have to deal with
+certain intricacies of conventional \UNIX{} command-line parsing that \module{optparse}
+normally handles for you.  In particular, callbacks should implement
+the conventional rules for bare \code{"-{}-"} and \code{"-"} arguments:
+\begin{itemize}
+\item {} 
+either \code{"-{}-"} or \code{"-"} can be option arguments
+
+\item {} 
+bare \code{"-{}-"} (if not the argument to some option): halt command-line
+processing and discard the \code{"-{}-"}
+
+\item {} 
+bare \code{"-"} (if not the argument to some option): halt command-line
+processing but keep the \code{"-"} (append it to \code{parser.largs})
+
+\end{itemize}
+
+If you want an option that takes a variable number of arguments, there
+are several subtle, tricky issues to worry about.  The exact
+implementation you choose will be based on which trade-offs you're
+willing to make for your application (which is why \module{optparse} doesn't support
+this sort of thing directly).
+
+Nevertheless, here's a stab at a callback for an option with variable
+arguments:
+\begin{verbatim}
+def vararg_callback(option, opt_str, value, parser):
+    assert value is None
+    done = 0
+    value = []
+    rargs = parser.rargs
+    while rargs:
+        arg = rargs[0]
+
+        # Stop if we hit an arg like "--foo", "-a", "-fx", "--file=f",
+        # etc.  Note that this also stops on "-3" or "-3.0", so if
+        # your option takes numeric values, you will need to handle
+        # this.
+        if ((arg[:2] == "--" and len(arg) > 2) or
+            (arg[:1] == "-" and len(arg) > 1 and arg[1] != "-")):
+            break
+        else:
+            value.append(arg)
+            del rargs[0]
+
+     setattr(parser.values, option.dest, value)
+
+[...]
+parser.add_option("-c", "--callback",
+                  action="callback", callback=varargs)
+\end{verbatim}
+
+The main weakness with this particular implementation is that negative
+numbers in the arguments following \code{"-c"} will be interpreted as
+further options (probably causing an error), rather than as arguments to
+\code{"-c"}.  Fixing this is left as an exercise for the reader.
+% $Id: callbacks.txt 415 2004-09-30 02:26:17Z greg $ 
+
+
+\subsection{Extending \module{optparse}\label{optparse-extending-optparse}}
+
+Since the two major controlling factors in how \module{optparse} interprets
+command-line options are the action and type of each option, the most
+likely direction of extension is to add new actions and new types.
+
+
+\subsubsection{Adding new types\label{optparse-adding-new-types}}
+
+To add new types, you need to define your own subclass of \module{optparse}'s Option
+class.  This class has a couple of attributes that define \module{optparse}'s types:
+\member{TYPES} and \member{TYPE{\_}CHECKER}.
+
+\member{TYPES} is a tuple of type names; in your subclass, simply define a new
+tuple \member{TYPES} that builds on the standard one.
+
+\member{TYPE{\_}CHECKER} is a dictionary mapping type names to type-checking
+functions.  A type-checking function has the following signature:
+\begin{verbatim}
+def check_mytype(option, opt, value)
+\end{verbatim}
+
+where \code{option} is an \class{Option} instance, \code{opt} is an option string
+(e.g., \code{"-f"}), and \code{value} is the string from the command line that
+must be checked and converted to your desired type.  \code{check{\_}mytype()}
+should return an object of the hypothetical type \code{mytype}.  The value
+returned by a type-checking function will wind up in the OptionValues
+instance returned by \method{OptionParser.parse{\_}args()}, or be passed to a
+callback as the \code{value} parameter.
+
+Your type-checking function should raise OptionValueError if it
+encounters any problems.  OptionValueError takes a single string
+argument, which is passed as-is to OptionParser's \method{error()} method,
+which in turn prepends the program name and the string \code{"error:"} and
+prints everything to stderr before terminating the process.
+
+Here's a silly example that demonstrates adding a \code{complex} option
+type to parse Python-style complex numbers on the command line.  (This
+is even sillier than it used to be, because \module{optparse} 1.3 added built-in
+support for complex numbers, but never mind.)
+
+First, the necessary imports:
+\begin{verbatim}
+from copy import copy
+from optparse import Option, OptionValueError
+\end{verbatim}
+
+You need to define your type-checker first, since it's referred to later
+(in the \member{TYPE{\_}CHECKER} class attribute of your Option subclass):
+\begin{verbatim}
+def check_complex(option, opt, value):
+    try:
+        return complex(value)
+    except ValueError:
+        raise OptionValueError(
+            "option %s: invalid complex value: %r" % (opt, value))
+\end{verbatim}
+
+Finally, the Option subclass:
+\begin{verbatim}
+class MyOption (Option):
+    TYPES = Option.TYPES + ("complex",)
+    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
+    TYPE_CHECKER["complex"] = check_complex
+\end{verbatim}
+
+(If we didn't make a \function{copy()} of \member{Option.TYPE{\_}CHECKER}, we would end
+up modifying the \member{TYPE{\_}CHECKER} attribute of \module{optparse}'s Option class.
+This being Python, nothing stops you from doing that except good manners
+and common sense.)
+
+That's it!  Now you can write a script that uses the new option type
+just like any other \module{optparse}-based script, except you have to instruct your
+OptionParser to use MyOption instead of Option:
+\begin{verbatim}
+parser = OptionParser(option_class=MyOption)
+parser.add_option("-c", type="complex")
+\end{verbatim}
+
+Alternately, you can build your own option list and pass it to
+OptionParser; if you don't use \method{add{\_}option()} in the above way, you
+don't need to tell OptionParser which option class to use:
+\begin{verbatim}
+option_list = [MyOption("-c", action="store", type="complex", dest="c")]
+parser = OptionParser(option_list=option_list)
+\end{verbatim}
+
+
+\subsubsection{Adding new actions\label{optparse-adding-new-actions}}
+
+Adding new actions is a bit trickier, because you have to understand
+that \module{optparse} has a couple of classifications for actions:
+\begin{description}
+\item[``store'' actions]
+actions that result in \module{optparse} storing a value to an attribute of the
+current OptionValues instance; these options require a \member{dest}
+attribute to be supplied to the Option constructor
+\item[``typed'' actions]
+actions that take a value from the command line and expect it to be
+of a certain type; or rather, a string that can be converted to a
+certain type.  These options require a \member{type} attribute to the
+Option constructor.
+\end{description}
+
+These are overlapping sets: some default ``store'' actions are \code{store},
+\code{store{\_}const}, \code{append}, and \code{count}, while the default ``typed''
+actions are \code{store}, \code{append}, and \code{callback}.
+
+When you add an action, you need to categorize it by listing it in at
+least one of the following class attributes of Option (all are lists of
+strings):
+\begin{description}
+\item[\member{ACTIONS}]
+all actions must be listed in ACTIONS
+\item[\member{STORE{\_}ACTIONS}]
+``store'' actions are additionally listed here
+\item[\member{TYPED{\_}ACTIONS}]
+``typed'' actions are additionally listed here
+\item[\code{ALWAYS{\_}TYPED{\_}ACTIONS}]
+actions that always take a type (i.e. whose options always take a
+value) are additionally listed here.  The only effect of this is
+that \module{optparse} assigns the default type, \code{string}, to options with no
+explicit type whose action is listed in \code{ALWAYS{\_}TYPED{\_}ACTIONS}.
+\end{description}
+
+In order to actually implement your new action, you must override
+Option's \method{take{\_}action()} method and add a case that recognizes your
+action.
+
+For example, let's add an \code{extend} action.  This is similar to the
+standard \code{append} action, but instead of taking a single value from
+the command-line and appending it to an existing list, \code{extend} will
+take multiple values in a single comma-delimited string, and extend an
+existing list with them.  That is, if \code{"-{}-names"} is an \code{extend}
+option of type \code{string}, the command line
+\begin{verbatim}
+--names=foo,bar --names blah --names ding,dong
+\end{verbatim}
+
+would result in a list
+\begin{verbatim}
+["foo", "bar", "blah", "ding", "dong"]
+\end{verbatim}
+
+Again we define a subclass of Option:
+\begin{verbatim}
+class MyOption (Option):
+
+    ACTIONS = Option.ACTIONS + ("extend",)
+    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
+    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
+    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)
+
+    def take_action(self, action, dest, opt, value, values, parser):
+        if action == "extend":
+            lvalue = value.split(",")
+            values.ensure_value(dest, []).extend(lvalue)
+        else:
+            Option.take_action(
+                self, action, dest, opt, value, values, parser)
+\end{verbatim}
+
+Features of note:
+\begin{itemize}
+\item {} 
+\code{extend} both expects a value on the command-line and stores that
+value somewhere, so it goes in both \member{STORE{\_}ACTIONS} and
+\member{TYPED{\_}ACTIONS}
+
+\item {} 
+to ensure that \module{optparse} assigns the default type of \code{string} to
+\code{extend} actions, we put the \code{extend} action in
+\code{ALWAYS{\_}TYPED{\_}ACTIONS} as well
+
+\item {} 
+\method{MyOption.take{\_}action()} implements just this one new action, and
+passes control back to \method{Option.take{\_}action()} for the standard
+\module{optparse} actions
+
+\item {} 
+\code{values} is an instance of the optparse{\_}parser.Values class,
+which provides the very useful \method{ensure{\_}value()} method.
+\method{ensure{\_}value()} is essentially \function{getattr()} with a safety valve;
+it is called as
+\begin{verbatim}
+values.ensure_value(attr, value)
+\end{verbatim}
+
+If the \code{attr} attribute of \code{values} doesn't exist or is None, then
+ensure{\_}value() first sets it to \code{value}, and then returns 'value.
+This is very handy for actions like \code{extend}, \code{append}, and
+\code{count}, all of which accumulate data in a variable and expect that
+variable to be of a certain type (a list for the first two, an integer
+for the latter).  Using \method{ensure{\_}value()} means that scripts using
+your action don't have to worry about setting a default value for the
+option destinations in question; they can just leave the default as
+None and \method{ensure{\_}value()} will take care of getting it right when
+it's needed.
+
+\end{itemize}
+% $Id: extending.txt 517 2006-06-10 16:18:11Z gward $ 
+
diff --git a/sys/src/cmd/python/Doc/lib/libos.tex b/sys/src/cmd/python/Doc/lib/libos.tex
new file mode 100644
index 000000000..7844028a6
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libos.tex
@@ -0,0 +1,2006 @@
+\section{\module{os} ---
+         Miscellaneous operating system interfaces}
+
+\declaremodule{standard}{os}
+\modulesynopsis{Miscellaneous operating system interfaces.}
+
+
+This module provides a more portable way of using operating system
+dependent functionality than importing a operating system dependent
+built-in module like \refmodule{posix} or \module{nt}.
+
+This module searches for an operating system dependent built-in module like
+\module{mac} or \refmodule{posix} and exports the same functions and data
+as found there.  The design of all Python's built-in operating system dependent
+modules is such that as long as the same functionality is available,
+it uses the same interface; for example, the function
+\code{os.stat(\var{path})} returns stat information about \var{path} in
+the same format (which happens to have originated with the
+\POSIX{} interface).
+
+Extensions peculiar to a particular operating system are also
+available through the \module{os} module, but using them is of course a
+threat to portability!
+
+Note that after the first time \module{os} is imported, there is
+\emph{no} performance penalty in using functions from \module{os}
+instead of directly from the operating system dependent built-in module,
+so there should be \emph{no} reason not to use \module{os}!
+
+
+% Frank Stajano  complained that it
+% wasn't clear that the entries described in the subsections were all
+% available at the module level (most uses of subsections are
+% different); I think this is only a problem for the HTML version,
+% where the relationship may not be as clear.
+%
+\ifhtml
+The \module{os} module contains many functions and data values.
+The items below and in the following sub-sections are all available
+directly from the \module{os} module.
+\fi
+
+
+\begin{excdesc}{error}
+This exception is raised when a function returns a system-related
+error (not for illegal argument types or other incidental errors).
+This is also known as the built-in exception \exception{OSError}.  The
+accompanying value is a pair containing the numeric error code from
+\cdata{errno} and the corresponding string, as would be printed by the
+C function \cfunction{perror()}.  See the module
+\refmodule{errno}\refbimodindex{errno}, which contains names for the
+error codes defined by the underlying operating system.
+
+When exceptions are classes, this exception carries two attributes,
+\member{errno} and \member{strerror}.  The first holds the value of
+the C \cdata{errno} variable, and the latter holds the corresponding
+error message from \cfunction{strerror()}.  For exceptions that
+involve a file system path (such as \function{chdir()} or
+\function{unlink()}), the exception instance will contain a third
+attribute, \member{filename}, which is the file name passed to the
+function.
+\end{excdesc}
+
+\begin{datadesc}{name}
+The name of the operating system dependent module imported.  The
+following names have currently been registered: \code{'posix'},
+\code{'nt'}, \code{'mac'}, \code{'os2'}, \code{'ce'},
+\code{'java'}, \code{'riscos'}.
+\end{datadesc}
+
+\begin{datadesc}{path}
+The corresponding operating system dependent standard module for pathname
+operations, such as \module{posixpath} or \module{macpath}.  Thus,
+given the proper imports, \code{os.path.split(\var{file})} is
+equivalent to but more portable than
+\code{posixpath.split(\var{file})}.  Note that this is also an
+importable module: it may be imported directly as
+\refmodule{os.path}.
+\end{datadesc}
+
+
+
+\subsection{Process Parameters \label{os-procinfo}}
+
+These functions and data items provide information and operate on the
+current process and user.
+
+\begin{datadesc}{environ}
+A mapping object representing the string environment. For example,
+\code{environ['HOME']} is the pathname of your home directory (on some
+platforms), and is equivalent to \code{getenv("HOME")} in C.
+
+This mapping is captured the first time the \module{os} module is
+imported, typically during Python startup as part of processing
+\file{site.py}.  Changes to the environment made after this time are
+not reflected in \code{os.environ}, except for changes made by modifying
+\code{os.environ} directly.
+
+If the platform supports the \function{putenv()} function, this
+mapping may be used to modify the environment as well as query the
+environment.  \function{putenv()} will be called automatically when
+the mapping is modified.
+\note{Calling \function{putenv()} directly does not change
+\code{os.environ}, so it's better to modify \code{os.environ}.}
+\note{On some platforms, including FreeBSD and Mac OS X, setting
+\code{environ} may cause memory leaks.  Refer to the system documentation
+for \cfunction{putenv()}.}
+
+If \function{putenv()} is not provided, a modified copy of this mapping 
+may be passed to the appropriate process-creation functions to cause 
+child processes to use a modified environment.
+
+If the platform supports the \function{unsetenv()} function, you can 
+delete items in this mapping to unset environment variables.
+\function{unsetenv()} will be called automatically when an item is
+deleted from \code{os.environ}.
+
+\end{datadesc}
+
+\begin{funcdescni}{chdir}{path}
+\funclineni{fchdir}{fd}
+\funclineni{getcwd}{}
+These functions are described in ``Files and Directories'' (section
+\ref{os-file-dir}).
+\end{funcdescni}
+
+\begin{funcdesc}{ctermid}{}
+Return the filename corresponding to the controlling terminal of the
+process.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getegid}{}
+Return the effective group id of the current process.  This
+corresponds to the `set id' bit on the file being executed in the
+current process.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{geteuid}{}
+\index{user!effective id}
+Return the current process' effective user id.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getgid}{}
+\index{process!group}
+Return the real group id of the current process.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getgroups}{}
+Return list of supplemental group ids associated with the current
+process.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getlogin}{}
+Return the name of the user logged in on the controlling terminal of
+the process.  For most purposes, it is more useful to use the
+environment variable \envvar{LOGNAME} to find out who the user is,
+or \code{pwd.getpwuid(os.getuid())[0]} to get the login name
+of the currently effective user ID.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getpgid}{pid}
+Return the process group id of the process with process id \var{pid}.
+If \var{pid} is 0, the process group id of the current process is
+returned. Availability: \UNIX.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{getpgrp}{}
+\index{process!group}
+Return the id of the current process group.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getpid}{}
+\index{process!id}
+Return the current process id.
+Availability: \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{getppid}{}
+\index{process!id of parent}
+Return the parent's process id.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getuid}{}
+\index{user!id}
+Return the current process' user id.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getenv}{varname\optional{, value}}
+Return the value of the environment variable \var{varname} if it
+exists, or \var{value} if it doesn't.  \var{value} defaults to
+\code{None}.
+Availability: most flavors of \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{putenv}{varname, value}
+\index{environment variables!setting}
+Set the environment variable named \var{varname} to the string
+\var{value}.  Such changes to the environment affect subprocesses
+started with \function{os.system()}, \function{popen()} or
+\function{fork()} and \function{execv()}.
+Availability: most flavors of \UNIX, Windows.
+
+\note{On some platforms, including FreeBSD and Mac OS X,
+setting \code{environ} may cause memory leaks.
+Refer to the system documentation for putenv.}
+
+When \function{putenv()} is
+supported, assignments to items in \code{os.environ} are automatically
+translated into corresponding calls to \function{putenv()}; however,
+calls to \function{putenv()} don't update \code{os.environ}, so it is
+actually preferable to assign to items of \code{os.environ}.
+\end{funcdesc}
+
+\begin{funcdesc}{setegid}{egid}
+Set the current process's effective group id.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{seteuid}{euid}
+Set the current process's effective user id.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{setgid}{gid}
+Set the current process' group id.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{setgroups}{groups}
+Set the list of supplemental group ids associated with the current
+process to \var{groups}. \var{groups} must be a sequence, and each
+element must be an integer identifying a group. This operation is
+typical available only to the superuser.
+Availability: \UNIX.
+\versionadded{2.2}
+\end{funcdesc}
+
+\begin{funcdesc}{setpgrp}{}
+Calls the system call \cfunction{setpgrp()} or \cfunction{setpgrp(0,
+0)} depending on which version is implemented (if any).  See the
+\UNIX{} manual for the semantics.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{setpgid}{pid, pgrp} Calls the system call
+\cfunction{setpgid()} to set the process group id of the process with
+id \var{pid} to the process group with id \var{pgrp}.  See the \UNIX{}
+manual for the semantics.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{setreuid}{ruid, euid}
+Set the current process's real and effective user ids.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{setregid}{rgid, egid}
+Set the current process's real and effective group ids.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{getsid}{pid}
+Calls the system call \cfunction{getsid()}.  See the \UNIX{} manual
+for the semantics.
+Availability: \UNIX. \versionadded{2.4}
+\end{funcdesc}
+
+\begin{funcdesc}{setsid}{}
+Calls the system call \cfunction{setsid()}.  See the \UNIX{} manual
+for the semantics.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{setuid}{uid}
+\index{user!id, setting}
+Set the current process' user id.
+Availability: \UNIX.
+\end{funcdesc}
+
+% placed in this section since it relates to errno.... a little weak
+\begin{funcdesc}{strerror}{code}
+Return the error message corresponding to the error code in
+\var{code}.
+Availability: \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{umask}{mask}
+Set the current numeric umask and returns the previous umask.
+Availability: \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{uname}{}
+Return a 5-tuple containing information identifying the current
+operating system.  The tuple contains 5 strings:
+\code{(\var{sysname}, \var{nodename}, \var{release}, \var{version},
+\var{machine})}.  Some systems truncate the nodename to 8
+characters or to the leading component; a better way to get the
+hostname is \function{socket.gethostname()}
+\withsubitem{(in module socket)}{\ttindex{gethostname()}}
+or even
+\withsubitem{(in module socket)}{\ttindex{gethostbyaddr()}}
+\code{socket.gethostbyaddr(socket.gethostname())}.
+Availability: recent flavors of \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{unsetenv}{varname}
+\index{environment variables!deleting}
+Unset (delete) the environment variable named \var{varname}. Such
+changes to the environment affect subprocesses started with
+\function{os.system()}, \function{popen()} or \function{fork()} and
+\function{execv()}. Availability: most flavors of \UNIX, Windows.
+
+When \function{unsetenv()} is
+supported, deletion of items in \code{os.environ} is automatically
+translated into a corresponding call to \function{unsetenv()}; however,
+calls to \function{unsetenv()} don't update \code{os.environ}, so it is
+actually preferable to delete items of \code{os.environ}.
+\end{funcdesc}
+
+\subsection{File Object Creation \label{os-newstreams}}
+
+These functions create new file objects.
+
+
+\begin{funcdesc}{fdopen}{fd\optional{, mode\optional{, bufsize}}}
+Return an open file object connected to the file descriptor \var{fd}.
+\index{I/O control!buffering}
+The \var{mode} and \var{bufsize} arguments have the same meaning as
+the corresponding arguments to the built-in \function{open()}
+function.
+Availability: Macintosh, \UNIX, Windows.
+
+\versionchanged[When specified, the \var{mode} argument must now start
+  with one of the letters \character{r}, \character{w}, or \character{a},
+  otherwise a \exception{ValueError} is raised]{2.3}
+\versionchanged[On \UNIX, when the \var{mode} argument starts with
+  \character{a}, the \var{O_APPEND} flag is set on the file descriptor
+  (which the \cfunction{fdopen()} implementation already does on most
+  platforms)]{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{popen}{command\optional{, mode\optional{, bufsize}}}
+Open a pipe to or from \var{command}.  The return value is an open
+file object connected to the pipe, which can be read or written
+depending on whether \var{mode} is \code{'r'} (default) or \code{'w'}.
+The \var{bufsize} argument has the same meaning as the corresponding
+argument to the built-in \function{open()} function.  The exit status of
+the command (encoded in the format specified for \function{wait()}) is
+available as the return value of the \method{close()} method of the file
+object, except that when the exit status is zero (termination without
+errors), \code{None} is returned.
+Availability: Macintosh, \UNIX, Windows.
+
+The \module{subprocess} module provides more powerful facilities for
+spawning new processes and retrieving their results; using that module
+is preferable to using this function.
+
+\versionchanged[This function worked unreliably under Windows in
+  earlier versions of Python.  This was due to the use of the
+  \cfunction{_popen()} function from the libraries provided with
+  Windows.  Newer versions of Python do not use the broken
+  implementation from the Windows libraries]{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{tmpfile}{}
+Return a new file object opened in update mode (\samp{w+b}).  The file
+has no directory entries associated with it and will be automatically
+deleted once there are no file descriptors for the file.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+There are a number of different \function{popen*()} functions that
+provide slightly different ways to create subprocesses.  Note that the
+\module{subprocess} module is easier to use and more powerful;
+consider using that module before writing code using the
+lower-level \function{popen*()} functions.
+
+For each of the \function{popen*()} variants, if \var{bufsize} is
+specified, it specifies the buffer size for the I/O pipes.
+\var{mode}, if provided, should be the string \code{'b'} or
+\code{'t'}; on Windows this is needed to determine whether the file
+objects should be opened in binary or text mode.  The default value
+for \var{mode} is \code{'t'}.
+
+Also, for each of these variants, on \UNIX, \var{cmd} may be a sequence, in
+which case arguments will be passed directly to the program without shell
+intervention (as with \function{os.spawnv()}). If \var{cmd} is a string it will
+be passed to the shell (as with \function{os.system()}).
+
+These methods do not make it possible to retrieve the exit status from
+the child processes.  The only way to control the input and output
+streams and also retrieve the return codes is to use the
+\class{Popen3} and \class{Popen4} classes from the \refmodule{popen2}
+module; these are only available on \UNIX.
+
+For a discussion of possible deadlock conditions related to the use
+of these functions, see ``\ulink{Flow Control
+Issues}{popen2-flow-control.html}''
+(section~\ref{popen2-flow-control}).
+
+\begin{funcdesc}{popen2}{cmd\optional{, mode\optional{, bufsize}}}
+Executes \var{cmd} as a sub-process.  Returns the file objects
+\code{(\var{child_stdin}, \var{child_stdout})}.
+Availability: Macintosh, \UNIX, Windows.
+\versionadded{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{popen3}{cmd\optional{, mode\optional{, bufsize}}}
+Executes \var{cmd} as a sub-process.  Returns the file objects
+\code{(\var{child_stdin}, \var{child_stdout}, \var{child_stderr})}.
+Availability: Macintosh, \UNIX, Windows.
+\versionadded{2.0}
+\end{funcdesc}
+
+\begin{funcdesc}{popen4}{cmd\optional{, mode\optional{, bufsize}}}
+Executes \var{cmd} as a sub-process.  Returns the file objects
+\code{(\var{child_stdin}, \var{child_stdout_and_stderr})}.
+Availability: Macintosh, \UNIX, Windows.
+\versionadded{2.0}
+\end{funcdesc}
+
+(Note that \code{\var{child_stdin}, \var{child_stdout}, and
+\var{child_stderr}} are named from the point of view of the child
+process, so \var{child_stdin} is the child's standard input.)
+
+This functionality is also available in the \refmodule{popen2} module
+using functions of the same names, but the return values of those
+functions have a different order.
+
+
+\subsection{File Descriptor Operations \label{os-fd-ops}}
+
+These functions operate on I/O streams referenced using file
+descriptors.  
+
+File descriptors are small integers corresponding to a file that has
+been opened by the current process.  For example, standard input is
+usually file descriptor 0, standard output is 1, and standard error is
+2.  Further files opened by a process will then be assigned 3, 4, 5,
+and so forth.  The name ``file descriptor'' is slightly deceptive; on
+{\UNIX} platforms, sockets and pipes are also referenced by file descriptors.
+
+
+\begin{funcdesc}{close}{fd}
+Close file descriptor \var{fd}.
+Availability: Macintosh, \UNIX, Windows.
+
+\begin{notice}
+This function is intended for low-level I/O and must be applied
+to a file descriptor as returned by \function{open()} or
+\function{pipe()}.  To close a ``file object'' returned by the
+built-in function \function{open()} or by \function{popen()} or
+\function{fdopen()}, use its \method{close()} method.
+\end{notice}
+\end{funcdesc}
+
+\begin{funcdesc}{dup}{fd}
+Return a duplicate of file descriptor \var{fd}.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{dup2}{fd, fd2}
+Duplicate file descriptor \var{fd} to \var{fd2}, closing the latter
+first if necessary.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{fdatasync}{fd}
+Force write of file with filedescriptor \var{fd} to disk.
+Does not force update of metadata.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{fpathconf}{fd, name}
+Return system configuration information relevant to an open file.
+\var{name} specifies the configuration value to retrieve; it may be a
+string which is the name of a defined system value; these names are
+specified in a number of standards (\POSIX.1, \UNIX{} 95, \UNIX{} 98, and
+others).  Some platforms define additional names as well.  The names
+known to the host operating system are given in the
+\code{pathconf_names} dictionary.  For configuration variables not
+included in that mapping, passing an integer for \var{name} is also
+accepted.
+Availability: Macintosh, \UNIX.
+
+If \var{name} is a string and is not known, \exception{ValueError} is
+raised.  If a specific value for \var{name} is not supported by the
+host system, even if it is included in \code{pathconf_names}, an
+\exception{OSError} is raised with \constant{errno.EINVAL} for the
+error number.
+\end{funcdesc}
+
+\begin{funcdesc}{fstat}{fd}
+Return status for file descriptor \var{fd}, like \function{stat()}.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{fstatvfs}{fd}
+Return information about the filesystem containing the file associated
+with file descriptor \var{fd}, like \function{statvfs()}.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{fsync}{fd}
+Force write of file with filedescriptor \var{fd} to disk.  On \UNIX,
+this calls the native \cfunction{fsync()} function; on Windows, the
+MS \cfunction{_commit()} function.
+
+If you're starting with a Python file object \var{f}, first do
+\code{\var{f}.flush()}, and then do \code{os.fsync(\var{f}.fileno())},
+to ensure that all internal buffers associated with \var{f} are written
+to disk.
+Availability: Macintosh, \UNIX, and Windows starting in 2.2.3.
+\end{funcdesc}
+
+\begin{funcdesc}{ftruncate}{fd, length}
+Truncate the file corresponding to file descriptor \var{fd},
+so that it is at most \var{length} bytes in size.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{isatty}{fd}
+Return \code{True} if the file descriptor \var{fd} is open and
+connected to a tty(-like) device, else \code{False}.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{lseek}{fd, pos, how}
+Set the current position of file descriptor \var{fd} to position
+\var{pos}, modified by \var{how}: \code{0} to set the position
+relative to the beginning of the file; \code{1} to set it relative to
+the current position; \code{2} to set it relative to the end of the
+file.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{open}{file, flags\optional{, mode}}
+Open the file \var{file} and set various flags according to
+\var{flags} and possibly its mode according to \var{mode}.
+The default \var{mode} is \code{0777} (octal), and the current umask
+value is first masked out.  Return the file descriptor for the newly
+opened file.
+Availability: Macintosh, \UNIX, Windows.
+
+For a description of the flag and mode values, see the C run-time
+documentation; flag constants (like \constant{O_RDONLY} and
+\constant{O_WRONLY}) are defined in this module too (see below).
+
+\begin{notice}
+This function is intended for low-level I/O.  For normal usage,
+use the built-in function \function{open()}, which returns a ``file
+object'' with \method{read()} and \method{write()} methods (and many
+more).  To wrap a file descriptor in a ``file object'', use
+\function{fdopen()}.
+\end{notice}
+\end{funcdesc}
+
+\begin{funcdesc}{openpty}{}
+Open a new pseudo-terminal pair. Return a pair of file descriptors
+\code{(\var{master}, \var{slave})} for the pty and the tty,
+respectively. For a (slightly) more portable approach, use the
+\refmodule{pty}\refstmodindex{pty} module.
+Availability: Macintosh, Some flavors of \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{pipe}{}
+Create a pipe.  Return a pair of file descriptors \code{(\var{r},
+\var{w})} usable for reading and writing, respectively.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{read}{fd, n}
+Read at most \var{n} bytes from file descriptor \var{fd}.
+Return a string containing the bytes read.  If the end of the file
+referred to by \var{fd} has been reached, an empty string is
+returned.
+Availability: Macintosh, \UNIX, Windows.
+
+\begin{notice}
+This function is intended for low-level I/O and must be applied
+to a file descriptor as returned by \function{open()} or
+\function{pipe()}.  To read a ``file object'' returned by the
+built-in function \function{open()} or by \function{popen()} or
+\function{fdopen()}, or \code{sys.stdin}, use its
+\method{read()} or \method{readline()} methods.
+\end{notice}
+\end{funcdesc}
+
+\begin{funcdesc}{tcgetpgrp}{fd}
+Return the process group associated with the terminal given by
+\var{fd} (an open file descriptor as returned by \function{open()}).
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{tcsetpgrp}{fd, pg}
+Set the process group associated with the terminal given by
+\var{fd} (an open file descriptor as returned by \function{open()})
+to \var{pg}.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{ttyname}{fd}
+Return a string which specifies the terminal device associated with
+file-descriptor \var{fd}.  If \var{fd} is not associated with a terminal
+device, an exception is raised.
+Availability:Macintosh,  \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{write}{fd, str}
+Write the string \var{str} to file descriptor \var{fd}.
+Return the number of bytes actually written.
+Availability: Macintosh, \UNIX, Windows.
+
+\begin{notice}
+This function is intended for low-level I/O and must be applied
+to a file descriptor as returned by \function{open()} or
+\function{pipe()}.  To write a ``file object'' returned by the
+built-in function \function{open()} or by \function{popen()} or
+\function{fdopen()}, or \code{sys.stdout} or \code{sys.stderr}, use
+its \method{write()} method.
+\end{notice}
+\end{funcdesc}
+
+
+The following data items are available for use in constructing the
+\var{flags} parameter to the \function{open()} function.  Some items will
+not be available on all platforms.  For descriptions of their availability
+and use, consult \manpage{open}{2}.
+
+\begin{datadesc}{O_RDONLY}
+\dataline{O_WRONLY}
+\dataline{O_RDWR}
+\dataline{O_APPEND}
+\dataline{O_CREAT}
+\dataline{O_EXCL}
+\dataline{O_TRUNC}
+Options for the \var{flag} argument to the \function{open()} function.
+These can be bit-wise OR'd together.
+Availability: Macintosh, \UNIX, Windows.
+\end{datadesc}
+
+\begin{datadesc}{O_DSYNC}
+\dataline{O_RSYNC}
+\dataline{O_SYNC}
+\dataline{O_NDELAY}
+\dataline{O_NONBLOCK}
+\dataline{O_NOCTTY}
+\dataline{O_SHLOCK}
+\dataline{O_EXLOCK}
+More options for the \var{flag} argument to the \function{open()} function.
+Availability: Macintosh, \UNIX.
+\end{datadesc}
+
+\begin{datadesc}{O_BINARY}
+Option for the \var{flag} argument to the \function{open()} function.
+This can be bit-wise OR'd together with those listed above.
+Availability: Windows.
+% XXX need to check on the availability of this one.
+\end{datadesc}
+
+\begin{datadesc}{O_NOINHERIT}
+\dataline{O_SHORT_LIVED}
+\dataline{O_TEMPORARY}
+\dataline{O_RANDOM}
+\dataline{O_SEQUENTIAL}
+\dataline{O_TEXT}
+Options for the \var{flag} argument to the \function{open()} function.
+These can be bit-wise OR'd together.
+Availability: Windows.
+\end{datadesc}
+
+\begin{datadesc}{SEEK_SET}
+\dataline{SEEK_CUR}
+\dataline{SEEK_END}
+Parameters to the \function{lseek()} function.
+Their values are 0, 1, and 2, respectively.
+Availability: Windows, Macintosh, \UNIX.
+\versionadded{2.5}
+\end{datadesc}
+
+\subsection{Files and Directories \label{os-file-dir}}
+
+\begin{funcdesc}{access}{path, mode}
+Use the real uid/gid to test for access to \var{path}.  Note that most
+operations will use the effective uid/gid, therefore this routine can
+be used in a suid/sgid environment to test if the invoking user has the
+specified access to \var{path}.  \var{mode} should be \constant{F_OK}
+to test the existence of \var{path}, or it can be the inclusive OR of
+one or more of \constant{R_OK}, \constant{W_OK}, and \constant{X_OK} to
+test permissions.  Return \constant{True} if access is allowed,
+\constant{False} if not.
+See the \UNIX{} man page \manpage{access}{2} for more information.
+Availability: Macintosh, \UNIX, Windows.
+
+\note{Using \function{access()} to check if a user is authorized to e.g.
+open a file before actually doing so using \function{open()} creates a 
+security hole, because the user might exploit the short time interval 
+between checking and opening the file to manipulate it.}
+
+\note{I/O operations may fail even when \function{access()}
+indicates that they would succeed, particularly for operations
+on network filesystems which may have permissions semantics
+beyond the usual \POSIX{} permission-bit model.}
+\end{funcdesc}
+
+\begin{datadesc}{F_OK}
+  Value to pass as the \var{mode} parameter of \function{access()} to
+  test the existence of \var{path}.
+\end{datadesc}
+
+\begin{datadesc}{R_OK}
+  Value to include in the \var{mode} parameter of \function{access()}
+  to test the readability of \var{path}.
+\end{datadesc}
+
+\begin{datadesc}{W_OK}
+  Value to include in the \var{mode} parameter of \function{access()}
+  to test the writability of \var{path}.
+\end{datadesc}
+
+\begin{datadesc}{X_OK}
+  Value to include in the \var{mode} parameter of \function{access()}
+  to determine if \var{path} can be executed.
+\end{datadesc}
+
+\begin{funcdesc}{chdir}{path}
+\index{directory!changing}
+Change the current working directory to \var{path}.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{fchdir}{fd}
+Change the current working directory to the directory represented by
+the file descriptor \var{fd}.  The descriptor must refer to an opened
+directory, not an open file.
+Availability: \UNIX.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{getcwd}{}
+Return a string representing the current working directory.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{getcwdu}{}
+Return a Unicode object representing the current working directory.
+Availability: Macintosh, \UNIX, Windows.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{chroot}{path}
+Change the root directory of the current process to \var{path}.
+Availability: Macintosh, \UNIX.
+\versionadded{2.2}
+\end{funcdesc}
+
+\begin{funcdesc}{chmod}{path, mode}
+Change the mode of \var{path} to the numeric \var{mode}.
+\var{mode} may take one of the following values
+(as defined in the \module{stat} module) or bitwise or-ed
+combinations of them:
+\begin{itemize}
+  \item \code{S_ISUID}
+  \item \code{S_ISGID}
+  \item \code{S_ENFMT}
+  \item \code{S_ISVTX}
+  \item \code{S_IREAD}
+  \item \code{S_IWRITE}
+  \item \code{S_IEXEC}
+  \item \code{S_IRWXU}
+  \item \code{S_IRUSR}
+  \item \code{S_IWUSR}
+  \item \code{S_IXUSR}
+  \item \code{S_IRWXG}
+  \item \code{S_IRGRP}
+  \item \code{S_IWGRP}
+  \item \code{S_IXGRP}
+  \item \code{S_IRWXO}
+  \item \code{S_IROTH}
+  \item \code{S_IWOTH}
+  \item \code{S_IXOTH}
+\end{itemize}
+Availability: Macintosh, \UNIX, Windows.
+
+\note{Although Windows supports \function{chmod()}, you can only 
+set the file's read-only flag with it (via the \code{S_IWRITE} 
+and \code{S_IREAD} constants or a corresponding integer value). 
+All other bits are ignored.}
+\end{funcdesc}
+
+\begin{funcdesc}{chown}{path, uid, gid}
+Change the owner and group id of \var{path} to the numeric \var{uid}
+and \var{gid}. To leave one of the ids unchanged, set it to -1.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{lchown}{path, uid, gid}
+Change the owner and group id of \var{path} to the numeric \var{uid}
+and gid. This function will not follow symbolic links.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{link}{src, dst}
+Create a hard link pointing to \var{src} named \var{dst}.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{listdir}{path}
+Return a list containing the names of the entries in the directory.
+The list is in arbitrary order.  It does not include the special
+entries \code{'.'} and \code{'..'} even if they are present in the
+directory.
+Availability: Macintosh, \UNIX, Windows.
+
+\versionchanged[On Windows NT/2k/XP and \UNIX, if \var{path} is a Unicode
+object, the result will be a list of Unicode objects]{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{lstat}{path}
+Like \function{stat()}, but do not follow symbolic links.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{mkfifo}{path\optional{, mode}}
+Create a FIFO (a named pipe) named \var{path} with numeric mode
+\var{mode}.  The default \var{mode} is \code{0666} (octal).  The current
+umask value is first masked out from the mode.
+Availability: Macintosh, \UNIX.
+
+FIFOs are pipes that can be accessed like regular files.  FIFOs exist
+until they are deleted (for example with \function{os.unlink()}).
+Generally, FIFOs are used as rendezvous between ``client'' and
+``server'' type processes: the server opens the FIFO for reading, and
+the client opens it for writing.  Note that \function{mkfifo()}
+doesn't open the FIFO --- it just creates the rendezvous point.
+\end{funcdesc}
+
+\begin{funcdesc}{mknod}{filename\optional{, mode=0600, device}}
+Create a filesystem node (file, device special file or named pipe)
+named \var{filename}. \var{mode} specifies both the permissions to use and
+the type of node to be created, being combined (bitwise OR) with one
+of S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO (those constants are
+available in \module{stat}). For S_IFCHR and S_IFBLK, \var{device}
+defines the newly created device special file (probably using
+\function{os.makedev()}), otherwise it is ignored.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{major}{device}
+Extracts the device major number from a raw device number (usually
+the \member{st_dev} or \member{st_rdev} field from \ctype{stat}).
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{minor}{device}
+Extracts the device minor number from a raw device number (usually
+the \member{st_dev} or \member{st_rdev} field from \ctype{stat}).
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{makedev}{major, minor}
+Composes a raw device number from the major and minor device numbers.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{mkdir}{path\optional{, mode}}
+Create a directory named \var{path} with numeric mode \var{mode}.
+The default \var{mode} is \code{0777} (octal).  On some systems,
+\var{mode} is ignored.  Where it is used, the current umask value is
+first masked out.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{makedirs}{path\optional{, mode}}
+Recursive directory creation function.\index{directory!creating}
+\index{UNC paths!and \function{os.makedirs()}}
+Like \function{mkdir()},
+but makes all intermediate-level directories needed to contain the
+leaf directory.  Throws an \exception{error} exception if the leaf
+directory already exists or cannot be created.  The default \var{mode}
+is \code{0777} (octal).  On some systems, \var{mode} is ignored.
+Where it is used, the current umask value is first masked out.
+\note{\function{makedirs()} will become confused if the path elements
+to create include \var{os.pardir}.}
+\versionadded{1.5.2}
+\versionchanged[This function now handles UNC paths correctly]{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{pathconf}{path, name}
+Return system configuration information relevant to a named file.
+\var{name} specifies the configuration value to retrieve; it may be a
+string which is the name of a defined system value; these names are
+specified in a number of standards (\POSIX.1, \UNIX{} 95, \UNIX{} 98, and
+others).  Some platforms define additional names as well.  The names
+known to the host operating system are given in the
+\code{pathconf_names} dictionary.  For configuration variables not
+included in that mapping, passing an integer for \var{name} is also
+accepted.
+Availability: Macintosh, \UNIX.
+
+If \var{name} is a string and is not known, \exception{ValueError} is
+raised.  If a specific value for \var{name} is not supported by the
+host system, even if it is included in \code{pathconf_names}, an
+\exception{OSError} is raised with \constant{errno.EINVAL} for the
+error number.
+\end{funcdesc}
+
+\begin{datadesc}{pathconf_names}
+Dictionary mapping names accepted by \function{pathconf()} and
+\function{fpathconf()} to the integer values defined for those names
+by the host operating system.  This can be used to determine the set
+of names known to the system.
+Availability: Macintosh, \UNIX.
+\end{datadesc}
+
+\begin{funcdesc}{readlink}{path}
+Return a string representing the path to which the symbolic link
+points.  The result may be either an absolute or relative pathname; if
+it is relative, it may be converted to an absolute pathname using
+\code{os.path.join(os.path.dirname(\var{path}), \var{result})}.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{remove}{path}
+Remove the file \var{path}.  If \var{path} is a directory,
+\exception{OSError} is raised; see \function{rmdir()} below to remove
+a directory.  This is identical to the \function{unlink()} function
+documented below.  On Windows, attempting to remove a file that is in
+use causes an exception to be raised; on \UNIX, the directory entry is
+removed but the storage allocated to the file is not made available
+until the original file is no longer in use.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{removedirs}{path}
+\index{directory!deleting}
+Removes directories recursively.  Works like
+\function{rmdir()} except that, if the leaf directory is
+successfully removed, \function{removedirs()} 
+tries to successively remove every parent directory mentioned in 
+\var{path} until an error is raised (which is ignored, because
+it generally means that a parent directory is not empty).
+For example, \samp{os.removedirs('foo/bar/baz')} will first remove
+the directory \samp{'foo/bar/baz'}, and then remove \samp{'foo/bar'}
+and \samp{'foo'} if they are empty.
+Raises \exception{OSError} if the leaf directory could not be 
+successfully removed.
+\versionadded{1.5.2}
+\end{funcdesc}
+
+\begin{funcdesc}{rename}{src, dst}
+Rename the file or directory \var{src} to \var{dst}.  If \var{dst} is
+a directory, \exception{OSError} will be raised.  On \UNIX, if
+\var{dst} exists and is a file, it will be removed silently if the
+user has permission.  The operation may fail on some \UNIX{} flavors
+if \var{src} and \var{dst} are on different filesystems.  If
+successful, the renaming will be an atomic operation (this is a
+\POSIX{} requirement).  On Windows, if \var{dst} already exists,
+\exception{OSError} will be raised even if it is a file; there may be
+no way to implement an atomic rename when \var{dst} names an existing
+file.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{renames}{old, new}
+Recursive directory or file renaming function.
+Works like \function{rename()}, except creation of any intermediate
+directories needed to make the new pathname good is attempted first.
+After the rename, directories corresponding to rightmost path segments
+of the old name will be pruned away using \function{removedirs()}.
+\versionadded{1.5.2}
+
+\begin{notice}
+This function can fail with the new directory structure made if
+you lack permissions needed to remove the leaf directory or file.
+\end{notice}
+\end{funcdesc}
+
+\begin{funcdesc}{rmdir}{path}
+Remove the directory \var{path}.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{stat}{path}
+Perform a \cfunction{stat()} system call on the given path.  The
+return value is an object whose attributes correspond to the members of
+the \ctype{stat} structure, namely:
+\member{st_mode} (protection bits),
+\member{st_ino} (inode number),
+\member{st_dev} (device),
+\member{st_nlink} (number of hard links),
+\member{st_uid} (user ID of owner),
+\member{st_gid} (group ID of owner),
+\member{st_size} (size of file, in bytes),
+\member{st_atime} (time of most recent access),
+\member{st_mtime} (time of most recent content modification),
+\member{st_ctime}
+(platform dependent; time of most recent metadata change on \UNIX, or
+the time of creation on Windows):
+
+\begin{verbatim}
+>>> import os
+>>> statinfo = os.stat('somefile.txt')
+>>> statinfo
+(33188, 422511L, 769L, 1, 1032, 100, 926L, 1105022698,1105022732, 1105022732)
+>>> statinfo.st_size
+926L
+>>>
+\end{verbatim}
+
+\versionchanged [If \function{stat_float_times} returns true, the time
+values are floats, measuring seconds. Fractions of a second may be
+reported if the system supports that. On Mac OS, the times are always
+floats. See \function{stat_float_times} for further discussion]{2.3}
+
+On some \UNIX{} systems (such as Linux), the following attributes may
+also be available:
+\member{st_blocks} (number of blocks allocated for file),
+\member{st_blksize} (filesystem blocksize),
+\member{st_rdev} (type of device if an inode device).
+\member{st_flags} (user defined flags for file).
+
+On other \UNIX{} systems (such as FreeBSD), the following attributes
+may be available (but may be only filled out if root tries to
+use them):
+\member{st_gen} (file generation number),
+\member{st_birthtime} (time of file creation).
+
+On Mac OS systems, the following attributes may also be available:
+\member{st_rsize},
+\member{st_creator},
+\member{st_type}.
+
+On RISCOS systems, the following attributes are also available:
+\member{st_ftype} (file type),
+\member{st_attrs} (attributes),
+\member{st_obtype} (object type).
+
+For backward compatibility, the return value of \function{stat()} is
+also accessible as a tuple of at least 10 integers giving the most
+important (and portable) members of the \ctype{stat} structure, in the
+order
+\member{st_mode},
+\member{st_ino},
+\member{st_dev},
+\member{st_nlink},
+\member{st_uid},
+\member{st_gid},
+\member{st_size},
+\member{st_atime},
+\member{st_mtime},
+\member{st_ctime}.
+More items may be added at the end by some implementations.
+The standard module \refmodule{stat}\refstmodindex{stat} defines
+functions and constants that are useful for extracting information
+from a \ctype{stat} structure.
+(On Windows, some items are filled with dummy values.)
+
+\note{The exact meaning and resolution of the \member{st_atime},
+ \member{st_mtime}, and \member{st_ctime} members depends on the
+ operating system and the file system.  For example, on Windows systems
+ using the FAT or FAT32 file systems, \member{st_mtime} has 2-second
+ resolution, and \member{st_atime} has only 1-day resolution.  See
+ your operating system documentation for details.}
+
+Availability: Macintosh, \UNIX, Windows.
+
+\versionchanged
+[Added access to values as attributes of the returned object]{2.2}
+\versionchanged[Added st_gen, st_birthtime]{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{stat_float_times}{\optional{newvalue}}
+Determine whether \class{stat_result} represents time stamps as float
+objects.  If \var{newvalue} is \code{True}, future calls to \function{stat()}
+return floats, if it is \code{False}, future calls return ints.
+If \var{newvalue} is omitted, return the current setting.
+
+For compatibility with older Python versions, accessing
+\class{stat_result} as a tuple always returns integers.
+
+\versionchanged[Python now returns float values by default. Applications
+which do not work correctly with floating point time stamps can use
+this function to restore the old behaviour]{2.5}
+
+The resolution of the timestamps (that is the smallest possible fraction)
+depends on the system. Some systems only support second resolution;
+on these systems, the fraction will always be zero.
+
+It is recommended that this setting is only changed at program startup
+time in the \var{__main__} module; libraries should never change this
+setting. If an application uses a library that works incorrectly if
+floating point time stamps are processed, this application should turn
+the feature off until the library has been corrected.
+
+\end{funcdesc}
+
+\begin{funcdesc}{statvfs}{path}
+Perform a \cfunction{statvfs()} system call on the given path.  The
+return value is an object whose attributes describe the filesystem on
+the given path, and correspond to the members of the
+\ctype{statvfs} structure, namely:
+\member{f_bsize},
+\member{f_frsize},
+\member{f_blocks},
+\member{f_bfree},
+\member{f_bavail},
+\member{f_files},
+\member{f_ffree},
+\member{f_favail},
+\member{f_flag},
+\member{f_namemax}.
+Availability: \UNIX.
+
+For backward compatibility, the return value is also accessible as a
+tuple whose values correspond to the attributes, in the order given above.
+The standard module \refmodule{statvfs}\refstmodindex{statvfs}
+defines constants that are useful for extracting information
+from a \ctype{statvfs} structure when accessing it as a sequence; this
+remains useful when writing code that needs to work with versions of
+Python that don't support accessing the fields as attributes.
+
+\versionchanged
+[Added access to values as attributes of the returned object]{2.2}
+\end{funcdesc}
+
+\begin{funcdesc}{symlink}{src, dst}
+Create a symbolic link pointing to \var{src} named \var{dst}.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{tempnam}{\optional{dir\optional{, prefix}}}
+Return a unique path name that is reasonable for creating a temporary
+file.  This will be an absolute path that names a potential directory
+entry in the directory \var{dir} or a common location for temporary
+files if \var{dir} is omitted or \code{None}.  If given and not
+\code{None}, \var{prefix} is used to provide a short prefix to the
+filename.  Applications are responsible for properly creating and
+managing files created using paths returned by \function{tempnam()};
+no automatic cleanup is provided.
+On \UNIX, the environment variable \envvar{TMPDIR} overrides
+\var{dir}, while on Windows the \envvar{TMP} is used.  The specific
+behavior of this function depends on the C library implementation;
+some aspects are underspecified in system documentation.
+\warning{Use of \function{tempnam()} is vulnerable to symlink attacks;
+consider using \function{tmpfile()} (section \ref{os-newstreams})
+instead.}  Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{tmpnam}{}
+Return a unique path name that is reasonable for creating a temporary
+file.  This will be an absolute path that names a potential directory
+entry in a common location for temporary files.  Applications are
+responsible for properly creating and managing files created using
+paths returned by \function{tmpnam()}; no automatic cleanup is
+provided.
+\warning{Use of \function{tmpnam()} is vulnerable to symlink attacks;
+consider using \function{tmpfile()} (section \ref{os-newstreams})
+instead.}  Availability: \UNIX, Windows.  This function probably
+shouldn't be used on Windows, though: Microsoft's implementation of
+\function{tmpnam()} always creates a name in the root directory of the
+current drive, and that's generally a poor location for a temp file
+(depending on privileges, you may not even be able to open a file
+using this name).
+\end{funcdesc}
+
+\begin{datadesc}{TMP_MAX}
+The maximum number of unique names that \function{tmpnam()} will
+generate before reusing names.
+\end{datadesc}
+
+\begin{funcdesc}{unlink}{path}
+Remove the file \var{path}.  This is the same function as
+\function{remove()}; the \function{unlink()} name is its traditional
+\UNIX{} name.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{utime}{path, times}
+Set the access and modified times of the file specified by \var{path}.
+If \var{times} is \code{None}, then the file's access and modified
+times are set to the current time.  Otherwise, \var{times} must be a
+2-tuple of numbers, of the form \code{(\var{atime}, \var{mtime})}
+which is used to set the access and modified times, respectively.
+Whether a directory can be given for \var{path} depends on whether the
+operating system implements directories as files (for example, Windows
+does not).  Note that the exact times you set here may not be returned
+by a subsequent \function{stat()} call, depending on the resolution
+with which your operating system records access and modification times;
+see \function{stat()}.
+\versionchanged[Added support for \code{None} for \var{times}]{2.0}
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{walk}{top\optional{, topdown\code{=True}
+                       \optional{, onerror\code{=None}}}}
+\index{directory!walking}
+\index{directory!traversal}
+\function{walk()} generates the file names in a directory tree, by
+walking the tree either top down or bottom up.
+For each directory in the tree rooted at directory \var{top} (including
+\var{top} itself), it yields a 3-tuple
+\code{(\var{dirpath}, \var{dirnames}, \var{filenames})}.
+
+\var{dirpath} is a string, the path to the directory.  \var{dirnames} is
+a list of the names of the subdirectories in \var{dirpath}
+(excluding \code{'.'} and \code{'..'}).  \var{filenames} is a list of
+the names of the non-directory files in \var{dirpath}.  Note that the
+names in the lists contain no path components.  To get a full
+path (which begins with \var{top}) to a file or directory in
+\var{dirpath}, do \code{os.path.join(\var{dirpath}, \var{name})}.
+
+If optional argument \var{topdown} is true or not specified, the triple
+for a directory is generated before the triples for any of its
+subdirectories (directories are generated top down).  If \var{topdown} is
+false, the triple for a directory is generated after the triples for all
+of its subdirectories (directories are generated bottom up).
+
+When \var{topdown} is true, the caller can modify the \var{dirnames} list
+in-place (perhaps using \keyword{del} or slice assignment), and
+\function{walk()} will only recurse into the subdirectories whose names
+remain in \var{dirnames}; this can be used to prune the search,
+impose a specific order of visiting, or even to inform \function{walk()}
+about directories the caller creates or renames before it resumes
+\function{walk()} again.  Modifying \var{dirnames} when \var{topdown} is
+false is ineffective, because in bottom-up mode the directories in
+\var{dirnames} are generated before \var{dirpath} itself is generated.
+
+By default errors from the \code{os.listdir()} call are ignored.  If
+optional argument \var{onerror} is specified, it should be a function;
+it will be called with one argument, an \exception{OSError} instance.  It can
+report the error to continue with the walk, or raise the exception
+to abort the walk.  Note that the filename is available as the
+\code{filename} attribute of the exception object.
+
+\begin{notice}
+If you pass a relative pathname, don't change the current working
+directory between resumptions of \function{walk()}.  \function{walk()}
+never changes the current directory, and assumes that its caller
+doesn't either.
+\end{notice}
+
+\begin{notice}
+On systems that support symbolic links, links to subdirectories appear
+in \var{dirnames} lists, but \function{walk()} will not visit them
+(infinite loops are hard to avoid when following symbolic links).
+To visit linked directories, you can identify them with
+\code{os.path.islink(\var{path})}, and invoke \code{walk(\var{path})}
+on each directly.
+\end{notice}
+
+This example displays the number of bytes taken by non-directory files
+in each directory under the starting directory, except that it doesn't
+look under any CVS subdirectory:
+
+\begin{verbatim}
+import os
+from os.path import join, getsize
+for root, dirs, files in os.walk('python/Lib/email'):
+    print root, "consumes",
+    print sum(getsize(join(root, name)) for name in files),
+    print "bytes in", len(files), "non-directory files"
+    if 'CVS' in dirs:
+        dirs.remove('CVS')  # don't visit CVS directories
+\end{verbatim}
+
+In the next example, walking the tree bottom up is essential:
+\function{rmdir()} doesn't allow deleting a directory before the
+directory is empty:
+
+\begin{verbatim}
+# Delete everything reachable from the directory named in 'top',
+# assuming there are no symbolic links.
+# CAUTION:  This is dangerous!  For example, if top == '/', it
+# could delete all your disk files.
+import os
+for root, dirs, files in os.walk(top, topdown=False):
+    for name in files:
+        os.remove(os.path.join(root, name))
+    for name in dirs:
+        os.rmdir(os.path.join(root, name))
+\end{verbatim}
+
+\versionadded{2.3}
+\end{funcdesc}
+
+\subsection{Process Management \label{os-process}}
+
+These functions may be used to create and manage processes.
+
+The various \function{exec*()} functions take a list of arguments for
+the new program loaded into the process.  In each case, the first of
+these arguments is passed to the new program as its own name rather
+than as an argument a user may have typed on a command line.  For the
+C programmer, this is the \code{argv[0]} passed to a program's
+\cfunction{main()}.  For example, \samp{os.execv('/bin/echo', ['foo',
+'bar'])} will only print \samp{bar} on standard output; \samp{foo}
+will seem to be ignored.
+
+
+\begin{funcdesc}{abort}{}
+Generate a \constant{SIGABRT} signal to the current process.  On
+\UNIX, the default behavior is to produce a core dump; on Windows, the
+process immediately returns an exit code of \code{3}.  Be aware that
+programs which use \function{signal.signal()} to register a handler
+for \constant{SIGABRT} will behave differently.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{execl}{path, arg0, arg1, \moreargs}
+\funcline{execle}{path, arg0, arg1, \moreargs, env}
+\funcline{execlp}{file, arg0, arg1, \moreargs}
+\funcline{execlpe}{file, arg0, arg1, \moreargs, env}
+\funcline{execv}{path, args}
+\funcline{execve}{path, args, env}
+\funcline{execvp}{file, args}
+\funcline{execvpe}{file, args, env}
+These functions all execute a new program, replacing the current
+process; they do not return.  On \UNIX, the new executable is loaded
+into the current process, and will have the same process ID as the
+caller.  Errors will be reported as \exception{OSError} exceptions.
+
+The \character{l} and \character{v} variants of the
+\function{exec*()} functions differ in how command-line arguments are
+passed.  The \character{l} variants are perhaps the easiest to work
+with if the number of parameters is fixed when the code is written;
+the individual parameters simply become additional parameters to the
+\function{execl*()} functions.  The \character{v} variants are good
+when the number of parameters is variable, with the arguments being
+passed in a list or tuple as the \var{args} parameter.  In either
+case, the arguments to the child process should start with the name of
+the command being run, but this is not enforced.
+
+The variants which include a \character{p} near the end
+(\function{execlp()}, \function{execlpe()}, \function{execvp()},
+and \function{execvpe()}) will use the \envvar{PATH} environment
+variable to locate the program \var{file}.  When the environment is
+being replaced (using one of the \function{exec*e()} variants,
+discussed in the next paragraph), the
+new environment is used as the source of the \envvar{PATH} variable.
+The other variants, \function{execl()}, \function{execle()},
+\function{execv()}, and \function{execve()}, will not use the
+\envvar{PATH} variable to locate the executable; \var{path} must
+contain an appropriate absolute or relative path.
+
+For \function{execle()}, \function{execlpe()}, \function{execve()},
+and \function{execvpe()} (note that these all end in \character{e}),
+the \var{env} parameter must be a mapping which is used to define the
+environment variables for the new process; the \function{execl()},
+\function{execlp()}, \function{execv()}, and \function{execvp()}
+all cause the new process to inherit the environment of the current
+process.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{_exit}{n}
+Exit to the system with status \var{n}, without calling cleanup
+handlers, flushing stdio buffers, etc.
+Availability: Macintosh, \UNIX, Windows.
+
+\begin{notice}
+The standard way to exit is \code{sys.exit(\var{n})}.
+\function{_exit()} should normally only be used in the child process
+after a \function{fork()}.
+\end{notice}
+\end{funcdesc}
+
+The following exit codes are a defined, and can be used with
+\function{_exit()}, although they are not required.  These are
+typically used for system programs written in Python, such as a
+mail server's external command delivery program.
+\note{Some of these may not be available on all \UNIX{} platforms,
+since there is some variation.  These constants are defined where they
+are defined by the underlying platform.}
+
+\begin{datadesc}{EX_OK}
+Exit code that means no error occurred.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_USAGE}
+Exit code that means the command was used incorrectly, such as when
+the wrong number of arguments are given.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_DATAERR}
+Exit code that means the input data was incorrect.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_NOINPUT}
+Exit code that means an input file did not exist or was not readable.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_NOUSER}
+Exit code that means a specified user did not exist.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_NOHOST}
+Exit code that means a specified host did not exist.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_UNAVAILABLE}
+Exit code that means that a required service is unavailable.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_SOFTWARE}
+Exit code that means an internal software error was detected.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_OSERR}
+Exit code that means an operating system error was detected, such as
+the inability to fork or create a pipe.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_OSFILE}
+Exit code that means some system file did not exist, could not be
+opened, or had some other kind of error.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_CANTCREAT}
+Exit code that means a user specified output file could not be created.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_IOERR}
+Exit code that means that an error occurred while doing I/O on some file.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_TEMPFAIL}
+Exit code that means a temporary failure occurred.  This indicates
+something that may not really be an error, such as a network
+connection that couldn't be made during a retryable operation.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_PROTOCOL}
+Exit code that means that a protocol exchange was illegal, invalid, or
+not understood.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_NOPERM}
+Exit code that means that there were insufficient permissions to
+perform the operation (but not intended for file system problems).
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_CONFIG}
+Exit code that means that some kind of configuration error occurred.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{EX_NOTFOUND}
+Exit code that means something like ``an entry was not found''.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{funcdesc}{fork}{}
+Fork a child process.  Return \code{0} in the child, the child's
+process id in the parent.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{forkpty}{}
+Fork a child process, using a new pseudo-terminal as the child's
+controlling terminal. Return a pair of \code{(\var{pid}, \var{fd})},
+where \var{pid} is \code{0} in the child, the new child's process id
+in the parent, and \var{fd} is the file descriptor of the master end
+of the pseudo-terminal.  For a more portable approach, use the
+\refmodule{pty} module.
+Availability: Macintosh, Some flavors of \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{kill}{pid, sig}
+\index{process!killing}
+\index{process!signalling}
+Send signal \var{sig} to the process \var{pid}.  Constants for the
+specific signals available on the host platform are defined in the
+\refmodule{signal} module.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{killpg}{pgid, sig}
+\index{process!killing}
+\index{process!signalling}
+Send the signal \var{sig} to the process group \var{pgid}.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{nice}{increment}
+Add \var{increment} to the process's ``niceness''.  Return the new
+niceness.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{plock}{op}
+Lock program segments into memory.  The value of \var{op}
+(defined in \code{}) determines which segments are locked.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdescni}{popen}{\unspecified}
+\funclineni{popen2}{\unspecified}
+\funclineni{popen3}{\unspecified}
+\funclineni{popen4}{\unspecified}
+Run child processes, returning opened pipes for communications.  These
+functions are described in section \ref{os-newstreams}.
+\end{funcdescni}
+
+\begin{funcdesc}{spawnl}{mode, path, \moreargs}
+\funcline{spawnle}{mode, path, \moreargs, env}
+\funcline{spawnlp}{mode, file, \moreargs}
+\funcline{spawnlpe}{mode, file, \moreargs, env}
+\funcline{spawnv}{mode, path, args}
+\funcline{spawnve}{mode, path, args, env}
+\funcline{spawnvp}{mode, file, args}
+\funcline{spawnvpe}{mode, file, args, env}
+Execute the program \var{path} in a new process.  
+
+(Note that the \module{subprocess} module provides more powerful
+facilities for spawning new processes and retrieving their results;
+using that module is preferable to using these functions.)
+
+If \var{mode} is
+\constant{P_NOWAIT}, this function returns the process ID of the new
+process; if \var{mode} is \constant{P_WAIT}, returns the process's
+exit code if it exits normally, or \code{-\var{signal}}, where
+\var{signal} is the signal that killed the process.  On Windows, the
+process ID will actually be the process handle, so can be used with
+the \function{waitpid()} function.
+
+The \character{l} and \character{v} variants of the
+\function{spawn*()} functions differ in how command-line arguments are
+passed.  The \character{l} variants are perhaps the easiest to work
+with if the number of parameters is fixed when the code is written;
+the individual parameters simply become additional parameters to the
+\function{spawnl*()} functions.  The \character{v} variants are good
+when the number of parameters is variable, with the arguments being
+passed in a list or tuple as the \var{args} parameter.  In either
+case, the arguments to the child process must start with the name of
+the command being run.
+
+The variants which include a second \character{p} near the end
+(\function{spawnlp()}, \function{spawnlpe()}, \function{spawnvp()},
+and \function{spawnvpe()}) will use the \envvar{PATH} environment
+variable to locate the program \var{file}.  When the environment is
+being replaced (using one of the \function{spawn*e()} variants,
+discussed in the next paragraph), the new environment is used as the
+source of the \envvar{PATH} variable.  The other variants,
+\function{spawnl()}, \function{spawnle()}, \function{spawnv()}, and
+\function{spawnve()}, will not use the \envvar{PATH} variable to
+locate the executable; \var{path} must contain an appropriate absolute
+or relative path.
+
+For \function{spawnle()}, \function{spawnlpe()}, \function{spawnve()},
+and \function{spawnvpe()} (note that these all end in \character{e}),
+the \var{env} parameter must be a mapping which is used to define the
+environment variables for the new process; the \function{spawnl()},
+\function{spawnlp()}, \function{spawnv()}, and \function{spawnvp()}
+all cause the new process to inherit the environment of the current
+process.
+
+As an example, the following calls to \function{spawnlp()} and
+\function{spawnvpe()} are equivalent:
+
+\begin{verbatim}
+import os
+os.spawnlp(os.P_WAIT, 'cp', 'cp', 'index.html', '/dev/null')
+
+L = ['cp', 'index.html', '/dev/null']
+os.spawnvpe(os.P_WAIT, 'cp', L, os.environ)
+\end{verbatim}
+
+Availability: \UNIX, Windows.  \function{spawnlp()},
+\function{spawnlpe()}, \function{spawnvp()} and \function{spawnvpe()}
+are not available on Windows.
+\versionadded{1.6}
+\end{funcdesc}
+
+\begin{datadesc}{P_NOWAIT}
+\dataline{P_NOWAITO}
+Possible values for the \var{mode} parameter to the \function{spawn*()}
+family of functions.  If either of these values is given, the
+\function{spawn*()} functions will return as soon as the new process
+has been created, with the process ID as the return value.
+Availability: Macintosh, \UNIX, Windows.
+\versionadded{1.6}
+\end{datadesc}
+
+\begin{datadesc}{P_WAIT}
+Possible value for the \var{mode} parameter to the \function{spawn*()}
+family of functions.  If this is given as \var{mode}, the
+\function{spawn*()} functions will not return until the new process
+has run to completion and will return the exit code of the process the
+run is successful, or \code{-\var{signal}} if a signal kills the
+process.
+Availability: Macintosh, \UNIX, Windows.
+\versionadded{1.6}
+\end{datadesc}
+
+\begin{datadesc}{P_DETACH}
+\dataline{P_OVERLAY}
+Possible values for the \var{mode} parameter to the
+\function{spawn*()} family of functions.  These are less portable than
+those listed above.
+\constant{P_DETACH} is similar to \constant{P_NOWAIT}, but the new
+process is detached from the console of the calling process.
+If \constant{P_OVERLAY} is used, the current process will be replaced;
+the \function{spawn*()} function will not return.
+Availability: Windows.
+\versionadded{1.6}
+\end{datadesc}
+
+\begin{funcdesc}{startfile}{path\optional{, operation}}
+Start a file with its associated application.
+
+When \var{operation} is not specified or \code{'open'}, this acts like
+double-clicking the file in Windows Explorer, or giving the file name
+as an argument to the \program{start} command from the interactive
+command shell: the file is opened with whatever application (if any)
+its extension is associated.
+
+When another \var{operation} is given, it must be a ``command verb''
+that specifies what should be done with the file.
+Common verbs documented by Microsoft are \code{'print'} and 
+\code{'edit'} (to be used on files) as well as \code{'explore'} and
+\code{'find'} (to be used on directories).
+
+\function{startfile()} returns as soon as the associated application
+is launched.  There is no option to wait for the application to close,
+and no way to retrieve the application's exit status.  The \var{path}
+parameter is relative to the current directory.  If you want to use an
+absolute path, make sure the first character is not a slash
+(\character{/}); the underlying Win32 \cfunction{ShellExecute()}
+function doesn't work if it is.  Use the \function{os.path.normpath()}
+function to ensure that the path is properly encoded for Win32.
+Availability: Windows.
+\versionadded{2.0}
+\versionadded[The \var{operation} parameter]{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{system}{command}
+Execute the command (a string) in a subshell.  This is implemented by
+calling the Standard C function \cfunction{system()}, and has the
+same limitations.  Changes to \code{posix.environ}, \code{sys.stdin},
+etc.\ are not reflected in the environment of the executed command.
+
+On \UNIX, the return value is the exit status of the process encoded in the
+format specified for \function{wait()}.  Note that \POSIX{} does not
+specify the meaning of the return value of the C \cfunction{system()}
+function, so the return value of the Python function is system-dependent.
+
+On Windows, the return value is that returned by the system shell after
+running \var{command}, given by the Windows environment variable
+\envvar{COMSPEC}: on \program{command.com} systems (Windows 95, 98 and ME)
+this is always \code{0}; on \program{cmd.exe} systems (Windows NT, 2000
+and XP) this is the exit status of the command run; on systems using
+a non-native shell, consult your shell documentation.
+
+Availability: Macintosh, \UNIX, Windows.
+
+The \module{subprocess} module provides more powerful facilities for
+spawning new processes and retrieving their results; using that module
+is preferable to using this function.
+\end{funcdesc}
+
+\begin{funcdesc}{times}{}
+Return a 5-tuple of floating point numbers indicating accumulated
+(processor or other)
+times, in seconds.  The items are: user time, system time, children's
+user time, children's system time, and elapsed real time since a fixed
+point in the past, in that order.  See the \UNIX{} manual page
+\manpage{times}{2} or the corresponding Windows Platform API
+documentation.
+Availability: Macintosh, \UNIX, Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{wait}{}
+Wait for completion of a child process, and return a tuple containing
+its pid and exit status indication: a 16-bit number, whose low byte is
+the signal number that killed the process, and whose high byte is the
+exit status (if the signal number is zero); the high bit of the low
+byte is set if a core file was produced.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{waitpid}{pid, options}
+The details of this function differ on \UNIX{} and Windows.
+
+On \UNIX:
+Wait for completion of a child process given by process id \var{pid},
+and return a tuple containing its process id and exit status
+indication (encoded as for \function{wait()}).  The semantics of the
+call are affected by the value of the integer \var{options}, which
+should be \code{0} for normal operation.
+
+If \var{pid} is greater than \code{0}, \function{waitpid()} requests
+status information for that specific process.  If \var{pid} is
+\code{0}, the request is for the status of any child in the process
+group of the current process.  If \var{pid} is \code{-1}, the request
+pertains to any child of the current process.  If \var{pid} is less
+than \code{-1}, status is requested for any process in the process
+group \code{-\var{pid}} (the absolute value of \var{pid}).
+
+On Windows:
+Wait for completion of a process given by process handle \var{pid},
+and return a tuple containing \var{pid},
+and its exit status shifted left by 8 bits (shifting makes cross-platform
+use of the function easier).
+A \var{pid} less than or equal to \code{0} has no special meaning on
+Windows, and raises an exception.
+The value of integer \var{options} has no effect.
+\var{pid} can refer to any process whose id is known, not necessarily a
+child process.
+The \function{spawn()} functions called with \constant{P_NOWAIT}
+return suitable process handles.
+\end{funcdesc}
+
+\begin{funcdesc}{wait3}{\optional{options}}
+Similar to \function{waitpid()}, except no process id argument is given and
+a 3-element tuple containing the child's process id, exit status indication,
+and resource usage information is returned.  Refer to
+\module{resource}.\function{getrusage()}
+for details on resource usage information.  The option argument is the same
+as that provided to \function{waitpid()} and \function{wait4()}.
+Availability: \UNIX.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{funcdesc}{wait4}{pid, options}
+Similar to \function{waitpid()}, except a 3-element tuple, containing the
+child's process id, exit status indication, and resource usage information
+is returned.  Refer to \module{resource}.\function{getrusage()} for details
+on resource usage information.  The arguments to \function{wait4()} are
+the same as those provided to \function{waitpid()}.
+Availability: \UNIX.
+\versionadded{2.5}
+\end{funcdesc}
+
+\begin{datadesc}{WNOHANG}
+The option for \function{waitpid()} to return immediately if no child
+process status is available immediately. The function returns
+\code{(0, 0)} in this case.
+Availability: Macintosh, \UNIX.
+\end{datadesc}
+
+\begin{datadesc}{WCONTINUED}
+This option causes child processes to be reported if they have been
+continued from a job control stop since their status was last
+reported.
+Availability: Some \UNIX{} systems.
+\versionadded{2.3}
+\end{datadesc}
+
+\begin{datadesc}{WUNTRACED}
+This option causes child processes to be reported if they have been
+stopped but their current state has not been reported since they were
+stopped.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{datadesc}
+
+The following functions take a process status code as returned by
+\function{system()}, \function{wait()}, or \function{waitpid()} as a
+parameter.  They may be used to determine the disposition of a
+process.
+
+\begin{funcdesc}{WCOREDUMP}{status}
+Returns \code{True} if a core dump was generated for the process,
+otherwise it returns \code{False}.
+Availability: Macintosh, \UNIX.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{WIFCONTINUED}{status}
+Returns \code{True} if the process has been continued from a job
+control stop, otherwise it returns \code{False}.
+Availability: \UNIX.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{WIFSTOPPED}{status}
+Returns \code{True} if the process has been stopped, otherwise it
+returns \code{False}.
+Availability: \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{WIFSIGNALED}{status}
+Returns \code{True} if the process exited due to a signal, otherwise
+it returns \code{False}.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{WIFEXITED}{status}
+Returns \code{True} if the process exited using the \manpage{exit}{2}
+system call, otherwise it returns \code{False}.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{WEXITSTATUS}{status}
+If \code{WIFEXITED(\var{status})} is true, return the integer
+parameter to the \manpage{exit}{2} system call.  Otherwise, the return
+value is meaningless.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{WSTOPSIG}{status}
+Return the signal which caused the process to stop.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{WTERMSIG}{status}
+Return the signal which caused the process to exit.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+
+\subsection{Miscellaneous System Information \label{os-path}}
+
+
+\begin{funcdesc}{confstr}{name}
+Return string-valued system configuration values.
+\var{name} specifies the configuration value to retrieve; it may be a
+string which is the name of a defined system value; these names are
+specified in a number of standards (\POSIX, \UNIX{} 95, \UNIX{} 98, and
+others).  Some platforms define additional names as well.  The names
+known to the host operating system are given as the keys of the
+\code{confstr_names} dictionary.  For configuration variables not
+included in that mapping, passing an integer for \var{name} is also
+accepted.
+Availability: Macintosh, \UNIX.
+
+If the configuration value specified by \var{name} isn't defined,
+\code{None} is returned.
+
+If \var{name} is a string and is not known, \exception{ValueError} is
+raised.  If a specific value for \var{name} is not supported by the
+host system, even if it is included in \code{confstr_names}, an
+\exception{OSError} is raised with \constant{errno.EINVAL} for the
+error number.
+\end{funcdesc}
+
+\begin{datadesc}{confstr_names}
+Dictionary mapping names accepted by \function{confstr()} to the
+integer values defined for those names by the host operating system.
+This can be used to determine the set of names known to the system.
+Availability: Macintosh, \UNIX.
+\end{datadesc}
+
+\begin{funcdesc}{getloadavg}{}
+Return the number of processes in the system run queue averaged over
+the last 1, 5, and 15 minutes or raises \exception{OSError} if the load 
+average was unobtainable.
+
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{sysconf}{name}
+Return integer-valued system configuration values.
+If the configuration value specified by \var{name} isn't defined,
+\code{-1} is returned.  The comments regarding the \var{name}
+parameter for \function{confstr()} apply here as well; the dictionary
+that provides information on the known names is given by
+\code{sysconf_names}.
+Availability: Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{datadesc}{sysconf_names}
+Dictionary mapping names accepted by \function{sysconf()} to the
+integer values defined for those names by the host operating system.
+This can be used to determine the set of names known to the system.
+Availability: Macintosh, \UNIX.
+\end{datadesc}
+
+
+The follow data values are used to support path manipulation
+operations.  These are defined for all platforms.
+
+Higher-level operations on pathnames are defined in the
+\refmodule{os.path} module.
+
+
+\begin{datadesc}{curdir}
+The constant string used by the operating system to refer to the current
+directory.
+For example: \code{'.'} for \POSIX{} or \code{':'} for Mac OS 9.
+Also available via \module{os.path}.
+\end{datadesc}
+
+\begin{datadesc}{pardir}
+The constant string used by the operating system to refer to the parent
+directory.
+For example: \code{'..'} for \POSIX{} or \code{'::'} for Mac OS 9.
+Also available via \module{os.path}.
+\end{datadesc}
+
+\begin{datadesc}{sep}
+The character used by the operating system to separate pathname components,
+for example, \character{/} for \POSIX{} or \character{:} for
+Mac OS 9.  Note that knowing this is not sufficient to be able to
+parse or concatenate pathnames --- use \function{os.path.split()} and
+\function{os.path.join()} --- but it is occasionally useful.
+Also available via \module{os.path}.
+\end{datadesc}
+
+\begin{datadesc}{altsep}
+An alternative character used by the operating system to separate pathname
+components, or \code{None} if only one separator character exists.  This is
+set to \character{/} on Windows systems where \code{sep} is a
+backslash.
+Also available via \module{os.path}.
+\end{datadesc}
+
+\begin{datadesc}{extsep}
+The character which separates the base filename from the extension;
+for example, the \character{.} in \file{os.py}.
+Also available via \module{os.path}.
+\versionadded{2.2}
+\end{datadesc}
+
+\begin{datadesc}{pathsep}
+The character conventionally used by the operating system to separate
+search path components (as in \envvar{PATH}), such as \character{:} for
+\POSIX{} or \character{;} for Windows.
+Also available via \module{os.path}.
+\end{datadesc}
+
+\begin{datadesc}{defpath}
+The default search path used by \function{exec*p*()} and
+\function{spawn*p*()} if the environment doesn't have a \code{'PATH'}
+key.
+Also available via \module{os.path}.
+\end{datadesc}
+
+\begin{datadesc}{linesep}
+The string used to separate (or, rather, terminate) lines on the
+current platform.  This may be a single character, such as \code{'\e
+n'} for \POSIX{} or \code{'\e r'} for Mac OS, or multiple characters,
+for example, \code{'\e r\e n'} for Windows.
+\end{datadesc}
+
+\begin{datadesc}{devnull}
+The file path of the null device.
+For example: \code{'/dev/null'} for \POSIX{} or \code{'Dev:Nul'} for
+Mac OS 9.
+Also available via \module{os.path}.
+\versionadded{2.4}
+\end{datadesc}
+
+
+\subsection{Miscellaneous Functions \label{os-miscfunc}}
+
+\begin{funcdesc}{urandom}{n}
+Return a string of \var{n} random bytes suitable for cryptographic use.
+
+This function returns random bytes from an OS-specific
+randomness source.  The returned data should be unpredictable enough for
+cryptographic applications, though its exact quality depends on the OS
+implementation.  On a UNIX-like system this will query /dev/urandom, and
+on Windows it will use CryptGenRandom.  If a randomness source is not
+found, \exception{NotImplementedError} will be raised.
+\versionadded{2.4}
+\end{funcdesc}
+
+
+
+
diff --git a/sys/src/cmd/python/Doc/lib/libossaudiodev.tex b/sys/src/cmd/python/Doc/lib/libossaudiodev.tex
new file mode 100644
index 000000000..4c19aafbd
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libossaudiodev.tex
@@ -0,0 +1,401 @@
+\section{\module{ossaudiodev} ---
+         Access to OSS-compatible audio devices}
+
+\declaremodule{builtin}{ossaudiodev}
+\platform{Linux, FreeBSD}
+\modulesynopsis{Access to OSS-compatible audio devices.}
+
+\versionadded{2.3}
+
+This module allows you to access the OSS (Open Sound System) audio
+interface.  OSS is available for a wide range of open-source and
+commercial Unices, and is the standard audio interface for Linux and
+recent versions of FreeBSD.
+
+% Things will get more complicated for future Linux versions, since
+% ALSA is in the standard kernel as of 2.5.x.  Presumably if you
+% use ALSA, you'll have to make sure its OSS compatibility layer
+% is active to use ossaudiodev, but you're gonna need it for the vast
+% majority of Linux audio apps anyways.  
+%
+% Sounds like things are also complicated for other BSDs.  In response
+% to my python-dev query, Thomas Wouters said:
+%
+% > Likewise, googling shows OpenBSD also uses OSS/Free -- the commercial
+% > OSS installation manual tells you to remove references to OSS/Free from the
+% > kernel :)
+%
+% but Aleksander Piotrowsk actually has an OpenBSD box, and he quotes
+% from its :
+% >  * WARNING!  WARNING!
+% >  * This is an OSS (Linux) audio emulator.
+% >  * Use the Native NetBSD API for developing new code, and this
+% >  * only for compiling Linux programs.
+%
+% There's also an ossaudio manpage on OpenBSD that explains things
+% further.  Presumably NetBSD and OpenBSD have a different standard
+% audio interface.  That's the great thing about standards, there are so
+% many to choose from ... ;-)  
+%
+% This probably all warrants a footnote or two, but I don't understand
+% things well enough right now to write it!   --GPW
+
+\begin{seealso}
+\seetitle[http://www.opensound.com/pguide/oss.pdf]
+         {Open Sound System Programmer's Guide} {the official
+         documentation for the OSS C API}
+\seetext{The module defines a large number of constants supplied by
+         the OSS device driver; see \code{} on either
+         Linux or FreeBSD for a listing .}
+\end{seealso}
+
+\module{ossaudiodev} defines the following variables and functions:
+
+\begin{excdesc}{OSSAudioError}
+This exception is raised on certain errors.  The argument is a string
+describing what went wrong.
+
+(If \module{ossaudiodev} receives an error from a system call such as
+\cfunction{open()}, \cfunction{write()}, or \cfunction{ioctl()}, it
+raises \exception{IOError}.  Errors detected directly by
+\module{ossaudiodev} result in \exception{OSSAudioError}.)
+
+(For backwards compatibility, the exception class is also available as
+\code{ossaudiodev.error}.)
+\end{excdesc}
+
+\begin{funcdesc}{open}{\optional{device, }mode}
+Open an audio device and return an OSS audio device object.  This
+object supports many file-like methods, such as \method{read()},
+\method{write()}, and \method{fileno()} (although there are subtle
+differences between conventional \UNIX{} read/write semantics and those of
+OSS audio devices).  It also supports a number of audio-specific
+methods; see below for the complete list of methods.
+
+\var{device} is the audio device filename to use.  If it is not
+specified, this module first looks in the environment variable
+\envvar{AUDIODEV} for a device to use.  If not found, it falls back to
+\file{/dev/dsp}.
+
+\var{mode} is one of \code{'r'} for read-only (record) access,
+\code{'w'} for write-only (playback) access and \code{'rw'} for both.
+Since many sound cards only allow one process to have the recorder or
+player open at a time, it is a good idea to open the device only for the
+activity needed.  Further, some sound cards are half-duplex: they can be
+opened for reading or writing, but not both at once.
+
+Note the unusual calling syntax: the \emph{first} argument is optional,
+and the second is required.  This is a historical artifact for
+compatibility with the older \module{linuxaudiodev} module which
+\module{ossaudiodev} supersedes.  % XXX it might also be motivated
+% by my unfounded-but-still-possibly-true belief that the default
+% audio device varies unpredictably across operating systems.  -GW
+\end{funcdesc}
+
+\begin{funcdesc}{openmixer}{\optional{device}}
+Open a mixer device and return an OSS mixer device object.  
+\var{device} is the mixer device filename to use.  If it is
+not specified, this module first looks in the environment variable
+\envvar{MIXERDEV} for a device to use.  If not found, it falls back to
+\file{/dev/mixer}.
+
+\end{funcdesc}
+
+\subsection{Audio Device Objects \label{ossaudio-device-objects}}
+
+Before you can write to or read from an audio device, you must call
+three methods in the correct order:
+\begin{enumerate}
+\item \method{setfmt()} to set the output format
+\item \method{channels()} to set the number of channels
+\item \method{speed()} to set the sample rate
+\end{enumerate}
+Alternately, you can use the \method{setparameters()} method to set all
+three audio parameters at once.  This is more convenient, but may not be
+as flexible in all cases.
+
+The audio device objects returned by \function{open()} define the
+following methods and (read-only) attributes:
+
+\begin{methoddesc}[audio device]{close}{}
+Explicitly close the audio device.  When you are done writing to or
+reading from an audio device, you should explicitly close it.  A closed
+device cannot be used again.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{fileno}{}
+Return the file descriptor associated with the device.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{read}{size}
+Read \var{size} bytes from the audio input and return them as a Python
+string.  Unlike most \UNIX{} device drivers, OSS audio devices in
+blocking mode (the default) will block \function{read()} until the
+entire requested amount of data is available.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{write}{data}
+Write the Python string \var{data} to the audio device and return the
+number of bytes written.  If the audio device is in blocking mode (the
+default), the entire string is always written (again, this is different
+from usual \UNIX{} device semantics).  If the device is in non-blocking
+mode, some data may not be written---see \method{writeall()}.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{writeall}{data}
+Write the entire Python string \var{data} to the audio device: waits
+until the audio device is able to accept data, writes as much data as it
+will accept, and repeats until \var{data} has been completely written.
+If the device is in blocking mode (the default), this has the same
+effect as \method{write()}; \method{writeall()} is only useful in
+non-blocking mode.  Has no return value, since the amount of data
+written is always equal to the amount of data supplied.
+\end{methoddesc}
+
+The following methods each map to exactly one
+\function{ioctl()} system call.  The correspondence is obvious: for
+example, \method{setfmt()} corresponds to the \code{SNDCTL_DSP_SETFMT}
+ioctl, and \method{sync()} to \code{SNDCTL_DSP_SYNC} (this can be useful
+when consulting the OSS documentation).  If the underlying
+\function{ioctl()} fails, they all raise \exception{IOError}.
+
+\begin{methoddesc}[audio device]{nonblock}{}
+Put the device into non-blocking mode.  Once in non-blocking mode, there
+is no way to return it to blocking mode.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{getfmts}{}
+Return a bitmask of the audio output formats supported by the
+soundcard.  Some of the formats supported by OSS are:
+
+\begin{tableii}{l|l}{constant}{Format}{Description}
+\lineii{AFMT_MU_LAW}
+       {a logarithmic encoding (used by Sun \code{.au} files and
+        \filenq{/dev/audio})}
+\lineii{AFMT_A_LAW}
+       {a logarithmic encoding}
+\lineii{AFMT_IMA_ADPCM}
+       {a 4:1 compressed format defined by the Interactive Multimedia
+        Association} 
+\lineii{AFMT_U8}
+       {Unsigned, 8-bit audio}
+\lineii{AFMT_S16_LE}
+       {Signed, 16-bit audio, little-endian byte order (as used by
+        Intel processors)}
+\lineii{AFMT_S16_BE}
+       {Signed, 16-bit audio, big-endian byte order (as used by 68k,
+        PowerPC, Sparc)}
+\lineii{AFMT_S8}
+       {Signed, 8 bit audio}
+\lineii{AFMT_U16_LE}
+       {Unsigned, 16-bit little-endian audio}
+\lineii{AFMT_U16_BE}
+       {Unsigned, 16-bit big-endian audio}
+\end{tableii}
+Consult the OSS documentation for a full list of audio formats, and note
+that most devices support only a subset of these formats.  Some older
+devices only support \constant{AFMT_U8}; the most common format used
+today is \constant{AFMT_S16_LE}.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{setfmt}{format}
+Try to set the current audio format to \var{format}---see
+\method{getfmts()} for a list.  Returns the audio format that the device
+was set to, which may not be the requested format.  May also be used to
+return the current audio format---do this by passing an ``audio format''
+of
+\constant{AFMT_QUERY}.  
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{channels}{nchannels}
+Set the number of output channels to \var{nchannels}.  A value of 1
+indicates monophonic sound, 2 stereophonic.  Some devices may have more
+than 2 channels, and some high-end devices may not support mono.
+Returns the number of channels the device was set to.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{speed}{samplerate}
+Try to set the audio sampling rate to \var{samplerate} samples per
+second.  Returns the rate actually set.  Most sound devices don't
+support arbitrary sampling rates.  Common rates are:
+\begin{tableii}{l|l}{textrm}{Rate}{Description}
+\lineii{8000}{default rate for \filenq{/dev/audio}}
+\lineii{11025}{speech recording}
+\lineii{22050}{}
+\lineii{44100}{CD quality audio (at 16 bits/sample and 2 channels)}
+\lineii{96000}{DVD quality audio (at 24 bits/sample)}
+\end{tableii}
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{sync}{}
+Wait until the sound device has played every byte in its buffer.  (This
+happens implicitly when the device is closed.)  The OSS documentation
+recommends closing and re-opening the device rather than using
+\method{sync()}.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{reset}{}
+Immediately stop playing or recording and return the device to a
+state where it can accept commands.  The OSS documentation recommends
+closing and re-opening the device after calling \method{reset()}.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{post}{}
+Tell the driver that there is likely to be a pause in the output, making
+it possible for the device to handle the pause more intelligently.  You
+might use this after playing a spot sound effect, before waiting for
+user input, or before doing disk I/O.
+\end{methoddesc}
+
+The following convenience methods combine several ioctls, or one ioctl
+and some simple calculations.
+
+\begin{methoddesc}[audio device]{setparameters}
+  {format, nchannels, samplerate \optional{, strict=False}}
+
+Set the key audio sampling parameters---sample format, number of
+channels, and sampling rate---in one method call.  \var{format}, 
+\var{nchannels}, and \var{samplerate} should be as specified in the
+\method{setfmt()}, \method{channels()}, and \method{speed()} 
+methods.  If \var{strict} is true, \method{setparameters()} checks to
+see if each parameter was actually set to the requested value, and
+raises \exception{OSSAudioError} if not.  Returns a tuple (\var{format},
+\var{nchannels}, \var{samplerate}) indicating the parameter values that
+were actually set by the device driver (i.e., the same as the return
+values of \method{setfmt()}, \method{channels()}, and \method{speed()}).
+
+For example,
+\begin{verbatim}
+  (fmt, channels, rate) = dsp.setparameters(fmt, channels, rate)
+\end{verbatim}
+is equivalent to
+\begin{verbatim}
+  fmt = dsp.setfmt(fmt)
+  channels = dsp.channels(channels)
+  rate = dsp.rate(channels)
+\end{verbatim}
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{bufsize}{}
+Returns the size of the hardware buffer, in samples.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{obufcount}{}
+Returns the number of samples that are in the hardware buffer yet to be
+played.
+\end{methoddesc}
+
+\begin{methoddesc}[audio device]{obuffree}{}
+Returns the number of samples that could be queued into the hardware
+buffer to be played without blocking.
+\end{methoddesc}
+
+Audio device objects also support several read-only attributes:
+
+\begin{memberdesc}[audio device]{closed}{}
+Boolean indicating whether the device has been closed.
+\end{memberdesc}
+
+\begin{memberdesc}[audio device]{name}{}
+String containing the name of the device file.
+\end{memberdesc}
+
+\begin{memberdesc}[audio device]{mode}{}
+The I/O mode for the file, either \code{"r"}, \code{"rw"}, or \code{"w"}.
+\end{memberdesc}
+
+
+\subsection{Mixer Device Objects \label{mixer-device-objects}}
+
+The mixer object provides two file-like methods:
+
+\begin{methoddesc}[mixer device]{close}{}
+This method closes the open mixer device file.  Any further attempts to
+use the mixer after this file is closed will raise an \exception{IOError}.
+\end{methoddesc}
+
+\begin{methoddesc}[mixer device]{fileno}{}
+Returns the file handle number of the open mixer device file.
+\end{methoddesc}
+
+The remaining methods are specific to audio mixing:
+
+\begin{methoddesc}[mixer device]{controls}{}
+This method returns a bitmask specifying the available mixer controls
+(``Control'' being a specific mixable ``channel'', such as
+\constant{SOUND_MIXER_PCM} or \constant{SOUND_MIXER_SYNTH}).  This
+bitmask indicates a subset of all available mixer controls---the
+\constant{SOUND_MIXER_*} constants defined at module level.  To determine if,
+for example, the current mixer object supports a PCM mixer, use the
+following Python code:
+
+\begin{verbatim}
+mixer=ossaudiodev.openmixer()
+if mixer.controls() & (1 << ossaudiodev.SOUND_MIXER_PCM):
+    # PCM is supported
+    ... code ...
+\end{verbatim}
+
+For most purposes, the \constant{SOUND_MIXER_VOLUME} (master volume) and
+\constant{SOUND_MIXER_PCM} controls should suffice---but code that uses the
+mixer should be flexible when it comes to choosing mixer controls.  On
+the Gravis Ultrasound, for example, \constant{SOUND_MIXER_VOLUME} does not
+exist.
+\end{methoddesc}
+
+\begin{methoddesc}[mixer device]{stereocontrols}{}
+Returns a bitmask indicating stereo mixer controls.  If a bit is set,
+the corresponding control is stereo; if it is unset, the control is
+either monophonic or not supported by the mixer (use in combination with
+\method{controls()} to determine which).
+
+See the code example for the \method{controls()} function for an example
+of getting data from a bitmask.
+\end{methoddesc}
+
+\begin{methoddesc}[mixer device]{reccontrols}{}
+Returns a bitmask specifying the mixer controls that may be used to
+record.  See the code example for \method{controls()} for an example of
+reading from a bitmask.
+\end{methoddesc}
+
+\begin{methoddesc}[mixer device]{get}{control}
+Returns the volume of a given mixer control.  The returned volume is a
+2-tuple \code{(left_volume,right_volume)}.  Volumes are specified as
+numbers from 0 (silent) to 100 (full volume).  If the control is
+monophonic, a 2-tuple is still returned, but both volumes are
+the same.
+
+Raises \exception{OSSAudioError} if an invalid control was is specified,
+or \exception{IOError} if an unsupported control is specified.
+\end{methoddesc}
+
+\begin{methoddesc}[mixer device]{set}{control, (left, right)}
+Sets the volume for a given mixer control to \code{(left,right)}.
+\code{left} and \code{right} must be ints and between 0 (silent) and 100
+(full volume).  On success, the new volume is returned as a 2-tuple.
+Note that this may not be exactly the same as the volume specified,
+because of the limited resolution of some soundcard's mixers.
+
+Raises \exception{OSSAudioError} if an invalid mixer control was
+specified, or if the specified volumes were out-of-range.
+\end{methoddesc}
+
+\begin{methoddesc}[mixer device]{get_recsrc}{}
+This method returns a bitmask indicating which control(s) are
+currently being used as a recording source.
+\end{methoddesc}
+
+\begin{methoddesc}[mixer device]{set_recsrc}{bitmask}
+Call this function to specify a recording source.  Returns a bitmask
+indicating the new recording source (or sources) if successful; raises
+\exception{IOError} if an invalid source was specified.  To set the current
+recording source to the microphone input:
+
+\begin{verbatim}
+mixer.setrecsrc (1 << ossaudiodev.SOUND_MIXER_MIC)
+\end{verbatim}
+\end{methoddesc}
+
+
+
diff --git a/sys/src/cmd/python/Doc/lib/libpanel.tex b/sys/src/cmd/python/Doc/lib/libpanel.tex
new file mode 100644
index 000000000..f2db0b038
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpanel.tex
@@ -0,0 +1,74 @@
+\section{\module{panel} ---
+         None}
+\declaremodule{standard}{panel}
+
+\modulesynopsis{None}
+
+
+\strong{Please note:} The FORMS library, to which the
+\code{fl}\refbimodindex{fl} module described above interfaces, is a
+simpler and more accessible user interface library for use with GL
+than the \code{panel} module (besides also being by a Dutch author).
+
+This module should be used instead of the built-in module
+\code{pnl}\refbimodindex{pnl}
+to interface with the
+\emph{Panel Library}.
+
+The module is too large to document here in its entirety.
+One interesting function:
+
+\begin{funcdesc}{defpanellist}{filename}
+Parses a panel description file containing S-expressions written by the
+\emph{Panel Editor}
+that accompanies the Panel Library and creates the described panels.
+It returns a list of panel objects.
+\end{funcdesc}
+
+\warning{The Python interpreter will dump core if you don't create a
+GL window before calling
+\code{panel.mkpanel()}
+or
+\code{panel.defpanellist()}.}
+
+\section{\module{panelparser} ---
+         None}
+\declaremodule{standard}{panelparser}
+
+\modulesynopsis{None}
+
+
+This module defines a self-contained parser for S-expressions as output
+by the Panel Editor (which is written in Scheme so it can't help writing
+S-expressions).
+The relevant function is
+\code{panelparser.parse_file(\var{file})}
+which has a file object (not a filename!) as argument and returns a list
+of parsed S-expressions.
+Each S-expression is converted into a Python list, with atoms converted
+to Python strings and sub-expressions (recursively) to Python lists.
+For more details, read the module file.
+% XXXXJH should be funcdesc, I think
+
+\section{\module{pnl} ---
+         None}
+\declaremodule{builtin}{pnl}
+
+\modulesynopsis{None}
+
+
+This module provides access to the
+\emph{Panel Library}
+built by NASA Ames\index{NASA} (to get it, send email to
+\code{panel-request@nas.nasa.gov}).
+All access to it should be done through the standard module
+\code{panel}\refstmodindex{panel},
+which transparently exports most functions from
+\code{pnl}
+but redefines
+\code{pnl.dopanel()}.
+
+\warning{The Python interpreter will dump core if you don't create a
+GL window before calling \code{pnl.mkpanel()}.}
+
+The module is too large to document here in its entirety.
diff --git a/sys/src/cmd/python/Doc/lib/libparser.tex b/sys/src/cmd/python/Doc/lib/libparser.tex
new file mode 100644
index 000000000..15b46ae57
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libparser.tex
@@ -0,0 +1,711 @@
+\section{\module{parser} ---
+         Access Python parse trees}
+
+% Copyright 1995 Virginia Polytechnic Institute and State University
+% and Fred L. Drake, Jr.  This copyright notice must be distributed on
+% all copies, but this document otherwise may be distributed as part
+% of the Python distribution.  No fee may be charged for this document
+% in any representation, either on paper or electronically.  This
+% restriction does not affect other elements in a distributed package
+% in any way.
+
+\declaremodule{builtin}{parser}
+\modulesynopsis{Access parse trees for Python source code.}
+\moduleauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+
+\index{parsing!Python source code}
+
+The \module{parser} module provides an interface to Python's internal
+parser and byte-code compiler.  The primary purpose for this interface
+is to allow Python code to edit the parse tree of a Python expression
+and create executable code from this.  This is better than trying
+to parse and modify an arbitrary Python code fragment as a string
+because parsing is performed in a manner identical to the code
+forming the application.  It is also faster.
+
+There are a few things to note about this module which are important
+to making use of the data structures created.  This is not a tutorial
+on editing the parse trees for Python code, but some examples of using
+the \module{parser} module are presented.
+
+Most importantly, a good understanding of the Python grammar processed
+by the internal parser is required.  For full information on the
+language syntax, refer to the \citetitle[../ref/ref.html]{Python
+Language Reference}.  The parser itself is created from a grammar
+specification defined in the file \file{Grammar/Grammar} in the
+standard Python distribution.  The parse trees stored in the AST
+objects created by this module are the actual output from the internal
+parser when created by the \function{expr()} or \function{suite()}
+functions, described below.  The AST objects created by
+\function{sequence2ast()} faithfully simulate those structures.  Be
+aware that the values of the sequences which are considered
+``correct'' will vary from one version of Python to another as the
+formal grammar for the language is revised.  However, transporting
+code from one Python version to another as source text will always
+allow correct parse trees to be created in the target version, with
+the only restriction being that migrating to an older version of the
+interpreter will not support more recent language constructs.  The
+parse trees are not typically compatible from one version to another,
+whereas source code has always been forward-compatible.
+
+Each element of the sequences returned by \function{ast2list()} or
+\function{ast2tuple()} has a simple form.  Sequences representing
+non-terminal elements in the grammar always have a length greater than
+one.  The first element is an integer which identifies a production in
+the grammar.  These integers are given symbolic names in the C header
+file \file{Include/graminit.h} and the Python module
+\refmodule{symbol}.  Each additional element of the sequence represents
+a component of the production as recognized in the input string: these
+are always sequences which have the same form as the parent.  An
+important aspect of this structure which should be noted is that
+keywords used to identify the parent node type, such as the keyword
+\keyword{if} in an \constant{if_stmt}, are included in the node tree without
+any special treatment.  For example, the \keyword{if} keyword is
+represented by the tuple \code{(1, 'if')}, where \code{1} is the
+numeric value associated with all \constant{NAME} tokens, including
+variable and function names defined by the user.  In an alternate form
+returned when line number information is requested, the same token
+might be represented as \code{(1, 'if', 12)}, where the \code{12}
+represents the line number at which the terminal symbol was found.
+
+Terminal elements are represented in much the same way, but without
+any child elements and the addition of the source text which was
+identified.  The example of the \keyword{if} keyword above is
+representative.  The various types of terminal symbols are defined in
+the C header file \file{Include/token.h} and the Python module
+\refmodule{token}.
+
+The AST objects are not required to support the functionality of this
+module, but are provided for three purposes: to allow an application
+to amortize the cost of processing complex parse trees, to provide a
+parse tree representation which conserves memory space when compared
+to the Python list or tuple representation, and to ease the creation
+of additional modules in C which manipulate parse trees.  A simple
+``wrapper'' class may be created in Python to hide the use of AST
+objects.
+
+The \module{parser} module defines functions for a few distinct
+purposes.  The most important purposes are to create AST objects and
+to convert AST objects to other representations such as parse trees
+and compiled code objects, but there are also functions which serve to
+query the type of parse tree represented by an AST object.
+
+
+\begin{seealso}
+  \seemodule{symbol}{Useful constants representing internal nodes of
+                     the parse tree.}
+  \seemodule{token}{Useful constants representing leaf nodes of the
+                    parse tree and functions for testing node values.}
+\end{seealso}
+
+
+\subsection{Creating AST Objects \label{Creating ASTs}}
+
+AST objects may be created from source code or from a parse tree.
+When creating an AST object from source, different functions are used
+to create the \code{'eval'} and \code{'exec'} forms.
+
+\begin{funcdesc}{expr}{source}
+The \function{expr()} function parses the parameter \var{source}
+as if it were an input to \samp{compile(\var{source}, 'file.py',
+'eval')}.  If the parse succeeds, an AST object is created to hold the
+internal parse tree representation, otherwise an appropriate exception
+is thrown.
+\end{funcdesc}
+
+\begin{funcdesc}{suite}{source}
+The \function{suite()} function parses the parameter \var{source}
+as if it were an input to \samp{compile(\var{source}, 'file.py',
+'exec')}.  If the parse succeeds, an AST object is created to hold the
+internal parse tree representation, otherwise an appropriate exception
+is thrown.
+\end{funcdesc}
+
+\begin{funcdesc}{sequence2ast}{sequence}
+This function accepts a parse tree represented as a sequence and
+builds an internal representation if possible.  If it can validate
+that the tree conforms to the Python grammar and all nodes are valid
+node types in the host version of Python, an AST object is created
+from the internal representation and returned to the called.  If there
+is a problem creating the internal representation, or if the tree
+cannot be validated, a \exception{ParserError} exception is thrown.  An AST
+object created this way should not be assumed to compile correctly;
+normal exceptions thrown by compilation may still be initiated when
+the AST object is passed to \function{compileast()}.  This may indicate
+problems not related to syntax (such as a \exception{MemoryError}
+exception), but may also be due to constructs such as the result of
+parsing \code{del f(0)}, which escapes the Python parser but is
+checked by the bytecode compiler.
+
+Sequences representing terminal tokens may be represented as either
+two-element lists of the form \code{(1, 'name')} or as three-element
+lists of the form \code{(1, 'name', 56)}.  If the third element is
+present, it is assumed to be a valid line number.  The line number
+may be specified for any subset of the terminal symbols in the input
+tree.
+\end{funcdesc}
+
+\begin{funcdesc}{tuple2ast}{sequence}
+This is the same function as \function{sequence2ast()}.  This entry point
+is maintained for backward compatibility.
+\end{funcdesc}
+
+
+\subsection{Converting AST Objects \label{Converting ASTs}}
+
+AST objects, regardless of the input used to create them, may be
+converted to parse trees represented as list- or tuple- trees, or may
+be compiled into executable code objects.  Parse trees may be
+extracted with or without line numbering information.
+
+\begin{funcdesc}{ast2list}{ast\optional{, line_info}}
+This function accepts an AST object from the caller in
+\var{ast} and returns a Python list representing the
+equivalent parse tree.  The resulting list representation can be used
+for inspection or the creation of a new parse tree in list form.  This
+function does not fail so long as memory is available to build the
+list representation.  If the parse tree will only be used for
+inspection, \function{ast2tuple()} should be used instead to reduce memory
+consumption and fragmentation.  When the list representation is
+required, this function is significantly faster than retrieving a
+tuple representation and converting that to nested lists.
+
+If \var{line_info} is true, line number information will be
+included for all terminal tokens as a third element of the list
+representing the token.  Note that the line number provided specifies
+the line on which the token \emph{ends}.  This information is
+omitted if the flag is false or omitted.
+\end{funcdesc}
+
+\begin{funcdesc}{ast2tuple}{ast\optional{, line_info}}
+This function accepts an AST object from the caller in
+\var{ast} and returns a Python tuple representing the
+equivalent parse tree.  Other than returning a tuple instead of a
+list, this function is identical to \function{ast2list()}.
+
+If \var{line_info} is true, line number information will be
+included for all terminal tokens as a third element of the list
+representing the token.  This information is omitted if the flag is
+false or omitted.
+\end{funcdesc}
+
+\begin{funcdesc}{compileast}{ast\optional{, filename\code{ = ''}}}
+The Python byte compiler can be invoked on an AST object to produce
+code objects which can be used as part of an \keyword{exec} statement or
+a call to the built-in \function{eval()}\bifuncindex{eval} function.
+This function provides the interface to the compiler, passing the
+internal parse tree from \var{ast} to the parser, using the
+source file name specified by the \var{filename} parameter.
+The default value supplied for \var{filename} indicates that
+the source was an AST object.
+
+Compiling an AST object may result in exceptions related to
+compilation; an example would be a \exception{SyntaxError} caused by the
+parse tree for \code{del f(0)}: this statement is considered legal
+within the formal grammar for Python but is not a legal language
+construct.  The \exception{SyntaxError} raised for this condition is
+actually generated by the Python byte-compiler normally, which is why
+it can be raised at this point by the \module{parser} module.  Most
+causes of compilation failure can be diagnosed programmatically by
+inspection of the parse tree.
+\end{funcdesc}
+
+
+\subsection{Queries on AST Objects \label{Querying ASTs}}
+
+Two functions are provided which allow an application to determine if
+an AST was created as an expression or a suite.  Neither of these
+functions can be used to determine if an AST was created from source
+code via \function{expr()} or \function{suite()} or from a parse tree
+via \function{sequence2ast()}.
+
+\begin{funcdesc}{isexpr}{ast}
+When \var{ast} represents an \code{'eval'} form, this function
+returns true, otherwise it returns false.  This is useful, since code
+objects normally cannot be queried for this information using existing
+built-in functions.  Note that the code objects created by
+\function{compileast()} cannot be queried like this either, and are
+identical to those created by the built-in
+\function{compile()}\bifuncindex{compile} function.
+\end{funcdesc}
+
+
+\begin{funcdesc}{issuite}{ast}
+This function mirrors \function{isexpr()} in that it reports whether an
+AST object represents an \code{'exec'} form, commonly known as a
+``suite.''  It is not safe to assume that this function is equivalent
+to \samp{not isexpr(\var{ast})}, as additional syntactic fragments may
+be supported in the future.
+\end{funcdesc}
+
+
+\subsection{Exceptions and Error Handling \label{AST Errors}}
+
+The parser module defines a single exception, but may also pass other
+built-in exceptions from other portions of the Python runtime
+environment.  See each function for information about the exceptions
+it can raise.
+
+\begin{excdesc}{ParserError}
+Exception raised when a failure occurs within the parser module.  This
+is generally produced for validation failures rather than the built in
+\exception{SyntaxError} thrown during normal parsing.
+The exception argument is either a string describing the reason of the
+failure or a tuple containing a sequence causing the failure from a parse
+tree passed to \function{sequence2ast()} and an explanatory string.  Calls to
+\function{sequence2ast()} need to be able to handle either type of exception,
+while calls to other functions in the module will only need to be
+aware of the simple string values.
+\end{excdesc}
+
+Note that the functions \function{compileast()}, \function{expr()}, and
+\function{suite()} may throw exceptions which are normally thrown by the
+parsing and compilation process.  These include the built in
+exceptions \exception{MemoryError}, \exception{OverflowError},
+\exception{SyntaxError}, and \exception{SystemError}.  In these cases, these
+exceptions carry all the meaning normally associated with them.  Refer
+to the descriptions of each function for detailed information.
+
+
+\subsection{AST Objects \label{AST Objects}}
+
+Ordered and equality comparisons are supported between AST objects.
+Pickling of AST objects (using the \refmodule{pickle} module) is also
+supported.
+
+\begin{datadesc}{ASTType}
+The type of the objects returned by \function{expr()},
+\function{suite()} and \function{sequence2ast()}.
+\end{datadesc}
+
+
+AST objects have the following methods:
+
+
+\begin{methoddesc}[AST]{compile}{\optional{filename}}
+Same as \code{compileast(\var{ast}, \var{filename})}.
+\end{methoddesc}
+
+\begin{methoddesc}[AST]{isexpr}{}
+Same as \code{isexpr(\var{ast})}.
+\end{methoddesc}
+
+\begin{methoddesc}[AST]{issuite}{}
+Same as \code{issuite(\var{ast})}.
+\end{methoddesc}
+
+\begin{methoddesc}[AST]{tolist}{\optional{line_info}}
+Same as \code{ast2list(\var{ast}, \var{line_info})}.
+\end{methoddesc}
+
+\begin{methoddesc}[AST]{totuple}{\optional{line_info}}
+Same as \code{ast2tuple(\var{ast}, \var{line_info})}.
+\end{methoddesc}
+
+
+\subsection{Examples \label{AST Examples}}
+
+The parser modules allows operations to be performed on the parse tree
+of Python source code before the bytecode is generated, and provides
+for inspection of the parse tree for information gathering purposes.
+Two examples are presented.  The simple example demonstrates emulation
+of the \function{compile()}\bifuncindex{compile} built-in function and
+the complex example shows the use of a parse tree for information
+discovery.
+
+\subsubsection{Emulation of \function{compile()}}
+
+While many useful operations may take place between parsing and
+bytecode generation, the simplest operation is to do nothing.  For
+this purpose, using the \module{parser} module to produce an
+intermediate data structure is equivalent to the code
+
+\begin{verbatim}
+>>> code = compile('a + 5', 'file.py', 'eval')
+>>> a = 5
+>>> eval(code)
+10
+\end{verbatim}
+
+The equivalent operation using the \module{parser} module is somewhat
+longer, and allows the intermediate internal parse tree to be retained
+as an AST object:
+
+\begin{verbatim}
+>>> import parser
+>>> ast = parser.expr('a + 5')
+>>> code = ast.compile('file.py')
+>>> a = 5
+>>> eval(code)
+10
+\end{verbatim}
+
+An application which needs both AST and code objects can package this
+code into readily available functions:
+
+\begin{verbatim}
+import parser
+
+def load_suite(source_string):
+    ast = parser.suite(source_string)
+    return ast, ast.compile()
+
+def load_expression(source_string):
+    ast = parser.expr(source_string)
+    return ast, ast.compile()
+\end{verbatim}
+
+\subsubsection{Information Discovery}
+
+Some applications benefit from direct access to the parse tree.  The
+remainder of this section demonstrates how the parse tree provides
+access to module documentation defined in
+docstrings\index{string!documentation}\index{docstrings} without
+requiring that the code being examined be loaded into a running
+interpreter via \keyword{import}.  This can be very useful for
+performing analyses of untrusted code.
+
+Generally, the example will demonstrate how the parse tree may be
+traversed to distill interesting information.  Two functions and a set
+of classes are developed which provide programmatic access to high
+level function and class definitions provided by a module.  The
+classes extract information from the parse tree and provide access to
+the information at a useful semantic level, one function provides a
+simple low-level pattern matching capability, and the other function
+defines a high-level interface to the classes by handling file
+operations on behalf of the caller.  All source files mentioned here
+which are not part of the Python installation are located in the
+\file{Demo/parser/} directory of the distribution.
+
+The dynamic nature of Python allows the programmer a great deal of
+flexibility, but most modules need only a limited measure of this when
+defining classes, functions, and methods.  In this example, the only
+definitions that will be considered are those which are defined in the
+top level of their context, e.g., a function defined by a \keyword{def}
+statement at column zero of a module, but not a function defined
+within a branch of an \keyword{if} ... \keyword{else} construct, though
+there are some good reasons for doing so in some situations.  Nesting
+of definitions will be handled by the code developed in the example.
+
+To construct the upper-level extraction methods, we need to know what
+the parse tree structure looks like and how much of it we actually
+need to be concerned about.  Python uses a moderately deep parse tree
+so there are a large number of intermediate nodes.  It is important to
+read and understand the formal grammar used by Python.  This is
+specified in the file \file{Grammar/Grammar} in the distribution.
+Consider the simplest case of interest when searching for docstrings:
+a module consisting of a docstring and nothing else.  (See file
+\file{docstring.py}.)
+
+\begin{verbatim}
+"""Some documentation.
+"""
+\end{verbatim}
+
+Using the interpreter to take a look at the parse tree, we find a
+bewildering mass of numbers and parentheses, with the documentation
+buried deep in nested tuples.
+
+\begin{verbatim}
+>>> import parser
+>>> import pprint
+>>> ast = parser.suite(open('docstring.py').read())
+>>> tup = ast.totuple()
+>>> pprint.pprint(tup)
+(257,
+ (264,
+  (265,
+   (266,
+    (267,
+     (307,
+      (287,
+       (288,
+        (289,
+         (290,
+          (292,
+           (293,
+            (294,
+             (295,
+              (296,
+               (297,
+                (298,
+                 (299,
+                  (300, (3, '"""Some documentation.\n"""'))))))))))))))))),
+   (4, ''))),
+ (4, ''),
+ (0, ''))
+\end{verbatim}
+
+The numbers at the first element of each node in the tree are the node
+types; they map directly to terminal and non-terminal symbols in the
+grammar.  Unfortunately, they are represented as integers in the
+internal representation, and the Python structures generated do not
+change that.  However, the \refmodule{symbol} and \refmodule{token} modules
+provide symbolic names for the node types and dictionaries which map
+from the integers to the symbolic names for the node types.
+
+In the output presented above, the outermost tuple contains four
+elements: the integer \code{257} and three additional tuples.  Node
+type \code{257} has the symbolic name \constant{file_input}.  Each of
+these inner tuples contains an integer as the first element; these
+integers, \code{264}, \code{4}, and \code{0}, represent the node types
+\constant{stmt}, \constant{NEWLINE}, and \constant{ENDMARKER},
+respectively.
+Note that these values may change depending on the version of Python
+you are using; consult \file{symbol.py} and \file{token.py} for
+details of the mapping.  It should be fairly clear that the outermost
+node is related primarily to the input source rather than the contents
+of the file, and may be disregarded for the moment.  The \constant{stmt}
+node is much more interesting.  In particular, all docstrings are
+found in subtrees which are formed exactly as this node is formed,
+with the only difference being the string itself.  The association
+between the docstring in a similar tree and the defined entity (class,
+function, or module) which it describes is given by the position of
+the docstring subtree within the tree defining the described
+structure.
+
+By replacing the actual docstring with something to signify a variable
+component of the tree, we allow a simple pattern matching approach to
+check any given subtree for equivalence to the general pattern for
+docstrings.  Since the example demonstrates information extraction, we
+can safely require that the tree be in tuple form rather than list
+form, allowing a simple variable representation to be
+\code{['variable_name']}.  A simple recursive function can implement
+the pattern matching, returning a Boolean and a dictionary of variable
+name to value mappings.  (See file \file{example.py}.)
+
+\begin{verbatim}
+from types import ListType, TupleType
+
+def match(pattern, data, vars=None):
+    if vars is None:
+        vars = {}
+    if type(pattern) is ListType:
+        vars[pattern[0]] = data
+        return 1, vars
+    if type(pattern) is not TupleType:
+        return (pattern == data), vars
+    if len(data) != len(pattern):
+        return 0, vars
+    for pattern, data in map(None, pattern, data):
+        same, vars = match(pattern, data, vars)
+        if not same:
+            break
+    return same, vars
+\end{verbatim}
+
+Using this simple representation for syntactic variables and the symbolic
+node types, the pattern for the candidate docstring subtrees becomes
+fairly readable.  (See file \file{example.py}.)
+
+\begin{verbatim}
+import symbol
+import token
+
+DOCSTRING_STMT_PATTERN = (
+    symbol.stmt,
+    (symbol.simple_stmt,
+     (symbol.small_stmt,
+      (symbol.expr_stmt,
+       (symbol.testlist,
+        (symbol.test,
+         (symbol.and_test,
+          (symbol.not_test,
+           (symbol.comparison,
+            (symbol.expr,
+             (symbol.xor_expr,
+              (symbol.and_expr,
+               (symbol.shift_expr,
+                (symbol.arith_expr,
+                 (symbol.term,
+                  (symbol.factor,
+                   (symbol.power,
+                    (symbol.atom,
+                     (token.STRING, ['docstring'])
+                     )))))))))))))))),
+     (token.NEWLINE, '')
+     ))
+\end{verbatim}
+
+Using the \function{match()} function with this pattern, extracting the
+module docstring from the parse tree created previously is easy:
+
+\begin{verbatim}
+>>> found, vars = match(DOCSTRING_STMT_PATTERN, tup[1])
+>>> found
+1
+>>> vars
+{'docstring': '"""Some documentation.\n"""'}
+\end{verbatim}
+
+Once specific data can be extracted from a location where it is
+expected, the question of where information can be expected
+needs to be answered.  When dealing with docstrings, the answer is
+fairly simple: the docstring is the first \constant{stmt} node in a code
+block (\constant{file_input} or \constant{suite} node types).  A module
+consists of a single \constant{file_input} node, and class and function
+definitions each contain exactly one \constant{suite} node.  Classes and
+functions are readily identified as subtrees of code block nodes which
+start with \code{(stmt, (compound_stmt, (classdef, ...} or
+\code{(stmt, (compound_stmt, (funcdef, ...}.  Note that these subtrees
+cannot be matched by \function{match()} since it does not support multiple
+sibling nodes to match without regard to number.  A more elaborate
+matching function could be used to overcome this limitation, but this
+is sufficient for the example.
+
+Given the ability to determine whether a statement might be a
+docstring and extract the actual string from the statement, some work
+needs to be performed to walk the parse tree for an entire module and
+extract information about the names defined in each context of the
+module and associate any docstrings with the names.  The code to
+perform this work is not complicated, but bears some explanation.
+
+The public interface to the classes is straightforward and should
+probably be somewhat more flexible.  Each ``major'' block of the
+module is described by an object providing several methods for inquiry
+and a constructor which accepts at least the subtree of the complete
+parse tree which it represents.  The \class{ModuleInfo} constructor
+accepts an optional \var{name} parameter since it cannot
+otherwise determine the name of the module.
+
+The public classes include \class{ClassInfo}, \class{FunctionInfo},
+and \class{ModuleInfo}.  All objects provide the
+methods \method{get_name()}, \method{get_docstring()},
+\method{get_class_names()}, and \method{get_class_info()}.  The
+\class{ClassInfo} objects support \method{get_method_names()} and
+\method{get_method_info()} while the other classes provide
+\method{get_function_names()} and \method{get_function_info()}.
+
+Within each of the forms of code block that the public classes
+represent, most of the required information is in the same form and is
+accessed in the same way, with classes having the distinction that
+functions defined at the top level are referred to as ``methods.''
+Since the difference in nomenclature reflects a real semantic
+distinction from functions defined outside of a class, the
+implementation needs to maintain the distinction.
+Hence, most of the functionality of the public classes can be
+implemented in a common base class, \class{SuiteInfoBase}, with the
+accessors for function and method information provided elsewhere.
+Note that there is only one class which represents function and method
+information; this parallels the use of the \keyword{def} statement to
+define both types of elements.
+
+Most of the accessor functions are declared in \class{SuiteInfoBase}
+and do not need to be overridden by subclasses.  More importantly, the
+extraction of most information from a parse tree is handled through a
+method called by the \class{SuiteInfoBase} constructor.  The example
+code for most of the classes is clear when read alongside the formal
+grammar, but the method which recursively creates new information
+objects requires further examination.  Here is the relevant part of
+the \class{SuiteInfoBase} definition from \file{example.py}:
+
+\begin{verbatim}
+class SuiteInfoBase:
+    _docstring = ''
+    _name = ''
+
+    def __init__(self, tree = None):
+        self._class_info = {}
+        self._function_info = {}
+        if tree:
+            self._extract_info(tree)
+
+    def _extract_info(self, tree):
+        # extract docstring
+        if len(tree) == 2:
+            found, vars = match(DOCSTRING_STMT_PATTERN[1], tree[1])
+        else:
+            found, vars = match(DOCSTRING_STMT_PATTERN, tree[3])
+        if found:
+            self._docstring = eval(vars['docstring'])
+        # discover inner definitions
+        for node in tree[1:]:
+            found, vars = match(COMPOUND_STMT_PATTERN, node)
+            if found:
+                cstmt = vars['compound']
+                if cstmt[0] == symbol.funcdef:
+                    name = cstmt[2][1]
+                    self._function_info[name] = FunctionInfo(cstmt)
+                elif cstmt[0] == symbol.classdef:
+                    name = cstmt[2][1]
+                    self._class_info[name] = ClassInfo(cstmt)
+\end{verbatim}
+
+After initializing some internal state, the constructor calls the
+\method{_extract_info()} method.  This method performs the bulk of the
+information extraction which takes place in the entire example.  The
+extraction has two distinct phases: the location of the docstring for
+the parse tree passed in, and the discovery of additional definitions
+within the code block represented by the parse tree.
+
+The initial \keyword{if} test determines whether the nested suite is of
+the ``short form'' or the ``long form.''  The short form is used when
+the code block is on the same line as the definition of the code
+block, as in
+
+\begin{verbatim}
+def square(x): "Square an argument."; return x ** 2
+\end{verbatim}
+
+while the long form uses an indented block and allows nested
+definitions:
+
+\begin{verbatim}
+def make_power(exp):
+    "Make a function that raises an argument to the exponent `exp'."
+    def raiser(x, y=exp):
+        return x ** y
+    return raiser
+\end{verbatim}
+
+When the short form is used, the code block may contain a docstring as
+the first, and possibly only, \constant{small_stmt} element.  The
+extraction of such a docstring is slightly different and requires only
+a portion of the complete pattern used in the more common case.  As
+implemented, the docstring will only be found if there is only
+one \constant{small_stmt} node in the \constant{simple_stmt} node.
+Since most functions and methods which use the short form do not
+provide a docstring, this may be considered sufficient.  The
+extraction of the docstring proceeds using the \function{match()} function
+as described above, and the value of the docstring is stored as an
+attribute of the \class{SuiteInfoBase} object.
+
+After docstring extraction, a simple definition discovery
+algorithm operates on the \constant{stmt} nodes of the
+\constant{suite} node.  The special case of the short form is not
+tested; since there are no \constant{stmt} nodes in the short form,
+the algorithm will silently skip the single \constant{simple_stmt}
+node and correctly not discover any nested definitions.
+
+Each statement in the code block is categorized as
+a class definition, function or method definition, or
+something else.  For the definition statements, the name of the
+element defined is extracted and a representation object
+appropriate to the definition is created with the defining subtree
+passed as an argument to the constructor.  The representation objects
+are stored in instance variables and may be retrieved by name using
+the appropriate accessor methods.
+
+The public classes provide any accessors required which are more
+specific than those provided by the \class{SuiteInfoBase} class, but
+the real extraction algorithm remains common to all forms of code
+blocks.  A high-level function can be used to extract the complete set
+of information from a source file.  (See file \file{example.py}.)
+
+\begin{verbatim}
+def get_docs(fileName):
+    import os
+    import parser
+
+    source = open(fileName).read()
+    basename = os.path.basename(os.path.splitext(fileName)[0])
+    ast = parser.suite(source)
+    return ModuleInfo(ast.totuple(), basename)
+\end{verbatim}
+
+This provides an easy-to-use interface to the documentation of a
+module.  If information is required which is not extracted by the code
+of this example, the code may be extended at clearly defined points to
+provide additional capabilities.
diff --git a/sys/src/cmd/python/Doc/lib/libpdb.tex b/sys/src/cmd/python/Doc/lib/libpdb.tex
new file mode 100644
index 000000000..b252aeb42
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpdb.tex
@@ -0,0 +1,456 @@
+\chapter{The Python Debugger \label{debugger}}
+
+\declaremodule{standard}{pdb}
+\modulesynopsis{The Python debugger for interactive interpreters.}
+
+
+The module \module{pdb} defines an interactive source code
+debugger\index{debugging} for Python programs.  It supports setting
+(conditional) breakpoints and single stepping at the source line
+level, inspection of stack frames, source code listing, and evaluation
+of arbitrary Python code in the context of any stack frame.  It also
+supports post-mortem debugging and can be called under program
+control.
+
+The debugger is extensible --- it is actually defined as the class
+\class{Pdb}\withsubitem{(class in pdb)}{\ttindex{Pdb}}.
+This is currently undocumented but easily understood by reading the
+source.  The extension interface uses the modules
+\module{bdb}\refstmodindex{bdb} (undocumented) and
+\refmodule{cmd}\refstmodindex{cmd}.
+
+The debugger's prompt is \samp{(Pdb) }.
+Typical usage to run a program under control of the debugger is:
+
+\begin{verbatim}
+>>> import pdb
+>>> import mymodule
+>>> pdb.run('mymodule.test()')
+> (0)?()
+(Pdb) continue
+> (1)?()
+(Pdb) continue
+NameError: 'spam'
+> (1)?()
+(Pdb) 
+\end{verbatim}
+
+\file{pdb.py} can also be invoked as
+a script to debug other scripts.  For example:
+
+\begin{verbatim}
+python -m pdb myscript.py
+\end{verbatim}
+
+When invoked as a script, pdb will automatically enter post-mortem debugging
+if the program being debugged exits abnormally. After post-mortem debugging
+(or after normal exit of the program), pdb will restart the program.
+Automatic restarting preserves pdb's state (such as breakpoints) and in most
+cases is more useful than quitting the debugger upon program's exit.
+\versionadded[Restarting post-mortem behavior added]{2.4}
+
+Typical usage to inspect a crashed program is:
+
+\begin{verbatim}
+>>> import pdb
+>>> import mymodule
+>>> mymodule.test()
+Traceback (most recent call last):
+  File "", line 1, in ?
+  File "./mymodule.py", line 4, in test
+    test2()
+  File "./mymodule.py", line 3, in test2
+    print spam
+NameError: spam
+>>> pdb.pm()
+> ./mymodule.py(3)test2()
+-> print spam
+(Pdb) 
+\end{verbatim}
+
+The module defines the following functions; each enters the debugger
+in a slightly different way:
+
+\begin{funcdesc}{run}{statement\optional{, globals\optional{, locals}}}
+Execute the \var{statement} (given as a string) under debugger
+control.  The debugger prompt appears before any code is executed; you
+can set breakpoints and type \samp{continue}, or you can step through
+the statement using \samp{step} or \samp{next} (all these commands are
+explained below).  The optional \var{globals} and \var{locals}
+arguments specify the environment in which the code is executed; by
+default the dictionary of the module \refmodule[main]{__main__} is
+used.  (See the explanation of the \keyword{exec} statement or the
+\function{eval()} built-in function.)
+\end{funcdesc}
+
+\begin{funcdesc}{runeval}{expression\optional{, globals\optional{, locals}}}
+Evaluate the \var{expression} (given as a string) under debugger
+control.  When \function{runeval()} returns, it returns the value of the
+expression.  Otherwise this function is similar to
+\function{run()}.
+\end{funcdesc}
+
+\begin{funcdesc}{runcall}{function\optional{, argument, ...}}
+Call the \var{function} (a function or method object, not a string)
+with the given arguments.  When \function{runcall()} returns, it returns
+whatever the function call returned.  The debugger prompt appears as
+soon as the function is entered.
+\end{funcdesc}
+
+\begin{funcdesc}{set_trace}{}
+Enter the debugger at the calling stack frame.  This is useful to
+hard-code a breakpoint at a given point in a program, even if the code
+is not otherwise being debugged (e.g. when an assertion fails).
+\end{funcdesc}
+
+\begin{funcdesc}{post_mortem}{traceback}
+Enter post-mortem debugging of the given \var{traceback} object.
+\end{funcdesc}
+
+\begin{funcdesc}{pm}{}
+Enter post-mortem debugging of the traceback found in
+\code{sys.last_traceback}.
+\end{funcdesc}
+
+
+\section{Debugger Commands \label{debugger-commands}}
+
+The debugger recognizes the following commands.  Most commands can be
+abbreviated to one or two letters; e.g. \samp{h(elp)} means that
+either \samp{h} or \samp{help} can be used to enter the help
+command (but not \samp{he} or \samp{hel}, nor \samp{H} or
+\samp{Help} or \samp{HELP}).  Arguments to commands must be
+separated by whitespace (spaces or tabs).  Optional arguments are
+enclosed in square brackets (\samp{[]}) in the command syntax; the
+square brackets must not be typed.  Alternatives in the command syntax
+are separated by a vertical bar (\samp{|}).
+
+Entering a blank line repeats the last command entered.  Exception: if
+the last command was a \samp{list} command, the next 11 lines are
+listed.
+
+Commands that the debugger doesn't recognize are assumed to be Python
+statements and are executed in the context of the program being
+debugged.  Python statements can also be prefixed with an exclamation
+point (\samp{!}).  This is a powerful way to inspect the program
+being debugged; it is even possible to change a variable or call a
+function.  When an
+exception occurs in such a statement, the exception name is printed
+but the debugger's state is not changed.
+
+Multiple commands may be entered on a single line, separated by
+\samp{;;}.  (A single \samp{;} is not used as it is
+the separator for multiple commands in a line that is passed to
+the Python parser.)
+No intelligence is applied to separating the commands;
+the input is split at the first \samp{;;} pair, even if it is in
+the middle of a quoted string.
+
+The debugger supports aliases.  Aliases can have parameters which
+allows one a certain level of adaptability to the context under
+examination.
+
+If a file \file{.pdbrc}
+\indexii{.pdbrc}{file}\indexiii{debugger}{configuration}{file}
+exists in the user's home directory or in the current directory, it is
+read in and executed as if it had been typed at the debugger prompt.
+This is particularly useful for aliases.  If both files exist, the one
+in the home directory is read first and aliases defined there can be
+overridden by the local file.
+
+\begin{description}
+
+\item[h(elp) \optional{\var{command}}]
+
+Without argument, print the list of available commands.  With a
+\var{command} as argument, print help about that command.  \samp{help
+pdb} displays the full documentation file; if the environment variable
+\envvar{PAGER} is defined, the file is piped through that command
+instead.  Since the \var{command} argument must be an identifier,
+\samp{help exec} must be entered to get help on the \samp{!} command.
+
+\item[w(here)]
+
+Print a stack trace, with the most recent frame at the bottom.  An
+arrow indicates the current frame, which determines the context of
+most commands.
+
+\item[d(own)]
+
+Move the current frame one level down in the stack trace
+(to a newer frame).
+
+\item[u(p)]
+
+Move the current frame one level up in the stack trace
+(to an older frame).
+
+\item[b(reak) \optional{\optional{\var{filename}:}\var{lineno}\code{\Large{|}}\var{function}\optional{, \var{condition}}}]
+
+With a \var{lineno} argument, set a break there in the current
+file.  With a \var{function} argument, set a break at the first
+executable statement within that function.
+The line number may be prefixed with a filename and a colon,
+to specify a breakpoint in another file (probably one that
+hasn't been loaded yet).  The file is searched on \code{sys.path}.
+Note that each breakpoint is assigned a number to which all the other
+breakpoint commands refer.
+
+If a second argument is present, it is an expression which must
+evaluate to true before the breakpoint is honored.
+
+Without argument, list all breaks, including for each breakpoint,
+the number of times that breakpoint has been hit, the current
+ignore count, and the associated condition if any.
+
+\item[tbreak \optional{\optional{\var{filename}:}\var{lineno}\code{\Large{|}}\var{function}\optional{, \var{condition}}}]
+
+Temporary breakpoint, which is removed automatically when it is
+first hit.  The arguments are the same as break.
+
+\item[cl(ear) \optional{\var{bpnumber} \optional{\var{bpnumber ...}}}]
+
+With a space separated list of breakpoint numbers, clear those
+breakpoints.  Without argument, clear all breaks (but first
+ask confirmation).
+
+\item[disable \optional{\var{bpnumber} \optional{\var{bpnumber ...}}}]
+
+Disables the breakpoints given as a space separated list of
+breakpoint numbers.  Disabling a breakpoint means it cannot cause
+the program to stop execution, but unlike clearing a breakpoint, it
+remains in the list of breakpoints and can be (re-)enabled.
+
+\item[enable \optional{\var{bpnumber} \optional{\var{bpnumber ...}}}]
+
+Enables the breakpoints specified.
+
+\item[ignore \var{bpnumber} \optional{\var{count}}]
+
+Sets the ignore count for the given breakpoint number.  If
+count is omitted, the ignore count is set to 0.  A breakpoint
+becomes active when the ignore count is zero.  When non-zero,
+the count is decremented each time the breakpoint is reached
+and the breakpoint is not disabled and any associated condition
+evaluates to true.
+
+\item[condition \var{bpnumber} \optional{\var{condition}}]
+
+Condition is an expression which must evaluate to true before
+the breakpoint is honored.  If condition is absent, any existing
+condition is removed; i.e., the breakpoint is made unconditional.
+
+\item[commands \optional{\var{bpnumber}}]
+
+Specify a list of commands for breakpoint number \var{bpnumber}.  The
+commands themselves appear on the following lines.  Type a line
+containing just 'end' to terminate the commands. An example:
+
+\begin{verbatim}
+(Pdb) commands 1
+(com) print some_variable
+(com) end
+(Pdb)
+\end{verbatim}
+
+To remove all commands from a breakpoint, type commands and
+follow it immediately with  end; that is, give no commands.
+
+With no \var{bpnumber} argument, commands refers to the last
+breakpoint set.
+
+You can use breakpoint commands to start your program up again.
+Simply use the continue command, or step, or any other
+command that resumes execution.
+
+Specifying any command resuming execution (currently continue,
+step, next, return, jump, quit and their abbreviations) terminates
+the command list (as if that command was immediately followed by end).
+This is because any time you resume execution
+(even with a simple next or step), you may encounter·
+another breakpoint--which could have its own command list, leading to
+ambiguities about which list to execute.
+
+   If you use the 'silent' command in the command list, the
+usual message about stopping at a breakpoint is not printed.  This may
+be desirable for breakpoints that are to print a specific message and
+then continue.  If none of the other commands print anything, you
+see no sign that the breakpoint was reached.
+
+\versionadded{2.5}
+
+\item[s(tep)]
+
+Execute the current line, stop at the first possible occasion
+(either in a function that is called or on the next line in the
+current function).
+
+\item[n(ext)]
+
+Continue execution until the next line in the current function
+is reached or it returns.  (The difference between \samp{next} and
+\samp{step} is that \samp{step} stops inside a called function, while
+\samp{next} executes called functions at (nearly) full speed, only
+stopping at the next line in the current function.)
+
+\item[r(eturn)]
+
+Continue execution until the current function returns.
+
+\item[c(ont(inue))]
+
+Continue execution, only stop when a breakpoint is encountered.
+
+\item[j(ump) \var{lineno}]
+
+Set the next line that will be executed.  Only available in the
+bottom-most frame.  This lets you jump back and execute code
+again, or jump forward to skip code that you don't want to run.
+
+It should be noted that not all jumps are allowed --- for instance it
+is not possible to jump into the middle of a \keyword{for} loop or out
+of a \keyword{finally} clause.
+
+\item[l(ist) \optional{\var{first}\optional{, \var{last}}}]
+
+List source code for the current file.  Without arguments, list 11
+lines around the current line or continue the previous listing.  With
+one argument, list 11 lines around at that line.  With two arguments,
+list the given range; if the second argument is less than the first,
+it is interpreted as a count.
+
+\item[a(rgs)]
+
+Print the argument list of the current function.
+
+\item[p \var{expression}]
+
+Evaluate the \var{expression} in the current context and print its
+value.  \note{\samp{print} can also be used, but is not a debugger
+command --- this executes the Python \keyword{print} statement.}
+
+\item[pp \var{expression}]
+
+Like the \samp{p} command, except the value of the expression is
+pretty-printed using the \module{pprint} module.
+
+\item[alias \optional{\var{name} \optional{command}}]
+
+Creates an alias called \var{name} that executes \var{command}.  The
+command must \emph{not} be enclosed in quotes.  Replaceable parameters
+can be indicated by \samp{\%1}, \samp{\%2}, and so on, while \samp{\%*} is
+replaced by all the parameters.  If no command is given, the current
+alias for \var{name} is shown. If no arguments are given, all
+aliases are listed.
+
+Aliases may be nested and can contain anything that can be
+legally typed at the pdb prompt.  Note that internal pdb commands
+\emph{can} be overridden by aliases.  Such a command is
+then hidden until the alias is removed.  Aliasing is recursively
+applied to the first word of the command line; all other words
+in the line are left alone.
+
+As an example, here are two useful aliases (especially when placed
+in the \file{.pdbrc} file):
+
+\begin{verbatim}
+#Print instance variables (usage "pi classInst")
+alias pi for k in %1.__dict__.keys(): print "%1.",k,"=",%1.__dict__[k]
+#Print instance variables in self
+alias ps pi self
+\end{verbatim}
+                
+\item[unalias \var{name}]
+
+Deletes the specified alias.
+
+\item[\optional{!}\var{statement}]
+
+Execute the (one-line) \var{statement} in the context of
+the current stack frame.
+The exclamation point can be omitted unless the first word
+of the statement resembles a debugger command.
+To set a global variable, you can prefix the assignment
+command with a \samp{global} command on the same line, e.g.:
+
+\begin{verbatim}
+(Pdb) global list_options; list_options = ['-l']
+(Pdb)
+\end{verbatim}
+
+\item[q(uit)]
+
+Quit from the debugger.
+The program being executed is aborted.
+
+\end{description}
+
+\section{How It Works \label{debugger-hooks}}
+
+Some changes were made to the interpreter:
+
+\begin{itemize}
+\item \code{sys.settrace(\var{func})} sets the global trace function
+\item there can also a local trace function (see later)
+\end{itemize}
+
+Trace functions have three arguments: \var{frame}, \var{event}, and
+\var{arg}. \var{frame} is the current stack frame.  \var{event} is a
+string: \code{'call'}, \code{'line'}, \code{'return'}, \code{'exception'},
+ \code{'c_call'}, \code{'c_return'}, or \code{'c_exception'}. \var{arg}
+ depends on the event type.
+
+The global trace function is invoked (with \var{event} set to
+\code{'call'}) whenever a new local scope is entered; it should return
+a reference to the local trace function to be used that scope, or
+\code{None} if the scope shouldn't be traced.
+
+The local trace function should return a reference to itself (or to
+another function for further tracing in that scope), or \code{None} to
+turn off tracing in that scope.
+
+Instance methods are accepted (and very useful!) as trace functions.
+
+The events have the following meaning:
+
+\begin{description}
+
+\item[\code{'call'}]
+A function is called (or some other code block entered).  The global
+trace function is called; \var{arg} is \code{None};
+the return value specifies the local trace function.
+
+\item[\code{'line'}]
+The interpreter is about to execute a new line of code (sometimes
+multiple line events on one line exist).  The local trace function is
+called; \var{arg} is \code{None}; the return value specifies the new
+local trace function.
+
+\item[\code{'return'}]
+A function (or other code block) is about to return.  The local trace
+function is called; \var{arg} is the value that will be returned.  The
+trace function's return value is ignored.
+
+\item[\code{'exception'}]
+An exception has occurred.  The local trace function is called;
+\var{arg} is a triple \code{(\var{exception}, \var{value},
+\var{traceback})}; the return value specifies the new local trace
+function.
+
+\item[\code{'c_call'}]
+A C function is about to be called.  This may be an extension function
+or a builtin.  \var{arg} is the C function object.
+
+\item[\code{'c_return'}]
+A C function has returned. \var{arg} is \code{None}.
+
+\item[\code{'c_exception'}]
+A C function has thrown an exception.  \var{arg} is \code{None}.
+
+\end{description}
+
+Note that as an exception is propagated down the chain of callers, an
+\code{'exception'} event is generated at each level.
+
+For more information on code and frame objects, refer to the
+\citetitle[../ref/ref.html]{Python Reference Manual}.
diff --git a/sys/src/cmd/python/Doc/lib/libpickle.tex b/sys/src/cmd/python/Doc/lib/libpickle.tex
new file mode 100644
index 000000000..329064123
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpickle.tex
@@ -0,0 +1,888 @@
+\section{\module{pickle} --- Python object serialization}
+
+\declaremodule{standard}{pickle}
+\modulesynopsis{Convert Python objects to streams of bytes and back.}
+% Substantial improvements by Jim Kerr .
+% Rewritten by Barry Warsaw 
+
+\index{persistence}
+\indexii{persistent}{objects}
+\indexii{serializing}{objects}
+\indexii{marshalling}{objects}
+\indexii{flattening}{objects}
+\indexii{pickling}{objects}
+
+The \module{pickle} module implements a fundamental, but powerful
+algorithm for serializing and de-serializing a Python object
+structure.  ``Pickling'' is the process whereby a Python object
+hierarchy is converted into a byte stream, and ``unpickling'' is the
+inverse operation, whereby a byte stream is converted back into an
+object hierarchy.  Pickling (and unpickling) is alternatively known as
+``serialization'', ``marshalling,''\footnote{Don't confuse this with
+the \refmodule{marshal} module} or ``flattening'',
+however, to avoid confusion, the terms used here are ``pickling'' and
+``unpickling''.
+
+This documentation describes both the \module{pickle} module and the 
+\refmodule{cPickle} module.
+
+\subsection{Relationship to other Python modules}
+
+The \module{pickle} module has an optimized cousin called the
+\module{cPickle} module.  As its name implies, \module{cPickle} is
+written in C, so it can be up to 1000 times faster than
+\module{pickle}.  However it does not support subclassing of the
+\function{Pickler()} and \function{Unpickler()} classes, because in
+\module{cPickle} these are functions, not classes.  Most applications
+have no need for this functionality, and can benefit from the improved
+performance of \module{cPickle}.  Other than that, the interfaces of
+the two modules are nearly identical; the common interface is
+described in this manual and differences are pointed out where
+necessary.  In the following discussions, we use the term ``pickle''
+to collectively describe the \module{pickle} and
+\module{cPickle} modules.
+
+The data streams the two modules produce are guaranteed to be
+interchangeable.
+
+Python has a more primitive serialization module called
+\refmodule{marshal}, but in general
+\module{pickle} should always be the preferred way to serialize Python
+objects.  \module{marshal} exists primarily to support Python's
+\file{.pyc} files.
+
+The \module{pickle} module differs from \refmodule{marshal} several
+significant ways:
+
+\begin{itemize}
+
+\item The \module{pickle} module keeps track of the objects it has
+      already serialized, so that later references to the same object
+      won't be serialized again.  \module{marshal} doesn't do this.
+
+      This has implications both for recursive objects and object
+      sharing.  Recursive objects are objects that contain references
+      to themselves.  These are not handled by marshal, and in fact,
+      attempting to marshal recursive objects will crash your Python
+      interpreter.  Object sharing happens when there are multiple
+      references to the same object in different places in the object
+      hierarchy being serialized.  \module{pickle} stores such objects
+      only once, and ensures that all other references point to the
+      master copy.  Shared objects remain shared, which can be very
+      important for mutable objects.
+
+\item \module{marshal} cannot be used to serialize user-defined
+      classes and their instances.  \module{pickle} can save and
+      restore class instances transparently, however the class
+      definition must be importable and live in the same module as
+      when the object was stored.
+
+\item The \module{marshal} serialization format is not guaranteed to
+      be portable across Python versions.  Because its primary job in
+      life is to support \file{.pyc} files, the Python implementers
+      reserve the right to change the serialization format in
+      non-backwards compatible ways should the need arise.  The
+      \module{pickle} serialization format is guaranteed to be
+      backwards compatible across Python releases.
+
+\end{itemize}
+
+\begin{notice}[warning]
+The \module{pickle} module is not intended to be secure against
+erroneous or maliciously constructed data.  Never unpickle data
+received from an untrusted or unauthenticated source.
+\end{notice}
+
+Note that serialization is a more primitive notion than persistence;
+although
+\module{pickle} reads and writes file objects, it does not handle the
+issue of naming persistent objects, nor the (even more complicated)
+issue of concurrent access to persistent objects.  The \module{pickle}
+module can transform a complex object into a byte stream and it can
+transform the byte stream into an object with the same internal
+structure.  Perhaps the most obvious thing to do with these byte
+streams is to write them onto a file, but it is also conceivable to
+send them across a network or store them in a database.  The module
+\refmodule{shelve} provides a simple interface
+to pickle and unpickle objects on DBM-style database files.
+
+\subsection{Data stream format}
+
+The data format used by \module{pickle} is Python-specific.  This has
+the advantage that there are no restrictions imposed by external
+standards such as XDR\index{XDR}\index{External Data Representation}
+(which can't represent pointer sharing); however it means that
+non-Python programs may not be able to reconstruct pickled Python
+objects.
+
+By default, the \module{pickle} data format uses a printable \ASCII{}
+representation.  This is slightly more voluminous than a binary
+representation.  The big advantage of using printable \ASCII{} (and of
+some other characteristics of \module{pickle}'s representation) is that
+for debugging or recovery purposes it is possible for a human to read
+the pickled file with a standard text editor.
+
+There are currently 3 different protocols which can be used for pickling.
+
+\begin{itemize}
+
+\item Protocol version 0 is the original ASCII protocol and is backwards
+compatible with earlier versions of Python.
+
+\item Protocol version 1 is the old binary format which is also compatible
+with earlier versions of Python.
+
+\item Protocol version 2 was introduced in Python 2.3.  It provides
+much more efficient pickling of new-style classes.
+
+\end{itemize}
+
+Refer to PEP 307 for more information.
+
+If a \var{protocol} is not specified, protocol 0 is used.
+If \var{protocol} is specified as a negative value
+or \constant{HIGHEST_PROTOCOL},
+the highest protocol version available will be used.
+
+\versionchanged[Introduced the \var{protocol} parameter]{2.3}
+
+A binary format, which is slightly more efficient, can be chosen by
+specifying a \var{protocol} version >= 1.
+
+\subsection{Usage}
+
+To serialize an object hierarchy, you first create a pickler, then you
+call the pickler's \method{dump()} method.  To de-serialize a data
+stream, you first create an unpickler, then you call the unpickler's
+\method{load()} method.  The \module{pickle} module provides the
+following constant:
+
+\begin{datadesc}{HIGHEST_PROTOCOL}
+The highest protocol version available.  This value can be passed
+as a \var{protocol} value.
+\versionadded{2.3}
+\end{datadesc}
+
+\note{Be sure to always open pickle files created with protocols >= 1 in
+      binary mode. For the old ASCII-based pickle protocol 0 you can use
+      either text mode or binary mode as long as you stay consistent.
+      
+      A pickle file written with protocol 0 in binary mode will contain
+      lone linefeeds as line terminators and therefore will look ``funny''
+      when viewed in Notepad or other editors which do not support this
+      format.}
+
+The \module{pickle} module provides the
+following functions to make the pickling process more convenient:
+
+\begin{funcdesc}{dump}{obj, file\optional{, protocol}}
+Write a pickled representation of \var{obj} to the open file object
+\var{file}.  This is equivalent to
+\code{Pickler(\var{file}, \var{protocol}).dump(\var{obj})}.
+
+If the \var{protocol} parameter is omitted, protocol 0 is used.
+If \var{protocol} is specified as a negative value
+or \constant{HIGHEST_PROTOCOL},
+the highest protocol version will be used.
+
+\versionchanged[Introduced the \var{protocol} parameter]{2.3}
+
+\var{file} must have a \method{write()} method that accepts a single
+string argument.  It can thus be a file object opened for writing, a
+\refmodule{StringIO} object, or any other custom
+object that meets this interface.
+\end{funcdesc}
+
+\begin{funcdesc}{load}{file}
+Read a string from the open file object \var{file} and interpret it as
+a pickle data stream, reconstructing and returning the original object
+hierarchy.  This is equivalent to \code{Unpickler(\var{file}).load()}.
+
+\var{file} must have two methods, a \method{read()} method that takes
+an integer argument, and a \method{readline()} method that requires no
+arguments.  Both methods should return a string.  Thus \var{file} can
+be a file object opened for reading, a
+\module{StringIO} object, or any other custom
+object that meets this interface.
+
+This function automatically determines whether the data stream was
+written in binary mode or not.
+\end{funcdesc}
+
+\begin{funcdesc}{dumps}{obj\optional{, protocol}}
+Return the pickled representation of the object as a string, instead
+of writing it to a file.
+
+If the \var{protocol} parameter is omitted, protocol 0 is used.
+If \var{protocol} is specified as a negative value
+or \constant{HIGHEST_PROTOCOL},
+the highest protocol version will be used.
+
+\versionchanged[The \var{protocol} parameter was added]{2.3}
+
+\end{funcdesc}
+
+\begin{funcdesc}{loads}{string}
+Read a pickled object hierarchy from a string.  Characters in the
+string past the pickled object's representation are ignored.
+\end{funcdesc}
+
+The \module{pickle} module also defines three exceptions:
+
+\begin{excdesc}{PickleError}
+A common base class for the other exceptions defined below.  This
+inherits from \exception{Exception}.
+\end{excdesc}
+
+\begin{excdesc}{PicklingError}
+This exception is raised when an unpicklable object is passed to
+the \method{dump()} method.
+\end{excdesc}
+
+\begin{excdesc}{UnpicklingError}
+This exception is raised when there is a problem unpickling an object.
+Note that other exceptions may also be raised during unpickling,
+including (but not necessarily limited to) \exception{AttributeError},
+\exception{EOFError}, \exception{ImportError}, and \exception{IndexError}.
+\end{excdesc}
+
+The \module{pickle} module also exports two callables\footnote{In the
+\module{pickle} module these callables are classes, which you could
+subclass to customize the behavior.  However, in the \refmodule{cPickle}
+module these callables are factory functions and so cannot be
+subclassed.  One common reason to subclass is to control what
+objects can actually be unpickled.  See section~\ref{pickle-sub} for
+more details.}, \class{Pickler} and \class{Unpickler}:
+
+\begin{classdesc}{Pickler}{file\optional{, protocol}}
+This takes a file-like object to which it will write a pickle data
+stream.  
+
+If the \var{protocol} parameter is omitted, protocol 0 is used.
+If \var{protocol} is specified as a negative value,
+the highest protocol version will be used.
+
+\versionchanged[Introduced the \var{protocol} parameter]{2.3}
+
+\var{file} must have a \method{write()} method that accepts a single
+string argument.  It can thus be an open file object, a
+\module{StringIO} object, or any other custom
+object that meets this interface.
+\end{classdesc}
+
+\class{Pickler} objects define one (or two) public methods:
+
+\begin{methoddesc}[Pickler]{dump}{obj}
+Write a pickled representation of \var{obj} to the open file object
+given in the constructor.  Either the binary or \ASCII{} format will
+be used, depending on the value of the \var{protocol} argument passed to the
+constructor.
+\end{methoddesc}
+
+\begin{methoddesc}[Pickler]{clear_memo}{}
+Clears the pickler's ``memo''.  The memo is the data structure that
+remembers which objects the pickler has already seen, so that shared
+or recursive objects pickled by reference and not by value.  This
+method is useful when re-using picklers.
+
+\begin{notice}
+Prior to Python 2.3, \method{clear_memo()} was only available on the
+picklers created by \refmodule{cPickle}.  In the \module{pickle} module,
+picklers have an instance variable called \member{memo} which is a
+Python dictionary.  So to clear the memo for a \module{pickle} module
+pickler, you could do the following:
+
+\begin{verbatim}
+mypickler.memo.clear()
+\end{verbatim}
+
+Code that does not need to support older versions of Python should
+simply use \method{clear_memo()}.
+\end{notice}
+\end{methoddesc}
+
+It is possible to make multiple calls to the \method{dump()} method of
+the same \class{Pickler} instance.  These must then be matched to the
+same number of calls to the \method{load()} method of the
+corresponding \class{Unpickler} instance.  If the same object is
+pickled by multiple \method{dump()} calls, the \method{load()} will
+all yield references to the same object.\footnote{\emph{Warning}: this
+is intended for pickling multiple objects without intervening
+modifications to the objects or their parts.  If you modify an object
+and then pickle it again using the same \class{Pickler} instance, the
+object is not pickled again --- a reference to it is pickled and the
+\class{Unpickler} will return the old value, not the modified one.
+There are two problems here: (1) detecting changes, and (2)
+marshalling a minimal set of changes.  Garbage Collection may also
+become a problem here.}
+
+\class{Unpickler} objects are defined as:
+
+\begin{classdesc}{Unpickler}{file}
+This takes a file-like object from which it will read a pickle data
+stream.  This class automatically determines whether the data stream
+was written in binary mode or not, so it does not need a flag as in
+the \class{Pickler} factory.
+
+\var{file} must have two methods, a \method{read()} method that takes
+an integer argument, and a \method{readline()} method that requires no
+arguments.  Both methods should return a string.  Thus \var{file} can
+be a file object opened for reading, a
+\module{StringIO} object, or any other custom
+object that meets this interface.
+\end{classdesc}
+
+\class{Unpickler} objects have one (or two) public methods:
+
+\begin{methoddesc}[Unpickler]{load}{}
+Read a pickled object representation from the open file object given
+in the constructor, and return the reconstituted object hierarchy
+specified therein.
+\end{methoddesc}
+
+\begin{methoddesc}[Unpickler]{noload}{}
+This is just like \method{load()} except that it doesn't actually
+create any objects.  This is useful primarily for finding what's
+called ``persistent ids'' that may be referenced in a pickle data
+stream.  See section~\ref{pickle-protocol} below for more details.
+
+\strong{Note:} the \method{noload()} method is currently only
+available on \class{Unpickler} objects created with the
+\module{cPickle} module.  \module{pickle} module \class{Unpickler}s do
+not have the \method{noload()} method.
+\end{methoddesc}
+
+\subsection{What can be pickled and unpickled?}
+
+The following types can be pickled:
+
+\begin{itemize}
+
+\item \code{None}, \code{True}, and \code{False}
+
+\item integers, long integers, floating point numbers, complex numbers
+
+\item normal and Unicode strings
+
+\item tuples, lists, sets, and dictionaries containing only picklable objects
+
+\item functions defined at the top level of a module
+
+\item built-in functions defined at the top level of a module
+
+\item classes that are defined at the top level of a module
+
+\item instances of such classes whose \member{__dict__} or
+\method{__setstate__()} is picklable  (see
+section~\ref{pickle-protocol} for details)
+
+\end{itemize}
+
+Attempts to pickle unpicklable objects will raise the
+\exception{PicklingError} exception; when this happens, an unspecified
+number of bytes may have already been written to the underlying file.
+Trying to pickle a highly recursive data structure may exceed the
+maximum recursion depth, a \exception{RuntimeError} will be raised
+in this case. You can carefully raise this limit with 
+\function{sys.setrecursionlimit()}.
+
+Note that functions (built-in and user-defined) are pickled by ``fully
+qualified'' name reference, not by value.  This means that only the
+function name is pickled, along with the name of module the function
+is defined in.  Neither the function's code, nor any of its function
+attributes are pickled.  Thus the defining module must be importable
+in the unpickling environment, and the module must contain the named
+object, otherwise an exception will be raised.\footnote{The exception
+raised will likely be an \exception{ImportError} or an
+\exception{AttributeError} but it could be something else.}
+
+Similarly, classes are pickled by named reference, so the same
+restrictions in the unpickling environment apply.  Note that none of
+the class's code or data is pickled, so in the following example the
+class attribute \code{attr} is not restored in the unpickling
+environment:
+
+\begin{verbatim}
+class Foo:
+    attr = 'a class attr'
+
+picklestring = pickle.dumps(Foo)
+\end{verbatim}
+
+These restrictions are why picklable functions and classes must be
+defined in the top level of a module.
+
+Similarly, when class instances are pickled, their class's code and
+data are not pickled along with them.  Only the instance data are
+pickled.  This is done on purpose, so you can fix bugs in a class or
+add methods to the class and still load objects that were created with
+an earlier version of the class.  If you plan to have long-lived
+objects that will see many versions of a class, it may be worthwhile
+to put a version number in the objects so that suitable conversions
+can be made by the class's \method{__setstate__()} method.
+
+\subsection{The pickle protocol
+\label{pickle-protocol}}\setindexsubitem{(pickle protocol)}
+
+This section describes the ``pickling protocol'' that defines the
+interface between the pickler/unpickler and the objects that are being
+serialized.  This protocol provides a standard way for you to define,
+customize, and control how your objects are serialized and
+de-serialized.  The description in this section doesn't cover specific
+customizations that you can employ to make the unpickling environment
+slightly safer from untrusted pickle data streams; see section~\ref{pickle-sub}
+for more details.
+
+\subsubsection{Pickling and unpickling normal class
+    instances\label{pickle-inst}}
+
+When a pickled class instance is unpickled, its \method{__init__()}
+method is normally \emph{not} invoked.  If it is desirable that the
+\method{__init__()} method be called on unpickling, an old-style class
+can define a method \method{__getinitargs__()}, which should return a
+\emph{tuple} containing the arguments to be passed to the class
+constructor (\method{__init__()} for example).  The
+\method{__getinitargs__()} method is called at
+pickle time; the tuple it returns is incorporated in the pickle for
+the instance.
+\withsubitem{(copy protocol)}{\ttindex{__getinitargs__()}}
+\withsubitem{(instance constructor)}{\ttindex{__init__()}}
+
+\withsubitem{(copy protocol)}{\ttindex{__getnewargs__()}}
+
+New-style types can provide a \method{__getnewargs__()} method that is
+used for protocol 2.  Implementing this method is needed if the type
+establishes some internal invariants when the instance is created, or
+if the memory allocation is affected by the values passed to the
+\method{__new__()} method for the type (as it is for tuples and
+strings).  Instances of a new-style type \class{C} are created using
+
+\begin{alltt}
+obj = C.__new__(C, *\var{args})
+\end{alltt}
+
+where \var{args} is the result of calling \method{__getnewargs__()} on
+the original object; if there is no \method{__getnewargs__()}, an
+empty tuple is assumed.
+
+\withsubitem{(copy protocol)}{
+  \ttindex{__getstate__()}\ttindex{__setstate__()}}
+\withsubitem{(instance attribute)}{
+  \ttindex{__dict__}}
+
+Classes can further influence how their instances are pickled; if the
+class defines the method \method{__getstate__()}, it is called and the
+return state is pickled as the contents for the instance, instead of
+the contents of the instance's dictionary.  If there is no
+\method{__getstate__()} method, the instance's \member{__dict__} is
+pickled.
+
+Upon unpickling, if the class also defines the method
+\method{__setstate__()}, it is called with the unpickled
+state.\footnote{These methods can also be used to implement copying
+class instances.}  If there is no \method{__setstate__()} method, the
+pickled state must be a dictionary and its items are assigned to the
+new instance's dictionary.  If a class defines both
+\method{__getstate__()} and \method{__setstate__()}, the state object
+needn't be a dictionary and these methods can do what they
+want.\footnote{This protocol is also used by the shallow and deep
+copying operations defined in the
+\refmodule{copy} module.}
+
+\begin{notice}[warning]
+  For new-style classes, if \method{__getstate__()} returns a false
+  value, the \method{__setstate__()} method will not be called.
+\end{notice}
+
+
+\subsubsection{Pickling and unpickling extension types}
+
+When the \class{Pickler} encounters an object of a type it knows
+nothing about --- such as an extension type --- it looks in two places
+for a hint of how to pickle it.  One alternative is for the object to
+implement a \method{__reduce__()} method.  If provided, at pickling
+time \method{__reduce__()} will be called with no arguments, and it
+must return either a string or a tuple.
+
+If a string is returned, it names a global variable whose contents are
+pickled as normal.  The string returned by \method{__reduce__} should
+be the object's local name relative to its module; the pickle module
+searches the module namespace to determine the object's module.
+
+When a tuple is returned, it must be between two and five elements
+long. Optional elements can either be omitted, or \code{None} can be provided 
+as their value.  The semantics of each element are:
+
+\begin{itemize}
+
+\item A callable object that will be called to create the initial
+version of the object.  The next element of the tuple will provide
+arguments for this callable, and later elements provide additional
+state information that will subsequently be used to fully reconstruct
+the pickled data.
+
+In the unpickling environment this object must be either a class, a
+callable registered as a ``safe constructor'' (see below), or it must
+have an attribute \member{__safe_for_unpickling__} with a true value.
+Otherwise, an \exception{UnpicklingError} will be raised in the
+unpickling environment.  Note that as usual, the callable itself is
+pickled by name.
+
+\item A tuple of arguments for the callable object.
+\versionchanged[Formerly, this argument could also be \code{None}]{2.5}
+
+\item Optionally, the object's state, which will be passed to
+      the object's \method{__setstate__()} method as described in
+      section~\ref{pickle-inst}.  If the object has no
+      \method{__setstate__()} method, then, as above, the value must
+      be a dictionary and it will be added to the object's
+      \member{__dict__}.
+
+\item Optionally, an iterator (and not a sequence) yielding successive
+list items.  These list items will be pickled, and appended to the
+object using either \code{obj.append(\var{item})} or
+\code{obj.extend(\var{list_of_items})}.  This is primarily used for
+list subclasses, but may be used by other classes as long as they have
+\method{append()} and \method{extend()} methods with the appropriate
+signature.  (Whether \method{append()} or \method{extend()} is used
+depends on which pickle protocol version is used as well as the number
+of items to append, so both must be supported.)
+
+\item Optionally, an iterator (not a sequence)
+yielding successive dictionary items, which should be tuples of the
+form \code{(\var{key}, \var{value})}.  These items will be pickled
+and stored to the object using \code{obj[\var{key}] = \var{value}}.
+This is primarily used for dictionary subclasses, but may be used by
+other classes as long as they implement \method{__setitem__}.
+
+\end{itemize}
+
+It is sometimes useful to know the protocol version when implementing
+\method{__reduce__}.  This can be done by implementing a method named
+\method{__reduce_ex__} instead of \method{__reduce__}.
+\method{__reduce_ex__}, when it exists, is called in preference over
+\method{__reduce__} (you may still provide \method{__reduce__} for
+backwards compatibility).  The \method{__reduce_ex__} method will be
+called with a single integer argument, the protocol version.
+
+The \class{object} class implements both \method{__reduce__} and
+\method{__reduce_ex__}; however, if a subclass overrides
+\method{__reduce__} but not \method{__reduce_ex__}, the
+\method{__reduce_ex__} implementation detects this and calls
+\method{__reduce__}.
+
+An alternative to implementing a \method{__reduce__()} method on the
+object to be pickled, is to register the callable with the
+\refmodule[copyreg]{copy_reg} module.  This module provides a way
+for programs to register ``reduction functions'' and constructors for
+user-defined types.   Reduction functions have the same semantics and
+interface as the \method{__reduce__()} method described above, except
+that they are called with a single argument, the object to be pickled.
+
+The registered constructor is deemed a ``safe constructor'' for purposes
+of unpickling as described above.
+
+
+\subsubsection{Pickling and unpickling external objects}
+
+For the benefit of object persistence, the \module{pickle} module
+supports the notion of a reference to an object outside the pickled
+data stream.  Such objects are referenced by a ``persistent id'',
+which is just an arbitrary string of printable \ASCII{} characters.
+The resolution of such names is not defined by the \module{pickle}
+module; it will delegate this resolution to user defined functions on
+the pickler and unpickler.\footnote{The actual mechanism for
+associating these user defined functions is slightly different for
+\module{pickle} and \module{cPickle}.  The description given here
+works the same for both implementations.  Users of the \module{pickle}
+module could also use subclassing to effect the same results,
+overriding the \method{persistent_id()} and \method{persistent_load()}
+methods in the derived classes.}
+
+To define external persistent id resolution, you need to set the
+\member{persistent_id} attribute of the pickler object and the
+\member{persistent_load} attribute of the unpickler object.
+
+To pickle objects that have an external persistent id, the pickler
+must have a custom \function{persistent_id()} method that takes an
+object as an argument and returns either \code{None} or the persistent
+id for that object.  When \code{None} is returned, the pickler simply
+pickles the object as normal.  When a persistent id string is
+returned, the pickler will pickle that string, along with a marker
+so that the unpickler will recognize the string as a persistent id.
+
+To unpickle external objects, the unpickler must have a custom
+\function{persistent_load()} function that takes a persistent id
+string and returns the referenced object.
+
+Here's a silly example that \emph{might} shed more light:
+
+\begin{verbatim}
+import pickle
+from cStringIO import StringIO
+
+src = StringIO()
+p = pickle.Pickler(src)
+
+def persistent_id(obj):
+    if hasattr(obj, 'x'):
+        return 'the value %d' % obj.x
+    else:
+        return None
+
+p.persistent_id = persistent_id
+
+class Integer:
+    def __init__(self, x):
+        self.x = x
+    def __str__(self):
+        return 'My name is integer %d' % self.x
+
+i = Integer(7)
+print i
+p.dump(i)
+
+datastream = src.getvalue()
+print repr(datastream)
+dst = StringIO(datastream)
+
+up = pickle.Unpickler(dst)
+
+class FancyInteger(Integer):
+    def __str__(self):
+        return 'I am the integer %d' % self.x
+
+def persistent_load(persid):
+    if persid.startswith('the value '):
+        value = int(persid.split()[2])
+        return FancyInteger(value)
+    else:
+        raise pickle.UnpicklingError, 'Invalid persistent id'
+
+up.persistent_load = persistent_load
+
+j = up.load()
+print j
+\end{verbatim}
+
+In the \module{cPickle} module, the unpickler's
+\member{persistent_load} attribute can also be set to a Python
+list, in which case, when the unpickler reaches a persistent id, the
+persistent id string will simply be appended to this list.  This
+functionality exists so that a pickle data stream can be ``sniffed''
+for object references without actually instantiating all the objects
+in a pickle.\footnote{We'll leave you with the image of Guido and Jim
+sitting around sniffing pickles in their living rooms.}  Setting
+\member{persistent_load} to a list is usually used in conjunction with
+the \method{noload()} method on the Unpickler.
+
+% BAW: Both pickle and cPickle support something called
+% inst_persistent_id() which appears to give unknown types a second
+% shot at producing a persistent id.  Since Jim Fulton can't remember
+% why it was added or what it's for, I'm leaving it undocumented.
+
+\subsection{Subclassing Unpicklers \label{pickle-sub}}
+
+By default, unpickling will import any class that it finds in the
+pickle data.  You can control exactly what gets unpickled and what
+gets called by customizing your unpickler.  Unfortunately, exactly how
+you do this is different depending on whether you're using
+\module{pickle} or \module{cPickle}.\footnote{A word of caution: the
+mechanisms described here use internal attributes and methods, which
+are subject to change in future versions of Python.  We intend to
+someday provide a common interface for controlling this behavior,
+which will work in either \module{pickle} or \module{cPickle}.}
+
+In the \module{pickle} module, you need to derive a subclass from
+\class{Unpickler}, overriding the \method{load_global()}
+method.  \method{load_global()} should read two lines from the pickle
+data stream where the first line will the name of the module
+containing the class and the second line will be the name of the
+instance's class.  It then looks up the class, possibly importing the
+module and digging out the attribute, then it appends what it finds to
+the unpickler's stack.  Later on, this class will be assigned to the
+\member{__class__} attribute of an empty class, as a way of magically
+creating an instance without calling its class's \method{__init__()}.
+Your job (should you choose to accept it), would be to have
+\method{load_global()} push onto the unpickler's stack, a known safe
+version of any class you deem safe to unpickle.  It is up to you to
+produce such a class.  Or you could raise an error if you want to
+disallow all unpickling of instances.  If this sounds like a hack,
+you're right.  Refer to the source code to make this work.
+
+Things are a little cleaner with \module{cPickle}, but not by much.
+To control what gets unpickled, you can set the unpickler's
+\member{find_global} attribute to a function or \code{None}.  If it is
+\code{None} then any attempts to unpickle instances will raise an
+\exception{UnpicklingError}.  If it is a function,
+then it should accept a module name and a class name, and return the
+corresponding class object.  It is responsible for looking up the
+class and performing any necessary imports, and it may raise an
+error to prevent instances of the class from being unpickled.
+
+The moral of the story is that you should be really careful about the
+source of the strings your application unpickles.
+
+\subsection{Example \label{pickle-example}}
+
+For the simplest code, use the \function{dump()} and \function{load()}
+functions.  Note that a self-referencing list is pickled and restored
+correctly.
+
+\begin{verbatim}
+import pickle
+
+data1 = {'a': [1, 2.0, 3, 4+6j],
+         'b': ('string', u'Unicode string'),
+         'c': None}
+
+selfref_list = [1, 2, 3]
+selfref_list.append(selfref_list)
+
+output = open('data.pkl', 'wb')
+
+# Pickle dictionary using protocol 0.
+pickle.dump(data1, output)
+
+# Pickle the list using the highest protocol available.
+pickle.dump(selfref_list, output, -1)
+
+output.close()
+\end{verbatim}
+
+The following example reads the resulting pickled data.  When reading
+a pickle-containing file, you should open the file in binary mode
+because you can't be sure if the ASCII or binary format was used.
+
+\begin{verbatim}
+import pprint, pickle
+
+pkl_file = open('data.pkl', 'rb')
+
+data1 = pickle.load(pkl_file)
+pprint.pprint(data1)
+
+data2 = pickle.load(pkl_file)
+pprint.pprint(data2)
+
+pkl_file.close()
+\end{verbatim}
+
+Here's a larger example that shows how to modify pickling behavior for a
+class.  The \class{TextReader} class opens a text file, and returns
+the line number and line contents each time its \method{readline()}
+method is called. If a \class{TextReader} instance is pickled, all
+attributes \emph{except} the file object member are saved. When the
+instance is unpickled, the file is reopened, and reading resumes from
+the last location. The \method{__setstate__()} and
+\method{__getstate__()} methods are used to implement this behavior.
+
+\begin{verbatim}
+class TextReader:
+    """Print and number lines in a text file."""
+    def __init__(self, file):
+        self.file = file
+        self.fh = open(file)
+        self.lineno = 0
+
+    def readline(self):
+        self.lineno = self.lineno + 1
+        line = self.fh.readline()
+        if not line:
+            return None
+        if line.endswith("\n"):
+            line = line[:-1]
+        return "%d: %s" % (self.lineno, line)
+
+    def __getstate__(self):
+        odict = self.__dict__.copy() # copy the dict since we change it
+        del odict['fh']              # remove filehandle entry
+        return odict
+
+    def __setstate__(self,dict):
+        fh = open(dict['file'])      # reopen file
+        count = dict['lineno']       # read from file...
+        while count:                 # until line count is restored
+            fh.readline()
+            count = count - 1
+        self.__dict__.update(dict)   # update attributes
+        self.fh = fh                 # save the file object
+\end{verbatim}
+
+A sample usage might be something like this:
+
+\begin{verbatim}
+>>> import TextReader
+>>> obj = TextReader.TextReader("TextReader.py")
+>>> obj.readline()
+'1: #!/usr/local/bin/python'
+>>> # (more invocations of obj.readline() here)
+... obj.readline()
+'7: class TextReader:'
+>>> import pickle
+>>> pickle.dump(obj,open('save.p','w'))
+\end{verbatim}
+
+If you want to see that \refmodule{pickle} works across Python
+processes, start another Python session, before continuing.  What
+follows can happen from either the same process or a new process.
+
+\begin{verbatim}
+>>> import pickle
+>>> reader = pickle.load(open('save.p'))
+>>> reader.readline()
+'8:     "Print and number lines in a text file."'
+\end{verbatim}
+
+
+\begin{seealso}
+  \seemodule[copyreg]{copy_reg}{Pickle interface constructor
+                                registration for extension types.}
+
+  \seemodule{shelve}{Indexed databases of objects; uses \module{pickle}.}
+
+  \seemodule{copy}{Shallow and deep object copying.}
+
+  \seemodule{marshal}{High-performance serialization of built-in types.}
+\end{seealso}
+
+
+\section{\module{cPickle} --- A faster \module{pickle}}
+
+\declaremodule{builtin}{cPickle}
+\modulesynopsis{Faster version of \refmodule{pickle}, but not subclassable.}
+\moduleauthor{Jim Fulton}{jim@zope.com}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+The \module{cPickle} module supports serialization and
+de-serialization of Python objects, providing an interface and
+functionality nearly identical to the
+\refmodule{pickle}\refstmodindex{pickle} module.  There are several
+differences, the most important being performance and subclassability.
+
+First, \module{cPickle} can be up to 1000 times faster than
+\module{pickle} because the former is implemented in C.  Second, in
+the \module{cPickle} module the callables \function{Pickler()} and
+\function{Unpickler()} are functions, not classes.  This means that
+you cannot use them to derive custom pickling and unpickling
+subclasses.  Most applications have no need for this functionality and
+should benefit from the greatly improved performance of the
+\module{cPickle} module.
+
+The pickle data stream produced by \module{pickle} and
+\module{cPickle} are identical, so it is possible to use
+\module{pickle} and \module{cPickle} interchangeably with existing
+pickles.\footnote{Since the pickle data format is actually a tiny
+stack-oriented programming language, and some freedom is taken in the
+encodings of certain objects, it is possible that the two modules
+produce different data streams for the same input objects.  However it
+is guaranteed that they will always be able to read each other's
+data streams.}
+
+There are additional minor differences in API between \module{cPickle}
+and \module{pickle}, however for most applications, they are
+interchangeable.  More documentation is provided in the
+\module{pickle} module documentation, which
+includes a list of the documented differences.
+
+
diff --git a/sys/src/cmd/python/Doc/lib/libpickletools.tex b/sys/src/cmd/python/Doc/lib/libpickletools.tex
new file mode 100644
index 000000000..8f6362621
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpickletools.tex
@@ -0,0 +1,34 @@
+\section{\module{pickletools} --- Tools for pickle developers.}
+
+\declaremodule{standard}{pickletools}
+\modulesynopsis{Contains extensive comments about the pickle protocols and pickle-machine opcodes, as well as some useful functions.}
+
+\versionadded{2.3}
+
+This module contains various constants relating to the intimate
+details of the \refmodule{pickle} module, some lengthy comments about
+the implementation, and a few useful functions for analyzing pickled
+data.  The contents of this module are useful for Python core
+developers who are working on the \module{pickle} and \module{cPickle}
+implementations; ordinary users of the \module{pickle} module probably
+won't find the \module{pickletools} module relevant.
+
+\begin{funcdesc}{dis}{pickle\optional{, out=None, memo=None, indentlevel=4}}
+Outputs a symbolic disassembly of the pickle to the file-like object
+\var{out}, defaulting to \code{sys.stdout}.  \var{pickle} can be a
+string or a file-like object.  \var{memo} can be a Python dictionary
+that will be used as the pickle's memo; it can be used to perform
+disassemblies across multiple pickles created by the same pickler.
+Successive levels, indicated by \code{MARK} opcodes in the stream, are
+indented by \var{indentlevel} spaces.
+\end{funcdesc}
+
+\begin{funcdesc}{genops}{pickle}
+Provides an iterator over all of the opcodes in a pickle, returning a
+sequence of \code{(\var{opcode}, \var{arg}, \var{pos})} triples.
+\var{opcode} is an instance of an \class{OpcodeInfo} class; \var{arg} 
+is the decoded value, as a Python object, of the opcode's argument; 
+\var{pos} is the position at which this opcode is located.
+\var{pickle} can be a string or a file-like object.
+\end{funcdesc}
+
diff --git a/sys/src/cmd/python/Doc/lib/libpipes.tex b/sys/src/cmd/python/Doc/lib/libpipes.tex
new file mode 100644
index 000000000..1815e09d5
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpipes.tex
@@ -0,0 +1,84 @@
+\section{\module{pipes} ---
+         Interface to shell pipelines}
+
+\declaremodule{standard}{pipes}
+  \platform{Unix}
+\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il}
+\modulesynopsis{A Python interface to \UNIX\ shell pipelines.}
+
+
+The \module{pipes} module defines a class to abstract the concept of
+a \emph{pipeline} --- a sequence of converters from one file to 
+another.
+
+Because the module uses \program{/bin/sh} command lines, a \POSIX{} or
+compatible shell for \function{os.system()} and \function{os.popen()}
+is required.
+
+The \module{pipes} module defines the following class:
+
+\begin{classdesc}{Template}{}
+An abstraction of a pipeline.
+\end{classdesc}
+
+Example:
+
+\begin{verbatim}
+>>> import pipes
+>>> t=pipes.Template()
+>>> t.append('tr a-z A-Z', '--')
+>>> f=t.open('/tmp/1', 'w')
+>>> f.write('hello world')
+>>> f.close()
+>>> open('/tmp/1').read()
+'HELLO WORLD'
+\end{verbatim}
+
+
+\subsection{Template Objects \label{template-objects}}
+
+Template objects following methods:
+
+\begin{methoddesc}{reset}{}
+Restore a pipeline template to its initial state.
+\end{methoddesc}
+
+\begin{methoddesc}{clone}{}
+Return a new, equivalent, pipeline template.
+\end{methoddesc}
+
+\begin{methoddesc}{debug}{flag}
+If \var{flag} is true, turn debugging on. Otherwise, turn debugging
+off. When debugging is on, commands to be executed are printed, and
+the shell is given \code{set -x} command to be more verbose.
+\end{methoddesc}
+
+\begin{methoddesc}{append}{cmd, kind}
+Append a new action at the end. The \var{cmd} variable must be a valid
+bourne shell command. The \var{kind} variable consists of two letters.
+
+The first letter can be either of \code{'-'} (which means the command
+reads its standard input), \code{'f'} (which means the commands reads
+a given file on the command line) or \code{'.'} (which means the commands
+reads no input, and hence must be first.)
+
+Similarly, the second letter can be either of \code{'-'} (which means 
+the command writes to standard output), \code{'f'} (which means the 
+command writes a file on the command line) or \code{'.'} (which means
+the command does not write anything, and hence must be last.)
+\end{methoddesc}
+
+\begin{methoddesc}{prepend}{cmd, kind}
+Add a new action at the beginning. See \method{append()} for explanations
+of the arguments.
+\end{methoddesc}
+
+\begin{methoddesc}{open}{file, mode}
+Return a file-like object, open to \var{file}, but read from or
+written to by the pipeline.  Note that only one of \code{'r'},
+\code{'w'} may be given.
+\end{methoddesc}
+
+\begin{methoddesc}{copy}{infile, outfile}
+Copy \var{infile} to \var{outfile} through the pipe.
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libpkgutil.tex b/sys/src/cmd/python/Doc/lib/libpkgutil.tex
new file mode 100644
index 000000000..a286f00f2
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpkgutil.tex
@@ -0,0 +1,45 @@
+\section{\module{pkgutil} ---
+         Package extension utility}
+
+\declaremodule{standard}{pkgutil}
+\modulesynopsis{Utilities to support extension of packages.}
+
+\versionadded{2.3}
+
+This module provides a single function:
+
+\begin{funcdesc}{extend_path}{path, name}
+  Extend the search path for the modules which comprise a package.
+  Intended use is to place the following code in a package's
+  \file{__init__.py}:
+
+\begin{verbatim}
+from pkgutil import extend_path
+__path__ = extend_path(__path__, __name__)
+\end{verbatim}
+
+  This will add to the package's \code{__path__} all subdirectories of
+  directories on \code{sys.path} named after the package.  This is
+  useful if one wants to distribute different parts of a single
+  logical package as multiple directories.
+
+  It also looks for \file{*.pkg} files beginning where \code{*}
+  matches the \var{name} argument.  This feature is similar to
+  \file{*.pth} files (see the \refmodule{site} module for more
+  information), except that it doesn't special-case lines starting
+  with \code{import}.  A \file{*.pkg} file is trusted at face value:
+  apart from checking for duplicates, all entries found in a
+  \file{*.pkg} file are added to the path, regardless of whether they
+  exist on the filesystem.  (This is a feature.)
+
+  If the input path is not a list (as is the case for frozen
+  packages) it is returned unchanged.  The input path is not
+  modified; an extended copy is returned.  Items are only appended
+  to the copy at the end.
+
+  It is assumed that \code{sys.path} is a sequence.  Items of
+  \code{sys.path} that are not (Unicode or 8-bit) strings referring to
+  existing directories are ignored.  Unicode items on \code{sys.path}
+  that cause errors when used as filenames may cause this function to
+  raise an exception (in line with \function{os.path.isdir()} behavior).
+\end{funcdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libplatform.tex b/sys/src/cmd/python/Doc/lib/libplatform.tex
new file mode 100644
index 000000000..810e08b63
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libplatform.tex
@@ -0,0 +1,221 @@
+\section{\module{platform} --- 
+   Access to underlying platform's identifying data.}
+
+\declaremodule{standard}{platform}
+\modulesynopsis{Retrieves as much platform identifying data as possible.}
+\moduleauthor{Marc-Andre Lemburg}{mal@egenix.com}
+\sectionauthor{Bjorn Pettersen}{bpettersen@corp.fairisaac.com}
+
+\versionadded{2.3}
+
+\begin{notice}
+  Specific platforms listed alphabetically, with Linux included in the
+  \UNIX{} section.
+\end{notice}
+
+\subsection{Cross Platform}
+
+\begin{funcdesc}{architecture}{executable=sys.executable, bits='', linkage=''}
+  Queries the given executable (defaults to the Python interpreter
+  binary) for various architecture information.
+
+  Returns a tuple \code{(bits, linkage)} which contain information about
+  the bit architecture and the linkage format used for the
+  executable. Both values are returned as strings.
+
+  Values that cannot be determined are returned as given by the
+  parameter presets. If bits is given as \code{''}, the
+  \cfunction{sizeof(pointer)}
+  (or \cfunction{sizeof(long)} on Python version < 1.5.2) is used as
+  indicator for the supported pointer size.
+
+  The function relies on the system's \file{file} command to do the
+  actual work. This is available on most if not all \UNIX{} 
+  platforms and some non-\UNIX{} platforms and then only if the
+  executable points to the Python interpreter.  Reasonable defaults
+  are used when the above needs are not met.
+\end{funcdesc}
+
+\begin{funcdesc}{machine}{}
+  Returns the machine type, e.g. \code{'i386'}.
+  An empty string is returned if the value cannot be determined.
+\end{funcdesc}
+
+\begin{funcdesc}{node}{}
+  Returns the computer's network name (may not be fully qualified!).
+  An empty string is returned if the value cannot be determined.
+\end{funcdesc}
+
+\begin{funcdesc}{platform}{aliased=0, terse=0}
+  Returns a single string identifying the underlying platform
+  with as much useful information as possible.
+
+  The output is intended to be \emph{human readable} rather than
+  machine parseable. It may look different on different platforms and
+  this is intended.
+
+  If \var{aliased} is true, the function will use aliases for various
+  platforms that report system names which differ from their common
+  names, for example SunOS will be reported as Solaris.  The
+  \function{system_alias()} function is used to implement this.
+
+  Setting \var{terse} to true causes the function to return only the
+  absolute minimum information needed to identify the platform.
+\end{funcdesc}
+
+\begin{funcdesc}{processor}{}
+  Returns the (real) processor name, e.g. \code{'amdk6'}.
+
+  An empty string is returned if the value cannot be determined. Note
+  that many platforms do not provide this information or simply return
+  the same value as for \function{machine()}.  NetBSD does this.
+\end{funcdesc}
+
+\begin{funcdesc}{python_build}{}
+  Returns a tuple \code{(\var{buildno}, \var{builddate})} stating the
+  Python build number and date as strings.
+\end{funcdesc}
+
+\begin{funcdesc}{python_compiler}{}
+  Returns a string identifying the compiler used for compiling Python.
+\end{funcdesc}
+
+\begin{funcdesc}{python_version}{}
+  Returns the Python version as string \code{'major.minor.patchlevel'}
+
+  Note that unlike the Python \code{sys.version}, the returned value
+  will always include the patchlevel (it defaults to 0).
+\end{funcdesc}
+
+\begin{funcdesc}{python_version_tuple}{}
+  Returns the Python version as tuple \code{(\var{major}, \var{minor},
+  \var{patchlevel})} of strings.
+
+  Note that unlike the Python \code{sys.version}, the returned value
+  will always include the patchlevel (it defaults to \code{'0'}).
+\end{funcdesc}
+
+\begin{funcdesc}{release}{}
+  Returns the system's release, e.g. \code{'2.2.0'} or \code{'NT'}
+  An empty string is returned if the value cannot be determined.
+\end{funcdesc}
+
+\begin{funcdesc}{system}{}
+  Returns the system/OS name, e.g. \code{'Linux'}, \code{'Windows'},
+  or \code{'Java'}.
+  An empty string is returned if the value cannot be determined.
+\end{funcdesc}
+
+\begin{funcdesc}{system_alias}{system, release, version}
+  Returns \code{(\var{system}, \var{release}, \var{version})} aliased
+  to common marketing names used for some systems.  It also does some
+  reordering of the information in some cases where it would otherwise
+  cause confusion.
+\end{funcdesc}
+
+\begin{funcdesc}{version}{}
+  Returns the system's release version, e.g. \code{'\#3 on degas'}.
+  An empty string is returned if the value cannot be determined.
+\end{funcdesc}
+
+\begin{funcdesc}{uname}{}
+  Fairly portable uname interface. Returns a tuple of strings
+  \code{(\var{system}, \var{node}, \var{release}, \var{version},
+  \var{machine}, \var{processor})} identifying the underlying
+  platform.
+
+  Note that unlike the \function{os.uname()} function this also returns
+  possible processor information as additional tuple entry.
+
+  Entries which cannot be determined are set to \code{''}.
+\end{funcdesc}
+
+
+\subsection{Java Platform}
+
+\begin{funcdesc}{java_ver}{release='', vendor='', vminfo=('','',''),
+                           osinfo=('','','')}
+  Version interface for JPython.
+
+  Returns a tuple \code{(\var{release}, \var{vendor}, \var{vminfo},
+  \var{osinfo})} with \var{vminfo} being a tuple \code{(\var{vm_name},
+  \var{vm_release}, \var{vm_vendor})} and \var{osinfo} being a tuple
+  \code{(\var{os_name}, \var{os_version}, \var{os_arch})}.
+  Values which cannot be determined are set to the defaults
+  given as parameters (which all default to \code{''}).
+\end{funcdesc}
+
+
+\subsection{Windows Platform}
+
+\begin{funcdesc}{win32_ver}{release='', version='', csd='', ptype=''}
+  Get additional version information from the Windows Registry
+  and return a tuple \code{(\var{version}, \var{csd}, \var{ptype})}
+  referring to version number, CSD level and OS type (multi/single
+  processor).
+
+  As a hint: \var{ptype} is \code{'Uniprocessor Free'} on single
+  processor NT machines and \code{'Multiprocessor Free'} on multi
+  processor machines. The \emph{'Free'} refers to the OS version being
+  free of debugging code. It could also state \emph{'Checked'} which
+  means the OS version uses debugging code, i.e. code that
+  checks arguments, ranges, etc.
+
+  \begin{notice}[note]
+    This function only works if Mark Hammond's \module{win32all}
+    package is installed and (obviously) only runs on Win32
+    compatible platforms.
+  \end{notice}
+\end{funcdesc}
+
+\subsubsection{Win95/98 specific}
+
+\begin{funcdesc}{popen}{cmd, mode='r', bufsize=None}
+  Portable \function{popen()} interface.  Find a working popen
+  implementation preferring \function{win32pipe.popen()}.  On Windows
+  NT, \function{win32pipe.popen()} should work; on Windows 9x it hangs
+  due to bugs in the MS C library.
+  % This KnowledgeBase article appears to be missing...
+  %See also \ulink{MS KnowledgeBase article Q150956}{}.
+\end{funcdesc}
+
+
+\subsection{Mac OS Platform}
+
+\begin{funcdesc}{mac_ver}{release='', versioninfo=('','',''), machine=''}
+  Get Mac OS version information and return it as tuple
+  \code{(\var{release}, \var{versioninfo}, \var{machine})} with
+  \var{versioninfo} being a tuple \code{(\var{version},
+  \var{dev_stage}, \var{non_release_version})}.
+
+  Entries which cannot be determined are set to \code{''}.  All tuple
+  entries are strings.
+
+  Documentation for the underlying \cfunction{gestalt()} API is
+  available online at \url{http://www.rgaros.nl/gestalt/}.
+\end{funcdesc}
+
+
+\subsection{\UNIX{} Platforms}
+
+\begin{funcdesc}{dist}{distname='', version='', id='',
+                       supported_dists=('SuSE','debian','redhat','mandrake')}
+  Tries to determine the name of the OS distribution name
+  Returns a tuple \code{(\var{distname}, \var{version}, \var{id})}
+  which defaults to the args given as parameters.
+\end{funcdesc}
+
+
+\begin{funcdesc}{libc_ver}{executable=sys.executable, lib='',
+                           version='', chunksize=2048}
+  Tries to determine the libc version against which the file
+  executable (defaults to the Python interpreter) is linked.  Returns
+  a tuple of strings \code{(\var{lib}, \var{version})} which default
+  to the given parameters in case the lookup fails.
+
+  Note that this function has intimate knowledge of how different
+  libc versions add symbols to the executable is probably only
+  useable for executables compiled using \program{gcc}.
+
+  The file is read and scanned in chunks of \var{chunksize} bytes.
+\end{funcdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libpopen2.tex b/sys/src/cmd/python/Doc/lib/libpopen2.tex
new file mode 100644
index 000000000..e3b157358
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpopen2.tex
@@ -0,0 +1,189 @@
+\section{\module{popen2} ---
+         Subprocesses with accessible I/O streams}
+
+\declaremodule{standard}{popen2}
+\modulesynopsis{Subprocesses with accessible standard I/O streams.}
+\sectionauthor{Drew Csillag}{drew_csillag@geocities.com}
+
+
+This module allows you to spawn processes and connect to their
+input/output/error pipes and obtain their return codes under
+\UNIX{} and Windows.
+
+The \module{subprocess} module provides more powerful facilities for
+spawning new processes and retrieving their results.  Using the
+\module{subprocess} module is preferable to using the \module{popen2}
+module.
+
+The primary interface offered by this module is a trio of factory
+functions.  For each of these, if \var{bufsize} is specified, 
+it specifies the buffer size for the I/O pipes.  \var{mode}, if
+provided, should be the string \code{'b'} or \code{'t'}; on Windows
+this is needed to determine whether the file objects should be opened
+in binary or text mode.  The default value for \var{mode} is
+\code{'t'}.
+
+On \UNIX, \var{cmd} may be a sequence, in which case arguments will be passed
+directly to the program without shell intervention (as with
+\function{os.spawnv()}). If \var{cmd} is a string it will be passed to the
+shell (as with \function{os.system()}).
+
+The only way to retrieve the return codes for the child processes is
+by using the \method{poll()} or \method{wait()} methods on the
+\class{Popen3} and \class{Popen4} classes; these are only available on
+\UNIX.  This information is not available when using the
+\function{popen2()}, \function{popen3()}, and \function{popen4()}
+functions, or the equivalent functions in the \refmodule{os} module.
+(Note that the tuples returned by the \refmodule{os} module's functions
+are in a different order from the ones returned by the \module{popen2}
+module.)
+
+\begin{funcdesc}{popen2}{cmd\optional{, bufsize\optional{, mode}}}
+Executes \var{cmd} as a sub-process.  Returns the file objects
+\code{(\var{child_stdout}, \var{child_stdin})}.
+\end{funcdesc}
+
+\begin{funcdesc}{popen3}{cmd\optional{, bufsize\optional{, mode}}}
+Executes \var{cmd} as a sub-process.  Returns the file objects
+\code{(\var{child_stdout}, \var{child_stdin}, \var{child_stderr})}.
+\end{funcdesc}
+
+\begin{funcdesc}{popen4}{cmd\optional{, bufsize\optional{, mode}}}
+Executes \var{cmd} as a sub-process.  Returns the file objects
+\code{(\var{child_stdout_and_stderr}, \var{child_stdin})}.
+\versionadded{2.0}
+\end{funcdesc}
+
+
+On \UNIX, a class defining the objects returned by the factory
+functions is also available.  These are not used for the Windows
+implementation, and are not available on that platform.
+
+\begin{classdesc}{Popen3}{cmd\optional{, capturestderr\optional{, bufsize}}}
+This class represents a child process.  Normally, \class{Popen3}
+instances are created using the \function{popen2()} and
+\function{popen3()} factory functions described above.
+
+If not using one of the helper functions to create \class{Popen3}
+objects, the parameter \var{cmd} is the shell command to execute in a
+sub-process.  The \var{capturestderr} flag, if true, specifies that
+the object should capture standard error output of the child process.
+The default is false.  If the \var{bufsize} parameter is specified, it
+specifies the size of the I/O buffers to/from the child process.
+\end{classdesc}
+
+\begin{classdesc}{Popen4}{cmd\optional{, bufsize}}
+Similar to \class{Popen3}, but always captures standard error into the
+same file object as standard output.  These are typically created
+using \function{popen4()}.
+\versionadded{2.0}
+\end{classdesc}
+
+\subsection{Popen3 and Popen4 Objects \label{popen3-objects}}
+
+Instances of the \class{Popen3} and \class{Popen4} classes have the
+following methods:
+
+\begin{methoddesc}{poll}{}
+Returns \code{-1} if child process hasn't completed yet, or its return 
+code otherwise.
+\end{methoddesc}
+
+\begin{methoddesc}{wait}{}
+Waits for and returns the status code of the child process.  The
+status code encodes both the return code of the process and
+information about whether it exited using the \cfunction{exit()}
+system call or died due to a signal.  Functions to help interpret the
+status code are defined in the \refmodule{os} module; see section
+\ref{os-process} for the \function{W\var{*}()} family of functions.
+\end{methoddesc}
+
+
+The following attributes are also available: 
+
+\begin{memberdesc}{fromchild}
+A file object that provides output from the child process.  For
+\class{Popen4} instances, this will provide both the standard output
+and standard error streams.
+\end{memberdesc}
+
+\begin{memberdesc}{tochild}
+A file object that provides input to the child process.
+\end{memberdesc}
+
+\begin{memberdesc}{childerr}
+A file object that provides error output from the child process, if
+\var{capturestderr} was true for the constructor, otherwise
+\code{None}.  This will always be \code{None} for \class{Popen4}
+instances.
+\end{memberdesc}
+
+\begin{memberdesc}{pid}
+The process ID of the child process.
+\end{memberdesc}
+
+
+\subsection{Flow Control Issues \label{popen2-flow-control}}
+
+Any time you are working with any form of inter-process communication,
+control flow needs to be carefully thought out.  This remains the case
+with the file objects provided by this module (or the \refmodule{os}
+module equivalents).
+
+% Example explanation and suggested work-arounds substantially stolen
+% from Martin von Löwis:
+% http://mail.python.org/pipermail/python-dev/2000-September/009460.html
+
+When reading output from a child process that writes a lot of data to
+standard error while the parent is reading from the child's standard
+output, a deadlock can occur.  A similar situation can occur with other
+combinations of reads and writes.  The essential factors are that more
+than \constant{_PC_PIPE_BUF} bytes are being written by one process in
+a blocking fashion, while the other process is reading from the other
+process, also in a blocking fashion.
+
+There are several ways to deal with this situation.
+
+The simplest application change, in many cases, will be to follow this
+model in the parent process:
+
+\begin{verbatim}
+import popen2
+
+r, w, e = popen2.popen3('python slave.py')
+e.readlines()
+r.readlines()
+r.close()
+e.close()
+w.close()
+\end{verbatim}
+
+with code like this in the child:
+
+\begin{verbatim}
+import os
+import sys
+
+# note that each of these print statements
+# writes a single long string
+
+print >>sys.stderr, 400 * 'this is a test\n'
+os.close(sys.stderr.fileno())
+print >>sys.stdout, 400 * 'this is another test\n'
+\end{verbatim}
+
+In particular, note that \code{sys.stderr} must be closed after
+writing all data, or \method{readlines()} won't return.  Also note
+that \function{os.close()} must be used, as \code{sys.stderr.close()}
+won't close \code{stderr} (otherwise assigning to \code{sys.stderr}
+will silently close it, so no further errors can be printed).
+
+Applications which need to support a more general approach should
+integrate I/O over pipes with their \function{select()} loops, or use
+separate threads to read each of the individual files provided by
+whichever \function{popen*()} function or \class{Popen*} class was
+used.
+
+\begin{seealso}
+  \seemodule{subprocess}{Module for spawning and managing subprocesses.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libpoplib.tex b/sys/src/cmd/python/Doc/lib/libpoplib.tex
new file mode 100644
index 000000000..25570ae72
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpoplib.tex
@@ -0,0 +1,181 @@
+\section{\module{poplib} ---
+         POP3 protocol client}
+
+\declaremodule{standard}{poplib}
+\modulesynopsis{POP3 protocol client (requires sockets).}
+
+%By Andrew T. Csillag
+%Even though I put it into LaTeX, I cannot really claim that I wrote
+%it since I just stole most of it from the poplib.py source code and
+%the imaplib ``chapter''.
+%Revised by ESR, January 2000
+
+\indexii{POP3}{protocol}
+
+This module defines a class, \class{POP3}, which encapsulates a
+connection to a POP3 server and implements the protocol as defined in
+\rfc{1725}.  The \class{POP3} class supports both the minimal and
+optional command sets. Additionally, this module provides a class
+\class{POP3_SSL}, which provides support for connecting to POP3
+servers that use SSL as an underlying protocol layer.
+
+
+Note that POP3, though widely supported, is obsolescent.  The
+implementation quality of POP3 servers varies widely, and too many are
+quite poor. If your mailserver supports IMAP, you would be better off
+using the \code{\refmodule{imaplib}.\class{IMAP4}} class, as IMAP
+servers tend to be better implemented.
+
+A single class is provided by the \module{poplib} module:
+
+\begin{classdesc}{POP3}{host\optional{, port}}
+This class implements the actual POP3 protocol.  The connection is
+created when the instance is initialized.
+If \var{port} is omitted, the standard POP3 port (110) is used.
+\end{classdesc}
+
+\begin{classdesc}{POP3_SSL}{host\optional{, port\optional{, keyfile\optional{, certfile}}}}
+This is a subclass of \class{POP3} that connects to the server over an
+SSL encrypted socket.  If \var{port} is not specified, 995, the
+standard POP3-over-SSL port is used.  \var{keyfile} and \var{certfile}
+are also optional - they can contain a PEM formatted private key and
+certificate chain file for the SSL connection.
+
+\versionadded{2.4}
+\end{classdesc}
+
+One exception is defined as an attribute of the \module{poplib} module:
+
+\begin{excdesc}{error_proto}
+Exception raised on any errors.  The reason for the exception is
+passed to the constructor as a string.
+\end{excdesc}
+
+\begin{seealso}
+  \seemodule{imaplib}{The standard Python IMAP module.}
+  \seetitle[http://www.catb.org/\~{}esr/fetchmail/fetchmail-FAQ.html]
+        {Frequently Asked Questions About Fetchmail}
+        {The FAQ for the \program{fetchmail} POP/IMAP client collects
+         information on POP3 server variations and RFC noncompliance
+         that may be useful if you need to write an application based
+         on the POP protocol.}
+\end{seealso}
+
+
+\subsection{POP3 Objects \label{pop3-objects}}
+
+All POP3 commands are represented by methods of the same name,
+in lower-case; most return the response text sent by the server.
+
+An \class{POP3} instance has the following methods:
+
+
+\begin{methoddesc}{set_debuglevel}{level}
+Set the instance's debugging level.  This controls the amount of
+debugging output printed.  The default, \code{0}, produces no
+debugging output.  A value of \code{1} produces a moderate amount of
+debugging output, generally a single line per request.  A value of
+\code{2} or higher produces the maximum amount of debugging output,
+logging each line sent and received on the control connection.
+\end{methoddesc}
+
+\begin{methoddesc}{getwelcome}{}
+Returns the greeting string sent by the POP3 server.
+\end{methoddesc}
+
+\begin{methoddesc}{user}{username}
+Send user command, response should indicate that a password is required.
+\end{methoddesc}
+
+\begin{methoddesc}{pass_}{password}
+Send password, response includes message count and mailbox size.
+Note: the mailbox on the server is locked until \method{quit()} is
+called.
+\end{methoddesc}
+
+\begin{methoddesc}{apop}{user, secret}
+Use the more secure APOP authentication to log into the POP3 server.
+\end{methoddesc}
+
+\begin{methoddesc}{rpop}{user}
+Use RPOP authentication (similar to UNIX r-commands) to log into POP3 server.
+\end{methoddesc}
+
+\begin{methoddesc}{stat}{}
+Get mailbox status.  The result is a tuple of 2 integers:
+\code{(\var{message count}, \var{mailbox size})}.
+\end{methoddesc}
+
+\begin{methoddesc}{list}{\optional{which}}
+Request message list, result is in the form
+\code{(\var{response}, ['mesg_num octets', ...], \var{octets})}.
+If \var{which} is set, it is the message to list.
+\end{methoddesc}
+
+\begin{methoddesc}{retr}{which}
+Retrieve whole message number \var{which}, and set its seen flag.
+Result is in form  \code{(\var{response}, ['line', ...], \var{octets})}.
+\end{methoddesc}
+
+\begin{methoddesc}{dele}{which}
+Flag message number \var{which} for deletion.  On most servers
+deletions are not actually performed until QUIT (the major exception is
+Eudora QPOP, which deliberately violates the RFCs by doing pending
+deletes on any disconnect).
+\end{methoddesc}
+
+\begin{methoddesc}{rset}{}
+Remove any deletion marks for the mailbox.
+\end{methoddesc}
+
+\begin{methoddesc}{noop}{}
+Do nothing.  Might be used as a keep-alive.
+\end{methoddesc}
+
+\begin{methoddesc}{quit}{}
+Signoff:  commit changes, unlock mailbox, drop connection.
+\end{methoddesc}
+
+\begin{methoddesc}{top}{which, howmuch}
+Retrieves the message header plus \var{howmuch} lines of the message
+after the header of message number \var{which}. Result is in form
+\code{(\var{response}, ['line', ...], \var{octets})}.
+
+The POP3 TOP command this method uses, unlike the RETR command,
+doesn't set the message's seen flag; unfortunately, TOP is poorly
+specified in the RFCs and is frequently broken in off-brand servers.
+Test this method by hand against the POP3 servers you will use before
+trusting it.
+\end{methoddesc}
+
+\begin{methoddesc}{uidl}{\optional{which}}
+Return message digest (unique id) list.
+If \var{which} is specified, result contains the unique id for that
+message in the form \code{'\var{response}\ \var{mesgnum}\ \var{uid}},
+otherwise result is list \code{(\var{response}, ['mesgnum uid', ...],
+\var{octets})}.
+\end{methoddesc}
+
+Instances of \class{POP3_SSL} have no additional methods. The
+interface of this subclass is identical to its parent.
+
+
+\subsection{POP3 Example \label{pop3-example}}
+
+Here is a minimal example (without error checking) that opens a
+mailbox and retrieves and prints all messages:
+
+\begin{verbatim}
+import getpass, poplib
+
+M = poplib.POP3('localhost')
+M.user(getpass.getuser())
+M.pass_(getpass.getpass())
+numMessages = len(M.list()[1])
+for i in range(numMessages):
+    for j in M.retr(i+1)[1]:
+        print j
+\end{verbatim}
+
+At the end of the module, there is a test section that contains a more
+extensive example of usage.
diff --git a/sys/src/cmd/python/Doc/lib/libposix.tex b/sys/src/cmd/python/Doc/lib/libposix.tex
new file mode 100644
index 000000000..aee6c0db3
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libposix.tex
@@ -0,0 +1,97 @@
+\section{\module{posix} ---
+         The most common \POSIX{} system calls}
+
+\declaremodule{builtin}{posix}
+  \platform{Unix}
+\modulesynopsis{The most common \POSIX\ system calls (normally used
+                via module \refmodule{os}).}
+
+
+This module provides access to operating system functionality that is
+standardized by the C Standard and the \POSIX{} standard (a thinly
+disguised \UNIX{} interface).
+
+\strong{Do not import this module directly.}  Instead, import the
+module \refmodule{os}, which provides a \emph{portable} version of this
+interface.  On \UNIX, the \refmodule{os} module provides a superset of
+the \module{posix} interface.  On non-\UNIX{} operating systems the
+\module{posix} module is not available, but a subset is always
+available through the \refmodule{os} interface.  Once \refmodule{os} is
+imported, there is \emph{no} performance penalty in using it instead
+of \module{posix}.  In addition, \refmodule{os}\refstmodindex{os}
+provides some additional functionality, such as automatically calling
+\function{putenv()} when an entry in \code{os.environ} is changed.
+
+The descriptions below are very terse; refer to the corresponding
+\UNIX{} manual (or \POSIX{} documentation) entry for more information.
+Arguments called \var{path} refer to a pathname given as a string.
+
+Errors are reported as exceptions; the usual exceptions are given for
+type errors, while errors reported by the system calls raise
+\exception{error} (a synonym for the standard exception
+\exception{OSError}), described below.
+
+
+\subsection{Large File Support \label{posix-large-files}}
+\sectionauthor{Steve Clift}{clift@mail.anacapa.net}
+\index{large files}
+\index{file!large files}
+
+
+Several operating systems (including AIX, HPUX, Irix and Solaris)
+provide support for files that are larger than 2 Gb from a C
+programming model where \ctype{int} and \ctype{long} are 32-bit
+values. This is typically accomplished by defining the relevant size
+and offset types as 64-bit values. Such files are sometimes referred
+to as \dfn{large files}.
+
+Large file support is enabled in Python when the size of an
+\ctype{off_t} is larger than a \ctype{long} and the \ctype{long long}
+type is available and is at least as large as an \ctype{off_t}. Python
+longs are then used to represent file sizes, offsets and other values
+that can exceed the range of a Python int. It may be necessary to
+configure and compile Python with certain compiler flags to enable
+this mode. For example, it is enabled by default with recent versions
+of Irix, but with Solaris 2.6 and 2.7 you need to do something like:
+
+\begin{verbatim}
+CFLAGS="`getconf LFS_CFLAGS`" OPT="-g -O2 $CFLAGS" \
+        ./configure
+\end{verbatim} % $ <-- bow to font-lock
+
+On large-file-capable Linux systems, this might work:
+
+\begin{verbatim}
+CFLAGS='-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64' OPT="-g -O2 $CFLAGS" \
+        ./configure
+\end{verbatim} % $ <-- bow to font-lock
+
+
+\subsection{Module Contents \label{posix-contents}}
+
+
+Module \module{posix} defines the following data item:
+
+\begin{datadesc}{environ}
+A dictionary representing the string environment at the time the
+interpreter was started. For example, \code{environ['HOME']} is the
+pathname of your home directory, equivalent to
+\code{getenv("HOME")} in C.
+
+Modifying this dictionary does not affect the string environment
+passed on by \function{execv()}, \function{popen()} or
+\function{system()}; if you need to change the environment, pass
+\code{environ} to \function{execve()} or add variable assignments and
+export statements to the command string for \function{system()} or
+\function{popen()}.
+
+\note{The \refmodule{os} module provides an alternate
+implementation of \code{environ} which updates the environment on
+modification.  Note also that updating \code{os.environ} will render
+this dictionary obsolete.  Use of the \refmodule{os} module version of
+this is recommended over direct access to the \module{posix} module.}
+\end{datadesc}
+
+Additional contents of this module should only be accessed via the
+\refmodule{os} module; refer to the documentation for that module for
+further information.
diff --git a/sys/src/cmd/python/Doc/lib/libposixfile.tex b/sys/src/cmd/python/Doc/lib/libposixfile.tex
new file mode 100644
index 000000000..62861f02d
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libposixfile.tex
@@ -0,0 +1,175 @@
+% Manual text and implementation by Jaap Vermeulen
+\section{\module{posixfile} ---
+         File-like objects with locking support}
+
+\declaremodule{builtin}{posixfile}
+  \platform{Unix}
+\modulesynopsis{A file-like object with support for locking.}
+\moduleauthor{Jaap Vermeulen}{}
+\sectionauthor{Jaap Vermeulen}{}
+
+
+\indexii{\POSIX}{file object}
+
+\deprecated{1.5}{The locking operation that this module provides is
+done better and more portably by the
+\function{\refmodule{fcntl}.lockf()} call.
+\withsubitem{(in module fcntl)}{\ttindex{lockf()}}}
+
+This module implements some additional functionality over the built-in
+file objects.  In particular, it implements file locking, control over
+the file flags, and an easy interface to duplicate the file object.
+The module defines a new file object, the posixfile object.  It
+has all the standard file object methods and adds the methods
+described below.  This module only works for certain flavors of
+\UNIX, since it uses \function{fcntl.fcntl()} for file locking.%
+\withsubitem{(in module fcntl)}{\ttindex{fcntl()}}
+
+To instantiate a posixfile object, use the \function{open()} function
+in the \module{posixfile} module.  The resulting object looks and
+feels roughly the same as a standard file object.
+
+The \module{posixfile} module defines the following constants:
+
+
+\begin{datadesc}{SEEK_SET}
+Offset is calculated from the start of the file.
+\end{datadesc}
+
+\begin{datadesc}{SEEK_CUR}
+Offset is calculated from the current position in the file.
+\end{datadesc}
+
+\begin{datadesc}{SEEK_END}
+Offset is calculated from the end of the file.
+\end{datadesc}
+
+The \module{posixfile} module defines the following functions:
+
+
+\begin{funcdesc}{open}{filename\optional{, mode\optional{, bufsize}}}
+ Create a new posixfile object with the given filename and mode.  The
+ \var{filename}, \var{mode} and \var{bufsize} arguments are
+ interpreted the same way as by the built-in \function{open()}
+ function.
+\end{funcdesc}
+
+\begin{funcdesc}{fileopen}{fileobject}
+ Create a new posixfile object with the given standard file object.
+ The resulting object has the same filename and mode as the original
+ file object.
+\end{funcdesc}
+
+The posixfile object defines the following additional methods:
+
+\setindexsubitem{(posixfile method)}
+\begin{funcdesc}{lock}{fmt, \optional{len\optional{, start\optional{, whence}}}}
+ Lock the specified section of the file that the file object is
+ referring to.  The format is explained
+ below in a table.  The \var{len} argument specifies the length of the
+ section that should be locked. The default is \code{0}. \var{start}
+ specifies the starting offset of the section, where the default is
+ \code{0}.  The \var{whence} argument specifies where the offset is
+ relative to. It accepts one of the constants \constant{SEEK_SET},
+ \constant{SEEK_CUR} or \constant{SEEK_END}.  The default is
+ \constant{SEEK_SET}.  For more information about the arguments refer
+ to the \manpage{fcntl}{2} manual page on your system.
+\end{funcdesc}
+
+\begin{funcdesc}{flags}{\optional{flags}}
+ Set the specified flags for the file that the file object is referring
+ to.  The new flags are ORed with the old flags, unless specified
+ otherwise.  The format is explained below in a table.  Without
+ the \var{flags} argument
+ a string indicating the current flags is returned (this is
+ the same as the \samp{?} modifier).  For more information about the
+ flags refer to the \manpage{fcntl}{2} manual page on your system.
+\end{funcdesc}
+
+\begin{funcdesc}{dup}{}
+ Duplicate the file object and the underlying file pointer and file
+ descriptor.  The resulting object behaves as if it were newly
+ opened.
+\end{funcdesc}
+
+\begin{funcdesc}{dup2}{fd}
+ Duplicate the file object and the underlying file pointer and file
+ descriptor.  The new object will have the given file descriptor.
+ Otherwise the resulting object behaves as if it were newly opened.
+\end{funcdesc}
+
+\begin{funcdesc}{file}{}
+ Return the standard file object that the posixfile object is based
+ on.  This is sometimes necessary for functions that insist on a
+ standard file object.
+\end{funcdesc}
+
+All methods raise \exception{IOError} when the request fails.
+
+Format characters for the \method{lock()} method have the following
+meaning:
+
+\begin{tableii}{c|l}{samp}{Format}{Meaning}
+  \lineii{u}{unlock the specified region}
+  \lineii{r}{request a read lock for the specified section}
+  \lineii{w}{request a write lock for the specified section}
+\end{tableii}
+
+In addition the following modifiers can be added to the format:
+
+\begin{tableiii}{c|l|c}{samp}{Modifier}{Meaning}{Notes}
+  \lineiii{|}{wait until the lock has been granted}{}
+  \lineiii{?}{return the first lock conflicting with the requested lock, or
+              \code{None} if there is no conflict.}{(1)} 
+\end{tableiii}
+
+\noindent
+Note:
+
+\begin{description}
+\item[(1)] The lock returned is in the format \code{(\var{mode}, \var{len},
+\var{start}, \var{whence}, \var{pid})} where \var{mode} is a character
+representing the type of lock ('r' or 'w').  This modifier prevents a
+request from being granted; it is for query purposes only.
+\end{description}
+
+Format characters for the \method{flags()} method have the following
+meanings:
+
+\begin{tableii}{c|l}{samp}{Format}{Meaning}
+  \lineii{a}{append only flag}
+  \lineii{c}{close on exec flag}
+  \lineii{n}{no delay flag (also called non-blocking flag)}
+  \lineii{s}{synchronization flag}
+\end{tableii}
+
+In addition the following modifiers can be added to the format:
+
+\begin{tableiii}{c|l|c}{samp}{Modifier}{Meaning}{Notes}
+  \lineiii{!}{turn the specified flags 'off', instead of the default 'on'}{(1)}
+  \lineiii{=}{replace the flags, instead of the default 'OR' operation}{(1)}
+  \lineiii{?}{return a string in which the characters represent the flags that
+  are set.}{(2)}
+\end{tableiii}
+
+\noindent
+Notes:
+
+\begin{description}
+\item[(1)] The \samp{!} and \samp{=} modifiers are mutually exclusive.
+
+\item[(2)] This string represents the flags after they may have been altered
+by the same call.
+\end{description}
+
+Examples:
+
+\begin{verbatim}
+import posixfile
+
+file = posixfile.open('/tmp/test', 'w')
+file.lock('w|')
+...
+file.lock('u')
+file.close()
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libposixpath.tex b/sys/src/cmd/python/Doc/lib/libposixpath.tex
new file mode 100644
index 000000000..0b2da66a0
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libposixpath.tex
@@ -0,0 +1,281 @@
+\section{\module{os.path} ---
+         Common pathname manipulations}
+\declaremodule{standard}{os.path}
+
+\modulesynopsis{Common pathname manipulations.}
+
+This module implements some useful functions on pathnames.
+\index{path!operations}
+
+\warning{On Windows, many of these functions do not properly
+support UNC pathnames.  \function{splitunc()} and \function{ismount()}
+do handle them correctly.}
+
+
+\begin{funcdesc}{abspath}{path}
+Return a normalized absolutized version of the pathname \var{path}.
+On most platforms, this is equivalent to
+\code{normpath(join(os.getcwd(), \var{path}))}.
+\versionadded{1.5.2}
+\end{funcdesc}
+
+\begin{funcdesc}{basename}{path}
+Return the base name of pathname \var{path}.  This is the second half
+of the pair returned by \code{split(\var{path})}.  Note that the
+result of this function is different from the
+\UNIX{} \program{basename} program; where \program{basename} for
+\code{'/foo/bar/'} returns \code{'bar'}, the \function{basename()}
+function returns an empty string (\code{''}).
+\end{funcdesc}
+
+\begin{funcdesc}{commonprefix}{list}
+Return the longest path prefix (taken character-by-character) that is a
+prefix of all paths in 
+\var{list}.  If \var{list} is empty, return the empty string
+(\code{''}).  Note that this may return invalid paths because it works a
+character at a time.
+\end{funcdesc}
+
+\begin{funcdesc}{dirname}{path}
+Return the directory name of pathname \var{path}.  This is the first
+half of the pair returned by \code{split(\var{path})}.
+\end{funcdesc}
+
+\begin{funcdesc}{exists}{path}
+Return \code{True} if \var{path} refers to an existing path.  Returns
+\code{False} for broken symbolic links. On some platforms, this
+function may return \code{False} if permission is not granted to
+execute \function{os.stat()} on the requested file, even if the
+\var{path} physically exists.
+\end{funcdesc}
+
+\begin{funcdesc}{lexists}{path}
+Return \code{True} if \var{path} refers to an existing path.
+Returns \code{True} for broken symbolic links.  
+Equivalent to \function{exists()} on platforms lacking
+\function{os.lstat()}.
+\versionadded{2.4}
+\end{funcdesc}
+
+\begin{funcdesc}{expanduser}{path}
+On \UNIX, return the argument with an initial component of \samp{\~} or
+\samp{\~\var{user}} replaced by that \var{user}'s home directory.
+An initial \samp{\~} is replaced by the environment variable
+\envvar{HOME} if it is set; otherwise the current user's home directory
+is looked up in the password directory through the built-in module
+\refmodule{pwd}\refbimodindex{pwd}.
+An initial \samp{\~\var{user}} is looked up directly in the
+password directory.
+
+On Windows, only \samp{\~} is supported; it is replaced by the
+environment variable \envvar{HOME} or by a combination of
+\envvar{HOMEDRIVE} and \envvar{HOMEPATH}.
+
+If the expansion fails or if the
+path does not begin with a tilde, the path is returned unchanged.
+\end{funcdesc}
+
+\begin{funcdesc}{expandvars}{path}
+Return the argument with environment variables expanded.  Substrings
+of the form \samp{\$\var{name}} or \samp{\$\{\var{name}\}} are
+replaced by the value of environment variable \var{name}.  Malformed
+variable names and references to non-existing variables are left
+unchanged.
+\end{funcdesc}
+
+\begin{funcdesc}{getatime}{path}
+Return the time of last access of \var{path}.  The return
+value is a number giving the number of seconds since the epoch (see the 
+\refmodule{time} module).  Raise \exception{os.error} if the file does
+not exist or is inaccessible.
+\versionadded{1.5.2}
+\versionchanged[If \function{os.stat_float_times()} returns True, the result is a floating point number]{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{getmtime}{path}
+Return the time of last modification of \var{path}.  The return
+value is a number giving the number of seconds since the epoch (see the 
+\refmodule{time} module).  Raise \exception{os.error} if the file does
+not exist or is inaccessible.
+\versionadded{1.5.2}
+\versionchanged[If \function{os.stat_float_times()} returns True, the result is a floating point number]{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{getctime}{path}
+Return the system's ctime which, on some systems (like \UNIX) is the
+time of the last change, and, on others (like Windows), is the
+creation time for \var{path}.  The return
+value is a number giving the number of seconds since the epoch (see the 
+\refmodule{time} module).  Raise \exception{os.error} if the file does
+not exist or is inaccessible.
+\versionadded{2.3}
+\end{funcdesc}
+
+\begin{funcdesc}{getsize}{path}
+Return the size, in bytes, of \var{path}.  Raise
+\exception{os.error} if the file does not exist or is inaccessible.
+\versionadded{1.5.2}
+\end{funcdesc}
+
+\begin{funcdesc}{isabs}{path}
+Return \code{True} if \var{path} is an absolute pathname (begins with a
+slash).
+\end{funcdesc}
+
+\begin{funcdesc}{isfile}{path}
+Return \code{True} if \var{path} is an existing regular file.  This follows
+symbolic links, so both \function{islink()} and \function{isfile()}
+can be true for the same path.
+\end{funcdesc}
+
+\begin{funcdesc}{isdir}{path}
+Return \code{True} if \var{path} is an existing directory.  This follows
+symbolic links, so both \function{islink()} and \function{isdir()} can
+be true for the same path.
+\end{funcdesc}
+
+\begin{funcdesc}{islink}{path}
+Return \code{True} if \var{path} refers to a directory entry that is a
+symbolic link.  Always \code{False} if symbolic links are not supported.
+\end{funcdesc}
+
+\begin{funcdesc}{ismount}{path}
+Return \code{True} if pathname \var{path} is a \dfn{mount point}: a point in
+a file system where a different file system has been mounted.  The
+function checks whether \var{path}'s parent, \file{\var{path}/..}, is
+on a different device than \var{path}, or whether \file{\var{path}/..}
+and \var{path} point to the same i-node on the same device --- this
+should detect mount points for all \UNIX{} and \POSIX{} variants.
+\end{funcdesc}
+
+\begin{funcdesc}{join}{path1\optional{, path2\optional{, ...}}}
+Join one or more path components intelligently.  If any component is
+an absolute path, all previous components (on Windows, including the
+previous drive letter, if there was one) are thrown away, and joining
+continues.  The return value is the concatenation of \var{path1}, and
+optionally \var{path2}, etc., with exactly one directory separator
+(\code{os.sep}) inserted between components, unless \var{path2} is
+empty.  Note that on Windows, since there is a current directory for
+each drive, \function{os.path.join("c:", "foo")} represents a path
+relative to the current directory on drive \file{C:} (\file{c:foo}), not
+\file{c:\textbackslash\textbackslash foo}.
+\end{funcdesc}
+
+\begin{funcdesc}{normcase}{path}
+Normalize the case of a pathname.  On \UNIX, this returns the path
+unchanged; on case-insensitive filesystems, it converts the path to
+lowercase.  On Windows, it also converts forward slashes to backward
+slashes.
+\end{funcdesc}
+
+\begin{funcdesc}{normpath}{path}
+Normalize a pathname.  This collapses redundant separators and
+up-level references so that \code{A//B}, \code{A/./B} and
+\code{A/foo/../B} all become \code{A/B}.  It does not normalize the
+case (use \function{normcase()} for that).  On Windows, it converts
+forward slashes to backward slashes. It should be understood that this may
+change the meaning of the path if it contains symbolic links! 
+\end{funcdesc}
+
+\begin{funcdesc}{realpath}{path}
+Return the canonical path of the specified filename, eliminating any
+symbolic links encountered in the path (if they are supported by the
+operating system).
+\versionadded{2.2}
+\end{funcdesc}
+
+\begin{funcdesc}{samefile}{path1, path2}
+Return \code{True} if both pathname arguments refer to the same file or
+directory (as indicated by device number and i-node number).
+Raise an exception if a \function{os.stat()} call on either pathname
+fails.
+Availability:  Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{sameopenfile}{fp1, fp2}
+Return \code{True} if the file descriptors \var{fp1} and \var{fp2} refer
+to the same file.
+Availability:  Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{samestat}{stat1, stat2}
+Return \code{True} if the stat tuples \var{stat1} and \var{stat2} refer to
+the same file.  These structures may have been returned by
+\function{fstat()}, \function{lstat()}, or \function{stat()}.  This
+function implements the underlying comparison used by
+\function{samefile()} and \function{sameopenfile()}.
+Availability:  Macintosh, \UNIX.
+\end{funcdesc}
+
+\begin{funcdesc}{split}{path}
+Split the pathname \var{path} into a pair, \code{(\var{head},
+\var{tail})} where \var{tail} is the last pathname component and
+\var{head} is everything leading up to that.  The \var{tail} part will
+never contain a slash; if \var{path} ends in a slash, \var{tail} will
+be empty.  If there is no slash in \var{path}, \var{head} will be
+empty.  If \var{path} is empty, both \var{head} and \var{tail} are
+empty.  Trailing slashes are stripped from \var{head} unless it is the
+root (one or more slashes only).  In nearly all cases,
+\code{join(\var{head}, \var{tail})} equals \var{path} (the only
+exception being when there were multiple slashes separating \var{head}
+from \var{tail}).
+\end{funcdesc}
+
+\begin{funcdesc}{splitdrive}{path}
+Split the pathname \var{path} into a pair \code{(\var{drive},
+\var{tail})} where \var{drive} is either a drive specification or the
+empty string.  On systems which do not use drive specifications,
+\var{drive} will always be the empty string.  In all cases,
+\code{\var{drive} + \var{tail}} will be the same as \var{path}.
+\versionadded{1.3}
+\end{funcdesc}
+
+\begin{funcdesc}{splitext}{path}
+Split the pathname \var{path} into a pair \code{(\var{root}, \var{ext})} 
+such that \code{\var{root} + \var{ext} == \var{path}},
+and \var{ext} is empty or begins with a period and contains
+at most one period.
+\end{funcdesc}
+
+\begin{funcdesc}{splitunc}{path}
+Split the pathname \var{path} into a pair \code{(\var{unc}, \var{rest})}
+so that \var{unc} is the UNC mount point (such as \code{r'\e\e host\e mount'}),
+if present, and \var{rest} the rest of the path (such as 
+\code{r'\e path\e file.ext'}).  For paths containing drive letters, \var{unc}
+will always be the empty string.
+Availability:  Windows.
+\end{funcdesc}
+
+\begin{funcdesc}{walk}{path, visit, arg}
+Calls the function \var{visit} with arguments
+\code{(\var{arg}, \var{dirname}, \var{names})} for each directory in the
+directory tree rooted at \var{path} (including \var{path} itself, if it
+is a directory).  The argument \var{dirname} specifies the visited
+directory, the argument \var{names} lists the files in the directory
+(gotten from \code{os.listdir(\var{dirname})}).
+The \var{visit} function may modify \var{names} to
+influence the set of directories visited below \var{dirname}, e.g. to
+avoid visiting certain parts of the tree.  (The object referred to by
+\var{names} must be modified in place, using \keyword{del} or slice
+assignment.)
+
+\begin{notice}
+Symbolic links to directories are not treated as subdirectories, and
+that \function{walk()} therefore will not visit them. To visit linked
+directories you must identify them with
+\code{os.path.islink(\var{file})} and
+\code{os.path.isdir(\var{file})}, and invoke \function{walk()} as
+necessary.
+\end{notice}
+
+\note{The newer \function{\refmodule{os}.walk()} generator supplies
+      similar functionality and can be easier to use.}
+\end{funcdesc}
+
+\begin{datadesc}{supports_unicode_filenames}
+True if arbitrary Unicode strings can be used as file names (within
+limitations imposed by the file system), and if
+\function{os.listdir()} returns Unicode strings for a Unicode
+argument.
+\versionadded{2.3}
+\end{datadesc}
diff --git a/sys/src/cmd/python/Doc/lib/libpprint.tex b/sys/src/cmd/python/Doc/lib/libpprint.tex
new file mode 100644
index 000000000..fd030389b
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpprint.tex
@@ -0,0 +1,210 @@
+\section{\module{pprint} ---
+         Data pretty printer}
+
+\declaremodule{standard}{pprint}
+\modulesynopsis{Data pretty printer.}
+\moduleauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+
+The \module{pprint} module provides a capability to ``pretty-print''
+arbitrary Python data structures in a form which can be used as input
+to the interpreter.  If the formatted structures include objects which
+are not fundamental Python types, the representation may not be
+loadable.  This may be the case if objects such as files, sockets,
+classes, or instances are included, as well as many other builtin
+objects which are not representable as Python constants.
+
+The formatted representation keeps objects on a single line if it can,
+and breaks them onto multiple lines if they don't fit within the
+allowed width.  Construct \class{PrettyPrinter} objects explicitly if
+you need to adjust the width constraint.
+
+\versionchanged[Dictionaries are sorted by key before the display is
+computed; before 2.5, a dictionary was sorted only if its display
+required more than one line, although that wasn't documented]{2.5}
+
+The \module{pprint} module defines one class:
+
+
+% First the implementation class:
+
+\begin{classdesc}{PrettyPrinter}{...}
+Construct a \class{PrettyPrinter} instance.  This constructor
+understands several keyword parameters.  An output stream may be set
+using the \var{stream} keyword; the only method used on the stream
+object is the file protocol's \method{write()} method.  If not
+specified, the \class{PrettyPrinter} adopts \code{sys.stdout}.  Three
+additional parameters may be used to control the formatted
+representation.  The keywords are \var{indent}, \var{depth}, and
+\var{width}.  The amount of indentation added for each recursive level
+is specified by \var{indent}; the default is one.  Other values can
+cause output to look a little odd, but can make nesting easier to
+spot.  The number of levels which may be printed is controlled by
+\var{depth}; if the data structure being printed is too deep, the next
+contained level is replaced by \samp{...}.  By default, there is no
+constraint on the depth of the objects being formatted.  The desired
+output width is constrained using the \var{width} parameter; the
+default is eighty characters.  If a structure cannot be formatted
+within the constrained width, a best effort will be made.
+
+\begin{verbatim}
+>>> import pprint, sys
+>>> stuff = sys.path[:]
+>>> stuff.insert(0, stuff[:])
+>>> pp = pprint.PrettyPrinter(indent=4)
+>>> pp.pprint(stuff)
+[   [   '',
+        '/usr/local/lib/python1.5',
+        '/usr/local/lib/python1.5/test',
+        '/usr/local/lib/python1.5/sunos5',
+        '/usr/local/lib/python1.5/sharedmodules',
+        '/usr/local/lib/python1.5/tkinter'],
+    '',
+    '/usr/local/lib/python1.5',
+    '/usr/local/lib/python1.5/test',
+    '/usr/local/lib/python1.5/sunos5',
+    '/usr/local/lib/python1.5/sharedmodules',
+    '/usr/local/lib/python1.5/tkinter']
+>>>
+>>> import parser
+>>> tup = parser.ast2tuple(
+...     parser.suite(open('pprint.py').read()))[1][1][1]
+>>> pp = pprint.PrettyPrinter(depth=6)
+>>> pp.pprint(tup)
+(266, (267, (307, (287, (288, (...))))))
+\end{verbatim}
+\end{classdesc}
+
+
+% Now the derivative functions:
+
+The \class{PrettyPrinter} class supports several derivative functions:
+
+\begin{funcdesc}{pformat}{object\optional{, indent\optional{,
+width\optional{, depth}}}}
+Return the formatted representation of \var{object} as a string.  \var{indent},
+\var{width} and \var{depth} will be passed to the \class{PrettyPrinter}
+constructor as formatting parameters.
+\versionchanged[The parameters \var{indent}, \var{width} and \var{depth}
+were added]{2.4}
+\end{funcdesc}
+
+\begin{funcdesc}{pprint}{object\optional{, stream\optional{,
+indent\optional{, width\optional{, depth}}}}}
+Prints the formatted representation of \var{object} on \var{stream},
+followed by a newline.  If \var{stream} is omitted, \code{sys.stdout}
+is used.  This may be used in the interactive interpreter instead of a
+\keyword{print} statement for inspecting values.    \var{indent},
+\var{width} and \var{depth} will be passed to the \class{PrettyPrinter}
+constructor as formatting parameters.
+
+\begin{verbatim}
+>>> stuff = sys.path[:]
+>>> stuff.insert(0, stuff)
+>>> pprint.pprint(stuff)
+[,
+ '',
+ '/usr/local/lib/python1.5',
+ '/usr/local/lib/python1.5/test',
+ '/usr/local/lib/python1.5/sunos5',
+ '/usr/local/lib/python1.5/sharedmodules',
+ '/usr/local/lib/python1.5/tkinter']
+\end{verbatim}
+\versionchanged[The parameters \var{indent}, \var{width} and \var{depth}
+were added]{2.4}
+\end{funcdesc}
+
+\begin{funcdesc}{isreadable}{object}
+Determine if the formatted representation of \var{object} is
+``readable,'' or can be used to reconstruct the value using
+\function{eval()}\bifuncindex{eval}.  This always returns false for
+recursive objects.
+
+\begin{verbatim}
+>>> pprint.isreadable(stuff)
+False
+\end{verbatim}
+\end{funcdesc}
+
+\begin{funcdesc}{isrecursive}{object}
+Determine if \var{object} requires a recursive representation.
+\end{funcdesc}
+
+
+One more support function is also defined:
+
+\begin{funcdesc}{saferepr}{object}
+Return a string representation of \var{object}, protected against
+recursive data structures.  If the representation of \var{object}
+exposes a recursive entry, the recursive reference will be represented
+as \samp{}.  The
+representation is not otherwise formatted.
+\end{funcdesc}
+
+% This example is outside the {funcdesc} to keep it from running over
+% the right margin.
+\begin{verbatim}
+>>> pprint.saferepr(stuff)
+"[, '', '/usr/local/lib/python1.5', '/usr/loca
+l/lib/python1.5/test', '/usr/local/lib/python1.5/sunos5', '/usr/local/lib/python
+1.5/sharedmodules', '/usr/local/lib/python1.5/tkinter']"
+\end{verbatim}
+
+
+\subsection{PrettyPrinter Objects}
+\label{PrettyPrinter Objects}
+
+\class{PrettyPrinter} instances have the following methods:
+
+
+\begin{methoddesc}{pformat}{object}
+Return the formatted representation of \var{object}.  This takes into
+account the options passed to the \class{PrettyPrinter} constructor.
+\end{methoddesc}
+
+\begin{methoddesc}{pprint}{object}
+Print the formatted representation of \var{object} on the configured
+stream, followed by a newline.
+\end{methoddesc}
+
+The following methods provide the implementations for the
+corresponding functions of the same names.  Using these methods on an
+instance is slightly more efficient since new \class{PrettyPrinter}
+objects don't need to be created.
+
+\begin{methoddesc}{isreadable}{object}
+Determine if the formatted representation of the object is
+``readable,'' or can be used to reconstruct the value using
+\function{eval()}\bifuncindex{eval}.  Note that this returns false for
+recursive objects.  If the \var{depth} parameter of the
+\class{PrettyPrinter} is set and the object is deeper than allowed,
+this returns false.
+\end{methoddesc}
+
+\begin{methoddesc}{isrecursive}{object}
+Determine if the object requires a recursive representation.
+\end{methoddesc}
+
+This method is provided as a hook to allow subclasses to modify the
+way objects are converted to strings.  The default implementation uses
+the internals of the \function{saferepr()} implementation.
+
+\begin{methoddesc}{format}{object, context, maxlevels, level}
+Returns three values: the formatted version of \var{object} as a
+string, a flag indicating whether the result is readable, and a flag
+indicating whether recursion was detected.  The first argument is the
+object to be presented.  The second is a dictionary which contains the
+\function{id()} of objects that are part of the current presentation
+context (direct and indirect containers for \var{object} that are
+affecting the presentation) as the keys; if an object needs to be
+presented which is already represented in \var{context}, the third
+return value should be true.  Recursive calls to the \method{format()}
+method should add additional entries for containers to this
+dictionary.  The third argument, \var{maxlevels}, gives the requested
+limit to recursion; this will be \code{0} if there is no requested
+limit.  This argument should be passed unmodified to recursive calls.
+The fourth argument, \var{level}, gives the current level; recursive
+calls should be passed a value less than that of the current call.
+\versionadded{2.3}
+\end{methoddesc}
diff --git a/sys/src/cmd/python/Doc/lib/libprofile.tex b/sys/src/cmd/python/Doc/lib/libprofile.tex
new file mode 100644
index 000000000..179b39698
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libprofile.tex
@@ -0,0 +1,722 @@
+\chapter{The Python Profilers \label{profile}}
+
+\sectionauthor{James Roskind}{}
+
+Copyright \copyright{} 1994, by InfoSeek Corporation, all rights reserved.
+\index{InfoSeek Corporation}
+
+Written by James Roskind.\footnote{
+  Updated and converted to \LaTeX\ by Guido van Rossum.
+  Further updated by Armin Rigo to integrate the documentation for the new
+  \module{cProfile} module of Python 2.5.}
+
+Permission to use, copy, modify, and distribute this Python software
+and its associated documentation for any purpose (subject to the
+restriction in the following sentence) without fee is hereby granted,
+provided that the above copyright notice appears in all copies, and
+that both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of InfoSeek not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.  This permission is
+explicitly restricted to the copying and modification of the software
+to remain in Python, compiled Python, or other languages (such as C)
+wherein the modified or derived code is exclusively imported into a
+Python module.
+
+INFOSEEK CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL INFOSEEK CORPORATION BE LIABLE FOR ANY
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+
+The profiler was written after only programming in Python for 3 weeks.
+As a result, it is probably clumsy code, but I don't know for sure yet
+'cause I'm a beginner :-).  I did work hard to make the code run fast,
+so that profiling would be a reasonable thing to do.  I tried not to
+repeat code fragments, but I'm sure I did some stuff in really awkward
+ways at times.  Please send suggestions for improvements to:
+\email{jar@netscape.com}.  I won't promise \emph{any} support.  ...but
+I'd appreciate the feedback.
+
+
+\section{Introduction to the profilers}
+\nodename{Profiler Introduction}
+
+A \dfn{profiler} is a program that describes the run time performance
+of a program, providing a variety of statistics.  This documentation
+describes the profiler functionality provided in the modules
+\module{profile} and \module{pstats}.  This profiler provides
+\dfn{deterministic profiling} of any Python programs.  It also
+provides a series of report generation tools to allow users to rapidly
+examine the results of a profile operation.
+\index{deterministic profiling}
+\index{profiling, deterministic}
+
+The Python standard library provides three different profilers:
+
+\begin{enumerate}
+\item \module{profile}, a pure Python module, described in the sequel.
+  Copyright \copyright{} 1994, by InfoSeek Corporation.
+  \versionchanged[also reports the time spent in calls to built-in
+  functions and methods]{2.4}
+
+\item \module{cProfile}, a module written in C, with a reasonable
+  overhead that makes it suitable for profiling long-running programs.
+  Based on \module{lsprof}, contributed by Brett Rosen and Ted Czotter.
+  \versionadded{2.5}
+
+\item \module{hotshot}, a C module focusing on minimizing the overhead
+  while profiling, at the expense of long data post-processing times.
+  \versionchanged[the results should be more meaningful than in the
+  past: the timing core contained a critical bug]{2.5}
+\end{enumerate}
+
+The \module{profile} and \module{cProfile} modules export the same
+interface, so they are mostly interchangeables; \module{cProfile} has a
+much lower overhead but is not so far as well-tested and might not be
+available on all systems.  \module{cProfile} is really a compatibility
+layer on top of the internal \module{_lsprof} module.  The
+\module{hotshot} module is reserved to specialized usages.
+
+%\section{How Is This Profiler Different From The Old Profiler?}
+%\nodename{Profiler Changes}
+%
+%(This section is of historical importance only; the old profiler
+%discussed here was last seen in Python 1.1.)
+%
+%The big changes from old profiling module are that you get more
+%information, and you pay less CPU time.  It's not a trade-off, it's a
+%trade-up.
+%
+%To be specific:
+%
+%\begin{description}
+%
+%\item[Bugs removed:]
+%Local stack frame is no longer molested, execution time is now charged
+%to correct functions.
+%
+%\item[Accuracy increased:]
+%Profiler execution time is no longer charged to user's code,
+%calibration for platform is supported, file reads are not done \emph{by}
+%profiler \emph{during} profiling (and charged to user's code!).
+%
+%\item[Speed increased:]
+%Overhead CPU cost was reduced by more than a factor of two (perhaps a
+%factor of five), lightweight profiler module is all that must be
+%loaded, and the report generating module (\module{pstats}) is not needed
+%during profiling.
+%
+%\item[Recursive functions support:]
+%Cumulative times in recursive functions are correctly calculated;
+%recursive entries are counted.
+%
+%\item[Large growth in report generating UI:]
+%Distinct profiles runs can be added together forming a comprehensive
+%report; functions that import statistics take arbitrary lists of
+%files; sorting criteria is now based on keywords (instead of 4 integer
+%options); reports shows what functions were profiled as well as what
+%profile file was referenced; output format has been improved.
+%
+%\end{description}
+
+
+\section{Instant User's Manual \label{profile-instant}}
+
+This section is provided for users that ``don't want to read the
+manual.'' It provides a very brief overview, and allows a user to
+rapidly perform profiling on an existing application.
+
+To profile an application with a main entry point of \function{foo()},
+you would add the following to your module:
+
+\begin{verbatim}
+import cProfile
+cProfile.run('foo()')
+\end{verbatim}
+
+(Use \module{profile} instead of \module{cProfile} if the latter is not
+available on your system.)
+
+The above action would cause \function{foo()} to be run, and a series of
+informative lines (the profile) to be printed.  The above approach is
+most useful when working with the interpreter.  If you would like to
+save the results of a profile into a file for later examination, you
+can supply a file name as the second argument to the \function{run()}
+function:
+
+\begin{verbatim}
+import cProfile
+cProfile.run('foo()', 'fooprof')
+\end{verbatim}
+
+The file \file{cProfile.py} can also be invoked as
+a script to profile another script.  For example:
+
+\begin{verbatim}
+python -m cProfile myscript.py
+\end{verbatim}
+
+\file{cProfile.py} accepts two optional arguments on the command line:
+
+\begin{verbatim}
+cProfile.py [-o output_file] [-s sort_order]
+\end{verbatim}
+
+\programopt{-s} only applies to standard output (\programopt{-o} is
+not supplied).  Look in the \class{Stats} documentation for valid sort
+values.
+
+When you wish to review the profile, you should use the methods in the
+\module{pstats} module.  Typically you would load the statistics data as
+follows:
+
+\begin{verbatim}
+import pstats
+p = pstats.Stats('fooprof')
+\end{verbatim}
+
+The class \class{Stats} (the above code just created an instance of
+this class) has a variety of methods for manipulating and printing the
+data that was just read into \code{p}.  When you ran
+\function{cProfile.run()} above, what was printed was the result of three
+method calls:
+
+\begin{verbatim}
+p.strip_dirs().sort_stats(-1).print_stats()
+\end{verbatim}
+
+The first method removed the extraneous path from all the module
+names. The second method sorted all the entries according to the
+standard module/line/name string that is printed.
+%(this is to comply with the semantics of the old profiler).
+The third method printed out
+all the statistics.  You might try the following sort calls:
+
+\begin{verbatim}
+p.sort_stats('name')
+p.print_stats()
+\end{verbatim}
+
+The first call will actually sort the list by function name, and the
+second call will print out the statistics.  The following are some
+interesting calls to experiment with:
+
+\begin{verbatim}
+p.sort_stats('cumulative').print_stats(10)
+\end{verbatim}
+
+This sorts the profile by cumulative time in a function, and then only
+prints the ten most significant lines.  If you want to understand what
+algorithms are taking time, the above line is what you would use.
+
+If you were looking to see what functions were looping a lot, and
+taking a lot of time, you would do:
+
+\begin{verbatim}
+p.sort_stats('time').print_stats(10)
+\end{verbatim}
+
+to sort according to time spent within each function, and then print
+the statistics for the top ten functions.
+
+You might also try:
+
+\begin{verbatim}
+p.sort_stats('file').print_stats('__init__')
+\end{verbatim}
+
+This will sort all the statistics by file name, and then print out
+statistics for only the class init methods (since they are spelled
+with \code{__init__} in them).  As one final example, you could try:
+
+\begin{verbatim}
+p.sort_stats('time', 'cum').print_stats(.5, 'init')
+\end{verbatim}
+
+This line sorts statistics with a primary key of time, and a secondary
+key of cumulative time, and then prints out some of the statistics.
+To be specific, the list is first culled down to 50\% (re: \samp{.5})
+of its original size, then only lines containing \code{init} are
+maintained, and that sub-sub-list is printed.
+
+If you wondered what functions called the above functions, you could
+now (\code{p} is still sorted according to the last criteria) do:
+
+\begin{verbatim}
+p.print_callers(.5, 'init')
+\end{verbatim}
+
+and you would get a list of callers for each of the listed functions.
+
+If you want more functionality, you're going to have to read the
+manual, or guess what the following functions do:
+
+\begin{verbatim}
+p.print_callees()
+p.add('fooprof')
+\end{verbatim}
+
+Invoked as a script, the \module{pstats} module is a statistics
+browser for reading and examining profile dumps.  It has a simple
+line-oriented interface (implemented using \refmodule{cmd}) and
+interactive help.
+
+\section{What Is Deterministic Profiling?}
+\nodename{Deterministic Profiling}
+
+\dfn{Deterministic profiling} is meant to reflect the fact that all
+\emph{function call}, \emph{function return}, and \emph{exception} events
+are monitored, and precise timings are made for the intervals between
+these events (during which time the user's code is executing).  In
+contrast, \dfn{statistical profiling} (which is not done by this
+module) randomly samples the effective instruction pointer, and
+deduces where time is being spent.  The latter technique traditionally
+involves less overhead (as the code does not need to be instrumented),
+but provides only relative indications of where time is being spent.
+
+In Python, since there is an interpreter active during execution, the
+presence of instrumented code is not required to do deterministic
+profiling.  Python automatically provides a \dfn{hook} (optional
+callback) for each event.  In addition, the interpreted nature of
+Python tends to add so much overhead to execution, that deterministic
+profiling tends to only add small processing overhead in typical
+applications.  The result is that deterministic profiling is not that
+expensive, yet provides extensive run time statistics about the
+execution of a Python program.
+
+Call count statistics can be used to identify bugs in code (surprising
+counts), and to identify possible inline-expansion points (high call
+counts).  Internal time statistics can be used to identify ``hot
+loops'' that should be carefully optimized.  Cumulative time
+statistics should be used to identify high level errors in the
+selection of algorithms.  Note that the unusual handling of cumulative
+times in this profiler allows statistics for recursive implementations
+of algorithms to be directly compared to iterative implementations.
+
+
+\section{Reference Manual -- \module{profile} and \module{cProfile}}
+
+\declaremodule{standard}{profile}
+\declaremodule{standard}{cProfile}
+\modulesynopsis{Python profiler}
+
+
+
+The primary entry point for the profiler is the global function
+\function{profile.run()} (resp. \function{cProfile.run()}).
+It is typically used to create any profile
+information.  The reports are formatted and printed using methods of
+the class \class{pstats.Stats}.  The following is a description of all
+of these standard entry points and functions.  For a more in-depth
+view of some of the code, consider reading the later section on
+Profiler Extensions, which includes discussion of how to derive
+``better'' profilers from the classes presented, or reading the source
+code for these modules.
+
+\begin{funcdesc}{run}{command\optional{, filename}}
+
+This function takes a single argument that can be passed to the
+\keyword{exec} statement, and an optional file name.  In all cases this
+routine attempts to \keyword{exec} its first argument, and gather profiling
+statistics from the execution. If no file name is present, then this
+function automatically prints a simple profiling report, sorted by the
+standard name string (file/line/function-name) that is presented in
+each line.  The following is a typical output from such a call:
+
+\begin{verbatim}
+      2706 function calls (2004 primitive calls) in 4.504 CPU seconds
+
+Ordered by: standard name
+
+ncalls  tottime  percall  cumtime  percall filename:lineno(function)
+     2    0.006    0.003    0.953    0.477 pobject.py:75(save_objects)
+  43/3    0.533    0.012    0.749    0.250 pobject.py:99(evaluate)
+ ...
+\end{verbatim}
+
+The first line indicates that 2706 calls were
+monitored.  Of those calls, 2004 were \dfn{primitive}.  We define
+\dfn{primitive} to mean that the call was not induced via recursion.
+The next line: \code{Ordered by:\ standard name}, indicates that
+the text string in the far right column was used to sort the output.
+The column headings include:
+
+\begin{description}
+
+\item[ncalls ]
+for the number of calls,
+
+\item[tottime ]
+for the total time spent in the given function (and excluding time
+made in calls to sub-functions),
+
+\item[percall ]
+is the quotient of \code{tottime} divided by \code{ncalls}
+
+\item[cumtime ]
+is the total time spent in this and all subfunctions (from invocation
+till exit). This figure is accurate \emph{even} for recursive
+functions.
+
+\item[percall ]
+is the quotient of \code{cumtime} divided by primitive calls
+
+\item[filename:lineno(function) ]
+provides the respective data of each function
+
+\end{description}
+
+When there are two numbers in the first column (for example,
+\samp{43/3}), then the latter is the number of primitive calls, and
+the former is the actual number of calls.  Note that when the function
+does not recurse, these two values are the same, and only the single
+figure is printed.
+
+\end{funcdesc}
+
+\begin{funcdesc}{runctx}{command, globals, locals\optional{, filename}}
+This function is similar to \function{run()}, with added
+arguments to supply the globals and locals dictionaries for the
+\var{command} string.
+\end{funcdesc}
+
+Analysis of the profiler data is done using the \class{Stats} class.
+
+\note{The \class{Stats} class is defined in the \module{pstats} module.}
+
+% now switch modules....
+% (This \stmodindex use may be hard to change ;-( )
+\stmodindex{pstats}
+
+\begin{classdesc}{Stats}{filename\optional{, stream=sys.stdout\optional{, \moreargs}}}
+This class constructor creates an instance of a ``statistics object''
+from a \var{filename} (or set of filenames).  \class{Stats} objects are
+manipulated by methods, in order to print useful reports.  You may specify
+an alternate output stream by giving the keyword argument, \code{stream}.
+
+The file selected by the above constructor must have been created by the
+corresponding version of \module{profile} or \module{cProfile}.  To be
+specific, there is \emph{no} file compatibility guaranteed with future
+versions of this profiler, and there is no compatibility with files produced
+by other profilers.
+%(such as the old system profiler).
+
+If several files are provided, all the statistics for identical
+functions will be coalesced, so that an overall view of several
+processes can be considered in a single report.  If additional files
+need to be combined with data in an existing \class{Stats} object, the
+\method{add()} method can be used.
+
+\versionchanged[The \var{stream} parameter was added]{2.5}
+\end{classdesc}
+
+
+\subsection{The \class{Stats} Class \label{profile-stats}}
+
+\class{Stats} objects have the following methods:
+
+\begin{methoddesc}[Stats]{strip_dirs}{}
+This method for the \class{Stats} class removes all leading path
+information from file names.  It is very useful in reducing the size
+of the printout to fit within (close to) 80 columns.  This method
+modifies the object, and the stripped information is lost.  After
+performing a strip operation, the object is considered to have its
+entries in a ``random'' order, as it was just after object
+initialization and loading.  If \method{strip_dirs()} causes two
+function names to be indistinguishable (they are on the same
+line of the same filename, and have the same function name), then the
+statistics for these two entries are accumulated into a single entry.
+\end{methoddesc}
+
+
+\begin{methoddesc}[Stats]{add}{filename\optional{, \moreargs}}
+This method of the \class{Stats} class accumulates additional
+profiling information into the current profiling object.  Its
+arguments should refer to filenames created by the corresponding
+version of \function{profile.run()} or \function{cProfile.run()}.
+Statistics for identically named
+(re: file, line, name) functions are automatically accumulated into
+single function statistics.
+\end{methoddesc}
+
+\begin{methoddesc}[Stats]{dump_stats}{filename}
+Save the data loaded into the \class{Stats} object to a file named
+\var{filename}.  The file is created if it does not exist, and is
+overwritten if it already exists.  This is equivalent to the method of
+the same name on the \class{profile.Profile} and
+\class{cProfile.Profile} classes.
+\versionadded{2.3}
+\end{methoddesc}
+
+\begin{methoddesc}[Stats]{sort_stats}{key\optional{, \moreargs}}
+This method modifies the \class{Stats} object by sorting it according
+to the supplied criteria.  The argument is typically a string
+identifying the basis of a sort (example: \code{'time'} or
+\code{'name'}).
+
+When more than one key is provided, then additional keys are used as
+secondary criteria when there is equality in all keys selected
+before them.  For example, \code{sort_stats('name', 'file')} will sort
+all the entries according to their function name, and resolve all ties
+(identical function names) by sorting by file name.
+
+Abbreviations can be used for any key names, as long as the
+abbreviation is unambiguous.  The following are the keys currently
+defined:
+
+\begin{tableii}{l|l}{code}{Valid Arg}{Meaning}
+  \lineii{'calls'}{call count}
+  \lineii{'cumulative'}{cumulative time}
+  \lineii{'file'}{file name}
+  \lineii{'module'}{file name}
+  \lineii{'pcalls'}{primitive call count}
+  \lineii{'line'}{line number}
+  \lineii{'name'}{function name}
+  \lineii{'nfl'}{name/file/line}
+  \lineii{'stdname'}{standard name}
+  \lineii{'time'}{internal time}
+\end{tableii}
+
+Note that all sorts on statistics are in descending order (placing
+most time consuming items first), where as name, file, and line number
+searches are in ascending order (alphabetical). The subtle
+distinction between \code{'nfl'} and \code{'stdname'} is that the
+standard name is a sort of the name as printed, which means that the
+embedded line numbers get compared in an odd way.  For example, lines
+3, 20, and 40 would (if the file names were the same) appear in the
+string order 20, 3 and 40.  In contrast, \code{'nfl'} does a numeric
+compare of the line numbers.  In fact, \code{sort_stats('nfl')} is the
+same as \code{sort_stats('name', 'file', 'line')}.
+
+%For compatibility with the old profiler,
+For backward-compatibility reasons, the numeric arguments
+\code{-1}, \code{0}, \code{1}, and \code{2} are permitted.  They are
+interpreted as \code{'stdname'}, \code{'calls'}, \code{'time'}, and
+\code{'cumulative'} respectively.  If this old style format (numeric)
+is used, only one sort key (the numeric key) will be used, and
+additional arguments will be silently ignored.
+\end{methoddesc}
+
+
+\begin{methoddesc}[Stats]{reverse_order}{}
+This method for the \class{Stats} class reverses the ordering of the basic
+list within the object.  %This method is provided primarily for
+%compatibility with the old profiler.
+Note that by default ascending vs descending order is properly selected
+based on the sort key of choice.
+\end{methoddesc}
+
+\begin{methoddesc}[Stats]{print_stats}{\optional{restriction, \moreargs}}
+This method for the \class{Stats} class prints out a report as described
+in the \function{profile.run()} definition.
+
+The order of the printing is based on the last \method{sort_stats()}
+operation done on the object (subject to caveats in \method{add()} and
+\method{strip_dirs()}).
+
+The arguments provided (if any) can be used to limit the list down to
+the significant entries.  Initially, the list is taken to be the
+complete set of profiled functions.  Each restriction is either an
+integer (to select a count of lines), or a decimal fraction between
+0.0 and 1.0 inclusive (to select a percentage of lines), or a regular
+expression (to pattern match the standard name that is printed; as of
+Python 1.5b1, this uses the Perl-style regular expression syntax
+defined by the \refmodule{re} module).  If several restrictions are
+provided, then they are applied sequentially.  For example:
+
+\begin{verbatim}
+print_stats(.1, 'foo:')
+\end{verbatim}
+
+would first limit the printing to first 10\% of list, and then only
+print functions that were part of filename \file{.*foo:}.  In
+contrast, the command:
+
+\begin{verbatim}
+print_stats('foo:', .1)
+\end{verbatim}
+
+would limit the list to all functions having file names \file{.*foo:},
+and then proceed to only print the first 10\% of them.
+\end{methoddesc}
+
+
+\begin{methoddesc}[Stats]{print_callers}{\optional{restriction, \moreargs}}
+This method for the \class{Stats} class prints a list of all functions
+that called each function in the profiled database.  The ordering is
+identical to that provided by \method{print_stats()}, and the definition
+of the restricting argument is also identical.  Each caller is reported on
+its own line.  The format differs slightly depending on the profiler that
+produced the stats:
+
+\begin{itemize}
+\item With \module{profile}, a number is shown in parentheses after each
+  caller to show how many times this specific call was made.  For
+  convenience, a second non-parenthesized number repeats the cumulative
+  time spent in the function at the right.
+
+\item With \module{cProfile}, each caller is preceeded by three numbers:
+  the number of times this specific call was made, and the total and
+  cumulative times spent in the current function while it was invoked by
+  this specific caller.
+\end{itemize}
+\end{methoddesc}
+
+\begin{methoddesc}[Stats]{print_callees}{\optional{restriction, \moreargs}}
+This method for the \class{Stats} class prints a list of all function
+that were called by the indicated function.  Aside from this reversal
+of direction of calls (re: called vs was called by), the arguments and
+ordering are identical to the \method{print_callers()} method.
+\end{methoddesc}
+
+
+\section{Limitations \label{profile-limits}}
+
+One limitation has to do with accuracy of timing information.
+There is a fundamental problem with deterministic profilers involving
+accuracy.  The most obvious restriction is that the underlying ``clock''
+is only ticking at a rate (typically) of about .001 seconds.  Hence no
+measurements will be more accurate than the underlying clock.  If
+enough measurements are taken, then the ``error'' will tend to average
+out. Unfortunately, removing this first error induces a second source
+of error.
+
+The second problem is that it ``takes a while'' from when an event is
+dispatched until the profiler's call to get the time actually
+\emph{gets} the state of the clock.  Similarly, there is a certain lag
+when exiting the profiler event handler from the time that the clock's
+value was obtained (and then squirreled away), until the user's code
+is once again executing.  As a result, functions that are called many
+times, or call many functions, will typically accumulate this error.
+The error that accumulates in this fashion is typically less than the
+accuracy of the clock (less than one clock tick), but it
+\emph{can} accumulate and become very significant.
+
+The problem is more important with \module{profile} than with the
+lower-overhead \module{cProfile}.  For this reason, \module{profile}
+provides a means of calibrating itself for a given platform so that
+this error can be probabilistically (on the average) removed.
+After the profiler is calibrated, it will be more accurate (in a least
+square sense), but it will sometimes produce negative numbers (when
+call counts are exceptionally low, and the gods of probability work
+against you :-). )  Do \emph{not} be alarmed by negative numbers in
+the profile.  They should \emph{only} appear if you have calibrated
+your profiler, and the results are actually better than without
+calibration.
+
+
+\section{Calibration \label{profile-calibration}}
+
+The profiler of the \module{profile} module subtracts a constant from each
+event handling time to compensate for the overhead of calling the time
+function, and socking away the results.  By default, the constant is 0.
+The following procedure can
+be used to obtain a better constant for a given platform (see discussion
+in section Limitations above).
+
+\begin{verbatim}
+import profile
+pr = profile.Profile()
+for i in range(5):
+    print pr.calibrate(10000)
+\end{verbatim}
+
+The method executes the number of Python calls given by the argument,
+directly and again under the profiler, measuring the time for both.
+It then computes the hidden overhead per profiler event, and returns
+that as a float.  For example, on an 800 MHz Pentium running
+Windows 2000, and using Python's time.clock() as the timer,
+the magical number is about 12.5e-6.
+
+The object of this exercise is to get a fairly consistent result.
+If your computer is \emph{very} fast, or your timer function has poor
+resolution, you might have to pass 100000, or even 1000000, to get
+consistent results.
+
+When you have a consistent answer,
+there are three ways you can use it:\footnote{Prior to Python 2.2, it
+  was necessary to edit the profiler source code to embed the bias as
+  a literal number.  You still can, but that method is no longer
+  described, because no longer needed.}
+
+\begin{verbatim}
+import profile
+
+# 1. Apply computed bias to all Profile instances created hereafter.
+profile.Profile.bias = your_computed_bias
+
+# 2. Apply computed bias to a specific Profile instance.
+pr = profile.Profile()
+pr.bias = your_computed_bias
+
+# 3. Specify computed bias in instance constructor.
+pr = profile.Profile(bias=your_computed_bias)
+\end{verbatim}
+
+If you have a choice, you are better off choosing a smaller constant, and
+then your results will ``less often'' show up as negative in profile
+statistics.
+
+
+\section{Extensions --- Deriving Better Profilers}
+\nodename{Profiler Extensions}
+
+The \class{Profile} class of both modules, \module{profile} and
+\module{cProfile}, were written so that
+derived classes could be developed to extend the profiler.  The details
+are not described here, as doing this successfully requires an expert
+understanding of how the \class{Profile} class works internally.  Study
+the source code of the module carefully if you want to
+pursue this.
+
+If all you want to do is change how current time is determined (for
+example, to force use of wall-clock time or elapsed process time),
+pass the timing function you want to the \class{Profile} class
+constructor:
+
+\begin{verbatim}
+pr = profile.Profile(your_time_func)
+\end{verbatim}
+
+The resulting profiler will then call \function{your_time_func()}.
+
+\begin{description}
+\item[\class{profile.Profile}]
+\function{your_time_func()} should return a single number, or a list of
+numbers whose sum is the current time (like what \function{os.times()}
+returns).  If the function returns a single time number, or the list of
+returned numbers has length 2, then you will get an especially fast
+version of the dispatch routine.
+
+Be warned that you should calibrate the profiler class for the
+timer function that you choose.  For most machines, a timer that
+returns a lone integer value will provide the best results in terms of
+low overhead during profiling.  (\function{os.times()} is
+\emph{pretty} bad, as it returns a tuple of floating point values).  If
+you want to substitute a better timer in the cleanest fashion,
+derive a class and hardwire a replacement dispatch method that best
+handles your timer call, along with the appropriate calibration
+constant.
+
+\item[\class{cProfile.Profile}]
+\function{your_time_func()} should return a single number.  If it returns
+plain integers, you can also invoke the class constructor with a second
+argument specifying the real duration of one unit of time.  For example,
+if \function{your_integer_time_func()} returns times measured in thousands
+of seconds, you would constuct the \class{Profile} instance as follows:
+
+\begin{verbatim}
+pr = profile.Profile(your_integer_time_func, 0.001)
+\end{verbatim}
+
+As the \module{cProfile.Profile} class cannot be calibrated, custom
+timer functions should be used with care and should be as fast as
+possible.  For the best results with a custom timer, it might be
+necessary to hard-code it in the C source of the internal
+\module{_lsprof} module.
+
+\end{description}
diff --git a/sys/src/cmd/python/Doc/lib/libpty.tex b/sys/src/cmd/python/Doc/lib/libpty.tex
new file mode 100644
index 000000000..2db75030b
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpty.tex
@@ -0,0 +1,44 @@
+\section{\module{pty} ---
+         Pseudo-terminal utilities}
+\declaremodule{standard}{pty}
+  \platform{IRIX, Linux}
+\modulesynopsis{Pseudo-Terminal Handling for SGI and Linux.}
+\moduleauthor{Steen Lumholt}{}
+\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il}
+
+
+The \module{pty} module defines operations for handling the
+pseudo-terminal concept: starting another process and being able to
+write to and read from its controlling terminal programmatically.
+
+Because pseudo-terminal handling is highly platform dependant, there
+is code to do it only for SGI and Linux. (The Linux code is supposed
+to work on other platforms, but hasn't been tested yet.)
+
+The \module{pty} module defines the following functions:
+
+\begin{funcdesc}{fork}{}
+Fork. Connect the child's controlling terminal to a pseudo-terminal.
+Return value is \code{(\var{pid}, \var{fd})}. Note that the child 
+gets \var{pid} 0, and the \var{fd} is \emph{invalid}. The parent's
+return value is the \var{pid} of the child, and \var{fd} is a file
+descriptor connected to the child's controlling terminal (and also
+to the child's standard input and output).
+\end{funcdesc}
+
+\begin{funcdesc}{openpty}{}
+Open a new pseudo-terminal pair, using \function{os.openpty()} if
+possible, or emulation code for SGI and generic \UNIX{} systems.
+Return a pair of file descriptors \code{(\var{master}, \var{slave})},
+for the master and the slave end, respectively.
+\end{funcdesc}
+
+\begin{funcdesc}{spawn}{argv\optional{, master_read\optional{, stdin_read}}}
+Spawn a process, and connect its controlling terminal with the current 
+process's standard io. This is often used to baffle programs which
+insist on reading from the controlling terminal.
+
+The functions \var{master_read} and \var{stdin_read} should be
+functions which read from a file-descriptor. The defaults try to read
+1024 bytes each time they are called.
+\end{funcdesc}
diff --git a/sys/src/cmd/python/Doc/lib/libpwd.tex b/sys/src/cmd/python/Doc/lib/libpwd.tex
new file mode 100644
index 000000000..0c74d2655
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpwd.tex
@@ -0,0 +1,57 @@
+\section{\module{pwd} ---
+         The password database}
+
+\declaremodule{builtin}{pwd}
+  \platform{Unix}
+\modulesynopsis{The password database (\function{getpwnam()} and friends).}
+
+This module provides access to the \UNIX{} user account and password
+database.  It is available on all \UNIX{} versions.
+
+Password database entries are reported as a tuple-like object, whose
+attributes correspond to the members of the \code{passwd} structure
+(Attribute field below, see \code{}):
+
+\begin{tableiii}{r|l|l}{textrm}{Index}{Attribute}{Meaning}
+  \lineiii{0}{\code{pw_name}}{Login name}
+  \lineiii{1}{\code{pw_passwd}}{Optional encrypted password}
+  \lineiii{2}{\code{pw_uid}}{Numerical user ID}
+  \lineiii{3}{\code{pw_gid}}{Numerical group ID}
+  \lineiii{4}{\code{pw_gecos}}{User name or comment field}
+  \lineiii{5}{\code{pw_dir}}{User home directory}
+  \lineiii{6}{\code{pw_shell}}{User command interpreter}
+\end{tableiii}
+
+The uid and gid items are integers, all others are strings.
+\exception{KeyError} is raised if the entry asked for cannot be found.
+
+\note{In traditional \UNIX{} the field \code{pw_passwd} usually
+contains a password encrypted with a DES derived algorithm (see module
+\refmodule{crypt}\refbimodindex{crypt}).  However most modern unices 
+use a so-called \emph{shadow password} system.  On those unices the
+\var{pw_passwd} field only contains an asterisk (\code{'*'}) or the 
+letter \character{x} where the encrypted password is stored in a file
+\file{/etc/shadow} which is not world readable.  Whether the \var{pw_passwd}
+field contains anything useful is system-dependent.  If available, the
+\module{spwd} module should be used where access to the encrypted password
+is required.}
+
+It defines the following items:
+
+\begin{funcdesc}{getpwuid}{uid}
+Return the password database entry for the given numeric user ID.
+\end{funcdesc}
+
+\begin{funcdesc}{getpwnam}{name}
+Return the password database entry for the given user name.
+\end{funcdesc}
+
+\begin{funcdesc}{getpwall}{}
+Return a list of all available password database entries, in arbitrary order.
+\end{funcdesc}
+
+
+\begin{seealso}
+  \seemodule{grp}{An interface to the group database, similar to this.}
+  \seemodule{spwd}{An interface to the shadow password database, similar to this.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libpyclbr.tex b/sys/src/cmd/python/Doc/lib/libpyclbr.tex
new file mode 100644
index 000000000..0dedb9e5d
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpyclbr.tex
@@ -0,0 +1,102 @@
+\section{\module{pyclbr} ---
+         Python class browser support}
+
+\declaremodule{standard}{pyclbr}
+\modulesynopsis{Supports information extraction for a Python class
+                browser.}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+
+The \module{pyclbr} can be used to determine some limited information
+about the classes, methods and top-level functions
+defined in a module.  The information
+provided is sufficient to implement a traditional three-pane class
+browser.  The information is extracted from the source code rather
+than by importing the module, so this module is safe to use with
+untrusted source code.  This restriction makes it impossible to use
+this module with modules not implemented in Python, including many
+standard and optional extension modules.
+
+
+\begin{funcdesc}{readmodule}{module\optional{, path}}
+  % The 'inpackage' parameter appears to be for internal use only....
+  Read a module and return a dictionary mapping class names to class
+  descriptor objects.  The parameter \var{module} should be the name
+  of a module as a string; it may be the name of a module within a
+  package.  The \var{path} parameter should be a sequence, and is used
+  to augment the value of \code{sys.path}, which is used to locate
+  module source code.
+\end{funcdesc}
+
+\begin{funcdesc}{readmodule_ex}{module\optional{, path}}
+  % The 'inpackage' parameter appears to be for internal use only....
+  Like \function{readmodule()}, but the returned dictionary, in addition
+  to mapping class names to class descriptor objects, also maps
+  top-level function names to function descriptor objects.  Moreover, if
+  the module being read is a package, the key \code{'__path__'} in the
+  returned dictionary has as its value a list which contains the package
+  search path.
+\end{funcdesc}
+
+
+\subsection{Class Descriptor Objects \label{pyclbr-class-objects}}
+
+The class descriptor objects used as values in the dictionary returned
+by \function{readmodule()} and \function{readmodule_ex()}
+provide the following data members:
+
+
+\begin{memberdesc}[class descriptor]{module}
+  The name of the module defining the class described by the class
+  descriptor.
+\end{memberdesc}
+
+\begin{memberdesc}[class descriptor]{name}
+  The name of the class.
+\end{memberdesc}
+
+\begin{memberdesc}[class descriptor]{super}
+  A list of class descriptors which describe the immediate base
+  classes of the class being described.  Classes which are named as
+  superclasses but which are not discoverable by
+  \function{readmodule()} are listed as a string with the class name
+  instead of class descriptors.
+\end{memberdesc}
+
+\begin{memberdesc}[class descriptor]{methods}
+  A dictionary mapping method names to line numbers.
+\end{memberdesc}
+
+\begin{memberdesc}[class descriptor]{file}
+  Name of the file containing the \code{class} statement defining the class.
+\end{memberdesc}
+
+\begin{memberdesc}[class descriptor]{lineno}
+  The line number of the \code{class} statement within the file named by
+  \member{file}.
+\end{memberdesc}
+
+\subsection{Function Descriptor Objects \label{pyclbr-function-objects}}
+
+The function descriptor objects used as values in the dictionary returned
+by \function{readmodule_ex()} provide the following data members:
+
+
+\begin{memberdesc}[function descriptor]{module}
+  The name of the module defining the function described by the function
+  descriptor.
+\end{memberdesc}
+
+\begin{memberdesc}[function descriptor]{name}
+  The name of the function.
+\end{memberdesc}
+
+\begin{memberdesc}[function descriptor]{file}
+  Name of the file containing the \code{def} statement defining the function.
+\end{memberdesc}
+
+\begin{memberdesc}[function descriptor]{lineno}
+  The line number of the \code{def} statement within the file named by
+  \member{file}.
+\end{memberdesc}
+
diff --git a/sys/src/cmd/python/Doc/lib/libpycompile.tex b/sys/src/cmd/python/Doc/lib/libpycompile.tex
new file mode 100644
index 000000000..85f0aaa8b
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpycompile.tex
@@ -0,0 +1,53 @@
+\section{\module{py_compile} ---
+         Compile Python source files}
+
+% Documentation based on module docstrings, by Fred L. Drake, Jr.
+% 
+
+\declaremodule[pycompile]{standard}{py_compile}
+
+\modulesynopsis{Compile Python source files to byte-code files.}
+
+
+\indexii{file}{byte-code}
+The \module{py_compile} module provides a function to generate a
+byte-code file from a source file, and another function used when the
+module source file is invoked as a script.
+
+Though not often needed, this function can be useful when installing
+modules for shared use, especially if some of the users may not have
+permission to write the byte-code cache files in the directory
+containing the source code.
+
+\begin{excdesc}{PyCompileError}
+Exception raised when an error occurs while attempting to compile the file.
+\end{excdesc}
+
+\begin{funcdesc}{compile}{file\optional{, cfile\optional{, dfile\optional{, doraise}}}}
+  Compile a source file to byte-code and write out the byte-code cache 
+  file.  The source code is loaded from the file name \var{file}.  The 
+  byte-code is written to \var{cfile}, which defaults to \var{file}
+  \code{+} \code{'c'} (\code{'o'} if optimization is enabled in the
+  current interpreter).  If \var{dfile} is specified, it is used as
+  the name of the source file in error messages instead of \var{file}. 
+  If \var{doraise} is true, a \exception{PyCompileError} is raised when
+  an error is encountered while compiling \var{file}. If \var{doraise}
+  is false (the default), an error string is written to \code{sys.stderr},
+  but no exception is raised.
+\end{funcdesc}
+
+\begin{funcdesc}{main}{\optional{args}}
+  Compile several source files.  The files named in \var{args} (or on
+  the command line, if \var{args} is not specified) are compiled and
+  the resulting bytecode is cached in the normal manner.  This
+  function does not search a directory structure to locate source
+  files; it only compiles files named explicitly.
+\end{funcdesc}
+
+When this module is run as a script, the \function{main()} is used to
+compile all the files named on the command line.
+
+\begin{seealso}
+  \seemodule{compileall}{Utilities to compile all Python source files
+                         in a directory tree.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libpydoc.tex b/sys/src/cmd/python/Doc/lib/libpydoc.tex
new file mode 100644
index 000000000..bb74df6cb
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpydoc.tex
@@ -0,0 +1,67 @@
+\section{\module{pydoc} ---
+         Documentation generator and online help system}
+
+\declaremodule{standard}{pydoc}
+\modulesynopsis{Documentation generator and online help system.}
+\moduleauthor{Ka-Ping Yee}{ping@lfw.org}
+\sectionauthor{Ka-Ping Yee}{ping@lfw.org}
+
+\versionadded{2.1}
+\index{documentation!generation}
+\index{documentation!online}
+\index{help!online}
+
+The \module{pydoc} module automatically generates documentation from
+Python modules.  The documentation can be presented as pages of text
+on the console, served to a Web browser, or saved to HTML files.
+
+The built-in function \function{help()} invokes the online help system
+in the interactive interpreter, which uses \module{pydoc} to generate
+its documentation as text on the console.  The same text documentation
+can also be viewed from outside the Python interpreter by running
+\program{pydoc} as a script at the operating system's command prompt.
+For example, running
+
+\begin{verbatim}
+pydoc sys
+\end{verbatim}
+
+at a shell prompt will display documentation on the \refmodule{sys}
+module, in a style similar to the manual pages shown by the \UNIX{}
+\program{man} command.  The argument to \program{pydoc} can be the name
+of a function, module, or package, or a dotted reference to a class,
+method, or function within a module or module in a package.  If the
+argument to \program{pydoc} looks like a path (that is, it contains the
+path separator for your operating system, such as a slash in \UNIX),
+and refers to an existing Python source file, then documentation is
+produced for that file.
+
+Specifying a \programopt{-w} flag before the argument will cause HTML
+documentation to be written out to a file in the current directory,
+instead of displaying text on the console.
+
+Specifying a \programopt{-k} flag before the argument will search the
+synopsis lines of all available modules for the keyword given as the
+argument, again in a manner similar to the \UNIX{} \program{man}
+command.  The synopsis line of a module is the first line of its
+documentation string.
+
+You can also use \program{pydoc} to start an HTTP server on the local
+machine that will serve documentation to visiting Web browsers.
+\program{pydoc} \programopt{-p 1234} will start a HTTP server on port
+1234, allowing you to browse the documentation at
+\code{http://localhost:1234/} in your preferred Web browser.
+\program{pydoc} \programopt{-g} will start the server and additionally
+bring up a small \refmodule{Tkinter}-based graphical interface to help
+you search for documentation pages.
+
+When \program{pydoc} generates documentation, it uses the current
+environment and path to locate modules.  Thus, invoking
+\program{pydoc} \programopt{spam} documents precisely the version of
+the module you would get if you started the Python interpreter and
+typed \samp{import spam}.
+
+Module docs for core modules are assumed to reside in
+{}\url{http://www.python.org/doc/current/lib/}.  This can be overridden by
+setting the \envvar{PYTHONDOCS} environment variable to a different URL or
+to a local directory containing the Library Reference Manual pages.
diff --git a/sys/src/cmd/python/Doc/lib/libpyexpat.tex b/sys/src/cmd/python/Doc/lib/libpyexpat.tex
new file mode 100644
index 000000000..a0ea8a1a4
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpyexpat.tex
@@ -0,0 +1,777 @@
+\section{\module{xml.parsers.expat} ---
+         Fast XML parsing using Expat}
+
+% Markup notes:
+%
+% Many of the attributes of the XMLParser objects are callbacks.
+% Since signature information must be presented, these are described
+% using the methoddesc environment.  Since they are attributes which
+% are set by client code, in-text references to these attributes
+% should be marked using the \member macro and should not include the
+% parentheses used when marking functions and methods.
+
+\declaremodule{standard}{xml.parsers.expat}
+\modulesynopsis{An interface to the Expat non-validating XML parser.}
+\moduleauthor{Paul Prescod}{paul@prescod.net}
+
+\versionadded{2.0}
+
+The \module{xml.parsers.expat} module is a Python interface to the
+Expat\index{Expat} non-validating XML parser.
+The module provides a single extension type, \class{xmlparser}, that
+represents the current state of an XML parser.  After an
+\class{xmlparser} object has been created, various attributes of the object 
+can be set to handler functions.  When an XML document is then fed to
+the parser, the handler functions are called for the character data
+and markup in the XML document.
+
+This module uses the \module{pyexpat}\refbimodindex{pyexpat} module to
+provide access to the Expat parser.  Direct use of the
+\module{pyexpat} module is deprecated.
+
+This module provides one exception and one type object:
+
+\begin{excdesc}{ExpatError}
+  The exception raised when Expat reports an error.  See section
+  \ref{expaterror-objects}, ``ExpatError Exceptions,'' for more
+  information on interpreting Expat errors.
+\end{excdesc}
+
+\begin{excdesc}{error}
+  Alias for \exception{ExpatError}.
+\end{excdesc}
+
+\begin{datadesc}{XMLParserType}
+  The type of the return values from the \function{ParserCreate()}
+  function.
+\end{datadesc}
+
+
+The \module{xml.parsers.expat} module contains two functions:
+
+\begin{funcdesc}{ErrorString}{errno}
+Returns an explanatory string for a given error number \var{errno}.
+\end{funcdesc}
+
+\begin{funcdesc}{ParserCreate}{\optional{encoding\optional{,
+                               namespace_separator}}}
+Creates and returns a new \class{xmlparser} object.  
+\var{encoding}, if specified, must be a string naming the encoding 
+used by the XML data.  Expat doesn't support as many encodings as
+Python does, and its repertoire of encodings can't be extended; it
+supports UTF-8, UTF-16, ISO-8859-1 (Latin1), and ASCII.  If
+\var{encoding} is given it will override the implicit or explicit
+encoding of the document.
+
+Expat can optionally do XML namespace processing for you, enabled by
+providing a value for \var{namespace_separator}.  The value must be a
+one-character string; a \exception{ValueError} will be raised if the
+string has an illegal length (\code{None} is considered the same as
+omission).  When namespace processing is enabled, element type names
+and attribute names that belong to a namespace will be expanded.  The
+element name passed to the element handlers
+\member{StartElementHandler} and \member{EndElementHandler}
+will be the concatenation of the namespace URI, the namespace
+separator character, and the local part of the name.  If the namespace
+separator is a zero byte (\code{chr(0)}) then the namespace URI and
+the local part will be concatenated without any separator.
+
+For example, if \var{namespace_separator} is set to a space character
+(\character{ }) and the following document is parsed:
+
+\begin{verbatim}
+
+
+  
+  
+
+\end{verbatim}
+
+\member{StartElementHandler} will receive the following strings
+for each element:
+
+\begin{verbatim}
+http://default-namespace.org/ root
+http://www.python.org/ns/ elem1
+elem2
+\end{verbatim}
+\end{funcdesc}
+
+
+\begin{seealso}
+  \seetitle[http://www.libexpat.org/]{The Expat XML Parser}
+           {Home page of the Expat project.}
+\end{seealso}
+
+
+\subsection{XMLParser Objects \label{xmlparser-objects}}
+
+\class{xmlparser} objects have the following methods:
+
+\begin{methoddesc}[xmlparser]{Parse}{data\optional{, isfinal}}
+Parses the contents of the string \var{data}, calling the appropriate
+handler functions to process the parsed data.  \var{isfinal} must be
+true on the final call to this method.  \var{data} can be the empty
+string at any time.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{ParseFile}{file}
+Parse XML data reading from the object \var{file}.  \var{file} only
+needs to provide the \method{read(\var{nbytes})} method, returning the
+empty string when there's no more data.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{SetBase}{base}
+Sets the base to be used for resolving relative URIs in system
+identifiers in declarations.  Resolving relative identifiers is left
+to the application: this value will be passed through as the
+\var{base} argument to the \function{ExternalEntityRefHandler},
+\function{NotationDeclHandler}, and
+\function{UnparsedEntityDeclHandler} functions.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{GetBase}{}
+Returns a string containing the base set by a previous call to
+\method{SetBase()}, or \code{None} if 
+\method{SetBase()} hasn't been called.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{GetInputContext}{}
+Returns the input data that generated the current event as a string.
+The data is in the encoding of the entity which contains the text.
+When called while an event handler is not active, the return value is
+\code{None}.
+\versionadded{2.1}
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{ExternalEntityParserCreate}{context\optional{,
+                                                          encoding}}
+Create a ``child'' parser which can be used to parse an external
+parsed entity referred to by content parsed by the parent parser.  The
+\var{context} parameter should be the string passed to the
+\method{ExternalEntityRefHandler()} handler function, described below.
+The child parser is created with the \member{ordered_attributes},
+\member{returns_unicode} and \member{specified_attributes} set to the
+values of this parser.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{UseForeignDTD}{\optional{flag}}
+Calling this with a true value for \var{flag} (the default) will cause
+Expat to call the \member{ExternalEntityRefHandler} with
+\constant{None} for all arguments to allow an alternate DTD to be
+loaded.  If the document does not contain a document type declaration,
+the \member{ExternalEntityRefHandler} will still be called, but the
+\member{StartDoctypeDeclHandler} and \member{EndDoctypeDeclHandler}
+will not be called.
+
+Passing a false value for \var{flag} will cancel a previous call that
+passed a true value, but otherwise has no effect.
+
+This method can only be called before the \method{Parse()} or
+\method{ParseFile()} methods are called; calling it after either of
+those have been called causes \exception{ExpatError} to be raised with
+the \member{code} attribute set to
+\constant{errors.XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING}.
+
+\versionadded{2.3}
+\end{methoddesc}
+
+
+\class{xmlparser} objects have the following attributes:
+
+\begin{memberdesc}[xmlparser]{buffer_size}
+The size of the buffer used when \member{buffer_text} is true.  This
+value cannot be changed at this time.
+\versionadded{2.3}
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{buffer_text}
+Setting this to true causes the \class{xmlparser} object to buffer
+textual content returned by Expat to avoid multiple calls to the
+\method{CharacterDataHandler()} callback whenever possible.  This can
+improve performance substantially since Expat normally breaks
+character data into chunks at every line ending.  This attribute is
+false by default, and may be changed at any time.
+\versionadded{2.3}
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{buffer_used}
+If \member{buffer_text} is enabled, the number of bytes stored in the
+buffer.  These bytes represent UTF-8 encoded text.  This attribute has
+no meaningful interpretation when \member{buffer_text} is false.
+\versionadded{2.3}
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{ordered_attributes}
+Setting this attribute to a non-zero integer causes the attributes to
+be reported as a list rather than a dictionary.  The attributes are
+presented in the order found in the document text.  For each
+attribute, two list entries are presented: the attribute name and the
+attribute value.  (Older versions of this module also used this
+format.)  By default, this attribute is false; it may be changed at
+any time.
+\versionadded{2.1}
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{returns_unicode} 
+If this attribute is set to a non-zero integer, the handler functions
+will be passed Unicode strings.  If \member{returns_unicode} is
+\constant{False}, 8-bit strings containing UTF-8 encoded data will be
+passed to the handlers.  This is \constant{True} by default when
+Python is built with Unicode support.
+\versionchanged[Can be changed at any time to affect the result
+  type]{1.6}
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{specified_attributes}
+If set to a non-zero integer, the parser will report only those
+attributes which were specified in the document instance and not those
+which were derived from attribute declarations.  Applications which
+set this need to be especially careful to use what additional
+information is available from the declarations as needed to comply
+with the standards for the behavior of XML processors.  By default,
+this attribute is false; it may be changed at any time.
+\versionadded{2.1}
+\end{memberdesc}
+
+The following attributes contain values relating to the most recent
+error encountered by an \class{xmlparser} object, and will only have
+correct values once a call to \method{Parse()} or \method{ParseFile()}
+has raised a \exception{xml.parsers.expat.ExpatError} exception.
+
+\begin{memberdesc}[xmlparser]{ErrorByteIndex} 
+Byte index at which an error occurred.
+\end{memberdesc} 
+
+\begin{memberdesc}[xmlparser]{ErrorCode} 
+Numeric code specifying the problem.  This value can be passed to the
+\function{ErrorString()} function, or compared to one of the constants
+defined in the \code{errors} object.
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{ErrorColumnNumber} 
+Column number at which an error occurred.
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{ErrorLineNumber}
+Line number at which an error occurred.
+\end{memberdesc}
+
+The following attributes contain values relating to the current parse
+location in an \class{xmlparser} object.  During a callback reporting
+a parse event they indicate the location of the first of the sequence
+of characters that generated the event.  When called outside of a
+callback, the position indicated will be just past the last parse
+event (regardless of whether there was an associated callback).
+\versionadded{2.4}
+
+\begin{memberdesc}[xmlparser]{CurrentByteIndex} 
+Current byte index in the parser input.
+\end{memberdesc} 
+
+\begin{memberdesc}[xmlparser]{CurrentColumnNumber} 
+Current column number in the parser input.
+\end{memberdesc}
+
+\begin{memberdesc}[xmlparser]{CurrentLineNumber}
+Current line number in the parser input.
+\end{memberdesc}
+
+Here is the list of handlers that can be set.  To set a handler on an
+\class{xmlparser} object \var{o}, use
+\code{\var{o}.\var{handlername} = \var{func}}.  \var{handlername} must
+be taken from the following list, and \var{func} must be a callable
+object accepting the correct number of arguments.  The arguments are
+all strings, unless otherwise stated.
+
+\begin{methoddesc}[xmlparser]{XmlDeclHandler}{version, encoding, standalone}
+Called when the XML declaration is parsed.  The XML declaration is the
+(optional) declaration of the applicable version of the XML
+recommendation, the encoding of the document text, and an optional
+``standalone'' declaration.  \var{version} and \var{encoding} will be
+strings of the type dictated by the \member{returns_unicode}
+attribute, and \var{standalone} will be \code{1} if the document is
+declared standalone, \code{0} if it is declared not to be standalone,
+or \code{-1} if the standalone clause was omitted.
+This is only available with Expat version 1.95.0 or newer.
+\versionadded{2.1}
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{StartDoctypeDeclHandler}{doctypeName,
+                                                       systemId, publicId,
+                                                       has_internal_subset}
+Called when Expat begins parsing the document type declaration
+(\code{}'.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{StartCdataSectionHandler}{}
+Called at the start of a CDATA section.  This and
+\member{EndCdataSectionHandler} are needed to be able to identify
+the syntactical start and end for CDATA sections.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{EndCdataSectionHandler}{}
+Called at the end of a CDATA section.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{DefaultHandler}{data}
+Called for any characters in the XML document for
+which no applicable handler has been specified.  This means
+characters that are part of a construct which could be reported, but
+for which no handler has been supplied. 
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{DefaultHandlerExpand}{data}
+This is the same as the \function{DefaultHandler}, 
+but doesn't inhibit expansion of internal entities.
+The entity reference will not be passed to the default handler.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{NotStandaloneHandler}{} Called if the
+XML document hasn't been declared as being a standalone document.
+This happens when there is an external subset or a reference to a
+parameter entity, but the XML declaration does not set standalone to
+\code{yes} in an XML declaration.  If this handler returns \code{0},
+then the parser will throw an \constant{XML_ERROR_NOT_STANDALONE}
+error.  If this handler is not set, no exception is raised by the
+parser for this condition.
+\end{methoddesc}
+
+\begin{methoddesc}[xmlparser]{ExternalEntityRefHandler}{context, base,
+                                                        systemId, publicId}
+Called for references to external entities.  \var{base} is the current
+base, as set by a previous call to \method{SetBase()}.  The public and
+system identifiers, \var{systemId} and \var{publicId}, are strings if
+given; if the public identifier is not given, \var{publicId} will be
+\code{None}.  The \var{context} value is opaque and should only be
+used as described below.
+
+For external entities to be parsed, this handler must be implemented.
+It is responsible for creating the sub-parser using
+\code{ExternalEntityParserCreate(\var{context})}, initializing it with
+the appropriate callbacks, and parsing the entity.  This handler
+should return an integer; if it returns \code{0}, the parser will
+throw an \constant{XML_ERROR_EXTERNAL_ENTITY_HANDLING} error,
+otherwise parsing will continue.
+
+If this handler is not provided, external entities are reported by the
+\member{DefaultHandler} callback, if provided.
+\end{methoddesc}
+
+
+\subsection{ExpatError Exceptions \label{expaterror-objects}}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+\exception{ExpatError} exceptions have a number of interesting
+attributes:
+
+\begin{memberdesc}[ExpatError]{code}
+  Expat's internal error number for the specific error.  This will
+  match one of the constants defined in the \code{errors} object from
+  this module.
+  \versionadded{2.1}
+\end{memberdesc}
+
+\begin{memberdesc}[ExpatError]{lineno}
+  Line number on which the error was detected.  The first line is
+  numbered \code{1}.
+  \versionadded{2.1}
+\end{memberdesc}
+
+\begin{memberdesc}[ExpatError]{offset}
+  Character offset into the line where the error occurred.  The first
+  column is numbered \code{0}.
+  \versionadded{2.1}
+\end{memberdesc}
+
+
+\subsection{Example \label{expat-example}}
+
+The following program defines three handlers that just print out their
+arguments.
+
+\begin{verbatim}
+import xml.parsers.expat
+
+# 3 handler functions
+def start_element(name, attrs):
+    print 'Start element:', name, attrs
+def end_element(name):
+    print 'End element:', name
+def char_data(data):
+    print 'Character data:', repr(data)
+
+p = xml.parsers.expat.ParserCreate()
+
+p.StartElementHandler = start_element
+p.EndElementHandler = end_element
+p.CharacterDataHandler = char_data
+
+p.Parse("""
+Text goes here
+More text
+""", 1)
+\end{verbatim}
+
+The output from this program is:
+
+\begin{verbatim}
+Start element: parent {'id': 'top'}
+Start element: child1 {'name': 'paul'}
+Character data: 'Text goes here'
+End element: child1
+Character data: '\n'
+Start element: child2 {'name': 'fred'}
+Character data: 'More text'
+End element: child2
+Character data: '\n'
+End element: parent
+\end{verbatim}
+
+
+\subsection{Content Model Descriptions \label{expat-content-models}}
+\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org}
+
+Content modules are described using nested tuples.  Each tuple
+contains four values: the type, the quantifier, the name, and a tuple
+of children.  Children are simply additional content module
+descriptions.
+
+The values of the first two fields are constants defined in the
+\code{model} object of the \module{xml.parsers.expat} module.  These
+constants can be collected in two groups: the model type group and the
+quantifier group.
+
+The constants in the model type group are:
+
+\begin{datadescni}{XML_CTYPE_ANY}
+The element named by the model name was declared to have a content
+model of \code{ANY}.
+\end{datadescni}
+
+\begin{datadescni}{XML_CTYPE_CHOICE}
+The named element allows a choice from a number of options; this is
+used for content models such as \code{(A | B | C)}.
+\end{datadescni}
+
+\begin{datadescni}{XML_CTYPE_EMPTY}
+Elements which are declared to be \code{EMPTY} have this model type.
+\end{datadescni}
+
+\begin{datadescni}{XML_CTYPE_MIXED}
+\end{datadescni}
+
+\begin{datadescni}{XML_CTYPE_NAME}
+\end{datadescni}
+
+\begin{datadescni}{XML_CTYPE_SEQ}
+Models which represent a series of models which follow one after the
+other are indicated with this model type.  This is used for models
+such as \code{(A, B, C)}.
+\end{datadescni}
+
+
+The constants in the quantifier group are:
+
+\begin{datadescni}{XML_CQUANT_NONE}
+No modifier is given, so it can appear exactly once, as for \code{A}.
+\end{datadescni}
+
+\begin{datadescni}{XML_CQUANT_OPT}
+The model is optional: it can appear once or not at all, as for
+\code{A?}.
+\end{datadescni}
+
+\begin{datadescni}{XML_CQUANT_PLUS}
+The model must occur one or more times (like \code{A+}).
+\end{datadescni}
+
+\begin{datadescni}{XML_CQUANT_REP}
+The model must occur zero or more times, as for \code{A*}.
+\end{datadescni}
+
+
+\subsection{Expat error constants \label{expat-errors}}
+
+The following constants are provided in the \code{errors} object of
+the \refmodule{xml.parsers.expat} module.  These constants are useful
+in interpreting some of the attributes of the \exception{ExpatError}
+exception objects raised when an error has occurred.
+
+The \code{errors} object has the following attributes:
+
+\begin{datadescni}{XML_ERROR_ASYNC_ENTITY}
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF}
+An entity reference in an attribute value referred to an external
+entity instead of an internal entity.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_BAD_CHAR_REF}
+A character reference referred to a character which is illegal in XML
+(for example, character \code{0}, or `\code{\&\#0;}').
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_BINARY_ENTITY_REF}
+An entity reference referred to an entity which was declared with a
+notation, so cannot be parsed.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_DUPLICATE_ATTRIBUTE}
+An attribute was used more than once in a start tag.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_INCORRECT_ENCODING}
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_INVALID_TOKEN}
+Raised when an input byte could not properly be assigned to a
+character; for example, a NUL byte (value \code{0}) in a UTF-8 input
+stream.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_JUNK_AFTER_DOC_ELEMENT}
+Something other than whitespace occurred after the document element.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_MISPLACED_XML_PI}
+An XML declaration was found somewhere other than the start of the
+input data.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_NO_ELEMENTS}
+The document contains no elements (XML requires all documents to
+contain exactly one top-level element)..
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_NO_MEMORY}
+Expat was not able to allocate memory internally.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_PARAM_ENTITY_REF}
+A parameter entity reference was found where it was not allowed.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_PARTIAL_CHAR}
+An incomplete character was found in the input.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_RECURSIVE_ENTITY_REF}
+An entity reference contained another reference to the same entity;
+possibly via a different name, and possibly indirectly.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_SYNTAX}
+Some unspecified syntax error was encountered.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_TAG_MISMATCH}
+An end tag did not match the innermost open start tag.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_UNCLOSED_TOKEN}
+Some token (such as a start tag) was not closed before the end of the
+stream or the next token was encountered.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_UNDEFINED_ENTITY}
+A reference was made to a entity which was not defined.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_UNKNOWN_ENCODING}
+The document encoding is not supported by Expat.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_UNCLOSED_CDATA_SECTION}
+A CDATA marked section was not closed.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_EXTERNAL_ENTITY_HANDLING}
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_NOT_STANDALONE}
+The parser determined that the document was not ``standalone'' though
+it declared itself to be in the XML declaration, and the
+\member{NotStandaloneHandler} was set and returned \code{0}.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_UNEXPECTED_STATE}
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_ENTITY_DECLARED_IN_PE}
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_FEATURE_REQUIRES_XML_DTD}
+An operation was requested that requires DTD support to be compiled
+in, but Expat was configured without DTD support.  This should never
+be reported by a standard build of the \module{xml.parsers.expat}
+module.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING}
+A behavioral change was requested after parsing started that can only
+be changed before parsing has started.  This is (currently) only
+raised by \method{UseForeignDTD()}.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_UNBOUND_PREFIX}
+An undeclared prefix was found when namespace processing was enabled.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_UNDECLARING_PREFIX}
+The document attempted to remove the namespace declaration associated
+with a prefix.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_INCOMPLETE_PE}
+A parameter entity contained incomplete markup.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_XML_DECL}
+The document contained no document element at all.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_TEXT_DECL}
+There was an error parsing a text declaration in an external entity.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_PUBLICID}
+Characters were found in the public id that are not allowed.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_SUSPENDED}
+The requested operation was made on a suspended parser, but isn't
+allowed.  This includes attempts to provide additional input or to
+stop the parser.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_NOT_SUSPENDED}
+An attempt to resume the parser was made when the parser had not been
+suspended.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_ABORTED}
+This should not be reported to Python applications.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_FINISHED}
+The requested operation was made on a parser which was finished
+parsing input, but isn't allowed.  This includes attempts to provide
+additional input or to stop the parser.
+\end{datadescni}
+
+\begin{datadescni}{XML_ERROR_SUSPEND_PE}
+\end{datadescni}
diff --git a/sys/src/cmd/python/Doc/lib/libpython.tex b/sys/src/cmd/python/Doc/lib/libpython.tex
new file mode 100644
index 000000000..c41c38678
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libpython.tex
@@ -0,0 +1,8 @@
+\chapter{Python Runtime Services
+         \label{python}}
+
+The modules described in this chapter provide a wide range of services
+related to the Python interpreter and its interaction with its
+environment.  Here's an overview:
+
+\localmoduletable
diff --git a/sys/src/cmd/python/Doc/lib/libqueue.tex b/sys/src/cmd/python/Doc/lib/libqueue.tex
new file mode 100644
index 000000000..95ad47f47
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libqueue.tex
@@ -0,0 +1,145 @@
+
+\section{\module{Queue} ---
+         A synchronized queue class}
+
+\declaremodule{standard}{Queue}
+\modulesynopsis{A synchronized queue class.}
+
+
+The \module{Queue} module implements a multi-producer, multi-consumer
+FIFO queue.  It is especially useful in threads programming when
+information must be exchanged safely between multiple threads.  The
+\class{Queue} class in this module implements all the required locking
+semantics.  It depends on the availability of thread support in
+Python.
+
+The \module{Queue} module defines the following class and exception:
+
+
+\begin{classdesc}{Queue}{maxsize}
+Constructor for the class.  \var{maxsize} is an integer that sets the
+upperbound limit on the number of items that can be placed in the
+queue.  Insertion will block once this size has been reached, until
+queue items are consumed.  If \var{maxsize} is less than or equal to
+zero, the queue size is infinite.
+\end{classdesc}
+
+\begin{excdesc}{Empty}
+Exception raised when non-blocking \method{get()} (or
+\method{get_nowait()}) is called on a \class{Queue} object which is
+empty.
+\end{excdesc}
+
+\begin{excdesc}{Full}
+Exception raised when non-blocking \method{put()} (or
+\method{put_nowait()}) is called on a \class{Queue} object which is
+full.
+\end{excdesc}
+
+\subsection{Queue Objects}
+\label{QueueObjects}
+
+Class \class{Queue} implements queue objects and has the methods
+described below.  This class can be derived from in order to implement
+other queue organizations (e.g. stack) but the inheritable interface
+is not described here.  See the source code for details.  The public
+methods are:
+
+\begin{methoddesc}{qsize}{}
+Return the approximate size of the queue.  Because of multithreading
+semantics, this number is not reliable.
+\end{methoddesc}
+
+\begin{methoddesc}{empty}{}
+Return \code{True} if the queue is empty, \code{False} otherwise.
+Because of multithreading semantics, this is not reliable.
+\end{methoddesc}
+
+\begin{methoddesc}{full}{}
+Return \code{True} if the queue is full, \code{False} otherwise.
+Because of multithreading semantics, this is not reliable.
+\end{methoddesc}
+
+\begin{methoddesc}{put}{item\optional{, block\optional{, timeout}}}
+Put \var{item} into the queue. If optional args \var{block} is true
+and \var{timeout} is None (the default), block if necessary until a
+free slot is available. If \var{timeout} is a positive number, it
+blocks at most \var{timeout} seconds and raises the \exception{Full}
+exception if no free slot was available within that time.
+Otherwise (\var{block} is false), put an item on the queue if a free
+slot is immediately available, else raise the \exception{Full}
+exception (\var{timeout} is ignored in that case).
+
+\versionadded[the timeout parameter]{2.3}
+
+\end{methoddesc}
+
+\begin{methoddesc}{put_nowait}{item}
+Equivalent to \code{put(\var{item}, False)}.
+\end{methoddesc}
+
+\begin{methoddesc}{get}{\optional{block\optional{, timeout}}}
+Remove and return an item from the queue. If optional args
+\var{block} is true and \var{timeout} is None (the default),
+block if necessary until an item is available. If \var{timeout} is
+a positive number, it blocks at most \var{timeout} seconds and raises
+the \exception{Empty} exception if no item was available within that
+time. Otherwise (\var{block} is false), return an item if one is
+immediately available, else raise the \exception{Empty} exception
+(\var{timeout} is ignored in that case).
+
+\versionadded[the timeout parameter]{2.3}
+
+\end{methoddesc}
+
+\begin{methoddesc}{get_nowait}{}
+Equivalent to \code{get(False)}.
+\end{methoddesc}
+
+Two methods are offered to support tracking whether enqueued tasks have
+been fully processed by daemon consumer threads.
+
+\begin{methoddesc}{task_done}{}
+Indicate that a formerly enqueued task is complete.  Used by queue consumer
+threads.  For each \method{get()} used to fetch a task, a subsequent call to
+\method{task_done()} tells the queue that the processing on the task is complete.
+
+If a \method{join()} is currently blocking, it will resume when all items
+have been processed (meaning that a \method{task_done()} call was received
+for every item that had been \method{put()} into the queue).
+
+Raises a \exception{ValueError} if called more times than there were items
+placed in the queue.
+\versionadded{2.5}
+\end{methoddesc}
+
+\begin{methoddesc}{join}{}
+Blocks until all items in the queue have been gotten and processed.
+
+The count of unfinished tasks goes up whenever an item is added to the
+queue. The count goes down whenever a consumer thread calls \method{task_done()}
+to indicate that the item was retrieved and all work on it is complete.
+When the count of unfinished tasks drops to zero, join() unblocks.
+\versionadded{2.5}
+\end{methoddesc}
+
+Example of how to wait for enqueued tasks to be completed:
+
+\begin{verbatim}
+    def worker(): 
+        while True: 
+            item = q.get() 
+            do_work(item) 
+            q.task_done() 
+
+    q = Queue() 
+    for i in range(num_worker_threads): 
+         t = Thread(target=worker)
+         t.setDaemon(True)
+         t.start() 
+
+    for item in source():
+        q.put(item) 
+
+    q.join()       # block until all tasks are done
+\end{verbatim}
diff --git a/sys/src/cmd/python/Doc/lib/libquopri.tex b/sys/src/cmd/python/Doc/lib/libquopri.tex
new file mode 100644
index 000000000..9e7895bd9
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libquopri.tex
@@ -0,0 +1,61 @@
+\section{\module{quopri} ---
+         Encode and decode MIME quoted-printable data}
+
+\declaremodule{standard}{quopri}
+\modulesynopsis{Encode and decode files using the MIME
+                quoted-printable encoding.}
+
+
+This module performs quoted-printable transport encoding and decoding,
+as defined in \rfc{1521}: ``MIME (Multipurpose Internet Mail
+Extensions) Part One: Mechanisms for Specifying and Describing the
+Format of Internet Message Bodies''.  The quoted-printable encoding is
+designed for data where there are relatively few nonprintable
+characters; the base64 encoding scheme available via the
+\refmodule{base64} module is more compact if there are many such
+characters, as when sending a graphics file.
+\indexii{quoted-printable}{encoding}
+\index{MIME!quoted-printable encoding}
+
+
+\begin{funcdesc}{decode}{input, output\optional{,header}}
+Decode the contents of the \var{input} file and write the resulting
+decoded binary data to the \var{output} file.
+\var{input} and \var{output} must either be file objects or objects that
+mimic the file object interface. \var{input} will be read until
+\code{\var{input}.readline()} returns an empty string.
+If the optional argument \var{header} is present and true, underscore
+will be decoded as space. This is used to decode
+``Q''-encoded headers as described in \rfc{1522}: ``MIME (Multipurpose Internet Mail Extensions)
+Part Two: Message Header Extensions for Non-ASCII Text''.
+\end{funcdesc}
+
+\begin{funcdesc}{encode}{input, output, quotetabs}
+Encode the contents of the \var{input} file and write the resulting
+quoted-printable data to the \var{output} file.
+\var{input} and \var{output} must either be file objects or objects that
+mimic the file object interface. \var{input} will be read until
+\code{\var{input}.readline()} returns an empty string.
+\var{quotetabs} is a flag which controls whether to encode embedded
+spaces and tabs; when true it encodes such embedded whitespace, and
+when false it leaves them unencoded.  Note that spaces and tabs
+appearing at the end of lines are always encoded, as per \rfc{1521}.
+\end{funcdesc}
+
+\begin{funcdesc}{decodestring}{s\optional{,header}}
+Like \function{decode()}, except that it accepts a source string and
+returns the corresponding decoded string.
+\end{funcdesc}
+
+\begin{funcdesc}{encodestring}{s\optional{, quotetabs}}
+Like \function{encode()}, except that it accepts a source string and
+returns the corresponding encoded string.  \var{quotetabs} is optional
+(defaulting to 0), and is passed straight through to
+\function{encode()}.
+\end{funcdesc}
+
+
+\begin{seealso}
+  \seemodule{mimify}{General utilities for processing of MIME messages.}
+  \seemodule{base64}{Encode and decode MIME base64 data}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/librandom.tex b/sys/src/cmd/python/Doc/lib/librandom.tex
new file mode 100644
index 000000000..78c536b32
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/librandom.tex
@@ -0,0 +1,309 @@
+\section{\module{random} ---
+         Generate pseudo-random numbers}
+
+\declaremodule{standard}{random}
+\modulesynopsis{Generate pseudo-random numbers with various common
+                distributions.}
+
+
+This module implements pseudo-random number generators for various
+distributions.
+
+For integers, uniform selection from a range.
+For sequences, uniform selection of a random element, a function to
+generate a random permutation of a list in-place, and a function for
+random sampling without replacement.
+
+On the real line, there are functions to compute uniform, normal (Gaussian),
+lognormal, negative exponential, gamma, and beta distributions.
+For generating distributions of angles, the von Mises distribution
+is available.
+
+Almost all module functions depend on the basic function
+\function{random()}, which generates a random float uniformly in
+the semi-open range [0.0, 1.0).  Python uses the Mersenne Twister as
+the core generator.  It produces 53-bit precision floats and has a
+period of 2**19937-1.  The underlying implementation in C
+is both fast and threadsafe.  The Mersenne Twister is one of the most
+extensively tested random number generators in existence.  However, being
+completely deterministic, it is not suitable for all purposes, and is
+completely unsuitable for cryptographic purposes.
+
+The functions supplied by this module are actually bound methods of a
+hidden instance of the \class{random.Random} class.  You can
+instantiate your own instances of \class{Random} to get generators
+that don't share state.  This is especially useful for multi-threaded
+programs, creating a different instance of \class{Random} for each
+thread, and using the \method{jumpahead()} method to make it likely that the
+generated sequences seen by each thread don't overlap.
+
+Class \class{Random} can also be subclassed if you want to use a
+different basic generator of your own devising: in that case, override
+the \method{random()}, \method{seed()}, \method{getstate()},
+\method{setstate()} and \method{jumpahead()} methods.
+Optionally, a new generator can supply a \method{getrandombits()}
+method --- this allows \method{randrange()} to produce selections
+over an arbitrarily large range.
+\versionadded[the \method{getrandombits()} method]{2.4}
+
+As an example of subclassing, the \module{random} module provides
+the \class{WichmannHill} class that implements an alternative generator
+in pure Python.  The class provides a backward compatible way to
+reproduce results from earlier versions of Python, which used the
+Wichmann-Hill algorithm as the core generator.  Note that this Wichmann-Hill
+generator can no longer be recommended:  its period is too short by
+contemporary standards, and the sequence generated is known to fail some
+stringent randomness tests.  See the references below for a recent
+variant that repairs these flaws.
+\versionchanged[Substituted MersenneTwister for Wichmann-Hill]{2.3}
+
+
+Bookkeeping functions:
+
+\begin{funcdesc}{seed}{\optional{x}}
+  Initialize the basic random number generator.
+  Optional argument \var{x} can be any hashable object.
+  If \var{x} is omitted or \code{None}, current system time is used;
+  current system time is also used to initialize the generator when the
+  module is first imported.  If randomness sources are provided by the
+  operating system, they are used instead of the system time (see the
+  \function{os.urandom()}
+  function for details on availability).  \versionchanged[formerly,
+  operating system resources were not used]{2.4}
+  If \var{x} is not \code{None} or an int or long,
+  \code{hash(\var{x})} is used instead.
+  If \var{x} is an int or long, \var{x} is used directly.
+\end{funcdesc}
+
+\begin{funcdesc}{getstate}{}
+  Return an object capturing the current internal state of the
+  generator.  This object can be passed to \function{setstate()} to
+  restore the state.
+  \versionadded{2.1}
+\end{funcdesc}
+
+\begin{funcdesc}{setstate}{state}
+  \var{state} should have been obtained from a previous call to
+  \function{getstate()}, and \function{setstate()} restores the
+  internal state of the generator to what it was at the time
+  \function{setstate()} was called.
+  \versionadded{2.1}
+\end{funcdesc}
+
+\begin{funcdesc}{jumpahead}{n}
+  Change the internal state to one different from and likely far away from
+  the current state.  \var{n} is a non-negative integer which is used to
+  scramble the current state vector.  This is most useful in multi-threaded
+  programs, in conjuction with multiple instances of the \class{Random}
+  class: \method{setstate()} or \method{seed()} can be used to force all
+  instances into the same internal state, and then \method{jumpahead()}
+  can be used to force the instances' states far apart.
+  \versionadded{2.1}
+  \versionchanged[Instead of jumping to a specific state, \var{n} steps
+  ahead, \method{jumpahead(\var{n})} jumps to another state likely to be
+  separated by many steps]{2.3}
+ \end{funcdesc}
+
+\begin{funcdesc}{getrandbits}{k}
+  Returns a python \class{long} int with \var{k} random bits.
+  This method is supplied with the MersenneTwister generator and some
+  other generators may also provide it as an optional part of the API.
+  When available, \method{getrandbits()} enables \method{randrange()}
+  to handle arbitrarily large ranges.
+  \versionadded{2.4}
+\end{funcdesc}
+
+Functions for integers:
+
+\begin{funcdesc}{randrange}{\optional{start,} stop\optional{, step}}
+  Return a randomly selected element from \code{range(\var{start},
+  \var{stop}, \var{step})}.  This is equivalent to
+  \code{choice(range(\var{start}, \var{stop}, \var{step}))},
+  but doesn't actually build a range object.
+  \versionadded{1.5.2}
+\end{funcdesc}
+
+\begin{funcdesc}{randint}{a, b}
+  Return a random integer \var{N} such that
+  \code{\var{a} <= \var{N} <= \var{b}}.
+\end{funcdesc}
+
+
+Functions for sequences:
+
+\begin{funcdesc}{choice}{seq}
+  Return a random element from the non-empty sequence \var{seq}.
+  If \var{seq} is empty, raises \exception{IndexError}.
+\end{funcdesc}
+
+\begin{funcdesc}{shuffle}{x\optional{, random}}
+  Shuffle the sequence \var{x} in place.
+  The optional argument \var{random} is a 0-argument function
+  returning a random float in [0.0, 1.0); by default, this is the
+  function \function{random()}.
+
+  Note that for even rather small \code{len(\var{x})}, the total
+  number of permutations of \var{x} is larger than the period of most
+  random number generators; this implies that most permutations of a
+  long sequence can never be generated.
+\end{funcdesc}
+
+\begin{funcdesc}{sample}{population, k}
+  Return a \var{k} length list of unique elements chosen from the
+  population sequence.  Used for random sampling without replacement.
+  \versionadded{2.3}
+
+  Returns a new list containing elements from the population while
+  leaving the original population unchanged.  The resulting list is
+  in selection order so that all sub-slices will also be valid random
+  samples.  This allows raffle winners (the sample) to be partitioned
+  into grand prize and second place winners (the subslices).
+
+  Members of the population need not be hashable or unique.  If the
+  population contains repeats, then each occurrence is a possible
+  selection in the sample.
+
+  To choose a sample from a range of integers, use an \function{xrange()}
+  object as an argument.  This is especially fast and space efficient for
+  sampling from a large population:  \code{sample(xrange(10000000), 60)}.
+\end{funcdesc}
+
+
+The following functions generate specific real-valued distributions.
+Function parameters are named after the corresponding variables in the
+distribution's equation, as used in common mathematical practice; most of
+these equations can be found in any statistics text.
+
+\begin{funcdesc}{random}{}
+  Return the next random floating point number in the range [0.0, 1.0).
+\end{funcdesc}
+
+\begin{funcdesc}{uniform}{a, b}
+  Return a random real number \var{N} such that
+  \code{\var{a} <= \var{N} < \var{b}}.
+\end{funcdesc}
+
+\begin{funcdesc}{betavariate}{alpha, beta}
+  Beta distribution.  Conditions on the parameters are
+  \code{\var{alpha} > 0} and \code{\var{beta} > 0}.
+  Returned values range between 0 and 1.
+\end{funcdesc}
+
+\begin{funcdesc}{expovariate}{lambd}
+  Exponential distribution.  \var{lambd} is 1.0 divided by the desired
+  mean.  (The parameter would be called ``lambda'', but that is a
+  reserved word in Python.)  Returned values range from 0 to
+  positive infinity.
+\end{funcdesc}
+
+\begin{funcdesc}{gammavariate}{alpha, beta}
+  Gamma distribution.  (\emph{Not} the gamma function!)  Conditions on
+  the parameters are \code{\var{alpha} > 0} and \code{\var{beta} > 0}.
+\end{funcdesc}
+
+\begin{funcdesc}{gauss}{mu, sigma}
+  Gaussian distribution.  \var{mu} is the mean, and \var{sigma} is the
+  standard deviation.  This is slightly faster than the
+  \function{normalvariate()} function defined below.
+\end{funcdesc}
+
+\begin{funcdesc}{lognormvariate}{mu, sigma}
+  Log normal distribution.  If you take the natural logarithm of this
+  distribution, you'll get a normal distribution with mean \var{mu}
+  and standard deviation \var{sigma}.  \var{mu} can have any value,
+  and \var{sigma} must be greater than zero.
+\end{funcdesc}
+
+\begin{funcdesc}{normalvariate}{mu, sigma}
+  Normal distribution.  \var{mu} is the mean, and \var{sigma} is the
+  standard deviation.
+\end{funcdesc}
+
+\begin{funcdesc}{vonmisesvariate}{mu, kappa}
+  \var{mu} is the mean angle, expressed in radians between 0 and
+  2*\emph{pi}, and \var{kappa} is the concentration parameter, which
+  must be greater than or equal to zero.  If \var{kappa} is equal to
+  zero, this distribution reduces to a uniform random angle over the
+  range 0 to 2*\emph{pi}.
+\end{funcdesc}
+
+\begin{funcdesc}{paretovariate}{alpha}
+  Pareto distribution.  \var{alpha} is the shape parameter.
+\end{funcdesc}
+
+\begin{funcdesc}{weibullvariate}{alpha, beta}
+  Weibull distribution.  \var{alpha} is the scale parameter and
+  \var{beta} is the shape parameter.
+\end{funcdesc}
+
+Alternative Generators:
+
+\begin{classdesc}{WichmannHill}{\optional{seed}}
+Class that implements the Wichmann-Hill algorithm as the core generator.
+Has all of the same methods as \class{Random} plus the \method{whseed()}
+method described below.  Because this class is implemented in pure
+Python, it is not threadsafe and may require locks between calls.  The
+period of the generator is 6,953,607,871,644 which is small enough to
+require care that two independent random sequences do not overlap.
+\end{classdesc}
+
+\begin{funcdesc}{whseed}{\optional{x}}
+  This is obsolete, supplied for bit-level compatibility with versions
+  of Python prior to 2.1.
+  See \function{seed()} for details.  \function{whseed()} does not guarantee
+  that distinct integer arguments yield distinct internal states, and can
+  yield no more than about 2**24 distinct internal states in all.
+\end{funcdesc}
+
+\begin{classdesc}{SystemRandom}{\optional{seed}}
+Class that uses the \function{os.urandom()} function for generating
+random numbers from sources provided by the operating system.
+Not available on all systems.
+Does not rely on software state and sequences are not reproducible.
+Accordingly, the \method{seed()} and \method{jumpahead()} methods
+have no effect and are ignored.  The \method{getstate()} and
+\method{setstate()} methods raise \exception{NotImplementedError} if
+called.
+\versionadded{2.4}
+\end{classdesc}
+
+Examples of basic usage:
+
+\begin{verbatim}
+>>> random.random()        # Random float x, 0.0 <= x < 1.0
+0.37444887175646646
+>>> random.uniform(1, 10)  # Random float x, 1.0 <= x < 10.0
+1.1800146073117523
+>>> random.randint(1, 10)  # Integer from 1 to 10, endpoints included
+7
+>>> random.randrange(0, 101, 2)  # Even integer from 0 to 100
+26
+>>> random.choice('abcdefghij')  # Choose a random element
+'c'
+
+>>> items = [1, 2, 3, 4, 5, 6, 7]
+>>> random.shuffle(items)
+>>> items
+[7, 3, 2, 5, 6, 4, 1]
+
+>>> random.sample([1, 2, 3, 4, 5],  3)  # Choose 3 elements
+[4, 1, 5]
+
+\end{verbatim}
+
+\begin{seealso}
+  \seetext{M. Matsumoto and T. Nishimura, ``Mersenne Twister: A
+	   623-dimensionally equidistributed uniform pseudorandom
+	   number generator'',
+	   \citetitle{ACM Transactions on Modeling and Computer Simulation}
+	   Vol. 8, No. 1, January pp.3-30 1998.}
+
+  \seetext{Wichmann, B. A. \& Hill, I. D., ``Algorithm AS 183:
+           An efficient and portable pseudo-random number generator'',
+           \citetitle{Applied Statistics} 31 (1982) 188-190.}
+
+  \seeurl{http://www.npl.co.uk/ssfm/download/abstracts.html\#196}{A modern
+          variation of the Wichmann-Hill generator that greatly increases
+          the period, and passes now-standard statistical tests that the
+          original generator failed.}
+\end{seealso}
diff --git a/sys/src/cmd/python/Doc/lib/libre.tex b/sys/src/cmd/python/Doc/lib/libre.tex
new file mode 100644
index 000000000..84e382d0f
--- /dev/null
+++ b/sys/src/cmd/python/Doc/lib/libre.tex
@@ -0,0 +1,954 @@
+\section{\module{re} ---
+         Regular expression operations}
+\declaremodule{standard}{re}
+\moduleauthor{Fredrik Lundh}{fredrik@pythonware.com}
+\sectionauthor{Andrew M. Kuchling}{amk@amk.ca}
+
+
+\modulesynopsis{Regular expression search and match operations with a
+                Perl-style expression syntax.}
+
+
+This module provides regular expression matching operations similar to
+those found in Perl.  Regular expression pattern strings may not
+contain null bytes, but can specify the null byte using the
+\code{\e\var{number}} notation.  Both patterns and strings to be
+searched can be Unicode strings as well as 8-bit strings.  The
+\module{re} module is always available.
+
+Regular expressions use the backslash character (\character{\e}) to
+indicate special forms or to allow special characters to be used
+without invoking their special meaning.  This collides with Python's
+usage of the same character for the same purpose in string literals;
+for example, to match a literal backslash, one might have to write
+\code{'\e\e\e\e'} as the pattern string, because the regular expression
+must be \samp{\e\e}, and each backslash must be expressed as
+\samp{\e\e} inside a regular Python string literal.
+
+The solution is to use Python's raw string notation for regular
+expression patterns; backslashes are not handled in any special way in
+a string literal prefixed with \character{r}.  So \code{r"\e n"} is a
+two-character string containing \character{\e} and \character{n},
+while \code{"\e n"} is a one-character string containing a newline.
+Usually patterns will be expressed in Python code using this raw
+string notation.
+
+\begin{seealso}
+  \seetitle{Mastering Regular Expressions}{Book on regular expressions
+            by Jeffrey Friedl, published by O'Reilly.  The second 
+            edition of the book no longer covers Python at all, 
+            but the first edition covered writing good regular expression
+            patterns in great detail.}
+\end{seealso}
+
+
+\subsection{Regular Expression Syntax \label{re-syntax}}
+
+A regular expression (or RE) specifies a set of strings that matches
+it; the functions in this module let you check if a particular string
+matches a given regular expression (or if a given regular expression
+matches a particular string, which comes down to the same thing).
+
+Regular expressions can be concatenated to form new regular
+expressions; if \emph{A} and \emph{B} are both regular expressions,
+then \emph{AB} is also a regular expression.  In general, if a string
+\emph{p} matches \emph{A} and another string \emph{q} matches \emph{B},
+the string \emph{pq} will match AB.  This holds unless \emph{A} or
+\emph{B} contain low precedence operations; boundary conditions between
+\emph{A} and \emph{B}; or have numbered group references.  Thus, complex
+expressions can easily be constructed from simpler primitive
+expressions like the ones described here.  For details of the theory
+and implementation of regular expressions, consult the Friedl book
+referenced above, or almost any textbook about compiler construction.
+
+A brief explanation of the format of regular expressions follows.  For
+further information and a gentler presentation, consult the Regular
+Expression HOWTO, accessible from \url{http://www.python.org/doc/howto/}.
+
+Regular expressions can contain both special and ordinary characters.
+Most ordinary characters, like \character{A}, \character{a}, or
+\character{0}, are the simplest regular expressions; they simply match
+themselves.  You can concatenate ordinary characters, so \regexp{last}
+matches the string \code{'last'}.  (In the rest of this section, we'll
+write RE's in \regexp{this special style}, usually without quotes, and
+strings to be matched \code{'in single quotes'}.)
+
+Some characters, like \character{|} or \character{(}, are special.
+Special characters either stand for classes of ordinary characters, or
+affect how the regular expressions around them are interpreted.
+
+The special characters are:
+%
+\begin{description}
+
+\item[\character{.}] (Dot.)  In the default mode, this matches any
+character except a newline.  If the \constant{DOTALL} flag has been
+specified, this matches any character including a newline.
+
+\item[\character{\textasciicircum}] (Caret.)  Matches the start of the
+string, and in \constant{MULTILINE} mode also matches immediately
+after each newline.
+
+\item[\character{\$}] Matches the end of the string or just before the
+newline at the end of the string, and in \constant{MULTILINE} mode
+also matches before a newline.  \regexp{foo} matches both 'foo' and
+'foobar', while the regular expression \regexp{foo\$} matches only
+'foo'.  More interestingly, searching for \regexp{foo.\$} in
+'foo1\textbackslash nfoo2\textbackslash n' matches 'foo2' normally,
+but 'foo1' in \constant{MULTILINE} mode.
+
+\item[\character{*}] Causes the resulting RE to
+match 0 or more repetitions of the preceding RE, as many repetitions
+as are possible.  \regexp{ab*} will
+match 'a', 'ab', or 'a' followed by any number of 'b's.
+
+\item[\character{+}] Causes the
+resulting RE to match 1 or more repetitions of the preceding RE.
+\regexp{ab+} will match 'a' followed by any non-zero number of 'b's; it
+will not match just 'a'.
+
+\item[\character{?}] Causes the resulting RE to
+match 0 or 1 repetitions of the preceding RE.  \regexp{ab?} will
+match either 'a' or 'ab'.
+
+\item[\code{*?}, \code{+?}, \code{??}] The \character{*},
+\character{+}, and \character{?} qualifiers are all \dfn{greedy}; they
+match as much text as possible.  Sometimes this behaviour isn't
+desired; if the RE \regexp{<.*>} is matched against
+\code{'

title

'}, it will match the entire string, and not just +\code{'

'}. Adding \character{?} after the qualifier makes it +perform the match in \dfn{non-greedy} or \dfn{minimal} fashion; as +\emph{few} characters as possible will be matched. Using \regexp{.*?} +in the previous expression will match only \code{'

'}. + +\item[\code{\{\var{m}\}}] +Specifies that exactly \var{m} copies of the previous RE should be +matched; fewer matches cause the entire RE not to match. For example, +\regexp{a\{6\}} will match exactly six \character{a} characters, but +not five. + +\item[\code{\{\var{m},\var{n}\}}] Causes the resulting RE to match from +\var{m} to \var{n} repetitions of the preceding RE, attempting to +match as many repetitions as possible. For example, \regexp{a\{3,5\}} +will match from 3 to 5 \character{a} characters. Omitting \var{m} +specifies a lower bound of zero, +and omitting \var{n} specifies an infinite upper bound. As an +example, \regexp{a\{4,\}b} will match \code{aaaab} or a thousand +\character{a} characters followed by a \code{b}, but not \code{aaab}. +The comma may not be omitted or the modifier would be confused with +the previously described form. + +\item[\code{\{\var{m},\var{n}\}?}] Causes the resulting RE to +match from \var{m} to \var{n} repetitions of the preceding RE, +attempting to match as \emph{few} repetitions as possible. This is +the non-greedy version of the previous qualifier. For example, on the +6-character string \code{'aaaaaa'}, \regexp{a\{3,5\}} will match 5 +\character{a} characters, while \regexp{a\{3,5\}?} will only match 3 +characters. + +\item[\character{\e}] Either escapes special characters (permitting +you to match characters like \character{*}, \character{?}, and so +forth), or signals a special sequence; special sequences are discussed +below. + +If you're not using a raw string to +express the pattern, remember that Python also uses the +backslash as an escape sequence in string literals; if the escape +sequence isn't recognized by Python's parser, the backslash and +subsequent character are included in the resulting string. However, +if Python would recognize the resulting sequence, the backslash should +be repeated twice. This is complicated and hard to understand, so +it's highly recommended that you use raw strings for all but the +simplest expressions. + +\item[\code{[]}] Used to indicate a set of characters. Characters can +be listed individually, or a range of characters can be indicated by +giving two characters and separating them by a \character{-}. Special +characters are not active inside sets. For example, \regexp{[akm\$]} +will match any of the characters \character{a}, \character{k}, +\character{m}, or \character{\$}; \regexp{[a-z]} +will match any lowercase letter, and \code{[a-zA-Z0-9]} matches any +letter or digit. Character classes such as \code{\e w} or \code{\e S} +(defined below) are also acceptable inside a range. If you want to +include a \character{]} or a \character{-} inside a set, precede it with a +backslash, or place it as the first character. The +pattern \regexp{[]]} will match \code{']'}, for example. + +You can match the characters not within a range by \dfn{complementing} +the set. This is indicated by including a +\character{\textasciicircum} as the first character of the set; +\character{\textasciicircum} elsewhere will simply match the +\character{\textasciicircum} character. For example, +\regexp{[{\textasciicircum}5]} will match +any character except \character{5}, and +\regexp{[\textasciicircum\code{\textasciicircum}]} will match any character +except \character{\textasciicircum}. + +\item[\character{|}]\code{A|B}, where A and B can be arbitrary REs, +creates a regular expression that will match either A or B. An +arbitrary number of REs can be separated by the \character{|} in this +way. This can be used inside groups (see below) as well. As the target +string is scanned, REs separated by \character{|} are tried from left to +right. When one pattern completely matches, that branch is accepted. +This means that once \code{A} matches, \code{B} will not be tested further, +even if it would produce a longer overall match. In other words, the +\character{|} operator is never greedy. To match a literal \character{|}, +use \regexp{\e|}, or enclose it inside a character class, as in \regexp{[|]}. + +\item[\code{(...)}] Matches whatever regular expression is inside the +parentheses, and indicates the start and end of a group; the contents +of a group can be retrieved after a match has been performed, and can +be matched later in the string with the \regexp{\e \var{number}} special +sequence, described below. To match the literals \character{(} or +\character{)}, use \regexp{\e(} or \regexp{\e)}, or enclose them +inside a character class: \regexp{[(] [)]}. + +\item[\code{(?...)}] This is an extension notation (a \character{?} +following a \character{(} is not meaningful otherwise). The first +character after the \character{?} +determines what the meaning and further syntax of the construct is. +Extensions usually do not create a new group; +\regexp{(?P<\var{name}>...)} is the only exception to this rule. +Following are the currently supported extensions. + +\item[\code{(?iLmsux)}] (One or more letters from the set \character{i}, +\character{L}, \character{m}, \character{s}, \character{u}, +\character{x}.) The group matches the empty string; the letters set +the corresponding flags (\constant{re.I}, \constant{re.L}, +\constant{re.M}, \constant{re.S}, \constant{re.U}, \constant{re.X}) +for the entire regular expression. This is useful if you wish to +include the flags as part of the regular expression, instead of +passing a \var{flag} argument to the \function{compile()} function. + +Note that the \regexp{(?x)} flag changes how the expression is parsed. +It should be used first in the expression string, or after one or more +whitespace characters. If there are non-whitespace characters before +the flag, the results are undefined. + +\item[\code{(?:...)}] A non-grouping version of regular parentheses. +Matches whatever regular expression is inside the parentheses, but the +substring matched by the +group \emph{cannot} be retrieved after performing a match or +referenced later in the pattern. + +\item[\code{(?P<\var{name}>...)}] Similar to regular parentheses, but +the substring matched by the group is accessible via the symbolic group +name \var{name}. Group names must be valid Python identifiers, and +each group name must be defined only once within a regular expression. A +symbolic group is also a numbered group, just as if the group were not +named. So the group named 'id' in the example above can also be +referenced as the numbered group 1. + +For example, if the pattern is +\regexp{(?P[a-zA-Z_]\e w*)}, the group can be referenced by its +name in arguments to methods of match objects, such as +\code{m.group('id')} or \code{m.end('id')}, and also by name in +pattern text (for example, \regexp{(?P=id)}) and replacement text +(such as \code{\e g}). + +\item[\code{(?P=\var{name})}] Matches whatever text was matched by the +earlier group named \var{name}. + +\item[\code{(?\#...)}] A comment; the contents of the parentheses are +simply ignored. + +\item[\code{(?=...)}] Matches if \regexp{...} matches next, but doesn't +consume any of the string. This is called a lookahead assertion. For +example, \regexp{Isaac (?=Asimov)} will match \code{'Isaac~'} only if it's +followed by \code{'Asimov'}. + +\item[\code{(?!...)}] Matches if \regexp{...} doesn't match next. This +is a negative lookahead assertion. For example, +\regexp{Isaac (?!Asimov)} will match \code{'Isaac~'} only if it's \emph{not} +followed by \code{'Asimov'}. + +\item[\code{(?<=...)}] Matches if the current position in the string +is preceded by a match for \regexp{...} that ends at the current +position. This is called a \dfn{positive lookbehind assertion}. +\regexp{(?<=abc)def} will find a match in \samp{abcdef}, since the +lookbehind will back up 3 characters and check if the contained +pattern matches. The contained pattern must only match strings of +some fixed length, meaning that \regexp{abc} or \regexp{a|b} are +allowed, but \regexp{a*} and \regexp{a\{3,4\}} are not. Note that +patterns which start with positive lookbehind assertions will never +match at the beginning of the string being searched; you will most +likely want to use the \function{search()} function rather than the +\function{match()} function: + +\begin{verbatim} +>>> import re +>>> m = re.search('(?<=abc)def', 'abcdef') +>>> m.group(0) +'def' +\end{verbatim} + +This example looks for a word following a hyphen: + +\begin{verbatim} +>>> m = re.search('(?<=-)\w+', 'spam-egg') +>>> m.group(0) +'egg' +\end{verbatim} + +\item[\code{(?)} is a poor email matching +pattern, which will match with \code{''} as well as +\code{'user@host.com'}, but not with \code{'>> re.split('\W+', 'Words, words, words.') +['Words', 'words', 'words', ''] +>>> re.split('(\W+)', 'Words, words, words.') +['Words', ', ', 'words', ', ', 'words', '.', ''] +>>> re.split('\W+', 'Words, words, words.', 1) +['Words', 'words, words.'] +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{findall}{pattern, string\optional{, flags}} + Return a list of all non-overlapping matches of \var{pattern} in + \var{string}. If one or more groups are present in the pattern, + return a list of groups; this will be a list of tuples if the + pattern has more than one group. Empty matches are included in the + result unless they touch the beginning of another match. + \versionadded{1.5.2} + \versionchanged[Added the optional flags argument]{2.4} +\end{funcdesc} + +\begin{funcdesc}{finditer}{pattern, string\optional{, flags}} + Return an iterator over all non-overlapping matches for the RE + \var{pattern} in \var{string}. For each match, the iterator returns + a match object. Empty matches are included in the result unless they + touch the beginning of another match. + \versionadded{2.2} + \versionchanged[Added the optional flags argument]{2.4} +\end{funcdesc} + +\begin{funcdesc}{sub}{pattern, repl, string\optional{, count}} + Return the string obtained by replacing the leftmost non-overlapping + occurrences of \var{pattern} in \var{string} by the replacement + \var{repl}. If the pattern isn't found, \var{string} is returned + unchanged. \var{repl} can be a string or a function; if it is a + string, any backslash escapes in it are processed. That is, + \samp{\e n} is converted to a single newline character, \samp{\e r} + is converted to a linefeed, and so forth. Unknown escapes such as + \samp{\e j} are left alone. Backreferences, such as \samp{\e6}, are + replaced with the substring matched by group 6 in the pattern. For + example: + +\begin{verbatim} +>>> re.sub(r'def\s+([a-zA-Z_][a-zA-Z_0-9]*)\s*\(\s*\):', +... r'static PyObject*\npy_\1(void)\n{', +... 'def myfunc():') +'static PyObject*\npy_myfunc(void)\n{' +\end{verbatim} + + If \var{repl} is a function, it is called for every non-overlapping + occurrence of \var{pattern}. The function takes a single match + object argument, and returns the replacement string. For example: + +\begin{verbatim} +>>> def dashrepl(matchobj): +... if matchobj.group(0) == '-': return ' ' +... else: return '-' +>>> re.sub('-{1,2}', dashrepl, 'pro----gram-files') +'pro--gram files' +\end{verbatim} + + The pattern may be a string or an RE object; if you need to specify + regular expression flags, you must use a RE object, or use embedded + modifiers in a pattern; for example, \samp{sub("(?i)b+", "x", "bbbb + BBBB")} returns \code{'x x'}. + + The optional argument \var{count} is the maximum number of pattern + occurrences to be replaced; \var{count} must be a non-negative + integer. If omitted or zero, all occurrences will be replaced. + Empty matches for the pattern are replaced only when not adjacent to + a previous match, so \samp{sub('x*', '-', 'abc')} returns + \code{'-a-b-c-'}. + + In addition to character escapes and backreferences as described + above, \samp{\e g} will use the substring matched by the group + named \samp{name}, as defined by the \regexp{(?P...)} syntax. + \samp{\e g} uses the corresponding group number; + \samp{\e g<2>} is therefore equivalent to \samp{\e 2}, but isn't + ambiguous in a replacement such as \samp{\e g<2>0}. \samp{\e 20} + would be interpreted as a reference to group 20, not a reference to + group 2 followed by the literal character \character{0}. The + backreference \samp{\e g<0>} substitutes in the entire substring + matched by the RE. +\end{funcdesc} + +\begin{funcdesc}{subn}{pattern, repl, string\optional{, count}} + Perform the same operation as \function{sub()}, but return a tuple + \code{(\var{new_string}, \var{number_of_subs_made})}. +\end{funcdesc} + +\begin{funcdesc}{escape}{string} + Return \var{string} with all non-alphanumerics backslashed; this is + useful if you want to match an arbitrary literal string that may have + regular expression metacharacters in it. +\end{funcdesc} + +\begin{excdesc}{error} + Exception raised when a string passed to one of the functions here + is not a valid regular expression (for example, it might contain + unmatched parentheses) or when some other error occurs during + compilation or matching. It is never an error if a string contains + no match for a pattern. +\end{excdesc} + + +\subsection{Regular Expression Objects \label{re-objects}} + +Compiled regular expression objects support the following methods and +attributes: + +\begin{methoddesc}[RegexObject]{match}{string\optional{, pos\optional{, + endpos}}} + If zero or more characters at the beginning of \var{string} match + this regular expression, return a corresponding + \class{MatchObject} instance. Return \code{None} if the string does not + match the pattern; note that this is different from a zero-length + match. + + \note{If you want to locate a match anywhere in + \var{string}, use \method{search()} instead.} + + The optional second parameter \var{pos} gives an index in the string + where the search is to start; it defaults to \code{0}. This is not + completely equivalent to slicing the string; the + \code{'\textasciicircum'} pattern + character matches at the real beginning of the string and at positions + just after a newline, but not necessarily at the index where the search + is to start. + + The optional parameter \var{endpos} limits how far the string will + be searched; it will be as if the string is \var{endpos} characters + long, so only the characters from \var{pos} to \code{\var{endpos} - + 1} will be searched for a match. If \var{endpos} is less than + \var{pos}, no match will be found, otherwise, if \var{rx} is a + compiled regular expression object, + \code{\var{rx}.match(\var{string}, 0, 50)} is equivalent to + \code{\var{rx}.match(\var{string}[:50], 0)}. +\end{methoddesc} + +\begin{methoddesc}[RegexObject]{search}{string\optional{, pos\optional{, + endpos}}} + Scan through \var{string} looking for a location where this regular + expression produces a match, and return a + corresponding \class{MatchObject} instance. Return \code{None} if no + position in the string matches the pattern; note that this is + different from finding a zero-length match at some point in the string. + + The optional \var{pos} and \var{endpos} parameters have the same + meaning as for the \method{match()} method. +\end{methoddesc} + +\begin{methoddesc}[RegexObject]{split}{string\optional{, + maxsplit\code{ = 0}}} +Identical to the \function{split()} function, using the compiled pattern. +\end{methoddesc} + +\begin{methoddesc}[RegexObject]{findall}{string\optional{, pos\optional{, + endpos}}} +Identical to the \function{findall()} function, using the compiled pattern. +\end{methoddesc} + +\begin{methoddesc}[RegexObject]{finditer}{string\optional{, pos\optional{, + endpos}}} +Identical to the \function{finditer()} function, using the compiled pattern. +\end{methoddesc} + +\begin{methoddesc}[RegexObject]{sub}{repl, string\optional{, count\code{ = 0}}} +Identical to the \function{sub()} function, using the compiled pattern. +\end{methoddesc} + +\begin{methoddesc}[RegexObject]{subn}{repl, string\optional{, + count\code{ = 0}}} +Identical to the \function{subn()} function, using the compiled pattern. +\end{methoddesc} + + +\begin{memberdesc}[RegexObject]{flags} +The flags argument used when the RE object was compiled, or +\code{0} if no flags were provided. +\end{memberdesc} + +\begin{memberdesc}[RegexObject]{groupindex} +A dictionary mapping any symbolic group names defined by +\regexp{(?P<\var{id}>)} to group numbers. The dictionary is empty if no +symbolic groups were used in the pattern. +\end{memberdesc} + +\begin{memberdesc}[RegexObject]{pattern} +The pattern string from which the RE object was compiled. +\end{memberdesc} + + +\subsection{Match Objects \label{match-objects}} + +\class{MatchObject} instances support the following methods and +attributes: + +\begin{methoddesc}[MatchObject]{expand}{template} + Return the string obtained by doing backslash substitution on the +template string \var{template}, as done by the \method{sub()} method. +Escapes such as \samp{\e n} are converted to the appropriate +characters, and numeric backreferences (\samp{\e 1}, \samp{\e 2}) and +named backreferences (\samp{\e g<1>}, \samp{\e g}) are replaced +by the contents of the corresponding group. +\end{methoddesc} + +\begin{methoddesc}[MatchObject]{group}{\optional{group1, \moreargs}} +Returns one or more subgroups of the match. If there is a single +argument, the result is a single string; if there are +multiple arguments, the result is a tuple with one item per argument. +Without arguments, \var{group1} defaults to zero (the whole match +is returned). +If a \var{groupN} argument is zero, the corresponding return value is the +entire matching string; if it is in the inclusive range [1..99], it is +the string matching the corresponding parenthesized group. If a +group number is negative or larger than the number of groups defined +in the pattern, an \exception{IndexError} exception is raised. +If a group is contained in a part of the pattern that did not match, +the corresponding result is \code{None}. If a group is contained in a +part of the pattern that matched multiple times, the last match is +returned. + +If the regular expression uses the \regexp{(?P<\var{name}>...)} syntax, +the \var{groupN} arguments may also be strings identifying groups by +their group name. If a string argument is not used as a group name in +the pattern, an \exception{IndexError} exception is raised. + +A moderately complicated example: + +\begin{verbatim} +m = re.match(r"(?P\d+)\.(\d*)", '3.14') +\end{verbatim} + +After performing this match, \code{m.group(1)} is \code{'3'}, as is +\code{m.group('int')}, and \code{m.group(2)} is \code{'14'}. +\end{methoddesc} + +\begin{methoddesc}[MatchObject]{groups}{\optional{default}} +Return a tuple containing all the subgroups of the match, from 1 up to +however many groups are in the pattern. The \var{default} argument is +used for groups that did not participate in the match; it defaults to +\code{None}. (Incompatibility note: in the original Python 1.5 +release, if the tuple was one element long, a string would be returned +instead. In later versions (from 1.5.1 on), a singleton tuple is +returned in such cases.) +\end{methoddesc} + +\begin{methoddesc}[MatchObject]{groupdict}{\optional{default}} +Return a dictionary containing all the \emph{named} subgroups of the +match, keyed by the subgroup name. The \var{default} argument is +used for groups that did not participate in the match; it defaults to +\code{None}. +\end{methoddesc} + +\begin{methoddesc}[MatchObject]{start}{\optional{group}} +\methodline{end}{\optional{group}} +Return the indices of the start and end of the substring +matched by \var{group}; \var{group} defaults to zero (meaning the whole +matched substring). +Return \code{-1} if \var{group} exists but +did not contribute to the match. For a match object +\var{m}, and a group \var{g} that did contribute to the match, the +substring matched by group \var{g} (equivalent to +\code{\var{m}.group(\var{g})}) is + +\begin{verbatim} +m.string[m.start(g):m.end(g)] +\end{verbatim} + +Note that +\code{m.start(\var{group})} will equal \code{m.end(\var{group})} if +\var{group} matched a null string. For example, after \code{\var{m} = +re.search('b(c?)', 'cba')}, \code{\var{m}.start(0)} is 1, +\code{\var{m}.end(0)} is 2, \code{\var{m}.start(1)} and +\code{\var{m}.end(1)} are both 2, and \code{\var{m}.start(2)} raises +an \exception{IndexError} exception. +\end{methoddesc} + +\begin{methoddesc}[MatchObject]{span}{\optional{group}} +For \class{MatchObject} \var{m}, return the 2-tuple +\code{(\var{m}.start(\var{group}), \var{m}.end(\var{group}))}. +Note that if \var{group} did not contribute to the match, this is +\code{(-1, -1)}. Again, \var{group} defaults to zero. +\end{methoddesc} + +\begin{memberdesc}[MatchObject]{pos} +The value of \var{pos} which was passed to the \function{search()} or +\function{match()} method of the \class{RegexObject}. This is the +index into the string at which the RE engine started looking for a +match. +\end{memberdesc} + +\begin{memberdesc}[MatchObject]{endpos} +The value of \var{endpos} which was passed to the \function{search()} +or \function{match()} method of the \class{RegexObject}. This is the +index into the string beyond which the RE engine will not go. +\end{memberdesc} + +\begin{memberdesc}[MatchObject]{lastindex} +The integer index of the last matched capturing group, or \code{None} +if no group was matched at all. For example, the expressions +\regexp{(a)b}, \regexp{((a)(b))}, and \regexp{((ab))} will have +\code{lastindex == 1} if applied to the string \code{'ab'}, +while the expression \regexp{(a)(b)} will have \code{lastindex == 2}, +if applied to the same string. +\end{memberdesc} + +\begin{memberdesc}[MatchObject]{lastgroup} +The name of the last matched capturing group, or \code{None} if the +group didn't have a name, or if no group was matched at all. +\end{memberdesc} + +\begin{memberdesc}[MatchObject]{re} +The regular expression object whose \method{match()} or +\method{search()} method produced this \class{MatchObject} instance. +\end{memberdesc} + +\begin{memberdesc}[MatchObject]{string} +The string passed to \function{match()} or \function{search()}. +\end{memberdesc} + +\subsection{Examples} + +\leftline{\strong{Simulating \cfunction{scanf()}}} + +Python does not currently have an equivalent to \cfunction{scanf()}. +\ttindex{scanf()} +Regular expressions are generally more powerful, though also more +verbose, than \cfunction{scanf()} format strings. The table below +offers some more-or-less equivalent mappings between +\cfunction{scanf()} format tokens and regular expressions. + +\begin{tableii}{l|l}{textrm}{\cfunction{scanf()} Token}{Regular Expression} + \lineii{\code{\%c}} + {\regexp{.}} + \lineii{\code{\%5c}} + {\regexp{.\{5\}}} + \lineii{\code{\%d}} + {\regexp{[-+]?\e d+}} + \lineii{\code{\%e}, \code{\%E}, \code{\%f}, \code{\%g}} + {\regexp{[-+]?(\e d+(\e.\e d*)?|\e.\e d+)([eE][-+]?\e d+)?}} + \lineii{\code{\%i}} + {\regexp{[-+]?(0[xX][\e dA-Fa-f]+|0[0-7]*|\e d+)}} + \lineii{\code{\%o}} + {\regexp{0[0-7]*}} + \lineii{\code{\%s}} + {\regexp{\e S+}} + \lineii{\code{\%u}} + {\regexp{\e d+}} + \lineii{\code{\%x}, \code{\%X}} + {\regexp{0[xX][\e dA-Fa-f]+}} +\end{tableii} + +To extract the filename and numbers from a string like + +\begin{verbatim} + /usr/sbin/sendmail - 0 errors, 4 warnings +\end{verbatim} + +you would use a \cfunction{scanf()} format like + +\begin{verbatim} + %s - %d errors, %d warnings +\end{verbatim} + +The equivalent regular expression would be + +\begin{verbatim} + (\S+) - (\d+) errors, (\d+) warnings +\end{verbatim} + +\leftline{\strong{Avoiding recursion}} + +If you create regular expressions that require the engine to perform a +lot of recursion, you may encounter a \exception{RuntimeError} exception with +the message \code{maximum recursion limit} exceeded. For example, + +\begin{verbatim} +>>> import re +>>> s = 'Begin ' + 1000*'a very long string ' + 'end' +>>> re.match('Begin (\w| )*? end', s).end() +Traceback (most recent call last): + File "", line 1, in ? + File "/usr/local/lib/python2.5/re.py", line 132, in match + return _compile(pattern, flags).match(string) +RuntimeError: maximum recursion limit exceeded +\end{verbatim} + +You can often restructure your regular expression to avoid recursion. + +Starting with Python 2.3, simple uses of the \regexp{*?} pattern are +special-cased to avoid recursion. Thus, the above regular expression +can avoid recursion by being recast as +\regexp{Begin [a-zA-Z0-9_ ]*?end}. As a further benefit, such regular +expressions will run faster than their recursive equivalents. diff --git a/sys/src/cmd/python/Doc/lib/libreadline.tex b/sys/src/cmd/python/Doc/lib/libreadline.tex new file mode 100644 index 000000000..dec37b67e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libreadline.tex @@ -0,0 +1,196 @@ +\section{\module{readline} --- + GNU readline interface} + +\declaremodule{builtin}{readline} + \platform{Unix} +\sectionauthor{Skip Montanaro}{skip@mojam.com} +\modulesynopsis{GNU readline support for Python.} + + +The \module{readline} module defines a number of functions to +facilitate completion and reading/writing of history files from the +Python interpreter. This module can be used directly or via the +\refmodule{rlcompleter} module. Settings made using +this module affect the behaviour of both the interpreter's interactive prompt +and the prompts offered by the \function{raw_input()} and \function{input()} +built-in functions. + +The \module{readline} module defines the following functions: + + +\begin{funcdesc}{parse_and_bind}{string} +Parse and execute single line of a readline init file. +\end{funcdesc} + +\begin{funcdesc}{get_line_buffer}{} +Return the current contents of the line buffer. +\end{funcdesc} + +\begin{funcdesc}{insert_text}{string} +Insert text into the command line. +\end{funcdesc} + +\begin{funcdesc}{read_init_file}{\optional{filename}} +Parse a readline initialization file. +The default filename is the last filename used. +\end{funcdesc} + +\begin{funcdesc}{read_history_file}{\optional{filename}} +Load a readline history file. +The default filename is \file{\~{}/.history}. +\end{funcdesc} + +\begin{funcdesc}{write_history_file}{\optional{filename}} +Save a readline history file. +The default filename is \file{\~{}/.history}. +\end{funcdesc} + +\begin{funcdesc}{clear_history}{} +Clear the current history. (Note: this function is not available if +the installed version of GNU readline doesn't support it.) +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{get_history_length}{} +Return the desired length of the history file. Negative values imply +unlimited history file size. +\end{funcdesc} + +\begin{funcdesc}{set_history_length}{length} +Set the number of lines to save in the history file. +\function{write_history_file()} uses this value to truncate the +history file when saving. Negative values imply unlimited history +file size. +\end{funcdesc} + +\begin{funcdesc}{get_current_history_length}{} +Return the number of lines currently in the history. (This is different +from \function{get_history_length()}, which returns the maximum number of +lines that will be written to a history file.) \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{get_history_item}{index} +Return the current contents of history item at \var{index}. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{remove_history_item}{pos} +Remove history item specified by its position from the history. +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{replace_history_item}{pos, line} +Replace history item specified by its position with the given line. +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{redisplay}{} +Change what's displayed on the screen to reflect the current contents +of the line buffer. \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{set_startup_hook}{\optional{function}} +Set or remove the startup_hook function. If \var{function} is specified, +it will be used as the new startup_hook function; if omitted or +\code{None}, any hook function already installed is removed. The +startup_hook function is called with no arguments just +before readline prints the first prompt. +\end{funcdesc} + +\begin{funcdesc}{set_pre_input_hook}{\optional{function}} +Set or remove the pre_input_hook function. If \var{function} is specified, +it will be used as the new pre_input_hook function; if omitted or +\code{None}, any hook function already installed is removed. The +pre_input_hook function is called with no arguments after the first prompt +has been printed and just before readline starts reading input characters. +\end{funcdesc} + +\begin{funcdesc}{set_completer}{\optional{function}} +Set or remove the completer function. If \var{function} is specified, +it will be used as the new completer function; if omitted or +\code{None}, any completer function already installed is removed. The +completer function is called as \code{\var{function}(\var{text}, +\var{state})}, for \var{state} in \code{0}, \code{1}, \code{2}, ..., +until it returns a non-string value. It should return the next +possible completion starting with \var{text}. +\end{funcdesc} + +\begin{funcdesc}{get_completer}{} +Get the completer function, or \code{None} if no completer function +has been set. \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{get_begidx}{} +Get the beginning index of the readline tab-completion scope. +\end{funcdesc} + +\begin{funcdesc}{get_endidx}{} +Get the ending index of the readline tab-completion scope. +\end{funcdesc} + +\begin{funcdesc}{set_completer_delims}{string} +Set the readline word delimiters for tab-completion. +\end{funcdesc} + +\begin{funcdesc}{get_completer_delims}{} +Get the readline word delimiters for tab-completion. +\end{funcdesc} + +\begin{funcdesc}{add_history}{line} +Append a line to the history buffer, as if it was the last line typed. +\end{funcdesc} + +\begin{seealso} + \seemodule{rlcompleter}{Completion of Python identifiers at the + interactive prompt.} +\end{seealso} + + +\subsection{Example \label{readline-example}} + +The following example demonstrates how to use the +\module{readline} module's history reading and writing functions to +automatically load and save a history file named \file{.pyhist} from +the user's home directory. The code below would normally be executed +automatically during interactive sessions from the user's +\envvar{PYTHONSTARTUP} file. + +\begin{verbatim} +import os +histfile = os.path.join(os.environ["HOME"], ".pyhist") +try: + readline.read_history_file(histfile) +except IOError: + pass +import atexit +atexit.register(readline.write_history_file, histfile) +del os, histfile +\end{verbatim} + +The following example extends the \class{code.InteractiveConsole} class to +support history save/restore. + +\begin{verbatim} +import code +import readline +import atexit +import os + +class HistoryConsole(code.InteractiveConsole): + def __init__(self, locals=None, filename="", + histfile=os.path.expanduser("~/.console-history")): + code.InteractiveConsole.__init__(self) + self.init_history(histfile) + + def init_history(self, histfile): + readline.parse_and_bind("tab: complete") + if hasattr(readline, "read_history_file"): + try: + readline.read_history_file(histfile) + except IOError: + pass + atexit.register(self.save_history, histfile) + + def save_history(self, histfile): + readline.write_history_file(histfile) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/librepr.tex b/sys/src/cmd/python/Doc/lib/librepr.tex new file mode 100644 index 000000000..7905112dd --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librepr.tex @@ -0,0 +1,133 @@ +\section{\module{repr} --- + Alternate \function{repr()} implementation} + +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +\declaremodule{standard}{repr} +\modulesynopsis{Alternate \function{repr()} implementation with size limits.} + + +The \module{repr} module provides a means for producing object +representations with limits on the size of the resulting strings. +This is used in the Python debugger and may be useful in other +contexts as well. + +This module provides a class, an instance, and a function: + + +\begin{classdesc}{Repr}{} + Class which provides formatting services useful in implementing + functions similar to the built-in \function{repr()}; size limits for + different object types are added to avoid the generation of + representations which are excessively long. +\end{classdesc} + + +\begin{datadesc}{aRepr} + This is an instance of \class{Repr} which is used to provide the + \function{repr()} function described below. Changing the attributes + of this object will affect the size limits used by \function{repr()} + and the Python debugger. +\end{datadesc} + + +\begin{funcdesc}{repr}{obj} + This is the \method{repr()} method of \code{aRepr}. It returns a + string similar to that returned by the built-in function of the same + name, but with limits on most sizes. +\end{funcdesc} + + +\subsection{Repr Objects \label{Repr-objects}} + +\class{Repr} instances provide several members which can be used to +provide size limits for the representations of different object types, +and methods which format specific object types. + + +\begin{memberdesc}{maxlevel} + Depth limit on the creation of recursive representations. The + default is \code{6}. +\end{memberdesc} + +\begin{memberdesc}{maxdict} +\memberline{maxlist} +\memberline{maxtuple} +\memberline{maxset} +\memberline{maxfrozenset} +\memberline{maxdeque} +\memberline{maxarray} + Limits on the number of entries represented for the named object + type. The default is \code{4} for \member{maxdict}, \code{5} for + \member{maxarray}, and \code{6} for the others. + \versionadded[\member{maxset}, \member{maxfrozenset}, + and \member{set}]{2.4}. +\end{memberdesc} + +\begin{memberdesc}{maxlong} + Maximum number of characters in the representation for a long + integer. Digits are dropped from the middle. The default is + \code{40}. +\end{memberdesc} + +\begin{memberdesc}{maxstring} + Limit on the number of characters in the representation of the + string. Note that the ``normal'' representation of the string is + used as the character source: if escape sequences are needed in the + representation, these may be mangled when the representation is + shortened. The default is \code{30}. +\end{memberdesc} + +\begin{memberdesc}{maxother} + This limit is used to control the size of object types for which no + specific formatting method is available on the \class{Repr} object. + It is applied in a similar manner as \member{maxstring}. The + default is \code{20}. +\end{memberdesc} + +\begin{methoddesc}{repr}{obj} + The equivalent to the built-in \function{repr()} that uses the + formatting imposed by the instance. +\end{methoddesc} + +\begin{methoddesc}{repr1}{obj, level} + Recursive implementation used by \method{repr()}. This uses the + type of \var{obj} to determine which formatting method to call, + passing it \var{obj} and \var{level}. The type-specific methods + should call \method{repr1()} to perform recursive formatting, with + \code{\var{level} - 1} for the value of \var{level} in the recursive + call. +\end{methoddesc} + +\begin{methoddescni}{repr_\var{type}}{obj, level} + Formatting methods for specific types are implemented as methods + with a name based on the type name. In the method name, \var{type} + is replaced by + \code{string.join(string.split(type(\var{obj}).__name__, '_'))}. + Dispatch to these methods is handled by \method{repr1()}. + Type-specific methods which need to recursively format a value + should call \samp{self.repr1(\var{subobj}, \var{level} - 1)}. +\end{methoddescni} + + +\subsection{Subclassing Repr Objects \label{subclassing-reprs}} + +The use of dynamic dispatching by \method{Repr.repr1()} allows +subclasses of \class{Repr} to add support for additional built-in +object types or to modify the handling of types already supported. +This example shows how special support for file objects could be +added: + +\begin{verbatim} +import repr +import sys + +class MyRepr(repr.Repr): + def repr_file(self, obj, level): + if obj.name in ['', '', '']: + return obj.name + else: + return `obj` + +aRepr = MyRepr() +print aRepr.repr(sys.stdin) # prints '' +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libresource.tex b/sys/src/cmd/python/Doc/lib/libresource.tex new file mode 100644 index 000000000..8e102b8ee --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libresource.tex @@ -0,0 +1,215 @@ +\section{\module{resource} --- + Resource usage information} + +\declaremodule{builtin}{resource} + \platform{Unix} +\modulesynopsis{An interface to provide resource usage information on + the current process.} +\moduleauthor{Jeremy Hylton}{jeremy@alum.mit.edu} +\sectionauthor{Jeremy Hylton}{jeremy@alum.mit.edu} + + +This module provides basic mechanisms for measuring and controlling +system resources utilized by a program. + +Symbolic constants are used to specify particular system resources and +to request usage information about either the current process or its +children. + +A single exception is defined for errors: + + +\begin{excdesc}{error} + The functions described below may raise this error if the underlying + system call failures unexpectedly. +\end{excdesc} + +\subsection{Resource Limits} + +Resources usage can be limited using the \function{setrlimit()} function +described below. Each resource is controlled by a pair of limits: a +soft limit and a hard limit. The soft limit is the current limit, and +may be lowered or raised by a process over time. The soft limit can +never exceed the hard limit. The hard limit can be lowered to any +value greater than the soft limit, but not raised. (Only processes with +the effective UID of the super-user can raise a hard limit.) + +The specific resources that can be limited are system dependent. They +are described in the \manpage{getrlimit}{2} man page. The resources +listed below are supported when the underlying operating system +supports them; resources which cannot be checked or controlled by the +operating system are not defined in this module for those platforms. + +\begin{funcdesc}{getrlimit}{resource} + Returns a tuple \code{(\var{soft}, \var{hard})} with the current + soft and hard limits of \var{resource}. Raises \exception{ValueError} if + an invalid resource is specified, or \exception{error} if the + underlying system call fails unexpectedly. +\end{funcdesc} + +\begin{funcdesc}{setrlimit}{resource, limits} + Sets new limits of consumption of \var{resource}. The \var{limits} + argument must be a tuple \code{(\var{soft}, \var{hard})} of two + integers describing the new limits. A value of \code{-1} can be used to + specify the maximum possible upper limit. + + Raises \exception{ValueError} if an invalid resource is specified, + if the new soft limit exceeds the hard limit, or if a process tries + to raise its hard limit (unless the process has an effective UID of + super-user). Can also raise \exception{error} if the underlying + system call fails. +\end{funcdesc} + +These symbols define resources whose consumption can be controlled +using the \function{setrlimit()} and \function{getrlimit()} functions +described below. The values of these symbols are exactly the constants +used by \C{} programs. + +The \UNIX{} man page for \manpage{getrlimit}{2} lists the available +resources. Note that not all systems use the same symbol or same +value to denote the same resource. This module does not attempt to +mask platform differences --- symbols not defined for a platform will +not be available from this module on that platform. + +\begin{datadesc}{RLIMIT_CORE} + The maximum size (in bytes) of a core file that the current process + can create. This may result in the creation of a partial core file + if a larger core would be required to contain the entire process + image. +\end{datadesc} + +\begin{datadesc}{RLIMIT_CPU} + The maximum amount of processor time (in seconds) that a process can + use. If this limit is exceeded, a \constant{SIGXCPU} signal is sent to + the process. (See the \refmodule{signal} module documentation for + information about how to catch this signal and do something useful, + e.g. flush open files to disk.) +\end{datadesc} + +\begin{datadesc}{RLIMIT_FSIZE} + The maximum size of a file which the process may create. This only + affects the stack of the main thread in a multi-threaded process. +\end{datadesc} + +\begin{datadesc}{RLIMIT_DATA} + The maximum size (in bytes) of the process's heap. +\end{datadesc} + +\begin{datadesc}{RLIMIT_STACK} + The maximum size (in bytes) of the call stack for the current + process. +\end{datadesc} + +\begin{datadesc}{RLIMIT_RSS} + The maximum resident set size that should be made available to the + process. +\end{datadesc} + +\begin{datadesc}{RLIMIT_NPROC} + The maximum number of processes the current process may create. +\end{datadesc} + +\begin{datadesc}{RLIMIT_NOFILE} + The maximum number of open file descriptors for the current + process. +\end{datadesc} + +\begin{datadesc}{RLIMIT_OFILE} + The BSD name for \constant{RLIMIT_NOFILE}. +\end{datadesc} + +\begin{datadesc}{RLIMIT_MEMLOCK} + The maximum address space which may be locked in memory. +\end{datadesc} + +\begin{datadesc}{RLIMIT_VMEM} + The largest area of mapped memory which the process may occupy. +\end{datadesc} + +\begin{datadesc}{RLIMIT_AS} + The maximum area (in bytes) of address space which may be taken by + the process. +\end{datadesc} + +\subsection{Resource Usage} + +These functions are used to retrieve resource usage information: + +\begin{funcdesc}{getrusage}{who} + This function returns an object that describes the resources + consumed by either the current process or its children, as specified + by the \var{who} parameter. The \var{who} parameter should be + specified using one of the \constant{RUSAGE_*} constants described + below. + + The fields of the return value each describe how a particular system + resource has been used, e.g. amount of time spent running is user mode + or number of times the process was swapped out of main memory. Some + values are dependent on the clock tick internal, e.g. the amount of + memory the process is using. + + For backward compatibility, the return value is also accessible as + a tuple of 16 elements. + + The fields \member{ru_utime} and \member{ru_stime} of the return value + are floating point values representing the amount of time spent + executing in user mode and the amount of time spent executing in system + mode, respectively. The remaining values are integers. Consult the + \manpage{getrusage}{2} man page for detailed information about these + values. A brief summary is presented here: + +\begin{tableiii}{r|l|l}{code}{Index}{Field}{Resource} + \lineiii{0}{\member{ru_utime}}{time in user mode (float)} + \lineiii{1}{\member{ru_stime}}{time in system mode (float)} + \lineiii{2}{\member{ru_maxrss}}{maximum resident set size} + \lineiii{3}{\member{ru_ixrss}}{shared memory size} + \lineiii{4}{\member{ru_idrss}}{unshared memory size} + \lineiii{5}{\member{ru_isrss}}{unshared stack size} + \lineiii{6}{\member{ru_minflt}}{page faults not requiring I/O} + \lineiii{7}{\member{ru_majflt}}{page faults requiring I/O} + \lineiii{8}{\member{ru_nswap}}{number of swap outs} + \lineiii{9}{\member{ru_inblock}}{block input operations} + \lineiii{10}{\member{ru_oublock}}{block output operations} + \lineiii{11}{\member{ru_msgsnd}}{messages sent} + \lineiii{12}{\member{ru_msgrcv}}{messages received} + \lineiii{13}{\member{ru_nsignals}}{signals received} + \lineiii{14}{\member{ru_nvcsw}}{voluntary context switches} + \lineiii{15}{\member{ru_nivcsw}}{involuntary context switches} +\end{tableiii} + + This function will raise a \exception{ValueError} if an invalid + \var{who} parameter is specified. It may also raise + \exception{error} exception in unusual circumstances. + + \versionchanged[Added access to values as attributes of the + returned object]{2.3} +\end{funcdesc} + +\begin{funcdesc}{getpagesize}{} + Returns the number of bytes in a system page. (This need not be the + same as the hardware page size.) This function is useful for + determining the number of bytes of memory a process is using. The + third element of the tuple returned by \function{getrusage()} describes + memory usage in pages; multiplying by page size produces number of + bytes. +\end{funcdesc} + +The following \constant{RUSAGE_*} symbols are passed to the +\function{getrusage()} function to specify which processes information +should be provided for. + +\begin{datadesc}{RUSAGE_SELF} + \constant{RUSAGE_SELF} should be used to + request information pertaining only to the process itself. +\end{datadesc} + +\begin{datadesc}{RUSAGE_CHILDREN} + Pass to \function{getrusage()} to request resource information for + child processes of the calling process. +\end{datadesc} + +\begin{datadesc}{RUSAGE_BOTH} + Pass to \function{getrusage()} to request resources consumed by both + the current process and child processes. May not be available on all + systems. +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/librestricted.tex b/sys/src/cmd/python/Doc/lib/librestricted.tex new file mode 100644 index 000000000..5d4b15736 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librestricted.tex @@ -0,0 +1,66 @@ +\chapter{Restricted Execution \label{restricted}} + +\begin{notice}[warning] + In Python 2.3 these modules have been disabled due to various known + and not readily fixable security holes. The modules are still + documented here to help in reading old code that uses the + \module{rexec} and \module{Bastion} modules. +\end{notice} + +\emph{Restricted execution} is the basic framework in Python that allows +for the segregation of trusted and untrusted code. The framework is based on the +notion that trusted Python code (a \emph{supervisor}) can create a +``padded cell' (or environment) with limited permissions, and run the +untrusted code within this cell. The untrusted code cannot break out +of its cell, and can only interact with sensitive system resources +through interfaces defined and managed by the trusted code. The term +``restricted execution'' is favored over ``safe-Python'' +since true safety is hard to define, and is determined by the way the +restricted environment is created. Note that the restricted +environments can be nested, with inner cells creating subcells of +lesser, but never greater, privilege. + +An interesting aspect of Python's restricted execution model is that +the interfaces presented to untrusted code usually have the same names +as those presented to trusted code. Therefore no special interfaces +need to be learned to write code designed to run in a restricted +environment. And because the exact nature of the padded cell is +determined by the supervisor, different restrictions can be imposed, +depending on the application. For example, it might be deemed +``safe'' for untrusted code to read any file within a specified +directory, but never to write a file. In this case, the supervisor +may redefine the built-in \function{open()} function so that it raises +an exception whenever the \var{mode} parameter is \code{'w'}. It +might also perform a \cfunction{chroot()}-like operation on the +\var{filename} parameter, such that root is always relative to some +safe ``sandbox'' area of the filesystem. In this case, the untrusted +code would still see an built-in \function{open()} function in its +environment, with the same calling interface. The semantics would be +identical too, with \exception{IOError}s being raised when the +supervisor determined that an unallowable parameter is being used. + +The Python run-time determines whether a particular code block is +executing in restricted execution mode based on the identity of the +\code{__builtins__} object in its global variables: if this is (the +dictionary of) the standard \refmodule[builtin]{__builtin__} module, +the code is deemed to be unrestricted, else it is deemed to be +restricted. + +Python code executing in restricted mode faces a number of limitations +that are designed to prevent it from escaping from the padded cell. +For instance, the function object attribute \member{func_globals} and +the class and instance object attribute \member{__dict__} are +unavailable. + +Two modules provide the framework for setting up restricted execution +environments: + +\localmoduletable + +\begin{seealso} + \seetitle[http://grail.sourceforge.net/]{Grail Home Page} + {Grail, an Internet browser written in Python, uses these + modules to support Python applets. More + information on the use of Python's restricted execution + mode in Grail is available on the Web site.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/librexec.tex b/sys/src/cmd/python/Doc/lib/librexec.tex new file mode 100644 index 000000000..35619e636 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librexec.tex @@ -0,0 +1,275 @@ +\section{\module{rexec} --- + Restricted execution framework} + +\declaremodule{standard}{rexec} +\modulesynopsis{Basic restricted execution framework.} +\versionchanged[Disabled module]{2.3} + +\begin{notice}[warning] + The documentation has been left in place to help in reading old code + that uses the module. +\end{notice} + +This module contains the \class{RExec} class, which supports +\method{r_eval()}, \method{r_execfile()}, \method{r_exec()}, and +\method{r_import()} methods, which are restricted versions of the standard +Python functions \method{eval()}, \method{execfile()} and +the \keyword{exec} and \keyword{import} statements. +Code executed in this restricted environment will +only have access to modules and functions that are deemed safe; you +can subclass \class{RExec} to add or remove capabilities as desired. + +\begin{notice}[warning] + While the \module{rexec} module is designed to perform as described + below, it does have a few known vulnerabilities which could be + exploited by carefully written code. Thus it should not be relied + upon in situations requiring ``production ready'' security. In such + situations, execution via sub-processes or very careful + ``cleansing'' of both code and data to be processed may be + necessary. Alternatively, help in patching known \module{rexec} + vulnerabilities would be welcomed. +\end{notice} + +\begin{notice} + The \class{RExec} class can prevent code from performing unsafe + operations like reading or writing disk files, or using TCP/IP + sockets. However, it does not protect against code using extremely + large amounts of memory or processor time. +\end{notice} + +\begin{classdesc}{RExec}{\optional{hooks\optional{, verbose}}} +Returns an instance of the \class{RExec} class. + +\var{hooks} is an instance of the \class{RHooks} class or a subclass of it. +If it is omitted or \code{None}, the default \class{RHooks} class is +instantiated. +Whenever the \module{rexec} module searches for a module (even a +built-in one) or reads a module's code, it doesn't actually go out to +the file system itself. Rather, it calls methods of an \class{RHooks} +instance that was passed to or created by its constructor. (Actually, +the \class{RExec} object doesn't make these calls --- they are made by +a module loader object that's part of the \class{RExec} object. This +allows another level of flexibility, which can be useful when changing +the mechanics of \keyword{import} within the restricted environment.) + +By providing an alternate \class{RHooks} object, we can control the +file system accesses made to import a module, without changing the +actual algorithm that controls the order in which those accesses are +made. For instance, we could substitute an \class{RHooks} object that +passes all filesystem requests to a file server elsewhere, via some +RPC mechanism such as ILU. Grail's applet loader uses this to support +importing applets from a URL for a directory. + +If \var{verbose} is true, additional debugging output may be sent to +standard output. +\end{classdesc} + +It is important to be aware that code running in a restricted +environment can still call the \function{sys.exit()} function. To +disallow restricted code from exiting the interpreter, always protect +calls that cause restricted code to run with a +\keyword{try}/\keyword{except} statement that catches the +\exception{SystemExit} exception. Removing the \function{sys.exit()} +function from the restricted environment is not sufficient --- the +restricted code could still use \code{raise SystemExit}. Removing +\exception{SystemExit} is not a reasonable option; some library code +makes use of this and would break were it not available. + + +\begin{seealso} + \seetitle[http://grail.sourceforge.net/]{Grail Home Page}{Grail is a + Web browser written entirely in Python. It uses the + \module{rexec} module as a foundation for supporting + Python applets, and can be used as an example usage of + this module.} +\end{seealso} + + +\subsection{RExec Objects \label{rexec-objects}} + +\class{RExec} instances support the following methods: + +\begin{methoddesc}{r_eval}{code} +\var{code} must either be a string containing a Python expression, or +a compiled code object, which will be evaluated in the restricted +environment's \module{__main__} module. The value of the expression or +code object will be returned. +\end{methoddesc} + +\begin{methoddesc}{r_exec}{code} +\var{code} must either be a string containing one or more lines of +Python code, or a compiled code object, which will be executed in the +restricted environment's \module{__main__} module. +\end{methoddesc} + +\begin{methoddesc}{r_execfile}{filename} +Execute the Python code contained in the file \var{filename} in the +restricted environment's \module{__main__} module. +\end{methoddesc} + +Methods whose names begin with \samp{s_} are similar to the functions +beginning with \samp{r_}, but the code will be granted access to +restricted versions of the standard I/O streams \code{sys.stdin}, +\code{sys.stderr}, and \code{sys.stdout}. + +\begin{methoddesc}{s_eval}{code} +\var{code} must be a string containing a Python expression, which will +be evaluated in the restricted environment. +\end{methoddesc} + +\begin{methoddesc}{s_exec}{code} +\var{code} must be a string containing one or more lines of Python code, +which will be executed in the restricted environment. +\end{methoddesc} + +\begin{methoddesc}{s_execfile}{code} +Execute the Python code contained in the file \var{filename} in the +restricted environment. +\end{methoddesc} + +\class{RExec} objects must also support various methods which will be +implicitly called by code executing in the restricted environment. +Overriding these methods in a subclass is used to change the policies +enforced by a restricted environment. + +\begin{methoddesc}{r_import}{modulename\optional{, globals\optional{, + locals\optional{, fromlist}}}} +Import the module \var{modulename}, raising an \exception{ImportError} +exception if the module is considered unsafe. +\end{methoddesc} + +\begin{methoddesc}{r_open}{filename\optional{, mode\optional{, bufsize}}} +Method called when \function{open()} is called in the restricted +environment. The arguments are identical to those of \function{open()}, +and a file object (or a class instance compatible with file objects) +should be returned. \class{RExec}'s default behaviour is allow opening +any file for reading, but forbidding any attempt to write a file. See +the example below for an implementation of a less restrictive +\method{r_open()}. +\end{methoddesc} + +\begin{methoddesc}{r_reload}{module} +Reload the module object \var{module}, re-parsing and re-initializing it. +\end{methoddesc} + +\begin{methoddesc}{r_unload}{module} +Unload the module object \var{module} (remove it from the +restricted environment's \code{sys.modules} dictionary). +\end{methoddesc} + +And their equivalents with access to restricted standard I/O streams: + +\begin{methoddesc}{s_import}{modulename\optional{, globals\optional{, + locals\optional{, fromlist}}}} +Import the module \var{modulename}, raising an \exception{ImportError} +exception if the module is considered unsafe. +\end{methoddesc} + +\begin{methoddesc}{s_reload}{module} +Reload the module object \var{module}, re-parsing and re-initializing it. +\end{methoddesc} + +\begin{methoddesc}{s_unload}{module} +Unload the module object \var{module}. +% XXX what are the semantics of this? +\end{methoddesc} + + +\subsection{Defining restricted environments \label{rexec-extension}} + +The \class{RExec} class has the following class attributes, which are +used by the \method{__init__()} method. Changing them on an existing +instance won't have any effect; instead, create a subclass of +\class{RExec} and assign them new values in the class definition. +Instances of the new class will then use those new values. All these +attributes are tuples of strings. + +\begin{memberdesc}{nok_builtin_names} +Contains the names of built-in functions which will \emph{not} be +available to programs running in the restricted environment. The +value for \class{RExec} is \code{('open', 'reload', '__import__')}. +(This gives the exceptions, because by far the majority of built-in +functions are harmless. A subclass that wants to override this +variable should probably start with the value from the base class and +concatenate additional forbidden functions --- when new dangerous +built-in functions are added to Python, they will also be added to +this module.) +\end{memberdesc} + +\begin{memberdesc}{ok_builtin_modules} +Contains the names of built-in modules which can be safely imported. +The value for \class{RExec} is \code{('audioop', 'array', 'binascii', +'cmath', 'errno', 'imageop', 'marshal', 'math', 'md5', 'operator', +'parser', 'regex', 'select', 'sha', '_sre', 'strop', +'struct', 'time')}. A similar remark about overriding this variable +applies --- use the value from the base class as a starting point. +\end{memberdesc} + +\begin{memberdesc}{ok_path} +Contains the directories which will be searched when an \keyword{import} +is performed in the restricted environment. +The value for \class{RExec} is the same as \code{sys.path} (at the time +the module is loaded) for unrestricted code. +\end{memberdesc} + +\begin{memberdesc}{ok_posix_names} +% Should this be called ok_os_names? +Contains the names of the functions in the \refmodule{os} module which will be +available to programs running in the restricted environment. The +value for \class{RExec} is \code{('error', 'fstat', 'listdir', +'lstat', 'readlink', 'stat', 'times', 'uname', 'getpid', 'getppid', +'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')}. +\end{memberdesc} + +\begin{memberdesc}{ok_sys_names} +Contains the names of the functions and variables in the \refmodule{sys} +module which will be available to programs running in the restricted +environment. The value for \class{RExec} is \code{('ps1', 'ps2', +'copyright', 'version', 'platform', 'exit', 'maxint')}. +\end{memberdesc} + +\begin{memberdesc}{ok_file_types} +Contains the file types from which modules are allowed to be loaded. +Each file type is an integer constant defined in the \refmodule{imp} module. +The meaningful values are \constant{PY_SOURCE}, \constant{PY_COMPILED}, and +\constant{C_EXTENSION}. The value for \class{RExec} is \code{(C_EXTENSION, +PY_SOURCE)}. Adding \constant{PY_COMPILED} in subclasses is not recommended; +an attacker could exit the restricted execution mode by putting a forged +byte-compiled file (\file{.pyc}) anywhere in your file system, for example +by writing it to \file{/tmp} or uploading it to the \file{/incoming} +directory of your public FTP server. +\end{memberdesc} + + +\subsection{An example} + +Let us say that we want a slightly more relaxed policy than the +standard \class{RExec} class. For example, if we're willing to allow +files in \file{/tmp} to be written, we can subclass the \class{RExec} +class: + +\begin{verbatim} +class TmpWriterRExec(rexec.RExec): + def r_open(self, file, mode='r', buf=-1): + if mode in ('r', 'rb'): + pass + elif mode in ('w', 'wb', 'a', 'ab'): + # check filename : must begin with /tmp/ + if file[:5]!='/tmp/': + raise IOError, "can't write outside /tmp" + elif (string.find(file, '/../') >= 0 or + file[:3] == '../' or file[-3:] == '/..'): + raise IOError, "'..' in filename forbidden" + else: raise IOError, "Illegal open() mode" + return open(file, mode, buf) +\end{verbatim} +% +Notice that the above code will occasionally forbid a perfectly valid +filename; for example, code in the restricted environment won't be +able to open a file called \file{/tmp/foo/../bar}. To fix this, the +\method{r_open()} method would have to simplify the filename to +\file{/tmp/bar}, which would require splitting apart the filename and +performing various operations on it. In cases where security is at +stake, it may be preferable to write simple code which is sometimes +overly restrictive, instead of more general code that is also more +complex and may harbor a subtle security hole. diff --git a/sys/src/cmd/python/Doc/lib/librfc822.tex b/sys/src/cmd/python/Doc/lib/librfc822.tex new file mode 100644 index 000000000..4ca3734db --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librfc822.tex @@ -0,0 +1,336 @@ +\section{\module{rfc822} --- + Parse RFC 2822 mail headers} + +\declaremodule{standard}{rfc822} +\modulesynopsis{Parse \rfc{2822} style mail messages.} + +\deprecated{2.3}{The \refmodule{email} package should be used in + preference to the \module{rfc822} module. This + module is present only to maintain backward + compatibility.} + +This module defines a class, \class{Message}, which represents an +``email message'' as defined by the Internet standard +\rfc{2822}.\footnote{This module originally conformed to \rfc{822}, +hence the name. Since then, \rfc{2822} has been released as an +update to \rfc{822}. This module should be considered +\rfc{2822}-conformant, especially in cases where the +syntax or semantics have changed since \rfc{822}.} Such messages +consist of a collection of message headers, and a message body. This +module also defines a helper class +\class{AddressList} for parsing \rfc{2822} addresses. Please refer to +the RFC for information on the specific syntax of \rfc{2822} messages. + +The \refmodule{mailbox}\refstmodindex{mailbox} module provides classes +to read mailboxes produced by various end-user mail programs. + +\begin{classdesc}{Message}{file\optional{, seekable}} +A \class{Message} instance is instantiated with an input object as +parameter. Message relies only on the input object having a +\method{readline()} method; in particular, ordinary file objects +qualify. Instantiation reads headers from the input object up to a +delimiter line (normally a blank line) and stores them in the +instance. The message body, following the headers, is not consumed. + +This class can work with any input object that supports a +\method{readline()} method. If the input object has seek and tell +capability, the \method{rewindbody()} method will work; also, illegal +lines will be pushed back onto the input stream. If the input object +lacks seek but has an \method{unread()} method that can push back a +line of input, \class{Message} will use that to push back illegal +lines. Thus this class can be used to parse messages coming from a +buffered stream. + +The optional \var{seekable} argument is provided as a workaround for +certain stdio libraries in which \cfunction{tell()} discards buffered +data before discovering that the \cfunction{lseek()} system call +doesn't work. For maximum portability, you should set the seekable +argument to zero to prevent that initial \method{tell()} when passing +in an unseekable object such as a file object created from a socket +object. + +Input lines as read from the file may either be terminated by CR-LF or +by a single linefeed; a terminating CR-LF is replaced by a single +linefeed before the line is stored. + +All header matching is done independent of upper or lower case; +e.g.\ \code{\var{m}['From']}, \code{\var{m}['from']} and +\code{\var{m}['FROM']} all yield the same result. +\end{classdesc} + +\begin{classdesc}{AddressList}{field} +You may instantiate the \class{AddressList} helper class using a single +string parameter, a comma-separated list of \rfc{2822} addresses to be +parsed. (The parameter \code{None} yields an empty list.) +\end{classdesc} + +\begin{funcdesc}{quote}{str} +Return a new string with backslashes in \var{str} replaced by two +backslashes and double quotes replaced by backslash-double quote. +\end{funcdesc} + +\begin{funcdesc}{unquote}{str} +Return a new string which is an \emph{unquoted} version of \var{str}. +If \var{str} ends and begins with double quotes, they are stripped +off. Likewise if \var{str} ends and begins with angle brackets, they +are stripped off. +\end{funcdesc} + +\begin{funcdesc}{parseaddr}{address} +Parse \var{address}, which should be the value of some +address-containing field such as \mailheader{To} or \mailheader{Cc}, +into its constituent ``realname'' and ``email address'' parts. +Returns a tuple of that information, unless the parse fails, in which +case a 2-tuple \code{(None, None)} is returned. +\end{funcdesc} + +\begin{funcdesc}{dump_address_pair}{pair} +The inverse of \method{parseaddr()}, this takes a 2-tuple of the form +\code{(\var{realname}, \var{email_address})} and returns the string +value suitable for a \mailheader{To} or \mailheader{Cc} header. If +the first element of \var{pair} is false, then the second element is +returned unmodified. +\end{funcdesc} + +\begin{funcdesc}{parsedate}{date} +Attempts to parse a date according to the rules in \rfc{2822}. +however, some mailers don't follow that format as specified, so +\function{parsedate()} tries to guess correctly in such cases. +\var{date} is a string containing an \rfc{2822} date, such as +\code{'Mon, 20 Nov 1995 19:12:08 -0500'}. If it succeeds in parsing +the date, \function{parsedate()} returns a 9-tuple that can be passed +directly to \function{time.mktime()}; otherwise \code{None} will be +returned. Note that fields 6, 7, and 8 of the result tuple are not +usable. +\end{funcdesc} + +\begin{funcdesc}{parsedate_tz}{date} +Performs the same function as \function{parsedate()}, but returns +either \code{None} or a 10-tuple; the first 9 elements make up a tuple +that can be passed directly to \function{time.mktime()}, and the tenth +is the offset of the date's timezone from UTC (which is the official +term for Greenwich Mean Time). (Note that the sign of the timezone +offset is the opposite of the sign of the \code{time.timezone} +variable for the same timezone; the latter variable follows the +\POSIX{} standard while this module follows \rfc{2822}.) If the input +string has no timezone, the last element of the tuple returned is +\code{None}. Note that fields 6, 7, and 8 of the result tuple are not +usable. +\end{funcdesc} + +\begin{funcdesc}{mktime_tz}{tuple} +Turn a 10-tuple as returned by \function{parsedate_tz()} into a UTC +timestamp. If the timezone item in the tuple is \code{None}, assume +local time. Minor deficiency: this first interprets the first 8 +elements as a local time and then compensates for the timezone +difference; this may yield a slight error around daylight savings time +switch dates. Not enough to worry about for common use. +\end{funcdesc} + + +\begin{seealso} + \seemodule{email}{Comprehensive email handling package; supersedes + the \module{rfc822} module.} + \seemodule{mailbox}{Classes to read various mailbox formats produced + by end-user mail programs.} + \seemodule{mimetools}{Subclass of \class{rfc822.Message} that + handles MIME encoded messages.} +\end{seealso} + + +\subsection{Message Objects \label{message-objects}} + +A \class{Message} instance has the following methods: + +\begin{methoddesc}{rewindbody}{} +Seek to the start of the message body. This only works if the file +object is seekable. +\end{methoddesc} + +\begin{methoddesc}{isheader}{line} +Returns a line's canonicalized fieldname (the dictionary key that will +be used to index it) if the line is a legal \rfc{2822} header; otherwise +returns \code{None} (implying that parsing should stop here and the +line be pushed back on the input stream). It is sometimes useful to +override this method in a subclass. +\end{methoddesc} + +\begin{methoddesc}{islast}{line} +Return true if the given line is a delimiter on which Message should +stop. The delimiter line is consumed, and the file object's read +location positioned immediately after it. By default this method just +checks that the line is blank, but you can override it in a subclass. +\end{methoddesc} + +\begin{methoddesc}{iscomment}{line} +Return \code{True} if the given line should be ignored entirely, just skipped. +By default this is a stub that always returns \code{False}, but you can +override it in a subclass. +\end{methoddesc} + +\begin{methoddesc}{getallmatchingheaders}{name} +Return a list of lines consisting of all headers matching +\var{name}, if any. Each physical line, whether it is a continuation +line or not, is a separate list item. Return the empty list if no +header matches \var{name}. +\end{methoddesc} + +\begin{methoddesc}{getfirstmatchingheader}{name} +Return a list of lines comprising the first header matching +\var{name}, and its continuation line(s), if any. Return +\code{None} if there is no header matching \var{name}. +\end{methoddesc} + +\begin{methoddesc}{getrawheader}{name} +Return a single string consisting of the text after the colon in the +first header matching \var{name}. This includes leading whitespace, +the trailing linefeed, and internal linefeeds and whitespace if there +any continuation line(s) were present. Return \code{None} if there is +no header matching \var{name}. +\end{methoddesc} + +\begin{methoddesc}{getheader}{name\optional{, default}} +Like \code{getrawheader(\var{name})}, but strip leading and trailing +whitespace. Internal whitespace is not stripped. The optional +\var{default} argument can be used to specify a different default to +be returned when there is no header matching \var{name}. +\end{methoddesc} + +\begin{methoddesc}{get}{name\optional{, default}} +An alias for \method{getheader()}, to make the interface more compatible +with regular dictionaries. +\end{methoddesc} + +\begin{methoddesc}{getaddr}{name} +Return a pair \code{(\var{full name}, \var{email address})} parsed +from the string returned by \code{getheader(\var{name})}. If no +header matching \var{name} exists, return \code{(None, None)}; +otherwise both the full name and the address are (possibly empty) +strings. + +Example: If \var{m}'s first \mailheader{From} header contains the +string \code{'jack@cwi.nl (Jack Jansen)'}, then +\code{m.getaddr('From')} will yield the pair +\code{('Jack Jansen', 'jack@cwi.nl')}. +If the header contained +\code{'Jack Jansen '} instead, it would yield the +exact same result. +\end{methoddesc} + +\begin{methoddesc}{getaddrlist}{name} +This is similar to \code{getaddr(\var{list})}, but parses a header +containing a list of email addresses (e.g.\ a \mailheader{To} header) and +returns a list of \code{(\var{full name}, \var{email address})} pairs +(even if there was only one address in the header). If there is no +header matching \var{name}, return an empty list. + +If multiple headers exist that match the named header (e.g. if there +are several \mailheader{Cc} headers), all are parsed for addresses. +Any continuation lines the named headers contain are also parsed. +\end{methoddesc} + +\begin{methoddesc}{getdate}{name} +Retrieve a header using \method{getheader()} and parse it into a 9-tuple +compatible with \function{time.mktime()}; note that fields 6, 7, and 8 +are not usable. If there is no header matching +\var{name}, or it is unparsable, return \code{None}. + +Date parsing appears to be a black art, and not all mailers adhere to +the standard. While it has been tested and found correct on a large +collection of email from many sources, it is still possible that this +function may occasionally yield an incorrect result. +\end{methoddesc} + +\begin{methoddesc}{getdate_tz}{name} +Retrieve a header using \method{getheader()} and parse it into a +10-tuple; the first 9 elements will make a tuple compatible with +\function{time.mktime()}, and the 10th is a number giving the offset +of the date's timezone from UTC. Note that fields 6, 7, and 8 +are not usable. Similarly to \method{getdate()}, if +there is no header matching \var{name}, or it is unparsable, return +\code{None}. +\end{methoddesc} + +\class{Message} instances also support a limited mapping interface. +In particular: \code{\var{m}[name]} is like +\code{\var{m}.getheader(name)} but raises \exception{KeyError} if +there is no matching header; and \code{len(\var{m})}, +\code{\var{m}.get(\var{name}\optional{, \var{default}})}, +\code{\var{m}.has_key(\var{name})}, \code{\var{m}.keys()}, +\code{\var{m}.values()} \code{\var{m}.items()}, and +\code{\var{m}.setdefault(\var{name}\optional{, \var{default}})} act as +expected, with the one difference that \method{setdefault()} uses +an empty string as the default value. \class{Message} instances +also support the mapping writable interface \code{\var{m}[name] = +value} and \code{del \var{m}[name]}. \class{Message} objects do not +support the \method{clear()}, \method{copy()}, \method{popitem()}, or +\method{update()} methods of the mapping interface. (Support for +\method{get()} and \method{setdefault()} was only added in Python +2.2.) + +Finally, \class{Message} instances have some public instance variables: + +\begin{memberdesc}{headers} +A list containing the entire set of header lines, in the order in +which they were read (except that setitem calls may disturb this +order). Each line contains a trailing newline. The +blank line terminating the headers is not contained in the list. +\end{memberdesc} + +\begin{memberdesc}{fp} +The file or file-like object passed at instantiation time. This can +be used to read the message content. +\end{memberdesc} + +\begin{memberdesc}{unixfrom} +The \UNIX{} \samp{From~} line, if the message had one, or an empty +string. This is needed to regenerate the message in some contexts, +such as an \code{mbox}-style mailbox file. +\end{memberdesc} + + +\subsection{AddressList Objects \label{addresslist-objects}} + +An \class{AddressList} instance has the following methods: + +\begin{methoddesc}{__len__}{} +Return the number of addresses in the address list. +\end{methoddesc} + +\begin{methoddesc}{__str__}{} +Return a canonicalized string representation of the address list. +Addresses are rendered in "name" form, comma-separated. +\end{methoddesc} + +\begin{methoddesc}{__add__}{alist} +Return a new \class{AddressList} instance that contains all addresses +in both \class{AddressList} operands, with duplicates removed (set +union). +\end{methoddesc} + +\begin{methoddesc}{__iadd__}{alist} +In-place version of \method{__add__()}; turns this \class{AddressList} +instance into the union of itself and the right-hand instance, +\var{alist}. +\end{methoddesc} + +\begin{methoddesc}{__sub__}{alist} +Return a new \class{AddressList} instance that contains every address +in the left-hand \class{AddressList} operand that is not present in +the right-hand address operand (set difference). +\end{methoddesc} + +\begin{methoddesc}{__isub__}{alist} +In-place version of \method{__sub__()}, removing addresses in this +list which are also in \var{alist}. +\end{methoddesc} + + +Finally, \class{AddressList} instances have one public instance variable: + +\begin{memberdesc}{addresslist} +A list of tuple string pairs, one per address. In each member, the +first is the canonicalized name part, the second is the +actual route-address (\character{@}-separated username-host.domain +pair). +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/lib/librgbimg.tex b/sys/src/cmd/python/Doc/lib/librgbimg.tex new file mode 100644 index 000000000..ab20fd621 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librgbimg.tex @@ -0,0 +1,54 @@ +\section{\module{rgbimg} --- + Read and write ``SGI RGB'' files} + +\declaremodule{builtin}{rgbimg} +\modulesynopsis{Read and write image files in ``SGI RGB'' format (the module + is \emph{not} SGI specific though!).} + +\deprecated{2.5}{This module is not maintained anymore and seems to be + unused.} + +The \module{rgbimg} module allows Python programs to access SGI imglib image +files (also known as \file{.rgb} files). The module is far from +complete, but is provided anyway since the functionality that there is +enough in some cases. Currently, colormap files are not supported. + +\note{This module is only built by default for 32-bit platforms; it is +not expected to work properly on other systems.} + +The module defines the following variables and functions: + +\begin{excdesc}{error} +This exception is raised on all errors, such as unsupported file type, etc. +\end{excdesc} + +\begin{funcdesc}{sizeofimage}{file} +This function returns a tuple \code{(\var{x}, \var{y})} where +\var{x} and \var{y} are the size of the image in pixels. +Only 4 byte RGBA pixels, 3 byte RGB pixels, and 1 byte greyscale pixels +are currently supported. +\end{funcdesc} + +\begin{funcdesc}{longimagedata}{file} +This function reads and decodes the image on the specified file, and +returns it as a Python string. The string has 4 byte RGBA pixels. +The bottom left pixel is the first in +the string. This format is suitable to pass to \function{gl.lrectwrite()}, +for instance. +\end{funcdesc} + +\begin{funcdesc}{longstoimage}{data, x, y, z, file} +This function writes the RGBA data in \var{data} to image +file \var{file}. \var{x} and \var{y} give the size of the image. +\var{z} is 1 if the saved image should be 1 byte greyscale, 3 if the +saved image should be 3 byte RGB data, or 4 if the saved images should +be 4 byte RGBA data. The input data always contains 4 bytes per pixel. +These are the formats returned by \function{gl.lrectread()}. +\end{funcdesc} + +\begin{funcdesc}{ttob}{flag} +This function sets a global flag which defines whether the scan lines +of the image are read or written from bottom to top (flag is zero, +compatible with SGI GL) or from top to bottom (flag is one, +compatible with X). The default is zero. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/librlcompleter.tex b/sys/src/cmd/python/Doc/lib/librlcompleter.tex new file mode 100644 index 000000000..cb2ac59c5 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librlcompleter.tex @@ -0,0 +1,65 @@ +\section{\module{rlcompleter} --- + Completion function for GNU readline} + +\declaremodule{standard}{rlcompleter} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Python identifier completion, suitable for the GNU readline library.} + +The \module{rlcompleter} module defines a completion function suitable for +the \refmodule{readline} module by completing valid Python identifiers +and keywords. + +When this module is imported on a \UNIX\ platform with the \module{readline} +module available, an instance of the \class{Completer} class is automatically +created and its \method{complete} method is set as the \module{readline} +completer. + +Example: + +\begin{verbatim} +>>> import rlcompleter +>>> import readline +>>> readline.parse_and_bind("tab: complete") +>>> readline. +readline.__doc__ readline.get_line_buffer readline.read_init_file +readline.__file__ readline.insert_text readline.set_completer +readline.__name__ readline.parse_and_bind +>>> readline. +\end{verbatim} + +The \module{rlcompleter} module is designed for use with Python's +interactive mode. A user can add the following lines to his or her +initialization file (identified by the \envvar{PYTHONSTARTUP} +environment variable) to get automatic \kbd{Tab} completion: + +\begin{verbatim} +try: + import readline +except ImportError: + print "Module readline not available." +else: + import rlcompleter + readline.parse_and_bind("tab: complete") +\end{verbatim} + + +On platforms without \module{readline}, the \class{Completer} class defined +by this module can still be used for custom purposes. + +\subsection{Completer Objects \label{completer-objects}} + +Completer objects have the following method: + +\begin{methoddesc}[Completer]{complete}{text, state} +Return the \var{state}th completion for \var{text}. + +If called for \var{text} that doesn't include a period character +(\character{.}), it will complete from names currently defined in +\refmodule[main]{__main__}, \refmodule[builtin]{__builtin__} and +keywords (as defined by the \refmodule{keyword} module). + +If called for a dotted name, it will try to evaluate anything without +obvious side-effects (functions will not be evaluated, but it +can generate calls to \method{__getattr__()}) up to the last part, and +find matches for the rest via the \function{dir()} function. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/librobotparser.tex b/sys/src/cmd/python/Doc/lib/librobotparser.tex new file mode 100644 index 000000000..5eac5283e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librobotparser.tex @@ -0,0 +1,66 @@ +\section{\module{robotparser} --- + Parser for robots.txt} + +\declaremodule{standard}{robotparser} +\modulesynopsis{Loads a \protect\file{robots.txt} file and + answers questions about fetchability of other URLs.} +\sectionauthor{Skip Montanaro}{skip@mojam.com} + +\index{WWW} +\index{World Wide Web} +\index{URL} +\index{robots.txt} + +This module provides a single class, \class{RobotFileParser}, which answers +questions about whether or not a particular user agent can fetch a URL on +the Web site that published the \file{robots.txt} file. For more details on +the structure of \file{robots.txt} files, see +\url{http://www.robotstxt.org/wc/norobots.html}. + +\begin{classdesc}{RobotFileParser}{} + +This class provides a set of methods to read, parse and answer questions +about a single \file{robots.txt} file. + +\begin{methoddesc}{set_url}{url} +Sets the URL referring to a \file{robots.txt} file. +\end{methoddesc} + +\begin{methoddesc}{read}{} +Reads the \file{robots.txt} URL and feeds it to the parser. +\end{methoddesc} + +\begin{methoddesc}{parse}{lines} +Parses the lines argument. +\end{methoddesc} + +\begin{methoddesc}{can_fetch}{useragent, url} +Returns \code{True} if the \var{useragent} is allowed to fetch the \var{url} +according to the rules contained in the parsed \file{robots.txt} file. +\end{methoddesc} + +\begin{methoddesc}{mtime}{} +Returns the time the \code{robots.txt} file was last fetched. This is +useful for long-running web spiders that need to check for new +\code{robots.txt} files periodically. +\end{methoddesc} + +\begin{methoddesc}{modified}{} +Sets the time the \code{robots.txt} file was last fetched to the current +time. +\end{methoddesc} + +\end{classdesc} + +The following example demonstrates basic use of the RobotFileParser class. + +\begin{verbatim} +>>> import robotparser +>>> rp = robotparser.RobotFileParser() +>>> rp.set_url("http://www.musi-cal.com/robots.txt") +>>> rp.read() +>>> rp.can_fetch("*", "http://www.musi-cal.com/cgi-bin/search?city=San+Francisco") +False +>>> rp.can_fetch("*", "http://www.musi-cal.com/") +True +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/librunpy.tex b/sys/src/cmd/python/Doc/lib/librunpy.tex new file mode 100644 index 000000000..c7a7e5197 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/librunpy.tex @@ -0,0 +1,74 @@ +\section{\module{runpy} --- + Locating and executing Python modules.} + +\declaremodule{standard}{runpy} % standard library, in Python + +\moduleauthor{Nick Coghlan}{ncoghlan@gmail.com} + +\modulesynopsis{Locate and execute Python modules as scripts} + +\versionadded{2.5} + +The \module{runpy} module is used to locate and run Python modules +without importing them first. Its main use is to implement the +\programopt{-m} command line switch that allows scripts to be located +using the Python module namespace rather than the filesystem. + +When executed as a script, the module effectively operates as follows: +\begin{verbatim} + del sys.argv[0] # Remove the runpy module from the arguments + run_module(sys.argv[0], run_name="__main__", alter_sys=True) +\end{verbatim} + +The \module{runpy} module provides a single function: + +\begin{funcdesc}{run_module}{mod_name\optional{, init_globals} +\optional{, run_name}\optional{, alter_sys}} +Execute the code of the specified module and return the resulting +module globals dictionary. The module's code is first located using +the standard import mechanism (refer to PEP 302 for details) and +then executed in a fresh module namespace. + +The optional dictionary argument \var{init_globals} may be used to +pre-populate the globals dictionary before the code is executed. +The supplied dictionary will not be modified. If any of the special +global variables below are defined in the supplied dictionary, those +definitions are overridden by the \code{run_module} function. + +The special global variables \code{__name__}, \code{__file__}, +\code{__loader__} and \code{__builtins__} are set in the globals +dictionary before the module code is executed. + +\code{__name__} is set to \var{run_name} if this optional argument is +supplied, and the \var{mod_name} argument otherwise. + +\code{__loader__} is set to the PEP 302 module loader used to retrieve +the code for the module (This loader may be a wrapper around the +standard import mechanism). + +\code{__file__} is set to the name provided by the module loader. If +the loader does not make filename information available, this +variable is set to \code{None}. + +\code{__builtins__} is automatically initialised with a reference to +the top level namespace of the \module{__builtin__} module. + +If the argument \var{alter_sys} is supplied and evaluates to +\code{True}, then \code{sys.argv[0]} is updated with the value of +\code{__file__} and \code{sys.modules[__name__]} is updated with a +temporary module object for the module being executed. Both +\code{sys.argv[0]} and \code{sys.modules[__name__]} are restored to +their original values before the function returns. + +Note that this manipulation of \module{sys} is not thread-safe. Other +threads may see the partially initialised module, as well as the +altered list of arguments. It is recommended that the \module{sys} +module be left alone when invoking this function from threaded code. +\end{funcdesc} + +\begin{seealso} + +\seepep{338}{Executing modules as scripts}{PEP written and +implemented by Nick Coghlan.} + +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libsched.tex b/sys/src/cmd/python/Doc/lib/libsched.tex new file mode 100644 index 000000000..6b586a845 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsched.tex @@ -0,0 +1,97 @@ +\section{\module{sched} --- + Event scheduler} + +% LaTeXed and enhanced from comments in file + +\declaremodule{standard}{sched} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{General purpose event scheduler.} + +The \module{sched} module defines a class which implements a general +purpose event scheduler:\index{event scheduling} + +\begin{classdesc}{scheduler}{timefunc, delayfunc} +The \class{scheduler} class defines a generic interface to scheduling +events. It needs two functions to actually deal with the ``outside world'' +--- \var{timefunc} should be callable without arguments, and return +a number (the ``time'', in any units whatsoever). The \var{delayfunc} +function should be callable with one argument, compatible with the output +of \var{timefunc}, and should delay that many time units. +\var{delayfunc} will also be called with the argument \code{0} after +each event is run to allow other threads an opportunity to run in +multi-threaded applications. +\end{classdesc} + +Example: + +\begin{verbatim} +>>> import sched, time +>>> s=sched.scheduler(time.time, time.sleep) +>>> def print_time(): print "From print_time", time.time() +... +>>> def print_some_times(): +... print time.time() +... s.enter(5, 1, print_time, ()) +... s.enter(10, 1, print_time, ()) +... s.run() +... print time.time() +... +>>> print_some_times() +930343690.257 +From print_time 930343695.274 +From print_time 930343700.273 +930343700.276 +\end{verbatim} + + +\subsection{Scheduler Objects \label{scheduler-objects}} + +\class{scheduler} instances have the following methods: + +\begin{methoddesc}{enterabs}{time, priority, action, argument} +Schedule a new event. The \var{time} argument should be a numeric type +compatible with the return value of the \var{timefunc} function passed +to the constructor. Events scheduled for +the same \var{time} will be executed in the order of their +\var{priority}. + +Executing the event means executing +\code{\var{action}(*\var{argument})}. \var{argument} must be a +sequence holding the parameters for \var{action}. + +Return value is an event which may be used for later cancellation of +the event (see \method{cancel()}). +\end{methoddesc} + +\begin{methoddesc}{enter}{delay, priority, action, argument} +Schedule an event for \var{delay} more time units. Other then the +relative time, the other arguments, the effect and the return value +are the same as those for \method{enterabs()}. +\end{methoddesc} + +\begin{methoddesc}{cancel}{event} +Remove the event from the queue. If \var{event} is not an event +currently in the queue, this method will raise a +\exception{RuntimeError}. +\end{methoddesc} + +\begin{methoddesc}{empty}{} +Return true if the event queue is empty. +\end{methoddesc} + +\begin{methoddesc}{run}{} +Run all scheduled events. This function will wait +(using the \function{delayfunc} function passed to the constructor) +for the next event, then execute it and so on until there are no more +scheduled events. + +Either \var{action} or \var{delayfunc} can raise an exception. In +either case, the scheduler will maintain a consistent state and +propagate the exception. If an exception is raised by \var{action}, +the event will not be attempted in future calls to \method{run()}. + +If a sequence of events takes longer to run than the time available +before the next event, the scheduler will simply fall behind. No +events will be dropped; the calling code is responsible for canceling +events which are no longer pertinent. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libselect.tex b/sys/src/cmd/python/Doc/lib/libselect.tex new file mode 100644 index 000000000..e93f70fe1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libselect.tex @@ -0,0 +1,132 @@ +\section{\module{select} --- + Waiting for I/O completion} + +\declaremodule{builtin}{select} +\modulesynopsis{Wait for I/O completion on multiple streams.} + + +This module provides access to the \cfunction{select()} +and \cfunction{poll()} functions +available in most operating systems. Note that on Windows, it only +works for sockets; on other operating systems, it also works for other +file types (in particular, on \UNIX, it works on pipes). It cannot +be used on regular files to determine whether a file has grown since +it was last read. + +The module defines the following: + +\begin{excdesc}{error} +The exception raised when an error occurs. The accompanying value is +a pair containing the numeric error code from \cdata{errno} and the +corresponding string, as would be printed by the \C{} function +\cfunction{perror()}. +\end{excdesc} + +\begin{funcdesc}{poll}{} +(Not supported by all operating systems.) Returns a polling object, +which supports registering and unregistering file descriptors, and +then polling them for I/O events; +see section~\ref{poll-objects} below for the methods supported by +polling objects. +\end{funcdesc} + +\begin{funcdesc}{select}{iwtd, owtd, ewtd\optional{, timeout}} +This is a straightforward interface to the \UNIX{} \cfunction{select()} +system call. The first three arguments are sequences of `waitable +objects': either integers representing file descriptors or +objects with a parameterless method named \method{fileno()} returning +such an integer. The three sequences of waitable objects are for input, +output and `exceptional conditions', respectively. Empty sequences are +allowed, but acceptance of three empty sequences is platform-dependent. +(It is known to work on \UNIX{} but not on Windows.) The optional +\var{timeout} argument specifies a time-out as a floating point number +in seconds. When the \var{timeout} argument is omitted the function +blocks until at least one file descriptor is ready. A time-out value +of zero specifies a poll and never blocks. + +The return value is a triple of lists of objects that are ready: +subsets of the first three arguments. When the time-out is reached +without a file descriptor becoming ready, three empty lists are +returned. + +Among the acceptable object types in the sequences are Python file +objects (e.g. \code{sys.stdin}, or objects returned by +\function{open()} or \function{os.popen()}), socket objects +returned by \function{socket.socket()}.% +\withsubitem{(in module socket)}{\ttindex{socket()}} +\withsubitem{(in module os)}{\ttindex{popen()}} +You may also define a \dfn{wrapper} class yourself, as long as it has +an appropriate \method{fileno()} method (that really returns a file +descriptor, not just a random integer). +\note{File objects on Windows are not acceptable, but sockets +are.\index{WinSock} On Windows, the underlying \cfunction{select()} +function is provided by the WinSock library, and does not handle file +descriptors that don't originate from WinSock.} +\end{funcdesc} + +\subsection{Polling Objects + \label{poll-objects}} + +The \cfunction{poll()} system call, supported on most \UNIX{} systems, +provides better scalability for network servers that service many, +many clients at the same time. +\cfunction{poll()} scales better because the system call only +requires listing the file descriptors of interest, while \cfunction{select()} +builds a bitmap, turns on bits for the fds of interest, and then +afterward the whole bitmap has to be linearly scanned again. +\cfunction{select()} is O(highest file descriptor), while +\cfunction{poll()} is O(number of file descriptors). + +\begin{methoddesc}{register}{fd\optional{, eventmask}} +Register a file descriptor with the polling object. Future calls to +the \method{poll()} method will then check whether the file descriptor +has any pending I/O events. \var{fd} can be either an integer, or an +object with a \method{fileno()} method that returns an integer. File +objects implement +\method{fileno()}, so they can also be used as the argument. + +\var{eventmask} is an optional bitmask describing the type of events you +want to check for, and can be a combination of the constants +\constant{POLLIN}, \constant{POLLPRI}, and \constant{POLLOUT}, +described in the table below. If not specified, the default value +used will check for all 3 types of events. + +\begin{tableii}{l|l}{constant}{Constant}{Meaning} + \lineii{POLLIN}{There is data to read} + \lineii{POLLPRI}{There is urgent data to read} + \lineii{POLLOUT}{Ready for output: writing will not block} + \lineii{POLLERR}{Error condition of some sort} + \lineii{POLLHUP}{Hung up} + \lineii{POLLNVAL}{Invalid request: descriptor not open} +\end{tableii} + +Registering a file descriptor that's already registered is not an +error, and has the same effect as registering the descriptor exactly +once. +\end{methoddesc} + +\begin{methoddesc}{unregister}{fd} +Remove a file descriptor being tracked by a polling object. Just like +the \method{register()} method, \var{fd} can be an integer or an +object with a \method{fileno()} method that returns an integer. + +Attempting to remove a file descriptor that was never registered +causes a \exception{KeyError} exception to be raised. +\end{methoddesc} + +\begin{methoddesc}{poll}{\optional{timeout}} +Polls the set of registered file descriptors, and returns a +possibly-empty list containing \code{(\var{fd}, \var{event})} 2-tuples +for the descriptors that have events or errors to report. +\var{fd} is the file descriptor, and \var{event} is a bitmask +with bits set for the reported events for that descriptor +--- \constant{POLLIN} for waiting input, +\constant{POLLOUT} to indicate that the descriptor can be written to, and +so forth. +An empty list indicates that the call timed out and no file +descriptors had any events to report. +If \var{timeout} is given, it specifies the length of time in +milliseconds which the system will wait for events before returning. +If \var{timeout} is omitted, negative, or \constant{None}, the call will +block until there is an event for this poll object. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libsets.tex b/sys/src/cmd/python/Doc/lib/libsets.tex new file mode 100644 index 000000000..22bf34bfb --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsets.tex @@ -0,0 +1,264 @@ +\section{\module{sets} --- + Unordered collections of unique elements} + +\declaremodule{standard}{sets} +\modulesynopsis{Implementation of sets of unique elements.} +\moduleauthor{Greg V. Wilson}{gvwilson@nevex.com} +\moduleauthor{Alex Martelli}{aleax@aleax.it} +\moduleauthor{Guido van Rossum}{guido@python.org} +\sectionauthor{Raymond D. Hettinger}{python@rcn.com} + +\versionadded{2.3} + +The \module{sets} module provides classes for constructing and manipulating +unordered collections of unique elements. Common uses include membership +testing, removing duplicates from a sequence, and computing standard math +operations on sets such as intersection, union, difference, and symmetric +difference. + +Like other collections, sets support \code{\var{x} in \var{set}}, +\code{len(\var{set})}, and \code{for \var{x} in \var{set}}. Being an +unordered collection, sets do not record element position or order of +insertion. Accordingly, sets do not support indexing, slicing, or +other sequence-like behavior. + +Most set applications use the \class{Set} class which provides every set +method except for \method{__hash__()}. For advanced applications requiring +a hash method, the \class{ImmutableSet} class adds a \method{__hash__()} +method but omits methods which alter the contents of the set. Both +\class{Set} and \class{ImmutableSet} derive from \class{BaseSet}, an +abstract class useful for determining whether something is a set: +\code{isinstance(\var{obj}, BaseSet)}. + +The set classes are implemented using dictionaries. Accordingly, the +requirements for set elements are the same as those for dictionary keys; +namely, that the element defines both \method{__eq__} and \method{__hash__}. +As a result, sets +cannot contain mutable elements such as lists or dictionaries. +However, they can contain immutable collections such as tuples or +instances of \class{ImmutableSet}. For convenience in implementing +sets of sets, inner sets are automatically converted to immutable +form, for example, \code{Set([Set(['dog'])])} is transformed to +\code{Set([ImmutableSet(['dog'])])}. + +\begin{classdesc}{Set}{\optional{iterable}} +Constructs a new empty \class{Set} object. If the optional \var{iterable} +parameter is supplied, updates the set with elements obtained from iteration. +All of the elements in \var{iterable} should be immutable or be transformable +to an immutable using the protocol described in +section~\ref{immutable-transforms}. +\end{classdesc} + +\begin{classdesc}{ImmutableSet}{\optional{iterable}} +Constructs a new empty \class{ImmutableSet} object. If the optional +\var{iterable} parameter is supplied, updates the set with elements obtained +from iteration. All of the elements in \var{iterable} should be immutable or +be transformable to an immutable using the protocol described in +section~\ref{immutable-transforms}. + +Because \class{ImmutableSet} objects provide a \method{__hash__()} method, +they can be used as set elements or as dictionary keys. \class{ImmutableSet} +objects do not have methods for adding or removing elements, so all of the +elements must be known when the constructor is called. +\end{classdesc} + + +\subsection{Set Objects \label{set-objects}} + +Instances of \class{Set} and \class{ImmutableSet} both provide +the following operations: + +\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result} + \lineiii{len(\var{s})}{}{cardinality of set \var{s}} + + \hline + \lineiii{\var{x} in \var{s}}{} + {test \var{x} for membership in \var{s}} + \lineiii{\var{x} not in \var{s}}{} + {test \var{x} for non-membership in \var{s}} + \lineiii{\var{s}.issubset(\var{t})}{\code{\var{s} <= \var{t}}} + {test whether every element in \var{s} is in \var{t}} + \lineiii{\var{s}.issuperset(\var{t})}{\code{\var{s} >= \var{t}}} + {test whether every element in \var{t} is in \var{s}} + + \hline + \lineiii{\var{s}.union(\var{t})}{\var{s} \textbar{} \var{t}} + {new set with elements from both \var{s} and \var{t}} + \lineiii{\var{s}.intersection(\var{t})}{\var{s} \&\ \var{t}} + {new set with elements common to \var{s} and \var{t}} + \lineiii{\var{s}.difference(\var{t})}{\var{s} - \var{t}} + {new set with elements in \var{s} but not in \var{t}} + \lineiii{\var{s}.symmetric_difference(\var{t})}{\var{s} \^\ \var{t}} + {new set with elements in either \var{s} or \var{t} but not both} + \lineiii{\var{s}.copy()}{} + {new set with a shallow copy of \var{s}} +\end{tableiii} + +Note, the non-operator versions of \method{union()}, +\method{intersection()}, \method{difference()}, and +\method{symmetric_difference()} will accept any iterable as an argument. +In contrast, their operator based counterparts require their arguments to +be sets. This precludes error-prone constructions like +\code{Set('abc') \&\ 'cbs'} in favor of the more readable +\code{Set('abc').intersection('cbs')}. +\versionchanged[Formerly all arguments were required to be sets]{2.3.1} + +In addition, both \class{Set} and \class{ImmutableSet} +support set to set comparisons. Two sets are equal if and only if +every element of each set is contained in the other (each is a subset +of the other). +A set is less than another set if and only if the first set is a proper +subset of the second set (is a subset, but is not equal). +A set is greater than another set if and only if the first set is a proper +superset of the second set (is a superset, but is not equal). + +The subset and equality comparisons do not generalize to a complete +ordering function. For example, any two disjoint sets are not equal and +are not subsets of each other, so \emph{all} of the following return +\code{False}: \code{\var{a}<\var{b}}, \code{\var{a}==\var{b}}, or +\code{\var{a}>\var{b}}. +Accordingly, sets do not implement the \method{__cmp__} method. + +Since sets only define partial ordering (subset relationships), the output +of the \method{list.sort()} method is undefined for lists of sets. + +The following table lists operations available in \class{ImmutableSet} +but not found in \class{Set}: + +\begin{tableii}{c|l}{code}{Operation}{Result} + \lineii{hash(\var{s})}{returns a hash value for \var{s}} +\end{tableii} + +The following table lists operations available in \class{Set} +but not found in \class{ImmutableSet}: + +\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result} + \lineiii{\var{s}.update(\var{t})} + {\var{s} \textbar= \var{t}} + {return set \var{s} with elements added from \var{t}} + \lineiii{\var{s}.intersection_update(\var{t})} + {\var{s} \&= \var{t}} + {return set \var{s} keeping only elements also found in \var{t}} + \lineiii{\var{s}.difference_update(\var{t})} + {\var{s} -= \var{t}} + {return set \var{s} after removing elements found in \var{t}} + \lineiii{\var{s}.symmetric_difference_update(\var{t})} + {\var{s} \textasciicircum= \var{t}} + {return set \var{s} with elements from \var{s} or \var{t} + but not both} + + \hline + \lineiii{\var{s}.add(\var{x})}{} + {add element \var{x} to set \var{s}} + \lineiii{\var{s}.remove(\var{x})}{} + {remove \var{x} from set \var{s}; raises \exception{KeyError} + if not present} + \lineiii{\var{s}.discard(\var{x})}{} + {removes \var{x} from set \var{s} if present} + \lineiii{\var{s}.pop()}{} + {remove and return an arbitrary element from \var{s}; raises + \exception{KeyError} if empty} + \lineiii{\var{s}.clear()}{} + {remove all elements from set \var{s}} +\end{tableiii} + +Note, the non-operator versions of \method{update()}, +\method{intersection_update()}, \method{difference_update()}, and +\method{symmetric_difference_update()} will accept any iterable as +an argument. +\versionchanged[Formerly all arguments were required to be sets]{2.3.1} + +Also note, the module also includes a \method{union_update()} method +which is an alias for \method{update()}. The method is included for +backwards compatibility. Programmers should prefer the +\method{update()} method because it is supported by the builtin +\class{set()} and \class{frozenset()} types. + +\subsection{Example \label{set-example}} + +\begin{verbatim} +>>> from sets import Set +>>> engineers = Set(['John', 'Jane', 'Jack', 'Janice']) +>>> programmers = Set(['Jack', 'Sam', 'Susan', 'Janice']) +>>> managers = Set(['Jane', 'Jack', 'Susan', 'Zack']) +>>> employees = engineers | programmers | managers # union +>>> engineering_management = engineers & managers # intersection +>>> fulltime_management = managers - engineers - programmers # difference +>>> engineers.add('Marvin') # add element +>>> print engineers +Set(['Jane', 'Marvin', 'Janice', 'John', 'Jack']) +>>> employees.issuperset(engineers) # superset test +False +>>> employees.union_update(engineers) # update from another set +>>> employees.issuperset(engineers) +True +>>> for group in [engineers, programmers, managers, employees]: +... group.discard('Susan') # unconditionally remove element +... print group +... +Set(['Jane', 'Marvin', 'Janice', 'John', 'Jack']) +Set(['Janice', 'Jack', 'Sam']) +Set(['Jane', 'Zack', 'Jack']) +Set(['Jack', 'Sam', 'Jane', 'Marvin', 'Janice', 'John', 'Zack']) +\end{verbatim} + + +\subsection{Protocol for automatic conversion to immutable + \label{immutable-transforms}} + +Sets can only contain immutable elements. For convenience, mutable +\class{Set} objects are automatically copied to an \class{ImmutableSet} +before being added as a set element. + +The mechanism is to always add a hashable element, or if it is not +hashable, the element is checked to see if it has an +\method{__as_immutable__()} method which returns an immutable equivalent. + +Since \class{Set} objects have a \method{__as_immutable__()} method +returning an instance of \class{ImmutableSet}, it is possible to +construct sets of sets. + +A similar mechanism is needed by the \method{__contains__()} and +\method{remove()} methods which need to hash an element to check +for membership in a set. Those methods check an element for hashability +and, if not, check for a \method{__as_temporarily_immutable__()} method +which returns the element wrapped by a class that provides temporary +methods for \method{__hash__()}, \method{__eq__()}, and \method{__ne__()}. + +The alternate mechanism spares the need to build a separate copy of +the original mutable object. + +\class{Set} objects implement the \method{__as_temporarily_immutable__()} +method which returns the \class{Set} object wrapped by a new class +\class{_TemporarilyImmutableSet}. + +The two mechanisms for adding hashability are normally invisible to the +user; however, a conflict can arise in a multi-threaded environment +where one thread is updating a set while another has temporarily wrapped it +in \class{_TemporarilyImmutableSet}. In other words, sets of mutable sets +are not thread-safe. + + +\subsection{Comparison to the built-in \class{set} types + \label{comparison-to-builtin-set}} + +The built-in \class{set} and \class{frozenset} types were designed based +on lessons learned from the \module{sets} module. The key differences are: + +\begin{itemize} +\item \class{Set} and \class{ImmutableSet} were renamed to \class{set} and + \class{frozenset}. +\item There is no equivalent to \class{BaseSet}. Instead, use + \code{isinstance(x, (set, frozenset))}. +\item The hash algorithm for the built-ins performs significantly better + (fewer collisions) for most datasets. +\item The built-in versions have more space efficient pickles. +\item The built-in versions do not have a \method{union_update()} method. + Instead, use the \method{update()} method which is equivalent. +\item The built-in versions do not have a \method{_repr(sorted=True)} method. + Instead, use the built-in \function{repr()} and \function{sorted()} + functions: \code{repr(sorted(s))}. +\item The built-in version does not have a protocol for automatic conversion + to immutable. Many found this feature to be confusing and no one + in the community reported having found real uses for it. +\end{itemize} diff --git a/sys/src/cmd/python/Doc/lib/libsgi.tex b/sys/src/cmd/python/Doc/lib/libsgi.tex new file mode 100644 index 000000000..ca17ad03b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsgi.tex @@ -0,0 +1,7 @@ +\chapter{SGI IRIX Specific Services} +\label{sgi} + +The modules described in this chapter provide interfaces to features +that are unique to SGI's IRIX operating system (versions 4 and 5). + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/libsgmllib.tex b/sys/src/cmd/python/Doc/lib/libsgmllib.tex new file mode 100644 index 000000000..1fe0d6309 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsgmllib.tex @@ -0,0 +1,271 @@ +\section{\module{sgmllib} --- + Simple SGML parser} + +\declaremodule{standard}{sgmllib} +\modulesynopsis{Only as much of an SGML parser as needed to parse HTML.} + +\index{SGML} + +This module defines a class \class{SGMLParser} which serves as the +basis for parsing text files formatted in SGML (Standard Generalized +Mark-up Language). In fact, it does not provide a full SGML parser +--- it only parses SGML insofar as it is used by HTML, and the module +only exists as a base for the \refmodule{htmllib} module. Another +HTML parser which supports XHTML and offers a somewhat different +interface is available in the \refmodule{HTMLParser} module. + +\begin{classdesc}{SGMLParser}{} +The \class{SGMLParser} class is instantiated without arguments. +The parser is hardcoded to recognize the following +constructs: + +\begin{itemize} +\item +Opening and closing tags of the form +\samp{<\var{tag} \var{attr}="\var{value}" ...>} and +\samp{}, respectively. + +\item +Numeric character references of the form \samp{\&\#\var{name};}. + +\item +Entity references of the form \samp{\&\var{name};}. + +\item +SGML comments of the form \samp{}. Note that +spaces, tabs, and newlines are allowed between the trailing +\samp{>} and the immediately preceding \samp{--}. + +\end{itemize} +\end{classdesc} + +A single exception is defined as well: + +\begin{excdesc}{SGMLParseError} +Exception raised by the \class{SGMLParser} class when it encounters an +error while parsing. +\versionadded{2.1} +\end{excdesc} + + +\class{SGMLParser} instances have the following methods: + + +\begin{methoddesc}{reset}{} +Reset the instance. Loses all unprocessed data. This is called +implicitly at instantiation time. +\end{methoddesc} + +\begin{methoddesc}{setnomoretags}{} +Stop processing tags. Treat all following input as literal input +(CDATA). (This is only provided so the HTML tag +\code{} can be implemented.) +\end{methoddesc} + +\begin{methoddesc}{setliteral}{} +Enter literal mode (CDATA mode). +\end{methoddesc} + +\begin{methoddesc}{feed}{data} +Feed some text to the parser. It is processed insofar as it consists +of complete elements; incomplete data is buffered until more data is +fed or \method{close()} is called. +\end{methoddesc} + +\begin{methoddesc}{close}{} +Force processing of all buffered data as if it were followed by an +end-of-file mark. This method may be redefined by a derived class to +define additional processing at the end of the input, but the +redefined version should always call \method{close()}. +\end{methoddesc} + +\begin{methoddesc}{get_starttag_text}{} +Return the text of the most recently opened start tag. This should +not normally be needed for structured processing, but may be useful in +dealing with HTML ``as deployed'' or for re-generating input with +minimal changes (whitespace between attributes can be preserved, +etc.). +\end{methoddesc} + +\begin{methoddesc}{handle_starttag}{tag, method, attributes} +This method is called to handle start tags for which either a +\method{start_\var{tag}()} or \method{do_\var{tag}()} method has been +defined. The \var{tag} argument is the name of the tag converted to +lower case, and the \var{method} argument is the bound method which +should be used to support semantic interpretation of the start tag. +The \var{attributes} argument is a list of \code{(\var{name}, +\var{value})} pairs containing the attributes found inside the tag's +\code{<>} brackets. + +The \var{name} has been translated to lower case. +Double quotes and backslashes in the \var{value} have been interpreted, +as well as known character references and known entity references +terminated by a semicolon (normally, entity references can be terminated +by any non-alphanumerical character, but this would break the very +common case of \code{<A HREF="url?spam=1\&eggs=2">} when \code{eggs} +is a valid entity name). + +For instance, for the tag \code{<A HREF="http://www.cwi.nl/">}, this +method would be called as \samp{unknown_starttag('a', [('href', +'http://www.cwi.nl/')])}. The base implementation simply calls +\var{method} with \var{attributes} as the only argument. +\versionadded[Handling of entity and character references within + attribute values]{2.5} +\end{methoddesc} + +\begin{methoddesc}{handle_endtag}{tag, method} +This method is called to handle endtags for which an +\method{end_\var{tag}()} method has been defined. The +\var{tag} argument is the name of the tag converted to lower case, and +the \var{method} argument is the bound method which should be used to +support semantic interpretation of the end tag. If no +\method{end_\var{tag}()} method is defined for the closing element, +this handler is not called. The base implementation simply calls +\var{method}. +\end{methoddesc} + +\begin{methoddesc}{handle_data}{data} +This method is called to process arbitrary data. It is intended to be +overridden by a derived class; the base class implementation does +nothing. +\end{methoddesc} + +\begin{methoddesc}{handle_charref}{ref} +This method is called to process a character reference of the form +\samp{\&\#\var{ref};}. The base implementation uses +\method{convert_charref()} to convert the reference to a string. If +that method returns a string, it is passed to \method{handle_data()}, +otherwise \method{unknown_charref(\var{ref})} is called to handle the +error. +\versionchanged[Use \method{convert_charref()} instead of hard-coding +the conversion]{2.5} +\end{methoddesc} + +\begin{methoddesc}{convert_charref}{ref} +Convert a character reference to a string, or \code{None}. \var{ref} +is the reference passed in as a string. In the base implementation, +\var{ref} must be a decimal number in the range 0-255. It converts +the code point found using the \method{convert_codepoint()} method. +If \var{ref} is invalid or out of range, this method returns +\code{None}. This method is called by the default +\method{handle_charref()} implementation and by the attribute value +parser. +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}{convert_codepoint}{codepoint} +Convert a codepoint to a \class{str} value. Encodings can be handled +here if appropriate, though the rest of \module{sgmllib} is oblivious +on this matter. +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}{handle_entityref}{ref} +This method is called to process a general entity reference of the +form \samp{\&\var{ref};} where \var{ref} is an general entity +reference. It converts \var{ref} by passing it to +\method{convert_entityref()}. If a translation is returned, it +calls the method \method{handle_data()} with the translation; +otherwise, it calls the method \code{unknown_entityref(\var{ref})}. +The default \member{entitydefs} defines translations for +\code{\&amp;}, \code{\&apos}, \code{\&gt;}, \code{\&lt;}, and +\code{\&quot;}. +\versionchanged[Use \method{convert_entityref()} instead of hard-coding +the conversion]{2.5} +\end{methoddesc} + +\begin{methoddesc}{convert_entityref}{ref} +Convert a named entity reference to a \class{str} value, or +\code{None}. The resulting value will not be parsed. \var{ref} will +be only the name of the entity. The default implementation looks for +\var{ref} in the instance (or class) variable \member{entitydefs} +which should be a mapping from entity names to corresponding +translations. If no translation is available for \var{ref}, this +method returns \code{None}. This method is called by the default +\method{handle_entityref()} implementation and by the attribute value +parser. +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}{handle_comment}{comment} +This method is called when a comment is encountered. The +\var{comment} argument is a string containing the text between the +\samp{<!--} and \samp{-->} delimiters, but not the delimiters +themselves. For example, the comment \samp{<!--text-->} will +cause this method to be called with the argument \code{'text'}. The +default method does nothing. +\end{methoddesc} + +\begin{methoddesc}{handle_decl}{data} +Method called when an SGML declaration is read by the parser. In +practice, the \code{DOCTYPE} declaration is the only thing observed in +HTML, but the parser does not discriminate among different (or broken) +declarations. Internal subsets in a \code{DOCTYPE} declaration are +not supported. The \var{data} parameter will be the entire contents +of the declaration inside the \code{<!}...\code{>} markup. The +default implementation does nothing. +\end{methoddesc} + +\begin{methoddesc}{report_unbalanced}{tag} +This method is called when an end tag is found which does not +correspond to any open element. +\end{methoddesc} + +\begin{methoddesc}{unknown_starttag}{tag, attributes} +This method is called to process an unknown start tag. It is intended +to be overridden by a derived class; the base class implementation +does nothing. +\end{methoddesc} + +\begin{methoddesc}{unknown_endtag}{tag} +This method is called to process an unknown end tag. It is intended +to be overridden by a derived class; the base class implementation +does nothing. +\end{methoddesc} + +\begin{methoddesc}{unknown_charref}{ref} +This method is called to process unresolvable numeric character +references. Refer to \method{handle_charref()} to determine what is +handled by default. It is intended to be overridden by a derived +class; the base class implementation does nothing. +\end{methoddesc} + +\begin{methoddesc}{unknown_entityref}{ref} +This method is called to process an unknown entity reference. It is +intended to be overridden by a derived class; the base class +implementation does nothing. +\end{methoddesc} + +Apart from overriding or extending the methods listed above, derived +classes may also define methods of the following form to define +processing of specific tags. Tag names in the input stream are case +independent; the \var{tag} occurring in method names must be in lower +case: + +\begin{methoddescni}{start_\var{tag}}{attributes} +This method is called to process an opening tag \var{tag}. It has +preference over \method{do_\var{tag}()}. The +\var{attributes} argument has the same meaning as described for +\method{handle_starttag()} above. +\end{methoddescni} + +\begin{methoddescni}{do_\var{tag}}{attributes} +This method is called to process an opening tag \var{tag} +for which no \method{start_\var{tag}} method is defined. +The \var{attributes} argument +has the same meaning as described for \method{handle_starttag()} above. +\end{methoddescni} + +\begin{methoddescni}{end_\var{tag}}{} +This method is called to process a closing tag \var{tag}. +\end{methoddescni} + +Note that the parser maintains a stack of open elements for which no +end tag has been found yet. Only tags processed by +\method{start_\var{tag}()} are pushed on this stack. Definition of an +\method{end_\var{tag}()} method is optional for these tags. For tags +processed by \method{do_\var{tag}()} or by \method{unknown_tag()}, no +\method{end_\var{tag}()} method must be defined; if defined, it will +not be used. If both \method{start_\var{tag}()} and +\method{do_\var{tag}()} methods exist for a tag, the +\method{start_\var{tag}()} method takes precedence. diff --git a/sys/src/cmd/python/Doc/lib/libsha.tex b/sys/src/cmd/python/Doc/lib/libsha.tex new file mode 100644 index 000000000..6d1da68da --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsha.tex @@ -0,0 +1,83 @@ +\section{\module{sha} --- + SHA-1 message digest algorithm} + +\declaremodule{builtin}{sha} +\modulesynopsis{NIST's secure hash algorithm, SHA.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +\deprecated{2.5}{Use the \refmodule{hashlib} module instead.} + + +This module implements the interface to NIST's\index{NIST} secure hash +algorithm,\index{Secure Hash Algorithm} known as SHA-1. SHA-1 is an +improved version of the original SHA hash algorithm. It is used in +the same way as the \refmodule{md5} module:\ use \function{new()} +to create an sha object, then feed this object with arbitrary strings +using the \method{update()} method, and at any point you can ask it +for the \dfn{digest} of the concatenation of the strings fed to it +so far.\index{checksum!SHA} SHA-1 digests are 160 bits instead of +MD5's 128 bits. + + +\begin{funcdesc}{new}{\optional{string}} + Return a new sha object. If \var{string} is present, the method + call \code{update(\var{string})} is made. +\end{funcdesc} + + +The following values are provided as constants in the module and as +attributes of the sha objects returned by \function{new()}: + +\begin{datadesc}{blocksize} + Size of the blocks fed into the hash function; this is always + \code{1}. This size is used to allow an arbitrary string to be + hashed. +\end{datadesc} + +\begin{datadesc}{digest_size} + The size of the resulting digest in bytes. This is always + \code{20}. +\end{datadesc} + + +An sha object has the same methods as md5 objects: + +\begin{methoddesc}[sha]{update}{arg} +Update the sha object with the string \var{arg}. Repeated calls are +equivalent to a single call with the concatenation of all the +arguments: \code{m.update(a); m.update(b)} is equivalent to +\code{m.update(a+b)}. +\end{methoddesc} + +\begin{methoddesc}[sha]{digest}{} +Return the digest of the strings passed to the \method{update()} +method so far. This is a 20-byte string which may contain +non-\ASCII{} characters, including null bytes. +\end{methoddesc} + +\begin{methoddesc}[sha]{hexdigest}{} +Like \method{digest()} except the digest is returned as a string of +length 40, containing only hexadecimal digits. This may +be used to exchange the value safely in email or other non-binary +environments. +\end{methoddesc} + +\begin{methoddesc}[sha]{copy}{} +Return a copy (``clone'') of the sha object. This can be used to +efficiently compute the digests of strings that share a common initial +substring. +\end{methoddesc} + +\begin{seealso} + \seetitle[http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf] + {Secure Hash Standard} + {The Secure Hash Algorithm is defined by NIST document FIPS + PUB 180-2: + \citetitle[http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf] + {Secure Hash Standard}, published in August 2002.} + + \seetitle[http://csrc.nist.gov/encryption/tkhash.html] + {Cryptographic Toolkit (Secure Hashing)} + {Links from NIST to various information on secure hashing.} +\end{seealso} + diff --git a/sys/src/cmd/python/Doc/lib/libshelve.tex b/sys/src/cmd/python/Doc/lib/libshelve.tex new file mode 100644 index 000000000..6ca357609 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libshelve.tex @@ -0,0 +1,174 @@ +\section{\module{shelve} --- + Python object persistence} + +\declaremodule{standard}{shelve} +\modulesynopsis{Python object persistence.} + + +A ``shelf'' is a persistent, dictionary-like object. The difference +with ``dbm'' databases is that the values (not the keys!) in a shelf +can be essentially arbitrary Python objects --- anything that the +\refmodule{pickle} module can handle. This includes most class +instances, recursive data types, and objects containing lots of shared +sub-objects. The keys are ordinary strings. +\refstmodindex{pickle} + +\begin{funcdesc}{open}{filename\optional{,flag='c'\optional{,protocol=\code{None}\optional{,writeback=\code{False}}}}} +Open a persistent dictionary. The filename specified is the base filename +for the underlying database. As a side-effect, an extension may be added to +the filename and more than one file may be created. By default, the +underlying database file is opened for reading and writing. The optional +{}\var{flag} parameter has the same interpretation as the \var{flag} +parameter of \function{anydbm.open}. + +By default, version 0 pickles are used to serialize values. +The version of the pickle protocol can be specified with the +\var{protocol} parameter. \versionchanged[The \var{protocol} +parameter was added]{2.3} + +By default, mutations to persistent-dictionary mutable entries are not +automatically written back. If the optional \var{writeback} parameter +is set to {}\var{True}, all entries accessed are cached in memory, and +written back at close time; this can make it handier to mutate mutable +entries in the persistent dictionary, but, if many entries are +accessed, it can consume vast amounts of memory for the cache, and it +can make the close operation very slow since all accessed entries are +written back (there is no way to determine which accessed entries are +mutable, nor which ones were actually mutated). + +\end{funcdesc} + +Shelve objects support all methods supported by dictionaries. This eases +the transition from dictionary based scripts to those requiring persistent +storage. + +One additional method is supported: +\begin{methoddesc}[Shelf]{sync}{} +Write back all entries in the cache if the shelf was opened with +\var{writeback} set to \var{True}. Also empty the cache and synchronize +the persistent dictionary on disk, if feasible. This is called automatically +when the shelf is closed with \method{close()}. +\end{methoddesc} + +\subsection{Restrictions} + +\begin{itemize} + +\item +The choice of which database package will be used +(such as \refmodule{dbm}, \refmodule{gdbm} or \refmodule{bsddb}) depends on +which interface is available. Therefore it is not safe to open the database +directly using \refmodule{dbm}. The database is also (unfortunately) subject +to the limitations of \refmodule{dbm}, if it is used --- this means +that (the pickled representation of) the objects stored in the +database should be fairly small, and in rare cases key collisions may +cause the database to refuse updates. +\refbimodindex{dbm} +\refbimodindex{gdbm} +\refbimodindex{bsddb} + +\item +Depending on the implementation, closing a persistent dictionary may +or may not be necessary to flush changes to disk. The \method{__del__} +method of the \class{Shelf} class calls the \method{close} method, so the +programmer generally need not do this explicitly. + +\item +The \module{shelve} module does not support \emph{concurrent} read/write +access to shelved objects. (Multiple simultaneous read accesses are +safe.) When a program has a shelf open for writing, no other program +should have it open for reading or writing. \UNIX{} file locking can +be used to solve this, but this differs across \UNIX{} versions and +requires knowledge about the database implementation used. + +\end{itemize} + +\begin{classdesc}{Shelf}{dict\optional{, protocol=None\optional{, writeback=False}}} +A subclass of \class{UserDict.DictMixin} which stores pickled values in the +\var{dict} object. + +By default, version 0 pickles are used to serialize values. The +version of the pickle protocol can be specified with the +\var{protocol} parameter. See the \module{pickle} documentation for a +discussion of the pickle protocols. \versionchanged[The \var{protocol} +parameter was added]{2.3} + +If the \var{writeback} parameter is \code{True}, the object will hold a +cache of all entries accessed and write them back to the \var{dict} at +sync and close times. This allows natural operations on mutable entries, +but can consume much more memory and make sync and close take a long time. +\end{classdesc} + +\begin{classdesc}{BsdDbShelf}{dict\optional{, protocol=None\optional{, writeback=False}}} + +A subclass of \class{Shelf} which exposes \method{first}, +\method{next}, \method{previous}, \method{last} and +\method{set_location} which are available in the \module{bsddb} module +but not in other database modules. The \var{dict} object passed to +the constructor must support those methods. This is generally +accomplished by calling one of \function{bsddb.hashopen}, +\function{bsddb.btopen} or \function{bsddb.rnopen}. The optional +\var{protocol} and \var{writeback} parameters have the +same interpretation as for the \class{Shelf} class. + +\end{classdesc} + +\begin{classdesc}{DbfilenameShelf}{filename\optional{, flag='c'\optional{, protocol=None\optional{, writeback=False}}}} + +A subclass of \class{Shelf} which accepts a \var{filename} instead of +a dict-like object. The underlying file will be opened using +{}\function{anydbm.open}. By default, the file will be created and +opened for both read and write. The optional \var{flag} parameter has +the same interpretation as for the \function{open} function. The +optional \var{protocol} and \var{writeback} parameters +have the same interpretation as for the \class{Shelf} class. + +\end{classdesc} + +\subsection{Example} + +To summarize the interface (\code{key} is a string, \code{data} is an +arbitrary object): + +\begin{verbatim} +import shelve + +d = shelve.open(filename) # open -- file may get suffix added by low-level + # library + +d[key] = data # store data at key (overwrites old data if + # using an existing key) +data = d[key] # retrieve a COPY of data at key (raise KeyError if no + # such key) +del d[key] # delete data stored at key (raises KeyError + # if no such key) +flag = d.has_key(key) # true if the key exists +klist = d.keys() # a list of all existing keys (slow!) + +# as d was opened WITHOUT writeback=True, beware: +d['xx'] = range(4) # this works as expected, but... +d['xx'].append(5) # *this doesn't!* -- d['xx'] is STILL range(4)!!! + +# having opened d without writeback=True, you need to code carefully: +temp = d['xx'] # extracts the copy +temp.append(5) # mutates the copy +d['xx'] = temp # stores the copy right back, to persist it + +# or, d=shelve.open(filename,writeback=True) would let you just code +# d['xx'].append(5) and have it work as expected, BUT it would also +# consume more memory and make the d.close() operation slower. + +d.close() # close it +\end{verbatim} + +\begin{seealso} + \seemodule{anydbm}{Generic interface to \code{dbm}-style databases.} + \seemodule{bsddb}{BSD \code{db} database interface.} + \seemodule{dbhash}{Thin layer around the \module{bsddb} which provides an + \function{open} function like the other database modules.} + \seemodule{dbm}{Standard \UNIX{} database interface.} + \seemodule{dumbdbm}{Portable implementation of the \code{dbm} interface.} + \seemodule{gdbm}{GNU database interface, based on the \code{dbm} interface.} + \seemodule{pickle}{Object serialization used by \module{shelve}.} + \seemodule{cPickle}{High-performance version of \refmodule{pickle}.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libshlex.tex b/sys/src/cmd/python/Doc/lib/libshlex.tex new file mode 100644 index 000000000..3a4364889 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libshlex.tex @@ -0,0 +1,274 @@ +\section{\module{shlex} --- + Simple lexical analysis} + +\declaremodule{standard}{shlex} +\modulesynopsis{Simple lexical analysis for \UNIX\ shell-like languages.} +\moduleauthor{Eric S. Raymond}{esr@snark.thyrsus.com} +\moduleauthor{Gustavo Niemeyer}{niemeyer@conectiva.com} +\sectionauthor{Eric S. Raymond}{esr@snark.thyrsus.com} +\sectionauthor{Gustavo Niemeyer}{niemeyer@conectiva.com} + +\versionadded{1.5.2} + +The \class{shlex} class makes it easy to write lexical analyzers for +simple syntaxes resembling that of the \UNIX{} shell. This will often +be useful for writing minilanguages, (for example, in run control +files for Python applications) or for parsing quoted strings. + +\note{The \module{shlex} module currently does not support Unicode input.} + +The \module{shlex} module defines the following functions: + +\begin{funcdesc}{split}{s\optional{, comments}} +Split the string \var{s} using shell-like syntax. If \var{comments} is +\constant{False} (the default), the parsing of comments in the given +string will be disabled (setting the \member{commenters} member of the +\class{shlex} instance to the empty string). This function operates +in \POSIX{} mode. +\versionadded{2.3} +\end{funcdesc} + +The \module{shlex} module defines the following class: + +\begin{classdesc}{shlex}{\optional{instream\optional{, + infile\optional{, posix}}}} +A \class{shlex} instance or subclass instance is a lexical analyzer +object. The initialization argument, if present, specifies where to +read characters from. It must be a file-/stream-like object with +\method{read()} and \method{readline()} methods, or a string (strings +are accepted since Python 2.3). If no argument is given, input will be +taken from \code{sys.stdin}. The second optional argument is a filename +string, which sets the initial value of the \member{infile} member. If +the \var{instream} argument is omitted or equal to \code{sys.stdin}, +this second argument defaults to ``stdin''. The \var{posix} argument +was introduced in Python 2.3, and defines the operational mode. When +\var{posix} is not true (default), the \class{shlex} instance will +operate in compatibility mode. When operating in \POSIX{} mode, +\class{shlex} will try to be as close as possible to the \POSIX{} shell +parsing rules. See section~\ref{shlex-objects}. +\end{classdesc} + +\begin{seealso} + \seemodule{ConfigParser}{Parser for configuration files similar to the + Windows \file{.ini} files.} +\end{seealso} + + +\subsection{shlex Objects \label{shlex-objects}} + +A \class{shlex} instance has the following methods: + +\begin{methoddesc}{get_token}{} +Return a token. If tokens have been stacked using +\method{push_token()}, pop a token off the stack. Otherwise, read one +from the input stream. If reading encounters an immediate +end-of-file, \member{self.eof} is returned (the empty string (\code{''}) +in non-\POSIX{} mode, and \code{None} in \POSIX{} mode). +\end{methoddesc} + +\begin{methoddesc}{push_token}{str} +Push the argument onto the token stack. +\end{methoddesc} + +\begin{methoddesc}{read_token}{} +Read a raw token. Ignore the pushback stack, and do not interpret source +requests. (This is not ordinarily a useful entry point, and is +documented here only for the sake of completeness.) +\end{methoddesc} + +\begin{methoddesc}{sourcehook}{filename} +When \class{shlex} detects a source request (see +\member{source} below) this method is given the following token as +argument, and expected to return a tuple consisting of a filename and +an open file-like object. + +Normally, this method first strips any quotes off the argument. If +the result is an absolute pathname, or there was no previous source +request in effect, or the previous source was a stream +(such as \code{sys.stdin}), the result is left alone. Otherwise, if the +result is a relative pathname, the directory part of the name of the +file immediately before it on the source inclusion stack is prepended +(this behavior is like the way the C preprocessor handles +\code{\#include "file.h"}). + +The result of the manipulations is treated as a filename, and returned +as the first component of the tuple, with +\function{open()} called on it to yield the second component. (Note: +this is the reverse of the order of arguments in instance initialization!) + +This hook is exposed so that you can use it to implement directory +search paths, addition of file extensions, and other namespace hacks. +There is no corresponding `close' hook, but a shlex instance will call +the \method{close()} method of the sourced input stream when it +returns \EOF. + +For more explicit control of source stacking, use the +\method{push_source()} and \method{pop_source()} methods. +\end{methoddesc} + +\begin{methoddesc}{push_source}{stream\optional{, filename}} +Push an input source stream onto the input stack. If the filename +argument is specified it will later be available for use in error +messages. This is the same method used internally by the +\method{sourcehook} method. +\versionadded{2.1} +\end{methoddesc} + +\begin{methoddesc}{pop_source}{} +Pop the last-pushed input source from the input stack. +This is the same method used internally when the lexer reaches +\EOF{} on a stacked input stream. +\versionadded{2.1} +\end{methoddesc} + +\begin{methoddesc}{error_leader}{\optional{file\optional{, line}}} +This method generates an error message leader in the format of a +\UNIX{} C compiler error label; the format is \code{'"\%s", line \%d: '}, +where the \samp{\%s} is replaced with the name of the current source +file and the \samp{\%d} with the current input line number (the +optional arguments can be used to override these). + +This convenience is provided to encourage \module{shlex} users to +generate error messages in the standard, parseable format understood +by Emacs and other \UNIX{} tools. +\end{methoddesc} + +Instances of \class{shlex} subclasses have some public instance +variables which either control lexical analysis or can be used for +debugging: + +\begin{memberdesc}{commenters} +The string of characters that are recognized as comment beginners. +All characters from the comment beginner to end of line are ignored. +Includes just \character{\#} by default. +\end{memberdesc} + +\begin{memberdesc}{wordchars} +The string of characters that will accumulate into multi-character +tokens. By default, includes all \ASCII{} alphanumerics and +underscore. +\end{memberdesc} + +\begin{memberdesc}{whitespace} +Characters that will be considered whitespace and skipped. Whitespace +bounds tokens. By default, includes space, tab, linefeed and +carriage-return. +\end{memberdesc} + +\begin{memberdesc}{escape} +Characters that will be considered as escape. This will be only used +in \POSIX{} mode, and includes just \character{\textbackslash} by default. +\versionadded{2.3} +\end{memberdesc} + +\begin{memberdesc}{quotes} +Characters that will be considered string quotes. The token +accumulates until the same quote is encountered again (thus, different +quote types protect each other as in the shell.) By default, includes +\ASCII{} single and double quotes. +\end{memberdesc} + +\begin{memberdesc}{escapedquotes} +Characters in \member{quotes} that will interpret escape characters +defined in \member{escape}. This is only used in \POSIX{} mode, and +includes just \character{"} by default. +\versionadded{2.3} +\end{memberdesc} + +\begin{memberdesc}{whitespace_split} +If \code{True}, tokens will only be split in whitespaces. This is useful, for +example, for parsing command lines with \class{shlex}, getting tokens +in a similar way to shell arguments. +\versionadded{2.3} +\end{memberdesc} + +\begin{memberdesc}{infile} +The name of the current input file, as initially set at class +instantiation time or stacked by later source requests. It may +be useful to examine this when constructing error messages. +\end{memberdesc} + +\begin{memberdesc}{instream} +The input stream from which this \class{shlex} instance is reading +characters. +\end{memberdesc} + +\begin{memberdesc}{source} +This member is \code{None} by default. If you assign a string to it, +that string will be recognized as a lexical-level inclusion request +similar to the \samp{source} keyword in various shells. That is, the +immediately following token will opened as a filename and input taken +from that stream until \EOF, at which point the \method{close()} +method of that stream will be called and the input source will again +become the original input stream. Source requests may be stacked any +number of levels deep. +\end{memberdesc} + +\begin{memberdesc}{debug} +If this member is numeric and \code{1} or more, a \class{shlex} +instance will print verbose progress output on its behavior. If you +need to use this, you can read the module source code to learn the +details. +\end{memberdesc} + +\begin{memberdesc}{lineno} +Source line number (count of newlines seen so far plus one). +\end{memberdesc} + +\begin{memberdesc}{token} +The token buffer. It may be useful to examine this when catching +exceptions. +\end{memberdesc} + +\begin{memberdesc}{eof} +Token used to determine end of file. This will be set to the empty +string (\code{''}), in non-\POSIX{} mode, and to \code{None} in +\POSIX{} mode. +\versionadded{2.3} +\end{memberdesc} + +\subsection{Parsing Rules\label{shlex-parsing-rules}} + +When operating in non-\POSIX{} mode, \class{shlex} will try to obey to +the following rules. + +\begin{itemize} +\item Quote characters are not recognized within words + (\code{Do"Not"Separate} is parsed as the single word + \code{Do"Not"Separate}); +\item Escape characters are not recognized; +\item Enclosing characters in quotes preserve the literal value of + all characters within the quotes; +\item Closing quotes separate words (\code{"Do"Separate} is parsed + as \code{"Do"} and \code{Separate}); +\item If \member{whitespace_split} is \code{False}, any character not + declared to be a word character, whitespace, or a quote will be + returned as a single-character token. If it is \code{True}, + \class{shlex} will only split words in whitespaces; +\item EOF is signaled with an empty string (\code{''}); +\item It's not possible to parse empty strings, even if quoted. +\end{itemize} + +When operating in \POSIX{} mode, \class{shlex} will try to obey to the +following parsing rules. + +\begin{itemize} +\item Quotes are stripped out, and do not separate words + (\code{"Do"Not"Separate"} is parsed as the single word + \code{DoNotSeparate}); +\item Non-quoted escape characters (e.g. \character{\textbackslash}) + preserve the literal value of the next character that follows; +\item Enclosing characters in quotes which are not part of + \member{escapedquotes} (e.g. \character{'}) preserve the literal + value of all characters within the quotes; +\item Enclosing characters in quotes which are part of + \member{escapedquotes} (e.g. \character{"}) preserves the literal + value of all characters within the quotes, with the exception of + the characters mentioned in \member{escape}. The escape characters + retain its special meaning only when followed by the quote in use, + or the escape character itself. Otherwise the escape character + will be considered a normal character. +\item EOF is signaled with a \constant{None} value; +\item Quoted empty strings (\code{''}) are allowed; +\end{itemize} + diff --git a/sys/src/cmd/python/Doc/lib/libshutil.tex b/sys/src/cmd/python/Doc/lib/libshutil.tex new file mode 100644 index 000000000..f5c55a04b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libshutil.tex @@ -0,0 +1,151 @@ +\section{\module{shutil} --- + High-level file operations} + +\declaremodule{standard}{shutil} +\modulesynopsis{High-level file operations, including copying.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +% partly based on the docstrings + + +The \module{shutil} module offers a number of high-level operations on +files and collections of files. In particular, functions are provided +which support file copying and removal. +\index{file!copying} +\index{copying files} + +\strong{Caveat:} On MacOS, the resource fork and other metadata are +not used. For file copies, this means that resources will be lost and +file type and creator codes will not be correct. + + +\begin{funcdesc}{copyfile}{src, dst} + Copy the contents of the file named \var{src} to a file named + \var{dst}. The destination location must be writable; otherwise, + an \exception{IOError} exception will be raised. + If \var{dst} already exists, it will be replaced. + Special files such as character or block devices + and pipes cannot be copied with this function. \var{src} and + \var{dst} are path names given as strings. +\end{funcdesc} + +\begin{funcdesc}{copyfileobj}{fsrc, fdst\optional{, length}} + Copy the contents of the file-like object \var{fsrc} to the + file-like object \var{fdst}. The integer \var{length}, if given, + is the buffer size. In particular, a negative \var{length} value + means to copy the data without looping over the source data in + chunks; by default the data is read in chunks to avoid uncontrolled + memory consumption. Note that if the current file position of the + \var{fsrc} object is not 0, only the contents from the current file + position to the end of the file will be copied. +\end{funcdesc} + +\begin{funcdesc}{copymode}{src, dst} + Copy the permission bits from \var{src} to \var{dst}. The file + contents, owner, and group are unaffected. \var{src} and \var{dst} + are path names given as strings. +\end{funcdesc} + +\begin{funcdesc}{copystat}{src, dst} + Copy the permission bits, last access time, and last modification + time from \var{src} to \var{dst}. The file contents, owner, and + group are unaffected. \var{src} and \var{dst} are path names given + as strings. +\end{funcdesc} + +\begin{funcdesc}{copy}{src, dst} + Copy the file \var{src} to the file or directory \var{dst}. If + \var{dst} is a directory, a file with the same basename as \var{src} + is created (or overwritten) in the directory specified. Permission + bits are copied. \var{src} and \var{dst} are path names given as + strings. +\end{funcdesc} + +\begin{funcdesc}{copy2}{src, dst} + Similar to \function{copy()}, but last access time and last + modification time are copied as well. This is similar to the + \UNIX{} command \program{cp} \programopt{-p}. +\end{funcdesc} + +\begin{funcdesc}{copytree}{src, dst\optional{, symlinks}} + Recursively copy an entire directory tree rooted at \var{src}. The + destination directory, named by \var{dst}, must not already exist; + it will be created as well as missing parent directories. + Permissions and times of directories are copied with \function{copystat()}, + individual files are copied using \function{copy2()}. + If \var{symlinks} is true, symbolic links in + the source tree are represented as symbolic links in the new tree; + if false or omitted, the contents of the linked files are copied to + the new tree. If exception(s) occur, an \exception{Error} is raised + with a list of reasons. + + The source code for this should be considered an example rather than + a tool. + + \versionchanged[\exception{Error} is raised if any exceptions occur during + copying, rather than printing a message]{2.3} + + \versionchanged[Create intermediate directories needed to create \var{dst}, + rather than raising an error. Copy permissions and times of + directories using \function{copystat()}]{2.5} + +\end{funcdesc} + +\begin{funcdesc}{rmtree}{path\optional{, ignore_errors\optional{, onerror}}} + Delete an entire directory tree.\index{directory!deleting} + If \var{ignore_errors} is true, + errors resulting from failed removals will be ignored; if false or + omitted, such errors are handled by calling a handler specified by + \var{onerror} or, if that is omitted, they raise an exception. + + If \var{onerror} is provided, it must be a callable that accepts + three parameters: \var{function}, \var{path}, and \var{excinfo}. + The first parameter, \var{function}, is the function which raised + the exception; it will be \function{os.listdir()}, \function{os.remove()} or + \function{os.rmdir()}. The second parameter, \var{path}, will be + the path name passed to \var{function}. The third parameter, + \var{excinfo}, will be the exception information return by + \function{sys.exc_info()}. Exceptions raised by \var{onerror} will + not be caught. +\end{funcdesc} + +\begin{funcdesc}{move}{src, dst} +Recursively move a file or directory to another location. + +If the destination is on our current filesystem, then simply use +rename. Otherwise, copy src to the dst and then remove src. + +\versionadded{2.3} +\end{funcdesc} + +\begin{excdesc}{Error} +This exception collects exceptions that raised during a mult-file +operation. For \function{copytree}, the exception argument is a +list of 3-tuples (\var{srcname}, \var{dstname}, \var{exception}). + +\versionadded{2.3} +\end{excdesc} + +\subsection{Example \label{shutil-example}} + +This example is the implementation of the \function{copytree()} +function, described above, with the docstring omitted. It +demonstrates many of the other functions provided by this module. + +\begin{verbatim} +def copytree(src, dst, symlinks=0): + names = os.listdir(src) + os.mkdir(dst) + for name in names: + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if symlinks and os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif os.path.isdir(srcname): + copytree(srcname, dstname, symlinks) + else: + copy2(srcname, dstname) + except (IOError, os.error), why: + print "Can't copy %s to %s: %s" % (`srcname`, `dstname`, str(why)) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libsignal.tex b/sys/src/cmd/python/Doc/lib/libsignal.tex new file mode 100644 index 000000000..cfdb4dde1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsignal.tex @@ -0,0 +1,174 @@ +\section{\module{signal} --- + Set handlers for asynchronous events} + +\declaremodule{builtin}{signal} +\modulesynopsis{Set handlers for asynchronous events.} + + +This module provides mechanisms to use signal handlers in Python. +Some general rules for working with signals and their handlers: + +\begin{itemize} + +\item +A handler for a particular signal, once set, remains installed until +it is explicitly reset (Python emulates the BSD style interface +regardless of the underlying implementation), with the exception of +the handler for \constant{SIGCHLD}, which follows the underlying +implementation. + +\item +There is no way to ``block'' signals temporarily from critical +sections (since this is not supported by all \UNIX{} flavors). + +\item +Although Python signal handlers are called asynchronously as far as +the Python user is concerned, they can only occur between the +``atomic'' instructions of the Python interpreter. This means that +signals arriving during long calculations implemented purely in C +(such as regular expression matches on large bodies of text) may be +delayed for an arbitrary amount of time. + +\item +When a signal arrives during an I/O operation, it is possible that the +I/O operation raises an exception after the signal handler returns. +This is dependent on the underlying \UNIX{} system's semantics regarding +interrupted system calls. + +\item +Because the \C{} signal handler always returns, it makes little sense to +catch synchronous errors like \constant{SIGFPE} or \constant{SIGSEGV}. + +\item +Python installs a small number of signal handlers by default: +\constant{SIGPIPE} is ignored (so write errors on pipes and sockets can be +reported as ordinary Python exceptions) and \constant{SIGINT} is translated +into a \exception{KeyboardInterrupt} exception. All of these can be +overridden. + +\item +Some care must be taken if both signals and threads are used in the +same program. The fundamental thing to remember in using signals and +threads simultaneously is:\ always perform \function{signal()} operations +in the main thread of execution. Any thread can perform an +\function{alarm()}, \function{getsignal()}, or \function{pause()}; +only the main thread can set a new signal handler, and the main thread +will be the only one to receive signals (this is enforced by the +Python \module{signal} module, even if the underlying thread +implementation supports sending signals to individual threads). This +means that signals can't be used as a means of inter-thread +communication. Use locks instead. + +\end{itemize} + +The variables defined in the \module{signal} module are: + +\begin{datadesc}{SIG_DFL} + This is one of two standard signal handling options; it will simply + perform the default function for the signal. For example, on most + systems the default action for \constant{SIGQUIT} is to dump core + and exit, while the default action for \constant{SIGCLD} is to + simply ignore it. +\end{datadesc} + +\begin{datadesc}{SIG_IGN} + This is another standard signal handler, which will simply ignore + the given signal. +\end{datadesc} + +\begin{datadesc}{SIG*} + All the signal numbers are defined symbolically. For example, the + hangup signal is defined as \constant{signal.SIGHUP}; the variable names + are identical to the names used in C programs, as found in + \code{<signal.h>}. + The \UNIX{} man page for `\cfunction{signal()}' lists the existing + signals (on some systems this is \manpage{signal}{2}, on others the + list is in \manpage{signal}{7}). + Note that not all systems define the same set of signal names; only + those names defined by the system are defined by this module. +\end{datadesc} + +\begin{datadesc}{NSIG} + One more than the number of the highest signal number. +\end{datadesc} + +The \module{signal} module defines the following functions: + +\begin{funcdesc}{alarm}{time} + If \var{time} is non-zero, this function requests that a + \constant{SIGALRM} signal be sent to the process in \var{time} seconds. + Any previously scheduled alarm is canceled (only one alarm can + be scheduled at any time). The returned value is then the number of + seconds before any previously set alarm was to have been delivered. + If \var{time} is zero, no alarm is scheduled, and any scheduled + alarm is canceled. The return value is the number of seconds + remaining before a previously scheduled alarm. If the return value + is zero, no alarm is currently scheduled. (See the \UNIX{} man page + \manpage{alarm}{2}.) + Availability: \UNIX. +\end{funcdesc} + +\begin{funcdesc}{getsignal}{signalnum} + Return the current signal handler for the signal \var{signalnum}. + The returned value may be a callable Python object, or one of the + special values \constant{signal.SIG_IGN}, \constant{signal.SIG_DFL} or + \constant{None}. Here, \constant{signal.SIG_IGN} means that the + signal was previously ignored, \constant{signal.SIG_DFL} means that the + default way of handling the signal was previously in use, and + \code{None} means that the previous signal handler was not installed + from Python. +\end{funcdesc} + +\begin{funcdesc}{pause}{} + Cause the process to sleep until a signal is received; the + appropriate handler will then be called. Returns nothing. Not on + Windows. (See the \UNIX{} man page \manpage{signal}{2}.) +\end{funcdesc} + +\begin{funcdesc}{signal}{signalnum, handler} + Set the handler for signal \var{signalnum} to the function + \var{handler}. \var{handler} can be a callable Python object + taking two arguments (see below), or + one of the special values \constant{signal.SIG_IGN} or + \constant{signal.SIG_DFL}. The previous signal handler will be returned + (see the description of \function{getsignal()} above). (See the + \UNIX{} man page \manpage{signal}{2}.) + + When threads are enabled, this function can only be called from the + main thread; attempting to call it from other threads will cause a + \exception{ValueError} exception to be raised. + + The \var{handler} is called with two arguments: the signal number + and the current stack frame (\code{None} or a frame object; + for a description of frame objects, see the reference manual section + on the standard type hierarchy or see the attribute descriptions in + the \refmodule{inspect} module). +\end{funcdesc} + +\subsection{Example} +\nodename{Signal Example} + +Here is a minimal example program. It uses the \function{alarm()} +function to limit the time spent waiting to open a file; this is +useful if the file is for a serial device that may not be turned on, +which would normally cause the \function{os.open()} to hang +indefinitely. The solution is to set a 5-second alarm before opening +the file; if the operation takes too long, the alarm signal will be +sent, and the handler raises an exception. + +\begin{verbatim} +import signal, os + +def handler(signum, frame): + print 'Signal handler called with signal', signum + raise IOError, "Couldn't open device!" + +# Set the signal handler and a 5-second alarm +signal.signal(signal.SIGALRM, handler) +signal.alarm(5) + +# This open() may hang indefinitely +fd = os.open('/dev/ttyS0', os.O_RDWR) + +signal.alarm(0) # Disable the alarm +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libsimplehttp.tex b/sys/src/cmd/python/Doc/lib/libsimplehttp.tex new file mode 100644 index 000000000..efb40eccf --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsimplehttp.tex @@ -0,0 +1,86 @@ +\section{\module{SimpleHTTPServer} --- + Simple HTTP request handler} + +\declaremodule{standard}{SimpleHTTPServer} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{This module provides a basic request handler for HTTP + servers.} + + +The \module{SimpleHTTPServer} module defines a request-handler class, +interface-compatible with \class{BaseHTTPServer.BaseHTTPRequestHandler}, +that serves files only from a base directory. + +The \module{SimpleHTTPServer} module defines the following class: + +\begin{classdesc}{SimpleHTTPRequestHandler}{request, client_address, server} +This class is used to serve files from the current directory and below, +directly mapping the directory structure to HTTP requests. + +A lot of the work, such as parsing the request, is done by the base +class \class{BaseHTTPServer.BaseHTTPRequestHandler}. This class +implements the \function{do_GET()} and \function{do_HEAD()} functions. +\end{classdesc} + +The \class{SimpleHTTPRequestHandler} defines the following member +variables: + +\begin{memberdesc}{server_version} +This will be \code{"SimpleHTTP/" + __version__}, where \code{__version__} +is defined in the module. +\end{memberdesc} + +\begin{memberdesc}{extensions_map} +A dictionary mapping suffixes into MIME types. The default is signified +by an empty string, and is considered to be \code{application/octet-stream}. +The mapping is used case-insensitively, and so should contain only +lower-cased keys. +\end{memberdesc} + +The \class{SimpleHTTPRequestHandler} defines the following methods: + +\begin{methoddesc}{do_HEAD}{} +This method serves the \code{'HEAD'} request type: it sends the +headers it would send for the equivalent \code{GET} request. See the +\method{do_GET()} method for a more complete explanation of the possible +headers. +\end{methoddesc} + +\begin{methoddesc}{do_GET}{} +The request is mapped to a local file by interpreting the request as +a path relative to the current working directory. + +If the request was mapped to a directory, the directory is checked for +a file named \code{index.html} or \code{index.htm} (in that order). +If found, the file's contents are returned; otherwise a directory +listing is generated by calling the \method{list_directory()} method. +This method uses \function{os.listdir()} to scan the directory, and +returns a \code{404} error response if the \function{listdir()} fails. + +If the request was mapped to a file, it is opened and the contents are +returned. Any \exception{IOError} exception in opening the requested +file is mapped to a \code{404}, \code{'File not found'} +error. Otherwise, the content type is guessed by calling the +\method{guess_type()} method, which in turn uses the +\var{extensions_map} variable. + +A \code{'Content-type:'} header with the guessed content type is +output, followed by a \code{'Content-Length:'} header with the file's +size and a \code{'Last-Modified:'} header with the file's modification +time. + +Then follows a blank line signifying the end of the headers, +and then the contents of the file are output. If the file's MIME type +starts with \code{text/} the file is opened in text mode; otherwise +binary mode is used. + +For example usage, see the implementation of the \function{test()} +function. +\versionadded[The \code{'Last-Modified'} header]{2.5} +\end{methoddesc} + + +\begin{seealso} + \seemodule{BaseHTTPServer}{Base class implementation for Web server + and request handler.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libsimplexmlrpc.tex b/sys/src/cmd/python/Doc/lib/libsimplexmlrpc.tex new file mode 100644 index 000000000..6b458558c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsimplexmlrpc.tex @@ -0,0 +1,228 @@ +\section{\module{SimpleXMLRPCServer} --- + Basic XML-RPC server} + +\declaremodule{standard}{SimpleXMLRPCServer} +\modulesynopsis{Basic XML-RPC server implementation.} +\moduleauthor{Brian Quinlan}{brianq@activestate.com} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +\versionadded{2.2} + +The \module{SimpleXMLRPCServer} module provides a basic server +framework for XML-RPC servers written in Python. Servers can either +be free standing, using \class{SimpleXMLRPCServer}, or embedded in a +CGI environment, using \class{CGIXMLRPCRequestHandler}. + +\begin{classdesc}{SimpleXMLRPCServer}{addr\optional{, + requestHandler\optional{, + logRequests\optional{, allow_none\optional{, encoding}}}}} + + Create a new server instance. This class + provides methods for registration of functions that can be called by + the XML-RPC protocol. The \var{requestHandler} parameter + should be a factory for request handler instances; it defaults to + \class{SimpleXMLRPCRequestHandler}. The \var{addr} and + \var{requestHandler} parameters are passed to the + \class{\refmodule{SocketServer}.TCPServer} constructor. If + \var{logRequests} is true (the default), requests will be logged; + setting this parameter to false will turn off logging. + The \var{allow_none} and \var{encoding} parameters are passed on to + \module{xmlrpclib} and control the XML-RPC responses that will be returned + from the server. + \versionchanged[The \var{allow_none} and \var{encoding} parameters were added]{2.5} +\end{classdesc} + +\begin{classdesc}{CGIXMLRPCRequestHandler}{\optional{allow_none\optional{, encoding}}} + Create a new instance to handle XML-RPC requests in a CGI + environment. + The \var{allow_none} and \var{encoding} parameters are passed on to + \module{xmlrpclib} and control the XML-RPC responses that will be returned + from the server. + \versionadded{2.3} + \versionchanged[The \var{allow_none} and \var{encoding} parameters were added]{2.5} +\end{classdesc} + +\begin{classdesc}{SimpleXMLRPCRequestHandler}{} + Create a new request handler instance. This request handler + supports \code{POST} requests and modifies logging so that the + \var{logRequests} parameter to the \class{SimpleXMLRPCServer} + constructor parameter is honored. +\end{classdesc} + + +\subsection{SimpleXMLRPCServer Objects \label{simple-xmlrpc-servers}} + +The \class{SimpleXMLRPCServer} class is based on +\class{SocketServer.TCPServer} and provides a means of creating +simple, stand alone XML-RPC servers. + +\begin{methoddesc}[SimpleXMLRPCServer]{register_function}{function\optional{, + name}} + Register a function that can respond to XML-RPC requests. If + \var{name} is given, it will be the method name associated with + \var{function}, otherwise \code{\var{function}.__name__} will be + used. \var{name} can be either a normal or Unicode string, and may + contain characters not legal in Python identifiers, including the + period character. +\end{methoddesc} + +\begin{methoddesc}[SimpleXMLRPCServer]{register_instance}{instance\optional{, + allow_dotted_names}} + Register an object which is used to expose method names which have + not been registered using \method{register_function()}. If + \var{instance} contains a \method{_dispatch()} method, it is called + with the requested method name and the parameters from the request. Its + API is \code{def \method{_dispatch}(self, method, params)} (note that + \var{params} does not represent a variable argument list). If it calls an + underlying function to perform its task, that function is called as + \code{func(*params)}, expanding the parameter list. + The return value from \method{_dispatch()} is returned to the client as + the result. If + \var{instance} does not have a \method{_dispatch()} method, it is + searched for an attribute matching the name of the requested method. + + If the optional \var{allow_dotted_names} argument is true and the + instance does not have a \method{_dispatch()} method, then + if the requested method name contains periods, each component of the + method name is searched for individually, with the effect that a + simple hierarchical search is performed. The value found from this + search is then called with the parameters from the request, and the + return value is passed back to the client. + + \begin{notice}[warning] + Enabling the \var{allow_dotted_names} option allows intruders to access + your module's global variables and may allow intruders to execute + arbitrary code on your machine. Only use this option on a secure, + closed network. + \end{notice} + + \versionchanged[\var{allow_dotted_names} was added to plug a security hole; + prior versions are insecure]{2.3.5, 2.4.1} + +\end{methoddesc} + +\begin{methoddesc}{register_introspection_functions}{} + Registers the XML-RPC introspection functions \code{system.listMethods}, + \code{system.methodHelp} and \code{system.methodSignature}. + \versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}{register_multicall_functions}{} + Registers the XML-RPC multicall function system.multicall. +\end{methoddesc} + +\begin{memberdesc}[SimpleXMLRPCServer]{rpc_paths} +An attribute value that must be a tuple listing valid path portions of +the URL for receiving XML-RPC requests. Requests posted to other +paths will result in a 404 ``no such page'' HTTP error. If this +tuple is empty, all paths will be considered valid. +The default value is \code{('/', '/RPC2')}. + \versionadded{2.5} +\end{memberdesc} + +Example: + +\begin{verbatim} +from SimpleXMLRPCServer import SimpleXMLRPCServer + +# Create server +server = SimpleXMLRPCServer(("localhost", 8000)) +server.register_introspection_functions() + +# Register pow() function; this will use the value of +# pow.__name__ as the name, which is just 'pow'. +server.register_function(pow) + +# Register a function under a different name +def adder_function(x,y): + return x + y +server.register_function(adder_function, 'add') + +# Register an instance; all the methods of the instance are +# published as XML-RPC methods (in this case, just 'div'). +class MyFuncs: + def div(self, x, y): + return x // y + +server.register_instance(MyFuncs()) + +# Run the server's main loop +server.serve_forever() +\end{verbatim} + +The following client code will call the methods made available by +the preceding server: + +\begin{verbatim} +import xmlrpclib + +s = xmlrpclib.Server('http://localhost:8000') +print s.pow(2,3) # Returns 2**3 = 8 +print s.add(2,3) # Returns 5 +print s.div(5,2) # Returns 5//2 = 2 + +# Print list of available methods +print s.system.listMethods() +\end{verbatim} + + +\subsection{CGIXMLRPCRequestHandler} + +The \class{CGIXMLRPCRequestHandler} class can be used to +handle XML-RPC requests sent to Python CGI scripts. + +\begin{methoddesc}{register_function}{function\optional{, name}} +Register a function that can respond to XML-RPC requests. If +\var{name} is given, it will be the method name associated with +function, otherwise \var{function.__name__} will be used. \var{name} +can be either a normal or Unicode string, and may contain +characters not legal in Python identifiers, including the period +character. +\end{methoddesc} + +\begin{methoddesc}{register_instance}{instance} +Register an object which is used to expose method names +which have not been registered using \method{register_function()}. If +instance contains a \method{_dispatch()} method, it is called with the +requested method name and the parameters from the +request; the return value is returned to the client as the result. +If instance does not have a \method{_dispatch()} method, it is searched +for an attribute matching the name of the requested method; if +the requested method name contains periods, each +component of the method name is searched for individually, +with the effect that a simple hierarchical search is performed. +The value found from this search is then called with the +parameters from the request, and the return value is passed +back to the client. +\end{methoddesc} + +\begin{methoddesc}{register_introspection_functions}{} +Register the XML-RPC introspection functions +\code{system.listMethods}, \code{system.methodHelp} and +\code{system.methodSignature}. +\end{methoddesc} + +\begin{methoddesc}{register_multicall_functions}{} +Register the XML-RPC multicall function \code{system.multicall}. +\end{methoddesc} + +\begin{methoddesc}{handle_request}{\optional{request_text = None}} +Handle a XML-RPC request. If \var{request_text} is given, it +should be the POST data provided by the HTTP server, +otherwise the contents of stdin will be used. +\end{methoddesc} + +Example: + +\begin{verbatim} +class MyFuncs: + def div(self, x, y) : return x // y + + +handler = CGIXMLRPCRequestHandler() +handler.register_function(pow) +handler.register_function(lambda x,y: x+y, 'add') +handler.register_introspection_functions() +handler.register_instance(MyFuncs()) +handler.handle_request() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libsite.tex b/sys/src/cmd/python/Doc/lib/libsite.tex new file mode 100644 index 000000000..c0797904b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsite.tex @@ -0,0 +1,88 @@ +\section{\module{site} --- + Site-specific configuration hook} + +\declaremodule{standard}{site} +\modulesynopsis{A standard way to reference site-specific modules.} + + +\strong{This module is automatically imported during initialization.} +The automatic import can be suppressed using the interpreter's +\programopt{-S} option. + +Importing this module will append site-specific paths to the module +search path. +\indexiii{module}{search}{path} + +It starts by constructing up to four directories from a head and a +tail part. For the head part, it uses \code{sys.prefix} and +\code{sys.exec_prefix}; empty heads are skipped. For +the tail part, it uses the empty string and then +\file{lib/site-packages} (on Windows) or +\file{lib/python\shortversion/site-packages} and then +\file{lib/site-python} (on \UNIX{} and Macintosh). For each of the +distinct head-tail combinations, it sees if it refers to an existing +directory, and if so, adds it to \code{sys.path} and also inspects +the newly added path for configuration files. +\indexii{site-python}{directory} +\indexii{site-packages}{directory} + +A path configuration file is a file whose name has the form +\file{\var{package}.pth} and exists in one of the four directories +mentioned above; its contents are additional items (one +per line) to be added to \code{sys.path}. Non-existing items are +never added to \code{sys.path}, but no check is made that the item +refers to a directory (rather than a file). No item is added to +\code{sys.path} more than once. Blank lines and lines beginning with +\code{\#} are skipped. Lines starting with \code{import} are executed. +\index{package} +\indexiii{path}{configuration}{file} + +For example, suppose \code{sys.prefix} and \code{sys.exec_prefix} are +set to \file{/usr/local}. The Python \version\ library is then +installed in \file{/usr/local/lib/python\shortversion} (where only the +first three characters of \code{sys.version} are used to form the +installation path name). Suppose this has a subdirectory +\file{/usr/local/lib/python\shortversion/site-packages} with three +subsubdirectories, \file{foo}, \file{bar} and \file{spam}, and two +path configuration files, \file{foo.pth} and \file{bar.pth}. Assume +\file{foo.pth} contains the following: + +\begin{verbatim} +# foo package configuration + +foo +bar +bletch +\end{verbatim} + +and \file{bar.pth} contains: + +\begin{verbatim} +# bar package configuration + +bar +\end{verbatim} + +Then the following directories are added to \code{sys.path}, in this +order: + +\begin{verbatim} +/usr/local/lib/python2.3/site-packages/bar +/usr/local/lib/python2.3/site-packages/foo +\end{verbatim} + +Note that \file{bletch} is omitted because it doesn't exist; the +\file{bar} directory precedes the \file{foo} directory because +\file{bar.pth} comes alphabetically before \file{foo.pth}; and +\file{spam} is omitted because it is not mentioned in either path +configuration file. + +After these path manipulations, an attempt is made to import a module +named \module{sitecustomize}\refmodindex{sitecustomize}, which can +perform arbitrary site-specific customizations. If this import fails +with an \exception{ImportError} exception, it is silently ignored. + +Note that for some non-\UNIX{} systems, \code{sys.prefix} and +\code{sys.exec_prefix} are empty, and the path manipulations are +skipped; however the import of +\module{sitecustomize}\refmodindex{sitecustomize} is still attempted. diff --git a/sys/src/cmd/python/Doc/lib/libsmtpd.tex b/sys/src/cmd/python/Doc/lib/libsmtpd.tex new file mode 100644 index 000000000..657050d04 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsmtpd.tex @@ -0,0 +1,63 @@ +\section{\module{smtpd} --- + SMTP Server} + +\declaremodule{standard}{smtpd} + +\moduleauthor{Barry Warsaw}{barry@zope.com} +\sectionauthor{Moshe Zadka}{moshez@moshez.org} + +\modulesynopsis{Implement a flexible SMTP server} + +This module offers several classes to implement SMTP servers. One is +a generic do-nothing implementation, which can be overridden, while +the other two offer specific mail-sending strategies. + + +\subsection{SMTPServer Objects} + +\begin{classdesc}{SMTPServer}{localaddr, remoteaddr} +Create a new \class{SMTPServer} object, which binds to local address +\var{localaddr}. It will treat \var{remoteaddr} as an upstream SMTP +relayer. It inherits from \class{asyncore.dispatcher}, and so will +insert itself into \refmodule{asyncore}'s event loop on instantiation. +\end{classdesc} + +\begin{methoddesc}[SMTPServer]{process_message}{peer, mailfrom, rcpttos, data} +Raise \exception{NotImplementedError} exception. Override this in +subclasses to do something useful with this message. Whatever was +passed in the constructor as \var{remoteaddr} will be available as the +\member{_remoteaddr} attribute. \var{peer} is the remote host's address, +\var{mailfrom} is the envelope originator, \var{rcpttos} are the +envelope recipients and \var{data} is a string containing the contents +of the e-mail (which should be in \rfc{2822} format). +\end{methoddesc} + + +\subsection{DebuggingServer Objects} + +\begin{classdesc}{DebuggingServer}{localaddr, remoteaddr} +Create a new debugging server. Arguments are as per +\class{SMTPServer}. Messages will be discarded, and printed on +stdout. +\end{classdesc} + + +\subsection{PureProxy Objects} + +\begin{classdesc}{PureProxy}{localaddr, remoteaddr} +Create a new pure proxy server. Arguments are as per \class{SMTPServer}. +Everything will be relayed to \var{remoteaddr}. Note that running +this has a good chance to make you into an open relay, so please be +careful. +\end{classdesc} + + +\subsection{MailmanProxy Objects} + +\begin{classdesc}{MailmanProxy}{localaddr, remoteaddr} +Create a new pure proxy server. Arguments are as per +\class{SMTPServer}. Everything will be relayed to \var{remoteaddr}, +unless local mailman configurations knows about an address, in which +case it will be handled via mailman. Note that running this has a +good chance to make you into an open relay, so please be careful. +\end{classdesc} diff --git a/sys/src/cmd/python/Doc/lib/libsmtplib.tex b/sys/src/cmd/python/Doc/lib/libsmtplib.tex new file mode 100644 index 000000000..3d74dd8b2 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsmtplib.tex @@ -0,0 +1,295 @@ +\section{\module{smtplib} --- + SMTP protocol client} + +\declaremodule{standard}{smtplib} +\modulesynopsis{SMTP protocol client (requires sockets).} +\sectionauthor{Eric S. Raymond}{esr@snark.thyrsus.com} + +\indexii{SMTP}{protocol} +\index{Simple Mail Transfer Protocol} + +The \module{smtplib} module defines an SMTP client session object that +can be used to send mail to any Internet machine with an SMTP or ESMTP +listener daemon. For details of SMTP and ESMTP operation, consult +\rfc{821} (\citetitle{Simple Mail Transfer Protocol}) and \rfc{1869} +(\citetitle{SMTP Service Extensions}). + +\begin{classdesc}{SMTP}{\optional{host\optional{, port\optional{, + local_hostname}}}} +A \class{SMTP} instance encapsulates an SMTP connection. It has +methods that support a full repertoire of SMTP and ESMTP +operations. If the optional host and port parameters are given, the +SMTP \method{connect()} method is called with those parameters during +initialization. An \exception{SMTPConnectError} is raised if the +specified host doesn't respond correctly. + +For normal use, you should only require the initialization/connect, +\method{sendmail()}, and \method{quit()} methods. An example is +included below. +\end{classdesc} + + +A nice selection of exceptions is defined as well: + +\begin{excdesc}{SMTPException} + Base exception class for all exceptions raised by this module. +\end{excdesc} + +\begin{excdesc}{SMTPServerDisconnected} + This exception is raised when the server unexpectedly disconnects, + or when an attempt is made to use the \class{SMTP} instance before + connecting it to a server. +\end{excdesc} + +\begin{excdesc}{SMTPResponseException} + Base class for all exceptions that include an SMTP error code. + These exceptions are generated in some instances when the SMTP + server returns an error code. The error code is stored in the + \member{smtp_code} attribute of the error, and the + \member{smtp_error} attribute is set to the error message. +\end{excdesc} + +\begin{excdesc}{SMTPSenderRefused} + Sender address refused. In addition to the attributes set by on all + \exception{SMTPResponseException} exceptions, this sets `sender' to + the string that the SMTP server refused. +\end{excdesc} + +\begin{excdesc}{SMTPRecipientsRefused} + All recipient addresses refused. The errors for each recipient are + accessible through the attribute \member{recipients}, which is a + dictionary of exactly the same sort as \method{SMTP.sendmail()} + returns. +\end{excdesc} + +\begin{excdesc}{SMTPDataError} + The SMTP server refused to accept the message data. +\end{excdesc} + +\begin{excdesc}{SMTPConnectError} + Error occurred during establishment of a connection with the server. +\end{excdesc} + +\begin{excdesc}{SMTPHeloError} + The server refused our \samp{HELO} message. +\end{excdesc} + + +\begin{seealso} + \seerfc{821}{Simple Mail Transfer Protocol}{Protocol definition for + SMTP. This document covers the model, operating procedure, + and protocol details for SMTP.} + \seerfc{1869}{SMTP Service Extensions}{Definition of the ESMTP + extensions for SMTP. This describes a framework for + extending SMTP with new commands, supporting dynamic + discovery of the commands provided by the server, and + defines a few additional commands.} +\end{seealso} + + +\subsection{SMTP Objects \label{SMTP-objects}} + +An \class{SMTP} instance has the following methods: + +\begin{methoddesc}{set_debuglevel}{level} +Set the debug output level. A true value for \var{level} results in +debug messages for connection and for all messages sent to and +received from the server. +\end{methoddesc} + +\begin{methoddesc}{connect}{\optional{host\optional{, port}}} +Connect to a host on a given port. The defaults are to connect to the +local host at the standard SMTP port (25). +If the hostname ends with a colon (\character{:}) followed by a +number, that suffix will be stripped off and the number interpreted as +the port number to use. +This method is automatically invoked by the constructor if a +host is specified during instantiation. +\end{methoddesc} + +\begin{methoddesc}{docmd}{cmd, \optional{, argstring}} +Send a command \var{cmd} to the server. The optional argument +\var{argstring} is simply concatenated to the command, separated by a +space. + +This returns a 2-tuple composed of a numeric response code and the +actual response line (multiline responses are joined into one long +line.) + +In normal operation it should not be necessary to call this method +explicitly. It is used to implement other methods and may be useful +for testing private extensions. + +If the connection to the server is lost while waiting for the reply, +\exception{SMTPServerDisconnected} will be raised. +\end{methoddesc} + +\begin{methoddesc}{helo}{\optional{hostname}} +Identify yourself to the SMTP server using \samp{HELO}. The hostname +argument defaults to the fully qualified domain name of the local +host. + +In normal operation it should not be necessary to call this method +explicitly. It will be implicitly called by the \method{sendmail()} +when necessary. +\end{methoddesc} + +\begin{methoddesc}{ehlo}{\optional{hostname}} +Identify yourself to an ESMTP server using \samp{EHLO}. The hostname +argument defaults to the fully qualified domain name of the local +host. Examine the response for ESMTP option and store them for use by +\method{has_extn()}. + +Unless you wish to use \method{has_extn()} before sending +mail, it should not be necessary to call this method explicitly. It +will be implicitly called by \method{sendmail()} when necessary. +\end{methoddesc} + +\begin{methoddesc}{has_extn}{name} +Return \constant{True} if \var{name} is in the set of SMTP service +extensions returned by the server, \constant{False} otherwise. +Case is ignored. +\end{methoddesc} + +\begin{methoddesc}{verify}{address} +Check the validity of an address on this server using SMTP \samp{VRFY}. +Returns a tuple consisting of code 250 and a full \rfc{822} address +(including human name) if the user address is valid. Otherwise returns +an SMTP error code of 400 or greater and an error string. + +\note{Many sites disable SMTP \samp{VRFY} in order to foil spammers.} +\end{methoddesc} + +\begin{methoddesc}{login}{user, password} +Log in on an SMTP server that requires authentication. +The arguments are the username and the password to authenticate with. +If there has been no previous \samp{EHLO} or \samp{HELO} command this +session, this method tries ESMTP \samp{EHLO} first. +This method will return normally if the authentication was successful, +or may raise the following exceptions: + +\begin{description} + \item[\exception{SMTPHeloError}] + The server didn't reply properly to the \samp{HELO} greeting. + \item[\exception{SMTPAuthenticationError}] + The server didn't accept the username/password combination. + \item[\exception{SMTPException}] + No suitable authentication method was found. +\end{description} +\end{methoddesc} + +\begin{methoddesc}{starttls}{\optional{keyfile\optional{, certfile}}} +Put the SMTP connection in TLS (Transport Layer Security) mode. All +SMTP commands that follow will be encrypted. You should then call +\method{ehlo()} again. + +If \var{keyfile} and \var{certfile} are provided, these are passed to +the \refmodule{socket} module's \function{ssl()} function. +\end{methoddesc} + +\begin{methoddesc}{sendmail}{from_addr, to_addrs, msg\optional{, + mail_options, rcpt_options}} +Send mail. The required arguments are an \rfc{822} from-address +string, a list of \rfc{822} to-address strings (a bare string will be +treated as a list with 1 address), and a message string. The caller +may pass a list of ESMTP options (such as \samp{8bitmime}) to be used +in \samp{MAIL FROM} commands as \var{mail_options}. ESMTP options +(such as \samp{DSN} commands) that should be used with all \samp{RCPT} +commands can be passed as \var{rcpt_options}. (If you need to use +different ESMTP options to different recipients you have to use the +low-level methods such as \method{mail}, \method{rcpt} and +\method{data} to send the message.) + +\note{The \var{from_addr} and \var{to_addrs} parameters are +used to construct the message envelope used by the transport agents. +The \class{SMTP} does not modify the message headers in any way.} + +If there has been no previous \samp{EHLO} or \samp{HELO} command this +session, this method tries ESMTP \samp{EHLO} first. If the server does +ESMTP, message size and each of the specified options will be passed +to it (if the option is in the feature set the server advertises). If +\samp{EHLO} fails, \samp{HELO} will be tried and ESMTP options +suppressed. + +This method will return normally if the mail is accepted for at least +one recipient. Otherwise it will throw an exception. That is, if this +method does not throw an exception, then someone should get your mail. +If this method does not throw an exception, it returns a dictionary, +with one entry for each recipient that was refused. Each entry +contains a tuple of the SMTP error code and the accompanying error +message sent by the server. + +This method may raise the following exceptions: + +\begin{description} +\item[\exception{SMTPRecipientsRefused}] +All recipients were refused. Nobody got the mail. The +\member{recipients} attribute of the exception object is a dictionary +with information about the refused recipients (like the one returned +when at least one recipient was accepted). + +\item[\exception{SMTPHeloError}] +The server didn't reply properly to the \samp{HELO} greeting. + +\item[\exception{SMTPSenderRefused}] +The server didn't accept the \var{from_addr}. + +\item[\exception{SMTPDataError}] +The server replied with an unexpected error code (other than a refusal +of a recipient). +\end{description} + +Unless otherwise noted, the connection will be open even after +an exception is raised. + +\end{methoddesc} + +\begin{methoddesc}{quit}{} +Terminate the SMTP session and close the connection. +\end{methoddesc} + +Low-level methods corresponding to the standard SMTP/ESMTP commands +\samp{HELP}, \samp{RSET}, \samp{NOOP}, \samp{MAIL}, \samp{RCPT}, and +\samp{DATA} are also supported. Normally these do not need to be +called directly, so they are not documented here. For details, +consult the module code. + + +\subsection{SMTP Example \label{SMTP-example}} + +This example prompts the user for addresses needed in the message +envelope (`To' and `From' addresses), and the message to be +delivered. Note that the headers to be included with the message must +be included in the message as entered; this example doesn't do any +processing of the \rfc{822} headers. In particular, the `To' and +`From' addresses must be included in the message headers explicitly. + +\begin{verbatim} +import smtplib + +def prompt(prompt): + return raw_input(prompt).strip() + +fromaddr = prompt("From: ") +toaddrs = prompt("To: ").split() +print "Enter message, end with ^D (Unix) or ^Z (Windows):" + +# Add the From: and To: headers at the start! +msg = ("From: %s\r\nTo: %s\r\n\r\n" + % (fromaddr, ", ".join(toaddrs))) +while 1: + try: + line = raw_input() + except EOFError: + break + if not line: + break + msg = msg + line + +print "Message length is " + repr(len(msg)) + +server = smtplib.SMTP('localhost') +server.set_debuglevel(1) +server.sendmail(fromaddr, toaddrs, msg) +server.quit() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libsndhdr.tex b/sys/src/cmd/python/Doc/lib/libsndhdr.tex new file mode 100644 index 000000000..a7f8c6eaa --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsndhdr.tex @@ -0,0 +1,41 @@ +\section{\module{sndhdr} --- + Determine type of sound file} + +\declaremodule{standard}{sndhdr} +\modulesynopsis{Determine type of a sound file.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +% Based on comments in the module source file. + + +The \module{sndhdr} provides utility functions which attempt to +determine the type of sound data which is in a file. When these +functions are able to determine what type of sound data is stored in a +file, they return a tuple \code{(\var{type}, \var{sampling_rate}, +\var{channels}, \var{frames}, \var{bits_per_sample})}. The value for +\var{type} indicates the data type and will be one of the strings +\code{'aifc'}, \code{'aiff'}, \code{'au'}, \code{'hcom'}, +\code{'sndr'}, \code{'sndt'}, \code{'voc'}, \code{'wav'}, +\code{'8svx'}, \code{'sb'}, \code{'ub'}, or \code{'ul'}. The +\var{sampling_rate} will be either the actual value or \code{0} if +unknown or difficult to decode. Similarly, \var{channels} will be +either the number of channels or \code{0} if it cannot be determined +or if the value is difficult to decode. The value for \var{frames} +will be either the number of frames or \code{-1}. The last item in +the tuple, \var{bits_per_sample}, will either be the sample size in +bits or \code{'A'} for A-LAW\index{A-LAW} or \code{'U'} for +u-LAW\index{u-LAW}. + + +\begin{funcdesc}{what}{filename} + Determines the type of sound data stored in the file \var{filename} + using \function{whathdr()}. If it succeeds, returns a tuple as + described above, otherwise \code{None} is returned. +\end{funcdesc} + + +\begin{funcdesc}{whathdr}{filename} + Determines the type of sound data stored in a file based on the file + header. The name of the file is given by \var{filename}. This + function returns a tuple as described above on success, or + \code{None}. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libsocket.tex b/sys/src/cmd/python/Doc/lib/libsocket.tex new file mode 100644 index 000000000..e5a3c3280 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsocket.tex @@ -0,0 +1,910 @@ +\section{\module{socket} --- + Low-level networking interface} + +\declaremodule{builtin}{socket} +\modulesynopsis{Low-level networking interface.} + + +This module provides access to the BSD \emph{socket} interface. +It is available on all modern \UNIX{} systems, Windows, MacOS, BeOS, +OS/2, and probably additional platforms. \note{Some behavior may be +platform dependent, since calls are made to the operating system socket APIs.} + +For an introduction to socket programming (in C), see the following +papers: \citetitle{An Introductory 4.3BSD Interprocess Communication +Tutorial}, by Stuart Sechrest and \citetitle{An Advanced 4.3BSD +Interprocess Communication Tutorial}, by Samuel J. Leffler et al, +both in the \citetitle{\UNIX{} Programmer's Manual, Supplementary Documents 1} +(sections PS1:7 and PS1:8). The platform-specific reference material +for the various socket-related system calls are also a valuable source +of information on the details of socket semantics. For \UNIX, refer +to the manual pages; for Windows, see the WinSock (or Winsock 2) +specification. +For IPv6-ready APIs, readers may want to refer to \rfc{2553} titled +\citetitle{Basic Socket Interface Extensions for IPv6}. + +The Python interface is a straightforward transliteration of the +\UNIX{} system call and library interface for sockets to Python's +object-oriented style: the \function{socket()} function returns a +\dfn{socket object}\obindex{socket} whose methods implement the +various socket system calls. Parameter types are somewhat +higher-level than in the C interface: as with \method{read()} and +\method{write()} operations on Python files, buffer allocation on +receive operations is automatic, and buffer length is implicit on send +operations. + +Socket addresses are represented as follows: +A single string is used for the \constant{AF_UNIX} address family. +A pair \code{(\var{host}, \var{port})} is used for the +\constant{AF_INET} address family, where \var{host} is a string +representing either a hostname in Internet domain notation like +\code{'daring.cwi.nl'} or an IPv4 address like \code{'100.50.200.5'}, +and \var{port} is an integral port number. +For \constant{AF_INET6} address family, a four-tuple +\code{(\var{host}, \var{port}, \var{flowinfo}, \var{scopeid})} is +used, where \var{flowinfo} and \var{scopeid} represents +\code{sin6_flowinfo} and \code{sin6_scope_id} member in +\constant{struct sockaddr_in6} in C. +For \module{socket} module methods, \var{flowinfo} and \var{scopeid} +can be omitted just for backward compatibility. Note, however, +omission of \var{scopeid} can cause problems in manipulating scoped +IPv6 addresses. Other address families are currently not supported. +The address format required by a particular socket object is +automatically selected based on the address family specified when the +socket object was created. + +For IPv4 addresses, two special forms are accepted instead of a host +address: the empty string represents \constant{INADDR_ANY}, and the string +\code{'<broadcast>'} represents \constant{INADDR_BROADCAST}. +The behavior is not available for IPv6 for backward compatibility, +therefore, you may want to avoid these if you intend to support IPv6 with +your Python programs. + +If you use a hostname in the \var{host} portion of IPv4/v6 socket +address, the program may show a nondeterministic behavior, as Python +uses the first address returned from the DNS resolution. The socket +address will be resolved differently into an actual IPv4/v6 address, +depending on the results from DNS resolution and/or the host +configuration. For deterministic behavior use a numeric address in +\var{host} portion. + +\versionadded[AF_NETLINK sockets are represented as +pairs \code{\var{pid}, \var{groups}}]{2.5} + +All errors raise exceptions. The normal exceptions for invalid +argument types and out-of-memory conditions can be raised; errors +related to socket or address semantics raise the error +\exception{socket.error}. + +Non-blocking mode is supported through +\method{setblocking()}. A generalization of this based on timeouts +is supported through \method{settimeout()}. + +The module \module{socket} exports the following constants and functions: + + +\begin{excdesc}{error} +This exception is raised for socket-related errors. +The accompanying value is either a string telling what went wrong or a +pair \code{(\var{errno}, \var{string})} +representing an error returned by a system +call, similar to the value accompanying \exception{os.error}. +See the module \refmodule{errno}\refbimodindex{errno}, which contains +names for the error codes defined by the underlying operating system. +\end{excdesc} + +\begin{excdesc}{herror} +This exception is raised for address-related errors, i.e. for +functions that use \var{h_errno} in the C API, including +\function{gethostbyname_ex()} and \function{gethostbyaddr()}. + +The accompanying value is a pair \code{(\var{h_errno}, \var{string})} +representing an error returned by a library call. \var{string} +represents the description of \var{h_errno}, as returned by +the \cfunction{hstrerror()} C function. +\end{excdesc} + +\begin{excdesc}{gaierror} +This exception is raised for address-related errors, for +\function{getaddrinfo()} and \function{getnameinfo()}. +The accompanying value is a pair \code{(\var{error}, \var{string})} +representing an error returned by a library call. +\var{string} represents the description of \var{error}, as returned +by the \cfunction{gai_strerror()} C function. +The \var{error} value will match one of the \constant{EAI_*} constants +defined in this module. +\end{excdesc} + +\begin{excdesc}{timeout} +This exception is raised when a timeout occurs on a socket which has +had timeouts enabled via a prior call to \method{settimeout()}. The +accompanying value is a string whose value is currently always ``timed +out''. +\versionadded{2.3} +\end{excdesc} + +\begin{datadesc}{AF_UNIX} +\dataline{AF_INET} +\dataline{AF_INET6} +These constants represent the address (and protocol) families, +used for the first argument to \function{socket()}. If the +\constant{AF_UNIX} constant is not defined then this protocol is +unsupported. +\end{datadesc} + +\begin{datadesc}{SOCK_STREAM} +\dataline{SOCK_DGRAM} +\dataline{SOCK_RAW} +\dataline{SOCK_RDM} +\dataline{SOCK_SEQPACKET} +These constants represent the socket types, +used for the second argument to \function{socket()}. +(Only \constant{SOCK_STREAM} and +\constant{SOCK_DGRAM} appear to be generally useful.) +\end{datadesc} + +\begin{datadesc}{SO_*} +\dataline{SOMAXCONN} +\dataline{MSG_*} +\dataline{SOL_*} +\dataline{IPPROTO_*} +\dataline{IPPORT_*} +\dataline{INADDR_*} +\dataline{IP_*} +\dataline{IPV6_*} +\dataline{EAI_*} +\dataline{AI_*} +\dataline{NI_*} +\dataline{TCP_*} +Many constants of these forms, documented in the \UNIX{} documentation on +sockets and/or the IP protocol, are also defined in the socket module. +They are generally used in arguments to the \method{setsockopt()} and +\method{getsockopt()} methods of socket objects. In most cases, only +those symbols that are defined in the \UNIX{} header files are defined; +for a few symbols, default values are provided. +\end{datadesc} + +\begin{datadesc}{has_ipv6} +This constant contains a boolean value which indicates if IPv6 is +supported on this platform. +\versionadded{2.3} +\end{datadesc} + +\begin{funcdesc}{getaddrinfo}{host, port\optional{, family\optional{, + socktype\optional{, proto\optional{, + flags}}}}} +Resolves the \var{host}/\var{port} argument, into a sequence of +5-tuples that contain all the necessary argument for the sockets +manipulation. \var{host} is a domain name, a string representation of +IPv4/v6 address or \code{None}. +\var{port} is a string service name (like \code{'http'}), a numeric +port number or \code{None}. + +The rest of the arguments are optional and must be numeric if +specified. For \var{host} and \var{port}, by passing either an empty +string or \code{None}, you can pass \code{NULL} to the C API. The +\function{getaddrinfo()} function returns a list of 5-tuples with +the following structure: + +\code{(\var{family}, \var{socktype}, \var{proto}, \var{canonname}, + \var{sockaddr})} + +\var{family}, \var{socktype}, \var{proto} are all integer and are meant to +be passed to the \function{socket()} function. +\var{canonname} is a string representing the canonical name of the \var{host}. +It can be a numeric IPv4/v6 address when \constant{AI_CANONNAME} is specified +for a numeric \var{host}. +\var{sockaddr} is a tuple describing a socket address, as described above. +See the source for the \refmodule{httplib} and other library modules +for a typical usage of the function. +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{getfqdn}{\optional{name}} +Return a fully qualified domain name for \var{name}. +If \var{name} is omitted or empty, it is interpreted as the local +host. To find the fully qualified name, the hostname returned by +\function{gethostbyaddr()} is checked, then aliases for the host, if +available. The first name which includes a period is selected. In +case no fully qualified domain name is available, the hostname as +returned by \function{gethostname()} is returned. +\versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{gethostbyname}{hostname} +Translate a host name to IPv4 address format. The IPv4 address is +returned as a string, such as \code{'100.50.200.5'}. If the host name +is an IPv4 address itself it is returned unchanged. See +\function{gethostbyname_ex()} for a more complete interface. +\function{gethostbyname()} does not support IPv6 name resolution, and +\function{getaddrinfo()} should be used instead for IPv4/v6 dual stack support. +\end{funcdesc} + +\begin{funcdesc}{gethostbyname_ex}{hostname} +Translate a host name to IPv4 address format, extended interface. +Return a triple \code{(\var{hostname}, \var{aliaslist}, +\var{ipaddrlist})} where +\var{hostname} is the primary host name responding to the given +\var{ip_address}, \var{aliaslist} is a (possibly empty) list of +alternative host names for the same address, and \var{ipaddrlist} is +a list of IPv4 addresses for the same interface on the same +host (often but not always a single address). +\function{gethostbyname_ex()} does not support IPv6 name resolution, and +\function{getaddrinfo()} should be used instead for IPv4/v6 dual stack support. +\end{funcdesc} + +\begin{funcdesc}{gethostname}{} +Return a string containing the hostname of the machine where +the Python interpreter is currently executing. +If you want to know the current machine's IP address, you may want to use +\code{gethostbyname(gethostname())}. +This operation assumes that there is a valid address-to-host mapping for +the host, and the assumption does not always hold. +Note: \function{gethostname()} doesn't always return the fully qualified +domain name; use \code{getfqdn()} +(see above). +\end{funcdesc} + +\begin{funcdesc}{gethostbyaddr}{ip_address} +Return a triple \code{(\var{hostname}, \var{aliaslist}, +\var{ipaddrlist})} where \var{hostname} is the primary host name +responding to the given \var{ip_address}, \var{aliaslist} is a +(possibly empty) list of alternative host names for the same address, +and \var{ipaddrlist} is a list of IPv4/v6 addresses for the same interface +on the same host (most likely containing only a single address). +To find the fully qualified domain name, use the function +\function{getfqdn()}. +\function{gethostbyaddr} supports both IPv4 and IPv6. +\end{funcdesc} + +\begin{funcdesc}{getnameinfo}{sockaddr, flags} +Translate a socket address \var{sockaddr} into a 2-tuple +\code{(\var{host}, \var{port})}. +Depending on the settings of \var{flags}, the result can contain a +fully-qualified domain name or numeric address representation in +\var{host}. Similarly, \var{port} can contain a string port name or a +numeric port number. +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{getprotobyname}{protocolname} +Translate an Internet protocol name (for example, \code{'icmp'}) to a constant +suitable for passing as the (optional) third argument to the +\function{socket()} function. This is usually only needed for sockets +opened in ``raw'' mode (\constant{SOCK_RAW}); for the normal socket +modes, the correct protocol is chosen automatically if the protocol is +omitted or zero. +\end{funcdesc} + +\begin{funcdesc}{getservbyname}{servicename\optional{, protocolname}} +Translate an Internet service name and protocol name to a port number +for that service. The optional protocol name, if given, should be +\code{'tcp'} or \code{'udp'}, otherwise any protocol will match. +\end{funcdesc} + +\begin{funcdesc}{getservbyport}{port\optional{, protocolname}} +Translate an Internet port number and protocol name to a service name +for that service. The optional protocol name, if given, should be +\code{'tcp'} or \code{'udp'}, otherwise any protocol will match. +\end{funcdesc} + +\begin{funcdesc}{socket}{\optional{family\optional{, + type\optional{, proto}}}} +Create a new socket using the given address family, socket type and +protocol number. The address family should be \constant{AF_INET} (the +default), \constant{AF_INET6} or \constant{AF_UNIX}. The socket type +should be \constant{SOCK_STREAM} (the default), \constant{SOCK_DGRAM} +or perhaps one of the other \samp{SOCK_} constants. The protocol +number is usually zero and may be omitted in that case. +\end{funcdesc} + +\begin{funcdesc}{ssl}{sock\optional{, keyfile, certfile}} +Initiate a SSL connection over the socket \var{sock}. \var{keyfile} is +the name of a PEM formatted file that contains your private +key. \var{certfile} is a PEM formatted certificate chain file. On +success, a new \class{SSLObject} is returned. + +\warning{This does not do any certificate verification!} +\end{funcdesc} + +\begin{funcdesc}{socketpair}{\optional{family\optional{, type\optional{, proto}}}} +Build a pair of connected socket objects using the given address +family, socket type, and protocol number. Address family, socket type, +and protocol number are as for the \function{socket()} function above. +The default family is \constant{AF_UNIX} if defined on the platform; +otherwise, the default is \constant{AF_INET}. +Availability: \UNIX. \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{fromfd}{fd, family, type\optional{, proto}} +Duplicate the file descriptor \var{fd} (an integer as returned by a file +object's \method{fileno()} method) and build a socket object from the +result. Address family, socket type and protocol number are as for the +\function{socket()} function above. +The file descriptor should refer to a socket, but this is not +checked --- subsequent operations on the object may fail if the file +descriptor is invalid. This function is rarely needed, but can be +used to get or set socket options on a socket passed to a program as +standard input or output (such as a server started by the \UNIX{} inet +daemon). The socket is assumed to be in blocking mode. +Availability: \UNIX. +\end{funcdesc} + +\begin{funcdesc}{ntohl}{x} +Convert 32-bit integers from network to host byte order. On machines +where the host byte order is the same as network byte order, this is a +no-op; otherwise, it performs a 4-byte swap operation. +\end{funcdesc} + +\begin{funcdesc}{ntohs}{x} +Convert 16-bit integers from network to host byte order. On machines +where the host byte order is the same as network byte order, this is a +no-op; otherwise, it performs a 2-byte swap operation. +\end{funcdesc} + +\begin{funcdesc}{htonl}{x} +Convert 32-bit integers from host to network byte order. On machines +where the host byte order is the same as network byte order, this is a +no-op; otherwise, it performs a 4-byte swap operation. +\end{funcdesc} + +\begin{funcdesc}{htons}{x} +Convert 16-bit integers from host to network byte order. On machines +where the host byte order is the same as network byte order, this is a +no-op; otherwise, it performs a 2-byte swap operation. +\end{funcdesc} + +\begin{funcdesc}{inet_aton}{ip_string} +Convert an IPv4 address from dotted-quad string format (for example, +'123.45.67.89') to 32-bit packed binary format, as a string four +characters in length. This is useful when conversing with a program +that uses the standard C library and needs objects of type +\ctype{struct in_addr}, which is the C type for the 32-bit packed +binary this function returns. + +If the IPv4 address string passed to this function is invalid, +\exception{socket.error} will be raised. Note that exactly what is +valid depends on the underlying C implementation of +\cfunction{inet_aton()}. + +\function{inet_aton()} does not support IPv6, and +\function{getnameinfo()} should be used instead for IPv4/v6 dual stack +support. +\end{funcdesc} + +\begin{funcdesc}{inet_ntoa}{packed_ip} +Convert a 32-bit packed IPv4 address (a string four characters in +length) to its standard dotted-quad string representation (for +example, '123.45.67.89'). This is useful when conversing with a +program that uses the standard C library and needs objects of type +\ctype{struct in_addr}, which is the C type for the 32-bit packed +binary data this function takes as an argument. + +If the string passed to this function is not exactly 4 bytes in +length, \exception{socket.error} will be raised. +\function{inet_ntoa()} does not support IPv6, and +\function{getnameinfo()} should be used instead for IPv4/v6 dual stack +support. +\end{funcdesc} + +\begin{funcdesc}{inet_pton}{address_family, ip_string} +Convert an IP address from its family-specific string format to a packed, +binary format. +\function{inet_pton()} is useful when a library or network protocol calls for +an object of type \ctype{struct in_addr} (similar to \function{inet_aton()}) +or \ctype{struct in6_addr}. + +Supported values for \var{address_family} are currently +\constant{AF_INET} and \constant{AF_INET6}. +If the IP address string \var{ip_string} is invalid, +\exception{socket.error} will be raised. Note that exactly what is valid +depends on both the value of \var{address_family} and the underlying +implementation of \cfunction{inet_pton()}. + +Availability: \UNIX{} (maybe not all platforms). +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{inet_ntop}{address_family, packed_ip} +Convert a packed IP address (a string of some number of characters) to +its standard, family-specific string representation (for example, +\code{'7.10.0.5'} or \code{'5aef:2b::8'}) +\function{inet_ntop()} is useful when a library or network protocol returns +an object of type \ctype{struct in_addr} (similar to \function{inet_ntoa()}) +or \ctype{struct in6_addr}. + +Supported values for \var{address_family} are currently +\constant{AF_INET} and \constant{AF_INET6}. +If the string \var{packed_ip} is not the correct length for the +specified address family, \exception{ValueError} will be raised. A +\exception{socket.error} is raised for errors from the call to +\function{inet_ntop()}. + +Availability: \UNIX{} (maybe not all platforms). +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{getdefaulttimeout}{} +Return the default timeout in floating seconds for new socket objects. +A value of \code{None} indicates that new socket objects have no timeout. +When the socket module is first imported, the default is \code{None}. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{setdefaulttimeout}{timeout} +Set the default timeout in floating seconds for new socket objects. +A value of \code{None} indicates that new socket objects have no timeout. +When the socket module is first imported, the default is \code{None}. +\versionadded{2.3} +\end{funcdesc} + +\begin{datadesc}{SocketType} +This is a Python type object that represents the socket object type. +It is the same as \code{type(socket(...))}. +\end{datadesc} + + +\begin{seealso} + \seemodule{SocketServer}{Classes that simplify writing network servers.} +\end{seealso} + + +\subsection{Socket Objects \label{socket-objects}} + +Socket objects have the following methods. Except for +\method{makefile()} these correspond to \UNIX{} system calls +applicable to sockets. + +\begin{methoddesc}[socket]{accept}{} +Accept a connection. +The socket must be bound to an address and listening for connections. +The return value is a pair \code{(\var{conn}, \var{address})} +where \var{conn} is a \emph{new} socket object usable to send and +receive data on the connection, and \var{address} is the address bound +to the socket on the other end of the connection. +\end{methoddesc} + +\begin{methoddesc}[socket]{bind}{address} +Bind the socket to \var{address}. The socket must not already be bound. +(The format of \var{address} depends on the address family --- see +above.) \note{This method has historically accepted a pair +of parameters for \constant{AF_INET} addresses instead of only a +tuple. This was never intentional and is no longer available in +Python 2.0 and later.} +\end{methoddesc} + +\begin{methoddesc}[socket]{close}{} +Close the socket. All future operations on the socket object will fail. +The remote end will receive no more data (after queued data is flushed). +Sockets are automatically closed when they are garbage-collected. +\end{methoddesc} + +\begin{methoddesc}[socket]{connect}{address} +Connect to a remote socket at \var{address}. +(The format of \var{address} depends on the address family --- see +above.) \note{This method has historically accepted a pair +of parameters for \constant{AF_INET} addresses instead of only a +tuple. This was never intentional and is no longer available in +Python 2.0 and later.} +\end{methoddesc} + +\begin{methoddesc}[socket]{connect_ex}{address} +Like \code{connect(\var{address})}, but return an error indicator +instead of raising an exception for errors returned by the C-level +\cfunction{connect()} call (other problems, such as ``host not found,'' +can still raise exceptions). The error indicator is \code{0} if the +operation succeeded, otherwise the value of the \cdata{errno} +variable. This is useful to support, for example, asynchronous connects. +\note{This method has historically accepted a pair of +parameters for \constant{AF_INET} addresses instead of only a tuple. +This was never intentional and is no longer available in Python +2.0 and later.} +\end{methoddesc} + +\begin{methoddesc}[socket]{fileno}{} +Return the socket's file descriptor (a small integer). This is useful +with \function{select.select()}. + +Under Windows the small integer returned by this method cannot be used where +a file descriptor can be used (such as \function{os.fdopen()}). \UNIX{} does +not have this limitation. +\end{methoddesc} + +\begin{methoddesc}[socket]{getpeername}{} +Return the remote address to which the socket is connected. This is +useful to find out the port number of a remote IPv4/v6 socket, for instance. +(The format of the address returned depends on the address family --- +see above.) On some systems this function is not supported. +\end{methoddesc} + +\begin{methoddesc}[socket]{getsockname}{} +Return the socket's own address. This is useful to find out the port +number of an IPv4/v6 socket, for instance. +(The format of the address returned depends on the address family --- +see above.) +\end{methoddesc} + +\begin{methoddesc}[socket]{getsockopt}{level, optname\optional{, buflen}} +Return the value of the given socket option (see the \UNIX{} man page +\manpage{getsockopt}{2}). The needed symbolic constants +(\constant{SO_*} etc.) are defined in this module. If \var{buflen} +is absent, an integer option is assumed and its integer value +is returned by the function. If \var{buflen} is present, it specifies +the maximum length of the buffer used to receive the option in, and +this buffer is returned as a string. It is up to the caller to decode +the contents of the buffer (see the optional built-in module +\refmodule{struct} for a way to decode C structures encoded as strings). +\end{methoddesc} + +\begin{methoddesc}[socket]{listen}{backlog} +Listen for connections made to the socket. The \var{backlog} argument +specifies the maximum number of queued connections and should be at +least 1; the maximum value is system-dependent (usually 5). +\end{methoddesc} + +\begin{methoddesc}[socket]{makefile}{\optional{mode\optional{, bufsize}}} +Return a \dfn{file object} associated with the socket. (File objects +are described in \ref{bltin-file-objects}, ``File Objects.'') +The file object references a \cfunction{dup()}ped version of the +socket file descriptor, so the file object and socket object may be +closed or garbage-collected independently. +The socket must be in blocking mode. +\index{I/O control!buffering}The optional \var{mode} +and \var{bufsize} arguments are interpreted the same way as by the +built-in \function{file()} function; see ``Built-in Functions'' +(section \ref{built-in-funcs}) for more information. +\end{methoddesc} + +\begin{methoddesc}[socket]{recv}{bufsize\optional{, flags}} +Receive data from the socket. The return value is a string representing +the data received. The maximum amount of data to be received +at once is specified by \var{bufsize}. See the \UNIX{} manual page +\manpage{recv}{2} for the meaning of the optional argument +\var{flags}; it defaults to zero. +\note{For best match with hardware and network realities, the value of +\var{bufsize} should be a relatively small power of 2, for example, 4096.} +\end{methoddesc} + +\begin{methoddesc}[socket]{recvfrom}{bufsize\optional{, flags}} +Receive data from the socket. The return value is a pair +\code{(\var{string}, \var{address})} where \var{string} is a string +representing the data received and \var{address} is the address of the +socket sending the data. The optional \var{flags} argument has the +same meaning as for \method{recv()} above. +(The format of \var{address} depends on the address family --- see above.) +\end{methoddesc} + +\begin{methoddesc}[socket]{recvfrom_into}{buffer\optional{, nbytes\optional{, flags}}} +Receive data from the socket, writing it into \var{buffer} instead of +creating a new string. The return value is a pair +\code{(\var{nbytes}, \var{address})} where \var{nbytes} is the number +of bytes received and \var{address} is the address of the socket +sending the data. See the \UNIX{} manual page +\manpage{recv}{2} for the meaning of the optional argument +\var{flags}; it defaults to zero. (The format of \var{address} +depends on the address family --- see above.) +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}[socket]{recv_into}{buffer\optional{, nbytes\optional{, flags}}} +Receive up to \var{nbytes} bytes from the socket, +storing the data into a buffer rather than creating a new string. +If \var{nbytes} is not specified (or 0), +receive up to the size available in the given buffer. +See the \UNIX{} manual page \manpage{recv}{2} for the meaning of the +optional argument \var{flags}; it defaults to zero. +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}[socket]{send}{string\optional{, flags}} +Send data to the socket. The socket must be connected to a remote +socket. The optional \var{flags} argument has the same meaning as for +\method{recv()} above. Returns the number of bytes sent. +Applications are responsible for checking that all data has been sent; +if only some of the data was transmitted, the application needs to +attempt delivery of the remaining data. +\end{methoddesc} + +\begin{methoddesc}[socket]{sendall}{string\optional{, flags}} +Send data to the socket. The socket must be connected to a remote +socket. The optional \var{flags} argument has the same meaning as for +\method{recv()} above. Unlike \method{send()}, this method continues +to send data from \var{string} until either all data has been sent or +an error occurs. \code{None} is returned on success. On error, an +exception is raised, and there is no way to determine how much data, +if any, was successfully sent. +\end{methoddesc} + +\begin{methoddesc}[socket]{sendto}{string\optional{, flags}, address} +Send data to the socket. The socket should not be connected to a +remote socket, since the destination socket is specified by +\var{address}. The optional \var{flags} argument has the same +meaning as for \method{recv()} above. Return the number of bytes sent. +(The format of \var{address} depends on the address family --- see above.) +\end{methoddesc} + +\begin{methoddesc}[socket]{setblocking}{flag} +Set blocking or non-blocking mode of the socket: if \var{flag} is 0, +the socket is set to non-blocking, else to blocking mode. Initially +all sockets are in blocking mode. In non-blocking mode, if a +\method{recv()} call doesn't find any data, or if a +\method{send()} call can't immediately dispose of the data, a +\exception{error} exception is raised; in blocking mode, the calls +block until they can proceed. +\code{s.setblocking(0)} is equivalent to \code{s.settimeout(0)}; +\code{s.setblocking(1)} is equivalent to \code{s.settimeout(None)}. +\end{methoddesc} + +\begin{methoddesc}[socket]{settimeout}{value} +Set a timeout on blocking socket operations. The \var{value} argument +can be a nonnegative float expressing seconds, or \code{None}. +If a float is +given, subsequent socket operations will raise an \exception{timeout} +exception if the timeout period \var{value} has elapsed before the +operation has completed. Setting a timeout of \code{None} disables +timeouts on socket operations. +\code{s.settimeout(0.0)} is equivalent to \code{s.setblocking(0)}; +\code{s.settimeout(None)} is equivalent to \code{s.setblocking(1)}. +\versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}[socket]{gettimeout}{} +Return the timeout in floating seconds associated with socket +operations, or \code{None} if no timeout is set. This reflects +the last call to \method{setblocking()} or \method{settimeout()}. +\versionadded{2.3} +\end{methoddesc} + +Some notes on socket blocking and timeouts: A socket object can be in +one of three modes: blocking, non-blocking, or timeout. Sockets are +always created in blocking mode. In blocking mode, operations block +until complete. In non-blocking mode, operations fail (with an error +that is unfortunately system-dependent) if they cannot be completed +immediately. In timeout mode, operations fail if they cannot be +completed within the timeout specified for the socket. The +\method{setblocking()} method is simply a shorthand for certain +\method{settimeout()} calls. + +Timeout mode internally sets the socket in non-blocking mode. The +blocking and timeout modes are shared between file descriptors and +socket objects that refer to the same network endpoint. A consequence +of this is that file objects returned by the \method{makefile()} +method must only be used when the socket is in blocking mode; in +timeout or non-blocking mode file operations that cannot be completed +immediately will fail. + +Note that the \method{connect()} operation is subject to the timeout +setting, and in general it is recommended to call +\method{settimeout()} before calling \method{connect()}. + +\begin{methoddesc}[socket]{setsockopt}{level, optname, value} +Set the value of the given socket option (see the \UNIX{} manual page +\manpage{setsockopt}{2}). The needed symbolic constants are defined in +the \module{socket} module (\constant{SO_*} etc.). The value can be an +integer or a string representing a buffer. In the latter case it is +up to the caller to ensure that the string contains the proper bits +(see the optional built-in module +\refmodule{struct}\refbimodindex{struct} for a way to encode C +structures as strings). +\end{methoddesc} + +\begin{methoddesc}[socket]{shutdown}{how} +Shut down one or both halves of the connection. If \var{how} is +\constant{SHUT_RD}, further receives are disallowed. If \var{how} is \constant{SHUT_WR}, +further sends are disallowed. If \var{how} is \constant{SHUT_RDWR}, further sends +and receives are disallowed. +\end{methoddesc} + +Note that there are no methods \method{read()} or \method{write()}; +use \method{recv()} and \method{send()} without \var{flags} argument +instead. + + +Socket objects also have these (read-only) attributes that correspond +to the values given to the \class{socket} constructor. + +\begin{memberdesc}[socket]{family} +The socket family. +\versionadded{2.5} +\end{memberdesc} + +\begin{memberdesc}[socket]{type} +The socket type. +\versionadded{2.5} +\end{memberdesc} + +\begin{memberdesc}[socket]{proto} +The socket protocol. +\versionadded{2.5} +\end{memberdesc} + + +\subsection{SSL Objects \label{ssl-objects}} + +SSL objects have the following methods. + +\begin{methoddesc}{write}{s} +Writes the string \var{s} to the on the object's SSL connection. +The return value is the number of bytes written. +\end{methoddesc} + +\begin{methoddesc}{read}{\optional{n}} +If \var{n} is provided, read \var{n} bytes from the SSL connection, otherwise +read until EOF. The return value is a string of the bytes read. +\end{methoddesc} + +\begin{methoddesc}{server}{} +Returns a string describing the server's certificate. +Useful for debugging purposes; do not parse the content of this string +because its format can't be parsed unambiguously. +\end{methoddesc} + +\begin{methoddesc}{issuer}{} +Returns a string describing the issuer of the server's certificate. +Useful for debugging purposes; do not parse the content of this string +because its format can't be parsed unambiguously. +\end{methoddesc} + +\subsection{Example \label{socket-example}} + +Here are four minimal example programs using the TCP/IP protocol:\ a +server that echoes all data that it receives back (servicing only one +client), and a client using it. Note that a server must perform the +sequence \function{socket()}, \method{bind()}, \method{listen()}, +\method{accept()} (possibly repeating the \method{accept()} to service +more than one client), while a client only needs the sequence +\function{socket()}, \method{connect()}. Also note that the server +does not \method{send()}/\method{recv()} on the +socket it is listening on but on the new socket returned by +\method{accept()}. + +The first two examples support IPv4 only. + +\begin{verbatim} +# Echo server program +import socket + +HOST = '' # Symbolic name meaning the local host +PORT = 50007 # Arbitrary non-privileged port +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.bind((HOST, PORT)) +s.listen(1) +conn, addr = s.accept() +print 'Connected by', addr +while 1: + data = conn.recv(1024) + if not data: break + conn.send(data) +conn.close() +\end{verbatim} + +\begin{verbatim} +# Echo client program +import socket + +HOST = 'daring.cwi.nl' # The remote host +PORT = 50007 # The same port as used by the server +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.connect((HOST, PORT)) +s.send('Hello, world') +data = s.recv(1024) +s.close() +print 'Received', repr(data) +\end{verbatim} + +The next two examples are identical to the above two, but support both +IPv4 and IPv6. +The server side will listen to the first address family available +(it should listen to both instead). +On most of IPv6-ready systems, IPv6 will take precedence +and the server may not accept IPv4 traffic. +The client side will try to connect to the all addresses returned as a result +of the name resolution, and sends traffic to the first one connected +successfully. + +\begin{verbatim} +# Echo server program +import socket +import sys + +HOST = '' # Symbolic name meaning the local host +PORT = 50007 # Arbitrary non-privileged port +s = None +for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): + af, socktype, proto, canonname, sa = res + try: + s = socket.socket(af, socktype, proto) + except socket.error, msg: + s = None + continue + try: + s.bind(sa) + s.listen(1) + except socket.error, msg: + s.close() + s = None + continue + break +if s is None: + print 'could not open socket' + sys.exit(1) +conn, addr = s.accept() +print 'Connected by', addr +while 1: + data = conn.recv(1024) + if not data: break + conn.send(data) +conn.close() +\end{verbatim} + +\begin{verbatim} +# Echo client program +import socket +import sys + +HOST = 'daring.cwi.nl' # The remote host +PORT = 50007 # The same port as used by the server +s = None +for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + try: + s = socket.socket(af, socktype, proto) + except socket.error, msg: + s = None + continue + try: + s.connect(sa) + except socket.error, msg: + s.close() + s = None + continue + break +if s is None: + print 'could not open socket' + sys.exit(1) +s.send('Hello, world') +data = s.recv(1024) +s.close() +print 'Received', repr(data) +\end{verbatim} + +This example connects to an SSL server, prints the +server and issuer's distinguished names, sends some bytes, +and reads part of the response: + +\begin{verbatim} +import socket + +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.connect(('www.verisign.com', 443)) + +ssl_sock = socket.ssl(s) + +print repr(ssl_sock.server()) +print repr(ssl_sock.issuer()) + +# Set a simple HTTP request -- use httplib in actual code. +ssl_sock.write("""GET / HTTP/1.0\r +Host: www.verisign.com\r\n\r\n""") + +# Read a chunk of data. Will not necessarily +# read all the data returned by the server. +data = ssl_sock.read() + +# Note that you need to close the underlying socket, not the SSL object. +del ssl_sock +s.close() +\end{verbatim} + +At this writing, this SSL example prints the following output (line +breaks inserted for readability): + +\begin{verbatim} +'/C=US/ST=California/L=Mountain View/ + O=VeriSign, Inc./OU=Production Services/ + OU=Terms of use at www.verisign.com/rpa (c)00/ + CN=www.verisign.com' +'/O=VeriSign Trust Network/OU=VeriSign, Inc./ + OU=VeriSign International Server CA - Class 3/ + OU=www.verisign.com/CPS Incorp.by Ref. LIABILITY LTD.(c)97 VeriSign' +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libsocksvr.tex b/sys/src/cmd/python/Doc/lib/libsocksvr.tex new file mode 100644 index 000000000..c7b28ea0d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsocksvr.tex @@ -0,0 +1,293 @@ +\section{\module{SocketServer} --- + A framework for network servers} + +\declaremodule{standard}{SocketServer} +\modulesynopsis{A framework for network servers.} + + +The \module{SocketServer} module simplifies the task of writing network +servers. + +There are four basic server classes: \class{TCPServer} uses the +Internet TCP protocol, which provides for continuous streams of data +between the client and server. \class{UDPServer} uses datagrams, which +are discrete packets of information that may arrive out of order or be +lost while in transit. The more infrequently used +\class{UnixStreamServer} and \class{UnixDatagramServer} classes are +similar, but use \UNIX{} domain sockets; they're not available on +non-\UNIX{} platforms. For more details on network programming, consult +a book such as W. Richard Steven's \citetitle{UNIX Network Programming} +or Ralph Davis's \citetitle{Win32 Network Programming}. + +These four classes process requests \dfn{synchronously}; each request +must be completed before the next request can be started. This isn't +suitable if each request takes a long time to complete, because it +requires a lot of computation, or because it returns a lot of data +which the client is slow to process. The solution is to create a +separate process or thread to handle each request; the +\class{ForkingMixIn} and \class{ThreadingMixIn} mix-in classes can be +used to support asynchronous behaviour. + +Creating a server requires several steps. First, you must create a +request handler class by subclassing the \class{BaseRequestHandler} +class and overriding its \method{handle()} method; this method will +process incoming requests. Second, you must instantiate one of the +server classes, passing it the server's address and the request +handler class. Finally, call the \method{handle_request()} or +\method{serve_forever()} method of the server object to process one or +many requests. + +When inheriting from \class{ThreadingMixIn} for threaded connection +behavior, you should explicitly declare how you want your threads +to behave on an abrupt shutdown. The \class{ThreadingMixIn} class +defines an attribute \var{daemon_threads}, which indicates whether +or not the server should wait for thread termination. You should +set the flag explicitly if you would like threads to behave +autonomously; the default is \constant{False}, meaning that Python +will not exit until all threads created by \class{ThreadingMixIn} have +exited. + +Server classes have the same external methods and attributes, no +matter what network protocol they use: + +\setindexsubitem{(SocketServer protocol)} + +\subsection{Server Creation Notes} + +There are five classes in an inheritance diagram, four of which represent +synchronous servers of four types: + +\begin{verbatim} + +------------+ + | BaseServer | + +------------+ + | + v + +-----------+ +------------------+ + | TCPServer |------->| UnixStreamServer | + +-----------+ +------------------+ + | + v + +-----------+ +--------------------+ + | UDPServer |------->| UnixDatagramServer | + +-----------+ +--------------------+ +\end{verbatim} + +Note that \class{UnixDatagramServer} derives from \class{UDPServer}, not +from \class{UnixStreamServer} --- the only difference between an IP and a +\UNIX{} stream server is the address family, which is simply repeated in both +\UNIX{} server classes. + +Forking and threading versions of each type of server can be created using +the \class{ForkingMixIn} and \class{ThreadingMixIn} mix-in classes. For +instance, a threading UDP server class is created as follows: + +\begin{verbatim} + class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass +\end{verbatim} + +The mix-in class must come first, since it overrides a method defined in +\class{UDPServer}. Setting the various member variables also changes the +behavior of the underlying server mechanism. + +To implement a service, you must derive a class from +\class{BaseRequestHandler} and redefine its \method{handle()} method. You +can then run various versions of the service by combining one of the server +classes with your request handler class. The request handler class must be +different for datagram or stream services. This can be hidden by using the +handler subclasses \class{StreamRequestHandler} or \class{DatagramRequestHandler}. + +Of course, you still have to use your head! For instance, it makes no sense +to use a forking server if the service contains state in memory that can be +modified by different requests, since the modifications in the child process +would never reach the initial state kept in the parent process and passed to +each child. In this case, you can use a threading server, but you will +probably have to use locks to protect the integrity of the shared data. + +On the other hand, if you are building an HTTP server where all data is +stored externally (for instance, in the file system), a synchronous class +will essentially render the service "deaf" while one request is being +handled -- which may be for a very long time if a client is slow to receive +all the data it has requested. Here a threading or forking server is +appropriate. + +In some cases, it may be appropriate to process part of a request +synchronously, but to finish processing in a forked child depending on the +request data. This can be implemented by using a synchronous server and +doing an explicit fork in the request handler class \method{handle()} +method. + +Another approach to handling multiple simultaneous requests in an +environment that supports neither threads nor \function{fork()} (or where +these are too expensive or inappropriate for the service) is to maintain an +explicit table of partially finished requests and to use \function{select()} +to decide which request to work on next (or whether to handle a new incoming +request). This is particularly important for stream services where each +client can potentially be connected for a long time (if threads or +subprocesses cannot be used). + +%XXX should data and methods be intermingled, or separate? +% how should the distinction between class and instance variables be +% drawn? + +\subsection{Server Objects} + +\begin{funcdesc}{fileno}{} +Return an integer file descriptor for the socket on which the server +is listening. This function is most commonly passed to +\function{select.select()}, to allow monitoring multiple servers in the +same process. +\end{funcdesc} + +\begin{funcdesc}{handle_request}{} +Process a single request. This function calls the following methods +in order: \method{get_request()}, \method{verify_request()}, and +\method{process_request()}. If the user-provided \method{handle()} +method of the handler class raises an exception, the server's +\method{handle_error()} method will be called. +\end{funcdesc} + +\begin{funcdesc}{serve_forever}{} +Handle an infinite number of requests. This simply calls +\method{handle_request()} inside an infinite loop. +\end{funcdesc} + +\begin{datadesc}{address_family} +The family of protocols to which the server's socket belongs. +\constant{socket.AF_INET} and \constant{socket.AF_UNIX} are two +possible values. +\end{datadesc} + +\begin{datadesc}{RequestHandlerClass} +The user-provided request handler class; an instance of this class is +created for each request. +\end{datadesc} + +\begin{datadesc}{server_address} +The address on which the server is listening. The format of addresses +varies depending on the protocol family; see the documentation for the +socket module for details. For Internet protocols, this is a tuple +containing a string giving the address, and an integer port number: +\code{('127.0.0.1', 80)}, for example. +\end{datadesc} + +\begin{datadesc}{socket} +The socket object on which the server will listen for incoming requests. +\end{datadesc} + +% XXX should class variables be covered before instance variables, or +% vice versa? + +The server classes support the following class variables: + +\begin{datadesc}{allow_reuse_address} +Whether the server will allow the reuse of an address. This defaults +to \constant{False}, and can be set in subclasses to change the policy. +\end{datadesc} + +\begin{datadesc}{request_queue_size} +The size of the request queue. If it takes a long time to process a +single request, any requests that arrive while the server is busy are +placed into a queue, up to \member{request_queue_size} requests. Once +the queue is full, further requests from clients will get a +``Connection denied'' error. The default value is usually 5, but this +can be overridden by subclasses. +\end{datadesc} + +\begin{datadesc}{socket_type} +The type of socket used by the server; \constant{socket.SOCK_STREAM} +and \constant{socket.SOCK_DGRAM} are two possible values. +\end{datadesc} + +There are various server methods that can be overridden by subclasses +of base server classes like \class{TCPServer}; these methods aren't +useful to external users of the server object. + +% should the default implementations of these be documented, or should +% it be assumed that the user will look at SocketServer.py? + +\begin{funcdesc}{finish_request}{} +Actually processes the request by instantiating +\member{RequestHandlerClass} and calling its \method{handle()} method. +\end{funcdesc} + +\begin{funcdesc}{get_request}{} +Must accept a request from the socket, and return a 2-tuple containing +the \emph{new} socket object to be used to communicate with the +client, and the client's address. +\end{funcdesc} + +\begin{funcdesc}{handle_error}{request, client_address} +This function is called if the \member{RequestHandlerClass}'s +\method{handle()} method raises an exception. The default action is +to print the traceback to standard output and continue handling +further requests. +\end{funcdesc} + +\begin{funcdesc}{process_request}{request, client_address} +Calls \method{finish_request()} to create an instance of the +\member{RequestHandlerClass}. If desired, this function can create a +new process or thread to handle the request; the \class{ForkingMixIn} +and \class{ThreadingMixIn} classes do this. +\end{funcdesc} + +% Is there any point in documenting the following two functions? +% What would the purpose of overriding them be: initializing server +% instance variables, adding new network families? + +\begin{funcdesc}{server_activate}{} +Called by the server's constructor to activate the server. The default +behavior just \method{listen}s to the server's socket. +May be overridden. +\end{funcdesc} + +\begin{funcdesc}{server_bind}{} +Called by the server's constructor to bind the socket to the desired +address. May be overridden. +\end{funcdesc} + +\begin{funcdesc}{verify_request}{request, client_address} +Must return a Boolean value; if the value is \constant{True}, the request will be +processed, and if it's \constant{False}, the request will be denied. +This function can be overridden to implement access controls for a server. +The default implementation always returns \constant{True}. +\end{funcdesc} + +\subsection{RequestHandler Objects} + +The request handler class must define a new \method{handle()} method, +and can override any of the following methods. A new instance is +created for each request. + +\begin{funcdesc}{finish}{} +Called after the \method{handle()} method to perform any clean-up +actions required. The default implementation does nothing. If +\method{setup()} or \method{handle()} raise an exception, this +function will not be called. +\end{funcdesc} + +\begin{funcdesc}{handle}{} +This function must do all the work required to service a request. +The default implementation does nothing. +Several instance attributes are available to it; the request is +available as \member{self.request}; the client address as +\member{self.client_address}; and the server instance as +\member{self.server}, in case it needs access to per-server +information. + +The type of \member{self.request} is different for datagram or stream +services. For stream services, \member{self.request} is a socket +object; for datagram services, \member{self.request} is a string. +However, this can be hidden by using the request handler subclasses +\class{StreamRequestHandler} or \class{DatagramRequestHandler}, which +override the \method{setup()} and \method{finish()} methods, and +provide \member{self.rfile} and \member{self.wfile} attributes. +\member{self.rfile} and \member{self.wfile} can be read or written, +respectively, to get the request data or return data to the client. +\end{funcdesc} + +\begin{funcdesc}{setup}{} +Called before the \method{handle()} method to perform any +initialization actions required. The default implementation does +nothing. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libsomeos.tex b/sys/src/cmd/python/Doc/lib/libsomeos.tex new file mode 100644 index 000000000..680c590d7 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsomeos.tex @@ -0,0 +1,10 @@ +\chapter{Optional Operating System Services} +\label{someos} + +The modules described in this chapter provide interfaces to operating +system features that are available on selected operating systems only. +The interfaces are generally modeled after the \UNIX{} or \C{} +interfaces but they are available on some other systems as well +(e.g. Windows or NT). Here's an overview: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/libspwd.tex b/sys/src/cmd/python/Doc/lib/libspwd.tex new file mode 100644 index 000000000..5f0e6f136 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libspwd.tex @@ -0,0 +1,48 @@ +\section{\module{spwd} --- + The shadow password database} + +\declaremodule{builtin}{spwd} + \platform{Unix} +\modulesynopsis{The shadow password database (\function{getspnam()} and friends).} +\versionadded{2.5} + +This module provides access to the \UNIX{} shadow password database. +It is available on various \UNIX{} versions. + +You must have enough privileges to access the shadow password database +(this usually means you have to be root). + +Shadow password database entries are reported as a tuple-like object, whose +attributes correspond to the members of the \code{spwd} structure +(Attribute field below, see \code{<shadow.h>}): + +\begin{tableiii}{r|l|l}{textrm}{Index}{Attribute}{Meaning} + \lineiii{0}{\code{sp_nam}}{Login name} + \lineiii{1}{\code{sp_pwd}}{Encrypted password} + \lineiii{2}{\code{sp_lstchg}}{Date of last change} + \lineiii{3}{\code{sp_min}}{Minimal number of days between changes} + \lineiii{4}{\code{sp_max}}{Maximum number of days between changes} + \lineiii{5}{\code{sp_warn}}{Number of days before password expires to warn user about it} + \lineiii{6}{\code{sp_inact}}{Number of days after password expires until account is blocked} + \lineiii{7}{\code{sp_expire}}{Number of days since 1970-01-01 until account is disabled} + \lineiii{8}{\code{sp_flag}}{Reserved} +\end{tableiii} + +The sp_nam and sp_pwd items are strings, all others are integers. +\exception{KeyError} is raised if the entry asked for cannot be found. + +It defines the following items: + +\begin{funcdesc}{getspnam}{name} +Return the shadow password database entry for the given user name. +\end{funcdesc} + +\begin{funcdesc}{getspall}{} +Return a list of all available shadow password database entries, in arbitrary order. +\end{funcdesc} + + +\begin{seealso} + \seemodule{grp}{An interface to the group database, similar to this.} + \seemodule{pwd}{An interface to the normal password database, similar to this.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libsqlite3.tex b/sys/src/cmd/python/Doc/lib/libsqlite3.tex new file mode 100644 index 000000000..46e980025 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsqlite3.tex @@ -0,0 +1,642 @@ +\section{\module{sqlite3} --- + DB-API 2.0 interface for SQLite databases} + +\declaremodule{builtin}{sqlite3} +\modulesynopsis{A DB-API 2.0 implementation using SQLite 3.x.} +\sectionauthor{Gerhard Häring}{gh@ghaering.de} +\versionadded{2.5} + +SQLite is a C library that provides a lightweight disk-based database +that doesn't require a separate server process and allows accessing +the database using a nonstandard variant of the SQL query language. +Some applications can use SQLite for internal data storage. It's also +possible to prototype an application using SQLite and then port the +code to a larger database such as PostgreSQL or Oracle. + +pysqlite was written by Gerhard H\"aring and provides a SQL interface +compliant with the DB-API 2.0 specification described by +\pep{249}. + +To use the module, you must first create a \class{Connection} object +that represents the database. Here the data will be stored in the +\file{/tmp/example} file: + +\begin{verbatim} +conn = sqlite3.connect('/tmp/example') +\end{verbatim} + +You can also supply the special name \samp{:memory:} to create +a database in RAM. + +Once you have a \class{Connection}, you can create a \class{Cursor} +object and call its \method{execute()} method to perform SQL commands: + +\begin{verbatim} +c = conn.cursor() + +# Create table +c.execute('''create table stocks +(date text, trans text, symbol text, + qty real, price real)''') + +# Insert a row of data +c.execute("""insert into stocks + values ('2006-01-05','BUY','RHAT',100,35.14)""") +\end{verbatim} + +Usually your SQL operations will need to use values from Python +variables. You shouldn't assemble your query using Python's string +operations because doing so is insecure; it makes your program +vulnerable to an SQL injection attack. + +Instead, use the DB-API's parameter substitution. Put \samp{?} as a +placeholder wherever you want to use a value, and then provide a tuple +of values as the second argument to the cursor's \method{execute()} +method. (Other database modules may use a different placeholder, +such as \samp{\%s} or \samp{:1}.) For example: + +\begin{verbatim} +# Never do this -- insecure! +symbol = 'IBM' +c.execute("... where symbol = '%s'" % symbol) + +# Do this instead +t = (symbol,) +c.execute('select * from stocks where symbol=?', t) + +# Larger example +for t in (('2006-03-28', 'BUY', 'IBM', 1000, 45.00), + ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00), + ('2006-04-06', 'SELL', 'IBM', 500, 53.00), + ): + c.execute('insert into stocks values (?,?,?,?,?)', t) +\end{verbatim} + +To retrieve data after executing a SELECT statement, you can either +treat the cursor as an iterator, call the cursor's \method{fetchone()} +method to retrieve a single matching row, +or call \method{fetchall()} to get a list of the matching rows. + +This example uses the iterator form: + +\begin{verbatim} +>>> c = conn.cursor() +>>> c.execute('select * from stocks order by price') +>>> for row in c: +... print row +... +(u'2006-01-05', u'BUY', u'RHAT', 100, 35.140000000000001) +(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0) +(u'2006-04-06', u'SELL', u'IBM', 500, 53.0) +(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0) +>>> +\end{verbatim} + +\begin{seealso} + +\seeurl{http://www.pysqlite.org} +{The pysqlite web page.} + +\seeurl{http://www.sqlite.org} +{The SQLite web page; the documentation describes the syntax and the +available data types for the supported SQL dialect.} + +\seepep{249}{Database API Specification 2.0}{PEP written by +Marc-Andr\'e Lemburg.} + +\end{seealso} + + +\subsection{Module functions and constants\label{sqlite3-Module-Contents}} + +\begin{datadesc}{PARSE_DECLTYPES} +This constant is meant to be used with the \var{detect_types} parameter of the +\function{connect} function. + +Setting it makes the \module{sqlite3} module parse the declared type for each column it +returns. It will parse out the first word of the declared type, i. e. for +"integer primary key", it will parse out "integer". Then for that column, it +will look into the converters dictionary and use the converter function +registered for that type there. Converter names are case-sensitive! +\end{datadesc} + + +\begin{datadesc}{PARSE_COLNAMES} +This constant is meant to be used with the \var{detect_types} parameter of the +\function{connect} function. + +Setting this makes the SQLite interface parse the column name for each column +it returns. It will look for a string formed [mytype] in there, and then +decide that 'mytype' is the type of the column. It will try to find an entry of +'mytype' in the converters dictionary and then use the converter function found +there to return the value. The column name found in \member{cursor.description} is only +the first word of the column name, i. e. if you use something like +\code{'as "x [datetime]"'} in your SQL, then we will parse out everything until the +first blank for the column name: the column name would simply be "x". +\end{datadesc} + +\begin{funcdesc}{connect}{database\optional{, timeout, isolation_level, detect_types, factory}} +Opens a connection to the SQLite database file \var{database}. You can use +\code{":memory:"} to open a database connection to a database that resides in +RAM instead of on disk. + +When a database is accessed by multiple connections, and one of the processes +modifies the database, the SQLite database is locked until that transaction is +committed. The \var{timeout} parameter specifies how long the connection should +wait for the lock to go away until raising an exception. The default for the +timeout parameter is 5.0 (five seconds). + +For the \var{isolation_level} parameter, please see the \member{isolation_level} +property of \class{Connection} objects in section~\ref{sqlite3-Connection-IsolationLevel}. + +SQLite natively supports only the types TEXT, INTEGER, FLOAT, BLOB and NULL. If +you want to use other types, like you have to add support for them yourself. +The \var{detect_types} parameter and the using custom \strong{converters} registered with +the module-level \function{register_converter} function allow you to easily do that. + +\var{detect_types} defaults to 0 (i. e. off, no type detection), you can set it +to any combination of \constant{PARSE_DECLTYPES} and \constant{PARSE_COLNAMES} to turn type +detection on. + +By default, the \module{sqlite3} module uses its \class{Connection} class for the +connect call. You can, however, subclass the \class{Connection} class and make +\function{connect} use your class instead by providing your class for the +\var{factory} parameter. + +Consult the section \ref{sqlite3-Types} of this manual for details. + +The \module{sqlite3} module internally uses a statement cache to avoid SQL parsing +overhead. If you want to explicitly set the number of statements that are +cached for the connection, you can set the \var{cached_statements} parameter. +The currently implemented default is to cache 100 statements. +\end{funcdesc} + +\begin{funcdesc}{register_converter}{typename, callable} +Registers a callable to convert a bytestring from the database into a custom +Python type. The callable will be invoked for all database values that are of +the type \var{typename}. Confer the parameter \var{detect_types} of the +\function{connect} function for how the type detection works. Note that the case of +\var{typename} and the name of the type in your query must match! +\end{funcdesc} + +\begin{funcdesc}{register_adapter}{type, callable} +Registers a callable to convert the custom Python type \var{type} into one of +SQLite's supported types. The callable \var{callable} accepts as single +parameter the Python value, and must return a value of the following types: +int, long, float, str (UTF-8 encoded), unicode or buffer. +\end{funcdesc} + +\begin{funcdesc}{complete_statement}{sql} +Returns \constant{True} if the string \var{sql} contains one or more complete SQL +statements terminated by semicolons. It does not verify that the SQL is +syntactically correct, only that there are no unclosed string literals and the +statement is terminated by a semicolon. + +This can be used to build a shell for SQLite, as in the following example: + + \verbatiminput{sqlite3/complete_statement.py} +\end{funcdesc} + +\begin{funcdesc}{enable_callback_tracebacks}{flag} +By default you will not get any tracebacks in user-defined functions, +aggregates, converters, authorizer callbacks etc. If you want to debug them, +you can call this function with \var{flag} as True. Afterwards, you will get +tracebacks from callbacks on \code{sys.stderr}. Use \constant{False} to disable +the feature again. +\end{funcdesc} + +\subsection{Connection Objects \label{sqlite3-Connection-Objects}} + +A \class{Connection} instance has the following attributes and methods: + +\label{sqlite3-Connection-IsolationLevel} +\begin{memberdesc}{isolation_level} + Get or set the current isolation level. None for autocommit mode or one of + "DEFERRED", "IMMEDIATE" or "EXLUSIVE". See ``Controlling Transactions'', + section~\ref{sqlite3-Controlling-Transactions}, for a more detailed explanation. +\end{memberdesc} + +\begin{methoddesc}{cursor}{\optional{cursorClass}} + The cursor method accepts a single optional parameter \var{cursorClass}. + If supplied, this must be a custom cursor class that extends + \class{sqlite3.Cursor}. +\end{methoddesc} + +\begin{methoddesc}{execute}{sql, \optional{parameters}} +This is a nonstandard shortcut that creates an intermediate cursor object by +calling the cursor method, then calls the cursor's \method{execute} method with the +parameters given. +\end{methoddesc} + +\begin{methoddesc}{executemany}{sql, \optional{parameters}} +This is a nonstandard shortcut that creates an intermediate cursor object by +calling the cursor method, then calls the cursor's \method{executemany} method with the +parameters given. +\end{methoddesc} + +\begin{methoddesc}{executescript}{sql_script} +This is a nonstandard shortcut that creates an intermediate cursor object by +calling the cursor method, then calls the cursor's \method{executescript} method with the +parameters given. +\end{methoddesc} + +\begin{methoddesc}{create_function}{name, num_params, func} + +Creates a user-defined function that you can later use from within SQL +statements under the function name \var{name}. \var{num_params} is the number +of parameters the function accepts, and \var{func} is a Python callable that is +called as the SQL function. + +The function can return any of the types supported by SQLite: unicode, str, +int, long, float, buffer and None. + +Example: + + \verbatiminput{sqlite3/md5func.py} +\end{methoddesc} + +\begin{methoddesc}{create_aggregate}{name, num_params, aggregate_class} + +Creates a user-defined aggregate function. + +The aggregate class must implement a \code{step} method, which accepts the +number of parameters \var{num_params}, and a \code{finalize} method which +will return the final result of the aggregate. + +The \code{finalize} method can return any of the types supported by SQLite: +unicode, str, int, long, float, buffer and None. + +Example: + + \verbatiminput{sqlite3/mysumaggr.py} +\end{methoddesc} + +\begin{methoddesc}{create_collation}{name, callable} + +Creates a collation with the specified \var{name} and \var{callable}. The +callable will be passed two string arguments. It should return -1 if the first +is ordered lower than the second, 0 if they are ordered equal and 1 if the +first is ordered higher than the second. Note that this controls sorting +(ORDER BY in SQL) so your comparisons don't affect other SQL operations. + +Note that the callable will get its parameters as Python bytestrings, which +will normally be encoded in UTF-8. + +The following example shows a custom collation that sorts "the wrong way": + + \verbatiminput{sqlite3/collation_reverse.py} + +To remove a collation, call \code{create_collation} with None as callable: + +\begin{verbatim} + con.create_collation("reverse", None) +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}{interrupt}{} + +You can call this method from a different thread to abort any queries that +might be executing on the connection. The query will then abort and the caller +will get an exception. +\end{methoddesc} + +\begin{methoddesc}{set_authorizer}{authorizer_callback} + +This routine registers a callback. The callback is invoked for each attempt to +access a column of a table in the database. The callback should return +\constant{SQLITE_OK} if access is allowed, \constant{SQLITE_DENY} if the entire +SQL statement should be aborted with an error and \constant{SQLITE_IGNORE} if +the column should be treated as a NULL value. These constants are available in +the \module{sqlite3} module. + +The first argument to the callback signifies what kind of operation is to be +authorized. The second and third argument will be arguments or \constant{None} +depending on the first argument. The 4th argument is the name of the database +("main", "temp", etc.) if applicable. The 5th argument is the name of the +inner-most trigger or view that is responsible for the access attempt or +\constant{None} if this access attempt is directly from input SQL code. + +Please consult the SQLite documentation about the possible values for the first +argument and the meaning of the second and third argument depending on the +first one. All necessary constants are available in the \module{sqlite3} +module. +\end{methoddesc} + +\begin{memberdesc}{row_factory} + You can change this attribute to a callable that accepts the cursor and + the original row as a tuple and will return the real result row. This + way, you can implement more advanced ways of returning results, such + as returning an object that can also access columns by name. + + Example: + + \verbatiminput{sqlite3/row_factory.py} + + If returning a tuple doesn't suffice and you want name-based + access to columns, you should consider setting \member{row_factory} to the + highly-optimized \class{sqlite3.Row} type. \class{Row} provides both + index-based and case-insensitive name-based access to columns with almost + no memory overhead. It will probably be better than your own custom + dictionary-based approach or even a db_row based solution. + % XXX what's a db_row-based solution? +\end{memberdesc} + +\begin{memberdesc}{text_factory} + Using this attribute you can control what objects are returned for the + TEXT data type. By default, this attribute is set to \class{unicode} and + the \module{sqlite3} module will return Unicode objects for TEXT. If you want to return + bytestrings instead, you can set it to \class{str}. + + For efficiency reasons, there's also a way to return Unicode objects only + for non-ASCII data, and bytestrings otherwise. To activate it, set this + attribute to \constant{sqlite3.OptimizedUnicode}. + + You can also set it to any other callable that accepts a single bytestring + parameter and returns the resulting object. + + See the following example code for illustration: + + \verbatiminput{sqlite3/text_factory.py} +\end{memberdesc} + +\begin{memberdesc}{total_changes} + Returns the total number of database rows that have been modified, inserted, + or deleted since the database connection was opened. +\end{memberdesc} + + + + + +\subsection{Cursor Objects \label{sqlite3-Cursor-Objects}} + +A \class{Cursor} instance has the following attributes and methods: + +\begin{methoddesc}{execute}{sql, \optional{parameters}} + +Executes a SQL statement. The SQL statement may be parametrized (i. e. +placeholders instead of SQL literals). The \module{sqlite3} module supports two kinds of +placeholders: question marks (qmark style) and named placeholders (named +style). + +This example shows how to use parameters with qmark style: + + \verbatiminput{sqlite3/execute_1.py} + +This example shows how to use the named style: + + \verbatiminput{sqlite3/execute_2.py} + + \method{execute()} will only execute a single SQL statement. If you try to + execute more than one statement with it, it will raise a Warning. Use + \method{executescript()} if you want to execute multiple SQL statements with one + call. +\end{methoddesc} + + +\begin{methoddesc}{executemany}{sql, seq_of_parameters} +Executes a SQL command against all parameter sequences or mappings found in the +sequence \var{sql}. The \module{sqlite3} module also allows +using an iterator yielding parameters instead of a sequence. + +\verbatiminput{sqlite3/executemany_1.py} + +Here's a shorter example using a generator: + +\verbatiminput{sqlite3/executemany_2.py} +\end{methoddesc} + +\begin{methoddesc}{executescript}{sql_script} + +This is a nonstandard convenience method for executing multiple SQL statements +at once. It issues a COMMIT statement first, then executes the SQL script it +gets as a parameter. + +\var{sql_script} can be a bytestring or a Unicode string. + +Example: + +\verbatiminput{sqlite3/executescript.py} +\end{methoddesc} + +\begin{memberdesc}{rowcount} + Although the \class{Cursor} class of the \module{sqlite3} module implements this + attribute, the database engine's own support for the determination of "rows + affected"/"rows selected" is quirky. + + For \code{SELECT} statements, \member{rowcount} is always None because we cannot + determine the number of rows a query produced until all rows were fetched. + + For \code{DELETE} statements, SQLite reports \member{rowcount} as 0 if you make a + \code{DELETE FROM table} without any condition. + + For \method{executemany} statements, the number of modifications are summed + up into \member{rowcount}. + + As required by the Python DB API Spec, the \member{rowcount} attribute "is -1 + in case no executeXX() has been performed on the cursor or the rowcount + of the last operation is not determinable by the interface". +\end{memberdesc} + +\subsection{SQLite and Python types\label{sqlite3-Types}} + +\subsubsection{Introduction} + +SQLite natively supports the following types: NULL, INTEGER, REAL, TEXT, BLOB. + +The following Python types can thus be sent to SQLite without any problem: + +\begin{tableii} {c|l}{code}{Python type}{SQLite type} +\lineii{None}{NULL} +\lineii{int}{INTEGER} +\lineii{long}{INTEGER} +\lineii{float}{REAL} +\lineii{str (UTF8-encoded)}{TEXT} +\lineii{unicode}{TEXT} +\lineii{buffer}{BLOB} +\end{tableii} + +This is how SQLite types are converted to Python types by default: + +\begin{tableii} {c|l}{code}{SQLite type}{Python type} +\lineii{NULL}{None} +\lineii{INTEGER}{int or long, depending on size} +\lineii{REAL}{float} +\lineii{TEXT}{depends on text_factory, unicode by default} +\lineii{BLOB}{buffer} +\end{tableii} + +The type system of the \module{sqlite3} module is extensible in two ways: you can store +additional Python types in a SQLite database via object adaptation, and you can +let the \module{sqlite3} module convert SQLite types to different Python types via +converters. + +\subsubsection{Using adapters to store additional Python types in SQLite databases} + +As described before, SQLite supports only a limited set of types natively. To +use other Python types with SQLite, you must \strong{adapt} them to one of the sqlite3 +module's supported types for SQLite: one of NoneType, int, long, float, +str, unicode, buffer. + +The \module{sqlite3} module uses Python object adaptation, as described in \pep{246} for this. The protocol to use is \class{PrepareProtocol}. + +There are two ways to enable the \module{sqlite3} module to adapt a custom Python type +to one of the supported ones. + +\paragraph{Letting your object adapt itself} + +This is a good approach if you write the class yourself. Let's suppose you have +a class like this: + +\begin{verbatim} +class Point(object): + def __init__(self, x, y): + self.x, self.y = x, y +\end{verbatim} + +Now you want to store the point in a single SQLite column. First you'll have to +choose one of the supported types first to be used for representing the point. +Let's just use str and separate the coordinates using a semicolon. Then you +need to give your class a method \code{__conform__(self, protocol)} which must +return the converted value. The parameter \var{protocol} will be +\class{PrepareProtocol}. + +\verbatiminput{sqlite3/adapter_point_1.py} + +\paragraph{Registering an adapter callable} + +The other possibility is to create a function that converts the type to the +string representation and register the function with \method{register_adapter}. + +\begin{notice} +The type/class to adapt must be a new-style class, i. e. it must have +\class{object} as one of its bases. +\end{notice} + + \verbatiminput{sqlite3/adapter_point_2.py} + +The \module{sqlite3} module has two default adapters for Python's built-in +\class{datetime.date} and \class{datetime.datetime} types. Now let's suppose +we want to store \class{datetime.datetime} objects not in ISO representation, +but as a \UNIX{} timestamp. + + \verbatiminput{sqlite3/adapter_datetime.py} + +\subsubsection{Converting SQLite values to custom Python types} + +Writing an adapter lets you send custom Python types to SQLite. +But to make it really useful we need to make the Python to SQLite to Python +roundtrip work. + +Enter converters. + +Let's go back to the \class{Point} class. We stored the x and y +coordinates separated via semicolons as strings in SQLite. + +First, we'll define a converter function that accepts the string as a +parameter and constructs a \class{Point} object from it. + +\begin{notice} +Converter functions \strong{always} get called with a string, no matter +under which data type you sent the value to SQLite. +\end{notice} + +\begin{notice} +Converter names are looked up in a case-sensitive manner. +\end{notice} + + +\begin{verbatim} + def convert_point(s): + x, y = map(float, s.split(";")) + return Point(x, y) +\end{verbatim} + +Now you need to make the \module{sqlite3} module know that what you select from the +database is actually a point. There are two ways of doing this: + +\begin{itemize} + \item Implicitly via the declared type + \item Explicitly via the column name +\end{itemize} + +Both ways are described in ``Module Constants'', section~\ref{sqlite3-Module-Contents}, in +the entries for the constants \constant{PARSE_DECLTYPES} and +\constant{PARSE_COLNAMES}. + + +The following example illustrates both approaches. + + \verbatiminput{sqlite3/converter_point.py} + +\subsubsection{Default adapters and converters} + +There are default adapters for the date and datetime types in the datetime +module. They will be sent as ISO dates/ISO timestamps to SQLite. + +The default converters are registered under the name "date" for \class{datetime.date} +and under the name "timestamp" for \class{datetime.datetime}. + +This way, you can use date/timestamps from Python without any additional +fiddling in most cases. The format of the adapters is also compatible with the +experimental SQLite date/time functions. + +The following example demonstrates this. + + \verbatiminput{sqlite3/pysqlite_datetime.py} + +\subsection{Controlling Transactions \label{sqlite3-Controlling-Transactions}} + +By default, the \module{sqlite3} module opens transactions implicitly before a Data Modification Language (DML) +statement (i.e. INSERT/UPDATE/DELETE/REPLACE), and commits transactions implicitly +before a non-DML, non-query statement (i. e. anything other than +SELECT/INSERT/UPDATE/DELETE/REPLACE). + +So if you are within a transaction and issue a command like \code{CREATE TABLE +...}, \code{VACUUM}, \code{PRAGMA}, the \module{sqlite3} module will commit implicitly +before executing that command. There are two reasons for doing that. The first +is that some of these commands don't work within transactions. The other reason +is that pysqlite needs to keep track of the transaction state (if a transaction +is active or not). + +You can control which kind of "BEGIN" statements pysqlite implicitly executes +(or none at all) via the \var{isolation_level} parameter to the +\function{connect} call, or via the \member{isolation_level} property of +connections. + +If you want \strong{autocommit mode}, then set \member{isolation_level} to None. + +Otherwise leave it at its default, which will result in a plain "BEGIN" +statement, or set it to one of SQLite's supported isolation levels: DEFERRED, +IMMEDIATE or EXCLUSIVE. + +As the \module{sqlite3} module needs to keep track of the transaction state, you should +not use \code{OR ROLLBACK} or \code{ON CONFLICT ROLLBACK} in your SQL. Instead, +catch the \exception{IntegrityError} and call the \method{rollback} method of +the connection yourself. + +\subsection{Using pysqlite efficiently} + +\subsubsection{Using shortcut methods} + +Using the nonstandard \method{execute}, \method{executemany} and +\method{executescript} methods of the \class{Connection} object, your code can +be written more concisely because you don't have to create the (often +superfluous) \class{Cursor} objects explicitly. Instead, the \class{Cursor} +objects are created implicitly and these shortcut methods return the cursor +objects. This way, you can execute a SELECT statement and iterate +over it directly using only a single call on the \class{Connection} object. + + \verbatiminput{sqlite3/shortcut_methods.py} + +\subsubsection{Accessing columns by name instead of by index} + +One useful feature of the \module{sqlite3} module is the builtin \class{sqlite3.Row} class +designed to be used as a row factory. + +Rows wrapped with this class can be accessed both by index (like tuples) and +case-insensitively by name: + + \verbatiminput{sqlite3/rowclass.py} + + diff --git a/sys/src/cmd/python/Doc/lib/libstat.tex b/sys/src/cmd/python/Doc/lib/libstat.tex new file mode 100644 index 000000000..d5353f1d1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstat.tex @@ -0,0 +1,157 @@ +\section{\module{stat} --- + Interpreting \function{stat()} results} + +\declaremodule{standard}{stat} +\modulesynopsis{Utilities for interpreting the results of + \function{os.stat()}, \function{os.lstat()} and \function{os.fstat()}.} +\sectionauthor{Skip Montanaro}{skip@automatrix.com} + + +The \module{stat} module defines constants and functions for +interpreting the results of \function{os.stat()}, +\function{os.fstat()} and \function{os.lstat()} (if they exist). For +complete details about the \cfunction{stat()}, \cfunction{fstat()} and +\cfunction{lstat()} calls, consult the documentation for your system. + +The \module{stat} module defines the following functions to test for +specific file types: + + +\begin{funcdesc}{S_ISDIR}{mode} +Return non-zero if the mode is from a directory. +\end{funcdesc} + +\begin{funcdesc}{S_ISCHR}{mode} +Return non-zero if the mode is from a character special device file. +\end{funcdesc} + +\begin{funcdesc}{S_ISBLK}{mode} +Return non-zero if the mode is from a block special device file. +\end{funcdesc} + +\begin{funcdesc}{S_ISREG}{mode} +Return non-zero if the mode is from a regular file. +\end{funcdesc} + +\begin{funcdesc}{S_ISFIFO}{mode} +Return non-zero if the mode is from a FIFO (named pipe). +\end{funcdesc} + +\begin{funcdesc}{S_ISLNK}{mode} +Return non-zero if the mode is from a symbolic link. +\end{funcdesc} + +\begin{funcdesc}{S_ISSOCK}{mode} +Return non-zero if the mode is from a socket. +\end{funcdesc} + +Two additional functions are defined for more general manipulation of +the file's mode: + +\begin{funcdesc}{S_IMODE}{mode} +Return the portion of the file's mode that can be set by +\function{os.chmod()}---that is, the file's permission bits, plus the +sticky bit, set-group-id, and set-user-id bits (on systems that support +them). +\end{funcdesc} + +\begin{funcdesc}{S_IFMT}{mode} +Return the portion of the file's mode that describes the file type (used +by the \function{S_IS*()} functions above). +\end{funcdesc} + +Normally, you would use the \function{os.path.is*()} functions for +testing the type of a file; the functions here are useful when you are +doing multiple tests of the same file and wish to avoid the overhead of +the \cfunction{stat()} system call for each test. These are also +useful when checking for information about a file that isn't handled +by \refmodule{os.path}, like the tests for block and character +devices. + +All the variables below are simply symbolic indexes into the 10-tuple +returned by \function{os.stat()}, \function{os.fstat()} or +\function{os.lstat()}. + +\begin{datadesc}{ST_MODE} +Inode protection mode. +\end{datadesc} + +\begin{datadesc}{ST_INO} +Inode number. +\end{datadesc} + +\begin{datadesc}{ST_DEV} +Device inode resides on. +\end{datadesc} + +\begin{datadesc}{ST_NLINK} +Number of links to the inode. +\end{datadesc} + +\begin{datadesc}{ST_UID} +User id of the owner. +\end{datadesc} + +\begin{datadesc}{ST_GID} +Group id of the owner. +\end{datadesc} + +\begin{datadesc}{ST_SIZE} +Size in bytes of a plain file; amount of data waiting on some special +files. +\end{datadesc} + +\begin{datadesc}{ST_ATIME} +Time of last access. +\end{datadesc} + +\begin{datadesc}{ST_MTIME} +Time of last modification. +\end{datadesc} + +\begin{datadesc}{ST_CTIME} +The ``ctime'' as reported by the operating system. On some systems +(like \UNIX) is the time of the last metadata change, and, on others +(like Windows), is the creation time (see platform documentation for +details). +\end{datadesc} + +The interpretation of ``file size'' changes according to the file +type. For plain files this is the size of the file in bytes. For +FIFOs and sockets under most flavors of \UNIX{} (including Linux in +particular), the ``size'' is the number of bytes waiting to be read at +the time of the call to \function{os.stat()}, \function{os.fstat()}, +or \function{os.lstat()}; this can sometimes be useful, especially for +polling one of these special files after a non-blocking open. The +meaning of the size field for other character and block devices varies +more, depending on the implementation of the underlying system call. + +Example: + +\begin{verbatim} +import os, sys +from stat import * + +def walktree(top, callback): + '''recursively descend the directory tree rooted at top, + calling the callback function for each regular file''' + + for f in os.listdir(top): + pathname = os.path.join(top, f) + mode = os.stat(pathname)[ST_MODE] + if S_ISDIR(mode): + # It's a directory, recurse into it + walktree(pathname, callback) + elif S_ISREG(mode): + # It's a file, call the callback function + callback(pathname) + else: + # Unknown file type, print a message + print 'Skipping %s' % pathname + +def visitfile(file): + print 'visiting', file + +if __name__ == '__main__': + walktree(sys.argv[1], visitfile) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libstatvfs.tex b/sys/src/cmd/python/Doc/lib/libstatvfs.tex new file mode 100644 index 000000000..2dc89333b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstatvfs.tex @@ -0,0 +1,55 @@ +\section{\module{statvfs} --- + Constants used with \function{os.statvfs()}} + +\declaremodule{standard}{statvfs} +% LaTeX'ed from comments in module +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Constants for interpreting the result of + \function{os.statvfs()}.} + +The \module{statvfs} module defines constants so interpreting the result +if \function{os.statvfs()}, which returns a tuple, can be made without +remembering ``magic numbers.'' Each of the constants defined in this +module is the \emph{index} of the entry in the tuple returned by +\function{os.statvfs()} that contains the specified information. + + +\begin{datadesc}{F_BSIZE} +Preferred file system block size. +\end{datadesc} + +\begin{datadesc}{F_FRSIZE} +Fundamental file system block size. +\end{datadesc} + +\begin{datadesc}{F_BLOCKS} +Total number of blocks in the filesystem. +\end{datadesc} + +\begin{datadesc}{F_BFREE} +Total number of free blocks. +\end{datadesc} + +\begin{datadesc}{F_BAVAIL} +Free blocks available to non-super user. +\end{datadesc} + +\begin{datadesc}{F_FILES} +Total number of file nodes. +\end{datadesc} + +\begin{datadesc}{F_FFREE} +Total number of free file nodes. +\end{datadesc} + +\begin{datadesc}{F_FAVAIL} +Free nodes available to non-super user. +\end{datadesc} + +\begin{datadesc}{F_FLAG} +Flags. System dependent: see \cfunction{statvfs()} man page. +\end{datadesc} + +\begin{datadesc}{F_NAMEMAX} +Maximum file name length. +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/libstdtypes.tex b/sys/src/cmd/python/Doc/lib/libstdtypes.tex new file mode 100644 index 000000000..2de7f617a --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstdtypes.tex @@ -0,0 +1,2095 @@ +\chapter{Built-in Types \label{types}} + +The following sections describe the standard types that are built into +the interpreter. +\note{Historically (until release 2.2), Python's built-in types have +differed from user-defined types because it was not possible to use +the built-in types as the basis for object-oriented inheritance. +This limitation does not exist any longer.} + +The principal built-in types are numerics, sequences, mappings, files, +classes, instances and exceptions. +\indexii{built-in}{types} + +Some operations are supported by several object types; in particular, +practically all objects can be compared, tested for truth value, +and converted to a string (with +the \function{repr()} function or the slightly different +\function{str()} function). The latter +function is implicitly used when an object is written by the +\keyword{print}\stindex{print} statement. +(Information on the \ulink{\keyword{print} statement}{../ref/print.html} +and other language statements can be found in the +\citetitle[../ref/ref.html]{Python Reference Manual} and the +\citetitle[../tut/tut.html]{Python Tutorial}.) + + +\section{Truth Value Testing\label{truth}} + +Any object can be tested for truth value, for use in an \keyword{if} or +\keyword{while} condition or as operand of the Boolean operations below. +The following values are considered false: +\stindex{if} +\stindex{while} +\indexii{truth}{value} +\indexii{Boolean}{operations} +\index{false} + +\begin{itemize} + +\item \code{None} + \withsubitem{(Built-in object)}{\ttindex{None}} + +\item \code{False} + \withsubitem{(Built-in object)}{\ttindex{False}} + +\item zero of any numeric type, for example, \code{0}, \code{0L}, + \code{0.0}, \code{0j}. + +\item any empty sequence, for example, \code{''}, \code{()}, \code{[]}. + +\item any empty mapping, for example, \code{\{\}}. + +\item instances of user-defined classes, if the class defines a + \method{__nonzero__()} or \method{__len__()} method, when that + method returns the integer zero or \class{bool} value + \code{False}.\footnote{Additional +information on these special methods may be found in the +\citetitle[../ref/ref.html]{Python Reference Manual}.} + +\end{itemize} + +All other values are considered true --- so objects of many types are +always true. +\index{true} + +Operations and built-in functions that have a Boolean result always +return \code{0} or \code{False} for false and \code{1} or \code{True} +for true, unless otherwise stated. (Important exception: the Boolean +operations \samp{or}\opindex{or} and \samp{and}\opindex{and} always +return one of their operands.) +\index{False} +\index{True} + +\section{Boolean Operations --- + \keyword{and}, \keyword{or}, \keyword{not} + \label{boolean}} + +These are the Boolean operations, ordered by ascending priority: +\indexii{Boolean}{operations} + +\begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} + \lineiii{\var{x} or \var{y}} + {if \var{x} is false, then \var{y}, else \var{x}}{(1)} + \lineiii{\var{x} and \var{y}} + {if \var{x} is false, then \var{x}, else \var{y}}{(1)} + \hline + \lineiii{not \var{x}} + {if \var{x} is false, then \code{True}, else \code{False}}{(2)} +\end{tableiii} +\opindex{and} +\opindex{or} +\opindex{not} + +\noindent +Notes: + +\begin{description} + +\item[(1)] +These only evaluate their second argument if needed for their outcome. + +\item[(2)] +\samp{not} has a lower priority than non-Boolean operators, so +\code{not \var{a} == \var{b}} is interpreted as \code{not (\var{a} == +\var{b})}, and \code{\var{a} == not \var{b}} is a syntax error. + +\end{description} + + +\section{Comparisons \label{comparisons}} + +Comparison operations are supported by all objects. They all have the +same priority (which is higher than that of the Boolean operations). +Comparisons can be chained arbitrarily; for example, \code{\var{x} < +\var{y} <= \var{z}} is equivalent to \code{\var{x} < \var{y} and +\var{y} <= \var{z}}, except that \var{y} is evaluated only once (but +in both cases \var{z} is not evaluated at all when \code{\var{x} < +\var{y}} is found to be false). +\indexii{chaining}{comparisons} + +This table summarizes the comparison operations: + +\begin{tableiii}{c|l|c}{code}{Operation}{Meaning}{Notes} + \lineiii{<}{strictly less than}{} + \lineiii{<=}{less than or equal}{} + \lineiii{>}{strictly greater than}{} + \lineiii{>=}{greater than or equal}{} + \lineiii{==}{equal}{} + \lineiii{!=}{not equal}{(1)} + \lineiii{<>}{not equal}{(1)} + \lineiii{is}{object identity}{} + \lineiii{is not}{negated object identity}{} +\end{tableiii} +\indexii{operator}{comparison} +\opindex{==} % XXX *All* others have funny characters < ! > +\opindex{is} +\opindex{is not} + +\noindent +Notes: + +\begin{description} + +\item[(1)] +\code{<>} and \code{!=} are alternate spellings for the same operator. +\code{!=} is the preferred spelling; \code{<>} is obsolescent. + +\end{description} + +Objects of different types, except different numeric types and different string types, never +compare equal; such objects are ordered consistently but arbitrarily +(so that sorting a heterogeneous array yields a consistent result). +Furthermore, some types (for example, file objects) support only a +degenerate notion of comparison where any two objects of that type are +unequal. Again, such objects are ordered arbitrarily but +consistently. The \code{<}, \code{<=}, \code{>} and \code{>=} +operators will raise a \exception{TypeError} exception when any operand +is a complex number. +\indexii{object}{numeric} +\indexii{objects}{comparing} + +Instances of a class normally compare as non-equal unless the class +\withsubitem{(instance method)}{\ttindex{__cmp__()}} +defines the \method{__cmp__()} method. Refer to the +\citetitle[../ref/customization.html]{Python Reference Manual} for +information on the use of this method to effect object comparisons. + +\strong{Implementation note:} Objects of different types except +numbers are ordered by their type names; objects of the same types +that don't support proper comparison are ordered by their address. + +Two more operations with the same syntactic priority, +\samp{in}\opindex{in} and \samp{not in}\opindex{not in}, are supported +only by sequence types (below). + + +\section{Numeric Types --- + \class{int}, \class{float}, \class{long}, \class{complex} + \label{typesnumeric}} + +There are four distinct numeric types: \dfn{plain integers}, +\dfn{long integers}, +\dfn{floating point numbers}, and \dfn{complex numbers}. +In addition, Booleans are a subtype of plain integers. +Plain integers (also just called \dfn{integers}) +are implemented using \ctype{long} in C, which gives them at least 32 +bits of precision (\code{sys.maxint} is always set to the maximum +plain integer value for the current platform, the minimum value is +\code{-sys.maxint - 1}). Long integers have unlimited precision. +Floating point numbers are implemented using \ctype{double} in C. +All bets on their precision are off unless you happen to know the +machine you are working with. +\obindex{numeric} +\obindex{Boolean} +\obindex{integer} +\obindex{long integer} +\obindex{floating point} +\obindex{complex number} +\indexii{C}{language} + +Complex numbers have a real and imaginary part, which are each +implemented using \ctype{double} in C. To extract these parts from +a complex number \var{z}, use \code{\var{z}.real} and \code{\var{z}.imag}. + +Numbers are created by numeric literals or as the result of built-in +functions and operators. Unadorned integer literals (including hex +and octal numbers) yield plain integers unless the value they denote +is too large to be represented as a plain integer, in which case +they yield a long integer. Integer literals with an +\character{L} or \character{l} suffix yield long integers +(\character{L} is preferred because \samp{1l} looks too much like +eleven!). Numeric literals containing a decimal point or an exponent +sign yield floating point numbers. Appending \character{j} or +\character{J} to a numeric literal yields a complex number with a +zero real part. A complex numeric literal is the sum of a real and +an imaginary part. +\indexii{numeric}{literals} +\indexii{integer}{literals} +\indexiii{long}{integer}{literals} +\indexii{floating point}{literals} +\indexii{complex number}{literals} +\indexii{hexadecimal}{literals} +\indexii{octal}{literals} + +Python fully supports mixed arithmetic: when a binary arithmetic +operator has operands of different numeric types, the operand with the +``narrower'' type is widened to that of the other, where plain +integer is narrower than long integer is narrower than floating point is +narrower than complex. +Comparisons between numbers of mixed type use the same rule.\footnote{ + As a consequence, the list \code{[1, 2]} is considered equal + to \code{[1.0, 2.0]}, and similarly for tuples. +} The constructors \function{int()}, \function{long()}, \function{float()}, +and \function{complex()} can be used +to produce numbers of a specific type. +\index{arithmetic} +\bifuncindex{int} +\bifuncindex{long} +\bifuncindex{float} +\bifuncindex{complex} + +All numeric types (except complex) support the following operations, +sorted by ascending priority (operations in the same box have the same +priority; all numeric operations have a higher priority than +comparison operations): + +\begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} + \lineiii{\var{x} + \var{y}}{sum of \var{x} and \var{y}}{} + \lineiii{\var{x} - \var{y}}{difference of \var{x} and \var{y}}{} + \hline + \lineiii{\var{x} * \var{y}}{product of \var{x} and \var{y}}{} + \lineiii{\var{x} / \var{y}}{quotient of \var{x} and \var{y}}{(1)} + \lineiii{\var{x} // \var{y}}{(floored) quotient of \var{x} and \var{y}}{(5)} + \lineiii{\var{x} \%{} \var{y}}{remainder of \code{\var{x} / \var{y}}}{(4)} + \hline + \lineiii{-\var{x}}{\var{x} negated}{} + \lineiii{+\var{x}}{\var{x} unchanged}{} + \hline + \lineiii{abs(\var{x})}{absolute value or magnitude of \var{x}}{} + \lineiii{int(\var{x})}{\var{x} converted to integer}{(2)} + \lineiii{long(\var{x})}{\var{x} converted to long integer}{(2)} + \lineiii{float(\var{x})}{\var{x} converted to floating point}{} + \lineiii{complex(\var{re},\var{im})}{a complex number with real part \var{re}, imaginary part \var{im}. \var{im} defaults to zero.}{} + \lineiii{\var{c}.conjugate()}{conjugate of the complex number \var{c}}{} + \lineiii{divmod(\var{x}, \var{y})}{the pair \code{(\var{x} // \var{y}, \var{x} \%{} \var{y})}}{(3)(4)} + \lineiii{pow(\var{x}, \var{y})}{\var{x} to the power \var{y}}{} + \lineiii{\var{x} ** \var{y}}{\var{x} to the power \var{y}}{} +\end{tableiii} +\indexiii{operations on}{numeric}{types} +\withsubitem{(complex number method)}{\ttindex{conjugate()}} + +\noindent +Notes: +\begin{description} + +\item[(1)] +For (plain or long) integer division, the result is an integer. +The result is always rounded towards minus infinity: 1/2 is 0, +(-1)/2 is -1, 1/(-2) is -1, and (-1)/(-2) is 0. Note that the result +is a long integer if either operand is a long integer, regardless of +the numeric value. +\indexii{integer}{division} +\indexiii{long}{integer}{division} + +\item[(2)] +Conversion from floating point to (long or plain) integer may round or +truncate as in C; see functions \function{floor()} and +\function{ceil()} in the \refmodule{math}\refbimodindex{math} module +for well-defined conversions. +\withsubitem{(in module math)}{\ttindex{floor()}\ttindex{ceil()}} +\indexii{numeric}{conversions} +\indexii{C}{language} + +\item[(3)] +See section \ref{built-in-funcs}, ``Built-in Functions,'' for a full +description. + +\item[(4)] +Complex floor division operator, modulo operator, and \function{divmod()}. + +\deprecated{2.3}{Instead convert to float using \function{abs()} +if appropriate.} + +\item[(5)] +Also referred to as integer division. The resultant value is a whole integer, +though the result's type is not necessarily int. +\end{description} +% XXXJH exceptions: overflow (when? what operations?) zerodivision + +\subsection{Bit-string Operations on Integer Types \label{bitstring-ops}} +\nodename{Bit-string Operations} + +Plain and long integer types support additional operations that make +sense only for bit-strings. Negative numbers are treated as their 2's +complement value (for long integers, this assumes a sufficiently large +number of bits that no overflow occurs during the operation). + +The priorities of the binary bit-wise operations are all lower than +the numeric operations and higher than the comparisons; the unary +operation \samp{\~} has the same priority as the other unary numeric +operations (\samp{+} and \samp{-}). + +This table lists the bit-string operations sorted in ascending +priority (operations in the same box have the same priority): + +\begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} + \lineiii{\var{x} | \var{y}}{bitwise \dfn{or} of \var{x} and \var{y}}{} + \lineiii{\var{x} \^{} \var{y}}{bitwise \dfn{exclusive or} of \var{x} and \var{y}}{} + \lineiii{\var{x} \&{} \var{y}}{bitwise \dfn{and} of \var{x} and \var{y}}{} + % The empty groups below prevent conversion to guillemets. + \lineiii{\var{x} <{}< \var{n}}{\var{x} shifted left by \var{n} bits}{(1), (2)} + \lineiii{\var{x} >{}> \var{n}}{\var{x} shifted right by \var{n} bits}{(1), (3)} + \hline + \lineiii{\~\var{x}}{the bits of \var{x} inverted}{} +\end{tableiii} +\indexiii{operations on}{integer}{types} +\indexii{bit-string}{operations} +\indexii{shifting}{operations} +\indexii{masking}{operations} + +\noindent +Notes: +\begin{description} +\item[(1)] Negative shift counts are illegal and cause a +\exception{ValueError} to be raised. +\item[(2)] A left shift by \var{n} bits is equivalent to +multiplication by \code{pow(2, \var{n})} without overflow check. +\item[(3)] A right shift by \var{n} bits is equivalent to +division by \code{pow(2, \var{n})} without overflow check. +\end{description} + + +\section{Iterator Types \label{typeiter}} + +\versionadded{2.2} +\index{iterator protocol} +\index{protocol!iterator} +\index{sequence!iteration} +\index{container!iteration over} + +Python supports a concept of iteration over containers. This is +implemented using two distinct methods; these are used to allow +user-defined classes to support iteration. Sequences, described below +in more detail, always support the iteration methods. + +One method needs to be defined for container objects to provide +iteration support: + +\begin{methoddesc}[container]{__iter__}{} + Return an iterator object. The object is required to support the + iterator protocol described below. If a container supports + different types of iteration, additional methods can be provided to + specifically request iterators for those iteration types. (An + example of an object supporting multiple forms of iteration would be + a tree structure which supports both breadth-first and depth-first + traversal.) This method corresponds to the \member{tp_iter} slot of + the type structure for Python objects in the Python/C API. +\end{methoddesc} + +The iterator objects themselves are required to support the following +two methods, which together form the \dfn{iterator protocol}: + +\begin{methoddesc}[iterator]{__iter__}{} + Return the iterator object itself. This is required to allow both + containers and iterators to be used with the \keyword{for} and + \keyword{in} statements. This method corresponds to the + \member{tp_iter} slot of the type structure for Python objects in + the Python/C API. +\end{methoddesc} + +\begin{methoddesc}[iterator]{next}{} + Return the next item from the container. If there are no further + items, raise the \exception{StopIteration} exception. This method + corresponds to the \member{tp_iternext} slot of the type structure + for Python objects in the Python/C API. +\end{methoddesc} + +Python defines several iterator objects to support iteration over +general and specific sequence types, dictionaries, and other more +specialized forms. The specific types are not important beyond their +implementation of the iterator protocol. + +The intention of the protocol is that once an iterator's +\method{next()} method raises \exception{StopIteration}, it will +continue to do so on subsequent calls. Implementations that +do not obey this property are deemed broken. (This constraint +was added in Python 2.3; in Python 2.2, various iterators are +broken according to this rule.) + +Python's generators provide a convenient way to implement the +iterator protocol. If a container object's \method{__iter__()} +method is implemented as a generator, it will automatically +return an iterator object (technically, a generator object) +supplying the \method{__iter__()} and \method{next()} methods. + + +\section{Sequence Types --- + \class{str}, \class{unicode}, \class{list}, + \class{tuple}, \class{buffer}, \class{xrange} + \label{typesseq}} + +There are six sequence types: strings, Unicode strings, lists, +tuples, buffers, and xrange objects. + +String literals are written in single or double quotes: +\code{'xyzzy'}, \code{"frobozz"}. See chapter 2 of the +\citetitle[../ref/strings.html]{Python Reference Manual} for more about +string literals. Unicode strings are much like strings, but are +specified in the syntax using a preceding \character{u} character: +\code{u'abc'}, \code{u"def"}. Lists are constructed with square brackets, +separating items with commas: \code{[a, b, c]}. Tuples are +constructed by the comma operator (not within square brackets), with +or without enclosing parentheses, but an empty tuple must have the +enclosing parentheses, such as \code{a, b, c} or \code{()}. A single +item tuple must have a trailing comma, such as \code{(d,)}. +\obindex{sequence} +\obindex{string} +\obindex{Unicode} +\obindex{tuple} +\obindex{list} + +Buffer objects are not directly supported by Python syntax, but can be +created by calling the builtin function +\function{buffer()}.\bifuncindex{buffer} They don't support +concatenation or repetition. +\obindex{buffer} + +Xrange objects are similar to buffers in that there is no specific +syntax to create them, but they are created using the \function{xrange()} +function.\bifuncindex{xrange} They don't support slicing, +concatenation or repetition, and using \code{in}, \code{not in}, +\function{min()} or \function{max()} on them is inefficient. +\obindex{xrange} + +Most sequence types support the following operations. The \samp{in} and +\samp{not in} operations have the same priorities as the comparison +operations. The \samp{+} and \samp{*} operations have the same +priority as the corresponding numeric operations.\footnote{They must +have since the parser can't tell the type of the operands.} + +This table lists the sequence operations sorted in ascending priority +(operations in the same box have the same priority). In the table, +\var{s} and \var{t} are sequences of the same type; \var{n}, \var{i} +and \var{j} are integers: + +\begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} + \lineiii{\var{x} in \var{s}}{\code{True} if an item of \var{s} is equal to \var{x}, else \code{False}}{(1)} + \lineiii{\var{x} not in \var{s}}{\code{False} if an item of \var{s} is +equal to \var{x}, else \code{True}}{(1)} + \hline + \lineiii{\var{s} + \var{t}}{the concatenation of \var{s} and \var{t}}{(6)} + \lineiii{\var{s} * \var{n}\textrm{,} \var{n} * \var{s}}{\var{n} shallow copies of \var{s} concatenated}{(2)} + \hline + \lineiii{\var{s}[\var{i}]}{\var{i}'th item of \var{s}, origin 0}{(3)} + \lineiii{\var{s}[\var{i}:\var{j}]}{slice of \var{s} from \var{i} to \var{j}}{(3), (4)} + \lineiii{\var{s}[\var{i}:\var{j}:\var{k}]}{slice of \var{s} from \var{i} to \var{j} with step \var{k}}{(3), (5)} + \hline + \lineiii{len(\var{s})}{length of \var{s}}{} + \lineiii{min(\var{s})}{smallest item of \var{s}}{} + \lineiii{max(\var{s})}{largest item of \var{s}}{} +\end{tableiii} +\indexiii{operations on}{sequence}{types} +\bifuncindex{len} +\bifuncindex{min} +\bifuncindex{max} +\indexii{concatenation}{operation} +\indexii{repetition}{operation} +\indexii{subscript}{operation} +\indexii{slice}{operation} +\indexii{extended slice}{operation} +\opindex{in} +\opindex{not in} + +\noindent +Notes: + +\begin{description} +\item[(1)] When \var{s} is a string or Unicode string object the +\code{in} and \code{not in} operations act like a substring test. In +Python versions before 2.3, \var{x} had to be a string of length 1. +In Python 2.3 and beyond, \var{x} may be a string of any length. + +\item[(2)] Values of \var{n} less than \code{0} are treated as + \code{0} (which yields an empty sequence of the same type as + \var{s}). Note also that the copies are shallow; nested structures + are not copied. This often haunts new Python programmers; consider: + +\begin{verbatim} +>>> lists = [[]] * 3 +>>> lists +[[], [], []] +>>> lists[0].append(3) +>>> lists +[[3], [3], [3]] +\end{verbatim} + + What has happened is that \code{[[]]} is a one-element list containing + an empty list, so all three elements of \code{[[]] * 3} are (pointers to) + this single empty list. Modifying any of the elements of \code{lists} + modifies this single list. You can create a list of different lists this + way: + +\begin{verbatim} +>>> lists = [[] for i in range(3)] +>>> lists[0].append(3) +>>> lists[1].append(5) +>>> lists[2].append(7) +>>> lists +[[3], [5], [7]] +\end{verbatim} + +\item[(3)] If \var{i} or \var{j} is negative, the index is relative to + the end of the string: \code{len(\var{s}) + \var{i}} or + \code{len(\var{s}) + \var{j}} is substituted. But note that \code{-0} is + still \code{0}. + +\item[(4)] The slice of \var{s} from \var{i} to \var{j} is defined as + the sequence of items with index \var{k} such that \code{\var{i} <= + \var{k} < \var{j}}. If \var{i} or \var{j} is greater than + \code{len(\var{s})}, use \code{len(\var{s})}. If \var{i} is omitted + or \code{None}, use \code{0}. If \var{j} is omitted or \code{None}, + use \code{len(\var{s})}. If \var{i} is greater than or equal to \var{j}, + the slice is empty. + +\item[(5)] The slice of \var{s} from \var{i} to \var{j} with step + \var{k} is defined as the sequence of items with index + \code{\var{x} = \var{i} + \var{n}*\var{k}} such that + $0 \leq n < \frac{j-i}{k}$. In other words, the indices + are \code{i}, \code{i+k}, \code{i+2*k}, \code{i+3*k} and so on, stopping when + \var{j} is reached (but never including \var{j}). If \var{i} or \var{j} + is greater than \code{len(\var{s})}, use \code{len(\var{s})}. If + \var{i} or \var{j} are omitted or \code{None}, they become ``end'' values + (which end depends on the sign of \var{k}). Note, \var{k} cannot + be zero. If \var{k} is \code{None}, it is treated like \code{1}. + +\item[(6)] If \var{s} and \var{t} are both strings, some Python +implementations such as CPython can usually perform an in-place optimization +for assignments of the form \code{\var{s}=\var{s}+\var{t}} or +\code{\var{s}+=\var{t}}. When applicable, this optimization makes +quadratic run-time much less likely. This optimization is both version +and implementation dependent. For performance sensitive code, it is +preferable to use the \method{str.join()} method which assures consistent +linear concatenation performance across versions and implementations. +\versionchanged[Formerly, string concatenation never occurred in-place]{2.4} + +\end{description} + + +\subsection{String Methods \label{string-methods}} +\indexii{string}{methods} + +These are the string methods which both 8-bit strings and Unicode +objects support: + +\begin{methoddesc}[string]{capitalize}{} +Return a copy of the string with only its first character capitalized. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{center}{width\optional{, fillchar}} +Return centered in a string of length \var{width}. Padding is done +using the specified \var{fillchar} (default is a space). +\versionchanged[Support for the \var{fillchar} argument]{2.4} +\end{methoddesc} + +\begin{methoddesc}[string]{count}{sub\optional{, start\optional{, end}}} +Return the number of occurrences of substring \var{sub} in string +S\code{[\var{start}:\var{end}]}. Optional arguments \var{start} and +\var{end} are interpreted as in slice notation. +\end{methoddesc} + +\begin{methoddesc}[string]{decode}{\optional{encoding\optional{, errors}}} +Decodes the string using the codec registered for \var{encoding}. +\var{encoding} defaults to the default string encoding. \var{errors} +may be given to set a different error handling scheme. The default is +\code{'strict'}, meaning that encoding errors raise +\exception{UnicodeError}. Other possible values are \code{'ignore'}, +\code{'replace'} and any other name registered via +\function{codecs.register_error}, see section~\ref{codec-base-classes}. +\versionadded{2.2} +\versionchanged[Support for other error handling schemes added]{2.3} +\end{methoddesc} + +\begin{methoddesc}[string]{encode}{\optional{encoding\optional{,errors}}} +Return an encoded version of the string. Default encoding is the current +default string encoding. \var{errors} may be given to set a different +error handling scheme. The default for \var{errors} is +\code{'strict'}, meaning that encoding errors raise a +\exception{UnicodeError}. Other possible values are \code{'ignore'}, +\code{'replace'}, \code{'xmlcharrefreplace'}, \code{'backslashreplace'} +and any other name registered via \function{codecs.register_error}, +see section~\ref{codec-base-classes}. +For a list of possible encodings, see section~\ref{standard-encodings}. +\versionadded{2.0} +\versionchanged[Support for \code{'xmlcharrefreplace'} and +\code{'backslashreplace'} and other error handling schemes added]{2.3} +\end{methoddesc} + +\begin{methoddesc}[string]{endswith}{suffix\optional{, start\optional{, end}}} +Return \code{True} if the string ends with the specified \var{suffix}, +otherwise return \code{False}. \var{suffix} can also be a tuple of +suffixes to look for. With optional \var{start}, test beginning at +that position. With optional \var{end}, stop comparing at that position. + +\versionchanged[Accept tuples as \var{suffix}]{2.5} +\end{methoddesc} + +\begin{methoddesc}[string]{expandtabs}{\optional{tabsize}} +Return a copy of the string where all tab characters are expanded +using spaces. If \var{tabsize} is not given, a tab size of \code{8} +characters is assumed. +\end{methoddesc} + +\begin{methoddesc}[string]{find}{sub\optional{, start\optional{, end}}} +Return the lowest index in the string where substring \var{sub} is +found, such that \var{sub} is contained in the range [\var{start}, +\var{end}]. Optional arguments \var{start} and \var{end} are +interpreted as in slice notation. Return \code{-1} if \var{sub} is +not found. +\end{methoddesc} + +\begin{methoddesc}[string]{index}{sub\optional{, start\optional{, end}}} +Like \method{find()}, but raise \exception{ValueError} when the +substring is not found. +\end{methoddesc} + +\begin{methoddesc}[string]{isalnum}{} +Return true if all characters in the string are alphanumeric and there +is at least one character, false otherwise. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{isalpha}{} +Return true if all characters in the string are alphabetic and there +is at least one character, false otherwise. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{isdigit}{} +Return true if all characters in the string are digits and there +is at least one character, false otherwise. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{islower}{} +Return true if all cased characters in the string are lowercase and +there is at least one cased character, false otherwise. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{isspace}{} +Return true if there are only whitespace characters in the string and +there is at least one character, false otherwise. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{istitle}{} +Return true if the string is a titlecased string and there is at least one +character, for example uppercase characters may only follow uncased +characters and lowercase characters only cased ones. Return false +otherwise. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{isupper}{} +Return true if all cased characters in the string are uppercase and +there is at least one cased character, false otherwise. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{join}{seq} +Return a string which is the concatenation of the strings in the +sequence \var{seq}. The separator between elements is the string +providing this method. +\end{methoddesc} + +\begin{methoddesc}[string]{ljust}{width\optional{, fillchar}} +Return the string left justified in a string of length \var{width}. +Padding is done using the specified \var{fillchar} (default is a +space). The original string is returned if +\var{width} is less than \code{len(\var{s})}. +\versionchanged[Support for the \var{fillchar} argument]{2.4} +\end{methoddesc} + +\begin{methoddesc}[string]{lower}{} +Return a copy of the string converted to lowercase. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{lstrip}{\optional{chars}} +Return a copy of the string with leading characters removed. The +\var{chars} argument is a string specifying the set of characters +to be removed. If omitted or \code{None}, the \var{chars} argument +defaults to removing whitespace. The \var{chars} argument is not +a prefix; rather, all combinations of its values are stripped: +\begin{verbatim} + >>> ' spacious '.lstrip() + 'spacious ' + >>> 'www.example.com'.lstrip('cmowz.') + 'example.com' +\end{verbatim} +\versionchanged[Support for the \var{chars} argument]{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[string]{partition}{sep} +Split the string at the first occurrence of \var{sep}, and return +a 3-tuple containing the part before the separator, the separator +itself, and the part after the separator. If the separator is not +found, return a 3-tuple containing the string itself, followed by +two empty strings. +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}[string]{replace}{old, new\optional{, count}} +Return a copy of the string with all occurrences of substring +\var{old} replaced by \var{new}. If the optional argument +\var{count} is given, only the first \var{count} occurrences are +replaced. +\end{methoddesc} + +\begin{methoddesc}[string]{rfind}{sub \optional{,start \optional{,end}}} +Return the highest index in the string where substring \var{sub} is +found, such that \var{sub} is contained within s[start,end]. Optional +arguments \var{start} and \var{end} are interpreted as in slice +notation. Return \code{-1} on failure. +\end{methoddesc} + +\begin{methoddesc}[string]{rindex}{sub\optional{, start\optional{, end}}} +Like \method{rfind()} but raises \exception{ValueError} when the +substring \var{sub} is not found. +\end{methoddesc} + +\begin{methoddesc}[string]{rjust}{width\optional{, fillchar}} +Return the string right justified in a string of length \var{width}. +Padding is done using the specified \var{fillchar} (default is a space). +The original string is returned if +\var{width} is less than \code{len(\var{s})}. +\versionchanged[Support for the \var{fillchar} argument]{2.4} +\end{methoddesc} + +\begin{methoddesc}[string]{rpartition}{sep} +Split the string at the last occurrence of \var{sep}, and return +a 3-tuple containing the part before the separator, the separator +itself, and the part after the separator. If the separator is not +found, return a 3-tuple containing two empty strings, followed by +the string itself. +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}[string]{rsplit}{\optional{sep \optional{,maxsplit}}} +Return a list of the words in the string, using \var{sep} as the +delimiter string. If \var{maxsplit} is given, at most \var{maxsplit} +splits are done, the \emph{rightmost} ones. If \var{sep} is not specified +or \code{None}, any whitespace string is a separator. Except for splitting +from the right, \method{rsplit()} behaves like \method{split()} which +is described in detail below. +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[string]{rstrip}{\optional{chars}} +Return a copy of the string with trailing characters removed. The +\var{chars} argument is a string specifying the set of characters +to be removed. If omitted or \code{None}, the \var{chars} argument +defaults to removing whitespace. The \var{chars} argument is not +a suffix; rather, all combinations of its values are stripped: +\begin{verbatim} + >>> ' spacious '.rstrip() + ' spacious' + >>> 'mississippi'.rstrip('ipz') + 'mississ' +\end{verbatim} +\versionchanged[Support for the \var{chars} argument]{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[string]{split}{\optional{sep \optional{,maxsplit}}} +Return a list of the words in the string, using \var{sep} as the +delimiter string. If \var{maxsplit} is given, at most \var{maxsplit} +splits are done. (thus, the list will have at most \code{\var{maxsplit}+1} +elements). If \var{maxsplit} is not specified, then there +is no limit on the number of splits (all possible splits are made). +Consecutive delimiters are not grouped together and are +deemed to delimit empty strings (for example, \samp{'1,,2'.split(',')} +returns \samp{['1', '', '2']}). The \var{sep} argument may consist of +multiple characters (for example, \samp{'1, 2, 3'.split(', ')} returns +\samp{['1', '2', '3']}). Splitting an empty string with a specified +separator returns \samp{['']}. + +If \var{sep} is not specified or is \code{None}, a different splitting +algorithm is applied. First, whitespace characters (spaces, tabs, +newlines, returns, and formfeeds) are stripped from both ends. Then, +words are separated by arbitrary length strings of whitespace +characters. Consecutive whitespace delimiters are treated as a single +delimiter (\samp{'1 2 3'.split()} returns \samp{['1', '2', '3']}). +Splitting an empty string or a string consisting of just whitespace +returns an empty list. +\end{methoddesc} + +\begin{methoddesc}[string]{splitlines}{\optional{keepends}} +Return a list of the lines in the string, breaking at line +boundaries. Line breaks are not included in the resulting list unless +\var{keepends} is given and true. +\end{methoddesc} + +\begin{methoddesc}[string]{startswith}{prefix\optional{, + start\optional{, end}}} +Return \code{True} if string starts with the \var{prefix}, otherwise +return \code{False}. \var{prefix} can also be a tuple of +prefixes to look for. With optional \var{start}, test string beginning at +that position. With optional \var{end}, stop comparing string at that +position. + +\versionchanged[Accept tuples as \var{prefix}]{2.5} +\end{methoddesc} + +\begin{methoddesc}[string]{strip}{\optional{chars}} +Return a copy of the string with the leading and trailing characters +removed. The \var{chars} argument is a string specifying the set of +characters to be removed. If omitted or \code{None}, the \var{chars} +argument defaults to removing whitespace. The \var{chars} argument is not +a prefix or suffix; rather, all combinations of its values are stripped: +\begin{verbatim} + >>> ' spacious '.strip() + 'spacious' + >>> 'www.example.com'.strip('cmowz.') + 'example' +\end{verbatim} +\versionchanged[Support for the \var{chars} argument]{2.2.2} +\end{methoddesc} + +\begin{methoddesc}[string]{swapcase}{} +Return a copy of the string with uppercase characters converted to +lowercase and vice versa. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{title}{} +Return a titlecased version of the string: words start with uppercase +characters, all remaining cased characters are lowercase. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{translate}{table\optional{, deletechars}} +Return a copy of the string where all characters occurring in the +optional argument \var{deletechars} are removed, and the remaining +characters have been mapped through the given translation table, which +must be a string of length 256. + +You can use the \function{maketrans()} helper function in the +\refmodule{string} module to create a translation table. + +For Unicode objects, the \method{translate()} method does not +accept the optional \var{deletechars} argument. Instead, it +returns a copy of the \var{s} where all characters have been mapped +through the given translation table which must be a mapping of +Unicode ordinals to Unicode ordinals, Unicode strings or \code{None}. +Unmapped characters are left untouched. Characters mapped to \code{None} +are deleted. Note, a more flexible approach is to create a custom +character mapping codec using the \refmodule{codecs} module (see +\module{encodings.cp1251} for an example). +\end{methoddesc} + +\begin{methoddesc}[string]{upper}{} +Return a copy of the string converted to uppercase. + +For 8-bit strings, this method is locale-dependent. +\end{methoddesc} + +\begin{methoddesc}[string]{zfill}{width} +Return the numeric string left filled with zeros in a string +of length \var{width}. The original string is returned if +\var{width} is less than \code{len(\var{s})}. +\versionadded{2.2.2} +\end{methoddesc} + + +\subsection{String Formatting Operations \label{typesseq-strings}} + +\index{formatting, string (\%{})} +\index{interpolation, string (\%{})} +\index{string!formatting} +\index{string!interpolation} +\index{printf-style formatting} +\index{sprintf-style formatting} +\index{\protect\%{} formatting} +\index{\protect\%{} interpolation} + +String and Unicode objects have one unique built-in operation: the +\code{\%} operator (modulo). This is also known as the string +\emph{formatting} or \emph{interpolation} operator. Given +\code{\var{format} \% \var{values}} (where \var{format} is a string or +Unicode object), \code{\%} conversion specifications in \var{format} +are replaced with zero or more elements of \var{values}. The effect +is similar to the using \cfunction{sprintf()} in the C language. If +\var{format} is a Unicode object, or if any of the objects being +converted using the \code{\%s} conversion are Unicode objects, the +result will also be a Unicode object. + +If \var{format} requires a single argument, \var{values} may be a +single non-tuple object.\footnote{To format only a tuple you +should therefore provide a singleton tuple whose only element +is the tuple to be formatted.} Otherwise, \var{values} must be a tuple with +exactly the number of items specified by the format string, or a +single mapping object (for example, a dictionary). + +A conversion specifier contains two or more characters and has the +following components, which must occur in this order: + +\begin{enumerate} + \item The \character{\%} character, which marks the start of the + specifier. + \item Mapping key (optional), consisting of a parenthesised sequence + of characters (for example, \code{(somename)}). + \item Conversion flags (optional), which affect the result of some + conversion types. + \item Minimum field width (optional). If specified as an + \character{*} (asterisk), the actual width is read from the + next element of the tuple in \var{values}, and the object to + convert comes after the minimum field width and optional + precision. + \item Precision (optional), given as a \character{.} (dot) followed + by the precision. If specified as \character{*} (an + asterisk), the actual width is read from the next element of + the tuple in \var{values}, and the value to convert comes after + the precision. + \item Length modifier (optional). + \item Conversion type. +\end{enumerate} + +When the right argument is a dictionary (or other mapping type), then +the formats in the string \emph{must} include a parenthesised mapping key into +that dictionary inserted immediately after the \character{\%} +character. The mapping key selects the value to be formatted from the +mapping. For example: + +\begin{verbatim} +>>> print '%(language)s has %(#)03d quote types.' % \ + {'language': "Python", "#": 2} +Python has 002 quote types. +\end{verbatim} + +In this case no \code{*} specifiers may occur in a format (since they +require a sequential parameter list). + +The conversion flag characters are: + +\begin{tableii}{c|l}{character}{Flag}{Meaning} + \lineii{\#}{The value conversion will use the ``alternate form'' + (where defined below).} + \lineii{0}{The conversion will be zero padded for numeric values.} + \lineii{-}{The converted value is left adjusted (overrides + the \character{0} conversion if both are given).} + \lineii{{~}}{(a space) A blank should be left before a positive number + (or empty string) produced by a signed conversion.} + \lineii{+}{A sign character (\character{+} or \character{-}) will + precede the conversion (overrides a "space" flag).} +\end{tableii} + +A length modifier (\code{h}, \code{l}, or \code{L}) may be +present, but is ignored as it is not necessary for Python. + +The conversion types are: + +\begin{tableiii}{c|l|c}{character}{Conversion}{Meaning}{Notes} + \lineiii{d}{Signed integer decimal.}{} + \lineiii{i}{Signed integer decimal.}{} + \lineiii{o}{Unsigned octal.}{(1)} + \lineiii{u}{Unsigned decimal.}{} + \lineiii{x}{Unsigned hexadecimal (lowercase).}{(2)} + \lineiii{X}{Unsigned hexadecimal (uppercase).}{(2)} + \lineiii{e}{Floating point exponential format (lowercase).}{(3)} + \lineiii{E}{Floating point exponential format (uppercase).}{(3)} + \lineiii{f}{Floating point decimal format.}{(3)} + \lineiii{F}{Floating point decimal format.}{(3)} + \lineiii{g}{Floating point format. Uses exponential format + if exponent is greater than -4 or less than precision, + decimal format otherwise.}{(4)} + \lineiii{G}{Floating point format. Uses exponential format + if exponent is greater than -4 or less than precision, + decimal format otherwise.}{(4)} + \lineiii{c}{Single character (accepts integer or single character + string).}{} + \lineiii{r}{String (converts any python object using + \function{repr()}).}{(5)} + \lineiii{s}{String (converts any python object using + \function{str()}).}{(6)} + \lineiii{\%}{No argument is converted, results in a \character{\%} + character in the result.}{} +\end{tableiii} + +\noindent +Notes: +\begin{description} + \item[(1)] + The alternate form causes a leading zero (\character{0}) to be + inserted between left-hand padding and the formatting of the + number if the leading character of the result is not already a + zero. + \item[(2)] + The alternate form causes a leading \code{'0x'} or \code{'0X'} + (depending on whether the \character{x} or \character{X} format + was used) to be inserted between left-hand padding and the + formatting of the number if the leading character of the result is + not already a zero. + \item[(3)] + The alternate form causes the result to always contain a decimal + point, even if no digits follow it. + + The precision determines the number of digits after the decimal + point and defaults to 6. + \item[(4)] + The alternate form causes the result to always contain a decimal + point, and trailing zeroes are not removed as they would + otherwise be. + + The precision determines the number of significant digits before + and after the decimal point and defaults to 6. + \item[(5)] + The \code{\%r} conversion was added in Python 2.0. + + The precision determines the maximal number of characters used. + \item[(6)] + If the object or format provided is a \class{unicode} string, + the resulting string will also be \class{unicode}. + + The precision determines the maximal number of characters used. +\end{description} + +% XXX Examples? + +Since Python strings have an explicit length, \code{\%s} conversions +do not assume that \code{'\e0'} is the end of the string. + +For safety reasons, floating point precisions are clipped to 50; +\code{\%f} conversions for numbers whose absolute value is over 1e25 +are replaced by \code{\%g} conversions.\footnote{ + These numbers are fairly arbitrary. They are intended to + avoid printing endless strings of meaningless digits without hampering + correct use and without having to know the exact precision of floating + point values on a particular machine. +} All other errors raise exceptions. + +Additional string operations are defined in standard modules +\refmodule{string}\refstmodindex{string}\ and +\refmodule{re}.\refstmodindex{re} + + +\subsection{XRange Type \label{typesseq-xrange}} + +The \class{xrange}\obindex{xrange} type is an immutable sequence which +is commonly used for looping. The advantage of the \class{xrange} +type is that an \class{xrange} object will always take the same amount +of memory, no matter the size of the range it represents. There are +no consistent performance advantages. + +XRange objects have very little behavior: they only support indexing, +iteration, and the \function{len()} function. + + +\subsection{Mutable Sequence Types \label{typesseq-mutable}} + +List objects support additional operations that allow in-place +modification of the object. +Other mutable sequence types (when added to the language) should +also support these operations. +Strings and tuples are immutable sequence types: such objects cannot +be modified once created. +The following operations are defined on mutable sequence types (where +\var{x} is an arbitrary object): +\indexiii{mutable}{sequence}{types} +\obindex{list} + +\begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} + \lineiii{\var{s}[\var{i}] = \var{x}} + {item \var{i} of \var{s} is replaced by \var{x}}{} + \lineiii{\var{s}[\var{i}:\var{j}] = \var{t}} + {slice of \var{s} from \var{i} to \var{j} + is replaced by the contents of the iterable \var{t}}{} + \lineiii{del \var{s}[\var{i}:\var{j}]} + {same as \code{\var{s}[\var{i}:\var{j}] = []}}{} + \lineiii{\var{s}[\var{i}:\var{j}:\var{k}] = \var{t}} + {the elements of \code{\var{s}[\var{i}:\var{j}:\var{k}]} are replaced by those of \var{t}}{(1)} + \lineiii{del \var{s}[\var{i}:\var{j}:\var{k}]} + {removes the elements of \code{\var{s}[\var{i}:\var{j}:\var{k}]} from the list}{} + \lineiii{\var{s}.append(\var{x})} + {same as \code{\var{s}[len(\var{s}):len(\var{s})] = [\var{x}]}}{(2)} + \lineiii{\var{s}.extend(\var{x})} + {same as \code{\var{s}[len(\var{s}):len(\var{s})] = \var{x}}}{(3)} + \lineiii{\var{s}.count(\var{x})} + {return number of \var{i}'s for which \code{\var{s}[\var{i}] == \var{x}}}{} + \lineiii{\var{s}.index(\var{x}\optional{, \var{i}\optional{, \var{j}}})} + {return smallest \var{k} such that \code{\var{s}[\var{k}] == \var{x}} and + \code{\var{i} <= \var{k} < \var{j}}}{(4)} + \lineiii{\var{s}.insert(\var{i}, \var{x})} + {same as \code{\var{s}[\var{i}:\var{i}] = [\var{x}]}}{(5)} + \lineiii{\var{s}.pop(\optional{\var{i}})} + {same as \code{\var{x} = \var{s}[\var{i}]; del \var{s}[\var{i}]; return \var{x}}}{(6)} + \lineiii{\var{s}.remove(\var{x})} + {same as \code{del \var{s}[\var{s}.index(\var{x})]}}{(4)} + \lineiii{\var{s}.reverse()} + {reverses the items of \var{s} in place}{(7)} + \lineiii{\var{s}.sort(\optional{\var{cmp}\optional{, + \var{key}\optional{, \var{reverse}}}})} + {sort the items of \var{s} in place}{(7), (8), (9), (10)} +\end{tableiii} +\indexiv{operations on}{mutable}{sequence}{types} +\indexiii{operations on}{sequence}{types} +\indexiii{operations on}{list}{type} +\indexii{subscript}{assignment} +\indexii{slice}{assignment} +\indexii{extended slice}{assignment} +\stindex{del} +\withsubitem{(list method)}{ + \ttindex{append()}\ttindex{extend()}\ttindex{count()}\ttindex{index()} + \ttindex{insert()}\ttindex{pop()}\ttindex{remove()}\ttindex{reverse()} + \ttindex{sort()}} +\noindent +Notes: +\begin{description} +\item[(1)] \var{t} must have the same length as the slice it is + replacing. + +\item[(2)] The C implementation of Python has historically accepted + multiple parameters and implicitly joined them into a tuple; this + no longer works in Python 2.0. Use of this misfeature has been + deprecated since Python 1.4. + +\item[(3)] \var{x} can be any iterable object. + +\item[(4)] Raises \exception{ValueError} when \var{x} is not found in + \var{s}. When a negative index is passed as the second or third parameter + to the \method{index()} method, the list length is added, as for slice + indices. If it is still negative, it is truncated to zero, as for + slice indices. \versionchanged[Previously, \method{index()} didn't + have arguments for specifying start and stop positions]{2.3} + +\item[(5)] When a negative index is passed as the first parameter to + the \method{insert()} method, the list length is added, as for slice + indices. If it is still negative, it is truncated to zero, as for + slice indices. \versionchanged[Previously, all negative indices + were truncated to zero]{2.3} + +\item[(6)] The \method{pop()} method is only supported by the list and + array types. The optional argument \var{i} defaults to \code{-1}, + so that by default the last item is removed and returned. + +\item[(7)] The \method{sort()} and \method{reverse()} methods modify the + list in place for economy of space when sorting or reversing a large + list. To remind you that they operate by side effect, they don't return + the sorted or reversed list. + +\item[(8)] The \method{sort()} method takes optional arguments for + controlling the comparisons. + + \var{cmp} specifies a custom comparison function of two arguments + (list items) which should return a negative, zero or positive number + depending on whether the first argument is considered smaller than, + equal to, or larger than the second argument: + \samp{\var{cmp}=\keyword{lambda} \var{x},\var{y}: + \function{cmp}(x.lower(), y.lower())} + + \var{key} specifies a function of one argument that is used to + extract a comparison key from each list element: + \samp{\var{key}=\function{str.lower}} + + \var{reverse} is a boolean value. If set to \code{True}, then the + list elements are sorted as if each comparison were reversed. + + In general, the \var{key} and \var{reverse} conversion processes are + much faster than specifying an equivalent \var{cmp} function. This is + because \var{cmp} is called multiple times for each list element while + \var{key} and \var{reverse} touch each element only once. + + \versionchanged[Support for \code{None} as an equivalent to omitting + \var{cmp} was added]{2.3} + + \versionchanged[Support for \var{key} and \var{reverse} was added]{2.4} + +\item[(9)] Starting with Python 2.3, the \method{sort()} method is + guaranteed to be stable. A sort is stable if it guarantees not to + change the relative order of elements that compare equal --- this is + helpful for sorting in multiple passes (for example, sort by + department, then by salary grade). + +\item[(10)] While a list is being sorted, the effect of attempting to + mutate, or even inspect, the list is undefined. The C + implementation of Python 2.3 and newer makes the list appear empty + for the duration, and raises \exception{ValueError} if it can detect + that the list has been mutated during a sort. +\end{description} + +\section{Set Types --- + \class{set}, \class{frozenset} + \label{types-set}} +\obindex{set} + +A \dfn{set} object is an unordered collection of distinct hashable objects. +Common uses include membership testing, removing duplicates from a sequence, +and computing mathematical operations such as intersection, union, difference, +and symmetric difference. +\versionadded{2.4} + +Like other collections, sets support \code{\var{x} in \var{set}}, +\code{len(\var{set})}, and \code{for \var{x} in \var{set}}. Being an +unordered collection, sets do not record element position or order of +insertion. Accordingly, sets do not support indexing, slicing, or +other sequence-like behavior. + +There are currently two builtin set types, \class{set} and \class{frozenset}. +The \class{set} type is mutable --- the contents can be changed using methods +like \method{add()} and \method{remove()}. Since it is mutable, it has no +hash value and cannot be used as either a dictionary key or as an element of +another set. The \class{frozenset} type is immutable and hashable --- its +contents cannot be altered after is created; however, it can be used as +a dictionary key or as an element of another set. + +Instances of \class{set} and \class{frozenset} provide the following operations: + +\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result} + \lineiii{len(\var{s})}{}{cardinality of set \var{s}} + + \hline + \lineiii{\var{x} in \var{s}}{} + {test \var{x} for membership in \var{s}} + \lineiii{\var{x} not in \var{s}}{} + {test \var{x} for non-membership in \var{s}} + \lineiii{\var{s}.issubset(\var{t})}{\code{\var{s} <= \var{t}}} + {test whether every element in \var{s} is in \var{t}} + \lineiii{\var{s}.issuperset(\var{t})}{\code{\var{s} >= \var{t}}} + {test whether every element in \var{t} is in \var{s}} + + \hline + \lineiii{\var{s}.union(\var{t})}{\var{s} | \var{t}} + {new set with elements from both \var{s} and \var{t}} + \lineiii{\var{s}.intersection(\var{t})}{\var{s} \&\ \var{t}} + {new set with elements common to \var{s} and \var{t}} + \lineiii{\var{s}.difference(\var{t})}{\var{s} - \var{t}} + {new set with elements in \var{s} but not in \var{t}} + \lineiii{\var{s}.symmetric_difference(\var{t})}{\var{s} \^\ \var{t}} + {new set with elements in either \var{s} or \var{t} but not both} + \lineiii{\var{s}.copy()}{} + {new set with a shallow copy of \var{s}} +\end{tableiii} + +Note, the non-operator versions of \method{union()}, \method{intersection()}, +\method{difference()}, and \method{symmetric_difference()}, +\method{issubset()}, and \method{issuperset()} methods will accept any +iterable as an argument. In contrast, their operator based counterparts +require their arguments to be sets. This precludes error-prone constructions +like \code{set('abc') \&\ 'cbs'} in favor of the more readable +\code{set('abc').intersection('cbs')}. + +Both \class{set} and \class{frozenset} support set to set comparisons. +Two sets are equal if and only if every element of each set is contained in +the other (each is a subset of the other). +A set is less than another set if and only if the first set is a proper +subset of the second set (is a subset, but is not equal). +A set is greater than another set if and only if the first set is a proper +superset of the second set (is a superset, but is not equal). + +Instances of \class{set} are compared to instances of \class{frozenset} based +on their members. For example, \samp{set('abc') == frozenset('abc')} returns +\code{True}. + +The subset and equality comparisons do not generalize to a complete +ordering function. For example, any two disjoint sets are not equal and +are not subsets of each other, so \emph{all} of the following return +\code{False}: \code{\var{a}<\var{b}}, \code{\var{a}==\var{b}}, or +\code{\var{a}>\var{b}}. +Accordingly, sets do not implement the \method{__cmp__} method. + +Since sets only define partial ordering (subset relationships), the output +of the \method{list.sort()} method is undefined for lists of sets. + +Set elements are like dictionary keys; they need to define both +\method{__hash__} and \method{__eq__} methods. + +Binary operations that mix \class{set} instances with \class{frozenset} +return the type of the first operand. For example: +\samp{frozenset('ab') | set('bc')} returns an instance of \class{frozenset}. + +The following table lists operations available for \class{set} +that do not apply to immutable instances of \class{frozenset}: + +\begin{tableiii}{c|c|l}{code}{Operation}{Equivalent}{Result} + \lineiii{\var{s}.update(\var{t})} + {\var{s} |= \var{t}} + {update set \var{s}, adding elements from \var{t}} + \lineiii{\var{s}.intersection_update(\var{t})} + {\var{s} \&= \var{t}} + {update set \var{s}, keeping only elements found in both \var{s} and \var{t}} + \lineiii{\var{s}.difference_update(\var{t})} + {\var{s} -= \var{t}} + {update set \var{s}, removing elements found in \var{t}} + \lineiii{\var{s}.symmetric_difference_update(\var{t})} + {\var{s} \textasciicircum= \var{t}} + {update set \var{s}, keeping only elements found in either \var{s} or \var{t} + but not in both} + + \hline + \lineiii{\var{s}.add(\var{x})}{} + {add element \var{x} to set \var{s}} + \lineiii{\var{s}.remove(\var{x})}{} + {remove \var{x} from set \var{s}; raises \exception{KeyError} + if not present} + \lineiii{\var{s}.discard(\var{x})}{} + {removes \var{x} from set \var{s} if present} + \lineiii{\var{s}.pop()}{} + {remove and return an arbitrary element from \var{s}; raises + \exception{KeyError} if empty} + \lineiii{\var{s}.clear()}{} + {remove all elements from set \var{s}} +\end{tableiii} + +Note, the non-operator versions of the \method{update()}, +\method{intersection_update()}, \method{difference_update()}, and +\method{symmetric_difference_update()} methods will accept any iterable +as an argument. + +The design of the set types was based on lessons learned from the +\module{sets} module. + +\begin{seealso} + \seelink{comparison-to-builtin-set.html} + {Comparison to the built-in set types} + {Differences between the \module{sets} module and the + built-in set types.} +\end{seealso} + + +\section{Mapping Types --- \class{dict} \label{typesmapping}} +\obindex{mapping} +\obindex{dictionary} + +A \dfn{mapping} object maps immutable values to +arbitrary objects. Mappings are mutable objects. There is currently +only one standard mapping type, the \dfn{dictionary}. A dictionary's keys are +almost arbitrary values. Only values containing lists, dictionaries +or other mutable types (that are compared by value rather than by +object identity) may not be used as keys. +Numeric types used for keys obey the normal rules for numeric +comparison: if two numbers compare equal (such as \code{1} and +\code{1.0}) then they can be used interchangeably to index the same +dictionary entry. + +Dictionaries are created by placing a comma-separated list of +\code{\var{key}: \var{value}} pairs within braces, for example: +\code{\{'jack': 4098, 'sjoerd': 4127\}} or +\code{\{4098: 'jack', 4127: 'sjoerd'\}}. + +The following operations are defined on mappings (where \var{a} and +\var{b} are mappings, \var{k} is a key, and \var{v} and \var{x} are +arbitrary objects): +\indexiii{operations on}{mapping}{types} +\indexiii{operations on}{dictionary}{type} +\stindex{del} +\bifuncindex{len} +\withsubitem{(dictionary method)}{ + \ttindex{clear()} + \ttindex{copy()} + \ttindex{has_key()} + \ttindex{fromkeys()} + \ttindex{items()} + \ttindex{keys()} + \ttindex{update()} + \ttindex{values()} + \ttindex{get()} + \ttindex{setdefault()} + \ttindex{pop()} + \ttindex{popitem()} + \ttindex{iteritems()} + \ttindex{iterkeys()} + \ttindex{itervalues()}} + +\begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} + \lineiii{len(\var{a})}{the number of items in \var{a}}{} + \lineiii{\var{a}[\var{k}]}{the item of \var{a} with key \var{k}}{(1), (10)} + \lineiii{\var{a}[\var{k}] = \var{v}} + {set \code{\var{a}[\var{k}]} to \var{v}} + {} + \lineiii{del \var{a}[\var{k}]} + {remove \code{\var{a}[\var{k}]} from \var{a}} + {(1)} + \lineiii{\var{a}.clear()}{remove all items from \code{a}}{} + \lineiii{\var{a}.copy()}{a (shallow) copy of \code{a}}{} + \lineiii{\var{k} in \var{a}} + {\code{True} if \var{a} has a key \var{k}, else \code{False}} + {(2)} + \lineiii{\var{k} not in \var{a}} + {Equivalent to \code{not} \var{k} in \var{a}} + {(2)} + \lineiii{\var{a}.has_key(\var{k})} + {Equivalent to \var{k} \code{in} \var{a}, use that form in new code} + {} + \lineiii{\var{a}.items()} + {a copy of \var{a}'s list of (\var{key}, \var{value}) pairs} + {(3)} + \lineiii{\var{a}.keys()}{a copy of \var{a}'s list of keys}{(3)} + \lineiii{\var{a}.update(\optional{\var{b}})} + {updates \var{a} with key/value pairs from \var{b}, overwriting + existing keys, returns \code{None}} + {(9)} + \lineiii{\var{a}.fromkeys(\var{seq}\optional{, \var{value}})} + {Creates a new dictionary with keys from \var{seq} and values set to \var{value}} + {(7)} + \lineiii{\var{a}.values()}{a copy of \var{a}'s list of values}{(3)} + \lineiii{\var{a}.get(\var{k}\optional{, \var{x}})} + {\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}, + else \var{x}} + {(4)} + \lineiii{\var{a}.setdefault(\var{k}\optional{, \var{x}})} + {\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}, + else \var{x} (also setting it)} + {(5)} + \lineiii{\var{a}.pop(\var{k}\optional{, \var{x}})} + {\code{\var{a}[\var{k}]} if \code{\var{k} in \var{a}}, + else \var{x} (and remove k)} + {(8)} + \lineiii{\var{a}.popitem()} + {remove and return an arbitrary (\var{key}, \var{value}) pair} + {(6)} + \lineiii{\var{a}.iteritems()} + {return an iterator over (\var{key}, \var{value}) pairs} + {(2), (3)} + \lineiii{\var{a}.iterkeys()} + {return an iterator over the mapping's keys} + {(2), (3)} + \lineiii{\var{a}.itervalues()} + {return an iterator over the mapping's values} + {(2), (3)} +\end{tableiii} + +\noindent +Notes: +\begin{description} +\item[(1)] Raises a \exception{KeyError} exception if \var{k} is not +in the map. + +\item[(2)] \versionadded{2.2} + +\item[(3)] Keys and values are listed in an arbitrary order which is +non-random, varies across Python implementations, and depends on the +dictionary's history of insertions and deletions. +If \method{items()}, \method{keys()}, \method{values()}, +\method{iteritems()}, \method{iterkeys()}, and \method{itervalues()} +are called with no intervening modifications to the dictionary, the +lists will directly correspond. This allows the creation of +\code{(\var{value}, \var{key})} pairs using \function{zip()}: +\samp{pairs = zip(\var{a}.values(), \var{a}.keys())}. The same +relationship holds for the \method{iterkeys()} and +\method{itervalues()} methods: \samp{pairs = zip(\var{a}.itervalues(), +\var{a}.iterkeys())} provides the same value for \code{pairs}. +Another way to create the same list is \samp{pairs = [(v, k) for (k, +v) in \var{a}.iteritems()]}. + +\item[(4)] Never raises an exception if \var{k} is not in the map, +instead it returns \var{x}. \var{x} is optional; when \var{x} is not +provided and \var{k} is not in the map, \code{None} is returned. + +\item[(5)] \function{setdefault()} is like \function{get()}, except +that if \var{k} is missing, \var{x} is both returned and inserted into +the dictionary as the value of \var{k}. \var{x} defaults to \var{None}. + +\item[(6)] \function{popitem()} is useful to destructively iterate +over a dictionary, as often used in set algorithms. If the dictionary +is empty, calling \function{popitem()} raises a \exception{KeyError}. + +\item[(7)] \function{fromkeys()} is a class method that returns a +new dictionary. \var{value} defaults to \code{None}. \versionadded{2.3} + +\item[(8)] \function{pop()} raises a \exception{KeyError} when no default +value is given and the key is not found. \versionadded{2.3} + +\item[(9)] \function{update()} accepts either another mapping object +or an iterable of key/value pairs (as a tuple or other iterable of +length two). If keyword arguments are specified, the mapping is +then is updated with those key/value pairs: +\samp{d.update(red=1, blue=2)}. +\versionchanged[Allowed the argument to be an iterable of key/value + pairs and allowed keyword arguments]{2.4} + +\item[(10)] If a subclass of dict defines a method \method{__missing__}, +if the key \var{k} is not present, the \var{a}[\var{k}] operation calls +that method with the key \var{k} as argument. The \var{a}[\var{k}] +operation then returns or raises whatever is returned or raised by the +\function{__missing__}(\var{k}) call if the key is not present. +No other operations or methods invoke \method{__missing__}(). +If \method{__missing__} is not defined, \exception{KeyError} is raised. +\method{__missing__} must be a method; it cannot be an instance variable. +For an example, see \module{collections}.\class{defaultdict}. +\versionadded{2.5} + +\end{description} + +\section{File Objects + \label{bltin-file-objects}} + +File objects\obindex{file} are implemented using C's \code{stdio} +package and can be created with the built-in constructor +\function{file()}\bifuncindex{file} described in section +\ref{built-in-funcs}, ``Built-in Functions.''\footnote{\function{file()} +is new in Python 2.2. The older built-in \function{open()} is an +alias for \function{file()}.} File objects are also returned +by some other built-in functions and methods, such as +\function{os.popen()} and \function{os.fdopen()} and the +\method{makefile()} method of socket objects. +\refstmodindex{os} +\refbimodindex{socket} + +When a file operation fails for an I/O-related reason, the exception +\exception{IOError} is raised. This includes situations where the +operation is not defined for some reason, like \method{seek()} on a tty +device or writing a file opened for reading. + +Files have the following methods: + + +\begin{methoddesc}[file]{close}{} + Close the file. A closed file cannot be read or written any more. + Any operation which requires that the file be open will raise a + \exception{ValueError} after the file has been closed. Calling + \method{close()} more than once is allowed. + + As of Python 2.5, you can avoid having to call this method explicitly + if you use the \keyword{with} statement. For example, the following + code will automatically close \code{f} when the \keyword{with} block + is exited: + +\begin{verbatim} +from __future__ import with_statement + +with open("hello.txt") as f: + for line in f: + print line +\end{verbatim} + + In older versions of Python, you would have needed to do this to get + the same effect: + +\begin{verbatim} +f = open("hello.txt") +try: + for line in f: + print line +finally: + f.close() +\end{verbatim} + + \note{Not all ``file-like'' types in Python support use as a context + manager for the \keyword{with} statement. If your code is intended to + work with any file-like object, you can use the \function{closing()} + function in the \module{contextlib} module instead of using the object + directly. See section~\ref{context-closing} for details.} + +\end{methoddesc} + +\begin{methoddesc}[file]{flush}{} + Flush the internal buffer, like \code{stdio}'s + \cfunction{fflush()}. This may be a no-op on some file-like + objects. +\end{methoddesc} + +\begin{methoddesc}[file]{fileno}{} + \index{file descriptor} + \index{descriptor, file} + Return the integer ``file descriptor'' that is used by the + underlying implementation to request I/O operations from the + operating system. This can be useful for other, lower level + interfaces that use file descriptors, such as the + \refmodule{fcntl}\refbimodindex{fcntl} module or + \function{os.read()} and friends. \note{File-like objects + which do not have a real file descriptor should \emph{not} provide + this method!} +\end{methoddesc} + +\begin{methoddesc}[file]{isatty}{} + Return \code{True} if the file is connected to a tty(-like) device, else + \code{False}. \note{If a file-like object is not associated + with a real file, this method should \emph{not} be implemented.} +\end{methoddesc} + +\begin{methoddesc}[file]{next}{} +A file object is its own iterator, for example \code{iter(\var{f})} returns +\var{f} (unless \var{f} is closed). When a file is used as an +iterator, typically in a \keyword{for} loop (for example, +\code{for line in f: print line}), the \method{next()} method is +called repeatedly. This method returns the next input line, or raises +\exception{StopIteration} when \EOF{} is hit. In order to make a +\keyword{for} loop the most efficient way of looping over the lines of +a file (a very common operation), the \method{next()} method uses a +hidden read-ahead buffer. As a consequence of using a read-ahead +buffer, combining \method{next()} with other file methods (like +\method{readline()}) does not work right. However, using +\method{seek()} to reposition the file to an absolute position will +flush the read-ahead buffer. +\versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}[file]{read}{\optional{size}} + Read at most \var{size} bytes from the file (less if the read hits + \EOF{} before obtaining \var{size} bytes). If the \var{size} + argument is negative or omitted, read all data until \EOF{} is + reached. The bytes are returned as a string object. An empty + string is returned when \EOF{} is encountered immediately. (For + certain files, like ttys, it makes sense to continue reading after + an \EOF{} is hit.) Note that this method may call the underlying + C function \cfunction{fread()} more than once in an effort to + acquire as close to \var{size} bytes as possible. Also note that + when in non-blocking mode, less data than what was requested may + be returned, even if no \var{size} parameter was given. +\end{methoddesc} + +\begin{methoddesc}[file]{readline}{\optional{size}} + Read one entire line from the file. A trailing newline character is + kept in the string (but may be absent when a file ends with an + incomplete line).\footnote{ + The advantage of leaving the newline on is that + returning an empty string is then an unambiguous \EOF{} + indication. It is also possible (in cases where it might + matter, for example, if you + want to make an exact copy of a file while scanning its lines) + to tell whether the last line of a file ended in a newline + or not (yes this happens!). + } If the \var{size} argument is present and + non-negative, it is a maximum byte count (including the trailing + newline) and an incomplete line may be returned. + An empty string is returned \emph{only} when \EOF{} is encountered + immediately. \note{Unlike \code{stdio}'s \cfunction{fgets()}, the + returned string contains null characters (\code{'\e 0'}) if they + occurred in the input.} +\end{methoddesc} + +\begin{methoddesc}[file]{readlines}{\optional{sizehint}} + Read until \EOF{} using \method{readline()} and return a list containing + the lines thus read. If the optional \var{sizehint} argument is + present, instead of reading up to \EOF, whole lines totalling + approximately \var{sizehint} bytes (possibly after rounding up to an + internal buffer size) are read. Objects implementing a file-like + interface may choose to ignore \var{sizehint} if it cannot be + implemented, or cannot be implemented efficiently. +\end{methoddesc} + +\begin{methoddesc}[file]{xreadlines}{} + This method returns the same thing as \code{iter(f)}. + \versionadded{2.1} + \deprecated{2.3}{Use \samp{for \var{line} in \var{file}} instead.} +\end{methoddesc} + +\begin{methoddesc}[file]{seek}{offset\optional{, whence}} + Set the file's current position, like \code{stdio}'s \cfunction{fseek()}. + The \var{whence} argument is optional and defaults to + \code{os.SEEK_SET} or \code{0} + (absolute file positioning); other values are \code{os.SEEK_CUR} or \code{1} + (seek + relative to the current position) and \code{os.SEEK_END} or \code{2} + (seek relative to the + file's end). There is no return value. Note that if the file is + opened for appending (mode \code{'a'} or \code{'a+'}), any + \method{seek()} operations will be undone at the next write. If the + file is only opened for writing in append mode (mode \code{'a'}), + this method is essentially a no-op, but it remains useful for files + opened in append mode with reading enabled (mode \code{'a+'}). If the + file is opened in text mode (without \code{'b'}), only offsets returned + by \method{tell()} are legal. Use of other offsets causes undefined + behavior. + + Note that not all file objects are seekable. +\end{methoddesc} + +\begin{methoddesc}[file]{tell}{} + Return the file's current position, like \code{stdio}'s + \cfunction{ftell()}. + + \note{On Windows, \method{tell()} can return illegal values (after an + \cfunction{fgets()}) when reading files with \UNIX{}-style line-endings. + Use binary mode (\code{'rb'}) to circumvent this problem.} +\end{methoddesc} + +\begin{methoddesc}[file]{truncate}{\optional{size}} + Truncate the file's size. If the optional \var{size} argument is + present, the file is truncated to (at most) that size. The size + defaults to the current position. The current file position is + not changed. Note that if a specified size exceeds the file's + current size, the result is platform-dependent: possibilities + include that the file may remain unchanged, increase to the specified + size as if zero-filled, or increase to the specified size with + undefined new content. + Availability: Windows, many \UNIX{} variants. +\end{methoddesc} + +\begin{methoddesc}[file]{write}{str} + Write a string to the file. There is no return value. Due to + buffering, the string may not actually show up in the file until + the \method{flush()} or \method{close()} method is called. +\end{methoddesc} + +\begin{methoddesc}[file]{writelines}{sequence} + Write a sequence of strings to the file. The sequence can be any + iterable object producing strings, typically a list of strings. + There is no return value. + (The name is intended to match \method{readlines()}; + \method{writelines()} does not add line separators.) +\end{methoddesc} + + +Files support the iterator protocol. Each iteration returns the same +result as \code{\var{file}.readline()}, and iteration ends when the +\method{readline()} method returns an empty string. + + +File objects also offer a number of other interesting attributes. +These are not required for file-like objects, but should be +implemented if they make sense for the particular object. + +\begin{memberdesc}[file]{closed} +bool indicating the current state of the file object. This is a +read-only attribute; the \method{close()} method changes the value. +It may not be available on all file-like objects. +\end{memberdesc} + +\begin{memberdesc}[file]{encoding} +The encoding that this file uses. When Unicode strings are written +to a file, they will be converted to byte strings using this encoding. +In addition, when the file is connected to a terminal, the attribute +gives the encoding that the terminal is likely to use (that +information might be incorrect if the user has misconfigured the +terminal). The attribute is read-only and may not be present on +all file-like objects. It may also be \code{None}, in which case +the file uses the system default encoding for converting Unicode +strings. + +\versionadded{2.3} +\end{memberdesc} + +\begin{memberdesc}[file]{mode} +The I/O mode for the file. If the file was created using the +\function{open()} built-in function, this will be the value of the +\var{mode} parameter. This is a read-only attribute and may not be +present on all file-like objects. +\end{memberdesc} + +\begin{memberdesc}[file]{name} +If the file object was created using \function{open()}, the name of +the file. Otherwise, some string that indicates the source of the +file object, of the form \samp{<\mbox{\ldots}>}. This is a read-only +attribute and may not be present on all file-like objects. +\end{memberdesc} + +\begin{memberdesc}[file]{newlines} +If Python was built with the \longprogramopt{with-universal-newlines} +option to \program{configure} (the default) this read-only attribute +exists, and for files opened in +universal newline read mode it keeps track of the types of newlines +encountered while reading the file. The values it can take are +\code{'\e r'}, \code{'\e n'}, \code{'\e r\e n'}, \code{None} (unknown, +no newlines read yet) or a tuple containing all the newline +types seen, to indicate that multiple +newline conventions were encountered. For files not opened in universal +newline read mode the value of this attribute will be \code{None}. +\end{memberdesc} + +\begin{memberdesc}[file]{softspace} +Boolean that indicates whether a space character needs to be printed +before another value when using the \keyword{print} statement. +Classes that are trying to simulate a file object should also have a +writable \member{softspace} attribute, which should be initialized to +zero. This will be automatic for most classes implemented in Python +(care may be needed for objects that override attribute access); types +implemented in C will have to provide a writable +\member{softspace} attribute. +\note{This attribute is not used to control the +\keyword{print} statement, but to allow the implementation of +\keyword{print} to keep track of its internal state.} +\end{memberdesc} + + +\section{Context Manager Types \label{typecontextmanager}} + +\versionadded{2.5} +\index{context manager} +\index{context management protocol} +\index{protocol!context management} + +Python's \keyword{with} statement supports the concept of a runtime +context defined by a context manager. This is implemented using +two separate methods that allow user-defined classes to define +a runtime context that is entered before the statement body is +executed and exited when the statement ends. + +The \dfn{context management protocol} consists of a pair of +methods that need to be provided for a context manager object to +define a runtime context: + +\begin{methoddesc}[context manager]{__enter__}{} + Enter the runtime context and return either this object or another + object related to the runtime context. The value returned by this + method is bound to the identifier in the \keyword{as} clause of + \keyword{with} statements using this context manager. + + An example of a context manager that returns itself is a file object. + File objects return themselves from __enter__() to allow + \function{open()} to be used as the context expression in a + \keyword{with} statement. + + An example of a context manager that returns a related + object is the one returned by \code{decimal.Context.get_manager()}. + These managers set the active decimal context to a copy of the + original decimal context and then return the copy. This allows + changes to be made to the current decimal context in the body of + the \keyword{with} statement without affecting code outside + the \keyword{with} statement. +\end{methoddesc} + +\begin{methoddesc}[context manager]{__exit__}{exc_type, exc_val, exc_tb} + Exit the runtime context and return a Boolean flag indicating if any + expection that occurred should be suppressed. If an exception + occurred while executing the body of the \keyword{with} statement, the + arguments contain the exception type, value and traceback information. + Otherwise, all three arguments are \var{None}. + + Returning a true value from this method will cause the \keyword{with} + statement to suppress the exception and continue execution with the + statement immediately following the \keyword{with} statement. Otherwise + the exception continues propagating after this method has finished + executing. Exceptions that occur during execution of this method will + replace any exception that occurred in the body of the \keyword{with} + statement. + + The exception passed in should never be reraised explicitly - instead, + this method should return a false value to indicate that the method + completed successfully and does not want to suppress the raised + exception. This allows context management code (such as + \code{contextlib.nested}) to easily detect whether or not an + \method{__exit__()} method has actually failed. +\end{methoddesc} + +Python defines several context managers to support easy thread +synchronisation, prompt closure of files or other objects, and +simpler manipulation of the active decimal arithmetic +context. The specific types are not treated specially beyond +their implementation of the context management protocol. + +Python's generators and the \code{contextlib.contextfactory} decorator +provide a convenient way to implement these protocols. If a generator +function is decorated with the \code{contextlib.contextfactory} +decorator, it will return a context manager implementing the necessary +\method{__enter__()} and \method{__exit__()} methods, rather than the +iterator produced by an undecorated generator function. + +Note that there is no specific slot for any of these methods in the +type structure for Python objects in the Python/C API. Extension +types wanting to define these methods must provide them as a normal +Python accessible method. Compared to the overhead of setting up the +runtime context, the overhead of a single class dictionary lookup +is negligible. + + +\section{Other Built-in Types \label{typesother}} + +The interpreter supports several other kinds of objects. +Most of these support only one or two operations. + + +\subsection{Modules \label{typesmodules}} + +The only special operation on a module is attribute access: +\code{\var{m}.\var{name}}, where \var{m} is a module and \var{name} +accesses a name defined in \var{m}'s symbol table. Module attributes +can be assigned to. (Note that the \keyword{import} statement is not, +strictly speaking, an operation on a module object; \code{import +\var{foo}} does not require a module object named \var{foo} to exist, +rather it requires an (external) \emph{definition} for a module named +\var{foo} somewhere.) + +A special member of every module is \member{__dict__}. +This is the dictionary containing the module's symbol table. +Modifying this dictionary will actually change the module's symbol +table, but direct assignment to the \member{__dict__} attribute is not +possible (you can write \code{\var{m}.__dict__['a'] = 1}, which +defines \code{\var{m}.a} to be \code{1}, but you can't write +\code{\var{m}.__dict__ = \{\}}). Modifying \member{__dict__} directly +is not recommended. + +Modules built into the interpreter are written like this: +\code{<module 'sys' (built-in)>}. If loaded from a file, they are +written as \code{<module 'os' from +'/usr/local/lib/python\shortversion/os.pyc'>}. + + +\subsection{Classes and Class Instances \label{typesobjects}} +\nodename{Classes and Instances} + +See chapters 3 and 7 of the \citetitle[../ref/ref.html]{Python +Reference Manual} for these. + + +\subsection{Functions \label{typesfunctions}} + +Function objects are created by function definitions. The only +operation on a function object is to call it: +\code{\var{func}(\var{argument-list})}. + +There are really two flavors of function objects: built-in functions +and user-defined functions. Both support the same operation (to call +the function), but the implementation is different, hence the +different object types. + +See the \citetitle[../ref/ref.html]{Python Reference Manual} for more +information. + +\subsection{Methods \label{typesmethods}} +\obindex{method} + +Methods are functions that are called using the attribute notation. +There are two flavors: built-in methods (such as \method{append()} on +lists) and class instance methods. Built-in methods are described +with the types that support them. + +The implementation adds two special read-only attributes to class +instance methods: \code{\var{m}.im_self} is the object on which the +method operates, and \code{\var{m}.im_func} is the function +implementing the method. Calling \code{\var{m}(\var{arg-1}, +\var{arg-2}, \textrm{\ldots}, \var{arg-n})} is completely equivalent to +calling \code{\var{m}.im_func(\var{m}.im_self, \var{arg-1}, +\var{arg-2}, \textrm{\ldots}, \var{arg-n})}. + +Class instance methods are either \emph{bound} or \emph{unbound}, +referring to whether the method was accessed through an instance or a +class, respectively. When a method is unbound, its \code{im_self} +attribute will be \code{None} and if called, an explicit \code{self} +object must be passed as the first argument. In this case, +\code{self} must be an instance of the unbound method's class (or a +subclass of that class), otherwise a \exception{TypeError} is raised. + +Like function objects, methods objects support getting +arbitrary attributes. However, since method attributes are actually +stored on the underlying function object (\code{meth.im_func}), +setting method attributes on either bound or unbound methods is +disallowed. Attempting to set a method attribute results in a +\exception{TypeError} being raised. In order to set a method attribute, +you need to explicitly set it on the underlying function object: + +\begin{verbatim} +class C: + def method(self): + pass + +c = C() +c.method.im_func.whoami = 'my name is c' +\end{verbatim} + +See the \citetitle[../ref/ref.html]{Python Reference Manual} for more +information. + + +\subsection{Code Objects \label{bltin-code-objects}} +\obindex{code} + +Code objects are used by the implementation to represent +``pseudo-compiled'' executable Python code such as a function body. +They differ from function objects because they don't contain a +reference to their global execution environment. Code objects are +returned by the built-in \function{compile()} function and can be +extracted from function objects through their \member{func_code} +attribute. +\bifuncindex{compile} +\withsubitem{(function object attribute)}{\ttindex{func_code}} + +A code object can be executed or evaluated by passing it (instead of a +source string) to the \keyword{exec} statement or the built-in +\function{eval()} function. +\stindex{exec} +\bifuncindex{eval} + +See the \citetitle[../ref/ref.html]{Python Reference Manual} for more +information. + + +\subsection{Type Objects \label{bltin-type-objects}} + +Type objects represent the various object types. An object's type is +accessed by the built-in function \function{type()}. There are no special +operations on types. The standard module \refmodule{types} defines names +for all standard built-in types. +\bifuncindex{type} +\refstmodindex{types} + +Types are written like this: \code{<type 'int'>}. + + +\subsection{The Null Object \label{bltin-null-object}} + +This object is returned by functions that don't explicitly return a +value. It supports no special operations. There is exactly one null +object, named \code{None} (a built-in name). + +It is written as \code{None}. + + +\subsection{The Ellipsis Object \label{bltin-ellipsis-object}} + +This object is used by extended slice notation (see the +\citetitle[../ref/ref.html]{Python Reference Manual}). It supports no +special operations. There is exactly one ellipsis object, named +\constant{Ellipsis} (a built-in name). + +It is written as \code{Ellipsis}. + +\subsection{Boolean Values} + +Boolean values are the two constant objects \code{False} and +\code{True}. They are used to represent truth values (although other +values can also be considered false or true). In numeric contexts +(for example when used as the argument to an arithmetic operator), +they behave like the integers 0 and 1, respectively. The built-in +function \function{bool()} can be used to cast any value to a Boolean, +if the value can be interpreted as a truth value (see section Truth +Value Testing above). + +They are written as \code{False} and \code{True}, respectively. +\index{False} +\index{True} +\indexii{Boolean}{values} + + +\subsection{Internal Objects \label{typesinternal}} + +See the \citetitle[../ref/ref.html]{Python Reference Manual} for this +information. It describes stack frame objects, traceback objects, and +slice objects. + + +\section{Special Attributes \label{specialattrs}} + +The implementation adds a few special read-only attributes to several +object types, where they are relevant. Some of these are not reported +by the \function{dir()} built-in function. + +\begin{memberdesc}[object]{__dict__} +A dictionary or other mapping object used to store an +object's (writable) attributes. +\end{memberdesc} + +\begin{memberdesc}[object]{__methods__} +\deprecated{2.2}{Use the built-in function \function{dir()} to get a +list of an object's attributes. This attribute is no longer available.} +\end{memberdesc} + +\begin{memberdesc}[object]{__members__} +\deprecated{2.2}{Use the built-in function \function{dir()} to get a +list of an object's attributes. This attribute is no longer available.} +\end{memberdesc} + +\begin{memberdesc}[instance]{__class__} +The class to which a class instance belongs. +\end{memberdesc} + +\begin{memberdesc}[class]{__bases__} +The tuple of base classes of a class object. If there are no base +classes, this will be an empty tuple. +\end{memberdesc} + +\begin{memberdesc}[class]{__name__} +The name of the class or type. +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/lib/libstdwin.tex b/sys/src/cmd/python/Doc/lib/libstdwin.tex new file mode 100644 index 000000000..84aad2f48 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstdwin.tex @@ -0,0 +1,832 @@ +\chapter{Standard Windowing Interface} + +The modules in this chapter are available only on those systems where +the STDWIN library is available. STDWIN runs on \UNIX{} under X11 and +on the Macintosh. See CWI report CS-R8817. + +\warning{Using STDWIN is not recommended for new +applications. It has never been ported to Microsoft Windows or +Windows NT, and for X11 or the Macintosh it lacks important +functionality --- in particular, it has no tools for the construction +of dialogs. For most platforms, alternative, native solutions exist +(though none are currently documented in this manual): Tkinter for +\UNIX{} under X11, native Xt with Motif or Athena widgets for \UNIX{} +under X11, Win32 for Windows and Windows NT, and a collection of +native toolkit interfaces for the Macintosh.} + + +\section{\module{stdwin} --- + Platform-independent Graphical User Interface System} + +\declaremodule{builtin}{stdwin} +\modulesynopsis{Older graphical user interface system for X11 and Macintosh.} + + +This module defines several new object types and functions that +provide access to the functionality of STDWIN. + +On \UNIX{} running X11, it can only be used if the \envvar{DISPLAY} +environment variable is set or an explicit +\programopt{-display} \var{displayname} argument is passed to the +Python interpreter. + +Functions have names that usually resemble their C STDWIN counterparts +with the initial `w' dropped. Points are represented by pairs of +integers; rectangles by pairs of points. For a complete description +of STDWIN please refer to the documentation of STDWIN for C +programmers (aforementioned CWI report). + +\subsection{Functions Defined in Module \module{stdwin}} +\nodename{STDWIN Functions} + +The following functions are defined in the \module{stdwin} module: + +\begin{funcdesc}{open}{title} +Open a new window whose initial title is given by the string argument. +Return a window object; window object methods are described +below.\footnote{ + The Python version of STDWIN does not support draw procedures; + all drawing requests are reported as draw events.} +\end{funcdesc} + +\begin{funcdesc}{getevent}{} +Wait for and return the next event. +An event is returned as a triple: the first element is the event +type, a small integer; the second element is the window object to which +the event applies, or +\code{None} +if it applies to no window in particular; +the third element is type-dependent. +Names for event types and command codes are defined in the standard +module \refmodule{stdwinevents}. +\end{funcdesc} + +\begin{funcdesc}{pollevent}{} +Return the next event, if one is immediately available. +If no event is available, return \code{()}. +\end{funcdesc} + +\begin{funcdesc}{getactive}{} +Return the window that is currently active, or \code{None} if no +window is currently active. (This can be emulated by monitoring +WE_ACTIVATE and WE_DEACTIVATE events.) +\end{funcdesc} + +\begin{funcdesc}{listfontnames}{pattern} +Return the list of font names in the system that match the pattern (a +string). The pattern should normally be \code{'*'}; returns all +available fonts. If the underlying window system is X11, other +patterns follow the standard X11 font selection syntax (as used e.g. +in resource definitions), i.e. the wildcard character \code{'*'} +matches any sequence of characters (including none) and \code{'?'} +matches any single character. +On the Macintosh this function currently returns an empty list. +\end{funcdesc} + +\begin{funcdesc}{setdefscrollbars}{hflag, vflag} +Set the flags controlling whether subsequently opened windows will +have horizontal and/or vertical scroll bars. +\end{funcdesc} + +\begin{funcdesc}{setdefwinpos}{h, v} +Set the default window position for windows opened subsequently. +\end{funcdesc} + +\begin{funcdesc}{setdefwinsize}{width, height} +Set the default window size for windows opened subsequently. +\end{funcdesc} + +\begin{funcdesc}{getdefscrollbars}{} +Return the flags controlling whether subsequently opened windows will +have horizontal and/or vertical scroll bars. +\end{funcdesc} + +\begin{funcdesc}{getdefwinpos}{} +Return the default window position for windows opened subsequently. +\end{funcdesc} + +\begin{funcdesc}{getdefwinsize}{} +Return the default window size for windows opened subsequently. +\end{funcdesc} + +\begin{funcdesc}{getscrsize}{} +Return the screen size in pixels. +\end{funcdesc} + +\begin{funcdesc}{getscrmm}{} +Return the screen size in millimetres. +\end{funcdesc} + +\begin{funcdesc}{fetchcolor}{colorname} +Return the pixel value corresponding to the given color name. +Return the default foreground color for unknown color names. +Hint: the following code tests whether you are on a machine that +supports more than two colors: +\begin{verbatim} +if stdwin.fetchcolor('black') <> \ + stdwin.fetchcolor('red') <> \ + stdwin.fetchcolor('white'): + print 'color machine' +else: + print 'monochrome machine' +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{setfgcolor}{pixel} +Set the default foreground color. +This will become the default foreground color of windows opened +subsequently, including dialogs. +\end{funcdesc} + +\begin{funcdesc}{setbgcolor}{pixel} +Set the default background color. +This will become the default background color of windows opened +subsequently, including dialogs. +\end{funcdesc} + +\begin{funcdesc}{getfgcolor}{} +Return the pixel value of the current default foreground color. +\end{funcdesc} + +\begin{funcdesc}{getbgcolor}{} +Return the pixel value of the current default background color. +\end{funcdesc} + +\begin{funcdesc}{setfont}{fontname} +Set the current default font. +This will become the default font for windows opened subsequently, +and is also used by the text measuring functions \function{textwidth()}, +\function{textbreak()}, \function{lineheight()} and +\function{baseline()} below. This accepts two more optional +parameters, size and style: Size is the font size (in `points'). +Style is a single character specifying the style, as follows: +\code{'b'} = bold, +\code{'i'} = italic, +\code{'o'} = bold + italic, +\code{'u'} = underline; +default style is roman. +Size and style are ignored under X11 but used on the Macintosh. +(Sorry for all this complexity --- a more uniform interface is being designed.) +\end{funcdesc} + +\begin{funcdesc}{menucreate}{title} +Create a menu object referring to a global menu (a menu that appears in +all windows). +Methods of menu objects are described below. +Note: normally, menus are created locally; see the window method +\method{menucreate()} below. +\warning{The menu only appears in a window as long as the object +returned by this call exists.} +\end{funcdesc} + +\begin{funcdesc}{newbitmap}{width, height} +Create a new bitmap object of the given dimensions. +Methods of bitmap objects are described below. +Not available on the Macintosh. +\end{funcdesc} + +\begin{funcdesc}{fleep}{} +Cause a beep or bell (or perhaps a `visual bell' or flash, hence the +name). +\end{funcdesc} + +\begin{funcdesc}{message}{string} +Display a dialog box containing the string. +The user must click OK before the function returns. +\end{funcdesc} + +\begin{funcdesc}{askync}{prompt, default} +Display a dialog that prompts the user to answer a question with yes or +no. Return 0 for no, 1 for yes. If the user hits the Return key, the +default (which must be 0 or 1) is returned. If the user cancels the +dialog, \exception{KeyboardInterrupt} is raised. +\end{funcdesc} + +\begin{funcdesc}{askstr}{prompt, default} +Display a dialog that prompts the user for a string. +If the user hits the Return key, the default string is returned. +If the user cancels the dialog, \exception{KeyboardInterrupt} is +raised. +\end{funcdesc} + +\begin{funcdesc}{askfile}{prompt, default, new} +Ask the user to specify a filename. If \var{new} is zero it must be +an existing file; otherwise, it must be a new file. If the user +cancels the dialog, \exception{KeyboardInterrupt} is raised. +\end{funcdesc} + +\begin{funcdesc}{setcutbuffer}{i, string} +Store the string in the system's cut buffer number \var{i}, where it +can be found (for pasting) by other applications. On X11, there are 8 +cut buffers (numbered 0..7). Cut buffer number 0 is the `clipboard' +on the Macintosh. +\end{funcdesc} + +\begin{funcdesc}{getcutbuffer}{i} +Return the contents of the system's cut buffer number \var{i}. +\end{funcdesc} + +\begin{funcdesc}{rotatecutbuffers}{n} +On X11, rotate the 8 cut buffers by \var{n}. Ignored on the +Macintosh. +\end{funcdesc} + +\begin{funcdesc}{getselection}{i} +Return X11 selection number \var{i.} Selections are not cut buffers. +Selection numbers are defined in module \refmodule{stdwinevents}. +Selection \constant{WS_PRIMARY} is the \dfn{primary} selection (used +by \program{xterm}, for instance); selection \constant{WS_SECONDARY} +is the \dfn{secondary} selection; selection \constant{WS_CLIPBOARD} is +the \dfn{clipboard} selection (used by \program{xclipboard}). On the +Macintosh, this always returns an empty string. +\end{funcdesc} + +\begin{funcdesc}{resetselection}{i} +Reset selection number \var{i}, if this process owns it. (See window +method \method{setselection()}). +\end{funcdesc} + +\begin{funcdesc}{baseline}{} +Return the baseline of the current font (defined by STDWIN as the +vertical distance between the baseline and the top of the +characters). +\end{funcdesc} + +\begin{funcdesc}{lineheight}{} +Return the total line height of the current font. +\end{funcdesc} + +\begin{funcdesc}{textbreak}{str, width} +Return the number of characters of the string that fit into a space of +\var{width} +bits wide when drawn in the current font. +\end{funcdesc} + +\begin{funcdesc}{textwidth}{str} +Return the width in bits of the string when drawn in the current font. +\end{funcdesc} + +\begin{funcdesc}{connectionnumber}{} +\funcline{fileno}{} +(X11 under \UNIX{} only) Return the ``connection number'' used by the +underlying X11 implementation. (This is normally the file number of +the socket.) Both functions return the same value; +\method{connectionnumber()} is named after the corresponding function in +X11 and STDWIN, while \method{fileno()} makes it possible to use the +\module{stdwin} module as a ``file'' object parameter to +\function{select.select()}. Note that if \constant{select()} implies that +input is possible on \module{stdwin}, this does not guarantee that an +event is ready --- it may be some internal communication going on +between the X server and the client library. Thus, you should call +\function{stdwin.pollevent()} until it returns \code{None} to check for +events if you don't want your program to block. Because of internal +buffering in X11, it is also possible that \function{stdwin.pollevent()} +returns an event while \function{select()} does not find \module{stdwin} to +be ready, so you should read any pending events with +\function{stdwin.pollevent()} until it returns \code{None} before entering +a blocking \function{select()} call. +\withsubitem{(in module select)}{\ttindex{select()}} +\end{funcdesc} + +\subsection{Window Objects} +\nodename{STDWIN Window Objects} + +Window objects are created by \function{stdwin.open()}. They are closed +by their \method{close()} method or when they are garbage-collected. +Window objects have the following methods: + +\begin{methoddesc}[window]{begindrawing}{} +Return a drawing object, whose methods (described below) allow drawing +in the window. +\end{methoddesc} + +\begin{methoddesc}[window]{change}{rect} +Invalidate the given rectangle; this may cause a draw event. +\end{methoddesc} + +\begin{methoddesc}[window]{gettitle}{} +Returns the window's title string. +\end{methoddesc} + +\begin{methoddesc}[window]{getdocsize}{} +\begin{sloppypar} +Return a pair of integers giving the size of the document as set by +\method{setdocsize()}. +\end{sloppypar} +\end{methoddesc} + +\begin{methoddesc}[window]{getorigin}{} +Return a pair of integers giving the origin of the window with respect +to the document. +\end{methoddesc} + +\begin{methoddesc}[window]{gettitle}{} +Return the window's title string. +\end{methoddesc} + +\begin{methoddesc}[window]{getwinsize}{} +Return a pair of integers giving the size of the window. +\end{methoddesc} + +\begin{methoddesc}[window]{getwinpos}{} +Return a pair of integers giving the position of the window's upper +left corner (relative to the upper left corner of the screen). +\end{methoddesc} + +\begin{methoddesc}[window]{menucreate}{title} +Create a menu object referring to a local menu (a menu that appears +only in this window). +Methods of menu objects are described below. +\warning{The menu only appears as long as the object +returned by this call exists.} +\end{methoddesc} + +\begin{methoddesc}[window]{scroll}{rect, point} +Scroll the given rectangle by the vector given by the point. +\end{methoddesc} + +\begin{methoddesc}[window]{setdocsize}{point} +Set the size of the drawing document. +\end{methoddesc} + +\begin{methoddesc}[window]{setorigin}{point} +Move the origin of the window (its upper left corner) +to the given point in the document. +\end{methoddesc} + +\begin{methoddesc}[window]{setselection}{i, str} +Attempt to set X11 selection number \var{i} to the string \var{str}. +(See \module{stdwin} function \function{getselection()} for the +meaning of \var{i}.) Return true if it succeeds. +If succeeds, the window ``owns'' the selection until +(a) another application takes ownership of the selection; or +(b) the window is deleted; or +(c) the application clears ownership by calling +\function{stdwin.resetselection(\var{i})}. When another application +takes ownership of the selection, a \constant{WE_LOST_SEL} event is +received for no particular window and with the selection number as +detail. Ignored on the Macintosh. +\end{methoddesc} + +\begin{methoddesc}[window]{settimer}{dsecs} +Schedule a timer event for the window in \code{\var{dsecs}/10} +seconds. +\end{methoddesc} + +\begin{methoddesc}[window]{settitle}{title} +Set the window's title string. +\end{methoddesc} + +\begin{methoddesc}[window]{setwincursor}{name} +\begin{sloppypar} +Set the window cursor to a cursor of the given name. It raises +\exception{RuntimeError} if no cursor of the given name exists. +Suitable names include +\code{'ibeam'}, +\code{'arrow'}, +\code{'cross'}, +\code{'watch'} +and +\code{'plus'}. +On X11, there are many more (see \code{<X11/cursorfont.h>}). +\end{sloppypar} +\end{methoddesc} + +\begin{methoddesc}[window]{setwinpos}{h, v} +Set the position of the window's upper left corner (relative to +the upper left corner of the screen). +\end{methoddesc} + +\begin{methoddesc}[window]{setwinsize}{width, height} +Set the window's size. +\end{methoddesc} + +\begin{methoddesc}[window]{show}{rect} +Try to ensure that the given rectangle of the document is visible in +the window. +\end{methoddesc} + +\begin{methoddesc}[window]{textcreate}{rect} +Create a text-edit object in the document at the given rectangle. +Methods of text-edit objects are described below. +\end{methoddesc} + +\begin{methoddesc}[window]{setactive}{} +Attempt to make this window the active window. If successful, this +will generate a WE_ACTIVATE event (and a WE_DEACTIVATE event in case +another window in this application became inactive). +\end{methoddesc} + +\begin{methoddesc}[window]{close}{} +Discard the window object. It should not be used again. +\end{methoddesc} + +\subsection{Drawing Objects} + +Drawing objects are created exclusively by the window method +\method{begindrawing()}. Only one drawing object can exist at any +given time; the drawing object must be deleted to finish drawing. No +drawing object may exist when \function{stdwin.getevent()} is called. +Drawing objects have the following methods: + +\begin{methoddesc}[drawing]{box}{rect} +Draw a box just inside a rectangle. +\end{methoddesc} + +\begin{methoddesc}[drawing]{circle}{center, radius} +Draw a circle with given center point and radius. +\end{methoddesc} + +\begin{methoddesc}[drawing]{elarc}{center, (rh, rv), (a1, a2)} +Draw an elliptical arc with given center point. +\code{(\var{rh}, \var{rv})} +gives the half sizes of the horizontal and vertical radii. +\code{(\var{a1}, \var{a2})} +gives the angles (in degrees) of the begin and end points. +0 degrees is at 3 o'clock, 90 degrees is at 12 o'clock. +\end{methoddesc} + +\begin{methoddesc}[drawing]{erase}{rect} +Erase a rectangle. +\end{methoddesc} + +\begin{methoddesc}[drawing]{fillcircle}{center, radius} +Draw a filled circle with given center point and radius. +\end{methoddesc} + +\begin{methoddesc}[drawing]{fillelarc}{center, (rh, rv), (a1, a2)} +Draw a filled elliptical arc; arguments as for \method{elarc()}. +\end{methoddesc} + +\begin{methoddesc}[drawing]{fillpoly}{points} +Draw a filled polygon given by a list (or tuple) of points. +\end{methoddesc} + +\begin{methoddesc}[drawing]{invert}{rect} +Invert a rectangle. +\end{methoddesc} + +\begin{methoddesc}[drawing]{line}{p1, p2} +Draw a line from point +\var{p1} +to +\var{p2}. +\end{methoddesc} + +\begin{methoddesc}[drawing]{paint}{rect} +Fill a rectangle. +\end{methoddesc} + +\begin{methoddesc}[drawing]{poly}{points} +Draw the lines connecting the given list (or tuple) of points. +\end{methoddesc} + +\begin{methoddesc}[drawing]{shade}{rect, percent} +Fill a rectangle with a shading pattern that is about +\var{percent} +percent filled. +\end{methoddesc} + +\begin{methoddesc}[drawing]{text}{p, str} +Draw a string starting at point p (the point specifies the +top left coordinate of the string). +\end{methoddesc} + +\begin{methoddesc}[drawing]{xorcircle}{center, radius} +\funcline{xorelarc}{center, (rh, rv), (a1, a2)} +\funcline{xorline}{p1, p2} +\funcline{xorpoly}{points} +Draw a circle, an elliptical arc, a line or a polygon, respectively, +in XOR mode. +\end{methoddesc} + +\begin{methoddesc}[drawing]{setfgcolor}{} +\funcline{setbgcolor}{} +\funcline{getfgcolor}{} +\funcline{getbgcolor}{} +These functions are similar to the corresponding functions described +above for the \module{stdwin} +module, but affect or return the colors currently used for drawing +instead of the global default colors. +When a drawing object is created, its colors are set to the window's +default colors, which are in turn initialized from the global default +colors when the window is created. +\end{methoddesc} + +\begin{methoddesc}[drawing]{setfont}{} +\funcline{baseline}{} +\funcline{lineheight}{} +\funcline{textbreak}{} +\funcline{textwidth}{} +These functions are similar to the corresponding functions described +above for the \module{stdwin} +module, but affect or use the current drawing font instead of +the global default font. +When a drawing object is created, its font is set to the window's +default font, which is in turn initialized from the global default +font when the window is created. +\end{methoddesc} + +\begin{methoddesc}[drawing]{bitmap}{point, bitmap, mask} +Draw the \var{bitmap} with its top left corner at \var{point}. +If the optional \var{mask} argument is present, it should be either +the same object as \var{bitmap}, to draw only those bits that are set +in the bitmap, in the foreground color, or \code{None}, to draw all +bits (ones are drawn in the foreground color, zeros in the background +color). +Not available on the Macintosh. +\end{methoddesc} + +\begin{methoddesc}[drawing]{cliprect}{rect} +Set the ``clipping region'' to a rectangle. +The clipping region limits the effect of all drawing operations, until +it is changed again or until the drawing object is closed. When a +drawing object is created the clipping region is set to the entire +window. When an object to be drawn falls partly outside the clipping +region, the set of pixels drawn is the intersection of the clipping +region and the set of pixels that would be drawn by the same operation +in the absence of a clipping region. +\end{methoddesc} + +\begin{methoddesc}[drawing]{noclip}{} +Reset the clipping region to the entire window. +\end{methoddesc} + +\begin{methoddesc}[drawing]{close}{} +\funcline{enddrawing}{} +Discard the drawing object. It should not be used again. +\end{methoddesc} + +\subsection{Menu Objects} + +A menu object represents a menu. +The menu is destroyed when the menu object is deleted. +The following methods are defined: + + +\begin{methoddesc}[menu]{additem}{text, shortcut} +Add a menu item with given text. +The shortcut must be a string of length 1, or omitted (to specify no +shortcut). +\end{methoddesc} + +\begin{methoddesc}[menu]{setitem}{i, text} +Set the text of item number \var{i}. +\end{methoddesc} + +\begin{methoddesc}[menu]{enable}{i, flag} +Enable or disables item \var{i}. +\end{methoddesc} + +\begin{methoddesc}[menu]{check}{i, flag} +Set or clear the \dfn{check mark} for item \var{i}. +\end{methoddesc} + +\begin{methoddesc}[menu]{close}{} +Discard the menu object. It should not be used again. +\end{methoddesc} + +\subsection{Bitmap Objects} + +A bitmap represents a rectangular array of bits. +The top left bit has coordinate (0, 0). +A bitmap can be drawn with the \method{bitmap()} method of a drawing object. +Bitmaps are currently not available on the Macintosh. + +The following methods are defined: + + +\begin{methoddesc}[bitmap]{getsize}{} +Return a tuple representing the width and height of the bitmap. +(This returns the values that have been passed to the +\function{newbitmap()} function.) +\end{methoddesc} + +\begin{methoddesc}[bitmap]{setbit}{point, bit} +Set the value of the bit indicated by \var{point} to \var{bit}. +\end{methoddesc} + +\begin{methoddesc}[bitmap]{getbit}{point} +Return the value of the bit indicated by \var{point}. +\end{methoddesc} + +\begin{methoddesc}[bitmap]{close}{} +Discard the bitmap object. It should not be used again. +\end{methoddesc} + +\subsection{Text-edit Objects} + +A text-edit object represents a text-edit block. +For semantics, see the STDWIN documentation for \C{} programmers. +The following methods exist: + + +\begin{methoddesc}[text-edit]{arrow}{code} +Pass an arrow event to the text-edit block. +The \var{code} must be one of \constant{WC_LEFT}, \constant{WC_RIGHT}, +\constant{WC_UP} or \constant{WC_DOWN} (see module +\refmodule{stdwinevents}). +\end{methoddesc} + +\begin{methoddesc}[text-edit]{draw}{rect} +Pass a draw event to the text-edit block. +The rectangle specifies the redraw area. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{event}{type, window, detail} +Pass an event gotten from +\function{stdwin.getevent()} +to the text-edit block. +Return true if the event was handled. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{getfocus}{} +Return 2 integers representing the start and end positions of the +focus, usable as slice indices on the string returned by +\method{gettext()}. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{getfocustext}{} +Return the text in the focus. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{getrect}{} +Return a rectangle giving the actual position of the text-edit block. +(The bottom coordinate may differ from the initial position because +the block automatically shrinks or grows to fit.) +\end{methoddesc} + +\begin{methoddesc}[text-edit]{gettext}{} +Return the entire text buffer. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{move}{rect} +Specify a new position for the text-edit block in the document. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{replace}{str} +Replace the text in the focus by the given string. +The new focus is an insert point at the end of the string. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{setfocus}{i, j} +Specify the new focus. +Out-of-bounds values are silently clipped. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{settext}{str} +Replace the entire text buffer by the given string and set the focus +to \code{(0, 0)}. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{setview}{rect} +Set the view rectangle to \var{rect}. If \var{rect} is \code{None}, +viewing mode is reset. In viewing mode, all output from the text-edit +object is clipped to the viewing rectangle. This may be useful to +implement your own scrolling text subwindow. +\end{methoddesc} + +\begin{methoddesc}[text-edit]{close}{} +Discard the text-edit object. It should not be used again. +\end{methoddesc} + +\subsection{Example} +\nodename{STDWIN Example} + +Here is a minimal example of using STDWIN in Python. +It creates a window and draws the string ``Hello world'' in the top +left corner of the window. +The window will be correctly redrawn when covered and re-exposed. +The program quits when the close icon or menu item is requested. + +\begin{verbatim} +import stdwin +from stdwinevents import * + +def main(): + mywin = stdwin.open('Hello') + # + while 1: + (type, win, detail) = stdwin.getevent() + if type == WE_DRAW: + draw = win.begindrawing() + draw.text((0, 0), 'Hello, world') + del draw + elif type == WE_CLOSE: + break + +main() +\end{verbatim} + + +\section{\module{stdwinevents} --- + Constants for use with \module{stdwin}} + +\declaremodule{standard}{stdwinevents} +\modulesynopsis{Constant definitions for use with \module{stdwin}} + + +This module defines constants used by STDWIN for event types +(\constant{WE_ACTIVATE} etc.), command codes (\constant{WC_LEFT} etc.) +and selection types (\constant{WS_PRIMARY} etc.). +Read the file for details. +Suggested usage is + +\begin{verbatim} +>>> from stdwinevents import * +>>> +\end{verbatim} + + +\section{\module{rect} --- + Functions for use with \module{stdwin}} + +\declaremodule{standard}{rect} +\modulesynopsis{Geometry-related utility function for use with + \module{stdwin}.} + + +This module contains useful operations on rectangles. +A rectangle is defined as in module \refmodule{stdwin}: +a pair of points, where a point is a pair of integers. +For example, the rectangle + +\begin{verbatim} +(10, 20), (90, 80) +\end{verbatim} + +is a rectangle whose left, top, right and bottom edges are 10, 20, 90 +and 80, respectively. Note that the positive vertical axis points +down (as in \refmodule{stdwin}). + +The module defines the following objects: + +\begin{excdesc}{error} +The exception raised by functions in this module when they detect an +error. The exception argument is a string describing the problem in +more detail. +\end{excdesc} + +\begin{datadesc}{empty} +The rectangle returned when some operations return an empty result. +This makes it possible to quickly check whether a result is empty: + +\begin{verbatim} +>>> import rect +>>> r1 = (10, 20), (90, 80) +>>> r2 = (0, 0), (10, 20) +>>> r3 = rect.intersect([r1, r2]) +>>> if r3 is rect.empty: print 'Empty intersection' +Empty intersection +>>> +\end{verbatim} +\end{datadesc} + +\begin{funcdesc}{is_empty}{r} +Returns true if the given rectangle is empty. +A rectangle +\code{(\var{left}, \var{top}), (\var{right}, \var{bottom})} +is empty if +\begin{math}\var{left} \geq \var{right}\end{math} or +\begin{math}\var{top} \geq \var{bottom}\end{math}. +\end{funcdesc} + +\begin{funcdesc}{intersect}{list} +Returns the intersection of all rectangles in the list argument. +It may also be called with a tuple argument. Raises +\exception{rect.error} if the list is empty. Returns +\constant{rect.empty} if the intersection of the rectangles is empty. +\end{funcdesc} + +\begin{funcdesc}{union}{list} +Returns the smallest rectangle that contains all non-empty rectangles in +the list argument. It may also be called with a tuple argument or +with two or more rectangles as arguments. Returns +\constant{rect.empty} if the list is empty or all its rectangles are +empty. +\end{funcdesc} + +\begin{funcdesc}{pointinrect}{point, rect} +Returns true if the point is inside the rectangle. By definition, a +point \code{(\var{h}, \var{v})} is inside a rectangle +\code{(\var{left}, \var{top}), (\var{right}, \var{bottom})} if +\begin{math}\var{left} \leq \var{h} < \var{right}\end{math} and +\begin{math}\var{top} \leq \var{v} < \var{bottom}\end{math}. +\end{funcdesc} + +\begin{funcdesc}{inset}{rect, (dh, dv)} +Returns a rectangle that lies inside the \var{rect} argument by +\var{dh} pixels horizontally and \var{dv} pixels vertically. If +\var{dh} or \var{dv} is negative, the result lies outside \var{rect}. +\end{funcdesc} + +\begin{funcdesc}{rect2geom}{rect} +Converts a rectangle to geometry representation: +\code{(\var{left}, \var{top}), (\var{width}, \var{height})}. +\end{funcdesc} + +\begin{funcdesc}{geom2rect}{geom} +Converts a rectangle given in geometry representation back to the +standard rectangle representation +\code{(\var{left}, \var{top}), (\var{right}, \var{bottom})}. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libstring.tex b/sys/src/cmd/python/Doc/lib/libstring.tex new file mode 100644 index 000000000..bc1649fdb --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstring.tex @@ -0,0 +1,451 @@ +\section{\module{string} --- + Common string operations} + +\declaremodule{standard}{string} +\modulesynopsis{Common string operations.} + +The \module{string} module contains a number of useful constants and classes, +as well as some deprecated legacy functions that are also available as methods +on strings. See the module \refmodule{re}\refstmodindex{re} for string +functions based on regular expressions. + +\subsection{String constants} + +The constants defined in this module are: + +\begin{datadesc}{ascii_letters} + The concatenation of the \constant{ascii_lowercase} and + \constant{ascii_uppercase} constants described below. This value is + not locale-dependent. +\end{datadesc} + +\begin{datadesc}{ascii_lowercase} + The lowercase letters \code{'abcdefghijklmnopqrstuvwxyz'}. This + value is not locale-dependent and will not change. +\end{datadesc} + +\begin{datadesc}{ascii_uppercase} + The uppercase letters \code{'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}. This + value is not locale-dependent and will not change. +\end{datadesc} + +\begin{datadesc}{digits} + The string \code{'0123456789'}. +\end{datadesc} + +\begin{datadesc}{hexdigits} + The string \code{'0123456789abcdefABCDEF'}. +\end{datadesc} + +\begin{datadesc}{letters} + The concatenation of the strings \constant{lowercase} and + \constant{uppercase} described below. The specific value is + locale-dependent, and will be updated when + \function{locale.setlocale()} is called. +\end{datadesc} + +\begin{datadesc}{lowercase} + A string containing all the characters that are considered lowercase + letters. On most systems this is the string + \code{'abcdefghijklmnopqrstuvwxyz'}. Do not change its definition --- + the effect on the routines \function{upper()} and + \function{swapcase()} is undefined. The specific value is + locale-dependent, and will be updated when + \function{locale.setlocale()} is called. +\end{datadesc} + +\begin{datadesc}{octdigits} + The string \code{'01234567'}. +\end{datadesc} + +\begin{datadesc}{punctuation} + String of \ASCII{} characters which are considered punctuation + characters in the \samp{C} locale. +\end{datadesc} + +\begin{datadesc}{printable} + String of characters which are considered printable. This is a + combination of \constant{digits}, \constant{letters}, + \constant{punctuation}, and \constant{whitespace}. +\end{datadesc} + +\begin{datadesc}{uppercase} + A string containing all the characters that are considered uppercase + letters. On most systems this is the string + \code{'ABCDEFGHIJKLMNOPQRSTUVWXYZ'}. Do not change its definition --- + the effect on the routines \function{lower()} and + \function{swapcase()} is undefined. The specific value is + locale-dependent, and will be updated when + \function{locale.setlocale()} is called. +\end{datadesc} + +\begin{datadesc}{whitespace} + A string containing all characters that are considered whitespace. + On most systems this includes the characters space, tab, linefeed, + return, formfeed, and vertical tab. Do not change its definition --- + the effect on the routines \function{strip()} and \function{split()} + is undefined. +\end{datadesc} + +\subsection{Template strings} + +Templates provide simpler string substitutions as described in \pep{292}. +Instead of the normal \samp{\%}-based substitutions, Templates support +\samp{\$}-based substitutions, using the following rules: + +\begin{itemize} +\item \samp{\$\$} is an escape; it is replaced with a single \samp{\$}. + +\item \samp{\$identifier} names a substitution placeholder matching a mapping + key of "identifier". By default, "identifier" must spell a Python + identifier. The first non-identifier character after the \samp{\$} + character terminates this placeholder specification. + +\item \samp{\$\{identifier\}} is equivalent to \samp{\$identifier}. It is + required when valid identifier characters follow the placeholder but are + not part of the placeholder, such as "\$\{noun\}ification". +\end{itemize} + +Any other appearance of \samp{\$} in the string will result in a +\exception{ValueError} being raised. + +\versionadded{2.4} + +The \module{string} module provides a \class{Template} class that implements +these rules. The methods of \class{Template} are: + +\begin{classdesc}{Template}{template} +The constructor takes a single argument which is the template string. +\end{classdesc} + +\begin{methoddesc}[Template]{substitute}{mapping\optional{, **kws}} +Performs the template substitution, returning a new string. \var{mapping} is +any dictionary-like object with keys that match the placeholders in the +template. Alternatively, you can provide keyword arguments, where the +keywords are the placeholders. When both \var{mapping} and \var{kws} are +given and there are duplicates, the placeholders from \var{kws} take +precedence. +\end{methoddesc} + +\begin{methoddesc}[Template]{safe_substitute}{mapping\optional{, **kws}} +Like \method{substitute()}, except that if placeholders are missing from +\var{mapping} and \var{kws}, instead of raising a \exception{KeyError} +exception, the original placeholder will appear in the resulting string +intact. Also, unlike with \method{substitute()}, any other appearances of the +\samp{\$} will simply return \samp{\$} instead of raising +\exception{ValueError}. + +While other exceptions may still occur, this method is called ``safe'' because +substitutions always tries to return a usable string instead of raising an +exception. In another sense, \method{safe_substitute()} may be anything other +than safe, since it will silently ignore malformed templates containing +dangling delimiters, unmatched braces, or placeholders that are not valid +Python identifiers. +\end{methoddesc} + +\class{Template} instances also provide one public data attribute: + +\begin{memberdesc}[string]{template} +This is the object passed to the constructor's \var{template} argument. In +general, you shouldn't change it, but read-only access is not enforced. +\end{memberdesc} + +Here is an example of how to use a Template: + +\begin{verbatim} +>>> from string import Template +>>> s = Template('$who likes $what') +>>> s.substitute(who='tim', what='kung pao') +'tim likes kung pao' +>>> d = dict(who='tim') +>>> Template('Give $who $100').substitute(d) +Traceback (most recent call last): +[...] +ValueError: Invalid placeholder in string: line 1, col 10 +>>> Template('$who likes $what').substitute(d) +Traceback (most recent call last): +[...] +KeyError: 'what' +>>> Template('$who likes $what').safe_substitute(d) +'tim likes $what' +\end{verbatim} + +Advanced usage: you can derive subclasses of \class{Template} to customize the +placeholder syntax, delimiter character, or the entire regular expression used +to parse template strings. To do this, you can override these class +attributes: + +\begin{itemize} +\item \var{delimiter} -- This is the literal string describing a placeholder + introducing delimiter. The default value \samp{\$}. Note that this + should \emph{not} be a regular expression, as the implementation will + call \method{re.escape()} on this string as needed. +\item \var{idpattern} -- This is the regular expression describing the pattern + for non-braced placeholders (the braces will be added automatically as + appropriate). The default value is the regular expression + \samp{[_a-z][_a-z0-9]*}. +\end{itemize} + +Alternatively, you can provide the entire regular expression pattern by +overriding the class attribute \var{pattern}. If you do this, the value must +be a regular expression object with four named capturing groups. The +capturing groups correspond to the rules given above, along with the invalid +placeholder rule: + +\begin{itemize} +\item \var{escaped} -- This group matches the escape sequence, + e.g. \samp{\$\$}, in the default pattern. +\item \var{named} -- This group matches the unbraced placeholder name; it + should not include the delimiter in capturing group. +\item \var{braced} -- This group matches the brace enclosed placeholder name; + it should not include either the delimiter or braces in the capturing + group. +\item \var{invalid} -- This group matches any other delimiter pattern (usually + a single delimiter), and it should appear last in the regular + expression. +\end{itemize} + +\subsection{String functions} + +The following functions are available to operate on string and Unicode +objects. They are not available as string methods. + +\begin{funcdesc}{capwords}{s} + Split the argument into words using \function{split()}, capitalize + each word using \function{capitalize()}, and join the capitalized + words using \function{join()}. Note that this replaces runs of + whitespace characters by a single space, and removes leading and + trailing whitespace. +\end{funcdesc} + +\begin{funcdesc}{maketrans}{from, to} + Return a translation table suitable for passing to + \function{translate()}, that will map + each character in \var{from} into the character at the same position + in \var{to}; \var{from} and \var{to} must have the same length. + + \warning{Don't use strings derived from \constant{lowercase} + and \constant{uppercase} as arguments; in some locales, these don't have + the same length. For case conversions, always use + \function{lower()} and \function{upper()}.} +\end{funcdesc} + +\subsection{Deprecated string functions} + +The following list of functions are also defined as methods of string and +Unicode objects; see ``String Methods'' (section +\ref{string-methods}) for more information on those. You should consider +these functions as deprecated, although they will not be removed until Python +3.0. The functions defined in this module are: + +\begin{funcdesc}{atof}{s} + \deprecated{2.0}{Use the \function{float()} built-in function.} + Convert a string to a floating point number. The string must have + the standard syntax for a floating point literal in Python, + optionally preceded by a sign (\samp{+} or \samp{-}). Note that + this behaves identical to the built-in function + \function{float()}\bifuncindex{float} when passed a string. + + \note{When passing in a string, values for NaN\index{NaN} + and Infinity\index{Infinity} may be returned, depending on the + underlying C library. The specific set of strings accepted which + cause these values to be returned depends entirely on the C library + and is known to vary.} +\end{funcdesc} + +\begin{funcdesc}{atoi}{s\optional{, base}} + \deprecated{2.0}{Use the \function{int()} built-in function.} + Convert string \var{s} to an integer in the given \var{base}. The + string must consist of one or more digits, optionally preceded by a + sign (\samp{+} or \samp{-}). The \var{base} defaults to 10. If it + is 0, a default base is chosen depending on the leading characters + of the string (after stripping the sign): \samp{0x} or \samp{0X} + means 16, \samp{0} means 8, anything else means 10. If \var{base} + is 16, a leading \samp{0x} or \samp{0X} is always accepted, though + not required. This behaves identically to the built-in function + \function{int()} when passed a string. (Also note: for a more + flexible interpretation of numeric literals, use the built-in + function \function{eval()}\bifuncindex{eval}.) +\end{funcdesc} + +\begin{funcdesc}{atol}{s\optional{, base}} + \deprecated{2.0}{Use the \function{long()} built-in function.} + Convert string \var{s} to a long integer in the given \var{base}. + The string must consist of one or more digits, optionally preceded + by a sign (\samp{+} or \samp{-}). The \var{base} argument has the + same meaning as for \function{atoi()}. A trailing \samp{l} or + \samp{L} is not allowed, except if the base is 0. Note that when + invoked without \var{base} or with \var{base} set to 10, this + behaves identical to the built-in function + \function{long()}\bifuncindex{long} when passed a string. +\end{funcdesc} + +\begin{funcdesc}{capitalize}{word} + Return a copy of \var{word} with only its first character capitalized. +\end{funcdesc} + +\begin{funcdesc}{expandtabs}{s\optional{, tabsize}} + Expand tabs in a string replacing them by one or more spaces, + depending on the current column and the given tab size. The column + number is reset to zero after each newline occurring in the string. + This doesn't understand other non-printing characters or escape + sequences. The tab size defaults to 8. +\end{funcdesc} + +\begin{funcdesc}{find}{s, sub\optional{, start\optional{,end}}} + Return the lowest index in \var{s} where the substring \var{sub} is + found such that \var{sub} is wholly contained in + \code{\var{s}[\var{start}:\var{end}]}. Return \code{-1} on failure. + Defaults for \var{start} and \var{end} and interpretation of + negative values is the same as for slices. +\end{funcdesc} + +\begin{funcdesc}{rfind}{s, sub\optional{, start\optional{, end}}} + Like \function{find()} but find the highest index. +\end{funcdesc} + +\begin{funcdesc}{index}{s, sub\optional{, start\optional{, end}}} + Like \function{find()} but raise \exception{ValueError} when the + substring is not found. +\end{funcdesc} + +\begin{funcdesc}{rindex}{s, sub\optional{, start\optional{, end}}} + Like \function{rfind()} but raise \exception{ValueError} when the + substring is not found. +\end{funcdesc} + +\begin{funcdesc}{count}{s, sub\optional{, start\optional{, end}}} + Return the number of (non-overlapping) occurrences of substring + \var{sub} in string \code{\var{s}[\var{start}:\var{end}]}. + Defaults for \var{start} and \var{end} and interpretation of + negative values are the same as for slices. +\end{funcdesc} + +\begin{funcdesc}{lower}{s} + Return a copy of \var{s}, but with upper case letters converted to + lower case. +\end{funcdesc} + +\begin{funcdesc}{split}{s\optional{, sep\optional{, maxsplit}}} + Return a list of the words of the string \var{s}. If the optional + second argument \var{sep} is absent or \code{None}, the words are + separated by arbitrary strings of whitespace characters (space, tab, + newline, return, formfeed). If the second argument \var{sep} is + present and not \code{None}, it specifies a string to be used as the + word separator. The returned list will then have one more item + than the number of non-overlapping occurrences of the separator in + the string. The optional third argument \var{maxsplit} defaults to + 0. If it is nonzero, at most \var{maxsplit} number of splits occur, + and the remainder of the string is returned as the final element of + the list (thus, the list will have at most \code{\var{maxsplit}+1} + elements). + + The behavior of split on an empty string depends on the value of \var{sep}. + If \var{sep} is not specified, or specified as \code{None}, the result will + be an empty list. If \var{sep} is specified as any string, the result will + be a list containing one element which is an empty string. +\end{funcdesc} + +\begin{funcdesc}{rsplit}{s\optional{, sep\optional{, maxsplit}}} + Return a list of the words of the string \var{s}, scanning \var{s} + from the end. To all intents and purposes, the resulting list of + words is the same as returned by \function{split()}, except when the + optional third argument \var{maxsplit} is explicitly specified and + nonzero. When \var{maxsplit} is nonzero, at most \var{maxsplit} + number of splits -- the \emph{rightmost} ones -- occur, and the remainder + of the string is returned as the first element of the list (thus, the + list will have at most \code{\var{maxsplit}+1} elements). + \versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{splitfields}{s\optional{, sep\optional{, maxsplit}}} + This function behaves identically to \function{split()}. (In the + past, \function{split()} was only used with one argument, while + \function{splitfields()} was only used with two arguments.) +\end{funcdesc} + +\begin{funcdesc}{join}{words\optional{, sep}} + Concatenate a list or tuple of words with intervening occurrences of + \var{sep}. The default value for \var{sep} is a single space + character. It is always true that + \samp{string.join(string.split(\var{s}, \var{sep}), \var{sep})} + equals \var{s}. +\end{funcdesc} + +\begin{funcdesc}{joinfields}{words\optional{, sep}} + This function behaves identically to \function{join()}. (In the past, + \function{join()} was only used with one argument, while + \function{joinfields()} was only used with two arguments.) + Note that there is no \method{joinfields()} method on string + objects; use the \method{join()} method instead. +\end{funcdesc} + +\begin{funcdesc}{lstrip}{s\optional{, chars}} +Return a copy of the string with leading characters removed. If +\var{chars} is omitted or \code{None}, whitespace characters are +removed. If given and not \code{None}, \var{chars} must be a string; +the characters in the string will be stripped from the beginning of +the string this method is called on. +\versionchanged[The \var{chars} parameter was added. The \var{chars} +parameter cannot be passed in earlier 2.2 versions]{2.2.3} +\end{funcdesc} + +\begin{funcdesc}{rstrip}{s\optional{, chars}} +Return a copy of the string with trailing characters removed. If +\var{chars} is omitted or \code{None}, whitespace characters are +removed. If given and not \code{None}, \var{chars} must be a string; +the characters in the string will be stripped from the end of the +string this method is called on. +\versionchanged[The \var{chars} parameter was added. The \var{chars} +parameter cannot be passed in earlier 2.2 versions]{2.2.3} +\end{funcdesc} + +\begin{funcdesc}{strip}{s\optional{, chars}} +Return a copy of the string with leading and trailing characters +removed. If \var{chars} is omitted or \code{None}, whitespace +characters are removed. If given and not \code{None}, \var{chars} +must be a string; the characters in the string will be stripped from +the both ends of the string this method is called on. +\versionchanged[The \var{chars} parameter was added. The \var{chars} +parameter cannot be passed in earlier 2.2 versions]{2.2.3} +\end{funcdesc} + +\begin{funcdesc}{swapcase}{s} + Return a copy of \var{s}, but with lower case letters + converted to upper case and vice versa. +\end{funcdesc} + +\begin{funcdesc}{translate}{s, table\optional{, deletechars}} + Delete all characters from \var{s} that are in \var{deletechars} (if + present), and then translate the characters using \var{table}, which + must be a 256-character string giving the translation for each + character value, indexed by its ordinal. +\end{funcdesc} + +\begin{funcdesc}{upper}{s} + Return a copy of \var{s}, but with lower case letters converted to + upper case. +\end{funcdesc} + +\begin{funcdesc}{ljust}{s, width} +\funcline{rjust}{s, width} +\funcline{center}{s, width} + These functions respectively left-justify, right-justify and center + a string in a field of given width. They return a string that is at + least \var{width} characters wide, created by padding the string + \var{s} with spaces until the given width on the right, left or both + sides. The string is never truncated. +\end{funcdesc} + +\begin{funcdesc}{zfill}{s, width} + Pad a numeric string on the left with zero digits until the given + width is reached. Strings starting with a sign are handled + correctly. +\end{funcdesc} + +\begin{funcdesc}{replace}{str, old, new\optional{, maxreplace}} + Return a copy of string \var{str} with all occurrences of substring + \var{old} replaced by \var{new}. If the optional argument + \var{maxreplace} is given, the first \var{maxreplace} occurrences are + replaced. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libstringio.tex b/sys/src/cmd/python/Doc/lib/libstringio.tex new file mode 100644 index 000000000..24312518f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstringio.tex @@ -0,0 +1,121 @@ +\section{\module{StringIO} --- + Read and write strings as files} + +\declaremodule{standard}{StringIO} +\modulesynopsis{Read and write strings as if they were files.} + + +This module implements a file-like class, \class{StringIO}, +that reads and writes a string buffer (also known as \emph{memory +files}). See the description of file objects for operations (section +\ref{bltin-file-objects}). + +\begin{classdesc}{StringIO}{\optional{buffer}} +When a \class{StringIO} object is created, it can be initialized +to an existing string by passing the string to the constructor. +If no string is given, the \class{StringIO} will start empty. +In both cases, the initial file position starts at zero. + +The \class{StringIO} object can accept either Unicode or 8-bit +strings, but mixing the two may take some care. If both are used, +8-bit strings that cannot be interpreted as 7-bit \ASCII{} (that +use the 8th bit) will cause a \exception{UnicodeError} to be raised +when \method{getvalue()} is called. +\end{classdesc} + +The following methods of \class{StringIO} objects require special +mention: + +\begin{methoddesc}{getvalue}{} +Retrieve the entire contents of the ``file'' at any time before the +\class{StringIO} object's \method{close()} method is called. See the +note above for information about mixing Unicode and 8-bit strings; +such mixing can cause this method to raise \exception{UnicodeError}. +\end{methoddesc} + +\begin{methoddesc}{close}{} +Free the memory buffer. +\end{methoddesc} + +Example usage: + +\begin{verbatim} +import StringIO + +output = StringIO.StringIO() +output.write('First line.\n') +print >>output, 'Second line.' + +# Retrieve file contents -- this will be +# 'First line.\nSecond line.\n' +contents = output.getvalue() + +# Close object and discard memory buffer -- +# .getvalue() will now raise an exception. +output.close() +\end{verbatim} + + +\section{\module{cStringIO} --- + Faster version of \module{StringIO}} + +\declaremodule{builtin}{cStringIO} +\modulesynopsis{Faster version of \module{StringIO}, but not + subclassable.} +\moduleauthor{Jim Fulton}{jim@zope.com} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +The module \module{cStringIO} provides an interface similar to that of +the \refmodule{StringIO} module. Heavy use of \class{StringIO.StringIO} +objects can be made more efficient by using the function +\function{StringIO()} from this module instead. + +Since this module provides a factory function which returns objects of +built-in types, there's no way to build your own version using +subclassing. Use the original \refmodule{StringIO} module in that case. + +Unlike the memory files implemented by the \refmodule{StringIO} +module, those provided by this module are not able to accept Unicode +strings that cannot be encoded as plain \ASCII{} strings. + +Another difference from the \refmodule{StringIO} module is that calling +\function{StringIO()} with a string parameter creates a read-only object. +Unlike an object created without a string parameter, it does not have +write methods. These objects are not generally visible. They turn up in +tracebacks as \class{StringI} and \class{StringO}. + +The following data objects are provided as well: + + +\begin{datadesc}{InputType} + The type object of the objects created by calling + \function{StringIO} with a string parameter. +\end{datadesc} + +\begin{datadesc}{OutputType} + The type object of the objects returned by calling + \function{StringIO} with no parameters. +\end{datadesc} + + +There is a C API to the module as well; refer to the module source for +more information. + +Example usage: + +\begin{verbatim} +import cStringIO + +output = cStringIO.StringIO() +output.write('First line.\n') +print >>output, 'Second line.' + +# Retrieve file contents -- this will be +# 'First line.\nSecond line.\n' +contents = output.getvalue() + +# Close object and discard memory buffer -- +# .getvalue() will now raise an exception. +output.close() +\end{verbatim} + diff --git a/sys/src/cmd/python/Doc/lib/libstringprep.tex b/sys/src/cmd/python/Doc/lib/libstringprep.tex new file mode 100644 index 000000000..2614314cb --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstringprep.tex @@ -0,0 +1,136 @@ +\section{\module{stringprep} --- + Internet String Preparation} + +\declaremodule{standard}{stringprep} +\modulesynopsis{String preparation, as per RFC 3453} +\moduleauthor{Martin v. L\"owis}{martin@v.loewis.de} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} + +\versionadded{2.3} + +When identifying things (such as host names) in the internet, it is +often necessary to compare such identifications for +``equality''. Exactly how this comparison is executed may depend on +the application domain, e.g. whether it should be case-insensitive or +not. It may be also necessary to restrict the possible +identifications, to allow only identifications consisting of +``printable'' characters. + +\rfc{3454} defines a procedure for ``preparing'' Unicode strings in +internet protocols. Before passing strings onto the wire, they are +processed with the preparation procedure, after which they have a +certain normalized form. The RFC defines a set of tables, which can be +combined into profiles. Each profile must define which tables it uses, +and what other optional parts of the \code{stringprep} procedure are +part of the profile. One example of a \code{stringprep} profile is +\code{nameprep}, which is used for internationalized domain names. + +The module \module{stringprep} only exposes the tables from RFC +3454. As these tables would be very large to represent them as +dictionaries or lists, the module uses the Unicode character database +internally. The module source code itself was generated using the +\code{mkstringprep.py} utility. + +As a result, these tables are exposed as functions, not as data +structures. There are two kinds of tables in the RFC: sets and +mappings. For a set, \module{stringprep} provides the ``characteristic +function'', i.e. a function that returns true if the parameter is part +of the set. For mappings, it provides the mapping function: given the +key, it returns the associated value. Below is a list of all functions +available in the module. + +\begin{funcdesc}{in_table_a1}{code} +Determine whether \var{code} is in table{A.1} (Unassigned code points +in Unicode 3.2). +\end{funcdesc} + +\begin{funcdesc}{in_table_b1}{code} +Determine whether \var{code} is in table{B.1} (Commonly mapped to +nothing). +\end{funcdesc} + +\begin{funcdesc}{map_table_b2}{code} +Return the mapped value for \var{code} according to table{B.2} +(Mapping for case-folding used with NFKC). +\end{funcdesc} + +\begin{funcdesc}{map_table_b3}{code} +Return the mapped value for \var{code} according to table{B.3} +(Mapping for case-folding used with no normalization). +\end{funcdesc} + +\begin{funcdesc}{in_table_c11}{code} +Determine whether \var{code} is in table{C.1.1} +(ASCII space characters). +\end{funcdesc} + +\begin{funcdesc}{in_table_c12}{code} +Determine whether \var{code} is in table{C.1.2} +(Non-ASCII space characters). +\end{funcdesc} + +\begin{funcdesc}{in_table_c11_c12}{code} +Determine whether \var{code} is in table{C.1} +(Space characters, union of C.1.1 and C.1.2). +\end{funcdesc} + +\begin{funcdesc}{in_table_c21}{code} +Determine whether \var{code} is in table{C.2.1} +(ASCII control characters). +\end{funcdesc} + +\begin{funcdesc}{in_table_c22}{code} +Determine whether \var{code} is in table{C.2.2} +(Non-ASCII control characters). +\end{funcdesc} + +\begin{funcdesc}{in_table_c21_c22}{code} +Determine whether \var{code} is in table{C.2} +(Control characters, union of C.2.1 and C.2.2). +\end{funcdesc} + +\begin{funcdesc}{in_table_c3}{code} +Determine whether \var{code} is in table{C.3} +(Private use). +\end{funcdesc} + +\begin{funcdesc}{in_table_c4}{code} +Determine whether \var{code} is in table{C.4} +(Non-character code points). +\end{funcdesc} + +\begin{funcdesc}{in_table_c5}{code} +Determine whether \var{code} is in table{C.5} +(Surrogate codes). +\end{funcdesc} + +\begin{funcdesc}{in_table_c6}{code} +Determine whether \var{code} is in table{C.6} +(Inappropriate for plain text). +\end{funcdesc} + +\begin{funcdesc}{in_table_c7}{code} +Determine whether \var{code} is in table{C.7} +(Inappropriate for canonical representation). +\end{funcdesc} + +\begin{funcdesc}{in_table_c8}{code} +Determine whether \var{code} is in table{C.8} +(Change display properties or are deprecated). +\end{funcdesc} + +\begin{funcdesc}{in_table_c9}{code} +Determine whether \var{code} is in table{C.9} +(Tagging characters). +\end{funcdesc} + +\begin{funcdesc}{in_table_d1}{code} +Determine whether \var{code} is in table{D.1} +(Characters with bidirectional property ``R'' or ``AL''). +\end{funcdesc} + +\begin{funcdesc}{in_table_d2}{code} +Determine whether \var{code} is in table{D.2} +(Characters with bidirectional property ``L''). +\end{funcdesc} + diff --git a/sys/src/cmd/python/Doc/lib/libstrings.tex b/sys/src/cmd/python/Doc/lib/libstrings.tex new file mode 100644 index 000000000..f3a31f44a --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstrings.tex @@ -0,0 +1,10 @@ +\chapter{String Services} +\label{strings} + +The modules described in this chapter provide a wide range of string +manipulation operations. Here's an overview: + +\localmoduletable + +Information on the methods of string objects can be found in +section~\ref{string-methods}, ``String Methods.'' diff --git a/sys/src/cmd/python/Doc/lib/libstruct.tex b/sys/src/cmd/python/Doc/lib/libstruct.tex new file mode 100644 index 000000000..2c10be753 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libstruct.tex @@ -0,0 +1,256 @@ +\section{\module{struct} --- + Interpret strings as packed binary data} +\declaremodule{builtin}{struct} + +\modulesynopsis{Interpret strings as packed binary data.} + +\indexii{C}{structures} +\indexiii{packing}{binary}{data} + +This module performs conversions between Python values and C +structs represented as Python strings. It uses \dfn{format strings} +(explained below) as compact descriptions of the lay-out of the C +structs and the intended conversion to/from Python values. This can +be used in handling binary data stored in files or from network +connections, among other sources. + +The module defines the following exception and functions: + + +\begin{excdesc}{error} + Exception raised on various occasions; argument is a string + describing what is wrong. +\end{excdesc} + +\begin{funcdesc}{pack}{fmt, v1, v2, \textrm{\ldots}} + Return a string containing the values + \code{\var{v1}, \var{v2}, \textrm{\ldots}} packed according to the given + format. The arguments must match the values required by the format + exactly. +\end{funcdesc} + +\begin{funcdesc}{pack_into}{fmt, buffer, offset, v1, v2, \moreargs} + Pack the values \code{\var{v1}, \var{v2}, \textrm{\ldots}} according to the given + format, write the packed bytes into the writable \var{buffer} starting at + \var{offset}. + Note that the offset is not an optional argument. + + \versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{unpack}{fmt, string} + Unpack the string (presumably packed by \code{pack(\var{fmt}, + \textrm{\ldots})}) according to the given format. The result is a + tuple even if it contains exactly one item. The string must contain + exactly the amount of data required by the format + (\code{len(\var{string})} must equal \code{calcsize(\var{fmt})}). +\end{funcdesc} + +\begin{funcdesc}{unpack_from}{fmt, buffer\optional{,offset \code{= 0}}} + Unpack the \var{buffer} according to tthe given format. + The result is a tuple even if it contains exactly one item. The + \var{buffer} must contain at least the amount of data required by the + format (\code{len(buffer[offset:])} must be at least + \code{calcsize(\var{fmt})}). + + \versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{calcsize}{fmt} + Return the size of the struct (and hence of the string) + corresponding to the given format. +\end{funcdesc} + +Format characters have the following meaning; the conversion between +C and Python values should be obvious given their types: + +\begin{tableiv}{c|l|l|c}{samp}{Format}{C Type}{Python}{Notes} + \lineiv{x}{pad byte}{no value}{} + \lineiv{c}{\ctype{char}}{string of length 1}{} + \lineiv{b}{\ctype{signed char}}{integer}{} + \lineiv{B}{\ctype{unsigned char}}{integer}{} + \lineiv{h}{\ctype{short}}{integer}{} + \lineiv{H}{\ctype{unsigned short}}{integer}{} + \lineiv{i}{\ctype{int}}{integer}{} + \lineiv{I}{\ctype{unsigned int}}{long}{} + \lineiv{l}{\ctype{long}}{integer}{} + \lineiv{L}{\ctype{unsigned long}}{long}{} + \lineiv{q}{\ctype{long long}}{long}{(1)} + \lineiv{Q}{\ctype{unsigned long long}}{long}{(1)} + \lineiv{f}{\ctype{float}}{float}{} + \lineiv{d}{\ctype{double}}{float}{} + \lineiv{s}{\ctype{char[]}}{string}{} + \lineiv{p}{\ctype{char[]}}{string}{} + \lineiv{P}{\ctype{void *}}{integer}{} +\end{tableiv} + +\noindent +Notes: + +\begin{description} +\item[(1)] + The \character{q} and \character{Q} conversion codes are available in + native mode only if the platform C compiler supports C \ctype{long long}, + or, on Windows, \ctype{__int64}. They are always available in standard + modes. + \versionadded{2.2} +\end{description} + + +A format character may be preceded by an integral repeat count. For +example, the format string \code{'4h'} means exactly the same as +\code{'hhhh'}. + +Whitespace characters between formats are ignored; a count and its +format must not contain whitespace though. + +For the \character{s} format character, the count is interpreted as the +size of the string, not a repeat count like for the other format +characters; for example, \code{'10s'} means a single 10-byte string, while +\code{'10c'} means 10 characters. For packing, the string is +truncated or padded with null bytes as appropriate to make it fit. +For unpacking, the resulting string always has exactly the specified +number of bytes. As a special case, \code{'0s'} means a single, empty +string (while \code{'0c'} means 0 characters). + +The \character{p} format character encodes a "Pascal string", meaning +a short variable-length string stored in a fixed number of bytes. +The count is the total number of bytes stored. The first byte stored is +the length of the string, or 255, whichever is smaller. The bytes +of the string follow. If the string passed in to \function{pack()} is too +long (longer than the count minus 1), only the leading count-1 bytes of the +string are stored. If the string is shorter than count-1, it is padded +with null bytes so that exactly count bytes in all are used. Note that +for \function{unpack()}, the \character{p} format character consumes count +bytes, but that the string returned can never contain more than 255 +characters. + +For the \character{I}, \character{L}, \character{q} and \character{Q} +format characters, the return value is a Python long integer. + +For the \character{P} format character, the return value is a Python +integer or long integer, depending on the size needed to hold a +pointer when it has been cast to an integer type. A \NULL{} pointer will +always be returned as the Python integer \code{0}. When packing pointer-sized +values, Python integer or long integer objects may be used. For +example, the Alpha and Merced processors use 64-bit pointer values, +meaning a Python long integer will be used to hold the pointer; other +platforms use 32-bit pointers and will use a Python integer. + +By default, C numbers are represented in the machine's native format +and byte order, and properly aligned by skipping pad bytes if +necessary (according to the rules used by the C compiler). + +Alternatively, the first character of the format string can be used to +indicate the byte order, size and alignment of the packed data, +according to the following table: + +\begin{tableiii}{c|l|l}{samp}{Character}{Byte order}{Size and alignment} + \lineiii{@}{native}{native} + \lineiii{=}{native}{standard} + \lineiii{<}{little-endian}{standard} + \lineiii{>}{big-endian}{standard} + \lineiii{!}{network (= big-endian)}{standard} +\end{tableiii} + +If the first character is not one of these, \character{@} is assumed. + +Native byte order is big-endian or little-endian, depending on the +host system. For example, Motorola and Sun processors are big-endian; +Intel and DEC processors are little-endian. + +Native size and alignment are determined using the C compiler's +\keyword{sizeof} expression. This is always combined with native byte +order. + +Standard size and alignment are as follows: no alignment is required +for any type (so you have to use pad bytes); +\ctype{short} is 2 bytes; +\ctype{int} and \ctype{long} are 4 bytes; +\ctype{long long} (\ctype{__int64} on Windows) is 8 bytes; +\ctype{float} and \ctype{double} are 32-bit and 64-bit +IEEE floating point numbers, respectively. + +Note the difference between \character{@} and \character{=}: both use +native byte order, but the size and alignment of the latter is +standardized. + +The form \character{!} is available for those poor souls who claim they +can't remember whether network byte order is big-endian or +little-endian. + +There is no way to indicate non-native byte order (force +byte-swapping); use the appropriate choice of \character{<} or +\character{>}. + +The \character{P} format character is only available for the native +byte ordering (selected as the default or with the \character{@} byte +order character). The byte order character \character{=} chooses to +use little- or big-endian ordering based on the host system. The +struct module does not interpret this as native ordering, so the +\character{P} format is not available. + +Examples (all using native byte order, size and alignment, on a +big-endian machine): + +\begin{verbatim} +>>> from struct import * +>>> pack('hhl', 1, 2, 3) +'\x00\x01\x00\x02\x00\x00\x00\x03' +>>> unpack('hhl', '\x00\x01\x00\x02\x00\x00\x00\x03') +(1, 2, 3) +>>> calcsize('hhl') +8 +\end{verbatim} + +Hint: to align the end of a structure to the alignment requirement of +a particular type, end the format with the code for that type with a +repeat count of zero. For example, the format \code{'llh0l'} +specifies two pad bytes at the end, assuming longs are aligned on +4-byte boundaries. This only works when native size and alignment are +in effect; standard size and alignment does not enforce any alignment. + +\begin{seealso} + \seemodule{array}{Packed binary storage of homogeneous data.} + \seemodule{xdrlib}{Packing and unpacking of XDR data.} +\end{seealso} + +\subsection{Struct Objects \label{struct-objects}} + +The \module{struct} module also defines the following type: + +\begin{classdesc}{Struct}{format} + Return a new Struct object which writes and reads binary data according to + the format string \var{format}. Creating a Struct object once and calling + its methods is more efficient than calling the \module{struct} functions + with the same format since the format string only needs to be compiled once. + + \versionadded{2.5} +\end{classdesc} + +Compiled Struct objects support the following methods and attributes: + +\begin{methoddesc}[Struct]{pack}{v1, v2, \moreargs} + Identical to the \function{pack()} function, using the compiled format. + (\code{len(result)} will equal \member{self.size}.) +\end{methoddesc} + +\begin{methoddesc}[Struct]{pack_into}{buffer, offset, v1, v2, \moreargs} + Identical to the \function{pack_into()} function, using the compiled format. +\end{methoddesc} + +\begin{methoddesc}[Struct]{unpack}{string} + Identical to the \function{unpack()} function, using the compiled format. + (\code{len(string)} must equal \member{self.size}). +\end{methoddesc} + +\begin{methoddesc}[Struct]{unpack_from}{buffer\optional{,offset + \code{= 0}}} + Identical to the \function{unpack_from()} function, using the compiled format. + (\code{len(buffer[offset:])} must be at least \member{self.size}). +\end{methoddesc} + +\begin{memberdesc}[Struct]{format} + The format string used to construct this Struct object. +\end{memberdesc} + diff --git a/sys/src/cmd/python/Doc/lib/libsubprocess.tex b/sys/src/cmd/python/Doc/lib/libsubprocess.tex new file mode 100644 index 000000000..f6397105a --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsubprocess.tex @@ -0,0 +1,402 @@ +\section{\module{subprocess} --- Subprocess management} + +\declaremodule{standard}{subprocess} +\modulesynopsis{Subprocess management.} +\moduleauthor{Peter \AA strand}{astrand@lysator.liu.se} +\sectionauthor{Peter \AA strand}{astrand@lysator.liu.se} + +\versionadded{2.4} + +The \module{subprocess} module allows you to spawn new processes, +connect to their input/output/error pipes, and obtain their return +codes. This module intends to replace several other, older modules +and functions, such as: + +\begin{verbatim} +os.system +os.spawn* +os.popen* +popen2.* +commands.* +\end{verbatim} + +Information about how the \module{subprocess} module can be used to +replace these modules and functions can be found in the following +sections. + +\subsection{Using the subprocess Module} + +This module defines one class called \class{Popen}: + +\begin{classdesc}{Popen}{args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0} + +Arguments are: + +\var{args} should be a string, or a sequence of program arguments. The +program to execute is normally the first item in the args sequence or +string, but can be explicitly set by using the executable argument. + +On \UNIX{}, with \var{shell=False} (default): In this case, the Popen +class uses \method{os.execvp()} to execute the child program. +\var{args} should normally be a sequence. A string will be treated as a +sequence with the string as the only item (the program to execute). + +On \UNIX{}, with \var{shell=True}: If args is a string, it specifies the +command string to execute through the shell. If \var{args} is a +sequence, the first item specifies the command string, and any +additional items will be treated as additional shell arguments. + +On Windows: the \class{Popen} class uses CreateProcess() to execute +the child program, which operates on strings. If \var{args} is a +sequence, it will be converted to a string using the +\method{list2cmdline} method. Please note that not all MS Windows +applications interpret the command line the same way: +\method{list2cmdline} is designed for applications using the same +rules as the MS C runtime. + +\var{bufsize}, if given, has the same meaning as the corresponding +argument to the built-in open() function: \constant{0} means unbuffered, +\constant{1} means line buffered, any other positive value means use a +buffer of (approximately) that size. A negative \var{bufsize} means to +use the system default, which usually means fully buffered. The default +value for \var{bufsize} is \constant{0} (unbuffered). + +The \var{executable} argument specifies the program to execute. It is +very seldom needed: Usually, the program to execute is defined by the +\var{args} argument. If \code{shell=True}, the \var{executable} +argument specifies which shell to use. On \UNIX{}, the default shell +is \file{/bin/sh}. On Windows, the default shell is specified by the +\envvar{COMSPEC} environment variable. + +\var{stdin}, \var{stdout} and \var{stderr} specify the executed +programs' standard input, standard output and standard error file +handles, respectively. Valid values are \code{PIPE}, an existing file +descriptor (a positive integer), an existing file object, and +\code{None}. \code{PIPE} indicates that a new pipe to the child +should be created. With \code{None}, no redirection will occur; the +child's file handles will be inherited from the parent. Additionally, +\var{stderr} can be \code{STDOUT}, which indicates that the stderr +data from the applications should be captured into the same file +handle as for stdout. + +If \var{preexec_fn} is set to a callable object, this object will be +called in the child process just before the child is executed. +(\UNIX{} only) + +If \var{close_fds} is true, all file descriptors except \constant{0}, +\constant{1} and \constant{2} will be closed before the child process is +executed. (\UNIX{} only) + +If \var{shell} is \constant{True}, the specified command will be +executed through the shell. + +If \var{cwd} is not \code{None}, the child's current directory will be +changed to \var{cwd} before it is executed. Note that this directory +is not considered when searching the executable, so you can't specify +the program's path relative to \var{cwd}. + +If \var{env} is not \code{None}, it defines the environment variables +for the new process. + +If \var{universal_newlines} is \constant{True}, the file objects stdout +and stderr are opened as text files, but lines may be terminated by +any of \code{'\e n'}, the \UNIX{} end-of-line convention, \code{'\e r'}, +the Macintosh convention or \code{'\e r\e n'}, the Windows convention. +All of these external representations are seen as \code{'\e n'} by the +Python program. \note{This feature is only available if Python is built +with universal newline support (the default). Also, the newlines +attribute of the file objects \member{stdout}, \member{stdin} and +\member{stderr} are not updated by the communicate() method.} + +The \var{startupinfo} and \var{creationflags}, if given, will be +passed to the underlying CreateProcess() function. They can specify +things such as appearance of the main window and priority for the new +process. (Windows only) +\end{classdesc} + +\subsubsection{Convenience Functions} + +This module also defines two shortcut functions: + +\begin{funcdesc}{call}{*popenargs, **kwargs} +Run command with arguments. Wait for command to complete, then +return the \member{returncode} attribute. + +The arguments are the same as for the Popen constructor. Example: + +\begin{verbatim} + retcode = call(["ls", "-l"]) +\end{verbatim} +\end{funcdesc} + +\begin{funcdesc}{check_call}{*popenargs, **kwargs} +Run command with arguments. Wait for command to complete. If the exit +code was zero then return, otherwise raise \exception{CalledProcessError.} +The \exception{CalledProcessError} object will have the return code in the +\member{returncode} attribute. + +The arguments are the same as for the Popen constructor. Example: + +\begin{verbatim} + check_call(["ls", "-l"]) +\end{verbatim} +\end{funcdesc} + +\subsubsection{Exceptions} + +Exceptions raised in the child process, before the new program has +started to execute, will be re-raised in the parent. Additionally, +the exception object will have one extra attribute called +\member{child_traceback}, which is a string containing traceback +information from the childs point of view. + +The most common exception raised is \exception{OSError}. This occurs, +for example, when trying to execute a non-existent file. Applications +should prepare for \exception{OSError} exceptions. + +A \exception{ValueError} will be raised if \class{Popen} is called +with invalid arguments. + +check_call() will raise \exception{CalledProcessError}, if the called +process returns a non-zero return code. + + +\subsubsection{Security} + +Unlike some other popen functions, this implementation will never call +/bin/sh implicitly. This means that all characters, including shell +metacharacters, can safely be passed to child processes. + + +\subsection{Popen Objects} + +Instances of the \class{Popen} class have the following methods: + +\begin{methoddesc}{poll}{} +Check if child process has terminated. Returns returncode +attribute. +\end{methoddesc} + +\begin{methoddesc}{wait}{} +Wait for child process to terminate. Returns returncode attribute. +\end{methoddesc} + +\begin{methoddesc}{communicate}{input=None} +Interact with process: Send data to stdin. Read data from stdout and +stderr, until end-of-file is reached. Wait for process to terminate. +The optional \var{input} argument should be a string to be sent to the +child process, or \code{None}, if no data should be sent to the child. + +communicate() returns a tuple (stdout, stderr). + +\note{The data read is buffered in memory, so do not use this method +if the data size is large or unlimited.} +\end{methoddesc} + +The following attributes are also available: + +\begin{memberdesc}{stdin} +If the \var{stdin} argument is \code{PIPE}, this attribute is a file +object that provides input to the child process. Otherwise, it is +\code{None}. +\end{memberdesc} + +\begin{memberdesc}{stdout} +If the \var{stdout} argument is \code{PIPE}, this attribute is a file +object that provides output from the child process. Otherwise, it is +\code{None}. +\end{memberdesc} + +\begin{memberdesc}{stderr} +If the \var{stderr} argument is \code{PIPE}, this attribute is file +object that provides error output from the child process. Otherwise, +it is \code{None}. +\end{memberdesc} + +\begin{memberdesc}{pid} +The process ID of the child process. +\end{memberdesc} + +\begin{memberdesc}{returncode} +The child return code. A \code{None} value indicates that the process +hasn't terminated yet. A negative value -N indicates that the child +was terminated by signal N (\UNIX{} only). +\end{memberdesc} + + +\subsection{Replacing Older Functions with the subprocess Module} + +In this section, "a ==> b" means that b can be used as a replacement +for a. + +\note{All functions in this section fail (more or less) silently if +the executed program cannot be found; this module raises an +\exception{OSError} exception.} + +In the following examples, we assume that the subprocess module is +imported with "from subprocess import *". + +\subsubsection{Replacing /bin/sh shell backquote} + +\begin{verbatim} +output=`mycmd myarg` +==> +output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] +\end{verbatim} + +\subsubsection{Replacing shell pipe line} + +\begin{verbatim} +output=`dmesg | grep hda` +==> +p1 = Popen(["dmesg"], stdout=PIPE) +p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE) +output = p2.communicate()[0] +\end{verbatim} + +\subsubsection{Replacing os.system()} + +\begin{verbatim} +sts = os.system("mycmd" + " myarg") +==> +p = Popen("mycmd" + " myarg", shell=True) +sts = os.waitpid(p.pid, 0) +\end{verbatim} + +Notes: + +\begin{itemize} +\item Calling the program through the shell is usually not required. +\item It's easier to look at the \member{returncode} attribute than + the exit status. +\end{itemize} + +A more realistic example would look like this: + +\begin{verbatim} +try: + retcode = call("mycmd" + " myarg", shell=True) + if retcode < 0: + print >>sys.stderr, "Child was terminated by signal", -retcode + else: + print >>sys.stderr, "Child returned", retcode +except OSError, e: + print >>sys.stderr, "Execution failed:", e +\end{verbatim} + +\subsubsection{Replacing os.spawn*} + +P_NOWAIT example: + +\begin{verbatim} +pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") +==> +pid = Popen(["/bin/mycmd", "myarg"]).pid +\end{verbatim} + +P_WAIT example: + +\begin{verbatim} +retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") +==> +retcode = call(["/bin/mycmd", "myarg"]) +\end{verbatim} + +Vector example: + +\begin{verbatim} +os.spawnvp(os.P_NOWAIT, path, args) +==> +Popen([path] + args[1:]) +\end{verbatim} + +Environment example: + +\begin{verbatim} +os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) +==> +Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) +\end{verbatim} + +\subsubsection{Replacing os.popen*} + +\begin{verbatim} +pipe = os.popen(cmd, mode='r', bufsize) +==> +pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout +\end{verbatim} + +\begin{verbatim} +pipe = os.popen(cmd, mode='w', bufsize) +==> +pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin +\end{verbatim} + +\begin{verbatim} +(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) +==> +p = Popen(cmd, shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) +(child_stdin, child_stdout) = (p.stdin, p.stdout) +\end{verbatim} + +\begin{verbatim} +(child_stdin, + child_stdout, + child_stderr) = os.popen3(cmd, mode, bufsize) +==> +p = Popen(cmd, shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) +(child_stdin, + child_stdout, + child_stderr) = (p.stdin, p.stdout, p.stderr) +\end{verbatim} + +\begin{verbatim} +(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) +==> +p = Popen(cmd, shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) +(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) +\end{verbatim} + +\subsubsection{Replacing popen2.*} + +\note{If the cmd argument to popen2 functions is a string, the command +is executed through /bin/sh. If it is a list, the command is directly +executed.} + +\begin{verbatim} +(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) +==> +p = Popen(["somestring"], shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) +(child_stdout, child_stdin) = (p.stdout, p.stdin) +\end{verbatim} + +\begin{verbatim} +(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) +==> +p = Popen(["mycmd", "myarg"], bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) +(child_stdout, child_stdin) = (p.stdout, p.stdin) +\end{verbatim} + +The popen2.Popen3 and popen2.Popen4 basically works as subprocess.Popen, +except that: + +\begin{itemize} +\item subprocess.Popen raises an exception if the execution fails + +\item the \var{capturestderr} argument is replaced with the \var{stderr} + argument. + +\item stdin=PIPE and stdout=PIPE must be specified. + +\item popen2 closes all file descriptors by default, but you have to + specify close_fds=True with subprocess.Popen. +\end{itemize} diff --git a/sys/src/cmd/python/Doc/lib/libsun.tex b/sys/src/cmd/python/Doc/lib/libsun.tex new file mode 100644 index 000000000..1472509e1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsun.tex @@ -0,0 +1,5 @@ +\chapter{SunOS Specific Services} +\label{sunos} + +The modules described in this chapter provide interfaces to features +that are unique to SunOS 5 (also known as Solaris version 2). diff --git a/sys/src/cmd/python/Doc/lib/libsunau.tex b/sys/src/cmd/python/Doc/lib/libsunau.tex new file mode 100644 index 000000000..235bc3b08 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsunau.tex @@ -0,0 +1,218 @@ +\section{\module{sunau} --- + Read and write Sun AU files} + +\declaremodule{standard}{sunau} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Provide an interface to the Sun AU sound format.} + +The \module{sunau} module provides a convenient interface to the Sun +AU sound format. Note that this module is interface-compatible with +the modules \refmodule{aifc} and \refmodule{wave}. + +An audio file consists of a header followed by the data. The fields +of the header are: + +\begin{tableii}{l|l}{textrm}{Field}{Contents} + \lineii{magic word}{The four bytes \samp{.snd}.} + \lineii{header size}{Size of the header, including info, in bytes.} + \lineii{data size}{Physical size of the data, in bytes.} + \lineii{encoding}{Indicates how the audio samples are encoded.} + \lineii{sample rate}{The sampling rate.} + \lineii{\# of channels}{The number of channels in the samples.} + \lineii{info}{\ASCII{} string giving a description of the audio + file (padded with null bytes).} +\end{tableii} + +Apart from the info field, all header fields are 4 bytes in size. +They are all 32-bit unsigned integers encoded in big-endian byte +order. + + +The \module{sunau} module defines the following functions: + +\begin{funcdesc}{open}{file, mode} +If \var{file} is a string, open the file by that name, otherwise treat it +as a seekable file-like object. \var{mode} can be any of +\begin{description} + \item[\code{'r'}] Read only mode. + \item[\code{'w'}] Write only mode. +\end{description} +Note that it does not allow read/write files. + +A \var{mode} of \code{'r'} returns a \class{AU_read} +object, while a \var{mode} of \code{'w'} or \code{'wb'} returns +a \class{AU_write} object. +\end{funcdesc} + +\begin{funcdesc}{openfp}{file, mode} +A synonym for \function{open}, maintained for backwards compatibility. +\end{funcdesc} + +The \module{sunau} module defines the following exception: + +\begin{excdesc}{Error} +An error raised when something is impossible because of Sun AU specs or +implementation deficiency. +\end{excdesc} + +The \module{sunau} module defines the following data items: + +\begin{datadesc}{AUDIO_FILE_MAGIC} +An integer every valid Sun AU file begins with, stored in big-endian +form. This is the string \samp{.snd} interpreted as an integer. +\end{datadesc} + +\begin{datadesc}{AUDIO_FILE_ENCODING_MULAW_8} +\dataline{AUDIO_FILE_ENCODING_LINEAR_8} +\dataline{AUDIO_FILE_ENCODING_LINEAR_16} +\dataline{AUDIO_FILE_ENCODING_LINEAR_24} +\dataline{AUDIO_FILE_ENCODING_LINEAR_32} +\dataline{AUDIO_FILE_ENCODING_ALAW_8} +Values of the encoding field from the AU header which are supported by +this module. +\end{datadesc} + +\begin{datadesc}{AUDIO_FILE_ENCODING_FLOAT} +\dataline{AUDIO_FILE_ENCODING_DOUBLE} +\dataline{AUDIO_FILE_ENCODING_ADPCM_G721} +\dataline{AUDIO_FILE_ENCODING_ADPCM_G722} +\dataline{AUDIO_FILE_ENCODING_ADPCM_G723_3} +\dataline{AUDIO_FILE_ENCODING_ADPCM_G723_5} +Additional known values of the encoding field from the AU header, but +which are not supported by this module. +\end{datadesc} + + +\subsection{AU_read Objects \label{au-read-objects}} + +AU_read objects, as returned by \function{open()} above, have the +following methods: + +\begin{methoddesc}[AU_read]{close}{} +Close the stream, and make the instance unusable. (This is +called automatically on deletion.) +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getnchannels}{} +Returns number of audio channels (1 for mone, 2 for stereo). +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getsampwidth}{} +Returns sample width in bytes. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getframerate}{} +Returns sampling frequency. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getnframes}{} +Returns number of audio frames. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getcomptype}{} +Returns compression type. +Supported compression types are \code{'ULAW'}, \code{'ALAW'} and \code{'NONE'}. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getcompname}{} +Human-readable version of \method{getcomptype()}. +The supported types have the respective names \code{'CCITT G.711 +u-law'}, \code{'CCITT G.711 A-law'} and \code{'not compressed'}. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getparams}{} +Returns a tuple \code{(\var{nchannels}, \var{sampwidth}, +\var{framerate}, \var{nframes}, \var{comptype}, \var{compname})}, +equivalent to output of the \method{get*()} methods. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{readframes}{n} +Reads and returns at most \var{n} frames of audio, as a string of +bytes. The data will be returned in linear format. If the original +data is in u-LAW format, it will be converted. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{rewind}{} +Rewind the file pointer to the beginning of the audio stream. +\end{methoddesc} + +The following two methods define a term ``position'' which is compatible +between them, and is otherwise implementation dependent. + +\begin{methoddesc}[AU_read]{setpos}{pos} +Set the file pointer to the specified position. Only values returned +from \method{tell()} should be used for \var{pos}. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{tell}{} +Return current file pointer position. Note that the returned value +has nothing to do with the actual position in the file. +\end{methoddesc} + +The following two functions are defined for compatibility with the +\refmodule{aifc}, and don't do anything interesting. + +\begin{methoddesc}[AU_read]{getmarkers}{} +Returns \code{None}. +\end{methoddesc} + +\begin{methoddesc}[AU_read]{getmark}{id} +Raise an error. +\end{methoddesc} + + +\subsection{AU_write Objects \label{au-write-objects}} + +AU_write objects, as returned by \function{open()} above, have the +following methods: + +\begin{methoddesc}[AU_write]{setnchannels}{n} +Set the number of channels. +\end{methoddesc} + +\begin{methoddesc}[AU_write]{setsampwidth}{n} +Set the sample width (in bytes.) +\end{methoddesc} + +\begin{methoddesc}[AU_write]{setframerate}{n} +Set the frame rate. +\end{methoddesc} + +\begin{methoddesc}[AU_write]{setnframes}{n} +Set the number of frames. This can be later changed, when and if more +frames are written. +\end{methoddesc} + + +\begin{methoddesc}[AU_write]{setcomptype}{type, name} +Set the compression type and description. +Only \code{'NONE'} and \code{'ULAW'} are supported on output. +\end{methoddesc} + +\begin{methoddesc}[AU_write]{setparams}{tuple} +The \var{tuple} should be \code{(\var{nchannels}, \var{sampwidth}, +\var{framerate}, \var{nframes}, \var{comptype}, \var{compname})}, with +values valid for the \method{set*()} methods. Set all parameters. +\end{methoddesc} + +\begin{methoddesc}[AU_write]{tell}{} +Return current position in the file, with the same disclaimer for +the \method{AU_read.tell()} and \method{AU_read.setpos()} methods. +\end{methoddesc} + +\begin{methoddesc}[AU_write]{writeframesraw}{data} +Write audio frames, without correcting \var{nframes}. +\end{methoddesc} + +\begin{methoddesc}[AU_write]{writeframes}{data} +Write audio frames and make sure \var{nframes} is correct. +\end{methoddesc} + +\begin{methoddesc}[AU_write]{close}{} +Make sure \var{nframes} is correct, and close the file. + +This method is called upon deletion. +\end{methoddesc} + +Note that it is invalid to set any parameters after calling +\method{writeframes()} or \method{writeframesraw()}. diff --git a/sys/src/cmd/python/Doc/lib/libsunaudio.tex b/sys/src/cmd/python/Doc/lib/libsunaudio.tex new file mode 100644 index 000000000..ec7043797 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsunaudio.tex @@ -0,0 +1,146 @@ +\section{\module{sunaudiodev} --- + Access to Sun audio hardware} + +\declaremodule{builtin}{sunaudiodev} + \platform{SunOS} +\modulesynopsis{Access to Sun audio hardware.} + + +This module allows you to access the Sun audio interface. The Sun +audio hardware is capable of recording and playing back audio data +in u-LAW\index{u-LAW} format with a sample rate of 8K per second. A +full description can be found in the \manpage{audio}{7I} manual page. + +The module +\refmodule[sunaudiodev-constants]{SUNAUDIODEV}\refstmodindex{SUNAUDIODEV} +defines constants which may be used with this module. + +This module defines the following variables and functions: + +\begin{excdesc}{error} +This exception is raised on all errors. The argument is a string +describing what went wrong. +\end{excdesc} + +\begin{funcdesc}{open}{mode} +This function opens the audio device and returns a Sun audio device +object. This object can then be used to do I/O on. The \var{mode} parameter +is one of \code{'r'} for record-only access, \code{'w'} for play-only +access, \code{'rw'} for both and \code{'control'} for access to the +control device. Since only one process is allowed to have the recorder +or player open at the same time it is a good idea to open the device +only for the activity needed. See \manpage{audio}{7I} for details. + +As per the manpage, this module first looks in the environment +variable \code{AUDIODEV} for the base audio device filename. If not +found, it falls back to \file{/dev/audio}. The control device is +calculated by appending ``ctl'' to the base audio device. +\end{funcdesc} + + +\subsection{Audio Device Objects \label{audio-device-objects}} + +The audio device objects are returned by \function{open()} define the +following methods (except \code{control} objects which only provide +\method{getinfo()}, \method{setinfo()}, \method{fileno()}, and +\method{drain()}): + +\begin{methoddesc}[audio device]{close}{} +This method explicitly closes the device. It is useful in situations +where deleting the object does not immediately close it since there +are other references to it. A closed device should not be used again. +\end{methoddesc} + +\begin{methoddesc}[audio device]{fileno}{} +Returns the file descriptor associated with the device. This can be +used to set up \code{SIGPOLL} notification, as described below. +\end{methoddesc} + +\begin{methoddesc}[audio device]{drain}{} +This method waits until all pending output is processed and then returns. +Calling this method is often not necessary: destroying the object will +automatically close the audio device and this will do an implicit drain. +\end{methoddesc} + +\begin{methoddesc}[audio device]{flush}{} +This method discards all pending output. It can be used avoid the +slow response to a user's stop request (due to buffering of up to one +second of sound). +\end{methoddesc} + +\begin{methoddesc}[audio device]{getinfo}{} +This method retrieves status information like input and output volume, +etc. and returns it in the form of +an audio status object. This object has no methods but it contains a +number of attributes describing the current device status. The names +and meanings of the attributes are described in +\code{<sun/audioio.h>} and in the \manpage{audio}{7I} +manual page. Member names +are slightly different from their C counterparts: a status object is +only a single structure. Members of the \cdata{play} substructure have +\samp{o_} prepended to their name and members of the \cdata{record} +structure have \samp{i_}. So, the C member \cdata{play.sample_rate} is +accessed as \member{o_sample_rate}, \cdata{record.gain} as \member{i_gain} +and \cdata{monitor_gain} plainly as \member{monitor_gain}. +\end{methoddesc} + +\begin{methoddesc}[audio device]{ibufcount}{} +This method returns the number of samples that are buffered on the +recording side, i.e.\ the program will not block on a +\function{read()} call of so many samples. +\end{methoddesc} + +\begin{methoddesc}[audio device]{obufcount}{} +This method returns the number of samples buffered on the playback +side. Unfortunately, this number cannot be used to determine a number +of samples that can be written without blocking since the kernel +output queue length seems to be variable. +\end{methoddesc} + +\begin{methoddesc}[audio device]{read}{size} +This method reads \var{size} samples from the audio input and returns +them as a Python string. The function blocks until enough data is available. +\end{methoddesc} + +\begin{methoddesc}[audio device]{setinfo}{status} +This method sets the audio device status parameters. The \var{status} +parameter is an device status object as returned by \function{getinfo()} and +possibly modified by the program. +\end{methoddesc} + +\begin{methoddesc}[audio device]{write}{samples} +Write is passed a Python string containing audio samples to be played. +If there is enough buffer space free it will immediately return, +otherwise it will block. +\end{methoddesc} + +The audio device supports asynchronous notification of various events, +through the SIGPOLL signal. Here's an example of how you might enable +this in Python: + +\begin{verbatim} +def handle_sigpoll(signum, frame): + print 'I got a SIGPOLL update' + +import fcntl, signal, STROPTS + +signal.signal(signal.SIGPOLL, handle_sigpoll) +fcntl.ioctl(audio_obj.fileno(), STROPTS.I_SETSIG, STROPTS.S_MSG) +\end{verbatim} + + +\section{\module{SUNAUDIODEV} --- + Constants used with \module{sunaudiodev}} + +\declaremodule[sunaudiodev-constants]{standard}{SUNAUDIODEV} + \platform{SunOS} +\modulesynopsis{Constants for use with \refmodule{sunaudiodev}.} + + +This is a companion module to +\refmodule{sunaudiodev}\refbimodindex{sunaudiodev} which defines +useful symbolic constants like \constant{MIN_GAIN}, +\constant{MAX_GAIN}, \constant{SPEAKER}, etc. The names of the +constants are the same names as used in the C include file +\code{<sun/audioio.h>}, with the leading string \samp{AUDIO_} +stripped. diff --git a/sys/src/cmd/python/Doc/lib/libsymbol.tex b/sys/src/cmd/python/Doc/lib/libsymbol.tex new file mode 100644 index 000000000..54cabeb7b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsymbol.tex @@ -0,0 +1,30 @@ +\section{\module{symbol} --- + Constants used with Python parse trees} + +\declaremodule{standard}{symbol} +\modulesynopsis{Constants representing internal nodes of the parse tree.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + + +This module provides constants which represent the numeric values of +internal nodes of the parse tree. Unlike most Python constants, these +use lower-case names. Refer to the file \file{Grammar/Grammar} in the +Python distribution for the definitions of the names in the context of +the language grammar. The specific numeric values which the names map +to may change between Python versions. + +This module also provides one additional data object: + + +\begin{datadesc}{sym_name} + Dictionary mapping the numeric values of the constants defined in + this module back to name strings, allowing more human-readable + representation of parse trees to be generated. +\end{datadesc} + + +\begin{seealso} + \seemodule{parser}{The second example for the \refmodule{parser} + module shows how to use the \module{symbol} + module.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libsys.tex b/sys/src/cmd/python/Doc/lib/libsys.tex new file mode 100644 index 000000000..c0aa2380f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsys.tex @@ -0,0 +1,617 @@ +\section{\module{sys} --- + System-specific parameters and functions} + +\declaremodule{builtin}{sys} +\modulesynopsis{Access system-specific parameters and functions.} + +This module provides access to some variables used or maintained by the +interpreter and to functions that interact strongly with the interpreter. +It is always available. + + +\begin{datadesc}{argv} + The list of command line arguments passed to a Python script. + \code{argv[0]} is the script name (it is operating system dependent + whether this is a full pathname or not). If the command was + executed using the \programopt{-c} command line option to the + interpreter, \code{argv[0]} is set to the string \code{'-c'}. If no + script name was passed to the Python interpreter, \code{argv} has + zero length. +\end{datadesc} + +\begin{datadesc}{byteorder} + An indicator of the native byte order. This will have the value + \code{'big'} on big-endian (most-significant byte first) platforms, + and \code{'little'} on little-endian (least-significant byte first) + platforms. + \versionadded{2.0} +\end{datadesc} + +\begin{datadesc}{subversion} + A triple (repo, branch, version) representing the Subversion + information of the Python interpreter. + \var{repo} is the name of the repository, \code{'CPython'}. + \var{branch} is a string of one of the forms \code{'trunk'}, + \code{'branches/name'} or \code{'tags/name'}. + \var{version} is the output of \code{svnversion}, if the + interpreter was built from a Subversion checkout; it contains + the revision number (range) and possibly a trailing 'M' if + there were local modifications. If the tree was exported + (or svnversion was not available), it is the revision of + \code{Include/patchlevel.h} if the branch is a tag. Otherwise, + it is \code{None}. + \versionadded{2.5} +\end{datadesc} + +\begin{datadesc}{builtin_module_names} + A tuple of strings giving the names of all modules that are compiled + into this Python interpreter. (This information is not available in + any other way --- \code{modules.keys()} only lists the imported + modules.) +\end{datadesc} + +\begin{datadesc}{copyright} + A string containing the copyright pertaining to the Python + interpreter. +\end{datadesc} + +\begin{funcdesc}{_current_frames}{} + Return a dictionary mapping each thread's identifier to the topmost stack + frame currently active in that thread at the time the function is called. + Note that functions in the \refmodule{traceback} module can build the + call stack given such a frame. + + This is most useful for debugging deadlock: this function does not + require the deadlocked threads' cooperation, and such threads' call stacks + are frozen for as long as they remain deadlocked. The frame returned + for a non-deadlocked thread may bear no relationship to that thread's + current activity by the time calling code examines the frame. + + This function should be used for internal and specialized purposes + only. + \versionadded{2.5} +\end{funcdesc} + +\begin{datadesc}{dllhandle} + Integer specifying the handle of the Python DLL. + Availability: Windows. +\end{datadesc} + +\begin{funcdesc}{displayhook}{\var{value}} + If \var{value} is not \code{None}, this function prints it to + \code{sys.stdout}, and saves it in \code{__builtin__._}. + + \code{sys.displayhook} is called on the result of evaluating an + expression entered in an interactive Python session. The display of + these values can be customized by assigning another one-argument + function to \code{sys.displayhook}. +\end{funcdesc} + +\begin{funcdesc}{excepthook}{\var{type}, \var{value}, \var{traceback}} + This function prints out a given traceback and exception to + \code{sys.stderr}. + + When an exception is raised and uncaught, the interpreter calls + \code{sys.excepthook} with three arguments, the exception class, + exception instance, and a traceback object. In an interactive + session this happens just before control is returned to the prompt; + in a Python program this happens just before the program exits. The + handling of such top-level exceptions can be customized by assigning + another three-argument function to \code{sys.excepthook}. +\end{funcdesc} + +\begin{datadesc}{__displayhook__} +\dataline{__excepthook__} + These objects contain the original values of \code{displayhook} and + \code{excepthook} at the start of the program. They are saved so + that \code{displayhook} and \code{excepthook} can be restored in + case they happen to get replaced with broken objects. +\end{datadesc} + +\begin{funcdesc}{exc_info}{} + This function returns a tuple of three values that give information + about the exception that is currently being handled. The + information returned is specific both to the current thread and to + the current stack frame. If the current stack frame is not handling + an exception, the information is taken from the calling stack frame, + or its caller, and so on until a stack frame is found that is + handling an exception. Here, ``handling an exception'' is defined + as ``executing or having executed an except clause.'' For any stack + frame, only information about the most recently handled exception is + accessible. + + If no exception is being handled anywhere on the stack, a tuple + containing three \code{None} values is returned. Otherwise, the + values returned are \code{(\var{type}, \var{value}, + \var{traceback})}. Their meaning is: \var{type} gets the exception + type of the exception being handled (a class object); + \var{value} gets the exception parameter (its \dfn{associated value} + or the second argument to \keyword{raise}, which is always a class + instance if the exception type is a class object); \var{traceback} + gets a traceback object (see the Reference Manual) which + encapsulates the call stack at the point where the exception + originally occurred. \obindex{traceback} + + If \function{exc_clear()} is called, this function will return three + \code{None} values until either another exception is raised in the + current thread or the execution stack returns to a frame where + another exception is being handled. + + \warning{Assigning the \var{traceback} return value to a + local variable in a function that is handling an exception will + cause a circular reference. This will prevent anything referenced + by a local variable in the same function or by the traceback from + being garbage collected. Since most functions don't need access to + the traceback, the best solution is to use something like + \code{exctype, value = sys.exc_info()[:2]} to extract only the + exception type and value. If you do need the traceback, make sure + to delete it after use (best done with a \keyword{try} + ... \keyword{finally} statement) or to call \function{exc_info()} in + a function that does not itself handle an exception.} \note{Beginning + with Python 2.2, such cycles are automatically reclaimed when garbage + collection is enabled and they become unreachable, but it remains more + efficient to avoid creating cycles.} +\end{funcdesc} + +\begin{funcdesc}{exc_clear}{} + This function clears all information relating to the current or last + exception that occurred in the current thread. After calling this + function, \function{exc_info()} will return three \code{None} values until + another exception is raised in the current thread or the execution stack + returns to a frame where another exception is being handled. + + This function is only needed in only a few obscure situations. These + include logging and error handling systems that report information on the + last or current exception. This function can also be used to try to free + resources and trigger object finalization, though no guarantee is made as + to what objects will be freed, if any. +\versionadded{2.3} +\end{funcdesc} + +\begin{datadesc}{exc_type} +\dataline{exc_value} +\dataline{exc_traceback} +\deprecated {1.5} + {Use \function{exc_info()} instead.} + Since they are global variables, they are not specific to the + current thread, so their use is not safe in a multi-threaded + program. When no exception is being handled, \code{exc_type} is set + to \code{None} and the other two are undefined. +\end{datadesc} + +\begin{datadesc}{exec_prefix} + A string giving the site-specific directory prefix where the + platform-dependent Python files are installed; by default, this is + also \code{'/usr/local'}. This can be set at build time with the + \longprogramopt{exec-prefix} argument to the \program{configure} + script. Specifically, all configuration files (e.g. the + \file{pyconfig.h} header file) are installed in the directory + \code{exec_prefix + '/lib/python\var{version}/config'}, and shared + library modules are installed in \code{exec_prefix + + '/lib/python\var{version}/lib-dynload'}, where \var{version} is + equal to \code{version[:3]}. +\end{datadesc} + +\begin{datadesc}{executable} + A string giving the name of the executable binary for the Python + interpreter, on systems where this makes sense. +\end{datadesc} + +\begin{funcdesc}{exit}{\optional{arg}} + Exit from Python. This is implemented by raising the + \exception{SystemExit} exception, so cleanup actions specified by + finally clauses of \keyword{try} statements are honored, and it is + possible to intercept the exit attempt at an outer level. The + optional argument \var{arg} can be an integer giving the exit status + (defaulting to zero), or another type of object. If it is an + integer, zero is considered ``successful termination'' and any + nonzero value is considered ``abnormal termination'' by shells and + the like. Most systems require it to be in the range 0-127, and + produce undefined results otherwise. Some systems have a convention + for assigning specific meanings to specific exit codes, but these + are generally underdeveloped; \UNIX{} programs generally use 2 for + command line syntax errors and 1 for all other kind of errors. If + another type of object is passed, \code{None} is equivalent to + passing zero, and any other object is printed to \code{sys.stderr} + and results in an exit code of 1. In particular, + \code{sys.exit("some error message")} is a quick way to exit a + program when an error occurs. +\end{funcdesc} + +\begin{datadesc}{exitfunc} + This value is not actually defined by the module, but can be set by + the user (or by a program) to specify a clean-up action at program + exit. When set, it should be a parameterless function. This + function will be called when the interpreter exits. Only one + function may be installed in this way; to allow multiple functions + which will be called at termination, use the \refmodule{atexit} + module. \note{The exit function is not called when the program is + killed by a signal, when a Python fatal internal error is detected, + or when \code{os._exit()} is called.} + \deprecated{2.4}{Use \refmodule{atexit} instead.} +\end{datadesc} + +\begin{funcdesc}{getcheckinterval}{} + Return the interpreter's ``check interval''; + see \function{setcheckinterval()}. + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{getdefaultencoding}{} + Return the name of the current default string encoding used by the + Unicode implementation. + \versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{getdlopenflags}{} + Return the current value of the flags that are used for + \cfunction{dlopen()} calls. The flag constants are defined in the + \refmodule{dl} and \module{DLFCN} modules. + Availability: \UNIX. + \versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{getfilesystemencoding}{} + Return the name of the encoding used to convert Unicode filenames + into system file names, or \code{None} if the system default encoding + is used. The result value depends on the operating system: +\begin{itemize} +\item On Windows 9x, the encoding is ``mbcs''. +\item On Mac OS X, the encoding is ``utf-8''. +\item On \UNIX, the encoding is the user's preference + according to the result of nl_langinfo(CODESET), or \constant{None} + if the \code{nl_langinfo(CODESET)} failed. +\item On Windows NT+, file names are Unicode natively, so no conversion + is performed. \function{getfilesystemencoding()} still returns + \code{'mbcs'}, as this is the encoding that applications should use + when they explicitly want to convert Unicode strings to byte strings + that are equivalent when used as file names. +\end{itemize} + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{getrefcount}{object} + Return the reference count of the \var{object}. The count returned + is generally one higher than you might expect, because it includes + the (temporary) reference as an argument to + \function{getrefcount()}. +\end{funcdesc} + +\begin{funcdesc}{getrecursionlimit}{} + Return the current value of the recursion limit, the maximum depth + of the Python interpreter stack. This limit prevents infinite + recursion from causing an overflow of the C stack and crashing + Python. It can be set by \function{setrecursionlimit()}. +\end{funcdesc} + +\begin{funcdesc}{_getframe}{\optional{depth}} + Return a frame object from the call stack. If optional integer + \var{depth} is given, return the frame object that many calls below + the top of the stack. If that is deeper than the call stack, + \exception{ValueError} is raised. The default for \var{depth} is + zero, returning the frame at the top of the call stack. + + This function should be used for internal and specialized purposes + only. +\end{funcdesc} + +\begin{funcdesc}{getwindowsversion}{} + Return a tuple containing five components, describing the Windows + version currently running. The elements are \var{major}, \var{minor}, + \var{build}, \var{platform}, and \var{text}. \var{text} contains + a string while all other values are integers. + + \var{platform} may be one of the following values: + + \begin{tableii}{l|l}{constant}{Constant}{Platform} + \lineii{0 (VER_PLATFORM_WIN32s)} {Win32s on Windows 3.1} + \lineii{1 (VER_PLATFORM_WIN32_WINDOWS)}{Windows 95/98/ME} + \lineii{2 (VER_PLATFORM_WIN32_NT)} {Windows NT/2000/XP} + \lineii{3 (VER_PLATFORM_WIN32_CE)} {Windows CE} + \end{tableii} + + This function wraps the Win32 \cfunction{GetVersionEx()} function; + see the Microsoft documentation for more information about these + fields. + + Availability: Windows. + \versionadded{2.3} +\end{funcdesc} + +\begin{datadesc}{hexversion} + The version number encoded as a single integer. This is guaranteed + to increase with each version, including proper support for + non-production releases. For example, to test that the Python + interpreter is at least version 1.5.2, use: + +\begin{verbatim} +if sys.hexversion >= 0x010502F0: + # use some advanced feature + ... +else: + # use an alternative implementation or warn the user + ... +\end{verbatim} + + This is called \samp{hexversion} since it only really looks + meaningful when viewed as the result of passing it to the built-in + \function{hex()} function. The \code{version_info} value may be + used for a more human-friendly encoding of the same information. + \versionadded{1.5.2} +\end{datadesc} + +\begin{datadesc}{last_type} +\dataline{last_value} +\dataline{last_traceback} + These three variables are not always defined; they are set when an + exception is not handled and the interpreter prints an error message + and a stack traceback. Their intended use is to allow an + interactive user to import a debugger module and engage in + post-mortem debugging without having to re-execute the command that + caused the error. (Typical use is \samp{import pdb; pdb.pm()} to + enter the post-mortem debugger; see chapter~\ref{debugger}, ``The + Python Debugger,'' for more information.) + + The meaning of the variables is the same as that of the return + values from \function{exc_info()} above. (Since there is only one + interactive thread, thread-safety is not a concern for these + variables, unlike for \code{exc_type} etc.) +\end{datadesc} + +\begin{datadesc}{maxint} + The largest positive integer supported by Python's regular integer + type. This is at least 2**31-1. The largest negative integer is + \code{-maxint-1} --- the asymmetry results from the use of 2's + complement binary arithmetic. +\end{datadesc} + +\begin{datadesc}{maxunicode} + An integer giving the largest supported code point for a Unicode + character. The value of this depends on the configuration option + that specifies whether Unicode characters are stored as UCS-2 or + UCS-4. +\end{datadesc} + +\begin{datadesc}{modules} + This is a dictionary that maps module names to modules which have + already been loaded. This can be manipulated to force reloading of + modules and other tricks. Note that removing a module from this + dictionary is \emph{not} the same as calling + \function{reload()}\bifuncindex{reload} on the corresponding module + object. +\end{datadesc} + +\begin{datadesc}{path} +\indexiii{module}{search}{path} + A list of strings that specifies the search path for modules. + Initialized from the environment variable \envvar{PYTHONPATH}, plus an + installation-dependent default. + + As initialized upon program startup, + the first item of this list, \code{path[0]}, is the directory + containing the script that was used to invoke the Python + interpreter. If the script directory is not available (e.g. if the + interpreter is invoked interactively or if the script is read from + standard input), \code{path[0]} is the empty string, which directs + Python to search modules in the current directory first. Notice + that the script directory is inserted \emph{before} the entries + inserted as a result of \envvar{PYTHONPATH}. + + A program is free to modify this list for its own purposes. + + \versionchanged[Unicode strings are no longer ignored]{2.3} +\end{datadesc} + +\begin{datadesc}{platform} + This string contains a platform identifier, e.g. \code{'sunos5'} or + \code{'linux1'}. This can be used to append platform-specific + components to \code{path}, for instance. +\end{datadesc} + +\begin{datadesc}{prefix} + A string giving the site-specific directory prefix where the + platform independent Python files are installed; by default, this is + the string \code{'/usr/local'}. This can be set at build time with + the \longprogramopt{prefix} argument to the \program{configure} + script. The main collection of Python library modules is installed + in the directory \code{prefix + '/lib/python\var{version}'} while + the platform independent header files (all except \file{pyconfig.h}) + are stored in \code{prefix + '/include/python\var{version}'}, where + \var{version} is equal to \code{version[:3]}. +\end{datadesc} + +\begin{datadesc}{ps1} +\dataline{ps2} +\index{interpreter prompts} +\index{prompts, interpreter} + Strings specifying the primary and secondary prompt of the + interpreter. These are only defined if the interpreter is in + interactive mode. Their initial values in this case are + \code{'>>>~'} and \code{'...~'}. If a non-string object is + assigned to either variable, its \function{str()} is re-evaluated + each time the interpreter prepares to read a new interactive + command; this can be used to implement a dynamic prompt. +\end{datadesc} + +\begin{funcdesc}{setcheckinterval}{interval} + Set the interpreter's ``check interval''. This integer value + determines how often the interpreter checks for periodic things such + as thread switches and signal handlers. The default is \code{100}, + meaning the check is performed every 100 Python virtual instructions. + Setting it to a larger value may increase performance for programs + using threads. Setting it to a value \code{<=} 0 checks every + virtual instruction, maximizing responsiveness as well as overhead. +\end{funcdesc} + +\begin{funcdesc}{setdefaultencoding}{name} + Set the current default string encoding used by the Unicode + implementation. If \var{name} does not match any available + encoding, \exception{LookupError} is raised. This function is only + intended to be used by the \refmodule{site} module implementation + and, where needed, by \module{sitecustomize}. Once used by the + \refmodule{site} module, it is removed from the \module{sys} + module's namespace. +% Note that \refmodule{site} is not imported if +% the \programopt{-S} option is passed to the interpreter, in which +% case this function will remain available. + \versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{setdlopenflags}{n} + Set the flags used by the interpreter for \cfunction{dlopen()} + calls, such as when the interpreter loads extension modules. Among + other things, this will enable a lazy resolving of symbols when + importing a module, if called as \code{sys.setdlopenflags(0)}. To + share symbols across extension modules, call as + \code{sys.setdlopenflags(dl.RTLD_NOW | dl.RTLD_GLOBAL)}. Symbolic + names for the flag modules can be either found in the \refmodule{dl} + module, or in the \module{DLFCN} module. If \module{DLFCN} is not + available, it can be generated from \file{/usr/include/dlfcn.h} + using the \program{h2py} script. + Availability: \UNIX. + \versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{setprofile}{profilefunc} + Set the system's profile function,\index{profile function} which + allows you to implement a Python source code profiler in + Python.\index{profiler} See chapter~\ref{profile} for more + information on the Python profiler. The system's profile function + is called similarly to the system's trace function (see + \function{settrace()}), but it isn't called for each executed line + of code (only on call and return, but the return event is reported + even when an exception has been set). The function is + thread-specific, but there is no way for the profiler to know about + context switches between threads, so it does not make sense to use + this in the presence of multiple threads. + Also, its return value is not used, so it can simply return + \code{None}. +\end{funcdesc} + +\begin{funcdesc}{setrecursionlimit}{limit} + Set the maximum depth of the Python interpreter stack to + \var{limit}. This limit prevents infinite recursion from causing an + overflow of the C stack and crashing Python. + + The highest possible limit is platform-dependent. A user may need + to set the limit higher when she has a program that requires deep + recursion and a platform that supports a higher limit. This should + be done with care, because a too-high limit can lead to a crash. +\end{funcdesc} + +\begin{funcdesc}{settrace}{tracefunc} + Set the system's trace function,\index{trace function} which allows + you to implement a Python source code debugger in Python. See + section \ref{debugger-hooks}, ``How It Works,'' in the chapter on + the Python debugger.\index{debugger} The function is + thread-specific; for a debugger to support multiple threads, it must + be registered using \function{settrace()} for each thread being + debugged. \note{The \function{settrace()} function is intended only + for implementing debuggers, profilers, coverage tools and the like. + Its behavior is part of the implementation platform, rather than + part of the language definition, and thus may not be available in + all Python implementations.} +\end{funcdesc} + +\begin{funcdesc}{settscdump}{on_flag} + Activate dumping of VM measurements using the Pentium timestamp + counter, if \var{on_flag} is true. Deactivate these dumps if + \var{on_flag} is off. The function is available only if Python + was compiled with \longprogramopt{with-tsc}. To understand the + output of this dump, read \file{Python/ceval.c} in the Python + sources. + \versionadded{2.4} +\end{funcdesc} + +\begin{datadesc}{stdin} +\dataline{stdout} +\dataline{stderr} + File objects corresponding to the interpreter's standard input, + output and error streams. \code{stdin} is used for all interpreter + input except for scripts but including calls to + \function{input()}\bifuncindex{input} and + \function{raw_input()}\bifuncindex{raw_input}. \code{stdout} is + used for the output of \keyword{print} and expression statements and + for the prompts of \function{input()} and \function{raw_input()}. + The interpreter's own prompts and (almost all of) its error messages + go to \code{stderr}. \code{stdout} and \code{stderr} needn't be + built-in file objects: any object is acceptable as long as it has a + \method{write()} method that takes a string argument. (Changing + these objects doesn't affect the standard I/O streams of processes + executed by \function{os.popen()}, \function{os.system()} or the + \function{exec*()} family of functions in the \refmodule{os} + module.) +\end{datadesc} + +\begin{datadesc}{__stdin__} +\dataline{__stdout__} +\dataline{__stderr__} + These objects contain the original values of \code{stdin}, + \code{stderr} and \code{stdout} at the start of the program. They + are used during finalization, and could be useful to restore the + actual files to known working file objects in case they have been + overwritten with a broken object. +\end{datadesc} + +\begin{datadesc}{tracebacklimit} + When this variable is set to an integer value, it determines the + maximum number of levels of traceback information printed when an + unhandled exception occurs. The default is \code{1000}. When set + to \code{0} or less, all traceback information is suppressed and + only the exception type and value are printed. +\end{datadesc} + +\begin{datadesc}{version} + A string containing the version number of the Python interpreter + plus additional information on the build number and compiler used. + It has a value of the form \code{'\var{version} + (\#\var{build_number}, \var{build_date}, \var{build_time}) + [\var{compiler}]'}. The first three characters are used to identify + the version in the installation directories (where appropriate on + each platform). An example: + +\begin{verbatim} +>>> import sys +>>> sys.version +'1.5.2 (#0 Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)]' +\end{verbatim} +\end{datadesc} + +\begin{datadesc}{api_version} + The C API version for this interpreter. Programmers may find this useful + when debugging version conflicts between Python and extension + modules. \versionadded{2.3} +\end{datadesc} + +\begin{datadesc}{version_info} + A tuple containing the five components of the version number: + \var{major}, \var{minor}, \var{micro}, \var{releaselevel}, and + \var{serial}. All values except \var{releaselevel} are integers; + the release level is \code{'alpha'}, \code{'beta'}, + \code{'candidate'}, or \code{'final'}. The \code{version_info} + value corresponding to the Python version 2.0 is \code{(2, 0, 0, + 'final', 0)}. + \versionadded{2.0} +\end{datadesc} + +\begin{datadesc}{warnoptions} + This is an implementation detail of the warnings framework; do not + modify this value. Refer to the \refmodule{warnings} module for + more information on the warnings framework. +\end{datadesc} + +\begin{datadesc}{winver} + The version number used to form registry keys on Windows platforms. + This is stored as string resource 1000 in the Python DLL. The value + is normally the first three characters of \constant{version}. It is + provided in the \module{sys} module for informational purposes; + modifying this value has no effect on the registry keys used by + Python. + Availability: Windows. +\end{datadesc} + + +\begin{seealso} + \seemodule{site} + {This describes how to use .pth files to extend \code{sys.path}.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libsyslog.tex b/sys/src/cmd/python/Doc/lib/libsyslog.tex new file mode 100644 index 000000000..fc59776c6 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libsyslog.tex @@ -0,0 +1,76 @@ +\section{\module{syslog} --- + \UNIX{} syslog library routines} + +\declaremodule{builtin}{syslog} + \platform{Unix} +\modulesynopsis{An interface to the \UNIX\ syslog library routines.} + + +This module provides an interface to the \UNIX{} \code{syslog} library +routines. Refer to the \UNIX{} manual pages for a detailed description +of the \code{syslog} facility. + +The module defines the following functions: + + +\begin{funcdesc}{syslog}{\optional{priority,} message} +Send the string \var{message} to the system logger. A trailing +newline is added if necessary. Each message is tagged with a priority +composed of a \var{facility} and a \var{level}. The optional +\var{priority} argument, which defaults to \constant{LOG_INFO}, +determines the message priority. If the facility is not encoded in +\var{priority} using logical-or (\code{LOG_INFO | LOG_USER}), the +value given in the \function{openlog()} call is used. +\end{funcdesc} + +\begin{funcdesc}{openlog}{ident\optional{, logopt\optional{, facility}}} +Logging options other than the defaults can be set by explicitly +opening the log file with \function{openlog()} prior to calling +\function{syslog()}. The defaults are (usually) \var{ident} = +\code{'syslog'}, \var{logopt} = \code{0}, \var{facility} = +\constant{LOG_USER}. The \var{ident} argument is a string which is +prepended to every message. The optional \var{logopt} argument is a +bit field - see below for possible values to combine. The optional +\var{facility} argument sets the default facility for messages which +do not have a facility explicitly encoded. +\end{funcdesc} + +\begin{funcdesc}{closelog}{} +Close the log file. +\end{funcdesc} + +\begin{funcdesc}{setlogmask}{maskpri} +Set the priority mask to \var{maskpri} and return the +previous mask value. Calls to \function{syslog()} with a priority +level not set in \var{maskpri} are ignored. The default is to log all +priorities. The function \code{LOG_MASK(\var{pri})} calculates the +mask for the individual priority \var{pri}. The function +\code{LOG_UPTO(\var{pri})} calculates the mask for all priorities up +to and including \var{pri}. +\end{funcdesc} + + +The module defines the following constants: + +\begin{description} + +\item[Priority levels (high to low):] + +\constant{LOG_EMERG}, \constant{LOG_ALERT}, \constant{LOG_CRIT}, +\constant{LOG_ERR}, \constant{LOG_WARNING}, \constant{LOG_NOTICE}, +\constant{LOG_INFO}, \constant{LOG_DEBUG}. + +\item[Facilities:] + +\constant{LOG_KERN}, \constant{LOG_USER}, \constant{LOG_MAIL}, +\constant{LOG_DAEMON}, \constant{LOG_AUTH}, \constant{LOG_LPR}, +\constant{LOG_NEWS}, \constant{LOG_UUCP}, \constant{LOG_CRON} and +\constant{LOG_LOCAL0} to \constant{LOG_LOCAL7}. + +\item[Log options:] + +\constant{LOG_PID}, \constant{LOG_CONS}, \constant{LOG_NDELAY}, +\constant{LOG_NOWAIT} and \constant{LOG_PERROR} if defined in +\code{<syslog.h>}. + +\end{description} diff --git a/sys/src/cmd/python/Doc/lib/libtabnanny.tex b/sys/src/cmd/python/Doc/lib/libtabnanny.tex new file mode 100644 index 000000000..12b9385b8 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtabnanny.tex @@ -0,0 +1,62 @@ +\section{\module{tabnanny} --- + Detection of ambiguous indentation} + +% rudimentary documentation based on module comments, by Peter Funk +% <pf@artcom-gmbh.de> + +\declaremodule{standard}{tabnanny} +\modulesynopsis{Tool for detecting white space related problems + in Python source files in a directory tree.} +\moduleauthor{Tim Peters}{tim_one@users.sourceforge.net} +\sectionauthor{Peter Funk}{pf@artcom-gmbh.de} + +For the time being this module is intended to be called as a script. +However it is possible to import it into an IDE and use the function +\function{check()} described below. + +\warning{The API provided by this module is likely to change +in future releases; such changes may not be backward compatible.} + +\begin{funcdesc}{check}{file_or_dir} + If \var{file_or_dir} is a directory and not a symbolic link, then + recursively descend the directory tree named by \var{file_or_dir}, + checking all \file{.py} files along the way. If \var{file_or_dir} + is an ordinary Python source file, it is checked for whitespace + related problems. The diagnostic messages are written to standard + output using the print statement. +\end{funcdesc} + + +\begin{datadesc}{verbose} + Flag indicating whether to print verbose messages. + This is incremented by the \code{-v} option if called as a script. +\end{datadesc} + + +\begin{datadesc}{filename_only} + Flag indicating whether to print only the filenames of files + containing whitespace related problems. This is set to true by the + \code{-q} option if called as a script. +\end{datadesc} + + +\begin{excdesc}{NannyNag} + Raised by \function{tokeneater()} if detecting an ambiguous indent. + Captured and handled in \function{check()}. +\end{excdesc} + + +\begin{funcdesc}{tokeneater}{type, token, start, end, line} + This function is used by \function{check()} as a callback parameter to + the function \function{tokenize.tokenize()}. +\end{funcdesc} + +% XXX FIXME: Document \function{errprint}, +% \function{format_witnesses} \class{Whitespace} +% check_equal, indents +% \function{reset_globals} + +\begin{seealso} + \seemodule{tokenize}{Lexical scanner for Python source code.} + % XXX may be add a reference to IDLE? +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libtarfile.tex b/sys/src/cmd/python/Doc/lib/libtarfile.tex new file mode 100644 index 000000000..b33ac606c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtarfile.tex @@ -0,0 +1,497 @@ +\section{\module{tarfile} --- Read and write tar archive files} + +\declaremodule{standard}{tarfile} +\modulesynopsis{Read and write tar-format archive files.} +\versionadded{2.3} + +\moduleauthor{Lars Gust\"abel}{lars@gustaebel.de} +\sectionauthor{Lars Gust\"abel}{lars@gustaebel.de} + +The \module{tarfile} module makes it possible to read and create tar archives. +Some facts and figures: + +\begin{itemize} +\item reads and writes \module{gzip} and \module{bzip2} compressed archives. +\item creates \POSIX{} 1003.1-1990 compliant or GNU tar compatible archives. +\item reads GNU tar extensions \emph{longname}, \emph{longlink} and + \emph{sparse}. +\item stores pathnames of unlimited length using GNU tar extensions. +\item handles directories, regular files, hardlinks, symbolic links, fifos, + character devices and block devices and is able to acquire and + restore file information like timestamp, access permissions and owner. +\item can handle tape devices. +\end{itemize} + +\begin{funcdesc}{open}{\optional{name\optional{, mode + \optional{, fileobj\optional{, bufsize}}}}} + Return a \class{TarFile} object for the pathname \var{name}. + For detailed information on \class{TarFile} objects, + see \citetitle{TarFile Objects} (section \ref{tarfile-objects}). + + \var{mode} has to be a string of the form \code{'filemode[:compression]'}, + it defaults to \code{'r'}. Here is a full list of mode combinations: + + \begin{tableii}{c|l}{code}{mode}{action} + \lineii{'r' or 'r:*'}{Open for reading with transparent compression (recommended).} + \lineii{'r:'}{Open for reading exclusively without compression.} + \lineii{'r:gz'}{Open for reading with gzip compression.} + \lineii{'r:bz2'}{Open for reading with bzip2 compression.} + \lineii{'a' or 'a:'}{Open for appending with no compression.} + \lineii{'w' or 'w:'}{Open for uncompressed writing.} + \lineii{'w:gz'}{Open for gzip compressed writing.} + \lineii{'w:bz2'}{Open for bzip2 compressed writing.} + \end{tableii} + + Note that \code{'a:gz'} or \code{'a:bz2'} is not possible. + If \var{mode} is not suitable to open a certain (compressed) file for + reading, \exception{ReadError} is raised. Use \var{mode} \code{'r'} to + avoid this. If a compression method is not supported, + \exception{CompressionError} is raised. + + If \var{fileobj} is specified, it is used as an alternative to a file + object opened for \var{name}. It is supposed to be at position 0. + + For special purposes, there is a second format for \var{mode}: + \code{'filemode|[compression]'}. \function{open()} will return a + \class{TarFile} object that processes its data as a stream of + blocks. No random seeking will be done on the file. If given, + \var{fileobj} may be any object that has a \method{read()} or + \method{write()} method (depending on the \var{mode}). + \var{bufsize} specifies the blocksize and defaults to \code{20 * + 512} bytes. Use this variant in combination with + e.g. \code{sys.stdin}, a socket file object or a tape device. + However, such a \class{TarFile} object is limited in that it does + not allow to be accessed randomly, see ``Examples'' + (section~\ref{tar-examples}). The currently possible modes: + + \begin{tableii}{c|l}{code}{Mode}{Action} + \lineii{'r|*'}{Open a \emph{stream} of tar blocks for reading with transparent compression.} + \lineii{'r|'}{Open a \emph{stream} of uncompressed tar blocks for reading.} + \lineii{'r|gz'}{Open a gzip compressed \emph{stream} for reading.} + \lineii{'r|bz2'}{Open a bzip2 compressed \emph{stream} for reading.} + \lineii{'w|'}{Open an uncompressed \emph{stream} for writing.} + \lineii{'w|gz'}{Open an gzip compressed \emph{stream} for writing.} + \lineii{'w|bz2'}{Open an bzip2 compressed \emph{stream} for writing.} + \end{tableii} +\end{funcdesc} + +\begin{classdesc*}{TarFile} + Class for reading and writing tar archives. Do not use this + class directly, better use \function{open()} instead. + See ``TarFile Objects'' (section~\ref{tarfile-objects}). +\end{classdesc*} + +\begin{funcdesc}{is_tarfile}{name} + Return \constant{True} if \var{name} is a tar archive file, that + the \module{tarfile} module can read. +\end{funcdesc} + +\begin{classdesc}{TarFileCompat}{filename\optional{, mode\optional{, + compression}}} + Class for limited access to tar archives with a + \refmodule{zipfile}-like interface. Please consult the + documentation of the \refmodule{zipfile} module for more details. + \var{compression} must be one of the following constants: + \begin{datadesc}{TAR_PLAIN} + Constant for an uncompressed tar archive. + \end{datadesc} + \begin{datadesc}{TAR_GZIPPED} + Constant for a \refmodule{gzip} compressed tar archive. + \end{datadesc} +\end{classdesc} + +\begin{excdesc}{TarError} + Base class for all \module{tarfile} exceptions. +\end{excdesc} + +\begin{excdesc}{ReadError} + Is raised when a tar archive is opened, that either cannot be handled by + the \module{tarfile} module or is somehow invalid. +\end{excdesc} + +\begin{excdesc}{CompressionError} + Is raised when a compression method is not supported or when the data + cannot be decoded properly. +\end{excdesc} + +\begin{excdesc}{StreamError} + Is raised for the limitations that are typical for stream-like + \class{TarFile} objects. +\end{excdesc} + +\begin{excdesc}{ExtractError} + Is raised for \emph{non-fatal} errors when using \method{extract()}, but + only if \member{TarFile.errorlevel}\code{ == 2}. +\end{excdesc} + +\begin{seealso} + \seemodule{zipfile}{Documentation of the \refmodule{zipfile} + standard module.} + + \seetitle[http://www.gnu.org/software/tar/manual/html_node/tar_134.html\#SEC134] + {GNU tar manual, Basic Tar Format}{Documentation for tar archive files, + including GNU tar extensions.} +\end{seealso} + +%----------------- +% TarFile Objects +%----------------- + +\subsection{TarFile Objects \label{tarfile-objects}} + +The \class{TarFile} object provides an interface to a tar archive. A tar +archive is a sequence of blocks. An archive member (a stored file) is made up +of a header block followed by data blocks. It is possible, to store a file in a +tar archive several times. Each archive member is represented by a +\class{TarInfo} object, see \citetitle{TarInfo Objects} (section +\ref{tarinfo-objects}) for details. + +\begin{classdesc}{TarFile}{\optional{name + \optional{, mode\optional{, fileobj}}}} + Open an \emph{(uncompressed)} tar archive \var{name}. + \var{mode} is either \code{'r'} to read from an existing archive, + \code{'a'} to append data to an existing file or \code{'w'} to create a new + file overwriting an existing one. \var{mode} defaults to \code{'r'}. + + If \var{fileobj} is given, it is used for reading or writing data. + If it can be determined, \var{mode} is overridden by \var{fileobj}'s mode. + \var{fileobj} will be used from position 0. + \begin{notice} + \var{fileobj} is not closed, when \class{TarFile} is closed. + \end{notice} +\end{classdesc} + +\begin{methoddesc}{open}{...} + Alternative constructor. The \function{open()} function on module level is + actually a shortcut to this classmethod. See section~\ref{module-tarfile} + for details. +\end{methoddesc} + +\begin{methoddesc}{getmember}{name} + Return a \class{TarInfo} object for member \var{name}. If \var{name} can + not be found in the archive, \exception{KeyError} is raised. + \begin{notice} + If a member occurs more than once in the archive, its last + occurrence is assumed to be the most up-to-date version. + \end{notice} +\end{methoddesc} + +\begin{methoddesc}{getmembers}{} + Return the members of the archive as a list of \class{TarInfo} objects. + The list has the same order as the members in the archive. +\end{methoddesc} + +\begin{methoddesc}{getnames}{} + Return the members as a list of their names. It has the same order as + the list returned by \method{getmembers()}. +\end{methoddesc} + +\begin{methoddesc}{list}{verbose=True} + Print a table of contents to \code{sys.stdout}. If \var{verbose} is + \constant{False}, only the names of the members are printed. If it is + \constant{True}, output similar to that of \program{ls -l} is produced. +\end{methoddesc} + +\begin{methoddesc}{next}{} + Return the next member of the archive as a \class{TarInfo} object, when + \class{TarFile} is opened for reading. Return \code{None} if there is no + more available. +\end{methoddesc} + +\begin{methoddesc}{extractall}{\optional{path\optional{, members}}} + Extract all members from the archive to the current working directory + or directory \var{path}. If optional \var{members} is given, it must be + a subset of the list returned by \method{getmembers()}. + Directory informations like owner, modification time and permissions are + set after all members have been extracted. This is done to work around two + problems: A directory's modification time is reset each time a file is + created in it. And, if a directory's permissions do not allow writing, + extracting files to it will fail. + \versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}{extract}{member\optional{, path}} + Extract a member from the archive to the current working directory, + using its full name. Its file information is extracted as accurately as + possible. + \var{member} may be a filename or a \class{TarInfo} object. + You can specify a different directory using \var{path}. + \begin{notice} + Because the \method{extract()} method allows random access to a tar + archive there are some issues you must take care of yourself. See the + description for \method{extractall()} above. + \end{notice} +\end{methoddesc} + +\begin{methoddesc}{extractfile}{member} + Extract a member from the archive as a file object. + \var{member} may be a filename or a \class{TarInfo} object. + If \var{member} is a regular file, a file-like object is returned. + If \var{member} is a link, a file-like object is constructed from the + link's target. + If \var{member} is none of the above, \code{None} is returned. + \begin{notice} + The file-like object is read-only and provides the following methods: + \method{read()}, \method{readline()}, \method{readlines()}, + \method{seek()}, \method{tell()}. + \end{notice} +\end{methoddesc} + +\begin{methoddesc}{add}{name\optional{, arcname\optional{, recursive}}} + Add the file \var{name} to the archive. \var{name} may be any type + of file (directory, fifo, symbolic link, etc.). + If given, \var{arcname} specifies an alternative name for the file in the + archive. Directories are added recursively by default. + This can be avoided by setting \var{recursive} to \constant{False}; + the default is \constant{True}. +\end{methoddesc} + +\begin{methoddesc}{addfile}{tarinfo\optional{, fileobj}} + Add the \class{TarInfo} object \var{tarinfo} to the archive. + If \var{fileobj} is given, \code{\var{tarinfo}.size} bytes are read + from it and added to the archive. You can create \class{TarInfo} objects + using \method{gettarinfo()}. + \begin{notice} + On Windows platforms, \var{fileobj} should always be opened with mode + \code{'rb'} to avoid irritation about the file size. + \end{notice} +\end{methoddesc} + +\begin{methoddesc}{gettarinfo}{\optional{name\optional{, + arcname\optional{, fileobj}}}} + Create a \class{TarInfo} object for either the file \var{name} or + the file object \var{fileobj} (using \function{os.fstat()} on its + file descriptor). You can modify some of the \class{TarInfo}'s + attributes before you add it using \method{addfile()}. If given, + \var{arcname} specifies an alternative name for the file in the + archive. +\end{methoddesc} + +\begin{methoddesc}{close}{} + Close the \class{TarFile}. In write mode, two finishing zero + blocks are appended to the archive. +\end{methoddesc} + +\begin{memberdesc}{posix} + If true, create a \POSIX{} 1003.1-1990 compliant archive. GNU + extensions are not used, because they are not part of the \POSIX{} + standard. This limits the length of filenames to at most 256, + link names to 100 characters and the maximum file size to 8 + gigabytes. A \exception{ValueError} is raised if a file exceeds + this limit. If false, create a GNU tar compatible archive. It + will not be \POSIX{} compliant, but can store files without any + of the above restrictions. + \versionchanged[\var{posix} defaults to \constant{False}]{2.4} +\end{memberdesc} + +\begin{memberdesc}{dereference} + If false, add symbolic and hard links to archive. If true, add the + content of the target files to the archive. This has no effect on + systems that do not support symbolic links. +\end{memberdesc} + +\begin{memberdesc}{ignore_zeros} + If false, treat an empty block as the end of the archive. If true, + skip empty (and invalid) blocks and try to get as many members as + possible. This is only useful for concatenated or damaged + archives. +\end{memberdesc} + +\begin{memberdesc}{debug=0} + To be set from \code{0} (no debug messages; the default) up to + \code{3} (all debug messages). The messages are written to + \code{sys.stderr}. +\end{memberdesc} + +\begin{memberdesc}{errorlevel} + If \code{0} (the default), all errors are ignored when using + \method{extract()}. Nevertheless, they appear as error messages + in the debug output, when debugging is enabled. If \code{1}, all + \emph{fatal} errors are raised as \exception{OSError} or + \exception{IOError} exceptions. If \code{2}, all \emph{non-fatal} + errors are raised as \exception{TarError} exceptions as well. +\end{memberdesc} + +%----------------- +% TarInfo Objects +%----------------- + +\subsection{TarInfo Objects \label{tarinfo-objects}} + +A \class{TarInfo} object represents one member in a +\class{TarFile}. Aside from storing all required attributes of a file +(like file type, size, time, permissions, owner etc.), it provides +some useful methods to determine its type. It does \emph{not} contain +the file's data itself. + +\class{TarInfo} objects are returned by \class{TarFile}'s methods +\method{getmember()}, \method{getmembers()} and \method{gettarinfo()}. + +\begin{classdesc}{TarInfo}{\optional{name}} + Create a \class{TarInfo} object. +\end{classdesc} + +\begin{methoddesc}{frombuf}{} + Create and return a \class{TarInfo} object from a string buffer. +\end{methoddesc} + +\begin{methoddesc}{tobuf}{posix} + Create a string buffer from a \class{TarInfo} object. + See \class{TarFile}'s \member{posix} attribute for information + on the \var{posix} argument. It defaults to \constant{False}. + + \versionadded[The \var{posix} parameter]{2.5} +\end{methoddesc} + +A \code{TarInfo} object has the following public data attributes: + +\begin{memberdesc}{name} + Name of the archive member. +\end{memberdesc} + +\begin{memberdesc}{size} + Size in bytes. +\end{memberdesc} + +\begin{memberdesc}{mtime} + Time of last modification. +\end{memberdesc} + +\begin{memberdesc}{mode} + Permission bits. +\end{memberdesc} + +\begin{memberdesc}{type} + File type. \var{type} is usually one of these constants: + \constant{REGTYPE}, \constant{AREGTYPE}, \constant{LNKTYPE}, + \constant{SYMTYPE}, \constant{DIRTYPE}, \constant{FIFOTYPE}, + \constant{CONTTYPE}, \constant{CHRTYPE}, \constant{BLKTYPE}, + \constant{GNUTYPE_SPARSE}. To determine the type of a + \class{TarInfo} object more conveniently, use the \code{is_*()} + methods below. +\end{memberdesc} + +\begin{memberdesc}{linkname} + Name of the target file name, which is only present in + \class{TarInfo} objects of type \constant{LNKTYPE} and + \constant{SYMTYPE}. +\end{memberdesc} + +\begin{memberdesc}{uid} + User ID of the user who originally stored this member. +\end{memberdesc} + +\begin{memberdesc}{gid} + Group ID of the user who originally stored this member. +\end{memberdesc} + +\begin{memberdesc}{uname} + User name. +\end{memberdesc} + +\begin{memberdesc}{gname} + Group name. +\end{memberdesc} + +A \class{TarInfo} object also provides some convenient query methods: + +\begin{methoddesc}{isfile}{} + Return \constant{True} if the \class{Tarinfo} object is a regular + file. +\end{methoddesc} + +\begin{methoddesc}{isreg}{} + Same as \method{isfile()}. +\end{methoddesc} + +\begin{methoddesc}{isdir}{} + Return \constant{True} if it is a directory. +\end{methoddesc} + +\begin{methoddesc}{issym}{} + Return \constant{True} if it is a symbolic link. +\end{methoddesc} + +\begin{methoddesc}{islnk}{} + Return \constant{True} if it is a hard link. +\end{methoddesc} + +\begin{methoddesc}{ischr}{} + Return \constant{True} if it is a character device. +\end{methoddesc} + +\begin{methoddesc}{isblk}{} + Return \constant{True} if it is a block device. +\end{methoddesc} + +\begin{methoddesc}{isfifo}{} + Return \constant{True} if it is a FIFO. +\end{methoddesc} + +\begin{methoddesc}{isdev}{} + Return \constant{True} if it is one of character device, block + device or FIFO. +\end{methoddesc} + +%------------------------ +% Examples +%------------------------ + +\subsection{Examples \label{tar-examples}} + +How to extract an entire tar archive to the current working directory: +\begin{verbatim} +import tarfile +tar = tarfile.open("sample.tar.gz") +tar.extractall() +tar.close() +\end{verbatim} + +How to create an uncompressed tar archive from a list of filenames: +\begin{verbatim} +import tarfile +tar = tarfile.open("sample.tar", "w") +for name in ["foo", "bar", "quux"]: + tar.add(name) +tar.close() +\end{verbatim} + +How to read a gzip compressed tar archive and display some member information: +\begin{verbatim} +import tarfile +tar = tarfile.open("sample.tar.gz", "r:gz") +for tarinfo in tar: + print tarinfo.name, "is", tarinfo.size, "bytes in size and is", + if tarinfo.isreg(): + print "a regular file." + elif tarinfo.isdir(): + print "a directory." + else: + print "something else." +tar.close() +\end{verbatim} + +How to create a tar archive with faked information: +\begin{verbatim} +import tarfile +tar = tarfile.open("sample.tar.gz", "w:gz") +for name in namelist: + tarinfo = tar.gettarinfo(name, "fakeproj-1.0/" + name) + tarinfo.uid = 123 + tarinfo.gid = 456 + tarinfo.uname = "johndoe" + tarinfo.gname = "fake" + tar.addfile(tarinfo, file(name)) +tar.close() +\end{verbatim} + +The \emph{only} way to extract an uncompressed tar stream from +\code{sys.stdin}: +\begin{verbatim} +import sys +import tarfile +tar = tarfile.open(mode="r|", fileobj=sys.stdin) +for tarinfo in tar: + tar.extract(tarinfo) +tar.close() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libtelnetlib.tex b/sys/src/cmd/python/Doc/lib/libtelnetlib.tex new file mode 100644 index 000000000..c7a4226dc --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtelnetlib.tex @@ -0,0 +1,215 @@ +\section{\module{telnetlib} --- + Telnet client} + +\declaremodule{standard}{telnetlib} +\modulesynopsis{Telnet client class.} +\sectionauthor{Skip Montanaro}{skip@mojam.com} + +\index{protocol!Telnet} + +The \module{telnetlib} module provides a \class{Telnet} class that +implements the Telnet protocol. See \rfc{854} for details about the +protocol. In addition, it provides symbolic constants for the protocol +characters (see below), and for the telnet options. The +symbolic names of the telnet options follow the definitions in +\code{arpa/telnet.h}, with the leading \code{TELOPT_} removed. For +symbolic names of options which are traditionally not included in +\code{arpa/telnet.h}, see the module source itself. + +The symbolic constants for the telnet commands are: IAC, DONT, DO, +WONT, WILL, SE (Subnegotiation End), NOP (No Operation), DM (Data +Mark), BRK (Break), IP (Interrupt process), AO (Abort output), AYT +(Are You There), EC (Erase Character), EL (Erase Line), GA (Go Ahead), +SB (Subnegotiation Begin). + + +\begin{classdesc}{Telnet}{\optional{host\optional{, port}}} +\class{Telnet} represents a connection to a Telnet server. The +instance is initially not connected by default; the \method{open()} +method must be used to establish a connection. Alternatively, the +host name and optional port number can be passed to the constructor, +to, in which case the connection to the server will be established +before the constructor returns. + +Do not reopen an already connected instance. + +This class has many \method{read_*()} methods. Note that some of them +raise \exception{EOFError} when the end of the connection is read, +because they can return an empty string for other reasons. See the +individual descriptions below. +\end{classdesc} + + +\begin{seealso} + \seerfc{854}{Telnet Protocol Specification}{ + Definition of the Telnet protocol.} +\end{seealso} + + + +\subsection{Telnet Objects \label{telnet-objects}} + +\class{Telnet} instances have the following methods: + + +\begin{methoddesc}{read_until}{expected\optional{, timeout}} +Read until a given string, \var{expected}, is encountered or until +\var{timeout} seconds have passed. + +When no match is found, return whatever is available instead, +possibly the empty string. Raise \exception{EOFError} if the connection +is closed and no cooked data is available. +\end{methoddesc} + +\begin{methoddesc}{read_all}{} +Read all data until \EOF; block until connection closed. +\end{methoddesc} + +\begin{methoddesc}{read_some}{} +Read at least one byte of cooked data unless \EOF{} is hit. +Return \code{''} if \EOF{} is hit. Block if no data is immediately +available. +\end{methoddesc} + +\begin{methoddesc}{read_very_eager}{} +Read everything that can be without blocking in I/O (eager). + +Raise \exception{EOFError} if connection closed and no cooked data +available. Return \code{''} if no cooked data available otherwise. +Do not block unless in the midst of an IAC sequence. +\end{methoddesc} + +\begin{methoddesc}{read_eager}{} +Read readily available data. + +Raise \exception{EOFError} if connection closed and no cooked data +available. Return \code{''} if no cooked data available otherwise. +Do not block unless in the midst of an IAC sequence. +\end{methoddesc} + +\begin{methoddesc}{read_lazy}{} +Process and return data already in the queues (lazy). + +Raise \exception{EOFError} if connection closed and no data available. +Return \code{''} if no cooked data available otherwise. Do not block +unless in the midst of an IAC sequence. +\end{methoddesc} + +\begin{methoddesc}{read_very_lazy}{} +Return any data available in the cooked queue (very lazy). + +Raise \exception{EOFError} if connection closed and no data available. +Return \code{''} if no cooked data available otherwise. This method +never blocks. +\end{methoddesc} + +\begin{methoddesc}{read_sb_data}{} +Return the data collected between a SB/SE pair (suboption begin/end). +The callback should access these data when it was invoked with a +\code{SE} command. This method never blocks. + +\versionadded{2.3} +\end{methoddesc} + +\begin{methoddesc}{open}{host\optional{, port}} +Connect to a host. +The optional second argument is the port number, which +defaults to the standard Telnet port (23). + +Do not try to reopen an already connected instance. +\end{methoddesc} + +\begin{methoddesc}{msg}{msg\optional{, *args}} +Print a debug message when the debug level is \code{>} 0. +If extra arguments are present, they are substituted in the +message using the standard string formatting operator. +\end{methoddesc} + +\begin{methoddesc}{set_debuglevel}{debuglevel} +Set the debug level. The higher the value of \var{debuglevel}, the +more debug output you get (on \code{sys.stdout}). +\end{methoddesc} + +\begin{methoddesc}{close}{} +Close the connection. +\end{methoddesc} + +\begin{methoddesc}{get_socket}{} +Return the socket object used internally. +\end{methoddesc} + +\begin{methoddesc}{fileno}{} +Return the file descriptor of the socket object used internally. +\end{methoddesc} + +\begin{methoddesc}{write}{buffer} +Write a string to the socket, doubling any IAC characters. +This can block if the connection is blocked. May raise +\exception{socket.error} if the connection is closed. +\end{methoddesc} + +\begin{methoddesc}{interact}{} +Interaction function, emulates a very dumb Telnet client. +\end{methoddesc} + +\begin{methoddesc}{mt_interact}{} +Multithreaded version of \method{interact()}. +\end{methoddesc} + +\begin{methoddesc}{expect}{list\optional{, timeout}} +Read until one from a list of a regular expressions matches. + +The first argument is a list of regular expressions, either +compiled (\class{re.RegexObject} instances) or uncompiled (strings). +The optional second argument is a timeout, in seconds; the default +is to block indefinitely. + +Return a tuple of three items: the index in the list of the +first regular expression that matches; the match object +returned; and the text read up till and including the match. + +If end of file is found and no text was read, raise +\exception{EOFError}. Otherwise, when nothing matches, return +\code{(-1, None, \var{text})} where \var{text} is the text received so +far (may be the empty string if a timeout happened). + +If a regular expression ends with a greedy match (such as \regexp{.*}) +or if more than one expression can match the same input, the +results are indeterministic, and may depend on the I/O timing. +\end{methoddesc} + +\begin{methoddesc}{set_option_negotiation_callback}{callback} +Each time a telnet option is read on the input flow, this +\var{callback} (if set) is called with the following parameters : +callback(telnet socket, command (DO/DONT/WILL/WONT), option). No other +action is done afterwards by telnetlib. +\end{methoddesc} + + +\subsection{Telnet Example \label{telnet-example}} +\sectionauthor{Peter Funk}{pf@artcom-gmbh.de} + +A simple example illustrating typical use: + +\begin{verbatim} +import getpass +import sys +import telnetlib + +HOST = "localhost" +user = raw_input("Enter your remote account: ") +password = getpass.getpass() + +tn = telnetlib.Telnet(HOST) + +tn.read_until("login: ") +tn.write(user + "\n") +if password: + tn.read_until("Password: ") + tn.write(password + "\n") + +tn.write("ls\n") +tn.write("exit\n") + +print tn.read_all() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libtempfile.tex b/sys/src/cmd/python/Doc/lib/libtempfile.tex new file mode 100644 index 000000000..9b4d8488b --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtempfile.tex @@ -0,0 +1,194 @@ +\section{\module{tempfile} --- + Generate temporary files and directories} +\sectionauthor{Zack Weinberg}{zack@codesourcery.com} + +\declaremodule{standard}{tempfile} +\modulesynopsis{Generate temporary files and directories.} + +\indexii{temporary}{file name} +\indexii{temporary}{file} + +This module generates temporary files and directories. It works on +all supported platforms. + +In version 2.3 of Python, this module was overhauled for enhanced +security. It now provides three new functions, +\function{NamedTemporaryFile()}, \function{mkstemp()}, and +\function{mkdtemp()}, which should eliminate all remaining need to use +the insecure \function{mktemp()} function. Temporary file names created +by this module no longer contain the process ID; instead a string of +six random characters is used. + +Also, all the user-callable functions now take additional arguments +which allow direct control over the location and name of temporary +files. It is no longer necessary to use the global \var{tempdir} and +\var{template} variables. To maintain backward compatibility, the +argument order is somewhat odd; it is recommended to use keyword +arguments for clarity. + +The module defines the following user-callable functions: + +\begin{funcdesc}{TemporaryFile}{\optional{mode=\code{'w+b'}\optional{, + bufsize=\code{-1}\optional{, + suffix\optional{, prefix\optional{, dir}}}}}} +Return a file (or file-like) object that can be used as a temporary +storage area. The file is created using \function{mkstemp}. It will +be destroyed as soon as it is closed (including an implicit close when +the object is garbage collected). Under \UNIX, the directory entry +for the file is removed immediately after the file is created. Other +platforms do not support this; your code should not rely on a +temporary file created using this function having or not having a +visible name in the file system. + +The \var{mode} parameter defaults to \code{'w+b'} so that the file +created can be read and written without being closed. Binary mode is +used so that it behaves consistently on all platforms without regard +for the data that is stored. \var{bufsize} defaults to \code{-1}, +meaning that the operating system default is used. + +The \var{dir}, \var{prefix} and \var{suffix} parameters are passed to +\function{mkstemp()}. +\end{funcdesc} + +\begin{funcdesc}{NamedTemporaryFile}{\optional{mode=\code{'w+b'}\optional{, + bufsize=\code{-1}\optional{, + suffix\optional{, prefix\optional{, + dir}}}}}} +This function operates exactly as \function{TemporaryFile()} does, +except that the file is guaranteed to have a visible name in the file +system (on \UNIX, the directory entry is not unlinked). That name can +be retrieved from the \member{name} member of the file object. Whether +the name can be used to open the file a second time, while the +named temporary file is still open, varies across platforms (it can +be so used on \UNIX; it cannot on Windows NT or later). +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{mkstemp}{\optional{suffix\optional{, + prefix\optional{, dir\optional{, text}}}}} +Creates a temporary file in the most secure manner possible. There +are no race conditions in the file's creation, assuming that the +platform properly implements the \constant{O_EXCL} flag for +\function{os.open()}. The file is readable and writable only by the +creating user ID. If the platform uses permission bits to indicate +whether a file is executable, the file is executable by no one. The +file descriptor is not inherited by child processes. + +Unlike \function{TemporaryFile()}, the user of \function{mkstemp()} is +responsible for deleting the temporary file when done with it. + +If \var{suffix} is specified, the file name will end with that suffix, +otherwise there will be no suffix. \function{mkstemp()} does not put a +dot between the file name and the suffix; if you need one, put it at +the beginning of \var{suffix}. + +If \var{prefix} is specified, the file name will begin with that +prefix; otherwise, a default prefix is used. + +If \var{dir} is specified, the file will be created in that directory; +otherwise, a default directory is used. The default directory is chosen +from a platform-dependent list, but the user of the application can control +the directory location by setting the \var{TMPDIR}, \var{TEMP} or \var{TMP} +environment variables. There is thus no guarantee that the generated +filename will have any nice properties, such as not requiring quoting when +passed to external commands via \code{os.popen()}. + +If \var{text} is specified, it indicates whether to open the file in +binary mode (the default) or text mode. On some platforms, this makes +no difference. + +\function{mkstemp()} returns a tuple containing an OS-level handle to +an open file (as would be returned by \function{os.open()}) and the +absolute pathname of that file, in that order. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{mkdtemp}{\optional{suffix\optional{, prefix\optional{, dir}}}} +Creates a temporary directory in the most secure manner possible. +There are no race conditions in the directory's creation. The +directory is readable, writable, and searchable only by the +creating user ID. + +The user of \function{mkdtemp()} is responsible for deleting the +temporary directory and its contents when done with it. + +The \var{prefix}, \var{suffix}, and \var{dir} arguments are the same +as for \function{mkstemp()}. + +\function{mkdtemp()} returns the absolute pathname of the new directory. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{mktemp}{\optional{suffix\optional{, prefix\optional{, dir}}}} +\deprecated{2.3}{Use \function{mkstemp()} instead.} +Return an absolute pathname of a file that did not exist at the time +the call is made. The \var{prefix}, \var{suffix}, and \var{dir} +arguments are the same as for \function{mkstemp()}. + +\warning{Use of this function may introduce a security hole in your +program. By the time you get around to doing anything with the file +name it returns, someone else may have beaten you to the punch.} +\end{funcdesc} + +The module uses two global variables that tell it how to construct a +temporary name. They are initialized at the first call to any of the +functions above. The caller may change them, but this is discouraged; +use the appropriate function arguments, instead. + +\begin{datadesc}{tempdir} +When set to a value other than \code{None}, this variable defines the +default value for the \var{dir} argument to all the functions defined +in this module. + +If \code{tempdir} is unset or \code{None} at any call to any of the +above functions, Python searches a standard list of directories and +sets \var{tempdir} to the first one which the calling user can create +files in. The list is: + +\begin{enumerate} +\item The directory named by the \envvar{TMPDIR} environment variable. +\item The directory named by the \envvar{TEMP} environment variable. +\item The directory named by the \envvar{TMP} environment variable. +\item A platform-specific location: + \begin{itemize} + \item On RiscOS, the directory named by the + \envvar{Wimp\$ScrapDir} environment variable. + \item On Windows, the directories + \file{C:$\backslash$TEMP}, + \file{C:$\backslash$TMP}, + \file{$\backslash$TEMP}, and + \file{$\backslash$TMP}, in that order. + \item On all other platforms, the directories + \file{/tmp}, \file{/var/tmp}, and \file{/usr/tmp}, in that order. + \end{itemize} +\item As a last resort, the current working directory. +\end{enumerate} +\end{datadesc} + +\begin{funcdesc}{gettempdir}{} +Return the directory currently selected to create temporary files in. +If \code{tempdir} is not \code{None}, this simply returns its contents; +otherwise, the search described above is performed, and the result +returned. +\end{funcdesc} + +\begin{datadesc}{template} +\deprecated{2.0}{Use \function{gettempprefix()} instead.} +When set to a value other than \code{None}, this variable defines the +prefix of the final component of the filenames returned by +\function{mktemp()}. A string of six random letters and digits is +appended to the prefix to make the filename unique. On Windows, +the default prefix is \file{\textasciitilde{}T}; on all other systems +it is \file{tmp}. + +Older versions of this module used to require that \code{template} be +set to \code{None} after a call to \function{os.fork()}; this has not +been necessary since version 1.5.2. +\end{datadesc} + +\begin{funcdesc}{gettempprefix}{} +Return the filename prefix used to create temporary files. This does +not contain the directory component. Using this function is preferred +over reading the \var{template} variable directly. +\versionadded{1.5.2} +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libtermios.tex b/sys/src/cmd/python/Doc/lib/libtermios.tex new file mode 100644 index 000000000..ef99cf9ed --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtermios.tex @@ -0,0 +1,106 @@ +\section{\module{termios} --- + \POSIX{} style tty control} + +\declaremodule{builtin}{termios} + \platform{Unix} +\modulesynopsis{\POSIX\ style tty control.} + +\indexii{\POSIX}{I/O control} +\indexii{tty}{I/O control} + + +This module provides an interface to the \POSIX{} calls for tty I/O +control. For a complete description of these calls, see the \POSIX{} or +\UNIX{} manual pages. It is only available for those \UNIX{} versions +that support \POSIX{} \emph{termios} style tty I/O control (and then +only if configured at installation time). + +All functions in this module take a file descriptor \var{fd} as their +first argument. This can be an integer file descriptor, such as +returned by \code{sys.stdin.fileno()}, or a file object, such as +\code{sys.stdin} itself. + +This module also defines all the constants needed to work with the +functions provided here; these have the same name as their +counterparts in C. Please refer to your system documentation for more +information on using these terminal control interfaces. + +The module defines the following functions: + +\begin{funcdesc}{tcgetattr}{fd} +Return a list containing the tty attributes for file descriptor +\var{fd}, as follows: \code{[}\var{iflag}, \var{oflag}, \var{cflag}, +\var{lflag}, \var{ispeed}, \var{ospeed}, \var{cc}\code{]} where +\var{cc} is a list of the tty special characters (each a string of +length 1, except the items with indices \constant{VMIN} and +\constant{VTIME}, which are integers when these fields are +defined). The interpretation of the flags and the speeds as well as +the indexing in the \var{cc} array must be done using the symbolic +constants defined in the \module{termios} +module. +\end{funcdesc} + +\begin{funcdesc}{tcsetattr}{fd, when, attributes} +Set the tty attributes for file descriptor \var{fd} from the +\var{attributes}, which is a list like the one returned by +\function{tcgetattr()}. The \var{when} argument determines when the +attributes are changed: \constant{TCSANOW} to change immediately, +\constant{TCSADRAIN} to change after transmitting all queued output, +or \constant{TCSAFLUSH} to change after transmitting all queued +output and discarding all queued input. +\end{funcdesc} + +\begin{funcdesc}{tcsendbreak}{fd, duration} +Send a break on file descriptor \var{fd}. A zero \var{duration} sends +a break for 0.25--0.5 seconds; a nonzero \var{duration} has a system +dependent meaning. +\end{funcdesc} + +\begin{funcdesc}{tcdrain}{fd} +Wait until all output written to file descriptor \var{fd} has been +transmitted. +\end{funcdesc} + +\begin{funcdesc}{tcflush}{fd, queue} +Discard queued data on file descriptor \var{fd}. The \var{queue} +selector specifies which queue: \constant{TCIFLUSH} for the input +queue, \constant{TCOFLUSH} for the output queue, or +\constant{TCIOFLUSH} for both queues. +\end{funcdesc} + +\begin{funcdesc}{tcflow}{fd, action} +Suspend or resume input or output on file descriptor \var{fd}. The +\var{action} argument can be \constant{TCOOFF} to suspend output, +\constant{TCOON} to restart output, \constant{TCIOFF} to suspend +input, or \constant{TCION} to restart input. +\end{funcdesc} + + +\begin{seealso} + \seemodule{tty}{Convenience functions for common terminal control + operations.} +\end{seealso} + + +\subsection{Example} +\nodename{termios Example} + +Here's a function that prompts for a password with echoing turned +off. Note the technique using a separate \function{tcgetattr()} call +and a \keyword{try} ... \keyword{finally} statement to ensure that the +old tty attributes are restored exactly no matter what happens: + +\begin{verbatim} +def getpass(prompt = "Password: "): + import termios, sys + fd = sys.stdin.fileno() + old = termios.tcgetattr(fd) + new = termios.tcgetattr(fd) + new[3] = new[3] & ~termios.ECHO # lflags + try: + termios.tcsetattr(fd, termios.TCSADRAIN, new) + passwd = raw_input(prompt) + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old) + return passwd +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libtest.tex b/sys/src/cmd/python/Doc/lib/libtest.tex new file mode 100644 index 000000000..54a24b1c9 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtest.tex @@ -0,0 +1,278 @@ +\section{\module{test} --- + Regression tests package for Python} + +\declaremodule{standard}{test} +\sectionauthor{Brett Cannon}{brett@python.org} +\modulesynopsis{Regression tests package containing the testing suite + for Python.} + + +The \module{test} package contains all regression tests for Python as +well as the modules \module{test.test_support} and +\module{test.regrtest}. \module{test.test_support} is used to enhance +your tests while \module{test.regrtest} drives the testing suite. + +Each module in the \module{test} package whose name starts with +\samp{test_} is a testing suite for a specific module or feature. +All new tests should be written using the \refmodule{unittest} module; +using \refmodule{unittest} is not required but makes the tests more +flexible and maintenance of the tests easier. Some older tests are +written to use \refmodule{doctest} and a ``traditional'' testing +style; these styles of tests will not be covered. + +\begin{seealso} +\seemodule{unittest}{Writing PyUnit regression tests.} +\seemodule{doctest}{Tests embedded in documentation strings.} +\end{seealso} + + +\subsection{Writing Unit Tests for the \module{test} package% + \label{writing-tests}} + +It is preferred that tests for the \module{test} package use the +\refmodule{unittest} module and follow a few guidelines. +One is to name the test module by starting it with \samp{test_} and end it with +the name of the module being tested. +The test methods in the test module should start with \samp{test_} and end with +a description of what the method is testing. +This is needed so that the methods are recognized by the test driver as +test methods. +Also, no documentation string for the method should be included. +A comment (such as +\samp{\# Tests function returns only True or False}) should be used to provide +documentation for test methods. +This is done because documentation strings get printed out if they exist and +thus what test is being run is not stated. + +A basic boilerplate is often used: + +\begin{verbatim} +import unittest +from test import test_support + +class MyTestCase1(unittest.TestCase): + + # Only use setUp() and tearDown() if necessary + + def setUp(self): + ... code to execute in preparation for tests ... + + def tearDown(self): + ... code to execute to clean up after tests ... + + def test_feature_one(self): + # Test feature one. + ... testing code ... + + def test_feature_two(self): + # Test feature two. + ... testing code ... + + ... more test methods ... + +class MyTestCase2(unittest.TestCase): + ... same structure as MyTestCase1 ... + +... more test classes ... + +def test_main(): + test_support.run_unittest(MyTestCase1, + MyTestCase2, + ... list other tests ... + ) + +if __name__ == '__main__': + test_main() +\end{verbatim} + +This boilerplate code allows the testing suite to be run by +\module{test.regrtest} as well as on its own as a script. + +The goal for regression testing is to try to break code. +This leads to a few guidelines to be followed: + +\begin{itemize} +\item The testing suite should exercise all classes, functions, and + constants. + This includes not just the external API that is to be presented to the + outside world but also "private" code. +\item Whitebox testing (examining the code being tested when the tests are + being written) is preferred. + Blackbox testing (testing only the published user interface) is not + complete enough to make sure all boundary and edge cases are tested. +\item Make sure all possible values are tested including invalid ones. + This makes sure that not only all valid values are acceptable but also + that improper values are handled correctly. +\item Exhaust as many code paths as possible. + Test where branching occurs and thus tailor input to make sure as many + different paths through the code are taken. +\item Add an explicit test for any bugs discovered for the tested code. + This will make sure that the error does not crop up again if the code is + changed in the future. +\item Make sure to clean up after your tests (such as close and remove all + temporary files). +\item If a test is dependent on a specific condition of the operating system + then verify the condition already exists before attempting the test. +\item Import as few modules as possible and do it as soon as possible. + This minimizes external dependencies of tests and also minimizes possible + anomalous behavior from side-effects of importing a module. +\item Try to maximize code reuse. + On occasion, tests will vary by something as small as what type + of input is used. + Minimize code duplication by subclassing a basic test class with a class + that specifies the input: +\begin{verbatim} +class TestFuncAcceptsSequences(unittest.TestCase): + + func = mySuperWhammyFunction + + def test_func(self): + self.func(self.arg) + +class AcceptLists(TestFuncAcceptsSequences): + arg = [1,2,3] + +class AcceptStrings(TestFuncAcceptsSequences): + arg = 'abc' + +class AcceptTuples(TestFuncAcceptsSequences): + arg = (1,2,3) +\end{verbatim} +\end{itemize} + +\begin{seealso} +\seetitle{Test Driven Development} + {A book by Kent Beck on writing tests before code.} +\end{seealso} + + +\subsection{Running tests using \module{test.regrtest} \label{regrtest}} + +\module{test.regrtest} can be used as a script to drive Python's +regression test suite. +Running the script by itself automatically starts running all +regression tests in the \module{test} package. +It does this by finding all modules in the package whose name starts with +\samp{test_}, importing them, and executing the function +\function{test_main()} if present. +The names of tests to execute may also be passed to the script. +Specifying a single regression test (\program{python regrtest.py} +\programopt{test_spam.py}) will minimize output and only print whether +the test passed or failed and thus minimize output. + +Running \module{test.regrtest} directly allows what resources are +available for tests to use to be set. +You do this by using the \programopt{-u} command-line option. +Run \program{python regrtest.py} \programopt{-uall} to turn on all +resources; specifying \programopt{all} as an option for +\programopt{-u} enables all possible resources. +If all but one resource is desired (a more common case), a +comma-separated list of resources that are not desired may be listed after +\programopt{all}. +The command \program{python regrtest.py} +\programopt{-uall,-audio,-largefile} will run \module{test.regrtest} +with all resources except the \programopt{audio} and +\programopt{largefile} resources. +For a list of all resources and more command-line options, run +\program{python regrtest.py} \programopt{-h}. + +Some other ways to execute the regression tests depend on what platform the +tests are being executed on. +On \UNIX{}, you can run \program{make} \programopt{test} at the +top-level directory where Python was built. +On Windows, executing \program{rt.bat} from your \file{PCBuild} +directory will run all regression tests. + + +\section{\module{test.test_support} --- + Utility functions for tests} + +\declaremodule[test.testsupport]{standard}{test.test_support} +\modulesynopsis{Support for Python regression tests.} + +The \module{test.test_support} module provides support for Python's +regression tests. + +This module defines the following exceptions: + +\begin{excdesc}{TestFailed} +Exception to be raised when a test fails. +\end{excdesc} + +\begin{excdesc}{TestSkipped} +Subclass of \exception{TestFailed}. +Raised when a test is skipped. +This occurs when a needed resource (such as a network connection) is not +available at the time of testing. +\end{excdesc} + +\begin{excdesc}{ResourceDenied} +Subclass of \exception{TestSkipped}. +Raised when a resource (such as a network connection) is not available. +Raised by the \function{requires()} function. +\end{excdesc} + + +The \module{test.test_support} module defines the following constants: + +\begin{datadesc}{verbose} +\constant{True} when verbose output is enabled. +Should be checked when more detailed information is desired about a running +test. +\var{verbose} is set by \module{test.regrtest}. +\end{datadesc} + +\begin{datadesc}{have_unicode} +\constant{True} when Unicode support is available. +\end{datadesc} + +\begin{datadesc}{is_jython} +\constant{True} if the running interpreter is Jython. +\end{datadesc} + +\begin{datadesc}{TESTFN} +Set to the path that a temporary file may be created at. +Any temporary that is created should be closed and unlinked (removed). +\end{datadesc} + + +The \module{test.test_support} module defines the following functions: + +\begin{funcdesc}{forget}{module_name} +Removes the module named \var{module_name} from \code{sys.modules} and deletes +any byte-compiled files of the module. +\end{funcdesc} + +\begin{funcdesc}{is_resource_enabled}{resource} +Returns \constant{True} if \var{resource} is enabled and available. +The list of available resources is only set when \module{test.regrtest} +is executing the tests. +\end{funcdesc} + +\begin{funcdesc}{requires}{resource\optional{, msg}} +Raises \exception{ResourceDenied} if \var{resource} is not available. +\var{msg} is the argument to \exception{ResourceDenied} if it is raised. +Always returns true if called by a function whose \code{__name__} is +\code{'__main__'}. +Used when tests are executed by \module{test.regrtest}. +\end{funcdesc} + +\begin{funcdesc}{findfile}{filename} +Return the path to the file named \var{filename}. +If no match is found \var{filename} is returned. +This does not equal a failure since it could be the path to the file. +\end{funcdesc} + +\begin{funcdesc}{run_unittest}{*classes} +Execute \class{unittest.TestCase} subclasses passed to the function. +The function scans the classes for methods starting with the prefix +\samp{test_} and executes the tests individually. +This is the preferred way to execute tests. +\end{funcdesc} + +\begin{funcdesc}{run_suite}{suite\optional{, testclass}} +Execute the \class{unittest.TestSuite} instance \var{suite}. +The optional argument \var{testclass} accepts one of the test classes in the +suite so as to print out more detailed information on where the testing suite +originated from. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libtextwrap.tex b/sys/src/cmd/python/Doc/lib/libtextwrap.tex new file mode 100644 index 000000000..38f9b03f9 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtextwrap.tex @@ -0,0 +1,181 @@ +\section{\module{textwrap} --- + Text wrapping and filling} + +\declaremodule{standard}{textwrap} +\modulesynopsis{Text wrapping and filling} +\moduleauthor{Greg Ward}{gward@python.net} +\sectionauthor{Greg Ward}{gward@python.net} + +\versionadded{2.3} + +The \module{textwrap} module provides two convenience functions, +\function{wrap()} and \function{fill()}, as well as +\class{TextWrapper}, the class that does all the work, and a utility function +\function{dedent()}. If you're just wrapping or filling one or two +text strings, the convenience functions should be good enough; otherwise, +you should use an instance of \class{TextWrapper} for efficiency. + +\begin{funcdesc}{wrap}{text\optional{, width\optional{, \moreargs}}} +Wraps the single paragraph in \var{text} (a string) so every line is at +most \var{width} characters long. Returns a list of output lines, +without final newlines. + +Optional keyword arguments correspond to the instance attributes of +\class{TextWrapper}, documented below. \var{width} defaults to +\code{70}. +\end{funcdesc} + +\begin{funcdesc}{fill}{text\optional{, width\optional{, \moreargs}}} +Wraps the single paragraph in \var{text}, and returns a single string +containing the wrapped paragraph. \function{fill()} is shorthand for +\begin{verbatim} +"\n".join(wrap(text, ...)) +\end{verbatim} + +In particular, \function{fill()} accepts exactly the same keyword +arguments as \function{wrap()}. +\end{funcdesc} + +Both \function{wrap()} and \function{fill()} work by creating a +\class{TextWrapper} instance and calling a single method on it. That +instance is not reused, so for applications that wrap/fill many text +strings, it will be more efficient for you to create your own +\class{TextWrapper} object. + +An additional utility function, \function{dedent()}, is provided to +remove indentation from strings that have unwanted whitespace to the +left of the text. + +\begin{funcdesc}{dedent}{text} +Remove any common leading whitespace from every line in \var{text}. + +This can be used to make triple-quoted strings line up with the left +edge of the display, while still presenting them in the source code +in indented form. + +Note that tabs and spaces are both treated as whitespace, but they are +not equal: the lines \code{" {} hello"} and \code{"\textbackslash{}thello"} +are considered to have no common leading whitespace. (This behaviour is +new in Python 2.5; older versions of this module incorrectly expanded +tabs before searching for common leading whitespace.) + +For example: +\begin{verbatim} +def test(): + # end first line with \ to avoid the empty line! + s = '''\ + hello + world + ''' + print repr(s) # prints ' hello\n world\n ' + print repr(dedent(s)) # prints 'hello\n world\n' +\end{verbatim} +\end{funcdesc} + +\begin{classdesc}{TextWrapper}{...} +The \class{TextWrapper} constructor accepts a number of optional +keyword arguments. Each argument corresponds to one instance attribute, +so for example +\begin{verbatim} +wrapper = TextWrapper(initial_indent="* ") +\end{verbatim} +is the same as +\begin{verbatim} +wrapper = TextWrapper() +wrapper.initial_indent = "* " +\end{verbatim} + +You can re-use the same \class{TextWrapper} object many times, and you +can change any of its options through direct assignment to instance +attributes between uses. +\end{classdesc} + +The \class{TextWrapper} instance attributes (and keyword arguments to +the constructor) are as follows: + +\begin{memberdesc}{width} +(default: \code{70}) The maximum length of wrapped lines. As long as +there are no individual words in the input text longer than +\member{width}, \class{TextWrapper} guarantees that no output line +will be longer than \member{width} characters. +\end{memberdesc} + +\begin{memberdesc}{expand_tabs} +(default: \code{True}) If true, then all tab characters in \var{text} +will be expanded to spaces using the \method{expandtabs()} method of +\var{text}. +\end{memberdesc} + +\begin{memberdesc}{replace_whitespace} +(default: \code{True}) If true, each whitespace character (as defined +by \code{string.whitespace}) remaining after tab expansion will be +replaced by a single space. \note{If \member{expand_tabs} is false +and \member{replace_whitespace} is true, each tab character will be +replaced by a single space, which is \emph{not} the same as tab +expansion.} +\end{memberdesc} + +\begin{memberdesc}{initial_indent} +(default: \code{''}) String that will be prepended to the first line +of wrapped output. Counts towards the length of the first line. +\end{memberdesc} + +\begin{memberdesc}{subsequent_indent} +(default: \code{''}) String that will be prepended to all lines of +wrapped output except the first. Counts towards the length of each +line except the first. +\end{memberdesc} + +\begin{memberdesc}{fix_sentence_endings} +(default: \code{False}) If true, \class{TextWrapper} attempts to detect +sentence endings and ensure that sentences are always separated by +exactly two spaces. This is generally desired for text in a monospaced +font. However, the sentence detection algorithm is imperfect: it +assumes that a sentence ending consists of a lowercase letter followed +by one of \character{.}, +\character{!}, or \character{?}, possibly followed by one of +\character{"} or \character{'}, followed by a space. One problem +with this is algorithm is that it is unable to detect the difference +between ``Dr.'' in + +\begin{verbatim} +[...] Dr. Frankenstein's monster [...] +\end{verbatim} + +and ``Spot.'' in + +\begin{verbatim} +[...] See Spot. See Spot run [...] +\end{verbatim} + +\member{fix_sentence_endings} is false by default. + +Since the sentence detection algorithm relies on +\code{string.lowercase} for the definition of ``lowercase letter,'' +and a convention of using two spaces after a period to separate +sentences on the same line, it is specific to English-language texts. +\end{memberdesc} + +\begin{memberdesc}{break_long_words} +(default: \code{True}) If true, then words longer than +\member{width} will be broken in order to ensure that no lines are +longer than \member{width}. If it is false, long words will not be +broken, and some lines may be longer than \member{width}. (Long words +will be put on a line by themselves, in order to minimize the amount +by which \member{width} is exceeded.) +\end{memberdesc} + +\class{TextWrapper} also provides two public methods, analogous to the +module-level convenience functions: + +\begin{methoddesc}{wrap}{text} +Wraps the single paragraph in \var{text} (a string) so every line is +at most \member{width} characters long. All wrapping options are +taken from instance attributes of the \class{TextWrapper} instance. +Returns a list of output lines, without final newlines. +\end{methoddesc} + +\begin{methoddesc}{fill}{text} +Wraps the single paragraph in \var{text}, and returns a single string +containing the wrapped paragraph. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libthread.tex b/sys/src/cmd/python/Doc/lib/libthread.tex new file mode 100644 index 000000000..d007eecde --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libthread.tex @@ -0,0 +1,173 @@ +\section{\module{thread} --- + Multiple threads of control} + +\declaremodule{builtin}{thread} +\modulesynopsis{Create multiple threads of control within one interpreter.} + + +This module provides low-level primitives for working with multiple +threads (a.k.a.\ \dfn{light-weight processes} or \dfn{tasks}) --- multiple +threads of control sharing their global data space. For +synchronization, simple locks (a.k.a.\ \dfn{mutexes} or \dfn{binary +semaphores}) are provided. +\index{light-weight processes} +\index{processes, light-weight} +\index{binary semaphores} +\index{semaphores, binary} + +The module is optional. It is supported on Windows, Linux, SGI +IRIX, Solaris 2.x, as well as on systems that have a \POSIX{} thread +(a.k.a. ``pthread'') implementation. For systems lacking the \module{thread} +module, the \refmodule[dummythread]{dummy_thread} module is available. +It duplicates this module's interface and can be +used as a drop-in replacement. +\index{pthreads} +\indexii{threads}{\POSIX} + +It defines the following constant and functions: + +\begin{excdesc}{error} +Raised on thread-specific errors. +\end{excdesc} + +\begin{datadesc}{LockType} +This is the type of lock objects. +\end{datadesc} + +\begin{funcdesc}{start_new_thread}{function, args\optional{, kwargs}} +Start a new thread and return its identifier. The thread executes the function +\var{function} with the argument list \var{args} (which must be a tuple). The +optional \var{kwargs} argument specifies a dictionary of keyword arguments. +When the function returns, the thread silently exits. When the function +terminates with an unhandled exception, a stack trace is printed and +then the thread exits (but other threads continue to run). +\end{funcdesc} + +\begin{funcdesc}{interrupt_main}{} +Raise a \exception{KeyboardInterrupt} exception in the main thread. A subthread +can use this function to interrupt the main thread. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{exit}{} +Raise the \exception{SystemExit} exception. When not caught, this +will cause the thread to exit silently. +\end{funcdesc} + +%\begin{funcdesc}{exit_prog}{status} +%Exit all threads and report the value of the integer argument +%\var{status} as the exit status of the entire program. +%\strong{Caveat:} code in pending \keyword{finally} clauses, in this thread +%or in other threads, is not executed. +%\end{funcdesc} + +\begin{funcdesc}{allocate_lock}{} +Return a new lock object. Methods of locks are described below. The +lock is initially unlocked. +\end{funcdesc} + +\begin{funcdesc}{get_ident}{} +Return the `thread identifier' of the current thread. This is a +nonzero integer. Its value has no direct meaning; it is intended as a +magic cookie to be used e.g. to index a dictionary of thread-specific +data. Thread identifiers may be recycled when a thread exits and +another thread is created. +\end{funcdesc} + +\begin{funcdesc}{stack_size}{\optional{size}} +Return the thread stack size used when creating new threads. The +optional \var{size} argument specifies the stack size to be used for +subsequently created threads, and must be 0 (use platform or +configured default) or a positive integer value of at least 32,768 (32kB). +If changing the thread stack size is unsupported, a \exception{ThreadError} +is raised. If the specified stack size is invalid, a \exception{ValueError} +is raised and the stack size is unmodified. 32kB is currently the minimum +supported stack size value to guarantee sufficient stack space for the +interpreter itself. Note that some platforms may have particular +restrictions on values for the stack size, such as requiring a minimum +stack size > 32kB or requiring allocation in multiples of the system +memory page size - platform documentation should be referred to for +more information (4kB pages are common; using multiples of 4096 for +the stack size is the suggested approach in the absence of more +specific information). +Availability: Windows, systems with \POSIX{} threads. +\versionadded{2.5} +\end{funcdesc} + + +Lock objects have the following methods: + +\begin{methoddesc}[lock]{acquire}{\optional{waitflag}} +Without the optional argument, this method acquires the lock +unconditionally, if necessary waiting until it is released by another +thread (only one thread at a time can acquire a lock --- that's their +reason for existence). If the integer +\var{waitflag} argument is present, the action depends on its +value: if it is zero, the lock is only acquired if it can be acquired +immediately without waiting, while if it is nonzero, the lock is +acquired unconditionally as before. The +return value is \code{True} if the lock is acquired successfully, +\code{False} if not. +\end{methoddesc} + +\begin{methoddesc}[lock]{release}{} +Releases the lock. The lock must have been acquired earlier, but not +necessarily by the same thread. +\end{methoddesc} + +\begin{methoddesc}[lock]{locked}{} +Return the status of the lock:\ \code{True} if it has been acquired by +some thread, \code{False} if not. +\end{methoddesc} + +In addition to these methods, lock objects can also be used via the +\keyword{with} statement, e.g.: + +\begin{verbatim} +from __future__ import with_statement +import thread + +a_lock = thread.allocate_lock() + +with a_lock: + print "a_lock is locked while this executes" +\end{verbatim} + +\strong{Caveats:} + +\begin{itemize} +\item +Threads interact strangely with interrupts: the +\exception{KeyboardInterrupt} exception will be received by an +arbitrary thread. (When the \refmodule{signal}\refbimodindex{signal} +module is available, interrupts always go to the main thread.) + +\item +Calling \function{sys.exit()} or raising the \exception{SystemExit} +exception is equivalent to calling \function{exit()}. + +\item +Not all built-in functions that may block waiting for I/O allow other +threads to run. (The most popular ones (\function{time.sleep()}, +\method{\var{file}.read()}, \function{select.select()}) work as +expected.) + +\item +It is not possible to interrupt the \method{acquire()} method on a lock +--- the \exception{KeyboardInterrupt} exception will happen after the +lock has been acquired. + +\item +When the main thread exits, it is system defined whether the other +threads survive. On SGI IRIX using the native thread implementation, +they survive. On most other systems, they are killed without +executing \keyword{try} ... \keyword{finally} clauses or executing +object destructors. +\indexii{threads}{IRIX} + +\item +When the main thread exits, it does not do any of its usual cleanup +(except that \keyword{try} ... \keyword{finally} clauses are honored), +and the standard I/O files are not flushed. + +\end{itemize} diff --git a/sys/src/cmd/python/Doc/lib/libthreading.tex b/sys/src/cmd/python/Doc/lib/libthreading.tex new file mode 100644 index 000000000..eb8778b20 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libthreading.tex @@ -0,0 +1,716 @@ +\section{\module{threading} --- + Higher-level threading interface} + +\declaremodule{standard}{threading} +\modulesynopsis{Higher-level threading interface.} + + +This module constructs higher-level threading interfaces on top of the +lower level \refmodule{thread} module. + +The \refmodule[dummythreading]{dummy_threading} module is provided for +situations where \module{threading} cannot be used because +\refmodule{thread} is missing. + +This module defines the following functions and objects: + +\begin{funcdesc}{activeCount}{} +Return the number of \class{Thread} objects currently alive. The +returned count is equal to the length of the list returned by +\function{enumerate()}. +\end{funcdesc} + +\begin{funcdesc}{Condition}{} +A factory function that returns a new condition variable object. +A condition variable allows one or more threads to wait until they +are notified by another thread. +\end{funcdesc} + +\begin{funcdesc}{currentThread}{} +Return the current \class{Thread} object, corresponding to the +caller's thread of control. If the caller's thread of control was not +created through the +\module{threading} module, a dummy thread object with limited functionality +is returned. +\end{funcdesc} + +\begin{funcdesc}{enumerate}{} +Return a list of all \class{Thread} objects currently alive. The list +includes daemonic threads, dummy thread objects created by +\function{currentThread()}, and the main thread. It excludes +terminated threads and threads that have not yet been started. +\end{funcdesc} + +\begin{funcdesc}{Event}{} +A factory function that returns a new event object. An event manages +a flag that can be set to true with the \method{set()} method and +reset to false with the \method{clear()} method. The \method{wait()} +method blocks until the flag is true. +\end{funcdesc} + +\begin{classdesc*}{local}{} +A class that represents thread-local data. Thread-local data are data +whose values are thread specific. To manage thread-local data, just +create an instance of \class{local} (or a subclass) and store +attributes on it: + +\begin{verbatim} +mydata = threading.local() +mydata.x = 1 +\end{verbatim} + +The instance's values will be different for separate threads. + +For more details and extensive examples, see the documentation string +of the \module{_threading_local} module. + +\versionadded{2.4} +\end{classdesc*} + +\begin{funcdesc}{Lock}{} +A factory function that returns a new primitive lock object. Once +a thread has acquired it, subsequent attempts to acquire it block, +until it is released; any thread may release it. +\end{funcdesc} + +\begin{funcdesc}{RLock}{} +A factory function that returns a new reentrant lock object. +A reentrant lock must be released by the thread that acquired it. +Once a thread has acquired a reentrant lock, the same thread may +acquire it again without blocking; the thread must release it once +for each time it has acquired it. +\end{funcdesc} + +\begin{funcdesc}{Semaphore}{\optional{value}} +A factory function that returns a new semaphore object. A +semaphore manages a counter representing the number of \method{release()} +calls minus the number of \method{acquire()} calls, plus an initial value. +The \method{acquire()} method blocks if necessary until it can return +without making the counter negative. If not given, \var{value} defaults to +1. +\end{funcdesc} + +\begin{funcdesc}{BoundedSemaphore}{\optional{value}} +A factory function that returns a new bounded semaphore object. A bounded +semaphore checks to make sure its current value doesn't exceed its initial +value. If it does, \exception{ValueError} is raised. In most situations +semaphores are used to guard resources with limited capacity. If the +semaphore is released too many times it's a sign of a bug. If not given, +\var{value} defaults to 1. +\end{funcdesc} + +\begin{classdesc*}{Thread}{} +A class that represents a thread of control. This class can be safely +subclassed in a limited fashion. +\end{classdesc*} + +\begin{classdesc*}{Timer}{} +A thread that executes a function after a specified interval has passed. +\end{classdesc*} + +\begin{funcdesc}{settrace}{func} +Set a trace function\index{trace function} for all threads started +from the \module{threading} module. The \var{func} will be passed to +\function{sys.settrace()} for each thread, before its \method{run()} +method is called. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{setprofile}{func} +Set a profile function\index{profile function} for all threads started +from the \module{threading} module. The \var{func} will be passed to +\function{sys.setprofile()} for each thread, before its \method{run()} +method is called. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{stack_size}{\optional{size}} +Return the thread stack size used when creating new threads. The +optional \var{size} argument specifies the stack size to be used for +subsequently created threads, and must be 0 (use platform or +configured default) or a positive integer value of at least 32,768 (32kB). +If changing the thread stack size is unsupported, a \exception{ThreadError} +is raised. If the specified stack size is invalid, a \exception{ValueError} +is raised and the stack size is unmodified. 32kB is currently the minimum +supported stack size value to guarantee sufficient stack space for the +interpreter itself. Note that some platforms may have particular +restrictions on values for the stack size, such as requiring a minimum +stack size > 32kB or requiring allocation in multiples of the system +memory page size - platform documentation should be referred to for +more information (4kB pages are common; using multiples of 4096 for +the stack size is the suggested approach in the absence of more +specific information). +Availability: Windows, systems with \POSIX{} threads. +\versionadded{2.5} +\end{funcdesc} + +Detailed interfaces for the objects are documented below. + +The design of this module is loosely based on Java's threading model. +However, where Java makes locks and condition variables basic behavior +of every object, they are separate objects in Python. Python's \class{Thread} +class supports a subset of the behavior of Java's Thread class; +currently, there are no priorities, no thread groups, and threads +cannot be destroyed, stopped, suspended, resumed, or interrupted. The +static methods of Java's Thread class, when implemented, are mapped to +module-level functions. + +All of the methods described below are executed atomically. + + +\subsection{Lock Objects \label{lock-objects}} + +A primitive lock is a synchronization primitive that is not owned +by a particular thread when locked. In Python, it is currently +the lowest level synchronization primitive available, implemented +directly by the \refmodule{thread} extension module. + +A primitive lock is in one of two states, ``locked'' or ``unlocked''. +It is created in the unlocked state. It has two basic methods, +\method{acquire()} and \method{release()}. When the state is +unlocked, \method{acquire()} changes the state to locked and returns +immediately. When the state is locked, \method{acquire()} blocks +until a call to \method{release()} in another thread changes it to +unlocked, then the \method{acquire()} call resets it to locked and +returns. The \method{release()} method should only be called in the +locked state; it changes the state to unlocked and returns +immediately. When more than one thread is blocked in +\method{acquire()} waiting for the state to turn to unlocked, only one +thread proceeds when a \method{release()} call resets the state to +unlocked; which one of the waiting threads proceeds is not defined, +and may vary across implementations. + +All methods are executed atomically. + +\begin{methoddesc}{acquire}{\optional{blocking\code{ = 1}}} +Acquire a lock, blocking or non-blocking. + +When invoked without arguments, block until the lock is +unlocked, then set it to locked, and return true. + +When invoked with the \var{blocking} argument set to true, do the +same thing as when called without arguments, and return true. + +When invoked with the \var{blocking} argument set to false, do not +block. If a call without an argument would block, return false +immediately; otherwise, do the same thing as when called +without arguments, and return true. +\end{methoddesc} + +\begin{methoddesc}{release}{} +Release a lock. + +When the lock is locked, reset it to unlocked, and return. If +any other threads are blocked waiting for the lock to become +unlocked, allow exactly one of them to proceed. + +Do not call this method when the lock is unlocked. + +There is no return value. +\end{methoddesc} + + +\subsection{RLock Objects \label{rlock-objects}} + +A reentrant lock is a synchronization primitive that may be +acquired multiple times by the same thread. Internally, it uses +the concepts of ``owning thread'' and ``recursion level'' in +addition to the locked/unlocked state used by primitive locks. In +the locked state, some thread owns the lock; in the unlocked +state, no thread owns it. + +To lock the lock, a thread calls its \method{acquire()} method; this +returns once the thread owns the lock. To unlock the lock, a +thread calls its \method{release()} method. +\method{acquire()}/\method{release()} call pairs may be nested; only +the final \method{release()} (the \method{release()} of the outermost +pair) resets the lock to unlocked and allows another thread blocked in +\method{acquire()} to proceed. + +\begin{methoddesc}{acquire}{\optional{blocking\code{ = 1}}} +Acquire a lock, blocking or non-blocking. + +When invoked without arguments: if this thread already owns +the lock, increment the recursion level by one, and return +immediately. Otherwise, if another thread owns the lock, +block until the lock is unlocked. Once the lock is unlocked +(not owned by any thread), then grab ownership, set the +recursion level to one, and return. If more than one thread +is blocked waiting until the lock is unlocked, only one at a +time will be able to grab ownership of the lock. There is no +return value in this case. + +When invoked with the \var{blocking} argument set to true, do the +same thing as when called without arguments, and return true. + +When invoked with the \var{blocking} argument set to false, do not +block. If a call without an argument would block, return false +immediately; otherwise, do the same thing as when called +without arguments, and return true. +\end{methoddesc} + +\begin{methoddesc}{release}{} +Release a lock, decrementing the recursion level. If after the +decrement it is zero, reset the lock to unlocked (not owned by any +thread), and if any other threads are blocked waiting for the lock to +become unlocked, allow exactly one of them to proceed. If after the +decrement the recursion level is still nonzero, the lock remains +locked and owned by the calling thread. + +Only call this method when the calling thread owns the lock. +Do not call this method when the lock is unlocked. + +There is no return value. +\end{methoddesc} + + +\subsection{Condition Objects \label{condition-objects}} + +A condition variable is always associated with some kind of lock; +this can be passed in or one will be created by default. (Passing +one in is useful when several condition variables must share the +same lock.) + +A condition variable has \method{acquire()} and \method{release()} +methods that call the corresponding methods of the associated lock. +It also has a \method{wait()} method, and \method{notify()} and +\method{notifyAll()} methods. These three must only be called when +the calling thread has acquired the lock. + +The \method{wait()} method releases the lock, and then blocks until it +is awakened by a \method{notify()} or \method{notifyAll()} call for +the same condition variable in another thread. Once awakened, it +re-acquires the lock and returns. It is also possible to specify a +timeout. + +The \method{notify()} method wakes up one of the threads waiting for +the condition variable, if any are waiting. The \method{notifyAll()} +method wakes up all threads waiting for the condition variable. + +Note: the \method{notify()} and \method{notifyAll()} methods don't +release the lock; this means that the thread or threads awakened will +not return from their \method{wait()} call immediately, but only when +the thread that called \method{notify()} or \method{notifyAll()} +finally relinquishes ownership of the lock. + +Tip: the typical programming style using condition variables uses the +lock to synchronize access to some shared state; threads that are +interested in a particular change of state call \method{wait()} +repeatedly until they see the desired state, while threads that modify +the state call \method{notify()} or \method{notifyAll()} when they +change the state in such a way that it could possibly be a desired +state for one of the waiters. For example, the following code is a +generic producer-consumer situation with unlimited buffer capacity: + +\begin{verbatim} +# Consume one item +cv.acquire() +while not an_item_is_available(): + cv.wait() +get_an_available_item() +cv.release() + +# Produce one item +cv.acquire() +make_an_item_available() +cv.notify() +cv.release() +\end{verbatim} + +To choose between \method{notify()} and \method{notifyAll()}, consider +whether one state change can be interesting for only one or several +waiting threads. E.g. in a typical producer-consumer situation, +adding one item to the buffer only needs to wake up one consumer +thread. + +\begin{classdesc}{Condition}{\optional{lock}} +If the \var{lock} argument is given and not \code{None}, it must be a +\class{Lock} or \class{RLock} object, and it is used as the underlying +lock. Otherwise, a new \class{RLock} object is created and used as +the underlying lock. +\end{classdesc} + +\begin{methoddesc}{acquire}{*args} +Acquire the underlying lock. +This method calls the corresponding method on the underlying +lock; the return value is whatever that method returns. +\end{methoddesc} + +\begin{methoddesc}{release}{} +Release the underlying lock. +This method calls the corresponding method on the underlying +lock; there is no return value. +\end{methoddesc} + +\begin{methoddesc}{wait}{\optional{timeout}} +Wait until notified or until a timeout occurs. +This must only be called when the calling thread has acquired the +lock. + +This method releases the underlying lock, and then blocks until it is +awakened by a \method{notify()} or \method{notifyAll()} call for the +same condition variable in another thread, or until the optional +timeout occurs. Once awakened or timed out, it re-acquires the lock +and returns. + +When the \var{timeout} argument is present and not \code{None}, it +should be a floating point number specifying a timeout for the +operation in seconds (or fractions thereof). + +When the underlying lock is an \class{RLock}, it is not released using +its \method{release()} method, since this may not actually unlock the +lock when it was acquired multiple times recursively. Instead, an +internal interface of the \class{RLock} class is used, which really +unlocks it even when it has been recursively acquired several times. +Another internal interface is then used to restore the recursion level +when the lock is reacquired. +\end{methoddesc} + +\begin{methoddesc}{notify}{} +Wake up a thread waiting on this condition, if any. +This must only be called when the calling thread has acquired the +lock. + +This method wakes up one of the threads waiting for the condition +variable, if any are waiting; it is a no-op if no threads are waiting. + +The current implementation wakes up exactly one thread, if any are +waiting. However, it's not safe to rely on this behavior. A future, +optimized implementation may occasionally wake up more than one +thread. + +Note: the awakened thread does not actually return from its +\method{wait()} call until it can reacquire the lock. Since +\method{notify()} does not release the lock, its caller should. +\end{methoddesc} + +\begin{methoddesc}{notifyAll}{} +Wake up all threads waiting on this condition. This method acts like +\method{notify()}, but wakes up all waiting threads instead of one. +\end{methoddesc} + + +\subsection{Semaphore Objects \label{semaphore-objects}} + +This is one of the oldest synchronization primitives in the history of +computer science, invented by the early Dutch computer scientist +Edsger W. Dijkstra (he used \method{P()} and \method{V()} instead of +\method{acquire()} and \method{release()}). + +A semaphore manages an internal counter which is decremented by each +\method{acquire()} call and incremented by each \method{release()} +call. The counter can never go below zero; when \method{acquire()} +finds that it is zero, it blocks, waiting until some other thread +calls \method{release()}. + +\begin{classdesc}{Semaphore}{\optional{value}} +The optional argument gives the initial value for the internal +counter; it defaults to \code{1}. +\end{classdesc} + +\begin{methoddesc}{acquire}{\optional{blocking}} +Acquire a semaphore. + +When invoked without arguments: if the internal counter is larger than +zero on entry, decrement it by one and return immediately. If it is +zero on entry, block, waiting until some other thread has called +\method{release()} to make it larger than zero. This is done with +proper interlocking so that if multiple \method{acquire()} calls are +blocked, \method{release()} will wake exactly one of them up. The +implementation may pick one at random, so the order in which blocked +threads are awakened should not be relied on. There is no return +value in this case. + +When invoked with \var{blocking} set to true, do the same thing as +when called without arguments, and return true. + +When invoked with \var{blocking} set to false, do not block. If a +call without an argument would block, return false immediately; +otherwise, do the same thing as when called without arguments, and +return true. +\end{methoddesc} + +\begin{methoddesc}{release}{} +Release a semaphore, +incrementing the internal counter by one. When it was zero on +entry and another thread is waiting for it to become larger +than zero again, wake up that thread. +\end{methoddesc} + + +\subsubsection{\class{Semaphore} Example \label{semaphore-examples}} + +Semaphores are often used to guard resources with limited capacity, for +example, a database server. In any situation where the size of the resource +size is fixed, you should use a bounded semaphore. Before spawning any +worker threads, your main thread would initialize the semaphore: + +\begin{verbatim} +maxconnections = 5 +... +pool_sema = BoundedSemaphore(value=maxconnections) +\end{verbatim} + +Once spawned, worker threads call the semaphore's acquire and release +methods when they need to connect to the server: + +\begin{verbatim} +pool_sema.acquire() +conn = connectdb() +... use connection ... +conn.close() +pool_sema.release() +\end{verbatim} + +The use of a bounded semaphore reduces the chance that a programming error +which causes the semaphore to be released more than it's acquired will go +undetected. + + +\subsection{Event Objects \label{event-objects}} + +This is one of the simplest mechanisms for communication between +threads: one thread signals an event and other threads wait for it. + +An event object manages an internal flag that can be set to true with +the \method{set()} method and reset to false with the \method{clear()} +method. The \method{wait()} method blocks until the flag is true. + + +\begin{classdesc}{Event}{} +The internal flag is initially false. +\end{classdesc} + +\begin{methoddesc}{isSet}{} +Return true if and only if the internal flag is true. +\end{methoddesc} + +\begin{methoddesc}{set}{} +Set the internal flag to true. +All threads waiting for it to become true are awakened. +Threads that call \method{wait()} once the flag is true will not block +at all. +\end{methoddesc} + +\begin{methoddesc}{clear}{} +Reset the internal flag to false. +Subsequently, threads calling \method{wait()} will block until +\method{set()} is called to set the internal flag to true again. +\end{methoddesc} + +\begin{methoddesc}{wait}{\optional{timeout}} +Block until the internal flag is true. +If the internal flag is true on entry, return immediately. Otherwise, +block until another thread calls \method{set()} to set the flag to +true, or until the optional timeout occurs. + +When the timeout argument is present and not \code{None}, it should be a +floating point number specifying a timeout for the operation in +seconds (or fractions thereof). +\end{methoddesc} + + +\subsection{Thread Objects \label{thread-objects}} + +This class represents an activity that is run in a separate thread +of control. There are two ways to specify the activity: by +passing a callable object to the constructor, or by overriding the +\method{run()} method in a subclass. No other methods (except for the +constructor) should be overridden in a subclass. In other words, +\emph{only} override the \method{__init__()} and \method{run()} +methods of this class. + +Once a thread object is created, its activity must be started by +calling the thread's \method{start()} method. This invokes the +\method{run()} method in a separate thread of control. + +Once the thread's activity is started, the thread is considered +'alive'. It stops being alive when its \method{run()} method terminates +-- either normally, or by raising an unhandled exception. The +\method{isAlive()} method tests whether the thread is alive. + +Other threads can call a thread's \method{join()} method. This blocks +the calling thread until the thread whose \method{join()} method is +called is terminated. + +A thread has a name. The name can be passed to the constructor, +set with the \method{setName()} method, and retrieved with the +\method{getName()} method. + +A thread can be flagged as a ``daemon thread''. The significance +of this flag is that the entire Python program exits when only +daemon threads are left. The initial value is inherited from the +creating thread. The flag can be set with the \method{setDaemon()} +method and retrieved with the \method{isDaemon()} method. + +There is a ``main thread'' object; this corresponds to the +initial thread of control in the Python program. It is not a +daemon thread. + +There is the possibility that ``dummy thread objects'' are created. +These are thread objects corresponding to ``alien threads'', which +are threads of control started outside the threading module, such as +directly from C code. Dummy thread objects have limited +functionality; they are always considered alive and daemonic, and +cannot be \method{join()}ed. They are never deleted, since it is +impossible to detect the termination of alien threads. + + +\begin{classdesc}{Thread}{group=None, target=None, name=None, + args=(), kwargs=\{\}} +This constructor should always be called with keyword +arguments. Arguments are: + +\var{group} should be \code{None}; reserved for future extension when +a \class{ThreadGroup} class is implemented. + +\var{target} is the callable object to be invoked by the +\method{run()} method. Defaults to \code{None}, meaning nothing is +called. + +\var{name} is the thread name. By default, a unique name is +constructed of the form ``Thread-\var{N}'' where \var{N} is a small +decimal number. + +\var{args} is the argument tuple for the target invocation. Defaults +to \code{()}. + +\var{kwargs} is a dictionary of keyword arguments for the target +invocation. Defaults to \code{\{\}}. + +If the subclass overrides the constructor, it must make sure +to invoke the base class constructor (\code{Thread.__init__()}) +before doing anything else to the thread. +\end{classdesc} + +\begin{methoddesc}{start}{} +Start the thread's activity. + +This must be called at most once per thread object. It +arranges for the object's \method{run()} method to be invoked in a +separate thread of control. +\end{methoddesc} + +\begin{methoddesc}{run}{} +Method representing the thread's activity. + +You may override this method in a subclass. The standard +\method{run()} method invokes the callable object passed to the +object's constructor as the \var{target} argument, if any, with +sequential and keyword arguments taken from the \var{args} and +\var{kwargs} arguments, respectively. +\end{methoddesc} + +\begin{methoddesc}{join}{\optional{timeout}} +Wait until the thread terminates. +This blocks the calling thread until the thread whose \method{join()} +method is called terminates -- either normally or through an +unhandled exception -- or until the optional timeout occurs. + +When the \var{timeout} argument is present and not \code{None}, it +should be a floating point number specifying a timeout for the +operation in seconds (or fractions thereof). As \method{join()} always +returns \code{None}, you must call \method{isAlive()} to decide whether +a timeout happened. + +When the \var{timeout} argument is not present or \code{None}, the +operation will block until the thread terminates. + +A thread can be \method{join()}ed many times. + +A thread cannot join itself because this would cause a +deadlock. + +It is an error to attempt to \method{join()} a thread before it has +been started. +\end{methoddesc} + +\begin{methoddesc}{getName}{} +Return the thread's name. +\end{methoddesc} + +\begin{methoddesc}{setName}{name} +Set the thread's name. + +The name is a string used for identification purposes only. +It has no semantics. Multiple threads may be given the same +name. The initial name is set by the constructor. +\end{methoddesc} + +\begin{methoddesc}{isAlive}{} +Return whether the thread is alive. + +Roughly, a thread is alive from the moment the \method{start()} method +returns until its \method{run()} method terminates. The module +function \function{enumerate()} returns a list of all alive threads. +\end{methoddesc} + +\begin{methoddesc}{isDaemon}{} +Return the thread's daemon flag. +\end{methoddesc} + +\begin{methoddesc}{setDaemon}{daemonic} +Set the thread's daemon flag to the Boolean value \var{daemonic}. +This must be called before \method{start()} is called. + +The initial value is inherited from the creating thread. + +The entire Python program exits when no alive non-daemon threads are +left. +\end{methoddesc} + + +\subsection{Timer Objects \label{timer-objects}} + +This class represents an action that should be run only after a +certain amount of time has passed --- a timer. \class{Timer} is a +subclass of \class{Thread} and as such also functions as an example of +creating custom threads. + +Timers are started, as with threads, by calling their \method{start()} +method. The timer can be stopped (before its action has begun) by +calling the \method{cancel()} method. The interval the timer will +wait before executing its action may not be exactly the same as the +interval specified by the user. + +For example: +\begin{verbatim} +def hello(): + print "hello, world" + +t = Timer(30.0, hello) +t.start() # after 30 seconds, "hello, world" will be printed +\end{verbatim} + +\begin{classdesc}{Timer}{interval, function, args=[], kwargs=\{\}} +Create a timer that will run \var{function} with arguments \var{args} and +keyword arguments \var{kwargs}, after \var{interval} seconds have passed. +\end{classdesc} + +\begin{methoddesc}{cancel}{} +Stop the timer, and cancel the execution of the timer's action. This +will only work if the timer is still in its waiting stage. +\end{methoddesc} + +\subsection{Using locks, conditions, and semaphores in the \keyword{with} +statement \label{with-locks}} + +All of the objects provided by this module that have \method{acquire()} and +\method{release()} methods can be used as context managers for a \keyword{with} +statement. The \method{acquire()} method will be called when the block is +entered, and \method{release()} will be called when the block is exited. + +Currently, \class{Lock}, \class{RLock}, \class{Condition}, \class{Semaphore}, +and \class{BoundedSemaphore} objects may be used as \keyword{with} +statement context managers. For example: + +\begin{verbatim} +from __future__ import with_statement +import threading + +some_rlock = threading.RLock() + +with some_rlock: + print "some_rlock is locked while this executes" +\end{verbatim} + diff --git a/sys/src/cmd/python/Doc/lib/libtime.tex b/sys/src/cmd/python/Doc/lib/libtime.tex new file mode 100644 index 000000000..f40838a44 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtime.tex @@ -0,0 +1,461 @@ +\section{\module{time} --- + Time access and conversions} + +\declaremodule{builtin}{time} +\modulesynopsis{Time access and conversions.} + + +This module provides various time-related functions. It is always +available, but not all functions are available on all platforms. Most +of the functions defined in this module call platform C library +functions with the same name. It may sometimes be helpful to consult +the platform documentation, because the semantics of these functions +varies among platforms. + +An explanation of some terminology and conventions is in order. + +\begin{itemize} + +\item +The \dfn{epoch}\index{epoch} is the point where the time starts. On +January 1st of that year, at 0 hours, the ``time since the epoch'' is +zero. For \UNIX, the epoch is 1970. To find out what the epoch is, +look at \code{gmtime(0)}. + +\item +The functions in this module do not handle dates and times before the +epoch or far in the future. The cut-off point in the future is +determined by the C library; for \UNIX, it is typically in +2038\index{Year 2038}. + +\item +\strong{Year 2000 (Y2K) issues}:\index{Year 2000}\index{Y2K} Python +depends on the platform's C library, which generally doesn't have year +2000 issues, since all dates and times are represented internally as +seconds since the epoch. Functions accepting a \class{struct_time} +(see below) generally require a 4-digit year. For backward +compatibility, 2-digit years are supported if the module variable +\code{accept2dyear} is a non-zero integer; this variable is +initialized to \code{1} unless the environment variable +\envvar{PYTHONY2K} is set to a non-empty string, in which case it is +initialized to \code{0}. Thus, you can set +\envvar{PYTHONY2K} to a non-empty string in the environment to require 4-digit +years for all year input. When 2-digit years are accepted, they are +converted according to the \POSIX{} or X/Open standard: values 69-99 +are mapped to 1969-1999, and values 0--68 are mapped to 2000--2068. +Values 100--1899 are always illegal. Note that this is new as of +Python 1.5.2(a2); earlier versions, up to Python 1.5.1 and 1.5.2a1, +would add 1900 to year values below 1900. + +\item +UTC\index{UTC} is Coordinated Universal Time\index{Coordinated +Universal Time} (formerly known as Greenwich Mean +Time,\index{Greenwich Mean Time} or GMT). The acronym UTC is not a +mistake but a compromise between English and French. + +\item +DST is Daylight Saving Time,\index{Daylight Saving Time} an adjustment +of the timezone by (usually) one hour during part of the year. DST +rules are magic (determined by local law) and can change from year to +year. The C library has a table containing the local rules (often it +is read from a system file for flexibility) and is the only source of +True Wisdom in this respect. + +\item +The precision of the various real-time functions may be less than +suggested by the units in which their value or argument is expressed. +E.g.\ on most \UNIX{} systems, the clock ``ticks'' only 50 or 100 times a +second, and on the Mac, times are only accurate to whole seconds. + +\item +On the other hand, the precision of \function{time()} and +\function{sleep()} is better than their \UNIX{} equivalents: times are +expressed as floating point numbers, \function{time()} returns the +most accurate time available (using \UNIX{} \cfunction{gettimeofday()} +where available), and \function{sleep()} will accept a time with a +nonzero fraction (\UNIX{} \cfunction{select()} is used to implement +this, where available). + +\item +The time value as returned by \function{gmtime()}, +\function{localtime()}, and \function{strptime()}, and accepted by +\function{asctime()}, \function{mktime()} and \function{strftime()}, +is a sequence of 9 integers. The return values of \function{gmtime()}, +\function{localtime()}, and \function{strptime()} also offer attribute +names for individual fields. + +\begin{tableiii}{c|l|l}{textrm}{Index}{Attribute}{Values} + \lineiii{0}{\member{tm_year}}{(for example, 1993)} + \lineiii{1}{\member{tm_mon}}{range [1,12]} + \lineiii{2}{\member{tm_mday}}{range [1,31]} + \lineiii{3}{\member{tm_hour}}{range [0,23]} + \lineiii{4}{\member{tm_min}}{range [0,59]} + \lineiii{5}{\member{tm_sec}}{range [0,61]; see \strong{(1)} in \function{strftime()} description} + \lineiii{6}{\member{tm_wday}}{range [0,6], Monday is 0} + \lineiii{7}{\member{tm_yday}}{range [1,366]} + \lineiii{8}{\member{tm_isdst}}{0, 1 or -1; see below} +\end{tableiii} + +Note that unlike the C structure, the month value is a +range of 1-12, not 0-11. A year value will be handled as described +under ``Year 2000 (Y2K) issues'' above. A \code{-1} argument as the +daylight savings flag, passed to \function{mktime()} will usually +result in the correct daylight savings state to be filled in. + +When a tuple with an incorrect length is passed to a function +expecting a \class{struct_time}, or having elements of the wrong type, a +\exception{TypeError} is raised. + +\versionchanged[The time value sequence was changed from a tuple to a + \class{struct_time}, with the addition of attribute names + for the fields]{2.2} +\end{itemize} + +The module defines the following functions and data items: + + +\begin{datadesc}{accept2dyear} +Boolean value indicating whether two-digit year values will be +accepted. This is true by default, but will be set to false if the +environment variable \envvar{PYTHONY2K} has been set to a non-empty +string. It may also be modified at run time. +\end{datadesc} + +\begin{datadesc}{altzone} +The offset of the local DST timezone, in seconds west of UTC, if one +is defined. This is negative if the local DST timezone is east of UTC +(as in Western Europe, including the UK). Only use this if +\code{daylight} is nonzero. +\end{datadesc} + +\begin{funcdesc}{asctime}{\optional{t}} +Convert a tuple or \class{struct_time} representing a time as returned +by \function{gmtime()} +or \function{localtime()} to a 24-character string of the following form: +\code{'Sun Jun 20 23:21:05 1993'}. If \var{t} is not provided, the +current time as returned by \function{localtime()} is used. +Locale information is not used by \function{asctime()}. +\note{Unlike the C function of the same name, there is no trailing +newline.} +\versionchanged[Allowed \var{t} to be omitted]{2.1} +\end{funcdesc} + +\begin{funcdesc}{clock}{} +On \UNIX, return +the current processor time as a floating point number expressed in +seconds. The precision, and in fact the very definition of the meaning +of ``processor time''\index{CPU time}\index{processor time}, depends +on that of the C function of the same name, but in any case, this is +the function to use for benchmarking\index{benchmarking} Python or +timing algorithms. + +On Windows, this function returns wall-clock seconds elapsed since the +first call to this function, as a floating point number, +based on the Win32 function \cfunction{QueryPerformanceCounter()}. +The resolution is typically better than one microsecond. +\end{funcdesc} + +\begin{funcdesc}{ctime}{\optional{secs}} +Convert a time expressed in seconds since the epoch to a string +representing local time. If \var{secs} is not provided or +\constant{None}, the current time as returned by \function{time()} is +used. \code{ctime(\var{secs})} is equivalent to +\code{asctime(localtime(\var{secs}))}. +Locale information is not used by \function{ctime()}. +\versionchanged[Allowed \var{secs} to be omitted]{2.1} +\versionchanged[If \var{secs} is \constant{None}, the current time is + used]{2.4} +\end{funcdesc} + +\begin{datadesc}{daylight} +Nonzero if a DST timezone is defined. +\end{datadesc} + +\begin{funcdesc}{gmtime}{\optional{secs}} +Convert a time expressed in seconds since the epoch to a \class{struct_time} +in UTC in which the dst flag is always zero. If \var{secs} is not +provided or \constant{None}, the current time as returned by +\function{time()} is used. Fractions of a second are ignored. See +above for a description of the \class{struct_time} object. See +\function{calendar.timegm()} for the inverse of this function. +\versionchanged[Allowed \var{secs} to be omitted]{2.1} +\versionchanged[If \var{secs} is \constant{None}, the current time is + used]{2.4} +\end{funcdesc} + +\begin{funcdesc}{localtime}{\optional{secs}} +Like \function{gmtime()} but converts to local time. If \var{secs} is +not provided or \constant{None}, the current time as returned by +\function{time()} is used. The dst flag is set to \code{1} when DST +applies to the given time. +\versionchanged[Allowed \var{secs} to be omitted]{2.1} +\versionchanged[If \var{secs} is \constant{None}, the current time is + used]{2.4} +\end{funcdesc} + +\begin{funcdesc}{mktime}{t} +This is the inverse function of \function{localtime()}. Its argument +is the \class{struct_time} or full 9-tuple (since the dst flag is +needed; use \code{-1} as the dst flag if it is unknown) which +expresses the time in +\emph{local} time, not UTC. It returns a floating point number, for +compatibility with \function{time()}. If the input value cannot be +represented as a valid time, either \exception{OverflowError} or +\exception{ValueError} will be raised (which depends on whether the +invalid value is caught by Python or the underlying C libraries). The +earliest date for which it can generate a time is platform-dependent. +\end{funcdesc} + +\begin{funcdesc}{sleep}{secs} +Suspend execution for the given number of seconds. The argument may +be a floating point number to indicate a more precise sleep time. +The actual suspension time may be less than that requested because any +caught signal will terminate the \function{sleep()} following +execution of that signal's catching routine. Also, the suspension +time may be longer than requested by an arbitrary amount because of +the scheduling of other activity in the system. +\end{funcdesc} + +\begin{funcdesc}{strftime}{format\optional{, t}} +Convert a tuple or \class{struct_time} representing a time as returned +by \function{gmtime()} or \function{localtime()} to a string as +specified by the \var{format} argument. If \var{t} is not +provided, the current time as returned by \function{localtime()} is +used. \var{format} must be a string. \exception{ValueError} is raised +if any field in \var{t} is outside of the allowed range. +\versionchanged[Allowed \var{t} to be omitted]{2.1} +\versionchanged[\exception{ValueError} raised if a field in \var{t} is +out of range]{2.4} +\versionchanged[0 is now a legal argument for any position in the time tuple; +if it is normally illegal the value is forced to a correct one.]{2.5} + + +The following directives can be embedded in the \var{format} string. +They are shown without the optional field width and precision +specification, and are replaced by the indicated characters in the +\function{strftime()} result: + +\begin{tableiii}{c|p{24em}|c}{code}{Directive}{Meaning}{Notes} + \lineiii{\%a}{Locale's abbreviated weekday name.}{} + \lineiii{\%A}{Locale's full weekday name.}{} + \lineiii{\%b}{Locale's abbreviated month name.}{} + \lineiii{\%B}{Locale's full month name.}{} + \lineiii{\%c}{Locale's appropriate date and time representation.}{} + \lineiii{\%d}{Day of the month as a decimal number [01,31].}{} + \lineiii{\%H}{Hour (24-hour clock) as a decimal number [00,23].}{} + \lineiii{\%I}{Hour (12-hour clock) as a decimal number [01,12].}{} + \lineiii{\%j}{Day of the year as a decimal number [001,366].}{} + \lineiii{\%m}{Month as a decimal number [01,12].}{} + \lineiii{\%M}{Minute as a decimal number [00,59].}{} + \lineiii{\%p}{Locale's equivalent of either AM or PM.}{(1)} + \lineiii{\%S}{Second as a decimal number [00,61].}{(2)} + \lineiii{\%U}{Week number of the year (Sunday as the first day of the + week) as a decimal number [00,53]. All days in a new year + preceding the first Sunday are considered to be in week 0.}{(3)} + \lineiii{\%w}{Weekday as a decimal number [0(Sunday),6].}{} + \lineiii{\%W}{Week number of the year (Monday as the first day of the + week) as a decimal number [00,53]. All days in a new year + preceding the first Monday are considered to be in week 0.}{(3)} + \lineiii{\%x}{Locale's appropriate date representation.}{} + \lineiii{\%X}{Locale's appropriate time representation.}{} + \lineiii{\%y}{Year without century as a decimal number [00,99].}{} + \lineiii{\%Y}{Year with century as a decimal number.}{} + \lineiii{\%Z}{Time zone name (no characters if no time zone exists).}{} + \lineiii{\%\%}{A literal \character{\%} character.}{} +\end{tableiii} + +\noindent +Notes: + +\begin{description} + \item[(1)] + When used with the \function{strptime()} function, the \code{\%p} + directive only affects the output hour field if the \code{\%I} directive + is used to parse the hour. + \item[(2)] + The range really is \code{0} to \code{61}; this accounts for leap + seconds and the (very rare) double leap seconds. + \item[(3)] + When used with the \function{strptime()} function, \code{\%U} and \code{\%W} + are only used in calculations when the day of the week and the year are + specified. +\end{description} + +Here is an example, a format for dates compatible with that specified +in the \rfc{2822} Internet email standard. + \footnote{The use of \code{\%Z} is now + deprecated, but the \code{\%z} escape that expands to the preferred + hour/minute offset is not supported by all ANSI C libraries. Also, + a strict reading of the original 1982 \rfc{822} standard calls for + a two-digit year (\%y rather than \%Y), but practice moved to + 4-digit years long before the year 2000. The 4-digit year has + been mandated by \rfc{2822}, which obsoletes \rfc{822}.} + +\begin{verbatim} +>>> from time import gmtime, strftime +>>> strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) +'Thu, 28 Jun 2001 14:17:15 +0000' +\end{verbatim} + +Additional directives may be supported on certain platforms, but +only the ones listed here have a meaning standardized by ANSI C. + +On some platforms, an optional field width and precision +specification can immediately follow the initial \character{\%} of a +directive in the following order; this is also not portable. +The field width is normally 2 except for \code{\%j} where it is 3. +\end{funcdesc} + +\begin{funcdesc}{strptime}{string\optional{, format}} +Parse a string representing a time according to a format. The return +value is a \class{struct_time} as returned by \function{gmtime()} or +\function{localtime()}. The \var{format} parameter uses the same +directives as those used by \function{strftime()}; it defaults to +\code{"\%a \%b \%d \%H:\%M:\%S \%Y"} which matches the formatting +returned by \function{ctime()}. If \var{string} cannot be parsed +according to \var{format}, \exception{ValueError} is raised. If the +string to be parsed has excess data after parsing, +\exception{ValueError} is raised. The default values used to fill in +any missing data when more accurate values cannot be inferred are +\code{(1900, 1, 1, 0, 0, 0, 0, 1, -1)} . + +Support for the \code{\%Z} directive is based on the values contained in +\code{tzname} and whether \code{daylight} is true. Because of this, +it is platform-specific except for recognizing UTC and GMT which are +always known (and are considered to be non-daylight savings +timezones). +\end{funcdesc} + +\begin{datadesc}{struct_time} +The type of the time value sequence returned by \function{gmtime()}, +\function{localtime()}, and \function{strptime()}. +\versionadded{2.2} +\end{datadesc} + +\begin{funcdesc}{time}{} +Return the time as a floating point number expressed in seconds since +the epoch, in UTC. Note that even though the time is always returned +as a floating point number, not all systems provide time with a better +precision than 1 second. While this function normally returns +non-decreasing values, it can return a lower value than a previous +call if the system clock has been set back between the two calls. +\end{funcdesc} + +\begin{datadesc}{timezone} +The offset of the local (non-DST) timezone, in seconds west of UTC +(negative in most of Western Europe, positive in the US, zero in the +UK). +\end{datadesc} + +\begin{datadesc}{tzname} +A tuple of two strings: the first is the name of the local non-DST +timezone, the second is the name of the local DST timezone. If no DST +timezone is defined, the second string should not be used. +\end{datadesc} + +\begin{funcdesc}{tzset}{} +Resets the time conversion rules used by the library routines. +The environment variable \envvar{TZ} specifies how this is done. +\versionadded{2.3} + +Availability: \UNIX. + +\begin{notice} +Although in many cases, changing the \envvar{TZ} environment variable +may affect the output of functions like \function{localtime} without calling +\function{tzset}, this behavior should not be relied on. + +The \envvar{TZ} environment variable should contain no whitespace. +\end{notice} + +The standard format of the \envvar{TZ} environment variable is: +(whitespace added for clarity) +\begin{itemize} + \item[std offset [dst [offset] [,start[/time], end[/time]]]] +\end{itemize} + +Where: + +\begin{itemize} + \item[std and dst] + Three or more alphanumerics giving the timezone abbreviations. + These will be propagated into time.tzname + + \item[offset] + The offset has the form: \plusminus{} hh[:mm[:ss]]. + This indicates the value added the local time to arrive at UTC. + If preceded by a '-', the timezone is east of the Prime + Meridian; otherwise, it is west. If no offset follows + dst, summer time is assumed to be one hour ahead of standard time. + + \item[start[/time],end[/time]] + Indicates when to change to and back from DST. The format of the + start and end dates are one of the following: + + \begin{itemize} + \item[J\var{n}] + The Julian day \var{n} (1 <= \var{n} <= 365). Leap days are not + counted, so in all years February 28 is day 59 and + March 1 is day 60. + + \item[\var{n}] + The zero-based Julian day (0 <= \var{n} <= 365). Leap days are + counted, and it is possible to refer to February 29. + + \item[M\var{m}.\var{n}.\var{d}] + The \var{d}'th day (0 <= \var{d} <= 6) or week \var{n} + of month \var{m} of the year (1 <= \var{n} <= 5, + 1 <= \var{m} <= 12, where week 5 means "the last \var{d} day + in month \var{m}" which may occur in either the fourth or + the fifth week). Week 1 is the first week in which the + \var{d}'th day occurs. Day zero is Sunday. + \end{itemize} + + time has the same format as offset except that no leading sign ('-' or + '+') is allowed. The default, if time is not given, is 02:00:00. +\end{itemize} + + +\begin{verbatim} +>>> os.environ['TZ'] = 'EST+05EDT,M4.1.0,M10.5.0' +>>> time.tzset() +>>> time.strftime('%X %x %Z') +'02:07:36 05/08/03 EDT' +>>> os.environ['TZ'] = 'AEST-10AEDT-11,M10.5.0,M3.5.0' +>>> time.tzset() +>>> time.strftime('%X %x %Z') +'16:08:12 05/08/03 AEST' +\end{verbatim} + +On many \UNIX{} systems (including *BSD, Linux, Solaris, and Darwin), it +is more convenient to use the system's zoneinfo (\manpage{tzfile}{5}) +database to specify the timezone rules. To do this, set the +\envvar{TZ} environment variable to the path of the required timezone +datafile, relative to the root of the systems 'zoneinfo' timezone database, +usually located at \file{/usr/share/zoneinfo}. For example, +\code{'US/Eastern'}, \code{'Australia/Melbourne'}, \code{'Egypt'} or +\code{'Europe/Amsterdam'}. + +\begin{verbatim} +>>> os.environ['TZ'] = 'US/Eastern' +>>> time.tzset() +>>> time.tzname +('EST', 'EDT') +>>> os.environ['TZ'] = 'Egypt' +>>> time.tzset() +>>> time.tzname +('EET', 'EEST') +\end{verbatim} + +\end{funcdesc} + + +\begin{seealso} + \seemodule{datetime}{More object-oriented interface to dates and times.} + \seemodule{locale}{Internationalization services. The locale + settings can affect the return values for some of + the functions in the \module{time} module.} + \seemodule{calendar}{General calendar-related functions. + \function{timegm()} is the inverse of + \function{gmtime()} from this module.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libtimeit.tex b/sys/src/cmd/python/Doc/lib/libtimeit.tex new file mode 100644 index 000000000..0be156c95 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtimeit.tex @@ -0,0 +1,224 @@ +\section{\module{timeit} --- + Measure execution time of small code snippets} + +\declaremodule{standard}{timeit} +\modulesynopsis{Measure the execution time of small code snippets.} + +\versionadded{2.3} +\index{Benchmarking} +\index{Performance} + +This module provides a simple way to time small bits of Python code. +It has both command line as well as callable interfaces. It avoids a +number of common traps for measuring execution times. See also Tim +Peters' introduction to the ``Algorithms'' chapter in the +\citetitle{Python Cookbook}, published by O'Reilly. + +The module defines the following public class: + +\begin{classdesc}{Timer}{\optional{stmt=\code{'pass'} + \optional{, setup=\code{'pass'} + \optional{, timer=<timer function>}}}} +Class for timing execution speed of small code snippets. + +The constructor takes a statement to be timed, an additional statement +used for setup, and a timer function. Both statements default to +\code{'pass'}; the timer function is platform-dependent (see the +module doc string). The statements may contain newlines, as long as +they don't contain multi-line string literals. + +To measure the execution time of the first statement, use the +\method{timeit()} method. The \method{repeat()} method is a +convenience to call \method{timeit()} multiple times and return a list +of results. +\end{classdesc} + +\begin{methoddesc}{print_exc}{\optional{file=\constant{None}}} +Helper to print a traceback from the timed code. + +Typical use: + +\begin{verbatim} + t = Timer(...) # outside the try/except + try: + t.timeit(...) # or t.repeat(...) + except: + t.print_exc() +\end{verbatim} + +The advantage over the standard traceback is that source lines in the +compiled template will be displayed. +The optional \var{file} argument directs where the traceback is sent; +it defaults to \code{sys.stderr}. +\end{methoddesc} + +\begin{methoddesc}{repeat}{\optional{repeat\code{=3} \optional{, + number\code{=1000000}}}} +Call \method{timeit()} a few times. + +This is a convenience function that calls the \method{timeit()} +repeatedly, returning a list of results. The first argument specifies +how many times to call \method{timeit()}. The second argument +specifies the \var{number} argument for \function{timeit()}. + +\begin{notice} +It's tempting to calculate mean and standard deviation from the result +vector and report these. However, this is not very useful. In a typical +case, the lowest value gives a lower bound for how fast your machine can run +the given code snippet; higher values in the result vector are typically not +caused by variability in Python's speed, but by other processes interfering +with your timing accuracy. So the \function{min()} of the result is +probably the only number you should be interested in. After that, you +should look at the entire vector and apply common sense rather than +statistics. +\end{notice} +\end{methoddesc} + +\begin{methoddesc}{timeit}{\optional{number\code{=1000000}}} +Time \var{number} executions of the main statement. +This executes the setup statement once, and then +returns the time it takes to execute the main statement a number of +times, measured in seconds as a float. The argument is the number of +times through the loop, defaulting to one million. The main +statement, the setup statement and the timer function to be used are +passed to the constructor. + +\begin{notice} +By default, \method{timeit()} temporarily turns off garbage collection +during the timing. The advantage of this approach is that it makes +independent timings more comparable. This disadvantage is that GC +may be an important component of the performance of the function being +measured. If so, GC can be re-enabled as the first statement in the +\var{setup} string. For example: +\begin{verbatim} + timeit.Timer('for i in xrange(10): oct(i)', 'gc.enable()').timeit() +\end{verbatim} +\end{notice} +\end{methoddesc} + + +\subsection{Command Line Interface} + +When called as a program from the command line, the following form is used: + +\begin{verbatim} +python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...] +\end{verbatim} + +where the following options are understood: + +\begin{description} +\item[-n N/\longprogramopt{number=N}] how many times to execute 'statement' +\item[-r N/\longprogramopt{repeat=N}] how many times to repeat the timer (default 3) +\item[-s S/\longprogramopt{setup=S}] statement to be executed once initially (default +\code{'pass'}) +\item[-t/\longprogramopt{time}] use \function{time.time()} +(default on all platforms but Windows) +\item[-c/\longprogramopt{clock}] use \function{time.clock()} (default on Windows) +\item[-v/\longprogramopt{verbose}] print raw timing results; repeat for more digits +precision +\item[-h/\longprogramopt{help}] print a short usage message and exit +\end{description} + +A multi-line statement may be given by specifying each line as a +separate statement argument; indented lines are possible by enclosing +an argument in quotes and using leading spaces. Multiple +\programopt{-s} options are treated similarly. + +If \programopt{-n} is not given, a suitable number of loops is +calculated by trying successive powers of 10 until the total time is +at least 0.2 seconds. + +The default timer function is platform dependent. On Windows, +\function{time.clock()} has microsecond granularity but +\function{time.time()}'s granularity is 1/60th of a second; on \UNIX, +\function{time.clock()} has 1/100th of a second granularity and +\function{time.time()} is much more precise. On either platform, the +default timer functions measure wall clock time, not the CPU time. +This means that other processes running on the same computer may +interfere with the timing. The best thing to do when accurate timing +is necessary is to repeat the timing a few times and use the best +time. The \programopt{-r} option is good for this; the default of 3 +repetitions is probably enough in most cases. On \UNIX, you can use +\function{time.clock()} to measure CPU time. + +\begin{notice} + There is a certain baseline overhead associated with executing a + pass statement. The code here doesn't try to hide it, but you + should be aware of it. The baseline overhead can be measured by + invoking the program without arguments. +\end{notice} + +The baseline overhead differs between Python versions! Also, to +fairly compare older Python versions to Python 2.3, you may want to +use Python's \programopt{-O} option for the older versions to avoid +timing \code{SET_LINENO} instructions. + +\subsection{Examples} + +Here are two example sessions (one using the command line, one using +the module interface) that compare the cost of using +\function{hasattr()} vs. \keyword{try}/\keyword{except} to test for +missing and present object attributes. + +\begin{verbatim} +% timeit.py 'try:' ' str.__nonzero__' 'except AttributeError:' ' pass' +100000 loops, best of 3: 15.7 usec per loop +% timeit.py 'if hasattr(str, "__nonzero__"): pass' +100000 loops, best of 3: 4.26 usec per loop +% timeit.py 'try:' ' int.__nonzero__' 'except AttributeError:' ' pass' +1000000 loops, best of 3: 1.43 usec per loop +% timeit.py 'if hasattr(int, "__nonzero__"): pass' +100000 loops, best of 3: 2.23 usec per loop +\end{verbatim} + +\begin{verbatim} +>>> import timeit +>>> s = """\ +... try: +... str.__nonzero__ +... except AttributeError: +... pass +... """ +>>> t = timeit.Timer(stmt=s) +>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) +17.09 usec/pass +>>> s = """\ +... if hasattr(str, '__nonzero__'): pass +... """ +>>> t = timeit.Timer(stmt=s) +>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) +4.85 usec/pass +>>> s = """\ +... try: +... int.__nonzero__ +... except AttributeError: +... pass +... """ +>>> t = timeit.Timer(stmt=s) +>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) +1.97 usec/pass +>>> s = """\ +... if hasattr(int, '__nonzero__'): pass +... """ +>>> t = timeit.Timer(stmt=s) +>>> print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) +3.15 usec/pass +\end{verbatim} + +To give the \module{timeit} module access to functions you +define, you can pass a \code{setup} parameter which contains an import +statement: + +\begin{verbatim} +def test(): + "Stupid test function" + L = [] + for i in range(100): + L.append(i) + +if __name__=='__main__': + from timeit import Timer + t = Timer("test()", "from __main__ import test") + print t.timeit() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libtoken.tex b/sys/src/cmd/python/Doc/lib/libtoken.tex new file mode 100644 index 000000000..47f4750db --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtoken.tex @@ -0,0 +1,44 @@ +\section{\module{token} --- + Constants used with Python parse trees} + +\declaremodule{standard}{token} +\modulesynopsis{Constants representing terminal nodes of the parse tree.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + + +This module provides constants which represent the numeric values of +leaf nodes of the parse tree (terminal tokens). Refer to the file +\file{Grammar/Grammar} in the Python distribution for the definitions +of the names in the context of the language grammar. The specific +numeric values which the names map to may change between Python +versions. + +This module also provides one data object and some functions. The +functions mirror definitions in the Python C header files. + + + +\begin{datadesc}{tok_name} +Dictionary mapping the numeric values of the constants defined in this +module back to name strings, allowing more human-readable +representation of parse trees to be generated. +\end{datadesc} + +\begin{funcdesc}{ISTERMINAL}{x} +Return true for terminal token values. +\end{funcdesc} + +\begin{funcdesc}{ISNONTERMINAL}{x} +Return true for non-terminal token values. +\end{funcdesc} + +\begin{funcdesc}{ISEOF}{x} +Return true if \var{x} is the marker indicating the end of input. +\end{funcdesc} + + +\begin{seealso} + \seemodule{parser}{The second example for the \refmodule{parser} + module shows how to use the \module{symbol} + module.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libtokenize.tex b/sys/src/cmd/python/Doc/lib/libtokenize.tex new file mode 100644 index 000000000..8c9ad3eb7 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtokenize.tex @@ -0,0 +1,119 @@ +\section{\module{tokenize} --- + Tokenizer for Python source} + +\declaremodule{standard}{tokenize} +\modulesynopsis{Lexical scanner for Python source code.} +\moduleauthor{Ka Ping Yee}{} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + + +The \module{tokenize} module provides a lexical scanner for Python +source code, implemented in Python. The scanner in this module +returns comments as tokens as well, making it useful for implementing +``pretty-printers,'' including colorizers for on-screen displays. + +The primary entry point is a generator: + +\begin{funcdesc}{generate_tokens}{readline} + The \function{generate_tokens()} generator requires one argment, + \var{readline}, which must be a callable object which + provides the same interface as the \method{readline()} method of + built-in file objects (see section~\ref{bltin-file-objects}). Each + call to the function should return one line of input as a string. + + The generator produces 5-tuples with these members: + the token type; + the token string; + a 2-tuple \code{(\var{srow}, \var{scol})} of ints specifying the + row and column where the token begins in the source; + a 2-tuple \code{(\var{erow}, \var{ecol})} of ints specifying the + row and column where the token ends in the source; + and the line on which the token was found. + The line passed is the \emph{logical} line; + continuation lines are included. + \versionadded{2.2} +\end{funcdesc} + +An older entry point is retained for backward compatibility: + +\begin{funcdesc}{tokenize}{readline\optional{, tokeneater}} + The \function{tokenize()} function accepts two parameters: one + representing the input stream, and one providing an output mechanism + for \function{tokenize()}. + + The first parameter, \var{readline}, must be a callable object which + provides the same interface as the \method{readline()} method of + built-in file objects (see section~\ref{bltin-file-objects}). Each + call to the function should return one line of input as a string. + Alternately, \var{readline} may be a callable object that signals + completion by raising \exception{StopIteration}. + \versionchanged[Added \exception{StopIteration} support]{2.5} + + The second parameter, \var{tokeneater}, must also be a callable + object. It is called once for each token, with five arguments, + corresponding to the tuples generated by \function{generate_tokens()}. +\end{funcdesc} + + +All constants from the \refmodule{token} module are also exported from +\module{tokenize}, as are two additional token type values that might be +passed to the \var{tokeneater} function by \function{tokenize()}: + +\begin{datadesc}{COMMENT} + Token value used to indicate a comment. +\end{datadesc} +\begin{datadesc}{NL} + Token value used to indicate a non-terminating newline. The NEWLINE + token indicates the end of a logical line of Python code; NL tokens + are generated when a logical line of code is continued over multiple + physical lines. +\end{datadesc} + +Another function is provided to reverse the tokenization process. +This is useful for creating tools that tokenize a script, modify +the token stream, and write back the modified script. + +\begin{funcdesc}{untokenize}{iterable} + Converts tokens back into Python source code. The \var{iterable} + must return sequences with at least two elements, the token type and + the token string. Any additional sequence elements are ignored. + + The reconstructed script is returned as a single string. The + result is guaranteed to tokenize back to match the input so that + the conversion is lossless and round-trips are assured. The + guarantee applies only to the token type and token string as + the spacing between tokens (column positions) may change. + \versionadded{2.5} +\end{funcdesc} + +Example of a script re-writer that transforms float literals into +Decimal objects: +\begin{verbatim} +def decistmt(s): + """Substitute Decimals for floats in a string of statements. + + >>> from decimal import Decimal + >>> s = 'print +21.3e-5*-.1234/81.7' + >>> decistmt(s) + "print +Decimal ('21.3e-5')*-Decimal ('.1234')/Decimal ('81.7')" + + >>> exec(s) + -3.21716034272e-007 + >>> exec(decistmt(s)) + -3.217160342717258261933904529E-7 + + """ + result = [] + g = generate_tokens(StringIO(s).readline) # tokenize the string + for toknum, tokval, _, _, _ in g: + if toknum == NUMBER and '.' in tokval: # replace NUMBER tokens + result.extend([ + (NAME, 'Decimal'), + (OP, '('), + (STRING, repr(tokval)), + (OP, ')') + ]) + else: + result.append((toknum, tokval)) + return untokenize(result) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libtrace.tex b/sys/src/cmd/python/Doc/lib/libtrace.tex new file mode 100644 index 000000000..2465aacaf --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtrace.tex @@ -0,0 +1,125 @@ +\section{\module{trace} --- + Trace or track Python statement execution} + +\declaremodule{standard}{trace} +\modulesynopsis{Trace or track Python statement execution.} + +The \module{trace} module allows you to trace program execution, generate +annotated statement coverage listings, print caller/callee relationships and +list functions executed during a program run. It can be used in another +program or from the command line. + +\subsection{Command Line Usage\label{trace-cli}} + +The \module{trace} module can be invoked from the command line. It can be +as simple as + +\begin{verbatim} +python -m trace --count somefile.py ... +\end{verbatim} + +The above will generate annotated listings of all Python modules imported +during the execution of \file{somefile.py}. + +The following command-line arguments are supported: + +\begin{description} +\item[\longprogramopt{trace}, \programopt{-t}] +Display lines as they are executed. + +\item[\longprogramopt{count}, \programopt{-c}] +Produce a set of annotated listing files upon program +completion that shows how many times each statement was executed. + +\item[\longprogramopt{report}, \programopt{-r}] +Produce an annotated list from an earlier program run that +used the \longprogramopt{count} and \longprogramopt{file} arguments. + +\item[\longprogramopt{no-report}, \programopt{-R}] +Do not generate annotated listings. This is useful if you intend to make +several runs with \longprogramopt{count} then produce a single set +of annotated listings at the end. + +\item[\longprogramopt{listfuncs}, \programopt{-l}] +List the functions executed by running the program. + +\item[\longprogramopt{trackcalls}, \programopt{-T}] +Generate calling relationships exposed by running the program. + +\item[\longprogramopt{file}, \programopt{-f}] +Name a file containing (or to contain) counts. + +\item[\longprogramopt{coverdir}, \programopt{-C}] +Name a directory in which to save annotated listing files. + +\item[\longprogramopt{missing}, \programopt{-m}] +When generating annotated listings, mark lines which +were not executed with `\code{>>>>>>}'. + +\item[\longprogramopt{summary}, \programopt{-s}] +When using \longprogramopt{count} or \longprogramopt{report}, write a +brief summary to stdout for each file processed. + +\item[\longprogramopt{ignore-module}] +Ignore the named module and its submodules (if it is +a package). May be given multiple times. + +\item[\longprogramopt{ignore-dir}] +Ignore all modules and packages in the named directory +and subdirectories. May be given multiple times. +\end{description} + +\subsection{Programming Interface\label{trace-api}} + +\begin{classdesc}{Trace}{\optional{count=1\optional{, trace=1\optional{, + countfuncs=0\optional{, countcallers=0\optional{, + ignoremods=()\optional{, ignoredirs=()\optional{, + infile=None\optional{, outfile=None}}}}}}}}} +Create an object to trace execution of a single statement or expression. +All parameters are optional. \var{count} enables counting of line numbers. +\var{trace} enables line execution tracing. \var{countfuncs} enables +listing of the functions called during the run. \var{countcallers} enables +call relationship tracking. \var{ignoremods} is a list of modules or +packages to ignore. \var{ignoredirs} is a list of directories whose modules +or packages should be ignored. \var{infile} is the file from which to read +stored count information. \var{outfile} is a file in which to write updated +count information. +\end{classdesc} + +\begin{methoddesc}[Trace]{run}{cmd} +Run \var{cmd} under control of the Trace object with the current tracing +parameters. +\end{methoddesc} + +\begin{methoddesc}[Trace]{runctx}{cmd\optional{, globals=None\optional{, + locals=None}}} +Run \var{cmd} under control of the Trace object with the current tracing +parameters in the defined global and local environments. If not defined, +\var{globals} and \var{locals} default to empty dictionaries. +\end{methoddesc} + +\begin{methoddesc}[Trace]{runfunc}{func, *args, **kwds} +Call \var{func} with the given arguments under control of the +\class{Trace} object with the current tracing parameters. +\end{methoddesc} + +This is a simple example showing the use of this module: + +\begin{verbatim} +import sys +import trace + +# create a Trace object, telling it what to ignore, and whether to +# do tracing or line-counting or both. +tracer = trace.Trace( + ignoredirs=[sys.prefix, sys.exec_prefix], + trace=0, + count=1) + +# run the new command using the given tracer +tracer.run('main()') + +# make a report, placing output in /tmp +r = tracer.results() +r.write_results(show_missing=True, coverdir="/tmp") +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libtraceback.tex b/sys/src/cmd/python/Doc/lib/libtraceback.tex new file mode 100644 index 000000000..b7f61ace9 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtraceback.tex @@ -0,0 +1,157 @@ +\section{\module{traceback} --- + Print or retrieve a stack traceback} + +\declaremodule{standard}{traceback} +\modulesynopsis{Print or retrieve a stack traceback.} + + +This module provides a standard interface to extract, format and print +stack traces of Python programs. It exactly mimics the behavior of +the Python interpreter when it prints a stack trace. This is useful +when you want to print stack traces under program control, such as in a +``wrapper'' around the interpreter. + +The module uses traceback objects --- this is the object type that is +stored in the variables \code{sys.exc_traceback} (deprecated) and +\code{sys.last_traceback} and returned as the third item from +\function{sys.exc_info()}. +\obindex{traceback} + +The module defines the following functions: + +\begin{funcdesc}{print_tb}{traceback\optional{, limit\optional{, file}}} +Print up to \var{limit} stack trace entries from \var{traceback}. If +\var{limit} is omitted or \code{None}, all entries are printed. +If \var{file} is omitted or \code{None}, the output goes to +\code{sys.stderr}; otherwise it should be an open file or file-like +object to receive the output. +\end{funcdesc} + +\begin{funcdesc}{print_exception}{type, value, traceback\optional{, + limit\optional{, file}}} +Print exception information and up to \var{limit} stack trace entries +from \var{traceback} to \var{file}. +This differs from \function{print_tb()} in the +following ways: (1) if \var{traceback} is not \code{None}, it prints a +header \samp{Traceback (most recent call last):}; (2) it prints the +exception \var{type} and \var{value} after the stack trace; (3) if +\var{type} is \exception{SyntaxError} and \var{value} has the +appropriate format, it prints the line where the syntax error occurred +with a caret indicating the approximate position of the error. +\end{funcdesc} + +\begin{funcdesc}{print_exc}{\optional{limit\optional{, file}}} +This is a shorthand for \code{print_exception(sys.exc_type, +sys.exc_value, sys.exc_traceback, \var{limit}, \var{file})}. (In +fact, it uses \function{sys.exc_info()} to retrieve the same +information in a thread-safe way instead of using the deprecated +variables.) +\end{funcdesc} + +\begin{funcdesc}{format_exc}{\optional{limit}} +This is like \code{print_exc(\var{limit})} but returns a string +instead of printing to a file. +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{print_last}{\optional{limit\optional{, file}}} +This is a shorthand for \code{print_exception(sys.last_type, +sys.last_value, sys.last_traceback, \var{limit}, \var{file})}. +\end{funcdesc} + +\begin{funcdesc}{print_stack}{\optional{f\optional{, limit\optional{, file}}}} +This function prints a stack trace from its invocation point. The +optional \var{f} argument can be used to specify an alternate stack +frame to start. The optional \var{limit} and \var{file} arguments have the +same meaning as for \function{print_exception()}. +\end{funcdesc} + +\begin{funcdesc}{extract_tb}{traceback\optional{, limit}} +Return a list of up to \var{limit} ``pre-processed'' stack trace +entries extracted from the traceback object \var{traceback}. It is +useful for alternate formatting of stack traces. If \var{limit} is +omitted or \code{None}, all entries are extracted. A +``pre-processed'' stack trace entry is a quadruple (\var{filename}, +\var{line number}, \var{function name}, \var{text}) representing +the information that is usually printed for a stack trace. The +\var{text} is a string with leading and trailing whitespace +stripped; if the source is not available it is \code{None}. +\end{funcdesc} + +\begin{funcdesc}{extract_stack}{\optional{f\optional{, limit}}} +Extract the raw traceback from the current stack frame. The return +value has the same format as for \function{extract_tb()}. The +optional \var{f} and \var{limit} arguments have the same meaning as +for \function{print_stack()}. +\end{funcdesc} + +\begin{funcdesc}{format_list}{list} +Given a list of tuples as returned by \function{extract_tb()} or +\function{extract_stack()}, return a list of strings ready for +printing. Each string in the resulting list corresponds to the item +with the same index in the argument list. Each string ends in a +newline; the strings may contain internal newlines as well, for those +items whose source text line is not \code{None}. +\end{funcdesc} + +\begin{funcdesc}{format_exception_only}{type, value} +Format the exception part of a traceback. The arguments are the +exception type and value such as given by \code{sys.last_type} and +\code{sys.last_value}. The return value is a list of strings, each +ending in a newline. Normally, the list contains a single string; +however, for \exception{SyntaxError} exceptions, it contains several +lines that (when printed) display detailed information about where the +syntax error occurred. The message indicating which exception +occurred is the always last string in the list. +\end{funcdesc} + +\begin{funcdesc}{format_exception}{type, value, tb\optional{, limit}} +Format a stack trace and the exception information. The arguments +have the same meaning as the corresponding arguments to +\function{print_exception()}. The return value is a list of strings, +each ending in a newline and some containing internal newlines. When +these lines are concatenated and printed, exactly the same text is +printed as does \function{print_exception()}. +\end{funcdesc} + +\begin{funcdesc}{format_tb}{tb\optional{, limit}} +A shorthand for \code{format_list(extract_tb(\var{tb}, \var{limit}))}. +\end{funcdesc} + +\begin{funcdesc}{format_stack}{\optional{f\optional{, limit}}} +A shorthand for \code{format_list(extract_stack(\var{f}, \var{limit}))}. +\end{funcdesc} + +\begin{funcdesc}{tb_lineno}{tb} +This function returns the current line number set in the traceback +object. This function was necessary because in versions of Python +prior to 2.3 when the \programopt{-O} flag was passed to Python the +\code{\var{tb}.tb_lineno} was not updated correctly. This function +has no use in versions past 2.3. +\end{funcdesc} + + +\subsection{Traceback Example \label{traceback-example}} + +This simple example implements a basic read-eval-print loop, similar +to (but less useful than) the standard Python interactive interpreter +loop. For a more complete implementation of the interpreter loop, +refer to the \refmodule{code} module. + +\begin{verbatim} +import sys, traceback + +def run_user_code(envdir): + source = raw_input(">>> ") + try: + exec source in envdir + except: + print "Exception in user code:" + print '-'*60 + traceback.print_exc(file=sys.stdout) + print '-'*60 + +envdir = {} +while 1: + run_user_code(envdir) +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libtty.tex b/sys/src/cmd/python/Doc/lib/libtty.tex new file mode 100644 index 000000000..d42771aac --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtty.tex @@ -0,0 +1,34 @@ +\section{\module{tty} --- + Terminal control functions} + +\declaremodule{standard}{tty} + \platform{Unix} +\moduleauthor{Steen Lumholt}{} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Utility functions that perform common terminal control + operations.} + +The \module{tty} module defines functions for putting the tty into +cbreak and raw modes. + +Because it requires the \refmodule{termios} module, it will work +only on \UNIX. + +The \module{tty} module defines the following functions: + +\begin{funcdesc}{setraw}{fd\optional{, when}} +Change the mode of the file descriptor \var{fd} to raw. If \var{when} +is omitted, it defaults to \constant{termios.TCSAFLUSH}, and is passed +to \function{termios.tcsetattr()}. +\end{funcdesc} + +\begin{funcdesc}{setcbreak}{fd\optional{, when}} +Change the mode of file descriptor \var{fd} to cbreak. If \var{when} +is omitted, it defaults to \constant{termios.TCSAFLUSH}, and is passed +to \function{termios.tcsetattr()}. +\end{funcdesc} + + +\begin{seealso} + \seemodule{termios}{Low-level terminal control interface.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libturtle.tex b/sys/src/cmd/python/Doc/lib/libturtle.tex new file mode 100644 index 000000000..6161cd989 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libturtle.tex @@ -0,0 +1,268 @@ +\section{\module{turtle} --- + Turtle graphics for Tk} + +\declaremodule{standard}{turtle} + \platform{Tk} +\moduleauthor{Guido van Rossum}{guido@python.org} +\modulesynopsis{An environment for turtle graphics.} + +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} + + +The \module{turtle} module provides turtle graphics primitives, in both an +object-oriented and procedure-oriented ways. Because it uses \module{Tkinter} +for the underlying graphics, it needs a version of python installed with +Tk support. + +The procedural interface uses a pen and a canvas which are automagically +created when any of the functions are called. + +The \module{turtle} module defines the following functions: + +\begin{funcdesc}{degrees}{} +Set angle measurement units to degrees. +\end{funcdesc} + +\begin{funcdesc}{radians}{} +Set angle measurement units to radians. +\end{funcdesc} + +\begin{funcdesc}{setup}{**kwargs} +Sets the size and position of the main window. Keywords are: +\begin{itemize} + \item \code{width}: either a size in pixels or a fraction of the screen. + The default is 50\% of the screen. + \item \code{height}: either a size in pixels or a fraction of the screen. + The default is 50\% of the screen. + \item \code{startx}: starting position in pixels from the left edge + of the screen. \code{None} is the default value and + centers the window horizontally on screen. + \item \code{starty}: starting position in pixels from the top edge + of the screen. \code{None} is the default value and + centers the window vertically on screen. +\end{itemize} + + Examples: + +\begin{verbatim} +# Uses default geometry: 50% x 50% of screen, centered. +setup() + +# Sets window to 200x200 pixels, in upper left of screen +setup (width=200, height=200, startx=0, starty=0) + +# Sets window to 75% of screen by 50% of screen, and centers it. +setup(width=.75, height=0.5, startx=None, starty=None) +\end{verbatim} + +\end{funcdesc} + +\begin{funcdesc}{title}{title_str} +Set the window's title to \var{title}. +\end{funcdesc} + +\begin{funcdesc}{done}{} +Enters the Tk main loop. The window will continue to +be displayed until the user closes it or the process is killed. +\end{funcdesc} + +\begin{funcdesc}{reset}{} +Clear the screen, re-center the pen, and set variables to the default +values. +\end{funcdesc} + +\begin{funcdesc}{clear}{} +Clear the screen. +\end{funcdesc} + +\begin{funcdesc}{tracer}{flag} +Set tracing on/off (according to whether flag is true or not). Tracing +means line are drawn more slowly, with an animation of an arrow along the +line. +\end{funcdesc} + +\begin{funcdesc}{speed}{speed} +Set the speed of the turtle. Valid values for the parameter +\var{speed} are \code{'fastest'} (no delay), \code{'fast'}, +(delay 5ms), \code{'normal'} (delay 10ms), \code{'slow'} +(delay 15ms), and \code{'slowest'} (delay 20ms). +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{delay}{delay} +Set the speed of the turtle to \var{delay}, which is given +in ms. \versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{forward}{distance} +Go forward \var{distance} steps. +\end{funcdesc} + +\begin{funcdesc}{backward}{distance} +Go backward \var{distance} steps. +\end{funcdesc} + +\begin{funcdesc}{left}{angle} +Turn left \var{angle} units. Units are by default degrees, but can be +set via the \function{degrees()} and \function{radians()} functions. +\end{funcdesc} + +\begin{funcdesc}{right}{angle} +Turn right \var{angle} units. Units are by default degrees, but can be +set via the \function{degrees()} and \function{radians()} functions. +\end{funcdesc} + +\begin{funcdesc}{up}{} +Move the pen up --- stop drawing. +\end{funcdesc} + +\begin{funcdesc}{down}{} +Move the pen down --- draw when moving. +\end{funcdesc} + +\begin{funcdesc}{width}{width} +Set the line width to \var{width}. +\end{funcdesc} + +\begin{funcdesc}{color}{s} +\funclineni{color}{(r, g, b)} +\funclineni{color}{r, g, b} +Set the pen color. In the first form, the color is specified as a +Tk color specification as a string. The second form specifies the +color as a tuple of the RGB values, each in the range [0..1]. For the +third form, the color is specified giving the RGB values as three +separate parameters (each in the range [0..1]). +\end{funcdesc} + +\begin{funcdesc}{write}{text\optional{, move}} +Write \var{text} at the current pen position. If \var{move} is true, +the pen is moved to the bottom-right corner of the text. By default, +\var{move} is false. +\end{funcdesc} + +\begin{funcdesc}{fill}{flag} +The complete specifications are rather complex, but the recommended +usage is: call \code{fill(1)} before drawing a path you want to fill, +and call \code{fill(0)} when you finish to draw the path. +\end{funcdesc} + +\begin{funcdesc}{begin\_fill}{} +Switch turtle into filling mode; +Must eventually be followed by a corresponding end_fill() call. +Otherwise it will be ignored. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{end\_fill}{} +End filling mode, and fill the shape; equivalent to \code{fill(0)}. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{circle}{radius\optional{, extent}} +Draw a circle with radius \var{radius} whose center-point is +\var{radius} units left of the turtle. +\var{extent} determines which part of a circle is drawn: if +not given it defaults to a full circle. + +If \var{extent} is not a full circle, one endpoint of the arc is the +current pen position. The arc is drawn in a counter clockwise +direction if \var{radius} is positive, otherwise in a clockwise +direction. In the process, the direction of the turtle is changed +by the amount of the \var{extent}. +\end{funcdesc} + +\begin{funcdesc}{goto}{x, y} +\funclineni{goto}{(x, y)} +Go to co-ordinates \var{x}, \var{y}. The co-ordinates may be +specified either as two separate arguments or as a 2-tuple. +\end{funcdesc} + +\begin{funcdesc}{towards}{x, y} +Return the angle of the line from the turtle's position +to the point \var{x}, \var{y}. The co-ordinates may be +specified either as two separate arguments, as a 2-tuple, +or as another pen object. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{heading}{} +Return the current orientation of the turtle. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{setheading}{angle} +Set the orientation of the turtle to \var{angle}. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{position}{} +Return the current location of the turtle as an \code{(x,y)} pair. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{setx}{x} +Set the x coordinate of the turtle to \var{x}. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{sety}{y} +Set the y coordinate of the turtle to \var{y}. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{window\_width}{} +Return the width of the canvas window. +\versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{window\_height}{} +Return the height of the canvas window. +\versionadded{2.3} +\end{funcdesc} + +This module also does \code{from math import *}, so see the +documentation for the \refmodule{math} module for additional constants +and functions useful for turtle graphics. + +\begin{funcdesc}{demo}{} +Exercise the module a bit. +\end{funcdesc} + +\begin{excdesc}{Error} +Exception raised on any error caught by this module. +\end{excdesc} + +For examples, see the code of the \function{demo()} function. + +This module defines the following classes: + +\begin{classdesc}{Pen}{} +Define a pen. All above functions can be called as a methods on the given +pen. The constructor automatically creates a canvas do be drawn on. +\end{classdesc} + +\begin{classdesc}{Turtle}{} +Define a pen. This is essentially a synonym for \code{Pen()}; +\class{Turtle} is an empty subclass of \class{Pen}. +\end{classdesc} + +\begin{classdesc}{RawPen}{canvas} +Define a pen which draws on a canvas \var{canvas}. This is useful if +you want to use the module to create graphics in a ``real'' program. +\end{classdesc} + +\subsection{Turtle, Pen and RawPen Objects \label{pen-rawpen-objects}} + +Most of the global functions available in the module are also +available as methods of the \class{Turtle}, \class{Pen} and +\class{RawPen} classes, affecting only the state of the given pen. + +The only method which is more powerful as a method is +\function{degrees()}, which takes an optional argument letting +you specify the number of units corresponding to a full circle: + +\begin{methoddesc}{degrees}{\optional{fullcircle}} +\var{fullcircle} is by default 360. This can cause the pen to have any +angular units whatever: give \var{fullcircle} 2*$\pi$ for radians, or +400 for gradians. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libtypes.tex b/sys/src/cmd/python/Doc/lib/libtypes.tex new file mode 100644 index 000000000..5e0c5a6ab --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libtypes.tex @@ -0,0 +1,215 @@ +\section{\module{types} --- + Names for built-in types} + +\declaremodule{standard}{types} +\modulesynopsis{Names for built-in types.} + + +This module defines names for some object types that are used by +the standard Python interpreter, but not for the types defined by various +extension modules. Also, it does not include some of the types that +arise during processing such as the \code{listiterator} type. +It is safe to use \samp{from types import *} --- +the module does not export any names besides the ones listed here. +New names exported by future versions of this module will all end in +\samp{Type}. + +Typical use is for functions that do different things depending on +their argument types, like the following: + +\begin{verbatim} +from types import * +def delete(mylist, item): + if type(item) is IntType: + del mylist[item] + else: + mylist.remove(item) +\end{verbatim} + +Starting in Python 2.2, built-in factory functions such as +\function{int()} and \function{str()} are also names for the +corresponding types. This is now the preferred way to access +the type instead of using the \module{types} module. Accordingly, +the example above should be written as follows: + +\begin{verbatim} +def delete(mylist, item): + if isinstance(item, int): + del mylist[item] + else: + mylist.remove(item) +\end{verbatim} + +The module defines the following names: + +\begin{datadesc}{NoneType} +The type of \code{None}. +\end{datadesc} + +\begin{datadesc}{TypeType} +The type of type objects (such as returned by +\function{type()}\bifuncindex{type}). +\end{datadesc} + +\begin{datadesc}{BooleanType} +The type of the \class{bool} values \code{True} and \code{False}; this +is an alias of the built-in \function{bool()} function. +\versionadded{2.3} +\end{datadesc} + +\begin{datadesc}{IntType} +The type of integers (e.g. \code{1}). +\end{datadesc} + +\begin{datadesc}{LongType} +The type of long integers (e.g. \code{1L}). +\end{datadesc} + +\begin{datadesc}{FloatType} +The type of floating point numbers (e.g. \code{1.0}). +\end{datadesc} + +\begin{datadesc}{ComplexType} +The type of complex numbers (e.g. \code{1.0j}). This is not defined +if Python was built without complex number support. +\end{datadesc} + +\begin{datadesc}{StringType} +The type of character strings (e.g. \code{'Spam'}). +\end{datadesc} + +\begin{datadesc}{UnicodeType} +The type of Unicode character strings (e.g. \code{u'Spam'}). This is +not defined if Python was built without Unicode support. +\end{datadesc} + +\begin{datadesc}{TupleType} +The type of tuples (e.g. \code{(1, 2, 3, 'Spam')}). +\end{datadesc} + +\begin{datadesc}{ListType} +The type of lists (e.g. \code{[0, 1, 2, 3]}). +\end{datadesc} + +\begin{datadesc}{DictType} +The type of dictionaries (e.g. \code{\{'Bacon': 1, 'Ham': 0\}}). +\end{datadesc} + +\begin{datadesc}{DictionaryType} +An alternate name for \code{DictType}. +\end{datadesc} + +\begin{datadesc}{FunctionType} +The type of user-defined functions and lambdas. +\end{datadesc} + +\begin{datadesc}{LambdaType} +An alternate name for \code{FunctionType}. +\end{datadesc} + +\begin{datadesc}{GeneratorType} +The type of generator-iterator objects, produced by calling a +generator function. +\versionadded{2.2} +\end{datadesc} + +\begin{datadesc}{CodeType} +The type for code objects such as returned by +\function{compile()}\bifuncindex{compile}. +\end{datadesc} + +\begin{datadesc}{ClassType} +The type of user-defined classes. +\end{datadesc} + +\begin{datadesc}{InstanceType} +The type of instances of user-defined classes. +\end{datadesc} + +\begin{datadesc}{MethodType} +The type of methods of user-defined class instances. +\end{datadesc} + +\begin{datadesc}{UnboundMethodType} +An alternate name for \code{MethodType}. +\end{datadesc} + +\begin{datadesc}{BuiltinFunctionType} +The type of built-in functions like \function{len()} or +\function{sys.exit()}. +\end{datadesc} + +\begin{datadesc}{BuiltinMethodType} +An alternate name for \code{BuiltinFunction}. +\end{datadesc} + +\begin{datadesc}{ModuleType} +The type of modules. +\end{datadesc} + +\begin{datadesc}{FileType} +The type of open file objects such as \code{sys.stdout}. +\end{datadesc} + +\begin{datadesc}{XRangeType} +The type of range objects returned by +\function{xrange()}\bifuncindex{xrange}. +\end{datadesc} + +\begin{datadesc}{SliceType} +The type of objects returned by +\function{slice()}\bifuncindex{slice}. +\end{datadesc} + +\begin{datadesc}{EllipsisType} +The type of \code{Ellipsis}. +\end{datadesc} + +\begin{datadesc}{TracebackType} +The type of traceback objects such as found in +\code{sys.exc_traceback}. +\end{datadesc} + +\begin{datadesc}{FrameType} +The type of frame objects such as found in \code{tb.tb_frame} if +\code{tb} is a traceback object. +\end{datadesc} + +\begin{datadesc}{BufferType} +The type of buffer objects created by the +\function{buffer()}\bifuncindex{buffer} function. +\end{datadesc} + +\begin{datadesc}{DictProxyType} +The type of dict proxies, such as \code{TypeType.__dict__}. +\end{datadesc} + +\begin{datadesc}{NotImplementedType} +The type of \code{NotImplemented} +\end{datadesc} + +\begin{datadesc}{GetSetDescriptorType} +The type of objects defined in extension modules with \code{PyGetSetDef}, such +as \code{FrameType.f_locals} or \code{array.array.typecode}. This constant is +not defined in implementations of Python that do not have such extension +types, so for portable code use \code{hasattr(types, 'GetSetDescriptorType')}. +\versionadded{2.5} +\end{datadesc} + +\begin{datadesc}{MemberDescriptorType} +The type of objects defined in extension modules with \code{PyMemberDef}, such +as \code {datetime.timedelta.days}. This constant is not defined in +implementations of Python that do not have such extension types, so for +portable code use \code{hasattr(types, 'MemberDescriptorType')}. +\versionadded{2.5} +\end{datadesc} + +\begin{datadesc}{StringTypes} +A sequence containing \code{StringType} and \code{UnicodeType} used to +facilitate easier checking for any string object. Using this is more +portable than using a sequence of the two string types constructed +elsewhere since it only contains \code{UnicodeType} if it has been +built in the running version of Python. For example: +\code{isinstance(s, types.StringTypes)}. +\versionadded{2.2} +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/libundoc.tex b/sys/src/cmd/python/Doc/lib/libundoc.tex new file mode 100644 index 000000000..e7d388f15 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libundoc.tex @@ -0,0 +1,113 @@ +\chapter{Undocumented Modules \label{undoc}} + +Here's a quick listing of modules that are currently undocumented, but +that should be documented. Feel free to contribute documentation for +them! (Send via email to \email{docs@python.org}.) + +The idea and original contents for this chapter were taken +from a posting by Fredrik Lundh; the specific contents of this chapter +have been substantially revised. + + +\section{Frameworks} + +Frameworks tend to be harder to document, but are well worth the +effort spent. + +\begin{description} +\item None at this time. +\end{description} + + +\section{Miscellaneous useful utilities} + +Some of these are very old and/or not very robust; marked with ``hmm.'' + +\begin{description} +\item[\module{bdb}] +--- A generic Python debugger base class (used by pdb). + +\item[\module{ihooks}] +--- Import hook support (for \refmodule{rexec}; may become obsolete). +\end{description} + + + +\section{Platform specific modules} + +These modules are used to implement the \refmodule{os.path} module, +and are not documented beyond this mention. There's little need to +document these. + +\begin{description} +\item[\module{ntpath}] +--- Implementation of \module{os.path} on Win32, Win64, WinCE, and + OS/2 platforms. + +\item[\module{posixpath}] +--- Implementation of \module{os.path} on \POSIX. + +\item[\module{bsddb185}] +--- Backwards compatibility module for systems which still use the Berkeley + DB 1.85 module. It is normally only available on certain BSD \UNIX-based + systems. It should never be used directly. +\end{description} + + +\section{Multimedia} + +\begin{description} +\item[\module{audiodev}] +--- Platform-independent API for playing audio data. + +\item[\module{linuxaudiodev}] +--- Play audio data on the Linux audio device. Replaced in Python 2.3 + by the \module{ossaudiodev} module. + +\item[\module{sunaudio}] +--- Interpret Sun audio headers (may become obsolete or a tool/demo). + +\item[\module{toaiff}] +--- Convert "arbitrary" sound files to AIFF files; should probably + become a tool or demo. Requires the external program \program{sox}. +\end{description} + + +\section{Obsolete \label{obsolete-modules}} + +These modules are not normally available for import; additional work +must be done to make them available. + +%%% lib-old is empty as of Python 2.5 +% Those which are written in Python will be installed into the directory +% \file{lib-old/} installed as part of the standard library. To use +% these, the directory must be added to \code{sys.path}, possibly using +% \envvar{PYTHONPATH}. + +These extension modules written in C are not built by default. +Under \UNIX, these must be enabled by uncommenting the appropriate +lines in \file{Modules/Setup} in the build tree and either rebuilding +Python if the modules are statically linked, or building and +installing the shared object if using dynamically-loaded extensions. + +% XXX need Windows instructions! + +\begin{description} +\item[\module{timing}] +--- Measure time intervals to high resolution (use \function{time.clock()} + instead). +\end{description} + +\section{SGI-specific Extension modules} + +The following are SGI specific, and may be out of touch with the +current version of reality. + +\begin{description} +\item[\module{cl}] +--- Interface to the SGI compression library. + +\item[\module{sv}] +--- Interface to the ``simple video'' board on SGI Indigo + (obsolete hardware). +\end{description} diff --git a/sys/src/cmd/python/Doc/lib/libunicodedata.tex b/sys/src/cmd/python/Doc/lib/libunicodedata.tex new file mode 100644 index 000000000..435466a31 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libunicodedata.tex @@ -0,0 +1,160 @@ +\section{\module{unicodedata} --- + Unicode Database} + +\declaremodule{standard}{unicodedata} +\modulesynopsis{Access the Unicode Database.} +\moduleauthor{Marc-Andre Lemburg}{mal@lemburg.com} +\sectionauthor{Marc-Andre Lemburg}{mal@lemburg.com} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} + +\index{Unicode} +\index{character} +\indexii{Unicode}{database} + +This module provides access to the Unicode Character Database which +defines character properties for all Unicode characters. The data in +this database is based on the \file{UnicodeData.txt} file version +4.1.0 which is publicly available from \url{ftp://ftp.unicode.org/}. + +The module uses the same names and symbols as defined by the +UnicodeData File Format 4.1.0 (see +\url{http://www.unicode.org/Public/4.1.0/ucd/UCD.html}). It +defines the following functions: + +\begin{funcdesc}{lookup}{name} + Look up character by name. If a character with the + given name is found, return the corresponding Unicode + character. If not found, \exception{KeyError} is raised. +\end{funcdesc} + +\begin{funcdesc}{name}{unichr\optional{, default}} + Returns the name assigned to the Unicode character + \var{unichr} as a string. If no name is defined, + \var{default} is returned, or, if not given, + \exception{ValueError} is raised. +\end{funcdesc} + +\begin{funcdesc}{decimal}{unichr\optional{, default}} + Returns the decimal value assigned to the Unicode character + \var{unichr} as integer. If no such value is defined, + \var{default} is returned, or, if not given, + \exception{ValueError} is raised. +\end{funcdesc} + +\begin{funcdesc}{digit}{unichr\optional{, default}} + Returns the digit value assigned to the Unicode character + \var{unichr} as integer. If no such value is defined, + \var{default} is returned, or, if not given, + \exception{ValueError} is raised. +\end{funcdesc} + +\begin{funcdesc}{numeric}{unichr\optional{, default}} + Returns the numeric value assigned to the Unicode character + \var{unichr} as float. If no such value is defined, \var{default} is + returned, or, if not given, \exception{ValueError} is raised. +\end{funcdesc} + +\begin{funcdesc}{category}{unichr} + Returns the general category assigned to the Unicode character + \var{unichr} as string. +\end{funcdesc} + +\begin{funcdesc}{bidirectional}{unichr} + Returns the bidirectional category assigned to the Unicode character + \var{unichr} as string. If no such value is defined, an empty string + is returned. +\end{funcdesc} + +\begin{funcdesc}{combining}{unichr} + Returns the canonical combining class assigned to the Unicode + character \var{unichr} as integer. Returns \code{0} if no combining + class is defined. +\end{funcdesc} + +\begin{funcdesc}{east_asian_width}{unichr} + Returns the east asian width assigned to the Unicode character + \var{unichr} as string. +\versionadded{2.4} +\end{funcdesc} + +\begin{funcdesc}{mirrored}{unichr} + Returns the mirrored property assigned to the Unicode character + \var{unichr} as integer. Returns \code{1} if the character has been + identified as a ``mirrored'' character in bidirectional text, + \code{0} otherwise. +\end{funcdesc} + +\begin{funcdesc}{decomposition}{unichr} + Returns the character decomposition mapping assigned to the Unicode + character \var{unichr} as string. An empty string is returned in case + no such mapping is defined. +\end{funcdesc} + +\begin{funcdesc}{normalize}{form, unistr} + +Return the normal form \var{form} for the Unicode string \var{unistr}. +Valid values for \var{form} are 'NFC', 'NFKC', 'NFD', and 'NFKD'. + +The Unicode standard defines various normalization forms of a Unicode +string, based on the definition of canonical equivalence and +compatibility equivalence. In Unicode, several characters can be +expressed in various way. For example, the character U+00C7 (LATIN +CAPITAL LETTER C WITH CEDILLA) can also be expressed as the sequence +U+0043 (LATIN CAPITAL LETTER C) U+0327 (COMBINING CEDILLA). + +For each character, there are two normal forms: normal form C and +normal form D. Normal form D (NFD) is also known as canonical +decomposition, and translates each character into its decomposed form. +Normal form C (NFC) first applies a canonical decomposition, then +composes pre-combined characters again. + +In addition to these two forms, there are two additional normal forms +based on compatibility equivalence. In Unicode, certain characters are +supported which normally would be unified with other characters. For +example, U+2160 (ROMAN NUMERAL ONE) is really the same thing as U+0049 +(LATIN CAPITAL LETTER I). However, it is supported in Unicode for +compatibility with existing character sets (e.g. gb2312). + +The normal form KD (NFKD) will apply the compatibility decomposition, +i.e. replace all compatibility characters with their equivalents. The +normal form KC (NFKC) first applies the compatibility decomposition, +followed by the canonical composition. + +\versionadded{2.3} +\end{funcdesc} + +In addition, the module exposes the following constant: + +\begin{datadesc}{unidata_version} +The version of the Unicode database used in this module. + +\versionadded{2.3} +\end{datadesc} + +\begin{datadesc}{ucd_3_2_0} +This is an object that has the same methods as the entire +module, but uses the Unicode database version 3.2 instead, +for applications that require this specific version of +the Unicode database (such as IDNA). + +\versionadded{2.5} +\end{datadesc} + +Examples: + +\begin{verbatim} +>>> unicodedata.lookup('LEFT CURLY BRACKET') +u'{' +>>> unicodedata.name(u'/') +'SOLIDUS' +>>> unicodedata.decimal(u'9') +9 +>>> unicodedata.decimal(u'a') +Traceback (most recent call last): + File "<stdin>", line 1, in ? +ValueError: not a decimal +>>> unicodedata.category(u'A') # 'L'etter, 'u'ppercase +'Lu' +>>> unicodedata.bidirectional(u'\u0660') # 'A'rabic, 'N'umber +'AN' +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libunittest.tex b/sys/src/cmd/python/Doc/lib/libunittest.tex new file mode 100644 index 000000000..f1e1033c1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libunittest.tex @@ -0,0 +1,974 @@ +\section{\module{unittest} --- + Unit testing framework} + +\declaremodule{standard}{unittest} +\modulesynopsis{Unit testing framework for Python.} +\moduleauthor{Steve Purcell}{stephen\textunderscore{}purcell@yahoo.com} +\sectionauthor{Steve Purcell}{stephen\textunderscore{}purcell@yahoo.com} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +\sectionauthor{Raymond Hettinger}{python@rcn.com} + +\versionadded{2.1} + +The Python unit testing framework, sometimes referred to as ``PyUnit,'' is +a Python language version of JUnit, by Kent Beck and Erich Gamma. +JUnit is, in turn, a Java version of Kent's Smalltalk testing +framework. Each is the de facto standard unit testing framework for +its respective language. + +\module{unittest} supports test automation, sharing of setup and shutdown +code for tests, aggregation of tests into collections, and independence of +the tests from the reporting framework. The \module{unittest} module +provides classes that make it easy to support these qualities for a +set of tests. + +To achieve this, \module{unittest} supports some important concepts: + +\begin{definitions} +\term{test fixture} +A \dfn{test fixture} represents the preparation needed to perform one +or more tests, and any associate cleanup actions. This may involve, +for example, creating temporary or proxy databases, directories, or +starting a server process. + +\term{test case} +A \dfn{test case} is the smallest unit of testing. It checks for a +specific response to a particular set of inputs. \module{unittest} +provides a base class, \class{TestCase}, which may be used to create +new test cases. + +\term{test suite} +A \dfn{test suite} is a collection of test cases, test suites, or +both. It is used to aggregate tests that should be executed +together. + +\term{test runner} +A \dfn{test runner} is a component which orchestrates the execution of +tests and provides the outcome to the user. The runner may use a +graphical interface, a textual interface, or return a special value to +indicate the results of executing the tests. +\end{definitions} + + +The test case and test fixture concepts are supported through the +\class{TestCase} and \class{FunctionTestCase} classes; the former +should be used when creating new tests, and the latter can be used when +integrating existing test code with a \module{unittest}-driven framework. +When building test fixtures using \class{TestCase}, the \method{setUp()} +and \method{tearDown()} methods can be overridden to provide +initialization and cleanup for the fixture. With +\class{FunctionTestCase}, existing functions can be passed to the +constructor for these purposes. When the test is run, the +fixture initialization is run first; if it succeeds, the cleanup +method is run after the test has been executed, regardless of the +outcome of the test. Each instance of the \class{TestCase} will only +be used to run a single test method, so a new fixture is created for +each test. + +Test suites are implemented by the \class{TestSuite} class. This +class allows individual tests and test suites to be aggregated; when +the suite is executed, all tests added directly to the suite and in +``child'' test suites are run. + +A test runner is an object that provides a single method, +\method{run()}, which accepts a \class{TestCase} or \class{TestSuite} +object as a parameter, and returns a result object. The class +\class{TestResult} is provided for use as the result object. +\module{unittest} provides the \class{TextTestRunner} as an example +test runner which reports test results on the standard error stream by +default. Alternate runners can be implemented for other environments +(such as graphical environments) without any need to derive from a +specific class. + + +\begin{seealso} + \seemodule{doctest}{Another test-support module with a very + different flavor.} + \seetitle[http://www.XProgramming.com/testfram.htm]{Simple Smalltalk + Testing: With Patterns}{Kent Beck's original paper on + testing frameworks using the pattern shared by + \module{unittest}.} +\end{seealso} + + +\subsection{Basic example \label{minimal-example}} + +The \module{unittest} module provides a rich set of tools for +constructing and running tests. This section demonstrates that a +small subset of the tools suffice to meet the needs of most users. + +Here is a short script to test three functions from the +\refmodule{random} module: + +\begin{verbatim} +import random +import unittest + +class TestSequenceFunctions(unittest.TestCase): + + def setUp(self): + self.seq = range(10) + + def testshuffle(self): + # make sure the shuffled sequence does not lose any elements + random.shuffle(self.seq) + self.seq.sort() + self.assertEqual(self.seq, range(10)) + + def testchoice(self): + element = random.choice(self.seq) + self.assert_(element in self.seq) + + def testsample(self): + self.assertRaises(ValueError, random.sample, self.seq, 20) + for element in random.sample(self.seq, 5): + self.assert_(element in self.seq) + +if __name__ == '__main__': + unittest.main() +\end{verbatim} + +A testcase is created by subclassing \class{unittest.TestCase}. +The three individual tests are defined with methods whose names start with +the letters \samp{test}. This naming convention informs the test runner +about which methods represent tests. + +The crux of each test is a call to \method{assertEqual()} to +check for an expected result; \method{assert_()} to verify a condition; +or \method{assertRaises()} to verify that an expected exception gets +raised. These methods are used instead of the \keyword{assert} statement +so the test runner can accumulate all test results and produce a report. + +When a \method{setUp()} method is defined, the test runner will run that +method prior to each test. Likewise, if a \method{tearDown()} method is +defined, the test runner will invoke that method after each test. In the +example, \method{setUp()} was used to create a fresh sequence for each test. + +The final block shows a simple way to run the tests. +\function{unittest.main()} provides a command line interface to the +test script. When run from the command line, the above script +produces an output that looks like this: + +\begin{verbatim} +... +---------------------------------------------------------------------- +Ran 3 tests in 0.000s + +OK +\end{verbatim} + +Instead of \function{unittest.main()}, there are other ways to run the tests +with a finer level of control, less terse output, and no requirement to be +run from the command line. For example, the last two lines may be replaced +with: + +\begin{verbatim} +suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions) +unittest.TextTestRunner(verbosity=2).run(suite) +\end{verbatim} + +Running the revised script from the interpreter or another script +produces the following output: + +\begin{verbatim} +testchoice (__main__.TestSequenceFunctions) ... ok +testsample (__main__.TestSequenceFunctions) ... ok +testshuffle (__main__.TestSequenceFunctions) ... ok + +---------------------------------------------------------------------- +Ran 3 tests in 0.110s + +OK +\end{verbatim} + +The above examples show the most commonly used \module{unittest} features +which are sufficient to meet many everyday testing needs. The remainder +of the documentation explores the full feature set from first principles. + + +\subsection{Organizing test code + \label{organizing-tests}} + +The basic building blocks of unit testing are \dfn{test cases} --- +single scenarios that must be set up and checked for correctness. In +\module{unittest}, test cases are represented by instances of +\module{unittest}'s \class{TestCase} class. To make +your own test cases you must write subclasses of \class{TestCase}, or +use \class{FunctionTestCase}. + +An instance of a \class{TestCase}-derived class is an object that can +completely run a single test method, together with optional set-up +and tidy-up code. + +The testing code of a \class{TestCase} instance should be entirely +self contained, such that it can be run either in isolation or in +arbitrary combination with any number of other test cases. + +The simplest \class{TestCase} subclass will simply override the +\method{runTest()} method in order to perform specific testing code: + +\begin{verbatim} +import unittest + +class DefaultWidgetSizeTestCase(unittest.TestCase): + def runTest(self): + widget = Widget('The widget') + self.assertEqual(widget.size(), (50, 50), 'incorrect default size') +\end{verbatim} + +Note that in order to test something, we use the one of the +\method{assert*()} or \method{fail*()} methods provided by the +\class{TestCase} base class. If the test fails, an exception will be +raised, and \module{unittest} will identify the test case as a +\dfn{failure}. Any other exceptions will be treated as \dfn{errors}. +This helps you identify where the problem is: \dfn{failures} are caused by +incorrect results - a 5 where you expected a 6. \dfn{Errors} are caused by +incorrect code - e.g., a \exception{TypeError} caused by an incorrect +function call. + +The way to run a test case will be described later. For now, note +that to construct an instance of such a test case, we call its +constructor without arguments: + +\begin{verbatim} +testCase = DefaultWidgetSizeTestCase() +\end{verbatim} + +Now, such test cases can be numerous, and their set-up can be +repetitive. In the above case, constructing a \class{Widget} in each of +100 Widget test case subclasses would mean unsightly duplication. + +Luckily, we can factor out such set-up code by implementing a method +called \method{setUp()}, which the testing framework will +automatically call for us when we run the test: + +\begin{verbatim} +import unittest + +class SimpleWidgetTestCase(unittest.TestCase): + def setUp(self): + self.widget = Widget('The widget') + +class DefaultWidgetSizeTestCase(SimpleWidgetTestCase): + def runTest(self): + self.failUnless(self.widget.size() == (50,50), + 'incorrect default size') + +class WidgetResizeTestCase(SimpleWidgetTestCase): + def runTest(self): + self.widget.resize(100,150) + self.failUnless(self.widget.size() == (100,150), + 'wrong size after resize') +\end{verbatim} + +If the \method{setUp()} method raises an exception while the test is +running, the framework will consider the test to have suffered an +error, and the \method{runTest()} method will not be executed. + +Similarly, we can provide a \method{tearDown()} method that tidies up +after the \method{runTest()} method has been run: + +\begin{verbatim} +import unittest + +class SimpleWidgetTestCase(unittest.TestCase): + def setUp(self): + self.widget = Widget('The widget') + + def tearDown(self): + self.widget.dispose() + self.widget = None +\end{verbatim} + +If \method{setUp()} succeeded, the \method{tearDown()} method will be +run whether \method{runTest()} succeeded or not. + +Such a working environment for the testing code is called a +\dfn{fixture}. + +Often, many small test cases will use the same fixture. In this case, +we would end up subclassing \class{SimpleWidgetTestCase} into many +small one-method classes such as +\class{DefaultWidgetSizeTestCase}. This is time-consuming and +discouraging, so in the same vein as JUnit, \module{unittest} provides +a simpler mechanism: + +\begin{verbatim} +import unittest + +class WidgetTestCase(unittest.TestCase): + def setUp(self): + self.widget = Widget('The widget') + + def tearDown(self): + self.widget.dispose() + self.widget = None + + def testDefaultSize(self): + self.failUnless(self.widget.size() == (50,50), + 'incorrect default size') + + def testResize(self): + self.widget.resize(100,150) + self.failUnless(self.widget.size() == (100,150), + 'wrong size after resize') +\end{verbatim} + +Here we have not provided a \method{runTest()} method, but have +instead provided two different test methods. Class instances will now +each run one of the \method{test*()} methods, with \code{self.widget} +created and destroyed separately for each instance. When creating an +instance we must specify the test method it is to run. We do this by +passing the method name in the constructor: + +\begin{verbatim} +defaultSizeTestCase = WidgetTestCase('testDefaultSize') +resizeTestCase = WidgetTestCase('testResize') +\end{verbatim} + +Test case instances are grouped together according to the features +they test. \module{unittest} provides a mechanism for this: the +\dfn{test suite}, represented by \module{unittest}'s \class{TestSuite} +class: + +\begin{verbatim} +widgetTestSuite = unittest.TestSuite() +widgetTestSuite.addTest(WidgetTestCase('testDefaultSize')) +widgetTestSuite.addTest(WidgetTestCase('testResize')) +\end{verbatim} + +For the ease of running tests, as we will see later, it is a good +idea to provide in each test module a callable object that returns a +pre-built test suite: + +\begin{verbatim} +def suite(): + suite = unittest.TestSuite() + suite.addTest(WidgetTestCase('testDefaultSize')) + suite.addTest(WidgetTestCase('testResize')) + return suite +\end{verbatim} + +or even: + +\begin{verbatim} +def suite(): + tests = ['testDefaultSize', 'testResize'] + + return unittest.TestSuite(map(WidgetTestCase, tests)) +\end{verbatim} + +Since it is a common pattern to create a \class{TestCase} subclass +with many similarly named test functions, \module{unittest} provides a +\class{TestLoader} class that can be used to automate the process of +creating a test suite and populating it with individual tests. +For example, + +\begin{verbatim} +suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase) +\end{verbatim} + +will create a test suite that will run +\code{WidgetTestCase.testDefaultSize()} and \code{WidgetTestCase.testResize}. +\class{TestLoader} uses the \code{'test'} method name prefix to identify +test methods automatically. + +Note that the order in which the various test cases will be run is +determined by sorting the test function names with the built-in +\function{cmp()} function. + +Often it is desirable to group suites of test cases together, so as to +run tests for the whole system at once. This is easy, since +\class{TestSuite} instances can be added to a \class{TestSuite} just +as \class{TestCase} instances can be added to a \class{TestSuite}: + +\begin{verbatim} +suite1 = module1.TheTestSuite() +suite2 = module2.TheTestSuite() +alltests = unittest.TestSuite([suite1, suite2]) +\end{verbatim} + +You can place the definitions of test cases and test suites in the +same modules as the code they are to test (such as \file{widget.py}), +but there are several advantages to placing the test code in a +separate module, such as \file{test_widget.py}: + +\begin{itemize} + \item The test module can be run standalone from the command line. + \item The test code can more easily be separated from shipped code. + \item There is less temptation to change test code to fit the code + it tests without a good reason. + \item Test code should be modified much less frequently than the + code it tests. + \item Tested code can be refactored more easily. + \item Tests for modules written in C must be in separate modules + anyway, so why not be consistent? + \item If the testing strategy changes, there is no need to change + the source code. +\end{itemize} + + +\subsection{Re-using old test code + \label{legacy-unit-tests}} + +Some users will find that they have existing test code that they would +like to run from \module{unittest}, without converting every old test +function to a \class{TestCase} subclass. + +For this reason, \module{unittest} provides a \class{FunctionTestCase} +class. This subclass of \class{TestCase} can be used to wrap an existing +test function. Set-up and tear-down functions can also be provided. + +Given the following test function: + +\begin{verbatim} +def testSomething(): + something = makeSomething() + assert something.name is not None + # ... +\end{verbatim} + +one can create an equivalent test case instance as follows: + +\begin{verbatim} +testcase = unittest.FunctionTestCase(testSomething) +\end{verbatim} + +If there are additional set-up and tear-down methods that should be +called as part of the test case's operation, they can also be provided +like so: + +\begin{verbatim} +testcase = unittest.FunctionTestCase(testSomething, + setUp=makeSomethingDB, + tearDown=deleteSomethingDB) +\end{verbatim} + +To make migrating existing test suites easier, \module{unittest} +supports tests raising \exception{AssertionError} to indicate test failure. +However, it is recommended that you use the explicit +\method{TestCase.fail*()} and \method{TestCase.assert*()} methods instead, +as future versions of \module{unittest} may treat \exception{AssertionError} +differently. + +\note{Even though \class{FunctionTestCase} can be used to quickly convert +an existing test base over to a \module{unittest}-based system, this +approach is not recommended. Taking the time to set up proper +\class{TestCase} subclasses will make future test refactorings infinitely +easier.} + + + +\subsection{Classes and functions + \label{unittest-contents}} + +\begin{classdesc}{TestCase}{\optional{methodName}} + Instances of the \class{TestCase} class represent the smallest + testable units in the \module{unittest} universe. This class is + intended to be used as a base class, with specific tests being + implemented by concrete subclasses. This class implements the + interface needed by the test runner to allow it to drive the + test, and methods that the test code can use to check for and + report various kinds of failure. + + Each instance of \class{TestCase} will run a single test method: + the method named \var{methodName}. If you remember, we had an + earlier example that went something like this: + + \begin{verbatim} + def suite(): + suite = unittest.TestSuite() + suite.addTest(WidgetTestCase('testDefaultSize')) + suite.addTest(WidgetTestCase('testResize')) + return suite + \end{verbatim} + + Here, we create two instances of \class{WidgetTestCase}, each of + which runs a single test. + + \var{methodName} defaults to \code{'runTest'}. +\end{classdesc} + +\begin{classdesc}{FunctionTestCase}{testFunc\optional{, + setUp\optional{, tearDown\optional{, description}}}} + This class implements the portion of the \class{TestCase} interface + which allows the test runner to drive the test, but does not provide + the methods which test code can use to check and report errors. + This is used to create test cases using legacy test code, allowing + it to be integrated into a \refmodule{unittest}-based test + framework. +\end{classdesc} + +\begin{classdesc}{TestSuite}{\optional{tests}} + This class represents an aggregation of individual tests cases and + test suites. The class presents the interface needed by the test + runner to allow it to be run as any other test case. Running a + \class{TestSuite} instance is the same as iterating over the suite, + running each test individually. + + If \var{tests} is given, it must be an iterable of individual test cases or + other test suites that will be used to build the suite initially. + Additional methods are provided to add test cases and suites to the + collection later on. +\end{classdesc} + +\begin{classdesc}{TestLoader}{} + This class is responsible for loading tests according to various + criteria and returning them wrapped in a \class{TestSuite}. + It can load all tests within a given module or \class{TestCase} + subclass. +\end{classdesc} + +\begin{classdesc}{TestResult}{} + This class is used to compile information about which tests have succeeded + and which have failed. +\end{classdesc} + +\begin{datadesc}{defaultTestLoader} + Instance of the \class{TestLoader} class intended to be shared. If no + customization of the \class{TestLoader} is needed, this instance can + be used instead of repeatedly creating new instances. +\end{datadesc} + +\begin{classdesc}{TextTestRunner}{\optional{stream\optional{, + descriptions\optional{, verbosity}}}} + A basic test runner implementation which prints results on standard + error. It has a few configurable parameters, but is essentially + very simple. Graphical applications which run test suites should + provide alternate implementations. +\end{classdesc} + +\begin{funcdesc}{main}{\optional{module\optional{, + defaultTest\optional{, argv\optional{, + testRunner\optional{, testLoader}}}}}} + A command-line program that runs a set of tests; this is primarily + for making test modules conveniently executable. The simplest use + for this function is to include the following line at the end of a + test script: + +\begin{verbatim} +if __name__ == '__main__': + unittest.main() +\end{verbatim} +\end{funcdesc} + +In some cases, the existing tests may have been written using the +\refmodule{doctest} module. If so, that module provides a +\class{DocTestSuite} class that can automatically build +\class{unittest.TestSuite} instances from the existing +\module{doctest}-based tests. +\versionadded{2.3} + + +\subsection{TestCase Objects + \label{testcase-objects}} + +Each \class{TestCase} instance represents a single test, but each +concrete subclass may be used to define multiple tests --- the +concrete class represents a single test fixture. The fixture is +created and cleaned up for each test case. + +\class{TestCase} instances provide three groups of methods: one group +used to run the test, another used by the test implementation to +check conditions and report failures, and some inquiry methods +allowing information about the test itself to be gathered. + +Methods in the first group (running the test) are: + +\begin{methoddesc}[TestCase]{setUp}{} + Method called to prepare the test fixture. This is called + immediately before calling the test method; any exception raised by + this method will be considered an error rather than a test failure. + The default implementation does nothing. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{tearDown}{} + Method called immediately after the test method has been called and + the result recorded. This is called even if the test method raised + an exception, so the implementation in subclasses may need to be + particularly careful about checking internal state. Any exception + raised by this method will be considered an error rather than a test + failure. This method will only be called if the \method{setUp()} + succeeds, regardless of the outcome of the test method. + The default implementation does nothing. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{run}{\optional{result}} + Run the test, collecting the result into the test result object + passed as \var{result}. If \var{result} is omitted or \constant{None}, + a temporary result object is created (by calling the + \method{defaultTestCase()} method) and used; this result object is not + returned to \method{run()}'s caller. + + The same effect may be had by simply calling the \class{TestCase} + instance. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{debug}{} + Run the test without collecting the result. This allows exceptions + raised by the test to be propagated to the caller, and can be used + to support running tests under a debugger. +\end{methoddesc} + + +The test code can use any of the following methods to check for and +report failures. + +\begin{methoddesc}[TestCase]{assert_}{expr\optional{, msg}} +\methodline{failUnless}{expr\optional{, msg}} + Signal a test failure if \var{expr} is false; the explanation for + the error will be \var{msg} if given, otherwise it will be + \constant{None}. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{assertEqual}{first, second\optional{, msg}} +\methodline{failUnlessEqual}{first, second\optional{, msg}} + Test that \var{first} and \var{second} are equal. If the values do + not compare equal, the test will fail with the explanation given by + \var{msg}, or \constant{None}. Note that using \method{failUnlessEqual()} + improves upon doing the comparison as the first parameter to + \method{failUnless()}: the default value for \var{msg} can be + computed to include representations of both \var{first} and + \var{second}. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{assertNotEqual}{first, second\optional{, msg}} +\methodline{failIfEqual}{first, second\optional{, msg}} + Test that \var{first} and \var{second} are not equal. If the values + do compare equal, the test will fail with the explanation given by + \var{msg}, or \constant{None}. Note that using \method{failIfEqual()} + improves upon doing the comparison as the first parameter to + \method{failUnless()} is that the default value for \var{msg} can be + computed to include representations of both \var{first} and + \var{second}. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{assertAlmostEqual}{first, second\optional{, + places\optional{, msg}}} +\methodline{failUnlessAlmostEqual}{first, second\optional{, + places\optional{, msg}}} + Test that \var{first} and \var{second} are approximately equal + by computing the difference, rounding to the given number of \var{places}, + and comparing to zero. Note that comparing a given number of decimal places + is not the same as comparing a given number of significant digits. + If the values do not compare equal, the test will fail with the explanation + given by \var{msg}, or \constant{None}. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{assertNotAlmostEqual}{first, second\optional{, + places\optional{, msg}}} +\methodline{failIfAlmostEqual}{first, second\optional{, + places\optional{, msg}}} + Test that \var{first} and \var{second} are not approximately equal + by computing the difference, rounding to the given number of \var{places}, + and comparing to zero. Note that comparing a given number of decimal places + is not the same as comparing a given number of significant digits. + If the values do not compare equal, the test will fail with the explanation + given by \var{msg}, or \constant{None}. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{assertRaises}{exception, callable, \moreargs} +\methodline{failUnlessRaises}{exception, callable, \moreargs} + Test that an exception is raised when \var{callable} is called with + any positional or keyword arguments that are also passed to + \method{assertRaises()}. The test passes if \var{exception} is + raised, is an error if another exception is raised, or fails if no + exception is raised. To catch any of a group of exceptions, a tuple + containing the exception classes may be passed as \var{exception}. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{failIf}{expr\optional{, msg}} + The inverse of the \method{failUnless()} method is the + \method{failIf()} method. This signals a test failure if \var{expr} + is true, with \var{msg} or \constant{None} for the error message. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{fail}{\optional{msg}} + Signals a test failure unconditionally, with \var{msg} or + \constant{None} for the error message. +\end{methoddesc} + +\begin{memberdesc}[TestCase]{failureException} + This class attribute gives the exception raised by the + \method{test()} method. If a test framework needs to use a + specialized exception, possibly to carry additional information, it + must subclass this exception in order to ``play fair'' with the + framework. The initial value of this attribute is + \exception{AssertionError}. +\end{memberdesc} + + +Testing frameworks can use the following methods to collect +information on the test: + +\begin{methoddesc}[TestCase]{countTestCases}{} + Return the number of tests represented by this test object. For + \class{TestCase} instances, this will always be \code{1}. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{defaultTestResult}{} + Return an instance of the test result class that should be used + for this test case class (if no other result instance is provided + to the \method{run()} method). + + For \class{TestCase} instances, this will always be an instance of + \class{TestResult}; subclasses of \class{TestCase} should + override this as necessary. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{id}{} + Return a string identifying the specific test case. This is usually + the full name of the test method, including the module and class + name. +\end{methoddesc} + +\begin{methoddesc}[TestCase]{shortDescription}{} + Returns a one-line description of the test, or \constant{None} if no + description has been provided. The default implementation of this + method returns the first line of the test method's docstring, if + available, or \constant{None}. +\end{methoddesc} + + +\subsection{TestSuite Objects + \label{testsuite-objects}} + +\class{TestSuite} objects behave much like \class{TestCase} objects, +except they do not actually implement a test. Instead, they are used +to aggregate tests into groups of tests that should be run together. +Some additional methods are available to add tests to \class{TestSuite} +instances: + +\begin{methoddesc}[TestSuite]{addTest}{test} + Add a \class{TestCase} or \class{TestSuite} to the suite. +\end{methoddesc} + +\begin{methoddesc}[TestSuite]{addTests}{tests} + Add all the tests from an iterable of \class{TestCase} and + \class{TestSuite} instances to this test suite. + + This is equivalent to iterating over \var{tests}, calling + \method{addTest()} for each element. +\end{methoddesc} + +\class{TestSuite} shares the following methods with \class{TestCase}: + +\begin{methoddesc}[TestSuite]{run}{result} + Run the tests associated with this suite, collecting the result into + the test result object passed as \var{result}. Note that unlike + \method{TestCase.run()}, \method{TestSuite.run()} requires the + result object to be passed in. +\end{methoddesc} + +\begin{methoddesc}[TestSuite]{debug}{} + Run the tests associated with this suite without collecting the result. + This allows exceptions raised by the test to be propagated to the caller + and can be used to support running tests under a debugger. +\end{methoddesc} + +\begin{methoddesc}[TestSuite]{countTestCases}{} + Return the number of tests represented by this test object, including + all individual tests and sub-suites. +\end{methoddesc} + +In the typical usage of a \class{TestSuite} object, the \method{run()} +method is invoked by a \class{TestRunner} rather than by the end-user +test harness. + + +\subsection{TestResult Objects + \label{testresult-objects}} + +A \class{TestResult} object stores the results of a set of tests. The +\class{TestCase} and \class{TestSuite} classes ensure that results are +properly recorded; test authors do not need to worry about recording the +outcome of tests. + +Testing frameworks built on top of \refmodule{unittest} may want +access to the \class{TestResult} object generated by running a set of +tests for reporting purposes; a \class{TestResult} instance is +returned by the \method{TestRunner.run()} method for this purpose. + +\class{TestResult} instances have the following attributes that will +be of interest when inspecting the results of running a set of tests: + +\begin{memberdesc}[TestResult]{errors} + A list containing 2-tuples of \class{TestCase} instances and + strings holding formatted tracebacks. Each tuple represents a test which + raised an unexpected exception. + \versionchanged[Contains formatted tracebacks instead of + \function{sys.exc_info()} results]{2.2} +\end{memberdesc} + +\begin{memberdesc}[TestResult]{failures} + A list containing 2-tuples of \class{TestCase} instances and strings + holding formatted tracebacks. Each tuple represents a test where a failure + was explicitly signalled using the \method{TestCase.fail*()} or + \method{TestCase.assert*()} methods. + \versionchanged[Contains formatted tracebacks instead of + \function{sys.exc_info()} results]{2.2} +\end{memberdesc} + +\begin{memberdesc}[TestResult]{testsRun} + The total number of tests run so far. +\end{memberdesc} + +\begin{methoddesc}[TestResult]{wasSuccessful}{} + Returns \constant{True} if all tests run so far have passed, + otherwise returns \constant{False}. +\end{methoddesc} + +\begin{methoddesc}[TestResult]{stop}{} + This method can be called to signal that the set of tests being run + should be aborted by setting the \class{TestResult}'s \code{shouldStop} + attribute to \constant{True}. \class{TestRunner} objects should respect + this flag and return without running any additional tests. + + For example, this feature is used by the \class{TextTestRunner} class + to stop the test framework when the user signals an interrupt from + the keyboard. Interactive tools which provide \class{TestRunner} + implementations can use this in a similar manner. +\end{methoddesc} + + +The following methods of the \class{TestResult} class are used to +maintain the internal data structures, and may be extended in +subclasses to support additional reporting requirements. This is +particularly useful in building tools which support interactive +reporting while tests are being run. + +\begin{methoddesc}[TestResult]{startTest}{test} + Called when the test case \var{test} is about to be run. + + The default implementation simply increments the instance's + \code{testsRun} counter. +\end{methoddesc} + +\begin{methoddesc}[TestResult]{stopTest}{test} + Called after the test case \var{test} has been executed, regardless + of the outcome. + + The default implementation does nothing. +\end{methoddesc} + +\begin{methoddesc}[TestResult]{addError}{test, err} + Called when the test case \var{test} raises an unexpected exception + \var{err} is a tuple of the form returned by \function{sys.exc_info()}: + \code{(\var{type}, \var{value}, \var{traceback})}. + + The default implementation appends \code{(\var{test}, \var{err})} to + the instance's \code{errors} attribute. +\end{methoddesc} + +\begin{methoddesc}[TestResult]{addFailure}{test, err} + Called when the test case \var{test} signals a failure. + \var{err} is a tuple of the form returned by + \function{sys.exc_info()}: \code{(\var{type}, \var{value}, + \var{traceback})}. + + The default implementation appends \code{(\var{test}, \var{err})} to + the instance's \code{failures} attribute. +\end{methoddesc} + +\begin{methoddesc}[TestResult]{addSuccess}{test} + Called when the test case \var{test} succeeds. + + The default implementation does nothing. +\end{methoddesc} + + + +\subsection{TestLoader Objects + \label{testloader-objects}} + +The \class{TestLoader} class is used to create test suites from +classes and modules. Normally, there is no need to create an instance +of this class; the \refmodule{unittest} module provides an instance +that can be shared as \code{unittest.defaultTestLoader}. +Using a subclass or instance, however, allows customization of some +configurable properties. + +\class{TestLoader} objects have the following methods: + +\begin{methoddesc}[TestLoader]{loadTestsFromTestCase}{testCaseClass} + Return a suite of all tests cases contained in the + \class{TestCase}-derived \class{testCaseClass}. +\end{methoddesc} + +\begin{methoddesc}[TestLoader]{loadTestsFromModule}{module} + Return a suite of all tests cases contained in the given module. + This method searches \var{module} for classes derived from + \class{TestCase} and creates an instance of the class for each test + method defined for the class. + + \warning{While using a hierarchy of + \class{TestCase}-derived classes can be convenient in sharing + fixtures and helper functions, defining test methods on base classes + that are not intended to be instantiated directly does not play well + with this method. Doing so, however, can be useful when the + fixtures are different and defined in subclasses.} +\end{methoddesc} + +\begin{methoddesc}[TestLoader]{loadTestsFromName}{name\optional{, module}} + Return a suite of all tests cases given a string specifier. + + The specifier \var{name} is a ``dotted name'' that may resolve + either to a module, a test case class, a test method within a test + case class, a \class{TestSuite} instance, or a callable object which + returns a \class{TestCase} or \class{TestSuite} instance. These checks + are applied in the order listed here; that is, a method on a possible + test case class will be picked up as ``a test method within a test + case class'', rather than ``a callable object''. + + For example, if you have a module \module{SampleTests} containing a + \class{TestCase}-derived class \class{SampleTestCase} with three test + methods (\method{test_one()}, \method{test_two()}, and + \method{test_three()}), the specifier \code{'SampleTests.SampleTestCase'} + would cause this method to return a suite which will run all three test + methods. Using the specifier \code{'SampleTests.SampleTestCase.test_two'} + would cause it to return a test suite which will run only the + \method{test_two()} test method. The specifier can refer to modules + and packages which have not been imported; they will be imported as + a side-effect. + + The method optionally resolves \var{name} relative to the given + \var{module}. +\end{methoddesc} + +\begin{methoddesc}[TestLoader]{loadTestsFromNames}{names\optional{, module}} + Similar to \method{loadTestsFromName()}, but takes a sequence of + names rather than a single name. The return value is a test suite + which supports all the tests defined for each name. +\end{methoddesc} + +\begin{methoddesc}[TestLoader]{getTestCaseNames}{testCaseClass} + Return a sorted sequence of method names found within + \var{testCaseClass}; this should be a subclass of \class{TestCase}. +\end{methoddesc} + + +The following attributes of a \class{TestLoader} can be configured +either by subclassing or assignment on an instance: + +\begin{memberdesc}[TestLoader]{testMethodPrefix} + String giving the prefix of method names which will be interpreted + as test methods. The default value is \code{'test'}. + + This affects \method{getTestCaseNames()} and all the + \method{loadTestsFrom*()} methods. +\end{memberdesc} + +\begin{memberdesc}[TestLoader]{sortTestMethodsUsing} + Function to be used to compare method names when sorting them in + \method{getTestCaseNames()} and all the \method{loadTestsFrom*()} methods. + The default value is the built-in \function{cmp()} function; the attribute + can also be set to \constant{None} to disable the sort. +\end{memberdesc} + +\begin{memberdesc}[TestLoader]{suiteClass} + Callable object that constructs a test suite from a list of tests. + No methods on the resulting object are needed. The default value is + the \class{TestSuite} class. + + This affects all the \method{loadTestsFrom*()} methods. +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/lib/libunix.tex b/sys/src/cmd/python/Doc/lib/libunix.tex new file mode 100644 index 000000000..686df0137 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libunix.tex @@ -0,0 +1,8 @@ +\chapter{Unix Specific Services} +\label{unix} + +The modules described in this chapter provide interfaces to features +that are unique to the \UNIX{} operating system, or in some cases to +some or many variants of it. Here's an overview: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/liburllib.tex b/sys/src/cmd/python/Doc/lib/liburllib.tex new file mode 100644 index 000000000..75ee310d5 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/liburllib.tex @@ -0,0 +1,497 @@ +\section{\module{urllib} --- + Open arbitrary resources by URL} + +\declaremodule{standard}{urllib} +\modulesynopsis{Open an arbitrary network resource by URL (requires sockets).} + +\index{WWW} +\index{World Wide Web} +\index{URL} + + +This module provides a high-level interface for fetching data across +the World Wide Web. In particular, the \function{urlopen()} function +is similar to the built-in function \function{open()}, but accepts +Universal Resource Locators (URLs) instead of filenames. Some +restrictions apply --- it can only open URLs for reading, and no seek +operations are available. + +It defines the following public functions: + +\begin{funcdesc}{urlopen}{url\optional{, data\optional{, proxies}}} +Open a network object denoted by a URL for reading. If the URL does +not have a scheme identifier, or if it has \file{file:} as its scheme +identifier, this opens a local file (without universal newlines); +otherwise it opens a socket to a server somewhere on the network. If +the connection cannot be made +the \exception{IOError} exception is raised. If all went well, a +file-like object is returned. This supports the following methods: +\method{read()}, \method{readline()}, \method{readlines()}, \method{fileno()}, +\method{close()}, \method{info()} and \method{geturl()}. It also has +proper support for the iterator protocol. +One caveat: the \method{read()} method, if the size argument is +omitted or negative, may not read until the end of the data stream; +there is no good way to determine that the entire stream from a socket +has been read in the general case. + +Except for the \method{info()} and \method{geturl()} methods, +these methods have the same interface as for +file objects --- see section \ref{bltin-file-objects} in this +manual. (It is not a built-in file object, however, so it can't be +used at those few places where a true built-in file object is +required.) + +The \method{info()} method returns an instance of the class +\class{mimetools.Message} containing meta-information associated +with the URL. When the method is HTTP, these headers are those +returned by the server at the head of the retrieved HTML page +(including Content-Length and Content-Type). When the method is FTP, +a Content-Length header will be present if (as is now usual) the +server passed back a file length in response to the FTP retrieval +request. A Content-Type header will be present if the MIME type can +be guessed. When the method is local-file, returned headers will include +a Date representing the file's last-modified time, a Content-Length +giving file size, and a Content-Type containing a guess at the file's +type. See also the description of the +\refmodule{mimetools}\refstmodindex{mimetools} module. + +The \method{geturl()} method returns the real URL of the page. In +some cases, the HTTP server redirects a client to another URL. The +\function{urlopen()} function handles this transparently, but in some +cases the caller needs to know which URL the client was redirected +to. The \method{geturl()} method can be used to get at this +redirected URL. + +If the \var{url} uses the \file{http:} scheme identifier, the optional +\var{data} argument may be given to specify a \code{POST} request +(normally the request type is \code{GET}). The \var{data} argument +must be in standard \mimetype{application/x-www-form-urlencoded} format; +see the \function{urlencode()} function below. + +The \function{urlopen()} function works transparently with proxies +which do not require authentication. In a \UNIX{} or Windows +environment, set the \envvar{http_proxy}, \envvar{ftp_proxy} or +\envvar{gopher_proxy} environment variables to a URL that identifies +the proxy server before starting the Python interpreter. For example +(the \character{\%} is the command prompt): + +\begin{verbatim} +% http_proxy="http://www.someproxy.com:3128" +% export http_proxy +% python +... +\end{verbatim} + +In a Windows environment, if no proxy environment variables are set, +proxy settings are obtained from the registry's Internet Settings +section. + +In a Macintosh environment, \function{urlopen()} will retrieve proxy +information from Internet\index{Internet Config} Config. + +Alternatively, the optional \var{proxies} argument may be used to +explicitly specify proxies. It must be a dictionary mapping scheme +names to proxy URLs, where an empty dictionary causes no proxies to be +used, and \code{None} (the default value) causes environmental proxy +settings to be used as discussed above. For example: + +\begin{verbatim} +# Use http://www.someproxy.com:3128 for http proxying +proxies = {'http': 'http://www.someproxy.com:3128'} +filehandle = urllib.urlopen(some_url, proxies=proxies) +# Don't use any proxies +filehandle = urllib.urlopen(some_url, proxies={}) +# Use proxies from environment - both versions are equivalent +filehandle = urllib.urlopen(some_url, proxies=None) +filehandle = urllib.urlopen(some_url) +\end{verbatim} + +The \function{urlopen()} function does not support explicit proxy +specification. If you need to override environmental proxy settings, +use \class{URLopener}, or a subclass such as \class{FancyURLopener}. + +Proxies which require authentication for use are not currently +supported; this is considered an implementation limitation. + +\versionchanged[Added the \var{proxies} support]{2.3} +\end{funcdesc} + +\begin{funcdesc}{urlretrieve}{url\optional{, filename\optional{, + reporthook\optional{, data}}}} +Copy a network object denoted by a URL to a local file, if necessary. +If the URL points to a local file, or a valid cached copy of the +object exists, the object is not copied. Return a tuple +\code{(\var{filename}, \var{headers})} where \var{filename} is the +local file name under which the object can be found, and \var{headers} +is whatever the \method{info()} method of the object returned by +\function{urlopen()} returned (for a remote object, possibly cached). +Exceptions are the same as for \function{urlopen()}. + +The second argument, if present, specifies the file location to copy +to (if absent, the location will be a tempfile with a generated name). +The third argument, if present, is a hook function that will be called +once on establishment of the network connection and once after each +block read thereafter. The hook will be passed three arguments; a +count of blocks transferred so far, a block size in bytes, and the +total size of the file. The third argument may be \code{-1} on older +FTP servers which do not return a file size in response to a retrieval +request. + +If the \var{url} uses the \file{http:} scheme identifier, the optional +\var{data} argument may be given to specify a \code{POST} request +(normally the request type is \code{GET}). The \var{data} argument +must in standard \mimetype{application/x-www-form-urlencoded} format; +see the \function{urlencode()} function below. + +\versionchanged[ +\function{urlretrieve()} will raise \exception{ContentTooShortError} +when it detects that the amount of data available +was less than the expected amount (which is the size reported by a +\var{Content-Length} header). This can occur, for example, when the +download is interrupted. + +The \var{Content-Length} is treated as a lower bound: if there's more data +to read, urlretrieve reads more data, but if less data is available, +it raises the exception. + +You can still retrieve the downloaded data in this case, it is stored +in the \member{content} attribute of the exception instance. + +If no \var{Content-Length} header was supplied, urlretrieve can +not check the size of the data it has downloaded, and just returns it. +In this case you just have to assume that the download was successful]{2.5} + +\end{funcdesc} + +\begin{datadesc}{_urlopener} +The public functions \function{urlopen()} and +\function{urlretrieve()} create an instance of the +\class{FancyURLopener} class and use it to perform their requested +actions. To override this functionality, programmers can create a +subclass of \class{URLopener} or \class{FancyURLopener}, then assign +an instance of that class to the +\code{urllib._urlopener} variable before calling the desired function. +For example, applications may want to specify a different +\mailheader{User-Agent} header than \class{URLopener} defines. This +can be accomplished with the following code: + +\begin{verbatim} +import urllib + +class AppURLopener(urllib.FancyURLopener): + version = "App/1.7" + +urllib._urlopener = AppURLopener() +\end{verbatim} +\end{datadesc} + +\begin{funcdesc}{urlcleanup}{} +Clear the cache that may have been built up by previous calls to +\function{urlretrieve()}. +\end{funcdesc} + +\begin{funcdesc}{quote}{string\optional{, safe}} +Replace special characters in \var{string} using the \samp{\%xx} escape. +Letters, digits, and the characters \character{_.-} are never quoted. +The optional \var{safe} parameter specifies additional characters +that should not be quoted --- its default value is \code{'/'}. + +Example: \code{quote('/\~{}connolly/')} yields \code{'/\%7econnolly/'}. +\end{funcdesc} + +\begin{funcdesc}{quote_plus}{string\optional{, safe}} +Like \function{quote()}, but also replaces spaces by plus signs, as +required for quoting HTML form values. Plus signs in the original +string are escaped unless they are included in \var{safe}. It also +does not have \var{safe} default to \code{'/'}. +\end{funcdesc} + +\begin{funcdesc}{unquote}{string} +Replace \samp{\%xx} escapes by their single-character equivalent. + +Example: \code{unquote('/\%7Econnolly/')} yields \code{'/\~{}connolly/'}. +\end{funcdesc} + +\begin{funcdesc}{unquote_plus}{string} +Like \function{unquote()}, but also replaces plus signs by spaces, as +required for unquoting HTML form values. +\end{funcdesc} + +\begin{funcdesc}{urlencode}{query\optional{, doseq}} +Convert a mapping object or a sequence of two-element tuples to a +``url-encoded'' string, suitable to pass to +\function{urlopen()} above as the optional \var{data} argument. This +is useful to pass a dictionary of form fields to a \code{POST} +request. The resulting string is a series of +\code{\var{key}=\var{value}} pairs separated by \character{\&} +characters, where both \var{key} and \var{value} are quoted using +\function{quote_plus()} above. If the optional parameter \var{doseq} is +present and evaluates to true, individual \code{\var{key}=\var{value}} pairs +are generated for each element of the sequence. +When a sequence of two-element tuples is used as the \var{query} argument, +the first element of each tuple is a key and the second is a value. The +order of parameters in the encoded string will match the order of parameter +tuples in the sequence. +The \refmodule{cgi} module provides the functions +\function{parse_qs()} and \function{parse_qsl()} which are used to +parse query strings into Python data structures. +\end{funcdesc} + +\begin{funcdesc}{pathname2url}{path} +Convert the pathname \var{path} from the local syntax for a path to +the form used in the path component of a URL. This does not produce a +complete URL. The return value will already be quoted using the +\function{quote()} function. +\end{funcdesc} + +\begin{funcdesc}{url2pathname}{path} +Convert the path component \var{path} from an encoded URL to the local +syntax for a path. This does not accept a complete URL. This +function uses \function{unquote()} to decode \var{path}. +\end{funcdesc} + +\begin{classdesc}{URLopener}{\optional{proxies\optional{, **x509}}} +Base class for opening and reading URLs. Unless you need to support +opening objects using schemes other than \file{http:}, \file{ftp:}, +\file{gopher:} or \file{file:}, you probably want to use +\class{FancyURLopener}. + +By default, the \class{URLopener} class sends a +\mailheader{User-Agent} header of \samp{urllib/\var{VVV}}, where +\var{VVV} is the \module{urllib} version number. Applications can +define their own \mailheader{User-Agent} header by subclassing +\class{URLopener} or \class{FancyURLopener} and setting the class +attribute \member{version} to an appropriate string value in the +subclass definition. + +The optional \var{proxies} parameter should be a dictionary mapping +scheme names to proxy URLs, where an empty dictionary turns proxies +off completely. Its default value is \code{None}, in which case +environmental proxy settings will be used if present, as discussed in +the definition of \function{urlopen()}, above. + +Additional keyword parameters, collected in \var{x509}, may be used for +authentication of the client when using the \file{https:} scheme. The keywords +\var{key_file} and \var{cert_file} are supported to provide an +SSL key and certificate; both are needed to support client authentication. + +\class{URLopener} objects will raise an \exception{IOError} exception +if the server returns an error code. +\end{classdesc} + +\begin{classdesc}{FancyURLopener}{...} +\class{FancyURLopener} subclasses \class{URLopener} providing default +handling for the following HTTP response codes: 301, 302, 303, 307 and +401. For the 30x response codes listed above, the +\mailheader{Location} header is used to fetch the actual URL. For 401 +response codes (authentication required), basic HTTP authentication is +performed. For the 30x response codes, recursion is bounded by the +value of the \var{maxtries} attribute, which defaults to 10. + +For all other response codes, the method \method{http_error_default()} +is called which you can override in subclasses to handle the error +appropriately. + +\note{According to the letter of \rfc{2616}, 301 and 302 responses to + POST requests must not be automatically redirected without + confirmation by the user. In reality, browsers do allow automatic + redirection of these responses, changing the POST to a GET, and + \module{urllib} reproduces this behaviour.} + +The parameters to the constructor are the same as those for +\class{URLopener}. + +\note{When performing basic authentication, a +\class{FancyURLopener} instance calls its +\method{prompt_user_passwd()} method. The default implementation asks +the users for the required information on the controlling terminal. A +subclass may override this method to support more appropriate behavior +if needed.} +\end{classdesc} + +\begin{excclassdesc}{ContentTooShortError}{msg\optional{, content}} +This exception is raised when the \function{urlretrieve()} function +detects that the amount of the downloaded data is less than the +expected amount (given by the \var{Content-Length} header). The +\member{content} attribute stores the downloaded (and supposedly +truncated) data. +\versionadded{2.5} +\end{excclassdesc} + +Restrictions: + +\begin{itemize} + +\item +Currently, only the following protocols are supported: HTTP, (versions +0.9 and 1.0), Gopher (but not Gopher-+), FTP, and local files. +\indexii{HTTP}{protocol} +\indexii{Gopher}{protocol} +\indexii{FTP}{protocol} + +\item +The caching feature of \function{urlretrieve()} has been disabled +until I find the time to hack proper processing of Expiration time +headers. + +\item +There should be a function to query whether a particular URL is in +the cache. + +\item +For backward compatibility, if a URL appears to point to a local file +but the file can't be opened, the URL is re-interpreted using the FTP +protocol. This can sometimes cause confusing error messages. + +\item +The \function{urlopen()} and \function{urlretrieve()} functions can +cause arbitrarily long delays while waiting for a network connection +to be set up. This means that it is difficult to build an interactive +Web client using these functions without using threads. + +\item +The data returned by \function{urlopen()} or \function{urlretrieve()} +is the raw data returned by the server. This may be binary data +(such as an image), plain text or (for example) HTML\index{HTML}. The +HTTP\indexii{HTTP}{protocol} protocol provides type information in the +reply header, which can be inspected by looking at the +\mailheader{Content-Type} header. For the +Gopher\indexii{Gopher}{protocol} protocol, type information is encoded +in the URL; there is currently no easy way to extract it. If the +returned data is HTML, you can use the module +\refmodule{htmllib}\refstmodindex{htmllib} to parse it. + +\item +The code handling the FTP\index{FTP} protocol cannot differentiate +between a file and a directory. This can lead to unexpected behavior +when attempting to read a URL that points to a file that is not +accessible. If the URL ends in a \code{/}, it is assumed to refer to +a directory and will be handled accordingly. But if an attempt to +read a file leads to a 550 error (meaning the URL cannot be found or +is not accessible, often for permission reasons), then the path is +treated as a directory in order to handle the case when a directory is +specified by a URL but the trailing \code{/} has been left off. This can +cause misleading results when you try to fetch a file whose read +permissions make it inaccessible; the FTP code will try to read it, +fail with a 550 error, and then perform a directory listing for the +unreadable file. If fine-grained control is needed, consider using the +\module{ftplib} module, subclassing \class{FancyURLOpener}, or changing +\var{_urlopener} to meet your needs. + +\item +This module does not support the use of proxies which require +authentication. This may be implemented in the future. + +\item +Although the \module{urllib} module contains (undocumented) routines +to parse and unparse URL strings, the recommended interface for URL +manipulation is in module \refmodule{urlparse}\refstmodindex{urlparse}. + +\end{itemize} + + +\subsection{URLopener Objects \label{urlopener-objs}} +\sectionauthor{Skip Montanaro}{skip@mojam.com} + +\class{URLopener} and \class{FancyURLopener} objects have the +following attributes. + +\begin{methoddesc}[URLopener]{open}{fullurl\optional{, data}} +Open \var{fullurl} using the appropriate protocol. This method sets +up cache and proxy information, then calls the appropriate open method with +its input arguments. If the scheme is not recognized, +\method{open_unknown()} is called. The \var{data} argument +has the same meaning as the \var{data} argument of \function{urlopen()}. +\end{methoddesc} + +\begin{methoddesc}[URLopener]{open_unknown}{fullurl\optional{, data}} +Overridable interface to open unknown URL types. +\end{methoddesc} + +\begin{methoddesc}[URLopener]{retrieve}{url\optional{, + filename\optional{, + reporthook\optional{, data}}}} +Retrieves the contents of \var{url} and places it in \var{filename}. The +return value is a tuple consisting of a local filename and either a +\class{mimetools.Message} object containing the response headers (for remote +URLs) or \code{None} (for local URLs). The caller must then open and read the +contents of \var{filename}. If \var{filename} is not given and the URL +refers to a local file, the input filename is returned. If the URL is +non-local and \var{filename} is not given, the filename is the output of +\function{tempfile.mktemp()} with a suffix that matches the suffix of the last +path component of the input URL. If \var{reporthook} is given, it must be +a function accepting three numeric parameters. It will be called after each +chunk of data is read from the network. \var{reporthook} is ignored for +local URLs. + +If the \var{url} uses the \file{http:} scheme identifier, the optional +\var{data} argument may be given to specify a \code{POST} request +(normally the request type is \code{GET}). The \var{data} argument +must in standard \mimetype{application/x-www-form-urlencoded} format; +see the \function{urlencode()} function below. +\end{methoddesc} + +\begin{memberdesc}[URLopener]{version} +Variable that specifies the user agent of the opener object. To get +\refmodule{urllib} to tell servers that it is a particular user agent, +set this in a subclass as a class variable or in the constructor +before calling the base constructor. +\end{memberdesc} + +The \class{FancyURLopener} class offers one additional method that +should be overloaded to provide the appropriate behavior: + +\begin{methoddesc}[FancyURLopener]{prompt_user_passwd}{host, realm} +Return information needed to authenticate the user at the given host +in the specified security realm. The return value should be a tuple, +\code{(\var{user}, \var{password})}, which can be used for basic +authentication. + +The implementation prompts for this information on the terminal; an +application should override this method to use an appropriate +interaction model in the local environment. +\end{methoddesc} + + +\subsection{Examples} +\nodename{Urllib Examples} + +Here is an example session that uses the \samp{GET} method to retrieve +a URL containing parameters: + +\begin{verbatim} +>>> import urllib +>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) +>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query?%s" % params) +>>> print f.read() +\end{verbatim} + +The following example uses the \samp{POST} method instead: + +\begin{verbatim} +>>> import urllib +>>> params = urllib.urlencode({'spam': 1, 'eggs': 2, 'bacon': 0}) +>>> f = urllib.urlopen("http://www.musi-cal.com/cgi-bin/query", params) +>>> print f.read() +\end{verbatim} + +The following example uses an explicitly specified HTTP proxy, +overriding environment settings: + +\begin{verbatim} +>>> import urllib +>>> proxies = {'http': 'http://proxy.example.com:8080/'} +>>> opener = urllib.FancyURLopener(proxies) +>>> f = opener.open("http://www.python.org") +>>> f.read() +\end{verbatim} + +The following example uses no proxies at all, overriding environment +settings: + +\begin{verbatim} +>>> import urllib +>>> opener = urllib.FancyURLopener({}) +>>> f = opener.open("http://www.python.org/") +>>> f.read() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/liburllib2.tex b/sys/src/cmd/python/Doc/lib/liburllib2.tex new file mode 100644 index 000000000..542a7b8ea --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/liburllib2.tex @@ -0,0 +1,872 @@ +\section{\module{urllib2} --- + extensible library for opening URLs} + +\declaremodule{standard}{urllib2} +\moduleauthor{Jeremy Hylton}{jhylton@users.sourceforge.net} +\sectionauthor{Moshe Zadka}{moshez@users.sourceforge.net} + +\modulesynopsis{An extensible library for opening URLs using a variety of + protocols} + +The \module{urllib2} module defines functions and classes which help +in opening URLs (mostly HTTP) in a complex world --- basic and digest +authentication, redirections, cookies and more. + +The \module{urllib2} module defines the following functions: + +\begin{funcdesc}{urlopen}{url\optional{, data}} +Open the URL \var{url}, which can be either a string or a \class{Request} +object. + +\var{data} may be a string specifying additional data to send to the +server, or \code{None} if no such data is needed. +Currently HTTP requests are the only ones that use \var{data}; +the HTTP request will be a POST instead of a GET when the \var{data} +parameter is provided. \var{data} should be a buffer in the standard +\mimetype{application/x-www-form-urlencoded} format. The +\function{urllib.urlencode()} function takes a mapping or sequence of +2-tuples and returns a string in this format. + +This function returns a file-like object with two additional methods: + +\begin{itemize} + \item \method{geturl()} --- return the URL of the resource retrieved + \item \method{info()} --- return the meta-information of the page, as + a dictionary-like object +\end{itemize} + +Raises \exception{URLError} on errors. + +Note that \code{None} may be returned if no handler handles the +request (though the default installed global \class{OpenerDirector} +uses \class{UnknownHandler} to ensure this never happens). +\end{funcdesc} + +\begin{funcdesc}{install_opener}{opener} +Install an \class{OpenerDirector} instance as the default global +opener. Installing an opener is only necessary if you want urlopen to +use that opener; otherwise, simply call \method{OpenerDirector.open()} +instead of \function{urlopen()}. The code does not check for a real +\class{OpenerDirector}, and any class with the appropriate interface +will work. +\end{funcdesc} + +\begin{funcdesc}{build_opener}{\optional{handler, \moreargs}} +Return an \class{OpenerDirector} instance, which chains the +handlers in the order given. \var{handler}s can be either instances +of \class{BaseHandler}, or subclasses of \class{BaseHandler} (in +which case it must be possible to call the constructor without +any parameters). Instances of the following classes will be in +front of the \var{handler}s, unless the \var{handler}s contain +them, instances of them or subclasses of them: +\class{ProxyHandler}, \class{UnknownHandler}, \class{HTTPHandler}, +\class{HTTPDefaultErrorHandler}, \class{HTTPRedirectHandler}, +\class{FTPHandler}, \class{FileHandler}, \class{HTTPErrorProcessor}. + +If the Python installation has SSL support (\function{socket.ssl()} +exists), \class{HTTPSHandler} will also be added. + +Beginning in Python 2.3, a \class{BaseHandler} subclass may also +change its \member{handler_order} member variable to modify its +position in the handlers list. +\end{funcdesc} + + +The following exceptions are raised as appropriate: + +\begin{excdesc}{URLError} +The handlers raise this exception (or derived exceptions) when they +run into a problem. It is a subclass of \exception{IOError}. +\end{excdesc} + +\begin{excdesc}{HTTPError} +A subclass of \exception{URLError}, it can also function as a +non-exceptional file-like return value (the same thing that +\function{urlopen()} returns). This is useful when handling exotic +HTTP errors, such as requests for authentication. +\end{excdesc} + +\begin{excdesc}{GopherError} +A subclass of \exception{URLError}, this is the error raised by the +Gopher handler. +\end{excdesc} + + +The following classes are provided: + +\begin{classdesc}{Request}{url\optional{, data}\optional{, headers} + \optional{, origin_req_host}\optional{, unverifiable}} +This class is an abstraction of a URL request. + +\var{url} should be a string containing a valid URL. + +\var{data} may be a string specifying additional data to send to the +server, or \code{None} if no such data is needed. +Currently HTTP requests are the only ones that use \var{data}; +the HTTP request will be a POST instead of a GET when the \var{data} +parameter is provided. \var{data} should be a buffer in the standard +\mimetype{application/x-www-form-urlencoded} format. The +\function{urllib.urlencode()} function takes a mapping or sequence of +2-tuples and returns a string in this format. + +\var{headers} should be a dictionary, and will be treated as if +\method{add_header()} was called with each key and value as arguments. + +The final two arguments are only of interest for correct handling of +third-party HTTP cookies: + +\var{origin_req_host} should be the request-host of the origin +transaction, as defined by \rfc{2965}. It defaults to +\code{cookielib.request_host(self)}. This is the host name or IP +address of the original request that was initiated by the user. For +example, if the request is for an image in an HTML document, this +should be the request-host of the request for the page containing the +image. + +\var{unverifiable} should indicate whether the request is +unverifiable, as defined by RFC 2965. It defaults to False. An +unverifiable request is one whose URL the user did not have the option +to approve. For example, if the request is for an image in an HTML +document, and the user had no option to approve the automatic fetching +of the image, this should be true. +\end{classdesc} + +\begin{classdesc}{OpenerDirector}{} +The \class{OpenerDirector} class opens URLs via \class{BaseHandler}s +chained together. It manages the chaining of handlers, and recovery +from errors. +\end{classdesc} + +\begin{classdesc}{BaseHandler}{} +This is the base class for all registered handlers --- and handles only +the simple mechanics of registration. +\end{classdesc} + +\begin{classdesc}{HTTPDefaultErrorHandler}{} +A class which defines a default handler for HTTP error responses; all +responses are turned into \exception{HTTPError} exceptions. +\end{classdesc} + +\begin{classdesc}{HTTPRedirectHandler}{} +A class to handle redirections. +\end{classdesc} + +\begin{classdesc}{HTTPCookieProcessor}{\optional{cookiejar}} +A class to handle HTTP Cookies. +\end{classdesc} + +\begin{classdesc}{ProxyHandler}{\optional{proxies}} +Cause requests to go through a proxy. +If \var{proxies} is given, it must be a dictionary mapping +protocol names to URLs of proxies. +The default is to read the list of proxies from the environment +variables \envvar{<protocol>_proxy}. +\end{classdesc} + +\begin{classdesc}{HTTPPasswordMgr}{} +Keep a database of +\code{(\var{realm}, \var{uri}) -> (\var{user}, \var{password})} +mappings. +\end{classdesc} + +\begin{classdesc}{HTTPPasswordMgrWithDefaultRealm}{} +Keep a database of +\code{(\var{realm}, \var{uri}) -> (\var{user}, \var{password})} mappings. +A realm of \code{None} is considered a catch-all realm, which is searched +if no other realm fits. +\end{classdesc} + +\begin{classdesc}{AbstractBasicAuthHandler}{\optional{password_mgr}} +This is a mixin class that helps with HTTP authentication, both +to the remote host and to a proxy. +\var{password_mgr}, if given, should be something that is compatible +with \class{HTTPPasswordMgr}; refer to section~\ref{http-password-mgr} +for information on the interface that must be supported. +\end{classdesc} + +\begin{classdesc}{HTTPBasicAuthHandler}{\optional{password_mgr}} +Handle authentication with the remote host. +\var{password_mgr}, if given, should be something that is compatible +with \class{HTTPPasswordMgr}; refer to section~\ref{http-password-mgr} +for information on the interface that must be supported. +\end{classdesc} + +\begin{classdesc}{ProxyBasicAuthHandler}{\optional{password_mgr}} +Handle authentication with the proxy. +\var{password_mgr}, if given, should be something that is compatible +with \class{HTTPPasswordMgr}; refer to section~\ref{http-password-mgr} +for information on the interface that must be supported. +\end{classdesc} + +\begin{classdesc}{AbstractDigestAuthHandler}{\optional{password_mgr}} +This is a mixin class that helps with HTTP authentication, both +to the remote host and to a proxy. +\var{password_mgr}, if given, should be something that is compatible +with \class{HTTPPasswordMgr}; refer to section~\ref{http-password-mgr} +for information on the interface that must be supported. +\end{classdesc} + +\begin{classdesc}{HTTPDigestAuthHandler}{\optional{password_mgr}} +Handle authentication with the remote host. +\var{password_mgr}, if given, should be something that is compatible +with \class{HTTPPasswordMgr}; refer to section~\ref{http-password-mgr} +for information on the interface that must be supported. +\end{classdesc} + +\begin{classdesc}{ProxyDigestAuthHandler}{\optional{password_mgr}} +Handle authentication with the proxy. +\var{password_mgr}, if given, should be something that is compatible +with \class{HTTPPasswordMgr}; refer to section~\ref{http-password-mgr} +for information on the interface that must be supported. +\end{classdesc} + +\begin{classdesc}{HTTPHandler}{} +A class to handle opening of HTTP URLs. +\end{classdesc} + +\begin{classdesc}{HTTPSHandler}{} +A class to handle opening of HTTPS URLs. +\end{classdesc} + +\begin{classdesc}{FileHandler}{} +Open local files. +\end{classdesc} + +\begin{classdesc}{FTPHandler}{} +Open FTP URLs. +\end{classdesc} + +\begin{classdesc}{CacheFTPHandler}{} +Open FTP URLs, keeping a cache of open FTP connections to minimize +delays. +\end{classdesc} + +\begin{classdesc}{GopherHandler}{} +Open gopher URLs. +\end{classdesc} + +\begin{classdesc}{UnknownHandler}{} +A catch-all class to handle unknown URLs. +\end{classdesc} + + +\subsection{Request Objects \label{request-objects}} + +The following methods describe all of \class{Request}'s public interface, +and so all must be overridden in subclasses. + +\begin{methoddesc}[Request]{add_data}{data} +Set the \class{Request} data to \var{data}. This is ignored by all +handlers except HTTP handlers --- and there it should be a byte +string, and will change the request to be \code{POST} rather than +\code{GET}. +\end{methoddesc} + +\begin{methoddesc}[Request]{get_method}{} +Return a string indicating the HTTP request method. This is only +meaningful for HTTP requests, and currently always returns +\code{'GET'} or \code{'POST'}. +\end{methoddesc} + +\begin{methoddesc}[Request]{has_data}{} +Return whether the instance has a non-\code{None} data. +\end{methoddesc} + +\begin{methoddesc}[Request]{get_data}{} +Return the instance's data. +\end{methoddesc} + +\begin{methoddesc}[Request]{add_header}{key, val} +Add another header to the request. Headers are currently ignored by +all handlers except HTTP handlers, where they are added to the list +of headers sent to the server. Note that there cannot be more than +one header with the same name, and later calls will overwrite +previous calls in case the \var{key} collides. Currently, this is +no loss of HTTP functionality, since all headers which have meaning +when used more than once have a (header-specific) way of gaining the +same functionality using only one header. +\end{methoddesc} + +\begin{methoddesc}[Request]{add_unredirected_header}{key, header} +Add a header that will not be added to a redirected request. +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[Request]{has_header}{header} +Return whether the instance has the named header (checks both regular +and unredirected). +\versionadded{2.4} +\end{methoddesc} + +\begin{methoddesc}[Request]{get_full_url}{} +Return the URL given in the constructor. +\end{methoddesc} + +\begin{methoddesc}[Request]{get_type}{} +Return the type of the URL --- also known as the scheme. +\end{methoddesc} + +\begin{methoddesc}[Request]{get_host}{} +Return the host to which a connection will be made. +\end{methoddesc} + +\begin{methoddesc}[Request]{get_selector}{} +Return the selector --- the part of the URL that is sent to +the server. +\end{methoddesc} + +\begin{methoddesc}[Request]{set_proxy}{host, type} +Prepare the request by connecting to a proxy server. The \var{host} +and \var{type} will replace those of the instance, and the instance's +selector will be the original URL given in the constructor. +\end{methoddesc} + +\begin{methoddesc}[Request]{get_origin_req_host}{} +Return the request-host of the origin transaction, as defined by +\rfc{2965}. See the documentation for the \class{Request} +constructor. +\end{methoddesc} + +\begin{methoddesc}[Request]{is_unverifiable}{} +Return whether the request is unverifiable, as defined by RFC 2965. +See the documentation for the \class{Request} constructor. +\end{methoddesc} + + +\subsection{OpenerDirector Objects \label{opener-director-objects}} + +\class{OpenerDirector} instances have the following methods: + +\begin{methoddesc}[OpenerDirector]{add_handler}{handler} +\var{handler} should be an instance of \class{BaseHandler}. The +following methods are searched, and added to the possible chains (note +that HTTP errors are a special case). + +\begin{itemize} + \item \method{\var{protocol}_open()} --- + signal that the handler knows how to open \var{protocol} URLs. + \item \method{http_error_\var{type}()} --- + signal that the handler knows how to handle HTTP errors with HTTP + error code \var{type}. + \item \method{\var{protocol}_error()} --- + signal that the handler knows how to handle errors from + (non-\code{http}) \var{protocol}. + \item \method{\var{protocol}_request()} --- + signal that the handler knows how to pre-process \var{protocol} + requests. + \item \method{\var{protocol}_response()} --- + signal that the handler knows how to post-process \var{protocol} + responses. +\end{itemize} +\end{methoddesc} + +\begin{methoddesc}[OpenerDirector]{open}{url\optional{, data}} +Open the given \var{url} (which can be a request object or a string), +optionally passing the given \var{data}. +Arguments, return values and exceptions raised are the same as those +of \function{urlopen()} (which simply calls the \method{open()} method +on the currently installed global \class{OpenerDirector}). +\end{methoddesc} + +\begin{methoddesc}[OpenerDirector]{error}{proto\optional{, + arg\optional{, \moreargs}}} +Handle an error of the given protocol. This will call the registered +error handlers for the given protocol with the given arguments (which +are protocol specific). The HTTP protocol is a special case which +uses the HTTP response code to determine the specific error handler; +refer to the \method{http_error_*()} methods of the handler classes. + +Return values and exceptions raised are the same as those +of \function{urlopen()}. +\end{methoddesc} + +OpenerDirector objects open URLs in three stages: + +The order in which these methods are called within each stage is +determined by sorting the handler instances. + +\begin{enumerate} + \item Every handler with a method named like + \method{\var{protocol}_request()} has that method called to + pre-process the request. + + \item Handlers with a method named like + \method{\var{protocol}_open()} are called to handle the request. + This stage ends when a handler either returns a + non-\constant{None} value (ie. a response), or raises an exception + (usually \exception{URLError}). Exceptions are allowed to propagate. + + In fact, the above algorithm is first tried for methods named + \method{default_open}. If all such methods return + \constant{None}, the algorithm is repeated for methods named like + \method{\var{protocol}_open()}. If all such methods return + \constant{None}, the algorithm is repeated for methods named + \method{unknown_open()}. + + Note that the implementation of these methods may involve calls of + the parent \class{OpenerDirector} instance's \method{.open()} and + \method{.error()} methods. + + \item Every handler with a method named like + \method{\var{protocol}_response()} has that method called to + post-process the response. + +\end{enumerate} + +\subsection{BaseHandler Objects \label{base-handler-objects}} + +\class{BaseHandler} objects provide a couple of methods that are +directly useful, and others that are meant to be used by derived +classes. These are intended for direct use: + +\begin{methoddesc}[BaseHandler]{add_parent}{director} +Add a director as parent. +\end{methoddesc} + +\begin{methoddesc}[BaseHandler]{close}{} +Remove any parents. +\end{methoddesc} + +The following members and methods should only be used by classes +derived from \class{BaseHandler}. \note{The convention has been +adopted that subclasses defining \method{\var{protocol}_request()} or +\method{\var{protocol}_response()} methods are named +\class{*Processor}; all others are named \class{*Handler}.} + + +\begin{memberdesc}[BaseHandler]{parent} +A valid \class{OpenerDirector}, which can be used to open using a +different protocol, or handle errors. +\end{memberdesc} + +\begin{methoddesc}[BaseHandler]{default_open}{req} +This method is \emph{not} defined in \class{BaseHandler}, but +subclasses should define it if they want to catch all URLs. + +This method, if implemented, will be called by the parent +\class{OpenerDirector}. It should return a file-like object as +described in the return value of the \method{open()} of +\class{OpenerDirector}, or \code{None}. It should raise +\exception{URLError}, unless a truly exceptional thing happens (for +example, \exception{MemoryError} should not be mapped to +\exception{URLError}). + +This method will be called before any protocol-specific open method. +\end{methoddesc} + +\begin{methoddescni}[BaseHandler]{\var{protocol}_open}{req} +This method is \emph{not} defined in \class{BaseHandler}, but +subclasses should define it if they want to handle URLs with the given +protocol. + +This method, if defined, will be called by the parent +\class{OpenerDirector}. Return values should be the same as for +\method{default_open()}. +\end{methoddescni} + +\begin{methoddesc}[BaseHandler]{unknown_open}{req} +This method is \var{not} defined in \class{BaseHandler}, but +subclasses should define it if they want to catch all URLs with no +specific registered handler to open it. + +This method, if implemented, will be called by the \member{parent} +\class{OpenerDirector}. Return values should be the same as for +\method{default_open()}. +\end{methoddesc} + +\begin{methoddesc}[BaseHandler]{http_error_default}{req, fp, code, msg, hdrs} +This method is \emph{not} defined in \class{BaseHandler}, but +subclasses should override it if they intend to provide a catch-all +for otherwise unhandled HTTP errors. It will be called automatically +by the \class{OpenerDirector} getting the error, and should not +normally be called in other circumstances. + +\var{req} will be a \class{Request} object, \var{fp} will be a +file-like object with the HTTP error body, \var{code} will be the +three-digit code of the error, \var{msg} will be the user-visible +explanation of the code and \var{hdrs} will be a mapping object with +the headers of the error. + +Return values and exceptions raised should be the same as those +of \function{urlopen()}. +\end{methoddesc} + +\begin{methoddesc}[BaseHandler]{http_error_\var{nnn}}{req, fp, code, msg, hdrs} +\var{nnn} should be a three-digit HTTP error code. This method is +also not defined in \class{BaseHandler}, but will be called, if it +exists, on an instance of a subclass, when an HTTP error with code +\var{nnn} occurs. + +Subclasses should override this method to handle specific HTTP +errors. + +Arguments, return values and exceptions raised should be the same as +for \method{http_error_default()}. +\end{methoddesc} + +\begin{methoddescni}[BaseHandler]{\var{protocol}_request}{req} +This method is \emph{not} defined in \class{BaseHandler}, but +subclasses should define it if they want to pre-process requests of +the given protocol. + +This method, if defined, will be called by the parent +\class{OpenerDirector}. \var{req} will be a \class{Request} object. +The return value should be a \class{Request} object. +\end{methoddescni} + +\begin{methoddescni}[BaseHandler]{\var{protocol}_response}{req, response} +This method is \emph{not} defined in \class{BaseHandler}, but +subclasses should define it if they want to post-process responses of +the given protocol. + +This method, if defined, will be called by the parent +\class{OpenerDirector}. \var{req} will be a \class{Request} object. +\var{response} will be an object implementing the same interface as +the return value of \function{urlopen()}. The return value should +implement the same interface as the return value of +\function{urlopen()}. +\end{methoddescni} + +\subsection{HTTPRedirectHandler Objects \label{http-redirect-handler}} + +\note{Some HTTP redirections require action from this module's client + code. If this is the case, \exception{HTTPError} is raised. See + \rfc{2616} for details of the precise meanings of the various + redirection codes.} + +\begin{methoddesc}[HTTPRedirectHandler]{redirect_request}{req, + fp, code, msg, hdrs} +Return a \class{Request} or \code{None} in response to a redirect. +This is called by the default implementations of the +\method{http_error_30*()} methods when a redirection is received from +the server. If a redirection should take place, return a new +\class{Request} to allow \method{http_error_30*()} to perform the +redirect. Otherwise, raise \exception{HTTPError} if no other handler +should try to handle this URL, or return \code{None} if you can't but +another handler might. + +\begin{notice} + The default implementation of this method does not strictly + follow \rfc{2616}, which says that 301 and 302 responses to \code{POST} + requests must not be automatically redirected without confirmation by + the user. In reality, browsers do allow automatic redirection of + these responses, changing the POST to a \code{GET}, and the default + implementation reproduces this behavior. +\end{notice} +\end{methoddesc} + + +\begin{methoddesc}[HTTPRedirectHandler]{http_error_301}{req, + fp, code, msg, hdrs} +Redirect to the \code{Location:} URL. This method is called by +the parent \class{OpenerDirector} when getting an HTTP +`moved permanently' response. +\end{methoddesc} + +\begin{methoddesc}[HTTPRedirectHandler]{http_error_302}{req, + fp, code, msg, hdrs} +The same as \method{http_error_301()}, but called for the +`found' response. +\end{methoddesc} + +\begin{methoddesc}[HTTPRedirectHandler]{http_error_303}{req, + fp, code, msg, hdrs} +The same as \method{http_error_301()}, but called for the +`see other' response. +\end{methoddesc} + +\begin{methoddesc}[HTTPRedirectHandler]{http_error_307}{req, + fp, code, msg, hdrs} +The same as \method{http_error_301()}, but called for the +`temporary redirect' response. +\end{methoddesc} + + +\subsection{HTTPCookieProcessor Objects \label{http-cookie-processor}} + +\versionadded{2.4} + +\class{HTTPCookieProcessor} instances have one attribute: + +\begin{memberdesc}{cookiejar} +The \class{cookielib.CookieJar} in which cookies are stored. +\end{memberdesc} + + +\subsection{ProxyHandler Objects \label{proxy-handler}} + +\begin{methoddescni}[ProxyHandler]{\var{protocol}_open}{request} +The \class{ProxyHandler} will have a method +\method{\var{protocol}_open()} for every \var{protocol} which has a +proxy in the \var{proxies} dictionary given in the constructor. The +method will modify requests to go through the proxy, by calling +\code{request.set_proxy()}, and call the next handler in the chain to +actually execute the protocol. +\end{methoddescni} + + +\subsection{HTTPPasswordMgr Objects \label{http-password-mgr}} + +These methods are available on \class{HTTPPasswordMgr} and +\class{HTTPPasswordMgrWithDefaultRealm} objects. + +\begin{methoddesc}[HTTPPasswordMgr]{add_password}{realm, uri, user, passwd} +\var{uri} can be either a single URI, or a sequence of URIs. \var{realm}, +\var{user} and \var{passwd} must be strings. This causes +\code{(\var{user}, \var{passwd})} to be used as authentication tokens +when authentication for \var{realm} and a super-URI of any of the +given URIs is given. +\end{methoddesc} + +\begin{methoddesc}[HTTPPasswordMgr]{find_user_password}{realm, authuri} +Get user/password for given realm and URI, if any. This method will +return \code{(None, None)} if there is no matching user/password. + +For \class{HTTPPasswordMgrWithDefaultRealm} objects, the realm +\code{None} will be searched if the given \var{realm} has no matching +user/password. +\end{methoddesc} + + +\subsection{AbstractBasicAuthHandler Objects + \label{abstract-basic-auth-handler}} + +\begin{methoddesc}[AbstractBasicAuthHandler]{http_error_auth_reqed} + {authreq, host, req, headers} +Handle an authentication request by getting a user/password pair, and +re-trying the request. \var{authreq} should be the name of the header +where the information about the realm is included in the request, +\var{host} specifies the URL and path to authenticate for, \var{req} +should be the (failed) \class{Request} object, and \var{headers} +should be the error headers. + +\var{host} is either an authority (e.g. \code{"python.org"}) or a URL +containing an authority component (e.g. \code{"http://python.org/"}). +In either case, the authority must not contain a userinfo component +(so, \code{"python.org"} and \code{"python.org:80"} are fine, +\code{"joe:password@python.org"} is not). +\end{methoddesc} + + +\subsection{HTTPBasicAuthHandler Objects + \label{http-basic-auth-handler}} + +\begin{methoddesc}[HTTPBasicAuthHandler]{http_error_401}{req, fp, code, + msg, hdrs} +Retry the request with authentication information, if available. +\end{methoddesc} + + +\subsection{ProxyBasicAuthHandler Objects + \label{proxy-basic-auth-handler}} + +\begin{methoddesc}[ProxyBasicAuthHandler]{http_error_407}{req, fp, code, + msg, hdrs} +Retry the request with authentication information, if available. +\end{methoddesc} + + +\subsection{AbstractDigestAuthHandler Objects + \label{abstract-digest-auth-handler}} + +\begin{methoddesc}[AbstractDigestAuthHandler]{http_error_auth_reqed} + {authreq, host, req, headers} +\var{authreq} should be the name of the header where the information about +the realm is included in the request, \var{host} should be the host to +authenticate to, \var{req} should be the (failed) \class{Request} +object, and \var{headers} should be the error headers. +\end{methoddesc} + + +\subsection{HTTPDigestAuthHandler Objects + \label{http-digest-auth-handler}} + +\begin{methoddesc}[HTTPDigestAuthHandler]{http_error_401}{req, fp, code, + msg, hdrs} +Retry the request with authentication information, if available. +\end{methoddesc} + + +\subsection{ProxyDigestAuthHandler Objects + \label{proxy-digest-auth-handler}} + +\begin{methoddesc}[ProxyDigestAuthHandler]{http_error_407}{req, fp, code, + msg, hdrs} +Retry the request with authentication information, if available. +\end{methoddesc} + + +\subsection{HTTPHandler Objects \label{http-handler-objects}} + +\begin{methoddesc}[HTTPHandler]{http_open}{req} +Send an HTTP request, which can be either GET or POST, depending on +\code{\var{req}.has_data()}. +\end{methoddesc} + + +\subsection{HTTPSHandler Objects \label{https-handler-objects}} + +\begin{methoddesc}[HTTPSHandler]{https_open}{req} +Send an HTTPS request, which can be either GET or POST, depending on +\code{\var{req}.has_data()}. +\end{methoddesc} + + +\subsection{FileHandler Objects \label{file-handler-objects}} + +\begin{methoddesc}[FileHandler]{file_open}{req} +Open the file locally, if there is no host name, or +the host name is \code{'localhost'}. Change the +protocol to \code{ftp} otherwise, and retry opening +it using \member{parent}. +\end{methoddesc} + + +\subsection{FTPHandler Objects \label{ftp-handler-objects}} + +\begin{methoddesc}[FTPHandler]{ftp_open}{req} +Open the FTP file indicated by \var{req}. +The login is always done with empty username and password. +\end{methoddesc} + + +\subsection{CacheFTPHandler Objects \label{cacheftp-handler-objects}} + +\class{CacheFTPHandler} objects are \class{FTPHandler} objects with +the following additional methods: + +\begin{methoddesc}[CacheFTPHandler]{setTimeout}{t} +Set timeout of connections to \var{t} seconds. +\end{methoddesc} + +\begin{methoddesc}[CacheFTPHandler]{setMaxConns}{m} +Set maximum number of cached connections to \var{m}. +\end{methoddesc} + + +\subsection{GopherHandler Objects \label{gopher-handler}} + +\begin{methoddesc}[GopherHandler]{gopher_open}{req} +Open the gopher resource indicated by \var{req}. +\end{methoddesc} + + +\subsection{UnknownHandler Objects \label{unknown-handler-objects}} + +\begin{methoddesc}[UnknownHandler]{unknown_open}{} +Raise a \exception{URLError} exception. +\end{methoddesc} + + +\subsection{HTTPErrorProcessor Objects \label{http-error-processor-objects}} + +\versionadded{2.4} + +\begin{methoddesc}[HTTPErrorProcessor]{unknown_open}{} +Process HTTP error responses. + +For 200 error codes, the response object is returned immediately. + +For non-200 error codes, this simply passes the job on to the +\method{\var{protocol}_error_\var{code}()} handler methods, via +\method{OpenerDirector.error()}. Eventually, +\class{urllib2.HTTPDefaultErrorHandler} will raise an +\exception{HTTPError} if no other handler handles the error. +\end{methoddesc} + + +\subsection{Examples \label{urllib2-examples}} + +This example gets the python.org main page and displays the first 100 +bytes of it: + +\begin{verbatim} +>>> import urllib2 +>>> f = urllib2.urlopen('http://www.python.org/') +>>> print f.read(100) +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<?xml-stylesheet href="./css/ht2html +\end{verbatim} + +Here we are sending a data-stream to the stdin of a CGI and reading +the data it returns to us. Note that this example will only work when the +Python installation supports SSL. + +\begin{verbatim} +>>> import urllib2 +>>> req = urllib2.Request(url='https://localhost/cgi-bin/test.cgi', +... data='This data is passed to stdin of the CGI') +>>> f = urllib2.urlopen(req) +>>> print f.read() +Got Data: "This data is passed to stdin of the CGI" +\end{verbatim} + +The code for the sample CGI used in the above example is: + +\begin{verbatim} +#!/usr/bin/env python +import sys +data = sys.stdin.read() +print 'Content-type: text-plain\n\nGot Data: "%s"' % data +\end{verbatim} + + +Use of Basic HTTP Authentication: + +\begin{verbatim} +import urllib2 +# Create an OpenerDirector with support for Basic HTTP Authentication... +auth_handler = urllib2.HTTPBasicAuthHandler() +auth_handler.add_password('realm', 'host', 'username', 'password') +opener = urllib2.build_opener(auth_handler) +# ...and install it globally so it can be used with urlopen. +urllib2.install_opener(opener) +urllib2.urlopen('http://www.example.com/login.html') +\end{verbatim} + +\function{build_opener()} provides many handlers by default, including a +\class{ProxyHandler}. By default, \class{ProxyHandler} uses the +environment variables named \code{<scheme>_proxy}, where \code{<scheme>} +is the URL scheme involved. For example, the \envvar{http_proxy} +environment variable is read to obtain the HTTP proxy's URL. + +This example replaces the default \class{ProxyHandler} with one that uses +programatically-supplied proxy URLs, and adds proxy authorization support +with \class{ProxyBasicAuthHandler}. + +\begin{verbatim} +proxy_handler = urllib2.ProxyHandler({'http': 'http://www.example.com:3128/'}) +proxy_auth_handler = urllib2.HTTPBasicAuthHandler() +proxy_auth_handler.add_password('realm', 'host', 'username', 'password') + +opener = build_opener(proxy_handler, proxy_auth_handler) +# This time, rather than install the OpenerDirector, we use it directly: +opener.open('http://www.example.com/login.html') +\end{verbatim} + + +Adding HTTP headers: + +Use the \var{headers} argument to the \class{Request} constructor, or: + +\begin{verbatim} +import urllib2 +req = urllib2.Request('http://www.example.com/') +req.add_header('Referer', 'http://www.python.org/') +r = urllib2.urlopen(req) +\end{verbatim} + +\class{OpenerDirector} automatically adds a \mailheader{User-Agent} +header to every \class{Request}. To change this: + +\begin{verbatim} +import urllib2 +opener = urllib2.build_opener() +opener.addheaders = [('User-agent', 'Mozilla/5.0')] +opener.open('http://www.example.com/') +\end{verbatim} + +Also, remember that a few standard headers +(\mailheader{Content-Length}, \mailheader{Content-Type} and +\mailheader{Host}) are added when the \class{Request} is passed to +\function{urlopen()} (or \method{OpenerDirector.open()}). diff --git a/sys/src/cmd/python/Doc/lib/liburlparse.tex b/sys/src/cmd/python/Doc/lib/liburlparse.tex new file mode 100644 index 000000000..76622d534 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/liburlparse.tex @@ -0,0 +1,253 @@ +\section{\module{urlparse} --- + Parse URLs into components} +\declaremodule{standard}{urlparse} + +\modulesynopsis{Parse URLs into components.} + +\index{WWW} +\index{World Wide Web} +\index{URL} +\indexii{URL}{parsing} +\indexii{relative}{URL} + + +This module defines a standard interface to break Uniform Resource +Locator (URL) strings up in components (addressing scheme, network +location, path etc.), to combine the components back into a URL +string, and to convert a ``relative URL'' to an absolute URL given a +``base URL.'' + +The module has been designed to match the Internet RFC on Relative +Uniform Resource Locators (and discovered a bug in an earlier +draft!). It supports the following URL schemes: +\code{file}, \code{ftp}, \code{gopher}, \code{hdl}, \code{http}, +\code{https}, \code{imap}, \code{mailto}, \code{mms}, \code{news}, +\code{nntp}, \code{prospero}, \code{rsync}, \code{rtsp}, \code{rtspu}, +\code{sftp}, \code{shttp}, \code{sip}, \code{sips}, \code{snews}, \code{svn}, +\code{svn+ssh}, \code{telnet}, \code{wais}. + +\versionadded[Support for the \code{sftp} and \code{sips} schemes]{2.5} + +The \module{urlparse} module defines the following functions: + +\begin{funcdesc}{urlparse}{urlstring\optional{, + default_scheme\optional{, allow_fragments}}} +Parse a URL into six components, returning a 6-tuple. This +corresponds to the general structure of a URL: +\code{\var{scheme}://\var{netloc}/\var{path};\var{parameters}?\var{query}\#\var{fragment}}. +Each tuple item is a string, possibly empty. +The components are not broken up in smaller parts (for example, the network +location is a single string), and \% escapes are not expanded. +The delimiters as shown above are not part of the result, +except for a leading slash in the \var{path} component, which is +retained if present. For example: + +\begin{verbatim} +>>> from urlparse import urlparse +>>> o = urlparse('http://www.cwi.nl:80/%7Eguido/Python.html') +>>> o +('http', 'www.cwi.nl:80', '/%7Eguido/Python.html', '', '', '') +>>> o.scheme +'http' +>>> o.port +80 +>>> o.geturl() +'http://www.cwi.nl:80/%7Eguido/Python.html' +\end{verbatim} + +If the \var{default_scheme} argument is specified, it gives the +default addressing scheme, to be used only if the URL does not +specify one. The default value for this argument is the empty string. + +If the \var{allow_fragments} argument is false, fragment identifiers +are not allowed, even if the URL's addressing scheme normally does +support them. The default value for this argument is \constant{True}. + +The return value is actually an instance of a subclass of +\pytype{tuple}. This class has the following additional read-only +convenience attributes: + +\begin{tableiv}{l|c|l|c}{member}{Attribute}{Index}{Value}{Value if not present} + \lineiv{scheme} {0} {URL scheme specifier} {empty string} + \lineiv{netloc} {1} {Network location part} {empty string} + \lineiv{path} {2} {Hierarchical path} {empty string} + \lineiv{params} {3} {Parameters for last path element} {empty string} + \lineiv{query} {4} {Query component} {empty string} + \lineiv{fragment}{5} {Fragment identifier} {empty string} + \lineiv{username}{ } {User name} {\constant{None}} + \lineiv{password}{ } {Password} {\constant{None}} + \lineiv{hostname}{ } {Host name (lower case)} {\constant{None}} + \lineiv{port} { } {Port number as integer, if present} {\constant{None}} +\end{tableiv} + +See section~\ref{urlparse-result-object}, ``Results of +\function{urlparse()} and \function{urlsplit()},'' for more +information on the result object. + +\versionchanged[Added attributes to return value]{2.5} +\end{funcdesc} + +\begin{funcdesc}{urlunparse}{parts} +Construct a URL from a tuple as returned by \code{urlparse()}. +The \var{parts} argument can be any six-item iterable. +This may result in a slightly different, but equivalent URL, if the +URL that was parsed originally had unnecessary delimiters (for example, +a ? with an empty query; the RFC states that these are equivalent). +\end{funcdesc} + +\begin{funcdesc}{urlsplit}{urlstring\optional{, + default_scheme\optional{, allow_fragments}}} +This is similar to \function{urlparse()}, but does not split the +params from the URL. This should generally be used instead of +\function{urlparse()} if the more recent URL syntax allowing +parameters to be applied to each segment of the \var{path} portion of +the URL (see \rfc{2396}) is wanted. A separate function is needed to +separate the path segments and parameters. This function returns a +5-tuple: (addressing scheme, network location, path, query, fragment +identifier). + +The return value is actually an instance of a subclass of +\pytype{tuple}. This class has the following additional read-only +convenience attributes: + +\begin{tableiv}{l|c|l|c}{member}{Attribute}{Index}{Value}{Value if not present} + \lineiv{scheme} {0} {URL scheme specifier} {empty string} + \lineiv{netloc} {1} {Network location part} {empty string} + \lineiv{path} {2} {Hierarchical path} {empty string} + \lineiv{query} {3} {Query component} {empty string} + \lineiv{fragment} {4} {Fragment identifier} {empty string} + \lineiv{username} { } {User name} {\constant{None}} + \lineiv{password} { } {Password} {\constant{None}} + \lineiv{hostname} { } {Host name (lower case)} {\constant{None}} + \lineiv{port} { } {Port number as integer, if present} {\constant{None}} +\end{tableiv} + +See section~\ref{urlparse-result-object}, ``Results of +\function{urlparse()} and \function{urlsplit()},'' for more +information on the result object. + +\versionadded{2.2} +\versionchanged[Added attributes to return value]{2.5} +\end{funcdesc} + +\begin{funcdesc}{urlunsplit}{parts} +Combine the elements of a tuple as returned by \function{urlsplit()} +into a complete URL as a string. +The \var{parts} argument can be any five-item iterable. +This may result in a slightly different, but equivalent URL, if the +URL that was parsed originally had unnecessary delimiters (for example, +a ? with an empty query; the RFC states that these are equivalent). +\versionadded{2.2} +\end{funcdesc} + +\begin{funcdesc}{urljoin}{base, url\optional{, allow_fragments}} +Construct a full (``absolute'') URL by combining a ``base URL'' +(\var{base}) with another URL (\var{url}). Informally, this +uses components of the base URL, in particular the addressing scheme, +the network location and (part of) the path, to provide missing +components in the relative URL. For example: + +\begin{verbatim} +>>> from urlparse import urljoin +>>> urljoin('http://www.cwi.nl/%7Eguido/Python.html', 'FAQ.html') +'http://www.cwi.nl/%7Eguido/FAQ.html' +\end{verbatim} + +The \var{allow_fragments} argument has the same meaning and default as +for \function{urlparse()}. + +\note{If \var{url} is an absolute URL (that is, starting with \code{//} + or \code{scheme://}, the \var{url}'s host name and/or scheme + will be present in the result. For example:} + +\begin{verbatim} +>>> urljoin('http://www.cwi.nl/%7Eguido/Python.html', +... '//www.python.org/%7Eguido') +'http://www.python.org/%7Eguido' +\end{verbatim} + +If you do not want that behavior, preprocess +the \var{url} with \function{urlsplit()} and \function{urlunsplit()}, +removing possible \emph{scheme} and \emph{netloc} parts. +\end{funcdesc} + +\begin{funcdesc}{urldefrag}{url} +If \var{url} contains a fragment identifier, returns a modified +version of \var{url} with no fragment identifier, and the fragment +identifier as a separate string. If there is no fragment identifier +in \var{url}, returns \var{url} unmodified and an empty string. +\end{funcdesc} + + +\begin{seealso} + \seerfc{1738}{Uniform Resource Locators (URL)}{ + This specifies the formal syntax and semantics of absolute + URLs.} + \seerfc{1808}{Relative Uniform Resource Locators}{ + This Request For Comments includes the rules for joining an + absolute and a relative URL, including a fair number of + ``Abnormal Examples'' which govern the treatment of border + cases.} + \seerfc{2396}{Uniform Resource Identifiers (URI): Generic Syntax}{ + Document describing the generic syntactic requirements for + both Uniform Resource Names (URNs) and Uniform Resource + Locators (URLs).} +\end{seealso} + + +\subsection{Results of \function{urlparse()} and \function{urlsplit()} + \label{urlparse-result-object}} + +The result objects from the \function{urlparse()} and +\function{urlsplit()} functions are subclasses of the \pytype{tuple} +type. These subclasses add the attributes described in those +functions, as well as provide an additional method: + +\begin{methoddesc}[ParseResult]{geturl}{} + Return the re-combined version of the original URL as a string. + This may differ from the original URL in that the scheme will always + be normalized to lower case and empty components may be dropped. + Specifically, empty parameters, queries, and fragment identifiers + will be removed. + + The result of this method is a fixpoint if passed back through the + original parsing function: + +\begin{verbatim} +>>> import urlparse +>>> url = 'HTTP://www.Python.org/doc/#' + +>>> r1 = urlparse.urlsplit(url) +>>> r1.geturl() +'http://www.Python.org/doc/' + +>>> r2 = urlparse.urlsplit(r1.geturl()) +>>> r2.geturl() +'http://www.Python.org/doc/' +\end{verbatim} + +\versionadded{2.5} +\end{methoddesc} + +The following classes provide the implementations of the parse results:: + +\begin{classdesc*}{BaseResult} + Base class for the concrete result classes. This provides most of + the attribute definitions. It does not provide a \method{geturl()} + method. It is derived from \class{tuple}, but does not override the + \method{__init__()} or \method{__new__()} methods. +\end{classdesc*} + + +\begin{classdesc}{ParseResult}{scheme, netloc, path, params, query, fragment} + Concrete class for \function{urlparse()} results. The + \method{__new__()} method is overridden to support checking that the + right number of arguments are passed. +\end{classdesc} + + +\begin{classdesc}{SplitResult}{scheme, netloc, path, query, fragment} + Concrete class for \function{urlsplit()} results. The + \method{__new__()} method is overridden to support checking that the + right number of arguments are passed. +\end{classdesc} diff --git a/sys/src/cmd/python/Doc/lib/libuser.tex b/sys/src/cmd/python/Doc/lib/libuser.tex new file mode 100644 index 000000000..4e915a22c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libuser.tex @@ -0,0 +1,71 @@ +\section{\module{user} --- + User-specific configuration hook} + +\declaremodule{standard}{user} +\modulesynopsis{A standard way to reference user-specific modules.} + + +\indexii{.pythonrc.py}{file} +\indexiii{user}{configuration}{file} + +As a policy, Python doesn't run user-specified code on startup of +Python programs. (Only interactive sessions execute the script +specified in the \envvar{PYTHONSTARTUP} environment variable if it +exists). + +However, some programs or sites may find it convenient to allow users +to have a standard customization file, which gets run when a program +requests it. This module implements such a mechanism. A program +that wishes to use the mechanism must execute the statement + +\begin{verbatim} +import user +\end{verbatim} + +The \module{user} module looks for a file \file{.pythonrc.py} in the user's +home directory and if it can be opened, executes it (using +\function{execfile()}\bifuncindex{execfile}) in its own (the +module \module{user}'s) global namespace. Errors during this phase +are not caught; that's up to the program that imports the +\module{user} module, if it wishes. The home directory is assumed to +be named by the \envvar{HOME} environment variable; if this is not set, +the current directory is used. + +The user's \file{.pythonrc.py} could conceivably test for +\code{sys.version} if it wishes to do different things depending on +the Python version. + +A warning to users: be very conservative in what you place in your +\file{.pythonrc.py} file. Since you don't know which programs will +use it, changing the behavior of standard modules or functions is +generally not a good idea. + +A suggestion for programmers who wish to use this mechanism: a simple +way to let users specify options for your package is to have them +define variables in their \file{.pythonrc.py} file that you test in +your module. For example, a module \module{spam} that has a verbosity +level can look for a variable \code{user.spam_verbose}, as follows: + +\begin{verbatim} +import user + +verbose = bool(getattr(user, "spam_verbose", 0)) +\end{verbatim} + +(The three-argument form of \function{getattr()} is used in case +the user has not defined \code{spam_verbose} in their +\file{.pythonrc.py} file.) + +Programs with extensive customization needs are better off reading a +program-specific customization file. + +Programs with security or privacy concerns should \emph{not} import +this module; a user can easily break into a program by placing +arbitrary code in the \file{.pythonrc.py} file. + +Modules for general use should \emph{not} import this module; it may +interfere with the operation of the importing program. + +\begin{seealso} + \seemodule{site}{Site-wide customization mechanism.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libuserdict.tex b/sys/src/cmd/python/Doc/lib/libuserdict.tex new file mode 100644 index 000000000..0bb57c826 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libuserdict.tex @@ -0,0 +1,181 @@ +\section{\module{UserDict} --- + Class wrapper for dictionary objects} + +\declaremodule{standard}{UserDict} +\modulesynopsis{Class wrapper for dictionary objects.} + + +The module defines a mixin, \class{DictMixin}, defining all dictionary +methods for classes that already have a minimum mapping interface. This +greatly simplifies writing classes that need to be substitutable for +dictionaries (such as the shelve module). + +This also module defines a class, \class{UserDict}, that acts as a wrapper +around dictionary objects. The need for this class has been largely +supplanted by the ability to subclass directly from \class{dict} (a feature +that became available starting with Python version 2.2). Prior to the +introduction of \class{dict}, the \class{UserDict} class was used to +create dictionary-like sub-classes that obtained new behaviors by overriding +existing methods or adding new ones. + +The \module{UserDict} module defines the \class{UserDict} class +and \class{DictMixin}: + +\begin{classdesc}{UserDict}{\optional{initialdata}} +Class that simulates a dictionary. The instance's contents are kept +in a regular dictionary, which is accessible via the \member{data} +attribute of \class{UserDict} instances. If \var{initialdata} is +provided, \member{data} is initialized with its contents; note that a +reference to \var{initialdata} will not be kept, allowing it be used +for other purposes. \note{For backward compatibility, instances of +\class{UserDict} are not iterable.} +\end{classdesc} + +\begin{classdesc}{IterableUserDict}{\optional{initialdata}} +Subclass of \class{UserDict} that supports direct iteration (e.g. +\code{for key in myDict}). +\end{classdesc} + +In addition to supporting the methods and operations of mappings (see +section \ref{typesmapping}), \class{UserDict} and +\class{IterableUserDict} instances provide the following attribute: + +\begin{memberdesc}{data} +A real dictionary used to store the contents of the \class{UserDict} +class. +\end{memberdesc} + +\begin{classdesc}{DictMixin}{} +Mixin defining all dictionary methods for classes that already have +a minimum dictionary interface including \method{__getitem__()}, +\method{__setitem__()}, \method{__delitem__()}, and \method{keys()}. + +This mixin should be used as a superclass. Adding each of the +above methods adds progressively more functionality. For instance, +defining all but \method{__delitem__} will preclude only \method{pop} +and \method{popitem} from the full interface. + +In addition to the four base methods, progressively more efficiency +comes with defining \method{__contains__()}, \method{__iter__()}, and +\method{iteritems()}. + +Since the mixin has no knowledge of the subclass constructor, it +does not define \method{__init__()} or \method{copy()}. +\end{classdesc} + + +\section{\module{UserList} --- + Class wrapper for list objects} + +\declaremodule{standard}{UserList} +\modulesynopsis{Class wrapper for list objects.} + + +\note{This module is available for backward compatibility only. If +you are writing code that does not need to work with versions of +Python earlier than Python 2.2, please consider subclassing directly +from the built-in \class{list} type.} + +This module defines a class that acts as a wrapper around +list objects. It is a useful base class for +your own list-like classes, which can inherit from +them and override existing methods or add new ones. In this way one +can add new behaviors to lists. + +The \module{UserList} module defines the \class{UserList} class: + +\begin{classdesc}{UserList}{\optional{list}} +Class that simulates a list. The instance's +contents are kept in a regular list, which is accessible via the +\member{data} attribute of \class{UserList} instances. The instance's +contents are initially set to a copy of \var{list}, defaulting to the +empty list \code{[]}. \var{list} can be either a regular Python list, +or an instance of \class{UserList} (or a subclass). +\end{classdesc} + +In addition to supporting the methods and operations of mutable +sequences (see section \ref{typesseq}), \class{UserList} instances +provide the following attribute: + +\begin{memberdesc}{data} +A real Python list object used to store the contents of the +\class{UserList} class. +\end{memberdesc} + +\strong{Subclassing requirements:} +Subclasses of \class{UserList} are expect to offer a constructor which +can be called with either no arguments or one argument. List +operations which return a new sequence attempt to create an instance +of the actual implementation class. To do so, it assumes that the +constructor can be called with a single parameter, which is a sequence +object used as a data source. + +If a derived class does not wish to comply with this requirement, all +of the special methods supported by this class will need to be +overridden; please consult the sources for information about the +methods which need to be provided in that case. + +\versionchanged[Python versions 1.5.2 and 1.6 also required that the + constructor be callable with no parameters, and offer + a mutable \member{data} attribute. Earlier versions + of Python did not attempt to create instances of the + derived class]{2.0} + + +\section{\module{UserString} --- + Class wrapper for string objects} + +\declaremodule{standard}{UserString} +\modulesynopsis{Class wrapper for string objects.} +\moduleauthor{Peter Funk}{pf@artcom-gmbh.de} +\sectionauthor{Peter Funk}{pf@artcom-gmbh.de} + +\note{This \class{UserString} class from this module is available for +backward compatibility only. If you are writing code that does not +need to work with versions of Python earlier than Python 2.2, please +consider subclassing directly from the built-in \class{str} type +instead of using \class{UserString} (there is no built-in equivalent +to \class{MutableString}).} + +This module defines a class that acts as a wrapper around string +objects. It is a useful base class for your own string-like classes, +which can inherit from them and override existing methods or add new +ones. In this way one can add new behaviors to strings. + +It should be noted that these classes are highly inefficient compared +to real string or Unicode objects; this is especially the case for +\class{MutableString}. + +The \module{UserString} module defines the following classes: + +\begin{classdesc}{UserString}{\optional{sequence}} +Class that simulates a string or a Unicode string +object. The instance's content is kept in a regular string or Unicode +string object, which is accessible via the \member{data} attribute of +\class{UserString} instances. The instance's contents are initially +set to a copy of \var{sequence}. \var{sequence} can be either a +regular Python string or Unicode string, an instance of +\class{UserString} (or a subclass) or an arbitrary sequence which can +be converted into a string using the built-in \function{str()} function. +\end{classdesc} + +\begin{classdesc}{MutableString}{\optional{sequence}} +This class is derived from the \class{UserString} above and redefines +strings to be \emph{mutable}. Mutable strings can't be used as +dictionary keys, because dictionaries require \emph{immutable} objects as +keys. The main intention of this class is to serve as an educational +example for inheritance and necessity to remove (override) the +\method{__hash__()} method in order to trap attempts to use a +mutable object as dictionary key, which would be otherwise very +error prone and hard to track down. +\end{classdesc} + +In addition to supporting the methods and operations of string and +Unicode objects (see section \ref{string-methods}, ``String +Methods''), \class{UserString} instances provide the following +attribute: + +\begin{memberdesc}{data} +A real Python string or Unicode object used to store the content of the +\class{UserString} class. +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/lib/libuu.tex b/sys/src/cmd/python/Doc/lib/libuu.tex new file mode 100644 index 000000000..7e546a0d4 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libuu.tex @@ -0,0 +1,58 @@ +\section{\module{uu} --- + Encode and decode uuencode files} + +\declaremodule{standard}{uu} +\modulesynopsis{Encode and decode files in uuencode format.} +\moduleauthor{Lance Ellinghouse}{} + + +This module encodes and decodes files in uuencode format, allowing +arbitrary binary data to be transferred over ASCII-only connections. +Wherever a file argument is expected, the methods accept a file-like +object. For backwards compatibility, a string containing a pathname +is also accepted, and the corresponding file will be opened for +reading and writing; the pathname \code{'-'} is understood to mean the +standard input or output. However, this interface is deprecated; it's +better for the caller to open the file itself, and be sure that, when +required, the mode is \code{'rb'} or \code{'wb'} on Windows. + +This code was contributed by Lance Ellinghouse, and modified by Jack +Jansen. +\index{Jansen, Jack} +\index{Ellinghouse, Lance} + +The \module{uu} module defines the following functions: + +\begin{funcdesc}{encode}{in_file, out_file\optional{, name\optional{, mode}}} + Uuencode file \var{in_file} into file \var{out_file}. The uuencoded + file will have the header specifying \var{name} and \var{mode} as + the defaults for the results of decoding the file. The default + defaults are taken from \var{in_file}, or \code{'-'} and \code{0666} + respectively. +\end{funcdesc} + +\begin{funcdesc}{decode}{in_file\optional{, out_file\optional{, mode\optional{, quiet}}}} + This call decodes uuencoded file \var{in_file} placing the result on + file \var{out_file}. If \var{out_file} is a pathname, \var{mode} is + used to set the permission bits if the file must be + created. Defaults for \var{out_file} and \var{mode} are taken from + the uuencode header. However, if the file specified in the header + already exists, a \exception{uu.Error} is raised. + + \function{decode()} may print a warning to standard error if the + input was produced by an incorrect uuencoder and Python could + recover from that error. Setting \var{quiet} to a true value + silences this warning. +\end{funcdesc} + +\begin{excclassdesc}{Error}{} + Subclass of \exception{Exception}, this can be raised by + \function{uu.decode()} under various situations, such as described + above, but also including a badly formatted header, or truncated + input file. +\end{excclassdesc} + +\begin{seealso} + \seemodule{binascii}{Support module containing \ASCII-to-binary + and binary-to-\ASCII{} conversions.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libuuid.tex b/sys/src/cmd/python/Doc/lib/libuuid.tex new file mode 100644 index 000000000..5aa9d8cf3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libuuid.tex @@ -0,0 +1,233 @@ +\section{\module{uuid} --- + UUID objects according to RFC 4122} +\declaremodule{builtin}{uuid} +\modulesynopsis{UUID objects (universally unique identifiers) according to RFC 4122} +\moduleauthor{Ka-Ping Yee}{ping@zesty.ca} +\sectionauthor{George Yoshida}{quiver@users.sourceforge.net} + +\versionadded{2.5} + +This module provides immutable \class{UUID} objects (the \class{UUID} class) +and the functions \function{uuid1()}, \function{uuid3()}, +\function{uuid4()}, \function{uuid5()} for generating version 1, 3, 4, +and 5 UUIDs as specified in \rfc{4122}. + +If all you want is a unique ID, you should probably call +\function{uuid1()} or \function{uuid4()}. Note that \function{uuid1()} +may compromise privacy since it creates a UUID containing the computer's +network address. \function{uuid4()} creates a random UUID. + +\begin{classdesc}{UUID}{\optional{hex\optional{, bytes\optional{, +bytes_le\optional{, fields\optional{, int\optional{, version}}}}}}} + +Create a UUID from either a string of 32 hexadecimal digits, +a string of 16 bytes as the \var{bytes} argument, a string of 16 bytes +in little-endian order as the \var{bytes_le} argument, a tuple of six +integers (32-bit \var{time_low}, 16-bit \var{time_mid}, +16-bit \var{time_hi_version}, +8-bit \var{clock_seq_hi_variant}, 8-bit \var{clock_seq_low}, 48-bit \var{node}) +as the \var{fields} argument, or a single 128-bit integer as the \var{int} +argument. When a string of hex digits is given, curly braces, +hyphens, and a URN prefix are all optional. For example, these +expressions all yield the same UUID: + +\begin{verbatim} +UUID('{12345678-1234-5678-1234-567812345678}') +UUID('12345678123456781234567812345678') +UUID('urn:uuid:12345678-1234-5678-1234-567812345678') +UUID(bytes='\x12\x34\x56\x78'*4) +UUID(bytes_le='\x78\x56\x34\x12\x34\x12\x78\x56' + + '\x12\x34\x56\x78\x12\x34\x56\x78') +UUID(fields=(0x12345678, 0x1234, 0x5678, 0x12, 0x34, 0x567812345678)) +UUID(int=0x12345678123456781234567812345678) +\end{verbatim} + +Exactly one of \var{hex}, \var{bytes}, \var{bytes_le}, \var{fields}, +or \var{int} must +be given. The \var{version} argument is optional; if given, the +resulting UUID will have its variant and version number set according to +RFC 4122, overriding bits in the given \var{hex}, \var{bytes}, +\var{bytes_le}, \var{fields}, or \var{int}. + +\end{classdesc} + +\class{UUID} instances have these read-only attributes: + +\begin{memberdesc}{bytes} +The UUID as a 16-byte string (containing the six +integer fields in big-endian byte order). +\end{memberdesc} + +\begin{memberdesc}{bytes_le} +The UUID as a 16-byte string (with \var{time_low}, \var{time_mid}, +and \var{time_hi_version} in little-endian byte order). +\end{memberdesc} + +\begin{memberdesc}{fields} +A tuple of the six integer fields of the UUID, which are also available +as six individual attributes and two derived attributes: + +\begin{tableii}{l|l}{member}{Field}{Meaning} + \lineii{time_low}{the first 32 bits of the UUID} + \lineii{time_mid}{the next 16 bits of the UUID} + \lineii{time_hi_version}{the next 16 bits of the UUID} + \lineii{clock_seq_hi_variant}{the next 8 bits of the UUID} + \lineii{clock_seq_low}{the next 8 bits of the UUID} + \lineii{node}{the last 48 bits of the UUID} + \lineii{time}{the 60-bit timestamp} + \lineii{clock_seq}{the 14-bit sequence number} +\end{tableii} + + +\end{memberdesc} + +\begin{memberdesc}{hex} +The UUID as a 32-character hexadecimal string. +\end{memberdesc} + +\begin{memberdesc}{int} +The UUID as a 128-bit integer. +\end{memberdesc} + +\begin{memberdesc}{urn} +The UUID as a URN as specified in RFC 4122. +\end{memberdesc} + +\begin{memberdesc}{variant} +The UUID variant, which determines the internal layout of the UUID. +This will be one of the integer constants +\constant{RESERVED_NCS}, +\constant{RFC_4122}, \constant{RESERVED_MICROSOFT}, or +\constant{RESERVED_FUTURE}. +\end{memberdesc} + +\begin{memberdesc}{version} +The UUID version number (1 through 5, meaningful only +when the variant is \constant{RFC_4122}). +\end{memberdesc} + +The \module{uuid} module defines the following functions: + +\begin{funcdesc}{getnode}{} +Get the hardware address as a 48-bit positive integer. The first time this +runs, it may launch a separate program, which could be quite slow. If all +attempts to obtain the hardware address fail, we choose a random 48-bit +number with its eighth bit set to 1 as recommended in RFC 4122. "Hardware +address" means the MAC address of a network interface, and on a machine +with multiple network interfaces the MAC address of any one of them may +be returned. +\end{funcdesc} +\index{getnode} + +\begin{funcdesc}{uuid1}{\optional{node\optional{, clock_seq}}} +Generate a UUID from a host ID, sequence number, and the current time. +If \var{node} is not given, \function{getnode()} is used to obtain the +hardware address. +If \var{clock_seq} is given, it is used as the sequence number; +otherwise a random 14-bit sequence number is chosen. +\end{funcdesc} +\index{uuid1} + +\begin{funcdesc}{uuid3}{namespace, name} +Generate a UUID based on the MD5 hash +of a namespace identifier (which is a UUID) and a name (which is a string). +\end{funcdesc} +\index{uuid3} + +\begin{funcdesc}{uuid4}{} +Generate a random UUID. +\end{funcdesc} +\index{uuid4} + +\begin{funcdesc}{uuid5}{namespace, name} +Generate a UUID based on the SHA-1 hash +of a namespace identifier (which is a UUID) and a name (which is a string). +\end{funcdesc} +\index{uuid5} + +The \module{uuid} module defines the following namespace identifiers +for use with \function{uuid3()} or \function{uuid5()}. + +\begin{datadesc}{NAMESPACE_DNS} +When this namespace is specified, +the \var{name} string is a fully-qualified domain name. +\end{datadesc} + +\begin{datadesc}{NAMESPACE_URL} +When this namespace is specified, +the \var{name} string is a URL. +\end{datadesc} + +\begin{datadesc}{NAMESPACE_OID} +When this namespace is specified, +the \var{name} string is an ISO OID. +\end{datadesc} + +\begin{datadesc}{NAMESPACE_X500} +When this namespace is specified, +the \var{name} string is an X.500 DN in DER or a text output format. +\end{datadesc} + +The \module{uuid} module defines the following constants +for the possible values of the \member{variant} attribute: + +\begin{datadesc}{RESERVED_NCS} +Reserved for NCS compatibility. +\end{datadesc} + +\begin{datadesc}{RFC_4122} +Specifies the UUID layout given in \rfc{4122}. +\end{datadesc} + +\begin{datadesc}{RESERVED_MICROSOFT} +Reserved for Microsoft compatibility. +\end{datadesc} + +\begin{datadesc}{RESERVED_FUTURE} +Reserved for future definition. +\end{datadesc} + + +\begin{seealso} + \seerfc{4122}{A Universally Unique IDentifier (UUID) URN Namespace}{ +This specification defines a Uniform Resource Name namespace for UUIDs, +the internal format of UUIDs, and methods of generating UUIDs.} +\end{seealso} + +\subsection{Example \label{uuid-example}} + +Here are some examples of typical usage of the \module{uuid} module: +\begin{verbatim} +>>> import uuid + +# make a UUID based on the host ID and current time +>>> uuid.uuid1() +UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') + +# make a UUID using an MD5 hash of a namespace UUID and a name +>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') +UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') + +# make a random UUID +>>> uuid.uuid4() +UUID('16fd2706-8baf-433b-82eb-8c7fada847da') + +# make a UUID using a SHA-1 hash of a namespace UUID and a name +>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') +UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') + +# make a UUID from a string of hex digits (braces and hyphens ignored) +>>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') + +# convert a UUID to a string of hex digits in standard form +>>> str(x) +'00010203-0405-0607-0809-0a0b0c0d0e0f' + +# get the raw 16 bytes of the UUID +>>> x.bytes +'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' + +# make a UUID from a 16-byte string +>>> uuid.UUID(bytes=x.bytes) +UUID('00010203-0405-0607-0809-0a0b0c0d0e0f') +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libwarnings.tex b/sys/src/cmd/python/Doc/lib/libwarnings.tex new file mode 100644 index 000000000..a37a9f533 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libwarnings.tex @@ -0,0 +1,253 @@ +\section{\module{warnings} --- + Warning control} + +\declaremodule{standard}{warnings} +\modulesynopsis{Issue warning messages and control their disposition.} +\index{warnings} + +\versionadded{2.1} + +Warning messages are typically issued in situations where it is useful +to alert the user of some condition in a program, where that condition +(normally) doesn't warrant raising an exception and terminating the +program. For example, one might want to issue a warning when a +program uses an obsolete module. + +Python programmers issue warnings by calling the \function{warn()} +function defined in this module. (C programmers use +\cfunction{PyErr_Warn()}; see the +\citetitle[../api/exceptionHandling.html]{Python/C API Reference +Manual} for details). + +Warning messages are normally written to \code{sys.stderr}, but their +disposition can be changed flexibly, from ignoring all warnings to +turning them into exceptions. The disposition of warnings can vary +based on the warning category (see below), the text of the warning +message, and the source location where it is issued. Repetitions of a +particular warning for the same source location are typically +suppressed. + +There are two stages in warning control: first, each time a warning is +issued, a determination is made whether a message should be issued or +not; next, if a message is to be issued, it is formatted and printed +using a user-settable hook. + +The determination whether to issue a warning message is controlled by +the warning filter, which is a sequence of matching rules and actions. +Rules can be added to the filter by calling +\function{filterwarnings()} and reset to its default state by calling +\function{resetwarnings()}. + +The printing of warning messages is done by calling +\function{showwarning()}, which may be overridden; the default +implementation of this function formats the message by calling +\function{formatwarning()}, which is also available for use by custom +implementations. + + +\subsection{Warning Categories \label{warning-categories}} + +There are a number of built-in exceptions that represent warning +categories. This categorization is useful to be able to filter out +groups of warnings. The following warnings category classes are +currently defined: + +\begin{tableii}{l|l}{exception}{Class}{Description} + +\lineii{Warning}{This is the base class of all warning category +classes. It is a subclass of \exception{Exception}.} + +\lineii{UserWarning}{The default category for \function{warn()}.} + +\lineii{DeprecationWarning}{Base category for warnings about +deprecated features.} + +\lineii{SyntaxWarning}{Base category for warnings about dubious +syntactic features.} + +\lineii{RuntimeWarning}{Base category for warnings about dubious +runtime features.} + +\lineii{FutureWarning}{Base category for warnings about constructs +that will change semantically in the future.} + +\lineii{PendingDeprecationWarning}{Base category for warnings about +features that will be deprecated in the future (ignored by default).} + +\lineii{ImportWarning}{Base category for warnings triggered during the +process of importing a module (ignored by default).} + +\lineii{UnicodeWarning}{Base category for warnings related to Unicode.} + +\end{tableii} + +While these are technically built-in exceptions, they are documented +here, because conceptually they belong to the warnings mechanism. + +User code can define additional warning categories by subclassing one +of the standard warning categories. A warning category must always be +a subclass of the \exception{Warning} class. + + +\subsection{The Warnings Filter \label{warning-filter}} + +The warnings filter controls whether warnings are ignored, displayed, +or turned into errors (raising an exception). + +Conceptually, the warnings filter maintains an ordered list of filter +specifications; any specific warning is matched against each filter +specification in the list in turn until a match is found; the match +determines the disposition of the match. Each entry is a tuple of the +form (\var{action}, \var{message}, \var{category}, \var{module}, +\var{lineno}), where: + +\begin{itemize} + +\item \var{action} is one of the following strings: + + \begin{tableii}{l|l}{code}{Value}{Disposition} + + \lineii{"error"}{turn matching warnings into exceptions} + + \lineii{"ignore"}{never print matching warnings} + + \lineii{"always"}{always print matching warnings} + + \lineii{"default"}{print the first occurrence of matching + warnings for each location where the warning is issued} + + \lineii{"module"}{print the first occurrence of matching + warnings for each module where the warning is issued} + + \lineii{"once"}{print only the first occurrence of matching + warnings, regardless of location} + + \end{tableii} + +\item \var{message} is a string containing a regular expression that +the warning message must match (the match is compiled to always be +case-insensitive) + +\item \var{category} is a class (a subclass of \exception{Warning}) of + which the warning category must be a subclass in order to match + +\item \var{module} is a string containing a regular expression that the module + name must match (the match is compiled to be case-sensitive) + +\item \var{lineno} is an integer that the line number where the + warning occurred must match, or \code{0} to match all line + numbers + +\end{itemize} + +Since the \exception{Warning} class is derived from the built-in +\exception{Exception} class, to turn a warning into an error we simply +raise \code{category(message)}. + +The warnings filter is initialized by \programopt{-W} options passed +to the Python interpreter command line. The interpreter saves the +arguments for all \programopt{-W} options without interpretation in +\code{sys.warnoptions}; the \module{warnings} module parses these when +it is first imported (invalid options are ignored, after printing a +message to \code{sys.stderr}). + +The warnings that are ignored by default may be enabled by passing + \programopt{-Wd} to the interpreter. This enables default handling +for all warnings, including those that are normally ignored by +default. This is particular useful for enabling ImportWarning when +debugging problems importing a developed package. ImportWarning can +also be enabled explicitly in Python code using: + +\begin{verbatim} + warnings.simplefilter('default', ImportWarning) +\end{verbatim} + + +\subsection{Available Functions \label{warning-functions}} + +\begin{funcdesc}{warn}{message\optional{, category\optional{, stacklevel}}} +Issue a warning, or maybe ignore it or raise an exception. The +\var{category} argument, if given, must be a warning category class +(see above); it defaults to \exception{UserWarning}. Alternatively +\var{message} can be a \exception{Warning} instance, in which case +\var{category} will be ignored and \code{message.__class__} will be used. +In this case the message text will be \code{str(message)}. This function +raises an exception if the particular warning issued is changed +into an error by the warnings filter see above. The \var{stacklevel} +argument can be used by wrapper functions written in Python, like +this: + +\begin{verbatim} +def deprecation(message): + warnings.warn(message, DeprecationWarning, stacklevel=2) +\end{verbatim} + +This makes the warning refer to \function{deprecation()}'s caller, +rather than to the source of \function{deprecation()} itself (since +the latter would defeat the purpose of the warning message). +\end{funcdesc} + +\begin{funcdesc}{warn_explicit}{message, category, filename, + lineno\optional{, module\optional{, registry\optional{, + module_globals}}}} +This is a low-level interface to the functionality of +\function{warn()}, passing in explicitly the message, category, +filename and line number, and optionally the module name and the +registry (which should be the \code{__warningregistry__} dictionary of +the module). The module name defaults to the filename with \code{.py} +stripped; if no registry is passed, the warning is never suppressed. +\var{message} must be a string and \var{category} a subclass of +\exception{Warning} or \var{message} may be a \exception{Warning} instance, +in which case \var{category} will be ignored. + +\var{module_globals}, if supplied, should be the global namespace in use +by the code for which the warning is issued. (This argument is used to +support displaying source for modules found in zipfiles or other +non-filesystem import sources, and was added in Python 2.5.) +\end{funcdesc} + +\begin{funcdesc}{showwarning}{message, category, filename, + lineno\optional{, file}} +Write a warning to a file. The default implementation calls +\code{formatwarning(\var{message}, \var{category}, \var{filename}, +\var{lineno})} and writes the resulting string to \var{file}, which +defaults to \code{sys.stderr}. You may replace this function with an +alternative implementation by assigning to +\code{warnings.showwarning}. +\end{funcdesc} + +\begin{funcdesc}{formatwarning}{message, category, filename, lineno} +Format a warning the standard way. This returns a string which may +contain embedded newlines and ends in a newline. +\end{funcdesc} + +\begin{funcdesc}{filterwarnings}{action\optional{, + message\optional{, category\optional{, + module\optional{, lineno\optional{, append}}}}}} +Insert an entry into the list of warnings filters. The entry is +inserted at the front by default; if \var{append} is true, it is +inserted at the end. +This checks the types of the arguments, compiles the message and +module regular expressions, and inserts them as a tuple in the +list of warnings filters. Entries closer to the front of the list +override entries later in the list, if both match a particular +warning. Omitted arguments default to a value that matches +everything. +\end{funcdesc} + +\begin{funcdesc}{simplefilter}{action\optional{, + category\optional{, + lineno\optional{, append}}}} +Insert a simple entry into the list of warnings filters. The meaning +of the function parameters is as for \function{filterwarnings()}, but +regular expressions are not needed as the filter inserted always +matches any message in any module as long as the category and line +number match. +\end{funcdesc} + +\begin{funcdesc}{resetwarnings}{} +Reset the warnings filter. This discards the effect of all previous +calls to \function{filterwarnings()}, including that of the +\programopt{-W} command line options and calls to +\function{simplefilter()}. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libwave.tex b/sys/src/cmd/python/Doc/lib/libwave.tex new file mode 100644 index 000000000..c0f300bc6 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libwave.tex @@ -0,0 +1,169 @@ +% Documentations stolen and LaTeX'ed from comments in file. +\section{\module{wave} --- + Read and write WAV files} + +\declaremodule{standard}{wave} +\sectionauthor{Moshe Zadka}{moshez@zadka.site.co.il} +\modulesynopsis{Provide an interface to the WAV sound format.} + +The \module{wave} module provides a convenient interface to the WAV sound +format. It does not support compression/decompression, but it does support +mono/stereo. + +The \module{wave} module defines the following function and exception: + +\begin{funcdesc}{open}{file\optional{, mode}} +If \var{file} is a string, open the file by that name, other treat it +as a seekable file-like object. \var{mode} can be any of +\begin{description} + \item[\code{'r'}, \code{'rb'}] Read only mode. + \item[\code{'w'}, \code{'wb'}] Write only mode. +\end{description} +Note that it does not allow read/write WAV files. + +A \var{mode} of \code{'r'} or \code{'rb'} returns a \class{Wave_read} +object, while a \var{mode} of \code{'w'} or \code{'wb'} returns +a \class{Wave_write} object. If \var{mode} is omitted and a file-like +object is passed as \var{file}, \code{\var{file}.mode} is used as the +default value for \var{mode} (the \character{b} flag is still added if +necessary). +\end{funcdesc} + +\begin{funcdesc}{openfp}{file, mode} +A synonym for \function{open()}, maintained for backwards compatibility. +\end{funcdesc} + +\begin{excdesc}{Error} +An error raised when something is impossible because it violates the +WAV specification or hits an implementation deficiency. +\end{excdesc} + + +\subsection{Wave_read Objects \label{Wave-read-objects}} + +Wave_read objects, as returned by \function{open()}, have the +following methods: + +\begin{methoddesc}[Wave_read]{close}{} +Close the stream, and make the instance unusable. This is +called automatically on object collection. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getnchannels}{} +Returns number of audio channels (\code{1} for mono, \code{2} for +stereo). +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getsampwidth}{} +Returns sample width in bytes. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getframerate}{} +Returns sampling frequency. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getnframes}{} +Returns number of audio frames. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getcomptype}{} +Returns compression type (\code{'NONE'} is the only supported type). +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getcompname}{} +Human-readable version of \method{getcomptype()}. +Usually \code{'not compressed'} parallels \code{'NONE'}. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getparams}{} +Returns a tuple +\code{(\var{nchannels}, \var{sampwidth}, \var{framerate}, +\var{nframes}, \var{comptype}, \var{compname})}, equivalent to output +of the \method{get*()} methods. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{readframes}{n} +Reads and returns at most \var{n} frames of audio, as a string of bytes. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{rewind}{} +Rewind the file pointer to the beginning of the audio stream. +\end{methoddesc} + +The following two methods are defined for compatibility with the +\refmodule{aifc} module, and don't do anything interesting. + +\begin{methoddesc}[Wave_read]{getmarkers}{} +Returns \code{None}. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{getmark}{id} +Raise an error. +\end{methoddesc} + +The following two methods define a term ``position'' which is compatible +between them, and is otherwise implementation dependent. + +\begin{methoddesc}[Wave_read]{setpos}{pos} +Set the file pointer to the specified position. +\end{methoddesc} + +\begin{methoddesc}[Wave_read]{tell}{} +Return current file pointer position. +\end{methoddesc} + + +\subsection{Wave_write Objects \label{Wave-write-objects}} + +Wave_write objects, as returned by \function{open()}, have the +following methods: + +\begin{methoddesc}[Wave_write]{close}{} +Make sure \var{nframes} is correct, and close the file. +This method is called upon deletion. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{setnchannels}{n} +Set the number of channels. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{setsampwidth}{n} +Set the sample width to \var{n} bytes. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{setframerate}{n} +Set the frame rate to \var{n}. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{setnframes}{n} +Set the number of frames to \var{n}. This will be changed later if +more frames are written. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{setcomptype}{type, name} +Set the compression type and description. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{setparams}{tuple} +The \var{tuple} should be \code{(\var{nchannels}, \var{sampwidth}, +\var{framerate}, \var{nframes}, \var{comptype}, \var{compname})}, with +values valid for the \method{set*()} methods. Sets all parameters. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{tell}{} +Return current position in the file, with the same disclaimer for +the \method{Wave_read.tell()} and \method{Wave_read.setpos()} +methods. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{writeframesraw}{data} +Write audio frames, without correcting \var{nframes}. +\end{methoddesc} + +\begin{methoddesc}[Wave_write]{writeframes}{data} +Write audio frames and make sure \var{nframes} is correct. +\end{methoddesc} + +Note that it is invalid to set any parameters after calling +\method{writeframes()} or \method{writeframesraw()}, and any attempt +to do so will raise \exception{wave.Error}. diff --git a/sys/src/cmd/python/Doc/lib/libweakref.tex b/sys/src/cmd/python/Doc/lib/libweakref.tex new file mode 100644 index 000000000..6f676a287 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libweakref.tex @@ -0,0 +1,336 @@ +\section{\module{weakref} --- + Weak references} + +\declaremodule{extension}{weakref} +\modulesynopsis{Support for weak references and weak dictionaries.} +\moduleauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +\moduleauthor{Neil Schemenauer}{nas@arctrix.com} +\moduleauthor{Martin von L\"owis}{martin@loewis.home.cs.tu-berlin.de} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +\versionadded{2.1} + +% When making changes to the examples in this file, be sure to update +% Lib/test/test_weakref.py::libreftest too! + +The \module{weakref} module allows the Python programmer to create +\dfn{weak references} to objects. + +In the following, the term \dfn{referent} means the +object which is referred to by a weak reference. + +A weak reference to an object is not enough to keep the object alive: +when the only remaining references to a referent are weak references, +garbage collection is free to destroy the referent and reuse its memory +for something else. A primary use for weak references is to implement +caches or mappings holding large objects, where it's desired that a +large object not be kept alive solely because it appears in a cache or +mapping. For example, if you have a number of large binary image objects, +you may wish to associate a name with each. If you used a Python +dictionary to map names to images, or images to names, the image objects +would remain alive just because they appeared as values or keys in the +dictionaries. The \class{WeakKeyDictionary} and +\class{WeakValueDictionary} classes supplied by the \module{weakref} +module are an alternative, using weak references to construct mappings +that don't keep objects alive solely because they appear in the mapping +objects. If, for example, an image object is a value in a +\class{WeakValueDictionary}, then when the last remaining +references to that image object are the weak references held by weak +mappings, garbage collection can reclaim the object, and its corresponding +entries in weak mappings are simply deleted. + +\class{WeakKeyDictionary} and \class{WeakValueDictionary} use weak +references in their implementation, setting up callback functions on +the weak references that notify the weak dictionaries when a key or value +has been reclaimed by garbage collection. Most programs should find that +using one of these weak dictionary types is all they need -- it's +not usually necessary to create your own weak references directly. The +low-level machinery used by the weak dictionary implementations is exposed +by the \module{weakref} module for the benefit of advanced uses. + +Not all objects can be weakly referenced; those objects which can +include class instances, functions written in Python (but not in C), +methods (both bound and unbound), sets, frozensets, file objects, +generators, type objects, DBcursor objects from the \module{bsddb} module, +sockets, arrays, deques, and regular expression pattern objects. +\versionchanged[Added support for files, sockets, arrays, and patterns]{2.4} + +Several builtin types such as \class{list} and \class{dict} do not +directly support weak references but can add support through subclassing: + +\begin{verbatim} +class Dict(dict): + pass + +obj = Dict(red=1, green=2, blue=3) # this object is weak referencable +\end{verbatim} + +Extension types can easily be made to support weak references; see +``\ulink{Weak Reference Support}{../ext/weakref-support.html}'' in +\citetitle[../ext/ext.html]{Extending and Embedding the Python +Interpreter}. +% The referenced section used to appear in this document with the +% \label weakref-extension. It would be good to be able to generate a +% redirect for the corresponding HTML page (weakref-extension.html) +% for on-line versions of this document. + +\begin{classdesc}{ref}{object\optional{, callback}} + Return a weak reference to \var{object}. The original object can be + retrieved by calling the reference object if the referent is still + alive; if the referent is no longer alive, calling the reference + object will cause \constant{None} to be returned. If \var{callback} is + provided and not \constant{None}, and the returned weakref object is + still alive, the callback will be called when the object is about to be + finalized; the weak reference object will be passed as the only + parameter to the callback; the referent will no longer be available. + + It is allowable for many weak references to be constructed for the + same object. Callbacks registered for each weak reference will be + called from the most recently registered callback to the oldest + registered callback. + + Exceptions raised by the callback will be noted on the standard + error output, but cannot be propagated; they are handled in exactly + the same way as exceptions raised from an object's + \method{__del__()} method. + + Weak references are hashable if the \var{object} is hashable. They + will maintain their hash value even after the \var{object} was + deleted. If \function{hash()} is called the first time only after + the \var{object} was deleted, the call will raise + \exception{TypeError}. + + Weak references support tests for equality, but not ordering. If + the referents are still alive, two references have the same + equality relationship as their referents (regardless of the + \var{callback}). If either referent has been deleted, the + references are equal only if the reference objects are the same + object. + + \versionchanged[This is now a subclassable type rather than a + factory function; it derives from \class{object}] + {2.4} +\end{classdesc} + +\begin{funcdesc}{proxy}{object\optional{, callback}} + Return a proxy to \var{object} which uses a weak reference. This + supports use of the proxy in most contexts instead of requiring the + explicit dereferencing used with weak reference objects. The + returned object will have a type of either \code{ProxyType} or + \code{CallableProxyType}, depending on whether \var{object} is + callable. Proxy objects are not hashable regardless of the + referent; this avoids a number of problems related to their + fundamentally mutable nature, and prevent their use as dictionary + keys. \var{callback} is the same as the parameter of the same name + to the \function{ref()} function. +\end{funcdesc} + +\begin{funcdesc}{getweakrefcount}{object} + Return the number of weak references and proxies which refer to + \var{object}. +\end{funcdesc} + +\begin{funcdesc}{getweakrefs}{object} + Return a list of all weak reference and proxy objects which refer to + \var{object}. +\end{funcdesc} + +\begin{classdesc}{WeakKeyDictionary}{\optional{dict}} + Mapping class that references keys weakly. Entries in the + dictionary will be discarded when there is no longer a strong + reference to the key. This can be used to associate additional data + with an object owned by other parts of an application without adding + attributes to those objects. This can be especially useful with + objects that override attribute accesses. + + \note{Caution: Because a \class{WeakKeyDictionary} is built on top + of a Python dictionary, it must not change size when iterating + over it. This can be difficult to ensure for a + \class{WeakKeyDictionary} because actions performed by the + program during iteration may cause items in the dictionary + to vanish "by magic" (as a side effect of garbage collection).} +\end{classdesc} + +\class{WeakKeyDictionary} objects have the following additional +methods. These expose the internal references directly. The +references are not guaranteed to be ``live'' at the time they are +used, so the result of calling the references needs to be checked +before being used. This can be used to avoid creating references that +will cause the garbage collector to keep the keys around longer than +needed. + +\begin{methoddesc}{iterkeyrefs}{} + Return an iterator that yields the weak references to the keys. + \versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}{keyrefs}{} + Return a list of weak references to the keys. + \versionadded{2.5} +\end{methoddesc} + +\begin{classdesc}{WeakValueDictionary}{\optional{dict}} + Mapping class that references values weakly. Entries in the + dictionary will be discarded when no strong reference to the value + exists any more. + + \note{Caution: Because a \class{WeakValueDictionary} is built on top + of a Python dictionary, it must not change size when iterating + over it. This can be difficult to ensure for a + \class{WeakValueDictionary} because actions performed by the + program during iteration may cause items in the dictionary + to vanish "by magic" (as a side effect of garbage collection).} +\end{classdesc} + +\class{WeakValueDictionary} objects have the following additional +methods. These method have the same issues as the +\method{iterkeyrefs()} and \method{keyrefs()} methods of +\class{WeakKeyDictionary} objects. + +\begin{methoddesc}{itervaluerefs}{} + Return an iterator that yields the weak references to the values. + \versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}{valuerefs}{} + Return a list of weak references to the values. + \versionadded{2.5} +\end{methoddesc} + +\begin{datadesc}{ReferenceType} + The type object for weak references objects. +\end{datadesc} + +\begin{datadesc}{ProxyType} + The type object for proxies of objects which are not callable. +\end{datadesc} + +\begin{datadesc}{CallableProxyType} + The type object for proxies of callable objects. +\end{datadesc} + +\begin{datadesc}{ProxyTypes} + Sequence containing all the type objects for proxies. This can make + it simpler to test if an object is a proxy without being dependent + on naming both proxy types. +\end{datadesc} + +\begin{excdesc}{ReferenceError} + Exception raised when a proxy object is used but the underlying + object has been collected. This is the same as the standard + \exception{ReferenceError} exception. +\end{excdesc} + + +\begin{seealso} + \seepep{0205}{Weak References}{The proposal and rationale for this + feature, including links to earlier implementations + and information about similar features in other + languages.} +\end{seealso} + + +\subsection{Weak Reference Objects + \label{weakref-objects}} + +Weak reference objects have no attributes or methods, but do allow the +referent to be obtained, if it still exists, by calling it: + +\begin{verbatim} +>>> import weakref +>>> class Object: +... pass +... +>>> o = Object() +>>> r = weakref.ref(o) +>>> o2 = r() +>>> o is o2 +True +\end{verbatim} + +If the referent no longer exists, calling the reference object returns +\constant{None}: + +\begin{verbatim} +>>> del o, o2 +>>> print r() +None +\end{verbatim} + +Testing that a weak reference object is still live should be done +using the expression \code{\var{ref}() is not None}. Normally, +application code that needs to use a reference object should follow +this pattern: + +\begin{verbatim} +# r is a weak reference object +o = r() +if o is None: + # referent has been garbage collected + print "Object has been deallocated; can't frobnicate." +else: + print "Object is still live!" + o.do_something_useful() +\end{verbatim} + +Using a separate test for ``liveness'' creates race conditions in +threaded applications; another thread can cause a weak reference to +become invalidated before the weak reference is called; the +idiom shown above is safe in threaded applications as well as +single-threaded applications. + +Specialized versions of \class{ref} objects can be created through +subclassing. This is used in the implementation of the +\class{WeakValueDictionary} to reduce the memory overhead for each +entry in the mapping. This may be most useful to associate additional +information with a reference, but could also be used to insert +additional processing on calls to retrieve the referent. + +This example shows how a subclass of \class{ref} can be used to store +additional information about an object and affect the value that's +returned when the referent is accessed: + +\begin{verbatim} +import weakref + +class ExtendedRef(weakref.ref): + def __init__(self, ob, callback=None, **annotations): + super(ExtendedRef, self).__init__(ob, callback) + self.__counter = 0 + for k, v in annotations.iteritems(): + setattr(self, k, v) + + def __call__(self): + """Return a pair containing the referent and the number of + times the reference has been called. + """ + ob = super(ExtendedRef, self).__call__() + if ob is not None: + self.__counter += 1 + ob = (ob, self.__counter) + return ob +\end{verbatim} + + +\subsection{Example \label{weakref-example}} + +This simple example shows how an application can use objects IDs to +retrieve objects that it has seen before. The IDs of the objects can +then be used in other data structures without forcing the objects to +remain alive, but the objects can still be retrieved by ID if they +do. + +% Example contributed by Tim Peters. +\begin{verbatim} +import weakref + +_id2obj_dict = weakref.WeakValueDictionary() + +def remember(obj): + oid = id(obj) + _id2obj_dict[oid] = obj + return oid + +def id2obj(oid): + return _id2obj_dict[oid] +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libwebbrowser.tex b/sys/src/cmd/python/Doc/lib/libwebbrowser.tex new file mode 100644 index 000000000..11d77a124 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libwebbrowser.tex @@ -0,0 +1,173 @@ +\section{\module{webbrowser} --- + Convenient Web-browser controller} + +\declaremodule{standard}{webbrowser} +\modulesynopsis{Easy-to-use controller for Web browsers.} +\moduleauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +The \module{webbrowser} module provides a high-level interface to +allow displaying Web-based documents to users. Under most +circumstances, simply calling the \function{open()} function from this +module will do the right thing. + +Under \UNIX{}, graphical browsers are preferred under X11, but text-mode +browsers will be used if graphical browsers are not available or an X11 +display isn't available. If text-mode browsers are used, the calling +process will block until the user exits the browser. + +If the environment variable \envvar{BROWSER} exists, it +is interpreted to override the platform default list of browsers, as a +os.pathsep-separated list of browsers to try in order. When the value of +a list part contains the string \code{\%s}, then it is +interpreted as a literal browser command line to be used with the argument URL +substituted for \code{\%s}; if the part does not contain +\code{\%s}, it is simply interpreted as the name of the browser to +launch. + +For non-\UNIX{} platforms, or when a remote browser is available on +\UNIX{}, the controlling process will not wait for the user to finish +with the browser, but allow the remote browser to maintain its own +windows on the display. If remote browsers are not available on \UNIX{}, +the controlling process will launch a new browser and wait. + +The script \program{webbrowser} can be used as a command-line interface +for the module. It accepts an URL as the argument. It accepts the following +optional parameters: \programopt{-n} opens the URL in a new browser window, +if possible; \programopt{-t} opens the URL in a new browser page ("tab"). The +options are, naturally, mutually exclusive. + +The following exception is defined: + +\begin{excdesc}{Error} + Exception raised when a browser control error occurs. +\end{excdesc} + +The following functions are defined: + +\begin{funcdesc}{open}{url\optional{, new=0\optional{, autoraise=1}}} + Display \var{url} using the default browser. If \var{new} is 0, the + \var{url} is opened in the same browser window. If \var{new} is 1, + a new browser window is opened if possible. If \var{new} is 2, + a new browser page ("tab") is opened if possible. If \var{autoraise} is + true, the window is raised if possible (note that under many window + managers this will occur regardless of the setting of this variable). +\versionchanged[\var{new} can now be 2]{2.5} +\end{funcdesc} + +\begin{funcdesc}{open_new}{url} + Open \var{url} in a new window of the default browser, if possible, + otherwise, open \var{url} in the only browser window. +\end{funcdesc} + +\begin{funcdesc}{open_new_tab}{url} + Open \var{url} in a new page ("tab") of the default browser, if possible, + otherwise equivalent to \function{open_new}. +\versionadded{2.5} +\end{funcdesc} + +\begin{funcdesc}{get}{\optional{name}} + Return a controller object for the browser type \var{name}. If + \var{name} is empty, return a controller for a default browser + appropriate to the caller's environment. +\end{funcdesc} + +\begin{funcdesc}{register}{name, constructor\optional{, instance}} + Register the browser type \var{name}. Once a browser type is + registered, the \function{get()} function can return a controller + for that browser type. If \var{instance} is not provided, or is + \code{None}, \var{constructor} will be called without parameters to + create an instance when needed. If \var{instance} is provided, + \var{constructor} will never be called, and may be \code{None}. + + This entry point is only useful if you plan to either set the + \envvar{BROWSER} variable or call \function{get} with a nonempty + argument matching the name of a handler you declare. +\end{funcdesc} + +A number of browser types are predefined. This table gives the type +names that may be passed to the \function{get()} function and the +corresponding instantiations for the controller classes, all defined +in this module. + +\begin{tableiii}{l|l|c}{code}{Type Name}{Class Name}{Notes} + \lineiii{'mozilla'}{\class{Mozilla('mozilla')}}{} + \lineiii{'firefox'}{\class{Mozilla('mozilla')}}{} + \lineiii{'netscape'}{\class{Mozilla('netscape')}}{} + \lineiii{'galeon'}{\class{Galeon('galeon')}}{} + \lineiii{'epiphany'}{\class{Galeon('epiphany')}}{} + \lineiii{'skipstone'}{\class{BackgroundBrowser('skipstone')}}{} + \lineiii{'kfmclient'}{\class{Konqueror()}}{(1)} + \lineiii{'konqueror'}{\class{Konqueror()}}{(1)} + \lineiii{'kfm'}{\class{Konqueror()}}{(1)} + \lineiii{'mosaic'}{\class{BackgroundBrowser('mosaic')}}{} + \lineiii{'opera'}{\class{Opera()}}{} + \lineiii{'grail'}{\class{Grail()}}{} + \lineiii{'links'}{\class{GenericBrowser('links')}}{} + \lineiii{'elinks'}{\class{Elinks('elinks')}}{} + \lineiii{'lynx'}{\class{GenericBrowser('lynx')}}{} + \lineiii{'w3m'}{\class{GenericBrowser('w3m')}}{} + \lineiii{'windows-default'}{\class{WindowsDefault}}{(2)} + \lineiii{'internet-config'}{\class{InternetConfig}}{(3)} + \lineiii{'macosx'}{\class{MacOSX('default')}}{(4)} +\end{tableiii} + +\noindent +Notes: + +\begin{description} +\item[(1)] +``Konqueror'' is the file manager for the KDE desktop environment for +\UNIX{}, and only makes sense to use if KDE is running. Some way of +reliably detecting KDE would be nice; the \envvar{KDEDIR} variable is +not sufficient. Note also that the name ``kfm'' is used even when +using the \program{konqueror} command with KDE 2 --- the +implementation selects the best strategy for running Konqueror. + +\item[(2)] +Only on Windows platforms. + +\item[(3)] +Only on MacOS platforms; requires the standard MacPython \module{ic} +module, described in the \citetitle[../mac/module-ic.html]{Macintosh +Library Modules} manual. + +\item[(4)] +Only on MacOS X platform. +\end{description} + +Here are some simple examples: + +\begin{verbatim} +url = 'http://www.python.org' + +# Open URL in a new tab, if a browser window is already open. +webbrowser.open_new_tab(url + '/doc') + +# Open URL in new window, raising the window if possible. +webbrowser.open_new(url) +\end{verbatim} + + +\subsection{Browser Controller Objects \label{browser-controllers}} + +Browser controllers provide two methods which parallel two of the +module-level convenience functions: + +\begin{funcdesc}{open}{url\optional{, new\optional{, autoraise=1}}} + Display \var{url} using the browser handled by this controller. + If \var{new} is 1, a new browser window is opened if possible. + If \var{new} is 2, a new browser page ("tab") is opened if possible. +\end{funcdesc} + +\begin{funcdesc}{open_new}{url} + Open \var{url} in a new window of the browser handled by this + controller, if possible, otherwise, open \var{url} in the only + browser window. Alias \function{open_new}. +\end{funcdesc} + +\begin{funcdesc}{open_new_tab}{url} + Open \var{url} in a new page ("tab") of the browser handled by this + controller, if possible, otherwise equivalent to \function{open_new}. +\versionadded{2.5} +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/lib/libwhichdb.tex b/sys/src/cmd/python/Doc/lib/libwhichdb.tex new file mode 100644 index 000000000..92d37e723 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libwhichdb.tex @@ -0,0 +1,20 @@ +\section{\module{whichdb} --- + Guess which DBM module created a database} + +\declaremodule{standard}{whichdb} +\modulesynopsis{Guess which DBM-style module created a given database.} + + +The single function in this module attempts to guess which of the +several simple database modules available--\refmodule{dbm}, +\refmodule{gdbm}, or \refmodule{dbhash}--should be used to open a +given file. + +\begin{funcdesc}{whichdb}{filename} +Returns one of the following values: \code{None} if the file can't be +opened because it's unreadable or doesn't exist; the empty string +(\code{''}) if the file's format can't be guessed; or a string +containing the required module name, such as \code{'dbm'} or +\code{'gdbm'}. +\end{funcdesc} + diff --git a/sys/src/cmd/python/Doc/lib/libwinreg.tex b/sys/src/cmd/python/Doc/lib/libwinreg.tex new file mode 100644 index 000000000..d1e23da51 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libwinreg.tex @@ -0,0 +1,414 @@ +\section{\module{_winreg} -- + Windows registry access} + +\declaremodule[-winreg]{extension}{_winreg} + \platform{Windows} +\modulesynopsis{Routines and objects for manipulating the Windows registry.} +\sectionauthor{Mark Hammond}{MarkH@ActiveState.com} + +\versionadded{2.0} + +These functions expose the Windows registry API to Python. Instead of +using an integer as the registry handle, a handle object is used to +ensure that the handles are closed correctly, even if the programmer +neglects to explicitly close them. + +This module exposes a very low-level interface to the Windows +registry; it is expected that in the future a new \code{winreg} +module will be created offering a higher-level interface to the +registry API. + +This module offers the following functions: + + +\begin{funcdesc}{CloseKey}{hkey} + Closes a previously opened registry key. + The hkey argument specifies a previously opened key. + + Note that if \var{hkey} is not closed using this method (or via + \method{handle.Close()}), it is closed when the \var{hkey} object + is destroyed by Python. +\end{funcdesc} + + +\begin{funcdesc}{ConnectRegistry}{computer_name, key} + Establishes a connection to a predefined registry handle on + another computer, and returns a \dfn{handle object} + + \var{computer_name} is the name of the remote computer, of the + form \code{r"\e\e computername"}. If \code{None}, the local computer + is used. + + \var{key} is the predefined handle to connect to. + + The return value is the handle of the opened key. + If the function fails, an \exception{EnvironmentError} exception is + raised. +\end{funcdesc} + + +\begin{funcdesc}{CreateKey}{key, sub_key} + Creates or opens the specified key, returning a \dfn{handle object} + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + \var{sub_key} is a string that names the key this method opens + or creates. + + If \var{key} is one of the predefined keys, \var{sub_key} may + be \code{None}. In that case, the handle returned is the same key handle + passed in to the function. + + If the key already exists, this function opens the existing key. + + The return value is the handle of the opened key. + If the function fails, an \exception{EnvironmentError} exception is + raised. +\end{funcdesc} + +\begin{funcdesc}{DeleteKey}{key, sub_key} + Deletes the specified key. + + \var{key} is an already open key, or any one of the predefined + \constant{HKEY_*} constants. + + \var{sub_key} is a string that must be a subkey of the key + identified by the \var{key} parameter. This value must not be + \code{None}, and the key may not have subkeys. + + \emph{This method can not delete keys with subkeys.} + + If the method succeeds, the entire key, including all of its values, + is removed. If the method fails, an \exception{EnvironmentError} + exception is raised. +\end{funcdesc} + + +\begin{funcdesc}{DeleteValue}{key, value} + Removes a named value from a registry key. + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + \var{value} is a string that identifies the value to remove. +\end{funcdesc} + + +\begin{funcdesc}{EnumKey}{key, index} + Enumerates subkeys of an open registry key, returning a string. + + \var{key} is an already open key, or any one of the predefined + \constant{HKEY_*} constants. + + \var{index} is an integer that identifies the index of the key to + retrieve. + + The function retrieves the name of one subkey each time it + is called. It is typically called repeatedly until an + \exception{EnvironmentError} exception + is raised, indicating, no more values are available. +\end{funcdesc} + + +\begin{funcdesc}{EnumValue}{key, index} + Enumerates values of an open registry key, returning a tuple. + + \var{key} is an already open key, or any one of the predefined + \constant{HKEY_*} constants. + + \var{index} is an integer that identifies the index of the value + to retrieve. + + The function retrieves the name of one subkey each time it is + called. It is typically called repeatedly, until an + \exception{EnvironmentError} exception is raised, indicating + no more values. + + The result is a tuple of 3 items: + + \begin{tableii}{c|p{3in}}{code}{Index}{Meaning} + \lineii{0}{A string that identifies the value name} + \lineii{1}{An object that holds the value data, and whose + type depends on the underlying registry type} + \lineii{2}{An integer that identifies the type of the value data} + \end{tableii} + +\end{funcdesc} + + +\begin{funcdesc}{FlushKey}{key} + Writes all the attributes of a key to the registry. + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + It is not necessary to call RegFlushKey to change a key. + Registry changes are flushed to disk by the registry using its lazy + flusher. Registry changes are also flushed to disk at system + shutdown. Unlike \function{CloseKey()}, the \function{FlushKey()} method + returns only when all the data has been written to the registry. + An application should only call \function{FlushKey()} if it requires absolute + certainty that registry changes are on disk. + + \emph{If you don't know whether a \function{FlushKey()} call is required, it + probably isn't.} + +\end{funcdesc} + + +\begin{funcdesc}{RegLoadKey}{key, sub_key, file_name} + Creates a subkey under the specified key and stores registration + information from a specified file into that subkey. + + \var{key} is an already open key, or any of the predefined + \constant{HKEY_*} constants. + + \var{sub_key} is a string that identifies the sub_key to load. + + \var {file_name} is the name of the file to load registry data from. + This file must have been created with the \function{SaveKey()} function. + Under the file allocation table (FAT) file system, the filename may not + have an extension. + + A call to LoadKey() fails if the calling process does not have the + \constant{SE_RESTORE_PRIVILEGE} privilege. Note that privileges + are different than permissions - see the Win32 documentation for + more details. + + If \var{key} is a handle returned by \function{ConnectRegistry()}, + then the path specified in \var{fileName} is relative to the + remote computer. + + The Win32 documentation implies \var{key} must be in the + \constant{HKEY_USER} or \constant{HKEY_LOCAL_MACHINE} tree. + This may or may not be true. +\end{funcdesc} + + +\begin{funcdesc}{OpenKey}{key, sub_key\optional{, res\code{ = 0}}\optional{, sam\code{ = \constant{KEY_READ}}}} + Opens the specified key, returning a \dfn{handle object} + + \var{key} is an already open key, or any one of the predefined + \constant{HKEY_*} constants. + + \var{sub_key} is a string that identifies the sub_key to open. + + \var{res} is a reserved integer, and must be zero. The default is zero. + + \var{sam} is an integer that specifies an access mask that describes + the desired security access for the key. Default is \constant{KEY_READ} + + The result is a new handle to the specified key. + + If the function fails, \exception{EnvironmentError} is raised. +\end{funcdesc} + + +\begin{funcdesc}{OpenKeyEx}{} + The functionality of \function{OpenKeyEx()} is provided via + \function{OpenKey()}, by the use of default arguments. +\end{funcdesc} + + +\begin{funcdesc}{QueryInfoKey}{key} + Returns information about a key, as a tuple. + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + The result is a tuple of 3 items: + + \begin{tableii}{c|p{3in}}{code}{Index}{Meaning} + \lineii{0}{An integer giving the number of sub keys this key has.} + \lineii{1}{An integer giving the number of values this key has.} + \lineii{2}{A long integer giving when the key was last modified (if + available) as 100's of nanoseconds since Jan 1, 1600.} + \end{tableii} +\end{funcdesc} + + +\begin{funcdesc}{QueryValue}{key, sub_key} + Retrieves the unnamed value for a key, as a string + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + \var{sub_key} is a string that holds the name of the subkey with which + the value is associated. If this parameter is \code{None} or empty, the + function retrieves the value set by the \function{SetValue()} method + for the key identified by \var{key}. + + Values in the registry have name, type, and data components. This + method retrieves the data for a key's first value that has a NULL name. + But the underlying API call doesn't return the type, Lame Lame Lame, + DO NOT USE THIS!!! +\end{funcdesc} + + +\begin{funcdesc}{QueryValueEx}{key, value_name} + Retrieves the type and data for a specified value name associated with + an open registry key. + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + \var{value_name} is a string indicating the value to query. + + The result is a tuple of 2 items: + + \begin{tableii}{c|p{3in}}{code}{Index}{Meaning} + \lineii{0}{The value of the registry item.} + \lineii{1}{An integer giving the registry type for this value.} + \end{tableii} +\end{funcdesc} + + +\begin{funcdesc}{SaveKey}{key, file_name} + Saves the specified key, and all its subkeys to the specified file. + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + \var{file_name} is the name of the file to save registry data to. + This file cannot already exist. If this filename includes an extension, + it cannot be used on file allocation table (FAT) file systems by the + \method{LoadKey()}, \method{ReplaceKey()} or + \method{RestoreKey()} methods. + + If \var{key} represents a key on a remote computer, the path + described by \var{file_name} is relative to the remote computer. + The caller of this method must possess the \constant{SeBackupPrivilege} + security privilege. Note that privileges are different than permissions + - see the Win32 documentation for more details. + + This function passes NULL for \var{security_attributes} to the API. +\end{funcdesc} + + +\begin{funcdesc}{SetValue}{key, sub_key, type, value} + Associates a value with a specified key. + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + \var{sub_key} is a string that names the subkey with which the value + is associated. + + \var{type} is an integer that specifies the type of the data. + Currently this must be \constant{REG_SZ}, meaning only strings are + supported. Use the \function{SetValueEx()} function for support for + other data types. + + \var{value} is a string that specifies the new value. + + If the key specified by the \var{sub_key} parameter does not exist, + the SetValue function creates it. + + Value lengths are limited by available memory. Long values (more than + 2048 bytes) should be stored as files with the filenames stored in + the configuration registry. This helps the registry perform + efficiently. + + The key identified by the \var{key} parameter must have been + opened with \constant{KEY_SET_VALUE} access. +\end{funcdesc} + + +\begin{funcdesc}{SetValueEx}{key, value_name, reserved, type, value} + Stores data in the value field of an open registry key. + + \var{key} is an already open key, or one of the predefined + \constant{HKEY_*} constants. + + \var{sub_key} is a string that names the subkey with which the + value is associated. + + \var{type} is an integer that specifies the type of the data. + This should be one of the following constants defined in this module: + + \begin{tableii}{l|p{3in}}{constant}{Constant}{Meaning} + \lineii{REG_BINARY}{Binary data in any form.} + \lineii{REG_DWORD}{A 32-bit number.} + \lineii{REG_DWORD_LITTLE_ENDIAN}{A 32-bit number in little-endian format.} + \lineii{REG_DWORD_BIG_ENDIAN}{A 32-bit number in big-endian format.} + \lineii{REG_EXPAND_SZ}{Null-terminated string containing references + to environment variables (\samp{\%PATH\%}).} + \lineii{REG_LINK}{A Unicode symbolic link.} + \lineii{REG_MULTI_SZ}{A sequence of null-terminated strings, + terminated by two null characters. (Python handles + this termination automatically.)} + \lineii{REG_NONE}{No defined value type.} + \lineii{REG_RESOURCE_LIST}{A device-driver resource list.} + \lineii{REG_SZ}{A null-terminated string.} + \end{tableii} + + \var{reserved} can be anything - zero is always passed to the + API. + + \var{value} is a string that specifies the new value. + + This method can also set additional value and type information for the + specified key. The key identified by the key parameter must have been + opened with \constant{KEY_SET_VALUE} access. + + To open the key, use the \function{CreateKeyEx()} or + \function{OpenKey()} methods. + + Value lengths are limited by available memory. Long values (more than + 2048 bytes) should be stored as files with the filenames stored in + the configuration registry. This helps the registry perform efficiently. +\end{funcdesc} + + + +\subsection{Registry Handle Objects \label{handle-object}} + + This object wraps a Windows HKEY object, automatically closing it when + the object is destroyed. To guarantee cleanup, you can call either + the \method{Close()} method on the object, or the + \function{CloseKey()} function. + + All registry functions in this module return one of these objects. + + All registry functions in this module which accept a handle object + also accept an integer, however, use of the handle object is + encouraged. + + Handle objects provide semantics for \method{__nonzero__()} - thus +\begin{verbatim} + if handle: + print "Yes" +\end{verbatim} + will print \code{Yes} if the handle is currently valid (has not been + closed or detached). + + The object also support comparison semantics, so handle + objects will compare true if they both reference the same + underlying Windows handle value. + + Handle objects can be converted to an integer (e.g., using the + builtin \function{int()} function), in which case the underlying + Windows handle value is returned. You can also use the + \method{Detach()} method to return the integer handle, and + also disconnect the Windows handle from the handle object. + +\begin{methoddesc}{Close}{} + Closes the underlying Windows handle. + + If the handle is already closed, no error is raised. +\end{methoddesc} + + +\begin{methoddesc}{Detach}{} + Detaches the Windows handle from the handle object. + + The result is an integer (or long on 64 bit Windows) that holds + the value of the handle before it is detached. If the + handle is already detached or closed, this will return zero. + + After calling this function, the handle is effectively invalidated, + but the handle is not closed. You would call this function when + you need the underlying Win32 handle to exist beyond the lifetime + of the handle object. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/libwinsound.tex b/sys/src/cmd/python/Doc/lib/libwinsound.tex new file mode 100644 index 000000000..5f5b15e07 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libwinsound.tex @@ -0,0 +1,142 @@ +\section{\module{winsound} --- + Sound-playing interface for Windows} + +\declaremodule{builtin}{winsound} + \platform{Windows} +\modulesynopsis{Access to the sound-playing machinery for Windows.} +\moduleauthor{Toby Dickenson}{htrd90@zepler.org} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +\versionadded{1.5.2} + +The \module{winsound} module provides access to the basic +sound-playing machinery provided by Windows platforms. It includes +functions and several constants. + + +\begin{funcdesc}{Beep}{frequency, duration} + Beep the PC's speaker. + The \var{frequency} parameter specifies frequency, in hertz, of the + sound, and must be in the range 37 through 32,767. + The \var{duration} parameter specifies the number of milliseconds the + sound should last. If the system is not + able to beep the speaker, \exception{RuntimeError} is raised. + \note{Under Windows 95 and 98, the Windows \cfunction{Beep()} + function exists but is useless (it ignores its arguments). In that + case Python simulates it via direct port manipulation (added in version + 2.1). It's unknown whether that will work on all systems.} + \versionadded{1.6} +\end{funcdesc} + +\begin{funcdesc}{PlaySound}{sound, flags} + Call the underlying \cfunction{PlaySound()} function from the + Platform API. The \var{sound} parameter may be a filename, audio + data as a string, or \code{None}. Its interpretation depends on the + value of \var{flags}, which can be a bit-wise ORed combination of + the constants described below. If the system indicates an error, + \exception{RuntimeError} is raised. +\end{funcdesc} + +\begin{funcdesc}{MessageBeep}{\optional{type=\code{MB_OK}}} + Call the underlying \cfunction{MessageBeep()} function from the + Platform API. This plays a sound as specified in the registry. The + \var{type} argument specifies which sound to play; possible values + are \code{-1}, \code{MB_ICONASTERISK}, \code{MB_ICONEXCLAMATION}, + \code{MB_ICONHAND}, \code{MB_ICONQUESTION}, and \code{MB_OK}, all + described below. The value \code{-1} produces a ``simple beep''; + this is the final fallback if a sound cannot be played otherwise. + \versionadded{2.3} +\end{funcdesc} + +\begin{datadesc}{SND_FILENAME} + The \var{sound} parameter is the name of a WAV file. + Do not use with \constant{SND_ALIAS}. +\end{datadesc} + +\begin{datadesc}{SND_ALIAS} + The \var{sound} parameter is a sound association name from the + registry. If the registry contains no such name, play the system + default sound unless \constant{SND_NODEFAULT} is also specified. + If no default sound is registered, raise \exception{RuntimeError}. + Do not use with \constant{SND_FILENAME}. + + All Win32 systems support at least the following; most systems support + many more: + +\begin{tableii}{l|l}{code} + {\function{PlaySound()} \var{name}} + {Corresponding Control Panel Sound name} + \lineii{'SystemAsterisk'} {Asterisk} + \lineii{'SystemExclamation'}{Exclamation} + \lineii{'SystemExit'} {Exit Windows} + \lineii{'SystemHand'} {Critical Stop} + \lineii{'SystemQuestion'} {Question} +\end{tableii} + + For example: + +\begin{verbatim} +import winsound +# Play Windows exit sound. +winsound.PlaySound("SystemExit", winsound.SND_ALIAS) + +# Probably play Windows default sound, if any is registered (because +# "*" probably isn't the registered name of any sound). +winsound.PlaySound("*", winsound.SND_ALIAS) +\end{verbatim} +\end{datadesc} + +\begin{datadesc}{SND_LOOP} + Play the sound repeatedly. The \constant{SND_ASYNC} flag must also + be used to avoid blocking. Cannot be used with \constant{SND_MEMORY}. +\end{datadesc} + +\begin{datadesc}{SND_MEMORY} + The \var{sound} parameter to \function{PlaySound()} is a memory + image of a WAV file, as a string. + + \note{This module does not support playing from a memory + image asynchronously, so a combination of this flag and + \constant{SND_ASYNC} will raise \exception{RuntimeError}.} +\end{datadesc} + +\begin{datadesc}{SND_PURGE} + Stop playing all instances of the specified sound. +\end{datadesc} + +\begin{datadesc}{SND_ASYNC} + Return immediately, allowing sounds to play asynchronously. +\end{datadesc} + +\begin{datadesc}{SND_NODEFAULT} + If the specified sound cannot be found, do not play the system default + sound. +\end{datadesc} + +\begin{datadesc}{SND_NOSTOP} + Do not interrupt sounds currently playing. +\end{datadesc} + +\begin{datadesc}{SND_NOWAIT} + Return immediately if the sound driver is busy. +\end{datadesc} + +\begin{datadesc}{MB_ICONASTERISK} + Play the \code{SystemDefault} sound. +\end{datadesc} + +\begin{datadesc}{MB_ICONEXCLAMATION} + Play the \code{SystemExclamation} sound. +\end{datadesc} + +\begin{datadesc}{MB_ICONHAND} + Play the \code{SystemHand} sound. +\end{datadesc} + +\begin{datadesc}{MB_ICONQUESTION} + Play the \code{SystemQuestion} sound. +\end{datadesc} + +\begin{datadesc}{MB_OK} + Play the \code{SystemDefault} sound. +\end{datadesc} diff --git a/sys/src/cmd/python/Doc/lib/libwsgiref.tex b/sys/src/cmd/python/Doc/lib/libwsgiref.tex new file mode 100755 index 000000000..37ded9fda --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libwsgiref.tex @@ -0,0 +1,782 @@ +\section{\module{wsgiref} --- WSGI Utilities and Reference +Implementation} +\declaremodule{}{wsgiref} +\moduleauthor{Phillip J. Eby}{pje@telecommunity.com} +\sectionauthor{Phillip J. Eby}{pje@telecommunity.com} +\modulesynopsis{WSGI Utilities and Reference Implementation} + +\versionadded{2.5} + +The Web Server Gateway Interface (WSGI) is a standard interface +between web server software and web applications written in Python. +Having a standard interface makes it easy to use an application +that supports WSGI with a number of different web servers. + +Only authors of web servers and programming frameworks need to know +every detail and corner case of the WSGI design. You don't need to +understand every detail of WSGI just to install a WSGI application or +to write a web application using an existing framework. + +\module{wsgiref} is a reference implementation of the WSGI specification +that can be used to add WSGI support to a web server or framework. It +provides utilities for manipulating WSGI environment variables and +response headers, base classes for implementing WSGI servers, a demo +HTTP server that serves WSGI applications, and a validation tool that +checks WSGI servers and applications for conformance to the +WSGI specification (\pep{333}). + +% XXX If you're just trying to write a web application... + +See \url{http://www.wsgi.org} for more information about WSGI, +and links to tutorials and other resources. + + + + + + + + + + + + + +\subsection{\module{wsgiref.util} -- WSGI environment utilities} +\declaremodule{}{wsgiref.util} + +This module provides a variety of utility functions for working with +WSGI environments. A WSGI environment is a dictionary containing +HTTP request variables as described in \pep{333}. All of the functions +taking an \var{environ} parameter expect a WSGI-compliant dictionary to +be supplied; please see \pep{333} for a detailed specification. + +\begin{funcdesc}{guess_scheme}{environ} +Return a guess for whether \code{wsgi.url_scheme} should be ``http'' or +``https'', by checking for a \code{HTTPS} environment variable in the +\var{environ} dictionary. The return value is a string. + +This function is useful when creating a gateway that wraps CGI or a +CGI-like protocol such as FastCGI. Typically, servers providing such +protocols will include a \code{HTTPS} variable with a value of ``1'' +``yes'', or ``on'' when a request is received via SSL. So, this +function returns ``https'' if such a value is found, and ``http'' +otherwise. +\end{funcdesc} + +\begin{funcdesc}{request_uri}{environ \optional{, include_query=1}} +Return the full request URI, optionally including the query string, +using the algorithm found in the ``URL Reconstruction'' section of +\pep{333}. If \var{include_query} is false, the query string is +not included in the resulting URI. +\end{funcdesc} + +\begin{funcdesc}{application_uri}{environ} +Similar to \function{request_uri}, except that the \code{PATH_INFO} and +\code{QUERY_STRING} variables are ignored. The result is the base URI +of the application object addressed by the request. +\end{funcdesc} + +\begin{funcdesc}{shift_path_info}{environ} +Shift a single name from \code{PATH_INFO} to \code{SCRIPT_NAME} and +return the name. The \var{environ} dictionary is \emph{modified} +in-place; use a copy if you need to keep the original \code{PATH_INFO} +or \code{SCRIPT_NAME} intact. + +If there are no remaining path segments in \code{PATH_INFO}, \code{None} +is returned. + +Typically, this routine is used to process each portion of a request +URI path, for example to treat the path as a series of dictionary keys. +This routine modifies the passed-in environment to make it suitable for +invoking another WSGI application that is located at the target URI. +For example, if there is a WSGI application at \code{/foo}, and the +request URI path is \code{/foo/bar/baz}, and the WSGI application at +\code{/foo} calls \function{shift_path_info}, it will receive the string +``bar'', and the environment will be updated to be suitable for passing +to a WSGI application at \code{/foo/bar}. That is, \code{SCRIPT_NAME} +will change from \code{/foo} to \code{/foo/bar}, and \code{PATH_INFO} +will change from \code{/bar/baz} to \code{/baz}. + +When \code{PATH_INFO} is just a ``/'', this routine returns an empty +string and appends a trailing slash to \code{SCRIPT_NAME}, even though +empty path segments are normally ignored, and \code{SCRIPT_NAME} doesn't +normally end in a slash. This is intentional behavior, to ensure that +an application can tell the difference between URIs ending in \code{/x} +from ones ending in \code{/x/} when using this routine to do object +traversal. + +\end{funcdesc} + +\begin{funcdesc}{setup_testing_defaults}{environ} +Update \var{environ} with trivial defaults for testing purposes. + +This routine adds various parameters required for WSGI, including +\code{HTTP_HOST}, \code{SERVER_NAME}, \code{SERVER_PORT}, +\code{REQUEST_METHOD}, \code{SCRIPT_NAME}, \code{PATH_INFO}, and all of +the \pep{333}-defined \code{wsgi.*} variables. It only supplies default +values, and does not replace any existing settings for these variables. + +This routine is intended to make it easier for unit tests of WSGI +servers and applications to set up dummy environments. It should NOT +be used by actual WSGI servers or applications, since the data is fake! +\end{funcdesc} + + + +In addition to the environment functions above, the +\module{wsgiref.util} module also provides these miscellaneous +utilities: + +\begin{funcdesc}{is_hop_by_hop}{header_name} +Return true if 'header_name' is an HTTP/1.1 ``Hop-by-Hop'' header, as +defined by \rfc{2616}. +\end{funcdesc} + +\begin{classdesc}{FileWrapper}{filelike \optional{, blksize=8192}} +A wrapper to convert a file-like object to an iterator. The resulting +objects support both \method{__getitem__} and \method{__iter__} +iteration styles, for compatibility with Python 2.1 and Jython. +As the object is iterated over, the optional \var{blksize} parameter +will be repeatedly passed to the \var{filelike} object's \method{read()} +method to obtain strings to yield. When \method{read()} returns an +empty string, iteration is ended and is not resumable. + +If \var{filelike} has a \method{close()} method, the returned object +will also have a \method{close()} method, and it will invoke the +\var{filelike} object's \method{close()} method when called. +\end{classdesc} + + + + + + + + + + + + + + + + + + + +\subsection{\module{wsgiref.headers} -- WSGI response header tools} +\declaremodule{}{wsgiref.headers} + +This module provides a single class, \class{Headers}, for convenient +manipulation of WSGI response headers using a mapping-like interface. + +\begin{classdesc}{Headers}{headers} +Create a mapping-like object wrapping \var{headers}, which must be a +list of header name/value tuples as described in \pep{333}. Any changes +made to the new \class{Headers} object will directly update the +\var{headers} list it was created with. + +\class{Headers} objects support typical mapping operations including +\method{__getitem__}, \method{get}, \method{__setitem__}, +\method{setdefault}, \method{__delitem__}, \method{__contains__} and +\method{has_key}. For each of these methods, the key is the header name +(treated case-insensitively), and the value is the first value +associated with that header name. Setting a header deletes any existing +values for that header, then adds a new value at the end of the wrapped +header list. Headers' existing order is generally maintained, with new +headers added to the end of the wrapped list. + +Unlike a dictionary, \class{Headers} objects do not raise an error when +you try to get or delete a key that isn't in the wrapped header list. +Getting a nonexistent header just returns \code{None}, and deleting +a nonexistent header does nothing. + +\class{Headers} objects also support \method{keys()}, \method{values()}, +and \method{items()} methods. The lists returned by \method{keys()} +and \method{items()} can include the same key more than once if there +is a multi-valued header. The \code{len()} of a \class{Headers} object +is the same as the length of its \method{items()}, which is the same +as the length of the wrapped header list. In fact, the \method{items()} +method just returns a copy of the wrapped header list. + +Calling \code{str()} on a \class{Headers} object returns a formatted +string suitable for transmission as HTTP response headers. Each header +is placed on a line with its value, separated by a colon and a space. +Each line is terminated by a carriage return and line feed, and the +string is terminated with a blank line. + +In addition to their mapping interface and formatting features, +\class{Headers} objects also have the following methods for querying +and adding multi-valued headers, and for adding headers with MIME +parameters: + +\begin{methoddesc}{get_all}{name} +Return a list of all the values for the named header. + +The returned list will be sorted in the order they appeared in the +original header list or were added to this instance, and may contain +duplicates. Any fields deleted and re-inserted are always appended to +the header list. If no fields exist with the given name, returns an +empty list. +\end{methoddesc} + + +\begin{methoddesc}{add_header}{name, value, **_params} +Add a (possibly multi-valued) header, with optional MIME parameters +specified via keyword arguments. + +\var{name} is the header field to add. Keyword arguments can be used to +set MIME parameters for the header field. Each parameter must be a +string or \code{None}. Underscores in parameter names are converted to +dashes, since dashes are illegal in Python identifiers, but many MIME +parameter names include dashes. If the parameter value is a string, it +is added to the header value parameters in the form \code{name="value"}. +If it is \code{None}, only the parameter name is added. (This is used +for MIME parameters without a value.) Example usage: + +\begin{verbatim} +h.add_header('content-disposition', 'attachment', filename='bud.gif') +\end{verbatim} + +The above will add a header that looks like this: + +\begin{verbatim} +Content-Disposition: attachment; filename="bud.gif" +\end{verbatim} +\end{methoddesc} +\end{classdesc} + +\subsection{\module{wsgiref.simple_server} -- a simple WSGI HTTP server} +\declaremodule[wsgiref.simpleserver]{}{wsgiref.simple_server} + +This module implements a simple HTTP server (based on +\module{BaseHTTPServer}) that serves WSGI applications. Each server +instance serves a single WSGI application on a given host and port. If +you want to serve multiple applications on a single host and port, you +should create a WSGI application that parses \code{PATH_INFO} to select +which application to invoke for each request. (E.g., using the +\function{shift_path_info()} function from \module{wsgiref.util}.) + + +\begin{funcdesc}{make_server}{host, port, app +\optional{, server_class=\class{WSGIServer} \optional{, +handler_class=\class{WSGIRequestHandler}}}} +Create a new WSGI server listening on \var{host} and \var{port}, +accepting connections for \var{app}. The return value is an instance of +the supplied \var{server_class}, and will process requests using the +specified \var{handler_class}. \var{app} must be a WSGI application +object, as defined by \pep{333}. + +Example usage: +\begin{verbatim}from wsgiref.simple_server import make_server, demo_app + +httpd = make_server('', 8000, demo_app) +print "Serving HTTP on port 8000..." + +# Respond to requests until process is killed +httpd.serve_forever() + +# Alternative: serve one request, then exit +##httpd.handle_request() +\end{verbatim} + +\end{funcdesc} + + + + + + +\begin{funcdesc}{demo_app}{environ, start_response} +This function is a small but complete WSGI application that +returns a text page containing the message ``Hello world!'' +and a list of the key/value pairs provided in the +\var{environ} parameter. It's useful for verifying that a WSGI server +(such as \module{wsgiref.simple_server}) is able to run a simple WSGI +application correctly. +\end{funcdesc} + + +\begin{classdesc}{WSGIServer}{server_address, RequestHandlerClass} +Create a \class{WSGIServer} instance. \var{server_address} should be +a \code{(host,port)} tuple, and \var{RequestHandlerClass} should be +the subclass of \class{BaseHTTPServer.BaseHTTPRequestHandler} that will +be used to process requests. + +You do not normally need to call this constructor, as the +\function{make_server()} function can handle all the details for you. + +\class{WSGIServer} is a subclass +of \class{BaseHTTPServer.HTTPServer}, so all of its methods (such as +\method{serve_forever()} and \method{handle_request()}) are available. +\class{WSGIServer} also provides these WSGI-specific methods: + +\begin{methoddesc}{set_app}{application} +Sets the callable \var{application} as the WSGI application that will +receive requests. +\end{methoddesc} + +\begin{methoddesc}{get_app}{} +Returns the currently-set application callable. +\end{methoddesc} + +Normally, however, you do not need to use these additional methods, as +\method{set_app()} is normally called by \function{make_server()}, and +the \method{get_app()} exists mainly for the benefit of request handler +instances. +\end{classdesc} + + + +\begin{classdesc}{WSGIRequestHandler}{request, client_address, server} +Create an HTTP handler for the given \var{request} (i.e. a socket), +\var{client_address} (a \code{(\var{host},\var{port})} tuple), and +\var{server} (\class{WSGIServer} instance). + +You do not need to create instances of this class directly; they are +automatically created as needed by \class{WSGIServer} objects. You +can, however, subclass this class and supply it as a \var{handler_class} +to the \function{make_server()} function. Some possibly relevant +methods for overriding in subclasses: + +\begin{methoddesc}{get_environ}{} +Returns a dictionary containing the WSGI environment for a request. The +default implementation copies the contents of the \class{WSGIServer} +object's \member{base_environ} dictionary attribute and then adds +various headers derived from the HTTP request. Each call to this method +should return a new dictionary containing all of the relevant CGI +environment variables as specified in \pep{333}. +\end{methoddesc} + +\begin{methoddesc}{get_stderr}{} +Return the object that should be used as the \code{wsgi.errors} stream. +The default implementation just returns \code{sys.stderr}. +\end{methoddesc} + +\begin{methoddesc}{handle}{} +Process the HTTP request. The default implementation creates a handler +instance using a \module{wsgiref.handlers} class to implement the actual +WSGI application interface. +\end{methoddesc} + +\end{classdesc} + + + + + + + + + +\subsection{\module{wsgiref.validate} -- WSGI conformance checker} +\declaremodule{}{wsgiref.validate} +When creating new WSGI application objects, frameworks, servers, or +middleware, it can be useful to validate the new code's conformance +using \module{wsgiref.validate}. This module provides a function that +creates WSGI application objects that validate communications between +a WSGI server or gateway and a WSGI application object, to check both +sides for protocol conformance. + +Note that this utility does not guarantee complete \pep{333} compliance; +an absence of errors from this module does not necessarily mean that +errors do not exist. However, if this module does produce an error, +then it is virtually certain that either the server or application is +not 100\% compliant. + +This module is based on the \module{paste.lint} module from Ian +Bicking's ``Python Paste'' library. + +\begin{funcdesc}{validator}{application} +Wrap \var{application} and return a new WSGI application object. The +returned application will forward all requests to the original +\var{application}, and will check that both the \var{application} and +the server invoking it are conforming to the WSGI specification and to +RFC 2616. + +Any detected nonconformance results in an \exception{AssertionError} +being raised; note, however, that how these errors are handled is +server-dependent. For example, \module{wsgiref.simple_server} and other +servers based on \module{wsgiref.handlers} (that don't override the +error handling methods to do something else) will simply output a +message that an error has occurred, and dump the traceback to +\code{sys.stderr} or some other error stream. + +This wrapper may also generate output using the \module{warnings} module +to indicate behaviors that are questionable but which may not actually +be prohibited by \pep{333}. Unless they are suppressed using Python +command-line options or the \module{warnings} API, any such warnings +will be written to \code{sys.stderr} (\emph{not} \code{wsgi.errors}, +unless they happen to be the same object). +\end{funcdesc} + +\subsection{\module{wsgiref.handlers} -- server/gateway base classes} +\declaremodule{}{wsgiref.handlers} + +This module provides base handler classes for implementing WSGI servers +and gateways. These base classes handle most of the work of +communicating with a WSGI application, as long as they are given a +CGI-like environment, along with input, output, and error streams. + + +\begin{classdesc}{CGIHandler}{} +CGI-based invocation via \code{sys.stdin}, \code{sys.stdout}, +\code{sys.stderr} and \code{os.environ}. This is useful when you have +a WSGI application and want to run it as a CGI script. Simply invoke +\code{CGIHandler().run(app)}, where \code{app} is the WSGI application +object you wish to invoke. + +This class is a subclass of \class{BaseCGIHandler} that sets +\code{wsgi.run_once} to true, \code{wsgi.multithread} to false, and +\code{wsgi.multiprocess} to true, and always uses \module{sys} and +\module{os} to obtain the necessary CGI streams and environment. +\end{classdesc} + + +\begin{classdesc}{BaseCGIHandler}{stdin, stdout, stderr, environ +\optional{, multithread=True \optional{, multiprocess=False}}} + +Similar to \class{CGIHandler}, but instead of using the \module{sys} and +\module{os} modules, the CGI environment and I/O streams are specified +explicitly. The \var{multithread} and \var{multiprocess} values are +used to set the \code{wsgi.multithread} and \code{wsgi.multiprocess} +flags for any applications run by the handler instance. + +This class is a subclass of \class{SimpleHandler} intended for use with +software other than HTTP ``origin servers''. If you are writing a +gateway protocol implementation (such as CGI, FastCGI, SCGI, etc.) that +uses a \code{Status:} header to send an HTTP status, you probably want +to subclass this instead of \class{SimpleHandler}. +\end{classdesc} + + + +\begin{classdesc}{SimpleHandler}{stdin, stdout, stderr, environ +\optional{,multithread=True \optional{, multiprocess=False}}} + +Similar to \class{BaseCGIHandler}, but designed for use with HTTP origin +servers. If you are writing an HTTP server implementation, you will +probably want to subclass this instead of \class{BaseCGIHandler} + +This class is a subclass of \class{BaseHandler}. It overrides the +\method{__init__()}, \method{get_stdin()}, \method{get_stderr()}, +\method{add_cgi_vars()}, \method{_write()}, and \method{_flush()} +methods to support explicitly setting the environment and streams via +the constructor. The supplied environment and streams are stored in +the \member{stdin}, \member{stdout}, \member{stderr}, and +\member{environ} attributes. +\end{classdesc} + +\begin{classdesc}{BaseHandler}{} +This is an abstract base class for running WSGI applications. Each +instance will handle a single HTTP request, although in principle you +could create a subclass that was reusable for multiple requests. + +\class{BaseHandler} instances have only one method intended for external +use: + +\begin{methoddesc}{run}{app} +Run the specified WSGI application, \var{app}. +\end{methoddesc} + +All of the other \class{BaseHandler} methods are invoked by this method +in the process of running the application, and thus exist primarily to +allow customizing the process. + +The following methods MUST be overridden in a subclass: + +\begin{methoddesc}{_write}{data} +Buffer the string \var{data} for transmission to the client. It's okay +if this method actually transmits the data; \class{BaseHandler} +just separates write and flush operations for greater efficiency +when the underlying system actually has such a distinction. +\end{methoddesc} + +\begin{methoddesc}{_flush}{} +Force buffered data to be transmitted to the client. It's okay if this +method is a no-op (i.e., if \method{_write()} actually sends the data). +\end{methoddesc} + +\begin{methoddesc}{get_stdin}{} +Return an input stream object suitable for use as the \code{wsgi.input} +of the request currently being processed. +\end{methoddesc} + +\begin{methoddesc}{get_stderr}{} +Return an output stream object suitable for use as the +\code{wsgi.errors} of the request currently being processed. +\end{methoddesc} + +\begin{methoddesc}{add_cgi_vars}{} +Insert CGI variables for the current request into the \member{environ} +attribute. +\end{methoddesc} + +Here are some other methods and attributes you may wish to override. +This list is only a summary, however, and does not include every method +that can be overridden. You should consult the docstrings and source +code for additional information before attempting to create a customized +\class{BaseHandler} subclass. + + + + + + + + + + + + + + + + +Attributes and methods for customizing the WSGI environment: + +\begin{memberdesc}{wsgi_multithread} +The value to be used for the \code{wsgi.multithread} environment +variable. It defaults to true in \class{BaseHandler}, but may have +a different default (or be set by the constructor) in the other +subclasses. +\end{memberdesc} + +\begin{memberdesc}{wsgi_multiprocess} +The value to be used for the \code{wsgi.multiprocess} environment +variable. It defaults to true in \class{BaseHandler}, but may have +a different default (or be set by the constructor) in the other +subclasses. +\end{memberdesc} + +\begin{memberdesc}{wsgi_run_once} +The value to be used for the \code{wsgi.run_once} environment +variable. It defaults to false in \class{BaseHandler}, but +\class{CGIHandler} sets it to true by default. +\end{memberdesc} + +\begin{memberdesc}{os_environ} +The default environment variables to be included in every request's +WSGI environment. By default, this is a copy of \code{os.environ} at +the time that \module{wsgiref.handlers} was imported, but subclasses can +either create their own at the class or instance level. Note that the +dictionary should be considered read-only, since the default value is +shared between multiple classes and instances. +\end{memberdesc} + +\begin{memberdesc}{server_software} +If the \member{origin_server} attribute is set, this attribute's value +is used to set the default \code{SERVER_SOFTWARE} WSGI environment +variable, and also to set a default \code{Server:} header in HTTP +responses. It is ignored for handlers (such as \class{BaseCGIHandler} +and \class{CGIHandler}) that are not HTTP origin servers. +\end{memberdesc} + + + +\begin{methoddesc}{get_scheme}{} +Return the URL scheme being used for the current request. The default +implementation uses the \function{guess_scheme()} function from +\module{wsgiref.util} to guess whether the scheme should be ``http'' or +``https'', based on the current request's \member{environ} variables. +\end{methoddesc} + +\begin{methoddesc}{setup_environ}{} +Set the \member{environ} attribute to a fully-populated WSGI +environment. The default implementation uses all of the above methods +and attributes, plus the \method{get_stdin()}, \method{get_stderr()}, +and \method{add_cgi_vars()} methods and the \member{wsgi_file_wrapper} +attribute. It also inserts a \code{SERVER_SOFTWARE} key if not present, +as long as the \member{origin_server} attribute is a true value and the +\member{server_software} attribute is set. +\end{methoddesc} + + + + + + + + + + + + + + + + + + + + + + + + + +Methods and attributes for customizing exception handling: + +\begin{methoddesc}{log_exception}{exc_info} +Log the \var{exc_info} tuple in the server log. \var{exc_info} is a +\code{(\var{type}, \var{value}, \var{traceback})} tuple. The default +implementation simply writes the traceback to the request's +\code{wsgi.errors} stream and flushes it. Subclasses can override this +method to change the format or retarget the output, mail the traceback +to an administrator, or whatever other action may be deemed suitable. +\end{methoddesc} + +\begin{memberdesc}{traceback_limit} +The maximum number of frames to include in tracebacks output by the +default \method{log_exception()} method. If \code{None}, all frames +are included. +\end{memberdesc} + +\begin{methoddesc}{error_output}{environ, start_response} +This method is a WSGI application to generate an error page for the +user. It is only invoked if an error occurs before headers are sent +to the client. + +This method can access the current error information using +\code{sys.exc_info()}, and should pass that information to +\var{start_response} when calling it (as described in the ``Error +Handling'' section of \pep{333}). + +The default implementation just uses the \member{error_status}, +\member{error_headers}, and \member{error_body} attributes to generate +an output page. Subclasses can override this to produce more dynamic +error output. + +Note, however, that it's not recommended from a security perspective to +spit out diagnostics to any old user; ideally, you should have to do +something special to enable diagnostic output, which is why the default +implementation doesn't include any. +\end{methoddesc} + + + + +\begin{memberdesc}{error_status} +The HTTP status used for error responses. This should be a status +string as defined in \pep{333}; it defaults to a 500 code and message. +\end{memberdesc} + +\begin{memberdesc}{error_headers} +The HTTP headers used for error responses. This should be a list of +WSGI response headers (\code{(\var{name}, \var{value})} tuples), as +described in \pep{333}. The default list just sets the content type +to \code{text/plain}. +\end{memberdesc} + +\begin{memberdesc}{error_body} +The error response body. This should be an HTTP response body string. +It defaults to the plain text, ``A server error occurred. Please +contact the administrator.'' +\end{memberdesc} + + + + + + + + + + + + + + + + + + + + + + + + +Methods and attributes for \pep{333}'s ``Optional Platform-Specific File +Handling'' feature: + +\begin{memberdesc}{wsgi_file_wrapper} +A \code{wsgi.file_wrapper} factory, or \code{None}. The default value +of this attribute is the \class{FileWrapper} class from +\module{wsgiref.util}. +\end{memberdesc} + +\begin{methoddesc}{sendfile}{} +Override to implement platform-specific file transmission. This method +is called only if the application's return value is an instance of +the class specified by the \member{wsgi_file_wrapper} attribute. It +should return a true value if it was able to successfully transmit the +file, so that the default transmission code will not be executed. +The default implementation of this method just returns a false value. +\end{methoddesc} + + +Miscellaneous methods and attributes: + +\begin{memberdesc}{origin_server} +This attribute should be set to a true value if the handler's +\method{_write()} and \method{_flush()} are being used to communicate +directly to the client, rather than via a CGI-like gateway protocol that +wants the HTTP status in a special \code{Status:} header. + +This attribute's default value is true in \class{BaseHandler}, but +false in \class{BaseCGIHandler} and \class{CGIHandler}. +\end{memberdesc} + +\begin{memberdesc}{http_version} +If \member{origin_server} is true, this string attribute is used to +set the HTTP version of the response set to the client. It defaults to +\code{"1.0"}. +\end{memberdesc} + + + + + +\end{classdesc} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sys/src/cmd/python/Doc/lib/libxdrlib.tex b/sys/src/cmd/python/Doc/lib/libxdrlib.tex new file mode 100644 index 000000000..d0863d932 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libxdrlib.tex @@ -0,0 +1,251 @@ +\section{\module{xdrlib} --- + Encode and decode XDR data} + +\declaremodule{standard}{xdrlib} +\modulesynopsis{Encoders and decoders for the External Data + Representation (XDR).} + +\index{XDR} +\index{External Data Representation} + +The \module{xdrlib} module supports the External Data Representation +Standard as described in \rfc{1014}, written by Sun Microsystems, +Inc. June 1987. It supports most of the data types described in the +RFC. + +The \module{xdrlib} module defines two classes, one for packing +variables into XDR representation, and another for unpacking from XDR +representation. There are also two exception classes. + +\begin{classdesc}{Packer}{} +\class{Packer} is the class for packing data into XDR representation. +The \class{Packer} class is instantiated with no arguments. +\end{classdesc} + +\begin{classdesc}{Unpacker}{data} +\code{Unpacker} is the complementary class which unpacks XDR data +values from a string buffer. The input buffer is given as +\var{data}. +\end{classdesc} + + +\begin{seealso} + \seerfc{1014}{XDR: External Data Representation Standard}{This RFC + defined the encoding of data which was XDR at the time + this module was originally written. It has + apparently been obsoleted by \rfc{1832}.} + + \seerfc{1832}{XDR: External Data Representation Standard}{Newer RFC + that provides a revised definition of XDR.} +\end{seealso} + + +\subsection{Packer Objects \label{xdr-packer-objects}} + +\class{Packer} instances have the following methods: + +\begin{methoddesc}[Packer]{get_buffer}{} +Returns the current pack buffer as a string. +\end{methoddesc} + +\begin{methoddesc}[Packer]{reset}{} +Resets the pack buffer to the empty string. +\end{methoddesc} + +In general, you can pack any of the most common XDR data types by +calling the appropriate \code{pack_\var{type}()} method. Each method +takes a single argument, the value to pack. The following simple data +type packing methods are supported: \method{pack_uint()}, +\method{pack_int()}, \method{pack_enum()}, \method{pack_bool()}, +\method{pack_uhyper()}, and \method{pack_hyper()}. + +\begin{methoddesc}[Packer]{pack_float}{value} +Packs the single-precision floating point number \var{value}. +\end{methoddesc} + +\begin{methoddesc}[Packer]{pack_double}{value} +Packs the double-precision floating point number \var{value}. +\end{methoddesc} + +The following methods support packing strings, bytes, and opaque data: + +\begin{methoddesc}[Packer]{pack_fstring}{n, s} +Packs a fixed length string, \var{s}. \var{n} is the length of the +string but it is \emph{not} packed into the data buffer. The string +is padded with null bytes if necessary to guaranteed 4 byte alignment. +\end{methoddesc} + +\begin{methoddesc}[Packer]{pack_fopaque}{n, data} +Packs a fixed length opaque data stream, similarly to +\method{pack_fstring()}. +\end{methoddesc} + +\begin{methoddesc}[Packer]{pack_string}{s} +Packs a variable length string, \var{s}. The length of the string is +first packed as an unsigned integer, then the string data is packed +with \method{pack_fstring()}. +\end{methoddesc} + +\begin{methoddesc}[Packer]{pack_opaque}{data} +Packs a variable length opaque data string, similarly to +\method{pack_string()}. +\end{methoddesc} + +\begin{methoddesc}[Packer]{pack_bytes}{bytes} +Packs a variable length byte stream, similarly to \method{pack_string()}. +\end{methoddesc} + +The following methods support packing arrays and lists: + +\begin{methoddesc}[Packer]{pack_list}{list, pack_item} +Packs a \var{list} of homogeneous items. This method is useful for +lists with an indeterminate size; i.e. the size is not available until +the entire list has been walked. For each item in the list, an +unsigned integer \code{1} is packed first, followed by the data value +from the list. \var{pack_item} is the function that is called to pack +the individual item. At the end of the list, an unsigned integer +\code{0} is packed. + +For example, to pack a list of integers, the code might appear like +this: + +\begin{verbatim} +import xdrlib +p = xdrlib.Packer() +p.pack_list([1, 2, 3], p.pack_int) +\end{verbatim} +\end{methoddesc} + +\begin{methoddesc}[Packer]{pack_farray}{n, array, pack_item} +Packs a fixed length list (\var{array}) of homogeneous items. \var{n} +is the length of the list; it is \emph{not} packed into the buffer, +but a \exception{ValueError} exception is raised if +\code{len(\var{array})} is not equal to \var{n}. As above, +\var{pack_item} is the function used to pack each element. +\end{methoddesc} + +\begin{methoddesc}[Packer]{pack_array}{list, pack_item} +Packs a variable length \var{list} of homogeneous items. First, the +length of the list is packed as an unsigned integer, then each element +is packed as in \method{pack_farray()} above. +\end{methoddesc} + + +\subsection{Unpacker Objects \label{xdr-unpacker-objects}} + +The \class{Unpacker} class offers the following methods: + +\begin{methoddesc}[Unpacker]{reset}{data} +Resets the string buffer with the given \var{data}. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{get_position}{} +Returns the current unpack position in the data buffer. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{set_position}{position} +Sets the data buffer unpack position to \var{position}. You should be +careful about using \method{get_position()} and \method{set_position()}. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{get_buffer}{} +Returns the current unpack data buffer as a string. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{done}{} +Indicates unpack completion. Raises an \exception{Error} exception +if all of the data has not been unpacked. +\end{methoddesc} + +In addition, every data type that can be packed with a \class{Packer}, +can be unpacked with an \class{Unpacker}. Unpacking methods are of the +form \code{unpack_\var{type}()}, and take no arguments. They return the +unpacked object. + +\begin{methoddesc}[Unpacker]{unpack_float}{} +Unpacks a single-precision floating point number. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{unpack_double}{} +Unpacks a double-precision floating point number, similarly to +\method{unpack_float()}. +\end{methoddesc} + +In addition, the following methods unpack strings, bytes, and opaque +data: + +\begin{methoddesc}[Unpacker]{unpack_fstring}{n} +Unpacks and returns a fixed length string. \var{n} is the number of +characters expected. Padding with null bytes to guaranteed 4 byte +alignment is assumed. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{unpack_fopaque}{n} +Unpacks and returns a fixed length opaque data stream, similarly to +\method{unpack_fstring()}. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{unpack_string}{} +Unpacks and returns a variable length string. The length of the +string is first unpacked as an unsigned integer, then the string data +is unpacked with \method{unpack_fstring()}. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{unpack_opaque}{} +Unpacks and returns a variable length opaque data string, similarly to +\method{unpack_string()}. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{unpack_bytes}{} +Unpacks and returns a variable length byte stream, similarly to +\method{unpack_string()}. +\end{methoddesc} + +The following methods support unpacking arrays and lists: + +\begin{methoddesc}[Unpacker]{unpack_list}{unpack_item} +Unpacks and returns a list of homogeneous items. The list is unpacked +one element at a time +by first unpacking an unsigned integer flag. If the flag is \code{1}, +then the item is unpacked and appended to the list. A flag of +\code{0} indicates the end of the list. \var{unpack_item} is the +function that is called to unpack the items. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{unpack_farray}{n, unpack_item} +Unpacks and returns (as a list) a fixed length array of homogeneous +items. \var{n} is number of list elements to expect in the buffer. +As above, \var{unpack_item} is the function used to unpack each element. +\end{methoddesc} + +\begin{methoddesc}[Unpacker]{unpack_array}{unpack_item} +Unpacks and returns a variable length \var{list} of homogeneous items. +First, the length of the list is unpacked as an unsigned integer, then +each element is unpacked as in \method{unpack_farray()} above. +\end{methoddesc} + + +\subsection{Exceptions \label{xdr-exceptions}} + +Exceptions in this module are coded as class instances: + +\begin{excdesc}{Error} +The base exception class. \exception{Error} has a single public data +member \member{msg} containing the description of the error. +\end{excdesc} + +\begin{excdesc}{ConversionError} +Class derived from \exception{Error}. Contains no additional instance +variables. +\end{excdesc} + +Here is an example of how you would catch one of these exceptions: + +\begin{verbatim} +import xdrlib +p = xdrlib.Packer() +try: + p.pack_double(8.01) +except xdrlib.ConversionError, instance: + print 'packing the double failed:', instance.msg +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libxmllib.tex b/sys/src/cmd/python/Doc/lib/libxmllib.tex new file mode 100644 index 000000000..f7197cade --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libxmllib.tex @@ -0,0 +1,287 @@ +\section{\module{xmllib} --- + A parser for XML documents} + +\declaremodule{standard}{xmllib} +\modulesynopsis{A parser for XML documents.} +\moduleauthor{Sjoerd Mullender}{Sjoerd.Mullender@cwi.nl} +\sectionauthor{Sjoerd Mullender}{Sjoerd.Mullender@cwi.nl} + + +\index{XML} +\index{Extensible Markup Language} + +\deprecated{2.0}{Use \refmodule{xml.sax} instead. The newer XML + package includes full support for XML 1.0.} + +\versionchanged[Added namespace support]{1.5.2} + +This module defines a class \class{XMLParser} which serves as the basis +for parsing text files formatted in XML (Extensible Markup Language). + +\begin{classdesc}{XMLParser}{} +The \class{XMLParser} class must be instantiated without +arguments.\footnote{Actually, a number of keyword arguments are +recognized which influence the parser to accept certain non-standard +constructs. The following keyword arguments are currently +recognized. The defaults for all of these is \code{0} (false) except +for the last one for which the default is \code{1} (true). +\var{accept_unquoted_attributes} (accept certain attribute values +without requiring quotes), \var{accept_missing_endtag_name} (accept +end tags that look like \code{</>}), \var{map_case} (map upper case to +lower case in tags and attributes), \var{accept_utf8} (allow UTF-8 +characters in input; this is required according to the XML standard, +but Python does not as yet deal properly with these characters, so +this is not the default), \var{translate_attribute_references} (don't +attempt to translate character and entity references in attribute values).} +\end{classdesc} + +This class provides the following interface methods and instance variables: + +\begin{memberdesc}{attributes} +A mapping of element names to mappings. The latter mapping maps +attribute names that are valid for the element to the default value of +the attribute, or if there is no default to \code{None}. The default +value is the empty dictionary. This variable is meant to be +overridden, not extended since the default is shared by all instances +of \class{XMLParser}. +\end{memberdesc} + +\begin{memberdesc}{elements} +A mapping of element names to tuples. The tuples contain a function +for handling the start and end tag respectively of the element, or +\code{None} if the method \method{unknown_starttag()} or +\method{unknown_endtag()} is to be called. The default value is the +empty dictionary. This variable is meant to be overridden, not +extended since the default is shared by all instances of +\class{XMLParser}. +\end{memberdesc} + +\begin{memberdesc}{entitydefs} +A mapping of entitynames to their values. The default value contains +definitions for \code{'lt'}, \code{'gt'}, \code{'amp'}, \code{'quot'}, +and \code{'apos'}. +\end{memberdesc} + +\begin{methoddesc}{reset}{} +Reset the instance. Loses all unprocessed data. This is called +implicitly at the instantiation time. +\end{methoddesc} + +\begin{methoddesc}{setnomoretags}{} +Stop processing tags. Treat all following input as literal input +(CDATA). +\end{methoddesc} + +\begin{methoddesc}{setliteral}{} +Enter literal mode (CDATA mode). This mode is automatically exited +when the close tag matching the last unclosed open tag is encountered. +\end{methoddesc} + +\begin{methoddesc}{feed}{data} +Feed some text to the parser. It is processed insofar as it consists +of complete tags; incomplete data is buffered until more data is +fed or \method{close()} is called. +\end{methoddesc} + +\begin{methoddesc}{close}{} +Force processing of all buffered data as if it were followed by an +end-of-file mark. This method may be redefined by a derived class to +define additional processing at the end of the input, but the +redefined version should always call \method{close()}. +\end{methoddesc} + +\begin{methoddesc}{translate_references}{data} +Translate all entity and character references in \var{data} and +return the translated string. +\end{methoddesc} + +\begin{methoddesc}{getnamespace}{} +Return a mapping of namespace abbreviations to namespace URIs that are +currently in effect. +\end{methoddesc} + +\begin{methoddesc}{handle_xml}{encoding, standalone} +This method is called when the \samp{<?xml ...?>} tag is processed. +The arguments are the values of the encoding and standalone attributes +in the tag. Both encoding and standalone are optional. The values +passed to \method{handle_xml()} default to \code{None} and the string +\code{'no'} respectively. +\end{methoddesc} + +\begin{methoddesc}{handle_doctype}{tag, pubid, syslit, data} +This\index{DOCTYPE declaration} method is called when the +\samp{<!DOCTYPE...>} declaration is processed. The arguments are the +tag name of the root element, the Formal Public\index{Formal Public +Identifier} Identifier (or \code{None} if not specified), the system +identifier, and the uninterpreted contents of the internal DTD subset +as a string (or \code{None} if not present). +\end{methoddesc} + +\begin{methoddesc}{handle_starttag}{tag, method, attributes} +This method is called to handle start tags for which a start tag +handler is defined in the instance variable \member{elements}. The +\var{tag} argument is the name of the tag, and the +\var{method} argument is the function (method) which should be used to +support semantic interpretation of the start tag. The +\var{attributes} argument is a dictionary of attributes, the key being +the \var{name} and the value being the \var{value} of the attribute +found inside the tag's \code{<>} brackets. Character and entity +references in the \var{value} have been interpreted. For instance, +for the start tag \code{<A HREF="http://www.cwi.nl/">}, this method +would be called as \code{handle_starttag('A', self.elements['A'][0], +\{'HREF': 'http://www.cwi.nl/'\})}. The base implementation simply +calls \var{method} with \var{attributes} as the only argument. +\end{methoddesc} + +\begin{methoddesc}{handle_endtag}{tag, method} +This method is called to handle endtags for which an end tag handler +is defined in the instance variable \member{elements}. The \var{tag} +argument is the name of the tag, and the \var{method} argument is the +function (method) which should be used to support semantic +interpretation of the end tag. For instance, for the endtag +\code{</A>}, this method would be called as \code{handle_endtag('A', +self.elements['A'][1])}. The base implementation simply calls +\var{method}. +\end{methoddesc} + +\begin{methoddesc}{handle_data}{data} +This method is called to process arbitrary data. It is intended to be +overridden by a derived class; the base class implementation does +nothing. +\end{methoddesc} + +\begin{methoddesc}{handle_charref}{ref} +This method is called to process a character reference of the form +\samp{\&\#\var{ref};}. \var{ref} can either be a decimal number, +or a hexadecimal number when preceded by an \character{x}. +In the base implementation, \var{ref} must be a number in the +range 0-255. It translates the character to \ASCII{} and calls the +method \method{handle_data()} with the character as argument. If +\var{ref} is invalid or out of range, the method +\code{unknown_charref(\var{ref})} is called to handle the error. A +subclass must override this method to provide support for character +references outside of the \ASCII{} range. +\end{methoddesc} + +\begin{methoddesc}{handle_comment}{comment} +This method is called when a comment is encountered. The +\var{comment} argument is a string containing the text between the +\samp{<!--} and \samp{-->} delimiters, but not the delimiters +themselves. For example, the comment \samp{<!--text-->} will +cause this method to be called with the argument \code{'text'}. The +default method does nothing. +\end{methoddesc} + +\begin{methoddesc}{handle_cdata}{data} +This method is called when a CDATA element is encountered. The +\var{data} argument is a string containing the text between the +\samp{<![CDATA[} and \samp{]]>} delimiters, but not the delimiters +themselves. For example, the entity \samp{<![CDATA[text]]>} will +cause this method to be called with the argument \code{'text'}. The +default method does nothing, and is intended to be overridden. +\end{methoddesc} + +\begin{methoddesc}{handle_proc}{name, data} +This method is called when a processing instruction (PI) is +encountered. The \var{name} is the PI target, and the \var{data} +argument is a string containing the text between the PI target and the +closing delimiter, but not the delimiter itself. For example, the +instruction \samp{<?XML text?>} will cause this method to be called +with the arguments \code{'XML'} and \code{'text'}. The default method +does nothing. Note that if a document starts with \samp{<?xml +..?>}, \method{handle_xml()} is called to handle it. +\end{methoddesc} + +\begin{methoddesc}{handle_special}{data} +This method is called when a declaration is encountered. The +\var{data} argument is a string containing the text between the +\samp{<!} and \samp{>} delimiters, but not the delimiters +themselves. For example, the \index{ENTITY declaration}entity +declaration \samp{<!ENTITY text>} will cause this method to be called +with the argument \code{'ENTITY text'}. The default method does +nothing. Note that \samp{<!DOCTYPE ...>} is handled separately if it +is located at the start of the document. +\end{methoddesc} + +\begin{methoddesc}{syntax_error}{message} +This method is called when a syntax error is encountered. The +\var{message} is a description of what was wrong. The default method +raises a \exception{RuntimeError} exception. If this method is +overridden, it is permissible for it to return. This method is only +called when the error can be recovered from. Unrecoverable errors +raise a \exception{RuntimeError} without first calling +\method{syntax_error()}. +\end{methoddesc} + +\begin{methoddesc}{unknown_starttag}{tag, attributes} +This method is called to process an unknown start tag. It is intended +to be overridden by a derived class; the base class implementation +does nothing. +\end{methoddesc} + +\begin{methoddesc}{unknown_endtag}{tag} +This method is called to process an unknown end tag. It is intended +to be overridden by a derived class; the base class implementation +does nothing. +\end{methoddesc} + +\begin{methoddesc}{unknown_charref}{ref} +This method is called to process unresolvable numeric character +references. It is intended to be overridden by a derived class; the +base class implementation does nothing. +\end{methoddesc} + +\begin{methoddesc}{unknown_entityref}{ref} +This method is called to process an unknown entity reference. It is +intended to be overridden by a derived class; the base class +implementation calls \method{syntax_error()} to signal an error. +\end{methoddesc} + + +\begin{seealso} + \seetitle[http://www.w3.org/TR/REC-xml]{Extensible Markup Language + (XML) 1.0}{The XML specification, published by the World + Wide Web Consortium (W3C), defines the syntax and + processor requirements for XML. References to additional + material on XML, including translations of the + specification, are available at + \url{http://www.w3.org/XML/}.} + + \seetitle[http://www.python.org/topics/xml/]{Python and XML + Processing}{The Python XML Topic Guide provides a great + deal of information on using XML from Python and links to + other sources of information on XML.} + + \seetitle[http://www.python.org/sigs/xml-sig/]{SIG for XML + Processing in Python}{The Python XML Special Interest + Group is developing substantial support for processing XML + from Python.} +\end{seealso} + + +\subsection{XML Namespaces \label{xml-namespace}} + +This module has support for XML namespaces as defined in the XML +Namespaces proposed recommendation. +\indexii{XML}{namespaces} + +Tag and attribute names that are defined in an XML namespace are +handled as if the name of the tag or element consisted of the +namespace (the URL that defines the namespace) followed by a +space and the name of the tag or attribute. For instance, the tag +\code{<html xmlns='http://www.w3.org/TR/REC-html40'>} is treated as if +the tag name was \code{'http://www.w3.org/TR/REC-html40 html'}, and +the tag \code{<html:a href='http://frob.com'>} inside the above +mentioned element is treated as if the tag name were +\code{'http://www.w3.org/TR/REC-html40 a'} and the attribute name as +if it were \code{'http://www.w3.org/TR/REC-html40 href'}. + +An older draft of the XML Namespaces proposal is also recognized, but +triggers a warning. + +\begin{seealso} + \seetitle[http://www.w3.org/TR/REC-xml-names/]{Namespaces in XML}{ + This World Wide Web Consortium recommendation describes the + proper syntax and processing requirements for namespaces in + XML.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/libxmlrpclib.tex b/sys/src/cmd/python/Doc/lib/libxmlrpclib.tex new file mode 100644 index 000000000..3645b824d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libxmlrpclib.tex @@ -0,0 +1,383 @@ +\section{\module{xmlrpclib} --- XML-RPC client access} + +\declaremodule{standard}{xmlrpclib} +\modulesynopsis{XML-RPC client access.} +\moduleauthor{Fredrik Lundh}{fredrik@pythonware.com} +\sectionauthor{Eric S. Raymond}{esr@snark.thyrsus.com} + +% Not everything is documented yet. It might be good to describe +% Marshaller, Unmarshaller, getparser, dumps, loads, and Transport. + +\versionadded{2.2} + +XML-RPC is a Remote Procedure Call method that uses XML passed via +HTTP as a transport. With it, a client can call methods with +parameters on a remote server (the server is named by a URI) and get back +structured data. This module supports writing XML-RPC client code; it +handles all the details of translating between conformable Python +objects and XML on the wire. + +\begin{classdesc}{ServerProxy}{uri\optional{, transport\optional{, + encoding\optional{, verbose\optional{, + allow_none\optional{, use_datetime}}}}}} +A \class{ServerProxy} instance is an object that manages communication +with a remote XML-RPC server. The required first argument is a URI +(Uniform Resource Indicator), and will normally be the URL of the +server. The optional second argument is a transport factory instance; +by default it is an internal \class{SafeTransport} instance for https: +URLs and an internal HTTP \class{Transport} instance otherwise. The +optional third argument is an encoding, by default UTF-8. The optional +fourth argument is a debugging flag. If \var{allow_none} is true, +the Python constant \code{None} will be translated into XML; the +default behaviour is for \code{None} to raise a \exception{TypeError}. +This is a commonly-used extension to the XML-RPC specification, but isn't +supported by all clients and servers; see +\url{http://ontosys.com/xml-rpc/extensions.php} for a description. +The \var{use_datetime} flag can be used to cause date/time values to be +presented as \class{\refmodule{datetime}.datetime} objects; this is false +by default. \class{\refmodule{datetime}.datetime}, +\class{\refmodule{datetime}.date} and \class{\refmodule{datetime}.time} +objects may be passed to calls. \class{\refmodule{datetime}.date} objects +are converted with a time of ``00:00:00''. +\class{\refmodule{datetime}.time} objects are converted using today's date. + +Both the HTTP and HTTPS transports support the URL syntax extension for +HTTP Basic Authentication: \code{http://user:pass@host:port/path}. The +\code{user:pass} portion will be base64-encoded as an HTTP `Authorization' +header, and sent to the remote server as part of the connection process +when invoking an XML-RPC method. You only need to use this if the +remote server requires a Basic Authentication user and password. + +The returned instance is a proxy object with methods that can be used +to invoke corresponding RPC calls on the remote server. If the remote +server supports the introspection API, the proxy can also be used to query +the remote server for the methods it supports (service discovery) and +fetch other server-associated metadata. + +\class{ServerProxy} instance methods take Python basic types and objects as +arguments and return Python basic types and classes. Types that are +conformable (e.g. that can be marshalled through XML), include the +following (and except where noted, they are unmarshalled as the same +Python type): + +\begin{tableii}{l|l}{constant}{Name}{Meaning} + \lineii{boolean}{The \constant{True} and \constant{False} constants} + \lineii{integers}{Pass in directly} + \lineii{floating-point numbers}{Pass in directly} + \lineii{strings}{Pass in directly} + \lineii{arrays}{Any Python sequence type containing conformable + elements. Arrays are returned as lists} + \lineii{structures}{A Python dictionary. Keys must be strings, + values may be any conformable type.} + \lineii{dates}{in seconds since the epoch (pass in an instance of the + \class{DateTime} class) or a + \class{\refmodule{datetime}.datetime}, + \class{\refmodule{datetime}.date} or + \class{\refmodule{datetime}.time} instance} + \lineii{binary data}{pass in an instance of the \class{Binary} + wrapper class} +\end{tableii} + +This is the full set of data types supported by XML-RPC. Method calls +may also raise a special \exception{Fault} instance, used to signal +XML-RPC server errors, or \exception{ProtocolError} used to signal an +error in the HTTP/HTTPS transport layer. Both \exception{Fault} and +\exception{ProtocolError} derive from a base class called +\exception{Error}. Note that even though starting with Python 2.2 you +can subclass builtin types, the xmlrpclib module currently does not +marshal instances of such subclasses. + +When passing strings, characters special to XML such as \samp{<}, +\samp{>}, and \samp{\&} will be automatically escaped. However, it's +the caller's responsibility to ensure that the string is free of +characters that aren't allowed in XML, such as the control characters +with ASCII values between 0 and 31; failing to do this will result in +an XML-RPC request that isn't well-formed XML. If you have to pass +arbitrary strings via XML-RPC, use the \class{Binary} wrapper class +described below. + +\class{Server} is retained as an alias for \class{ServerProxy} for backwards +compatibility. New code should use \class{ServerProxy}. + +\versionchanged[The \var{use_datetime} flag was added]{2.5} +\end{classdesc} + + +\begin{seealso} + \seetitle[http://www.tldp.org/HOWTO/XML-RPC-HOWTO/index.html] + {XML-RPC HOWTO}{A good description of XML operation and + client software in several languages. Contains pretty much + everything an XML-RPC client developer needs to know.} + \seetitle[http://xmlrpc-c.sourceforge.net/hacks.php] + {XML-RPC Hacks page}{Extensions for various open-source + libraries to support introspection and multicall.} +\end{seealso} + + +\subsection{ServerProxy Objects \label{serverproxy-objects}} + +A \class{ServerProxy} instance has a method corresponding to +each remote procedure call accepted by the XML-RPC server. Calling +the method performs an RPC, dispatched by both name and argument +signature (e.g. the same method name can be overloaded with multiple +argument signatures). The RPC finishes by returning a value, which +may be either returned data in a conformant type or a \class{Fault} or +\class{ProtocolError} object indicating an error. + +Servers that support the XML introspection API support some common +methods grouped under the reserved \member{system} member: + +\begin{methoddesc}{system.listMethods}{} +This method returns a list of strings, one for each (non-system) +method supported by the XML-RPC server. +\end{methoddesc} + +\begin{methoddesc}{system.methodSignature}{name} +This method takes one parameter, the name of a method implemented by +the XML-RPC server.It returns an array of possible signatures for this +method. A signature is an array of types. The first of these types is +the return type of the method, the rest are parameters. + +Because multiple signatures (ie. overloading) is permitted, this method +returns a list of signatures rather than a singleton. + +Signatures themselves are restricted to the top level parameters +expected by a method. For instance if a method expects one array of +structs as a parameter, and it returns a string, its signature is +simply "string, array". If it expects three integers and returns a +string, its signature is "string, int, int, int". + +If no signature is defined for the method, a non-array value is +returned. In Python this means that the type of the returned +value will be something other that list. +\end{methoddesc} + +\begin{methoddesc}{system.methodHelp}{name} +This method takes one parameter, the name of a method implemented by +the XML-RPC server. It returns a documentation string describing the +use of that method. If no such string is available, an empty string is +returned. The documentation string may contain HTML markup. +\end{methoddesc} + +Introspection methods are currently supported by servers written in +PHP, C and Microsoft .NET. Partial introspection support is included +in recent updates to UserLand Frontier. Introspection support for +Perl, Python and Java is available at the \ulink{XML-RPC +Hacks}{http://xmlrpc-c.sourceforge.net/hacks.php} page. + + +\subsection{Boolean Objects \label{boolean-objects}} + +This class may be initialized from any Python value; the instance +returned depends only on its truth value. It supports various Python +operators through \method{__cmp__()}, \method{__repr__()}, +\method{__int__()}, and \method{__nonzero__()} methods, all +implemented in the obvious ways. + +It also has the following method, supported mainly for internal use by +the unmarshalling code: + +\begin{methoddesc}{encode}{out} +Write the XML-RPC encoding of this Boolean item to the out stream object. +\end{methoddesc} + + +\subsection{DateTime Objects \label{datetime-objects}} + +This class may be initialized with seconds since the epoch, a time tuple, an +ISO 8601 time/date string, or a {}\class{\refmodule{datetime}.datetime}, +{}\class{\refmodule{datetime}.date} or {}\class{\refmodule{datetime}.time} +instance. It has the following methods, supported mainly for internal use +by the marshalling/unmarshalling code: + +\begin{methoddesc}{decode}{string} +Accept a string as the instance's new time value. +\end{methoddesc} + +\begin{methoddesc}{encode}{out} +Write the XML-RPC encoding of this \class{DateTime} item to the +\var{out} stream object. +\end{methoddesc} + +It also supports certain of Python's built-in operators through +\method{__cmp__()} and \method{__repr__()} methods. + + +\subsection{Binary Objects \label{binary-objects}} + +This class may be initialized from string data (which may include NULs). +The primary access to the content of a \class{Binary} object is +provided by an attribute: + +\begin{memberdesc}[Binary]{data} +The binary data encapsulated by the \class{Binary} instance. The data +is provided as an 8-bit string. +\end{memberdesc} + +\class{Binary} objects have the following methods, supported mainly +for internal use by the marshalling/unmarshalling code: + +\begin{methoddesc}[Binary]{decode}{string} +Accept a base64 string and decode it as the instance's new data. +\end{methoddesc} + +\begin{methoddesc}[Binary]{encode}{out} +Write the XML-RPC base 64 encoding of this binary item to the out +stream object. +\end{methoddesc} + +It also supports certain of Python's built-in operators through a +\method{__cmp__()} method. + + +\subsection{Fault Objects \label{fault-objects}} + +A \class{Fault} object encapsulates the content of an XML-RPC fault tag. +Fault objects have the following members: + +\begin{memberdesc}{faultCode} +A string indicating the fault type. +\end{memberdesc} + +\begin{memberdesc}{faultString} +A string containing a diagnostic message associated with the fault. +\end{memberdesc} + + +\subsection{ProtocolError Objects \label{protocol-error-objects}} + +A \class{ProtocolError} object describes a protocol error in the +underlying transport layer (such as a 404 `not found' error if the +server named by the URI does not exist). It has the following +members: + +\begin{memberdesc}{url} +The URI or URL that triggered the error. +\end{memberdesc} + +\begin{memberdesc}{errcode} +The error code. +\end{memberdesc} + +\begin{memberdesc}{errmsg} +The error message or diagnostic string. +\end{memberdesc} + +\begin{memberdesc}{headers} +A string containing the headers of the HTTP/HTTPS request that +triggered the error. +\end{memberdesc} + +\subsection{MultiCall Objects} + +\versionadded{2.4} + +In \url{http://www.xmlrpc.com/discuss/msgReader\%241208}, an approach +is presented to encapsulate multiple calls to a remote server into a +single request. + +\begin{classdesc}{MultiCall}{server} + +Create an object used to boxcar method calls. \var{server} is the +eventual target of the call. Calls can be made to the result object, +but they will immediately return \var{None}, and only store the +call name and parameters in the \class{MultiCall} object. Calling +the object itself causes all stored calls to be transmitted as +a single \code{system.multicall} request. The result of this call +is a generator; iterating over this generator yields the individual +results. + +\end{classdesc} + +A usage example of this class is + +\begin{verbatim} +multicall = MultiCall(server_proxy) +multicall.add(2,3) +multicall.get_address("Guido") +add_result, address = multicall() +\end{verbatim} + +\subsection{Convenience Functions} + +\begin{funcdesc}{boolean}{value} +Convert any Python value to one of the XML-RPC Boolean constants, +\code{True} or \code{False}. +\end{funcdesc} + +\begin{funcdesc}{dumps}{params\optional{, methodname\optional{, + methodresponse\optional{, encoding\optional{, + allow_none}}}}} +Convert \var{params} into an XML-RPC request. +or into a response if \var{methodresponse} is true. +\var{params} can be either a tuple of arguments or an instance of the +\exception{Fault} exception class. If \var{methodresponse} is true, +only a single value can be returned, meaning that \var{params} must be of length 1. +\var{encoding}, if supplied, is the encoding to use in the generated +XML; the default is UTF-8. Python's \constant{None} value cannot be +used in standard XML-RPC; to allow using it via an extension, +provide a true value for \var{allow_none}. +\end{funcdesc} + +\begin{funcdesc}{loads}{data\optional{, use_datetime}} +Convert an XML-RPC request or response into Python objects, a +\code{(\var{params}, \var{methodname})}. \var{params} is a tuple of argument; \var{methodname} +is a string, or \code{None} if no method name is present in the packet. +If the XML-RPC packet represents a fault condition, this +function will raise a \exception{Fault} exception. +The \var{use_datetime} flag can be used to cause date/time values to be +presented as \class{\refmodule{datetime}.datetime} objects; this is false +by default. +Note that even if you call an XML-RPC method with +\class{\refmodule{datetime}.date} or \class{\refmodule{datetime}.time} +objects, they are converted to \class{DateTime} objects internally, so only +{}\class{\refmodule{datetime}.datetime} objects will be returned. + +\versionchanged[The \var{use_datetime} flag was added]{2.5} +\end{funcdesc} + + + +\subsection{Example of Client Usage \label{xmlrpc-client-example}} + +\begin{verbatim} +# simple test program (from the XML-RPC specification) +from xmlrpclib import ServerProxy, Error + +# server = ServerProxy("http://localhost:8000") # local server +server = ServerProxy("http://betty.userland.com") + +print server + +try: + print server.examples.getStateName(41) +except Error, v: + print "ERROR", v +\end{verbatim} + +To access an XML-RPC server through a proxy, you need to define +a custom transport. The following example, +written by NoboNobo, % fill in original author's name if we ever learn it +shows how: + +% Example taken from http://lowlife.jp/nobonobo/wiki/xmlrpcwithproxy.html +\begin{verbatim} +import xmlrpclib, httplib + +class ProxiedTransport(xmlrpclib.Transport): + def set_proxy(self, proxy): + self.proxy = proxy + def make_connection(self, host): + self.realhost = host + h = httplib.HTTP(self.proxy) + return h + def send_request(self, connection, handler, request_body): + connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler)) + def send_host(self, connection, host): + connection.putheader('Host', self.realhost) + +p = ProxiedTransport() +p.set_proxy('proxy-server:8080') +server = xmlrpclib.Server('http://time.xmlrpc.com/RPC2', transport=p) +print server.currentTime.getCurrentTime() +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libzipfile.tex b/sys/src/cmd/python/Doc/lib/libzipfile.tex new file mode 100644 index 000000000..3d81e50a3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libzipfile.tex @@ -0,0 +1,309 @@ +\section{\module{zipfile} --- + Work with ZIP archives} + +\declaremodule{standard}{zipfile} +\modulesynopsis{Read and write ZIP-format archive files.} +\moduleauthor{James C. Ahlstrom}{jim@interet.com} +\sectionauthor{James C. Ahlstrom}{jim@interet.com} +% LaTeX markup by Fred L. Drake, Jr. <fdrake@acm.org> + +\versionadded{1.6} + +The ZIP file format is a common archive and compression standard. +This module provides tools to create, read, write, append, and list a +ZIP file. Any advanced use of this module will require an +understanding of the format, as defined in +\citetitle[http://www.pkware.com/business_and_developers/developer/appnote/] +{PKZIP Application Note}. + +This module does not currently handle ZIP files which have appended +comments, or multi-disk ZIP files. It can handle ZIP files that use the +ZIP64 extensions (that is ZIP files that are more than 4 GByte in size). + +The available attributes of this module are: + +\begin{excdesc}{error} + The error raised for bad ZIP files. +\end{excdesc} + +\begin{excdesc}{LargeZipFile} + The error raised when a ZIP file would require ZIP64 functionality but that + has not been enabled. +\end{excdesc} + +\begin{classdesc*}{ZipFile} + The class for reading and writing ZIP files. See + ``\citetitle{ZipFile Objects}'' (section \ref{zipfile-objects}) for + constructor details. +\end{classdesc*} + +\begin{classdesc*}{PyZipFile} + Class for creating ZIP archives containing Python libraries. +\end{classdesc*} + +\begin{classdesc}{ZipInfo}{\optional{filename\optional{, date_time}}} + Class used to represent information about a member of an archive. + Instances of this class are returned by the \method{getinfo()} and + \method{infolist()} methods of \class{ZipFile} objects. Most users + of the \module{zipfile} module will not need to create these, but + only use those created by this module. + \var{filename} should be the full name of the archive member, and + \var{date_time} should be a tuple containing six fields which + describe the time of the last modification to the file; the fields + are described in section \ref{zipinfo-objects}, ``ZipInfo Objects.'' +\end{classdesc} + +\begin{funcdesc}{is_zipfile}{filename} + Returns \code{True} if \var{filename} is a valid ZIP file based on its magic + number, otherwise returns \code{False}. This module does not currently + handle ZIP files which have appended comments. +\end{funcdesc} + +\begin{datadesc}{ZIP_STORED} + The numeric constant for an uncompressed archive member. +\end{datadesc} + +\begin{datadesc}{ZIP_DEFLATED} + The numeric constant for the usual ZIP compression method. This + requires the zlib module. No other compression methods are + currently supported. +\end{datadesc} + + +\begin{seealso} + \seetitle[http://www.pkware.com/business_and_developers/developer/appnote/] + {PKZIP Application Note}{Documentation on the ZIP file format by + Phil Katz, the creator of the format and algorithms used.} + + \seetitle[http://www.info-zip.org/pub/infozip/]{Info-ZIP Home Page}{ + Information about the Info-ZIP project's ZIP archive + programs and development libraries.} +\end{seealso} + + +\subsection{ZipFile Objects \label{zipfile-objects}} + +\begin{classdesc}{ZipFile}{file\optional{, mode\optional{, compression\optional{, allowZip64}}}} + Open a ZIP file, where \var{file} can be either a path to a file + (a string) or a file-like object. The \var{mode} parameter + should be \code{'r'} to read an existing file, \code{'w'} to + truncate and write a new file, or \code{'a'} to append to an + existing file. For \var{mode} is \code{'a'} and \var{file} + refers to an existing ZIP file, then additional files are added to + it. If \var{file} does not refer to a ZIP file, then a new ZIP + archive is appended to the file. This is meant for adding a ZIP + archive to another file, such as \file{python.exe}. Using + +\begin{verbatim} +cat myzip.zip >> python.exe +\end{verbatim} + + also works, and at least \program{WinZip} can read such files. + \var{compression} is the ZIP compression method to use when writing + the archive, and should be \constant{ZIP_STORED} or + \constant{ZIP_DEFLATED}; unrecognized values will cause + \exception{RuntimeError} to be raised. If \constant{ZIP_DEFLATED} + is specified but the \refmodule{zlib} module is not available, + \exception{RuntimeError} is also raised. The default is + \constant{ZIP_STORED}. + If \var{allowZip64} is \code{True} zipfile will create ZIP files that use + the ZIP64 extensions when the zipfile is larger than 2 GB. If it is + false (the default) \module{zipfile} will raise an exception when the + ZIP file would require ZIP64 extensions. ZIP64 extensions are disabled by + default because the default \program{zip} and \program{unzip} commands on + \UNIX{} (the InfoZIP utilities) don't support these extensions. +\end{classdesc} + +\begin{methoddesc}{close}{} + Close the archive file. You must call \method{close()} before + exiting your program or essential records will not be written. +\end{methoddesc} + +\begin{methoddesc}{getinfo}{name} + Return a \class{ZipInfo} object with information about the archive + member \var{name}. +\end{methoddesc} + +\begin{methoddesc}{infolist}{} + Return a list containing a \class{ZipInfo} object for each member of + the archive. The objects are in the same order as their entries in + the actual ZIP file on disk if an existing archive was opened. +\end{methoddesc} + +\begin{methoddesc}{namelist}{} + Return a list of archive members by name. +\end{methoddesc} + +\begin{methoddesc}{printdir}{} + Print a table of contents for the archive to \code{sys.stdout}. +\end{methoddesc} + +\begin{methoddesc}{read}{name} + Return the bytes of the file in the archive. The archive must be + open for read or append. +\end{methoddesc} + +\begin{methoddesc}{testzip}{} + Read all the files in the archive and check their CRC's and file + headers. Return the name of the first bad file, or else return \code{None}. +\end{methoddesc} + +\begin{methoddesc}{write}{filename\optional{, arcname\optional{, + compress_type}}} + Write the file named \var{filename} to the archive, giving it the + archive name \var{arcname} (by default, this will be the same as + \var{filename}, but without a drive letter and with leading path + separators removed). If given, \var{compress_type} overrides the + value given for the \var{compression} parameter to the constructor + for the new entry. The archive must be open with mode \code{'w'} + or \code{'a'}. + + \note{There is no official file name encoding for ZIP files. + If you have unicode file names, please convert them to byte strings + in your desired encoding before passing them to \method{write()}. + WinZip interprets all file names as encoded in CP437, also known + as DOS Latin.} + + \note{Archive names should be relative to the archive root, that is, + they should not start with a path separator.} +\end{methoddesc} + +\begin{methoddesc}{writestr}{zinfo_or_arcname, bytes} + Write the string \var{bytes} to the archive; \var{zinfo_or_arcname} + is either the file name it will be given in the archive, or a + \class{ZipInfo} instance. If it's an instance, at least the + filename, date, and time must be given. If it's a name, the date + and time is set to the current date and time. The archive must be + opened with mode \code{'w'} or \code{'a'}. +\end{methoddesc} + + +The following data attribute is also available: + +\begin{memberdesc}{debug} + The level of debug output to use. This may be set from \code{0} + (the default, no output) to \code{3} (the most output). Debugging + information is written to \code{sys.stdout}. +\end{memberdesc} + + +\subsection{PyZipFile Objects \label{pyzipfile-objects}} + +The \class{PyZipFile} constructor takes the same parameters as the +\class{ZipFile} constructor. Instances have one method in addition to +those of \class{ZipFile} objects. + +\begin{methoddesc}[PyZipFile]{writepy}{pathname\optional{, basename}} + Search for files \file{*.py} and add the corresponding file to the + archive. The corresponding file is a \file{*.pyo} file if + available, else a \file{*.pyc} file, compiling if necessary. If the + pathname is a file, the filename must end with \file{.py}, and just + the (corresponding \file{*.py[co]}) file is added at the top level + (no path information). If it is a directory, and the directory is + not a package directory, then all the files \file{*.py[co]} are + added at the top level. If the directory is a package directory, + then all \file{*.py[oc]} are added under the package name as a file + path, and if any subdirectories are package directories, all of + these are added recursively. \var{basename} is intended for + internal use only. The \method{writepy()} method makes archives + with file names like this: + +\begin{verbatim} + string.pyc # Top level name + test/__init__.pyc # Package directory + test/testall.pyc # Module test.testall + test/bogus/__init__.pyc # Subpackage directory + test/bogus/myfile.pyc # Submodule test.bogus.myfile +\end{verbatim} +\end{methoddesc} + + +\subsection{ZipInfo Objects \label{zipinfo-objects}} + +Instances of the \class{ZipInfo} class are returned by the +\method{getinfo()} and \method{infolist()} methods of +\class{ZipFile} objects. Each object stores information about a +single member of the ZIP archive. + +Instances have the following attributes: + +\begin{memberdesc}[ZipInfo]{filename} + Name of the file in the archive. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{date_time} + The time and date of the last modification to the archive + member. This is a tuple of six values: + +\begin{tableii}{c|l}{code}{Index}{Value} + \lineii{0}{Year} + \lineii{1}{Month (one-based)} + \lineii{2}{Day of month (one-based)} + \lineii{3}{Hours (zero-based)} + \lineii{4}{Minutes (zero-based)} + \lineii{5}{Seconds (zero-based)} +\end{tableii} +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{compress_type} + Type of compression for the archive member. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{comment} + Comment for the individual archive member. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{extra} + Expansion field data. The + \citetitle[http://www.pkware.com/business_and_developers/developer/appnote/] + {PKZIP Application Note} contains some comments on the internal + structure of the data contained in this string. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{create_system} + System which created ZIP archive. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{create_version} + PKZIP version which created ZIP archive. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{extract_version} + PKZIP version needed to extract archive. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{reserved} + Must be zero. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{flag_bits} + ZIP flag bits. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{volume} + Volume number of file header. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{internal_attr} + Internal attributes. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{external_attr} + External file attributes. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{header_offset} + Byte offset to the file header. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{CRC} + CRC-32 of the uncompressed file. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{compress_size} + Size of the compressed data. +\end{memberdesc} + +\begin{memberdesc}[ZipInfo]{file_size} + Size of the uncompressed file. +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/lib/libzipimport.tex b/sys/src/cmd/python/Doc/lib/libzipimport.tex new file mode 100644 index 000000000..098e78816 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libzipimport.tex @@ -0,0 +1,133 @@ +\section{\module{zipimport} --- + Import modules from Zip archives} + +\declaremodule{standard}{zipimport} +\modulesynopsis{support for importing Python modules from ZIP archives.} +\moduleauthor{Just van Rossum}{just@letterror.com} + +\versionadded{2.3} + +This module adds the ability to import Python modules (\file{*.py}, +\file{*.py[co]}) and packages from ZIP-format archives. It is usually +not needed to use the \module{zipimport} module explicitly; it is +automatically used by the builtin \keyword{import} mechanism for +\code{sys.path} items that are paths to ZIP archives. + +Typically, \code{sys.path} is a list of directory names as strings. This +module also allows an item of \code{sys.path} to be a string naming a ZIP +file archive. The ZIP archive can contain a subdirectory structure to +support package imports, and a path within the archive can be specified to +only import from a subdirectory. For example, the path +\file{/tmp/example.zip/lib/} would only import from the +\file{lib/} subdirectory within the archive. + +Any files may be present in the ZIP archive, but only files \file{.py} and +\file{.py[co]} are available for import. ZIP import of dynamic modules +(\file{.pyd}, \file{.so}) is disallowed. Note that if an archive only +contains \file{.py} files, Python will not attempt to modify the archive +by adding the corresponding \file{.pyc} or \file{.pyo} file, meaning that +if a ZIP archive doesn't contain \file{.pyc} files, importing may be rather +slow. + +Using the built-in \function{reload()} function will +fail if called on a module loaded from a ZIP archive; it is unlikely that +\function{reload()} would be needed, since this would imply that the ZIP +has been altered during runtime. + +The available attributes of this module are: + +\begin{excdesc}{ZipImportError} + Exception raised by zipimporter objects. It's a subclass of + \exception{ImportError}, so it can be caught as \exception{ImportError}, + too. +\end{excdesc} + +\begin{classdesc*}{zipimporter} + The class for importing ZIP files. See + ``\citetitle{zipimporter Objects}'' (section \ref{zipimporter-objects}) + for constructor details. +\end{classdesc*} + + +\begin{seealso} + \seetitle[http://www.pkware.com/business_and_developers/developer/appnote/] + {PKZIP Application Note}{Documentation on the ZIP file format by + Phil Katz, the creator of the format and algorithms used.} + + \seepep{0273}{Import Modules from Zip Archives}{Written by James C. + Ahlstrom, who also provided an implementation. Python 2.3 + follows the specification in PEP 273, but uses an + implementation written by Just van Rossum that uses the import + hooks described in PEP 302.} + + \seepep{0302}{New Import Hooks}{The PEP to add the import hooks that help + this module work.} +\end{seealso} + + +\subsection{zipimporter Objects \label{zipimporter-objects}} + +\begin{classdesc}{zipimporter}{archivepath} + Create a new zipimporter instance. \var{archivepath} must be a path to + a zipfile. \exception{ZipImportError} is raised if \var{archivepath} + doesn't point to a valid ZIP archive. +\end{classdesc} + +\begin{methoddesc}{find_module}{fullname\optional{, path}} + Search for a module specified by \var{fullname}. \var{fullname} must be + the fully qualified (dotted) module name. It returns the zipimporter + instance itself if the module was found, or \constant{None} if it wasn't. + The optional \var{path} argument is ignored---it's there for + compatibility with the importer protocol. +\end{methoddesc} + +\begin{methoddesc}{get_code}{fullname} + Return the code object for the specified module. Raise + \exception{ZipImportError} if the module couldn't be found. +\end{methoddesc} + +\begin{methoddesc}{get_data}{pathname} + Return the data associated with \var{pathname}. Raise \exception{IOError} + if the file wasn't found. +\end{methoddesc} + +\begin{methoddesc}{get_source}{fullname} + Return the source code for the specified module. Raise + \exception{ZipImportError} if the module couldn't be found, return + \constant{None} if the archive does contain the module, but has + no source for it. +\end{methoddesc} + +\begin{methoddesc}{is_package}{fullname} + Return True if the module specified by \var{fullname} is a package. + Raise \exception{ZipImportError} if the module couldn't be found. +\end{methoddesc} + +\begin{methoddesc}{load_module}{fullname} + Load the module specified by \var{fullname}. \var{fullname} must be the + fully qualified (dotted) module name. It returns the imported + module, or raises \exception{ZipImportError} if it wasn't found. +\end{methoddesc} + +\subsection{Examples} +\nodename{zipimport Examples} + +Here is an example that imports a module from a ZIP archive - note that +the \module{zipimport} module is not explicitly used. + +\begin{verbatim} +$ unzip -l /tmp/example.zip +Archive: /tmp/example.zip + Length Date Time Name + -------- ---- ---- ---- + 8467 11-26-02 22:30 jwzthreading.py + -------- ------- + 8467 1 file +$ ./python +Python 2.3 (#1, Aug 1 2003, 19:54:32) +>>> import sys +>>> sys.path.insert(0, '/tmp/example.zip') # Add .zip file to front of path +>>> import jwzthreading +>>> jwzthreading.__file__ +'/tmp/example.zip/jwzthreading.py' +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/lib/libzlib.tex b/sys/src/cmd/python/Doc/lib/libzlib.tex new file mode 100644 index 000000000..876f8c0f7 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/libzlib.tex @@ -0,0 +1,197 @@ +\section{\module{zlib} --- + Compression compatible with \program{gzip}} + +\declaremodule{builtin}{zlib} +\modulesynopsis{Low-level interface to compression and decompression + routines compatible with \program{gzip}.} + + +For applications that require data compression, the functions in this +module allow compression and decompression, using the zlib library. +The zlib library has its own home page at \url{http://www.zlib.net}. +There are known incompatibilities between the Python module and +versions of the zlib library earlier than 1.1.3; 1.1.3 has a security +vulnerability, so we recommend using 1.1.4 or later. + +zlib's functions have many options and often need to be used in a +particular order. This documentation doesn't attempt to cover all of +the permutations; consult the zlib manual at +\url{http://www.zlib.net/manual.html} for authoritative information. + +The available exception and functions in this module are: + +\begin{excdesc}{error} + Exception raised on compression and decompression errors. +\end{excdesc} + + +\begin{funcdesc}{adler32}{string\optional{, value}} + Computes a Adler-32 checksum of \var{string}. (An Adler-32 + checksum is almost as reliable as a CRC32 but can be computed much + more quickly.) If \var{value} is present, it is used as the + starting value of the checksum; otherwise, a fixed default value is + used. This allows computing a running checksum over the + concatenation of several input strings. The algorithm is not + cryptographically strong, and should not be used for + authentication or digital signatures. Since the algorithm is + designed for use as a checksum algorithm, it is not suitable for + use as a general hash algorithm. +\end{funcdesc} + +\begin{funcdesc}{compress}{string\optional{, level}} + Compresses the data in \var{string}, returning a string contained + compressed data. \var{level} is an integer from \code{1} to + \code{9} controlling the level of compression; \code{1} is fastest + and produces the least compression, \code{9} is slowest and produces + the most. The default value is \code{6}. Raises the + \exception{error} exception if any error occurs. +\end{funcdesc} + +\begin{funcdesc}{compressobj}{\optional{level}} + Returns a compression object, to be used for compressing data streams + that won't fit into memory at once. \var{level} is an integer from + \code{1} to \code{9} controlling the level of compression; \code{1} is + fastest and produces the least compression, \code{9} is slowest and + produces the most. The default value is \code{6}. +\end{funcdesc} + +\begin{funcdesc}{crc32}{string\optional{, value}} + Computes a CRC (Cyclic Redundancy Check)% + \index{Cyclic Redundancy Check} + \index{checksum!Cyclic Redundancy Check} + checksum of \var{string}. If + \var{value} is present, it is used as the starting value of the + checksum; otherwise, a fixed default value is used. This allows + computing a running checksum over the concatenation of several + input strings. The algorithm is not cryptographically strong, and + should not be used for authentication or digital signatures. Since + the algorithm is designed for use as a checksum algorithm, it is not + suitable for use as a general hash algorithm. +\end{funcdesc} + +\begin{funcdesc}{decompress}{string\optional{, wbits\optional{, bufsize}}} + Decompresses the data in \var{string}, returning a string containing + the uncompressed data. The \var{wbits} parameter controls the size of + the window buffer. If \var{bufsize} is given, it is used as the + initial size of the output buffer. Raises the \exception{error} + exception if any error occurs. + +The absolute value of \var{wbits} is the base two logarithm of the +size of the history buffer (the ``window size'') used when compressing +data. Its absolute value should be between 8 and 15 for the most +recent versions of the zlib library, larger values resulting in better +compression at the expense of greater memory usage. The default value +is 15. When \var{wbits} is negative, the standard +\program{gzip} header is suppressed; this is an undocumented feature +of the zlib library, used for compatibility with \program{unzip}'s +compression file format. + +\var{bufsize} is the initial size of the buffer used to hold +decompressed data. If more space is required, the buffer size will be +increased as needed, so you don't have to get this value exactly +right; tuning it will only save a few calls to \cfunction{malloc()}. The +default size is 16384. + +\end{funcdesc} + +\begin{funcdesc}{decompressobj}{\optional{wbits}} + Returns a decompression object, to be used for decompressing data + streams that won't fit into memory at once. The \var{wbits} + parameter controls the size of the window buffer. +\end{funcdesc} + +Compression objects support the following methods: + +\begin{methoddesc}[Compress]{compress}{string} +Compress \var{string}, returning a string containing compressed data +for at least part of the data in \var{string}. This data should be +concatenated to the output produced by any preceding calls to the +\method{compress()} method. Some input may be kept in internal buffers +for later processing. +\end{methoddesc} + +\begin{methoddesc}[Compress]{flush}{\optional{mode}} +All pending input is processed, and a string containing the remaining +compressed output is returned. \var{mode} can be selected from the +constants \constant{Z_SYNC_FLUSH}, \constant{Z_FULL_FLUSH}, or +\constant{Z_FINISH}, defaulting to \constant{Z_FINISH}. \constant{Z_SYNC_FLUSH} and +\constant{Z_FULL_FLUSH} allow compressing further strings of data, while +\constant{Z_FINISH} finishes the compressed stream and +prevents compressing any more data. After calling +\method{flush()} with \var{mode} set to \constant{Z_FINISH}, the +\method{compress()} method cannot be called again; the only realistic +action is to delete the object. +\end{methoddesc} + +\begin{methoddesc}[Compress]{copy}{} +Returns a copy of the compression object. This can be used to efficiently +compress a set of data that share a common initial prefix. +\versionadded{2.5} +\end{methoddesc} + +Decompression objects support the following methods, and two attributes: + +\begin{memberdesc}{unused_data} +A string which contains any bytes past the end of the compressed data. +That is, this remains \code{""} until the last byte that contains +compression data is available. If the whole string turned out to +contain compressed data, this is \code{""}, the empty string. + +The only way to determine where a string of compressed data ends is by +actually decompressing it. This means that when compressed data is +contained part of a larger file, you can only find the end of it by +reading data and feeding it followed by some non-empty string into a +decompression object's \method{decompress} method until the +\member{unused_data} attribute is no longer the empty string. +\end{memberdesc} + +\begin{memberdesc}{unconsumed_tail} +A string that contains any data that was not consumed by the last +\method{decompress} call because it exceeded the limit for the +uncompressed data buffer. This data has not yet been seen by the zlib +machinery, so you must feed it (possibly with further data +concatenated to it) back to a subsequent \method{decompress} method +call in order to get correct output. +\end{memberdesc} + + +\begin{methoddesc}[Decompress]{decompress}{string\optional{, max_length}} +Decompress \var{string}, returning a string containing the +uncompressed data corresponding to at least part of the data in +\var{string}. This data should be concatenated to the output produced +by any preceding calls to the +\method{decompress()} method. Some of the input data may be preserved +in internal buffers for later processing. + +If the optional parameter \var{max_length} is supplied then the return value +will be no longer than \var{max_length}. This may mean that not all of the +compressed input can be processed; and unconsumed data will be stored +in the attribute \member{unconsumed_tail}. This string must be passed +to a subsequent call to \method{decompress()} if decompression is to +continue. If \var{max_length} is not supplied then the whole input is +decompressed, and \member{unconsumed_tail} is an empty string. +\end{methoddesc} + +\begin{methoddesc}[Decompress]{flush}{\optional{length}} +All pending input is processed, and a string containing the remaining +uncompressed output is returned. After calling \method{flush()}, the +\method{decompress()} method cannot be called again; the only realistic +action is to delete the object. + +The optional parameter \var{length} sets the initial size of the +output buffer. +\end{methoddesc} + +\begin{methoddesc}[Decompress]{copy}{} +Returns a copy of the decompression object. This can be used to save the +state of the decompressor midway through the data stream in order to speed up +random seeks into the stream at a future point. +\versionadded{2.5} +\end{methoddesc} + +\begin{seealso} + \seemodule{gzip}{Reading and writing \program{gzip}-format files.} + \seeurl{http://www.zlib.net}{The zlib library home page.} + \seeurl{http://www.zlib.net/manual.html}{The zlib manual explains + the semantics and usage of the library's many functions.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/markup.tex b/sys/src/cmd/python/Doc/lib/markup.tex new file mode 100644 index 000000000..0d923a72d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/markup.tex @@ -0,0 +1,29 @@ +\chapter{Structured Markup Processing Tools + \label{markup}} + +Python supports a variety of modules to work with various forms of +structured data markup. This includes modules to work with the +Standard Generalized Markup Language (SGML) and the Hypertext Markup +Language (HTML), and several interfaces for working with the +Extensible Markup Language (XML). + +It is important to note that modules in the \module{xml} package +require that there be at least one SAX-compliant XML parser available. +Starting with Python 2.3, the Expat parser is included with Python, so +the \refmodule{xml.parsers.expat} module will always be available. +You may still want to be aware of the \ulink{PyXML add-on +package}{http://pyxml.sourceforge.net/}; that package provides an +extended set of XML libraries for Python. + +The documentation for the \module{xml.dom} and \module{xml.sax} +packages are the definition of the Python bindings for the DOM and SAX +interfaces. + +\localmoduletable + +\begin{seealso} + \seetitle[http://pyxml.sourceforge.net/] + {Python/XML Libraries} + {Home page for the PyXML package, containing an extension + of \module{xml} package bundled with Python.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/mimelib.tex b/sys/src/cmd/python/Doc/lib/mimelib.tex new file mode 100644 index 000000000..491d844eb --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/mimelib.tex @@ -0,0 +1,65 @@ +% This document is largely a stub used to allow the email package docs +% to be formatted separately from the rest of the Python +% documentation. This allows the documentation to be released +% independently of the rest of Python since the email package is being +% maintained for multiple Python versions, and on an accelerated +% schedule. + +\documentclass{howto} + +\title{email Package Reference} +\author{Barry Warsaw} +\authoraddress{\email{barry@python.org}} + +\date{\today} +\release{4.0} % software release, not documentation +\setreleaseinfo{} % empty for final release +\setshortversion{4.0} % major.minor only for software + +\begin{document} + +\maketitle + +\begin{abstract} + The \module{email} package provides classes and utilities to create, + parse, generate, and modify email messages, conforming to all the + relevant email and MIME related RFCs. +\end{abstract} + +% The ugly "%begin{latexonly}" pseudo-environment suppresses the table +% of contents for HTML generation. +% +%begin{latexonly} +\tableofcontents +%end{latexonly} + +\section{Introduction} +The \module{email} package provides classes and utilities to create, +parse, generate, and modify email messages, conforming to all the +relevant email and MIME related RFCs. + +This document describes version 4.0 of the \module{email} package, which is +distributed with Python 2.5 and is available as a standalone distutils-based +package for use with earlier Python versions. \module{email} 4.0 is not +compatible with Python versions earlier than 2.3. For more information about +the \module{email} package, including download links and mailing lists, see +\ulink{Python's email SIG}{http://www.python.org/sigs/email-sig}. + +The documentation that follows was written for the Python project, so +if you're reading this as part of the standalone \module{email} +package documentation, there are a few notes to be aware of: + +\begin{itemize} +\item Deprecation and ``version added'' notes are relative to the + Python version a feature was added or deprecated. See + the package history in section \ref{email-pkg-history} for details. + +\item If you're reading this documentation as part of the + standalone \module{email} package, some of the internal links to + other sections of the Python standard library may not resolve. + +\end{itemize} + +\input{email} + +\end{document} diff --git a/sys/src/cmd/python/Doc/lib/minidom-example.py b/sys/src/cmd/python/Doc/lib/minidom-example.py new file mode 100644 index 000000000..c30c4e08a --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/minidom-example.py @@ -0,0 +1,64 @@ +import xml.dom.minidom + +document = """\ +<slideshow> +<title>Demo slideshow</title> +<slide><title>Slide title</title> +<point>This is a demo</point> +<point>Of a program for processing slides</point> +</slide> + +<slide><title>Another demo slide</title> +<point>It is important</point> +<point>To have more than</point> +<point>one slide</point> +</slide> +</slideshow> +""" + +dom = xml.dom.minidom.parseString(document) + +def getText(nodelist): + rc = "" + for node in nodelist: + if node.nodeType == node.TEXT_NODE: + rc = rc + node.data + return rc + +def handleSlideshow(slideshow): + print "<html>" + handleSlideshowTitle(slideshow.getElementsByTagName("title")[0]) + slides = slideshow.getElementsByTagName("slide") + handleToc(slides) + handleSlides(slides) + print "</html>" + +def handleSlides(slides): + for slide in slides: + handleSlide(slide) + +def handleSlide(slide): + handleSlideTitle(slide.getElementsByTagName("title")[0]) + handlePoints(slide.getElementsByTagName("point")) + +def handleSlideshowTitle(title): + print "<title>%s</title>" % getText(title.childNodes) + +def handleSlideTitle(title): + print "<h2>%s</h2>" % getText(title.childNodes) + +def handlePoints(points): + print "<ul>" + for point in points: + handlePoint(point) + print "</ul>" + +def handlePoint(point): + print "<li>%s</li>" % getText(point.childNodes) + +def handleToc(slides): + for slide in slides: + title = slide.getElementsByTagName("title")[0] + print "<p>%s</p>" % getText(title.childNodes) + +handleSlideshow(dom) diff --git a/sys/src/cmd/python/Doc/lib/modules.tex b/sys/src/cmd/python/Doc/lib/modules.tex new file mode 100644 index 000000000..e23d05101 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/modules.tex @@ -0,0 +1,9 @@ +\chapter{Importing Modules} +\label{modules} + +The modules described in this chapter provide new ways to import other +Python modules and hooks for customizing the import process. + +The full list of modules described in this chapter is: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/netdata.tex b/sys/src/cmd/python/Doc/lib/netdata.tex new file mode 100644 index 000000000..08062d023 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/netdata.tex @@ -0,0 +1,6 @@ +\chapter{Internet Data Handling \label{netdata}} + +This chapter describes modules which support handling data formats +commonly used on the Internet. + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/numeric.tex b/sys/src/cmd/python/Doc/lib/numeric.tex new file mode 100644 index 000000000..a9a9e18d4 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/numeric.tex @@ -0,0 +1,13 @@ +\chapter{Numeric and Mathematical Modules} +\label{numeric} + +The modules described in this chapter provide +numeric and math-related functions and data types. +The \module{math} and \module{cmath} contain +various mathematical functions for floating-point and complex numbers. +For users more interested in decimal accuracy than in speed, the +\module{decimal} module supports exact representations of decimal numbers. + +The following modules are documented in this chapter: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/persistence.tex b/sys/src/cmd/python/Doc/lib/persistence.tex new file mode 100644 index 000000000..0bcdad21f --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/persistence.tex @@ -0,0 +1,15 @@ +\chapter{Data Persistence} +\label{persistence} + +The modules described in this chapter support storing Python data in a +persistent form on disk. The \module{pickle} and \module{marshal} +modules can turn many Python data types into a stream of bytes and +then recreate the objects from the bytes. The various DBM-related +modules support a family of hash-based file formats that store a +mapping of strings to other strings. The \module{bsddb} module also +provides such disk-based string-to-string mappings based on hashing, +and also supports B-Tree and record-based formats. + +The list of modules described in this chapter is: + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/required_1.py b/sys/src/cmd/python/Doc/lib/required_1.py new file mode 100755 index 000000000..6be5668ee --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/required_1.py @@ -0,0 +1,20 @@ +import optparse + +class OptionParser (optparse.OptionParser): + + def check_required (self, opt): + option = self.get_option(opt) + + # Assumes the option's 'default' is set to None! + if getattr(self.values, option.dest) is None: + self.error("%s option not supplied" % option) + + +parser = OptionParser() +parser.add_option("-v", action="count", dest="verbose") +parser.add_option("-f", "--file", default=None) +(options, args) = parser.parse_args() + +print "verbose:", options.verbose +print "file:", options.file +parser.check_required("-f") diff --git a/sys/src/cmd/python/Doc/lib/required_2.py b/sys/src/cmd/python/Doc/lib/required_2.py new file mode 100755 index 000000000..421514af0 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/required_2.py @@ -0,0 +1,41 @@ +import optparse + +class Option (optparse.Option): + ATTRS = optparse.Option.ATTRS + ['required'] + + def _check_required (self): + if self.required and not self.takes_value(): + raise OptionError( + "required flag set for option that doesn't take a value", + self) + + # Make sure _check_required() is called from the constructor! + CHECK_METHODS = optparse.Option.CHECK_METHODS + [_check_required] + + def process (self, opt, value, values, parser): + optparse.Option.process(self, opt, value, values, parser) + parser.option_seen[self] = 1 + + +class OptionParser (optparse.OptionParser): + + def _init_parsing_state (self): + optparse.OptionParser._init_parsing_state(self) + self.option_seen = {} + + def check_values (self, values, args): + for option in self.option_list: + if (isinstance(option, Option) and + option.required and + not self.option_seen.has_key(option)): + self.error("%s not supplied" % option) + return (values, args) + + +parser = OptionParser(option_list=[ + Option("-v", action="count", dest="verbose"), + Option("-f", "--file", required=1)]) +(options, args) = parser.parse_args() + +print "verbose:", options.verbose +print "file:", options.file diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/adapter_datetime.py b/sys/src/cmd/python/Doc/lib/sqlite3/adapter_datetime.py new file mode 100644 index 000000000..34604985c --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/adapter_datetime.py @@ -0,0 +1,14 @@ +import sqlite3 +import datetime, time + +def adapt_datetime(ts): + return time.mktime(ts.timetuple()) + +sqlite3.register_adapter(datetime.datetime, adapt_datetime) + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +now = datetime.datetime.now() +cur.execute("select ?", (now,)) +print cur.fetchone()[0] diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_1.py b/sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_1.py new file mode 100644 index 000000000..a741f6c25 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_1.py @@ -0,0 +1,16 @@ +import sqlite3 + +class Point(object): + def __init__(self, x, y): + self.x, self.y = x, y + + def __conform__(self, protocol): + if protocol is sqlite3.PrepareProtocol: + return "%f;%f" % (self.x, self.y) + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +p = Point(4.0, -3.2) +cur.execute("select ?", (p,)) +print cur.fetchone()[0] diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_2.py b/sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_2.py new file mode 100644 index 000000000..200a064ea --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/adapter_point_2.py @@ -0,0 +1,17 @@ +import sqlite3 + +class Point(object): + def __init__(self, x, y): + self.x, self.y = x, y + +def adapt_point(point): + return "%f;%f" % (point.x, point.y) + +sqlite3.register_adapter(Point, adapt_point) + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +p = Point(4.0, -3.2) +cur.execute("select ?", (p,)) +print cur.fetchone()[0] diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/collation_reverse.py b/sys/src/cmd/python/Doc/lib/sqlite3/collation_reverse.py new file mode 100644 index 000000000..e9564023d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/collation_reverse.py @@ -0,0 +1,15 @@ +import sqlite3 + +def collate_reverse(string1, string2): + return -cmp(string1, string2) + +con = sqlite3.connect(":memory:") +con.create_collation("reverse", collate_reverse) + +cur = con.cursor() +cur.execute("create table test(x)") +cur.executemany("insert into test(x) values (?)", [("a",), ("b",)]) +cur.execute("select x from test order by x collate reverse") +for row in cur: + print row +con.close() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/complete_statement.py b/sys/src/cmd/python/Doc/lib/sqlite3/complete_statement.py new file mode 100644 index 000000000..22525e310 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/complete_statement.py @@ -0,0 +1,30 @@ +# A minimal SQLite shell for experiments + +import sqlite3 + +con = sqlite3.connect(":memory:") +con.isolation_level = None +cur = con.cursor() + +buffer = "" + +print "Enter your SQL commands to execute in sqlite3." +print "Enter a blank line to exit." + +while True: + line = raw_input() + if line == "": + break + buffer += line + if sqlite3.complete_statement(buffer): + try: + buffer = buffer.strip() + cur.execute(buffer) + + if buffer.lstrip().upper().startswith("SELECT"): + print cur.fetchall() + except sqlite3.Error, e: + print "An error occurred:", e.args[0] + buffer = "" + +con.close() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/connect_db_1.py b/sys/src/cmd/python/Doc/lib/sqlite3/connect_db_1.py new file mode 100644 index 000000000..1b9752328 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/connect_db_1.py @@ -0,0 +1,3 @@ +import sqlite3 + +con = sqlite3.connect("mydb") diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/connect_db_2.py b/sys/src/cmd/python/Doc/lib/sqlite3/connect_db_2.py new file mode 100644 index 000000000..f9728b361 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/connect_db_2.py @@ -0,0 +1,3 @@ +import sqlite3 + +con = sqlite3.connect(":memory:") diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/converter_point.py b/sys/src/cmd/python/Doc/lib/sqlite3/converter_point.py new file mode 100644 index 000000000..e220e9b08 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/converter_point.py @@ -0,0 +1,47 @@ +import sqlite3 + +class Point(object): + def __init__(self, x, y): + self.x, self.y = x, y + + def __repr__(self): + return "(%f;%f)" % (self.x, self.y) + +def adapt_point(point): + return "%f;%f" % (point.x, point.y) + +def convert_point(s): + x, y = map(float, s.split(";")) + return Point(x, y) + +# Register the adapter +sqlite3.register_adapter(Point, adapt_point) + +# Register the converter +sqlite3.register_converter("point", convert_point) + +p = Point(4.0, -3.2) + +######################### +# 1) Using declared types +con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES) +cur = con.cursor() +cur.execute("create table test(p point)") + +cur.execute("insert into test(p) values (?)", (p,)) +cur.execute("select p from test") +print "with declared types:", cur.fetchone()[0] +cur.close() +con.close() + +####################### +# 1) Using column names +con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES) +cur = con.cursor() +cur.execute("create table test(p)") + +cur.execute("insert into test(p) values (?)", (p,)) +cur.execute('select p as "p [point]" from test') +print "with column names:", cur.fetchone()[0] +cur.close() +con.close() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/countcursors.py b/sys/src/cmd/python/Doc/lib/sqlite3/countcursors.py new file mode 100644 index 000000000..df04cad59 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/countcursors.py @@ -0,0 +1,15 @@ +import sqlite3 + +class CountCursorsConnection(sqlite3.Connection): + def __init__(self, *args, **kwargs): + sqlite3.Connection.__init__(self, *args, **kwargs) + self.numcursors = 0 + + def cursor(self, *args, **kwargs): + self.numcursors += 1 + return sqlite3.Connection.cursor(self, *args, **kwargs) + +con = sqlite3.connect(":memory:", factory=CountCursorsConnection) +cur1 = con.cursor() +cur2 = con.cursor() +print con.numcursors diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/createdb.py b/sys/src/cmd/python/Doc/lib/sqlite3/createdb.py new file mode 100644 index 000000000..ee2950bdf --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/createdb.py @@ -0,0 +1,28 @@ +# Not referenced from the documentation, but builds the database file the other +# code snippets expect. + +import sqlite3 +import os + +DB_FILE = "mydb" + +if os.path.exists(DB_FILE): + os.remove(DB_FILE) + +con = sqlite3.connect(DB_FILE) +cur = con.cursor() +cur.execute(""" + create table people + ( + name_last varchar(20), + age integer + ) + """) + +cur.execute("insert into people (name_last, age) values ('Yeltsin', 72)") +cur.execute("insert into people (name_last, age) values ('Putin', 51)") + +con.commit() + +cur.close() +con.close() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/execsql_fetchonerow.py b/sys/src/cmd/python/Doc/lib/sqlite3/execsql_fetchonerow.py new file mode 100644 index 000000000..8044ecf95 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/execsql_fetchonerow.py @@ -0,0 +1,17 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() +SELECT = "select name_last, age from people order by age, name_last" + +# 1. Iterate over the rows available from the cursor, unpacking the +# resulting sequences to yield their elements (name_last, age): +cur.execute(SELECT) +for (name_last, age) in cur: + print '%s is %d years old.' % (name_last, age) + +# 2. Equivalently: +cur.execute(SELECT) +for row in cur: + print '%s is %d years old.' % (row[0], row[1]) diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/execsql_printall_1.py b/sys/src/cmd/python/Doc/lib/sqlite3/execsql_printall_1.py new file mode 100644 index 000000000..d27d735a2 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/execsql_printall_1.py @@ -0,0 +1,13 @@ +import sqlite3 + +# Create a connection to the database file "mydb": +con = sqlite3.connect("mydb") + +# Get a Cursor object that operates in the context of Connection con: +cur = con.cursor() + +# Execute the SELECT statement: +cur.execute("select * from people order by age") + +# Retrieve all rows as a sequence and print that sequence: +print cur.fetchall() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/execute_1.py b/sys/src/cmd/python/Doc/lib/sqlite3/execute_1.py new file mode 100644 index 000000000..fb3784ffb --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/execute_1.py @@ -0,0 +1,11 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() + +who = "Yeltsin" +age = 72 + +cur.execute("select name_last, age from people where name_last=? and age=?", (who, age)) +print cur.fetchone() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/execute_2.py b/sys/src/cmd/python/Doc/lib/sqlite3/execute_2.py new file mode 100644 index 000000000..df6c8940e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/execute_2.py @@ -0,0 +1,12 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() + +who = "Yeltsin" +age = 72 + +cur.execute("select name_last, age from people where name_last=:who and age=:age", + {"who": who, "age": age}) +print cur.fetchone() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/execute_3.py b/sys/src/cmd/python/Doc/lib/sqlite3/execute_3.py new file mode 100644 index 000000000..b64621fc0 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/execute_3.py @@ -0,0 +1,12 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() + +who = "Yeltsin" +age = 72 + +cur.execute("select name_last, age from people where name_last=:who and age=:age", + locals()) +print cur.fetchone() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/executemany_1.py b/sys/src/cmd/python/Doc/lib/sqlite3/executemany_1.py new file mode 100644 index 000000000..24357c52d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/executemany_1.py @@ -0,0 +1,24 @@ +import sqlite3 + +class IterChars: + def __init__(self): + self.count = ord('a') + + def __iter__(self): + return self + + def next(self): + if self.count > ord('z'): + raise StopIteration + self.count += 1 + return (chr(self.count - 1),) # this is a 1-tuple + +con = sqlite3.connect(":memory:") +cur = con.cursor() +cur.execute("create table characters(c)") + +theIter = IterChars() +cur.executemany("insert into characters(c) values (?)", theIter) + +cur.execute("select c from characters") +print cur.fetchall() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/executemany_2.py b/sys/src/cmd/python/Doc/lib/sqlite3/executemany_2.py new file mode 100644 index 000000000..05857c0bd --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/executemany_2.py @@ -0,0 +1,15 @@ +import sqlite3 + +def char_generator(): + import string + for c in string.letters[:26]: + yield (c,) + +con = sqlite3.connect(":memory:") +cur = con.cursor() +cur.execute("create table characters(c)") + +cur.executemany("insert into characters(c) values (?)", char_generator()) + +cur.execute("select c from characters") +print cur.fetchall() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/executescript.py b/sys/src/cmd/python/Doc/lib/sqlite3/executescript.py new file mode 100644 index 000000000..7e5358178 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/executescript.py @@ -0,0 +1,24 @@ +import sqlite3 + +con = sqlite3.connect(":memory:") +cur = con.cursor() +cur.executescript(""" + create table person( + firstname, + lastname, + age + ); + + create table book( + title, + author, + published + ); + + insert into book(title, author, published) + values ( + 'Dirk Gently''s Holistic Detective Agency', + 'Douglas Adams', + 1987 + ); + """) diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/insert_more_people.py b/sys/src/cmd/python/Doc/lib/sqlite3/insert_more_people.py new file mode 100644 index 000000000..edbc79e7e --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/insert_more_people.py @@ -0,0 +1,16 @@ +import sqlite3 + +con = sqlite3.connect("mydb") + +cur = con.cursor() + +newPeople = ( + ('Lebed' , 53), + ('Zhirinovsky' , 57), + ) + +for person in newPeople: + cur.execute("insert into people (name_last, age) values (?, ?)", person) + +# The changes will not be saved unless the transaction is committed explicitly: +con.commit() diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/md5func.py b/sys/src/cmd/python/Doc/lib/sqlite3/md5func.py new file mode 100644 index 000000000..5769687d9 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/md5func.py @@ -0,0 +1,11 @@ +import sqlite3 +import md5 + +def md5sum(t): + return md5.md5(t).hexdigest() + +con = sqlite3.connect(":memory:") +con.create_function("md5", 1, md5sum) +cur = con.cursor() +cur.execute("select md5(?)", ("foo",)) +print cur.fetchone()[0] diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/mysumaggr.py b/sys/src/cmd/python/Doc/lib/sqlite3/mysumaggr.py new file mode 100644 index 000000000..6d0cd551d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/mysumaggr.py @@ -0,0 +1,20 @@ +import sqlite3 + +class MySum: + def __init__(self): + self.count = 0 + + def step(self, value): + self.count += value + + def finalize(self): + return self.count + +con = sqlite3.connect(":memory:") +con.create_aggregate("mysum", 1, MySum) +cur = con.cursor() +cur.execute("create table test(i)") +cur.execute("insert into test(i) values (1)") +cur.execute("insert into test(i) values (2)") +cur.execute("select mysum(i) from test") +print cur.fetchone()[0] diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/parse_colnames.py b/sys/src/cmd/python/Doc/lib/sqlite3/parse_colnames.py new file mode 100644 index 000000000..fcded00f3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/parse_colnames.py @@ -0,0 +1,8 @@ +import sqlite3 +import datetime + +con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES) +cur = con.cursor() +cur.execute('select ? as "x [timestamp]"', (datetime.datetime.now(),)) +dt = cur.fetchone()[0] +print dt, type(dt) diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/pysqlite_datetime.py b/sys/src/cmd/python/Doc/lib/sqlite3/pysqlite_datetime.py new file mode 100644 index 000000000..efa4b06ce --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/pysqlite_datetime.py @@ -0,0 +1,20 @@ +import sqlite3 +import datetime + +con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES) +cur = con.cursor() +cur.execute("create table test(d date, ts timestamp)") + +today = datetime.date.today() +now = datetime.datetime.now() + +cur.execute("insert into test(d, ts) values (?, ?)", (today, now)) +cur.execute("select d, ts from test") +row = cur.fetchone() +print today, "=>", row[0], type(row[0]) +print now, "=>", row[1], type(row[1]) + +cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"') +row = cur.fetchone() +print "current_date", row[0], type(row[0]) +print "current_timestamp", row[1], type(row[1]) diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/row_factory.py b/sys/src/cmd/python/Doc/lib/sqlite3/row_factory.py new file mode 100644 index 000000000..64676c8f3 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/row_factory.py @@ -0,0 +1,13 @@ +import sqlite3 + +def dict_factory(cursor, row): + d = {} + for idx, col in enumerate(cursor.description): + d[col[0]] = row[idx] + return d + +con = sqlite3.connect(":memory:") +con.row_factory = dict_factory +cur = con.cursor() +cur.execute("select 1 as a") +print cur.fetchone()["a"] diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/rowclass.py b/sys/src/cmd/python/Doc/lib/sqlite3/rowclass.py new file mode 100644 index 000000000..3fa0b8738 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/rowclass.py @@ -0,0 +1,12 @@ +import sqlite3 + +con = sqlite3.connect("mydb") +con.row_factory = sqlite3.Row + +cur = con.cursor() +cur.execute("select name_last, age from people") +for row in cur: + assert row[0] == row["name_last"] + assert row["name_last"] == row["nAmE_lAsT"] + assert row[1] == row["age"] + assert row[1] == row["AgE"] diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/shared_cache.py b/sys/src/cmd/python/Doc/lib/sqlite3/shared_cache.py new file mode 100644 index 000000000..bf1d7b4a2 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/shared_cache.py @@ -0,0 +1,6 @@ +import sqlite3 + +# The shared cache is only available in SQLite versions 3.3.3 or later +# See the SQLite documentaton for details. + +sqlite3.enable_shared_cache(True) diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/shortcut_methods.py b/sys/src/cmd/python/Doc/lib/sqlite3/shortcut_methods.py new file mode 100644 index 000000000..72ed4b371 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/shortcut_methods.py @@ -0,0 +1,21 @@ +import sqlite3 + +persons = [ + ("Hugo", "Boss"), + ("Calvin", "Klein") + ] + +con = sqlite3.connect(":memory:") + +# Create the table +con.execute("create table person(firstname, lastname)") + +# Fill the table +con.executemany("insert into person(firstname, lastname) values (?, ?)", persons) + +# Print the table contents +for row in con.execute("select firstname, lastname from person"): + print row + +# Using a dummy WHERE clause to not let SQLite take the shortcut table deletes. +print "I just deleted", con.execute("delete from person where 1=1").rowcount, "rows" diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/simple_tableprinter.py b/sys/src/cmd/python/Doc/lib/sqlite3/simple_tableprinter.py new file mode 100644 index 000000000..67ea6a2b1 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/simple_tableprinter.py @@ -0,0 +1,26 @@ +import sqlite3 + +FIELD_MAX_WIDTH = 20 +TABLE_NAME = 'people' +SELECT = 'select * from %s order by age, name_last' % TABLE_NAME + +con = sqlite3.connect("mydb") + +cur = con.cursor() +cur.execute(SELECT) + +# Print a header. +for fieldDesc in cur.description: + print fieldDesc[0].ljust(FIELD_MAX_WIDTH) , +print # Finish the header with a newline. +print '-' * 78 + +# For each row, print the value of each field left-justified within +# the maximum possible width of that field. +fieldIndices = range(len(cur.description)) +for row in cur: + for fieldIndex in fieldIndices: + fieldValue = str(row[fieldIndex]) + print fieldValue.ljust(FIELD_MAX_WIDTH) , + + print # Finish the row with a newline. diff --git a/sys/src/cmd/python/Doc/lib/sqlite3/text_factory.py b/sys/src/cmd/python/Doc/lib/sqlite3/text_factory.py new file mode 100644 index 000000000..3e157a8ea --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/sqlite3/text_factory.py @@ -0,0 +1,42 @@ +import sqlite3 + +con = sqlite3.connect(":memory:") +cur = con.cursor() + +# Create the table +con.execute("create table person(lastname, firstname)") + +AUSTRIA = u"\xd6sterreich" + +# by default, rows are returned as Unicode +cur.execute("select ?", (AUSTRIA,)) +row = cur.fetchone() +assert row[0] == AUSTRIA + +# but we can make pysqlite always return bytestrings ... +con.text_factory = str +cur.execute("select ?", (AUSTRIA,)) +row = cur.fetchone() +assert type(row[0]) == str +# the bytestrings will be encoded in UTF-8, unless you stored garbage in the +# database ... +assert row[0] == AUSTRIA.encode("utf-8") + +# we can also implement a custom text_factory ... +# here we implement one that will ignore Unicode characters that cannot be +# decoded from UTF-8 +con.text_factory = lambda x: unicode(x, "utf-8", "ignore") +cur.execute("select ?", ("this is latin1 and would normally create errors" + u"\xe4\xf6\xfc".encode("latin1"),)) +row = cur.fetchone() +assert type(row[0]) == unicode + +# pysqlite offers a builtin optimized text_factory that will return bytestring +# objects, if the data is in ASCII only, and otherwise return unicode objects +con.text_factory = sqlite3.OptimizedUnicode +cur.execute("select ?", (AUSTRIA,)) +row = cur.fetchone() +assert type(row[0]) == unicode + +cur.execute("select ?", ("Germany",)) +row = cur.fetchone() +assert type(row[0]) == str diff --git a/sys/src/cmd/python/Doc/lib/tkinter.tex b/sys/src/cmd/python/Doc/lib/tkinter.tex new file mode 100644 index 000000000..20b23730d --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/tkinter.tex @@ -0,0 +1,1873 @@ +\chapter{Graphical User Interfaces with Tk \label{tkinter}} + +\index{GUI} +\index{Graphical User Interface} +\index{Tkinter} +\index{Tk} + +Tk/Tcl has long been an integral part of Python. It provides a robust +and platform independent windowing toolkit, that is available to +Python programmers using the \refmodule{Tkinter} module, and its +extension, the \refmodule{Tix} module. + +The \refmodule{Tkinter} module is a thin object-oriented layer on top of +Tcl/Tk. To use \refmodule{Tkinter}, you don't need to write Tcl code, +but you will need to consult the Tk documentation, and occasionally +the Tcl documentation. \refmodule{Tkinter} is a set of wrappers that +implement the Tk widgets as Python classes. In addition, the internal +module \module{\_tkinter} provides a threadsafe mechanism which allows +Python and Tcl to interact. + +Tk is not the only GUI for Python; see +section~\ref{other-gui-packages}, ``Other User Interface Modules and +Packages,'' for more information on other GUI toolkits for Python. + +% Other sections I have in mind are +% Tkinter internals +% Freezing Tkinter applications + +\localmoduletable + + +\section{\module{Tkinter} --- + Python interface to Tcl/Tk} + +\declaremodule{standard}{Tkinter} +\modulesynopsis{Interface to Tcl/Tk for graphical user interfaces} +\moduleauthor{Guido van Rossum}{guido@Python.org} + +The \module{Tkinter} module (``Tk interface'') is the standard Python +interface to the Tk GUI toolkit. Both Tk and \module{Tkinter} are +available on most \UNIX{} platforms, as well as on Windows and +Macintosh systems. (Tk itself is not part of Python; it is maintained +at ActiveState.) + +\begin{seealso} +\seetitle[http://www.python.org/topics/tkinter/] + {Python Tkinter Resources} + {The Python Tkinter Topic Guide provides a great + deal of information on using Tk from Python and links to + other sources of information on Tk.} + +\seetitle[http://www.pythonware.com/library/an-introduction-to-tkinter.htm] + {An Introduction to Tkinter} + {Fredrik Lundh's on-line reference material.} + +\seetitle[http://www.nmt.edu/tcc/help/pubs/lang.html] + {Tkinter reference: a GUI for Python} + {On-line reference material.} + +\seetitle[http://jtkinter.sourceforge.net] + {Tkinter for JPython} + {The Jython interface to Tkinter.} + +\seetitle[http://www.amazon.com/exec/obidos/ASIN/1884777813] + {Python and Tkinter Programming} + {The book by John Grayson (ISBN 1-884777-81-3).} +\end{seealso} + + +\subsection{Tkinter Modules} + +Most of the time, the \refmodule{Tkinter} module is all you really +need, but a number of additional modules are available as well. The +Tk interface is located in a binary module named \module{_tkinter}. +This module contains the low-level interface to Tk, and should never +be used directly by application programmers. It is usually a shared +library (or DLL), but might in some cases be statically linked with +the Python interpreter. + +In addition to the Tk interface module, \refmodule{Tkinter} includes a +number of Python modules. The two most important modules are the +\refmodule{Tkinter} module itself, and a module called +\module{Tkconstants}. The former automatically imports the latter, so +to use Tkinter, all you need to do is to import one module: + +\begin{verbatim} +import Tkinter +\end{verbatim} + +Or, more often: + +\begin{verbatim} +from Tkinter import * +\end{verbatim} + +\begin{classdesc}{Tk}{screenName=None, baseName=None, className='Tk', useTk=1} +The \class{Tk} class is instantiated without arguments. +This creates a toplevel widget of Tk which usually is the main window +of an application. Each instance has its own associated Tcl interpreter. +% FIXME: The following keyword arguments are currently recognized: +\versionchanged[The \var{useTk} parameter was added]{2.4} +\end{classdesc} + +\begin{funcdesc}{Tcl}{screenName=None, baseName=None, className='Tk', useTk=0} +The \function{Tcl} function is a factory function which creates an +object much like that created by the \class{Tk} class, except that it +does not initialize the Tk subsystem. This is most often useful when +driving the Tcl interpreter in an environment where one doesn't want +to create extraneous toplevel windows, or where one cannot (such as +\UNIX/Linux systems without an X server). An object created by the +\function{Tcl} object can have a Toplevel window created (and the Tk +subsystem initialized) by calling its \method{loadtk} method. +\versionadded{2.4} +\end{funcdesc} + +Other modules that provide Tk support include: + +\begin{description} +% \declaremodule{standard}{Tkconstants} +% \modulesynopsis{Constants used by Tkinter} +% FIXME + +\item[\refmodule{ScrolledText}] +Text widget with a vertical scroll bar built in. + +\item[\module{tkColorChooser}] +Dialog to let the user choose a color. + +\item[\module{tkCommonDialog}] +Base class for the dialogs defined in the other modules listed here. + +\item[\module{tkFileDialog}] +Common dialogs to allow the user to specify a file to open or save. + +\item[\module{tkFont}] +Utilities to help work with fonts. + +\item[\module{tkMessageBox}] +Access to standard Tk dialog boxes. + +\item[\module{tkSimpleDialog}] +Basic dialogs and convenience functions. + +\item[\module{Tkdnd}] +Drag-and-drop support for \refmodule{Tkinter}. +This is experimental and should become deprecated when it is replaced +with the Tk DND. + +\item[\refmodule{turtle}] +Turtle graphics in a Tk window. + +\end{description} + +\subsection{Tkinter Life Preserver} +\sectionauthor{Matt Conway}{} +% Converted to LaTeX by Mike Clarkson. + +This section is not designed to be an exhaustive tutorial on either +Tk or Tkinter. Rather, it is intended as a stop gap, providing some +introductory orientation on the system. + +Credits: +\begin{itemize} +\item Tkinter was written by Steen Lumholt and Guido van Rossum. +\item Tk was written by John Ousterhout while at Berkeley. +\item This Life Preserver was written by Matt Conway at +the University of Virginia. +\item The html rendering, and some liberal editing, was +produced from a FrameMaker version by Ken Manheimer. +\item Fredrik Lundh elaborated and revised the class interface descriptions, +to get them current with Tk 4.2. +\item Mike Clarkson converted the documentation to \LaTeX, and compiled the +User Interface chapter of the reference manual. +\end{itemize} + + +\subsubsection{How To Use This Section} + +This section is designed in two parts: the first half (roughly) covers +background material, while the second half can be taken to the +keyboard as a handy reference. + +When trying to answer questions of the form ``how do I do blah'', it +is often best to find out how to do``blah'' in straight Tk, and then +convert this back into the corresponding \refmodule{Tkinter} call. +Python programmers can often guess at the correct Python command by +looking at the Tk documentation. This means that in order to use +Tkinter, you will have to know a little bit about Tk. This document +can't fulfill that role, so the best we can do is point you to the +best documentation that exists. Here are some hints: + +\begin{itemize} +\item The authors strongly suggest getting a copy of the Tk man +pages. Specifically, the man pages in the \code{mann} directory are most +useful. The \code{man3} man pages describe the C interface to the Tk +library and thus are not especially helpful for script writers. + +\item Addison-Wesley publishes a book called \citetitle{Tcl and the +Tk Toolkit} by John Ousterhout (ISBN 0-201-63337-X) which is a good +introduction to Tcl and Tk for the novice. The book is not +exhaustive, and for many details it defers to the man pages. + +\item \file{Tkinter.py} is a last resort for most, but can be a good +place to go when nothing else makes sense. +\end{itemize} + +\begin{seealso} +\seetitle[http://tcl.activestate.com/] + {ActiveState Tcl Home Page} + {The Tk/Tcl development is largely taking place at + ActiveState.} +\seetitle[http://www.amazon.com/exec/obidos/ASIN/020163337X] + {Tcl and the Tk Toolkit} + {The book by John Ousterhout, the inventor of Tcl .} +\seetitle[http://www.amazon.com/exec/obidos/ASIN/0130220280] + {Practical Programming in Tcl and Tk} + {Brent Welch's encyclopedic book.} +\end{seealso} + + +\subsubsection{A Simple Hello World Program} % HelloWorld.html + +%begin{latexonly} +%\begin{figure}[hbtp] +%\centerline{\epsfig{file=HelloWorld.gif,width=.9\textwidth}} +%\vspace{.5cm} +%\caption{HelloWorld gadget image} +%\end{figure} +%See also the hello-world \ulink{notes}{classes/HelloWorld-notes.html} and +%\ulink{summary}{classes/HelloWorld-summary.html}. +%end{latexonly} + + +\begin{verbatim} +from Tkinter import * + +class Application(Frame): + def say_hi(self): + print "hi there, everyone!" + + def createWidgets(self): + self.QUIT = Button(self) + self.QUIT["text"] = "QUIT" + self.QUIT["fg"] = "red" + self.QUIT["command"] = self.quit + + self.QUIT.pack({"side": "left"}) + + self.hi_there = Button(self) + self.hi_there["text"] = "Hello", + self.hi_there["command"] = self.say_hi + + self.hi_there.pack({"side": "left"}) + + def __init__(self, master=None): + Frame.__init__(self, master) + self.pack() + self.createWidgets() + +root = Tk() +app = Application(master=root) +app.mainloop() +root.destroy() +\end{verbatim} + + +\subsection{A (Very) Quick Look at Tcl/Tk} % BriefTclTk.html + +The class hierarchy looks complicated, but in actual practice, +application programmers almost always refer to the classes at the very +bottom of the hierarchy. + +Notes: +\begin{itemize} +\item These classes are provided for the purposes of +organizing certain functions under one namespace. They aren't meant to +be instantiated independently. + +\item The \class{Tk} class is meant to be instantiated only once in +an application. Application programmers need not instantiate one +explicitly, the system creates one whenever any of the other classes +are instantiated. + +\item The \class{Widget} class is not meant to be instantiated, it +is meant only for subclassing to make ``real'' widgets (in \Cpp, this +is called an `abstract class'). +\end{itemize} + +To make use of this reference material, there will be times when you +will need to know how to read short passages of Tk and how to identify +the various parts of a Tk command. +(See section~\ref{tkinter-basic-mapping} for the +\refmodule{Tkinter} equivalents of what's below.) + +Tk scripts are Tcl programs. Like all Tcl programs, Tk scripts are +just lists of tokens separated by spaces. A Tk widget is just its +\emph{class}, the \emph{options} that help configure it, and the +\emph{actions} that make it do useful things. + +To make a widget in Tk, the command is always of the form: + +\begin{verbatim} + classCommand newPathname options +\end{verbatim} + +\begin{description} +\item[\var{classCommand}] +denotes which kind of widget to make (a button, a label, a menu...) + +\item[\var{newPathname}] +is the new name for this widget. All names in Tk must be unique. To +help enforce this, widgets in Tk are named with \emph{pathnames}, just +like files in a file system. The top level widget, the \emph{root}, +is called \code{.} (period) and children are delimited by more +periods. For example, \code{.myApp.controlPanel.okButton} might be +the name of a widget. + +\item[\var{options}] +configure the widget's appearance and in some cases, its +behavior. The options come in the form of a list of flags and values. +Flags are preceded by a `-', like \UNIX{} shell command flags, and +values are put in quotes if they are more than one word. +\end{description} + +For example: + +\begin{verbatim} + button .fred -fg red -text "hi there" + ^ ^ \_____________________/ + | | | + class new options + command widget (-opt val -opt val ...) +\end{verbatim} + +Once created, the pathname to the widget becomes a new command. This +new \var{widget command} is the programmer's handle for getting the new +widget to perform some \var{action}. In C, you'd express this as +someAction(fred, someOptions), in \Cpp, you would express this as +fred.someAction(someOptions), and in Tk, you say: + +\begin{verbatim} + .fred someAction someOptions +\end{verbatim} + +Note that the object name, \code{.fred}, starts with a dot. + +As you'd expect, the legal values for \var{someAction} will depend on +the widget's class: \code{.fred disable} works if fred is a +button (fred gets greyed out), but does not work if fred is a label +(disabling of labels is not supported in Tk). + +The legal values of \var{someOptions} is action dependent. Some +actions, like \code{disable}, require no arguments, others, like +a text-entry box's \code{delete} command, would need arguments +to specify what range of text to delete. + + +\subsection{Mapping Basic Tk into Tkinter + \label{tkinter-basic-mapping}} + +Class commands in Tk correspond to class constructors in Tkinter. + +\begin{verbatim} + button .fred =====> fred = Button() +\end{verbatim} + +The master of an object is implicit in the new name given to it at +creation time. In Tkinter, masters are specified explicitly. + +\begin{verbatim} + button .panel.fred =====> fred = Button(panel) +\end{verbatim} + +The configuration options in Tk are given in lists of hyphened tags +followed by values. In Tkinter, options are specified as +keyword-arguments in the instance constructor, and keyword-args for +configure calls or as instance indices, in dictionary style, for +established instances. See section~\ref{tkinter-setting-options} on +setting options. + +\begin{verbatim} + button .fred -fg red =====> fred = Button(panel, fg = "red") + .fred configure -fg red =====> fred["fg"] = red + OR ==> fred.config(fg = "red") +\end{verbatim} + +In Tk, to perform an action on a widget, use the widget name as a +command, and follow it with an action name, possibly with arguments +(options). In Tkinter, you call methods on the class instance to +invoke actions on the widget. The actions (methods) that a given +widget can perform are listed in the Tkinter.py module. + +\begin{verbatim} + .fred invoke =====> fred.invoke() +\end{verbatim} + +To give a widget to the packer (geometry manager), you call pack with +optional arguments. In Tkinter, the Pack class holds all this +functionality, and the various forms of the pack command are +implemented as methods. All widgets in \refmodule{Tkinter} are +subclassed from the Packer, and so inherit all the packing +methods. See the \refmodule{Tix} module documentation for additional +information on the Form geometry manager. + +\begin{verbatim} + pack .fred -side left =====> fred.pack(side = "left") +\end{verbatim} + + +\subsection{How Tk and Tkinter are Related} % Relationship.html + +\note{This was derived from a graphical image; the image will be used + more directly in a subsequent version of this document.} + +From the top down: +\begin{description} +\item[\b{Your App Here (Python)}] +A Python application makes a \refmodule{Tkinter} call. + +\item[\b{Tkinter (Python Module)}] +This call (say, for example, creating a button widget), is +implemented in the \emph{Tkinter} module, which is written in +Python. This Python function will parse the commands and the +arguments and convert them into a form that makes them look as if they +had come from a Tk script instead of a Python script. + +\item[\b{tkinter (C)}] +These commands and their arguments will be passed to a C function +in the \emph{tkinter} - note the lowercase - extension module. + +\item[\b{Tk Widgets} (C and Tcl)] +This C function is able to make calls into other C modules, +including the C functions that make up the Tk library. Tk is +implemented in C and some Tcl. The Tcl part of the Tk widgets is used +to bind certain default behaviors to widgets, and is executed once at +the point where the Python \refmodule{Tkinter} module is +imported. (The user never sees this stage). + +\item[\b{Tk (C)}] +The Tk part of the Tk Widgets implement the final mapping to ... + +\item[\b{Xlib (C)}] +the Xlib library to draw graphics on the screen. +\end{description} + + +\subsection{Handy Reference} + +\subsubsection{Setting Options + \label{tkinter-setting-options}} + +Options control things like the color and border width of a widget. +Options can be set in three ways: + +\begin{description} +\item[At object creation time, using keyword arguments]: +\begin{verbatim} +fred = Button(self, fg = "red", bg = "blue") +\end{verbatim} +\item[After object creation, treating the option name like a dictionary index]: +\begin{verbatim} +fred["fg"] = "red" +fred["bg"] = "blue" +\end{verbatim} +\item[Use the config() method to update multiple attrs subsequent to +object creation]: +\begin{verbatim} +fred.config(fg = "red", bg = "blue") +\end{verbatim} +\end{description} + +For a complete explanation of a given option and its behavior, see the +Tk man pages for the widget in question. + +Note that the man pages list "STANDARD OPTIONS" and "WIDGET SPECIFIC +OPTIONS" for each widget. The former is a list of options that are +common to many widgets, the latter are the options that are +idiosyncratic to that particular widget. The Standard Options are +documented on the \manpage{options}{3} man page. + +No distinction between standard and widget-specific options is made in +this document. Some options don't apply to some kinds of widgets. +Whether a given widget responds to a particular option depends on the +class of the widget; buttons have a \code{command} option, labels do not. + +The options supported by a given widget are listed in that widget's +man page, or can be queried at runtime by calling the +\method{config()} method without arguments, or by calling the +\method{keys()} method on that widget. The return value of these +calls is a dictionary whose key is the name of the option as a string +(for example, \code{'relief'}) and whose values are 5-tuples. + +Some options, like \code{bg} are synonyms for common options with long +names (\code{bg} is shorthand for "background"). Passing the +\code{config()} method the name of a shorthand option will return a +2-tuple, not 5-tuple. The 2-tuple passed back will contain the name of +the synonym and the ``real'' option (such as \code{('bg', +'background')}). + +\begin{tableiii}{c|l|l}{textrm}{Index}{Meaning}{Example} + \lineiii{0}{option name} {\code{'relief'}} + \lineiii{1}{option name for database lookup} {\code{'relief'}} + \lineiii{2}{option class for database lookup} {\code{'Relief'}} + \lineiii{3}{default value} {\code{'raised'}} + \lineiii{4}{current value} {\code{'groove'}} +\end{tableiii} + + +Example: + +\begin{verbatim} +>>> print fred.config() +{'relief' : ('relief', 'relief', 'Relief', 'raised', 'groove')} +\end{verbatim} + +Of course, the dictionary printed will include all the options +available and their values. This is meant only as an example. + + +\subsubsection{The Packer} % Packer.html +\index{packing (widgets)} + +The packer is one of Tk's geometry-management mechanisms. +% See also \citetitle[classes/ClassPacker.html]{the Packer class interface}. + +Geometry managers are used to specify the relative positioning of the +positioning of widgets within their container - their mutual +\emph{master}. In contrast to the more cumbersome \emph{placer} +(which is used less commonly, and we do not cover here), the packer +takes qualitative relationship specification - \emph{above}, \emph{to +the left of}, \emph{filling}, etc - and works everything out to +determine the exact placement coordinates for you. + +The size of any \emph{master} widget is determined by the size of +the "slave widgets" inside. The packer is used to control where slave +widgets appear inside the master into which they are packed. You can +pack widgets into frames, and frames into other frames, in order to +achieve the kind of layout you desire. Additionally, the arrangement +is dynamically adjusted to accommodate incremental changes to the +configuration, once it is packed. + +Note that widgets do not appear until they have had their geometry +specified with a geometry manager. It's a common early mistake to +leave out the geometry specification, and then be surprised when the +widget is created but nothing appears. A widget will appear only +after it has had, for example, the packer's \method{pack()} method +applied to it. + +The pack() method can be called with keyword-option/value pairs that +control where the widget is to appear within its container, and how it +is to behave when the main application window is resized. Here are +some examples: + +\begin{verbatim} + fred.pack() # defaults to side = "top" + fred.pack(side = "left") + fred.pack(expand = 1) +\end{verbatim} + + +\subsubsection{Packer Options} + +For more extensive information on the packer and the options that it +can take, see the man pages and page 183 of John Ousterhout's book. + +\begin{description} +\item[\b{anchor }] +Anchor type. Denotes where the packer is to place each slave in its +parcel. + +\item[\b{expand}] +Boolean, \code{0} or \code{1}. + +\item[\b{fill}] +Legal values: \code{'x'}, \code{'y'}, \code{'both'}, \code{'none'}. + +\item[\b{ipadx} and \b{ipady}] +A distance - designating internal padding on each side of the slave +widget. + +\item[\b{padx} and \b{pady}] +A distance - designating external padding on each side of the slave +widget. + +\item[\b{side}] +Legal values are: \code{'left'}, \code{'right'}, \code{'top'}, +\code{'bottom'}. +\end{description} + + +\subsubsection{Coupling Widget Variables} % VarCouplings.html + +The current-value setting of some widgets (like text entry widgets) +can be connected directly to application variables by using special +options. These options are \code{variable}, \code{textvariable}, +\code{onvalue}, \code{offvalue}, and \code{value}. This +connection works both ways: if the variable changes for any reason, +the widget it's connected to will be updated to reflect the new value. + +Unfortunately, in the current implementation of \refmodule{Tkinter} it is +not possible to hand over an arbitrary Python variable to a widget +through a \code{variable} or \code{textvariable} option. The only +kinds of variables for which this works are variables that are +subclassed from a class called Variable, defined in the +\refmodule{Tkinter} module. + +There are many useful subclasses of Variable already defined: +\class{StringVar}, \class{IntVar}, \class{DoubleVar}, and +\class{BooleanVar}. To read the current value of such a variable, +call the \method{get()} method on +it, and to change its value you call the \method{set()} method. If +you follow this protocol, the widget will always track the value of +the variable, with no further intervention on your part. + +For example: +\begin{verbatim} +class App(Frame): + def __init__(self, master=None): + Frame.__init__(self, master) + self.pack() + + self.entrythingy = Entry() + self.entrythingy.pack() + + # here is the application variable + self.contents = StringVar() + # set it to some value + self.contents.set("this is a variable") + # tell the entry widget to watch this variable + self.entrythingy["textvariable"] = self.contents + + # and here we get a callback when the user hits return. + # we will have the program print out the value of the + # application variable when the user hits return + self.entrythingy.bind('<Key-Return>', + self.print_contents) + + def print_contents(self, event): + print "hi. contents of entry is now ---->", \ + self.contents.get() +\end{verbatim} + + +\subsubsection{The Window Manager} % WindowMgr.html +\index{window manager (widgets)} + +In Tk, there is a utility command, \code{wm}, for interacting with the +window manager. Options to the \code{wm} command allow you to control +things like titles, placement, icon bitmaps, and the like. In +\refmodule{Tkinter}, these commands have been implemented as methods +on the \class{Wm} class. Toplevel widgets are subclassed from the +\class{Wm} class, and so can call the \class{Wm} methods directly. + +%See also \citetitle[classes/ClassWm.html]{the Wm class interface}. + +To get at the toplevel window that contains a given widget, you can +often just refer to the widget's master. Of course if the widget has +been packed inside of a frame, the master won't represent a toplevel +window. To get at the toplevel window that contains an arbitrary +widget, you can call the \method{_root()} method. This +method begins with an underscore to denote the fact that this function +is part of the implementation, and not an interface to Tk functionality. + +Here are some examples of typical usage: + +\begin{verbatim} +from Tkinter import * +class App(Frame): + def __init__(self, master=None): + Frame.__init__(self, master) + self.pack() + + +# create the application +myapp = App() + +# +# here are method calls to the window manager class +# +myapp.master.title("My Do-Nothing Application") +myapp.master.maxsize(1000, 400) + +# start the program +myapp.mainloop() +\end{verbatim} + + +\subsubsection{Tk Option Data Types} % OptionTypes.html + +\index{Tk Option Data Types} + +\begin{description} +\item[anchor] +Legal values are points of the compass: \code{"n"}, +\code{"ne"}, \code{"e"}, \code{"se"}, \code{"s"}, +\code{"sw"}, \code{"w"}, \code{"nw"}, and also +\code{"center"}. + +\item[bitmap] +There are eight built-in, named bitmaps: \code{'error'}, \code{'gray25'}, +\code{'gray50'}, \code{'hourglass'}, \code{'info'}, \code{'questhead'}, +\code{'question'}, \code{'warning'}. To specify an X bitmap +filename, give the full path to the file, preceded with an \code{@}, +as in \code{"@/usr/contrib/bitmap/gumby.bit"}. + +\item[boolean] +You can pass integers 0 or 1 or the strings \code{"yes"} or \code{"no"} . + +\item[callback] +This is any Python function that takes no arguments. For example: +\begin{verbatim} + def print_it(): + print "hi there" + fred["command"] = print_it +\end{verbatim} + +\item[color] +Colors can be given as the names of X colors in the rgb.txt file, +or as strings representing RGB values in 4 bit: \code{"\#RGB"}, 8 +bit: \code{"\#RRGGBB"}, 12 bit" \code{"\#RRRGGGBBB"}, or 16 bit +\code{"\#RRRRGGGGBBBB"} ranges, where R,G,B here represent any +legal hex digit. See page 160 of Ousterhout's book for details. + +\item[cursor] +The standard X cursor names from \file{cursorfont.h} can be used, +without the \code{XC_} prefix. For example to get a hand cursor +(\constant{XC_hand2}), use the string \code{"hand2"}. You can also +specify a bitmap and mask file of your own. See page 179 of +Ousterhout's book. + +\item[distance] +Screen distances can be specified in either pixels or absolute +distances. Pixels are given as numbers and absolute distances as +strings, with the trailing character denoting units: \code{c} +for centimetres, \code{i} for inches, \code{m} for millimetres, +\code{p} for printer's points. For example, 3.5 inches is expressed +as \code{"3.5i"}. + +\item[font] +Tk uses a list font name format, such as \code{\{courier 10 bold\}}. +Font sizes with positive numbers are measured in points; +sizes with negative numbers are measured in pixels. + +\item[geometry] +This is a string of the form \samp{\var{width}x\var{height}}, where +width and height are measured in pixels for most widgets (in +characters for widgets displaying text). For example: +\code{fred["geometry"] = "200x100"}. + +\item[justify] +Legal values are the strings: \code{"left"}, +\code{"center"}, \code{"right"}, and \code{"fill"}. + +\item[region] +This is a string with four space-delimited elements, each of +which is a legal distance (see above). For example: \code{"2 3 4 +5"} and \code{"3i 2i 4.5i 2i"} and \code{"3c 2c 4c 10.43c"} +are all legal regions. + +\item[relief] +Determines what the border style of a widget will be. Legal +values are: \code{"raised"}, \code{"sunken"}, +\code{"flat"}, \code{"groove"}, and \code{"ridge"}. + +\item[scrollcommand] +This is almost always the \method{set()} method of some scrollbar +widget, but can be any widget method that takes a single argument. +Refer to the file \file{Demo/tkinter/matt/canvas-with-scrollbars.py} +in the Python source distribution for an example. + +\item[wrap:] +Must be one of: \code{"none"}, \code{"char"}, or \code{"word"}. +\end{description} + + +\subsubsection{Bindings and Events} % Bindings.html + +\index{bind (widgets)} +\index{events (widgets)} + +The bind method from the widget command allows you to watch for +certain events and to have a callback function trigger when that event +type occurs. The form of the bind method is: + +\begin{verbatim} + def bind(self, sequence, func, add=''): +\end{verbatim} +where: + +\begin{description} +\item[sequence] +is a string that denotes the target kind of event. (See the bind +man page and page 201 of John Ousterhout's book for details). + +\item[func] +is a Python function, taking one argument, to be invoked when the +event occurs. An Event instance will be passed as the argument. +(Functions deployed this way are commonly known as \var{callbacks}.) + +\item[add] +is optional, either \samp{} or \samp{+}. Passing an empty string +denotes that this binding is to replace any other bindings that this +event is associated with. Preceeding with a \samp{+} means that this +function is to be added to the list of functions bound to this event type. +\end{description} + +For example: +\begin{verbatim} + def turnRed(self, event): + event.widget["activeforeground"] = "red" + + self.button.bind("<Enter>", self.turnRed) +\end{verbatim} + +Notice how the widget field of the event is being accessed in the +\method{turnRed()} callback. This field contains the widget that +caught the X event. The following table lists the other event fields +you can access, and how they are denoted in Tk, which can be useful +when referring to the Tk man pages. + +\begin{verbatim} +Tk Tkinter Event Field Tk Tkinter Event Field +-- ------------------- -- ------------------- +%f focus %A char +%h height %E send_event +%k keycode %K keysym +%s state %N keysym_num +%t time %T type +%w width %W widget +%x x %X x_root +%y y %Y y_root +\end{verbatim} + + +\subsubsection{The index Parameter} % Index.html + +A number of widgets require``index'' parameters to be passed. These +are used to point at a specific place in a Text widget, or to +particular characters in an Entry widget, or to particular menu items +in a Menu widget. + +\begin{description} +\item[\b{Entry widget indexes (index, view index, etc.)}] +Entry widgets have options that refer to character positions in the +text being displayed. You can use these \refmodule{Tkinter} functions +to access these special points in text widgets: + +\begin{description} +\item[AtEnd()] +refers to the last position in the text + +\item[AtInsert()] +refers to the point where the text cursor is + +\item[AtSelFirst()] +indicates the beginning point of the selected text + +\item[AtSelLast()] +denotes the last point of the selected text and finally + +\item[At(x\optional{, y})] +refers to the character at pixel location \var{x}, \var{y} (with +\var{y} not used in the case of a text entry widget, which contains a +single line of text). +\end{description} + +\item[\b{Text widget indexes}] +The index notation for Text widgets is very rich and is best described +in the Tk man pages. + +\item[\b{Menu indexes (menu.invoke(), menu.entryconfig(), etc.)}] + +Some options and methods for menus manipulate specific menu entries. +Anytime a menu index is needed for an option or a parameter, you may +pass in: +\begin{itemize} +\item an integer which refers to the numeric position of the entry in +the widget, counted from the top, starting with 0; +\item the string \code{'active'}, which refers to the menu position that is +currently under the cursor; +\item the string \code{"last"} which refers to the last menu +item; +\item An integer preceded by \code{@}, as in \code{@6}, where the integer is +interpreted as a y pixel coordinate in the menu's coordinate system; +\item the string \code{"none"}, which indicates no menu entry at all, most +often used with menu.activate() to deactivate all entries, and +finally, +\item a text string that is pattern matched against the label of the +menu entry, as scanned from the top of the menu to the bottom. Note +that this index type is considered after all the others, which means +that matches for menu items labelled \code{last}, \code{active}, or +\code{none} may be interpreted as the above literals, instead. +\end{itemize} +\end{description} + +\subsubsection{Images} + +Bitmap/Pixelmap images can be created through the subclasses of +\class{Tkinter.Image}: + +\begin{itemize} +\item \class{BitmapImage} can be used for X11 bitmap data. +\item \class{PhotoImage} can be used for GIF and PPM/PGM color bitmaps. +\end{itemize} + +Either type of image is created through either the \code{file} or the +\code{data} option (other options are available as well). + +The image object can then be used wherever an \code{image} option is +supported by some widget (e.g. labels, buttons, menus). In these +cases, Tk will not keep a reference to the image. When the last Python +reference to the image object is deleted, the image data is deleted as +well, and Tk will display an empty box wherever the image was used. + +\section{\module{Tix} --- + Extension widgets for Tk} + +\declaremodule{standard}{Tix} +\modulesynopsis{Tk Extension Widgets for Tkinter} +\sectionauthor{Mike Clarkson}{mikeclarkson@users.sourceforge.net} + +\index{Tix} + +The \module{Tix} (Tk Interface Extension) module provides an +additional rich set of widgets. Although the standard Tk library has +many useful widgets, they are far from complete. The \module{Tix} +library provides most of the commonly needed widgets that are missing +from standard Tk: \class{HList}, \class{ComboBox}, \class{Control} +(a.k.a. SpinBox) and an assortment of scrollable widgets. \module{Tix} +also includes many more widgets that are generally useful in a wide +range of applications: \class{NoteBook}, \class{FileEntry}, +\class{PanedWindow}, etc; there are more than 40 of them. + +With all these new widgets, you can introduce new interaction +techniques into applications, creating more useful and more intuitive +user interfaces. You can design your application by choosing the most +appropriate widgets to match the special needs of your application and +users. + +\begin{seealso} +\seetitle[http://tix.sourceforge.net/] + {Tix Homepage} + {The home page for \module{Tix}. This includes links to + additional documentation and downloads.} +\seetitle[http://tix.sourceforge.net/dist/current/man/] + {Tix Man Pages} + {On-line version of the man pages and reference material.} +\seetitle[http://tix.sourceforge.net/dist/current/docs/tix-book/tix.book.html] + {Tix Programming Guide} + {On-line version of the programmer's reference material.} +\seetitle[http://tix.sourceforge.net/Tide/] + {Tix Development Applications} + {Tix applications for development of Tix and Tkinter programs. + Tide applications work under Tk or Tkinter, and include + \program{TixInspect}, an inspector to remotely modify and + debug Tix/Tk/Tkinter applications.} +\end{seealso} + + +\subsection{Using Tix} + +\begin{classdesc}{Tix}{screenName\optional{, baseName\optional{, className}}} + Toplevel widget of Tix which represents mostly the main window + of an application. It has an associated Tcl interpreter. + +Classes in the \refmodule{Tix} module subclasses the classes in the +\refmodule{Tkinter} module. The former imports the latter, so to use +\refmodule{Tix} with Tkinter, all you need to do is to import one +module. In general, you can just import \refmodule{Tix}, and replace +the toplevel call to \class{Tkinter.Tk} with \class{Tix.Tk}: +\begin{verbatim} +import Tix +from Tkconstants import * +root = Tix.Tk() +\end{verbatim} +\end{classdesc} + +To use \refmodule{Tix}, you must have the \refmodule{Tix} widgets installed, +usually alongside your installation of the Tk widgets. +To test your installation, try the following: +\begin{verbatim} +import Tix +root = Tix.Tk() +root.tk.eval('package require Tix') +\end{verbatim} + +If this fails, you have a Tk installation problem which must be +resolved before proceeding. Use the environment variable \envvar{TIX_LIBRARY} +to point to the installed \refmodule{Tix} library directory, and +make sure you have the dynamic object library (\file{tix8183.dll} or +\file{libtix8183.so}) in the same directory that contains your Tk +dynamic object library (\file{tk8183.dll} or \file{libtk8183.so}). The +directory with the dynamic object library should also have a file +called \file{pkgIndex.tcl} (case sensitive), which contains the line: + +\begin{verbatim} +package ifneeded Tix 8.1 [list load "[file join $dir tix8183.dll]" Tix] +\end{verbatim} % $ <-- bow to font-lock + + +\subsection{Tix Widgets} + +\ulink{Tix} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/TixIntro.htm} +introduces over 40 widget classes to the \refmodule{Tkinter} +repertoire. There is a demo of all the \refmodule{Tix} widgets in the +\file{Demo/tix} directory of the standard distribution. + + +% The Python sample code is still being added to Python, hence commented out + + +\subsubsection{Basic Widgets} + +\begin{classdesc}{Balloon}{} +A \ulink{Balloon} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixBalloon.htm} +that pops up over a widget to provide help. When the user moves the +cursor inside a widget to which a Balloon widget has been bound, a +small pop-up window with a descriptive message will be shown on the +screen. +\end{classdesc} + +% Python Demo of: +% \ulink{Balloon}{http://tix.sourceforge.net/dist/current/demos/samples/Balloon.tcl} + +\begin{classdesc}{ButtonBox}{} +The \ulink{ButtonBox} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixButtonBox.htm} +widget creates a box of buttons, such as is commonly used for \code{Ok +Cancel}. +\end{classdesc} + +% Python Demo of: +% \ulink{ButtonBox}{http://tix.sourceforge.net/dist/current/demos/samples/BtnBox.tcl} + +\begin{classdesc}{ComboBox}{} +The \ulink{ComboBox} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixComboBox.htm} +widget is similar to the combo box control in MS Windows. The user can +select a choice by either typing in the entry subwdget or selecting +from the listbox subwidget. +\end{classdesc} + +% Python Demo of: +% \ulink{ComboBox}{http://tix.sourceforge.net/dist/current/demos/samples/ComboBox.tcl} + +\begin{classdesc}{Control}{} +The \ulink{Control} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixControl.htm} +widget is also known as the \class{SpinBox} widget. The user can +adjust the value by pressing the two arrow buttons or by entering the +value directly into the entry. The new value will be checked against +the user-defined upper and lower limits. +\end{classdesc} + +% Python Demo of: +% \ulink{Control}{http://tix.sourceforge.net/dist/current/demos/samples/Control.tcl} + +\begin{classdesc}{LabelEntry}{} +The \ulink{LabelEntry} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixLabelEntry.htm} +widget packages an entry widget and a label into one mega widget. It +can be used be used to simplify the creation of ``entry-form'' type of +interface. +\end{classdesc} + +% Python Demo of: +% \ulink{LabelEntry}{http://tix.sourceforge.net/dist/current/demos/samples/LabEntry.tcl} + +\begin{classdesc}{LabelFrame}{} +The \ulink{LabelFrame} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixLabelFrame.htm} +widget packages a frame widget and a label into one mega widget. To +create widgets inside a LabelFrame widget, one creates the new widgets +relative to the \member{frame} subwidget and manage them inside the +\member{frame} subwidget. +\end{classdesc} + +% Python Demo of: +% \ulink{LabelFrame}{http://tix.sourceforge.net/dist/current/demos/samples/LabFrame.tcl} + +\begin{classdesc}{Meter}{} +The \ulink{Meter} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixMeter.htm} +widget can be used to show the progress of a background job which may +take a long time to execute. +\end{classdesc} + +% Python Demo of: +% \ulink{Meter}{http://tix.sourceforge.net/dist/current/demos/samples/Meter.tcl} + +\begin{classdesc}{OptionMenu}{} +The \ulink{OptionMenu} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixOptionMenu.htm} +creates a menu button of options. +\end{classdesc} + +% Python Demo of: +% \ulink{OptionMenu}{http://tix.sourceforge.net/dist/current/demos/samples/OptMenu.tcl} + +\begin{classdesc}{PopupMenu}{} +The \ulink{PopupMenu} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixPopupMenu.htm} +widget can be used as a replacement of the \code{tk_popup} +command. The advantage of the \refmodule{Tix} \class{PopupMenu} widget +is it requires less application code to manipulate. +\end{classdesc} + +% Python Demo of: +% \ulink{PopupMenu}{http://tix.sourceforge.net/dist/current/demos/samples/PopMenu.tcl} + +\begin{classdesc}{Select}{} +The \ulink{Select} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixSelect.htm} +widget is a container of button subwidgets. It can be used to provide +radio-box or check-box style of selection options for the user. +\end{classdesc} + +% Python Demo of: +% \ulink{Select}{http://tix.sourceforge.net/dist/current/demos/samples/Select.tcl} + +\begin{classdesc}{StdButtonBox}{} +The \ulink{StdButtonBox} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixStdButtonBox.htm} +widget is a group of standard buttons for Motif-like dialog boxes. +\end{classdesc} + +% Python Demo of: +% \ulink{StdButtonBox}{http://tix.sourceforge.net/dist/current/demos/samples/StdBBox.tcl} + + +\subsubsection{File Selectors} + +\begin{classdesc}{DirList}{} +The \ulink{DirList} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixDirList.htm} widget +displays a list view of a directory, its previous directories and its +sub-directories. The user can choose one of the directories displayed +in the list or change to another directory. +\end{classdesc} + +% Python Demo of: +% \ulink{DirList}{http://tix.sourceforge.net/dist/current/demos/samples/DirList.tcl} + +\begin{classdesc}{DirTree}{} +The \ulink{DirTree} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixDirTree.htm} +widget displays a tree view of a directory, its previous directories +and its sub-directories. The user can choose one of the directories +displayed in the list or change to another directory. +\end{classdesc} + +% Python Demo of: +% \ulink{DirTree}{http://tix.sourceforge.net/dist/current/demos/samples/DirTree.tcl} + +\begin{classdesc}{DirSelectDialog}{} +The \ulink{DirSelectDialog} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixDirSelectDialog.htm} +widget presents the directories in the file system in a dialog +window. The user can use this dialog window to navigate through the +file system to select the desired directory. +\end{classdesc} + +% Python Demo of: +% \ulink{DirSelectDialog}{http://tix.sourceforge.net/dist/current/demos/samples/DirDlg.tcl} + +\begin{classdesc}{DirSelectBox}{} +The \class{DirSelectBox} is similar +to the standard Motif(TM) directory-selection box. It is generally used for +the user to choose a directory. DirSelectBox stores the directories mostly +recently selected into a ComboBox widget so that they can be quickly +selected again. +\end{classdesc} + +\begin{classdesc}{ExFileSelectBox}{} +The \ulink{ExFileSelectBox} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixExFileSelectBox.htm} +widget is usually embedded in a tixExFileSelectDialog widget. It +provides an convenient method for the user to select files. The style +of the \class{ExFileSelectBox} widget is very similar to the standard +file dialog on MS Windows 3.1. +\end{classdesc} + +% Python Demo of: +%\ulink{ExFileSelectDialog}{http://tix.sourceforge.net/dist/current/demos/samples/EFileDlg.tcl} + +\begin{classdesc}{FileSelectBox}{} +The \ulink{FileSelectBox} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixFileSelectBox.htm} +is similar to the standard Motif(TM) file-selection box. It is +generally used for the user to choose a file. FileSelectBox stores the +files mostly recently selected into a \class{ComboBox} widget so that +they can be quickly selected again. +\end{classdesc} + +% Python Demo of: +% \ulink{FileSelectDialog}{http://tix.sourceforge.net/dist/current/demos/samples/FileDlg.tcl} + +\begin{classdesc}{FileEntry}{} +The \ulink{FileEntry} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixFileEntry.htm} +widget can be used to input a filename. The user can type in the +filename manually. Alternatively, the user can press the button widget +that sits next to the entry, which will bring up a file selection +dialog. +\end{classdesc} + +% Python Demo of: +% \ulink{FileEntry}{http://tix.sourceforge.net/dist/current/demos/samples/FileEnt.tcl} + + +\subsubsection{Hierachical ListBox} + +\begin{classdesc}{HList}{} +The \ulink{HList} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixHList.htm} +widget can be used to display any data that have a hierarchical +structure, for example, file system directory trees. The list entries +are indented and connected by branch lines according to their places +in the hierarchy. +\end{classdesc} + +% Python Demo of: +% \ulink{HList}{http://tix.sourceforge.net/dist/current/demos/samples/HList1.tcl} + +\begin{classdesc}{CheckList}{} +The \ulink{CheckList} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixCheckList.htm} +widget displays a list of items to be selected by the user. CheckList +acts similarly to the Tk checkbutton or radiobutton widgets, except it +is capable of handling many more items than checkbuttons or +radiobuttons. +\end{classdesc} + +% Python Demo of: +% \ulink{ CheckList}{http://tix.sourceforge.net/dist/current/demos/samples/ChkList.tcl} +% Python Demo of: +% \ulink{ScrolledHList (1)}{http://tix.sourceforge.net/dist/current/demos/samples/SHList.tcl} +% Python Demo of: +% \ulink{ScrolledHList (2)}{http://tix.sourceforge.net/dist/current/demos/samples/SHList2.tcl} + +\begin{classdesc}{Tree}{} +The \ulink{Tree} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixTree.htm} +widget can be used to display hierarchical data in a tree form. The +user can adjust the view of the tree by opening or closing parts of +the tree. +\end{classdesc} + +% Python Demo of: +% \ulink{Tree}{http://tix.sourceforge.net/dist/current/demos/samples/Tree.tcl} + +% Python Demo of: +% \ulink{Tree (Dynamic)}{http://tix.sourceforge.net/dist/current/demos/samples/DynTree.tcl} + + +\subsubsection{Tabular ListBox} + +\begin{classdesc}{TList}{} +The \ulink{TList} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixTList.htm} +widget can be used to display data in a tabular format. The list +entries of a \class{TList} widget are similar to the entries in the Tk +listbox widget. The main differences are (1) the \class{TList} widget +can display the list entries in a two dimensional format and (2) you +can use graphical images as well as multiple colors and fonts for the +list entries. +\end{classdesc} + +% Python Demo of: +% \ulink{ScrolledTList (1)}{http://tix.sourceforge.net/dist/current/demos/samples/STList1.tcl} +% Python Demo of: +% \ulink{ScrolledTList (2)}{http://tix.sourceforge.net/dist/current/demos/samples/STList2.tcl} + +% Grid has yet to be added to Python +% \subsubsection{Grid Widget} +% Python Demo of: +% \ulink{Simple Grid}{http://tix.sourceforge.net/dist/current/demos/samples/SGrid0.tcl} +% Python Demo of: +% \ulink{ScrolledGrid}{http://tix.sourceforge.net/dist/current/demos/samples/SGrid1.tcl} +% Python Demo of: +% \ulink{Editable Grid}{http://tix.sourceforge.net/dist/current/demos/samples/EditGrid.tcl} + + +\subsubsection{Manager Widgets} + +\begin{classdesc}{PanedWindow}{} +The \ulink{PanedWindow} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixPanedWindow.htm} +widget allows the user to interactively manipulate the sizes of +several panes. The panes can be arranged either vertically or +horizontally. The user changes the sizes of the panes by dragging the +resize handle between two panes. +\end{classdesc} + +% Python Demo of: +% \ulink{PanedWindow}{http://tix.sourceforge.net/dist/current/demos/samples/PanedWin.tcl} + +\begin{classdesc}{ListNoteBook}{} +The \ulink{ListNoteBook} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixListNoteBook.htm} +widget is very similar to the \class{TixNoteBook} widget: it can be +used to display many windows in a limited space using a notebook +metaphor. The notebook is divided into a stack of pages (windows). At +one time only one of these pages can be shown. The user can navigate +through these pages by choosing the name of the desired page in the +\member{hlist} subwidget. +\end{classdesc} + +% Python Demo of: +% \ulink{ListNoteBook}{http://tix.sourceforge.net/dist/current/demos/samples/ListNBK.tcl} + +\begin{classdesc}{NoteBook}{} +The \ulink{NoteBook} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixNoteBook.htm} +widget can be used to display many windows in a limited space using a +notebook metaphor. The notebook is divided into a stack of pages. At +one time only one of these pages can be shown. The user can navigate +through these pages by choosing the visual ``tabs'' at the top of the +NoteBook widget. +\end{classdesc} + +% Python Demo of: +% \ulink{NoteBook}{http://tix.sourceforge.net/dist/current/demos/samples/NoteBook.tcl} + + +% \subsubsection{Scrolled Widgets} +% Python Demo of: +% \ulink{ScrolledListBox}{http://tix.sourceforge.net/dist/current/demos/samples/SListBox.tcl} +% Python Demo of: +% \ulink{ScrolledText}{http://tix.sourceforge.net/dist/current/demos/samples/SText.tcl} +% Python Demo of: +% \ulink{ScrolledWindow}{http://tix.sourceforge.net/dist/current/demos/samples/SWindow.tcl} +% Python Demo of: +% \ulink{Canvas Object View}{http://tix.sourceforge.net/dist/current/demos/samples/CObjView.tcl} + + +\subsubsection{Image Types} + +The \refmodule{Tix} module adds: +\begin{itemize} +\item +\ulink{pixmap} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/pixmap.htm} +capabilities to all \refmodule{Tix} and \refmodule{Tkinter} widgets to +create color images from XPM files. + +% Python Demo of: +% \ulink{XPM Image In Button}{http://tix.sourceforge.net/dist/current/demos/samples/Xpm.tcl} + +% Python Demo of: +% \ulink{XPM Image In Menu}{http://tix.sourceforge.net/dist/current/demos/samples/Xpm1.tcl} + +\item +\ulink{Compound} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/compound.htm} +image types can be used to create images that consists of multiple +horizontal lines; each line is composed of a series of items (texts, +bitmaps, images or spaces) arranged from left to right. For example, a +compound image can be used to display a bitmap and a text string +simultaneously in a Tk \class{Button} widget. + +% Python Demo of: +% \ulink{Compound Image In Buttons}{http://tix.sourceforge.net/dist/current/demos/samples/CmpImg.tcl} + +% Python Demo of: +% \ulink{Compound Image In NoteBook}{http://tix.sourceforge.net/dist/current/demos/samples/CmpImg2.tcl} + +% Python Demo of: +% \ulink{Compound Image Notebook Color Tabs}{http://tix.sourceforge.net/dist/current/demos/samples/CmpImg4.tcl} + +% Python Demo of: +% \ulink{Compound Image Icons}{http://tix.sourceforge.net/dist/current/demos/samples/CmpImg3.tcl} +\end{itemize} + + +\subsubsection{Miscellaneous Widgets} + +\begin{classdesc}{InputOnly}{} +The \ulink{InputOnly} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixInputOnly.htm} +widgets are to accept inputs from the user, which can be done with the +\code{bind} command (\UNIX{} only). +\end{classdesc} + +\subsubsection{Form Geometry Manager} + +In addition, \refmodule{Tix} augments \refmodule{Tkinter} by providing: + +\begin{classdesc}{Form}{} +The \ulink{Form} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tixForm.htm} +geometry manager based on attachment rules for all Tk widgets. +\end{classdesc} + + +%begin{latexonly} +%\subsection{Tix Class Structure} +% +%\begin{figure}[hbtp] +%\centerline{\epsfig{file=hierarchy.png,width=.9\textwidth}} +%\vspace{.5cm} +%\caption{The Class Hierarchy of Tix Widgets} +%\end{figure} +%end{latexonly} + +\subsection{Tix Commands} + +\begin{classdesc}{tixCommand}{} +The \ulink{tix commands} +{http://tix.sourceforge.net/dist/current/man/html/TixCmd/tix.htm} +provide access to miscellaneous elements of \refmodule{Tix}'s internal +state and the \refmodule{Tix} application context. Most of the information +manipulated by these methods pertains to the application as a whole, +or to a screen or display, rather than to a particular window. + +To view the current settings, the common usage is: +\begin{verbatim} +import Tix +root = Tix.Tk() +print root.tix_configure() +\end{verbatim} +\end{classdesc} + +\begin{methoddesc}{tix_configure}{\optional{cnf,} **kw} +Query or modify the configuration options of the Tix application +context. If no option is specified, returns a dictionary all of the +available options. If option is specified with no value, then the +method returns a list describing the one named option (this list will +be identical to the corresponding sublist of the value returned if no +option is specified). If one or more option-value pairs are +specified, then the method modifies the given option(s) to have the +given value(s); in this case the method returns an empty string. +Option may be any of the configuration options. +\end{methoddesc} + +\begin{methoddesc}{tix_cget}{option} +Returns the current value of the configuration option given by +\var{option}. Option may be any of the configuration options. +\end{methoddesc} + +\begin{methoddesc}{tix_getbitmap}{name} +Locates a bitmap file of the name \code{name.xpm} or \code{name} in +one of the bitmap directories (see the \method{tix_addbitmapdir()} +method). By using \method{tix_getbitmap()}, you can avoid hard +coding the pathnames of the bitmap files in your application. When +successful, it returns the complete pathname of the bitmap file, +prefixed with the character \samp{@}. The returned value can be used to +configure the \code{bitmap} option of the Tk and Tix widgets. +\end{methoddesc} + +\begin{methoddesc}{tix_addbitmapdir}{directory} +Tix maintains a list of directories under which the +\method{tix_getimage()} and \method{tix_getbitmap()} methods will +search for image files. The standard bitmap directory is +\file{\$TIX_LIBRARY/bitmaps}. The \method{tix_addbitmapdir()} method +adds \var{directory} into this list. By using this method, the image +files of an applications can also be located using the +\method{tix_getimage()} or \method{tix_getbitmap()} method. +\end{methoddesc} + +\begin{methoddesc}{tix_filedialog}{\optional{dlgclass}} +Returns the file selection dialog that may be shared among different +calls from this application. This method will create a file selection +dialog widget when it is called the first time. This dialog will be +returned by all subsequent calls to \method{tix_filedialog()}. An +optional dlgclass parameter can be passed as a string to specified +what type of file selection dialog widget is desired. Possible +options are \code{tix}, \code{FileSelectDialog} or +\code{tixExFileSelectDialog}. +\end{methoddesc} + + +\begin{methoddesc}{tix_getimage}{self, name} +Locates an image file of the name \file{name.xpm}, \file{name.xbm} or +\file{name.ppm} in one of the bitmap directories (see the +\method{tix_addbitmapdir()} method above). If more than one file with +the same name (but different extensions) exist, then the image type is +chosen according to the depth of the X display: xbm images are chosen +on monochrome displays and color images are chosen on color +displays. By using \method{tix_getimage()}, you can avoid hard coding +the pathnames of the image files in your application. When successful, +this method returns the name of the newly created image, which can be +used to configure the \code{image} option of the Tk and Tix widgets. +\end{methoddesc} + +\begin{methoddesc}{tix_option_get}{name} +Gets the options maintained by the Tix scheme mechanism. +\end{methoddesc} + +\begin{methoddesc}{tix_resetoptions}{newScheme, newFontSet\optional{, + newScmPrio}} +Resets the scheme and fontset of the Tix application to +\var{newScheme} and \var{newFontSet}, respectively. This affects only +those widgets created after this call. Therefore, it is best to call +the resetoptions method before the creation of any widgets in a Tix +application. + +The optional parameter \var{newScmPrio} can be given to reset the +priority level of the Tk options set by the Tix schemes. + +Because of the way Tk handles the X option database, after Tix has +been has imported and inited, it is not possible to reset the color +schemes and font sets using the \method{tix_config()} method. +Instead, the \method{tix_resetoptions()} method must be used. +\end{methoddesc} + + + +\section{\module{ScrolledText} --- + Scrolled Text Widget} + +\declaremodule{standard}{ScrolledText} + \platform{Tk} +\modulesynopsis{Text widget with a vertical scroll bar.} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + +The \module{ScrolledText} module provides a class of the same name +which implements a basic text widget which has a vertical scroll bar +configured to do the ``right thing.'' Using the \class{ScrolledText} +class is a lot easier than setting up a text widget and scroll bar +directly. The constructor is the same as that of the +\class{Tkinter.Text} class. + +The text widget and scrollbar are packed together in a \class{Frame}, +and the methods of the \class{Grid} and \class{Pack} geometry managers +are acquired from the \class{Frame} object. This allows the +\class{ScrolledText} widget to be used directly to achieve most normal +geometry management behavior. + +Should more specific control be necessary, the following attributes +are available: + +\begin{memberdesc}[ScrolledText]{frame} + The frame which surrounds the text and scroll bar widgets. +\end{memberdesc} + +\begin{memberdesc}[ScrolledText]{vbar} + The scroll bar widget. +\end{memberdesc} + + +\input{libturtle} + + +\section{Idle \label{idle}} + +%\declaremodule{standard}{idle} +%\modulesynopsis{A Python Integrated Development Environment} +\moduleauthor{Guido van Rossum}{guido@Python.org} + +Idle is the Python IDE built with the \refmodule{Tkinter} GUI toolkit. +\index{Idle} +\index{Python Editor} +\index{Integrated Development Environment} + + +IDLE has the following features: + +\begin{itemize} +\item coded in 100\% pure Python, using the \refmodule{Tkinter} GUI toolkit + +\item cross-platform: works on Windows and \UNIX{} (on Mac OS, there are +currently problems with Tcl/Tk) + +\item multi-window text editor with multiple undo, Python colorizing +and many other features, e.g. smart indent and call tips + +\item Python shell window (a.k.a. interactive interpreter) + +\item debugger (not complete, but you can set breakpoints, view and step) +\end{itemize} + + +\subsection{Menus} + +\subsubsection{File menu} + +\begin{description} +\item[New window] create a new editing window +\item[Open...] open an existing file +\item[Open module...] open an existing module (searches sys.path) +\item[Class browser] show classes and methods in current file +\item[Path browser] show sys.path directories, modules, classes and methods +\end{description} +\index{Class browser} +\index{Path browser} + +\begin{description} +\item[Save] save current window to the associated file (unsaved +windows have a * before and after the window title) + +\item[Save As...] save current window to new file, which becomes +the associated file +\item[Save Copy As...] save current window to different file +without changing the associated file +\end{description} + +\begin{description} +\item[Close] close current window (asks to save if unsaved) +\item[Exit] close all windows and quit IDLE (asks to save if unsaved) +\end{description} + + +\subsubsection{Edit menu} + +\begin{description} +\item[Undo] Undo last change to current window (max 1000 changes) +\item[Redo] Redo last undone change to current window +\end{description} + +\begin{description} +\item[Cut] Copy selection into system-wide clipboard; then delete selection +\item[Copy] Copy selection into system-wide clipboard +\item[Paste] Insert system-wide clipboard into window +\item[Select All] Select the entire contents of the edit buffer +\end{description} + +\begin{description} +\item[Find...] Open a search dialog box with many options +\item[Find again] Repeat last search +\item[Find selection] Search for the string in the selection +\item[Find in Files...] Open a search dialog box for searching files +\item[Replace...] Open a search-and-replace dialog box +\item[Go to line] Ask for a line number and show that line +\end{description} + +\begin{description} +\item[Indent region] Shift selected lines right 4 spaces +\item[Dedent region] Shift selected lines left 4 spaces +\item[Comment out region] Insert \#\# in front of selected lines +\item[Uncomment region] Remove leading \# or \#\# from selected lines +\item[Tabify region] Turns \emph{leading} stretches of spaces into tabs +\item[Untabify region] Turn \emph{all} tabs into the right number of spaces +\item[Expand word] Expand the word you have typed to match another + word in the same buffer; repeat to get a different expansion +\item[Format Paragraph] Reformat the current blank-line-separated paragraph +\end{description} + +\begin{description} +\item[Import module] Import or reload the current module +\item[Run script] Execute the current file in the __main__ namespace +\end{description} + +\index{Import module} +\index{Run script} + + +\subsubsection{Windows menu} + +\begin{description} +\item[Zoom Height] toggles the window between normal size (24x80) + and maximum height. +\end{description} + +The rest of this menu lists the names of all open windows; select one +to bring it to the foreground (deiconifying it if necessary). + + +\subsubsection{Debug menu (in the Python Shell window only)} + +\begin{description} +\item[Go to file/line] look around the insert point for a filename + and linenumber, open the file, and show the line. +\item[Open stack viewer] show the stack traceback of the last exception +\item[Debugger toggle] Run commands in the shell under the debugger +\item[JIT Stack viewer toggle] Open stack viewer on traceback +\end{description} + +\index{stack viewer} +\index{debugger} + + +\subsection{Basic editing and navigation} + +\begin{itemize} +\item \kbd{Backspace} deletes to the left; \kbd{Del} deletes to the right +\item Arrow keys and \kbd{Page Up}/\kbd{Page Down} to move around +\item \kbd{Home}/\kbd{End} go to begin/end of line +\item \kbd{C-Home}/\kbd{C-End} go to begin/end of file +\item Some \program{Emacs} bindings may also work, including \kbd{C-B}, + \kbd{C-P}, \kbd{C-A}, \kbd{C-E}, \kbd{C-D}, \kbd{C-L} +\end{itemize} + + +\subsubsection{Automatic indentation} + +After a block-opening statement, the next line is indented by 4 spaces +(in the Python Shell window by one tab). After certain keywords +(break, return etc.) the next line is dedented. In leading +indentation, \kbd{Backspace} deletes up to 4 spaces if they are there. +\kbd{Tab} inserts 1-4 spaces (in the Python Shell window one tab). +See also the indent/dedent region commands in the edit menu. + + +\subsubsection{Python Shell window} + +\begin{itemize} +\item \kbd{C-C} interrupts executing command +\item \kbd{C-D} sends end-of-file; closes window if typed at +a \samp{>>>~} prompt +\end{itemize} + +\begin{itemize} +\item \kbd{Alt-p} retrieves previous command matching what you have typed +\item \kbd{Alt-n} retrieves next +\item \kbd{Return} while on any previous command retrieves that command +\item \kbd{Alt-/} (Expand word) is also useful here +\end{itemize} + +\index{indentation} + + +\subsection{Syntax colors} + +The coloring is applied in a background ``thread,'' so you may +occasionally see uncolorized text. To change the color +scheme, edit the \code{[Colors]} section in \file{config.txt}. + +\begin{description} +\item[Python syntax colors:] + +\begin{description} +\item[Keywords] orange +\item[Strings ] green +\item[Comments] red +\item[Definitions] blue +\end{description} + +\item[Shell colors:] +\begin{description} +\item[Console output] brown +\item[stdout] blue +\item[stderr] dark green +\item[stdin] black +\end{description} +\end{description} + + +\subsubsection{Command line usage} + +\begin{verbatim} +idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ... + +-c command run this command +-d enable debugger +-e edit mode; arguments are files to be edited +-s run $IDLESTARTUP or $PYTHONSTARTUP first +-t title set title of shell window +\end{verbatim} + +If there are arguments: + +\begin{enumerate} +\item If \programopt{-e} is used, arguments are files opened for + editing and \code{sys.argv} reflects the arguments passed to + IDLE itself. + +\item Otherwise, if \programopt{-c} is used, all arguments are + placed in \code{sys.argv[1:...]}, with \code{sys.argv[0]} set + to \code{'-c'}. + +\item Otherwise, if neither \programopt{-e} nor \programopt{-c} is + used, the first argument is a script which is executed with + the remaining arguments in \code{sys.argv[1:...]} and + \code{sys.argv[0]} set to the script name. If the script name + is '-', no script is executed but an interactive Python + session is started; the arguments are still available in + \code{sys.argv}. +\end{enumerate} + + +\section{Other Graphical User Interface Packages + \label{other-gui-packages}} + + +There are an number of extension widget sets to \refmodule{Tkinter}. + +\begin{seealso*} +\seetitle[http://pmw.sourceforge.net/]{Python megawidgets}{is a +toolkit for building high-level compound widgets in Python using the +\refmodule{Tkinter} module. It consists of a set of base classes and +a library of flexible and extensible megawidgets built on this +foundation. These megawidgets include notebooks, comboboxes, selection +widgets, paned widgets, scrolled widgets, dialog windows, etc. Also, +with the Pmw.Blt interface to BLT, the busy, graph, stripchart, tabset +and vector commands are be available. + +The initial ideas for Pmw were taken from the Tk \code{itcl} +extensions \code{[incr Tk]} by Michael McLennan and \code{[incr +Widgets]} by Mark Ulferts. Several of the megawidgets are direct +translations from the itcl to Python. It offers most of the range of +widgets that \code{[incr Widgets]} does, and is almost as complete as +Tix, lacking however Tix's fast \class{HList} widget for drawing trees. +} + +\seetitle[http://tkinter.effbot.org/]{Tkinter3000 Widget Construction + Kit (WCK)}{% +is a library that allows you to write new Tkinter widgets in pure +Python. The WCK framework gives you full control over widget +creation, configuration, screen appearance, and event handling. WCK +widgets can be very fast and light-weight, since they can operate +directly on Python data structures, without having to transfer data +through the Tk/Tcl layer.} +\end{seealso*} + +Other GUI packages are also available for Python: + +\begin{seealso*} +\seetitle[http://www.wxpython.org]{wxPython}{ +wxPython is a cross-platform GUI toolkit for Python that is built +around the popular \ulink{wxWidgets}{http://www.wxwidgets.org/} \Cpp{} +toolkit.  It provides a native look and feel for applications on +Windows, Mac OS X, and \UNIX{} systems by using each platform's native +widgets where ever possible, (GTK+ on \UNIX-like systems).  In +addition to an extensive set of widgets, wxPython provides classes for +online documentation and context sensitive help, printing, HTML +viewing, low-level device context drawing, drag and drop, system +clipboard access, an XML-based resource format and more, including an +ever growing library of user-contributed modules.  Both the wxWidgets +and wxPython projects are under active development and continuous +improvement, and have active and helpful user and developer +communities. +} +\seetitle[http://www.amazon.com/exec/obidos/ASIN/1932394621] +{wxPython in Action}{ +The wxPython book, by Noel Rappin and Robin Dunn. +} +\seetitle{PyQt}{ +PyQt is a \program{sip}-wrapped binding to the Qt toolkit. Qt is an +extensive \Cpp{} GUI toolkit that is available for \UNIX, Windows and +Mac OS X. \program{sip} is a tool for generating bindings for \Cpp{} +libraries as Python classes, and is specifically designed for Python. +An online manual is available at +\url{http://www.opendocspublishing.com/pyqt/} (errata are located at +\url{http://www.valdyas.org/python/book.html}). +} +\seetitle[http://www.riverbankcomputing.co.uk/pykde/index.php]{PyKDE}{ +PyKDE is a \program{sip}-wrapped interface to the KDE desktop +libraries. KDE is a desktop environment for \UNIX{} computers; the +graphical components are based on Qt. +} +\seetitle[http://fxpy.sourceforge.net/]{FXPy}{ +is a Python extension module which provides an interface to the +\citetitle[http://www.cfdrc.com/FOX/fox.html]{FOX} GUI. +FOX is a \Cpp{} based Toolkit for developing Graphical User Interfaces +easily and effectively. It offers a wide, and growing, collection of +Controls, and provides state of the art facilities such as drag and +drop, selection, as well as OpenGL widgets for 3D graphical +manipulation. FOX also implements icons, images, and user-convenience +features such as status line help, and tooltips. + +Even though FOX offers a large collection of controls already, FOX +leverages \Cpp{} to allow programmers to easily build additional Controls +and GUI elements, simply by taking existing controls, and creating a +derived class which simply adds or redefines the desired behavior. +} +\seetitle[http://www.daa.com.au/\textasciitilde james/software/pygtk/]{PyGTK}{ +is a set of bindings for the \ulink{GTK}{http://www.gtk.org/} widget set. +It provides an object oriented interface that is slightly higher +level than the C one. It automatically does all the type casting and +reference counting that you would have to do normally with the C +API. There are also +\ulink{bindings}{http://www.daa.com.au/\textasciitilde james/gnome/} +to \ulink{GNOME}{http://www.gnome.org}, and a +\ulink{tutorial} +{http://laguna.fmedic.unam.mx/\textasciitilde daniel/pygtutorial/pygtutorial/index.html} +is available. +} +\end{seealso*} + +% XXX Reference URLs that compare the different UI packages diff --git a/sys/src/cmd/python/Doc/lib/tzinfo-examples.py b/sys/src/cmd/python/Doc/lib/tzinfo-examples.py new file mode 100644 index 000000000..5a2b8ad1a --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/tzinfo-examples.py @@ -0,0 +1,139 @@ +from datetime import tzinfo, timedelta, datetime + +ZERO = timedelta(0) +HOUR = timedelta(hours=1) + +# A UTC class. + +class UTC(tzinfo): + """UTC""" + + def utcoffset(self, dt): + return ZERO + + def tzname(self, dt): + return "UTC" + + def dst(self, dt): + return ZERO + +utc = UTC() + +# A class building tzinfo objects for fixed-offset time zones. +# Note that FixedOffset(0, "UTC") is a different way to build a +# UTC tzinfo object. + +class FixedOffset(tzinfo): + """Fixed offset in minutes east from UTC.""" + + def __init__(self, offset, name): + self.__offset = timedelta(minutes = offset) + self.__name = name + + def utcoffset(self, dt): + return self.__offset + + def tzname(self, dt): + return self.__name + + def dst(self, dt): + return ZERO + +# A class capturing the platform's idea of local time. + +import time as _time + +STDOFFSET = timedelta(seconds = -_time.timezone) +if _time.daylight: + DSTOFFSET = timedelta(seconds = -_time.altzone) +else: + DSTOFFSET = STDOFFSET + +DSTDIFF = DSTOFFSET - STDOFFSET + +class LocalTimezone(tzinfo): + + def utcoffset(self, dt): + if self._isdst(dt): + return DSTOFFSET + else: + return STDOFFSET + + def dst(self, dt): + if self._isdst(dt): + return DSTDIFF + else: + return ZERO + + def tzname(self, dt): + return _time.tzname[self._isdst(dt)] + + def _isdst(self, dt): + tt = (dt.year, dt.month, dt.day, + dt.hour, dt.minute, dt.second, + dt.weekday(), 0, -1) + stamp = _time.mktime(tt) + tt = _time.localtime(stamp) + return tt.tm_isdst > 0 + +Local = LocalTimezone() + + +# A complete implementation of current DST rules for major US time zones. + +def first_sunday_on_or_after(dt): + days_to_go = 6 - dt.weekday() + if days_to_go: + dt += timedelta(days_to_go) + return dt + +# In the US, DST starts at 2am (standard time) on the first Sunday in April. +DSTSTART = datetime(1, 4, 1, 2) +# and ends at 2am (DST time; 1am standard time) on the last Sunday of Oct. +# which is the first Sunday on or after Oct 25. +DSTEND = datetime(1, 10, 25, 1) + +class USTimeZone(tzinfo): + + def __init__(self, hours, reprname, stdname, dstname): + self.stdoffset = timedelta(hours=hours) + self.reprname = reprname + self.stdname = stdname + self.dstname = dstname + + def __repr__(self): + return self.reprname + + def tzname(self, dt): + if self.dst(dt): + return self.dstname + else: + return self.stdname + + def utcoffset(self, dt): + return self.stdoffset + self.dst(dt) + + def dst(self, dt): + if dt is None or dt.tzinfo is None: + # An exception may be sensible here, in one or both cases. + # It depends on how you want to treat them. The default + # fromutc() implementation (called by the default astimezone() + # implementation) passes a datetime with dt.tzinfo is self. + return ZERO + assert dt.tzinfo is self + + # Find first Sunday in April & the last in October. + start = first_sunday_on_or_after(DSTSTART.replace(year=dt.year)) + end = first_sunday_on_or_after(DSTEND.replace(year=dt.year)) + + # Can't compare naive to aware objects, so strip the timezone from + # dt first. + if start <= dt.replace(tzinfo=None) < end: + return HOUR + else: + return ZERO + +Eastern = USTimeZone(-5, "Eastern", "EST", "EDT") +Central = USTimeZone(-6, "Central", "CST", "CDT") +Mountain = USTimeZone(-7, "Mountain", "MST", "MDT") +Pacific = USTimeZone(-8, "Pacific", "PST", "PDT") diff --git a/sys/src/cmd/python/Doc/lib/windows.tex b/sys/src/cmd/python/Doc/lib/windows.tex new file mode 100644 index 000000000..ced355971 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/windows.tex @@ -0,0 +1,8 @@ +\chapter{MS Windows Specific Services} + + +This chapter describes modules that are only available on MS Windows +platforms. + + +\localmoduletable diff --git a/sys/src/cmd/python/Doc/lib/xmldom.tex b/sys/src/cmd/python/Doc/lib/xmldom.tex new file mode 100644 index 000000000..d651bf089 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmldom.tex @@ -0,0 +1,928 @@ +\section{\module{xml.dom} --- + The Document Object Model API} + +\declaremodule{standard}{xml.dom} +\modulesynopsis{Document Object Model API for Python.} +\sectionauthor{Paul Prescod}{paul@prescod.net} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} + +\versionadded{2.0} + +The Document Object Model, or ``DOM,'' is a cross-language API from +the World Wide Web Consortium (W3C) for accessing and modifying XML +documents. A DOM implementation presents an XML document as a tree +structure, or allows client code to build such a structure from +scratch. It then gives access to the structure through a set of +objects which provided well-known interfaces. + +The DOM is extremely useful for random-access applications. SAX only +allows you a view of one bit of the document at a time. If you are +looking at one SAX element, you have no access to another. If you are +looking at a text node, you have no access to a containing element. +When you write a SAX application, you need to keep track of your +program's position in the document somewhere in your own code. SAX +does not do it for you. Also, if you need to look ahead in the XML +document, you are just out of luck. + +Some applications are simply impossible in an event driven model with +no access to a tree. Of course you could build some sort of tree +yourself in SAX events, but the DOM allows you to avoid writing that +code. The DOM is a standard tree representation for XML data. + +%What if your needs are somewhere between SAX and the DOM? Perhaps +%you cannot afford to load the entire tree in memory but you find the +%SAX model somewhat cumbersome and low-level. There is also a module +%called xml.dom.pulldom that allows you to build trees of only the +%parts of a document that you need structured access to. It also has +%features that allow you to find your way around the DOM. +% See http://www.prescod.net/python/pulldom + +The Document Object Model is being defined by the W3C in stages, or +``levels'' in their terminology. The Python mapping of the API is +substantially based on the DOM Level~2 recommendation. The mapping of +the Level~3 specification, currently only available in draft form, is +being developed by the \ulink{Python XML Special Interest +Group}{http://www.python.org/sigs/xml-sig/} as part of the +\ulink{PyXML package}{http://pyxml.sourceforge.net/}. Refer to the +documentation bundled with that package for information on the current +state of DOM Level~3 support. + +DOM applications typically start by parsing some XML into a DOM. How +this is accomplished is not covered at all by DOM Level~1, and Level~2 +provides only limited improvements: There is a +\class{DOMImplementation} object class which provides access to +\class{Document} creation methods, but no way to access an XML +reader/parser/Document builder in an implementation-independent way. +There is also no well-defined way to access these methods without an +existing \class{Document} object. In Python, each DOM implementation +will provide a function \function{getDOMImplementation()}. DOM Level~3 +adds a Load/Store specification, which defines an interface to the +reader, but this is not yet available in the Python standard library. + +Once you have a DOM document object, you can access the parts of your +XML document through its properties and methods. These properties are +defined in the DOM specification; this portion of the reference manual +describes the interpretation of the specification in Python. + +The specification provided by the W3C defines the DOM API for Java, +ECMAScript, and OMG IDL. The Python mapping defined here is based in +large part on the IDL version of the specification, but strict +compliance is not required (though implementations are free to support +the strict mapping from IDL). See section \ref{dom-conformance}, +``Conformance,'' for a detailed discussion of mapping requirements. + + +\begin{seealso} + \seetitle[http://www.w3.org/TR/DOM-Level-2-Core/]{Document Object + Model (DOM) Level~2 Specification} + {The W3C recommendation upon which the Python DOM API is + based.} + \seetitle[http://www.w3.org/TR/REC-DOM-Level-1/]{Document Object + Model (DOM) Level~1 Specification} + {The W3C recommendation for the + DOM supported by \module{xml.dom.minidom}.} + \seetitle[http://pyxml.sourceforge.net]{PyXML}{Users that require a + full-featured implementation of DOM should use the PyXML + package.} + \seetitle[http://www.omg.org/docs/formal/02-11-05.pdf]{Python + Language Mapping Specification} + {This specifies the mapping from OMG IDL to Python.} +\end{seealso} + +\subsection{Module Contents} + +The \module{xml.dom} contains the following functions: + +\begin{funcdesc}{registerDOMImplementation}{name, factory} +Register the \var{factory} function with the name \var{name}. The +factory function should return an object which implements the +\class{DOMImplementation} interface. The factory function can return +the same object every time, or a new one for each call, as appropriate +for the specific implementation (e.g. if that implementation supports +some customization). +\end{funcdesc} + +\begin{funcdesc}{getDOMImplementation}{\optional{name\optional{, features}}} +Return a suitable DOM implementation. The \var{name} is either +well-known, the module name of a DOM implementation, or +\code{None}. If it is not \code{None}, imports the corresponding +module and returns a \class{DOMImplementation} object if the import +succeeds. If no name is given, and if the environment variable +\envvar{PYTHON_DOM} is set, this variable is used to find the +implementation. + +If name is not given, this examines the available implementations to +find one with the required feature set. If no implementation can be +found, raise an \exception{ImportError}. The features list must be a +sequence of \code{(\var{feature}, \var{version})} pairs which are +passed to the \method{hasFeature()} method on available +\class{DOMImplementation} objects. +\end{funcdesc} + + +Some convenience constants are also provided: + +\begin{datadesc}{EMPTY_NAMESPACE} + The value used to indicate that no namespace is associated with a + node in the DOM. This is typically found as the + \member{namespaceURI} of a node, or used as the \var{namespaceURI} + parameter to a namespaces-specific method. + \versionadded{2.2} +\end{datadesc} + +\begin{datadesc}{XML_NAMESPACE} + The namespace URI associated with the reserved prefix \code{xml}, as + defined by + \citetitle[http://www.w3.org/TR/REC-xml-names/]{Namespaces in XML} + (section~4). + \versionadded{2.2} +\end{datadesc} + +\begin{datadesc}{XMLNS_NAMESPACE} + The namespace URI for namespace declarations, as defined by + \citetitle[http://www.w3.org/TR/DOM-Level-2-Core/core.html]{Document + Object Model (DOM) Level~2 Core Specification} (section~1.1.8). + \versionadded{2.2} +\end{datadesc} + +\begin{datadesc}{XHTML_NAMESPACE} + The URI of the XHTML namespace as defined by + \citetitle[http://www.w3.org/TR/xhtml1/]{XHTML 1.0: The Extensible + HyperText Markup Language} (section~3.1.1). + \versionadded{2.2} +\end{datadesc} + + +% Should the Node documentation go here? + +In addition, \module{xml.dom} contains a base \class{Node} class and +the DOM exception classes. The \class{Node} class provided by this +module does not implement any of the methods or attributes defined by +the DOM specification; concrete DOM implementations must provide +those. The \class{Node} class provided as part of this module does +provide the constants used for the \member{nodeType} attribute on +concrete \class{Node} objects; they are located within the class +rather than at the module level to conform with the DOM +specifications. + + +\subsection{Objects in the DOM \label{dom-objects}} + +The definitive documentation for the DOM is the DOM specification from +the W3C. + +Note that DOM attributes may also be manipulated as nodes instead of +as simple strings. It is fairly rare that you must do this, however, +so this usage is not yet documented. + + +\begin{tableiii}{l|l|l}{class}{Interface}{Section}{Purpose} + \lineiii{DOMImplementation}{\ref{dom-implementation-objects}} + {Interface to the underlying implementation.} + \lineiii{Node}{\ref{dom-node-objects}} + {Base interface for most objects in a document.} + \lineiii{NodeList}{\ref{dom-nodelist-objects}} + {Interface for a sequence of nodes.} + \lineiii{DocumentType}{\ref{dom-documenttype-objects}} + {Information about the declarations needed to process a document.} + \lineiii{Document}{\ref{dom-document-objects}} + {Object which represents an entire document.} + \lineiii{Element}{\ref{dom-element-objects}} + {Element nodes in the document hierarchy.} + \lineiii{Attr}{\ref{dom-attr-objects}} + {Attribute value nodes on element nodes.} + \lineiii{Comment}{\ref{dom-comment-objects}} + {Representation of comments in the source document.} + \lineiii{Text}{\ref{dom-text-objects}} + {Nodes containing textual content from the document.} + \lineiii{ProcessingInstruction}{\ref{dom-pi-objects}} + {Processing instruction representation.} +\end{tableiii} + +An additional section describes the exceptions defined for working +with the DOM in Python. + + +\subsubsection{DOMImplementation Objects + \label{dom-implementation-objects}} + +The \class{DOMImplementation} interface provides a way for +applications to determine the availability of particular features in +the DOM they are using. DOM Level~2 added the ability to create new +\class{Document} and \class{DocumentType} objects using the +\class{DOMImplementation} as well. + +\begin{methoddesc}[DOMImplementation]{hasFeature}{feature, version} +Return true if the feature identified by the pair of strings +\var{feature} and \var{version} is implemented. +\end{methoddesc} + +\begin{methoddesc}[DOMImplementation]{createDocument}{namespaceUri, qualifiedName, doctype} +Return a new \class{Document} object (the root of the DOM), with a +child \class{Element} object having the given \var{namespaceUri} and +\var{qualifiedName}. The \var{doctype} must be a \class{DocumentType} +object created by \method{createDocumentType()}, or \code{None}. +In the Python DOM API, the first two arguments can also be \code{None} +in order to indicate that no \class{Element} child is to be created. +\end{methoddesc} + +\begin{methoddesc}[DOMImplementation]{createDocumentType}{qualifiedName, publicId, systemId} +Return a new \class{DocumentType} object that encapsulates the given +\var{qualifiedName}, \var{publicId}, and \var{systemId} strings, +representing the information contained in an XML document type +declaration. +\end{methoddesc} + + +\subsubsection{Node Objects \label{dom-node-objects}} + +All of the components of an XML document are subclasses of +\class{Node}. + +\begin{memberdesc}[Node]{nodeType} +An integer representing the node type. Symbolic constants for the +types are on the \class{Node} object: +\constant{ELEMENT_NODE}, \constant{ATTRIBUTE_NODE}, +\constant{TEXT_NODE}, \constant{CDATA_SECTION_NODE}, +\constant{ENTITY_NODE}, \constant{PROCESSING_INSTRUCTION_NODE}, +\constant{COMMENT_NODE}, \constant{DOCUMENT_NODE}, +\constant{DOCUMENT_TYPE_NODE}, \constant{NOTATION_NODE}. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{parentNode} +The parent of the current node, or \code{None} for the document node. +The value is always a \class{Node} object or \code{None}. For +\class{Element} nodes, this will be the parent element, except for the +root element, in which case it will be the \class{Document} object. +For \class{Attr} nodes, this is always \code{None}. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{attributes} +A \class{NamedNodeMap} of attribute objects. Only elements have +actual values for this; others provide \code{None} for this attribute. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{previousSibling} +The node that immediately precedes this one with the same parent. For +instance the element with an end-tag that comes just before the +\var{self} element's start-tag. Of course, XML documents are made +up of more than just elements so the previous sibling could be text, a +comment, or something else. If this node is the first child of the +parent, this attribute will be \code{None}. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{nextSibling} +The node that immediately follows this one with the same parent. See +also \member{previousSibling}. If this is the last child of the +parent, this attribute will be \code{None}. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{childNodes} +A list of nodes contained within this node. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{firstChild} +The first child of the node, if there are any, or \code{None}. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{lastChild} +The last child of the node, if there are any, or \code{None}. +This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{localName} +The part of the \member{tagName} following the colon if there is one, +else the entire \member{tagName}. The value is a string. +\end{memberdesc} + +\begin{memberdesc}[Node]{prefix} +The part of the \member{tagName} preceding the colon if there is one, +else the empty string. The value is a string, or \code{None} +\end{memberdesc} + +\begin{memberdesc}[Node]{namespaceURI} +The namespace associated with the element name. This will be a +string or \code{None}. This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{nodeName} +This has a different meaning for each node type; see the DOM +specification for details. You can always get the information you +would get here from another property such as the \member{tagName} +property for elements or the \member{name} property for attributes. +For all node types, the value of this attribute will be either a +string or \code{None}. This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Node]{nodeValue} +This has a different meaning for each node type; see the DOM +specification for details. The situation is similar to that with +\member{nodeName}. The value is a string or \code{None}. +\end{memberdesc} + +\begin{methoddesc}[Node]{hasAttributes}{} +Returns true if the node has any attributes. +\end{methoddesc} + +\begin{methoddesc}[Node]{hasChildNodes}{} +Returns true if the node has any child nodes. +\end{methoddesc} + +\begin{methoddesc}[Node]{isSameNode}{other} +Returns true if \var{other} refers to the same node as this node. +This is especially useful for DOM implementations which use any sort +of proxy architecture (because more than one object can refer to the +same node). + +\begin{notice} + This is based on a proposed DOM Level~3 API which is still in the + ``working draft'' stage, but this particular interface appears + uncontroversial. Changes from the W3C will not necessarily affect + this method in the Python DOM interface (though any new W3C API for + this would also be supported). +\end{notice} +\end{methoddesc} + +\begin{methoddesc}[Node]{appendChild}{newChild} +Add a new child node to this node at the end of the list of children, +returning \var{newChild}. +\end{methoddesc} + +\begin{methoddesc}[Node]{insertBefore}{newChild, refChild} +Insert a new child node before an existing child. It must be the case +that \var{refChild} is a child of this node; if not, +\exception{ValueError} is raised. \var{newChild} is returned. If +\var{refChild} is \code{None}, it inserts \var{newChild} at the end of +the children's list. +\end{methoddesc} + +\begin{methoddesc}[Node]{removeChild}{oldChild} +Remove a child node. \var{oldChild} must be a child of this node; if +not, \exception{ValueError} is raised. \var{oldChild} is returned on +success. If \var{oldChild} will not be used further, its +\method{unlink()} method should be called. +\end{methoddesc} + +\begin{methoddesc}[Node]{replaceChild}{newChild, oldChild} +Replace an existing node with a new node. It must be the case that +\var{oldChild} is a child of this node; if not, +\exception{ValueError} is raised. +\end{methoddesc} + +\begin{methoddesc}[Node]{normalize}{} +Join adjacent text nodes so that all stretches of text are stored as +single \class{Text} instances. This simplifies processing text from a +DOM tree for many applications. +\versionadded{2.1} +\end{methoddesc} + +\begin{methoddesc}[Node]{cloneNode}{deep} +Clone this node. Setting \var{deep} means to clone all child nodes as +well. This returns the clone. +\end{methoddesc} + + +\subsubsection{NodeList Objects \label{dom-nodelist-objects}} + +A \class{NodeList} represents a sequence of nodes. These objects are +used in two ways in the DOM Core recommendation: the +\class{Element} objects provides one as its list of child nodes, and +the \method{getElementsByTagName()} and +\method{getElementsByTagNameNS()} methods of \class{Node} return +objects with this interface to represent query results. + +The DOM Level~2 recommendation defines one method and one attribute +for these objects: + +\begin{methoddesc}[NodeList]{item}{i} + Return the \var{i}'th item from the sequence, if there is one, or + \code{None}. The index \var{i} is not allowed to be less then zero + or greater than or equal to the length of the sequence. +\end{methoddesc} + +\begin{memberdesc}[NodeList]{length} + The number of nodes in the sequence. +\end{memberdesc} + +In addition, the Python DOM interface requires that some additional +support is provided to allow \class{NodeList} objects to be used as +Python sequences. All \class{NodeList} implementations must include +support for \method{__len__()} and \method{__getitem__()}; this allows +iteration over the \class{NodeList} in \keyword{for} statements and +proper support for the \function{len()} built-in function. + +If a DOM implementation supports modification of the document, the +\class{NodeList} implementation must also support the +\method{__setitem__()} and \method{__delitem__()} methods. + + +\subsubsection{DocumentType Objects \label{dom-documenttype-objects}} + +Information about the notations and entities declared by a document +(including the external subset if the parser uses it and can provide +the information) is available from a \class{DocumentType} object. The +\class{DocumentType} for a document is available from the +\class{Document} object's \member{doctype} attribute; if there is no +\code{DOCTYPE} declaration for the document, the document's +\member{doctype} attribute will be set to \code{None} instead of an +instance of this interface. + +\class{DocumentType} is a specialization of \class{Node}, and adds the +following attributes: + +\begin{memberdesc}[DocumentType]{publicId} + The public identifier for the external subset of the document type + definition. This will be a string or \code{None}. +\end{memberdesc} + +\begin{memberdesc}[DocumentType]{systemId} + The system identifier for the external subset of the document type + definition. This will be a URI as a string, or \code{None}. +\end{memberdesc} + +\begin{memberdesc}[DocumentType]{internalSubset} + A string giving the complete internal subset from the document. + This does not include the brackets which enclose the subset. If the + document has no internal subset, this should be \code{None}. +\end{memberdesc} + +\begin{memberdesc}[DocumentType]{name} + The name of the root element as given in the \code{DOCTYPE} + declaration, if present. +\end{memberdesc} + +\begin{memberdesc}[DocumentType]{entities} + This is a \class{NamedNodeMap} giving the definitions of external + entities. For entity names defined more than once, only the first + definition is provided (others are ignored as required by the XML + recommendation). This may be \code{None} if the information is not + provided by the parser, or if no entities are defined. +\end{memberdesc} + +\begin{memberdesc}[DocumentType]{notations} + This is a \class{NamedNodeMap} giving the definitions of notations. + For notation names defined more than once, only the first definition + is provided (others are ignored as required by the XML + recommendation). This may be \code{None} if the information is not + provided by the parser, or if no notations are defined. +\end{memberdesc} + + +\subsubsection{Document Objects \label{dom-document-objects}} + +A \class{Document} represents an entire XML document, including its +constituent elements, attributes, processing instructions, comments +etc. Remeber that it inherits properties from \class{Node}. + +\begin{memberdesc}[Document]{documentElement} +The one and only root element of the document. +\end{memberdesc} + +\begin{methoddesc}[Document]{createElement}{tagName} +Create and return a new element node. The element is not inserted +into the document when it is created. You need to explicitly insert +it with one of the other methods such as \method{insertBefore()} or +\method{appendChild()}. +\end{methoddesc} + +\begin{methoddesc}[Document]{createElementNS}{namespaceURI, tagName} +Create and return a new element with a namespace. The +\var{tagName} may have a prefix. The element is not inserted into the +document when it is created. You need to explicitly insert it with +one of the other methods such as \method{insertBefore()} or +\method{appendChild()}. +\end{methoddesc} + +\begin{methoddesc}[Document]{createTextNode}{data} +Create and return a text node containing the data passed as a +parameter. As with the other creation methods, this one does not +insert the node into the tree. +\end{methoddesc} + +\begin{methoddesc}[Document]{createComment}{data} +Create and return a comment node containing the data passed as a +parameter. As with the other creation methods, this one does not +insert the node into the tree. +\end{methoddesc} + +\begin{methoddesc}[Document]{createProcessingInstruction}{target, data} +Create and return a processing instruction node containing the +\var{target} and \var{data} passed as parameters. As with the other +creation methods, this one does not insert the node into the tree. +\end{methoddesc} + +\begin{methoddesc}[Document]{createAttribute}{name} +Create and return an attribute node. This method does not associate +the attribute node with any particular element. You must use +\method{setAttributeNode()} on the appropriate \class{Element} object +to use the newly created attribute instance. +\end{methoddesc} + +\begin{methoddesc}[Document]{createAttributeNS}{namespaceURI, qualifiedName} +Create and return an attribute node with a namespace. The +\var{tagName} may have a prefix. This method does not associate the +attribute node with any particular element. You must use +\method{setAttributeNode()} on the appropriate \class{Element} object +to use the newly created attribute instance. +\end{methoddesc} + +\begin{methoddesc}[Document]{getElementsByTagName}{tagName} +Search for all descendants (direct children, children's children, +etc.) with a particular element type name. +\end{methoddesc} + +\begin{methoddesc}[Document]{getElementsByTagNameNS}{namespaceURI, localName} +Search for all descendants (direct children, children's children, +etc.) with a particular namespace URI and localname. The localname is +the part of the namespace after the prefix. +\end{methoddesc} + + +\subsubsection{Element Objects \label{dom-element-objects}} + +\class{Element} is a subclass of \class{Node}, so inherits all the +attributes of that class. + +\begin{memberdesc}[Element]{tagName} +The element type name. In a namespace-using document it may have +colons in it. The value is a string. +\end{memberdesc} + +\begin{methoddesc}[Element]{getElementsByTagName}{tagName} +Same as equivalent method in the \class{Document} class. +\end{methoddesc} + +\begin{methoddesc}[Element]{getElementsByTagNameNS}{tagName} +Same as equivalent method in the \class{Document} class. +\end{methoddesc} + +\begin{methoddesc}[Element]{hasAttribute}{name} +Returns true if the element has an attribute named by \var{name}. +\end{methoddesc} + +\begin{methoddesc}[Element]{hasAttributeNS}{namespaceURI, localName} +Returns true if the element has an attribute named by +\var{namespaceURI} and \var{localName}. +\end{methoddesc} + +\begin{methoddesc}[Element]{getAttribute}{name} +Return the value of the attribute named by \var{name} as a +string. If no such attribute exists, an empty string is returned, +as if the attribute had no value. +\end{methoddesc} + +\begin{methoddesc}[Element]{getAttributeNode}{attrname} +Return the \class{Attr} node for the attribute named by +\var{attrname}. +\end{methoddesc} + +\begin{methoddesc}[Element]{getAttributeNS}{namespaceURI, localName} +Return the value of the attribute named by \var{namespaceURI} and +\var{localName} as a string. If no such attribute exists, an empty +string is returned, as if the attribute had no value. +\end{methoddesc} + +\begin{methoddesc}[Element]{getAttributeNodeNS}{namespaceURI, localName} +Return an attribute value as a node, given a \var{namespaceURI} and +\var{localName}. +\end{methoddesc} + +\begin{methoddesc}[Element]{removeAttribute}{name} +Remove an attribute by name. No exception is raised if there is no +matching attribute. +\end{methoddesc} + +\begin{methoddesc}[Element]{removeAttributeNode}{oldAttr} +Remove and return \var{oldAttr} from the attribute list, if present. +If \var{oldAttr} is not present, \exception{NotFoundErr} is raised. +\end{methoddesc} + +\begin{methoddesc}[Element]{removeAttributeNS}{namespaceURI, localName} +Remove an attribute by name. Note that it uses a localName, not a +qname. No exception is raised if there is no matching attribute. +\end{methoddesc} + +\begin{methoddesc}[Element]{setAttribute}{name, value} +Set an attribute value from a string. +\end{methoddesc} + +\begin{methoddesc}[Element]{setAttributeNode}{newAttr} +Add a new attribute node to the element, replacing an existing +attribute if necessary if the \member{name} attribute matches. If a +replacement occurs, the old attribute node will be returned. If +\var{newAttr} is already in use, \exception{InuseAttributeErr} will be +raised. +\end{methoddesc} + +\begin{methoddesc}[Element]{setAttributeNodeNS}{newAttr} +Add a new attribute node to the element, replacing an existing +attribute if necessary if the \member{namespaceURI} and +\member{localName} attributes match. If a replacement occurs, the old +attribute node will be returned. If \var{newAttr} is already in use, +\exception{InuseAttributeErr} will be raised. +\end{methoddesc} + +\begin{methoddesc}[Element]{setAttributeNS}{namespaceURI, qname, value} +Set an attribute value from a string, given a \var{namespaceURI} and a +\var{qname}. Note that a qname is the whole attribute name. This is +different than above. +\end{methoddesc} + + +\subsubsection{Attr Objects \label{dom-attr-objects}} + +\class{Attr} inherits from \class{Node}, so inherits all its +attributes. + +\begin{memberdesc}[Attr]{name} +The attribute name. In a namespace-using document it may have colons +in it. +\end{memberdesc} + +\begin{memberdesc}[Attr]{localName} +The part of the name following the colon if there is one, else the +entire name. This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[Attr]{prefix} +The part of the name preceding the colon if there is one, else the +empty string. +\end{memberdesc} + + +\subsubsection{NamedNodeMap Objects \label{dom-attributelist-objects}} + +\class{NamedNodeMap} does \emph{not} inherit from \class{Node}. + +\begin{memberdesc}[NamedNodeMap]{length} +The length of the attribute list. +\end{memberdesc} + +\begin{methoddesc}[NamedNodeMap]{item}{index} +Return an attribute with a particular index. The order you get the +attributes in is arbitrary but will be consistent for the life of a +DOM. Each item is an attribute node. Get its value with the +\member{value} attribute. +\end{methoddesc} + +There are also experimental methods that give this class more mapping +behavior. You can use them or you can use the standardized +\method{getAttribute*()} family of methods on the \class{Element} +objects. + + +\subsubsection{Comment Objects \label{dom-comment-objects}} + +\class{Comment} represents a comment in the XML document. It is a +subclass of \class{Node}, but cannot have child nodes. + +\begin{memberdesc}[Comment]{data} +The content of the comment as a string. The attribute contains all +characters between the leading \code{<!-}\code{-} and trailing +\code{-}\code{->}, but does not include them. +\end{memberdesc} + + +\subsubsection{Text and CDATASection Objects \label{dom-text-objects}} + +The \class{Text} interface represents text in the XML document. If +the parser and DOM implementation support the DOM's XML extension, +portions of the text enclosed in CDATA marked sections are stored in +\class{CDATASection} objects. These two interfaces are identical, but +provide different values for the \member{nodeType} attribute. + +These interfaces extend the \class{Node} interface. They cannot have +child nodes. + +\begin{memberdesc}[Text]{data} +The content of the text node as a string. +\end{memberdesc} + +\begin{notice} + The use of a \class{CDATASection} node does not indicate that the + node represents a complete CDATA marked section, only that the + content of the node was part of a CDATA section. A single CDATA + section may be represented by more than one node in the document + tree. There is no way to determine whether two adjacent + \class{CDATASection} nodes represent different CDATA marked + sections. +\end{notice} + + +\subsubsection{ProcessingInstruction Objects \label{dom-pi-objects}} + +Represents a processing instruction in the XML document; this inherits +from the \class{Node} interface and cannot have child nodes. + +\begin{memberdesc}[ProcessingInstruction]{target} +The content of the processing instruction up to the first whitespace +character. This is a read-only attribute. +\end{memberdesc} + +\begin{memberdesc}[ProcessingInstruction]{data} +The content of the processing instruction following the first +whitespace character. +\end{memberdesc} + + +\subsubsection{Exceptions \label{dom-exceptions}} + +\versionadded{2.1} + +The DOM Level~2 recommendation defines a single exception, +\exception{DOMException}, and a number of constants that allow +applications to determine what sort of error occurred. +\exception{DOMException} instances carry a \member{code} attribute +that provides the appropriate value for the specific exception. + +The Python DOM interface provides the constants, but also expands the +set of exceptions so that a specific exception exists for each of the +exception codes defined by the DOM. The implementations must raise +the appropriate specific exception, each of which carries the +appropriate value for the \member{code} attribute. + +\begin{excdesc}{DOMException} + Base exception class used for all specific DOM exceptions. This + exception class cannot be directly instantiated. +\end{excdesc} + +\begin{excdesc}{DomstringSizeErr} + Raised when a specified range of text does not fit into a string. + This is not known to be used in the Python DOM implementations, but + may be received from DOM implementations not written in Python. +\end{excdesc} + +\begin{excdesc}{HierarchyRequestErr} + Raised when an attempt is made to insert a node where the node type + is not allowed. +\end{excdesc} + +\begin{excdesc}{IndexSizeErr} + Raised when an index or size parameter to a method is negative or + exceeds the allowed values. +\end{excdesc} + +\begin{excdesc}{InuseAttributeErr} + Raised when an attempt is made to insert an \class{Attr} node that + is already present elsewhere in the document. +\end{excdesc} + +\begin{excdesc}{InvalidAccessErr} + Raised if a parameter or an operation is not supported on the + underlying object. +\end{excdesc} + +\begin{excdesc}{InvalidCharacterErr} + This exception is raised when a string parameter contains a + character that is not permitted in the context it's being used in by + the XML 1.0 recommendation. For example, attempting to create an + \class{Element} node with a space in the element type name will + cause this error to be raised. +\end{excdesc} + +\begin{excdesc}{InvalidModificationErr} + Raised when an attempt is made to modify the type of a node. +\end{excdesc} + +\begin{excdesc}{InvalidStateErr} + Raised when an attempt is made to use an object that is not defined or is no + longer usable. +\end{excdesc} + +\begin{excdesc}{NamespaceErr} + If an attempt is made to change any object in a way that is not + permitted with regard to the + \citetitle[http://www.w3.org/TR/REC-xml-names/]{Namespaces in XML} + recommendation, this exception is raised. +\end{excdesc} + +\begin{excdesc}{NotFoundErr} + Exception when a node does not exist in the referenced context. For + example, \method{NamedNodeMap.removeNamedItem()} will raise this if + the node passed in does not exist in the map. +\end{excdesc} + +\begin{excdesc}{NotSupportedErr} + Raised when the implementation does not support the requested type + of object or operation. +\end{excdesc} + +\begin{excdesc}{NoDataAllowedErr} + This is raised if data is specified for a node which does not + support data. + % XXX a better explanation is needed! +\end{excdesc} + +\begin{excdesc}{NoModificationAllowedErr} + Raised on attempts to modify an object where modifications are not + allowed (such as for read-only nodes). +\end{excdesc} + +\begin{excdesc}{SyntaxErr} + Raised when an invalid or illegal string is specified. + % XXX how is this different from InvalidCharacterErr ??? +\end{excdesc} + +\begin{excdesc}{WrongDocumentErr} + Raised when a node is inserted in a different document than it + currently belongs to, and the implementation does not support + migrating the node from one document to the other. +\end{excdesc} + +The exception codes defined in the DOM recommendation map to the +exceptions described above according to this table: + +\begin{tableii}{l|l}{constant}{Constant}{Exception} + \lineii{DOMSTRING_SIZE_ERR}{\exception{DomstringSizeErr}} + \lineii{HIERARCHY_REQUEST_ERR}{\exception{HierarchyRequestErr}} + \lineii{INDEX_SIZE_ERR}{\exception{IndexSizeErr}} + \lineii{INUSE_ATTRIBUTE_ERR}{\exception{InuseAttributeErr}} + \lineii{INVALID_ACCESS_ERR}{\exception{InvalidAccessErr}} + \lineii{INVALID_CHARACTER_ERR}{\exception{InvalidCharacterErr}} + \lineii{INVALID_MODIFICATION_ERR}{\exception{InvalidModificationErr}} + \lineii{INVALID_STATE_ERR}{\exception{InvalidStateErr}} + \lineii{NAMESPACE_ERR}{\exception{NamespaceErr}} + \lineii{NOT_FOUND_ERR}{\exception{NotFoundErr}} + \lineii{NOT_SUPPORTED_ERR}{\exception{NotSupportedErr}} + \lineii{NO_DATA_ALLOWED_ERR}{\exception{NoDataAllowedErr}} + \lineii{NO_MODIFICATION_ALLOWED_ERR}{\exception{NoModificationAllowedErr}} + \lineii{SYNTAX_ERR}{\exception{SyntaxErr}} + \lineii{WRONG_DOCUMENT_ERR}{\exception{WrongDocumentErr}} +\end{tableii} + + +\subsection{Conformance \label{dom-conformance}} + +This section describes the conformance requirements and relationships +between the Python DOM API, the W3C DOM recommendations, and the OMG +IDL mapping for Python. + + +\subsubsection{Type Mapping \label{dom-type-mapping}} + +The primitive IDL types used in the DOM specification are mapped to +Python types according to the following table. + +\begin{tableii}{l|l}{code}{IDL Type}{Python Type} + \lineii{boolean}{\code{IntegerType} (with a value of \code{0} or \code{1})} + \lineii{int}{\code{IntegerType}} + \lineii{long int}{\code{IntegerType}} + \lineii{unsigned int}{\code{IntegerType}} +\end{tableii} + +Additionally, the \class{DOMString} defined in the recommendation is +mapped to a Python string or Unicode string. Applications should +be able to handle Unicode whenever a string is returned from the DOM. + +The IDL \keyword{null} value is mapped to \code{None}, which may be +accepted or provided by the implementation whenever \keyword{null} is +allowed by the API. + + +\subsubsection{Accessor Methods \label{dom-accessor-methods}} + +The mapping from OMG IDL to Python defines accessor functions for IDL +\keyword{attribute} declarations in much the way the Java mapping +does. Mapping the IDL declarations + +\begin{verbatim} +readonly attribute string someValue; + attribute string anotherValue; +\end{verbatim} + +yields three accessor functions: a ``get'' method for +\member{someValue} (\method{_get_someValue()}), and ``get'' and +``set'' methods for +\member{anotherValue} (\method{_get_anotherValue()} and +\method{_set_anotherValue()}). The mapping, in particular, does not +require that the IDL attributes are accessible as normal Python +attributes: \code{\var{object}.someValue} is \emph{not} required to +work, and may raise an \exception{AttributeError}. + +The Python DOM API, however, \emph{does} require that normal attribute +access work. This means that the typical surrogates generated by +Python IDL compilers are not likely to work, and wrapper objects may +be needed on the client if the DOM objects are accessed via CORBA. +While this does require some additional consideration for CORBA DOM +clients, the implementers with experience using DOM over CORBA from +Python do not consider this a problem. Attributes that are declared +\keyword{readonly} may not restrict write access in all DOM +implementations. + +In the Python DOM API, accessor functions are not required. If provided, +they should take the form defined by the Python IDL mapping, but +these methods are considered unnecessary since the attributes are +accessible directly from Python. ``Set'' accessors should never be +provided for \keyword{readonly} attributes. + +The IDL definitions do not fully embody the requirements of the W3C DOM +API, such as the notion of certain objects, such as the return value of +\method{getElementsByTagName()}, being ``live''. The Python DOM API +does not require implementations to enforce such requirements. diff --git a/sys/src/cmd/python/Doc/lib/xmldomminidom.tex b/sys/src/cmd/python/Doc/lib/xmldomminidom.tex new file mode 100644 index 000000000..093915fc8 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmldomminidom.tex @@ -0,0 +1,285 @@ +\section{\module{xml.dom.minidom} --- + Lightweight DOM implementation} + +\declaremodule{standard}{xml.dom.minidom} +\modulesynopsis{Lightweight Document Object Model (DOM) implementation.} +\moduleauthor{Paul Prescod}{paul@prescod.net} +\sectionauthor{Paul Prescod}{paul@prescod.net} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} + +\versionadded{2.0} + +\module{xml.dom.minidom} is a light-weight implementation of the +Document Object Model interface. It is intended to be +simpler than the full DOM and also significantly smaller. + +DOM applications typically start by parsing some XML into a DOM. With +\module{xml.dom.minidom}, this is done through the parse functions: + +\begin{verbatim} +from xml.dom.minidom import parse, parseString + +dom1 = parse('c:\\temp\\mydata.xml') # parse an XML file by name + +datasource = open('c:\\temp\\mydata.xml') +dom2 = parse(datasource) # parse an open file + +dom3 = parseString('<myxml>Some data<empty/> some more data</myxml>') +\end{verbatim} + +The \function{parse()} function can take either a filename or an open +file object. + +\begin{funcdesc}{parse}{filename_or_file{, parser}} + Return a \class{Document} from the given input. \var{filename_or_file} + may be either a file name, or a file-like object. \var{parser}, if + given, must be a SAX2 parser object. This function will change the + document handler of the parser and activate namespace support; other + parser configuration (like setting an entity resolver) must have been + done in advance. +\end{funcdesc} + +If you have XML in a string, you can use the +\function{parseString()} function instead: + +\begin{funcdesc}{parseString}{string\optional{, parser}} + Return a \class{Document} that represents the \var{string}. This + method creates a \class{StringIO} object for the string and passes + that on to \function{parse}. +\end{funcdesc} + +Both functions return a \class{Document} object representing the +content of the document. + +What the \function{parse()} and \function{parseString()} functions do +is connect an XML parser with a ``DOM builder'' that can accept parse +events from any SAX parser and convert them into a DOM tree. The name +of the functions are perhaps misleading, but are easy to grasp when +learning the interfaces. The parsing of the document will be +completed before these functions return; it's simply that these +functions do not provide a parser implementation themselves. + +You can also create a \class{Document} by calling a method on a ``DOM +Implementation'' object. You can get this object either by calling +the \function{getDOMImplementation()} function in the +\refmodule{xml.dom} package or the \module{xml.dom.minidom} module. +Using the implementation from the \module{xml.dom.minidom} module will +always return a \class{Document} instance from the minidom +implementation, while the version from \refmodule{xml.dom} may provide +an alternate implementation (this is likely if you have the +\ulink{PyXML package}{http://pyxml.sourceforge.net/} installed). Once +you have a \class{Document}, you can add child nodes to it to populate +the DOM: + +\begin{verbatim} +from xml.dom.minidom import getDOMImplementation + +impl = getDOMImplementation() + +newdoc = impl.createDocument(None, "some_tag", None) +top_element = newdoc.documentElement +text = newdoc.createTextNode('Some textual content.') +top_element.appendChild(text) +\end{verbatim} + +Once you have a DOM document object, you can access the parts of your +XML document through its properties and methods. These properties are +defined in the DOM specification. The main property of the document +object is the \member{documentElement} property. It gives you the +main element in the XML document: the one that holds all others. Here +is an example program: + +\begin{verbatim} +dom3 = parseString("<myxml>Some data</myxml>") +assert dom3.documentElement.tagName == "myxml" +\end{verbatim} + +When you are finished with a DOM, you should clean it up. This is +necessary because some versions of Python do not support garbage +collection of objects that refer to each other in a cycle. Until this +restriction is removed from all versions of Python, it is safest to +write your code as if cycles would not be cleaned up. + +The way to clean up a DOM is to call its \method{unlink()} method: + +\begin{verbatim} +dom1.unlink() +dom2.unlink() +dom3.unlink() +\end{verbatim} + +\method{unlink()} is a \module{xml.dom.minidom}-specific extension to +the DOM API. After calling \method{unlink()} on a node, the node and +its descendants are essentially useless. + +\begin{seealso} + \seetitle[http://www.w3.org/TR/REC-DOM-Level-1/]{Document Object + Model (DOM) Level 1 Specification} + {The W3C recommendation for the + DOM supported by \module{xml.dom.minidom}.} +\end{seealso} + + +\subsection{DOM Objects \label{dom-objects}} + +The definition of the DOM API for Python is given as part of the +\refmodule{xml.dom} module documentation. This section lists the +differences between the API and \refmodule{xml.dom.minidom}. + + +\begin{methoddesc}[Node]{unlink}{} +Break internal references within the DOM so that it will be garbage +collected on versions of Python without cyclic GC. Even when cyclic +GC is available, using this can make large amounts of memory available +sooner, so calling this on DOM objects as soon as they are no longer +needed is good practice. This only needs to be called on the +\class{Document} object, but may be called on child nodes to discard +children of that node. +\end{methoddesc} + +\begin{methoddesc}[Node]{writexml}{writer\optional{,indent=""\optional{,addindent=""\optional{,newl=""}}}} +Write XML to the writer object. The writer should have a +\method{write()} method which matches that of the file object +interface. The \var{indent} parameter is the indentation of the current +node. The \var{addindent} parameter is the incremental indentation to use +for subnodes of the current one. The \var{newl} parameter specifies the +string to use to terminate newlines. + +\versionchanged[The optional keyword parameters +\var{indent}, \var{addindent}, and \var{newl} were added to support pretty +output]{2.1} + +\versionchanged[For the \class{Document} node, an additional keyword +argument \var{encoding} can be used to specify the encoding field of the XML +header]{2.3} +\end{methoddesc} + +\begin{methoddesc}[Node]{toxml}{\optional{encoding}} +Return the XML that the DOM represents as a string. + +With no argument, the XML header does not specify an encoding, and the +result is Unicode string if the default encoding cannot represent all +characters in the document. Encoding this string in an encoding other +than UTF-8 is likely incorrect, since UTF-8 is the default encoding of +XML. + +With an explicit \var{encoding} argument, the result is a byte string +in the specified encoding. It is recommended that this argument is +always specified. To avoid \exception{UnicodeError} exceptions in case of +unrepresentable text data, the encoding argument should be specified +as "utf-8". + +\versionchanged[the \var{encoding} argument was introduced]{2.3} +\end{methoddesc} + +\begin{methoddesc}[Node]{toprettyxml}{\optional{indent\optional{, newl}}} +Return a pretty-printed version of the document. \var{indent} specifies +the indentation string and defaults to a tabulator; \var{newl} specifies +the string emitted at the end of each line and defaults to \code{\e n}. + +\versionadded{2.1} +\versionchanged[the encoding argument; see \method{toxml()}]{2.3} +\end{methoddesc} + +The following standard DOM methods have special considerations with +\refmodule{xml.dom.minidom}: + +\begin{methoddesc}[Node]{cloneNode}{deep} +Although this method was present in the version of +\refmodule{xml.dom.minidom} packaged with Python 2.0, it was seriously +broken. This has been corrected for subsequent releases. +\end{methoddesc} + + +\subsection{DOM Example \label{dom-example}} + +This example program is a fairly realistic example of a simple +program. In this particular case, we do not take much advantage +of the flexibility of the DOM. + +\verbatiminput{minidom-example.py} + + +\subsection{minidom and the DOM standard \label{minidom-and-dom}} + +The \refmodule{xml.dom.minidom} module is essentially a DOM +1.0-compatible DOM with some DOM 2 features (primarily namespace +features). + +Usage of the DOM interface in Python is straight-forward. The +following mapping rules apply: + +\begin{itemize} +\item Interfaces are accessed through instance objects. Applications + should not instantiate the classes themselves; they should use + the creator functions available on the \class{Document} object. + Derived interfaces support all operations (and attributes) from + the base interfaces, plus any new operations. + +\item Operations are used as methods. Since the DOM uses only + \keyword{in} parameters, the arguments are passed in normal + order (from left to right). There are no optional + arguments. \keyword{void} operations return \code{None}. + +\item IDL attributes map to instance attributes. For compatibility + with the OMG IDL language mapping for Python, an attribute + \code{foo} can also be accessed through accessor methods + \method{_get_foo()} and \method{_set_foo()}. \keyword{readonly} + attributes must not be changed; this is not enforced at + runtime. + +\item The types \code{short int}, \code{unsigned int}, \code{unsigned + long long}, and \code{boolean} all map to Python integer + objects. + +\item The type \code{DOMString} maps to Python strings. + \refmodule{xml.dom.minidom} supports either byte or Unicode + strings, but will normally produce Unicode strings. Values + of type \code{DOMString} may also be \code{None} where allowed + to have the IDL \code{null} value by the DOM specification from + the W3C. + +\item \keyword{const} declarations map to variables in their + respective scope + (e.g. \code{xml.dom.minidom.Node.PROCESSING_INSTRUCTION_NODE}); + they must not be changed. + +\item \code{DOMException} is currently not supported in + \refmodule{xml.dom.minidom}. Instead, + \refmodule{xml.dom.minidom} uses standard Python exceptions such + as \exception{TypeError} and \exception{AttributeError}. + +\item \class{NodeList} objects are implemented using Python's built-in + list type. Starting with Python 2.2, these objects provide the + interface defined in the DOM specification, but with earlier + versions of Python they do not support the official API. They + are, however, much more ``Pythonic'' than the interface defined + in the W3C recommendations. +\end{itemize} + + +The following interfaces have no implementation in +\refmodule{xml.dom.minidom}: + +\begin{itemize} +\item \class{DOMTimeStamp} + +\item \class{DocumentType} (added in Python 2.1) + +\item \class{DOMImplementation} (added in Python 2.1) + +\item \class{CharacterData} + +\item \class{CDATASection} + +\item \class{Notation} + +\item \class{Entity} + +\item \class{EntityReference} + +\item \class{DocumentFragment} +\end{itemize} + +Most of these reflect information in the XML document that is not of +general utility to most DOM users. diff --git a/sys/src/cmd/python/Doc/lib/xmldompulldom.tex b/sys/src/cmd/python/Doc/lib/xmldompulldom.tex new file mode 100644 index 000000000..a2ce66708 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmldompulldom.tex @@ -0,0 +1,61 @@ +\section{\module{xml.dom.pulldom} --- + Support for building partial DOM trees} + +\declaremodule{standard}{xml.dom.pulldom} +\modulesynopsis{Support for building partial DOM trees from SAX events.} +\moduleauthor{Paul Prescod}{paul@prescod.net} + +\versionadded{2.0} + +\module{xml.dom.pulldom} allows building only selected portions of a +Document Object Model representation of a document from SAX events. + + +\begin{classdesc}{PullDOM}{\optional{documentFactory}} + \class{xml.sax.handler.ContentHandler} implementation that ... +\end{classdesc} + + +\begin{classdesc}{DOMEventStream}{stream, parser, bufsize} + ... +\end{classdesc} + + +\begin{classdesc}{SAX2DOM}{\optional{documentFactory}} + \class{xml.sax.handler.ContentHandler} implementation that ... +\end{classdesc} + + +\begin{funcdesc}{parse}{stream_or_string\optional{, + parser\optional{, bufsize}}} + ... +\end{funcdesc} + + +\begin{funcdesc}{parseString}{string\optional{, parser}} + ... +\end{funcdesc} + + +\begin{datadesc}{default_bufsize} + Default value for the \var{bufsize} parameter to \function{parse()}. + \versionchanged[The value of this variable can be changed before + calling \function{parse()} and the new value will + take effect]{2.1} +\end{datadesc} + + +\subsection{DOMEventStream Objects \label{domeventstream-objects}} + + +\begin{methoddesc}[DOMEventStream]{getEvent}{} + ... +\end{methoddesc} + +\begin{methoddesc}[DOMEventStream]{expandNode}{node} + ... +\end{methoddesc} + +\begin{methoddesc}[DOMEventStream]{reset}{} + ... +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/xmletree.tex b/sys/src/cmd/python/Doc/lib/xmletree.tex new file mode 100644 index 000000000..789062d81 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmletree.tex @@ -0,0 +1,27 @@ +\section{\module{xml.etree} --- + The ElementTree API for XML} + +\declaremodule{standard}{xml.etree} +\modulesynopsis{Package containing common ElementTree modules.} +\moduleauthor{Fredrik Lundh}{fredrik@pythonware.com} + +\versionadded{2.5} + +The ElementTree package is a simple, efficient, and quite popular +library for XML manipulation in Python. + +The \module{xml.etree} package contains the most common components +from the ElementTree API library. +In the current release, this package contains the \module{ElementTree}, +\module{ElementPath}, and \module{ElementInclude} modules from the full +ElementTree distribution. + +% XXX To be continued! + +\begin{seealso} +\seetitle[http://effbot.org/tag/elementtree] + {ElementTree Overview} + {The home page for \module{ElementTree}. This includes links + to additional documentation, alternative implementations, and + other add-ons.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/lib/xmlsax.tex b/sys/src/cmd/python/Doc/lib/xmlsax.tex new file mode 100644 index 000000000..838c279fd --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmlsax.tex @@ -0,0 +1,143 @@ +\section{\module{xml.sax} --- + Support for SAX2 parsers} + +\declaremodule{standard}{xml.sax} +\modulesynopsis{Package containing SAX2 base classes and convenience + functions.} +\moduleauthor{Lars Marius Garshol}{larsga@garshol.priv.no} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} + +\versionadded{2.0} + + +The \module{xml.sax} package provides a number of modules which +implement the Simple API for XML (SAX) interface for Python. The +package itself provides the SAX exceptions and the convenience +functions which will be most used by users of the SAX API. + +The convenience functions are: + +\begin{funcdesc}{make_parser}{\optional{parser_list}} + Create and return a SAX \class{XMLReader} object. The first parser + found will be used. If \var{parser_list} is provided, it must be a + sequence of strings which name modules that have a function named + \function{create_parser()}. Modules listed in \var{parser_list} + will be used before modules in the default list of parsers. +\end{funcdesc} + +\begin{funcdesc}{parse}{filename_or_stream, handler\optional{, error_handler}} + Create a SAX parser and use it to parse a document. The document, + passed in as \var{filename_or_stream}, can be a filename or a file + object. The \var{handler} parameter needs to be a SAX + \class{ContentHandler} instance. If \var{error_handler} is given, + it must be a SAX \class{ErrorHandler} instance; if omitted, + \exception{SAXParseException} will be raised on all errors. There + is no return value; all work must be done by the \var{handler} + passed in. +\end{funcdesc} + +\begin{funcdesc}{parseString}{string, handler\optional{, error_handler}} + Similar to \function{parse()}, but parses from a buffer \var{string} + received as a parameter. +\end{funcdesc} + +A typical SAX application uses three kinds of objects: readers, +handlers and input sources. ``Reader'' in this context is another +term for parser, i.e.\ some piece of code that reads the bytes or +characters from the input source, and produces a sequence of events. +The events then get distributed to the handler objects, i.e.\ the +reader invokes a method on the handler. A SAX application must +therefore obtain a reader object, create or open the input sources, +create the handlers, and connect these objects all together. As the +final step of preparation, the reader is called to parse the input. +During parsing, methods on the handler objects are called based on +structural and syntactic events from the input data. + +For these objects, only the interfaces are relevant; they are normally +not instantiated by the application itself. Since Python does not have +an explicit notion of interface, they are formally introduced as +classes, but applications may use implementations which do not inherit +from the provided classes. The \class{InputSource}, \class{Locator}, +\class{Attributes}, \class{AttributesNS}, and +\class{XMLReader} interfaces are defined in the module +\refmodule{xml.sax.xmlreader}. The handler interfaces are defined in +\refmodule{xml.sax.handler}. For convenience, \class{InputSource} +(which is often instantiated directly) and the handler classes are +also available from \module{xml.sax}. These interfaces are described +below. + +In addition to these classes, \module{xml.sax} provides the following +exception classes. + +\begin{excclassdesc}{SAXException}{msg\optional{, exception}} + Encapsulate an XML error or warning. This class can contain basic + error or warning information from either the XML parser or the + application: it can be subclassed to provide additional + functionality or to add localization. Note that although the + handlers defined in the \class{ErrorHandler} interface receive + instances of this exception, it is not required to actually raise + the exception --- it is also useful as a container for information. + + When instantiated, \var{msg} should be a human-readable description + of the error. The optional \var{exception} parameter, if given, + should be \code{None} or an exception that was caught by the parsing + code and is being passed along as information. + + This is the base class for the other SAX exception classes. +\end{excclassdesc} + +\begin{excclassdesc}{SAXParseException}{msg, exception, locator} + Subclass of \exception{SAXException} raised on parse errors. + Instances of this class are passed to the methods of the SAX + \class{ErrorHandler} interface to provide information about the + parse error. This class supports the SAX \class{Locator} interface + as well as the \class{SAXException} interface. +\end{excclassdesc} + +\begin{excclassdesc}{SAXNotRecognizedException}{msg\optional{, exception}} + Subclass of \exception{SAXException} raised when a SAX + \class{XMLReader} is confronted with an unrecognized feature or + property. SAX applications and extensions may use this class for + similar purposes. +\end{excclassdesc} + +\begin{excclassdesc}{SAXNotSupportedException}{msg\optional{, exception}} + Subclass of \exception{SAXException} raised when a SAX + \class{XMLReader} is asked to enable a feature that is not + supported, or to set a property to a value that the implementation + does not support. SAX applications and extensions may use this + class for similar purposes. +\end{excclassdesc} + + +\begin{seealso} + \seetitle[http://www.saxproject.org/]{SAX: The Simple API for + XML}{This site is the focal point for the definition of + the SAX API. It provides a Java implementation and online + documentation. Links to implementations and historical + information are also available.} + + \seemodule{xml.sax.handler}{Definitions of the interfaces for + application-provided objects.} + + \seemodule{xml.sax.saxutils}{Convenience functions for use in SAX + applications.} + + \seemodule{xml.sax.xmlreader}{Definitions of the interfaces for + parser-provided objects.} +\end{seealso} + + +\subsection{SAXException Objects \label{sax-exception-objects}} + +The \class{SAXException} exception class supports the following +methods: + +\begin{methoddesc}[SAXException]{getMessage}{} + Return a human-readable message describing the error condition. +\end{methoddesc} + +\begin{methoddesc}[SAXException]{getException}{} + Return an encapsulated exception object, or \code{None}. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/xmlsaxhandler.tex b/sys/src/cmd/python/Doc/lib/xmlsaxhandler.tex new file mode 100644 index 000000000..c3c72e7c0 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmlsaxhandler.tex @@ -0,0 +1,381 @@ +\section{\module{xml.sax.handler} --- + Base classes for SAX handlers} + +\declaremodule{standard}{xml.sax.handler} +\modulesynopsis{Base classes for SAX event handlers.} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} +\moduleauthor{Lars Marius Garshol}{larsga@garshol.priv.no} + +\versionadded{2.0} + + +The SAX API defines four kinds of handlers: content handlers, DTD +handlers, error handlers, and entity resolvers. Applications normally +only need to implement those interfaces whose events they are +interested in; they can implement the interfaces in a single object or +in multiple objects. Handler implementations should inherit from the +base classes provided in the module \module{xml.sax.handler}, so that all +methods get default implementations. + +\begin{classdesc*}{ContentHandler} + This is the main callback interface in SAX, and the one most + important to applications. The order of events in this interface + mirrors the order of the information in the document. +\end{classdesc*} + +\begin{classdesc*}{DTDHandler} + Handle DTD events. + + This interface specifies only those DTD events required for basic + parsing (unparsed entities and attributes). +\end{classdesc*} + +\begin{classdesc*}{EntityResolver} + Basic interface for resolving entities. If you create an object + implementing this interface, then register the object with your + Parser, the parser will call the method in your object to resolve all + external entities. +\end{classdesc*} + +\begin{classdesc*}{ErrorHandler} + Interface used by the parser to present error and warning messages + to the application. The methods of this object control whether errors + are immediately converted to exceptions or are handled in some other + way. +\end{classdesc*} + +In addition to these classes, \module{xml.sax.handler} provides +symbolic constants for the feature and property names. + +\begin{datadesc}{feature_namespaces} + Value: \code{"http://xml.org/sax/features/namespaces"}\\ + true: Perform Namespace processing.\\ + false: Optionally do not perform Namespace processing + (implies namespace-prefixes; default).\\ + access: (parsing) read-only; (not parsing) read/write +\end{datadesc} + +\begin{datadesc}{feature_namespace_prefixes} + Value: \code{"http://xml.org/sax/features/namespace-prefixes"}\\ + true: Report the original prefixed names and attributes used for Namespace + declarations.\\ + false: Do not report attributes used for Namespace declarations, and + optionally do not report original prefixed names (default).\\ + access: (parsing) read-only; (not parsing) read/write +\end{datadesc} + +\begin{datadesc}{feature_string_interning} + Value: \code{"http://xml.org/sax/features/string-interning"}\\ + true: All element names, prefixes, attribute names, Namespace URIs, and + local names are interned using the built-in intern function.\\ + false: Names are not necessarily interned, although they may be (default).\\ + access: (parsing) read-only; (not parsing) read/write +\end{datadesc} + +\begin{datadesc}{feature_validation} + Value: \code{"http://xml.org/sax/features/validation"}\\ + true: Report all validation errors (implies external-general-entities and + external-parameter-entities).\\ + false: Do not report validation errors.\\ + access: (parsing) read-only; (not parsing) read/write +\end{datadesc} + +\begin{datadesc}{feature_external_ges} + Value: \code{"http://xml.org/sax/features/external-general-entities"}\\ + true: Include all external general (text) entities.\\ + false: Do not include external general entities.\\ + access: (parsing) read-only; (not parsing) read/write +\end{datadesc} + +\begin{datadesc}{feature_external_pes} + Value: \code{"http://xml.org/sax/features/external-parameter-entities"}\\ + true: Include all external parameter entities, including the external + DTD subset.\\ + false: Do not include any external parameter entities, even the external + DTD subset.\\ + access: (parsing) read-only; (not parsing) read/write +\end{datadesc} + +\begin{datadesc}{all_features} + List of all features. +\end{datadesc} + +\begin{datadesc}{property_lexical_handler} + Value: \code{"http://xml.org/sax/properties/lexical-handler"}\\ + data type: xml.sax.sax2lib.LexicalHandler (not supported in Python 2)\\ + description: An optional extension handler for lexical events like comments.\\ + access: read/write +\end{datadesc} + +\begin{datadesc}{property_declaration_handler} + Value: \code{"http://xml.org/sax/properties/declaration-handler"}\\ + data type: xml.sax.sax2lib.DeclHandler (not supported in Python 2)\\ + description: An optional extension handler for DTD-related events other + than notations and unparsed entities.\\ + access: read/write +\end{datadesc} + +\begin{datadesc}{property_dom_node} + Value: \code{"http://xml.org/sax/properties/dom-node"}\\ + data type: org.w3c.dom.Node (not supported in Python 2) \\ + description: When parsing, the current DOM node being visited if this is + a DOM iterator; when not parsing, the root DOM node for + iteration.\\ + access: (parsing) read-only; (not parsing) read/write +\end{datadesc} + +\begin{datadesc}{property_xml_string} + Value: \code{"http://xml.org/sax/properties/xml-string"}\\ + data type: String\\ + description: The literal string of characters that was the source for + the current event.\\ + access: read-only +\end{datadesc} + +\begin{datadesc}{all_properties} + List of all known property names. +\end{datadesc} + + +\subsection{ContentHandler Objects \label{content-handler-objects}} + +Users are expected to subclass \class{ContentHandler} to support their +application. The following methods are called by the parser on the +appropriate events in the input document: + +\begin{methoddesc}[ContentHandler]{setDocumentLocator}{locator} + Called by the parser to give the application a locator for locating + the origin of document events. + + SAX parsers are strongly encouraged (though not absolutely required) + to supply a locator: if it does so, it must supply the locator to + the application by invoking this method before invoking any of the + other methods in the DocumentHandler interface. + + The locator allows the application to determine the end position of + any document-related event, even if the parser is not reporting an + error. Typically, the application will use this information for + reporting its own errors (such as character content that does not + match an application's business rules). The information returned by + the locator is probably not sufficient for use with a search engine. + + Note that the locator will return correct information only during + the invocation of the events in this interface. The application + should not attempt to use it at any other time. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{startDocument}{} + Receive notification of the beginning of a document. + + The SAX parser will invoke this method only once, before any other + methods in this interface or in DTDHandler (except for + \method{setDocumentLocator()}). +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{endDocument}{} + Receive notification of the end of a document. + + The SAX parser will invoke this method only once, and it will be the + last method invoked during the parse. The parser shall not invoke + this method until it has either abandoned parsing (because of an + unrecoverable error) or reached the end of input. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{startPrefixMapping}{prefix, uri} + Begin the scope of a prefix-URI Namespace mapping. + + The information from this event is not necessary for normal + Namespace processing: the SAX XML reader will automatically replace + prefixes for element and attribute names when the + \code{feature_namespaces} feature is enabled (the default). + +%% XXX This is not really the default, is it? MvL + + There are cases, however, when applications need to use prefixes in + character data or in attribute values, where they cannot safely be + expanded automatically; the \method{startPrefixMapping()} and + \method{endPrefixMapping()} events supply the information to the + application to expand prefixes in those contexts itself, if + necessary. + + Note that \method{startPrefixMapping()} and + \method{endPrefixMapping()} events are not guaranteed to be properly + nested relative to each-other: all \method{startPrefixMapping()} + events will occur before the corresponding \method{startElement()} + event, and all \method{endPrefixMapping()} events will occur after + the corresponding \method{endElement()} event, but their order is + not guaranteed. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{endPrefixMapping}{prefix} + End the scope of a prefix-URI mapping. + + See \method{startPrefixMapping()} for details. This event will + always occur after the corresponding \method{endElement()} event, + but the order of \method{endPrefixMapping()} events is not otherwise + guaranteed. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{startElement}{name, attrs} + Signals the start of an element in non-namespace mode. + + The \var{name} parameter contains the raw XML 1.0 name of the + element type as a string and the \var{attrs} parameter holds an + object of the \ulink{\class{Attributes} + interface}{attributes-objects.html} containing the attributes of the + element. The object passed as \var{attrs} may be re-used by the + parser; holding on to a reference to it is not a reliable way to + keep a copy of the attributes. To keep a copy of the attributes, + use the \method{copy()} method of the \var{attrs} object. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{endElement}{name} + Signals the end of an element in non-namespace mode. + + The \var{name} parameter contains the name of the element type, just + as with the \method{startElement()} event. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{startElementNS}{name, qname, attrs} + Signals the start of an element in namespace mode. + + The \var{name} parameter contains the name of the element type as a + \code{(\var{uri}, \var{localname})} tuple, the \var{qname} parameter + contains the raw XML 1.0 name used in the source document, and the + \var{attrs} parameter holds an instance of the + \ulink{\class{AttributesNS} interface}{attributes-ns-objects.html} + containing the attributes of the element. If no namespace is + associated with the element, the \var{uri} component of \var{name} + will be \code{None}. The object passed as \var{attrs} may be + re-used by the parser; holding on to a reference to it is not a + reliable way to keep a copy of the attributes. To keep a copy of + the attributes, use the \method{copy()} method of the \var{attrs} + object. + + Parsers may set the \var{qname} parameter to \code{None}, unless the + \code{feature_namespace_prefixes} feature is activated. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{endElementNS}{name, qname} + Signals the end of an element in namespace mode. + + The \var{name} parameter contains the name of the element type, just + as with the \method{startElementNS()} method, likewise the + \var{qname} parameter. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{characters}{content} + Receive notification of character data. + + The Parser will call this method to report each chunk of character + data. SAX parsers may return all contiguous character data in a + single chunk, or they may split it into several chunks; however, all + of the characters in any single event must come from the same + external entity so that the Locator provides useful information. + + \var{content} may be a Unicode string or a byte string; the + \code{expat} reader module produces always Unicode strings. + + \note{The earlier SAX 1 interface provided by the Python + XML Special Interest Group used a more Java-like interface for this + method. Since most parsers used from Python did not take advantage + of the older interface, the simpler signature was chosen to replace + it. To convert old code to the new interface, use \var{content} + instead of slicing content with the old \var{offset} and + \var{length} parameters.} +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{ignorableWhitespace}{whitespace} + Receive notification of ignorable whitespace in element content. + + Validating Parsers must use this method to report each chunk + of ignorable whitespace (see the W3C XML 1.0 recommendation, + section 2.10): non-validating parsers may also use this method + if they are capable of parsing and using content models. + + SAX parsers may return all contiguous whitespace in a single + chunk, or they may split it into several chunks; however, all + of the characters in any single event must come from the same + external entity, so that the Locator provides useful + information. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{processingInstruction}{target, data} + Receive notification of a processing instruction. + + The Parser will invoke this method once for each processing + instruction found: note that processing instructions may occur + before or after the main document element. + + A SAX parser should never report an XML declaration (XML 1.0, + section 2.8) or a text declaration (XML 1.0, section 4.3.1) using + this method. +\end{methoddesc} + +\begin{methoddesc}[ContentHandler]{skippedEntity}{name} + Receive notification of a skipped entity. + + The Parser will invoke this method once for each entity + skipped. Non-validating processors may skip entities if they have + not seen the declarations (because, for example, the entity was + declared in an external DTD subset). All processors may skip + external entities, depending on the values of the + \code{feature_external_ges} and the + \code{feature_external_pes} properties. +\end{methoddesc} + + +\subsection{DTDHandler Objects \label{dtd-handler-objects}} + +\class{DTDHandler} instances provide the following methods: + +\begin{methoddesc}[DTDHandler]{notationDecl}{name, publicId, systemId} + Handle a notation declaration event. +\end{methoddesc} + +\begin{methoddesc}[DTDHandler]{unparsedEntityDecl}{name, publicId, + systemId, ndata} + Handle an unparsed entity declaration event. +\end{methoddesc} + + +\subsection{EntityResolver Objects \label{entity-resolver-objects}} + +\begin{methoddesc}[EntityResolver]{resolveEntity}{publicId, systemId} + Resolve the system identifier of an entity and return either the + system identifier to read from as a string, or an InputSource to + read from. The default implementation returns \var{systemId}. +\end{methoddesc} + + +\subsection{ErrorHandler Objects \label{sax-error-handler}} + +Objects with this interface are used to receive error and warning +information from the \class{XMLReader}. If you create an object that +implements this interface, then register the object with your +\class{XMLReader}, the parser will call the methods in your object to +report all warnings and errors. There are three levels of errors +available: warnings, (possibly) recoverable errors, and unrecoverable +errors. All methods take a \exception{SAXParseException} as the only +parameter. Errors and warnings may be converted to an exception by +raising the passed-in exception object. + +\begin{methoddesc}[ErrorHandler]{error}{exception} + Called when the parser encounters a recoverable error. If this method + does not raise an exception, parsing may continue, but further document + information should not be expected by the application. Allowing the + parser to continue may allow additional errors to be discovered in the + input document. +\end{methoddesc} + +\begin{methoddesc}[ErrorHandler]{fatalError}{exception} + Called when the parser encounters an error it cannot recover from; + parsing is expected to terminate when this method returns. +\end{methoddesc} + +\begin{methoddesc}[ErrorHandler]{warning}{exception} + Called when the parser presents minor warning information to the + application. Parsing is expected to continue when this method returns, + and document information will continue to be passed to the application. + Raising an exception in this method will cause parsing to end. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/xmlsaxreader.tex b/sys/src/cmd/python/Doc/lib/xmlsaxreader.tex new file mode 100644 index 000000000..d66958170 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmlsaxreader.tex @@ -0,0 +1,351 @@ +\section{\module{xml.sax.xmlreader} --- + Interface for XML parsers} + +\declaremodule{standard}{xml.sax.xmlreader} +\modulesynopsis{Interface which SAX-compliant XML parsers must implement.} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} +\moduleauthor{Lars Marius Garshol}{larsga@garshol.priv.no} + +\versionadded{2.0} + + +SAX parsers implement the \class{XMLReader} interface. They are +implemented in a Python module, which must provide a function +\function{create_parser()}. This function is invoked by +\function{xml.sax.make_parser()} with no arguments to create a new +parser object. + +\begin{classdesc}{XMLReader}{} + Base class which can be inherited by SAX parsers. +\end{classdesc} + +\begin{classdesc}{IncrementalParser}{} + In some cases, it is desirable not to parse an input source at once, + but to feed chunks of the document as they get available. Note that + the reader will normally not read the entire file, but read it in + chunks as well; still \method{parse()} won't return until the entire + document is processed. So these interfaces should be used if the + blocking behaviour of \method{parse()} is not desirable. + + When the parser is instantiated it is ready to begin accepting data + from the feed method immediately. After parsing has been finished + with a call to close the reset method must be called to make the + parser ready to accept new data, either from feed or using the parse + method. + + Note that these methods must \emph{not} be called during parsing, + that is, after parse has been called and before it returns. + + By default, the class also implements the parse method of the + XMLReader interface using the feed, close and reset methods of the + IncrementalParser interface as a convenience to SAX 2.0 driver + writers. +\end{classdesc} + +\begin{classdesc}{Locator}{} + Interface for associating a SAX event with a document location. A + locator object will return valid results only during calls to + DocumentHandler methods; at any other time, the results are + unpredictable. If information is not available, methods may return + \code{None}. +\end{classdesc} + +\begin{classdesc}{InputSource}{\optional{systemId}} + Encapsulation of the information needed by the \class{XMLReader} to + read entities. + + This class may include information about the public identifier, + system identifier, byte stream (possibly with character encoding + information) and/or the character stream of an entity. + + Applications will create objects of this class for use in the + \method{XMLReader.parse()} method and for returning from + EntityResolver.resolveEntity. + + An \class{InputSource} belongs to the application, the + \class{XMLReader} is not allowed to modify \class{InputSource} objects + passed to it from the application, although it may make copies and + modify those. +\end{classdesc} + +\begin{classdesc}{AttributesImpl}{attrs} + This is an implementation of the \ulink{\class{Attributes} + interface}{attributes-objects.html} (see + section~\ref{attributes-objects}). This is a dictionary-like + object which represents the element attributes in a + \method{startElement()} call. In addition to the most useful + dictionary operations, it supports a number of other methods as + described by the interface. Objects of this class should be + instantiated by readers; \var{attrs} must be a dictionary-like + object containing a mapping from attribute names to attribute + values. +\end{classdesc} + +\begin{classdesc}{AttributesNSImpl}{attrs, qnames} + Namespace-aware variant of \class{AttributesImpl}, which will be + passed to \method{startElementNS()}. It is derived from + \class{AttributesImpl}, but understands attribute names as + two-tuples of \var{namespaceURI} and \var{localname}. In addition, + it provides a number of methods expecting qualified names as they + appear in the original document. This class implements the + \ulink{\class{AttributesNS} interface}{attributes-ns-objects.html} + (see section~\ref{attributes-ns-objects}). +\end{classdesc} + + +\subsection{XMLReader Objects \label{xmlreader-objects}} + +The \class{XMLReader} interface supports the following methods: + +\begin{methoddesc}[XMLReader]{parse}{source} + Process an input source, producing SAX events. The \var{source} + object can be a system identifier (a string identifying the + input source -- typically a file name or an URL), a file-like + object, or an \class{InputSource} object. When \method{parse()} + returns, the input is completely processed, and the parser object + can be discarded or reset. As a limitation, the current implementation + only accepts byte streams; processing of character streams is for + further study. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{getContentHandler}{} + Return the current \class{ContentHandler}. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{setContentHandler}{handler} + Set the current \class{ContentHandler}. If no + \class{ContentHandler} is set, content events will be discarded. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{getDTDHandler}{} + Return the current \class{DTDHandler}. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{setDTDHandler}{handler} + Set the current \class{DTDHandler}. If no \class{DTDHandler} is + set, DTD events will be discarded. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{getEntityResolver}{} + Return the current \class{EntityResolver}. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{setEntityResolver}{handler} + Set the current \class{EntityResolver}. If no + \class{EntityResolver} is set, attempts to resolve an external + entity will result in opening the system identifier for the entity, + and fail if it is not available. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{getErrorHandler}{} + Return the current \class{ErrorHandler}. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{setErrorHandler}{handler} + Set the current error handler. If no \class{ErrorHandler} is set, + errors will be raised as exceptions, and warnings will be printed. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{setLocale}{locale} + Allow an application to set the locale for errors and warnings. + + SAX parsers are not required to provide localization for errors and + warnings; if they cannot support the requested locale, however, they + must throw a SAX exception. Applications may request a locale change + in the middle of a parse. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{getFeature}{featurename} + Return the current setting for feature \var{featurename}. If the + feature is not recognized, \exception{SAXNotRecognizedException} is + raised. The well-known featurenames are listed in the module + \module{xml.sax.handler}. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{setFeature}{featurename, value} + Set the \var{featurename} to \var{value}. If the feature is not + recognized, \exception{SAXNotRecognizedException} is raised. If the + feature or its setting is not supported by the parser, + \var{SAXNotSupportedException} is raised. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{getProperty}{propertyname} + Return the current setting for property \var{propertyname}. If the + property is not recognized, a \exception{SAXNotRecognizedException} + is raised. The well-known propertynames are listed in the module + \module{xml.sax.handler}. +\end{methoddesc} + +\begin{methoddesc}[XMLReader]{setProperty}{propertyname, value} + Set the \var{propertyname} to \var{value}. If the property is not + recognized, \exception{SAXNotRecognizedException} is raised. If the + property or its setting is not supported by the parser, + \var{SAXNotSupportedException} is raised. +\end{methoddesc} + + +\subsection{IncrementalParser Objects + \label{incremental-parser-objects}} + +Instances of \class{IncrementalParser} offer the following additional +methods: + +\begin{methoddesc}[IncrementalParser]{feed}{data} + Process a chunk of \var{data}. +\end{methoddesc} + +\begin{methoddesc}[IncrementalParser]{close}{} + Assume the end of the document. That will check well-formedness + conditions that can be checked only at the end, invoke handlers, and + may clean up resources allocated during parsing. +\end{methoddesc} + +\begin{methoddesc}[IncrementalParser]{reset}{} + This method is called after close has been called to reset the + parser so that it is ready to parse new documents. The results of + calling parse or feed after close without calling reset are + undefined. +\end{methoddesc} + + +\subsection{Locator Objects \label{locator-objects}} + +Instances of \class{Locator} provide these methods: + +\begin{methoddesc}[Locator]{getColumnNumber}{} + Return the column number where the current event ends. +\end{methoddesc} + +\begin{methoddesc}[Locator]{getLineNumber}{} + Return the line number where the current event ends. +\end{methoddesc} + +\begin{methoddesc}[Locator]{getPublicId}{} + Return the public identifier for the current event. +\end{methoddesc} + +\begin{methoddesc}[Locator]{getSystemId}{} + Return the system identifier for the current event. +\end{methoddesc} + + +\subsection{InputSource Objects \label{input-source-objects}} + +\begin{methoddesc}[InputSource]{setPublicId}{id} + Sets the public identifier of this \class{InputSource}. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{getPublicId}{} + Returns the public identifier of this \class{InputSource}. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{setSystemId}{id} + Sets the system identifier of this \class{InputSource}. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{getSystemId}{} + Returns the system identifier of this \class{InputSource}. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{setEncoding}{encoding} + Sets the character encoding of this \class{InputSource}. + + The encoding must be a string acceptable for an XML encoding + declaration (see section 4.3.3 of the XML recommendation). + + The encoding attribute of the \class{InputSource} is ignored if the + \class{InputSource} also contains a character stream. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{getEncoding}{} + Get the character encoding of this InputSource. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{setByteStream}{bytefile} + Set the byte stream (a Python file-like object which does not + perform byte-to-character conversion) for this input source. + + The SAX parser will ignore this if there is also a character stream + specified, but it will use a byte stream in preference to opening a + URI connection itself. + + If the application knows the character encoding of the byte stream, + it should set it with the setEncoding method. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{getByteStream}{} + Get the byte stream for this input source. + + The getEncoding method will return the character encoding for this + byte stream, or None if unknown. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{setCharacterStream}{charfile} + Set the character stream for this input source. (The stream must be + a Python 1.6 Unicode-wrapped file-like that performs conversion to + Unicode strings.) + + If there is a character stream specified, the SAX parser will ignore + any byte stream and will not attempt to open a URI connection to the + system identifier. +\end{methoddesc} + +\begin{methoddesc}[InputSource]{getCharacterStream}{} + Get the character stream for this input source. +\end{methoddesc} + + +\subsection{The \class{Attributes} Interface \label{attributes-objects}} + +\class{Attributes} objects implement a portion of the mapping +protocol, including the methods \method{copy()}, \method{get()}, +\method{has_key()}, \method{items()}, \method{keys()}, and +\method{values()}. The following methods are also provided: + +\begin{methoddesc}[Attributes]{getLength}{} + Return the number of attributes. +\end{methoddesc} + +\begin{methoddesc}[Attributes]{getNames}{} + Return the names of the attributes. +\end{methoddesc} + +\begin{methoddesc}[Attributes]{getType}{name} + Returns the type of the attribute \var{name}, which is normally + \code{'CDATA'}. +\end{methoddesc} + +\begin{methoddesc}[Attributes]{getValue}{name} + Return the value of attribute \var{name}. +\end{methoddesc} + +% getValueByQName, getNameByQName, getQNameByName, getQNames available +% here already, but documented only for derived class. + + +\subsection{The \class{AttributesNS} Interface \label{attributes-ns-objects}} + +This interface is a subtype of the \ulink{\class{Attributes} +interface}{attributes-objects.html} (see +section~\ref{attributes-objects}). All methods supported by that +interface are also available on \class{AttributesNS} objects. + +The following methods are also available: + +\begin{methoddesc}[AttributesNS]{getValueByQName}{name} + Return the value for a qualified name. +\end{methoddesc} + +\begin{methoddesc}[AttributesNS]{getNameByQName}{name} + Return the \code{(\var{namespace}, \var{localname})} pair for a + qualified \var{name}. +\end{methoddesc} + +\begin{methoddesc}[AttributesNS]{getQNameByName}{name} + Return the qualified name for a \code{(\var{namespace}, + \var{localname})} pair. +\end{methoddesc} + +\begin{methoddesc}[AttributesNS]{getQNames}{} + Return the qualified names of all attributes. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/lib/xmlsaxutils.tex b/sys/src/cmd/python/Doc/lib/xmlsaxutils.tex new file mode 100644 index 000000000..64221f595 --- /dev/null +++ b/sys/src/cmd/python/Doc/lib/xmlsaxutils.tex @@ -0,0 +1,81 @@ +\section{\module{xml.sax.saxutils} --- + SAX Utilities} + +\declaremodule{standard}{xml.sax.saxutils} +\modulesynopsis{Convenience functions and classes for use with SAX.} +\sectionauthor{Martin v. L\"owis}{martin@v.loewis.de} +\moduleauthor{Lars Marius Garshol}{larsga@garshol.priv.no} + +\versionadded{2.0} + + +The module \module{xml.sax.saxutils} contains a number of classes and +functions that are commonly useful when creating SAX applications, +either in direct use, or as base classes. + +\begin{funcdesc}{escape}{data\optional{, entities}} + Escape \character{\&}, \character{<}, and \character{>} in a string + of data. + + You can escape other strings of data by passing a dictionary as the + optional \var{entities} parameter. The keys and values must all be + strings; each key will be replaced with its corresponding value. +\end{funcdesc} + +\begin{funcdesc}{unescape}{data\optional{, entities}} + Unescape \character{\&amp;}, \character{\&lt;}, and \character{\&gt;} + in a string of data. + + You can unescape other strings of data by passing a dictionary as the + optional \var{entities} parameter. The keys and values must all be + strings; each key will be replaced with its corresponding value. + + \versionadded{2.3} +\end{funcdesc} + +\begin{funcdesc}{quoteattr}{data\optional{, entities}} + Similar to \function{escape()}, but also prepares \var{data} to be + used as an attribute value. The return value is a quoted version of + \var{data} with any additional required replacements. + \function{quoteattr()} will select a quote character based on the + content of \var{data}, attempting to avoid encoding any quote + characters in the string. If both single- and double-quote + characters are already in \var{data}, the double-quote characters + will be encoded and \var{data} will be wrapped in double-quotes. The + resulting string can be used directly as an attribute value: + +\begin{verbatim} +>>> print "<element attr=%s>" % quoteattr("ab ' cd \" ef") +<element attr="ab ' cd &quot; ef"> +\end{verbatim} + + This function is useful when generating attribute values for HTML or + any SGML using the reference concrete syntax. + \versionadded{2.2} +\end{funcdesc} + +\begin{classdesc}{XMLGenerator}{\optional{out\optional{, encoding}}} + This class implements the \class{ContentHandler} interface by + writing SAX events back into an XML document. In other words, using + an \class{XMLGenerator} as the content handler will reproduce the + original document being parsed. \var{out} should be a file-like + object which will default to \var{sys.stdout}. \var{encoding} is the + encoding of the output stream which defaults to \code{'iso-8859-1'}. +\end{classdesc} + +\begin{classdesc}{XMLFilterBase}{base} + This class is designed to sit between an \class{XMLReader} and the + client application's event handlers. By default, it does nothing + but pass requests up to the reader and events on to the handlers + unmodified, but subclasses can override specific methods to modify + the event stream or the configuration requests as they pass through. +\end{classdesc} + +\begin{funcdesc}{prepare_input_source}{source\optional{, base}} + This function takes an input source and an optional base URL and + returns a fully resolved \class{InputSource} object ready for + reading. The input source can be given as a string, a file-like + object, or an \class{InputSource} object; parsers will use this + function to implement the polymorphic \var{source} argument to their + \method{parse()} method. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/mac/libaepack.tex b/sys/src/cmd/python/Doc/mac/libaepack.tex new file mode 100644 index 000000000..26a672e80 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libaepack.tex @@ -0,0 +1,82 @@ +\section{\module{aepack} --- + Conversion between Python variables and AppleEvent data containers} + +\declaremodule{standard}{aepack} + \platform{Mac} +%\moduleauthor{Jack Jansen?}{email} +\modulesynopsis{Conversion between Python variables and AppleEvent + data containers.} +\sectionauthor{Vincent Marchetti}{vincem@en.com} + + +The \module{aepack} module defines functions for converting (packing) +Python variables to AppleEvent descriptors and back (unpacking). +Within Python the AppleEvent descriptor is handled by Python objects +of built-in type \class{AEDesc}, defined in module \refmodule{Carbon.AE}. + +The \module{aepack} module defines the following functions: + + +\begin{funcdesc}{pack}{x\optional{, forcetype}} +Returns an \class{AEDesc} object containing a conversion of Python +value x. If \var{forcetype} is provided it specifies the descriptor +type of the result. Otherwise, a default mapping of Python types to +Apple Event descriptor types is used, as follows: + +\begin{tableii}{l|l}{textrm}{Python type}{descriptor type} + \lineii{\class{FSSpec}}{typeFSS} + \lineii{\class{FSRef}}{typeFSRef} + \lineii{\class{Alias}}{typeAlias} + \lineii{integer}{typeLong (32 bit integer)} + \lineii{float}{typeFloat (64 bit floating point)} + \lineii{string}{typeText} + \lineii{unicode}{typeUnicodeText} + \lineii{list}{typeAEList} + \lineii{dictionary}{typeAERecord} + \lineii{instance}{\emph{see below}} +\end{tableii} + +If \var{x} is a Python instance then this function attempts to call an +\method{__aepack__()} method. This method should return an +\class{AEDesc} object. + +If the conversion \var{x} is not defined above, this function returns +the Python string representation of a value (the repr() function) +encoded as a text descriptor. +\end{funcdesc} + +\begin{funcdesc}{unpack}{x\optional{, formodulename}} + \var{x} must be an object of type \class{AEDesc}. This function + returns a Python object representation of the data in the Apple + Event descriptor \var{x}. Simple AppleEvent data types (integer, + text, float) are returned as their obvious Python counterparts. + Apple Event lists are returned as Python lists, and the list + elements are recursively unpacked. Object references + (ex. \code{line 3 of document 1}) are returned as instances of + \class{aetypes.ObjectSpecifier}, unless \code{formodulename} + is specified. AppleEvent descriptors with + descriptor type typeFSS are returned as \class{FSSpec} + objects. AppleEvent record descriptors are returned as Python + dictionaries, with 4-character string keys and elements recursively + unpacked. + + The optional \code{formodulename} argument is used by the stub packages + generated by \module{gensuitemodule}, and ensures that the OSA classes + for object specifiers are looked up in the correct module. This ensures + that if, say, the Finder returns an object specifier for a window + you get an instance of \code{Finder.Window} and not a generic + \code{aetypes.Window}. The former knows about all the properties + and elements a window has in the Finder, while the latter knows + no such things. +\end{funcdesc} + + +\begin{seealso} + \seemodule{Carbon.AE}{Built-in access to Apple Event Manager routines.} + \seemodule{aetypes}{Python definitions of codes for Apple Event + descriptor types.} + \seetitle[http://developer.apple.com/techpubs/mac/IAC/IAC-2.html]{ + Inside Macintosh: Interapplication + Communication}{Information about inter-process + communications on the Macintosh.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/mac/libaetools.tex b/sys/src/cmd/python/Doc/mac/libaetools.tex new file mode 100644 index 000000000..463755bf8 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libaetools.tex @@ -0,0 +1,83 @@ +\section{\module{aetools} --- + OSA client support} + +\declaremodule{standard}{aetools} + \platform{Mac} +%\moduleauthor{Jack Jansen?}{email} +\modulesynopsis{Basic support for sending Apple Events} +\sectionauthor{Jack Jansen}{Jack.Jansen@cwi.nl} + + +The \module{aetools} module contains the basic functionality +on which Python AppleScript client support is built. It also +imports and re-exports the core functionality of the +\module{aetypes} and \module{aepack} modules. The stub packages +generated by \module{gensuitemodule} import the relevant +portions of \module{aetools}, so usually you do not need to +import it yourself. The exception to this is when you +cannot use a generated suite package and need lower-level +access to scripting. + +The \module{aetools} module itself uses the AppleEvent support +provided by the \module{Carbon.AE} module. This has one drawback: +you need access to the window manager, see section \ref{osx-gui-scripts} +for details. This restriction may be lifted in future releases. + + +The \module{aetools} module defines the following functions: + +\begin{funcdesc}{packevent}{ae, parameters, attributes} +Stores parameters and attributes in a pre-created \code{Carbon.AE.AEDesc} +object. \code{parameters} and \code{attributes} are +dictionaries mapping 4-character OSA parameter keys to Python objects. The +objects are packed using \code{aepack.pack()}. +\end{funcdesc} + +\begin{funcdesc}{unpackevent}{ae\optional{, formodulename}} +Recursively unpacks a \code{Carbon.AE.AEDesc} event to Python objects. +The function returns the parameter dictionary and the attribute dictionary. +The \code{formodulename} argument is used by generated stub packages to +control where AppleScript classes are looked up. +\end{funcdesc} + +\begin{funcdesc}{keysubst}{arguments, keydict} +Converts a Python keyword argument dictionary \code{arguments} to +the format required by \code{packevent} by replacing the keys, +which are Python identifiers, by the four-character OSA keys according +to the mapping specified in \code{keydict}. Used by the generated suite +packages. +\end{funcdesc} + +\begin{funcdesc}{enumsubst}{arguments, key, edict} +If the \code{arguments} dictionary contains an entry for \code{key} +convert the value for that entry according to dictionary \code{edict}. +This converts human-readable Python enumeration names to the OSA 4-character +codes. +Used by the generated suite +packages. +\end{funcdesc} + +The \module{aetools} module defines the following class: + +\begin{classdesc}{TalkTo}{\optional{signature=None, start=0, timeout=0}} + +Base class for the proxy used to talk to an application. \code{signature} +overrides the class attribute \code{_signature} (which is usually set by subclasses) +and is the 4-char creator code defining the application to talk to. +\code{start} can be set to true to enable running the application on +class instantiation. \code{timeout} can be specified to change the +default timeout used while waiting for an AppleEvent reply. +\end{classdesc} + +\begin{methoddesc}{_start}{} +Test whether the application is running, and attempt to start it if not. +\end{methoddesc} + +\begin{methoddesc}{send}{code, subcode\optional{, parameters, attributes}} +Create the AppleEvent \code{Carbon.AE.AEDesc} for the verb with +the OSA designation \code{code, subcode} (which are the usual 4-character +strings), pack the \code{parameters} and \code{attributes} into it, send it +to the target application, wait for the reply, unpack the reply with +\code{unpackevent} and return the reply appleevent, the unpacked return values +as a dictionary and the return attributes. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/mac/libaetypes.tex b/sys/src/cmd/python/Doc/mac/libaetypes.tex new file mode 100644 index 000000000..f7d8f8b19 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libaetypes.tex @@ -0,0 +1,135 @@ +\section{\module{aetypes} --- + AppleEvent objects} + +\declaremodule{standard}{aetypes} + \platform{Mac} +%\moduleauthor{Jack Jansen?}{email} +\modulesynopsis{Python representation of the Apple Event Object Model.} +\sectionauthor{Vincent Marchetti}{vincem@en.com} + + +The \module{aetypes} defines classes used to represent Apple Event data +descriptors and Apple Event object specifiers. + +Apple Event data is contained in descriptors, and these descriptors +are typed. For many descriptors the Python representation is simply the +corresponding Python type: \code{typeText} in OSA is a Python string, +\code{typeFloat} is a float, etc. For OSA types that have no direct +Python counterpart this module declares classes. Packing and unpacking +instances of these classes is handled automatically by \module{aepack}. + +An object specifier is essentially an address of an object implemented +in a Apple Event server. An Apple Event specifier is used as the direct +object for an Apple Event or as the argument of an optional parameter. +The \module{aetypes} module contains the base classes for OSA classes +and properties, which are used by the packages generated by +\module{gensuitemodule} to populate the classes and properties in a +given suite. + +For reasons of backward compatibility, and for cases where you need to +script an application for which you have not generated the stub package +this module also contains object specifiers for a number of common OSA +classes such as \code{Document}, \code{Window}, \code{Character}, etc. + + + +The \module{AEObjects} module defines the following classes to represent +Apple Event descriptor data: + +\begin{classdesc}{Unknown}{type, data} +The representation of OSA descriptor data for which the \module{aepack} +and \module{aetypes} modules have no support, i.e. anything that is not +represented by the other classes here and that is not equivalent to a +simple Python value. +\end{classdesc} + +\begin{classdesc}{Enum}{enum} +An enumeration value with the given 4-character string value. +\end{classdesc} + +\begin{classdesc}{InsertionLoc}{of, pos} +Position \code{pos} in object \code{of}. +\end{classdesc} + +\begin{classdesc}{Boolean}{bool} +A boolean. +\end{classdesc} + +\begin{classdesc}{StyledText}{style, text} +Text with style information (font, face, etc) included. +\end{classdesc} + +\begin{classdesc}{AEText}{script, style, text} +Text with script system and style information included. +\end{classdesc} + +\begin{classdesc}{IntlText}{script, language, text} +Text with script system and language information included. +\end{classdesc} + +\begin{classdesc}{IntlWritingCode}{script, language} +Script system and language information. +\end{classdesc} + +\begin{classdesc}{QDPoint}{v, h} +A quickdraw point. +\end{classdesc} + +\begin{classdesc}{QDRectangle}{v0, h0, v1, h1} +A quickdraw rectangle. +\end{classdesc} + +\begin{classdesc}{RGBColor}{r, g, b} +A color. +\end{classdesc} + +\begin{classdesc}{Type}{type} +An OSA type value with the given 4-character name. +\end{classdesc} + +\begin{classdesc}{Keyword}{name} +An OSA keyword with the given 4-character name. +\end{classdesc} + +\begin{classdesc}{Range}{start, stop} +A range. +\end{classdesc} + +\begin{classdesc}{Ordinal}{abso} +Non-numeric absolute positions, such as \code{"firs"}, first, or \code{"midd"}, +middle. +\end{classdesc} + +\begin{classdesc}{Logical}{logc, term} +The logical expression of applying operator \code{logc} to +\code{term}. +\end{classdesc} + +\begin{classdesc}{Comparison}{obj1, relo, obj2} +The comparison \code{relo} of \code{obj1} to \code{obj2}. +\end{classdesc} + +The following classes are used as base classes by the generated stub +packages to represent AppleScript classes and properties in Python: + +\begin{classdesc}{ComponentItem}{which\optional{, fr}} +Abstract baseclass for an OSA class. The subclass should set the class +attribute \code{want} to the 4-character OSA class code. Instances of +subclasses of this class are equivalent to AppleScript Object +Specifiers. Upon instantiation you should pass a selector in +\code{which}, and optionally a parent object in \code{fr}. +\end{classdesc} + +\begin{classdesc}{NProperty}{fr} +Abstract baseclass for an OSA property. The subclass should set the class +attributes \code{want} and \code{which} to designate which property we +are talking about. Instances of subclasses of this class are Object +Specifiers. +\end{classdesc} + +\begin{classdesc}{ObjectSpecifier}{want, form, seld\optional{, fr}} +Base class of \code{ComponentItem} and \code{NProperty}, a general +OSA Object Specifier. See the Apple Open Scripting Architecture +documentation for the parameters. Note that this class is not abstract. +\end{classdesc} + diff --git a/sys/src/cmd/python/Doc/mac/libautogil.tex b/sys/src/cmd/python/Doc/mac/libautogil.tex new file mode 100644 index 000000000..002e87228 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libautogil.tex @@ -0,0 +1,26 @@ +\section{\module{autoGIL} --- + Global Interpreter Lock handling in event loops} + +\declaremodule{extension}{autoGIL} + \platform{Mac} +\modulesynopsis{Global Interpreter Lock handling in event loops.} +\moduleauthor{Just van Rossum}{just@letterror.com} + + +The \module{autoGIL} module provides a function \function{installAutoGIL} that +automatically locks and unlocks Python's Global Interpreter Lock +when running an event loop. + +\begin{excdesc}{AutoGILError} +Raised if the observer callback cannot be installed, for example because +the current thread does not have a run loop. +\end{excdesc} + +\begin{funcdesc}{installAutoGIL}{} + Install an observer callback in the event loop (CFRunLoop) for the + current thread, that will lock and unlock the Global Interpreter Lock + (GIL) at appropriate times, allowing other Python threads to run while + the event loop is idle. + + Availability: OSX 10.1 or later. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/mac/libcolorpicker.tex b/sys/src/cmd/python/Doc/mac/libcolorpicker.tex new file mode 100644 index 000000000..596e9c2e2 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libcolorpicker.tex @@ -0,0 +1,23 @@ +\section{\module{ColorPicker} --- + Color selection dialog} + +\declaremodule{extension}{ColorPicker} + \platform{Mac} +\modulesynopsis{Interface to the standard color selection dialog.} +\moduleauthor{Just van Rossum}{just@letterror.com} +\sectionauthor{Fred L. Drake, Jr.}{fdrake@acm.org} + + +The \module{ColorPicker} module provides access to the standard color +picker dialog. + + +\begin{funcdesc}{GetColor}{prompt, rgb} + Show a standard color selection dialog and allow the user to select + a color. The user is given instruction by the \var{prompt} string, + and the default color is set to \var{rgb}. \var{rgb} must be a + tuple giving the red, green, and blue components of the color. + \function{GetColor()} returns a tuple giving the user's selected + color and a flag indicating whether they accepted the selection of + cancelled. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/mac/libframework.tex b/sys/src/cmd/python/Doc/mac/libframework.tex new file mode 100644 index 000000000..692c31fe4 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libframework.tex @@ -0,0 +1,314 @@ +\section{\module{FrameWork} --- + Interactive application framework} + +\declaremodule{standard}{FrameWork} + \platform{Mac} +\modulesynopsis{Interactive application framework.} + + +The \module{FrameWork} module contains classes that together provide a +framework for an interactive Macintosh application. The programmer +builds an application by creating subclasses that override various +methods of the bases classes, thereby implementing the functionality +wanted. Overriding functionality can often be done on various +different levels, i.e. to handle clicks in a single dialog window in a +non-standard way it is not necessary to override the complete event +handling. + +Work on the \module{FrameWork} has pretty much stopped, now that +\module{PyObjC} is available for full Cocoa access from Python, and the +documentation describes only the most important functionality, and not +in the most logical manner at that. Examine the source or the examples +for more details. The following are some comments posted on the +MacPython newsgroup about the strengths and limitations of +\module{FrameWork}: + +\begin{quotation} +The strong point of \module{FrameWork} is that it allows you to break +into the control-flow at many different places. \refmodule{W}, for +instance, uses a different way to enable/disable menus and that plugs +right in leaving the rest intact. The weak points of +\module{FrameWork} are that it has no abstract command interface (but +that shouldn't be difficult), that its dialog support is minimal and +that its control/toolbar support is non-existent. +\end{quotation} + + +The \module{FrameWork} module defines the following functions: + + +\begin{funcdesc}{Application}{} +An object representing the complete application. See below for a +description of the methods. The default \method{__init__()} routine +creates an empty window dictionary and a menu bar with an apple menu. +\end{funcdesc} + +\begin{funcdesc}{MenuBar}{} +An object representing the menubar. This object is usually not created +by the user. +\end{funcdesc} + +\begin{funcdesc}{Menu}{bar, title\optional{, after}} +An object representing a menu. Upon creation you pass the +\code{MenuBar} the menu appears in, the \var{title} string and a +position (1-based) \var{after} where the menu should appear (default: +at the end). +\end{funcdesc} + +\begin{funcdesc}{MenuItem}{menu, title\optional{, shortcut, callback}} +Create a menu item object. The arguments are the menu to create, the +item title string and optionally the keyboard shortcut +and a callback routine. The callback is called with the arguments +menu-id, item number within menu (1-based), current front window and +the event record. + +Instead of a callable object the callback can also be a string. In +this case menu selection causes the lookup of a method in the topmost +window and the application. The method name is the callback string +with \code{'domenu_'} prepended. + +Calling the \code{MenuBar} \method{fixmenudimstate()} method sets the +correct dimming for all menu items based on the current front window. +\end{funcdesc} + +\begin{funcdesc}{Separator}{menu} +Add a separator to the end of a menu. +\end{funcdesc} + +\begin{funcdesc}{SubMenu}{menu, label} +Create a submenu named \var{label} under menu \var{menu}. The menu +object is returned. +\end{funcdesc} + +\begin{funcdesc}{Window}{parent} +Creates a (modeless) window. \var{Parent} is the application object to +which the window belongs. The window is not displayed until later. +\end{funcdesc} + +\begin{funcdesc}{DialogWindow}{parent} +Creates a modeless dialog window. +\end{funcdesc} + +\begin{funcdesc}{windowbounds}{width, height} +Return a \code{(\var{left}, \var{top}, \var{right}, \var{bottom})} +tuple suitable for creation of a window of given width and height. The +window will be staggered with respect to previous windows, and an +attempt is made to keep the whole window on-screen. However, the window will +however always be the exact size given, so parts may be offscreen. +\end{funcdesc} + +\begin{funcdesc}{setwatchcursor}{} +Set the mouse cursor to a watch. +\end{funcdesc} + +\begin{funcdesc}{setarrowcursor}{} +Set the mouse cursor to an arrow. +\end{funcdesc} + + +\subsection{Application Objects \label{application-objects}} + +Application objects have the following methods, among others: + + +\begin{methoddesc}[Application]{makeusermenus}{} +Override this method if you need menus in your application. Append the +menus to the attribute \member{menubar}. +\end{methoddesc} + +\begin{methoddesc}[Application]{getabouttext}{} +Override this method to return a text string describing your +application. Alternatively, override the \method{do_about()} method +for more elaborate ``about'' messages. +\end{methoddesc} + +\begin{methoddesc}[Application]{mainloop}{\optional{mask\optional{, wait}}} +This routine is the main event loop, call it to set your application +rolling. \var{Mask} is the mask of events you want to handle, +\var{wait} is the number of ticks you want to leave to other +concurrent application (default 0, which is probably not a good +idea). While raising \var{self} to exit the mainloop is still +supported it is not recommended: call \code{self._quit()} instead. + +The event loop is split into many small parts, each of which can be +overridden. The default methods take care of dispatching events to +windows and dialogs, handling drags and resizes, Apple Events, events +for non-FrameWork windows, etc. + +In general, all event handlers should return \code{1} if the event is fully +handled and \code{0} otherwise (because the front window was not a FrameWork +window, for instance). This is needed so that update events and such +can be passed on to other windows like the Sioux console window. +Calling \function{MacOS.HandleEvent()} is not allowed within +\var{our_dispatch} or its callees, since this may result in an +infinite loop if the code is called through the Python inner-loop +event handler. +\end{methoddesc} + +\begin{methoddesc}[Application]{asyncevents}{onoff} +Call this method with a nonzero parameter to enable +asynchronous event handling. This will tell the inner interpreter loop +to call the application event handler \var{async_dispatch} whenever events +are available. This will cause FrameWork window updates and the user +interface to remain working during long computations, but will slow the +interpreter down and may cause surprising results in non-reentrant code +(such as FrameWork itself). By default \var{async_dispatch} will immediately +call \var{our_dispatch} but you may override this to handle only certain +events asynchronously. Events you do not handle will be passed to Sioux +and such. + +The old on/off value is returned. +\end{methoddesc} + +\begin{methoddesc}[Application]{_quit}{} +Terminate the running \method{mainloop()} call at the next convenient +moment. +\end{methoddesc} + +\begin{methoddesc}[Application]{do_char}{c, event} +The user typed character \var{c}. The complete details of the event +can be found in the \var{event} structure. This method can also be +provided in a \code{Window} object, which overrides the +application-wide handler if the window is frontmost. +\end{methoddesc} + +\begin{methoddesc}[Application]{do_dialogevent}{event} +Called early in the event loop to handle modeless dialog events. The +default method simply dispatches the event to the relevant dialog (not +through the \code{DialogWindow} object involved). Override if you +need special handling of dialog events (keyboard shortcuts, etc). +\end{methoddesc} + +\begin{methoddesc}[Application]{idle}{event} +Called by the main event loop when no events are available. The +null-event is passed (so you can look at mouse position, etc). +\end{methoddesc} + + +\subsection{Window Objects \label{window-objects}} + +Window objects have the following methods, among others: + +\setindexsubitem{(Window method)} + +\begin{methoddesc}[Window]{open}{} +Override this method to open a window. Store the MacOS window-id in +\member{self.wid} and call the \method{do_postopen()} method to +register the window with the parent application. +\end{methoddesc} + +\begin{methoddesc}[Window]{close}{} +Override this method to do any special processing on window +close. Call the \method{do_postclose()} method to cleanup the parent +state. +\end{methoddesc} + +\begin{methoddesc}[Window]{do_postresize}{width, height, macoswindowid} +Called after the window is resized. Override if more needs to be done +than calling \code{InvalRect}. +\end{methoddesc} + +\begin{methoddesc}[Window]{do_contentclick}{local, modifiers, event} +The user clicked in the content part of a window. The arguments are +the coordinates (window-relative), the key modifiers and the raw +event. +\end{methoddesc} + +\begin{methoddesc}[Window]{do_update}{macoswindowid, event} +An update event for the window was received. Redraw the window. +\end{methoddesc} + +\begin{methoddesc}{do_activate}{activate, event} +The window was activated (\code{\var{activate} == 1}) or deactivated +(\code{\var{activate} == 0}). Handle things like focus highlighting, +etc. +\end{methoddesc} + + +\subsection{ControlsWindow Object \label{controlswindow-object}} + +ControlsWindow objects have the following methods besides those of +\code{Window} objects: + + +\begin{methoddesc}[ControlsWindow]{do_controlhit}{window, control, + pcode, event} +Part \var{pcode} of control \var{control} was hit by the +user. Tracking and such has already been taken care of. +\end{methoddesc} + + +\subsection{ScrolledWindow Object \label{scrolledwindow-object}} + +ScrolledWindow objects are ControlsWindow objects with the following +extra methods: + + +\begin{methoddesc}[ScrolledWindow]{scrollbars}{\optional{wantx\optional{, + wanty}}} +Create (or destroy) horizontal and vertical scrollbars. The arguments +specify which you want (default: both). The scrollbars always have +minimum \code{0} and maximum \code{32767}. +\end{methoddesc} + +\begin{methoddesc}[ScrolledWindow]{getscrollbarvalues}{} +You must supply this method. It should return a tuple \code{(\var{x}, +\var{y})} giving the current position of the scrollbars (between +\code{0} and \code{32767}). You can return \code{None} for either to +indicate the whole document is visible in that direction. +\end{methoddesc} + +\begin{methoddesc}[ScrolledWindow]{updatescrollbars}{} +Call this method when the document has changed. It will call +\method{getscrollbarvalues()} and update the scrollbars. +\end{methoddesc} + +\begin{methoddesc}[ScrolledWindow]{scrollbar_callback}{which, what, value} +Supplied by you and called after user interaction. \var{which} will +be \code{'x'} or \code{'y'}, \var{what} will be \code{'-'}, +\code{'--'}, \code{'set'}, \code{'++'} or \code{'+'}. For +\code{'set'}, \var{value} will contain the new scrollbar position. +\end{methoddesc} + +\begin{methoddesc}[ScrolledWindow]{scalebarvalues}{absmin, absmax, + curmin, curmax} +Auxiliary method to help you calculate values to return from +\method{getscrollbarvalues()}. You pass document minimum and maximum value +and topmost (leftmost) and bottommost (rightmost) visible values and +it returns the correct number or \code{None}. +\end{methoddesc} + +\begin{methoddesc}[ScrolledWindow]{do_activate}{onoff, event} +Takes care of dimming/highlighting scrollbars when a window becomes +frontmost. If you override this method, call this one at the end of +your method. +\end{methoddesc} + +\begin{methoddesc}[ScrolledWindow]{do_postresize}{width, height, window} +Moves scrollbars to the correct position. Call this method initially +if you override it. +\end{methoddesc} + +\begin{methoddesc}[ScrolledWindow]{do_controlhit}{window, control, + pcode, event} +Handles scrollbar interaction. If you override it call this method +first, a nonzero return value indicates the hit was in the scrollbars +and has been handled. +\end{methoddesc} + + +\subsection{DialogWindow Objects \label{dialogwindow-objects}} + +DialogWindow objects have the following methods besides those of +\code{Window} objects: + + +\begin{methoddesc}[DialogWindow]{open}{resid} +Create the dialog window, from the DLOG resource with id +\var{resid}. The dialog object is stored in \member{self.wid}. +\end{methoddesc} + +\begin{methoddesc}[DialogWindow]{do_itemhit}{item, event} +Item number \var{item} was hit. You are responsible for redrawing +toggle buttons, etc. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/mac/libgensuitemodule.tex b/sys/src/cmd/python/Doc/mac/libgensuitemodule.tex new file mode 100644 index 000000000..57ab587dd --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libgensuitemodule.tex @@ -0,0 +1,64 @@ +\section{\module{gensuitemodule} --- + Generate OSA stub packages} + +\declaremodule{standard}{gensuitemodule} + \platform{Mac} +%\moduleauthor{Jack Jansen?}{email} +\modulesynopsis{Create a stub package from an OSA dictionary} +\sectionauthor{Jack Jansen}{Jack.Jansen@cwi.nl} + +The \module{gensuitemodule} module creates a Python package implementing +stub code for the AppleScript suites that are implemented by a specific +application, according to its AppleScript dictionary. + +It is usually invoked by the user through the \program{PythonIDE}, but +it can also be run as a script from the command line (pass +\longprogramopt{help} for help on the options) or imported from Python +code. For an example of its use see \file{Mac/scripts/genallsuites.py} +in a source distribution, which generates the stub packages that are +included in the standard library. + +It defines the following public functions: + +\begin{funcdesc}{is_scriptable}{application} +Returns true if \code{application}, which should be passed as a pathname, +appears to be scriptable. Take the return value with a grain of salt: +\program{Internet Explorer} appears not to be scriptable but definitely is. +\end{funcdesc} + +\begin{funcdesc}{processfile}{application\optional{, output, basepkgname, + edit_modnames, creatorsignature, dump, verbose}} +Create a stub package for \code{application}, which should be passed as +a full pathname. For a \file{.app} bundle this is the pathname to the +bundle, not to the executable inside the bundle; for an unbundled CFM +application you pass the filename of the application binary. + +This function asks the application for its OSA terminology resources, +decodes these resources and uses the resultant data to create the Python +code for the package implementing the client stubs. + +\code{output} is the pathname where the resulting package is stored, if +not specified a standard "save file as" dialog is presented to +the user. \code{basepkgname} is the base package on which this package +will build, and defaults to \module{StdSuites}. Only when generating +\module{StdSuites} itself do you need to specify this. +\code{edit_modnames} is a dictionary that can be used to change +modulenames that are too ugly after name mangling. +\code{creator_signature} can be used to override the 4-char creator +code, which is normally obtained from the \file{PkgInfo} file in the +package or from the CFM file creator signature. When \code{dump} is +given it should refer to a file object, and \code{processfile} will stop +after decoding the resources and dump the Python representation of the +terminology resources to this file. \code{verbose} should also be a file +object, and specifying it will cause \code{processfile} to tell you what +it is doing. +\end{funcdesc} + +\begin{funcdesc}{processfile_fromresource}{application\optional{, output, + basepkgname, edit_modnames, creatorsignature, dump, verbose}} +This function does the same as \code{processfile}, except that it uses a +different method to get the terminology resources. It opens \code{application} +as a resource file and reads all \code{"aete"} and \code{"aeut"} resources +from this file. +\end{funcdesc} + diff --git a/sys/src/cmd/python/Doc/mac/libmac.tex b/sys/src/cmd/python/Doc/mac/libmac.tex new file mode 100644 index 000000000..9dece8d12 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libmac.tex @@ -0,0 +1,29 @@ + +\section{\module{macpath} --- + MacOS path manipulation functions} + +\declaremodule{standard}{macpath} +% Could be labeled \platform{Mac}, but the module should work anywhere and +% is distributed with the standard library. +\modulesynopsis{MacOS path manipulation functions.} + + +This module is the Mac OS 9 (and earlier) implementation of the \module{os.path} +module. It can be used to manipulate old-style Macintosh pathnames on Mac OS +X (or any other platform). +Refer to the +\citetitle[../lib/lib.html]{Python Library Reference} for +documentation of \module{os.path}. + +The following functions are available in this module: +\function{normcase()}, +\function{normpath()}, +\function{isabs()}, +\function{join()}, +\function{split()}, +\function{isdir()}, +\function{isfile()}, +\function{walk()}, +\function{exists()}. +For other functions available in \module{os.path} dummy counterparts +are available. diff --git a/sys/src/cmd/python/Doc/mac/libmacfs.tex b/sys/src/cmd/python/Doc/mac/libmacfs.tex new file mode 100644 index 000000000..12a7cc34b --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libmacfs.tex @@ -0,0 +1,241 @@ +\section{\module{macfs} --- + Various file system services} + +\declaremodule{standard}{macfs} + \platform{Mac} +\modulesynopsis{Support for FSSpec, the Alias Manager, + \program{finder} aliases, and the Standard File package.} + +\deprecated{2.3}{The macfs module should be considered obsolete. For +\class{FSSpec}, \class{FSRef} and \class{Alias} handling use the +\module{Carbon.File} or \refmodule{Carbon.Folder} module. For file +dialogs use the \refmodule{EasyDialogs} module. Also, this module is +known to not work correctly with UFS partitions.} + +This module provides access to Macintosh \class{FSSpec} handling, the +Alias Manager, \program{finder} aliases and the Standard File package. +\index{Macintosh Alias Manager} +\index{Alias Manager, Macintosh} +\index{Standard File} + +Whenever a function or method expects a \var{file} argument, this +argument can be one of three things:\ (1) a full or partial Macintosh +pathname, (2) an \class{FSSpec} object or (3) a 3-tuple +\code{(\var{wdRefNum}, \var{parID}, \var{name})} as described in +\citetitle{Inside Macintosh:\ Files}. An \class{FSSpec} can point to +a non-existing file, as long as the folder containing the file exists. +Under MacPython the same is true for a pathname, but not under \UNIX-Python +because of the way pathnames and FSRefs works. See Apple's documentation +for details. + +A description of aliases and the +Standard File package can also be found there. + +\begin{funcdesc}{FSSpec}{file} +Create an \class{FSSpec} object for the specified file. +\end{funcdesc} + +\begin{funcdesc}{RawFSSpec}{data} +Create an \class{FSSpec} object given the raw data for the \C{} +structure for the \class{FSSpec} as a string. This is mainly useful +if you have obtained an \class{FSSpec} structure over a network. +\end{funcdesc} + +\begin{funcdesc}{RawAlias}{data} +Create an \class{Alias} object given the raw data for the \C{} +structure for the alias as a string. This is mainly useful if you +have obtained an \class{FSSpec} structure over a network. +\end{funcdesc} + +\begin{funcdesc}{FInfo}{} +Create a zero-filled \class{FInfo} object. +\end{funcdesc} + +\begin{funcdesc}{ResolveAliasFile}{file} +Resolve an alias file. Returns a 3-tuple \code{(\var{fsspec}, +\var{isfolder}, \var{aliased})} where \var{fsspec} is the resulting +\class{FSSpec} object, \var{isfolder} is true if \var{fsspec} points +to a folder and \var{aliased} is true if the file was an alias in the +first place (otherwise the \class{FSSpec} object for the file itself +is returned). +\end{funcdesc} + +\begin{funcdesc}{StandardGetFile}{\optional{type, \moreargs}} +Present the user with a standard ``open input file'' +dialog. Optionally, you can pass up to four 4-character file types to limit +the files the user can choose from. The function returns an \class{FSSpec} +object and a flag indicating that the user completed the dialog +without cancelling. +\end{funcdesc} + +\begin{funcdesc}{PromptGetFile}{prompt\optional{, type, \moreargs}} +Similar to \function{StandardGetFile()} but allows you to specify a +prompt which will be displayed at the top of the dialog. +\end{funcdesc} + +\begin{funcdesc}{StandardPutFile}{prompt\optional{, default}} +Present the user with a standard ``open output file'' +dialog. \var{prompt} is the prompt string, and the optional +\var{default} argument initializes the output file name. The function +returns an \class{FSSpec} object and a flag indicating that the user +completed the dialog without cancelling. +\end{funcdesc} + +\begin{funcdesc}{GetDirectory}{\optional{prompt}} +Present the user with a non-standard ``select a directory'' dialog. You +have to first open the directory before clicking on the ``select current +directory'' button. \var{prompt} is the prompt string which will be +displayed at the top of the dialog. Return an \class{FSSpec} object and +a success-indicator. +\end{funcdesc} + +\begin{funcdesc}{SetFolder}{\optional{fsspec}} +Set the folder that is initially presented to the user when one of +the file selection dialogs is presented. \var{fsspec} should point to +a file in the folder, not the folder itself (the file need not exist, +though). If no argument is passed the folder will be set to the +current directory, i.e. what \function{os.getcwd()} returns. + +Note that starting with System 7.5 the user can change Standard File +behaviour with the ``general controls'' control panel, thereby making +this call inoperative. +\end{funcdesc} + +\begin{funcdesc}{FindFolder}{where, which, create} +Locates one of the ``special'' folders that Mac OS knows about, such as +the trash or the Preferences folder. \var{where} is the disk to +search, \var{which} is the 4-character string specifying which folder to +locate. Setting \var{create} causes the folder to be created if it +does not exist. Returns a \code{(\var{vrefnum}, \var{dirid})} tuple. + +The constants for \var{where} and \var{which} can be obtained from the +standard module \var{Carbon.Folders}. +\end{funcdesc} + +\begin{funcdesc}{NewAliasMinimalFromFullPath}{pathname} +Return a minimal \class{alias} object that points to the given file, which +must be specified as a full pathname. This is the only way to create an +\class{Alias} pointing to a non-existing file. + +\end{funcdesc} + +\begin{funcdesc}{FindApplication}{creator} +Locate the application with 4-character creator code \var{creator}. The +function returns an \class{FSSpec} object pointing to the application. +\end{funcdesc} + + +\subsection{FSSpec Objects \label{fsspec-objects}} + +\begin{memberdesc}[FSSpec]{data} +The raw data from the FSSpec object, suitable for passing +to other applications, for instance. +\end{memberdesc} + +\begin{methoddesc}[FSSpec]{as_pathname}{} +Return the full pathname of the file described by the \class{FSSpec} +object. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{as_tuple}{} +Return the \code{(\var{wdRefNum}, \var{parID}, \var{name})} tuple of +the file described by the \class{FSSpec} object. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{NewAlias}{\optional{file}} +Create an Alias object pointing to the file described by this +FSSpec. If the optional \var{file} parameter is present the alias +will be relative to that file, otherwise it will be absolute. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{NewAliasMinimal}{} +Create a minimal alias pointing to this file. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{GetCreatorType}{} +Return the 4-character creator and type of the file. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{SetCreatorType}{creator, type} +Set the 4-character creator and type of the file. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{GetFInfo}{} +Return a \class{FInfo} object describing the finder info for the file. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{SetFInfo}{finfo} +Set the finder info for the file to the values given as \var{finfo} +(an \class{FInfo} object). +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{GetDates}{} +Return a tuple with three floating point values representing the +creation date, modification date and backup date of the file. +\end{methoddesc} + +\begin{methoddesc}[FSSpec]{SetDates}{crdate, moddate, backupdate} +Set the creation, modification and backup date of the file. The values +are in the standard floating point format used for times throughout +Python. +\end{methoddesc} + + +\subsection{Alias Objects \label{alias-objects}} + +\begin{memberdesc}[Alias]{data} +The raw data for the Alias record, suitable for storing in a resource +or transmitting to other programs. +\end{memberdesc} + +\begin{methoddesc}[Alias]{Resolve}{\optional{file}} +Resolve the alias. If the alias was created as a relative alias you +should pass the file relative to which it is. Return the FSSpec for +the file pointed to and a flag indicating whether the \class{Alias} object +itself was modified during the search process. If the file does +not exist but the path leading up to it does exist a valid fsspec +is returned. +\end{methoddesc} + +\begin{methoddesc}[Alias]{GetInfo}{num} +An interface to the \C{} routine \cfunction{GetAliasInfo()}. +\end{methoddesc} + +\begin{methoddesc}[Alias]{Update}{file\optional{, file2}} +Update the alias to point to the \var{file} given. If \var{file2} is +present a relative alias will be created. +\end{methoddesc} + +Note that it is currently not possible to directly manipulate a +resource as an \class{Alias} object. Hence, after calling +\method{Update()} or after \method{Resolve()} indicates that the alias +has changed the Python program is responsible for getting the +\member{data} value from the \class{Alias} object and modifying the +resource. + + +\subsection{FInfo Objects \label{finfo-objects}} + +See \citetitle{Inside Macintosh: Files} for a complete description of what +the various fields mean. + +\begin{memberdesc}[FInfo]{Creator} +The 4-character creator code of the file. +\end{memberdesc} + +\begin{memberdesc}[FInfo]{Type} +The 4-character type code of the file. +\end{memberdesc} + +\begin{memberdesc}[FInfo]{Flags} +The finder flags for the file as 16-bit integer. The bit values in +\var{Flags} are defined in standard module \module{MACFS}. +\end{memberdesc} + +\begin{memberdesc}[FInfo]{Location} +A Point giving the position of the file's icon in its folder. +\end{memberdesc} + +\begin{memberdesc}[FInfo]{Fldr} +The folder the file is in (as an integer). +\end{memberdesc} diff --git a/sys/src/cmd/python/Doc/mac/libmacic.tex b/sys/src/cmd/python/Doc/mac/libmacic.tex new file mode 100644 index 000000000..6d3a0d794 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libmacic.tex @@ -0,0 +1,123 @@ +\section{\module{ic} --- + Access to Internet Config} + +\declaremodule{builtin}{ic} + \platform{Mac} +\modulesynopsis{Access to Internet Config.} + + +This module provides access to various internet-related preferences +set through \program{System Preferences} or the \program{Finder}. + +There is a low-level companion module +\module{icglue}\refbimodindex{icglue} which provides the basic +Internet Config access functionality. This low-level module is not +documented, but the docstrings of the routines document the parameters +and the routine names are the same as for the Pascal or \C{} API to +Internet Config, so the standard IC programmers' documentation can be +used if this module is needed. + +The \module{ic} module defines the \exception{error} exception and +symbolic names for all error codes Internet Config can produce; see +the source for details. + +\begin{excdesc}{error} +Exception raised on errors in the \module{ic} module. +\end{excdesc} + + +The \module{ic} module defines the following class and function: + +\begin{classdesc}{IC}{\optional{signature\optional{, ic}}} +Create an Internet Config object. The signature is a 4-character creator +code of the current application (default \code{'Pyth'}) which may +influence some of ICs settings. The optional \var{ic} argument is a +low-level \code{icglue.icinstance} created beforehand, this may be +useful if you want to get preferences from a different config file, +etc. +\end{classdesc} + +\begin{funcdesc}{launchurl}{url\optional{, hint}} +\funcline{parseurl}{data\optional{, start\optional{, end\optional{, hint}}}} +\funcline{mapfile}{file} +\funcline{maptypecreator}{type, creator\optional{, filename}} +\funcline{settypecreator}{file} +These functions are ``shortcuts'' to the methods of the same name, +described below. +\end{funcdesc} + + +\subsection{IC Objects} + +\class{IC} objects have a mapping interface, hence to obtain the mail +address you simply get \code{\var{ic}['MailAddress']}. Assignment also +works, and changes the option in the configuration file. + +The module knows about various datatypes, and converts the internal IC +representation to a ``logical'' Python data structure. Running the +\module{ic} module standalone will run a test program that lists all +keys and values in your IC database, this will have to serve as +documentation. + +If the module does not know how to represent the data it returns an +instance of the \code{ICOpaqueData} type, with the raw data in its +\member{data} attribute. Objects of this type are also acceptable values +for assignment. + +Besides the dictionary interface, \class{IC} objects have the +following methods: + + +\begin{methoddesc}{launchurl}{url\optional{, hint}} +Parse the given URL, launch the correct application and pass it the +URL. The optional \var{hint} can be a scheme name such as +\code{'mailto:'}, in which case incomplete URLs are completed with this +scheme. If \var{hint} is not provided, incomplete URLs are invalid. +\end{methoddesc} + +\begin{methoddesc}{parseurl}{data\optional{, start\optional{, end\optional{, hint}}}} +Find an URL somewhere in \var{data} and return start position, end +position and the URL. The optional \var{start} and \var{end} can be +used to limit the search, so for instance if a user clicks in a long +text field you can pass the whole text field and the click-position in +\var{start} and this routine will return the whole URL in which the +user clicked. As above, \var{hint} is an optional scheme used to +complete incomplete URLs. +\end{methoddesc} + +\begin{methoddesc}{mapfile}{file} +Return the mapping entry for the given \var{file}, which can be passed +as either a filename or an \function{FSSpec()} result, and which +need not exist. + +The mapping entry is returned as a tuple \code{(\var{version}, +\var{type}, \var{creator}, \var{postcreator}, \var{flags}, +\var{extension}, \var{appname}, \var{postappname}, \var{mimetype}, +\var{entryname})}, where \var{version} is the entry version +number, \var{type} is the 4-character filetype, \var{creator} is the +4-character creator type, \var{postcreator} is the 4-character creator +code of an +optional application to post-process the file after downloading, +\var{flags} are various bits specifying whether to transfer in binary +or ascii and such, \var{extension} is the filename extension for this +file type, \var{appname} is the printable name of the application to +which this file belongs, \var{postappname} is the name of the +postprocessing application, \var{mimetype} is the MIME type of this +file and \var{entryname} is the name of this entry. +\end{methoddesc} + +\begin{methoddesc}{maptypecreator}{type, creator\optional{, filename}} +Return the mapping entry for files with given 4-character \var{type} and +\var{creator} codes. The optional \var{filename} may be specified to +further help finding the correct entry (if the creator code is +\code{'????'}, for instance). + +The mapping entry is returned in the same format as for \var{mapfile}. +\end{methoddesc} + +\begin{methoddesc}{settypecreator}{file} +Given an existing \var{file}, specified either as a filename or as an +\function{FSSpec()} result, set its creator and type correctly based +on its extension. The finder is told about the change, so the finder +icon will be updated quickly. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/mac/libmacos.tex b/sys/src/cmd/python/Doc/mac/libmacos.tex new file mode 100644 index 000000000..e50b99be2 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libmacos.tex @@ -0,0 +1,90 @@ +\section{\module{MacOS} --- + Access to Mac OS interpreter features} + +\declaremodule{builtin}{MacOS} + \platform{Mac} +\modulesynopsis{Access to Mac OS-specific interpreter features.} + + +This module provides access to MacOS specific functionality in the +Python interpreter, such as how the interpreter eventloop functions +and the like. Use with care. + +Note the capitalization of the module name; this is a historical +artifact. + +\begin{datadesc}{runtimemodel} +Always \code{'macho'}, from Python 2.4 on. +In earlier versions of Python the value could +also be \code{'ppc'} for the classic Mac OS 8 runtime model or +\code{'carbon'} for the Mac OS 9 runtime model. +\end{datadesc} + +\begin{datadesc}{linkmodel} +The way the interpreter has been linked. As extension modules may be +incompatible between linking models, packages could use this information to give +more decent error messages. The value is one of \code{'static'} for a +statically linked Python, \code{'framework'} for Python in a Mac OS X framework, +\code{'shared'} for Python in a standard \UNIX{} shared library. +Older Pythons could also have the value +\code{'cfm'} for Mac OS 9-compatible Python. +\end{datadesc} + +\begin{excdesc}{Error} +This exception is raised on MacOS generated errors, either from +functions in this module or from other mac-specific modules like the +toolbox interfaces. The arguments are the integer error code (the +\cdata{OSErr} value) and a textual description of the error code. +Symbolic names for all known error codes are defined in the standard +module \refmodule{macerrors}.\refstmodindex{macerrors} +\end{excdesc} + + +\begin{funcdesc}{GetErrorString}{errno} +Return the textual description of MacOS error code \var{errno}. +\end{funcdesc} + +\begin{funcdesc}{DebugStr}{message \optional{, object}} +On Mac OS X the string is simply printed to stderr (on older +Mac OS systems more elaborate functionality was available), +but it provides a convenient location to attach a breakpoint +in a low-level debugger like \program{gdb}. +\end{funcdesc} + +\begin{funcdesc}{SysBeep}{} +Ring the bell. +\end{funcdesc} + +\begin{funcdesc}{GetTicks}{} +Get the number of clock ticks (1/60th of a second) since system boot. +\end{funcdesc} + +\begin{funcdesc}{GetCreatorAndType}{file} +Return the file creator and file type as two four-character strings. +The \var{file} parameter can be a pathname or an \code{FSSpec} or +\code{FSRef} object. +\end{funcdesc} + +\begin{funcdesc}{SetCreatorAndType}{file, creator, type} +Set the file creator and file type. +The \var{file} parameter can be a pathname or an \code{FSSpec} or +\code{FSRef} object. \var{creator} and \var{type} must be four character +strings. +\end{funcdesc} + +\begin{funcdesc}{openrf}{name \optional{, mode}} +Open the resource fork of a file. Arguments are the same as for the +built-in function \function{open()}. The object returned has file-like +semantics, but it is not a Python file object, so there may be subtle +differences. +\end{funcdesc} + +\begin{funcdesc}{WMAvailable}{} +Checks whether the current process has access to the window manager. +The method will return \code{False} if the window manager is not available, +for instance when running on Mac OS X Server or when logged in via ssh, +or when the current interpreter is not running from a fullblown application +bundle. A script runs from an application bundle either when it has been +started with \program{pythonw} instead of \program{python} or when running +as an applet. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/mac/libmacostools.tex b/sys/src/cmd/python/Doc/mac/libmacostools.tex new file mode 100644 index 000000000..556e46f15 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libmacostools.tex @@ -0,0 +1,105 @@ +\section{\module{macostools} --- + Convenience routines for file manipulation} + +\declaremodule{standard}{macostools} + \platform{Mac} +\modulesynopsis{Convenience routines for file manipulation.} + + +This module contains some convenience routines for file-manipulation +on the Macintosh. All file parameters can be specified as +pathnames, \class{FSRef} or \class{FSSpec} objects. This module +expects a filesystem which supports forked files, so it should not +be used on UFS partitions. + +The \module{macostools} module defines the following functions: + + +\begin{funcdesc}{copy}{src, dst\optional{, createpath\optional{, copytimes}}} +Copy file \var{src} to \var{dst}. If \var{createpath} is non-zero +the folders leading to \var{dst} are created if necessary. +The method copies data and +resource fork and some finder information (creator, type, flags) and +optionally the creation, modification and backup times (default is to +copy them). Custom icons, comments and icon position are not copied. +\end{funcdesc} + +\begin{funcdesc}{copytree}{src, dst} +Recursively copy a file tree from \var{src} to \var{dst}, creating +folders as needed. \var{src} and \var{dst} should be specified as +pathnames. +\end{funcdesc} + +\begin{funcdesc}{mkalias}{src, dst} +Create a finder alias \var{dst} pointing to \var{src}. +\end{funcdesc} + +\begin{funcdesc}{touched}{dst} +Tell the finder that some bits of finder-information such as creator +or type for file \var{dst} has changed. The file can be specified by +pathname or fsspec. This call should tell the finder to redraw the +files icon. +\end{funcdesc} + +\begin{datadesc}{BUFSIZ} +The buffer size for \code{copy}, default 1 megabyte. +\end{datadesc} + +Note that the process of creating finder aliases is not specified in +the Apple documentation. Hence, aliases created with \function{mkalias()} +could conceivably have incompatible behaviour in some cases. + + +\section{\module{findertools} --- + The \program{finder}'s Apple Events interface} + +\declaremodule{standard}{findertools} + \platform{Mac} +\modulesynopsis{Wrappers around the \program{finder}'s Apple Events interface.} + + +This module contains routines that give Python programs access to some +functionality provided by the finder. They are implemented as wrappers +around the AppleEvent\index{AppleEvents} interface to the finder. + +All file and folder parameters can be specified either as full +pathnames, or as \class{FSRef} or \class{FSSpec} objects. + +The \module{findertools} module defines the following functions: + + +\begin{funcdesc}{launch}{file} +Tell the finder to launch \var{file}. What launching means depends on the file: +applications are started, folders are opened and documents are opened +in the correct application. +\end{funcdesc} + +\begin{funcdesc}{Print}{file} +Tell the finder to print a file. The behaviour is identical to selecting the file and using +the print command in the finder's file menu. +\end{funcdesc} + +\begin{funcdesc}{copy}{file, destdir} +Tell the finder to copy a file or folder \var{file} to folder +\var{destdir}. The function returns an \class{Alias} object pointing to +the new file. +\end{funcdesc} + +\begin{funcdesc}{move}{file, destdir} +Tell the finder to move a file or folder \var{file} to folder +\var{destdir}. The function returns an \class{Alias} object pointing to +the new file. +\end{funcdesc} + +\begin{funcdesc}{sleep}{} +Tell the finder to put the Macintosh to sleep, if your machine +supports it. +\end{funcdesc} + +\begin{funcdesc}{restart}{} +Tell the finder to perform an orderly restart of the machine. +\end{funcdesc} + +\begin{funcdesc}{shutdown}{} +Tell the finder to perform an orderly shutdown of the machine. +\end{funcdesc} diff --git a/sys/src/cmd/python/Doc/mac/libmacui.tex b/sys/src/cmd/python/Doc/mac/libmacui.tex new file mode 100644 index 000000000..db649abaa --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libmacui.tex @@ -0,0 +1,266 @@ +\section{\module{EasyDialogs} --- + Basic Macintosh dialogs} + +\declaremodule{standard}{EasyDialogs} + \platform{Mac} +\modulesynopsis{Basic Macintosh dialogs.} + +The \module{EasyDialogs} module contains some simple dialogs for the +Macintosh. All routines take an optional resource ID parameter \var{id} +with which one can override the \constant{DLOG} resource used for the +dialog, provided that the dialog items correspond (both type and item +number) to those in the default \constant{DLOG} resource. See source +code for details. + +The \module{EasyDialogs} module defines the following functions: + + +\begin{funcdesc}{Message}{str\optional{, id\optional{, ok}}} +Displays a modal dialog with the message text \var{str}, which should be +at most 255 characters long. The button text defaults to ``OK'', but is +set to the string argument \var{ok} if the latter is supplied. Control +is returned when the user clicks the ``OK'' button. +\end{funcdesc} + + +\begin{funcdesc}{AskString}{prompt\optional{, default\optional{, + id\optional{, ok\optional{, cancel}}}}} +Asks the user to input a string value via a modal dialog. \var{prompt} +is the prompt message, and the optional \var{default} supplies the +initial value for the string (otherwise \code{""} is used). The text of +the ``OK'' and ``Cancel'' buttons can be changed with the \var{ok} and +\var{cancel} arguments. All strings can be at most 255 bytes long. +\function{AskString()} returns the string entered or \constant{None} +in case the user cancelled. +\end{funcdesc} + + +\begin{funcdesc}{AskPassword}{prompt\optional{, default\optional{, + id\optional{, ok\optional{, cancel}}}}} +Asks the user to input a string value via a modal dialog. Like +\function{AskString()}, but with the text shown as bullets. The +arguments have the same meaning as for \function{AskString()}. +\end{funcdesc} + + +\begin{funcdesc}{AskYesNoCancel}{question\optional{, default\optional{, + yes\optional{, no\optional{, cancel\optional{, id}}}}}} +Presents a dialog with prompt \var{question} and three buttons labelled +``Yes'', ``No'', and ``Cancel''. Returns \code{1} for ``Yes'', \code{0} +for ``No'' and \code{-1} for ``Cancel''. The value of \var{default} (or +\code{0} if \var{default} is not supplied) is returned when the +\kbd{RETURN} key is pressed. The text of the buttons can be changed with +the \var{yes}, \var{no}, and \var{cancel} arguments; to prevent a button +from appearing, supply \code{""} for the corresponding argument. +\end{funcdesc} + + +\begin{funcdesc}{ProgressBar}{\optional{title\optional{, maxval\optional{, + label\optional{, id}}}}} +Displays a modeless progress-bar dialog. This is the constructor for the +\class{ProgressBar} class described below. \var{title} is the text +string displayed (default ``Working...''), \var{maxval} is the value at +which progress is complete (default \code{0}, indicating that an +indeterminate amount of work remains to be done), and \var{label} is +the text that is displayed above the progress bar itself. +\end{funcdesc} + + +\begin{funcdesc}{GetArgv}{\optional{optionlist\optional{ + commandlist\optional{, addoldfile\optional{, addnewfile\optional{, + addfolder\optional{, id}}}}}}} +Displays a dialog which aids the user in constructing a command-line +argument list. Returns the list in \code{sys.argv} format, suitable for +passing as an argument to \function{getopt.getopt()}. \var{addoldfile}, +\var{addnewfile}, and \var{addfolder} are boolean arguments. When +nonzero, they enable the user to insert into the command line paths to +an existing file, a (possibly) not-yet-existent file, and a folder, +respectively. (Note: Option arguments must appear in the command line +before file and folder arguments in order to be recognized by +\function{getopt.getopt()}.) Arguments containing spaces can be +specified by enclosing them within single or double quotes. A +\exception{SystemExit} exception is raised if the user presses the +``Cancel'' button. + +\var{optionlist} is a list that determines a popup menu from which the +allowed options are selected. Its items can take one of two forms: +\var{optstr} or \code{(\var{optstr}, \var{descr})}. When present, +\var{descr} is a short descriptive string that is displayed in the +dialog while this option is selected in the popup menu. The +correspondence between \var{optstr}s and command-line arguments is: + +\begin{tableii}{l|l}{textrm}{\var{optstr} format}{Command-line format} +\lineii{\code{x}} + {\programopt{-x} (short option)} +\lineii{\code{x:} or \code{x=}} + {\programopt{-x} (short option with value)} +\lineii{\code{xyz}} + {\longprogramopt{xyz} (long option)} +\lineii{\code{xyz:} or \code{xyz=}} + {\longprogramopt{xyz} (long option with value)} +\end{tableii} + +\var{commandlist} is a list of items of the form \var{cmdstr} or +\code{(\var{cmdstr}, \var{descr})}, where \var{descr} is as above. The +\var{cmdstr}s will appear in a popup menu. When chosen, the text of +\var{cmdstr} will be appended to the command line as is, except that a +trailing \character{:} or \character{=} (if present) will be trimmed +off. + +\versionadded{2.0} +\end{funcdesc} + +\begin{funcdesc}{AskFileForOpen}{ + \optional{message} + \optional{, typeList} + \optional{, defaultLocation} + \optional{, defaultOptionFlags} + \optional{, location} + \optional{, clientName} + \optional{, windowTitle} + \optional{, actionButtonLabel} + \optional{, cancelButtonLabel} + \optional{, preferenceKey} + \optional{, popupExtension} + \optional{, eventProc} + \optional{, previewProc} + \optional{, filterProc} + \optional{, wanted} + } +Post a dialog asking the user for a file to open, and return the file +selected or \constant{None} if the user cancelled. +\var{message} is a text message to display, +\var{typeList} is a list of 4-char filetypes allowable, +\var{defaultLocation} is the pathname, \class{FSSpec} or \class{FSRef} +of the folder to show initially, +\var{location} is the \code{(x, y)} position on the screen where the +dialog is shown, +\var{actionButtonLabel} is a string to show instead of ``Open'' in the +OK button, +\var{cancelButtonLabel} is a string to show instead of ``Cancel'' in the +cancel button, +\var{wanted} is the type of value wanted as a return: \class{str}, +\class{unicode}, \class{FSSpec}, \class{FSRef} and subtypes thereof are +acceptable. + +\index{Navigation Services} +For a description of the other arguments please see the Apple Navigation +Services documentation and the \module{EasyDialogs} source code. +\end{funcdesc} + +\begin{funcdesc}{AskFileForSave}{ + \optional{message} + \optional{, savedFileName} + \optional{, defaultLocation} + \optional{, defaultOptionFlags} + \optional{, location} + \optional{, clientName} + \optional{, windowTitle} + \optional{, actionButtonLabel} + \optional{, cancelButtonLabel} + \optional{, preferenceKey} + \optional{, popupExtension} + \optional{, fileType} + \optional{, fileCreator} + \optional{, eventProc} + \optional{, wanted} + } +Post a dialog asking the user for a file to save to, and return the +file selected or \constant{None} if the user cancelled. +\var{savedFileName} is the default for the file name to save to (the +return value). See \function{AskFileForOpen()} for a description of +the other arguments. +\end{funcdesc} + +\begin{funcdesc}{AskFolder}{ + \optional{message} + \optional{, defaultLocation} + \optional{, defaultOptionFlags} + \optional{, location} + \optional{, clientName} + \optional{, windowTitle} + \optional{, actionButtonLabel} + \optional{, cancelButtonLabel} + \optional{, preferenceKey} + \optional{, popupExtension} + \optional{, eventProc} + \optional{, filterProc} + \optional{, wanted} + } +Post a dialog asking the user to select a folder, and return the +folder selected or \constant{None} if the user cancelled. See +\function{AskFileForOpen()} for a description of the arguments. +\end{funcdesc} + + +\begin{seealso} + \seetitle + [http://developer.apple.com/documentation/Carbon/Reference/Navigation_Services_Ref/] + {Navigation Services Reference}{Programmer's reference documentation + for the Navigation Services, a part of the Carbon framework.} +\end{seealso} + + +\subsection{ProgressBar Objects \label{progressbar-objects}} + +\class{ProgressBar} objects provide support for modeless progress-bar +dialogs. Both determinate (thermometer style) and indeterminate +(barber-pole style) progress bars are supported. The bar will be +determinate if its maximum value is greater than zero; otherwise it +will be indeterminate. +\versionchanged[Support for indeterminate-style progress bars was + added]{2.2} + +The dialog is displayed immediately after creation. If the dialog's +``Cancel'' button is pressed, or if \kbd{Cmd-.} or \kbd{ESC} is typed, +the dialog window is hidden and \exception{KeyboardInterrupt} is +raised (but note that this response does not occur until the progress +bar is next updated, typically via a call to \method{inc()} or +\method{set()}). Otherwise, the bar remains visible until the +\class{ProgressBar} object is discarded. + +\class{ProgressBar} objects possess the following attributes and +methods: + +\begin{memberdesc}[ProgressBar]{curval} +The current value (of type integer or long integer) of the progress +bar. The normal access methods coerce \member{curval} between +\code{0} and \member{maxval}. This attribute should not be altered +directly. +\end{memberdesc} + +\begin{memberdesc}[ProgressBar]{maxval} +The maximum value (of type integer or long integer) of the progress +bar; the progress bar (thermometer style) is full when \member{curval} +equals \member{maxval}. If \member{maxval} is \code{0}, the bar will +be indeterminate (barber-pole). This attribute should not be altered +directly. +\end{memberdesc} + +\begin{methoddesc}[ProgressBar]{title}{\optional{newstr}} +Sets the text in the title bar of the progress dialog to +\var{newstr}. +\end{methoddesc} + +\begin{methoddesc}[ProgressBar]{label}{\optional{newstr}} +Sets the text in the progress box of the progress dialog to +\var{newstr}. +\end{methoddesc} + +\begin{methoddesc}[ProgressBar]{set}{value\optional{, max}} +Sets the progress bar's \member{curval} to \var{value}, and also +\member{maxval} to \var{max} if the latter is provided. \var{value} +is first coerced between 0 and \member{maxval}. The thermometer bar +is updated to reflect the changes, including a change from +indeterminate to determinate or vice versa. +\end{methoddesc} + +\begin{methoddesc}[ProgressBar]{inc}{\optional{n}} +Increments the progress bar's \member{curval} by \var{n}, or by \code{1} +if \var{n} is not provided. (Note that \var{n} may be negative, in +which case the effect is a decrement.) The progress bar is updated to +reflect the change. If the bar is indeterminate, this causes one +``spin'' of the barber pole. The resulting \member{curval} is coerced +between 0 and \member{maxval} if incrementing causes it to fall +outside this range. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/mac/libminiae.tex b/sys/src/cmd/python/Doc/mac/libminiae.tex new file mode 100644 index 000000000..9d815f098 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libminiae.tex @@ -0,0 +1,65 @@ +\section{\module{MiniAEFrame} --- + Open Scripting Architecture server support} + +\declaremodule{standard}{MiniAEFrame} + \platform{Mac} +\modulesynopsis{Support to act as an Open Scripting Architecture (OSA) server +(``Apple Events'').} + + +The module \module{MiniAEFrame} provides a framework for an application +that can function as an Open Scripting Architecture +\index{Open Scripting Architecture} +(OSA) server, i.e. receive and process +AppleEvents\index{AppleEvents}. It can be used in conjunction with +\refmodule{FrameWork}\refstmodindex{FrameWork} or standalone. As an +example, it is used in \program{PythonCGISlave}. + + +The \module{MiniAEFrame} module defines the following classes: + + +\begin{classdesc}{AEServer}{} +A class that handles AppleEvent dispatch. Your application should +subclass this class together with either +\class{MiniApplication} or +\class{FrameWork.Application}. Your \method{__init__()} method should +call the \method{__init__()} method for both classes. +\end{classdesc} + +\begin{classdesc}{MiniApplication}{} +A class that is more or less compatible with +\class{FrameWork.Application} but with less functionality. Its +event loop supports the apple menu, command-dot and AppleEvents; other +events are passed on to the Python interpreter and/or Sioux. +Useful if your application wants to use \class{AEServer} but does not +provide its own windows, etc. +\end{classdesc} + + +\subsection{AEServer Objects \label{aeserver-objects}} + +\begin{methoddesc}[AEServer]{installaehandler}{classe, type, callback} +Installs an AppleEvent handler. \var{classe} and \var{type} are the +four-character OSA Class and Type designators, \code{'****'} wildcards +are allowed. When a matching AppleEvent is received the parameters are +decoded and your callback is invoked. +\end{methoddesc} + +\begin{methoddesc}[AEServer]{callback}{_object, **kwargs} +Your callback is called with the OSA Direct Object as first positional +parameter. The other parameters are passed as keyword arguments, with +the 4-character designator as name. Three extra keyword parameters are +passed: \code{_class} and \code{_type} are the Class and Type +designators and \code{_attributes} is a dictionary with the AppleEvent +attributes. + +The return value of your method is packed with +\function{aetools.packevent()} and sent as reply. +\end{methoddesc} + +Note that there are some serious problems with the current +design. AppleEvents which have non-identifier 4-character designators +for arguments are not implementable, and it is not possible to return +an error to the originator. This will be addressed in a future +release. diff --git a/sys/src/cmd/python/Doc/mac/libscrap.tex b/sys/src/cmd/python/Doc/mac/libscrap.tex new file mode 100644 index 000000000..aa4627871 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/libscrap.tex @@ -0,0 +1,42 @@ +\section{\module{Carbon.Scrap} --- Scrap Manager} +\declaremodule{standard}{Carbon.Scrap} + \platform{Mac} +\modulesynopsis{The Scrap Manager provides basic services for + implementing cut \&\ paste and clipboard operations.} + + +This module is only fully available on MacOS9 and earlier under +classic PPC MacPython. Very limited functionality is available under +Carbon MacPython. + +The Scrap\index{Scrap Manager} Manager supports the simplest form of +cut \&\ paste operations on the Macintosh. It can be use for both +inter- and intra-application clipboard operations. + +The \module{Scrap} module provides low-level access to the functions +of the Scrap Manager. It contains the following functions: + + +\begin{funcdesc}{InfoScrap}{} + Return current information about the scrap. The information is + encoded as a tuple containing the fields \code{(\var{size}, + \var{handle}, \var{count}, \var{state}, \var{path})}. + + \begin{tableii}{l|l}{var}{Field}{Meaning} + \lineii{size}{Size of the scrap in bytes.} + \lineii{handle}{Resource object representing the scrap.} + \lineii{count}{Serial number of the scrap contents.} + \lineii{state}{Integer; positive if in memory, \code{0} if on + disk, negative if uninitialized.} + \lineii{path}{Filename of the scrap when stored on disk.} + \end{tableii} +\end{funcdesc} + + + +\begin{seealso} + \seetitle[http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-109.html] + {Scrap Manager}{Apple's documentation for the Scrap Manager + gives a lot of useful information about using the Scrap + Manager in applications.} +\end{seealso} diff --git a/sys/src/cmd/python/Doc/mac/mac.tex b/sys/src/cmd/python/Doc/mac/mac.tex new file mode 100644 index 000000000..c67545aea --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/mac.tex @@ -0,0 +1,89 @@ +\documentclass{manual} + +\title{Macintosh Library Modules} + +\input{boilerplate} + +\makeindex % tell \index to actually write the .idx file +\makemodindex % ... and the module index as well. + + +\begin{document} + +\maketitle + +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +\input{copyright} + +\begin{abstract} + +\noindent +This library reference manual documents Python's extensions for the +Macintosh. It should be used in conjunction with the +\citetitle[../lib/lib.html]{Python Library Reference}, which documents +the standard library and built-in types. + +This manual assumes basic knowledge about the Python language. For an +informal introduction to Python, see the +\citetitle[../tut/tut.html]{Python Tutorial}; the +\citetitle[../ref/ref.html]{Python Reference Manual} remains the +highest authority on syntactic and semantic questions. Finally, the +manual entitled \citetitle[../ext/ext.html]{Extending and Embedding +the Python Interpreter} describes how to add new extensions to Python +and how to embed it in other applications. + +\end{abstract} + +\tableofcontents + + +\input{using.tex} % Using Python on the Macintosh + + +\chapter{MacPython Modules \label{macpython-modules}} + +The following modules are only available on the Macintosh, and are +documented here: + +\localmoduletable + +\input{libmac} +\input{libmacfs} +\input{libmacic} +\input{libmacos} +\input{libmacostools} +\input{libmacui} +\input{libframework} +\input{libautogil} + +\input{scripting} + +\input{toolbox} % MacOS Toolbox Modules +\input{libcolorpicker} + +\input{undoc} % Undocumented Modules + +\appendix +\chapter{History and License} +\input{license} + +% +% The ugly "%begin{latexonly}" pseudo-environments are really just to +% keep LaTeX2HTML quiet during the \renewcommand{} macros; they're +% not really valuable. +% + +%begin{latexonly} +\renewcommand{\indexname}{Module Index} +%end{latexonly} +\input{modmac.ind} % Module Index + +%begin{latexonly} +\renewcommand{\indexname}{Index} +%end{latexonly} +\input{mac.ind} % Index + +\end{document} diff --git a/sys/src/cmd/python/Doc/mac/scripting.tex b/sys/src/cmd/python/Doc/mac/scripting.tex new file mode 100644 index 000000000..5ec497814 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/scripting.tex @@ -0,0 +1,101 @@ +\chapter{MacPython OSA Modules \label{scripting}} + +This chapter describes the current implementation of the Open Scripting +Architecure (OSA, also commonly referred to as AppleScript) for Python, allowing +you to control scriptable applications from your Python program, +and with a fairly pythonic interface. Development on this set of modules +has stopped, and a replacement is expected for Python 2.5. + +For a description of the various components of AppleScript and OSA, and +to get an understanding of the architecture and terminology, you should +read Apple's documentation. The "Applescript Language Guide" explains +the conceptual model and the terminology, and documents the standard +suite. The "Open Scripting Architecture" document explains how to use +OSA from an application programmers point of view. In the Apple Help +Viewer these books are located in the Developer Documentation, Core +Technologies section. + + +As an example of scripting an application, the following piece of +AppleScript will get the name of the frontmost \program{Finder} window +and print it: + +\begin{verbatim} +tell application "Finder" + get name of window 1 +end tell +\end{verbatim} + +In Python, the following code fragment will do the same: + +\begin{verbatim} +import Finder + +f = Finder.Finder() +print f.get(f.window(1).name) +\end{verbatim} + +As distributed the Python library includes packages that implement the +standard suites, plus packages that interface to a small number of +common applications. + +To send AppleEvents to an application you must first create the Python +package interfacing to the terminology of the application (what +\program{Script Editor} calls the "Dictionary"). This can be done from +within the \program{PythonIDE} or by running the +\file{gensuitemodule.py} module as a standalone program from the command +line. + +The generated output is a package with a number of modules, one for +every suite used in the program plus an \module{__init__} module to glue +it all together. The Python inheritance graph follows the AppleScript +inheritance graph, so if a program's dictionary specifies that it +includes support for the Standard Suite, but extends one or two verbs +with extra arguments then the output suite will contain a module +\module{Standard_Suite} that imports and re-exports everything from +\module{StdSuites.Standard_Suite} but overrides the methods that have +extra functionality. The output of \module{gensuitemodule} is pretty +readable, and contains the documentation that was in the original +AppleScript dictionary in Python docstrings, so reading it is a good +source of documentation. + +The output package implements a main class with the same name as the +package which contains all the AppleScript verbs as methods, with the +direct object as the first argument and all optional parameters as +keyword arguments. AppleScript classes are also implemented as Python +classes, as are comparisons and all the other thingies. + +The main +Python class implementing the verbs also allows access to the properties +and elements declared in the AppleScript class "application". In the +current release that is as far as the object orientation goes, so +in the example above we need to use +\code{f.get(f.window(1).name)} instead of the more Pythonic +\code{f.window(1).name.get()}. + + +If an AppleScript identifier is not a Python identifier the name is +mangled according to a small number of rules: +\begin{itemize} + \item spaces are replaced with underscores + \item other non-alphanumeric characters are replaced with + \code{_xx_} where \code{xx} is the hexadecimal character value + \item any Python reserved word gets an underscore appended +\end{itemize} + +Python also has support for creating scriptable applications +in Python, but +The following modules are relevant to MacPython AppleScript support: + +\localmoduletable + +In addition, support modules have been pre-generated for +\module{Finder}, \module{Terminal}, \module{Explorer}, +\module{Netscape}, \module{CodeWarrior}, \module{SystemEvents} and +\module{StdSuites}. + +\input{libgensuitemodule} +\input{libaetools} +\input{libaepack} +\input{libaetypes} +\input{libminiae} diff --git a/sys/src/cmd/python/Doc/mac/toolbox.tex b/sys/src/cmd/python/Doc/mac/toolbox.tex new file mode 100644 index 000000000..e7ce24f0a --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/toolbox.tex @@ -0,0 +1,173 @@ +\chapter{MacOS Toolbox Modules \label{toolbox}} + +There are a set of modules that provide interfaces to various MacOS +toolboxes. If applicable the module will define a number of Python +objects for the various structures declared by the toolbox, and +operations will be implemented as methods of the object. Other +operations will be implemented as functions in the module. Not all +operations possible in C will also be possible in Python (callbacks +are often a problem), and parameters will occasionally be different in +Python (input and output buffers, especially). All methods and +functions have a \member{__doc__} string describing their arguments +and return values, and for additional description you are referred to +\citetitle[http://developer.apple.com/documentation/macos8/mac8.html]{Inside +Macintosh} or similar works. + +These modules all live in a package called \module{Carbon}. Despite that name +they are not all part of the Carbon framework: CF is really in the CoreFoundation +framework and Qt is in the QuickTime framework. +The normal use pattern is + +\begin{verbatim} +from Carbon import AE +\end{verbatim} + +\strong{Warning!} These modules are not yet documented. If you +wish to contribute documentation of any of these modules, please get +in touch with \email{docs@python.org}. + +\localmoduletable + + +%\section{Argument Handling for Toolbox Modules} + + +\section{\module{Carbon.AE} --- Apple Events} +\declaremodule{standard}{Carbon.AE} + \platform{Mac} +\modulesynopsis{Interface to the Apple Events toolbox.} + +\section{\module{Carbon.AH} --- Apple Help} +\declaremodule{standard}{Carbon.AH} + \platform{Mac} +\modulesynopsis{Interface to the Apple Help manager.} + + +\section{\module{Carbon.App} --- Appearance Manager} +\declaremodule{standard}{Carbon.App} + \platform{Mac} +\modulesynopsis{Interface to the Appearance Manager.} + + +\section{\module{Carbon.CF} --- Core Foundation} +\declaremodule{standard}{Carbon.CF} + \platform{Mac} +\modulesynopsis{Interface to the Core Foundation.} + +The +\code{CFBase}, \code{CFArray}, \code{CFData}, \code{CFDictionary}, +\code{CFString} and \code{CFURL} objects are supported, some +only partially. + +\section{\module{Carbon.CG} --- Core Graphics} +\declaremodule{standard}{Carbon.CG} + \platform{Mac} +\modulesynopsis{Interface to the Component Manager.} + +\section{\module{Carbon.CarbonEvt} --- Carbon Event Manager} +\declaremodule{standard}{Carbon.CarbonEvt} + \platform{Mac} +\modulesynopsis{Interface to the Carbon Event Manager.} + +\section{\module{Carbon.Cm} --- Component Manager} +\declaremodule{standard}{Carbon.Cm} + \platform{Mac} +\modulesynopsis{Interface to the Component Manager.} + + +\section{\module{Carbon.Ctl} --- Control Manager} +\declaremodule{standard}{Carbon.Ctl} + \platform{Mac} +\modulesynopsis{Interface to the Control Manager.} + + +\section{\module{Carbon.Dlg} --- Dialog Manager} +\declaremodule{standard}{Carbon.Dlg} + \platform{Mac} +\modulesynopsis{Interface to the Dialog Manager.} + + +\section{\module{Carbon.Evt} --- Event Manager} +\declaremodule{standard}{Carbon.Evt} + \platform{Mac} +\modulesynopsis{Interface to the classic Event Manager.} + + +\section{\module{Carbon.Fm} --- Font Manager} +\declaremodule{standard}{Carbon.Fm} + \platform{Mac} +\modulesynopsis{Interface to the Font Manager.} + +\section{\module{Carbon.Folder} --- Folder Manager} +\declaremodule{standard}{Carbon.Folder} + \platform{Mac} +\modulesynopsis{Interface to the Folder Manager.} + + +\section{\module{Carbon.Help} --- Help Manager} +\declaremodule{standard}{Carbon.Help} + \platform{Mac} +\modulesynopsis{Interface to the Carbon Help Manager.} + +\section{\module{Carbon.List} --- List Manager} +\declaremodule{standard}{Carbon.List} + \platform{Mac} +\modulesynopsis{Interface to the List Manager.} + + +\section{\module{Carbon.Menu} --- Menu Manager} +\declaremodule{standard}{Carbon.Menu} + \platform{Mac} +\modulesynopsis{Interface to the Menu Manager.} + + +\section{\module{Carbon.Mlte} --- MultiLingual Text Editor} +\declaremodule{standard}{Carbon.Mlte} + \platform{Mac} +\modulesynopsis{Interface to the MultiLingual Text Editor.} + + +\section{\module{Carbon.Qd} --- QuickDraw} +\declaremodule{builtin}{Carbon.Qd} + \platform{Mac} +\modulesynopsis{Interface to the QuickDraw toolbox.} + + +\section{\module{Carbon.Qdoffs} --- QuickDraw Offscreen} +\declaremodule{builtin}{Carbon.Qdoffs} + \platform{Mac} +\modulesynopsis{Interface to the QuickDraw Offscreen APIs.} + + +\section{\module{Carbon.Qt} --- QuickTime} +\declaremodule{standard}{Carbon.Qt} + \platform{Mac} +\modulesynopsis{Interface to the QuickTime toolbox.} + + +\section{\module{Carbon.Res} --- Resource Manager and Handles} +\declaremodule{standard}{Carbon.Res} + \platform{Mac} +\modulesynopsis{Interface to the Resource Manager and Handles.} + +\section{\module{Carbon.Scrap} --- Scrap Manager} +\declaremodule{standard}{Carbon.Scrap} + \platform{Mac} +\modulesynopsis{Interface to the Carbon Scrap Manager.} + +\section{\module{Carbon.Snd} --- Sound Manager} +\declaremodule{standard}{Carbon.Snd} + \platform{Mac} +\modulesynopsis{Interface to the Sound Manager.} + + +\section{\module{Carbon.TE} --- TextEdit} +\declaremodule{standard}{Carbon.TE} + \platform{Mac} +\modulesynopsis{Interface to TextEdit.} + + +\section{\module{Carbon.Win} --- Window Manager} +\declaremodule{standard}{Carbon.Win} + \platform{Mac} +\modulesynopsis{Interface to the Window Manager.} diff --git a/sys/src/cmd/python/Doc/mac/undoc.tex b/sys/src/cmd/python/Doc/mac/undoc.tex new file mode 100644 index 000000000..72abadff6 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/undoc.tex @@ -0,0 +1,97 @@ +\chapter{Undocumented Modules \label{undocumented-modules}} + + +The modules in this chapter are poorly documented (if at all). If you +wish to contribute documentation of any of these modules, please get in +touch with +\ulink{\email{docs@python.org}}{mailto:docs@python.org}. + +\localmoduletable + + +\section{\module{applesingle} --- AppleSingle decoder} +\declaremodule{standard}{applesingle} + \platform{Mac} +\modulesynopsis{Rudimentary decoder for AppleSingle format files.} + + +\section{\module{buildtools} --- Helper module for BuildApplet and Friends} +\declaremodule{standard}{buildtools} + \platform{Mac} +\modulesynopsis{Helper module for BuildApplet, BuildApplication and + macfreeze.} + +\deprecated{2.4} + +\section{\module{cfmfile} --- Code Fragment Resource module} +\declaremodule{standard}{cfmfile} + \platform{Mac} +\modulesynopsis{Code Fragment Resource module.} + +\module{cfmfile} is a module that understands Code Fragments and the +accompanying ``cfrg'' resources. It can parse them and merge them, and is +used by BuildApplication to combine all plugin modules to a single +executable. + +\deprecated{2.4} + +\section{\module{icopen} --- Internet Config replacement for \method{open()}} +\declaremodule{standard}{icopen} + \platform{Mac} +\modulesynopsis{Internet Config replacement for \method{open()}.} + +Importing \module{icopen} will replace the builtin \method{open()} +with a version that uses Internet Config to set file type and creator +for new files. + + +\section{\module{macerrors} --- Mac OS Errors} +\declaremodule{standard}{macerrors} + \platform{Mac} +\modulesynopsis{Constant definitions for many Mac OS error codes.} + +\module{macerrors} contains constant definitions for many Mac OS error +codes. + + +\section{\module{macresource} --- Locate script resources} +\declaremodule{standard}{macresource} + \platform{Mac} +\modulesynopsis{Locate script resources.} + +\module{macresource} helps scripts finding their resources, such as +dialogs and menus, without requiring special case code for when the +script is run under MacPython, as a MacPython applet or under OSX Python. + +\section{\module{Nav} --- NavServices calls} +\declaremodule{standard}{Nav} + \platform{Mac} +\modulesynopsis{Interface to Navigation Services.} + +A low-level interface to Navigation Services. + +\section{\module{PixMapWrapper} --- Wrapper for PixMap objects} +\declaremodule{standard}{PixMapWrapper} + \platform{Mac} +\modulesynopsis{Wrapper for PixMap objects.} + +\module{PixMapWrapper} wraps a PixMap object with a Python object that +allows access to the fields by name. It also has methods to convert +to and from \module{PIL} images. + +\section{\module{videoreader} --- Read QuickTime movies} +\declaremodule{standard}{videoreader} + \platform{Mac} +\modulesynopsis{Read QuickTime movies frame by frame for further processing.} + +\module{videoreader} reads and decodes QuickTime movies and passes +a stream of images to your program. It also provides some support for +audio tracks. + +\section{\module{W} --- Widgets built on \module{FrameWork}} +\declaremodule{standard}{W} + \platform{Mac} +\modulesynopsis{Widgets for the Mac, built on top of \refmodule{FrameWork}.} + +The \module{W} widgets are used extensively in the \program{IDE}. + diff --git a/sys/src/cmd/python/Doc/mac/using.tex b/sys/src/cmd/python/Doc/mac/using.tex new file mode 100644 index 000000000..b21a98eb9 --- /dev/null +++ b/sys/src/cmd/python/Doc/mac/using.tex @@ -0,0 +1,218 @@ +\chapter{Using Python on a Macintosh \label{using}} +\sectionauthor{Bob Savage}{bobsavage@mac.com} + +Python on a Macintosh running Mac OS X is in principle very similar to +Python on any other \UNIX platform, but there are a number of additional +features such as the IDE and the Package Manager that are worth pointing out. + +Python on Mac OS 9 or earlier can be quite different from Python on +\UNIX{} or Windows, but is beyond the scope of this manual, as that platform +is no longer supported, starting with Python 2.4. See +\url{http://www.cwi.nl/\textasciitilde jack/macpython} for installers +for the latest 2.3 release for Mac OS 9 and related documentation. + +\section{Getting and Installing MacPython \label{getting-OSX}} + +Mac OS X 10.3 comes with Python 2.3 pre-installed by Apple. +This installation does not come with the IDE and other additions, however, +so to get these you need to install the \program{MacPython for Panther additions} +from the MacPython website, \url{http://www.cwi.nl/\textasciitilde jack/macpython}. + +For MacPython 2.4, or for any MacPython on earlier releases of Mac OS X, +you need to install a full distribution from the same website. + +What you get after installing is a number of things: + +\begin{itemize} + \item A \file{MacPython-2.3} folder in your \file{Applications} + folder. In here you find the PythonIDE Integrated Development Environment; + PythonLauncher, which handles double-clicking Python scripts from + the Finder; and the Package Manager. + + \item A fairly standard \UNIX{} commandline Python interpreter in + \file{/usr/local/bin/python}, but without the usual + \file{/usr/local/lib/python}. + + \item A framework \file{/Library/Frameworks/Python.framework}, where + all the action really is, but which you usually do not have to be aware of. +\end{itemize} + +To uninstall MacPython you can simply remove these three things. + +If you use the ``additions'' installer to install on top of an existing +Apple-Python you will not get the framework and the commandline interpreter, +as they have been installed by Apple already, in +\file{/System/Library/Frameworks/Python.framework} and +\file{/usr/bin/python}, respectively. You should in principle never modify +or delete these, as they are Apple-controlled and may be used by Apple- or +third-party software. + +PythonIDE contains an Apple Help Viewer book called "MacPython Help" +which you can access through its help menu. If you are completely new to +Python you should start reading the IDE introduction in that document. + +If you are familiar with Python on other \UNIX{} platforms you should +read the section on running Python scripts from the \UNIX{} shell. + +\subsection{How to run a Python script} + +Your best way to get started with Python on Mac OS X is through the PythonIDE +integrated development environment, see section \ref{IDE} and use the Help +menu when the IDE is running. + +If you want to run Python scripts from the Terminal window command line +or from the Finder you first need an editor to create your script. +Mac OS X comes with a number of standard \UNIX{} command line editors, +\program{vim} and \program{emacs} among them. If you want a more Mac-like +editor \program{BBEdit} or \program{TextWrangler} from Bare Bones Software +(see \url{http://www.barebones.com/products/bbedit/index.shtml}) are +good choices. \program{AppleWorks} or any other +word processor that can save files in ASCII is also a possibility, including +\program{TextEdit} which is included with OS X. + +To run your script from the Terminal window you must make sure that +\file{/usr/local/bin} is in your shell search path. + +To run your script from the Finder you have two options: +\begin{itemize} + \item Drag it to \program{PythonLauncher} + \item Select \program{PythonLauncher} as the default application + to open your script (or any .py script) through the finder Info window + and double-click it. +\end{itemize} + +PythonLauncher has various preferences to control how your script is launched. +Option-dragging allows you to change these for one invocation, or use its +Preferences menu to change things globally. + +\subsection{Running scripts with a GUI \label{osx-gui-scripts}} + +There is one Mac OS X quirk that you need to be aware of: programs +that talk to the Aqua window manager (in other words, anything that has a GUI) +need to be run in a special way. Use \program{pythonw} instead of \program{python} +to start such scripts. + +\subsection{configuration} + +MacPython honours all standard \UNIX{} environment variables such as +\envvar{PYTHONPATH}, but setting these variables for programs started +from the Finder is non-standard +as the Finder does not read your \file{.profile} or \file{.cshrc} at startup. +You need to create a file \file{\textasciitilde /.MacOSX/environment.plist}. +See Apple's Technical Document QA1067 for details. + +Installing additional Python packages is most easily done through the +Package Manager, see the MacPython Help Book for details. + + +\section{The IDE\label{IDE}} + +The \program{Python IDE} (Integrated Development Environment) is a +separate application that acts as a text editor for your Python code, +a class browser, a graphical debugger, and more. + +The online Python Help contains a quick walkthrough of the IDE that +shows the major features and how to use them. + +\subsection{Using the ``Python Interactive'' window} + +Use this window like you would use a normal \UNIX{} command line +interpreter. + +\subsection{Writing a Python Script \label{IDEwrite}} + +In addition to using the \program{Python IDE} interactively, you can +also type out a complete Python program, saving it incrementally, and +execute it or smaller selections of it. + +You can create a new script, open a previously saved script, and save +your currently open script by selecting the appropriate item in the +``File'' menu. Dropping a Python script onto the +\program{Python IDE} will open it for editing. + +When the \program{Python IDE} saves a script, it uses the creator code +settings which are available by clicking on the small black triangle +on the top right of the document window, and selecting ``save +options''. The default is to save the file with the \program{Python +IDE} as the creator, this means that you can open the file for editing +by simply double-clicking on its icon. You might want to change this +behaviour so that it will be opened by the +\program{PythonLauncher}, and run. To do this simply choose +``PythonLauncher'' from the ``save options''. Note that these +options are associated with the \emph{file} not the application. + + +\subsection{Executing a script from within the IDE + \label{IDEexecution}} + +You can run the script in the frontmost window of the \program{Python +IDE} by hitting the run all button. You should be aware, however that +if you use the Python convention \samp{if __name__ == "__main__":} the +script will \emph{not} be ``__main__'' by default. To get that +behaviour you must select the ``Run as __main__'' option from the +small black triangle on the top right of the document window. Note +that this option is associated with the \emph{file} not the +application. It \emph{will} stay active after a save, however; to shut +this feature off simply select it again. + + +\subsection{``Save as'' versus ``Save as Applet'' + \label{IDEapplet}} + +When you are done writing your Python script you have the option of +saving it as an ``applet'' (by selecting ``Save as applet'' from the +``File'' menu). This has a significant advantage in that you can drop +files or folders onto it, to pass them to the applet the way +command-line users would type them onto the command-line to pass them +as arguments to the script. However, you should make sure to save the +applet as a separate file, do not overwrite the script you are +writing, because you will not be able to edit it again. + +Accessing the items passed to the applet via ``drag-and-drop'' is done +using the standard \member{sys.argv} mechanism. See the general +documentation for more +% need to link to the appropriate place in non-Mac docs + +Note that saving a script as an applet will not make it runnable on a +system without a Python installation. + +%\subsection{Debugger} +% **NEED INFO HERE** + +%\subsection{Module Browser} +% **NEED INFO HERE** + +%\subsection{Profiler} +% **NEED INFO HERE** +% end IDE + +%\subsection{The ``Scripts'' menu} +% **NEED INFO HERE** + +\section{The Package Manager} + +Historically MacPython came with a number of useful extension packages +included, because most Macintosh users do not have access to a development +environment and C compiler. For Mac OS X that bundling is no longer done, +but a new mechanism has been made available to allow easy access to +extension packages. + +The Python Package Manager helps you installing additional packages +that enhance Python. It determines the exact MacOS version and Python +version you have and uses that information to download a database that +has packages that are tested and tried on that combination. In other +words: if something is in your Package Manager window but does not work +you are free to blame the database maintainer. + +PackageManager then checks which of the packages you have installed and +which ones are not. This should also work when you have installed packages +outside of PackageManager. You can select packages and install them, +and PackageManager will work out the requirements and install these too. + +Often PackageManager will list a package in two flavors: binary and +source. Binary should always work, source will only work if you have +installed the Apple Developer Tools. PackageManager will warn you about +this, and also about other external dependencies. + +PackageManager is available as a separate application and also as a +function of the IDE, through the File->Package Manager menu entry. diff --git a/sys/src/cmd/python/Doc/paper-a4/pypaper.sty b/sys/src/cmd/python/Doc/paper-a4/pypaper.sty new file mode 100644 index 000000000..2415aad02 --- /dev/null +++ b/sys/src/cmd/python/Doc/paper-a4/pypaper.sty @@ -0,0 +1,17 @@ +% +% Change this to say a4paper instead of letterpaper if you want A4. +% +\newcommand{\py@paper}{a4paper} +\newcommand{\py@ptsize}{10pt} + +% These set up the fonts for the documents. +% +% The "times" package makes the default font the PostScript Times +% font, which makes for smaller PostScript and a font that more people +% like. +% +% The "avant" package causes the AvantGarde font to be used for +% sans-serif text, instead of the uglier Helvetica set up by the "times" +% package. +% +\RequirePackage{times}\typeout{Using Times instead of Computer Modern.} diff --git a/sys/src/cmd/python/Doc/perl/SynopsisTable.pm b/sys/src/cmd/python/Doc/perl/SynopsisTable.pm new file mode 100644 index 000000000..3c65a67d1 --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/SynopsisTable.pm @@ -0,0 +1,95 @@ +package SynopsisTable; + +sub new{ + return bless {names=>'', info=>{}, file=>''}; +} + +sub declare{ + my($self,$name,$key,$type) = @_; + if ($self->{names}) { + $self->{names} .= ",$name"; + } + else { + $self->{names} .= "$name"; + } + $self->{info}{$name} = "$key,$type,"; +} + +# The 'file' attribute is used to store the filename of the node in which +# the table will be presented; this assumes that each table will be presented +# only once, which works for the current use of this object. + +sub set_file{ + my($self, $filename) = @_; + $self->{file} = "$filename"; +} + +sub get_file{ + my $self = shift; + return $self->{file}; +} + +sub set_synopsis{ + my($self,$name,$synopsis) = @_; + my($key,$type,$unused) = split ',', $self->{info}{$name}, 3; + $self->{info}{$name} = "$key,$type,$synopsis"; +} + +sub get{ + my($self,$name) = @_; + return split /,/, $self->{info}{$name}, 3; +} + +sub show{ + my $self = shift; + my $name; + print "names: ", $self->{names}, "\n\n"; + foreach $name (split /,/, $self->{names}) { + my($key,$type,$synopsis) = $self->get($name); + print "$name($key) is $type: $synopsis\n"; + } +} + +sub tohtml{ + my $self = shift; + my $oddrow = 1; + my $data = "<table class='synopsistable' valign='baseline'>\n"; + my $name; + foreach $name (split /,/, $self->{names}) { + my($key,$type,$synopsis) = $self->get($name); + my $link = "<a href='module-$key.html'>"; + $synopsis =~ s/<tex2html_percent_mark>/%/g; + $synopsis =~ s/<tex2html_ampersand_mark>/\&amp;/g; + $data .= (' <tr' + . ($oddrow ? " class='oddrow'>\n " : '>') + . "<td><b><tt class='module'>$link$name</a></tt></b></td>\n" + . " <td>\&nbsp;</td>\n" + . " <td class='synopsis'>$synopsis</td></tr>\n"); + $oddrow = !$oddrow; + } + $data .= "</table>\n"; + $data; +} + + +package testSynopsisTable; + +sub test{ + # this little test is mostly to debug the stuff above, since this is + # my first Perl "object". + my $st = SynopsisTable->new(); + $st->declare("sample", "sample", "standard"); + $st->set_synopsis("sample", "This is a little synopsis...."); + $st->declare("copy_reg", "copyreg", "standard"); + $st->set_synopsis("copy_reg", "pickle support stuff"); + $st->show(); + + print "\n\n"; + + my $st2 = SynopsisTable->new(); + $st2->declare("st2module", "st2module", "built-in"); + $st2->set_synopsis("st2module", "silly little synopsis"); + $st2->show(); +} + +1; # This must be the last line -- Perl is bogus! diff --git a/sys/src/cmd/python/Doc/perl/distutils.perl b/sys/src/cmd/python/Doc/perl/distutils.perl new file mode 100644 index 000000000..afc2e4aec --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/distutils.perl @@ -0,0 +1,21 @@ +# LaTeX2HTML support for distutils.sty. + +package main; + +sub do_cmd_command { + return use_wrappers(@_[0], '<code class="du-command">', '</code>'); +} + +sub do_cmd_option { + return use_wrappers(@_[0], '<span class="du-option">', '</span>'); +} + +sub do_cmd_filevar { + return use_wrappers(@_[0], '<span class="du-filevar">', '</span>'); +} + +sub do_cmd_XXX { + return use_wrappers(@_[0], '<b class="du-xxx">', '</b>'); +} + +1; # Bad Perl. diff --git a/sys/src/cmd/python/Doc/perl/howto.perl b/sys/src/cmd/python/Doc/perl/howto.perl new file mode 100644 index 000000000..76791ebb2 --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/howto.perl @@ -0,0 +1,12 @@ +# -*- perl -*- +# +# This implements the Python howto class. All it really needs to do it +# load the "python" style. + +package main; + +do_require_package("article"); +do_require_package("alltt"); +do_require_package("python"); + +1; # sheesh.... diff --git a/sys/src/cmd/python/Doc/perl/isilo.perl b/sys/src/cmd/python/Doc/perl/isilo.perl new file mode 100644 index 000000000..e990b36cb --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/isilo.perl @@ -0,0 +1,12 @@ +package main; + +$USING_STYLES = 0; +$NO_NAVIGATION = 1; +$INDEX_COLUMNS = 1; +$MODULE_INDEX_COLUMNS = 1; + +sub child_line { + return ''; +} + +1; # stupid perl... diff --git a/sys/src/cmd/python/Doc/perl/l2hinit.perl b/sys/src/cmd/python/Doc/perl/l2hinit.perl new file mode 100644 index 000000000..7c5d1230d --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/l2hinit.perl @@ -0,0 +1,801 @@ +# LaTeX2HTML support base for use with Python documentation. + +package main; + +use L2hos; + +$HTML_VERSION = 4.01; +$LOWER_CASE_TAGS = 1; +$NO_FRENCH_QUOTES = 1; + +# '' in \code{...} is still converted, so we can't use this yet. +#$USE_CURLY_QUOTES = 1; + +# Force Unicode support to be loaded; request UTF-8 output. +do_require_extension('unicode'); +do_require_extension('utf8'); +$HTML_OPTIONS = 'utf8'; + +$MAX_LINK_DEPTH = 2; +$ADDRESS = ''; + +$NO_FOOTNODE = 1; +$NUMBERED_FOOTNOTES = 1; + +# Python documentation uses section numbers to support references to match +# in the printed and online versions. +# +$SHOW_SECTION_NUMBERS = 1; + +$ICONSERVER = '.'; +$IMAGE_TYPE = 'gif'; + +# Control where the navigation bars should show up: +$TOP_NAVIGATION = 1; +$BOTTOM_NAVIGATION = 1; +$AUTO_NAVIGATION = 0; + +$BODYTEXT = ''; +$CHILDLINE = "\n<p><br /></p><hr class='online-navigation' />\n"; +$VERBOSITY = 0; + +# default # of columns for the indexes +$INDEX_COLUMNS = 2; +$MODULE_INDEX_COLUMNS = 4; + +$HAVE_MODULE_INDEX = 0; +$HAVE_GENERAL_INDEX = 0; +$HAVE_TABLE_OF_CONTENTS = 0; + +$AESOP_META_TYPE = 'information'; + + +# A little painful, but lets us clean up the top level directory a little, +# and not be tied to the current directory (as far as I can tell). Testing +# an existing definition of $mydir is needed since it cannot be computed when +# run under mkhowto with recent versions of LaTeX2HTML, since this file is +# not read directly by LaTeX2HTML any more. mkhowto is required to prepend +# the required definition at the top of the actual input file. +# +if (!defined $mydir) { + use Cwd; + use File::Basename; + ($myname, $mydir, $myext) = fileparse(__FILE__, '\..*'); + chop $mydir; # remove trailing '/' + $mydir = getcwd() . "$dd$mydir" + unless $mydir =~ s|^/|/|; +} +$LATEX2HTMLSTYLES = "$mydir$envkey$LATEX2HTMLSTYLES"; +push (@INC, $mydir); + +($myrootname, $myrootdir, $myext) = fileparse($mydir, '\..*'); +chop $myrootdir; + + +# Hackish way to get the appropriate paper-*/ directory into $TEXINPUTS; +# pass in the paper size (a4 or letter) as the environment variable PAPER +# to add the right directory. If not given, the current directory is +# added instead for use with HOWTO processing. +# +if (defined $ENV{'PAPER'}) { + $mytexinputs = "$myrootdir${dd}paper-$ENV{'PAPER'}$envkey"; +} +else { + $mytexinputs = getcwd() . $envkey; +} +$mytexinputs .= "$myrootdir${dd}texinputs"; + + +# Change this variable to change the text added in "About this document..."; +# this should be an absolute pathname to get it right. +# +$ABOUT_FILE = "$myrootdir${dd}html${dd}stdabout.dat"; + + +sub custom_driver_hook { + # + # This adds the directory of the main input file to $TEXINPUTS; it + # seems to be sufficiently general that it should be fine for HOWTO + # processing. + # + # XXX This still isn't quite right; we should actually be inserting + # $mytexinputs just before any empty entry in TEXINPUTS is one + # exists instead of just concatenating the pieces like we do here. + # + my $file = $_[0]; + my($jobname, $dir, $ext) = fileparse($file, '\..*'); + $dir = L2hos->Make_directory_absolute($dir); + $dir =~ s/$dd$//; + $TEXINPUTS = "$dir$envkey$mytexinputs"; + # Push everything into $TEXINPUTS since LaTeX2HTML doesn't pick + # this up on its own; we clear $ENV{'TEXINPUTS'} so the value set + # for this by the main LaTeX2HTML script doesn't contain duplicate + # directories. + if ($ENV{'TEXINPUTS'}) { + $TEXINPUTS .= "$envkey$ENV{'TEXINPUTS'}"; + $ENV{'TEXINPUTS'} = undef; + } + print "\nSetting \$TEXINPUTS to $TEXINPUTS\n"; + + # Not sure why we need to deal with this both here and at the top, + # but this is needed to actually make it work. + do_require_extension('utf8'); + $charset = $utf8_str; + $CHARSET = $utf8_str; + $USE_UTF = 1; +} + + +# $CUSTOM_BUTTONS is only used for the module index link. +$CUSTOM_BUTTONS = ''; + +sub make_nav_sectref($$$) { + my($label, $linktype, $title) = @_; + if ($title) { + if ($title =~ /\<[aA] /) { + $title =~ s/\<[aA] /<a class="sectref" rel="$linktype" /; + $title =~ s/ HREF=/ href=/; + } + else { + $title = "<span class=\"sectref\">$title</span>"; + } + return "<b class=\"navlabel\">$label:</b>\n$title\n"; + } + return ''; +} + +@my_icon_tags = (); +$my_icon_tags{'next'} = 'Next Page'; +$my_icon_tags{'next_page'} = 'Next Page'; +$my_icon_tags{'previous'} = 'Previous Page'; +$my_icon_tags{'previous_page'} = 'Previous Page'; +$my_icon_tags{'up'} = 'Up One Level'; +$my_icon_tags{'contents'} = 'Contents'; +$my_icon_tags{'index'} = 'Index'; +$my_icon_tags{'modules'} = 'Module Index'; + +@my_icon_names = (); +$my_icon_names{'previous_page'} = 'previous'; +$my_icon_names{'next_page'} = 'next'; + +sub get_my_icon($) { + my $name = $_[0]; + my $text = $my_icon_tags{$name}; + if ($my_icon_names{$name}) { + $name = $my_icon_names{$name}; + } + if ($text eq '') { + $name = 'blank'; + } + my $iconserver = ($ICONSERVER eq '.') ? '' : "$ICONSERVER/"; + return "<img src='$iconserver$name.$IMAGE_TYPE'\n border='0'" + . " height='32' alt='$text' width='32' />"; +} + +sub unlinkify($) { + my $text = "$_[0]"; + $text =~ s|</[aA]>||; + $text =~ s|<a\s+[^>]*>||i; + return $text; +} + +sub use_icon($$$) { + my($rel,$str,$title) = @_; + if ($str) { + my $s = "$str"; + if ($s =~ /\<tex2html_([a-z_]+)_visible_mark\>/) { + my $r = get_my_icon($1); + $s =~ s/\<tex2html_[a-z_]+_visible_mark\>/$r/; + } + $s =~ s/<[aA] /<a rel="$rel" title="$title"\n /; + $s =~ s/ HREF=/ href=/; + return $s; + } + else { + return get_my_icon('blank'); + } +} + +sub make_nav_panel() { + my $s; + # new iconic rel iconic page title + my $next = use_icon('next', $NEXT, unlinkify($NEXT_TITLE)); + my $up = use_icon('parent', $UP, unlinkify($UP_TITLE)); + my $previous = use_icon('prev', $PREVIOUS, unlinkify($PREVIOUS_TITLE)); + my $contents = use_icon('contents', $CONTENTS, 'Table of Contents'); + my $index = use_icon('index', $INDEX, 'Index'); + if (!$CUSTOM_BUTTONS) { + $CUSTOM_BUTTONS = get_my_icon('blank'); + } + $s = ('<table align="center" width="100%" cellpadding="0" cellspacing="2">' + . "\n<tr>" + # left-hand side + . "\n<td class='online-navigation'>$previous</td>" + . "\n<td class='online-navigation'>$up</td>" + . "\n<td class='online-navigation'>$next</td>" + # title box + . "\n<td align=\"center\" width=\"100%\">$t_title</td>" + # right-hand side + . "\n<td class='online-navigation'>$contents</td>" + # module index + . "\n<td class='online-navigation'>$CUSTOM_BUTTONS</td>" + . "\n<td class='online-navigation'>$index</td>" + . "\n</tr></table>\n" + # textual navigation + . "<div class='online-navigation'>\n" + . make_nav_sectref("Previous", "prev", $PREVIOUS_TITLE) + . make_nav_sectref("Up", "parent", $UP_TITLE) + . make_nav_sectref("Next", "next", $NEXT_TITLE) + . "</div>\n" + ); + # remove these; they are unnecessary and cause errors from validation + $s =~ s/ NAME="tex2html\d+"\n */ /g; + return $s; +} + +sub add_child_links { + my $toc = add_real_child_links(@_); + $toc =~ s|\s*</[aA]>|</a>|g; + $toc =~ s/ NAME=\"tex2html\d+\"\s*href=/ href=/gi; + $toc =~ s|</UL>(\s*<BR( /)?>)?|</ul>|gi; + if ($toc =~ / NAME=["']CHILD_LINKS["']/) { + return "<div class='online-navigation'>\n$toc</div>\n"; + } + return $toc; +} + +sub get_version_text() { + if ($PACKAGE_VERSION ne '' && $t_date) { + return ("<span class=\"release-info\">" + . "Release $PACKAGE_VERSION$RELEASE_INFO," + . " documentation updated on $t_date.</span>"); + } + if ($PACKAGE_VERSION ne '') { + return ("<span class=\"release-info\">" + . "Release $PACKAGE_VERSION$RELEASE_INFO.</span>"); + } + if ($t_date) { + return ("<span class=\"release-info\">Documentation released on " + . "$t_date.</span>"); + } + return ''; +} + + +sub top_navigation_panel() { + return "\n<div id='top-navigation-panel' xml:id='top-navigation-panel'>\n" + . make_nav_panel() + . "<hr /></div>\n"; +} + +sub bot_navigation_panel() { + return "\n<div class='online-navigation'>\n" + . "<p></p><hr />\n" + . make_nav_panel() + . "</div>\n" + . "<hr />\n" + . get_version_text() + . "\n"; +} + +sub add_link { + # Returns a pair (iconic link, textual link) + my($icon, $current_file, @link) = @_; + my($dummy, $file, $title) = split($delim, + $section_info{join(' ',@link)}); + if ($icon =~ /\<tex2html_([_a-z]+)_visible_mark\>/) { + my $r = get_my_icon($1); + $icon =~ s/\<tex2html_[_a-z]+_visible_mark\>/$r/; + } + if ($title && ($file ne $current_file)) { + $title = purify($title); + $title = get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES); + return (make_href($file, $icon), make_href($file, "$title")) + } + elsif ($icon eq get_my_icon('up') && $EXTERNAL_UP_LINK) { + return (make_href($EXTERNAL_UP_LINK, $icon), + make_href($EXTERNAL_UP_LINK, "$EXTERNAL_UP_TITLE")) + } + elsif ($icon eq get_my_icon('previous') + && $EXTERNAL_PREV_LINK && $EXTERNAL_PREV_TITLE) { + return (make_href($EXTERNAL_PREV_LINK, $icon), + make_href($EXTERNAL_PREV_LINK, "$EXTERNAL_PREV_TITLE")) + } + elsif ($icon eq get_my_icon('next') + && $EXTERNAL_DOWN_LINK && $EXTERNAL_DOWN_TITLE) { + return (make_href($EXTERNAL_DOWN_LINK, $icon), + make_href($EXTERNAL_DOWN_LINK, "$EXTERNAL_DOWN_TITLE")) + } + return (&inactive_img($icon), ""); +} + +sub add_special_link($$$) { + my($icon, $file, $current_file) = @_; + if ($icon =~ /\<tex2html_([_a-z]+)_visible_mark\>/) { + my $r = get_my_icon($1); + $icon =~ s/\<tex2html_[_a-z]+_visible_mark\>/$r/; + } + return (($file && ($file ne $current_file)) + ? make_href($file, $icon) + : undef) +} + +# The img_tag() function seems only to be called with the parameter +# 'anchor_invisible_mark', which we want to turn into ''. Since +# replace_icon_marks() is the only interesting caller, and all it really +# does is call img_tag(), we can just define the hook alternative to be +# a no-op instead. +# +sub replace_icons_hook {} + +sub do_cmd_arabic { + # get rid of that nasty <SPAN CLASS="arabic">...</SPAN> + my($ctr, $val, $id, $text) = &read_counter_value($_[0]); + return ($val ? farabic($val) : "0") . $text; +} + + +sub gen_index_id($$) { + # this is used to ensure common index key generation and a stable sort + my($str, $extra) = @_; + sprintf('%s###%s%010d', $str, $extra, ++$global{'max_id'}); +} + +sub insert_index($$$$$) { + my($mark, $datafile, $columns, $letters, $prefix) = @_; + my $prog = "$myrootdir/tools/buildindex.py"; + my $index; + if ($letters) { + $index = `$prog --columns $columns --letters $datafile`; + } + else { + $index = `$prog --columns $columns $datafile`; + } + if (!s/$mark/$prefix$index/) { + print "\nCould not locate index mark: $mark"; + } +} + +sub add_idx() { + print "\nBuilding HTML for the index ..."; + close(IDXFILE); + insert_index($idx_mark, 'index.dat', $INDEX_COLUMNS, 1, ''); +} + + +$idx_module_mark = '<tex2html_idx_module_mark>'; +$idx_module_title = 'Module Index'; + +sub add_module_idx() { + print "\nBuilding HTML for the module index ..."; + my $key; + my $first = 1; + my $prevplat = ''; + my $allthesame = 1; + my $prefix = ''; + foreach $key (keys %Modules) { + $key =~ s/<tt>([a-zA-Z0-9._]*)<\/tt>/$1/; + my $plat = "$ModulePlatforms{$key}"; + $plat = '' + if ($plat eq $IGNORE_PLATFORM_ANNOTATION); + if (!$first) { + $allthesame = 0 + if ($prevplat ne $plat); + } + else { $first = 0; } + $prevplat = $plat; + } + open(MODIDXFILE, '>modindex.dat') || die "\n$!\n"; + foreach $key (keys %Modules) { + # dump the line in the data file; just use a dummy seqno field + my $nkey = $1; + my $moditem = "$Modules{$key}"; + my $plat = ''; + $key =~ s/<tt>([a-zA-Z0-9._]*)<\/tt>/$1/; + if ($ModulePlatforms{$key} && !$allthesame) { + $plat = (" <em>(<span class=\"platform\">$ModulePlatforms{$key}" + . '</span>)</em>'); + } + print MODIDXFILE $moditem . $IDXFILE_FIELD_SEP + . "<tt class=\"module\">$key</tt>$plat###\n"; + } + close(MODIDXFILE); + + if ($GLOBAL_MODULE_INDEX) { + $prefix = <<MODULE_INDEX_PREFIX; + +<p> This index only lists modules documented in this manual. + The <em class="citetitle"><a href="$GLOBAL_MODULE_INDEX">Global Module + Index</a></em> lists all modules that are documented in this set + of manuals.</p> +MODULE_INDEX_PREFIX + } + if (!$allthesame) { + $prefix .= <<PLAT_DISCUSS; + +<p> Some module names are followed by an annotation indicating what +platform they are available on.</p> + +PLAT_DISCUSS + } + insert_index($idx_module_mark, 'modindex.dat', $MODULE_INDEX_COLUMNS, 0, + $prefix); +} + +# replace both indexes as needed: +sub add_idx_hook { + add_idx() if (/$idx_mark/); + process_python_state(); + if ($MODULE_INDEX_FILE) { + local ($_); + open(MYFILE, "<$MODULE_INDEX_FILE"); + sysread(MYFILE, $_, 1024*1024); + close(MYFILE); + add_module_idx(); + open(MYFILE,">$MODULE_INDEX_FILE"); + print MYFILE $_; + close(MYFILE); + } +} + + +# In addition to the standard stuff, add label to allow named node files and +# support suppression of the page complete (for HTML Help use). +$MY_CONTENTS_PAGE = ''; +sub do_cmd_tableofcontents { + local($_) = @_; + $TITLE = $toc_title; + $tocfile = $CURRENT_FILE; + my($closures, $reopens) = preserve_open_tags(); + anchor_label('contents', $CURRENT_FILE, $_); # this is added + $MY_CONTENTS_PAGE = "$CURRENT_FILE"; + join('', "\\tableofchildlinks[off]", $closures + , make_section_heading($toc_title, 'h2'), $toc_mark + , $reopens, $_); +} +# In addition to the standard stuff, add label to allow named node files. +sub do_cmd_listoffigures { + local($_) = @_; + $TITLE = $lof_title; + $loffile = $CURRENT_FILE; + my($closures, $reopens) = preserve_open_tags(); + anchor_label('lof', $CURRENT_FILE, $_); # this is added + join('', "<br />\n", $closures + , make_section_heading($lof_title, 'h2'), $lof_mark + , $reopens, $_); +} +# In addition to the standard stuff, add label to allow named node files. +sub do_cmd_listoftables { + local($_) = @_; + $TITLE = $lot_title; + $lotfile = $CURRENT_FILE; + my($closures, $reopens) = preserve_open_tags(); + anchor_label('lot', $CURRENT_FILE, $_); # this is added + join('', "<br />\n", $closures + , make_section_heading($lot_title, 'h2'), $lot_mark + , $reopens, $_); +} +# In addition to the standard stuff, add label to allow named node files. +sub do_cmd_textohtmlinfopage { + local($_) = @_; + if ($INFO) { # + anchor_label("about",$CURRENT_FILE,$_); # this is added + } # + my $the_version = ''; # and the rest is + if ($t_date) { # mostly ours + $the_version = ",\n$t_date"; + if ($PACKAGE_VERSION) { + $the_version .= ", Release $PACKAGE_VERSION$RELEASE_INFO"; + } + } + my $about; + open(ABOUT, "<$ABOUT_FILE") || die "\n$!\n"; + sysread(ABOUT, $about, 1024*1024); + close(ABOUT); + $_ = (($INFO == 1) + ? join('', + $close_all, + "<strong>$t_title</strong>$the_version\n", + $about, + $open_all, $_) + : join('', $close_all, $INFO,"\n", $open_all, $_)); + $_; +} + +$GENERAL_INDEX_FILE = ''; +$MODULE_INDEX_FILE = ''; + +# $idx_mark will be replaced with the real index at the end +sub do_cmd_textohtmlindex { + local($_) = @_; + $TITLE = $idx_title; + $idxfile = $CURRENT_FILE; + $GENERAL_INDEX_FILE = "$CURRENT_FILE"; + if (%index_labels) { make_index_labels(); } + if (($SHORT_INDEX) && (%index_segment)) { make_preindex(); } + else { $preindex = ''; } + my $heading = make_section_heading($idx_title, 'h2') . $idx_mark; + my($pre, $post) = minimize_open_tags($heading); + anchor_label('genindex',$CURRENT_FILE,$_); # this is added + return "<br />\n" . $pre . $_; +} + +# $idx_module_mark will be replaced with the real index at the end +sub do_cmd_textohtmlmoduleindex { + local($_) = @_; + $TITLE = $idx_module_title; + anchor_label('modindex', $CURRENT_FILE, $_); + $MODULE_INDEX_FILE = "$CURRENT_FILE"; + $_ = ('<p></p>' . make_section_heading($idx_module_title, 'h2') + . $idx_module_mark . $_); + return $_; +} + +# The bibliography and the index should be treated as separate +# sections in their own HTML files. The \bibliography{} command acts +# as a sectioning command that has the desired effect. But when the +# bibliography is constructed manually using the thebibliography +# environment, or when using the theindex environment it is not +# possible to use the normal sectioning mechanism. This subroutine +# inserts a \bibliography{} or a dummy \textohtmlindex command just +# before the appropriate environments to force sectioning. + +# XXX This *assumes* that if there are two {theindex} environments, +# the first is the module index and the second is the standard +# index. This is sufficient for the current Python documentation, +# but that's about it. + +sub add_bbl_and_idx_dummy_commands { + my $id = $global{'max_id'}; + + if (/[\\]tableofcontents/) { + $HAVE_TABLE_OF_CONTENTS = 1; + } + s/([\\]begin\s*$O\d+$C\s*thebibliography)/$bbl_cnt++; $1/eg; + s/([\\]begin\s*$O\d+$C\s*thebibliography)/$id++; "\\bibliography$O$id$C$O$id$C $1"/geo; + my(@parts) = split(/\\begin\s*$O\d+$C\s*theindex/); + if (scalar(@parts) == 3) { + # Be careful to re-write the string in place, since $_ is *not* + # returned explicity; *** nasty side-effect dependency! *** + print "\nadd_bbl_and_idx_dummy_commands ==> adding general index"; + print "\nadd_bbl_and_idx_dummy_commands ==> adding module index"; + my $rx = "([\\\\]begin\\s*$O\\d+$C\\s*theindex[\\s\\S]*)" + . "([\\\\]begin\\s*$O\\d+$C\\s*theindex)"; + s/$rx/\\textohtmlmoduleindex $1 \\textohtmlindex $2/o; + # Add a button to the navigation areas: + $CUSTOM_BUTTONS .= ('<a href="modindex.html" title="Module Index">' + . get_my_icon('modules') + . '</a>'); + $HAVE_MODULE_INDEX = 1; + $HAVE_GENERAL_INDEX = 1; + } + elsif (scalar(@parts) == 2) { + print "\nadd_bbl_and_idx_dummy_commands ==> adding general index"; + my $rx = "([\\\\]begin\\s*$O\\d+$C\\s*theindex)"; + s/$rx/\\textohtmlindex $1/o; + $HAVE_GENERAL_INDEX = 1; + } + elsif (scalar(@parts) == 1) { + print "\nadd_bbl_and_idx_dummy_commands ==> no index found"; + $CUSTOM_BUTTONS .= get_my_icon('blank'); + $global{'max_id'} = $id; # not sure why.... + s/([\\]begin\s*$O\d+$C\s*theindex)/\\textohtmlindex $1/o; + s/[\\]printindex/\\textohtmlindex /o; + } + else { + die "\n\nBad number of index environments!\n\n"; + } + #---------------------------------------------------------------------- + lib_add_bbl_and_idx_dummy_commands() + if defined(&lib_add_bbl_and_idx_dummy_commands); +} + +# The bibliographic references, the appendices, the lists of figures +# and tables etc. must appear in the contents table at the same level +# as the outermost sectioning command. This subroutine finds what is +# the outermost level and sets the above to the same level; + +sub set_depth_levels { + # Sets $outermost_level + my $level; + #RRM: do not alter user-set value for $MAX_SPLIT_DEPTH + foreach $level ("part", "chapter", "section", "subsection", + "subsubsection", "paragraph") { + last if (($outermost_level) = /\\($level)$delimiter_rx/); + } + $level = ($outermost_level ? $section_commands{$outermost_level} : + do {$outermost_level = 'section'; 3;}); + + #RRM: but calculate value for $MAX_SPLIT_DEPTH when a $REL_DEPTH was given + if ($REL_DEPTH && $MAX_SPLIT_DEPTH) { + $MAX_SPLIT_DEPTH = $level + $MAX_SPLIT_DEPTH; + } elsif (!($MAX_SPLIT_DEPTH)) { $MAX_SPLIT_DEPTH = 1 }; + + %unnumbered_section_commands = ('tableofcontents' => $level, + 'listoffigures' => $level, + 'listoftables' => $level, + 'bibliography' => $level, + 'textohtmlindex' => $level, + 'textohtmlmoduleindex' => $level); + $section_headings{'textohtmlmoduleindex'} = 'h1'; + + %section_commands = (%unnumbered_section_commands, + %section_commands); + + make_sections_rx(); +} + + +# This changes the markup used for {verbatim} environments, and is the +# best way I've found that ensures the <dl> goes on the outside of the +# <pre>...</pre>. +# +# Note that this *must* be done in the init file, not the python.perl +# style support file. The %declarations must be set before +# initialize() is called in the main LaTeX2HTML script (which happens +# before style files are loaded). +# +%declarations = ('preform' => '<div class="verbatim"><pre></pre></div>', + %declarations); + + +# This is a modified version of what's provided by LaTeX2HTML; see the +# comment on the middle stanza for an explanation of why we keep our +# own version. +# +# This routine must be called once on the text only, +# else it will "eat up" sensitive constructs. +sub text_cleanup { + # MRO: replaced $* with /m + s/(\s*\n){3,}/\n\n/gom; # Replace consecutive blank lines with one + s/<(\/?)P>\s*(\w)/<$1P>\n$2/gom; # clean up paragraph starts and ends + s/$O\d+$C//go; # Get rid of bracket id's + s/$OP\d+$CP//go; # Get rid of processed bracket id's + s/(<!)?--?(>)?/(length($1) || length($2)) ? "$1--$2" : "-"/ge; + # Spacing commands + s/\\( |$)/ /go; + #JKR: There should be no more comments in the source now. + #s/([^\\]?)%/$1/go; # Remove the comment character + # Cannot treat \, as a command because , is a delimiter ... + s/\\,/ /go; + # Replace tilde's with non-breaking spaces + s/ *~/&nbsp;/g; + + # This is why we have this copy of this routine; the following + # isn't so desirable as the author/maintainers of LaTeX2HTML seem + # to think. It's not commented out in the main script, so we have + # to override the whole thing. In particular, we don't want empty + # table cells to disappear. + + ### DANGEROUS ?? ### + # remove redundant (not <P></P>) empty tags, incl. with attributes + #s/\n?<([^PD >][^>]*)>\s*<\/\1>//g; + #s/\n?<([^PD >][^>]*)>\s*<\/\1>//g; + # remove redundant empty tags (not </P><P> or <TD> or <TH>) + #s/<\/(TT|[^PTH][A-Z]+)><\1>//g; + #s/<([^PD ]+)(\s[^>]*)?>\n*<\/\1>//g; + + #JCL(jcl-hex) + # Replace ^^ special chars (according to p.47 of the TeX book) + # Useful when coming from the .aux file (german umlauts, etc.) + s/\^\^([^0-9a-f])/chr((64+ord($1))&127)/ge; + s/\^\^([0-9a-f][0-9a-f])/chr(hex($1))/ge; +} + +# This is used to map the link rel attributes LaTeX2HTML uses to those +# currently recommended by the W3C. +sub custom_REL_hook { + my($rel,$junk) = @_; + return 'parent' if $rel eq 'up'; + return 'prev' if $rel eq 'previous'; + return $rel; +} + +# This is added to get rid of the long comment that follows the +# doctype declaration; MSIE5 on NT4 SP4 barfs on it and drops the +# content of the page. +$MY_PARTIAL_HEADER = ''; +sub make_head_and_body($$) { + my($title, $body) = @_; + $body = " $body" unless ($body eq ''); + my $DTDcomment = ''; + my($version, $isolanguage) = ($HTML_VERSION, 'EN'); + my %isolanguages = ( 'english', 'EN' , 'USenglish', 'EN.US' + , 'original', 'EN' , 'german' , 'DE' + , 'austrian', 'DE.AT', 'french' , 'FR' + , 'spanish', 'ES'); + $isolanguage = $isolanguages{$default_language}; + $isolanguage = 'EN' unless $isolanguage; + $title = &purify($title,1); + eval("\$title = ". $default_title ) unless ($title); + + # allow user-modification of the <title> tag; thanks Dan Young + if (defined &custom_TITLE_hook) { + $title = &custom_TITLE_hook($title, $toc_sec_title); + } + + if ($DOCTYPE =~ /\/\/[\w\.]+\s*$/) { # language spec included + $DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE\">\n"; + } else { + $DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE//" + . ($ISO_LANGUAGE ? $ISO_LANGUAGE : $isolanguage) . "\">\n"; + } + if ($MY_PARTIAL_HEADER eq '') { + my $favicon = ''; + if ($FAVORITES_ICON) { + my($myname, $mydir, $myext) = fileparse($FAVORITES_ICON, '\..*'); + my $favtype = ''; + if ($myext eq '.gif' || $myext eq '.png') { + $myext =~ s/^[.]//; + $favtype = " type=\"image/$myext\""; + } + $favicon = ( + "\n<link rel=\"SHORTCUT ICON\" href=\"$FAVORITES_ICON\"" + . "$favtype />"); + } + $STYLESHEET = $FILE.".css" unless $STYLESHEET; + $MY_PARTIAL_HEADER = join('', + ($DOCTYPE ? $DTDcomment : ''), + "<html>\n<head>", + ($BASE ? "\n<base href=\"$BASE\" />" : ''), + "\n<link rel=\"STYLESHEET\" href=\"$STYLESHEET\" type='text/css'", + " />", + $favicon, + ($EXTERNAL_UP_LINK + ? ("\n<link rel='start' href='" . $EXTERNAL_UP_LINK + . ($EXTERNAL_UP_TITLE ? + "' title='$EXTERNAL_UP_TITLE' />" : "' />")) + : ''), + "\n<link rel=\"first\" href=\"$FILE.html\"", + ($t_title ? " title='$t_title'" : ''), + ' />', + ($HAVE_TABLE_OF_CONTENTS + ? ("\n<link rel='contents' href='$MY_CONTENTS_PAGE'" + . ' title="Contents" />') + : ''), + ($HAVE_GENERAL_INDEX + ? ("\n<link rel='index' href='$GENERAL_INDEX_FILE'" + . " title='Index' />") + : ''), + # disable for now -- Mozilla doesn't do well with multiple indexes + # ($HAVE_MODULE_INDEX + # ? ("<link rel="index" href='$MODULE_INDEX_FILE'" + # . " title='Module Index' />\n") + # : ''), + ($INFO + # XXX We can do this with the Python tools since the About... + # page always gets copied to about.html, even when we use the + # generated node###.html page names. Won't work with the + # rest of the Python doc tools. + ? ("\n<link rel='last' href='about.html'" + . " title='About this document...' />" + . "\n<link rel='help' href='about.html'" + . " title='About this document...' />") + : ''), + $more_links_mark, + "\n", + ($CHARSET && $HTML_VERSION ge "2.1" + ? ('<meta http-equiv="Content-Type" content="text/html; ' + . "charset=$CHARSET\" />\n") + : ''), + ($AESOP_META_TYPE + ? "<meta name='aesop' content='$AESOP_META_TYPE' />\n" : '')); + } + if (!$charset && $CHARSET) { + $charset = $CHARSET; + $charset =~ s/_/\-/go; + } + join('', + $MY_PARTIAL_HEADER, + "<title>", $title, "</title>\n</head>\n<body$body>"); +} + +sub replace_morelinks { + $more_links =~ s/ REL=/ rel=/g; + $more_links =~ s/ HREF=/ href=/g; + $more_links =~ s/<LINK /<link /g; + $more_links =~ s/">/" \/>/g; + $_ =~ s/$more_links_mark/$more_links/e; +} + +1; # This must be the last line diff --git a/sys/src/cmd/python/Doc/perl/ltxmarkup.perl b/sys/src/cmd/python/Doc/perl/ltxmarkup.perl new file mode 100644 index 000000000..1a0f7e193 --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/ltxmarkup.perl @@ -0,0 +1,67 @@ +# LaTeX2HTML support for the ltxmarkup package. Doesn't do indexing. + +package main; + + +sub ltx_next_argument{ + my $param; + $param = missing_braces() + unless ((s/$next_pair_pr_rx/$param=$2;''/eo) + ||(s/$next_pair_rx/$param=$2;''/eo)); + return $param; +} + + +sub do_cmd_macro{ + local($_) = @_; + my $macro = ltx_next_argument(); + return "<tt class='macro'>&#92;$macro</tt>" . $_; +} + +sub do_cmd_env{ + local($_) = @_; + my $env = ltx_next_argument(); + return "<tt class='environment'>&#92;$env</tt>" . $_; +} + +sub ltx_process_params{ + # Handle processing of \p and \op for parameter specifications for + # envdesc and macrodesc. It's done this way to avoid defining do_cmd_p() + # and do_cmd_op() functions, which would be interpreted outside the context + # in which these commands are legal, and cause LaTeX2HTML to think they're + # defined. This way, other uses of \p and \op are properly flagged as + # unknown macros. + my $s = @_[0]; + $s =~ s%\\op<<(\d+)>>(.+)<<\1>>%<tt>[</tt><var>$2</var><tt>]</tt>%; + while ($s =~ /\\p<<(\d+)>>(.+)<<\1>>/) { + $s =~ s%\\p<<(\d+)>>(.+)<<\1>>%<tt>{</tt><var>$2</var><tt>}</tt>%; + } + return $s; +} + +sub do_env_macrodesc{ + local($_) = @_; + my $macro = ltx_next_argument(); + my $params = ltx_process_params(ltx_next_argument()); + return "\n<dl class='macrodesc'>" + . "\n<dt><b><tt class='macro'>&#92;$macro</tt></b>" + . "\n $params</dt>" + . "\n<dd>" + . $_ + . '</dd></dl>'; +} + +sub do_env_envdesc{ + local($_) = @_; + my $env = ltx_next_argument(); + my $params = ltx_process_params(ltx_next_argument()); + return "\n<dl class='envdesc'>" + . "\n<dt><tt>&#92;begin{<b class='environment'>$env</b>}</tt>" + . "\n $params" + . "\n<br /><tt>&#92;end{<b class='environment'>$env</b>}</tt></dt>" + . "\n<dd>" + . $_ + . '</dd></dl>'; +} + +1; # Must end with this, because Perl is bogus. diff --git a/sys/src/cmd/python/Doc/perl/manual.perl b/sys/src/cmd/python/Doc/perl/manual.perl new file mode 100644 index 000000000..ea65b36e7 --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/manual.perl @@ -0,0 +1,15 @@ +# -*- perl -*- +# +# This implements the Python manual class. All it really needs to do it +# load the "python" style. The style code is not moved into the class code +# at this time, since we expect additional document class to be developed +# for the Python documentation in the future. Appropriate relocations will +# be made at that time. + +package main; + +do_require_package("report"); +do_require_package("alltt"); +do_require_package("python"); + +1; # sheesh.... diff --git a/sys/src/cmd/python/Doc/perl/python.perl b/sys/src/cmd/python/Doc/perl/python.perl new file mode 100644 index 000000000..ab93c7cf8 --- /dev/null +++ b/sys/src/cmd/python/Doc/perl/python.perl @@ -0,0 +1,2172 @@ +# python.perl by Fred L. Drake, Jr. <fdrake@acm.org> -*- perl -*- +# +# Heavily based on Guido van Rossum's myformat.perl (now obsolete). +# +# Extension to LaTeX2HTML for documents using myformat.sty. +# Subroutines of the form do_cmd_<name> here define translations +# for LaTeX commands \<name> defined in the corresponding .sty file. + +package main; + +use warnings; +use File::Basename; + + +sub next_argument{ + my $param; + $param = missing_braces() + unless ((s/$next_pair_pr_rx/$param=$2;''/eo) + ||(s/$next_pair_rx/$param=$2;''/eo)); + return $param; +} + +sub next_optional_argument{ + my($param, $rx) = ('', "^\\s*(\\[([^]]*)\\])?"); + s/$rx/$param=$2;''/eo; + return $param; +} + +sub make_icon_filename($){ + my($myname, $mydir, $myext) = fileparse($_[0], '\..*'); + chop $mydir; + if ($mydir eq '.') { + $mydir = $ICONSERVER; + } + $myext = ".$IMAGE_TYPE" + unless $myext; + return "$mydir$dd$myname$myext"; +} + +sub get_link_icon($){ + my $url = $_[0]; + if ($OFF_SITE_LINK_ICON && ($url =~ /^[-a-zA-Z0-9.]+:/)) { + # absolute URL; assume it points off-site + my $icon = make_icon_filename($OFF_SITE_LINK_ICON); + return (" <img src=\"$icon\"\n" + . ' border="0" class="offsitelink"' + . ($OFF_SITE_LINK_ICON_HEIGHT + ? " height=\"$OFF_SITE_LINK_ICON_HEIGHT\"" + : '') + . ($OFF_SITE_LINK_ICON_WIDTH + ? " width=\"$OFF_SITE_LINK_ICON_WIDTH\"" + : '') + . " alt=\"[off-site link]\"\n" + . " />"); + } + return ''; +} + +# This is a fairly simple hack; it supports \let when it is used to create +# (or redefine) a macro to exactly be some other macro: \let\newname=\oldname. +# Many possible uses of \let aren't supported or aren't supported correctly. +# +sub do_cmd_let{ + local($_) = @_; + my $matched = 0; + s/[\\]([a-zA-Z]+)\s*(=\s*)?[\\]([a-zA-Z]*)/$matched=1; ''/e; + if ($matched) { + my($new, $old) = ($1, $3); + eval "sub do_cmd_$new { do_cmd_$old" . '(@_); }'; + print "\ndefining handler for \\$new using \\$old\n"; + } + else { + s/[\\]([a-zA-Z]+)\s*(=\s*)?([^\\])/$matched=1; ''/es; + if ($matched) { + my($new, $char) = ($1, $3); + eval "sub do_cmd_$new { \"\\$char\" . \$_[0]; }"; + print "\ndefining handler for \\$new to insert '$char'\n"; + } + else { + write_warnings("Could not interpret \\let construct..."); + } + } + return $_; +} + + +# the older version of LaTeX2HTML we use doesn't support this, but we use it: + +sub do_cmd_textasciitilde{ '&#126;' . $_[0]; } +sub do_cmd_textasciicircum{ '^' . $_[0]; } +sub do_cmd_textbar{ '|' . $_[0]; } +sub do_cmd_texteuro { '&#8364;' . $_[0]; } +sub do_cmd_textgreater{ '&gt;' . $_[0]; } +sub do_cmd_textless{ '&lt;' . $_[0]; } +sub do_cmd_textunderscore{ '_' . $_[0]; } +sub do_cmd_infinity{ '&infin;' . $_[0]; } +sub do_cmd_plusminus{ '&plusmn;' . $_[0]; } +sub do_cmd_guilabel{ + return use_wrappers($_[0]. '<span class="guilabel">', '</span>'); } +sub do_cmd_menuselection{ + return use_wrappers($_[0], '<span class="guilabel">', '</span>'); } +sub do_cmd_sub{ + return '</span> &gt; <span class="guilabel">' . $_[0]; } + + +# words typeset in a special way (not in HTML though) + +sub do_cmd_ABC{ 'ABC' . $_[0]; } +sub do_cmd_UNIX{ '<span class="Unix">Unix</span>' . $_[0]; } +sub do_cmd_LaTeX{ '<span class="LaTeX">LaTeX</span>' . $_[0]; } +sub do_cmd_TeX{ '<span class="TeX">TeX</span>' . $_[0]; } +sub do_cmd_ASCII{ 'ASCII' . $_[0]; } +sub do_cmd_POSIX{ 'POSIX' . $_[0]; } +sub do_cmd_C{ 'C' . $_[0]; } +sub do_cmd_Cpp{ 'C++' . $_[0]; } +sub do_cmd_EOF{ 'EOF' . $_[0]; } +sub do_cmd_NULL{ '<tt class="constant">NULL</tt>' . $_[0]; } + +sub do_cmd_e{ '&#92;' . $_[0]; } + +$DEVELOPER_ADDRESS = ''; +$SHORT_VERSION = ''; +$RELEASE_INFO = ''; +$PACKAGE_VERSION = ''; + +sub do_cmd_version{ $PACKAGE_VERSION . $_[0]; } +sub do_cmd_shortversion{ $SHORT_VERSION . $_[0]; } +sub do_cmd_release{ + local($_) = @_; + $PACKAGE_VERSION = next_argument(); + return $_; +} + +sub do_cmd_setreleaseinfo{ + local($_) = @_; + $RELEASE_INFO = next_argument(); + return $_; +} + +sub do_cmd_setshortversion{ + local($_) = @_; + $SHORT_VERSION = next_argument(); + return $_; +} + +sub do_cmd_authoraddress{ + local($_) = @_; + $DEVELOPER_ADDRESS = next_argument(); + return $_; +} + +sub do_cmd_hackscore{ + local($_) = @_; + next_argument(); + return '_' . $_; +} + +# Helper used in many places that arbitrary code-like text appears: + +sub codetext($){ + my $text = "$_[0]"; + # Make sure that "---" is not converted to "--" later when + # LaTeX2HTML tries converting em-dashes based on the conventional + # TeX font ligatures: + $text =~ s/--/-\&#45;/go; + return $text; +} + +sub use_wrappers($$$){ + local($_,$before,$after) = @_; + my $stuff = next_argument(); + return $before . $stuff . $after . $_; +} + +sub use_code_wrappers($$$){ + local($_,$before,$after) = @_; + my $stuff = codetext(next_argument()); + return $before . $stuff . $after . $_; +} + +$IN_DESC_HANDLER = 0; +sub do_cmd_optional{ + if ($IN_DESC_HANDLER) { + return use_wrappers($_[0], "</var><big>\[</big><var>", + "</var><big>\]</big><var>"); + } + else { + return use_wrappers($_[0], "<big>\[</big>", "<big>\]</big>"); + } +} + +# Logical formatting (some based on texinfo), needs to be converted to +# minimalist HTML. The "minimalist" is primarily to reduce the size of +# output files for users that read them over the network rather than +# from local repositories. + +sub do_cmd_pytype{ return $_[0]; } +sub do_cmd_makevar{ + return use_wrappers($_[0], '<span class="makevar">', '</span>'); } +sub do_cmd_code{ + return use_code_wrappers($_[0], '<code>', '</code>'); } +sub do_cmd_module{ + return use_wrappers($_[0], '<tt class="module">', '</tt>'); } +sub do_cmd_keyword{ + return use_wrappers($_[0], '<tt class="keyword">', '</tt>'); } +sub do_cmd_exception{ + return use_wrappers($_[0], '<tt class="exception">', '</tt>'); } +sub do_cmd_class{ + return use_wrappers($_[0], '<tt class="class">', '</tt>'); } +sub do_cmd_function{ + return use_wrappers($_[0], '<tt class="function">', '</tt>'); } +sub do_cmd_constant{ + return use_wrappers($_[0], '<tt class="constant">', '</tt>'); } +sub do_cmd_member{ + return use_wrappers($_[0], '<tt class="member">', '</tt>'); } +sub do_cmd_method{ + return use_wrappers($_[0], '<tt class="method">', '</tt>'); } +sub do_cmd_cfunction{ + return use_wrappers($_[0], '<tt class="cfunction">', '</tt>'); } +sub do_cmd_cdata{ + return use_wrappers($_[0], '<tt class="cdata">', '</tt>'); } +sub do_cmd_ctype{ + return use_wrappers($_[0], '<tt class="ctype">', '</tt>'); } +sub do_cmd_regexp{ + return use_code_wrappers($_[0], '<tt class="regexp">', '</tt>'); } +sub do_cmd_character{ + return use_code_wrappers($_[0], '"<tt class="character">', '</tt>"'); } +sub do_cmd_program{ + return use_wrappers($_[0], '<b class="program">', '</b>'); } +sub do_cmd_programopt{ + return use_wrappers($_[0], '<b class="programopt">', '</b>'); } +sub do_cmd_longprogramopt{ + # note that the --- will be later converted to -- by LaTeX2HTML + return use_wrappers($_[0], '<b class="programopt">---', '</b>'); } +sub do_cmd_email{ + return use_wrappers($_[0], '<span class="email">', '</span>'); } +sub do_cmd_mailheader{ + return use_wrappers($_[0], '<span class="mailheader">', ':</span>'); } +sub do_cmd_mimetype{ + return use_wrappers($_[0], '<span class="mimetype">', '</span>'); } +sub do_cmd_var{ + return use_wrappers($_[0], "<var>", "</var>"); } +sub do_cmd_dfn{ + return use_wrappers($_[0], '<i class="dfn">', '</i>'); } +sub do_cmd_emph{ + return use_wrappers($_[0], '<em>', '</em>'); } +sub do_cmd_file{ + return use_wrappers($_[0], '<span class="file">', '</span>'); } +sub do_cmd_filenq{ + return do_cmd_file($_[0]); } +sub do_cmd_samp{ + return use_code_wrappers($_[0], '"<tt class="samp">', '</tt>"'); } +sub do_cmd_kbd{ + return use_wrappers($_[0], '<kbd>', '</kbd>'); } +sub do_cmd_strong{ + return use_wrappers($_[0], '<strong>', '</strong>'); } +sub do_cmd_textbf{ + return use_wrappers($_[0], '<b>', '</b>'); } +sub do_cmd_textit{ + return use_wrappers($_[0], '<i>', '</i>'); } +# This can be changed/overridden for translations: +%NoticeNames = ('note' => 'Note:', + 'warning' => 'Warning:', + ); + +sub do_cmd_note{ + my $label = $NoticeNames{'note'}; + return use_wrappers( + $_[0], + "<span class=\"note\"><b class=\"label\">$label</b>\n", + '</span>'); } +sub do_cmd_warning{ + my $label = $NoticeNames{'warning'}; + return use_wrappers( + $_[0], + "<span class=\"warning\"><b class=\"label\">$label</b>\n", + '</span>'); } + +sub do_env_notice{ + local($_) = @_; + my $notice = next_optional_argument(); + if (!$notice) { + $notice = 'note'; + } + my $label = $NoticeNames{$notice}; + return ("<div class=\"$notice\"><b class=\"label\">$label</b>\n" + . $_ + . '</div>'); +} + +sub do_cmd_moreargs{ + return '...' . $_[0]; } +sub do_cmd_unspecified{ + return '...' . $_[0]; } + + +sub do_cmd_refmodule{ + # Insert the right magic to jump to the module definition. + local($_) = @_; + my $key = next_optional_argument(); + my $module = next_argument(); + $key = $module + unless $key; + return "<tt class=\"module\"><a href=\"module-$key.html\">$module</a></tt>" + . $_; +} + +sub do_cmd_newsgroup{ + local($_) = @_; + my $newsgroup = next_argument(); + my $icon = get_link_icon("news:$newsgroup"); + my $stuff = ("<a class=\"newsgroup\" href=\"news:$newsgroup\">" + . "$newsgroup$icon</a>"); + return $stuff . $_; +} + +sub do_cmd_envvar{ + local($_) = @_; + my $envvar = next_argument(); + my($name, $aname, $ahref) = new_link_info(); + # The <tt> here is really to keep buildindex.py from making + # the variable name case-insensitive. + add_index_entry("environment variables!$envvar@<tt>$envvar</tt>", + $ahref); + add_index_entry("$envvar (environment variable)", $ahref); + $aname =~ s/<a/<a class="envvar"/; + return "$aname$envvar</a>" . $_; +} + +sub do_cmd_url{ + # use the URL as both text and hyperlink + local($_) = @_; + my $url = next_argument(); + my $icon = get_link_icon($url); + $url =~ s/~/&#126;/g; + return "<a class=\"url\" href=\"$url\">$url$icon</a>" . $_; +} + +sub do_cmd_manpage{ + # two parameters: \manpage{name}{section} + local($_) = @_; + my $page = next_argument(); + my $section = next_argument(); + return "<span class=\"manpage\"><i>$page</i>($section)</span>" . $_; +} + +$PEP_FORMAT = "http://www.python.org/peps/pep-%04d.html"; +#$RFC_FORMAT = "http://www.ietf.org/rfc/rfc%04d.txt"; +$RFC_FORMAT = "http://www.faqs.org/rfcs/rfc%d.html"; + +sub get_rfc_url($$){ + my($rfcnum, $format) = @_; + return sprintf($format, $rfcnum); +} + +sub do_cmd_pep{ + local($_) = @_; + my $rfcnumber = next_argument(); + my $id = "rfcref-" . ++$global{'max_id'}; + my $href = get_rfc_url($rfcnumber, $PEP_FORMAT); + my $icon = get_link_icon($href); + # Save the reference + my $nstr = gen_index_id("Python Enhancement Proposals!PEP $rfcnumber", ''); + $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); + return ("<a class=\"rfc\" id='$id' xml:id='$id'\n" + . "href=\"$href\">PEP $rfcnumber$icon</a>" . $_); +} + +sub do_cmd_rfc{ + local($_) = @_; + my $rfcnumber = next_argument(); + my $id = "rfcref-" . ++$global{'max_id'}; + my $href = get_rfc_url($rfcnumber, $RFC_FORMAT); + my $icon = get_link_icon($href); + # Save the reference + my $nstr = gen_index_id("RFC!RFC $rfcnumber", ''); + $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); + return ("<a class=\"rfc\" id='$id' xml:id='$id'\nhref=\"$href\">" + . "RFC $rfcnumber$icon</a>" . $_); +} + +sub do_cmd_ulink{ + local($_) = @_; + my $text = next_argument(); + my $url = next_argument(); + return "<a class=\"ulink\" href=\"$url\"\n >$text</a>" . $_; +} + +sub do_cmd_citetitle{ + local($_) = @_; + my $url = next_optional_argument(); + my $title = next_argument(); + my $icon = get_link_icon($url); + my $repl = ''; + if ($url) { + my $titletext = strip_html_markup("$title"); + $repl = ("<em class=\"citetitle\"><a\n" + . " href=\"$url\"\n" + . " title=\"$titletext\"\n" + . " >$title$icon</a></em>"); + } + else { + $repl = "<em class=\"citetitle\"\n >$title</em>"; + } + return $repl . $_; +} + +sub do_cmd_deprecated{ + # two parameters: \deprecated{version}{whattodo} + local($_) = @_; + my $release = next_argument(); + my $reason = next_argument(); + return ('<div class="versionnote">' + . "<b>Deprecated since release $release.</b>" + . "\n$reason</div><p></p>" + . $_); +} + +sub versionnote($$){ + # one or two parameters: \versionnote[explanation]{version} + my $type = $_[0]; + local $_ = $_[1]; + my $explanation = next_optional_argument(); + my $release = next_argument(); + my $text = "$type in version $release."; + if ($explanation) { + $text = "$type in version $release:\n$explanation."; + } + return "\n<span class=\"versionnote\">$text</span>\n" . $_; +} + +sub do_cmd_versionadded{ + return versionnote('New', $_[0]); +} + +sub do_cmd_versionchanged{ + return versionnote('Changed', $_[0]); +} + +# +# These function handle platform dependency tracking. +# +sub do_cmd_platform{ + local($_) = @_; + my $platform = next_argument(); + $ModulePlatforms{"<tt class=\"module\">$THIS_MODULE</tt>"} = $platform; + $platform = "Macintosh" + if $platform eq 'Mac'; + return "\n<p class=\"availability\">Availability: <span" + . "\n class=\"platform\">$platform</span>.</p>\n" . $_; +} + +$IGNORE_PLATFORM_ANNOTATION = ''; +sub do_cmd_ignorePlatformAnnotation{ + local($_) = @_; + $IGNORE_PLATFORM_ANNOTATION = next_argument(); + return $_; +} + + +# index commands + +$INDEX_SUBITEM = ""; + +sub get_indexsubitem(){ + return $INDEX_SUBITEM ? " $INDEX_SUBITEM" : ''; +} + +sub do_cmd_setindexsubitem{ + local($_) = @_; + $INDEX_SUBITEM = next_argument(); + return $_; +} + +sub do_cmd_withsubitem{ + # We can't really do the right thing, because LaTeX2HTML doesn't + # do things in the right order, but we need to at least strip this stuff + # out, and leave anything that the second argument expanded out to. + # + local($_) = @_; + my $oldsubitem = $INDEX_SUBITEM; + $INDEX_SUBITEM = next_argument(); + my $stuff = next_argument(); + my $br_id = ++$globals{'max_id'}; + my $marker = "$O$br_id$C"; + $stuff =~ s/^\s+//; + return + $stuff + . "\\setindexsubitem$marker$oldsubitem$marker" + . $_; +} + +# This is the prologue macro which is required to start writing the +# mod\jobname.idx file; we can just ignore it. (Defining this suppresses +# a warning that \makemodindex is unknown.) +# +sub do_cmd_makemodindex{ return $_[0]; } + +# We're in the document subdirectory when this happens! +# +open(IDXFILE, '>index.dat') || die "\n$!\n"; +open(INTLABELS, '>intlabels.pl') || die "\n$!\n"; +print INTLABELS "%internal_labels = ();\n"; +print INTLABELS "1; # hack in case there are no entries\n\n"; + +# Using \0 for this is bad because we can't use common tools to work with the +# resulting files. Things like grep can be useful with this stuff! +# +$IDXFILE_FIELD_SEP = "\1"; + +sub write_idxfile($$){ + my($ahref, $str) = @_; + print IDXFILE $ahref, $IDXFILE_FIELD_SEP, $str, "\n"; +} + + +sub gen_link($$){ + my($node, $target) = @_; + print INTLABELS "\$internal_labels{\"$target\"} = \"/$node\";\n"; + return "<a href=\"$node#$target\">"; +} + +sub add_index_entry($$){ + # add an entry to the index structures; ignore the return value + my($str, $ahref) = @_; + $str = gen_index_id($str, ''); + $index{$str} .= $ahref; + write_idxfile($ahref, $str); +} + +sub new_link_name_info(){ + my $name = "l2h-" . ++$globals{'max_id'}; + my $ahref = gen_link($CURRENT_FILE, $name); + return ($name, $ahref); +} + +sub new_link_info(){ + my($name, $ahref) = new_link_name_info(); + my $aname = "<a id='$name' xml:id='$name'>"; + return ($name, $aname, $ahref); +} + +$IndexMacroPattern = ''; +sub define_indexing_macro(@){ + my $count = @_; + my $i = 0; + for (; $i < $count; ++$i) { + my $name = $_[$i]; + my $cmd = "idx_cmd_$name"; + die "\nNo function $cmd() defined!\n" + if (!defined &$cmd); + eval ("sub do_cmd_$name { return process_index_macros(" + . "\$_[0], '$name'); }"); + if (length($IndexMacroPattern) == 0) { + $IndexMacroPattern = "$name"; + } + else { + $IndexMacroPattern .= "|$name"; + } + } +} + +$DEBUG_INDEXING = 0; +sub process_index_macros($$){ + local($_) = @_; + my $cmdname = $_[1]; # This is what triggered us in the first place; + # we know it's real, so just process it. + my($name, $aname, $ahref) = new_link_info(); + my $cmd = "idx_cmd_$cmdname"; + print "\nIndexing: \\$cmdname" + if $DEBUG_INDEXING; + &$cmd($ahref); # modifies $_ and adds index entries + while (/^[\s\n]*\\($IndexMacroPattern)</) { + $cmdname = "$1"; + print " \\$cmdname" + if $DEBUG_INDEXING; + $cmd = "idx_cmd_$cmdname"; + if (!defined &$cmd) { + last; + } + else { + s/^[\s\n]*\\$cmdname//; + &$cmd($ahref); + } + } +# XXX I don't remember why I added this to begin with. +# if (/^[ \t\r\n]/) { +# $_ = substr($_, 1); +# } + return "$aname$anchor_invisible_mark</a>" . $_; +} + +define_indexing_macro('index'); +sub idx_cmd_index($){ + my $str = next_argument(); + add_index_entry("$str", $_[0]); +} + +define_indexing_macro('kwindex'); +sub idx_cmd_kwindex($){ + my $str = next_argument(); + add_index_entry("<tt>$str</tt>!keyword", $_[0]); + add_index_entry("keyword!<tt>$str</tt>", $_[0]); +} + +define_indexing_macro('indexii'); +sub idx_cmd_indexii($){ + my $str1 = next_argument(); + my $str2 = next_argument(); + add_index_entry("$str1!$str2", $_[0]); + add_index_entry("$str2!$str1", $_[0]); +} + +define_indexing_macro('indexiii'); +sub idx_cmd_indexiii($){ + my $str1 = next_argument(); + my $str2 = next_argument(); + my $str3 = next_argument(); + add_index_entry("$str1!$str2 $str3", $_[0]); + add_index_entry("$str2!$str3, $str1", $_[0]); + add_index_entry("$str3!$str1 $str2", $_[0]); +} + +define_indexing_macro('indexiv'); +sub idx_cmd_indexiv($){ + my $str1 = next_argument(); + my $str2 = next_argument(); + my $str3 = next_argument(); + my $str4 = next_argument(); + add_index_entry("$str1!$str2 $str3 $str4", $_[0]); + add_index_entry("$str2!$str3 $str4, $str1", $_[0]); + add_index_entry("$str3!$str4, $str1 $str2", $_[0]); + add_index_entry("$str4!$str1 $str2 $str3", $_[0]); +} + +define_indexing_macro('ttindex'); +sub idx_cmd_ttindex($){ + my $str = codetext(next_argument()); + my $entry = $str . get_indexsubitem(); + add_index_entry($entry, $_[0]); +} + +sub my_typed_index_helper($$){ + my($word, $ahref) = @_; + my $str = next_argument(); + add_index_entry("$str $word", $ahref); + add_index_entry("$word!$str", $ahref); +} + +define_indexing_macro('stindex', 'opindex', 'exindex', 'obindex'); +sub idx_cmd_stindex($){ my_typed_index_helper('statement', $_[0]); } +sub idx_cmd_opindex($){ my_typed_index_helper('operator', $_[0]); } +sub idx_cmd_exindex($){ my_typed_index_helper('exception', $_[0]); } +sub idx_cmd_obindex($){ my_typed_index_helper('object', $_[0]); } + +define_indexing_macro('bifuncindex'); +sub idx_cmd_bifuncindex($){ + my $str = next_argument(); + add_index_entry("<tt class=\"function\">$str()</tt> (built-in function)", + $_[0]); +} + + +sub make_mod_index_entry($$){ + my($str, $define) = @_; + my($name, $aname, $ahref) = new_link_info(); + # equivalent of add_index_entry() using $define instead of '' + $ahref =~ s/\#[-_a-zA-Z0-9]*\"/\"/ + if ($define eq 'DEF'); + $str = gen_index_id($str, $define); + $index{$str} .= $ahref; + write_idxfile($ahref, $str); + + if ($define eq 'DEF') { + # add to the module index + $str =~ /(<tt.*<\/tt>)/; + my $nstr = $1; + $Modules{$nstr} .= $ahref; + } + return "$aname$anchor_invisible_mark2</a>"; +} + + +$THIS_MODULE = ''; +$THIS_CLASS = ''; + +sub define_module($$){ + my($word, $name) = @_; + my $section_tag = join('', @curr_sec_id); + if ($word ne "built-in" && $word ne "extension" + && $word ne "standard" && $word ne "") { + write_warnings("Bad module type '$word'" + . " for \\declaremodule (module $name)"); + $word = ""; + } + $word = "$word " if $word; + $THIS_MODULE = "$name"; + $INDEX_SUBITEM = "(in module $name)"; + print "[$name]"; + return make_mod_index_entry( + "<tt class=\"module\">$name</tt> (${word}module)", 'DEF'); +} + +sub my_module_index_helper($$){ + local($word, $_) = @_; + my $name = next_argument(); + return define_module($word, $name) . $_; +} + +sub do_cmd_modindex{ return my_module_index_helper('', $_[0]); } +sub do_cmd_bimodindex{ return my_module_index_helper('built-in', $_[0]); } +sub do_cmd_exmodindex{ return my_module_index_helper('extension', $_[0]); } +sub do_cmd_stmodindex{ return my_module_index_helper('standard', $_[0]); } +# local($_) = @_; +# my $name = next_argument(); +# return define_module('standard', $name) . $_; +# } + +sub ref_module_index_helper($$){ + my($word, $ahref) = @_; + my $str = next_argument(); + $word = "$word " if $word; + $str = "<tt class=\"module\">$str</tt> (${word}module)"; + # can't use add_index_entry() since the 2nd arg to gen_index_id() is used; + # just inline it all here + $str = gen_index_id($str, 'REF'); + $index{$str} .= $ahref; + write_idxfile($ahref, $str); +} + +# these should be adjusted a bit.... +define_indexing_macro('refmodindex', 'refbimodindex', + 'refexmodindex', 'refstmodindex'); +sub idx_cmd_refmodindex($){ + return ref_module_index_helper('', $_[0]); } +sub idx_cmd_refbimodindex($){ + return ref_module_index_helper('built-in', $_[0]); } +sub idx_cmd_refexmodindex($){ + return ref_module_index_helper('extension', $_[0]);} +sub idx_cmd_refstmodindex($){ + return ref_module_index_helper('standard', $_[0]); } + +sub do_cmd_nodename{ return do_cmd_label($_[0]); } + +sub init_myformat(){ + # This depends on the override of text_cleanup() in l2hinit.perl; + # if that function cleans out empty tags, the first three of these + # variables must be set to comments. + # + # Thanks to Dave Kuhlman for figuring why some named anchors were + # being lost. + $anchor_invisible_mark = ''; + $anchor_invisible_mark2 = ''; + $anchor_mark = ''; + $icons{'anchor_mark'} = ''; +} +init_myformat(); + +# Create an index entry, but include the string in the target anchor +# instead of the dummy filler. +# +sub make_str_index_entry($){ + my $str = $_[0]; + my($name, $ahref) = new_link_name_info(); + add_index_entry($str, $ahref); + if ($str =~ /^<[a-z]+\b/) { + my $s = "$str"; + $s =~ s/^<([a-z]+)\b/<$1 id='$name' xml:id='$name'/; + return $s; + } + else { + return "<a id='$name' xml:id='$name'>$str</a>"; + } +} + + +%TokenToTargetMapping = (); # language:token -> link target +%DefinedGrammars = (); # language -> full grammar text +%BackpatchGrammarFiles = (); # file -> 1 (hash of files to fixup) + +sub do_cmd_token{ + local($_) = @_; + my $token = next_argument(); + my $target = $TokenToTargetMapping{"$CURRENT_GRAMMAR:$token"}; + if ($token eq $CURRENT_TOKEN || $CURRENT_GRAMMAR eq '*') { + # recursive definition or display-only productionlist + return "$token"; + } + if ($target eq '') { + $target = "<pyGrammarToken><$CURRENT_GRAMMAR><$token>"; + if (! $BackpatchGrammarFiles{"$CURRENT_FILE"}) { + print "Adding '$CURRENT_FILE' to back-patch list.\n"; + } + $BackpatchGrammarFiles{"$CURRENT_FILE"} = 1; + } + return "<a class='grammartoken' href=\"$target\">$token</a>" . $_; +} + +sub do_cmd_grammartoken{ + return do_cmd_token(@_); +} + +sub do_env_productionlist{ + local($_) = @_; + my $lang = next_optional_argument(); + my $filename = "grammar-$lang.txt"; + if ($lang eq '') { + $filename = 'grammar.txt'; + } + local($CURRENT_GRAMMAR) = $lang; + $DefinedGrammars{$lang} .= $_; + return ("<dl><dd class=\"grammar\">\n" + . "<div class=\"productions\">\n" + . "<table>\n" + . translate_commands(translate_environments($_)) + . "</table>\n" + . "</div>\n" + . (($lang eq '*') + ? '' + : ("<a class=\"grammar-footer\"\n" + . " href=\"$filename\" type=\"text/plain\"\n" + . " >Download entire grammar as text.</a>\n")) + . "</dd></dl>"); +} + +sub do_cmd_production{ + local($_) = @_; + my $token = next_argument(); + my $defn = next_argument(); + my $lang = $CURRENT_GRAMMAR; + local($CURRENT_TOKEN) = $token; + if ($lang eq '*') { + return ("<tr>\n" + . " <td>$token</td>\n" + . " <td>::=</td>\n" + . " <td>" + . translate_commands($defn) + . "</td></tr>" + . $_); + } + my $target; + if ($lang eq '') { + $target = "$CURRENT_FILE\#tok-$token"; + } + else { + $target = "$CURRENT_FILE\#tok-$lang-$token"; + } + $TokenToTargetMapping{"$CURRENT_GRAMMAR:$token"} = $target; + return ("<tr>\n" + . " <td><a id='tok-$token' xml:id='tok-$token'>" + . "$token</a></td>\n" + . " <td>::=</td>\n" + . " <td>" + . translate_commands($defn) + . "</td></tr>" + . $_); +} + +sub do_cmd_productioncont{ + local($_) = @_; + my $defn = next_argument(); + $defn =~ s/^( +)/'&nbsp;' x length $1/e; + return ("<tr>\n" + . " <td></td>\n" + . " <td></td>\n" + . " <td><code>" + . translate_commands($defn) + . "</code></td></tr>" + . $_); +} + +sub process_grammar_files(){ + my $lang; + my $filename; + local($_); + print "process_grammar_files()\n"; + foreach $lang (keys %DefinedGrammars) { + $filename = "grammar-$lang.txt"; + if ($lang eq '*') { + next; + } + if ($lang eq '') { + $filename = 'grammar.txt'; + } + open(GRAMMAR, ">$filename") || die "\n$!\n"; + print GRAMMAR strip_grammar_markup($DefinedGrammars{$lang}); + close(GRAMMAR); + print "Wrote grammar file $filename\n"; + } + my $PATTERN = '<pyGrammarToken><([^>]*)><([^>]*)>'; + foreach $filename (keys %BackpatchGrammarFiles) { + print "\nBack-patching grammar links in $filename\n"; + my $buffer; + open(GRAMMAR, "<$filename") || die "\n$!\n"; + # read all of the file into the buffer + sysread(GRAMMAR, $buffer, 1024*1024); + close(GRAMMAR); + while ($buffer =~ /$PATTERN/) { + my($lang, $token) = ($1, $2); + my $target = $TokenToTargetMapping{"$lang:$token"}; + my $source = "<pyGrammarToken><$lang><$token>"; + $buffer =~ s/$source/$target/g; + } + open(GRAMMAR, ">$filename") || die "\n$!\n"; + print GRAMMAR $buffer; + close(GRAMMAR); + } +} + +sub strip_grammar_markup($){ + local($_) = @_; + s/\\productioncont/ /g; + s/\\production(<<\d+>>)(.+)\1/\n$2 ::= /g; + s/\\token(<<\d+>>)(.+)\1/$2/g; + s/\\e([^a-zA-Z])/\\$1/g; + s/<<\d+>>//g; + s/;SPMgt;/>/g; + s/;SPMlt;/</g; + s/;SPMquot;/\"/g; + return $_; +} + + +$REFCOUNTS_LOADED = 0; + +sub load_refcounts(){ + $REFCOUNTS_LOADED = 1; + + my($myname, $mydir, $myext) = fileparse(__FILE__, '\..*'); + chop $mydir; # remove trailing '/' + ($myname, $mydir, $myext) = fileparse($mydir, '\..*'); + chop $mydir; # remove trailing '/' + $mydir = getcwd() . "$dd$mydir" + unless $mydir =~ s|^/|/|; + local $_; + my $filename = "$mydir${dd}api${dd}refcounts.dat"; + open(REFCOUNT_FILE, "<$filename") || die "\n$!\n"; + print "[loading API refcount data]"; + while (<REFCOUNT_FILE>) { + if (/([a-zA-Z0-9_]+):PyObject\*:([a-zA-Z0-9_]*):(0|[-+]1|null):(.*)$/) { + my($func, $param, $count, $comment) = ($1, $2, $3, $4); + #print "\n$func($param) --> $count"; + $REFCOUNTS{"$func:$param"} = $count; + } + } +} + +sub get_refcount($$){ + my($func, $param) = @_; + load_refcounts() + unless $REFCOUNTS_LOADED; + return $REFCOUNTS{"$func:$param"}; +} + + +$TLSTART = '<span class="typelabel">'; +$TLEND = '</span>&nbsp;'; + +sub cfuncline_helper($$$){ + my($type, $name, $args) = @_; + my $idx = make_str_index_entry( + "<tt class=\"cfunction\">$name()</tt>" . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; # ???? - why both of these? + $args =~ s/(\s|\*)([a-z_][a-z_0-9]*),/$1<var>$2<\/var>,/g; + $args =~ s/(\s|\*)([a-z_][a-z_0-9]*)$/$1<var>$2<\/var>/s; + return ('<table cellpadding="0" cellspacing="0"><tr valign="baseline">' + . "<td><nobr>$type\&nbsp;<b>$idx</b>(</nobr></td>" + . "<td>$args)</td>" + . '</tr></table>'); +} +sub do_cmd_cfuncline{ + local($_) = @_; + my $type = next_argument(); + my $name = next_argument(); + my $args = next_argument(); + my $siginfo = cfuncline_helper($type, $name, $args); + return "<dt>$siginfo\n<dd>" . $_; +} +sub do_env_cfuncdesc{ + local($_) = @_; + my $type = next_argument(); + my $name = next_argument(); + my $args = next_argument(); + my $siginfo = cfuncline_helper($type, $name, $args); + my $result_rc = get_refcount($name, ''); + my $rcinfo = ''; + if ($result_rc eq '+1') { + $rcinfo = 'New reference'; + } + elsif ($result_rc eq '0') { + $rcinfo = 'Borrowed reference'; + } + elsif ($result_rc eq 'null') { + $rcinfo = 'Always <tt class="constant">NULL</tt>'; + } + if ($rcinfo ne '') { + $rcinfo = ( "\n<div class=\"refcount-info\">" + . "\n <span class=\"label\">Return value:</span>" + . "\n <span class=\"value\">$rcinfo.</span>" + . "\n</div>"); + } + return "<dl><dt>$siginfo</dt>\n<dd>" + . $rcinfo + . $_ + . '</dd></dl>'; +} + +sub do_cmd_cmemberline{ + local($_) = @_; + my $container = next_argument(); + my $type = next_argument(); + my $name = next_argument(); + my $idx = make_str_index_entry("<tt class=\"cmember\">$name</tt>" + . " ($container member)"); + $idx =~ s/ \(.*\)//; + return "<dt>$type <b>$idx</b></dt>\n<dd>" + . $_; +} +sub do_env_cmemberdesc{ + local($_) = @_; + my $container = next_argument(); + my $type = next_argument(); + my $name = next_argument(); + my $idx = make_str_index_entry("<tt class=\"cmember\">$name</tt>" + . " ($container member)"); + $idx =~ s/ \(.*\)//; + return "<dl><dt>$type <b>$idx</b></dt>\n<dd>" + . $_ + . '</dl>'; +} + +sub do_env_csimplemacrodesc{ + local($_) = @_; + my $name = next_argument(); + my $idx = make_str_index_entry("<tt class=\"macro\">$name</tt>"); + return "<dl><dt><b>$idx</b></dt>\n<dd>" + . $_ + . '</dl>' +} + +sub do_env_ctypedesc{ + local($_) = @_; + my $index_name = next_optional_argument(); + my $type_name = next_argument(); + $index_name = $type_name + unless $index_name; + my($name, $aname, $ahref) = new_link_info(); + add_index_entry("<tt class=\"ctype\">$index_name</tt> (C type)", $ahref); + return "<dl><dt><b><tt class=\"ctype\">$aname$type_name</a></tt></b></dt>" + . "\n<dd>" + . $_ + . '</dl>' +} + +sub do_env_cvardesc{ + local($_) = @_; + my $var_type = next_argument(); + my $var_name = next_argument(); + my $idx = make_str_index_entry("<tt class=\"cdata\">$var_name</tt>" + . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + return "<dl><dt>$var_type <b>$idx</b></dt>\n" + . '<dd>' + . $_ + . '</dd></dl>'; +} + +sub convert_args($){ + local($IN_DESC_HANDLER) = 1; + local($_) = @_; + return translate_commands($_); +} + +sub funcline_helper($$$){ + my($first, $idxitem, $arglist) = @_; + return (($first ? '<dl>' : '') + . '<dt><table cellpadding="0" cellspacing="0"><tr valign="baseline">' + . "\n <td><nobr><b>$idxitem</b>(</nobr></td>" + . "\n <td><var>$arglist</var>)</td></tr></table></dt>\n<dd>"); +} + +sub do_env_funcdesc{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + my $idx = make_str_index_entry("<tt class=\"function\">$function_name()" + . '</tt>' + . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)<\/tt>/<\/tt>/; + return funcline_helper(1, $idx, $arg_list) . $_ . '</dl>'; +} + +sub do_env_funcdescni{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + my $prefix = "<tt class=\"function\">$function_name</tt>"; + return funcline_helper(1, $prefix, $arg_list) . $_ . '</dl>'; +} + +sub do_cmd_funcline{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + my $prefix = "<tt class=\"function\">$function_name()</tt>"; + my $idx = make_str_index_entry($prefix . get_indexsubitem()); + $prefix =~ s/\(\)//; + + return funcline_helper(0, $prefix, $arg_list) . $_; +} + +sub do_cmd_funclineni{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + my $prefix = "<tt class=\"function\">$function_name</tt>"; + + return funcline_helper(0, $prefix, $arg_list) . $_; +} + +# Change this flag to index the opcode entries. I don't think it's very +# useful to index them, since they're only presented to describe the dis +# module. +# +$INDEX_OPCODES = 0; + +sub do_env_opcodedesc{ + local($_) = @_; + my $opcode_name = next_argument(); + my $arg_list = next_argument(); + my $idx; + if ($INDEX_OPCODES) { + $idx = make_str_index_entry("<tt class=\"opcode\">$opcode_name</tt>" + . ' (byte code instruction)'); + $idx =~ s/ \(byte code instruction\)//; + } + else { + $idx = "<tt class=\"opcode\">$opcode_name</tt>"; + } + my $stuff = "<dl><dt><b>$idx</b>"; + if ($arg_list) { + $stuff .= "&nbsp;&nbsp;&nbsp;&nbsp;<var>$arg_list</var>"; + } + return $stuff . "</dt>\n<dd>" . $_ . '</dt></dl>'; +} + +sub do_env_datadesc{ + local($_) = @_; + my $dataname = next_argument(); + my $idx = make_str_index_entry("<tt>$dataname</tt>" . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + return "<dl><dt><b>$idx</b></dt>\n<dd>" + . $_ + . '</dd></dl>'; +} + +sub do_env_datadescni{ + local($_) = @_; + my $idx = next_argument(); + if (! $STRING_INDEX_TT) { + $idx = "<tt>$idx</tt>"; + } + return "<dl><dt><b>$idx</b></dt>\n<dd>" . $_ . '</dd></dl>'; +} + +sub do_cmd_dataline{ + local($_) = @_; + my $data_name = next_argument(); + my $idx = make_str_index_entry("<tt>$data_name</tt>" . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + return "<dt><b>$idx</b></dt><dd>" . $_; +} + +sub do_cmd_datalineni{ + local($_) = @_; + my $data_name = next_argument(); + return "<dt><b><tt>$data_name</tt></b></dt><dd>" . $_; +} + +sub do_env_excdesc{ + local($_) = @_; + my $excname = next_argument(); + my $idx = make_str_index_entry("<tt class=\"exception\">$excname</tt>"); + return ("<dl><dt><b>${TLSTART}exception$TLEND$idx</b></dt>" + . "\n<dd>" + . $_ + . '</dd></dl>'); +} + +sub do_env_fulllineitems{ return do_env_itemize(@_); } + + +sub handle_classlike_descriptor($$){ + local($_, $what) = @_; + $THIS_CLASS = next_argument(); + my $arg_list = convert_args(next_argument()); + $idx = make_str_index_entry( + "<tt class=\"$what\">$THIS_CLASS</tt> ($what in $THIS_MODULE)" ); + $idx =~ s/ \(.*\)//; + my $prefix = "$TLSTART$what$TLEND$idx"; + return funcline_helper(1, $prefix, $arg_list) . $_ . '</dl>'; +} + +sub do_env_classdesc{ + return handle_classlike_descriptor($_[0], "class"); +} + +sub do_env_classdescstar{ + local($_) = @_; + $THIS_CLASS = next_argument(); + $idx = make_str_index_entry( + "<tt class=\"class\">$THIS_CLASS</tt> (class in $THIS_MODULE)"); + $idx =~ s/ \(.*\)//; + my $prefix = "${TLSTART}class$TLEND$idx"; + # Can't use funcline_helper() since there is no args list. + return "<dl><dt><b>$prefix</b>\n<dd>" . $_ . '</dl>'; +} + +sub do_env_excclassdesc{ + return handle_classlike_descriptor($_[0], "exception"); +} + + +sub do_env_methoddesc{ + local($_) = @_; + my $class_name = next_optional_argument(); + $class_name = $THIS_CLASS + unless $class_name; + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + my $extra = ''; + if ($class_name) { + $extra = " ($class_name method)"; + } + my $idx = make_str_index_entry( + "<tt class=\"method\">$method()</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return funcline_helper(1, $idx, $arg_list) . $_ . '</dl>'; +} + + +sub do_cmd_methodline{ + local($_) = @_; + my $class_name = next_optional_argument(); + $class_name = $THIS_CLASS + unless $class_name; + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + my $extra = ''; + if ($class_name) { + $extra = " ($class_name method)"; + } + my $idx = make_str_index_entry( + "<tt class=\"method\">$method()</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return funcline_helper(0, $idx, $arg_list) . $_; +} + + +sub do_cmd_methodlineni{ + local($_) = @_; + next_optional_argument(); + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + return funcline_helper(0, $method, $arg_list) . $_; +} + +sub do_env_methoddescni{ + local($_) = @_; + next_optional_argument(); + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + return funcline_helper(1, $method, $arg_list) . $_ . '</dl>'; +} + + +sub do_env_memberdesc{ + local($_) = @_; + my $class = next_optional_argument(); + my $member = next_argument(); + $class = $THIS_CLASS + unless $class; + my $extra = ''; + $extra = " ($class attribute)" + if ($class ne ''); + my $idx = make_str_index_entry("<tt class=\"member\">$member</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return "<dl><dt><b>$idx</b></dt>\n<dd>" . $_ . '</dl>'; +} + + +sub do_cmd_memberline{ + local($_) = @_; + my $class = next_optional_argument(); + my $member = next_argument(); + $class = $THIS_CLASS + unless $class; + my $extra = ''; + $extra = " ($class attribute)" + if ($class ne ''); + my $idx = make_str_index_entry("<tt class=\"member\">$member</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return "<dt><b>$idx</b></dt><dd>" . $_; +} + + +sub do_env_memberdescni{ + local($_) = @_; + next_optional_argument(); + my $member = next_argument(); + return "<dl><dt><b><tt class=\"member\">$member</tt></b></dt>\n<dd>" + . $_ + . '</dd></dl>'; +} + + +sub do_cmd_memberlineni{ + local($_) = @_; + next_optional_argument(); + my $member = next_argument(); + return "<dt><b><tt class=\"member\">$member</tt></b></dt>\n<dd>" . $_; +} + + +# For tables, we include a class on every cell to allow the CSS to set +# the text-align property; this is because support for styling columns +# via the <col> element appears nearly non-existant on even the latest +# browsers (Mozilla 1.7 is stable at the time of this writing). +# Hopefully this can be improved as browsers evolve. + +@col_aligns = ('<td>', '<td>', '<td>', '<td>', '<td>'); + +%FontConversions = ('cdata' => 'tt class="cdata"', + 'character' => 'tt class="character"', + 'class' => 'tt class="class"', + 'command' => 'code', + 'constant' => 'tt class="constant"', + 'exception' => 'tt class="exception"', + 'file' => 'tt class="file"', + 'filenq' => 'tt class="file"', + 'kbd' => 'kbd', + 'member' => 'tt class="member"', + 'programopt' => 'b', + 'textrm' => '', + ); + +sub fix_font($){ + # do a little magic on a font name to get the right behavior in the first + # column of the output table + my $font = $_[0]; + if (defined $FontConversions{$font}) { + $font = $FontConversions{$font}; + } + return $font; +} + +sub figure_column_alignment($){ + my $a = $_[0]; + if (!defined $a) { + return ''; + } + my $mark = substr($a, 0, 1); + my $r = ''; + if ($mark eq 'c') + { $r = ' class="center"'; } + elsif ($mark eq 'r') + { $r = ' class="right" '; } + elsif ($mark eq 'l') + { $r = ' class="left" '; } + elsif ($mark eq 'p') + { $r = ' class="left" '; } + return $r; +} + +sub setup_column_alignments($){ + local($_) = @_; + my($s1, $s2, $s3, $s4, $s5) = split(/[|]/,$_); + my $a1 = figure_column_alignment($s1); + my $a2 = figure_column_alignment($s2); + my $a3 = figure_column_alignment($s3); + my $a4 = figure_column_alignment($s4); + my $a5 = figure_column_alignment($s5); + $col_aligns[0] = "<td$a1 valign=\"baseline\">"; + $col_aligns[1] = "<td$a2>"; + $col_aligns[2] = "<td$a3>"; + $col_aligns[3] = "<td$a4>"; + $col_aligns[4] = "<td$a5>"; + # return the aligned header start tags + return ("<th$a1>", "<th$a2>", "<th$a3>", "<th$a4>", "<th$a5>"); +} + +sub get_table_col1_fonts(){ + my $font = $globals{'lineifont'}; + my($sfont, $efont) = ('', ''); + if ($font) { + $sfont = "<$font>"; + $efont = "</$font>"; + $efont =~ s/ .*>/>/; + } + return ($sfont, $efont); +} + +sub do_env_tableii{ + local($_) = @_; + my $arg = next_argument(); + my($th1, $th2, $th3, $th4, $th5) = setup_column_alignments($arg); + my $font = fix_font(next_argument()); + my $h1 = next_argument(); + my $h2 = next_argument(); + s/[\s\n]+//; + $globals{'lineifont'} = $font; + my $a1 = $col_aligns[0]; + my $a2 = $col_aligns[1]; + s/\\lineii</\\lineii[$a1|$a2]</g; + return '<div class="center"><table class="realtable">' + . "\n <thead>" + . "\n <tr>" + . "\n $th1$h1</th>" + . "\n $th2$h2</th>" + . "\n </tr>" + . "\n </thead>" + . "\n <tbody>" + . $_ + . "\n </tbody>" + . "\n</table></div>"; +} + +sub do_env_longtableii{ + return do_env_tableii(@_); +} + +sub do_cmd_lineii{ + local($_) = @_; + my $aligns = next_optional_argument(); + my $c1 = next_argument(); + my $c2 = next_argument(); + s/[\s\n]+//; + my($sfont, $efont) = get_table_col1_fonts(); + my($c1align, $c2align) = split('\|', $aligns); + return "\n <tr>$c1align$sfont$c1$efont</td>\n" + . " $c2align$c2</td></tr>" + . $_; +} + +sub do_env_tableiii{ + local($_) = @_; + my $arg = next_argument(); + my($th1, $th2, $th3, $th4, $th5) = setup_column_alignments($arg); + my $font = fix_font(next_argument()); + my $h1 = next_argument(); + my $h2 = next_argument(); + my $h3 = next_argument(); + s/[\s\n]+//; + $globals{'lineifont'} = $font; + my $a1 = $col_aligns[0]; + my $a2 = $col_aligns[1]; + my $a3 = $col_aligns[2]; + s/\\lineiii</\\lineiii[$a1|$a2|$a3]</g; + return '<div class="center"><table class="realtable">' + . "\n <thead>" + . "\n <tr>" + . "\n $th1$h1</th>" + . "\n $th2$h2</th>" + . "\n $th3$h3</th>" + . "\n </tr>" + . "\n </thead>" + . "\n <tbody>" + . $_ + . "\n </tbody>" + . "\n</table></div>"; +} + +sub do_env_longtableiii{ + return do_env_tableiii(@_); +} + +sub do_cmd_lineiii{ + local($_) = @_; + my $aligns = next_optional_argument(); + my $c1 = next_argument(); + my $c2 = next_argument(); + my $c3 = next_argument(); + s/[\s\n]+//; + my($sfont, $efont) = get_table_col1_fonts(); + my($c1align, $c2align, $c3align) = split('\|', $aligns); + return "\n <tr>$c1align$sfont$c1$efont</td>\n" + . " $c2align$c2</td>\n" + . " $c3align$c3</td></tr>" + . $_; +} + +sub do_env_tableiv{ + local($_) = @_; + my $arg = next_argument(); + my($th1, $th2, $th3, $th4, $th5) = setup_column_alignments($arg); + my $font = fix_font(next_argument()); + my $h1 = next_argument(); + my $h2 = next_argument(); + my $h3 = next_argument(); + my $h4 = next_argument(); + s/[\s\n]+//; + $globals{'lineifont'} = $font; + my $a1 = $col_aligns[0]; + my $a2 = $col_aligns[1]; + my $a3 = $col_aligns[2]; + my $a4 = $col_aligns[3]; + s/\\lineiv</\\lineiv[$a1|$a2|$a3|$a4]</g; + return '<div class="center"><table class="realtable">' + . "\n <thead>" + . "\n <tr>" + . "\n $th1$h1</th>" + . "\n $th2$h2</th>" + . "\n $th3$h3</th>" + . "\n $th4$h4</th>" + . "\n </tr>" + . "\n </thead>" + . "\n <tbody>" + . $_ + . "\n </tbody>" + . "\n</table></div>"; +} + +sub do_env_longtableiv{ + return do_env_tableiv(@_); +} + +sub do_cmd_lineiv{ + local($_) = @_; + my $aligns = next_optional_argument(); + my $c1 = next_argument(); + my $c2 = next_argument(); + my $c3 = next_argument(); + my $c4 = next_argument(); + s/[\s\n]+//; + my($sfont, $efont) = get_table_col1_fonts(); + my($c1align, $c2align, $c3align, $c4align) = split('\|', $aligns); + return "\n <tr>$c1align$sfont$c1$efont</td>\n" + . " $c2align$c2</td>\n" + . " $c3align$c3</td>\n" + . " $c4align$c4</td></tr>" + . $_; +} + +sub do_env_tablev{ + local($_) = @_; + my $arg = next_argument(); + my($th1, $th2, $th3, $th4, $th5) = setup_column_alignments($arg); + my $font = fix_font(next_argument()); + my $h1 = next_argument(); + my $h2 = next_argument(); + my $h3 = next_argument(); + my $h4 = next_argument(); + my $h5 = next_argument(); + s/[\s\n]+//; + $globals{'lineifont'} = $font; + my $a1 = $col_aligns[0]; + my $a2 = $col_aligns[1]; + my $a3 = $col_aligns[2]; + my $a4 = $col_aligns[3]; + my $a5 = $col_aligns[4]; + s/\\linev</\\linev[$a1|$a2|$a3|$a4|$a5]</g; + return '<div class="center"><table class="realtable">' + . "\n <thead>" + . "\n <tr>" + . "\n $th1$h1</th>" + . "\n $th2$h2</th>" + . "\n $th3$h3</th>" + . "\n $th4$h4</th>" + . "\n $th5$h5</th>" + . "\n </tr>" + . "\n </thead>" + . "\n <tbody>" + . $_ + . "\n </tbody>" + . "\n</table></div>"; +} + +sub do_env_longtablev{ + return do_env_tablev(@_); +} + +sub do_cmd_linev{ + local($_) = @_; + my $aligns = next_optional_argument(); + my $c1 = next_argument(); + my $c2 = next_argument(); + my $c3 = next_argument(); + my $c4 = next_argument(); + my $c5 = next_argument(); + s/[\s\n]+//; + my($sfont, $efont) = get_table_col1_fonts(); + my($c1align, $c2align, $c3align, $c4align, $c5align) = split('\|',$aligns); + return "\n <tr>$c1align$sfont$c1$efont</td>\n" + . " $c2align$c2</td>\n" + . " $c3align$c3</td>\n" + . " $c4align$c4</td>\n" + . " $c5align$c5</td></tr>" + . $_; +} + + +# These can be used to control the title page appearance; +# they need a little bit of documentation. +# +# If $TITLE_PAGE_GRAPHIC is set, it should be the name of a file in the +# $ICONSERVER directory, or include path information (other than "./"). The +# default image type will be assumed if an extension is not provided. +# +# If specified, the "title page" will contain two colums: one containing the +# title/author/etc., and the other containing the graphic. Use the other +# four variables listed here to control specific details of the layout; all +# are optional. +# +# $TITLE_PAGE_GRAPHIC = "my-company-logo"; +# $TITLE_PAGE_GRAPHIC_COLWIDTH = "30%"; +# $TITLE_PAGE_GRAPHIC_WIDTH = 150; +# $TITLE_PAGE_GRAPHIC_HEIGHT = 150; +# $TITLE_PAGE_GRAPHIC_ON_RIGHT = 0; + +sub make_my_titlepage(){ + my $the_title = ""; + if ($t_title) { + $the_title .= "\n<h1>$t_title</h1>"; + } + else { + write_warnings("\nThis document has no title."); + } + if ($t_author) { + if ($t_authorURL) { + my $href = translate_commands($t_authorURL); + $href = make_named_href('author', $href, + "<b><font size=\"+2\">$t_author" + . '</font></b>'); + $the_title .= "\n<p>$href</p>"; + } + else { + $the_title .= ("\n<p><b><font size=\"+2\">$t_author" + . '</font></b></p>'); + } + } + else { + write_warnings("\nThere is no author for this document."); + } + if ($t_institute) { + $the_title .= "\n<p>$t_institute</p>"; + } + if ($DEVELOPER_ADDRESS) { + $the_title .= "\n<p>$DEVELOPER_ADDRESS</p>"; + } + if ($t_affil) { + $the_title .= "\n<p><i>$t_affil</i></p>"; + } + if ($t_date) { + $the_title .= "\n<p>"; + if ($PACKAGE_VERSION) { + $the_title .= ('<strong>Release ' + . "$PACKAGE_VERSION$RELEASE_INFO</strong><br />\n"); + } + $the_title .= "<strong>$t_date</strong></p>" + } + if ($t_address) { + $the_title .= "\n<p>$t_address</p>"; + } + else { + $the_title .= "\n<p></p>"; + } + if ($t_email) { + $the_title .= "\n<p>$t_email</p>"; + } + return $the_title; +} + +sub make_my_titlegraphic(){ + my $filename = make_icon_filename($TITLE_PAGE_GRAPHIC); + my $graphic = "<td class=\"titlegraphic\""; + $graphic .= " width=\"$TITLE_PAGE_GRAPHIC_COLWIDTH\"" + if ($TITLE_PAGE_GRAPHIC_COLWIDTH); + $graphic .= "><img"; + $graphic .= " width=\"$TITLE_PAGE_GRAPHIC_WIDTH\"" + if ($TITLE_PAGE_GRAPHIC_WIDTH); + $graphic .= " height=\"$TITLE_PAGE_GRAPHIC_HEIGHT\"" + if ($TITLE_PAGE_GRAPHIC_HEIGHT); + $graphic .= "\n src=\"$filename\" /></td>\n"; + return $graphic; +} + +sub do_cmd_maketitle{ + local($_) = @_; + my $the_title = "\n"; + if ($EXTERNAL_UP_LINK) { + # This generates a <link> element in the wrong place (the + # body), but I don't see any other way to get this generated + # at all. Browsers like Mozilla, that support navigation + # links, can make use of this. + $the_title .= ("<link rel='up' href='$EXTERNAL_UP_LINK'" + . ($EXTERNAL_UP_TITLE + ? " title='$EXTERNAL_UP_TITLE'" : '') + . " />\n"); + } + $the_title .= '<div class="titlepage">'; + if ($TITLE_PAGE_GRAPHIC) { + if ($TITLE_PAGE_GRAPHIC_ON_RIGHT) { + $the_title .= ("\n<table border=\"0\" width=\"100%\">" + . "<tr align=\"right\">\n<td>" + . make_my_titlepage() + . "</td>\n" + . make_my_titlegraphic() + . "</tr>\n</table>"); + } + else { + $the_title .= ("\n<table border=\"0\" width=\"100%\"><tr>\n" + . make_my_titlegraphic() + . "<td>" + . make_my_titlepage() + . "</td></tr>\n</table>"); + } + } + else { + $the_title .= ("\n<div class='center'>" + . make_my_titlepage() + . "\n</div>"); + } + $the_title .= "\n</div>"; + return $the_title . $_; +} + + +# +# Module synopsis support +# + +require SynopsisTable; + +sub get_chapter_id(){ + my $id = do_cmd_thechapter(''); + $id =~ s/<SPAN CLASS="arabic">(\d+)<\/SPAN>/$1/; + $id =~ s/\.//; + return $id; +} + +# 'chapter' => 'SynopsisTable instance' +%ModuleSynopses = (); + +sub get_synopsis_table($){ + my $chap = $_[0]; + my $key; + foreach $key (keys %ModuleSynopses) { + if ($key eq $chap) { + return $ModuleSynopses{$chap}; + } + } + my $st = SynopsisTable->new(); + $ModuleSynopses{$chap} = $st; + return $st; +} + +sub do_cmd_moduleauthor{ + local($_) = @_; + next_argument(); + next_argument(); + return $_; +} + +sub do_cmd_sectionauthor{ + local($_) = @_; + next_argument(); + next_argument(); + return $_; +} + +sub do_cmd_declaremodule{ + local($_) = @_; + my $key = next_optional_argument(); + my $type = next_argument(); + my $name = next_argument(); + my $st = get_synopsis_table(get_chapter_id()); + # + $key = $name unless $key; + $type = 'built-in' if $type eq 'builtin'; + $st->declare($name, $key, $type); + define_module($type, $name); + return anchor_label("module-$key",$CURRENT_FILE,$_) +} + +sub do_cmd_modulesynopsis{ + local($_) = @_; + my $st = get_synopsis_table(get_chapter_id()); + $st->set_synopsis($THIS_MODULE, translate_commands(next_argument())); + return $_; +} + +sub do_cmd_localmoduletable{ + local($_) = @_; + my $chap = get_chapter_id(); + my $st = get_synopsis_table($chap); + $st->set_file("$CURRENT_FILE"); + return "<tex2html-localmoduletable><$chap>\\tableofchildlinks[off]" . $_; +} + +sub process_all_localmoduletables(){ + my $key; + foreach $key (keys %ModuleSynopses) { + my $st = $ModuleSynopses{$key}; + my $file = $st->get_file(); + if ($file) { + process_localmoduletables_in_file($file); + } + else { + print "\nsynopsis table $key has no file association\n"; + } + } +} + +sub process_localmoduletables_in_file($){ + my $file = $_[0]; + open(MYFILE, "<$file"); + local($_); + sysread(MYFILE, $_, 1024*1024); + close(MYFILE); + # need to get contents of file in $_ + while (/<tex2html-localmoduletable><(\d+)>/) { + my $match = $&; + my $chap = $1; + my $st = get_synopsis_table($chap); + my $data = $st->tohtml(); + s/$match/$data/; + } + open(MYFILE,">$file"); + print MYFILE $_; + close(MYFILE); +} +sub process_python_state(){ + process_all_localmoduletables(); + process_grammar_files(); +} + + +# +# "See also:" -- references placed at the end of a \section +# + +sub do_env_seealso{ + return ("<div class=\"seealso\">\n " + . "<p class=\"heading\">See Also:</p>\n" + . $_[0] + . '</div>'); +} + +sub do_env_seealsostar{ + return ("<div class=\"seealso-simple\">\n " + . $_[0] + . '</div>'); +} + +sub do_cmd_seemodule{ + # Insert the right magic to jump to the module definition. This should + # work most of the time, at least for repeat builds.... + local($_) = @_; + my $key = next_optional_argument(); + my $module = next_argument(); + my $text = next_argument(); + my $period = '.'; + $key = $module + unless $key; + if ($text =~ /\.$/) { + $period = ''; + } + return ('<dl compact="compact" class="seemodule">' + . "\n <dt>Module <b><tt class=\"module\">" + . "<a href=\"module-$key.html\">$module</a></tt>:</b>" + . "\n <dd>$text$period\n </dl>" + . $_); +} + +sub strip_html_markup($){ + my $str = $_[0]; + my $s = "$str"; + $s =~ s/<[a-zA-Z0-9]+(\s+[a-zA-Z0-9]+(\s*=\s*(\'[^\']*\'|\"[^\"]*\"|[a-zA-Z0-9]+))?)*\s*>//g; + $s =~ s/<\/[a-zA-Z0-9]+>//g; + return $s; +} + +sub handle_rfclike_reference($$$){ + local($_, $what, $format) = @_; + my $rfcnum = next_argument(); + my $title = next_argument(); + my $text = next_argument(); + my $url = get_rfc_url($rfcnum, $format); + my $icon = get_link_icon($url); + my $attrtitle = strip_html_markup($title); + return '<dl compact="compact" class="seerfc">' + . "\n <dt><a href=\"$url\"" + . "\n title=\"$attrtitle\"" + . "\n >$what $rfcnum, <em>$title</em>$icon</a>" + . "\n <dd>$text\n </dl>" + . $_; +} + +sub do_cmd_seepep{ + return handle_rfclike_reference($_[0], "PEP", $PEP_FORMAT); +} + +sub do_cmd_seerfc{ + # XXX Would be nice to add links to the text/plain and PDF versions. + return handle_rfclike_reference($_[0], "RFC", $RFC_FORMAT); +} + +sub do_cmd_seetitle{ + local($_) = @_; + my $url = next_optional_argument(); + my $title = next_argument(); + my $text = next_argument(); + if ($url) { + my $icon = get_link_icon($url); + return '<dl compact="compact" class="seetitle">' + . "\n <dt><em class=\"citetitle\"><a href=\"$url\"" + . "\n >$title$icon</a></em></dt>" + . "\n <dd>$text</dd>\n </dl>" + . $_; + } + return '<dl compact="compact" class="seetitle">' + . "\n <dt><em class=\"citetitle\"" + . "\n >$title</em></dt>" + . "\n <dd>$text</dd>\n </dl>" + . $_; +} + +sub do_cmd_seelink{ + local($_) = @_; + my $url = next_argument(); + my $linktext = next_argument(); + my $text = next_argument(); + my $icon = get_link_icon($url); + return '<dl compact="compact" class="seeurl">' + . "\n <dt><a href='$url'" + . "\n >$linktext$icon</a></dt>" + . "\n <dd>$text</dd>\n </dl>" + . $_; +} + +sub do_cmd_seeurl{ + local($_) = @_; + my $url = next_argument(); + my $text = next_argument(); + my $icon = get_link_icon($url); + return '<dl compact="compact" class="seeurl">' + . "\n <dt><a href=\"$url\"" + . "\n class=\"url\">$url$icon</a></dt>" + . "\n <dd>$text</dd>\n </dl>" + . $_; +} + +sub do_cmd_seetext{ + local($_) = @_; + my $content = next_argument(); + return '<div class="seetext"><p>' . $content . '</p></div>' . $_; +} + + +# +# Definition list support. +# + +sub do_env_definitions{ + return '<dl class="definitions">' . $_[0] . "</dl>\n"; +} + +sub do_cmd_term{ + local($_) = @_; + my $term = next_argument(); + my($name, $aname, $ahref) = new_link_info(); + # could easily add an index entry here... + return "<dt><b>$aname" . $term . "</a></b></dt>\n<dd>" . $_; +} + + +# Commands listed here have process-order dependencies; these often +# are related to indexing operations. +# XXX Not sure why funclineni, methodlineni, and samp are here. +# +process_commands_wrap_deferred(<<_RAW_ARG_DEFERRED_CMDS_); +declaremodule # [] # {} # {} +funcline # {} # {} +funclineni # {} # {} +memberline # [] # {} +methodline # [] # {} # {} +methodlineni # [] # {} # {} +modulesynopsis # {} +bifuncindex # {} +exindex # {} +indexii # {} # {} +indexiii # {} # {} # {} +indexiv # {} # {} # {} # {} +kwindex # {} +obindex # {} +opindex # {} +stindex # {} +platform # {} +samp # {} +setindexsubitem # {} +withsubitem # {} # {} +_RAW_ARG_DEFERRED_CMDS_ + + +$alltt_start = '<div class="verbatim"><pre>'; +$alltt_end = '</pre></div>'; + +sub do_env_alltt{ + local ($_) = @_; + local($closures,$reopens,@open_block_tags); + + # get the tag-strings for all open tags + local(@keep_open_tags) = @$open_tags_R; + ($closures,$reopens) = &preserve_open_tags() if (@$open_tags_R); + + # get the tags for text-level tags only + $open_tags_R = [ @keep_open_tags ]; + local($local_closures, $local_reopens); + ($local_closures, $local_reopens,@open_block_tags) + = &preserve_open_block_tags + if (@$open_tags_R); + + $open_tags_R = [ @open_block_tags ]; + + do { + local($open_tags_R) = [ @open_block_tags ]; + local(@save_open_tags) = (); + + local($cnt) = ++$global{'max_id'}; + $_ = join('',"$O$cnt$C\\tt$O", ++$global{'max_id'}, $C + , $_ , $O, $global{'max_id'}, "$C$O$cnt$C"); + + $_ = &translate_environments($_); + $_ = &translate_commands($_) if (/\\/); + + # remove spurious <BR> someone sticks in; not sure where they + # actually come from + # XXX the replacement space is there to accomodate something + # broken that inserts a space in front of the first line of + # the environment + s/<BR>/ /gi; + + $_ = join('', $closures, $alltt_start, $local_reopens + , $_ + , &balance_tags() #, $local_closures + , $alltt_end, $reopens); + undef $open_tags_R; undef @save_open_tags; + }; + $open_tags_R = [ @keep_open_tags ]; + return codetext($_); +} + +# List of all filenames produced by do_cmd_verbatiminput() +%VerbatimFiles = (); +@VerbatimOutputs = (); + +sub get_verbatim_output_name($){ + my $file = $_[0]; + # + # Re-write the source filename to always use a .txt extension + # so that Web servers will present it as text/plain. This is + # needed since there is no other even moderately reliable way + # to get the right Content-Type header on text files for + # servers which we can't configure (like python.org mirrors). + # + if (defined $VerbatimFiles{$file}) { + # We've seen this one before; re-use the same output file. + return $VerbatimFiles{$file}; + } + my($srcname, $srcdir, $srcext) = fileparse($file, '\..*'); + $filename = "$srcname.txt"; + # + # We need to determine if our default filename is already + # being used, and find a new one it it is. If the name is in + # used, this algorithm will first attempt to include the + # source extension as part of the name, and if that is also in + # use (if the same file is included multiple times, or if + # another source file has that as the base name), a counter is + # used instead. + # + my $found = 1; + FIND: + while ($found) { + foreach $fn (@VerbatimOutputs) { + if ($fn eq $filename) { + if ($found == 1) { + $srcext =~ s/^[.]//; # Remove '.' from extension + $filename = "$srcname-$srcext.txt"; + } + else { + $filename = "$srcname-$found.txt"; + } + ++$found; + next FIND; + } + } + $found = 0; + } + push @VerbatimOutputs, $filename; + $VerbatimFiles{$file} = $filename; + return $filename; +} + +sub do_cmd_verbatiminput{ + local($_) = @_; + my $fname = next_argument(); + my $file; + my $found = 0; + my $texpath; + # Search TEXINPUTS for the input file, the way we're supposed to: + foreach $texpath (split /$envkey/, $TEXINPUTS) { + $file = "$texpath$dd$fname"; + last if ($found = (-f $file)); + } + my $filename = ''; + my $text; + if ($found) { + open(MYFILE, "<$file") || die "\n$!\n"; + read(MYFILE, $text, 1024*1024); + close(MYFILE); + $filename = get_verbatim_output_name($file); + # Now that we have a filename, write it out. + open(MYFILE, ">$filename"); + print MYFILE $text; + close(MYFILE); + # + # These rewrites convert the raw text to something that will + # be properly visible as HTML and also will pass through the + # vagaries of conversion through LaTeX2HTML. The order in + # which the specific rewrites are performed is significant. + # + $text =~ s/\&/\&amp;/g; + # These need to happen before the normal < and > re-writes, + # since we need to avoid LaTeX2HTML's attempt to perform + # ligature processing without regard to context (since it + # doesn't have font information). + $text =~ s/--/-&\#45;/g; + $text =~ s/<</\&lt;\&\#60;/g; + $text =~ s/>>/\&gt;\&\#62;/g; + # Just normal re-writes... + $text =~ s/</\&lt;/g; + $text =~ s/>/\&gt;/g; + # These last isn't needed for the HTML, but is needed to get + # past LaTeX2HTML processing TeX macros. We use &#92; instead + # of &sol; since many browsers don't support that. + $text =~ s/\\/\&\#92;/g; + } + else { + return '<b>Could not locate requested file <i>$fname</i>!</b>\n'; + } + my $note = 'Download as text.'; + if ($file ne $filename) { + $note = ('Download as text (original file name: <span class="file">' + . $fname + . '</span>).'); + } + return ("<div class=\"verbatim\">\n<pre>" + . $text + . "</pre>\n<div class=\"footer\">\n" + . "<a href=\"$filename\" type=\"text/plain\"" + . ">$note</a>" + . "\n</div></div>" + . $_); +} + +1; # This must be the last line diff --git a/sys/src/cmd/python/Doc/python-docs.txt b/sys/src/cmd/python/Doc/python-docs.txt new file mode 100644 index 000000000..bf475b610 --- /dev/null +++ b/sys/src/cmd/python/Doc/python-docs.txt @@ -0,0 +1,183 @@ +This message is being sent in response to your message to the Python +documentation maintainers (docs@python.org). Your message will +be handled by a human, but this message serves to answer the most +common questions sent to this address. + +You will only receive this message if it has not been sent to you for +at least three months. + +If your question is answered below, you may not receive an additional +message from the documentation maintainers. If you feel the answers +below are not sufficient and you do not receive an additional response +within a week, please do send a note letting us know that your +question has not been properly answered, and be specific regarding +what additional information you are looking for. + + + -Fred + + +Frequently Asked Questions about the Python Documentation +--------------------------------------------------------- + + 1. Can I download HTML/PDF/PostScript versions of the docs? + 2. Where can I download Python? + 3. I can't unpack a downloaded copy on Windows; what should I do? + 4. I can't unpack a downloaded copy on Mac OS; what should I do? + 5. What can I use Python for? + 6. How do I use module/function/whatever XXX? + 7. What about JPython? + 8. I found a bug in the documentation, who should I tell? + 9. Can I get an algorithm to do THIS in language THAT? + 10. How do I decode an XXX file from my email on a YYY computer? + 11. Acrobat Reader won't print the PDF. What's wrong? + 12. Where can I find documentation in my native language? + 13. Why is Python installed on my computer? + + +Answers to the Questions +------------------------ + + 1. Can I download HTML/PDF/PostScript/<other> versions of the docs? + + Yes. These are available via the Web and traditional FTP. For + Web access to the latest version, see: + + http://www.python.org/doc/ + + For FTP access to the latest version and archives of previous + versions, see: + + ftp.python.org:/pub/python/doc/ + + 2. Where can I download Python? + + You can get Python in source form and as a Windows installer + from the main Python website. You can also find information + about pre-built packages for other platforms there as well. + + Downloading information at the website is at the URL: + + http://www.python.org/download/ + + The sources and Windows installer can be downloaded from the FTP + site as well: + + ftp://ftp.python.org/pub/python/ + + 3. I can't unpack a downloaded archive on Windows; what should I do? + + Make sure the archive was saved with the .tgz extension; you may + need to watch carefully when telling the browser where to save + the file, as the default may change the extension to .tar or + even .exe. + + Once you're sure the file has the right extension, use a recent + version of WinZip to upack the file (version 7.0 works). Get + WinZip from: + + http://www.winzip.com/ + + 4. I can't unpack a downloaded archive on Mac OS; what should I do? + + Stuffit Expander 4.5 (and probably other versions) cannot handle + the "tar" archive, although it can decompress it from the .tgz + file. Expander Enhancer, which you have to pay for, can handle + the tar archive. + + 5. What can I use Python for? + + Python is a general purpose programming language. See the + Python home page at http://www.python.org/ for more information; + introductory material is available at: + + http://www.python.org/doc/Intros.html + + 6. How do I use module/function/whatever XXX? + + Start by reading the documentation for XXX. If the + documentation doesn't make sense or seems incomplete, please + file a specific bug report to docs@python.org (the + address you sent your question to). Otherwise, you probably + sent your question to the wrong place (which does not preclude + an answer, if I know it). + + If you're looking for examples or tutorial information on how to + use a particular Python library component, check the Demo/ + directory of the source distribution or Windows installation; + there might be an example. If that doesn't help, point your Web + browser to http://www.python.org/doc/ and look around; there may + be a link to some interesting examples online. After that, try + searching the Python Web site at http://www.python.org/search/. + + If your question still hasn't been answered, you may send your + query to the Python newsgroup (comp.lang.python) or the mailing + list (see http://www.python.org/mailman/listinfo/python-list). + If you'd rather not send you message to a public forum, you can + try sending it to python-help@python.org. (This is typically + slower than sending your question to the public list, however.) + + 7. What about Jython and JPython? + + If your question is specific to Jython or JPython, you should + consult the Jython website at: + + http://www.jython.org/ + + Chances are very good that the person who answers questions + posted to docs@python.org doesn't use Jython very often, + and won't be able to give you a meaningful answer beyond "Look + at the Jython website." Sorry, I don't have *all* the answers! + + 8. I found a bug in the documentation, who should I tell? + + If you're reading this, you've found the right address! Send + all documentation bug reports to docs@python.org. If + you prefer to use a Web-based reporting mechanism, you can use + the bug database at http://www.python.org/python-bugs/. + + 9. Can I get an algorithm to do THIS in language THAT? + + If THAT is Python, look in the standard library. If THAT isn't + Python, use your favorite Internet search engine. + + 10. How do I decode an XXX file from my email on a YYY computer? + + I really, honestly do not know. I don't even know why this + question gets asked here. Since I don't have a YYY computer, + I couldn't even try a few things out for you. + + 11. Acrobat Reader won't print the PDF. What's wrong? + + Adobe has reportedly admitted that there is a bug in Acrobat Reader + 5.0 which causes it not to print at least some PDF files + generated by pdfTeX. This software is used to produce the PDF + version of the Python documentation, and our documents + definately trigger this bug in Acrobat Reader. To print the PDF + files, use Acrobat Reader 4.x, ghostscript, or xpdf. + + Information on ghostscript can be found at: + + http://www.ghostscript.com/ + + Information on xpdf can be found at: + + http://www.foolabs.com/xpdf/ + + 12. Where can I find documentation in my native language? + + There is a lot of contributed documentation in languages other + than English. Some of the documents are translations of English + documents, and others were originally authored in other + languages. If we know about it, it will be listed at: + + http://www.python.org/doc/NonEnglish.html + + 13. Why is Python installed on my computer? + + We're increasingly seeing Python being installed on computers + as delivered by vendors. For more information on why, and + whether it's safe to remove, see the "Why is Python Installed on + my Computer?" FAQ, found at: + + http://www.python.org/doc/faq/installed/ diff --git a/sys/src/cmd/python/Doc/ref/ref.tex b/sys/src/cmd/python/Doc/ref/ref.tex new file mode 100644 index 000000000..03c0acf8d --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref.tex @@ -0,0 +1,68 @@ +\documentclass{manual} + +\title{Python Reference Manual} + +\input{boilerplate} + +\makeindex + +\begin{document} + +\maketitle + +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +\input{copyright} + +\begin{abstract} + +\noindent +Python is an interpreted, object-oriented, high-level programming +language with dynamic semantics. Its high-level built in data +structures, combined with dynamic typing and dynamic binding, make it +very attractive for rapid application development, as well as for use +as a scripting or glue language to connect existing components +together. Python's simple, easy to learn syntax emphasizes +readability and therefore reduces the cost of program +maintenance. Python supports modules and packages, which encourages +program modularity and code reuse. The Python interpreter and the +extensive standard library are available in source or binary form +without charge for all major platforms, and can be freely distributed. + +This reference manual describes the syntax and ``core semantics'' of +the language. It is terse, but attempts to be exact and complete. +The semantics of non-essential built-in object types and of the +built-in functions and modules are described in the +\citetitle[../lib/lib.html]{Python Library Reference}. For an +informal introduction to the language, see the +\citetitle[../tut/tut.html]{Python Tutorial}. For C or +\Cpp{} programmers, two additional manuals exist: +\citetitle[../ext/ext.html]{Extending and Embedding the Python +Interpreter} describes the high-level picture of how to write a Python +extension module, and the \citetitle[../api/api.html]{Python/C API +Reference Manual} describes the interfaces available to +C/\Cpp{} programmers in detail. + +\end{abstract} + +\tableofcontents + +\input{ref1} % Introduction +\input{ref2} % Lexical analysis +\input{ref3} % Data model +\input{ref4} % Execution model +\input{ref5} % Expressions and conditions +\input{ref6} % Simple statements +\input{ref7} % Compound statements +\input{ref8} % Top-level components + +\appendix + +\chapter{History and License} +\input{license} + +\input{ref.ind} + +\end{document} diff --git a/sys/src/cmd/python/Doc/ref/ref1.tex b/sys/src/cmd/python/Doc/ref/ref1.tex new file mode 100644 index 000000000..623471656 --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref1.tex @@ -0,0 +1,136 @@ +\chapter{Introduction\label{introduction}} + +This reference manual describes the Python programming language. +It is not intended as a tutorial. + +While I am trying to be as precise as possible, I chose to use English +rather than formal specifications for everything except syntax and +lexical analysis. This should make the document more understandable +to the average reader, but will leave room for ambiguities. +Consequently, if you were coming from Mars and tried to re-implement +Python from this document alone, you might have to guess things and in +fact you would probably end up implementing quite a different language. +On the other hand, if you are using +Python and wonder what the precise rules about a particular area of +the language are, you should definitely be able to find them here. +If you would like to see a more formal definition of the language, +maybe you could volunteer your time --- or invent a cloning machine +:-). + +It is dangerous to add too many implementation details to a language +reference document --- the implementation may change, and other +implementations of the same language may work differently. On the +other hand, there is currently only one Python implementation in +widespread use (although alternate implementations exist), and +its particular quirks are sometimes worth being mentioned, especially +where the implementation imposes additional limitations. Therefore, +you'll find short ``implementation notes'' sprinkled throughout the +text. + +Every Python implementation comes with a number of built-in and +standard modules. These are not documented here, but in the separate +\citetitle[../lib/lib.html]{Python Library Reference} document. A few +built-in modules are mentioned when they interact in a significant way +with the language definition. + + +\section{Alternate Implementations\label{implementations}} + +Though there is one Python implementation which is by far the most +popular, there are some alternate implementations which are of +particular interest to different audiences. + +Known implementations include: + +\begin{itemize} +\item[CPython] +This is the original and most-maintained implementation of Python, +written in C. New language features generally appear here first. + +\item[Jython] +Python implemented in Java. This implementation can be used as a +scripting language for Java applications, or can be used to create +applications using the Java class libraries. It is also often used to +create tests for Java libraries. More information can be found at +\ulink{the Jython website}{http://www.jython.org/}. + +\item[Python for .NET] +This implementation actually uses the CPython implementation, but is a +managed .NET application and makes .NET libraries available. This was +created by Brian Lloyd. For more information, see the \ulink{Python +for .NET home page}{http://www.zope.org/Members/Brian/PythonNet}. + +\item[IronPython] +An alternate Python for\ .NET. Unlike Python.NET, this is a complete +Python implementation that generates IL, and compiles Python code +directly to\ .NET assemblies. It was created by Jim Hugunin, the +original creator of Jython. For more information, see \ulink{the +IronPython website}{http://workspaces.gotdotnet.com/ironpython}. + +\item[PyPy] +An implementation of Python written in Python; even the bytecode +interpreter is written in Python. This is executed using CPython as +the underlying interpreter. One of the goals of the project is to +encourage experimentation with the language itself by making it easier +to modify the interpreter (since it is written in Python). Additional +information is available on \ulink{the PyPy project's home +page}{http://codespeak.net/pypy/}. +\end{itemize} + +Each of these implementations varies in some way from the language as +documented in this manual, or introduces specific information beyond +what's covered in the standard Python documentation. Please refer to +the implementation-specific documentation to determine what else you +need to know about the specific implementation you're using. + + +\section{Notation\label{notation}} + +The descriptions of lexical analysis and syntax use a modified BNF +grammar notation. This uses the following style of definition: +\index{BNF} +\index{grammar} +\index{syntax} +\index{notation} + +\begin{productionlist}[*] + \production{name}{\token{lc_letter} (\token{lc_letter} | "_")*} + \production{lc_letter}{"a"..."z"} +\end{productionlist} + +The first line says that a \code{name} is an \code{lc_letter} followed by +a sequence of zero or more \code{lc_letter}s and underscores. An +\code{lc_letter} in turn is any of the single characters \character{a} +through \character{z}. (This rule is actually adhered to for the +names defined in lexical and grammar rules in this document.) + +Each rule begins with a name (which is the name defined by the rule) +and \code{::=}. A vertical bar (\code{|}) is used to separate +alternatives; it is the least binding operator in this notation. A +star (\code{*}) means zero or more repetitions of the preceding item; +likewise, a plus (\code{+}) means one or more repetitions, and a +phrase enclosed in square brackets (\code{[ ]}) means zero or one +occurrences (in other words, the enclosed phrase is optional). The +\code{*} and \code{+} operators bind as tightly as possible; +parentheses are used for grouping. Literal strings are enclosed in +quotes. White space is only meaningful to separate tokens. +Rules are normally contained on a single line; rules with many +alternatives may be formatted alternatively with each line after the +first beginning with a vertical bar. + +In lexical definitions (as the example above), two more conventions +are used: Two literal characters separated by three dots mean a choice +of any single character in the given (inclusive) range of \ASCII{} +characters. A phrase between angular brackets (\code{<...>}) gives an +informal description of the symbol defined; e.g., this could be used +to describe the notion of `control character' if needed. +\index{lexical definitions} +\index{ASCII@\ASCII} + +Even though the notation used is almost the same, there is a big +difference between the meaning of lexical and syntactic definitions: +a lexical definition operates on the individual characters of the +input source, while a syntax definition operates on the stream of +tokens generated by the lexical analysis. All uses of BNF in the next +chapter (``Lexical Analysis'') are lexical definitions; uses in +subsequent chapters are syntactic definitions. diff --git a/sys/src/cmd/python/Doc/ref/ref2.tex b/sys/src/cmd/python/Doc/ref/ref2.tex new file mode 100644 index 000000000..bad4609fb --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref2.tex @@ -0,0 +1,731 @@ +\chapter{Lexical analysis\label{lexical}} + +A Python program is read by a \emph{parser}. Input to the parser is a +stream of \emph{tokens}, generated by the \emph{lexical analyzer}. This +chapter describes how the lexical analyzer breaks a file into tokens. +\index{lexical analysis} +\index{parser} +\index{token} + +Python uses the 7-bit \ASCII{} character set for program text. +\versionadded[An encoding declaration can be used to indicate that +string literals and comments use an encoding different from ASCII]{2.3} +For compatibility with older versions, Python only warns if it finds +8-bit characters; those warnings should be corrected by either declaring +an explicit encoding, or using escape sequences if those bytes are binary +data, instead of characters. + + +The run-time character set depends on the I/O devices connected to the +program but is generally a superset of \ASCII. + +\strong{Future compatibility note:} It may be tempting to assume that the +character set for 8-bit characters is ISO Latin-1 (an \ASCII{} +superset that covers most western languages that use the Latin +alphabet), but it is possible that in the future Unicode text editors +will become common. These generally use the UTF-8 encoding, which is +also an \ASCII{} superset, but with very different use for the +characters with ordinals 128-255. While there is no consensus on this +subject yet, it is unwise to assume either Latin-1 or UTF-8, even +though the current implementation appears to favor Latin-1. This +applies both to the source character set and the run-time character +set. + + +\section{Line structure\label{line-structure}} + +A Python program is divided into a number of \emph{logical lines}. +\index{line structure} + + +\subsection{Logical lines\label{logical}} + +The end of +a logical line is represented by the token NEWLINE. Statements cannot +cross logical line boundaries except where NEWLINE is allowed by the +syntax (e.g., between statements in compound statements). +A logical line is constructed from one or more \emph{physical lines} +by following the explicit or implicit \emph{line joining} rules. +\index{logical line} +\index{physical line} +\index{line joining} +\index{NEWLINE token} + + +\subsection{Physical lines\label{physical}} + +A physical line is a sequence of characters terminated by an end-of-line +sequence. In source files, any of the standard platform line +termination sequences can be used - the \UNIX{} form using \ASCII{} LF +(linefeed), the Windows form using the \ASCII{} sequence CR LF (return +followed by linefeed), or the Macintosh form using the \ASCII{} CR +(return) character. All of these forms can be used equally, regardless +of platform. + +When embedding Python, source code strings should be passed to Python +APIs using the standard C conventions for newline characters (the +\code{\e n} character, representing \ASCII{} LF, is the line +terminator). + + +\subsection{Comments\label{comments}} + +A comment starts with a hash character (\code{\#}) that is not part of +a string literal, and ends at the end of the physical line. A comment +signifies the end of the logical line unless the implicit line joining +rules are invoked. +Comments are ignored by the syntax; they are not tokens. +\index{comment} +\index{hash character} + + +\subsection{Encoding declarations\label{encodings}} +\index{source character set} +\index{encodings} + +If a comment in the first or second line of the Python script matches +the regular expression \regexp{coding[=:]\e s*([-\e w.]+)}, this comment is +processed as an encoding declaration; the first group of this +expression names the encoding of the source code file. The recommended +forms of this expression are + +\begin{verbatim} +# -*- coding: <encoding-name> -*- +\end{verbatim} + +which is recognized also by GNU Emacs, and + +\begin{verbatim} +# vim:fileencoding=<encoding-name> +\end{verbatim} + +which is recognized by Bram Moolenaar's VIM. In addition, if the first +bytes of the file are the UTF-8 byte-order mark +(\code{'\e xef\e xbb\e xbf'}), the declared file encoding is UTF-8 +(this is supported, among others, by Microsoft's \program{notepad}). + +If an encoding is declared, the encoding name must be recognized by +Python. % XXX there should be a list of supported encodings. +The encoding is used for all lexical analysis, in particular to find +the end of a string, and to interpret the contents of Unicode literals. +String literals are converted to Unicode for syntactical analysis, +then converted back to their original encoding before interpretation +starts. The encoding declaration must appear on a line of its own. + +\subsection{Explicit line joining\label{explicit-joining}} + +Two or more physical lines may be joined into logical lines using +backslash characters (\code{\e}), as follows: when a physical line ends +in a backslash that is not part of a string literal or comment, it is +joined with the following forming a single logical line, deleting the +backslash and the following end-of-line character. For example: +\index{physical line} +\index{line joining} +\index{line continuation} +\index{backslash character} +% +\begin{verbatim} +if 1900 < year < 2100 and 1 <= month <= 12 \ + and 1 <= day <= 31 and 0 <= hour < 24 \ + and 0 <= minute < 60 and 0 <= second < 60: # Looks like a valid date + return 1 +\end{verbatim} + +A line ending in a backslash cannot carry a comment. A backslash does +not continue a comment. A backslash does not continue a token except +for string literals (i.e., tokens other than string literals cannot be +split across physical lines using a backslash). A backslash is +illegal elsewhere on a line outside a string literal. + + +\subsection{Implicit line joining\label{implicit-joining}} + +Expressions in parentheses, square brackets or curly braces can be +split over more than one physical line without using backslashes. +For example: + +\begin{verbatim} +month_names = ['Januari', 'Februari', 'Maart', # These are the + 'April', 'Mei', 'Juni', # Dutch names + 'Juli', 'Augustus', 'September', # for the months + 'Oktober', 'November', 'December'] # of the year +\end{verbatim} + +Implicitly continued lines can carry comments. The indentation of the +continuation lines is not important. Blank continuation lines are +allowed. There is no NEWLINE token between implicit continuation +lines. Implicitly continued lines can also occur within triple-quoted +strings (see below); in that case they cannot carry comments. + + +\subsection{Blank lines \label{blank-lines}} + +\index{blank line} +A logical line that contains only spaces, tabs, formfeeds and possibly +a comment, is ignored (i.e., no NEWLINE token is generated). During +interactive input of statements, handling of a blank line may differ +depending on the implementation of the read-eval-print loop. In the +standard implementation, an entirely blank logical line (i.e.\ one +containing not even whitespace or a comment) terminates a multi-line +statement. + + +\subsection{Indentation\label{indentation}} + +Leading whitespace (spaces and tabs) at the beginning of a logical +line is used to compute the indentation level of the line, which in +turn is used to determine the grouping of statements. +\index{indentation} +\index{whitespace} +\index{leading whitespace} +\index{space} +\index{tab} +\index{grouping} +\index{statement grouping} + +First, tabs are replaced (from left to right) by one to eight spaces +such that the total number of characters up to and including the +replacement is a multiple of +eight (this is intended to be the same rule as used by \UNIX). The +total number of spaces preceding the first non-blank character then +determines the line's indentation. Indentation cannot be split over +multiple physical lines using backslashes; the whitespace up to the +first backslash determines the indentation. + +\strong{Cross-platform compatibility note:} because of the nature of +text editors on non-UNIX platforms, it is unwise to use a mixture of +spaces and tabs for the indentation in a single source file. It +should also be noted that different platforms may explicitly limit the +maximum indentation level. + +A formfeed character may be present at the start of the line; it will +be ignored for the indentation calculations above. Formfeed +characters occurring elsewhere in the leading whitespace have an +undefined effect (for instance, they may reset the space count to +zero). + +The indentation levels of consecutive lines are used to generate +INDENT and DEDENT tokens, using a stack, as follows. +\index{INDENT token} +\index{DEDENT token} + +Before the first line of the file is read, a single zero is pushed on +the stack; this will never be popped off again. The numbers pushed on +the stack will always be strictly increasing from bottom to top. At +the beginning of each logical line, the line's indentation level is +compared to the top of the stack. If it is equal, nothing happens. +If it is larger, it is pushed on the stack, and one INDENT token is +generated. If it is smaller, it \emph{must} be one of the numbers +occurring on the stack; all numbers on the stack that are larger are +popped off, and for each number popped off a DEDENT token is +generated. At the end of the file, a DEDENT token is generated for +each number remaining on the stack that is larger than zero. + +Here is an example of a correctly (though confusingly) indented piece +of Python code: + +\begin{verbatim} +def perm(l): + # Compute the list of all permutations of l + if len(l) <= 1: + return [l] + r = [] + for i in range(len(l)): + s = l[:i] + l[i+1:] + p = perm(s) + for x in p: + r.append(l[i:i+1] + x) + return r +\end{verbatim} + +The following example shows various indentation errors: + +\begin{verbatim} + def perm(l): # error: first line indented +for i in range(len(l)): # error: not indented + s = l[:i] + l[i+1:] + p = perm(l[:i] + l[i+1:]) # error: unexpected indent + for x in p: + r.append(l[i:i+1] + x) + return r # error: inconsistent dedent +\end{verbatim} + +(Actually, the first three errors are detected by the parser; only the +last error is found by the lexical analyzer --- the indentation of +\code{return r} does not match a level popped off the stack.) + + +\subsection{Whitespace between tokens\label{whitespace}} + +Except at the beginning of a logical line or in string literals, the +whitespace characters space, tab and formfeed can be used +interchangeably to separate tokens. Whitespace is needed between two +tokens only if their concatenation could otherwise be interpreted as a +different token (e.g., ab is one token, but a b is two tokens). + + +\section{Other tokens\label{other-tokens}} + +Besides NEWLINE, INDENT and DEDENT, the following categories of tokens +exist: \emph{identifiers}, \emph{keywords}, \emph{literals}, +\emph{operators}, and \emph{delimiters}. +Whitespace characters (other than line terminators, discussed earlier) +are not tokens, but serve to delimit tokens. +Where +ambiguity exists, a token comprises the longest possible string that +forms a legal token, when read from left to right. + + +\section{Identifiers and keywords\label{identifiers}} + +Identifiers (also referred to as \emph{names}) are described by the following +lexical definitions: +\index{identifier} +\index{name} + +\begin{productionlist} + \production{identifier} + {(\token{letter}|"_") (\token{letter} | \token{digit} | "_")*} + \production{letter} + {\token{lowercase} | \token{uppercase}} + \production{lowercase} + {"a"..."z"} + \production{uppercase} + {"A"..."Z"} + \production{digit} + {"0"..."9"} +\end{productionlist} + +Identifiers are unlimited in length. Case is significant. + + +\subsection{Keywords\label{keywords}} + +The following identifiers are used as reserved words, or +\emph{keywords} of the language, and cannot be used as ordinary +identifiers. They must be spelled exactly as written here:% +\index{keyword}% +\index{reserved word} + +\begin{verbatim} +and del from not while +as elif global or with +assert else if pass yield +break except import print +class exec in raise +continue finally is return +def for lambda try +\end{verbatim} + +% When adding keywords, use reswords.py for reformatting + +\versionchanged[\constant{None} became a constant and is now +recognized by the compiler as a name for the built-in object +\constant{None}. Although it is not a keyword, you cannot assign +a different object to it]{2.4} + +\versionchanged[Both \keyword{as} and \keyword{with} are only recognized +when the \code{with_statement} future feature has been enabled. +It will always be enabled in Python 2.6. See section~\ref{with} for +details. Note that using \keyword{as} and \keyword{with} as identifiers +will always issue a warning, even when the \code{with_statement} future +directive is not in effect]{2.5} + + +\subsection{Reserved classes of identifiers\label{id-classes}} + +Certain classes of identifiers (besides keywords) have special +meanings. These classes are identified by the patterns of leading and +trailing underscore characters: + +\begin{description} + +\item[\code{_*}] + Not imported by \samp{from \var{module} import *}. The special + identifier \samp{_} is used in the interactive interpreter to store + the result of the last evaluation; it is stored in the + \module{__builtin__} module. When not in interactive mode, \samp{_} + has no special meaning and is not defined. + See section~\ref{import}, ``The \keyword{import} statement.'' + + \note{The name \samp{_} is often used in conjunction with + internationalization; refer to the documentation for the + \ulink{\module{gettext} module}{../lib/module-gettext.html} for more + information on this convention.} + +\item[\code{__*__}] + System-defined names. These names are defined by the interpreter + and its implementation (including the standard library); + applications should not expect to define additional names using this + convention. The set of names of this class defined by Python may be + extended in future versions. + See section~\ref{specialnames}, ``Special method names.'' + +\item[\code{__*}] + Class-private names. Names in this category, when used within the + context of a class definition, are re-written to use a mangled form + to help avoid name clashes between ``private'' attributes of base + and derived classes. + See section~\ref{atom-identifiers}, ``Identifiers (Names).'' + +\end{description} + + +\section{Literals\label{literals}} + +Literals are notations for constant values of some built-in types. +\index{literal} +\index{constant} + + +\subsection{String literals\label{strings}} + +String literals are described by the following lexical definitions: +\index{string literal} + +\index{ASCII@\ASCII} +\begin{productionlist} + \production{stringliteral} + {[\token{stringprefix}](\token{shortstring} | \token{longstring})} + \production{stringprefix} + {"r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"} + \production{shortstring} + {"'" \token{shortstringitem}* "'" + | '"' \token{shortstringitem}* '"'} + \production{longstring} + {"'''" \token{longstringitem}* "'''"} + \productioncont{| '"""' \token{longstringitem}* '"""'} + \production{shortstringitem} + {\token{shortstringchar} | \token{escapeseq}} + \production{longstringitem} + {\token{longstringchar} | \token{escapeseq}} + \production{shortstringchar} + {<any source character except "\e" or newline or the quote>} + \production{longstringchar} + {<any source character except "\e">} + \production{escapeseq} + {"\e" <any ASCII character>} +\end{productionlist} + +One syntactic restriction not indicated by these productions is that +whitespace is not allowed between the \grammartoken{stringprefix} and +the rest of the string literal. The source character set is defined +by the encoding declaration; it is \ASCII{} if no encoding declaration +is given in the source file; see section~\ref{encodings}. + +\index{triple-quoted string} +\index{Unicode Consortium} +\index{string!Unicode} +In plain English: String literals can be enclosed in matching single +quotes (\code{'}) or double quotes (\code{"}). They can also be +enclosed in matching groups of three single or double quotes (these +are generally referred to as \emph{triple-quoted strings}). The +backslash (\code{\e}) character is used to escape characters that +otherwise have a special meaning, such as newline, backslash itself, +or the quote character. String literals may optionally be prefixed +with a letter \character{r} or \character{R}; such strings are called +\dfn{raw strings}\index{raw string} and use different rules for interpreting +backslash escape sequences. A prefix of \character{u} or \character{U} +makes the string a Unicode string. Unicode strings use the Unicode character +set as defined by the Unicode Consortium and ISO~10646. Some additional +escape sequences, described below, are available in Unicode strings. +The two prefix characters may be combined; in this case, \character{u} must +appear before \character{r}. + +In triple-quoted strings, +unescaped newlines and quotes are allowed (and are retained), except +that three unescaped quotes in a row terminate the string. (A +``quote'' is the character used to open the string, i.e. either +\code{'} or \code{"}.) + +Unless an \character{r} or \character{R} prefix is present, escape +sequences in strings are interpreted according to rules similar +to those used by Standard C. The recognized escape sequences are: +\index{physical line} +\index{escape sequence} +\index{Standard C} +\index{C} + +\begin{tableiii}{l|l|c}{code}{Escape Sequence}{Meaning}{Notes} +\lineiii{\e\var{newline}} {Ignored}{} +\lineiii{\e\e} {Backslash (\code{\e})}{} +\lineiii{\e'} {Single quote (\code{'})}{} +\lineiii{\e"} {Double quote (\code{"})}{} +\lineiii{\e a} {\ASCII{} Bell (BEL)}{} +\lineiii{\e b} {\ASCII{} Backspace (BS)}{} +\lineiii{\e f} {\ASCII{} Formfeed (FF)}{} +\lineiii{\e n} {\ASCII{} Linefeed (LF)}{} +\lineiii{\e N\{\var{name}\}} + {Character named \var{name} in the Unicode database (Unicode only)}{} +\lineiii{\e r} {\ASCII{} Carriage Return (CR)}{} +\lineiii{\e t} {\ASCII{} Horizontal Tab (TAB)}{} +\lineiii{\e u\var{xxxx}} + {Character with 16-bit hex value \var{xxxx} (Unicode only)}{(1)} +\lineiii{\e U\var{xxxxxxxx}} + {Character with 32-bit hex value \var{xxxxxxxx} (Unicode only)}{(2)} +\lineiii{\e v} {\ASCII{} Vertical Tab (VT)}{} +\lineiii{\e\var{ooo}} {Character with octal value \var{ooo}}{(3,5)} +\lineiii{\e x\var{hh}} {Character with hex value \var{hh}}{(4,5)} +\end{tableiii} +\index{ASCII@\ASCII} + +\noindent +Notes: + +\begin{itemize} +\item[(1)] + Individual code units which form parts of a surrogate pair can be + encoded using this escape sequence. +\item[(2)] + Any Unicode character can be encoded this way, but characters + outside the Basic Multilingual Plane (BMP) will be encoded using a + surrogate pair if Python is compiled to use 16-bit code units (the + default). Individual code units which form parts of a surrogate + pair can be encoded using this escape sequence. +\item[(3)] + As in Standard C, up to three octal digits are accepted. +\item[(4)] + Unlike in Standard C, at most two hex digits are accepted. +\item[(5)] + In a string literal, hexadecimal and octal escapes denote the + byte with the given value; it is not necessary that the byte + encodes a character in the source character set. In a Unicode + literal, these escapes denote a Unicode character with the given + value. +\end{itemize} + + +Unlike Standard \index{unrecognized escape sequence}C, +all unrecognized escape sequences are left in the string unchanged, +i.e., \emph{the backslash is left in the string}. (This behavior is +useful when debugging: if an escape sequence is mistyped, the +resulting output is more easily recognized as broken.) It is also +important to note that the escape sequences marked as ``(Unicode +only)'' in the table above fall into the category of unrecognized +escapes for non-Unicode string literals. + +When an \character{r} or \character{R} prefix is present, a character +following a backslash is included in the string without change, and \emph{all +backslashes are left in the string}. For example, the string literal +\code{r"\e n"} consists of two characters: a backslash and a lowercase +\character{n}. String quotes can be escaped with a backslash, but the +backslash remains in the string; for example, \code{r"\e""} is a valid string +literal consisting of two characters: a backslash and a double quote; +\code{r"\e"} is not a valid string literal (even a raw string cannot +end in an odd number of backslashes). Specifically, \emph{a raw +string cannot end in a single backslash} (since the backslash would +escape the following quote character). Note also that a single +backslash followed by a newline is interpreted as those two characters +as part of the string, \emph{not} as a line continuation. + +When an \character{r} or \character{R} prefix is used in conjunction +with a \character{u} or \character{U} prefix, then the \code{\e uXXXX} +and \code{\e UXXXXXXXX} escape sequences are processed while +\emph{all other backslashes are left in the string}. +For example, the string literal +\code{ur"\e{}u0062\e n"} consists of three Unicode characters: `LATIN +SMALL LETTER B', `REVERSE SOLIDUS', and `LATIN SMALL LETTER N'. +Backslashes can be escaped with a preceding backslash; however, both +remain in the string. As a result, \code{\e uXXXX} escape sequences +are only recognized when there are an odd number of backslashes. + +\subsection{String literal concatenation\label{string-catenation}} + +Multiple adjacent string literals (delimited by whitespace), possibly +using different quoting conventions, are allowed, and their meaning is +the same as their concatenation. Thus, \code{"hello" 'world'} is +equivalent to \code{"helloworld"}. This feature can be used to reduce +the number of backslashes needed, to split long strings conveniently +across long lines, or even to add comments to parts of strings, for +example: + +\begin{verbatim} +re.compile("[A-Za-z_]" # letter or underscore + "[A-Za-z0-9_]*" # letter, digit or underscore + ) +\end{verbatim} + +Note that this feature is defined at the syntactical level, but +implemented at compile time. The `+' operator must be used to +concatenate string expressions at run time. Also note that literal +concatenation can use different quoting styles for each component +(even mixing raw strings and triple quoted strings). + + +\subsection{Numeric literals\label{numbers}} + +There are four types of numeric literals: plain integers, long +integers, floating point numbers, and imaginary numbers. There are no +complex literals (complex numbers can be formed by adding a real +number and an imaginary number). +\index{number} +\index{numeric literal} +\index{integer literal} +\index{plain integer literal} +\index{long integer literal} +\index{floating point literal} +\index{hexadecimal literal} +\index{octal literal} +\index{decimal literal} +\index{imaginary literal} +\index{complex!literal} + +Note that numeric literals do not include a sign; a phrase like +\code{-1} is actually an expression composed of the unary operator +`\code{-}' and the literal \code{1}. + + +\subsection{Integer and long integer literals\label{integers}} + +Integer and long integer literals are described by the following +lexical definitions: + +\begin{productionlist} + \production{longinteger} + {\token{integer} ("l" | "L")} + \production{integer} + {\token{decimalinteger} | \token{octinteger} | \token{hexinteger}} + \production{decimalinteger} + {\token{nonzerodigit} \token{digit}* | "0"} + \production{octinteger} + {"0" \token{octdigit}+} + \production{hexinteger} + {"0" ("x" | "X") \token{hexdigit}+} + \production{nonzerodigit} + {"1"..."9"} + \production{octdigit} + {"0"..."7"} + \production{hexdigit} + {\token{digit} | "a"..."f" | "A"..."F"} +\end{productionlist} + +Although both lower case \character{l} and upper case \character{L} are +allowed as suffix for long integers, it is strongly recommended to always +use \character{L}, since the letter \character{l} looks too much like the +digit \character{1}. + +Plain integer literals that are above the largest representable plain +integer (e.g., 2147483647 when using 32-bit arithmetic) are accepted +as if they were long integers instead.\footnote{In versions of Python +prior to 2.4, octal and hexadecimal literals in the range just above +the largest representable plain integer but below the largest unsigned +32-bit number (on a machine using 32-bit arithmetic), 4294967296, were +taken as the negative plain integer obtained by subtracting 4294967296 +from their unsigned value.} There is no limit for long integer +literals apart from what can be stored in available memory. + +Some examples of plain integer literals (first row) and long integer +literals (second and third rows): + +\begin{verbatim} +7 2147483647 0177 +3L 79228162514264337593543950336L 0377L 0x100000000L + 79228162514264337593543950336 0xdeadbeef +\end{verbatim} + + +\subsection{Floating point literals\label{floating}} + +Floating point literals are described by the following lexical +definitions: + +\begin{productionlist} + \production{floatnumber} + {\token{pointfloat} | \token{exponentfloat}} + \production{pointfloat} + {[\token{intpart}] \token{fraction} | \token{intpart} "."} + \production{exponentfloat} + {(\token{intpart} | \token{pointfloat}) + \token{exponent}} + \production{intpart} + {\token{digit}+} + \production{fraction} + {"." \token{digit}+} + \production{exponent} + {("e" | "E") ["+" | "-"] \token{digit}+} +\end{productionlist} + +Note that the integer and exponent parts of floating point numbers +can look like octal integers, but are interpreted using radix 10. For +example, \samp{077e010} is legal, and denotes the same number +as \samp{77e10}. +The allowed range of floating point literals is +implementation-dependent. +Some examples of floating point literals: + +\begin{verbatim} +3.14 10. .001 1e100 3.14e-10 0e0 +\end{verbatim} + +Note that numeric literals do not include a sign; a phrase like +\code{-1} is actually an expression composed of the unary operator +\code{-} and the literal \code{1}. + + +\subsection{Imaginary literals\label{imaginary}} + +Imaginary literals are described by the following lexical definitions: + +\begin{productionlist} + \production{imagnumber}{(\token{floatnumber} | \token{intpart}) ("j" | "J")} +\end{productionlist} + +An imaginary literal yields a complex number with a real part of +0.0. Complex numbers are represented as a pair of floating point +numbers and have the same restrictions on their range. To create a +complex number with a nonzero real part, add a floating point number +to it, e.g., \code{(3+4j)}. Some examples of imaginary literals: + +\begin{verbatim} +3.14j 10.j 10j .001j 1e100j 3.14e-10j +\end{verbatim} + + +\section{Operators\label{operators}} + +The following tokens are operators: +\index{operators} + +\begin{verbatim} ++ - * ** / // % +<< >> & | ^ ~ +< > <= >= == != <> +\end{verbatim} + +The comparison operators \code{<>} and \code{!=} are alternate +spellings of the same operator. \code{!=} is the preferred spelling; +\code{<>} is obsolescent. + + +\section{Delimiters\label{delimiters}} + +The following tokens serve as delimiters in the grammar: +\index{delimiters} + +\begin{verbatim} +( ) [ ] { } @ +, : . ` = ; ++= -= *= /= //= %= +&= |= ^= >>= <<= **= +\end{verbatim} + +The period can also occur in floating-point and imaginary literals. A +sequence of three periods has a special meaning as an ellipsis in slices. +The second half of the list, the augmented assignment operators, serve +lexically as delimiters, but also perform an operation. + +The following printing \ASCII{} characters have special meaning as part +of other tokens or are otherwise significant to the lexical analyzer: + +\begin{verbatim} +' " # \ +\end{verbatim} + +The following printing \ASCII{} characters are not used in Python. Their +occurrence outside string literals and comments is an unconditional +error: +\index{ASCII@\ASCII} + +\begin{verbatim} +$ ? +\end{verbatim} diff --git a/sys/src/cmd/python/Doc/ref/ref3.tex b/sys/src/cmd/python/Doc/ref/ref3.tex new file mode 100644 index 000000000..c5dbfd22d --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref3.tex @@ -0,0 +1,2225 @@ +\chapter{Data model\label{datamodel}} + + +\section{Objects, values and types\label{objects}} + +\dfn{Objects} are Python's abstraction for data. All data in a Python +program is represented by objects or by relations between objects. +(In a sense, and in conformance to Von Neumann's model of a +``stored program computer,'' code is also represented by objects.) +\index{object} +\index{data} + +Every object has an identity, a type and a value. An object's +\emph{identity} never changes once it has been created; you may think +of it as the object's address in memory. The `\keyword{is}' operator +compares the identity of two objects; the +\function{id()}\bifuncindex{id} function returns an integer +representing its identity (currently implemented as its address). +An object's \dfn{type} is +also unchangeable.\footnote{Since Python 2.2, a gradual merging of +types and classes has been started that makes this and a few other +assertions made in this manual not 100\% accurate and complete: +for example, it \emph{is} now possible in some cases to change an +object's type, under certain controlled conditions. Until this manual +undergoes extensive revision, it must now be taken as authoritative +only regarding ``classic classes'', that are still the default, for +compatibility purposes, in Python 2.2 and 2.3. For more information, +see \url{http://www.python.org/doc/newstyle.html}.} +An object's type determines the operations that the object +supports (e.g., ``does it have a length?'') and also defines the +possible values for objects of that type. The +\function{type()}\bifuncindex{type} function returns an object's type +(which is an object itself). The \emph{value} of some +objects can change. Objects whose value can change are said to be +\emph{mutable}; objects whose value is unchangeable once they are +created are called \emph{immutable}. +(The value of an immutable container object that contains a reference +to a mutable object can change when the latter's value is changed; +however the container is still considered immutable, because the +collection of objects it contains cannot be changed. So, immutability +is not strictly the same as having an unchangeable value, it is more +subtle.) +An object's mutability is determined by its type; for instance, +numbers, strings and tuples are immutable, while dictionaries and +lists are mutable. +\index{identity of an object} +\index{value of an object} +\index{type of an object} +\index{mutable object} +\index{immutable object} + +Objects are never explicitly destroyed; however, when they become +unreachable they may be garbage-collected. An implementation is +allowed to postpone garbage collection or omit it altogether --- it is +a matter of implementation quality how garbage collection is +implemented, as long as no objects are collected that are still +reachable. (Implementation note: the current implementation uses a +reference-counting scheme with (optional) delayed detection of +cyclically linked garbage, which collects most objects as soon as they +become unreachable, but is not guaranteed to collect garbage +containing circular references. See the +\citetitle[../lib/module-gc.html]{Python Library Reference} for +information on controlling the collection of cyclic garbage.) +\index{garbage collection} +\index{reference counting} +\index{unreachable object} + +Note that the use of the implementation's tracing or debugging +facilities may keep objects alive that would normally be collectable. +Also note that catching an exception with a +`\keyword{try}...\keyword{except}' statement may keep objects alive. + +Some objects contain references to ``external'' resources such as open +files or windows. It is understood that these resources are freed +when the object is garbage-collected, but since garbage collection is +not guaranteed to happen, such objects also provide an explicit way to +release the external resource, usually a \method{close()} method. +Programs are strongly recommended to explicitly close such +objects. The `\keyword{try}...\keyword{finally}' statement provides +a convenient way to do this. + +Some objects contain references to other objects; these are called +\emph{containers}. Examples of containers are tuples, lists and +dictionaries. The references are part of a container's value. In +most cases, when we talk about the value of a container, we imply the +values, not the identities of the contained objects; however, when we +talk about the mutability of a container, only the identities of +the immediately contained objects are implied. So, if an immutable +container (like a tuple) +contains a reference to a mutable object, its value changes +if that mutable object is changed. +\index{container} + +Types affect almost all aspects of object behavior. Even the importance +of object identity is affected in some sense: for immutable types, +operations that compute new values may actually return a reference to +any existing object with the same type and value, while for mutable +objects this is not allowed. E.g., after +\samp{a = 1; b = 1}, +\code{a} and \code{b} may or may not refer to the same object with the +value one, depending on the implementation, but after +\samp{c = []; d = []}, \code{c} and \code{d} +are guaranteed to refer to two different, unique, newly created empty +lists. +(Note that \samp{c = d = []} assigns the same object to both +\code{c} and \code{d}.) + + +\section{The standard type hierarchy\label{types}} + +Below is a list of the types that are built into Python. Extension +modules (written in C, Java, or other languages, depending on +the implementation) can define additional types. Future versions of +Python may add types to the type hierarchy (e.g., rational +numbers, efficiently stored arrays of integers, etc.). +\index{type} +\indexii{data}{type} +\indexii{type}{hierarchy} +\indexii{extension}{module} +\indexii{C}{language} + +Some of the type descriptions below contain a paragraph listing +`special attributes.' These are attributes that provide access to the +implementation and are not intended for general use. Their definition +may change in the future. +\index{attribute} +\indexii{special}{attribute} +\indexiii{generic}{special}{attribute} + +\begin{description} + +\item[None] +This type has a single value. There is a single object with this value. +This object is accessed through the built-in name \code{None}. +It is used to signify the absence of a value in many situations, e.g., +it is returned from functions that don't explicitly return anything. +Its truth value is false. +\obindex{None} + +\item[NotImplemented] +This type has a single value. There is a single object with this value. +This object is accessed through the built-in name \code{NotImplemented}. +Numeric methods and rich comparison methods may return this value if +they do not implement the operation for the operands provided. (The +interpreter will then try the reflected operation, or some other +fallback, depending on the operator.) Its truth value is true. +\obindex{NotImplemented} + +\item[Ellipsis] +This type has a single value. There is a single object with this value. +This object is accessed through the built-in name \code{Ellipsis}. +It is used to indicate the presence of the \samp{...} syntax in a +slice. Its truth value is true. +\obindex{Ellipsis} + +\item[Numbers] +These are created by numeric literals and returned as results by +arithmetic operators and arithmetic built-in functions. Numeric +objects are immutable; once created their value never changes. Python +numbers are of course strongly related to mathematical numbers, but +subject to the limitations of numerical representation in computers. +\obindex{numeric} + +Python distinguishes between integers, floating point numbers, and +complex numbers: + +\begin{description} +\item[Integers] +These represent elements from the mathematical set of integers +(positive and negative). +\obindex{integer} + +There are three types of integers: + +\begin{description} + +\item[Plain integers] +These represent numbers in the range -2147483648 through 2147483647. +(The range may be larger on machines with a larger natural word +size, but not smaller.) +When the result of an operation would fall outside this range, the +result is normally returned as a long integer (in some cases, the +exception \exception{OverflowError} is raised instead). +For the purpose of shift and mask operations, integers are assumed to +have a binary, 2's complement notation using 32 or more bits, and +hiding no bits from the user (i.e., all 4294967296 different bit +patterns correspond to different values). +\obindex{plain integer} +\withsubitem{(built-in exception)}{\ttindex{OverflowError}} + +\item[Long integers] +These represent numbers in an unlimited range, subject to available +(virtual) memory only. For the purpose of shift and mask operations, +a binary representation is assumed, and negative numbers are +represented in a variant of 2's complement which gives the illusion of +an infinite string of sign bits extending to the left. +\obindex{long integer} + +\item[Booleans] +These represent the truth values False and True. The two objects +representing the values False and True are the only Boolean objects. +The Boolean type is a subtype of plain integers, and Boolean values +behave like the values 0 and 1, respectively, in almost all contexts, +the exception being that when converted to a string, the strings +\code{"False"} or \code{"True"} are returned, respectively. +\obindex{Boolean} +\ttindex{False} +\ttindex{True} + +\end{description} % Integers + +The rules for integer representation are intended to give the most +meaningful interpretation of shift and mask operations involving +negative integers and the least surprises when switching between the +plain and long integer domains. Any operation except left shift, +if it yields a result in the plain integer domain without causing +overflow, will yield the same result in the long integer domain or +when using mixed operands. +\indexii{integer}{representation} + +\item[Floating point numbers] +These represent machine-level double precision floating point numbers. +You are at the mercy of the underlying machine architecture (and +C or Java implementation) for the accepted range and handling of overflow. +Python does not support single-precision floating point numbers; the +savings in processor and memory usage that are usually the reason for using +these is dwarfed by the overhead of using objects in Python, so there +is no reason to complicate the language with two kinds of floating +point numbers. +\obindex{floating point} +\indexii{floating point}{number} +\indexii{C}{language} +\indexii{Java}{language} + +\item[Complex numbers] +These represent complex numbers as a pair of machine-level double +precision floating point numbers. The same caveats apply as for +floating point numbers. The real and imaginary parts of a complex +number \code{z} can be retrieved through the read-only attributes +\code{z.real} and \code{z.imag}. +\obindex{complex} +\indexii{complex}{number} + +\end{description} % Numbers + + +\item[Sequences] +These represent finite ordered sets indexed by non-negative numbers. +The built-in function \function{len()}\bifuncindex{len} returns the +number of items of a sequence. +When the length of a sequence is \var{n}, the +index set contains the numbers 0, 1, \ldots, \var{n}-1. Item +\var{i} of sequence \var{a} is selected by \code{\var{a}[\var{i}]}. +\obindex{sequence} +\index{index operation} +\index{item selection} +\index{subscription} + +Sequences also support slicing: \code{\var{a}[\var{i}:\var{j}]} +selects all items with index \var{k} such that \var{i} \code{<=} +\var{k} \code{<} \var{j}. When used as an expression, a slice is a +sequence of the same type. This implies that the index set is +renumbered so that it starts at 0. +\index{slicing} + +Some sequences also support ``extended slicing'' with a third ``step'' +parameter: \code{\var{a}[\var{i}:\var{j}:\var{k}]} selects all items +of \var{a} with index \var{x} where \code{\var{x} = \var{i} + +\var{n}*\var{k}}, \var{n} \code{>=} \code{0} and \var{i} \code{<=} +\var{x} \code{<} \var{j}. +\index{extended slicing} + +Sequences are distinguished according to their mutability: + +\begin{description} + +\item[Immutable sequences] +An object of an immutable sequence type cannot change once it is +created. (If the object contains references to other objects, +these other objects may be mutable and may be changed; however, +the collection of objects directly referenced by an immutable object +cannot change.) +\obindex{immutable sequence} +\obindex{immutable} + +The following types are immutable sequences: + +\begin{description} + +\item[Strings] +The items of a string are characters. There is no separate +character type; a character is represented by a string of one item. +Characters represent (at least) 8-bit bytes. The built-in +functions \function{chr()}\bifuncindex{chr} and +\function{ord()}\bifuncindex{ord} convert between characters and +nonnegative integers representing the byte values. Bytes with the +values 0-127 usually represent the corresponding \ASCII{} values, but +the interpretation of values is up to the program. The string +data type is also used to represent arrays of bytes, e.g., to hold data +read from a file. +\obindex{string} +\index{character} +\index{byte} +\index{ASCII@\ASCII} + +(On systems whose native character set is not \ASCII, strings may use +EBCDIC in their internal representation, provided the functions +\function{chr()} and \function{ord()} implement a mapping between \ASCII{} and +EBCDIC, and string comparison preserves the \ASCII{} order. +Or perhaps someone can propose a better rule?) +\index{ASCII@\ASCII} +\index{EBCDIC} +\index{character set} +\indexii{string}{comparison} +\bifuncindex{chr} +\bifuncindex{ord} + +\item[Unicode] +The items of a Unicode object are Unicode code units. A Unicode code +unit is represented by a Unicode object of one item and can hold +either a 16-bit or 32-bit value representing a Unicode ordinal (the +maximum value for the ordinal is given in \code{sys.maxunicode}, and +depends on how Python is configured at compile time). Surrogate pairs +may be present in the Unicode object, and will be reported as two +separate items. The built-in functions +\function{unichr()}\bifuncindex{unichr} and +\function{ord()}\bifuncindex{ord} convert between code units and +nonnegative integers representing the Unicode ordinals as defined in +the Unicode Standard 3.0. Conversion from and to other encodings are +possible through the Unicode method \method{encode()} and the built-in +function \function{unicode()}.\bifuncindex{unicode} +\obindex{unicode} +\index{character} +\index{integer} +\index{Unicode} + +\item[Tuples] +The items of a tuple are arbitrary Python objects. +Tuples of two or more items are formed by comma-separated lists +of expressions. A tuple of one item (a `singleton') can be formed +by affixing a comma to an expression (an expression by itself does +not create a tuple, since parentheses must be usable for grouping of +expressions). An empty tuple can be formed by an empty pair of +parentheses. +\obindex{tuple} +\indexii{singleton}{tuple} +\indexii{empty}{tuple} + +\end{description} % Immutable sequences + +\item[Mutable sequences] +Mutable sequences can be changed after they are created. The +subscription and slicing notations can be used as the target of +assignment and \keyword{del} (delete) statements. +\obindex{mutable sequence} +\obindex{mutable} +\indexii{assignment}{statement} +\index{delete} +\stindex{del} +\index{subscription} +\index{slicing} + +There is currently a single intrinsic mutable sequence type: + +\begin{description} + +\item[Lists] +The items of a list are arbitrary Python objects. Lists are formed +by placing a comma-separated list of expressions in square brackets. +(Note that there are no special cases needed to form lists of length 0 +or 1.) +\obindex{list} + +\end{description} % Mutable sequences + +The extension module \module{array}\refstmodindex{array} provides an +additional example of a mutable sequence type. + + +\end{description} % Sequences + + +\item[Set types] +These represent unordered, finite sets of unique, immutable objects. +As such, they cannot be indexed by any subscript. However, they can be +iterated over, and the built-in function \function{len()} returns the +number of items in a set. Common uses for sets are +fast membership testing, removing duplicates from a sequence, and +computing mathematical operations such as intersection, union, difference, +and symmetric difference. +\bifuncindex{len} +\obindex{set type} + +For set elements, the same immutability rules apply as for dictionary +keys. Note that numeric types obey the normal rules for numeric +comparison: if two numbers compare equal (e.g., \code{1} and +\code{1.0}), only one of them can be contained in a set. + +There are currently two intrinsic set types: + +\begin{description} + +\item[Sets] +These\obindex{set} represent a mutable set. They are created by the +built-in \function{set()} constructor and can be modified afterwards +by several methods, such as \method{add()}. + +\item[Frozen sets] +These\obindex{frozenset} represent an immutable set. They are created by +the built-in \function{frozenset()} constructor. As a frozenset is +immutable and hashable, it can be used again as an element of another set, +or as a dictionary key. + +\end{description} % Set types + + +\item[Mappings] +These represent finite sets of objects indexed by arbitrary index sets. +The subscript notation \code{a[k]} selects the item indexed +by \code{k} from the mapping \code{a}; this can be used in +expressions and as the target of assignments or \keyword{del} statements. +The built-in function \function{len()} returns the number of items +in a mapping. +\bifuncindex{len} +\index{subscription} +\obindex{mapping} + +There is currently a single intrinsic mapping type: + +\begin{description} + +\item[Dictionaries] +These\obindex{dictionary} represent finite sets of objects indexed by +nearly arbitrary values. The only types of values not acceptable as +keys are values containing lists or dictionaries or other mutable +types that are compared by value rather than by object identity, the +reason being that the efficient implementation of dictionaries +requires a key's hash value to remain constant. +Numeric types used for keys obey the normal rules for numeric +comparison: if two numbers compare equal (e.g., \code{1} and +\code{1.0}) then they can be used interchangeably to index the same +dictionary entry. + +Dictionaries are mutable; they can be created by the +\code{\{...\}} notation (see section~\ref{dict}, ``Dictionary +Displays''). + +The extension modules \module{dbm}\refstmodindex{dbm}, +\module{gdbm}\refstmodindex{gdbm}, and +\module{bsddb}\refstmodindex{bsddb} provide additional examples of +mapping types. + +\end{description} % Mapping types + +\item[Callable types] +These\obindex{callable} are the types to which the function call +operation (see section~\ref{calls}, ``Calls'') can be applied: +\indexii{function}{call} +\index{invocation} +\indexii{function}{argument} + +\begin{description} + +\item[User-defined functions] +A user-defined function object is created by a function definition +(see section~\ref{function}, ``Function definitions''). It should be +called with an argument +list containing the same number of items as the function's formal +parameter list. +\indexii{user-defined}{function} +\obindex{function} +\obindex{user-defined function} + +Special attributes: + +\begin{tableiii}{lll}{member}{Attribute}{Meaning}{} + \lineiii{func_doc}{The function's documentation string, or + \code{None} if unavailable}{Writable} + + \lineiii{__doc__}{Another way of spelling + \member{func_doc}}{Writable} + + \lineiii{func_name}{The function's name}{Writable} + + \lineiii{__name__}{Another way of spelling + \member{func_name}}{Writable} + + \lineiii{__module__}{The name of the module the function was defined + in, or \code{None} if unavailable.}{Writable} + + \lineiii{func_defaults}{A tuple containing default argument values + for those arguments that have defaults, or \code{None} if no + arguments have a default value}{Writable} + + \lineiii{func_code}{The code object representing the compiled + function body.}{Writable} + + \lineiii{func_globals}{A reference to the dictionary that holds the + function's global variables --- the global namespace of the module + in which the function was defined.}{Read-only} + + \lineiii{func_dict}{The namespace supporting arbitrary function + attributes.}{Writable} + + \lineiii{func_closure}{\code{None} or a tuple of cells that contain + bindings for the function's free variables.}{Read-only} +\end{tableiii} + +Most of the attributes labelled ``Writable'' check the type of the +assigned value. + +\versionchanged[\code{func_name} is now writable]{2.4} + +Function objects also support getting and setting arbitrary +attributes, which can be used, for example, to attach metadata to +functions. Regular attribute dot-notation is used to get and set such +attributes. \emph{Note that the current implementation only supports +function attributes on user-defined functions. Function attributes on +built-in functions may be supported in the future.} + +Additional information about a function's definition can be retrieved +from its code object; see the description of internal types below. + +\withsubitem{(function attribute)}{ + \ttindex{func_doc} + \ttindex{__doc__} + \ttindex{__name__} + \ttindex{__module__} + \ttindex{__dict__} + \ttindex{func_defaults} + \ttindex{func_closure} + \ttindex{func_code} + \ttindex{func_globals} + \ttindex{func_dict}} +\indexii{global}{namespace} + +\item[User-defined methods] +A user-defined method object combines a class, a class instance (or +\code{None}) and any callable object (normally a user-defined +function). +\obindex{method} +\obindex{user-defined method} +\indexii{user-defined}{method} + +Special read-only attributes: \member{im_self} is the class instance +object, \member{im_func} is the function object; +\member{im_class} is the class of \member{im_self} for bound methods +or the class that asked for the method for unbound methods; +\member{__doc__} is the method's documentation (same as +\code{im_func.__doc__}); \member{__name__} is the method name (same as +\code{im_func.__name__}); \member{__module__} is the name of the +module the method was defined in, or \code{None} if unavailable. +\versionchanged[\member{im_self} used to refer to the class that + defined the method]{2.2} +\withsubitem{(method attribute)}{ + \ttindex{__doc__} + \ttindex{__name__} + \ttindex{__module__} + \ttindex{im_func} + \ttindex{im_self}} + +Methods also support accessing (but not setting) the arbitrary +function attributes on the underlying function object. + +User-defined method objects may be created when getting an attribute +of a class (perhaps via an instance of that class), if that attribute +is a user-defined function object, an unbound user-defined method object, +or a class method object. +When the attribute is a user-defined method object, a new +method object is only created if the class from which it is being +retrieved is the same as, or a derived class of, the class stored +in the original method object; otherwise, the original method object +is used as it is. + +When a user-defined method object is created by retrieving +a user-defined function object from a class, its \member{im_self} +attribute is \code{None} and the method object is said to be unbound. +When one is created by retrieving a user-defined function object +from a class via one of its instances, its \member{im_self} attribute +is the instance, and the method object is said to be bound. +In either case, the new method's \member{im_class} attribute +is the class from which the retrieval takes place, and +its \member{im_func} attribute is the original function object. +\withsubitem{(method attribute)}{ + \ttindex{im_class}\ttindex{im_func}\ttindex{im_self}} + +When a user-defined method object is created by retrieving another +method object from a class or instance, the behaviour is the same +as for a function object, except that the \member{im_func} attribute +of the new instance is not the original method object but its +\member{im_func} attribute. +\withsubitem{(method attribute)}{ + \ttindex{im_func}} + +When a user-defined method object is created by retrieving a +class method object from a class or instance, its \member{im_self} +attribute is the class itself (the same as the \member{im_class} +attribute), and its \member{im_func} attribute is the function +object underlying the class method. +\withsubitem{(method attribute)}{ + \ttindex{im_class}\ttindex{im_func}\ttindex{im_self}} + +When an unbound user-defined method object is called, the underlying +function (\member{im_func}) is called, with the restriction that the +first argument must be an instance of the proper class +(\member{im_class}) or of a derived class thereof. + +When a bound user-defined method object is called, the underlying +function (\member{im_func}) is called, inserting the class instance +(\member{im_self}) in front of the argument list. For instance, when +\class{C} is a class which contains a definition for a function +\method{f()}, and \code{x} is an instance of \class{C}, calling +\code{x.f(1)} is equivalent to calling \code{C.f(x, 1)}. + +When a user-defined method object is derived from a class method object, +the ``class instance'' stored in \member{im_self} will actually be the +class itself, so that calling either \code{x.f(1)} or \code{C.f(1)} is +equivalent to calling \code{f(C,1)} where \code{f} is the underlying +function. + +Note that the transformation from function object to (unbound or +bound) method object happens each time the attribute is retrieved from +the class or instance. In some cases, a fruitful optimization is to +assign the attribute to a local variable and call that local variable. +Also notice that this transformation only happens for user-defined +functions; other callable objects (and all non-callable objects) are +retrieved without transformation. It is also important to note that +user-defined functions which are attributes of a class instance are +not converted to bound methods; this \emph{only} happens when the +function is an attribute of the class. + +\item[Generator functions\index{generator!function}\index{generator!iterator}] +A function or method which uses the \keyword{yield} statement (see +section~\ref{yield}, ``The \keyword{yield} statement'') is called a +\dfn{generator function}. Such a function, when called, always +returns an iterator object which can be used to execute the body of +the function: calling the iterator's \method{next()} method will +cause the function to execute until it provides a value using the +\keyword{yield} statement. When the function executes a +\keyword{return} statement or falls off the end, a +\exception{StopIteration} exception is raised and the iterator will +have reached the end of the set of values to be returned. + +\item[Built-in functions] +A built-in function object is a wrapper around a C function. Examples +of built-in functions are \function{len()} and \function{math.sin()} +(\module{math} is a standard built-in module). +The number and type of the arguments are +determined by the C function. +Special read-only attributes: \member{__doc__} is the function's +documentation string, or \code{None} if unavailable; \member{__name__} +is the function's name; \member{__self__} is set to \code{None} (but see +the next item); \member{__module__} is the name of the module the +function was defined in or \code{None} if unavailable. +\obindex{built-in function} +\obindex{function} +\indexii{C}{language} + +\item[Built-in methods] +This is really a different disguise of a built-in function, this time +containing an object passed to the C function as an implicit extra +argument. An example of a built-in method is +\code{\var{alist}.append()}, assuming +\var{alist} is a list object. +In this case, the special read-only attribute \member{__self__} is set +to the object denoted by \var{list}. +\obindex{built-in method} +\obindex{method} +\indexii{built-in}{method} + +\item[Class Types] +Class types, or ``new-style classes,'' are callable. These objects +normally act as factories for new instances of themselves, but +variations are possible for class types that override +\method{__new__()}. The arguments of the call are passed to +\method{__new__()} and, in the typical case, to \method{__init__()} to +initialize the new instance. + +\item[Classic Classes] +Class objects are described below. When a class object is called, +a new class instance (also described below) is created and +returned. This implies a call to the class's \method{__init__()} method +if it has one. Any arguments are passed on to the \method{__init__()} +method. If there is no \method{__init__()} method, the class must be called +without arguments. +\withsubitem{(object method)}{\ttindex{__init__()}} +\obindex{class} +\obindex{class instance} +\obindex{instance} +\indexii{class object}{call} + +\item[Class instances] +Class instances are described below. Class instances are callable +only when the class has a \method{__call__()} method; \code{x(arguments)} +is a shorthand for \code{x.__call__(arguments)}. + +\end{description} + +\item[Modules] +Modules are imported by the \keyword{import} statement (see +section~\ref{import}, ``The \keyword{import} statement'').% +\stindex{import}\obindex{module} +A module object has a namespace implemented by a dictionary object +(this is the dictionary referenced by the func_globals attribute of +functions defined in the module). Attribute references are translated +to lookups in this dictionary, e.g., \code{m.x} is equivalent to +\code{m.__dict__["x"]}. +A module object does not contain the code object used to +initialize the module (since it isn't needed once the initialization +is done). + +Attribute assignment updates the module's namespace dictionary, +e.g., \samp{m.x = 1} is equivalent to \samp{m.__dict__["x"] = 1}. + +Special read-only attribute: \member{__dict__} is the module's +namespace as a dictionary object. +\withsubitem{(module attribute)}{\ttindex{__dict__}} + +Predefined (writable) attributes: \member{__name__} +is the module's name; \member{__doc__} is the +module's documentation string, or +\code{None} if unavailable; \member{__file__} is the pathname of the +file from which the module was loaded, if it was loaded from a file. +The \member{__file__} attribute is not present for C{} modules that are +statically linked into the interpreter; for extension modules loaded +dynamically from a shared library, it is the pathname of the shared +library file. +\withsubitem{(module attribute)}{ + \ttindex{__name__} + \ttindex{__doc__} + \ttindex{__file__}} +\indexii{module}{namespace} + +\item[Classes] +Class objects are created by class definitions (see +section~\ref{class}, ``Class definitions''). +A class has a namespace implemented by a dictionary object. +Class attribute references are translated to +lookups in this dictionary, +e.g., \samp{C.x} is translated to \samp{C.__dict__["x"]}. +When the attribute name is not found +there, the attribute search continues in the base classes. The search +is depth-first, left-to-right in the order of occurrence in the +base class list. + +When a class attribute reference (for class \class{C}, say) +would yield a user-defined function object or +an unbound user-defined method object whose associated class is either +\class{C} or one of its base classes, it is transformed into an unbound +user-defined method object whose \member{im_class} attribute is~\class{C}. +When it would yield a class method object, it is transformed into +a bound user-defined method object whose \member{im_class} and +\member{im_self} attributes are both~\class{C}. When it would yield +a static method object, it is transformed into the object wrapped +by the static method object. See section~\ref{descriptors} for another +way in which attributes retrieved from a class may differ from those +actually contained in its \member{__dict__}. +\obindex{class} +\obindex{class instance} +\obindex{instance} +\indexii{class object}{call} +\index{container} +\obindex{dictionary} +\indexii{class}{attribute} + +Class attribute assignments update the class's dictionary, never the +dictionary of a base class. +\indexiii{class}{attribute}{assignment} + +A class object can be called (see above) to yield a class instance (see +below). +\indexii{class object}{call} + +Special attributes: \member{__name__} is the class name; +\member{__module__} is the module name in which the class was defined; +\member{__dict__} is the dictionary containing the class's namespace; +\member{__bases__} is a tuple (possibly empty or a singleton) +containing the base classes, in the order of their occurrence in the +base class list; \member{__doc__} is the class's documentation string, +or None if undefined. +\withsubitem{(class attribute)}{ + \ttindex{__name__} + \ttindex{__module__} + \ttindex{__dict__} + \ttindex{__bases__} + \ttindex{__doc__}} + +\item[Class instances] +A class instance is created by calling a class object (see above). +A class instance has a namespace implemented as a dictionary which +is the first place in which +attribute references are searched. When an attribute is not found +there, and the instance's class has an attribute by that name, +the search continues with the class attributes. If a class attribute +is found that is a user-defined function object or an unbound +user-defined method object whose associated class is the class +(call it~\class{C}) of the instance for which the attribute reference +was initiated or one of its bases, +it is transformed into a bound user-defined method object whose +\member{im_class} attribute is~\class{C} and whose \member{im_self} attribute +is the instance. Static method and class method objects are also +transformed, as if they had been retrieved from class~\class{C}; +see above under ``Classes''. See section~\ref{descriptors} for +another way in which attributes of a class retrieved via its +instances may differ from the objects actually stored in the +class's \member{__dict__}. +If no class attribute is found, and the object's class has a +\method{__getattr__()} method, that is called to satisfy the lookup. +\obindex{class instance} +\obindex{instance} +\indexii{class}{instance} +\indexii{class instance}{attribute} + +Attribute assignments and deletions update the instance's dictionary, +never a class's dictionary. If the class has a \method{__setattr__()} or +\method{__delattr__()} method, this is called instead of updating the +instance dictionary directly. +\indexiii{class instance}{attribute}{assignment} + +Class instances can pretend to be numbers, sequences, or mappings if +they have methods with certain special names. See +section~\ref{specialnames}, ``Special method names.'' +\obindex{numeric} +\obindex{sequence} +\obindex{mapping} + +Special attributes: \member{__dict__} is the attribute +dictionary; \member{__class__} is the instance's class. +\withsubitem{(instance attribute)}{ + \ttindex{__dict__} + \ttindex{__class__}} + +\item[Files] +A file\obindex{file} object represents an open file. File objects are +created by the \function{open()}\bifuncindex{open} built-in function, +and also by +\withsubitem{(in module os)}{\ttindex{popen()}}\function{os.popen()}, +\function{os.fdopen()}, and the +\method{makefile()}\withsubitem{(socket method)}{\ttindex{makefile()}} +method of socket objects (and perhaps by other functions or methods +provided by extension modules). The objects +\ttindex{sys.stdin}\code{sys.stdin}, +\ttindex{sys.stdout}\code{sys.stdout} and +\ttindex{sys.stderr}\code{sys.stderr} are initialized to file objects +corresponding to the interpreter's standard\index{stdio} input, output +and error streams. See the \citetitle[../lib/lib.html]{Python Library +Reference} for complete documentation of file objects. +\withsubitem{(in module sys)}{ + \ttindex{stdin} + \ttindex{stdout} + \ttindex{stderr}} + + +\item[Internal types] +A few types used internally by the interpreter are exposed to the user. +Their definitions may change with future versions of the interpreter, +but they are mentioned here for completeness. +\index{internal type} +\index{types, internal} + +\begin{description} + +\item[Code objects] +Code objects represent \emph{byte-compiled} executable Python code, or +\emph{bytecode}. +The difference between a code +object and a function object is that the function object contains an +explicit reference to the function's globals (the module in which it +was defined), while a code object contains no context; +also the default argument values are stored in the function object, +not in the code object (because they represent values calculated at +run-time). Unlike function objects, code objects are immutable and +contain no references (directly or indirectly) to mutable objects. +\index{bytecode} +\obindex{code} + +Special read-only attributes: \member{co_name} gives the function +name; \member{co_argcount} is the number of positional arguments +(including arguments with default values); \member{co_nlocals} is the +number of local variables used by the function (including arguments); +\member{co_varnames} is a tuple containing the names of the local +variables (starting with the argument names); \member{co_cellvars} is +a tuple containing the names of local variables that are referenced by +nested functions; \member{co_freevars} is a tuple containing the names +of free variables; \member{co_code} is a string representing the +sequence of bytecode instructions; +\member{co_consts} is a tuple containing the literals used by the +bytecode; \member{co_names} is a tuple containing the names used by +the bytecode; \member{co_filename} is the filename from which the code +was compiled; \member{co_firstlineno} is the first line number of the +function; \member{co_lnotab} is a string encoding the mapping from +byte code offsets to line numbers (for details see the source code of +the interpreter); \member{co_stacksize} is the required stack size +(including local variables); \member{co_flags} is an integer encoding +a number of flags for the interpreter. + +\withsubitem{(code object attribute)}{ + \ttindex{co_argcount} + \ttindex{co_code} + \ttindex{co_consts} + \ttindex{co_filename} + \ttindex{co_firstlineno} + \ttindex{co_flags} + \ttindex{co_lnotab} + \ttindex{co_name} + \ttindex{co_names} + \ttindex{co_nlocals} + \ttindex{co_stacksize} + \ttindex{co_varnames} + \ttindex{co_cellvars} + \ttindex{co_freevars}} + +The following flag bits are defined for \member{co_flags}: bit +\code{0x04} is set if the function uses the \samp{*arguments} syntax +to accept an arbitrary number of positional arguments; bit +\code{0x08} is set if the function uses the \samp{**keywords} syntax +to accept arbitrary keyword arguments; bit \code{0x20} is set if the +function is a generator. +\obindex{generator} + +Future feature declarations (\samp{from __future__ import division}) +also use bits in \member{co_flags} to indicate whether a code object +was compiled with a particular feature enabled: bit \code{0x2000} is +set if the function was compiled with future division enabled; bits +\code{0x10} and \code{0x1000} were used in earlier versions of Python. + +Other bits in \member{co_flags} are reserved for internal use. + +If\index{documentation string} a code object represents a function, +the first item in +\member{co_consts} is the documentation string of the function, or +\code{None} if undefined. + +\item[Frame objects] +Frame objects represent execution frames. They may occur in traceback +objects (see below). +\obindex{frame} + +Special read-only attributes: \member{f_back} is to the previous +stack frame (towards the caller), or \code{None} if this is the bottom +stack frame; \member{f_code} is the code object being executed in this +frame; \member{f_locals} is the dictionary used to look up local +variables; \member{f_globals} is used for global variables; +\member{f_builtins} is used for built-in (intrinsic) names; +\member{f_restricted} is a flag indicating whether the function is +executing in restricted execution mode; \member{f_lasti} gives the +precise instruction (this is an index into the bytecode string of +the code object). +\withsubitem{(frame attribute)}{ + \ttindex{f_back} + \ttindex{f_code} + \ttindex{f_globals} + \ttindex{f_locals} + \ttindex{f_lasti} + \ttindex{f_builtins} + \ttindex{f_restricted}} + +Special writable attributes: \member{f_trace}, if not \code{None}, is +a function called at the start of each source code line (this is used +by the debugger); \member{f_exc_type}, \member{f_exc_value}, +\member{f_exc_traceback} represent the last exception raised in the +parent frame provided another exception was ever raised in the current +frame (in all other cases they are None); \member{f_lineno} is the +current line number of the frame --- writing to this from within a +trace function jumps to the given line (only for the bottom-most +frame). A debugger can implement a Jump command (aka Set Next +Statement) by writing to f_lineno. +\withsubitem{(frame attribute)}{ + \ttindex{f_trace} + \ttindex{f_exc_type} + \ttindex{f_exc_value} + \ttindex{f_exc_traceback} + \ttindex{f_lineno}} + +\item[Traceback objects] \label{traceback} +Traceback objects represent a stack trace of an exception. A +traceback object is created when an exception occurs. When the search +for an exception handler unwinds the execution stack, at each unwound +level a traceback object is inserted in front of the current +traceback. When an exception handler is entered, the stack trace is +made available to the program. +(See section~\ref{try}, ``The \code{try} statement.'') +It is accessible as \code{sys.exc_traceback}, and also as the third +item of the tuple returned by \code{sys.exc_info()}. The latter is +the preferred interface, since it works correctly when the program is +using multiple threads. +When the program contains no suitable handler, the stack trace is written +(nicely formatted) to the standard error stream; if the interpreter is +interactive, it is also made available to the user as +\code{sys.last_traceback}. +\obindex{traceback} +\indexii{stack}{trace} +\indexii{exception}{handler} +\indexii{execution}{stack} +\withsubitem{(in module sys)}{ + \ttindex{exc_info} + \ttindex{exc_traceback} + \ttindex{last_traceback}} +\ttindex{sys.exc_info} +\ttindex{sys.exc_traceback} +\ttindex{sys.last_traceback} + +Special read-only attributes: \member{tb_next} is the next level in the +stack trace (towards the frame where the exception occurred), or +\code{None} if there is no next level; \member{tb_frame} points to the +execution frame of the current level; \member{tb_lineno} gives the line +number where the exception occurred; \member{tb_lasti} indicates the +precise instruction. The line number and last instruction in the +traceback may differ from the line number of its frame object if the +exception occurred in a \keyword{try} statement with no matching +except clause or with a finally clause. +\withsubitem{(traceback attribute)}{ + \ttindex{tb_next} + \ttindex{tb_frame} + \ttindex{tb_lineno} + \ttindex{tb_lasti}} +\stindex{try} + +\item[Slice objects] +Slice objects are used to represent slices when \emph{extended slice +syntax} is used. This is a slice using two colons, or multiple slices +or ellipses separated by commas, e.g., \code{a[i:j:step]}, \code{a[i:j, +k:l]}, or \code{a[..., i:j]}. They are also created by the built-in +\function{slice()}\bifuncindex{slice} function. + +Special read-only attributes: \member{start} is the lower bound; +\member{stop} is the upper bound; \member{step} is the step value; each is +\code{None} if omitted. These attributes can have any type. +\withsubitem{(slice object attribute)}{ + \ttindex{start} + \ttindex{stop} + \ttindex{step}} + +Slice objects support one method: + +\begin{methoddesc}[slice]{indices}{self, length} +This method takes a single integer argument \var{length} and computes +information about the extended slice that the slice object would +describe if applied to a sequence of \var{length} items. It returns a +tuple of three integers; respectively these are the \var{start} and +\var{stop} indices and the \var{step} or stride length of the slice. +Missing or out-of-bounds indices are handled in a manner consistent +with regular slices. +\versionadded{2.3} +\end{methoddesc} + +\item[Static method objects] +Static method objects provide a way of defeating the transformation +of function objects to method objects described above. A static method +object is a wrapper around any other object, usually a user-defined +method object. When a static method object is retrieved from a class +or a class instance, the object actually returned is the wrapped object, +which is not subject to any further transformation. Static method +objects are not themselves callable, although the objects they +wrap usually are. Static method objects are created by the built-in +\function{staticmethod()} constructor. + +\item[Class method objects] +A class method object, like a static method object, is a wrapper +around another object that alters the way in which that object +is retrieved from classes and class instances. The behaviour of +class method objects upon such retrieval is described above, +under ``User-defined methods''. Class method objects are created +by the built-in \function{classmethod()} constructor. + +\end{description} % Internal types + +\end{description} % Types + +%========================================================================= +\section{New-style and classic classes} + +Classes and instances come in two flavors: old-style or classic, and new-style. + +Up to Python 2.1, old-style classes were the only flavour available to the +user. The concept of (old-style) class is unrelated to the concept of type: if +\var{x} is an instance of an old-style class, then \code{x.__class__} +designates the class of \var{x}, but \code{type(x)} is always \code{<type +'instance'>}. This reflects the fact that all old-style instances, +independently of their class, are implemented with a single built-in type, +called \code{instance}. + +New-style classes were introduced in Python 2.2 to unify classes and types. A +new-style class neither more nor less than a user-defined type. If \var{x} is +an instance of a new-style class, then \code{type(x)} is the same as +\code{x.__class__}. + +The major motivation for introducing new-style classes is to provide a unified +object model with a full meta-model. It also has a number of immediate +benefits, like the ability to subclass most built-in types, or the introduction +of "descriptors", which enable computed properties. + +For compatibility reasons, classes are still old-style by default. New-style +classes are created by specifying another new-style class (i.e.\ a type) as a +parent class, or the "top-level type" \class{object} if no other parent is +needed. The behaviour of new-style classes differs from that of old-style +classes in a number of important details in addition to what \function{type} +returns. Some of these changes are fundamental to the new object model, like +the way special methods are invoked. Others are "fixes" that could not be +implemented before for compatibility concerns, like the method resolution order +in case of multiple inheritance. + +This manual is not up-to-date with respect to new-style classes. For now, +please see \url{http://www.python.org/doc/newstyle.html} for more information. + +The plan is to eventually drop old-style classes, leaving only the semantics of +new-style classes. This change will probably only be feasible in Python 3.0. +\index{class}{new-style} +\index{class}{classic} +\index{class}{old-style} + +%========================================================================= +\section{Special method names\label{specialnames}} + +A class can implement certain operations that are invoked by special +syntax (such as arithmetic operations or subscripting and slicing) by +defining methods with special names.\indexii{operator}{overloading} +This is Python's approach to \dfn{operator overloading}, allowing +classes to define their own behavior with respect to language +operators. For instance, if a class defines +a method named \method{__getitem__()}, and \code{x} is an instance of +this class, then \code{x[i]} is equivalent\footnote{This, and other +statements, are only roughly true for instances of new-style +classes.} to +\code{x.__getitem__(i)}. Except where mentioned, attempts to execute +an operation raise an exception when no appropriate method is defined. +\withsubitem{(mapping object method)}{\ttindex{__getitem__()}} + +When implementing a class that emulates any built-in type, it is +important that the emulation only be implemented to the degree that it +makes sense for the object being modelled. For example, some +sequences may work well with retrieval of individual elements, but +extracting a slice may not make sense. (One example of this is the +\class{NodeList} interface in the W3C's Document Object Model.) + + +\subsection{Basic customization\label{customization}} + +\begin{methoddesc}[object]{__new__}{cls\optional{, \moreargs}} +Called to create a new instance of class \var{cls}. \method{__new__()} +is a static method (special-cased so you need not declare it as such) +that takes the class of which an instance was requested as its first +argument. The remaining arguments are those passed to the object +constructor expression (the call to the class). The return value of +\method{__new__()} should be the new object instance (usually an +instance of \var{cls}). + +Typical implementations create a new instance of the class by invoking +the superclass's \method{__new__()} method using +\samp{super(\var{currentclass}, \var{cls}).__new__(\var{cls}[, ...])} +with appropriate arguments and then modifying the newly-created instance +as necessary before returning it. + +If \method{__new__()} returns an instance of \var{cls}, then the new +instance's \method{__init__()} method will be invoked like +\samp{__init__(\var{self}[, ...])}, where \var{self} is the new instance +and the remaining arguments are the same as were passed to +\method{__new__()}. + +If \method{__new__()} does not return an instance of \var{cls}, then the +new instance's \method{__init__()} method will not be invoked. + +\method{__new__()} is intended mainly to allow subclasses of +immutable types (like int, str, or tuple) to customize instance +creation. +\end{methoddesc} + +\begin{methoddesc}[object]{__init__}{self\optional{, \moreargs}} +Called\indexii{class}{constructor} when the instance is created. The +arguments are those passed to the class constructor expression. If a +base class has an \method{__init__()} method, the derived class's +\method{__init__()} method, if any, must explicitly call it to ensure proper +initialization of the base class part of the instance; for example: +\samp{BaseClass.__init__(\var{self}, [\var{args}...])}. As a special +constraint on constructors, no value may be returned; doing so will +cause a \exception{TypeError} to be raised at runtime. +\end{methoddesc} + + +\begin{methoddesc}[object]{__del__}{self} +Called when the instance is about to be destroyed. This is also +called a destructor\index{destructor}. If a base class +has a \method{__del__()} method, the derived class's \method{__del__()} +method, if any, +must explicitly call it to ensure proper deletion of the base class +part of the instance. Note that it is possible (though not recommended!) +for the \method{__del__()} +method to postpone destruction of the instance by creating a new +reference to it. It may then be called at a later time when this new +reference is deleted. It is not guaranteed that +\method{__del__()} methods are called for objects that still exist when +the interpreter exits. +\stindex{del} + +\begin{notice} +\samp{del x} doesn't directly call +\code{x.__del__()} --- the former decrements the reference count for +\code{x} by one, and the latter is only called when \code{x}'s reference +count reaches zero. Some common situations that may prevent the +reference count of an object from going to zero include: circular +references between objects (e.g., a doubly-linked list or a tree data +structure with parent and child pointers); a reference to the object +on the stack frame of a function that caught an exception (the +traceback stored in \code{sys.exc_traceback} keeps the stack frame +alive); or a reference to the object on the stack frame that raised an +unhandled exception in interactive mode (the traceback stored in +\code{sys.last_traceback} keeps the stack frame alive). The first +situation can only be remedied by explicitly breaking the cycles; the +latter two situations can be resolved by storing \code{None} in +\code{sys.exc_traceback} or \code{sys.last_traceback}. Circular +references which are garbage are detected when the option cycle +detector is enabled (it's on by default), but can only be cleaned up +if there are no Python-level \method{__del__()} methods involved. +Refer to the documentation for the \ulink{\module{gc} +module}{../lib/module-gc.html} for more information about how +\method{__del__()} methods are handled by the cycle detector, +particularly the description of the \code{garbage} value. +\end{notice} + +\begin{notice}[warning] +Due to the precarious circumstances under which +\method{__del__()} methods are invoked, exceptions that occur during their +execution are ignored, and a warning is printed to \code{sys.stderr} +instead. Also, when \method{__del__()} is invoked in response to a module +being deleted (e.g., when execution of the program is done), other +globals referenced by the \method{__del__()} method may already have been +deleted. For this reason, \method{__del__()} methods should do the +absolute minimum needed to maintain external invariants. Starting with +version 1.5, Python guarantees that globals whose name begins with a single +underscore are deleted from their module before other globals are deleted; +if no other references to such globals exist, this may help in assuring that +imported modules are still available at the time when the +\method{__del__()} method is called. +\end{notice} +\end{methoddesc} + +\begin{methoddesc}[object]{__repr__}{self} +Called by the \function{repr()}\bifuncindex{repr} built-in function +and by string conversions (reverse quotes) to compute the ``official'' +string representation of an object. If at all possible, this should +look like a valid Python expression that could be used to recreate an +object with the same value (given an appropriate environment). If +this is not possible, a string of the form \samp{<\var{...some useful +description...}>} should be returned. The return value must be a +string object. +If a class defines \method{__repr__()} but not \method{__str__()}, +then \method{__repr__()} is also used when an ``informal'' string +representation of instances of that class is required. + +This is typically used for debugging, so it is important that the +representation is information-rich and unambiguous. +\indexii{string}{conversion} +\indexii{reverse}{quotes} +\indexii{backward}{quotes} +\index{back-quotes} +\end{methoddesc} + +\begin{methoddesc}[object]{__str__}{self} +Called by the \function{str()}\bifuncindex{str} built-in function and +by the \keyword{print}\stindex{print} statement to compute the +``informal'' string representation of an object. This differs from +\method{__repr__()} in that it does not have to be a valid Python +expression: a more convenient or concise representation may be used +instead. The return value must be a string object. +\end{methoddesc} + +\begin{methoddesc}[object]{__lt__}{self, other} +\methodline[object]{__le__}{self, other} +\methodline[object]{__eq__}{self, other} +\methodline[object]{__ne__}{self, other} +\methodline[object]{__gt__}{self, other} +\methodline[object]{__ge__}{self, other} +\versionadded{2.1} +These are the so-called ``rich comparison'' methods, and are called +for comparison operators in preference to \method{__cmp__()} below. +The correspondence between operator symbols and method names is as +follows: +\code{\var{x}<\var{y}} calls \code{\var{x}.__lt__(\var{y})}, +\code{\var{x}<=\var{y}} calls \code{\var{x}.__le__(\var{y})}, +\code{\var{x}==\var{y}} calls \code{\var{x}.__eq__(\var{y})}, +\code{\var{x}!=\var{y}} and \code{\var{x}<>\var{y}} call +\code{\var{x}.__ne__(\var{y})}, +\code{\var{x}>\var{y}} calls \code{\var{x}.__gt__(\var{y})}, and +\code{\var{x}>=\var{y}} calls \code{\var{x}.__ge__(\var{y})}. + +A rich comparison method may return the singleton \code{NotImplemented} if it +does not implement the operation for a given pair of arguments. +By convention, \code{False} and \code{True} are returned for a successful +comparison. However, these methods can return any value, so if the +comparison operator is used in a Boolean context (e.g., in the condition +of an \code{if} statement), Python will call \function{bool()} on the +value to determine if the result is true or false. + +There are no implied relationships among the comparison operators. +The truth of \code{\var{x}==\var{y}} does not imply that \code{\var{x}!=\var{y}} +is false. Accordingly, when defining \method{__eq__()}, one should also +define \method{__ne__()} so that the operators will behave as expected. + +There are no reflected (swapped-argument) versions of these methods +(to be used when the left argument does not support the operation but +the right argument does); rather, \method{__lt__()} and +\method{__gt__()} are each other's reflection, \method{__le__()} and +\method{__ge__()} are each other's reflection, and \method{__eq__()} +and \method{__ne__()} are their own reflection. + +Arguments to rich comparison methods are never coerced. +\end{methoddesc} + +\begin{methoddesc}[object]{__cmp__}{self, other} +Called by comparison operations if rich comparison (see above) is not +defined. Should return a negative integer if \code{self < other}, +zero if \code{self == other}, a positive integer if \code{self > +other}. If no \method{__cmp__()}, \method{__eq__()} or +\method{__ne__()} operation is defined, class instances are compared +by object identity (``address''). See also the description of +\method{__hash__()} for some important notes on creating objects which +support custom comparison operations and are usable as dictionary +keys. +(Note: the restriction that exceptions are not propagated by +\method{__cmp__()} has been removed since Python 1.5.) +\bifuncindex{cmp} +\index{comparisons} +\end{methoddesc} + +\begin{methoddesc}[object]{__rcmp__}{self, other} + \versionchanged[No longer supported]{2.1} +\end{methoddesc} + +\begin{methoddesc}[object]{__hash__}{self} +Called for the key object for dictionary \obindex{dictionary} +operations, and by the built-in function +\function{hash()}\bifuncindex{hash}. Should return a 32-bit integer +usable as a hash value +for dictionary operations. The only required property is that objects +which compare equal have the same hash value; it is advised to somehow +mix together (e.g., using exclusive or) the hash values for the +components of the object that also play a part in comparison of +objects. If a class does not define a \method{__cmp__()} method it should +not define a \method{__hash__()} operation either; if it defines +\method{__cmp__()} or \method{__eq__()} but not \method{__hash__()}, +its instances will not be usable as dictionary keys. If a class +defines mutable objects and implements a \method{__cmp__()} or +\method{__eq__()} method, it should not implement \method{__hash__()}, +since the dictionary implementation requires that a key's hash value +is immutable (if the object's hash value changes, it will be in the +wrong hash bucket). + +\versionchanged[\method{__hash__()} may now also return a long +integer object; the 32-bit integer is then derived from the hash +of that object]{2.5} + +\withsubitem{(object method)}{\ttindex{__cmp__()}} +\end{methoddesc} + +\begin{methoddesc}[object]{__nonzero__}{self} +Called to implement truth value testing, and the built-in operation +\code{bool()}; should return \code{False} or \code{True}, or their +integer equivalents \code{0} or \code{1}. +When this method is not defined, \method{__len__()} is +called, if it is defined (see below). If a class defines neither +\method{__len__()} nor \method{__nonzero__()}, all its instances are +considered true. +\withsubitem{(mapping object method)}{\ttindex{__len__()}} +\end{methoddesc} + +\begin{methoddesc}[object]{__unicode__}{self} +Called to implement \function{unicode()}\bifuncindex{unicode} builtin; +should return a Unicode object. When this method is not defined, string +conversion is attempted, and the result of string conversion is converted +to Unicode using the system default encoding. +\end{methoddesc} + + +\subsection{Customizing attribute access\label{attribute-access}} + +The following methods can be defined to customize the meaning of +attribute access (use of, assignment to, or deletion of \code{x.name}) +for class instances. + +\begin{methoddesc}[object]{__getattr__}{self, name} +Called when an attribute lookup has not found the attribute in the +usual places (i.e. it is not an instance attribute nor is it found in +the class tree for \code{self}). \code{name} is the attribute name. +This method should return the (computed) attribute value or raise an +\exception{AttributeError} exception. + +Note that if the attribute is found through the normal mechanism, +\method{__getattr__()} is not called. (This is an intentional +asymmetry between \method{__getattr__()} and \method{__setattr__()}.) +This is done both for efficiency reasons and because otherwise +\method{__setattr__()} would have no way to access other attributes of +the instance. Note that at least for instance variables, you can fake +total control by not inserting any values in the instance attribute +dictionary (but instead inserting them in another object). See the +\method{__getattribute__()} method below for a way to actually get +total control in new-style classes. +\withsubitem{(object method)}{\ttindex{__setattr__()}} +\end{methoddesc} + +\begin{methoddesc}[object]{__setattr__}{self, name, value} +Called when an attribute assignment is attempted. This is called +instead of the normal mechanism (i.e.\ store the value in the instance +dictionary). \var{name} is the attribute name, \var{value} is the +value to be assigned to it. + +If \method{__setattr__()} wants to assign to an instance attribute, it +should not simply execute \samp{self.\var{name} = value} --- this +would cause a recursive call to itself. Instead, it should insert the +value in the dictionary of instance attributes, e.g., +\samp{self.__dict__[\var{name}] = value}. For new-style classes, +rather than accessing the instance dictionary, it should call the base +class method with the same name, for example, +\samp{object.__setattr__(self, name, value)}. +\withsubitem{(instance attribute)}{\ttindex{__dict__}} +\end{methoddesc} + +\begin{methoddesc}[object]{__delattr__}{self, name} +Like \method{__setattr__()} but for attribute deletion instead of +assignment. This should only be implemented if \samp{del +obj.\var{name}} is meaningful for the object. +\end{methoddesc} + +\subsubsection{More attribute access for new-style classes \label{new-style-attribute-access}} + +The following methods only apply to new-style classes. + +\begin{methoddesc}[object]{__getattribute__}{self, name} +Called unconditionally to implement attribute accesses for instances +of the class. If the class also defines \method{__getattr__()}, the latter +will not be called unless \method{__getattribute__()} either calls it +explicitly or raises an \exception{AttributeError}. +This method should return the (computed) attribute +value or raise an \exception{AttributeError} exception. +In order to avoid infinite recursion in this method, its +implementation should always call the base class method with the same +name to access any attributes it needs, for example, +\samp{object.__getattribute__(self, name)}. +\end{methoddesc} + +\subsubsection{Implementing Descriptors \label{descriptors}} + +The following methods only apply when an instance of the class +containing the method (a so-called \emph{descriptor} class) appears in +the class dictionary of another new-style class, known as the +\emph{owner} class. In the examples below, ``the attribute'' refers to +the attribute whose name is the key of the property in the owner +class' \code{__dict__}. Descriptors can only be implemented as +new-style classes themselves. + +\begin{methoddesc}[object]{__get__}{self, instance, owner} +Called to get the attribute of the owner class (class attribute access) +or of an instance of that class (instance attribute access). +\var{owner} is always the owner class, while \var{instance} is the +instance that the attribute was accessed through, or \code{None} when +the attribute is accessed through the \var{owner}. This method should +return the (computed) attribute value or raise an +\exception{AttributeError} exception. +\end{methoddesc} + +\begin{methoddesc}[object]{__set__}{self, instance, value} +Called to set the attribute on an instance \var{instance} of the owner +class to a new value, \var{value}. +\end{methoddesc} + +\begin{methoddesc}[object]{__delete__}{self, instance} +Called to delete the attribute on an instance \var{instance} of the +owner class. +\end{methoddesc} + + +\subsubsection{Invoking Descriptors \label{descriptor-invocation}} + +In general, a descriptor is an object attribute with ``binding behavior'', +one whose attribute access has been overridden by methods in the descriptor +protocol: \method{__get__()}, \method{__set__()}, and \method{__delete__()}. +If any of those methods are defined for an object, it is said to be a +descriptor. + +The default behavior for attribute access is to get, set, or delete the +attribute from an object's dictionary. For instance, \code{a.x} has a +lookup chain starting with \code{a.__dict__['x']}, then +\code{type(a).__dict__['x']}, and continuing +through the base classes of \code{type(a)} excluding metaclasses. + +However, if the looked-up value is an object defining one of the descriptor +methods, then Python may override the default behavior and invoke the +descriptor method instead. Where this occurs in the precedence chain depends +on which descriptor methods were defined and how they were called. Note that +descriptors are only invoked for new style objects or classes +(ones that subclass \class{object()} or \class{type()}). + +The starting point for descriptor invocation is a binding, \code{a.x}. +How the arguments are assembled depends on \code{a}: + +\begin{itemize} + + \item[Direct Call] The simplest and least common call is when user code + directly invokes a descriptor method: \code{x.__get__(a)}. + + \item[Instance Binding] If binding to a new-style object instance, + \code{a.x} is transformed into the call: + \code{type(a).__dict__['x'].__get__(a, type(a))}. + + \item[Class Binding] If binding to a new-style class, \code{A.x} + is transformed into the call: \code{A.__dict__['x'].__get__(None, A)}. + + \item[Super Binding] If \code{a} is an instance of \class{super}, + then the binding \code{super(B, obj).m()} searches + \code{obj.__class__.__mro__} for the base class \code{A} immediately + preceding \code{B} and then invokes the descriptor with the call: + \code{A.__dict__['m'].__get__(obj, A)}. + +\end{itemize} + +For instance bindings, the precedence of descriptor invocation depends +on the which descriptor methods are defined. Data descriptors define +both \method{__get__()} and \method{__set__()}. Non-data descriptors have +just the \method{__get__()} method. Data descriptors always override +a redefinition in an instance dictionary. In contrast, non-data +descriptors can be overridden by instances. + +Python methods (including \function{staticmethod()} and \function{classmethod()}) +are implemented as non-data descriptors. Accordingly, instances can +redefine and override methods. This allows individual instances to acquire +behaviors that differ from other instances of the same class. + +The \function{property()} function is implemented as a data descriptor. +Accordingly, instances cannot override the behavior of a property. + + +\subsubsection{__slots__\label{slots}} + +By default, instances of both old and new-style classes have a dictionary +for attribute storage. This wastes space for objects having very few instance +variables. The space consumption can become acute when creating large numbers +of instances. + +The default can be overridden by defining \var{__slots__} in a new-style class +definition. The \var{__slots__} declaration takes a sequence of instance +variables and reserves just enough space in each instance to hold a value +for each variable. Space is saved because \var{__dict__} is not created for +each instance. + +\begin{datadesc}{__slots__} +This class variable can be assigned a string, iterable, or sequence of strings +with variable names used by instances. If defined in a new-style class, +\var{__slots__} reserves space for the declared variables +and prevents the automatic creation of \var{__dict__} and \var{__weakref__} +for each instance. +\versionadded{2.2} +\end{datadesc} + +\noindent +Notes on using \var{__slots__} + +\begin{itemize} + +\item Without a \var{__dict__} variable, instances cannot be assigned new +variables not listed in the \var{__slots__} definition. Attempts to assign +to an unlisted variable name raises \exception{AttributeError}. If dynamic +assignment of new variables is desired, then add \code{'__dict__'} to the +sequence of strings in the \var{__slots__} declaration. +\versionchanged[Previously, adding \code{'__dict__'} to the \var{__slots__} +declaration would not enable the assignment of new attributes not +specifically listed in the sequence of instance variable names]{2.3} + +\item Without a \var{__weakref__} variable for each instance, classes +defining \var{__slots__} do not support weak references to its instances. +If weak reference support is needed, then add \code{'__weakref__'} to the +sequence of strings in the \var{__slots__} declaration. +\versionchanged[Previously, adding \code{'__weakref__'} to the \var{__slots__} +declaration would not enable support for weak references]{2.3} + +\item \var{__slots__} are implemented at the class level by creating +descriptors (\ref{descriptors}) for each variable name. As a result, +class attributes cannot be used to set default values for instance +variables defined by \var{__slots__}; otherwise, the class attribute would +overwrite the descriptor assignment. + +\item If a class defines a slot also defined in a base class, the instance +variable defined by the base class slot is inaccessible (except by retrieving +its descriptor directly from the base class). This renders the meaning of the +program undefined. In the future, a check may be added to prevent this. + +\item The action of a \var{__slots__} declaration is limited to the class +where it is defined. As a result, subclasses will have a \var{__dict__} +unless they also define \var{__slots__}. + +\item \var{__slots__} do not work for classes derived from ``variable-length'' +built-in types such as \class{long}, \class{str} and \class{tuple}. + +\item Any non-string iterable may be assigned to \var{__slots__}. +Mappings may also be used; however, in the future, special meaning may +be assigned to the values corresponding to each key. + +\end{itemize} + + +\subsection{Customizing class creation\label{metaclasses}} + +By default, new-style classes are constructed using \function{type()}. +A class definition is read into a separate namespace and the value +of class name is bound to the result of \code{type(name, bases, dict)}. + +When the class definition is read, if \var{__metaclass__} is defined +then the callable assigned to it will be called instead of \function{type()}. +The allows classes or functions to be written which monitor or alter the class +creation process: + +\begin{itemize} +\item Modifying the class dictionary prior to the class being created. +\item Returning an instance of another class -- essentially performing +the role of a factory function. +\end{itemize} + +\begin{datadesc}{__metaclass__} +This variable can be any callable accepting arguments for \code{name}, +\code{bases}, and \code{dict}. Upon class creation, the callable is +used instead of the built-in \function{type()}. +\versionadded{2.2} +\end{datadesc} + +The appropriate metaclass is determined by the following precedence rules: + +\begin{itemize} + +\item If \code{dict['__metaclass__']} exists, it is used. + +\item Otherwise, if there is at least one base class, its metaclass is used +(this looks for a \var{__class__} attribute first and if not found, uses its +type). + +\item Otherwise, if a global variable named __metaclass__ exists, it is used. + +\item Otherwise, the old-style, classic metaclass (types.ClassType) is used. + +\end{itemize} + +The potential uses for metaclasses are boundless. Some ideas that have +been explored including logging, interface checking, automatic delegation, +automatic property creation, proxies, frameworks, and automatic resource +locking/synchronization. + + +\subsection{Emulating callable objects\label{callable-types}} + +\begin{methoddesc}[object]{__call__}{self\optional{, args...}} +Called when the instance is ``called'' as a function; if this method +is defined, \code{\var{x}(arg1, arg2, ...)} is a shorthand for +\code{\var{x}.__call__(arg1, arg2, ...)}. +\indexii{call}{instance} +\end{methoddesc} + + +\subsection{Emulating container types\label{sequence-types}} + +The following methods can be defined to implement container +objects. Containers usually are sequences (such as lists or tuples) +or mappings (like dictionaries), but can represent other containers as +well. The first set of methods is used either to emulate a +sequence or to emulate a mapping; the difference is that for a +sequence, the allowable keys should be the integers \var{k} for which +\code{0 <= \var{k} < \var{N}} where \var{N} is the length of the +sequence, or slice objects, which define a range of items. (For backwards +compatibility, the method \method{__getslice__()} (see below) can also be +defined to handle simple, but not extended slices.) It is also recommended +that mappings provide the methods \method{keys()}, \method{values()}, +\method{items()}, \method{has_key()}, \method{get()}, \method{clear()}, +\method{setdefault()}, \method{iterkeys()}, \method{itervalues()}, +\method{iteritems()}, \method{pop()}, \method{popitem()}, +\method{copy()}, and \method{update()} behaving similar to those for +Python's standard dictionary objects. The \module{UserDict} module +provides a \class{DictMixin} class to help create those methods +from a base set of \method{__getitem__()}, \method{__setitem__()}, +\method{__delitem__()}, and \method{keys()}. +Mutable sequences should provide +methods \method{append()}, \method{count()}, \method{index()}, +\method{extend()}, +\method{insert()}, \method{pop()}, \method{remove()}, \method{reverse()} +and \method{sort()}, like Python standard list objects. Finally, +sequence types should implement addition (meaning concatenation) and +multiplication (meaning repetition) by defining the methods +\method{__add__()}, \method{__radd__()}, \method{__iadd__()}, +\method{__mul__()}, \method{__rmul__()} and \method{__imul__()} described +below; they should not define \method{__coerce__()} or other numerical +operators. It is recommended that both mappings and sequences +implement the \method{__contains__()} method to allow efficient use of +the \code{in} operator; for mappings, \code{in} should be equivalent +of \method{has_key()}; for sequences, it should search through the +values. It is further recommended that both mappings and sequences +implement the \method{__iter__()} method to allow efficient iteration +through the container; for mappings, \method{__iter__()} should be +the same as \method{iterkeys()}; for sequences, it should iterate +through the values. +\withsubitem{(mapping object method)}{ + \ttindex{keys()} + \ttindex{values()} + \ttindex{items()} + \ttindex{iterkeys()} + \ttindex{itervalues()} + \ttindex{iteritems()} + \ttindex{has_key()} + \ttindex{get()} + \ttindex{setdefault()} + \ttindex{pop()} + \ttindex{popitem()} + \ttindex{clear()} + \ttindex{copy()} + \ttindex{update()} + \ttindex{__contains__()}} +\withsubitem{(sequence object method)}{ + \ttindex{append()} + \ttindex{count()} + \ttindex{extend()} + \ttindex{index()} + \ttindex{insert()} + \ttindex{pop()} + \ttindex{remove()} + \ttindex{reverse()} + \ttindex{sort()} + \ttindex{__add__()} + \ttindex{__radd__()} + \ttindex{__iadd__()} + \ttindex{__mul__()} + \ttindex{__rmul__()} + \ttindex{__imul__()} + \ttindex{__contains__()} + \ttindex{__iter__()}} +\withsubitem{(numeric object method)}{\ttindex{__coerce__()}} + +\begin{methoddesc}[container object]{__len__}{self} +Called to implement the built-in function +\function{len()}\bifuncindex{len}. Should return the length of the +object, an integer \code{>=} 0. Also, an object that doesn't define a +\method{__nonzero__()} method and whose \method{__len__()} method +returns zero is considered to be false in a Boolean context. +\withsubitem{(object method)}{\ttindex{__nonzero__()}} +\end{methoddesc} + +\begin{methoddesc}[container object]{__getitem__}{self, key} +Called to implement evaluation of \code{\var{self}[\var{key}]}. +For sequence types, the accepted keys should be integers and slice +objects.\obindex{slice} Note that +the special interpretation of negative indexes (if the class wishes to +emulate a sequence type) is up to the \method{__getitem__()} method. +If \var{key} is of an inappropriate type, \exception{TypeError} may be +raised; if of a value outside the set of indexes for the sequence +(after any special interpretation of negative values), +\exception{IndexError} should be raised. +For mapping types, if \var{key} is missing (not in the container), +\exception{KeyError} should be raised. +\note{\keyword{for} loops expect that an +\exception{IndexError} will be raised for illegal indexes to allow +proper detection of the end of the sequence.} +\end{methoddesc} + +\begin{methoddesc}[container object]{__setitem__}{self, key, value} +Called to implement assignment to \code{\var{self}[\var{key}]}. Same +note as for \method{__getitem__()}. This should only be implemented +for mappings if the objects support changes to the values for keys, or +if new keys can be added, or for sequences if elements can be +replaced. The same exceptions should be raised for improper +\var{key} values as for the \method{__getitem__()} method. +\end{methoddesc} + +\begin{methoddesc}[container object]{__delitem__}{self, key} +Called to implement deletion of \code{\var{self}[\var{key}]}. Same +note as for \method{__getitem__()}. This should only be implemented +for mappings if the objects support removal of keys, or for sequences +if elements can be removed from the sequence. The same exceptions +should be raised for improper \var{key} values as for the +\method{__getitem__()} method. +\end{methoddesc} + +\begin{methoddesc}[container object]{__iter__}{self} +This method is called when an iterator is required for a container. +This method should return a new iterator object that can iterate over +all the objects in the container. For mappings, it should iterate +over the keys of the container, and should also be made available as +the method \method{iterkeys()}. + +Iterator objects also need to implement this method; they are required +to return themselves. For more information on iterator objects, see +``\ulink{Iterator Types}{../lib/typeiter.html}'' in the +\citetitle[../lib/lib.html]{Python Library Reference}. +\end{methoddesc} + +The membership test operators (\keyword{in} and \keyword{not in}) are +normally implemented as an iteration through a sequence. However, +container objects can supply the following special method with a more +efficient implementation, which also does not require the object be a +sequence. + +\begin{methoddesc}[container object]{__contains__}{self, item} +Called to implement membership test operators. Should return true if +\var{item} is in \var{self}, false otherwise. For mapping objects, +this should consider the keys of the mapping rather than the values or +the key-item pairs. +\end{methoddesc} + + +\subsection{Additional methods for emulation of sequence types + \label{sequence-methods}} + +The following optional methods can be defined to further emulate sequence +objects. Immutable sequences methods should at most only define +\method{__getslice__()}; mutable sequences might define all three +methods. + +\begin{methoddesc}[sequence object]{__getslice__}{self, i, j} +\deprecated{2.0}{Support slice objects as parameters to the +\method{__getitem__()} method.} +Called to implement evaluation of \code{\var{self}[\var{i}:\var{j}]}. +The returned object should be of the same type as \var{self}. Note +that missing \var{i} or \var{j} in the slice expression are replaced +by zero or \code{sys.maxint}, respectively. If negative indexes are +used in the slice, the length of the sequence is added to that index. +If the instance does not implement the \method{__len__()} method, an +\exception{AttributeError} is raised. +No guarantee is made that indexes adjusted this way are not still +negative. Indexes which are greater than the length of the sequence +are not modified. +If no \method{__getslice__()} is found, a slice +object is created instead, and passed to \method{__getitem__()} instead. +\end{methoddesc} + +\begin{methoddesc}[sequence object]{__setslice__}{self, i, j, sequence} +Called to implement assignment to \code{\var{self}[\var{i}:\var{j}]}. +Same notes for \var{i} and \var{j} as for \method{__getslice__()}. + +This method is deprecated. If no \method{__setslice__()} is found, +or for extended slicing of the form +\code{\var{self}[\var{i}:\var{j}:\var{k}]}, a +slice object is created, and passed to \method{__setitem__()}, +instead of \method{__setslice__()} being called. +\end{methoddesc} + +\begin{methoddesc}[sequence object]{__delslice__}{self, i, j} +Called to implement deletion of \code{\var{self}[\var{i}:\var{j}]}. +Same notes for \var{i} and \var{j} as for \method{__getslice__()}. +This method is deprecated. If no \method{__delslice__()} is found, +or for extended slicing of the form +\code{\var{self}[\var{i}:\var{j}:\var{k}]}, a +slice object is created, and passed to \method{__delitem__()}, +instead of \method{__delslice__()} being called. +\end{methoddesc} + +Notice that these methods are only invoked when a single slice with a +single colon is used, and the slice method is available. For slice +operations involving extended slice notation, or in absence of the +slice methods, \method{__getitem__()}, \method{__setitem__()} or +\method{__delitem__()} is called with a slice object as argument. + +The following example demonstrate how to make your program or module +compatible with earlier versions of Python (assuming that methods +\method{__getitem__()}, \method{__setitem__()} and \method{__delitem__()} +support slice objects as arguments): + +\begin{verbatim} +class MyClass: + ... + def __getitem__(self, index): + ... + def __setitem__(self, index, value): + ... + def __delitem__(self, index): + ... + + if sys.version_info < (2, 0): + # They won't be defined if version is at least 2.0 final + + def __getslice__(self, i, j): + return self[max(0, i):max(0, j):] + def __setslice__(self, i, j, seq): + self[max(0, i):max(0, j):] = seq + def __delslice__(self, i, j): + del self[max(0, i):max(0, j):] + ... +\end{verbatim} + +Note the calls to \function{max()}; these are necessary because of +the handling of negative indices before the +\method{__*slice__()} methods are called. When negative indexes are +used, the \method{__*item__()} methods receive them as provided, but +the \method{__*slice__()} methods get a ``cooked'' form of the index +values. For each negative index value, the length of the sequence is +added to the index before calling the method (which may still result +in a negative index); this is the customary handling of negative +indexes by the built-in sequence types, and the \method{__*item__()} +methods are expected to do this as well. However, since they should +already be doing that, negative indexes cannot be passed in; they must +be constrained to the bounds of the sequence before being passed to +the \method{__*item__()} methods. +Calling \code{max(0, i)} conveniently returns the proper value. + + +\subsection{Emulating numeric types\label{numeric-types}} + +The following methods can be defined to emulate numeric objects. +Methods corresponding to operations that are not supported by the +particular kind of number implemented (e.g., bitwise operations for +non-integral numbers) should be left undefined. + +\begin{methoddesc}[numeric object]{__add__}{self, other} +\methodline[numeric object]{__sub__}{self, other} +\methodline[numeric object]{__mul__}{self, other} +\methodline[numeric object]{__floordiv__}{self, other} +\methodline[numeric object]{__mod__}{self, other} +\methodline[numeric object]{__divmod__}{self, other} +\methodline[numeric object]{__pow__}{self, other\optional{, modulo}} +\methodline[numeric object]{__lshift__}{self, other} +\methodline[numeric object]{__rshift__}{self, other} +\methodline[numeric object]{__and__}{self, other} +\methodline[numeric object]{__xor__}{self, other} +\methodline[numeric object]{__or__}{self, other} +These methods are +called to implement the binary arithmetic operations (\code{+}, +\code{-}, \code{*}, \code{//}, \code{\%}, +\function{divmod()}\bifuncindex{divmod}, +\function{pow()}\bifuncindex{pow}, \code{**}, \code{<<}, +\code{>>}, \code{\&}, \code{\^}, \code{|}). For instance, to +evaluate the expression \var{x}\code{+}\var{y}, where \var{x} is an +instance of a class that has an \method{__add__()} method, +\code{\var{x}.__add__(\var{y})} is called. The \method{__divmod__()} +method should be the equivalent to using \method{__floordiv__()} and +\method{__mod__()}; it should not be related to \method{__truediv__()} +(described below). Note that +\method{__pow__()} should be defined to accept an optional third +argument if the ternary version of the built-in +\function{pow()}\bifuncindex{pow} function is to be supported. + +If one of those methods does not support the operation with the +supplied arguments, it should return \code{NotImplemented}. +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__div__}{self, other} +\methodline[numeric object]{__truediv__}{self, other} +The division operator (\code{/}) is implemented by these methods. The +\method{__truediv__()} method is used when \code{__future__.division} +is in effect, otherwise \method{__div__()} is used. If only one of +these two methods is defined, the object will not support division in +the alternate context; \exception{TypeError} will be raised instead. +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__radd__}{self, other} +\methodline[numeric object]{__rsub__}{self, other} +\methodline[numeric object]{__rmul__}{self, other} +\methodline[numeric object]{__rdiv__}{self, other} +\methodline[numeric object]{__rtruediv__}{self, other} +\methodline[numeric object]{__rfloordiv__}{self, other} +\methodline[numeric object]{__rmod__}{self, other} +\methodline[numeric object]{__rdivmod__}{self, other} +\methodline[numeric object]{__rpow__}{self, other} +\methodline[numeric object]{__rlshift__}{self, other} +\methodline[numeric object]{__rrshift__}{self, other} +\methodline[numeric object]{__rand__}{self, other} +\methodline[numeric object]{__rxor__}{self, other} +\methodline[numeric object]{__ror__}{self, other} +These methods are +called to implement the binary arithmetic operations (\code{+}, +\code{-}, \code{*}, \code{/}, \code{\%}, +\function{divmod()}\bifuncindex{divmod}, +\function{pow()}\bifuncindex{pow}, \code{**}, \code{<<}, +\code{>>}, \code{\&}, \code{\^}, \code{|}) with reflected +(swapped) operands. These functions are only called if the left +operand does not support the corresponding operation and the +operands are of different types.\footnote{ + For operands of the same type, it is assumed that if the + non-reflected method (such as \method{__add__()}) fails the + operation is not supported, which is why the reflected method + is not called.} +For instance, to evaluate the expression \var{x}\code{-}\var{y}, +where \var{y} is an instance of a class that has an +\method{__rsub__()} method, \code{\var{y}.__rsub__(\var{x})} +is called if \code{\var{x}.__sub__(\var{y})} returns +\var{NotImplemented}. + +Note that ternary +\function{pow()}\bifuncindex{pow} will not try calling +\method{__rpow__()} (the coercion rules would become too +complicated). + +\note{If the right operand's type is a subclass of the left operand's + type and that subclass provides the reflected method for the + operation, this method will be called before the left operand's + non-reflected method. This behavior allows subclasses to + override their ancestors' operations.} +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__iadd__}{self, other} +\methodline[numeric object]{__isub__}{self, other} +\methodline[numeric object]{__imul__}{self, other} +\methodline[numeric object]{__idiv__}{self, other} +\methodline[numeric object]{__itruediv__}{self, other} +\methodline[numeric object]{__ifloordiv__}{self, other} +\methodline[numeric object]{__imod__}{self, other} +\methodline[numeric object]{__ipow__}{self, other\optional{, modulo}} +\methodline[numeric object]{__ilshift__}{self, other} +\methodline[numeric object]{__irshift__}{self, other} +\methodline[numeric object]{__iand__}{self, other} +\methodline[numeric object]{__ixor__}{self, other} +\methodline[numeric object]{__ior__}{self, other} +These methods are called to implement the augmented arithmetic +operations (\code{+=}, \code{-=}, \code{*=}, \code{/=}, \code{//=}, +\code{\%=}, \code{**=}, \code{<<=}, \code{>>=}, \code{\&=}, +\code{\textasciicircum=}, \code{|=}). These methods should attempt to do the +operation in-place (modifying \var{self}) and return the result (which +could be, but does not have to be, \var{self}). If a specific method +is not defined, the augmented operation falls back to the normal +methods. For instance, to evaluate the expression +\var{x}\code{+=}\var{y}, where \var{x} is an instance of a class that +has an \method{__iadd__()} method, \code{\var{x}.__iadd__(\var{y})} is +called. If \var{x} is an instance of a class that does not define a +\method{__iadd__()} method, \code{\var{x}.__add__(\var{y})} and +\code{\var{y}.__radd__(\var{x})} are considered, as with the +evaluation of \var{x}\code{+}\var{y}. +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__neg__}{self} +\methodline[numeric object]{__pos__}{self} +\methodline[numeric object]{__abs__}{self} +\methodline[numeric object]{__invert__}{self} +Called to implement the unary arithmetic operations (\code{-}, +\code{+}, \function{abs()}\bifuncindex{abs} and \code{\~{}}). +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__complex__}{self} +\methodline[numeric object]{__int__}{self} +\methodline[numeric object]{__long__}{self} +\methodline[numeric object]{__float__}{self} +Called to implement the built-in functions +\function{complex()}\bifuncindex{complex}, +\function{int()}\bifuncindex{int}, \function{long()}\bifuncindex{long}, +and \function{float()}\bifuncindex{float}. Should return a value of +the appropriate type. +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__oct__}{self} +\methodline[numeric object]{__hex__}{self} +Called to implement the built-in functions +\function{oct()}\bifuncindex{oct} and +\function{hex()}\bifuncindex{hex}. Should return a string value. +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__index__}{self} +Called to implement \function{operator.index()}. Also called whenever +Python needs an integer object (such as in slicing). Must return an +integer (int or long). +\versionadded{2.5} +\end{methoddesc} + +\begin{methoddesc}[numeric object]{__coerce__}{self, other} +Called to implement ``mixed-mode'' numeric arithmetic. Should either +return a 2-tuple containing \var{self} and \var{other} converted to +a common numeric type, or \code{None} if conversion is impossible. When +the common type would be the type of \code{other}, it is sufficient to +return \code{None}, since the interpreter will also ask the other +object to attempt a coercion (but sometimes, if the implementation of +the other type cannot be changed, it is useful to do the conversion to +the other type here). A return value of \code{NotImplemented} is +equivalent to returning \code{None}. +\end{methoddesc} + +\subsection{Coercion rules\label{coercion-rules}} + +This section used to document the rules for coercion. As the language +has evolved, the coercion rules have become hard to document +precisely; documenting what one version of one particular +implementation does is undesirable. Instead, here are some informal +guidelines regarding coercion. In Python 3.0, coercion will not be +supported. + +\begin{itemize} + +\item + +If the left operand of a \% operator is a string or Unicode object, no +coercion takes place and the string formatting operation is invoked +instead. + +\item + +It is no longer recommended to define a coercion operation. +Mixed-mode operations on types that don't define coercion pass the +original arguments to the operation. + +\item + +New-style classes (those derived from \class{object}) never invoke the +\method{__coerce__()} method in response to a binary operator; the only +time \method{__coerce__()} is invoked is when the built-in function +\function{coerce()} is called. + +\item + +For most intents and purposes, an operator that returns +\code{NotImplemented} is treated the same as one that is not +implemented at all. + +\item + +Below, \method{__op__()} and \method{__rop__()} are used to signify +the generic method names corresponding to an operator; +\method{__iop__()} is used for the corresponding in-place operator. For +example, for the operator `\code{+}', \method{__add__()} and +\method{__radd__()} are used for the left and right variant of the +binary operator, and \method{__iadd__()} for the in-place variant. + +\item + +For objects \var{x} and \var{y}, first \code{\var{x}.__op__(\var{y})} +is tried. If this is not implemented or returns \code{NotImplemented}, +\code{\var{y}.__rop__(\var{x})} is tried. If this is also not +implemented or returns \code{NotImplemented}, a \exception{TypeError} +exception is raised. But see the following exception: + +\item + +Exception to the previous item: if the left operand is an instance of +a built-in type or a new-style class, and the right operand is an instance +of a proper subclass of that type or class and overrides the base's +\method{__rop__()} method, the right operand's \method{__rop__()} method +is tried \emph{before} the left operand's \method{__op__()} method. + +This is done so that a subclass can completely override binary operators. +Otherwise, the left operand's \method{__op__()} method would always +accept the right operand: when an instance of a given class is expected, +an instance of a subclass of that class is always acceptable. + +\item + +When either operand type defines a coercion, this coercion is called +before that type's \method{__op__()} or \method{__rop__()} method is +called, but no sooner. If the coercion returns an object of a +different type for the operand whose coercion is invoked, part of the +process is redone using the new object. + +\item + +When an in-place operator (like `\code{+=}') is used, if the left +operand implements \method{__iop__()}, it is invoked without any +coercion. When the operation falls back to \method{__op__()} and/or +\method{__rop__()}, the normal coercion rules apply. + +\item + +In \var{x}\code{+}\var{y}, if \var{x} is a sequence that implements +sequence concatenation, sequence concatenation is invoked. + +\item + +In \var{x}\code{*}\var{y}, if one operator is a sequence that +implements sequence repetition, and the other is an integer +(\class{int} or \class{long}), sequence repetition is invoked. + +\item + +Rich comparisons (implemented by methods \method{__eq__()} and so on) +never use coercion. Three-way comparison (implemented by +\method{__cmp__()}) does use coercion under the same conditions as +other binary operations use it. + +\item + +In the current implementation, the built-in numeric types \class{int}, +\class{long} and \class{float} do not use coercion; the type +\class{complex} however does use it. The difference can become +apparent when subclassing these types. Over time, the type +\class{complex} may be fixed to avoid coercion. All these types +implement a \method{__coerce__()} method, for use by the built-in +\function{coerce()} function. + +\end{itemize} + +\subsection{With Statement Context Managers\label{context-managers}} + +\versionadded{2.5} + +A \dfn{context manager} is an object that defines the runtime +context to be established when executing a \keyword{with} +statement. The context manager handles the entry into, +and the exit from, the desired runtime context for the execution +of the block of code. Context managers are normally invoked using +the \keyword{with} statement (described in section~\ref{with}), but +can also be used by directly invoking their methods. + +\stindex{with} +\index{context manager} + +Typical uses of context managers include saving and +restoring various kinds of global state, locking and unlocking +resources, closing opened files, etc. + +For more information on context managers, see +``\ulink{Context Types}{../lib/typecontextmanager.html}'' in the +\citetitle[../lib/lib.html]{Python Library Reference}. + +\begin{methoddesc}[context manager]{__enter__}{self} +Enter the runtime context related to this object. The \keyword{with} +statement will bind this method's return value to the target(s) +specified in the \keyword{as} clause of the statement, if any. +\end{methoddesc} + +\begin{methoddesc}[context manager]{__exit__} +{self, exc_type, exc_value, traceback} +Exit the runtime context related to this object. The parameters +describe the exception that caused the context to be exited. If +the context was exited without an exception, all three arguments +will be \constant{None}. + +If an exception is supplied, and the method wishes to suppress the +exception (i.e., prevent it from being propagated), it should return a +true value. Otherwise, the exception will be processed normally upon +exit from this method. + +Note that \method{__exit__} methods should not reraise the passed-in +exception; this is the caller's responsibility. +\end{methoddesc} + +\begin{seealso} + \seepep{0343}{The "with" statement} + {The specification, background, and examples for the + Python \keyword{with} statement.} +\end{seealso} + diff --git a/sys/src/cmd/python/Doc/ref/ref4.tex b/sys/src/cmd/python/Doc/ref/ref4.tex new file mode 100644 index 000000000..12a2b92e1 --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref4.tex @@ -0,0 +1,219 @@ +\chapter{Execution model \label{execmodel}} +\index{execution model} + + +\section{Naming and binding \label{naming}} +\indexii{code}{block} +\index{namespace} +\index{scope} + +\dfn{Names}\index{name} refer to objects. Names are introduced by +name binding operations. Each occurrence of a name in the program +text refers to the \dfn{binding}\indexii{binding}{name} of that name +established in the innermost function block containing the use. + +A \dfn{block}\index{block} is a piece of Python program text that is +executed as a unit. The following are blocks: a module, a function +body, and a class definition. Each command typed interactively is a +block. A script file (a file given as standard input to the +interpreter or specified on the interpreter command line the first +argument) is a code block. A script command (a command specified on +the interpreter command line with the `\strong{-c}' option) is a code +block. The file read by the built-in function \function{execfile()} +is a code block. The string argument passed to the built-in function +\function{eval()} and to the \keyword{exec} statement is a code block. +The expression read and evaluated by the built-in function +\function{input()} is a code block. + +A code block is executed in an \dfn{execution +frame}\indexii{execution}{frame}. A frame contains some +administrative information (used for debugging) and determines where +and how execution continues after the code block's execution has +completed. + +A \dfn{scope}\index{scope} defines the visibility of a name within a +block. If a local variable is defined in a block, its scope includes +that block. If the definition occurs in a function block, the scope +extends to any blocks contained within the defining one, unless a +contained block introduces a different binding for the name. The +scope of names defined in a class block is limited to the class block; +it does not extend to the code blocks of methods. + +When a name is used in a code block, it is resolved using the nearest +enclosing scope. The set of all such scopes visible to a code block +is called the block's \dfn{environment}\index{environment}. + +If a name is bound in a block, it is a local variable of that block. +If a name is bound at the module level, it is a global variable. (The +variables of the module code block are local and global.) If a +variable is used in a code block but not defined there, it is a +\dfn{free variable}\indexii{free}{variable}. + +When a name is not found at all, a +\exception{NameError}\withsubitem{(built-in +exception)}{\ttindex{NameError}} exception is raised. If the name +refers to a local variable that has not been bound, a +\exception{UnboundLocalError}\ttindex{UnboundLocalError} exception is +raised. \exception{UnboundLocalError} is a subclass of +\exception{NameError}. + +The following constructs bind names: formal parameters to functions, +\keyword{import} statements, class and function definitions (these +bind the class or function name in the defining block), and targets +that are identifiers if occurring in an assignment, \keyword{for} loop +header, or in the second position of an \keyword{except} clause +header. The \keyword{import} statement of the form ``\samp{from +\ldots import *}''\stindex{from} binds all names defined in the +imported module, except those beginning with an underscore. This form +may only be used at the module level. + +A target occurring in a \keyword{del} statement is also considered bound +for this purpose (though the actual semantics are to unbind the +name). It is illegal to unbind a name that is referenced by an +enclosing scope; the compiler will report a \exception{SyntaxError}. + +Each assignment or import statement occurs within a block defined by a +class or function definition or at the module level (the top-level +code block). + +If a name binding operation occurs anywhere within a code block, all +uses of the name within the block are treated as references to the +current block. This can lead to errors when a name is used within a +block before it is bound. +This rule is subtle. Python lacks declarations and allows +name binding operations to occur anywhere within a code block. The +local variables of a code block can be determined by scanning the +entire text of the block for name binding operations. + +If the global statement occurs within a block, all uses of the name +specified in the statement refer to the binding of that name in the +top-level namespace. Names are resolved in the top-level namespace by +searching the global namespace, i.e. the namespace of the module +containing the code block, and the builtin namespace, the namespace of +the module \module{__builtin__}. The global namespace is searched +first. If the name is not found there, the builtin namespace is +searched. The global statement must precede all uses of the name. + +The built-in namespace associated with the execution of a code block +is actually found by looking up the name \code{__builtins__} in its +global namespace; this should be a dictionary or a module (in the +latter case the module's dictionary is used). By default, when in the +\module{__main__} module, \code{__builtins__} is the built-in module +\module{__builtin__} (note: no `s'); when in any other module, +\code{__builtins__} is an alias for the dictionary of the +\module{__builtin__} module itself. \code{__builtins__} can be set +to a user-created dictionary to create a weak form of restricted +execution\indexii{restricted}{execution}. + +\begin{notice} + Users should not touch \code{__builtins__}; it is strictly an + implementation detail. Users wanting to override values in the + built-in namespace should \keyword{import} the \module{__builtin__} + (no `s') module and modify its attributes appropriately. +\end{notice} + +The namespace for a module is automatically created the first time a +module is imported. The main module for a script is always called +\module{__main__}\refbimodindex{__main__}. + +The global statement has the same scope as a name binding operation +in the same block. If the nearest enclosing scope for a free variable +contains a global statement, the free variable is treated as a global. + +A class definition is an executable statement that may use and define +names. These references follow the normal rules for name resolution. +The namespace of the class definition becomes the attribute dictionary +of the class. Names defined at the class scope are not visible in +methods. + +\subsection{Interaction with dynamic features \label{dynamic-features}} + +There are several cases where Python statements are illegal when +used in conjunction with nested scopes that contain free +variables. + +If a variable is referenced in an enclosing scope, it is illegal +to delete the name. An error will be reported at compile time. + +If the wild card form of import --- \samp{import *} --- is used in a +function and the function contains or is a nested block with free +variables, the compiler will raise a \exception{SyntaxError}. + +If \keyword{exec} is used in a function and the function contains or +is a nested block with free variables, the compiler will raise a +\exception{SyntaxError} unless the exec explicitly specifies the local +namespace for the \keyword{exec}. (In other words, \samp{exec obj} +would be illegal, but \samp{exec obj in ns} would be legal.) + +The \function{eval()}, \function{execfile()}, and \function{input()} +functions and the \keyword{exec} statement do not have access to the +full environment for resolving names. Names may be resolved in the +local and global namespaces of the caller. Free variables are not +resolved in the nearest enclosing namespace, but in the global +namespace.\footnote{This limitation occurs because the code that is + executed by these operations is not available at the time the + module is compiled.} +The \keyword{exec} statement and the \function{eval()} and +\function{execfile()} functions have optional arguments to override +the global and local namespace. If only one namespace is specified, +it is used for both. + +\section{Exceptions \label{exceptions}} +\index{exception} + +Exceptions are a means of breaking out of the normal flow of control +of a code block in order to handle errors or other exceptional +conditions. An exception is +\emph{raised}\index{raise an exception} at the point where the error +is detected; it may be \emph{handled}\index{handle an exception} by +the surrounding code block or by any code block that directly or +indirectly invoked the code block where the error occurred. +\index{exception handler} +\index{errors} +\index{error handling} + +The Python interpreter raises an exception when it detects a run-time +error (such as division by zero). A Python program can also +explicitly raise an exception with the \keyword{raise} statement. +Exception handlers are specified with the \keyword{try} ... \keyword{except} +statement. The \keyword{try} ... \keyword{finally} statement +specifies cleanup code which does not handle the exception, but is +executed whether an exception occurred or not in the preceding code. + +Python uses the ``termination''\index{termination model} model of +error handling: an exception handler can find out what happened and +continue execution at an outer level, but it cannot repair the cause +of the error and retry the failing operation (except by re-entering +the offending piece of code from the top). + +When an exception is not handled at all, the interpreter terminates +execution of the program, or returns to its interactive main loop. In +either case, it prints a stack backtrace, except when the exception is +\exception{SystemExit}\withsubitem{(built-in +exception)}{\ttindex{SystemExit}}. + +Exceptions are identified by class instances. The \keyword{except} +clause is selected depending on the class of the instance: it must +reference the class of the instance or a base class thereof. The +instance can be received by the handler and can carry additional +information about the exceptional condition. + +Exceptions can also be identified by strings, in which case the +\keyword{except} clause is selected by object identity. An arbitrary +value can be raised along with the identifying string which can be +passed to the handler. + +\deprecated{2.5}{String exceptions should not be used in new code. +They will not be supported in a future version of Python. Old code +should be rewritten to use class exceptions instead.} + +\begin{notice}[warning] +Messages to exceptions are not part of the Python API. Their contents may +change from one version of Python to the next without warning and should not +be relied on by code which will run under multiple versions of the +interpreter. +\end{notice} + +See also the description of the \keyword{try} statement in +section~\ref{try} and \keyword{raise} statement in +section~\ref{raise}. diff --git a/sys/src/cmd/python/Doc/ref/ref5.tex b/sys/src/cmd/python/Doc/ref/ref5.tex new file mode 100644 index 000000000..17c57d43f --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref5.tex @@ -0,0 +1,1325 @@ +\chapter{Expressions\label{expressions}} +\index{expression} + +This chapter explains the meaning of the elements of expressions in +Python. + +\strong{Syntax Notes:} In this and the following chapters, extended +BNF\index{BNF} notation will be used to describe syntax, not lexical +analysis. When (one alternative of) a syntax rule has the form + +\begin{productionlist}[*] + \production{name}{\token{othername}} +\end{productionlist} + +and no semantics are given, the semantics of this form of \code{name} +are the same as for \code{othername}. +\index{syntax} + + +\section{Arithmetic conversions\label{conversions}} +\indexii{arithmetic}{conversion} + +When a description of an arithmetic operator below uses the phrase +``the numeric arguments are converted to a common type,'' the +arguments are coerced using the coercion rules listed at +~\ref{coercion-rules}. If both arguments are standard numeric types, +the following coercions are applied: + +\begin{itemize} +\item If either argument is a complex number, the other is converted + to complex; +\item otherwise, if either argument is a floating point number, + the other is converted to floating point; +\item otherwise, if either argument is a long integer, + the other is converted to long integer; +\item otherwise, both must be plain integers and no conversion + is necessary. +\end{itemize} + +Some additional rules apply for certain operators (e.g., a string left +argument to the `\%' operator). Extensions can define their own +coercions. + + +\section{Atoms\label{atoms}} +\index{atom} + +Atoms are the most basic elements of expressions. The simplest atoms +are identifiers or literals. Forms enclosed in +reverse quotes or in parentheses, brackets or braces are also +categorized syntactically as atoms. The syntax for atoms is: + +\begin{productionlist} + \production{atom} + {\token{identifier} | \token{literal} | \token{enclosure}} + \production{enclosure} + {\token{parenth_form} | \token{list_display}} + \productioncont{| \token{generator_expression} | \token{dict_display}} + \productioncont{| \token{string_conversion} | \token{yield_atom}} +\end{productionlist} + + +\subsection{Identifiers (Names)\label{atom-identifiers}} +\index{name} +\index{identifier} + +An identifier occurring as an atom is a name. See +section \ref{identifiers} for lexical definition and +section~\ref{naming} for documentation of naming and binding. + +When the name is bound to an object, evaluation of the atom yields +that object. When a name is not bound, an attempt to evaluate it +raises a \exception{NameError} exception. +\exindex{NameError} + +\strong{Private name mangling:} +\indexii{name}{mangling}% +\indexii{private}{names}% +When an identifier that textually occurs in a class definition begins +with two or more underscore characters and does not end in two or more +underscores, it is considered a \dfn{private name} of that class. +Private names are transformed to a longer form before code is +generated for them. The transformation inserts the class name in +front of the name, with leading underscores removed, and a single +underscore inserted in front of the class name. For example, the +identifier \code{__spam} occurring in a class named \code{Ham} will be +transformed to \code{_Ham__spam}. This transformation is independent +of the syntactical context in which the identifier is used. If the +transformed name is extremely long (longer than 255 characters), +implementation defined truncation may happen. If the class name +consists only of underscores, no transformation is done. + + +\subsection{Literals\label{atom-literals}} +\index{literal} + +Python supports string literals and various numeric literals: + +\begin{productionlist} + \production{literal} + {\token{stringliteral} | \token{integer} | \token{longinteger}} + \productioncont{| \token{floatnumber} | \token{imagnumber}} +\end{productionlist} + +Evaluation of a literal yields an object of the given type (string, +integer, long integer, floating point number, complex number) with the +given value. The value may be approximated in the case of floating +point and imaginary (complex) literals. See section \ref{literals} +for details. + +All literals correspond to immutable data types, and hence the +object's identity is less important than its value. Multiple +evaluations of literals with the same value (either the same +occurrence in the program text or a different occurrence) may obtain +the same object or a different object with the same value. +\indexiii{immutable}{data}{type} +\indexii{immutable}{object} + + +\subsection{Parenthesized forms\label{parenthesized}} +\index{parenthesized form} + +A parenthesized form is an optional expression list enclosed in +parentheses: + +\begin{productionlist} + \production{parenth_form} + {"(" [\token{expression_list}] ")"} +\end{productionlist} + +A parenthesized expression list yields whatever that expression list +yields: if the list contains at least one comma, it yields a tuple; +otherwise, it yields the single expression that makes up the +expression list. + +An empty pair of parentheses yields an empty tuple object. Since +tuples are immutable, the rules for literals apply (i.e., two +occurrences of the empty tuple may or may not yield the same object). +\indexii{empty}{tuple} + +Note that tuples are not formed by the parentheses, but rather by use +of the comma operator. The exception is the empty tuple, for which +parentheses \emph{are} required --- allowing unparenthesized ``nothing'' +in expressions would cause ambiguities and allow common typos to +pass uncaught. +\index{comma} +\indexii{tuple}{display} + + +\subsection{List displays\label{lists}} +\indexii{list}{display} +\indexii{list}{comprehensions} + +A list display is a possibly empty series of expressions enclosed in +square brackets: + +\begin{productionlist} + \production{list_display} + {"[" [\token{expression_list} | \token{list_comprehension}] "]"} + \production{list_comprehension} + {\token{expression} \token{list_for}} + \production{list_for} + {"for" \token{target_list} "in" \token{old_expression_list} + [\token{list_iter}]} + \production{old_expression_list} + {\token{old_expression} + [("," \token{old_expression})+ [","]]} + \production{list_iter} + {\token{list_for} | \token{list_if}} + \production{list_if} + {"if" \token{old_expression} [\token{list_iter}]} +\end{productionlist} + +A list display yields a new list object. Its contents are specified +by providing either a list of expressions or a list comprehension. +\indexii{list}{comprehensions} +When a comma-separated list of expressions is supplied, its elements are +evaluated from left to right and placed into the list object in that +order. When a list comprehension is supplied, it consists of a +single expression followed by at least one \keyword{for} clause and zero or +more \keyword{for} or \keyword{if} clauses. In this +case, the elements of the new list are those that would be produced +by considering each of the \keyword{for} or \keyword{if} clauses a block, +nesting from +left to right, and evaluating the expression to produce a list element +each time the innermost block is reached\footnote{In Python 2.3, a +list comprehension "leaks" the control variables of each +\samp{for} it contains into the containing scope. However, this +behavior is deprecated, and relying on it will not work once this +bug is fixed in a future release}. +\obindex{list} +\indexii{empty}{list} + + +\subsection{Generator expressions\label{genexpr}} +\indexii{generator}{expression} + +A generator expression is a compact generator notation in parentheses: + +\begin{productionlist} + \production{generator_expression} + {"(" \token{expression} \token{genexpr_for} ")"} + \production{genexpr_for} + {"for" \token{target_list} "in" \token{or_test} + [\token{genexpr_iter}]} + \production{genexpr_iter} + {\token{genexpr_for} | \token{genexpr_if}} + \production{genexpr_if} + {"if" \token{old_expression} [\token{genexpr_iter}]} +\end{productionlist} + +A generator expression yields a new generator object. +\obindex{generator} +It consists of a single expression followed by at least one +\keyword{for} clause and zero or more \keyword{for} or \keyword{if} +clauses. The iterating values of the new generator are those that +would be produced by considering each of the \keyword{for} or +\keyword{if} clauses a block, nesting from left to right, and +evaluating the expression to yield a value that is reached the +innermost block for each iteration. + +Variables used in the generator expression are evaluated lazily +when the \method{next()} method is called for generator object +(in the same fashion as normal generators). However, the leftmost +\keyword{for} clause is immediately evaluated so that error produced +by it can be seen before any other possible error in the code that +handles the generator expression. +Subsequent \keyword{for} clauses cannot be evaluated immediately since +they may depend on the previous \keyword{for} loop. +For example: \samp{(x*y for x in range(10) for y in bar(x))}. + +The parentheses can be omitted on calls with only one argument. +See section \ref{calls} for the detail. + + +\subsection{Dictionary displays\label{dict}} +\indexii{dictionary}{display} + +A dictionary display is a possibly empty series of key/datum pairs +enclosed in curly braces: +\index{key} +\index{datum} +\index{key/datum pair} + +\begin{productionlist} + \production{dict_display} + {"\{" [\token{key_datum_list}] "\}"} + \production{key_datum_list} + {\token{key_datum} ("," \token{key_datum})* [","]} + \production{key_datum} + {\token{expression} ":" \token{expression}} +\end{productionlist} + +A dictionary display yields a new dictionary object. +\obindex{dictionary} + +The key/datum pairs are evaluated from left to right to define the +entries of the dictionary: each key object is used as a key into the +dictionary to store the corresponding datum. + +Restrictions on the types of the key values are listed earlier in +section \ref{types}. (To summarize, the key type should be hashable, +which excludes all mutable objects.) Clashes between duplicate keys +are not detected; the last datum (textually rightmost in the display) +stored for a given key value prevails. +\indexii{immutable}{object} + + +\subsection{String conversions\label{string-conversions}} +\indexii{string}{conversion} +\indexii{reverse}{quotes} +\indexii{backward}{quotes} +\index{back-quotes} + +A string conversion is an expression list enclosed in reverse (a.k.a. +backward) quotes: + +\begin{productionlist} + \production{string_conversion} + {"`" \token{expression_list} "`"} +\end{productionlist} + +A string conversion evaluates the contained expression list and +converts the resulting object into a string according to rules +specific to its type. + +If the object is a string, a number, \code{None}, or a tuple, list or +dictionary containing only objects whose type is one of these, the +resulting string is a valid Python expression which can be passed to +the built-in function \function{eval()} to yield an expression with the +same value (or an approximation, if floating point numbers are +involved). + +(In particular, converting a string adds quotes around it and converts +``funny'' characters to escape sequences that are safe to print.) + +Recursive objects (for example, lists or dictionaries that contain a +reference to themselves, directly or indirectly) use \samp{...} to +indicate a recursive reference, and the result cannot be passed to +\function{eval()} to get an equal value (\exception{SyntaxError} will +be raised instead). +\obindex{recursive} + +The built-in function \function{repr()} performs exactly the same +conversion in its argument as enclosing it in parentheses and reverse +quotes does. The built-in function \function{str()} performs a +similar but more user-friendly conversion. +\bifuncindex{repr} +\bifuncindex{str} + + +\subsection{Yield expressions\label{yieldexpr}} +\kwindex{yield} +\indexii{yield}{expression} +\indexii{generator}{function} + +\begin{productionlist} + \production{yield_atom} + {"(" \token{yield_expression} ")"} + \production{yield_expression} + {"yield" [\token{expression_list}]} +\end{productionlist} + +\versionadded{2.5} + +The \keyword{yield} expression is only used when defining a generator +function, and can only be used in the body of a function definition. +Using a \keyword{yield} expression in a function definition is +sufficient to cause that definition to create a generator function +instead of a normal function. + +When a generator function is called, it returns an iterator known as a +generator. That generator then controls the execution of a generator +function. The execution starts when one of the generator's methods is +called. At that time, the execution proceeds to the first +\keyword{yield} expression, where it is suspended again, returning the +value of \grammartoken{expression_list} to generator's caller. By +suspended we mean that all local state is retained, including the +current bindings of local variables, the instruction pointer, and the +internal evaluation stack. When the execution is resumed by calling +one of the generator's methods, the function can proceed exactly as +if the \keyword{yield} expression was just another external call. +The value of the \keyword{yield} expression after resuming depends on +the method which resumed the execution. + +\index{coroutine} + +All of this makes generator functions quite similar to coroutines; they +yield multiple times, they have more than one entry point and their +execution can be suspended. The only difference is that a generator +function cannot control where should the execution continue after it +yields; the control is always transfered to the generator's caller. + +\obindex{generator} + +The following generator's methods can be used to control the execution +of a generator function: + +\exindex{StopIteration} + +\begin{methoddesc}[generator]{next}{} + Starts the execution of a generator function or resumes it at the + last executed \keyword{yield} expression. When a generator function + is resumed with a \method{next()} method, the current \keyword{yield} + expression always evaluates to \constant{None}. The execution then + continues to the next \keyword{yield} expression, where the generator + is suspended again, and the value of the + \grammartoken{expression_list} is returned to \method{next()}'s + caller. If the generator exits without yielding another value, a + \exception{StopIteration} exception is raised. +\end{methoddesc} + +\begin{methoddesc}[generator]{send}{value} + Resumes the execution and ``sends'' a value into the generator + function. The \code{value} argument becomes the result of the + current \keyword{yield} expression. The \method{send()} method + returns the next value yielded by the generator, or raises + \exception{StopIteration} if the generator exits without yielding + another value. + When \method{send()} is called to start the generator, it must be + called with \constant{None} as the argument, because there is no + \keyword{yield} expression that could receieve the value. +\end{methoddesc} + +\begin{methoddesc}[generator]{throw} + {type\optional{, value\optional{, traceback}}} + Raises an exception of type \code{type} at the point where generator + was paused, and returns the next value yielded by the generator + function. If the generator exits without yielding another value, a + \exception{StopIteration} exception is raised. If the generator + function does not catch the passed-in exception, or raises a + different exception, then that exception propagates to the caller. +\end{methoddesc} + +\exindex{GeneratorExit} + +\begin{methoddesc}[generator]{close}{} + Raises a \exception{GeneratorExit} at the point where the generator + function was paused. If the generator function then raises + \exception{StopIteration} (by exiting normally, or due to already + being closed) or \exception{GeneratorExit} (by not catching the + exception), close returns to its caller. If the generator yields a + value, a \exception{RuntimeError} is raised. If the generator raises + any other exception, it is propagated to the caller. \method{close} + does nothing if the generator has already exited due to an exception + or normal exit. +\end{methoddesc} + +Here is a simple example that demonstrates the behavior of generators +and generator functions: + +\begin{verbatim} +>>> def echo(value=None): +... print "Execution starts when 'next()' is called for the first time." +... try: +... while True: +... try: +... value = (yield value) +... except GeneratorExit: +... # never catch GeneratorExit +... raise +... except Exception, e: +... value = e +... finally: +... print "Don't forget to clean up when 'close()' is called." +... +>>> generator = echo(1) +>>> print generator.next() +Execution starts when 'next()' is called for the first time. +1 +>>> print generator.next() +None +>>> print generator.send(2) +2 +>>> generator.throw(TypeError, "spam") +TypeError('spam',) +>>> generator.close() +Don't forget to clean up when 'close()' is called. +\end{verbatim} + +\begin{seealso} + \seepep{0342}{Coroutines via Enhanced Generators} + {The proposal to enhance the API and syntax of generators, + making them usable as simple coroutines.} +\end{seealso} + + +\section{Primaries\label{primaries}} +\index{primary} + +Primaries represent the most tightly bound operations of the language. +Their syntax is: + +\begin{productionlist} + \production{primary} + {\token{atom} | \token{attributeref} + | \token{subscription} | \token{slicing} | \token{call}} +\end{productionlist} + + +\subsection{Attribute references\label{attribute-references}} +\indexii{attribute}{reference} + +An attribute reference is a primary followed by a period and a name: + +\begin{productionlist} + \production{attributeref} + {\token{primary} "." \token{identifier}} +\end{productionlist} + +The primary must evaluate to an object of a type that supports +attribute references, e.g., a module, list, or an instance. This +object is then asked to produce the attribute whose name is the +identifier. If this attribute is not available, the exception +\exception{AttributeError}\exindex{AttributeError} is raised. +Otherwise, the type and value of the object produced is determined by +the object. Multiple evaluations of the same attribute reference may +yield different objects. +\obindex{module} +\obindex{list} + + +\subsection{Subscriptions\label{subscriptions}} +\index{subscription} + +A subscription selects an item of a sequence (string, tuple or list) +or mapping (dictionary) object: +\obindex{sequence} +\obindex{mapping} +\obindex{string} +\obindex{tuple} +\obindex{list} +\obindex{dictionary} +\indexii{sequence}{item} + +\begin{productionlist} + \production{subscription} + {\token{primary} "[" \token{expression_list} "]"} +\end{productionlist} + +The primary must evaluate to an object of a sequence or mapping type. + +If the primary is a mapping, the expression list must evaluate to an +object whose value is one of the keys of the mapping, and the +subscription selects the value in the mapping that corresponds to that +key. (The expression list is a tuple except if it has exactly one +item.) + +If the primary is a sequence, the expression (list) must evaluate to a +plain integer. If this value is negative, the length of the sequence +is added to it (so that, e.g., \code{x[-1]} selects the last item of +\code{x}.) The resulting value must be a nonnegative integer less +than the number of items in the sequence, and the subscription selects +the item whose index is that value (counting from zero). + +A string's items are characters. A character is not a separate data +type but a string of exactly one character. +\index{character} +\indexii{string}{item} + + +\subsection{Slicings\label{slicings}} +\index{slicing} +\index{slice} + +A slicing selects a range of items in a sequence object (e.g., a +string, tuple or list). Slicings may be used as expressions or as +targets in assignment or \keyword{del} statements. The syntax for a +slicing: +\obindex{sequence} +\obindex{string} +\obindex{tuple} +\obindex{list} + +\begin{productionlist} + \production{slicing} + {\token{simple_slicing} | \token{extended_slicing}} + \production{simple_slicing} + {\token{primary} "[" \token{short_slice} "]"} + \production{extended_slicing} + {\token{primary} "[" \token{slice_list} "]" } + \production{slice_list} + {\token{slice_item} ("," \token{slice_item})* [","]} + \production{slice_item} + {\token{expression} | \token{proper_slice} | \token{ellipsis}} + \production{proper_slice} + {\token{short_slice} | \token{long_slice}} + \production{short_slice} + {[\token{lower_bound}] ":" [\token{upper_bound}]} + \production{long_slice} + {\token{short_slice} ":" [\token{stride}]} + \production{lower_bound} + {\token{expression}} + \production{upper_bound} + {\token{expression}} + \production{stride} + {\token{expression}} + \production{ellipsis} + {"..."} +\end{productionlist} + +There is ambiguity in the formal syntax here: anything that looks like +an expression list also looks like a slice list, so any subscription +can be interpreted as a slicing. Rather than further complicating the +syntax, this is disambiguated by defining that in this case the +interpretation as a subscription takes priority over the +interpretation as a slicing (this is the case if the slice list +contains no proper slice nor ellipses). Similarly, when the slice +list has exactly one short slice and no trailing comma, the +interpretation as a simple slicing takes priority over that as an +extended slicing.\indexii{extended}{slicing} + +The semantics for a simple slicing are as follows. The primary must +evaluate to a sequence object. The lower and upper bound expressions, +if present, must evaluate to plain integers; defaults are zero and the +\code{sys.maxint}, respectively. If either bound is negative, the +sequence's length is added to it. The slicing now selects all items +with index \var{k} such that +\code{\var{i} <= \var{k} < \var{j}} where \var{i} +and \var{j} are the specified lower and upper bounds. This may be an +empty sequence. It is not an error if \var{i} or \var{j} lie outside the +range of valid indexes (such items don't exist so they aren't +selected). + +The semantics for an extended slicing are as follows. The primary +must evaluate to a mapping object, and it is indexed with a key that +is constructed from the slice list, as follows. If the slice list +contains at least one comma, the key is a tuple containing the +conversion of the slice items; otherwise, the conversion of the lone +slice item is the key. The conversion of a slice item that is an +expression is that expression. The conversion of an ellipsis slice +item is the built-in \code{Ellipsis} object. The conversion of a +proper slice is a slice object (see section \ref{types}) whose +\member{start}, \member{stop} and \member{step} attributes are the +values of the expressions given as lower bound, upper bound and +stride, respectively, substituting \code{None} for missing +expressions. +\withsubitem{(slice object attribute)}{\ttindex{start} + \ttindex{stop}\ttindex{step}} + + +\subsection{Calls\label{calls}} +\index{call} + +A call calls a callable object (e.g., a function) with a possibly empty +series of arguments: +\obindex{callable} + +\begin{productionlist} + \production{call} + {\token{primary} "(" [\token{argument_list} [","]} + \productioncont{ | \token{expression} \token{genexpr_for}] ")"} + \production{argument_list} + {\token{positional_arguments} ["," \token{keyword_arguments}]} + \productioncont{ ["," "*" \token{expression}]} + \productioncont{ ["," "**" \token{expression}]} + \productioncont{| \token{keyword_arguments} ["," "*" \token{expression}]} + \productioncont{ ["," "**" \token{expression}]} + \productioncont{| "*" \token{expression} ["," "**" \token{expression}]} + \productioncont{| "**" \token{expression}} + \production{positional_arguments} + {\token{expression} ("," \token{expression})*} + \production{keyword_arguments} + {\token{keyword_item} ("," \token{keyword_item})*} + \production{keyword_item} + {\token{identifier} "=" \token{expression}} +\end{productionlist} + +A trailing comma may be present after the positional and keyword +arguments but does not affect the semantics. + +The primary must evaluate to a callable object (user-defined +functions, built-in functions, methods of built-in objects, class +objects, methods of class instances, and certain class instances +themselves are callable; extensions may define additional callable +object types). All argument expressions are evaluated before the call +is attempted. Please refer to section \ref{function} for the syntax +of formal parameter lists. + +If keyword arguments are present, they are first converted to +positional arguments, as follows. First, a list of unfilled slots is +created for the formal parameters. If there are N positional +arguments, they are placed in the first N slots. Next, for each +keyword argument, the identifier is used to determine the +corresponding slot (if the identifier is the same as the first formal +parameter name, the first slot is used, and so on). If the slot is +already filled, a \exception{TypeError} exception is raised. +Otherwise, the value of the argument is placed in the slot, filling it +(even if the expression is \code{None}, it fills the slot). When all +arguments have been processed, the slots that are still unfilled are +filled with the corresponding default value from the function +definition. (Default values are calculated, once, when the function +is defined; thus, a mutable object such as a list or dictionary used +as default value will be shared by all calls that don't specify an +argument value for the corresponding slot; this should usually be +avoided.) If there are any unfilled slots for which no default value +is specified, a \exception{TypeError} exception is raised. Otherwise, +the list of filled slots is used as the argument list for the call. + +If there are more positional arguments than there are formal parameter +slots, a \exception{TypeError} exception is raised, unless a formal +parameter using the syntax \samp{*identifier} is present; in this +case, that formal parameter receives a tuple containing the excess +positional arguments (or an empty tuple if there were no excess +positional arguments). + +If any keyword argument does not correspond to a formal parameter +name, a \exception{TypeError} exception is raised, unless a formal +parameter using the syntax \samp{**identifier} is present; in this +case, that formal parameter receives a dictionary containing the +excess keyword arguments (using the keywords as keys and the argument +values as corresponding values), or a (new) empty dictionary if there +were no excess keyword arguments. + +If the syntax \samp{*expression} appears in the function call, +\samp{expression} must evaluate to a sequence. Elements from this +sequence are treated as if they were additional positional arguments; +if there are postional arguments \var{x1},...,\var{xN} , and +\samp{expression} evaluates to a sequence \var{y1},...,\var{yM}, this +is equivalent to a call with M+N positional arguments +\var{x1},...,\var{xN},\var{y1},...,\var{yM}. + +A consequence of this is that although the \samp{*expression} syntax +appears \emph{after} any keyword arguments, it is processed +\emph{before} the keyword arguments (and the +\samp{**expression} argument, if any -- see below). So: + +\begin{verbatim} +>>> def f(a, b): +... print a, b +... +>>> f(b=1, *(2,)) +2 1 +>>> f(a=1, *(2,)) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: f() got multiple values for keyword argument 'a' +>>> f(1, *(2,)) +1 2 +\end{verbatim} + +It is unusual for both keyword arguments and the +\samp{*expression} syntax to be used in the same call, so in practice +this confusion does not arise. + +If the syntax \samp{**expression} appears in the function call, +\samp{expression} must evaluate to a (subclass of) dictionary, the +contents of which are treated as additional keyword arguments. In the +case of a keyword appearing in both \samp{expression} and as an +explicit keyword argument, a \exception{TypeError} exception is +raised. + +Formal parameters using the syntax \samp{*identifier} or +\samp{**identifier} cannot be used as positional argument slots or +as keyword argument names. Formal parameters using the syntax +\samp{(sublist)} cannot be used as keyword argument names; the +outermost sublist corresponds to a single unnamed argument slot, and +the argument value is assigned to the sublist using the usual tuple +assignment rules after all other parameter processing is done. + +A call always returns some value, possibly \code{None}, unless it +raises an exception. How this value is computed depends on the type +of the callable object. + +If it is--- + +\begin{description} + +\item[a user-defined function:] The code block for the function is +executed, passing it the argument list. The first thing the code +block will do is bind the formal parameters to the arguments; this is +described in section \ref{function}. When the code block executes a +\keyword{return} statement, this specifies the return value of the +function call. +\indexii{function}{call} +\indexiii{user-defined}{function}{call} +\obindex{user-defined function} +\obindex{function} + +\item[a built-in function or method:] The result is up to the +interpreter; see the \citetitle[../lib/built-in-funcs.html]{Python +Library Reference} for the descriptions of built-in functions and +methods. +\indexii{function}{call} +\indexii{built-in function}{call} +\indexii{method}{call} +\indexii{built-in method}{call} +\obindex{built-in method} +\obindex{built-in function} +\obindex{method} +\obindex{function} + +\item[a class object:] A new instance of that class is returned. +\obindex{class} +\indexii{class object}{call} + +\item[a class instance method:] The corresponding user-defined +function is called, with an argument list that is one longer than the +argument list of the call: the instance becomes the first argument. +\obindex{class instance} +\obindex{instance} +\indexii{class instance}{call} + +\item[a class instance:] The class must define a \method{__call__()} +method; the effect is then the same as if that method was called. +\indexii{instance}{call} +\withsubitem{(object method)}{\ttindex{__call__()}} + +\end{description} + + +\section{The power operator\label{power}} + +The power operator binds more tightly than unary operators on its +left; it binds less tightly than unary operators on its right. The +syntax is: + +\begin{productionlist} + \production{power} + {\token{primary} ["**" \token{u_expr}]} +\end{productionlist} + +Thus, in an unparenthesized sequence of power and unary operators, the +operators are evaluated from right to left (this does not constrain +the evaluation order for the operands). + +The power operator has the same semantics as the built-in +\function{pow()} function, when called with two arguments: it yields +its left argument raised to the power of its right argument. The +numeric arguments are first converted to a common type. The result +type is that of the arguments after coercion. + +With mixed operand types, the coercion rules for binary arithmetic +operators apply. For int and long int operands, the result has the +same type as the operands (after coercion) unless the second argument +is negative; in that case, all arguments are converted to float and a +float result is delivered. For example, \code{10**2} returns \code{100}, +but \code{10**-2} returns \code{0.01}. (This last feature was added in +Python 2.2. In Python 2.1 and before, if both arguments were of integer +types and the second argument was negative, an exception was raised). + +Raising \code{0.0} to a negative power results in a +\exception{ZeroDivisionError}. Raising a negative number to a +fractional power results in a \exception{ValueError}. + + +\section{Unary arithmetic operations \label{unary}} +\indexiii{unary}{arithmetic}{operation} +\indexiii{unary}{bit-wise}{operation} + +All unary arithmetic (and bit-wise) operations have the same priority: + +\begin{productionlist} + \production{u_expr} + {\token{power} | "-" \token{u_expr} + | "+" \token{u_expr} | "{\~}" \token{u_expr}} +\end{productionlist} + +The unary \code{-} (minus) operator yields the negation of its +numeric argument. +\index{negation} +\index{minus} + +The unary \code{+} (plus) operator yields its numeric argument +unchanged. +\index{plus} + +The unary \code{\~} (invert) operator yields the bit-wise inversion +of its plain or long integer argument. The bit-wise inversion of +\code{x} is defined as \code{-(x+1)}. It only applies to integral +numbers. +\index{inversion} + +In all three cases, if the argument does not have the proper type, +a \exception{TypeError} exception is raised. +\exindex{TypeError} + + +\section{Binary arithmetic operations\label{binary}} +\indexiii{binary}{arithmetic}{operation} + +The binary arithmetic operations have the conventional priority +levels. Note that some of these operations also apply to certain +non-numeric types. Apart from the power operator, there are only two +levels, one for multiplicative operators and one for additive +operators: + +\begin{productionlist} + \production{m_expr} + {\token{u_expr} | \token{m_expr} "*" \token{u_expr} + | \token{m_expr} "//" \token{u_expr} + | \token{m_expr} "/" \token{u_expr}} + \productioncont{| \token{m_expr} "\%" \token{u_expr}} + \production{a_expr} + {\token{m_expr} | \token{a_expr} "+" \token{m_expr} + | \token{a_expr} "-" \token{m_expr}} +\end{productionlist} + +The \code{*} (multiplication) operator yields the product of its +arguments. The arguments must either both be numbers, or one argument +must be an integer (plain or long) and the other must be a sequence. +In the former case, the numbers are converted to a common type and +then multiplied together. In the latter case, sequence repetition is +performed; a negative repetition factor yields an empty sequence. +\index{multiplication} + +The \code{/} (division) and \code{//} (floor division) operators yield +the quotient of their arguments. The numeric arguments are first +converted to a common type. Plain or long integer division yields an +integer of the same type; the result is that of mathematical division +with the `floor' function applied to the result. Division by zero +raises the +\exception{ZeroDivisionError} exception. +\exindex{ZeroDivisionError} +\index{division} + +The \code{\%} (modulo) operator yields the remainder from the +division of the first argument by the second. The numeric arguments +are first converted to a common type. A zero right argument raises +the \exception{ZeroDivisionError} exception. The arguments may be floating +point numbers, e.g., \code{3.14\%0.7} equals \code{0.34} (since +\code{3.14} equals \code{4*0.7 + 0.34}.) The modulo operator always +yields a result with the same sign as its second operand (or zero); +the absolute value of the result is strictly smaller than the absolute +value of the second operand\footnote{ + While \code{abs(x\%y) < abs(y)} is true mathematically, for + floats it may not be true numerically due to roundoff. For + example, and assuming a platform on which a Python float is an + IEEE 754 double-precision number, in order that \code{-1e-100 \% 1e100} + have the same sign as \code{1e100}, the computed result is + \code{-1e-100 + 1e100}, which is numerically exactly equal + to \code{1e100}. Function \function{fmod()} in the \module{math} + module returns a result whose sign matches the sign of the + first argument instead, and so returns \code{-1e-100} in this case. + Which approach is more appropriate depends on the application. +}. +\index{modulo} + +The integer division and modulo operators are connected by the +following identity: \code{x == (x/y)*y + (x\%y)}. Integer division and +modulo are also connected with the built-in function \function{divmod()}: +\code{divmod(x, y) == (x/y, x\%y)}. These identities don't hold for +floating point numbers; there similar identities hold +approximately where \code{x/y} is replaced by \code{floor(x/y)} or +\code{floor(x/y) - 1}\footnote{ + If x is very close to an exact integer multiple of y, it's + possible for \code{floor(x/y)} to be one larger than + \code{(x-x\%y)/y} due to rounding. In such cases, Python returns + the latter result, in order to preserve that \code{divmod(x,y)[0] + * y + x \%{} y} be very close to \code{x}. +}. + +In addition to performing the modulo operation on numbers, the \code{\%} +operator is also overloaded by string and unicode objects to perform +string formatting (also known as interpolation). The syntax for string +formatting is described in the +\citetitle[../lib/typesseq-strings.html]{Python Library Reference}, +section ``Sequence Types''. + +\deprecated{2.3}{The floor division operator, the modulo operator, +and the \function{divmod()} function are no longer defined for complex +numbers. Instead, convert to a floating point number using the +\function{abs()} function if appropriate.} + +The \code{+} (addition) operator yields the sum of its arguments. +The arguments must either both be numbers or both sequences of the +same type. In the former case, the numbers are converted to a common +type and then added together. In the latter case, the sequences are +concatenated. +\index{addition} + +The \code{-} (subtraction) operator yields the difference of its +arguments. The numeric arguments are first converted to a common +type. +\index{subtraction} + + +\section{Shifting operations\label{shifting}} +\indexii{shifting}{operation} + +The shifting operations have lower priority than the arithmetic +operations: + +\begin{productionlist} + \production{shift_expr} + {\token{a_expr} + | \token{shift_expr} ( "<<" | ">>" ) \token{a_expr}} +\end{productionlist} + +These operators accept plain or long integers as arguments. The +arguments are converted to a common type. They shift the first +argument to the left or right by the number of bits given by the +second argument. + +A right shift by \var{n} bits is defined as division by +\code{pow(2,\var{n})}. A left shift by \var{n} bits is defined as +multiplication with \code{pow(2,\var{n})}; for plain integers there is +no overflow check so in that case the operation drops bits and flips +the sign if the result is not less than \code{pow(2,31)} in absolute +value. Negative shift counts raise a \exception{ValueError} +exception. +\exindex{ValueError} + + +\section{Binary bit-wise operations\label{bitwise}} +\indexiii{binary}{bit-wise}{operation} + +Each of the three bitwise operations has a different priority level: + +\begin{productionlist} + \production{and_expr} + {\token{shift_expr} | \token{and_expr} "\&" \token{shift_expr}} + \production{xor_expr} + {\token{and_expr} | \token{xor_expr} "\textasciicircum" \token{and_expr}} + \production{or_expr} + {\token{xor_expr} | \token{or_expr} "|" \token{xor_expr}} +\end{productionlist} + +The \code{\&} operator yields the bitwise AND of its arguments, which +must be plain or long integers. The arguments are converted to a +common type. +\indexii{bit-wise}{and} + +The \code{\^} operator yields the bitwise XOR (exclusive OR) of its +arguments, which must be plain or long integers. The arguments are +converted to a common type. +\indexii{bit-wise}{xor} +\indexii{exclusive}{or} + +The \code{|} operator yields the bitwise (inclusive) OR of its +arguments, which must be plain or long integers. The arguments are +converted to a common type. +\indexii{bit-wise}{or} +\indexii{inclusive}{or} + + +\section{Comparisons\label{comparisons}} +\index{comparison} + +Unlike C, all comparison operations in Python have the same priority, +which is lower than that of any arithmetic, shifting or bitwise +operation. Also unlike C, expressions like \code{a < b < c} have the +interpretation that is conventional in mathematics: +\indexii{C}{language} + +\begin{productionlist} + \production{comparison} + {\token{or_expr} ( \token{comp_operator} \token{or_expr} )*} + \production{comp_operator} + {"<" | ">" | "==" | ">=" | "<=" | "<>" | "!="} + \productioncont{| "is" ["not"] | ["not"] "in"} +\end{productionlist} + +Comparisons yield boolean values: \code{True} or \code{False}. + +Comparisons can be chained arbitrarily, e.g., \code{x < y <= z} is +equivalent to \code{x < y and y <= z}, except that \code{y} is +evaluated only once (but in both cases \code{z} is not evaluated at all +when \code{x < y} is found to be false). +\indexii{chaining}{comparisons} + +Formally, if \var{a}, \var{b}, \var{c}, \ldots, \var{y}, \var{z} are +expressions and \var{opa}, \var{opb}, \ldots, \var{opy} are comparison +operators, then \var{a opa b opb c} \ldots \var{y opy z} is equivalent +to \var{a opa b} \keyword{and} \var{b opb c} \keyword{and} \ldots +\var{y opy z}, except that each expression is evaluated at most once. + +Note that \var{a opa b opb c} doesn't imply any kind of comparison +between \var{a} and \var{c}, so that, e.g., \code{x < y > z} is +perfectly legal (though perhaps not pretty). + +The forms \code{<>} and \code{!=} are equivalent; for consistency with +C, \code{!=} is preferred; where \code{!=} is mentioned below +\code{<>} is also accepted. The \code{<>} spelling is considered +obsolescent. + +The operators \code{<}, \code{>}, \code{==}, \code{>=}, \code{<=}, and +\code{!=} compare +the values of two objects. The objects need not have the same type. +If both are numbers, they are converted to a common type. Otherwise, +objects of different types \emph{always} compare unequal, and are +ordered consistently but arbitrarily. You can control comparison +behavior of objects of non-builtin types by defining a \code{__cmp__} +method or rich comparison methods like \code{__gt__}, described in +section~\ref{specialnames}. + +(This unusual definition of comparison was used to simplify the +definition of operations like sorting and the \keyword{in} and +\keyword{not in} operators. In the future, the comparison rules for +objects of different types are likely to change.) + +Comparison of objects of the same type depends on the type: + +\begin{itemize} + +\item +Numbers are compared arithmetically. + +\item +Strings are compared lexicographically using the numeric equivalents +(the result of the built-in function \function{ord()}) of their +characters. Unicode and 8-bit strings are fully interoperable in this +behavior. + +\item +Tuples and lists are compared lexicographically using comparison of +corresponding elements. This means that to compare equal, each +element must compare equal and the two sequences must be of the same +type and have the same length. + +If not equal, the sequences are ordered the same as their first +differing elements. For example, \code{cmp([1,2,x], [1,2,y])} returns +the same as \code{cmp(x,y)}. If the corresponding element does not +exist, the shorter sequence is ordered first (for example, +\code{[1,2] < [1,2,3]}). + +\item +Mappings (dictionaries) compare equal if and only if their sorted +(key, value) lists compare equal.\footnote{The implementation computes + this efficiently, without constructing lists or sorting.} +Outcomes other than equality are resolved consistently, but are not +otherwise defined.\footnote{Earlier versions of Python used + lexicographic comparison of the sorted (key, value) lists, but this + was very expensive for the common case of comparing for equality. An + even earlier version of Python compared dictionaries by identity only, + but this caused surprises because people expected to be able to test + a dictionary for emptiness by comparing it to \code{\{\}}.} + +\item +Most other objects of builtin types compare unequal unless they are +the same object; +the choice whether one object is considered smaller or larger than +another one is made arbitrarily but consistently within one +execution of a program. + +\end{itemize} + +The operators \keyword{in} and \keyword{not in} test for set +membership. \code{\var{x} in \var{s}} evaluates to true if \var{x} +is a member of the set \var{s}, and false otherwise. \code{\var{x} +not in \var{s}} returns the negation of \code{\var{x} in \var{s}}. +The set membership test has traditionally been bound to sequences; an +object is a member of a set if the set is a sequence and contains an +element equal to that object. However, it is possible for an object +to support membership tests without being a sequence. In particular, +dictionaries support membership testing as a nicer way of spelling +\code{\var{key} in \var{dict}}; other mapping types may follow suit. + +For the list and tuple types, \code{\var{x} in \var{y}} is true if and +only if there exists an index \var{i} such that +\code{\var{x} == \var{y}[\var{i}]} is true. + +For the Unicode and string types, \code{\var{x} in \var{y}} is true if +and only if \var{x} is a substring of \var{y}. An equivalent test is +\code{y.find(x) != -1}. Note, \var{x} and \var{y} need not be the +same type; consequently, \code{u'ab' in 'abc'} will return \code{True}. +Empty strings are always considered to be a substring of any other string, +so \code{"" in "abc"} will return \code{True}. +\versionchanged[Previously, \var{x} was required to be a string of +length \code{1}]{2.3} + +For user-defined classes which define the \method{__contains__()} method, +\code{\var{x} in \var{y}} is true if and only if +\code{\var{y}.__contains__(\var{x})} is true. + +For user-defined classes which do not define \method{__contains__()} and +do define \method{__getitem__()}, \code{\var{x} in \var{y}} is true if +and only if there is a non-negative integer index \var{i} such that +\code{\var{x} == \var{y}[\var{i}]}, and all lower integer indices +do not raise \exception{IndexError} exception. (If any other exception +is raised, it is as if \keyword{in} raised that exception). + +The operator \keyword{not in} is defined to have the inverse true value +of \keyword{in}. +\opindex{in} +\opindex{not in} +\indexii{membership}{test} +\obindex{sequence} + +The operators \keyword{is} and \keyword{is not} test for object identity: +\code{\var{x} is \var{y}} is true if and only if \var{x} and \var{y} +are the same object. \code{\var{x} is not \var{y}} yields the inverse +truth value. +\opindex{is} +\opindex{is not} +\indexii{identity}{test} + + +\section{Boolean operations\label{Booleans}} +\indexii{Conditional}{expression} +\indexii{Boolean}{operation} + +Boolean operations have the lowest priority of all Python operations: + +\begin{productionlist} + \production{expression} + {\token{conditional_expression} | \token{lambda_form}} + \production{old_expression} + {\token{or_test} | \token{old_lambda_form}} + \production{conditional_expression} + {\token{or_test} ["if" \token{or_test} "else" \token{expression}]} + \production{or_test} + {\token{and_test} | \token{or_test} "or" \token{and_test}} + \production{and_test} + {\token{not_test} | \token{and_test} "and" \token{not_test}} + \production{not_test} + {\token{comparison} | "not" \token{not_test}} +\end{productionlist} + +In the context of Boolean operations, and also when expressions are +used by control flow statements, the following values are interpreted +as false: \code{False}, \code{None}, numeric zero of all types, and empty +strings and containers (including strings, tuples, lists, dictionaries, +sets and frozensets). All other values are interpreted as true. + +The operator \keyword{not} yields \code{True} if its argument is false, +\code{False} otherwise. +\opindex{not} + +The expression \code{\var{x} if \var{C} else \var{y}} first evaluates +\var{C} (\emph{not} \var{x}); if \var{C} is true, \var{x} is evaluated and +its value is returned; otherwise, \var{y} is evaluated and its value is +returned. \versionadded{2.5} + +The expression \code{\var{x} and \var{y}} first evaluates \var{x}; if +\var{x} is false, its value is returned; otherwise, \var{y} is +evaluated and the resulting value is returned. +\opindex{and} + +The expression \code{\var{x} or \var{y}} first evaluates \var{x}; if +\var{x} is true, its value is returned; otherwise, \var{y} is +evaluated and the resulting value is returned. +\opindex{or} + +(Note that neither \keyword{and} nor \keyword{or} restrict the value +and type they return to \code{False} and \code{True}, but rather return the +last evaluated argument. +This is sometimes useful, e.g., if \code{s} is a string that should be +replaced by a default value if it is empty, the expression +\code{s or 'foo'} yields the desired value. Because \keyword{not} has to +invent a value anyway, it does not bother to return a value of the +same type as its argument, so e.g., \code{not 'foo'} yields \code{False}, +not \code{''}.) + +\section{Lambdas\label{lambdas}} +\indexii{lambda}{expression} +\indexii{lambda}{form} +\indexii{anonymous}{function} + +\begin{productionlist} + \production{lambda_form} + {"lambda" [\token{parameter_list}]: \token{expression}} + \production{old_lambda_form} + {"lambda" [\token{parameter_list}]: \token{old_expression}} +\end{productionlist} + +Lambda forms (lambda expressions) have the same syntactic position as +expressions. They are a shorthand to create anonymous functions; the +expression \code{lambda \var{arguments}: \var{expression}} +yields a function object. The unnamed object behaves like a function +object defined with + +\begin{verbatim} +def name(arguments): + return expression +\end{verbatim} + +See section \ref{function} for the syntax of parameter lists. Note +that functions created with lambda forms cannot contain statements. +\label{lambda} + +\section{Expression lists\label{exprlists}} +\indexii{expression}{list} + +\begin{productionlist} + \production{expression_list} + {\token{expression} ( "," \token{expression} )* [","]} +\end{productionlist} + +An expression list containing at least one comma yields a +tuple. The length of the tuple is the number of expressions in the +list. The expressions are evaluated from left to right. +\obindex{tuple} + +The trailing comma is required only to create a single tuple (a.k.a. a +\emph{singleton}); it is optional in all other cases. A single +expression without a trailing comma doesn't create a +tuple, but rather yields the value of that expression. +(To create an empty tuple, use an empty pair of parentheses: +\code{()}.) +\indexii{trailing}{comma} + +\section{Evaluation order\label{evalorder}} +\indexii{evaluation}{order} + +Python evaluates expressions from left to right. Notice that while +evaluating an assignment, the right-hand side is evaluated before +the left-hand side. + +In the following lines, expressions will be evaluated in the +arithmetic order of their suffixes: + +\begin{verbatim} +expr1, expr2, expr3, expr4 +(expr1, expr2, expr3, expr4) +{expr1: expr2, expr3: expr4} +expr1 + expr2 * (expr3 - expr4) +func(expr1, expr2, *expr3, **expr4) +expr3, expr4 = expr1, expr2 +\end{verbatim} + +\section{Summary\label{summary}} + +The following table summarizes the operator +precedences\indexii{operator}{precedence} in Python, from lowest +precedence (least binding) to highest precedence (most binding). +Operators in the same box have the same precedence. Unless the syntax +is explicitly given, operators are binary. Operators in the same box +group left to right (except for comparisons, including tests, which all +have the same precedence and chain from left to right --- see section +\ref{comparisons} -- and exponentiation, which groups from right to left). + +\begin{tableii}{c|l}{textrm}{Operator}{Description} + \lineii{\keyword{lambda}} {Lambda expression} + \hline + \lineii{\keyword{or}} {Boolean OR} + \hline + \lineii{\keyword{and}} {Boolean AND} + \hline + \lineii{\keyword{not} \var{x}} {Boolean NOT} + \hline + \lineii{\keyword{in}, \keyword{not} \keyword{in}}{Membership tests} + \lineii{\keyword{is}, \keyword{is not}}{Identity tests} + \lineii{\code{<}, \code{<=}, \code{>}, \code{>=}, + \code{<>}, \code{!=}, \code{==}} + {Comparisons} + \hline + \lineii{\code{|}} {Bitwise OR} + \hline + \lineii{\code{\^}} {Bitwise XOR} + \hline + \lineii{\code{\&}} {Bitwise AND} + \hline + \lineii{\code{<<}, \code{>>}} {Shifts} + \hline + \lineii{\code{+}, \code{-}}{Addition and subtraction} + \hline + \lineii{\code{*}, \code{/}, \code{\%}} + {Multiplication, division, remainder} + \hline + \lineii{\code{+\var{x}}, \code{-\var{x}}} {Positive, negative} + \lineii{\code{\~\var{x}}} {Bitwise not} + \hline + \lineii{\code{**}} {Exponentiation} + \hline + \lineii{\code{\var{x}.\var{attribute}}} {Attribute reference} + \lineii{\code{\var{x}[\var{index}]}} {Subscription} + \lineii{\code{\var{x}[\var{index}:\var{index}]}} {Slicing} + \lineii{\code{\var{f}(\var{arguments}...)}} {Function call} + \hline + \lineii{\code{(\var{expressions}\ldots)}} {Binding or tuple display} + \lineii{\code{[\var{expressions}\ldots]}} {List display} + \lineii{\code{\{\var{key}:\var{datum}\ldots\}}}{Dictionary display} + \lineii{\code{`\var{expressions}\ldots`}} {String conversion} +\end{tableii} diff --git a/sys/src/cmd/python/Doc/ref/ref6.tex b/sys/src/cmd/python/Doc/ref/ref6.tex new file mode 100644 index 000000000..1fc885ed1 --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref6.tex @@ -0,0 +1,928 @@ +\chapter{Simple statements \label{simple}} +\indexii{simple}{statement} + +Simple statements are comprised within a single logical line. +Several simple statements may occur on a single line separated +by semicolons. The syntax for simple statements is: + +\begin{productionlist} + \production{simple_stmt}{\token{expression_stmt}} + \productioncont{| \token{assert_stmt}} + \productioncont{| \token{assignment_stmt}} + \productioncont{| \token{augmented_assignment_stmt}} + \productioncont{| \token{pass_stmt}} + \productioncont{| \token{del_stmt}} + \productioncont{| \token{print_stmt}} + \productioncont{| \token{return_stmt}} + \productioncont{| \token{yield_stmt}} + \productioncont{| \token{raise_stmt}} + \productioncont{| \token{break_stmt}} + \productioncont{| \token{continue_stmt}} + \productioncont{| \token{import_stmt}} + \productioncont{| \token{global_stmt}} + \productioncont{| \token{exec_stmt}} +\end{productionlist} + + +\section{Expression statements \label{exprstmts}} +\indexii{expression}{statement} + +Expression statements are used (mostly interactively) to compute and +write a value, or (usually) to call a procedure (a function that +returns no meaningful result; in Python, procedures return the value +\code{None}). Other uses of expression statements are allowed and +occasionally useful. The syntax for an expression statement is: + +\begin{productionlist} + \production{expression_stmt} + {\token{expression_list}} +\end{productionlist} + +An expression statement evaluates the expression list (which may be a +single expression). +\indexii{expression}{list} + +In interactive mode, if the value is not \code{None}, it is converted +to a string using the built-in \function{repr()}\bifuncindex{repr} +function and the resulting string is written to standard output (see +section~\ref{print}) on a line by itself. (Expression statements +yielding \code{None} are not written, so that procedure calls do not +cause any output.) +\obindex{None} +\indexii{string}{conversion} +\index{output} +\indexii{standard}{output} +\indexii{writing}{values} +\indexii{procedure}{call} + + +\section{Assert statements \label{assert}} + +Assert statements\stindex{assert} are a convenient way to insert +debugging assertions\indexii{debugging}{assertions} into a program: + +\begin{productionlist} + \production{assert_stmt} + {"assert" \token{expression} ["," \token{expression}]} +\end{productionlist} + +The simple form, \samp{assert expression}, is equivalent to + +\begin{verbatim} +if __debug__: + if not expression: raise AssertionError +\end{verbatim} + +The extended form, \samp{assert expression1, expression2}, is +equivalent to + +\begin{verbatim} +if __debug__: + if not expression1: raise AssertionError, expression2 +\end{verbatim} + +These equivalences assume that \code{__debug__}\ttindex{__debug__} and +\exception{AssertionError}\exindex{AssertionError} refer to the built-in +variables with those names. In the current implementation, the +built-in variable \code{__debug__} is \code{True} under normal +circumstances, \code{False} when optimization is requested (command line +option -O). The current code generator emits no code for an assert +statement when optimization is requested at compile time. Note that it +is unnecessary to include the source code for the expression that failed +in the error message; +it will be displayed as part of the stack trace. + +Assignments to \code{__debug__} are illegal. The value for the +built-in variable is determined when the interpreter starts. + + +\section{Assignment statements \label{assignment}} + +Assignment statements\indexii{assignment}{statement} are used to +(re)bind names to values and to modify attributes or items of mutable +objects: +\indexii{binding}{name} +\indexii{rebinding}{name} +\obindex{mutable} +\indexii{attribute}{assignment} + +\begin{productionlist} + \production{assignment_stmt} + {(\token{target_list} "=")+ + (\token{expression_list} | \token{yield_expression})} + \production{target_list} + {\token{target} ("," \token{target})* [","]} + \production{target} + {\token{identifier}} + \productioncont{| "(" \token{target_list} ")"} + \productioncont{| "[" \token{target_list} "]"} + \productioncont{| \token{attributeref}} + \productioncont{| \token{subscription}} + \productioncont{| \token{slicing}} +\end{productionlist} + +(See section~\ref{primaries} for the syntax definitions for the last +three symbols.) + +An assignment statement evaluates the expression list (remember that +this can be a single expression or a comma-separated list, the latter +yielding a tuple) and assigns the single resulting object to each of +the target lists, from left to right. +\indexii{expression}{list} + +Assignment is defined recursively depending on the form of the target +(list). When a target is part of a mutable object (an attribute +reference, subscription or slicing), the mutable object must +ultimately perform the assignment and decide about its validity, and +may raise an exception if the assignment is unacceptable. The rules +observed by various types and the exceptions raised are given with the +definition of the object types (see section~\ref{types}). +\index{target} +\indexii{target}{list} + +Assignment of an object to a target list is recursively defined as +follows. +\indexiii{target}{list}{assignment} + +\begin{itemize} +\item +If the target list is a single target: The object is assigned to that +target. + +\item +If the target list is a comma-separated list of targets: The object +must be a sequence with the same number of items as there are +targets in the target list, and the items are assigned, from left to +right, to the corresponding targets. (This rule is relaxed as of +Python 1.5; in earlier versions, the object had to be a tuple. Since +strings are sequences, an assignment like \samp{a, b = "xy"} is +now legal as long as the string has the right length.) + +\end{itemize} + +Assignment of an object to a single target is recursively defined as +follows. + +\begin{itemize} % nested + +\item +If the target is an identifier (name): + +\begin{itemize} + +\item +If the name does not occur in a \keyword{global} statement in the current +code block: the name is bound to the object in the current local +namespace. +\stindex{global} + +\item +Otherwise: the name is bound to the object in the current global +namespace. + +\end{itemize} % nested + +The name is rebound if it was already bound. This may cause the +reference count for the object previously bound to the name to reach +zero, causing the object to be deallocated and its +destructor\index{destructor} (if it has one) to be called. + +\item +If the target is a target list enclosed in parentheses or in square +brackets: The object must be a sequence with the same number of items +as there are targets in the target list, and its items are assigned, +from left to right, to the corresponding targets. + +\item +If the target is an attribute reference: The primary expression in the +reference is evaluated. It should yield an object with assignable +attributes; if this is not the case, \exception{TypeError} is raised. That +object is then asked to assign the assigned object to the given +attribute; if it cannot perform the assignment, it raises an exception +(usually but not necessarily \exception{AttributeError}). +\indexii{attribute}{assignment} + +\item +If the target is a subscription: The primary expression in the +reference is evaluated. It should yield either a mutable sequence +object (such as a list) or a mapping object (such as a dictionary). Next, +the subscript expression is evaluated. +\indexii{subscription}{assignment} +\obindex{mutable} + +If the primary is a mutable sequence object (such as a list), the subscript +must yield a plain integer. If it is negative, the sequence's length +is added to it. The resulting value must be a nonnegative integer +less than the sequence's length, and the sequence is asked to assign +the assigned object to its item with that index. If the index is out +of range, \exception{IndexError} is raised (assignment to a subscripted +sequence cannot add new items to a list). +\obindex{sequence} +\obindex{list} + +If the primary is a mapping object (such as a dictionary), the subscript must +have a type compatible with the mapping's key type, and the mapping is +then asked to create a key/datum pair which maps the subscript to +the assigned object. This can either replace an existing key/value +pair with the same key value, or insert a new key/value pair (if no +key with the same value existed). +\obindex{mapping} +\obindex{dictionary} + +\item +If the target is a slicing: The primary expression in the reference is +evaluated. It should yield a mutable sequence object (such as a list). The +assigned object should be a sequence object of the same type. Next, +the lower and upper bound expressions are evaluated, insofar they are +present; defaults are zero and the sequence's length. The bounds +should evaluate to (small) integers. If either bound is negative, the +sequence's length is added to it. The resulting bounds are clipped to +lie between zero and the sequence's length, inclusive. Finally, the +sequence object is asked to replace the slice with the items of the +assigned sequence. The length of the slice may be different from the +length of the assigned sequence, thus changing the length of the +target sequence, if the object allows it. +\indexii{slicing}{assignment} + +\end{itemize} + +(In the current implementation, the syntax for targets is taken +to be the same as for expressions, and invalid syntax is rejected +during the code generation phase, causing less detailed error +messages.) + +WARNING: Although the definition of assignment implies that overlaps +between the left-hand side and the right-hand side are `safe' (for example +\samp{a, b = b, a} swaps two variables), overlaps \emph{within} the +collection of assigned-to variables are not safe! For instance, the +following program prints \samp{[0, 2]}: + +\begin{verbatim} +x = [0, 1] +i = 0 +i, x[i] = 1, 2 +print x +\end{verbatim} + + +\subsection{Augmented assignment statements \label{augassign}} + +Augmented assignment is the combination, in a single statement, of a binary +operation and an assignment statement: +\indexii{augmented}{assignment} +\index{statement!assignment, augmented} + +\begin{productionlist} + \production{augmented_assignment_stmt} + {\token{target} \token{augop} + (\token{expression_list} | \token{yield_expression})} + \production{augop} + {"+=" | "-=" | "*=" | "/=" | "\%=" | "**="} + \productioncont{| ">>=" | "<<=" | "\&=" | "\textasciicircum=" | "|="} +\end{productionlist} + +(See section~\ref{primaries} for the syntax definitions for the last +three symbols.) + +An augmented assignment evaluates the target (which, unlike normal +assignment statements, cannot be an unpacking) and the expression +list, performs the binary operation specific to the type of assignment +on the two operands, and assigns the result to the original +target. The target is only evaluated once. + +An augmented assignment expression like \code{x += 1} can be rewritten as +\code{x = x + 1} to achieve a similar, but not exactly equal effect. In the +augmented version, \code{x} is only evaluated once. Also, when possible, the +actual operation is performed \emph{in-place}, meaning that rather than +creating a new object and assigning that to the target, the old object is +modified instead. + +With the exception of assigning to tuples and multiple targets in a single +statement, the assignment done by augmented assignment statements is handled +the same way as normal assignments. Similarly, with the exception of the +possible \emph{in-place} behavior, the binary operation performed by +augmented assignment is the same as the normal binary operations. + +For targets which are attribute references, the initial value is +retrieved with a \method{getattr()} and the result is assigned with a +\method{setattr()}. Notice that the two methods do not necessarily +refer to the same variable. When \method{getattr()} refers to a class +variable, \method{setattr()} still writes to an instance variable. +For example: + +\begin{verbatim} +class A: + x = 3 # class variable +a = A() +a.x += 1 # writes a.x as 4 leaving A.x as 3 +\end{verbatim} + + +\section{The \keyword{pass} statement \label{pass}} +\stindex{pass} + +\begin{productionlist} + \production{pass_stmt} + {"pass"} +\end{productionlist} + +\keyword{pass} is a null operation --- when it is executed, nothing +happens. It is useful as a placeholder when a statement is +required syntactically, but no code needs to be executed, for example: +\indexii{null}{operation} + +\begin{verbatim} +def f(arg): pass # a function that does nothing (yet) + +class C: pass # a class with no methods (yet) +\end{verbatim} + + +\section{The \keyword{del} statement \label{del}} +\stindex{del} + +\begin{productionlist} + \production{del_stmt} + {"del" \token{target_list}} +\end{productionlist} + +Deletion is recursively defined very similar to the way assignment is +defined. Rather that spelling it out in full details, here are some +hints. +\indexii{deletion}{target} +\indexiii{deletion}{target}{list} + +Deletion of a target list recursively deletes each target, from left +to right. + +Deletion of a name removes the binding of that name +from the local or global namespace, depending on whether the name +occurs in a \keyword{global} statement in the same code block. If the +name is unbound, a \exception{NameError} exception will be raised. +\stindex{global} +\indexii{unbinding}{name} + +It is illegal to delete a name from the local namespace if it occurs +as a free variable\indexii{free}{variable} in a nested block. + +Deletion of attribute references, subscriptions and slicings +is passed to the primary object involved; deletion of a slicing +is in general equivalent to assignment of an empty slice of the +right type (but even this is determined by the sliced object). +\indexii{attribute}{deletion} + + +\section{The \keyword{print} statement \label{print}} +\stindex{print} + +\begin{productionlist} + \production{print_stmt} + {"print" ([\token{expression} ("," \token{expression})* [","]} + \productioncont{| ">>" \token{expression} + [("," \token{expression})+ [","])} +\end{productionlist} + +\keyword{print} evaluates each expression in turn and writes the +resulting object to standard output (see below). If an object is not +a string, it is first converted to a string using the rules for string +conversions. The (resulting or original) string is then written. A +space is written before each object is (converted and) written, unless +the output system believes it is positioned at the beginning of a +line. This is the case (1) when no characters have yet been written +to standard output, (2) when the last character written to standard +output is \character{\e n}, or (3) when the last write operation on +standard output was not a \keyword{print} statement. (In some cases +it may be functional to write an empty string to standard output for +this reason.) \note{Objects which act like file objects but which are +not the built-in file objects often do not properly emulate this +aspect of the file object's behavior, so it is best not to rely on +this.} +\index{output} +\indexii{writing}{values} + +A \character{\e n} character is written at the end, unless the +\keyword{print} statement ends with a comma. This is the only action +if the statement contains just the keyword \keyword{print}. +\indexii{trailing}{comma} +\indexii{newline}{suppression} + +Standard output is defined as the file object named \code{stdout} +in the built-in module \module{sys}. If no such object exists, or if +it does not have a \method{write()} method, a \exception{RuntimeError} +exception is raised. +\indexii{standard}{output} +\refbimodindex{sys} +\withsubitem{(in module sys)}{\ttindex{stdout}} +\exindex{RuntimeError} + +\keyword{print} also has an extended\index{extended print statement} +form, defined by the second portion of the syntax described above. +This form is sometimes referred to as ``\keyword{print} chevron.'' +In this form, the first expression after the \code{>>} must +evaluate to a ``file-like'' object, specifically an object that has a +\method{write()} method as described above. With this extended form, +the subsequent expressions are printed to this file object. If the +first expression evaluates to \code{None}, then \code{sys.stdout} is +used as the file for output. + + +\section{The \keyword{return} statement \label{return}} +\stindex{return} + +\begin{productionlist} + \production{return_stmt} + {"return" [\token{expression_list}]} +\end{productionlist} + +\keyword{return} may only occur syntactically nested in a function +definition, not within a nested class definition. +\indexii{function}{definition} +\indexii{class}{definition} + +If an expression list is present, it is evaluated, else \code{None} +is substituted. + +\keyword{return} leaves the current function call with the expression +list (or \code{None}) as return value. + +When \keyword{return} passes control out of a \keyword{try} statement +with a \keyword{finally} clause, that \keyword{finally} clause is executed +before really leaving the function. +\kwindex{finally} + +In a generator function, the \keyword{return} statement is not allowed +to include an \grammartoken{expression_list}. In that context, a bare +\keyword{return} indicates that the generator is done and will cause +\exception{StopIteration} to be raised. + + +\section{The \keyword{yield} statement \label{yield}} +\stindex{yield} + +\begin{productionlist} + \production{yield_stmt} + {\token{yield_expression}} +\end{productionlist} + +\index{generator!function} +\index{generator!iterator} +\index{function!generator} +\exindex{StopIteration} + +The \keyword{yield} statement is only used when defining a generator +function, and is only used in the body of the generator function. +Using a \keyword{yield} statement in a function definition is +sufficient to cause that definition to create a generator function +instead of a normal function. + +When a generator function is called, it returns an iterator known as a +generator iterator, or more commonly, a generator. The body of the +generator function is executed by calling the generator's +\method{next()} method repeatedly until it raises an exception. + +When a \keyword{yield} statement is executed, the state of the +generator is frozen and the value of \grammartoken{expression_list} is +returned to \method{next()}'s caller. By ``frozen'' we mean that all +local state is retained, including the current bindings of local +variables, the instruction pointer, and the internal evaluation stack: +enough information is saved so that the next time \method{next()} is +invoked, the function can proceed exactly as if the \keyword{yield} +statement were just another external call. + +As of Python version 2.5, the \keyword{yield} statement is now +allowed in the \keyword{try} clause of a \keyword{try} ...\ +\keyword{finally} construct. If the generator is not resumed before +it is finalized (by reaching a zero reference count or by being garbage +collected), the generator-iterator's \method{close()} method will be +called, allowing any pending \keyword{finally} clauses to execute. + +\begin{notice} +In Python 2.2, the \keyword{yield} statement is only allowed +when the \code{generators} feature has been enabled. It will always +be enabled in Python 2.3. This \code{__future__} import statement can +be used to enable the feature: + +\begin{verbatim} +from __future__ import generators +\end{verbatim} +\end{notice} + + +\begin{seealso} + \seepep{0255}{Simple Generators} + {The proposal for adding generators and the \keyword{yield} + statement to Python.} + + \seepep{0342}{Coroutines via Enhanced Generators} + {The proposal that, among other generator enhancements, + proposed allowing \keyword{yield} to appear inside a + \keyword{try} ... \keyword{finally} block.} +\end{seealso} + + +\section{The \keyword{raise} statement \label{raise}} +\stindex{raise} + +\begin{productionlist} + \production{raise_stmt} + {"raise" [\token{expression} ["," \token{expression} + ["," \token{expression}]]]} +\end{productionlist} + +If no expressions are present, \keyword{raise} re-raises the last +exception that was active in the current scope. If no exception is +active in the current scope, a \exception{TypeError} exception is +raised indicating that this is an error (if running under IDLE, a +\exception{Queue.Empty} exception is raised instead). +\index{exception} +\indexii{raising}{exception} + +Otherwise, \keyword{raise} evaluates the expressions to get three +objects, using \code{None} as the value of omitted expressions. The +first two objects are used to determine the \emph{type} and +\emph{value} of the exception. + +If the first object is an instance, the type of the exception is the +class of the instance, the instance itself is the value, and the +second object must be \code{None}. + +If the first object is a class, it becomes the type of the exception. +The second object is used to determine the exception value: If it is +an instance of the class, the instance becomes the exception value. +If the second object is a tuple, it is used as the argument list for +the class constructor; if it is \code{None}, an empty argument list is +used, and any other object is treated as a single argument to the +constructor. The instance so created by calling the constructor is +used as the exception value. + +If a third object is present and not \code{None}, it must be a +traceback\obindex{traceback} object (see section~\ref{traceback}), and +it is substituted instead of the current location as the place where +the exception occurred. If the third object is present and not a +traceback object or \code{None}, a \exception{TypeError} exception is +raised. The three-expression form of \keyword{raise} is useful to +re-raise an exception transparently in an except clause, but +\keyword{raise} with no expressions should be preferred if the +exception to be re-raised was the most recently active exception in +the current scope. + +Additional information on exceptions can be found in +section~\ref{exceptions}, and information about handling exceptions is +in section~\ref{try}. + + +\section{The \keyword{break} statement \label{break}} +\stindex{break} + +\begin{productionlist} + \production{break_stmt} + {"break"} +\end{productionlist} + +\keyword{break} may only occur syntactically nested in a \keyword{for} +or \keyword{while} loop, but not nested in a function or class definition +within that loop. +\stindex{for} +\stindex{while} +\indexii{loop}{statement} + +It terminates the nearest enclosing loop, skipping the optional +\keyword{else} clause if the loop has one. +\kwindex{else} + +If a \keyword{for} loop is terminated by \keyword{break}, the loop control +target keeps its current value. +\indexii{loop control}{target} + +When \keyword{break} passes control out of a \keyword{try} statement +with a \keyword{finally} clause, that \keyword{finally} clause is executed +before really leaving the loop. +\kwindex{finally} + + +\section{The \keyword{continue} statement \label{continue}} +\stindex{continue} + +\begin{productionlist} + \production{continue_stmt} + {"continue"} +\end{productionlist} + +\keyword{continue} may only occur syntactically nested in a \keyword{for} or +\keyword{while} loop, but not nested in a function or class definition or +\keyword{finally} statement within that loop.\footnote{It may +occur within an \keyword{except} or \keyword{else} clause. The +restriction on occurring in the \keyword{try} clause is implementor's +laziness and will eventually be lifted.} +It continues with the next cycle of the nearest enclosing loop. +\stindex{for} +\stindex{while} +\indexii{loop}{statement} +\kwindex{finally} + + +\section{The \keyword{import} statement \label{import}} +\stindex{import} +\index{module!importing} +\indexii{name}{binding} +\kwindex{from} + +\begin{productionlist} + \production{import_stmt} + {"import" \token{module} ["as" \token{name}] + ( "," \token{module} ["as" \token{name}] )*} + \productioncont{| "from" \token{relative_module} "import" \token{identifier} + ["as" \token{name}]} + \productioncont{ ( "," \token{identifier} ["as" \token{name}] )*} + \productioncont{| "from" \token{relative_module} "import" "(" + \token{identifier} ["as" \token{name}]} + \productioncont{ ( "," \token{identifier} ["as" \token{name}] )* [","] ")"} + \productioncont{| "from" \token{module} "import" "*"} + \production{module} + {(\token{identifier} ".")* \token{identifier}} + \production{relative_module} + {"."* \token{module} | "."+} + \production{name} + {\token{identifier}} +\end{productionlist} + +Import statements are executed in two steps: (1) find a module, and +initialize it if necessary; (2) define a name or names in the local +namespace (of the scope where the \keyword{import} statement occurs). +The first form (without \keyword{from}) repeats these steps for each +identifier in the list. The form with \keyword{from} performs step +(1) once, and then performs step (2) repeatedly. + +In this context, to ``initialize'' a built-in or extension module means to +call an initialization function that the module must provide for the purpose +(in the reference implementation, the function's name is obtained by +prepending string ``init'' to the module's name); to ``initialize'' a +Python-coded module means to execute the module's body. + +The system maintains a table of modules that have been or are being +initialized, +indexed by module name. This table is +accessible as \code{sys.modules}. When a module name is found in +this table, step (1) is finished. If not, a search for a module +definition is started. When a module is found, it is loaded. Details +of the module searching and loading process are implementation and +platform specific. It generally involves searching for a ``built-in'' +module with the given name and then searching a list of locations +given as \code{sys.path}. +\withsubitem{(in module sys)}{\ttindex{modules}} +\ttindex{sys.modules} +\indexii{module}{name} +\indexii{built-in}{module} +\indexii{user-defined}{module} +\refbimodindex{sys} +\indexii{filename}{extension} +\indexiii{module}{search}{path} + +If a built-in module is found,\indexii{module}{initialization} its +built-in initialization code is executed and step (1) is finished. If +no matching file is found, +\exception{ImportError}\exindex{ImportError} is raised. +\index{code block}If a file is found, it is parsed, +yielding an executable code block. If a syntax error occurs, +\exception{SyntaxError}\exindex{SyntaxError} is raised. Otherwise, an +empty module of the given name is created and inserted in the module +table, and then the code block is executed in the context of this +module. Exceptions during this execution terminate step (1). + +When step (1) finishes without raising an exception, step (2) can +begin. + +The first form of \keyword{import} statement binds the module name in +the local namespace to the module object, and then goes on to import +the next identifier, if any. If the module name is followed by +\keyword{as}, the name following \keyword{as} is used as the local +name for the module. + +The \keyword{from} form does not bind the module name: it goes through the +list of identifiers, looks each one of them up in the module found in step +(1), and binds the name in the local namespace to the object thus found. +As with the first form of \keyword{import}, an alternate local name can be +supplied by specifying "\keyword{as} localname". If a name is not found, +\exception{ImportError} is raised. If the list of identifiers is replaced +by a star (\character{*}), all public names defined in the module are +bound in the local namespace of the \keyword{import} statement.. +\indexii{name}{binding} +\exindex{ImportError} + +The \emph{public names} defined by a module are determined by checking +the module's namespace for a variable named \code{__all__}; if +defined, it must be a sequence of strings which are names defined or +imported by that module. The names given in \code{__all__} are all +considered public and are required to exist. If \code{__all__} is not +defined, the set of public names includes all names found in the +module's namespace which do not begin with an underscore character +(\character{_}). \code{__all__} should contain the entire public API. +It is intended to avoid accidentally exporting items that are not part +of the API (such as library modules which were imported and used within +the module). +\withsubitem{(optional module attribute)}{\ttindex{__all__}} + +The \keyword{from} form with \samp{*} may only occur in a module +scope. If the wild card form of import --- \samp{import *} --- is +used in a function and the function contains or is a nested block with +free variables, the compiler will raise a \exception{SyntaxError}. + +\kwindex{from} +\stindex{from} + +\strong{Hierarchical module names:}\indexiii{hierarchical}{module}{names} +when the module names contains one or more dots, the module search +path is carried out differently. The sequence of identifiers up to +the last dot is used to find a ``package''\index{packages}; the final +identifier is then searched inside the package. A package is +generally a subdirectory of a directory on \code{sys.path} that has a +file \file{__init__.py}.\ttindex{__init__.py} +% +[XXX Can't be bothered to spell this out right now; see the URL +\url{http://www.python.org/doc/essays/packages.html} for more details, also +about how the module search works from inside a package.] + +The built-in function \function{__import__()} is provided to support +applications that determine which modules need to be loaded +dynamically; refer to \ulink{Built-in +Functions}{../lib/built-in-funcs.html} in the +\citetitle[../lib/lib.html]{Python Library Reference} for additional +information. +\bifuncindex{__import__} + +\subsection{Future statements \label{future}} + +A \dfn{future statement}\indexii{future}{statement} is a directive to +the compiler that a particular module should be compiled using syntax +or semantics that will be available in a specified future release of +Python. The future statement is intended to ease migration to future +versions of Python that introduce incompatible changes to the +language. It allows use of the new features on a per-module basis +before the release in which the feature becomes standard. + +\begin{productionlist}[*] + \production{future_statement} + {"from" "__future__" "import" feature ["as" name]} + \productioncont{ ("," feature ["as" name])*} + \productioncont{| "from" "__future__" "import" "(" feature ["as" name]} + \productioncont{ ("," feature ["as" name])* [","] ")"} + \production{feature}{identifier} + \production{name}{identifier} +\end{productionlist} + +A future statement must appear near the top of the module. The only +lines that can appear before a future statement are: + +\begin{itemize} + +\item the module docstring (if any), +\item comments, +\item blank lines, and +\item other future statements. + +\end{itemize} + +The features recognized by Python 2.5 are \samp{absolute_import}, +\samp{division}, \samp{generators}, \samp{nested_scopes} and +\samp{with_statement}. \samp{generators} and \samp{nested_scopes} +are redundant in Python version 2.3 and above because they are always +enabled. + +A future statement is recognized and treated specially at compile +time: Changes to the semantics of core constructs are often +implemented by generating different code. It may even be the case +that a new feature introduces new incompatible syntax (such as a new +reserved word), in which case the compiler may need to parse the +module differently. Such decisions cannot be pushed off until +runtime. + +For any given release, the compiler knows which feature names have been +defined, and raises a compile-time error if a future statement contains +a feature not known to it. + +The direct runtime semantics are the same as for any import statement: +there is a standard module \module{__future__}, described later, and +it will be imported in the usual way at the time the future statement +is executed. + +The interesting runtime semantics depend on the specific feature +enabled by the future statement. + +Note that there is nothing special about the statement: + +\begin{verbatim} +import __future__ [as name] +\end{verbatim} + +That is not a future statement; it's an ordinary import statement with +no special semantics or syntax restrictions. + +Code compiled by an \keyword{exec} statement or calls to the builtin functions +\function{compile()} and \function{execfile()} that occur in a module +\module{M} containing a future statement will, by default, use the new +syntax or semantics associated with the future statement. This can, +starting with Python 2.2 be controlled by optional arguments to +\function{compile()} --- see the documentation of that function in the +\citetitle[../lib/built-in-funcs.html]{Python Library Reference} for +details. + +A future statement typed at an interactive interpreter prompt will +take effect for the rest of the interpreter session. If an +interpreter is started with the \programopt{-i} option, is passed a +script name to execute, and the script includes a future statement, it +will be in effect in the interactive session started after the script +is executed. + +\section{The \keyword{global} statement \label{global}} +\stindex{global} + +\begin{productionlist} + \production{global_stmt} + {"global" \token{identifier} ("," \token{identifier})*} +\end{productionlist} + +The \keyword{global} statement is a declaration which holds for the +entire current code block. It means that the listed identifiers are to be +interpreted as globals. It would be impossible to assign to a global +variable without \keyword{global}, although free variables may refer +to globals without being declared global. +\indexiii{global}{name}{binding} + +Names listed in a \keyword{global} statement must not be used in the same +code block textually preceding that \keyword{global} statement. + +Names listed in a \keyword{global} statement must not be defined as formal +parameters or in a \keyword{for} loop control target, \keyword{class} +definition, function definition, or \keyword{import} statement. + +(The current implementation does not enforce the latter two +restrictions, but programs should not abuse this freedom, as future +implementations may enforce them or silently change the meaning of the +program.) + +\strong{Programmer's note:} +the \keyword{global} is a directive to the parser. It +applies only to code parsed at the same time as the \keyword{global} +statement. In particular, a \keyword{global} statement contained in an +\keyword{exec} statement does not affect the code block \emph{containing} +the \keyword{exec} statement, and code contained in an \keyword{exec} +statement is unaffected by \keyword{global} statements in the code +containing the \keyword{exec} statement. The same applies to the +\function{eval()}, \function{execfile()} and \function{compile()} functions. +\stindex{exec} +\bifuncindex{eval} +\bifuncindex{execfile} +\bifuncindex{compile} + + +\section{The \keyword{exec} statement \label{exec}} +\stindex{exec} + +\begin{productionlist} + \production{exec_stmt} + {"exec" \token{or_expr} + ["in" \token{expression} ["," \token{expression}]]} +\end{productionlist} + +This statement supports dynamic execution of Python code. The first +expression should evaluate to either a string, an open file object, or +a code object. If it is a string, the string is parsed as a suite of +Python statements which is then executed (unless a syntax error +occurs). If it is an open file, the file is parsed until \EOF{} and +executed. If it is a code object, it is simply executed. In all +cases, the code that's executed is expected to be valid as file +input (see section~\ref{file-input}, ``File input''). Be aware that +the \keyword{return} and \keyword{yield} statements may not be used +outside of function definitions even within the context of code passed +to the \keyword{exec} statement. + +In all cases, if the optional parts are omitted, the code is executed +in the current scope. If only the first expression after \keyword{in} +is specified, it should be a dictionary, which will be used for both +the global and the local variables. If two expressions are given, +they are used for the global and local variables, respectively. +If provided, \var{locals} can be any mapping object. +\versionchanged[formerly \var{locals} was required to be a dictionary]{2.4} + +As a side effect, an implementation may insert additional keys into +the dictionaries given besides those corresponding to variable names +set by the executed code. For example, the current implementation +may add a reference to the dictionary of the built-in module +\module{__builtin__} under the key \code{__builtins__} (!). +\ttindex{__builtins__} +\refbimodindex{__builtin__} + +\strong{Programmer's hints:} +dynamic evaluation of expressions is supported by the built-in +function \function{eval()}. The built-in functions +\function{globals()} and \function{locals()} return the current global +and local dictionary, respectively, which may be useful to pass around +for use by \keyword{exec}. +\bifuncindex{eval} +\bifuncindex{globals} +\bifuncindex{locals} + + + + + diff --git a/sys/src/cmd/python/Doc/ref/ref7.tex b/sys/src/cmd/python/Doc/ref/ref7.tex new file mode 100644 index 000000000..c9e07fb7e --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref7.tex @@ -0,0 +1,544 @@ +\chapter{Compound statements\label{compound}} +\indexii{compound}{statement} + +Compound statements contain (groups of) other statements; they affect +or control the execution of those other statements in some way. In +general, compound statements span multiple lines, although in simple +incarnations a whole compound statement may be contained in one line. + +The \keyword{if}, \keyword{while} and \keyword{for} statements implement +traditional control flow constructs. \keyword{try} specifies exception +handlers and/or cleanup code for a group of statements. Function and +class definitions are also syntactically compound statements. + +Compound statements consist of one or more `clauses.' A clause +consists of a header and a `suite.' The clause headers of a +particular compound statement are all at the same indentation level. +Each clause header begins with a uniquely identifying keyword and ends +with a colon. A suite is a group of statements controlled by a +clause. A suite can be one or more semicolon-separated simple +statements on the same line as the header, following the header's +colon, or it can be one or more indented statements on subsequent +lines. Only the latter form of suite can contain nested compound +statements; the following is illegal, mostly because it wouldn't be +clear to which \keyword{if} clause a following \keyword{else} clause would +belong: +\index{clause} +\index{suite} + +\begin{verbatim} +if test1: if test2: print x +\end{verbatim} + +Also note that the semicolon binds tighter than the colon in this +context, so that in the following example, either all or none of the +\keyword{print} statements are executed: + +\begin{verbatim} +if x < y < z: print x; print y; print z +\end{verbatim} + +Summarizing: + +\begin{productionlist} + \production{compound_stmt} + {\token{if_stmt}} + \productioncont{| \token{while_stmt}} + \productioncont{| \token{for_stmt}} + \productioncont{| \token{try_stmt}} + \productioncont{| \token{with_stmt}} + \productioncont{| \token{funcdef}} + \productioncont{| \token{classdef}} + \production{suite} + {\token{stmt_list} NEWLINE + | NEWLINE INDENT \token{statement}+ DEDENT} + \production{statement} + {\token{stmt_list} NEWLINE | \token{compound_stmt}} + \production{stmt_list} + {\token{simple_stmt} (";" \token{simple_stmt})* [";"]} +\end{productionlist} + +Note that statements always end in a +\code{NEWLINE}\index{NEWLINE token} possibly followed by a +\code{DEDENT}.\index{DEDENT token} Also note that optional +continuation clauses always begin with a keyword that cannot start a +statement, thus there are no ambiguities (the `dangling +\keyword{else}' problem is solved in Python by requiring nested +\keyword{if} statements to be indented). +\indexii{dangling}{else} + +The formatting of the grammar rules in the following sections places +each clause on a separate line for clarity. + + +\section{The \keyword{if} statement\label{if}} +\stindex{if} + +The \keyword{if} statement is used for conditional execution: + +\begin{productionlist} + \production{if_stmt} + {"if" \token{expression} ":" \token{suite}} + \productioncont{( "elif" \token{expression} ":" \token{suite} )*} + \productioncont{["else" ":" \token{suite}]} +\end{productionlist} + +It selects exactly one of the suites by evaluating the expressions one +by one until one is found to be true (see section~\ref{Booleans} for +the definition of true and false); then that suite is executed (and no +other part of the \keyword{if} statement is executed or evaluated). If +all expressions are false, the suite of the \keyword{else} clause, if +present, is executed. +\kwindex{elif} +\kwindex{else} + + +\section{The \keyword{while} statement\label{while}} +\stindex{while} +\indexii{loop}{statement} + +The \keyword{while} statement is used for repeated execution as long +as an expression is true: + +\begin{productionlist} + \production{while_stmt} + {"while" \token{expression} ":" \token{suite}} + \productioncont{["else" ":" \token{suite}]} +\end{productionlist} + +This repeatedly tests the expression and, if it is true, executes the +first suite; if the expression is false (which may be the first time it +is tested) the suite of the \keyword{else} clause, if present, is +executed and the loop terminates. +\kwindex{else} + +A \keyword{break} statement executed in the first suite terminates the +loop without executing the \keyword{else} clause's suite. A +\keyword{continue} statement executed in the first suite skips the rest +of the suite and goes back to testing the expression. +\stindex{break} +\stindex{continue} + + +\section{The \keyword{for} statement\label{for}} +\stindex{for} +\indexii{loop}{statement} + +The \keyword{for} statement is used to iterate over the elements of a +sequence (such as a string, tuple or list) or other iterable object: +\obindex{sequence} + +\begin{productionlist} + \production{for_stmt} + {"for" \token{target_list} "in" \token{expression_list} + ":" \token{suite}} + \productioncont{["else" ":" \token{suite}]} +\end{productionlist} + +The expression list is evaluated once; it should yield an iterable +object. An iterator is created for the result of the +{}\code{expression_list}. The suite is then executed once for each +item provided by the iterator, in the +order of ascending indices. Each item in turn is assigned to the +target list using the standard rules for assignments, and then the +suite is executed. When the items are exhausted (which is immediately +when the sequence is empty), the suite in the \keyword{else} clause, if +present, is executed, and the loop terminates. +\kwindex{in} +\kwindex{else} +\indexii{target}{list} + +A \keyword{break} statement executed in the first suite terminates the +loop without executing the \keyword{else} clause's suite. A +\keyword{continue} statement executed in the first suite skips the rest +of the suite and continues with the next item, or with the \keyword{else} +clause if there was no next item. +\stindex{break} +\stindex{continue} + +The suite may assign to the variable(s) in the target list; this does +not affect the next item assigned to it. + +The target list is not deleted when the loop is finished, but if the +sequence is empty, it will not have been assigned to at all by the +loop. Hint: the built-in function \function{range()} returns a +sequence of integers suitable to emulate the effect of Pascal's +\code{for i := a to b do}; +e.g., \code{range(3)} returns the list \code{[0, 1, 2]}. +\bifuncindex{range} +\indexii{Pascal}{language} + +\warning{There is a subtlety when the sequence is being modified +by the loop (this can only occur for mutable sequences, i.e. lists). +An internal counter is used to keep track of which item is used next, +and this is incremented on each iteration. When this counter has +reached the length of the sequence the loop terminates. This means that +if the suite deletes the current (or a previous) item from the +sequence, the next item will be skipped (since it gets the index of +the current item which has already been treated). Likewise, if the +suite inserts an item in the sequence before the current item, the +current item will be treated again the next time through the loop. +This can lead to nasty bugs that can be avoided by making a temporary +copy using a slice of the whole sequence, e.g., +\index{loop!over mutable sequence} +\index{mutable sequence!loop over}} + +\begin{verbatim} +for x in a[:]: + if x < 0: a.remove(x) +\end{verbatim} + + +\section{The \keyword{try} statement\label{try}} +\stindex{try} + +The \keyword{try} statement specifies exception handlers and/or cleanup +code for a group of statements: + +\begin{productionlist} + \production{try_stmt} {try1_stmt | try2_stmt} + \production{try1_stmt} + {"try" ":" \token{suite}} + \productioncont{("except" [\token{expression} + ["," \token{target}]] ":" \token{suite})+} + \productioncont{["else" ":" \token{suite}]} + \productioncont{["finally" ":" \token{suite}]} + \production{try2_stmt} + {"try" ":" \token{suite}} + \productioncont{"finally" ":" \token{suite}} +\end{productionlist} + +\versionchanged[In previous versions of Python, +\keyword{try}...\keyword{except}...\keyword{finally} did not work. +\keyword{try}...\keyword{except} had to be nested in +\keyword{try}...\keyword{finally}]{2.5} + +The \keyword{except} clause(s) specify one or more exception handlers. +When no exception occurs in the +\keyword{try} clause, no exception handler is executed. When an +exception occurs in the \keyword{try} suite, a search for an exception +handler is started. This search inspects the except clauses in turn until +one is found that matches the exception. An expression-less except +clause, if present, must be last; it matches any exception. For an +except clause with an expression, that expression is evaluated, and the +clause matches the exception if the resulting object is ``compatible'' +with the exception. An object is compatible with an exception if it +is the class or a base class of the exception object, a tuple +containing an item compatible with the exception, or, in the +(deprecated) case of string exceptions, is the raised string itself +(note that the object identities must match, i.e. it must be the same +string object, not just a string with the same value). +\kwindex{except} + +If no except clause matches the exception, the search for an exception +handler continues in the surrounding code and on the invocation stack. +\footnote{The exception is propogated to the invocation stack only if +there is no \keyword{finally} clause that negates the exception.} + +If the evaluation of an expression in the header of an except clause +raises an exception, the original search for a handler is canceled +and a search starts for the new exception in the surrounding code and +on the call stack (it is treated as if the entire \keyword{try} statement +raised the exception). + +When a matching except clause is found, the exception is assigned to +the target specified in that except clause, if present, and the except +clause's suite is executed. All except clauses must have an +executable block. When the end of this block is reached, execution +continues normally after the entire try statement. (This means that +if two nested handlers exist for the same exception, and the exception +occurs in the try clause of the inner handler, the outer handler will +not handle the exception.) + +Before an except clause's suite is executed, details about the +exception are assigned to three variables in the +\module{sys}\refbimodindex{sys} module: \code{sys.exc_type} receives +the object identifying the exception; \code{sys.exc_value} receives +the exception's parameter; \code{sys.exc_traceback} receives a +traceback object\obindex{traceback} (see section~\ref{traceback}) +identifying the point in the program where the exception occurred. +These details are also available through the \function{sys.exc_info()} +function, which returns a tuple \code{(\var{exc_type}, \var{exc_value}, +\var{exc_traceback})}. Use of the corresponding variables is +deprecated in favor of this function, since their use is unsafe in a +threaded program. As of Python 1.5, the variables are restored to +their previous values (before the call) when returning from a function +that handled an exception. +\withsubitem{(in module sys)}{\ttindex{exc_type} + \ttindex{exc_value}\ttindex{exc_traceback}} + +The optional \keyword{else} clause is executed if and when control +flows off the end of the \keyword{try} clause.\footnote{ + Currently, control ``flows off the end'' except in the case of an + exception or the execution of a \keyword{return}, + \keyword{continue}, or \keyword{break} statement. +} Exceptions in the \keyword{else} clause are not handled by the +preceding \keyword{except} clauses. +\kwindex{else} +\stindex{return} +\stindex{break} +\stindex{continue} + +If \keyword{finally} is present, it specifies a `cleanup' handler. The +\keyword{try} clause is executed, including any \keyword{except} and +\keyword{else} clauses. If an exception occurs in any of the clauses +and is not handled, the exception is temporarily saved. The +\keyword{finally} clause is executed. If there is a saved exception, +it is re-raised at the end of the \keyword{finally} clause. +If the \keyword{finally} clause raises another exception or +executes a \keyword{return} or \keyword{break} statement, the saved +exception is lost. The exception information is not available to the +program during execution of the \keyword{finally} clause. +\kwindex{finally} + +When a \keyword{return}, \keyword{break} or \keyword{continue} statement is +executed in the \keyword{try} suite of a \keyword{try}...\keyword{finally} +statement, the \keyword{finally} clause is also executed `on the way out.' A +\keyword{continue} statement is illegal in the \keyword{finally} clause. +(The reason is a problem with the current implementation --- this +restriction may be lifted in the future). +\stindex{return} +\stindex{break} +\stindex{continue} + +Additional information on exceptions can be found in +section~\ref{exceptions}, and information on using the \keyword{raise} +statement to generate exceptions may be found in section~\ref{raise}. + + +\section{The \keyword{with} statement\label{with}} +\stindex{with} + +\versionadded{2.5} + +The \keyword{with} statement is used to wrap the execution of a block +with methods defined by a context manager (see +section~\ref{context-managers}). This allows common +\keyword{try}...\keyword{except}...\keyword{finally} usage patterns to +be encapsulated for convenient reuse. + +\begin{productionlist} + \production{with_stmt} + {"with" \token{expression} ["as" \token{target}] ":" \token{suite}} +\end{productionlist} + +The execution of the \keyword{with} statement proceeds as follows: + +\begin{enumerate} + +\item The context expression is evaluated to obtain a context manager. + +\item The context manager's \method{__enter__()} method is invoked. + +\item If a target was included in the \keyword{with} +statement, the return value from \method{__enter__()} is assigned to it. + +\note{The \keyword{with} statement guarantees that if the +\method{__enter__()} method returns without an error, then +\method{__exit__()} will always be called. Thus, if an error occurs +during the assignment to the target list, it will be treated the same as +an error occurring within the suite would be. See step 5 below.} + +\item The suite is executed. + +\item The context manager's \method{__exit__()} method is invoked. If +an exception caused the suite to be exited, its type, value, and +traceback are passed as arguments to \method{__exit__()}. Otherwise, +three \constant{None} arguments are supplied. + +If the suite was exited due to an exception, and the return +value from the \method{__exit__()} method was false, the exception is +reraised. If the return value was true, the exception is suppressed, and +execution continues with the statement following the \keyword{with} +statement. + +If the suite was exited for any reason other than an exception, the +return value from \method{__exit__()} is ignored, and execution proceeds +at the normal location for the kind of exit that was taken. + +\end{enumerate} + +\begin{notice} +In Python 2.5, the \keyword{with} statement is only allowed +when the \code{with_statement} feature has been enabled. It will always +be enabled in Python 2.6. This \code{__future__} import statement can +be used to enable the feature: + +\begin{verbatim} +from __future__ import with_statement +\end{verbatim} +\end{notice} + +\begin{seealso} + \seepep{0343}{The "with" statement} + {The specification, background, and examples for the + Python \keyword{with} statement.} +\end{seealso} + +\section{Function definitions\label{function}} +\indexii{function}{definition} +\stindex{def} + +A function definition defines a user-defined function object (see +section~\ref{types}): +\obindex{user-defined function} +\obindex{function} + +\begin{productionlist} + \production{funcdef} + {[\token{decorators}] "def" \token{funcname} "(" [\token{parameter_list}] ")" + ":" \token{suite}} + \production{decorators} + {\token{decorator}+} + \production{decorator} + {"@" \token{dotted_name} ["(" [\token{argument_list} [","]] ")"] NEWLINE} + \production{dotted_name} + {\token{identifier} ("." \token{identifier})*} + \production{parameter_list} + {(\token{defparameter} ",")*} + \productioncont{(~~"*" \token{identifier} [, "**" \token{identifier}]} + \productioncont{ | "**" \token{identifier}} + \productioncont{ | \token{defparameter} [","] )} + \production{defparameter} + {\token{parameter} ["=" \token{expression}]} + \production{sublist} + {\token{parameter} ("," \token{parameter})* [","]} + \production{parameter} + {\token{identifier} | "(" \token{sublist} ")"} + \production{funcname} + {\token{identifier}} +\end{productionlist} + +A function definition is an executable statement. Its execution binds +the function name in the current local namespace to a function object +(a wrapper around the executable code for the function). This +function object contains a reference to the current global namespace +as the global namespace to be used when the function is called. +\indexii{function}{name} +\indexii{name}{binding} + +The function definition does not execute the function body; this gets +executed only when the function is called. + +A function definition may be wrapped by one or more decorator expressions. +Decorator expressions are evaluated when the function is defined, in the scope +that contains the function definition. The result must be a callable, +which is invoked with the function object as the only argument. +The returned value is bound to the function name instead of the function +object. Multiple decorators are applied in nested fashion. +For example, the following code: + +\begin{verbatim} +@f1(arg) +@f2 +def func(): pass +\end{verbatim} + +is equivalent to: + +\begin{verbatim} +def func(): pass +func = f1(arg)(f2(func)) +\end{verbatim} + +When one or more top-level parameters have the form \var{parameter} +\code{=} \var{expression}, the function is said to have ``default +parameter values.'' For a parameter with a +default value, the corresponding argument may be omitted from a call, +in which case the parameter's default value is substituted. If a +parameter has a default value, all following parameters must also have +a default value --- this is a syntactic restriction that is not +expressed by the grammar. +\indexiii{default}{parameter}{value} + +\strong{Default parameter values are evaluated when the function +definition is executed.} This means that the expression is evaluated +once, when the function is defined, and that that same +``pre-computed'' value is used for each call. This is especially +important to understand when a default parameter is a mutable object, +such as a list or a dictionary: if the function modifies the object +(e.g. by appending an item to a list), the default value is in effect +modified. This is generally not what was intended. A way around this +is to use \code{None} as the default, and explicitly test for it in +the body of the function, e.g.: + +\begin{verbatim} +def whats_on_the_telly(penguin=None): + if penguin is None: + penguin = [] + penguin.append("property of the zoo") + return penguin +\end{verbatim} + +Function call semantics are described in more detail in +section~\ref{calls}. +A function call always assigns values to all parameters mentioned in +the parameter list, either from position arguments, from keyword +arguments, or from default values. If the form ``\code{*identifier}'' +is present, it is initialized to a tuple receiving any excess +positional parameters, defaulting to the empty tuple. If the form +``\code{**identifier}'' is present, it is initialized to a new +dictionary receiving any excess keyword arguments, defaulting to a +new empty dictionary. + +It is also possible to create anonymous functions (functions not bound +to a name), for immediate use in expressions. This uses lambda forms, +described in section~\ref{lambda}. Note that the lambda form is +merely a shorthand for a simplified function definition; a function +defined in a ``\keyword{def}'' statement can be passed around or +assigned to another name just like a function defined by a lambda +form. The ``\keyword{def}'' form is actually more powerful since it +allows the execution of multiple statements. +\indexii{lambda}{form} + +\strong{Programmer's note:} Functions are first-class objects. A +``\code{def}'' form executed inside a function definition defines a +local function that can be returned or passed around. Free variables +used in the nested function can access the local variables of the +function containing the def. See section~\ref{naming} for details. + + +\section{Class definitions\label{class}} +\indexii{class}{definition} +\stindex{class} + +A class definition defines a class object (see section~\ref{types}): +\obindex{class} + +\begin{productionlist} + \production{classdef} + {"class" \token{classname} [\token{inheritance}] ":" + \token{suite}} + \production{inheritance} + {"(" [\token{expression_list}] ")"} + \production{classname} + {\token{identifier}} +\end{productionlist} + +A class definition is an executable statement. It first evaluates the +inheritance list, if present. Each item in the inheritance list +should evaluate to a class object or class type which allows +subclassing. The class's suite is then executed +in a new execution frame (see section~\ref{naming}), using a newly +created local namespace and the original global namespace. +(Usually, the suite contains only function definitions.) When the +class's suite finishes execution, its execution frame is discarded but +its local namespace is saved. A class object is then created using +the inheritance list for the base classes and the saved local +namespace for the attribute dictionary. The class name is bound to this +class object in the original local namespace. +\index{inheritance} +\indexii{class}{name} +\indexii{name}{binding} +\indexii{execution}{frame} + +\strong{Programmer's note:} Variables defined in the class definition +are class variables; they are shared by all instances. To define +instance variables, they must be given a value in the +\method{__init__()} method or in another method. Both class and +instance variables are accessible through the notation +``\code{self.name}'', and an instance variable hides a class variable +with the same name when accessed in this way. Class variables with +immutable values can be used as defaults for instance variables. +For new-style classes, descriptors can be used to create instance +variables with different implementation details. diff --git a/sys/src/cmd/python/Doc/ref/ref8.tex b/sys/src/cmd/python/Doc/ref/ref8.tex new file mode 100644 index 000000000..b77789f71 --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/ref8.tex @@ -0,0 +1,112 @@ +\chapter{Top-level components\label{top-level}} + +The Python interpreter can get its input from a number of sources: +from a script passed to it as standard input or as program argument, +typed in interactively, from a module source file, etc. This chapter +gives the syntax used in these cases. +\index{interpreter} + + +\section{Complete Python programs\label{programs}} +\index{program} + +While a language specification need not prescribe how the language +interpreter is invoked, it is useful to have a notion of a complete +Python program. A complete Python program is executed in a minimally +initialized environment: all built-in and standard modules are +available, but none have been initialized, except for \module{sys} +(various system services), \module{__builtin__} (built-in functions, +exceptions and \code{None}) and \module{__main__}. The latter is used +to provide the local and global namespace for execution of the +complete program. +\refbimodindex{sys} +\refbimodindex{__main__} +\refbimodindex{__builtin__} + +The syntax for a complete Python program is that for file input, +described in the next section. + +The interpreter may also be invoked in interactive mode; in this case, +it does not read and execute a complete program but reads and executes +one statement (possibly compound) at a time. The initial environment +is identical to that of a complete program; each statement is executed +in the namespace of \module{__main__}. +\index{interactive mode} +\refbimodindex{__main__} + +Under \UNIX, a complete program can be passed to the interpreter in +three forms: with the \programopt{-c} \var{string} command line option, as a +file passed as the first command line argument, or as standard input. +If the file or standard input is a tty device, the interpreter enters +interactive mode; otherwise, it executes the file as a complete +program. +\index{UNIX} +\index{command line} +\index{standard input} + + +\section{File input\label{file-input}} + +All input read from non-interactive files has the same form: + +\begin{productionlist} + \production{file_input} + {(NEWLINE | \token{statement})*} +\end{productionlist} + +This syntax is used in the following situations: + +\begin{itemize} + +\item when parsing a complete Python program (from a file or from a string); + +\item when parsing a module; + +\item when parsing a string passed to the \keyword{exec} statement; + +\end{itemize} + + +\section{Interactive input\label{interactive}} + +Input in interactive mode is parsed using the following grammar: + +\begin{productionlist} + \production{interactive_input} + {[\token{stmt_list}] NEWLINE | \token{compound_stmt} NEWLINE} +\end{productionlist} + +Note that a (top-level) compound statement must be followed by a blank +line in interactive mode; this is needed to help the parser detect the +end of the input. + + +\section{Expression input\label{expression-input}} +\index{input} + +There are two forms of expression input. Both ignore leading +whitespace. +The string argument to \function{eval()} must have the following form: +\bifuncindex{eval} + +\begin{productionlist} + \production{eval_input} + {\token{expression_list} NEWLINE*} +\end{productionlist} + +The input line read by \function{input()} must have the following form: +\bifuncindex{input} + +\begin{productionlist} + \production{input_input} + {\token{expression_list} NEWLINE} +\end{productionlist} + +Note: to read `raw' input line without interpretation, you can use the +built-in function \function{raw_input()} or the \method{readline()} method +of file objects. +\obindex{file} +\index{input!raw} +\index{raw input} +\bifuncindex{raw_input} +\withsubitem{(file method)}{\ttindex{readline()}} diff --git a/sys/src/cmd/python/Doc/ref/reswords.py b/sys/src/cmd/python/Doc/ref/reswords.py new file mode 100644 index 000000000..68862bbcf --- /dev/null +++ b/sys/src/cmd/python/Doc/ref/reswords.py @@ -0,0 +1,23 @@ +"""Spit out the Python reserved words table.""" + +import keyword + +ncols = 5 + +def main(): + words = keyword.kwlist[:] + words.sort() + colwidth = 1 + max(map(len, words)) + nwords = len(words) + nrows = (nwords + ncols - 1) / ncols + for irow in range(nrows): + for icol in range(ncols): + i = irow + icol * nrows + if 0 <= i < nwords: + word = words[i] + else: + word = "" + print "%-*s" % (colwidth, word), + print + +main() diff --git a/sys/src/cmd/python/Doc/templates/howto.tex b/sys/src/cmd/python/Doc/templates/howto.tex new file mode 100644 index 000000000..fdbb0657c --- /dev/null +++ b/sys/src/cmd/python/Doc/templates/howto.tex @@ -0,0 +1,112 @@ +% Complete documentation on the extended LaTeX markup used for Python +% documentation is available in ``Documenting Python'', which is part +% of the standard documentation for Python. It may be found online +% at: +% +% http://www.python.org/doc/current/doc/doc.html + +\documentclass{howto} + +% This is a template for short or medium-size Python-related documents, +% mostly notably the series of HOWTOs, but it can be used for any +% document you like. + +% The title should be descriptive enough for people to be able to find +% the relevant document. +\title{Spammifying Sprockets in Python} + +% Increment the release number whenever significant changes are made. +% The author and/or editor can define 'significant' however they like. +\release{0.00} + +% At minimum, give your name and an email address. You can include a +% snail-mail address if you like. +\author{Me, 'cause I wrote it} +\authoraddress{Me, 'cause I'm self-employed.} + +\begin{document} +\maketitle + +% This makes the Abstract go on a separate page in the HTML version; +% if a copyright notice is used, it should go immediately after this. +% +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +% Copyright statement should go here, if needed. +% ... + +% The abstract should be a paragraph or two long, and describe the +% scope of the document. +\begin{abstract} +\noindent +This document describes how to spammify sprockets. It is a useful +example of a Python HOWTO document. It is not dependent on any +particular sprocket implementation, and includes a Python-based +implementation in the \module{sprunkit} module. +\end{abstract} + +\tableofcontents + +Spammifying sprockets from Python is both fun and entertaining. +Applying the techniques described here, you can also fill your hard +disk quite effectively. + +\section{What is Sprocket Spammification?} + +You have to ask? It's the only thing to do to your sprockets! + + +\section{Why Use Python?} + +Python is an excellent language from which to spammify your sprockets +since you can do it on any platform. + + +\section{Software Requirements} + +You need to have the following software installed: + +% The {itemize} environment uses a bullet for each \item. If you want the +% \item's numbered, use the {enumerate} environment instead. +\begin{itemize} + \item Python 1.9. + \item Some sprocket definition files. + \item At least one sprocket system implementation. +\end{itemize} + +Note that the \module{sprunkit} is provided with this package and +implements ActiveSprockets in Python. + + +% The preceding sections will have been written in a gentler, +% introductory style. You may also wish to include a reference +% section, documenting all the functions/exceptions/constants. +% Often, these will be placed in separate files and input like this: + +\input{module} + + +\appendix + +\section{This is an Appendix} + +To create an appendix in a Python HOWTO document, use markup like +this: + +\begin{verbatim} +\appendix + +\section{This is an Appendix} + +To create an appendix in a Python HOWTO document, .... + + +\section{This is another} + +Just add another \section{}, but don't say \appendix again. +\end{verbatim} + + +\end{document} diff --git a/sys/src/cmd/python/Doc/templates/manual.tex b/sys/src/cmd/python/Doc/templates/manual.tex new file mode 100644 index 000000000..19dec8bf6 --- /dev/null +++ b/sys/src/cmd/python/Doc/templates/manual.tex @@ -0,0 +1,89 @@ +% Complete documentation on the extended LaTeX markup used for Python +% documentation is available in ``Documenting Python'', which is part +% of the standard documentation for Python. It may be found online +% at: +% +% http://www.python.org/doc/current/doc/doc.html + +\documentclass{manual} + +\title{Big Python Manual} + +\author{Your Name Here} + +% Please at least include a long-lived email address; +% the rest is at your discretion. +\authoraddress{ + Organization name, if applicable \\ + Street address, if you want to use it \\ + Email: \email{your-email@your.domain} +} + +\date{April 30, 1999} % update before release! + % Use an explicit date so that reformatting + % doesn't cause a new date to be used. Setting + % the date to \today can be used during draft + % stages to make it easier to handle versions. + +\release{x.y} % release version; this is used to define the + % \version macro + +\makeindex % tell \index to actually write the .idx file +\makemodindex % If this contains a lot of module sections. + + +\begin{document} + +\maketitle + +% This makes the contents more accessible from the front page of the HTML. +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +%\input{copyright} + +\begin{abstract} + +\noindent +Big Python is a special version of Python for users who require larger +keys on their keyboards. It accommodates their special needs by ... + +\end{abstract} + +\tableofcontents + + +\chapter{...} + +My chapter. + + +\appendix +\chapter{...} + +My appendix. + +The \code{\e appendix} markup need not be repeated for additional +appendices. + + +% +% The ugly "%begin{latexonly}" pseudo-environments are really just to +% keep LaTeX2HTML quiet during the \renewcommand{} macros; they're +% not really valuable. +% +% If you don't want the Module Index, you can remove all of this up +% until the second \input line. +% +%begin{latexonly} +\renewcommand{\indexname}{Module Index} +%end{latexonly} +\input{mod\jobname.ind} % Module Index + +%begin{latexonly} +\renewcommand{\indexname}{Index} +%end{latexonly} +\input{\jobname.ind} % Index + +\end{document} diff --git a/sys/src/cmd/python/Doc/templates/module.tex b/sys/src/cmd/python/Doc/templates/module.tex new file mode 100644 index 000000000..69e1b1216 --- /dev/null +++ b/sys/src/cmd/python/Doc/templates/module.tex @@ -0,0 +1,170 @@ +% Template for a library manual section. +% PLEASE REMOVE THE COMMENTS AFTER USING THE TEMPLATE +% +% Complete documentation on the extended LaTeX markup used for Python +% documentation is available in ``Documenting Python'', which is part +% of the standard documentation for Python. It may be found online +% at: +% +% http://www.python.org/doc/current/doc/doc.html + +% ==== 0. ==== +% Copy this file to <mydir>/lib<mymodule>.tex, and edit that file +% according to the instructions below. + + +% ==== 1. ==== +% The section prologue. Give the section a title and provide some +% meta-information. References to the module should use +% \refbimodindex, \refstmodindex, \refexmodindex or \refmodindex, as +% appropriate. + +\section{\module{spam} --- + Short description, for section title and table of contents} + +% Choose one of these to specify the module module name. If there's +% an underscore in the name, use +% \declaremodule[modname]{...}{mod_name} instead. +% +\declaremodule{builtin}{spam} % standard library, in C +\declaremodule{standard}{spam} % standard library, in Python +\declaremodule{extension}{spam} % not standard, in C +\declaremodule{}{spam} % not standard, in Python + +% Portability statement: Uncomment and fill in the parameter to specify the +% availability of the module. The parameter can be Unix, IRIX, SunOS, Mac, +% Windows, or lots of other stuff. When ``Mac'' is specified, the availability +% statement will say ``Macintosh'' and the Module Index may say ``Mac''. +% Please use a name that has already been used whenever applicable. If this +% is omitted, no availability statement is produced or implied. +% +% \platform{Unix} + +% These apply to all modules, and may be given more than once: + +\moduleauthor{name}{email} % Author of the module code; + % omit if not known. +\sectionauthor{name}{email} % Author of the documentation, + % even if not a module section. + + +% Leave at least one blank line after this, to simplify ad-hoc tools +% that are sometimes used to massage these files. +\modulesynopsis{This is a one-line description, for the chapter header.} + + +% ==== 2. ==== +% Give a short overview of what the module does. +% If it is platform specific, mention this. +% Mention other important restrictions or general operating principles. +% For example: + +The \module{spam} module defines operations for handling cans of Spam. +It knows the four generally available Spam varieties and understands +both can sizes. + +Because spamification requires \UNIX{} process management, the module +is only available on genuine \UNIX{} systems. + + +% ==== 3. ==== +% List the public functions defined by the module. Begin with a +% standard phrase. You may also list the exceptions and other data +% items defined in the module, insofar as they are important for the +% user. + +The \module{spam} module defines the following functions: + +% ---- 3.1. ---- +% For each function, use a ``funcdesc'' block. This has exactly two +% parameters (each parameters is contained in a set of curly braces): +% the first parameter is the function name (this automatically +% generates an index entry); the second parameter is the function's +% argument list. If there are no arguments, use an empty pair of +% curly braces. If there is more than one argument, separate the +% arguments with backslash-comma. Optional parts of the parameter +% list are contained in \optional{...} (this generates a set of square +% brackets around its parameter). Arguments are automatically set in +% italics in the parameter list. Each argument should be mentioned at +% least once in the description; each usage (even inside \code{...}) +% should be enclosed in \var{...}. + +\begin{funcdesc}{open}{filename\optional{, mode\optional{, buffersize}}} +Open the file \var{filename} as a can of Spam. The optional +\var{mode} and \var{buffersize} arguments specify the read/write mode +(\code{'r'} (default) or \code{'w'}) and the buffer size (default: +system dependent). +\end{funcdesc} + +% ---- 3.2. ---- +% Data items are described using a ``datadesc'' block. This has only +% one parameter: the item's name. + +\begin{datadesc}{cansize} +The default can size, in ounces. Legal values are 7 and 12. The +default varies per supermarket. This variable should not be changed +once the \function{open()} function has been called. +\end{datadesc} + +% --- 3.3. --- +% Exceptions are described using a ``excdesc'' block. This has only +% one parameter: the exception name. Exceptions defined as classes in +% the source code should be documented using this environment, but +% constructor parameters must be omitted. + +\begin{excdesc}{error} +Exception raised when an operation fails for a Spam specific reason. +The exception argument is a string describing the reason of the +failure. +\end{excdesc} + +% ---- 3.4. ---- +% Other standard environments: +% +% classdesc - Python classes; same arguments are funcdesc +% methoddesc - methods, like funcdesc but has an optional parameter +% to give the type name: \begin{methoddesc}[mytype]{name}{args} +% By default, the type name will be the name of the +% last class defined using classdesc. The type name +% is required if the type is implemented in C (because +% there's no classdesc) or if the class isn't directly +% documented (if it's private). +% memberdesc - data members, like datadesc, but with an optional +% type name like methoddesc. + + +% ==== 4. ==== +% Now is probably a good time for a complete example. (Alternatively, +% an example giving the flavor of the module may be given before the +% detailed list of functions.) + +\subsection{Example \label{spam-example}} + +The following example demonstrates how to open a can of spam using the +\module{spam} module. + +\begin{verbatim} +>>> import spam +>>> can = spam.open('/etc/passwd') +>>> can.empty() +>>> can.close() +\end{verbatim} +% Note that there is no trailing ">>> " prompt shown. + +% ==== 5. ==== +% If your module defines new object types (for a built-in module) or +% classes (for a module written in Python), you should list the +% methods and instance variables (if any) of each type or class in a +% separate subsection. + +\subsection{Spam Objects} +\label{spam-objects} +% This label is generally useful for referencing this section, but is +% also used to give a filename when generating HTML. + +Spam objects, as returned by \function{open()} above, have the +following methods: + +\begin{methoddesc}[spam]{empty}{} +Empty the can into the trash. +\end{methoddesc} diff --git a/sys/src/cmd/python/Doc/templates/whatsnewXY.tex b/sys/src/cmd/python/Doc/templates/whatsnewXY.tex new file mode 100644 index 000000000..9650bdd84 --- /dev/null +++ b/sys/src/cmd/python/Doc/templates/whatsnewXY.tex @@ -0,0 +1,149 @@ +\documentclass{howto} +\usepackage{distutils} +% $Id: whatsnewXY.tex 33728 2003-07-31 01:17:22Z montanaro $ + +% When creating a new ``What's New'' document, copy this to +% ../whatsnew/whatsnewXY.tex, where X is replaced by the major version +% number and Y, by the minor version number for the release of Python +% being described. +% +% The following replacements need to be made in the text: +% +% X.Y -- the version of Python this document describes +% X.Y-1 -- previous minor release (not a maintenance release) +% X.Y-2 -- minor release before that one (optional; search the +% template to see the usage +% +% Once done, write and edit to your heart's content! + +\title{What's New in Python X.Y} +\release{0.0} +\author{Young Author} +\authoraddress{\email{ya@example.com}} + +\begin{document} +\maketitle +\tableofcontents + +This article explains the new features in Python X.Y. No release date +for Python X.Y has been set; expect that this will happen next year. + +% Compare with previous release in 2 - 3 sentences here. + +This article doesn't attempt to provide a complete specification of +the new features, but instead provides a convenient overview. For +full details, you should refer to the documentation for Python X.Y. +% add hyperlink when the documentation becomes available online. +If you want to understand the complete implementation and design +rationale, refer to the PEP for a particular new feature. + + +%====================================================================== + +% Large, PEP-level features and changes should be described here. + + +%====================================================================== +\section{Other Language Changes} + +Here are all of the changes that Python X.Y makes to the core Python +language. + +\begin{itemize} +\item TBD + +\end{itemize} + + +%====================================================================== +\subsection{Optimizations} + +\begin{itemize} + +\item Optimizations should be described here. + +\end{itemize} + +The net result of the X.Y optimizations is that Python X.Y runs the +pystone benchmark around XX\% faster than Python X.Y-1.% +% only use the next line if you want to do the extra work ;) : +% and YY\% faster than Python X.Y-2. + + +%====================================================================== +\section{New, Improved, and Deprecated Modules} + +As usual, Python's standard library received a number of enhancements and +bug fixes. Here's a partial list of the most notable changes, sorted +alphabetically by module name. Consult the +\file{Misc/NEWS} file in the source tree for a more +complete list of changes, or look through the CVS logs for all the +details. + +\begin{itemize} + +\item Descriptions go here. + +\end{itemize} + + +%====================================================================== +% whole new modules get described in \subsections here + + +% ====================================================================== +\section{Build and C API Changes} + +Changes to Python's build process and to the C API include: + +\begin{itemize} + +\item Detailed changes are listed here. + +\end{itemize} + + +%====================================================================== +\subsection{Port-Specific Changes} + +Platform-specific changes go here. + + +%====================================================================== +\section{Other Changes and Fixes \label{section-other}} + +As usual, there were a bunch of other improvements and bugfixes +scattered throughout the source tree. A search through the CVS change +logs finds there were XXX patches applied and YYY bugs fixed between +Python X.Y-1 and X.Y. Both figures are likely to be underestimates. + +Some of the more notable changes are: + +\begin{itemize} + +\item Details go here. + +\end{itemize} + + +%====================================================================== +\section{Porting to Python X.Y} + +This section lists previously described changes that may require +changes to your code: + +\begin{itemize} + +\item Everything is all in the details! + +\end{itemize} + + +%====================================================================== +\section{Acknowledgements \label{acks}} + +The author would like to thank the following people for offering +suggestions, corrections and assistance with various drafts of this +article: . + +\end{document} diff --git a/sys/src/cmd/python/Doc/tests/math.tex b/sys/src/cmd/python/Doc/tests/math.tex new file mode 100644 index 000000000..11880e5a9 --- /dev/null +++ b/sys/src/cmd/python/Doc/tests/math.tex @@ -0,0 +1,16 @@ +\documentclass{howto} + +\title{Test of python.sty with math} + +\begin{document} + +\maketitle + +\section{Subscripts in Math Mode} + +This contains an inline formula containing a subscript: $H_20$. +This display doesn't make sense, but contains a subscript as well: + +$$\sum_1^2 = a_x$$ + +\end{document} diff --git a/sys/src/cmd/python/Doc/texinputs/distutils.sty b/sys/src/cmd/python/Doc/texinputs/distutils.sty new file mode 100644 index 000000000..bbed8415f --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/distutils.sty @@ -0,0 +1,33 @@ +% +% LaTeX commands and macros needed for the two Distutils manuals, +% inst.tex and dist.tex. +% +% $Id: distutils.sty 15178 2000-04-19 22:40:34Z gward $ +% + +% My gripe list about the Python style files: +% * I want italics in verbatim environments for variable +% text (verbatim.sty?) +% * I hate escaping underscores (url.sty fixes this) + +% '\command' is for Distutils commands which, depending on your +% perspective, are just arguments to the setup script, or sub- +% commands of the setup script, or the classes that implement +% each "command". +\newcommand{\command}[1]{\code{#1}} + +% '\option' is for Distutils options *in* the setup script. Command- +% line options *to* the setup script are marked up in the usual +% way, ie. with '\programopt' or '\longprogramopt' +\newcommand{\option}[1]{\textsf{\small{#1}}} + +% '\filevar' is for variable components of file/path names -- eg. +% when you put 'prefix' in a pathname, you mark it up with +% '\filevar' so that it still looks pathname-ish, but is +% distinguished from the literal part of the path. Fred says +% this can be accomplished just fine with '\var', but I violently +% disagree. Pistols at dawn will sort this one out. +\newcommand{\filevar}[1]{{\textsl{\filenq{#1}}}} + +% Just while the code and docs are still under development. +\newcommand{\XXX}[1]{\textbf{**#1**}} diff --git a/sys/src/cmd/python/Doc/texinputs/fancyhdr.sty b/sys/src/cmd/python/Doc/texinputs/fancyhdr.sty new file mode 100644 index 000000000..c1026e95c --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/fancyhdr.sty @@ -0,0 +1,329 @@ +% fancyhdr.sty version 1.99d +% Fancy headers and footers for LaTeX. +% Piet van Oostrum, Dept of Computer Science, University of Utrecht +% Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands +% Telephone: +31 30 2532180. Email: piet@cs.ruu.nl +% ======================================================================== +% LICENCE: This is free software. You are allowed to use and distribute +% this software in any way you like. You are also allowed to make modified +% versions of it, but you can distribute a modified version only if you +% clearly indicate that it is a modified version and the person(s) who +% modified it. This indication should be in a prominent place, e.g. in the +% top of the file. If possible a contact address, preferably by email, +% should be given for these persons. If that is feasible the modifications +% should be indicated in the source code. +% ======================================================================== +% MODIFICATION HISTORY: +% Sep 16, 1994 +% version 1.4: Correction for use with \reversemargin +% Sep 29, 1994: +% version 1.5: Added the \iftopfloat, \ifbotfloat and \iffloatpage commands +% Oct 4, 1994: +% version 1.6: Reset single spacing in headers/footers for use with +% setspace.sty or doublespace.sty +% Oct 4, 1994: +% version 1.7: changed \let\@mkboth\markboth to +% \def\@mkboth{\protect\markboth} to make it more robust +% Dec 5, 1994: +% version 1.8: corrections for amsbook/amsart: define \@chapapp and (more +% importantly) use the \chapter/sectionmark definitions from ps@headings if +% they exist (which should be true for all standard classes). +% May 31, 1995: +% version 1.9: The proposed \renewcommand{\headrulewidth}{\iffloatpage... +% construction in the doc did not work properly with the fancyplain style. +% June 1, 1995: +% version 1.91: The definition of \@mkboth wasn't restored on subsequent +% \pagestyle{fancy}'s. +% June 1, 1995: +% version 1.92: The sequence \pagestyle{fancyplain} \pagestyle{plain} +% \pagestyle{fancy} would erroneously select the plain version. +% June 1, 1995: +% version 1.93: \fancypagestyle command added. +% Dec 11, 1995: +% version 1.94: suggested by Conrad Hughes <chughes@maths.tcd.ie> +% CJCH, Dec 11, 1995: added \footruleskip to allow control over footrule +% position (old hardcoded value of .3\normalbaselineskip is far too high +% when used with very small footer fonts). +% Jan 31, 1996: +% version 1.95: call \@normalsize in the reset code if that is defined, +% otherwise \normalsize. +% this is to solve a problem with ucthesis.cls, as this doesn't +% define \@currsize. Unfortunately for latex209 calling \normalsize doesn't +% work as this is optimized to do very little, so there \@normalsize should +% be called. Hopefully this code works for all versions of LaTeX known to +% mankind. +% April 25, 1996: +% version 1.96: initialize \headwidth to a magic (negative) value to catch +% most common cases that people change it before calling \pagestyle{fancy}. +% Note it can't be initialized when reading in this file, because +% \textwidth could be changed afterwards. This is quite probable. +% We also switch to \MakeUppercase rather than \uppercase and introduce a +% \nouppercase command for use in headers. and footers. +% May 3, 1996: +% version 1.97: Two changes: +% 1. Undo the change in version 1.8 (using the pagestyle{headings} defaults +% for the chapter and section marks. The current version of amsbook and +% amsart classes don't seem to need them anymore. Moreover the standard +% latex classes don't use \markboth if twoside isn't selected, and this is +% confusing as \leftmark doesn't work as expected. +% 2. include a call to \ps@empty in ps@@fancy. This is to solve a problem +% in the amsbook and amsart classes, that make global changes to \topskip, +% which are reset in \ps@empty. Hopefully this doesn't break other things. +% May 7, 1996: +% version 1.98: +% Added % after the line \def\nouppercase +% May 7, 1996: +% version 1.99: This is the alpha version of fancyhdr 2.0 +% Introduced the new commands \fancyhead, \fancyfoot, and \fancyhf. +% Changed \headrulewidth, \footrulewidth, \footruleskip to +% macros rather than length parameters, In this way they can be +% conditionalized and they don't consume length registers. There is no need +% to have them as length registers unless you want to do calculations with +% them, which is unlikely. Note that this may make some uses of them +% incompatible (i.e. if you have a file that uses \setlength or \xxxx=) +% May 10, 1996: +% version 1.99a: +% Added a few more % signs +% May 10, 1996: +% version 1.99b: +% Changed the syntax of \f@nfor to be resistent to catcode changes of := +% Removed the [1] from the defs of \lhead etc. because the parameter is +% consumed by the \@[xy]lhead etc. macros. +% June 24, 1997: +% version 1.99c: +% corrected \nouppercase to also include the protected form of \MakeUppercase +% \global added to manipulation of \headwidth. +% \iffootnote command added. +% Some comments added about \@fancyhead and \@fancyfoot. +% Aug 24, 1998 +% version 1.99d +% Changed the default \ps@empty to \ps@@empty in order to allow +% \fancypagestyle{empty} redefinition. + +\let\fancy@def\gdef + +\def\if@mpty#1#2#3{\def\temp@ty{#1}\ifx\@empty\temp@ty #2\else#3\fi} + +% Usage: \@forc \var{charstring}{command to be executed for each char} +% This is similar to LaTeX's \@tfor, but expands the charstring. + +\def\@forc#1#2#3{\expandafter\f@rc\expandafter#1\expandafter{#2}{#3}} +\def\f@rc#1#2#3{\def\temp@ty{#2}\ifx\@empty\temp@ty\else + \f@@rc#1#2\f@@rc{#3}\fi} +\def\f@@rc#1#2#3\f@@rc#4{\def#1{#2}#4\f@rc#1{#3}{#4}} + +% Usage: \f@nfor\name:=list\do{body} +% Like LaTeX's \@for but an empty list is treated as a list with an empty +% element + +\newcommand{\f@nfor}[3]{\edef\@fortmp{#2}% + \expandafter\@forloop#2,\@nil,\@nil\@@#1{#3}} + +% Usage: \def@ult \cs{defaults}{argument} +% sets \cs to the characters from defaults appearing in argument +% or defaults if it would be empty. All characters are lowercased. + +\newcommand\def@ult[3]{% + \edef\temp@a{\lowercase{\edef\noexpand\temp@a{#3}}}\temp@a + \def#1{}% + \@forc\tmpf@ra{#2}% + {\expandafter\if@in\tmpf@ra\temp@a{\edef#1{#1\tmpf@ra}}{}}% + \ifx\@empty#1\def#1{#2}\fi} +% +% \if@in <char><set><truecase><falsecase> +% +\newcommand{\if@in}[4]{% + \edef\temp@a{#2}\def\temp@b##1#1##2\temp@b{\def\temp@b{##1}}% + \expandafter\temp@b#2#1\temp@b\ifx\temp@a\temp@b #4\else #3\fi} + +\newcommand{\fancyhead}{\@ifnextchar[{\f@ncyhf h}{\f@ncyhf h[]}} +\newcommand{\fancyfoot}{\@ifnextchar[{\f@ncyhf f}{\f@ncyhf f[]}} +\newcommand{\fancyhf}{\@ifnextchar[{\f@ncyhf {}}{\f@ncyhf {}[]}} + +% The header and footer fields are stored in command sequences with +% names of the form: \f@ncy<x><y><z> with <x> for [eo], <y> form [lcr] +% and <z> from [hf]. + +\def\f@ncyhf#1[#2]#3{% + \def\temp@c{}% + \@forc\tmpf@ra{#2}% + {\expandafter\if@in\tmpf@ra{eolcrhf,EOLCRHF}% + {}{\edef\temp@c{\temp@c\tmpf@ra}}}% + \ifx\@empty\temp@c\else + \ifx\PackageError\undefined + \errmessage{Illegal char `\temp@c' in fancyhdr argument: + [#2]}\else + \PackageError{Fancyhdr}{Illegal char `\temp@c' in fancyhdr argument: + [#2]}{}\fi + \fi + \f@nfor\temp@c{#2}% + {\def@ult\f@@@eo{eo}\temp@c + \def@ult\f@@@lcr{lcr}\temp@c + \def@ult\f@@@hf{hf}{#1\temp@c}% + \@forc\f@@eo\f@@@eo + {\@forc\f@@lcr\f@@@lcr + {\@forc\f@@hf\f@@@hf + {\expandafter\fancy@def\csname + f@ncy\f@@eo\f@@lcr\f@@hf\endcsname + {#3}}}}}} + +% Fancyheadings version 1 commands. These are more or less deprecated, +% but they continue to work. + +\newcommand{\lhead}{\@ifnextchar[{\@xlhead}{\@ylhead}} +\def\@xlhead[#1]#2{\fancy@def\f@ncyelh{#1}\fancy@def\f@ncyolh{#2}} +\def\@ylhead#1{\fancy@def\f@ncyelh{#1}\fancy@def\f@ncyolh{#1}} + +\newcommand{\chead}{\@ifnextchar[{\@xchead}{\@ychead}} +\def\@xchead[#1]#2{\fancy@def\f@ncyech{#1}\fancy@def\f@ncyoch{#2}} +\def\@ychead#1{\fancy@def\f@ncyech{#1}\fancy@def\f@ncyoch{#1}} + +\newcommand{\rhead}{\@ifnextchar[{\@xrhead}{\@yrhead}} +\def\@xrhead[#1]#2{\fancy@def\f@ncyerh{#1}\fancy@def\f@ncyorh{#2}} +\def\@yrhead#1{\fancy@def\f@ncyerh{#1}\fancy@def\f@ncyorh{#1}} + +\newcommand{\lfoot}{\@ifnextchar[{\@xlfoot}{\@ylfoot}} +\def\@xlfoot[#1]#2{\fancy@def\f@ncyelf{#1}\fancy@def\f@ncyolf{#2}} +\def\@ylfoot#1{\fancy@def\f@ncyelf{#1}\fancy@def\f@ncyolf{#1}} + +\newcommand{\cfoot}{\@ifnextchar[{\@xcfoot}{\@ycfoot}} +\def\@xcfoot[#1]#2{\fancy@def\f@ncyecf{#1}\fancy@def\f@ncyocf{#2}} +\def\@ycfoot#1{\fancy@def\f@ncyecf{#1}\fancy@def\f@ncyocf{#1}} + +\newcommand{\rfoot}{\@ifnextchar[{\@xrfoot}{\@yrfoot}} +\def\@xrfoot[#1]#2{\fancy@def\f@ncyerf{#1}\fancy@def\f@ncyorf{#2}} +\def\@yrfoot#1{\fancy@def\f@ncyerf{#1}\fancy@def\f@ncyorf{#1}} + +\newdimen\headwidth +\newcommand{\headrulewidth}{0.4pt} +\newcommand{\footrulewidth}{\z@skip} +\newcommand{\footruleskip}{.3\normalbaselineskip} + +% Fancyplain stuff shouldn't be used anymore (rather +% \fancypagestyle{plain} should be used), but it must be present for +% compatibility reasons. + +\newcommand{\plainheadrulewidth}{\z@skip} +\newcommand{\plainfootrulewidth}{\z@skip} +\newif\if@fancyplain \@fancyplainfalse +\def\fancyplain#1#2{\if@fancyplain#1\else#2\fi} + +\headwidth=-123456789sp %magic constant + +% Command to reset various things in the headers: +% a.o. single spacing (taken from setspace.sty) +% and the catcode of ^^M (so that epsf files in the header work if a +% verbatim crosses a page boundary) +% It also defines a \nouppercase command that disables \uppercase and +% \Makeuppercase. It can only be used in the headers and footers. +\def\fancy@reset{\restorecr + \def\baselinestretch{1}% + \def\nouppercase##1{{\let\uppercase\relax\let\MakeUppercase\relax + \expandafter\let\csname MakeUppercase \endcsname\relax##1}}% + \ifx\undefined\@newbaseline% NFSS not present; 2.09 or 2e + \ifx\@normalsize\undefined \normalsize % for ucthesis.cls + \else \@normalsize \fi + \else% NFSS (2.09) present + \@newbaseline% + \fi} + +% Initialization of the head and foot text. + +% The default values still contain \fancyplain for compatibility. +\fancyhf{} % clear all +% lefthead empty on ``plain'' pages, \rightmark on even, \leftmark on odd pages +% evenhead empty on ``plain'' pages, \leftmark on even, \rightmark on odd pages +\fancyhead[el,or]{\fancyplain{}{\sl\rightmark}} +\fancyhead[er,ol]{\fancyplain{}{\sl\leftmark}} +\fancyfoot[c]{\rm\thepage} % page number + +% Put together a header or footer given the left, center and +% right text, fillers at left and right and a rule. +% The \lap commands put the text into an hbox of zero size, +% so overlapping text does not generate an errormessage. +% These macros have 5 parameters: +% 1. \@lodd or \@rodd % This determines at which side the header will stick +% out. +% 2. \f@ncyolh, \f@ncyelh, \f@ncyolf or \f@ncyelf. This is the left component. +% 3. \f@ncyoch, \f@ncyech, \f@ncyocf or \f@ncyecf. This is the middle comp. +% 4. \f@ncyorh, \f@ncyerh, \f@ncyorf or \f@ncyerf. This is the right component. +% 5. \@lodd or \@rodd % This determines at which side the header will stick +% out. This is the reverse of parameter nr. 1. One of them is always +% \relax and the other one is \hss (after expansion). + +\def\@fancyhead#1#2#3#4#5{#1\hbox to\headwidth{\fancy@reset\vbox{\hbox +{\rlap{\parbox[b]{\headwidth}{\raggedright#2\strut}}\hfill +\parbox[b]{\headwidth}{\centering#3\strut}\hfill +\llap{\parbox[b]{\headwidth}{\raggedleft#4\strut}}}\headrule}}#5} + +\def\@fancyfoot#1#2#3#4#5{#1\hbox to\headwidth{\fancy@reset\vbox{\footrule +\hbox{\rlap{\parbox[t]{\headwidth}{\raggedright#2\strut}}\hfill +\parbox[t]{\headwidth}{\centering#3\strut}\hfill +\llap{\parbox[t]{\headwidth}{\raggedleft#4\strut}}}}}#5} + +\def\headrule{{\if@fancyplain\let\headrulewidth\plainheadrulewidth\fi +\hrule\@height\headrulewidth\@width\headwidth \vskip-\headrulewidth}} + +\def\footrule{{\if@fancyplain\let\footrulewidth\plainfootrulewidth\fi +\vskip-\footruleskip\vskip-\footrulewidth +\hrule\@width\headwidth\@height\footrulewidth\vskip\footruleskip}} + +\def\ps@fancy{% +\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{}%for amsbook +% +% Define \MakeUppercase for old LaTeXen. +% Note: we used \def rather than \let, so that \let\uppercase\relax (from +% the version 1 documentation) will still work. +% +\@ifundefined{MakeUppercase}{\def\MakeUppercase{\uppercase}}{}% +\@ifundefined{chapter}{\def\sectionmark##1{\markboth +{\MakeUppercase{\ifnum \c@secnumdepth>\z@ + \thesection\hskip 1em\relax \fi ##1}}{}}% +\def\subsectionmark##1{\markright {\ifnum \c@secnumdepth >\@ne + \thesubsection\hskip 1em\relax \fi ##1}}}% +{\def\chaptermark##1{\markboth {\MakeUppercase{\ifnum \c@secnumdepth>\m@ne + \@chapapp\ \thechapter. \ \fi ##1}}{}}% +\def\sectionmark##1{\markright{\MakeUppercase{\ifnum \c@secnumdepth >\z@ + \thesection. \ \fi ##1}}}}% +%\csname ps@headings\endcsname % use \ps@headings defaults if they exist +\ps@@fancy +\gdef\ps@fancy{\@fancyplainfalse\ps@@fancy}% +% Initialize \headwidth if the user didn't +% +\ifdim\headwidth<0sp +% +% This catches the case that \headwidth hasn't been initialized and the +% case that the user added something to \headwidth in the expectation that +% it was initialized to \textwidth. We compensate this now. This loses if +% the user intended to multiply it by a factor. But that case is more +% likely done by saying something like \headwidth=1.2\textwidth. +% The doc says you have to change \headwidth after the first call to +% \pagestyle{fancy}. This code is just to catch the most common cases were +% that requirement is violated. +% + \global\advance\headwidth123456789sp\global\advance\headwidth\textwidth +\fi} +\def\ps@fancyplain{\ps@fancy \let\ps@plain\ps@plain@fancy} +\def\ps@plain@fancy{\@fancyplaintrue\ps@@fancy} +\let\ps@@empty\ps@empty +\def\ps@@fancy{% +\ps@@empty % This is for amsbook/amsart, which do strange things with \topskip +\def\@mkboth{\protect\markboth}% +\def\@oddhead{\@fancyhead\@lodd\f@ncyolh\f@ncyoch\f@ncyorh\@rodd}% +\def\@oddfoot{\@fancyfoot\@lodd\f@ncyolf\f@ncyocf\f@ncyorf\@rodd}% +\def\@evenhead{\@fancyhead\@rodd\f@ncyelh\f@ncyech\f@ncyerh\@lodd}% +\def\@evenfoot{\@fancyfoot\@rodd\f@ncyelf\f@ncyecf\f@ncyerf\@lodd}% +} +\def\@lodd{\if@reversemargin\hss\else\relax\fi} +\def\@rodd{\if@reversemargin\relax\else\hss\fi} + +\newif\iffootnote +\let\latex@makecol\@makecol +\def\@makecol{\ifvoid\footins\footnotetrue\else\footnotefalse\fi +\let\topfloat\@toplist\let\botfloat\@botlist\latex@makecol} +\def\iftopfloat#1#2{\ifx\topfloat\empty #2\else #1\fi} +\def\ifbotfloat#1#2{\ifx\botfloat\empty #2\else #1\fi} +\def\iffloatpage#1#2{\if@fcolmade #1\else #2\fi} + +\newcommand{\fancypagestyle}[2]{% + \@namedef{ps@#1}{\let\fancy@def\def#2\relax\ps@fancy}} diff --git a/sys/src/cmd/python/Doc/texinputs/fncychap.sty b/sys/src/cmd/python/Doc/texinputs/fncychap.sty new file mode 100644 index 000000000..b0d7b76b7 --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/fncychap.sty @@ -0,0 +1,433 @@ +%%% Derived from the original fncychap.sty, +%%% but changed ``TWELV'' to ``TWELVE''. + +%%% Copyright Ulf A. Lindgren +%%% Department of Applied Electronics +%%% Chalmers University of Technology +%%% S-412 96 Gothenburg, Sweden +%%% E-mail lindgren@ae.chalmers.se +%%% +%%% Note Permission is granted to modify this file under +%%% the condition that it is saved using another +%%% file and package name. +%%% +%%% Revision 1.1 +%%% +%%% Jan. 8th Modified package name base date option +%%% Jan. 22th Modified FmN and FmTi for error in book.cls +%%% \MakeUppercase{#}->{\MakeUppercase#} +%%% Apr. 6th Modified Lenny option to prevent undesired +%%% skip of line. +%%% Nov. 8th Fixed \@chapapp for AMS +%%% Feb. 11th Fixed appendix problem related to Bjarne +%%% Last modified Feb. 11th 1998 + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{fncychap} + [1997/04/06 v1.11 + LaTeX package (Revised chapters)] + +%%%% DEFINITION OF Chapapp variables +\newcommand{\CNV}{\huge\bfseries} +\newcommand{\ChNameVar}[1]{\renewcommand{\CNV}{#1}} + + +%%%% DEFINITION OF TheChapter variables +\newcommand{\CNoV}{\huge\bfseries} +\newcommand{\ChNumVar}[1]{\renewcommand{\CNoV}{#1}} + +\newif\ifUCN +\UCNfalse +\newif\ifLCN +\LCNfalse +\def\ChNameLowerCase{\LCNtrue\UCNfalse} +\def\ChNameUpperCase{\UCNtrue\LCNfalse} +\def\ChNameAsIs{\UCNfalse\LCNfalse} + +%%%%% Fix for AMSBook 971008 + +\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{} + + +%%%%% Fix for Bjarne and appendix 980211 + +\newif\ifinapp +\inappfalse +\renewcommand\appendix{\par + \setcounter{chapter}{0}% + \setcounter{section}{0}% + \inapptrue% + \renewcommand\@chapapp{\appendixname}% + \renewcommand\thechapter{\@Alph\c@chapter}} + +%%%%% + +\newcommand{\FmN}[1]{% +\ifUCN + {\MakeUppercase#1}\LCNfalse +\else + \ifLCN + {\MakeLowercase#1}\UCNfalse + \else #1 + \fi +\fi} + + +%%%% DEFINITION OF Title variables +\newcommand{\CTV}{\Huge\bfseries} +\newcommand{\ChTitleVar}[1]{\renewcommand{\CTV}{#1}} + +%%%% DEFINITION OF the basic rule width +\newlength{\RW} +\setlength{\RW}{1pt} +\newcommand{\ChRuleWidth}[1]{\setlength{\RW}{#1}} + +\newif\ifUCT +\UCTfalse +\newif\ifLCT +\LCTfalse +\def\ChTitleLowerCase{\LCTtrue\UCTfalse} +\def\ChTitleUpperCase{\UCTtrue\LCTfalse} +\def\ChTitleAsIs{\UCTfalse\LCTfalse} +\newcommand{\FmTi}[1]{% +\ifUCT + + {\MakeUppercase#1}\LCTfalse +\else + \ifLCT + {\MakeLowercase#1}\UCTfalse + \else #1 + \fi +\fi} + + + +\newlength{\mylen} +\newlength{\myhi} +\newlength{\px} +\newlength{\py} +\newlength{\pyy} +\newlength{\pxx} + + +\def\mghrulefill#1{\leavevmode\leaders\hrule\@height #1\hfill\kern\z@} + +\newcommand{\DOCH}{% + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip 20\p@ + } +\newcommand{\DOTI}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } +\newcommand{\DOTIS}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } + +%%%%%% SONNY DEF + +\DeclareOption{Sonny}{% + \ChNameVar{\Large\sf} + \ChNumVar{\Huge} + \ChTitleVar{\Large\sf} + \ChRuleWidth{0.5pt} + \ChNameUpperCase + \renewcommand{\DOCH}{% + \raggedleft + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip 40\p@} + \renewcommand{\DOTI}[1]{% + \CTV\raggedleft\mghrulefill{\RW}\par\nobreak + \vskip 5\p@ + \CTV\FmTi{#1}\par\nobreak + \mghrulefill{\RW}\par\nobreak + \vskip 40\p@} + \renewcommand{\DOTIS}[1]{% + \CTV\raggedleft\mghrulefill{\RW}\par\nobreak + \vskip 5\p@ + \CTV\FmTi{#1}\par\nobreak + \mghrulefill{\RW}\par\nobreak + \vskip 40\p@} +} + +%%%%%% LENNY DEF + +\DeclareOption{Lenny}{% + + \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont} + \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont} + \ChTitleVar{\Huge\bfseries\rm} + \ChRuleWidth{1pt} + \renewcommand{\DOCH}{% + \settowidth{\px}{\CNV\FmN{\@chapapp}} + \addtolength{\px}{2pt} + \settoheight{\py}{\CNV\FmN{\@chapapp}} + \addtolength{\py}{1pt} + + \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter} + \addtolength{\mylen}{1pt} + \settowidth{\pxx}{\CNoV\thechapter} + \addtolength{\pxx}{-1pt} + + \settoheight{\pyy}{\CNoV\thechapter} + \addtolength{\pyy}{-2pt} + \setlength{\myhi}{\pyy} + \addtolength{\myhi}{-1\py} + \par + \parbox[b]{\textwidth}{% + \rule[\py]{\RW}{\myhi}% + \hskip -\RW% + \rule[\pyy]{\px}{\RW}% + \hskip -\px% + \raggedright% + \CNV\FmN{\@chapapp}\space\CNoV\thechapter% + \hskip1pt% + \mghrulefill{\RW}% + \rule{\RW}{\pyy}\par\nobreak% + \vskip -\baselineskip% + \vskip -\pyy% + \hskip \mylen% + \mghrulefill{\RW}\par\nobreak% + \vskip \pyy}% + \vskip 20\p@} + + + \renewcommand{\DOTI}[1]{% + \raggedright + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@} + + \renewcommand{\DOTIS}[1]{% + \raggedright + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@} + } + + +%%%%%%% GLENN DEF + + +\DeclareOption{Glenn}{% + \ChNameVar{\bfseries\Large\sf} + \ChNumVar{\Huge} + \ChTitleVar{\bfseries\Large\rm} + \ChRuleWidth{1pt} + \ChNameUpperCase + \ChTitleUpperCase + \renewcommand{\DOCH}{% + \settoheight{\myhi}{\CTV\FmTi{Test}} + \setlength{\py}{\baselineskip} + \addtolength{\py}{\RW} + \addtolength{\py}{\myhi} + \setlength{\pyy}{\py} + \addtolength{\pyy}{-1\RW} + + \raggedright + \CNV\FmN{\@chapapp}\space\CNoV\thechapter + \hskip 3pt\mghrulefill{\RW}\rule[-1\pyy]{2\RW}{\py}\par\nobreak} + + \renewcommand{\DOTI}[1]{% + \addtolength{\pyy}{-4pt} + \settoheight{\myhi}{\CTV\FmTi{#1}} + \addtolength{\myhi}{\py} + \addtolength{\myhi}{-1\RW} + \vskip -1\pyy + \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt + \raggedleft\CTV\FmTi{#1}\par\nobreak + \vskip 80\p@} + + \renewcommand{\DOTIS}[1]{% + \setlength{\py}{10pt} + \setlength{\pyy}{\py} + \addtolength{\pyy}{\RW} + \setlength{\myhi}{\baselineskip} + \addtolength{\myhi}{\pyy} + \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak +% \addtolength{}{} +\vskip -1\baselineskip + \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt + \raggedleft\CTV\FmTi{#1}\par\nobreak + \vskip 60\p@} + } + +%%%%%%% CONNY DEF + +\DeclareOption{Conny}{% + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\centering\Huge\rm\bfseries} + \ChNumVar{\Huge} + \ChTitleVar{\centering\Huge\rm} + \ChRuleWidth{2pt} + + \renewcommand{\DOCH}{% + \mghrulefill{3\RW}\par\nobreak + \vskip -0.5\baselineskip + \mghrulefill{\RW}\par\nobreak + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip -0.5\baselineskip + } + \renewcommand{\DOTI}[1]{% + \mghrulefill{\RW}\par\nobreak + \CTV\FmTi{#1}\par\nobreak + \vskip 60\p@ + } + \renewcommand{\DOTIS}[1]{% + \mghrulefill{\RW}\par\nobreak + \CTV\FmTi{#1}\par\nobreak + \vskip 60\p@ + } + } + +%%%%%%% REJNE DEF + +\DeclareOption{Rejne}{% + + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\centering\Large\rm} + \ChNumVar{\Huge} + \ChTitleVar{\centering\Huge\rm} + \ChRuleWidth{1pt} + \renewcommand{\DOCH}{% + \settoheight{\py}{\CNoV\thechapter} + \addtolength{\py}{-1pt} + \CNV\FmN{\@chapapp}\par\nobreak + \vskip 20\p@ + \setlength{\myhi}{2\baselineskip} + \setlength{\px}{\myhi} + \addtolength{\px}{-1\RW} + \rule[-1\px]{\RW}{\myhi}\mghrulefill{\RW}\hskip + 10pt\raisebox{-0.5\py}{\CNoV\thechapter}\hskip +10pt\mghrulefill{\RW}\rule[-1\px]{\RW}{\myhi}\par\nobreak + \vskip -1\p@ + } + \renewcommand{\DOTI}[1]{% + \setlength{\mylen}{\textwidth} + \addtolength{\mylen}{-2\RW} + {\vrule width\RW}\parbox{\mylen}{\CTV\FmTi{#1}}{\vrule +width\RW}\par\nobreak + \vskip +-1pt\rule{\RW}{2\baselineskip}\mghrulefill{\RW}\rule{\RW}{2\baselineskip} + \vskip 60\p@ + } + \renewcommand{\DOTIS}[1]{% + \setlength{\py}{\fboxrule} + \setlength{\fboxrule}{\RW} + \setlength{\mylen}{\textwidth} + \addtolength{\mylen}{-2\RW} + \fbox{\parbox{\mylen}{\vskip +2\baselineskip\CTV\FmTi{#1}\par\nobreak\vskip \baselineskip}} + \setlength{\fboxrule}{\py} + \vskip 60\p@ + } + } + + +%%%%%%% BJARNE DEF + +\DeclareOption{Bjarne}{% + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\raggedleft\normalsize\rm} + \ChNumVar{\raggedleft \bfseries\Large} + \ChTitleVar{\raggedleft \Large\rm} + \ChRuleWidth{1pt} + + +%% Note thechapter -> c@chapter fix appendix bug + + \newcounter{AlphaCnt} + \newcounter{AlphaDecCnt} + \newcommand{\AlphaNo}{% + \ifcase\number\theAlphaCnt + \ifnum\c@chapter=0 + ZERO\else{}\fi + \or ONE\or TWO\or THREE\or FOUR\or FIVE + \or SIX\or SEVEN\or EIGHT\or NINE\or TEN + \or ELEVEN\or TWELVE\or THIRTEEN\or FOURTEEN\or FIFTEEN + \or SIXTEEN\or SEVENTEEN\or EIGHTEEN\or NINETEEN\fi +} + + \newcommand{\AlphaDecNo}{% + \setcounter{AlphaDecCnt}{0} + \@whilenum\number\theAlphaCnt>0\do + {\addtocounter{AlphaCnt}{-10} + \addtocounter{AlphaDecCnt}{1}} + \ifnum\number\theAlphaCnt=0 + \else + \addtocounter{AlphaDecCnt}{-1} + \addtocounter{AlphaCnt}{10} + \fi + + + \ifcase\number\theAlphaDecCnt\or TEN\or TWENTY\or THIRTY\or + FORTY\or FIFTY\or SIXTY\or SEVENTY\or EIGHTY\or NINETY\fi + } + \newcommand{\TheAlphaChapter}{% + + \ifinapp + \thechapter + \else + \setcounter{AlphaCnt}{\c@chapter} + \ifnum\c@chapter<20 + \AlphaNo + \else + \AlphaDecNo\AlphaNo + \fi + \fi + } + \renewcommand{\DOCH}{% + \mghrulefill{\RW}\par\nobreak + \CNV\FmN{\@chapapp}\par\nobreak + \CNoV\TheAlphaChapter\par\nobreak + \vskip -1\baselineskip\vskip 5pt\mghrulefill{\RW}\par\nobreak + \vskip 20\p@ + } + \renewcommand{\DOTI}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } + \renewcommand{\DOTIS}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } +} + +\DeclareOption*{% + \PackageWarning{fancychapter}{unknown style option} + } + +\ProcessOptions* \relax + +\def\@makechapterhead#1{% + \vspace*{50\p@}% + {\parindent \z@ \raggedright \normalfont + \ifnum \c@secnumdepth >\m@ne + \DOCH + \fi + \interlinepenalty\@M + \DOTI{#1} + }} +\def\@schapter#1{\if@twocolumn + \@topnewpage[\@makeschapterhead{#1}]% + \else + \@makeschapterhead{#1}% + \@afterheading + \fi} +\def\@makeschapterhead#1{% + \vspace*{50\p@}% + {\parindent \z@ \raggedright + \normalfont + \interlinepenalty\@M + \DOTIS{#1} + \vskip 40\p@ + }} + +\endinput + + diff --git a/sys/src/cmd/python/Doc/texinputs/howto.cls b/sys/src/cmd/python/Doc/texinputs/howto.cls new file mode 100644 index 000000000..c9beb4a5c --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/howto.cls @@ -0,0 +1,109 @@ +% +% howto.cls for the Python documentation +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{howto} + [1998/02/25 Document class (Python HOWTO)] + +\RequirePackage{pypaper} +\RequirePackage{fancybox} + +% Change the options here to get a different set of basic options, This +% is where to add things like "a4paper" or "10pt". +% +\LoadClass[\py@paper,\py@ptsize,twoside]{article} + +\setcounter{secnumdepth}{1} + +% Optional packages: +% +% If processing of these documents fails at your TeX installation, +% these may be commented out (independently) to make things work. +% These are both supplied with the current version of the teTeX +% distribution. +% +% The "fancyhdr" package makes nicer page footers reasonable to +% implement, and is used to put the chapter and section information in +% the footers. +% +\RequirePackage{fancyhdr}\typeout{Using fancier footers than usual.} + + +% Required package: +% +% This gives us all the Python-specific markup that we really want. +% This should come last. Do not change this. +% +\RequirePackage{python} + +% support for module synopsis sections: +\newcommand{\py@ModSynopsisFilename}{\jobname.syn} + + +% need to do one of these.... +\newcommand{\py@doHorizontalRule}{\rule{\textwidth}{1pt}} + + +% Change the title page to look a bit better, and fit in with the +% fncychap ``Bjarne'' style a bit better. +% +\renewcommand{\maketitle}{ + \py@doHorizontalRule + \ifpdf + \begingroup + % This \def is required to deal with multi-line authors; it + % changes \\ to ', ' (comma-space), making it pass muster for + % generating document info in the PDF file. + \def\\{, } + \pdfinfo{ + /Author (\@author) + /Title (\@title) + } + \endgroup + \fi + \begin{flushright} + {\rm\Huge\py@HeaderFamily \@title} \par + {\em\large\py@HeaderFamily \py@release\releaseinfo} \par + \vspace{25pt} + {\Large\py@HeaderFamily \@author} \par + \vspace{25pt} + \@date \par + \py@authoraddress \par + \end{flushright} + \@thanks + \setcounter{footnote}{0} + \let\thanks\relax\let\maketitle\relax + \gdef\@thanks{}\gdef\@author{}\gdef\@title{} +} + + +\let\py@OldTableofcontents=\tableofcontents +\renewcommand{\tableofcontents}{ + \begingroup + \parskip = 0mm + \py@OldTableofcontents + \endgroup + \py@doHorizontalRule + \vspace{12pt} + \py@doing@page@targetstrue +} + +% Fix the theindex environment to add an entry to the Table of +% Contents; this is much nicer than just having to jump to the end of +% the book and flip around, especially with multiple indexes. +% +\let\py@OldTheindex=\theindex +\renewcommand{\theindex}{ + \clearpage + \py@OldTheindex + \addcontentsline{toc}{section}{\indexname} +} + +\@ifundefined{fancyhf}{ + \pagestyle{plain}}{ + \pagestyle{normal}} % start this way; change for +\pagenumbering{arabic} % ToC & chapters +\setcounter{secnumdepth}{2} + +\thispagestyle{empty} diff --git a/sys/src/cmd/python/Doc/texinputs/ltxmarkup.sty b/sys/src/cmd/python/Doc/texinputs/ltxmarkup.sty new file mode 100644 index 000000000..ace08cc83 --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/ltxmarkup.sty @@ -0,0 +1,40 @@ +% Created by Fred L. Drake, Jr. <fdrake@acm.org>, as part of the +% Python Documentation Project. +% +% Define some simple markup for the LaTeX command documentation: + +\ProvidesPackage{ltxmarkup} +\RequirePackage{python} % fulllineitems environment + +% These two macros are used in constructing the last parameter to the +% envdesc and macrodesc environments. + +\newcommand{\py@ltx@optparam}[1]{{[}\var{#1}{]}} +\newcommand{\py@ltx@param}[1]{\{\var{#1}\}} + +\newenvironment{envdesc}[2]{ + \begin{fulllineitems} + \item[\code{\e begin\{{\bfseries #1}\}{% + \let\op=\py@ltx@optparam% + \let\p=\py@ltx@param% + \let\unspecified=\py@unspecified% + \let\moreargs=\py@moreargs% + #2}}] + \item[\code{\e end\{{\bfseries #1}\}}] + \index{#1 environment@\py@idxcode{#1} environment} + \index{environments!#1@\py@idxcode{#1}} +}{\end{fulllineitems}} + +\newenvironment{macrodesc}[2]{ + \begin{fulllineitems} + \item[\code{{\e\bfseries#1}{% + \let\op=\py@ltx@optparam% + \let\p=\py@ltx@param% + \let\unspecified=\py@unspecified% + \let\moreargs=\py@moreargs% + #2}}] + \index{#1@\py@idxcode{#1}} +}{\end{fulllineitems}} + +\newcommand{\env}[1]{\code{#1}} +\newcommand{\macro}[1]{\code{\e#1}} diff --git a/sys/src/cmd/python/Doc/texinputs/manual.cls b/sys/src/cmd/python/Doc/texinputs/manual.cls new file mode 100644 index 000000000..ddaa404f1 --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/manual.cls @@ -0,0 +1,155 @@ +% +% manual.cls for the Python documentation +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{manual} + [1998/03/03 Document class (Python manual)] + +\RequirePackage{pypaper} +\RequirePackage{fancybox} + +% Change the options here to get a different set of basic options, but only +% if you have to. Paper and font size should be adjusted in pypaper.sty. +% +\LoadClass[\py@paper,\py@ptsize,twoside,openright]{report} + +\setcounter{secnumdepth}{2} + +% Optional packages: +% +% If processing of these documents fails at your TeX installation, +% these may be commented out (independently) to make things work. +% These are both supplied with the current version of the teTeX +% distribution. +% +% The "fancyhdr" package makes nicer page footers reasonable to +% implement, and is used to put the chapter and section information in +% the footers. +% +\RequirePackage{fancyhdr}\typeout{Using fancier footers than usual.} + + +% Required packages: +% +% The "fncychap" package is used to get the nice chapter headers. The +% .sty file is distributed with Python, so you should not need to disable +% it. You'd also end up with a mixed page style; uglier than stock LaTeX! +% +\RequirePackage[Bjarne]{fncychap}\typeout{Using fancy chapter headings.} +% Do horizontal rules it this way to match: +\newcommand{\py@doHorizontalRule}{\mghrulefill{\RW}} +% +% +% This gives us all the Python-specific markup that we really want. +% This should come last. Do not change this. +% +\RequirePackage{python} + +% support for module synopsis sections: +\newcommand{\py@ModSynopsisFilename}{\jobname\thechapter.syn} +\let\py@OldChapter=\chapter +\renewcommand{\chapter}{ + \py@ProcessModSynopsis + \py@closeModSynopsisFile + \py@OldChapter +} + + +% Change the title page to look a bit better, and fit in with the +% fncychap ``Bjarne'' style a bit better. +% +\renewcommand{\maketitle}{% + \begin{titlepage}% + \let\footnotesize\small + \let\footnoterule\relax + \py@doHorizontalRule% + \ifpdf + \begingroup + % This \def is required to deal with multi-line authors; it + % changes \\ to ', ' (comma-space), making it pass muster for + % generating document info in the PDF file. + \def\\{, } + \pdfinfo{ + /Author (\@author) + /Title (\@title) + } + \endgroup + \fi + \begin{flushright}% + {\rm\Huge\py@HeaderFamily \@title \par}% + {\em\LARGE\py@HeaderFamily \py@release\releaseinfo \par} + \vfill + {\LARGE\py@HeaderFamily \@author \par} + \vfill\vfill + {\large + \@date \par + \vfill + \py@authoraddress \par + }% + \end{flushright}%\par + \@thanks + \end{titlepage}% + \setcounter{footnote}{0}% + \let\thanks\relax\let\maketitle\relax + \gdef\@thanks{}\gdef\@author{}\gdef\@title{} +} + + +% Catch the end of the {abstract} environment, but here make sure the +% abstract is followed by a blank page if the 'openright' option is used. +% +\let\py@OldEndAbstract=\endabstract +\renewcommand{\endabstract}{ + \if@openright + \ifodd\value{page} + \typeout{Adding blank page after the abstract.} + \vfil\pagebreak + \fi + \fi + \py@OldEndAbstract +} + +% This wraps the \tableofcontents macro with all the magic to get the +% spacing right and have the right number of pages if the 'openright' +% option has been used. This eliminates a fair amount of crud in the +% individual document files. +% +\let\py@OldTableofcontents=\tableofcontents +\renewcommand{\tableofcontents}{% + \setcounter{page}{1}% + \pagebreak% + \pagestyle{plain}% + {% + \parskip = 0mm% + \py@OldTableofcontents% + \if@openright% + \ifodd\value{page}% + \typeout{Adding blank page after the table of contents.}% + \pagebreak\hspace{0pt}% + \fi% + \fi% + \cleardoublepage% + }% + \pagenumbering{arabic}% + \@ifundefined{fancyhf}{}{\pagestyle{normal}}% + \py@doing@page@targetstrue% +} +% This is needed to get the width of the section # area wide enough in the +% library reference. Doing it here keeps it the same for all the manuals. +% +\renewcommand*\l@section{\@dottedtocline{1}{1.5em}{2.6em}} +\renewcommand*\l@subsection{\@dottedtocline{2}{4.1em}{3.5em}} +\setcounter{tocdepth}{1} + + +% Fix the theindex environment to add an entry to the Table of +% Contents; this is much nicer than just having to jump to the end of +% the book and flip around, especially with multiple indexes. +% +\let\py@OldTheindex=\theindex +\renewcommand{\theindex}{ + \cleardoublepage + \py@OldTheindex + \addcontentsline{toc}{chapter}{\indexname} +} diff --git a/sys/src/cmd/python/Doc/texinputs/pypaper.sty b/sys/src/cmd/python/Doc/texinputs/pypaper.sty new file mode 100644 index 000000000..395963761 --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/pypaper.sty @@ -0,0 +1,18 @@ +% +% Change this to say a4paper instead of letterpaper if you want A4. These +% are the latex defaults. +% +\newcommand{\py@paper}{letterpaper} +\newcommand{\py@ptsize}{10pt} + +% These set up the fonts for the documents. +% +% The "times" package makes the default font the PostScript Times +% font, which makes for smaller PostScript and a font that more people +% like. +% +% The "avant" package causes the AvantGarde font to be used for +% sans-serif text, instead of the uglier Helvetica set up by the "times" +% package. +% +\RequirePackage{times}\typeout{Using Times instead of Computer Modern.} diff --git a/sys/src/cmd/python/Doc/texinputs/python.ist b/sys/src/cmd/python/Doc/texinputs/python.ist new file mode 100644 index 000000000..9ffa0f959 --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/python.ist @@ -0,0 +1,11 @@ +line_max 100 +headings_flag 1 +heading_prefix " \\bigletter " + +preamble "\\begin{theindex} +\\def\\bigletter#1{{\\Large\\sffamily#1}\\nopagebreak\\vspace{1mm}} + +" + +symhead_positive "{Symbols}" +numhead_positive "{Numbers}" diff --git a/sys/src/cmd/python/Doc/texinputs/python.sty b/sys/src/cmd/python/Doc/texinputs/python.sty new file mode 100644 index 000000000..3ce62f4f9 --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/python.sty @@ -0,0 +1,1327 @@ +% +% python.sty for the Python docummentation [works only with Latex2e] +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{python} + [1998/01/11 LaTeX package (Python markup)] + +\RequirePackage{longtable} +\RequirePackage{underscore} + +% Uncomment these two lines to ignore the paper size and make the page +% size more like a typical published manual. +%\renewcommand{\paperheight}{9in} +%\renewcommand{\paperwidth}{8.5in} % typical squarish manual +%\renewcommand{\paperwidth}{7in} % O'Reilly ``Programmming Python'' + +% These packages can be used to add marginal annotations which indicate +% index entries and labels; useful for reviewing this messy documentation! +% +%\RequirePackage{showkeys} +%\RequirePackage{showidx} + +% If we ever want to indent paragraphs, this needs to be changed. +% This is used inside the macros defined here instead of coding +% \noindent directly. +\let\py@parindent=\noindent + +% for PDF output, use maximal compression & a lot of other stuff +% (test for PDF recommended by Tanmoy Bhattacharya <tanmoy@qcd.lanl.gov>) +% +\newif\ifpy@doing@page@targets +\py@doing@page@targetsfalse + +\newif\ifpdf\pdffalse +\ifx\pdfoutput\undefined\else\ifcase\pdfoutput +\else + \pdftrue + \input{pdfcolor} + \let\py@LinkColor=\NavyBlue + \let\py@NormalColor=\Black + \pdfcompresslevel=9 + \pdfpagewidth=\paperwidth % page width of PDF output + \pdfpageheight=\paperheight % page height of PDF output + % + % Pad the number with '0' to 3 digits wide so no page name is a prefix + % of any other. + % + \newcommand{\py@targetno}[1]{\ifnum#1<100 0\fi\ifnum#1<10 0\fi#1} + \newcommand{\py@pageno}{\py@targetno\thepage} + % + % This definition allows the entries in the page-view of the ToC to be + % active links. Some work, some don't. + % + \let\py@OldContentsline=\contentsline + % + % Backward compatibility hack: pdfTeX 0.13 defined \pdfannotlink, + % but it changed to \pdfstartlink in 0.14. This let's us use either + % version and still get useful behavior. + % + \@ifundefined{pdfstartlink}{ + \let\pdfstartlink=\pdfannotlink + }{} + % + % The \py@parindent here is a hack -- we're forcing pdfTeX into + % horizontal mode since \pdfstartlink requires that. + \def\py@pdfstartlink{% + \ifvmode\py@parindent\fi% + \pdfstartlink% + } + % + % Macro that takes two args: the name to link to and the content of + % the link. This takes care of the PDF magic, getting the colors + % the same for each link, and avoids having lots of garbage all over + % this style file. + \newcommand{\py@linkToName}[2]{% + \py@pdfstartlink attr{/Border [0 0 0]} goto name{#1}% + \py@LinkColor#2\py@NormalColor% + \pdfendlink% + } + % Compute the padded page number separately since we end up with a pair of + % \relax tokens; this gets the right string computed and works. + \renewcommand{\contentsline}[3]{% + \def\my@pageno{\py@targetno{#3}}% + \py@OldContentsline{#1}{\py@linkToName{page\my@pageno}{#2}}{#3}% + } + \AtEndDocument{ + \def\_{\string_} + \InputIfFileExists{\jobname.bkm}{\pdfcatalog{/PageMode /UseOutlines}}{} + } + \newcommand{\py@target}[1]{% + \ifpy@doing@page@targets% + {\pdfdest name{#1} xyz}% + \fi% + } + \let\py@OldLabel=\label + \renewcommand{\label}[1]{% + \py@OldLabel{#1}% + \py@target{label-#1}% + } + % This stuff adds a page# destination to every PDF page, where # is three + % digits wide, padded with leading zeros. This doesn't really help with + % the frontmatter, but does fine with the body. + % + % This is *heavily* based on the hyperref package. + % + \def\@begindvi{% + \unvbox \@begindvibox + \@hyperfixhead + } + \def\@hyperfixhead{% + \let\H@old@thehead\@thehead + \global\def\@foo{\py@target{page\py@pageno}}% + \expandafter\ifx\expandafter\@empty\H@old@thehead + \def\H@old@thehead{\hfil}\fi + \def\@thehead{\@foo\relax\H@old@thehead}% + } +\fi\fi + +% Increase printable page size (copied from fullpage.sty) +\topmargin 0pt +\advance \topmargin by -\headheight +\advance \topmargin by -\headsep + +% attempt to work a little better for A4 users +\textheight \paperheight +\advance\textheight by -2in + +\oddsidemargin 0pt +\evensidemargin 0pt +%\evensidemargin -.25in % for ``manual size'' documents +\marginparwidth 0.5in + +\textwidth \paperwidth +\advance\textwidth by -2in + + +% Style parameters and macros used by most documents here +\raggedbottom +\sloppy +\parindent = 0mm +\parskip = 2mm +\hbadness = 5000 % don't print trivial gripes + +\pagestyle{empty} % start this way; change for +\pagenumbering{roman} % ToC & chapters + +% Use this to set the font family for headers and other decor: +\newcommand{\py@HeaderFamily}{\sffamily} + +% Set up abstract ways to get the normal and smaller font sizes that +% work even in footnote context. +\newif\ifpy@infootnote \py@infootnotefalse +\let\py@oldmakefntext\@makefntext +\def\@makefntext#1{% + \bgroup% + \py@infootnotetrue + \py@oldmakefntext{#1}% + \egroup% +} +\def\py@defaultsize{% + \ifpy@infootnote\footnotesize\else\normalsize\fi% +} +\def\py@smallsize{% + \ifpy@infootnote\scriptsize\else\small\fi% +} + +% Redefine the 'normal' header/footer style when using "fancyhdr" package: +\@ifundefined{fancyhf}{}{ + % Use \pagestyle{normal} as the primary pagestyle for text. + \fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} + \fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}} + \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0.4pt} + } + % Update the plain style so we get the page number & footer line, + % but not a chapter or section title. This is to keep the first + % page of a chapter and the blank page between chapters `clean.' + \fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0.4pt} + } + % Redefine \cleardoublepage so that the blank page between chapters + % gets the plain style and not the fancy style. This is described + % in the documentation for the fancyhdr package by Piet von Oostrum. + \@ifundefined{chapter}{}{ + \renewcommand{\cleardoublepage}{ + \clearpage\if@openright \ifodd\c@page\else + \hbox{} + \thispagestyle{plain} + \newpage + \if@twocolumn\hbox{}\newpage\fi\fi\fi + } + } +} + +% This sets up the {verbatim} environment to be indented and a minipage, +% and to have all the other mostly nice properties that we want for +% code samples. + +\let\py@OldVerbatim=\verbatim +\let\py@OldEndVerbatim=\endverbatim +\RequirePackage{verbatim} +\let\py@OldVerbatimInput=\verbatiminput + +% Variable used by begin code command +\newlength{\py@codewidth} + +\renewcommand{\verbatim}{% + \setlength{\parindent}{1cm}% + % Calculate the text width for the minipage: + \setlength{\py@codewidth}{\linewidth}% + \addtolength{\py@codewidth}{-\parindent}% + % + \par\indent% + \begin{minipage}[t]{\py@codewidth}% + \small% + \py@OldVerbatim% +} +\renewcommand{\endverbatim}{% + \py@OldEndVerbatim% + \end{minipage}% +} +\renewcommand{\verbatiminput}[1]{% + {\setlength{\parindent}{1cm}% + % Calculate the text width for the minipage: + \setlength{\py@codewidth}{\linewidth}% + \addtolength{\py@codewidth}{-\parindent}% + % + \small% + \begin{list}{}{\setlength{\leftmargin}{1cm}} + \item% + \py@OldVerbatimInput{#1}% + \end{list} + }% +} + +% This does a similar thing for the {alltt} environment: +\RequirePackage{alltt} +\let\py@OldAllTT=\alltt +\let\py@OldEndAllTT=\endalltt + +\renewcommand{\alltt}{% + \setlength{\parindent}{1cm}% + % Calculate the text width for the minipage: + \setlength{\py@codewidth}{\linewidth}% + \addtolength{\py@codewidth}{-\parindent}% + \let\e=\textbackslash% + % + \par\indent% + \begin{minipage}[t]{\py@codewidth}% + \small% + \py@OldAllTT% +} +\renewcommand{\endalltt}{% + \py@OldEndAllTT% + \end{minipage}% +} + + +\newcommand{\py@modulebadkey}{{--just-some-junk--}} + + +%% Lots of index-entry generation support. + +% Command to wrap around stuff that refers to function / module / +% attribute names in the index. Default behavior: like \code{}. To +% just keep the index entries in the roman font, uncomment the second +% definition; it matches O'Reilly style more. +% +\newcommand{\py@idxcode}[1]{\texttt{#1}} +%\renewcommand{\py@idxcode}[1]{#1} + +% Command to generate two index entries (using subentries) +\newcommand{\indexii}[2]{\index{#1!#2}\index{#2!#1}} + +% And three entries (using only one level of subentries) +\newcommand{\indexiii}[3]{\index{#1!#2 #3}\index{#2!#3, #1}\index{#3!#1 #2}} + +% And four (again, using only one level of subentries) +\newcommand{\indexiv}[4]{ +\index{#1!#2 #3 #4} +\index{#2!#3 #4, #1} +\index{#3!#4, #1 #2} +\index{#4!#1 #2 #3} +} + +% Command to generate a reference to a function, statement, keyword, +% operator. +\newcommand{\kwindex}[1]{\indexii{keyword}{#1@{\py@idxcode{#1}}}} +\newcommand{\stindex}[1]{\indexii{statement}{#1@{\py@idxcode{#1}}}} +\newcommand{\opindex}[1]{\indexii{operator}{#1@{\py@idxcode{#1}}}} +\newcommand{\exindex}[1]{\indexii{exception}{#1@{\py@idxcode{#1}}}} +\newcommand{\obindex}[1]{\indexii{object}{#1}} +\newcommand{\bifuncindex}[1]{% + \index{#1@{\py@idxcode{#1()}} (built-in function)}} + +% Add an index entry for a module +\newcommand{\py@refmodule}[2]{\index{#1@{\py@idxcode{#1}} (#2module)}} +\newcommand{\refmodindex}[1]{\py@refmodule{#1}{}} +\newcommand{\refbimodindex}[1]{\py@refmodule{#1}{built-in }} +\newcommand{\refexmodindex}[1]{\py@refmodule{#1}{extension }} +\newcommand{\refstmodindex}[1]{\py@refmodule{#1}{standard }} + +% Refer to a module's documentation using a hyperlink of the module's +% name, at least if we're building PDF: +\ifpdf + \newcommand{\refmodule}[2][\py@modulebadkey]{% + \ifx\py@modulebadkey#1\def\py@modulekey{#2}\else\def\py@modulekey{#1}\fi% + \py@linkToName{label-module-\py@modulekey}{\module{#2}}% + } +\else + \newcommand{\refmodule}[2][\py@modulebadkey]{\module{#2}} +\fi + +% support for the module index +\newif\ifpy@UseModuleIndex +\py@UseModuleIndexfalse + +\newcommand{\makemodindex}{ + \newwrite\modindexfile + \openout\modindexfile=mod\jobname.idx + \py@UseModuleIndextrue +} + +% Add the defining entry for a module +\newcommand{\py@modindex}[2]{% + \renewcommand{\py@thismodule}{#1} + \setindexsubitem{(in module #1)}% + \index{#1@{\py@idxcode{#1}} (#2module)|textbf}% + \ifpy@UseModuleIndex% + \@ifundefined{py@modplat@\py@thismodulekey}{ + \write\modindexfile{\protect\indexentry{#1@{\texttt{#1}}}{\thepage}}% + }{\write\modindexfile{\protect\indexentry{#1@{\texttt{#1} % + \emph{(\py@platformof[\py@thismodulekey]{})}}}{\thepage}}% + } + \fi% +} + +% *** XXX *** THE NEXT FOUR MACROS ARE NOW OBSOLETE !!! *** + +% built-in & Python modules in the main distribution +\newcommand{\bimodindex}[1]{\py@modindex{#1}{built-in }% + \typeout{*** MACRO bimodindex IS OBSOLETE -- USE declaremodule INSTEAD!}} +\newcommand{\stmodindex}[1]{\py@modindex{#1}{standard }% + \typeout{*** MACRO stmodindex IS OBSOLETE -- USE declaremodule INSTEAD!}} + +% Python & extension modules outside the main distribution +\newcommand{\modindex}[1]{\py@modindex{#1}{}% + \typeout{*** MACRO modindex IS OBSOLETE -- USE declaremodule INSTEAD!}} +\newcommand{\exmodindex}[1]{\py@modindex{#1}{extension }% + \typeout{*** MACRO exmodindex IS OBSOLETE -- USE declaremodule INSTEAD!}} + +% Additional string for an index entry +\newif\ifpy@usingsubitem\py@usingsubitemfalse +\newcommand{\py@indexsubitem}{} +\newcommand{\setindexsubitem}[1]{\renewcommand{\py@indexsubitem}{ #1}% + \py@usingsubitemtrue} +\newcommand{\ttindex}[1]{% + \ifpy@usingsubitem + \index{#1@{\py@idxcode{#1}}\py@indexsubitem}% + \else% + \index{#1@{\py@idxcode{#1}}}% + \fi% +} +\newcommand{\withsubitem}[2]{% + \begingroup% + \def\ttindex##1{\index{##1@{\py@idxcode{##1}} #1}}% + #2% + \endgroup% +} + + +% Module synopsis processing ----------------------------------------------- +% +\newcommand{\py@thisclass}{} +\newcommand{\py@thismodule}{} +\newcommand{\py@thismodulekey}{} +\newcommand{\py@thismoduletype}{} + +\newcommand{\py@standardIndexModule}[1]{\py@modindex{#1}{standard }} +\newcommand{\py@builtinIndexModule}[1]{\py@modindex{#1}{built-in }} +\newcommand{\py@extensionIndexModule}[1]{\py@modindex{#1}{extension }} +\newcommand{\py@IndexModule}[1]{\py@modindex{#1}{}} + +\newif\ifpy@HaveModSynopsis \py@HaveModSynopsisfalse +\newif\ifpy@ModSynopsisFileIsOpen \py@ModSynopsisFileIsOpenfalse +\newif\ifpy@HaveModPlatform \py@HaveModPlatformfalse + +% \declaremodule[key]{type}{name} +\newcommand{\declaremodule}[3][\py@modulebadkey]{ + \py@openModSynopsisFile + \renewcommand{\py@thismoduletype}{#2} + \ifx\py@modulebadkey#1 + \renewcommand{\py@thismodulekey}{#3} + \else + \renewcommand{\py@thismodulekey}{#1} + \fi + \@ifundefined{py@#2IndexModule}{% + \typeout{*** MACRO declaremodule called with unknown module type: `#2'} + \py@IndexModule{#3}% + }{% + \csname py@#2IndexModule\endcsname{#3}% + } + \label{module-\py@thismodulekey} +} +\newif\ifpy@ModPlatformFileIsOpen \py@ModPlatformFileIsOpenfalse +\newcommand{\py@ModPlatformFilename}{\jobname.pla} +\newcommand{\platform}[1]{ + \ifpy@ModPlatformFileIsOpen\else + \newwrite\py@ModPlatformFile + \openout\py@ModPlatformFile=\py@ModPlatformFilename + \py@ModPlatformFileIsOpentrue + \fi +} +\InputIfFileExists{\jobname.pla}{}{} +\newcommand{\py@platformof}[2][\py@modulebadkey]{% + \ifx\py@modulebadkey#1 \def\py@key{#2}% + \else \def\py@key{#1}% + \fi% + \csname py@modplat@\py@key\endcsname% +} +\newcommand{\ignorePlatformAnnotation}[1]{} + +% \moduleauthor{name}{email} +\newcommand{\moduleauthor}[2]{} + +% \sectionauthor{name}{email} +\newcommand{\sectionauthor}[2]{} + + +\newcommand{\py@defsynopsis}{Module has no synopsis.} +\newcommand{\py@modulesynopsis}{\py@defsynopsis} +\newcommand{\modulesynopsis}[1]{ + \py@HaveModSynopsistrue + \renewcommand{\py@modulesynopsis}{#1} +} + +% define the file +\newwrite\py@ModSynopsisFile + +% hacked from \addtocontents from latex.ltx: +\long\def\py@writeModSynopsisFile#1{% + \protected@write\py@ModSynopsisFile% + {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}% + {\string#1}% +} +\newcommand{\py@closeModSynopsisFile}{ + \ifpy@ModSynopsisFileIsOpen + \closeout\py@ModSynopsisFile + \py@ModSynopsisFileIsOpenfalse + \fi +} +\newcommand{\py@openModSynopsisFile}{ + \ifpy@ModSynopsisFileIsOpen\else + \openout\py@ModSynopsisFile=\py@ModSynopsisFilename + \py@ModSynopsisFileIsOpentrue + \fi +} + +\newcommand{\py@ProcessModSynopsis}{ + \ifpy@HaveModSynopsis + \py@writeModSynopsisFile{\modulesynopsis% + {\py@thismodulekey}{\py@thismodule}% + {\py@thismoduletype}{\py@modulesynopsis}}% + \py@HaveModSynopsisfalse + \fi + \renewcommand{\py@modulesynopsis}{\py@defsynopsis} +} +\AtEndDocument{\py@ProcessModSynopsis\py@closeModSynopsisFile} + + +\long\def\py@writeModPlatformFile#1{% + \protected@write\py@ModPlatformFile% + {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}% + {\string#1}% +} + + +\newcommand{\localmoduletable}{ + \IfFileExists{\py@ModSynopsisFilename}{ + \begin{synopsistable} + \input{\py@ModSynopsisFilename} + \end{synopsistable} + }{} +} + +\ifpdf + \newcommand{\py@ModSynopsisSummary}[4]{% + \py@linkToName{label-module-#1}{\bfcode{#2}} & #4\\ + } +\else + \newcommand{\py@ModSynopsisSummary}[4]{\bfcode{#2} & #4\\} +\fi +\newenvironment{synopsistable}{ + % key, name, type, synopsis + \let\modulesynopsis=\py@ModSynopsisSummary + \begin{tabular}{ll} +}{ + \end{tabular} +} +% +% -------------------------------------------------------------------------- + + +\newcommand{\py@reset}{ + \py@usingsubitemfalse + \py@ProcessModSynopsis + \renewcommand{\py@thisclass}{} + \renewcommand{\py@thismodule}{} + \renewcommand{\py@thismodulekey}{} + \renewcommand{\py@thismoduletype}{} +} + +% Augment the sectioning commands used to get our own font family in place, +% and reset some internal data items: +\renewcommand{\section}{\py@reset% + \@startsection{section}{1}{\z@}% + {-3.5ex \@plus -1ex \@minus -.2ex}% + {2.3ex \@plus.2ex}% + {\reset@font\Large\py@HeaderFamily}} +\renewcommand{\subsection}{\@startsection{subsection}{2}{\z@}% + {-3.25ex\@plus -1ex \@minus -.2ex}% + {1.5ex \@plus .2ex}% + {\reset@font\large\py@HeaderFamily}} +\renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{\z@}% + {-3.25ex\@plus -1ex \@minus -.2ex}% + {1.5ex \@plus .2ex}% + {\reset@font\normalsize\py@HeaderFamily}} +\renewcommand{\paragraph}{\@startsection{paragraph}{4}{\z@}% + {3.25ex \@plus1ex \@minus.2ex}% + {-1em}% + {\reset@font\normalsize\py@HeaderFamily}} +\renewcommand{\subparagraph}{\@startsection{subparagraph}{5}{\parindent}% + {3.25ex \@plus1ex \@minus .2ex}% + {-1em}% + {\reset@font\normalsize\py@HeaderFamily}} + + +% Now for a lot of semantically-loaded environments that do a ton of magical +% things to get the right formatting and index entries for the stuff in +% Python modules and C API. + + +% {fulllineitems} is used in one place in libregex.tex, but is really for +% internal use in this file. +% +\newcommand{\py@itemnewline}[1]{% + \@tempdima\linewidth% + \advance\@tempdima \leftmargin\makebox[\@tempdima][l]{#1}% +} + +\newenvironment{fulllineitems}{ + \begin{list}{}{\labelwidth \leftmargin \labelsep 0pt + \rightmargin 0pt \topsep -\parskip \partopsep \parskip + \itemsep -\parsep + \let\makelabel=\py@itemnewline} +}{\end{list}} + +% \optional is mostly for use in the arguments parameters to the various +% {*desc} environments defined below, but may be used elsewhere. Known to +% be used in the debugger chapter. +% +% Typical usage: +% +% \begin{funcdesc}{myfunc}{reqparm\optional{, optparm}} +% ^^^ ^^^ +% No space here No space here +% +% When a function has multiple optional parameters, \optional should be +% nested, not chained. This is right: +% +% \begin{funcdesc}{myfunc}{\optional{parm1\optional{, parm2}}} +% +\let\py@badkey=\@undefined + +\newcommand{\optional}[1]{% + {\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}} + +% This can be used when a function or method accepts an varying number +% of arguments, such as by using the *args syntax in the parameter list. +\newcommand{\py@moreargs}{...} + +% This can be used when you don't want to document the parameters to a +% function or method, but simply state that it's an alias for +% something else. +\newcommand{\py@unspecified}{...} + + +\newlength{\py@argswidth} +\newcommand{\py@sigparams}[1]{% + \parbox[t]{\py@argswidth}{\py@varvars{#1}\code{)}}} +\newcommand{\py@sigline}[2]{% + \settowidth{\py@argswidth}{#1\code{(}}% + \addtolength{\py@argswidth}{-2\py@argswidth}% + \addtolength{\py@argswidth}{\textwidth}% + \item[#1\code{(}\py@sigparams{#2}]} + +% C functions ------------------------------------------------------------ +% \begin{cfuncdesc}[refcount]{type}{name}{arglist} +% Note that the [refcount] slot should only be filled in by +% tools/anno-api.py; it pulls the value from the refcounts database. +\newcommand{\cfuncline}[3]{ + \py@sigline{\code{#1 \bfcode{#2}}}{#3}% + \index{#2@{\py@idxcode{#2()}}} +} +\newenvironment{cfuncdesc}[4][\py@badkey]{ + \begin{fulllineitems} + \cfuncline{#2}{#3}{#4} + \ifx#1\@undefined\else% + \emph{Return value: \textbf{#1}.}\\ + \fi +}{\end{fulllineitems}} + +% C variables ------------------------------------------------------------ +% \begin{cvardesc}{type}{name} +\newenvironment{cvardesc}[2]{ + \begin{fulllineitems} + \item[\code{#1 \bfcode{#2}}\index{#2@{\py@idxcode{#2}}}] +}{\end{fulllineitems}} + +% C data types ----------------------------------------------------------- +% \begin{ctypedesc}[index name]{typedef name} +\newenvironment{ctypedesc}[2][\py@badkey]{ + \begin{fulllineitems} + \item[\bfcode{#2}% + \ifx#1\@undefined% + \index{#2@{\py@idxcode{#2}} (C type)} + \else% + \index{#2@{\py@idxcode{#1}} (C type)} + \fi] +}{\end{fulllineitems}} + +% C type fields ---------------------------------------------------------- +% \begin{cmemberdesc}{container type}{ctype}{membername} +\newcommand{\cmemberline}[3]{ + \item[\code{#2 \bfcode{#3}}] + \index{#3@{\py@idxcode{#3}} (#1 member)} +} +\newenvironment{cmemberdesc}[3]{ + \begin{fulllineitems} + \cmemberline{#1}{#2}{#3} +}{\end{fulllineitems}} + +% Funky macros ----------------------------------------------------------- +% \begin{csimplemacrodesc}{name} +% -- "simple" because it has no args; NOT for constant definitions! +\newenvironment{csimplemacrodesc}[1]{ + \begin{fulllineitems} + \item[\bfcode{#1}\index{#1@{\py@idxcode{#1}} (macro)}] +}{\end{fulllineitems}} + +% simple functions (not methods) ----------------------------------------- +% \begin{funcdesc}{name}{args} +\newcommand{\funcline}[2]{% + \funclineni{#1}{#2}% + \index{#1@{\py@idxcode{#1()}} (in module \py@thismodule)}} +\newenvironment{funcdesc}[2]{ + \begin{fulllineitems} + \funcline{#1}{#2} +}{\end{fulllineitems}} + +% similar to {funcdesc}, but doesn't add to the index +\newcommand{\funclineni}[2]{% + \py@sigline{\bfcode{#1}}{#2}} +\newenvironment{funcdescni}[2]{ + \begin{fulllineitems} + \funclineni{#1}{#2} +}{\end{fulllineitems}} + +% classes ---------------------------------------------------------------- +% \begin{classdesc}{name}{constructor args} +\newenvironment{classdesc}[2]{ + % Using \renewcommand doesn't work for this, for unknown reasons: + \global\def\py@thisclass{#1} + \begin{fulllineitems} + \py@sigline{\strong{class }\bfcode{#1}}{#2}% + \index{#1@{\py@idxcode{#1}} (class in \py@thismodule)} +}{\end{fulllineitems}} + +% \begin{classdesc*}{name} +\newenvironment{classdesc*}[1]{ + % Using \renewcommand doesn't work for this, for unknown reasons: + \global\def\py@thisclass{#1} + \begin{fulllineitems} + \item[\strong{class }\code{\bfcode{#1}}% + \index{#1@{\py@idxcode{#1}} (class in \py@thismodule)}] +}{\end{fulllineitems}} + +% \begin{excclassdesc}{name}{constructor args} +% but indexes as an exception +\newenvironment{excclassdesc}[2]{ + % Using \renewcommand doesn't work for this, for unknown reasons: + \global\def\py@thisclass{#1} + \begin{fulllineitems} + \py@sigline{\strong{exception }\bfcode{#1}}{#2}% + \index{#1@{\py@idxcode{#1}} (exception in \py@thismodule)} +}{\end{fulllineitems}} + +% There is no corresponding {excclassdesc*} environment. To describe +% a class exception without parameters, use the {excdesc} environment. + + +\let\py@classbadkey=\@undefined + +% object method ---------------------------------------------------------- +% \begin{methoddesc}[classname]{methodname}{args} +\newcommand{\methodline}[3][\@undefined]{ + \methodlineni{#2}{#3} + \ifx#1\@undefined + \index{#2@{\py@idxcode{#2()}} (\py@thisclass\ method)} + \else + \index{#2@{\py@idxcode{#2()}} (#1 method)} + \fi +} +\newenvironment{methoddesc}[3][\@undefined]{ + \begin{fulllineitems} + \ifx#1\@undefined + \methodline{#2}{#3} + \else + \def\py@thisclass{#1} + \methodline{#2}{#3} + \fi +}{\end{fulllineitems}} + +% similar to {methoddesc}, but doesn't add to the index +% (never actually uses the optional argument) +\newcommand{\methodlineni}[3][\py@classbadkey]{% + \py@sigline{\bfcode{#2}}{#3}} +\newenvironment{methoddescni}[3][\py@classbadkey]{ + \begin{fulllineitems} + \methodlineni{#2}{#3} +}{\end{fulllineitems}} + +% object data attribute -------------------------------------------------- +% \begin{memberdesc}[classname]{membername} +\newcommand{\memberline}[2][\py@classbadkey]{% + \ifx#1\@undefined + \memberlineni{#2} + \index{#2@{\py@idxcode{#2}} (\py@thisclass\ attribute)} + \else + \memberlineni{#2} + \index{#2@{\py@idxcode{#2}} (#1 attribute)} + \fi +} +\newenvironment{memberdesc}[2][\py@classbadkey]{ + \begin{fulllineitems} + \ifx#1\@undefined + \memberline{#2} + \else + \def\py@thisclass{#1} + \memberline{#2} + \fi +}{\end{fulllineitems}} + +% similar to {memberdesc}, but doesn't add to the index +% (never actually uses the optional argument) +\newcommand{\memberlineni}[2][\py@classbadkey]{\item[\bfcode{#2}]} +\newenvironment{memberdescni}[2][\py@classbadkey]{ + \begin{fulllineitems} + \memberlineni{#2} +}{\end{fulllineitems}} + +% For exceptions: -------------------------------------------------------- +% \begin{excdesc}{name} +% -- for constructor information, use excclassdesc instead +\newenvironment{excdesc}[1]{ + \begin{fulllineitems} + \item[\strong{exception }\bfcode{#1}% + \index{#1@{\py@idxcode{#1}} (exception in \py@thismodule)}] +}{\end{fulllineitems}} + +% Module data or constants: ---------------------------------------------- +% \begin{datadesc}{name} +\newcommand{\dataline}[1]{% + \datalineni{#1}\index{#1@{\py@idxcode{#1}} (data in \py@thismodule)}} +\newenvironment{datadesc}[1]{ + \begin{fulllineitems} + \dataline{#1} +}{\end{fulllineitems}} + +% similar to {datadesc}, but doesn't add to the index +\newcommand{\datalineni}[1]{\item[\bfcode{#1}]\nopagebreak} +\newenvironment{datadescni}[1]{ + \begin{fulllineitems} + \datalineni{#1} +}{\end{fulllineitems}} + +% bytecode instruction --------------------------------------------------- +% \begin{opcodedesc}{name}{var} +% -- {var} may be {} +\newenvironment{opcodedesc}[2]{ + \begin{fulllineitems} + \item[\bfcode{#1}\quad\var{#2}] +}{\end{fulllineitems}} + + +\newcommand{\nodename}[1]{\label{#1}} + +% For these commands, use \command{} to get the typography right, not +% {\command}. This works better with the texinfo translation. +\newcommand{\ABC}{{\sc abc}} +\newcommand{\UNIX}{{\sc Unix}} +\newcommand{\POSIX}{POSIX} +\newcommand{\ASCII}{{\sc ascii}} +\newcommand{\Cpp}{C\protect\raisebox{.18ex}{++}} +\newcommand{\C}{C} +\newcommand{\EOF}{{\sc eof}} +\newcommand{\NULL}{\constant{NULL}} +\newcommand{\infinity}{\ensuremath{\infty}} +\newcommand{\plusminus}{\ensuremath{\pm}} + +% \guilabel{Start} +\newcommand{\guilabel}[1]{\textsf{#1}} +% \menuselection{Start \sub Programs \sub Python} +\newcommand{\menuselection}[1]{\guilabel{{\def\sub{ \ensuremath{>} }#1}}} + +% Also for consistency: spell Python "Python", not "python"! + +% code is the most difficult one... +\newcommand{\code}[1]{\textrm{\@vobeyspaces\@noligs\def\{{\char`\{}\def\}{\char`\}}\def\~{\char`\~}\def\^{\char`\^}\def\e{\char`\\}\def\${\char`\$}\def\#{\char`\#}\def\&{\char`\&}\def\%{\char`\%}% +\texttt{#1}}} + +\newcommand{\bfcode}[1]{\code{\bfseries#1}} % bold-faced code font +\newcommand{\csimplemacro}[1]{\code{#1}} +\newcommand{\kbd}[1]{\code{#1}} +\newcommand{\samp}[1]{`\code{#1}'} +\newcommand{\var}[1]{% + \ifmmode% + \hbox{\py@defaultsize\textrm{\textit{#1\/}}}% + \else% + \py@defaultsize\textrm{\textit{#1\/}}% + \fi% +} +\renewcommand{\emph}[1]{{\em #1}} +\newcommand{\dfn}[1]{\emph{#1}} +\newcommand{\strong}[1]{{\bf #1}} +% let's experiment with a new font: +\newcommand{\file}[1]{`\filenq{#1}'} +\newcommand{\filenq}[1]{{\py@smallsize\textsf{\let\e=\textbackslash#1}}} + +% Use this def/redef approach for \url{} since hyperref defined this already, +% but only if we actually used hyperref: +\ifpdf + \newcommand{\url}[1]{{% + \py@pdfstartlink% + attr{ /Border [0 0 0] }% + user{% + /Subtype/Link% + /A<<% + /Type/Action% + /S/URI% + /URI(#1)% + >>% + }% + \py@LinkColor% color of the link text + \py@smallsize\sf #1% + \py@NormalColor% Turn it back off; these are declarative + \pdfendlink}% and don't appear bound to the current + }% formatting "box". +\else + \newcommand{\url}[1]{\mbox{\py@smallsize\textsf{#1}}} +\fi +\newcommand{\email}[1]{{\py@smallsize\textsf{#1}}} +\newcommand{\newsgroup}[1]{{\py@smallsize\textsf{#1}}} + +\newcommand{\py@varvars}[1]{{% + {\let\unspecified=\py@unspecified% + \let\moreargs=\py@moreargs% + \var{#1}}}} + +% I'd really like to get rid of this! +\newif\iftexi\texifalse + +% This is used to get l2h to put the copyright and abstract on +% a separate HTML page. +\newif\ifhtml\htmlfalse + + +% These should be used for all references to identifiers which are +% used to refer to instances of specific language constructs. See the +% names for specific semantic assignments. +% +% For now, don't do anything really fancy with them; just use them as +% logical markup. This might change in the future. +% +\newcommand{\module}[1]{\texttt{#1}} +\newcommand{\keyword}[1]{\texttt{#1}} +\newcommand{\exception}[1]{\texttt{#1}} +\newcommand{\class}[1]{\texttt{#1}} +\newcommand{\function}[1]{\texttt{#1}} +\newcommand{\member}[1]{\texttt{#1}} +\newcommand{\method}[1]{\texttt{#1}} + +\newcommand{\pytype}[1]{#1} % built-in Python type + +\newcommand{\cfunction}[1]{\texttt{#1}} +\newcommand{\ctype}[1]{\texttt{#1}} % C struct or typedef name +\newcommand{\cdata}[1]{\texttt{#1}} % C variable, typically global + +\newcommand{\mailheader}[1]{{\py@smallsize\textsf{#1:}}} +\newcommand{\mimetype}[1]{{\py@smallsize\textsf{#1}}} +% The \! is a "negative thin space" in math mode. +\newcommand{\regexp}[1]{% + {\tiny$^{^\lceil}\!\!$% + {\py@defaultsize\code{#1}}% + $\!\rfloor\!$% + }} +\newcommand{\envvar}[1]{% + #1% + \index{#1}% + \index{environment variables!{#1}}% +} +\newcommand{\makevar}[1]{#1} % variable in a Makefile +\newcommand{\character}[1]{\samp{#1}} + +% constants defined in Python modules or C headers, not language constants: +\newcommand{\constant}[1]{\code{#1}} % manifest constant, not syntactic + +\newcommand{\manpage}[2]{{\emph{#1}(#2)}} +\newcommand{\pep}[1]{PEP #1\index{Python Enhancement Proposals!PEP #1}} +\newcommand{\rfc}[1]{RFC #1\index{RFC!RFC #1}} +\newcommand{\program}[1]{\strong{#1}} +\newcommand{\programopt}[1]{\strong{#1}} +% Note that \longprogramopt provides the '--'! +\newcommand{\longprogramopt}[1]{\strong{-{}-#1}} + +% \ulink{link text}{URL} +\ifpdf + \newcommand{\ulink}[2]{{% + % For PDF, we *should* only generate a link when the URL is absolute. + \py@pdfstartlink% + attr{ /Border [0 0 0] }% + user{% + /Subtype/Link% + /A<<% + /Type/Action% + /S/URI% + /URI(#2)% + >>% + }% + \py@LinkColor% color of the link text + #1% + \py@NormalColor% Turn it back off; these are declarative + \pdfendlink}% and don't appear bound to the current + }% formatting "box". +\else + \newcommand{\ulink}[2]{#1} +\fi + +% cited titles: \citetitle{Title of Work} +% online: \citetitle[url-to-resource]{Title of Work} +\ifpdf + \newcommand{\citetitle}[2][\py@modulebadkey]{% + \ifx\py@modulebadkey#1\emph{#2}\else\ulink{\emph{#2}}{#1}\fi% + } +\else + \newcommand{\citetitle}[2][URL]{\emph{#2}} +\fi + + + +% This version is being checked in for the historical record; it shows +% how I've managed to get some aspects of this to work. It will not +% be used in practice, so a subsequent revision will change things +% again. This version has problems, but shows how to do something +% that proved more tedious than I'd expected, so I don't want to lose +% the example completely. +% +\newcommand{\grammartoken}[1]{\texttt{#1}} +\newenvironment{productionlist}[1][\py@badkey]{ + \def\optional##1{{\Large[}##1{\Large]}} + \def\production##1##2{\code{##1}&::=&\code{##2}\\} + \def\productioncont##1{& &\code{##1}\\} + \def\token##1{##1} + \let\grammartoken=\token + \parindent=2em + \indent + \begin{tabular}{lcl} +}{% + \end{tabular} +} + +\newlength{\py@noticelength} + +\newcommand{\py@heavybox}{ + \setlength{\fboxrule}{2pt} + \setlength{\fboxsep}{7pt} + \setlength{\py@noticelength}{\linewidth} + \addtolength{\py@noticelength}{-2\fboxsep} + \addtolength{\py@noticelength}{-2\fboxrule} + \setlength{\shadowsize}{3pt} + \Sbox + \minipage{\py@noticelength} +} +\newcommand{\py@endheavybox}{ + \endminipage + \endSbox + \fbox{\TheSbox} +} + +% a 'note' is as plain as it gets: +\newcommand{\py@noticelabel@note}{Note:} +\newcommand{\py@noticestart@note}{} +\newcommand{\py@noticeend@note}{} + +% a 'warning' gets more visible distinction: +\newcommand{\py@noticelabel@warning}{Warning:} +\newcommand{\py@noticestart@warning}{\py@heavybox} +\newcommand{\py@noticeend@warning}{\py@endheavybox} + +\newenvironment{notice}[1][note]{ + \def\py@noticetype{#1} + \csname py@noticestart@#1\endcsname + \par\strong{\csname py@noticelabel@#1\endcsname} +}{\csname py@noticeend@\py@noticetype\endcsname} +\newcommand{\note}[1]{\strong{\py@noticelabel@note} #1} +\newcommand{\warning}[1]{\strong{\py@noticelabel@warning} #1} + +% Deprecation stuff. +% Should be extended to allow an index / list of deprecated stuff. But +% there's a lot of stuff that needs to be done to make that automatable. +% +% First parameter is the release number that deprecates the feature, the +% second is the action the should be taken by users of the feature. +% +% Example: +% \deprecated{1.5.1}{Use \method{frobnicate()} instead.} +% +\newcommand{\deprecated}[2]{% + \strong{Deprecated since release #1.} #2\par} + +% New stuff. +% This should be used to mark things which have been added to the +% development tree but that aren't in the release, but are documented. +% This allows release of documentation that already includes updated +% descriptions. Place at end of descriptor environment. +% +% Example: +% \versionadded{1.5.2} +% \versionchanged[short explanation]{2.0} +% +\newcommand{\versionadded}[2][\py@badkey]{% + \ifx#1\@undefined% + { New in version #2. }% + \else% + { New in version #2:\ #1. }% + \fi% +} +\newcommand{\versionchanged}[2][\py@badkey]{% + \ifx#1\@undefined% + { Changed in version #2. }% + \else% + { Changed in version #2:\ #1. }% + \fi% +} + + +% Tables. +% +\newenvironment{tableii}[4]{% + \begin{center}% + \def\lineii##1##2{\csname#2\endcsname{##1}&##2\\}% + \begin{tabular}{#1}\strong{#3}&\strong{#4} \\* \hline% +}{% + \end{tabular}% + \end{center}% +} + +\newenvironment{longtableii}[4]{% + \begin{center}% + \def\lineii##1##2{\csname#2\endcsname{##1}&##2\\}% + \begin{longtable}[c]{#1}\strong{#3}&\strong{#4} \\* \hline\endhead% +}{% + \end{longtable}% + \end{center}% +} + +\newenvironment{tableiii}[5]{% + \begin{center}% + \def\lineiii##1##2##3{\csname#2\endcsname{##1}&##2&##3\\}% + \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5} \\% + \hline% +}{% + \end{tabular}% + \end{center}% +} + +\newenvironment{longtableiii}[5]{% + \begin{center}% + \def\lineiii##1##2##3{\csname#2\endcsname{##1}&##2&##3\\}% + \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5} \\% + \hline\endhead% +}{% + \end{longtable}% + \end{center}% +} + +\newenvironment{tableiv}[6]{% + \begin{center}% + \def\lineiv##1##2##3##4{\csname#2\endcsname{##1}&##2&##3&##4\\}% + \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6} \\% + \hline% +}{% + \end{tabular}% + \end{center}% +} + +\newenvironment{longtableiv}[6]{% + \begin{center}% + \def\lineiv##1##2##3##4{\csname#2\endcsname{##1}&##2&##3&##4\\}% + \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6}% + \\% + \hline\endhead% +}{% + \end{longtable}% + \end{center}% +} + +\newenvironment{tablev}[7]{% + \begin{center}% + \def\linev##1##2##3##4##5{\csname#2\endcsname{##1}&##2&##3&##4&##5\\}% + \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6}&\strong{#7} \\% + \hline% +}{% + \end{tabular}% + \end{center}% +} + +\newenvironment{longtablev}[7]{% + \begin{center}% + \def\linev##1##2##3##4##5{\csname#2\endcsname{##1}&##2&##3&##4&##5\\}% + \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6}&\strong{#7}% + \\% + \hline\endhead% +}{% + \end{longtable}% + \end{center}% +} + +% XXX Don't think we can use this yet, though it cleans up some +% tedious markup. There's no equivalent for the HTML transform yet, +% and that needs to exist. I don't know how to write it. +% +% This should really have something that makes it easier to bind a +% table's ``Notes'' column and an associated tablenotes environment, +% and generates the right magic for getting the numbers right in the +% table. +% +% So this is quite incomplete. +% +\newcounter{py@tablenotescounter} +\newenvironment{tablenotes}{% + \noindent Notes: + \par + \setcounter{py@tablenotescounter}{0} + \begin{list}{(\arabic{py@tablenotescounter})}% + {\usecounter{py@tablenotescounter}} +}{\end{list}} + + +% Cross-referencing (AMK, new impl. FLD) +% Sample usage: +% \begin{seealso} +% \seemodule{rand}{Uniform random number generator.}; % Module xref +% \seetext{\emph{Encyclopedia Britannica}}. % Ref to a book +% +% % A funky case: module name contains '_'; have to supply an optional key +% \seemodule[copyreg]{copy_reg}{Interface constructor registration for +% \module{pickle}.} +% \end{seealso} +% +% Note that the last parameter for \seemodule and \seetext should be complete +% sentences and be terminated with the proper punctuation. + +\ifpdf + \newcommand{\py@seemodule}[3][\py@modulebadkey]{% + \par% + \ifx\py@modulebadkey#1\def\py@modulekey{#2}\else\def\py@modulekey{#1}\fi% + \begin{fulllineitems} + \item[\py@linkToName{label-module-\py@modulekey}{Module \module{#2}} + (section \ref{module-\py@modulekey}):] + #3 + \end{fulllineitems} + } +\else + \newcommand{\py@seemodule}[3][\py@modulebadkey]{% + \par% + \ifx\py@modulebadkey#1\def\py@modulekey{#2}\else\def\py@modulekey{#1}\fi% + \begin{fulllineitems} + \item[Module \module{#2} (section \ref{module-\py@modulekey}):] + #3 + \end{fulllineitems} + } +\fi + +% \seelink{url}{link text}{why it's interesting} +\newcommand{\py@seelink}[3]{% + \par + \begin{fulllineitems} + \item[\ulink{#2}{#1}] + #3 + \end{fulllineitems} +} +% \seetitle[url]{title}{why it's interesting} +\newcommand{\py@seetitle}[3][\py@modulebadkey]{% + \par + \begin{fulllineitems} + \item[\citetitle{#2}] + \ifx\py@modulebadkey#1\else + \item[{\small{(\url{#1})}}] + \fi + #3 + \end{fulllineitems} +} +% \seepep{number}{title}{why it's interesting} +\newcommand{\py@seepep}[3]{% + \par% + \begin{fulllineitems} + \item[\pep{#1}, ``\emph{#2}''] + #3 + \end{fulllineitems} +} +% \seerfc{number}{title}{why it's interesting} +\newcommand{\py@seerfc}[3]{% + \par% + \begin{fulllineitems} + \item[\rfc{#1}, ``\emph{#2}''] + #3 + \end{fulllineitems} +} +% \seeurl{url}{why it's interesting} +\newcommand{\py@seeurl}[2]{% + \par% + \begin{fulllineitems} + \item[\url{#1}] + #2 + \end{fulllineitems} +} + +\newenvironment{seealso*}{ + \par + \def\seetext##1{\par{##1}} + \let\seemodule=\py@seemodule + \let\seepep=\py@seepep + \let\seerfc=\py@seerfc + \let\seetitle=\py@seetitle + \let\seeurl=\py@seeurl + \let\seelink=\py@seelink +}{\par} +\newenvironment{seealso}{ + \par + \strong{See Also:} + \par + \def\seetext##1{\par{##1}} + \let\seemodule=\py@seemodule + \let\seepep=\py@seepep + \let\seerfc=\py@seerfc + \let\seetitle=\py@seetitle + \let\seeurl=\py@seeurl + \let\seelink=\py@seelink +}{\par} + +% Allow the Python release number to be specified independently of the +% \date{}. This allows the date to reflect the document's date and +% release to specify the Python release that is documented. +% +\newcommand{\py@release}{} +\newcommand{\version}{} +\newcommand{\shortversion}{} +\newcommand{\releaseinfo}{} +\newcommand{\releasename}{Release} +\newcommand{\release}[1]{% + \renewcommand{\py@release}{\releasename\space\version}% + \renewcommand{\version}{#1}} +\newcommand{\setshortversion}[1]{% + \renewcommand{\shortversion}{#1}} +\newcommand{\setreleaseinfo}[1]{% + \renewcommand{\releaseinfo}{#1}} + +% Allow specification of the author's address separately from the +% author's name. This can be used to format them differently, which +% is a good thing. +% +\newcommand{\py@authoraddress}{} +\newcommand{\authoraddress}[1]{\renewcommand{\py@authoraddress}{#1}} +\let\developersaddress=\authoraddress +\let\developer=\author +\let\developers=\author + +% This sets up the fancy chapter headings that make the documents look +% at least a little better than the usual LaTeX output. +% +\@ifundefined{ChTitleVar}{}{ + \ChNameVar{\raggedleft\normalsize\py@HeaderFamily} + \ChNumVar{\raggedleft \bfseries\Large\py@HeaderFamily} + \ChTitleVar{\raggedleft \rm\Huge\py@HeaderFamily} + % This creates chapter heads without the leading \vspace*{}: + \def\@makechapterhead#1{% + {\parindent \z@ \raggedright \normalfont + \ifnum \c@secnumdepth >\m@ne + \DOCH + \fi + \interlinepenalty\@M + \DOTI{#1} + } + } +} + + +% Definition lists; requested by AMK for HOWTO documents. Probably useful +% elsewhere as well, so keep in in the general style support. +% +\newenvironment{definitions}{% + \begin{description}% + \def\term##1{\item[##1]\mbox{}\\*[0mm]} +}{% + \end{description}% +} + +% Tell TeX about pathological hyphenation cases: +\hyphenation{Base-HTTP-Re-quest-Hand-ler} diff --git a/sys/src/cmd/python/Doc/texinputs/underscore.sty b/sys/src/cmd/python/Doc/texinputs/underscore.sty new file mode 100644 index 000000000..a274b39e5 --- /dev/null +++ b/sys/src/cmd/python/Doc/texinputs/underscore.sty @@ -0,0 +1,232 @@ +% underscore.sty 12-Oct-2001 Donald Arseneau asnd@triumf.ca +% Make the "_" character print as "\textunderscore" in text. +% Copyright 1998,2001 Donald Arseneau; Distribute freely if unchanged. +% Instructions follow after the definitions. + +\ProvidesPackage{underscore}[2001/10/12] + +\begingroup + \catcode`\_=\active + \gdef_{% \relax % No relax gives a small vulnerability in alignments + \ifx\if@safe@actives\iftrue % must be outermost test! + \string_% + \else + \ifx\protect\@typeset@protect + \ifmmode \sb \else \BreakableUnderscore \fi + \else + \ifx\protect\@unexpandable@protect \noexpand_% + \else \protect_% + \fi\fi + \fi} +\endgroup + +% At begin: set catcode; fix \long \ttdefault so I can use it in comparisons; +\AtBeginDocument{% + {\immediate\write\@auxout{\catcode\number\string`\_ \string\active}}% + \catcode\string`\_\string=\active + \edef\ttdefault{\ttdefault}% +} + +\newcommand{\BreakableUnderscore}{\leavevmode\nobreak\hskip\z@skip + \ifx\f@family\ttdefault \string_\else \textunderscore\fi + \usc@dischyph\nobreak\hskip\z@skip} + +\DeclareRobustCommand{\_}{% + \ifmmode \nfss@text{\textunderscore}\else \BreakableUnderscore \fi} + +\let\usc@dischyph\@dischyph +\DeclareOption{nohyphen}{\def\usc@dischyph{\discretionary{}{}{}}} +\DeclareOption{strings}{\catcode`\_=\active} + +\ProcessOptions +\ifnum\catcode`\_=\active\else \endinput \fi + +%%%%%%%% Redefine commands that use character strings %%%%%%%% + +\@ifundefined{UnderscoreCommands}{\let\UnderscoreCommands\@empty}{} +\expandafter\def\expandafter\UnderscoreCommands\expandafter{% + \UnderscoreCommands + \do\include \do\includeonly + \do\@input \do\@iinput \do\InputIfFileExists + \do\ref \do\pageref \do\newlabel + \do\bibitem \do\@bibitem \do\cite \do\nocite \do\bibcite +} + +% Macro to redefine a macro to pre-process its string argument +% with \protect -> \string. +\def\do#1{% Avoid double processing if user includes command twice! + \@ifundefined{US\string_\expandafter\@gobble\string#1}{% + \edef\@tempb{\meaning#1}% Check if macro is just a protection shell... + \def\@tempc{\protect}% + \edef\@tempc{\meaning\@tempc\string#1\space\space}% + \ifx\@tempb\@tempc % just a shell: hook into the protected inner command + \expandafter\do + \csname \expandafter\@gobble\string#1 \expandafter\endcsname + \else % Check if macro takes an optional argument + \def\@tempc{\@ifnextchar[}% + \edef\@tempa{\def\noexpand\@tempa####1\meaning\@tempc}% + \@tempa##2##3\@tempa{##2\relax}% + \edef\@tempb{\meaning#1\meaning\@tempc}% + \edef\@tempc{\noexpand\@tempd \csname + US\string_\expandafter\@gobble\string#1\endcsname}% + \if \expandafter\@tempa\@tempb \relax 12\@tempa % then no optional arg + \@tempc #1\US@prot + \else % There is optional arg + \@tempc #1\US@protopt + \fi + \fi + }{}} + +\def\@tempd#1#2#3{\let#1#2\def#2{#3#1}} + +\def\US@prot#1#2{\let\@@protect\protect \let\protect\string + \edef\US@temp##1{##1{#2}}\restore@protect\US@temp#1} +\def\US@protopt#1{\@ifnextchar[{\US@protarg#1}{\US@prot#1}} +\def\US@protarg #1[#2]{\US@prot{{#1[#2]}}} + +\UnderscoreCommands +\let\do\relax \let\@tempd\relax % un-do + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\endinput + +underscore.sty 12-Oct-2001 Donald Arseneau + +Features: +~~~~~~~~~ +\_ prints an underscore so that the hyphenation of constituent words +is not affected and hyphenation is permitted after the underscore. +For example, "compound\_fracture" hyphenates as com- pound_- frac- ture. +If you prefer the underscore to break without a hyphen (but still with +the same rules for explicit hyphen-breaks) then use the [nohyphen] +package option. + +A simple _ acts just like \_ in text mode, but makes a subscript in +math mode: activation_energy $E_a$ + +Both forms use an underscore character if the font encoding contains +one (e.g., "\usepackage[T1]{fontenc}" or typewriter fonts in any encoding), +but they use a rule if the there is no proper character. + +Deficiencies: +~~~~~~~~~~~~~ +The skips and penalties ruin any kerning with the underscore character +(when a character is used). However, there doesn't seem to be much, if +any, such kerning in the ec fonts, and there is never any kerning with +a rule. + +You must avoid "_" in file names and in cite or ref tags, or you must use +the babel package, with its active-character controls, or you must give +the [strings] option, which attempts to redefine several commands (and +may not work perfectly). Even without the [strings] option or babel, you +can use occasional underscores like: "\include{file\string_name}". + +Option: [strings] +~~~~~~~~~~~~~~~~~ +The default operation is quite simple and needs no customization; but +you must avoid using "_" in any place where LaTeX uses an argument as +a string of characters for some control function or as a name. These +include the tags for \cite and \ref, file names for \input, \include, +and \includegraphics, environment names, counter names, and placement +parameters (like "[t]"). The problem with these contexts is that they +are `moving arguments' but LaTeX does not `switch on' the \protect +mechanism for them. + +If you need to use the underscore character in these places, the package +option [strings] is provided to redefine commands taking a string argument +so that the argument is protected (with \protect -> \string). The list +of commands is given in "\UnderscoreCommands", with "\do" before each, +covering \cite, \ref, \input, and their variants. Not included are many +commands regarding font names, everything with counter names, environment +names, page styles, and versions of \ref and \cite defined by external +packages (e.g. \vref and \citeyear). + +You can add to the list of supported commands by defining \UnderscoreCommands +before loading this package; e.g. + + \usepackage{chicago} + \newcommand{\UnderscoreCommands}{% (\cite already done) + \do\citeNP \do\citeA \do\citeANP \do\citeN \do\shortcite + \do\shortciteNP \do\shortciteA \do\shortciteANP \do\shortciteN + \do\citeyear \do\citeyearNP + } + \usepackage[strings]{underscore} + +Not all commands can be supported this way! Only commands that take a +string argument *first* can be protected. One optional argument before +the string argument is also permitted, as exemplified by \cite: both +\cite{tags} and \cite[text]{tags} are allowed. A command like +\@addtoreset which takes two counter names as arguments could not +be protected by adding it to \UnderscoreCommands. + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!! When you use the [strings] option, you must load this package !! +!! last (or nearly last). !! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +There are two reasons: 1) The redefinitions done for protection must come +after other packages define their customized versions of those commands. +2) The [strings] option requires the _ character to be activated immediately +in order for the cite and ref tags to be read properly from the .aux file +as plain strings, and this catcode setting might disrupt other packages. + +The babel package implements a protection mechanism for many commands, +and will be a complete fix for most documents without the [strings] option. +Many add-on packages are compatible with babel, so they will get the +strings protection also. However, there are several commands that are +not covered by babel, but can easily be supported by the [strings] and +\UnderscoreCommands mechanism. Beware that using both [strings] and babel +may lead to conflicts, but does appear to work (load babel last). + +Implementation Notes: +~~~~~~~~~~~~~~~~~~~~~ +The first setting of "_" to be an active character is performed in a local +group so as to not interfere with other packages. The catcode setting +is repeated with \AtBeginDocument so the definition is in effect for the +text. However, the catcode setting is repeated immediately when the +[strings] option is detected. + +The definition of the active "_" is essentially: + \ifmmode \sb \else \BreakableUnderscore \fi +where "\sb" retains the normal subscript meaning of "_" and where +"\BreakableUnderscore" is essentially "\_". The rest of the definition +handles the "\protect"ion without causing \relax to be inserted before +the character. + +\BreakableUnderscore uses "\nobreak\hskip\z@skip" to separate the +underscore from surrounding words, thus allowing TeX to hyphenate them, +but preventing free breaks around the underscore. Next, it checks the +current font family, and uses the underscore character from tt fonts or +otherwise \textunderscore (which is a character or rule depending on +the font encoding). After the underscore, it inserts a discretionary +hyphenation point as "\usc@dischyph", which is usually just "\-" +except that it still works in the tabbing environment, although it +will give "\discretionary{}{}{}" under the [nohyphen] option. After +that, another piece of non-breaking interword glue is inserted. +Ordinarily, the comparison "\ifx\f@family\ttdefault" will always fail +because \ttdefault is `long' where \f@family is not (boooo hisss), but +\ttdefault is redefined to be non-long by "\AtBeginDocument". + +The "\_" command is then defined to use "\BreakableUnderscore". + +If the [strings] option is not given, then that is all! + +Under the [strings] option, the list of special commands is processed to: +- retain the original command as \US_command (\US_ref) +- redefine the command as \US@prot\US_command for ordinary commands + (\ref -> \US@prot\US_ref) or as \US@protopt\US_command when an optional + argument is possible (\bibitem -> \US@protopt\US_bibitem). +- self-protecting commands (\cite) retain their self-protection. +Diagnosing the state of the pre-existing command is done by painful +contortions involving \meaning. + +\US@prot and \US@protopt read the argument, process it with \protect +enabled, then invoke the saved \US_command. + +Modifications: +~~~~~~~~~~~~~~ +12-Oct-2001 Babel (safe@actives) compatibility and [nohyphen] option. + +Test file integrity: ASCII 32-57, 58-126: !"#$%&'()*+,-./0123456789 +:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ diff --git a/sys/src/cmd/python/Doc/tools/anno-api.py b/sys/src/cmd/python/Doc/tools/anno-api.py new file mode 100755 index 000000000..68e2ad9ce --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/anno-api.py @@ -0,0 +1,71 @@ +#! /usr/bin/env python +"""Add reference count annotations to the Python/C API Reference.""" +__version__ = '$Revision: 17623 $' + +import getopt +import os +import sys + +import refcounts + + +PREFIX_1 = r"\begin{cfuncdesc}{PyObject*}{" +PREFIX_2 = r"\begin{cfuncdesc}{PyVarObject*}{" + + +def main(): + rcfile = os.path.join(os.path.dirname(refcounts.__file__), os.pardir, + "api", "refcounts.dat") + outfile = "-" + opts, args = getopt.getopt(sys.argv[1:], "o:r:", ["output=", "refcounts="]) + for opt, arg in opts: + if opt in ("-o", "--output"): + outfile = arg + elif opt in ("-r", "--refcounts"): + rcfile = arg + rcdict = refcounts.load(rcfile) + if outfile == "-": + output = sys.stdout + else: + output = open(outfile, "w") + if not args: + args = ["-"] + for infile in args: + if infile == "-": + input = sys.stdin + else: + input = open(infile) + while 1: + line = input.readline() + if not line: + break + prefix = None + if line.startswith(PREFIX_1): + prefix = PREFIX_1 + elif line.startswith(PREFIX_2): + prefix = PREFIX_2 + if prefix: + s = line[len(prefix):].split('}', 1)[0] + try: + info = rcdict[s] + except KeyError: + sys.stderr.write("No refcount data for %s\n" % s) + else: + if info.result_type in ("PyObject*", "PyVarObject*"): + if info.result_refs is None: + rc = "Always \NULL{}" + else: + rc = info.result_refs and "New" or "Borrowed" + rc = rc + " reference" + line = (r"\begin{cfuncdesc}[%s]{%s}{" + % (rc, info.result_type)) \ + + line[len(prefix):] + output.write(line) + if infile != "-": + input.close() + if outfile != "-": + output.close() + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/buildindex.py b/sys/src/cmd/python/Doc/tools/buildindex.py new file mode 100755 index 000000000..1bf3748f1 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/buildindex.py @@ -0,0 +1,388 @@ +#! /usr/bin/env python + +__version__ = '$Revision: 36356 $' + +import os.path +import re +import string +import sys + +from xml.sax.saxutils import quoteattr + + +bang_join = "!".join +null_join = "".join + +REPLACEMENTS = [ + # Hackish way to deal with macros replaced with simple text + (re.compile(r"\\ABC\b"), "ABC"), + (re.compile(r"\\ASCII\b"), "ASCII"), + (re.compile(r"\\Cpp\b"), "C++"), + (re.compile(r"\\EOF\b"), "EOF"), + (re.compile(r"\\NULL\b"), "NULL"), + (re.compile(r"\\POSIX\b"), "POSIX"), + (re.compile(r"\\UNIX\b"), "Unix"), + # deal with turds left over from LaTeX2HTML + (re.compile(r"<#\d+#>"), ""), + ] + +class Node: + continuation = 0 + + def __init__(self, link, str, seqno): + self.links = [link] + self.seqno = seqno + for pattern, replacement in REPLACEMENTS: + str = pattern.sub(replacement, str) + # build up the text + self.text = split_entry_text(str) + self.key = split_entry_key(str) + + def __cmp__(self, other): + """Comparison operator includes sequence number, for use with + list.sort().""" + return self.cmp_entry(other) or cmp(self.seqno, other.seqno) + + def cmp_entry(self, other): + """Comparison 'operator' that ignores sequence number.""" + c = 0 + for i in range(min(len(self.key), len(other.key))): + c = (cmp_part(self.key[i], other.key[i]) + or cmp_part(self.text[i], other.text[i])) + if c: + break + return c or cmp(self.key, other.key) or cmp(self.text, other.text) + + def __repr__(self): + return "<Node for %s (%s)>" % (bang_join(self.text), self.seqno) + + def __str__(self): + return bang_join(self.key) + + def dump(self): + return "%s\1%s###%s\n" \ + % ("\1".join(self.links), + bang_join(self.text), + self.seqno) + + +def cmp_part(s1, s2): + result = cmp(s1, s2) + if result == 0: + return 0 + l1 = s1.lower() + l2 = s2.lower() + minlen = min(len(s1), len(s2)) + if len(s1) < len(s2) and l1 == l2[:len(s1)]: + result = -1 + elif len(s2) < len(s1) and l2 == l1[:len(s2)]: + result = 1 + else: + result = cmp(l1, l2) or cmp(s1, s2) + return result + + +def split_entry(str, which): + stuff = [] + parts = str.split('!') + parts = [part.split('@') for part in parts] + for entry in parts: + if len(entry) != 1: + key = entry[which] + else: + key = entry[0] + stuff.append(key) + return stuff + + +_rmtt = re.compile(r"""(.*)<tt(?: class=['"][a-z0-9]+["'])?>(.*)</tt>(.*)$""", + re.IGNORECASE) +_rmparens = re.compile(r"\(\)") + +def split_entry_key(str): + parts = split_entry(str, 1) + for i in range(len(parts)): + m = _rmtt.match(parts[i]) + if m: + parts[i] = null_join(m.group(1, 2, 3)) + else: + parts[i] = parts[i].lower() + # remove '()' from the key: + parts[i] = _rmparens.sub('', parts[i]) + return map(trim_ignored_letters, parts) + + +def split_entry_text(str): + if '<' in str: + m = _rmtt.match(str) + if m: + str = null_join(m.group(1, 2, 3)) + return split_entry(str, 1) + + +def load(fp): + nodes = [] + rx = re.compile("(.*)\1(.*)###(.*)$") + while 1: + line = fp.readline() + if not line: + break + m = rx.match(line) + if m: + link, str, seqno = m.group(1, 2, 3) + nodes.append(Node(link, str, seqno)) + return nodes + + +def trim_ignored_letters(s): + # ignore $ to keep environment variables with the + # leading letter from the name + if s.startswith("$"): + return s[1:].lower() + else: + return s.lower() + +def get_first_letter(s): + if s.startswith("<tex2html_percent_mark>"): + return "%" + else: + return trim_ignored_letters(s)[0] + + +def split_letters(nodes): + letter_groups = [] + if nodes: + group = [] + append = group.append + letter = get_first_letter(nodes[0].text[0]) + letter_groups.append((letter, group)) + for node in nodes: + nletter = get_first_letter(node.text[0]) + if letter != nletter: + letter = nletter + group = [] + letter_groups.append((letter, group)) + append = group.append + append(node) + return letter_groups + + +def group_symbols(groups): + entries = [] + ident_letters = string.ascii_letters + "_" + while groups[0][0] not in ident_letters: + entries += groups[0][1] + del groups[0] + if entries: + groups.insert(0, ("Symbols", entries)) + + +# need a function to separate the nodes into columns... +def split_columns(nodes, columns=1): + if columns <= 1: + return [nodes] + # This is a rough height; we may have to increase to avoid breaks before + # a subitem. + colheight = int(len(nodes) / columns) + numlong = int(len(nodes) % columns) + if numlong: + colheight = colheight + 1 + else: + numlong = columns + cols = [] + for i in range(numlong): + start = i * colheight + end = start + colheight + cols.append(nodes[start:end]) + del nodes[:end] + colheight = colheight - 1 + try: + numshort = int(len(nodes) / colheight) + except ZeroDivisionError: + cols = cols + (columns - len(cols)) * [[]] + else: + for i in range(numshort): + start = i * colheight + end = start + colheight + cols.append(nodes[start:end]) + # + # If items continue across columns, make sure they are marked + # as continuations so the user knows to look at the previous column. + # + for i in range(len(cols) - 1): + try: + prev = cols[i][-1] + next = cols[i + 1][0] + except IndexError: + return cols + else: + n = min(len(prev.key), len(next.key)) + for j in range(n): + if prev.key[j] != next.key[j]: + break + next.continuation = j + 1 + return cols + + +DL_LEVEL_INDENT = " " + +def format_column(nodes): + strings = ["<dl compact='compact'>"] + append = strings.append + level = 0 + previous = [] + for node in nodes: + current = node.text + count = 0 + for i in range(min(len(current), len(previous))): + if previous[i] != current[i]: + break + count = i + 1 + if count > level: + append("<dl compact='compact'>" * (count - level) + "\n") + level = count + elif level > count: + append("\n") + append(level * DL_LEVEL_INDENT) + append("</dl>" * (level - count)) + level = count + # else: level == count + for i in range(count, len(current) - 1): + term = node.text[i] + level = level + 1 + if node.continuation > i: + extra = " (continued)" + else: + extra = "" + append("\n<dt>%s%s\n<dd>\n%s<dl compact='compact'>" + % (term, extra, level * DL_LEVEL_INDENT)) + append("\n%s<dt>%s%s</a>" + % (level * DL_LEVEL_INDENT, node.links[0], node.text[-1])) + for link in node.links[1:]: + append(",\n%s %s[Link]</a>" % (level * DL_LEVEL_INDENT, link)) + previous = current + append("\n") + append("</dl>" * (level + 1)) + return null_join(strings) + + +def format_nodes(nodes, columns=1): + strings = [] + append = strings.append + if columns > 1: + colnos = range(columns) + colheight = int(len(nodes) / columns) + if len(nodes) % columns: + colheight = colheight + 1 + colwidth = int(100 / columns) + append('<table width="100%"><tr valign="top">') + for col in split_columns(nodes, columns): + append('<td width="%d%%">\n' % colwidth) + append(format_column(col)) + append("\n</td>") + append("\n</tr></table>") + else: + append(format_column(nodes)) + return null_join(strings) + + +def format_letter(letter): + if letter == '.': + lettername = ". (dot)" + elif letter == '_': + lettername = "_ (underscore)" + else: + lettername = letter.capitalize() + return "\n<hr />\n<h2 id=%s>%s</h2>\n\n" \ + % (quoteattr("letter-" + letter), lettername) + + +def format_html_letters(nodes, columns, group_symbol_nodes): + letter_groups = split_letters(nodes) + if group_symbol_nodes: + group_symbols(letter_groups) + items = [] + for letter, nodes in letter_groups: + s = "<b><a href=\"#letter-%s\">%s</a></b>" % (letter, letter) + items.append(s) + s = ["<hr /><center>\n%s</center>\n" % " |\n".join(items)] + for letter, nodes in letter_groups: + s.append(format_letter(letter)) + s.append(format_nodes(nodes, columns)) + return null_join(s) + +def format_html(nodes, columns): + return format_nodes(nodes, columns) + + +def collapse(nodes): + """Collapse sequences of nodes with matching keys into a single node. + Destructive.""" + if len(nodes) < 2: + return + prev = nodes[0] + i = 1 + while i < len(nodes): + node = nodes[i] + if not node.cmp_entry(prev): + prev.links.append(node.links[0]) + del nodes[i] + else: + i = i + 1 + prev = node + + +def dump(nodes, fp): + for node in nodes: + fp.write(node.dump()) + + +def process_nodes(nodes, columns, letters=0, group_symbol_nodes=0): + nodes.sort() + collapse(nodes) + if letters: + return format_html_letters(nodes, columns, group_symbol_nodes) + else: + return format_html(nodes, columns) + + +def main(): + import getopt + ifn = "-" + ofn = "-" + columns = 1 + letters = 0 + group_symbol_nodes = 1 + opts, args = getopt.getopt(sys.argv[1:], "c:lo:", + ["columns=", "dont-group-symbols", + "group-symbols", "letters", "output="]) + for opt, val in opts: + if opt in ("-o", "--output"): + ofn = val + elif opt in ("-c", "--columns"): + columns = int(val, 10) + elif opt in ("-l", "--letters"): + letters = 1 + elif opt == "--group-symbols": + group_symbol_nodes = 1 + elif opt == "--dont-group-symbols": + group_symbol_nodes = 0 + if not args: + args = [ifn] + nodes = [] + for fn in args: + nodes = nodes + load(open(fn)) + num_nodes = len(nodes) + html = process_nodes(nodes, columns, letters, group_symbol_nodes) + program = os.path.basename(sys.argv[0]) + if ofn == "-": + sys.stdout.write(html) + sys.stderr.write("\n%s: %d index nodes" % (program, num_nodes)) + else: + open(ofn, "w").write(html) + print + print "%s: %d index nodes" % (program, num_nodes) + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/checkargs.pm b/sys/src/cmd/python/Doc/tools/checkargs.pm new file mode 100644 index 000000000..005d3c61f --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/checkargs.pm @@ -0,0 +1,112 @@ +#! /usr/bin/perl + +package checkargs; +require 5.004; # uses "for my $var" +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(check_args check_args_range check_args_at_least); +use strict; +use Carp; + +=head1 NAME + +checkargs -- Provide rudimentary argument checking for perl5 functions + +=head1 SYNOPSIS + + check_args(cArgsExpected, @_) + check_args_range(cArgsMin, cArgsMax, @_) + check_args_at_least(cArgsMin, @_) +where "@_" should be supplied literally. + +=head1 DESCRIPTION + +As the first line of user-written subroutine foo, do one of the following: + + my ($arg1, $arg2) = check_args(2, @_); + my ($arg1, @rest) = check_args_range(1, 4, @_); + my ($arg1, @rest) = check_args_at_least(1, @_); + my @args = check_args_at_least(0, @_); + +These functions may also be called for side effect (put a call to one +of the functions near the beginning of the subroutine), but using the +argument checkers to set the argument list is the recommended usage. + +The number of arguments and their definedness are checked; if the wrong +number are received, the program exits with an error message. + +=head1 AUTHOR + +Michael D. Ernst <F<mernst@cs.washington.edu>> + +=cut + +## Need to check that use of caller(1) really gives desired results. +## Need to give input chunk information. +## Is this obviated by Perl 5.003's declarations? Not entirely, I think. + +sub check_args ( $@ ) +{ + my ($num_formals, @args) = @_; + my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1); + if (@_ < 1) { croak "check_args needs at least 7 args, got ", scalar(@_), ": @_\n "; } + if ((!wantarray) && ($num_formals != 0)) + { croak "check_args called in scalar context"; } + # Can't use croak below here: it would only go out to caller, not its caller + my $num_actuals = @args; + if ($num_actuals != $num_formals) + { die "$file_arg:$line_arg: function $subname expected $num_formals argument", + (($num_formals == 1) ? "" : "s"), + ", got $num_actuals", + (($num_actuals == 0) ? "" : ": @args"), + "\n"; } + for my $index (0..$#args) + { if (!defined($args[$index])) + { die "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; } } + return @args; +} + +sub check_args_range ( $$@ ) +{ + my ($min_formals, $max_formals, @args) = @_; + my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1); + if (@_ < 2) { croak "check_args_range needs at least 8 args, got ", scalar(@_), ": @_"; } + if ((!wantarray) && ($max_formals != 0) && ($min_formals !=0) ) + { croak "check_args_range called in scalar context"; } + # Can't use croak below here: it would only go out to caller, not its caller + my $num_actuals = @args; + if (($num_actuals < $min_formals) || ($num_actuals > $max_formals)) + { die "$file_arg:$line_arg: function $subname expected $min_formals-$max_formals arguments, got $num_actuals", + ($num_actuals == 0) ? "" : ": @args", "\n"; } + for my $index (0..$#args) + { if (!defined($args[$index])) + { die "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; } } + return @args; +} + +sub check_args_at_least ( $@ ) +{ + my ($min_formals, @args) = @_; + my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1); + # Don't do this, because we want every sub to start with a call to check_args* + # if ($min_formals == 0) + # { die "Isn't it pointless to check for at least zero args to $subname?\n"; } + if (scalar(@_) < 1) + { croak "check_args_at_least needs at least 1 arg, got ", scalar(@_), ": @_"; } + if ((!wantarray) && ($min_formals != 0)) + { croak "check_args_at_least called in scalar context"; } + # Can't use croak below here: it would only go out to caller, not its caller + my $num_actuals = @args; + if ($num_actuals < $min_formals) + { die "$file_arg:$line_arg: function $subname expected at least $min_formals argument", + ($min_formals == 1) ? "" : "s", + ", got $num_actuals", + ($num_actuals == 0) ? "" : ": @args", "\n"; } + for my $index (0..$#args) + { if (!defined($args[$index])) + { warn "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; last; } } + return @args; +} + +1; # successful import +__END__ diff --git a/sys/src/cmd/python/Doc/tools/cklatex b/sys/src/cmd/python/Doc/tools/cklatex new file mode 100755 index 000000000..396e914c0 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/cklatex @@ -0,0 +1,26 @@ +#! /bin/sh +# -*- ksh -*- + +# This script *helps* locate lines of normal content that end in '}'; +# this is useful since LaTeX2HTML (at least the old version that we +# use) breaks on many lines that end that way. +# +# Usage: cklatex files... | less +# +# *Read* the output looking for suspicious lines! + +grep -n "[^ ]}\$" $@ | \ + grep -v '\\begin{' | \ + grep -v '\\end{' | \ + grep -v '\\input{' | \ + grep -v '\\documentclass{' | \ + grep -v '\\title{' | \ + grep -v '\\chapter{' | \ + grep -v '\\chapter\*{' | \ + grep -v '\\section{' | \ + grep -v '\\subsection{' | \ + grep -v '\\subsubsection{' | \ + grep -v '\\sectionauthor{' | \ + grep -v '\\moduleauthor{' + +exit $? diff --git a/sys/src/cmd/python/Doc/tools/cmpcsyms b/sys/src/cmd/python/Doc/tools/cmpcsyms new file mode 100755 index 000000000..55f99546e --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/cmpcsyms @@ -0,0 +1,157 @@ +#! /usr/bin/env python +from __future__ import with_statement +import errno +import os +import re +import sys +import string + +if __name__ == "__main__": + _base = sys.argv[0] +else: + _base = __file__ + +_script_home = os.path.abspath(os.path.dirname(_base)) + +srcdir = os.path.dirname(os.path.dirname(_script_home)) + +EXCLUDES = ["bitset.h", "cStringIO.h", "graminit.h", "grammar.h", + "longintrepr.h", "metagrammar.h", + "node.h", "opcode.h", "osdefs.h", "pgenheaders.h", + "py_curses.h", "parsetok.h", "symtable.h", "token.h"] + + +def list_headers(): + """Return a list of headers.""" + incdir = os.path.join(srcdir, "Include") + return [os.path.join(incdir, fn) for fn in os.listdir(incdir) + if fn.endswith(".h") and fn not in EXCLUDES] + + +def matcher(pattern): + return re.compile(pattern).search + +MATCHERS = [ + # XXX this should also deal with ctypedesc, cvardesc and cmemberdesc + matcher(r"\\begin\{cfuncdesc\}\{(?P<result>[^}]*)\}\{(?P<sym>[^}]*)\}{(?P<params>[^}]*)\}"), + matcher(r"\\cfuncline\{(?P<result>[^})]*)\}\{(?P<sym>[^}]*)\}{(?P<params>[^}]*)\}"), + ] + +def list_documented_items(): + """Return a list of everything that's already documented.""" + apidir = os.path.join(srcdir, "Doc", "api") + files = [fn for fn in os.listdir(apidir) if fn.endswith(".tex")] + L = [] + for fn in files: + fullname = os.path.join(apidir, fn) + data = open(fullname).read() + for matcher in MATCHERS: + pos = 0 + while 1: + m = matcher(data, pos) + if not m: break + pos = m.end() + sym = m.group("sym") + result = m.group("result") + params = m.group("params") + # replace all whitespace with a single one + params = " ".join(params.split()) + L.append((sym, result, params, fn)) + return L + +def normalize_type(t): + t = t.strip() + s = t.rfind("*") + if s != -1: + # strip everything after the pointer name + t = t[:s+1] + # Drop the variable name + s = t.split() + typenames = 1 + if len(s)>1 and s[0]=='unsigned' and s[1]=='int': + typenames = 2 + if len(s) > typenames and s[-1][0] in string.letters: + del s[-1] + if not s: + print "XXX", t + return "" + # Drop register + if s[0] == "register": + del s[0] + # discard all spaces + return ''.join(s) + +def compare_type(t1, t2): + t1 = normalize_type(t1) + t2 = normalize_type(t2) + if t1 == r'\moreargs' and t2 == '...': + return False + if t1 != t2: + #print "different:", t1, t2 + return False + return True + + +def compare_types(ret, params, hret, hparams): + if not compare_type(ret, hret): + return False + params = params.split(",") + hparams = hparams.split(",") + if not params and hparams == ['void']: + return True + if not hparams and params == ['void']: + return True + if len(params) != len(hparams): + return False + for p1, p2 in zip(params, hparams): + if not compare_type(p1, p2): + return False + return True + +def main(): + headers = list_headers() + documented = list_documented_items() + + lines = [] + for h in headers: + data = open(h).read() + data, n = re.subn(r"PyAPI_FUNC\(([^)]*)\)", r"\1", data) + name = os.path.basename(h) + with open(name, "w") as f: + f.write(data) + cmd = ("ctags -f - --file-scope=no --c-kinds=p --fields=S " + "-Istaticforward -Istatichere=static " + name) + with os.popen(cmd) as f: + lines.extend(f.readlines()) + os.unlink(name) + L = {} + prevsym = None + for line in lines: + if not line: + break + sym, filename, signature = line.split(None, 2) + if sym == prevsym: + continue + expr = "\^(.*)%s" % sym + m = re.search(expr, signature) + if not m: + print "Could not split",signature, "using",expr + rettype = m.group(1).strip() + m = re.search("signature:\(([^)]*)\)", signature) + if not m: + print "Could not get signature from", signature + params = m.group(1) + L[sym] = (rettype, params) + + for sym, ret, params, fn in documented: + if sym not in L: + print "No declaration for '%s'" % sym + continue + hret, hparams = L[sym] + if not compare_types(ret, params, hret, hparams): + print "Declaration error for %s (%s):" % (sym, fn) + print ret+": "+params + print hret+": "+hparams + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/custlib.py b/sys/src/cmd/python/Doc/tools/custlib.py new file mode 100644 index 000000000..15f07baf0 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/custlib.py @@ -0,0 +1,78 @@ +# Generate custlib.tex, which is a site-specific library document. + +# Phase I: list all the things that can be imported + +import glob +import os.path +import sys + +modules = {} + +for modname in sys.builtin_module_names: + modules[modname] = modname + +for dir in sys.path: + # Look for *.py files + filelist = glob.glob(os.path.join(dir, '*.py')) + for file in filelist: + path, file = os.path.split(file) + base, ext = os.path.splitext(file) + modules[base.lower()] = base + + # Look for shared library files + filelist = (glob.glob(os.path.join(dir, '*.so')) + + glob.glob(os.path.join(dir, '*.sl')) + + glob.glob(os.path.join(dir, '*.o')) ) + for file in filelist: + path, file = os.path.split(file) + base, ext = os.path.splitext(file) + if base[-6:] == 'module': + base = base[:-6] + modules[base.lower()] = base + +# Minor oddity: the types module is documented in libtypes2.tex +if modules.has_key('types'): + del modules['types'] + modules['types2'] = None + +# Phase II: find all documentation files (lib*.tex) +# and eliminate modules that don't have one. + +docs = {} +filelist = glob.glob('lib*.tex') +for file in filelist: + modname = file[3:-4] + docs[modname] = modname + +mlist = modules.keys() +mlist = filter(lambda x, docs=docs: docs.has_key(x), mlist) +mlist.sort() +mlist = map(lambda x, docs=docs: docs[x], mlist) + +modules = mlist + +# Phase III: write custlib.tex + +# Write the boilerplate +# XXX should be fancied up. +print """\documentstyle[twoside,11pt,myformat]{report} +\\title{Python Library Reference} +\\input{boilerplate} +\\makeindex % tell \\index to actually write the .idx file +\\begin{document} +\\pagenumbering{roman} +\\maketitle +\\input{copyright} +\\begin{abstract} +\\noindent This is a customized version of the Python Library Reference. +\\end{abstract} +\\pagebreak +{\\parskip = 0mm \\tableofcontents} +\\pagebreak\\pagenumbering{arabic}""" + +for modname in mlist: + print "\\input{lib%s}" % (modname,) + +# Write the end +print """\\input{custlib.ind} % Index +\\end{document}""" diff --git a/sys/src/cmd/python/Doc/tools/findcsyms b/sys/src/cmd/python/Doc/tools/findcsyms new file mode 100755 index 000000000..ac9b75425 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/findcsyms @@ -0,0 +1,136 @@ +#! /usr/bin/env python + +import errno +import os +import re +import sys + +if __name__ == "__main__": + _base = sys.argv[0] +else: + _base = __file__ + +_script_home = os.path.abspath(os.path.dirname(_base)) + +srcdir = os.path.dirname(os.path.dirname(_script_home)) + +EXCLUDES = ["bitset.h", "cStringIO.h", "graminit.h", "grammar.h", + "longintrepr.h", "metagrammar.h", + "node.h", "opcode.h", "osdefs.h", "pgenheaders.h", + "py_curses.h", "parsetok.h", "symtable.h", "token.h"] + + +def list_headers(): + """Return a list of headers.""" + incdir = os.path.join(srcdir, "Include") + return [fn for fn in os.listdir(incdir) + if fn.endswith(".h") and fn not in EXCLUDES] + + +def matcher(pattern): + return re.compile(pattern).match + +MATCHERS = [ + matcher(r"\\begin\{cfuncdesc\}\{[^{]*\}\{(?P<sym>[^{]*)\}"), + matcher(r"\\cfuncline\{[^{]*\}\{(?P<sym>[^{]*)\}"), + matcher(r"\\begin\{ctypedesc\}(\[[^{]*\])?\{(?P<sym>[^{]*)\}"), + matcher(r"\\begin\{cvardesc\}\{[^{]*\}\{(?P<sym>[^{]*)\}"), + matcher(r"\\begin\{cmemberdesc\}\{[^{]*\}\{(?P<sym>[^{]*)\}"), + matcher(r"\\cmemberline\{[^{]*\}\{(?P<sym>[^{]*)\}"), + matcher(r"\\begin\{csimplemacrodesc\}\{(?P<sym>[^{]*)\}"), + ] + + +def list_documented_items(): + """Return a list of everything that's already documented.""" + apidir = os.path.join(srcdir, "Doc", "api") + files = [fn for fn in os.listdir(apidir) if fn.endswith(".tex")] + L = [] + for fn in files: + fullname = os.path.join(apidir, fn) + for line in open(fullname): + line = line.lstrip() + if not line.startswith("\\"): + continue + for matcher in MATCHERS: + m = matcher(line) + if m: + L.append(m.group("sym")) + break + return L + +def split_documented(all, documented): + """Split the list of all symbols into documented and undocumented + categories.""" + doc = [] + undoc = [] + for t in all: + if t[0] in documented: + doc.append(t) + else: + undoc.append(t) + return doc, undoc + +def print_list(L, title=None): + """Dump a list to stdout.""" + if title: + print title + ":" + print "-" * (len(title) + 1) + w = 0 + for sym, filename in L: + w = max(w, len(sym)) + if w % 4 == 0: + w += 4 + else: + w += (4 - (w % 4)) + for sym, filename in L: + print "%-*s%s" % (w, sym, filename) + + +_spcjoin = ' '.join + +def main(): + args = sys.argv[1:] + if args: + headers = args + documented = [] + else: + os.chdir(os.path.join(srcdir, "Include")) + headers = list_headers() + documented = list_documented_items() + + cmd = ("ctags -f - --file-scope=no --c-types=dgpstux " + "-Istaticforward -Istatichere=static " + + _spcjoin(headers)) + fp = os.popen(cmd) + L = [] + prevsym = None + while 1: + line = fp.readline() + if not line: + break + sym, filename = line.split()[:2] + if sym == prevsym: + continue + if not sym.endswith("_H"): + L.append((sym, filename)) + prevsym = sym + L.sort() + fp.close() + + try: + if documented: + documented, undocumented = split_documented(L, documented) + print_list(documented, "Documented symbols") + if undocumented: + print + print_list(undocumented, "Undocumented symbols") + else: + print_list(L) + except IOError, e: + if e.errno != errno.EPIPE: + raise + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/findmodrefs b/sys/src/cmd/python/Doc/tools/findmodrefs new file mode 100755 index 000000000..8c5f93fb6 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/findmodrefs @@ -0,0 +1,63 @@ +#! /usr/bin/env python +# -*- Python -*- + +import fileinput +import getopt +import glob +import os +import re +import sys + + +declare_rx = re.compile( + r"\\declaremodule(?:\[[a-zA-Z0-9]*\]*)?{[a-zA-Z_0-9]+}{([a-zA-Z_0-9]+)}") + +module_rx = re.compile(r"\\module{([a-zA-Z_0-9]+)}") + +def main(): + try: + just_list = 0 + print_lineno = 0 + opts, args = getopt.getopt(sys.argv[1:], "ln", ["list", "number"]) + for opt, arg in opts: + if opt in ("-l", "--list"): + just_list = 1 + elif opt in ("-n", "--number"): + print_lineno = 1 + files = args + if not files: + files = glob.glob("*.tex") + files.sort() + modulename = None + for line in fileinput.input(files): + if line[:9] == r"\section{": + modulename = None + continue + if line[:16] == r"\modulesynopsys{": + continue + m = declare_rx.match(line) + if m: + modulename = m.group(1) + continue + if not modulename: + continue + m = module_rx.search(line) + if m: + name = m.group(1) + if name != modulename: + filename = fileinput.filename() + if just_list: + print filename + fileinput.nextfile() + modulename = None + elif print_lineno: + print "%s(%d):%s" \ + % (filename, fileinput.filelineno(), line[:-1]) + else: + print "%s:%s" % (filename, line[:-1]) + except KeyboardInterrupt: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/findsyms b/sys/src/cmd/python/Doc/tools/findsyms new file mode 100755 index 000000000..3b0f70991 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/findsyms @@ -0,0 +1,128 @@ +#!/usr/bin/env python + +# Released to the public domain by Skip Montanaro, 28 March 2002 + +""" +findsyms.py - try to identify undocumented symbols exported by modules + +Usage: findsyms.py librefdir + +For each lib*.tex file in the libref manual source directory, identify which +module is documented, import the module if possible, then search the LaTeX +source for the symbols global to that module. Report any that don't seem to +be documented. + +Certain exceptions are made to the list of undocumented symbols: + + * don't mention symbols in which all letters are upper case on the + assumption they are manifest constants + + * don't mention symbols that are themselves modules + + * don't mention symbols that match those exported by os, math, string, + types, or __builtin__ modules + +Finally, if a name is exported by the module but fails a getattr() lookup, +that anomaly is reported. +""" + +import __builtin__ +import getopt +import glob +import math +import os +import re +import string +import sys +import types +import warnings + +def usage(): + print >> sys.stderr, """ +usage: %s dir +where 'dir' is the Library Reference Manual source directory. +""" % os.path.basename(sys.argv[0]) + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "") + except getopt.error: + usage() + return + + if not args: + usage() + return + + libdir = args[0] + + warnings.filterwarnings("error") + + pat = re.compile(r"\\declaremodule\s*{[^}]*}\s*{([^}]*)}") + + missing = [] + filelist = glob.glob(os.path.join(libdir, "lib*.tex")) + filelist.sort() + for f in filelist: + mod = f[3:-4] + if not mod: continue + data = open(f).read() + mods = re.findall(pat, data) + if not mods: + print "No module declarations found in", f + continue + for modname in mods: + # skip special modules + if modname.startswith("__"): + continue + try: + mod = __import__(modname) + except ImportError: + missing.append(modname) + continue + except DeprecationWarning: + print "Deprecated module:", modname + continue + if hasattr(mod, "__all__"): + all = mod.__all__ + else: + all = [k for k in dir(mod) if k[0] != "_"] + mentioned = 0 + all.sort() + for name in all: + if data.find(name) == -1: + # certain names are predominantly used for testing + if name in ("main","test","_test"): + continue + # is it some sort of manifest constant? + if name.upper() == name: + continue + try: + item = getattr(mod, name) + except AttributeError: + print " ", name, "exposed, but not an attribute" + continue + # don't care about modules that might be exposed + if type(item) == types.ModuleType: + continue + # check a few modules which tend to be import *'d + isglobal = 0 + for m in (os, math, string, __builtin__, types): + if hasattr(m, name) and item == getattr(m, name): + isglobal = 1 + break + if isglobal: continue + if not mentioned: + print "Not mentioned in", modname, "docs:" + mentioned = 1 + print " ", name + if missing: + missing.sort() + print "Could not import:" + print " ", ", ".join(missing) + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + pass diff --git a/sys/src/cmd/python/Doc/tools/fix_hack b/sys/src/cmd/python/Doc/tools/fix_hack new file mode 100755 index 000000000..8dad11101 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/fix_hack @@ -0,0 +1,2 @@ +#!/bin/sh +sed -e 's/{\\ptt[ ]*\\char[ ]*'"'"'137}/_/g' <"$1" > "@$1" && mv "@$1" $1 diff --git a/sys/src/cmd/python/Doc/tools/fix_libaux.sed b/sys/src/cmd/python/Doc/tools/fix_libaux.sed new file mode 100755 index 000000000..fb33cc575 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/fix_libaux.sed @@ -0,0 +1,3 @@ +#! /bin/sed -f +s/{\\tt \\hackscore {}\\hackscore {}/\\sectcode{__/ +s/\\hackscore {}\\hackscore {}/__/ diff --git a/sys/src/cmd/python/Doc/tools/fixinfo.el b/sys/src/cmd/python/Doc/tools/fixinfo.el new file mode 100644 index 000000000..267a7e3c9 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/fixinfo.el @@ -0,0 +1,15 @@ +(defun fix-python-texinfo () + (goto-char (point-min)) + (replace-regexp "\\(@setfilename \\)\\([-a-z]*\\)$" + "\\1python-\\2.info") + (replace-string "@node Front Matter\n@chapter Abstract\n" + "@node Abstract\n@section Abstract\n") + (mark-whole-buffer) + (texinfo-master-menu 'update-all-nodes) + (save-buffer) + ) ;; fix-python-texinfo + +;; now really do it: +(find-file (car command-line-args-left)) +(fix-python-texinfo) +(kill-emacs) diff --git a/sys/src/cmd/python/Doc/tools/getpagecounts b/sys/src/cmd/python/Doc/tools/getpagecounts new file mode 100755 index 000000000..53404e747 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/getpagecounts @@ -0,0 +1,97 @@ +#! /usr/bin/env python + +"""Generate a page count report of the PostScript version of the manuals.""" + +__version__ = '$Revision: 39598 $' + +import getopt +import sys + + +class PageCounter: + def __init__(self): + self.doclist = [] + self.total = 0 + self.title_width = 0 + self.version = "" + + def add_document(self, prefix, title): + count = count_pages(prefix + ".ps") + self.doclist.append((title, prefix, count)) + self.title_width = max(self.title_width, len(title)) + self.total = self.total + count + + def dump(self): + fmt = "%%-%ds (%%s.ps, %%d pages)" % self.title_width + for item in self.doclist: + print fmt % item + print + print " Total page count: %d" % self.total + + def parse_options(self): + opts, args = getopt.getopt(sys.argv[1:], "r:", ["release="]) + assert not args + for opt, arg in opts: + if opt in ("-r", "--release"): + self.version = arg + + def run(self): + self.parse_options() + if self.version: + version = self.version[:3] + self.add_document("whatsnew" + version.replace(".", ""), + "What's New in Python " + version) + for prefix, title in [ + ("api", "Python/C API"), + ("ext", "Extending and Embedding the Python Interpreter"), + ("lib", "Python Library Reference"), + ("mac", "Macintosh Module Reference"), + ("ref", "Python Reference Manual"), + ("tut", "Python Tutorial"), + ("doc", "Documenting Python"), + ("inst", "Installing Python Modules"), + ("dist", "Distributing Python Modules"), + ]: + self.add_document(prefix, title) + print self.PREFIX + self.dump() + print self.SUFFIX + + PREFIX = """\ +This is the PostScript version of the standard Python documentation. +If you plan to print this, be aware that some of the documents are +long. It is formatted for printing on two-sided paper; if you do plan +to print this, *please* print two-sided if you have a printer capable +of it! To locate published copies of the larger manuals, or other +Python reference material, consult the Python Bookstore at: + + http://wiki.python.org/moin/PythonBooks + +The following manuals are included in this package: +""" + SUFFIX = """\ + + +If you have any questions, comments, or suggestions regarding these +documents, please send them via email to docs@python.org. +""" + +def count_pages(filename): + fp = open(filename) + count = 0 + while 1: + lines = fp.readlines(1024*40) + if not lines: + break + for line in lines: + if line[:7] == "%%Page:": + count = count + 1 + fp.close() + return count + + +def main(): + PageCounter().run() + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/getversioninfo b/sys/src/cmd/python/Doc/tools/getversioninfo new file mode 100755 index 000000000..d22c16ddc --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/getversioninfo @@ -0,0 +1,71 @@ +#! /usr/bin/env python + +import os +import re +import sys + +try: + __file__ +except NameError: + __file__ = sys.argv[0] + +tools = os.path.dirname(os.path.abspath(__file__)) +Doc = os.path.dirname(tools) +src = os.path.dirname(Doc) +patchlevel_h = os.path.join(src, "Include", "patchlevel.h") + +# This won't pick out all #defines, but it will pick up the ones we +# care about. +rx = re.compile(r"\s*#define\s+([a-zA-Z][a-zA-Z_0-9]*)\s+([a-zA-Z_0-9]+)") + +d = {} +f = open(patchlevel_h) +for line in f: + m = rx.match(line) + if m is not None: + name, value = m.group(1, 2) + d[name] = value +f.close() + +release = "%s.%s" % (d["PY_MAJOR_VERSION"], d["PY_MINOR_VERSION"]) +micro = int(d["PY_MICRO_VERSION"]) +shortversion = release +if micro != 0: + release += "." + str(micro) +level = d["PY_RELEASE_LEVEL"] + +suffixes = { + "PY_RELEASE_LEVEL_ALPHA": "a", + "PY_RELEASE_LEVEL_BETA": "b", + "PY_RELEASE_LEVEL_GAMMA": "c", + } + +releaseinfo = "" +if level != "PY_RELEASE_LEVEL_FINAL": + releaseinfo = suffixes[level] + str(int(d["PY_RELEASE_SERIAL"])) + +def write_file(name, text): + """Write text to a file if the file doesn't exist or if text + differs from any existing content.""" + if os.path.exists(name): + f = open(name, "r") + s = f.read() + f.close() + if s == text: + return + f = open(name, "w") + f.write(text) + f.close() + +patchlevel_tex = os.path.join(Doc, "commontex", "patchlevel.tex") + +write_file(patchlevel_tex, + "%% This file is generated by ../tools/getversioninfo;\n" + "%% do not edit manually.\n" + "\n" + "\\release{%s}\n" + "\\setreleaseinfo{%s}\n" + "\\setshortversion{%s}\n" + % (release, releaseinfo, shortversion)) + +print release + releaseinfo diff --git a/sys/src/cmd/python/Doc/tools/html2texi.pl b/sys/src/cmd/python/Doc/tools/html2texi.pl new file mode 100755 index 000000000..5dcfd46f0 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/html2texi.pl @@ -0,0 +1,1750 @@ +#! /usr/bin/env perl +# html2texi.pl -- Convert HTML documentation to Texinfo format +# Michael Ernst <mernst@cs.washington.edu> +# Time-stamp: <1999-01-12 21:34:27 mernst> + +# This program converts HTML documentation trees into Texinfo format. +# Given the name of a main (or contents) HTML file, it processes that file, +# and other files (transitively) referenced by it, into a Texinfo file +# (whose name is chosen from the file or directory name of the argument). +# For instance: +# html2texi.pl api/index.html +# produces file "api.texi". + +# Texinfo format can be easily converted to Info format (for browsing in +# Emacs or the standalone Info browser), to a printed manual, or to HTML. +# Thus, html2texi.pl permits conversion of HTML files to Info format, and +# secondarily enables producing printed versions of Web page hierarchies. + +# Unlike HTML, Info format is searchable. Since Info is integrated into +# Emacs, one can read documentation without starting a separate Web +# browser. Additionally, Info browsers (including Emacs) contain +# convenient features missing from Web browsers, such as easy index lookup +# and mouse-free browsing. + +# Limitations: +# html2texi.pl is currently tuned to latex2html output (and it corrects +# several latex2html bugs), but should be extensible to arbitrary HTML +# documents. It will be most useful for HTML with a hierarchical structure +# and an index, and it recognizes those features as created by latex2html +# (and possibly by some other tools). The HTML tree to be traversed must +# be on local disk, rather than being accessed via HTTP. +# This script requires the use of "checkargs.pm". To eliminate that +# dependence, replace calls to check_args* by @_ (which is always the last +# argument to those functions). +# Also see the "to do" section, below. +# Comments, suggestions, bug fixes, and enhancements are welcome. + +# Troubleshooting: +# Malformed HTML can cause this program to abort, so +# you should check your HTML files to make sure they are legal. + + +### +### Typical usage for the Python documentation: +### + +# (Actually, most of this is in a Makefile instead.) +# The resulting Info format Python documentation is currently available at +# ftp://ftp.cs.washington.edu/homes/mernst/python-info.tar.gz + +# Fix up HTML problems, eg <DT><DL COMPACT><DD> should be <DT><DL COMPACT><DD>. + +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/api/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/ext/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/lib/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/mac/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/ref/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/tut/index.html + +# Edit the generated .texi files: +# * change @setfilename to prefix "python-" +# * fix up any sectioning, such as for Abstract +# * make Texinfo menus +# * perhaps remove the @detailmenu ... @end detailmenu +# In Emacs, to do all this: +# (progn (goto-char (point-min)) (replace-regexp "\\(@setfilename \\)\\([-a-z]*\\)$" "\\1python-\\2.info") (replace-string "@node Front Matter\n@chapter Abstract\n" "@node Abstract\n@section Abstract\n") (progn (mark-whole-buffer) (texinfo-master-menu 'update-all-nodes)) (save-buffer)) + +# makeinfo api.texi +# makeinfo ext.texi +# makeinfo lib.texi +# makeinfo mac.texi +# makeinfo ref.texi +# makeinfo tut.texi + + +### +### Structure of the code +### + +# To be written... + + +### +### Design decisions +### + +# Source and destination languages +# -------------------------------- +# +# The goal is Info files; I create Texinfo, so I don't have to worry about +# the finer details of Info file creation. (I'm not even sure of its exact +# format.) +# +# Why not start from LaTeX rather than HTML? +# I could hack latex2html itself to produce Texinfo instead, or fix up +# partparse.py (which already translates LaTeX to Teinfo). +# Pros: +# * has high-level information such as index entries, original formatting +# Cons: +# * those programs are complicated to read and understand +# * those programs try to handle arbitrary LaTeX input, track catcodes, +# and more: I don't want to go to that effort. HTML isn't as powerful +# as LaTeX, so there are fewer subtleties. +# * the result wouldn't work for arbitrary HTML documents; it would be +# nice to eventually extend this program to HTML produced from Docbook, +# Frame, and more. + +# Parsing +# ------- +# +# I don't want to view the text as a linear stream; I'd rather parse the +# whole thing and then do pattern matching over the parsed representation (to +# find idioms such as indices, lists of child nodes, etc.). +# * Perl provides HTML::TreeBuilder, which does just what I want. +# * libwww-perl: http://www.linpro.no/lwp/ +# * TreeBuilder: HTML-Tree-0.51.tar.gz +# * Python Parsers, Formatters, and Writers don't really provide the right +# interface (and the version in Grail doesn't correspond to another +# distributed version, so I'm confused about which to be using). I could +# write something in Python that creates a parse tree, but why bother? + +# Other implementation language issues: +# * Python lacks variable declarations, reasonable scoping, and static +# checking tools. I've written some of the latter for myself that make +# my Perl programming a lot safer than my Python programming will be until +# I have a similar suite for that language. + + +########################################################################### +### To do +### + +# Section names: +# Fix the problem with multiple sections in a single file (eg, Abstract in +# Front Matter section). +# Deal with cross-references, as in /homes/fish/mernst/tmp/python-doc/html/ref/types.html:310 +# Index: +# Perhaps double-check that every tag mentioned in the index is found +# in the text. +# Python: email to docs@python.org, to get their feedback. +# Compare to existing lib/ Info manual +# Write the hooks into info-look; replace pyliblookup1-1.tar.gz. +# Postpass to remove extra quotation marks around typography already in +# a different font (to avoid double delimiters as in "`code'"); or +# perhaps consider using only font-based markup so that we don't get +# the extra *bold* and `code' markup in Info. + +## Perhaps don't rely on automatic means for adding up, next, prev; I have +## all that info available to me already, so it's not so much trouble to +## add it. (Right?) But it is *so* easy to use Emacs instead... + + +########################################################################### +### Strictures +### + +# man HTML::TreeBuilder +# man HTML::Parser +# man HTML::Element + +# require HTML::ParserWComment; +require HTML::Parser; +require HTML::TreeBuilder; +require HTML::Element; + +use File::Basename; + +use strict; +# use Carp; + +use checkargs; + + +########################################################################### +### Variables +### + +my @section_stack = (); # elements are chapter/section/subsec nodetitles (I think) +my $current_ref_tdf; # for the file currently being processed; + # used in error messages +my $html_directory; +my %footnotes; + +# First element should not be used. +my @sectionmarker = ("manual", "chapter", "section", "subsection", "subsubsection"); + +my %inline_markup = ("b" => "strong", + "code" => "code", + "i" => "emph", + "kbd" => "kbd", + "samp" => "samp", + "strong" => "strong", + "tt" => "code", + "var" => "var"); + +my @deferred_index_entries = (); + +my @index_titles = (); # list of (filename, type) lists +my %index_info = ("Index" => ["\@blindex", "bl"], + "Concept Index" => ["\@cindex", "cp"], + "Module Index" => ["\@mdindex", "md"]); + + +########################################################################### +### Main/contents page +### + +# Process first-level page on its own, or just a contents page? Well, I do +# want the title, author, etc., and the front matter... For now, just add +# that by hand at the end. + + +# data structure possibilities: +# * tree-like (need some kind of stack when processing (or parent pointers)) +# * list of name and depth; remember old and new depths. + +# Each element is a reference to a list of (nodetitle, depth, filename). +my @contents_list = (); + +# The problem with doing fixups on the fly is that some sections may have +# already been processed (and no longer available) by the time we notice +# others with the same name. It's probably better to fully construct the +# contents list (reading in all files of interest) upfront; that will also +# let me do a better job with cross-references, because again, all files +# will already be read in. +my %contents_hash = (); +my %contents_fixups = (); + +my @current_contents_list = (); + +# Merge @current_contents_list into @contents_list, +# and set @current_contents_list to be empty. +sub merge_contents_lists ( ) +{ check_args(0, @_); + + # Three possibilities: + # * @contents_list is empty: replace it by @current_contents_list. + # * prefixes of the two lists are identical: do nothing + # * @current_contents_list is all at lower level than $contents_list[0]; + # prefix @contents_list by @current_contents_list + + if (scalar(@current_contents_list) == 0) + { die "empty current_contents_list"; } + + # if (scalar(@contents_list) == 0) + # { @contents_list = @current_contents_list; + # @current_contents_list = (); + # return; } + + # if (($ {$contents_list[0]}[1]) < ($ {$current_contents_list[0]}[1])) + # { unshift @contents_list, @current_contents_list; + # @current_contents_list = (); + # return; } + + for (my $i=0; $i<scalar(@current_contents_list); $i++) + { my $ref_c_tdf = $current_contents_list[$i]; + if ($i >= scalar(@contents_list)) + { push @contents_list, $ref_c_tdf; + my $title = $ {$ref_c_tdf}[0]; + if (defined $contents_hash{$title}) + { $contents_fixups{$title} = 1; } + else + { $contents_hash{$title} = 1; } + next; } + my $ref_tdf = $contents_list[$i]; + my ($title, $depth, $file) = @{$ref_tdf}; + my ($c_title, $c_depth, $c_file) = @{$ref_c_tdf}; + + if (($title ne $c_title) + && ($depth < $c_depth) + && ($file ne $c_file)) + { splice @contents_list, $i, 0, $ref_c_tdf; + if (defined $contents_hash{$c_title}) + { $contents_fixups{$c_title} = 1; } + else + { $contents_hash{$c_title} = 1; } + next; } + + if (($title ne $c_title) + || ($depth != $c_depth) + || ($file ne $c_file)) + { die ("while processing $ {$current_ref_tdf}[2] at depth $ {$current_ref_tdf}[1], mismatch at index $i:", + "\n main: <<<$title>>> $depth $file", + "\n curr: <<<$c_title>>> $c_depth $c_file"); } + } + @current_contents_list = (); +} + + + +# Set @current_contents_list to a list of (title, href, sectionlevel); +# then merge that list into @contents_list. +# Maybe this function should also produce a map +# from title (or href) to sectionlevel (eg "chapter"?). +sub process_child_links ( $ ) +{ my ($he) = check_args(1, @_); + + # $he->dump(); + if (scalar(@current_contents_list) != 0) + { die "current_contents_list nonempty: @current_contents_list"; } + $he->traverse(\&increment_current_contents_list, 'ignore text'); + + # Normalize the depths; for instance, convert 1,3,5 into 0,1,2. + my %depths = (); + for my $ref_tdf (@current_contents_list) + { $depths{$ {$ref_tdf}[1]} = 1; } + my @sorted_depths = sort keys %depths; + my $current_depth = scalar(@section_stack)-1; + my $current_depth_2 = $ {$current_ref_tdf}[1]; + if ($current_depth != $current_depth_2) + { die "mismatch in current depths: $current_depth $current_depth_2; ", join(", ", @section_stack); } + for (my $i=0; $i<scalar(@sorted_depths); $i++) + { $depths{$sorted_depths[$i]} = $i + $current_depth+1; } + for my $ref_tdf (@current_contents_list) + { $ {$ref_tdf}[1] = $depths{$ {$ref_tdf}[1]}; } + + # Eliminate uninteresting sections. Hard-coded hack for now. + if ($ {$current_contents_list[-1]}[0] eq "About this document ...") + { pop @current_contents_list; } + if ((scalar(@current_contents_list) > 1) + && ($ {$current_contents_list[1]}[0] eq "Contents")) + { my $ref_first_tdf = shift @current_contents_list; + $current_contents_list[0] = $ref_first_tdf; } + + for (my $i=0; $i<scalar(@current_contents_list); $i++) + { my $ref_tdf = $current_contents_list[$i]; + my $title = $ {$ref_tdf}[0]; + if (exists $index_info{$title}) + { my $index_file = $ {$ref_tdf}[2]; + my ($indexing_command, $suffix) = @{$index_info{$title}}; + process_index_file($index_file, $indexing_command); + print TEXI "\n\@defindex $suffix\n"; + push @index_titles, $title; + splice @current_contents_list, $i, 1; + $i--; } + elsif ($title =~ /\bIndex$/) + { print STDERR "Warning: \"$title\" might be an index; if so, edit \%index_info.\n"; } } + + merge_contents_lists(); + + # print_contents_list(); + # print_index_info(); +} + + +sub increment_current_contents_list ( $$$ ) +{ my ($he, $startflag, $depth) = check_args(3, @_); + if (!$startflag) + { return; } + + if ($he->tag eq "li") + { my @li_content = @{$he->content}; + if ($li_content[0]->tag ne "a") + { die "first element of <LI> should be <A>"; } + my ($name, $href, @content) = anchor_info($li_content[0]); + # unused $name + my $title = join("", collect_texts($li_content[0])); + $title = texi_remove_punctuation($title); + # The problem with these is that they are formatted differently in + # @menu and @node! + $title =~ s/``/\"/g; + $title =~ s/''/\"/g; + $title =~ s/ -- / /g; + push @current_contents_list, [ $title, $depth, $href ]; } + return 1; +} + +# Simple version for section titles +sub html_to_texi ( $ ) +{ my ($he) = check_args(1, @_); + if (!ref $he) + { return $he; } + + my $tag = $he->tag; + if (exists $inline_markup{$tag}) + { my $result = "\@$inline_markup{$tag}\{"; + for my $elt (@{$he->content}) + { $result .= html_to_texi($elt); } + $result .= "\}"; + return $result; } + else + { $he->dump(); + die "html_to_texi confused by <$tag>"; } +} + + + +sub print_contents_list () +{ check_args(0, @_); + print STDERR "Contents list:\n"; + for my $ref_tdf (@contents_list) + { my ($title, $depth, $file) = @{$ref_tdf}; + print STDERR "$title $depth $file\n"; } +} + + + +########################################################################### +### Index +### + +my $l2h_broken_link_name = "l2h-"; + + +# map from file to (map from anchor name to (list of index texts)) +# (The list is needed when a single LaTeX command like \envvar +# expands to multiple \index commands.) +my %file_index_entries = (); +my %this_index_entries; # map from anchor name to (list of index texts) + +my %file_index_entries_broken = (); # map from file to (list of index texts) +my @this_index_entries_broken; + +my $index_prefix = ""; +my @index_prefixes = (); + +my $this_indexing_command; + +sub print_index_info () +{ check_args(0, @_); + my ($key, $val); + for my $file (sort keys %file_index_entries) + { my %index_entries = %{$file_index_entries{$file}}; + print STDERR "file: $file\n"; + for my $aname (sort keys %index_entries) + { my @entries = @{$index_entries{$aname}}; + if (scalar(@entries) == 1) + { print STDERR " $aname : $entries[0]\n"; } + else + { print STDERR " $aname : ", join("\n " . (" " x length($aname)), @entries), "\n"; } } } + for my $file (sort keys %file_index_entries_broken) + { my @entries = @{$file_index_entries_broken{$file}}; + print STDERR "file: $file\n"; + for my $entry (@entries) + { print STDERR " $entry\n"; } + } +} + + +sub process_index_file ( $$ ) +{ my ($file, $indexing_command) = check_args(2, @_); + # print "process_index_file $file $indexing_command\n"; + + my $he = file_to_tree($html_directory . $file); + # $he->dump(); + + $this_indexing_command = $indexing_command; + $he->traverse(\&process_if_index_dl_compact, 'ignore text'); + undef $this_indexing_command; + # print "process_index_file done\n"; +} + + +sub process_if_index_dl_compact ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if (($he->tag() eq "dl") && (defined $he->attr('compact'))) + { process_index_dl_compact($he); + return 0; } + else + { return 1; } +} + + +# The elements of a <DL COMPACT> list from a LaTeX2HTML index: +# * a single space: text to be ignored +# * <DT> elements with an optional <DD> element following each one +# Two types of <DT> elements: +# * Followed by a <DD> element: the <DT> contains a single +# string, and the <DD> contains a whitespace string to be ignored, a +# <DL COMPACT> to be recursively processed (with the <DT> string as a +# prefix), and a whitespace string to be ignored. +# * Not followed by a <DD> element: contains a list of anchors +# and texts (ignore the texts, which are only whitespace and commas). +# Optionally contains a <DL COMPACT> to be recursively processed (with +# the <DT> string as a prefix) +sub process_index_dl_compact ( $ ) +{ my ($h) = check_args(1, @_); + my @content = @{$h->content()}; + for (my $i = 0; $i < scalar(@content); $i++) + { my $this_he = $content[$i]; + if ($this_he->tag ne "dt") + { $this_he->dump(); + die "Expected <DT> tag: " . $this_he->tag; } + if (($i < scalar(@content) - 1) && ($content[$i+1]->tag eq "dd")) + { process_index_dt_and_dd($this_he, $content[$i+1]); + $i++; } + else + { process_index_lone_dt($this_he); } } } + + + +# Argument is a <DT> element. If it contains more than one anchor, then +# the texts of all subsequent ones are "[Link]". Example: +# <DT> +# <A HREF="embedding.html#l2h-201"> +# "$PATH" +# ", " +# <A HREF="embedding.html#l2h-205"> +# "[Link]" +# Optionally contains a <DL COMPACT> as well. Example: +# <DT> +# <A HREF="types.html#l2h-616"> +# "attribute" +# <DL COMPACT> +# <DT> +# <A HREF="assignment.html#l2h-3074"> +# "assignment" +# ", " +# <A HREF="assignment.html#l2h-3099"> +# "[Link]" +# <DT> +# <A HREF="types.html#l2h-"> +# "assignment, class" + +sub process_index_lone_dt ( $ ) +{ my ($dt) = check_args(1, @_); + my @dtcontent = @{$dt->content()}; + my $acontent; + my $acontent_suffix; + for my $a (@dtcontent) + { if ($a eq ", ") + { next; } + if (!ref $a) + { $dt->dump; + die "Unexpected <DT> string element: $a"; } + + if ($a->tag eq "dl") + { push @index_prefixes, $index_prefix; + if (!defined $acontent_suffix) + { die "acontent_suffix not yet defined"; } + $index_prefix .= $acontent_suffix . ", "; + process_index_dl_compact($a); + $index_prefix = pop(@index_prefixes); + return; } + + if ($a->tag ne "a") + { $dt->dump; + $a->dump; + die "Expected anchor in lone <DT>"; } + + my ($aname, $ahref, @acontent) = anchor_info($a); + # unused $aname + if (scalar(@acontent) != 1) + { die "Expected just one content of <A> in <DT>: @acontent"; } + if (ref $acontent[0]) + { $acontent[0]->dump; + die "Expected string content of <A> in <DT>: $acontent[0]"; } + if (!defined($acontent)) + { $acontent = $index_prefix . $acontent[0]; + $acontent_suffix = $acontent[0]; } + elsif (($acontent[0] ne "[Link]") && ($acontent ne ($index_prefix . $acontent[0]))) + { die "Differing content: <<<$acontent>>>, <<<$acontent[0]>>>"; } + + if (!defined $ahref) + { $dt->dump; + die "no HREF in nachor in <DT>"; } + my ($ahref_file, $ahref_name) = split(/\#/, $ahref); + if (!defined $ahref_name) + { # Reference to entire file + $ahref_name = ""; } + + if ($ahref_name eq $l2h_broken_link_name) + { if (!exists $file_index_entries_broken{$ahref_file}) + { $file_index_entries_broken{$ahref_file} = []; } + push @{$file_index_entries_broken{$ahref_file}}, "$this_indexing_command $acontent"; + next; } + + if (!exists $file_index_entries{$ahref_file}) + { $file_index_entries{$ahref_file} = {}; } + # Don't do this! It appears to make a copy, which is not desired. + # my %index_entries = %{$file_index_entries{$ahref_file}}; + if (!exists $ {$file_index_entries{$ahref_file}}{$ahref_name}) + { $ {$file_index_entries{$ahref_file}}{$ahref_name} = []; } + # { my $oldcontent = $ {$file_index_entries{$ahref_file}}{$ahref_name}; + # if ($acontent eq $oldcontent) + # { die "Multiple identical index entries?"; } + # die "Trying to add $acontent, but already have index entry pointing at $ahref_file\#$ahref_name: ${$file_index_entries{$ahref_file}}{$ahref_name}"; } + + push @{$ {$file_index_entries{$ahref_file}}{$ahref_name}}, "$this_indexing_command $acontent"; + # print STDERR "keys: ", keys %{$file_index_entries{$ahref_file}}, "\n"; + } +} + +sub process_index_dt_and_dd ( $$ ) +{ my ($dt, $dd) = check_args(2, @_); + my $dtcontent; + { my @dtcontent = @{$dt->content()}; + if ((scalar(@dtcontent) != 1) || (ref $dtcontent[0])) + { $dd->dump; + $dt->dump; + die "Expected single string (actual size = " . scalar(@dtcontent) . ") in content of <DT>: @dtcontent"; } + $dtcontent = $dtcontent[0]; + $dtcontent =~ s/ +$//; } + my $ddcontent; + { my @ddcontent = @{$dd->content()}; + if (scalar(@ddcontent) != 1) + { die "Expected single <DD> content, got ", scalar(@ddcontent), " elements:\n", join("\n", @ddcontent), "\n "; } + $ddcontent = $ddcontent[0]; } + if ($ddcontent->tag ne "dl") + { die "Expected <DL> as content of <DD>, but saw: $ddcontent"; } + + push @index_prefixes, $index_prefix; + $index_prefix .= $dtcontent . ", "; + process_index_dl_compact($ddcontent); + $index_prefix = pop(@index_prefixes); +} + + +########################################################################### +### Ordinary sections +### + +sub process_section_file ( $$$ ) +{ my ($file, $depth, $nodetitle) = check_args(3, @_); + my $he = file_to_tree(($file =~ /^\//) ? $file : $html_directory . $file); + + # print STDERR "process_section_file: $file $depth $nodetitle\n"; + + # Equivalently: + # while ($depth >= scalar(@section_stack)) { pop(@section_stack); } + @section_stack = @section_stack[0..$depth-1]; + + # Not a great nodename fixup scheme; need a more global view + if ((defined $contents_fixups{$nodetitle}) + && (scalar(@section_stack) > 0)) + { my $up_title = $section_stack[$#section_stack]; + # hack for Python Standard Library + $up_title =~ s/^(Built-in|Standard) Module //g; + my ($up_first_word) = split(/ /, $up_title); + $nodetitle = "$up_first_word $nodetitle"; + } + + push @section_stack, $nodetitle; + # print STDERR "new section_stack: ", join(", ", @section_stack), "\n"; + + $he->traverse(\&process_if_child_links, 'ignore text'); + %footnotes = (); + # $he->dump; + $he->traverse(\&process_if_footnotes, 'ignore text'); + + # $he->dump; + + if (exists $file_index_entries{$file}) + { %this_index_entries = %{$file_index_entries{$file}}; + # print STDERR "this_index_entries:\n ", join("\n ", keys %this_index_entries), "\n"; + } + else + { # print STDERR "Warning: no index entries for file $file\n"; + %this_index_entries = (); } + + if (exists $file_index_entries_broken{$file}) + { @this_index_entries_broken = @{$file_index_entries_broken{$file}}; } + else + { # print STDERR "Warning: no index entries for file $file\n"; + @this_index_entries_broken = (); } + + + if ($he->tag() ne "html") + { die "Expected <HTML> at top level"; } + my @content = @{$he->content()}; + if ((!ref $content[0]) or ($content[0]->tag ne "head")) + { $he->dump; + die "<HEAD> not first element of <HTML>"; } + if ((!ref $content[1]) or ($content[1]->tag ne "body")) + { $he->dump; + die "<BODY> not second element of <HTML>"; } + + $content[1]->traverse(\&output_body); +} + +# stack of things we're inside that are preventing indexing from occurring now. +# These are "h1", "h2", "h3", "h4", "h5", "h6", "dt" (and possibly others?) +my @index_deferrers = (); + +sub push_or_pop_index_deferrers ( $$ ) +{ my ($tag, $startflag) = check_args(2, @_); + if ($startflag) + { push @index_deferrers, $tag; } + else + { my $old_deferrer = pop @index_deferrers; + if ($tag ne $old_deferrer) + { die "Expected $tag at top of index_deferrers but saw $old_deferrer; remainder = ", join(" ", @index_deferrers); } + do_deferred_index_entries(); } +} + + +sub label_add_index_entries ( $;$ ) +{ my ($label, $he) = check_args_range(1, 2, @_); + # print ((exists $this_index_entries{$label}) ? "*" : " "), " label_add_index_entries $label\n"; + # $he is the anchor element + if (exists $this_index_entries{$label}) + { push @deferred_index_entries, @{$this_index_entries{$label}}; + return; } + + if ($label eq $l2h_broken_link_name) + { # Try to find some text to use in guessing which links should point here + # I should probably only look at the previous element, or if that is + # all punctuation, the one before it; collecting all the previous texts + # is a bit of overkill. + my @anchor_texts = collect_texts($he); + my @previous_texts = collect_texts($he->parent, $he); + # 4 elements is arbitrary; ought to filter out punctuation and small words + # first, then perhaps keep fewer. Perhaps also filter out formatting so + # that we can see a larger chunk of text? (Probably not.) + # Also perhaps should do further chunking into words, in case the + # index term isn't a chunk of its own (eg, was in <tt>...</tt>. + my @candidate_texts = (@anchor_texts, (reverse(@previous_texts))[0..min(3,$#previous_texts)]); + + my $guessed = 0; + for my $text (@candidate_texts) + { # my $orig_text = $text; + if ($text =~ /^[\"\`\'().?! ]*$/) + { next; } + if (length($text) <= 2) + { next; } + # hack for Python manual; maybe defer until failure first time around? + $text =~ s/^sys\.//g; + for my $iterm (@this_index_entries_broken) + { # I could test for zero: LaTeX2HTML's failures in the Python + # documentation are only for items of the form "... (built-in...)" + if (index($iterm, $text) != -1) + { push @deferred_index_entries, $iterm; + # print STDERR "Guessing index term `$iterm' for text `$orig_text'\n"; + $guessed = 1; + } } } + if (!$guessed) + { # print STDERR "No guess in `", join("'; `", @this_index_entries_broken), "' for texts:\n `", join("'\n `", @candidate_texts), "'\n"; + } + } +} + + +# Need to add calls to this at various places. +# Perhaps add HTML::Element argument and do the check for appropriateness +# here (ie, no action if inside <H1>, etc.). +sub do_deferred_index_entries () +{ check_args(0, @_); + if ((scalar(@deferred_index_entries) > 0) + && (scalar(@index_deferrers) == 0)) + { print TEXI "\n", join("\n", @deferred_index_entries), "\n"; + @deferred_index_entries = (); } +} + +my $table_columns; # undefined if not in a table +my $table_first_column; # boolean + +sub output_body ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + + if (!ref $he) + { my $space_index = index($he, " "); + if ($space_index != -1) + { # Why does + # print TEXI texi_quote(substr($he, 0, $space_index+1)); + # give: Can't locate object method "TEXI" via package "texi_quote" + # (Because the definition texi_quote hasn't been seen yet.) + print TEXI &texi_quote(substr($he, 0, $space_index+1)); + do_deferred_index_entries(); + print TEXI &texi_quote(substr($he, $space_index+1)); } + else + { print TEXI &texi_quote($he); } + return; } + + my $tag = $he->tag(); + + # Ordinary text markup first + if (exists $inline_markup{$tag}) + { if ($startflag) + { print TEXI "\@$inline_markup{$tag}\{"; } + else + { print TEXI "\}"; } } + elsif ($tag eq "a") + { my ($name, $href, @content) = anchor_info($he); + if (!$href) + { # This anchor is only here for indexing/cross referencing purposes. + if ($startflag) + { label_add_index_entries($name, $he); } + } + elsif ($href =~ "^(ftp|http|news):") + { if ($startflag) + { # Should avoid second argument if it's identical to the URL. + print TEXI "\@uref\{$href, "; } + else + { print TEXI "\}"; } + } + elsif ($href =~ /^\#(foot[0-9]+)$/) + { # Footnote + if ($startflag) + { # Could double-check name and content, but I'm not + # currently storing that information. + print TEXI "\@footnote\{"; + $footnotes{$1}->traverse(\&output_body); + print TEXI "\}"; + return 0; } } + else + { if ($startflag) + { # cross-references are not active Info links, but no text is lost + print STDERR "Can't deal with internal HREF anchors yet:\n"; + $he->dump; } + } + } + elsif ($tag eq "br") + { print TEXI "\@\n"; } + elsif ($tag eq "body") + { } + elsif ($tag eq "center") + { if (has_single_content_string($he) + && ($ {$he->content}[0] =~ /^ *$/)) + { return 0; } + if ($startflag) + { print TEXI "\n\@center\n"; } + else + { print TEXI "\n\@end center\n"; } + } + elsif ($tag eq "div") + { my $align = $he->attr('align'); + if (defined($align) && ($align eq "center")) + { if (has_single_content_string($he) + && ($ {$he->content}[0] =~ /^ *$/)) + { return 0; } + if ($startflag) + { print TEXI "\n\@center\n"; } + else + { print TEXI "\n\@end center\n"; } } + } + elsif ($tag eq "dl") + { # Recognize "<dl><dd><pre> ... </pre></dl>" paradigm for "@example" + if (has_single_content_with_tag($he, "dd")) + { my $he_dd = $ {$he->content}[0]; + if (has_single_content_with_tag($he_dd, "pre")) + { my $he_pre = $ {$he_dd->content}[0]; + print_pre($he_pre); + return 0; } } + if ($startflag) + { # Could examine the elements, to be cleverer about formatting. + # (Also to use ftable, vtable...) + print TEXI "\n\@table \@asis\n"; } + else + { print TEXI "\n\@end table\n"; } + } + elsif ($tag eq "dt") + { push_or_pop_index_deferrers($tag, $startflag); + if ($startflag) + { print TEXI "\n\@item "; } + else + { } } + elsif ($tag eq "dd") + { if ($startflag) + { print TEXI "\n"; } + else + { } + if (scalar(@index_deferrers) != 0) + { $he->dump; + die "Unexpected <$tag> while inside: (" . join(" ", @index_deferrers) . "); bad HTML?"; } + do_deferred_index_entries(); + } + elsif ($tag =~ /^(font|big|small)$/) + { # Do nothing for now. + } + elsif ($tag =~ /^h[1-6]$/) + { # We don't need this because we never recursively enter the heading content. + # push_or_pop_index_deferrers($tag, $startflag); + my $secname = ""; + my @seclabels = (); + for my $elt (@{$he->content}) + { if (!ref $elt) + { $secname .= $elt; } + elsif ($elt->tag eq "br") + { } + elsif ($elt->tag eq "a") + { my ($name, $href, @acontent) = anchor_info($elt); + if ($href) + { $he->dump; + $elt->dump; + die "Nonsimple anchor in <$tag>"; } + if (!defined $name) + { die "No NAME for anchor in $tag"; } + push @seclabels, $name; + for my $subelt (@acontent) + { $secname .= html_to_texi($subelt); } } + else + { $secname .= html_to_texi($elt); } } + if ($secname eq "") + { die "No section name in <$tag>"; } + if (scalar(@section_stack) == 1) + { if ($section_stack[-1] ne "Top") + { die "Not top? $section_stack[-1]"; } + print TEXI "\@settitle $secname\n"; + print TEXI "\@c %**end of header\n"; + print TEXI "\n"; + print TEXI "\@node Top\n"; + print TEXI "\n"; } + else + { print TEXI "\n\@node $section_stack[-1]\n"; + print TEXI "\@$sectionmarker[scalar(@section_stack)-1] ", texi_remove_punctuation($secname), "\n"; } + for my $seclabel (@seclabels) + { label_add_index_entries($seclabel); } + # This should only happen once per file. + label_add_index_entries(""); + if (scalar(@index_deferrers) != 0) + { $he->dump; + die "Unexpected <$tag> while inside: (" . join(" ", @index_deferrers) . "); bad HTML?"; } + do_deferred_index_entries(); + return 0; + } + elsif ($tag eq "hr") + { } + elsif ($tag eq "ignore") + { # Hack for ignored elements + return 0; + } + elsif ($tag eq "li") + { if ($startflag) + { print TEXI "\n\n\@item\n"; + do_deferred_index_entries(); } } + elsif ($tag eq "ol") + { if ($startflag) + { print TEXI "\n\@enumerate \@bullet\n"; } + else + { print TEXI "\n\@end enumerate\n"; } } + elsif ($tag eq "p") + { if ($startflag) + { print TEXI "\n\n"; } + if (scalar(@index_deferrers) != 0) + { $he->dump; + die "Unexpected <$tag> while inside: (" . join(" ", @index_deferrers) . "); bad HTML?"; } + do_deferred_index_entries(); } + elsif ($tag eq "pre") + { print_pre($he); + return 0; } + elsif ($tag eq "table") + { # Could also indicate common formatting for first column, or + # determine relative widths for columns (or determine a prototype row) + if ($startflag) + { if (defined $table_columns) + { $he->dump; + die "Can't deal with table nested inside $table_columns-column table"; } + $table_columns = table_columns($he); + if ($table_columns < 2) + { $he->dump; + die "Column with $table_columns columns?"; } + elsif ($table_columns == 2) + { print TEXI "\n\@table \@asis\n"; } + else + { print TEXI "\n\@multitable \@columnfractions"; + for (my $i=0; $i<$table_columns; $i++) + { print TEXI " ", 1.0/$table_columns; } + print TEXI "\n"; } } + else + { if ($table_columns == 2) + { print TEXI "\n\@end table\n"; } + else + { print TEXI "\n\@end multitable\n"; } + undef $table_columns; } } + elsif (($tag eq "td") || ($tag eq "th")) + { if ($startflag) + { if ($table_first_column) + { print TEXI "\n\@item "; + $table_first_column = 0; } + elsif ($table_columns > 2) + { print TEXI "\n\@tab "; } } + else + { print TEXI "\n"; } } + elsif ($tag eq "tr") + { if ($startflag) + { $table_first_column = 1; } } + elsif ($tag eq "ul") + { if ($startflag) + { print TEXI "\n\@itemize \@bullet\n"; } + else + { print TEXI "\n\@end itemize\n"; } } + else + { # I used to have a newline before "output_body" here. + print STDERR "output_body: ignoring <$tag> tag\n"; + $he->dump; + return 0; } + + return 1; +} + +sub print_pre ( $ ) +{ my ($he_pre) = check_args(1, @_); + if (!has_single_content_string($he_pre)) + { die "Multiple or non-string content for <PRE>: ", @{$he_pre->content}; } + my $pre_content = $ {$he_pre->content}[0]; + print TEXI "\n\@example"; + print TEXI &texi_quote($pre_content); + print TEXI "\@end example\n"; +} + +sub table_columns ( $ ) +{ my ($table) = check_args(1, @_); + my $result = 0; + for my $row (@{$table->content}) + { if ($row->tag ne "tr") + { $table->dump; + $row->dump; + die "Expected <TR> as table row."; } + $result = max($result, scalar(@{$row->content})); } + return $result; +} + + +########################################################################### +### Utilities +### + +sub min ( $$ ) +{ my ($x, $y) = check_args(2, @_); + return ($x < $y) ? $x : $y; +} + +sub max ( $$ ) +{ my ($x, $y) = check_args(2, @_); + return ($x > $y) ? $x : $y; +} + +sub file_to_tree ( $ ) +{ my ($file) = check_args(1, @_); + + my $tree = new HTML::TreeBuilder; + $tree->ignore_unknown(1); + # $tree->warn(1); + $tree->parse_file($file); + cleanup_parse_tree($tree); + return $tree +} + + +sub has_single_content ( $ ) +{ my ($he) = check_args(1, @_); + if (!ref $he) + { # return 0; + die "Non-reference argument: $he"; } + my $ref_content = $he->content; + if (!defined $ref_content) + { return 0; } + my @content = @{$ref_content}; + if (scalar(@content) != 1) + { return 0; } + return 1; +} + + +# Return true if the content of the element contains only one element itself, +# and that inner element has the specified tag. +sub has_single_content_with_tag ( $$ ) +{ my ($he, $tag) = check_args(2, @_); + if (!has_single_content($he)) + { return 0; } + my $content = $ {$he->content}[0]; + if (!ref $content) + { return 0; } + my $content_tag = $content->tag; + if (!defined $content_tag) + { return 0; } + return $content_tag eq $tag; +} + +sub has_single_content_string ( $ ) +{ my ($he) = check_args(1, @_); + if (!has_single_content($he)) + { return 0; } + my $content = $ {$he->content}[0]; + if (ref $content) + { return 0; } + return 1; +} + + +# Return name, href, content. First two may be undefined; third is an array. +# I don't see how to determine if there are more attributes. +sub anchor_info ( $ ) +{ my ($he) = check_args(1, @_); + if ($he->tag ne "a") + { $he->dump; + die "passed non-anchor to anchor_info"; } + my $name = $he->attr('name'); + my $href = $he->attr('href'); + my @content = (); + { my $ref_content = $he->content; + if (defined $ref_content) + { @content = @{$ref_content}; } } + return ($name, $href, @content); +} + + +sub texi_quote ( $ ) +{ my ($text) = check_args(1, @_); + $text =~ s/([\@\{\}])/\@$1/g; + $text =~ s/ -- / --- /g; + return $text; +} + +# Eliminate bad punctuation (that confuses Makeinfo or Info) for section titles. +sub texi_remove_punctuation ( $ ) +{ my ($text) = check_args(1, @_); + + $text =~ s/^ +//g; + $text =~ s/[ :]+$//g; + $text =~ s/^[1-9][0-9.]* +//g; + $text =~ s/,//g; + # Both embedded colons and " -- " confuse makeinfo. (Perhaps " -- " + # gets converted into " - ", just as "---" would be converted into " -- ", + # so the names end up differing.) + # $text =~ s/:/ -- /g; + $text =~ s/://g; + return $text; +} + + +## Do not use this inside `traverse': it throws off the traversal. Use +## html_replace_by_ignore or html_replace_by_meta instead. +# Returns 1 if success, 0 if failure. +sub html_remove ( $;$ ) +{ my ($he, $parent) = check_args_range(1, 2, @_); + if (!defined $parent) + { $parent = $he->parent; } + my $ref_pcontent = $parent->content; + my @pcontent = @{$ref_pcontent}; + for (my $i=0; $i<scalar(@pcontent); $i++) + { if ($pcontent[$i] eq $he) + { splice @{$ref_pcontent}, $i, 1; + $he->parent(undef); + return 1; } } + die "Didn't find $he in $parent"; +} + + +sub html_replace ( $$;$ ) +{ my ($orig, $new, $parent) = check_args_range(2, 3, @_); + if (!defined $parent) + { $parent = $orig->parent; } + my $ref_pcontent = $parent->content; + my @pcontent = @{$ref_pcontent}; + for (my $i=0; $i<scalar(@pcontent); $i++) + { if ($pcontent[$i] eq $orig) + { $ {$ref_pcontent}[$i] = $new; + $new->parent($parent); + $orig->parent(undef); + return 1; } } + die "Didn't find $orig in $parent"; +} + +sub html_replace_by_meta ( $;$ ) +{ my ($orig, $parent) = check_args_range(1, 2, @_); + my $meta = new HTML::Element "meta"; + if (!defined $parent) + { $parent = $orig->parent; } + return html_replace($orig, $meta, $parent); +} + +sub html_replace_by_ignore ( $;$ ) +{ my ($orig, $parent) = check_args_range(1, 2, @_); + my $ignore = new HTML::Element "ignore"; + if (!defined $parent) + { $parent = $orig->parent; } + return html_replace($orig, $ignore, $parent); +} + + + +### +### Collect text elements +### + +my @collected_texts; +my $collect_texts_stoppoint; +my $done_collecting; + +sub collect_texts ( $;$ ) +{ my ($root, $stop) = check_args_range(1, 2, @_); + # print STDERR "collect_texts: $root $stop\n"; + $collect_texts_stoppoint = $stop; + $done_collecting = 0; + @collected_texts = (); + $root->traverse(\&collect_if_text); # process texts + # print STDERR "collect_texts => ", join(";;;", @collected_texts), "\n"; + return @collected_texts; +} + +sub collect_if_text ( $$$ ) +{ my $he = (check_args(3, @_))[0]; # ignore depth and startflag arguments + if ($done_collecting) + { return 0; } + if (!defined $he) + { return 0; } + if (!ref $he) + { push @collected_texts, $he; + return 0; } + if ((defined $collect_texts_stoppoint) && ($he eq $collect_texts_stoppoint)) + { $done_collecting = 1; + return 0; } + return 1; +} + + +########################################################################### +### Clean up parse tree +### + +sub cleanup_parse_tree ( $ ) +{ my ($he) = check_args(1, @_); + $he->traverse(\&delete_if_navigation, 'ignore text'); + $he->traverse(\&delete_extra_spaces, 'ignore text'); + $he->traverse(\&merge_dl, 'ignore text'); + $he->traverse(\&reorder_dt_and_dl, 'ignore text'); + return $he; +} + + +## Simpler version that deletes contents but not the element itself. +# sub delete_if_navigation ( $$$ ) +# { my $he = (check_args(3, @_))[0]; # ignore startflag and depth +# if (($he->tag() eq "div") && ($he->attr('class') eq 'navigation')) +# { $he->delete(); +# return 0; } +# else +# { return 1; } +# } + +sub delete_if_navigation ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if (($he->tag() eq "div") && (defined $he->attr('class')) && ($he->attr('class') eq 'navigation')) + { my $ref_pcontent = $he->parent()->content(); + # Don't try to modify @pcontent, which appears to be a COPY. + # my @pcontent = @{$ref_pcontent}; + for (my $i = 0; $i<scalar(@{$ref_pcontent}); $i++) + { if (${$ref_pcontent}[$i] eq $he) + { splice(@{$ref_pcontent}, $i, 1); + last; } } + $he->delete(); + return 0; } + else + { return 1; } +} + +sub delete_extra_spaces ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + my $tag = $he->tag; + if ($tag =~ /^(head|html|table|tr|ul)$/) + { delete_child_spaces($he); } + delete_trailing_spaces($he); + return 1; +} + + +sub delete_child_spaces ( $ ) +{ my ($he) = check_args(1, @_); + my $ref_content = $he->content(); + for (my $i = 0; $i<scalar(@{$ref_content}); $i++) + { if ($ {$ref_content}[$i] =~ /^ *$/) + { splice(@{$ref_content}, $i, 1); + $i--; } } +} + +sub delete_trailing_spaces ( $ ) +{ my ($he) = check_args(1, @_); + my $ref_content = $he->content(); + if (! defined $ref_content) + { return; } + # Could also check for previous element = /^h[1-6]$/. + for (my $i = 0; $i<scalar(@{$ref_content})-1; $i++) + { if ($ {$ref_content}[$i] =~ /^ *$/) + { my $next_elt = $ {$ref_content}[$i+1]; + if ((ref $next_elt) && ($next_elt->tag =~ /^(br|dd|dl|dt|hr|p|ul)$/)) + { splice(@{$ref_content}, $i, 1); + $i--; } } } + if ($he->tag =~ /^(dd|dt|^h[1-6]|li|p)$/) + { my $last_elt = $ {$ref_content}[$#{$ref_content}]; + if ((defined $last_elt) && ($last_elt =~ /^ *$/)) + { pop @{$ref_content}; } } +} + + +# LaTeX2HTML sometimes creates +# <DT>text +# <DL COMPACT><DD>text +# which should actually be: +# <DL COMPACT> +# <DT>text +# <DD>text +# Since a <DL> gets added, this ends up looking like +# <P> +# <DL> +# <DT> +# text1... +# <DL COMPACT> +# <DD> +# text2... +# dt_or_dd1... +# dt_or_dd2... +# which should become +# <P> +# <DL COMPACT> +# <DT> +# text1... +# <DD> +# text2... +# dt_or_dd1... +# dt_or_dd2... + +sub reorder_dt_and_dl ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if ($he->tag() eq "p") + { my $ref_pcontent = $he->content(); + if (defined $ref_pcontent) + { my @pcontent = @{$ref_pcontent}; + # print "reorder_dt_and_dl found a <p>\n"; $he->dump(); + if ((scalar(@pcontent) >= 1) + && (ref $pcontent[0]) && ($pcontent[0]->tag() eq "dl") + && $pcontent[0]->implicit()) + { my $ref_dlcontent = $pcontent[0]->content(); + # print "reorder_dt_and_dl found a <p> and implicit <dl>\n"; + if (defined $ref_dlcontent) + { my @dlcontent = @{$ref_dlcontent}; + if ((scalar(@dlcontent) >= 1) + && (ref $dlcontent[0]) && ($dlcontent[0]->tag() eq "dt")) + { my $ref_dtcontent = $dlcontent[0]->content(); + # print "reorder_dt_and_dl found a <p>, implicit <dl>, and <dt>\n"; + if (defined $ref_dtcontent) + { my @dtcontent = @{$ref_dtcontent}; + if ((scalar(@dtcontent) > 0) + && (ref $dtcontent[$#dtcontent]) + && ($dtcontent[$#dtcontent]->tag() eq "dl")) + { my $ref_dl2content = $dtcontent[$#dtcontent]->content(); + # print "reorder_dt_and_dl found a <p>, implicit <dl>, <dt>, and <dl>\n"; + if (defined $ref_dl2content) + { my @dl2content = @{$ref_dl2content}; + if ((scalar(@dl2content) > 0) + && (ref ($dl2content[0])) + && ($dl2content[0]->tag() eq "dd")) + { + # print "reorder_dt_and_dl found a <p>, implicit <dl>, <dt>, <dl>, and <dd>\n"; + # print STDERR "CHANGING\n"; $he->dump(); + html_replace_by_ignore($dtcontent[$#dtcontent]); + splice(@{$ref_dlcontent}, 1, 0, @dl2content); + # print STDERR "CHANGED TO:\n"; $he->dump(); + return 0; # don't traverse children + } } } } } } } } } + return 1; +} + + +# If we find a paragraph that looks like +# <P> +# <HR> +# <UL> +# then accumulate its links into a contents_list and delete the paragraph. +sub process_if_child_links ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if ($he->tag() eq "p") + { my $ref_content = $he->content(); + if (defined $ref_content) + { my @content = @{$ref_content}; + if ((scalar(@content) == 2) + && (ref $content[0]) && $content[0]->tag() eq "hr" + && (ref $content[1]) && $content[1]->tag() eq "ul") + { process_child_links($he); + $he->delete(); + return 0; } } } + return 1; +} + + +# If we find +# <H4> +# "Footnotes" +# <DL> +# <DT> +# <A NAME="foot560"> +# "...borrow" +# <A HREF="refcountsInPython.html#tex2html2" NAME="foot560"> +# "1.2" +# <DD> +# "The metaphor of ``borrowing'' a reference is not completely correct: the owner still has a copy of the reference. " +# ... +# then record the footnote information and delete the section and list. + +my $process_if_footnotes_expect_dl_next = 0; + +sub process_if_footnotes ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if (($he->tag() eq "h4") + && has_single_content_string($he) + && ($ {$he->content}[0] eq "Footnotes")) + { html_replace_by_ignore($he); + $process_if_footnotes_expect_dl_next = 1; + return 0; } + + if ($process_if_footnotes_expect_dl_next && ($he->tag() eq "dl")) + { my $ref_content = $he->content(); + if (defined $ref_content) + { $process_if_footnotes_expect_dl_next = 0; + my @content = @{$ref_content}; + for (my $i=0; $i<$#content; $i+=2) + { my $he_dt = $content[$i]; + my $he_dd = $content[$i+1]; + if (($he_dt->tag ne "dt") || ($he_dd->tag ne "dd")) + { $he->dump; + die "expected <DT> and <DD> at positions $i and ", $i+1; } + my @dt_content = @{$he_dt->content()}; + if ((scalar(@dt_content) != 2) + || ($dt_content[0]->tag ne "a") + || ($dt_content[1]->tag ne "a")) + { $he_dt->dump; + die "Expected 2 anchors as content of <DT>"; } + my ($dt1_name, $dt1_href, $dt1_content) = anchor_info($dt_content[0]); + my ($dt2_name, $dt2_href, $dt2_content) = anchor_info($dt_content[0]); + # unused: $dt1_href, $dt1_content, $dt2_href, $dt2_content + if ($dt1_name ne $dt2_name) + { $he_dt->dump; + die "Expected identical names for anchors"; } + html_replace_by_ignore($he_dd); + $he_dd->tag("div"); # has no effect + $footnotes{$dt1_name} = $he_dd; } + html_replace_by_ignore($he); + return 0; } } + + if ($process_if_footnotes_expect_dl_next) + { $he->dump; + die "Expected <DL> for footnotes next"; } + + return 1; +} + + + +## Merge two adjacent paragraphs containing <DL> items, such as: +# <P> +# <DL> +# <DT> +# ... +# <DD> +# ... +# <P> +# <DL> +# <DT> +# ... +# <DD> +# ... + +sub merge_dl ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + my $ref_content = $he->content; + if (!defined $ref_content) + { return; } + my $i = 0; + while ($i < scalar(@{$ref_content})-1) + { my $p1 = $ {$ref_content}[$i]; + if ((ref $p1) && ($p1->tag eq "p") + && has_single_content_with_tag($p1, "dl")) + { my $dl1 = $ {$p1->content}[0]; + # In this loop, rhs, not lhs, of < comparison changes, + # because we are removing elements from the content of $he. + while ($i < scalar(@{$ref_content})-1) + { my $p2 = $ {$ref_content}[$i+1]; + if (!((ref $p2) && ($p2->tag eq "p") + && has_single_content_with_tag($p2, "dl"))) + { last; } + # Merge these two elements. + splice(@{$ref_content}, $i+1, 1); # remove $p2 + my $dl2 = $ {$p2->content}[0]; + $dl1->push_content(@{$dl2->content}); # put $dl2's content in $dl1 + } + # extra increment because next element isn't a candidate for $p1 + $i++; } + $i++; } + return 1; +} + + + +########################################################################### +### Testing +### + +sub test ( $$ ) +{ my ($action, $file) = check_args(2, @_); + + # General testing + if (($action eq "view") || ($action eq "")) + { # # $file = "/homes/gws/mernst/www/links.html"; + # # $file = "/homes/gws/mernst/www/index.html"; + # # $file = "/homes/fish/mernst/java/gud/doc/manual.html"; + # # $file = "/projects/cecil/cecil/doc/manuals/stdlib-man/stdlib/stdlib.html"; + # # $file = "/homes/fish/mernst/tmp/python-doc/html/index.html"; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/complexObjects.html"; + my $tree = file_to_tree($file); + + ## Testing + # print STDERR $tree->as_HTML; + $tree->dump(); + + # print STDERR $tree->tag(), "\n"; + # print STDERR @{$tree->content()}, "\n"; + # + # for (@{ $tree->extract_links(qw(a img)) }) { + # my ($link, $linkelem) = @$_; + # print STDERR "$link ", $linkelem->as_HTML; + # } + # + # print STDERR @{$tree->extract_links()}, "\n"; + + # my @top_level_elts = @{$tree->content()}; + + # if scalar(@{$tree->content()}) + return; + } + + elsif ($action eq "raw") + { my $tree = new HTML::TreeBuilder; + $tree->ignore_unknown(1); + # $tree->warn(1); + $tree->parse_file($file); + + $tree->dump(); + + # cleanup_parse_tree($tree); + # $tree->dump(); + return; + } + + # Test dealing with a section. + elsif ($action eq "section") + { # my $file; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/intro.html"; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/includes.html"; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/complexObjects.html"; + process_section_file($file, 0, "Title"); + } + + # Test dealing with many sections + elsif (0) + { my @files = ("/homes/fish/mernst/tmp/python-doc/html/api/about.html", + "/homes/fish/mernst/tmp/python-doc/html/api/abstract.html", + "/homes/fish/mernst/tmp/python-doc/html/api/api.html", + "/homes/fish/mernst/tmp/python-doc/html/api/cObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/complexObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/concrete.html", + # "/homes/fish/mernst/tmp/python-doc/html/api/contents.html", + "/homes/fish/mernst/tmp/python-doc/html/api/countingRefs.html", + "/homes/fish/mernst/tmp/python-doc/html/api/debugging.html", + "/homes/fish/mernst/tmp/python-doc/html/api/dictObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/embedding.html", + "/homes/fish/mernst/tmp/python-doc/html/api/exceptionHandling.html", + "/homes/fish/mernst/tmp/python-doc/html/api/exceptions.html", + "/homes/fish/mernst/tmp/python-doc/html/api/fileObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/floatObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/front.html", + "/homes/fish/mernst/tmp/python-doc/html/api/fundamental.html", + # "/homes/fish/mernst/tmp/python-doc/html/api/genindex.html", + "/homes/fish/mernst/tmp/python-doc/html/api/importing.html", + "/homes/fish/mernst/tmp/python-doc/html/api/includes.html", + "/homes/fish/mernst/tmp/python-doc/html/api/index.html", + "/homes/fish/mernst/tmp/python-doc/html/api/initialization.html", + "/homes/fish/mernst/tmp/python-doc/html/api/intObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/intro.html", + "/homes/fish/mernst/tmp/python-doc/html/api/listObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/longObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/mapObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/mapping.html", + "/homes/fish/mernst/tmp/python-doc/html/api/newTypes.html", + "/homes/fish/mernst/tmp/python-doc/html/api/node24.html", + "/homes/fish/mernst/tmp/python-doc/html/api/noneObject.html", + "/homes/fish/mernst/tmp/python-doc/html/api/number.html", + "/homes/fish/mernst/tmp/python-doc/html/api/numericObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/object.html", + "/homes/fish/mernst/tmp/python-doc/html/api/objects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/os.html", + "/homes/fish/mernst/tmp/python-doc/html/api/otherObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/processControl.html", + "/homes/fish/mernst/tmp/python-doc/html/api/refcountDetails.html", + "/homes/fish/mernst/tmp/python-doc/html/api/refcounts.html", + "/homes/fish/mernst/tmp/python-doc/html/api/sequence.html", + "/homes/fish/mernst/tmp/python-doc/html/api/sequenceObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/standardExceptions.html", + "/homes/fish/mernst/tmp/python-doc/html/api/stringObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/threads.html", + "/homes/fish/mernst/tmp/python-doc/html/api/tupleObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/typeObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/types.html", + "/homes/fish/mernst/tmp/python-doc/html/api/utilities.html", + "/homes/fish/mernst/tmp/python-doc/html/api/veryhigh.html"); + for my $file (@files) + { print STDERR "\n", "=" x 75, "\n", "$file:\n"; + process_section_file($file, 0, "Title"); + } + } + + # Test dealing with index. + elsif ($action eq "index") + { # my $file; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/genindex.html"; + + process_index_file($file, "\@cindex"); + print_index_info(); + } + + else + { die "Unrecognized action `$action'"; } +} + + +########################################################################### +### Main loop +### + +sub process_contents_file ( $ ) +{ my ($file) = check_args(1, @_); + + # could also use File::Basename + my $info_file = $file; + $info_file =~ s/(\/?index)?\.html$//; + if ($info_file eq "") + { chomp($info_file = `pwd`); } + $info_file =~ s/^.*\///; # not the most efficient way to remove dirs + + $html_directory = $file; + $html_directory =~ s/(\/|^)[^\/]+$/$1/; + + my $texi_file = "$info_file.texi"; + open(TEXI, ">$texi_file"); + + print TEXI "\\input texinfo \@c -*-texinfo-*-\n"; + print TEXI "\@c %**start of header\n"; + print TEXI "\@setfilename $info_file\n"; + + # 2. Summary Description and Copyright + # The "Summary Description and Copyright" segment describes the + # document and contains the copyright notice and copying permissions + # for the Info file. The segment must be enclosed between `@ifinfo' + # and `@end ifinfo' commands so that the formatters place it only in + # the Info file. + # + # The summary description and copyright segment does not appear in the + # printed document. + # + # @ifinfo + # This is a short example of a complete Texinfo file. + # + # Copyright @copyright{} 1990 Free Software Foundation, Inc. + # @end ifinfo + + + # 3. Title and Copyright + # The "Title and Copyright" segment contains the title and copyright + # pages and copying permissions for the printed manual. The segment + # must be enclosed between `@titlepage' and `@end titlepage' + # commands. The title and copyright page appear only in the printed + # manual. + # + # The titlepage segment does not appear in the Info file. + # + # @titlepage + # @sp 10 + # @comment The title is printed in a large font. + # @center @titlefont{Sample Title} + # + # @c The following two commands start the copyright page. + # @page + # @vskip 0pt plus 1filll + # Copyright @copyright{} 1990 Free Software Foundation, Inc. + # @end titlepage + + + # 4. `Top' Node and Master Menu + # The "Master Menu" contains a complete menu of all the nodes in the + # whole Info file. It appears only in the Info file, in the `Top' + # node. + # + # The `Top' node contains the master menu for the Info file. Since a + # printed manual uses a table of contents rather than a menu, the master + # menu appears only in the Info file. + # + # @node Top, First Chapter, , (dir) + # @comment node-name, next, previous, up + # + # @menu + # * First Chapter:: The first chapter is the + # only chapter in this sample. + # * Concept Index:: This index has two entries. + # @end menu + + + + $current_ref_tdf = [ "Top", 0, $ARGV[0] ]; + process_section_file($file, 0, "Top"); + while (scalar(@contents_list)) + { $current_ref_tdf = shift @contents_list; + process_section_file($ {$current_ref_tdf}[2], $ {$current_ref_tdf}[1], $ {$current_ref_tdf}[0]); + } + + print TEXI "\n"; + for my $indextitle (@index_titles) + { print TEXI "\@node $indextitle\n"; + print TEXI "\@unnumbered $indextitle\n"; + print TEXI "\@printindex $ {$index_info{$indextitle}}[1]\n"; + print TEXI "\n"; } + + print TEXI "\@contents\n"; + print TEXI "\@bye\n"; + close(TEXI); +} + +# This needs to be last so global variable initializations are reached. + +if (scalar(@ARGV) == 0) +{ die "No arguments supplied to html2texi.pl"; } + +if ($ARGV[0] eq "-test") +{ my @test_args = @ARGV[1..$#ARGV]; + if (scalar(@test_args) == 0) + { test("", "index.html"); } + elsif (scalar(@test_args) == 1) + { test("", $test_args[0]); } + elsif (scalar(@test_args) == 2) + { test($test_args[0], $test_args[1]); } + else + { die "Too many test arguments passed to html2texi: ", join(" ", @ARGV); } + exit(); +} + +if (scalar(@ARGV) != 1) +{ die "Pass one argument, the main/contents page"; } + +process_contents_file($ARGV[0]); + +# end of html2texi.pl diff --git a/sys/src/cmd/python/Doc/tools/indfix.py b/sys/src/cmd/python/Doc/tools/indfix.py new file mode 100755 index 000000000..f88c3f37d --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/indfix.py @@ -0,0 +1,100 @@ +#! /usr/bin/env python + +"""Combine similar index entries into an entry and subentries. + +For example: + + \item {foobar} (in module flotz), 23 + \item {foobar} (in module whackit), 4323 + +becomes + + \item {foobar} + \subitem in module flotz, 23 + \subitem in module whackit, 4323 + +Note that an item which matches the format of a collapsable item but which +isn't part of a group of similar items is not modified. +""" +__version__ = '$Revision: 29268 $' + +import re +import StringIO +import sys + + +def cmp_entries(e1, e2): + return cmp(e1[1].lower(), e2[1].lower()) or cmp(e1, e2) + + +def dump_entries(write, entries): + if len(entries) == 1: + write(" \\item %s (%s)%s\n" % entries[0]) + return + write(" \item %s\n" % entries[0][0]) + # now sort these in a case insensitive manner: + if len(entries) > 0: + entries.sort(cmp_entries) + for xxx, subitem, pages in entries: + write(" \subitem %s%s\n" % (subitem, pages)) + + +breakable_re = re.compile( + r" \\item (.*) [(](.*)[)]((?:(?:, \d+)|(?:, \\[a-z]*\{\d+\}))+)") + + +def process(ifn, ofn=None): + if ifn == "-": + ifp = sys.stdin + else: + ifp = open(ifn) + if ofn is None: + ofn = ifn + ofp = StringIO.StringIO() + entries = [] + match = breakable_re.match + write = ofp.write + while 1: + line = ifp.readline() + if not line: + break + m = match(line) + if m: + entry = m.group(1, 2, 3) + if entries and entries[-1][0] != entry[0]: + dump_entries(write, entries) + entries = [] + entries.append(entry) + elif entries: + dump_entries(write, entries) + entries = [] + write(line) + else: + write(line) + del write + del match + ifp.close() + data = ofp.getvalue() + ofp.close() + if ofn == "-": + ofp = sys.stdout + else: + ofp = open(ofn, "w") + ofp.write(data) + ofp.close() + + +def main(): + import getopt + outfile = None + opts, args = getopt.getopt(sys.argv[1:], "o:") + for opt, val in opts: + if opt in ("-o", "--output"): + outfile = val + filename = args[0] + outfile = outfile or filename + process(filename, outfile) + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/keywords.py b/sys/src/cmd/python/Doc/tools/keywords.py new file mode 100644 index 000000000..9f32056db --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/keywords.py @@ -0,0 +1,19 @@ +#! /usr/bin/env python + +# This Python program sorts and reformats the table of keywords in ref2.tex + +l = [] +try: + while 1: + l = l + raw_input().split() +except EOFError: + pass +l.sort() +for x in l[:]: + while l.count(x) > 1: l.remove(x) +ncols = 5 +nrows = (len(l)+ncols-1)/ncols +for i in range(nrows): + for j in range(i, len(l), nrows): + print l[j].ljust(10), + print diff --git a/sys/src/cmd/python/Doc/tools/listmodules b/sys/src/cmd/python/Doc/tools/listmodules new file mode 100755 index 000000000..506bde33b --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/listmodules @@ -0,0 +1,183 @@ +#! /usr/bin/env python +# -*- Python -*- +# +# This script can be used to identify undocumented modules in the Python +# standard library. Use it like this: +# +# .../Doc/tools/listmodules --ignore-from .../Doc/paper-<paper>/modlib.idx + +"""%(program)s - list modules in the Python standard library + +-a, --annotate Annotate the module names with the subdirectory they + live in +-c, --categorize Group the modules by subdirectory +-i <file>, + +--ignore-from <file> Ignore the modules listed in <file>. <file> may + contain a list of module names or a module index file + as produced when formatting the Python documentation + (.idx or .html flavor). + +If neither -a nor -c are given, the modules are listed in alphabetical +order. + +Note that -a and -c are mutually exclusive. + +Limitation: Modules loadable as shared objects may not be listed, +though this script attempts to locate such modules. + +""" + +__version__ = '$Revision: 18276 $' + +import getopt +import glob +import os +import re +import string +import sys + + +REMOVE_DIRS = ["dos-8x3", "encodings", "distutils", + "lib-old", "lib-stdwin", "test"] + + +def main(): + args = sys.argv[1:] + annotate = 0 + builtin = 0 + categorize = 0 + ignore_dict = {} + ignore = ignore_dict.has_key + try: + opts, args = getopt.getopt( + args, "abchi:", + ["annotate", "built-in", "categorize", "help", "ignore-from="]) + except getopt.error, msg: + sys.stdout = sys.stderr + print msg + print + usage() + sys.exit(2) + for opt, arg in opts: + if opt in ("-a", "--annotate"): + annotate = 1 + elif opt in ("-b", "--built-in"): + builtin = 1 + elif opt in ("-c", "--categorize"): + categorize = 1 + elif opt in ("-h", "--help"): + usage() + sys.exit() + elif opt in ("-i", "--ignore-from"): + data = open(arg).read() + if data[:1] == "\\": + ignore_from_idx(data, ignore_dict) + else: + ignore_from_modulelist(data, ignore_dict) + if args or (annotate and categorize): + usage() + sys.exit(2) + # + # Populate the database: + # + srcdir = os.path.normpath(os.path.join( + os.path.dirname(sys.argv[0]), os.pardir, os.pardir)) + os.chdir(srcdir) + modules_by_name = {} + modules_by_dir = {} + if builtin: + l = [] + modules_by_dir["<builtin>"] = l + for name in sys.builtin_module_names: + if not ignore(name): + modules_by_name[name] = "<built-in>" + l.append(name) + rx = re.compile("Lib/plat-[a-zA-Z0-9]*/") + fp = os.popen("find Lib -name \*.py -print", "r") + while 1: + line = fp.readline() + if not line: + break + m = rx.match(line) + if m: + line = "Lib/plat-*/" + line[m.end():] + line = line[4:-4] # strip off 'Lib/' and '.py\n' + dir, name = os.path.split(line) + dir = dir or "<standard>" + if ignore(name): + continue + if dir not in REMOVE_DIRS: + modules_by_name[name] = dir + l = modules_by_dir.get(dir, []) + modules_by_dir[dir] = l + if name not in l: + l.append(name) + # load up extension modules: + pwd = os.getcwd() + try: + os.chdir("Modules") + dir = "<extension>" + for line in glob.glob("*module.c"): + name = line[:-8] + if ignore(name) or modules_by_name.has_key(name) or name == "xx": + continue + modules_by_name[name] = dir + l = modules_by_dir.get(dir, []) + modules_by_dir[dir] = l + if name not in l: + l.append(name) + finally: + os.chdir(pwd) + # + # Dump the results: + # + if annotate: + modules = modules_by_name.items() + modules.sort() + width = max(map(len, modules_by_name.keys())) + format = "%%-%ds %%s" % width + for name, dir in modules: + if dir and dir[0] != "<": + print format % (name, dir) + else: + print name + elif categorize: + modules = modules_by_dir.items() + modules.sort() + width = max(map(len, modules_by_dir.keys())) + format = "%%-%ds %%s" % width + for dir, names in modules: + names.sort() + print format % (dir, names[0]) + for name in names[1:]: + print format % ('', name) + print + else: + modules = modules_by_name.keys() + modules.sort() + print string.join(modules, "\n") + + +def ignore_from_modulelist(data, ignore_dict): + for name in string.split(data): + ignore_dict[name] = name + +def ignore_from_idx(data, ignore_dict): + data = string.replace(data, r"\hackscore {}", "_") + rx = re.compile(r"\\indexentry\s*{([^@]*)@") + for line in string.split(data, "\n"): + m = rx.match(line) + if m: + name = m.group(1) + ignore_dict[name] = name + + +def usage(): + vars = {} + vars["program"] = os.path.basename(sys.argv[0]) + print __doc__ % vars + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/listmodules.py b/sys/src/cmd/python/Doc/tools/listmodules.py new file mode 100644 index 000000000..67099bf8c --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/listmodules.py @@ -0,0 +1,126 @@ +# $Id: listmodules.py 42172 2006-01-24 16:16:19Z fredrik.lundh $ +# +# Locate all standard modules available in this build. +# +# This script is designed to run on Python 1.5.2 and newer. +# +# Written by Fredrik Lundh, January 2005 +# + +import imp, sys, os, re, time + +identifier = "python-%s-%s" % (sys.version[:3], sys.platform) +timestamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime(time.time())) + +# known test packages +TEST_PACKAGES = "test.", "bsddb.test.", "distutils.tests." + +try: + import platform + platform = platform.platform() +except: + platform = None # unknown + +suffixes = imp.get_suffixes() + +def get_suffix(file): + for suffix in suffixes: + if file[-len(suffix[0]):] == suffix[0]: + return suffix + return None + +def main(): + + path = getpath() + + modules = {} + for m in sys.builtin_module_names: + modules[m] = None + + for p in path: + modules.update(getmodules(p)) + + keys = modules.keys() + keys.sort() + + # filter out known test packages + def cb(m): + for d in TEST_PACKAGES: + if m[:len(d)] == d: + return 0 + return 1 + keys = filter(cb, keys) + + try: + outfile = sys.argv[1] + if outfile == "-": + outfile = None + elif outfile == "-f": + outfile = "modules-" + identifier + ".txt" + except IndexError: + outfile = None + + if not outfile: + out = sys.stdout + else: + out = open(outfile, "w") + + out.write("# module list (generated by listmodules.py)\n") + out.write("#\n") + out.write("# timestamp=%s\n" % repr(timestamp)) + out.write("# sys.version=%s\n" % repr(sys.version)) + out.write("# sys.platform=%s\n" % repr(sys.platform)) + if platform: + out.write("# platform=%s\n" % repr(platform)) + out.write("#\n") + + for k in keys: + out.write(k + "\n") + + if out is not sys.stdout: + out.close() + print out.name, "ok (%d modules)" % len(modules) + +def getmodules(p): + # get modules in a given directory + modules = {} + for f in os.listdir(p): + f = os.path.join(p, f) + if os.path.isfile(f): + m, e = os.path.splitext(f) + suffix = get_suffix(f) + if not suffix: + continue + m = os.path.basename(m) + if re.compile("(?i)[a-z_]\w*$").match(m): + if suffix[2] == imp.C_EXTENSION: + # check that this extension can be imported + try: + __import__(m) + except ImportError: + continue + modules[m] = f + elif os.path.isdir(f): + m = os.path.basename(f) + if os.path.isfile(os.path.join(f, "__init__.py")): + for mm, f in getmodules(f).items(): + modules[m + "." + mm] = f + return modules + +def getpath(): + path = map(os.path.normcase, map(os.path.abspath, sys.path[:])) + # get rid of site packages + for p in path: + if p[-13:] == "site-packages": + def cb(p, site_package_path=os.path.abspath(p)): + return p[:len(site_package_path)] != site_package_path + path = filter(cb, path) + break + # get rid of non-existent directories and the current directory + def cb(p, cwd=os.path.normcase(os.getcwd())): + return os.path.isdir(p) and p != cwd + path = filter(cb, path) + return path + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/makesec.sh b/sys/src/cmd/python/Doc/tools/makesec.sh new file mode 100755 index 000000000..6159d6fa8 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/makesec.sh @@ -0,0 +1,129 @@ +#!/bin/sh + +# Simple little checker for individual libref manual sections +# +# usage: makesec.sh section +# + +# This script builds the minimal file necessary to run a single section +# through latex, does so, then converts the resulting dvi file to ps or pdf +# and feeds the result into a viewer. It's by no means foolproof, but seems +# to work okay for me (knock wood). It sure beats manually commenting out +# most of the man lib.tex file and running everything manually. + +# It attempts to locate an appropriate dvi converter and viewer for the +# selected output format. It understands the following environment +# variables: +# +# PYSRC - refers to the root of your build tree (dir containing Doc) +# DVICVT - refers to a dvi converter like dvips or dvipdf +# VIEWER - refers to an appropriate viewer for the ps/pdf file +# +# Of the three, only PYSRC is currently required. The other two can be set +# to specify unusual tools which perform those tasks. + +# Known issues: +# - It would be nice if the script could determine PYSRC on its own. +# - Something about \seealso{}s blows the latex stack, so they need +# to be commented out for now. + +if [ x$PYSRC = x ] ; then + echo "PYSRC must refer to the Python source tree" 1>&2 + exit 1 +fi + +if [ ! -d $PYSRC/Doc ] ; then + echo "Can't find a Doc subdirectory in $PYSRC" 1>&2 + exit 1 +fi + +if [ "$#" -ne 1 ] ; then + echo "Must specify a single libref manual section on cmd line" 1>&2 + exit 1 +fi + +# settle on a dvi converter +if [ x$DVICVT != x ] ; then + converter=$DVICVT + ext=`echo $DVICVT | sed -e 's/^dvi//'` + result=lib.$ext +elif [ x`which dvipdf` != x ] ; then + converter=`which dvipdf` + ext=.pdf +elif [ x`which dvips` != x ] ; then + converter=`which dvips` + ext=.ps +else + echo "Can't find a reasonable dvi converter" 1>&2 + echo "Set DVICVT to refer to one" 1>&2 + exit 1 +fi + +# how about a viewer? +if [ x$VIEWER != x ] ; then + viewer=$VIEWER +elif [ $ext = ".ps" -a x`which gv` != x ] ; then + viewer=gv +elif [ $ext = ".ps" -a x`which gs` != x ] ; then + viewer=gs +elif [ $ext = ".pdf" -a x`which acroread` != x ] ; then + viewer=acroread +elif [ $ext = ".pdf" -a "`uname`" = "Darwin" -a x`which open` != x ] ; then + viewer=open +elif [ $ext = ".pdf" -a x`which acroread` != x ] ; then + viewer=acroread +else + echo "Can't find a reasonable viewer" 1>&2 + echo "Set VIEWER to refer to one" 1>&2 + exit 1 +fi + +# make sure necessary links are in place +for f in howto.cls pypaper.sty ; do + rm -f $f + ln -s $PYSRC/Doc/$f +done + +export TEXINPUTS=.:$PYSRC/Doc/texinputs: + +# strip extension in case they gave full filename +inp=`basename $1 .tex` + +# create the minimal framework necessary to run section through latex +tmpf=lib.tex +cat > $tmpf <<EOF +\documentclass{manual} + +% NOTE: this file controls which chapters/sections of the library +% manual are actually printed. It is easy to customize your manual +% by commenting out sections that you are not interested in. + +\title{Python Library Reference} + +\input{boilerplate} + +\makeindex % tell \index to actually write the + % .idx file +\makemodindex % ... and the module index as well. + + +\begin{document} + +\maketitle + +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +\input{$inp} +\end{document} +EOF + +latex $tmpf + +$converter lib + +$viewer lib.pdf + +rm -f $tmpf howto.cls pypaper.sty *.idx *.syn +rm -f lib.aux lib.log diff --git a/sys/src/cmd/python/Doc/tools/mkackshtml b/sys/src/cmd/python/Doc/tools/mkackshtml new file mode 100755 index 000000000..2c79f5eb1 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/mkackshtml @@ -0,0 +1,66 @@ +#! /usr/bin/env python +# -*- Python -*- + +import string +import support +import sys + + +def collect(fp): + names = [] + while 1: + line = fp.readline() + if not line: + break + line = string.strip(line) + if line: + names.append(line) + else: + names = [] + return names + + +def main(): + options = support.Options() + options.columns = 4 + options.variables["title"] = "Acknowledgements" + options.parse(sys.argv[1:]) + names = collect(sys.stdin) + percol = (len(names) + options.columns - 1) / options.columns + colnums = [] + for i in range(options.columns): + colnums.append(percol*i) + options.aesop_type = "information" + fp = options.get_output_file() + fp.write(string.rstrip(options.get_header()) + "\n") + fp.write(THANKS + "\n") + fp.write('<table width="100%" align="center">\n') + for i in range(percol): + fp.write(" <tr>\n") + for j in colnums: + try: + fp.write(" <td>%s</td>\n" % names[i + j]) + except IndexError: + pass + fp.write(" </tr>\n") + fp.write("</table>\n") + fp.write(string.rstrip(options.get_footer()) + "\n") + fp.close() + +THANKS = '''\ + +<p>These people have contributed in some way to the Python +documentation. This list is probably not complete -- if you feel that +you or anyone else should be on this list, please let us know (send +email to <a +href="mailto:docs@python.org">docs@python.org</a>), and +we will be glad to correct the problem.</p> + +<p>It is only with the input and contributions of the Python community +that Python has such wonderful documentation -- <b>Thank You!</b></p> + +''' + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/mkhowto b/sys/src/cmd/python/Doc/tools/mkhowto new file mode 100755 index 000000000..21cd6fb27 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/mkhowto @@ -0,0 +1,659 @@ +#! /usr/bin/env python +# -*- Python -*- +"""usage: %(program)s [options...] file ... + +Options specifying formats to build: + --html HyperText Markup Language (default) + --pdf Portable Document Format + --ps PostScript + --dvi 'DeVice Indepentent' format from TeX + --text ASCII text (requires lynx) + + More than one output format may be specified, or --all. + +HTML options: + --address, -a Specify an address for page footers. + --dir Specify the directory for HTML output. + --link Specify the number of levels to include on each page. + --split, -s Specify a section level for page splitting, default: %(max_split_depth)s. + --iconserver, -i Specify location of icons (default: ./). + --image-type Specify the image type to use in HTML output; + values: gif, png (default). + --numeric Don't rename the HTML files; just keep node#.html for + the filenames. + --style Specify the CSS file to use for the output (filename, + not a URL). + --up-link URL to a parent document. + --up-title Title of a parent document. + --favicon Icon to display in the browsers location bar. + +Other options: + --a4 Format for A4 paper. + --letter Format for US letter paper (the default). + --help, -H Show this text. + --logging, -l Log stdout and stderr to a file (*.how). + --debugging, -D Echo commands as they are executed. + --keep, -k Keep temporary files around. + --quiet, -q Do not print command output to stdout. + (stderr is also lost, sorry; see *.how for errors) +""" + +import getopt +import glob +import os +import re +import shutil +import sys + + +MYDIR = os.path.abspath(sys.path[0]) +TOPDIR = os.path.dirname(MYDIR) + +ISTFILE = os.path.join(TOPDIR, "texinputs", "python.ist") +NODE2LABEL_SCRIPT = os.path.join(MYDIR, "node2label.pl") +L2H_INIT_FILE = os.path.join(TOPDIR, "perl", "l2hinit.perl") + +BIBTEX_BINARY = "bibtex" +DVIPS_BINARY = "dvips" +LATEX_BINARY = "latex" +LATEX2HTML_BINARY = "latex2html" +LYNX_BINARY = "lynx" +MAKEINDEX_BINARY = "makeindex" +PDFLATEX_BINARY = "pdflatex" +PERL_BINARY = "perl" +PYTHON_BINARY = "python" + + +def usage(options, file): + print >>file, __doc__ % options + +def error(options, message, err=2): + print >>sys.stderr, message + print >>sys.stderr + usage(options, sys.stderr) + sys.exit(2) + + +class Options: + program = os.path.basename(sys.argv[0]) + # + address = '' + builddir = None + debugging = 0 + discard_temps = 1 + have_temps = 0 + icon_server = "." + image_type = "png" + logging = 0 + max_link_depth = 3 + max_split_depth = 6 + paper = "letter" + quiet = 0 + runs = 0 + numeric = 0 + global_module_index = None + style_file = os.path.join(TOPDIR, "html", "style.css") + about_file = os.path.join(TOPDIR, "html", "about.dat") + up_link = None + up_title = None + favicon = None + # + # 'dvips_safe' is a weird option. It is used mostly to make + # LaTeX2HTML not try to be too smart about protecting the user + # from a bad version of dvips -- some versions would core dump if + # the path to the source DVI contained a dot, and it's appearantly + # difficult to determine if the version available has that bug. + # This option gets set when PostScript output is requested + # (because we're going to run dvips regardless, and we'll either + # know it succeeds before LaTeX2HTML is run, or we'll have + # detected the failure and bailed), or the user asserts that it's + # safe from the command line. + # + # So, why does LaTeX2HTML think it appropriate to protect the user + # from a dvips that's only potentially going to core dump? Only + # because they want to avoid doing a lot of work just to have to + # bail later with no useful intermediates. Unfortunately, they + # bail *before* they know whether dvips will be needed at all. + # I've gone around the bush a few times with the LaTeX2HTML + # developers over whether this is appropriate behavior, and they + # don't seem interested in changing their position. + # + dvips_safe = 0 + # + DEFAULT_FORMATS = ("html",) + ALL_FORMATS = ("dvi", "html", "pdf", "ps", "text") + + def __init__(self): + self.formats = [] + self.l2h_init_files = [] + + def __getitem__(self, key): + # This is used when formatting the usage message. + try: + return getattr(self, key) + except AttributeError: + raise KeyError, key + + def parse(self, args): + opts, args = getopt.getopt(args, "Hi:a:s:lDkqr:", + ["all", "postscript", "help", "iconserver=", + "address=", "a4", "letter", "l2h-init=", + "link=", "split=", "logging", "debugging", + "keep", "quiet", "runs=", "image-type=", + "about=", "numeric", "style=", "paper=", + "up-link=", "up-title=", "dir=", + "global-module-index=", "dvips-safe", + "favicon="] + + list(self.ALL_FORMATS)) + for opt, arg in opts: + if opt == "--all": + self.formats = list(self.ALL_FORMATS) + self.dvips_safe = "ps" in self.formats + elif opt in ("-H", "--help"): + usage(self, sys.stdout) + sys.exit() + elif opt == "--iconserver": + self.icon_server = arg + elif opt in ("-a", "--address"): + self.address = arg + elif opt == "--a4": + self.paper = "a4" + elif opt == "--letter": + self.paper = "letter" + elif opt == "--link": + self.max_link_depth = int(arg) + elif opt in ("-s", "--split"): + self.max_split_depth = int(arg) + elif opt in ("-l", "--logging"): + self.logging = self.logging + 1 + elif opt in ("-D", "--debugging"): + self.debugging = self.debugging + 1 + elif opt in ("-k", "--keep"): + self.discard_temps = 0 + elif opt in ("-q", "--quiet"): + self.quiet = 1 + elif opt in ("-r", "--runs"): + self.runs = int(arg) + elif opt == "--image-type": + self.image_type = arg + elif opt == "--about": + # always make this absolute: + self.about_file = os.path.normpath( + os.path.abspath(arg)) + elif opt == "--numeric": + self.numeric = 1 + elif opt == "--style": + self.style_file = os.path.abspath(arg) + elif opt == "--l2h-init": + self.l2h_init_files.append(os.path.abspath(arg)) + elif opt == "--favicon": + self.favicon = arg + elif opt == "--up-link": + self.up_link = arg + elif opt == "--up-title": + self.up_title = arg + elif opt == "--global-module-index": + self.global_module_index = arg + elif opt == "--dir": + if os.sep == "\\": + arg = re.sub("/", "\\\\", arg) + self.builddir = os.path.expanduser(arg) + elif opt == "--paper": + self.paper = arg + elif opt == "--dvips-safe": + self.dvips_safe = 1 + # + # Format specifiers: + # + elif opt[2:] in self.ALL_FORMATS: + self.add_format(opt[2:]) + elif opt == "--postscript": + # synonym for --ps + self.add_format("ps") + self.initialize() + # + # return the args to allow the caller access: + # + return args + + def add_format(self, format): + """Add a format to the formats list if not present.""" + if not format in self.formats: + if format == "ps": + # assume this is safe since we're going to run it anyway + self.dvips_safe = 1 + self.formats.append(format) + + def initialize(self): + """Complete initialization. This is needed if parse() isn't used.""" + # add the default format if no formats were specified: + if not self.formats: + self.formats = self.DEFAULT_FORMATS + # determine the base set of texinputs directories: + texinputs = os.environ.get("TEXINPUTS", "").split(os.pathsep) + if not texinputs: + texinputs = [''] + mydirs = [os.path.join(TOPDIR, "paper-" + self.paper), + os.path.join(TOPDIR, "texinputs"), + ] + if '' in texinputs: + i = texinputs.index('') + texinputs[i:i] = mydirs + else: + texinputs += mydirs + self.base_texinputs = texinputs + if self.builddir: + self.builddir = os.path.abspath(self.builddir) + + +class Job: + latex_runs = 0 + + def __init__(self, options, path): + self.options = options + self.doctype = get_doctype(path) + self.filedir, self.doc = split_pathname(path) + self.builddir = os.path.abspath(options.builddir or self.doc) + if ("html" in options.formats or "text" in options.formats): + if not os.path.exists(self.builddir): + os.mkdir(self.builddir) + self.log_filename = os.path.join(self.builddir, self.doc + ".how") + else: + self.log_filename = os.path.abspath(self.doc + ".how") + if os.path.exists(self.log_filename): + os.unlink(self.log_filename) + l2hconf = self.doc + ".l2h" + if os.path.exists(l2hconf): + if os.path.exists(l2hconf + "~"): + os.unlink(l2hconf + "~") + os.rename(l2hconf, l2hconf + "~") + self.l2h_aux_init_file = self.doc + ".l2h" + self.write_l2h_aux_init_file() + + def build(self): + self.setup_texinputs() + formats = self.options.formats + if "dvi" in formats or "ps" in formats: + self.build_dvi() + if "pdf" in formats: + self.build_pdf() + if "ps" in formats: + self.build_ps() + if "html" in formats: + self.require_temps() + self.build_html(self.builddir) + if self.options.icon_server == ".": + pattern = os.path.join(TOPDIR, "html", "icons", + "*." + self.options.image_type) + imgs = glob.glob(pattern) + if not imgs: + self.warning( + "Could not locate support images of type %s." + % `self.options.image_type`) + for fn in imgs: + new_fn = os.path.join(self.builddir, os.path.basename(fn)) + shutil.copyfile(fn, new_fn) + if "text" in formats: + self.require_temps() + tempdir = self.doc + need_html = "html" not in formats + if self.options.max_split_depth != 1: + fp = open(self.l2h_aux_init_file, "a") + fp.write("# re-hack this file for --text:\n") + l2hoption(fp, "MAX_SPLIT_DEPTH", "1") + fp.write("1;\n") + fp.close() + tempdir = self.doc + "-temp-html" + need_html = 1 + if need_html: + self.build_html(tempdir, max_split_depth=1) + self.build_text(tempdir) + if self.options.discard_temps: + self.cleanup() + + def setup_texinputs(self): + texinputs = [self.filedir] + self.options.base_texinputs + os.environ["TEXINPUTS"] = os.pathsep.join(texinputs) + self.message("TEXINPUTS=" + os.environ["TEXINPUTS"]) + + def build_aux(self, binary=None): + if binary is None: + binary = LATEX_BINARY + new_index( "%s.ind" % self.doc, "genindex") + new_index("mod%s.ind" % self.doc, "modindex") + self.run("%s %s" % (binary, self.doc)) + self.use_bibtex = check_for_bibtex(self.doc + ".aux") + self.latex_runs = 1 + + def build_dvi(self): + self.use_latex(LATEX_BINARY) + + def build_pdf(self): + self.use_latex(PDFLATEX_BINARY) + + def use_latex(self, binary): + self.require_temps(binary=binary) + if self.latex_runs < 2: + if os.path.isfile("mod%s.idx" % self.doc): + self.run("%s mod%s.idx" % (MAKEINDEX_BINARY, self.doc)) + use_indfix = 0 + if os.path.isfile(self.doc + ".idx"): + use_indfix = 1 + # call to Doc/tools/fix_hack omitted; doesn't appear necessary + self.run("%s %s.idx" % (MAKEINDEX_BINARY, self.doc)) + import indfix + indfix.process(self.doc + ".ind") + if self.use_bibtex: + self.run("%s %s" % (BIBTEX_BINARY, self.doc)) + self.process_synopsis_files() + self.run("%s %s" % (binary, self.doc)) + self.latex_runs = self.latex_runs + 1 + if os.path.isfile("mod%s.idx" % self.doc): + self.run("%s -s %s mod%s.idx" + % (MAKEINDEX_BINARY, ISTFILE, self.doc)) + if use_indfix: + self.run("%s -s %s %s.idx" + % (MAKEINDEX_BINARY, ISTFILE, self.doc)) + indfix.process(self.doc + ".ind") + self.process_synopsis_files() + # + # and now finish it off: + # + if os.path.isfile(self.doc + ".toc") and binary == PDFLATEX_BINARY: + import toc2bkm + if self.doctype == "manual": + bigpart = "chapter" + else: + bigpart = "section" + toc2bkm.process(self.doc + ".toc", self.doc + ".bkm", bigpart) + if self.use_bibtex: + self.run("%s %s" % (BIBTEX_BINARY, self.doc)) + self.run("%s %s" % (binary, self.doc)) + self.latex_runs = self.latex_runs + 1 + + def process_synopsis_files(self): + synopsis_files = glob.glob(self.doc + "*.syn") + for path in synopsis_files: + uniqify_module_table(path) + + def build_ps(self): + self.run("%s -N0 -o %s.ps %s" % (DVIPS_BINARY, self.doc, self.doc)) + + def build_html(self, builddir, max_split_depth=None): + if max_split_depth is None: + max_split_depth = self.options.max_split_depth + texfile = None + for p in os.environ["TEXINPUTS"].split(os.pathsep): + fn = os.path.join(p, self.doc + ".tex") + if os.path.isfile(fn): + texfile = fn + break + if not texfile: + self.warning("Could not locate %s.tex; aborting." % self.doc) + sys.exit(1) + # remove leading ./ (or equiv.); might avoid problems w/ dvips + if texfile[:2] == os.curdir + os.sep: + texfile = texfile[2:] + # build the command line and run LaTeX2HTML: + if not os.path.isdir(builddir): + os.mkdir(builddir) + else: + for fname in glob.glob(os.path.join(builddir, "*.html")): + os.unlink(fname) + args = [LATEX2HTML_BINARY, + "-init_file", self.l2h_aux_init_file, + "-dir", builddir, + texfile + ] + self.run(" ".join(args)) # XXX need quoting! + # ... postprocess + shutil.copyfile(self.options.style_file, + os.path.join(builddir, self.doc + ".css")) + shutil.copyfile(os.path.join(builddir, self.doc + ".html"), + os.path.join(builddir, "index.html")) + if max_split_depth != 1: + label_file = os.path.join(builddir, "labels.pl") + fp = open(label_file) + about_node = None + target = " = q/about/;\n" + x = len(target) + while 1: + line = fp.readline() + if not line: + break + if line[-x:] == target: + line = fp.readline() + m = re.search(r"\|(node\d+\.[a-z]+)\|", line) + about_node = m.group(1) + shutil.copyfile(os.path.join(builddir, about_node), + os.path.join(builddir, "about.html")) + break + if not self.options.numeric: + pwd = os.getcwd() + try: + os.chdir(builddir) + self.run("%s %s *.html" % (PERL_BINARY, NODE2LABEL_SCRIPT)) + finally: + os.chdir(pwd) + # These files need to be cleaned up here since builddir there + # can be more than one, so we clean each of them. + if self.options.discard_temps: + for fn in ("images.tex", "images.log", "images.aux"): + safe_unlink(os.path.join(builddir, fn)) + + def build_text(self, tempdir=None): + if tempdir is None: + tempdir = self.doc + indexfile = os.path.join(tempdir, "index.html") + self.run("%s -nolist -dump %s >%s.txt" + % (LYNX_BINARY, indexfile, self.doc)) + + def require_temps(self, binary=None): + if not self.latex_runs: + self.build_aux(binary=binary) + + def write_l2h_aux_init_file(self): + options = self.options + fp = open(self.l2h_aux_init_file, "w") + d = string_to_perl(os.path.dirname(L2H_INIT_FILE)) + fp.write("package main;\n" + "push (@INC, '%s');\n" + "$mydir = '%s';\n" + % (d, d)) + fp.write(open(L2H_INIT_FILE).read()) + for filename in options.l2h_init_files: + fp.write("\n# initialization code incorporated from:\n# ") + fp.write(filename) + fp.write("\n") + fp.write(open(filename).read()) + fp.write("\n" + "# auxillary init file for latex2html\n" + "# generated by mkhowto\n" + "$NO_AUTO_LINK = 1;\n" + ) + l2hoption(fp, "ABOUT_FILE", options.about_file) + l2hoption(fp, "ICONSERVER", options.icon_server) + l2hoption(fp, "IMAGE_TYPE", options.image_type) + l2hoption(fp, "ADDRESS", options.address) + l2hoption(fp, "MAX_LINK_DEPTH", options.max_link_depth) + l2hoption(fp, "MAX_SPLIT_DEPTH", options.max_split_depth) + l2hoption(fp, "EXTERNAL_UP_LINK", options.up_link) + l2hoption(fp, "EXTERNAL_UP_TITLE", options.up_title) + l2hoption(fp, "FAVORITES_ICON", options.favicon) + l2hoption(fp, "GLOBAL_MODULE_INDEX", options.global_module_index) + l2hoption(fp, "DVIPS_SAFE", options.dvips_safe) + fp.write("1;\n") + fp.close() + + def cleanup(self): + self.__have_temps = 0 + for pattern in ("%s.aux", "%s.log", "%s.out", "%s.toc", "%s.bkm", + "%s.idx", "%s.ilg", "%s.ind", "%s.pla", + "%s.bbl", "%s.blg", + "mod%s.idx", "mod%s.ind", "mod%s.ilg", + ): + safe_unlink(pattern % self.doc) + map(safe_unlink, glob.glob(self.doc + "*.syn")) + for spec in ("IMG*", "*.pl", "WARNINGS", "index.dat", "modindex.dat"): + pattern = os.path.join(self.doc, spec) + map(safe_unlink, glob.glob(pattern)) + if "dvi" not in self.options.formats: + safe_unlink(self.doc + ".dvi") + if os.path.isdir(self.doc + "-temp-html"): + shutil.rmtree(self.doc + "-temp-html", ignore_errors=1) + if not self.options.logging: + os.unlink(self.log_filename) + if not self.options.debugging: + os.unlink(self.l2h_aux_init_file) + + def run(self, command): + self.message(command) + if sys.platform.startswith("win"): + rc = os.system(command) + else: + rc = os.system("(%s) </dev/null >>%s 2>&1" + % (command, self.log_filename)) + if rc: + self.warning( + "Session transcript and error messages are in %s." + % self.log_filename) + result = 1 + if hasattr(os, "WIFEXITED"): + if os.WIFEXITED(rc): + result = os.WEXITSTATUS(rc) + self.warning("Exited with status %s." % result) + else: + self.warning("Killed by signal %s." % os.WSTOPSIG(rc)) + else: + self.warning("Return code: %s" % rc) + sys.stderr.write("The relevant lines from the transcript are:\n") + sys.stderr.write("-" * 72 + "\n") + sys.stderr.writelines(get_run_transcript(self.log_filename)) + sys.exit(result) + + def message(self, msg): + msg = "+++ " + msg + if not self.options.quiet: + print msg + self.log(msg + "\n") + + def warning(self, msg): + msg = "*** %s\n" % msg + sys.stderr.write(msg) + self.log(msg) + + def log(self, msg): + fp = open(self.log_filename, "a") + fp.write(msg) + fp.close() + + +def get_run_transcript(filename): + """Return lines from the transcript file for the most recent run() call.""" + fp = open(filename) + lines = fp.readlines() + fp.close() + lines.reverse() + L = [] + for line in lines: + L.append(line) + if line[:4] == "+++ ": + break + L.reverse() + return L + + +def safe_unlink(path): + """Unlink a file without raising an error if it doesn't exist.""" + try: + os.unlink(path) + except os.error: + pass + + +def split_pathname(path): + path = os.path.abspath(path) + dirname, basename = os.path.split(path) + if basename[-4:] == ".tex": + basename = basename[:-4] + return dirname, basename + + +_doctype_rx = re.compile(r"\\documentclass(?:\[[^]]*\])?{([a-zA-Z]*)}") +def get_doctype(path): + fp = open(path) + doctype = None + while 1: + line = fp.readline() + if not line: + break + m = _doctype_rx.match(line) + if m: + doctype = m.group(1) + break + fp.close() + return doctype + + +def main(): + options = Options() + try: + args = options.parse(sys.argv[1:]) + except getopt.error, msg: + error(options, msg) + if not args: + # attempt to locate single .tex file in current directory: + args = glob.glob("*.tex") + if not args: + error(options, "No file to process.") + if len(args) > 1: + error(options, "Could not deduce which files should be processed.") + # + # parameters are processed, let's go! + # + for path in args: + Job(options, path).build() + + +def l2hoption(fp, option, value): + if value: + fp.write('$%s = "%s";\n' % (option, string_to_perl(str(value)))) + + +_to_perl = {} +for c in map(chr, range(1, 256)): + _to_perl[c] = c +_to_perl["@"] = "\\@" +_to_perl["$"] = "\\$" +_to_perl['"'] = '\\"' + +def string_to_perl(s): + return ''.join(map(_to_perl.get, s)) + + +def check_for_bibtex(filename): + fp = open(filename) + pos = fp.read().find(r"\bibdata{") + fp.close() + return pos >= 0 + +def uniqify_module_table(filename): + lines = open(filename).readlines() + if len(lines) > 1: + if lines[-1] == lines[-2]: + del lines[-1] + open(filename, "w").writelines(lines) + + +def new_index(filename, label="genindex"): + fp = open(filename, "w") + fp.write(r"""\ +\begin{theindex} +\label{%s} +\end{theindex} +""" % label) + fp.close() + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/mkinfo b/sys/src/cmd/python/Doc/tools/mkinfo new file mode 100755 index 000000000..be75168fd --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/mkinfo @@ -0,0 +1,65 @@ +#! /bin/sh +# -*- Ksh -*- + +# Script to drive the HTML-info conversion process. +# Pass in upto three parameters: +# - the name of the main tex file +# - the name of the output file in texi format (optional) +# - the name of the output file in info format (optional) +# +# Written by Fred L. Drake, Jr. <fdrake@acm.org> + +EMACS=${EMACS:-emacs} +MAKEINFO=${MAKEINFO:-makeinfo} + + +# Normalize file name since something called by html2texi.pl seems to +# screw up with relative path names. +FILENAME="$1" +DOCDIR=`dirname "$FILENAME"` +DOCFILE=`basename "$FILENAME"` +DOCNAME=`basename "$FILENAME" .tex` +if [ $# -gt 1 ]; then + TEXINAME="$2" +else + TEXINAME="python-$DOCNAME.texi" +fi +if [ $# -gt 2 ]; then + INFONAME="$3" +else + INFONAME="python-$DOCNAME.info" +fi + +# Now build the real directory names, and locate our support stuff: +WORKDIR=`pwd` +cd `dirname $0` +TOOLSDIR=`pwd` +cd $DOCDIR +DOCDIR=`pwd` +cd $WORKDIR + +COMMONDIR="`dirname $DOCDIR`/commontex" + + +run() { + # show what we're doing, like make does: + echo "$*" + "$@" || exit $? +} + + +# generate the Texinfo file: + +run $EMACS -batch -q --no-site-file -l $TOOLSDIR/py2texi.el \ + --eval "(setq py2texi-dirs '(\"$DOCDIR\" \"$COMMONDIR\" \"../texinputs\"))" \ + --eval "(setq py2texi-texi-file-name \"$TEXINAME\")" \ + --eval "(setq py2texi-info-file-name \"$INFONAME\")" \ + --eval "(py2texi \"$DOCDIR/$DOCFILE\")" \ + -f kill-emacs +echo Done + + +# generate the .info files: + +run $MAKEINFO --footnote-style end --fill-column 72 \ + --paragraph-indent 0 --output=$INFONAME $TEXINAME diff --git a/sys/src/cmd/python/Doc/tools/mkmodindex b/sys/src/cmd/python/Doc/tools/mkmodindex new file mode 100755 index 000000000..8e869f926 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/mkmodindex @@ -0,0 +1,158 @@ +#! /usr/bin/env python +# -*- Python -*- + +"""usage: %(program)s [options] file... + +Supported options: + + --address addr + -a addr Set the address text to include at the end of the generated + HTML; this should be used for contact information. + --columns cols + -c cols Set the number of columns each index section should be + displayed in. The default is 1. + --help + -h Display this help message. + --letters + -l Split the output into sections by letter. + --output file + -o file Write output to 'file' instead of standard out. + --iconserver is Use 'is' as the directory containing icons for the + navigation bar. The default is 'icons'. + --title str Set the page title to 'str'. The default is 'Global + Module Index'. + --uplink url Set the upward link URL. The default is './'. + --uptitle str Set the upward link title. The default is 'Python + Documentation Index'. +""" +import os +import re +import sys + +from xml.sax.saxutils import quoteattr + +import buildindex +import support + + +class IndexOptions(support.Options): + aesop_type = "links" + + def __init__(self): + support.Options.__init__(self) + self.add_args("l", ["letters"]) + self.letters = 0 + + def handle_option(self, opt, val): + if opt in ("-l", "--letters"): + self.letters = 1 + + def usage(self): + program = os.path.basename(sys.argv[0]) + print __doc__ % {"program": program} + + links = [ + ('author', 'acks.html', 'Acknowledgements'), + ('help', 'about.html', 'About the Python Documentation'), + ] + + def get_header(self): + header = support.Options.get_header(self) + s = '' + for rel, href, title in self.links: + s += '<link rel="%s" href="%s"' % (rel, href) + if title: + s += ' title=' + quoteattr(title) + s += '>\n ' + return header.replace("<link ", s + "<link ", 1) + + +class Node(buildindex.Node): + def __init__(self, link, str, seqno, platinfo): + self.annotation = platinfo or None + if str[0][-5:] == "</tt>": + str = str[:-5] + self.modname = str + buildindex.Node.__init__(self, link, self.modname, seqno) + if platinfo: + s = '<tt class="module">%s</tt> %s' \ + % (self.modname, self.annotation) + else: + s = '<tt class="module">%s</tt>' % str + self.text = [s] + + def __str__(self): + if self.annotation: + return '<tt class="module">%s</tt> %s' \ + % (self.modname, self.annotation) + else: + return '<tt class="module">%s</tt>' % self.modname + +_rx = re.compile( + "<dt><a href=['\"](module-.*\.html)(?:#l2h-\d+)?['\"]>" + "<tt class=['\"]module['\"]>([a-zA-Z_][a-zA-Z0-9_.]*)</tt>\s*(<em>" + "\(<span class=['\"]platform['\"]>.*</span>\)</em>)?</a>") + +def main(): + options = IndexOptions() + options.variables["title"] = "Global Module Index" + options.parse(sys.argv[1:]) + args = options.args + if not args: + args = ["-"] + # + # Collect the input data: + # + nodes = [] + has_plat_flag = 0 + for ifn in args: + if ifn == "-": + ifp = sys.stdin + dirname = '' + else: + ifp = open(ifn) + dirname = os.path.dirname(ifn) + while 1: + line = ifp.readline() + if not line: + break + m = _rx.match(line) + if m: + # This line specifies a module! + basename, modname, platinfo = m.group(1, 2, 3) + has_plat_flag = has_plat_flag or platinfo + linkfile = os.path.join(dirname, basename) + nodes.append(Node('<a href="%s">' % linkfile, modname, + len(nodes), platinfo)) + ifp.close() + # + # Generate all output: + # + num_nodes = len(nodes) + # Here's the HTML generation: + parts = [options.get_header(), + buildindex.process_nodes(nodes, options.columns, options.letters), + options.get_footer(), + ] + if has_plat_flag: + parts.insert(1, PLAT_DISCUSS) + html = ''.join(parts) + program = os.path.basename(sys.argv[0]) + fp = options.get_output_file() + fp.write(html.rstrip() + "\n") + if options.outputfile == "-": + sys.stderr.write("%s: %d index nodes\n" % (program, num_nodes)) + else: + print + print "%s: %d index nodes" % (program, num_nodes) + + +PLAT_DISCUSS = """ +<p> Some module names are followed by an annotation indicating what +platform they are available on.</p> + +""" + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/mkpkglist b/sys/src/cmd/python/Doc/tools/mkpkglist new file mode 100755 index 000000000..1a1fd78f2 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/mkpkglist @@ -0,0 +1,85 @@ +#! /usr/bin/env python +# +# Simple script to create the table that lists the packages available +# for download. This expects the downloadable files and the Makefile +# to be in the current directory. +# +# The output of this script can be pasted directly into the download +# page for the documentation. + +import os +import sys + +from os.path import isfile + + +PKG_TYPES = [ + # human name, filename prefix + ("HTML", "html"), + ("PDF (US-Letter)", "pdf-letter"), + ("PDF (A4)", "pdf-a4"), + ("PostScript (US-Letter)", "postscript-letter"), + ("PostScript (A4)", "postscript-a4"), + ("GNU info", "info"), + ("iSilo", "isilo"), + ("LaTeX", "latex"), + ] + +getversioninfo = os.path.join(os.path.dirname(__file__), "getversioninfo") +fp = os.popen('"%s" "%s"' % (sys.executable, getversioninfo), "r") +release = fp.readline().strip() +fp.close() + +print '''\ +<table border="1" cellpadding="3" align="center"> + <thead> + <tr bgcolor="#99ccff"><th rowspan="2">Content</th> + <th colspan="3">Format</th></tr> + <tr bgcolor="#99ccff"><th>ZIP</th><th>GZip</th><th>BZip2</th></tr> + </thead> + <tbody>''' + +# formatted using FILE_TEMPLATE % (release, prefix, release, extension) +FILE_TEMPLATE = '''\ + <td><a href="../../ftp/python/doc/%s/%s-%s%s" + >%dK</a></td>''' + +NO_FILE_TEMPLATE = '''\ + <td>&nbsp;</td>''' + +def get_size(prefix, ext): + fn = "%s-%s%s" % (prefix, release, ext) + return int(round(os.path.getsize(fn) / 1024.0)) + +def get_file_cell(prefix, ext, have): + if have: + kb = get_size(prefix, ext) + return FILE_TEMPLATE % (release, prefix, release, ext, kb) + else: + return NO_FILE_TEMPLATE + +for name, prefix in PKG_TYPES: + zip_fn = "%s-%s.zip" % (prefix, release) + tgz_fn = "%s-%s.tgz" % (prefix, release) + bz2_fn = "%s-%s.tar.bz2" % (prefix, release) + + have_zip = isfile(zip_fn) + have_tgz = isfile(tgz_fn) + have_bz2 = isfile(bz2_fn) + + have_some = have_zip or have_tgz or have_bz2 + + if not have_some: + print " <!--" + print " <tr><td>%s</td>" % name + print get_file_cell(prefix, ".zip", have_zip) + print get_file_cell(prefix, ".tgz", have_tgz) + print get_file_cell(prefix, ".tar.bz2", have_bz2) + print " </tr>" + if not have_some: + print " -->" + +print '''\ + </tbody> +</table> +''' diff --git a/sys/src/cmd/python/Doc/tools/mksourcepkg b/sys/src/cmd/python/Doc/tools/mksourcepkg new file mode 100755 index 000000000..4b21f7747 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/mksourcepkg @@ -0,0 +1,164 @@ +#! /usr/bin/env python +# -*- Python -*- + +"""%(program)s - script to create the latex source distribution + +usage: + %(program)s [-t|--tools] release [tag] + +with -t|--tools: doesn't include the documents, only the framework + +without [tag]: generate from the current version that's checked in + (*NOT* what's in the current directory!) + +with [tag]: generate from the named tag +""" +#* should be modified to get the Python version number automatically +# from the Makefile or someplace. + +import getopt +import glob +import os +import re +import shutil +import sys +import tempfile + +try: + __file__ +except NameError: + __file__ = sys.argv[0] + +tools = os.path.dirname(os.path.abspath(__file__)) +Doc = os.path.dirname(tools) +patchlevel_tex = os.path.join(Doc, "commontex", "patchlevel.tex") + +quiet = 0 +rx = re.compile(r":ext:(?:[a-zA-Z0-9]+@)?cvs\.([a-zA-Z0-9]+).sourceforge.net:" + r"/cvsroot/\1") + + +def main(): + global quiet + anonymous = False + try: + opts, args = getopt.getopt(sys.argv[1:], "Aabgtzq", + ["all", "bzip2", "gzip", "tools", "zip", + "quiet", "anonymous"]) + except getopt.error, e: + usage(warning=str(e)) + sys.exit(2) + if len(args) not in (1, 2): + usage(warning="wrong number of parameters") + sys.exit(2) + tools = 0 + formats = {} + for opt, arg in opts: + if opt in ("-t", "--tools"): + tools = 1 + elif opt in ("-q", "--quiet"): + quiet = quiet + 1 + elif opt in ("-b", "--bzip2"): + formats["bzip2"] = 1 + elif opt in ("-g", "--gzip"): + formats["gzip"] = 1 + elif opt in ("-z", "--zip"): + formats["zip"] = 1 + elif opt in ("-a", "--all"): + formats["bzip2"] = 1 + formats["gzip"] = 1 + formats["zip"] = 1 + elif opt in ("-A", "--anonymous"): + anonymous = True + if formats: + # make order human-predictable + formats = formats.keys() + formats.sort() + else: + formats = ["gzip"] + release = args[0] + svntag = None + if len(args) > 1: + svntag = args[1] + tempdir = tempfile.mktemp() + os.mkdir(tempdir) + pkgdir = os.path.join(tempdir, "Python-Docs-" + release) + pwd = os.getcwd() + mydir = os.path.abspath(os.path.dirname(sys.argv[0])) + os.chdir(tempdir) + if not quiet: + print "--- current directory is:", tempdir + if not svntag: + svntag = "trunk" + svnbase = "http://svn.python.org/projects/python" + run("svn export %s/%s/Doc Python-Docs-%s" + % (svnbase, svntag, release)) + + # Copy in the version informtation, if we're not just going to + # rip it back out: + if not tools: + if not os.path.exists(patchlevel_tex): + run(os.path.join(here, "getversioninfo")) + dest = os.path.join("Python-Docs-" + release, "commontex", + "patchlevel.tex") + shutil.copyfile(patchlevel_tex, dest) + + # Copy in the license file: + LICENSE = os.path.normpath( + os.path.join(mydir, os.pardir, os.pardir, "LICENSE")) + shutil.copyfile(LICENSE, "LICENSE") + if tools: + archive = "doctools-" + release + # we don't want the actual documents in this case: + for d in ("api", "dist", "doc", "ext", "inst", + "lib", "mac", "ref", "tut", "commontex"): + shutil.rmtree(os.path.join(pkgdir, d)) + else: + archive = "latex-" + release + + # XXX should also remove the .cvsignore files at this point + + os.chdir(tempdir) + archive = os.path.join(pwd, archive) + for format in formats: + if format == "bzip2": + run("tar cf - Python-Docs-%s | bzip2 -9 >%s.tar.bz2" + % (release, archive)) + elif format == "gzip": + run("tar cf - Python-Docs-%s | gzip -9 >%s.tgz" + % (release, archive)) + elif format == "zip": + if os.path.exists(archive + ".zip"): + os.unlink(archive + ".zip") + run("zip -q -r9 %s.zip Python-Docs-%s" + % (archive, release)) + + # clean up the work area: + os.chdir(pwd) + shutil.rmtree(tempdir) + + +def run(cmd): + if quiet < 2: + print "+++", cmd + if quiet: + cmd = "%s >/dev/null" % cmd + rc = os.system(cmd) + if rc: + sys.exit(rc) + + +def usage(warning=None): + stdout = sys.stdout + sys.stdout = sys.stderr + program = os.path.basename(sys.argv[0]) + try: + if warning: + print "%s: %s\n" % (program, warning) + print __doc__ % {"program": program} + finally: + sys.stdout = stdout + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/node2label.pl b/sys/src/cmd/python/Doc/tools/node2label.pl new file mode 100755 index 000000000..6491b2048 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/node2label.pl @@ -0,0 +1,71 @@ +#! /usr/bin/env perl + +# On Cygwin, we actually have to generate a temporary file when doing +# the inplace edit, or we'll get permission errors. Not sure who's +# bug this is, except that it isn't ours. To deal with this, we +# generate backups during the edit phase and remove them at the end. +# +use English; +$INPLACE_EDIT = '.bak'; + +# read the labels, then reverse the mappings +require "labels.pl"; + +%nodes = (); +my $key; +# sort so that we get a consistent assignment for nodes with multiple labels +foreach $label (sort keys %external_labels) { + # + # If the label can't be used as a filename on non-Unix platforms, + # skip it. Such labels may be used internally within the documentation, + # but will never be used for filename generation. + # + if ($label =~ /^([-.a-zA-Z0-9]+)$/) { + $key = $external_labels{$label}; + $key =~ s|^/||; + $nodes{$key} = $label; + } +} + +# This adds the "internal" labels added for indexing. These labels will not +# be used for file names. +require "intlabels.pl"; +foreach $label (keys %internal_labels) { + $key = $internal_labels{$label}; + $key =~ s|^/||; + if (defined($nodes{$key})) { + $nodes{$label} = $nodes{$key}; + } +} + +# collect labels that have been used +%newnames = (); + +while (<>) { + # don't want to do one s/// per line per node + # so look for lines with hrefs, then do s/// on nodes present + if (/(HREF|href)=[\"\']node\d+\.html[\#\"\']/) { + @parts = split(/(HREF|href)\=[\"\']/); + shift @parts; + for $node (@parts) { + $node =~ s/[\#\"\'].*$//g; + chomp($node); + if (defined($nodes{$node})) { + $label = $nodes{$node}; + if (s/(HREF|href)=([\"\'])$node([\#\"\'])/href=$2$label.html$3/g) { + s/(HREF|href)=([\"\'])$label.html/href=$2$label.html/g; + $newnames{$node} = "$label.html"; + } + } + } + } + print; +} + +foreach $oldname (keys %newnames) { + rename($oldname, $newnames{$oldname}); +} + +foreach $filename (glob('*.bak')) { + unlink($filename); +} diff --git a/sys/src/cmd/python/Doc/tools/prechm.py b/sys/src/cmd/python/Doc/tools/prechm.py new file mode 100644 index 000000000..57a43fd6f --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/prechm.py @@ -0,0 +1,519 @@ +""" + Makes the necesary files to convert from plain html of + Python 1.5 and 1.5.x Documentation to + Microsoft HTML Help format version 1.1 + Doesn't change the html's docs. + + by hernan.foffani@iname.com + no copyright and no responsabilities. + + modified by Dale Nagata for Python 1.5.2 + + Renamed from make_chm.py to prechm.py, and checked into the Python + project, 19-Apr-2002 by Tim Peters. Assorted modifications by Tim + and Fred Drake. Obtained from Robin Dunn's .chm packaging of the + Python 2.2 docs, at <http://alldunn.com/python/>. +""" + +import sys +import os +from formatter import NullWriter, AbstractFormatter +from htmllib import HTMLParser +import getopt +import cgi + +usage_mode = ''' +Usage: prechm.py [-c] [-k] [-p] [-v 1.5[.x]] filename + -c: does not build filename.hhc (Table of Contents) + -k: does not build filename.hhk (Index) + -p: does not build filename.hhp (Project File) + -v 1.5[.x]: makes help for the python 1.5[.x] docs + (default is python 1.5.2 docs) +''' + +# Project file (*.hhp) template. 'arch' is the file basename (like +# the pythlp in pythlp.hhp); 'version' is the doc version number (like +# the 2.2 in Python 2.2). +# The magical numbers in the long line under [WINDOWS] set most of the +# user-visible features (visible buttons, tabs, etc). +# About 0x10384e: This defines the buttons in the help viewer. The +# following defns are taken from htmlhelp.h. Not all possibilities +# actually work, and not all those that work are available from the Help +# Workshop GUI. In particular, the Zoom/Font button works and is not +# available from the GUI. The ones we're using are marked with 'x': +# +# 0x000002 Hide/Show x +# 0x000004 Back x +# 0x000008 Forward x +# 0x000010 Stop +# 0x000020 Refresh +# 0x000040 Home x +# 0x000080 Forward +# 0x000100 Back +# 0x000200 Notes +# 0x000400 Contents +# 0x000800 Locate x +# 0x001000 Options x +# 0x002000 Print x +# 0x004000 Index +# 0x008000 Search +# 0x010000 History +# 0x020000 Favorites +# 0x040000 Jump 1 +# 0x080000 Jump 2 +# 0x100000 Zoom/Font x +# 0x200000 TOC Next +# 0x400000 TOC Prev + +project_template = ''' +[OPTIONS] +Compiled file=%(arch)s.chm +Contents file=%(arch)s.hhc +Default Window=%(arch)s +Default topic=index.html +Display compile progress=No +Full text search stop list file=%(arch)s.stp +Full-text search=Yes +Index file=%(arch)s.hhk +Language=0x409 +Title=Python %(version)s Documentation + +[WINDOWS] +%(arch)s="Python %(version)s Documentation","%(arch)s.hhc","%(arch)s.hhk",\ +"index.html","index.html",,,,,0x63520,220,0x10384e,[0,0,1024,768],,,,,,,0 + +[FILES] +''' + +contents_header = '''\ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<HTML> +<HEAD> +<meta name="GENERATOR" content="Microsoft&reg; HTML Help Workshop 4.1"> +<!-- Sitemap 1.0 --> +</HEAD><BODY> +<OBJECT type="text/site properties"> + <param name="Window Styles" value="0x801227"> + <param name="ImageType" value="Folder"> +</OBJECT> +<UL> +''' + +contents_footer = '''\ +</UL></BODY></HTML> +''' + +object_sitemap = '''\ +<OBJECT type="text/sitemap"> + <param name="Name" value="%s"> + <param name="Local" value="%s"> +</OBJECT> +''' + +# List of words the full text search facility shouldn't index. This +# becomes file ARCH.stp. Note that this list must be pretty small! +# Different versions of the MS docs claim the file has a maximum size of +# 256 or 512 bytes (including \r\n at the end of each line). +# Note that "and", "or", "not" and "near" are operators in the search +# language, so no point indexing them even if we wanted to. +stop_list = ''' +a and are as at +be but by +for +if in into is it +near no not +of on or +such +that the their then there these they this to +was will with +''' + +# s is a string or None. If None or empty, return None. Else tack '.html' +# on to the end, unless it's already there. +def addhtml(s): + if s: + if not s.endswith('.html'): + s += '.html' + return s + +# Convenience class to hold info about "a book" in HTMLHelp terms == a doc +# directory in Python terms. +class Book: + def __init__(self, directory, title, firstpage, + contentpage=None, indexpage=None): + self.directory = directory + self.title = title + self.firstpage = addhtml(firstpage) + self.contentpage = addhtml(contentpage) + self.indexpage = addhtml(indexpage) + +# Library Doc list of books: +# each 'book' : (Dir, Title, First page, Content page, Index page) +supported_libraries = { + '2.5': + [ + Book('.', 'Main page', 'index'), + Book('.', 'Global Module Index', 'modindex'), + Book('whatsnew', "What's New", 'index', 'contents'), + Book('tut','Tutorial','tut','node2'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref','contents','genindex'), + Book('mac','Macintosh Reference','mac','contents','genindex'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex'), + Book('doc','Documenting Python','doc','contents'), + Book('inst','Installing Python Modules', 'inst', 'index'), + Book('dist','Distributing Python Modules', 'dist', 'index', 'genindex'), + ], + + '2.4': + [ + Book('.', 'Main page', 'index'), + Book('.', 'Global Module Index', 'modindex'), + Book('whatsnew', "What's New", 'index', 'contents'), + Book('tut','Tutorial','tut','node2'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref','contents','genindex'), + Book('mac','Macintosh Reference','mac','contents','genindex'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex'), + Book('doc','Documenting Python','doc','contents'), + Book('inst','Installing Python Modules', 'inst', 'index'), + Book('dist','Distributing Python Modules', 'dist', 'index', 'genindex'), + ], + + '2.3': + [ + Book('.', 'Main page', 'index'), + Book('.', 'Global Module Index', 'modindex'), + Book('whatsnew', "What's New", 'index', 'contents'), + Book('tut','Tutorial','tut','node2'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref','contents','genindex'), + Book('mac','Macintosh Reference','mac','contents','genindex'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex'), + Book('doc','Documenting Python','doc','contents'), + Book('inst','Installing Python Modules', 'inst', 'index'), + Book('dist','Distributing Python Modules', 'dist', 'index'), + ], + + '2.2': + [ + Book('.', 'Main page', 'index'), + Book('.', 'Global Module Index', 'modindex'), + Book('whatsnew', "What's New", 'index', 'contents'), + Book('tut','Tutorial','tut','node2'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref','contents','genindex'), + Book('mac','Macintosh Reference','mac','contents','genindex'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex'), + Book('doc','Documenting Python','doc','contents'), + Book('inst','Installing Python Modules', 'inst', 'index'), + Book('dist','Distributing Python Modules', 'dist', 'index'), + ], + + '2.1.1': + [ + Book('.', 'Main page', 'index'), + Book('.', 'Global Module Index', 'modindex'), + Book('tut','Tutorial','tut','node2'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref','contents','genindex'), + Book('mac','Macintosh Reference','mac','contents','genindex'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex'), + Book('doc','Documenting Python','doc','contents'), + Book('inst','Installing Python Modules', 'inst', 'index'), + Book('dist','Distributing Python Modules', 'dist', 'index'), + ], + + '2.0.0': + [ + Book('.', 'Global Module Index', 'modindex'), + Book('tut','Tutorial','tut','node2'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref','contents','genindex'), + Book('mac','Macintosh Reference','mac','contents','genindex'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex'), + Book('doc','Documenting Python','doc','contents'), + Book('inst','Installing Python Modules', 'inst', 'contents'), + Book('dist','Distributing Python Modules', 'dist', 'contents'), + ], + + # <dnagata@creo.com> Apr 17/99: library for 1.5.2 version: + # <hernan.foffani@iname.com> May 01/99: library for 1.5.2 (04/30/99): + '1.5.2': + [ + Book('tut','Tutorial','tut','node2'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref','contents','genindex'), + Book('mac','Macintosh Reference','mac','contents','genindex'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex'), + Book('doc','Documenting Python','doc','contents') + ], + + # library for 1.5.1 version: + '1.5.1': + [ + Book('tut','Tutorial','tut','contents'), + Book('lib','Library Reference','lib','contents','genindex'), + Book('ref','Language Reference','ref-1','ref-2','ref-11'), + Book('ext','Extending and Embedding','ext','contents'), + Book('api','Python/C API','api','contents','genindex') + ], + + # library for 1.5 version: + '1.5': + [ + Book('tut','Tutorial','tut','node1'), + Book('lib','Library Reference','lib','node1','node268'), + Book('ref','Language Reference','ref-1','ref-2','ref-11'), + Book('ext','Extending and Embedding','ext','node1'), + Book('api','Python/C API','api','node1','node48') + ] +} + +# AlmostNullWriter doesn't print anything; it just arranges to save the +# text sent to send_flowing_data(). This is used to capture the text +# between an anchor begin/end pair, e.g. for TOC entries. + +class AlmostNullWriter(NullWriter): + + def __init__(self): + NullWriter.__init__(self) + self.saved_clear() + + def send_flowing_data(self, data): + stripped = data.strip() + if stripped: # don't bother to save runs of whitespace + self.saved.append(stripped) + + # Forget all saved text. + def saved_clear(self): + self.saved = [] + + # Return all saved text as a string. + def saved_get(self): + return ' '.join(self.saved) + +class HelpHtmlParser(HTMLParser): + + def __init__(self, formatter, path, output): + HTMLParser.__init__(self, formatter) + self.path = path # relative path + self.ft = output # output file + self.indent = 0 # number of tabs for pretty printing of files + self.proc = False # True when actively processing, else False + # (headers, footers, etc) + # XXX This shouldn't need to be a stack -- anchors shouldn't nest. + # XXX See SF bug <http://www.python.org/sf/546579>. + self.hrefstack = [] # stack of hrefs from anchor begins + + def begin_group(self): + self.indent += 1 + self.proc = True + + def finish_group(self): + self.indent -= 1 + # stop processing when back to top level + self.proc = self.indent > 0 + + def anchor_bgn(self, href, name, type): + if self.proc: + # XXX See SF bug <http://www.python.org/sf/546579>. + # XXX index.html for the 2.2.1 language reference manual contains + # XXX nested <a></a> tags in the entry for the section on blank + # XXX lines. We want to ignore the nested part completely. + if len(self.hrefstack) == 0: + self.saved_clear() + self.hrefstack.append(href) + + def anchor_end(self): + if self.proc: + # XXX See XXX above. + if self.hrefstack: + title = cgi.escape(self.saved_get(), True) + path = self.path + '/' + self.hrefstack.pop() + self.tab(object_sitemap % (title, path)) + + def start_dl(self, atr_val): + self.begin_group() + + def end_dl(self): + self.finish_group() + + def do_dt(self, atr_val): + # no trailing newline on purpose! + self.tab("<LI>") + + # Write text to output file. + def write(self, text): + self.ft.write(text) + + # Write text to output file after indenting by self.indent tabs. + def tab(self, text=''): + self.write('\t' * self.indent) + if text: + self.write(text) + + # Forget all saved text. + def saved_clear(self): + self.formatter.writer.saved_clear() + + # Return all saved text as a string. + def saved_get(self): + return self.formatter.writer.saved_get() + +class IdxHlpHtmlParser(HelpHtmlParser): + # nothing special here, seems enough with parent class + pass + +class TocHlpHtmlParser(HelpHtmlParser): + + def start_dl(self, atr_val): + self.begin_group() + self.tab('<UL>\n') + + def end_dl(self): + self.finish_group() + self.tab('</UL>\n') + + def start_ul(self, atr_val): + self.begin_group() + self.tab('<UL>\n') + + def end_ul(self): + self.finish_group() + self.tab('</UL>\n') + + def do_li(self, atr_val): + # no trailing newline on purpose! + self.tab("<LI>") + +def index(path, indexpage, output): + parser = IdxHlpHtmlParser(AbstractFormatter(AlmostNullWriter()), + path, output) + f = open(path + '/' + indexpage) + parser.feed(f.read()) + parser.close() + f.close() + +def content(path, contentpage, output): + parser = TocHlpHtmlParser(AbstractFormatter(AlmostNullWriter()), + path, output) + f = open(path + '/' + contentpage) + parser.feed(f.read()) + parser.close() + f.close() + +def do_index(library, output): + output.write('<UL>\n') + for book in library: + print '\t', book.title, '-', book.indexpage + if book.indexpage: + index(book.directory, book.indexpage, output) + output.write('</UL>\n') + +def do_content(library, version, output): + output.write(contents_header) + for book in library: + print '\t', book.title, '-', book.firstpage + path = book.directory + "/" + book.firstpage + output.write('<LI>') + output.write(object_sitemap % (book.title, path)) + if book.contentpage: + content(book.directory, book.contentpage, output) + output.write(contents_footer) + +# Fill in the [FILES] section of the project (.hhp) file. +# 'library' is the list of directory description tuples from +# supported_libraries for the version of the docs getting generated. +def do_project(library, output, arch, version): + output.write(project_template % locals()) + pathseen = {} + for book in library: + directory = book.directory + path = directory + '\\%s\n' + for page in os.listdir(directory): + if page.endswith('.html') or page.endswith('.css'): + fullpath = path % page + if fullpath not in pathseen: + output.write(fullpath) + pathseen[fullpath] = True + +def openfile(file): + try: + p = open(file, "w") + except IOError, msg: + print file, ":", msg + sys.exit(1) + return p + +def usage(): + print usage_mode + sys.exit(0) + +def do_it(args = None): + if not args: + args = sys.argv[1:] + + if not args: + usage() + + try: + optlist, args = getopt.getopt(args, 'ckpv:') + except getopt.error, msg: + print msg + usage() + + if not args or len(args) > 1: + usage() + arch = args[0] + + version = None + for opt in optlist: + if opt[0] == '-v': + version = opt[1] + break + if not version: + usage() + + library = supported_libraries[version] + + if not (('-p','') in optlist): + fname = arch + '.stp' + f = openfile(fname) + print "Building stoplist", fname, "..." + words = stop_list.split() + words.sort() + for word in words: + print >> f, word + f.close() + + f = openfile(arch + '.hhp') + print "Building Project..." + do_project(library, f, arch, version) + if version == '2.0.0': + for image in os.listdir('icons'): + f.write('icons'+ '\\' + image + '\n') + + f.close() + + if not (('-c','') in optlist): + f = openfile(arch + '.hhc') + print "Building Table of Content..." + do_content(library, version, f) + f.close() + + if not (('-k','') in optlist): + f = openfile(arch + '.hhk') + print "Building Index..." + do_index(library, f) + f.close() + +if __name__ == '__main__': + do_it() diff --git a/sys/src/cmd/python/Doc/tools/push-docs.sh b/sys/src/cmd/python/Doc/tools/push-docs.sh new file mode 100755 index 000000000..28a4b3158 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/push-docs.sh @@ -0,0 +1,138 @@ +#! /bin/sh + +# Script to push docs from my development area to SourceForge, where the +# update-docs.sh script unpacks them into their final destination. + +TARGETHOST=www.python.org +TARGETDIR=/usr/home/fdrake/tmp + +PKGTYPE="bzip" # must be one of: bzip, tar, zip ("tar" implies gzip) + +TARGET="$TARGETHOST:$TARGETDIR" + +ADDRESSES='python-dev@python.org doc-sig@python.org python-list@python.org' + +TOOLDIR="`dirname $0`" +VERSION=`$TOOLDIR/getversioninfo` + +# Set $EXTRA to something non-empty if this is a non-trunk version: +EXTRA=`echo "$VERSION" | sed 's/^[0-9][0-9]*\.[0-9][0-9]*//'` + +if echo "$EXTRA" | grep -q '[.]' ; then + DOCLABEL="maintenance" + DOCTYPE="maint" +else + DOCLABEL="development" + DOCTYPE="devel" +fi + +DOCTYPE_SPECIFIED=false +EXPLANATION='' +ANNOUNCE=true + +getopt -T >/dev/null +if [ $? -eq 4 ] ; then + # We have a sufficiently useful getopt(1) implementation. + eval "set -- `getopt -ssh m:p:qt:F: \"$@\"`" +else + # This version of getopt doesn't support quoting of long options + # with spaces, so let's not rely on it at all. + : +fi + +while [ "$#" -gt 0 ] ; do + case "$1" in + -m) + EXPLANATION="$2" + shift 2 + ;; + -p) + PKGTYPE="$2" + shift 1 + ;; + -q) + ANNOUNCE=false + shift 1 + ;; + -t) + DOCTYPE="$2" + DOCTYPE_SPECIFIED=true + shift 2 + ;; + -F) + EXPLANATION="`cat $2`" + shift 2 + ;; + --) + shift 1 + break + ;; + -*) + echo "Unknown option: $1" >&2 + exit 2 + ;; + *) + break + ;; + esac +done +if [ "$1" ] ; then + if [ "$EXPLANATION" ] ; then + echo "Explanation may only be given once!" >&2 + exit 2 + fi + EXPLANATION="$1" + shift +fi + +START="`pwd`" +MYDIR="`dirname $0`" +cd "$MYDIR" +MYDIR="`pwd`" + +if [ "$PKGTYPE" = bzip ] ; then + PKGEXT=tar.bz2 +elif [ "$PKGTYPE" = tar ] ; then + PKGEXT=tgz +elif [ "$PKGTYPE" = zip ] ; then + PKGEXT=zip +else + echo 1>&2 "unsupported package type: $PKGTYPE" + exit 2 +fi + +# switch to .../Doc/ +cd .. + +# If $DOCTYPE was not specified explicitly, look for .doctype in +# .../Doc/ and use the content of that file if present. +if $DOCTYPE_SPECIFIED ; then + : +elif [ -f .doctype ] ; then + DOCTYPE="`cat .doctype`" +fi + +make --no-print-directory ${PKGTYPE}html || exit $? +PACKAGE="html-$VERSION.$PKGEXT" +scp "$PACKAGE" tools/update-docs.sh $TARGET/ || exit $? +ssh "$TARGETHOST" tmp/update-docs.sh $DOCTYPE $PACKAGE '&&' rm tmp/update-docs.sh || exit $? + +if $ANNOUNCE ; then + sendmail $ADDRESSES <<EOF +To: $ADDRESSES +From: "Fred L. Drake" <fdrake@acm.org> +Subject: [$DOCLABEL doc updates] +X-No-Archive: yes + +The $DOCLABEL version of the documentation has been updated: + + http://$TARGETHOST/dev/doc/$DOCTYPE/ + +$EXPLANATION + +A downloadable package containing the HTML is also available: + + http://$TARGETHOST/dev/doc/python-docs-$DOCTYPE.$PKGEXT +EOF + exit $? +fi diff --git a/sys/src/cmd/python/Doc/tools/py2texi.el b/sys/src/cmd/python/Doc/tools/py2texi.el new file mode 100644 index 000000000..450c30c13 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/py2texi.el @@ -0,0 +1,970 @@ +;;; py2texi.el -- Conversion of Python LaTeX documentation to Texinfo + +;; Copyright (C) 2006 Jeroen Dekkers <jeroen@dekkers.cx> +;; Copyright (C) 1998, 1999, 2001, 2002 Milan Zamazal + +;; Author: Milan Zamazal <pdm@zamazal.org> +;; Version: $Id: py2texi.el 52974 2006-12-09 12:13:02Z matthias.klose $ +;; Keywords: python + +;; COPYRIGHT NOTICE +;; +;; This program is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This program is distributed in the hope that it will be useful, but +;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; You can find the GNU General Public License at +;; http://www.gnu.org/copyleft/gpl.html +;; or you can write to the Free Software Foundation, Inc., 59 Temple Place, +;; Suite 330, Boston, MA 02111-1307, USA. + +;;; Commentary: + +;; This is a Q&D hack for conversion of Python manuals to on-line help format. +;; I desperately needed usable online documenta for Python, so I wrote this. +;; The result code is ugly and need not contain complete information from +;; Python manuals. I apologize for my ignorance, especially ignorance to +;; python.sty. Improvements of this convertor are welcomed. + +;; How to use it: +;; Load this file and apply `M-x py2texi'. You will be asked for name of a +;; file to be converted. + +;; Where to find it: +;; New versions of this code might be found at +;; http://www.zamazal.org/software/python/py2texi/ . + +;;; Code: + + +(require 'texinfo) +(eval-when-compile + (require 'cl)) + + +(defvar py2texi-python-version "2.2" + "What to substitute for the \\version macro.") + +(defvar py2texi-python-short-version + (progn + (string-match "[0-9]+\\.[0-9]+" py2texi-python-version) + (match-string 0 py2texi-python-version)) + "Short version number, usually set by the LaTeX commands.") + +(defvar py2texi-texi-file-name nil + "If non-nil, that string is used as the name of the Texinfo file. +Otherwise a generated Texinfo file name is used.") + +(defvar py2texi-info-file-name nil + "If non-nil, that string is used as the name of the Info file. +Otherwise a generated Info file name is used.") + +(defvar py2texi-stop-on-problems nil + "*If non-nil, stop when you encouter soft problem.") + +(defconst py2texi-environments + '(("abstract" 0 "@quotation" "@end quotation\n") + ("center" 0 "" "") + ("cfuncdesc" 3 + (progn (setq findex t) + "\n@table @code\n@item \\1 \\2(\\3)\n@findex \\2\n") + "@end table\n") + ("cmemberdesc" 3 + "\n@table @code\n@item \\2 \\3\n" + "@end table\n") + ("classdesc" 2 + (progn (setq obindex t) + "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n") + "@end table\n") + ("classdesc*" 1 + (progn (setq obindex t) + "\n@table @code\n@item \\1\n@obindex \\1\n") + "@end table\n") + ("comment" 0 "\n@ignore\n" "\n@end ignore\n") + ("csimplemacrodesc" 1 + (progn (setq cindex t) + "\n@table @code\n@item \\1\n@cindex \\1\n") + "@end table\n") + ("ctypedesc" 1 + (progn (setq cindex t) + "\n@table @code\n@item \\1\n@cindex \\1\n") + "@end table\n") + ("cvardesc" 2 + (progn (setq findex t) + "\n@table @code\n@item \\1 \\2\n@findex \\2\n") + "@end table\n") + ("datadesc" 1 + (progn (setq findex t) + "\n@table @code\n@item \\1\n@findex \\1\n") + "@end table\n") + ("datadescni" 1 "\n@table @code\n@item \\1\n" "@end table\n") + ("definitions" 0 "@table @dfn" "@end table\n") + ("description" 0 "@table @samp" "@end table\n") + ("displaymath" 0 "" "") + ("document" 0 + (concat "@defcodeindex mo\n" + "@defcodeindex ob\n" + "@titlepage\n" + (format "@title " title "\n") + (format "@author " author "\n") + "@page\n" + author-address + "@end titlepage\n" + "@node Top, , , (dir)\n") + (concat "@indices\n" + "@contents\n" + "@bye\n")) + ("enumerate" 0 "@enumerate" "@end enumerate") + ("envdesc" 2 (concat "\n@table @code" + "\n@item @backslash{}begin@{\\1@}\\2") + "@end table\n") + ("excdesc" 1 + (progn (setq obindex t) + "\n@table @code\n@item \\1\n@obindex \\1\n") + "@end table\n") + ("excclassdesc" 2 + (progn (setq obindex t) + "\n@table @code\n@item \\1(\\2)\n@obindex \\1\n") + "@end table\n") + ("flushleft" 0 "" "") + ("fulllineitems" 0 "\n@table @code\n" "@end table\n") + ("funcdesc" 2 + (progn (setq findex t) + "\n@table @code\n@item \\1(\\2)\n@findex \\1\n") + "@end table\n") + ("funcdescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n") + ("itemize" 0 "@itemize @bullet" "@end itemize\n") + ("list" 2 "\n@table @code\n" "@end table\n") + ("longtableii" 4 (concat "@multitable @columnfractions .5 .5\n" + "@item \\3 @tab \\4\n" + "@item ------- @tab ------ \n") + "@end multitable\n") + ("longtableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n" + "@item \\3 @tab \\4 @tab \\5\n" + "@item ------- @tab ------ @tab ------\n") + "@end multitable\n") + ("macrodesc" 2 (concat "\n@table @code" + "\n@item \\1@{\\2@}") + "@end table\n") + ("memberdesc" 1 + (progn (setq findex t) + "\n@table @code\n@item \\1\n@findex \\1\n") + "@end table\n") + ("memberdescni" 1 "\n@table @code\n@item \\1\n" "@end table\n") + ("methoddesc" 2 + (progn (setq findex t) + "\n@table @code\n@item \\1(\\2)\n@findex \\1\n") + "@end table\n") + ("methoddescni" 2 "\n@table @code\n@item \\1(\\2)\n" "@end table\n") + ("notice" 0 "@emph{Notice:} " "") + ("opcodedesc" 2 + (progn (setq findex t) + "\n@table @code\n@item \\1 \\2\n@findex \\1\n") + "@end table\n") + ("productionlist" 0 "\n@table @code\n" "@end table\n") + ("quotation" 0 "@quotation" "@end quotation") + ("quote" 0 "@quotation" "@end quotation") + ("seealso" 0 "See also:\n@table @emph\n" "@end table\n") + ("seealso*" 0 "@table @emph\n" "@end table\n") + ("sloppypar" 0 "" "") + ("small" 0 "" "") + ("tableii" 4 (concat "@multitable @columnfractions .5 .5\n" + "@item \\3 @tab \\4\n" + "@item ------- @tab ------ \n") + "@end multitable\n") + ("tableiii" 5 (concat "@multitable @columnfractions .33 .33 .33\n" + "@item \\3 @tab \\4 @tab \\5\n" + "@item ------- @tab ------ @tab ------\n") + "@end multitable\n") + ("tableiv" 6 (concat + "@multitable @columnfractions .25 .25 .25 .25\n" + "@item \\3 @tab \\4 @tab \\5 @tab \\6\n" + "@item ------- @tab ------- @tab ------- @tab -------\n") + "@end multitable\n") + ("tablev" 7 (concat + "@multitable @columnfractions .20 .20 .20 .20 .20\n" + "@item \\3 @tab \\4 @tab \\5 @tab \\6 @tab \\7\n" + "@item ------- @tab ------- @tab ------- @tab ------- @tab -------\n") + "@end multitable\n") + ("alltt" 0 "@example" "@end example") + ) + "Associative list defining substitutions for environments. +Each list item is of the form (ENVIRONMENT ARGNUM BEGIN END) where: +- ENVIRONMENT is LaTeX environment name +- ARGNUM is number of (required) macro arguments +- BEGIN is substitution for \begin{ENVIRONMENT} +- END is substitution for \end{ENVIRONMENT} +Both BEGIN and END are evaled. Moreover, you can reference arguments through +\N regular expression notation in strings of BEGIN.") + +(defconst py2texi-commands + '(("AA" 0 "@AA{}") + ("aa" 0 "@aa{}") + ("ABC" 0 "ABC") + ("appendix" 0 (progn (setq appendix t) "")) + ("ASCII" 0 "ASCII") + ("author" 1 (progn (setq author (match-string 1 string)) "")) + ("authoraddress" 1 + (progn (setq author-address (match-string 1 string)) "")) + ("b" 1 "@w{\\1}") + ("backslash" 0 "@backslash{}") + ("bf" 0 "@destroy") + ("bifuncindex" 1 (progn (setq findex t) "@findex{\\1}")) + ("C" 0 "C") + ("c" 0 "@,") + ("catcode" 0 "") + ("cdata" 1 "@code{\\1}") + ("centerline" 1 "@center \\1") + ("cfuncline" 3 "@itemx \\1 \\2(\\3)\n@findex \\2") + ("cfunction" 1 "@code{\\1}") + ("chapter" 1 (format "@node \\1\n@%s \\1\n" + (if appendix "appendix" "chapter"))) + ("chapter*" 1 "@node \\1\n@unnumbered \\1\n") + ("character" 1 "@samp{\\1}") + ("citetitle" 1 "@ref{Top,,,\\1}") + ("class" 1 "@code{\\1}") + ("cmemberline" 3 "@itemx \\2 \\3\n") + ("code" 1 "@code{\\1}") + ("command" 1 "@command{\\1}") + ("constant" 1 "@code{\\1}") + ("copyright" 1 "@copyright{}") + ("Cpp" 0 "C++") + ("csimplemacro" 1 "@code{\\1}") + ("ctype" 1 "@code{\\1}") + ("dataline" 1 (progn (setq findex t) "@item \\1\n@findex \\1\n")) + ("date" 1 "\\1") + ("declaremodule" 2 (progn (setq cindex t) "@label{\\2}@cindex{\\2}")) + ("deprecated" 2 "@emph{This is deprecated in Python \\1. \\2}\n\n") + ("dfn" 1 "@dfn{\\1}") + ("documentclass" 1 py2texi-magic) + ("e" 0 "@backslash{}") + ("else" 0 (concat "@end ifinfo\n@" (setq last-if "iftex"))) + ("env" 1 "@code{\\1}") + ("EOF" 0 "@code{EOF}") + ("email" 1 "@email{\\1}") + ("em" 1 "@emph{\\1}") + ("emph" 1 "@emph{\\1}") + ("envvar" 1 "@env{\\1}") + ("exception" 1 "@code{\\1}") + ("exindex" 1 (progn (setq obindex t) "@obindex{\\1}")) + ("fi" 0 (if (equal last-if "ifx") "" (concat "@end " last-if))) + ("file" 1 "@file{\\1}") + ("filenq" 1 "@file{\\1}") + ("filevar" 1 "@file{@var{\\1}}") + ("footnote" 1 "@footnote{\\1}") + ("frac" 0 "") + ("funcline" 2 (progn (setq findex t) "@item \\1 \\2\n@findex \\1")) + ("funclineni" 2 "@item \\1 \\2") + ("function" 1 "@code{\\1}") + ("grammartoken" 1 "@code{\\1}") + ("guilabel" 1 "@strong{\\1}") + ("hline" 0 "") + ("ifx" 0 (progn (setq last-if "ifx") "")) + ("ifhtml" 0 (concat "@" (setq last-if "ifinfo"))) + ("iftexi" 0 (concat "@" (setq last-if "ifinfo"))) + ("index" 1 (progn (setq cindex t) "@cindex{\\1}")) + ("indexii" 2 (progn (setq cindex t) "@cindex{\\1 \\2}")) + ("indexiii" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3}")) + ("indexiv" 3 (progn (setq cindex t) "@cindex{\\1 \\2 \\3 \\4}")) + ("infinity" 0 "@emph{infinity}") + ("it" 0 "@destroy") + ("kbd" 1 "@key{\\1}") + ("keyword" 1 "@code{\\1}") + ("kwindex" 1 (progn (setq cindex t) "@cindex{\\1}")) + ("label" 1 "@label{\\1}") + ("Large" 0 "") + ("LaTeX" 0 "La@TeX{}") + ("large" 0 "") + ("ldots" 0 "@dots{}") + ("leftline" 1 "\\1") + ("leq" 0 "<=") + ("lineii" 2 "@item \\1 @tab \\2") + ("lineiii" 3 "@item \\1 @tab \\2 @tab \\3") + ("lineiv" 4 "@item \\1 @tab \\2 @tab \\3 @tab \\4") + ("linev" 5 "@item \\1 @tab \\2 @tab \\3 @tab \\4 @tab \\5") + ("locallinewidth" 0 "") + ("localmoduletable" 0 "") + ("longprogramopt" 1 "@option{--\\1}") + ("macro" 1 "@code{@backslash{}\\1}") + ("mailheader" 1 "@code{\\1}") + ("makeindex" 0 "") + ("makemodindex" 0 "") + ("maketitle" 0 (concat "@top " title "\n")) + ("makevar" 1 "@code{\\1}") + ("manpage" 2 "@samp{\\1(\\2)}") + ("mbox" 1 "@w{\\1}") + ("member" 1 "@code{\\1}") + ("memberline" 1 "@item \\1\n@findex \\1\n") + ("menuselection" 1 "@samp{\\1}") + ("method" 1 "@code{\\1}") + ("methodline" 2 (progn (setq moindex t) "@item \\1(\\2)\n@moindex \\1\n")) + ("methodlineni" 2 "@item \\1(\\2)\n") + ("mimetype" 1 "@samp{\\1}") + ("module" 1 "@samp{\\1}") + ("moduleauthor" 2 "") + ("modulesynopsis" 1 "\\1") + ("moreargs" 0 "@dots{}") + ("n" 0 "@backslash{}n") + ("newcommand" 2 "") + ("newlength" 1 "") + ("newsgroup" 1 "@samp{\\1}") + ("nodename" 1 + (save-excursion + (save-match-data + (re-search-backward "^@node ")) + (delete-region (point) (save-excursion (end-of-line) (point))) + (insert "@node " (match-string 1 string)) + "")) + ("noindent" 0 "@noindent ") + ("note" 1 "@emph{Note:} \\1") + ("NULL" 0 "@code{NULL}") + ("obindex" 1 (progn (setq obindex t) "@obindex{\\1}")) + ("opindex" 1 (progn (setq cindex t) "@cindex{\\1}")) + ("option" 1 "@option{\\1}") + ("optional" 1 "[\\1]") + ("paragraph" 1 "@subsubheading \\1") + ("pep" 1 (progn (setq cindex t) "PEP@ \\1@cindex PEP \\1\n")) + ("pi" 0 "pi") + ("platform" 1 "") + ("plusminus" 0 "+-") + ("POSIX" 0 "POSIX") + ("production" 2 "@item \\1 \\2") + ("productioncont" 1 "@item @w{} \\1") + ("program" 1 "@command{\\1}") + ("programopt" 1 "@option{\\1}") + ("protect" 0 "") + ("pytype" 1 "@code{\\1}") + ("ref" 1 "@ref{\\1}") + ("refbimodindex" 1 (progn (setq moindex t) "@moindex{\\1}")) + ("refmodindex" 1 (progn (setq moindex t) "@moindex{\\1}")) + ("refmodule" 1 "@samp{\\1}") + ("refstmodindex" 1 (progn (setq moindex t) "@moindex{\\1}")) + ("regexp" 1 "\"\\1\"") + ("release" 1 + (progn (setq py2texi-python-version (match-string 1 string)) "")) + ("renewcommand" 2 "") + ("rfc" 1 (progn (setq cindex t) "RFC@ \\1@cindex RFC \\1\n")) + ("rm" 0 "@destroy") + ("samp" 1 "@samp{\\1}") + ("section" 1 (let ((str (match-string 1 string))) + (save-match-data + (if (string-match "\\(.*\\)[ \t\n]*---[ \t\n]*\\(.*\\)" + str) + (format + "@node %s\n@section %s\n" + (py2texi-backslash-quote (match-string 1 str)) + (py2texi-backslash-quote (match-string 2 str))) + "@node \\1\n@section \\1\n")))) + ("sectionauthor" 2 "") + ("seelink" 3 "\n@table @url\n@item @strong{\\1}\n(\\2)\n\\3\n@end table\n") + ("seemodule" 2 "@ref{\\1} \\2") + ("seepep" 3 "\n@table @strong\n@item PEP\\1 \\2\n\\3\n@end table\n") + ("seerfc" 3 "\n@table @strong\n@item RFC\\1 \\2\n\\3\n@end table\n") + ("seetext" 1 "\\1") + ("seetitle" 1 "@cite{\\1}") + ("seeurl" 2 "\n@table @url\n@item \\1\n\\2\n@end table\n") + ("setindexsubitem" 1 (progn (setq cindex t) "@cindex \\1")) + ("setlength" 2 "") + ("setreleaseinfo" 1 (progn (setq py2texi-releaseinfo ""))) + ("setshortversion" 1 + (progn (setq py2texi-python-short-version (match-string 1 string)) "")) + ("shortversion" 0 py2texi-python-short-version) + ("sqrt" 0 "") + ("stindex" 1 (progn (setq cindex t) "@cindex{\\1}")) + ("stmodindex" 1 (progn (setq moindex t) "@moindex{\\1}")) + ("strong" 1 "@strong{\\1}") + ("sub" 0 "/") + ("subsection" 1 "@node \\1\n@subsection \\1\n") + ("subsubsection" 1 "@node \\1\n@subsubsection \\1\n") + ("sum" 0 "") + ("tableofcontents" 0 "") + ("term" 1 "@item \\1") + ("TeX" 0 "@TeX{}") + ("textasciitilde" 0 "~") + ("textasciicircum" 0 "^") + ("textbackslash" 0 "@backslash{}") + ("textbar" 0 "|") + ("textbf" 1 "@strong{\\1}") + ("texteuro" 0 "@euro{}") + ; Unfortunately, this alternate spelling doesn't actually apply to + ; the usage found in Python Tutorial, which actually requires a + ; Euro symbol to make sense, so this is commented out as well. + ; ("texteuro" 0 "Euro ") + ("textgreater" 0 ">") + ("textit" 1 "@i{\\1}") + ("textless" 0 "<") + ("textrm" 1 "\\1") + ("texttt" 1 "@code{\\1}") + ("textunderscore" 0 "_") + ("tilde" 0 "~") + ("title" 1 (progn (setq title (match-string 1 string)) "@settitle \\1")) + ("today" 0 "@today{}") + ("token" 1 "@code{\\1}") + ("tt" 0 "@destroy") + ("ttindex" 1 (progn (setq cindex t) "@cindex{\\1}")) + ("u" 0 "@backslash{}u") + ("ulink" 2 "\\1") + ("UNIX" 0 "UNIX") + ("undefined" 0 "") + ("unspecified" 0 "@dots{}") + ("url" 1 "@url{\\1}") + ("usepackage" 1 "") + ("var" 1 "@var{\\1}") + ("verbatiminput" 1 "@code{\\1}") + ("version" 0 py2texi-python-version) + ("versionadded" 1 "@emph{Added in Python version \\1}") + ("versionchanged" 1 "@emph{Changed in Python version \\1}") + ("vskip" 1 "") + ("vspace" 1 "") + ("warning" 1 "@emph{\\1}") + ("withsubitem" 2 "\\2") + ("XXX" 1 "@strong{\\1}")) + "Associative list of command substitutions. +Each list item is of the form (COMMAND ARGNUM SUBSTITUTION) where: +- COMMAND is LaTeX command name +- ARGNUM is number of (required) command arguments +- SUBSTITUTION substitution for the command. It is evaled and you can + reference command arguments through the \\N regexp notation in strings.") + +(defvar py2texi-magic "@documentclass\n" + "\"Magic\" string for auxiliary insertion at the beginning of document.") + +(defvar py2texi-dirs '("./" "../texinputs/") + "Where to search LaTeX input files.") + +(defvar py2texi-buffer "*py2texi*" + "The name of a buffer where Texinfo is generated.") + +(defconst py2texi-xemacs (string-match "^XEmacs" (emacs-version)) + "Running under XEmacs?") + + +(defmacro py2texi-search (regexp &rest body) + `(progn + (goto-char (point-min)) + (while (re-search-forward ,regexp nil t) + ,@body))) + +(defmacro py2texi-search-safe (regexp &rest body) + `(py2texi-search ,regexp + (unless (py2texi-protected) + ,@body))) + + +(defun py2texi-message (message) + "Report message and stop if `py2texi-stop-on-problems' is non-nil." + (if py2texi-stop-on-problems + (error message) + (message message))) + + +(defun py2texi-backslash-quote (string) + "Double backslahes in STRING." + (let ((i 0)) + (save-match-data + (while (setq i (string-match "\\\\" string i)) + (setq string (replace-match "\\\\\\\\" t nil string)) + (setq i (+ i 2)))) + string)) + + +(defun py2texi (file) + "Convert Python LaTeX documentation FILE to Texinfo." + (interactive "fFile to convert: ") + (switch-to-buffer (get-buffer-create py2texi-buffer)) + (erase-buffer) + (insert-file file) + (let ((case-fold-search nil) + (title "") + (author "") + (author-address "") + (appendix nil) + (findex nil) + (obindex nil) + (cindex nil) + (moindex nil) + last-if) + (py2texi-process-verbatims) + (py2texi-process-comments) + (py2texi-process-includes) + (py2texi-process-funnyas) + (py2texi-process-environments) + (py2texi-process-commands) + (py2texi-fix-indentation) + (py2texi-fix-nodes) + (py2texi-fix-references) + (py2texi-fix-indices) + (py2texi-process-simple-commands) + (py2texi-fix-fonts) + (py2texi-fix-braces) + (py2texi-fix-backslashes) + (py2texi-destroy-empties) + (py2texi-fix-newlines) + (py2texi-adjust-level)) + (let* ((texi-file-name (or py2texi-texi-file-name + (py2texi-texi-file-name file))) + (info-file-name (or py2texi-info-file-name + (py2texi-info-file-name texi-file-name)))) + (goto-char (point-min)) + (when (looking-at py2texi-magic) + (delete-region (point) (progn (beginning-of-line 2) (point))) + (insert "\\input texinfo @c -*-texinfo-*-\n") + (insert "@setfilename " info-file-name)) + (when (re-search-forward "@chapter" nil t) + (texinfo-all-menus-update t)) + (goto-char (point-min)) + (write-file texi-file-name) + (message (format "You can apply `makeinfo %s' now." texi-file-name)))) + + +(defun py2texi-texi-file-name (filename) + "Generate name of Texinfo file from original file name FILENAME." + (concat filename + (if (string-match "\\.tex$" filename) "i" ".texi"))) + + +(defun py2texi-info-file-name (filename) + "Generate name of info file from original file name FILENAME." + (setq filename (expand-file-name filename)) + (let ((directory (file-name-directory filename)) + (basename (file-name-nondirectory filename))) + (concat directory "python-" + (substring basename 0 (- (length basename) 4)) "info"))) + + +(defun py2texi-process-verbatims () + "Process and protect verbatim environments." + (let (delimiter + beg + end) + (py2texi-search-safe "\\\\begin{\\(verbatim\\|displaymath\\)}" + (when (save-excursion + ; Make sure we aren't looking at a commented out version + ; of a verbatim environment + (beginning-of-line) + (not (looking-at "%"))) + (replace-match "@example ") + (setq beg (copy-marker (point) nil)) + (re-search-forward "\\\\end{\\(verbatim\\|displaymath\\)}") + (setq end (copy-marker (match-beginning 0) nil)) + (replace-match "@end example") + (py2texi-texinfo-escape beg end) + (put-text-property (- beg (length "@example ")) + (+ end (length "@end example")) + 'py2texi-protected t))) + (py2texi-search-safe "\\\\verb\\([^a-z]\\)" + (setq delimiter (match-string 1)) + (replace-match "@code{") + (setq beg (copy-marker (point) nil)) + (re-search-forward (regexp-quote delimiter)) + (setq end (copy-marker (match-beginning 0) nil)) + (replace-match "}") + (put-text-property (- beg (length "@code{")) (+ end (length "}")) + 'py2texi-protected t) + (py2texi-texinfo-escape beg end)))) + + +(defun py2texi-process-comments () + "Remove comments." + (let (point) + (py2texi-search-safe "%" + (setq point (point)) + (when (save-excursion + (re-search-backward "\\(^\\|[^\\]\\(\\\\\\\\\\)*\\)%\\=" nil t)) + (delete-region (1- point) + (save-excursion (beginning-of-line 2) (point))))))) + + +(defun py2texi-process-includes () + "Include LaTeX input files. +Do not include .ind files." + (let ((path (file-name-directory file)) + filename + dirs + includefile) + (py2texi-search-safe "\\\\input{\\([^}]+\\)}" + (setq filename (match-string 1)) + (unless (save-match-data (string-match "\\.tex$" filename)) + (setq filename (concat filename ".tex"))) + (setq includefile (save-match-data + (string-match "\\.ind\\.tex$" filename))) + (setq dirs py2texi-dirs) + (while (and (not includefile) dirs) + (setq includefile + (concat (file-name-as-directory (car dirs)) filename)) + (if (not (file-name-absolute-p includefile)) + (setq includefile + (concat (file-name-as-directory path) includefile))) + (unless (file-exists-p includefile) + (setq includefile nil) + (setq dirs (cdr dirs)))) + (if includefile + (save-restriction + (narrow-to-region (match-beginning 0) (match-end 0)) + (delete-region (point-min) (point-max)) + (when (stringp includefile) + (insert-file-contents includefile) + (goto-char (point-min)) + (insert "\n") + (py2texi-process-verbatims) + (py2texi-process-comments) + (py2texi-process-includes))) + (replace-match (format "\\\\emph{Included file %s}" filename)) + (py2texi-message (format "Input file %s not found" filename)))))) + + +(defun py2texi-process-funnyas () + "Convert @s." + (py2texi-search-safe "@" + (replace-match "@@"))) + + +(defun py2texi-process-environments () + "Process LaTeX environments." + (let ((stack ()) + kind + environment + parameter + arguments + n + string + description) + (py2texi-search-safe (concat "\\\\\\(begin\\|end\\|item\\)" + "\\({\\([^}]*\\)}\\|[[]\\([^]]*\\)[]]\\|\\)") + (setq kind (match-string 1) + environment (match-string 3) + parameter (match-string 4)) + (replace-match "") + (cond + ((string= kind "begin") + (setq description (assoc environment py2texi-environments)) + (if description + (progn + (setq n (cadr description)) + (setq description (cddr description)) + (setq string (py2texi-tex-arguments n)) + (string-match (py2texi-regexp n) string) + ; incorrect but sufficient + (insert (replace-match (eval (car description)) + t nil string)) + (setq stack (cons (cadr description) stack))) + (py2texi-message (format "Unknown environment: %s" environment)) + (setq stack (cons "" stack)))) + ((string= kind "end") + (insert (eval (car stack))) + (setq stack (cdr stack))) + ((string= kind "item") + (insert "\n@item " (or parameter "") "\n")))) + (when stack + (py2texi-message (format "Unclosed environment: %s" (car stack)))))) + + +(defun py2texi-process-commands () + "Process LaTeX commands." + (let (done + command + command-info + string + n) + (while (not done) + (setq done t) + (py2texi-search-safe "\\\\\\([a-zA-Z*]+\\)\\(\\[[^]]*\\]\\)?" + (setq command (match-string 1)) + (setq command-info (assoc command py2texi-commands)) + (if command-info + (progn + (setq done nil) + (replace-match "") + (setq command-info (cdr command-info)) + (setq n (car command-info)) + (setq string (py2texi-tex-arguments n)) + (string-match (py2texi-regexp n) string) + ; incorrect but sufficient + (insert (replace-match (eval (cadr command-info)) + t nil string))) + (py2texi-message (format "Unknown command: %s (not processed)" + command))))))) + + +(defun py2texi-argument-pattern (count) + (let ((filler "\\(?:[^{}]\\|\\\\{\\|\\\\}\\)*")) + (if (<= count 0) + filler + (concat filler "\\(?:{" + (py2texi-argument-pattern (1- count)) + "}" filler "\\)*" filler)))) +(defconst py2texi-tex-argument + (concat + "{\\(" + (py2texi-argument-pattern 10) ;really at least 10! + "\\)}[ \t%@c\n]*") + "Regexp describing LaTeX command argument including argument separators.") + + +(defun py2texi-regexp (n) + "Make regexp matching N LaTeX command arguments." + (if (= n 0) + "" + (let ((regexp "^[^{]*")) + (while (> n 0) + (setq regexp (concat regexp py2texi-tex-argument)) + (setq n (1- n))) + regexp))) + + +(defun py2texi-tex-arguments (n) + "Remove N LaTeX command arguments and return them as a string." + (let ((point (point)) + (i 0) + result + match) + (if (= n 0) + (progn + (when (re-search-forward "\\=\\({}\\| *\\)" nil t) + (replace-match "")) + "") + (while (> n 0) + (unless (re-search-forward + "\\(\\=\\|[^\\\\]\\)\\(\\\\\\\\\\)*\\([{}]\\)" nil t) + (debug)) + (if (string= (match-string 3) "{") + (setq i (1+ i)) + (setq i (1- i)) + (when (<= i 0) + (setq n (1- n))))) + (setq result (buffer-substring-no-properties point (point))) + (while (string-match "\n[ \t]*" result) + (setq result (replace-match " " t nil result))) + (delete-region point (point)) + result))) + + +(defun py2texi-process-simple-commands () + "Replace single character LaTeX commands." + (let (char) + (py2texi-search-safe "\\\\\\([^a-z]\\)" + (setq char (match-string 1)) + (replace-match (format "%s%s" + (if (or (string= char "{") + (string= char "}") + (string= char " ")) + "@" + "") + (if (string= char "\\") + "\\\\" + char)))))) + + +(defun py2texi-fix-indentation () + "Remove white space at the beginning of lines." + (py2texi-search-safe "^[ \t]+" + (replace-match ""))) + + +(defun py2texi-fix-nodes () + "Remove unwanted characters from nodes and make nodes unique." + (let ((nodes (make-hash-table :test 'equal)) + id + counter + string + label + index) + (py2texi-search "^@node +\\(.*\\)$" + (setq string (match-string 1)) + (if py2texi-xemacs + (replace-match "@node " t) + (replace-match "" t nil nil 1)) + (while (string-match "@label{[^}]*}" string) + (setq label (match-string 0 string)) + (setq string (replace-match "" t nil string))) + (while (string-match "@..?index{[^}]*}" string) + (setq index (match-string 0 string)) + (setq string (replace-match "" t nil string))) + (while (string-match "@[a-zA-Z]+\\|[{}():]\\|``\\|''" string) + (setq string (replace-match "" t nil string))) + (while (string-match " -- " string) + (setq string (replace-match " - " t nil string))) + (while (string-match "\\." string) + (setq string (replace-match "" t nil string))) + (when (string-match " +$" string) + (setq string (replace-match "" t nil string))) + (when (string-match "^\\(Built-in\\|Standard\\) Module \\|The " string) + (setq string (replace-match "" t nil string))) + (string-match "^[^,]+" string) + (setq id (match-string 0 string)) + (setq counter (gethash id nodes)) + (if counter + (progn + (setq counter (1+ counter)) + (setq string (replace-match (format "\\& %d" counter) + t nil string))) + (setq counter 1)) + (setf (gethash id nodes) counter) + (insert string) + (beginning-of-line 3) + (when label + (insert label "\n")) + (when index + (insert index "\n"))))) + + +(defun py2texi-fix-references () + "Process labels and make references to point to appropriate nodes." + (let ((labels ()) + node) + (py2texi-search-safe "@label{\\([^}]*\\)}" + (setq node (save-excursion + (save-match-data + (and (re-search-backward "@node +\\([^,\n]+\\)" nil t) + (match-string 1))))) + (when node + (setq labels (cons (cons (match-string 1) node) labels))) + (replace-match "")) + (py2texi-search-safe "@ref{\\([^}]*\\)}" + (setq node (assoc (match-string 1) labels)) + (replace-match "") + (when node + (insert (format "@ref{%s}" (cdr node))))))) + + +(defun py2texi-fix-indices () + "Remove unwanted characters from @*index commands and create final indices." + (py2texi-search-safe "@..?index\\>[^\n]*\\(\\)\n" + (replace-match "" t nil nil 1)) + (py2texi-search-safe "@..?index\\>[^\n]*\\(\\)" + (replace-match "\n" t nil nil 1)) + (py2texi-search-safe "@..?index\\({\\)\\([^}]+\\)\\(}+\\)" + (replace-match " " t nil nil 1) + (replace-match "" t nil nil 3) + (let ((string (match-string 2))) + (save-match-data + (while (string-match "@[a-z]+{" string) + (setq string (replace-match "" nil nil string))) + (while (string-match "{" string) + (setq string (replace-match "" nil nil string)))) + (replace-match string t t nil 2))) + (py2texi-search-safe "@..?index\\>.*\\([{}]\\|@[a-z]*\\)" + (replace-match "" t nil nil 1) + (goto-char (match-beginning 0))) + (py2texi-search-safe "[^\n]\\(\\)@..?index\\>" + (replace-match "\n" t nil nil 1)) + (goto-char (point-max)) + (re-search-backward "@indices") + (replace-match "") + (insert (if moindex + (concat "@node Module Index\n" + "@unnumbered Module Index\n" + "@printindex mo\n") + "") + (if obindex + (concat "@node Class-Exception-Object Index\n" + "@unnumbered Class, Exception, and Object Index\n" + "@printindex ob\n") + "") + (if findex + (concat "@node Function-Method-Variable Index\n" + "@unnumbered Function, Method, and Variable Index\n" + "@printindex fn\n") + "") + (if cindex + (concat "@node Miscellaneous Index\n" + "@unnumbered Miscellaneous Index\n" + "@printindex cp\n") + ""))) + + +(defun py2texi-fix-backslashes () + "Make backslashes from auxiliary commands." + (py2texi-search-safe "@backslash{}" + (replace-match "\\\\"))) + + +(defun py2texi-fix-fonts () + "Remove garbage after unstructured font commands." + (let (string) + (py2texi-search-safe "@destroy" + (replace-match "") + (when (eq (preceding-char) ?{) + (forward-char -1) + (setq string (py2texi-tex-arguments 1)) + (insert (substring string 1 (1- (length string)))))))) + + +(defun py2texi-fix-braces () + "Escape braces for Texinfo." + (py2texi-search "{@{}" + (replace-match "@{")) + (py2texi-search "{@}}" + (replace-match "@}")) + (let (string) + (py2texi-search "{" + (unless (or (py2texi-protected) + (save-excursion + (re-search-backward + "@\\([a-zA-Z]*\\|multitable.*\\){\\=" nil t))) + (forward-char -1) + (setq string (py2texi-tex-arguments 1)) + (insert "@" (substring string 0 (1- (length string))) "@}"))))) + + +(defun py2texi-fix-newlines () + "Remove extra newlines." + (py2texi-search "\n\n\n+" + (replace-match "\n\n")) + (py2texi-search-safe "@item.*\n\n" + (delete-backward-char 1)) + (py2texi-search "@end example" + (unless (looking-at "\n\n") + (insert "\n")))) + + +(defun py2texi-destroy-empties () + "Remove all comments. +This avoids some makeinfo errors." + (py2texi-search "@c\\>" + (unless (eq (py2texi-protected) t) + (delete-region (- (point) 2) (save-excursion (end-of-line) (point))) + (cond + ((looking-at "\n\n") + (delete-char 1)) + ((save-excursion (re-search-backward "^[ \t]*\\=" nil t)) + (delete-region (save-excursion (beginning-of-line) (point)) + (1+ (point)))))))) + + +(defun py2texi-adjust-level () + "Increase heading level to @chapter, if needed. +This is only needed for distutils, so it has a very simple form only." + (goto-char (point-min)) + (unless (re-search-forward "@chapter\\>" nil t) + (py2texi-search-safe "@section\\>" + (replace-match "@chapter" t)) + (py2texi-search-safe "@\\(sub\\)\\(sub\\)?section\\>" + (replace-match "" nil nil nil 1)))) + + +(defun py2texi-texinfo-escape (beg end) + "Escape Texinfo special characters in region." + (save-excursion + (goto-char beg) + (while (re-search-forward "[@{}]" end t) + (replace-match "@\\&")))) + + +(defun py2texi-protected () + "Return protection status of the point before current point." + (get-text-property (1- (point)) 'py2texi-protected)) + + +;;; Announce + +(provide 'py2texi) + + +;;; py2texi.el ends here diff --git a/sys/src/cmd/python/Doc/tools/refcounts.py b/sys/src/cmd/python/Doc/tools/refcounts.py new file mode 100644 index 000000000..31cfe909e --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/refcounts.py @@ -0,0 +1,98 @@ +"""Support functions for loading the reference count data file.""" +__version__ = '$Revision: 35267 $' + +import os +import sys + + +# Determine the expected location of the reference count file: +try: + p = os.path.dirname(__file__) +except NameError: + p = os.path.dirname(sys.argv[0]) +p = os.path.normpath(os.path.join(os.getcwd(), p, os.pardir, + "api", "refcounts.dat")) +DEFAULT_PATH = p +del p + + +def load(path=DEFAULT_PATH): + return loadfile(open(path)) + + +def loadfile(fp): + d = {} + while 1: + line = fp.readline() + if not line: + break + line = line.strip() + if line[:1] in ("", "#"): + # blank lines and comments + continue + parts = line.split(":", 4) + if len(parts) != 5: + raise ValueError("Not enough fields in %r" % line) + function, type, arg, refcount, comment = parts + if refcount == "null": + refcount = None + elif refcount: + refcount = int(refcount) + else: + refcount = None + # + # Get the entry, creating it if needed: + # + try: + entry = d[function] + except KeyError: + entry = d[function] = Entry(function) + # + # Update the entry with the new parameter or the result information. + # + if arg: + entry.args.append((arg, type, refcount)) + else: + entry.result_type = type + entry.result_refs = refcount + return d + + +class Entry: + def __init__(self, name): + self.name = name + self.args = [] + self.result_type = '' + self.result_refs = None + + +def dump(d): + """Dump the data in the 'canonical' format, with functions in + sorted order.""" + items = d.items() + items.sort() + first = 1 + for k, entry in items: + if first: + first = 0 + else: + print + s = entry.name + ":%s:%s:%s:" + if entry.result_refs is None: + r = "" + else: + r = entry.result_refs + print s % (entry.result_type, "", r) + for t, n, r in entry.args: + if r is None: + r = "" + print s % (t, n, r) + + +def main(): + d = load() + dump(d) + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/rewrite.py b/sys/src/cmd/python/Doc/tools/rewrite.py new file mode 100644 index 000000000..1acdd9984 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/rewrite.py @@ -0,0 +1,54 @@ +"""Simple script to replace @DATE@ and friends with real information. + +Usage: rewrite.py boilerplate.tex [VAR=value] ... <template >output +""" + +import sys +import time + + +def get_info(fp): + s = fp.read() + + d = {} + start = s.find(r"\date{") + if start >= 0: + end = s.find("}", start) + date = s[start+6:end] + if date == r"\today": + date = time.strftime("%B %d, %Y", time.localtime(time.time())) + d["DATE"] = date + return d + + +def main(): + s = sys.stdin.read() + if "@" in s: + # yes, we actully need to load the replacement values + d = get_info(open(sys.argv[1])) + for arg in sys.argv[2:]: + name, value = arg.split("=", 1) + d[name] = value + start = 0 + while 1: + start = s.find("@", start) + if start < 0: + break + end = s.find("@", start+1) + name = s[start+1:end] + if name: + value = d.get(name) + if value is None: + start = end + 1 + else: + s = s[:start] + value + s[end+1:] + start = start + len(value) + else: + # "@@" --> "@" + s = s[:start] + s[end:] + start = end + sys.stdout.write(s) + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/Makefile b/sys/src/cmd/python/Doc/tools/sgmlconv/Makefile new file mode 100644 index 000000000..d222933e7 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/Makefile @@ -0,0 +1,67 @@ +# Simple makefile to control XML generation for the entire document tree. +# This should be used from the top-level directory (Doc/), not the directory +# that actually contains this file: +# +# $ pwd +# .../Doc +# $ make -f tools/sgmlconv/Makefile + +TOPDIR=. +TOOLSDIR=tools + +SGMLRULES=../$(TOOLSDIR)/sgmlconv/make.rules +# The 'inst' and 'tut' directories break the conversion, so skip them for now. +SUBDIRS=api dist ext lib mac ref +SUBMAKE=$(MAKE) -f $(SGMLRULES) TOOLSDIR=../$(TOOLSDIR) + +all: xml + +.PHONY: esis xml +.PHONY: $(SUBDIRS) + +xml: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR && $(SUBMAKE) xml) || exit $$? ; done + +esis: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR && $(SUBMAKE) esis) || exit $$? ; done + +esis1: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR && $(SUBMAKE) esis1) || exit $$? ; done + +tarball: xml + tar cf - tools/sgmlconv */*.xml | gzip -9 >xml-1.5.2b2.tgz + +api: + cd api && $(SUBMAKE) + +dist: + cd dist && $(SUBMAKE) + +ext: + cd ext && $(SUBMAKE) + +inst: + cd inst && $(SUBMAKE) + +lib: + cd lib && $(SUBMAKE) + +mac: + cd mac && $(SUBMAKE) + +ref: + cd ref && $(SUBMAKE) + +tut: + cd tut && $(SUBMAKE) + +clean: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR && $(SUBMAKE) clean) || exit $$? ; done + +clobber: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR && $(SUBMAKE) clobber) || exit $$? ; done diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/README b/sys/src/cmd/python/Doc/tools/sgmlconv/README new file mode 100644 index 000000000..02564eb5e --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/README @@ -0,0 +1,58 @@ +These scripts and Makefile fragment are used to convert the Python +documentation in LaTeX format to XML. + +This material is preliminary and incomplete. Python 2.0 is required. + +To convert all documents to XML: + + cd Doc/ + make -f tools/sgmlconv/Makefile + +To convert one document to XML: + + cd Doc/<document-dir> + make -f ../tools/sgmlconv/make.rules TOOLSDIR=../tools + +Please send comments and bug reports to docs@python.org. + + +What do the tools do? +--------------------- + +latex2esis.py + Reads in a conversion specification written in XML + (conversion.xml), reads a LaTeX document fragment, and interprets + the markup according to the specification. The output is a stream + of ESIS events like those created by the nsgmls SGML parser, but + is *not* guaranteed to represent a single tree! This is done to + allow conversion per entity rather than per document. Since many + of the LaTeX files for the Python documentation contain two + sections on closely related modules, it is important to allow both + of the resulting <section> elements to exist in the same output + stream. Additionally, since comments are not supported in ESIS, + comments are converted to <COMMENT> elements, which might exist at + the same level as the top-level content elements. + + The output of latex2esis.py gets saved as <filename>.esis1. + +docfixer.py + This is the really painful part of the conversion. Well, it's the + second really painful part, but more of the pain is specific to + the structure of the Python documentation and desired output + rather than to the parsing of LaTeX markup. + + This script loads the ESIS data created by latex2esis.py into a + DOM document *fragment* (remember, the latex2esis.py output may + not be well-formed). Once loaded, it walks over the tree many + times looking for a variety of possible specific + micro-conversions. Most of the code is not in any way "general". + After processing the fragment, a new ESIS data stream is written + out. Like the input, it may not represent a well-formed + document, but does represent a parsed entity. + + The output of docfixer.py is what gets saved in <filename>.esis. + +esis2sgml.py + Reads an ESIS stream and convert to SGML or XML. This also + converts <COMMENT> elements to real comments. This works quickly + because there's not much to actually do. diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/conversion.xml b/sys/src/cmd/python/Doc/tools/sgmlconv/conversion.xml new file mode 100644 index 000000000..f0151f437 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/conversion.xml @@ -0,0 +1,914 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<conversion> + <!-- Miscellaneous. --> + <macro name="declaremodule"> + <attribute name="id" optional="yes"/> + <attribute name="type"/> + <attribute name="name"/> + </macro> + <macro name="modulesynopsis"> + <content/> + </macro> + <macro name="platform"> + <content/> + </macro> + <macro name="deprecated"> + <attribute name="version"/> + <content/> + </macro> + <macro name="label"> + <attribute name="id"/> + </macro> + <macro name="nodename" outputname="label"> + <attribute name="id"/> + </macro> + <macro name="localmoduletable"/> + <macro name="manpage"> + <attribute name="name"/> + <attribute name="section"/> + </macro> + <macro name="module"> + <content/> + </macro> + <macro name="moduleauthor"> + <attribute name="name"/> + <attribute name="email"/> + </macro> + <macro name="citetitle"> + <attribute name="href" optional="yes"/> + <content/> + </macro> + <macro name="pep"> + <attribute name="num"/> + </macro> + <macro name="rfc"> + <attribute name="num"/> + </macro> + <macro name="sectionauthor" outputname="author"> + <attribute name="name"/> + <attribute name="email"/> + </macro> + <macro name="author"> + <attribute name="name"/> + </macro> + <macro name="authoraddress"> + <content/> + </macro> + <macro name="shortversion"/> + <macro name="note"> + <content/> + </macro> + <macro name="warning"> + <content/> + </macro> + <environment name="notice"> + <attribute name="role" optional="yes"/> + </environment> + + <macro name="menuselection"> + <content/> + </macro> + <macro name="sub"/> + + <!-- These are broken: we need to re-order the optional and required + parameters, making the optional parameter the content for the + element. latex2esis.py is not powerful enough to handle this. + --> + <macro name="versionadded"> + <attribute name="info" optional="yes"/> + <attribute name="version"/> + </macro> + <macro name="versionchanged"> + <attribute name="info" optional="yes"/> + <attribute name="version"/> + </macro> + + <!-- Module referencing. --> + <macro name="refmodule" outputname="module"> + <!-- this causes the optional parameter to \refmodule to be + discarded --> + <attribute name="" optional="yes"/> + <content/> + </macro> + + <!-- Information units. --> + <!-- C things. --> + <environment name="cfuncdesc"> + <attribute name="type"/> + <attribute name="name"/> + <child name="args"/> + </environment> + <environment name="csimplemacrodesc"> + <attribute name="name"/> + </environment> + <environment name="ctypedesc"> + <attribute name="tag" optional="yes"/> + <attribute name="name"/> + </environment> + <environment name="cvardesc"> + <attribute name="type"/> + <attribute name="name"/> + </environment> + + <!-- Python things. --> + <macro name="optional"> + <content/> + </macro> + <macro name="unspecified"/> + <macro name="moreargs"/> + <environment name="classdesc"> + <attribute name="name"/> + <child name="args"/> + </environment> + <environment name="classdesc*" outputname="classdesc"> + <attribute name="name"/> + </environment> + <environment name="datadesc"> + <attribute name="name"/> + </environment> + <environment name="datadescni" outputname="datadesc"> + <attribute name="index">no</attribute> + <attribute name="name"/> + </environment> + <macro name="dataline"> + <attribute name="name"/> + </macro> + <environment name="excclassdesc"> + <attribute name="name"/> + <child name="args"/> + </environment> + <environment name="excdesc"> + <attribute name="name"/> + </environment> + + <environment name="funcdesc"> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="funcline"> + <attribute name="name"/> + <child name="args"/> + </macro> + <environment name="funcdescni" outputname="funcdesc"> + <attribute name="index">no</attribute> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="funclineni" outputname="funcline"> + <attribute name="index">no</attribute> + <attribute name="name"/> + <child name="args"/> + </macro> + + <environment name="memberdesc"> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + </environment> + <environment name="memberdescni" outputname="memberdesc"> + <attribute name="index">no</attribute> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + </environment> + <macro name="memberline"> + <attribute name="name"/> + </macro> + + <environment name="methoddesc"> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="methodline"> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </macro> + <environment name="methoddescni"> + <attribute name="index">no</attribute> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="methodlineni" outputname="methodline"> + <attribute name="index">no</attribute> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </macro> + + <environment name="opcodedesc"> + <attribute name="name"/> + <attribute name="var"/> + </environment> + + <!-- "See also:" sections. --> + <environment name="seealso*" outputname="seealso"> + <attribute name="sidebar">no</attribute> + </environment> + <macro name="seemodule"> + <!-- this causes the optional parameter to \seemodule to be + discarded --> + <attribute name="" optional="yes"/> + <attribute name="name"/> + <child name="description"/> + </macro> + <macro name="seepep"> + <attribute name="number"/> + <child name="title"/> + <child name="description"/> + </macro> + <macro name="seerfc"> + <attribute name="number"/> + <child name="title"/> + <child name="description"/> + </macro> + <macro name="seetext"> + <child name="description"/> + </macro> + <macro name="seetitle"> + <attribute name="href" optional="yes"/> + <child name="title"/> + <child name="description"/> + </macro> + <macro name="seeurl"> + <attribute name="href"/> + <child name="description"/> + </macro> + + <!-- Index-generating markup. --> + <macro name="index" outputname="indexterm"> + <attribute name="term1"/> + </macro> + <macro name="indexii" outputname="indexterm"> + <attribute name="term1"/> + <attribute name="term2"/> + </macro> + <macro name="indexiii" outputname="indexterm"> + <attribute name="term1"/> + <attribute name="term2"/> + <attribute name="term3"/> + </macro> + <macro name="indexiv" outputname="indexterm"> + <attribute name="term1"/> + <attribute name="term2"/> + <attribute name="term3"/> + <attribute name="term4"/> + </macro> + + <macro name="ttindex" outputname="indexterm"> + <attribute name="style">tt</attribute> + <attribute name="term1"/> + </macro> + + <macro name="refmodindex"> + <attribute name="module"/> + </macro> + <macro name="stmodindex"> + <attribute name="module"/> + </macro> + <macro name="refbimodindex" outputname="refmodindex"> + <attribute name="module"/> + </macro> + <macro name="refexmodindex" outputname="refmodindex"> + <attribute name="module"/> + </macro> + <macro name="refstmodindex" outputname="refmodindex"> + <attribute name="module"/> + </macro> + + <macro name="bifuncindex"> + <attribute name="name"/> + </macro> + <macro name="exindex"> + <attribute name="name"/> + </macro> + <macro name="obindex"> + <attribute name="name"/> + </macro> + <macro name="kwindex"> + <attribute name="name"/> + </macro> + <macro name="opindex"> + <attribute name="type"/> + </macro> + <macro name="stindex"> + <attribute name="type"/> + </macro> + <macro name="withsubitem"> + <attribute name="text"/> + <content/> + </macro> + <macro name="setindexsubitem"> + <attribute name="text"/> + </macro> + + <!-- Entity management. --> + <macro name="include" outputname="xi:include"> + <attribute name="href"/> + </macro> + <macro name="input" outputname="xi:include"> + <attribute name="href"/> + </macro> + + <!-- Large-scale document structure. --> + <macro name="documentclass"> + <attribute name="classname"/> + </macro> + + <macro name="usepackage"> + <attribute name="options" optional="yes"/> + <attribute name="pkg"/> + </macro> + + <environment name="document" + endcloses="chapter chapter* section section* + subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph + subparagraph*"> + <attribute name="xmlns:xi" + >http://www.w3.org/2001/XInclude</attribute> + </environment> + + <macro name="chapter" + closes="chapter chapter* section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="chapter*" outputname="chapter" + closes="chapter chapter* section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="section" + closes="section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="section*" outputname="section" + closes="section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="subsection" + closes="subsection subsection* subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="subsection*" outputname="subsection" + closes="subsection subsection* subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="subsubsection" + closes="subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="subsubsection*" outputname="subsubsection" + closes="subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="paragraph" + closes="paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="paragraph*" outputname="paragraph" + closes="paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="subparagraph" + closes="subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="subparagraph*" outputname="subparagraph" + closes="subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="title"> + <content/> + </macro> + + <macro name="appendix" outputname="back-matter" + closes="chapter chapter* section subsection subsubsection + paragraph subparagraph"/> + + <environment name="list" + endcloses="item"> + <attribute name="bullet"/> + <attribute name="init"/> + </environment> + <macro name="item" closes="item"> + <child name="leader" optional="yes"/> + <content implied="yes"/> + </macro> + + <macro name="ref"> + <attribute name="ref"/> + </macro> + + <environment name="description" outputname="descriptionlist" + endcloses="item"/> + + <environment name="enumerate" outputname="enumeration" + endcloses="item"/> + + <environment name="fulllineitems" + endcloses="item"/> + + <environment name="itemize" + endcloses="item"/> + + <environment name="definitions" outputname="definitionlist" + encloses="term"/> + <macro name="term" closes="definition"> + <!-- not really optional, but uses the [] syntax --> + <child name="term" optional="yes"/> + <child name="definition" implied="yes"/> + </macro> + + <environment name="alltt" outputname="verbatim"/> + <environment name="comment" verbatim="yes"/> + <environment name="verbatim" verbatim="yes"/> + <environment name="verbatim*" verbatim="yes"> + <!-- not used anywhere, but it's a standard LaTeXism --> + <attribute name="spaces">visible</attribute> + </environment> + <macro name="verbatiminput" ouptutname="xi:include"> + <attribute name="parse">text</attribute> + <attribute name="href"/> + </macro> + + <!-- Table markup. --> + <macro name="hline"/> + <environment name="tableii" outputname="table"> + <attribute name="cols">2</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <environment name="longtableii" outputname="table"> + <attribute name="cols">2</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <macro name="lineii" outputname="row"> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </macro> + + <environment name="tableiii" outputname="table"> + <attribute name="cols">3</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <environment name="longtableiii" outputname="table"> + <attribute name="cols">3</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <macro name="lineiii" outputname="row"> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </macro> + + <environment name="tableiv" outputname="table"> + <attribute name="cols">4</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <environment name="longtableiv" outputname="table"> + <attribute name="cols">4</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <macro name="lineiv" outputname="row"> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </macro> + + <environment name="tablev" outputname="table"> + <attribute name="cols">4</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <environment name="longtablev" outputname="table"> + <attribute name="cols">4</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <macro name="linev" outputname="row"> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </macro> + + <!-- These are handled at a later translation stage, at least for now. --> + <macro name="Cpp" outputname=""> + <text>C++</text> + </macro> + <macro name="geq" outputname=""> + <entityref name="geq"/> + </macro> + <macro name="infinity" outputname=""> + <entityref name="infin"/> + </macro> + <macro name="LaTeX" outputname=""> + <text>LaTeX</text> + </macro> + <macro name="ldots" outputname=""> + <text>...</text> + </macro> + <macro name="leq" outputname=""> + <entityref name="leq"/> + </macro> + <macro name="plusminus" outputname=""> + <entityref name="plusmn"/> + </macro> + <macro name="TeX" outputname=""> + <text>TeX</text> + </macro> + <macro name="version"/> + + <!-- Distutils things. --> + <macro name="command"> + <content/> + </macro> + <macro name="option"> + <content/> + </macro> + <macro name="filevar" outputname="var"> + <content/> + </macro> + <macro name="XXX" outputname="editorial-comment"> + <content/> + </macro> + + <!-- Grammar production lists --> + <environment name="productionlist"> + <attribute name="grammar" optional="yes"/> + </environment> + <macro name="production"> + <attribute name="token"/> + <content/> + </macro> + <macro name="productioncont"> + <content/> + </macro> + <macro name="token" outputname="grammartoken"> + <content/> + </macro> + <macro name="grammartoken"> + <content/> + </macro> + + <!-- Misc. --> + <macro name="emph"> + <content/> + </macro> + <macro name="strong"> + <content/> + </macro> + <macro name="textrm"> + <content/> + </macro> + <macro name="texttt"> + <content/> + </macro> + <macro name="code"> + <content/> + </macro> + <macro name="exception"> + <content/> + </macro> + <macro name="keyword"> + <content/> + </macro> + <macro name="samp"> + <content/> + </macro> + <macro name="class"> + <content/> + </macro> + <macro name="cdata"> + <content/> + </macro> + <macro name="cfunction"> + <content/> + </macro> + <macro name="csimplemacro"> + <content/> + </macro> + <macro name="ctype"> + <content/> + </macro> + <macro name="pytype"> + <content/> + </macro> + <macro name="character"> + <content/> + </macro> + <macro name="constant"> + <content/> + </macro> + <macro name="envvar" outputname="envar"> + <content/> + </macro> + <macro name="file" outputname="filename"> + <content/> + </macro> + <macro name="filenq" outputname="filename"> + <attribute name="quote">no</attribute> + <content/> + </macro> + <macro name="function"> + <content/> + </macro> + <macro name="kbd" outputname="keysym"> + <content/> + </macro> + <macro name="mailheader"> + <content/> + </macro> + <macro name="makevar"> + <content/> + </macro> + <macro name="method"> + <content/> + </macro> + <macro name="member"> + <content/> + </macro> + <macro name="mimetype"> + <content/> + </macro> + <macro name="newsgroup"> + <content/> + </macro> + <macro name="program" outputname="command"> + <content/> + </macro> + <macro name="programopt" outputname="option"> + <content/> + </macro> + <macro name="longprogramopt" outputname="longoption"> + <content/> + </macro> + <macro name="regexp"> + <content/> + </macro> + <macro name="var"> + <content/> + </macro> + <macro name="email"> + <content/> + </macro> + <macro name="ulink"> + <!-- order of the parameters makes this difficult; + we'll need to fix it up to <ulink href="...">...</ulink> + in docfixer.py. + --> + <child name="text"/> + <child name="href"/> + </macro> + <macro name="url"> + <content/> + </macro> + <macro name="footnote"> + <content/> + </macro> + <macro name="dfn" outputname="definedterm"> + <content/> + </macro> + + <macro name="mbox"> + <content/> + </macro> + + <!-- minimal math stuff to get by --> + <macro name="pi"/> + <macro name="sqrt"> + <content/> + </macro> + <macro name="frac" outputname="fraction"> + <child name="numerator"/> + <child name="denominator"/> + </macro> + <macro name="sum"> + <content/> + </macro> + + <macro name="leftline" outputname=""> + <content/> + </macro> + + <!-- Conversions to text; perhaps could be different? There's --> + <!-- no way for a style sheet to work with these this way. --> + <macro name="ABC" outputname=""> + <text>ABC</text> + </macro> + <macro name="ASCII" outputname=""> + <text>ASCII</text> + </macro> + <macro name="C" outputname=""> + <text>C</text> + </macro> + <macro name="EOF" outputname=""> + <text>EOF</text> + </macro> + <macro name="e" outputname=""> + <text>\</text> + </macro> + <macro name="NULL" outputname="constant"> + <text>NULL</text> + </macro> + <macro name="POSIX" outputname=""> + <text>POSIX</text> + </macro> + <macro name="UNIX" outputname=""> + <text>Unix</text> + </macro> + <macro name="textasciicircum" outputname=""> + <text>^</text> + </macro> + <macro name="textasciitilde" outputname=""> + <text>~</text> + </macro> + <macro name="textbackslash" outputname=""> + <text>\</text> + </macro> + <macro name="textbar" outputname=""> + <text>|</text> + </macro> + <macro name="textgreater" outputname=""> + <text>&gt;</text> + </macro> + <macro name="textless" outputname=""> + <text>&lt;</text> + </macro> + + <!-- These will end up disappearing as well! --> + <macro name="catcode" outputname=""/> + <macro name="fi" outputname=""/> + <macro name="ifhtml" outputname=""/> + <macro name="indexname" outputname=""/> + <macro name="labelwidth" outputname=""/> + <macro name="large" outputname=""/> + <macro name="leftmargin" outputname=""/> + <macro name="makeindex" outputname=""/> + <macro name="makemodindex" outputname=""/> + <macro name="maketitle" outputname=""/> + <macro name="noindent" outputname=""/> + <macro name="protect" outputname=""/> + <macro name="textwidth"/> + <macro name="renewcommand"> + <attribute name="macro"/> + <attribute name="nargs" optional="yes"/> + <content/> + </macro> + <macro name="tableofcontents" outputname=""/> + <macro name="vspace"> + <attribute name="size"/> + </macro> +</conversion> diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/docfixer.py b/sys/src/cmd/python/Doc/tools/sgmlconv/docfixer.py new file mode 100755 index 000000000..81519ee58 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/docfixer.py @@ -0,0 +1,1073 @@ +#! /usr/bin/env python + +"""Perform massive transformations on a document tree created from the LaTeX +of the Python documentation, and dump the ESIS data for the transformed tree. +""" + + +import errno +import esistools +import re +import sys +import xml.dom +import xml.dom.minidom + +ELEMENT = xml.dom.Node.ELEMENT_NODE +ENTITY_REFERENCE = xml.dom.Node.ENTITY_REFERENCE_NODE +TEXT = xml.dom.Node.TEXT_NODE + + +class ConversionError(Exception): + pass + + +ewrite = sys.stderr.write +try: + # We can only do this trick on Unix (if tput is on $PATH)! + if sys.platform != "posix" or not sys.stderr.isatty(): + raise ImportError + import commands +except ImportError: + bwrite = ewrite +else: + def bwrite(s, BOLDON=commands.getoutput("tput bold"), + BOLDOFF=commands.getoutput("tput sgr0")): + ewrite("%s%s%s" % (BOLDON, s, BOLDOFF)) + + +PARA_ELEMENT = "para" + +DEBUG_PARA_FIXER = 0 + +if DEBUG_PARA_FIXER: + def para_msg(s): + ewrite("*** %s\n" % s) +else: + def para_msg(s): + pass + + +def get_first_element(doc, gi): + for n in doc.childNodes: + if n.nodeName == gi: + return n + +def extract_first_element(doc, gi): + node = get_first_element(doc, gi) + if node is not None: + doc.removeChild(node) + return node + + +def get_documentElement(node): + result = None + for child in node.childNodes: + if child.nodeType == ELEMENT: + result = child + return result + + +def set_tagName(elem, gi): + elem.nodeName = elem.tagName = gi + + +def find_all_elements(doc, gi): + nodes = [] + if doc.nodeName == gi: + nodes.append(doc) + for child in doc.childNodes: + if child.nodeType == ELEMENT: + if child.tagName == gi: + nodes.append(child) + for node in child.getElementsByTagName(gi): + nodes.append(node) + return nodes + +def find_all_child_elements(doc, gi): + nodes = [] + for child in doc.childNodes: + if child.nodeName == gi: + nodes.append(child) + return nodes + + +def find_all_elements_from_set(doc, gi_set): + return __find_all_elements_from_set(doc, gi_set, []) + +def __find_all_elements_from_set(doc, gi_set, nodes): + if doc.nodeName in gi_set: + nodes.append(doc) + for child in doc.childNodes: + if child.nodeType == ELEMENT: + __find_all_elements_from_set(child, gi_set, nodes) + return nodes + + +def simplify(doc, fragment): + # Try to rationalize the document a bit, since these things are simply + # not valid SGML/XML documents as they stand, and need a little work. + documentclass = "document" + inputs = [] + node = extract_first_element(fragment, "documentclass") + if node is not None: + documentclass = node.getAttribute("classname") + node = extract_first_element(fragment, "title") + if node is not None: + inputs.append(node) + # update the name of the root element + node = get_first_element(fragment, "document") + if node is not None: + set_tagName(node, documentclass) + # Move everything that comes before this node into this node; + # this will be the document element. + nodelist = fragment.childNodes + point = node.firstChild + while not nodelist[0].isSameNode(node): + node.insertBefore(nodelist[0], point) + while 1: + node = extract_first_element(fragment, "input") + if node is None: + break + inputs.append(node) + if inputs: + docelem = get_documentElement(fragment) + inputs.reverse() + for node in inputs: + text = doc.createTextNode("\n") + docelem.insertBefore(text, docelem.firstChild) + docelem.insertBefore(node, text) + docelem.insertBefore(doc.createTextNode("\n"), docelem.firstChild) + while fragment.firstChild and fragment.firstChild.nodeType == TEXT: + fragment.removeChild(fragment.firstChild) + + +def cleanup_root_text(doc): + discards = [] + skip = 0 + for n in doc.childNodes: + prevskip = skip + skip = 0 + if n.nodeType == TEXT and not prevskip: + discards.append(n) + elif n.nodeName == "COMMENT": + skip = 1 + for node in discards: + doc.removeChild(node) + + +DESCRIPTOR_ELEMENTS = ( + "cfuncdesc", "cvardesc", "ctypedesc", + "classdesc", "memberdesc", "memberdescni", "methoddesc", "methoddescni", + "excdesc", "funcdesc", "funcdescni", "opcodedesc", + "datadesc", "datadescni", + ) + +def fixup_descriptors(doc, fragment): + sections = find_all_elements(fragment, "section") + for section in sections: + find_and_fix_descriptors(doc, section) + + +def find_and_fix_descriptors(doc, container): + children = container.childNodes + for child in children: + if child.nodeType == ELEMENT: + tagName = child.tagName + if tagName in DESCRIPTOR_ELEMENTS: + rewrite_descriptor(doc, child) + elif tagName == "subsection": + find_and_fix_descriptors(doc, child) + + +def rewrite_descriptor(doc, descriptor): + # + # Do these things: + # 1. Add an "index='no'" attribute to the element if the tagName + # ends in 'ni', removing the 'ni' from the name. + # 2. Create a <signature> from the name attribute + # 2a.Create an <args> if it appears to be available. + # 3. Create additional <signature>s from <*line{,ni}> elements, + # if found. + # 4. If a <versionadded> is found, move it to an attribute on the + # descriptor. + # 5. Move remaining child nodes to a <description> element. + # 6. Put it back together. + # + # 1. + descname = descriptor.tagName + index = descriptor.getAttribute("name") != "no" + desctype = descname[:-4] # remove 'desc' + linename = desctype + "line" + if not index: + linename = linename + "ni" + # 2. + signature = doc.createElement("signature") + name = doc.createElement("name") + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(name) + name.appendChild(doc.createTextNode(descriptor.getAttribute("name"))) + descriptor.removeAttribute("name") + # 2a. + if descriptor.hasAttribute("var"): + if descname != "opcodedesc": + raise RuntimeError, \ + "got 'var' attribute on descriptor other than opcodedesc" + variable = descriptor.getAttribute("var") + if variable: + args = doc.createElement("args") + args.appendChild(doc.createTextNode(variable)) + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(args) + descriptor.removeAttribute("var") + newchildren = [signature] + children = descriptor.childNodes + pos = skip_leading_nodes(children) + if pos < len(children): + child = children[pos] + if child.nodeName == "args": + # move <args> to <signature>, or remove if empty: + child.parentNode.removeChild(child) + if len(child.childNodes): + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(child) + signature.appendChild(doc.createTextNode("\n ")) + # 3, 4. + pos = skip_leading_nodes(children, pos) + while pos < len(children) \ + and children[pos].nodeName in (linename, "versionadded"): + if children[pos].tagName == linename: + # this is really a supplemental signature, create <signature> + oldchild = children[pos].cloneNode(1) + try: + sig = methodline_to_signature(doc, children[pos]) + except KeyError: + print oldchild.toxml() + raise + newchildren.append(sig) + else: + # <versionadded added=...> + descriptor.setAttribute( + "added", children[pos].getAttribute("version")) + pos = skip_leading_nodes(children, pos + 1) + # 5. + description = doc.createElement("description") + description.appendChild(doc.createTextNode("\n")) + newchildren.append(description) + move_children(descriptor, description, pos) + last = description.childNodes[-1] + if last.nodeType == TEXT: + last.data = last.data.rstrip() + "\n " + # 6. + # should have nothing but whitespace and signature lines in <descriptor>; + # discard them + while descriptor.childNodes: + descriptor.removeChild(descriptor.childNodes[0]) + for node in newchildren: + descriptor.appendChild(doc.createTextNode("\n ")) + descriptor.appendChild(node) + descriptor.appendChild(doc.createTextNode("\n")) + + +def methodline_to_signature(doc, methodline): + signature = doc.createElement("signature") + signature.appendChild(doc.createTextNode("\n ")) + name = doc.createElement("name") + name.appendChild(doc.createTextNode(methodline.getAttribute("name"))) + methodline.removeAttribute("name") + signature.appendChild(name) + if len(methodline.childNodes): + args = doc.createElement("args") + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(args) + move_children(methodline, args) + signature.appendChild(doc.createTextNode("\n ")) + return signature + + +def move_children(origin, dest, start=0): + children = origin.childNodes + while start < len(children): + node = children[start] + origin.removeChild(node) + dest.appendChild(node) + + +def handle_appendix(doc, fragment): + # must be called after simplfy() if document is multi-rooted to begin with + docelem = get_documentElement(fragment) + toplevel = docelem.tagName == "manual" and "chapter" or "section" + appendices = 0 + nodes = [] + for node in docelem.childNodes: + if appendices: + nodes.append(node) + elif node.nodeType == ELEMENT: + appnodes = node.getElementsByTagName("appendix") + if appnodes: + appendices = 1 + parent = appnodes[0].parentNode + parent.removeChild(appnodes[0]) + parent.normalize() + if nodes: + map(docelem.removeChild, nodes) + docelem.appendChild(doc.createTextNode("\n\n\n")) + back = doc.createElement("back-matter") + docelem.appendChild(back) + back.appendChild(doc.createTextNode("\n")) + while nodes and nodes[0].nodeType == TEXT \ + and not nodes[0].data.strip(): + del nodes[0] + map(back.appendChild, nodes) + docelem.appendChild(doc.createTextNode("\n")) + + +def handle_labels(doc, fragment): + for label in find_all_elements(fragment, "label"): + id = label.getAttribute("id") + if not id: + continue + parent = label.parentNode + parentTagName = parent.tagName + if parentTagName == "title": + parent.parentNode.setAttribute("id", id) + else: + parent.setAttribute("id", id) + # now, remove <label id="..."/> from parent: + parent.removeChild(label) + if parentTagName == "title": + parent.normalize() + children = parent.childNodes + if children[-1].nodeType == TEXT: + children[-1].data = children[-1].data.rstrip() + + +def fixup_trailing_whitespace(doc, fragment, wsmap): + queue = [fragment] + fixups = [] + while queue: + node = queue[0] + del queue[0] + if wsmap.has_key(node.nodeName): + fixups.append(node) + for child in node.childNodes: + if child.nodeType == ELEMENT: + queue.append(child) + + # reverse the list to process from the inside out + fixups.reverse() + for node in fixups: + node.parentNode.normalize() + lastchild = node.lastChild + before, after = wsmap[node.tagName] + if lastchild.nodeType == TEXT: + data = lastchild.data.rstrip() + before + lastchild.data = data + norm = 0 + if wsmap[node.tagName]: + nextnode = node.nextSibling + if nextnode and nextnode.nodeType == TEXT: + nextnode.data = after + nextnode.data.lstrip() + else: + wsnode = doc.createTextNode(after) + node.parentNode.insertBefore(wsnode, nextnode) + # hack to get the title in place: + if node.tagName == "title" \ + and node.parentNode.firstChild.nodeType == ELEMENT: + node.parentNode.insertBefore(doc.createTextNode("\n "), + node.parentNode.firstChild) + node.parentNode.normalize() + + +def normalize(doc): + for node in doc.childNodes: + if node.nodeType == ELEMENT: + node.normalize() + + +def cleanup_trailing_parens(doc, element_names): + d = {} + for gi in element_names: + d[gi] = gi + rewrite_element = d.has_key + queue = [node for node in doc.childNodes if node.nodeType == ELEMENT] + while queue: + node = queue[0] + del queue[0] + if rewrite_element(node.tagName): + lastchild = node.lastChild + if lastchild and lastchild.nodeType == TEXT: + data = lastchild.data + if data.endswith("()"): + lastchild.data = data[:-2] + else: + for child in node.childNodes: + if child.nodeType == ELEMENT: + queue.append(child) + + +def contents_match(left, right): + left_children = left.childNodes + right_children = right.childNodes + if len(left_children) != len(right_children): + return 0 + for l, r in map(None, left_children, right_children): + nodeType = l.nodeType + if nodeType != r.nodeType: + return 0 + if nodeType == ELEMENT: + if l.tagName != r.tagName: + return 0 + # should check attributes, but that's not a problem here + if not contents_match(l, r): + return 0 + elif nodeType == TEXT: + if l.data != r.data: + return 0 + else: + # not quite right, but good enough + return 0 + return 1 + + +def create_module_info(doc, section): + # Heavy. + node = extract_first_element(section, "modulesynopsis") + if node is None: + return + set_tagName(node, "synopsis") + lastchild = node.childNodes[-1] + if lastchild.nodeType == TEXT \ + and lastchild.data[-1:] == ".": + lastchild.data = lastchild.data[:-1] + modauthor = extract_first_element(section, "moduleauthor") + if modauthor: + set_tagName(modauthor, "author") + modauthor.appendChild(doc.createTextNode( + modauthor.getAttribute("name"))) + modauthor.removeAttribute("name") + platform = extract_first_element(section, "platform") + if section.tagName == "section": + modinfo_pos = 2 + modinfo = doc.createElement("moduleinfo") + moddecl = extract_first_element(section, "declaremodule") + name = None + if moddecl: + modinfo.appendChild(doc.createTextNode("\n ")) + name = moddecl.attributes["name"].value + namenode = doc.createElement("name") + namenode.appendChild(doc.createTextNode(name)) + modinfo.appendChild(namenode) + type = moddecl.attributes.get("type") + if type: + type = type.value + modinfo.appendChild(doc.createTextNode("\n ")) + typenode = doc.createElement("type") + typenode.appendChild(doc.createTextNode(type)) + modinfo.appendChild(typenode) + versionadded = extract_first_element(section, "versionadded") + if versionadded: + modinfo.setAttribute("added", versionadded.getAttribute("version")) + title = get_first_element(section, "title") + if title: + children = title.childNodes + if len(children) >= 2 \ + and children[0].nodeName == "module" \ + and children[0].childNodes[0].data == name: + # this is it; morph the <title> into <short-synopsis> + first_data = children[1] + if first_data.data[:4] == " ---": + first_data.data = first_data.data[4:].lstrip() + set_tagName(title, "short-synopsis") + if children[-1].nodeType == TEXT \ + and children[-1].data[-1:] == ".": + children[-1].data = children[-1].data[:-1] + section.removeChild(title) + section.removeChild(section.childNodes[0]) + title.removeChild(children[0]) + modinfo_pos = 0 + else: + ewrite("module name in title doesn't match" + " <declaremodule/>; no <short-synopsis/>\n") + else: + ewrite("Unexpected condition: <section/> without <title/>\n") + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(node) + if title and not contents_match(title, node): + # The short synopsis is actually different, + # and needs to be stored: + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(title) + if modauthor: + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(modauthor) + if platform: + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(platform) + modinfo.appendChild(doc.createTextNode("\n ")) + section.insertBefore(modinfo, section.childNodes[modinfo_pos]) + section.insertBefore(doc.createTextNode("\n "), modinfo) + # + # The rest of this removes extra newlines from where we cut out + # a lot of elements. A lot of code for minimal value, but keeps + # keeps the generated *ML from being too funny looking. + # + section.normalize() + children = section.childNodes + for i in range(len(children)): + node = children[i] + if node.nodeName == "moduleinfo": + nextnode = children[i+1] + if nextnode.nodeType == TEXT: + data = nextnode.data + s = data.lstrip() + if len(s) < (len(data) - 4): + nextnode.data = "\n\n\n" + s + + +def cleanup_synopses(doc, fragment): + for node in find_all_elements(fragment, "section"): + create_module_info(doc, node) + + +def fixup_table_structures(doc, fragment): + for table in find_all_elements(fragment, "table"): + fixup_table(doc, table) + + +def fixup_table(doc, table): + # create the table head + thead = doc.createElement("thead") + row = doc.createElement("row") + move_elements_by_name(doc, table, row, "entry") + thead.appendChild(doc.createTextNode("\n ")) + thead.appendChild(row) + thead.appendChild(doc.createTextNode("\n ")) + # create the table body + tbody = doc.createElement("tbody") + prev_row = None + last_was_hline = 0 + children = table.childNodes + for child in children: + if child.nodeType == ELEMENT: + tagName = child.tagName + if tagName == "hline" and prev_row is not None: + prev_row.setAttribute("rowsep", "1") + elif tagName == "row": + prev_row = child + # save the rows: + tbody.appendChild(doc.createTextNode("\n ")) + move_elements_by_name(doc, table, tbody, "row", sep="\n ") + # and toss the rest: + while children: + child = children[0] + nodeType = child.nodeType + if nodeType == TEXT: + if child.data.strip(): + raise ConversionError("unexpected free data in <%s>: %r" + % (table.tagName, child.data)) + table.removeChild(child) + continue + if nodeType == ELEMENT: + if child.tagName != "hline": + raise ConversionError( + "unexpected <%s> in table" % child.tagName) + table.removeChild(child) + continue + raise ConversionError( + "unexpected %s node in table" % child.__class__.__name__) + # nothing left in the <table>; add the <thead> and <tbody> + tgroup = doc.createElement("tgroup") + tgroup.appendChild(doc.createTextNode("\n ")) + tgroup.appendChild(thead) + tgroup.appendChild(doc.createTextNode("\n ")) + tgroup.appendChild(tbody) + tgroup.appendChild(doc.createTextNode("\n ")) + table.appendChild(tgroup) + # now make the <entry>s look nice: + for row in table.getElementsByTagName("row"): + fixup_row(doc, row) + + +def fixup_row(doc, row): + entries = [] + map(entries.append, row.childNodes[1:]) + for entry in entries: + row.insertBefore(doc.createTextNode("\n "), entry) +# row.appendChild(doc.createTextNode("\n ")) + + +def move_elements_by_name(doc, source, dest, name, sep=None): + nodes = [] + for child in source.childNodes: + if child.nodeName == name: + nodes.append(child) + for node in nodes: + source.removeChild(node) + dest.appendChild(node) + if sep: + dest.appendChild(doc.createTextNode(sep)) + + +RECURSE_INTO_PARA_CONTAINERS = ( + "chapter", "abstract", "enumerate", + "section", "subsection", "subsubsection", + "paragraph", "subparagraph", "back-matter", + "howto", "manual", + "item", "itemize", "fulllineitems", "enumeration", "descriptionlist", + "definitionlist", "definition", + ) + +PARA_LEVEL_ELEMENTS = ( + "moduleinfo", "title", "verbatim", "enumerate", "item", + "interpreter-session", "back-matter", "interactive-session", + "opcodedesc", "classdesc", "datadesc", + "cfuncdesc", "ctypedesc", "cvardesc", + "funcdesc", "methoddesc", "excdesc", "memberdesc", "membderdescni", + "funcdescni", "methoddescni", "excdescni", + "tableii", "tableiii", "tableiv", "localmoduletable", + "sectionauthor", "seealso", "itemize", + # include <para>, so we can just do it again to get subsequent paras: + PARA_ELEMENT, + ) + +PARA_LEVEL_PRECEEDERS = ( + "setindexsubitem", "author", + "stindex", "obindex", "COMMENT", "label", "xi:include", "title", + "versionadded", "versionchanged", "declaremodule", "modulesynopsis", + "moduleauthor", "indexterm", "leader", + ) + + +def fixup_paras(doc, fragment): + for child in fragment.childNodes: + if child.nodeName in RECURSE_INTO_PARA_CONTAINERS: + fixup_paras_helper(doc, child) + descriptions = find_all_elements(fragment, "description") + for description in descriptions: + fixup_paras_helper(doc, description) + + +def fixup_paras_helper(doc, container, depth=0): + # document is already normalized + children = container.childNodes + start = skip_leading_nodes(children) + while len(children) > start: + if children[start].nodeName in RECURSE_INTO_PARA_CONTAINERS: + # Something to recurse into: + fixup_paras_helper(doc, children[start]) + else: + # Paragraph material: + build_para(doc, container, start, len(children)) + if DEBUG_PARA_FIXER and depth == 10: + sys.exit(1) + start = skip_leading_nodes(children, start + 1) + + +def build_para(doc, parent, start, i): + children = parent.childNodes + after = start + 1 + have_last = 0 + BREAK_ELEMENTS = PARA_LEVEL_ELEMENTS + RECURSE_INTO_PARA_CONTAINERS + # Collect all children until \n\n+ is found in a text node or a + # member of BREAK_ELEMENTS is found. + for j in range(start, i): + after = j + 1 + child = children[j] + nodeType = child.nodeType + if nodeType == ELEMENT: + if child.tagName in BREAK_ELEMENTS: + after = j + break + elif nodeType == TEXT: + pos = child.data.find("\n\n") + if pos == 0: + after = j + break + if pos >= 1: + child.splitText(pos) + break + else: + have_last = 1 + if (start + 1) > after: + raise ConversionError( + "build_para() could not identify content to turn into a paragraph") + if children[after - 1].nodeType == TEXT: + # we may need to split off trailing white space: + child = children[after - 1] + data = child.data + if data.rstrip() != data: + have_last = 0 + child.splitText(len(data.rstrip())) + para = doc.createElement(PARA_ELEMENT) + prev = None + indexes = range(start, after) + indexes.reverse() + for j in indexes: + node = parent.childNodes[j] + parent.removeChild(node) + para.insertBefore(node, prev) + prev = node + if have_last: + parent.appendChild(para) + parent.appendChild(doc.createTextNode("\n\n")) + return len(parent.childNodes) + else: + nextnode = parent.childNodes[start] + if nextnode.nodeType == TEXT: + if nextnode.data and nextnode.data[0] != "\n": + nextnode.data = "\n" + nextnode.data + else: + newnode = doc.createTextNode("\n") + parent.insertBefore(newnode, nextnode) + nextnode = newnode + start = start + 1 + parent.insertBefore(para, nextnode) + return start + 1 + + +def skip_leading_nodes(children, start=0): + """Return index into children of a node at which paragraph building should + begin or a recursive call to fixup_paras_helper() should be made (for + subsections, etc.). + + When the return value >= len(children), we've built all the paras we can + from this list of children. + """ + i = len(children) + while i > start: + # skip over leading comments and whitespace: + child = children[start] + nodeType = child.nodeType + if nodeType == TEXT: + data = child.data + shortened = data.lstrip() + if shortened: + if data != shortened: + # break into two nodes: whitespace and non-whitespace + child.splitText(len(data) - len(shortened)) + return start + 1 + return start + # all whitespace, just skip + elif nodeType == ELEMENT: + tagName = child.tagName + if tagName in RECURSE_INTO_PARA_CONTAINERS: + return start + if tagName not in PARA_LEVEL_ELEMENTS + PARA_LEVEL_PRECEEDERS: + return start + start = start + 1 + return start + + +def fixup_rfc_references(doc, fragment): + for rfcnode in find_all_elements_from_set(fragment, ("pep", "rfc")): + rfcnode.appendChild(doc.createTextNode( + rfcnode.tagName.upper() + " " + rfcnode.getAttribute("num"))) + + +def fixup_signatures(doc, fragment): + for child in fragment.childNodes: + if child.nodeType == ELEMENT: + args = child.getElementsByTagName("args") + for arg in args: + rewrite_args(doc, arg) + args = child.getElementsByTagName("constructor-args") + for arg in args: + rewrite_args(doc, arg) + +def rewrite_args(doc, arglist): + fixup_args(doc, arglist) + arglist.normalize() + if arglist.childNodes.length == 1 and arglist.firstChild.nodeType == TEXT: + node = arglist.firstChild + node.data = ' '.join(node.data.split()) + +def fixup_args(doc, arglist): + for child in arglist.childNodes: + if child.nodeName == "optional": + # found it; fix and return + arglist.insertBefore(doc.createTextNode("["), child) + optkids = child.childNodes + while optkids: + arglist.insertBefore(child.firstChild, child) + arglist.insertBefore(doc.createTextNode("]"), child) + arglist.removeChild(child) + return fixup_args(doc, arglist) + + +def fixup_sectionauthors(doc, fragment): + for sectauth in find_all_elements(fragment, "sectionauthor"): + section = sectauth.parentNode + section.removeChild(sectauth) + set_tagName(sectauth, "author") + sectauth.appendChild(doc.createTextNode( + sectauth.getAttribute("name"))) + sectauth.removeAttribute("name") + after = section.childNodes[2] + title = section.childNodes[1] + if title.nodeName != "title": + after = section.childNodes[0] + section.insertBefore(doc.createTextNode("\n "), after) + section.insertBefore(sectauth, after) + + +def fixup_verbatims(doc): + for verbatim in find_all_elements(doc, "verbatim"): + child = verbatim.childNodes[0] + if child.nodeType == TEXT \ + and child.data.lstrip().startswith(">>>"): + set_tagName(verbatim, "interactive-session") + + +def add_node_ids(fragment, counter=0): + fragment.node_id = counter + for node in fragment.childNodes: + counter = counter + 1 + if node.nodeType == ELEMENT: + counter = add_node_ids(node, counter) + else: + node.node_id = counter + return counter + 1 + + +def fixup_ulink(doc, fragment): + for ulink in find_all_elements(fragment, "ulink"): + children = ulink.childNodes + assert len(children) == 2 + text = children[0] + href = children[1] + href.normalize() + assert len(href.childNodes) == 1 + assert href.childNodes[0].nodeType == TEXT + url = href.childNodes[0].data + ulink.setAttribute("href", url) + ulink.removeChild(href) + content = text.childNodes + while len(content): + ulink.appendChild(content[0]) + ulink.removeChild(text) + + +REFMODINDEX_ELEMENTS = ('refmodindex', 'refbimodindex', + 'refexmodindex', 'refstmodindex') + +def fixup_refmodindexes(fragment): + # Locate <ref*modindex>...</> co-located with <module>...</>, and + # remove the <ref*modindex>, replacing it with index=index on the + # <module> element. + nodes = find_all_elements_from_set(fragment, REFMODINDEX_ELEMENTS) + d = {} + for node in nodes: + parent = node.parentNode + d[parent.node_id] = parent + del nodes + map(fixup_refmodindexes_chunk, d.values()) + + +def fixup_refmodindexes_chunk(container): + # node is probably a <para>; let's see how often it isn't: + if container.tagName != PARA_ELEMENT: + bwrite("--- fixup_refmodindexes_chunk(%s)\n" % container) + module_entries = find_all_elements(container, "module") + if not module_entries: + return + index_entries = find_all_elements_from_set(container, REFMODINDEX_ELEMENTS) + removes = [] + for entry in index_entries: + children = entry.childNodes + if len(children) != 0: + bwrite("--- unexpected number of children for %s node:\n" + % entry.tagName) + ewrite(entry.toxml() + "\n") + continue + found = 0 + module_name = entry.getAttribute("module") + for node in module_entries: + if len(node.childNodes) != 1: + continue + this_name = node.childNodes[0].data + if this_name == module_name: + found = 1 + node.setAttribute("index", "yes") + if found: + removes.append(entry) + for node in removes: + container.removeChild(node) + + +def fixup_bifuncindexes(fragment): + nodes = find_all_elements(fragment, 'bifuncindex') + d = {} + # make sure that each parent is only processed once: + for node in nodes: + parent = node.parentNode + d[parent.node_id] = parent + del nodes + map(fixup_bifuncindexes_chunk, d.values()) + + +def fixup_bifuncindexes_chunk(container): + removes = [] + entries = find_all_child_elements(container, "bifuncindex") + function_entries = find_all_child_elements(container, "function") + for entry in entries: + function_name = entry.getAttribute("name") + found = 0 + for func_entry in function_entries: + t2 = func_entry.childNodes[0].data + if t2[-2:] != "()": + continue + t2 = t2[:-2] + if t2 == function_name: + func_entry.setAttribute("index", "yes") + func_entry.setAttribute("module", "__builtin__") + if not found: + found = 1 + removes.append(entry) + for entry in removes: + container.removeChild(entry) + + +def join_adjacent_elements(container, gi): + queue = [container] + while queue: + parent = queue.pop() + i = 0 + children = parent.childNodes + nchildren = len(children) + while i < (nchildren - 1): + child = children[i] + if child.nodeName == gi: + if children[i+1].nodeName == gi: + ewrite("--- merging two <%s/> elements\n" % gi) + child = children[i] + nextchild = children[i+1] + nextchildren = nextchild.childNodes + while len(nextchildren): + node = nextchildren[0] + nextchild.removeChild(node) + child.appendChild(node) + parent.removeChild(nextchild) + continue + if child.nodeType == ELEMENT: + queue.append(child) + i = i + 1 + + +_token_rx = re.compile(r"[a-zA-Z][a-zA-Z0-9.-]*$") + +def write_esis(doc, ofp, knownempty): + for node in doc.childNodes: + nodeType = node.nodeType + if nodeType == ELEMENT: + gi = node.tagName + if knownempty(gi): + if node.hasChildNodes(): + raise ValueError, \ + "declared-empty node <%s> has children" % gi + ofp.write("e\n") + for k, value in node.attributes.items(): + if _token_rx.match(value): + dtype = "TOKEN" + else: + dtype = "CDATA" + ofp.write("A%s %s %s\n" % (k, dtype, esistools.encode(value))) + ofp.write("(%s\n" % gi) + write_esis(node, ofp, knownempty) + ofp.write(")%s\n" % gi) + elif nodeType == TEXT: + ofp.write("-%s\n" % esistools.encode(node.data)) + elif nodeType == ENTITY_REFERENCE: + ofp.write("&%s\n" % node.nodeName) + else: + raise RuntimeError, "unsupported node type: %s" % nodeType + + +def convert(ifp, ofp): + events = esistools.parse(ifp) + toktype, doc = events.getEvent() + fragment = doc.createDocumentFragment() + events.expandNode(fragment) + + normalize(fragment) + simplify(doc, fragment) + handle_labels(doc, fragment) + handle_appendix(doc, fragment) + fixup_trailing_whitespace(doc, fragment, { + # element -> (before-end-tag, after-end-tag) + "abstract": ("\n", "\n"), + "title": ("", "\n"), + "chapter": ("\n", "\n\n\n"), + "section": ("\n", "\n\n\n"), + "subsection": ("\n", "\n\n"), + "subsubsection": ("\n", "\n\n"), + "paragraph": ("\n", "\n\n"), + "subparagraph": ("\n", "\n\n"), + "description": ("\n", "\n\n"), + "enumeration": ("\n", "\n\n"), + "item": ("\n", "\n\n"), + }) + cleanup_root_text(doc) + cleanup_trailing_parens(fragment, ["function", "method", "cfunction"]) + cleanup_synopses(doc, fragment) + fixup_descriptors(doc, fragment) + fixup_verbatims(fragment) + normalize(fragment) + fixup_paras(doc, fragment) + fixup_sectionauthors(doc, fragment) + fixup_table_structures(doc, fragment) + fixup_rfc_references(doc, fragment) + fixup_signatures(doc, fragment) + fixup_ulink(doc, fragment) + add_node_ids(fragment) + fixup_refmodindexes(fragment) + fixup_bifuncindexes(fragment) + # Take care of ugly hacks in the LaTeX markup to avoid LaTeX and + # LaTeX2HTML screwing with GNU-style long options (the '--' problem). + join_adjacent_elements(fragment, "option") + # Attempt to avoid trailing blank lines: + fragment.normalize() + if fragment.lastChild.data[-1:] == "\n": + fragment.lastChild.data = fragment.lastChild.data.rstrip() + "\n" + # + d = {} + for gi in events.parser.get_empties(): + d[gi] = gi + for key in ("author", "pep", "rfc"): + if d.has_key(key): + del d[key] + knownempty = d.has_key + # + try: + write_esis(fragment, ofp, knownempty) + except IOError, (err, msg): + # Ignore EPIPE; it just means that whoever we're writing to stopped + # reading. The rest of the output would be ignored. All other errors + # should still be reported, + if err != errno.EPIPE: + raise + + +def main(): + if len(sys.argv) == 1: + ifp = sys.stdin + ofp = sys.stdout + elif len(sys.argv) == 2: + ifp = open(sys.argv[1]) + ofp = sys.stdout + elif len(sys.argv) == 3: + ifp = open(sys.argv[1]) + import StringIO + ofp = StringIO.StringIO() + else: + usage() + sys.exit(2) + convert(ifp, ofp) + if len(sys.argv) == 3: + fp = open(sys.argv[2], "w") + fp.write(ofp.getvalue()) + fp.close() + ofp.close() + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/esis2sgml.py b/sys/src/cmd/python/Doc/tools/sgmlconv/esis2sgml.py new file mode 100755 index 000000000..b6f9a4475 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/esis2sgml.py @@ -0,0 +1,264 @@ +#! /usr/bin/env python + +"""Convert ESIS events to SGML or XML markup. + +This is limited, but seems sufficient for the ESIS generated by the +latex2esis.py script when run over the Python documentation. +""" + +# This should have an explicit option to indicate whether the *INPUT* was +# generated from an SGML or an XML application. + +import errno +import os +import re +import string + +from xml.sax.saxutils import escape + +import esistools + + +AUTOCLOSE = () + +EMPTIES_FILENAME = "../sgml/empties.dat" +LIST_EMPTIES = 0 + + +_elem_map = {} +_attr_map = {} +_token_map = {} + +_normalize_case = str + +def map_gi(sgmlgi, map): + uncased = _normalize_case(sgmlgi) + try: + return map[uncased] + except IndexError: + map[uncased] = sgmlgi + return sgmlgi + +def null_map_gi(sgmlgi, map): + return sgmlgi + + +def format_attrs(attrs, xml=0): + attrs = attrs.items() + attrs.sort() + parts = [] + append = parts.append + for name, value in attrs: + if xml: + append('%s="%s"' % (name, escape(value))) + else: + # this is a little bogus, but should do for now + if name == value and isnmtoken(value): + append(value) + elif istoken(value): + if value == "no" + name: + append(value) + else: + append("%s=%s" % (name, value)) + else: + append('%s="%s"' % (name, escape(value))) + if parts: + parts.insert(0, '') + return " ".join(parts) + + +_nmtoken_rx = re.compile("[a-z][-._a-z0-9]*$", re.IGNORECASE) +def isnmtoken(s): + return _nmtoken_rx.match(s) is not None + +_token_rx = re.compile("[a-z0-9][-._a-z0-9]*$", re.IGNORECASE) +def istoken(s): + return _token_rx.match(s) is not None + + +def convert(ifp, ofp, xml=0, autoclose=(), verbatims=()): + if xml: + autoclose = () + attrs = {} + lastopened = None + knownempties = [] + knownempty = 0 + lastempty = 0 + inverbatim = 0 + while 1: + line = ifp.readline() + if not line: + break + + type = line[0] + data = line[1:] + if data and data[-1] == "\n": + data = data[:-1] + if type == "-": + data = esistools.decode(data) + data = escape(data) + if not inverbatim: + data = data.replace("---", "&mdash;") + ofp.write(data) + if "\n" in data: + lastopened = None + knownempty = 0 + lastempty = 0 + elif type == "(": + if data == "COMMENT": + ofp.write("<!--") + continue + data = map_gi(data, _elem_map) + if knownempty and xml: + ofp.write("<%s%s/>" % (data, format_attrs(attrs, xml))) + else: + ofp.write("<%s%s>" % (data, format_attrs(attrs, xml))) + if knownempty and data not in knownempties: + # accumulate knowledge! + knownempties.append(data) + attrs = {} + lastopened = data + lastempty = knownempty + knownempty = 0 + inverbatim = data in verbatims + elif type == ")": + if data == "COMMENT": + ofp.write("-->") + continue + data = map_gi(data, _elem_map) + if xml: + if not lastempty: + ofp.write("</%s>" % data) + elif data not in knownempties: + if data in autoclose: + pass + elif lastopened == data: + ofp.write("</>") + else: + ofp.write("</%s>" % data) + lastopened = None + lastempty = 0 + inverbatim = 0 + elif type == "A": + name, type, value = data.split(" ", 2) + name = map_gi(name, _attr_map) + attrs[name] = esistools.decode(value) + elif type == "e": + knownempty = 1 + elif type == "&": + ofp.write("&%s;" % data) + knownempty = 0 + else: + raise RuntimeError, "unrecognized ESIS event type: '%s'" % type + + if LIST_EMPTIES: + dump_empty_element_names(knownempties) + + +def dump_empty_element_names(knownempties): + d = {} + for gi in knownempties: + d[gi] = gi + knownempties.append("") + if os.path.isfile(EMPTIES_FILENAME): + fp = open(EMPTIES_FILENAME) + while 1: + line = fp.readline() + if not line: + break + gi = line.strip() + if gi: + d[gi] = gi + fp = open(EMPTIES_FILENAME, "w") + gilist = d.keys() + gilist.sort() + fp.write("\n".join(gilist)) + fp.write("\n") + fp.close() + + +def update_gi_map(map, names, fromsgml=1): + for name in names.split(","): + if fromsgml: + uncased = name.lower() + else: + uncased = name + map[uncased] = name + + +def main(): + import getopt + import sys + # + autoclose = AUTOCLOSE + xml = 1 + xmldecl = 0 + elem_names = '' + attr_names = '' + value_names = '' + verbatims = ('verbatim', 'interactive-session') + opts, args = getopt.getopt(sys.argv[1:], "adesx", + ["autoclose=", "declare", "sgml", "xml", + "elements-map=", "attributes-map", + "values-map="]) + for opt, arg in opts: + if opt in ("-d", "--declare"): + xmldecl = 1 + elif opt == "-e": + global LIST_EMPTIES + LIST_EMPTIES = 1 + elif opt in ("-s", "--sgml"): + xml = 0 + elif opt in ("-x", "--xml"): + xml = 1 + elif opt in ("-a", "--autoclose"): + autoclose = arg.split(",") + elif opt == "--elements-map": + elem_names = ("%s,%s" % (elem_names, arg))[1:] + elif opt == "--attributes-map": + attr_names = ("%s,%s" % (attr_names, arg))[1:] + elif opt == "--values-map": + value_names = ("%s,%s" % (value_names, arg))[1:] + # + # open input streams: + # + if len(args) == 0: + ifp = sys.stdin + ofp = sys.stdout + elif len(args) == 1: + ifp = open(args[0]) + ofp = sys.stdout + elif len(args) == 2: + ifp = open(args[0]) + ofp = open(args[1], "w") + else: + usage() + sys.exit(2) + # + # setup the name maps: + # + if elem_names or attr_names or value_names: + # assume the origin was SGML; ignore case of the names from the ESIS + # stream but set up conversion tables to get the case right on output + global _normalize_case + _normalize_case = string.lower + update_gi_map(_elem_map, elem_names.split(",")) + update_gi_map(_attr_map, attr_names.split(",")) + update_gi_map(_values_map, value_names.split(",")) + else: + global map_gi + map_gi = null_map_gi + # + # run the conversion: + # + try: + if xml and xmldecl: + opf.write('<?xml version="1.0" encoding="iso8859-1"?>\n') + convert(ifp, ofp, xml=xml, autoclose=autoclose, verbatims=verbatims) + except IOError, (err, msg): + if err != errno.EPIPE: + raise + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/esistools.py b/sys/src/cmd/python/Doc/tools/sgmlconv/esistools.py new file mode 100644 index 000000000..833fea171 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/esistools.py @@ -0,0 +1,312 @@ +"""Miscellaneous utility functions useful for dealing with ESIS streams.""" + +import re + +import xml.dom.pulldom + +import xml.sax +import xml.sax.handler +import xml.sax.xmlreader + + +_data_match = re.compile(r"[^\\][^\\]*").match + +def decode(s): + r = '' + while s: + m = _data_match(s) + if m: + r = r + m.group() + s = s[m.end():] + elif s[1] == "\\": + r = r + "\\" + s = s[2:] + elif s[1] == "n": + r = r + "\n" + s = s[2:] + elif s[1] == "%": + s = s[2:] + n, s = s.split(";", 1) + r = r + unichr(int(n)) + else: + raise ValueError, "can't handle %r" % s + return r + + +_charmap = {} +for c in range(128): + _charmap[chr(c)] = chr(c) + _charmap[unichr(c + 128)] = chr(c + 128) +_charmap["\n"] = r"\n" +_charmap["\\"] = r"\\" +del c + +_null_join = ''.join +def encode(s): + try: + return _null_join(map(_charmap.get, s)) + except TypeError: + raise Exception("could not encode %r: %r" % (s, map(_charmap.get, s))) + + +class ESISReader(xml.sax.xmlreader.XMLReader): + """SAX Reader which reads from an ESIS stream. + + No verification of the document structure is performed by the + reader; a general verifier could be used as the target + ContentHandler instance. + + """ + _decl_handler = None + _lexical_handler = None + + _public_id = None + _system_id = None + + _buffer = "" + _is_empty = 0 + _lineno = 0 + _started = 0 + + def __init__(self, contentHandler=None, errorHandler=None): + xml.sax.xmlreader.XMLReader.__init__(self) + self._attrs = {} + self._attributes = Attributes(self._attrs) + self._locator = Locator() + self._empties = {} + if contentHandler: + self.setContentHandler(contentHandler) + if errorHandler: + self.setErrorHandler(errorHandler) + + def get_empties(self): + return self._empties.keys() + + # + # XMLReader interface + # + + def parse(self, source): + raise RuntimeError + self._locator._public_id = source.getPublicId() + self._locator._system_id = source.getSystemId() + fp = source.getByteStream() + handler = self.getContentHandler() + if handler: + handler.startDocument() + lineno = 0 + while 1: + token, data = self._get_token(fp) + if token is None: + break + lineno = lineno + 1 + self._locator._lineno = lineno + self._handle_token(token, data) + handler = self.getContentHandler() + if handler: + handler.startDocument() + + def feed(self, data): + if not self._started: + handler = self.getContentHandler() + if handler: + handler.startDocument() + self._started = 1 + data = self._buffer + data + self._buffer = None + lines = data.split("\n") + if lines: + for line in lines[:-1]: + self._lineno = self._lineno + 1 + self._locator._lineno = self._lineno + if not line: + e = xml.sax.SAXParseException( + "ESIS input line contains no token type mark", + None, self._locator) + self.getErrorHandler().error(e) + else: + self._handle_token(line[0], line[1:]) + self._buffer = lines[-1] + else: + self._buffer = "" + + def close(self): + handler = self.getContentHandler() + if handler: + handler.endDocument() + self._buffer = "" + + def _get_token(self, fp): + try: + line = fp.readline() + except IOError, e: + e = SAXException("I/O error reading input stream", e) + self.getErrorHandler().fatalError(e) + return + if not line: + return None, None + if line[-1] == "\n": + line = line[:-1] + if not line: + e = xml.sax.SAXParseException( + "ESIS input line contains no token type mark", + None, self._locator) + self.getErrorHandler().error(e) + return + return line[0], line[1:] + + def _handle_token(self, token, data): + handler = self.getContentHandler() + if token == '-': + if data and handler: + handler.characters(decode(data)) + elif token == ')': + if handler: + handler.endElement(decode(data)) + elif token == '(': + if self._is_empty: + self._empties[data] = 1 + self._is_empty = 0 + if handler: + handler.startElement(data, self._attributes) + self._attrs.clear() + elif token == 'A': + name, value = data.split(' ', 1) + if value != "IMPLIED": + type, value = value.split(' ', 1) + self._attrs[name] = (decode(value), type) + elif token == '&': + # entity reference in SAX? + pass + elif token == '?': + if handler: + if ' ' in data: + target, data = data.split(None, 1) + else: + target, data = data, "" + handler.processingInstruction(target, decode(data)) + elif token == 'N': + handler = self.getDTDHandler() + if handler: + handler.notationDecl(data, self._public_id, self._system_id) + self._public_id = None + self._system_id = None + elif token == 'p': + self._public_id = decode(data) + elif token == 's': + self._system_id = decode(data) + elif token == 'e': + self._is_empty = 1 + elif token == 'C': + pass + else: + e = SAXParseException("unknown ESIS token in event stream", + None, self._locator) + self.getErrorHandler().error(e) + + def setContentHandler(self, handler): + old = self.getContentHandler() + if old: + old.setDocumentLocator(None) + if handler: + handler.setDocumentLocator(self._locator) + xml.sax.xmlreader.XMLReader.setContentHandler(self, handler) + + def getProperty(self, property): + if property == xml.sax.handler.property_lexical_handler: + return self._lexical_handler + + elif property == xml.sax.handler.property_declaration_handler: + return self._decl_handler + + else: + raise xml.sax.SAXNotRecognizedException("unknown property %r" + % (property, )) + + def setProperty(self, property, value): + if property == xml.sax.handler.property_lexical_handler: + if self._lexical_handler: + self._lexical_handler.setDocumentLocator(None) + if value: + value.setDocumentLocator(self._locator) + self._lexical_handler = value + + elif property == xml.sax.handler.property_declaration_handler: + if self._decl_handler: + self._decl_handler.setDocumentLocator(None) + if value: + value.setDocumentLocator(self._locator) + self._decl_handler = value + + else: + raise xml.sax.SAXNotRecognizedException() + + def getFeature(self, feature): + if feature == xml.sax.handler.feature_namespaces: + return 1 + else: + return xml.sax.xmlreader.XMLReader.getFeature(self, feature) + + def setFeature(self, feature, enabled): + if feature == xml.sax.handler.feature_namespaces: + pass + else: + xml.sax.xmlreader.XMLReader.setFeature(self, feature, enabled) + + +class Attributes(xml.sax.xmlreader.AttributesImpl): + # self._attrs has the form {name: (value, type)} + + def getType(self, name): + return self._attrs[name][1] + + def getValue(self, name): + return self._attrs[name][0] + + def getValueByQName(self, name): + return self._attrs[name][0] + + def __getitem__(self, name): + return self._attrs[name][0] + + def get(self, name, default=None): + if self._attrs.has_key(name): + return self._attrs[name][0] + return default + + def items(self): + L = [] + for name, (value, type) in self._attrs.items(): + L.append((name, value)) + return L + + def values(self): + L = [] + for value, type in self._attrs.values(): + L.append(value) + return L + + +class Locator(xml.sax.xmlreader.Locator): + _lineno = -1 + _public_id = None + _system_id = None + + def getLineNumber(self): + return self._lineno + + def getPublicId(self): + return self._public_id + + def getSystemId(self): + return self._system_id + + +def parse(stream_or_string, parser=None): + if type(stream_or_string) in [type(""), type(u"")]: + stream = open(stream_or_string) + else: + stream = stream_or_string + if not parser: + parser = ESISReader() + return xml.dom.pulldom.DOMEventStream(stream, parser, (2 ** 14) - 20) diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/latex2esis.py b/sys/src/cmd/python/Doc/tools/sgmlconv/latex2esis.py new file mode 100755 index 000000000..643ef2ca3 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/latex2esis.py @@ -0,0 +1,565 @@ +#! /usr/bin/env python + +"""Generate ESIS events based on a LaTeX source document and +configuration data. + +The conversion is not strong enough to work with arbitrary LaTeX +documents; it has only been designed to work with the highly stylized +markup used in the standard Python documentation. A lot of +information about specific markup is encoded in the control table +passed to the convert() function; changing this table can allow this +tool to support additional LaTeX markups. + +The format of the table is largely undocumented; see the commented +headers where the table is specified in main(). There is no provision +to load an alternate table from an external file. +""" + +import errno +import getopt +import os +import re +import sys +import xml.sax +import xml.sax.saxutils + +from esistools import encode + + +DEBUG = 0 + + +class LaTeXFormatError(Exception): + pass + + +class LaTeXStackError(LaTeXFormatError): + def __init__(self, found, stack): + msg = "environment close for %s doesn't match;\n stack = %s" \ + % (found, stack) + self.found = found + self.stack = stack[:] + LaTeXFormatError.__init__(self, msg) + + +_begin_env_rx = re.compile(r"[\\]begin{([^}]*)}") +_end_env_rx = re.compile(r"[\\]end{([^}]*)}") +_begin_macro_rx = re.compile(r"[\\]([a-zA-Z]+[*]?) ?({|\s*\n?)") +_comment_rx = re.compile("%+ ?(.*)\n[ \t]*") +_text_rx = re.compile(r"[^]~%\\{}]+") +_optional_rx = re.compile(r"\s*[[]([^]]*)[]]", re.MULTILINE) +# _parameter_rx is this complicated to allow {...} inside a parameter; +# this is useful to match tabular layout specifications like {c|p{24pt}} +_parameter_rx = re.compile("[ \n]*{(([^{}}]|{[^}]*})*)}") +_token_rx = re.compile(r"[a-zA-Z][a-zA-Z0-9.-]*$") +_start_group_rx = re.compile("[ \n]*{") +_start_optional_rx = re.compile("[ \n]*[[]") + + +ESCAPED_CHARS = "$%#^ {}&~" + + +def dbgmsg(msg): + if DEBUG: + sys.stderr.write(msg + "\n") + +def pushing(name, point, depth): + dbgmsg("pushing <%s> at %s" % (name, point)) + +def popping(name, point, depth): + dbgmsg("popping </%s> at %s" % (name, point)) + + +class _Stack(list): + def append(self, entry): + if not isinstance(entry, str): + raise LaTeXFormatError("cannot push non-string on stack: %r" + % (entry, )) + #dbgmsg("%s<%s>" % (" "*len(self.data), entry)) + list.append(self, entry) + + def pop(self, index=-1): + entry = self[index] + del self[index] + #dbgmsg("%s</%s>" % (" " * len(self), entry)) + + def __delitem__(self, index): + entry = self[index] + list.__delitem__(self, index) + #dbgmsg("%s</%s>" % (" " * len(self), entry)) + + +def new_stack(): + if DEBUG: + return _Stack() + else: + return [] + + +class Conversion: + def __init__(self, ifp, ofp, table): + self.write = ofp.write + self.ofp = ofp + self.table = table + L = [s.rstrip() for s in ifp.readlines()] + L.append("") + self.line = "\n".join(L) + self.preamble = 1 + + def convert(self): + self.subconvert() + + def subconvert(self, endchar=None, depth=0): + # + # Parses content, including sub-structures, until the character + # 'endchar' is found (with no open structures), or until the end + # of the input data is endchar is None. + # + stack = new_stack() + line = self.line + while line: + if line[0] == endchar and not stack: + self.line = line + return line + m = _comment_rx.match(line) + if m: + text = m.group(1) + if text: + self.write("(COMMENT\n- %s \n)COMMENT\n-\\n\n" + % encode(text)) + line = line[m.end():] + continue + m = _begin_env_rx.match(line) + if m: + name = m.group(1) + entry = self.get_env_entry(name) + # re-write to use the macro handler + line = r"\%s %s" % (name, line[m.end():]) + continue + m = _end_env_rx.match(line) + if m: + # end of environment + envname = m.group(1) + entry = self.get_entry(envname) + while stack and envname != stack[-1] \ + and stack[-1] in entry.endcloses: + self.write(")%s\n" % stack.pop()) + if stack and envname == stack[-1]: + self.write(")%s\n" % entry.outputname) + del stack[-1] + else: + raise LaTeXStackError(envname, stack) + line = line[m.end():] + continue + m = _begin_macro_rx.match(line) + if m: + # start of macro + macroname = m.group(1) + if macroname == "c": + # Ugh! This is a combining character... + endpos = m.end() + self.combining_char("c", line[endpos]) + line = line[endpos + 1:] + continue + entry = self.get_entry(macroname) + if entry.verbatim: + # magic case! + pos = line.find("\\end{%s}" % macroname) + text = line[m.end(1):pos] + stack.append(entry.name) + self.write("(%s\n" % entry.outputname) + self.write("-%s\n" % encode(text)) + self.write(")%s\n" % entry.outputname) + stack.pop() + line = line[pos + len("\\end{%s}" % macroname):] + continue + while stack and stack[-1] in entry.closes: + top = stack.pop() + topentry = self.get_entry(top) + if topentry.outputname: + self.write(")%s\n-\\n\n" % topentry.outputname) + # + if entry.outputname and entry.empty: + self.write("e\n") + # + params, optional, empty = self.start_macro(macroname) + # rip off the macroname + if params: + line = line[m.end(1):] + elif empty: + line = line[m.end(1):] + else: + line = line[m.end():] + opened = 0 + implied_content = 0 + + # handle attribute mappings here: + for pentry in params: + if pentry.type == "attribute": + if pentry.optional: + m = _optional_rx.match(line) + if m and entry.outputname: + line = line[m.end():] + self.dump_attr(pentry, m.group(1)) + elif pentry.text and entry.outputname: + # value supplied by conversion spec: + self.dump_attr(pentry, pentry.text) + else: + m = _parameter_rx.match(line) + if not m: + raise LaTeXFormatError( + "could not extract parameter %s for %s: %r" + % (pentry.name, macroname, line[:100])) + if entry.outputname: + self.dump_attr(pentry, m.group(1)) + line = line[m.end():] + elif pentry.type == "child": + if pentry.optional: + m = _optional_rx.match(line) + if m: + line = line[m.end():] + if entry.outputname and not opened: + opened = 1 + self.write("(%s\n" % entry.outputname) + stack.append(macroname) + stack.append(pentry.name) + self.write("(%s\n" % pentry.name) + self.write("-%s\n" % encode(m.group(1))) + self.write(")%s\n" % pentry.name) + stack.pop() + else: + if entry.outputname and not opened: + opened = 1 + self.write("(%s\n" % entry.outputname) + stack.append(entry.name) + self.write("(%s\n" % pentry.name) + stack.append(pentry.name) + self.line = skip_white(line)[1:] + line = self.subconvert( + "}", len(stack) + depth + 1)[1:] + self.write(")%s\n" % stack.pop()) + elif pentry.type == "content": + if pentry.implied: + implied_content = 1 + else: + if entry.outputname and not opened: + opened = 1 + self.write("(%s\n" % entry.outputname) + stack.append(entry.name) + line = skip_white(line) + if line[0] != "{": + raise LaTeXFormatError( + "missing content for " + macroname) + self.line = line[1:] + line = self.subconvert("}", len(stack) + depth + 1) + if line and line[0] == "}": + line = line[1:] + elif pentry.type == "text" and pentry.text: + if entry.outputname and not opened: + opened = 1 + stack.append(entry.name) + self.write("(%s\n" % entry.outputname) + #dbgmsg("--- text: %r" % pentry.text) + self.write("-%s\n" % encode(pentry.text)) + elif pentry.type == "entityref": + self.write("&%s\n" % pentry.name) + if entry.outputname: + if not opened: + self.write("(%s\n" % entry.outputname) + stack.append(entry.name) + if not implied_content: + self.write(")%s\n" % entry.outputname) + stack.pop() + continue + if line[0] == endchar and not stack: + self.line = line[1:] + return self.line + if line[0] == "}": + # end of macro or group + macroname = stack[-1] + if macroname: + conversion = self.table[macroname] + if conversion.outputname: + # otherwise, it was just a bare group + self.write(")%s\n" % conversion.outputname) + del stack[-1] + line = line[1:] + continue + if line[0] == "~": + # don't worry about the "tie" aspect of this command + line = line[1:] + self.write("- \n") + continue + if line[0] == "{": + stack.append("") + line = line[1:] + continue + if line[0] == "\\" and line[1] in ESCAPED_CHARS: + self.write("-%s\n" % encode(line[1])) + line = line[2:] + continue + if line[:2] == r"\\": + self.write("(BREAK\n)BREAK\n") + line = line[2:] + continue + if line[:2] == r"\_": + line = "_" + line[2:] + continue + if line[:2] in (r"\'", r'\"'): + # combining characters... + self.combining_char(line[1], line[2]) + line = line[3:] + continue + m = _text_rx.match(line) + if m: + text = encode(m.group()) + self.write("-%s\n" % text) + line = line[m.end():] + continue + # special case because of \item[] + # XXX can we axe this??? + if line[0] == "]": + self.write("-]\n") + line = line[1:] + continue + # avoid infinite loops + extra = "" + if len(line) > 100: + extra = "..." + raise LaTeXFormatError("could not identify markup: %r%s" + % (line[:100], extra)) + while stack: + entry = self.get_entry(stack[-1]) + if entry.closes: + self.write(")%s\n-%s\n" % (entry.outputname, encode("\n"))) + del stack[-1] + else: + break + if stack: + raise LaTeXFormatError("elements remain on stack: " + + ", ".join(stack)) + # otherwise we just ran out of input here... + + # This is a really limited table of combinations, but it will have + # to do for now. + _combinations = { + ("c", "c"): 0x00E7, + ("'", "e"): 0x00E9, + ('"', "o"): 0x00F6, + } + + def combining_char(self, prefix, char): + ordinal = self._combinations[(prefix, char)] + self.write("-\\%%%d;\n" % ordinal) + + def start_macro(self, name): + conversion = self.get_entry(name) + parameters = conversion.parameters + optional = parameters and parameters[0].optional + return parameters, optional, conversion.empty + + def get_entry(self, name): + entry = self.table.get(name) + if entry is None: + dbgmsg("get_entry(%r) failing; building default entry!" % (name, )) + # not defined; build a default entry: + entry = TableEntry(name) + entry.has_content = 1 + entry.parameters.append(Parameter("content")) + self.table[name] = entry + return entry + + def get_env_entry(self, name): + entry = self.table.get(name) + if entry is None: + # not defined; build a default entry: + entry = TableEntry(name, 1) + entry.has_content = 1 + entry.parameters.append(Parameter("content")) + entry.parameters[-1].implied = 1 + self.table[name] = entry + elif not entry.environment: + raise LaTeXFormatError( + name + " is defined as a macro; expected environment") + return entry + + def dump_attr(self, pentry, value): + if not (pentry.name and value): + return + if _token_rx.match(value): + dtype = "TOKEN" + else: + dtype = "CDATA" + self.write("A%s %s %s\n" % (pentry.name, dtype, encode(value))) + + +def convert(ifp, ofp, table): + c = Conversion(ifp, ofp, table) + try: + c.convert() + except IOError, (err, msg): + if err != errno.EPIPE: + raise + + +def skip_white(line): + while line and line[0] in " %\n\t\r": + line = line[1:].lstrip() + return line + + + +class TableEntry: + def __init__(self, name, environment=0): + self.name = name + self.outputname = name + self.environment = environment + self.empty = not environment + self.has_content = 0 + self.verbatim = 0 + self.auto_close = 0 + self.parameters = [] + self.closes = [] + self.endcloses = [] + +class Parameter: + def __init__(self, type, name=None, optional=0): + self.type = type + self.name = name + self.optional = optional + self.text = '' + self.implied = 0 + + +class TableHandler(xml.sax.handler.ContentHandler): + def __init__(self): + self.__table = {} + self.__buffer = '' + self.__methods = {} + + def get_table(self): + for entry in self.__table.values(): + if entry.environment and not entry.has_content: + p = Parameter("content") + p.implied = 1 + entry.parameters.append(p) + entry.has_content = 1 + return self.__table + + def startElement(self, tag, attrs): + try: + start, end = self.__methods[tag] + except KeyError: + start = getattr(self, "start_" + tag, None) + end = getattr(self, "end_" + tag, None) + self.__methods[tag] = (start, end) + if start: + start(attrs) + + def endElement(self, tag): + start, end = self.__methods[tag] + if end: + end() + + def endDocument(self): + self.__methods.clear() + + def characters(self, data): + self.__buffer += data + + def start_environment(self, attrs): + name = attrs["name"] + self.__current = TableEntry(name, environment=1) + self.__current.verbatim = attrs.get("verbatim") == "yes" + if attrs.has_key("outputname"): + self.__current.outputname = attrs.get("outputname") + self.__current.endcloses = attrs.get("endcloses", "").split() + def end_environment(self): + self.end_macro() + + def start_macro(self, attrs): + name = attrs["name"] + self.__current = TableEntry(name) + self.__current.closes = attrs.get("closes", "").split() + if attrs.has_key("outputname"): + self.__current.outputname = attrs.get("outputname") + def end_macro(self): + name = self.__current.name + if self.__table.has_key(name): + raise ValueError("name %r already in use" % (name,)) + self.__table[name] = self.__current + self.__current = None + + def start_attribute(self, attrs): + name = attrs.get("name") + optional = attrs.get("optional") == "yes" + if name: + p = Parameter("attribute", name, optional=optional) + else: + p = Parameter("attribute", optional=optional) + self.__current.parameters.append(p) + self.__buffer = '' + def end_attribute(self): + self.__current.parameters[-1].text = self.__buffer + + def start_entityref(self, attrs): + name = attrs["name"] + p = Parameter("entityref", name) + self.__current.parameters.append(p) + + def start_child(self, attrs): + name = attrs["name"] + p = Parameter("child", name, attrs.get("optional") == "yes") + self.__current.parameters.append(p) + self.__current.empty = 0 + + def start_content(self, attrs): + p = Parameter("content") + p.implied = attrs.get("implied") == "yes" + if self.__current.environment: + p.implied = 1 + self.__current.parameters.append(p) + self.__current.has_content = 1 + self.__current.empty = 0 + + def start_text(self, attrs): + self.__current.empty = 0 + self.__buffer = '' + def end_text(self): + p = Parameter("text") + p.text = self.__buffer + self.__current.parameters.append(p) + + +def load_table(fp): + ch = TableHandler() + xml.sax.parse(fp, ch) + return ch.get_table() + + +def main(): + global DEBUG + # + opts, args = getopt.getopt(sys.argv[1:], "D", ["debug"]) + for opt, arg in opts: + if opt in ("-D", "--debug"): + DEBUG += 1 + if len(args) == 0: + ifp = sys.stdin + ofp = sys.stdout + elif len(args) == 1: + ifp = open(args[0]) + ofp = sys.stdout + elif len(args) == 2: + ifp = open(args[0]) + ofp = open(args[1], "w") + else: + usage() + sys.exit(2) + + table = load_table(open(os.path.join(sys.path[0], 'conversion.xml'))) + convert(ifp, ofp, table) + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/sgmlconv/make.rules b/sys/src/cmd/python/Doc/tools/sgmlconv/make.rules new file mode 100644 index 000000000..93579c535 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/sgmlconv/make.rules @@ -0,0 +1,48 @@ +# -*- makefile -*- +# +# Extra magic needed by the LaTeX->XML conversion process. This requires +# $(TOOLSDIR) to be properly defined. + +DOCFIXER= $(TOOLSDIR)/sgmlconv/docfixer.py +ESIS2ML= $(TOOLSDIR)/sgmlconv/esis2sgml.py +LATEX2ESIS= $(TOOLSDIR)/sgmlconv/latex2esis.py +CONVERSION= $(TOOLSDIR)/sgmlconv/conversion.xml + +ESISTARGETS= $(patsubst %.tex,%.esis,$(wildcard *.tex)) +ESIS1TARGETS= $(patsubst %.tex,%.esis1,$(wildcard *.tex)) +XMLTARGETS= $(patsubst %.tex,%.xml,$(wildcard *.tex)) + +L2EFLAGS= + +all: xml + +esis: $(ESISTARGETS) +esis1: $(ESIS1TARGETS) +xml: $(XMLTARGETS) + +ESISTOOLS= $(TOOLSDIR)/sgmlconv/esistools.py + +$(ESISTARGETS): $(LATEX2ESIS) $(DOCFIXER) $(ESISTOOLS) $(CONVERSION) +$(ESIS1TARGETS): $(LATEX2ESIS) $(CONVERSION) +# This variant is easier to work with while debugging the conversion spec: +#$(ESISTARGETS): $(LATEX2ESIS) $(DOCFIXER) $(ESISTOOLS) +$(XMLTARGETS): $(ESIS2ML) + + +.SUFFIXES: .esis .esis1 .tex .xml + +.tex.esis1: + $(LATEX2ESIS) $(L2EFLAGS) $< $@ + +.esis1.esis: + $(DOCFIXER) $< $@ + +.esis.xml: + $(ESIS2ML) --xml $< $@ + + +clean: + rm -f *.esis *.esis1 + +clobber: clean + rm -f *.xml diff --git a/sys/src/cmd/python/Doc/tools/support.py b/sys/src/cmd/python/Doc/tools/support.py new file mode 100644 index 000000000..5b8471aac --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/support.py @@ -0,0 +1,202 @@ +"""Miscellaneous support code shared by some of the tool scripts. + +This includes option parsing code, HTML formatting code, and a couple of +useful helpers. + +""" +__version__ = '$Revision: 37764 $' + + +import getopt +import os.path +import sys + + +class Options: + __short_args = "a:c:ho:" + __long_args = [ + # script controls + "columns=", "help", "output=", + + # content components + "address=", "iconserver=", "favicon=", + "title=", "uplink=", "uptitle=", + "image-type=", + ] + + outputfile = "-" + columns = 1 + letters = 0 + uplink = "index.html" + uptitle = "Python Documentation Index" + favicon = None + + # The "Aesop Meta Tag" is poorly described, and may only be used + # by the Aesop search engine (www.aesop.com), but doesn't hurt. + # + # There are a number of values this may take to roughly categorize + # a page. A page should be marked according to its primary + # category. Known values are: + # 'personal' -- personal-info + # 'information' -- information + # 'interactive' -- interactive media + # 'multimedia' -- multimedia presenetation (non-sales) + # 'sales' -- sales material + # 'links' -- links to other information pages + # + # Setting the aesop_type value to one of these strings will cause + # get_header() to add the appropriate <meta> tag to the <head>. + # + aesop_type = None + + def __init__(self): + self.args = [] + self.variables = {"address": "", + "iconserver": "icons", + "imgtype": "png", + "title": "Global Module Index", + } + + def add_args(self, short=None, long=None): + if short: + self.__short_args = self.__short_args + short + if long: + self.__long_args = self.__long_args + long + + def parse(self, args): + try: + opts, args = getopt.getopt(args, self.__short_args, + self.__long_args) + except getopt.error: + sys.stdout = sys.stderr + self.usage() + sys.exit(2) + self.args = self.args + args + for opt, val in opts: + if opt in ("-a", "--address"): + val = val.strip() + if val: + val = "<address>\n%s\n</address>\n" % val + self.variables["address"] = val + elif opt in ("-h", "--help"): + self.usage() + sys.exit() + elif opt in ("-o", "--output"): + self.outputfile = val + elif opt in ("-c", "--columns"): + self.columns = int(val) + elif opt == "--title": + self.variables["title"] = val.strip() + elif opt == "--uplink": + self.uplink = val.strip() + elif opt == "--uptitle": + self.uptitle = val.strip() + elif opt == "--iconserver": + self.variables["iconserver"] = val.strip() or "." + elif opt == "--favicon": + self.favicon = val.strip() + elif opt == "--image-type": + self.variables["imgtype"] = val.strip() + else: + self.handle_option(opt, val) + if self.uplink and self.uptitle: + self.variables["uplinkalt"] = "up" + self.variables["uplinkicon"] = "up" + else: + self.variables["uplinkalt"] = "" + self.variables["uplinkicon"] = "blank" + self.variables["uplink"] = self.uplink + self.variables["uptitle"] = self.uptitle + + def handle_option(self, opt, val): + raise getopt.error("option %s not recognized" % opt) + + def get_header(self): + s = HEAD % self.variables + if self.uplink: + if self.uptitle: + link = ('<link rel="up" href="%s" title="%s">\n ' + '<link rel="start" href="%s" title="%s">' + % (self.uplink, self.uptitle, + self.uplink, self.uptitle)) + else: + link = ('<link rel="up" href="%s">\n ' + '<link rel="start" href="%s">' + % (self.uplink, self.uplink)) + repl = " %s\n</head>" % link + s = s.replace("</head>", repl, 1) + if self.aesop_type: + meta = '<meta name="aesop" content="%s">\n ' % self.aesop_type + # Insert this in the middle of the head that's been + # generated so far, keeping <meta> and <link> elements in + # neat groups: + s = s.replace("<link ", meta + "<link ", 1) + if self.favicon: + ext = os.path.splitext(self.favicon)[1] + if ext in (".gif", ".png"): + type = ' type="image/%s"' % ext[1:] + else: + type = '' + link = ('<link rel="SHORTCUT ICON" href="%s"%s>\n ' + % (self.favicon, type)) + s = s.replace("<link ", link + "<link ", 1) + return s + + def get_footer(self): + return TAIL % self.variables + + def get_output_file(self, filename=None): + if filename is None: + filename = self.outputfile + if filename == "-": + return sys.stdout + else: + return open(filename, "w") + + +NAVIGATION = '''\ +<div class="navigation"> +<table width="100%%" cellpadding="0" cellspacing="2"> +<tr> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td><a href="%(uplink)s" + title="%(uptitle)s"><img width="32" height="32" align="bottom" border="0" + alt="%(uplinkalt)s" + src="%(iconserver)s/%(uplinkicon)s.%(imgtype)s"></a></td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td align="center" width="100%%">%(title)s</td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +</tr></table> +<b class="navlabel">Up:</b> <span class="sectref"><a href="%(uplink)s" + title="%(uptitle)s">%(uptitle)s</A></span> +<br></div> +''' + +HEAD = '''\ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> + <title>%(title)s</title> + <meta name="description" content="%(title)s"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="STYLESHEET" href="lib/lib.css"> +</head> +<body> +''' + NAVIGATION + '''\ +<hr> + +<h2>%(title)s</h2> + +''' + +TAIL = "<hr>\n" + NAVIGATION + '''\ +%(address)s</body> +</html> +''' diff --git a/sys/src/cmd/python/Doc/tools/toc2bkm.py b/sys/src/cmd/python/Doc/tools/toc2bkm.py new file mode 100755 index 000000000..ab669ba95 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/toc2bkm.py @@ -0,0 +1,160 @@ +#! /usr/bin/env python + +"""Convert a LaTeX .toc file to some PDFTeX magic to create that neat outline. + +The output file has an extension of '.bkm' instead of '.out', since hyperref +already uses that extension. +""" + +import getopt +import os +import re +import string +import sys + + +# Ench item in an entry is a tuple of: +# +# Section #, Title String, Page #, List of Sub-entries +# +# The return value of parse_toc() is such a tuple. + +cline_re = r"""^ +\\contentsline\ \{([a-z]*)} # type of section in $1 +\{(?:\\numberline\ \{([0-9.A-Z]+)})? # section number +(.*)} # title string +\{(\d+)}$""" # page number + +cline_rx = re.compile(cline_re, re.VERBOSE) + +OUTER_TO_INNER = -1 + +_transition_map = { + ('chapter', 'section'): OUTER_TO_INNER, + ('section', 'subsection'): OUTER_TO_INNER, + ('subsection', 'subsubsection'): OUTER_TO_INNER, + ('subsubsection', 'subsection'): 1, + ('subsection', 'section'): 1, + ('section', 'chapter'): 1, + ('subsection', 'chapter'): 2, + ('subsubsection', 'section'): 2, + ('subsubsection', 'chapter'): 3, + } + +INCLUDED_LEVELS = ("chapter", "section", "subsection", "subsubsection") + + +class BadSectionNesting(Exception): + """Raised for unsupported section level transitions.""" + + def __init__(self, level, newsection, path, lineno): + self.level = level + self.newsection = newsection + self.path = path + self.lineno = lineno + + def __str__(self): + return ("illegal transition from %s to %s at %s (line %s)" + % (self.level, self.newsection, self.path, self.lineno)) + + +def parse_toc(fp, bigpart=None): + toc = top = [] + stack = [toc] + level = bigpart or 'chapter' + lineno = 0 + while 1: + line = fp.readline() + if not line: + break + lineno = lineno + 1 + m = cline_rx.match(line) + if m: + stype, snum, title, pageno = m.group(1, 2, 3, 4) + title = clean_title(title) + entry = (stype, snum, title, int(pageno), []) + if stype == level: + toc.append(entry) + else: + if stype not in INCLUDED_LEVELS: + # we don't want paragraphs & subparagraphs + continue + try: + direction = _transition_map[(level, stype)] + except KeyError: + raise BadSectionNesting(level, stype, fp.name, lineno) + if direction == OUTER_TO_INNER: + toc = toc[-1][-1] + stack.insert(0, toc) + toc.append(entry) + else: + for i in range(direction): + del stack[0] + toc = stack[0] + toc.append(entry) + level = stype + else: + sys.stderr.write("l.%s: " + line) + return top + + +hackscore_rx = re.compile(r"\\hackscore\s*{[^}]*}") +raisebox_rx = re.compile(r"\\raisebox\s*{[^}]*}") +title_rx = re.compile(r"\\([a-zA-Z])+\s+") +title_trans = string.maketrans("", "") + +def clean_title(title): + title = raisebox_rx.sub("", title) + title = hackscore_rx.sub(r"\\_", title) + pos = 0 + while 1: + m = title_rx.search(title, pos) + if m: + start = m.start() + if title[start:start+15] != "\\textunderscore": + title = title[:start] + title[m.end():] + pos = start + 1 + else: + break + title = title.translate(title_trans, "{}") + return title + + +def write_toc(toc, fp): + for entry in toc: + write_toc_entry(entry, fp, 0) + +def write_toc_entry(entry, fp, layer): + stype, snum, title, pageno, toc = entry + s = "\\pdfoutline goto name{page%03d}" % pageno + if toc: + s = "%s count -%d" % (s, len(toc)) + if snum: + title = "%s %s" % (snum, title) + s = "%s {%s}\n" % (s, title) + fp.write(s) + for entry in toc: + write_toc_entry(entry, fp, layer + 1) + + +def process(ifn, ofn, bigpart=None): + toc = parse_toc(open(ifn), bigpart) + write_toc(toc, open(ofn, "w")) + + +def main(): + bigpart = None + opts, args = getopt.getopt(sys.argv[1:], "c:") + if opts: + bigpart = opts[0][1] + if not args: + usage() + sys.exit(2) + for filename in args: + base, ext = os.path.splitext(filename) + ext = ext or ".toc" + process(base + ext, base + ".bkm", bigpart) + + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Doc/tools/undoc_symbols.py b/sys/src/cmd/python/Doc/tools/undoc_symbols.py new file mode 100644 index 000000000..3d776fa45 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/undoc_symbols.py @@ -0,0 +1,94 @@ +#! /usr/bin/env python + +"""\ +This script prints out a list of undocumented symbols found in +Python include files, prefixed by their tag kind. + +Pass Python's include files to ctags, parse the output into a +dictionary mapping symbol names to tag kinds. + +Then, the .tex files from Python docs are read into a giant string. + +Finally all symbols not found in the docs are written to standard +output, prefixed with their tag kind. +""" + +# Which kind of tags do we need? +TAG_KINDS = "dpst" + +# Doc sections to use +DOCSECTIONS = ["api"]# ["api", "ext"] + +# Only print symbols starting with this prefix, +# to get all symbols, use an empty string +PREFIXES = ("Py", "PY") + +INCLUDEPATTERN = "*.h" + +# end of customization section + + +# Tested with EXUBERANT CTAGS +# see http://ctags.sourceforge.net +# +# ctags fields are separated by tabs. +# The first field is the name, the last field the type: +# d macro definitions (and #undef names) +# e enumerators +# f function definitions +# g enumeration names +# m class, struct, or union members +# n namespaces +# p function prototypes and declarations +# s structure names +# t typedefs +# u union names +# v variable definitions +# x extern and forward variable declarations + +import os, glob, re, sys + +def findnames(file, prefixes=()): + names = {} + for line in file.xreadlines(): + if line[0] == '!': + continue + fields = line.split() + name, tag = fields[0], fields[-1] + if tag == 'd' and name.endswith('_H'): + continue + if prefixes: + sw = name.startswith + for prefix in prefixes: + if sw(prefix): + names[name] = tag + else: + names[name] = tag + return names + +def print_undoc_symbols(prefix, docdir, incdir): + docs = [] + + for sect in DOCSECTIONS: + for file in glob.glob(os.path.join(docdir, sect, "*.tex")): + docs.append(open(file).read()) + + docs = "\n".join(docs) + + incfiles = os.path.join(incdir, INCLUDEPATTERN) + + fp = os.popen("ctags -IPyAPI_FUNC -IPy_GCC_ATTRIBUTE --c-types=%s -f - %s" + % (TAG_KINDS, incfiles)) + dict = findnames(fp, prefix) + names = dict.keys() + names.sort() + for name in names: + if not re.search("%s\\W" % name, docs): + print dict[name], name + +if __name__ == '__main__': + srcdir = os.path.dirname(sys.argv[0]) + incdir = os.path.normpath(os.path.join(srcdir, "../../Include")) + docdir = os.path.normpath(os.path.join(srcdir, "..")) + + print_undoc_symbols(PREFIXES, docdir, incdir) diff --git a/sys/src/cmd/python/Doc/tools/update-docs.sh b/sys/src/cmd/python/Doc/tools/update-docs.sh new file mode 100755 index 000000000..6599c64d1 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/update-docs.sh @@ -0,0 +1,31 @@ +#! /bin/sh + +# Script which installs a development snapshot of the documentation +# into the development website. +# +# The push-docs.sh script pushes this to the server when needed +# and removes it when done. + +if [ -z "$HOME" ] ; then + HOME=`grep "$LOGNAME" /etc/passwd | sed 's|^.*:\([^:]*\):[^:]*$|\1|'` + export HOME +fi + +DOCTYPE="$1" +UPDATES="$HOME/tmp/$2" + +TMPDIR="$$-docs" + +cd /ftp/ftp.python.org/pub/www.python.org/dev/doc/ || exit $? +mkdir $TMPDIR || exit $? +cd $TMPDIR || exit $? +(bzip2 -dc "$UPDATES" | tar xf -) || exit $? +cd .. || exit $? + +if [ -d $DOCTYPE ] ; then + mv $DOCTYPE $DOCTYPE-temp +fi +mv $TMPDIR/Python-Docs-* $DOCTYPE +rmdir $TMPDIR +rm -rf $DOCTYPE-temp || exit $? +mv "$UPDATES" python-docs-$DOCTYPE.tar.bz2 || exit $? diff --git a/sys/src/cmd/python/Doc/tools/whichlibs b/sys/src/cmd/python/Doc/tools/whichlibs new file mode 100755 index 000000000..10d44ee71 --- /dev/null +++ b/sys/src/cmd/python/Doc/tools/whichlibs @@ -0,0 +1,2 @@ +#!/bin/sh +sed -n 's%^\\input{\(lib[a-zA-Z0-9_]*\)}.*%../lib/\1.tex%p' ../lib/lib.tex diff --git a/sys/src/cmd/python/Doc/tut/glossary.tex b/sys/src/cmd/python/Doc/tut/glossary.tex new file mode 100644 index 000000000..17cc76776 --- /dev/null +++ b/sys/src/cmd/python/Doc/tut/glossary.tex @@ -0,0 +1,352 @@ +\chapter{Glossary\label{glossary}} + +%%% keep the entries sorted and include at least one \index{} item for each +%%% cross-references are marked with \emph{entry} + +\begin{description} + + +\index{>>>} +\item[\code{>>>}] +The typical Python prompt of the interactive shell. Often seen for +code examples that can be tried right away in the interpreter. + +\index{...} +\item[\code{.\code{.}.}] +The typical Python prompt of the interactive shell when entering code +for an indented code block. + +\index{BDFL} +\item[BDFL] +Benevolent Dictator For Life, a.k.a. \ulink{Guido van +Rossum}{http://www.python.org/\textasciitilde{}guido/}, Python's creator. + +\index{byte code} +\item[byte code] +The internal representation of a Python program in the interpreter. +The byte code is also cached in \code{.pyc} and \code{.pyo} +files so that executing the same file is faster the second time +(recompilation from source to byte code can be avoided). This +``intermediate language'' is said to run on a ``virtual +machine'' that calls the subroutines corresponding to each bytecode. + +\index{classic class} +\item[classic class] +Any class which does not inherit from \class{object}. See +\emph{new-style class}. + +\index{coercion} +\item[coercion] +The implicit conversion of an instance of one type to another during an +operation which involves two arguments of the same type. For example, +{}\code{int(3.15)} converts the floating point number to the integer +{}\code{3}, but in {}\code{3+4.5}, each argument is of a different type (one +int, one float), and both must be converted to the same type before they can +be added or it will raise a {}\code{TypeError}. Coercion between two +operands can be performed with the {}\code{coerce} builtin function; thus, +{}\code{3+4.5} is equivalent to calling {}\code{operator.add(*coerce(3, +4.5))} and results in {}\code{operator.add(3.0, 4.5)}. Without coercion, +all arguments of even compatible types would have to be normalized to the +same value by the programmer, e.g., {}\code{float(3)+4.5} rather than just +{}\code{3+4.5}. + +\index{complex number} +\item[complex number] +An extension of the familiar real number system in which all numbers are +expressed as a sum of a real part and an imaginary part. Imaginary numbers +are real multiples of the imaginary unit (the square root of {}\code{-1}), +often written {}\code{i} in mathematics or {}\code{j} in engineering. +Python has builtin support for complex numbers, which are written with this +latter notation; the imaginary part is written with a {}\code{j} suffix, +e.g., {}\code{3+1j}. To get access to complex equivalents of the +{}\module{math} module, use {}\module{cmath}. Use of complex numbers is a +fairly advanced mathematical feature. If you're not aware of a need for them, +it's almost certain you can safely ignore them. + +\index{descriptor} +\item[descriptor] +Any \emph{new-style} object that defines the methods +{}\method{__get__()}, \method{__set__()}, or \method{__delete__()}. +When a class attribute is a descriptor, its special binding behavior +is triggered upon attribute lookup. Normally, writing \var{a.b} looks +up the object \var{b} in the class dictionary for \var{a}, but if +{}\var{b} is a descriptor, the defined method gets called. +Understanding descriptors is a key to a deep understanding of Python +because they are the basis for many features including functions, +methods, properties, class methods, static methods, and reference to +super classes. + +\index{dictionary} +\item[dictionary] +An associative array, where arbitrary keys are mapped to values. The +use of \class{dict} much resembles that for \class{list}, but the keys +can be any object with a \method{__hash__()} function, not just +integers starting from zero. Called a hash in Perl. + +\index{duck-typing} +\item[duck-typing] +Pythonic programming style that determines an object's type by inspection +of its method or attribute signature rather than by explicit relationship +to some type object ("If it looks like a duck and quacks like a duck, it +must be a duck.") By emphasizing interfaces rather than specific types, +well-designed code improves its flexibility by allowing polymorphic +substitution. Duck-typing avoids tests using \function{type()} or +\function{isinstance()}. Instead, it typically employs +\function{hasattr()} tests or {}\emph{EAFP} programming. + +\index{EAFP} +\item[EAFP] +Easier to ask for forgiveness than permission. This common Python +coding style assumes the existence of valid keys or attributes and +catches exceptions if the assumption proves false. This clean and +fast style is characterized by the presence of many \keyword{try} and +{}\keyword{except} statements. The technique contrasts with the +{}\emph{LBYL} style that is common in many other languages such as C. + +\index{__future__} +\item[__future__] +A pseudo module which programmers can use to enable new language +features which are not compatible with the current interpreter. For +example, the expression \code{11/4} currently evaluates to \code{2}. +If the module in which it is executed had enabled \emph{true division} +by executing: + +\begin{verbatim} +from __future__ import division +\end{verbatim} + +the expression \code{11/4} would evaluate to \code{2.75}. By +importing the \ulink{\module{__future__}}{../lib/module-future.html} +module and evaluating its variables, you can see when a new feature +was first added to the language and when it will become the default: + +\begin{verbatim} +>>> import __future__ +>>> __future__.division +_Feature((2, 2, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0), 8192) +\end{verbatim} + +\index{generator} +\item[generator] +A function that returns an iterator. It looks like a normal function except +that values are returned to the caller using a \keyword{yield} statement +instead of a {}\keyword{return} statement. Generator functions often +contain one or more {}\keyword{for} or \keyword{while} loops that +\keyword{yield} elements back to the caller. The function execution is +stopped at the {}\keyword{yield} keyword (returning the result) and is +resumed there when the next element is requested by calling the +\method{next()} method of the returned iterator. + +\index{generator expression} +\item[generator expression] +An expression that returns a generator. It looks like a normal expression +followed by a \keyword{for} expression defining a loop variable, range, and +an optional \keyword{if} expression. The combined expression generates +values for an enclosing function: + +\begin{verbatim} +>>> sum(i*i for i in range(10)) # sum of squares 0, 1, 4, ... 81 +285 +\end{verbatim} + +\index{GIL} +\item[GIL] +See \emph{global interpreter lock}. + +\index{global interpreter lock} +\item[global interpreter lock] +The lock used by Python threads to assure that only one thread can be +run at a time. This simplifies Python by assuring that no two +processes can access the same memory at the same time. Locking the +entire interpreter makes it easier for the interpreter to be +multi-threaded, at the expense of some parallelism on multi-processor +machines. Efforts have been made in the past to create a +``free-threaded'' interpreter (one which locks shared data at a much +finer granularity), but performance suffered in the common +single-processor case. + +\index{IDLE} +\item[IDLE] +An Integrated Development Environment for Python. IDLE is a +basic editor and interpreter environment that ships with the standard +distribution of Python. Good for beginners, it also serves as clear +example code for those wanting to implement a moderately +sophisticated, multi-platform GUI application. + +\index{immutable} +\item[immutable] +An object with fixed value. Immutable objects are numbers, strings or +tuples (and more). Such an object cannot be altered. A new object +has to be created if a different value has to be stored. They play an +important role in places where a constant hash value is needed, for +example as a key in a dictionary. + +\index{integer division} +\item[integer division] +Mathematical division discarding any remainder. For example, the +expression \code{11/4} currently evaluates to \code{2} in contrast +to the \code{2.75} returned by float division. Also called +{}\emph{floor division}. When dividing two integers the outcome will +always be another integer (having the floor function applied to it). +However, if one of the operands is another numeric type (such as a +{}\class{float}), the result will be coerced (see \emph{coercion}) to +a common type. For example, an integer divided by a float will result +in a float value, possibly with a decimal fraction. Integer division +can be forced by using the \code{//} operator instead of the \code{/} +operator. See also \emph{__future__}. + +\index{interactive} +\item[interactive] +Python has an interactive interpreter which means that you can try out +things and immediately see their results. Just launch \code{python} with no +arguments (possibly by selecting it from your computer's main menu). +It is a very powerful way to test out new ideas or inspect modules and +packages (remember \code{help(x)}). + +\index{interpreted} +\item[interpreted] +Python is an interpreted language, as opposed to a compiled one. This means +that the source files can be run directly without first creating an +executable which is then run. Interpreted languages typically have a +shorter development/debug cycle than compiled ones, though their programs +generally also run more slowly. See also {}\emph{interactive}. + +\index{iterable} +\item[iterable] +A container object capable of returning its members one at a time. +Examples of iterables include all sequence types (such as \class{list}, +{}\class{str}, and \class{tuple}) and some non-sequence types like +{}\class{dict} and \class{file} and objects of any classes you define +with an \method{__iter__()} or \method{__getitem__()} method. Iterables +can be used in a \keyword{for} loop and in many other places where a +sequence is needed (\function{zip()}, \function{map()}, ...). When an +iterable object is passed as an argument to the builtin function +{}\function{iter()}, it returns an iterator for the object. This +iterator is good for one pass over the set of values. When using +iterables, it is usually not necessary to call \function{iter()} or +deal with iterator objects yourself. The \code{for} statement does +that automatically for you, creating a temporary unnamed variable to +hold the iterator for the duration of the loop. See also +{}\emph{iterator}, \emph{sequence}, and \emph{generator}. + +\index{iterator} +\item[iterator] +An object representing a stream of data. Repeated calls to the +iterator's \method{next()} method return successive items in the +stream. When no more data is available a \exception{StopIteration} +exception is raised instead. At this point, the iterator object is +exhausted and any further calls to its \method{next()} method just +raise \exception{StopIteration} again. Iterators are required to have +an \method{__iter__()} method that returns the iterator object +itself so every iterator is also iterable and may be used in most +places where other iterables are accepted. One notable exception is +code that attempts multiple iteration passes. A container object +(such as a \class{list}) produces a fresh new iterator each time you +pass it to the \function{iter()} function or use it in a +{}\keyword{for} loop. Attempting this with an iterator will just +return the same exhausted iterator object used in the previous iteration +pass, making it appear like an empty container. + +\index{LBYL} +\item[LBYL] +Look before you leap. This coding style explicitly tests for +pre-conditions before making calls or lookups. This style contrasts +with the \emph{EAFP} approach and is characterized by the presence of +many \keyword{if} statements. + +\index{list comprehension} +\item[list comprehension] +A compact way to process all or a subset of elements in a sequence and +return a list with the results. \code{result = ["0x\%02x" +\% x for x in range(256) if x \% 2 == 0]} generates a list of strings +containing hex numbers (0x..) that are even and in the range from 0 to 255. +The \keyword{if} clause is optional. If omitted, all elements in +{}\code{range(256)} are processed. + +\index{mapping} +\item[mapping] +A container object (such as \class{dict}) that supports arbitrary key +lookups using the special method \method{__getitem__()}. + +\index{metaclass} +\item[metaclass] +The class of a class. Class definitions create a class name, a class +dictionary, and a list of base classes. The metaclass is responsible +for taking those three arguments and creating the class. Most object +oriented programming languages provide a default implementation. What +makes Python special is that it is possible to create custom +metaclasses. Most users never need this tool, but when the need +arises, metaclasses can provide powerful, elegant solutions. They +have been used for logging attribute access, adding thread-safety, +tracking object creation, implementing singletons, and many other +tasks. + +\index{mutable} +\item[mutable] +Mutable objects can change their value but keep their \function{id()}. +See also \emph{immutable}. + +\index{namespace} +\item[namespace] +The place where a variable is stored. Namespaces are implemented as +dictionaries. There are the local, global and builtin namespaces +as well as nested namespaces in objects (in methods). Namespaces support +modularity by preventing naming conflicts. For instance, the +functions \function{__builtin__.open()} and \function{os.open()} are +distinguished by their namespaces. Namespaces also aid readability +and maintainability by making it clear which module implements a +function. For instance, writing \function{random.seed()} or +{}\function{itertools.izip()} makes it clear that those functions are +implemented by the \ulink{\module{random}}{../lib/module-random.html} +and \ulink{\module{itertools}}{../lib/module-itertools.html} modules +respectively. + +\index{nested scope} +\item[nested scope] +The ability to refer to a variable in an enclosing definition. For +instance, a function defined inside another function can refer to +variables in the outer function. Note that nested scopes work only +for reference and not for assignment which will always write to the +innermost scope. In contrast, local variables both read and write in +the innermost scope. Likewise, global variables read and write to the +global namespace. + +\index{new-style class} +\item[new-style class] +Any class that inherits from \class{object}. This includes all +built-in types like \class{list} and \class{dict}. Only new-style +classes can use Python's newer, versatile features like +{}\method{__slots__}, descriptors, properties, +\method{__getattribute__()}, class methods, and static methods. + +\index{Python3000} +\item[Python3000] +A mythical python release, not required to be backward compatible, with +telepathic interface. + +\index{__slots__} +\item[__slots__] +A declaration inside a \emph{new-style class} that saves memory by +pre-declaring space for instance attributes and eliminating instance +dictionaries. Though popular, the technique is somewhat tricky to get +right and is best reserved for rare cases where there are large +numbers of instances in a memory-critical application. + +\index{sequence} +\item[sequence] +An \emph{iterable} which supports efficient element access using +integer indices via the \method{__getitem__()} and +{}\method{__len__()} special methods. Some built-in sequence types +are \class{list}, \class{str}, \class{tuple}, and \class{unicode}. +Note that \class{dict} also supports \method{__getitem__()} and +{}\method{__len__()}, but is considered a mapping rather than a +sequence because the lookups use arbitrary \emph{immutable} keys +rather than integers. + +\index{Zen of Python} +\item[Zen of Python] +Listing of Python design principles and philosophies that are helpful +in understanding and using the language. The listing can be found by +typing ``\code{import this}'' at the interactive prompt. + +\end{description} diff --git a/sys/src/cmd/python/Doc/tut/tut.tex b/sys/src/cmd/python/Doc/tut/tut.tex new file mode 100644 index 000000000..2981a789d --- /dev/null +++ b/sys/src/cmd/python/Doc/tut/tut.tex @@ -0,0 +1,5907 @@ +\documentclass{manual} +\usepackage[T1]{fontenc} +\usepackage{textcomp} + +% Things to do: +% Should really move the Python startup file info to an appendix + +\title{Python Tutorial} + +\input{boilerplate} + +\makeindex + +\begin{document} + +\maketitle + +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +\input{copyright} + +\begin{abstract} + +\noindent +Python is an easy to learn, powerful programming language. It has +efficient high-level data structures and a simple but effective +approach to object-oriented programming. Python's elegant syntax and +dynamic typing, together with its interpreted nature, make it an ideal +language for scripting and rapid application development in many areas +on most platforms. + +The Python interpreter and the extensive standard library are freely +available in source or binary form for all major platforms from the +Python Web site, \url{http://www.python.org/}, and may be freely +distributed. The same site also contains distributions of and +pointers to many free third party Python modules, programs and tools, +and additional documentation. + +The Python interpreter is easily extended with new functions and data +types implemented in C or \Cpp{} (or other languages callable from C). +Python is also suitable as an extension language for customizable +applications. + +This tutorial introduces the reader informally to the basic concepts +and features of the Python language and system. It helps to have a +Python interpreter handy for hands-on experience, but all examples are +self-contained, so the tutorial can be read off-line as well. + +For a description of standard objects and modules, see the +\citetitle[../lib/lib.html]{Python Library Reference} document. The +\citetitle[../ref/ref.html]{Python Reference Manual} gives a more +formal definition of the language. To write extensions in C or +\Cpp, read \citetitle[../ext/ext.html]{Extending and Embedding the +Python Interpreter} and \citetitle[../api/api.html]{Python/C API +Reference}. There are also several books covering Python in depth. + +This tutorial does not attempt to be comprehensive and cover every +single feature, or even every commonly used feature. Instead, it +introduces many of Python's most noteworthy features, and will give +you a good idea of the language's flavor and style. After reading it, +you will be able to read and write Python modules and programs, and +you will be ready to learn more about the various Python library +modules described in the \citetitle[../lib/lib.html]{Python Library +Reference}. + +\end{abstract} + +\tableofcontents + + +\chapter{Whetting Your Appetite \label{intro}} + +If you do much work on computers, eventually you find that there's +some task you'd like to automate. For example, you may wish to +perform a search-and-replace over a large number of text files, or +rename and rearrange a bunch of photo files in a complicated way. +Perhaps you'd like to write a small custom database, or a specialized +GUI application, or a simple game. + +If you're a professional software developer, you may have to work with +several C/\Cpp/Java libraries but find the usual +write/compile/test/re-compile cycle is too slow. Perhaps you're +writing a test suite for such a library and find writing the testing +code a tedious task. Or maybe you've written a program that could use +an extension language, and you don't want to design and implement a +whole new language for your application. + +Python is just the language for you. + +You could write a {\UNIX} shell script or Windows batch files for some +of these tasks, but shell scripts are best at moving around files and +changing text data, not well-suited for GUI applications or games. +You could write a C/{\Cpp}/Java program, but it can take a lot of +development time to get even a first-draft program. Python is simpler +to use, available on Windows, MacOS X, and {\UNIX} operating systems, +and will help you get the job done more quickly. + +Python is simple to use, but it is a real programming language, +offering much more structure and support for large programs than shell +scripts or batch files can offer. On the other hand, Python also +offers much more error checking than C, and, being a +\emph{very-high-level language}, it has high-level data types built +in, such as flexible arrays and dictionaries. Because of its more +general data types Python is applicable to a much larger problem +domain than Awk or even Perl, yet many things are at +least as easy in Python as in those languages. + +Python allows you to split your program into modules that can be +reused in other Python programs. It comes with a large collection of +standard modules that you can use as the basis of your programs --- or +as examples to start learning to program in Python. Some of these +modules provide things like file I/O, system calls, +sockets, and even interfaces to graphical user interface toolkits like Tk. + +Python is an interpreted language, which can save you considerable time +during program development because no compilation and linking is +necessary. The interpreter can be used interactively, which makes it +easy to experiment with features of the language, to write throw-away +programs, or to test functions during bottom-up program development. +It is also a handy desk calculator. + +Python enables programs to be written compactly and readably. Programs +written in Python are typically much shorter than equivalent C, +\Cpp{}, or Java programs, for several reasons: +\begin{itemize} +\item +the high-level data types allow you to express complex operations in a +single statement; +\item +statement grouping is done by indentation instead of beginning and ending +brackets; +\item +no variable or argument declarations are necessary. +\end{itemize} + +Python is \emph{extensible}: if you know how to program in C it is easy +to add a new built-in function or module to the interpreter, either to +perform critical operations at maximum speed, or to link Python +programs to libraries that may only be available in binary form (such +as a vendor-specific graphics library). Once you are really hooked, +you can link the Python interpreter into an application written in C +and use it as an extension or command language for that application. + +By the way, the language is named after the BBC show ``Monty Python's +Flying Circus'' and has nothing to do with nasty reptiles. Making +references to Monty Python skits in documentation is not only allowed, +it is encouraged! + +%\section{Where From Here \label{where}} + +Now that you are all excited about Python, you'll want to examine it +in some more detail. Since the best way to learn a language is +to use it, the tutorial invites you to play with the Python interpreter +as you read. + +In the next chapter, the mechanics of using the interpreter are +explained. This is rather mundane information, but essential for +trying out the examples shown later. + +The rest of the tutorial introduces various features of the Python +language and system through examples, beginning with simple +expressions, statements and data types, through functions and modules, +and finally touching upon advanced concepts like exceptions +and user-defined classes. + +\chapter{Using the Python Interpreter \label{using}} + +\section{Invoking the Interpreter \label{invoking}} + +The Python interpreter is usually installed as +\file{/usr/local/bin/python} on those machines where it is available; +putting \file{/usr/local/bin} in your \UNIX{} shell's search path +makes it possible to start it by typing the command + +\begin{verbatim} +python +\end{verbatim} + +to the shell. Since the choice of the directory where the interpreter +lives is an installation option, other places are possible; check with +your local Python guru or system administrator. (E.g., +\file{/usr/local/python} is a popular alternative location.) + +On Windows machines, the Python installation is usually placed in +\file{C:\e Python24}, though you can change this when you're running +the installer. To add this directory to your path, +you can type the following command into the command prompt in a DOS box: + +\begin{verbatim} +set path=%path%;C:\python24 +\end{verbatim} + + +Typing an end-of-file character (\kbd{Control-D} on \UNIX, +\kbd{Control-Z} on Windows) at the primary prompt causes the +interpreter to exit with a zero exit status. If that doesn't work, +you can exit the interpreter by typing the following commands: +\samp{import sys; sys.exit()}. + +The interpreter's line-editing features usually aren't very +sophisticated. On \UNIX, whoever installed the interpreter may have +enabled support for the GNU readline library, which adds more +elaborate interactive editing and history features. Perhaps the +quickest check to see whether command line editing is supported is +typing Control-P to the first Python prompt you get. If it beeps, you +have command line editing; see Appendix \ref{interacting} for an +introduction to the keys. If nothing appears to happen, or if +\code{\^P} is echoed, command line editing isn't available; you'll +only be able to use backspace to remove characters from the current +line. + +The interpreter operates somewhat like the \UNIX{} shell: when called +with standard input connected to a tty device, it reads and executes +commands interactively; when called with a file name argument or with +a file as standard input, it reads and executes a \emph{script} from +that file. + +A second way of starting the interpreter is +\samp{\program{python} \programopt{-c} \var{command} [arg] ...}, which +executes the statement(s) in \var{command}, analogous to the shell's +\programopt{-c} option. Since Python statements often contain spaces +or other characters that are special to the shell, it is best to quote +\var{command} in its entirety with double quotes. + +Some Python modules are also useful as scripts. These can be invoked using +\samp{\program{python} \programopt{-m} \var{module} [arg] ...}, which +executes the source file for \var{module} as if you had spelled out its +full name on the command line. + +Note that there is a difference between \samp{python file} and +\samp{python <file}. In the latter case, input requests from the +program, such as calls to \function{input()} and \function{raw_input()}, are +satisfied from \emph{file}. Since this file has already been read +until the end by the parser before the program starts executing, the +program will encounter end-of-file immediately. In the former case +(which is usually what you want) they are satisfied from whatever file +or device is connected to standard input of the Python interpreter. + +When a script file is used, it is sometimes useful to be able to run +the script and enter interactive mode afterwards. This can be done by +passing \programopt{-i} before the script. (This does not work if the +script is read from standard input, for the same reason as explained +in the previous paragraph.) + +\subsection{Argument Passing \label{argPassing}} + +When known to the interpreter, the script name and additional +arguments thereafter are passed to the script in the variable +\code{sys.argv}, which is a list of strings. Its length is at least +one; when no script and no arguments are given, \code{sys.argv[0]} is +an empty string. When the script name is given as \code{'-'} (meaning +standard input), \code{sys.argv[0]} is set to \code{'-'}. When +\programopt{-c} \var{command} is used, \code{sys.argv[0]} is set to +\code{'-c'}. When \programopt{-m} \var{module} is used, \code{sys.argv[0]} +is set to the full name of the located module. Options found after +\programopt{-c} \var{command} or \programopt{-m} \var{module} are not consumed +by the Python interpreter's option processing but left in \code{sys.argv} for +the command or module to handle. + +\subsection{Interactive Mode \label{interactive}} + +When commands are read from a tty, the interpreter is said to be in +\emph{interactive mode}. In this mode it prompts for the next command +with the \emph{primary prompt}, usually three greater-than signs +(\samp{>>>~}); for continuation lines it prompts with the +\emph{secondary prompt}, by default three dots (\samp{...~}). +The interpreter prints a welcome message stating its version number +and a copyright notice before printing the first prompt: + +\begin{verbatim} +python +Python 1.5.2b2 (#1, Feb 28 1999, 00:02:06) [GCC 2.8.1] on sunos5 +Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam +>>> +\end{verbatim} + +Continuation lines are needed when entering a multi-line construct. +As an example, take a look at this \keyword{if} statement: + +\begin{verbatim} +>>> the_world_is_flat = 1 +>>> if the_world_is_flat: +... print "Be careful not to fall off!" +... +Be careful not to fall off! +\end{verbatim} + + +\section{The Interpreter and Its Environment \label{interp}} + +\subsection{Error Handling \label{error}} + +When an error occurs, the interpreter prints an error +message and a stack trace. In interactive mode, it then returns to +the primary prompt; when input came from a file, it exits with a +nonzero exit status after printing +the stack trace. (Exceptions handled by an \keyword{except} clause in a +\keyword{try} statement are not errors in this context.) Some errors are +unconditionally fatal and cause an exit with a nonzero exit; this +applies to internal inconsistencies and some cases of running out of +memory. All error messages are written to the standard error stream; +normal output from executed commands is written to standard +output. + +Typing the interrupt character (usually Control-C or DEL) to the +primary or secondary prompt cancels the input and returns to the +primary prompt.\footnote{ + A problem with the GNU Readline package may prevent this. +} +Typing an interrupt while a command is executing raises the +\exception{KeyboardInterrupt} exception, which may be handled by a +\keyword{try} statement. + +\subsection{Executable Python Scripts \label{scripts}} + +On BSD'ish \UNIX{} systems, Python scripts can be made directly +executable, like shell scripts, by putting the line + +\begin{verbatim} +#! /usr/bin/env python +\end{verbatim} + +(assuming that the interpreter is on the user's \envvar{PATH}) at the +beginning of the script and giving the file an executable mode. The +\samp{\#!} must be the first two characters of the file. On some +platforms, this first line must end with a \UNIX-style line ending +(\character{\e n}), not a Mac OS (\character{\e r}) or Windows +(\character{\e r\e n}) line ending. Note that +the hash, or pound, character, \character{\#}, is used to start a +comment in Python. + +The script can be given an executable mode, or permission, using the +\program{chmod} command: + +\begin{verbatim} +$ chmod +x myscript.py +\end{verbatim} % $ <-- bow to font-lock + + +\subsection{Source Code Encoding} + +It is possible to use encodings different than \ASCII{} in Python source +files. The best way to do it is to put one more special comment line +right after the \code{\#!} line to define the source file encoding: + +\begin{alltt} +# -*- coding: \var{encoding} -*- +\end{alltt} + +With that declaration, all characters in the source file will be treated as +having the encoding \var{encoding}, and it will be +possible to directly write Unicode string literals in the selected +encoding. The list of possible encodings can be found in the +\citetitle[../lib/lib.html]{Python Library Reference}, in the section +on \ulink{\module{codecs}}{../lib/module-codecs.html}. + +For example, to write Unicode literals including the Euro currency +symbol, the ISO-8859-15 encoding can be used, with the Euro symbol +having the ordinal value 164. This script will print the value 8364 +(the Unicode codepoint corresponding to the Euro symbol) and then +exit: + +\begin{alltt} +# -*- coding: iso-8859-15 -*- + +currency = u"\texteuro" +print ord(currency) +\end{alltt} + +If your editor supports saving files as \code{UTF-8} with a UTF-8 +\emph{byte order mark} (aka BOM), you can use that instead of an +encoding declaration. IDLE supports this capability if +\code{Options/General/Default Source Encoding/UTF-8} is set. Notice +that this signature is not understood in older Python releases (2.2 +and earlier), and also not understood by the operating system for +script files with \code{\#!} lines (only used on \UNIX{} systems). + +By using UTF-8 (either through the signature or an encoding +declaration), characters of most languages in the world can be used +simultaneously in string literals and comments. Using non-\ASCII{} +characters in identifiers is not supported. To display all these +characters properly, your editor must recognize that the file is +UTF-8, and it must use a font that supports all the characters in the +file. + +\subsection{The Interactive Startup File \label{startup}} + +% XXX This should probably be dumped in an appendix, since most people +% don't use Python interactively in non-trivial ways. + +When you use Python interactively, it is frequently handy to have some +standard commands executed every time the interpreter is started. You +can do this by setting an environment variable named +\envvar{PYTHONSTARTUP} to the name of a file containing your start-up +commands. This is similar to the \file{.profile} feature of the +\UNIX{} shells. + +This file is only read in interactive sessions, not when Python reads +commands from a script, and not when \file{/dev/tty} is given as the +explicit source of commands (which otherwise behaves like an +interactive session). It is executed in the same namespace where +interactive commands are executed, so that objects that it defines or +imports can be used without qualification in the interactive session. +You can also change the prompts \code{sys.ps1} and \code{sys.ps2} in +this file. + +If you want to read an additional start-up file from the current +directory, you can program this in the global start-up file using code +like \samp{if os.path.isfile('.pythonrc.py'): +execfile('.pythonrc.py')}. If you want to use the startup file in a +script, you must do this explicitly in the script: + +\begin{verbatim} +import os +filename = os.environ.get('PYTHONSTARTUP') +if filename and os.path.isfile(filename): + execfile(filename) +\end{verbatim} + + +\chapter{An Informal Introduction to Python \label{informal}} + +In the following examples, input and output are distinguished by the +presence or absence of prompts (\samp{>>>~} and \samp{...~}): to repeat +the example, you must type everything after the prompt, when the +prompt appears; lines that do not begin with a prompt are output from +the interpreter. % +%\footnote{ +% I'd prefer to use different fonts to distinguish input +% from output, but the amount of LaTeX hacking that would require +% is currently beyond my ability. +%} +Note that a secondary prompt on a line by itself in an example means +you must type a blank line; this is used to end a multi-line command. + +Many of the examples in this manual, even those entered at the +interactive prompt, include comments. Comments in Python start with +the hash character, \character{\#}, and extend to the end of the +physical line. A comment may appear at the start of a line or +following whitespace or code, but not within a string literal. A hash +character within a string literal is just a hash character. + +Some examples: + +\begin{verbatim} +# this is the first comment +SPAM = 1 # and this is the second comment + # ... and now a third! +STRING = "# This is not a comment." +\end{verbatim} + + +\section{Using Python as a Calculator \label{calculator}} + +Let's try some simple Python commands. Start the interpreter and wait +for the primary prompt, \samp{>>>~}. (It shouldn't take long.) + +\subsection{Numbers \label{numbers}} + +The interpreter acts as a simple calculator: you can type an +expression at it and it will write the value. Expression syntax is +straightforward: the operators \code{+}, \code{-}, \code{*} and +\code{/} work just like in most other languages (for example, Pascal +or C); parentheses can be used for grouping. For example: + +\begin{verbatim} +>>> 2+2 +4 +>>> # This is a comment +... 2+2 +4 +>>> 2+2 # and a comment on the same line as code +4 +>>> (50-5*6)/4 +5 +>>> # Integer division returns the floor: +... 7/3 +2 +>>> 7/-3 +-3 +\end{verbatim} + +The equal sign (\character{=}) is used to assign a value to a variable. +Afterwards, no result is displayed before the next interactive prompt: + +\begin{verbatim} +>>> width = 20 +>>> height = 5*9 +>>> width * height +900 +\end{verbatim} + +A value can be assigned to several variables simultaneously: + +\begin{verbatim} +>>> x = y = z = 0 # Zero x, y and z +>>> x +0 +>>> y +0 +>>> z +0 +\end{verbatim} + +There is full support for floating point; operators with mixed type +operands convert the integer operand to floating point: + +\begin{verbatim} +>>> 3 * 3.75 / 1.5 +7.5 +>>> 7.0 / 2 +3.5 +\end{verbatim} + +Complex numbers are also supported; imaginary numbers are written with +a suffix of \samp{j} or \samp{J}. Complex numbers with a nonzero +real component are written as \samp{(\var{real}+\var{imag}j)}, or can +be created with the \samp{complex(\var{real}, \var{imag})} function. + +\begin{verbatim} +>>> 1j * 1J +(-1+0j) +>>> 1j * complex(0,1) +(-1+0j) +>>> 3+1j*3 +(3+3j) +>>> (3+1j)*3 +(9+3j) +>>> (1+2j)/(1+1j) +(1.5+0.5j) +\end{verbatim} + +Complex numbers are always represented as two floating point numbers, +the real and imaginary part. To extract these parts from a complex +number \var{z}, use \code{\var{z}.real} and \code{\var{z}.imag}. + +\begin{verbatim} +>>> a=1.5+0.5j +>>> a.real +1.5 +>>> a.imag +0.5 +\end{verbatim} + +The conversion functions to floating point and integer +(\function{float()}, \function{int()} and \function{long()}) don't +work for complex numbers --- there is no one correct way to convert a +complex number to a real number. Use \code{abs(\var{z})} to get its +magnitude (as a float) or \code{z.real} to get its real part. + +\begin{verbatim} +>>> a=3.0+4.0j +>>> float(a) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: can't convert complex to float; use abs(z) +>>> a.real +3.0 +>>> a.imag +4.0 +>>> abs(a) # sqrt(a.real**2 + a.imag**2) +5.0 +>>> +\end{verbatim} + +In interactive mode, the last printed expression is assigned to the +variable \code{_}. This means that when you are using Python as a +desk calculator, it is somewhat easier to continue calculations, for +example: + +\begin{verbatim} +>>> tax = 12.5 / 100 +>>> price = 100.50 +>>> price * tax +12.5625 +>>> price + _ +113.0625 +>>> round(_, 2) +113.06 +>>> +\end{verbatim} + +This variable should be treated as read-only by the user. Don't +explicitly assign a value to it --- you would create an independent +local variable with the same name masking the built-in variable with +its magic behavior. + +\subsection{Strings \label{strings}} + +Besides numbers, Python can also manipulate strings, which can be +expressed in several ways. They can be enclosed in single quotes or +double quotes: + +\begin{verbatim} +>>> 'spam eggs' +'spam eggs' +>>> 'doesn\'t' +"doesn't" +>>> "doesn't" +"doesn't" +>>> '"Yes," he said.' +'"Yes," he said.' +>>> "\"Yes,\" he said." +'"Yes," he said.' +>>> '"Isn\'t," she said.' +'"Isn\'t," she said.' +\end{verbatim} + +String literals can span multiple lines in several ways. Continuation +lines can be used, with a backslash as the last character on the line +indicating that the next line is a logical continuation of the line: + +\begin{verbatim} +hello = "This is a rather long string containing\n\ +several lines of text just as you would do in C.\n\ + Note that whitespace at the beginning of the line is\ + significant." + +print hello +\end{verbatim} + +Note that newlines still need to be embedded in the string using +\code{\e n}; the newline following the trailing backslash is +discarded. This example would print the following: + +\begin{verbatim} +This is a rather long string containing +several lines of text just as you would do in C. + Note that whitespace at the beginning of the line is significant. +\end{verbatim} + +If we make the string literal a ``raw'' string, however, the +\code{\e n} sequences are not converted to newlines, but the backslash +at the end of the line, and the newline character in the source, are +both included in the string as data. Thus, the example: + +\begin{verbatim} +hello = r"This is a rather long string containing\n\ +several lines of text much as you would do in C." + +print hello +\end{verbatim} + +would print: + +\begin{verbatim} +This is a rather long string containing\n\ +several lines of text much as you would do in C. +\end{verbatim} + +Or, strings can be surrounded in a pair of matching triple-quotes: +\code{"""} or \code{'\code{'}'}. End of lines do not need to be escaped +when using triple-quotes, but they will be included in the string. + +\begin{verbatim} +print """ +Usage: thingy [OPTIONS] + -h Display this usage message + -H hostname Hostname to connect to +""" +\end{verbatim} + +produces the following output: + +\begin{verbatim} +Usage: thingy [OPTIONS] + -h Display this usage message + -H hostname Hostname to connect to +\end{verbatim} + +The interpreter prints the result of string operations in the same way +as they are typed for input: inside quotes, and with quotes and other +funny characters escaped by backslashes, to show the precise +value. The string is enclosed in double quotes if the string contains +a single quote and no double quotes, else it's enclosed in single +quotes. (The \keyword{print} statement, described later, can be used +to write strings without quotes or escapes.) + +Strings can be concatenated (glued together) with the +\code{+} operator, and repeated with \code{*}: + +\begin{verbatim} +>>> word = 'Help' + 'A' +>>> word +'HelpA' +>>> '<' + word*5 + '>' +'<HelpAHelpAHelpAHelpAHelpA>' +\end{verbatim} + +Two string literals next to each other are automatically concatenated; +the first line above could also have been written \samp{word = 'Help' +'A'}; this only works with two literals, not with arbitrary string +expressions: + +\begin{verbatim} +>>> 'str' 'ing' # <- This is ok +'string' +>>> 'str'.strip() + 'ing' # <- This is ok +'string' +>>> 'str'.strip() 'ing' # <- This is invalid + File "<stdin>", line 1, in ? + 'str'.strip() 'ing' + ^ +SyntaxError: invalid syntax +\end{verbatim} + +Strings can be subscripted (indexed); like in C, the first character +of a string has subscript (index) 0. There is no separate character +type; a character is simply a string of size one. Like in Icon, +substrings can be specified with the \emph{slice notation}: two indices +separated by a colon. + +\begin{verbatim} +>>> word[4] +'A' +>>> word[0:2] +'He' +>>> word[2:4] +'lp' +\end{verbatim} + +Slice indices have useful defaults; an omitted first index defaults to +zero, an omitted second index defaults to the size of the string being +sliced. + +\begin{verbatim} +>>> word[:2] # The first two characters +'He' +>>> word[2:] # Everything except the first two characters +'lpA' +\end{verbatim} + +Unlike a C string, Python strings cannot be changed. Assigning to an +indexed position in the string results in an error: + +\begin{verbatim} +>>> word[0] = 'x' +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: object doesn't support item assignment +>>> word[:1] = 'Splat' +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: object doesn't support slice assignment +\end{verbatim} + +However, creating a new string with the combined content is easy and +efficient: + +\begin{verbatim} +>>> 'x' + word[1:] +'xelpA' +>>> 'Splat' + word[4] +'SplatA' +\end{verbatim} + +Here's a useful invariant of slice operations: +\code{s[:i] + s[i:]} equals \code{s}. + +\begin{verbatim} +>>> word[:2] + word[2:] +'HelpA' +>>> word[:3] + word[3:] +'HelpA' +\end{verbatim} + +Degenerate slice indices are handled gracefully: an index that is too +large is replaced by the string size, an upper bound smaller than the +lower bound returns an empty string. + +\begin{verbatim} +>>> word[1:100] +'elpA' +>>> word[10:] +'' +>>> word[2:1] +'' +\end{verbatim} + +Indices may be negative numbers, to start counting from the right. +For example: + +\begin{verbatim} +>>> word[-1] # The last character +'A' +>>> word[-2] # The last-but-one character +'p' +>>> word[-2:] # The last two characters +'pA' +>>> word[:-2] # Everything except the last two characters +'Hel' +\end{verbatim} + +But note that -0 is really the same as 0, so it does not count from +the right! + +\begin{verbatim} +>>> word[-0] # (since -0 equals 0) +'H' +\end{verbatim} + +Out-of-range negative slice indices are truncated, but don't try this +for single-element (non-slice) indices: + +\begin{verbatim} +>>> word[-100:] +'HelpA' +>>> word[-10] # error +Traceback (most recent call last): + File "<stdin>", line 1, in ? +IndexError: string index out of range +\end{verbatim} + +The best way to remember how slices work is to think of the indices as +pointing \emph{between} characters, with the left edge of the first +character numbered 0. Then the right edge of the last character of a +string of \var{n} characters has index \var{n}, for example: + +\begin{verbatim} + +---+---+---+---+---+ + | H | e | l | p | A | + +---+---+---+---+---+ + 0 1 2 3 4 5 +-5 -4 -3 -2 -1 +\end{verbatim} + +The first row of numbers gives the position of the indices 0...5 in +the string; the second row gives the corresponding negative indices. +The slice from \var{i} to \var{j} consists of all characters between +the edges labeled \var{i} and \var{j}, respectively. + +For non-negative indices, the length of a slice is the difference of +the indices, if both are within bounds. For example, the length of +\code{word[1:3]} is 2. + +The built-in function \function{len()} returns the length of a string: + +\begin{verbatim} +>>> s = 'supercalifragilisticexpialidocious' +>>> len(s) +34 +\end{verbatim} + + +\begin{seealso} + \seetitle[../lib/typesseq.html]{Sequence Types}% + {Strings, and the Unicode strings described in the next + section, are examples of \emph{sequence types}, and + support the common operations supported by such types.} + \seetitle[../lib/string-methods.html]{String Methods}% + {Both strings and Unicode strings support a large number of + methods for basic transformations and searching.} + \seetitle[../lib/typesseq-strings.html]{String Formatting Operations}% + {The formatting operations invoked when strings and Unicode + strings are the left operand of the \code{\%} operator are + described in more detail here.} +\end{seealso} + + +\subsection{Unicode Strings \label{unicodeStrings}} +\sectionauthor{Marc-Andre Lemburg}{mal@lemburg.com} + +Starting with Python 2.0 a new data type for storing text data is +available to the programmer: the Unicode object. It can be used to +store and manipulate Unicode data (see \url{http://www.unicode.org/}) +and integrates well with the existing string objects, providing +auto-conversions where necessary. + +Unicode has the advantage of providing one ordinal for every character +in every script used in modern and ancient texts. Previously, there +were only 256 possible ordinals for script characters. Texts were +typically bound to a code page which mapped the ordinals to script +characters. This lead to very much confusion especially with respect +to internationalization (usually written as \samp{i18n} --- +\character{i} + 18 characters + \character{n}) of software. Unicode +solves these problems by defining one code page for all scripts. + +Creating Unicode strings in Python is just as simple as creating +normal strings: + +\begin{verbatim} +>>> u'Hello World !' +u'Hello World !' +\end{verbatim} + +The small \character{u} in front of the quote indicates that a +Unicode string is supposed to be created. If you want to include +special characters in the string, you can do so by using the Python +\emph{Unicode-Escape} encoding. The following example shows how: + +\begin{verbatim} +>>> u'Hello\u0020World !' +u'Hello World !' +\end{verbatim} + +The escape sequence \code{\e u0020} indicates to insert the Unicode +character with the ordinal value 0x0020 (the space character) at the +given position. + +Other characters are interpreted by using their respective ordinal +values directly as Unicode ordinals. If you have literal strings +in the standard Latin-1 encoding that is used in many Western countries, +you will find it convenient that the lower 256 characters +of Unicode are the same as the 256 characters of Latin-1. + +For experts, there is also a raw mode just like the one for normal +strings. You have to prefix the opening quote with 'ur' to have +Python use the \emph{Raw-Unicode-Escape} encoding. It will only apply +the above \code{\e uXXXX} conversion if there is an uneven number of +backslashes in front of the small 'u'. + +\begin{verbatim} +>>> ur'Hello\u0020World !' +u'Hello World !' +>>> ur'Hello\\u0020World !' +u'Hello\\\\u0020World !' +\end{verbatim} + +The raw mode is most useful when you have to enter lots of +backslashes, as can be necessary in regular expressions. + +Apart from these standard encodings, Python provides a whole set of +other ways of creating Unicode strings on the basis of a known +encoding. + +The built-in function \function{unicode()}\bifuncindex{unicode} provides +access to all registered Unicode codecs (COders and DECoders). Some of +the more well known encodings which these codecs can convert are +\emph{Latin-1}, \emph{ASCII}, \emph{UTF-8}, and \emph{UTF-16}. +The latter two are variable-length encodings that store each Unicode +character in one or more bytes. The default encoding is +normally set to \ASCII, which passes through characters in the range +0 to 127 and rejects any other characters with an error. +When a Unicode string is printed, written to a file, or converted +with \function{str()}, conversion takes place using this default encoding. + +\begin{verbatim} +>>> u"abc" +u'abc' +>>> str(u"abc") +'abc' +>>> u"äöü" +u'\xe4\xf6\xfc' +>>> str(u"äöü") +Traceback (most recent call last): + File "<stdin>", line 1, in ? +UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128) +\end{verbatim} + +To convert a Unicode string into an 8-bit string using a specific +encoding, Unicode objects provide an \function{encode()} method +that takes one argument, the name of the encoding. Lowercase names +for encodings are preferred. + +\begin{verbatim} +>>> u"äöü".encode('utf-8') +'\xc3\xa4\xc3\xb6\xc3\xbc' +\end{verbatim} + +If you have data in a specific encoding and want to produce a +corresponding Unicode string from it, you can use the +\function{unicode()} function with the encoding name as the second +argument. + +\begin{verbatim} +>>> unicode('\xc3\xa4\xc3\xb6\xc3\xbc', 'utf-8') +u'\xe4\xf6\xfc' +\end{verbatim} + +\subsection{Lists \label{lists}} + +Python knows a number of \emph{compound} data types, used to group +together other values. The most versatile is the \emph{list}, which +can be written as a list of comma-separated values (items) between +square brackets. List items need not all have the same type. + +\begin{verbatim} +>>> a = ['spam', 'eggs', 100, 1234] +>>> a +['spam', 'eggs', 100, 1234] +\end{verbatim} + +Like string indices, list indices start at 0, and lists can be sliced, +concatenated and so on: + +\begin{verbatim} +>>> a[0] +'spam' +>>> a[3] +1234 +>>> a[-2] +100 +>>> a[1:-1] +['eggs', 100] +>>> a[:2] + ['bacon', 2*2] +['spam', 'eggs', 'bacon', 4] +>>> 3*a[:3] + ['Boo!'] +['spam', 'eggs', 100, 'spam', 'eggs', 100, 'spam', 'eggs', 100, 'Boo!'] +\end{verbatim} + +Unlike strings, which are \emph{immutable}, it is possible to change +individual elements of a list: + +\begin{verbatim} +>>> a +['spam', 'eggs', 100, 1234] +>>> a[2] = a[2] + 23 +>>> a +['spam', 'eggs', 123, 1234] +\end{verbatim} + +Assignment to slices is also possible, and this can even change the size +of the list or clear it entirely: + +\begin{verbatim} +>>> # Replace some items: +... a[0:2] = [1, 12] +>>> a +[1, 12, 123, 1234] +>>> # Remove some: +... a[0:2] = [] +>>> a +[123, 1234] +>>> # Insert some: +... a[1:1] = ['bletch', 'xyzzy'] +>>> a +[123, 'bletch', 'xyzzy', 1234] +>>> # Insert (a copy of) itself at the beginning +>>> a[:0] = a +>>> a +[123, 'bletch', 'xyzzy', 1234, 123, 'bletch', 'xyzzy', 1234] +>>> # Clear the list: replace all items with an empty list +>>> a[:] = [] +>>> a +[] +\end{verbatim} + +The built-in function \function{len()} also applies to lists: + +\begin{verbatim} +>>> len(a) +8 +\end{verbatim} + +It is possible to nest lists (create lists containing other lists), +for example: + +\begin{verbatim} +>>> q = [2, 3] +>>> p = [1, q, 4] +>>> len(p) +3 +>>> p[1] +[2, 3] +>>> p[1][0] +2 +>>> p[1].append('xtra') # See section 5.1 +>>> p +[1, [2, 3, 'xtra'], 4] +>>> q +[2, 3, 'xtra'] +\end{verbatim} + +Note that in the last example, \code{p[1]} and \code{q} really refer to +the same object! We'll come back to \emph{object semantics} later. + +\section{First Steps Towards Programming \label{firstSteps}} + +Of course, we can use Python for more complicated tasks than adding +two and two together. For instance, we can write an initial +sub-sequence of the \emph{Fibonacci} series as follows: + +\begin{verbatim} +>>> # Fibonacci series: +... # the sum of two elements defines the next +... a, b = 0, 1 +>>> while b < 10: +... print b +... a, b = b, a+b +... +1 +1 +2 +3 +5 +8 +\end{verbatim} + +This example introduces several new features. + +\begin{itemize} + +\item +The first line contains a \emph{multiple assignment}: the variables +\code{a} and \code{b} simultaneously get the new values 0 and 1. On the +last line this is used again, demonstrating that the expressions on +the right-hand side are all evaluated first before any of the +assignments take place. The right-hand side expressions are evaluated +from the left to the right. + +\item +The \keyword{while} loop executes as long as the condition (here: +\code{b < 10}) remains true. In Python, like in C, any non-zero +integer value is true; zero is false. The condition may also be a +string or list value, in fact any sequence; anything with a non-zero +length is true, empty sequences are false. The test used in the +example is a simple comparison. The standard comparison operators are +written the same as in C: \code{<} (less than), \code{>} (greater than), +\code{==} (equal to), \code{<=} (less than or equal to), +\code{>=} (greater than or equal to) and \code{!=} (not equal to). + +\item +The \emph{body} of the loop is \emph{indented}: indentation is Python's +way of grouping statements. Python does not (yet!) provide an +intelligent input line editing facility, so you have to type a tab or +space(s) for each indented line. In practice you will prepare more +complicated input for Python with a text editor; most text editors have +an auto-indent facility. When a compound statement is entered +interactively, it must be followed by a blank line to indicate +completion (since the parser cannot guess when you have typed the last +line). Note that each line within a basic block must be indented by +the same amount. + +\item +The \keyword{print} statement writes the value of the expression(s) it is +given. It differs from just writing the expression you want to write +(as we did earlier in the calculator examples) in the way it handles +multiple expressions and strings. Strings are printed without quotes, +and a space is inserted between items, so you can format things nicely, +like this: + +\begin{verbatim} +>>> i = 256*256 +>>> print 'The value of i is', i +The value of i is 65536 +\end{verbatim} + +A trailing comma avoids the newline after the output: + +\begin{verbatim} +>>> a, b = 0, 1 +>>> while b < 1000: +... print b, +... a, b = b, a+b +... +1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 +\end{verbatim} + +Note that the interpreter inserts a newline before it prints the next +prompt if the last line was not completed. + +\end{itemize} + + +\chapter{More Control Flow Tools \label{moreControl}} + +Besides the \keyword{while} statement just introduced, Python knows +the usual control flow statements known from other languages, with +some twists. + +\section{\keyword{if} Statements \label{if}} + +Perhaps the most well-known statement type is the +\keyword{if} statement. For example: + +\begin{verbatim} +>>> x = int(raw_input("Please enter an integer: ")) +>>> if x < 0: +... x = 0 +... print 'Negative changed to zero' +... elif x == 0: +... print 'Zero' +... elif x == 1: +... print 'Single' +... else: +... print 'More' +... +\end{verbatim} + +There can be zero or more \keyword{elif} parts, and the +\keyword{else} part is optional. The keyword `\keyword{elif}' is +short for `else if', and is useful to avoid excessive indentation. An +\keyword{if} \ldots\ \keyword{elif} \ldots\ \keyword{elif} \ldots\ sequence +% Weird spacings happen here if the wrapping of the source text +% gets changed in the wrong way. +is a substitute for the \keyword{switch} or +\keyword{case} statements found in other languages. + + +\section{\keyword{for} Statements \label{for}} + +The \keyword{for}\stindex{for} statement in Python differs a bit from +what you may be used to in C or Pascal. Rather than always +iterating over an arithmetic progression of numbers (like in Pascal), +or giving the user the ability to define both the iteration step and +halting condition (as C), Python's +\keyword{for}\stindex{for} statement iterates over the items of any +sequence (a list or a string), in the order that they appear in +the sequence. For example (no pun intended): +% One suggestion was to give a real C example here, but that may only +% serve to confuse non-C programmers. + +\begin{verbatim} +>>> # Measure some strings: +... a = ['cat', 'window', 'defenestrate'] +>>> for x in a: +... print x, len(x) +... +cat 3 +window 6 +defenestrate 12 +\end{verbatim} + +It is not safe to modify the sequence being iterated over in the loop +(this can only happen for mutable sequence types, such as lists). If +you need to modify the list you are iterating over (for example, to +duplicate selected items) you must iterate over a copy. The slice +notation makes this particularly convenient: + +\begin{verbatim} +>>> for x in a[:]: # make a slice copy of the entire list +... if len(x) > 6: a.insert(0, x) +... +>>> a +['defenestrate', 'cat', 'window', 'defenestrate'] +\end{verbatim} + + +\section{The \function{range()} Function \label{range}} + +If you do need to iterate over a sequence of numbers, the built-in +function \function{range()} comes in handy. It generates lists +containing arithmetic progressions: + +\begin{verbatim} +>>> range(10) +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +\end{verbatim} + +The given end point is never part of the generated list; +\code{range(10)} generates a list of 10 values, the legal +indices for items of a sequence of length 10. It is possible to let +the range start at another number, or to specify a different increment +(even negative; sometimes this is called the `step'): + +\begin{verbatim} +>>> range(5, 10) +[5, 6, 7, 8, 9] +>>> range(0, 10, 3) +[0, 3, 6, 9] +>>> range(-10, -100, -30) +[-10, -40, -70] +\end{verbatim} + +To iterate over the indices of a sequence, combine +\function{range()} and \function{len()} as follows: + +\begin{verbatim} +>>> a = ['Mary', 'had', 'a', 'little', 'lamb'] +>>> for i in range(len(a)): +... print i, a[i] +... +0 Mary +1 had +2 a +3 little +4 lamb +\end{verbatim} + + +\section{\keyword{break} and \keyword{continue} Statements, and + \keyword{else} Clauses on Loops + \label{break}} + +The \keyword{break} statement, like in C, breaks out of the smallest +enclosing \keyword{for} or \keyword{while} loop. + +The \keyword{continue} statement, also borrowed from C, continues +with the next iteration of the loop. + +Loop statements may have an \code{else} clause; it is executed when +the loop terminates through exhaustion of the list (with +\keyword{for}) or when the condition becomes false (with +\keyword{while}), but not when the loop is terminated by a +\keyword{break} statement. This is exemplified by the following loop, +which searches for prime numbers: + +\begin{verbatim} +>>> for n in range(2, 10): +... for x in range(2, n): +... if n % x == 0: +... print n, 'equals', x, '*', n/x +... break +... else: +... # loop fell through without finding a factor +... print n, 'is a prime number' +... +2 is a prime number +3 is a prime number +4 equals 2 * 2 +5 is a prime number +6 equals 2 * 3 +7 is a prime number +8 equals 2 * 4 +9 equals 3 * 3 +\end{verbatim} + + +\section{\keyword{pass} Statements \label{pass}} + +The \keyword{pass} statement does nothing. +It can be used when a statement is required syntactically but the +program requires no action. +For example: + +\begin{verbatim} +>>> while True: +... pass # Busy-wait for keyboard interrupt +... +\end{verbatim} + + +\section{Defining Functions \label{functions}} + +We can create a function that writes the Fibonacci series to an +arbitrary boundary: + +\begin{verbatim} +>>> def fib(n): # write Fibonacci series up to n +... """Print a Fibonacci series up to n.""" +... a, b = 0, 1 +... while b < n: +... print b, +... a, b = b, a+b +... +>>> # Now call the function we just defined: +... fib(2000) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 +\end{verbatim} + +The keyword \keyword{def} introduces a function \emph{definition}. It +must be followed by the function name and the parenthesized list of +formal parameters. The statements that form the body of the function +start at the next line, and must be indented. The first statement of +the function body can optionally be a string literal; this string +literal is the function's \index{documentation strings}documentation +string, or \dfn{docstring}.\index{docstrings}\index{strings, documentation} + +There are tools which use docstrings to automatically produce online +or printed documentation, or to let the user interactively browse +through code; it's good practice to include docstrings in code that +you write, so try to make a habit of it. + +The \emph{execution} of a function introduces a new symbol table used +for the local variables of the function. More precisely, all variable +assignments in a function store the value in the local symbol table; +whereas variable references first look in the local symbol table, then +in the global symbol table, and then in the table of built-in names. +Thus, global variables cannot be directly assigned a value within a +function (unless named in a \keyword{global} statement), although +they may be referenced. + +The actual parameters (arguments) to a function call are introduced in +the local symbol table of the called function when it is called; thus, +arguments are passed using \emph{call by value} (where the +\emph{value} is always an object \emph{reference}, not the value of +the object).\footnote{ + Actually, \emph{call by object reference} would be a better + description, since if a mutable object is passed, the caller + will see any changes the callee makes to it (items + inserted into a list). +} When a function calls another function, a new local symbol table is +created for that call. + +A function definition introduces the function name in the current +symbol table. The value of the function name +has a type that is recognized by the interpreter as a user-defined +function. This value can be assigned to another name which can then +also be used as a function. This serves as a general renaming +mechanism: + +\begin{verbatim} +>>> fib +<function fib at 10042ed0> +>>> f = fib +>>> f(100) +1 1 2 3 5 8 13 21 34 55 89 +\end{verbatim} + +You might object that \code{fib} is not a function but a procedure. In +Python, like in C, procedures are just functions that don't return a +value. In fact, technically speaking, procedures do return a value, +albeit a rather boring one. This value is called \code{None} (it's a +built-in name). Writing the value \code{None} is normally suppressed by +the interpreter if it would be the only value written. You can see it +if you really want to: + +\begin{verbatim} +>>> print fib(0) +None +\end{verbatim} + +It is simple to write a function that returns a list of the numbers of +the Fibonacci series, instead of printing it: + +\begin{verbatim} +>>> def fib2(n): # return Fibonacci series up to n +... """Return a list containing the Fibonacci series up to n.""" +... result = [] +... a, b = 0, 1 +... while b < n: +... result.append(b) # see below +... a, b = b, a+b +... return result +... +>>> f100 = fib2(100) # call it +>>> f100 # write the result +[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] +\end{verbatim} + +This example, as usual, demonstrates some new Python features: + +\begin{itemize} + +\item +The \keyword{return} statement returns with a value from a function. +\keyword{return} without an expression argument returns \code{None}. +Falling off the end of a procedure also returns \code{None}. + +\item +The statement \code{result.append(b)} calls a \emph{method} of the list +object \code{result}. A method is a function that `belongs' to an +object and is named \code{obj.methodname}, where \code{obj} is some +object (this may be an expression), and \code{methodname} is the name +of a method that is defined by the object's type. Different types +define different methods. Methods of different types may have the +same name without causing ambiguity. (It is possible to define your +own object types and methods, using \emph{classes}, as discussed later +in this tutorial.) +The method \method{append()} shown in the example is defined for +list objects; it adds a new element at the end of the list. In this +example it is equivalent to \samp{result = result + [b]}, but more +efficient. + +\end{itemize} + +\section{More on Defining Functions \label{defining}} + +It is also possible to define functions with a variable number of +arguments. There are three forms, which can be combined. + +\subsection{Default Argument Values \label{defaultArgs}} + +The most useful form is to specify a default value for one or more +arguments. This creates a function that can be called with fewer +arguments than it is defined to allow. For example: + +\begin{verbatim} +def ask_ok(prompt, retries=4, complaint='Yes or no, please!'): + while True: + ok = raw_input(prompt) + if ok in ('y', 'ye', 'yes'): return True + if ok in ('n', 'no', 'nop', 'nope'): return False + retries = retries - 1 + if retries < 0: raise IOError, 'refusenik user' + print complaint +\end{verbatim} + +This function can be called either like this: +\code{ask_ok('Do you really want to quit?')} or like this: +\code{ask_ok('OK to overwrite the file?', 2)}. + +This example also introduces the \keyword{in} keyword. This tests +whether or not a sequence contains a certain value. + +The default values are evaluated at the point of function definition +in the \emph{defining} scope, so that + +\begin{verbatim} +i = 5 + +def f(arg=i): + print arg + +i = 6 +f() +\end{verbatim} + +will print \code{5}. + +\strong{Important warning:} The default value is evaluated only once. +This makes a difference when the default is a mutable object such as a +list, dictionary, or instances of most classes. For example, the +following function accumulates the arguments passed to it on +subsequent calls: + +\begin{verbatim} +def f(a, L=[]): + L.append(a) + return L + +print f(1) +print f(2) +print f(3) +\end{verbatim} + +This will print + +\begin{verbatim} +[1] +[1, 2] +[1, 2, 3] +\end{verbatim} + +If you don't want the default to be shared between subsequent calls, +you can write the function like this instead: + +\begin{verbatim} +def f(a, L=None): + if L is None: + L = [] + L.append(a) + return L +\end{verbatim} + +\subsection{Keyword Arguments \label{keywordArgs}} + +Functions can also be called using +keyword arguments of the form \samp{\var{keyword} = \var{value}}. For +instance, the following function: + +\begin{verbatim} +def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): + print "-- This parrot wouldn't", action, + print "if you put", voltage, "volts through it." + print "-- Lovely plumage, the", type + print "-- It's", state, "!" +\end{verbatim} + +could be called in any of the following ways: + +\begin{verbatim} +parrot(1000) +parrot(action = 'VOOOOOM', voltage = 1000000) +parrot('a thousand', state = 'pushing up the daisies') +parrot('a million', 'bereft of life', 'jump') +\end{verbatim} + +but the following calls would all be invalid: + +\begin{verbatim} +parrot() # required argument missing +parrot(voltage=5.0, 'dead') # non-keyword argument following keyword +parrot(110, voltage=220) # duplicate value for argument +parrot(actor='John Cleese') # unknown keyword +\end{verbatim} + +In general, an argument list must have any positional arguments +followed by any keyword arguments, where the keywords must be chosen +from the formal parameter names. It's not important whether a formal +parameter has a default value or not. No argument may receive a +value more than once --- formal parameter names corresponding to +positional arguments cannot be used as keywords in the same calls. +Here's an example that fails due to this restriction: + +\begin{verbatim} +>>> def function(a): +... pass +... +>>> function(0, a=0) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: function() got multiple values for keyword argument 'a' +\end{verbatim} + +When a final formal parameter of the form \code{**\var{name}} is +present, it receives a \ulink{dictionary}{../lib/typesmapping.html} +containing all keyword arguments except for those corresponding to +a formal parameter. This may be +combined with a formal parameter of the form +\code{*\var{name}} (described in the next subsection) which receives a +tuple containing the positional arguments beyond the formal parameter +list. (\code{*\var{name}} must occur before \code{**\var{name}}.) +For example, if we define a function like this: + +\begin{verbatim} +def cheeseshop(kind, *arguments, **keywords): + print "-- Do you have any", kind, '?' + print "-- I'm sorry, we're all out of", kind + for arg in arguments: print arg + print '-'*40 + keys = keywords.keys() + keys.sort() + for kw in keys: print kw, ':', keywords[kw] +\end{verbatim} + +It could be called like this: + +\begin{verbatim} +cheeseshop('Limburger', "It's very runny, sir.", + "It's really very, VERY runny, sir.", + client='John Cleese', + shopkeeper='Michael Palin', + sketch='Cheese Shop Sketch') +\end{verbatim} + +and of course it would print: + +\begin{verbatim} +-- Do you have any Limburger ? +-- I'm sorry, we're all out of Limburger +It's very runny, sir. +It's really very, VERY runny, sir. +---------------------------------------- +client : John Cleese +shopkeeper : Michael Palin +sketch : Cheese Shop Sketch +\end{verbatim} + +Note that the \method{sort()} method of the list of keyword argument +names is called before printing the contents of the \code{keywords} +dictionary; if this is not done, the order in which the arguments are +printed is undefined. + + +\subsection{Arbitrary Argument Lists \label{arbitraryArgs}} + +Finally, the least frequently used option is to specify that a +function can be called with an arbitrary number of arguments. These +arguments will be wrapped up in a tuple. Before the variable number +of arguments, zero or more normal arguments may occur. + +\begin{verbatim} +def fprintf(file, format, *args): + file.write(format % args) +\end{verbatim} + + +\subsection{Unpacking Argument Lists \label{unpacking-arguments}} + +The reverse situation occurs when the arguments are already in a list +or tuple but need to be unpacked for a function call requiring separate +positional arguments. For instance, the built-in \function{range()} +function expects separate \var{start} and \var{stop} arguments. If they +are not available separately, write the function call with the +\code{*}-operator to unpack the arguments out of a list or tuple: + +\begin{verbatim} +>>> range(3, 6) # normal call with separate arguments +[3, 4, 5] +>>> args = [3, 6] +>>> range(*args) # call with arguments unpacked from a list +[3, 4, 5] +\end{verbatim} + +In the same fashion, dictionaries can deliver keyword arguments with the +\code{**}-operator: + +\begin{verbatim} +>>> def parrot(voltage, state='a stiff', action='voom'): +... print "-- This parrot wouldn't", action, +... print "if you put", voltage, "volts through it.", +... print "E's", state, "!" +... +>>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"} +>>> parrot(**d) +-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised ! +\end{verbatim} + + +\subsection{Lambda Forms \label{lambda}} + +By popular demand, a few features commonly found in functional +programming languages like Lisp have been added to Python. With the +\keyword{lambda} keyword, small anonymous functions can be created. +Here's a function that returns the sum of its two arguments: +\samp{lambda a, b: a+b}. Lambda forms can be used wherever function +objects are required. They are syntactically restricted to a single +expression. Semantically, they are just syntactic sugar for a normal +function definition. Like nested function definitions, lambda forms +can reference variables from the containing scope: + +\begin{verbatim} +>>> def make_incrementor(n): +... return lambda x: x + n +... +>>> f = make_incrementor(42) +>>> f(0) +42 +>>> f(1) +43 +\end{verbatim} + + +\subsection{Documentation Strings \label{docstrings}} + +There are emerging conventions about the content and formatting of +documentation strings. +\index{docstrings}\index{documentation strings} +\index{strings, documentation} + +The first line should always be a short, concise summary of the +object's purpose. For brevity, it should not explicitly state the +object's name or type, since these are available by other means +(except if the name happens to be a verb describing a function's +operation). This line should begin with a capital letter and end with +a period. + +If there are more lines in the documentation string, the second line +should be blank, visually separating the summary from the rest of the +description. The following lines should be one or more paragraphs +describing the object's calling conventions, its side effects, etc. + +The Python parser does not strip indentation from multi-line string +literals in Python, so tools that process documentation have to strip +indentation if desired. This is done using the following convention. +The first non-blank line \emph{after} the first line of the string +determines the amount of indentation for the entire documentation +string. (We can't use the first line since it is generally adjacent +to the string's opening quotes so its indentation is not apparent in +the string literal.) Whitespace ``equivalent'' to this indentation is +then stripped from the start of all lines of the string. Lines that +are indented less should not occur, but if they occur all their +leading whitespace should be stripped. Equivalence of whitespace +should be tested after expansion of tabs (to 8 spaces, normally). + +Here is an example of a multi-line docstring: + +\begin{verbatim} +>>> def my_function(): +... """Do nothing, but document it. +... +... No, really, it doesn't do anything. +... """ +... pass +... +>>> print my_function.__doc__ +Do nothing, but document it. + + No, really, it doesn't do anything. + +\end{verbatim} + + + +\chapter{Data Structures \label{structures}} + +This chapter describes some things you've learned about already in +more detail, and adds some new things as well. + + +\section{More on Lists \label{moreLists}} + +The list data type has some more methods. Here are all of the methods +of list objects: + +\begin{methoddesc}[list]{append}{x} +Add an item to the end of the list; +equivalent to \code{a[len(a):] = [\var{x}]}. +\end{methoddesc} + +\begin{methoddesc}[list]{extend}{L} +Extend the list by appending all the items in the given list; +equivalent to \code{a[len(a):] = \var{L}}. +\end{methoddesc} + +\begin{methoddesc}[list]{insert}{i, x} +Insert an item at a given position. The first argument is the index +of the element before which to insert, so \code{a.insert(0, \var{x})} +inserts at the front of the list, and \code{a.insert(len(a), \var{x})} +is equivalent to \code{a.append(\var{x})}. +\end{methoddesc} + +\begin{methoddesc}[list]{remove}{x} +Remove the first item from the list whose value is \var{x}. +It is an error if there is no such item. +\end{methoddesc} + +\begin{methoddesc}[list]{pop}{\optional{i}} +Remove the item at the given position in the list, and return it. If +no index is specified, \code{a.pop()} removes and returns the last item +in the list. (The square brackets +around the \var{i} in the method signature denote that the parameter +is optional, not that you should type square brackets at that +position. You will see this notation frequently in the +\citetitle[../lib/lib.html]{Python Library Reference}.) +\end{methoddesc} + +\begin{methoddesc}[list]{index}{x} +Return the index in the list of the first item whose value is \var{x}. +It is an error if there is no such item. +\end{methoddesc} + +\begin{methoddesc}[list]{count}{x} +Return the number of times \var{x} appears in the list. +\end{methoddesc} + +\begin{methoddesc}[list]{sort}{} +Sort the items of the list, in place. +\end{methoddesc} + +\begin{methoddesc}[list]{reverse}{} +Reverse the elements of the list, in place. +\end{methoddesc} + +An example that uses most of the list methods: + +\begin{verbatim} +>>> a = [66.25, 333, 333, 1, 1234.5] +>>> print a.count(333), a.count(66.25), a.count('x') +2 1 0 +>>> a.insert(2, -1) +>>> a.append(333) +>>> a +[66.25, 333, -1, 333, 1, 1234.5, 333] +>>> a.index(333) +1 +>>> a.remove(333) +>>> a +[66.25, -1, 333, 1, 1234.5, 333] +>>> a.reverse() +>>> a +[333, 1234.5, 1, 333, -1, 66.25] +>>> a.sort() +>>> a +[-1, 1, 66.25, 333, 333, 1234.5] +\end{verbatim} + + +\subsection{Using Lists as Stacks \label{lists-as-stacks}} +\sectionauthor{Ka-Ping Yee}{ping@lfw.org} + +The list methods make it very easy to use a list as a stack, where the +last element added is the first element retrieved (``last-in, +first-out''). To add an item to the top of the stack, use +\method{append()}. To retrieve an item from the top of the stack, use +\method{pop()} without an explicit index. For example: + +\begin{verbatim} +>>> stack = [3, 4, 5] +>>> stack.append(6) +>>> stack.append(7) +>>> stack +[3, 4, 5, 6, 7] +>>> stack.pop() +7 +>>> stack +[3, 4, 5, 6] +>>> stack.pop() +6 +>>> stack.pop() +5 +>>> stack +[3, 4] +\end{verbatim} + + +\subsection{Using Lists as Queues \label{lists-as-queues}} +\sectionauthor{Ka-Ping Yee}{ping@lfw.org} + +You can also use a list conveniently as a queue, where the first +element added is the first element retrieved (``first-in, +first-out''). To add an item to the back of the queue, use +\method{append()}. To retrieve an item from the front of the queue, +use \method{pop()} with \code{0} as the index. For example: + +\begin{verbatim} +>>> queue = ["Eric", "John", "Michael"] +>>> queue.append("Terry") # Terry arrives +>>> queue.append("Graham") # Graham arrives +>>> queue.pop(0) +'Eric' +>>> queue.pop(0) +'John' +>>> queue +['Michael', 'Terry', 'Graham'] +\end{verbatim} + + +\subsection{Functional Programming Tools \label{functional}} + +There are three built-in functions that are very useful when used with +lists: \function{filter()}, \function{map()}, and \function{reduce()}. + +\samp{filter(\var{function}, \var{sequence})} returns a sequence +consisting of those items from the +sequence for which \code{\var{function}(\var{item})} is true. +If \var{sequence} is a \class{string} or \class{tuple}, the result will +be of the same type; otherwise, it is always a \class{list}. +For example, to compute some primes: + +\begin{verbatim} +>>> def f(x): return x % 2 != 0 and x % 3 != 0 +... +>>> filter(f, range(2, 25)) +[5, 7, 11, 13, 17, 19, 23] +\end{verbatim} + +\samp{map(\var{function}, \var{sequence})} calls +\code{\var{function}(\var{item})} for each of the sequence's items and +returns a list of the return values. For example, to compute some +cubes: + +\begin{verbatim} +>>> def cube(x): return x*x*x +... +>>> map(cube, range(1, 11)) +[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] +\end{verbatim} + +More than one sequence may be passed; the function must then have as +many arguments as there are sequences and is called with the +corresponding item from each sequence (or \code{None} if some sequence +is shorter than another). For example: + +\begin{verbatim} +>>> seq = range(8) +>>> def add(x, y): return x+y +... +>>> map(add, seq, seq) +[0, 2, 4, 6, 8, 10, 12, 14] +\end{verbatim} + +\samp{reduce(\var{function}, \var{sequence})} returns a single value +constructed by calling the binary function \var{function} on the first two +items of the sequence, then on the result and the next item, and so +on. For example, to compute the sum of the numbers 1 through 10: + +\begin{verbatim} +>>> def add(x,y): return x+y +... +>>> reduce(add, range(1, 11)) +55 +\end{verbatim} + +If there's only one item in the sequence, its value is returned; if +the sequence is empty, an exception is raised. + +A third argument can be passed to indicate the starting value. In this +case the starting value is returned for an empty sequence, and the +function is first applied to the starting value and the first sequence +item, then to the result and the next item, and so on. For example, + +\begin{verbatim} +>>> def sum(seq): +... def add(x,y): return x+y +... return reduce(add, seq, 0) +... +>>> sum(range(1, 11)) +55 +>>> sum([]) +0 +\end{verbatim} + +Don't use this example's definition of \function{sum()}: since summing +numbers is such a common need, a built-in function +\code{sum(\var{sequence})} is already provided, and works exactly like +this. +\versionadded{2.3} + +\subsection{List Comprehensions} + +List comprehensions provide a concise way to create lists without resorting +to use of \function{map()}, \function{filter()} and/or \keyword{lambda}. +The resulting list definition tends often to be clearer than lists built +using those constructs. Each list comprehension consists of an expression +followed by a \keyword{for} clause, then zero or more \keyword{for} or +\keyword{if} clauses. The result will be a list resulting from evaluating +the expression in the context of the \keyword{for} and \keyword{if} clauses +which follow it. If the expression would evaluate to a tuple, it must be +parenthesized. + +\begin{verbatim} +>>> freshfruit = [' banana', ' loganberry ', 'passion fruit '] +>>> [weapon.strip() for weapon in freshfruit] +['banana', 'loganberry', 'passion fruit'] +>>> vec = [2, 4, 6] +>>> [3*x for x in vec] +[6, 12, 18] +>>> [3*x for x in vec if x > 3] +[12, 18] +>>> [3*x for x in vec if x < 2] +[] +>>> [[x,x**2] for x in vec] +[[2, 4], [4, 16], [6, 36]] +>>> [x, x**2 for x in vec] # error - parens required for tuples + File "<stdin>", line 1, in ? + [x, x**2 for x in vec] + ^ +SyntaxError: invalid syntax +>>> [(x, x**2) for x in vec] +[(2, 4), (4, 16), (6, 36)] +>>> vec1 = [2, 4, 6] +>>> vec2 = [4, 3, -9] +>>> [x*y for x in vec1 for y in vec2] +[8, 6, -18, 16, 12, -36, 24, 18, -54] +>>> [x+y for x in vec1 for y in vec2] +[6, 5, -7, 8, 7, -5, 10, 9, -3] +>>> [vec1[i]*vec2[i] for i in range(len(vec1))] +[8, 12, -54] +\end{verbatim} + +List comprehensions are much more flexible than \function{map()} and can be +applied to complex expressions and nested functions: + +\begin{verbatim} +>>> [str(round(355/113.0, i)) for i in range(1,6)] +['3.1', '3.14', '3.142', '3.1416', '3.14159'] +\end{verbatim} + + +\section{The \keyword{del} statement \label{del}} + +There is a way to remove an item from a list given its index instead +of its value: the \keyword{del} statement. This differs from the +\method{pop()} method which returns a value. The \keyword{del} +statement can also be used to remove slices from a list or clear the +entire list (which we did earlier by assignment of an empty list to +the slice). For example: + +\begin{verbatim} +>>> a = [-1, 1, 66.25, 333, 333, 1234.5] +>>> del a[0] +>>> a +[1, 66.25, 333, 333, 1234.5] +>>> del a[2:4] +>>> a +[1, 66.25, 1234.5] +>>> del a[:] +>>> a +[] +\end{verbatim} + +\keyword{del} can also be used to delete entire variables: + +\begin{verbatim} +>>> del a +\end{verbatim} + +Referencing the name \code{a} hereafter is an error (at least until +another value is assigned to it). We'll find other uses for +\keyword{del} later. + + +\section{Tuples and Sequences \label{tuples}} + +We saw that lists and strings have many common properties, such as +indexing and slicing operations. They are two examples of +\ulink{\emph{sequence} data types}{../lib/typesseq.html}. Since +Python is an evolving language, other sequence data types may be +added. There is also another standard sequence data type: the +\emph{tuple}. + +A tuple consists of a number of values separated by commas, for +instance: + +\begin{verbatim} +>>> t = 12345, 54321, 'hello!' +>>> t[0] +12345 +>>> t +(12345, 54321, 'hello!') +>>> # Tuples may be nested: +... u = t, (1, 2, 3, 4, 5) +>>> u +((12345, 54321, 'hello!'), (1, 2, 3, 4, 5)) +\end{verbatim} + +As you see, on output tuples are always enclosed in parentheses, so +that nested tuples are interpreted correctly; they may be input with +or without surrounding parentheses, although often parentheses are +necessary anyway (if the tuple is part of a larger expression). + +Tuples have many uses. For example: (x, y) coordinate pairs, employee +records from a database, etc. Tuples, like strings, are immutable: it +is not possible to assign to the individual items of a tuple (you can +simulate much of the same effect with slicing and concatenation, +though). It is also possible to create tuples which contain mutable +objects, such as lists. + +A special problem is the construction of tuples containing 0 or 1 +items: the syntax has some extra quirks to accommodate these. Empty +tuples are constructed by an empty pair of parentheses; a tuple with +one item is constructed by following a value with a comma +(it is not sufficient to enclose a single value in parentheses). +Ugly, but effective. For example: + +\begin{verbatim} +>>> empty = () +>>> singleton = 'hello', # <-- note trailing comma +>>> len(empty) +0 +>>> len(singleton) +1 +>>> singleton +('hello',) +\end{verbatim} + +The statement \code{t = 12345, 54321, 'hello!'} is an example of +\emph{tuple packing}: the values \code{12345}, \code{54321} and +\code{'hello!'} are packed together in a tuple. The reverse operation +is also possible: + +\begin{verbatim} +>>> x, y, z = t +\end{verbatim} + +This is called, appropriately enough, \emph{sequence unpacking}. +Sequence unpacking requires the list of variables on the left to +have the same number of elements as the length of the sequence. Note +that multiple assignment is really just a combination of tuple packing +and sequence unpacking! + +There is a small bit of asymmetry here: packing multiple values +always creates a tuple, and unpacking works for any sequence. + +% XXX Add a bit on the difference between tuples and lists. + + +\section{Sets \label{sets}} + +Python also includes a data type for \emph{sets}. A set is an unordered +collection with no duplicate elements. Basic uses include membership +testing and eliminating duplicate entries. Set objects also support +mathematical operations like union, intersection, difference, and +symmetric difference. + +Here is a brief demonstration: + +\begin{verbatim} +>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] +>>> fruit = set(basket) # create a set without duplicates +>>> fruit +set(['orange', 'pear', 'apple', 'banana']) +>>> 'orange' in fruit # fast membership testing +True +>>> 'crabgrass' in fruit +False + +>>> # Demonstrate set operations on unique letters from two words +... +>>> a = set('abracadabra') +>>> b = set('alacazam') +>>> a # unique letters in a +set(['a', 'r', 'b', 'c', 'd']) +>>> a - b # letters in a but not in b +set(['r', 'd', 'b']) +>>> a | b # letters in either a or b +set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l']) +>>> a & b # letters in both a and b +set(['a', 'c']) +>>> a ^ b # letters in a or b but not both +set(['r', 'd', 'b', 'm', 'z', 'l']) +\end{verbatim} + + +\section{Dictionaries \label{dictionaries}} + +Another useful data type built into Python is the +\ulink{\emph{dictionary}}{../lib/typesmapping.html}. +Dictionaries are sometimes found in other languages as ``associative +memories'' or ``associative arrays''. Unlike sequences, which are +indexed by a range of numbers, dictionaries are indexed by \emph{keys}, +which can be any immutable type; strings and numbers can always be +keys. Tuples can be used as keys if they contain only strings, +numbers, or tuples; if a tuple contains any mutable object either +directly or indirectly, it cannot be used as a key. You can't use +lists as keys, since lists can be modified in place using +index assignments, slice assignments, or methods like +\method{append()} and \method{extend()}. + +It is best to think of a dictionary as an unordered set of +\emph{key: value} pairs, with the requirement that the keys are unique +(within one dictionary). +A pair of braces creates an empty dictionary: \code{\{\}}. +Placing a comma-separated list of key:value pairs within the +braces adds initial key:value pairs to the dictionary; this is also the +way dictionaries are written on output. + +The main operations on a dictionary are storing a value with some key +and extracting the value given the key. It is also possible to delete +a key:value pair +with \code{del}. +If you store using a key that is already in use, the old value +associated with that key is forgotten. It is an error to extract a +value using a non-existent key. + +The \method{keys()} method of a dictionary object returns a list of all +the keys used in the dictionary, in arbitrary order (if you want it +sorted, just apply the \method{sort()} method to the list of keys). To +check whether a single key is in the dictionary, either use the dictionary's +\method{has_key()} method or the \keyword{in} keyword. + +Here is a small example using a dictionary: + +\begin{verbatim} +>>> tel = {'jack': 4098, 'sape': 4139} +>>> tel['guido'] = 4127 +>>> tel +{'sape': 4139, 'guido': 4127, 'jack': 4098} +>>> tel['jack'] +4098 +>>> del tel['sape'] +>>> tel['irv'] = 4127 +>>> tel +{'guido': 4127, 'irv': 4127, 'jack': 4098} +>>> tel.keys() +['guido', 'irv', 'jack'] +>>> tel.has_key('guido') +True +>>> 'guido' in tel +True +\end{verbatim} + +The \function{dict()} constructor builds dictionaries directly from +lists of key-value pairs stored as tuples. When the pairs form a +pattern, list comprehensions can compactly specify the key-value list. + +\begin{verbatim} +>>> dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) +{'sape': 4139, 'jack': 4098, 'guido': 4127} +>>> dict([(x, x**2) for x in (2, 4, 6)]) # use a list comprehension +{2: 4, 4: 16, 6: 36} +\end{verbatim} + +Later in the tutorial, we will learn about Generator Expressions +which are even better suited for the task of supplying key-values pairs to +the \function{dict()} constructor. + +When the keys are simple strings, it is sometimes easier to specify +pairs using keyword arguments: + +\begin{verbatim} +>>> dict(sape=4139, guido=4127, jack=4098) +{'sape': 4139, 'jack': 4098, 'guido': 4127} +\end{verbatim} + + +\section{Looping Techniques \label{loopidioms}} + +When looping through dictionaries, the key and corresponding value can +be retrieved at the same time using the \method{iteritems()} method. + +\begin{verbatim} +>>> knights = {'gallahad': 'the pure', 'robin': 'the brave'} +>>> for k, v in knights.iteritems(): +... print k, v +... +gallahad the pure +robin the brave +\end{verbatim} + +When looping through a sequence, the position index and corresponding +value can be retrieved at the same time using the +\function{enumerate()} function. + +\begin{verbatim} +>>> for i, v in enumerate(['tic', 'tac', 'toe']): +... print i, v +... +0 tic +1 tac +2 toe +\end{verbatim} + +To loop over two or more sequences at the same time, the entries +can be paired with the \function{zip()} function. + +\begin{verbatim} +>>> questions = ['name', 'quest', 'favorite color'] +>>> answers = ['lancelot', 'the holy grail', 'blue'] +>>> for q, a in zip(questions, answers): +... print 'What is your %s? It is %s.' % (q, a) +... +What is your name? It is lancelot. +What is your quest? It is the holy grail. +What is your favorite color? It is blue. +\end{verbatim} + +To loop over a sequence in reverse, first specify the sequence +in a forward direction and then call the \function{reversed()} +function. + +\begin{verbatim} +>>> for i in reversed(xrange(1,10,2)): +... print i +... +9 +7 +5 +3 +1 +\end{verbatim} + +To loop over a sequence in sorted order, use the \function{sorted()} +function which returns a new sorted list while leaving the source +unaltered. + +\begin{verbatim} +>>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] +>>> for f in sorted(set(basket)): +... print f +... +apple +banana +orange +pear +\end{verbatim} + +\section{More on Conditions \label{conditions}} + +The conditions used in \code{while} and \code{if} statements can +contain any operators, not just comparisons. + +The comparison operators \code{in} and \code{not in} check whether a value +occurs (does not occur) in a sequence. The operators \code{is} and +\code{is not} compare whether two objects are really the same object; this +only matters for mutable objects like lists. All comparison operators +have the same priority, which is lower than that of all numerical +operators. + +Comparisons can be chained. For example, \code{a < b == c} tests +whether \code{a} is less than \code{b} and moreover \code{b} equals +\code{c}. + +Comparisons may be combined using the Boolean operators \code{and} and +\code{or}, and the outcome of a comparison (or of any other Boolean +expression) may be negated with \code{not}. These have lower +priorities than comparison operators; between them, \code{not} has +the highest priority and \code{or} the lowest, so that +\code{A and not B or C} is equivalent to \code{(A and (not B)) or C}. +As always, parentheses can be used to express the desired composition. + +The Boolean operators \code{and} and \code{or} are so-called +\emph{short-circuit} operators: their arguments are evaluated from +left to right, and evaluation stops as soon as the outcome is +determined. For example, if \code{A} and \code{C} are true but +\code{B} is false, \code{A and B and C} does not evaluate the +expression \code{C}. When used as a general value and not as a +Boolean, the return value of a short-circuit operator is the last +evaluated argument. + +It is possible to assign the result of a comparison or other Boolean +expression to a variable. For example, + +\begin{verbatim} +>>> string1, string2, string3 = '', 'Trondheim', 'Hammer Dance' +>>> non_null = string1 or string2 or string3 +>>> non_null +'Trondheim' +\end{verbatim} + +Note that in Python, unlike C, assignment cannot occur inside expressions. +C programmers may grumble about this, but it avoids a common class of +problems encountered in C programs: typing \code{=} in an expression when +\code{==} was intended. + + +\section{Comparing Sequences and Other Types \label{comparing}} + +Sequence objects may be compared to other objects with the same +sequence type. The comparison uses \emph{lexicographical} ordering: +first the first two items are compared, and if they differ this +determines the outcome of the comparison; if they are equal, the next +two items are compared, and so on, until either sequence is exhausted. +If two items to be compared are themselves sequences of the same type, +the lexicographical comparison is carried out recursively. If all +items of two sequences compare equal, the sequences are considered +equal. If one sequence is an initial sub-sequence of the other, the +shorter sequence is the smaller (lesser) one. Lexicographical +ordering for strings uses the \ASCII{} ordering for individual +characters. Some examples of comparisons between sequences of the +same type: + +\begin{verbatim} +(1, 2, 3) < (1, 2, 4) +[1, 2, 3] < [1, 2, 4] +'ABC' < 'C' < 'Pascal' < 'Python' +(1, 2, 3, 4) < (1, 2, 4) +(1, 2) < (1, 2, -1) +(1, 2, 3) == (1.0, 2.0, 3.0) +(1, 2, ('aa', 'ab')) < (1, 2, ('abc', 'a'), 4) +\end{verbatim} + +Note that comparing objects of different types is legal. The outcome +is deterministic but arbitrary: the types are ordered by their name. +Thus, a list is always smaller than a string, a string is always +smaller than a tuple, etc. \footnote{ + The rules for comparing objects of different types should + not be relied upon; they may change in a future version of + the language. +} Mixed numeric types are compared according to their numeric value, so +0 equals 0.0, etc. + + +\chapter{Modules \label{modules}} + +If you quit from the Python interpreter and enter it again, the +definitions you have made (functions and variables) are lost. +Therefore, if you want to write a somewhat longer program, you are +better off using a text editor to prepare the input for the interpreter +and running it with that file as input instead. This is known as creating a +\emph{script}. As your program gets longer, you may want to split it +into several files for easier maintenance. You may also want to use a +handy function that you've written in several programs without copying +its definition into each program. + +To support this, Python has a way to put definitions in a file and use +them in a script or in an interactive instance of the interpreter. +Such a file is called a \emph{module}; definitions from a module can be +\emph{imported} into other modules or into the \emph{main} module (the +collection of variables that you have access to in a script +executed at the top level +and in calculator mode). + +A module is a file containing Python definitions and statements. The +file name is the module name with the suffix \file{.py} appended. Within +a module, the module's name (as a string) is available as the value of +the global variable \code{__name__}. For instance, use your favorite text +editor to create a file called \file{fibo.py} in the current directory +with the following contents: + +\begin{verbatim} +# Fibonacci numbers module + +def fib(n): # write Fibonacci series up to n + a, b = 0, 1 + while b < n: + print b, + a, b = b, a+b + +def fib2(n): # return Fibonacci series up to n + result = [] + a, b = 0, 1 + while b < n: + result.append(b) + a, b = b, a+b + return result +\end{verbatim} + +Now enter the Python interpreter and import this module with the +following command: + +\begin{verbatim} +>>> import fibo +\end{verbatim} + +This does not enter the names of the functions defined in \code{fibo} +directly in the current symbol table; it only enters the module name +\code{fibo} there. +Using the module name you can access the functions: + +\begin{verbatim} +>>> fibo.fib(1000) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 +>>> fibo.fib2(100) +[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] +>>> fibo.__name__ +'fibo' +\end{verbatim} + +If you intend to use a function often you can assign it to a local name: + +\begin{verbatim} +>>> fib = fibo.fib +>>> fib(500) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 +\end{verbatim} + + +\section{More on Modules \label{moreModules}} + +A module can contain executable statements as well as function +definitions. +These statements are intended to initialize the module. +They are executed only the +\emph{first} time the module is imported somewhere.\footnote{ + In fact function definitions are also `statements' that are + `executed'; the execution enters the function name in the + module's global symbol table. +} + +Each module has its own private symbol table, which is used as the +global symbol table by all functions defined in the module. +Thus, the author of a module can use global variables in the module +without worrying about accidental clashes with a user's global +variables. +On the other hand, if you know what you are doing you can touch a +module's global variables with the same notation used to refer to its +functions, +\code{modname.itemname}. + +Modules can import other modules. It is customary but not required to +place all \keyword{import} statements at the beginning of a module (or +script, for that matter). The imported module names are placed in the +importing module's global symbol table. + +There is a variant of the \keyword{import} statement that imports +names from a module directly into the importing module's symbol +table. For example: + +\begin{verbatim} +>>> from fibo import fib, fib2 +>>> fib(500) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 +\end{verbatim} + +This does not introduce the module name from which the imports are taken +in the local symbol table (so in the example, \code{fibo} is not +defined). + +There is even a variant to import all names that a module defines: + +\begin{verbatim} +>>> from fibo import * +>>> fib(500) +1 1 2 3 5 8 13 21 34 55 89 144 233 377 +\end{verbatim} + +This imports all names except those beginning with an underscore +(\code{_}). + + +\subsection{The Module Search Path \label{searchPath}} + +\indexiii{module}{search}{path} +When a module named \module{spam} is imported, the interpreter searches +for a file named \file{spam.py} in the current directory, +and then in the list of directories specified by +the environment variable \envvar{PYTHONPATH}. This has the same syntax as +the shell variable \envvar{PATH}, that is, a list of +directory names. When \envvar{PYTHONPATH} is not set, or when the file +is not found there, the search continues in an installation-dependent +default path; on \UNIX, this is usually \file{.:/usr/local/lib/python}. + +Actually, modules are searched in the list of directories given by the +variable \code{sys.path} which is initialized from the directory +containing the input script (or the current directory), +\envvar{PYTHONPATH} and the installation-dependent default. This allows +Python programs that know what they're doing to modify or replace the +module search path. Note that because the directory containing the +script being run is on the search path, it is important that the +script not have the same name as a standard module, or Python will +attempt to load the script as a module when that module is imported. +This will generally be an error. See section~\ref{standardModules}, +``Standard Modules,'' for more information. + + +\subsection{``Compiled'' Python files} + +As an important speed-up of the start-up time for short programs that +use a lot of standard modules, if a file called \file{spam.pyc} exists +in the directory where \file{spam.py} is found, this is assumed to +contain an already-``byte-compiled'' version of the module \module{spam}. +The modification time of the version of \file{spam.py} used to create +\file{spam.pyc} is recorded in \file{spam.pyc}, and the +\file{.pyc} file is ignored if these don't match. + +Normally, you don't need to do anything to create the +\file{spam.pyc} file. Whenever \file{spam.py} is successfully +compiled, an attempt is made to write the compiled version to +\file{spam.pyc}. It is not an error if this attempt fails; if for any +reason the file is not written completely, the resulting +\file{spam.pyc} file will be recognized as invalid and thus ignored +later. The contents of the \file{spam.pyc} file are platform +independent, so a Python module directory can be shared by machines of +different architectures. + +Some tips for experts: + +\begin{itemize} + +\item +When the Python interpreter is invoked with the \programopt{-O} flag, +optimized code is generated and stored in \file{.pyo} files. The +optimizer currently doesn't help much; it only removes +\keyword{assert} statements. When \programopt{-O} is used, \emph{all} +bytecode is optimized; \code{.pyc} files are ignored and \code{.py} +files are compiled to optimized bytecode. + +\item +Passing two \programopt{-O} flags to the Python interpreter +(\programopt{-OO}) will cause the bytecode compiler to perform +optimizations that could in some rare cases result in malfunctioning +programs. Currently only \code{__doc__} strings are removed from the +bytecode, resulting in more compact \file{.pyo} files. Since some +programs may rely on having these available, you should only use this +option if you know what you're doing. + +\item +A program doesn't run any faster when it is read from a \file{.pyc} or +\file{.pyo} file than when it is read from a \file{.py} file; the only +thing that's faster about \file{.pyc} or \file{.pyo} files is the +speed with which they are loaded. + +\item +When a script is run by giving its name on the command line, the +bytecode for the script is never written to a \file{.pyc} or +\file{.pyo} file. Thus, the startup time of a script may be reduced +by moving most of its code to a module and having a small bootstrap +script that imports that module. It is also possible to name a +\file{.pyc} or \file{.pyo} file directly on the command line. + +\item +It is possible to have a file called \file{spam.pyc} (or +\file{spam.pyo} when \programopt{-O} is used) without a file +\file{spam.py} for the same module. This can be used to distribute a +library of Python code in a form that is moderately hard to reverse +engineer. + +\item +The module \ulink{\module{compileall}}{../lib/module-compileall.html}% +{} \refstmodindex{compileall} can create \file{.pyc} files (or +\file{.pyo} files when \programopt{-O} is used) for all modules in a +directory. + +\end{itemize} + + +\section{Standard Modules \label{standardModules}} + +Python comes with a library of standard modules, described in a separate +document, the \citetitle[../lib/lib.html]{Python Library Reference} +(``Library Reference'' hereafter). Some modules are built into the +interpreter; these provide access to operations that are not part of +the core of the language but are nevertheless built in, either for +efficiency or to provide access to operating system primitives such as +system calls. The set of such modules is a configuration option which +also depends on the underlying platform For example, +the \module{amoeba} module is only provided on systems that somehow +support Amoeba primitives. One particular module deserves some +attention: \ulink{\module{sys}}{../lib/module-sys.html}% +\refstmodindex{sys}, which is built into every +Python interpreter. The variables \code{sys.ps1} and +\code{sys.ps2} define the strings used as primary and secondary +prompts: + +\begin{verbatim} +>>> import sys +>>> sys.ps1 +'>>> ' +>>> sys.ps2 +'... ' +>>> sys.ps1 = 'C> ' +C> print 'Yuck!' +Yuck! +C> + +\end{verbatim} + +These two variables are only defined if the interpreter is in +interactive mode. + +The variable \code{sys.path} is a list of strings that determines the +interpreter's search path for modules. It is initialized to a default +path taken from the environment variable \envvar{PYTHONPATH}, or from +a built-in default if \envvar{PYTHONPATH} is not set. You can modify +it using standard list operations: + +\begin{verbatim} +>>> import sys +>>> sys.path.append('/ufs/guido/lib/python') +\end{verbatim} + +\section{The \function{dir()} Function \label{dir}} + +The built-in function \function{dir()} is used to find out which names +a module defines. It returns a sorted list of strings: + +\begin{verbatim} +>>> import fibo, sys +>>> dir(fibo) +['__name__', 'fib', 'fib2'] +>>> dir(sys) +['__displayhook__', '__doc__', '__excepthook__', '__name__', '__stderr__', + '__stdin__', '__stdout__', '_getframe', 'api_version', 'argv', + 'builtin_module_names', 'byteorder', 'callstats', 'copyright', + 'displayhook', 'exc_clear', 'exc_info', 'exc_type', 'excepthook', + 'exec_prefix', 'executable', 'exit', 'getdefaultencoding', 'getdlopenflags', + 'getrecursionlimit', 'getrefcount', 'hexversion', 'maxint', 'maxunicode', + 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', + 'platform', 'prefix', 'ps1', 'ps2', 'setcheckinterval', 'setdlopenflags', + 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', + 'version', 'version_info', 'warnoptions'] +\end{verbatim} + +Without arguments, \function{dir()} lists the names you have defined +currently: + +\begin{verbatim} +>>> a = [1, 2, 3, 4, 5] +>>> import fibo +>>> fib = fibo.fib +>>> dir() +['__builtins__', '__doc__', '__file__', '__name__', 'a', 'fib', 'fibo', 'sys'] +\end{verbatim} + +Note that it lists all types of names: variables, modules, functions, etc. + +\function{dir()} does not list the names of built-in functions and +variables. If you want a list of those, they are defined in the +standard module \module{__builtin__}\refbimodindex{__builtin__}: + +\begin{verbatim} +>>> import __builtin__ +>>> dir(__builtin__) +['ArithmeticError', 'AssertionError', 'AttributeError', 'DeprecationWarning', + 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False', + 'FloatingPointError', 'FutureWarning', 'IOError', 'ImportError', + 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', + 'LookupError', 'MemoryError', 'NameError', 'None', 'NotImplemented', + 'NotImplementedError', 'OSError', 'OverflowError', + 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', + 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', + 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'True', + 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', + 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', + 'UserWarning', 'ValueError', 'Warning', 'WindowsError', + 'ZeroDivisionError', '_', '__debug__', '__doc__', '__import__', + '__name__', 'abs', 'apply', 'basestring', 'bool', 'buffer', + 'callable', 'chr', 'classmethod', 'cmp', 'coerce', 'compile', + 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', + 'enumerate', 'eval', 'execfile', 'exit', 'file', 'filter', 'float', + 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', + 'id', 'input', 'int', 'intern', 'isinstance', 'issubclass', 'iter', + 'len', 'license', 'list', 'locals', 'long', 'map', 'max', 'min', + 'object', 'oct', 'open', 'ord', 'pow', 'property', 'quit', 'range', + 'raw_input', 'reduce', 'reload', 'repr', 'reversed', 'round', 'set', + 'setattr', 'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', + 'tuple', 'type', 'unichr', 'unicode', 'vars', 'xrange', 'zip'] +\end{verbatim} + + +\section{Packages \label{packages}} + +Packages are a way of structuring Python's module namespace +by using ``dotted module names''. For example, the module name +\module{A.B} designates a submodule named \samp{B} in a package named +\samp{A}. Just like the use of modules saves the authors of different +modules from having to worry about each other's global variable names, +the use of dotted module names saves the authors of multi-module +packages like NumPy or the Python Imaging Library from having to worry +about each other's module names. + +Suppose you want to design a collection of modules (a ``package'') for +the uniform handling of sound files and sound data. There are many +different sound file formats (usually recognized by their extension, +for example: \file{.wav}, \file{.aiff}, \file{.au}), so you may need +to create and maintain a growing collection of modules for the +conversion between the various file formats. There are also many +different operations you might want to perform on sound data (such as +mixing, adding echo, applying an equalizer function, creating an +artificial stereo effect), so in addition you will be writing a +never-ending stream of modules to perform these operations. Here's a +possible structure for your package (expressed in terms of a +hierarchical filesystem): + +\begin{verbatim} +Sound/ Top-level package + __init__.py Initialize the sound package + Formats/ Subpackage for file format conversions + __init__.py + wavread.py + wavwrite.py + aiffread.py + aiffwrite.py + auread.py + auwrite.py + ... + Effects/ Subpackage for sound effects + __init__.py + echo.py + surround.py + reverse.py + ... + Filters/ Subpackage for filters + __init__.py + equalizer.py + vocoder.py + karaoke.py + ... +\end{verbatim} + +When importing the package, Python searches through the directories +on \code{sys.path} looking for the package subdirectory. + +The \file{__init__.py} files are required to make Python treat the +directories as containing packages; this is done to prevent +directories with a common name, such as \samp{string}, from +unintentionally hiding valid modules that occur later on the module +search path. In the simplest case, \file{__init__.py} can just be an +empty file, but it can also execute initialization code for the +package or set the \code{__all__} variable, described later. + +Users of the package can import individual modules from the +package, for example: + +\begin{verbatim} +import Sound.Effects.echo +\end{verbatim} + +This loads the submodule \module{Sound.Effects.echo}. It must be referenced +with its full name. + +\begin{verbatim} +Sound.Effects.echo.echofilter(input, output, delay=0.7, atten=4) +\end{verbatim} + +An alternative way of importing the submodule is: + +\begin{verbatim} +from Sound.Effects import echo +\end{verbatim} + +This also loads the submodule \module{echo}, and makes it available without +its package prefix, so it can be used as follows: + +\begin{verbatim} +echo.echofilter(input, output, delay=0.7, atten=4) +\end{verbatim} + +Yet another variation is to import the desired function or variable directly: + +\begin{verbatim} +from Sound.Effects.echo import echofilter +\end{verbatim} + +Again, this loads the submodule \module{echo}, but this makes its function +\function{echofilter()} directly available: + +\begin{verbatim} +echofilter(input, output, delay=0.7, atten=4) +\end{verbatim} + +Note that when using \code{from \var{package} import \var{item}}, the +item can be either a submodule (or subpackage) of the package, or some +other name defined in the package, like a function, class or +variable. The \code{import} statement first tests whether the item is +defined in the package; if not, it assumes it is a module and attempts +to load it. If it fails to find it, an +\exception{ImportError} exception is raised. + +Contrarily, when using syntax like \code{import +\var{item.subitem.subsubitem}}, each item except for the last must be +a package; the last item can be a module or a package but can't be a +class or function or variable defined in the previous item. + +\subsection{Importing * From a Package \label{pkg-import-star}} +%The \code{__all__} Attribute + +\ttindex{__all__} +Now what happens when the user writes \code{from Sound.Effects import +*}? Ideally, one would hope that this somehow goes out to the +filesystem, finds which submodules are present in the package, and +imports them all. Unfortunately, this operation does not work very +well on Windows platforms, where the filesystem does not +always have accurate information about the case of a filename! On +these platforms, there is no guaranteed way to know whether a file +\file{ECHO.PY} should be imported as a module \module{echo}, +\module{Echo} or \module{ECHO}. (For example, Windows 95 has the +annoying practice of showing all file names with a capitalized first +letter.) The DOS 8+3 filename restriction adds another interesting +problem for long module names. + +The only solution is for the package author to provide an explicit +index of the package. The import statement uses the following +convention: if a package's \file{__init__.py} code defines a list +named \code{__all__}, it is taken to be the list of module names that +should be imported when \code{from \var{package} import *} is +encountered. It is up to the package author to keep this list +up-to-date when a new version of the package is released. Package +authors may also decide not to support it, if they don't see a use for +importing * from their package. For example, the file +\file{Sounds/Effects/__init__.py} could contain the following code: + +\begin{verbatim} +__all__ = ["echo", "surround", "reverse"] +\end{verbatim} + +This would mean that \code{from Sound.Effects import *} would +import the three named submodules of the \module{Sound} package. + +If \code{__all__} is not defined, the statement \code{from Sound.Effects +import *} does \emph{not} import all submodules from the package +\module{Sound.Effects} into the current namespace; it only ensures that the +package \module{Sound.Effects} has been imported (possibly running any +initialization code in \file{__init__.py}) and then imports whatever names are +defined in the package. This includes any names defined (and +submodules explicitly loaded) by \file{__init__.py}. It also includes any +submodules of the package that were explicitly loaded by previous +import statements. Consider this code: + +\begin{verbatim} +import Sound.Effects.echo +import Sound.Effects.surround +from Sound.Effects import * +\end{verbatim} + +In this example, the echo and surround modules are imported in the +current namespace because they are defined in the +\module{Sound.Effects} package when the \code{from...import} statement +is executed. (This also works when \code{__all__} is defined.) + +Note that in general the practice of importing \code{*} from a module or +package is frowned upon, since it often causes poorly readable code. +However, it is okay to use it to save typing in interactive sessions, +and certain modules are designed to export only names that follow +certain patterns. + +Remember, there is nothing wrong with using \code{from Package +import specific_submodule}! In fact, this is the +recommended notation unless the importing module needs to use +submodules with the same name from different packages. + + +\subsection{Intra-package References} + +The submodules often need to refer to each other. For example, the +\module{surround} module might use the \module{echo} module. In fact, +such references are so common that the \keyword{import} statement +first looks in the containing package before looking in the standard +module search path. Thus, the \module{surround} module can simply use +\code{import echo} or \code{from echo import echofilter}. If the +imported module is not found in the current package (the package of +which the current module is a submodule), the \keyword{import} +statement looks for a top-level module with the given name. + +When packages are structured into subpackages (as with the +\module{Sound} package in the example), there's no shortcut to refer +to submodules of sibling packages - the full name of the subpackage +must be used. For example, if the module +\module{Sound.Filters.vocoder} needs to use the \module{echo} module +in the \module{Sound.Effects} package, it can use \code{from +Sound.Effects import echo}. + +Starting with Python 2.5, in addition to the implicit relative imports +described above, you can write explicit relative imports with the +\code{from module import name} form of import statement. These explicit +relative imports use leading dots to indicate the current and parent +packages involved in the relative import. From the \module{surround} +module for example, you might use: + +\begin{verbatim} +from . import echo +from .. import Formats +from ..Filters import equalizer +\end{verbatim} + +Note that both explicit and implicit relative imports are based on the +name of the current module. Since the name of the main module is always +\code{"__main__"}, modules intended for use as the main module of a +Python application should always use absolute imports. + +\subsection{Packages in Multiple Directories} + +Packages support one more special attribute, \member{__path__}. This +is initialized to be a list containing the name of the directory +holding the package's \file{__init__.py} before the code in that file +is executed. This variable can be modified; doing so affects future +searches for modules and subpackages contained in the package. + +While this feature is not often needed, it can be used to extend the +set of modules found in a package. + + + +\chapter{Input and Output \label{io}} + +There are several ways to present the output of a program; data can be +printed in a human-readable form, or written to a file for future use. +This chapter will discuss some of the possibilities. + + +\section{Fancier Output Formatting \label{formatting}} + +So far we've encountered two ways of writing values: \emph{expression +statements} and the \keyword{print} statement. (A third way is using +the \method{write()} method of file objects; the standard output file +can be referenced as \code{sys.stdout}. See the Library Reference for +more information on this.) + +Often you'll want more control over the formatting of your output than +simply printing space-separated values. There are two ways to format +your output; the first way is to do all the string handling yourself; +using string slicing and concatenation operations you can create any +layout you can imagine. The standard module +\module{string}\refstmodindex{string} contains some useful operations +for padding strings to a given column width; these will be discussed +shortly. The second way is to use the \code{\%} operator with a +string as the left argument. The \code{\%} operator interprets the +left argument much like a \cfunction{sprintf()}-style format +string to be applied to the right argument, and returns the string +resulting from this formatting operation. + +One question remains, of course: how do you convert values to strings? +Luckily, Python has ways to convert any value to a string: pass it to +the \function{repr()} or \function{str()} functions. Reverse quotes +(\code{``}) are equivalent to \function{repr()}, but they are no +longer used in modern Python code and will likely not be in future +versions of the language. + +The \function{str()} function is meant to return representations of +values which are fairly human-readable, while \function{repr()} is +meant to generate representations which can be read by the interpreter +(or will force a \exception{SyntaxError} if there is not equivalent +syntax). For objects which don't have a particular representation for +human consumption, \function{str()} will return the same value as +\function{repr()}. Many values, such as numbers or structures like +lists and dictionaries, have the same representation using either +function. Strings and floating point numbers, in particular, have two +distinct representations. + +Some examples: + +\begin{verbatim} +>>> s = 'Hello, world.' +>>> str(s) +'Hello, world.' +>>> repr(s) +"'Hello, world.'" +>>> str(0.1) +'0.1' +>>> repr(0.1) +'0.10000000000000001' +>>> x = 10 * 3.25 +>>> y = 200 * 200 +>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...' +>>> print s +The value of x is 32.5, and y is 40000... +>>> # The repr() of a string adds string quotes and backslashes: +... hello = 'hello, world\n' +>>> hellos = repr(hello) +>>> print hellos +'hello, world\n' +>>> # The argument to repr() may be any Python object: +... repr((x, y, ('spam', 'eggs'))) +"(32.5, 40000, ('spam', 'eggs'))" +>>> # reverse quotes are convenient in interactive sessions: +... `x, y, ('spam', 'eggs')` +"(32.5, 40000, ('spam', 'eggs'))" +\end{verbatim} + +Here are two ways to write a table of squares and cubes: + +\begin{verbatim} +>>> for x in range(1, 11): +... print repr(x).rjust(2), repr(x*x).rjust(3), +... # Note trailing comma on previous line +... print repr(x*x*x).rjust(4) +... + 1 1 1 + 2 4 8 + 3 9 27 + 4 16 64 + 5 25 125 + 6 36 216 + 7 49 343 + 8 64 512 + 9 81 729 +10 100 1000 + +>>> for x in range(1,11): +... print '%2d %3d %4d' % (x, x*x, x*x*x) +... + 1 1 1 + 2 4 8 + 3 9 27 + 4 16 64 + 5 25 125 + 6 36 216 + 7 49 343 + 8 64 512 + 9 81 729 +10 100 1000 +\end{verbatim} + +(Note that in the first example, one space between each column was +added by the way \keyword{print} works: it always adds spaces between +its arguments.) + +This example demonstrates the \method{rjust()} method of string objects, +which right-justifies a string in a field of a given width by padding +it with spaces on the left. There are similar methods +\method{ljust()} and \method{center()}. These +methods do not write anything, they just return a new string. If +the input string is too long, they don't truncate it, but return it +unchanged; this will mess up your column lay-out but that's usually +better than the alternative, which would be lying about a value. (If +you really want truncation you can always add a slice operation, as in +\samp{x.ljust(n)[:n]}.) + +There is another method, \method{zfill()}, which pads a +numeric string on the left with zeros. It understands about plus and +minus signs: + +\begin{verbatim} +>>> '12'.zfill(5) +'00012' +>>> '-3.14'.zfill(7) +'-003.14' +>>> '3.14159265359'.zfill(5) +'3.14159265359' +\end{verbatim} + +Using the \code{\%} operator looks like this: + +\begin{verbatim} +>>> import math +>>> print 'The value of PI is approximately %5.3f.' % math.pi +The value of PI is approximately 3.142. +\end{verbatim} + +If there is more than one format in the string, you need to pass a +tuple as right operand, as in this example: + +\begin{verbatim} +>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678} +>>> for name, phone in table.items(): +... print '%-10s ==> %10d' % (name, phone) +... +Jack ==> 4098 +Dcab ==> 7678 +Sjoerd ==> 4127 +\end{verbatim} + +Most formats work exactly as in C and require that you pass the proper +type; however, if you don't you get an exception, not a core dump. +The \code{\%s} format is more relaxed: if the corresponding argument is +not a string object, it is converted to string using the +\function{str()} built-in function. Using \code{*} to pass the width +or precision in as a separate (integer) argument is supported. The +C formats \code{\%n} and \code{\%p} are not supported. + +If you have a really long format string that you don't want to split +up, it would be nice if you could reference the variables to be +formatted by name instead of by position. This can be done by using +form \code{\%(name)format}, as shown here: + +\begin{verbatim} +>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678} +>>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; Dcab: %(Dcab)d' % table +Jack: 4098; Sjoerd: 4127; Dcab: 8637678 +\end{verbatim} + +This is particularly useful in combination with the new built-in +\function{vars()} function, which returns a dictionary containing all +local variables. + +\section{Reading and Writing Files \label{files}} + +% Opening files +\function{open()}\bifuncindex{open} returns a file +object\obindex{file}, and is most commonly used with two arguments: +\samp{open(\var{filename}, \var{mode})}. + +\begin{verbatim} +>>> f=open('/tmp/workfile', 'w') +>>> print f +<open file '/tmp/workfile', mode 'w' at 80a0960> +\end{verbatim} + +The first argument is a string containing the filename. The second +argument is another string containing a few characters describing the +way in which the file will be used. \var{mode} can be \code{'r'} when +the file will only be read, \code{'w'} for only writing (an existing +file with the same name will be erased), and \code{'a'} opens the file +for appending; any data written to the file is automatically added to +the end. \code{'r+'} opens the file for both reading and writing. +The \var{mode} argument is optional; \code{'r'} will be assumed if +it's omitted. + +On Windows and the Macintosh, \code{'b'} appended to the +mode opens the file in binary mode, so there are also modes like +\code{'rb'}, \code{'wb'}, and \code{'r+b'}. Windows makes a +distinction between text and binary files; the end-of-line characters +in text files are automatically altered slightly when data is read or +written. This behind-the-scenes modification to file data is fine for +\ASCII{} text files, but it'll corrupt binary data like that in \file{JPEG} or +\file{EXE} files. Be very careful to use binary mode when reading and +writing such files. + +\subsection{Methods of File Objects \label{fileMethods}} + +The rest of the examples in this section will assume that a file +object called \code{f} has already been created. + +To read a file's contents, call \code{f.read(\var{size})}, which reads +some quantity of data and returns it as a string. \var{size} is an +optional numeric argument. When \var{size} is omitted or negative, +the entire contents of the file will be read and returned; it's your +problem if the file is twice as large as your machine's memory. +Otherwise, at most \var{size} bytes are read and returned. If the end +of the file has been reached, \code{f.read()} will return an empty +string (\code {""}). +\begin{verbatim} +>>> f.read() +'This is the entire file.\n' +>>> f.read() +'' +\end{verbatim} + +\code{f.readline()} reads a single line from the file; a newline +character (\code{\e n}) is left at the end of the string, and is only +omitted on the last line of the file if the file doesn't end in a +newline. This makes the return value unambiguous; if +\code{f.readline()} returns an empty string, the end of the file has +been reached, while a blank line is represented by \code{'\e n'}, a +string containing only a single newline. + +\begin{verbatim} +>>> f.readline() +'This is the first line of the file.\n' +>>> f.readline() +'Second line of the file\n' +>>> f.readline() +'' +\end{verbatim} + +\code{f.readlines()} returns a list containing all the lines of data +in the file. If given an optional parameter \var{sizehint}, it reads +that many bytes from the file and enough more to complete a line, and +returns the lines from that. This is often used to allow efficient +reading of a large file by lines, but without having to load the +entire file in memory. Only complete lines will be returned. + +\begin{verbatim} +>>> f.readlines() +['This is the first line of the file.\n', 'Second line of the file\n'] +\end{verbatim} + +An alternate approach to reading lines is to loop over the file object. +This is memory efficient, fast, and leads to simpler code: + +\begin{verbatim} +>>> for line in f: + print line, + +This is the first line of the file. +Second line of the file +\end{verbatim} + +The alternative approach is simpler but does not provide as fine-grained +control. Since the two approaches manage line buffering differently, +they should not be mixed. + +\code{f.write(\var{string})} writes the contents of \var{string} to +the file, returning \code{None}. + +\begin{verbatim} +>>> f.write('This is a test\n') +\end{verbatim} + +To write something other than a string, it needs to be converted to a +string first: + +\begin{verbatim} +>>> value = ('the answer', 42) +>>> s = str(value) +>>> f.write(s) +\end{verbatim} + +\code{f.tell()} returns an integer giving the file object's current +position in the file, measured in bytes from the beginning of the +file. To change the file object's position, use +\samp{f.seek(\var{offset}, \var{from_what})}. The position is +computed from adding \var{offset} to a reference point; the reference +point is selected by the \var{from_what} argument. A +\var{from_what} value of 0 measures from the beginning of the file, 1 +uses the current file position, and 2 uses the end of the file as the +reference point. \var{from_what} can be omitted and defaults to 0, +using the beginning of the file as the reference point. + +\begin{verbatim} +>>> f = open('/tmp/workfile', 'r+') +>>> f.write('0123456789abcdef') +>>> f.seek(5) # Go to the 6th byte in the file +>>> f.read(1) +'5' +>>> f.seek(-3, 2) # Go to the 3rd byte before the end +>>> f.read(1) +'d' +\end{verbatim} + +When you're done with a file, call \code{f.close()} to close it and +free up any system resources taken up by the open file. After calling +\code{f.close()}, attempts to use the file object will automatically fail. + +\begin{verbatim} +>>> f.close() +>>> f.read() +Traceback (most recent call last): + File "<stdin>", line 1, in ? +ValueError: I/O operation on closed file +\end{verbatim} + +File objects have some additional methods, such as +\method{isatty()} and \method{truncate()} which are less frequently +used; consult the Library Reference for a complete guide to file +objects. + +\subsection{The \module{pickle} Module \label{pickle}} +\refstmodindex{pickle} + +Strings can easily be written to and read from a file. Numbers take a +bit more effort, since the \method{read()} method only returns +strings, which will have to be passed to a function like +\function{int()}, which takes a string like \code{'123'} and +returns its numeric value 123. However, when you want to save more +complex data types like lists, dictionaries, or class instances, +things get a lot more complicated. + +Rather than have users be constantly writing and debugging code to +save complicated data types, Python provides a standard module called +\ulink{\module{pickle}}{../lib/module-pickle.html}. This is an +amazing module that can take almost +any Python object (even some forms of Python code!), and convert it to +a string representation; this process is called \dfn{pickling}. +Reconstructing the object from the string representation is called +\dfn{unpickling}. Between pickling and unpickling, the string +representing the object may have been stored in a file or data, or +sent over a network connection to some distant machine. + +If you have an object \code{x}, and a file object \code{f} that's been +opened for writing, the simplest way to pickle the object takes only +one line of code: + +\begin{verbatim} +pickle.dump(x, f) +\end{verbatim} + +To unpickle the object again, if \code{f} is a file object which has +been opened for reading: + +\begin{verbatim} +x = pickle.load(f) +\end{verbatim} + +(There are other variants of this, used when pickling many objects or +when you don't want to write the pickled data to a file; consult the +complete documentation for +\ulink{\module{pickle}}{../lib/module-pickle.html} in the +\citetitle[../lib/]{Python Library Reference}.) + +\ulink{\module{pickle}}{../lib/module-pickle.html} is the standard way +to make Python objects which can be stored and reused by other +programs or by a future invocation of the same program; the technical +term for this is a \dfn{persistent} object. Because +\ulink{\module{pickle}}{../lib/module-pickle.html} is so widely used, +many authors who write Python extensions take care to ensure that new +data types such as matrices can be properly pickled and unpickled. + + + +\chapter{Errors and Exceptions \label{errors}} + +Until now error messages haven't been more than mentioned, but if you +have tried out the examples you have probably seen some. There are +(at least) two distinguishable kinds of errors: +\emph{syntax errors} and \emph{exceptions}. + +\section{Syntax Errors \label{syntaxErrors}} + +Syntax errors, also known as parsing errors, are perhaps the most common +kind of complaint you get while you are still learning Python: + +\begin{verbatim} +>>> while True print 'Hello world' + File "<stdin>", line 1, in ? + while True print 'Hello world' + ^ +SyntaxError: invalid syntax +\end{verbatim} + +The parser repeats the offending line and displays a little `arrow' +pointing at the earliest point in the line where the error was +detected. The error is caused by (or at least detected at) the token +\emph{preceding} the arrow: in the example, the error is detected at +the keyword \keyword{print}, since a colon (\character{:}) is missing +before it. File name and line number are printed so you know where to +look in case the input came from a script. + +\section{Exceptions \label{exceptions}} + +Even if a statement or expression is syntactically correct, it may +cause an error when an attempt is made to execute it. +Errors detected during execution are called \emph{exceptions} and are +not unconditionally fatal: you will soon learn how to handle them in +Python programs. Most exceptions are not handled by programs, +however, and result in error messages as shown here: + +\begin{verbatim} +>>> 10 * (1/0) +Traceback (most recent call last): + File "<stdin>", line 1, in ? +ZeroDivisionError: integer division or modulo by zero +>>> 4 + spam*3 +Traceback (most recent call last): + File "<stdin>", line 1, in ? +NameError: name 'spam' is not defined +>>> '2' + 2 +Traceback (most recent call last): + File "<stdin>", line 1, in ? +TypeError: cannot concatenate 'str' and 'int' objects +\end{verbatim} + +The last line of the error message indicates what happened. +Exceptions come in different types, and the type is printed as part of +the message: the types in the example are +\exception{ZeroDivisionError}, \exception{NameError} and +\exception{TypeError}. +The string printed as the exception type is the name of the built-in +exception that occurred. This is true for all built-in +exceptions, but need not be true for user-defined exceptions (although +it is a useful convention). +Standard exception names are built-in identifiers (not reserved +keywords). + +The rest of the line provides detail based on the type of exception +and what caused it. + +The preceding part of the error message shows the context where the +exception happened, in the form of a stack traceback. +In general it contains a stack traceback listing source lines; however, +it will not display lines read from standard input. + +The \citetitle[../lib/module-exceptions.html]{Python Library +Reference} lists the built-in exceptions and their meanings. + + +\section{Handling Exceptions \label{handling}} + +It is possible to write programs that handle selected exceptions. +Look at the following example, which asks the user for input until a +valid integer has been entered, but allows the user to interrupt the +program (using \kbd{Control-C} or whatever the operating system +supports); note that a user-generated interruption is signalled by +raising the \exception{KeyboardInterrupt} exception. + +\begin{verbatim} +>>> while True: +... try: +... x = int(raw_input("Please enter a number: ")) +... break +... except ValueError: +... print "Oops! That was no valid number. Try again..." +... +\end{verbatim} + +The \keyword{try} statement works as follows. + +\begin{itemize} +\item +First, the \emph{try clause} (the statement(s) between the +\keyword{try} and \keyword{except} keywords) is executed. + +\item +If no exception occurs, the \emph{except\ clause} is skipped and +execution of the \keyword{try} statement is finished. + +\item +If an exception occurs during execution of the try clause, the rest of +the clause is skipped. Then if its type matches the exception named +after the \keyword{except} keyword, the except clause is executed, and +then execution continues after the \keyword{try} statement. + +\item +If an exception occurs which does not match the exception named in the +except clause, it is passed on to outer \keyword{try} statements; if +no handler is found, it is an \emph{unhandled exception} and execution +stops with a message as shown above. + +\end{itemize} + +A \keyword{try} statement may have more than one except clause, to +specify handlers for different exceptions. At most one handler will +be executed. Handlers only handle exceptions that occur in the +corresponding try clause, not in other handlers of the same +\keyword{try} statement. An except clause may name multiple exceptions +as a parenthesized tuple, for example: + +\begin{verbatim} +... except (RuntimeError, TypeError, NameError): +... pass +\end{verbatim} + +The last except clause may omit the exception name(s), to serve as a +wildcard. Use this with extreme caution, since it is easy to mask a +real programming error in this way! It can also be used to print an +error message and then re-raise the exception (allowing a caller to +handle the exception as well): + +\begin{verbatim} +import sys + +try: + f = open('myfile.txt') + s = f.readline() + i = int(s.strip()) +except IOError, (errno, strerror): + print "I/O error(%s): %s" % (errno, strerror) +except ValueError: + print "Could not convert data to an integer." +except: + print "Unexpected error:", sys.exc_info()[0] + raise +\end{verbatim} + +The \keyword{try} \ldots\ \keyword{except} statement has an optional +\emph{else clause}, which, when present, must follow all except +clauses. It is useful for code that must be executed if the try +clause does not raise an exception. For example: + +\begin{verbatim} +for arg in sys.argv[1:]: + try: + f = open(arg, 'r') + except IOError: + print 'cannot open', arg + else: + print arg, 'has', len(f.readlines()), 'lines' + f.close() +\end{verbatim} + +The use of the \keyword{else} clause is better than adding additional +code to the \keyword{try} clause because it avoids accidentally +catching an exception that wasn't raised by the code being protected +by the \keyword{try} \ldots\ \keyword{except} statement. + + +When an exception occurs, it may have an associated value, also known as +the exception's \emph{argument}. +The presence and type of the argument depend on the exception type. + +The except clause may specify a variable after the exception name (or tuple). +The variable is bound to an exception instance with the arguments stored +in \code{instance.args}. For convenience, the exception instance +defines \method{__getitem__} and \method{__str__} so the arguments can +be accessed or printed directly without having to reference \code{.args}. + +But use of \code{.args} is discouraged. Instead, the preferred use is to pass +a single argument to an exception (which can be a tuple if multiple arguments +are needed) and have it bound to the \code{message} attribute. One may also +instantiate an exception first before raising it and add any attributes to it +as desired. + +\begin{verbatim} +>>> try: +... raise Exception('spam', 'eggs') +... except Exception, inst: +... print type(inst) # the exception instance +... print inst.args # arguments stored in .args +... print inst # __str__ allows args to printed directly +... x, y = inst # __getitem__ allows args to be unpacked directly +... print 'x =', x +... print 'y =', y +... +<type 'instance'> +('spam', 'eggs') +('spam', 'eggs') +x = spam +y = eggs +\end{verbatim} + +If an exception has an argument, it is printed as the last part +(`detail') of the message for unhandled exceptions. + +Exception handlers don't just handle exceptions if they occur +immediately in the try clause, but also if they occur inside functions +that are called (even indirectly) in the try clause. +For example: + +\begin{verbatim} +>>> def this_fails(): +... x = 1/0 +... +>>> try: +... this_fails() +... except ZeroDivisionError, detail: +... print 'Handling run-time error:', detail +... +Handling run-time error: integer division or modulo by zero +\end{verbatim} + + +\section{Raising Exceptions \label{raising}} + +The \keyword{raise} statement allows the programmer to force a +specified exception to occur. +For example: + +\begin{verbatim} +>>> raise NameError, 'HiThere' +Traceback (most recent call last): + File "<stdin>", line 1, in ? +NameError: HiThere +\end{verbatim} + +The first argument to \keyword{raise} names the exception to be +raised. The optional second argument specifies the exception's +argument. Alternatively, the above could be written as +\code{raise NameError('HiThere')}. Either form works fine, but there +seems to be a growing stylistic preference for the latter. + +If you need to determine whether an exception was raised but don't +intend to handle it, a simpler form of the \keyword{raise} statement +allows you to re-raise the exception: + +\begin{verbatim} +>>> try: +... raise NameError, 'HiThere' +... except NameError: +... print 'An exception flew by!' +... raise +... +An exception flew by! +Traceback (most recent call last): + File "<stdin>", line 2, in ? +NameError: HiThere +\end{verbatim} + + +\section{User-defined Exceptions \label{userExceptions}} + +Programs may name their own exceptions by creating a new exception +class. Exceptions should typically be derived from the +\exception{Exception} class, either directly or indirectly. For +example: + +\begin{verbatim} +>>> class MyError(Exception): +... def __init__(self, value): +... self.value = value +... def __str__(self): +... return repr(self.value) +... +>>> try: +... raise MyError(2*2) +... except MyError, e: +... print 'My exception occurred, value:', e.value +... +My exception occurred, value: 4 +>>> raise MyError, 'oops!' +Traceback (most recent call last): + File "<stdin>", line 1, in ? +__main__.MyError: 'oops!' +\end{verbatim} + +In this example, the default \method{__init__} of \class{Exception} +has been overridden. The new behavior simply creates the \var{value} +attribute. This replaces the default behavior of creating the +\var{args} attribute. + +Exception classes can be defined which do anything any other class can +do, but are usually kept simple, often only offering a number of +attributes that allow information about the error to be extracted by +handlers for the exception. When creating a module that can raise +several distinct errors, a common practice is to create a base class +for exceptions defined by that module, and subclass that to create +specific exception classes for different error conditions: + +\begin{verbatim} +class Error(Exception): + """Base class for exceptions in this module.""" + pass + +class InputError(Error): + """Exception raised for errors in the input. + + Attributes: + expression -- input expression in which the error occurred + message -- explanation of the error + """ + + def __init__(self, expression, message): + self.expression = expression + self.message = message + +class TransitionError(Error): + """Raised when an operation attempts a state transition that's not + allowed. + + Attributes: + previous -- state at beginning of transition + next -- attempted new state + message -- explanation of why the specific transition is not allowed + """ + + def __init__(self, previous, next, message): + self.previous = previous + self.next = next + self.message = message +\end{verbatim} + +Most exceptions are defined with names that end in ``Error,'' similar +to the naming of the standard exceptions. + +Many standard modules define their own exceptions to report errors +that may occur in functions they define. More information on classes +is presented in chapter \ref{classes}, ``Classes.'' + + +\section{Defining Clean-up Actions \label{cleanup}} + +The \keyword{try} statement has another optional clause which is +intended to define clean-up actions that must be executed under all +circumstances. For example: + +\begin{verbatim} +>>> try: +... raise KeyboardInterrupt +... finally: +... print 'Goodbye, world!' +... +Goodbye, world! +Traceback (most recent call last): + File "<stdin>", line 2, in ? +KeyboardInterrupt +\end{verbatim} + +A \emph{finally clause} is always executed before leaving the +\keyword{try} statement, whether an exception has occurred or not. +When an exception has occurred in the \keyword{try} clause and has not +been handled by an \keyword{except} clause (or it has occurred in a +\keyword{except} or \keyword{else} clause), it is re-raised after the +\keyword{finally} clause has been executed. The \keyword{finally} clause +is also executed ``on the way out'' when any other clause of the +\keyword{try} statement is left via a \keyword{break}, \keyword{continue} +or \keyword{return} statement. A more complicated example: + +\begin{verbatim} +>>> def divide(x, y): +... try: +... result = x / y +... except ZeroDivisionError: +... print "division by zero!" +... else: +... print "result is", result +... finally: +... print "executing finally clause" +... +>>> divide(2, 1) +result is 2 +executing finally clause +>>> divide(2, 0) +division by zero! +executing finally clause +>>> divide("2", "1") +executing finally clause +Traceback (most recent call last): + File "<stdin>", line 1, in ? + File "<stdin>", line 3, in divide +TypeError: unsupported operand type(s) for /: 'str' and 'str' +\end{verbatim} + +As you can see, the \keyword{finally} clause is executed in any +event. The \exception{TypeError} raised by dividing two strings +is not handled by the \keyword{except} clause and therefore +re-raised after the \keyword{finally} clauses has been executed. + +In real world applications, the \keyword{finally} clause is useful +for releasing external resources (such as files or network connections), +regardless of whether the use of the resource was successful. + + +\section{Predefined Clean-up Actions \label{cleanup-with}} + +Some objects define standard clean-up actions to be undertaken when +the object is no longer needed, regardless of whether or not the +operation using the object succeeded or failed. +Look at the following example, which tries to open a file and print +its contents to the screen. + +\begin{verbatim} +for line in open("myfile.txt"): + print line +\end{verbatim} + +The problem with this code is that it leaves the file open for an +indeterminate amount of time after the code has finished executing. +This is not an issue in simple scripts, but can be a problem for +larger applications. The \keyword{with} statement allows +objects like files to be used in a way that ensures they are +always cleaned up promptly and correctly. + +\begin{verbatim} +with open("myfile.txt") as f: + for line in f: + print line +\end{verbatim} + +After the statement is executed, the file \var{f} is always closed, +even if a problem was encountered while processing the lines. Other +objects which provide predefined clean-up actions will indicate +this in their documentation. + + +\chapter{Classes \label{classes}} + +Python's class mechanism adds classes to the language with a minimum +of new syntax and semantics. It is a mixture of the class mechanisms +found in \Cpp{} and Modula-3. As is true for modules, classes in Python +do not put an absolute barrier between definition and user, but rather +rely on the politeness of the user not to ``break into the +definition.'' The most important features of classes are retained +with full power, however: the class inheritance mechanism allows +multiple base classes, a derived class can override any methods of its +base class or classes, and a method can call the method of a base class with the +same name. Objects can contain an arbitrary amount of private data. + +In \Cpp{} terminology, all class members (including the data members) are +\emph{public}, and all member functions are \emph{virtual}. There are +no special constructors or destructors. As in Modula-3, there are no +shorthands for referencing the object's members from its methods: the +method function is declared with an explicit first argument +representing the object, which is provided implicitly by the call. As +in Smalltalk, classes themselves are objects, albeit in the wider +sense of the word: in Python, all data types are objects. This +provides semantics for importing and renaming. Unlike +\Cpp{} and Modula-3, built-in types can be used as base classes for +extension by the user. Also, like in \Cpp{} but unlike in Modula-3, most +built-in operators with special syntax (arithmetic operators, +subscripting etc.) can be redefined for class instances. + +\section{A Word About Terminology \label{terminology}} + +Lacking universally accepted terminology to talk about classes, I will +make occasional use of Smalltalk and \Cpp{} terms. (I would use Modula-3 +terms, since its object-oriented semantics are closer to those of +Python than \Cpp, but I expect that few readers have heard of it.) + +Objects have individuality, and multiple names (in multiple scopes) +can be bound to the same object. This is known as aliasing in other +languages. This is usually not appreciated on a first glance at +Python, and can be safely ignored when dealing with immutable basic +types (numbers, strings, tuples). However, aliasing has an +(intended!) effect on the semantics of Python code involving mutable +objects such as lists, dictionaries, and most types representing +entities outside the program (files, windows, etc.). This is usually +used to the benefit of the program, since aliases behave like pointers +in some respects. For example, passing an object is cheap since only +a pointer is passed by the implementation; and if a function modifies +an object passed as an argument, the caller will see the change --- this +eliminates the need for two different argument passing mechanisms as in +Pascal. + + +\section{Python Scopes and Name Spaces \label{scopes}} + +Before introducing classes, I first have to tell you something about +Python's scope rules. Class definitions play some neat tricks with +namespaces, and you need to know how scopes and namespaces work to +fully understand what's going on. Incidentally, knowledge about this +subject is useful for any advanced Python programmer. + +Let's begin with some definitions. + +A \emph{namespace} is a mapping from names to objects. Most +namespaces are currently implemented as Python dictionaries, but +that's normally not noticeable in any way (except for performance), +and it may change in the future. Examples of namespaces are: the set +of built-in names (functions such as \function{abs()}, and built-in +exception names); the global names in a module; and the local names in +a function invocation. In a sense the set of attributes of an object +also form a namespace. The important thing to know about namespaces +is that there is absolutely no relation between names in different +namespaces; for instance, two different modules may both define a +function ``maximize'' without confusion --- users of the modules must +prefix it with the module name. + +By the way, I use the word \emph{attribute} for any name following a +dot --- for example, in the expression \code{z.real}, \code{real} is +an attribute of the object \code{z}. Strictly speaking, references to +names in modules are attribute references: in the expression +\code{modname.funcname}, \code{modname} is a module object and +\code{funcname} is an attribute of it. In this case there happens to +be a straightforward mapping between the module's attributes and the +global names defined in the module: they share the same namespace! +\footnote{ + Except for one thing. Module objects have a secret read-only + attribute called \member{__dict__} which returns the dictionary + used to implement the module's namespace; the name + \member{__dict__} is an attribute but not a global name. + Obviously, using this violates the abstraction of namespace + implementation, and should be restricted to things like + post-mortem debuggers. +} + +Attributes may be read-only or writable. In the latter case, +assignment to attributes is possible. Module attributes are writable: +you can write \samp{modname.the_answer = 42}. Writable attributes may +also be deleted with the \keyword{del} statement. For example, +\samp{del modname.the_answer} will remove the attribute +\member{the_answer} from the object named by \code{modname}. + +Name spaces are created at different moments and have different +lifetimes. The namespace containing the built-in names is created +when the Python interpreter starts up, and is never deleted. The +global namespace for a module is created when the module definition +is read in; normally, module namespaces also last until the +interpreter quits. The statements executed by the top-level +invocation of the interpreter, either read from a script file or +interactively, are considered part of a module called +\module{__main__}, so they have their own global namespace. (The +built-in names actually also live in a module; this is called +\module{__builtin__}.) + +The local namespace for a function is created when the function is +called, and deleted when the function returns or raises an exception +that is not handled within the function. (Actually, forgetting would +be a better way to describe what actually happens.) Of course, +recursive invocations each have their own local namespace. + +A \emph{scope} is a textual region of a Python program where a +namespace is directly accessible. ``Directly accessible'' here means +that an unqualified reference to a name attempts to find the name in +the namespace. + +Although scopes are determined statically, they are used dynamically. +At any time during execution, there are at least three nested scopes whose +namespaces are directly accessible: the innermost scope, which is searched +first, contains the local names; the namespaces of any enclosing +functions, which are searched starting with the nearest enclosing scope; +the middle scope, searched next, contains the current module's global names; +and the outermost scope (searched last) is the namespace containing built-in +names. + +If a name is declared global, then all references and assignments go +directly to the middle scope containing the module's global names. +Otherwise, all variables found outside of the innermost scope are read-only +(an attempt to write to such a variable will simply create a \emph{new} +local variable in the innermost scope, leaving the identically named +outer variable unchanged). + +Usually, the local scope references the local names of the (textually) +current function. Outside functions, the local scope references +the same namespace as the global scope: the module's namespace. +Class definitions place yet another namespace in the local scope. + +It is important to realize that scopes are determined textually: the +global scope of a function defined in a module is that module's +namespace, no matter from where or by what alias the function is +called. On the other hand, the actual search for names is done +dynamically, at run time --- however, the language definition is +evolving towards static name resolution, at ``compile'' time, so don't +rely on dynamic name resolution! (In fact, local variables are +already determined statically.) + +A special quirk of Python is that assignments always go into the +innermost scope. Assignments do not copy data --- they just +bind names to objects. The same is true for deletions: the statement +\samp{del x} removes the binding of \code{x} from the namespace +referenced by the local scope. In fact, all operations that introduce +new names use the local scope: in particular, import statements and +function definitions bind the module or function name in the local +scope. (The \keyword{global} statement can be used to indicate that +particular variables live in the global scope.) + + +\section{A First Look at Classes \label{firstClasses}} + +Classes introduce a little bit of new syntax, three new object types, +and some new semantics. + + +\subsection{Class Definition Syntax \label{classDefinition}} + +The simplest form of class definition looks like this: + +\begin{verbatim} +class ClassName: + <statement-1> + . + . + . + <statement-N> +\end{verbatim} + +Class definitions, like function definitions +(\keyword{def} statements) must be executed before they have any +effect. (You could conceivably place a class definition in a branch +of an \keyword{if} statement, or inside a function.) + +In practice, the statements inside a class definition will usually be +function definitions, but other statements are allowed, and sometimes +useful --- we'll come back to this later. The function definitions +inside a class normally have a peculiar form of argument list, +dictated by the calling conventions for methods --- again, this is +explained later. + +When a class definition is entered, a new namespace is created, and +used as the local scope --- thus, all assignments to local variables +go into this new namespace. In particular, function definitions bind +the name of the new function here. + +When a class definition is left normally (via the end), a \emph{class +object} is created. This is basically a wrapper around the contents +of the namespace created by the class definition; we'll learn more +about class objects in the next section. The original local scope +(the one in effect just before the class definition was entered) is +reinstated, and the class object is bound here to the class name given +in the class definition header (\class{ClassName} in the example). + + +\subsection{Class Objects \label{classObjects}} + +Class objects support two kinds of operations: attribute references +and instantiation. + +\emph{Attribute references} use the standard syntax used for all +attribute references in Python: \code{obj.name}. Valid attribute +names are all the names that were in the class's namespace when the +class object was created. So, if the class definition looked like +this: + +\begin{verbatim} +class MyClass: + "A simple example class" + i = 12345 + def f(self): + return 'hello world' +\end{verbatim} + +then \code{MyClass.i} and \code{MyClass.f} are valid attribute +references, returning an integer and a function object, respectively. +Class attributes can also be assigned to, so you can change the value +of \code{MyClass.i} by assignment. \member{__doc__} is also a valid +attribute, returning the docstring belonging to the class: \code{"A +simple example class"}. + +Class \emph{instantiation} uses function notation. Just pretend that +the class object is a parameterless function that returns a new +instance of the class. For example (assuming the above class): + +\begin{verbatim} +x = MyClass() +\end{verbatim} + +creates a new \emph{instance} of the class and assigns this object to +the local variable \code{x}. + +The instantiation operation (``calling'' a class object) creates an +empty object. Many classes like to create objects with instances +customized to a specific initial state. +Therefore a class may define a special method named +\method{__init__()}, like this: + +\begin{verbatim} + def __init__(self): + self.data = [] +\end{verbatim} + +When a class defines an \method{__init__()} method, class +instantiation automatically invokes \method{__init__()} for the +newly-created class instance. So in this example, a new, initialized +instance can be obtained by: + +\begin{verbatim} +x = MyClass() +\end{verbatim} + +Of course, the \method{__init__()} method may have arguments for +greater flexibility. In that case, arguments given to the class +instantiation operator are passed on to \method{__init__()}. For +example, + +\begin{verbatim} +>>> class Complex: +... def __init__(self, realpart, imagpart): +... self.r = realpart +... self.i = imagpart +... +>>> x = Complex(3.0, -4.5) +>>> x.r, x.i +(3.0, -4.5) +\end{verbatim} + + +\subsection{Instance Objects \label{instanceObjects}} + +Now what can we do with instance objects? The only operations +understood by instance objects are attribute references. There are +two kinds of valid attribute names, data attributes and methods. + +\emph{data attributes} correspond to +``instance variables'' in Smalltalk, and to ``data members'' in +\Cpp. Data attributes need not be declared; like local variables, +they spring into existence when they are first assigned to. For +example, if \code{x} is the instance of \class{MyClass} created above, +the following piece of code will print the value \code{16}, without +leaving a trace: + +\begin{verbatim} +x.counter = 1 +while x.counter < 10: + x.counter = x.counter * 2 +print x.counter +del x.counter +\end{verbatim} + +The other kind of instance attribute reference is a \emph{method}. +A method is a function that ``belongs to'' an +object. (In Python, the term method is not unique to class instances: +other object types can have methods as well. For example, list objects have +methods called append, insert, remove, sort, and so on. However, +in the following discussion, we'll use the term method exclusively to mean +methods of class instance objects, unless explicitly stated otherwise.) + +Valid method names of an instance object depend on its class. By +definition, all attributes of a class that are function +objects define corresponding methods of its instances. So in our +example, \code{x.f} is a valid method reference, since +\code{MyClass.f} is a function, but \code{x.i} is not, since +\code{MyClass.i} is not. But \code{x.f} is not the same thing as +\code{MyClass.f} --- it is a \obindex{method}\emph{method object}, not +a function object. + + +\subsection{Method Objects \label{methodObjects}} + +Usually, a method is called right after it is bound: + +\begin{verbatim} +x.f() +\end{verbatim} + +In the \class{MyClass} example, this will return the string \code{'hello world'}. +However, it is not necessary to call a method right away: +\code{x.f} is a method object, and can be stored away and called at a +later time. For example: + +\begin{verbatim} +xf = x.f +while True: + print xf() +\end{verbatim} + +will continue to print \samp{hello world} until the end of time. + +What exactly happens when a method is called? You may have noticed +that \code{x.f()} was called without an argument above, even though +the function definition for \method{f} specified an argument. What +happened to the argument? Surely Python raises an exception when a +function that requires an argument is called without any --- even if +the argument isn't actually used... + +Actually, you may have guessed the answer: the special thing about +methods is that the object is passed as the first argument of the +function. In our example, the call \code{x.f()} is exactly equivalent +to \code{MyClass.f(x)}. In general, calling a method with a list of +\var{n} arguments is equivalent to calling the corresponding function +with an argument list that is created by inserting the method's object +before the first argument. + +If you still don't understand how methods work, a look at the +implementation can perhaps clarify matters. When an instance +attribute is referenced that isn't a data attribute, its class is +searched. If the name denotes a valid class attribute that is a +function object, a method object is created by packing (pointers to) +the instance object and the function object just found together in an +abstract object: this is the method object. When the method object is +called with an argument list, it is unpacked again, a new argument +list is constructed from the instance object and the original argument +list, and the function object is called with this new argument list. + + +\section{Random Remarks \label{remarks}} + +% [These should perhaps be placed more carefully...] + + +Data attributes override method attributes with the same name; to +avoid accidental name conflicts, which may cause hard-to-find bugs in +large programs, it is wise to use some kind of convention that +minimizes the chance of conflicts. Possible conventions include +capitalizing method names, prefixing data attribute names with a small +unique string (perhaps just an underscore), or using verbs for methods +and nouns for data attributes. + + +Data attributes may be referenced by methods as well as by ordinary +users (``clients'') of an object. In other words, classes are not +usable to implement pure abstract data types. In fact, nothing in +Python makes it possible to enforce data hiding --- it is all based +upon convention. (On the other hand, the Python implementation, +written in C, can completely hide implementation details and control +access to an object if necessary; this can be used by extensions to +Python written in C.) + + +Clients should use data attributes with care --- clients may mess up +invariants maintained by the methods by stamping on their data +attributes. Note that clients may add data attributes of their own to +an instance object without affecting the validity of the methods, as +long as name conflicts are avoided --- again, a naming convention can +save a lot of headaches here. + + +There is no shorthand for referencing data attributes (or other +methods!) from within methods. I find that this actually increases +the readability of methods: there is no chance of confusing local +variables and instance variables when glancing through a method. + + +Often, the first argument of a method is called +\code{self}. This is nothing more than a convention: the name +\code{self} has absolutely no special meaning to Python. (Note, +however, that by not following the convention your code may be less +readable to other Python programmers, and it is also conceivable that +a \emph{class browser} program might be written that relies upon such a +convention.) + + +Any function object that is a class attribute defines a method for +instances of that class. It is not necessary that the function +definition is textually enclosed in the class definition: assigning a +function object to a local variable in the class is also ok. For +example: + +\begin{verbatim} +# Function defined outside the class +def f1(self, x, y): + return min(x, x+y) + +class C: + f = f1 + def g(self): + return 'hello world' + h = g +\end{verbatim} + +Now \code{f}, \code{g} and \code{h} are all attributes of class +\class{C} that refer to function objects, and consequently they are all +methods of instances of \class{C} --- \code{h} being exactly equivalent +to \code{g}. Note that this practice usually only serves to confuse +the reader of a program. + + +Methods may call other methods by using method attributes of the +\code{self} argument: + +\begin{verbatim} +class Bag: + def __init__(self): + self.data = [] + def add(self, x): + self.data.append(x) + def addtwice(self, x): + self.add(x) + self.add(x) +\end{verbatim} + +Methods may reference global names in the same way as ordinary +functions. The global scope associated with a method is the module +containing the class definition. (The class itself is never used as a +global scope!) While one rarely encounters a good reason for using +global data in a method, there are many legitimate uses of the global +scope: for one thing, functions and modules imported into the global +scope can be used by methods, as well as functions and classes defined +in it. Usually, the class containing the method is itself defined in +this global scope, and in the next section we'll find some good +reasons why a method would want to reference its own class! + + +\section{Inheritance \label{inheritance}} + +Of course, a language feature would not be worthy of the name ``class'' +without supporting inheritance. The syntax for a derived class +definition looks like this: + +\begin{verbatim} +class DerivedClassName(BaseClassName): + <statement-1> + . + . + . + <statement-N> +\end{verbatim} + +The name \class{BaseClassName} must be defined in a scope containing +the derived class definition. In place of a base class name, other +arbitrary expressions are also allowed. This can be useful, for +example, when the base class is defined in another module: + +\begin{verbatim} +class DerivedClassName(modname.BaseClassName): +\end{verbatim} + +Execution of a derived class definition proceeds the same as for a +base class. When the class object is constructed, the base class is +remembered. This is used for resolving attribute references: if a +requested attribute is not found in the class, the search proceeds to look in the +base class. This rule is applied recursively if the base class itself +is derived from some other class. + +There's nothing special about instantiation of derived classes: +\code{DerivedClassName()} creates a new instance of the class. Method +references are resolved as follows: the corresponding class attribute +is searched, descending down the chain of base classes if necessary, +and the method reference is valid if this yields a function object. + +Derived classes may override methods of their base classes. Because +methods have no special privileges when calling other methods of the +same object, a method of a base class that calls another method +defined in the same base class may end up calling a method of +a derived class that overrides it. (For \Cpp{} programmers: all methods +in Python are effectively \keyword{virtual}.) + +An overriding method in a derived class may in fact want to extend +rather than simply replace the base class method of the same name. +There is a simple way to call the base class method directly: just +call \samp{BaseClassName.methodname(self, arguments)}. This is +occasionally useful to clients as well. (Note that this only works if +the base class is defined or imported directly in the global scope.) + + +\subsection{Multiple Inheritance \label{multiple}} + +Python supports a limited form of multiple inheritance as well. A +class definition with multiple base classes looks like this: + +\begin{verbatim} +class DerivedClassName(Base1, Base2, Base3): + <statement-1> + . + . + . + <statement-N> +\end{verbatim} + +For old-style classes, the only rule is depth-first, +left-to-right. Thus, if an attribute is not found in +\class{DerivedClassName}, it is searched in \class{Base1}, then +(recursively) in the base classes of \class{Base1}, and only if it is +not found there, it is searched in \class{Base2}, and so on. + +(To some people breadth first --- searching \class{Base2} and +\class{Base3} before the base classes of \class{Base1} --- looks more +natural. However, this would require you to know whether a particular +attribute of \class{Base1} is actually defined in \class{Base1} or in +one of its base classes before you can figure out the consequences of +a name conflict with an attribute of \class{Base2}. The depth-first +rule makes no differences between direct and inherited attributes of +\class{Base1}.) + +For new-style classes, the method resolution order changes dynamically +to support cooperative calls to \function{super()}. This approach +is known in some other multiple-inheritance languages as call-next-method +and is more powerful than the super call found in single-inheritance languages. + +With new-style classes, dynamic ordering is necessary because all +cases of multiple inheritance exhibit one or more diamond relationships +(where one at least one of the parent classes can be accessed through +multiple paths from the bottommost class). For example, all new-style +classes inherit from \class{object}, so any case of multiple inheritance +provides more than one path to reach \class{object}. To keep the +base classes from being accessed more than once, the dynamic algorithm +linearizes the search order in a way that preserves the left-to-right +ordering specified in each class, that calls each parent only once, and +that is monotonic (meaning that a class can be subclassed without affecting +the precedence order of its parents). Taken together, these properties +make it possible to design reliable and extensible classes with +multiple inheritance. For more detail, see +\url{http://www.python.org/download/releases/2.3/mro/}. + + +\section{Private Variables \label{private}} + +There is limited support for class-private +identifiers. Any identifier of the form \code{__spam} (at least two +leading underscores, at most one trailing underscore) is textually +replaced with \code{_classname__spam}, where \code{classname} is the +current class name with leading underscore(s) stripped. This mangling +is done without regard to the syntactic position of the identifier, so +it can be used to define class-private instance and class variables, +methods, variables stored in globals, and even variables stored in instances. +private to this class on instances of \emph{other} classes. Truncation +may occur when the mangled name would be longer than 255 characters. +Outside classes, or when the class name consists of only underscores, +no mangling occurs. + +Name mangling is intended to give classes an easy way to define +``private'' instance variables and methods, without having to worry +about instance variables defined by derived classes, or mucking with +instance variables by code outside the class. Note that the mangling +rules are designed mostly to avoid accidents; it still is possible for +a determined soul to access or modify a variable that is considered +private. This can even be useful in special circumstances, such as in +the debugger, and that's one reason why this loophole is not closed. +(Buglet: derivation of a class with the same name as the base class +makes use of private variables of the base class possible.) + +Notice that code passed to \code{exec}, \code{eval()} or +\code{execfile()} does not consider the classname of the invoking +class to be the current class; this is similar to the effect of the +\code{global} statement, the effect of which is likewise restricted to +code that is byte-compiled together. The same restriction applies to +\code{getattr()}, \code{setattr()} and \code{delattr()}, as well as +when referencing \code{__dict__} directly. + + +\section{Odds and Ends \label{odds}} + +Sometimes it is useful to have a data type similar to the Pascal +``record'' or C ``struct'', bundling together a few named data +items. An empty class definition will do nicely: + +\begin{verbatim} +class Employee: + pass + +john = Employee() # Create an empty employee record + +# Fill the fields of the record +john.name = 'John Doe' +john.dept = 'computer lab' +john.salary = 1000 +\end{verbatim} + +A piece of Python code that expects a particular abstract data type +can often be passed a class that emulates the methods of that data +type instead. For instance, if you have a function that formats some +data from a file object, you can define a class with methods +\method{read()} and \method{readline()} that get the data from a string +buffer instead, and pass it as an argument.% (Unfortunately, this +%technique has its limitations: a class can't define operations that +%are accessed by special syntax such as sequence subscripting or +%arithmetic operators, and assigning such a ``pseudo-file'' to +%\code{sys.stdin} will not cause the interpreter to read further input +%from it.) + + +Instance method objects have attributes, too: \code{m.im_self} is the +instance object with the method \method{m}, and \code{m.im_func} is the +function object corresponding to the method. + + +\section{Exceptions Are Classes Too\label{exceptionClasses}} + +User-defined exceptions are identified by classes as well. Using this +mechanism it is possible to create extensible hierarchies of exceptions. + +There are two new valid (semantic) forms for the raise statement: + +\begin{verbatim} +raise Class, instance + +raise instance +\end{verbatim} + +In the first form, \code{instance} must be an instance of +\class{Class} or of a class derived from it. The second form is a +shorthand for: + +\begin{verbatim} +raise instance.__class__, instance +\end{verbatim} + +A class in an except clause is compatible with an exception if it is the same +class or a base class thereof (but not the other way around --- an +except clause listing a derived class is not compatible with a base +class). For example, the following code will print B, C, D in that +order: + +\begin{verbatim} +class B: + pass +class C(B): + pass +class D(C): + pass + +for c in [B, C, D]: + try: + raise c() + except D: + print "D" + except C: + print "C" + except B: + print "B" +\end{verbatim} + +Note that if the except clauses were reversed (with +\samp{except B} first), it would have printed B, B, B --- the first +matching except clause is triggered. + +When an error message is printed for an unhandled exception, the +exception's class name is printed, then a colon and a space, and +finally the instance converted to a string using the built-in function +\function{str()}. + + +\section{Iterators\label{iterators}} + +By now you have probably noticed that most container objects can be looped +over using a \keyword{for} statement: + +\begin{verbatim} +for element in [1, 2, 3]: + print element +for element in (1, 2, 3): + print element +for key in {'one':1, 'two':2}: + print key +for char in "123": + print char +for line in open("myfile.txt"): + print line +\end{verbatim} + +This style of access is clear, concise, and convenient. The use of iterators +pervades and unifies Python. Behind the scenes, the \keyword{for} +statement calls \function{iter()} on the container object. The +function returns an iterator object that defines the method +\method{next()} which accesses elements in the container one at a +time. When there are no more elements, \method{next()} raises a +\exception{StopIteration} exception which tells the \keyword{for} loop +to terminate. This example shows how it all works: + +\begin{verbatim} +>>> s = 'abc' +>>> it = iter(s) +>>> it +<iterator object at 0x00A1DB50> +>>> it.next() +'a' +>>> it.next() +'b' +>>> it.next() +'c' +>>> it.next() + +Traceback (most recent call last): + File "<stdin>", line 1, in ? + it.next() +StopIteration +\end{verbatim} + +Having seen the mechanics behind the iterator protocol, it is easy to add +iterator behavior to your classes. Define a \method{__iter__()} method +which returns an object with a \method{next()} method. If the class defines +\method{next()}, then \method{__iter__()} can just return \code{self}: + +\begin{verbatim} +class Reverse: + "Iterator for looping over a sequence backwards" + def __init__(self, data): + self.data = data + self.index = len(data) + def __iter__(self): + return self + def next(self): + if self.index == 0: + raise StopIteration + self.index = self.index - 1 + return self.data[self.index] + +>>> for char in Reverse('spam'): +... print char +... +m +a +p +s +\end{verbatim} + + +\section{Generators\label{generators}} + +Generators are a simple and powerful tool for creating iterators. They are +written like regular functions but use the \keyword{yield} statement whenever +they want to return data. Each time \method{next()} is called, the +generator resumes where it left-off (it remembers all the data values and +which statement was last executed). An example shows that generators can +be trivially easy to create: + +\begin{verbatim} +def reverse(data): + for index in range(len(data)-1, -1, -1): + yield data[index] + +>>> for char in reverse('golf'): +... print char +... +f +l +o +g +\end{verbatim} + +Anything that can be done with generators can also be done with class based +iterators as described in the previous section. What makes generators so +compact is that the \method{__iter__()} and \method{next()} methods are +created automatically. + +Another key feature is that the local variables and execution state +are automatically saved between calls. This made the function easier to write +and much more clear than an approach using instance variables like +\code{self.index} and \code{self.data}. + +In addition to automatic method creation and saving program state, when +generators terminate, they automatically raise \exception{StopIteration}. +In combination, these features make it easy to create iterators with no +more effort than writing a regular function. + +\section{Generator Expressions\label{genexps}} + +Some simple generators can be coded succinctly as expressions using a syntax +similar to list comprehensions but with parentheses instead of brackets. These +expressions are designed for situations where the generator is used right +away by an enclosing function. Generator expressions are more compact but +less versatile than full generator definitions and tend to be more memory +friendly than equivalent list comprehensions. + +Examples: + +\begin{verbatim} +>>> sum(i*i for i in range(10)) # sum of squares +285 + +>>> xvec = [10, 20, 30] +>>> yvec = [7, 5, 3] +>>> sum(x*y for x,y in zip(xvec, yvec)) # dot product +260 + +>>> from math import pi, sin +>>> sine_table = dict((x, sin(x*pi/180)) for x in range(0, 91)) + +>>> unique_words = set(word for line in page for word in line.split()) + +>>> valedictorian = max((student.gpa, student.name) for student in graduates) + +>>> data = 'golf' +>>> list(data[i] for i in range(len(data)-1,-1,-1)) +['f', 'l', 'o', 'g'] + +\end{verbatim} + + + +\chapter{Brief Tour of the Standard Library \label{briefTour}} + + +\section{Operating System Interface\label{os-interface}} + +The \ulink{\module{os}}{../lib/module-os.html} +module provides dozens of functions for interacting with the +operating system: + +\begin{verbatim} +>>> import os +>>> os.system('time 0:02') +0 +>>> os.getcwd() # Return the current working directory +'C:\\Python24' +>>> os.chdir('/server/accesslogs') +\end{verbatim} + +Be sure to use the \samp{import os} style instead of +\samp{from os import *}. This will keep \function{os.open()} from +shadowing the builtin \function{open()} function which operates much +differently. + +\bifuncindex{help} +The builtin \function{dir()} and \function{help()} functions are useful +as interactive aids for working with large modules like \module{os}: + +\begin{verbatim} +>>> import os +>>> dir(os) +<returns a list of all module functions> +>>> help(os) +<returns an extensive manual page created from the module's docstrings> +\end{verbatim} + +For daily file and directory management tasks, the +\ulink{\module{shutil}}{../lib/module-shutil.html} +module provides a higher level interface that is easier to use: + +\begin{verbatim} +>>> import shutil +>>> shutil.copyfile('data.db', 'archive.db') +>>> shutil.move('/build/executables', 'installdir') +\end{verbatim} + + +\section{File Wildcards\label{file-wildcards}} + +The \ulink{\module{glob}}{../lib/module-glob.html} +module provides a function for making file lists from directory +wildcard searches: + +\begin{verbatim} +>>> import glob +>>> glob.glob('*.py') +['primes.py', 'random.py', 'quote.py'] +\end{verbatim} + + +\section{Command Line Arguments\label{command-line-arguments}} + +Common utility scripts often need to process command line arguments. +These arguments are stored in the +\ulink{\module{sys}}{../lib/module-sys.html}\ module's \var{argv} +attribute as a list. For instance the following output results from +running \samp{python demo.py one two three} at the command line: + +\begin{verbatim} +>>> import sys +>>> print sys.argv +['demo.py', 'one', 'two', 'three'] +\end{verbatim} + +The \ulink{\module{getopt}}{../lib/module-getopt.html} +module processes \var{sys.argv} using the conventions of the \UNIX{} +\function{getopt()} function. More powerful and flexible command line +processing is provided by the +\ulink{\module{optparse}}{../lib/module-optparse.html} module. + + +\section{Error Output Redirection and Program Termination\label{stderr}} + +The \ulink{\module{sys}}{../lib/module-sys.html} +module also has attributes for \var{stdin}, \var{stdout}, and +\var{stderr}. The latter is useful for emitting warnings and error +messages to make them visible even when \var{stdout} has been redirected: + +\begin{verbatim} +>>> sys.stderr.write('Warning, log file not found starting a new one\n') +Warning, log file not found starting a new one +\end{verbatim} + +The most direct way to terminate a script is to use \samp{sys.exit()}. + + +\section{String Pattern Matching\label{string-pattern-matching}} + +The \ulink{\module{re}}{../lib/module-re.html} +module provides regular expression tools for advanced string processing. +For complex matching and manipulation, regular expressions offer succinct, +optimized solutions: + +\begin{verbatim} +>>> import re +>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest') +['foot', 'fell', 'fastest'] +>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat') +'cat in the hat' +\end{verbatim} + +When only simple capabilities are needed, string methods are preferred +because they are easier to read and debug: + +\begin{verbatim} +>>> 'tea for too'.replace('too', 'two') +'tea for two' +\end{verbatim} + +\section{Mathematics\label{mathematics}} + +The \ulink{\module{math}}{../lib/module-math.html} module gives +access to the underlying C library functions for floating point math: + +\begin{verbatim} +>>> import math +>>> math.cos(math.pi / 4.0) +0.70710678118654757 +>>> math.log(1024, 2) +10.0 +\end{verbatim} + +The \ulink{\module{random}}{../lib/module-random.html} +module provides tools for making random selections: + +\begin{verbatim} +>>> import random +>>> random.choice(['apple', 'pear', 'banana']) +'apple' +>>> random.sample(xrange(100), 10) # sampling without replacement +[30, 83, 16, 4, 8, 81, 41, 50, 18, 33] +>>> random.random() # random float +0.17970987693706186 +>>> random.randrange(6) # random integer chosen from range(6) +4 +\end{verbatim} + + +\section{Internet Access\label{internet-access}} + +There are a number of modules for accessing the internet and processing +internet protocols. Two of the simplest are +\ulink{\module{urllib2}}{../lib/module-urllib2.html} +for retrieving data from urls and +\ulink{\module{smtplib}}{../lib/module-smtplib.html} +for sending mail: + +\begin{verbatim} +>>> import urllib2 +>>> for line in urllib2.urlopen('http://tycho.usno.navy.mil/cgi-bin/timer.pl'): +... if 'EST' in line or 'EDT' in line: # look for Eastern Time +... print line + +<BR>Nov. 25, 09:43:32 PM EST + +>>> import smtplib +>>> server = smtplib.SMTP('localhost') +>>> server.sendmail('soothsayer@example.org', 'jcaesar@example.org', +"""To: jcaesar@example.org +From: soothsayer@example.org + +Beware the Ides of March. +""") +>>> server.quit() +\end{verbatim} + + +\section{Dates and Times\label{dates-and-times}} + +The \ulink{\module{datetime}}{../lib/module-datetime.html} module +supplies classes for manipulating dates and times in both simple +and complex ways. While date and time arithmetic is supported, the +focus of the implementation is on efficient member extraction for +output formatting and manipulation. The module also supports objects +that are timezone aware. + +\begin{verbatim} +# dates are easily constructed and formatted +>>> from datetime import date +>>> now = date.today() +>>> now +datetime.date(2003, 12, 2) +>>> now.strftime("%m-%d-%y. %d %b %Y is a %A on the %d day of %B.") +'12-02-03. 02 Dec 2003 is a Tuesday on the 02 day of December.' + +# dates support calendar arithmetic +>>> birthday = date(1964, 7, 31) +>>> age = now - birthday +>>> age.days +14368 +\end{verbatim} + + +\section{Data Compression\label{data-compression}} + +Common data archiving and compression formats are directly supported +by modules including: +\ulink{\module{zlib}}{../lib/module-zlib.html}, +\ulink{\module{gzip}}{../lib/module-gzip.html}, +\ulink{\module{bz2}}{../lib/module-bz2.html}, +\ulink{\module{zipfile}}{../lib/module-zipfile.html}, and +\ulink{\module{tarfile}}{../lib/module-tarfile.html}. + +\begin{verbatim} +>>> import zlib +>>> s = 'witch which has which witches wrist watch' +>>> len(s) +41 +>>> t = zlib.compress(s) +>>> len(t) +37 +>>> zlib.decompress(t) +'witch which has which witches wrist watch' +>>> zlib.crc32(s) +226805979 +\end{verbatim} + + +\section{Performance Measurement\label{performance-measurement}} + +Some Python users develop a deep interest in knowing the relative +performance of different approaches to the same problem. +Python provides a measurement tool that answers those questions +immediately. + +For example, it may be tempting to use the tuple packing and unpacking +feature instead of the traditional approach to swapping arguments. +The \ulink{\module{timeit}}{../lib/module-timeit.html} module +quickly demonstrates a modest performance advantage: + +\begin{verbatim} +>>> from timeit import Timer +>>> Timer('t=a; a=b; b=t', 'a=1; b=2').timeit() +0.57535828626024577 +>>> Timer('a,b = b,a', 'a=1; b=2').timeit() +0.54962537085770791 +\end{verbatim} + +In contrast to \module{timeit}'s fine level of granularity, the +\ulink{\module{profile}}{../lib/module-profile.html} and \module{pstats} +modules provide tools for identifying time critical sections in larger blocks +of code. + + +\section{Quality Control\label{quality-control}} + +One approach for developing high quality software is to write tests for +each function as it is developed and to run those tests frequently during +the development process. + +The \ulink{\module{doctest}}{../lib/module-doctest.html} module provides +a tool for scanning a module and validating tests embedded in a program's +docstrings. Test construction is as simple as cutting-and-pasting a +typical call along with its results into the docstring. This improves +the documentation by providing the user with an example and it allows the +doctest module to make sure the code remains true to the documentation: + +\begin{verbatim} +def average(values): + """Computes the arithmetic mean of a list of numbers. + + >>> print average([20, 30, 70]) + 40.0 + """ + return sum(values, 0.0) / len(values) + +import doctest +doctest.testmod() # automatically validate the embedded tests +\end{verbatim} + +The \ulink{\module{unittest}}{../lib/module-unittest.html} module is not +as effortless as the \module{doctest} module, but it allows a more +comprehensive set of tests to be maintained in a separate file: + +\begin{verbatim} +import unittest + +class TestStatisticalFunctions(unittest.TestCase): + + def test_average(self): + self.assertEqual(average([20, 30, 70]), 40.0) + self.assertEqual(round(average([1, 5, 7]), 1), 4.3) + self.assertRaises(ZeroDivisionError, average, []) + self.assertRaises(TypeError, average, 20, 30, 70) + +unittest.main() # Calling from the command line invokes all tests +\end{verbatim} + +\section{Batteries Included\label{batteries-included}} + +Python has a ``batteries included'' philosophy. This is best seen +through the sophisticated and robust capabilities of its larger +packages. For example: + +\begin{itemize} +\item The \ulink{\module{xmlrpclib}}{../lib/module-xmlrpclib.html} and + \ulink{\module{SimpleXMLRPCServer}}{../lib/module-SimpleXMLRPCServer.html} + modules make implementing remote procedure calls into an almost trivial task. + Despite the modules names, no direct knowledge or handling of XML is needed. +\item The \ulink{\module{email}}{../lib/module-email.html} package is a library + for managing email messages, including MIME and other RFC 2822-based message + documents. Unlike \module{smtplib} and \module{poplib} which actually send + and receive messages, the email package has a complete toolset for building + or decoding complex message structures (including attachments) and for + implementing internet encoding and header protocols. +\item The \ulink{\module{xml.dom}}{../lib/module-xml.dom.html} and + \ulink{\module{xml.sax}}{../lib/module-xml.sax.html} packages provide robust + support for parsing this popular data interchange format. Likewise, the + \ulink{\module{csv}}{../lib/module-csv.html} module supports direct reads and + writes in a common database format. Together, these modules and packages + greatly simplify data interchange between python applications and other + tools. +\item Internationalization is supported by a number of modules including + \ulink{\module{gettext}}{../lib/module-gettext.html}, + \ulink{\module{locale}}{../lib/module-locale.html}, and the + \ulink{\module{codecs}}{../lib/module-codecs.html} package. +\end{itemize} + +\chapter{Brief Tour of the Standard Library -- Part II\label{briefTourTwo}} + +This second tour covers more advanced modules that support professional +programming needs. These modules rarely occur in small scripts. + + +\section{Output Formatting\label{output-formatting}} + +The \ulink{\module{repr}}{../lib/module-repr.html} module provides a +version of \function{repr()} customized for abbreviated displays of large +or deeply nested containers: + +\begin{verbatim} + >>> import repr + >>> repr.repr(set('supercalifragilisticexpialidocious')) + "set(['a', 'c', 'd', 'e', 'f', 'g', ...])" +\end{verbatim} + +The \ulink{\module{pprint}}{../lib/module-pprint.html} module offers +more sophisticated control over printing both built-in and user defined +objects in a way that is readable by the interpreter. When the result +is longer than one line, the ``pretty printer'' adds line breaks and +indentation to more clearly reveal data structure: + +\begin{verbatim} + >>> import pprint + >>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta', + ... 'yellow'], 'blue']]] + ... + >>> pprint.pprint(t, width=30) + [[[['black', 'cyan'], + 'white', + ['green', 'red']], + [['magenta', 'yellow'], + 'blue']]] +\end{verbatim} + +The \ulink{\module{textwrap}}{../lib/module-textwrap.html} module +formats paragraphs of text to fit a given screen width: + +\begin{verbatim} + >>> import textwrap + >>> doc = """The wrap() method is just like fill() except that it returns + ... a list of strings instead of one big string with newlines to separate + ... the wrapped lines.""" + ... + >>> print textwrap.fill(doc, width=40) + The wrap() method is just like fill() + except that it returns a list of strings + instead of one big string with newlines + to separate the wrapped lines. +\end{verbatim} + +The \ulink{\module{locale}}{../lib/module-locale.html} module accesses +a database of culture specific data formats. The grouping attribute +of locale's format function provides a direct way of formatting numbers +with group separators: + +\begin{verbatim} + >>> import locale + >>> locale.setlocale(locale.LC_ALL, 'English_United States.1252') + 'English_United States.1252' + >>> conv = locale.localeconv() # get a mapping of conventions + >>> x = 1234567.8 + >>> locale.format("%d", x, grouping=True) + '1,234,567' + >>> locale.format("%s%.*f", (conv['currency_symbol'], + ... conv['frac_digits'], x), grouping=True) + '$1,234,567.80' +\end{verbatim} + + +\section{Templating\label{templating}} + +The \ulink{\module{string}}{../lib/module-string.html} module includes a +versatile \class{Template} class with a simplified syntax suitable for +editing by end-users. This allows users to customize their applications +without having to alter the application. + +The format uses placeholder names formed by \samp{\$} with valid Python +identifiers (alphanumeric characters and underscores). Surrounding the +placeholder with braces allows it to be followed by more alphanumeric letters +with no intervening spaces. Writing \samp{\$\$} creates a single escaped +\samp{\$}: + +\begin{verbatim} +>>> from string import Template +>>> t = Template('${village}folk send $$10 to $cause.') +>>> t.substitute(village='Nottingham', cause='the ditch fund') +'Nottinghamfolk send $10 to the ditch fund.' +\end{verbatim} + +The \method{substitute} method raises a \exception{KeyError} when a +placeholder is not supplied in a dictionary or a keyword argument. For +mail-merge style applications, user supplied data may be incomplete and the +\method{safe_substitute} method may be more appropriate --- it will leave +placeholders unchanged if data is missing: + +\begin{verbatim} +>>> t = Template('Return the $item to $owner.') +>>> d = dict(item='unladen swallow') +>>> t.substitute(d) +Traceback (most recent call last): + . . . +KeyError: 'owner' +>>> t.safe_substitute(d) +'Return the unladen swallow to $owner.' +\end{verbatim} + +Template subclasses can specify a custom delimiter. For example, a batch +renaming utility for a photo browser may elect to use percent signs for +placeholders such as the current date, image sequence number, or file format: + +\begin{verbatim} +>>> import time, os.path +>>> photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg'] +>>> class BatchRename(Template): +... delimiter = '%' +>>> fmt = raw_input('Enter rename style (%d-date %n-seqnum %f-format): ') +Enter rename style (%d-date %n-seqnum %f-format): Ashley_%n%f + +>>> t = BatchRename(fmt) +>>> date = time.strftime('%d%b%y') +>>> for i, filename in enumerate(photofiles): +... base, ext = os.path.splitext(filename) +... newname = t.substitute(d=date, n=i, f=ext) +... print '%s --> %s' % (filename, newname) + +img_1074.jpg --> Ashley_0.jpg +img_1076.jpg --> Ashley_1.jpg +img_1077.jpg --> Ashley_2.jpg +\end{verbatim} + +Another application for templating is separating program logic from the +details of multiple output formats. This makes it possible to substitute +custom templates for XML files, plain text reports, and HTML web reports. + + +\section{Working with Binary Data Record Layouts\label{binary-formats}} + +The \ulink{\module{struct}}{../lib/module-struct.html} module provides +\function{pack()} and \function{unpack()} functions for working with +variable length binary record formats. The following example shows how +to loop through header information in a ZIP file (with pack codes +\code{"H"} and \code{"L"} representing two and four byte unsigned +numbers respectively): + +\begin{verbatim} + import struct + + data = open('myfile.zip', 'rb').read() + start = 0 + for i in range(3): # show the first 3 file headers + start += 14 + fields = struct.unpack('LLLHH', data[start:start+16]) + crc32, comp_size, uncomp_size, filenamesize, extra_size = fields + + start += 16 + filename = data[start:start+filenamesize] + start += filenamesize + extra = data[start:start+extra_size] + print filename, hex(crc32), comp_size, uncomp_size + + start += extra_size + comp_size # skip to the next header +\end{verbatim} + + +\section{Multi-threading\label{multi-threading}} + +Threading is a technique for decoupling tasks which are not sequentially +dependent. Threads can be used to improve the responsiveness of +applications that accept user input while other tasks run in the +background. A related use case is running I/O in parallel with +computations in another thread. + +The following code shows how the high level +\ulink{\module{threading}}{../lib/module-threading.html} module can run +tasks in background while the main program continues to run: + +\begin{verbatim} + import threading, zipfile + + class AsyncZip(threading.Thread): + def __init__(self, infile, outfile): + threading.Thread.__init__(self) + self.infile = infile + self.outfile = outfile + def run(self): + f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED) + f.write(self.infile) + f.close() + print 'Finished background zip of: ', self.infile + + background = AsyncZip('mydata.txt', 'myarchive.zip') + background.start() + print 'The main program continues to run in foreground.' + + background.join() # Wait for the background task to finish + print 'Main program waited until background was done.' +\end{verbatim} + +The principal challenge of multi-threaded applications is coordinating +threads that share data or other resources. To that end, the threading +module provides a number of synchronization primitives including locks, +events, condition variables, and semaphores. + +While those tools are powerful, minor design errors can result in +problems that are difficult to reproduce. So, the preferred approach +to task coordination is to concentrate all access to a resource +in a single thread and then use the +\ulink{\module{Queue}}{../lib/module-Queue.html} module to feed that +thread with requests from other threads. Applications using +\class{Queue} objects for inter-thread communication and coordination +are easier to design, more readable, and more reliable. + + +\section{Logging\label{logging}} + +The \ulink{\module{logging}}{../lib/module-logging.html} module offers +a full featured and flexible logging system. At its simplest, log +messages are sent to a file or to \code{sys.stderr}: + +\begin{verbatim} + import logging + logging.debug('Debugging information') + logging.info('Informational message') + logging.warning('Warning:config file %s not found', 'server.conf') + logging.error('Error occurred') + logging.critical('Critical error -- shutting down') +\end{verbatim} + +This produces the following output: + +\begin{verbatim} + WARNING:root:Warning:config file server.conf not found + ERROR:root:Error occurred + CRITICAL:root:Critical error -- shutting down +\end{verbatim} + +By default, informational and debugging messages are suppressed and the +output is sent to standard error. Other output options include routing +messages through email, datagrams, sockets, or to an HTTP Server. New +filters can select different routing based on message priority: +\constant{DEBUG}, \constant{INFO}, \constant{WARNING}, \constant{ERROR}, +and \constant{CRITICAL}. + +The logging system can be configured directly from Python or can be +loaded from a user editable configuration file for customized logging +without altering the application. + + +\section{Weak References\label{weak-references}} + +Python does automatic memory management (reference counting for most +objects and garbage collection to eliminate cycles). The memory is +freed shortly after the last reference to it has been eliminated. + +This approach works fine for most applications but occasionally there +is a need to track objects only as long as they are being used by +something else. Unfortunately, just tracking them creates a reference +that makes them permanent. The +\ulink{\module{weakref}}{../lib/module-weakref.html} module provides +tools for tracking objects without creating a reference. When the +object is no longer needed, it is automatically removed from a weakref +table and a callback is triggered for weakref objects. Typical +applications include caching objects that are expensive to create: + +\begin{verbatim} + >>> import weakref, gc + >>> class A: + ... def __init__(self, value): + ... self.value = value + ... def __repr__(self): + ... return str(self.value) + ... + >>> a = A(10) # create a reference + >>> d = weakref.WeakValueDictionary() + >>> d['primary'] = a # does not create a reference + >>> d['primary'] # fetch the object if it is still alive + 10 + >>> del a # remove the one reference + >>> gc.collect() # run garbage collection right away + 0 + >>> d['primary'] # entry was automatically removed + Traceback (most recent call last): + File "<pyshell#108>", line 1, in -toplevel- + d['primary'] # entry was automatically removed + File "C:/PY24/lib/weakref.py", line 46, in __getitem__ + o = self.data[key]() + KeyError: 'primary' +\end{verbatim} + +\section{Tools for Working with Lists\label{list-tools}} + +Many data structure needs can be met with the built-in list type. +However, sometimes there is a need for alternative implementations +with different performance trade-offs. + +The \ulink{\module{array}}{../lib/module-array.html} module provides an +\class{array()} object that is like a list that stores only homogenous +data and stores it more compactly. The following example shows an array +of numbers stored as two byte unsigned binary numbers (typecode +\code{"H"}) rather than the usual 16 bytes per entry for regular lists +of python int objects: + +\begin{verbatim} + >>> from array import array + >>> a = array('H', [4000, 10, 700, 22222]) + >>> sum(a) + 26932 + >>> a[1:3] + array('H', [10, 700]) +\end{verbatim} + +The \ulink{\module{collections}}{../lib/module-collections.html} module +provides a \class{deque()} object that is like a list with faster +appends and pops from the left side but slower lookups in the middle. +These objects are well suited for implementing queues and breadth first +tree searches: + +\begin{verbatim} + >>> from collections import deque + >>> d = deque(["task1", "task2", "task3"]) + >>> d.append("task4") + >>> print "Handling", d.popleft() + Handling task1 + + unsearched = deque([starting_node]) + def breadth_first_search(unsearched): + node = unsearched.popleft() + for m in gen_moves(node): + if is_goal(m): + return m + unsearched.append(m) +\end{verbatim} + +In addition to alternative list implementations, the library also offers +other tools such as the \ulink{\module{bisect}}{../lib/module-bisect.html} +module with functions for manipulating sorted lists: + +\begin{verbatim} + >>> import bisect + >>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')] + >>> bisect.insort(scores, (300, 'ruby')) + >>> scores + [(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')] +\end{verbatim} + +The \ulink{\module{heapq}}{../lib/module-heapq.html} module provides +functions for implementing heaps based on regular lists. The lowest +valued entry is always kept at position zero. This is useful for +applications which repeatedly access the smallest element but do not +want to run a full list sort: + +\begin{verbatim} + >>> from heapq import heapify, heappop, heappush + >>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] + >>> heapify(data) # rearrange the list into heap order + >>> heappush(data, -5) # add a new entry + >>> [heappop(data) for i in range(3)] # fetch the three smallest entries + [-5, 0, 1] +\end{verbatim} + + +\section{Decimal Floating Point Arithmetic\label{decimal-fp}} + +The \ulink{\module{decimal}}{../lib/module-decimal.html} module offers a +\class{Decimal} datatype for decimal floating point arithmetic. Compared to +the built-in \class{float} implementation of binary floating point, the new +class is especially helpful for financial applications and other uses which +require exact decimal representation, control over precision, control over +rounding to meet legal or regulatory requirements, tracking of significant +decimal places, or for applications where the user expects the results to +match calculations done by hand. + +For example, calculating a 5\%{} tax on a 70 cent phone charge gives +different results in decimal floating point and binary floating point. +The difference becomes significant if the results are rounded to the +nearest cent: + +\begin{verbatim} +>>> from decimal import * +>>> Decimal('0.70') * Decimal('1.05') +Decimal("0.7350") +>>> .70 * 1.05 +0.73499999999999999 +\end{verbatim} + +The \class{Decimal} result keeps a trailing zero, automatically inferring four +place significance from multiplicands with two place significance. Decimal reproduces +mathematics as done by hand and avoids issues that can arise when binary +floating point cannot exactly represent decimal quantities. + +Exact representation enables the \class{Decimal} class to perform +modulo calculations and equality tests that are unsuitable for binary +floating point: + +\begin{verbatim} +>>> Decimal('1.00') % Decimal('.10') +Decimal("0.00") +>>> 1.00 % 0.10 +0.09999999999999995 + +>>> sum([Decimal('0.1')]*10) == Decimal('1.0') +True +>>> sum([0.1]*10) == 1.0 +False +\end{verbatim} + +The \module{decimal} module provides arithmetic with as much precision as +needed: + +\begin{verbatim} +>>> getcontext().prec = 36 +>>> Decimal(1) / Decimal(7) +Decimal("0.142857142857142857142857142857142857") +\end{verbatim} + + + +\chapter{What Now? \label{whatNow}} + +Reading this tutorial has probably reinforced your interest in using +Python --- you should be eager to apply Python to solving your +real-world problems. Where should you go to learn more? + +This tutorial is part of Python's documentation set. +Some other documents in the set are: + +\begin{itemize} + +\item \citetitle[../lib/lib.html]{Python Library Reference}: + +You should browse through this manual, which gives complete (though +terse) reference material about types, functions, and the modules in +the standard library. The standard Python distribution includes a +\emph{lot} of additional code. There are modules to read \UNIX{} +mailboxes, retrieve documents via HTTP, generate random numbers, parse +command-line options, write CGI programs, compress data, and many other tasks. +Skimming through the Library Reference will give you an idea of +what's available. + +\item \citetitle[../inst/inst.html]{Installing Python Modules} +explains how to install external modules written by other Python +users. + +\item \citetitle[../ref/ref.html]{Language Reference}: A detailed +explanation of Python's syntax and semantics. It's heavy reading, +but is useful as a complete guide to the language itself. + +\end{itemize} + +More Python resources: + +\begin{itemize} + +\item \url{http://www.python.org}: The major Python Web site. It contains +code, documentation, and pointers to Python-related pages around the +Web. This Web site is mirrored in various places around the +world, such as Europe, Japan, and Australia; a mirror may be faster +than the main site, depending on your geographical location. + +\item \url{http://docs.python.org}: Fast access to Python's +documentation. + +\item \url{http://cheeseshop.python.org}: +The Python Package Index, nicknamed the Cheese Shop, +is an index of user-created Python modules that are available for +download. Once you begin releasing code, you can register it +here so that others can find it. + +\item \url{http://aspn.activestate.com/ASPN/Python/Cookbook/}: The +Python Cookbook is a sizable collection of code examples, larger +modules, and useful scripts. Particularly notable contributions are +collected in a book also titled \citetitle{Python Cookbook} (O'Reilly +\& Associates, ISBN 0-596-00797-3.) + +\end{itemize} + + +For Python-related questions and problem reports, you can post to the +newsgroup \newsgroup{comp.lang.python}, or send them to the mailing +list at \email{python-list@python.org}. The newsgroup and mailing list +are gatewayed, so messages posted to one will automatically be +forwarded to the other. There are around 120 postings a day (with peaks +up to several hundred), +% Postings figure based on average of last six months activity as +% reported by www.egroups.com; Jan. 2000 - June 2000: 21272 msgs / 182 +% days = 116.9 msgs / day and steadily increasing. +asking (and answering) questions, suggesting new features, and +announcing new modules. Before posting, be sure to check the list of +\ulink{Frequently Asked Questions}{http://www.python.org/doc/faq/} (also called the FAQ), or look for it in the +\file{Misc/} directory of the Python source distribution. Mailing +list archives are available at \url{http://mail.python.org/pipermail/}. +The FAQ answers many of the questions that come up again and again, +and may already contain the solution for your problem. + + +\appendix + +\chapter{Interactive Input Editing and History Substitution\label{interacting}} + +Some versions of the Python interpreter support editing of the current +input line and history substitution, similar to facilities found in +the Korn shell and the GNU Bash shell. This is implemented using the +\emph{GNU Readline} library, which supports Emacs-style and vi-style +editing. This library has its own documentation which I won't +duplicate here; however, the basics are easily explained. The +interactive editing and history described here are optionally +available in the \UNIX{} and Cygwin versions of the interpreter. + +This chapter does \emph{not} document the editing facilities of Mark +Hammond's PythonWin package or the Tk-based environment, IDLE, +distributed with Python. The command line history recall which +operates within DOS boxes on NT and some other DOS and Windows flavors +is yet another beast. + +\section{Line Editing \label{lineEditing}} + +If supported, input line editing is active whenever the interpreter +prints a primary or secondary prompt. The current line can be edited +using the conventional Emacs control characters. The most important +of these are: \kbd{C-A} (Control-A) moves the cursor to the beginning +of the line, \kbd{C-E} to the end, \kbd{C-B} moves it one position to +the left, \kbd{C-F} to the right. Backspace erases the character to +the left of the cursor, \kbd{C-D} the character to its right. +\kbd{C-K} kills (erases) the rest of the line to the right of the +cursor, \kbd{C-Y} yanks back the last killed string. +\kbd{C-underscore} undoes the last change you made; it can be repeated +for cumulative effect. + +\section{History Substitution \label{history}} + +History substitution works as follows. All non-empty input lines +issued are saved in a history buffer, and when a new prompt is given +you are positioned on a new line at the bottom of this buffer. +\kbd{C-P} moves one line up (back) in the history buffer, +\kbd{C-N} moves one down. Any line in the history buffer can be +edited; an asterisk appears in front of the prompt to mark a line as +modified. Pressing the \kbd{Return} key passes the current line to +the interpreter. \kbd{C-R} starts an incremental reverse search; +\kbd{C-S} starts a forward search. + +\section{Key Bindings \label{keyBindings}} + +The key bindings and some other parameters of the Readline library can +be customized by placing commands in an initialization file called +\file{\~{}/.inputrc}. Key bindings have the form + +\begin{verbatim} +key-name: function-name +\end{verbatim} + +or + +\begin{verbatim} +"string": function-name +\end{verbatim} + +and options can be set with + +\begin{verbatim} +set option-name value +\end{verbatim} + +For example: + +\begin{verbatim} +# I prefer vi-style editing: +set editing-mode vi + +# Edit using a single line: +set horizontal-scroll-mode On + +# Rebind some keys: +Meta-h: backward-kill-word +"\C-u": universal-argument +"\C-x\C-r": re-read-init-file +\end{verbatim} + +Note that the default binding for \kbd{Tab} in Python is to insert a +\kbd{Tab} character instead of Readline's default filename completion +function. If you insist, you can override this by putting + +\begin{verbatim} +Tab: complete +\end{verbatim} + +in your \file{\~{}/.inputrc}. (Of course, this makes it harder to +type indented continuation lines if you're accustomed to using +\kbd{Tab} for that purpose.) + +Automatic completion of variable and module names is optionally +available. To enable it in the interpreter's interactive mode, add +the following to your startup file:\footnote{ + Python will execute the contents of a file identified by the + \envvar{PYTHONSTARTUP} environment variable when you start an + interactive interpreter.} +\refstmodindex{rlcompleter}\refbimodindex{readline} + +\begin{verbatim} +import rlcompleter, readline +readline.parse_and_bind('tab: complete') +\end{verbatim} + +This binds the \kbd{Tab} key to the completion function, so hitting +the \kbd{Tab} key twice suggests completions; it looks at Python +statement names, the current local variables, and the available module +names. For dotted expressions such as \code{string.a}, it will +evaluate the expression up to the final \character{.} and then +suggest completions from the attributes of the resulting object. Note +that this may execute application-defined code if an object with a +\method{__getattr__()} method is part of the expression. + +A more capable startup file might look like this example. Note that +this deletes the names it creates once they are no longer needed; this +is done since the startup file is executed in the same namespace as +the interactive commands, and removing the names avoids creating side +effects in the interactive environment. You may find it convenient +to keep some of the imported modules, such as +\ulink{\module{os}}{../lib/module-os.html}, which turn +out to be needed in most sessions with the interpreter. + +\begin{verbatim} +# Add auto-completion and a stored history file of commands to your Python +# interactive interpreter. Requires Python 2.0+, readline. Autocomplete is +# bound to the Esc key by default (you can change it - see readline docs). +# +# Store the file in ~/.pystartup, and set an environment variable to point +# to it: "export PYTHONSTARTUP=/max/home/itamar/.pystartup" in bash. +# +# Note that PYTHONSTARTUP does *not* expand "~", so you have to put in the +# full path to your home directory. + +import atexit +import os +import readline +import rlcompleter + +historyPath = os.path.expanduser("~/.pyhistory") + +def save_history(historyPath=historyPath): + import readline + readline.write_history_file(historyPath) + +if os.path.exists(historyPath): + readline.read_history_file(historyPath) + +atexit.register(save_history) +del os, atexit, readline, rlcompleter, save_history, historyPath +\end{verbatim} + + +\section{Commentary \label{commentary}} + +This facility is an enormous step forward compared to earlier versions +of the interpreter; however, some wishes are left: It would be nice if +the proper indentation were suggested on continuation lines (the +parser knows if an indent token is required next). The completion +mechanism might use the interpreter's symbol table. A command to +check (or even suggest) matching parentheses, quotes, etc., would also +be useful. + + +\chapter{Floating Point Arithmetic: Issues and Limitations\label{fp-issues}} +\sectionauthor{Tim Peters}{tim_one@users.sourceforge.net} + +Floating-point numbers are represented in computer hardware as +base 2 (binary) fractions. For example, the decimal fraction + +\begin{verbatim} +0.125 +\end{verbatim} + +has value 1/10 + 2/100 + 5/1000, and in the same way the binary fraction + +\begin{verbatim} +0.001 +\end{verbatim} + +has value 0/2 + 0/4 + 1/8. These two fractions have identical values, +the only real difference being that the first is written in base 10 +fractional notation, and the second in base 2. + +Unfortunately, most decimal fractions cannot be represented exactly as +binary fractions. A consequence is that, in general, the decimal +floating-point numbers you enter are only approximated by the binary +floating-point numbers actually stored in the machine. + +The problem is easier to understand at first in base 10. Consider the +fraction 1/3. You can approximate that as a base 10 fraction: + +\begin{verbatim} +0.3 +\end{verbatim} + +or, better, + +\begin{verbatim} +0.33 +\end{verbatim} + +or, better, + +\begin{verbatim} +0.333 +\end{verbatim} + +and so on. No matter how many digits you're willing to write down, the +result will never be exactly 1/3, but will be an increasingly better +approximation of 1/3. + +In the same way, no matter how many base 2 digits you're willing to +use, the decimal value 0.1 cannot be represented exactly as a base 2 +fraction. In base 2, 1/10 is the infinitely repeating fraction + +\begin{verbatim} +0.0001100110011001100110011001100110011001100110011... +\end{verbatim} + +Stop at any finite number of bits, and you get an approximation. This +is why you see things like: + +\begin{verbatim} +>>> 0.1 +0.10000000000000001 +\end{verbatim} + +On most machines today, that is what you'll see if you enter 0.1 at +a Python prompt. You may not, though, because the number of bits +used by the hardware to store floating-point values can vary across +machines, and Python only prints a decimal approximation to the true +decimal value of the binary approximation stored by the machine. On +most machines, if Python were to print the true decimal value of +the binary approximation stored for 0.1, it would have to display + +\begin{verbatim} +>>> 0.1 +0.1000000000000000055511151231257827021181583404541015625 +\end{verbatim} + +instead! The Python prompt uses the builtin +\function{repr()} function to obtain a string version of everything it +displays. For floats, \code{repr(\var{float})} rounds the true +decimal value to 17 significant digits, giving + +\begin{verbatim} +0.10000000000000001 +\end{verbatim} + +\code{repr(\var{float})} produces 17 significant digits because it +turns out that's enough (on most machines) so that +\code{eval(repr(\var{x})) == \var{x}} exactly for all finite floats +\var{x}, but rounding to 16 digits is not enough to make that true. + +Note that this is in the very nature of binary floating-point: this is +not a bug in Python, and it is not a bug in your code either. You'll +see the same kind of thing in all languages that support your +hardware's floating-point arithmetic (although some languages may +not \emph{display} the difference by default, or in all output modes). + +Python's builtin \function{str()} function produces only 12 +significant digits, and you may wish to use that instead. It's +unusual for \code{eval(str(\var{x}))} to reproduce \var{x}, but the +output may be more pleasant to look at: + +\begin{verbatim} +>>> print str(0.1) +0.1 +\end{verbatim} + +It's important to realize that this is, in a real sense, an illusion: +the value in the machine is not exactly 1/10, you're simply rounding +the \emph{display} of the true machine value. + +Other surprises follow from this one. For example, after seeing + +\begin{verbatim} +>>> 0.1 +0.10000000000000001 +\end{verbatim} + +you may be tempted to use the \function{round()} function to chop it +back to the single digit you expect. But that makes no difference: + +\begin{verbatim} +>>> round(0.1, 1) +0.10000000000000001 +\end{verbatim} + +The problem is that the binary floating-point value stored for "0.1" +was already the best possible binary approximation to 1/10, so trying +to round it again can't make it better: it was already as good as it +gets. + +Another consequence is that since 0.1 is not exactly 1/10, +summing ten values of 0.1 may not yield exactly 1.0, either: + +\begin{verbatim} +>>> sum = 0.0 +>>> for i in range(10): +... sum += 0.1 +... +>>> sum +0.99999999999999989 +\end{verbatim} + +Binary floating-point arithmetic holds many surprises like this. The +problem with "0.1" is explained in precise detail below, in the +"Representation Error" section. See +\citetitle[http://www.lahey.com/float.htm]{The Perils of Floating +Point} for a more complete account of other common surprises. + +As that says near the end, ``there are no easy answers.'' Still, +don't be unduly wary of floating-point! The errors in Python float +operations are inherited from the floating-point hardware, and on most +machines are on the order of no more than 1 part in 2**53 per +operation. That's more than adequate for most tasks, but you do need +to keep in mind that it's not decimal arithmetic, and that every float +operation can suffer a new rounding error. + +While pathological cases do exist, for most casual use of +floating-point arithmetic you'll see the result you expect in the end +if you simply round the display of your final results to the number of +decimal digits you expect. \function{str()} usually suffices, and for +finer control see the discussion of Python's \code{\%} format +operator: the \code{\%g}, \code{\%f} and \code{\%e} format codes +supply flexible and easy ways to round float results for display. + + +\section{Representation Error + \label{fp-error}} + +This section explains the ``0.1'' example in detail, and shows how +you can perform an exact analysis of cases like this yourself. Basic +familiarity with binary floating-point representation is assumed. + +\dfn{Representation error} refers to the fact that some (most, actually) +decimal fractions cannot be represented exactly as binary (base 2) +fractions. This is the chief reason why Python (or Perl, C, \Cpp, +Java, Fortran, and many others) often won't display the exact decimal +number you expect: + +\begin{verbatim} +>>> 0.1 +0.10000000000000001 +\end{verbatim} + +Why is that? 1/10 is not exactly representable as a binary fraction. +Almost all machines today (November 2000) use IEEE-754 floating point +arithmetic, and almost all platforms map Python floats to IEEE-754 +"double precision". 754 doubles contain 53 bits of precision, so on +input the computer strives to convert 0.1 to the closest fraction it can +of the form \var{J}/2**\var{N} where \var{J} is an integer containing +exactly 53 bits. Rewriting + +\begin{verbatim} + 1 / 10 ~= J / (2**N) +\end{verbatim} + +as + +\begin{verbatim} +J ~= 2**N / 10 +\end{verbatim} + +and recalling that \var{J} has exactly 53 bits (is \code{>= 2**52} but +\code{< 2**53}), the best value for \var{N} is 56: + +\begin{verbatim} +>>> 2**52 +4503599627370496L +>>> 2**53 +9007199254740992L +>>> 2**56/10 +7205759403792793L +\end{verbatim} + +That is, 56 is the only value for \var{N} that leaves \var{J} with +exactly 53 bits. The best possible value for \var{J} is then that +quotient rounded: + +\begin{verbatim} +>>> q, r = divmod(2**56, 10) +>>> r +6L +\end{verbatim} + +Since the remainder is more than half of 10, the best approximation is +obtained by rounding up: + +\begin{verbatim} +>>> q+1 +7205759403792794L +\end{verbatim} + +Therefore the best possible approximation to 1/10 in 754 double +precision is that over 2**56, or + +\begin{verbatim} +7205759403792794 / 72057594037927936 +\end{verbatim} + +Note that since we rounded up, this is actually a little bit larger than +1/10; if we had not rounded up, the quotient would have been a little +bit smaller than 1/10. But in no case can it be \emph{exactly} 1/10! + +So the computer never ``sees'' 1/10: what it sees is the exact +fraction given above, the best 754 double approximation it can get: + +\begin{verbatim} +>>> .1 * 2**56 +7205759403792794.0 +\end{verbatim} + +If we multiply that fraction by 10**30, we can see the (truncated) +value of its 30 most significant decimal digits: + +\begin{verbatim} +>>> 7205759403792794 * 10**30 / 2**56 +100000000000000005551115123125L +\end{verbatim} + +meaning that the exact number stored in the computer is approximately +equal to the decimal value 0.100000000000000005551115123125. Rounding +that to 17 significant digits gives the 0.10000000000000001 that Python +displays (well, will display on any 754-conforming platform that does +best-possible input and output conversions in its C library --- yours may +not!). + +\chapter{History and License} +\input{license} + +\input{glossary} + +\input{tut.ind} + +\end{document} diff --git a/sys/src/cmd/python/Doc/whatsnew/Makefile b/sys/src/cmd/python/Doc/whatsnew/Makefile new file mode 100644 index 000000000..d11f97bf7 --- /dev/null +++ b/sys/src/cmd/python/Doc/whatsnew/Makefile @@ -0,0 +1,3 @@ + +check: + ../../python.exe ../../Tools/scripts/texcheck.py whatsnew25.tex diff --git a/sys/src/cmd/python/Doc/whatsnew/whatsnew20.tex b/sys/src/cmd/python/Doc/whatsnew/whatsnew20.tex new file mode 100644 index 000000000..57e0a369a --- /dev/null +++ b/sys/src/cmd/python/Doc/whatsnew/whatsnew20.tex @@ -0,0 +1,1337 @@ +\documentclass{howto} + +% $Id: whatsnew20.tex 50964 2006-07-30 03:03:43Z fred.drake $ + +\title{What's New in Python 2.0} +\release{1.02} +\author{A.M. Kuchling and Moshe Zadka} +\authoraddress{ + \strong{Python Software Foundation}\\ + Email: \email{amk@amk.ca}, \email{moshez@twistedmatrix.com} +} +\begin{document} +\maketitle\tableofcontents + +\section{Introduction} + +A new release of Python, version 2.0, was released on October 16, 2000. This +article covers the exciting new features in 2.0, highlights some other +useful changes, and points out a few incompatible changes that may require +rewriting code. + +Python's development never completely stops between releases, and a +steady flow of bug fixes and improvements are always being submitted. +A host of minor fixes, a few optimizations, additional docstrings, and +better error messages went into 2.0; to list them all would be +impossible, but they're certainly significant. Consult the +publicly-available CVS logs if you want to see the full list. This +progress is due to the five developers working for +PythonLabs are now getting paid to spend their days fixing bugs, +and also due to the improved communication resulting +from moving to SourceForge. + +% ====================================================================== +\section{What About Python 1.6?} + +Python 1.6 can be thought of as the Contractual Obligations Python +release. After the core development team left CNRI in May 2000, CNRI +requested that a 1.6 release be created, containing all the work on +Python that had been performed at CNRI. Python 1.6 therefore +represents the state of the CVS tree as of May 2000, with the most +significant new feature being Unicode support. Development continued +after May, of course, so the 1.6 tree received a few fixes to ensure +that it's forward-compatible with Python 2.0. 1.6 is therefore part +of Python's evolution, and not a side branch. + +So, should you take much interest in Python 1.6? Probably not. The +1.6final and 2.0beta1 releases were made on the same day (September 5, +2000), the plan being to finalize Python 2.0 within a month or so. If +you have applications to maintain, there seems little point in +breaking things by moving to 1.6, fixing them, and then having another +round of breakage within a month by moving to 2.0; you're better off +just going straight to 2.0. Most of the really interesting features +described in this document are only in 2.0, because a lot of work was +done between May and September. + +% ====================================================================== +\section{New Development Process} + +The most important change in Python 2.0 may not be to the code at all, +but to how Python is developed: in May 2000 the Python developers +began using the tools made available by SourceForge for storing +source code, tracking bug reports, and managing the queue of patch +submissions. To report bugs or submit patches for Python 2.0, use the +bug tracking and patch manager tools available from Python's project +page, located at \url{http://sourceforge.net/projects/python/}. + +The most important of the services now hosted at SourceForge is the +Python CVS tree, the version-controlled repository containing the +source code for Python. Previously, there were roughly 7 or so people +who had write access to the CVS tree, and all patches had to be +inspected and checked in by one of the people on this short list. +Obviously, this wasn't very scalable. By moving the CVS tree to +SourceForge, it became possible to grant write access to more people; +as of September 2000 there were 27 people able to check in changes, a +fourfold increase. This makes possible large-scale changes that +wouldn't be attempted if they'd have to be filtered through the small +group of core developers. For example, one day Peter Schneider-Kamp +took it into his head to drop K\&R C compatibility and convert the C +source for Python to ANSI C. After getting approval on the python-dev +mailing list, he launched into a flurry of checkins that lasted about +a week, other developers joined in to help, and the job was done. If +there were only 5 people with write access, probably that task would +have been viewed as ``nice, but not worth the time and effort needed'' +and it would never have gotten done. + +The shift to using SourceForge's services has resulted in a remarkable +increase in the speed of development. Patches now get submitted, +commented on, revised by people other than the original submitter, and +bounced back and forth between people until the patch is deemed worth +checking in. Bugs are tracked in one central location and can be +assigned to a specific person for fixing, and we can count the number +of open bugs to measure progress. This didn't come without a cost: +developers now have more e-mail to deal with, more mailing lists to +follow, and special tools had to be written for the new environment. +For example, SourceForge sends default patch and bug notification +e-mail messages that are completely unhelpful, so Ka-Ping Yee wrote an +HTML screen-scraper that sends more useful messages. + +The ease of adding code caused a few initial growing pains, such as +code was checked in before it was ready or without getting clear +agreement from the developer group. The approval process that has +emerged is somewhat similar to that used by the Apache group. +Developers can vote +1, +0, -0, or -1 on a patch; +1 and -1 denote +acceptance or rejection, while +0 and -0 mean the developer is mostly +indifferent to the change, though with a slight positive or negative +slant. The most significant change from the Apache model is that the +voting is essentially advisory, letting Guido van Rossum, who has +Benevolent Dictator For Life status, know what the general opinion is. +He can still ignore the result of a vote, and approve or +reject a change even if the community disagrees with him. + +Producing an actual patch is the last step in adding a new feature, +and is usually easy compared to the earlier task of coming up with a +good design. Discussions of new features can often explode into +lengthy mailing list threads, making the discussion hard to follow, +and no one can read every posting to python-dev. Therefore, a +relatively formal process has been set up to write Python Enhancement +Proposals (PEPs), modelled on the Internet RFC process. PEPs are +draft documents that describe a proposed new feature, and are +continually revised until the community reaches a consensus, either +accepting or rejecting the proposal. Quoting from the introduction to +PEP 1, ``PEP Purpose and Guidelines'': + +\begin{quotation} + PEP stands for Python Enhancement Proposal. A PEP is a design + document providing information to the Python community, or + describing a new feature for Python. The PEP should provide a + concise technical specification of the feature and a rationale for + the feature. + + We intend PEPs to be the primary mechanisms for proposing new + features, for collecting community input on an issue, and for + documenting the design decisions that have gone into Python. The + PEP author is responsible for building consensus within the + community and documenting dissenting opinions. +\end{quotation} + +Read the rest of PEP 1 for the details of the PEP editorial process, +style, and format. PEPs are kept in the Python CVS tree on +SourceForge, though they're not part of the Python 2.0 distribution, +and are also available in HTML form from +\url{http://www.python.org/peps/}. As of September 2000, +there are 25 PEPS, ranging from PEP 201, ``Lockstep Iteration'', to +PEP 225, ``Elementwise/Objectwise Operators''. + +% ====================================================================== +\section{Unicode} + +The largest new feature in Python 2.0 is a new fundamental data type: +Unicode strings. Unicode uses 16-bit numbers to represent characters +instead of the 8-bit number used by ASCII, meaning that 65,536 +distinct characters can be supported. + +The final interface for Unicode support was arrived at through +countless often-stormy discussions on the python-dev mailing list, and +mostly implemented by Marc-Andr\'e Lemburg, based on a Unicode string +type implementation by Fredrik Lundh. A detailed explanation of the +interface was written up as \pep{100}, ``Python Unicode Integration''. +This article will simply cover the most significant points about the +Unicode interfaces. + +In Python source code, Unicode strings are written as +\code{u"string"}. Arbitrary Unicode characters can be written using a +new escape sequence, \code{\e u\var{HHHH}}, where \var{HHHH} is a +4-digit hexadecimal number from 0000 to FFFF. The existing +\code{\e x\var{HHHH}} escape sequence can also be used, and octal +escapes can be used for characters up to U+01FF, which is represented +by \code{\e 777}. + +Unicode strings, just like regular strings, are an immutable sequence +type. They can be indexed and sliced, but not modified in place. +Unicode strings have an \method{encode( \optional{encoding} )} method +that returns an 8-bit string in the desired encoding. Encodings are +named by strings, such as \code{'ascii'}, \code{'utf-8'}, +\code{'iso-8859-1'}, or whatever. A codec API is defined for +implementing and registering new encodings that are then available +throughout a Python program. If an encoding isn't specified, the +default encoding is usually 7-bit ASCII, though it can be changed for +your Python installation by calling the +\function{sys.setdefaultencoding(\var{encoding})} function in a +customised version of \file{site.py}. + +Combining 8-bit and Unicode strings always coerces to Unicode, using +the default ASCII encoding; the result of \code{'a' + u'bc'} is +\code{u'abc'}. + +New built-in functions have been added, and existing built-ins +modified to support Unicode: + +\begin{itemize} +\item \code{unichr(\var{ch})} returns a Unicode string 1 character +long, containing the character \var{ch}. + +\item \code{ord(\var{u})}, where \var{u} is a 1-character regular or Unicode string, returns the number of the character as an integer. + +\item \code{unicode(\var{string} \optional{, \var{encoding}} +\optional{, \var{errors}} ) } creates a Unicode string from an 8-bit +string. \code{encoding} is a string naming the encoding to use. +The \code{errors} parameter specifies the treatment of characters that +are invalid for the current encoding; passing \code{'strict'} as the +value causes an exception to be raised on any encoding error, while +\code{'ignore'} causes errors to be silently ignored and +\code{'replace'} uses U+FFFD, the official replacement character, in +case of any problems. + +\item The \keyword{exec} statement, and various built-ins such as +\code{eval()}, \code{getattr()}, and \code{setattr()} will also +accept Unicode strings as well as regular strings. (It's possible +that the process of fixing this missed some built-ins; if you find a +built-in function that accepts strings but doesn't accept Unicode +strings at all, please report it as a bug.) + +\end{itemize} + +A new module, \module{unicodedata}, provides an interface to Unicode +character properties. For example, \code{unicodedata.category(u'A')} +returns the 2-character string 'Lu', the 'L' denoting it's a letter, +and 'u' meaning that it's uppercase. +\code{unicodedata.bidirectional(u'\e u0660')} returns 'AN', meaning that U+0660 is +an Arabic number. + +The \module{codecs} module contains functions to look up existing encodings +and register new ones. Unless you want to implement a +new encoding, you'll most often use the +\function{codecs.lookup(\var{encoding})} function, which returns a +4-element tuple: \code{(\var{encode_func}, +\var{decode_func}, \var{stream_reader}, \var{stream_writer})}. + +\begin{itemize} +\item \var{encode_func} is a function that takes a Unicode string, and +returns a 2-tuple \code{(\var{string}, \var{length})}. \var{string} +is an 8-bit string containing a portion (perhaps all) of the Unicode +string converted into the given encoding, and \var{length} tells you +how much of the Unicode string was converted. + +\item \var{decode_func} is the opposite of \var{encode_func}, taking +an 8-bit string and returning a 2-tuple \code{(\var{ustring}, +\var{length})}, consisting of the resulting Unicode string +\var{ustring} and the integer \var{length} telling how much of the +8-bit string was consumed. + +\item \var{stream_reader} is a class that supports decoding input from +a stream. \var{stream_reader(\var{file_obj})} returns an object that +supports the \method{read()}, \method{readline()}, and +\method{readlines()} methods. These methods will all translate from +the given encoding and return Unicode strings. + +\item \var{stream_writer}, similarly, is a class that supports +encoding output to a stream. \var{stream_writer(\var{file_obj})} +returns an object that supports the \method{write()} and +\method{writelines()} methods. These methods expect Unicode strings, +translating them to the given encoding on output. +\end{itemize} + +For example, the following code writes a Unicode string into a file, +encoding it as UTF-8: + +\begin{verbatim} +import codecs + +unistr = u'\u0660\u2000ab ...' + +(UTF8_encode, UTF8_decode, + UTF8_streamreader, UTF8_streamwriter) = codecs.lookup('UTF-8') + +output = UTF8_streamwriter( open( '/tmp/output', 'wb') ) +output.write( unistr ) +output.close() +\end{verbatim} + +The following code would then read UTF-8 input from the file: + +\begin{verbatim} +input = UTF8_streamreader( open( '/tmp/output', 'rb') ) +print repr(input.read()) +input.close() +\end{verbatim} + +Unicode-aware regular expressions are available through the +\module{re} module, which has a new underlying implementation called +SRE written by Fredrik Lundh of Secret Labs AB. + +A \code{-U} command line option was added which causes the Python +compiler to interpret all string literals as Unicode string literals. +This is intended to be used in testing and future-proofing your Python +code, since some future version of Python may drop support for 8-bit +strings and provide only Unicode strings. + +% ====================================================================== +\section{List Comprehensions} + +Lists are a workhorse data type in Python, and many programs +manipulate a list at some point. Two common operations on lists are +to loop over them, and either pick out the elements that meet a +certain criterion, or apply some function to each element. For +example, given a list of strings, you might want to pull out all the +strings containing a given substring, or strip off trailing whitespace +from each line. + +The existing \function{map()} and \function{filter()} functions can be +used for this purpose, but they require a function as one of their +arguments. This is fine if there's an existing built-in function that +can be passed directly, but if there isn't, you have to create a +little function to do the required work, and Python's scoping rules +make the result ugly if the little function needs additional +information. Take the first example in the previous paragraph, +finding all the strings in the list containing a given substring. You +could write the following to do it: + +\begin{verbatim} +# Given the list L, make a list of all strings +# containing the substring S. +sublist = filter( lambda s, substring=S: + string.find(s, substring) != -1, + L) +\end{verbatim} + +Because of Python's scoping rules, a default argument is used so that +the anonymous function created by the \keyword{lambda} statement knows +what substring is being searched for. List comprehensions make this +cleaner: + +\begin{verbatim} +sublist = [ s for s in L if string.find(s, S) != -1 ] +\end{verbatim} + +List comprehensions have the form: + +\begin{verbatim} +[ expression for expr in sequence1 + for expr2 in sequence2 ... + for exprN in sequenceN + if condition ] +\end{verbatim} + +The \keyword{for}...\keyword{in} clauses contain the sequences to be +iterated over. The sequences do not have to be the same length, +because they are \emph{not} iterated over in parallel, but +from left to right; this is explained more clearly in the following +paragraphs. The elements of the generated list will be the successive +values of \var{expression}. The final \keyword{if} clause is +optional; if present, \var{expression} is only evaluated and added to +the result if \var{condition} is true. + +To make the semantics very clear, a list comprehension is equivalent +to the following Python code: + +\begin{verbatim} +for expr1 in sequence1: + for expr2 in sequence2: + ... + for exprN in sequenceN: + if (condition): + # Append the value of + # the expression to the + # resulting list. +\end{verbatim} + +This means that when there are multiple \keyword{for}...\keyword{in} clauses, +the resulting list will be equal to the product of the lengths of all +the sequences. If you have two lists of length 3, the output list is +9 elements long: + +\begin{verbatim} +seq1 = 'abc' +seq2 = (1,2,3) +>>> [ (x,y) for x in seq1 for y in seq2] +[('a', 1), ('a', 2), ('a', 3), ('b', 1), ('b', 2), ('b', 3), ('c', 1), +('c', 2), ('c', 3)] +\end{verbatim} + +To avoid introducing an ambiguity into Python's grammar, if +\var{expression} is creating a tuple, it must be surrounded with +parentheses. The first list comprehension below is a syntax error, +while the second one is correct: + +\begin{verbatim} +# Syntax error +[ x,y for x in seq1 for y in seq2] +# Correct +[ (x,y) for x in seq1 for y in seq2] +\end{verbatim} + +The idea of list comprehensions originally comes from the functional +programming language Haskell (\url{http://www.haskell.org}). Greg +Ewing argued most effectively for adding them to Python and wrote the +initial list comprehension patch, which was then discussed for a +seemingly endless time on the python-dev mailing list and kept +up-to-date by Skip Montanaro. + +% ====================================================================== +\section{Augmented Assignment} + +Augmented assignment operators, another long-requested feature, have +been added to Python 2.0. Augmented assignment operators include +\code{+=}, \code{-=}, \code{*=}, and so forth. For example, the +statement \code{a += 2} increments the value of the variable +\code{a} by 2, equivalent to the slightly lengthier \code{a = a + 2}. + +% The empty groups below prevent conversion to guillemets. +The full list of supported assignment operators is \code{+=}, +\code{-=}, \code{*=}, \code{/=}, \code{\%=}, \code{**=}, \code{\&=}, +\code{|=}, \verb|^=|, \code{>>=}, and \code{<<=}. Python classes can +override the augmented assignment operators by defining methods named +\method{__iadd__}, \method{__isub__}, etc. For example, the following +\class{Number} class stores a number and supports using += to create a +new instance with an incremented value. + +\begin{verbatim} +class Number: + def __init__(self, value): + self.value = value + def __iadd__(self, increment): + return Number( self.value + increment) + +n = Number(5) +n += 3 +print n.value +\end{verbatim} + +The \method{__iadd__} special method is called with the value of the +increment, and should return a new instance with an appropriately +modified value; this return value is bound as the new value of the +variable on the left-hand side. + +Augmented assignment operators were first introduced in the C +programming language, and most C-derived languages, such as +\program{awk}, \Cpp, Java, Perl, and PHP also support them. The augmented +assignment patch was implemented by Thomas Wouters. + +% ====================================================================== +\section{String Methods} + +Until now string-manipulation functionality was in the \module{string} +module, which was usually a front-end for the \module{strop} +module written in C. The addition of Unicode posed a difficulty for +the \module{strop} module, because the functions would all need to be +rewritten in order to accept either 8-bit or Unicode strings. For +functions such as \function{string.replace()}, which takes 3 string +arguments, that means eight possible permutations, and correspondingly +complicated code. + +Instead, Python 2.0 pushes the problem onto the string type, making +string manipulation functionality available through methods on both +8-bit strings and Unicode strings. + +\begin{verbatim} +>>> 'andrew'.capitalize() +'Andrew' +>>> 'hostname'.replace('os', 'linux') +'hlinuxtname' +>>> 'moshe'.find('sh') +2 +\end{verbatim} + +One thing that hasn't changed, a noteworthy April Fools' joke +notwithstanding, is that Python strings are immutable. Thus, the +string methods return new strings, and do not modify the string on +which they operate. + +The old \module{string} module is still around for backwards +compatibility, but it mostly acts as a front-end to the new string +methods. + +Two methods which have no parallel in pre-2.0 versions, although they +did exist in JPython for quite some time, are \method{startswith()} +and \method{endswith}. \code{s.startswith(t)} is equivalent to \code{s[:len(t)] +== t}, while \code{s.endswith(t)} is equivalent to \code{s[-len(t):] == t}. + +One other method which deserves special mention is \method{join}. The +\method{join} method of a string receives one parameter, a sequence of +strings, and is equivalent to the \function{string.join} function from +the old \module{string} module, with the arguments reversed. In other +words, \code{s.join(seq)} is equivalent to the old +\code{string.join(seq, s)}. + +% ====================================================================== +\section{Garbage Collection of Cycles} + +The C implementation of Python uses reference counting to implement +garbage collection. Every Python object maintains a count of the +number of references pointing to itself, and adjusts the count as +references are created or destroyed. Once the reference count reaches +zero, the object is no longer accessible, since you need to have a +reference to an object to access it, and if the count is zero, no +references exist any longer. + +Reference counting has some pleasant properties: it's easy to +understand and implement, and the resulting implementation is +portable, fairly fast, and reacts well with other libraries that +implement their own memory handling schemes. The major problem with +reference counting is that it sometimes doesn't realise that objects +are no longer accessible, resulting in a memory leak. This happens +when there are cycles of references. + +Consider the simplest possible cycle, +a class instance which has a reference to itself: + +\begin{verbatim} +instance = SomeClass() +instance.myself = instance +\end{verbatim} + +After the above two lines of code have been executed, the reference +count of \code{instance} is 2; one reference is from the variable +named \samp{'instance'}, and the other is from the \samp{myself} +attribute of the instance. + +If the next line of code is \code{del instance}, what happens? The +reference count of \code{instance} is decreased by 1, so it has a +reference count of 1; the reference in the \samp{myself} attribute +still exists. Yet the instance is no longer accessible through Python +code, and it could be deleted. Several objects can participate in a +cycle if they have references to each other, causing all of the +objects to be leaked. + +Python 2.0 fixes this problem by periodically executing a cycle +detection algorithm which looks for inaccessible cycles and deletes +the objects involved. A new \module{gc} module provides functions to +perform a garbage collection, obtain debugging statistics, and tuning +the collector's parameters. + +Running the cycle detection algorithm takes some time, and therefore +will result in some additional overhead. It is hoped that after we've +gotten experience with the cycle collection from using 2.0, Python 2.1 +will be able to minimize the overhead with careful tuning. It's not +yet obvious how much performance is lost, because benchmarking this is +tricky and depends crucially on how often the program creates and +destroys objects. The detection of cycles can be disabled when Python +is compiled, if you can't afford even a tiny speed penalty or suspect +that the cycle collection is buggy, by specifying the +\longprogramopt{without-cycle-gc} switch when running the +\program{configure} script. + +Several people tackled this problem and contributed to a solution. An +early implementation of the cycle detection approach was written by +Toby Kelsey. The current algorithm was suggested by Eric Tiedemann +during a visit to CNRI, and Guido van Rossum and Neil Schemenauer +wrote two different implementations, which were later integrated by +Neil. Lots of other people offered suggestions along the way; the +March 2000 archives of the python-dev mailing list contain most of the +relevant discussion, especially in the threads titled ``Reference +cycle collection for Python'' and ``Finalization again''. + +% ====================================================================== +\section{Other Core Changes} + +Various minor changes have been made to Python's syntax and built-in +functions. None of the changes are very far-reaching, but they're +handy conveniences. + +\subsection{Minor Language Changes} + +A new syntax makes it more convenient to call a given function +with a tuple of arguments and/or a dictionary of keyword arguments. +In Python 1.5 and earlier, you'd use the \function{apply()} +built-in function: \code{apply(f, \var{args}, \var{kw})} calls the +function \function{f()} with the argument tuple \var{args} and the +keyword arguments in the dictionary \var{kw}. \function{apply()} +is the same in 2.0, but thanks to a patch from +Greg Ewing, \code{f(*\var{args}, **\var{kw})} as a shorter +and clearer way to achieve the same effect. This syntax is +symmetrical with the syntax for defining functions: + +\begin{verbatim} +def f(*args, **kw): + # args is a tuple of positional args, + # kw is a dictionary of keyword args + ... +\end{verbatim} + +The \keyword{print} statement can now have its output directed to a +file-like object by following the \keyword{print} with +\verb|>> file|, similar to the redirection operator in \UNIX{} shells. +Previously you'd either have to use the \method{write()} method of the +file-like object, which lacks the convenience and simplicity of +\keyword{print}, or you could assign a new value to +\code{sys.stdout} and then restore the old value. For sending output to standard error, +it's much easier to write this: + +\begin{verbatim} +print >> sys.stderr, "Warning: action field not supplied" +\end{verbatim} + +Modules can now be renamed on importing them, using the syntax +\code{import \var{module} as \var{name}} or \code{from \var{module} +import \var{name} as \var{othername}}. The patch was submitted by +Thomas Wouters. + +A new format style is available when using the \code{\%} operator; +'\%r' will insert the \function{repr()} of its argument. This was +also added from symmetry considerations, this time for symmetry with +the existing '\%s' format style, which inserts the \function{str()} of +its argument. For example, \code{'\%r \%s' \% ('abc', 'abc')} returns a +string containing \verb|'abc' abc|. + +Previously there was no way to implement a class that overrode +Python's built-in \keyword{in} operator and implemented a custom +version. \code{\var{obj} in \var{seq}} returns true if \var{obj} is +present in the sequence \var{seq}; Python computes this by simply +trying every index of the sequence until either \var{obj} is found or +an \exception{IndexError} is encountered. Moshe Zadka contributed a +patch which adds a \method{__contains__} magic method for providing a +custom implementation for \keyword{in}. Additionally, new built-in +objects written in C can define what \keyword{in} means for them via a +new slot in the sequence protocol. + +Earlier versions of Python used a recursive algorithm for deleting +objects. Deeply nested data structures could cause the interpreter to +fill up the C stack and crash; Christian Tismer rewrote the deletion +logic to fix this problem. On a related note, comparing recursive +objects recursed infinitely and crashed; Jeremy Hylton rewrote the +code to no longer crash, producing a useful result instead. For +example, after this code: + +\begin{verbatim} +a = [] +b = [] +a.append(a) +b.append(b) +\end{verbatim} + +The comparison \code{a==b} returns true, because the two recursive +data structures are isomorphic. See the thread ``trashcan +and PR\#7'' in the April 2000 archives of the python-dev mailing list +for the discussion leading up to this implementation, and some useful +relevant links. +% Starting URL: +% http://www.python.org/pipermail/python-dev/2000-April/004834.html + +Note that comparisons can now also raise exceptions. In earlier +versions of Python, a comparison operation such as \code{cmp(a,b)} +would always produce an answer, even if a user-defined +\method{__cmp__} method encountered an error, since the resulting +exception would simply be silently swallowed. + +Work has been done on porting Python to 64-bit Windows on the Itanium +processor, mostly by Trent Mick of ActiveState. (Confusingly, +\code{sys.platform} is still \code{'win32'} on Win64 because it seems +that for ease of porting, MS Visual \Cpp{} treats code as 32 bit on Itanium.) +PythonWin also supports Windows CE; see the Python CE page at +\url{http://starship.python.net/crew/mhammond/ce/} for more +information. + +Another new platform is Darwin/MacOS X; initial support for it is in +Python 2.0. Dynamic loading works, if you specify ``configure +--with-dyld --with-suffix=.x''. Consult the README in the Python +source distribution for more instructions. + +An attempt has been made to alleviate one of Python's warts, the +often-confusing \exception{NameError} exception when code refers to a +local variable before the variable has been assigned a value. For +example, the following code raises an exception on the \keyword{print} +statement in both 1.5.2 and 2.0; in 1.5.2 a \exception{NameError} +exception is raised, while 2.0 raises a new +\exception{UnboundLocalError} exception. +\exception{UnboundLocalError} is a subclass of \exception{NameError}, +so any existing code that expects \exception{NameError} to be raised +should still work. + +\begin{verbatim} +def f(): + print "i=",i + i = i + 1 +f() +\end{verbatim} + +Two new exceptions, \exception{TabError} and +\exception{IndentationError}, have been introduced. They're both +subclasses of \exception{SyntaxError}, and are raised when Python code +is found to be improperly indented. + +\subsection{Changes to Built-in Functions} + +A new built-in, \function{zip(\var{seq1}, \var{seq2}, ...)}, has been +added. \function{zip()} returns a list of tuples where each tuple +contains the i-th element from each of the argument sequences. The +difference between \function{zip()} and \code{map(None, \var{seq1}, +\var{seq2})} is that \function{map()} pads the sequences with +\code{None} if the sequences aren't all of the same length, while +\function{zip()} truncates the returned list to the length of the +shortest argument sequence. + +The \function{int()} and \function{long()} functions now accept an +optional ``base'' parameter when the first argument is a string. +\code{int('123', 10)} returns 123, while \code{int('123', 16)} returns +291. \code{int(123, 16)} raises a \exception{TypeError} exception +with the message ``can't convert non-string with explicit base''. + +A new variable holding more detailed version information has been +added to the \module{sys} module. \code{sys.version_info} is a tuple +\code{(\var{major}, \var{minor}, \var{micro}, \var{level}, +\var{serial})} For example, in a hypothetical 2.0.1beta1, +\code{sys.version_info} would be \code{(2, 0, 1, 'beta', 1)}. +\var{level} is a string such as \code{"alpha"}, \code{"beta"}, or +\code{"final"} for a final release. + +Dictionaries have an odd new method, \method{setdefault(\var{key}, +\var{default})}, which behaves similarly to the existing +\method{get()} method. However, if the key is missing, +\method{setdefault()} both returns the value of \var{default} as +\method{get()} would do, and also inserts it into the dictionary as +the value for \var{key}. Thus, the following lines of code: + +\begin{verbatim} +if dict.has_key( key ): return dict[key] +else: + dict[key] = [] + return dict[key] +\end{verbatim} + +can be reduced to a single \code{return dict.setdefault(key, [])} statement. + +The interpreter sets a maximum recursion depth in order to catch +runaway recursion before filling the C stack and causing a core dump +or GPF.. Previously this limit was fixed when you compiled Python, +but in 2.0 the maximum recursion depth can be read and modified using +\function{sys.getrecursionlimit} and \function{sys.setrecursionlimit}. +The default value is 1000, and a rough maximum value for a given +platform can be found by running a new script, +\file{Misc/find_recursionlimit.py}. + +% ====================================================================== +\section{Porting to 2.0} + +New Python releases try hard to be compatible with previous releases, +and the record has been pretty good. However, some changes are +considered useful enough, usually because they fix initial design decisions that +turned out to be actively mistaken, that breaking backward compatibility +can't always be avoided. This section lists the changes in Python 2.0 +that may cause old Python code to break. + +The change which will probably break the most code is tightening up +the arguments accepted by some methods. Some methods would take +multiple arguments and treat them as a tuple, particularly various +list methods such as \method{.append()} and \method{.insert()}. +In earlier versions of Python, if \code{L} is a list, \code{L.append( +1,2 )} appends the tuple \code{(1,2)} to the list. In Python 2.0 this +causes a \exception{TypeError} exception to be raised, with the +message: 'append requires exactly 1 argument; 2 given'. The fix is to +simply add an extra set of parentheses to pass both values as a tuple: +\code{L.append( (1,2) )}. + +The earlier versions of these methods were more forgiving because they +used an old function in Python's C interface to parse their arguments; +2.0 modernizes them to use \function{PyArg_ParseTuple}, the current +argument parsing function, which provides more helpful error messages +and treats multi-argument calls as errors. If you absolutely must use +2.0 but can't fix your code, you can edit \file{Objects/listobject.c} +and define the preprocessor symbol \code{NO_STRICT_LIST_APPEND} to +preserve the old behaviour; this isn't recommended. + +Some of the functions in the \module{socket} module are still +forgiving in this way. For example, \function{socket.connect( +('hostname', 25) )} is the correct form, passing a tuple representing +an IP address, but \function{socket.connect( 'hostname', 25 )} also +works. \function{socket.connect_ex()} and \function{socket.bind()} are +similarly easy-going. 2.0alpha1 tightened these functions up, but +because the documentation actually used the erroneous multiple +argument form, many people wrote code which would break with the +stricter checking. GvR backed out the changes in the face of public +reaction, so for the \module{socket} module, the documentation was +fixed and the multiple argument form is simply marked as deprecated; +it \emph{will} be tightened up again in a future Python version. + +The \code{\e x} escape in string literals now takes exactly 2 hex +digits. Previously it would consume all the hex digits following the +'x' and take the lowest 8 bits of the result, so \code{\e x123456} was +equivalent to \code{\e x56}. + +The \exception{AttributeError} and \exception{NameError} exceptions +have a more friendly error message, whose text will be something like +\code{'Spam' instance has no attribute 'eggs'} or \code{name 'eggs' is +not defined}. Previously the error message was just the missing +attribute name \code{eggs}, and code written to take advantage of this +fact will break in 2.0. + +Some work has been done to make integers and long integers a bit more +interchangeable. In 1.5.2, large-file support was added for Solaris, +to allow reading files larger than 2~GiB; this made the \method{tell()} +method of file objects return a long integer instead of a regular +integer. Some code would subtract two file offsets and attempt to use +the result to multiply a sequence or slice a string, but this raised a +\exception{TypeError}. In 2.0, long integers can be used to multiply +or slice a sequence, and it'll behave as you'd intuitively expect it +to; \code{3L * 'abc'} produces 'abcabcabc', and \code{ +(0,1,2,3)[2L:4L]} produces (2,3). Long integers can also be used in +various contexts where previously only integers were accepted, such +as in the \method{seek()} method of file objects, and in the formats +supported by the \verb|%| operator (\verb|%d|, \verb|%i|, \verb|%x|, +etc.). For example, \code{"\%d" \% 2L**64} will produce the string +\samp{18446744073709551616}. + +The subtlest long integer change of all is that the \function{str()} +of a long integer no longer has a trailing 'L' character, though +\function{repr()} still includes it. The 'L' annoyed many people who +wanted to print long integers that looked just like regular integers, +since they had to go out of their way to chop off the character. This +is no longer a problem in 2.0, but code which does \code{str(longval)[:-1]} and assumes the 'L' is there, will now lose +the final digit. + +Taking the \function{repr()} of a float now uses a different +formatting precision than \function{str()}. \function{repr()} uses +\code{\%.17g} format string for C's \function{sprintf()}, while +\function{str()} uses \code{\%.12g} as before. The effect is that +\function{repr()} may occasionally show more decimal places than +\function{str()}, for certain numbers. +For example, the number 8.1 can't be represented exactly in binary, so +\code{repr(8.1)} is \code{'8.0999999999999996'}, while str(8.1) is +\code{'8.1'}. + +The \code{-X} command-line option, which turned all standard +exceptions into strings instead of classes, has been removed; the +standard exceptions will now always be classes. The +\module{exceptions} module containing the standard exceptions was +translated from Python to a built-in C module, written by Barry Warsaw +and Fredrik Lundh. + +% Commented out for now -- I don't think anyone will care. +%The pattern and match objects provided by SRE are C types, not Python +%class instances as in 1.5. This means you can no longer inherit from +%\class{RegexObject} or \class{MatchObject}, but that shouldn't be much +%of a problem since no one should have been doing that in the first +%place. + +% ====================================================================== +\section{Extending/Embedding Changes} + +Some of the changes are under the covers, and will only be apparent to +people writing C extension modules or embedding a Python interpreter +in a larger application. If you aren't dealing with Python's C API, +you can safely skip this section. + +The version number of the Python C API was incremented, so C +extensions compiled for 1.5.2 must be recompiled in order to work with +2.0. On Windows, it's not possible for Python 2.0 to import a third +party extension built for Python 1.5.x due to how Windows DLLs work, +so Python will raise an exception and the import will fail. + +Users of Jim Fulton's ExtensionClass module will be pleased to find +out that hooks have been added so that ExtensionClasses are now +supported by \function{isinstance()} and \function{issubclass()}. +This means you no longer have to remember to write code such as +\code{if type(obj) == myExtensionClass}, but can use the more natural +\code{if isinstance(obj, myExtensionClass)}. + +The \file{Python/importdl.c} file, which was a mass of \#ifdefs to +support dynamic loading on many different platforms, was cleaned up +and reorganised by Greg Stein. \file{importdl.c} is now quite small, +and platform-specific code has been moved into a bunch of +\file{Python/dynload_*.c} files. Another cleanup: there were also a +number of \file{my*.h} files in the Include/ directory that held +various portability hacks; they've been merged into a single file, +\file{Include/pyport.h}. + +Vladimir Marangozov's long-awaited malloc restructuring was completed, +to make it easy to have the Python interpreter use a custom allocator +instead of C's standard \function{malloc()}. For documentation, read +the comments in \file{Include/pymem.h} and +\file{Include/objimpl.h}. For the lengthy discussions during which +the interface was hammered out, see the Web archives of the 'patches' +and 'python-dev' lists at python.org. + +Recent versions of the GUSI development environment for MacOS support +POSIX threads. Therefore, Python's POSIX threading support now works +on the Macintosh. Threading support using the user-space GNU \texttt{pth} +library was also contributed. + +Threading support on Windows was enhanced, too. Windows supports +thread locks that use kernel objects only in case of contention; in +the common case when there's no contention, they use simpler functions +which are an order of magnitude faster. A threaded version of Python +1.5.2 on NT is twice as slow as an unthreaded version; with the 2.0 +changes, the difference is only 10\%. These improvements were +contributed by Yakov Markovitch. + +Python 2.0's source now uses only ANSI C prototypes, so compiling Python now +requires an ANSI C compiler, and can no longer be done using a compiler that +only supports K\&R C. + +Previously the Python virtual machine used 16-bit numbers in its +bytecode, limiting the size of source files. In particular, this +affected the maximum size of literal lists and dictionaries in Python +source; occasionally people who are generating Python code would run +into this limit. A patch by Charles G. Waldman raises the limit from +\verb|2^16| to \verb|2^{32}|. + +Three new convenience functions intended for adding constants to a +module's dictionary at module initialization time were added: +\function{PyModule_AddObject()}, \function{PyModule_AddIntConstant()}, +and \function{PyModule_AddStringConstant()}. Each of these functions +takes a module object, a null-terminated C string containing the name +to be added, and a third argument for the value to be assigned to the +name. This third argument is, respectively, a Python object, a C +long, or a C string. + +A wrapper API was added for \UNIX-style signal handlers. +\function{PyOS_getsig()} gets a signal handler and +\function{PyOS_setsig()} will set a new handler. + +% ====================================================================== +\section{Distutils: Making Modules Easy to Install} + +Before Python 2.0, installing modules was a tedious affair -- there +was no way to figure out automatically where Python is installed, or +what compiler options to use for extension modules. Software authors +had to go through an arduous ritual of editing Makefiles and +configuration files, which only really work on \UNIX{} and leave Windows +and MacOS unsupported. Python users faced wildly differing +installation instructions which varied between different extension +packages, which made administering a Python installation something of +a chore. + +The SIG for distribution utilities, shepherded by Greg Ward, has +created the Distutils, a system to make package installation much +easier. They form the \module{distutils} package, a new part of +Python's standard library. In the best case, installing a Python +module from source will require the same steps: first you simply mean +unpack the tarball or zip archive, and the run ``\code{python setup.py +install}''. The platform will be automatically detected, the compiler +will be recognized, C extension modules will be compiled, and the +distribution installed into the proper directory. Optional +command-line arguments provide more control over the installation +process, the distutils package offers many places to override defaults +-- separating the build from the install, building or installing in +non-default directories, and more. + +In order to use the Distutils, you need to write a \file{setup.py} +script. For the simple case, when the software contains only .py +files, a minimal \file{setup.py} can be just a few lines long: + +\begin{verbatim} +from distutils.core import setup +setup (name = "foo", version = "1.0", + py_modules = ["module1", "module2"]) +\end{verbatim} + +The \file{setup.py} file isn't much more complicated if the software +consists of a few packages: + +\begin{verbatim} +from distutils.core import setup +setup (name = "foo", version = "1.0", + packages = ["package", "package.subpackage"]) +\end{verbatim} + +A C extension can be the most complicated case; here's an example taken from +the PyXML package: + + +\begin{verbatim} +from distutils.core import setup, Extension + +expat_extension = Extension('xml.parsers.pyexpat', + define_macros = [('XML_NS', None)], + include_dirs = [ 'extensions/expat/xmltok', + 'extensions/expat/xmlparse' ], + sources = [ 'extensions/pyexpat.c', + 'extensions/expat/xmltok/xmltok.c', + 'extensions/expat/xmltok/xmlrole.c', + ] + ) +setup (name = "PyXML", version = "0.5.4", + ext_modules =[ expat_extension ] ) +\end{verbatim} + +The Distutils can also take care of creating source and binary +distributions. The ``sdist'' command, run by ``\code{python setup.py +sdist}', builds a source distribution such as \file{foo-1.0.tar.gz}. +Adding new commands isn't difficult, ``bdist_rpm'' and +``bdist_wininst'' commands have already been contributed to create an +RPM distribution and a Windows installer for the software, +respectively. Commands to create other distribution formats such as +Debian packages and Solaris \file{.pkg} files are in various stages of +development. + +All this is documented in a new manual, \textit{Distributing Python +Modules}, that joins the basic set of Python documentation. + +% ====================================================================== +\section{XML Modules} + +Python 1.5.2 included a simple XML parser in the form of the +\module{xmllib} module, contributed by Sjoerd Mullender. Since +1.5.2's release, two different interfaces for processing XML have +become common: SAX2 (version 2 of the Simple API for XML) provides an +event-driven interface with some similarities to \module{xmllib}, and +the DOM (Document Object Model) provides a tree-based interface, +transforming an XML document into a tree of nodes that can be +traversed and modified. Python 2.0 includes a SAX2 interface and a +stripped-down DOM interface as part of the \module{xml} package. +Here we will give a brief overview of these new interfaces; consult +the Python documentation or the source code for complete details. +The Python XML SIG is also working on improved documentation. + +\subsection{SAX2 Support} + +SAX defines an event-driven interface for parsing XML. To use SAX, +you must write a SAX handler class. Handler classes inherit from +various classes provided by SAX, and override various methods that +will then be called by the XML parser. For example, the +\method{startElement} and \method{endElement} methods are called for +every starting and end tag encountered by the parser, the +\method{characters()} method is called for every chunk of character +data, and so forth. + +The advantage of the event-driven approach is that the whole +document doesn't have to be resident in memory at any one time, which +matters if you are processing really huge documents. However, writing +the SAX handler class can get very complicated if you're trying to +modify the document structure in some elaborate way. + +For example, this little example program defines a handler that prints +a message for every starting and ending tag, and then parses the file +\file{hamlet.xml} using it: + +\begin{verbatim} +from xml import sax + +class SimpleHandler(sax.ContentHandler): + def startElement(self, name, attrs): + print 'Start of element:', name, attrs.keys() + + def endElement(self, name): + print 'End of element:', name + +# Create a parser object +parser = sax.make_parser() + +# Tell it what handler to use +handler = SimpleHandler() +parser.setContentHandler( handler ) + +# Parse a file! +parser.parse( 'hamlet.xml' ) +\end{verbatim} + +For more information, consult the Python documentation, or the XML +HOWTO at \url{http://pyxml.sourceforge.net/topics/howto/xml-howto.html}. + +\subsection{DOM Support} + +The Document Object Model is a tree-based representation for an XML +document. A top-level \class{Document} instance is the root of the +tree, and has a single child which is the top-level \class{Element} +instance. This \class{Element} has children nodes representing +character data and any sub-elements, which may have further children +of their own, and so forth. Using the DOM you can traverse the +resulting tree any way you like, access element and attribute values, +insert and delete nodes, and convert the tree back into XML. + +The DOM is useful for modifying XML documents, because you can create +a DOM tree, modify it by adding new nodes or rearranging subtrees, and +then produce a new XML document as output. You can also construct a +DOM tree manually and convert it to XML, which can be a more flexible +way of producing XML output than simply writing +\code{<tag1>}...\code{</tag1>} to a file. + +The DOM implementation included with Python lives in the +\module{xml.dom.minidom} module. It's a lightweight implementation of +the Level 1 DOM with support for XML namespaces. The +\function{parse()} and \function{parseString()} convenience +functions are provided for generating a DOM tree: + +\begin{verbatim} +from xml.dom import minidom +doc = minidom.parse('hamlet.xml') +\end{verbatim} + +\code{doc} is a \class{Document} instance. \class{Document}, like all +the other DOM classes such as \class{Element} and \class{Text}, is a +subclass of the \class{Node} base class. All the nodes in a DOM tree +therefore support certain common methods, such as \method{toxml()} +which returns a string containing the XML representation of the node +and its children. Each class also has special methods of its own; for +example, \class{Element} and \class{Document} instances have a method +to find all child elements with a given tag name. Continuing from the +previous 2-line example: + +\begin{verbatim} +perslist = doc.getElementsByTagName( 'PERSONA' ) +print perslist[0].toxml() +print perslist[1].toxml() +\end{verbatim} + +For the \textit{Hamlet} XML file, the above few lines output: + +\begin{verbatim} +<PERSONA>CLAUDIUS, king of Denmark. </PERSONA> +<PERSONA>HAMLET, son to the late, and nephew to the present king.</PERSONA> +\end{verbatim} + +The root element of the document is available as +\code{doc.documentElement}, and its children can be easily modified +by deleting, adding, or removing nodes: + +\begin{verbatim} +root = doc.documentElement + +# Remove the first child +root.removeChild( root.childNodes[0] ) + +# Move the new first child to the end +root.appendChild( root.childNodes[0] ) + +# Insert the new first child (originally, +# the third child) before the 20th child. +root.insertBefore( root.childNodes[0], root.childNodes[20] ) +\end{verbatim} + +Again, I will refer you to the Python documentation for a complete +listing of the different \class{Node} classes and their various methods. + +\subsection{Relationship to PyXML} + +The XML Special Interest Group has been working on XML-related Python +code for a while. Its code distribution, called PyXML, is available +from the SIG's Web pages at \url{http://www.python.org/sigs/xml-sig/}. +The PyXML distribution also used the package name \samp{xml}. If +you've written programs that used PyXML, you're probably wondering +about its compatibility with the 2.0 \module{xml} package. + +The answer is that Python 2.0's \module{xml} package isn't compatible +with PyXML, but can be made compatible by installing a recent version +PyXML. Many applications can get by with the XML support that is +included with Python 2.0, but more complicated applications will +require that the full PyXML package will be installed. When +installed, PyXML versions 0.6.0 or greater will replace the +\module{xml} package shipped with Python, and will be a strict +superset of the standard package, adding a bunch of additional +features. Some of the additional features in PyXML include: + +\begin{itemize} +\item 4DOM, a full DOM implementation +from FourThought, Inc. +\item The xmlproc validating parser, written by Lars Marius Garshol. +\item The \module{sgmlop} parser accelerator module, written by Fredrik Lundh. +\end{itemize} + +% ====================================================================== +\section{Module changes} + +Lots of improvements and bugfixes were made to Python's extensive +standard library; some of the affected modules include +\module{readline}, \module{ConfigParser}, \module{cgi}, +\module{calendar}, \module{posix}, \module{readline}, \module{xmllib}, +\module{aifc}, \module{chunk, wave}, \module{random}, \module{shelve}, +and \module{nntplib}. Consult the CVS logs for the exact +patch-by-patch details. + +Brian Gallew contributed OpenSSL support for the \module{socket} +module. OpenSSL is an implementation of the Secure Socket Layer, +which encrypts the data being sent over a socket. When compiling +Python, you can edit \file{Modules/Setup} to include SSL support, +which adds an additional function to the \module{socket} module: +\function{socket.ssl(\var{socket}, \var{keyfile}, \var{certfile})}, +which takes a socket object and returns an SSL socket. The +\module{httplib} and \module{urllib} modules were also changed to +support ``https://'' URLs, though no one has implemented FTP or SMTP +over SSL. + +The \module{httplib} module has been rewritten by Greg Stein to +support HTTP/1.1. Backward compatibility with the 1.5 version of +\module{httplib} is provided, though using HTTP/1.1 features such as +pipelining will require rewriting code to use a different set of +interfaces. + +The \module{Tkinter} module now supports Tcl/Tk version 8.1, 8.2, or +8.3, and support for the older 7.x versions has been dropped. The +Tkinter module now supports displaying Unicode strings in Tk widgets. +Also, Fredrik Lundh contributed an optimization which makes operations +like \code{create_line} and \code{create_polygon} much faster, +especially when using lots of coordinates. + +The \module{curses} module has been greatly extended, starting from +Oliver Andrich's enhanced version, to provide many additional +functions from ncurses and SYSV curses, such as colour, alternative +character set support, pads, and mouse support. This means the module +is no longer compatible with operating systems that only have BSD +curses, but there don't seem to be any currently maintained OSes that +fall into this category. + +As mentioned in the earlier discussion of 2.0's Unicode support, the +underlying implementation of the regular expressions provided by the +\module{re} module has been changed. SRE, a new regular expression +engine written by Fredrik Lundh and partially funded by Hewlett +Packard, supports matching against both 8-bit strings and Unicode +strings. + +% ====================================================================== +\section{New modules} + +A number of new modules were added. We'll simply list them with brief +descriptions; consult the 2.0 documentation for the details of a +particular module. + +\begin{itemize} + +\item{\module{atexit}}: +For registering functions to be called before the Python interpreter exits. +Code that currently sets +\code{sys.exitfunc} directly should be changed to +use the \module{atexit} module instead, importing \module{atexit} +and calling \function{atexit.register()} with +the function to be called on exit. +(Contributed by Skip Montanaro.) + +\item{\module{codecs}, \module{encodings}, \module{unicodedata}:} Added as part of the new Unicode support. + +\item{\module{filecmp}:} Supersedes the old \module{cmp}, \module{cmpcache} and +\module{dircmp} modules, which have now become deprecated. +(Contributed by Gordon MacMillan and Moshe Zadka.) + +\item{\module{gettext}:} This module provides internationalization +(I18N) and localization (L10N) support for Python programs by +providing an interface to the GNU gettext message catalog library. +(Integrated by Barry Warsaw, from separate contributions by Martin +von~L\"owis, Peter Funk, and James Henstridge.) + +\item{\module{linuxaudiodev}:} Support for the \file{/dev/audio} +device on Linux, a twin to the existing \module{sunaudiodev} module. +(Contributed by Peter Bosch, with fixes by Jeremy Hylton.) + +\item{\module{mmap}:} An interface to memory-mapped files on both +Windows and \UNIX. A file's contents can be mapped directly into +memory, at which point it behaves like a mutable string, so its +contents can be read and modified. They can even be passed to +functions that expect ordinary strings, such as the \module{re} +module. (Contributed by Sam Rushing, with some extensions by +A.M. Kuchling.) + +\item{\module{pyexpat}:} An interface to the Expat XML parser. +(Contributed by Paul Prescod.) + +\item{\module{robotparser}:} Parse a \file{robots.txt} file, which is +used for writing Web spiders that politely avoid certain areas of a +Web site. The parser accepts the contents of a \file{robots.txt} file, +builds a set of rules from it, and can then answer questions about +the fetchability of a given URL. (Contributed by Skip Montanaro.) + +\item{\module{tabnanny}:} A module/script to +check Python source code for ambiguous indentation. +(Contributed by Tim Peters.) + +\item{\module{UserString}:} A base class useful for deriving objects that behave like strings. + +\item{\module{webbrowser}:} A module that provides a platform independent +way to launch a web browser on a specific URL. For each platform, various +browsers are tried in a specific order. The user can alter which browser +is launched by setting the \var{BROWSER} environment variable. +(Originally inspired by Eric S. Raymond's patch to \module{urllib} +which added similar functionality, but +the final module comes from code originally +implemented by Fred Drake as \file{Tools/idle/BrowserControl.py}, +and adapted for the standard library by Fred.) + +\item{\module{_winreg}:} An interface to the +Windows registry. \module{_winreg} is an adaptation of functions that +have been part of PythonWin since 1995, but has now been added to the core +distribution, and enhanced to support Unicode. +\module{_winreg} was written by Bill Tutt and Mark Hammond. + +\item{\module{zipfile}:} A module for reading and writing ZIP-format +archives. These are archives produced by \program{PKZIP} on +DOS/Windows or \program{zip} on \UNIX, not to be confused with +\program{gzip}-format files (which are supported by the \module{gzip} +module) +(Contributed by James C. Ahlstrom.) + +\item{\module{imputil}:} A module that provides a simpler way for +writing customised import hooks, in comparison to the existing +\module{ihooks} module. (Implemented by Greg Stein, with much +discussion on python-dev along the way.) + +\end{itemize} + +% ====================================================================== +\section{IDLE Improvements} + +IDLE is the official Python cross-platform IDE, written using Tkinter. +Python 2.0 includes IDLE 0.6, which adds a number of new features and +improvements. A partial list: + +\begin{itemize} +\item UI improvements and optimizations, +especially in the area of syntax highlighting and auto-indentation. + +\item The class browser now shows more information, such as the top +level functions in a module. + +\item Tab width is now a user settable option. When opening an existing Python +file, IDLE automatically detects the indentation conventions, and adapts. + +\item There is now support for calling browsers on various platforms, +used to open the Python documentation in a browser. + +\item IDLE now has a command line, which is largely similar to +the vanilla Python interpreter. + +\item Call tips were added in many places. + +\item IDLE can now be installed as a package. + +\item In the editor window, there is now a line/column bar at the bottom. + +\item Three new keystroke commands: Check module (Alt-F5), Import +module (F5) and Run script (Ctrl-F5). + +\end{itemize} + +% ====================================================================== +\section{Deleted and Deprecated Modules} + +A few modules have been dropped because they're obsolete, or because +there are now better ways to do the same thing. The \module{stdwin} +module is gone; it was for a platform-independent windowing toolkit +that's no longer developed. + +A number of modules have been moved to the +\file{lib-old} subdirectory: +\module{cmp}, \module{cmpcache}, \module{dircmp}, \module{dump}, +\module{find}, \module{grep}, \module{packmail}, +\module{poly}, \module{util}, \module{whatsound}, \module{zmod}. +If you have code which relies on a module that's been moved to +\file{lib-old}, you can simply add that directory to \code{sys.path} +to get them back, but you're encouraged to update any code that uses +these modules. + +\section{Acknowledgements} + +The authors would like to thank the following people for offering +suggestions on various drafts of this article: David Bolen, Mark +Hammond, Gregg Hauser, Jeremy Hylton, Fredrik Lundh, Detlef Lannert, +Aahz Maruch, Skip Montanaro, Vladimir Marangozov, Tobias Polzin, Guido +van Rossum, Neil Schemenauer, and Russ Schmidt. + +\end{document} diff --git a/sys/src/cmd/python/Doc/whatsnew/whatsnew21.tex b/sys/src/cmd/python/Doc/whatsnew/whatsnew21.tex new file mode 100644 index 000000000..53a179bfb --- /dev/null +++ b/sys/src/cmd/python/Doc/whatsnew/whatsnew21.tex @@ -0,0 +1,868 @@ +\documentclass{howto} + +\usepackage{distutils} + +% $Id: whatsnew21.tex 50964 2006-07-30 03:03:43Z fred.drake $ + +\title{What's New in Python 2.1} +\release{1.01} +\author{A.M. Kuchling} +\authoraddress{ + \strong{Python Software Foundation}\\ + Email: \email{amk@amk.ca} +} +\begin{document} +\maketitle\tableofcontents + +\section{Introduction} + +This article explains the new features in Python 2.1. While there aren't as +many changes in 2.1 as there were in Python 2.0, there are still some +pleasant surprises in store. 2.1 is the first release to be steered +through the use of Python Enhancement Proposals, or PEPs, so most of +the sizable changes have accompanying PEPs that provide more complete +documentation and a design rationale for the change. This article +doesn't attempt to document the new features completely, but simply +provides an overview of the new features for Python programmers. +Refer to the Python 2.1 documentation, or to the specific PEP, for +more details about any new feature that particularly interests you. + +One recent goal of the Python development team has been to accelerate +the pace of new releases, with a new release coming every 6 to 9 +months. 2.1 is the first release to come out at this faster pace, with +the first alpha appearing in January, 3 months after the final version +of 2.0 was released. + +The final release of Python 2.1 was made on April 17, 2001. + +%====================================================================== +\section{PEP 227: Nested Scopes} + +The largest change in Python 2.1 is to Python's scoping rules. In +Python 2.0, at any given time there are at most three namespaces used +to look up variable names: local, module-level, and the built-in +namespace. This often surprised people because it didn't match their +intuitive expectations. For example, a nested recursive function +definition doesn't work: + +\begin{verbatim} +def f(): + ... + def g(value): + ... + return g(value-1) + 1 + ... +\end{verbatim} + +The function \function{g()} will always raise a \exception{NameError} +exception, because the binding of the name \samp{g} isn't in either +its local namespace or in the module-level namespace. This isn't much +of a problem in practice (how often do you recursively define interior +functions like this?), but this also made using the \keyword{lambda} +statement clumsier, and this was a problem in practice. In code which +uses \keyword{lambda} you can often find local variables being copied +by passing them as the default values of arguments. + +\begin{verbatim} +def find(self, name): + "Return list of any entries equal to 'name'" + L = filter(lambda x, name=name: x == name, + self.list_attribute) + return L +\end{verbatim} + +The readability of Python code written in a strongly functional style +suffers greatly as a result. + +The most significant change to Python 2.1 is that static scoping has +been added to the language to fix this problem. As a first effect, +the \code{name=name} default argument is now unnecessary in the above +example. Put simply, when a given variable name is not assigned a +value within a function (by an assignment, or the \keyword{def}, +\keyword{class}, or \keyword{import} statements), references to the +variable will be looked up in the local namespace of the enclosing +scope. A more detailed explanation of the rules, and a dissection of +the implementation, can be found in the PEP. + +This change may cause some compatibility problems for code where the +same variable name is used both at the module level and as a local +variable within a function that contains further function definitions. +This seems rather unlikely though, since such code would have been +pretty confusing to read in the first place. + +One side effect of the change is that the \code{from \var{module} +import *} and \keyword{exec} statements have been made illegal inside +a function scope under certain conditions. The Python reference +manual has said all along that \code{from \var{module} import *} is +only legal at the top level of a module, but the CPython interpreter +has never enforced this before. As part of the implementation of +nested scopes, the compiler which turns Python source into bytecodes +has to generate different code to access variables in a containing +scope. \code{from \var{module} import *} and \keyword{exec} make it +impossible for the compiler to figure this out, because they add names +to the local namespace that are unknowable at compile time. +Therefore, if a function contains function definitions or +\keyword{lambda} expressions with free variables, the compiler will +flag this by raising a \exception{SyntaxError} exception. + +To make the preceding explanation a bit clearer, here's an example: + +\begin{verbatim} +x = 1 +def f(): + # The next line is a syntax error + exec 'x=2' + def g(): + return x +\end{verbatim} + +Line 4 containing the \keyword{exec} statement is a syntax error, +since \keyword{exec} would define a new local variable named \samp{x} +whose value should be accessed by \function{g()}. + +This shouldn't be much of a limitation, since \keyword{exec} is rarely +used in most Python code (and when it is used, it's often a sign of a +poor design anyway). + +Compatibility concerns have led to nested scopes being introduced +gradually; in Python 2.1, they aren't enabled by default, but can be +turned on within a module by using a future statement as described in +PEP 236. (See the following section for further discussion of PEP +236.) In Python 2.2, nested scopes will become the default and there +will be no way to turn them off, but users will have had all of 2.1's +lifetime to fix any breakage resulting from their introduction. + +\begin{seealso} + +\seepep{227}{Statically Nested Scopes}{Written and implemented by +Jeremy Hylton.} + +\end{seealso} + + +%====================================================================== +\section{PEP 236: __future__ Directives} + +The reaction to nested scopes was widespread concern about the dangers +of breaking code with the 2.1 release, and it was strong enough to +make the Pythoneers take a more conservative approach. This approach +consists of introducing a convention for enabling optional +functionality in release N that will become compulsory in release N+1. + +The syntax uses a \code{from...import} statement using the reserved +module name \module{__future__}. Nested scopes can be enabled by the +following statement: + +\begin{verbatim} +from __future__ import nested_scopes +\end{verbatim} + +While it looks like a normal \keyword{import} statement, it's not; +there are strict rules on where such a future statement can be put. +They can only be at the top of a module, and must precede any Python +code or regular \keyword{import} statements. This is because such +statements can affect how the Python bytecode compiler parses code and +generates bytecode, so they must precede any statement that will +result in bytecodes being produced. + +\begin{seealso} + +\seepep{236}{Back to the \module{__future__}}{Written by Tim Peters, +and primarily implemented by Jeremy Hylton.} + +\end{seealso} + +%====================================================================== +\section{PEP 207: Rich Comparisons} + +In earlier versions, Python's support for implementing comparisons on +user-defined classes and extension types was quite simple. Classes +could implement a \method{__cmp__} method that was given two instances +of a class, and could only return 0 if they were equal or +1 or -1 if +they weren't; the method couldn't raise an exception or return +anything other than a Boolean value. Users of Numeric Python often +found this model too weak and restrictive, because in the +number-crunching programs that numeric Python is used for, it would be +more useful to be able to perform elementwise comparisons of two +matrices, returning a matrix containing the results of a given +comparison for each element. If the two matrices are of different +sizes, then the compare has to be able to raise an exception to signal +the error. + +In Python 2.1, rich comparisons were added in order to support this +need. Python classes can now individually overload each of the +\code{<}, \code{<=}, \code{>}, \code{>=}, \code{==}, and \code{!=} +operations. The new magic method names are: + +\begin{tableii}{c|l}{code}{Operation}{Method name} + \lineii{<}{\method{__lt__}} \lineii{<=}{\method{__le__}} + \lineii{>}{\method{__gt__}} \lineii{>=}{\method{__ge__}} + \lineii{==}{\method{__eq__}} \lineii{!=}{\method{__ne__}} + \end{tableii} + +(The magic methods are named after the corresponding Fortran operators +\code{.LT.}. \code{.LE.}, \&c. Numeric programmers are almost +certainly quite familiar with these names and will find them easy to +remember.) + +Each of these magic methods is of the form \code{\var{method}(self, +other)}, where \code{self} will be the object on the left-hand side of +the operator, while \code{other} will be the object on the right-hand +side. For example, the expression \code{A < B} will cause +\code{A.__lt__(B)} to be called. + +Each of these magic methods can return anything at all: a Boolean, a +matrix, a list, or any other Python object. Alternatively they can +raise an exception if the comparison is impossible, inconsistent, or +otherwise meaningless. + +The built-in \function{cmp(A,B)} function can use the rich comparison +machinery, and now accepts an optional argument specifying which +comparison operation to use; this is given as one of the strings +\code{"<"}, \code{"<="}, \code{">"}, \code{">="}, \code{"=="}, or +\code{"!="}. If called without the optional third argument, +\function{cmp()} will only return -1, 0, or +1 as in previous versions +of Python; otherwise it will call the appropriate method and can +return any Python object. + +There are also corresponding changes of interest to C programmers; +there's a new slot \code{tp_richcmp} in type objects and an API for +performing a given rich comparison. I won't cover the C API here, but +will refer you to PEP 207, or to 2.1's C API documentation, for the +full list of related functions. + +\begin{seealso} + +\seepep{207}{Rich Comparisions}{Written by Guido van Rossum, heavily +based on earlier work by David Ascher, and implemented by Guido van +Rossum.} + +\end{seealso} + +%====================================================================== +\section{PEP 230: Warning Framework} + +Over its 10 years of existence, Python has accumulated a certain +number of obsolete modules and features along the way. It's difficult +to know when a feature is safe to remove, since there's no way of +knowing how much code uses it --- perhaps no programs depend on the +feature, or perhaps many do. To enable removing old features in a +more structured way, a warning framework was added. When the Python +developers want to get rid of a feature, it will first trigger a +warning in the next version of Python. The following Python version +can then drop the feature, and users will have had a full release +cycle to remove uses of the old feature. + +Python 2.1 adds the warning framework to be used in this scheme. It +adds a \module{warnings} module that provide functions to issue +warnings, and to filter out warnings that you don't want to be +displayed. Third-party modules can also use this framework to +deprecate old features that they no longer wish to support. + +For example, in Python 2.1 the \module{regex} module is deprecated, so +importing it causes a warning to be printed: + +\begin{verbatim} +>>> import regex +__main__:1: DeprecationWarning: the regex module + is deprecated; please use the re module +>>> +\end{verbatim} + +Warnings can be issued by calling the \function{warnings.warn} +function: + +\begin{verbatim} +warnings.warn("feature X no longer supported") +\end{verbatim} + +The first parameter is the warning message; an additional optional +parameters can be used to specify a particular warning category. + +Filters can be added to disable certain warnings; a regular expression +pattern can be applied to the message or to the module name in order +to suppress a warning. For example, you may have a program that uses +the \module{regex} module and not want to spare the time to convert it +to use the \module{re} module right now. The warning can be +suppressed by calling + +\begin{verbatim} +import warnings +warnings.filterwarnings(action = 'ignore', + message='.*regex module is deprecated', + category=DeprecationWarning, + module = '__main__') +\end{verbatim} + +This adds a filter that will apply only to warnings of the class +\class{DeprecationWarning} triggered in the \module{__main__} module, +and applies a regular expression to only match the message about the +\module{regex} module being deprecated, and will cause such warnings +to be ignored. Warnings can also be printed only once, printed every +time the offending code is executed, or turned into exceptions that +will cause the program to stop (unless the exceptions are caught in +the usual way, of course). + +Functions were also added to Python's C API for issuing warnings; +refer to PEP 230 or to Python's API documentation for the details. + +\begin{seealso} + +\seepep{5}{Guidelines for Language Evolution}{Written +by Paul Prescod, to specify procedures to be followed when removing +old features from Python. The policy described in this PEP hasn't +been officially adopted, but the eventual policy probably won't be too +different from Prescod's proposal.} + +\seepep{230}{Warning Framework}{Written and implemented by Guido van +Rossum.} + +\end{seealso} + +%====================================================================== +\section{PEP 229: New Build System} + +When compiling Python, the user had to go in and edit the +\file{Modules/Setup} file in order to enable various additional +modules; the default set is relatively small and limited to modules +that compile on most \UNIX{} platforms. This means that on \Unix{} +platforms with many more features, most notably Linux, Python +installations often don't contain all useful modules they could. + +Python 2.0 added the Distutils, a set of modules for distributing and +installing extensions. In Python 2.1, the Distutils are used to +compile much of the standard library of extension modules, +autodetecting which ones are supported on the current machine. It's +hoped that this will make Python installations easier and more +featureful. + +Instead of having to edit the \file{Modules/Setup} file in order to +enable modules, a \file{setup.py} script in the top directory of the +Python source distribution is run at build time, and attempts to +discover which modules can be enabled by examining the modules and +header files on the system. If a module is configured in +\file{Modules/Setup}, the \file{setup.py} script won't attempt to +compile that module and will defer to the \file{Modules/Setup} file's +contents. This provides a way to specific any strange command-line +flags or libraries that are required for a specific platform. + +In another far-reaching change to the build mechanism, Neil +Schemenauer restructured things so Python now uses a single makefile +that isn't recursive, instead of makefiles in the top directory and in +each of the \file{Python/}, \file{Parser/}, \file{Objects/}, and +\file{Modules/} subdirectories. This makes building Python faster +and also makes hacking the Makefiles clearer and simpler. + +\begin{seealso} + +\seepep{229}{Using Distutils to Build Python}{Written +and implemented by A.M. Kuchling.} + +\end{seealso} + +%====================================================================== +\section{PEP 205: Weak References} + +Weak references, available through the \module{weakref} module, are a +minor but useful new data type in the Python programmer's toolbox. + +Storing a reference to an object (say, in a dictionary or a list) has +the side effect of keeping that object alive forever. There are a few +specific cases where this behaviour is undesirable, object caches +being the most common one, and another being circular references in +data structures such as trees. + +For example, consider a memoizing function that caches the results of +another function \function{f(\var{x})} by storing the function's +argument and its result in a dictionary: + +\begin{verbatim} +_cache = {} +def memoize(x): + if _cache.has_key(x): + return _cache[x] + + retval = f(x) + + # Cache the returned object + _cache[x] = retval + + return retval +\end{verbatim} + +This version works for simple things such as integers, but it has a +side effect; the \code{_cache} dictionary holds a reference to the +return values, so they'll never be deallocated until the Python +process exits and cleans up This isn't very noticeable for integers, +but if \function{f()} returns an object, or a data structure that +takes up a lot of memory, this can be a problem. + +Weak references provide a way to implement a cache that won't keep +objects alive beyond their time. If an object is only accessible +through weak references, the object will be deallocated and the weak +references will now indicate that the object it referred to no longer +exists. A weak reference to an object \var{obj} is created by calling +\code{wr = weakref.ref(\var{obj})}. The object being referred to is +returned by calling the weak reference as if it were a function: +\code{wr()}. It will return the referenced object, or \code{None} if +the object no longer exists. + +This makes it possible to write a \function{memoize()} function whose +cache doesn't keep objects alive, by storing weak references in the +cache. + +\begin{verbatim} +_cache = {} +def memoize(x): + if _cache.has_key(x): + obj = _cache[x]() + # If weak reference object still exists, + # return it + if obj is not None: return obj + + retval = f(x) + + # Cache a weak reference + _cache[x] = weakref.ref(retval) + + return retval +\end{verbatim} + +The \module{weakref} module also allows creating proxy objects which +behave like weak references --- an object referenced only by proxy +objects is deallocated -- but instead of requiring an explicit call to +retrieve the object, the proxy transparently forwards all operations +to the object as long as the object still exists. If the object is +deallocated, attempting to use a proxy will cause a +\exception{weakref.ReferenceError} exception to be raised. + +\begin{verbatim} +proxy = weakref.proxy(obj) +proxy.attr # Equivalent to obj.attr +proxy.meth() # Equivalent to obj.meth() +del obj +proxy.attr # raises weakref.ReferenceError +\end{verbatim} + +\begin{seealso} + +\seepep{205}{Weak References}{Written and implemented by +Fred~L. Drake,~Jr.} + +\end{seealso} + +%====================================================================== +\section{PEP 232: Function Attributes} + +In Python 2.1, functions can now have arbitrary information attached +to them. People were often using docstrings to hold information about +functions and methods, because the \code{__doc__} attribute was the +only way of attaching any information to a function. For example, in +the Zope Web application server, functions are marked as safe for +public access by having a docstring, and in John Aycock's SPARK +parsing framework, docstrings hold parts of the BNF grammar to be +parsed. This overloading is unfortunate, since docstrings are really +intended to hold a function's documentation; for example, it means you +can't properly document functions intended for private use in Zope. + +Arbitrary attributes can now be set and retrieved on functions using the +regular Python syntax: + +\begin{verbatim} +def f(): pass + +f.publish = 1 +f.secure = 1 +f.grammar = "A ::= B (C D)*" +\end{verbatim} + +The dictionary containing attributes can be accessed as the function's +\member{__dict__}. Unlike the \member{__dict__} attribute of class +instances, in functions you can actually assign a new dictionary to +\member{__dict__}, though the new value is restricted to a regular +Python dictionary; you \emph{can't} be tricky and set it to a +\class{UserDict} instance, or any other random object that behaves +like a mapping. + +\begin{seealso} + +\seepep{232}{Function Attributes}{Written and implemented by Barry +Warsaw.} + +\end{seealso} + + +%====================================================================== + +\section{PEP 235: Importing Modules on Case-Insensitive Platforms} + +Some operating systems have filesystems that are case-insensitive, +MacOS and Windows being the primary examples; on these systems, it's +impossible to distinguish the filenames \samp{FILE.PY} and +\samp{file.py}, even though they do store the file's name +in its original case (they're case-preserving, too). + +In Python 2.1, the \keyword{import} statement will work to simulate +case-sensitivity on case-insensitive platforms. Python will now +search for the first case-sensitive match by default, raising an +\exception{ImportError} if no such file is found, so \code{import file} +will not import a module named \samp{FILE.PY}. Case-insensitive +matching can be requested by setting the \envvar{PYTHONCASEOK} environment +variable before starting the Python interpreter. + +%====================================================================== +\section{PEP 217: Interactive Display Hook} + +When using the Python interpreter interactively, the output of +commands is displayed using the built-in \function{repr()} function. +In Python 2.1, the variable \function{sys.displayhook} can be set to a +callable object which will be called instead of \function{repr()}. +For example, you can set it to a special pretty-printing function: + +\begin{verbatim} +>>> # Create a recursive data structure +... L = [1,2,3] +>>> L.append(L) +>>> L # Show Python's default output +[1, 2, 3, [...]] +>>> # Use pprint.pprint() as the display function +... import sys, pprint +>>> sys.displayhook = pprint.pprint +>>> L +[1, 2, 3, <Recursion on list with id=135143996>] +>>> +\end{verbatim} + +\begin{seealso} + +\seepep{217}{Display Hook for Interactive Use}{Written and implemented +by Moshe Zadka.} + +\end{seealso} + +%====================================================================== +\section{PEP 208: New Coercion Model} + +How numeric coercion is done at the C level was significantly +modified. This will only affect the authors of C extensions to +Python, allowing them more flexibility in writing extension types that +support numeric operations. + +Extension types can now set the type flag \code{Py_TPFLAGS_CHECKTYPES} +in their \code{PyTypeObject} structure to indicate that they support +the new coercion model. In such extension types, the numeric slot +functions can no longer assume that they'll be passed two arguments of +the same type; instead they may be passed two arguments of differing +types, and can then perform their own internal coercion. If the slot +function is passed a type it can't handle, it can indicate the failure +by returning a reference to the \code{Py_NotImplemented} singleton +value. The numeric functions of the other type will then be tried, +and perhaps they can handle the operation; if the other type also +returns \code{Py_NotImplemented}, then a \exception{TypeError} will be +raised. Numeric methods written in Python can also return +\code{Py_NotImplemented}, causing the interpreter to act as if the +method did not exist (perhaps raising a \exception{TypeError}, perhaps +trying another object's numeric methods). + +\begin{seealso} + +\seepep{208}{Reworking the Coercion Model}{Written and implemented by +Neil Schemenauer, heavily based upon earlier work by Marc-Andr\'e +Lemburg. Read this to understand the fine points of how numeric +operations will now be processed at the C level.} + +\end{seealso} + +%====================================================================== +\section{PEP 241: Metadata in Python Packages} + +A common complaint from Python users is that there's no single catalog +of all the Python modules in existence. T.~Middleton's Vaults of +Parnassus at \url{http://www.vex.net/parnassus/} are the largest +catalog of Python modules, but registering software at the Vaults is +optional, and many people don't bother. + +As a first small step toward fixing the problem, Python software +packaged using the Distutils \command{sdist} command will include a +file named \file{PKG-INFO} containing information about the package +such as its name, version, and author (metadata, in cataloguing +terminology). PEP 241 contains the full list of fields that can be +present in the \file{PKG-INFO} file. As people began to package their +software using Python 2.1, more and more packages will include +metadata, making it possible to build automated cataloguing systems +and experiment with them. With the result experience, perhaps it'll +be possible to design a really good catalog and then build support for +it into Python 2.2. For example, the Distutils \command{sdist} +and \command{bdist_*} commands could support a \option{upload} option +that would automatically upload your package to a catalog server. + +You can start creating packages containing \file{PKG-INFO} even if +you're not using Python 2.1, since a new release of the Distutils will +be made for users of earlier Python versions. Version 1.0.2 of the +Distutils includes the changes described in PEP 241, as well as +various bugfixes and enhancements. It will be available from +the Distutils SIG at \url{http://www.python.org/sigs/distutils-sig/}. + +\begin{seealso} + +\seepep{241}{Metadata for Python Software Packages}{Written and +implemented by A.M. Kuchling.} + +\seepep{243}{Module Repository Upload Mechanism}{Written by Sean +Reifschneider, this draft PEP describes a proposed mechanism for uploading +Python packages to a central server. +} + +\end{seealso} + +%====================================================================== +\section{New and Improved Modules} + +\begin{itemize} + +\item Ka-Ping Yee contributed two new modules: \module{inspect.py}, a +module for getting information about live Python code, and +\module{pydoc.py}, a module for interactively converting docstrings to +HTML or text. As a bonus, \file{Tools/scripts/pydoc}, which is now +automatically installed, uses \module{pydoc.py} to display +documentation given a Python module, package, or class name. For +example, \samp{pydoc xml.dom} displays the following: + +\begin{verbatim} +Python Library Documentation: package xml.dom in xml + +NAME + xml.dom - W3C Document Object Model implementation for Python. + +FILE + /usr/local/lib/python2.1/xml/dom/__init__.pyc + +DESCRIPTION + The Python mapping of the Document Object Model is documented in the + Python Library Reference in the section on the xml.dom package. + + This package contains the following modules: + ... +\end{verbatim} + +\file{pydoc} also includes a Tk-based interactive help browser. +\file{pydoc} quickly becomes addictive; try it out! + +\item Two different modules for unit testing were added to the +standard library. The \module{doctest} module, contributed by Tim +Peters, provides a testing framework based on running embedded +examples in docstrings and comparing the results against the expected +output. PyUnit, contributed by Steve Purcell, is a unit testing +framework inspired by JUnit, which was in turn an adaptation of Kent +Beck's Smalltalk testing framework. See +\url{http://pyunit.sourceforge.net/} for more information about +PyUnit. + +\item The \module{difflib} module contains a class, +\class{SequenceMatcher}, which compares two sequences and computes the +changes required to transform one sequence into the other. For +example, this module can be used to write a tool similar to the \UNIX{} +\program{diff} program, and in fact the sample program +\file{Tools/scripts/ndiff.py} demonstrates how to write such a script. + +\item \module{curses.panel}, a wrapper for the panel library, part of +ncurses and of SYSV curses, was contributed by Thomas Gellekum. The +panel library provides windows with the additional feature of depth. +Windows can be moved higher or lower in the depth ordering, and the +panel library figures out where panels overlap and which sections are +visible. + +\item The PyXML package has gone through a few releases since Python +2.0, and Python 2.1 includes an updated version of the \module{xml} +package. Some of the noteworthy changes include support for Expat 1.2 +and later versions, the ability for Expat parsers to handle files in +any encoding supported by Python, and various bugfixes for SAX, DOM, +and the \module{minidom} module. + +\item Ping also contributed another hook for handling uncaught +exceptions. \function{sys.excepthook} can be set to a callable +object. When an exception isn't caught by any +\keyword{try}...\keyword{except} blocks, the exception will be passed +to \function{sys.excepthook}, which can then do whatever it likes. At +the Ninth Python Conference, Ping demonstrated an application for this +hook: printing an extended traceback that not only lists the stack +frames, but also lists the function arguments and the local variables +for each frame. + +\item Various functions in the \module{time} module, such as +\function{asctime()} and \function{localtime()}, require a floating +point argument containing the time in seconds since the epoch. The +most common use of these functions is to work with the current time, +so the floating point argument has been made optional; when a value +isn't provided, the current time will be used. For example, log file +entries usually need a string containing the current time; in Python +2.1, \code{time.asctime()} can be used, instead of the lengthier +\code{time.asctime(time.localtime(time.time()))} that was previously +required. + +This change was proposed and implemented by Thomas Wouters. + +\item The \module{ftplib} module now defaults to retrieving files in +passive mode, because passive mode is more likely to work from behind +a firewall. This request came from the Debian bug tracking system, +since other Debian packages use \module{ftplib} to retrieve files and +then don't work from behind a firewall. It's deemed unlikely that +this will cause problems for anyone, because Netscape defaults to +passive mode and few people complain, but if passive mode is +unsuitable for your application or network setup, call +\method{set_pasv(0)} on FTP objects to disable passive mode. + +\item Support for raw socket access has been added to the +\module{socket} module, contributed by Grant Edwards. + +\item The \module{pstats} module now contains a simple interactive +statistics browser for displaying timing profiles for Python programs, +invoked when the module is run as a script. Contributed by +Eric S.\ Raymond. + +\item A new implementation-dependent function, \function{sys._getframe(\optional{depth})}, +has been added to return a given frame object from the current call stack. +\function{sys._getframe()} returns the frame at the top of the call stack; +if the optional integer argument \var{depth} is supplied, the function returns the frame +that is \var{depth} calls below the top of the stack. For example, \code{sys._getframe(1)} +returns the caller's frame object. + +This function is only present in CPython, not in Jython or the .NET +implementation. Use it for debugging, and resist the temptation to +put it into production code. + + + +\end{itemize} + +%====================================================================== +\section{Other Changes and Fixes} + +There were relatively few smaller changes made in Python 2.1 due to +the shorter release cycle. A search through the CVS change logs turns +up 117 patches applied, and 136 bugs fixed; both figures are likely to +be underestimates. Some of the more notable changes are: + +\begin{itemize} + + +\item A specialized object allocator is now optionally available, that +should be faster than the system \function{malloc()} and have less +memory overhead. The allocator uses C's \function{malloc()} function +to get large pools of memory, and then fulfills smaller memory +requests from these pools. It can be enabled by providing the +\longprogramopt{with-pymalloc} option to the \program{configure} script; see +\file{Objects/obmalloc.c} for the implementation details. + +Authors of C extension modules should test their code with the object +allocator enabled, because some incorrect code may break, causing core +dumps at runtime. There are a bunch of memory allocation functions in +Python's C API that have previously been just aliases for the C +library's \function{malloc()} and \function{free()}, meaning that if +you accidentally called mismatched functions, the error wouldn't be +noticeable. When the object allocator is enabled, these functions +aren't aliases of \function{malloc()} and \function{free()} any more, +and calling the wrong function to free memory will get you a core +dump. For example, if memory was allocated using +\function{PyMem_New()}, it has to be freed using +\function{PyMem_Del()}, not \function{free()}. A few modules included +with Python fell afoul of this and had to be fixed; doubtless there +are more third-party modules that will have the same problem. + +The object allocator was contributed by Vladimir Marangozov. + +\item The speed of line-oriented file I/O has been improved because +people often complain about its lack of speed, and because it's often +been used as a na\"ive benchmark. The \method{readline()} method of +file objects has therefore been rewritten to be much faster. The +exact amount of the speedup will vary from platform to platform +depending on how slow the C library's \function{getc()} was, but is +around 66\%, and potentially much faster on some particular operating +systems. Tim Peters did much of the benchmarking and coding for this +change, motivated by a discussion in comp.lang.python. + +A new module and method for file objects was also added, contributed +by Jeff Epler. The new method, \method{xreadlines()}, is similar to +the existing \function{xrange()} built-in. \function{xreadlines()} +returns an opaque sequence object that only supports being iterated +over, reading a line on every iteration but not reading the entire +file into memory as the existing \method{readlines()} method does. +You'd use it like this: + +\begin{verbatim} +for line in sys.stdin.xreadlines(): + # ... do something for each line ... + ... +\end{verbatim} + +For a fuller discussion of the line I/O changes, see the python-dev +summary for January 1-15, 2001 at +\url{http://www.python.org/dev/summary/2001-01-1.html}. + +\item A new method, \method{popitem()}, was added to dictionaries to +enable destructively iterating through the contents of a dictionary; +this can be faster for large dictionaries because there's no need to +construct a list containing all the keys or values. +\code{D.popitem()} removes a random \code{(\var{key}, \var{value})} +pair from the dictionary~\code{D} and returns it as a 2-tuple. This +was implemented mostly by Tim Peters and Guido van Rossum, after a +suggestion and preliminary patch by Moshe Zadka. + +\item Modules can now control which names are imported when \code{from +\var{module} import *} is used, by defining an \code{__all__} +attribute containing a list of names that will be imported. One +common complaint is that if the module imports other modules such as +\module{sys} or \module{string}, \code{from \var{module} import *} +will add them to the importing module's namespace. To fix this, +simply list the public names in \code{__all__}: + +\begin{verbatim} +# List public names +__all__ = ['Database', 'open'] +\end{verbatim} + +A stricter version of this patch was first suggested and implemented +by Ben Wolfson, but after some python-dev discussion, a weaker final +version was checked in. + +\item Applying \function{repr()} to strings previously used octal +escapes for non-printable characters; for example, a newline was +\code{'\e 012'}. This was a vestigial trace of Python's C ancestry, but +today octal is of very little practical use. Ka-Ping Yee suggested +using hex escapes instead of octal ones, and using the \code{\e n}, +\code{\e t}, \code{\e r} escapes for the appropriate characters, and +implemented this new formatting. + +\item Syntax errors detected at compile-time can now raise exceptions +containing the filename and line number of the error, a pleasant side +effect of the compiler reorganization done by Jeremy Hylton. + +\item C extensions which import other modules have been changed to use +\function{PyImport_ImportModule()}, which means that they will use any +import hooks that have been installed. This is also encouraged for +third-party extensions that need to import some other module from C +code. + +\item The size of the Unicode character database was shrunk by another +340K thanks to Fredrik Lundh. + +\item Some new ports were contributed: MacOS X (by Steven Majewski), +Cygwin (by Jason Tishler); RISCOS (by Dietmar Schwertberger); Unixware~7 +(by Billy G. Allie). + +\end{itemize} + +And there's the usual list of minor bugfixes, minor memory leaks, +docstring edits, and other tweaks, too lengthy to be worth itemizing; +see the CVS logs for the full details if you want them. + + +%====================================================================== +\section{Acknowledgements} + +The author would like to thank the following people for offering +suggestions on various drafts of this article: Graeme Cross, David +Goodger, Jay Graves, Michael Hudson, Marc-Andr\'e Lemburg, Fredrik +Lundh, Neil Schemenauer, Thomas Wouters. + +\end{document} diff --git a/sys/src/cmd/python/Doc/whatsnew/whatsnew22.tex b/sys/src/cmd/python/Doc/whatsnew/whatsnew22.tex new file mode 100644 index 000000000..25b347759 --- /dev/null +++ b/sys/src/cmd/python/Doc/whatsnew/whatsnew22.tex @@ -0,0 +1,1466 @@ +\documentclass{howto} + +% $Id: whatsnew22.tex 37315 2004-09-10 19:33:00Z akuchling $ + +\title{What's New in Python 2.2} +\release{1.02} +\author{A.M. Kuchling} +\authoraddress{ + \strong{Python Software Foundation}\\ + Email: \email{amk@amk.ca} +} +\begin{document} +\maketitle\tableofcontents + +\section{Introduction} + +This article explains the new features in Python 2.2.2, released on +October 14, 2002. Python 2.2.2 is a bugfix release of Python 2.2, +originally released on December 21, 2001. + +Python 2.2 can be thought of as the "cleanup release". There are some +features such as generators and iterators that are completely new, but +most of the changes, significant and far-reaching though they may be, +are aimed at cleaning up irregularities and dark corners of the +language design. + +This article doesn't attempt to provide a complete specification of +the new features, but instead provides a convenient overview. For +full details, you should refer to the documentation for Python 2.2, +such as the +\citetitle[http://www.python.org/doc/2.2/lib/lib.html]{Python +Library Reference} and the +\citetitle[http://www.python.org/doc/2.2/ref/ref.html]{Python +Reference Manual}. If you want to understand the complete +implementation and design rationale for a change, refer to the PEP for +a particular new feature. + +\begin{seealso} + +\seeurl{http://www.unixreview.com/documents/s=1356/urm0109h/0109h.htm} +{``What's So Special About Python 2.2?'' is also about the new 2.2 +features, and was written by Cameron Laird and Kathryn Soraiz.} + +\end{seealso} + + +%====================================================================== +\section{PEPs 252 and 253: Type and Class Changes} + +The largest and most far-reaching changes in Python 2.2 are to +Python's model of objects and classes. The changes should be backward +compatible, so it's likely that your code will continue to run +unchanged, but the changes provide some amazing new capabilities. +Before beginning this, the longest and most complicated section of +this article, I'll provide an overview of the changes and offer some +comments. + +A long time ago I wrote a Web page +(\url{http://www.amk.ca/python/writing/warts.html}) listing flaws in +Python's design. One of the most significant flaws was that it's +impossible to subclass Python types implemented in C. In particular, +it's not possible to subclass built-in types, so you can't just +subclass, say, lists in order to add a single useful method to them. +The \module{UserList} module provides a class that supports all of the +methods of lists and that can be subclassed further, but there's lots +of C code that expects a regular Python list and won't accept a +\class{UserList} instance. + +Python 2.2 fixes this, and in the process adds some exciting new +capabilities. A brief summary: + +\begin{itemize} + +\item You can subclass built-in types such as lists and even integers, +and your subclasses should work in every place that requires the +original type. + +\item It's now possible to define static and class methods, in addition +to the instance methods available in previous versions of Python. + +\item It's also possible to automatically call methods on accessing or +setting an instance attribute by using a new mechanism called +\dfn{properties}. Many uses of \method{__getattr__} can be rewritten +to use properties instead, making the resulting code simpler and +faster. As a small side benefit, attributes can now have docstrings, +too. + +\item The list of legal attributes for an instance can be limited to a +particular set using \dfn{slots}, making it possible to safeguard +against typos and perhaps make more optimizations possible in future +versions of Python. + +\end{itemize} + +Some users have voiced concern about all these changes. Sure, they +say, the new features are neat and lend themselves to all sorts of +tricks that weren't possible in previous versions of Python, but +they also make the language more complicated. Some people have said +that they've always recommended Python for its simplicity, and feel +that its simplicity is being lost. + +Personally, I think there's no need to worry. Many of the new +features are quite esoteric, and you can write a lot of Python code +without ever needed to be aware of them. Writing a simple class is no +more difficult than it ever was, so you don't need to bother learning +or teaching them unless they're actually needed. Some very +complicated tasks that were previously only possible from C will now +be possible in pure Python, and to my mind that's all for the better. + +I'm not going to attempt to cover every single corner case and small +change that were required to make the new features work. Instead this +section will paint only the broad strokes. See section~\ref{sect-rellinks}, +``Related Links'', for further sources of information about Python 2.2's new +object model. + + +\subsection{Old and New Classes} + +First, you should know that Python 2.2 really has two kinds of +classes: classic or old-style classes, and new-style classes. The +old-style class model is exactly the same as the class model in +earlier versions of Python. All the new features described in this +section apply only to new-style classes. This divergence isn't +intended to last forever; eventually old-style classes will be +dropped, possibly in Python 3.0. + +So how do you define a new-style class? You do it by subclassing an +existing new-style class. Most of Python's built-in types, such as +integers, lists, dictionaries, and even files, are new-style classes +now. A new-style class named \class{object}, the base class for all +built-in types, has also been added so if no built-in type is +suitable, you can just subclass \class{object}: + +\begin{verbatim} +class C(object): + def __init__ (self): + ... + ... +\end{verbatim} + +This means that \keyword{class} statements that don't have any base +classes are always classic classes in Python 2.2. (Actually you can +also change this by setting a module-level variable named +\member{__metaclass__} --- see \pep{253} for the details --- but it's +easier to just subclass \keyword{object}.) + +The type objects for the built-in types are available as built-ins, +named using a clever trick. Python has always had built-in functions +named \function{int()}, \function{float()}, and \function{str()}. In +2.2, they aren't functions any more, but type objects that behave as +factories when called. + +\begin{verbatim} +>>> int +<type 'int'> +>>> int('123') +123 +\end{verbatim} + +To make the set of types complete, new type objects such as +\function{dict} and \function{file} have been added. Here's a +more interesting example, adding a \method{lock()} method to file +objects: + +\begin{verbatim} +class LockableFile(file): + def lock (self, operation, length=0, start=0, whence=0): + import fcntl + return fcntl.lockf(self.fileno(), operation, + length, start, whence) +\end{verbatim} + +The now-obsolete \module{posixfile} module contained a class that +emulated all of a file object's methods and also added a +\method{lock()} method, but this class couldn't be passed to internal +functions that expected a built-in file, something which is possible +with our new \class{LockableFile}. + + +\subsection{Descriptors} + +In previous versions of Python, there was no consistent way to +discover what attributes and methods were supported by an object. +There were some informal conventions, such as defining +\member{__members__} and \member{__methods__} attributes that were +lists of names, but often the author of an extension type or a class +wouldn't bother to define them. You could fall back on inspecting the +\member{__dict__} of an object, but when class inheritance or an +arbitrary \method{__getattr__} hook were in use this could still be +inaccurate. + +The one big idea underlying the new class model is that an API for +describing the attributes of an object using \dfn{descriptors} has +been formalized. Descriptors specify the value of an attribute, +stating whether it's a method or a field. With the descriptor API, +static methods and class methods become possible, as well as more +exotic constructs. + +Attribute descriptors are objects that live inside class objects, and +have a few attributes of their own: + +\begin{itemize} + +\item \member{__name__} is the attribute's name. + +\item \member{__doc__} is the attribute's docstring. + +\item \method{__get__(\var{object})} is a method that retrieves the +attribute value from \var{object}. + +\item \method{__set__(\var{object}, \var{value})} sets the attribute +on \var{object} to \var{value}. + +\item \method{__delete__(\var{object}, \var{value})} deletes the \var{value} +attribute of \var{object}. +\end{itemize} + +For example, when you write \code{obj.x}, the steps that Python +actually performs are: + +\begin{verbatim} +descriptor = obj.__class__.x +descriptor.__get__(obj) +\end{verbatim} + +For methods, \method{descriptor.__get__} returns a temporary object that's +callable, and wraps up the instance and the method to be called on it. +This is also why static methods and class methods are now possible; +they have descriptors that wrap up just the method, or the method and +the class. As a brief explanation of these new kinds of methods, +static methods aren't passed the instance, and therefore resemble +regular functions. Class methods are passed the class of the object, +but not the object itself. Static and class methods are defined like +this: + +\begin{verbatim} +class C(object): + def f(arg1, arg2): + ... + f = staticmethod(f) + + def g(cls, arg1, arg2): + ... + g = classmethod(g) +\end{verbatim} + +The \function{staticmethod()} function takes the function +\function{f}, and returns it wrapped up in a descriptor so it can be +stored in the class object. You might expect there to be special +syntax for creating such methods (\code{def static f()}, +\code{defstatic f()}, or something like that) but no such syntax has +been defined yet; that's been left for future versions of Python. + +More new features, such as slots and properties, are also implemented +as new kinds of descriptors, and it's not difficult to write a +descriptor class that does something novel. For example, it would be +possible to write a descriptor class that made it possible to write +Eiffel-style preconditions and postconditions for a method. A class +that used this feature might be defined like this: + +\begin{verbatim} +from eiffel import eiffelmethod + +class C(object): + def f(self, arg1, arg2): + # The actual function + ... + def pre_f(self): + # Check preconditions + ... + def post_f(self): + # Check postconditions + ... + + f = eiffelmethod(f, pre_f, post_f) +\end{verbatim} + +Note that a person using the new \function{eiffelmethod()} doesn't +have to understand anything about descriptors. This is why I think +the new features don't increase the basic complexity of the language. +There will be a few wizards who need to know about it in order to +write \function{eiffelmethod()} or the ZODB or whatever, but most +users will just write code on top of the resulting libraries and +ignore the implementation details. + + +\subsection{Multiple Inheritance: The Diamond Rule} + +Multiple inheritance has also been made more useful through changing +the rules under which names are resolved. Consider this set of classes +(diagram taken from \pep{253} by Guido van Rossum): + +\begin{verbatim} + class A: + ^ ^ def save(self): ... + / \ + / \ + / \ + / \ + class B class C: + ^ ^ def save(self): ... + \ / + \ / + \ / + \ / + class D +\end{verbatim} + +The lookup rule for classic classes is simple but not very smart; the +base classes are searched depth-first, going from left to right. A +reference to \method{D.save} will search the classes \class{D}, +\class{B}, and then \class{A}, where \method{save()} would be found +and returned. \method{C.save()} would never be found at all. This is +bad, because if \class{C}'s \method{save()} method is saving some +internal state specific to \class{C}, not calling it will result in +that state never getting saved. + +New-style classes follow a different algorithm that's a bit more +complicated to explain, but does the right thing in this situation. +(Note that Python 2.3 changes this algorithm to one that produces the +same results in most cases, but produces more useful results for +really complicated inheritance graphs.) + +\begin{enumerate} + +\item List all the base classes, following the classic lookup rule and +include a class multiple times if it's visited repeatedly. In the +above example, the list of visited classes is [\class{D}, \class{B}, +\class{A}, \class{C}, \class{A}]. + +\item Scan the list for duplicated classes. If any are found, remove +all but one occurrence, leaving the \emph{last} one in the list. In +the above example, the list becomes [\class{D}, \class{B}, \class{C}, +\class{A}] after dropping duplicates. + +\end{enumerate} + +Following this rule, referring to \method{D.save()} will return +\method{C.save()}, which is the behaviour we're after. This lookup +rule is the same as the one followed by Common Lisp. A new built-in +function, \function{super()}, provides a way to get at a class's +superclasses without having to reimplement Python's algorithm. +The most commonly used form will be +\function{super(\var{class}, \var{obj})}, which returns +a bound superclass object (not the actual class object). This form +will be used in methods to call a method in the superclass; for +example, \class{D}'s \method{save()} method would look like this: + +\begin{verbatim} +class D (B,C): + def save (self): + # Call superclass .save() + super(D, self).save() + # Save D's private information here + ... +\end{verbatim} + +\function{super()} can also return unbound superclass objects +when called as \function{super(\var{class})} or +\function{super(\var{class1}, \var{class2})}, but this probably won't +often be useful. + + +\subsection{Attribute Access} + +A fair number of sophisticated Python classes define hooks for +attribute access using \method{__getattr__}; most commonly this is +done for convenience, to make code more readable by automatically +mapping an attribute access such as \code{obj.parent} into a method +call such as \code{obj.get_parent()}. Python 2.2 adds some new ways +of controlling attribute access. + +First, \method{__getattr__(\var{attr_name})} is still supported by +new-style classes, and nothing about it has changed. As before, it +will be called when an attempt is made to access \code{obj.foo} and no +attribute named \samp{foo} is found in the instance's dictionary. + +New-style classes also support a new method, +\method{__getattribute__(\var{attr_name})}. The difference between +the two methods is that \method{__getattribute__} is \emph{always} +called whenever any attribute is accessed, while the old +\method{__getattr__} is only called if \samp{foo} isn't found in the +instance's dictionary. + +However, Python 2.2's support for \dfn{properties} will often be a +simpler way to trap attribute references. Writing a +\method{__getattr__} method is complicated because to avoid recursion +you can't use regular attribute accesses inside them, and instead have +to mess around with the contents of \member{__dict__}. +\method{__getattr__} methods also end up being called by Python when +it checks for other methods such as \method{__repr__} or +\method{__coerce__}, and so have to be written with this in mind. +Finally, calling a function on every attribute access results in a +sizable performance loss. + +\class{property} is a new built-in type that packages up three +functions that get, set, or delete an attribute, and a docstring. For +example, if you want to define a \member{size} attribute that's +computed, but also settable, you could write: + +\begin{verbatim} +class C(object): + def get_size (self): + result = ... computation ... + return result + def set_size (self, size): + ... compute something based on the size + and set internal state appropriately ... + + # Define a property. The 'delete this attribute' + # method is defined as None, so the attribute + # can't be deleted. + size = property(get_size, set_size, + None, + "Storage size of this instance") +\end{verbatim} + +That is certainly clearer and easier to write than a pair of +\method{__getattr__}/\method{__setattr__} methods that check for the +\member{size} attribute and handle it specially while retrieving all +other attributes from the instance's \member{__dict__}. Accesses to +\member{size} are also the only ones which have to perform the work of +calling a function, so references to other attributes run at +their usual speed. + +Finally, it's possible to constrain the list of attributes that can be +referenced on an object using the new \member{__slots__} class attribute. +Python objects are usually very dynamic; at any time it's possible to +define a new attribute on an instance by just doing +\code{obj.new_attr=1}. A new-style class can define a class attribute named +\member{__slots__} to limit the legal attributes +to a particular set of names. An example will make this clear: + +\begin{verbatim} +>>> class C(object): +... __slots__ = ('template', 'name') +... +>>> obj = C() +>>> print obj.template +None +>>> obj.template = 'Test' +>>> print obj.template +Test +>>> obj.newattr = None +Traceback (most recent call last): + File "<stdin>", line 1, in ? +AttributeError: 'C' object has no attribute 'newattr' +\end{verbatim} + +Note how you get an \exception{AttributeError} on the attempt to +assign to an attribute not listed in \member{__slots__}. + + + +\subsection{Related Links} +\label{sect-rellinks} + +This section has just been a quick overview of the new features, +giving enough of an explanation to start you programming, but many +details have been simplified or ignored. Where should you go to get a +more complete picture? + +\url{http://www.python.org/2.2/descrintro.html} is a lengthy tutorial +introduction to the descriptor features, written by Guido van Rossum. +If my description has whetted your appetite, go read this tutorial +next, because it goes into much more detail about the new features +while still remaining quite easy to read. + +Next, there are two relevant PEPs, \pep{252} and \pep{253}. \pep{252} +is titled "Making Types Look More Like Classes", and covers the +descriptor API. \pep{253} is titled "Subtyping Built-in Types", and +describes the changes to type objects that make it possible to subtype +built-in objects. \pep{253} is the more complicated PEP of the two, +and at a few points the necessary explanations of types and meta-types +may cause your head to explode. Both PEPs were written and +implemented by Guido van Rossum, with substantial assistance from the +rest of the Zope Corp. team. + +Finally, there's the ultimate authority: the source code. Most of the +machinery for the type handling is in \file{Objects/typeobject.c}, but +you should only resort to it after all other avenues have been +exhausted, including posting a question to python-list or python-dev. + + +%====================================================================== +\section{PEP 234: Iterators} + +Another significant addition to 2.2 is an iteration interface at both +the C and Python levels. Objects can define how they can be looped +over by callers. + +In Python versions up to 2.1, the usual way to make \code{for item in +obj} work is to define a \method{__getitem__()} method that looks +something like this: + +\begin{verbatim} + def __getitem__(self, index): + return <next item> +\end{verbatim} + +\method{__getitem__()} is more properly used to define an indexing +operation on an object so that you can write \code{obj[5]} to retrieve +the sixth element. It's a bit misleading when you're using this only +to support \keyword{for} loops. Consider some file-like object that +wants to be looped over; the \var{index} parameter is essentially +meaningless, as the class probably assumes that a series of +\method{__getitem__()} calls will be made with \var{index} +incrementing by one each time. In other words, the presence of the +\method{__getitem__()} method doesn't mean that using \code{file[5]} +to randomly access the sixth element will work, though it really should. + +In Python 2.2, iteration can be implemented separately, and +\method{__getitem__()} methods can be limited to classes that really +do support random access. The basic idea of iterators is +simple. A new built-in function, \function{iter(obj)} or +\code{iter(\var{C}, \var{sentinel})}, is used to get an iterator. +\function{iter(obj)} returns an iterator for the object \var{obj}, +while \code{iter(\var{C}, \var{sentinel})} returns an iterator that +will invoke the callable object \var{C} until it returns +\var{sentinel} to signal that the iterator is done. + +Python classes can define an \method{__iter__()} method, which should +create and return a new iterator for the object; if the object is its +own iterator, this method can just return \code{self}. In particular, +iterators will usually be their own iterators. Extension types +implemented in C can implement a \member{tp_iter} function in order to +return an iterator, and extension types that want to behave as +iterators can define a \member{tp_iternext} function. + +So, after all this, what do iterators actually do? They have one +required method, \method{next()}, which takes no arguments and returns +the next value. When there are no more values to be returned, calling +\method{next()} should raise the \exception{StopIteration} exception. + +\begin{verbatim} +>>> L = [1,2,3] +>>> i = iter(L) +>>> print i +<iterator object at 0x8116870> +>>> i.next() +1 +>>> i.next() +2 +>>> i.next() +3 +>>> i.next() +Traceback (most recent call last): + File "<stdin>", line 1, in ? +StopIteration +>>> +\end{verbatim} + +In 2.2, Python's \keyword{for} statement no longer expects a sequence; +it expects something for which \function{iter()} will return an iterator. +For backward compatibility and convenience, an iterator is +automatically constructed for sequences that don't implement +\method{__iter__()} or a \member{tp_iter} slot, so \code{for i in +[1,2,3]} will still work. Wherever the Python interpreter loops over +a sequence, it's been changed to use the iterator protocol. This +means you can do things like this: + +\begin{verbatim} +>>> L = [1,2,3] +>>> i = iter(L) +>>> a,b,c = i +>>> a,b,c +(1, 2, 3) +\end{verbatim} + +Iterator support has been added to some of Python's basic types. +Calling \function{iter()} on a dictionary will return an iterator +which loops over its keys: + +\begin{verbatim} +>>> m = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, +... 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12} +>>> for key in m: print key, m[key] +... +Mar 3 +Feb 2 +Aug 8 +Sep 9 +May 5 +Jun 6 +Jul 7 +Jan 1 +Apr 4 +Nov 11 +Dec 12 +Oct 10 +\end{verbatim} + +That's just the default behaviour. If you want to iterate over keys, +values, or key/value pairs, you can explicitly call the +\method{iterkeys()}, \method{itervalues()}, or \method{iteritems()} +methods to get an appropriate iterator. In a minor related change, +the \keyword{in} operator now works on dictionaries, so +\code{\var{key} in dict} is now equivalent to +\code{dict.has_key(\var{key})}. + +Files also provide an iterator, which calls the \method{readline()} +method until there are no more lines in the file. This means you can +now read each line of a file using code like this: + +\begin{verbatim} +for line in file: + # do something for each line + ... +\end{verbatim} + +Note that you can only go forward in an iterator; there's no way to +get the previous element, reset the iterator, or make a copy of it. +An iterator object could provide such additional capabilities, but the +iterator protocol only requires a \method{next()} method. + +\begin{seealso} + +\seepep{234}{Iterators}{Written by Ka-Ping Yee and GvR; implemented +by the Python Labs crew, mostly by GvR and Tim Peters.} + +\end{seealso} + + +%====================================================================== +\section{PEP 255: Simple Generators} + +Generators are another new feature, one that interacts with the +introduction of iterators. + +You're doubtless familiar with how function calls work in Python or +C. When you call a function, it gets a private namespace where its local +variables are created. When the function reaches a \keyword{return} +statement, the local variables are destroyed and the resulting value +is returned to the caller. A later call to the same function will get +a fresh new set of local variables. But, what if the local variables +weren't thrown away on exiting a function? What if you could later +resume the function where it left off? This is what generators +provide; they can be thought of as resumable functions. + +Here's the simplest example of a generator function: + +\begin{verbatim} +def generate_ints(N): + for i in range(N): + yield i +\end{verbatim} + +A new keyword, \keyword{yield}, was introduced for generators. Any +function containing a \keyword{yield} statement is a generator +function; this is detected by Python's bytecode compiler which +compiles the function specially as a result. Because a new keyword was +introduced, generators must be explicitly enabled in a module by +including a \code{from __future__ import generators} statement near +the top of the module's source code. In Python 2.3 this statement +will become unnecessary. + +When you call a generator function, it doesn't return a single value; +instead it returns a generator object that supports the iterator +protocol. On executing the \keyword{yield} statement, the generator +outputs the value of \code{i}, similar to a \keyword{return} +statement. The big difference between \keyword{yield} and a +\keyword{return} statement is that on reaching a \keyword{yield} the +generator's state of execution is suspended and local variables are +preserved. On the next call to the generator's \code{next()} method, +the function will resume executing immediately after the +\keyword{yield} statement. (For complicated reasons, the +\keyword{yield} statement isn't allowed inside the \keyword{try} block +of a \keyword{try}...\keyword{finally} statement; read \pep{255} for a full +explanation of the interaction between \keyword{yield} and +exceptions.) + +Here's a sample usage of the \function{generate_ints} generator: + +\begin{verbatim} +>>> gen = generate_ints(3) +>>> gen +<generator object at 0x8117f90> +>>> gen.next() +0 +>>> gen.next() +1 +>>> gen.next() +2 +>>> gen.next() +Traceback (most recent call last): + File "<stdin>", line 1, in ? + File "<stdin>", line 2, in generate_ints +StopIteration +\end{verbatim} + +You could equally write \code{for i in generate_ints(5)}, or +\code{a,b,c = generate_ints(3)}. + +Inside a generator function, the \keyword{return} statement can only +be used without a value, and signals the end of the procession of +values; afterwards the generator cannot return any further values. +\keyword{return} with a value, such as \code{return 5}, is a syntax +error inside a generator function. The end of the generator's results +can also be indicated by raising \exception{StopIteration} manually, +or by just letting the flow of execution fall off the bottom of the +function. + +You could achieve the effect of generators manually by writing your +own class and storing all the local variables of the generator as +instance variables. For example, returning a list of integers could +be done by setting \code{self.count} to 0, and having the +\method{next()} method increment \code{self.count} and return it. +However, for a moderately complicated generator, writing a +corresponding class would be much messier. +\file{Lib/test/test_generators.py} contains a number of more +interesting examples. The simplest one implements an in-order +traversal of a tree using generators recursively. + +\begin{verbatim} +# A recursive generator that generates Tree leaves in in-order. +def inorder(t): + if t: + for x in inorder(t.left): + yield x + yield t.label + for x in inorder(t.right): + yield x +\end{verbatim} + +Two other examples in \file{Lib/test/test_generators.py} produce +solutions for the N-Queens problem (placing $N$ queens on an $NxN$ +chess board so that no queen threatens another) and the Knight's Tour +(a route that takes a knight to every square of an $NxN$ chessboard +without visiting any square twice). + +The idea of generators comes from other programming languages, +especially Icon (\url{http://www.cs.arizona.edu/icon/}), where the +idea of generators is central. In Icon, every +expression and function call behaves like a generator. One example +from ``An Overview of the Icon Programming Language'' at +\url{http://www.cs.arizona.edu/icon/docs/ipd266.htm} gives an idea of +what this looks like: + +\begin{verbatim} +sentence := "Store it in the neighboring harbor" +if (i := find("or", sentence)) > 5 then write(i) +\end{verbatim} + +In Icon the \function{find()} function returns the indexes at which the +substring ``or'' is found: 3, 23, 33. In the \keyword{if} statement, +\code{i} is first assigned a value of 3, but 3 is less than 5, so the +comparison fails, and Icon retries it with the second value of 23. 23 +is greater than 5, so the comparison now succeeds, and the code prints +the value 23 to the screen. + +Python doesn't go nearly as far as Icon in adopting generators as a +central concept. Generators are considered a new part of the core +Python language, but learning or using them isn't compulsory; if they +don't solve any problems that you have, feel free to ignore them. +One novel feature of Python's interface as compared to +Icon's is that a generator's state is represented as a concrete object +(the iterator) that can be passed around to other functions or stored +in a data structure. + +\begin{seealso} + +\seepep{255}{Simple Generators}{Written by Neil Schemenauer, Tim +Peters, Magnus Lie Hetland. Implemented mostly by Neil Schemenauer +and Tim Peters, with other fixes from the Python Labs crew.} + +\end{seealso} + + +%====================================================================== +\section{PEP 237: Unifying Long Integers and Integers} + +In recent versions, the distinction between regular integers, which +are 32-bit values on most machines, and long integers, which can be of +arbitrary size, was becoming an annoyance. For example, on platforms +that support files larger than \code{2**32} bytes, the +\method{tell()} method of file objects has to return a long integer. +However, there were various bits of Python that expected plain +integers and would raise an error if a long integer was provided +instead. For example, in Python 1.5, only regular integers +could be used as a slice index, and \code{'abc'[1L:]} would raise a +\exception{TypeError} exception with the message 'slice index must be +int'. + +Python 2.2 will shift values from short to long integers as required. +The 'L' suffix is no longer needed to indicate a long integer literal, +as now the compiler will choose the appropriate type. (Using the 'L' +suffix will be discouraged in future 2.x versions of Python, +triggering a warning in Python 2.4, and probably dropped in Python +3.0.) Many operations that used to raise an \exception{OverflowError} +will now return a long integer as their result. For example: + +\begin{verbatim} +>>> 1234567890123 +1234567890123L +>>> 2 ** 64 +18446744073709551616L +\end{verbatim} + +In most cases, integers and long integers will now be treated +identically. You can still distinguish them with the +\function{type()} built-in function, but that's rarely needed. + +\begin{seealso} + +\seepep{237}{Unifying Long Integers and Integers}{Written by +Moshe Zadka and Guido van Rossum. Implemented mostly by Guido van +Rossum.} + +\end{seealso} + + +%====================================================================== +\section{PEP 238: Changing the Division Operator} + +The most controversial change in Python 2.2 heralds the start of an effort +to fix an old design flaw that's been in Python from the beginning. +Currently Python's division operator, \code{/}, behaves like C's +division operator when presented with two integer arguments: it +returns an integer result that's truncated down when there would be +a fractional part. For example, \code{3/2} is 1, not 1.5, and +\code{(-1)/2} is -1, not -0.5. This means that the results of divison +can vary unexpectedly depending on the type of the two operands and +because Python is dynamically typed, it can be difficult to determine +the possible types of the operands. + +(The controversy is over whether this is \emph{really} a design flaw, +and whether it's worth breaking existing code to fix this. It's +caused endless discussions on python-dev, and in July 2001 erupted into an +storm of acidly sarcastic postings on \newsgroup{comp.lang.python}. I +won't argue for either side here and will stick to describing what's +implemented in 2.2. Read \pep{238} for a summary of arguments and +counter-arguments.) + +Because this change might break code, it's being introduced very +gradually. Python 2.2 begins the transition, but the switch won't be +complete until Python 3.0. + +First, I'll borrow some terminology from \pep{238}. ``True division'' is the +division that most non-programmers are familiar with: 3/2 is 1.5, 1/4 +is 0.25, and so forth. ``Floor division'' is what Python's \code{/} +operator currently does when given integer operands; the result is the +floor of the value returned by true division. ``Classic division'' is +the current mixed behaviour of \code{/}; it returns the result of +floor division when the operands are integers, and returns the result +of true division when one of the operands is a floating-point number. + +Here are the changes 2.2 introduces: + +\begin{itemize} + +\item A new operator, \code{//}, is the floor division operator. +(Yes, we know it looks like \Cpp's comment symbol.) \code{//} +\emph{always} performs floor division no matter what the types of +its operands are, so \code{1 // 2} is 0 and \code{1.0 // 2.0} is also +0.0. + +\code{//} is always available in Python 2.2; you don't need to enable +it using a \code{__future__} statement. + +\item By including a \code{from __future__ import division} in a +module, the \code{/} operator will be changed to return the result of +true division, so \code{1/2} is 0.5. Without the \code{__future__} +statement, \code{/} still means classic division. The default meaning +of \code{/} will not change until Python 3.0. + +\item Classes can define methods called \method{__truediv__} and +\method{__floordiv__} to overload the two division operators. At the +C level, there are also slots in the \ctype{PyNumberMethods} structure +so extension types can define the two operators. + +\item Python 2.2 supports some command-line arguments for testing +whether code will works with the changed division semantics. Running +python with \programopt{-Q warn} will cause a warning to be issued +whenever division is applied to two integers. You can use this to +find code that's affected by the change and fix it. By default, +Python 2.2 will simply perform classic division without a warning; the +warning will be turned on by default in Python 2.3. + +\end{itemize} + +\begin{seealso} + +\seepep{238}{Changing the Division Operator}{Written by Moshe Zadka and +Guido van Rossum. Implemented by Guido van Rossum..} + +\end{seealso} + + +%====================================================================== +\section{Unicode Changes} + +Python's Unicode support has been enhanced a bit in 2.2. Unicode +strings are usually stored as UCS-2, as 16-bit unsigned integers. +Python 2.2 can also be compiled to use UCS-4, 32-bit unsigned +integers, as its internal encoding by supplying +\longprogramopt{enable-unicode=ucs4} to the configure script. +(It's also possible to specify +\longprogramopt{disable-unicode} to completely disable Unicode +support.) + +When built to use UCS-4 (a ``wide Python''), the interpreter can +natively handle Unicode characters from U+000000 to U+110000, so the +range of legal values for the \function{unichr()} function is expanded +accordingly. Using an interpreter compiled to use UCS-2 (a ``narrow +Python''), values greater than 65535 will still cause +\function{unichr()} to raise a \exception{ValueError} exception. +This is all described in \pep{261}, ``Support for `wide' Unicode +characters''; consult it for further details. + +Another change is simpler to explain. Since their introduction, +Unicode strings have supported an \method{encode()} method to convert +the string to a selected encoding such as UTF-8 or Latin-1. A +symmetric \method{decode(\optional{\var{encoding}})} method has been +added to 8-bit strings (though not to Unicode strings) in 2.2. +\method{decode()} assumes that the string is in the specified encoding +and decodes it, returning whatever is returned by the codec. + +Using this new feature, codecs have been added for tasks not directly +related to Unicode. For example, codecs have been added for +uu-encoding, MIME's base64 encoding, and compression with the +\module{zlib} module: + +\begin{verbatim} +>>> s = """Here is a lengthy piece of redundant, overly verbose, +... and repetitive text. +... """ +>>> data = s.encode('zlib') +>>> data +'x\x9c\r\xc9\xc1\r\x80 \x10\x04\xc0?Ul...' +>>> data.decode('zlib') +'Here is a lengthy piece of redundant, overly verbose,\nand repetitive text.\n' +>>> print s.encode('uu') +begin 666 <data> +M2&5R92!I<R!A(&QE;F=T:'D@<&EE8V4@;V8@<F5D=6YD86YT+"!O=F5R;'D@ +>=F5R8F]S92P*86YD(')E<&5T:71I=F4@=&5X="X* + +end +>>> "sheesh".encode('rot-13') +'furrfu' +\end{verbatim} + +To convert a class instance to Unicode, a \method{__unicode__} method +can be defined by a class, analogous to \method{__str__}. + +\method{encode()}, \method{decode()}, and \method{__unicode__} were +implemented by Marc-Andr\'e Lemburg. The changes to support using +UCS-4 internally were implemented by Fredrik Lundh and Martin von +L\"owis. + +\begin{seealso} + +\seepep{261}{Support for `wide' Unicode characters}{Written by +Paul Prescod.} + +\end{seealso} + + +%====================================================================== +\section{PEP 227: Nested Scopes} + +In Python 2.1, statically nested scopes were added as an optional +feature, to be enabled by a \code{from __future__ import +nested_scopes} directive. In 2.2 nested scopes no longer need to be +specially enabled, and are now always present. The rest of this section +is a copy of the description of nested scopes from my ``What's New in +Python 2.1'' document; if you read it when 2.1 came out, you can skip +the rest of this section. + +The largest change introduced in Python 2.1, and made complete in 2.2, +is to Python's scoping rules. In Python 2.0, at any given time there +are at most three namespaces used to look up variable names: local, +module-level, and the built-in namespace. This often surprised people +because it didn't match their intuitive expectations. For example, a +nested recursive function definition doesn't work: + +\begin{verbatim} +def f(): + ... + def g(value): + ... + return g(value-1) + 1 + ... +\end{verbatim} + +The function \function{g()} will always raise a \exception{NameError} +exception, because the binding of the name \samp{g} isn't in either +its local namespace or in the module-level namespace. This isn't much +of a problem in practice (how often do you recursively define interior +functions like this?), but this also made using the \keyword{lambda} +statement clumsier, and this was a problem in practice. In code which +uses \keyword{lambda} you can often find local variables being copied +by passing them as the default values of arguments. + +\begin{verbatim} +def find(self, name): + "Return list of any entries equal to 'name'" + L = filter(lambda x, name=name: x == name, + self.list_attribute) + return L +\end{verbatim} + +The readability of Python code written in a strongly functional style +suffers greatly as a result. + +The most significant change to Python 2.2 is that static scoping has +been added to the language to fix this problem. As a first effect, +the \code{name=name} default argument is now unnecessary in the above +example. Put simply, when a given variable name is not assigned a +value within a function (by an assignment, or the \keyword{def}, +\keyword{class}, or \keyword{import} statements), references to the +variable will be looked up in the local namespace of the enclosing +scope. A more detailed explanation of the rules, and a dissection of +the implementation, can be found in the PEP. + +This change may cause some compatibility problems for code where the +same variable name is used both at the module level and as a local +variable within a function that contains further function definitions. +This seems rather unlikely though, since such code would have been +pretty confusing to read in the first place. + +One side effect of the change is that the \code{from \var{module} +import *} and \keyword{exec} statements have been made illegal inside +a function scope under certain conditions. The Python reference +manual has said all along that \code{from \var{module} import *} is +only legal at the top level of a module, but the CPython interpreter +has never enforced this before. As part of the implementation of +nested scopes, the compiler which turns Python source into bytecodes +has to generate different code to access variables in a containing +scope. \code{from \var{module} import *} and \keyword{exec} make it +impossible for the compiler to figure this out, because they add names +to the local namespace that are unknowable at compile time. +Therefore, if a function contains function definitions or +\keyword{lambda} expressions with free variables, the compiler will +flag this by raising a \exception{SyntaxError} exception. + +To make the preceding explanation a bit clearer, here's an example: + +\begin{verbatim} +x = 1 +def f(): + # The next line is a syntax error + exec 'x=2' + def g(): + return x +\end{verbatim} + +Line 4 containing the \keyword{exec} statement is a syntax error, +since \keyword{exec} would define a new local variable named \samp{x} +whose value should be accessed by \function{g()}. + +This shouldn't be much of a limitation, since \keyword{exec} is rarely +used in most Python code (and when it is used, it's often a sign of a +poor design anyway). + +\begin{seealso} + +\seepep{227}{Statically Nested Scopes}{Written and implemented by +Jeremy Hylton.} + +\end{seealso} + + +%====================================================================== +\section{New and Improved Modules} + +\begin{itemize} + + \item The \module{xmlrpclib} module was contributed to the standard + library by Fredrik Lundh, providing support for writing XML-RPC + clients. XML-RPC is a simple remote procedure call protocol built on + top of HTTP and XML. For example, the following snippet retrieves a + list of RSS channels from the O'Reilly Network, and then + lists the recent headlines for one channel: + +\begin{verbatim} +import xmlrpclib +s = xmlrpclib.Server( + 'http://www.oreillynet.com/meerkat/xml-rpc/server.php') +channels = s.meerkat.getChannels() +# channels is a list of dictionaries, like this: +# [{'id': 4, 'title': 'Freshmeat Daily News'} +# {'id': 190, 'title': '32Bits Online'}, +# {'id': 4549, 'title': '3DGamers'}, ... ] + +# Get the items for one channel +items = s.meerkat.getItems( {'channel': 4} ) + +# 'items' is another list of dictionaries, like this: +# [{'link': 'http://freshmeat.net/releases/52719/', +# 'description': 'A utility which converts HTML to XSL FO.', +# 'title': 'html2fo 0.3 (Default)'}, ... ] +\end{verbatim} + +The \module{SimpleXMLRPCServer} module makes it easy to create +straightforward XML-RPC servers. See \url{http://www.xmlrpc.com/} for +more information about XML-RPC. + + \item The new \module{hmac} module implements the HMAC + algorithm described by \rfc{2104}. + (Contributed by Gerhard H\"aring.) + + \item Several functions that originally returned lengthy tuples now + return pseudo-sequences that still behave like tuples but also have + mnemonic attributes such as member{st_mtime} or \member{tm_year}. + The enhanced functions include \function{stat()}, + \function{fstat()}, \function{statvfs()}, and \function{fstatvfs()} + in the \module{os} module, and \function{localtime()}, + \function{gmtime()}, and \function{strptime()} in the \module{time} + module. + + For example, to obtain a file's size using the old tuples, you'd end + up writing something like \code{file_size = + os.stat(filename)[stat.ST_SIZE]}, but now this can be written more + clearly as \code{file_size = os.stat(filename).st_size}. + + The original patch for this feature was contributed by Nick Mathewson. + + \item The Python profiler has been extensively reworked and various + errors in its output have been corrected. (Contributed by + Fred~L. Drake, Jr. and Tim Peters.) + + \item The \module{socket} module can be compiled to support IPv6; + specify the \longprogramopt{enable-ipv6} option to Python's configure + script. (Contributed by Jun-ichiro ``itojun'' Hagino.) + + \item Two new format characters were added to the \module{struct} + module for 64-bit integers on platforms that support the C + \ctype{long long} type. \samp{q} is for a signed 64-bit integer, + and \samp{Q} is for an unsigned one. The value is returned in + Python's long integer type. (Contributed by Tim Peters.) + + \item In the interpreter's interactive mode, there's a new built-in + function \function{help()} that uses the \module{pydoc} module + introduced in Python 2.1 to provide interactive help. + \code{help(\var{object})} displays any available help text about + \var{object}. \function{help()} with no argument puts you in an online + help utility, where you can enter the names of functions, classes, + or modules to read their help text. + (Contributed by Guido van Rossum, using Ka-Ping Yee's \module{pydoc} module.) + + \item Various bugfixes and performance improvements have been made + to the SRE engine underlying the \module{re} module. For example, + the \function{re.sub()} and \function{re.split()} functions have + been rewritten in C. Another contributed patch speeds up certain + Unicode character ranges by a factor of two, and a new \method{finditer()} + method that returns an iterator over all the non-overlapping matches in + a given string. + (SRE is maintained by + Fredrik Lundh. The BIGCHARSET patch was contributed by Martin von + L\"owis.) + + \item The \module{smtplib} module now supports \rfc{2487}, ``Secure + SMTP over TLS'', so it's now possible to encrypt the SMTP traffic + between a Python program and the mail transport agent being handed a + message. \module{smtplib} also supports SMTP authentication. + (Contributed by Gerhard H\"aring.) + + \item The \module{imaplib} module, maintained by Piers Lauder, has + support for several new extensions: the NAMESPACE extension defined + in \rfc{2342}, SORT, GETACL and SETACL. (Contributed by Anthony + Baxter and Michel Pelletier.) + + \item The \module{rfc822} module's parsing of email addresses is now + compliant with \rfc{2822}, an update to \rfc{822}. (The module's + name is \emph{not} going to be changed to \samp{rfc2822}.) A new + package, \module{email}, has also been added for parsing and + generating e-mail messages. (Contributed by Barry Warsaw, and + arising out of his work on Mailman.) + + \item The \module{difflib} module now contains a new \class{Differ} + class for producing human-readable lists of changes (a ``delta'') + between two sequences of lines of text. There are also two + generator functions, \function{ndiff()} and \function{restore()}, + which respectively return a delta from two sequences, or one of the + original sequences from a delta. (Grunt work contributed by David + Goodger, from ndiff.py code by Tim Peters who then did the + generatorization.) + + \item New constants \constant{ascii_letters}, + \constant{ascii_lowercase}, and \constant{ascii_uppercase} were + added to the \module{string} module. There were several modules in + the standard library that used \constant{string.letters} to mean the + ranges A-Za-z, but that assumption is incorrect when locales are in + use, because \constant{string.letters} varies depending on the set + of legal characters defined by the current locale. The buggy + modules have all been fixed to use \constant{ascii_letters} instead. + (Reported by an unknown person; fixed by Fred~L. Drake, Jr.) + + \item The \module{mimetypes} module now makes it easier to use + alternative MIME-type databases by the addition of a + \class{MimeTypes} class, which takes a list of filenames to be + parsed. (Contributed by Fred~L. Drake, Jr.) + + \item A \class{Timer} class was added to the \module{threading} + module that allows scheduling an activity to happen at some future + time. (Contributed by Itamar Shtull-Trauring.) + +\end{itemize} + + +%====================================================================== +\section{Interpreter Changes and Fixes} + +Some of the changes only affect people who deal with the Python +interpreter at the C level because they're writing Python extension modules, +embedding the interpreter, or just hacking on the interpreter itself. +If you only write Python code, none of the changes described here will +affect you very much. + +\begin{itemize} + + \item Profiling and tracing functions can now be implemented in C, + which can operate at much higher speeds than Python-based functions + and should reduce the overhead of profiling and tracing. This + will be of interest to authors of development environments for + Python. Two new C functions were added to Python's API, + \cfunction{PyEval_SetProfile()} and \cfunction{PyEval_SetTrace()}. + The existing \function{sys.setprofile()} and + \function{sys.settrace()} functions still exist, and have simply + been changed to use the new C-level interface. (Contributed by Fred + L. Drake, Jr.) + + \item Another low-level API, primarily of interest to implementors + of Python debuggers and development tools, was added. + \cfunction{PyInterpreterState_Head()} and + \cfunction{PyInterpreterState_Next()} let a caller walk through all + the existing interpreter objects; + \cfunction{PyInterpreterState_ThreadHead()} and + \cfunction{PyThreadState_Next()} allow looping over all the thread + states for a given interpreter. (Contributed by David Beazley.) + +\item The C-level interface to the garbage collector has been changed +to make it easier to write extension types that support garbage +collection and to debug misuses of the functions. +Various functions have slightly different semantics, so a bunch of +functions had to be renamed. Extensions that use the old API will +still compile but will \emph{not} participate in garbage collection, +so updating them for 2.2 should be considered fairly high priority. + +To upgrade an extension module to the new API, perform the following +steps: + +\begin{itemize} + +\item Rename \cfunction{Py_TPFLAGS_GC} to \cfunction{PyTPFLAGS_HAVE_GC}. + +\item Use \cfunction{PyObject_GC_New} or \cfunction{PyObject_GC_NewVar} to +allocate objects, and \cfunction{PyObject_GC_Del} to deallocate them. + +\item Rename \cfunction{PyObject_GC_Init} to \cfunction{PyObject_GC_Track} and +\cfunction{PyObject_GC_Fini} to \cfunction{PyObject_GC_UnTrack}. + +\item Remove \cfunction{PyGC_HEAD_SIZE} from object size calculations. + +\item Remove calls to \cfunction{PyObject_AS_GC} and \cfunction{PyObject_FROM_GC}. + +\end{itemize} + + \item A new \samp{et} format sequence was added to + \cfunction{PyArg_ParseTuple}; \samp{et} takes both a parameter and + an encoding name, and converts the parameter to the given encoding + if the parameter turns out to be a Unicode string, or leaves it + alone if it's an 8-bit string, assuming it to already be in the + desired encoding. This differs from the \samp{es} format character, + which assumes that 8-bit strings are in Python's default ASCII + encoding and converts them to the specified new encoding. + (Contributed by M.-A. Lemburg, and used for the MBCS support on + Windows described in the following section.) + + \item A different argument parsing function, + \cfunction{PyArg_UnpackTuple()}, has been added that's simpler and + presumably faster. Instead of specifying a format string, the + caller simply gives the minimum and maximum number of arguments + expected, and a set of pointers to \ctype{PyObject*} variables that + will be filled in with argument values. + + \item Two new flags \constant{METH_NOARGS} and \constant{METH_O} are + available in method definition tables to simplify implementation of + methods with no arguments or a single untyped argument. Calling + such methods is more efficient than calling a corresponding method + that uses \constant{METH_VARARGS}. + Also, the old \constant{METH_OLDARGS} style of writing C methods is + now officially deprecated. + +\item + Two new wrapper functions, \cfunction{PyOS_snprintf()} and + \cfunction{PyOS_vsnprintf()} were added to provide + cross-platform implementations for the relatively new + \cfunction{snprintf()} and \cfunction{vsnprintf()} C lib APIs. In + contrast to the standard \cfunction{sprintf()} and + \cfunction{vsprintf()} functions, the Python versions check the + bounds of the buffer used to protect against buffer overruns. + (Contributed by M.-A. Lemburg.) + + \item The \cfunction{_PyTuple_Resize()} function has lost an unused + parameter, so now it takes 2 parameters instead of 3. The third + argument was never used, and can simply be discarded when porting + code from earlier versions to Python 2.2. + +\end{itemize} + + +%====================================================================== +\section{Other Changes and Fixes} + +As usual there were a bunch of other improvements and bugfixes +scattered throughout the source tree. A search through the CVS change +logs finds there were 527 patches applied and 683 bugs fixed between +Python 2.1 and 2.2; 2.2.1 applied 139 patches and fixed 143 bugs; +2.2.2 applied 106 patches and fixed 82 bugs. These figures are likely +to be underestimates. + +Some of the more notable changes are: + +\begin{itemize} + + \item The code for the MacOS port for Python, maintained by Jack + Jansen, is now kept in the main Python CVS tree, and many changes + have been made to support MacOS~X. + +The most significant change is the ability to build Python as a +framework, enabled by supplying the \longprogramopt{enable-framework} +option to the configure script when compiling Python. According to +Jack Jansen, ``This installs a self-contained Python installation plus +the OS~X framework "glue" into +\file{/Library/Frameworks/Python.framework} (or another location of +choice). For now there is little immediate added benefit to this +(actually, there is the disadvantage that you have to change your PATH +to be able to find Python), but it is the basis for creating a +full-blown Python application, porting the MacPython IDE, possibly +using Python as a standard OSA scripting language and much more.'' + +Most of the MacPython toolbox modules, which interface to MacOS APIs +such as windowing, QuickTime, scripting, etc. have been ported to OS~X, +but they've been left commented out in \file{setup.py}. People who want +to experiment with these modules can uncomment them manually. + +% Jack's original comments: +%The main change is the possibility to build Python as a +%framework. This installs a self-contained Python installation plus the +%OSX framework "glue" into /Library/Frameworks/Python.framework (or +%another location of choice). For now there is little immedeate added +%benefit to this (actually, there is the disadvantage that you have to +%change your PATH to be able to find Python), but it is the basis for +%creating a fullblown Python application, porting the MacPython IDE, +%possibly using Python as a standard OSA scripting language and much +%more. You enable this with "configure --enable-framework". + +%The other change is that most MacPython toolbox modules, which +%interface to all the MacOS APIs such as windowing, quicktime, +%scripting, etc. have been ported. Again, most of these are not of +%immedeate use, as they need a full application to be really useful, so +%they have been commented out in setup.py. People wanting to experiment +%can uncomment them. Gestalt and Internet Config modules are enabled by +%default. + + \item Keyword arguments passed to builtin functions that don't take them + now cause a \exception{TypeError} exception to be raised, with the + message "\var{function} takes no keyword arguments". + + \item Weak references, added in Python 2.1 as an extension module, + are now part of the core because they're used in the implementation + of new-style classes. The \exception{ReferenceError} exception has + therefore moved from the \module{weakref} module to become a + built-in exception. + + \item A new script, \file{Tools/scripts/cleanfuture.py} by Tim + Peters, automatically removes obsolete \code{__future__} statements + from Python source code. + + \item An additional \var{flags} argument has been added to the + built-in function \function{compile()}, so the behaviour of + \code{__future__} statements can now be correctly observed in + simulated shells, such as those presented by IDLE and other + development environments. This is described in \pep{264}. + (Contributed by Michael Hudson.) + + \item The new license introduced with Python 1.6 wasn't + GPL-compatible. This is fixed by some minor textual changes to the + 2.2 license, so it's now legal to embed Python inside a GPLed + program again. Note that Python itself is not GPLed, but instead is + under a license that's essentially equivalent to the BSD license, + same as it always was. The license changes were also applied to the + Python 2.0.1 and 2.1.1 releases. + + \item When presented with a Unicode filename on Windows, Python will + now convert it to an MBCS encoded string, as used by the Microsoft + file APIs. As MBCS is explicitly used by the file APIs, Python's + choice of ASCII as the default encoding turns out to be an + annoyance. On \UNIX, the locale's character set is used if + \function{locale.nl_langinfo(CODESET)} is available. (Windows + support was contributed by Mark Hammond with assistance from + Marc-Andr\'e Lemburg. \UNIX{} support was added by Martin von L\"owis.) + + \item Large file support is now enabled on Windows. (Contributed by + Tim Peters.) + + \item The \file{Tools/scripts/ftpmirror.py} script + now parses a \file{.netrc} file, if you have one. + (Contributed by Mike Romberg.) + + \item Some features of the object returned by the + \function{xrange()} function are now deprecated, and trigger + warnings when they're accessed; they'll disappear in Python 2.3. + \class{xrange} objects tried to pretend they were full sequence + types by supporting slicing, sequence multiplication, and the + \keyword{in} operator, but these features were rarely used and + therefore buggy. The \method{tolist()} method and the + \member{start}, \member{stop}, and \member{step} attributes are also + being deprecated. At the C level, the fourth argument to the + \cfunction{PyRange_New()} function, \samp{repeat}, has also been + deprecated. + + \item There were a bunch of patches to the dictionary + implementation, mostly to fix potential core dumps if a dictionary + contains objects that sneakily changed their hash value, or mutated + the dictionary they were contained in. For a while python-dev fell + into a gentle rhythm of Michael Hudson finding a case that dumped + core, Tim Peters fixing the bug, Michael finding another case, and round + and round it went. + + \item On Windows, Python can now be compiled with Borland C thanks + to a number of patches contributed by Stephen Hansen, though the + result isn't fully functional yet. (But this \emph{is} progress...) + + \item Another Windows enhancement: Wise Solutions generously offered + PythonLabs use of their InstallerMaster 8.1 system. Earlier + PythonLabs Windows installers used Wise 5.0a, which was beginning to + show its age. (Packaged up by Tim Peters.) + + \item Files ending in \samp{.pyw} can now be imported on Windows. + \samp{.pyw} is a Windows-only thing, used to indicate that a script + needs to be run using PYTHONW.EXE instead of PYTHON.EXE in order to + prevent a DOS console from popping up to display the output. This + patch makes it possible to import such scripts, in case they're also + usable as modules. (Implemented by David Bolen.) + + \item On platforms where Python uses the C \cfunction{dlopen()} function + to load extension modules, it's now possible to set the flags used + by \cfunction{dlopen()} using the \function{sys.getdlopenflags()} and + \function{sys.setdlopenflags()} functions. (Contributed by Bram Stolk.) + + \item The \function{pow()} built-in function no longer supports 3 + arguments when floating-point numbers are supplied. + \code{pow(\var{x}, \var{y}, \var{z})} returns \code{(x**y) \% z}, but + this is never useful for floating point numbers, and the final + result varies unpredictably depending on the platform. A call such + as \code{pow(2.0, 8.0, 7.0)} will now raise a \exception{TypeError} + exception. + +\end{itemize} + + +%====================================================================== +\section{Acknowledgements} + +The author would like to thank the following people for offering +suggestions, corrections and assistance with various drafts of this +article: Fred Bremmer, Keith Briggs, Andrew Dalke, Fred~L. Drake, Jr., +Carel Fellinger, David Goodger, Mark Hammond, Stephen Hansen, Michael +Hudson, Jack Jansen, Marc-Andr\'e Lemburg, Martin von L\"owis, Fredrik +Lundh, Michael McLay, Nick Mathewson, Paul Moore, Gustavo Niemeyer, +Don O'Donnell, Joonas Paalasma, Tim Peters, Jens Quade, Tom Reinhardt, Neil +Schemenauer, Guido van Rossum, Greg Ward, Edward Welbourne. + +\end{document} diff --git a/sys/src/cmd/python/Doc/whatsnew/whatsnew23.tex b/sys/src/cmd/python/Doc/whatsnew/whatsnew23.tex new file mode 100644 index 000000000..8b0fb4ae8 --- /dev/null +++ b/sys/src/cmd/python/Doc/whatsnew/whatsnew23.tex @@ -0,0 +1,2380 @@ +\documentclass{howto} +\usepackage{distutils} +% $Id: whatsnew23.tex 50964 2006-07-30 03:03:43Z fred.drake $ + +\title{What's New in Python 2.3} +\release{1.01} +\author{A.M.\ Kuchling} +\authoraddress{ + \strong{Python Software Foundation}\\ + Email: \email{amk@amk.ca} +} + +\begin{document} +\maketitle +\tableofcontents + +This article explains the new features in Python 2.3. Python 2.3 was +released on July 29, 2003. + +The main themes for Python 2.3 are polishing some of the features +added in 2.2, adding various small but useful enhancements to the core +language, and expanding the standard library. The new object model +introduced in the previous version has benefited from 18 months of +bugfixes and from optimization efforts that have improved the +performance of new-style classes. A few new built-in functions have +been added such as \function{sum()} and \function{enumerate()}. The +\keyword{in} operator can now be used for substring searches (e.g. +\code{"ab" in "abc"} returns \constant{True}). + +Some of the many new library features include Boolean, set, heap, and +date/time data types, the ability to import modules from ZIP-format +archives, metadata support for the long-awaited Python catalog, an +updated version of IDLE, and modules for logging messages, wrapping +text, parsing CSV files, processing command-line options, using BerkeleyDB +databases... the list of new and enhanced modules is lengthy. + +This article doesn't attempt to provide a complete specification of +the new features, but instead provides a convenient overview. For +full details, you should refer to the documentation for Python 2.3, +such as the \citetitle[../lib/lib.html]{Python Library Reference} and +the \citetitle[../ref/ref.html]{Python Reference Manual}. If you want +to understand the complete implementation and design rationale, +refer to the PEP for a particular new feature. + + +%====================================================================== +\section{PEP 218: A Standard Set Datatype} + +The new \module{sets} module contains an implementation of a set +datatype. The \class{Set} class is for mutable sets, sets that can +have members added and removed. The \class{ImmutableSet} class is for +sets that can't be modified, and instances of \class{ImmutableSet} can +therefore be used as dictionary keys. Sets are built on top of +dictionaries, so the elements within a set must be hashable. + +Here's a simple example: + +\begin{verbatim} +>>> import sets +>>> S = sets.Set([1,2,3]) +>>> S +Set([1, 2, 3]) +>>> 1 in S +True +>>> 0 in S +False +>>> S.add(5) +>>> S.remove(3) +>>> S +Set([1, 2, 5]) +>>> +\end{verbatim} + +The union and intersection of sets can be computed with the +\method{union()} and \method{intersection()} methods; an alternative +notation uses the bitwise operators \code{\&} and \code{|}. +Mutable sets also have in-place versions of these methods, +\method{union_update()} and \method{intersection_update()}. + +\begin{verbatim} +>>> S1 = sets.Set([1,2,3]) +>>> S2 = sets.Set([4,5,6]) +>>> S1.union(S2) +Set([1, 2, 3, 4, 5, 6]) +>>> S1 | S2 # Alternative notation +Set([1, 2, 3, 4, 5, 6]) +>>> S1.intersection(S2) +Set([]) +>>> S1 & S2 # Alternative notation +Set([]) +>>> S1.union_update(S2) +>>> S1 +Set([1, 2, 3, 4, 5, 6]) +>>> +\end{verbatim} + +It's also possible to take the symmetric difference of two sets. This +is the set of all elements in the union that aren't in the +intersection. Another way of putting it is that the symmetric +difference contains all elements that are in exactly one +set. Again, there's an alternative notation (\code{\^}), and an +in-place version with the ungainly name +\method{symmetric_difference_update()}. + +\begin{verbatim} +>>> S1 = sets.Set([1,2,3,4]) +>>> S2 = sets.Set([3,4,5,6]) +>>> S1.symmetric_difference(S2) +Set([1, 2, 5, 6]) +>>> S1 ^ S2 +Set([1, 2, 5, 6]) +>>> +\end{verbatim} + +There are also \method{issubset()} and \method{issuperset()} methods +for checking whether one set is a subset or superset of another: + +\begin{verbatim} +>>> S1 = sets.Set([1,2,3]) +>>> S2 = sets.Set([2,3]) +>>> S2.issubset(S1) +True +>>> S1.issubset(S2) +False +>>> S1.issuperset(S2) +True +>>> +\end{verbatim} + + +\begin{seealso} + +\seepep{218}{Adding a Built-In Set Object Type}{PEP written by Greg V. Wilson. +Implemented by Greg V. Wilson, Alex Martelli, and GvR.} + +\end{seealso} + + + +%====================================================================== +\section{PEP 255: Simple Generators\label{section-generators}} + +In Python 2.2, generators were added as an optional feature, to be +enabled by a \code{from __future__ import generators} directive. In +2.3 generators no longer need to be specially enabled, and are now +always present; this means that \keyword{yield} is now always a +keyword. The rest of this section is a copy of the description of +generators from the ``What's New in Python 2.2'' document; if you read +it back when Python 2.2 came out, you can skip the rest of this section. + +You're doubtless familiar with how function calls work in Python or C. +When you call a function, it gets a private namespace where its local +variables are created. When the function reaches a \keyword{return} +statement, the local variables are destroyed and the resulting value +is returned to the caller. A later call to the same function will get +a fresh new set of local variables. But, what if the local variables +weren't thrown away on exiting a function? What if you could later +resume the function where it left off? This is what generators +provide; they can be thought of as resumable functions. + +Here's the simplest example of a generator function: + +\begin{verbatim} +def generate_ints(N): + for i in range(N): + yield i +\end{verbatim} + +A new keyword, \keyword{yield}, was introduced for generators. Any +function containing a \keyword{yield} statement is a generator +function; this is detected by Python's bytecode compiler which +compiles the function specially as a result. + +When you call a generator function, it doesn't return a single value; +instead it returns a generator object that supports the iterator +protocol. On executing the \keyword{yield} statement, the generator +outputs the value of \code{i}, similar to a \keyword{return} +statement. The big difference between \keyword{yield} and a +\keyword{return} statement is that on reaching a \keyword{yield} the +generator's state of execution is suspended and local variables are +preserved. On the next call to the generator's \code{.next()} method, +the function will resume executing immediately after the +\keyword{yield} statement. (For complicated reasons, the +\keyword{yield} statement isn't allowed inside the \keyword{try} block +of a \keyword{try}...\keyword{finally} statement; read \pep{255} for a full +explanation of the interaction between \keyword{yield} and +exceptions.) + +Here's a sample usage of the \function{generate_ints()} generator: + +\begin{verbatim} +>>> gen = generate_ints(3) +>>> gen +<generator object at 0x8117f90> +>>> gen.next() +0 +>>> gen.next() +1 +>>> gen.next() +2 +>>> gen.next() +Traceback (most recent call last): + File "stdin", line 1, in ? + File "stdin", line 2, in generate_ints +StopIteration +\end{verbatim} + +You could equally write \code{for i in generate_ints(5)}, or +\code{a,b,c = generate_ints(3)}. + +Inside a generator function, the \keyword{return} statement can only +be used without a value, and signals the end of the procession of +values; afterwards the generator cannot return any further values. +\keyword{return} with a value, such as \code{return 5}, is a syntax +error inside a generator function. The end of the generator's results +can also be indicated by raising \exception{StopIteration} manually, +or by just letting the flow of execution fall off the bottom of the +function. + +You could achieve the effect of generators manually by writing your +own class and storing all the local variables of the generator as +instance variables. For example, returning a list of integers could +be done by setting \code{self.count} to 0, and having the +\method{next()} method increment \code{self.count} and return it. +However, for a moderately complicated generator, writing a +corresponding class would be much messier. +\file{Lib/test/test_generators.py} contains a number of more +interesting examples. The simplest one implements an in-order +traversal of a tree using generators recursively. + +\begin{verbatim} +# A recursive generator that generates Tree leaves in in-order. +def inorder(t): + if t: + for x in inorder(t.left): + yield x + yield t.label + for x in inorder(t.right): + yield x +\end{verbatim} + +Two other examples in \file{Lib/test/test_generators.py} produce +solutions for the N-Queens problem (placing $N$ queens on an $NxN$ +chess board so that no queen threatens another) and the Knight's Tour +(a route that takes a knight to every square of an $NxN$ chessboard +without visiting any square twice). + +The idea of generators comes from other programming languages, +especially Icon (\url{http://www.cs.arizona.edu/icon/}), where the +idea of generators is central. In Icon, every +expression and function call behaves like a generator. One example +from ``An Overview of the Icon Programming Language'' at +\url{http://www.cs.arizona.edu/icon/docs/ipd266.htm} gives an idea of +what this looks like: + +\begin{verbatim} +sentence := "Store it in the neighboring harbor" +if (i := find("or", sentence)) > 5 then write(i) +\end{verbatim} + +In Icon the \function{find()} function returns the indexes at which the +substring ``or'' is found: 3, 23, 33. In the \keyword{if} statement, +\code{i} is first assigned a value of 3, but 3 is less than 5, so the +comparison fails, and Icon retries it with the second value of 23. 23 +is greater than 5, so the comparison now succeeds, and the code prints +the value 23 to the screen. + +Python doesn't go nearly as far as Icon in adopting generators as a +central concept. Generators are considered part of the core +Python language, but learning or using them isn't compulsory; if they +don't solve any problems that you have, feel free to ignore them. +One novel feature of Python's interface as compared to +Icon's is that a generator's state is represented as a concrete object +(the iterator) that can be passed around to other functions or stored +in a data structure. + +\begin{seealso} + +\seepep{255}{Simple Generators}{Written by Neil Schemenauer, Tim +Peters, Magnus Lie Hetland. Implemented mostly by Neil Schemenauer +and Tim Peters, with other fixes from the Python Labs crew.} + +\end{seealso} + + +%====================================================================== +\section{PEP 263: Source Code Encodings \label{section-encodings}} + +Python source files can now be declared as being in different +character set encodings. Encodings are declared by including a +specially formatted comment in the first or second line of the source +file. For example, a UTF-8 file can be declared with: + +\begin{verbatim} +#!/usr/bin/env python +# -*- coding: UTF-8 -*- +\end{verbatim} + +Without such an encoding declaration, the default encoding used is +7-bit ASCII. Executing or importing modules that contain string +literals with 8-bit characters and have no encoding declaration will result +in a \exception{DeprecationWarning} being signalled by Python 2.3; in +2.4 this will be a syntax error. + +The encoding declaration only affects Unicode string literals, which +will be converted to Unicode using the specified encoding. Note that +Python identifiers are still restricted to ASCII characters, so you +can't have variable names that use characters outside of the usual +alphanumerics. + +\begin{seealso} + +\seepep{263}{Defining Python Source Code Encodings}{Written by +Marc-Andr\'e Lemburg and Martin von~L\"owis; implemented by Suzuki +Hisao and Martin von~L\"owis.} + +\end{seealso} + + +%====================================================================== +\section{PEP 273: Importing Modules from ZIP Archives} + +The new \module{zipimport} module adds support for importing +modules from a ZIP-format archive. You don't need to import the +module explicitly; it will be automatically imported if a ZIP +archive's filename is added to \code{sys.path}. For example: + +\begin{verbatim} +amk@nyman:~/src/python$ unzip -l /tmp/example.zip +Archive: /tmp/example.zip + Length Date Time Name + -------- ---- ---- ---- + 8467 11-26-02 22:30 jwzthreading.py + -------- ------- + 8467 1 file +amk@nyman:~/src/python$ ./python +Python 2.3 (#1, Aug 1 2003, 19:54:32) +>>> import sys +>>> sys.path.insert(0, '/tmp/example.zip') # Add .zip file to front of path +>>> import jwzthreading +>>> jwzthreading.__file__ +'/tmp/example.zip/jwzthreading.py' +>>> +\end{verbatim} + +An entry in \code{sys.path} can now be the filename of a ZIP archive. +The ZIP archive can contain any kind of files, but only files named +\file{*.py}, \file{*.pyc}, or \file{*.pyo} can be imported. If an +archive only contains \file{*.py} files, Python will not attempt to +modify the archive by adding the corresponding \file{*.pyc} file, meaning +that if a ZIP archive doesn't contain \file{*.pyc} files, importing may be +rather slow. + +A path within the archive can also be specified to only import from a +subdirectory; for example, the path \file{/tmp/example.zip/lib/} +would only import from the \file{lib/} subdirectory within the +archive. + +\begin{seealso} + +\seepep{273}{Import Modules from Zip Archives}{Written by James C. Ahlstrom, +who also provided an implementation. +Python 2.3 follows the specification in \pep{273}, +but uses an implementation written by Just van~Rossum +that uses the import hooks described in \pep{302}. +See section~\ref{section-pep302} for a description of the new import hooks. +} + +\end{seealso} + +%====================================================================== +\section{PEP 277: Unicode file name support for Windows NT} + +On Windows NT, 2000, and XP, the system stores file names as Unicode +strings. Traditionally, Python has represented file names as byte +strings, which is inadequate because it renders some file names +inaccessible. + +Python now allows using arbitrary Unicode strings (within the +limitations of the file system) for all functions that expect file +names, most notably the \function{open()} built-in function. If a Unicode +string is passed to \function{os.listdir()}, Python now returns a list +of Unicode strings. A new function, \function{os.getcwdu()}, returns +the current directory as a Unicode string. + +Byte strings still work as file names, and on Windows Python will +transparently convert them to Unicode using the \code{mbcs} encoding. + +Other systems also allow Unicode strings as file names but convert +them to byte strings before passing them to the system, which can +cause a \exception{UnicodeError} to be raised. Applications can test +whether arbitrary Unicode strings are supported as file names by +checking \member{os.path.supports_unicode_filenames}, a Boolean value. + +Under MacOS, \function{os.listdir()} may now return Unicode filenames. + +\begin{seealso} + +\seepep{277}{Unicode file name support for Windows NT}{Written by Neil +Hodgson; implemented by Neil Hodgson, Martin von~L\"owis, and Mark +Hammond.} + +\end{seealso} + + +%====================================================================== +\section{PEP 278: Universal Newline Support} + +The three major operating systems used today are Microsoft Windows, +Apple's Macintosh OS, and the various \UNIX\ derivatives. A minor +irritation of cross-platform work +is that these three platforms all use different characters +to mark the ends of lines in text files. \UNIX\ uses the linefeed +(ASCII character 10), MacOS uses the carriage return (ASCII +character 13), and Windows uses a two-character sequence of a +carriage return plus a newline. + +Python's file objects can now support end of line conventions other +than the one followed by the platform on which Python is running. +Opening a file with the mode \code{'U'} or \code{'rU'} will open a file +for reading in universal newline mode. All three line ending +conventions will be translated to a \character{\e n} in the strings +returned by the various file methods such as \method{read()} and +\method{readline()}. + +Universal newline support is also used when importing modules and when +executing a file with the \function{execfile()} function. This means +that Python modules can be shared between all three operating systems +without needing to convert the line-endings. + +This feature can be disabled when compiling Python by specifying +the \longprogramopt{without-universal-newlines} switch when running Python's +\program{configure} script. + +\begin{seealso} + +\seepep{278}{Universal Newline Support}{Written +and implemented by Jack Jansen.} + +\end{seealso} + + +%====================================================================== +\section{PEP 279: enumerate()\label{section-enumerate}} + +A new built-in function, \function{enumerate()}, will make +certain loops a bit clearer. \code{enumerate(thing)}, where +\var{thing} is either an iterator or a sequence, returns a iterator +that will return \code{(0, \var{thing}[0])}, \code{(1, +\var{thing}[1])}, \code{(2, \var{thing}[2])}, and so forth. + +A common idiom to change every element of a list looks like this: + +\begin{verbatim} +for i in range(len(L)): + item = L[i] + # ... compute some result based on item ... + L[i] = result +\end{verbatim} + +This can be rewritten using \function{enumerate()} as: + +\begin{verbatim} +for i, item in enumerate(L): + # ... compute some result based on item ... + L[i] = result +\end{verbatim} + + +\begin{seealso} + +\seepep{279}{The enumerate() built-in function}{Written +and implemented by Raymond D. Hettinger.} + +\end{seealso} + + +%====================================================================== +\section{PEP 282: The logging Package} + +A standard package for writing logs, \module{logging}, has been added +to Python 2.3. It provides a powerful and flexible mechanism for +generating logging output which can then be filtered and processed in +various ways. A configuration file written in a standard format can +be used to control the logging behavior of a program. Python +includes handlers that will write log records to +standard error or to a file or socket, send them to the system log, or +even e-mail them to a particular address; of course, it's also +possible to write your own handler classes. + +The \class{Logger} class is the primary class. +Most application code will deal with one or more \class{Logger} +objects, each one used by a particular subsystem of the application. +Each \class{Logger} is identified by a name, and names are organized +into a hierarchy using \samp{.} as the component separator. For +example, you might have \class{Logger} instances named \samp{server}, +\samp{server.auth} and \samp{server.network}. The latter two +instances are below \samp{server} in the hierarchy. This means that +if you turn up the verbosity for \samp{server} or direct \samp{server} +messages to a different handler, the changes will also apply to +records logged to \samp{server.auth} and \samp{server.network}. +There's also a root \class{Logger} that's the parent of all other +loggers. + +For simple uses, the \module{logging} package contains some +convenience functions that always use the root log: + +\begin{verbatim} +import logging + +logging.debug('Debugging information') +logging.info('Informational message') +logging.warning('Warning:config file %s not found', 'server.conf') +logging.error('Error occurred') +logging.critical('Critical error -- shutting down') +\end{verbatim} + +This produces the following output: + +\begin{verbatim} +WARNING:root:Warning:config file server.conf not found +ERROR:root:Error occurred +CRITICAL:root:Critical error -- shutting down +\end{verbatim} + +In the default configuration, informational and debugging messages are +suppressed and the output is sent to standard error. You can enable +the display of informational and debugging messages by calling the +\method{setLevel()} method on the root logger. + +Notice the \function{warning()} call's use of string formatting +operators; all of the functions for logging messages take the +arguments \code{(\var{msg}, \var{arg1}, \var{arg2}, ...)} and log the +string resulting from \code{\var{msg} \% (\var{arg1}, \var{arg2}, +...)}. + +There's also an \function{exception()} function that records the most +recent traceback. Any of the other functions will also record the +traceback if you specify a true value for the keyword argument +\var{exc_info}. + +\begin{verbatim} +def f(): + try: 1/0 + except: logging.exception('Problem recorded') + +f() +\end{verbatim} + +This produces the following output: + +\begin{verbatim} +ERROR:root:Problem recorded +Traceback (most recent call last): + File "t.py", line 6, in f + 1/0 +ZeroDivisionError: integer division or modulo by zero +\end{verbatim} + +Slightly more advanced programs will use a logger other than the root +logger. The \function{getLogger(\var{name})} function is used to get +a particular log, creating it if it doesn't exist yet. +\function{getLogger(None)} returns the root logger. + + +\begin{verbatim} +log = logging.getLogger('server') + ... +log.info('Listening on port %i', port) + ... +log.critical('Disk full') + ... +\end{verbatim} + +Log records are usually propagated up the hierarchy, so a message +logged to \samp{server.auth} is also seen by \samp{server} and +\samp{root}, but a \class{Logger} can prevent this by setting its +\member{propagate} attribute to \constant{False}. + +There are more classes provided by the \module{logging} package that +can be customized. When a \class{Logger} instance is told to log a +message, it creates a \class{LogRecord} instance that is sent to any +number of different \class{Handler} instances. Loggers and handlers +can also have an attached list of filters, and each filter can cause +the \class{LogRecord} to be ignored or can modify the record before +passing it along. When they're finally output, \class{LogRecord} +instances are converted to text by a \class{Formatter} class. All of +these classes can be replaced by your own specially-written classes. + +With all of these features the \module{logging} package should provide +enough flexibility for even the most complicated applications. This +is only an incomplete overview of its features, so please see the +\ulink{package's reference documentation}{../lib/module-logging.html} +for all of the details. Reading \pep{282} will also be helpful. + + +\begin{seealso} + +\seepep{282}{A Logging System}{Written by Vinay Sajip and Trent Mick; +implemented by Vinay Sajip.} + +\end{seealso} + + +%====================================================================== +\section{PEP 285: A Boolean Type\label{section-bool}} + +A Boolean type was added to Python 2.3. Two new constants were added +to the \module{__builtin__} module, \constant{True} and +\constant{False}. (\constant{True} and +\constant{False} constants were added to the built-ins +in Python 2.2.1, but the 2.2.1 versions are simply set to integer values of +1 and 0 and aren't a different type.) + +The type object for this new type is named +\class{bool}; the constructor for it takes any Python value and +converts it to \constant{True} or \constant{False}. + +\begin{verbatim} +>>> bool(1) +True +>>> bool(0) +False +>>> bool([]) +False +>>> bool( (1,) ) +True +\end{verbatim} + +Most of the standard library modules and built-in functions have been +changed to return Booleans. + +\begin{verbatim} +>>> obj = [] +>>> hasattr(obj, 'append') +True +>>> isinstance(obj, list) +True +>>> isinstance(obj, tuple) +False +\end{verbatim} + +Python's Booleans were added with the primary goal of making code +clearer. For example, if you're reading a function and encounter the +statement \code{return 1}, you might wonder whether the \code{1} +represents a Boolean truth value, an index, or a +coefficient that multiplies some other quantity. If the statement is +\code{return True}, however, the meaning of the return value is quite +clear. + +Python's Booleans were \emph{not} added for the sake of strict +type-checking. A very strict language such as Pascal would also +prevent you performing arithmetic with Booleans, and would require +that the expression in an \keyword{if} statement always evaluate to a +Boolean result. Python is not this strict and never will be, as +\pep{285} explicitly says. This means you can still use any +expression in an \keyword{if} statement, even ones that evaluate to a +list or tuple or some random object. The Boolean type is a +subclass of the \class{int} class so that arithmetic using a Boolean +still works. + +\begin{verbatim} +>>> True + 1 +2 +>>> False + 1 +1 +>>> False * 75 +0 +>>> True * 75 +75 +\end{verbatim} + +To sum up \constant{True} and \constant{False} in a sentence: they're +alternative ways to spell the integer values 1 and 0, with the single +difference that \function{str()} and \function{repr()} return the +strings \code{'True'} and \code{'False'} instead of \code{'1'} and +\code{'0'}. + +\begin{seealso} + +\seepep{285}{Adding a bool type}{Written and implemented by GvR.} + +\end{seealso} + + +%====================================================================== +\section{PEP 293: Codec Error Handling Callbacks} + +When encoding a Unicode string into a byte string, unencodable +characters may be encountered. So far, Python has allowed specifying +the error processing as either ``strict'' (raising +\exception{UnicodeError}), ``ignore'' (skipping the character), or +``replace'' (using a question mark in the output string), with +``strict'' being the default behavior. It may be desirable to specify +alternative processing of such errors, such as inserting an XML +character reference or HTML entity reference into the converted +string. + +Python now has a flexible framework to add different processing +strategies. New error handlers can be added with +\function{codecs.register_error}, and codecs then can access the error +handler with \function{codecs.lookup_error}. An equivalent C API has +been added for codecs written in C. The error handler gets the +necessary state information such as the string being converted, the +position in the string where the error was detected, and the target +encoding. The handler can then either raise an exception or return a +replacement string. + +Two additional error handlers have been implemented using this +framework: ``backslashreplace'' uses Python backslash quoting to +represent unencodable characters and ``xmlcharrefreplace'' emits +XML character references. + +\begin{seealso} + +\seepep{293}{Codec Error Handling Callbacks}{Written and implemented by +Walter D\"orwald.} + +\end{seealso} + + +%====================================================================== +\section{PEP 301: Package Index and Metadata for +Distutils\label{section-pep301}} + +Support for the long-requested Python catalog makes its first +appearance in 2.3. + +The heart of the catalog is the new Distutils \command{register} command. +Running \code{python setup.py register} will collect the metadata +describing a package, such as its name, version, maintainer, +description, \&c., and send it to a central catalog server. The +resulting catalog is available from \url{http://www.python.org/pypi}. + +To make the catalog a bit more useful, a new optional +\var{classifiers} keyword argument has been added to the Distutils +\function{setup()} function. A list of +\ulink{Trove}{http://catb.org/\textasciitilde esr/trove/}-style +strings can be supplied to help classify the software. + +Here's an example \file{setup.py} with classifiers, written to be compatible +with older versions of the Distutils: + +\begin{verbatim} +from distutils import core +kw = {'name': "Quixote", + 'version': "0.5.1", + 'description': "A highly Pythonic Web application framework", + # ... + } + +if (hasattr(core, 'setup_keywords') and + 'classifiers' in core.setup_keywords): + kw['classifiers'] = \ + ['Topic :: Internet :: WWW/HTTP :: Dynamic Content', + 'Environment :: No Input/Output (Daemon)', + 'Intended Audience :: Developers'], + +core.setup(**kw) +\end{verbatim} + +The full list of classifiers can be obtained by running +\verb|python setup.py register --list-classifiers|. + +\begin{seealso} + +\seepep{301}{Package Index and Metadata for Distutils}{Written and +implemented by Richard Jones.} + +\end{seealso} + + +%====================================================================== +\section{PEP 302: New Import Hooks \label{section-pep302}} + +While it's been possible to write custom import hooks ever since the +\module{ihooks} module was introduced in Python 1.3, no one has ever +been really happy with it because writing new import hooks is +difficult and messy. There have been various proposed alternatives +such as the \module{imputil} and \module{iu} modules, but none of them +has ever gained much acceptance, and none of them were easily usable +from \C{} code. + +\pep{302} borrows ideas from its predecessors, especially from +Gordon McMillan's \module{iu} module. Three new items +are added to the \module{sys} module: + +\begin{itemize} + \item \code{sys.path_hooks} is a list of callable objects; most + often they'll be classes. Each callable takes a string containing a + path and either returns an importer object that will handle imports + from this path or raises an \exception{ImportError} exception if it + can't handle this path. + + \item \code{sys.path_importer_cache} caches importer objects for + each path, so \code{sys.path_hooks} will only need to be traversed + once for each path. + + \item \code{sys.meta_path} is a list of importer objects that will + be traversed before \code{sys.path} is checked. This list is + initially empty, but user code can add objects to it. Additional + built-in and frozen modules can be imported by an object added to + this list. + +\end{itemize} + +Importer objects must have a single method, +\method{find_module(\var{fullname}, \var{path}=None)}. \var{fullname} +will be a module or package name, e.g. \samp{string} or +\samp{distutils.core}. \method{find_module()} must return a loader object +that has a single method, \method{load_module(\var{fullname})}, that +creates and returns the corresponding module object. + +Pseudo-code for Python's new import logic, therefore, looks something +like this (simplified a bit; see \pep{302} for the full details): + +\begin{verbatim} +for mp in sys.meta_path: + loader = mp(fullname) + if loader is not None: + <module> = loader.load_module(fullname) + +for path in sys.path: + for hook in sys.path_hooks: + try: + importer = hook(path) + except ImportError: + # ImportError, so try the other path hooks + pass + else: + loader = importer.find_module(fullname) + <module> = loader.load_module(fullname) + +# Not found! +raise ImportError +\end{verbatim} + +\begin{seealso} + +\seepep{302}{New Import Hooks}{Written by Just van~Rossum and Paul Moore. +Implemented by Just van~Rossum. +} + +\end{seealso} + + +%====================================================================== +\section{PEP 305: Comma-separated Files \label{section-pep305}} + +Comma-separated files are a format frequently used for exporting data +from databases and spreadsheets. Python 2.3 adds a parser for +comma-separated files. + +Comma-separated format is deceptively simple at first glance: + +\begin{verbatim} +Costs,150,200,3.95 +\end{verbatim} + +Read a line and call \code{line.split(',')}: what could be simpler? +But toss in string data that can contain commas, and things get more +complicated: + +\begin{verbatim} +"Costs",150,200,3.95,"Includes taxes, shipping, and sundry items" +\end{verbatim} + +A big ugly regular expression can parse this, but using the new +\module{csv} package is much simpler: + +\begin{verbatim} +import csv + +input = open('datafile', 'rb') +reader = csv.reader(input) +for line in reader: + print line +\end{verbatim} + +The \function{reader} function takes a number of different options. +The field separator isn't limited to the comma and can be changed to +any character, and so can the quoting and line-ending characters. + +Different dialects of comma-separated files can be defined and +registered; currently there are two dialects, both used by Microsoft Excel. +A separate \class{csv.writer} class will generate comma-separated files +from a succession of tuples or lists, quoting strings that contain the +delimiter. + +\begin{seealso} + +\seepep{305}{CSV File API}{Written and implemented +by Kevin Altis, Dave Cole, Andrew McNamara, Skip Montanaro, Cliff Wells. +} + +\end{seealso} + +%====================================================================== +\section{PEP 307: Pickle Enhancements \label{section-pep305}} + +The \module{pickle} and \module{cPickle} modules received some +attention during the 2.3 development cycle. In 2.2, new-style classes +could be pickled without difficulty, but they weren't pickled very +compactly; \pep{307} quotes a trivial example where a new-style class +results in a pickled string three times longer than that for a classic +class. + +The solution was to invent a new pickle protocol. The +\function{pickle.dumps()} function has supported a text-or-binary flag +for a long time. In 2.3, this flag is redefined from a Boolean to an +integer: 0 is the old text-mode pickle format, 1 is the old binary +format, and now 2 is a new 2.3-specific format. A new constant, +\constant{pickle.HIGHEST_PROTOCOL}, can be used to select the fanciest +protocol available. + +Unpickling is no longer considered a safe operation. 2.2's +\module{pickle} provided hooks for trying to prevent unsafe classes +from being unpickled (specifically, a +\member{__safe_for_unpickling__} attribute), but none of this code +was ever audited and therefore it's all been ripped out in 2.3. You +should not unpickle untrusted data in any version of Python. + +To reduce the pickling overhead for new-style classes, a new interface +for customizing pickling was added using three special methods: +\method{__getstate__}, \method{__setstate__}, and +\method{__getnewargs__}. Consult \pep{307} for the full semantics +of these methods. + +As a way to compress pickles yet further, it's now possible to use +integer codes instead of long strings to identify pickled classes. +The Python Software Foundation will maintain a list of standardized +codes; there's also a range of codes for private use. Currently no +codes have been specified. + +\begin{seealso} + +\seepep{307}{Extensions to the pickle protocol}{Written and implemented +by Guido van Rossum and Tim Peters.} + +\end{seealso} + +%====================================================================== +\section{Extended Slices\label{section-slices}} + +Ever since Python 1.4, the slicing syntax has supported an optional +third ``step'' or ``stride'' argument. For example, these are all +legal Python syntax: \code{L[1:10:2]}, \code{L[:-1:1]}, +\code{L[::-1]}. This was added to Python at the request of +the developers of Numerical Python, which uses the third argument +extensively. However, Python's built-in list, tuple, and string +sequence types have never supported this feature, raising a +\exception{TypeError} if you tried it. Michael Hudson contributed a +patch to fix this shortcoming. + +For example, you can now easily extract the elements of a list that +have even indexes: + +\begin{verbatim} +>>> L = range(10) +>>> L[::2] +[0, 2, 4, 6, 8] +\end{verbatim} + +Negative values also work to make a copy of the same list in reverse +order: + +\begin{verbatim} +>>> L[::-1] +[9, 8, 7, 6, 5, 4, 3, 2, 1, 0] +\end{verbatim} + +This also works for tuples, arrays, and strings: + +\begin{verbatim} +>>> s='abcd' +>>> s[::2] +'ac' +>>> s[::-1] +'dcba' +\end{verbatim} + +If you have a mutable sequence such as a list or an array you can +assign to or delete an extended slice, but there are some differences +between assignment to extended and regular slices. Assignment to a +regular slice can be used to change the length of the sequence: + +\begin{verbatim} +>>> a = range(3) +>>> a +[0, 1, 2] +>>> a[1:3] = [4, 5, 6] +>>> a +[0, 4, 5, 6] +\end{verbatim} + +Extended slices aren't this flexible. When assigning to an extended +slice, the list on the right hand side of the statement must contain +the same number of items as the slice it is replacing: + +\begin{verbatim} +>>> a = range(4) +>>> a +[0, 1, 2, 3] +>>> a[::2] +[0, 2] +>>> a[::2] = [0, -1] +>>> a +[0, 1, -1, 3] +>>> a[::2] = [0,1,2] +Traceback (most recent call last): + File "<stdin>", line 1, in ? +ValueError: attempt to assign sequence of size 3 to extended slice of size 2 +\end{verbatim} + +Deletion is more straightforward: + +\begin{verbatim} +>>> a = range(4) +>>> a +[0, 1, 2, 3] +>>> a[::2] +[0, 2] +>>> del a[::2] +>>> a +[1, 3] +\end{verbatim} + +One can also now pass slice objects to the +\method{__getitem__} methods of the built-in sequences: + +\begin{verbatim} +>>> range(10).__getitem__(slice(0, 5, 2)) +[0, 2, 4] +\end{verbatim} + +Or use slice objects directly in subscripts: + +\begin{verbatim} +>>> range(10)[slice(0, 5, 2)] +[0, 2, 4] +\end{verbatim} + +To simplify implementing sequences that support extended slicing, +slice objects now have a method \method{indices(\var{length})} which, +given the length of a sequence, returns a \code{(\var{start}, +\var{stop}, \var{step})} tuple that can be passed directly to +\function{range()}. +\method{indices()} handles omitted and out-of-bounds indices in a +manner consistent with regular slices (and this innocuous phrase hides +a welter of confusing details!). The method is intended to be used +like this: + +\begin{verbatim} +class FakeSeq: + ... + def calc_item(self, i): + ... + def __getitem__(self, item): + if isinstance(item, slice): + indices = item.indices(len(self)) + return FakeSeq([self.calc_item(i) for i in range(*indices)]) + else: + return self.calc_item(i) +\end{verbatim} + +From this example you can also see that the built-in \class{slice} +object is now the type object for the slice type, and is no longer a +function. This is consistent with Python 2.2, where \class{int}, +\class{str}, etc., underwent the same change. + + +%====================================================================== +\section{Other Language Changes} + +Here are all of the changes that Python 2.3 makes to the core Python +language. + +\begin{itemize} +\item The \keyword{yield} statement is now always a keyword, as +described in section~\ref{section-generators} of this document. + +\item A new built-in function \function{enumerate()} +was added, as described in section~\ref{section-enumerate} of this +document. + +\item Two new constants, \constant{True} and \constant{False} were +added along with the built-in \class{bool} type, as described in +section~\ref{section-bool} of this document. + +\item The \function{int()} type constructor will now return a long +integer instead of raising an \exception{OverflowError} when a string +or floating-point number is too large to fit into an integer. This +can lead to the paradoxical result that +\code{isinstance(int(\var{expression}), int)} is false, but that seems +unlikely to cause problems in practice. + +\item Built-in types now support the extended slicing syntax, +as described in section~\ref{section-slices} of this document. + +\item A new built-in function, \function{sum(\var{iterable}, \var{start}=0)}, +adds up the numeric items in the iterable object and returns their sum. +\function{sum()} only accepts numbers, meaning that you can't use it +to concatenate a bunch of strings. (Contributed by Alex +Martelli.) + +\item \code{list.insert(\var{pos}, \var{value})} used to +insert \var{value} at the front of the list when \var{pos} was +negative. The behaviour has now been changed to be consistent with +slice indexing, so when \var{pos} is -1 the value will be inserted +before the last element, and so forth. + +\item \code{list.index(\var{value})}, which searches for \var{value} +within the list and returns its index, now takes optional +\var{start} and \var{stop} arguments to limit the search to +only part of the list. + +\item Dictionaries have a new method, \method{pop(\var{key}\optional{, +\var{default}})}, that returns the value corresponding to \var{key} +and removes that key/value pair from the dictionary. If the requested +key isn't present in the dictionary, \var{default} is returned if it's +specified and \exception{KeyError} raised if it isn't. + +\begin{verbatim} +>>> d = {1:2} +>>> d +{1: 2} +>>> d.pop(4) +Traceback (most recent call last): + File "stdin", line 1, in ? +KeyError: 4 +>>> d.pop(1) +2 +>>> d.pop(1) +Traceback (most recent call last): + File "stdin", line 1, in ? +KeyError: 'pop(): dictionary is empty' +>>> d +{} +>>> +\end{verbatim} + +There's also a new class method, +\method{dict.fromkeys(\var{iterable}, \var{value})}, that +creates a dictionary with keys taken from the supplied iterator +\var{iterable} and all values set to \var{value}, defaulting to +\code{None}. + +(Patches contributed by Raymond Hettinger.) + +Also, the \function{dict()} constructor now accepts keyword arguments to +simplify creating small dictionaries: + +\begin{verbatim} +>>> dict(red=1, blue=2, green=3, black=4) +{'blue': 2, 'black': 4, 'green': 3, 'red': 1} +\end{verbatim} + +(Contributed by Just van~Rossum.) + +\item The \keyword{assert} statement no longer checks the \code{__debug__} +flag, so you can no longer disable assertions by assigning to \code{__debug__}. +Running Python with the \programopt{-O} switch will still generate +code that doesn't execute any assertions. + +\item Most type objects are now callable, so you can use them +to create new objects such as functions, classes, and modules. (This +means that the \module{new} module can be deprecated in a future +Python version, because you can now use the type objects available in +the \module{types} module.) +% XXX should new.py use PendingDeprecationWarning? +For example, you can create a new module object with the following code: + +\begin{verbatim} +>>> import types +>>> m = types.ModuleType('abc','docstring') +>>> m +<module 'abc' (built-in)> +>>> m.__doc__ +'docstring' +\end{verbatim} + +\item +A new warning, \exception{PendingDeprecationWarning} was added to +indicate features which are in the process of being +deprecated. The warning will \emph{not} be printed by default. To +check for use of features that will be deprecated in the future, +supply \programopt{-Walways::PendingDeprecationWarning::} on the +command line or use \function{warnings.filterwarnings()}. + +\item The process of deprecating string-based exceptions, as +in \code{raise "Error occurred"}, has begun. Raising a string will +now trigger \exception{PendingDeprecationWarning}. + +\item Using \code{None} as a variable name will now result in a +\exception{SyntaxWarning} warning. In a future version of Python, +\code{None} may finally become a keyword. + +\item The \method{xreadlines()} method of file objects, introduced in +Python 2.1, is no longer necessary because files now behave as their +own iterator. \method{xreadlines()} was originally introduced as a +faster way to loop over all the lines in a file, but now you can +simply write \code{for line in file_obj}. File objects also have a +new read-only \member{encoding} attribute that gives the encoding used +by the file; Unicode strings written to the file will be automatically +converted to bytes using the given encoding. + +\item The method resolution order used by new-style classes has +changed, though you'll only notice the difference if you have a really +complicated inheritance hierarchy. Classic classes are unaffected by +this change. Python 2.2 originally used a topological sort of a +class's ancestors, but 2.3 now uses the C3 algorithm as described in +the paper \ulink{``A Monotonic Superclass Linearization for +Dylan''}{http://www.webcom.com/haahr/dylan/linearization-oopsla96.html}. +To understand the motivation for this change, +read Michele Simionato's article +\ulink{``Python 2.3 Method Resolution Order''} + {http://www.python.org/2.3/mro.html}, or +read the thread on python-dev starting with the message at +\url{http://mail.python.org/pipermail/python-dev/2002-October/029035.html}. +Samuele Pedroni first pointed out the problem and also implemented the +fix by coding the C3 algorithm. + +\item Python runs multithreaded programs by switching between threads +after executing N bytecodes. The default value for N has been +increased from 10 to 100 bytecodes, speeding up single-threaded +applications by reducing the switching overhead. Some multithreaded +applications may suffer slower response time, but that's easily fixed +by setting the limit back to a lower number using +\function{sys.setcheckinterval(\var{N})}. +The limit can be retrieved with the new +\function{sys.getcheckinterval()} function. + +\item One minor but far-reaching change is that the names of extension +types defined by the modules included with Python now contain the +module and a \character{.} in front of the type name. For example, in +Python 2.2, if you created a socket and printed its +\member{__class__}, you'd get this output: + +\begin{verbatim} +>>> s = socket.socket() +>>> s.__class__ +<type 'socket'> +\end{verbatim} + +In 2.3, you get this: +\begin{verbatim} +>>> s.__class__ +<type '_socket.socket'> +\end{verbatim} + +\item One of the noted incompatibilities between old- and new-style + classes has been removed: you can now assign to the + \member{__name__} and \member{__bases__} attributes of new-style + classes. There are some restrictions on what can be assigned to + \member{__bases__} along the lines of those relating to assigning to + an instance's \member{__class__} attribute. + +\end{itemize} + + +%====================================================================== +\subsection{String Changes} + +\begin{itemize} + +\item The \keyword{in} operator now works differently for strings. +Previously, when evaluating \code{\var{X} in \var{Y}} where \var{X} +and \var{Y} are strings, \var{X} could only be a single character. +That's now changed; \var{X} can be a string of any length, and +\code{\var{X} in \var{Y}} will return \constant{True} if \var{X} is a +substring of \var{Y}. If \var{X} is the empty string, the result is +always \constant{True}. + +\begin{verbatim} +>>> 'ab' in 'abcd' +True +>>> 'ad' in 'abcd' +False +>>> '' in 'abcd' +True +\end{verbatim} + +Note that this doesn't tell you where the substring starts; if you +need that information, use the \method{find()} string method. + +\item The \method{strip()}, \method{lstrip()}, and \method{rstrip()} +string methods now have an optional argument for specifying the +characters to strip. The default is still to remove all whitespace +characters: + +\begin{verbatim} +>>> ' abc '.strip() +'abc' +>>> '><><abc<><><>'.strip('<>') +'abc' +>>> '><><abc<><><>\n'.strip('<>') +'abc<><><>\n' +>>> u'\u4000\u4001abc\u4000'.strip(u'\u4000') +u'\u4001abc' +>>> +\end{verbatim} + +(Suggested by Simon Brunning and implemented by Walter D\"orwald.) + +\item The \method{startswith()} and \method{endswith()} +string methods now accept negative numbers for the \var{start} and \var{end} +parameters. + +\item Another new string method is \method{zfill()}, originally a +function in the \module{string} module. \method{zfill()} pads a +numeric string with zeros on the left until it's the specified width. +Note that the \code{\%} operator is still more flexible and powerful +than \method{zfill()}. + +\begin{verbatim} +>>> '45'.zfill(4) +'0045' +>>> '12345'.zfill(4) +'12345' +>>> 'goofy'.zfill(6) +'0goofy' +\end{verbatim} + +(Contributed by Walter D\"orwald.) + +\item A new type object, \class{basestring}, has been added. + Both 8-bit strings and Unicode strings inherit from this type, so + \code{isinstance(obj, basestring)} will return \constant{True} for + either kind of string. It's a completely abstract type, so you + can't create \class{basestring} instances. + +\item Interned strings are no longer immortal and will now be +garbage-collected in the usual way when the only reference to them is +from the internal dictionary of interned strings. (Implemented by +Oren Tirosh.) + +\end{itemize} + + +%====================================================================== +\subsection{Optimizations} + +\begin{itemize} + +\item The creation of new-style class instances has been made much +faster; they're now faster than classic classes! + +\item The \method{sort()} method of list objects has been extensively +rewritten by Tim Peters, and the implementation is significantly +faster. + +\item Multiplication of large long integers is now much faster thanks +to an implementation of Karatsuba multiplication, an algorithm that +scales better than the O(n*n) required for the grade-school +multiplication algorithm. (Original patch by Christopher A. Craig, +and significantly reworked by Tim Peters.) + +\item The \code{SET_LINENO} opcode is now gone. This may provide a +small speed increase, depending on your compiler's idiosyncrasies. +See section~\ref{section-other} for a longer explanation. +(Removed by Michael Hudson.) + +\item \function{xrange()} objects now have their own iterator, making +\code{for i in xrange(n)} slightly faster than +\code{for i in range(n)}. (Patch by Raymond Hettinger.) + +\item A number of small rearrangements have been made in various +hotspots to improve performance, such as inlining a function or removing +some code. (Implemented mostly by GvR, but lots of people have +contributed single changes.) + +\end{itemize} + +The net result of the 2.3 optimizations is that Python 2.3 runs the +pystone benchmark around 25\% faster than Python 2.2. + + +%====================================================================== +\section{New, Improved, and Deprecated Modules} + +As usual, Python's standard library received a number of enhancements and +bug fixes. Here's a partial list of the most notable changes, sorted +alphabetically by module name. Consult the +\file{Misc/NEWS} file in the source tree for a more +complete list of changes, or look through the CVS logs for all the +details. + +\begin{itemize} + +\item The \module{array} module now supports arrays of Unicode +characters using the \character{u} format character. Arrays also now +support using the \code{+=} assignment operator to add another array's +contents, and the \code{*=} assignment operator to repeat an array. +(Contributed by Jason Orendorff.) + +\item The \module{bsddb} module has been replaced by version 4.1.6 +of the \ulink{PyBSDDB}{http://pybsddb.sourceforge.net} package, +providing a more complete interface to the transactional features of +the BerkeleyDB library. + +The old version of the module has been renamed to +\module{bsddb185} and is no longer built automatically; you'll +have to edit \file{Modules/Setup} to enable it. Note that the new +\module{bsddb} package is intended to be compatible with the +old module, so be sure to file bugs if you discover any +incompatibilities. When upgrading to Python 2.3, if the new interpreter is compiled +with a new version of +the underlying BerkeleyDB library, you will almost certainly have to +convert your database files to the new version. You can do this +fairly easily with the new scripts \file{db2pickle.py} and +\file{pickle2db.py} which you will find in the distribution's +\file{Tools/scripts} directory. If you've already been using the PyBSDDB +package and importing it as \module{bsddb3}, you will have to change your +\code{import} statements to import it as \module{bsddb}. + +\item The new \module{bz2} module is an interface to the bz2 data +compression library. bz2-compressed data is usually smaller than +corresponding \module{zlib}-compressed data. (Contributed by Gustavo Niemeyer.) + +\item A set of standard date/time types has been added in the new \module{datetime} +module. See the following section for more details. + +\item The Distutils \class{Extension} class now supports +an extra constructor argument named \var{depends} for listing +additional source files that an extension depends on. This lets +Distutils recompile the module if any of the dependency files are +modified. For example, if \file{sampmodule.c} includes the header +file \file{sample.h}, you would create the \class{Extension} object like +this: + +\begin{verbatim} +ext = Extension("samp", + sources=["sampmodule.c"], + depends=["sample.h"]) +\end{verbatim} + +Modifying \file{sample.h} would then cause the module to be recompiled. +(Contributed by Jeremy Hylton.) + +\item Other minor changes to Distutils: +it now checks for the \envvar{CC}, \envvar{CFLAGS}, \envvar{CPP}, +\envvar{LDFLAGS}, and \envvar{CPPFLAGS} environment variables, using +them to override the settings in Python's configuration (contributed +by Robert Weber). + +\item Previously the \module{doctest} module would only search the +docstrings of public methods and functions for test cases, but it now +also examines private ones as well. The \function{DocTestSuite(} +function creates a \class{unittest.TestSuite} object from a set of +\module{doctest} tests. + +\item The new \function{gc.get_referents(\var{object})} function returns a +list of all the objects referenced by \var{object}. + +\item The \module{getopt} module gained a new function, +\function{gnu_getopt()}, that supports the same arguments as the existing +\function{getopt()} function but uses GNU-style scanning mode. +The existing \function{getopt()} stops processing options as soon as a +non-option argument is encountered, but in GNU-style mode processing +continues, meaning that options and arguments can be mixed. For +example: + +\begin{verbatim} +>>> getopt.getopt(['-f', 'filename', 'output', '-v'], 'f:v') +([('-f', 'filename')], ['output', '-v']) +>>> getopt.gnu_getopt(['-f', 'filename', 'output', '-v'], 'f:v') +([('-f', 'filename'), ('-v', '')], ['output']) +\end{verbatim} + +(Contributed by Peter \AA{strand}.) + +\item The \module{grp}, \module{pwd}, and \module{resource} modules +now return enhanced tuples: + +\begin{verbatim} +>>> import grp +>>> g = grp.getgrnam('amk') +>>> g.gr_name, g.gr_gid +('amk', 500) +\end{verbatim} + +\item The \module{gzip} module can now handle files exceeding 2~GiB. + +\item The new \module{heapq} module contains an implementation of a +heap queue algorithm. A heap is an array-like data structure that +keeps items in a partially sorted order such that, for every index +\var{k}, \code{heap[\var{k}] <= heap[2*\var{k}+1]} and +\code{heap[\var{k}] <= heap[2*\var{k}+2]}. This makes it quick to +remove the smallest item, and inserting a new item while maintaining +the heap property is O(lg~n). (See +\url{http://www.nist.gov/dads/HTML/priorityque.html} for more +information about the priority queue data structure.) + +The \module{heapq} module provides \function{heappush()} and +\function{heappop()} functions for adding and removing items while +maintaining the heap property on top of some other mutable Python +sequence type. Here's an example that uses a Python list: + +\begin{verbatim} +>>> import heapq +>>> heap = [] +>>> for item in [3, 7, 5, 11, 1]: +... heapq.heappush(heap, item) +... +>>> heap +[1, 3, 5, 11, 7] +>>> heapq.heappop(heap) +1 +>>> heapq.heappop(heap) +3 +>>> heap +[5, 7, 11] +\end{verbatim} + +(Contributed by Kevin O'Connor.) + +\item The IDLE integrated development environment has been updated +using the code from the IDLEfork project +(\url{http://idlefork.sf.net}). The most notable feature is that the +code being developed is now executed in a subprocess, meaning that +there's no longer any need for manual \code{reload()} operations. +IDLE's core code has been incorporated into the standard library as the +\module{idlelib} package. + +\item The \module{imaplib} module now supports IMAP over SSL. +(Contributed by Piers Lauder and Tino Lange.) + +\item The \module{itertools} contains a number of useful functions for +use with iterators, inspired by various functions provided by the ML +and Haskell languages. For example, +\code{itertools.ifilter(predicate, iterator)} returns all elements in +the iterator for which the function \function{predicate()} returns +\constant{True}, and \code{itertools.repeat(obj, \var{N})} returns +\code{obj} \var{N} times. There are a number of other functions in +the module; see the \ulink{package's reference +documentation}{../lib/module-itertools.html} for details. +(Contributed by Raymond Hettinger.) + +\item Two new functions in the \module{math} module, +\function{degrees(\var{rads})} and \function{radians(\var{degs})}, +convert between radians and degrees. Other functions in the +\module{math} module such as \function{math.sin()} and +\function{math.cos()} have always required input values measured in +radians. Also, an optional \var{base} argument was added to +\function{math.log()} to make it easier to compute logarithms for +bases other than \code{e} and \code{10}. (Contributed by Raymond +Hettinger.) + +\item Several new POSIX functions (\function{getpgid()}, \function{killpg()}, +\function{lchown()}, \function{loadavg()}, \function{major()}, \function{makedev()}, +\function{minor()}, and \function{mknod()}) were added to the +\module{posix} module that underlies the \module{os} module. +(Contributed by Gustavo Niemeyer, Geert Jansen, and Denis S. Otkidach.) + +\item In the \module{os} module, the \function{*stat()} family of +functions can now report fractions of a second in a timestamp. Such +time stamps are represented as floats, similar to +the value returned by \function{time.time()}. + +During testing, it was found that some applications will break if time +stamps are floats. For compatibility, when using the tuple interface +of the \class{stat_result} time stamps will be represented as integers. +When using named fields (a feature first introduced in Python 2.2), +time stamps are still represented as integers, unless +\function{os.stat_float_times()} is invoked to enable float return +values: + +\begin{verbatim} +>>> os.stat("/tmp").st_mtime +1034791200 +>>> os.stat_float_times(True) +>>> os.stat("/tmp").st_mtime +1034791200.6335014 +\end{verbatim} + +In Python 2.4, the default will change to always returning floats. + +Application developers should enable this feature only if all their +libraries work properly when confronted with floating point time +stamps, or if they use the tuple API. If used, the feature should be +activated on an application level instead of trying to enable it on a +per-use basis. + +\item The \module{optparse} module contains a new parser for command-line arguments +that can convert option values to a particular Python type +and will automatically generate a usage message. See the following section for +more details. + +\item The old and never-documented \module{linuxaudiodev} module has +been deprecated, and a new version named \module{ossaudiodev} has been +added. The module was renamed because the OSS sound drivers can be +used on platforms other than Linux, and the interface has also been +tidied and brought up to date in various ways. (Contributed by Greg +Ward and Nicholas FitzRoy-Dale.) + +\item The new \module{platform} module contains a number of functions +that try to determine various properties of the platform you're +running on. There are functions for getting the architecture, CPU +type, the Windows OS version, and even the Linux distribution version. +(Contributed by Marc-Andr\'e Lemburg.) + +\item The parser objects provided by the \module{pyexpat} module +can now optionally buffer character data, resulting in fewer calls to +your character data handler and therefore faster performance. Setting +the parser object's \member{buffer_text} attribute to \constant{True} +will enable buffering. + +\item The \function{sample(\var{population}, \var{k})} function was +added to the \module{random} module. \var{population} is a sequence or +\class{xrange} object containing the elements of a population, and +\function{sample()} chooses \var{k} elements from the population without +replacing chosen elements. \var{k} can be any value up to +\code{len(\var{population})}. For example: + +\begin{verbatim} +>>> days = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'St', 'Sn'] +>>> random.sample(days, 3) # Choose 3 elements +['St', 'Sn', 'Th'] +>>> random.sample(days, 7) # Choose 7 elements +['Tu', 'Th', 'Mo', 'We', 'St', 'Fr', 'Sn'] +>>> random.sample(days, 7) # Choose 7 again +['We', 'Mo', 'Sn', 'Fr', 'Tu', 'St', 'Th'] +>>> random.sample(days, 8) # Can't choose eight +Traceback (most recent call last): + File "<stdin>", line 1, in ? + File "random.py", line 414, in sample + raise ValueError, "sample larger than population" +ValueError: sample larger than population +>>> random.sample(xrange(1,10000,2), 10) # Choose ten odd nos. under 10000 +[3407, 3805, 1505, 7023, 2401, 2267, 9733, 3151, 8083, 9195] +\end{verbatim} + +The \module{random} module now uses a new algorithm, the Mersenne +Twister, implemented in C. It's faster and more extensively studied +than the previous algorithm. + +(All changes contributed by Raymond Hettinger.) + +\item The \module{readline} module also gained a number of new +functions: \function{get_history_item()}, +\function{get_current_history_length()}, and \function{redisplay()}. + +\item The \module{rexec} and \module{Bastion} modules have been +declared dead, and attempts to import them will fail with a +\exception{RuntimeError}. New-style classes provide new ways to break +out of the restricted execution environment provided by +\module{rexec}, and no one has interest in fixing them or time to do +so. If you have applications using \module{rexec}, rewrite them to +use something else. + +(Sticking with Python 2.2 or 2.1 will not make your applications any +safer because there are known bugs in the \module{rexec} module in +those versions. To repeat: if you're using \module{rexec}, stop using +it immediately.) + +\item The \module{rotor} module has been deprecated because the + algorithm it uses for encryption is not believed to be secure. If + you need encryption, use one of the several AES Python modules + that are available separately. + +\item The \module{shutil} module gained a \function{move(\var{src}, +\var{dest})} function that recursively moves a file or directory to a new +location. + +\item Support for more advanced POSIX signal handling was added +to the \module{signal} but then removed again as it proved impossible +to make it work reliably across platforms. + +\item The \module{socket} module now supports timeouts. You +can call the \method{settimeout(\var{t})} method on a socket object to +set a timeout of \var{t} seconds. Subsequent socket operations that +take longer than \var{t} seconds to complete will abort and raise a +\exception{socket.timeout} exception. + +The original timeout implementation was by Tim O'Malley. Michael +Gilfix integrated it into the Python \module{socket} module and +shepherded it through a lengthy review. After the code was checked +in, Guido van~Rossum rewrote parts of it. (This is a good example of +a collaborative development process in action.) + +\item On Windows, the \module{socket} module now ships with Secure +Sockets Layer (SSL) support. + +\item The value of the C \constant{PYTHON_API_VERSION} macro is now +exposed at the Python level as \code{sys.api_version}. The current +exception can be cleared by calling the new \function{sys.exc_clear()} +function. + +\item The new \module{tarfile} module +allows reading from and writing to \program{tar}-format archive files. +(Contributed by Lars Gust\"abel.) + +\item The new \module{textwrap} module contains functions for wrapping +strings containing paragraphs of text. The \function{wrap(\var{text}, +\var{width})} function takes a string and returns a list containing +the text split into lines of no more than the chosen width. The +\function{fill(\var{text}, \var{width})} function returns a single +string, reformatted to fit into lines no longer than the chosen width. +(As you can guess, \function{fill()} is built on top of +\function{wrap()}. For example: + +\begin{verbatim} +>>> import textwrap +>>> paragraph = "Not a whit, we defy augury: ... more text ..." +>>> textwrap.wrap(paragraph, 60) +["Not a whit, we defy augury: there's a special providence in", + "the fall of a sparrow. If it be now, 'tis not to come; if it", + ...] +>>> print textwrap.fill(paragraph, 35) +Not a whit, we defy augury: there's +a special providence in the fall of +a sparrow. If it be now, 'tis not +to come; if it be not to come, it +will be now; if it be not now, yet +it will come: the readiness is all. +>>> +\end{verbatim} + +The module also contains a \class{TextWrapper} class that actually +implements the text wrapping strategy. Both the +\class{TextWrapper} class and the \function{wrap()} and +\function{fill()} functions support a number of additional keyword +arguments for fine-tuning the formatting; consult the \ulink{module's +documentation}{../lib/module-textwrap.html} for details. +(Contributed by Greg Ward.) + +\item The \module{thread} and \module{threading} modules now have +companion modules, \module{dummy_thread} and \module{dummy_threading}, +that provide a do-nothing implementation of the \module{thread} +module's interface for platforms where threads are not supported. The +intention is to simplify thread-aware modules (ones that \emph{don't} +rely on threads to run) by putting the following code at the top: + +\begin{verbatim} +try: + import threading as _threading +except ImportError: + import dummy_threading as _threading +\end{verbatim} + +In this example, \module{_threading} is used as the module name to make +it clear that the module being used is not necessarily the actual +\module{threading} module. Code can call functions and use classes in +\module{_threading} whether or not threads are supported, avoiding an +\keyword{if} statement and making the code slightly clearer. This +module will not magically make multithreaded code run without threads; +code that waits for another thread to return or to do something will +simply hang forever. + +\item The \module{time} module's \function{strptime()} function has +long been an annoyance because it uses the platform C library's +\function{strptime()} implementation, and different platforms +sometimes have odd bugs. Brett Cannon contributed a portable +implementation that's written in pure Python and should behave +identically on all platforms. + +\item The new \module{timeit} module helps measure how long snippets +of Python code take to execute. The \file{timeit.py} file can be run +directly from the command line, or the module's \class{Timer} class +can be imported and used directly. Here's a short example that +figures out whether it's faster to convert an 8-bit string to Unicode +by appending an empty Unicode string to it or by using the +\function{unicode()} function: + +\begin{verbatim} +import timeit + +timer1 = timeit.Timer('unicode("abc")') +timer2 = timeit.Timer('"abc" + u""') + +# Run three trials +print timer1.repeat(repeat=3, number=100000) +print timer2.repeat(repeat=3, number=100000) + +# On my laptop this outputs: +# [0.36831796169281006, 0.37441694736480713, 0.35304892063140869] +# [0.17574405670166016, 0.18193507194519043, 0.17565798759460449] +\end{verbatim} + +\item The \module{Tix} module has received various bug fixes and +updates for the current version of the Tix package. + +\item The \module{Tkinter} module now works with a thread-enabled +version of Tcl. Tcl's threading model requires that widgets only be +accessed from the thread in which they're created; accesses from +another thread can cause Tcl to panic. For certain Tcl interfaces, +\module{Tkinter} will now automatically avoid this +when a widget is accessed from a different thread by marshalling a +command, passing it to the correct thread, and waiting for the +results. Other interfaces can't be handled automatically but +\module{Tkinter} will now raise an exception on such an access so that +you can at least find out about the problem. See +\url{http://mail.python.org/pipermail/python-dev/2002-December/031107.html} % +for a more detailed explanation of this change. (Implemented by +Martin von~L\"owis.) + +\item Calling Tcl methods through \module{_tkinter} no longer +returns only strings. Instead, if Tcl returns other objects those +objects are converted to their Python equivalent, if one exists, or +wrapped with a \class{_tkinter.Tcl_Obj} object if no Python equivalent +exists. This behavior can be controlled through the +\method{wantobjects()} method of \class{tkapp} objects. + +When using \module{_tkinter} through the \module{Tkinter} module (as +most Tkinter applications will), this feature is always activated. It +should not cause compatibility problems, since Tkinter would always +convert string results to Python types where possible. + +If any incompatibilities are found, the old behavior can be restored +by setting the \member{wantobjects} variable in the \module{Tkinter} +module to false before creating the first \class{tkapp} object. + +\begin{verbatim} +import Tkinter +Tkinter.wantobjects = 0 +\end{verbatim} + +Any breakage caused by this change should be reported as a bug. + +\item The \module{UserDict} module has a new \class{DictMixin} class which +defines all dictionary methods for classes that already have a minimum +mapping interface. This greatly simplifies writing classes that need +to be substitutable for dictionaries, such as the classes in +the \module{shelve} module. + +Adding the mix-in as a superclass provides the full dictionary +interface whenever the class defines \method{__getitem__}, +\method{__setitem__}, \method{__delitem__}, and \method{keys}. +For example: + +\begin{verbatim} +>>> import UserDict +>>> class SeqDict(UserDict.DictMixin): +... """Dictionary lookalike implemented with lists.""" +... def __init__(self): +... self.keylist = [] +... self.valuelist = [] +... def __getitem__(self, key): +... try: +... i = self.keylist.index(key) +... except ValueError: +... raise KeyError +... return self.valuelist[i] +... def __setitem__(self, key, value): +... try: +... i = self.keylist.index(key) +... self.valuelist[i] = value +... except ValueError: +... self.keylist.append(key) +... self.valuelist.append(value) +... def __delitem__(self, key): +... try: +... i = self.keylist.index(key) +... except ValueError: +... raise KeyError +... self.keylist.pop(i) +... self.valuelist.pop(i) +... def keys(self): +... return list(self.keylist) +... +>>> s = SeqDict() +>>> dir(s) # See that other dictionary methods are implemented +['__cmp__', '__contains__', '__delitem__', '__doc__', '__getitem__', + '__init__', '__iter__', '__len__', '__module__', '__repr__', + '__setitem__', 'clear', 'get', 'has_key', 'items', 'iteritems', + 'iterkeys', 'itervalues', 'keylist', 'keys', 'pop', 'popitem', + 'setdefault', 'update', 'valuelist', 'values'] +\end{verbatim} + +(Contributed by Raymond Hettinger.) + +\item The DOM implementation +in \module{xml.dom.minidom} can now generate XML output in a +particular encoding by providing an optional encoding argument to +the \method{toxml()} and \method{toprettyxml()} methods of DOM nodes. + +\item The \module{xmlrpclib} module now supports an XML-RPC extension +for handling nil data values such as Python's \code{None}. Nil values +are always supported on unmarshalling an XML-RPC response. To +generate requests containing \code{None}, you must supply a true value +for the \var{allow_none} parameter when creating a \class{Marshaller} +instance. + +\item The new \module{DocXMLRPCServer} module allows writing +self-documenting XML-RPC servers. Run it in demo mode (as a program) +to see it in action. Pointing the Web browser to the RPC server +produces pydoc-style documentation; pointing xmlrpclib to the +server allows invoking the actual methods. +(Contributed by Brian Quinlan.) + +\item Support for internationalized domain names (RFCs 3454, 3490, +3491, and 3492) has been added. The ``idna'' encoding can be used +to convert between a Unicode domain name and the ASCII-compatible +encoding (ACE) of that name. + +\begin{alltt} +>{}>{}> u"www.Alliancefran\c caise.nu".encode("idna") +'www.xn--alliancefranaise-npb.nu' +\end{alltt} + +The \module{socket} module has also been extended to transparently +convert Unicode hostnames to the ACE version before passing them to +the C library. Modules that deal with hostnames such as +\module{httplib} and \module{ftplib}) also support Unicode host names; +\module{httplib} also sends HTTP \samp{Host} headers using the ACE +version of the domain name. \module{urllib} supports Unicode URLs +with non-ASCII host names as long as the \code{path} part of the URL +is ASCII only. + +To implement this change, the \module{stringprep} module, the +\code{mkstringprep} tool and the \code{punycode} encoding have been added. + +\end{itemize} + + +%====================================================================== +\subsection{Date/Time Type} + +Date and time types suitable for expressing timestamps were added as +the \module{datetime} module. The types don't support different +calendars or many fancy features, and just stick to the basics of +representing time. + +The three primary types are: \class{date}, representing a day, month, +and year; \class{time}, consisting of hour, minute, and second; and +\class{datetime}, which contains all the attributes of both +\class{date} and \class{time}. There's also a +\class{timedelta} class representing differences between two points +in time, and time zone logic is implemented by classes inheriting from +the abstract \class{tzinfo} class. + +You can create instances of \class{date} and \class{time} by either +supplying keyword arguments to the appropriate constructor, +e.g. \code{datetime.date(year=1972, month=10, day=15)}, or by using +one of a number of class methods. For example, the \method{date.today()} +class method returns the current local date. + +Once created, instances of the date/time classes are all immutable. +There are a number of methods for producing formatted strings from +objects: + +\begin{verbatim} +>>> import datetime +>>> now = datetime.datetime.now() +>>> now.isoformat() +'2002-12-30T21:27:03.994956' +>>> now.ctime() # Only available on date, datetime +'Mon Dec 30 21:27:03 2002' +>>> now.strftime('%Y %d %b') +'2002 30 Dec' +\end{verbatim} + +The \method{replace()} method allows modifying one or more fields +of a \class{date} or \class{datetime} instance, returning a new instance: + +\begin{verbatim} +>>> d = datetime.datetime.now() +>>> d +datetime.datetime(2002, 12, 30, 22, 15, 38, 827738) +>>> d.replace(year=2001, hour = 12) +datetime.datetime(2001, 12, 30, 12, 15, 38, 827738) +>>> +\end{verbatim} + +Instances can be compared, hashed, and converted to strings (the +result is the same as that of \method{isoformat()}). \class{date} and +\class{datetime} instances can be subtracted from each other, and +added to \class{timedelta} instances. The largest missing feature is +that there's no standard library support for parsing strings and getting back a +\class{date} or \class{datetime}. + +For more information, refer to the \ulink{module's reference +documentation}{../lib/module-datetime.html}. +(Contributed by Tim Peters.) + + +%====================================================================== +\subsection{The optparse Module} + +The \module{getopt} module provides simple parsing of command-line +arguments. The new \module{optparse} module (originally named Optik) +provides more elaborate command-line parsing that follows the \UNIX{} +conventions, automatically creates the output for \longprogramopt{help}, +and can perform different actions for different options. + +You start by creating an instance of \class{OptionParser} and telling +it what your program's options are. + +\begin{verbatim} +import sys +from optparse import OptionParser + +op = OptionParser() +op.add_option('-i', '--input', + action='store', type='string', dest='input', + help='set input filename') +op.add_option('-l', '--length', + action='store', type='int', dest='length', + help='set maximum length of output') +\end{verbatim} + +Parsing a command line is then done by calling the \method{parse_args()} +method. + +\begin{verbatim} +options, args = op.parse_args(sys.argv[1:]) +print options +print args +\end{verbatim} + +This returns an object containing all of the option values, +and a list of strings containing the remaining arguments. + +Invoking the script with the various arguments now works as you'd +expect it to. Note that the length argument is automatically +converted to an integer. + +\begin{verbatim} +$ ./python opt.py -i data arg1 +<Values at 0x400cad4c: {'input': 'data', 'length': None}> +['arg1'] +$ ./python opt.py --input=data --length=4 +<Values at 0x400cad2c: {'input': 'data', 'length': 4}> +[] +$ +\end{verbatim} + +The help message is automatically generated for you: + +\begin{verbatim} +$ ./python opt.py --help +usage: opt.py [options] + +options: + -h, --help show this help message and exit + -iINPUT, --input=INPUT + set input filename + -lLENGTH, --length=LENGTH + set maximum length of output +$ +\end{verbatim} +% $ prevent Emacs tex-mode from getting confused + +See the \ulink{module's documentation}{../lib/module-optparse.html} +for more details. + +Optik was written by Greg Ward, with suggestions from the readers of +the Getopt SIG. + + +%====================================================================== +\section{Pymalloc: A Specialized Object Allocator\label{section-pymalloc}} + +Pymalloc, a specialized object allocator written by Vladimir +Marangozov, was a feature added to Python 2.1. Pymalloc is intended +to be faster than the system \cfunction{malloc()} and to have less +memory overhead for allocation patterns typical of Python programs. +The allocator uses C's \cfunction{malloc()} function to get large +pools of memory and then fulfills smaller memory requests from these +pools. + +In 2.1 and 2.2, pymalloc was an experimental feature and wasn't +enabled by default; you had to explicitly enable it when compiling +Python by providing the +\longprogramopt{with-pymalloc} option to the \program{configure} +script. In 2.3, pymalloc has had further enhancements and is now +enabled by default; you'll have to supply +\longprogramopt{without-pymalloc} to disable it. + +This change is transparent to code written in Python; however, +pymalloc may expose bugs in C extensions. Authors of C extension +modules should test their code with pymalloc enabled, +because some incorrect code may cause core dumps at runtime. + +There's one particularly common error that causes problems. There are +a number of memory allocation functions in Python's C API that have +previously just been aliases for the C library's \cfunction{malloc()} +and \cfunction{free()}, meaning that if you accidentally called +mismatched functions the error wouldn't be noticeable. When the +object allocator is enabled, these functions aren't aliases of +\cfunction{malloc()} and \cfunction{free()} any more, and calling the +wrong function to free memory may get you a core dump. For example, +if memory was allocated using \cfunction{PyObject_Malloc()}, it has to +be freed using \cfunction{PyObject_Free()}, not \cfunction{free()}. A +few modules included with Python fell afoul of this and had to be +fixed; doubtless there are more third-party modules that will have the +same problem. + +As part of this change, the confusing multiple interfaces for +allocating memory have been consolidated down into two API families. +Memory allocated with one family must not be manipulated with +functions from the other family. There is one family for allocating +chunks of memory and another family of functions specifically for +allocating Python objects. + +\begin{itemize} + \item To allocate and free an undistinguished chunk of memory use + the ``raw memory'' family: \cfunction{PyMem_Malloc()}, + \cfunction{PyMem_Realloc()}, and \cfunction{PyMem_Free()}. + + \item The ``object memory'' family is the interface to the pymalloc + facility described above and is biased towards a large number of + ``small'' allocations: \cfunction{PyObject_Malloc}, + \cfunction{PyObject_Realloc}, and \cfunction{PyObject_Free}. + + \item To allocate and free Python objects, use the ``object'' family + \cfunction{PyObject_New()}, \cfunction{PyObject_NewVar()}, and + \cfunction{PyObject_Del()}. +\end{itemize} + +Thanks to lots of work by Tim Peters, pymalloc in 2.3 also provides +debugging features to catch memory overwrites and doubled frees in +both extension modules and in the interpreter itself. To enable this +support, compile a debugging version of the Python interpreter by +running \program{configure} with \longprogramopt{with-pydebug}. + +To aid extension writers, a header file \file{Misc/pymemcompat.h} is +distributed with the source to Python 2.3 that allows Python +extensions to use the 2.3 interfaces to memory allocation while +compiling against any version of Python since 1.5.2. You would copy +the file from Python's source distribution and bundle it with the +source of your extension. + +\begin{seealso} + +\seeurl{http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/python/python/dist/src/Objects/obmalloc.c} +{For the full details of the pymalloc implementation, see +the comments at the top of the file \file{Objects/obmalloc.c} in the +Python source code. The above link points to the file within the +SourceForge CVS browser.} + +\end{seealso} + + +% ====================================================================== +\section{Build and C API Changes} + +Changes to Python's build process and to the C API include: + +\begin{itemize} + +\item The cycle detection implementation used by the garbage collection +has proven to be stable, so it's now been made mandatory. You can no +longer compile Python without it, and the +\longprogramopt{with-cycle-gc} switch to \program{configure} has been removed. + +\item Python can now optionally be built as a shared library +(\file{libpython2.3.so}) by supplying \longprogramopt{enable-shared} +when running Python's \program{configure} script. (Contributed by Ondrej +Palkovsky.) + +\item The \csimplemacro{DL_EXPORT} and \csimplemacro{DL_IMPORT} macros +are now deprecated. Initialization functions for Python extension +modules should now be declared using the new macro +\csimplemacro{PyMODINIT_FUNC}, while the Python core will generally +use the \csimplemacro{PyAPI_FUNC} and \csimplemacro{PyAPI_DATA} +macros. + +\item The interpreter can be compiled without any docstrings for +the built-in functions and modules by supplying +\longprogramopt{without-doc-strings} to the \program{configure} script. +This makes the Python executable about 10\% smaller, but will also +mean that you can't get help for Python's built-ins. (Contributed by +Gustavo Niemeyer.) + +\item The \cfunction{PyArg_NoArgs()} macro is now deprecated, and code +that uses it should be changed. For Python 2.2 and later, the method +definition table can specify the +\constant{METH_NOARGS} flag, signalling that there are no arguments, and +the argument checking can then be removed. If compatibility with +pre-2.2 versions of Python is important, the code could use +\code{PyArg_ParseTuple(\var{args}, "")} instead, but this will be slower +than using \constant{METH_NOARGS}. + +\item \cfunction{PyArg_ParseTuple()} accepts new format characters for various sizes of unsigned integers: \samp{B} for \ctype{unsigned char}, +\samp{H} for \ctype{unsigned short int}, +\samp{I} for \ctype{unsigned int}, +and \samp{K} for \ctype{unsigned long long}. + +\item A new function, \cfunction{PyObject_DelItemString(\var{mapping}, +char *\var{key})} was added as shorthand for +\code{PyObject_DelItem(\var{mapping}, PyString_New(\var{key}))}. + +\item File objects now manage their internal string buffer +differently, increasing it exponentially when needed. This results in +the benchmark tests in \file{Lib/test/test_bufio.py} speeding up +considerably (from 57 seconds to 1.7 seconds, according to one +measurement). + +\item It's now possible to define class and static methods for a C +extension type by setting either the \constant{METH_CLASS} or +\constant{METH_STATIC} flags in a method's \ctype{PyMethodDef} +structure. + +\item Python now includes a copy of the Expat XML parser's source code, +removing any dependence on a system version or local installation of +Expat. + +\item If you dynamically allocate type objects in your extension, you +should be aware of a change in the rules relating to the +\member{__module__} and \member{__name__} attributes. In summary, +you will want to ensure the type's dictionary contains a +\code{'__module__'} key; making the module name the part of the type +name leading up to the final period will no longer have the desired +effect. For more detail, read the API reference documentation or the +source. + +\end{itemize} + + +%====================================================================== +\subsection{Port-Specific Changes} + +Support for a port to IBM's OS/2 using the EMX runtime environment was +merged into the main Python source tree. EMX is a POSIX emulation +layer over the OS/2 system APIs. The Python port for EMX tries to +support all the POSIX-like capability exposed by the EMX runtime, and +mostly succeeds; \function{fork()} and \function{fcntl()} are +restricted by the limitations of the underlying emulation layer. The +standard OS/2 port, which uses IBM's Visual Age compiler, also gained +support for case-sensitive import semantics as part of the integration +of the EMX port into CVS. (Contributed by Andrew MacIntyre.) + +On MacOS, most toolbox modules have been weaklinked to improve +backward compatibility. This means that modules will no longer fail +to load if a single routine is missing on the current OS version. +Instead calling the missing routine will raise an exception. +(Contributed by Jack Jansen.) + +The RPM spec files, found in the \file{Misc/RPM/} directory in the +Python source distribution, were updated for 2.3. (Contributed by +Sean Reifschneider.) + +Other new platforms now supported by Python include AtheOS +(\url{http://www.atheos.cx/}), GNU/Hurd, and OpenVMS. + + +%====================================================================== +\section{Other Changes and Fixes \label{section-other}} + +As usual, there were a bunch of other improvements and bugfixes +scattered throughout the source tree. A search through the CVS change +logs finds there were 523 patches applied and 514 bugs fixed between +Python 2.2 and 2.3. Both figures are likely to be underestimates. + +Some of the more notable changes are: + +\begin{itemize} + +\item If the \envvar{PYTHONINSPECT} environment variable is set, the +Python interpreter will enter the interactive prompt after running a +Python program, as if Python had been invoked with the \programopt{-i} +option. The environment variable can be set before running the Python +interpreter, or it can be set by the Python program as part of its +execution. + +\item The \file{regrtest.py} script now provides a way to allow ``all +resources except \var{foo}.'' A resource name passed to the +\programopt{-u} option can now be prefixed with a hyphen +(\character{-}) to mean ``remove this resource.'' For example, the +option `\code{\programopt{-u}all,-bsddb}' could be used to enable the +use of all resources except \code{bsddb}. + +\item The tools used to build the documentation now work under Cygwin +as well as \UNIX. + +\item The \code{SET_LINENO} opcode has been removed. Back in the +mists of time, this opcode was needed to produce line numbers in +tracebacks and support trace functions (for, e.g., \module{pdb}). +Since Python 1.5, the line numbers in tracebacks have been computed +using a different mechanism that works with ``python -O''. For Python +2.3 Michael Hudson implemented a similar scheme to determine when to +call the trace function, removing the need for \code{SET_LINENO} +entirely. + +It would be difficult to detect any resulting difference from Python +code, apart from a slight speed up when Python is run without +\programopt{-O}. + +C extensions that access the \member{f_lineno} field of frame objects +should instead call \code{PyCode_Addr2Line(f->f_code, f->f_lasti)}. +This will have the added effect of making the code work as desired +under ``python -O'' in earlier versions of Python. + +A nifty new feature is that trace functions can now assign to the +\member{f_lineno} attribute of frame objects, changing the line that +will be executed next. A \samp{jump} command has been added to the +\module{pdb} debugger taking advantage of this new feature. +(Implemented by Richie Hindle.) + +\end{itemize} + + +%====================================================================== +\section{Porting to Python 2.3} + +This section lists previously described changes that may require +changes to your code: + +\begin{itemize} + +\item \keyword{yield} is now always a keyword; if it's used as a +variable name in your code, a different name must be chosen. + +\item For strings \var{X} and \var{Y}, \code{\var{X} in \var{Y}} now works +if \var{X} is more than one character long. + +\item The \function{int()} type constructor will now return a long +integer instead of raising an \exception{OverflowError} when a string +or floating-point number is too large to fit into an integer. + +\item If you have Unicode strings that contain 8-bit characters, you +must declare the file's encoding (UTF-8, Latin-1, or whatever) by +adding a comment to the top of the file. See +section~\ref{section-encodings} for more information. + +\item Calling Tcl methods through \module{_tkinter} no longer +returns only strings. Instead, if Tcl returns other objects those +objects are converted to their Python equivalent, if one exists, or +wrapped with a \class{_tkinter.Tcl_Obj} object if no Python equivalent +exists. + +\item Large octal and hex literals such as +\code{0xffffffff} now trigger a \exception{FutureWarning}. Currently +they're stored as 32-bit numbers and result in a negative value, but +in Python 2.4 they'll become positive long integers. + +% The empty groups below prevent conversion to guillemets. +There are a few ways to fix this warning. If you really need a +positive number, just add an \samp{L} to the end of the literal. If +you're trying to get a 32-bit integer with low bits set and have +previously used an expression such as \code{\textasciitilde(1 <{}< 31)}, +it's probably +clearest to start with all bits set and clear the desired upper bits. +For example, to clear just the top bit (bit 31), you could write +\code{0xffffffffL {\&}{\textasciitilde}(1L<{}<31)}. + +\item You can no longer disable assertions by assigning to \code{__debug__}. + +\item The Distutils \function{setup()} function has gained various new +keyword arguments such as \var{depends}. Old versions of the +Distutils will abort if passed unknown keywords. A solution is to check +for the presence of the new \function{get_distutil_options()} function +in your \file{setup.py} and only uses the new keywords +with a version of the Distutils that supports them: + +\begin{verbatim} +from distutils import core + +kw = {'sources': 'foo.c', ...} +if hasattr(core, 'get_distutil_options'): + kw['depends'] = ['foo.h'] +ext = Extension(**kw) +\end{verbatim} + +\item Using \code{None} as a variable name will now result in a +\exception{SyntaxWarning} warning. + +\item Names of extension types defined by the modules included with +Python now contain the module and a \character{.} in front of the type +name. + +\end{itemize} + + +%====================================================================== +\section{Acknowledgements \label{acks}} + +The author would like to thank the following people for offering +suggestions, corrections and assistance with various drafts of this +article: Jeff Bauer, Simon Brunning, Brett Cannon, Michael Chermside, +Andrew Dalke, Scott David Daniels, Fred~L. Drake, Jr., David Fraser, +Kelly Gerber, +Raymond Hettinger, Michael Hudson, Chris Lambert, Detlef Lannert, +Martin von~L\"owis, Andrew MacIntyre, Lalo Martins, Chad Netzer, +Gustavo Niemeyer, Neal Norwitz, Hans Nowak, Chris Reedy, Francesco +Ricciardi, Vinay Sajip, Neil Schemenauer, Roman Suzi, Jason Tishler, +Just van~Rossum. + +\end{document} diff --git a/sys/src/cmd/python/Doc/whatsnew/whatsnew24.tex b/sys/src/cmd/python/Doc/whatsnew/whatsnew24.tex new file mode 100644 index 000000000..6b146946a --- /dev/null +++ b/sys/src/cmd/python/Doc/whatsnew/whatsnew24.tex @@ -0,0 +1,1757 @@ +\documentclass{howto} +\usepackage{distutils} +% $Id: whatsnew24.tex 50936 2006-07-29 15:42:46Z andrew.kuchling $ + +% Don't write extensive text for new sections; I'll do that. +% Feel free to add commented-out reminders of things that need +% to be covered. --amk + +\title{What's New in Python 2.4} +\release{1.02} +\author{A.M.\ Kuchling} +\authoraddress{ + \strong{Python Software Foundation}\\ + Email: \email{amk@amk.ca} +} + +\begin{document} +\maketitle +\tableofcontents + +This article explains the new features in Python 2.4.1, released on +March~30, 2005. + +Python 2.4 is a medium-sized release. It doesn't introduce as many +changes as the radical Python 2.2, but introduces more features than +the conservative 2.3 release. The most significant new language +features are function decorators and generator expressions; most other +changes are to the standard library. + +According to the CVS change logs, there were 481 patches applied and +502 bugs fixed between Python 2.3 and 2.4. Both figures are likely to +be underestimates. + +This article doesn't attempt to provide a complete specification of +every single new feature, but instead provides a brief introduction to +each feature. For full details, you should refer to the documentation +for Python 2.4, such as the \citetitle[../lib/lib.html]{Python Library +Reference} and the \citetitle[../ref/ref.html]{Python Reference +Manual}. Often you will be referred to the PEP for a particular new +feature for explanations of the implementation and design rationale. + + +%====================================================================== +\section{PEP 218: Built-In Set Objects} + +Python 2.3 introduced the \module{sets} module. C implementations of +set data types have now been added to the Python core as two new +built-in types, \function{set(\var{iterable})} and +\function{frozenset(\var{iterable})}. They provide high speed +operations for membership testing, for eliminating duplicates from +sequences, and for mathematical operations like unions, intersections, +differences, and symmetric differences. + +\begin{verbatim} +>>> a = set('abracadabra') # form a set from a string +>>> 'z' in a # fast membership testing +False +>>> a # unique letters in a +set(['a', 'r', 'b', 'c', 'd']) +>>> ''.join(a) # convert back into a string +'arbcd' + +>>> b = set('alacazam') # form a second set +>>> a - b # letters in a but not in b +set(['r', 'd', 'b']) +>>> a | b # letters in either a or b +set(['a', 'c', 'r', 'd', 'b', 'm', 'z', 'l']) +>>> a & b # letters in both a and b +set(['a', 'c']) +>>> a ^ b # letters in a or b but not both +set(['r', 'd', 'b', 'm', 'z', 'l']) + +>>> a.add('z') # add a new element +>>> a.update('wxy') # add multiple new elements +>>> a +set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'x', 'z']) +>>> a.remove('x') # take one element out +>>> a +set(['a', 'c', 'b', 'd', 'r', 'w', 'y', 'z']) +\end{verbatim} + +The \function{frozenset} type is an immutable version of \function{set}. +Since it is immutable and hashable, it may be used as a dictionary key or +as a member of another set. + +The \module{sets} module remains in the standard library, and may be +useful if you wish to subclass the \class{Set} or \class{ImmutableSet} +classes. There are currently no plans to deprecate the module. + +\begin{seealso} +\seepep{218}{Adding a Built-In Set Object Type}{Originally proposed by +Greg Wilson and ultimately implemented by Raymond Hettinger.} +\end{seealso} + + +%====================================================================== +\section{PEP 237: Unifying Long Integers and Integers} + +The lengthy transition process for this PEP, begun in Python 2.2, +takes another step forward in Python 2.4. In 2.3, certain integer +operations that would behave differently after int/long unification +triggered \exception{FutureWarning} warnings and returned values +limited to 32 or 64 bits (depending on your platform). In 2.4, these +expressions no longer produce a warning and instead produce a +different result that's usually a long integer. + +The problematic expressions are primarily left shifts and lengthy +hexadecimal and octal constants. For example, +\code{2 \textless{}\textless{} 32} results +in a warning in 2.3, evaluating to 0 on 32-bit platforms. In Python +2.4, this expression now returns the correct answer, 8589934592. + +\begin{seealso} +\seepep{237}{Unifying Long Integers and Integers}{Original PEP +written by Moshe Zadka and GvR. The changes for 2.4 were implemented by +Kalle Svensson.} +\end{seealso} + + +%====================================================================== +\section{PEP 289: Generator Expressions} + +The iterator feature introduced in Python 2.2 and the +\module{itertools} module make it easier to write programs that loop +through large data sets without having the entire data set in memory +at one time. List comprehensions don't fit into this picture very +well because they produce a Python list object containing all of the +items. This unavoidably pulls all of the objects into memory, which +can be a problem if your data set is very large. When trying to write +a functionally-styled program, it would be natural to write something +like: + +\begin{verbatim} +links = [link for link in get_all_links() if not link.followed] +for link in links: + ... +\end{verbatim} + +instead of + +\begin{verbatim} +for link in get_all_links(): + if link.followed: + continue + ... +\end{verbatim} + +The first form is more concise and perhaps more readable, but if +you're dealing with a large number of link objects you'd have to write +the second form to avoid having all link objects in memory at the same +time. + +Generator expressions work similarly to list comprehensions but don't +materialize the entire list; instead they create a generator that will +return elements one by one. The above example could be written as: + +\begin{verbatim} +links = (link for link in get_all_links() if not link.followed) +for link in links: + ... +\end{verbatim} + +Generator expressions always have to be written inside parentheses, as +in the above example. The parentheses signalling a function call also +count, so if you want to create an iterator that will be immediately +passed to a function you could write: + +\begin{verbatim} +print sum(obj.count for obj in list_all_objects()) +\end{verbatim} + +Generator expressions differ from list comprehensions in various small +ways. Most notably, the loop variable (\var{obj} in the above +example) is not accessible outside of the generator expression. List +comprehensions leave the variable assigned to its last value; future +versions of Python will change this, making list comprehensions match +generator expressions in this respect. + +\begin{seealso} +\seepep{289}{Generator Expressions}{Proposed by Raymond Hettinger and +implemented by Jiwon Seo with early efforts steered by Hye-Shik Chang.} +\end{seealso} + + +%====================================================================== +\section{PEP 292: Simpler String Substitutions} + +Some new classes in the standard library provide an alternative +mechanism for substituting variables into strings; this style of +substitution may be better for applications where untrained +users need to edit templates. + +The usual way of substituting variables by name is the \code{\%} +operator: + +\begin{verbatim} +>>> '%(page)i: %(title)s' % {'page':2, 'title': 'The Best of Times'} +'2: The Best of Times' +\end{verbatim} + +When writing the template string, it can be easy to forget the +\samp{i} or \samp{s} after the closing parenthesis. This isn't a big +problem if the template is in a Python module, because you run the +code, get an ``Unsupported format character'' \exception{ValueError}, +and fix the problem. However, consider an application such as Mailman +where template strings or translations are being edited by users who +aren't aware of the Python language. The format string's syntax is +complicated to explain to such users, and if they make a mistake, it's +difficult to provide helpful feedback to them. + +PEP 292 adds a \class{Template} class to the \module{string} module +that uses \samp{\$} to indicate a substitution: + +\begin{verbatim} +>>> import string +>>> t = string.Template('$page: $title') +>>> t.substitute({'page':2, 'title': 'The Best of Times'}) +'2: The Best of Times' +\end{verbatim} + +% $ Terminate $-mode for Emacs + +If a key is missing from the dictionary, the \method{substitute} method +will raise a \exception{KeyError}. There's also a \method{safe_substitute} +method that ignores missing keys: + +\begin{verbatim} +>>> t = string.Template('$page: $title') +>>> t.safe_substitute({'page':3}) +'3: $title' +\end{verbatim} + +% $ Terminate math-mode for Emacs + + +\begin{seealso} +\seepep{292}{Simpler String Substitutions}{Written and implemented +by Barry Warsaw.} +\end{seealso} + + +%====================================================================== +\section{PEP 318: Decorators for Functions and Methods} + +Python 2.2 extended Python's object model by adding static methods and +class methods, but it didn't extend Python's syntax to provide any new +way of defining static or class methods. Instead, you had to write a +\keyword{def} statement in the usual way, and pass the resulting +method to a \function{staticmethod()} or \function{classmethod()} +function that would wrap up the function as a method of the new type. +Your code would look like this: + +\begin{verbatim} +class C: + def meth (cls): + ... + + meth = classmethod(meth) # Rebind name to wrapped-up class method +\end{verbatim} + +If the method was very long, it would be easy to miss or forget the +\function{classmethod()} invocation after the function body. + +The intention was always to add some syntax to make such definitions +more readable, but at the time of 2.2's release a good syntax was not +obvious. Today a good syntax \emph{still} isn't obvious but users are +asking for easier access to the feature; a new syntactic feature has +been added to meet this need. + +The new feature is called ``function decorators''. The name comes +from the idea that \function{classmethod}, \function{staticmethod}, +and friends are storing additional information on a function object; +they're \emph{decorating} functions with more details. + +The notation borrows from Java and uses the \character{@} character as an +indicator. Using the new syntax, the example above would be written: + +\begin{verbatim} +class C: + + @classmethod + def meth (cls): + ... + +\end{verbatim} + +The \code{@classmethod} is shorthand for the +\code{meth=classmethod(meth)} assignment. More generally, if you have +the following: + +\begin{verbatim} +@A +@B +@C +def f (): + ... +\end{verbatim} + +It's equivalent to the following pre-decorator code: + +\begin{verbatim} +def f(): ... +f = A(B(C(f))) +\end{verbatim} + +Decorators must come on the line before a function definition, one decorator +per line, and can't be on the same line as the def statement, meaning that +\code{@A def f(): ...} is illegal. You can only decorate function +definitions, either at the module level or inside a class; you can't +decorate class definitions. + +A decorator is just a function that takes the function to be decorated as an +argument and returns either the same function or some new object. The +return value of the decorator need not be callable (though it typically is), +unless further decorators will be applied to the result. It's easy to write +your own decorators. The following simple example just sets an attribute on +the function object: + +\begin{verbatim} +>>> def deco(func): +... func.attr = 'decorated' +... return func +... +>>> @deco +... def f(): pass +... +>>> f +<function f at 0x402ef0d4> +>>> f.attr +'decorated' +>>> +\end{verbatim} + +As a slightly more realistic example, the following decorator checks +that the supplied argument is an integer: + +\begin{verbatim} +def require_int (func): + def wrapper (arg): + assert isinstance(arg, int) + return func(arg) + + return wrapper + +@require_int +def p1 (arg): + print arg + +@require_int +def p2(arg): + print arg*2 +\end{verbatim} + +An example in \pep{318} contains a fancier version of this idea that +lets you both specify the required type and check the returned type. + +Decorator functions can take arguments. If arguments are supplied, +your decorator function is called with only those arguments and must +return a new decorator function; this function must take a single +function and return a function, as previously described. In other +words, \code{@A @B @C(args)} becomes: + +\begin{verbatim} +def f(): ... +_deco = C(args) +f = A(B(_deco(f))) +\end{verbatim} + +Getting this right can be slightly brain-bending, but it's not too +difficult. + +A small related change makes the \member{func_name} attribute of +functions writable. This attribute is used to display function names +in tracebacks, so decorators should change the name of any new +function that's constructed and returned. + +\begin{seealso} +\seepep{318}{Decorators for Functions, Methods and Classes}{Written +by Kevin D. Smith, Jim Jewett, and Skip Montanaro. Several people +wrote patches implementing function decorators, but the one that was +actually checked in was patch \#979728, written by Mark Russell.} + +\seeurl{http://www.python.org/moin/PythonDecoratorLibrary} +{This Wiki page contains several examples of decorators.} + +\end{seealso} + + +%====================================================================== +\section{PEP 322: Reverse Iteration} + +A new built-in function, \function{reversed(\var{seq})}, takes a sequence +and returns an iterator that loops over the elements of the sequence +in reverse order. + +\begin{verbatim} +>>> for i in reversed(xrange(1,4)): +... print i +... +3 +2 +1 +\end{verbatim} + +Compared to extended slicing, such as \code{range(1,4)[::-1]}, +\function{reversed()} is easier to read, runs faster, and uses +substantially less memory. + +Note that \function{reversed()} only accepts sequences, not arbitrary +iterators. If you want to reverse an iterator, first convert it to +a list with \function{list()}. + +\begin{verbatim} +>>> input = open('/etc/passwd', 'r') +>>> for line in reversed(list(input)): +... print line +... +root:*:0:0:System Administrator:/var/root:/bin/tcsh + ... +\end{verbatim} + +\begin{seealso} +\seepep{322}{Reverse Iteration}{Written and implemented by Raymond Hettinger.} + +\end{seealso} + + +%====================================================================== +\section{PEP 324: New subprocess Module} + +The standard library provides a number of ways to execute a +subprocess, offering different features and different levels of +complexity. \function{os.system(\var{command})} is easy to use, but +slow (it runs a shell process which executes the command) and +dangerous (you have to be careful about escaping the shell's +metacharacters). The \module{popen2} module offers classes that can +capture standard output and standard error from the subprocess, but +the naming is confusing. The \module{subprocess} module cleans +this up, providing a unified interface that offers all the features +you might need. + +Instead of \module{popen2}'s collection of classes, +\module{subprocess} contains a single class called \class{Popen} +whose constructor supports a number of different keyword arguments. + +\begin{verbatim} +class Popen(args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0): +\end{verbatim} + +\var{args} is commonly a sequence of strings that will be the +arguments to the program executed as the subprocess. (If the +\var{shell} argument is true, \var{args} can be a string which will +then be passed on to the shell for interpretation, just as +\function{os.system()} does.) + +\var{stdin}, \var{stdout}, and \var{stderr} specify what the +subprocess's input, output, and error streams will be. You can +provide a file object or a file descriptor, or you can use the +constant \code{subprocess.PIPE} to create a pipe between the +subprocess and the parent. + +The constructor has a number of handy options: + +\begin{itemize} + \item \var{close_fds} requests that all file descriptors be closed + before running the subprocess. + + \item \var{cwd} specifies the working directory in which the + subprocess will be executed (defaulting to whatever the parent's + working directory is). + + \item \var{env} is a dictionary specifying environment variables. + + \item \var{preexec_fn} is a function that gets called before the + child is started. + + \item \var{universal_newlines} opens the child's input and output + using Python's universal newline feature. + +\end{itemize} + +Once you've created the \class{Popen} instance, +you can call its \method{wait()} method to pause until the subprocess +has exited, \method{poll()} to check if it's exited without pausing, +or \method{communicate(\var{data})} to send the string \var{data} to +the subprocess's standard input. \method{communicate(\var{data})} +then reads any data that the subprocess has sent to its standard output +or standard error, returning a tuple \code{(\var{stdout_data}, +\var{stderr_data})}. + +\function{call()} is a shortcut that passes its arguments along to the +\class{Popen} constructor, waits for the command to complete, and +returns the status code of the subprocess. It can serve as a safer +analog to \function{os.system()}: + +\begin{verbatim} +sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb']) +if sts == 0: + # Success + ... +else: + # dpkg returned an error + ... +\end{verbatim} + +The command is invoked without use of the shell. If you really do want to +use the shell, you can add \code{shell=True} as a keyword argument and provide +a string instead of a sequence: + +\begin{verbatim} +sts = subprocess.call('dpkg -i /tmp/new-package.deb', shell=True) +\end{verbatim} + +The PEP takes various examples of shell and Python code and shows how +they'd be translated into Python code that uses \module{subprocess}. +Reading this section of the PEP is highly recommended. + +\begin{seealso} +\seepep{324}{subprocess - New process module}{Written and implemented by Peter {\AA}strand, with assistance from Fredrik Lundh and others.} +\end{seealso} + + +%====================================================================== +\section{PEP 327: Decimal Data Type} + +Python has always supported floating-point (FP) numbers, based on the +underlying C \ctype{double} type, as a data type. However, while most +programming languages provide a floating-point type, many people (even +programmers) are unaware that floating-point numbers don't represent +certain decimal fractions accurately. The new \class{Decimal} type +can represent these fractions accurately, up to a user-specified +precision limit. + + +\subsection{Why is Decimal needed?} + +The limitations arise from the representation used for floating-point numbers. +FP numbers are made up of three components: + +\begin{itemize} +\item The sign, which is positive or negative. +\item The mantissa, which is a single-digit binary number +followed by a fractional part. For example, \code{1.01} in base-2 notation +is \code{1 + 0/2 + 1/4}, or 1.25 in decimal notation. +\item The exponent, which tells where the decimal point is located in the number represented. +\end{itemize} + +For example, the number 1.25 has positive sign, a mantissa value of +1.01 (in binary), and an exponent of 0 (the decimal point doesn't need +to be shifted). The number 5 has the same sign and mantissa, but the +exponent is 2 because the mantissa is multiplied by 4 (2 to the power +of the exponent 2); 1.25 * 4 equals 5. + +Modern systems usually provide floating-point support that conforms to +a standard called IEEE 754. C's \ctype{double} type is usually +implemented as a 64-bit IEEE 754 number, which uses 52 bits of space +for the mantissa. This means that numbers can only be specified to 52 +bits of precision. If you're trying to represent numbers whose +expansion repeats endlessly, the expansion is cut off after 52 bits. +Unfortunately, most software needs to produce output in base 10, and +common fractions in base 10 are often repeating decimals in binary. +For example, 1.1 decimal is binary \code{1.0001100110011 ...}; .1 = +1/16 + 1/32 + 1/256 plus an infinite number of additional terms. IEEE +754 has to chop off that infinitely repeated decimal after 52 digits, +so the representation is slightly inaccurate. + +Sometimes you can see this inaccuracy when the number is printed: +\begin{verbatim} +>>> 1.1 +1.1000000000000001 +\end{verbatim} + +The inaccuracy isn't always visible when you print the number because +the FP-to-decimal-string conversion is provided by the C library, and +most C libraries try to produce sensible output. Even if it's not +displayed, however, the inaccuracy is still there and subsequent +operations can magnify the error. + +For many applications this doesn't matter. If I'm plotting points and +displaying them on my monitor, the difference between 1.1 and +1.1000000000000001 is too small to be visible. Reports often limit +output to a certain number of decimal places, and if you round the +number to two or three or even eight decimal places, the error is +never apparent. However, for applications where it does matter, +it's a lot of work to implement your own custom arithmetic routines. + +Hence, the \class{Decimal} type was created. + +\subsection{The \class{Decimal} type} + +A new module, \module{decimal}, was added to Python's standard +library. It contains two classes, \class{Decimal} and +\class{Context}. \class{Decimal} instances represent numbers, and +\class{Context} instances are used to wrap up various settings such as +the precision and default rounding mode. + +\class{Decimal} instances are immutable, like regular Python integers +and FP numbers; once it's been created, you can't change the value an +instance represents. \class{Decimal} instances can be created from +integers or strings: + +\begin{verbatim} +>>> import decimal +>>> decimal.Decimal(1972) +Decimal("1972") +>>> decimal.Decimal("1.1") +Decimal("1.1") +\end{verbatim} + +You can also provide tuples containing the sign, the mantissa represented +as a tuple of decimal digits, and the exponent: + +\begin{verbatim} +>>> decimal.Decimal((1, (1, 4, 7, 5), -2)) +Decimal("-14.75") +\end{verbatim} + +Cautionary note: the sign bit is a Boolean value, so 0 is positive and +1 is negative. + +Converting from floating-point numbers poses a bit of a problem: +should the FP number representing 1.1 turn into the decimal number for +exactly 1.1, or for 1.1 plus whatever inaccuracies are introduced? +The decision was to dodge the issue and leave such a conversion out of +the API. Instead, you should convert the floating-point number into a +string using the desired precision and pass the string to the +\class{Decimal} constructor: + +\begin{verbatim} +>>> f = 1.1 +>>> decimal.Decimal(str(f)) +Decimal("1.1") +>>> decimal.Decimal('%.12f' % f) +Decimal("1.100000000000") +\end{verbatim} + +Once you have \class{Decimal} instances, you can perform the usual +mathematical operations on them. One limitation: exponentiation +requires an integer exponent: + +\begin{verbatim} +>>> a = decimal.Decimal('35.72') +>>> b = decimal.Decimal('1.73') +>>> a+b +Decimal("37.45") +>>> a-b +Decimal("33.99") +>>> a*b +Decimal("61.7956") +>>> a/b +Decimal("20.64739884393063583815028902") +>>> a ** 2 +Decimal("1275.9184") +>>> a**b +Traceback (most recent call last): + ... +decimal.InvalidOperation: x ** (non-integer) +\end{verbatim} + +You can combine \class{Decimal} instances with integers, but not with +floating-point numbers: + +\begin{verbatim} +>>> a + 4 +Decimal("39.72") +>>> a + 4.5 +Traceback (most recent call last): + ... +TypeError: You can interact Decimal only with int, long or Decimal data types. +>>> +\end{verbatim} + +\class{Decimal} numbers can be used with the \module{math} and +\module{cmath} modules, but note that they'll be immediately converted to +floating-point numbers before the operation is performed, resulting in +a possible loss of precision and accuracy. You'll also get back a +regular floating-point number and not a \class{Decimal}. + +\begin{verbatim} +>>> import math, cmath +>>> d = decimal.Decimal('123456789012.345') +>>> math.sqrt(d) +351364.18288201344 +>>> cmath.sqrt(-d) +351364.18288201344j +\end{verbatim} + +\class{Decimal} instances have a \method{sqrt()} method that +returns a \class{Decimal}, but if you need other things such as +trigonometric functions you'll have to implement them. + +\begin{verbatim} +>>> d.sqrt() +Decimal("351364.1828820134592177245001") +\end{verbatim} + + +\subsection{The \class{Context} type} + +Instances of the \class{Context} class encapsulate several settings for +decimal operations: + +\begin{itemize} + \item \member{prec} is the precision, the number of decimal places. + \item \member{rounding} specifies the rounding mode. The \module{decimal} + module has constants for the various possibilities: + \constant{ROUND_DOWN}, \constant{ROUND_CEILING}, + \constant{ROUND_HALF_EVEN}, and various others. + \item \member{traps} is a dictionary specifying what happens on +encountering certain error conditions: either an exception is raised or +a value is returned. Some examples of error conditions are +division by zero, loss of precision, and overflow. +\end{itemize} + +There's a thread-local default context available by calling +\function{getcontext()}; you can change the properties of this context +to alter the default precision, rounding, or trap handling. The +following example shows the effect of changing the precision of the default +context: + +\begin{verbatim} +>>> decimal.getcontext().prec +28 +>>> decimal.Decimal(1) / decimal.Decimal(7) +Decimal("0.1428571428571428571428571429") +>>> decimal.getcontext().prec = 9 +>>> decimal.Decimal(1) / decimal.Decimal(7) +Decimal("0.142857143") +\end{verbatim} + +The default action for error conditions is selectable; the module can +either return a special value such as infinity or not-a-number, or +exceptions can be raised: + +\begin{verbatim} +>>> decimal.Decimal(1) / decimal.Decimal(0) +Traceback (most recent call last): + ... +decimal.DivisionByZero: x / 0 +>>> decimal.getcontext().traps[decimal.DivisionByZero] = False +>>> decimal.Decimal(1) / decimal.Decimal(0) +Decimal("Infinity") +>>> +\end{verbatim} + +The \class{Context} instance also has various methods for formatting +numbers such as \method{to_eng_string()} and \method{to_sci_string()}. + +For more information, see the documentation for the \module{decimal} +module, which includes a quick-start tutorial and a reference. + +\begin{seealso} +\seepep{327}{Decimal Data Type}{Written by Facundo Batista and implemented + by Facundo Batista, Eric Price, Raymond Hettinger, Aahz, and Tim Peters.} + +\seeurl{http://research.microsoft.com/\textasciitilde hollasch/cgindex/coding/ieeefloat.html} +{A more detailed overview of the IEEE-754 representation.} + +\seeurl{http://www.lahey.com/float.htm} +{The article uses Fortran code to illustrate many of the problems +that floating-point inaccuracy can cause.} + +\seeurl{http://www2.hursley.ibm.com/decimal/} +{A description of a decimal-based representation. This representation +is being proposed as a standard, and underlies the new Python decimal +type. Much of this material was written by Mike Cowlishaw, designer of the +Rexx language.} + +\end{seealso} + + +%====================================================================== +\section{PEP 328: Multi-line Imports} + +One language change is a small syntactic tweak aimed at making it +easier to import many names from a module. In a +\code{from \var{module} import \var{names}} statement, +\var{names} is a sequence of names separated by commas. If the sequence is +very long, you can either write multiple imports from the same module, +or you can use backslashes to escape the line endings like this: + +\begin{verbatim} +from SimpleXMLRPCServer import SimpleXMLRPCServer,\ + SimpleXMLRPCRequestHandler,\ + CGIXMLRPCRequestHandler,\ + resolve_dotted_attribute +\end{verbatim} + +The syntactic change in Python 2.4 simply allows putting the names +within parentheses. Python ignores newlines within a parenthesized +expression, so the backslashes are no longer needed: + +\begin{verbatim} +from SimpleXMLRPCServer import (SimpleXMLRPCServer, + SimpleXMLRPCRequestHandler, + CGIXMLRPCRequestHandler, + resolve_dotted_attribute) +\end{verbatim} + +The PEP also proposes that all \keyword{import} statements be absolute +imports, with a leading \samp{.} character to indicate a relative +import. This part of the PEP was not implemented for Python 2.4, +but was completed for Python 2.5. + +\begin{seealso} +\seepep{328}{Imports: Multi-Line and Absolute/Relative} + {Written by Aahz. Multi-line imports were implemented by + Dima Dorfman.} +\end{seealso} + + +%====================================================================== +\section{PEP 331: Locale-Independent Float/String Conversions} + +The \module{locale} modules lets Python software select various +conversions and display conventions that are localized to a particular +country or language. However, the module was careful to not change +the numeric locale because various functions in Python's +implementation required that the numeric locale remain set to the +\code{'C'} locale. Often this was because the code was using the C library's +\cfunction{atof()} function. + +Not setting the numeric locale caused trouble for extensions that used +third-party C libraries, however, because they wouldn't have the +correct locale set. The motivating example was GTK+, whose user +interface widgets weren't displaying numbers in the current locale. + +The solution described in the PEP is to add three new functions to the +Python API that perform ASCII-only conversions, ignoring the locale +setting: + +\begin{itemize} + \item \cfunction{PyOS_ascii_strtod(\var{str}, \var{ptr})} +and \cfunction{PyOS_ascii_atof(\var{str}, \var{ptr})} +both convert a string to a C \ctype{double}. + \item \cfunction{PyOS_ascii_formatd(\var{buffer}, \var{buf_len}, \var{format}, \var{d})} converts a \ctype{double} to an ASCII string. +\end{itemize} + +The code for these functions came from the GLib library +(\url{http://developer.gnome.org/arch/gtk/glib.html}), whose +developers kindly relicensed the relevant functions and donated them +to the Python Software Foundation. The \module{locale} module +can now change the numeric locale, letting extensions such as GTK+ +produce the correct results. + +\begin{seealso} +\seepep{331}{Locale-Independent Float/String Conversions} +{Written by Christian R. Reis, and implemented by Gustavo Carneiro.} +\end{seealso} + +%====================================================================== +\section{Other Language Changes} + +Here are all of the changes that Python 2.4 makes to the core Python +language. + +\begin{itemize} + +\item Decorators for functions and methods were added (\pep{318}). + +\item Built-in \function{set} and \function{frozenset} types were +added (\pep{218}). Other new built-ins include the \function{reversed(\var{seq})} function (\pep{322}). + +\item Generator expressions were added (\pep{289}). + +\item Certain numeric expressions no longer return values restricted to 32 or 64 bits (\pep{237}). + +\item You can now put parentheses around the list of names in a +\code{from \var{module} import \var{names}} statement (\pep{328}). + +\item The \method{dict.update()} method now accepts the same +argument forms as the \class{dict} constructor. This includes any +mapping, any iterable of key/value pairs, and keyword arguments. +(Contributed by Raymond Hettinger.) + +\item The string methods \method{ljust()}, \method{rjust()}, and +\method{center()} now take an optional argument for specifying a +fill character other than a space. +(Contributed by Raymond Hettinger.) + +\item Strings also gained an \method{rsplit()} method that +works like the \method{split()} method but splits from the end of +the string. +(Contributed by Sean Reifschneider.) + +\begin{verbatim} +>>> 'www.python.org'.split('.', 1) +['www', 'python.org'] +'www.python.org'.rsplit('.', 1) +['www.python', 'org'] +\end{verbatim} + +\item Three keyword parameters, \var{cmp}, \var{key}, and +\var{reverse}, were added to the \method{sort()} method of lists. +These parameters make some common usages of \method{sort()} simpler. +All of these parameters are optional. + +For the \var{cmp} parameter, the value should be a comparison function +that takes two parameters and returns -1, 0, or +1 depending on how +the parameters compare. This function will then be used to sort the +list. Previously this was the only parameter that could be provided +to \method{sort()}. + +\var{key} should be a single-parameter function that takes a list +element and returns a comparison key for the element. The list is +then sorted using the comparison keys. The following example sorts a +list case-insensitively: + +\begin{verbatim} +>>> L = ['A', 'b', 'c', 'D'] +>>> L.sort() # Case-sensitive sort +>>> L +['A', 'D', 'b', 'c'] +>>> # Using 'key' parameter to sort list +>>> L.sort(key=lambda x: x.lower()) +>>> L +['A', 'b', 'c', 'D'] +>>> # Old-fashioned way +>>> L.sort(cmp=lambda x,y: cmp(x.lower(), y.lower())) +>>> L +['A', 'b', 'c', 'D'] +\end{verbatim} + +The last example, which uses the \var{cmp} parameter, is the old way +to perform a case-insensitive sort. It works but is slower than using +a \var{key} parameter. Using \var{key} calls \method{lower()} method +once for each element in the list while using \var{cmp} will call it +twice for each comparison, so using \var{key} saves on invocations of +the \method{lower()} method. + +For simple key functions and comparison functions, it is often +possible to avoid a \keyword{lambda} expression by using an unbound +method instead. For example, the above case-insensitive sort is best +written as: + +\begin{verbatim} +>>> L.sort(key=str.lower) +>>> L +['A', 'b', 'c', 'D'] +\end{verbatim} + +Finally, the \var{reverse} parameter takes a Boolean value. If the +value is true, the list will be sorted into reverse order. +Instead of \code{L.sort() ; L.reverse()}, you can now write +\code{L.sort(reverse=True)}. + +The results of sorting are now guaranteed to be stable. This means +that two entries with equal keys will be returned in the same order as +they were input. For example, you can sort a list of people by name, +and then sort the list by age, resulting in a list sorted by age where +people with the same age are in name-sorted order. + +(All changes to \method{sort()} contributed by Raymond Hettinger.) + +\item There is a new built-in function +\function{sorted(\var{iterable})} that works like the in-place +\method{list.sort()} method but can be used in +expressions. The differences are: + \begin{itemize} + \item the input may be any iterable; + \item a newly formed copy is sorted, leaving the original intact; and + \item the expression returns the new sorted copy + \end{itemize} + +\begin{verbatim} +>>> L = [9,7,8,3,2,4,1,6,5] +>>> [10+i for i in sorted(L)] # usable in a list comprehension +[11, 12, 13, 14, 15, 16, 17, 18, 19] +>>> L # original is left unchanged +[9,7,8,3,2,4,1,6,5] +>>> sorted('Monty Python') # any iterable may be an input +[' ', 'M', 'P', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y', 'y'] + +>>> # List the contents of a dict sorted by key values +>>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5) +>>> for k, v in sorted(colormap.iteritems()): +... print k, v +... +black 4 +blue 2 +green 3 +red 1 +yellow 5 +\end{verbatim} + +(Contributed by Raymond Hettinger.) + +\item Integer operations will no longer trigger an \exception{OverflowWarning}. +The \exception{OverflowWarning} warning will disappear in Python 2.5. + +\item The interpreter gained a new switch, \programopt{-m}, that +takes a name, searches for the corresponding module on \code{sys.path}, +and runs the module as a script. For example, +you can now run the Python profiler with \code{python -m profile}. +(Contributed by Nick Coghlan.) + +\item The \function{eval(\var{expr}, \var{globals}, \var{locals})} +and \function{execfile(\var{filename}, \var{globals}, \var{locals})} +functions and the \keyword{exec} statement now accept any mapping type +for the \var{locals} parameter. Previously this had to be a regular +Python dictionary. (Contributed by Raymond Hettinger.) + +\item The \function{zip()} built-in function and \function{itertools.izip()} + now return an empty list if called with no arguments. + Previously they raised a \exception{TypeError} + exception. This makes them more + suitable for use with variable length argument lists: + +\begin{verbatim} +>>> def transpose(array): +... return zip(*array) +... +>>> transpose([(1,2,3), (4,5,6)]) +[(1, 4), (2, 5), (3, 6)] +>>> transpose([]) +[] +\end{verbatim} +(Contributed by Raymond Hettinger.) + +\item Encountering a failure while importing a module no longer leaves +a partially-initialized module object in \code{sys.modules}. The +incomplete module object left behind would fool further imports of the +same module into succeeding, leading to confusing errors. +(Fixed by Tim Peters.) + +\item \constant{None} is now a constant; code that binds a new value to +the name \samp{None} is now a syntax error. +(Contributed by Raymond Hettinger.) + +\end{itemize} + + +%====================================================================== +\subsection{Optimizations} + +\begin{itemize} + +\item The inner loops for list and tuple slicing + were optimized and now run about one-third faster. The inner loops + for dictionaries were also optimized, resulting in performance boosts for + \method{keys()}, \method{values()}, \method{items()}, + \method{iterkeys()}, \method{itervalues()}, and \method{iteritems()}. + (Contributed by Raymond Hettinger.) + +\item The machinery for growing and shrinking lists was optimized for + speed and for space efficiency. Appending and popping from lists now + runs faster due to more efficient code paths and less frequent use of + the underlying system \cfunction{realloc()}. List comprehensions + also benefit. \method{list.extend()} was also optimized and no + longer converts its argument into a temporary list before extending + the base list. (Contributed by Raymond Hettinger.) + +\item \function{list()}, \function{tuple()}, \function{map()}, + \function{filter()}, and \function{zip()} now run several times + faster with non-sequence arguments that supply a \method{__len__()} + method. (Contributed by Raymond Hettinger.) + +\item The methods \method{list.__getitem__()}, + \method{dict.__getitem__()}, and \method{dict.__contains__()} are + are now implemented as \class{method_descriptor} objects rather + than \class{wrapper_descriptor} objects. This form of + access doubles their performance and makes them more suitable for + use as arguments to functionals: + \samp{map(mydict.__getitem__, keylist)}. + (Contributed by Raymond Hettinger.) + +\item Added a new opcode, \code{LIST_APPEND}, that simplifies + the generated bytecode for list comprehensions and speeds them up + by about a third. (Contributed by Raymond Hettinger.) + +\item The peephole bytecode optimizer has been improved to +produce shorter, faster bytecode; remarkably, the resulting bytecode is +more readable. (Enhanced by Raymond Hettinger.) + +\item String concatenations in statements of the form \code{s = s + +"abc"} and \code{s += "abc"} are now performed more efficiently in +certain circumstances. This optimization won't be present in other +Python implementations such as Jython, so you shouldn't rely on it; +using the \method{join()} method of strings is still recommended when +you want to efficiently glue a large number of strings together. +(Contributed by Armin Rigo.) + +\end{itemize} + +% pystone is almost useless for comparing different versions of Python; +% instead, it excels at predicting relative Python performance on +% different machines. +% So, this section would be more informative if it used other tools +% such as pybench and parrotbench. For a more application oriented +% benchmark, try comparing the timings of test_decimal.py under 2.3 +% and 2.4. + +The net result of the 2.4 optimizations is that Python 2.4 runs the +pystone benchmark around 5\% faster than Python 2.3 and 35\% faster +than Python 2.2. (pystone is not a particularly good benchmark, but +it's the most commonly used measurement of Python's performance. Your +own applications may show greater or smaller benefits from Python~2.4.) + + +%====================================================================== +\section{New, Improved, and Deprecated Modules} + +As usual, Python's standard library received a number of enhancements and +bug fixes. Here's a partial list of the most notable changes, sorted +alphabetically by module name. Consult the +\file{Misc/NEWS} file in the source tree for a more +complete list of changes, or look through the CVS logs for all the +details. + +\begin{itemize} + +\item The \module{asyncore} module's \function{loop()} function now + has a \var{count} parameter that lets you perform a limited number + of passes through the polling loop. The default is still to loop + forever. + +\item The \module{base64} module now has more complete RFC 3548 support + for Base64, Base32, and Base16 encoding and decoding, including + optional case folding and optional alternative alphabets. + (Contributed by Barry Warsaw.) + +\item The \module{bisect} module now has an underlying C implementation + for improved performance. + (Contributed by Dmitry Vasiliev.) + +\item The CJKCodecs collections of East Asian codecs, maintained +by Hye-Shik Chang, was integrated into 2.4. +The new encodings are: + +\begin{itemize} + \item Chinese (PRC): gb2312, gbk, gb18030, big5hkscs, hz + \item Chinese (ROC): big5, cp950 + \item Japanese: cp932, euc-jis-2004, euc-jp, +euc-jisx0213, iso-2022-jp, iso-2022-jp-1, iso-2022-jp-2, + iso-2022-jp-3, iso-2022-jp-ext, iso-2022-jp-2004, + shift-jis, shift-jisx0213, shift-jis-2004 + \item Korean: cp949, euc-kr, johab, iso-2022-kr +\end{itemize} + +\item Some other new encodings were added: HP Roman8, +ISO_8859-11, ISO_8859-16, PCTP-154, and TIS-620. + +\item The UTF-8 and UTF-16 codecs now cope better with receiving partial input. +Previously the \class{StreamReader} class would try to read more data, +making it impossible to resume decoding from the stream. The +\method{read()} method will now return as much data as it can and future +calls will resume decoding where previous ones left off. +(Implemented by Walter D\"orwald.) + +\item There is a new \module{collections} module for + various specialized collection datatypes. + Currently it contains just one type, \class{deque}, + a double-ended queue that supports efficiently adding and removing + elements from either end: + +\begin{verbatim} +>>> from collections import deque +>>> d = deque('ghi') # make a new deque with three items +>>> d.append('j') # add a new entry to the right side +>>> d.appendleft('f') # add a new entry to the left side +>>> d # show the representation of the deque +deque(['f', 'g', 'h', 'i', 'j']) +>>> d.pop() # return and remove the rightmost item +'j' +>>> d.popleft() # return and remove the leftmost item +'f' +>>> list(d) # list the contents of the deque +['g', 'h', 'i'] +>>> 'h' in d # search the deque +True +\end{verbatim} + +Several modules, such as the \module{Queue} and \module{threading} +modules, now take advantage of \class{collections.deque} for improved +performance. (Contributed by Raymond Hettinger.) + +\item The \module{ConfigParser} classes have been enhanced slightly. + The \method{read()} method now returns a list of the files that + were successfully parsed, and the \method{set()} method raises + \exception{TypeError} if passed a \var{value} argument that isn't a + string. (Contributed by John Belmonte and David Goodger.) + +\item The \module{curses} module now supports the ncurses extension + \function{use_default_colors()}. On platforms where the terminal + supports transparency, this makes it possible to use a transparent + background. (Contributed by J\"org Lehmann.) + +\item The \module{difflib} module now includes an \class{HtmlDiff} class +that creates an HTML table showing a side by side comparison +of two versions of a text. (Contributed by Dan Gass.) + +\item The \module{email} package was updated to version 3.0, +which dropped various deprecated APIs and removes support for Python +versions earlier than 2.3. The 3.0 version of the package uses a new +incremental parser for MIME messages, available in the +\module{email.FeedParser} module. The new parser doesn't require +reading the entire message into memory, and doesn't throw exceptions +if a message is malformed; instead it records any problems in the +\member{defect} attribute of the message. (Developed by Anthony +Baxter, Barry Warsaw, Thomas Wouters, and others.) + +\item The \module{heapq} module has been converted to C. The resulting + tenfold improvement in speed makes the module suitable for handling + high volumes of data. In addition, the module has two new functions + \function{nlargest()} and \function{nsmallest()} that use heaps to + find the N largest or smallest values in a dataset without the + expense of a full sort. (Contributed by Raymond Hettinger.) + +\item The \module{httplib} module now contains constants for HTTP +status codes defined in various HTTP-related RFC documents. Constants +have names such as \constant{OK}, \constant{CREATED}, +\constant{CONTINUE}, and \constant{MOVED_PERMANENTLY}; use pydoc to +get a full list. (Contributed by Andrew Eland.) + +\item The \module{imaplib} module now supports IMAP's THREAD command +(contributed by Yves Dionne) and new \method{deleteacl()} and +\method{myrights()} methods (contributed by Arnaud Mazin). + +\item The \module{itertools} module gained a + \function{groupby(\var{iterable}\optional{, \var{func}})} function. + \var{iterable} is something that can be iterated over to return a + stream of elements, and the optional \var{func} parameter is a + function that takes an element and returns a key value; if omitted, + the key is simply the element itself. \function{groupby()} then + groups the elements into subsequences which have matching values of + the key, and returns a series of 2-tuples containing the key value + and an iterator over the subsequence. + +Here's an example to make this clearer. The \var{key} function simply +returns whether a number is even or odd, so the result of +\function{groupby()} is to return consecutive runs of odd or even +numbers. + +\begin{verbatim} +>>> import itertools +>>> L = [2, 4, 6, 7, 8, 9, 11, 12, 14] +>>> for key_val, it in itertools.groupby(L, lambda x: x % 2): +... print key_val, list(it) +... +0 [2, 4, 6] +1 [7] +0 [8] +1 [9, 11] +0 [12, 14] +>>> +\end{verbatim} + +\function{groupby()} is typically used with sorted input. The logic +for \function{groupby()} is similar to the \UNIX{} \code{uniq} filter +which makes it handy for eliminating, counting, or identifying +duplicate elements: + +\begin{verbatim} +>>> word = 'abracadabra' +>>> letters = sorted(word) # Turn string into a sorted list of letters +>>> letters +['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r'] +>>> for k, g in itertools.groupby(letters): +... print k, list(g) +... +a ['a', 'a', 'a', 'a', 'a'] +b ['b', 'b'] +c ['c'] +d ['d'] +r ['r', 'r'] +>>> # List unique letters +>>> [k for k, g in groupby(letters)] +['a', 'b', 'c', 'd', 'r'] +>>> # Count letter occurrences +>>> [(k, len(list(g))) for k, g in groupby(letters)] +[('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)] +\end{verbatim} + +(Contributed by Hye-Shik Chang.) + +\item \module{itertools} also gained a function named +\function{tee(\var{iterator}, \var{N})} that returns \var{N} independent +iterators that replicate \var{iterator}. If \var{N} is omitted, the +default is 2. + +\begin{verbatim} +>>> L = [1,2,3] +>>> i1, i2 = itertools.tee(L) +>>> i1,i2 +(<itertools.tee object at 0x402c2080>, <itertools.tee object at 0x402c2090>) +>>> list(i1) # Run the first iterator to exhaustion +[1, 2, 3] +>>> list(i2) # Run the second iterator to exhaustion +[1, 2, 3] +>\end{verbatim} + +Note that \function{tee()} has to keep copies of the values returned +by the iterator; in the worst case, it may need to keep all of them. +This should therefore be used carefully if the leading iterator +can run far ahead of the trailing iterator in a long stream of inputs. +If the separation is large, then you might as well use +\function{list()} instead. When the iterators track closely with one +another, \function{tee()} is ideal. Possible applications include +bookmarking, windowing, or lookahead iterators. +(Contributed by Raymond Hettinger.) + +\item A number of functions were added to the \module{locale} +module, such as \function{bind_textdomain_codeset()} to specify a +particular encoding and a family of \function{l*gettext()} functions +that return messages in the chosen encoding. +(Contributed by Gustavo Niemeyer.) + +\item Some keyword arguments were added to the \module{logging} +package's \function{basicConfig} function to simplify log +configuration. The default behavior is to log messages to standard +error, but various keyword arguments can be specified to log to a +particular file, change the logging format, or set the logging level. +For example: + +\begin{verbatim} +import logging +logging.basicConfig(filename='/var/log/application.log', + level=0, # Log all messages + format='%(levelname):%(process):%(thread):%(message)') +\end{verbatim} + +Other additions to the \module{logging} package include a +\method{log(\var{level}, \var{msg})} convenience method, as well as a +\class{TimedRotatingFileHandler} class that rotates its log files at a +timed interval. The module already had \class{RotatingFileHandler}, +which rotated logs once the file exceeded a certain size. Both +classes derive from a new \class{BaseRotatingHandler} class that can +be used to implement other rotating handlers. + +(Changes implemented by Vinay Sajip.) + +\item The \module{marshal} module now shares interned strings on unpacking a +data structure. This may shrink the size of certain pickle strings, +but the primary effect is to make \file{.pyc} files significantly smaller. +(Contributed by Martin von~L\"owis.) + +\item The \module{nntplib} module's \class{NNTP} class gained +\method{description()} and \method{descriptions()} methods to retrieve +newsgroup descriptions for a single group or for a range of groups. +(Contributed by J\"urgen A. Erhard.) + +\item Two new functions were added to the \module{operator} module, +\function{attrgetter(\var{attr})} and \function{itemgetter(\var{index})}. +Both functions return callables that take a single argument and return +the corresponding attribute or item; these callables make excellent +data extractors when used with \function{map()} or +\function{sorted()}. For example: + +\begin{verbatim} +>>> L = [('c', 2), ('d', 1), ('a', 4), ('b', 3)] +>>> map(operator.itemgetter(0), L) +['c', 'd', 'a', 'b'] +>>> map(operator.itemgetter(1), L) +[2, 1, 4, 3] +>>> sorted(L, key=operator.itemgetter(1)) # Sort list by second tuple item +[('d', 1), ('c', 2), ('b', 3), ('a', 4)] +\end{verbatim} + +(Contributed by Raymond Hettinger.) + +\item The \module{optparse} module was updated in various ways. The +module now passes its messages through \function{gettext.gettext()}, +making it possible to internationalize Optik's help and error +messages. Help messages for options can now include the string +\code{'\%default'}, which will be replaced by the option's default +value. (Contributed by Greg Ward.) + +\item The long-term plan is to deprecate the \module{rfc822} module +in some future Python release in favor of the \module{email} package. +To this end, the \function{email.Utils.formatdate()} function has been +changed to make it usable as a replacement for +\function{rfc822.formatdate()}. You may want to write new e-mail +processing code with this in mind. (Change implemented by Anthony +Baxter.) + +\item A new \function{urandom(\var{n})} function was added to the +\module{os} module, returning a string containing \var{n} bytes of +random data. This function provides access to platform-specific +sources of randomness such as \file{/dev/urandom} on Linux or the +Windows CryptoAPI. (Contributed by Trevor Perrin.) + +\item Another new function: \function{os.path.lexists(\var{path})} +returns true if the file specified by \var{path} exists, whether or +not it's a symbolic link. This differs from the existing +\function{os.path.exists(\var{path})} function, which returns false if +\var{path} is a symlink that points to a destination that doesn't exist. +(Contributed by Beni Cherniavsky.) + +\item A new \function{getsid()} function was added to the +\module{posix} module that underlies the \module{os} module. +(Contributed by J. Raynor.) + +\item The \module{poplib} module now supports POP over SSL. (Contributed by +Hector Urtubia.) + +\item The \module{profile} module can now profile C extension functions. +(Contributed by Nick Bastin.) + +\item The \module{random} module has a new method called + \method{getrandbits(\var{N})} that returns a long integer \var{N} + bits in length. The existing \method{randrange()} method now uses + \method{getrandbits()} where appropriate, making generation of + arbitrarily large random numbers more efficient. (Contributed by + Raymond Hettinger.) + +\item The regular expression language accepted by the \module{re} module + was extended with simple conditional expressions, written as + \regexp{(?(\var{group})\var{A}|\var{B})}. \var{group} is either a + numeric group ID or a group name defined with \regexp{(?P<group>...)} + earlier in the expression. If the specified group matched, the + regular expression pattern \var{A} will be tested against the string; if + the group didn't match, the pattern \var{B} will be used instead. + (Contributed by Gustavo Niemeyer.) + +\item The \module{re} module is also no longer recursive, thanks to a +massive amount of work by Gustavo Niemeyer. In a recursive regular +expression engine, certain patterns result in a large amount of C +stack space being consumed, and it was possible to overflow the stack. +For example, if you matched a 30000-byte string of \samp{a} characters +against the expression \regexp{(a|b)+}, one stack frame was consumed +per character. Python 2.3 tried to check for stack overflow and raise +a \exception{RuntimeError} exception, but certain patterns could +sidestep the checking and if you were unlucky Python could segfault. +Python 2.4's regular expression engine can match this pattern without +problems. + +\item The \module{signal} module now performs tighter error-checking +on the parameters to the \function{signal.signal()} function. For +example, you can't set a handler on the \constant{SIGKILL} signal; +previous versions of Python would quietly accept this, but 2.4 will +raise a \exception{RuntimeError} exception. + +\item Two new functions were added to the \module{socket} module. +\function{socketpair()} returns a pair of connected sockets and +\function{getservbyport(\var{port})} looks up the service name for a +given port number. (Contributed by Dave Cole and Barry Warsaw.) + +\item The \function{sys.exitfunc()} function has been deprecated. Code +should be using the existing \module{atexit} module, which correctly +handles calling multiple exit functions. Eventually +\function{sys.exitfunc()} will become a purely internal interface, +accessed only by \module{atexit}. + +\item The \module{tarfile} module now generates GNU-format tar files +by default. (Contributed by Lars Gustaebel.) + +\item The \module{threading} module now has an elegantly simple way to support +thread-local data. The module contains a \class{local} class whose +attribute values are local to different threads. + +\begin{verbatim} +import threading + +data = threading.local() +data.number = 42 +data.url = ('www.python.org', 80) +\end{verbatim} + +Other threads can assign and retrieve their own values for the +\member{number} and \member{url} attributes. You can subclass +\class{local} to initialize attributes or to add methods. +(Contributed by Jim Fulton.) + +\item The \module{timeit} module now automatically disables periodic + garbage collection during the timing loop. This change makes + consecutive timings more comparable. (Contributed by Raymond Hettinger.) + +\item The \module{weakref} module now supports a wider variety of objects + including Python functions, class instances, sets, frozensets, deques, + arrays, files, sockets, and regular expression pattern objects. + (Contributed by Raymond Hettinger.) + +\item The \module{xmlrpclib} module now supports a multi-call extension for +transmitting multiple XML-RPC calls in a single HTTP operation. +(Contributed by Brian Quinlan.) + +\item The \module{mpz}, \module{rotor}, and \module{xreadlines} modules have +been removed. + +\end{itemize} + + +%====================================================================== +% whole new modules get described in subsections here + +%===================== +\subsection{cookielib} + +The \module{cookielib} library supports client-side handling for HTTP +cookies, mirroring the \module{Cookie} module's server-side cookie +support. Cookies are stored in cookie jars; the library transparently +stores cookies offered by the web server in the cookie jar, and +fetches the cookie from the jar when connecting to the server. As in +web browsers, policy objects control whether cookies are accepted or +not. + +In order to store cookies across sessions, two implementations of +cookie jars are provided: one that stores cookies in the Netscape +format so applications can use the Mozilla or Lynx cookie files, and +one that stores cookies in the same format as the Perl libwww library. + +\module{urllib2} has been changed to interact with \module{cookielib}: +\class{HTTPCookieProcessor} manages a cookie jar that is used when +accessing URLs. + +This module was contributed by John J. Lee. + + +% ================== +\subsection{doctest} + +The \module{doctest} module underwent considerable refactoring thanks +to Edward Loper and Tim Peters. Testing can still be as simple as +running \function{doctest.testmod()}, but the refactorings allow +customizing the module's operation in various ways + +The new \class{DocTestFinder} class extracts the tests from a given +object's docstrings: + +\begin{verbatim} +def f (x, y): + """>>> f(2,2) +4 +>>> f(3,2) +6 + """ + return x*y + +finder = doctest.DocTestFinder() + +# Get list of DocTest instances +tests = finder.find(f) +\end{verbatim} + +The new \class{DocTestRunner} class then runs individual tests and can +produce a summary of the results: + +\begin{verbatim} +runner = doctest.DocTestRunner() +for t in tests: + tried, failed = runner.run(t) + +runner.summarize(verbose=1) +\end{verbatim} + +The above example produces the following output: + +\begin{verbatim} +1 items passed all tests: + 2 tests in f +2 tests in 1 items. +2 passed and 0 failed. +Test passed. +\end{verbatim} + +\class{DocTestRunner} uses an instance of the \class{OutputChecker} +class to compare the expected output with the actual output. This +class takes a number of different flags that customize its behaviour; +ambitious users can also write a completely new subclass of +\class{OutputChecker}. + +The default output checker provides a number of handy features. +For example, with the \constant{doctest.ELLIPSIS} option flag, +an ellipsis (\samp{...}) in the expected output matches any substring, +making it easier to accommodate outputs that vary in minor ways: + +\begin{verbatim} +def o (n): + """>>> o(1) +<__main__.C instance at 0x...> +>>> +""" +\end{verbatim} + +Another special string, \samp{<BLANKLINE>}, matches a blank line: + +\begin{verbatim} +def p (n): + """>>> p(1) +<BLANKLINE> +>>> +""" +\end{verbatim} + +Another new capability is producing a diff-style display of the output +by specifying the \constant{doctest.REPORT_UDIFF} (unified diffs), +\constant{doctest.REPORT_CDIFF} (context diffs), or +\constant{doctest.REPORT_NDIFF} (delta-style) option flags. For example: + +\begin{verbatim} +def g (n): + """>>> g(4) +here +is +a +lengthy +>>>""" + L = 'here is a rather lengthy list of words'.split() + for word in L[:n]: + print word +\end{verbatim} + +Running the above function's tests with +\constant{doctest.REPORT_UDIFF} specified, you get the following output: + +\begin{verbatim} +********************************************************************** +File ``t.py'', line 15, in g +Failed example: + g(4) +Differences (unified diff with -expected +actual): + @@ -2,3 +2,3 @@ + is + a + -lengthy + +rather +********************************************************************** +\end{verbatim} + + +% ====================================================================== +\section{Build and C API Changes} + +Some of the changes to Python's build process and to the C API are: + +\begin{itemize} + + \item Three new convenience macros were added for common return + values from extension functions: \csimplemacro{Py_RETURN_NONE}, + \csimplemacro{Py_RETURN_TRUE}, and \csimplemacro{Py_RETURN_FALSE}. + (Contributed by Brett Cannon.) + + \item Another new macro, \csimplemacro{Py_CLEAR(\var{obj})}, + decreases the reference count of \var{obj} and sets \var{obj} to the + null pointer. (Contributed by Jim Fulton.) + + \item A new function, \cfunction{PyTuple_Pack(\var{N}, \var{obj1}, + \var{obj2}, ..., \var{objN})}, constructs tuples from a variable + length argument list of Python objects. (Contributed by Raymond Hettinger.) + + \item A new function, \cfunction{PyDict_Contains(\var{d}, \var{k})}, + implements fast dictionary lookups without masking exceptions raised + during the look-up process. (Contributed by Raymond Hettinger.) + + \item The \csimplemacro{Py_IS_NAN(\var{X})} macro returns 1 if + its float or double argument \var{X} is a NaN. + (Contributed by Tim Peters.) + + \item C code can avoid unnecessary locking by using the new + \cfunction{PyEval_ThreadsInitialized()} function to tell + if any thread operations have been performed. If this function + returns false, no lock operations are needed. + (Contributed by Nick Coghlan.) + + \item A new function, \cfunction{PyArg_VaParseTupleAndKeywords()}, + is the same as \cfunction{PyArg_ParseTupleAndKeywords()} but takes a + \ctype{va_list} instead of a number of arguments. + (Contributed by Greg Chapman.) + + \item A new method flag, \constant{METH_COEXISTS}, allows a function + defined in slots to co-exist with a \ctype{PyCFunction} having the + same name. This can halve the access time for a method such as + \method{set.__contains__()}. (Contributed by Raymond Hettinger.) + + \item Python can now be built with additional profiling for the + interpreter itself, intended as an aid to people developing the + Python core. Providing \longprogramopt{--enable-profiling} to the + \program{configure} script will let you profile the interpreter with + \program{gprof}, and providing the \longprogramopt{--with-tsc} + switch enables profiling using the Pentium's Time-Stamp-Counter + register. Note that the \longprogramopt{--with-tsc} switch is slightly + misnamed, because the profiling feature also works on the PowerPC + platform, though that processor architecture doesn't call that + register ``the TSC register''. (Contributed by Jeremy Hylton.) + + \item The \ctype{tracebackobject} type has been renamed to \ctype{PyTracebackObject}. + +\end{itemize} + + +%====================================================================== +\subsection{Port-Specific Changes} + +\begin{itemize} + +\item The Windows port now builds under MSVC++ 7.1 as well as version 6. + (Contributed by Martin von~L\"owis.) + +\end{itemize} + + + +%====================================================================== +\section{Porting to Python 2.4} + +This section lists previously described changes that may require +changes to your code: + +\begin{itemize} + +\item Left shifts and hexadecimal/octal constants that are too + large no longer trigger a \exception{FutureWarning} and return + a value limited to 32 or 64 bits; instead they return a long integer. + +\item Integer operations will no longer trigger an \exception{OverflowWarning}. +The \exception{OverflowWarning} warning will disappear in Python 2.5. + +\item The \function{zip()} built-in function and \function{itertools.izip()} + now return an empty list instead of raising a \exception{TypeError} + exception if called with no arguments. + +\item You can no longer compare the \class{date} and \class{datetime} + instances provided by the \module{datetime} module. Two + instances of different classes will now always be unequal, and + relative comparisons (\code{<}, \code{>}) will raise a \exception{TypeError}. + +\item \function{dircache.listdir()} now passes exceptions to the caller + instead of returning empty lists. + +\item \function{LexicalHandler.startDTD()} used to receive the public and + system IDs in the wrong order. This has been corrected; applications + relying on the wrong order need to be fixed. + +\item \function{fcntl.ioctl} now warns if the \var{mutate} + argument is omitted and relevant. + +\item The \module{tarfile} module now generates GNU-format tar files +by default. + +\item Encountering a failure while importing a module no longer leaves +a partially-initialized module object in \code{sys.modules}. + +\item \constant{None} is now a constant; code that binds a new value to +the name \samp{None} is now a syntax error. + +\item The \function{signals.signal()} function now raises a +\exception{RuntimeError} exception for certain illegal values; +previously these errors would pass silently. For example, you can no +longer set a handler on the \constant{SIGKILL} signal. + +\end{itemize} + + +%====================================================================== +\section{Acknowledgements \label{acks}} + +The author would like to thank the following people for offering +suggestions, corrections and assistance with various drafts of this +article: Koray Can, Hye-Shik Chang, Michael Dyck, Raymond Hettinger, +Brian Hurt, Hamish Lawson, Fredrik Lundh, Sean Reifschneider, +Sadruddin Rejeb. + +\end{document} diff --git a/sys/src/cmd/python/Doc/whatsnew/whatsnew25.tex b/sys/src/cmd/python/Doc/whatsnew/whatsnew25.tex new file mode 100644 index 000000000..9d78adcd8 --- /dev/null +++ b/sys/src/cmd/python/Doc/whatsnew/whatsnew25.tex @@ -0,0 +1,2530 @@ +\documentclass{howto} +\usepackage{distutils} +% $Id: whatsnew25.tex 54622 2007-03-30 17:58:16Z andrew.kuchling $ + +% Fix XXX comments + +\title{What's New in Python 2.5} +\release{1.01} +\author{A.M. Kuchling} +\authoraddress{\email{amk@amk.ca}} + +\begin{document} +\maketitle +\tableofcontents + +This article explains the new features in Python 2.5. The final +release of Python 2.5 is scheduled for August 2006; +\pep{356} describes the planned release schedule. + +The changes in Python 2.5 are an interesting mix of language and +library improvements. The library enhancements will be more important +to Python's user community, I think, because several widely-useful +packages were added. New modules include ElementTree for XML +processing (section~\ref{module-etree}), the SQLite database module +(section~\ref{module-sqlite}), and the \module{ctypes} module for +calling C functions (section~\ref{module-ctypes}). + +The language changes are of middling significance. Some pleasant new +features were added, but most of them aren't features that you'll use +every day. Conditional expressions were finally added to the language +using a novel syntax; see section~\ref{pep-308}. The new +'\keyword{with}' statement will make writing cleanup code easier +(section~\ref{pep-343}). Values can now be passed into generators +(section~\ref{pep-342}). Imports are now visible as either absolute +or relative (section~\ref{pep-328}). Some corner cases of exception +handling are handled better (section~\ref{pep-341}). All these +improvements are worthwhile, but they're improvements to one specific +language feature or another; none of them are broad modifications to +Python's semantics. + +As well as the language and library additions, other improvements and +bugfixes were made throughout the source tree. A search through the +SVN change logs finds there were 353 patches applied and 458 bugs +fixed between Python 2.4 and 2.5. (Both figures are likely to be +underestimates.) + +This article doesn't try to be a complete specification of the new +features; instead changes are briefly introduced using helpful +examples. For full details, you should always refer to the +documentation for Python 2.5 at \url{http://docs.python.org}. +If you want to understand the complete implementation and design +rationale, refer to the PEP for a particular new feature. + +Comments, suggestions, and error reports for this document are +welcome; please e-mail them to the author or open a bug in the Python +bug tracker. + +%====================================================================== +\section{PEP 308: Conditional Expressions\label{pep-308}} + +For a long time, people have been requesting a way to write +conditional expressions, which are expressions that return value A or +value B depending on whether a Boolean value is true or false. A +conditional expression lets you write a single assignment statement +that has the same effect as the following: + +\begin{verbatim} +if condition: + x = true_value +else: + x = false_value +\end{verbatim} + +There have been endless tedious discussions of syntax on both +python-dev and comp.lang.python. A vote was even held that found the +majority of voters wanted conditional expressions in some form, +but there was no syntax that was preferred by a clear majority. +Candidates included C's \code{cond ? true_v : false_v}, +\code{if cond then true_v else false_v}, and 16 other variations. + +Guido van~Rossum eventually chose a surprising syntax: + +\begin{verbatim} +x = true_value if condition else false_value +\end{verbatim} + +Evaluation is still lazy as in existing Boolean expressions, so the +order of evaluation jumps around a bit. The \var{condition} +expression in the middle is evaluated first, and the \var{true_value} +expression is evaluated only if the condition was true. Similarly, +the \var{false_value} expression is only evaluated when the condition +is false. + +This syntax may seem strange and backwards; why does the condition go +in the \emph{middle} of the expression, and not in the front as in C's +\code{c ? x : y}? The decision was checked by applying the new syntax +to the modules in the standard library and seeing how the resulting +code read. In many cases where a conditional expression is used, one +value seems to be the 'common case' and one value is an 'exceptional +case', used only on rarer occasions when the condition isn't met. The +conditional syntax makes this pattern a bit more obvious: + +\begin{verbatim} +contents = ((doc + '\n') if doc else '') +\end{verbatim} + +I read the above statement as meaning ``here \var{contents} is +usually assigned a value of \code{doc+'\e n'}; sometimes +\var{doc} is empty, in which special case an empty string is returned.'' +I doubt I will use conditional expressions very often where there +isn't a clear common and uncommon case. + +There was some discussion of whether the language should require +surrounding conditional expressions with parentheses. The decision +was made to \emph{not} require parentheses in the Python language's +grammar, but as a matter of style I think you should always use them. +Consider these two statements: + +\begin{verbatim} +# First version -- no parens +level = 1 if logging else 0 + +# Second version -- with parens +level = (1 if logging else 0) +\end{verbatim} + +In the first version, I think a reader's eye might group the statement +into 'level = 1', 'if logging', 'else 0', and think that the condition +decides whether the assignment to \var{level} is performed. The +second version reads better, in my opinion, because it makes it clear +that the assignment is always performed and the choice is being made +between two values. + +Another reason for including the brackets: a few odd combinations of +list comprehensions and lambdas could look like incorrect conditional +expressions. See \pep{308} for some examples. If you put parentheses +around your conditional expressions, you won't run into this case. + + +\begin{seealso} + +\seepep{308}{Conditional Expressions}{PEP written by +Guido van~Rossum and Raymond D. Hettinger; implemented by Thomas +Wouters.} + +\end{seealso} + + +%====================================================================== +\section{PEP 309: Partial Function Application\label{pep-309}} + +The \module{functools} module is intended to contain tools for +functional-style programming. + +One useful tool in this module is the \function{partial()} function. +For programs written in a functional style, you'll sometimes want to +construct variants of existing functions that have some of the +parameters filled in. Consider a Python function \code{f(a, b, c)}; +you could create a new function \code{g(b, c)} that was equivalent to +\code{f(1, b, c)}. This is called ``partial function application''. + +\function{partial} takes the arguments +\code{(\var{function}, \var{arg1}, \var{arg2}, ... +\var{kwarg1}=\var{value1}, \var{kwarg2}=\var{value2})}. The resulting +object is callable, so you can just call it to invoke \var{function} +with the filled-in arguments. + +Here's a small but realistic example: + +\begin{verbatim} +import functools + +def log (message, subsystem): + "Write the contents of 'message' to the specified subsystem." + print '%s: %s' % (subsystem, message) + ... + +server_log = functools.partial(log, subsystem='server') +server_log('Unable to open socket') +\end{verbatim} + +Here's another example, from a program that uses PyGTK. Here a +context-sensitive pop-up menu is being constructed dynamically. The +callback provided for the menu option is a partially applied version +of the \method{open_item()} method, where the first argument has been +provided. + +\begin{verbatim} +... +class Application: + def open_item(self, path): + ... + def init (self): + open_func = functools.partial(self.open_item, item_path) + popup_menu.append( ("Open", open_func, 1) ) +\end{verbatim} + + +Another function in the \module{functools} module is the +\function{update_wrapper(\var{wrapper}, \var{wrapped})} function that +helps you write well-behaved decorators. \function{update_wrapper()} +copies the name, module, and docstring attribute to a wrapper function +so that tracebacks inside the wrapped function are easier to +understand. For example, you might write: + +\begin{verbatim} +def my_decorator(f): + def wrapper(*args, **kwds): + print 'Calling decorated function' + return f(*args, **kwds) + functools.update_wrapper(wrapper, f) + return wrapper +\end{verbatim} + +\function{wraps()} is a decorator that can be used inside your own +decorators to copy the wrapped function's information. An alternate +version of the previous example would be: + +\begin{verbatim} +def my_decorator(f): + @functools.wraps(f) + def wrapper(*args, **kwds): + print 'Calling decorated function' + return f(*args, **kwds) + return wrapper +\end{verbatim} + +\begin{seealso} + +\seepep{309}{Partial Function Application}{PEP proposed and written by +Peter Harris; implemented by Hye-Shik Chang and Nick Coghlan, with +adaptations by Raymond Hettinger.} + +\end{seealso} + + +%====================================================================== +\section{PEP 314: Metadata for Python Software Packages v1.1\label{pep-314}} + +Some simple dependency support was added to Distutils. The +\function{setup()} function now has \code{requires}, \code{provides}, +and \code{obsoletes} keyword parameters. When you build a source +distribution using the \code{sdist} command, the dependency +information will be recorded in the \file{PKG-INFO} file. + +Another new keyword parameter is \code{download_url}, which should be +set to a URL for the package's source code. This means it's now +possible to look up an entry in the package index, determine the +dependencies for a package, and download the required packages. + +\begin{verbatim} +VERSION = '1.0' +setup(name='PyPackage', + version=VERSION, + requires=['numarray', 'zlib (>=1.1.4)'], + obsoletes=['OldPackage'] + download_url=('http://www.example.com/pypackage/dist/pkg-%s.tar.gz' + % VERSION), + ) +\end{verbatim} + +Another new enhancement to the Python package index at +\url{http://cheeseshop.python.org} is storing source and binary +archives for a package. The new \command{upload} Distutils command +will upload a package to the repository. + +Before a package can be uploaded, you must be able to build a +distribution using the \command{sdist} Distutils command. Once that +works, you can run \code{python setup.py upload} to add your package +to the PyPI archive. Optionally you can GPG-sign the package by +supplying the \longprogramopt{sign} and +\longprogramopt{identity} options. + +Package uploading was implemented by Martin von~L\"owis and Richard Jones. + +\begin{seealso} + +\seepep{314}{Metadata for Python Software Packages v1.1}{PEP proposed +and written by A.M. Kuchling, Richard Jones, and Fred Drake; +implemented by Richard Jones and Fred Drake.} + +\end{seealso} + + +%====================================================================== +\section{PEP 328: Absolute and Relative Imports\label{pep-328}} + +The simpler part of PEP 328 was implemented in Python 2.4: parentheses +could now be used to enclose the names imported from a module using +the \code{from ... import ...} statement, making it easier to import +many different names. + +The more complicated part has been implemented in Python 2.5: +importing a module can be specified to use absolute or +package-relative imports. The plan is to move toward making absolute +imports the default in future versions of Python. + +Let's say you have a package directory like this: +\begin{verbatim} +pkg/ +pkg/__init__.py +pkg/main.py +pkg/string.py +\end{verbatim} + +This defines a package named \module{pkg} containing the +\module{pkg.main} and \module{pkg.string} submodules. + +Consider the code in the \file{main.py} module. What happens if it +executes the statement \code{import string}? In Python 2.4 and +earlier, it will first look in the package's directory to perform a +relative import, finds \file{pkg/string.py}, imports the contents of +that file as the \module{pkg.string} module, and that module is bound +to the name \samp{string} in the \module{pkg.main} module's namespace. + +That's fine if \module{pkg.string} was what you wanted. But what if +you wanted Python's standard \module{string} module? There's no clean +way to ignore \module{pkg.string} and look for the standard module; +generally you had to look at the contents of \code{sys.modules}, which +is slightly unclean. +Holger Krekel's \module{py.std} package provides a tidier way to perform +imports from the standard library, \code{import py ; py.std.string.join()}, +but that package isn't available on all Python installations. + +Reading code which relies on relative imports is also less clear, +because a reader may be confused about which module, \module{string} +or \module{pkg.string}, is intended to be used. Python users soon +learned not to duplicate the names of standard library modules in the +names of their packages' submodules, but you can't protect against +having your submodule's name being used for a new module added in a +future version of Python. + +In Python 2.5, you can switch \keyword{import}'s behaviour to +absolute imports using a \code{from __future__ import absolute_import} +directive. This absolute-import behaviour will become the default in +a future version (probably Python 2.7). Once absolute imports +are the default, \code{import string} will +always find the standard library's version. +It's suggested that users should begin using absolute imports as much +as possible, so it's preferable to begin writing \code{from pkg import +string} in your code. + +Relative imports are still possible by adding a leading period +to the module name when using the \code{from ... import} form: + +\begin{verbatim} +# Import names from pkg.string +from .string import name1, name2 +# Import pkg.string +from . import string +\end{verbatim} + +This imports the \module{string} module relative to the current +package, so in \module{pkg.main} this will import \var{name1} and +\var{name2} from \module{pkg.string}. Additional leading periods +perform the relative import starting from the parent of the current +package. For example, code in the \module{A.B.C} module can do: + +\begin{verbatim} +from . import D # Imports A.B.D +from .. import E # Imports A.E +from ..F import G # Imports A.F.G +\end{verbatim} + +Leading periods cannot be used with the \code{import \var{modname}} +form of the import statement, only the \code{from ... import} form. + +\begin{seealso} + +\seepep{328}{Imports: Multi-Line and Absolute/Relative} +{PEP written by Aahz; implemented by Thomas Wouters.} + +\seeurl{http://codespeak.net/py/current/doc/index.html} +{The py library by Holger Krekel, which contains the \module{py.std} package.} + +\end{seealso} + + +%====================================================================== +\section{PEP 338: Executing Modules as Scripts\label{pep-338}} + +The \programopt{-m} switch added in Python 2.4 to execute a module as +a script gained a few more abilities. Instead of being implemented in +C code inside the Python interpreter, the switch now uses an +implementation in a new module, \module{runpy}. + +The \module{runpy} module implements a more sophisticated import +mechanism so that it's now possible to run modules in a package such +as \module{pychecker.checker}. The module also supports alternative +import mechanisms such as the \module{zipimport} module. This means +you can add a .zip archive's path to \code{sys.path} and then use the +\programopt{-m} switch to execute code from the archive. + + +\begin{seealso} + +\seepep{338}{Executing modules as scripts}{PEP written and +implemented by Nick Coghlan.} + +\end{seealso} + + +%====================================================================== +\section{PEP 341: Unified try/except/finally\label{pep-341}} + +Until Python 2.5, the \keyword{try} statement came in two +flavours. You could use a \keyword{finally} block to ensure that code +is always executed, or one or more \keyword{except} blocks to catch +specific exceptions. You couldn't combine both \keyword{except} blocks and a +\keyword{finally} block, because generating the right bytecode for the +combined version was complicated and it wasn't clear what the +semantics of the combined statement should be. + +Guido van~Rossum spent some time working with Java, which does support the +equivalent of combining \keyword{except} blocks and a +\keyword{finally} block, and this clarified what the statement should +mean. In Python 2.5, you can now write: + +\begin{verbatim} +try: + block-1 ... +except Exception1: + handler-1 ... +except Exception2: + handler-2 ... +else: + else-block +finally: + final-block +\end{verbatim} + +The code in \var{block-1} is executed. If the code raises an +exception, the various \keyword{except} blocks are tested: if the +exception is of class \class{Exception1}, \var{handler-1} is executed; +otherwise if it's of class \class{Exception2}, \var{handler-2} is +executed, and so forth. If no exception is raised, the +\var{else-block} is executed. + +No matter what happened previously, the \var{final-block} is executed +once the code block is complete and any raised exceptions handled. +Even if there's an error in an exception handler or the +\var{else-block} and a new exception is raised, the +code in the \var{final-block} is still run. + +\begin{seealso} + +\seepep{341}{Unifying try-except and try-finally}{PEP written by Georg Brandl; +implementation by Thomas Lee.} + +\end{seealso} + + +%====================================================================== +\section{PEP 342: New Generator Features\label{pep-342}} + +Python 2.5 adds a simple way to pass values \emph{into} a generator. +As introduced in Python 2.3, generators only produce output; once a +generator's code was invoked to create an iterator, there was no way to +pass any new information into the function when its execution is +resumed. Sometimes the ability to pass in some information would be +useful. Hackish solutions to this include making the generator's code +look at a global variable and then changing the global variable's +value, or passing in some mutable object that callers then modify. + +To refresh your memory of basic generators, here's a simple example: + +\begin{verbatim} +def counter (maximum): + i = 0 + while i < maximum: + yield i + i += 1 +\end{verbatim} + +When you call \code{counter(10)}, the result is an iterator that +returns the values from 0 up to 9. On encountering the +\keyword{yield} statement, the iterator returns the provided value and +suspends the function's execution, preserving the local variables. +Execution resumes on the following call to the iterator's +\method{next()} method, picking up after the \keyword{yield} statement. + +In Python 2.3, \keyword{yield} was a statement; it didn't return any +value. In 2.5, \keyword{yield} is now an expression, returning a +value that can be assigned to a variable or otherwise operated on: + +\begin{verbatim} +val = (yield i) +\end{verbatim} + +I recommend that you always put parentheses around a \keyword{yield} +expression when you're doing something with the returned value, as in +the above example. The parentheses aren't always necessary, but it's +easier to always add them instead of having to remember when they're +needed. + +(\pep{342} explains the exact rules, which are that a +\keyword{yield}-expression must always be parenthesized except when it +occurs at the top-level expression on the right-hand side of an +assignment. This means you can write \code{val = yield i} but have to +use parentheses when there's an operation, as in \code{val = (yield i) ++ 12}.) + +Values are sent into a generator by calling its +\method{send(\var{value})} method. The generator's code is then +resumed and the \keyword{yield} expression returns the specified +\var{value}. If the regular \method{next()} method is called, the +\keyword{yield} returns \constant{None}. + +Here's the previous example, modified to allow changing the value of +the internal counter. + +\begin{verbatim} +def counter (maximum): + i = 0 + while i < maximum: + val = (yield i) + # If value provided, change counter + if val is not None: + i = val + else: + i += 1 +\end{verbatim} + +And here's an example of changing the counter: + +\begin{verbatim} +>>> it = counter(10) +>>> print it.next() +0 +>>> print it.next() +1 +>>> print it.send(8) +8 +>>> print it.next() +9 +>>> print it.next() +Traceback (most recent call last): + File ``t.py'', line 15, in ? + print it.next() +StopIteration +\end{verbatim} + +\keyword{yield} will usually return \constant{None}, so you +should always check for this case. Don't just use its value in +expressions unless you're sure that the \method{send()} method +will be the only method used to resume your generator function. + +In addition to \method{send()}, there are two other new methods on +generators: + +\begin{itemize} + + \item \method{throw(\var{type}, \var{value}=None, + \var{traceback}=None)} is used to raise an exception inside the + generator; the exception is raised by the \keyword{yield} expression + where the generator's execution is paused. + + \item \method{close()} raises a new \exception{GeneratorExit} + exception inside the generator to terminate the iteration. On + receiving this exception, the generator's code must either raise + \exception{GeneratorExit} or \exception{StopIteration}. Catching + the \exception{GeneratorExit} exception and returning a value is + illegal and will trigger a \exception{RuntimeError}; if the function + raises some other exception, that exception is propagated to the + caller. \method{close()} will also be called by Python's garbage + collector when the generator is garbage-collected. + + If you need to run cleanup code when a \exception{GeneratorExit} occurs, + I suggest using a \code{try: ... finally:} suite instead of + catching \exception{GeneratorExit}. + +\end{itemize} + +The cumulative effect of these changes is to turn generators from +one-way producers of information into both producers and consumers. + +Generators also become \emph{coroutines}, a more generalized form of +subroutines. Subroutines are entered at one point and exited at +another point (the top of the function, and a \keyword{return} +statement), but coroutines can be entered, exited, and resumed at +many different points (the \keyword{yield} statements). We'll have to +figure out patterns for using coroutines effectively in Python. + +The addition of the \method{close()} method has one side effect that +isn't obvious. \method{close()} is called when a generator is +garbage-collected, so this means the generator's code gets one last +chance to run before the generator is destroyed. This last chance +means that \code{try...finally} statements in generators can now be +guaranteed to work; the \keyword{finally} clause will now always get a +chance to run. The syntactic restriction that you couldn't mix +\keyword{yield} statements with a \code{try...finally} suite has +therefore been removed. This seems like a minor bit of language +trivia, but using generators and \code{try...finally} is actually +necessary in order to implement the \keyword{with} statement +described by PEP 343. I'll look at this new statement in the following +section. + +Another even more esoteric effect of this change: previously, the +\member{gi_frame} attribute of a generator was always a frame object. +It's now possible for \member{gi_frame} to be \code{None} +once the generator has been exhausted. + +\begin{seealso} + +\seepep{342}{Coroutines via Enhanced Generators}{PEP written by +Guido van~Rossum and Phillip J. Eby; +implemented by Phillip J. Eby. Includes examples of +some fancier uses of generators as coroutines. + +Earlier versions of these features were proposed in +\pep{288} by Raymond Hettinger and \pep{325} by Samuele Pedroni. +} + +\seeurl{http://en.wikipedia.org/wiki/Coroutine}{The Wikipedia entry for +coroutines.} + +\seeurl{http://www.sidhe.org/\~{}dan/blog/archives/000178.html}{An +explanation of coroutines from a Perl point of view, written by Dan +Sugalski.} + +\end{seealso} + + +%====================================================================== +\section{PEP 343: The 'with' statement\label{pep-343}} + +The '\keyword{with}' statement clarifies code that previously would +use \code{try...finally} blocks to ensure that clean-up code is +executed. In this section, I'll discuss the statement as it will +commonly be used. In the next section, I'll examine the +implementation details and show how to write objects for use with this +statement. + +The '\keyword{with}' statement is a new control-flow structure whose +basic structure is: + +\begin{verbatim} +with expression [as variable]: + with-block +\end{verbatim} + +The expression is evaluated, and it should result in an object that +supports the context management protocol. This object may return a +value that can optionally be bound to the name \var{variable}. (Note +carefully that \var{variable} is \emph{not} assigned the result of +\var{expression}.) The object can then run set-up code +before \var{with-block} is executed and some clean-up code +is executed after the block is done, even if the block raised an exception. + +To enable the statement in Python 2.5, you need +to add the following directive to your module: + +\begin{verbatim} +from __future__ import with_statement +\end{verbatim} + +The statement will always be enabled in Python 2.6. + +Some standard Python objects now support the context management +protocol and can be used with the '\keyword{with}' statement. File +objects are one example: + +\begin{verbatim} +with open('/etc/passwd', 'r') as f: + for line in f: + print line + ... more processing code ... +\end{verbatim} + +After this statement has executed, the file object in \var{f} will +have been automatically closed, even if the 'for' loop +raised an exception part-way through the block. + +The \module{threading} module's locks and condition variables +also support the '\keyword{with}' statement: + +\begin{verbatim} +lock = threading.Lock() +with lock: + # Critical section of code + ... +\end{verbatim} + +The lock is acquired before the block is executed and always released once +the block is complete. + +The new \function{localcontext()} function in the \module{decimal} module +makes it easy to save and restore the current decimal context, which +encapsulates the desired precision and rounding characteristics for +computations: + +\begin{verbatim} +from decimal import Decimal, Context, localcontext + +# Displays with default precision of 28 digits +v = Decimal('578') +print v.sqrt() + +with localcontext(Context(prec=16)): + # All code in this block uses a precision of 16 digits. + # The original context is restored on exiting the block. + print v.sqrt() +\end{verbatim} + +\subsection{Writing Context Managers\label{context-managers}} + +Under the hood, the '\keyword{with}' statement is fairly complicated. +Most people will only use '\keyword{with}' in company with existing +objects and don't need to know these details, so you can skip the rest +of this section if you like. Authors of new objects will need to +understand the details of the underlying implementation and should +keep reading. + +A high-level explanation of the context management protocol is: + +\begin{itemize} + +\item The expression is evaluated and should result in an object +called a ``context manager''. The context manager must have +\method{__enter__()} and \method{__exit__()} methods. + +\item The context manager's \method{__enter__()} method is called. The value +returned is assigned to \var{VAR}. If no \code{'as \var{VAR}'} clause +is present, the value is simply discarded. + +\item The code in \var{BLOCK} is executed. + +\item If \var{BLOCK} raises an exception, the +\method{__exit__(\var{type}, \var{value}, \var{traceback})} is called +with the exception details, the same values returned by +\function{sys.exc_info()}. The method's return value controls whether +the exception is re-raised: any false value re-raises the exception, +and \code{True} will result in suppressing it. You'll only rarely +want to suppress the exception, because if you do +the author of the code containing the +'\keyword{with}' statement will never realize anything went wrong. + +\item If \var{BLOCK} didn't raise an exception, +the \method{__exit__()} method is still called, +but \var{type}, \var{value}, and \var{traceback} are all \code{None}. + +\end{itemize} + +Let's think through an example. I won't present detailed code but +will only sketch the methods necessary for a database that supports +transactions. + +(For people unfamiliar with database terminology: a set of changes to +the database are grouped into a transaction. Transactions can be +either committed, meaning that all the changes are written into the +database, or rolled back, meaning that the changes are all discarded +and the database is unchanged. See any database textbook for more +information.) + +Let's assume there's an object representing a database connection. +Our goal will be to let the user write code like this: + +\begin{verbatim} +db_connection = DatabaseConnection() +with db_connection as cursor: + cursor.execute('insert into ...') + cursor.execute('delete from ...') + # ... more operations ... +\end{verbatim} + +The transaction should be committed if the code in the block +runs flawlessly or rolled back if there's an exception. +Here's the basic interface +for \class{DatabaseConnection} that I'll assume: + +\begin{verbatim} +class DatabaseConnection: + # Database interface + def cursor (self): + "Returns a cursor object and starts a new transaction" + def commit (self): + "Commits current transaction" + def rollback (self): + "Rolls back current transaction" +\end{verbatim} + +The \method {__enter__()} method is pretty easy, having only to start +a new transaction. For this application the resulting cursor object +would be a useful result, so the method will return it. The user can +then add \code{as cursor} to their '\keyword{with}' statement to bind +the cursor to a variable name. + +\begin{verbatim} +class DatabaseConnection: + ... + def __enter__ (self): + # Code to start a new transaction + cursor = self.cursor() + return cursor +\end{verbatim} + +The \method{__exit__()} method is the most complicated because it's +where most of the work has to be done. The method has to check if an +exception occurred. If there was no exception, the transaction is +committed. The transaction is rolled back if there was an exception. + +In the code below, execution will just fall off the end of the +function, returning the default value of \code{None}. \code{None} is +false, so the exception will be re-raised automatically. If you +wished, you could be more explicit and add a \keyword{return} +statement at the marked location. + +\begin{verbatim} +class DatabaseConnection: + ... + def __exit__ (self, type, value, tb): + if tb is None: + # No exception, so commit + self.commit() + else: + # Exception occurred, so rollback. + self.rollback() + # return False +\end{verbatim} + + +\subsection{The contextlib module\label{module-contextlib}} + +The new \module{contextlib} module provides some functions and a +decorator that are useful for writing objects for use with the +'\keyword{with}' statement. + +The decorator is called \function{contextmanager}, and lets you write +a single generator function instead of defining a new class. The generator +should yield exactly one value. The code up to the \keyword{yield} +will be executed as the \method{__enter__()} method, and the value +yielded will be the method's return value that will get bound to the +variable in the '\keyword{with}' statement's \keyword{as} clause, if +any. The code after the \keyword{yield} will be executed in the +\method{__exit__()} method. Any exception raised in the block will be +raised by the \keyword{yield} statement. + +Our database example from the previous section could be written +using this decorator as: + +\begin{verbatim} +from contextlib import contextmanager + +@contextmanager +def db_transaction (connection): + cursor = connection.cursor() + try: + yield cursor + except: + connection.rollback() + raise + else: + connection.commit() + +db = DatabaseConnection() +with db_transaction(db) as cursor: + ... +\end{verbatim} + +The \module{contextlib} module also has a \function{nested(\var{mgr1}, +\var{mgr2}, ...)} function that combines a number of context managers so you +don't need to write nested '\keyword{with}' statements. In this +example, the single '\keyword{with}' statement both starts a database +transaction and acquires a thread lock: + +\begin{verbatim} +lock = threading.Lock() +with nested (db_transaction(db), lock) as (cursor, locked): + ... +\end{verbatim} + +Finally, the \function{closing(\var{object})} function +returns \var{object} so that it can be bound to a variable, +and calls \code{\var{object}.close()} at the end of the block. + +\begin{verbatim} +import urllib, sys +from contextlib import closing + +with closing(urllib.urlopen('http://www.yahoo.com')) as f: + for line in f: + sys.stdout.write(line) +\end{verbatim} + +\begin{seealso} + +\seepep{343}{The ``with'' statement}{PEP written by Guido van~Rossum +and Nick Coghlan; implemented by Mike Bland, Guido van~Rossum, and +Neal Norwitz. The PEP shows the code generated for a '\keyword{with}' +statement, which can be helpful in learning how the statement works.} + +\seeurl{../lib/module-contextlib.html}{The documentation +for the \module{contextlib} module.} + +\end{seealso} + + +%====================================================================== +\section{PEP 352: Exceptions as New-Style Classes\label{pep-352}} + +Exception classes can now be new-style classes, not just classic +classes, and the built-in \exception{Exception} class and all the +standard built-in exceptions (\exception{NameError}, +\exception{ValueError}, etc.) are now new-style classes. + +The inheritance hierarchy for exceptions has been rearranged a bit. +In 2.5, the inheritance relationships are: + +\begin{verbatim} +BaseException # New in Python 2.5 +|- KeyboardInterrupt +|- SystemExit +|- Exception + |- (all other current built-in exceptions) +\end{verbatim} + +This rearrangement was done because people often want to catch all +exceptions that indicate program errors. \exception{KeyboardInterrupt} and +\exception{SystemExit} aren't errors, though, and usually represent an explicit +action such as the user hitting Control-C or code calling +\function{sys.exit()}. A bare \code{except:} will catch all exceptions, +so you commonly need to list \exception{KeyboardInterrupt} and +\exception{SystemExit} in order to re-raise them. The usual pattern is: + +\begin{verbatim} +try: + ... +except (KeyboardInterrupt, SystemExit): + raise +except: + # Log error... + # Continue running program... +\end{verbatim} + +In Python 2.5, you can now write \code{except Exception} to achieve +the same result, catching all the exceptions that usually indicate errors +but leaving \exception{KeyboardInterrupt} and +\exception{SystemExit} alone. As in previous versions, +a bare \code{except:} still catches all exceptions. + +The goal for Python 3.0 is to require any class raised as an exception +to derive from \exception{BaseException} or some descendant of +\exception{BaseException}, and future releases in the +Python 2.x series may begin to enforce this constraint. Therefore, I +suggest you begin making all your exception classes derive from +\exception{Exception} now. It's been suggested that the bare +\code{except:} form should be removed in Python 3.0, but Guido van~Rossum +hasn't decided whether to do this or not. + +Raising of strings as exceptions, as in the statement \code{raise +"Error occurred"}, is deprecated in Python 2.5 and will trigger a +warning. The aim is to be able to remove the string-exception feature +in a few releases. + + +\begin{seealso} + +\seepep{352}{Required Superclass for Exceptions}{PEP written by +Brett Cannon and Guido van~Rossum; implemented by Brett Cannon.} + +\end{seealso} + + +%====================================================================== +\section{PEP 353: Using ssize_t as the index type\label{pep-353}} + +A wide-ranging change to Python's C API, using a new +\ctype{Py_ssize_t} type definition instead of \ctype{int}, +will permit the interpreter to handle more data on 64-bit platforms. +This change doesn't affect Python's capacity on 32-bit platforms. + +Various pieces of the Python interpreter used C's \ctype{int} type to +store sizes or counts; for example, the number of items in a list or +tuple were stored in an \ctype{int}. The C compilers for most 64-bit +platforms still define \ctype{int} as a 32-bit type, so that meant +that lists could only hold up to \code{2**31 - 1} = 2147483647 items. +(There are actually a few different programming models that 64-bit C +compilers can use -- see +\url{http://www.unix.org/version2/whatsnew/lp64_wp.html} for a +discussion -- but the most commonly available model leaves \ctype{int} +as 32 bits.) + +A limit of 2147483647 items doesn't really matter on a 32-bit platform +because you'll run out of memory before hitting the length limit. +Each list item requires space for a pointer, which is 4 bytes, plus +space for a \ctype{PyObject} representing the item. 2147483647*4 is +already more bytes than a 32-bit address space can contain. + +It's possible to address that much memory on a 64-bit platform, +however. The pointers for a list that size would only require 16~GiB +of space, so it's not unreasonable that Python programmers might +construct lists that large. Therefore, the Python interpreter had to +be changed to use some type other than \ctype{int}, and this will be a +64-bit type on 64-bit platforms. The change will cause +incompatibilities on 64-bit machines, so it was deemed worth making +the transition now, while the number of 64-bit users is still +relatively small. (In 5 or 10 years, we may \emph{all} be on 64-bit +machines, and the transition would be more painful then.) + +This change most strongly affects authors of C extension modules. +Python strings and container types such as lists and tuples +now use \ctype{Py_ssize_t} to store their size. +Functions such as \cfunction{PyList_Size()} +now return \ctype{Py_ssize_t}. Code in extension modules +may therefore need to have some variables changed to +\ctype{Py_ssize_t}. + +The \cfunction{PyArg_ParseTuple()} and \cfunction{Py_BuildValue()} functions +have a new conversion code, \samp{n}, for \ctype{Py_ssize_t}. +\cfunction{PyArg_ParseTuple()}'s \samp{s\#} and \samp{t\#} still output +\ctype{int} by default, but you can define the macro +\csimplemacro{PY_SSIZE_T_CLEAN} before including \file{Python.h} +to make them return \ctype{Py_ssize_t}. + +\pep{353} has a section on conversion guidelines that +extension authors should read to learn about supporting 64-bit +platforms. + +\begin{seealso} + +\seepep{353}{Using ssize_t as the index type}{PEP written and implemented by Martin von~L\"owis.} + +\end{seealso} + + +%====================================================================== +\section{PEP 357: The '__index__' method\label{pep-357}} + +The NumPy developers had a problem that could only be solved by adding +a new special method, \method{__index__}. When using slice notation, +as in \code{[\var{start}:\var{stop}:\var{step}]}, the values of the +\var{start}, \var{stop}, and \var{step} indexes must all be either +integers or long integers. NumPy defines a variety of specialized +integer types corresponding to unsigned and signed integers of 8, 16, +32, and 64 bits, but there was no way to signal that these types could +be used as slice indexes. + +Slicing can't just use the existing \method{__int__} method because +that method is also used to implement coercion to integers. If +slicing used \method{__int__}, floating-point numbers would also +become legal slice indexes and that's clearly an undesirable +behaviour. + +Instead, a new special method called \method{__index__} was added. It +takes no arguments and returns an integer giving the slice index to +use. For example: + +\begin{verbatim} +class C: + def __index__ (self): + return self.value +\end{verbatim} + +The return value must be either a Python integer or long integer. +The interpreter will check that the type returned is correct, and +raises a \exception{TypeError} if this requirement isn't met. + +A corresponding \member{nb_index} slot was added to the C-level +\ctype{PyNumberMethods} structure to let C extensions implement this +protocol. \cfunction{PyNumber_Index(\var{obj})} can be used in +extension code to call the \method{__index__} function and retrieve +its result. + +\begin{seealso} + +\seepep{357}{Allowing Any Object to be Used for Slicing}{PEP written +and implemented by Travis Oliphant.} + +\end{seealso} + + +%====================================================================== +\section{Other Language Changes\label{other-lang}} + +Here are all of the changes that Python 2.5 makes to the core Python +language. + +\begin{itemize} + +\item The \class{dict} type has a new hook for letting subclasses +provide a default value when a key isn't contained in the dictionary. +When a key isn't found, the dictionary's +\method{__missing__(\var{key})} +method will be called. This hook is used to implement +the new \class{defaultdict} class in the \module{collections} +module. The following example defines a dictionary +that returns zero for any missing key: + +\begin{verbatim} +class zerodict (dict): + def __missing__ (self, key): + return 0 + +d = zerodict({1:1, 2:2}) +print d[1], d[2] # Prints 1, 2 +print d[3], d[4] # Prints 0, 0 +\end{verbatim} + +\item Both 8-bit and Unicode strings have new \method{partition(sep)} +and \method{rpartition(sep)} methods that simplify a common use case. + +The \method{find(S)} method is often used to get an index which is +then used to slice the string and obtain the pieces that are before +and after the separator. +\method{partition(sep)} condenses this +pattern into a single method call that returns a 3-tuple containing +the substring before the separator, the separator itself, and the +substring after the separator. If the separator isn't found, the +first element of the tuple is the entire string and the other two +elements are empty. \method{rpartition(sep)} also returns a 3-tuple +but starts searching from the end of the string; the \samp{r} stands +for 'reverse'. + +Some examples: + +\begin{verbatim} +>>> ('http://www.python.org').partition('://') +('http', '://', 'www.python.org') +>>> ('file:/usr/share/doc/index.html').partition('://') +('file:/usr/share/doc/index.html', '', '') +>>> (u'Subject: a quick question').partition(':') +(u'Subject', u':', u' a quick question') +>>> 'www.python.org'.rpartition('.') +('www.python', '.', 'org') +>>> 'www.python.org'.rpartition(':') +('', '', 'www.python.org') +\end{verbatim} + +(Implemented by Fredrik Lundh following a suggestion by Raymond Hettinger.) + +\item The \method{startswith()} and \method{endswith()} methods +of string types now accept tuples of strings to check for. + +\begin{verbatim} +def is_image_file (filename): + return filename.endswith(('.gif', '.jpg', '.tiff')) +\end{verbatim} + +(Implemented by Georg Brandl following a suggestion by Tom Lynn.) +% RFE #1491485 + +\item The \function{min()} and \function{max()} built-in functions +gained a \code{key} keyword parameter analogous to the \code{key} +argument for \method{sort()}. This parameter supplies a function that +takes a single argument and is called for every value in the list; +\function{min()}/\function{max()} will return the element with the +smallest/largest return value from this function. +For example, to find the longest string in a list, you can do: + +\begin{verbatim} +L = ['medium', 'longest', 'short'] +# Prints 'longest' +print max(L, key=len) +# Prints 'short', because lexicographically 'short' has the largest value +print max(L) +\end{verbatim} + +(Contributed by Steven Bethard and Raymond Hettinger.) + +\item Two new built-in functions, \function{any()} and +\function{all()}, evaluate whether an iterator contains any true or +false values. \function{any()} returns \constant{True} if any value +returned by the iterator is true; otherwise it will return +\constant{False}. \function{all()} returns \constant{True} only if +all of the values returned by the iterator evaluate as true. +(Suggested by Guido van~Rossum, and implemented by Raymond Hettinger.) + +\item The result of a class's \method{__hash__()} method can now +be either a long integer or a regular integer. If a long integer is +returned, the hash of that value is taken. In earlier versions the +hash value was required to be a regular integer, but in 2.5 the +\function{id()} built-in was changed to always return non-negative +numbers, and users often seem to use \code{id(self)} in +\method{__hash__()} methods (though this is discouraged). +% Bug #1536021 + +\item ASCII is now the default encoding for modules. It's now +a syntax error if a module contains string literals with 8-bit +characters but doesn't have an encoding declaration. In Python 2.4 +this triggered a warning, not a syntax error. See \pep{263} +for how to declare a module's encoding; for example, you might add +a line like this near the top of the source file: + +\begin{verbatim} +# -*- coding: latin1 -*- +\end{verbatim} + +\item A new warning, \class{UnicodeWarning}, is triggered when +you attempt to compare a Unicode string and an 8-bit string +that can't be converted to Unicode using the default ASCII encoding. +The result of the comparison is false: + +\begin{verbatim} +>>> chr(128) == unichr(128) # Can't convert chr(128) to Unicode +__main__:1: UnicodeWarning: Unicode equal comparison failed + to convert both arguments to Unicode - interpreting them + as being unequal +False +>>> chr(127) == unichr(127) # chr(127) can be converted +True +\end{verbatim} + +Previously this would raise a \class{UnicodeDecodeError} exception, +but in 2.5 this could result in puzzling problems when accessing a +dictionary. If you looked up \code{unichr(128)} and \code{chr(128)} +was being used as a key, you'd get a \class{UnicodeDecodeError} +exception. Other changes in 2.5 resulted in this exception being +raised instead of suppressed by the code in \file{dictobject.c} that +implements dictionaries. + +Raising an exception for such a comparison is strictly correct, but +the change might have broken code, so instead +\class{UnicodeWarning} was introduced. + +(Implemented by Marc-Andr\'e Lemburg.) + +\item One error that Python programmers sometimes make is forgetting +to include an \file{__init__.py} module in a package directory. +Debugging this mistake can be confusing, and usually requires running +Python with the \programopt{-v} switch to log all the paths searched. +In Python 2.5, a new \exception{ImportWarning} warning is triggered when +an import would have picked up a directory as a package but no +\file{__init__.py} was found. This warning is silently ignored by default; +provide the \programopt{-Wd} option when running the Python executable +to display the warning message. +(Implemented by Thomas Wouters.) + +\item The list of base classes in a class definition can now be empty. +As an example, this is now legal: + +\begin{verbatim} +class C(): + pass +\end{verbatim} +(Implemented by Brett Cannon.) + +\end{itemize} + + +%====================================================================== +\subsection{Interactive Interpreter Changes\label{interactive}} + +In the interactive interpreter, \code{quit} and \code{exit} +have long been strings so that new users get a somewhat helpful message +when they try to quit: + +\begin{verbatim} +>>> quit +'Use Ctrl-D (i.e. EOF) to exit.' +\end{verbatim} + +In Python 2.5, \code{quit} and \code{exit} are now objects that still +produce string representations of themselves, but are also callable. +Newbies who try \code{quit()} or \code{exit()} will now exit the +interpreter as they expect. (Implemented by Georg Brandl.) + +The Python executable now accepts the standard long options +\longprogramopt{help} and \longprogramopt{version}; on Windows, +it also accepts the \programopt{/?} option for displaying a help message. +(Implemented by Georg Brandl.) + + +%====================================================================== +\subsection{Optimizations\label{opts}} + +Several of the optimizations were developed at the NeedForSpeed +sprint, an event held in Reykjavik, Iceland, from May 21--28 2006. +The sprint focused on speed enhancements to the CPython implementation +and was funded by EWT LLC with local support from CCP Games. Those +optimizations added at this sprint are specially marked in the +following list. + +\begin{itemize} + +\item When they were introduced +in Python 2.4, the built-in \class{set} and \class{frozenset} types +were built on top of Python's dictionary type. +In 2.5 the internal data structure has been customized for implementing sets, +and as a result sets will use a third less memory and are somewhat faster. +(Implemented by Raymond Hettinger.) + +\item The speed of some Unicode operations, such as finding +substrings, string splitting, and character map encoding and decoding, +has been improved. (Substring search and splitting improvements were +added by Fredrik Lundh and Andrew Dalke at the NeedForSpeed +sprint. Character maps were improved by Walter D\"orwald and +Martin von~L\"owis.) +% Patch 1313939, 1359618 + +\item The \function{long(\var{str}, \var{base})} function is now +faster on long digit strings because fewer intermediate results are +calculated. The peak is for strings of around 800--1000 digits where +the function is 6 times faster. +(Contributed by Alan McIntyre and committed at the NeedForSpeed sprint.) +% Patch 1442927 + +\item It's now illegal to mix iterating over a file +with \code{for line in \var{file}} and calling +the file object's \method{read()}/\method{readline()}/\method{readlines()} +methods. Iteration uses an internal buffer and the +\method{read*()} methods don't use that buffer. +Instead they would return the data following the buffer, causing the +data to appear out of order. Mixing iteration and these methods will +now trigger a \exception{ValueError} from the \method{read*()} method. +(Implemented by Thomas Wouters.) +% Patch 1397960 + +\item The \module{struct} module now compiles structure format +strings into an internal representation and caches this +representation, yielding a 20\% speedup. (Contributed by Bob Ippolito +at the NeedForSpeed sprint.) + +\item The \module{re} module got a 1 or 2\% speedup by switching to +Python's allocator functions instead of the system's +\cfunction{malloc()} and \cfunction{free()}. +(Contributed by Jack Diederich at the NeedForSpeed sprint.) + +\item The code generator's peephole optimizer now performs +simple constant folding in expressions. If you write something like +\code{a = 2+3}, the code generator will do the arithmetic and produce +code corresponding to \code{a = 5}. (Proposed and implemented +by Raymond Hettinger.) + +\item Function calls are now faster because code objects now keep +the most recently finished frame (a ``zombie frame'') in an internal +field of the code object, reusing it the next time the code object is +invoked. (Original patch by Michael Hudson, modified by Armin Rigo +and Richard Jones; committed at the NeedForSpeed sprint.) +% Patch 876206 + +Frame objects are also slightly smaller, which may improve cache locality +and reduce memory usage a bit. (Contributed by Neal Norwitz.) +% Patch 1337051 + +\item Python's built-in exceptions are now new-style classes, a change +that speeds up instantiation considerably. Exception handling in +Python 2.5 is therefore about 30\% faster than in 2.4. +(Contributed by Richard Jones, Georg Brandl and Sean Reifschneider at +the NeedForSpeed sprint.) + +\item Importing now caches the paths tried, recording whether +they exist or not so that the interpreter makes fewer +\cfunction{open()} and \cfunction{stat()} calls on startup. +(Contributed by Martin von~L\"owis and Georg Brandl.) +% Patch 921466 + +\end{itemize} + + +%====================================================================== +\section{New, Improved, and Removed Modules\label{modules}} + +The standard library received many enhancements and bug fixes in +Python 2.5. Here's a partial list of the most notable changes, sorted +alphabetically by module name. Consult the \file{Misc/NEWS} file in +the source tree for a more complete list of changes, or look through +the SVN logs for all the details. + +\begin{itemize} + +\item The \module{audioop} module now supports the a-LAW encoding, +and the code for u-LAW encoding has been improved. (Contributed by +Lars Immisch.) + +\item The \module{codecs} module gained support for incremental +codecs. The \function{codec.lookup()} function now +returns a \class{CodecInfo} instance instead of a tuple. +\class{CodecInfo} instances behave like a 4-tuple to preserve backward +compatibility but also have the attributes \member{encode}, +\member{decode}, \member{incrementalencoder}, \member{incrementaldecoder}, +\member{streamwriter}, and \member{streamreader}. Incremental codecs +can receive input and produce output in multiple chunks; the output is +the same as if the entire input was fed to the non-incremental codec. +See the \module{codecs} module documentation for details. +(Designed and implemented by Walter D\"orwald.) +% Patch 1436130 + +\item The \module{collections} module gained a new type, +\class{defaultdict}, that subclasses the standard \class{dict} +type. The new type mostly behaves like a dictionary but constructs a +default value when a key isn't present, automatically adding it to the +dictionary for the requested key value. + +The first argument to \class{defaultdict}'s constructor is a factory +function that gets called whenever a key is requested but not found. +This factory function receives no arguments, so you can use built-in +type constructors such as \function{list()} or \function{int()}. For +example, +you can make an index of words based on their initial letter like this: + +\begin{verbatim} +words = """Nel mezzo del cammin di nostra vita +mi ritrovai per una selva oscura +che la diritta via era smarrita""".lower().split() + +index = defaultdict(list) + +for w in words: + init_letter = w[0] + index[init_letter].append(w) +\end{verbatim} + +Printing \code{index} results in the following output: + +\begin{verbatim} +defaultdict(<type 'list'>, {'c': ['cammin', 'che'], 'e': ['era'], + 'd': ['del', 'di', 'diritta'], 'm': ['mezzo', 'mi'], + 'l': ['la'], 'o': ['oscura'], 'n': ['nel', 'nostra'], + 'p': ['per'], 's': ['selva', 'smarrita'], + 'r': ['ritrovai'], 'u': ['una'], 'v': ['vita', 'via']} +\end{verbatim} + +(Contributed by Guido van~Rossum.) + +\item The \class{deque} double-ended queue type supplied by the +\module{collections} module now has a \method{remove(\var{value})} +method that removes the first occurrence of \var{value} in the queue, +raising \exception{ValueError} if the value isn't found. +(Contributed by Raymond Hettinger.) + +\item New module: The \module{contextlib} module contains helper functions for use +with the new '\keyword{with}' statement. See +section~\ref{module-contextlib} for more about this module. + +\item New module: The \module{cProfile} module is a C implementation of +the existing \module{profile} module that has much lower overhead. +The module's interface is the same as \module{profile}: you run +\code{cProfile.run('main()')} to profile a function, can save profile +data to a file, etc. It's not yet known if the Hotshot profiler, +which is also written in C but doesn't match the \module{profile} +module's interface, will continue to be maintained in future versions +of Python. (Contributed by Armin Rigo.) + +Also, the \module{pstats} module for analyzing the data measured by +the profiler now supports directing the output to any file object +by supplying a \var{stream} argument to the \class{Stats} constructor. +(Contributed by Skip Montanaro.) + +\item The \module{csv} module, which parses files in +comma-separated value format, received several enhancements and a +number of bugfixes. You can now set the maximum size in bytes of a +field by calling the \method{csv.field_size_limit(\var{new_limit})} +function; omitting the \var{new_limit} argument will return the +currently-set limit. The \class{reader} class now has a +\member{line_num} attribute that counts the number of physical lines +read from the source; records can span multiple physical lines, so +\member{line_num} is not the same as the number of records read. + +The CSV parser is now stricter about multi-line quoted +fields. Previously, if a line ended within a quoted field without a +terminating newline character, a newline would be inserted into the +returned field. This behavior caused problems when reading files that +contained carriage return characters within fields, so the code was +changed to return the field without inserting newlines. As a +consequence, if newlines embedded within fields are important, the +input should be split into lines in a manner that preserves the +newline characters. + +(Contributed by Skip Montanaro and Andrew McNamara.) + +\item The \class{datetime} class in the \module{datetime} +module now has a \method{strptime(\var{string}, \var{format})} +method for parsing date strings, contributed by Josh Spoerri. +It uses the same format characters as \function{time.strptime()} and +\function{time.strftime()}: + +\begin{verbatim} +from datetime import datetime + +ts = datetime.strptime('10:13:15 2006-03-07', + '%H:%M:%S %Y-%m-%d') +\end{verbatim} + +\item The \method{SequenceMatcher.get_matching_blocks()} method +in the \module{difflib} module now guarantees to return a minimal list +of blocks describing matching subsequences. Previously, the algorithm would +occasionally break a block of matching elements into two list entries. +(Enhancement by Tim Peters.) + +\item The \module{doctest} module gained a \code{SKIP} option that +keeps an example from being executed at all. This is intended for +code snippets that are usage examples intended for the reader and +aren't actually test cases. + +An \var{encoding} parameter was added to the \function{testfile()} +function and the \class{DocFileSuite} class to specify the file's +encoding. This makes it easier to use non-ASCII characters in +tests contained within a docstring. (Contributed by Bjorn Tillenius.) +% Patch 1080727 + +\item The \module{email} package has been updated to version 4.0. +% XXX need to provide some more detail here +(Contributed by Barry Warsaw.) + +\item The \module{fileinput} module was made more flexible. +Unicode filenames are now supported, and a \var{mode} parameter that +defaults to \code{"r"} was added to the +\function{input()} function to allow opening files in binary or +universal-newline mode. Another new parameter, \var{openhook}, +lets you use a function other than \function{open()} +to open the input files. Once you're iterating over +the set of files, the \class{FileInput} object's new +\method{fileno()} returns the file descriptor for the currently opened file. +(Contributed by Georg Brandl.) + +\item In the \module{gc} module, the new \function{get_count()} function +returns a 3-tuple containing the current collection counts for the +three GC generations. This is accounting information for the garbage +collector; when these counts reach a specified threshold, a garbage +collection sweep will be made. The existing \function{gc.collect()} +function now takes an optional \var{generation} argument of 0, 1, or 2 +to specify which generation to collect. +(Contributed by Barry Warsaw.) + +\item The \function{nsmallest()} and +\function{nlargest()} functions in the \module{heapq} module +now support a \code{key} keyword parameter similar to the one +provided by the \function{min()}/\function{max()} functions +and the \method{sort()} methods. For example: + +\begin{verbatim} +>>> import heapq +>>> L = ["short", 'medium', 'longest', 'longer still'] +>>> heapq.nsmallest(2, L) # Return two lowest elements, lexicographically +['longer still', 'longest'] +>>> heapq.nsmallest(2, L, key=len) # Return two shortest elements +['short', 'medium'] +\end{verbatim} + +(Contributed by Raymond Hettinger.) + +\item The \function{itertools.islice()} function now accepts +\code{None} for the start and step arguments. This makes it more +compatible with the attributes of slice objects, so that you can now write +the following: + +\begin{verbatim} +s = slice(5) # Create slice object +itertools.islice(iterable, s.start, s.stop, s.step) +\end{verbatim} + +(Contributed by Raymond Hettinger.) + +\item The \function{format()} function in the \module{locale} module +has been modified and two new functions were added, +\function{format_string()} and \function{currency()}. + +The \function{format()} function's \var{val} parameter could +previously be a string as long as no more than one \%char specifier +appeared; now the parameter must be exactly one \%char specifier with +no surrounding text. An optional \var{monetary} parameter was also +added which, if \code{True}, will use the locale's rules for +formatting currency in placing a separator between groups of three +digits. + +To format strings with multiple \%char specifiers, use the new +\function{format_string()} function that works like \function{format()} +but also supports mixing \%char specifiers with +arbitrary text. + +A new \function{currency()} function was also added that formats a +number according to the current locale's settings. + +(Contributed by Georg Brandl.) +% Patch 1180296 + +\item The \module{mailbox} module underwent a massive rewrite to add +the capability to modify mailboxes in addition to reading them. A new +set of classes that include \class{mbox}, \class{MH}, and +\class{Maildir} are used to read mailboxes, and have an +\method{add(\var{message})} method to add messages, +\method{remove(\var{key})} to remove messages, and +\method{lock()}/\method{unlock()} to lock/unlock the mailbox. The +following example converts a maildir-format mailbox into an mbox-format one: + +\begin{verbatim} +import mailbox + +# 'factory=None' uses email.Message.Message as the class representing +# individual messages. +src = mailbox.Maildir('maildir', factory=None) +dest = mailbox.mbox('/tmp/mbox') + +for msg in src: + dest.add(msg) +\end{verbatim} + +(Contributed by Gregory K. Johnson. Funding was provided by Google's +2005 Summer of Code.) + +\item New module: the \module{msilib} module allows creating +Microsoft Installer \file{.msi} files and CAB files. Some support +for reading the \file{.msi} database is also included. +(Contributed by Martin von~L\"owis.) + +\item The \module{nis} module now supports accessing domains other +than the system default domain by supplying a \var{domain} argument to +the \function{nis.match()} and \function{nis.maps()} functions. +(Contributed by Ben Bell.) + +\item The \module{operator} module's \function{itemgetter()} +and \function{attrgetter()} functions now support multiple fields. +A call such as \code{operator.attrgetter('a', 'b')} +will return a function +that retrieves the \member{a} and \member{b} attributes. Combining +this new feature with the \method{sort()} method's \code{key} parameter +lets you easily sort lists using multiple fields. +(Contributed by Raymond Hettinger.) + +\item The \module{optparse} module was updated to version 1.5.1 of the +Optik library. The \class{OptionParser} class gained an +\member{epilog} attribute, a string that will be printed after the +help message, and a \method{destroy()} method to break reference +cycles created by the object. (Contributed by Greg Ward.) + +\item The \module{os} module underwent several changes. The +\member{stat_float_times} variable now defaults to true, meaning that +\function{os.stat()} will now return time values as floats. (This +doesn't necessarily mean that \function{os.stat()} will return times +that are precise to fractions of a second; not all systems support +such precision.) + +Constants named \member{os.SEEK_SET}, \member{os.SEEK_CUR}, and +\member{os.SEEK_END} have been added; these are the parameters to the +\function{os.lseek()} function. Two new constants for locking are +\member{os.O_SHLOCK} and \member{os.O_EXLOCK}. + +Two new functions, \function{wait3()} and \function{wait4()}, were +added. They're similar the \function{waitpid()} function which waits +for a child process to exit and returns a tuple of the process ID and +its exit status, but \function{wait3()} and \function{wait4()} return +additional information. \function{wait3()} doesn't take a process ID +as input, so it waits for any child process to exit and returns a +3-tuple of \var{process-id}, \var{exit-status}, \var{resource-usage} +as returned from the \function{resource.getrusage()} function. +\function{wait4(\var{pid})} does take a process ID. +(Contributed by Chad J. Schroeder.) + +On FreeBSD, the \function{os.stat()} function now returns +times with nanosecond resolution, and the returned object +now has \member{st_gen} and \member{st_birthtime}. +The \member{st_flags} member is also available, if the platform supports it. +(Contributed by Antti Louko and Diego Petten\`o.) +% (Patch 1180695, 1212117) + +\item The Python debugger provided by the \module{pdb} module +can now store lists of commands to execute when a breakpoint is +reached and execution stops. Once breakpoint \#1 has been created, +enter \samp{commands 1} and enter a series of commands to be executed, +finishing the list with \samp{end}. The command list can include +commands that resume execution, such as \samp{continue} or +\samp{next}. (Contributed by Gr\'egoire Dooms.) +% Patch 790710 + +\item The \module{pickle} and \module{cPickle} modules no +longer accept a return value of \code{None} from the +\method{__reduce__()} method; the method must return a tuple of +arguments instead. The ability to return \code{None} was deprecated +in Python 2.4, so this completes the removal of the feature. + +\item The \module{pkgutil} module, containing various utility +functions for finding packages, was enhanced to support PEP 302's +import hooks and now also works for packages stored in ZIP-format archives. +(Contributed by Phillip J. Eby.) + +\item The pybench benchmark suite by Marc-Andr\'e~Lemburg is now +included in the \file{Tools/pybench} directory. The pybench suite is +an improvement on the commonly used \file{pystone.py} program because +pybench provides a more detailed measurement of the interpreter's +speed. It times particular operations such as function calls, +tuple slicing, method lookups, and numeric operations, instead of +performing many different operations and reducing the result to a +single number as \file{pystone.py} does. + +\item The \module{pyexpat} module now uses version 2.0 of the Expat parser. +(Contributed by Trent Mick.) + +\item The \class{Queue} class provided by the \module{Queue} module +gained two new methods. \method{join()} blocks until all items in +the queue have been retrieved and all processing work on the items +have been completed. Worker threads call the other new method, +\method{task_done()}, to signal that processing for an item has been +completed. (Contributed by Raymond Hettinger.) + +\item The old \module{regex} and \module{regsub} modules, which have been +deprecated ever since Python 2.0, have finally been deleted. +Other deleted modules: \module{statcache}, \module{tzparse}, +\module{whrandom}. + +\item Also deleted: the \file{lib-old} directory, +which includes ancient modules such as \module{dircmp} and +\module{ni}, was removed. \file{lib-old} wasn't on the default +\code{sys.path}, so unless your programs explicitly added the directory to +\code{sys.path}, this removal shouldn't affect your code. + +\item The \module{rlcompleter} module is no longer +dependent on importing the \module{readline} module and +therefore now works on non-{\UNIX} platforms. +(Patch from Robert Kiendl.) +% Patch #1472854 + +\item The \module{SimpleXMLRPCServer} and \module{DocXMLRPCServer} +classes now have a \member{rpc_paths} attribute that constrains +XML-RPC operations to a limited set of URL paths; the default is +to allow only \code{'/'} and \code{'/RPC2'}. Setting +\member{rpc_paths} to \code{None} or an empty tuple disables +this path checking. +% Bug #1473048 + +\item The \module{socket} module now supports \constant{AF_NETLINK} +sockets on Linux, thanks to a patch from Philippe Biondi. +Netlink sockets are a Linux-specific mechanism for communications +between a user-space process and kernel code; an introductory +article about them is at \url{http://www.linuxjournal.com/article/7356}. +In Python code, netlink addresses are represented as a tuple of 2 integers, +\code{(\var{pid}, \var{group_mask})}. + +Two new methods on socket objects, \method{recv_into(\var{buffer})} and +\method{recvfrom_into(\var{buffer})}, store the received data in an object +that supports the buffer protocol instead of returning the data as a +string. This means you can put the data directly into an array or a +memory-mapped file. + +Socket objects also gained \method{getfamily()}, \method{gettype()}, +and \method{getproto()} accessor methods to retrieve the family, type, +and protocol values for the socket. + +\item New module: the \module{spwd} module provides functions for +accessing the shadow password database on systems that support +shadow passwords. + +\item The \module{struct} is now faster because it +compiles format strings into \class{Struct} objects +with \method{pack()} and \method{unpack()} methods. This is similar +to how the \module{re} module lets you create compiled regular +expression objects. You can still use the module-level +\function{pack()} and \function{unpack()} functions; they'll create +\class{Struct} objects and cache them. Or you can use +\class{Struct} instances directly: + +\begin{verbatim} +s = struct.Struct('ih3s') + +data = s.pack(1972, 187, 'abc') +year, number, name = s.unpack(data) +\end{verbatim} + +You can also pack and unpack data to and from buffer objects directly +using the \method{pack_into(\var{buffer}, \var{offset}, \var{v1}, +\var{v2}, ...)} and \method{unpack_from(\var{buffer}, \var{offset})} +methods. This lets you store data directly into an array or a +memory-mapped file. + +(\class{Struct} objects were implemented by Bob Ippolito at the +NeedForSpeed sprint. Support for buffer objects was added by Martin +Blais, also at the NeedForSpeed sprint.) + +\item The Python developers switched from CVS to Subversion during the 2.5 +development process. Information about the exact build version is +available as the \code{sys.subversion} variable, a 3-tuple of +\code{(\var{interpreter-name}, \var{branch-name}, +\var{revision-range})}. For example, at the time of writing my copy +of 2.5 was reporting \code{('CPython', 'trunk', '45313:45315')}. + +This information is also available to C extensions via the +\cfunction{Py_GetBuildInfo()} function that returns a +string of build information like this: +\code{"trunk:45355:45356M, Apr 13 2006, 07:42:19"}. +(Contributed by Barry Warsaw.) + +\item Another new function, \function{sys._current_frames()}, returns +the current stack frames for all running threads as a dictionary +mapping thread identifiers to the topmost stack frame currently active +in that thread at the time the function is called. (Contributed by +Tim Peters.) + +\item The \class{TarFile} class in the \module{tarfile} module now has +an \method{extractall()} method that extracts all members from the +archive into the current working directory. It's also possible to set +a different directory as the extraction target, and to unpack only a +subset of the archive's members. + +The compression used for a tarfile opened in stream mode can now be +autodetected using the mode \code{'r|*'}. +% patch 918101 +(Contributed by Lars Gust\"abel.) + +\item The \module{threading} module now lets you set the stack size +used when new threads are created. The +\function{stack_size(\optional{\var{size}})} function returns the +currently configured stack size, and supplying the optional \var{size} +parameter sets a new value. Not all platforms support changing the +stack size, but Windows, POSIX threading, and OS/2 all do. +(Contributed by Andrew MacIntyre.) +% Patch 1454481 + +\item The \module{unicodedata} module has been updated to use version 4.1.0 +of the Unicode character database. Version 3.2.0 is required +by some specifications, so it's still available as +\member{unicodedata.ucd_3_2_0}. + +\item New module: the \module{uuid} module generates +universally unique identifiers (UUIDs) according to \rfc{4122}. The +RFC defines several different UUID versions that are generated from a +starting string, from system properties, or purely randomly. This +module contains a \class{UUID} class and +functions named \function{uuid1()}, +\function{uuid3()}, \function{uuid4()}, and +\function{uuid5()} to generate different versions of UUID. (Version 2 UUIDs +are not specified in \rfc{4122} and are not supported by this module.) + +\begin{verbatim} +>>> import uuid +>>> # make a UUID based on the host ID and current time +>>> uuid.uuid1() +UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') + +>>> # make a UUID using an MD5 hash of a namespace UUID and a name +>>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') +UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') + +>>> # make a random UUID +>>> uuid.uuid4() +UUID('16fd2706-8baf-433b-82eb-8c7fada847da') + +>>> # make a UUID using a SHA-1 hash of a namespace UUID and a name +>>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') +UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') +\end{verbatim} + +(Contributed by Ka-Ping Yee.) + +\item The \module{weakref} module's \class{WeakKeyDictionary} and +\class{WeakValueDictionary} types gained new methods for iterating +over the weak references contained in the dictionary. +\method{iterkeyrefs()} and \method{keyrefs()} methods were +added to \class{WeakKeyDictionary}, and +\method{itervaluerefs()} and \method{valuerefs()} were added to +\class{WeakValueDictionary}. (Contributed by Fred L.~Drake, Jr.) + +\item The \module{webbrowser} module received a number of +enhancements. +It's now usable as a script with \code{python -m webbrowser}, taking a +URL as the argument; there are a number of switches +to control the behaviour (\programopt{-n} for a new browser window, +\programopt{-t} for a new tab). New module-level functions, +\function{open_new()} and \function{open_new_tab()}, were added +to support this. The module's \function{open()} function supports an +additional feature, an \var{autoraise} parameter that signals whether +to raise the open window when possible. A number of additional +browsers were added to the supported list such as Firefox, Opera, +Konqueror, and elinks. (Contributed by Oleg Broytmann and Georg +Brandl.) +% Patch #754022 + +\item The \module{xmlrpclib} module now supports returning + \class{datetime} objects for the XML-RPC date type. Supply + \code{use_datetime=True} to the \function{loads()} function + or the \class{Unmarshaller} class to enable this feature. + (Contributed by Skip Montanaro.) +% Patch 1120353 + +\item The \module{zipfile} module now supports the ZIP64 version of the +format, meaning that a .zip archive can now be larger than 4~GiB and +can contain individual files larger than 4~GiB. (Contributed by +Ronald Oussoren.) +% Patch 1446489 + +\item The \module{zlib} module's \class{Compress} and \class{Decompress} +objects now support a \method{copy()} method that makes a copy of the +object's internal state and returns a new +\class{Compress} or \class{Decompress} object. +(Contributed by Chris AtLee.) +% Patch 1435422 + +\end{itemize} + + + +%====================================================================== +\subsection{The ctypes package\label{module-ctypes}} + +The \module{ctypes} package, written by Thomas Heller, has been added +to the standard library. \module{ctypes} lets you call arbitrary functions +in shared libraries or DLLs. Long-time users may remember the \module{dl} module, which +provides functions for loading shared libraries and calling functions in them. The \module{ctypes} package is much fancier. + +To load a shared library or DLL, you must create an instance of the +\class{CDLL} class and provide the name or path of the shared library +or DLL. Once that's done, you can call arbitrary functions +by accessing them as attributes of the \class{CDLL} object. + +\begin{verbatim} +import ctypes + +libc = ctypes.CDLL('libc.so.6') +result = libc.printf("Line of output\n") +\end{verbatim} + +Type constructors for the various C types are provided: \function{c_int}, +\function{c_float}, \function{c_double}, \function{c_char_p} (equivalent to \ctype{char *}), and so forth. Unlike Python's types, the C versions are all mutable; you can assign to their \member{value} attribute +to change the wrapped value. Python integers and strings will be automatically +converted to the corresponding C types, but for other types you +must call the correct type constructor. (And I mean \emph{must}; +getting it wrong will often result in the interpreter crashing +with a segmentation fault.) + +You shouldn't use \function{c_char_p} with a Python string when the C function will be modifying the memory area, because Python strings are +supposed to be immutable; breaking this rule will cause puzzling bugs. When you need a modifiable memory area, +use \function{create_string_buffer()}: + +\begin{verbatim} +s = "this is a string" +buf = ctypes.create_string_buffer(s) +libc.strfry(buf) +\end{verbatim} + +C functions are assumed to return integers, but you can set +the \member{restype} attribute of the function object to +change this: + +\begin{verbatim} +>>> libc.atof('2.71828') +-1783957616 +>>> libc.atof.restype = ctypes.c_double +>>> libc.atof('2.71828') +2.71828 +\end{verbatim} + +\module{ctypes} also provides a wrapper for Python's C API +as the \code{ctypes.pythonapi} object. This object does \emph{not} +release the global interpreter lock before calling a function, because the lock must be held when calling into the interpreter's code. +There's a \class{py_object()} type constructor that will create a +\ctype{PyObject *} pointer. A simple usage: + +\begin{verbatim} +import ctypes + +d = {} +ctypes.pythonapi.PyObject_SetItem(ctypes.py_object(d), + ctypes.py_object("abc"), ctypes.py_object(1)) +# d is now {'abc', 1}. +\end{verbatim} + +Don't forget to use \class{py_object()}; if it's omitted you end +up with a segmentation fault. + +\module{ctypes} has been around for a while, but people still write +and distribution hand-coded extension modules because you can't rely on \module{ctypes} being present. +Perhaps developers will begin to write +Python wrappers atop a library accessed through \module{ctypes} instead +of extension modules, now that \module{ctypes} is included with core Python. + +\begin{seealso} + +\seeurl{http://starship.python.net/crew/theller/ctypes/} +{The ctypes web page, with a tutorial, reference, and FAQ.} + +\seeurl{../lib/module-ctypes.html}{The documentation +for the \module{ctypes} module.} + +\end{seealso} + + +%====================================================================== +\subsection{The ElementTree package\label{module-etree}} + +A subset of Fredrik Lundh's ElementTree library for processing XML has +been added to the standard library as \module{xml.etree}. The +available modules are +\module{ElementTree}, \module{ElementPath}, and +\module{ElementInclude} from ElementTree 1.2.6. +The \module{cElementTree} accelerator module is also included. + +The rest of this section will provide a brief overview of using +ElementTree. Full documentation for ElementTree is available at +\url{http://effbot.org/zone/element-index.htm}. + +ElementTree represents an XML document as a tree of element nodes. +The text content of the document is stored as the \member{.text} +and \member{.tail} attributes of +(This is one of the major differences between ElementTree and +the Document Object Model; in the DOM there are many different +types of node, including \class{TextNode}.) + +The most commonly used parsing function is \function{parse()}, that +takes either a string (assumed to contain a filename) or a file-like +object and returns an \class{ElementTree} instance: + +\begin{verbatim} +from xml.etree import ElementTree as ET + +tree = ET.parse('ex-1.xml') + +feed = urllib.urlopen( + 'http://planet.python.org/rss10.xml') +tree = ET.parse(feed) +\end{verbatim} + +Once you have an \class{ElementTree} instance, you +can call its \method{getroot()} method to get the root \class{Element} node. + +There's also an \function{XML()} function that takes a string literal +and returns an \class{Element} node (not an \class{ElementTree}). +This function provides a tidy way to incorporate XML fragments, +approaching the convenience of an XML literal: + +\begin{verbatim} +svg = ET.XML("""<svg width="10px" version="1.0"> + </svg>""") +svg.set('height', '320px') +svg.append(elem1) +\end{verbatim} + +Each XML element supports some dictionary-like and some list-like +access methods. Dictionary-like operations are used to access attribute +values, and list-like operations are used to access child nodes. + +\begin{tableii}{c|l}{code}{Operation}{Result} + \lineii{elem[n]}{Returns n'th child element.} + \lineii{elem[m:n]}{Returns list of m'th through n'th child elements.} + \lineii{len(elem)}{Returns number of child elements.} + \lineii{list(elem)}{Returns list of child elements.} + \lineii{elem.append(elem2)}{Adds \var{elem2} as a child.} + \lineii{elem.insert(index, elem2)}{Inserts \var{elem2} at the specified location.} + \lineii{del elem[n]}{Deletes n'th child element.} + \lineii{elem.keys()}{Returns list of attribute names.} + \lineii{elem.get(name)}{Returns value of attribute \var{name}.} + \lineii{elem.set(name, value)}{Sets new value for attribute \var{name}.} + \lineii{elem.attrib}{Retrieves the dictionary containing attributes.} + \lineii{del elem.attrib[name]}{Deletes attribute \var{name}.} +\end{tableii} + +Comments and processing instructions are also represented as +\class{Element} nodes. To check if a node is a comment or processing +instructions: + +\begin{verbatim} +if elem.tag is ET.Comment: + ... +elif elem.tag is ET.ProcessingInstruction: + ... +\end{verbatim} + +To generate XML output, you should call the +\method{ElementTree.write()} method. Like \function{parse()}, +it can take either a string or a file-like object: + +\begin{verbatim} +# Encoding is US-ASCII +tree.write('output.xml') + +# Encoding is UTF-8 +f = open('output.xml', 'w') +tree.write(f, encoding='utf-8') +\end{verbatim} + +(Caution: the default encoding used for output is ASCII. For general +XML work, where an element's name may contain arbitrary Unicode +characters, ASCII isn't a very useful encoding because it will raise +an exception if an element's name contains any characters with values +greater than 127. Therefore, it's best to specify a different +encoding such as UTF-8 that can handle any Unicode character.) + +This section is only a partial description of the ElementTree interfaces. +Please read the package's official documentation for more details. + +\begin{seealso} + +\seeurl{http://effbot.org/zone/element-index.htm} +{Official documentation for ElementTree.} + +\end{seealso} + + +%====================================================================== +\subsection{The hashlib package\label{module-hashlib}} + +A new \module{hashlib} module, written by Gregory P. Smith, +has been added to replace the +\module{md5} and \module{sha} modules. \module{hashlib} adds support +for additional secure hashes (SHA-224, SHA-256, SHA-384, and SHA-512). +When available, the module uses OpenSSL for fast platform optimized +implementations of algorithms. + +The old \module{md5} and \module{sha} modules still exist as wrappers +around hashlib to preserve backwards compatibility. The new module's +interface is very close to that of the old modules, but not identical. +The most significant difference is that the constructor functions +for creating new hashing objects are named differently. + +\begin{verbatim} +# Old versions +h = md5.md5() +h = md5.new() + +# New version +h = hashlib.md5() + +# Old versions +h = sha.sha() +h = sha.new() + +# New version +h = hashlib.sha1() + +# Hash that weren't previously available +h = hashlib.sha224() +h = hashlib.sha256() +h = hashlib.sha384() +h = hashlib.sha512() + +# Alternative form +h = hashlib.new('md5') # Provide algorithm as a string +\end{verbatim} + +Once a hash object has been created, its methods are the same as before: +\method{update(\var{string})} hashes the specified string into the +current digest state, \method{digest()} and \method{hexdigest()} +return the digest value as a binary string or a string of hex digits, +and \method{copy()} returns a new hashing object with the same digest state. + +\begin{seealso} + +\seeurl{../lib/module-hashlib.html}{The documentation +for the \module{hashlib} module.} + +\end{seealso} + + +%====================================================================== +\subsection{The sqlite3 package\label{module-sqlite}} + +The pysqlite module (\url{http://www.pysqlite.org}), a wrapper for the +SQLite embedded database, has been added to the standard library under +the package name \module{sqlite3}. + +SQLite is a C library that provides a lightweight disk-based database +that doesn't require a separate server process and allows accessing +the database using a nonstandard variant of the SQL query language. +Some applications can use SQLite for internal data storage. It's also +possible to prototype an application using SQLite and then port the +code to a larger database such as PostgreSQL or Oracle. + +pysqlite was written by Gerhard H\"aring and provides a SQL interface +compliant with the DB-API 2.0 specification described by +\pep{249}. + +If you're compiling the Python source yourself, note that the source +tree doesn't include the SQLite code, only the wrapper module. +You'll need to have the SQLite libraries and headers installed before +compiling Python, and the build process will compile the module when +the necessary headers are available. + +To use the module, you must first create a \class{Connection} object +that represents the database. Here the data will be stored in the +\file{/tmp/example} file: + +\begin{verbatim} +conn = sqlite3.connect('/tmp/example') +\end{verbatim} + +You can also supply the special name \samp{:memory:} to create +a database in RAM. + +Once you have a \class{Connection}, you can create a \class{Cursor} +object and call its \method{execute()} method to perform SQL commands: + +\begin{verbatim} +c = conn.cursor() + +# Create table +c.execute('''create table stocks +(date text, trans text, symbol text, + qty real, price real)''') + +# Insert a row of data +c.execute("""insert into stocks + values ('2006-01-05','BUY','RHAT',100,35.14)""") +\end{verbatim} + +Usually your SQL operations will need to use values from Python +variables. You shouldn't assemble your query using Python's string +operations because doing so is insecure; it makes your program +vulnerable to an SQL injection attack. + +Instead, use the DB-API's parameter substitution. Put \samp{?} as a +placeholder wherever you want to use a value, and then provide a tuple +of values as the second argument to the cursor's \method{execute()} +method. (Other database modules may use a different placeholder, +such as \samp{\%s} or \samp{:1}.) For example: + +\begin{verbatim} +# Never do this -- insecure! +symbol = 'IBM' +c.execute("... where symbol = '%s'" % symbol) + +# Do this instead +t = (symbol,) +c.execute('select * from stocks where symbol=?', t) + +# Larger example +for t in (('2006-03-28', 'BUY', 'IBM', 1000, 45.00), + ('2006-04-05', 'BUY', 'MSOFT', 1000, 72.00), + ('2006-04-06', 'SELL', 'IBM', 500, 53.00), + ): + c.execute('insert into stocks values (?,?,?,?,?)', t) +\end{verbatim} + +To retrieve data after executing a SELECT statement, you can either +treat the cursor as an iterator, call the cursor's \method{fetchone()} +method to retrieve a single matching row, +or call \method{fetchall()} to get a list of the matching rows. + +This example uses the iterator form: + +\begin{verbatim} +>>> c = conn.cursor() +>>> c.execute('select * from stocks order by price') +>>> for row in c: +... print row +... +(u'2006-01-05', u'BUY', u'RHAT', 100, 35.140000000000001) +(u'2006-03-28', u'BUY', u'IBM', 1000, 45.0) +(u'2006-04-06', u'SELL', u'IBM', 500, 53.0) +(u'2006-04-05', u'BUY', u'MSOFT', 1000, 72.0) +>>> +\end{verbatim} + +For more information about the SQL dialect supported by SQLite, see +\url{http://www.sqlite.org}. + +\begin{seealso} + +\seeurl{http://www.pysqlite.org} +{The pysqlite web page.} + +\seeurl{http://www.sqlite.org} +{The SQLite web page; the documentation describes the syntax and the +available data types for the supported SQL dialect.} + +\seeurl{../lib/module-sqlite3.html}{The documentation +for the \module{sqlite3} module.} + +\seepep{249}{Database API Specification 2.0}{PEP written by +Marc-Andr\'e Lemburg.} + +\end{seealso} + + +%====================================================================== +\subsection{The wsgiref package\label{module-wsgiref}} + +% XXX should this be in a PEP 333 section instead? + +The Web Server Gateway Interface (WSGI) v1.0 defines a standard +interface between web servers and Python web applications and is +described in \pep{333}. The \module{wsgiref} package is a reference +implementation of the WSGI specification. + +The package includes a basic HTTP server that will run a WSGI +application; this server is useful for debugging but isn't intended for +production use. Setting up a server takes only a few lines of code: + +\begin{verbatim} +from wsgiref import simple_server + +wsgi_app = ... + +host = '' +port = 8000 +httpd = simple_server.make_server(host, port, wsgi_app) +httpd.serve_forever() +\end{verbatim} + +% XXX discuss structure of WSGI applications? +% XXX provide an example using Django or some other framework? + +\begin{seealso} + +\seeurl{http://www.wsgi.org}{A central web site for WSGI-related resources.} + +\seepep{333}{Python Web Server Gateway Interface v1.0}{PEP written by +Phillip J. Eby.} + +\end{seealso} + + +% ====================================================================== +\section{Build and C API Changes\label{build-api}} + +Changes to Python's build process and to the C API include: + +\begin{itemize} + +\item The Python source tree was converted from CVS to Subversion, +in a complex migration procedure that was supervised and flawlessly +carried out by Martin von~L\"owis. The procedure was developed as +\pep{347}. + +\item Coverity, a company that markets a source code analysis tool +called Prevent, provided the results of their examination of the Python +source code. The analysis found about 60 bugs that +were quickly fixed. Many of the bugs were refcounting problems, often +occurring in error-handling code. See +\url{http://scan.coverity.com} for the statistics. + +\item The largest change to the C API came from \pep{353}, +which modifies the interpreter to use a \ctype{Py_ssize_t} type +definition instead of \ctype{int}. See the earlier +section~\ref{pep-353} for a discussion of this change. + +\item The design of the bytecode compiler has changed a great deal, +no longer generating bytecode by traversing the parse tree. Instead +the parse tree is converted to an abstract syntax tree (or AST), and it is +the abstract syntax tree that's traversed to produce the bytecode. + +It's possible for Python code to obtain AST objects by using the +\function{compile()} built-in and specifying \code{_ast.PyCF_ONLY_AST} +as the value of the +\var{flags} parameter: + +\begin{verbatim} +from _ast import PyCF_ONLY_AST +ast = compile("""a=0 +for i in range(10): + a += i +""", "<string>", 'exec', PyCF_ONLY_AST) + +assignment = ast.body[0] +for_loop = ast.body[1] +\end{verbatim} + +No official documentation has been written for the AST code yet, but +\pep{339} discusses the design. To start learning about the code, read the +definition of the various AST nodes in \file{Parser/Python.asdl}. A +Python script reads this file and generates a set of C structure +definitions in \file{Include/Python-ast.h}. The +\cfunction{PyParser_ASTFromString()} and +\cfunction{PyParser_ASTFromFile()}, defined in +\file{Include/pythonrun.h}, take Python source as input and return the +root of an AST representing the contents. This AST can then be turned +into a code object by \cfunction{PyAST_Compile()}. For more +information, read the source code, and then ask questions on +python-dev. + +% List of names taken from Jeremy's python-dev post at +% http://mail.python.org/pipermail/python-dev/2005-October/057500.html +The AST code was developed under Jeremy Hylton's management, and +implemented by (in alphabetical order) Brett Cannon, Nick Coghlan, +Grant Edwards, John Ehresman, Kurt Kaiser, Neal Norwitz, Tim Peters, +Armin Rigo, and Neil Schemenauer, plus the participants in a number of +AST sprints at conferences such as PyCon. + +\item Evan Jones's patch to obmalloc, first described in a talk +at PyCon DC 2005, was applied. Python 2.4 allocated small objects in +256K-sized arenas, but never freed arenas. With this patch, Python +will free arenas when they're empty. The net effect is that on some +platforms, when you allocate many objects, Python's memory usage may +actually drop when you delete them and the memory may be returned to +the operating system. (Implemented by Evan Jones, and reworked by Tim +Peters.) + +Note that this change means extension modules must be more careful +when allocating memory. Python's API has many different +functions for allocating memory that are grouped into families. For +example, \cfunction{PyMem_Malloc()}, \cfunction{PyMem_Realloc()}, and +\cfunction{PyMem_Free()} are one family that allocates raw memory, +while \cfunction{PyObject_Malloc()}, \cfunction{PyObject_Realloc()}, +and \cfunction{PyObject_Free()} are another family that's supposed to +be used for creating Python objects. + +Previously these different families all reduced to the platform's +\cfunction{malloc()} and \cfunction{free()} functions. This meant +it didn't matter if you got things wrong and allocated memory with the +\cfunction{PyMem} function but freed it with the \cfunction{PyObject} +function. With 2.5's changes to obmalloc, these families now do different +things and mismatches will probably result in a segfault. You should +carefully test your C extension modules with Python 2.5. + +\item The built-in set types now have an official C API. Call +\cfunction{PySet_New()} and \cfunction{PyFrozenSet_New()} to create a +new set, \cfunction{PySet_Add()} and \cfunction{PySet_Discard()} to +add and remove elements, and \cfunction{PySet_Contains} and +\cfunction{PySet_Size} to examine the set's state. +(Contributed by Raymond Hettinger.) + +\item C code can now obtain information about the exact revision +of the Python interpreter by calling the +\cfunction{Py_GetBuildInfo()} function that returns a +string of build information like this: +\code{"trunk:45355:45356M, Apr 13 2006, 07:42:19"}. +(Contributed by Barry Warsaw.) + +\item Two new macros can be used to indicate C functions that are +local to the current file so that a faster calling convention can be +used. \cfunction{Py_LOCAL(\var{type})} declares the function as +returning a value of the specified \var{type} and uses a fast-calling +qualifier. \cfunction{Py_LOCAL_INLINE(\var{type})} does the same thing +and also requests the function be inlined. If +\cfunction{PY_LOCAL_AGGRESSIVE} is defined before \file{python.h} is +included, a set of more aggressive optimizations are enabled for the +module; you should benchmark the results to find out if these +optimizations actually make the code faster. (Contributed by Fredrik +Lundh at the NeedForSpeed sprint.) + +\item \cfunction{PyErr_NewException(\var{name}, \var{base}, +\var{dict})} can now accept a tuple of base classes as its \var{base} +argument. (Contributed by Georg Brandl.) + +\item The \cfunction{PyErr_Warn()} function for issuing warnings +is now deprecated in favour of \cfunction{PyErr_WarnEx(category, +message, stacklevel)} which lets you specify the number of stack +frames separating this function and the caller. A \var{stacklevel} of +1 is the function calling \cfunction{PyErr_WarnEx()}, 2 is the +function above that, and so forth. (Added by Neal Norwitz.) + +\item The CPython interpreter is still written in C, but +the code can now be compiled with a {\Cpp} compiler without errors. +(Implemented by Anthony Baxter, Martin von~L\"owis, Skip Montanaro.) + +\item The \cfunction{PyRange_New()} function was removed. It was +never documented, never used in the core code, and had dangerously lax +error checking. In the unlikely case that your extensions were using +it, you can replace it by something like the following: +\begin{verbatim} +range = PyObject_CallFunction((PyObject*) &PyRange_Type, "lll", + start, stop, step); +\end{verbatim} + +\end{itemize} + + +%====================================================================== +\subsection{Port-Specific Changes\label{ports}} + +\begin{itemize} + +\item MacOS X (10.3 and higher): dynamic loading of modules +now uses the \cfunction{dlopen()} function instead of MacOS-specific +functions. + +\item MacOS X: a \longprogramopt{enable-universalsdk} switch was added +to the \program{configure} script that compiles the interpreter as a +universal binary able to run on both PowerPC and Intel processors. +(Contributed by Ronald Oussoren.) + +\item Windows: \file{.dll} is no longer supported as a filename extension for +extension modules. \file{.pyd} is now the only filename extension that will +be searched for. + +\end{itemize} + + +%====================================================================== +\section{Porting to Python 2.5\label{porting}} + +This section lists previously described changes that may require +changes to your code: + +\begin{itemize} + +\item ASCII is now the default encoding for modules. It's now +a syntax error if a module contains string literals with 8-bit +characters but doesn't have an encoding declaration. In Python 2.4 +this triggered a warning, not a syntax error. + +\item Previously, the \member{gi_frame} attribute of a generator +was always a frame object. Because of the \pep{342} changes +described in section~\ref{pep-342}, it's now possible +for \member{gi_frame} to be \code{None}. + +\item A new warning, \class{UnicodeWarning}, is triggered when +you attempt to compare a Unicode string and an 8-bit string that can't +be converted to Unicode using the default ASCII encoding. Previously +such comparisons would raise a \class{UnicodeDecodeError} exception. + +\item Library: the \module{csv} module is now stricter about multi-line quoted +fields. If your files contain newlines embedded within fields, the +input should be split into lines in a manner which preserves the +newline characters. + +\item Library: the \module{locale} module's +\function{format()} function's would previously +accept any string as long as no more than one \%char specifier +appeared. In Python 2.5, the argument must be exactly one \%char +specifier with no surrounding text. + +\item Library: The \module{pickle} and \module{cPickle} modules no +longer accept a return value of \code{None} from the +\method{__reduce__()} method; the method must return a tuple of +arguments instead. The modules also no longer accept the deprecated +\var{bin} keyword parameter. + +\item Library: The \module{SimpleXMLRPCServer} and \module{DocXMLRPCServer} +classes now have a \member{rpc_paths} attribute that constrains +XML-RPC operations to a limited set of URL paths; the default is +to allow only \code{'/'} and \code{'/RPC2'}. Setting +\member{rpc_paths} to \code{None} or an empty tuple disables +this path checking. + +\item C API: Many functions now use \ctype{Py_ssize_t} +instead of \ctype{int} to allow processing more data on 64-bit +machines. Extension code may need to make the same change to avoid +warnings and to support 64-bit machines. See the earlier +section~\ref{pep-353} for a discussion of this change. + +\item C API: +The obmalloc changes mean that +you must be careful to not mix usage +of the \cfunction{PyMem_*()} and \cfunction{PyObject_*()} +families of functions. Memory allocated with +one family's \cfunction{*_Malloc()} must be +freed with the corresponding family's \cfunction{*_Free()} function. + +\end{itemize} + + +%====================================================================== +\section{Acknowledgements \label{acks}} + +The author would like to thank the following people for offering +suggestions, corrections and assistance with various drafts of this +article: Georg Brandl, Nick Coghlan, Phillip J. Eby, Lars Gust\"abel, +Raymond Hettinger, Ralf W. Grosse-Kunstleve, Kent Johnson, Iain Lowe, +Martin von~L\"owis, Fredrik Lundh, Andrew McNamara, Skip Montanaro, +Gustavo Niemeyer, Paul Prescod, James Pryor, Mike Rovner, Scott +Weikart, Barry Warsaw, Thomas Wouters. + +\end{document} diff --git a/sys/src/cmd/python/Extra/dummy.c b/sys/src/cmd/python/Extra/dummy.c new file mode 100644 index 000000000..602aeaad9 --- /dev/null +++ b/sys/src/cmd/python/Extra/dummy.c @@ -0,0 +1,6 @@ +#include "Python.h" + +PyMODINIT_FUNC +initdummy(void) +{ +} diff --git a/sys/src/cmd/python/Extra/mercurial/base85.c b/sys/src/cmd/python/Extra/mercurial/base85.c new file mode 100644 index 000000000..3e6c0614c --- /dev/null +++ b/sys/src/cmd/python/Extra/mercurial/base85.c @@ -0,0 +1,155 @@ +/* + base85 codec + + Copyright 2006 Brendan Cully <brendan@kublai.com> + + This software may be used and distributed according to the terms of + the GNU General Public License, incorporated herein by reference. + + Largely based on git's implementation +*/ + +#include <Python.h> + +static const char b85chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz!#$%&()*+-;<=>?@^_`{|}~"; +static char b85dec[256]; + +static void +b85prep(void) +{ + int i; + + memset(b85dec, 0, sizeof(b85dec)); + for (i = 0; i < sizeof(b85chars); i++) + b85dec[(int)(b85chars[i])] = i + 1; +} + +static PyObject * +b85encode(PyObject *self, PyObject *args) +{ + const unsigned char *text; + PyObject *out; + char *dst; + int len, olen, i; + unsigned int acc, val, ch; + int pad = 0; + + if (!PyArg_ParseTuple(args, "s#|i", &text, &len, &pad)) + return NULL; + + if (pad) + olen = ((len + 3) / 4 * 5) - 3; + else { + olen = len % 4; + if (olen) + olen++; + olen += len / 4 * 5; + } + if (!(out = PyString_FromStringAndSize(NULL, olen + 3))) + return NULL; + + dst = PyString_AS_STRING(out); + + while (len) { + acc = 0; + for (i = 24; i >= 0; i -= 8) { + ch = *text++; + acc |= ch << i; + if (--len == 0) + break; + } + for (i = 4; i >= 0; i--) { + val = acc % 85; + acc /= 85; + dst[i] = b85chars[val]; + } + dst += 5; + } + + if (!pad) + _PyString_Resize(&out, olen); + + return out; +} + +static PyObject * +b85decode(PyObject *self, PyObject *args) +{ + PyObject *out; + const char *text; + char *dst; + int len, i, j, olen, c, cap; + unsigned int acc; + + if (!PyArg_ParseTuple(args, "s#", &text, &len)) + return NULL; + + olen = len / 5 * 4; + i = len % 5; + if (i) + olen += i - 1; + if (!(out = PyString_FromStringAndSize(NULL, olen))) + return NULL; + + dst = PyString_AS_STRING(out); + + i = 0; + while (i < len) + { + acc = 0; + cap = len - i - 1; + if (cap > 4) + cap = 4; + for (j = 0; j < cap; i++, j++) + { + c = b85dec[(int)*text++] - 1; + if (c < 0) + return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i); + acc = acc * 85 + c; + } + if (i++ < len) + { + c = b85dec[(int)*text++] - 1; + if (c < 0) + return PyErr_Format(PyExc_ValueError, "Bad base85 character at position %d", i); + /* overflow detection: 0xffffffff == "|NsC0", + * "|NsC" == 0x03030303 */ + if (acc > 0x03030303 || (acc *= 85) > 0xffffffff - c) + return PyErr_Format(PyExc_ValueError, "Bad base85 sequence at position %d", i); + acc += c; + } + + cap = olen < 4 ? olen : 4; + olen -= cap; + for (j = 0; j < 4 - cap; j++) + acc *= 85; + if (cap && cap < 4) + acc += 0xffffff >> (cap - 1) * 8; + for (j = 0; j < cap; j++) + { + acc = (acc << 8) | (acc >> 24); + *dst++ = acc; + } + } + + return out; +} + +static char base85_doc[] = "Base85 Data Encoding"; + +static PyMethodDef methods[] = { + {"b85encode", b85encode, METH_VARARGS, + "Encode text in base85.\n\n" + "If the second parameter is true, pad the result to a multiple of " + "five characters.\n"}, + {"b85decode", b85decode, METH_VARARGS, "Decode base85 text.\n"}, + {NULL, NULL} +}; + +PyMODINIT_FUNC initbase85(void) +{ + Py_InitModule3("base85", methods, base85_doc); + + b85prep(); +} diff --git a/sys/src/cmd/python/Extra/mercurial/bdiff.c b/sys/src/cmd/python/Extra/mercurial/bdiff.c new file mode 100644 index 000000000..60d3c633b --- /dev/null +++ b/sys/src/cmd/python/Extra/mercurial/bdiff.c @@ -0,0 +1,401 @@ +/* + bdiff.c - efficient binary diff extension for Mercurial + + Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> + + This software may be used and distributed according to the terms of + the GNU General Public License, incorporated herein by reference. + + Based roughly on Python difflib +*/ + +#include <Python.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#if defined __hpux || defined __SUNPRO_C || defined _AIX +# define inline +#endif + +#ifdef __linux +# define inline __inline +#endif + +#ifdef _WIN32 +#ifdef _MSC_VER +#define inline __inline +typedef unsigned long uint32_t; +#else +#include <stdint.h> +#endif +static uint32_t htonl(uint32_t x) +{ + return ((x & 0x000000ffUL) << 24) | + ((x & 0x0000ff00UL) << 8) | + ((x & 0x00ff0000UL) >> 8) | + ((x & 0xff000000UL) >> 24); +} +#else +#include <sys/types.h> +#if defined __BEOS__ && !defined __HAIKU__ +#include <ByteOrder.h> +#else +#include <arpa/inet.h> +#endif +#include <inttypes.h> +#endif + +struct line { + int h, len, n, e; + const char *l; +}; + +struct pos { + int pos, len; +}; + +struct hunk { + int a1, a2, b1, b2; +}; + +struct hunklist { + struct hunk *base, *head; +}; + +int splitlines(const char *a, int len, struct line **lr) +{ + int h, i; + const char *p, *b = a; + const char * const plast = a + len - 1; + struct line *l; + + /* count the lines */ + i = 1; /* extra line for sentinel */ + for (p = a; p < a + len; p++) + if (*p == '\n' || p == plast) + i++; + + *lr = l = (struct line *)malloc(sizeof(struct line) * i); + if (!l) + return -1; + + /* build the line array and calculate hashes */ + h = 0; + for (p = a; p < a + len; p++) { + /* Leonid Yuriev's hash */ + h = (h * 1664525) + *p + 1013904223; + + if (*p == '\n' || p == plast) { + l->h = h; + h = 0; + l->len = p - b + 1; + l->l = b; + l->n = INT_MAX; + l++; + b = p + 1; + } + } + + /* set up a sentinel */ + l->h = l->len = 0; + l->l = a + len; + return i - 1; +} + +int inline cmp(struct line *a, struct line *b) +{ + return a->h != b->h || a->len != b->len || memcmp(a->l, b->l, a->len); +} + +static int equatelines(struct line *a, int an, struct line *b, int bn) +{ + int i, j, buckets = 1, t, scale; + struct pos *h = NULL; + + /* build a hash table of the next highest power of 2 */ + while (buckets < bn + 1) + buckets *= 2; + + /* try to allocate a large hash table to avoid collisions */ + for (scale = 4; scale; scale /= 2) { + h = (struct pos *)malloc(scale * buckets * sizeof(struct pos)); + if (h) + break; + } + + if (!h) + return 0; + + buckets = buckets * scale - 1; + + /* clear the hash table */ + for (i = 0; i <= buckets; i++) { + h[i].pos = INT_MAX; + h[i].len = 0; + } + + /* add lines to the hash table chains */ + for (i = bn - 1; i >= 0; i--) { + /* find the equivalence class */ + for (j = b[i].h & buckets; h[j].pos != INT_MAX; + j = (j + 1) & buckets) + if (!cmp(b + i, b + h[j].pos)) + break; + + /* add to the head of the equivalence class */ + b[i].n = h[j].pos; + b[i].e = j; + h[j].pos = i; + h[j].len++; /* keep track of popularity */ + } + + /* compute popularity threshold */ + t = (bn >= 4000) ? bn / 1000 : bn + 1; + + /* match items in a to their equivalence class in b */ + for (i = 0; i < an; i++) { + /* find the equivalence class */ + for (j = a[i].h & buckets; h[j].pos != INT_MAX; + j = (j + 1) & buckets) + if (!cmp(a + i, b + h[j].pos)) + break; + + a[i].e = j; /* use equivalence class for quick compare */ + if (h[j].len <= t) + a[i].n = h[j].pos; /* point to head of match list */ + else + a[i].n = INT_MAX; /* too popular */ + } + + /* discard hash tables */ + free(h); + return 1; +} + +static int longest_match(struct line *a, struct line *b, struct pos *pos, + int a1, int a2, int b1, int b2, int *omi, int *omj) +{ + int mi = a1, mj = b1, mk = 0, mb = 0, i, j, k; + + for (i = a1; i < a2; i++) { + /* skip things before the current block */ + for (j = a[i].n; j < b1; j = b[j].n) + ; + + /* loop through all lines match a[i] in b */ + for (; j < b2; j = b[j].n) { + /* does this extend an earlier match? */ + if (i > a1 && j > b1 && pos[j - 1].pos == i - 1) + k = pos[j - 1].len + 1; + else + k = 1; + pos[j].pos = i; + pos[j].len = k; + + /* best match so far? */ + if (k > mk) { + mi = i; + mj = j; + mk = k; + } + } + } + + if (mk) { + mi = mi - mk + 1; + mj = mj - mk + 1; + } + + /* expand match to include neighboring popular lines */ + while (mi - mb > a1 && mj - mb > b1 && + a[mi - mb - 1].e == b[mj - mb - 1].e) + mb++; + while (mi + mk < a2 && mj + mk < b2 && + a[mi + mk].e == b[mj + mk].e) + mk++; + + *omi = mi - mb; + *omj = mj - mb; + + return mk + mb; +} + +static void recurse(struct line *a, struct line *b, struct pos *pos, + int a1, int a2, int b1, int b2, struct hunklist *l) +{ + int i, j, k; + + /* find the longest match in this chunk */ + k = longest_match(a, b, pos, a1, a2, b1, b2, &i, &j); + if (!k) + return; + + /* and recurse on the remaining chunks on either side */ + recurse(a, b, pos, a1, i, b1, j, l); + l->head->a1 = i; + l->head->a2 = i + k; + l->head->b1 = j; + l->head->b2 = j + k; + l->head++; + recurse(a, b, pos, i + k, a2, j + k, b2, l); +} + +static struct hunklist diff(struct line *a, int an, struct line *b, int bn) +{ + struct hunklist l; + struct hunk *curr; + struct pos *pos; + int t; + + /* allocate and fill arrays */ + t = equatelines(a, an, b, bn); + pos = (struct pos *)calloc(bn ? bn : 1, sizeof(struct pos)); + /* we can't have more matches than lines in the shorter file */ + l.head = l.base = (struct hunk *)malloc(sizeof(struct hunk) * + ((an<bn ? an:bn) + 1)); + + if (pos && l.base && t) { + /* generate the matching block list */ + recurse(a, b, pos, 0, an, 0, bn, &l); + l.head->a1 = l.head->a2 = an; + l.head->b1 = l.head->b2 = bn; + l.head++; + } + + free(pos); + + /* normalize the hunk list, try to push each hunk towards the end */ + for (curr = l.base; curr != l.head; curr++) { + struct hunk *next = curr+1; + int shift = 0; + + if (next == l.head) + break; + + if (curr->a2 == next->a1) + while (curr->a2+shift < an && curr->b2+shift < bn + && !cmp(a+curr->a2+shift, b+curr->b2+shift)) + shift++; + else if (curr->b2 == next->b1) + while (curr->b2+shift < bn && curr->a2+shift < an + && !cmp(b+curr->b2+shift, a+curr->a2+shift)) + shift++; + if (!shift) + continue; + curr->b2 += shift; + next->b1 += shift; + curr->a2 += shift; + next->a1 += shift; + } + + return l; +} + +static PyObject *blocks(PyObject *self, PyObject *args) +{ + PyObject *sa, *sb, *rl = NULL, *m; + struct line *a, *b; + struct hunklist l = {NULL, NULL}; + struct hunk *h; + int an, bn, pos = 0; + + if (!PyArg_ParseTuple(args, "SS:bdiff", &sa, &sb)) + return NULL; + + an = splitlines(PyString_AsString(sa), PyString_Size(sa), &a); + bn = splitlines(PyString_AsString(sb), PyString_Size(sb), &b); + if (!a || !b) + goto nomem; + + l = diff(a, an, b, bn); + rl = PyList_New(l.head - l.base); + if (!l.head || !rl) + goto nomem; + + for (h = l.base; h != l.head; h++) { + m = Py_BuildValue("iiii", h->a1, h->a2, h->b1, h->b2); + PyList_SetItem(rl, pos, m); + pos++; + } + +nomem: + free(a); + free(b); + free(l.base); + return rl ? rl : PyErr_NoMemory(); +} + +static PyObject *bdiff(PyObject *self, PyObject *args) +{ + char *sa, *sb; + PyObject *result = NULL; + struct line *al, *bl; + struct hunklist l = {NULL, NULL}; + struct hunk *h; + char encode[12], *rb; + int an, bn, len = 0, la, lb; + + if (!PyArg_ParseTuple(args, "s#s#:bdiff", &sa, &la, &sb, &lb)) + return NULL; + + an = splitlines(sa, la, &al); + bn = splitlines(sb, lb, &bl); + if (!al || !bl) + goto nomem; + + l = diff(al, an, bl, bn); + if (!l.head) + goto nomem; + + /* calculate length of output */ + la = lb = 0; + for (h = l.base; h != l.head; h++) { + if (h->a1 != la || h->b1 != lb) + len += 12 + bl[h->b1].l - bl[lb].l; + la = h->a2; + lb = h->b2; + } + + result = PyString_FromStringAndSize(NULL, len); + if (!result) + goto nomem; + + /* build binary patch */ + rb = PyString_AsString(result); + la = lb = 0; + + for (h = l.base; h != l.head; h++) { + if (h->a1 != la || h->b1 != lb) { + len = bl[h->b1].l - bl[lb].l; + *(uint32_t *)(encode) = htonl(al[la].l - al->l); + *(uint32_t *)(encode + 4) = htonl(al[h->a1].l - al->l); + *(uint32_t *)(encode + 8) = htonl(len); + memcpy(rb, encode, 12); + memcpy(rb + 12, bl[lb].l, len); + rb += 12 + len; + } + la = h->a2; + lb = h->b2; + } + +nomem: + free(al); + free(bl); + free(l.base); + return result ? result : PyErr_NoMemory(); +} + +static char mdiff_doc[] = "Efficient binary diff."; + +static PyMethodDef methods[] = { + {"bdiff", bdiff, METH_VARARGS, "calculate a binary diff\n"}, + {"blocks", blocks, METH_VARARGS, "find a list of matching lines\n"}, + {NULL, NULL} +}; + +PyMODINIT_FUNC initbdiff(void) +{ + Py_InitModule3("bdiff", methods, mdiff_doc); +} + diff --git a/sys/src/cmd/python/Extra/mercurial/diffhelpers.c b/sys/src/cmd/python/Extra/mercurial/diffhelpers.c new file mode 100644 index 000000000..d9316ea4b --- /dev/null +++ b/sys/src/cmd/python/Extra/mercurial/diffhelpers.c @@ -0,0 +1,156 @@ +/* + * diffhelpers.c - helper routines for mpatch + * + * Copyright 2007 Chris Mason <chris.mason@oracle.com> + * + * This software may be used and distributed according to the terms + * of the GNU General Public License v2, incorporated herein by reference. + */ + +#include <Python.h> +#include <stdlib.h> +#include <string.h> + +static char diffhelpers_doc[] = "Efficient diff parsing"; +static PyObject *diffhelpers_Error; + + +/* fixup the last lines of a and b when the patch has no newline at eof */ +static void _fix_newline(PyObject *hunk, PyObject *a, PyObject *b) +{ + int hunksz = PyList_Size(hunk); + PyObject *s = PyList_GET_ITEM(hunk, hunksz-1); + char *l = PyString_AS_STRING(s); + int sz = PyString_GET_SIZE(s); + int alen = PyList_Size(a); + int blen = PyList_Size(b); + char c = l[0]; + + PyObject *hline = PyString_FromStringAndSize(l, sz-1); + if (c == ' ' || c == '+') { + PyObject *rline = PyString_FromStringAndSize(l+1, sz-2); + PyList_SetItem(b, blen-1, rline); + } + if (c == ' ' || c == '-') { + Py_INCREF(hline); + PyList_SetItem(a, alen-1, hline); + } + PyList_SetItem(hunk, hunksz-1, hline); +} + +/* python callable form of _fix_newline */ +static PyObject * +fix_newline(PyObject *self, PyObject *args) +{ + PyObject *hunk, *a, *b; + if (!PyArg_ParseTuple(args, "OOO", &hunk, &a, &b)) + return NULL; + _fix_newline(hunk, a, b); + return Py_BuildValue("l", 0); +} + +/* + * read lines from fp into the hunk. The hunk is parsed into two arrays + * a and b. a gets the old state of the text, b gets the new state + * The control char from the hunk is saved when inserting into a, but not b + * (for performance while deleting files) + */ +static PyObject * +addlines(PyObject *self, PyObject *args) +{ + + PyObject *fp, *hunk, *a, *b, *x; + int i; + int lena, lenb; + int num; + int todoa, todob; + char *s, c; + PyObject *l; + if (!PyArg_ParseTuple(args, "OOiiOO", &fp, &hunk, &lena, &lenb, &a, &b)) + return NULL; + + while(1) { + todoa = lena - PyList_Size(a); + todob = lenb - PyList_Size(b); + num = todoa > todob ? todoa : todob; + if (num == 0) + break; + for (i = 0 ; i < num ; i++) { + x = PyFile_GetLine(fp, 0); + s = PyString_AS_STRING(x); + c = *s; + if (strcmp(s, "\\ No newline at end of file\n") == 0) { + _fix_newline(hunk, a, b); + continue; + } + if (c == '\n') { + /* Some patches may be missing the control char + * on empty lines. Supply a leading space. */ + Py_DECREF(x); + x = PyString_FromString(" \n"); + } + PyList_Append(hunk, x); + if (c == '+') { + l = PyString_FromString(s + 1); + PyList_Append(b, l); + Py_DECREF(l); + } else if (c == '-') { + PyList_Append(a, x); + } else { + l = PyString_FromString(s + 1); + PyList_Append(b, l); + Py_DECREF(l); + PyList_Append(a, x); + } + Py_DECREF(x); + } + } + return Py_BuildValue("l", 0); +} + +/* + * compare the lines in a with the lines in b. a is assumed to have + * a control char at the start of each line, this char is ignored in the + * compare + */ +static PyObject * +testhunk(PyObject *self, PyObject *args) +{ + + PyObject *a, *b; + long bstart; + int alen, blen; + int i; + char *sa, *sb; + + if (!PyArg_ParseTuple(args, "OOl", &a, &b, &bstart)) + return NULL; + alen = PyList_Size(a); + blen = PyList_Size(b); + if (alen > blen - bstart) { + return Py_BuildValue("l", -1); + } + for (i = 0 ; i < alen ; i++) { + sa = PyString_AS_STRING(PyList_GET_ITEM(a, i)); + sb = PyString_AS_STRING(PyList_GET_ITEM(b, i + bstart)); + if (strcmp(sa+1, sb) != 0) + return Py_BuildValue("l", -1); + } + return Py_BuildValue("l", 0); +} + +static PyMethodDef methods[] = { + {"addlines", addlines, METH_VARARGS, "add lines to a hunk\n"}, + {"fix_newline", fix_newline, METH_VARARGS, "fixup newline counters\n"}, + {"testhunk", testhunk, METH_VARARGS, "test lines in a hunk\n"}, + {NULL, NULL} +}; + +PyMODINIT_FUNC +initdiffhelpers(void) +{ + Py_InitModule3("diffhelpers", methods, diffhelpers_doc); + diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError", + NULL, NULL); +} + diff --git a/sys/src/cmd/python/Extra/mercurial/mpatch.c b/sys/src/cmd/python/Extra/mercurial/mpatch.c new file mode 100644 index 000000000..d9ceefcae --- /dev/null +++ b/sys/src/cmd/python/Extra/mercurial/mpatch.c @@ -0,0 +1,444 @@ +/* + mpatch.c - efficient binary patching for Mercurial + + This implements a patch algorithm that's O(m + nlog n) where m is the + size of the output and n is the number of patches. + + Given a list of binary patches, it unpacks each into a hunk list, + then combines the hunk lists with a treewise recursion to form a + single hunk list. This hunk list is then applied to the original + text. + + The text (or binary) fragments are copied directly from their source + Python objects into a preallocated output string to avoid the + allocation of intermediate Python objects. Working memory is about 2x + the total number of hunks. + + Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. +*/ + +#include <Python.h> +#include <stdlib.h> +#include <string.h> + +/* Definitions to get compatibility with python 2.4 and earlier which + does not have Py_ssize_t. See also PEP 353. + Note: msvc (8 or earlier) does not have ssize_t, so we use Py_ssize_t. +*/ +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + +#ifdef _WIN32 +# ifdef _MSC_VER +/* msvc 6.0 has problems */ +# define inline __inline +typedef unsigned long uint32_t; +# else +# include <stdint.h> +# endif +static uint32_t ntohl(uint32_t x) +{ + return ((x & 0x000000ffUL) << 24) | + ((x & 0x0000ff00UL) << 8) | + ((x & 0x00ff0000UL) >> 8) | + ((x & 0xff000000UL) >> 24); +} +#else +/* not windows */ +# include <sys/types.h> +# if defined __BEOS__ && !defined __HAIKU__ +# include <ByteOrder.h> +# else +# include <arpa/inet.h> +# endif +# include <inttypes.h> +#endif + +static char mpatch_doc[] = "Efficient binary patching."; +static PyObject *mpatch_Error; + +struct frag { + int start, end, len; + const char *data; +}; + +struct flist { + struct frag *base, *head, *tail; +}; + +static struct flist *lalloc(int size) +{ + struct flist *a = NULL; + + if (size < 1) + size = 1; + + a = (struct flist *)malloc(sizeof(struct flist)); + if (a) { + a->base = (struct frag *)malloc(sizeof(struct frag) * size); + if (a->base) { + a->head = a->tail = a->base; + return a; + } + free(a); + a = NULL; + } + if (!PyErr_Occurred()) + PyErr_NoMemory(); + return NULL; +} + +static void lfree(struct flist *a) +{ + if (a) { + free(a->base); + free(a); + } +} + +static int lsize(struct flist *a) +{ + return a->tail - a->head; +} + +/* move hunks in source that are less cut to dest, compensating + for changes in offset. the last hunk may be split if necessary. +*/ +static int gather(struct flist *dest, struct flist *src, int cut, int offset) +{ + struct frag *d = dest->tail, *s = src->head; + int postend, c, l; + + while (s != src->tail) { + if (s->start + offset >= cut) + break; /* we've gone far enough */ + + postend = offset + s->start + s->len; + if (postend <= cut) { + /* save this hunk */ + offset += s->start + s->len - s->end; + *d++ = *s++; + } + else { + /* break up this hunk */ + c = cut - offset; + if (s->end < c) + c = s->end; + l = cut - offset - s->start; + if (s->len < l) + l = s->len; + + offset += s->start + l - c; + + d->start = s->start; + d->end = c; + d->len = l; + d->data = s->data; + d++; + s->start = c; + s->len = s->len - l; + s->data = s->data + l; + + break; + } + } + + dest->tail = d; + src->head = s; + return offset; +} + +/* like gather, but with no output list */ +static int discard(struct flist *src, int cut, int offset) +{ + struct frag *s = src->head; + int postend, c, l; + + while (s != src->tail) { + if (s->start + offset >= cut) + break; + + postend = offset + s->start + s->len; + if (postend <= cut) { + offset += s->start + s->len - s->end; + s++; + } + else { + c = cut - offset; + if (s->end < c) + c = s->end; + l = cut - offset - s->start; + if (s->len < l) + l = s->len; + + offset += s->start + l - c; + s->start = c; + s->len = s->len - l; + s->data = s->data + l; + + break; + } + } + + src->head = s; + return offset; +} + +/* combine hunk lists a and b, while adjusting b for offset changes in a/ + this deletes a and b and returns the resultant list. */ +static struct flist *combine(struct flist *a, struct flist *b) +{ + struct flist *c = NULL; + struct frag *bh, *ct; + int offset = 0, post; + + if (a && b) + c = lalloc((lsize(a) + lsize(b)) * 2); + + if (c) { + + for (bh = b->head; bh != b->tail; bh++) { + /* save old hunks */ + offset = gather(c, a, bh->start, offset); + + /* discard replaced hunks */ + post = discard(a, bh->end, offset); + + /* insert new hunk */ + ct = c->tail; + ct->start = bh->start - offset; + ct->end = bh->end - post; + ct->len = bh->len; + ct->data = bh->data; + c->tail++; + offset = post; + } + + /* hold on to tail from a */ + memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a)); + c->tail += lsize(a); + } + + lfree(a); + lfree(b); + return c; +} + +/* decode a binary patch into a hunk list */ +static struct flist *decode(const char *bin, int len) +{ + struct flist *l; + struct frag *lt; + const char *data = bin + 12, *end = bin + len; + char decode[12]; /* for dealing with alignment issues */ + + /* assume worst case size, we won't have many of these lists */ + l = lalloc(len / 12); + if (!l) + return NULL; + + lt = l->tail; + + while (data <= end) { + memcpy(decode, bin, 12); + lt->start = ntohl(*(uint32_t *)decode); + lt->end = ntohl(*(uint32_t *)(decode + 4)); + lt->len = ntohl(*(uint32_t *)(decode + 8)); + if (lt->start > lt->end) + break; /* sanity check */ + bin = data + lt->len; + if (bin < data) + break; /* big data + big (bogus) len can wrap around */ + lt->data = data; + data = bin + 12; + lt++; + } + + if (bin != end) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, "patch cannot be decoded"); + lfree(l); + return NULL; + } + + l->tail = lt; + return l; +} + +/* calculate the size of resultant text */ +static int calcsize(int len, struct flist *l) +{ + int outlen = 0, last = 0; + struct frag *f = l->head; + + while (f != l->tail) { + if (f->start < last || f->end > len) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, + "invalid patch"); + return -1; + } + outlen += f->start - last; + last = f->end; + outlen += f->len; + f++; + } + + outlen += len - last; + return outlen; +} + +static int apply(char *buf, const char *orig, int len, struct flist *l) +{ + struct frag *f = l->head; + int last = 0; + char *p = buf; + + while (f != l->tail) { + if (f->start < last || f->end > len) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, + "invalid patch"); + return 0; + } + memcpy(p, orig + last, f->start - last); + p += f->start - last; + memcpy(p, f->data, f->len); + last = f->end; + p += f->len; + f++; + } + memcpy(p, orig + last, len - last); + return 1; +} + +/* recursively generate a patch of all bins between start and end */ +static struct flist *fold(PyObject *bins, int start, int end) +{ + int len; + Py_ssize_t blen; + const char *buffer; + + if (start + 1 == end) { + /* trivial case, output a decoded list */ + PyObject *tmp = PyList_GetItem(bins, start); + if (!tmp) + return NULL; + if (PyObject_AsCharBuffer(tmp, &buffer, &blen)) + return NULL; + return decode(buffer, blen); + } + + /* divide and conquer, memory management is elsewhere */ + len = (end - start) / 2; + return combine(fold(bins, start, start + len), + fold(bins, start + len, end)); +} + +static PyObject * +patches(PyObject *self, PyObject *args) +{ + PyObject *text, *bins, *result; + struct flist *patch; + const char *in; + char *out; + int len, outlen; + Py_ssize_t inlen; + + if (!PyArg_ParseTuple(args, "OO:mpatch", &text, &bins)) + return NULL; + + len = PyList_Size(bins); + if (!len) { + /* nothing to do */ + Py_INCREF(text); + return text; + } + + if (PyObject_AsCharBuffer(text, &in, &inlen)) + return NULL; + + patch = fold(bins, 0, len); + if (!patch) + return NULL; + + outlen = calcsize(inlen, patch); + if (outlen < 0) { + result = NULL; + goto cleanup; + } + result = PyString_FromStringAndSize(NULL, outlen); + if (!result) { + result = NULL; + goto cleanup; + } + out = PyString_AsString(result); + if (!apply(out, in, inlen, patch)) { + Py_DECREF(result); + result = NULL; + } +cleanup: + lfree(patch); + return result; +} + +/* calculate size of a patched file directly */ +static PyObject * +patchedsize(PyObject *self, PyObject *args) +{ + long orig, start, end, len, outlen = 0, last = 0; + int patchlen; + char *bin, *binend, *data; + char decode[12]; /* for dealing with alignment issues */ + + if (!PyArg_ParseTuple(args, "ls#", &orig, &bin, &patchlen)) + return NULL; + + binend = bin + patchlen; + data = bin + 12; + + while (data <= binend) { + memcpy(decode, bin, 12); + start = ntohl(*(uint32_t *)decode); + end = ntohl(*(uint32_t *)(decode + 4)); + len = ntohl(*(uint32_t *)(decode + 8)); + if (start > end) + break; /* sanity check */ + bin = data + len; + if (bin < data) + break; /* big data + big (bogus) len can wrap around */ + data = bin + 12; + outlen += start - last; + last = end; + outlen += len; + } + + if (bin != binend) { + if (!PyErr_Occurred()) + PyErr_SetString(mpatch_Error, "patch cannot be decoded"); + return NULL; + } + + outlen += orig - last; + return Py_BuildValue("l", outlen); +} + +static PyMethodDef methods[] = { + {"patches", patches, METH_VARARGS, "apply a series of patches\n"}, + {"patchedsize", patchedsize, METH_VARARGS, "calculed patched size\n"}, + {NULL, NULL} +}; + +PyMODINIT_FUNC +initmpatch(void) +{ + Py_InitModule3("mpatch", methods, mpatch_doc); + mpatch_Error = PyErr_NewException("mpatch.mpatchError", NULL, NULL); +} + diff --git a/sys/src/cmd/python/Extra/mercurial/osutil.c b/sys/src/cmd/python/Extra/mercurial/osutil.c new file mode 100644 index 000000000..a9874d0c9 --- /dev/null +++ b/sys/src/cmd/python/Extra/mercurial/osutil.c @@ -0,0 +1,534 @@ +/* + osutil.c - native operating system services + + Copyright 2007 Matt Mackall and others + + This software may be used and distributed according to the terms of + the GNU General Public License, incorporated herein by reference. +*/ + +#define _ATFILE_SOURCE +#include <Python.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> + +#ifdef _WIN32 +# include <windows.h> +# include <io.h> +#else +# include <dirent.h> +# include <sys/stat.h> +# include <sys/types.h> +# include <unistd.h> +#endif + +// some platforms lack the PATH_MAX definition (eg. GNU/Hurd) +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#ifdef _WIN32 +/* +stat struct compatible with hg expectations +Mercurial only uses st_mode, st_size and st_mtime +the rest is kept to minimize changes between implementations +*/ +struct hg_stat { + int st_dev; + int st_mode; + int st_nlink; + __int64 st_size; + int st_mtime; + int st_ctime; +}; +struct listdir_stat { + PyObject_HEAD + struct hg_stat st; +}; +#else +struct listdir_stat { + PyObject_HEAD + struct stat st; +}; +#endif + +#define listdir_slot(name) \ + static PyObject *listdir_stat_##name(PyObject *self, void *x) \ + { \ + return PyInt_FromLong(((struct listdir_stat *)self)->st.name); \ + } + +listdir_slot(st_dev) +listdir_slot(st_mode) +listdir_slot(st_nlink) +#ifdef _WIN32 +static PyObject *listdir_stat_st_size(PyObject *self, void *x) +{ + return PyLong_FromLongLong( + (PY_LONG_LONG)((struct listdir_stat *)self)->st.st_size); +} +#else +listdir_slot(st_size) +#endif +listdir_slot(st_mtime) +listdir_slot(st_ctime) + +static struct PyGetSetDef listdir_stat_getsets[] = { + {"st_dev", listdir_stat_st_dev, 0, 0, 0}, + {"st_mode", listdir_stat_st_mode, 0, 0, 0}, + {"st_nlink", listdir_stat_st_nlink, 0, 0, 0}, + {"st_size", listdir_stat_st_size, 0, 0, 0}, + {"st_mtime", listdir_stat_st_mtime, 0, 0, 0}, + {"st_ctime", listdir_stat_st_ctime, 0, 0, 0}, + {0, 0, 0, 0, 0} +}; + +static PyObject *listdir_stat_new(PyTypeObject *t, PyObject *a, PyObject *k) +{ + return t->tp_alloc(t, 0); +} + +static void listdir_stat_dealloc(PyObject *o) +{ + o->ob_type->tp_free(o); +} + +static PyTypeObject listdir_stat_type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "osutil.stat", /*tp_name*/ + sizeof(struct listdir_stat), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)listdir_stat_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + "stat objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + listdir_stat_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + listdir_stat_new, /* tp_new */ +}; + +#ifdef _WIN32 + +static int to_python_time(const FILETIME *tm) +{ + /* number of seconds between epoch and January 1 1601 */ + const __int64 a0 = (__int64)134774L * (__int64)24L * (__int64)3600L; + /* conversion factor from 100ns to 1s */ + const __int64 a1 = 10000000; + /* explicit (int) cast to suspend compiler warnings */ + return (int)((((__int64)tm->dwHighDateTime << 32) + + tm->dwLowDateTime) / a1 - a0); +} + +static PyObject *make_item(const WIN32_FIND_DATAA *fd, int wantstat) +{ + PyObject *py_st; + struct hg_stat *stp; + + int kind = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? _S_IFDIR : _S_IFREG; + + if (!wantstat) + return Py_BuildValue("si", fd->cFileName, kind); + + py_st = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL); + if (!py_st) + return NULL; + + stp = &((struct listdir_stat *)py_st)->st; + /* + use kind as st_mode + rwx bits on Win32 are meaningless + and Hg does not use them anyway + */ + stp->st_mode = kind; + stp->st_mtime = to_python_time(&fd->ftLastWriteTime); + stp->st_ctime = to_python_time(&fd->ftCreationTime); + if (kind == _S_IFREG) + stp->st_size = ((__int64)fd->nFileSizeHigh << 32) + + fd->nFileSizeLow; + return Py_BuildValue("siN", fd->cFileName, + kind, py_st); +} + +static PyObject *_listdir(char *path, int plen, int wantstat, char *skip) +{ + PyObject *rval = NULL; /* initialize - return value */ + PyObject *list; + HANDLE fh; + WIN32_FIND_DATAA fd; + char *pattern; + + /* build the path + \* pattern string */ + pattern = malloc(plen+3); /* path + \* + \0 */ + if (!pattern) { + PyErr_NoMemory(); + goto error_nomem; + } + strcpy(pattern, path); + + if (plen > 0) { + char c = path[plen-1]; + if (c != ':' && c != '/' && c != '\\') + pattern[plen++] = '\\'; + } + strcpy(pattern + plen, "*"); + + fh = FindFirstFileA(pattern, &fd); + if (fh == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErrWithFilename(GetLastError(), path); + goto error_file; + } + + list = PyList_New(0); + if (!list) + goto error_list; + + do { + PyObject *item; + + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if (!strcmp(fd.cFileName, ".") + || !strcmp(fd.cFileName, "..")) + continue; + + if (skip && !strcmp(fd.cFileName, skip)) { + rval = PyList_New(0); + goto error; + } + } + + item = make_item(&fd, wantstat); + if (!item) + goto error; + + if (PyList_Append(list, item)) { + Py_XDECREF(item); + goto error; + } + + Py_XDECREF(item); + } while (FindNextFileA(fh, &fd)); + + if (GetLastError() != ERROR_NO_MORE_FILES) { + PyErr_SetFromWindowsErrWithFilename(GetLastError(), path); + goto error; + } + + rval = list; + Py_XINCREF(rval); +error: + Py_XDECREF(list); +error_list: + FindClose(fh); +error_file: + free(pattern); +error_nomem: + return rval; +} + +#else + +int entkind(struct dirent *ent) +{ +#ifdef DT_REG + switch (ent->d_type) { + case DT_REG: return S_IFREG; + case DT_DIR: return S_IFDIR; + case DT_LNK: return S_IFLNK; + case DT_BLK: return S_IFBLK; + case DT_CHR: return S_IFCHR; + case DT_FIFO: return S_IFIFO; + case DT_SOCK: return S_IFSOCK; + } +#endif + return -1; +} + +static PyObject *_listdir(char *path, int pathlen, int keepstat, char *skip) +{ + PyObject *list, *elem, *stat, *ret = NULL; + char fullpath[PATH_MAX + 10]; + int kind, err; + struct stat st; + struct dirent *ent; + DIR *dir; +#ifdef AT_SYMLINK_NOFOLLOW + int dfd = -1; +#endif + + if (pathlen >= PATH_MAX) { + PyErr_SetString(PyExc_ValueError, "path too long"); + goto error_value; + } + strncpy(fullpath, path, PATH_MAX); + fullpath[pathlen] = '/'; + +#ifdef AT_SYMLINK_NOFOLLOW + dfd = open(path, O_RDONLY); + if (dfd == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); + goto error_value; + } + dir = fdopendir(dfd); +#else + dir = opendir(path); +#endif + if (!dir) { + PyErr_SetFromErrnoWithFilename(PyExc_OSError, path); + goto error_dir; + } + + list = PyList_New(0); + if (!list) + goto error_list; + + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) + continue; + + kind = entkind(ent); + if (kind == -1 || keepstat) { +#ifdef AT_SYMLINK_NOFOLLOW + err = fstatat(dfd, ent->d_name, &st, + AT_SYMLINK_NOFOLLOW); +#else + strncpy(fullpath + pathlen + 1, ent->d_name, + PATH_MAX - pathlen); + fullpath[PATH_MAX] = 0; + err = lstat(fullpath, &st); +#endif + if (err == -1) { + strncpy(fullpath + pathlen + 1, ent->d_name, + PATH_MAX - pathlen); + fullpath[PATH_MAX] = 0; + PyErr_SetFromErrnoWithFilename(PyExc_OSError, + fullpath); + goto error; + } + kind = st.st_mode & S_IFMT; + } + + /* quit early? */ + if (skip && kind == S_IFDIR && !strcmp(ent->d_name, skip)) { + ret = PyList_New(0); + goto error; + } + + if (keepstat) { + stat = PyObject_CallObject((PyObject *)&listdir_stat_type, NULL); + if (!stat) + goto error; + memcpy(&((struct listdir_stat *)stat)->st, &st, sizeof(st)); + elem = Py_BuildValue("siN", ent->d_name, kind, stat); + } else + elem = Py_BuildValue("si", ent->d_name, kind); + if (!elem) + goto error; + + PyList_Append(list, elem); + Py_DECREF(elem); + } + + ret = list; + Py_INCREF(ret); + +error: + Py_DECREF(list); +error_list: + closedir(dir); +error_dir: +#ifdef AT_SYMLINK_NOFOLLOW + close(dfd); +#endif +error_value: + return ret; +} + +#endif /* ndef _WIN32 */ + +static PyObject *listdir(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *statobj = NULL; /* initialize - optional arg */ + PyObject *skipobj = NULL; /* initialize - optional arg */ + char *path, *skip = NULL; + int wantstat, plen; + + static char *kwlist[] = {"path", "stat", "skip", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|OO:listdir", + kwlist, &path, &plen, &statobj, &skipobj)) + return NULL; + + wantstat = statobj && PyObject_IsTrue(statobj); + + if (skipobj && skipobj != Py_None) { + skip = PyString_AsString(skipobj); + if (!skip) + return NULL; + } + + return _listdir(path, plen, wantstat, skip); +} + +#ifdef _WIN32 +static PyObject *posixfile(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"name", "mode", "buffering", NULL}; + PyObject *file_obj = NULL; + char *name = NULL; + char *mode = "rb"; + DWORD access = 0; + DWORD creation; + HANDLE handle; + int fd, flags = 0; + int bufsize = -1; + char m0, m1, m2; + char fpmode[4]; + int fppos = 0; + int plus; + FILE *fp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:posixfile", kwlist, + Py_FileSystemDefaultEncoding, + &name, &mode, &bufsize)) + return NULL; + + m0 = mode[0]; + m1 = m0 ? mode[1] : '\0'; + m2 = m1 ? mode[2] : '\0'; + plus = m1 == '+' || m2 == '+'; + + fpmode[fppos++] = m0; + if (m1 == 'b' || m2 == 'b') { + flags = _O_BINARY; + fpmode[fppos++] = 'b'; + } + else + flags = _O_TEXT; + if (plus) { + flags |= _O_RDWR; + access = GENERIC_READ | GENERIC_WRITE; + fpmode[fppos++] = '+'; + } + fpmode[fppos++] = '\0'; + + switch (m0) { + case 'r': + creation = OPEN_EXISTING; + if (!plus) { + flags |= _O_RDONLY; + access = GENERIC_READ; + } + break; + case 'w': + creation = CREATE_ALWAYS; + if (!plus) { + access = GENERIC_WRITE; + flags |= _O_WRONLY; + } + break; + case 'a': + creation = OPEN_ALWAYS; + flags |= _O_APPEND; + if (!plus) { + flags |= _O_WRONLY; + access = GENERIC_WRITE; + } + break; + default: + PyErr_Format(PyExc_ValueError, + "mode string must begin with one of 'r', 'w', " + "or 'a', not '%c'", m0); + goto bail; + } + + handle = CreateFile(name, access, + FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + NULL, + creation, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (handle == INVALID_HANDLE_VALUE) { + PyErr_SetFromWindowsErrWithFilename(GetLastError(), name); + goto bail; + } + + fd = _open_osfhandle((intptr_t) handle, flags); + if (fd == -1) { + CloseHandle(handle); + PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); + goto bail; + } + + fp = _fdopen(fd, fpmode); + if (fp == NULL) { + _close(fd); + PyErr_SetFromErrnoWithFilename(PyExc_IOError, name); + goto bail; + } + + file_obj = PyFile_FromFile(fp, name, mode, fclose); + if (file_obj == NULL) { + fclose(fp); + goto bail; + } + + PyFile_SetBufSize(file_obj, bufsize); +bail: + PyMem_Free(name); + return file_obj; +} +#endif + +static char osutil_doc[] = "Native operating system services."; + +static PyMethodDef methods[] = { + {"listdir", (PyCFunction)listdir, METH_VARARGS | METH_KEYWORDS, + "list a directory\n"}, +#ifdef _WIN32 + {"posixfile", (PyCFunction)posixfile, METH_VARARGS | METH_KEYWORDS, + "Open a file with POSIX-like semantics.\n" +"On error, this function may raise either a WindowsError or an IOError."}, +#endif + {NULL, NULL} +}; + +PyMODINIT_FUNC initosutil(void) +{ + if (PyType_Ready(&listdir_stat_type) == -1) + return; + + Py_InitModule3("osutil", methods, osutil_doc); +} diff --git a/sys/src/cmd/python/Extra/mercurial/parsers.c b/sys/src/cmd/python/Extra/mercurial/parsers.c new file mode 100644 index 000000000..93c10c05d --- /dev/null +++ b/sys/src/cmd/python/Extra/mercurial/parsers.c @@ -0,0 +1,435 @@ +/* + parsers.c - efficient content parsing + + Copyright 2008 Matt Mackall <mpm@selenic.com> and others + + This software may be used and distributed according to the terms of + the GNU General Public License, incorporated herein by reference. +*/ + +#include <Python.h> +#include <ctype.h> +#include <string.h> + +static int hexdigit(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + PyErr_SetString(PyExc_ValueError, "input contains non-hex character"); + return 0; +} + +/* + * Turn a hex-encoded string into binary. + */ +static PyObject *unhexlify(const char *str, int len) +{ + PyObject *ret; + const char *c; + char *d; + + ret = PyString_FromStringAndSize(NULL, len / 2); + if (!ret) + return NULL; + + d = PyString_AS_STRING(ret); + for (c = str; c < str + len;) { + int hi = hexdigit(*c++); + int lo = hexdigit(*c++); + *d++ = (hi << 4) | lo; + } + + return ret; +} + +/* + * This code assumes that a manifest is stitched together with newline + * ('\n') characters. + */ +static PyObject *parse_manifest(PyObject *self, PyObject *args) +{ + PyObject *mfdict, *fdict; + char *str, *cur, *start, *zero; + int len; + + if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest", + &PyDict_Type, &mfdict, + &PyDict_Type, &fdict, + &str, &len)) + goto quit; + + for (start = cur = str, zero = NULL; cur < str + len; cur++) { + PyObject *file = NULL, *node = NULL; + PyObject *flags = NULL; + int nlen; + + if (!*cur) { + zero = cur; + continue; + } + else if (*cur != '\n') + continue; + + if (!zero) { + PyErr_SetString(PyExc_ValueError, + "manifest entry has no separator"); + goto quit; + } + + file = PyString_FromStringAndSize(start, zero - start); + if (!file) + goto bail; + + nlen = cur - zero - 1; + + node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen); + if (!node) + goto bail; + + if (nlen > 40) { + PyObject *flags; + + flags = PyString_FromStringAndSize(zero + 41, + nlen - 40); + if (!flags) + goto bail; + + if (PyDict_SetItem(fdict, file, flags) == -1) + goto bail; + } + + if (PyDict_SetItem(mfdict, file, node) == -1) + goto bail; + + start = cur + 1; + zero = NULL; + + Py_XDECREF(flags); + Py_XDECREF(node); + Py_XDECREF(file); + continue; + bail: + Py_XDECREF(flags); + Py_XDECREF(node); + Py_XDECREF(file); + goto quit; + } + + if (len > 0 && *(cur - 1) != '\n') { + PyErr_SetString(PyExc_ValueError, + "manifest contains trailing garbage"); + goto quit; + } + + Py_INCREF(Py_None); + return Py_None; +quit: + return NULL; +} + +#ifdef _WIN32 +# ifdef _MSC_VER +/* msvc 6.0 has problems */ +# define inline __inline +typedef unsigned long uint32_t; +typedef unsigned __int64 uint64_t; +# else +# include <stdint.h> +# endif +static uint32_t ntohl(uint32_t x) +{ + return ((x & 0x000000ffUL) << 24) | + ((x & 0x0000ff00UL) << 8) | + ((x & 0x00ff0000UL) >> 8) | + ((x & 0xff000000UL) >> 24); +} +#else +/* not windows */ +# include <sys/types.h> +# if defined __BEOS__ && !defined __HAIKU__ +# include <ByteOrder.h> +# else +# include <arpa/inet.h> +# endif +# include <inttypes.h> +#endif + +static PyObject *parse_dirstate(PyObject *self, PyObject *args) +{ + PyObject *dmap, *cmap, *parents = NULL, *ret = NULL; + PyObject *fname = NULL, *cname = NULL, *entry = NULL; + char *str, *cur, *end, *cpos; + int state, mode, size, mtime; + unsigned int flen; + int len; + char decode[16]; /* for alignment */ + + if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate", + &PyDict_Type, &dmap, + &PyDict_Type, &cmap, + &str, &len)) + goto quit; + + /* read parents */ + if (len < 40) + goto quit; + + parents = Py_BuildValue("s#s#", str, 20, str + 20, 20); + if (!parents) + goto quit; + + /* read filenames */ + cur = str + 40; + end = str + len; + + while (cur < end - 17) { + /* unpack header */ + state = *cur; + memcpy(decode, cur + 1, 16); + mode = ntohl(*(uint32_t *)(decode)); + size = ntohl(*(uint32_t *)(decode + 4)); + mtime = ntohl(*(uint32_t *)(decode + 8)); + flen = ntohl(*(uint32_t *)(decode + 12)); + cur += 17; + if (flen > end - cur) { + PyErr_SetString(PyExc_ValueError, "overflow in dirstate"); + goto quit; + } + + entry = Py_BuildValue("ciii", state, mode, size, mtime); + if (!entry) + goto quit; + PyObject_GC_UnTrack(entry); /* don't waste time with this */ + + cpos = memchr(cur, 0, flen); + if (cpos) { + fname = PyString_FromStringAndSize(cur, cpos - cur); + cname = PyString_FromStringAndSize(cpos + 1, + flen - (cpos - cur) - 1); + if (!fname || !cname || + PyDict_SetItem(cmap, fname, cname) == -1 || + PyDict_SetItem(dmap, fname, entry) == -1) + goto quit; + Py_DECREF(cname); + } else { + fname = PyString_FromStringAndSize(cur, flen); + if (!fname || + PyDict_SetItem(dmap, fname, entry) == -1) + goto quit; + } + cur += flen; + Py_DECREF(fname); + Py_DECREF(entry); + fname = cname = entry = NULL; + } + + ret = parents; + Py_INCREF(ret); +quit: + Py_XDECREF(fname); + Py_XDECREF(cname); + Py_XDECREF(entry); + Py_XDECREF(parents); + return ret; +} + +const char nullid[20]; +const int nullrev = -1; + +/* create an index tuple, insert into the nodemap */ +static PyObject * _build_idx_entry(PyObject *nodemap, int n, uint64_t offset_flags, + int comp_len, int uncomp_len, int base_rev, + int link_rev, int parent_1, int parent_2, + const char *c_node_id) +{ + int err; + PyObject *entry, *node_id, *n_obj; + + node_id = PyString_FromStringAndSize(c_node_id, 20); + n_obj = PyInt_FromLong(n); + if (!node_id || !n_obj) + err = -1; + else + err = PyDict_SetItem(nodemap, node_id, n_obj); + + Py_XDECREF(n_obj); + if (err) + goto error_dealloc; + + entry = Py_BuildValue("LiiiiiiN", offset_flags, comp_len, + uncomp_len, base_rev, link_rev, + parent_1, parent_2, node_id); + if (!entry) + goto error_dealloc; + PyObject_GC_UnTrack(entry); /* don't waste time with this */ + + return entry; + +error_dealloc: + Py_XDECREF(node_id); + return NULL; +} + +/* RevlogNG format (all in big endian, data may be inlined): + * 6 bytes: offset + * 2 bytes: flags + * 4 bytes: compressed length + * 4 bytes: uncompressed length + * 4 bytes: base revision + * 4 bytes: link revision + * 4 bytes: parent 1 revision + * 4 bytes: parent 2 revision + * 32 bytes: nodeid (only 20 bytes used) + */ +static int _parse_index_ng (const char *data, int size, int inlined, + PyObject *index, PyObject *nodemap) +{ + PyObject *entry; + int n = 0, err; + uint64_t offset_flags; + int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2; + const char *c_node_id; + const char *end = data + size; + char decode[64]; /* to enforce alignment with inline data */ + + while (data < end) { + unsigned int step; + + memcpy(decode, data, 64); + offset_flags = ntohl(*((uint32_t *) (decode + 4))); + if (n == 0) /* mask out version number for the first entry */ + offset_flags &= 0xFFFF; + else { + uint32_t offset_high = ntohl(*((uint32_t *) decode)); + offset_flags |= ((uint64_t) offset_high) << 32; + } + + comp_len = ntohl(*((uint32_t *) (decode + 8))); + uncomp_len = ntohl(*((uint32_t *) (decode + 12))); + base_rev = ntohl(*((uint32_t *) (decode + 16))); + link_rev = ntohl(*((uint32_t *) (decode + 20))); + parent_1 = ntohl(*((uint32_t *) (decode + 24))); + parent_2 = ntohl(*((uint32_t *) (decode + 28))); + c_node_id = decode + 32; + + entry = _build_idx_entry(nodemap, n, offset_flags, + comp_len, uncomp_len, base_rev, + link_rev, parent_1, parent_2, + c_node_id); + if (!entry) + return 0; + + if (inlined) { + err = PyList_Append(index, entry); + Py_DECREF(entry); + if (err) + return 0; + } else + PyList_SET_ITEM(index, n, entry); /* steals reference */ + + n++; + step = 64 + (inlined ? comp_len : 0); + if (end - data < step) + break; + data += step; + } + if (data != end) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, "corrupt index file"); + return 0; + } + + /* create the nullid/nullrev entry in the nodemap and the + * magic nullid entry in the index at [-1] */ + entry = _build_idx_entry(nodemap, + nullrev, 0, 0, 0, -1, -1, -1, -1, nullid); + if (!entry) + return 0; + if (inlined) { + err = PyList_Append(index, entry); + Py_DECREF(entry); + if (err) + return 0; + } else + PyList_SET_ITEM(index, n, entry); /* steals reference */ + + return 1; +} + +/* This function parses a index file and returns a Python tuple of the + * following format: (index, nodemap, cache) + * + * index: a list of tuples containing the RevlogNG records + * nodemap: a dict mapping node ids to indices in the index list + * cache: if data is inlined, a tuple (index_file_content, 0) else None + */ +static PyObject *parse_index(PyObject *self, PyObject *args) +{ + const char *data; + int size, inlined; + PyObject *rval = NULL, *index = NULL, *nodemap = NULL, *cache = NULL; + PyObject *data_obj = NULL, *inlined_obj; + + if (!PyArg_ParseTuple(args, "s#O", &data, &size, &inlined_obj)) + return NULL; + inlined = inlined_obj && PyObject_IsTrue(inlined_obj); + + /* If no data is inlined, we know the size of the index list in + * advance: size divided by size of one one revlog record (64 bytes) + * plus one for the nullid */ + index = inlined ? PyList_New(0) : PyList_New(size / 64 + 1); + if (!index) + goto quit; + + nodemap = PyDict_New(); + if (!nodemap) + goto quit; + + /* set up the cache return value */ + if (inlined) { + /* Note that the reference to data_obj is only borrowed */ + data_obj = PyTuple_GET_ITEM(args, 0); + cache = Py_BuildValue("iO", 0, data_obj); + if (!cache) + goto quit; + } else { + cache = Py_None; + Py_INCREF(Py_None); + } + + /* actually populate the index and the nodemap with data */ + if (!_parse_index_ng (data, size, inlined, index, nodemap)) + goto quit; + + rval = Py_BuildValue("NNN", index, nodemap, cache); + if (!rval) + goto quit; + return rval; + +quit: + Py_XDECREF(index); + Py_XDECREF(nodemap); + Py_XDECREF(cache); + Py_XDECREF(rval); + return NULL; +} + + +static char parsers_doc[] = "Efficient content parsing."; + +static PyMethodDef methods[] = { + {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"}, + {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"}, + {"parse_index", parse_index, METH_VARARGS, "parse a revlog index\n"}, + {NULL, NULL} +}; + +PyMODINIT_FUNC initparsers(void) +{ + Py_InitModule3("parsers", methods, parsers_doc); +} diff --git a/sys/src/cmd/python/Extra/mkfile b/sys/src/cmd/python/Extra/mkfile new file mode 100644 index 000000000..cf30e453d --- /dev/null +++ b/sys/src/cmd/python/Extra/mkfile @@ -0,0 +1,16 @@ +APE=/sys/src/ape +<$APE/config + +LIB=../libextra.a$O + +OFILES=`{du -a . | grep '.c$' | awk '{print $2}' | sed 's/.$/\$O/'} + +</sys/src/cmd/mklib + +CFLAGS=-c -I.. -I../Include -DT$objtype -D_SUSV2_SOURCE -DNDEBUG + +%.$O: %.c + $CC $CFLAGS -o $stem.$O $stem.c + +clean:V: + rm -fr $OFILES diff --git a/sys/src/cmd/python/Grammar/Grammar b/sys/src/cmd/python/Grammar/Grammar new file mode 100644 index 000000000..c3709d2d1 --- /dev/null +++ b/sys/src/cmd/python/Grammar/Grammar @@ -0,0 +1,148 @@ +# Grammar for Python + +# Note: Changing the grammar specified in this file will most likely +# require corresponding changes in the parser module +# (../Modules/parsermodule.c). If you can't make the changes to +# that module yourself, please co-ordinate the required changes +# with someone who can; ask around on python-dev for help. Fred +# Drake <fdrake@acm.org> will probably be listening there. + +# NOTE WELL: You should also follow all the steps listed in PEP 306, +# "How to Change Python's Grammar" + +# Commands for Kees Blom's railroad program +#diagram:token NAME +#diagram:token NUMBER +#diagram:token STRING +#diagram:token NEWLINE +#diagram:token ENDMARKER +#diagram:token INDENT +#diagram:output\input python.bla +#diagram:token DEDENT +#diagram:output\textwidth 20.04cm\oddsidemargin 0.0cm\evensidemargin 0.0cm +#diagram:rules + +# Start symbols for the grammar: +# single_input is a single interactive statement; +# file_input is a module or sequence of commands read from an input file; +# eval_input is the input for the eval() and input() functions. +# NB: compound_stmt in single_input is followed by extra NEWLINE! +single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE +file_input: (NEWLINE | stmt)* ENDMARKER +eval_input: testlist NEWLINE* ENDMARKER + +decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE +decorators: decorator+ +funcdef: [decorators] 'def' NAME parameters ':' suite +parameters: '(' [varargslist] ')' +varargslist: ((fpdef ['=' test] ',')* + ('*' NAME [',' '**' NAME] | '**' NAME) | + fpdef ['=' test] (',' fpdef ['=' test])* [',']) +fpdef: NAME | '(' fplist ')' +fplist: fpdef (',' fpdef)* [','] + +stmt: simple_stmt | compound_stmt +simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE +small_stmt: (expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | + import_stmt | global_stmt | exec_stmt | assert_stmt) +expr_stmt: testlist (augassign (yield_expr|testlist) | + ('=' (yield_expr|testlist))*) +augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | + '<<=' | '>>=' | '**=' | '//=') +# For normal assignments, additional restrictions enforced by the interpreter +print_stmt: 'print' ( [ test (',' test)* [','] ] | + '>>' test [ (',' test)+ [','] ] ) +del_stmt: 'del' exprlist +pass_stmt: 'pass' +flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt +break_stmt: 'break' +continue_stmt: 'continue' +return_stmt: 'return' [testlist] +yield_stmt: yield_expr +raise_stmt: 'raise' [test [',' test [',' test]]] +import_stmt: import_name | import_from +import_name: 'import' dotted_as_names +import_from: ('from' ('.'* dotted_name | '.'+) + 'import' ('*' | '(' import_as_names ')' | import_as_names)) +import_as_name: NAME [('as' | NAME) NAME] +dotted_as_name: dotted_name [('as' | NAME) NAME] +import_as_names: import_as_name (',' import_as_name)* [','] +dotted_as_names: dotted_as_name (',' dotted_as_name)* +dotted_name: NAME ('.' NAME)* +global_stmt: 'global' NAME (',' NAME)* +exec_stmt: 'exec' expr ['in' test [',' test]] +assert_stmt: 'assert' test [',' test] + +compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef +if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] +while_stmt: 'while' test ':' suite ['else' ':' suite] +for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] +try_stmt: ('try' ':' suite + ((except_clause ':' suite)+ + ['else' ':' suite] + ['finally' ':' suite] | + 'finally' ':' suite)) +with_stmt: 'with' test [ with_var ] ':' suite +with_var: ('as' | NAME) expr +# NB compile.c makes sure that the default except clause is last +except_clause: 'except' [test [',' test]] +suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT + +# Backward compatibility cruft to support: +# [ x for x in lambda: True, lambda: False if x() ] +# even while also allowing: +# lambda x: 5 if x else 2 +# (But not a mix of the two) +testlist_safe: old_test [(',' old_test)+ [',']] +old_test: or_test | old_lambdef +old_lambdef: 'lambda' [varargslist] ':' old_test + +test: or_test ['if' or_test 'else' test] | lambdef +or_test: and_test ('or' and_test)* +and_test: not_test ('and' not_test)* +not_test: 'not' not_test | comparison +comparison: expr (comp_op expr)* +comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' +expr: xor_expr ('|' xor_expr)* +xor_expr: and_expr ('^' and_expr)* +and_expr: shift_expr ('&' shift_expr)* +shift_expr: arith_expr (('<<'|'>>') arith_expr)* +arith_expr: term (('+'|'-') term)* +term: factor (('*'|'/'|'%'|'//') factor)* +factor: ('+'|'-'|'~') factor | power +power: atom trailer* ['**' factor] +atom: ('(' [yield_expr|testlist_gexp] ')' | + '[' [listmaker] ']' | + '{' [dictmaker] '}' | + '`' testlist1 '`' | + NAME | NUMBER | STRING+) +listmaker: test ( list_for | (',' test)* [','] ) +testlist_gexp: test ( gen_for | (',' test)* [','] ) +lambdef: 'lambda' [varargslist] ':' test +trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME +subscriptlist: subscript (',' subscript)* [','] +subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] +sliceop: ':' [test] +exprlist: expr (',' expr)* [','] +testlist: test (',' test)* [','] +dictmaker: test ':' test (',' test ':' test)* [','] + +classdef: 'class' NAME ['(' [testlist] ')'] ':' suite + +arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) +argument: test [gen_for] | test '=' test # Really [keyword '='] test + +list_iter: list_for | list_if +list_for: 'for' exprlist 'in' testlist_safe [list_iter] +list_if: 'if' old_test [list_iter] + +gen_iter: gen_for | gen_if +gen_for: 'for' exprlist 'in' or_test [gen_iter] +gen_if: 'if' old_test [gen_iter] + +testlist1: test (',' test)* + +# not used in grammar, but may appear in "node" passed from Parser to Compiler +encoding_decl: NAME + +yield_expr: 'yield' [testlist] diff --git a/sys/src/cmd/python/Include/Python-ast.h b/sys/src/cmd/python/Include/Python-ast.h new file mode 100644 index 000000000..5d4147bf3 --- /dev/null +++ b/sys/src/cmd/python/Include/Python-ast.h @@ -0,0 +1,501 @@ +/* File automatically generated by Parser/asdl_c.py */ + +#include "asdl.h" + +typedef struct _mod *mod_ty; + +typedef struct _stmt *stmt_ty; + +typedef struct _expr *expr_ty; + +typedef enum _expr_context { Load=1, Store=2, Del=3, AugLoad=4, AugStore=5, + Param=6 } expr_context_ty; + +typedef struct _slice *slice_ty; + +typedef enum _boolop { And=1, Or=2 } boolop_ty; + +typedef enum _operator { Add=1, Sub=2, Mult=3, Div=4, Mod=5, Pow=6, LShift=7, + RShift=8, BitOr=9, BitXor=10, BitAnd=11, FloorDiv=12 } + operator_ty; + +typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty; + +typedef enum _cmpop { Eq=1, NotEq=2, Lt=3, LtE=4, Gt=5, GtE=6, Is=7, IsNot=8, + In=9, NotIn=10 } cmpop_ty; + +typedef struct _comprehension *comprehension_ty; + +typedef struct _excepthandler *excepthandler_ty; + +typedef struct _arguments *arguments_ty; + +typedef struct _keyword *keyword_ty; + +typedef struct _alias *alias_ty; + + +enum _mod_kind {Module_kind=1, Interactive_kind=2, Expression_kind=3, + Suite_kind=4}; +struct _mod { + enum _mod_kind kind; + union { + struct { + asdl_seq *body; + } Module; + + struct { + asdl_seq *body; + } Interactive; + + struct { + expr_ty body; + } Expression; + + struct { + asdl_seq *body; + } Suite; + + } v; +}; + +enum _stmt_kind {FunctionDef_kind=1, ClassDef_kind=2, Return_kind=3, + Delete_kind=4, Assign_kind=5, AugAssign_kind=6, Print_kind=7, + For_kind=8, While_kind=9, If_kind=10, With_kind=11, + Raise_kind=12, TryExcept_kind=13, TryFinally_kind=14, + Assert_kind=15, Import_kind=16, ImportFrom_kind=17, + Exec_kind=18, Global_kind=19, Expr_kind=20, Pass_kind=21, + Break_kind=22, Continue_kind=23}; +struct _stmt { + enum _stmt_kind kind; + union { + struct { + identifier name; + arguments_ty args; + asdl_seq *body; + asdl_seq *decorators; + } FunctionDef; + + struct { + identifier name; + asdl_seq *bases; + asdl_seq *body; + } ClassDef; + + struct { + expr_ty value; + } Return; + + struct { + asdl_seq *targets; + } Delete; + + struct { + asdl_seq *targets; + expr_ty value; + } Assign; + + struct { + expr_ty target; + operator_ty op; + expr_ty value; + } AugAssign; + + struct { + expr_ty dest; + asdl_seq *values; + bool nl; + } Print; + + struct { + expr_ty target; + expr_ty iter; + asdl_seq *body; + asdl_seq *orelse; + } For; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } While; + + struct { + expr_ty test; + asdl_seq *body; + asdl_seq *orelse; + } If; + + struct { + expr_ty context_expr; + expr_ty optional_vars; + asdl_seq *body; + } With; + + struct { + expr_ty type; + expr_ty inst; + expr_ty tback; + } Raise; + + struct { + asdl_seq *body; + asdl_seq *handlers; + asdl_seq *orelse; + } TryExcept; + + struct { + asdl_seq *body; + asdl_seq *finalbody; + } TryFinally; + + struct { + expr_ty test; + expr_ty msg; + } Assert; + + struct { + asdl_seq *names; + } Import; + + struct { + identifier module; + asdl_seq *names; + int level; + } ImportFrom; + + struct { + expr_ty body; + expr_ty globals; + expr_ty locals; + } Exec; + + struct { + asdl_seq *names; + } Global; + + struct { + expr_ty value; + } Expr; + + } v; + int lineno; + int col_offset; +}; + +enum _expr_kind {BoolOp_kind=1, BinOp_kind=2, UnaryOp_kind=3, Lambda_kind=4, + IfExp_kind=5, Dict_kind=6, ListComp_kind=7, + GeneratorExp_kind=8, Yield_kind=9, Compare_kind=10, + Call_kind=11, Repr_kind=12, Num_kind=13, Str_kind=14, + Attribute_kind=15, Subscript_kind=16, Name_kind=17, + List_kind=18, Tuple_kind=19}; +struct _expr { + enum _expr_kind kind; + union { + struct { + boolop_ty op; + asdl_seq *values; + } BoolOp; + + struct { + expr_ty left; + operator_ty op; + expr_ty right; + } BinOp; + + struct { + unaryop_ty op; + expr_ty operand; + } UnaryOp; + + struct { + arguments_ty args; + expr_ty body; + } Lambda; + + struct { + expr_ty test; + expr_ty body; + expr_ty orelse; + } IfExp; + + struct { + asdl_seq *keys; + asdl_seq *values; + } Dict; + + struct { + expr_ty elt; + asdl_seq *generators; + } ListComp; + + struct { + expr_ty elt; + asdl_seq *generators; + } GeneratorExp; + + struct { + expr_ty value; + } Yield; + + struct { + expr_ty left; + asdl_int_seq *ops; + asdl_seq *comparators; + } Compare; + + struct { + expr_ty func; + asdl_seq *args; + asdl_seq *keywords; + expr_ty starargs; + expr_ty kwargs; + } Call; + + struct { + expr_ty value; + } Repr; + + struct { + object n; + } Num; + + struct { + string s; + } Str; + + struct { + expr_ty value; + identifier attr; + expr_context_ty ctx; + } Attribute; + + struct { + expr_ty value; + slice_ty slice; + expr_context_ty ctx; + } Subscript; + + struct { + identifier id; + expr_context_ty ctx; + } Name; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } List; + + struct { + asdl_seq *elts; + expr_context_ty ctx; + } Tuple; + + } v; + int lineno; + int col_offset; +}; + +enum _slice_kind {Ellipsis_kind=1, Slice_kind=2, ExtSlice_kind=3, Index_kind=4}; +struct _slice { + enum _slice_kind kind; + union { + struct { + expr_ty lower; + expr_ty upper; + expr_ty step; + } Slice; + + struct { + asdl_seq *dims; + } ExtSlice; + + struct { + expr_ty value; + } Index; + + } v; +}; + +struct _comprehension { + expr_ty target; + expr_ty iter; + asdl_seq *ifs; +}; + +struct _excepthandler { + expr_ty type; + expr_ty name; + asdl_seq *body; + int lineno; + int col_offset; +}; + +struct _arguments { + asdl_seq *args; + identifier vararg; + identifier kwarg; + asdl_seq *defaults; +}; + +struct _keyword { + identifier arg; + expr_ty value; +}; + +struct _alias { + identifier name; + identifier asname; +}; + + +#define Module(a0, a1) _Py_Module(a0, a1) +mod_ty _Py_Module(asdl_seq * body, PyArena *arena); +#define Interactive(a0, a1) _Py_Interactive(a0, a1) +mod_ty _Py_Interactive(asdl_seq * body, PyArena *arena); +#define Expression(a0, a1) _Py_Expression(a0, a1) +mod_ty _Py_Expression(expr_ty body, PyArena *arena); +#define Suite(a0, a1) _Py_Suite(a0, a1) +mod_ty _Py_Suite(asdl_seq * body, PyArena *arena); +#define FunctionDef(a0, a1, a2, a3, a4, a5, a6) _Py_FunctionDef(a0, a1, a2, a3, a4, a5, a6) +stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body, + asdl_seq * decorators, int lineno, int col_offset, + PyArena *arena); +#define ClassDef(a0, a1, a2, a3, a4, a5) _Py_ClassDef(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int + lineno, int col_offset, PyArena *arena); +#define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3) +stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define Delete(a0, a1, a2, a3) _Py_Delete(a0, a1, a2, a3) +stmt_ty _Py_Delete(asdl_seq * targets, int lineno, int col_offset, PyArena + *arena); +#define Assign(a0, a1, a2, a3, a4) _Py_Assign(a0, a1, a2, a3, a4) +stmt_ty _Py_Assign(asdl_seq * targets, expr_ty value, int lineno, int + col_offset, PyArena *arena); +#define AugAssign(a0, a1, a2, a3, a4, a5) _Py_AugAssign(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_AugAssign(expr_ty target, operator_ty op, expr_ty value, int + lineno, int col_offset, PyArena *arena); +#define Print(a0, a1, a2, a3, a4, a5) _Py_Print(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_Print(expr_ty dest, asdl_seq * values, bool nl, int lineno, int + col_offset, PyArena *arena); +#define For(a0, a1, a2, a3, a4, a5, a6) _Py_For(a0, a1, a2, a3, a4, a5, a6) +stmt_ty _Py_For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * + orelse, int lineno, int col_offset, PyArena *arena); +#define While(a0, a1, a2, a3, a4, a5) _Py_While(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, + int col_offset, PyArena *arena); +#define If(a0, a1, a2, a3, a4, a5) _Py_If(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, + int col_offset, PyArena *arena); +#define With(a0, a1, a2, a3, a4, a5) _Py_With(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, + int lineno, int col_offset, PyArena *arena); +#define Raise(a0, a1, a2, a3, a4, a5) _Py_Raise(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, int + col_offset, PyArena *arena); +#define TryExcept(a0, a1, a2, a3, a4, a5) _Py_TryExcept(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, + int lineno, int col_offset, PyArena *arena); +#define TryFinally(a0, a1, a2, a3, a4) _Py_TryFinally(a0, a1, a2, a3, a4) +stmt_ty _Py_TryFinally(asdl_seq * body, asdl_seq * finalbody, int lineno, int + col_offset, PyArena *arena); +#define Assert(a0, a1, a2, a3, a4) _Py_Assert(a0, a1, a2, a3, a4) +stmt_ty _Py_Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, + PyArena *arena); +#define Import(a0, a1, a2, a3) _Py_Import(a0, a1, a2, a3) +stmt_ty _Py_Import(asdl_seq * names, int lineno, int col_offset, PyArena + *arena); +#define ImportFrom(a0, a1, a2, a3, a4, a5) _Py_ImportFrom(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_ImportFrom(identifier module, asdl_seq * names, int level, int + lineno, int col_offset, PyArena *arena); +#define Exec(a0, a1, a2, a3, a4, a5) _Py_Exec(a0, a1, a2, a3, a4, a5) +stmt_ty _Py_Exec(expr_ty body, expr_ty globals, expr_ty locals, int lineno, int + col_offset, PyArena *arena); +#define Global(a0, a1, a2, a3) _Py_Global(a0, a1, a2, a3) +stmt_ty _Py_Global(asdl_seq * names, int lineno, int col_offset, PyArena + *arena); +#define Expr(a0, a1, a2, a3) _Py_Expr(a0, a1, a2, a3) +stmt_ty _Py_Expr(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define Pass(a0, a1, a2) _Py_Pass(a0, a1, a2) +stmt_ty _Py_Pass(int lineno, int col_offset, PyArena *arena); +#define Break(a0, a1, a2) _Py_Break(a0, a1, a2) +stmt_ty _Py_Break(int lineno, int col_offset, PyArena *arena); +#define Continue(a0, a1, a2) _Py_Continue(a0, a1, a2) +stmt_ty _Py_Continue(int lineno, int col_offset, PyArena *arena); +#define BoolOp(a0, a1, a2, a3, a4) _Py_BoolOp(a0, a1, a2, a3, a4) +expr_ty _Py_BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, + PyArena *arena); +#define BinOp(a0, a1, a2, a3, a4, a5) _Py_BinOp(a0, a1, a2, a3, a4, a5) +expr_ty _Py_BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int + col_offset, PyArena *arena); +#define UnaryOp(a0, a1, a2, a3, a4) _Py_UnaryOp(a0, a1, a2, a3, a4) +expr_ty _Py_UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, + PyArena *arena); +#define Lambda(a0, a1, a2, a3, a4) _Py_Lambda(a0, a1, a2, a3, a4) +expr_ty _Py_Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, + PyArena *arena); +#define IfExp(a0, a1, a2, a3, a4, a5) _Py_IfExp(a0, a1, a2, a3, a4, a5) +expr_ty _Py_IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int + col_offset, PyArena *arena); +#define Dict(a0, a1, a2, a3, a4) _Py_Dict(a0, a1, a2, a3, a4) +expr_ty _Py_Dict(asdl_seq * keys, asdl_seq * values, int lineno, int + col_offset, PyArena *arena); +#define ListComp(a0, a1, a2, a3, a4) _Py_ListComp(a0, a1, a2, a3, a4) +expr_ty _Py_ListComp(expr_ty elt, asdl_seq * generators, int lineno, int + col_offset, PyArena *arena); +#define GeneratorExp(a0, a1, a2, a3, a4) _Py_GeneratorExp(a0, a1, a2, a3, a4) +expr_ty _Py_GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int + col_offset, PyArena *arena); +#define Yield(a0, a1, a2, a3) _Py_Yield(a0, a1, a2, a3) +expr_ty _Py_Yield(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define Compare(a0, a1, a2, a3, a4, a5) _Py_Compare(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, + int lineno, int col_offset, PyArena *arena); +#define Call(a0, a1, a2, a3, a4, a5, a6, a7) _Py_Call(a0, a1, a2, a3, a4, a5, a6, a7) +expr_ty _Py_Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty + starargs, expr_ty kwargs, int lineno, int col_offset, PyArena + *arena); +#define Repr(a0, a1, a2, a3) _Py_Repr(a0, a1, a2, a3) +expr_ty _Py_Repr(expr_ty value, int lineno, int col_offset, PyArena *arena); +#define Num(a0, a1, a2, a3) _Py_Num(a0, a1, a2, a3) +expr_ty _Py_Num(object n, int lineno, int col_offset, PyArena *arena); +#define Str(a0, a1, a2, a3) _Py_Str(a0, a1, a2, a3) +expr_ty _Py_Str(string s, int lineno, int col_offset, PyArena *arena); +#define Attribute(a0, a1, a2, a3, a4, a5) _Py_Attribute(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int + lineno, int col_offset, PyArena *arena); +#define Subscript(a0, a1, a2, a3, a4, a5) _Py_Subscript(a0, a1, a2, a3, a4, a5) +expr_ty _Py_Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int + lineno, int col_offset, PyArena *arena); +#define Name(a0, a1, a2, a3, a4) _Py_Name(a0, a1, a2, a3, a4) +expr_ty _Py_Name(identifier id, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena); +#define List(a0, a1, a2, a3, a4) _Py_List(a0, a1, a2, a3, a4) +expr_ty _Py_List(asdl_seq * elts, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena); +#define Tuple(a0, a1, a2, a3, a4) _Py_Tuple(a0, a1, a2, a3, a4) +expr_ty _Py_Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena); +#define Ellipsis(a0) _Py_Ellipsis(a0) +slice_ty _Py_Ellipsis(PyArena *arena); +#define Slice(a0, a1, a2, a3) _Py_Slice(a0, a1, a2, a3) +slice_ty _Py_Slice(expr_ty lower, expr_ty upper, expr_ty step, PyArena *arena); +#define ExtSlice(a0, a1) _Py_ExtSlice(a0, a1) +slice_ty _Py_ExtSlice(asdl_seq * dims, PyArena *arena); +#define Index(a0, a1) _Py_Index(a0, a1) +slice_ty _Py_Index(expr_ty value, PyArena *arena); +#define comprehension(a0, a1, a2, a3) _Py_comprehension(a0, a1, a2, a3) +comprehension_ty _Py_comprehension(expr_ty target, expr_ty iter, asdl_seq * + ifs, PyArena *arena); +#define excepthandler(a0, a1, a2, a3, a4, a5) _Py_excepthandler(a0, a1, a2, a3, a4, a5) +excepthandler_ty _Py_excepthandler(expr_ty type, expr_ty name, asdl_seq * body, + int lineno, int col_offset, PyArena *arena); +#define arguments(a0, a1, a2, a3, a4) _Py_arguments(a0, a1, a2, a3, a4) +arguments_ty _Py_arguments(asdl_seq * args, identifier vararg, identifier + kwarg, asdl_seq * defaults, PyArena *arena); +#define keyword(a0, a1, a2) _Py_keyword(a0, a1, a2) +keyword_ty _Py_keyword(identifier arg, expr_ty value, PyArena *arena); +#define alias(a0, a1, a2) _Py_alias(a0, a1, a2) +alias_ty _Py_alias(identifier name, identifier asname, PyArena *arena); + +PyObject* PyAST_mod2obj(mod_ty t); diff --git a/sys/src/cmd/python/Include/Python.h b/sys/src/cmd/python/Include/Python.h new file mode 100644 index 000000000..f0be28fa7 --- /dev/null +++ b/sys/src/cmd/python/Include/Python.h @@ -0,0 +1,173 @@ +#ifndef Py_PYTHON_H +#define Py_PYTHON_H +/* Since this is a "meta-include" file, no #ifdef __cplusplus / extern "C" { */ + +/* Include nearly all Python header files */ + +#include "patchlevel.h" +#include "pyconfig.h" + +/* Cyclic gc is always enabled, starting with release 2.3a1. Supply the + * old symbol for the benefit of extension modules written before then + * that may be conditionalizing on it. The core doesn't use it anymore. + */ +#ifndef WITH_CYCLE_GC +#define WITH_CYCLE_GC 1 +#endif + +#include <limits.h> + +#ifndef UCHAR_MAX +#error "Something's broken. UCHAR_MAX should be defined in limits.h." +#endif + +#if UCHAR_MAX != 255 +#error "Python's source code assumes C's unsigned char is an 8-bit type." +#endif + +#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE) +#define _SGI_MP_SOURCE +#endif + +#include <stdio.h> +#ifndef NULL +# error "Python.h requires that stdio.h define NULL." +#endif + +#include <string.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include <stdlib.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* For uintptr_t, intptr_t */ +#ifdef HAVE_STDDEF_H +#include <stddef.h> +#endif + +/* CAUTION: Build setups should ensure that NDEBUG is defined on the + * compiler command line when building Python in release mode; else + * assert() calls won't be removed. + */ +#include <assert.h> + +#include "pyport.h" + +/* pyconfig.h or pyport.h may or may not define DL_IMPORT */ +#ifndef DL_IMPORT /* declarations for DLL import/export */ +#define DL_IMPORT(RTYPE) RTYPE +#endif +#ifndef DL_EXPORT /* declarations for DLL import/export */ +#define DL_EXPORT(RTYPE) RTYPE +#endif + +/* Debug-mode build with pymalloc implies PYMALLOC_DEBUG. + * PYMALLOC_DEBUG is in error if pymalloc is not in use. + */ +#if defined(Py_DEBUG) && defined(WITH_PYMALLOC) && !defined(PYMALLOC_DEBUG) +#define PYMALLOC_DEBUG +#endif +#if defined(PYMALLOC_DEBUG) && !defined(WITH_PYMALLOC) +#error "PYMALLOC_DEBUG requires WITH_PYMALLOC" +#endif +#include "pymem.h" + +#include "object.h" +#include "objimpl.h" + +#include "pydebug.h" + +#include "unicodeobject.h" +#include "intobject.h" +#include "boolobject.h" +#include "longobject.h" +#include "floatobject.h" +#ifndef WITHOUT_COMPLEX +#include "complexobject.h" +#endif +#include "rangeobject.h" +#include "stringobject.h" +#include "bufferobject.h" +#include "tupleobject.h" +#include "listobject.h" +#include "dictobject.h" +#include "enumobject.h" +#include "setobject.h" +#include "methodobject.h" +#include "moduleobject.h" +#include "funcobject.h" +#include "classobject.h" +#include "fileobject.h" +#include "cobject.h" +#include "traceback.h" +#include "sliceobject.h" +#include "cellobject.h" +#include "iterobject.h" +#include "genobject.h" +#include "descrobject.h" +#include "weakrefobject.h" + +#include "codecs.h" +#include "pyerrors.h" + +#include "pystate.h" + +#include "pyarena.h" +#include "modsupport.h" +#include "pythonrun.h" +#include "ceval.h" +#include "sysmodule.h" +#include "intrcheck.h" +#include "import.h" + +#include "abstract.h" + +#include "compile.h" +#include "eval.h" + +#include "pystrtod.h" + +/* _Py_Mangle is defined in compile.c */ +PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name); + +/* PyArg_GetInt is deprecated and should not be used, use PyArg_Parse(). */ +#define PyArg_GetInt(v, a) PyArg_Parse((v), "i", (a)) + +/* PyArg_NoArgs should not be necessary. + Set ml_flags in the PyMethodDef to METH_NOARGS. */ +#define PyArg_NoArgs(v) PyArg_Parse(v, "") + +/* Convert a possibly signed character to a nonnegative int */ +/* XXX This assumes characters are 8 bits wide */ +#ifdef __CHAR_UNSIGNED__ +#define Py_CHARMASK(c) (c) +#else +#define Py_CHARMASK(c) ((c) & 0xff) +#endif + +#include "pyfpe.h" + +/* These definitions must match corresponding definitions in graminit.h. + There's code in compile.c that checks that they are the same. */ +#define Py_single_input 256 +#define Py_file_input 257 +#define Py_eval_input 258 + +#ifdef HAVE_PTH +/* GNU pth user-space thread support */ +#include <pth.h> +#endif + +/* Define macros for inline documentation. */ +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#ifdef WITH_DOC_STRINGS +#define PyDoc_STR(str) str +#else +#define PyDoc_STR(str) "" +#endif + +#endif /* !Py_PYTHON_H */ diff --git a/sys/src/cmd/python/Include/abstract.h b/sys/src/cmd/python/Include/abstract.h new file mode 100644 index 000000000..14510c6ab --- /dev/null +++ b/sys/src/cmd/python/Include/abstract.h @@ -0,0 +1,1276 @@ +#ifndef Py_ABSTRACTOBJECT_H +#define Py_ABSTRACTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PY_SSIZE_T_CLEAN +#define PyObject_CallFunction _PyObject_CallFunction_SizeT +#define PyObject_CallMethod _PyObject_CallMethod_SizeT +#endif + +/* Abstract Object Interface (many thanks to Jim Fulton) */ + +/* + PROPOSAL: A Generic Python Object Interface for Python C Modules + +Problem + + Python modules written in C that must access Python objects must do + so through routines whose interfaces are described by a set of + include files. Unfortunately, these routines vary according to the + object accessed. To use these routines, the C programmer must check + the type of the object being used and must call a routine based on + the object type. For example, to access an element of a sequence, + the programmer must determine whether the sequence is a list or a + tuple: + + if(is_tupleobject(o)) + e=gettupleitem(o,i) + else if(is_listitem(o)) + e=getlistitem(o,i) + + If the programmer wants to get an item from another type of object + that provides sequence behavior, there is no clear way to do it + correctly. + + The persistent programmer may peruse object.h and find that the + _typeobject structure provides a means of invoking up to (currently + about) 41 special operators. So, for example, a routine can get an + item from any object that provides sequence behavior. However, to + use this mechanism, the programmer must make their code dependent on + the current Python implementation. + + Also, certain semantics, especially memory management semantics, may + differ by the type of object being used. Unfortunately, these + semantics are not clearly described in the current include files. + An abstract interface providing more consistent semantics is needed. + +Proposal + + I propose the creation of a standard interface (with an associated + library of routines and/or macros) for generically obtaining the + services of Python objects. This proposal can be viewed as one + components of a Python C interface consisting of several components. + + From the viewpoint of C access to Python services, we have (as + suggested by Guido in off-line discussions): + + - "Very high level layer": two or three functions that let you exec or + eval arbitrary Python code given as a string in a module whose name is + given, passing C values in and getting C values out using + mkvalue/getargs style format strings. This does not require the user + to declare any variables of type "PyObject *". This should be enough + to write a simple application that gets Python code from the user, + execs it, and returns the output or errors. (Error handling must also + be part of this API.) + + - "Abstract objects layer": which is the subject of this proposal. + It has many functions operating on objects, and lest you do many + things from C that you can also write in Python, without going + through the Python parser. + + - "Concrete objects layer": This is the public type-dependent + interface provided by the standard built-in types, such as floats, + strings, and lists. This interface exists and is currently + documented by the collection of include files provided with the + Python distributions. + + From the point of view of Python accessing services provided by C + modules: + + - "Python module interface": this interface consist of the basic + routines used to define modules and their members. Most of the + current extensions-writing guide deals with this interface. + + - "Built-in object interface": this is the interface that a new + built-in type must provide and the mechanisms and rules that a + developer of a new built-in type must use and follow. + + This proposal is a "first-cut" that is intended to spur + discussion. See especially the lists of notes. + + The Python C object interface will provide four protocols: object, + numeric, sequence, and mapping. Each protocol consists of a + collection of related operations. If an operation that is not + provided by a particular type is invoked, then a standard exception, + NotImplementedError is raised with a operation name as an argument. + In addition, for convenience this interface defines a set of + constructors for building objects of built-in types. This is needed + so new objects can be returned from C functions that otherwise treat + objects generically. + +Memory Management + + For all of the functions described in this proposal, if a function + retains a reference to a Python object passed as an argument, then the + function will increase the reference count of the object. It is + unnecessary for the caller to increase the reference count of an + argument in anticipation of the object's retention. + + All Python objects returned from functions should be treated as new + objects. Functions that return objects assume that the caller will + retain a reference and the reference count of the object has already + been incremented to account for this fact. A caller that does not + retain a reference to an object that is returned from a function + must decrement the reference count of the object (using + DECREF(object)) to prevent memory leaks. + + Note that the behavior mentioned here is different from the current + behavior for some objects (e.g. lists and tuples) when certain + type-specific routines are called directly (e.g. setlistitem). The + proposed abstraction layer will provide a consistent memory + management interface, correcting for inconsistent behavior for some + built-in types. + +Protocols + +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ + +/* Object Protocol: */ + + /* Implemented elsewhere: + + int PyObject_Print(PyObject *o, FILE *fp, int flags); + + Print an object, o, on file, fp. Returns -1 on + error. The flags argument is used to enable certain printing + options. The only option currently supported is Py_Print_RAW. + + (What should be said about Py_Print_RAW?) + + */ + + /* Implemented elsewhere: + + int PyObject_HasAttrString(PyObject *o, char *attr_name); + + Returns 1 if o has the attribute attr_name, and 0 otherwise. + This is equivalent to the Python expression: + hasattr(o,attr_name). + + This function always succeeds. + + */ + + /* Implemented elsewhere: + + PyObject* PyObject_GetAttrString(PyObject *o, char *attr_name); + + Retrieve an attributed named attr_name form object o. + Returns the attribute value on success, or NULL on failure. + This is the equivalent of the Python expression: o.attr_name. + + */ + + /* Implemented elsewhere: + + int PyObject_HasAttr(PyObject *o, PyObject *attr_name); + + Returns 1 if o has the attribute attr_name, and 0 otherwise. + This is equivalent to the Python expression: + hasattr(o,attr_name). + + This function always succeeds. + + */ + + /* Implemented elsewhere: + + PyObject* PyObject_GetAttr(PyObject *o, PyObject *attr_name); + + Retrieve an attributed named attr_name form object o. + Returns the attribute value on success, or NULL on failure. + This is the equivalent of the Python expression: o.attr_name. + + */ + + + /* Implemented elsewhere: + + int PyObject_SetAttrString(PyObject *o, char *attr_name, PyObject *v); + + Set the value of the attribute named attr_name, for object o, + to the value, v. Returns -1 on failure. This is + the equivalent of the Python statement: o.attr_name=v. + + */ + + /* Implemented elsewhere: + + int PyObject_SetAttr(PyObject *o, PyObject *attr_name, PyObject *v); + + Set the value of the attribute named attr_name, for object o, + to the value, v. Returns -1 on failure. This is + the equivalent of the Python statement: o.attr_name=v. + + */ + + /* implemented as a macro: + + int PyObject_DelAttrString(PyObject *o, char *attr_name); + + Delete attribute named attr_name, for object o. Returns + -1 on failure. This is the equivalent of the Python + statement: del o.attr_name. + + */ +#define PyObject_DelAttrString(O,A) PyObject_SetAttrString((O),(A),NULL) + + /* implemented as a macro: + + int PyObject_DelAttr(PyObject *o, PyObject *attr_name); + + Delete attribute named attr_name, for object o. Returns -1 + on failure. This is the equivalent of the Python + statement: del o.attr_name. + + */ +#define PyObject_DelAttr(O,A) PyObject_SetAttr((O),(A),NULL) + + PyAPI_FUNC(int) PyObject_Cmp(PyObject *o1, PyObject *o2, int *result); + + /* + Compare the values of o1 and o2 using a routine provided by + o1, if one exists, otherwise with a routine provided by o2. + The result of the comparison is returned in result. Returns + -1 on failure. This is the equivalent of the Python + statement: result=cmp(o1,o2). + + */ + + /* Implemented elsewhere: + + int PyObject_Compare(PyObject *o1, PyObject *o2); + + Compare the values of o1 and o2 using a routine provided by + o1, if one exists, otherwise with a routine provided by o2. + Returns the result of the comparison on success. On error, + the value returned is undefined. This is equivalent to the + Python expression: cmp(o1,o2). + + */ + + /* Implemented elsewhere: + + PyObject *PyObject_Repr(PyObject *o); + + Compute the string representation of object, o. Returns the + string representation on success, NULL on failure. This is + the equivalent of the Python expression: repr(o). + + Called by the repr() built-in function and by reverse quotes. + + */ + + /* Implemented elsewhere: + + PyObject *PyObject_Str(PyObject *o); + + Compute the string representation of object, o. Returns the + string representation on success, NULL on failure. This is + the equivalent of the Python expression: str(o).) + + Called by the str() built-in function and by the print + statement. + + */ + + /* Implemented elsewhere: + + PyObject *PyObject_Unicode(PyObject *o); + + Compute the unicode representation of object, o. Returns the + unicode representation on success, NULL on failure. This is + the equivalent of the Python expression: unistr(o).) + + Called by the unistr() built-in function. + + */ + + /* Declared elsewhere + + PyAPI_FUNC(int) PyCallable_Check(PyObject *o); + + Determine if the object, o, is callable. Return 1 if the + object is callable and 0 otherwise. + + This function always succeeds. + + */ + + + + PyAPI_FUNC(PyObject *) PyObject_Call(PyObject *callable_object, + PyObject *args, PyObject *kw); + + /* + Call a callable Python object, callable_object, with + arguments and keywords arguments. The 'args' argument can not be + NULL, but the 'kw' argument can be NULL. + + */ + + PyAPI_FUNC(PyObject *) PyObject_CallObject(PyObject *callable_object, + PyObject *args); + + /* + Call a callable Python object, callable_object, with + arguments given by the tuple, args. If no arguments are + needed, then args may be NULL. Returns the result of the + call on success, or NULL on failure. This is the equivalent + of the Python expression: apply(o,args). + + */ + + PyAPI_FUNC(PyObject *) PyObject_CallFunction(PyObject *callable_object, + char *format, ...); + + /* + Call a callable Python object, callable_object, with a + variable number of C arguments. The C arguments are described + using a mkvalue-style format string. The format may be NULL, + indicating that no arguments are provided. Returns the + result of the call on success, or NULL on failure. This is + the equivalent of the Python expression: apply(o,args). + + */ + + + PyAPI_FUNC(PyObject *) PyObject_CallMethod(PyObject *o, char *m, + char *format, ...); + + /* + Call the method named m of object o with a variable number of + C arguments. The C arguments are described by a mkvalue + format string. The format may be NULL, indicating that no + arguments are provided. Returns the result of the call on + success, or NULL on failure. This is the equivalent of the + Python expression: o.method(args). + */ + + PyAPI_FUNC(PyObject *) _PyObject_CallFunction_SizeT(PyObject *callable, + char *format, ...); + PyAPI_FUNC(PyObject *) _PyObject_CallMethod_SizeT(PyObject *o, + char *name, + char *format, ...); + + PyAPI_FUNC(PyObject *) PyObject_CallFunctionObjArgs(PyObject *callable, + ...); + + /* + Call a callable Python object, callable_object, with a + variable number of C arguments. The C arguments are provided + as PyObject * values, terminated by a NULL. Returns the + result of the call on success, or NULL on failure. This is + the equivalent of the Python expression: apply(o,args). + */ + + + PyAPI_FUNC(PyObject *) PyObject_CallMethodObjArgs(PyObject *o, + PyObject *m, ...); + + /* + Call the method named m of object o with a variable number of + C arguments. The C arguments are provided as PyObject * + values, terminated by NULL. Returns the result of the call + on success, or NULL on failure. This is the equivalent of + the Python expression: o.method(args). + */ + + + /* Implemented elsewhere: + + long PyObject_Hash(PyObject *o); + + Compute and return the hash, hash_value, of an object, o. On + failure, return -1. This is the equivalent of the Python + expression: hash(o). + + */ + + + /* Implemented elsewhere: + + int PyObject_IsTrue(PyObject *o); + + Returns 1 if the object, o, is considered to be true, 0 if o is + considered to be false and -1 on failure. This is equivalent to the + Python expression: not not o + + */ + + /* Implemented elsewhere: + + int PyObject_Not(PyObject *o); + + Returns 0 if the object, o, is considered to be true, 1 if o is + considered to be false and -1 on failure. This is equivalent to the + Python expression: not o + + */ + + PyAPI_FUNC(PyObject *) PyObject_Type(PyObject *o); + + /* + On success, returns a type object corresponding to the object + type of object o. On failure, returns NULL. This is + equivalent to the Python expression: type(o). + */ + + PyAPI_FUNC(Py_ssize_t) PyObject_Size(PyObject *o); + + /* + Return the size of object o. If the object, o, provides + both sequence and mapping protocols, the sequence size is + returned. On error, -1 is returned. This is the equivalent + to the Python expression: len(o). + + */ + + /* For DLL compatibility */ +#undef PyObject_Length + PyAPI_FUNC(Py_ssize_t) PyObject_Length(PyObject *o); +#define PyObject_Length PyObject_Size + + PyAPI_FUNC(Py_ssize_t) _PyObject_LengthHint(PyObject *o); + + /* + Return the size of object o. If the object, o, provides + both sequence and mapping protocols, the sequence size is + returned. On error, -1 is returned. If the object provides + a __length_hint__() method, its value is returned. This is an + internal undocumented API provided for performance reasons; + for compatibility, don't use it outside the core. This is the + equivalent to the Python expression: + try: + return len(o) + except (AttributeError, TypeError): + exc_type, exc_value, exc_tb = sys.exc_info() + try: + return o.__length_hint__() + except: + pass + raise exc_type, exc_value, exc_tb + */ + + PyAPI_FUNC(PyObject *) PyObject_GetItem(PyObject *o, PyObject *key); + + /* + Return element of o corresponding to the object, key, or NULL + on failure. This is the equivalent of the Python expression: + o[key]. + + */ + + PyAPI_FUNC(int) PyObject_SetItem(PyObject *o, PyObject *key, PyObject *v); + + /* + Map the object, key, to the value, v. Returns + -1 on failure. This is the equivalent of the Python + statement: o[key]=v. + */ + + PyAPI_FUNC(int) PyObject_DelItemString(PyObject *o, char *key); + + /* + Remove the mapping for object, key, from the object *o. + Returns -1 on failure. This is equivalent to + the Python statement: del o[key]. + */ + + PyAPI_FUNC(int) PyObject_DelItem(PyObject *o, PyObject *key); + + /* + Delete the mapping for key from *o. Returns -1 on failure. + This is the equivalent of the Python statement: del o[key]. + */ + + PyAPI_FUNC(int) PyObject_AsCharBuffer(PyObject *obj, + const char **buffer, + Py_ssize_t *buffer_len); + + /* + Takes an arbitrary object which must support the (character, + single segment) buffer interface and returns a pointer to a + read-only memory location useable as character based input + for subsequent processing. + + 0 is returned on success. buffer and buffer_len are only + set in case no error occurs. Otherwise, -1 is returned and + an exception set. + + */ + + PyAPI_FUNC(int) PyObject_CheckReadBuffer(PyObject *obj); + + /* + Checks whether an arbitrary object supports the (character, + single segment) buffer interface. Returns 1 on success, 0 + on failure. + + */ + + PyAPI_FUNC(int) PyObject_AsReadBuffer(PyObject *obj, + const void **buffer, + Py_ssize_t *buffer_len); + + /* + Same as PyObject_AsCharBuffer() except that this API expects + (readable, single segment) buffer interface and returns a + pointer to a read-only memory location which can contain + arbitrary data. + + 0 is returned on success. buffer and buffer_len are only + set in case no error occurrs. Otherwise, -1 is returned and + an exception set. + + */ + + PyAPI_FUNC(int) PyObject_AsWriteBuffer(PyObject *obj, + void **buffer, + Py_ssize_t *buffer_len); + + /* + Takes an arbitrary object which must support the (writeable, + single segment) buffer interface and returns a pointer to a + writeable memory location in buffer of size buffer_len. + + 0 is returned on success. buffer and buffer_len are only + set in case no error occurrs. Otherwise, -1 is returned and + an exception set. + + */ + +/* Iterators */ + + PyAPI_FUNC(PyObject *) PyObject_GetIter(PyObject *); + /* Takes an object and returns an iterator for it. + This is typically a new iterator but if the argument + is an iterator, this returns itself. */ + +#define PyIter_Check(obj) \ + (PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \ + (obj)->ob_type->tp_iternext != NULL) + + PyAPI_FUNC(PyObject *) PyIter_Next(PyObject *); + /* Takes an iterator object and calls its tp_iternext slot, + returning the next value. If the iterator is exhausted, + this returns NULL without setting an exception. + NULL with an exception means an error occurred. */ + +/* Number Protocol:*/ + + PyAPI_FUNC(int) PyNumber_Check(PyObject *o); + + /* + Returns 1 if the object, o, provides numeric protocols, and + false otherwise. + + This function always succeeds. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Add(PyObject *o1, PyObject *o2); + + /* + Returns the result of adding o1 and o2, or null on failure. + This is the equivalent of the Python expression: o1+o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Subtract(PyObject *o1, PyObject *o2); + + /* + Returns the result of subtracting o2 from o1, or null on + failure. This is the equivalent of the Python expression: + o1-o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Multiply(PyObject *o1, PyObject *o2); + + /* + Returns the result of multiplying o1 and o2, or null on + failure. This is the equivalent of the Python expression: + o1*o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Divide(PyObject *o1, PyObject *o2); + + /* + Returns the result of dividing o1 by o2, or null on failure. + This is the equivalent of the Python expression: o1/o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_FloorDivide(PyObject *o1, PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving an integral result, + or null on failure. + This is the equivalent of the Python expression: o1//o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_TrueDivide(PyObject *o1, PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving a float result, + or null on failure. + This is the equivalent of the Python expression: o1/o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2); + + /* + Returns the remainder of dividing o1 by o2, or null on + failure. This is the equivalent of the Python expression: + o1%o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Divmod(PyObject *o1, PyObject *o2); + + /* + See the built-in function divmod. Returns NULL on failure. + This is the equivalent of the Python expression: + divmod(o1,o2). + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Power(PyObject *o1, PyObject *o2, + PyObject *o3); + + /* + See the built-in function pow. Returns NULL on failure. + This is the equivalent of the Python expression: + pow(o1,o2,o3), where o3 is optional. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Negative(PyObject *o); + + /* + Returns the negation of o on success, or null on failure. + This is the equivalent of the Python expression: -o. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Positive(PyObject *o); + + /* + Returns the (what?) of o on success, or NULL on failure. + This is the equivalent of the Python expression: +o. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Absolute(PyObject *o); + + /* + Returns the absolute value of o, or null on failure. This is + the equivalent of the Python expression: abs(o). + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Invert(PyObject *o); + + /* + Returns the bitwise negation of o on success, or NULL on + failure. This is the equivalent of the Python expression: + ~o. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Lshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of left shifting o1 by o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1 << o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Rshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of right shifting o1 by o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1 >> o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_And(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise and of o1 and o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1&o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Xor(PyObject *o1, PyObject *o2); + + /* + Returns the bitwise exclusive or of o1 by o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1^o2. + + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Or(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise or on o1 and o2 on success, or + NULL on failure. This is the equivalent of the Python + expression: o1|o2. + + */ + + /* Implemented elsewhere: + + int PyNumber_Coerce(PyObject **p1, PyObject **p2); + + This function takes the addresses of two variables of type + PyObject*. + + If the objects pointed to by *p1 and *p2 have the same type, + increment their reference count and return 0 (success). + If the objects can be converted to a common numeric type, + replace *p1 and *p2 by their converted value (with 'new' + reference counts), and return 0. + If no conversion is possible, or if some other error occurs, + return -1 (failure) and don't increment the reference counts. + The call PyNumber_Coerce(&o1, &o2) is equivalent to the Python + statement o1, o2 = coerce(o1, o2). + + */ + +#define PyIndex_Check(obj) \ + ((obj)->ob_type->tp_as_number != NULL && \ + PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_INDEX) && \ + (obj)->ob_type->tp_as_number->nb_index != NULL) + + PyAPI_FUNC(PyObject *) PyNumber_Index(PyObject *o); + + /* + Returns the object converted to a Python long or int + or NULL with an error raised on failure. + */ + + PyAPI_FUNC(Py_ssize_t) PyNumber_AsSsize_t(PyObject *o, PyObject *exc); + + /* + Returns the object converted to Py_ssize_t by going through + PyNumber_Index first. If an overflow error occurs while + converting the int-or-long to Py_ssize_t, then the second argument + is the error-type to return. If it is NULL, then the overflow error + is cleared and the value is clipped. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Int(PyObject *o); + + /* + Returns the o converted to an integer object on success, or + NULL on failure. This is the equivalent of the Python + expression: int(o). + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Long(PyObject *o); + + /* + Returns the o converted to a long integer object on success, + or NULL on failure. This is the equivalent of the Python + expression: long(o). + + */ + + PyAPI_FUNC(PyObject *) PyNumber_Float(PyObject *o); + + /* + Returns the o converted to a float object on success, or NULL + on failure. This is the equivalent of the Python expression: + float(o). + */ + +/* In-place variants of (some of) the above number protocol functions */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceAdd(PyObject *o1, PyObject *o2); + + /* + Returns the result of adding o2 to o1, possibly in-place, or null + on failure. This is the equivalent of the Python expression: + o1 += o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceSubtract(PyObject *o1, PyObject *o2); + + /* + Returns the result of subtracting o2 from o1, possibly in-place or + null on failure. This is the equivalent of the Python expression: + o1 -= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceMultiply(PyObject *o1, PyObject *o2); + + /* + Returns the result of multiplying o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 *= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceDivide(PyObject *o1, PyObject *o2); + + /* + Returns the result of dividing o1 by o2, possibly in-place, or null + on failure. This is the equivalent of the Python expression: + o1 /= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceFloorDivide(PyObject *o1, + PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving an integral result, + possibly in-place, or null on failure. + This is the equivalent of the Python expression: + o1 /= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceTrueDivide(PyObject *o1, + PyObject *o2); + + /* + Returns the result of dividing o1 by o2 giving a float result, + possibly in-place, or null on failure. + This is the equivalent of the Python expression: + o1 /= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2); + + /* + Returns the remainder of dividing o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 %= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlacePower(PyObject *o1, PyObject *o2, + PyObject *o3); + + /* + Returns the result of raising o1 to the power of o2, possibly + in-place, or null on failure. This is the equivalent of the Python + expression: o1 **= o2, or pow(o1, o2, o3) if o3 is present. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceLshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of left shifting o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 <<= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceRshift(PyObject *o1, PyObject *o2); + + /* + Returns the result of right shifting o1 by o2, possibly in-place or + null on failure. This is the equivalent of the Python expression: + o1 >>= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceAnd(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise and of o1 and o2, possibly in-place, + or null on failure. This is the equivalent of the Python + expression: o1 &= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceXor(PyObject *o1, PyObject *o2); + + /* + Returns the bitwise exclusive or of o1 by o2, possibly in-place, or + null on failure. This is the equivalent of the Python expression: + o1 ^= o2. + + */ + + PyAPI_FUNC(PyObject *) PyNumber_InPlaceOr(PyObject *o1, PyObject *o2); + + /* + Returns the result of bitwise or of o1 and o2, possibly in-place, + or null on failure. This is the equivalent of the Python + expression: o1 |= o2. + + */ + + +/* Sequence protocol:*/ + + PyAPI_FUNC(int) PySequence_Check(PyObject *o); + + /* + Return 1 if the object provides sequence protocol, and zero + otherwise. + + This function always succeeds. + + */ + + PyAPI_FUNC(Py_ssize_t) PySequence_Size(PyObject *o); + + /* + Return the size of sequence object o, or -1 on failure. + + */ + + /* For DLL compatibility */ +#undef PySequence_Length + PyAPI_FUNC(Py_ssize_t) PySequence_Length(PyObject *o); +#define PySequence_Length PySequence_Size + + + PyAPI_FUNC(PyObject *) PySequence_Concat(PyObject *o1, PyObject *o2); + + /* + Return the concatenation of o1 and o2 on success, and NULL on + failure. This is the equivalent of the Python + expression: o1+o2. + + */ + + PyAPI_FUNC(PyObject *) PySequence_Repeat(PyObject *o, Py_ssize_t count); + + /* + Return the result of repeating sequence object o count times, + or NULL on failure. This is the equivalent of the Python + expression: o1*count. + + */ + + PyAPI_FUNC(PyObject *) PySequence_GetItem(PyObject *o, Py_ssize_t i); + + /* + Return the ith element of o, or NULL on failure. This is the + equivalent of the Python expression: o[i]. + */ + + PyAPI_FUNC(PyObject *) PySequence_GetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); + + /* + Return the slice of sequence object o between i1 and i2, or + NULL on failure. This is the equivalent of the Python + expression: o[i1:i2]. + + */ + + PyAPI_FUNC(int) PySequence_SetItem(PyObject *o, Py_ssize_t i, PyObject *v); + + /* + Assign object v to the ith element of o. Returns + -1 on failure. This is the equivalent of the Python + statement: o[i]=v. + + */ + + PyAPI_FUNC(int) PySequence_DelItem(PyObject *o, Py_ssize_t i); + + /* + Delete the ith element of object v. Returns + -1 on failure. This is the equivalent of the Python + statement: del o[i]. + */ + + PyAPI_FUNC(int) PySequence_SetSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2, + PyObject *v); + + /* + Assign the sequence object, v, to the slice in sequence + object, o, from i1 to i2. Returns -1 on failure. This is the + equivalent of the Python statement: o[i1:i2]=v. + */ + + PyAPI_FUNC(int) PySequence_DelSlice(PyObject *o, Py_ssize_t i1, Py_ssize_t i2); + + /* + Delete the slice in sequence object, o, from i1 to i2. + Returns -1 on failure. This is the equivalent of the Python + statement: del o[i1:i2]. + */ + + PyAPI_FUNC(PyObject *) PySequence_Tuple(PyObject *o); + + /* + Returns the sequence, o, as a tuple on success, and NULL on failure. + This is equivalent to the Python expression: tuple(o) + */ + + + PyAPI_FUNC(PyObject *) PySequence_List(PyObject *o); + /* + Returns the sequence, o, as a list on success, and NULL on failure. + This is equivalent to the Python expression: list(o) + */ + + PyAPI_FUNC(PyObject *) PySequence_Fast(PyObject *o, const char* m); + /* + Returns the sequence, o, as a tuple, unless it's already a + tuple or list. Use PySequence_Fast_GET_ITEM to access the + members of this list, and PySequence_Fast_GET_SIZE to get its length. + + Returns NULL on failure. If the object does not support iteration, + raises a TypeError exception with m as the message text. + */ + +#define PySequence_Fast_GET_SIZE(o) \ + (PyList_Check(o) ? PyList_GET_SIZE(o) : PyTuple_GET_SIZE(o)) + /* + Return the size of o, assuming that o was returned by + PySequence_Fast and is not NULL. + */ + +#define PySequence_Fast_GET_ITEM(o, i)\ + (PyList_Check(o) ? PyList_GET_ITEM(o, i) : PyTuple_GET_ITEM(o, i)) + /* + Return the ith element of o, assuming that o was returned by + PySequence_Fast, and that i is within bounds. + */ + +#define PySequence_ITEM(o, i)\ + ( o->ob_type->tp_as_sequence->sq_item(o, i) ) + /* Assume tp_as_sequence and sq_item exist and that i does not + need to be corrected for a negative index + */ + +#define PySequence_Fast_ITEMS(sf) \ + (PyList_Check(sf) ? ((PyListObject *)(sf))->ob_item \ + : ((PyTupleObject *)(sf))->ob_item) + /* Return a pointer to the underlying item array for + an object retured by PySequence_Fast */ + + PyAPI_FUNC(Py_ssize_t) PySequence_Count(PyObject *o, PyObject *value); + + /* + Return the number of occurrences on value on o, that is, + return the number of keys for which o[key]==value. On + failure, return -1. This is equivalent to the Python + expression: o.count(value). + */ + + PyAPI_FUNC(int) PySequence_Contains(PyObject *seq, PyObject *ob); + /* + Return -1 if error; 1 if ob in seq; 0 if ob not in seq. + Use __contains__ if possible, else _PySequence_IterSearch(). + */ + +#define PY_ITERSEARCH_COUNT 1 +#define PY_ITERSEARCH_INDEX 2 +#define PY_ITERSEARCH_CONTAINS 3 + PyAPI_FUNC(Py_ssize_t) _PySequence_IterSearch(PyObject *seq, + PyObject *obj, int operation); + /* + Iterate over seq. Result depends on the operation: + PY_ITERSEARCH_COUNT: return # of times obj appears in seq; -1 if + error. + PY_ITERSEARCH_INDEX: return 0-based index of first occurrence of + obj in seq; set ValueError and return -1 if none found; + also return -1 on error. + PY_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on + error. + */ + +/* For DLL-level backwards compatibility */ +#undef PySequence_In + PyAPI_FUNC(int) PySequence_In(PyObject *o, PyObject *value); + +/* For source-level backwards compatibility */ +#define PySequence_In PySequence_Contains + + /* + Determine if o contains value. If an item in o is equal to + X, return 1, otherwise return 0. On error, return -1. This + is equivalent to the Python expression: value in o. + */ + + PyAPI_FUNC(Py_ssize_t) PySequence_Index(PyObject *o, PyObject *value); + + /* + Return the first index for which o[i]=value. On error, + return -1. This is equivalent to the Python + expression: o.index(value). + */ + +/* In-place versions of some of the above Sequence functions. */ + + PyAPI_FUNC(PyObject *) PySequence_InPlaceConcat(PyObject *o1, PyObject *o2); + + /* + Append o2 to o1, in-place when possible. Return the resulting + object, which could be o1, or NULL on failure. This is the + equivalent of the Python expression: o1 += o2. + + */ + + PyAPI_FUNC(PyObject *) PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count); + + /* + Repeat o1 by count, in-place when possible. Return the resulting + object, which could be o1, or NULL on failure. This is the + equivalent of the Python expression: o1 *= count. + + */ + +/* Mapping protocol:*/ + + PyAPI_FUNC(int) PyMapping_Check(PyObject *o); + + /* + Return 1 if the object provides mapping protocol, and zero + otherwise. + + This function always succeeds. + */ + + PyAPI_FUNC(Py_ssize_t) PyMapping_Size(PyObject *o); + + /* + Returns the number of keys in object o on success, and -1 on + failure. For objects that do not provide sequence protocol, + this is equivalent to the Python expression: len(o). + */ + + /* For DLL compatibility */ +#undef PyMapping_Length + PyAPI_FUNC(Py_ssize_t) PyMapping_Length(PyObject *o); +#define PyMapping_Length PyMapping_Size + + + /* implemented as a macro: + + int PyMapping_DelItemString(PyObject *o, char *key); + + Remove the mapping for object, key, from the object *o. + Returns -1 on failure. This is equivalent to + the Python statement: del o[key]. + */ +#define PyMapping_DelItemString(O,K) PyObject_DelItemString((O),(K)) + + /* implemented as a macro: + + int PyMapping_DelItem(PyObject *o, PyObject *key); + + Remove the mapping for object, key, from the object *o. + Returns -1 on failure. This is equivalent to + the Python statement: del o[key]. + */ +#define PyMapping_DelItem(O,K) PyObject_DelItem((O),(K)) + + PyAPI_FUNC(int) PyMapping_HasKeyString(PyObject *o, char *key); + + /* + On success, return 1 if the mapping object has the key, key, + and 0 otherwise. This is equivalent to the Python expression: + o.has_key(key). + + This function always succeeds. + */ + + PyAPI_FUNC(int) PyMapping_HasKey(PyObject *o, PyObject *key); + + /* + Return 1 if the mapping object has the key, key, + and 0 otherwise. This is equivalent to the Python expression: + o.has_key(key). + + This function always succeeds. + + */ + + /* Implemented as macro: + + PyObject *PyMapping_Keys(PyObject *o); + + On success, return a list of the keys in object o. On + failure, return NULL. This is equivalent to the Python + expression: o.keys(). + */ +#define PyMapping_Keys(O) PyObject_CallMethod(O,"keys",NULL) + + /* Implemented as macro: + + PyObject *PyMapping_Values(PyObject *o); + + On success, return a list of the values in object o. On + failure, return NULL. This is equivalent to the Python + expression: o.values(). + */ +#define PyMapping_Values(O) PyObject_CallMethod(O,"values",NULL) + + /* Implemented as macro: + + PyObject *PyMapping_Items(PyObject *o); + + On success, return a list of the items in object o, where + each item is a tuple containing a key-value pair. On + failure, return NULL. This is equivalent to the Python + expression: o.items(). + + */ +#define PyMapping_Items(O) PyObject_CallMethod(O,"items",NULL) + + PyAPI_FUNC(PyObject *) PyMapping_GetItemString(PyObject *o, char *key); + + /* + Return element of o corresponding to the object, key, or NULL + on failure. This is the equivalent of the Python expression: + o[key]. + */ + + PyAPI_FUNC(int) PyMapping_SetItemString(PyObject *o, char *key, + PyObject *value); + + /* + Map the object, key, to the value, v. Returns + -1 on failure. This is the equivalent of the Python + statement: o[key]=v. + */ + + +PyAPI_FUNC(int) PyObject_IsInstance(PyObject *object, PyObject *typeorclass); + /* isinstance(object, typeorclass) */ + +PyAPI_FUNC(int) PyObject_IsSubclass(PyObject *object, PyObject *typeorclass); + /* issubclass(object, typeorclass) */ + + +#ifdef __cplusplus +} +#endif +#endif /* Py_ABSTRACTOBJECT_H */ diff --git a/sys/src/cmd/python/Include/asdl.h b/sys/src/cmd/python/Include/asdl.h new file mode 100644 index 000000000..84e837e75 --- /dev/null +++ b/sys/src/cmd/python/Include/asdl.h @@ -0,0 +1,45 @@ +#ifndef Py_ASDL_H +#define Py_ASDL_H + +typedef PyObject * identifier; +typedef PyObject * string; +typedef PyObject * object; + +#ifndef __cplusplus +typedef enum {false, true} bool; +#endif + +/* It would be nice if the code generated by asdl_c.py was completely + independent of Python, but it is a goal the requires too much work + at this stage. So, for example, I'll represent identifiers as + interned Python strings. +*/ + +/* XXX A sequence should be typed so that its use can be typechecked. */ + +typedef struct { + int size; + void *elements[1]; +} asdl_seq; + +typedef struct { + int size; + int elements[1]; +} asdl_int_seq; + +asdl_seq *asdl_seq_new(int size, PyArena *arena); +asdl_int_seq *asdl_int_seq_new(int size, PyArena *arena); + +#define asdl_seq_GET(S, I) (S)->elements[(I)] +#define asdl_seq_LEN(S) ((S) == NULL ? 0 : (S)->size) +#ifdef Py_DEBUG +#define asdl_seq_SET(S, I, V) { \ + int _asdl_i = (I); \ + assert((S) && _asdl_i < (S)->size); \ + (S)->elements[_asdl_i] = (V); \ +} +#else +#define asdl_seq_SET(S, I, V) (S)->elements[I] = (V) +#endif + +#endif /* !Py_ASDL_H */ diff --git a/sys/src/cmd/python/Include/ast.h b/sys/src/cmd/python/Include/ast.h new file mode 100644 index 000000000..cc14b7fd7 --- /dev/null +++ b/sys/src/cmd/python/Include/ast.h @@ -0,0 +1,13 @@ +#ifndef Py_AST_H +#define Py_AST_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(mod_ty) PyAST_FromNode(const node *, PyCompilerFlags *flags, + const char *, PyArena *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_AST_H */ diff --git a/sys/src/cmd/python/Include/bitset.h b/sys/src/cmd/python/Include/bitset.h new file mode 100644 index 000000000..faeb41913 --- /dev/null +++ b/sys/src/cmd/python/Include/bitset.h @@ -0,0 +1,32 @@ + +#ifndef Py_BITSET_H +#define Py_BITSET_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Bitset interface */ + +#define BYTE char + +typedef BYTE *bitset; + +bitset newbitset(int nbits); +void delbitset(bitset bs); +#define testbit(ss, ibit) (((ss)[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0) +int addbit(bitset bs, int ibit); /* Returns 0 if already set */ +int samebitset(bitset bs1, bitset bs2, int nbits); +void mergebitset(bitset bs1, bitset bs2, int nbits); + +#define BITSPERBYTE (8*sizeof(BYTE)) +#define NBYTES(nbits) (((nbits) + BITSPERBYTE - 1) / BITSPERBYTE) + +#define BIT2BYTE(ibit) ((ibit) / BITSPERBYTE) +#define BIT2SHIFT(ibit) ((ibit) % BITSPERBYTE) +#define BIT2MASK(ibit) (1 << BIT2SHIFT(ibit)) +#define BYTE2BIT(ibyte) ((ibyte) * BITSPERBYTE) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BITSET_H */ diff --git a/sys/src/cmd/python/Include/boolobject.h b/sys/src/cmd/python/Include/boolobject.h new file mode 100644 index 000000000..7f9ad01a0 --- /dev/null +++ b/sys/src/cmd/python/Include/boolobject.h @@ -0,0 +1,36 @@ +/* Boolean object interface */ + +#ifndef Py_BOOLOBJECT_H +#define Py_BOOLOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +typedef PyIntObject PyBoolObject; + +PyAPI_DATA(PyTypeObject) PyBool_Type; + +#define PyBool_Check(x) ((x)->ob_type == &PyBool_Type) + +/* Py_False and Py_True are the only two bools in existence. +Don't forget to apply Py_INCREF() when returning either!!! */ + +/* Don't use these directly */ +PyAPI_DATA(PyIntObject) _Py_ZeroStruct, _Py_TrueStruct; + +/* Use these macros */ +#define Py_False ((PyObject *) &_Py_ZeroStruct) +#define Py_True ((PyObject *) &_Py_TrueStruct) + +/* Macros for returning Py_True or Py_False, respectively */ +#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True +#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False + +/* Function to return a bool from a C long */ +PyAPI_FUNC(PyObject *) PyBool_FromLong(long); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BOOLOBJECT_H */ diff --git a/sys/src/cmd/python/Include/bufferobject.h b/sys/src/cmd/python/Include/bufferobject.h new file mode 100644 index 000000000..75ba4963f --- /dev/null +++ b/sys/src/cmd/python/Include/bufferobject.h @@ -0,0 +1,33 @@ + +/* Buffer object interface */ + +/* Note: the object's structure is private */ + +#ifndef Py_BUFFEROBJECT_H +#define Py_BUFFEROBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +PyAPI_DATA(PyTypeObject) PyBuffer_Type; + +#define PyBuffer_Check(op) ((op)->ob_type == &PyBuffer_Type) + +#define Py_END_OF_BUFFER (-1) + +PyAPI_FUNC(PyObject *) PyBuffer_FromObject(PyObject *base, + Py_ssize_t offset, Py_ssize_t size); +PyAPI_FUNC(PyObject *) PyBuffer_FromReadWriteObject(PyObject *base, + Py_ssize_t offset, + Py_ssize_t size); + +PyAPI_FUNC(PyObject *) PyBuffer_FromMemory(void *ptr, Py_ssize_t size); +PyAPI_FUNC(PyObject *) PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size); + +PyAPI_FUNC(PyObject *) PyBuffer_New(Py_ssize_t size); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_BUFFEROBJECT_H */ diff --git a/sys/src/cmd/python/Include/cStringIO.h b/sys/src/cmd/python/Include/cStringIO.h new file mode 100644 index 000000000..25fc9dd0d --- /dev/null +++ b/sys/src/cmd/python/Include/cStringIO.h @@ -0,0 +1,70 @@ +#ifndef Py_CSTRINGIO_H +#define Py_CSTRINGIO_H +#ifdef __cplusplus +extern "C" { +#endif +/* + + This header provides access to cStringIO objects from C. + Functions are provided for calling cStringIO objects and + macros are provided for testing whether you have cStringIO + objects. + + Before calling any of the functions or macros, you must initialize + the routines with: + + PycString_IMPORT + + This would typically be done in your init function. + +*/ +#define PycString_IMPORT \ + PycStringIO = (struct PycStringIO_CAPI*)PyCObject_Import("cStringIO", \ + "cStringIO_CAPI") + +/* Basic functions to manipulate cStringIO objects from C */ + +static struct PycStringIO_CAPI { + + /* Read a string from an input object. If the last argument + is -1, the remainder will be read. + */ + int(*cread)(PyObject *, char **, Py_ssize_t); + + /* Read a line from an input object. Returns the length of the read + line as an int and a pointer inside the object buffer as char** (so + the caller doesn't have to provide its own buffer as destination). + */ + int(*creadline)(PyObject *, char **); + + /* Write a string to an output object*/ + int(*cwrite)(PyObject *, const char *, Py_ssize_t); + + /* Get the output object as a Python string (returns new reference). */ + PyObject *(*cgetvalue)(PyObject *); + + /* Create a new output object */ + PyObject *(*NewOutput)(int); + + /* Create an input object from a Python string + (copies the Python string reference). + */ + PyObject *(*NewInput)(PyObject *); + + /* The Python types for cStringIO input and output objects. + Note that you can do input on an output object. + */ + PyTypeObject *InputType, *OutputType; + +} *PycStringIO; + +/* These can be used to test if you have one */ +#define PycStringIO_InputCheck(O) \ + ((O)->ob_type==PycStringIO->InputType) +#define PycStringIO_OutputCheck(O) \ + ((O)->ob_type==PycStringIO->OutputType) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CSTRINGIO_H */ diff --git a/sys/src/cmd/python/Include/cellobject.h b/sys/src/cmd/python/Include/cellobject.h new file mode 100644 index 000000000..fd186e28c --- /dev/null +++ b/sys/src/cmd/python/Include/cellobject.h @@ -0,0 +1,28 @@ +/* Cell object interface */ + +#ifndef Py_CELLOBJECT_H +#define Py_CELLOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + PyObject *ob_ref; /* Content of the cell or NULL when empty */ +} PyCellObject; + +PyAPI_DATA(PyTypeObject) PyCell_Type; + +#define PyCell_Check(op) ((op)->ob_type == &PyCell_Type) + +PyAPI_FUNC(PyObject *) PyCell_New(PyObject *); +PyAPI_FUNC(PyObject *) PyCell_Get(PyObject *); +PyAPI_FUNC(int) PyCell_Set(PyObject *, PyObject *); + +#define PyCell_GET(op) (((PyCellObject *)(op))->ob_ref) +#define PyCell_SET(op, v) (((PyCellObject *)(op))->ob_ref = v) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TUPLEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/ceval.h b/sys/src/cmd/python/Include/ceval.h new file mode 100644 index 000000000..f4411977f --- /dev/null +++ b/sys/src/cmd/python/Include/ceval.h @@ -0,0 +1,157 @@ +#ifndef Py_CEVAL_H +#define Py_CEVAL_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Interface to random parts in ceval.c */ + +PyAPI_FUNC(PyObject *) PyEval_CallObjectWithKeywords( + PyObject *, PyObject *, PyObject *); + +/* DLL-level Backwards compatibility: */ +#undef PyEval_CallObject +PyAPI_FUNC(PyObject *) PyEval_CallObject(PyObject *, PyObject *); + +/* Inline this */ +#define PyEval_CallObject(func,arg) \ + PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) + +PyAPI_FUNC(PyObject *) PyEval_CallFunction(PyObject *obj, + const char *format, ...); +PyAPI_FUNC(PyObject *) PyEval_CallMethod(PyObject *obj, + const char *methodname, + const char *format, ...); + +PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); +PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); + +struct _frame; /* Avoid including frameobject.h */ + +PyAPI_FUNC(PyObject *) PyEval_GetBuiltins(void); +PyAPI_FUNC(PyObject *) PyEval_GetGlobals(void); +PyAPI_FUNC(PyObject *) PyEval_GetLocals(void); +PyAPI_FUNC(struct _frame *) PyEval_GetFrame(void); +PyAPI_FUNC(int) PyEval_GetRestricted(void); + +/* Look at the current frame's (if any) code's co_flags, and turn on + the corresponding compiler flags in cf->cf_flags. Return 1 if any + flag was set, else return 0. */ +PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf); + +PyAPI_FUNC(int) Py_FlushLine(void); + +PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg); +PyAPI_FUNC(int) Py_MakePendingCalls(void); + +/* Protection against deeply nested recursive calls */ +PyAPI_FUNC(void) Py_SetRecursionLimit(int); +PyAPI_FUNC(int) Py_GetRecursionLimit(void); + +#define Py_EnterRecursiveCall(where) \ + (_Py_MakeRecCheck(PyThreadState_GET()->recursion_depth) && \ + _Py_CheckRecursiveCall(where)) +#define Py_LeaveRecursiveCall() \ + (--PyThreadState_GET()->recursion_depth) +PyAPI_FUNC(int) _Py_CheckRecursiveCall(char *where); +PyAPI_DATA(int) _Py_CheckRecursionLimit; +#ifdef USE_STACKCHECK +# define _Py_MakeRecCheck(x) (++(x) > --_Py_CheckRecursionLimit) +#else +# define _Py_MakeRecCheck(x) (++(x) > _Py_CheckRecursionLimit) +#endif + +PyAPI_FUNC(const char *) PyEval_GetFuncName(PyObject *); +PyAPI_FUNC(const char *) PyEval_GetFuncDesc(PyObject *); + +PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *); +PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *); +PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc); + +/* this used to be handled on a per-thread basis - now just two globals */ +PyAPI_DATA(volatile int) _Py_Ticker; +PyAPI_DATA(int) _Py_CheckInterval; + +/* Interface for threads. + + A module that plans to do a blocking system call (or something else + that lasts a long time and doesn't touch Python data) can allow other + threads to run as follows: + + ...preparations here... + Py_BEGIN_ALLOW_THREADS + ...blocking system call here... + Py_END_ALLOW_THREADS + ...interpret result here... + + The Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS pair expands to a + {}-surrounded block. + To leave the block in the middle (e.g., with return), you must insert + a line containing Py_BLOCK_THREADS before the return, e.g. + + if (...premature_exit...) { + Py_BLOCK_THREADS + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + + An alternative is: + + Py_BLOCK_THREADS + if (...premature_exit...) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_UNBLOCK_THREADS + + For convenience, that the value of 'errno' is restored across + Py_END_ALLOW_THREADS and Py_BLOCK_THREADS. + + WARNING: NEVER NEST CALLS TO Py_BEGIN_ALLOW_THREADS AND + Py_END_ALLOW_THREADS!!! + + The function PyEval_InitThreads() should be called only from + initthread() in "threadmodule.c". + + Note that not yet all candidates have been converted to use this + mechanism! +*/ + +PyAPI_FUNC(PyThreadState *) PyEval_SaveThread(void); +PyAPI_FUNC(void) PyEval_RestoreThread(PyThreadState *); + +#ifdef WITH_THREAD + +PyAPI_FUNC(int) PyEval_ThreadsInitialized(void); +PyAPI_FUNC(void) PyEval_InitThreads(void); +PyAPI_FUNC(void) PyEval_AcquireLock(void); +PyAPI_FUNC(void) PyEval_ReleaseLock(void); +PyAPI_FUNC(void) PyEval_AcquireThread(PyThreadState *tstate); +PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate); +PyAPI_FUNC(void) PyEval_ReInitThreads(void); + +#define Py_BEGIN_ALLOW_THREADS { \ + PyThreadState *_save; \ + _save = PyEval_SaveThread(); +#define Py_BLOCK_THREADS PyEval_RestoreThread(_save); +#define Py_UNBLOCK_THREADS _save = PyEval_SaveThread(); +#define Py_END_ALLOW_THREADS PyEval_RestoreThread(_save); \ + } + +#else /* !WITH_THREAD */ + +#define Py_BEGIN_ALLOW_THREADS { +#define Py_BLOCK_THREADS +#define Py_UNBLOCK_THREADS +#define Py_END_ALLOW_THREADS } + +#endif /* !WITH_THREAD */ + +PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CEVAL_H */ diff --git a/sys/src/cmd/python/Include/classobject.h b/sys/src/cmd/python/Include/classobject.h new file mode 100644 index 000000000..8f8db7d81 --- /dev/null +++ b/sys/src/cmd/python/Include/classobject.h @@ -0,0 +1,81 @@ + +/* Class object interface */ + +/* Revealing some structures (not for general use) */ + +#ifndef Py_CLASSOBJECT_H +#define Py_CLASSOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + PyObject *cl_bases; /* A tuple of class objects */ + PyObject *cl_dict; /* A dictionary */ + PyObject *cl_name; /* A string */ + /* The following three are functions or NULL */ + PyObject *cl_getattr; + PyObject *cl_setattr; + PyObject *cl_delattr; +} PyClassObject; + +typedef struct { + PyObject_HEAD + PyClassObject *in_class; /* The class object */ + PyObject *in_dict; /* A dictionary */ + PyObject *in_weakreflist; /* List of weak references */ +} PyInstanceObject; + +typedef struct { + PyObject_HEAD + PyObject *im_func; /* The callable object implementing the method */ + PyObject *im_self; /* The instance it is bound to, or NULL */ + PyObject *im_class; /* The class that asked for the method */ + PyObject *im_weakreflist; /* List of weak references */ +} PyMethodObject; + +PyAPI_DATA(PyTypeObject) PyClass_Type, PyInstance_Type, PyMethod_Type; + +#define PyClass_Check(op) ((op)->ob_type == &PyClass_Type) +#define PyInstance_Check(op) ((op)->ob_type == &PyInstance_Type) +#define PyMethod_Check(op) ((op)->ob_type == &PyMethod_Type) + +PyAPI_FUNC(PyObject *) PyClass_New(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyInstance_New(PyObject *, PyObject *, + PyObject *); +PyAPI_FUNC(PyObject *) PyInstance_NewRaw(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyMethod_New(PyObject *, PyObject *, PyObject *); + +PyAPI_FUNC(PyObject *) PyMethod_Function(PyObject *); +PyAPI_FUNC(PyObject *) PyMethod_Self(PyObject *); +PyAPI_FUNC(PyObject *) PyMethod_Class(PyObject *); + +/* Look up attribute with name (a string) on instance object pinst, using + * only the instance and base class dicts. If a descriptor is found in + * a class dict, the descriptor is returned without calling it. + * Returns NULL if nothing found, else a borrowed reference to the + * value associated with name in the dict in which name was found. + * The point of this routine is that it never calls arbitrary Python + * code, so is always "safe": all it does is dict lookups. The function + * can't fail, never sets an exception, and NULL is not an error (it just + * means "not found"). + */ +PyAPI_FUNC(PyObject *) _PyInstance_Lookup(PyObject *pinst, PyObject *name); + +/* Macros for direct access to these values. Type checks are *not* + done, so use with care. */ +#define PyMethod_GET_FUNCTION(meth) \ + (((PyMethodObject *)meth) -> im_func) +#define PyMethod_GET_SELF(meth) \ + (((PyMethodObject *)meth) -> im_self) +#define PyMethod_GET_CLASS(meth) \ + (((PyMethodObject *)meth) -> im_class) + +PyAPI_FUNC(int) PyClass_IsSubclass(PyObject *, PyObject *); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CLASSOBJECT_H */ diff --git a/sys/src/cmd/python/Include/cobject.h b/sys/src/cmd/python/Include/cobject.h new file mode 100644 index 000000000..ad23ac8d6 --- /dev/null +++ b/sys/src/cmd/python/Include/cobject.h @@ -0,0 +1,54 @@ + +/* C objects to be exported from one extension module to another. + + C objects are used for communication between extension modules. + They provide a way for an extension module to export a C interface + to other extension modules, so that extension modules can use the + Python import mechanism to link to one another. + +*/ + +#ifndef Py_COBJECT_H +#define Py_COBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyCObject_Type; + +#define PyCObject_Check(op) ((op)->ob_type == &PyCObject_Type) + +/* Create a PyCObject from a pointer to a C object and an optional + destructor function. If the second argument is non-null, then it + will be called with the first argument if and when the PyCObject is + destroyed. + +*/ +PyAPI_FUNC(PyObject *) PyCObject_FromVoidPtr( + void *cobj, void (*destruct)(void*)); + + +/* Create a PyCObject from a pointer to a C object, a description object, + and an optional destructor function. If the third argument is non-null, + then it will be called with the first and second arguments if and when + the PyCObject is destroyed. +*/ +PyAPI_FUNC(PyObject *) PyCObject_FromVoidPtrAndDesc( + void *cobj, void *desc, void (*destruct)(void*,void*)); + +/* Retrieve a pointer to a C object from a PyCObject. */ +PyAPI_FUNC(void *) PyCObject_AsVoidPtr(PyObject *); + +/* Retrieve a pointer to a description object from a PyCObject. */ +PyAPI_FUNC(void *) PyCObject_GetDesc(PyObject *); + +/* Import a pointer to a C object from a module using a PyCObject. */ +PyAPI_FUNC(void *) PyCObject_Import(char *module_name, char *cobject_name); + +/* Modify a C object. Fails (==0) if object has a destructor. */ +PyAPI_FUNC(int) PyCObject_SetVoidPtr(PyObject *self, void *cobj); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_COBJECT_H */ diff --git a/sys/src/cmd/python/Include/code.h b/sys/src/cmd/python/Include/code.h new file mode 100644 index 000000000..334ebab42 --- /dev/null +++ b/sys/src/cmd/python/Include/code.h @@ -0,0 +1,94 @@ +/* Definitions for bytecode */ + +#ifndef Py_CODE_H +#define Py_CODE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Bytecode object */ +typedef struct { + PyObject_HEAD + int co_argcount; /* #arguments, except *args */ + int co_nlocals; /* #local variables */ + int co_stacksize; /* #entries needed for evaluation stack */ + int co_flags; /* CO_..., see below */ + PyObject *co_code; /* instruction opcodes */ + PyObject *co_consts; /* list (constants used) */ + PyObject *co_names; /* list of strings (names used) */ + PyObject *co_varnames; /* tuple of strings (local variable names) */ + PyObject *co_freevars; /* tuple of strings (free variable names) */ + PyObject *co_cellvars; /* tuple of strings (cell variable names) */ + /* The rest doesn't count for hash/cmp */ + PyObject *co_filename; /* string (where it was loaded from) */ + PyObject *co_name; /* string (name, for reference) */ + int co_firstlineno; /* first source line number */ + PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */ + void *co_zombieframe; /* for optimization only (see frameobject.c) */ +} PyCodeObject; + +/* Masks for co_flags above */ +#define CO_OPTIMIZED 0x0001 +#define CO_NEWLOCALS 0x0002 +#define CO_VARARGS 0x0004 +#define CO_VARKEYWORDS 0x0008 +#define CO_NESTED 0x0010 +#define CO_GENERATOR 0x0020 +/* The CO_NOFREE flag is set if there are no free or cell variables. + This information is redundant, but it allows a single flag test + to determine whether there is any extra work to be done when the + call frame it setup. +*/ +#define CO_NOFREE 0x0040 + +#if 0 +/* This is no longer used. Stopped defining in 2.5, do not re-use. */ +#define CO_GENERATOR_ALLOWED 0x1000 +#endif +#define CO_FUTURE_DIVISION 0x2000 +#define CO_FUTURE_ABSOLUTE_IMPORT 0x4000 /* do absolute imports by default */ +#define CO_FUTURE_WITH_STATEMENT 0x8000 + +/* This should be defined if a future statement modifies the syntax. + For example, when a keyword is added. +*/ +#define PY_PARSER_REQUIRES_FUTURE_KEYWORD + +#define CO_MAXBLOCKS 20 /* Max static block nesting within a function */ + +PyAPI_DATA(PyTypeObject) PyCode_Type; + +#define PyCode_Check(op) ((op)->ob_type == &PyCode_Type) +#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars)) + +/* Public interface */ +PyAPI_FUNC(PyCodeObject *) PyCode_New( + int, int, int, int, PyObject *, PyObject *, PyObject *, PyObject *, + PyObject *, PyObject *, PyObject *, PyObject *, int, PyObject *); + /* same as struct above */ +PyAPI_FUNC(int) PyCode_Addr2Line(PyCodeObject *, int); + +/* for internal use only */ +#define _PyCode_GETCODEPTR(co, pp) \ + ((*(co)->co_code->ob_type->tp_as_buffer->bf_getreadbuffer) \ + ((co)->co_code, 0, (void **)(pp))) + +typedef struct _addr_pair { + int ap_lower; + int ap_upper; +} PyAddrPair; + +/* Check whether lasti (an instruction offset) falls outside bounds + and whether it is a line number that should be traced. Returns + a line number if it should be traced or -1 if the line should not. + + If lasti is not within bounds, updates bounds. +*/ + +PyAPI_FUNC(int) PyCode_CheckLineNumber(PyCodeObject* co, + int lasti, PyAddrPair *bounds); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CODE_H */ diff --git a/sys/src/cmd/python/Include/codecs.h b/sys/src/cmd/python/Include/codecs.h new file mode 100644 index 000000000..0d76241db --- /dev/null +++ b/sys/src/cmd/python/Include/codecs.h @@ -0,0 +1,167 @@ +#ifndef Py_CODECREGISTRY_H +#define Py_CODECREGISTRY_H +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------------------------------------------------------ + + Python Codec Registry and support functions + + +Written by Marc-Andre Lemburg (mal@lemburg.com). + +Copyright (c) Corporation for National Research Initiatives. + + ------------------------------------------------------------------------ */ + +/* Register a new codec search function. + + As side effect, this tries to load the encodings package, if not + yet done, to make sure that it is always first in the list of + search functions. + + The search_function's refcount is incremented by this function. */ + +PyAPI_FUNC(int) PyCodec_Register( + PyObject *search_function + ); + +/* Codec register lookup API. + + Looks up the given encoding and returns a CodecInfo object with + function attributes which implement the different aspects of + processing the encoding. + + The encoding string is looked up converted to all lower-case + characters. This makes encodings looked up through this mechanism + effectively case-insensitive. + + If no codec is found, a KeyError is set and NULL returned. + + As side effect, this tries to load the encodings package, if not + yet done. This is part of the lazy load strategy for the encodings + package. + + */ + +PyAPI_FUNC(PyObject *) _PyCodec_Lookup( + const char *encoding + ); + +/* Generic codec based encoding API. + + object is passed through the encoder function found for the given + encoding using the error handling method defined by errors. errors + may be NULL to use the default method defined for the codec. + + Raises a LookupError in case no encoder can be found. + + */ + +PyAPI_FUNC(PyObject *) PyCodec_Encode( + PyObject *object, + const char *encoding, + const char *errors + ); + +/* Generic codec based decoding API. + + object is passed through the decoder function found for the given + encoding using the error handling method defined by errors. errors + may be NULL to use the default method defined for the codec. + + Raises a LookupError in case no encoder can be found. + + */ + +PyAPI_FUNC(PyObject *) PyCodec_Decode( + PyObject *object, + const char *encoding, + const char *errors + ); + +/* --- Codec Lookup APIs -------------------------------------------------- + + All APIs return a codec object with incremented refcount and are + based on _PyCodec_Lookup(). The same comments w/r to the encoding + name also apply to these APIs. + +*/ + +/* Get an encoder function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_Encoder( + const char *encoding + ); + +/* Get a decoder function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_Decoder( + const char *encoding + ); + +/* Get a IncrementalEncoder object for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_IncrementalEncoder( + const char *encoding, + const char *errors + ); + +/* Get a IncrementalDecoder object function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_IncrementalDecoder( + const char *encoding, + const char *errors + ); + +/* Get a StreamReader factory function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_StreamReader( + const char *encoding, + PyObject *stream, + const char *errors + ); + +/* Get a StreamWriter factory function for the given encoding. */ + +PyAPI_FUNC(PyObject *) PyCodec_StreamWriter( + const char *encoding, + PyObject *stream, + const char *errors + ); + +/* Unicode encoding error handling callback registry API */ + +/* Register the error handling callback function error under the name + name. This function will be called by the codec when it encounters + unencodable characters/undecodable bytes and doesn't know the + callback name, when name is specified as the error parameter + in the call to the encode/decode function. + Return 0 on success, -1 on error */ +PyAPI_FUNC(int) PyCodec_RegisterError(const char *name, PyObject *error); + +/* Lookup the error handling callback function registered under the + name error. As a special case NULL can be passed, in which case + the error handling callback for "strict" will be returned. */ +PyAPI_FUNC(PyObject *) PyCodec_LookupError(const char *name); + +/* raise exc as an exception */ +PyAPI_FUNC(PyObject *) PyCodec_StrictErrors(PyObject *exc); + +/* ignore the unicode error, skipping the faulty input */ +PyAPI_FUNC(PyObject *) PyCodec_IgnoreErrors(PyObject *exc); + +/* replace the unicode error with ? or U+FFFD */ +PyAPI_FUNC(PyObject *) PyCodec_ReplaceErrors(PyObject *exc); + +/* replace the unicode encode error with XML character references */ +PyAPI_FUNC(PyObject *) PyCodec_XMLCharRefReplaceErrors(PyObject *exc); + +/* replace the unicode encode error with backslash escapes (\x, \u and \U) */ +PyAPI_FUNC(PyObject *) PyCodec_BackslashReplaceErrors(PyObject *exc); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CODECREGISTRY_H */ diff --git a/sys/src/cmd/python/Include/compile.h b/sys/src/cmd/python/Include/compile.h new file mode 100644 index 000000000..2bde6fb56 --- /dev/null +++ b/sys/src/cmd/python/Include/compile.h @@ -0,0 +1,39 @@ + +#ifndef Py_COMPILE_H +#define Py_COMPILE_H + +#include "code.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Public interface */ +struct _node; /* Declare the existence of this type */ +PyAPI_FUNC(PyCodeObject *) PyNode_Compile(struct _node *, const char *); + +/* Future feature support */ + +typedef struct { + int ff_features; /* flags set by future statements */ + int ff_lineno; /* line number of last future statement */ +} PyFutureFeatures; + +#define FUTURE_NESTED_SCOPES "nested_scopes" +#define FUTURE_GENERATORS "generators" +#define FUTURE_DIVISION "division" +#define FUTURE_ABSOLUTE_IMPORT "absolute_import" +#define FUTURE_WITH_STATEMENT "with_statement" + +struct _mod; /* Declare the existence of this type */ +PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *, + PyCompilerFlags *, PyArena *); +PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST(struct _mod *, const char *); + +#define ERR_LATE_FUTURE \ +"from __future__ imports must occur at the beginning of the file" + +#ifdef __cplusplus +} +#endif +#endif /* !Py_COMPILE_H */ diff --git a/sys/src/cmd/python/Include/complexobject.h b/sys/src/cmd/python/Include/complexobject.h new file mode 100644 index 000000000..e59bf2ca9 --- /dev/null +++ b/sys/src/cmd/python/Include/complexobject.h @@ -0,0 +1,58 @@ +/* Complex number structure */ + +#ifndef Py_COMPLEXOBJECT_H +#define Py_COMPLEXOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + double real; + double imag; +} Py_complex; + +/* Operations on complex numbers from complexmodule.c */ + +#define c_sum _Py_c_sum +#define c_diff _Py_c_diff +#define c_neg _Py_c_neg +#define c_prod _Py_c_prod +#define c_quot _Py_c_quot +#define c_pow _Py_c_pow + +PyAPI_FUNC(Py_complex) c_sum(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) c_diff(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) c_neg(Py_complex); +PyAPI_FUNC(Py_complex) c_prod(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) c_quot(Py_complex, Py_complex); +PyAPI_FUNC(Py_complex) c_pow(Py_complex, Py_complex); + + +/* Complex object interface */ + +/* +PyComplexObject represents a complex number with double-precision +real and imaginary parts. +*/ + +typedef struct { + PyObject_HEAD + Py_complex cval; +} PyComplexObject; + +PyAPI_DATA(PyTypeObject) PyComplex_Type; + +#define PyComplex_Check(op) PyObject_TypeCheck(op, &PyComplex_Type) +#define PyComplex_CheckExact(op) ((op)->ob_type == &PyComplex_Type) + +PyAPI_FUNC(PyObject *) PyComplex_FromCComplex(Py_complex); +PyAPI_FUNC(PyObject *) PyComplex_FromDoubles(double real, double imag); + +PyAPI_FUNC(double) PyComplex_RealAsDouble(PyObject *op); +PyAPI_FUNC(double) PyComplex_ImagAsDouble(PyObject *op); +PyAPI_FUNC(Py_complex) PyComplex_AsCComplex(PyObject *op); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_COMPLEXOBJECT_H */ diff --git a/sys/src/cmd/python/Include/datetime.h b/sys/src/cmd/python/Include/datetime.h new file mode 100644 index 000000000..db0f3aa5a --- /dev/null +++ b/sys/src/cmd/python/Include/datetime.h @@ -0,0 +1,245 @@ +/* datetime.h + */ + +#ifndef DATETIME_H +#define DATETIME_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Fields are packed into successive bytes, each viewed as unsigned and + * big-endian, unless otherwise noted: + * + * byte offset + * 0 year 2 bytes, 1-9999 + * 2 month 1 byte, 1-12 + * 3 day 1 byte, 1-31 + * 4 hour 1 byte, 0-23 + * 5 minute 1 byte, 0-59 + * 6 second 1 byte, 0-59 + * 7 usecond 3 bytes, 0-999999 + * 10 + */ + +/* # of bytes for year, month, and day. */ +#define _PyDateTime_DATE_DATASIZE 4 + +/* # of bytes for hour, minute, second, and usecond. */ +#define _PyDateTime_TIME_DATASIZE 6 + +/* # of bytes for year, month, day, hour, minute, second, and usecond. */ +#define _PyDateTime_DATETIME_DATASIZE 10 + + +typedef struct +{ + PyObject_HEAD + long hashcode; /* -1 when unknown */ + int days; /* -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS */ + int seconds; /* 0 <= seconds < 24*3600 is invariant */ + int microseconds; /* 0 <= microseconds < 1000000 is invariant */ +} PyDateTime_Delta; + +typedef struct +{ + PyObject_HEAD /* a pure abstract base clase */ +} PyDateTime_TZInfo; + + +/* The datetime and time types have hashcodes, and an optional tzinfo member, + * present if and only if hastzinfo is true. + */ +#define _PyTZINFO_HEAD \ + PyObject_HEAD \ + long hashcode; \ + char hastzinfo; /* boolean flag */ + +/* No _PyDateTime_BaseTZInfo is allocated; it's just to have something + * convenient to cast to, when getting at the hastzinfo member of objects + * starting with _PyTZINFO_HEAD. + */ +typedef struct +{ + _PyTZINFO_HEAD +} _PyDateTime_BaseTZInfo; + +/* All time objects are of PyDateTime_TimeType, but that can be allocated + * in two ways, with or without a tzinfo member. Without is the same as + * tzinfo == None, but consumes less memory. _PyDateTime_BaseTime is an + * internal struct used to allocate the right amount of space for the + * "without" case. + */ +#define _PyDateTime_TIMEHEAD \ + _PyTZINFO_HEAD \ + unsigned char data[_PyDateTime_TIME_DATASIZE]; + +typedef struct +{ + _PyDateTime_TIMEHEAD +} _PyDateTime_BaseTime; /* hastzinfo false */ + +typedef struct +{ + _PyDateTime_TIMEHEAD + PyObject *tzinfo; +} PyDateTime_Time; /* hastzinfo true */ + + +/* All datetime objects are of PyDateTime_DateTimeType, but that can be + * allocated in two ways too, just like for time objects above. In addition, + * the plain date type is a base class for datetime, so it must also have + * a hastzinfo member (although it's unused there). + */ +typedef struct +{ + _PyTZINFO_HEAD + unsigned char data[_PyDateTime_DATE_DATASIZE]; +} PyDateTime_Date; + +#define _PyDateTime_DATETIMEHEAD \ + _PyTZINFO_HEAD \ + unsigned char data[_PyDateTime_DATETIME_DATASIZE]; + +typedef struct +{ + _PyDateTime_DATETIMEHEAD +} _PyDateTime_BaseDateTime; /* hastzinfo false */ + +typedef struct +{ + _PyDateTime_DATETIMEHEAD + PyObject *tzinfo; +} PyDateTime_DateTime; /* hastzinfo true */ + + +/* Apply for date and datetime instances. */ +#define PyDateTime_GET_YEAR(o) ((((PyDateTime_Date*)o)->data[0] << 8) | \ + ((PyDateTime_Date*)o)->data[1]) +#define PyDateTime_GET_MONTH(o) (((PyDateTime_Date*)o)->data[2]) +#define PyDateTime_GET_DAY(o) (((PyDateTime_Date*)o)->data[3]) + +#define PyDateTime_DATE_GET_HOUR(o) (((PyDateTime_DateTime*)o)->data[4]) +#define PyDateTime_DATE_GET_MINUTE(o) (((PyDateTime_DateTime*)o)->data[5]) +#define PyDateTime_DATE_GET_SECOND(o) (((PyDateTime_DateTime*)o)->data[6]) +#define PyDateTime_DATE_GET_MICROSECOND(o) \ + ((((PyDateTime_DateTime*)o)->data[7] << 16) | \ + (((PyDateTime_DateTime*)o)->data[8] << 8) | \ + ((PyDateTime_DateTime*)o)->data[9]) + +/* Apply for time instances. */ +#define PyDateTime_TIME_GET_HOUR(o) (((PyDateTime_Time*)o)->data[0]) +#define PyDateTime_TIME_GET_MINUTE(o) (((PyDateTime_Time*)o)->data[1]) +#define PyDateTime_TIME_GET_SECOND(o) (((PyDateTime_Time*)o)->data[2]) +#define PyDateTime_TIME_GET_MICROSECOND(o) \ + ((((PyDateTime_Time*)o)->data[3] << 16) | \ + (((PyDateTime_Time*)o)->data[4] << 8) | \ + ((PyDateTime_Time*)o)->data[5]) + + +/* Define structure for C API. */ +typedef struct { + /* type objects */ + PyTypeObject *DateType; + PyTypeObject *DateTimeType; + PyTypeObject *TimeType; + PyTypeObject *DeltaType; + PyTypeObject *TZInfoType; + + /* constructors */ + PyObject *(*Date_FromDate)(int, int, int, PyTypeObject*); + PyObject *(*DateTime_FromDateAndTime)(int, int, int, int, int, int, int, + PyObject*, PyTypeObject*); + PyObject *(*Time_FromTime)(int, int, int, int, PyObject*, PyTypeObject*); + PyObject *(*Delta_FromDelta)(int, int, int, int, PyTypeObject*); + + /* constructors for the DB API */ + PyObject *(*DateTime_FromTimestamp)(PyObject*, PyObject*, PyObject*); + PyObject *(*Date_FromTimestamp)(PyObject*, PyObject*); + +} PyDateTime_CAPI; + + +/* "magic" constant used to partially protect against developer mistakes. */ +#define DATETIME_API_MAGIC 0x414548d5 + +#ifdef Py_BUILD_CORE + +/* Macros for type checking when building the Python core. */ +#define PyDate_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateType) +#define PyDate_CheckExact(op) ((op)->ob_type == &PyDateTime_DateType) + +#define PyDateTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_DateTimeType) +#define PyDateTime_CheckExact(op) ((op)->ob_type == &PyDateTime_DateTimeType) + +#define PyTime_Check(op) PyObject_TypeCheck(op, &PyDateTime_TimeType) +#define PyTime_CheckExact(op) ((op)->ob_type == &PyDateTime_TimeType) + +#define PyDelta_Check(op) PyObject_TypeCheck(op, &PyDateTime_DeltaType) +#define PyDelta_CheckExact(op) ((op)->ob_type == &PyDateTime_DeltaType) + +#define PyTZInfo_Check(op) PyObject_TypeCheck(op, &PyDateTime_TZInfoType) +#define PyTZInfo_CheckExact(op) ((op)->ob_type == &PyDateTime_TZInfoType) + +#else + +/* Define global variable for the C API and a macro for setting it. */ +static PyDateTime_CAPI *PyDateTimeAPI; + +#define PyDateTime_IMPORT \ + PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_Import("datetime", \ + "datetime_CAPI") + +/* This macro would be used if PyCObject_ImportEx() was created. +#define PyDateTime_IMPORT \ + PyDateTimeAPI = (PyDateTime_CAPI*) PyCObject_ImportEx("datetime", \ + "datetime_CAPI", \ + DATETIME_API_MAGIC) +*/ + +/* Macros for type checking when not building the Python core. */ +#define PyDate_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateType) +#define PyDate_CheckExact(op) ((op)->ob_type == PyDateTimeAPI->DateType) + +#define PyDateTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DateTimeType) +#define PyDateTime_CheckExact(op) ((op)->ob_type == PyDateTimeAPI->DateTimeType) + +#define PyTime_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TimeType) +#define PyTime_CheckExact(op) ((op)->ob_type == PyDateTimeAPI->TimeType) + +#define PyDelta_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->DeltaType) +#define PyDelta_CheckExact(op) ((op)->ob_type == PyDateTimeAPI->DeltaType) + +#define PyTZInfo_Check(op) PyObject_TypeCheck(op, PyDateTimeAPI->TZInfoType) +#define PyTZInfo_CheckExact(op) ((op)->ob_type == PyDateTimeAPI->TZInfoType) + +/* Macros for accessing constructors in a simplified fashion. */ +#define PyDate_FromDate(year, month, day) \ + PyDateTimeAPI->Date_FromDate(year, month, day, PyDateTimeAPI->DateType) + +#define PyDateTime_FromDateAndTime(year, month, day, hour, min, sec, usec) \ + PyDateTimeAPI->DateTime_FromDateAndTime(year, month, day, hour, \ + min, sec, usec, Py_None, PyDateTimeAPI->DateTimeType) + +#define PyTime_FromTime(hour, minute, second, usecond) \ + PyDateTimeAPI->Time_FromTime(hour, minute, second, usecond, \ + Py_None, PyDateTimeAPI->TimeType) + +#define PyDelta_FromDSU(days, seconds, useconds) \ + PyDateTimeAPI->Delta_FromDelta(days, seconds, useconds, 1, \ + PyDateTimeAPI->DeltaType) + +/* Macros supporting the DB API. */ +#define PyDateTime_FromTimestamp(args) \ + PyDateTimeAPI->DateTime_FromTimestamp( \ + (PyObject*) (PyDateTimeAPI->DateTimeType), args, NULL) + +#define PyDate_FromTimestamp(args) \ + PyDateTimeAPI->Date_FromTimestamp( \ + (PyObject*) (PyDateTimeAPI->DateType), args) + +#endif /* Py_BUILD_CORE */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/sys/src/cmd/python/Include/descrobject.h b/sys/src/cmd/python/Include/descrobject.h new file mode 100644 index 000000000..a74af6009 --- /dev/null +++ b/sys/src/cmd/python/Include/descrobject.h @@ -0,0 +1,91 @@ +/* Descriptors */ +#ifndef Py_DESCROBJECT_H +#define Py_DESCROBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef PyObject *(*getter)(PyObject *, void *); +typedef int (*setter)(PyObject *, PyObject *, void *); + +typedef struct PyGetSetDef { + char *name; + getter get; + setter set; + char *doc; + void *closure; +} PyGetSetDef; + +typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args, + void *wrapped); + +typedef PyObject *(*wrapperfunc_kwds)(PyObject *self, PyObject *args, + void *wrapped, PyObject *kwds); + +struct wrapperbase { + char *name; + int offset; + void *function; + wrapperfunc wrapper; + char *doc; + int flags; + PyObject *name_strobj; +}; + +/* Flags for above struct */ +#define PyWrapperFlag_KEYWORDS 1 /* wrapper function takes keyword args */ + +/* Various kinds of descriptor objects */ + +#define PyDescr_COMMON \ + PyObject_HEAD \ + PyTypeObject *d_type; \ + PyObject *d_name + +typedef struct { + PyDescr_COMMON; +} PyDescrObject; + +typedef struct { + PyDescr_COMMON; + PyMethodDef *d_method; +} PyMethodDescrObject; + +typedef struct { + PyDescr_COMMON; + struct PyMemberDef *d_member; +} PyMemberDescrObject; + +typedef struct { + PyDescr_COMMON; + PyGetSetDef *d_getset; +} PyGetSetDescrObject; + +typedef struct { + PyDescr_COMMON; + struct wrapperbase *d_base; + void *d_wrapped; /* This can be any function pointer */ +} PyWrapperDescrObject; + +PyAPI_DATA(PyTypeObject) PyWrapperDescr_Type; + +PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *); +PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *); +PyAPI_FUNC(PyObject *) PyDescr_NewMember(PyTypeObject *, + struct PyMemberDef *); +PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *, + struct PyGetSetDef *); +PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *, + struct wrapperbase *, void *); +#define PyDescr_IsData(d) ((d)->ob_type->tp_descr_set != NULL) + +PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *); +PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *); + + +PyAPI_DATA(PyTypeObject) PyProperty_Type; +#ifdef __cplusplus +} +#endif +#endif /* !Py_DESCROBJECT_H */ + diff --git a/sys/src/cmd/python/Include/dictobject.h b/sys/src/cmd/python/Include/dictobject.h new file mode 100644 index 000000000..44b0838e0 --- /dev/null +++ b/sys/src/cmd/python/Include/dictobject.h @@ -0,0 +1,141 @@ +#ifndef Py_DICTOBJECT_H +#define Py_DICTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Dictionary object type -- mapping from hashable object to object */ + +/* The distribution includes a separate file, Objects/dictnotes.txt, + describing explorations into dictionary design and optimization. + It covers typical dictionary use patterns, the parameters for + tuning dictionaries, and several ideas for possible optimizations. +*/ + +/* +There are three kinds of slots in the table: + +1. Unused. me_key == me_value == NULL + Does not hold an active (key, value) pair now and never did. Unused can + transition to Active upon key insertion. This is the only case in which + me_key is NULL, and is each slot's initial state. + +2. Active. me_key != NULL and me_key != dummy and me_value != NULL + Holds an active (key, value) pair. Active can transition to Dummy upon + key deletion. This is the only case in which me_value != NULL. + +3. Dummy. me_key == dummy and me_value == NULL + Previously held an active (key, value) pair, but that was deleted and an + active pair has not yet overwritten the slot. Dummy can transition to + Active upon key insertion. Dummy slots cannot be made Unused again + (cannot have me_key set to NULL), else the probe sequence in case of + collision would have no way to know they were once active. + +Note: .popitem() abuses the me_hash field of an Unused or Dummy slot to +hold a search finger. The me_hash field of Unused or Dummy slots has no +meaning otherwise. +*/ + +/* PyDict_MINSIZE is the minimum size of a dictionary. This many slots are + * allocated directly in the dict object (in the ma_smalltable member). + * It must be a power of 2, and at least 4. 8 allows dicts with no more + * than 5 active entries to live in ma_smalltable (and so avoid an + * additional malloc); instrumentation suggested this suffices for the + * majority of dicts (consisting mostly of usually-small instance dicts and + * usually-small dicts created to pass keyword arguments). + */ +#define PyDict_MINSIZE 8 + +typedef struct { + /* Cached hash code of me_key. Note that hash codes are C longs. + * We have to use Py_ssize_t instead because dict_popitem() abuses + * me_hash to hold a search finger. + */ + Py_ssize_t me_hash; + PyObject *me_key; + PyObject *me_value; +} PyDictEntry; + +/* +To ensure the lookup algorithm terminates, there must be at least one Unused +slot (NULL key) in the table. +The value ma_fill is the number of non-NULL keys (sum of Active and Dummy); +ma_used is the number of non-NULL, non-dummy keys (== the number of non-NULL +values == the number of Active items). +To avoid slowing down lookups on a near-full table, we resize the table when +it's two-thirds full. +*/ +typedef struct _dictobject PyDictObject; +struct _dictobject { + PyObject_HEAD + Py_ssize_t ma_fill; /* # Active + # Dummy */ + Py_ssize_t ma_used; /* # Active */ + + /* The table contains ma_mask + 1 slots, and that's a power of 2. + * We store the mask instead of the size because the mask is more + * frequently needed. + */ + Py_ssize_t ma_mask; + + /* ma_table points to ma_smalltable for small tables, else to + * additional malloc'ed memory. ma_table is never NULL! This rule + * saves repeated runtime null-tests in the workhorse getitem and + * setitem calls. + */ + PyDictEntry *ma_table; + PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, long hash); + PyDictEntry ma_smalltable[PyDict_MINSIZE]; +}; + +PyAPI_DATA(PyTypeObject) PyDict_Type; + +#define PyDict_Check(op) PyObject_TypeCheck(op, &PyDict_Type) +#define PyDict_CheckExact(op) ((op)->ob_type == &PyDict_Type) + +PyAPI_FUNC(PyObject *) PyDict_New(void); +PyAPI_FUNC(PyObject *) PyDict_GetItem(PyObject *mp, PyObject *key); +PyAPI_FUNC(int) PyDict_SetItem(PyObject *mp, PyObject *key, PyObject *item); +PyAPI_FUNC(int) PyDict_DelItem(PyObject *mp, PyObject *key); +PyAPI_FUNC(void) PyDict_Clear(PyObject *mp); +PyAPI_FUNC(int) PyDict_Next( + PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value); +PyAPI_FUNC(int) _PyDict_Next( + PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value, long *hash); +PyAPI_FUNC(PyObject *) PyDict_Keys(PyObject *mp); +PyAPI_FUNC(PyObject *) PyDict_Values(PyObject *mp); +PyAPI_FUNC(PyObject *) PyDict_Items(PyObject *mp); +PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp); +PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp); +PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key); +PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, long hash); + +/* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */ +PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other); + +/* PyDict_Merge updates/merges from a mapping object (an object that + supports PyMapping_Keys() and PyObject_GetItem()). If override is true, + the last occurrence of a key wins, else the first. The Python + dict.update(other) is equivalent to PyDict_Merge(dict, other, 1). +*/ +PyAPI_FUNC(int) PyDict_Merge(PyObject *mp, + PyObject *other, + int override); + +/* PyDict_MergeFromSeq2 updates/merges from an iterable object producing + iterable objects of length 2. If override is true, the last occurrence + of a key wins, else the first. The Python dict constructor dict(seq2) + is equivalent to dict={}; PyDict_MergeFromSeq(dict, seq2, 1). +*/ +PyAPI_FUNC(int) PyDict_MergeFromSeq2(PyObject *d, + PyObject *seq2, + int override); + +PyAPI_FUNC(PyObject *) PyDict_GetItemString(PyObject *dp, const char *key); +PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item); +PyAPI_FUNC(int) PyDict_DelItemString(PyObject *dp, const char *key); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_DICTOBJECT_H */ diff --git a/sys/src/cmd/python/Include/enumobject.h b/sys/src/cmd/python/Include/enumobject.h new file mode 100644 index 000000000..c14dbfc8c --- /dev/null +++ b/sys/src/cmd/python/Include/enumobject.h @@ -0,0 +1,17 @@ +#ifndef Py_ENUMOBJECT_H +#define Py_ENUMOBJECT_H + +/* Enumerate Object */ + +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyEnum_Type; +PyAPI_DATA(PyTypeObject) PyReversed_Type; + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_ENUMOBJECT_H */ diff --git a/sys/src/cmd/python/Include/errcode.h b/sys/src/cmd/python/Include/errcode.h new file mode 100644 index 000000000..becec80c8 --- /dev/null +++ b/sys/src/cmd/python/Include/errcode.h @@ -0,0 +1,36 @@ +#ifndef Py_ERRCODE_H +#define Py_ERRCODE_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Error codes passed around between file input, tokenizer, parser and + interpreter. This is necessary so we can turn them into Python + exceptions at a higher level. Note that some errors have a + slightly different meaning when passed from the tokenizer to the + parser than when passed from the parser to the interpreter; e.g. + the parser only returns E_EOF when it hits EOF immediately, and it + never returns E_OK. */ + +#define E_OK 10 /* No error */ +#define E_EOF 11 /* End Of File */ +#define E_INTR 12 /* Interrupted */ +#define E_TOKEN 13 /* Bad token */ +#define E_SYNTAX 14 /* Syntax error */ +#define E_NOMEM 15 /* Ran out of memory */ +#define E_DONE 16 /* Parsing complete */ +#define E_ERROR 17 /* Execution error */ +#define E_TABSPACE 18 /* Inconsistent mixing of tabs and spaces */ +#define E_OVERFLOW 19 /* Node had too many children */ +#define E_TOODEEP 20 /* Too many indentation levels */ +#define E_DEDENT 21 /* No matching outer block for dedent */ +#define E_DECODE 22 /* Error in decoding into Unicode */ +#define E_EOFS 23 /* EOF in triple-quoted string */ +#define E_EOLS 24 /* EOL in single-quoted string */ +#define E_LINECONT 25 /* Unexpected characters after a line continuation */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py_ERRCODE_H */ diff --git a/sys/src/cmd/python/Include/eval.h b/sys/src/cmd/python/Include/eval.h new file mode 100644 index 000000000..b78dfe0fa --- /dev/null +++ b/sys/src/cmd/python/Include/eval.h @@ -0,0 +1,25 @@ + +/* Interface to execute compiled code */ + +#ifndef Py_EVAL_H +#define Py_EVAL_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyCodeObject *, PyObject *, PyObject *); + +PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co, + PyObject *globals, + PyObject *locals, + PyObject **args, int argc, + PyObject **kwds, int kwdc, + PyObject **defs, int defc, + PyObject *closure); + +PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_EVAL_H */ diff --git a/sys/src/cmd/python/Include/fileobject.h b/sys/src/cmd/python/Include/fileobject.h new file mode 100644 index 000000000..ebbb521d1 --- /dev/null +++ b/sys/src/cmd/python/Include/fileobject.h @@ -0,0 +1,63 @@ + +/* File object interface */ + +#ifndef Py_FILEOBJECT_H +#define Py_FILEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + FILE *f_fp; + PyObject *f_name; + PyObject *f_mode; + int (*f_close)(FILE *); + int f_softspace; /* Flag used by 'print' command */ + int f_binary; /* Flag which indicates whether the file is + open in binary (1) or text (0) mode */ + char* f_buf; /* Allocated readahead buffer */ + char* f_bufend; /* Points after last occupied position */ + char* f_bufptr; /* Current buffer position */ + char *f_setbuf; /* Buffer for setbuf(3) and setvbuf(3) */ + int f_univ_newline; /* Handle any newline convention */ + int f_newlinetypes; /* Types of newlines seen */ + int f_skipnextlf; /* Skip next \n */ + PyObject *f_encoding; + PyObject *weakreflist; /* List of weak references */ +} PyFileObject; + +PyAPI_DATA(PyTypeObject) PyFile_Type; + +#define PyFile_Check(op) PyObject_TypeCheck(op, &PyFile_Type) +#define PyFile_CheckExact(op) ((op)->ob_type == &PyFile_Type) + +PyAPI_FUNC(PyObject *) PyFile_FromString(char *, char *); +PyAPI_FUNC(void) PyFile_SetBufSize(PyObject *, int); +PyAPI_FUNC(int) PyFile_SetEncoding(PyObject *, const char *); +PyAPI_FUNC(PyObject *) PyFile_FromFile(FILE *, char *, char *, + int (*)(FILE *)); +PyAPI_FUNC(FILE *) PyFile_AsFile(PyObject *); +PyAPI_FUNC(PyObject *) PyFile_Name(PyObject *); +PyAPI_FUNC(PyObject *) PyFile_GetLine(PyObject *, int); +PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int); +PyAPI_FUNC(int) PyFile_SoftSpace(PyObject *, int); +PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *); +PyAPI_FUNC(int) PyObject_AsFileDescriptor(PyObject *); + +/* The default encoding used by the platform file system APIs + If non-NULL, this is different than the default encoding for strings +*/ +PyAPI_DATA(const char *) Py_FileSystemDefaultEncoding; + +/* Routines to replace fread() and fgets() which accept any of \r, \n + or \r\n as line terminators. +*/ +#define PY_STDIOTEXTMODE "b" +char *Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *); +size_t Py_UniversalNewlineFread(char *, size_t, FILE *, PyObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FILEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/floatobject.h b/sys/src/cmd/python/Include/floatobject.h new file mode 100644 index 000000000..f695de857 --- /dev/null +++ b/sys/src/cmd/python/Include/floatobject.h @@ -0,0 +1,100 @@ + +/* Float object interface */ + +/* +PyFloatObject represents a (double precision) floating point number. +*/ + +#ifndef Py_FLOATOBJECT_H +#define Py_FLOATOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + double ob_fval; +} PyFloatObject; + +PyAPI_DATA(PyTypeObject) PyFloat_Type; + +#define PyFloat_Check(op) PyObject_TypeCheck(op, &PyFloat_Type) +#define PyFloat_CheckExact(op) ((op)->ob_type == &PyFloat_Type) + +/* Return Python float from string PyObject. Second argument ignored on + input, and, if non-NULL, NULL is stored into *junk (this tried to serve a + purpose once but can't be made to work as intended). */ +PyAPI_FUNC(PyObject *) PyFloat_FromString(PyObject*, char** junk); + +/* Return Python float from C double. */ +PyAPI_FUNC(PyObject *) PyFloat_FromDouble(double); + +/* Extract C double from Python float. The macro version trades safety for + speed. */ +PyAPI_FUNC(double) PyFloat_AsDouble(PyObject *); +#define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval) + +/* Write repr(v) into the char buffer argument, followed by null byte. The + buffer must be "big enough"; >= 100 is very safe. + PyFloat_AsReprString(buf, x) strives to print enough digits so that + PyFloat_FromString(buf) then reproduces x exactly. */ +PyAPI_FUNC(void) PyFloat_AsReprString(char*, PyFloatObject *v); + +/* Write str(v) into the char buffer argument, followed by null byte. The + buffer must be "big enough"; >= 100 is very safe. Note that it's + unusual to be able to get back the float you started with from + PyFloat_AsString's result -- use PyFloat_AsReprString() if you want to + preserve precision across conversions. */ +PyAPI_FUNC(void) PyFloat_AsString(char*, PyFloatObject *v); + +/* _PyFloat_{Pack,Unpack}{4,8} + * + * The struct and pickle (at least) modules need an efficient platform- + * independent way to store floating-point values as byte strings. + * The Pack routines produce a string from a C double, and the Unpack + * routines produce a C double from such a string. The suffix (4 or 8) + * specifies the number of bytes in the string. + * + * On platforms that appear to use (see _PyFloat_Init()) IEEE-754 formats + * these functions work by copying bits. On other platforms, the formats the + * 4- byte format is identical to the IEEE-754 single precision format, and + * the 8-byte format to the IEEE-754 double precision format, although the + * packing of INFs and NaNs (if such things exist on the platform) isn't + * handled correctly, and attempting to unpack a string containing an IEEE + * INF or NaN will raise an exception. + * + * On non-IEEE platforms with more precision, or larger dynamic range, than + * 754 supports, not all values can be packed; on non-IEEE platforms with less + * precision, or smaller dynamic range, not all values can be unpacked. What + * happens in such cases is partly accidental (alas). + */ + +/* The pack routines write 4 or 8 bytes, starting at p. le is a bool + * argument, true if you want the string in little-endian format (exponent + * last, at p+3 or p+7), false if you want big-endian format (exponent + * first, at p). + * Return value: 0 if all is OK, -1 if error (and an exception is + * set, most likely OverflowError). + * There are two problems on non-IEEE platforms: + * 1): What this does is undefined if x is a NaN or infinity. + * 2): -0.0 and +0.0 produce the same string. + */ +PyAPI_FUNC(int) _PyFloat_Pack4(double x, unsigned char *p, int le); +PyAPI_FUNC(int) _PyFloat_Pack8(double x, unsigned char *p, int le); + +/* The unpack routines read 4 or 8 bytes, starting at p. le is a bool + * argument, true if the string is in little-endian format (exponent + * last, at p+3 or p+7), false if big-endian (exponent first, at p). + * Return value: The unpacked double. On error, this is -1.0 and + * PyErr_Occurred() is true (and an exception is set, most likely + * OverflowError). Note that on a non-IEEE platform this will refuse + * to unpack a string that represents a NaN or infinity. + */ +PyAPI_FUNC(double) _PyFloat_Unpack4(const unsigned char *p, int le); +PyAPI_FUNC(double) _PyFloat_Unpack8(const unsigned char *p, int le); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FLOATOBJECT_H */ diff --git a/sys/src/cmd/python/Include/frameobject.h b/sys/src/cmd/python/Include/frameobject.h new file mode 100644 index 000000000..794f6515b --- /dev/null +++ b/sys/src/cmd/python/Include/frameobject.h @@ -0,0 +1,81 @@ + +/* Frame object interface */ + +#ifndef Py_FRAMEOBJECT_H +#define Py_FRAMEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int b_type; /* what kind of block this is */ + int b_handler; /* where to jump to find handler */ + int b_level; /* value stack level to pop to */ +} PyTryBlock; + +typedef struct _frame { + PyObject_VAR_HEAD + struct _frame *f_back; /* previous frame, or NULL */ + PyCodeObject *f_code; /* code segment */ + PyObject *f_builtins; /* builtin symbol table (PyDictObject) */ + PyObject *f_globals; /* global symbol table (PyDictObject) */ + PyObject *f_locals; /* local symbol table (any mapping) */ + PyObject **f_valuestack; /* points after the last local */ + /* Next free slot in f_valuestack. Frame creation sets to f_valuestack. + Frame evaluation usually NULLs it, but a frame that yields sets it + to the current stack top. */ + PyObject **f_stacktop; + PyObject *f_trace; /* Trace function */ + + /* If an exception is raised in this frame, the next three are used to + * record the exception info (if any) originally in the thread state. See + * comments before set_exc_info() -- it's not obvious. + * Invariant: if _type is NULL, then so are _value and _traceback. + * Desired invariant: all three are NULL, or all three are non-NULL. That + * one isn't currently true, but "should be". + */ + PyObject *f_exc_type, *f_exc_value, *f_exc_traceback; + + PyThreadState *f_tstate; + int f_lasti; /* Last instruction if called */ + /* As of 2.3 f_lineno is only valid when tracing is active (i.e. when + f_trace is set) -- at other times use PyCode_Addr2Line instead. */ + int f_lineno; /* Current line number */ + int f_iblock; /* index in f_blockstack */ + PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */ + PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */ +} PyFrameObject; + + +/* Standard object interface */ + +PyAPI_DATA(PyTypeObject) PyFrame_Type; + +#define PyFrame_Check(op) ((op)->ob_type == &PyFrame_Type) +#define PyFrame_IsRestricted(f) \ + ((f)->f_builtins != (f)->f_tstate->interp->builtins) + +PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *, + PyObject *, PyObject *); + + +/* The rest of the interface is specific for frame objects */ + +/* Block management functions */ + +PyAPI_FUNC(void) PyFrame_BlockSetup(PyFrameObject *, int, int, int); +PyAPI_FUNC(PyTryBlock *) PyFrame_BlockPop(PyFrameObject *); + +/* Extend the value stack */ + +PyAPI_FUNC(PyObject **) PyFrame_ExtendStack(PyFrameObject *, int, int); + +/* Conversions between "fast locals" and locals in dictionary */ + +PyAPI_FUNC(void) PyFrame_LocalsToFast(PyFrameObject *, int); +PyAPI_FUNC(void) PyFrame_FastToLocals(PyFrameObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FRAMEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/funcobject.h b/sys/src/cmd/python/Include/funcobject.h new file mode 100644 index 000000000..59c19bb1e --- /dev/null +++ b/sys/src/cmd/python/Include/funcobject.h @@ -0,0 +1,76 @@ + +/* Function object interface */ + +#ifndef Py_FUNCOBJECT_H +#define Py_FUNCOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Function objects and code objects should not be confused with each other: + * + * Function objects are created by the execution of the 'def' statement. + * They reference a code object in their func_code attribute, which is a + * purely syntactic object, i.e. nothing more than a compiled version of some + * source code lines. There is one code object per source code "fragment", + * but each code object can be referenced by zero or many function objects + * depending only on how many times the 'def' statement in the source was + * executed so far. + */ + +typedef struct { + PyObject_HEAD + PyObject *func_code; /* A code object */ + PyObject *func_globals; /* A dictionary (other mappings won't do) */ + PyObject *func_defaults; /* NULL or a tuple */ + PyObject *func_closure; /* NULL or a tuple of cell objects */ + PyObject *func_doc; /* The __doc__ attribute, can be anything */ + PyObject *func_name; /* The __name__ attribute, a string object */ + PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */ + PyObject *func_weakreflist; /* List of weak references */ + PyObject *func_module; /* The __module__ attribute, can be anything */ + + /* Invariant: + * func_closure contains the bindings for func_code->co_freevars, so + * PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code) + * (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0). + */ +} PyFunctionObject; + +PyAPI_DATA(PyTypeObject) PyFunction_Type; + +#define PyFunction_Check(op) ((op)->ob_type == &PyFunction_Type) + +PyAPI_FUNC(PyObject *) PyFunction_New(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetCode(PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetGlobals(PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetModule(PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetDefaults(PyObject *); +PyAPI_FUNC(int) PyFunction_SetDefaults(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyFunction_GetClosure(PyObject *); +PyAPI_FUNC(int) PyFunction_SetClosure(PyObject *, PyObject *); + +/* Macros for direct access to these values. Type checks are *not* + done, so use with care. */ +#define PyFunction_GET_CODE(func) \ + (((PyFunctionObject *)func) -> func_code) +#define PyFunction_GET_GLOBALS(func) \ + (((PyFunctionObject *)func) -> func_globals) +#define PyFunction_GET_MODULE(func) \ + (((PyFunctionObject *)func) -> func_module) +#define PyFunction_GET_DEFAULTS(func) \ + (((PyFunctionObject *)func) -> func_defaults) +#define PyFunction_GET_CLOSURE(func) \ + (((PyFunctionObject *)func) -> func_closure) + +/* The classmethod and staticmethod types lives here, too */ +PyAPI_DATA(PyTypeObject) PyClassMethod_Type; +PyAPI_DATA(PyTypeObject) PyStaticMethod_Type; + +PyAPI_FUNC(PyObject *) PyClassMethod_New(PyObject *); +PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_FUNCOBJECT_H */ diff --git a/sys/src/cmd/python/Include/genobject.h b/sys/src/cmd/python/Include/genobject.h new file mode 100644 index 000000000..ca8443203 --- /dev/null +++ b/sys/src/cmd/python/Include/genobject.h @@ -0,0 +1,37 @@ + +/* Generator object interface */ + +#ifndef Py_GENOBJECT_H +#define Py_GENOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +struct _frame; /* Avoid including frameobject.h */ + +typedef struct { + PyObject_HEAD + /* The gi_ prefix is intended to remind of generator-iterator. */ + + /* Note: gi_frame can be NULL if the generator is "finished" */ + struct _frame *gi_frame; + + /* True if generator is being executed. */ + int gi_running; + + /* List of weak reference. */ + PyObject *gi_weakreflist; +} PyGenObject; + +PyAPI_DATA(PyTypeObject) PyGen_Type; + +#define PyGen_Check(op) PyObject_TypeCheck(op, &PyGen_Type) +#define PyGen_CheckExact(op) ((op)->ob_type == &PyGen_Type) + +PyAPI_FUNC(PyObject *) PyGen_New(struct _frame *); +PyAPI_FUNC(int) PyGen_NeedsFinalizing(PyGenObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GENOBJECT_H */ diff --git a/sys/src/cmd/python/Include/graminit.h b/sys/src/cmd/python/Include/graminit.h new file mode 100644 index 000000000..9af182a56 --- /dev/null +++ b/sys/src/cmd/python/Include/graminit.h @@ -0,0 +1,84 @@ +#define single_input 256 +#define file_input 257 +#define eval_input 258 +#define decorator 259 +#define decorators 260 +#define funcdef 261 +#define parameters 262 +#define varargslist 263 +#define fpdef 264 +#define fplist 265 +#define stmt 266 +#define simple_stmt 267 +#define small_stmt 268 +#define expr_stmt 269 +#define augassign 270 +#define print_stmt 271 +#define del_stmt 272 +#define pass_stmt 273 +#define flow_stmt 274 +#define break_stmt 275 +#define continue_stmt 276 +#define return_stmt 277 +#define yield_stmt 278 +#define raise_stmt 279 +#define import_stmt 280 +#define import_name 281 +#define import_from 282 +#define import_as_name 283 +#define dotted_as_name 284 +#define import_as_names 285 +#define dotted_as_names 286 +#define dotted_name 287 +#define global_stmt 288 +#define exec_stmt 289 +#define assert_stmt 290 +#define compound_stmt 291 +#define if_stmt 292 +#define while_stmt 293 +#define for_stmt 294 +#define try_stmt 295 +#define with_stmt 296 +#define with_var 297 +#define except_clause 298 +#define suite 299 +#define testlist_safe 300 +#define old_test 301 +#define old_lambdef 302 +#define test 303 +#define or_test 304 +#define and_test 305 +#define not_test 306 +#define comparison 307 +#define comp_op 308 +#define expr 309 +#define xor_expr 310 +#define and_expr 311 +#define shift_expr 312 +#define arith_expr 313 +#define term 314 +#define factor 315 +#define power 316 +#define atom 317 +#define listmaker 318 +#define testlist_gexp 319 +#define lambdef 320 +#define trailer 321 +#define subscriptlist 322 +#define subscript 323 +#define sliceop 324 +#define exprlist 325 +#define testlist 326 +#define dictmaker 327 +#define classdef 328 +#define arglist 329 +#define argument 330 +#define list_iter 331 +#define list_for 332 +#define list_if 333 +#define gen_iter 334 +#define gen_for 335 +#define gen_if 336 +#define testlist1 337 +#define encoding_decl 338 +#define yield_expr 339 diff --git a/sys/src/cmd/python/Include/grammar.h b/sys/src/cmd/python/Include/grammar.h new file mode 100644 index 000000000..8426da30d --- /dev/null +++ b/sys/src/cmd/python/Include/grammar.h @@ -0,0 +1,93 @@ + +/* Grammar interface */ + +#ifndef Py_GRAMMAR_H +#define Py_GRAMMAR_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "bitset.h" /* Sigh... */ + +/* A label of an arc */ + +typedef struct { + int lb_type; + char *lb_str; +} label; + +#define EMPTY 0 /* Label number 0 is by definition the empty label */ + +/* A list of labels */ + +typedef struct { + int ll_nlabels; + label *ll_label; +} labellist; + +/* An arc from one state to another */ + +typedef struct { + short a_lbl; /* Label of this arc */ + short a_arrow; /* State where this arc goes to */ +} arc; + +/* A state in a DFA */ + +typedef struct { + int s_narcs; + arc *s_arc; /* Array of arcs */ + + /* Optional accelerators */ + int s_lower; /* Lowest label index */ + int s_upper; /* Highest label index */ + int *s_accel; /* Accelerator */ + int s_accept; /* Nonzero for accepting state */ +} state; + +/* A DFA */ + +typedef struct { + int d_type; /* Non-terminal this represents */ + char *d_name; /* For printing */ + int d_initial; /* Initial state */ + int d_nstates; + state *d_state; /* Array of states */ + bitset d_first; +} dfa; + +/* A grammar */ + +typedef struct { + int g_ndfas; + dfa *g_dfa; /* Array of DFAs */ + labellist g_ll; + int g_start; /* Start symbol of the grammar */ + int g_accel; /* Set if accelerators present */ +} grammar; + +/* FUNCTIONS */ + +grammar *newgrammar(int start); +dfa *adddfa(grammar *g, int type, char *name); +int addstate(dfa *d); +void addarc(dfa *d, int from, int to, int lbl); +dfa *PyGrammar_FindDFA(grammar *g, int type); + +int addlabel(labellist *ll, int type, char *str); +int findlabel(labellist *ll, int type, char *str); +char *PyGrammar_LabelRepr(label *lb); +void translatelabels(grammar *g); + +void addfirstsets(grammar *g); + +void PyGrammar_AddAccelerators(grammar *g); +void PyGrammar_RemoveAccelerators(grammar *); + +void printgrammar(grammar *g, FILE *fp); +void printnonterminals(grammar *g, FILE *fp); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_GRAMMAR_H */ diff --git a/sys/src/cmd/python/Include/import.h b/sys/src/cmd/python/Include/import.h new file mode 100644 index 000000000..414e059a3 --- /dev/null +++ b/sys/src/cmd/python/Include/import.h @@ -0,0 +1,64 @@ + +/* Module definition and import interface */ + +#ifndef Py_IMPORT_H +#define Py_IMPORT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(long) PyImport_GetMagicNumber(void); +PyAPI_FUNC(PyObject *) PyImport_ExecCodeModule(char *name, PyObject *co); +PyAPI_FUNC(PyObject *) PyImport_ExecCodeModuleEx( + char *name, PyObject *co, char *pathname); +PyAPI_FUNC(PyObject *) PyImport_GetModuleDict(void); +PyAPI_FUNC(PyObject *) PyImport_AddModule(const char *name); +PyAPI_FUNC(PyObject *) PyImport_ImportModule(const char *name); +PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel(char *name, + PyObject *globals, PyObject *locals, PyObject *fromlist, int level); + +/* For DLL compatibility */ +#undef PyImport_ImportModuleEx +PyAPI_FUNC(PyObject *) PyImport_ImportModuleEx( + char *name, PyObject *globals, PyObject *locals, PyObject *fromlist); +#define PyImport_ImportModuleEx(n, g, l, f) \ + PyImport_ImportModuleLevel(n, g, l, f, -1) + +PyAPI_FUNC(PyObject *) PyImport_Import(PyObject *name); +PyAPI_FUNC(PyObject *) PyImport_ReloadModule(PyObject *m); +PyAPI_FUNC(void) PyImport_Cleanup(void); +PyAPI_FUNC(int) PyImport_ImportFrozenModule(char *); + +PyAPI_FUNC(struct filedescr *) _PyImport_FindModule( + const char *, PyObject *, char *, size_t, FILE **, PyObject **); +PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr *); +PyAPI_FUNC(void) _PyImport_ReInitLock(void); + +PyAPI_FUNC(PyObject *)_PyImport_FindExtension(char *, char *); +PyAPI_FUNC(PyObject *)_PyImport_FixupExtension(char *, char *); + +struct _inittab { + char *name; + void (*initfunc)(void); +}; + +PyAPI_DATA(struct _inittab *) PyImport_Inittab; + +PyAPI_FUNC(int) PyImport_AppendInittab(char *name, void (*initfunc)(void)); +PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab); + +struct _frozen { + char *name; + unsigned char *code; + int size; +}; + +/* Embedding apps may change this pointer to point to their favorite + collection of frozen modules: */ + +PyAPI_DATA(struct _frozen *) PyImport_FrozenModules; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_IMPORT_H */ diff --git a/sys/src/cmd/python/Include/intobject.h b/sys/src/cmd/python/Include/intobject.h new file mode 100644 index 000000000..1f4846e86 --- /dev/null +++ b/sys/src/cmd/python/Include/intobject.h @@ -0,0 +1,64 @@ + +/* Integer object interface */ + +/* +PyIntObject represents a (long) integer. This is an immutable object; +an integer cannot change its value after creation. + +There are functions to create new integer objects, to test an object +for integer-ness, and to get the integer value. The latter functions +returns -1 and sets errno to EBADF if the object is not an PyIntObject. +None of the functions should be applied to nil objects. + +The type PyIntObject is (unfortunately) exposed here so we can declare +_Py_TrueStruct and _Py_ZeroStruct in boolobject.h; don't use this. +*/ + +#ifndef Py_INTOBJECT_H +#define Py_INTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_HEAD + long ob_ival; +} PyIntObject; + +PyAPI_DATA(PyTypeObject) PyInt_Type; + +#define PyInt_Check(op) PyObject_TypeCheck(op, &PyInt_Type) +#define PyInt_CheckExact(op) ((op)->ob_type == &PyInt_Type) + +PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int); +#ifdef Py_USING_UNICODE +PyAPI_FUNC(PyObject *) PyInt_FromUnicode(Py_UNICODE*, Py_ssize_t, int); +#endif +PyAPI_FUNC(PyObject *) PyInt_FromLong(long); +PyAPI_FUNC(PyObject *) PyInt_FromSize_t(size_t); +PyAPI_FUNC(PyObject *) PyInt_FromSsize_t(Py_ssize_t); +PyAPI_FUNC(long) PyInt_AsLong(PyObject *); +PyAPI_FUNC(Py_ssize_t) PyInt_AsSsize_t(PyObject *); +PyAPI_FUNC(unsigned long) PyInt_AsUnsignedLongMask(PyObject *); +#ifdef HAVE_LONG_LONG +PyAPI_FUNC(unsigned PY_LONG_LONG) PyInt_AsUnsignedLongLongMask(PyObject *); +#endif + +PyAPI_FUNC(long) PyInt_GetMax(void); + +/* Macro, trading safety for speed */ +#define PyInt_AS_LONG(op) (((PyIntObject *)(op))->ob_ival) + +/* These aren't really part of the Int object, but they're handy; the protos + * are necessary for systems that need the magic of PyAPI_FUNC and that want + * to have stropmodule as a dynamically loaded module instead of building it + * into the main Python shared library/DLL. Guido thinks I'm weird for + * building it this way. :-) [cjh] + */ +PyAPI_FUNC(unsigned long) PyOS_strtoul(char *, char **, int); +PyAPI_FUNC(long) PyOS_strtol(char *, char **, int); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTOBJECT_H */ diff --git a/sys/src/cmd/python/Include/intrcheck.h b/sys/src/cmd/python/Include/intrcheck.h new file mode 100644 index 000000000..3b67ed0d5 --- /dev/null +++ b/sys/src/cmd/python/Include/intrcheck.h @@ -0,0 +1,15 @@ + +#ifndef Py_INTRCHECK_H +#define Py_INTRCHECK_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(int) PyOS_InterruptOccurred(void); +PyAPI_FUNC(void) PyOS_InitInterrupts(void); +PyAPI_FUNC(void) PyOS_AfterFork(void); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTRCHECK_H */ diff --git a/sys/src/cmd/python/Include/iterobject.h b/sys/src/cmd/python/Include/iterobject.h new file mode 100644 index 000000000..c078ebb28 --- /dev/null +++ b/sys/src/cmd/python/Include/iterobject.h @@ -0,0 +1,23 @@ +#ifndef Py_ITEROBJECT_H +#define Py_ITEROBJECT_H +/* Iterators (the basic kind, over a sequence) */ +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PySeqIter_Type; + +#define PySeqIter_Check(op) ((op)->ob_type == &PySeqIter_Type) + +PyAPI_FUNC(PyObject *) PySeqIter_New(PyObject *); + +PyAPI_DATA(PyTypeObject) PyCallIter_Type; + +#define PyCallIter_Check(op) ((op)->ob_type == &PyCallIter_Type) + +PyAPI_FUNC(PyObject *) PyCallIter_New(PyObject *, PyObject *); +#ifdef __cplusplus +} +#endif +#endif /* !Py_ITEROBJECT_H */ + diff --git a/sys/src/cmd/python/Include/listobject.h b/sys/src/cmd/python/Include/listobject.h new file mode 100644 index 000000000..d9012ce93 --- /dev/null +++ b/sys/src/cmd/python/Include/listobject.h @@ -0,0 +1,67 @@ + +/* List object interface */ + +/* +Another generally useful object type is an list of object pointers. +This is a mutable type: the list items can be changed, and items can be +added or removed. Out-of-range indices or non-list objects are ignored. + +*** WARNING *** PyList_SetItem does not increment the new item's reference +count, but does decrement the reference count of the item it replaces, +if not nil. It does *decrement* the reference count if it is *not* +inserted in the list. Similarly, PyList_GetItem does not increment the +returned item's reference count. +*/ + +#ifndef Py_LISTOBJECT_H +#define Py_LISTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + PyObject_VAR_HEAD + /* Vector of pointers to list elements. list[0] is ob_item[0], etc. */ + PyObject **ob_item; + + /* ob_item contains space for 'allocated' elements. The number + * currently in use is ob_size. + * Invariants: + * 0 <= ob_size <= allocated + * len(list) == ob_size + * ob_item == NULL implies ob_size == allocated == 0 + * list.sort() temporarily sets allocated to -1 to detect mutations. + * + * Items must normally not be NULL, except during construction when + * the list is not yet visible outside the function that builds it. + */ + Py_ssize_t allocated; +} PyListObject; + +PyAPI_DATA(PyTypeObject) PyList_Type; + +#define PyList_Check(op) PyObject_TypeCheck(op, &PyList_Type) +#define PyList_CheckExact(op) ((op)->ob_type == &PyList_Type) + +PyAPI_FUNC(PyObject *) PyList_New(Py_ssize_t size); +PyAPI_FUNC(Py_ssize_t) PyList_Size(PyObject *); +PyAPI_FUNC(PyObject *) PyList_GetItem(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyList_SetItem(PyObject *, Py_ssize_t, PyObject *); +PyAPI_FUNC(int) PyList_Insert(PyObject *, Py_ssize_t, PyObject *); +PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyList_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); +PyAPI_FUNC(int) PyList_SetSlice(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); +PyAPI_FUNC(int) PyList_Sort(PyObject *); +PyAPI_FUNC(int) PyList_Reverse(PyObject *); +PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *); +PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *); + +/* Macro, trading safety for speed */ +#define PyList_GET_ITEM(op, i) (((PyListObject *)(op))->ob_item[i]) +#define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v)) +#define PyList_GET_SIZE(op) (((PyListObject *)(op))->ob_size) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_LISTOBJECT_H */ diff --git a/sys/src/cmd/python/Include/longintrepr.h b/sys/src/cmd/python/Include/longintrepr.h new file mode 100644 index 000000000..b1574ba50 --- /dev/null +++ b/sys/src/cmd/python/Include/longintrepr.h @@ -0,0 +1,63 @@ +#ifndef Py_LONGINTREPR_H +#define Py_LONGINTREPR_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* This is published for the benefit of "friend" marshal.c only. */ + +/* Parameters of the long integer representation. + These shouldn't have to be changed as C should guarantee that a short + contains at least 16 bits, but it's made changeable anyway. + Note: 'digit' should be able to hold 2*MASK+1, and 'twodigits' + should be able to hold the intermediate results in 'mul' + (at most (BASE-1)*(2*BASE+1) == MASK*(2*MASK+3)). + Also, x_sub assumes that 'digit' is an unsigned type, and overflow + is handled by taking the result mod 2**N for some N > SHIFT. + And, at some places it is assumed that MASK fits in an int, as well. + long_pow() requires that SHIFT be divisible by 5. */ + +typedef unsigned short digit; +typedef unsigned int wdigit; /* digit widened to parameter size */ +#define BASE_TWODIGITS_TYPE long +typedef unsigned BASE_TWODIGITS_TYPE twodigits; +typedef BASE_TWODIGITS_TYPE stwodigits; /* signed variant of twodigits */ + +#define SHIFT 15 +#define BASE ((digit)1 << SHIFT) +#define MASK ((int)(BASE - 1)) + +#if SHIFT % 5 != 0 +#error "longobject.c requires that SHIFT be divisible by 5" +#endif + +/* Long integer representation. + The absolute value of a number is equal to + SUM(for i=0 through abs(ob_size)-1) ob_digit[i] * 2**(SHIFT*i) + Negative numbers are represented with ob_size < 0; + zero is represented by ob_size == 0. + In a normalized number, ob_digit[abs(ob_size)-1] (the most significant + digit) is never zero. Also, in all cases, for all valid i, + 0 <= ob_digit[i] <= MASK. + The allocation function takes care of allocating extra memory + so that ob_digit[0] ... ob_digit[abs(ob_size)-1] are actually available. + + CAUTION: Generic code manipulating subtypes of PyVarObject has to + aware that longs abuse ob_size's sign bit. +*/ + +struct _longobject { + PyObject_VAR_HEAD + digit ob_digit[1]; +}; + +PyAPI_FUNC(PyLongObject *) _PyLong_New(Py_ssize_t); + +/* Return a copy of src. */ +PyAPI_FUNC(PyObject *) _PyLong_Copy(PyLongObject *src); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_LONGINTREPR_H */ diff --git a/sys/src/cmd/python/Include/longobject.h b/sys/src/cmd/python/Include/longobject.h new file mode 100644 index 000000000..eef4e9b4b --- /dev/null +++ b/sys/src/cmd/python/Include/longobject.h @@ -0,0 +1,114 @@ +#ifndef Py_LONGOBJECT_H +#define Py_LONGOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Long (arbitrary precision) integer object interface */ + +typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */ + +PyAPI_DATA(PyTypeObject) PyLong_Type; + +#define PyLong_Check(op) PyObject_TypeCheck(op, &PyLong_Type) +#define PyLong_CheckExact(op) ((op)->ob_type == &PyLong_Type) + +PyAPI_FUNC(PyObject *) PyLong_FromLong(long); +PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLong(unsigned long); +PyAPI_FUNC(PyObject *) PyLong_FromDouble(double); +PyAPI_FUNC(long) PyLong_AsLong(PyObject *); +PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLong(PyObject *); +PyAPI_FUNC(unsigned long) PyLong_AsUnsignedLongMask(PyObject *); + +/* For use by intobject.c only */ +PyAPI_FUNC(Py_ssize_t) _PyLong_AsSsize_t(PyObject *); +PyAPI_FUNC(PyObject *) _PyLong_FromSize_t(size_t); +PyAPI_FUNC(PyObject *) _PyLong_FromSsize_t(Py_ssize_t); +PyAPI_DATA(int) _PyLong_DigitValue[256]; + +/* _PyLong_AsScaledDouble returns a double x and an exponent e such that + the true value is approximately equal to x * 2**(SHIFT*e). e is >= 0. + x is 0.0 if and only if the input is 0 (in which case, e and x are both + zeroes). Overflow is impossible. Note that the exponent returned must + be multiplied by SHIFT! There may not be enough room in an int to store + e*SHIFT directly. */ +PyAPI_FUNC(double) _PyLong_AsScaledDouble(PyObject *vv, int *e); + +PyAPI_FUNC(double) PyLong_AsDouble(PyObject *); +PyAPI_FUNC(PyObject *) PyLong_FromVoidPtr(void *); +PyAPI_FUNC(void *) PyLong_AsVoidPtr(PyObject *); + +#ifdef HAVE_LONG_LONG +PyAPI_FUNC(PyObject *) PyLong_FromLongLong(PY_LONG_LONG); +PyAPI_FUNC(PyObject *) PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG); +PyAPI_FUNC(PY_LONG_LONG) PyLong_AsLongLong(PyObject *); +PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLong(PyObject *); +PyAPI_FUNC(unsigned PY_LONG_LONG) PyLong_AsUnsignedLongLongMask(PyObject *); +#endif /* HAVE_LONG_LONG */ + +PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int); +#ifdef Py_USING_UNICODE +PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, Py_ssize_t, int); +#endif + +/* _PyLong_Sign. Return 0 if v is 0, -1 if v < 0, +1 if v > 0. + v must not be NULL, and must be a normalized long. + There are no error cases. +*/ +PyAPI_FUNC(int) _PyLong_Sign(PyObject *v); + + +/* _PyLong_NumBits. Return the number of bits needed to represent the + absolute value of a long. For example, this returns 1 for 1 and -1, 2 + for 2 and -2, and 2 for 3 and -3. It returns 0 for 0. + v must not be NULL, and must be a normalized long. + (size_t)-1 is returned and OverflowError set if the true result doesn't + fit in a size_t. +*/ +PyAPI_FUNC(size_t) _PyLong_NumBits(PyObject *v); + +/* _PyLong_FromByteArray: View the n unsigned bytes as a binary integer in + base 256, and return a Python long with the same numeric value. + If n is 0, the integer is 0. Else: + If little_endian is 1/true, bytes[n-1] is the MSB and bytes[0] the LSB; + else (little_endian is 0/false) bytes[0] is the MSB and bytes[n-1] the + LSB. + If is_signed is 0/false, view the bytes as a non-negative integer. + If is_signed is 1/true, view the bytes as a 2's-complement integer, + non-negative if bit 0x80 of the MSB is clear, negative if set. + Error returns: + + Return NULL with the appropriate exception set if there's not + enough memory to create the Python long. +*/ +PyAPI_FUNC(PyObject *) _PyLong_FromByteArray( + const unsigned char* bytes, size_t n, + int little_endian, int is_signed); + +/* _PyLong_AsByteArray: Convert the least-significant 8*n bits of long + v to a base-256 integer, stored in array bytes. Normally return 0, + return -1 on error. + If little_endian is 1/true, store the MSB at bytes[n-1] and the LSB at + bytes[0]; else (little_endian is 0/false) store the MSB at bytes[0] and + the LSB at bytes[n-1]. + If is_signed is 0/false, it's an error if v < 0; else (v >= 0) n bytes + are filled and there's nothing special about bit 0x80 of the MSB. + If is_signed is 1/true, bytes is filled with the 2's-complement + representation of v's value. Bit 0x80 of the MSB is the sign bit. + Error returns (-1): + + is_signed is 0 and v < 0. TypeError is set in this case, and bytes + isn't altered. + + n isn't big enough to hold the full mathematical value of v. For + example, if is_signed is 0 and there are more digits in the v than + fit in n; or if is_signed is 1, v < 0, and n is just 1 bit shy of + being large enough to hold a sign bit. OverflowError is set in this + case, but bytes holds the least-signficant n bytes of the true value. +*/ +PyAPI_FUNC(int) _PyLong_AsByteArray(PyLongObject* v, + unsigned char* bytes, size_t n, + int little_endian, int is_signed); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_LONGOBJECT_H */ diff --git a/sys/src/cmd/python/Include/marshal.h b/sys/src/cmd/python/Include/marshal.h new file mode 100644 index 000000000..411fdca36 --- /dev/null +++ b/sys/src/cmd/python/Include/marshal.h @@ -0,0 +1,25 @@ + +/* Interface for marshal.c */ + +#ifndef Py_MARSHAL_H +#define Py_MARSHAL_H +#ifdef __cplusplus +extern "C" { +#endif + +#define Py_MARSHAL_VERSION 2 + +PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int); +PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int); +PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); + +PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *); +PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *); +PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *); +PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *); +PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MARSHAL_H */ diff --git a/sys/src/cmd/python/Include/metagrammar.h b/sys/src/cmd/python/Include/metagrammar.h new file mode 100644 index 000000000..15c8ef8f3 --- /dev/null +++ b/sys/src/cmd/python/Include/metagrammar.h @@ -0,0 +1,18 @@ +#ifndef Py_METAGRAMMAR_H +#define Py_METAGRAMMAR_H +#ifdef __cplusplus +extern "C" { +#endif + + +#define MSTART 256 +#define RULE 257 +#define RHS 258 +#define ALT 259 +#define ITEM 260 +#define ATOM 261 + +#ifdef __cplusplus +} +#endif +#endif /* !Py_METAGRAMMAR_H */ diff --git a/sys/src/cmd/python/Include/methodobject.h b/sys/src/cmd/python/Include/methodobject.h new file mode 100644 index 000000000..c887d947e --- /dev/null +++ b/sys/src/cmd/python/Include/methodobject.h @@ -0,0 +1,91 @@ + +/* Method object interface */ + +#ifndef Py_METHODOBJECT_H +#define Py_METHODOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* This is about the type 'builtin_function_or_method', + not Python methods in user-defined classes. See classobject.h + for the latter. */ + +PyAPI_DATA(PyTypeObject) PyCFunction_Type; + +#define PyCFunction_Check(op) ((op)->ob_type == &PyCFunction_Type) + +typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); +typedef PyObject *(*PyCFunctionWithKeywords)(PyObject *, PyObject *, + PyObject *); +typedef PyObject *(*PyNoArgsFunction)(PyObject *); + +PyAPI_FUNC(PyCFunction) PyCFunction_GetFunction(PyObject *); +PyAPI_FUNC(PyObject *) PyCFunction_GetSelf(PyObject *); +PyAPI_FUNC(int) PyCFunction_GetFlags(PyObject *); + +/* Macros for direct access to these values. Type checks are *not* + done, so use with care. */ +#define PyCFunction_GET_FUNCTION(func) \ + (((PyCFunctionObject *)func) -> m_ml -> ml_meth) +#define PyCFunction_GET_SELF(func) \ + (((PyCFunctionObject *)func) -> m_self) +#define PyCFunction_GET_FLAGS(func) \ + (((PyCFunctionObject *)func) -> m_ml -> ml_flags) +PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); + +struct PyMethodDef { + const char *ml_name; /* The name of the built-in function/method */ + PyCFunction ml_meth; /* The C function that implements it */ + int ml_flags; /* Combination of METH_xxx flags, which mostly + describe the args expected by the C func */ + const char *ml_doc; /* The __doc__ attribute, or NULL */ +}; +typedef struct PyMethodDef PyMethodDef; + +PyAPI_FUNC(PyObject *) Py_FindMethod(PyMethodDef[], PyObject *, const char *); + +#define PyCFunction_New(ML, SELF) PyCFunction_NewEx((ML), (SELF), NULL) +PyAPI_FUNC(PyObject *) PyCFunction_NewEx(PyMethodDef *, PyObject *, + PyObject *); + +/* Flag passed to newmethodobject */ +#define METH_OLDARGS 0x0000 +#define METH_VARARGS 0x0001 +#define METH_KEYWORDS 0x0002 +/* METH_NOARGS and METH_O must not be combined with the flags above. */ +#define METH_NOARGS 0x0004 +#define METH_O 0x0008 + +/* METH_CLASS and METH_STATIC are a little different; these control + the construction of methods for a class. These cannot be used for + functions in modules. */ +#define METH_CLASS 0x0010 +#define METH_STATIC 0x0020 + +/* METH_COEXIST allows a method to be entered eventhough a slot has + already filled the entry. When defined, the flag allows a separate + method, "__contains__" for example, to coexist with a defined + slot like sq_contains. */ + +#define METH_COEXIST 0x0040 + +typedef struct PyMethodChain { + PyMethodDef *methods; /* Methods of this type */ + struct PyMethodChain *link; /* NULL or base type */ +} PyMethodChain; + +PyAPI_FUNC(PyObject *) Py_FindMethodInChain(PyMethodChain *, PyObject *, + const char *); + +typedef struct { + PyObject_HEAD + PyMethodDef *m_ml; /* Description of the C function to call */ + PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ + PyObject *m_module; /* The __module__ attribute, can be anything */ +} PyCFunctionObject; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_METHODOBJECT_H */ diff --git a/sys/src/cmd/python/Include/modsupport.h b/sys/src/cmd/python/Include/modsupport.h new file mode 100644 index 000000000..23d5d3a09 --- /dev/null +++ b/sys/src/cmd/python/Include/modsupport.h @@ -0,0 +1,133 @@ + +#ifndef Py_MODSUPPORT_H +#define Py_MODSUPPORT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Module support interface */ + +#include <stdarg.h> + +/* If PY_SSIZE_T_CLEAN is defined, each functions treats #-specifier + to mean Py_ssize_t */ +#ifdef PY_SSIZE_T_CLEAN +#define PyArg_Parse _PyArg_Parse_SizeT +#define PyArg_ParseTuple _PyArg_ParseTuple_SizeT +#define PyArg_ParseTupleAndKeywords _PyArg_ParseTupleAndKeywords_SizeT +#define PyArg_VaParse _PyArg_VaParse_SizeT +#define PyArg_VaParseTupleAndKeywords _PyArg_VaParseTupleAndKeywords_SizeT +#define Py_BuildValue _Py_BuildValue_SizeT +#define Py_VaBuildValue _Py_VaBuildValue_SizeT +#else +PyAPI_FUNC(PyObject *) _Py_VaBuildValue_SizeT(const char *, va_list); +#endif + +PyAPI_FUNC(int) PyArg_Parse(PyObject *, const char *, ...); +PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *, const char *, ...); +PyAPI_FUNC(int) PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, + const char *, char **, ...); +PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...); +PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...); +PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); +PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kw); + +PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list); +PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, + const char *, char **, va_list); +PyAPI_FUNC(PyObject *) Py_VaBuildValue(const char *, va_list); + +PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); +PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); +PyAPI_FUNC(int) PyModule_AddStringConstant(PyObject *, const char *, const char *); + + +#define PYTHON_API_VERSION 1013 +#define PYTHON_API_STRING "1013" +/* The API version is maintained (independently from the Python version) + so we can detect mismatches between the interpreter and dynamically + loaded modules. These are diagnosed by an error message but + the module is still loaded (because the mismatch can only be tested + after loading the module). The error message is intended to + explain the core dump a few seconds later. + + The symbol PYTHON_API_STRING defines the same value as a string + literal. *** PLEASE MAKE SURE THE DEFINITIONS MATCH. *** + + Please add a line or two to the top of this log for each API + version change: + + 22-Feb-2006 MvL 1013 PEP 353 - long indices for sequence lengths + + 19-Aug-2002 GvR 1012 Changes to string object struct for + interning changes, saving 3 bytes. + + 17-Jul-2001 GvR 1011 Descr-branch, just to be on the safe side + + 25-Jan-2001 FLD 1010 Parameters added to PyCode_New() and + PyFrame_New(); Python 2.1a2 + + 14-Mar-2000 GvR 1009 Unicode API added + + 3-Jan-1999 GvR 1007 Decided to change back! (Don't reuse 1008!) + + 3-Dec-1998 GvR 1008 Python 1.5.2b1 + + 18-Jan-1997 GvR 1007 string interning and other speedups + + 11-Oct-1996 GvR renamed Py_Ellipses to Py_Ellipsis :-( + + 30-Jul-1996 GvR Slice and ellipses syntax added + + 23-Jul-1996 GvR For 1.4 -- better safe than sorry this time :-) + + 7-Nov-1995 GvR Keyword arguments (should've been done at 1.3 :-( ) + + 10-Jan-1995 GvR Renamed globals to new naming scheme + + 9-Jan-1995 GvR Initial version (incompatible with older API) +*/ + +#ifdef MS_WINDOWS +/* Special defines for Windows versions used to live here. Things + have changed, and the "Version" is now in a global string variable. + Reason for this is that this for easier branding of a "custom DLL" + without actually needing a recompile. */ +#endif /* MS_WINDOWS */ + +#if SIZEOF_SIZE_T != SIZEOF_INT +/* On a 64-bit system, rename the Py_InitModule4 so that 2.4 + modules cannot get loaded into a 2.5 interpreter */ +#define Py_InitModule4 Py_InitModule4_64 +#endif + +#ifdef Py_TRACE_REFS + /* When we are tracing reference counts, rename Py_InitModule4 so + modules compiled with incompatible settings will generate a + link-time error. */ + #if SIZEOF_SIZE_T != SIZEOF_INT + #undef Py_InitModule4 + #define Py_InitModule4 Py_InitModule4TraceRefs_64 + #else + #define Py_InitModule4 Py_InitModule4TraceRefs + #endif +#endif + +PyAPI_FUNC(PyObject *) Py_InitModule4(const char *name, PyMethodDef *methods, + const char *doc, PyObject *self, + int apiver); + +#define Py_InitModule(name, methods) \ + Py_InitModule4(name, methods, (char *)NULL, (PyObject *)NULL, \ + PYTHON_API_VERSION) + +#define Py_InitModule3(name, methods, doc) \ + Py_InitModule4(name, methods, doc, (PyObject *)NULL, \ + PYTHON_API_VERSION) + +PyAPI_DATA(char *) _Py_PackageContext; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MODSUPPORT_H */ diff --git a/sys/src/cmd/python/Include/moduleobject.h b/sys/src/cmd/python/Include/moduleobject.h new file mode 100644 index 000000000..3d278af87 --- /dev/null +++ b/sys/src/cmd/python/Include/moduleobject.h @@ -0,0 +1,24 @@ + +/* Module object interface */ + +#ifndef Py_MODULEOBJECT_H +#define Py_MODULEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(PyTypeObject) PyModule_Type; + +#define PyModule_Check(op) PyObject_TypeCheck(op, &PyModule_Type) +#define PyModule_CheckExact(op) ((op)->ob_type == &PyModule_Type) + +PyAPI_FUNC(PyObject *) PyModule_New(const char *); +PyAPI_FUNC(PyObject *) PyModule_GetDict(PyObject *); +PyAPI_FUNC(char *) PyModule_GetName(PyObject *); +PyAPI_FUNC(char *) PyModule_GetFilename(PyObject *); +PyAPI_FUNC(void) _PyModule_Clear(PyObject *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_MODULEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/node.h b/sys/src/cmd/python/Include/node.h new file mode 100644 index 000000000..e23e709ff --- /dev/null +++ b/sys/src/cmd/python/Include/node.h @@ -0,0 +1,40 @@ + +/* Parse tree node interface */ + +#ifndef Py_NODE_H +#define Py_NODE_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _node { + short n_type; + char *n_str; + int n_lineno; + int n_col_offset; + int n_nchildren; + struct _node *n_child; +} node; + +PyAPI_FUNC(node *) PyNode_New(int type); +PyAPI_FUNC(int) PyNode_AddChild(node *n, int type, + char *str, int lineno, int col_offset); +PyAPI_FUNC(void) PyNode_Free(node *n); + +/* Node access functions */ +#define NCH(n) ((n)->n_nchildren) + +#define CHILD(n, i) (&(n)->n_child[i]) +#define RCHILD(n, i) (CHILD(n, NCH(n) + i)) +#define TYPE(n) ((n)->n_type) +#define STR(n) ((n)->n_str) + +/* Assert that the type of a node is what we expect */ +#define REQ(n, type) assert(TYPE(n) == (type)) + +PyAPI_FUNC(void) PyNode_ListTree(node *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_NODE_H */ diff --git a/sys/src/cmd/python/Include/object.h b/sys/src/cmd/python/Include/object.h new file mode 100644 index 000000000..b0817e6e3 --- /dev/null +++ b/sys/src/cmd/python/Include/object.h @@ -0,0 +1,868 @@ +#ifndef Py_OBJECT_H +#define Py_OBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Object and type object interface */ + +/* +Objects are structures allocated on the heap. Special rules apply to +the use of objects to ensure they are properly garbage-collected. +Objects are never allocated statically or on the stack; they must be +accessed through special macros and functions only. (Type objects are +exceptions to the first rule; the standard types are represented by +statically initialized type objects, although work on type/class unification +for Python 2.2 made it possible to have heap-allocated type objects too). + +An object has a 'reference count' that is increased or decreased when a +pointer to the object is copied or deleted; when the reference count +reaches zero there are no references to the object left and it can be +removed from the heap. + +An object has a 'type' that determines what it represents and what kind +of data it contains. An object's type is fixed when it is created. +Types themselves are represented as objects; an object contains a +pointer to the corresponding type object. The type itself has a type +pointer pointing to the object representing the type 'type', which +contains a pointer to itself!). + +Objects do not float around in memory; once allocated an object keeps +the same size and address. Objects that must hold variable-size data +can contain pointers to variable-size parts of the object. Not all +objects of the same type have the same size; but the size cannot change +after allocation. (These restrictions are made so a reference to an +object can be simply a pointer -- moving an object would require +updating all the pointers, and changing an object's size would require +moving it if there was another object right next to it.) + +Objects are always accessed through pointers of the type 'PyObject *'. +The type 'PyObject' is a structure that only contains the reference count +and the type pointer. The actual memory allocated for an object +contains other data that can only be accessed after casting the pointer +to a pointer to a longer structure type. This longer type must start +with the reference count and type fields; the macro PyObject_HEAD should be +used for this (to accommodate for future changes). The implementation +of a particular object type can cast the object pointer to the proper +type and back. + +A standard interface exists for objects that contain an array of items +whose size is determined when the object is allocated. +*/ + +/* Py_DEBUG implies Py_TRACE_REFS. */ +#if defined(Py_DEBUG) && !defined(Py_TRACE_REFS) +#define Py_TRACE_REFS +#endif + +/* Py_TRACE_REFS implies Py_REF_DEBUG. */ +#if defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) +#define Py_REF_DEBUG +#endif + +#ifdef Py_TRACE_REFS +/* Define pointers to support a doubly-linked list of all live heap objects. */ +#define _PyObject_HEAD_EXTRA \ + struct _object *_ob_next; \ + struct _object *_ob_prev; + +#define _PyObject_EXTRA_INIT 0, 0, + +#else +#define _PyObject_HEAD_EXTRA +#define _PyObject_EXTRA_INIT +#endif + +/* PyObject_HEAD defines the initial segment of every PyObject. */ +#define PyObject_HEAD \ + _PyObject_HEAD_EXTRA \ + Py_ssize_t ob_refcnt; \ + struct _typeobject *ob_type; + +#define PyObject_HEAD_INIT(type) \ + _PyObject_EXTRA_INIT \ + 1, type, + +/* PyObject_VAR_HEAD defines the initial segment of all variable-size + * container objects. These end with a declaration of an array with 1 + * element, but enough space is malloc'ed so that the array actually + * has room for ob_size elements. Note that ob_size is an element count, + * not necessarily a byte count. + */ +#define PyObject_VAR_HEAD \ + PyObject_HEAD \ + Py_ssize_t ob_size; /* Number of items in variable part */ +#define Py_INVALID_SIZE (Py_ssize_t)-1 + +/* Nothing is actually declared to be a PyObject, but every pointer to + * a Python object can be cast to a PyObject*. This is inheritance built + * by hand. Similarly every pointer to a variable-size Python object can, + * in addition, be cast to PyVarObject*. + */ +typedef struct _object { + PyObject_HEAD +} PyObject; + +typedef struct { + PyObject_VAR_HEAD +} PyVarObject; + + +/* +Type objects contain a string containing the type name (to help somewhat +in debugging), the allocation parameters (see PyObject_New() and +PyObject_NewVar()), +and methods for accessing objects of the type. Methods are optional, a +nil pointer meaning that particular kind of access is not available for +this type. The Py_DECREF() macro uses the tp_dealloc method without +checking for a nil pointer; it should always be implemented except if +the implementation can guarantee that the reference count will never +reach zero (e.g., for statically allocated type objects). + +NB: the methods for certain type groups are now contained in separate +method blocks. +*/ + +typedef PyObject * (*unaryfunc)(PyObject *); +typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); +typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); +typedef int (*inquiry)(PyObject *); +typedef Py_ssize_t (*lenfunc)(PyObject *); +typedef int (*coercion)(PyObject **, PyObject **); +typedef PyObject *(*intargfunc)(PyObject *, int) Py_DEPRECATED(2.5); +typedef PyObject *(*intintargfunc)(PyObject *, int, int) Py_DEPRECATED(2.5); +typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t); +typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t); +typedef int(*intobjargproc)(PyObject *, int, PyObject *); +typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *); +typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *); +typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); +typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *); + +/* int-based buffer interface */ +typedef int (*getreadbufferproc)(PyObject *, int, void **); +typedef int (*getwritebufferproc)(PyObject *, int, void **); +typedef int (*getsegcountproc)(PyObject *, int *); +typedef int (*getcharbufferproc)(PyObject *, int, char **); +/* ssize_t-based buffer interface */ +typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **); +typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **); +typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *); +typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **); + +typedef int (*objobjproc)(PyObject *, PyObject *); +typedef int (*visitproc)(PyObject *, void *); +typedef int (*traverseproc)(PyObject *, visitproc, void *); + +typedef struct { + /* For numbers without flag bit Py_TPFLAGS_CHECKTYPES set, all + arguments are guaranteed to be of the object's type (modulo + coercion hacks -- i.e. if the type's coercion function + returns other types, then these are allowed as well). Numbers that + have the Py_TPFLAGS_CHECKTYPES flag bit set should check *both* + arguments for proper type and implement the necessary conversions + in the slot functions themselves. */ + + binaryfunc nb_add; + binaryfunc nb_subtract; + binaryfunc nb_multiply; + binaryfunc nb_divide; + binaryfunc nb_remainder; + binaryfunc nb_divmod; + ternaryfunc nb_power; + unaryfunc nb_negative; + unaryfunc nb_positive; + unaryfunc nb_absolute; + inquiry nb_nonzero; + unaryfunc nb_invert; + binaryfunc nb_lshift; + binaryfunc nb_rshift; + binaryfunc nb_and; + binaryfunc nb_xor; + binaryfunc nb_or; + coercion nb_coerce; + unaryfunc nb_int; + unaryfunc nb_long; + unaryfunc nb_float; + unaryfunc nb_oct; + unaryfunc nb_hex; + /* Added in release 2.0 */ + binaryfunc nb_inplace_add; + binaryfunc nb_inplace_subtract; + binaryfunc nb_inplace_multiply; + binaryfunc nb_inplace_divide; + binaryfunc nb_inplace_remainder; + ternaryfunc nb_inplace_power; + binaryfunc nb_inplace_lshift; + binaryfunc nb_inplace_rshift; + binaryfunc nb_inplace_and; + binaryfunc nb_inplace_xor; + binaryfunc nb_inplace_or; + + /* Added in release 2.2 */ + /* The following require the Py_TPFLAGS_HAVE_CLASS flag */ + binaryfunc nb_floor_divide; + binaryfunc nb_true_divide; + binaryfunc nb_inplace_floor_divide; + binaryfunc nb_inplace_true_divide; + + /* Added in release 2.5 */ + unaryfunc nb_index; +} PyNumberMethods; + +typedef struct { + lenfunc sq_length; + binaryfunc sq_concat; + ssizeargfunc sq_repeat; + ssizeargfunc sq_item; + ssizessizeargfunc sq_slice; + ssizeobjargproc sq_ass_item; + ssizessizeobjargproc sq_ass_slice; + objobjproc sq_contains; + /* Added in release 2.0 */ + binaryfunc sq_inplace_concat; + ssizeargfunc sq_inplace_repeat; +} PySequenceMethods; + +typedef struct { + lenfunc mp_length; + binaryfunc mp_subscript; + objobjargproc mp_ass_subscript; +} PyMappingMethods; + +typedef struct { + readbufferproc bf_getreadbuffer; + writebufferproc bf_getwritebuffer; + segcountproc bf_getsegcount; + charbufferproc bf_getcharbuffer; +} PyBufferProcs; + + +typedef void (*freefunc)(void *); +typedef void (*destructor)(PyObject *); +typedef int (*printfunc)(PyObject *, FILE *, int); +typedef PyObject *(*getattrfunc)(PyObject *, char *); +typedef PyObject *(*getattrofunc)(PyObject *, PyObject *); +typedef int (*setattrfunc)(PyObject *, char *, PyObject *); +typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *); +typedef int (*cmpfunc)(PyObject *, PyObject *); +typedef PyObject *(*reprfunc)(PyObject *); +typedef long (*hashfunc)(PyObject *); +typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int); +typedef PyObject *(*getiterfunc) (PyObject *); +typedef PyObject *(*iternextfunc) (PyObject *); +typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *); +typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *); +typedef int (*initproc)(PyObject *, PyObject *, PyObject *); +typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); +typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t); + +typedef struct _typeobject { + PyObject_VAR_HEAD + const char *tp_name; /* For printing, in format "<module>.<name>" */ + Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */ + + /* Methods to implement standard operations */ + + destructor tp_dealloc; + printfunc tp_print; + getattrfunc tp_getattr; + setattrfunc tp_setattr; + cmpfunc tp_compare; + reprfunc tp_repr; + + /* Method suites for standard classes */ + + PyNumberMethods *tp_as_number; + PySequenceMethods *tp_as_sequence; + PyMappingMethods *tp_as_mapping; + + /* More standard operations (here for binary compatibility) */ + + hashfunc tp_hash; + ternaryfunc tp_call; + reprfunc tp_str; + getattrofunc tp_getattro; + setattrofunc tp_setattro; + + /* Functions to access object as input/output buffer */ + PyBufferProcs *tp_as_buffer; + + /* Flags to define presence of optional/expanded features */ + long tp_flags; + + const char *tp_doc; /* Documentation string */ + + /* Assigned meaning in release 2.0 */ + /* call function for all accessible objects */ + traverseproc tp_traverse; + + /* delete references to contained objects */ + inquiry tp_clear; + + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + richcmpfunc tp_richcompare; + + /* weak reference enabler */ + Py_ssize_t tp_weaklistoffset; + + /* Added in release 2.2 */ + /* Iterators */ + getiterfunc tp_iter; + iternextfunc tp_iternext; + + /* Attribute descriptor and subclassing stuff */ + struct PyMethodDef *tp_methods; + struct PyMemberDef *tp_members; + struct PyGetSetDef *tp_getset; + struct _typeobject *tp_base; + PyObject *tp_dict; + descrgetfunc tp_descr_get; + descrsetfunc tp_descr_set; + Py_ssize_t tp_dictoffset; + initproc tp_init; + allocfunc tp_alloc; + newfunc tp_new; + freefunc tp_free; /* Low-level free-memory routine */ + inquiry tp_is_gc; /* For PyObject_IS_GC */ + PyObject *tp_bases; + PyObject *tp_mro; /* method resolution order */ + PyObject *tp_cache; + PyObject *tp_subclasses; + PyObject *tp_weaklist; + destructor tp_del; + +#ifdef COUNT_ALLOCS + /* these must be last and never explicitly initialized */ + Py_ssize_t tp_allocs; + Py_ssize_t tp_frees; + Py_ssize_t tp_maxalloc; + struct _typeobject *tp_prev; + struct _typeobject *tp_next; +#endif +} PyTypeObject; + + +/* The *real* layout of a type object when allocated on the heap */ +typedef struct _heaptypeobject { + /* Note: there's a dependency on the order of these members + in slotptr() in typeobject.c . */ + PyTypeObject ht_type; + PyNumberMethods as_number; + PyMappingMethods as_mapping; + PySequenceMethods as_sequence; /* as_sequence comes after as_mapping, + so that the mapping wins when both + the mapping and the sequence define + a given operator (e.g. __getitem__). + see add_operators() in typeobject.c . */ + PyBufferProcs as_buffer; + PyObject *ht_name, *ht_slots; + /* here are optional user slots, followed by the members. */ +} PyHeapTypeObject; + +/* access macro to the members which are floating "behind" the object */ +#define PyHeapType_GET_MEMBERS(etype) \ + ((PyMemberDef *)(((char *)etype) + (etype)->ht_type.ob_type->tp_basicsize)) + + +/* Generic type check */ +PyAPI_FUNC(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *); +#define PyObject_TypeCheck(ob, tp) \ + ((ob)->ob_type == (tp) || PyType_IsSubtype((ob)->ob_type, (tp))) + +PyAPI_DATA(PyTypeObject) PyType_Type; /* built-in 'type' */ +PyAPI_DATA(PyTypeObject) PyBaseObject_Type; /* built-in 'object' */ +PyAPI_DATA(PyTypeObject) PySuper_Type; /* built-in 'super' */ + +#define PyType_Check(op) PyObject_TypeCheck(op, &PyType_Type) +#define PyType_CheckExact(op) ((op)->ob_type == &PyType_Type) + +PyAPI_FUNC(int) PyType_Ready(PyTypeObject *); +PyAPI_FUNC(PyObject *) PyType_GenericAlloc(PyTypeObject *, Py_ssize_t); +PyAPI_FUNC(PyObject *) PyType_GenericNew(PyTypeObject *, + PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *); + +/* Generic operations on objects */ +PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); +PyAPI_FUNC(void) _PyObject_Dump(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); +PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *); +#ifdef Py_USING_UNICODE +PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *); +#endif +PyAPI_FUNC(int) PyObject_Compare(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyObject_RichCompare(PyObject *, PyObject *, int); +PyAPI_FUNC(int) PyObject_RichCompareBool(PyObject *, PyObject *, int); +PyAPI_FUNC(PyObject *) PyObject_GetAttrString(PyObject *, const char *); +PyAPI_FUNC(int) PyObject_SetAttrString(PyObject *, const char *, PyObject *); +PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *); +PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *); +PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *); +PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *); +PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *, + PyObject *, PyObject *); +PyAPI_FUNC(long) PyObject_Hash(PyObject *); +PyAPI_FUNC(int) PyObject_IsTrue(PyObject *); +PyAPI_FUNC(int) PyObject_Not(PyObject *); +PyAPI_FUNC(int) PyCallable_Check(PyObject *); +PyAPI_FUNC(int) PyNumber_Coerce(PyObject **, PyObject **); +PyAPI_FUNC(int) PyNumber_CoerceEx(PyObject **, PyObject **); + +PyAPI_FUNC(void) PyObject_ClearWeakRefs(PyObject *); + +/* A slot function whose address we need to compare */ +extern int _PyObject_SlotCompare(PyObject *, PyObject *); + + +/* PyObject_Dir(obj) acts like Python __builtin__.dir(obj), returning a + list of strings. PyObject_Dir(NULL) is like __builtin__.dir(), + returning the names of the current locals. In this case, if there are + no current locals, NULL is returned, and PyErr_Occurred() is false. +*/ +PyAPI_FUNC(PyObject *) PyObject_Dir(PyObject *); + + +/* Helpers for printing recursive container types */ +PyAPI_FUNC(int) Py_ReprEnter(PyObject *); +PyAPI_FUNC(void) Py_ReprLeave(PyObject *); + +/* Helpers for hash functions */ +PyAPI_FUNC(long) _Py_HashDouble(double); +PyAPI_FUNC(long) _Py_HashPointer(void*); + +/* Helper for passing objects to printf and the like */ +#define PyObject_REPR(obj) PyString_AS_STRING(PyObject_Repr(obj)) + +/* Flag bits for printing: */ +#define Py_PRINT_RAW 1 /* No string quotes etc. */ + +/* +`Type flags (tp_flags) + +These flags are used to extend the type structure in a backwards-compatible +fashion. Extensions can use the flags to indicate (and test) when a given +type structure contains a new feature. The Python core will use these when +introducing new functionality between major revisions (to avoid mid-version +changes in the PYTHON_API_VERSION). + +Arbitration of the flag bit positions will need to be coordinated among +all extension writers who publically release their extensions (this will +be fewer than you might expect!).. + +Python 1.5.2 introduced the bf_getcharbuffer slot into PyBufferProcs. + +Type definitions should use Py_TPFLAGS_DEFAULT for their tp_flags value. + +Code can use PyType_HasFeature(type_ob, flag_value) to test whether the +given type object has a specified feature. +*/ + +/* PyBufferProcs contains bf_getcharbuffer */ +#define Py_TPFLAGS_HAVE_GETCHARBUFFER (1L<<0) + +/* PySequenceMethods contains sq_contains */ +#define Py_TPFLAGS_HAVE_SEQUENCE_IN (1L<<1) + +/* This is here for backwards compatibility. Extensions that use the old GC + * API will still compile but the objects will not be tracked by the GC. */ +#define Py_TPFLAGS_GC 0 /* used to be (1L<<2) */ + +/* PySequenceMethods and PyNumberMethods contain in-place operators */ +#define Py_TPFLAGS_HAVE_INPLACEOPS (1L<<3) + +/* PyNumberMethods do their own coercion */ +#define Py_TPFLAGS_CHECKTYPES (1L<<4) + +/* tp_richcompare is defined */ +#define Py_TPFLAGS_HAVE_RICHCOMPARE (1L<<5) + +/* Objects which are weakly referencable if their tp_weaklistoffset is >0 */ +#define Py_TPFLAGS_HAVE_WEAKREFS (1L<<6) + +/* tp_iter is defined */ +#define Py_TPFLAGS_HAVE_ITER (1L<<7) + +/* New members introduced by Python 2.2 exist */ +#define Py_TPFLAGS_HAVE_CLASS (1L<<8) + +/* Set if the type object is dynamically allocated */ +#define Py_TPFLAGS_HEAPTYPE (1L<<9) + +/* Set if the type allows subclassing */ +#define Py_TPFLAGS_BASETYPE (1L<<10) + +/* Set if the type is 'ready' -- fully initialized */ +#define Py_TPFLAGS_READY (1L<<12) + +/* Set while the type is being 'readied', to prevent recursive ready calls */ +#define Py_TPFLAGS_READYING (1L<<13) + +/* Objects support garbage collection (see objimp.h) */ +#define Py_TPFLAGS_HAVE_GC (1L<<14) + +/* These two bits are preserved for Stackless Python, next after this is 17 */ +#ifdef STACKLESS +#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION (3L<<15) +#else +#define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0 +#endif + +/* Objects support nb_index in PyNumberMethods */ +#define Py_TPFLAGS_HAVE_INDEX (1L<<17) + +#define Py_TPFLAGS_DEFAULT ( \ + Py_TPFLAGS_HAVE_GETCHARBUFFER | \ + Py_TPFLAGS_HAVE_SEQUENCE_IN | \ + Py_TPFLAGS_HAVE_INPLACEOPS | \ + Py_TPFLAGS_HAVE_RICHCOMPARE | \ + Py_TPFLAGS_HAVE_WEAKREFS | \ + Py_TPFLAGS_HAVE_ITER | \ + Py_TPFLAGS_HAVE_CLASS | \ + Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \ + Py_TPFLAGS_HAVE_INDEX | \ + 0) + +#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) + + +/* +The macros Py_INCREF(op) and Py_DECREF(op) are used to increment or decrement +reference counts. Py_DECREF calls the object's deallocator function when +the refcount falls to 0; for +objects that don't contain references to other objects or heap memory +this can be the standard function free(). Both macros can be used +wherever a void expression is allowed. The argument must not be a +NIL pointer. If it may be NIL, use Py_XINCREF/Py_XDECREF instead. +The macro _Py_NewReference(op) initialize reference counts to 1, and +in special builds (Py_REF_DEBUG, Py_TRACE_REFS) performs additional +bookkeeping appropriate to the special build. + +We assume that the reference count field can never overflow; this can +be proven when the size of the field is the same as the pointer size, so +we ignore the possibility. Provided a C int is at least 32 bits (which +is implicitly assumed in many parts of this code), that's enough for +about 2**31 references to an object. + +XXX The following became out of date in Python 2.2, but I'm not sure +XXX what the full truth is now. Certainly, heap-allocated type objects +XXX can and should be deallocated. +Type objects should never be deallocated; the type pointer in an object +is not considered to be a reference to the type object, to save +complications in the deallocation function. (This is actually a +decision that's up to the implementer of each new type so if you want, +you can count such references to the type object.) + +*** WARNING*** The Py_DECREF macro must have a side-effect-free argument +since it may evaluate its argument multiple times. (The alternative +would be to mace it a proper function or assign it to a global temporary +variable first, both of which are slower; and in a multi-threaded +environment the global variable trick is not safe.) +*/ + +/* First define a pile of simple helper macros, one set per special + * build symbol. These either expand to the obvious things, or to + * nothing at all when the special mode isn't in effect. The main + * macros can later be defined just once then, yet expand to different + * things depending on which special build options are and aren't in effect. + * Trust me <wink>: while painful, this is 20x easier to understand than, + * e.g, defining _Py_NewReference five different times in a maze of nested + * #ifdefs (we used to do that -- it was impenetrable). + */ +#ifdef Py_REF_DEBUG +PyAPI_DATA(Py_ssize_t) _Py_RefTotal; +PyAPI_FUNC(void) _Py_NegativeRefcount(const char *fname, + int lineno, PyObject *op); +PyAPI_FUNC(PyObject *) _PyDict_Dummy(void); +PyAPI_FUNC(PyObject *) _PySet_Dummy(void); +PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void); +#define _Py_INC_REFTOTAL _Py_RefTotal++ +#define _Py_DEC_REFTOTAL _Py_RefTotal-- +#define _Py_REF_DEBUG_COMMA , +#define _Py_CHECK_REFCNT(OP) \ +{ if ((OP)->ob_refcnt < 0) \ + _Py_NegativeRefcount(__FILE__, __LINE__, \ + (PyObject *)(OP)); \ +} +#else +#define _Py_INC_REFTOTAL +#define _Py_DEC_REFTOTAL +#define _Py_REF_DEBUG_COMMA +#define _Py_CHECK_REFCNT(OP) /* a semicolon */; +#endif /* Py_REF_DEBUG */ + +#ifdef COUNT_ALLOCS +PyAPI_FUNC(void) inc_count(PyTypeObject *); +PyAPI_FUNC(void) dec_count(PyTypeObject *); +#define _Py_INC_TPALLOCS(OP) inc_count((OP)->ob_type) +#define _Py_INC_TPFREES(OP) dec_count((OP)->ob_type) +#define _Py_DEC_TPFREES(OP) (OP)->ob_type->tp_frees-- +#define _Py_COUNT_ALLOCS_COMMA , +#else +#define _Py_INC_TPALLOCS(OP) +#define _Py_INC_TPFREES(OP) +#define _Py_DEC_TPFREES(OP) +#define _Py_COUNT_ALLOCS_COMMA +#endif /* COUNT_ALLOCS */ + +#ifdef Py_TRACE_REFS +/* Py_TRACE_REFS is such major surgery that we call external routines. */ +PyAPI_FUNC(void) _Py_NewReference(PyObject *); +PyAPI_FUNC(void) _Py_ForgetReference(PyObject *); +PyAPI_FUNC(void) _Py_Dealloc(PyObject *); +PyAPI_FUNC(void) _Py_PrintReferences(FILE *); +PyAPI_FUNC(void) _Py_PrintReferenceAddresses(FILE *); +PyAPI_FUNC(void) _Py_AddToAllObjects(PyObject *, int force); + +#else +/* Without Py_TRACE_REFS, there's little enough to do that we expand code + * inline. + */ +#define _Py_NewReference(op) ( \ + _Py_INC_TPALLOCS(op) _Py_COUNT_ALLOCS_COMMA \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + (op)->ob_refcnt = 1) + +#define _Py_ForgetReference(op) _Py_INC_TPFREES(op) + +#define _Py_Dealloc(op) ( \ + _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA \ + (*(op)->ob_type->tp_dealloc)((PyObject *)(op))) +#endif /* !Py_TRACE_REFS */ + +#define Py_INCREF(op) ( \ + _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA \ + (op)->ob_refcnt++) + +#define Py_DECREF(op) \ + if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA \ + --(op)->ob_refcnt != 0) \ + _Py_CHECK_REFCNT(op) \ + else \ + _Py_Dealloc((PyObject *)(op)) + +/* Safely decref `op` and set `op` to NULL, especially useful in tp_clear + * and tp_dealloc implementatons. + * + * Note that "the obvious" code can be deadly: + * + * Py_XDECREF(op); + * op = NULL; + * + * Typically, `op` is something like self->containee, and `self` is done + * using its `containee` member. In the code sequence above, suppose + * `containee` is non-NULL with a refcount of 1. Its refcount falls to + * 0 on the first line, which can trigger an arbitrary amount of code, + * possibly including finalizers (like __del__ methods or weakref callbacks) + * coded in Python, which in turn can release the GIL and allow other threads + * to run, etc. Such code may even invoke methods of `self` again, or cause + * cyclic gc to trigger, but-- oops! --self->containee still points to the + * object being torn down, and it may be in an insane state while being torn + * down. This has in fact been a rich historic source of miserable (rare & + * hard-to-diagnose) segfaulting (and other) bugs. + * + * The safe way is: + * + * Py_CLEAR(op); + * + * That arranges to set `op` to NULL _before_ decref'ing, so that any code + * triggered as a side-effect of `op` getting torn down no longer believes + * `op` points to a valid object. + * + * There are cases where it's safe to use the naive code, but they're brittle. + * For example, if `op` points to a Python integer, you know that destroying + * one of those can't cause problems -- but in part that relies on that + * Python integers aren't currently weakly referencable. Best practice is + * to use Py_CLEAR() even if you can't think of a reason for why you need to. + */ +#define Py_CLEAR(op) \ + do { \ + if (op) { \ + PyObject *tmp = (PyObject *)(op); \ + (op) = NULL; \ + Py_DECREF(tmp); \ + } \ + } while (0) + +/* Macros to use in case the object pointer may be NULL: */ +#define Py_XINCREF(op) if ((op) == NULL) ; else Py_INCREF(op) +#define Py_XDECREF(op) if ((op) == NULL) ; else Py_DECREF(op) + +/* +These are provided as conveniences to Python runtime embedders, so that +they can have object code that is not dependent on Python compilation flags. +*/ +PyAPI_FUNC(void) Py_IncRef(PyObject *); +PyAPI_FUNC(void) Py_DecRef(PyObject *); + +/* +_Py_NoneStruct is an object of undefined type which can be used in contexts +where NULL (nil) is not suitable (since NULL often means 'error'). + +Don't forget to apply Py_INCREF() when returning this value!!! +*/ +PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */ +#define Py_None (&_Py_NoneStruct) + +/* Macro for returning Py_None from a function */ +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None + +/* +Py_NotImplemented is a singleton used to signal that an operation is +not implemented for a given type combination. +*/ +PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */ +#define Py_NotImplemented (&_Py_NotImplementedStruct) + +/* Rich comparison opcodes */ +#define Py_LT 0 +#define Py_LE 1 +#define Py_EQ 2 +#define Py_NE 3 +#define Py_GT 4 +#define Py_GE 5 + +/* Maps Py_LT to Py_GT, ..., Py_GE to Py_LE. + * Defined in object.c. + */ +PyAPI_DATA(int) _Py_SwappedOp[]; + +/* +Define staticforward and statichere for source compatibility with old +C extensions. + +The staticforward define was needed to support certain broken C +compilers (notably SCO ODT 3.0, perhaps early AIX as well) botched the +static keyword when it was used with a forward declaration of a static +initialized structure. Standard C allows the forward declaration with +static, and we've decided to stop catering to broken C compilers. +(In fact, we expect that the compilers are all fixed eight years later.) +*/ + +#define staticforward static +#define statichere static + + +/* +More conventions +================ + +Argument Checking +----------------- + +Functions that take objects as arguments normally don't check for nil +arguments, but they do check the type of the argument, and return an +error if the function doesn't apply to the type. + +Failure Modes +------------- + +Functions may fail for a variety of reasons, including running out of +memory. This is communicated to the caller in two ways: an error string +is set (see errors.h), and the function result differs: functions that +normally return a pointer return NULL for failure, functions returning +an integer return -1 (which could be a legal return value too!), and +other functions return 0 for success and -1 for failure. +Callers should always check for errors before using the result. If +an error was set, the caller must either explicitly clear it, or pass +the error on to its caller. + +Reference Counts +---------------- + +It takes a while to get used to the proper usage of reference counts. + +Functions that create an object set the reference count to 1; such new +objects must be stored somewhere or destroyed again with Py_DECREF(). +Some functions that 'store' objects, such as PyTuple_SetItem() and +PyList_SetItem(), +don't increment the reference count of the object, since the most +frequent use is to store a fresh object. Functions that 'retrieve' +objects, such as PyTuple_GetItem() and PyDict_GetItemString(), also +don't increment +the reference count, since most frequently the object is only looked at +quickly. Thus, to retrieve an object and store it again, the caller +must call Py_INCREF() explicitly. + +NOTE: functions that 'consume' a reference count, like +PyList_SetItem(), consume the reference even if the object wasn't +successfully stored, to simplify error handling. + +It seems attractive to make other functions that take an object as +argument consume a reference count; however, this may quickly get +confusing (even the current practice is already confusing). Consider +it carefully, it may save lots of calls to Py_INCREF() and Py_DECREF() at +times. +*/ + + +/* Trashcan mechanism, thanks to Christian Tismer. + +When deallocating a container object, it's possible to trigger an unbounded +chain of deallocations, as each Py_DECREF in turn drops the refcount on "the +next" object in the chain to 0. This can easily lead to stack faults, and +especially in threads (which typically have less stack space to work with). + +A container object that participates in cyclic gc can avoid this by +bracketing the body of its tp_dealloc function with a pair of macros: + +static void +mytype_dealloc(mytype *p) +{ + ... declarations go here ... + + PyObject_GC_UnTrack(p); // must untrack first + Py_TRASHCAN_SAFE_BEGIN(p) + ... The body of the deallocator goes here, including all calls ... + ... to Py_DECREF on contained objects. ... + Py_TRASHCAN_SAFE_END(p) +} + +CAUTION: Never return from the middle of the body! If the body needs to +"get out early", put a label immediately before the Py_TRASHCAN_SAFE_END +call, and goto it. Else the call-depth counter (see below) will stay +above 0 forever, and the trashcan will never get emptied. + +How it works: The BEGIN macro increments a call-depth counter. So long +as this counter is small, the body of the deallocator is run directly without +further ado. But if the counter gets large, it instead adds p to a list of +objects to be deallocated later, skips the body of the deallocator, and +resumes execution after the END macro. The tp_dealloc routine then returns +without deallocating anything (and so unbounded call-stack depth is avoided). + +When the call stack finishes unwinding again, code generated by the END macro +notices this, and calls another routine to deallocate all the objects that +may have been added to the list of deferred deallocations. In effect, a +chain of N deallocations is broken into N / PyTrash_UNWIND_LEVEL pieces, +with the call stack never exceeding a depth of PyTrash_UNWIND_LEVEL. +*/ + +PyAPI_FUNC(void) _PyTrash_deposit_object(PyObject*); +PyAPI_FUNC(void) _PyTrash_destroy_chain(void); +PyAPI_DATA(int) _PyTrash_delete_nesting; +PyAPI_DATA(PyObject *) _PyTrash_delete_later; + +#define PyTrash_UNWIND_LEVEL 50 + +#define Py_TRASHCAN_SAFE_BEGIN(op) \ + if (_PyTrash_delete_nesting < PyTrash_UNWIND_LEVEL) { \ + ++_PyTrash_delete_nesting; + /* The body of the deallocator is here. */ +#define Py_TRASHCAN_SAFE_END(op) \ + --_PyTrash_delete_nesting; \ + if (_PyTrash_delete_later && _PyTrash_delete_nesting <= 0) \ + _PyTrash_destroy_chain(); \ + } \ + else \ + _PyTrash_deposit_object((PyObject*)op); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OBJECT_H */ diff --git a/sys/src/cmd/python/Include/objimpl.h b/sys/src/cmd/python/Include/objimpl.h new file mode 100644 index 000000000..03b6a8d49 --- /dev/null +++ b/sys/src/cmd/python/Include/objimpl.h @@ -0,0 +1,336 @@ +/* The PyObject_ memory family: high-level object memory interfaces. + See pymem.h for the low-level PyMem_ family. +*/ + +#ifndef Py_OBJIMPL_H +#define Py_OBJIMPL_H + +#include "pymem.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* BEWARE: + + Each interface exports both functions and macros. Extension modules should + use the functions, to ensure binary compatibility across Python versions. + Because the Python implementation is free to change internal details, and + the macros may (or may not) expose details for speed, if you do use the + macros you must recompile your extensions with each Python release. + + Never mix calls to PyObject_ memory functions with calls to the platform + malloc/realloc/ calloc/free, or with calls to PyMem_. +*/ + +/* +Functions and macros for modules that implement new object types. + + - PyObject_New(type, typeobj) allocates memory for a new object of the given + type, and initializes part of it. 'type' must be the C structure type used + to represent the object, and 'typeobj' the address of the corresponding + type object. Reference count and type pointer are filled in; the rest of + the bytes of the object are *undefined*! The resulting expression type is + 'type *'. The size of the object is determined by the tp_basicsize field + of the type object. + + - PyObject_NewVar(type, typeobj, n) is similar but allocates a variable-size + object with room for n items. In addition to the refcount and type pointer + fields, this also fills in the ob_size field. + + - PyObject_Del(op) releases the memory allocated for an object. It does not + run a destructor -- it only frees the memory. PyObject_Free is identical. + + - PyObject_Init(op, typeobj) and PyObject_InitVar(op, typeobj, n) don't + allocate memory. Instead of a 'type' parameter, they take a pointer to a + new object (allocated by an arbitrary allocator), and initialize its object + header fields. + +Note that objects created with PyObject_{New, NewVar} are allocated using the +specialized Python allocator (implemented in obmalloc.c), if WITH_PYMALLOC is +enabled. In addition, a special debugging allocator is used if PYMALLOC_DEBUG +is also #defined. + +In case a specific form of memory management is needed (for example, if you +must use the platform malloc heap(s), or shared memory, or C++ local storage or +operator new), you must first allocate the object with your custom allocator, +then pass its pointer to PyObject_{Init, InitVar} for filling in its Python- +specific fields: reference count, type pointer, possibly others. You should +be aware that Python no control over these objects because they don't +cooperate with the Python memory manager. Such objects may not be eligible +for automatic garbage collection and you have to make sure that they are +released accordingly whenever their destructor gets called (cf. the specific +form of memory management you're using). + +Unless you have specific memory management requirements, use +PyObject_{New, NewVar, Del}. +*/ + +/* + * Raw object memory interface + * =========================== + */ + +/* Functions to call the same malloc/realloc/free as used by Python's + object allocator. If WITH_PYMALLOC is enabled, these may differ from + the platform malloc/realloc/free. The Python object allocator is + designed for fast, cache-conscious allocation of many "small" objects, + and with low hidden memory overhead. + + PyObject_Malloc(0) returns a unique non-NULL pointer if possible. + + PyObject_Realloc(NULL, n) acts like PyObject_Malloc(n). + PyObject_Realloc(p != NULL, 0) does not return NULL, or free the memory + at p. + + Returned pointers must be checked for NULL explicitly; no action is + performed on failure other than to return NULL (no warning it printed, no + exception is set, etc). + + For allocating objects, use PyObject_{New, NewVar} instead whenever + possible. The PyObject_{Malloc, Realloc, Free} family is exposed + so that you can exploit Python's small-block allocator for non-object + uses. If you must use these routines to allocate object memory, make sure + the object gets initialized via PyObject_{Init, InitVar} after obtaining + the raw memory. +*/ +PyAPI_FUNC(void *) PyObject_Malloc(size_t); +PyAPI_FUNC(void *) PyObject_Realloc(void *, size_t); +PyAPI_FUNC(void) PyObject_Free(void *); + + +/* Macros */ +#ifdef WITH_PYMALLOC +#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */ +PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes); +PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes); +PyAPI_FUNC(void) _PyObject_DebugFree(void *p); +PyAPI_FUNC(void) _PyObject_DebugDumpAddress(const void *p); +PyAPI_FUNC(void) _PyObject_DebugCheckAddress(const void *p); +PyAPI_FUNC(void) _PyObject_DebugMallocStats(void); +#define PyObject_MALLOC _PyObject_DebugMalloc +#define PyObject_Malloc _PyObject_DebugMalloc +#define PyObject_REALLOC _PyObject_DebugRealloc +#define PyObject_Realloc _PyObject_DebugRealloc +#define PyObject_FREE _PyObject_DebugFree +#define PyObject_Free _PyObject_DebugFree + +#else /* WITH_PYMALLOC && ! PYMALLOC_DEBUG */ +#define PyObject_MALLOC PyObject_Malloc +#define PyObject_REALLOC PyObject_Realloc +#define PyObject_FREE PyObject_Free +#endif + +#else /* ! WITH_PYMALLOC */ +#define PyObject_MALLOC PyMem_MALLOC +#define PyObject_REALLOC PyMem_REALLOC +#define PyObject_FREE PyMem_FREE + +#endif /* WITH_PYMALLOC */ + +#define PyObject_Del PyObject_Free +#define PyObject_DEL PyObject_FREE + +/* for source compatibility with 2.2 */ +#define _PyObject_Del PyObject_Free + +/* + * Generic object allocator interface + * ================================== + */ + +/* Functions */ +PyAPI_FUNC(PyObject *) PyObject_Init(PyObject *, PyTypeObject *); +PyAPI_FUNC(PyVarObject *) PyObject_InitVar(PyVarObject *, + PyTypeObject *, Py_ssize_t); +PyAPI_FUNC(PyObject *) _PyObject_New(PyTypeObject *); +PyAPI_FUNC(PyVarObject *) _PyObject_NewVar(PyTypeObject *, Py_ssize_t); + +#define PyObject_New(type, typeobj) \ + ( (type *) _PyObject_New(typeobj) ) +#define PyObject_NewVar(type, typeobj, n) \ + ( (type *) _PyObject_NewVar((typeobj), (n)) ) + +/* Macros trading binary compatibility for speed. See also pymem.h. + Note that these macros expect non-NULL object pointers.*/ +#define PyObject_INIT(op, typeobj) \ + ( (op)->ob_type = (typeobj), _Py_NewReference((PyObject *)(op)), (op) ) +#define PyObject_INIT_VAR(op, typeobj, size) \ + ( (op)->ob_size = (size), PyObject_INIT((op), (typeobj)) ) + +#define _PyObject_SIZE(typeobj) ( (typeobj)->tp_basicsize ) + +/* _PyObject_VAR_SIZE returns the number of bytes (as size_t) allocated for a + vrbl-size object with nitems items, exclusive of gc overhead (if any). The + value is rounded up to the closest multiple of sizeof(void *), in order to + ensure that pointer fields at the end of the object are correctly aligned + for the platform (this is of special importance for subclasses of, e.g., + str or long, so that pointers can be stored after the embedded data). + + Note that there's no memory wastage in doing this, as malloc has to + return (at worst) pointer-aligned memory anyway. +*/ +#if ((SIZEOF_VOID_P - 1) & SIZEOF_VOID_P) != 0 +# error "_PyObject_VAR_SIZE requires SIZEOF_VOID_P be a power of 2" +#endif + +#define _PyObject_VAR_SIZE(typeobj, nitems) \ + (size_t) \ + ( ( (typeobj)->tp_basicsize + \ + (nitems)*(typeobj)->tp_itemsize + \ + (SIZEOF_VOID_P - 1) \ + ) & ~(SIZEOF_VOID_P - 1) \ + ) + +#define PyObject_NEW(type, typeobj) \ +( (type *) PyObject_Init( \ + (PyObject *) PyObject_MALLOC( _PyObject_SIZE(typeobj) ), (typeobj)) ) + +#define PyObject_NEW_VAR(type, typeobj, n) \ +( (type *) PyObject_InitVar( \ + (PyVarObject *) PyObject_MALLOC(_PyObject_VAR_SIZE((typeobj),(n)) ),\ + (typeobj), (n)) ) + +/* This example code implements an object constructor with a custom + allocator, where PyObject_New is inlined, and shows the important + distinction between two steps (at least): + 1) the actual allocation of the object storage; + 2) the initialization of the Python specific fields + in this storage with PyObject_{Init, InitVar}. + + PyObject * + YourObject_New(...) + { + PyObject *op; + + op = (PyObject *) Your_Allocator(_PyObject_SIZE(YourTypeStruct)); + if (op == NULL) + return PyErr_NoMemory(); + + PyObject_Init(op, &YourTypeStruct); + + op->ob_field = value; + ... + return op; + } + + Note that in C++, the use of the new operator usually implies that + the 1st step is performed automatically for you, so in a C++ class + constructor you would start directly with PyObject_Init/InitVar +*/ + +/* + * Garbage Collection Support + * ========================== + */ + +/* C equivalent of gc.collect(). */ +PyAPI_FUNC(Py_ssize_t) PyGC_Collect(void); + +/* Test if a type has a GC head */ +#define PyType_IS_GC(t) PyType_HasFeature((t), Py_TPFLAGS_HAVE_GC) + +/* Test if an object has a GC head */ +#define PyObject_IS_GC(o) (PyType_IS_GC((o)->ob_type) && \ + ((o)->ob_type->tp_is_gc == NULL || (o)->ob_type->tp_is_gc(o))) + +PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t); +#define PyObject_GC_Resize(type, op, n) \ + ( (type *) _PyObject_GC_Resize((PyVarObject *)(op), (n)) ) + +/* for source compatibility with 2.2 */ +#define _PyObject_GC_Del PyObject_GC_Del + +/* GC information is stored BEFORE the object structure. */ +typedef union _gc_head { + struct { + union _gc_head *gc_next; + union _gc_head *gc_prev; + Py_ssize_t gc_refs; + } gc; + long double dummy; /* force worst-case alignment */ +} PyGC_Head; + +extern PyGC_Head *_PyGC_generation0; + +#define _Py_AS_GC(o) ((PyGC_Head *)(o)-1) + +#define _PyGC_REFS_UNTRACKED (-2) +#define _PyGC_REFS_REACHABLE (-3) +#define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4) + +/* Tell the GC to track this object. NB: While the object is tracked the + * collector it must be safe to call the ob_traverse method. */ +#define _PyObject_GC_TRACK(o) do { \ + PyGC_Head *g = _Py_AS_GC(o); \ + if (g->gc.gc_refs != _PyGC_REFS_UNTRACKED) \ + Py_FatalError("GC object already tracked"); \ + g->gc.gc_refs = _PyGC_REFS_REACHABLE; \ + g->gc.gc_next = _PyGC_generation0; \ + g->gc.gc_prev = _PyGC_generation0->gc.gc_prev; \ + g->gc.gc_prev->gc.gc_next = g; \ + _PyGC_generation0->gc.gc_prev = g; \ + } while (0); + +/* Tell the GC to stop tracking this object. + * gc_next doesn't need to be set to NULL, but doing so is a good + * way to provoke memory errors if calling code is confused. + */ +#define _PyObject_GC_UNTRACK(o) do { \ + PyGC_Head *g = _Py_AS_GC(o); \ + assert(g->gc.gc_refs != _PyGC_REFS_UNTRACKED); \ + g->gc.gc_refs = _PyGC_REFS_UNTRACKED; \ + g->gc.gc_prev->gc.gc_next = g->gc.gc_next; \ + g->gc.gc_next->gc.gc_prev = g->gc.gc_prev; \ + g->gc.gc_next = NULL; \ + } while (0); + +PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t); +PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *); +PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t); +PyAPI_FUNC(void) PyObject_GC_Track(void *); +PyAPI_FUNC(void) PyObject_GC_UnTrack(void *); +PyAPI_FUNC(void) PyObject_GC_Del(void *); + +#define PyObject_GC_New(type, typeobj) \ + ( (type *) _PyObject_GC_New(typeobj) ) +#define PyObject_GC_NewVar(type, typeobj, n) \ + ( (type *) _PyObject_GC_NewVar((typeobj), (n)) ) + + +/* Utility macro to help write tp_traverse functions. + * To use this macro, the tp_traverse function must name its arguments + * "visit" and "arg". This is intended to keep tp_traverse functions + * looking as much alike as possible. + */ +#define Py_VISIT(op) \ + do { \ + if (op) { \ + int vret = visit((PyObject *)(op), arg); \ + if (vret) \ + return vret; \ + } \ + } while (0) + +/* This is here for the sake of backwards compatibility. Extensions that + * use the old GC API will still compile but the objects will not be + * tracked by the GC. */ +#define PyGC_HEAD_SIZE 0 +#define PyObject_GC_Init(op) +#define PyObject_GC_Fini(op) +#define PyObject_AS_GC(op) (op) +#define PyObject_FROM_GC(op) (op) + + +/* Test if a type supports weak references */ +#define PyType_SUPPORTS_WEAKREFS(t) \ + (PyType_HasFeature((t), Py_TPFLAGS_HAVE_WEAKREFS) \ + && ((t)->tp_weaklistoffset > 0)) + +#define PyObject_GET_WEAKREFS_LISTPTR(o) \ + ((PyObject **) (((char *) (o)) + (o)->ob_type->tp_weaklistoffset)) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OBJIMPL_H */ diff --git a/sys/src/cmd/python/Include/opcode.h b/sys/src/cmd/python/Include/opcode.h new file mode 100644 index 000000000..d8cb2cd48 --- /dev/null +++ b/sys/src/cmd/python/Include/opcode.h @@ -0,0 +1,152 @@ +#ifndef Py_OPCODE_H +#define Py_OPCODE_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Instruction opcodes for compiled code */ + +#define STOP_CODE 0 +#define POP_TOP 1 +#define ROT_TWO 2 +#define ROT_THREE 3 +#define DUP_TOP 4 +#define ROT_FOUR 5 +#define NOP 9 + +#define UNARY_POSITIVE 10 +#define UNARY_NEGATIVE 11 +#define UNARY_NOT 12 +#define UNARY_CONVERT 13 + +#define UNARY_INVERT 15 + +#define LIST_APPEND 18 +#define BINARY_POWER 19 + +#define BINARY_MULTIPLY 20 +#define BINARY_DIVIDE 21 +#define BINARY_MODULO 22 +#define BINARY_ADD 23 +#define BINARY_SUBTRACT 24 +#define BINARY_SUBSCR 25 +#define BINARY_FLOOR_DIVIDE 26 +#define BINARY_TRUE_DIVIDE 27 +#define INPLACE_FLOOR_DIVIDE 28 +#define INPLACE_TRUE_DIVIDE 29 + +#define SLICE 30 +/* Also uses 31-33 */ + +#define STORE_SLICE 40 +/* Also uses 41-43 */ + +#define DELETE_SLICE 50 +/* Also uses 51-53 */ + +#define INPLACE_ADD 55 +#define INPLACE_SUBTRACT 56 +#define INPLACE_MULTIPLY 57 +#define INPLACE_DIVIDE 58 +#define INPLACE_MODULO 59 +#define STORE_SUBSCR 60 +#define DELETE_SUBSCR 61 + +#define BINARY_LSHIFT 62 +#define BINARY_RSHIFT 63 +#define BINARY_AND 64 +#define BINARY_XOR 65 +#define BINARY_OR 66 +#define INPLACE_POWER 67 +#define GET_ITER 68 + +#define PRINT_EXPR 70 +#define PRINT_ITEM 71 +#define PRINT_NEWLINE 72 +#define PRINT_ITEM_TO 73 +#define PRINT_NEWLINE_TO 74 +#define INPLACE_LSHIFT 75 +#define INPLACE_RSHIFT 76 +#define INPLACE_AND 77 +#define INPLACE_XOR 78 +#define INPLACE_OR 79 +#define BREAK_LOOP 80 +#define WITH_CLEANUP 81 +#define LOAD_LOCALS 82 +#define RETURN_VALUE 83 +#define IMPORT_STAR 84 +#define EXEC_STMT 85 +#define YIELD_VALUE 86 +#define POP_BLOCK 87 +#define END_FINALLY 88 +#define BUILD_CLASS 89 + +#define HAVE_ARGUMENT 90 /* Opcodes from here have an argument: */ + +#define STORE_NAME 90 /* Index in name list */ +#define DELETE_NAME 91 /* "" */ +#define UNPACK_SEQUENCE 92 /* Number of sequence items */ +#define FOR_ITER 93 + +#define STORE_ATTR 95 /* Index in name list */ +#define DELETE_ATTR 96 /* "" */ +#define STORE_GLOBAL 97 /* "" */ +#define DELETE_GLOBAL 98 /* "" */ +#define DUP_TOPX 99 /* number of items to duplicate */ +#define LOAD_CONST 100 /* Index in const list */ +#define LOAD_NAME 101 /* Index in name list */ +#define BUILD_TUPLE 102 /* Number of tuple items */ +#define BUILD_LIST 103 /* Number of list items */ +#define BUILD_MAP 104 /* Always zero for now */ +#define LOAD_ATTR 105 /* Index in name list */ +#define COMPARE_OP 106 /* Comparison operator */ +#define IMPORT_NAME 107 /* Index in name list */ +#define IMPORT_FROM 108 /* Index in name list */ + +#define JUMP_FORWARD 110 /* Number of bytes to skip */ +#define JUMP_IF_FALSE 111 /* "" */ +#define JUMP_IF_TRUE 112 /* "" */ +#define JUMP_ABSOLUTE 113 /* Target byte offset from beginning of code */ + +#define LOAD_GLOBAL 116 /* Index in name list */ + +#define CONTINUE_LOOP 119 /* Start of loop (absolute) */ +#define SETUP_LOOP 120 /* Target address (absolute) */ +#define SETUP_EXCEPT 121 /* "" */ +#define SETUP_FINALLY 122 /* "" */ + +#define LOAD_FAST 124 /* Local variable number */ +#define STORE_FAST 125 /* Local variable number */ +#define DELETE_FAST 126 /* Local variable number */ + +#define RAISE_VARARGS 130 /* Number of raise arguments (1, 2 or 3) */ +/* CALL_FUNCTION_XXX opcodes defined below depend on this definition */ +#define CALL_FUNCTION 131 /* #args + (#kwargs<<8) */ +#define MAKE_FUNCTION 132 /* #defaults */ +#define BUILD_SLICE 133 /* Number of items */ + +#define MAKE_CLOSURE 134 /* #free vars */ +#define LOAD_CLOSURE 135 /* Load free variable from closure */ +#define LOAD_DEREF 136 /* Load and dereference from closure cell */ +#define STORE_DEREF 137 /* Store into cell */ + +/* The next 3 opcodes must be contiguous and satisfy + (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1 */ +#define CALL_FUNCTION_VAR 140 /* #args + (#kwargs<<8) */ +#define CALL_FUNCTION_KW 141 /* #args + (#kwargs<<8) */ +#define CALL_FUNCTION_VAR_KW 142 /* #args + (#kwargs<<8) */ + +/* Support for opargs more than 16 bits long */ +#define EXTENDED_ARG 143 + + +enum cmp_op {PyCmp_LT=Py_LT, PyCmp_LE=Py_LE, PyCmp_EQ=Py_EQ, PyCmp_NE=Py_NE, PyCmp_GT=Py_GT, PyCmp_GE=Py_GE, + PyCmp_IN, PyCmp_NOT_IN, PyCmp_IS, PyCmp_IS_NOT, PyCmp_EXC_MATCH, PyCmp_BAD}; + +#define HAS_ARG(op) ((op) >= HAVE_ARGUMENT) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OPCODE_H */ diff --git a/sys/src/cmd/python/Include/osdefs.h b/sys/src/cmd/python/Include/osdefs.h new file mode 100644 index 000000000..693765932 --- /dev/null +++ b/sys/src/cmd/python/Include/osdefs.h @@ -0,0 +1,55 @@ +#ifndef Py_OSDEFS_H +#define Py_OSDEFS_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Operating system dependencies */ + +/* Mod by chrish: QNX has WATCOM, but isn't DOS */ +#if !defined(__QNX__) +#if defined(MS_WINDOWS) || defined(__BORLANDC__) || defined(__WATCOMC__) || defined(__DJGPP__) || defined(PYOS_OS2) +#if defined(PYOS_OS2) && defined(PYCC_GCC) +#define MAXPATHLEN 260 +#define SEP '/' +#define ALTSEP '\\' +#else +#define SEP '\\' +#define ALTSEP '/' +#define MAXPATHLEN 256 +#endif +#define DELIM ';' +#endif +#endif + +#ifdef RISCOS +#define SEP '.' +#define MAXPATHLEN 256 +#define DELIM ',' +#endif + + +/* Filename separator */ +#ifndef SEP +#define SEP '/' +#endif + +/* Max pathname length */ +#ifndef MAXPATHLEN +#if defined(PATH_MAX) && PATH_MAX > 1024 +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 1024 +#endif +#endif + +/* Search path entry delimiter */ +#ifndef DELIM +#define DELIM ':' +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_OSDEFS_H */ diff --git a/sys/src/cmd/python/Include/parsetok.h b/sys/src/cmd/python/Include/parsetok.h new file mode 100644 index 000000000..0f87e81f0 --- /dev/null +++ b/sys/src/cmd/python/Include/parsetok.h @@ -0,0 +1,50 @@ + +/* Parser-tokenizer link interface */ + +#ifndef Py_PARSETOK_H +#define Py_PARSETOK_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + int error; + const char *filename; + int lineno; + int offset; + char *text; + int token; + int expected; +} perrdetail; + +#if 0 +#define PyPARSE_YIELD_IS_KEYWORD 0x0001 +#endif + +#define PyPARSE_DONT_IMPLY_DEDENT 0x0002 + +#define PyPARSE_WITH_IS_KEYWORD 0x0003 + +PyAPI_FUNC(node *) PyParser_ParseString(const char *, grammar *, int, + perrdetail *); +PyAPI_FUNC(node *) PyParser_ParseFile (FILE *, const char *, grammar *, int, + char *, char *, perrdetail *); + +PyAPI_FUNC(node *) PyParser_ParseStringFlags(const char *, grammar *, int, + perrdetail *, int); +PyAPI_FUNC(node *) PyParser_ParseFileFlags(FILE *, const char *, grammar *, + int, char *, char *, + perrdetail *, int); + +PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilename(const char *, + const char *, + grammar *, int, + perrdetail *, int); + +/* Note that he following function is defined in pythonrun.c not parsetok.c. */ +PyAPI_FUNC(void) PyParser_SetError(perrdetail *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PARSETOK_H */ diff --git a/sys/src/cmd/python/Include/patchlevel.h b/sys/src/cmd/python/Include/patchlevel.h new file mode 100644 index 000000000..85efe3b2f --- /dev/null +++ b/sys/src/cmd/python/Include/patchlevel.h @@ -0,0 +1,40 @@ + +/* Newfangled version identification scheme. + + This scheme was added in Python 1.5.2b2; before that time, only PATCHLEVEL + was available. To test for presence of the scheme, test for + defined(PY_MAJOR_VERSION). + + When the major or minor version changes, the VERSION variable in + configure.in must also be changed. + + There is also (independent) API version information in modsupport.h. +*/ + +/* Values for PY_RELEASE_LEVEL */ +#define PY_RELEASE_LEVEL_ALPHA 0xA +#define PY_RELEASE_LEVEL_BETA 0xB +#define PY_RELEASE_LEVEL_GAMMA 0xC /* For release candidates */ +#define PY_RELEASE_LEVEL_FINAL 0xF /* Serial should be 0 here */ + /* Higher for patch releases */ + +/* Version parsed out into numeric values */ +#define PY_MAJOR_VERSION 2 +#define PY_MINOR_VERSION 5 +#define PY_MICRO_VERSION 1 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_FINAL +#define PY_RELEASE_SERIAL 0 + +/* Version as a string */ +#define PY_VERSION "2.5.1" + +/* Subversion Revision number of this file (not of the repository) */ +#define PY_PATCHLEVEL_REVISION "$Revision: 54863 $" + +/* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. + Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ +#define PY_VERSION_HEX ((PY_MAJOR_VERSION << 24) | \ + (PY_MINOR_VERSION << 16) | \ + (PY_MICRO_VERSION << 8) | \ + (PY_RELEASE_LEVEL << 4) | \ + (PY_RELEASE_SERIAL << 0)) diff --git a/sys/src/cmd/python/Include/pgen.h b/sys/src/cmd/python/Include/pgen.h new file mode 100644 index 000000000..8a325ed07 --- /dev/null +++ b/sys/src/cmd/python/Include/pgen.h @@ -0,0 +1,18 @@ +#ifndef Py_PGEN_H +#define Py_PGEN_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Parser generator interface */ + +extern grammar *meta_grammar(void); + +struct _node; +extern grammar *pgen(struct _node *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PGEN_H */ diff --git a/sys/src/cmd/python/Include/pgenheaders.h b/sys/src/cmd/python/Include/pgenheaders.h new file mode 100644 index 000000000..2049ae32b --- /dev/null +++ b/sys/src/cmd/python/Include/pgenheaders.h @@ -0,0 +1,42 @@ +#ifndef Py_PGENHEADERS_H +#define Py_PGENHEADERS_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Include files and extern declarations used by most of the parser. */ + +#include "Python.h" + +PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); +PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); + +#define addarc _Py_addarc +#define addbit _Py_addbit +#define adddfa _Py_adddfa +#define addfirstsets _Py_addfirstsets +#define addlabel _Py_addlabel +#define addstate _Py_addstate +#define delbitset _Py_delbitset +#define dumptree _Py_dumptree +#define findlabel _Py_findlabel +#define mergebitset _Py_mergebitset +#define meta_grammar _Py_meta_grammar +#define newbitset _Py_newbitset +#define newgrammar _Py_newgrammar +#define pgen _Py_pgen +#define printgrammar _Py_printgrammar +#define printnonterminals _Py_printnonterminals +#define printtree _Py_printtree +#define samebitset _Py_samebitset +#define showtree _Py_showtree +#define tok_dump _Py_tok_dump +#define translatelabels _Py_translatelabels + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PGENHEADERS_H */ diff --git a/sys/src/cmd/python/Include/py_curses.h b/sys/src/cmd/python/Include/py_curses.h new file mode 100644 index 000000000..aaff4bd83 --- /dev/null +++ b/sys/src/cmd/python/Include/py_curses.h @@ -0,0 +1,176 @@ + +#ifndef Py_CURSES_H +#define Py_CURSES_H + +#ifdef __APPLE__ +/* +** On Mac OS X 10.2 [n]curses.h and stdlib.h use different guards +** against multiple definition of wchar_t. +*/ +#ifdef _BSD_WCHAR_T_DEFINED_ +#define _WCHAR_T +#endif +#endif + +#ifdef __FreeBSD__ +/* +** On FreeBSD, [n]curses.h and stdlib.h/wchar.h use different guards +** against multiple definition of wchar_t and wint_t. +*/ +#ifdef _XOPEN_SOURCE_EXTENDED +#ifndef __FreeBSD_version +#include <osreldate.h> +#endif +#if __FreeBSD_version >= 500000 +#ifndef __wchar_t +#define __wchar_t +#endif +#ifndef __wint_t +#define __wint_t +#endif +#else +#ifndef _WCHAR_T +#define _WCHAR_T +#endif +#ifndef _WINT_T +#define _WINT_T +#endif +#endif +#endif +#endif + +#ifdef HAVE_NCURSES_H +#include <ncurses.h> +#else +#include <curses.h> +#ifdef HAVE_TERM_H +/* for tigetstr, which is not declared in SysV curses */ +#include <term.h> +#endif +#endif + +#ifdef HAVE_NCURSES_H +/* configure was checking <curses.h>, but we will + use <ncurses.h>, which has all these features. */ +#ifndef WINDOW_HAS_FLAGS +#define WINDOW_HAS_FLAGS 1 +#endif +#ifndef MVWDELCH_IS_EXPRESSION +#define MVWDELCH_IS_EXPRESSION 1 +#endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define PyCurses_API_pointers 4 + +/* Type declarations */ + +typedef struct { + PyObject_HEAD + WINDOW *win; +} PyCursesWindowObject; + +#define PyCursesWindow_Check(v) ((v)->ob_type == &PyCursesWindow_Type) + +#ifdef CURSES_MODULE +/* This section is used when compiling _cursesmodule.c */ + +#else +/* This section is used in modules that use the _cursesmodule API */ + +static void **PyCurses_API; + +#define PyCursesWindow_Type (*(PyTypeObject *) PyCurses_API[0]) +#define PyCursesSetupTermCalled {if (! ((int (*)(void))PyCurses_API[1]) () ) return NULL;} +#define PyCursesInitialised {if (! ((int (*)(void))PyCurses_API[2]) () ) return NULL;} +#define PyCursesInitialisedColor {if (! ((int (*)(void))PyCurses_API[3]) () ) return NULL;} + +#define import_curses() \ +{ \ + PyObject *module = PyImport_ImportModule("_curses"); \ + if (module != NULL) { \ + PyObject *module_dict = PyModule_GetDict(module); \ + PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \ + if (PyCObject_Check(c_api_object)) { \ + PyCurses_API = (void **)PyCObject_AsVoidPtr(c_api_object); \ + } \ + } \ +} +#endif + +/* general error messages */ +static char *catchall_ERR = "curses function returned ERR"; +static char *catchall_NULL = "curses function returned NULL"; + +/* Function Prototype Macros - They are ugly but very, very useful. ;-) + + X - function name + TYPE - parameter Type + ERGSTR - format string for construction of the return value + PARSESTR - format string for argument parsing + */ + +#define NoArgNoReturnFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + return PyCursesCheckERR(X(), # X); } + +#define NoArgOrFlagNoReturnFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self, PyObject *args) \ +{ \ + int flag = 0; \ + PyCursesInitialised \ + switch(PyTuple_Size(args)) { \ + case 0: \ + return PyCursesCheckERR(X(), # X); \ + case 1: \ + if (!PyArg_ParseTuple(args, "i;True(1) or False(0)", &flag)) return NULL; \ + if (flag) return PyCursesCheckERR(X(), # X); \ + else return PyCursesCheckERR(no ## X (), # X); \ + default: \ + PyErr_SetString(PyExc_TypeError, # X " requires 0 or 1 arguments"); \ + return NULL; } } + +#define NoArgReturnIntFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + return PyInt_FromLong((long) X()); } + + +#define NoArgReturnStringFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + return PyString_FromString(X()); } + +#define NoArgTrueFalseFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + if (X () == FALSE) { \ + Py_INCREF(Py_False); \ + return Py_False; \ + } \ + Py_INCREF(Py_True); \ + return Py_True; } + +#define NoArgNoReturnVoidFunction(X) \ +static PyObject *PyCurses_ ## X (PyObject *self) \ +{ \ + PyCursesInitialised \ + X(); \ + Py_INCREF(Py_None); \ + return Py_None; } + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(Py_CURSES_H) */ + + diff --git a/sys/src/cmd/python/Include/pyarena.h b/sys/src/cmd/python/Include/pyarena.h new file mode 100644 index 000000000..5f193fece --- /dev/null +++ b/sys/src/cmd/python/Include/pyarena.h @@ -0,0 +1,62 @@ +/* An arena-like memory interface for the compiler. + */ + +#ifndef Py_PYARENA_H +#define Py_PYARENA_H + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct _arena PyArena; + + /* PyArena_New() and PyArena_Free() create a new arena and free it, + respectively. Once an arena has been created, it can be used + to allocate memory via PyArena_Malloc(). Pointers to PyObject can + also be registered with the arena via PyArena_AddPyObject(), and the + arena will ensure that the PyObjects stay alive at least until + PyArena_Free() is called. When an arena is freed, all the memory it + allocated is freed, the arena releases internal references to registered + PyObject*, and none of its pointers are valid. + XXX (tim) What does "none of its pointers are valid" mean? Does it + XXX mean that pointers previously obtained via PyArena_Malloc() are + XXX no longer valid? (That's clearly true, but not sure that's what + XXX the text is trying to say.) + + PyArena_New() returns an arena pointer. On error, it + returns a negative number and sets an exception. + XXX (tim): Not true. On error, PyArena_New() actually returns NULL, + XXX and looks like it may or may not set an exception (e.g., if the + XXX internal PyList_New(0) returns NULL, PyArena_New() passes that on + XXX and an exception is set; OTOH, if the internal + XXX block_new(DEFAULT_BLOCK_SIZE) returns NULL, that's passed on but + XXX an exception is not set in that case). + */ + PyAPI_FUNC(PyArena *) PyArena_New(void); + PyAPI_FUNC(void) PyArena_Free(PyArena *); + + /* Mostly like malloc(), return the address of a block of memory spanning + * `size` bytes, or return NULL (without setting an exception) if enough + * new memory can't be obtained. Unlike malloc(0), PyArena_Malloc() with + * size=0 does not guarantee to return a unique pointer (the pointer + * returned may equal one or more other pointers obtained from + * PyArena_Malloc()). + * Note that pointers obtained via PyArena_Malloc() must never be passed to + * the system free() or realloc(), or to any of Python's similar memory- + * management functions. PyArena_Malloc()-obtained pointers remain valid + * until PyArena_Free(ar) is called, at which point all pointers obtained + * from the arena `ar` become invalid simultaneously. + */ + PyAPI_FUNC(void *) PyArena_Malloc(PyArena *, size_t size); + + /* This routine isn't a proper arena allocation routine. It takes + * a PyObject* and records it so that it can be DECREFed when the + * arena is freed. + */ + PyAPI_FUNC(int) PyArena_AddPyObject(PyArena *, PyObject *); + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_PYARENA_H */ diff --git a/sys/src/cmd/python/Include/pydebug.h b/sys/src/cmd/python/Include/pydebug.h new file mode 100644 index 000000000..f49a98e4c --- /dev/null +++ b/sys/src/cmd/python/Include/pydebug.h @@ -0,0 +1,34 @@ + +#ifndef Py_PYDEBUG_H +#define Py_PYDEBUG_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(int) Py_DebugFlag; +PyAPI_DATA(int) Py_VerboseFlag; +PyAPI_DATA(int) Py_InteractiveFlag; +PyAPI_DATA(int) Py_OptimizeFlag; +PyAPI_DATA(int) Py_NoSiteFlag; +PyAPI_DATA(int) Py_UseClassExceptionsFlag; +PyAPI_DATA(int) Py_FrozenFlag; +PyAPI_DATA(int) Py_TabcheckFlag; +PyAPI_DATA(int) Py_UnicodeFlag; +PyAPI_DATA(int) Py_IgnoreEnvironmentFlag; +PyAPI_DATA(int) Py_DivisionWarningFlag; +/* _XXX Py_QnewFlag should go away in 3.0. It's true iff -Qnew is passed, + on the command line, and is used in 2.2 by ceval.c to make all "/" divisions + true divisions (which they will be in 3.0). */ +PyAPI_DATA(int) _Py_QnewFlag; + +/* this is a wrapper around getenv() that pays attention to + Py_IgnoreEnvironmentFlag. It should be used for getting variables like + PYTHONPATH and PYTHONHOME from the environment */ +#define Py_GETENV(s) (Py_IgnoreEnvironmentFlag ? NULL : getenv(s)) + +PyAPI_FUNC(void) Py_FatalError(const char *message); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYDEBUG_H */ diff --git a/sys/src/cmd/python/Include/pyerrors.h b/sys/src/cmd/python/Include/pyerrors.h new file mode 100644 index 000000000..9532e32b4 --- /dev/null +++ b/sys/src/cmd/python/Include/pyerrors.h @@ -0,0 +1,334 @@ +#ifndef Py_ERRORS_H +#define Py_ERRORS_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Error objects */ + +typedef struct { + PyObject_HEAD + PyObject *dict; + PyObject *args; + PyObject *message; +} PyBaseExceptionObject; + +typedef struct { + PyObject_HEAD + PyObject *dict; + PyObject *args; + PyObject *message; + PyObject *msg; + PyObject *filename; + PyObject *lineno; + PyObject *offset; + PyObject *text; + PyObject *print_file_and_line; +} PySyntaxErrorObject; + +#ifdef Py_USING_UNICODE +typedef struct { + PyObject_HEAD + PyObject *dict; + PyObject *args; + PyObject *message; + PyObject *encoding; + PyObject *object; + PyObject *start; + PyObject *end; + PyObject *reason; +} PyUnicodeErrorObject; +#endif + +typedef struct { + PyObject_HEAD + PyObject *dict; + PyObject *args; + PyObject *message; + PyObject *code; +} PySystemExitObject; + +typedef struct { + PyObject_HEAD + PyObject *dict; + PyObject *args; + PyObject *message; + PyObject *myerrno; + PyObject *strerror; + PyObject *filename; +} PyEnvironmentErrorObject; + +#ifdef MS_WINDOWS +typedef struct { + PyObject_HEAD + PyObject *dict; + PyObject *args; + PyObject *message; + PyObject *myerrno; + PyObject *strerror; + PyObject *filename; + PyObject *winerror; +} PyWindowsErrorObject; +#endif + +/* Error handling definitions */ + +PyAPI_FUNC(void) PyErr_SetNone(PyObject *); +PyAPI_FUNC(void) PyErr_SetObject(PyObject *, PyObject *); +PyAPI_FUNC(void) PyErr_SetString(PyObject *, const char *); +PyAPI_FUNC(PyObject *) PyErr_Occurred(void); +PyAPI_FUNC(void) PyErr_Clear(void); +PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); +PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); + +#ifdef Py_DEBUG +#define _PyErr_OCCURRED() PyErr_Occurred() +#else +#define _PyErr_OCCURRED() (_PyThreadState_Current->curexc_type) +#endif + +/* Error testing and normalization */ +PyAPI_FUNC(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *); +PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *); +PyAPI_FUNC(void) PyErr_NormalizeException(PyObject**, PyObject**, PyObject**); + +/* */ + +#define PyExceptionClass_Check(x) \ + (PyClass_Check((x)) \ + || (PyType_Check((x)) && PyType_IsSubtype( \ + (PyTypeObject*)(x), (PyTypeObject*)PyExc_BaseException))) + + +#define PyExceptionInstance_Check(x) \ + (PyInstance_Check((x)) || \ + (PyType_IsSubtype((x)->ob_type, (PyTypeObject*)PyExc_BaseException))) + +#define PyExceptionClass_Name(x) \ + (PyClass_Check((x)) \ + ? PyString_AS_STRING(((PyClassObject*)(x))->cl_name) \ + : (char *)(((PyTypeObject*)(x))->tp_name)) + +#define PyExceptionInstance_Class(x) \ + ((PyInstance_Check((x)) \ + ? (PyObject*)((PyInstanceObject*)(x))->in_class \ + : (PyObject*)((x)->ob_type))) + + +/* Predefined exceptions */ + +PyAPI_DATA(PyObject *) PyExc_BaseException; +PyAPI_DATA(PyObject *) PyExc_Exception; +PyAPI_DATA(PyObject *) PyExc_StopIteration; +PyAPI_DATA(PyObject *) PyExc_GeneratorExit; +PyAPI_DATA(PyObject *) PyExc_StandardError; +PyAPI_DATA(PyObject *) PyExc_ArithmeticError; +PyAPI_DATA(PyObject *) PyExc_LookupError; + +PyAPI_DATA(PyObject *) PyExc_AssertionError; +PyAPI_DATA(PyObject *) PyExc_AttributeError; +PyAPI_DATA(PyObject *) PyExc_EOFError; +PyAPI_DATA(PyObject *) PyExc_FloatingPointError; +PyAPI_DATA(PyObject *) PyExc_EnvironmentError; +PyAPI_DATA(PyObject *) PyExc_IOError; +PyAPI_DATA(PyObject *) PyExc_OSError; +PyAPI_DATA(PyObject *) PyExc_ImportError; +PyAPI_DATA(PyObject *) PyExc_IndexError; +PyAPI_DATA(PyObject *) PyExc_KeyError; +PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt; +PyAPI_DATA(PyObject *) PyExc_MemoryError; +PyAPI_DATA(PyObject *) PyExc_NameError; +PyAPI_DATA(PyObject *) PyExc_OverflowError; +PyAPI_DATA(PyObject *) PyExc_RuntimeError; +PyAPI_DATA(PyObject *) PyExc_NotImplementedError; +PyAPI_DATA(PyObject *) PyExc_SyntaxError; +PyAPI_DATA(PyObject *) PyExc_IndentationError; +PyAPI_DATA(PyObject *) PyExc_TabError; +PyAPI_DATA(PyObject *) PyExc_ReferenceError; +PyAPI_DATA(PyObject *) PyExc_SystemError; +PyAPI_DATA(PyObject *) PyExc_SystemExit; +PyAPI_DATA(PyObject *) PyExc_TypeError; +PyAPI_DATA(PyObject *) PyExc_UnboundLocalError; +PyAPI_DATA(PyObject *) PyExc_UnicodeError; +PyAPI_DATA(PyObject *) PyExc_UnicodeEncodeError; +PyAPI_DATA(PyObject *) PyExc_UnicodeDecodeError; +PyAPI_DATA(PyObject *) PyExc_UnicodeTranslateError; +PyAPI_DATA(PyObject *) PyExc_ValueError; +PyAPI_DATA(PyObject *) PyExc_ZeroDivisionError; +#ifdef MS_WINDOWS +PyAPI_DATA(PyObject *) PyExc_WindowsError; +#endif +#ifdef __VMS +PyAPI_DATA(PyObject *) PyExc_VMSError; +#endif + +PyAPI_DATA(PyObject *) PyExc_MemoryErrorInst; + +/* Predefined warning categories */ +PyAPI_DATA(PyObject *) PyExc_Warning; +PyAPI_DATA(PyObject *) PyExc_UserWarning; +PyAPI_DATA(PyObject *) PyExc_DeprecationWarning; +PyAPI_DATA(PyObject *) PyExc_PendingDeprecationWarning; +PyAPI_DATA(PyObject *) PyExc_SyntaxWarning; +PyAPI_DATA(PyObject *) PyExc_RuntimeWarning; +PyAPI_DATA(PyObject *) PyExc_FutureWarning; +PyAPI_DATA(PyObject *) PyExc_ImportWarning; +PyAPI_DATA(PyObject *) PyExc_UnicodeWarning; + + +/* Convenience functions */ + +PyAPI_FUNC(int) PyErr_BadArgument(void); +PyAPI_FUNC(PyObject *) PyErr_NoMemory(void); +PyAPI_FUNC(PyObject *) PyErr_SetFromErrno(PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilenameObject( + PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithFilename(PyObject *, char *); +#ifdef Py_WIN_WIDE_FILENAMES +PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilename( + PyObject *, Py_UNICODE *); +#endif /* Py_WIN_WIDE_FILENAMES */ + +PyAPI_FUNC(PyObject *) PyErr_Format(PyObject *, const char *, ...) + Py_GCC_ATTRIBUTE((format(printf, 2, 3))); + +#ifdef MS_WINDOWS +PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilenameObject( + int, const char *); +PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename( + int, const char *); +#ifdef Py_WIN_WIDE_FILENAMES +PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithUnicodeFilename( + int, const Py_UNICODE *); +#endif /* Py_WIN_WIDE_FILENAMES */ +PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErr(int); +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObject( + PyObject *,int, PyObject *); +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilename( + PyObject *,int, const char *); +#ifdef Py_WIN_WIDE_FILENAMES +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilename( + PyObject *,int, const Py_UNICODE *); +#endif /* Py_WIN_WIDE_FILENAMES */ +PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int); +#endif /* MS_WINDOWS */ + +/* Export the old function so that the existing API remains available: */ +PyAPI_FUNC(void) PyErr_BadInternalCall(void); +PyAPI_FUNC(void) _PyErr_BadInternalCall(char *filename, int lineno); +/* Mask the old API with a call to the new API for code compiled under + Python 2.0: */ +#define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) + +/* Function to create a new exception */ +PyAPI_FUNC(PyObject *) PyErr_NewException(char *name, PyObject *base, + PyObject *dict); +PyAPI_FUNC(void) PyErr_WriteUnraisable(PyObject *); + +/* Issue a warning or exception */ +PyAPI_FUNC(int) PyErr_WarnEx(PyObject *category, const char *msg, + Py_ssize_t stack_level); +PyAPI_FUNC(int) PyErr_WarnExplicit(PyObject *, const char *, + const char *, int, + const char *, PyObject *); +/* PyErr_Warn is only for backwards compatability and will be removed. + Use PyErr_WarnEx instead. */ +#define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1) + +/* In sigcheck.c or signalmodule.c */ +PyAPI_FUNC(int) PyErr_CheckSignals(void); +PyAPI_FUNC(void) PyErr_SetInterrupt(void); + +/* Support for adding program text to SyntaxErrors */ +PyAPI_FUNC(void) PyErr_SyntaxLocation(const char *, int); +PyAPI_FUNC(PyObject *) PyErr_ProgramText(const char *, int); + +#ifdef Py_USING_UNICODE +/* The following functions are used to create and modify unicode + exceptions from C */ + +/* create a UnicodeDecodeError object */ +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_Create( + const char *, const char *, Py_ssize_t, Py_ssize_t, Py_ssize_t, const char *); + +/* create a UnicodeEncodeError object */ +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_Create( + const char *, const Py_UNICODE *, Py_ssize_t, Py_ssize_t, Py_ssize_t, const char *); + +/* create a UnicodeTranslateError object */ +PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_Create( + const Py_UNICODE *, Py_ssize_t, Py_ssize_t, Py_ssize_t, const char *); + +/* get the encoding attribute */ +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetEncoding(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetEncoding(PyObject *); + +/* get the object attribute */ +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetObject(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetObject(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetObject(PyObject *); + +/* get the value of the start attribute (the int * may not be NULL) + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_GetStart(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeDecodeError_GetStart(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeTranslateError_GetStart(PyObject *, Py_ssize_t *); + +/* assign a new value to the start attribute + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_SetStart(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeDecodeError_SetStart(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeTranslateError_SetStart(PyObject *, Py_ssize_t); + +/* get the value of the end attribute (the int *may not be NULL) + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_GetEnd(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeDecodeError_GetEnd(PyObject *, Py_ssize_t *); +PyAPI_FUNC(int) PyUnicodeTranslateError_GetEnd(PyObject *, Py_ssize_t *); + +/* assign a new value to the end attribute + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_SetEnd(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeDecodeError_SetEnd(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyUnicodeTranslateError_SetEnd(PyObject *, Py_ssize_t); + +/* get the value of the reason attribute */ +PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetReason(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_GetReason(PyObject *); +PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_GetReason(PyObject *); + +/* assign a new value to the reason attribute + return 0 on success, -1 on failure */ +PyAPI_FUNC(int) PyUnicodeEncodeError_SetReason( + PyObject *, const char *); +PyAPI_FUNC(int) PyUnicodeDecodeError_SetReason( + PyObject *, const char *); +PyAPI_FUNC(int) PyUnicodeTranslateError_SetReason( + PyObject *, const char *); +#endif + + +/* These APIs aren't really part of the error implementation, but + often needed to format error messages; the native C lib APIs are + not available on all platforms, which is why we provide emulations + for those platforms in Python/mysnprintf.c, + WARNING: The return value of snprintf varies across platforms; do + not rely on any particular behavior; eventually the C99 defn may + be reliable. +*/ +#if defined(MS_WIN32) && !defined(HAVE_SNPRINTF) +# define HAVE_SNPRINTF +# define snprintf _snprintf +# define vsnprintf _vsnprintf +#endif + +#include <stdarg.h> +PyAPI_FUNC(int) PyOS_snprintf(char *str, size_t size, const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 3, 4))); +PyAPI_FUNC(int) PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) + Py_GCC_ATTRIBUTE((format(printf, 3, 0))); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_ERRORS_H */ diff --git a/sys/src/cmd/python/Include/pyexpat.h b/sys/src/cmd/python/Include/pyexpat.h new file mode 100644 index 000000000..1e79f4e76 --- /dev/null +++ b/sys/src/cmd/python/Include/pyexpat.h @@ -0,0 +1,47 @@ +/* Stuff to export relevant 'expat' entry points from pyexpat to other + * parser modules, such as cElementTree. */ + +/* note: you must import expat.h before importing this module! */ + +#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.0" + +struct PyExpat_CAPI +{ + char* magic; /* set to PyExpat_CAPI_MAGIC */ + int size; /* set to sizeof(struct PyExpat_CAPI) */ + int MAJOR_VERSION; + int MINOR_VERSION; + int MICRO_VERSION; + /* pointers to selected expat functions. add new functions at + the end, if needed */ + const XML_LChar * (*ErrorString)(enum XML_Error code); + enum XML_Error (*GetErrorCode)(XML_Parser parser); + XML_Size (*GetErrorColumnNumber)(XML_Parser parser); + XML_Size (*GetErrorLineNumber)(XML_Parser parser); + enum XML_Status (*Parse)( + XML_Parser parser, const char *s, int len, int isFinal); + XML_Parser (*ParserCreate_MM)( + const XML_Char *encoding, const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + void (*ParserFree)(XML_Parser parser); + void (*SetCharacterDataHandler)( + XML_Parser parser, XML_CharacterDataHandler handler); + void (*SetCommentHandler)( + XML_Parser parser, XML_CommentHandler handler); + void (*SetDefaultHandlerExpand)( + XML_Parser parser, XML_DefaultHandler handler); + void (*SetElementHandler)( + XML_Parser parser, XML_StartElementHandler start, + XML_EndElementHandler end); + void (*SetNamespaceDeclHandler)( + XML_Parser parser, XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + void (*SetProcessingInstructionHandler)( + XML_Parser parser, XML_ProcessingInstructionHandler handler); + void (*SetUnknownEncodingHandler)( + XML_Parser parser, XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + void (*SetUserData)(XML_Parser parser, void *userData); + /* always add new stuff to the end! */ +}; + diff --git a/sys/src/cmd/python/Include/pyfpe.h b/sys/src/cmd/python/Include/pyfpe.h new file mode 100644 index 000000000..19110ab05 --- /dev/null +++ b/sys/src/cmd/python/Include/pyfpe.h @@ -0,0 +1,176 @@ +#ifndef Py_PYFPE_H +#define Py_PYFPE_H +#ifdef __cplusplus +extern "C" { +#endif +/* + --------------------------------------------------------------------- + / Copyright (c) 1996. \ + | The Regents of the University of California. | + | All rights reserved. | + | | + | Permission to use, copy, modify, and distribute this software for | + | any purpose without fee is hereby granted, provided that this en- | + | tire notice is included in all copies of any software which is or | + | includes a copy or modification of this software and in all | + | copies of the supporting documentation for such software. | + | | + | This work was produced at the University of California, Lawrence | + | Livermore National Laboratory under contract no. W-7405-ENG-48 | + | between the U.S. Department of Energy and The Regents of the | + | University of California for the operation of UC LLNL. | + | | + | DISCLAIMER | + | | + | This software was prepared as an account of work sponsored by an | + | agency of the United States Government. Neither the United States | + | Government nor the University of California nor any of their em- | + | ployees, makes any warranty, express or implied, or assumes any | + | liability or responsibility for the accuracy, completeness, or | + | usefulness of any information, apparatus, product, or process | + | disclosed, or represents that its use would not infringe | + | privately-owned rights. Reference herein to any specific commer- | + | cial products, process, or service by trade name, trademark, | + | manufacturer, or otherwise, does not necessarily constitute or | + | imply its endorsement, recommendation, or favoring by the United | + | States Government or the University of California. The views and | + | opinions of authors expressed herein do not necessarily state or | + | reflect those of the United States Government or the University | + | of California, and shall not be used for advertising or product | + \ endorsement purposes. / + --------------------------------------------------------------------- +*/ + +/* + * Define macros for handling SIGFPE. + * Lee Busby, LLNL, November, 1996 + * busby1@llnl.gov + * + ********************************************* + * Overview of the system for handling SIGFPE: + * + * This file (Include/pyfpe.h) defines a couple of "wrapper" macros for + * insertion into your Python C code of choice. Their proper use is + * discussed below. The file Python/pyfpe.c defines a pair of global + * variables PyFPE_jbuf and PyFPE_counter which are used by the signal + * handler for SIGFPE to decide if a particular exception was protected + * by the macros. The signal handler itself, and code for enabling the + * generation of SIGFPE in the first place, is in a (new) Python module + * named fpectl. This module is standard in every respect. It can be loaded + * either statically or dynamically as you choose, and like any other + * Python module, has no effect until you import it. + * + * In the general case, there are three steps toward handling SIGFPE in any + * Python code: + * + * 1) Add the *_PROTECT macros to your C code as required to protect + * dangerous floating point sections. + * + * 2) Turn on the inclusion of the code by adding the ``--with-fpectl'' + * flag at the time you run configure. If the fpectl or other modules + * which use the *_PROTECT macros are to be dynamically loaded, be + * sure they are compiled with WANT_SIGFPE_HANDLER defined. + * + * 3) When python is built and running, import fpectl, and execute + * fpectl.turnon_sigfpe(). This sets up the signal handler and enables + * generation of SIGFPE whenever an exception occurs. From this point + * on, any properly trapped SIGFPE should result in the Python + * FloatingPointError exception. + * + * Step 1 has been done already for the Python kernel code, and should be + * done soon for the NumPy array package. Step 2 is usually done once at + * python install time. Python's behavior with respect to SIGFPE is not + * changed unless you also do step 3. Thus you can control this new + * facility at compile time, or run time, or both. + * + ******************************** + * Using the macros in your code: + * + * static PyObject *foobar(PyObject *self,PyObject *args) + * { + * .... + * PyFPE_START_PROTECT("Error in foobar", return 0) + * result = dangerous_op(somearg1, somearg2, ...); + * PyFPE_END_PROTECT(result) + * .... + * } + * + * If a floating point error occurs in dangerous_op, foobar returns 0 (NULL), + * after setting the associated value of the FloatingPointError exception to + * "Error in foobar". ``Dangerous_op'' can be a single operation, or a block + * of code, function calls, or any combination, so long as no alternate + * return is possible before the PyFPE_END_PROTECT macro is reached. + * + * The macros can only be used in a function context where an error return + * can be recognized as signaling a Python exception. (Generally, most + * functions that return a PyObject * will qualify.) + * + * Guido's original design suggestion for PyFPE_START_PROTECT and + * PyFPE_END_PROTECT had them open and close a local block, with a locally + * defined jmp_buf and jmp_buf pointer. This would allow recursive nesting + * of the macros. The Ansi C standard makes it clear that such local + * variables need to be declared with the "volatile" type qualifier to keep + * setjmp from corrupting their values. Some current implementations seem + * to be more restrictive. For example, the HPUX man page for setjmp says + * + * Upon the return from a setjmp() call caused by a longjmp(), the + * values of any non-static local variables belonging to the routine + * from which setjmp() was called are undefined. Code which depends on + * such values is not guaranteed to be portable. + * + * I therefore decided on a more limited form of nesting, using a counter + * variable (PyFPE_counter) to keep track of any recursion. If an exception + * occurs in an ``inner'' pair of macros, the return will apparently + * come from the outermost level. + * + */ + +#ifdef WANT_SIGFPE_HANDLER +#include <signal.h> +#include <setjmp.h> +#include <math.h> +extern jmp_buf PyFPE_jbuf; +extern int PyFPE_counter; +extern double PyFPE_dummy(void *); + +#define PyFPE_START_PROTECT(err_string, leave_stmt) \ +if (!PyFPE_counter++ && setjmp(PyFPE_jbuf)) { \ + PyErr_SetString(PyExc_FloatingPointError, err_string); \ + PyFPE_counter = 0; \ + leave_stmt; \ +} + +/* + * This (following) is a heck of a way to decrement a counter. However, + * unless the macro argument is provided, code optimizers will sometimes move + * this statement so that it gets executed *before* the unsafe expression + * which we're trying to protect. That pretty well messes things up, + * of course. + * + * If the expression(s) you're trying to protect don't happen to return a + * value, you will need to manufacture a dummy result just to preserve the + * correct ordering of statements. Note that the macro passes the address + * of its argument (so you need to give it something which is addressable). + * If your expression returns multiple results, pass the last such result + * to PyFPE_END_PROTECT. + * + * Note that PyFPE_dummy returns a double, which is cast to int. + * This seeming insanity is to tickle the Floating Point Unit (FPU). + * If an exception has occurred in a preceding floating point operation, + * some architectures (notably Intel 80x86) will not deliver the interrupt + * until the *next* floating point operation. This is painful if you've + * already decremented PyFPE_counter. + */ +#define PyFPE_END_PROTECT(v) PyFPE_counter -= (int)PyFPE_dummy(&(v)); + +#else + +#define PyFPE_START_PROTECT(err_string, leave_stmt) +#define PyFPE_END_PROTECT(v) + +#endif + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYFPE_H */ diff --git a/sys/src/cmd/python/Include/pygetopt.h b/sys/src/cmd/python/Include/pygetopt.h new file mode 100644 index 000000000..80908bea9 --- /dev/null +++ b/sys/src/cmd/python/Include/pygetopt.h @@ -0,0 +1,17 @@ + +#ifndef Py_PYGETOPT_H +#define Py_PYGETOPT_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_DATA(int) _PyOS_opterr; +PyAPI_DATA(int) _PyOS_optind; +PyAPI_DATA(char *) _PyOS_optarg; + +PyAPI_FUNC(int) _PyOS_GetOpt(int argc, char **argv, char *optstring); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYGETOPT_H */ diff --git a/sys/src/cmd/python/Include/pymactoolbox.h b/sys/src/cmd/python/Include/pymactoolbox.h new file mode 100644 index 000000000..92799e975 --- /dev/null +++ b/sys/src/cmd/python/Include/pymactoolbox.h @@ -0,0 +1,189 @@ +/* +** pymactoolbox.h - globals defined in mactoolboxglue.c +*/ +#ifndef Py_PYMACTOOLBOX_H +#define Py_PYMACTOOLBOX_H +#ifdef __cplusplus + extern "C" { +#endif + +#include <Carbon/Carbon.h> +#include <QuickTime/QuickTime.h> + +/* +** Helper routines for error codes and such. +*/ +char *PyMac_StrError(int); /* strerror with mac errors */ +extern PyObject *PyMac_OSErrException; /* Exception for OSErr */ +PyObject *PyMac_GetOSErrException(void); /* Initialize & return it */ +PyObject *PyErr_Mac(PyObject *, int); /* Exception with a mac error */ +PyObject *PyMac_Error(OSErr); /* Uses PyMac_GetOSErrException */ +extern OSErr PyMac_GetFullPathname(FSSpec *, char *, int); /* convert + fsspec->path */ +/* +** These conversion routines are defined in mactoolboxglue.c itself. +*/ +int PyMac_GetOSType(PyObject *, OSType *); /* argument parser for OSType */ +PyObject *PyMac_BuildOSType(OSType); /* Convert OSType to PyObject */ + +PyObject *PyMac_BuildNumVersion(NumVersion);/* Convert NumVersion to PyObject */ + +int PyMac_GetStr255(PyObject *, Str255); /* argument parser for Str255 */ +PyObject *PyMac_BuildStr255(Str255); /* Convert Str255 to PyObject */ +PyObject *PyMac_BuildOptStr255(Str255); /* Convert Str255 to PyObject, + NULL to None */ + +int PyMac_GetRect(PyObject *, Rect *); /* argument parser for Rect */ +PyObject *PyMac_BuildRect(Rect *); /* Convert Rect to PyObject */ + +int PyMac_GetPoint(PyObject *, Point *); /* argument parser for Point */ +PyObject *PyMac_BuildPoint(Point); /* Convert Point to PyObject */ + +int PyMac_GetEventRecord(PyObject *, EventRecord *); /* argument parser for + EventRecord */ +PyObject *PyMac_BuildEventRecord(EventRecord *); /* Convert EventRecord to + PyObject */ + +int PyMac_GetFixed(PyObject *, Fixed *); /* argument parser for Fixed */ +PyObject *PyMac_BuildFixed(Fixed); /* Convert Fixed to PyObject */ +int PyMac_Getwide(PyObject *, wide *); /* argument parser for wide */ +PyObject *PyMac_Buildwide(wide *); /* Convert wide to PyObject */ + +/* +** The rest of the routines are implemented by extension modules. If they are +** dynamically loaded mactoolboxglue will contain a stub implementation of the +** routine, which imports the module, whereupon the module's init routine will +** communicate the routine pointer back to the stub. +** If USE_TOOLBOX_OBJECT_GLUE is not defined there is no glue code, and the +** extension modules simply declare the routine. This is the case for static +** builds (and could be the case for MacPython CFM builds, because CFM extension +** modules can reference each other without problems). +*/ + +#ifdef USE_TOOLBOX_OBJECT_GLUE +/* +** These macros are used in the module init code. If we use toolbox object glue +** it sets the function pointer to point to the real function. +*/ +#define PyMac_INIT_TOOLBOX_OBJECT_NEW(object, rtn) { \ + extern PyObject *(*PyMacGluePtr_##rtn)(object); \ + PyMacGluePtr_##rtn = _##rtn; \ +} +#define PyMac_INIT_TOOLBOX_OBJECT_CONVERT(object, rtn) { \ + extern int (*PyMacGluePtr_##rtn)(PyObject *, object *); \ + PyMacGluePtr_##rtn = _##rtn; \ +} +#else +/* +** If we don't use toolbox object glue the init macros are empty. Moreover, we define +** _xxx_New to be the same as xxx_New, and the code in mactoolboxglue isn't included. +*/ +#define PyMac_INIT_TOOLBOX_OBJECT_NEW(object, rtn) +#define PyMac_INIT_TOOLBOX_OBJECT_CONVERT(object, rtn) +#endif /* USE_TOOLBOX_OBJECT_GLUE */ + +/* macfs exports */ +int PyMac_GetFSSpec(PyObject *, FSSpec *); /* argument parser for FSSpec */ +PyObject *PyMac_BuildFSSpec(FSSpec *); /* Convert FSSpec to PyObject */ + +int PyMac_GetFSRef(PyObject *, FSRef *); /* argument parser for FSRef */ +PyObject *PyMac_BuildFSRef(FSRef *); /* Convert FSRef to PyObject */ + +/* AE exports */ +extern PyObject *AEDesc_New(AppleEvent *); /* XXXX Why passed by address?? */ +extern PyObject *AEDesc_NewBorrowed(AppleEvent *); +extern int AEDesc_Convert(PyObject *, AppleEvent *); + +/* Cm exports */ +extern PyObject *CmpObj_New(Component); +extern int CmpObj_Convert(PyObject *, Component *); +extern PyObject *CmpInstObj_New(ComponentInstance); +extern int CmpInstObj_Convert(PyObject *, ComponentInstance *); + +/* Ctl exports */ +extern PyObject *CtlObj_New(ControlHandle); +extern int CtlObj_Convert(PyObject *, ControlHandle *); + +/* Dlg exports */ +extern PyObject *DlgObj_New(DialogPtr); +extern int DlgObj_Convert(PyObject *, DialogPtr *); +extern PyObject *DlgObj_WhichDialog(DialogPtr); + +/* Drag exports */ +extern PyObject *DragObj_New(DragReference); +extern int DragObj_Convert(PyObject *, DragReference *); + +/* List exports */ +extern PyObject *ListObj_New(ListHandle); +extern int ListObj_Convert(PyObject *, ListHandle *); + +/* Menu exports */ +extern PyObject *MenuObj_New(MenuHandle); +extern int MenuObj_Convert(PyObject *, MenuHandle *); + +/* Qd exports */ +extern PyObject *GrafObj_New(GrafPtr); +extern int GrafObj_Convert(PyObject *, GrafPtr *); +extern PyObject *BMObj_New(BitMapPtr); +extern int BMObj_Convert(PyObject *, BitMapPtr *); +extern PyObject *QdRGB_New(RGBColor *); +extern int QdRGB_Convert(PyObject *, RGBColor *); + +/* Qdoffs exports */ +extern PyObject *GWorldObj_New(GWorldPtr); +extern int GWorldObj_Convert(PyObject *, GWorldPtr *); + +/* Qt exports */ +extern PyObject *TrackObj_New(Track); +extern int TrackObj_Convert(PyObject *, Track *); +extern PyObject *MovieObj_New(Movie); +extern int MovieObj_Convert(PyObject *, Movie *); +extern PyObject *MovieCtlObj_New(MovieController); +extern int MovieCtlObj_Convert(PyObject *, MovieController *); +extern PyObject *TimeBaseObj_New(TimeBase); +extern int TimeBaseObj_Convert(PyObject *, TimeBase *); +extern PyObject *UserDataObj_New(UserData); +extern int UserDataObj_Convert(PyObject *, UserData *); +extern PyObject *MediaObj_New(Media); +extern int MediaObj_Convert(PyObject *, Media *); + +/* Res exports */ +extern PyObject *ResObj_New(Handle); +extern int ResObj_Convert(PyObject *, Handle *); +extern PyObject *OptResObj_New(Handle); +extern int OptResObj_Convert(PyObject *, Handle *); + +/* TE exports */ +extern PyObject *TEObj_New(TEHandle); +extern int TEObj_Convert(PyObject *, TEHandle *); + +/* Win exports */ +extern PyObject *WinObj_New(WindowPtr); +extern int WinObj_Convert(PyObject *, WindowPtr *); +extern PyObject *WinObj_WhichWindow(WindowPtr); + +/* CF exports */ +extern PyObject *CFObj_New(CFTypeRef); +extern int CFObj_Convert(PyObject *, CFTypeRef *); +extern PyObject *CFTypeRefObj_New(CFTypeRef); +extern int CFTypeRefObj_Convert(PyObject *, CFTypeRef *); +extern PyObject *CFStringRefObj_New(CFStringRef); +extern int CFStringRefObj_Convert(PyObject *, CFStringRef *); +extern PyObject *CFMutableStringRefObj_New(CFMutableStringRef); +extern int CFMutableStringRefObj_Convert(PyObject *, CFMutableStringRef *); +extern PyObject *CFArrayRefObj_New(CFArrayRef); +extern int CFArrayRefObj_Convert(PyObject *, CFArrayRef *); +extern PyObject *CFMutableArrayRefObj_New(CFMutableArrayRef); +extern int CFMutableArrayRefObj_Convert(PyObject *, CFMutableArrayRef *); +extern PyObject *CFDictionaryRefObj_New(CFDictionaryRef); +extern int CFDictionaryRefObj_Convert(PyObject *, CFDictionaryRef *); +extern PyObject *CFMutableDictionaryRefObj_New(CFMutableDictionaryRef); +extern int CFMutableDictionaryRefObj_Convert(PyObject *, CFMutableDictionaryRef *); +extern PyObject *CFURLRefObj_New(CFURLRef); +extern int CFURLRefObj_Convert(PyObject *, CFURLRef *); +extern int OptionalCFURLRefObj_Convert(PyObject *, CFURLRef *); + +#ifdef __cplusplus + } +#endif +#endif diff --git a/sys/src/cmd/python/Include/pymem.h b/sys/src/cmd/python/Include/pymem.h new file mode 100644 index 000000000..671f967c8 --- /dev/null +++ b/sys/src/cmd/python/Include/pymem.h @@ -0,0 +1,105 @@ +/* The PyMem_ family: low-level memory allocation interfaces. + See objimpl.h for the PyObject_ memory family. +*/ + +#ifndef Py_PYMEM_H +#define Py_PYMEM_H + +#include "pyport.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* BEWARE: + + Each interface exports both functions and macros. Extension modules should + use the functions, to ensure binary compatibility across Python versions. + Because the Python implementation is free to change internal details, and + the macros may (or may not) expose details for speed, if you do use the + macros you must recompile your extensions with each Python release. + + Never mix calls to PyMem_ with calls to the platform malloc/realloc/ + calloc/free. For example, on Windows different DLLs may end up using + different heaps, and if you use PyMem_Malloc you'll get the memory from the + heap used by the Python DLL; it could be a disaster if you free()'ed that + directly in your own extension. Using PyMem_Free instead ensures Python + can return the memory to the proper heap. As another example, in + PYMALLOC_DEBUG mode, Python wraps all calls to all PyMem_ and PyObject_ + memory functions in special debugging wrappers that add additional + debugging info to dynamic memory blocks. The system routines have no idea + what to do with that stuff, and the Python wrappers have no idea what to do + with raw blocks obtained directly by the system routines then. +*/ + +/* + * Raw memory interface + * ==================== + */ + +/* Functions + + Functions supplying platform-independent semantics for malloc/realloc/ + free. These functions make sure that allocating 0 bytes returns a distinct + non-NULL pointer (whenever possible -- if we're flat out of memory, NULL + may be returned), even if the platform malloc and realloc don't. + Returned pointers must be checked for NULL explicitly. No action is + performed on failure (no exception is set, no warning is printed, etc). +*/ + +PyAPI_FUNC(void *) PyMem_Malloc(size_t); +PyAPI_FUNC(void *) PyMem_Realloc(void *, size_t); +PyAPI_FUNC(void) PyMem_Free(void *); + +/* Starting from Python 1.6, the wrappers Py_{Malloc,Realloc,Free} are + no longer supported. They used to call PyErr_NoMemory() on failure. */ + +/* Macros. */ +#ifdef PYMALLOC_DEBUG +/* Redirect all memory operations to Python's debugging allocator. */ +#define PyMem_MALLOC PyObject_MALLOC +#define PyMem_REALLOC PyObject_REALLOC +#define PyMem_FREE PyObject_FREE + +#else /* ! PYMALLOC_DEBUG */ + +/* PyMem_MALLOC(0) means malloc(1). Some systems would return NULL + for malloc(0), which would be treated as an error. Some platforms + would return a pointer with no memory behind it, which would break + pymalloc. To solve these problems, allocate an extra byte. */ +#define PyMem_MALLOC(n) malloc((n) ? (n) : 1) +#define PyMem_REALLOC(p, n) realloc((p), (n) ? (n) : 1) +#define PyMem_FREE free + +#endif /* PYMALLOC_DEBUG */ + +/* + * Type-oriented memory interface + * ============================== + * + * These are carried along for historical reasons. There's rarely a good + * reason to use them anymore (you can just as easily do the multiply and + * cast yourself). + */ + +#define PyMem_New(type, n) \ + ( (type *) PyMem_Malloc((n) * sizeof(type)) ) +#define PyMem_NEW(type, n) \ + ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) + +#define PyMem_Resize(p, type, n) \ + ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) +#define PyMem_RESIZE(p, type, n) \ + ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) + +/* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used + * anymore. They're just confusing aliases for PyMem_{Free,FREE} now. + */ +#define PyMem_Del PyMem_Free +#define PyMem_DEL PyMem_FREE + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_PYMEM_H */ diff --git a/sys/src/cmd/python/Include/pyport.h b/sys/src/cmd/python/Include/pyport.h new file mode 100644 index 000000000..6fe3f0b52 --- /dev/null +++ b/sys/src/cmd/python/Include/pyport.h @@ -0,0 +1,771 @@ +#ifndef Py_PYPORT_H +#define Py_PYPORT_H + +#include "pyconfig.h" /* include for defines */ + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +/************************************************************************** +Symbols and macros to supply platform-independent interfaces to basic +C language & library operations whose spellings vary across platforms. + +Please try to make documentation here as clear as possible: by definition, +the stuff here is trying to illuminate C's darkest corners. + +Config #defines referenced here: + +SIGNED_RIGHT_SHIFT_ZERO_FILLS +Meaning: To be defined iff i>>j does not extend the sign bit when i is a + signed integral type and i < 0. +Used in: Py_ARITHMETIC_RIGHT_SHIFT + +Py_DEBUG +Meaning: Extra checks compiled in for debug mode. +Used in: Py_SAFE_DOWNCAST + +HAVE_UINTPTR_T +Meaning: The C9X type uintptr_t is supported by the compiler +Used in: Py_uintptr_t + +HAVE_LONG_LONG +Meaning: The compiler supports the C type "long long" +Used in: PY_LONG_LONG + +**************************************************************************/ + + +/* For backward compatibility only. Obsolete, do not use. */ +#ifdef HAVE_PROTOTYPES +#define Py_PROTO(x) x +#else +#define Py_PROTO(x) () +#endif +#ifndef Py_FPROTO +#define Py_FPROTO(x) Py_PROTO(x) +#endif + +/* typedefs for some C9X-defined synonyms for integral types. + * + * The names in Python are exactly the same as the C9X names, except with a + * Py_ prefix. Until C9X is universally implemented, this is the only way + * to ensure that Python gets reliable names that don't conflict with names + * in non-Python code that are playing their own tricks to define the C9X + * names. + * + * NOTE: don't go nuts here! Python has no use for *most* of the C9X + * integral synonyms. Only define the ones we actually need. + */ + +#ifdef HAVE_LONG_LONG +#ifndef PY_LONG_LONG +#define PY_LONG_LONG long long +#endif +#endif /* HAVE_LONG_LONG */ + +/* uintptr_t is the C9X name for an unsigned integral type such that a + * legitimate void* can be cast to uintptr_t and then back to void* again + * without loss of information. Similarly for intptr_t, wrt a signed + * integral type. + */ +#ifdef HAVE_UINTPTR_T +typedef uintptr_t Py_uintptr_t; +typedef intptr_t Py_intptr_t; + +#elif SIZEOF_VOID_P <= SIZEOF_INT +typedef unsigned int Py_uintptr_t; +typedef int Py_intptr_t; + +#elif SIZEOF_VOID_P <= SIZEOF_LONG +typedef unsigned long Py_uintptr_t; +typedef long Py_intptr_t; + +#elif defined(HAVE_LONG_LONG) && (SIZEOF_VOID_P <= SIZEOF_LONG_LONG) +typedef unsigned PY_LONG_LONG Py_uintptr_t; +typedef PY_LONG_LONG Py_intptr_t; + +#else +# error "Python needs a typedef for Py_uintptr_t in pyport.h." +#endif /* HAVE_UINTPTR_T */ + +/* Py_ssize_t is a signed integral type such that sizeof(Py_ssize_t) == + * sizeof(size_t). C99 doesn't define such a thing directly (size_t is an + * unsigned integral type). See PEP 353 for details. + */ +#ifdef HAVE_SSIZE_T +typedef ssize_t Py_ssize_t; +#elif SIZEOF_VOID_P == SIZEOF_SIZE_T +typedef Py_intptr_t Py_ssize_t; +#else +# error "Python needs a typedef for Py_ssize_t in pyport.h." +#endif + +/* Largest positive value of type Py_ssize_t. */ +#define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1)) +/* Smallest negative value of type Py_ssize_t. */ +#define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1) + +/* PY_FORMAT_SIZE_T is a platform-specific modifier for use in a printf + * format to convert an argument with the width of a size_t or Py_ssize_t. + * C99 introduced "z" for this purpose, but not all platforms support that; + * e.g., MS compilers use "I" instead. + * + * These "high level" Python format functions interpret "z" correctly on + * all platforms (Python interprets the format string itself, and does whatever + * the platform C requires to convert a size_t/Py_ssize_t argument): + * + * PyString_FromFormat + * PyErr_Format + * PyString_FromFormatV + * + * Lower-level uses require that you interpolate the correct format modifier + * yourself (e.g., calling printf, fprintf, sprintf, PyOS_snprintf); for + * example, + * + * Py_ssize_t index; + * fprintf(stderr, "index %" PY_FORMAT_SIZE_T "d sucks\n", index); + * + * That will expand to %ld, or %Id, or to something else correct for a + * Py_ssize_t on the platform. + */ +#ifndef PY_FORMAT_SIZE_T +# if SIZEOF_SIZE_T == SIZEOF_INT && !defined(__APPLE__) +# define PY_FORMAT_SIZE_T "" +# elif SIZEOF_SIZE_T == SIZEOF_LONG +# define PY_FORMAT_SIZE_T "l" +# elif defined(MS_WINDOWS) +# define PY_FORMAT_SIZE_T "I" +# else +# error "This platform's pyconfig.h needs to define PY_FORMAT_SIZE_T" +# endif +#endif + +/* Py_LOCAL can be used instead of static to get the fastest possible calling + * convention for functions that are local to a given module. + * + * Py_LOCAL_INLINE does the same thing, and also explicitly requests inlining, + * for platforms that support that. + * + * If PY_LOCAL_AGGRESSIVE is defined before python.h is included, more + * "aggressive" inlining/optimizaion is enabled for the entire module. This + * may lead to code bloat, and may slow things down for those reasons. It may + * also lead to errors, if the code relies on pointer aliasing. Use with + * care. + * + * NOTE: You can only use this for functions that are entirely local to a + * module; functions that are exported via method tables, callbacks, etc, + * should keep using static. + */ + +#undef USE_INLINE /* XXX - set via configure? */ + +#if defined(_MSC_VER) +#if defined(PY_LOCAL_AGGRESSIVE) +/* enable more aggressive optimization for visual studio */ +#pragma optimize("agtw", on) +#endif +/* ignore warnings if the compiler decides not to inline a function */ +#pragma warning(disable: 4710) +/* fastest possible local call under MSVC */ +#define Py_LOCAL(type) static type __fastcall +#define Py_LOCAL_INLINE(type) static __inline type __fastcall +#elif defined(USE_INLINE) +#define Py_LOCAL(type) static type +#define Py_LOCAL_INLINE(type) static inline type +#else +#define Py_LOCAL(type) static type +#define Py_LOCAL_INLINE(type) static type +#endif + +/* Py_MEMCPY can be used instead of memcpy in cases where the copied blocks + * are often very short. While most platforms have highly optimized code for + * large transfers, the setup costs for memcpy are often quite high. MEMCPY + * solves this by doing short copies "in line". + */ + +#if defined(_MSC_VER) +#define Py_MEMCPY(target, source, length) do { \ + size_t i_, n_ = (length); \ + char *t_ = (void*) (target); \ + const char *s_ = (void*) (source); \ + if (n_ >= 16) \ + memcpy(t_, s_, n_); \ + else \ + for (i_ = 0; i_ < n_; i_++) \ + t_[i_] = s_[i_]; \ + } while (0) +#else +#define Py_MEMCPY memcpy +#endif + +#include <stdlib.h> + +#include <math.h> /* Moved here from the math section, before extern "C" */ + +/******************************************** + * WRAPPER FOR <time.h> and/or <sys/time.h> * + ********************************************/ + +#ifdef TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else /* !TIME_WITH_SYS_TIME */ +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else /* !HAVE_SYS_TIME_H */ +#include <time.h> +#endif /* !HAVE_SYS_TIME_H */ +#endif /* !TIME_WITH_SYS_TIME */ + + +/****************************** + * WRAPPER FOR <sys/select.h> * + ******************************/ + +/* NB caller must include <sys/types.h> */ + +#ifdef HAVE_SYS_SELECT_H + +#include <sys/select.h> + +#endif /* !HAVE_SYS_SELECT_H */ + +/******************************* + * stat() and fstat() fiddling * + *******************************/ + +/* We expect that stat and fstat exist on most systems. + * It's confirmed on Unix, Mac and Windows. + * If you don't have them, add + * #define DONT_HAVE_STAT + * and/or + * #define DONT_HAVE_FSTAT + * to your pyconfig.h. Python code beyond this should check HAVE_STAT and + * HAVE_FSTAT instead. + * Also + * #define HAVE_SYS_STAT_H + * if <sys/stat.h> exists on your platform, and + * #define HAVE_STAT_H + * if <stat.h> does. + */ +#ifndef DONT_HAVE_STAT +#define HAVE_STAT +#endif + +#ifndef DONT_HAVE_FSTAT +#define HAVE_FSTAT +#endif + +#ifdef RISCOS +#include <sys/types.h> +#include "unixstuff.h" +#endif + +#ifdef HAVE_SYS_STAT_H +#if defined(PYOS_OS2) && defined(PYCC_GCC) +#include <sys/types.h> +#endif +#include <sys/stat.h> +#elif defined(HAVE_STAT_H) +#include <stat.h> +#endif + +#if defined(PYCC_VACPP) +/* VisualAge C/C++ Failed to Define MountType Field in sys/stat.h */ +#define S_IFMT (S_IFDIR|S_IFCHR|S_IFREG) +#endif + +#ifndef S_ISREG +#define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) +#endif + +#ifndef S_ISDIR +#define S_ISDIR(x) (((x) & S_IFMT) == S_IFDIR) +#endif + + +#ifdef __cplusplus +/* Move this down here since some C++ #include's don't like to be included + inside an extern "C" */ +extern "C" { +#endif + + +/* Py_ARITHMETIC_RIGHT_SHIFT + * C doesn't define whether a right-shift of a signed integer sign-extends + * or zero-fills. Here a macro to force sign extension: + * Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) + * Return I >> J, forcing sign extension. + * Requirements: + * I is of basic signed type TYPE (char, short, int, long, or long long). + * TYPE is one of char, short, int, long, or long long, although long long + * must not be used except on platforms that support it. + * J is an integer >= 0 and strictly less than the number of bits in TYPE + * (because C doesn't define what happens for J outside that range either). + * Caution: + * I may be evaluated more than once. + */ +#ifdef SIGNED_RIGHT_SHIFT_ZERO_FILLS +#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) \ + ((I) < 0 ? ~((~(unsigned TYPE)(I)) >> (J)) : (I) >> (J)) +#else +#define Py_ARITHMETIC_RIGHT_SHIFT(TYPE, I, J) ((I) >> (J)) +#endif + +/* Py_FORCE_EXPANSION(X) + * "Simply" returns its argument. However, macro expansions within the + * argument are evaluated. This unfortunate trickery is needed to get + * token-pasting to work as desired in some cases. + */ +#define Py_FORCE_EXPANSION(X) X + +/* Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) + * Cast VALUE to type NARROW from type WIDE. In Py_DEBUG mode, this + * assert-fails if any information is lost. + * Caution: + * VALUE may be evaluated more than once. + */ +#ifdef Py_DEBUG +#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) \ + (assert((WIDE)(NARROW)(VALUE) == (VALUE)), (NARROW)(VALUE)) +#else +#define Py_SAFE_DOWNCAST(VALUE, WIDE, NARROW) (NARROW)(VALUE) +#endif + +/* Py_IS_NAN(X) + * Return 1 if float or double arg is a NaN, else 0. + * Caution: + * X is evaluated more than once. + * This may not work on all platforms. Each platform has *some* + * way to spell this, though -- override in pyconfig.h if you have + * a platform where it doesn't work. + */ +#ifndef Py_IS_NAN +#define Py_IS_NAN(X) ((X) != (X)) +#endif + +/* Py_IS_INFINITY(X) + * Return 1 if float or double arg is an infinity, else 0. + * Caution: + * X is evaluated more than once. + * This implementation may set the underflow flag if |X| is very small; + * it really can't be implemented correctly (& easily) before C99. + * Override in pyconfig.h if you have a better spelling on your platform. + */ +#ifndef Py_IS_INFINITY +#define Py_IS_INFINITY(X) ((X) && (X)*0.5 == (X)) +#endif + +/* Py_IS_FINITE(X) + * Return 1 if float or double arg is neither infinite nor NAN, else 0. + * Some compilers (e.g. VisualStudio) have intrisics for this, so a special + * macro for this particular test is useful + */ +#ifndef Py_IS_FINITE +#define Py_IS_FINITE(X) (!Py_IS_INFINITY(X) && !Py_IS_NAN(X)) +#endif + +/* HUGE_VAL is supposed to expand to a positive double infinity. Python + * uses Py_HUGE_VAL instead because some platforms are broken in this + * respect. We used to embed code in pyport.h to try to worm around that, + * but different platforms are broken in conflicting ways. If you're on + * a platform where HUGE_VAL is defined incorrectly, fiddle your Python + * config to #define Py_HUGE_VAL to something that works on your platform. + */ +#ifndef Py_HUGE_VAL +#define Py_HUGE_VAL HUGE_VAL +#endif + +/* Py_OVERFLOWED(X) + * Return 1 iff a libm function overflowed. Set errno to 0 before calling + * a libm function, and invoke this macro after, passing the function + * result. + * Caution: + * This isn't reliable. C99 no longer requires libm to set errno under + * any exceptional condition, but does require +- HUGE_VAL return + * values on overflow. A 754 box *probably* maps HUGE_VAL to a + * double infinity, and we're cool if that's so, unless the input + * was an infinity and an infinity is the expected result. A C89 + * system sets errno to ERANGE, so we check for that too. We're + * out of luck if a C99 754 box doesn't map HUGE_VAL to +Inf, or + * if the returned result is a NaN, or if a C89 box returns HUGE_VAL + * in non-overflow cases. + * X is evaluated more than once. + * Some platforms have better way to spell this, so expect some #ifdef'ery. + * + * OpenBSD uses 'isinf()' because a compiler bug on that platform causes + * the longer macro version to be mis-compiled. This isn't optimal, and + * should be removed once a newer compiler is available on that platform. + * The system that had the failure was running OpenBSD 3.2 on Intel, with + * gcc 2.95.3. + * + * According to Tim's checkin, the FreeBSD systems use isinf() to work + * around a FPE bug on that platform. + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) +#define Py_OVERFLOWED(X) isinf(X) +#else +#define Py_OVERFLOWED(X) ((X) != 0.0 && (errno == ERANGE || \ + (X) == Py_HUGE_VAL || \ + (X) == -Py_HUGE_VAL)) +#endif + +/* Py_SET_ERRNO_ON_MATH_ERROR(x) + * If a libm function did not set errno, but it looks like the result + * overflowed or not-a-number, set errno to ERANGE or EDOM. Set errno + * to 0 before calling a libm function, and invoke this macro after, + * passing the function result. + * Caution: + * This isn't reliable. See Py_OVERFLOWED comments. + * X is evaluated more than once. + */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || (defined(__hpux) && defined(__ia64)) +#define _Py_SET_EDOM_FOR_NAN(X) if (isnan(X)) errno = EDOM; +#else +#define _Py_SET_EDOM_FOR_NAN(X) ; +#endif +#define Py_SET_ERRNO_ON_MATH_ERROR(X) \ + do { \ + if (errno == 0) { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ + errno = ERANGE; \ + else _Py_SET_EDOM_FOR_NAN(X) \ + } \ + } while(0) + +/* Py_SET_ERANGE_ON_OVERFLOW(x) + * An alias of Py_SET_ERRNO_ON_MATH_ERROR for backward-compatibility. + */ +#define Py_SET_ERANGE_IF_OVERFLOW(X) Py_SET_ERRNO_ON_MATH_ERROR(X) + +/* Py_ADJUST_ERANGE1(x) + * Py_ADJUST_ERANGE2(x, y) + * Set errno to 0 before calling a libm function, and invoke one of these + * macros after, passing the function result(s) (Py_ADJUST_ERANGE2 is useful + * for functions returning complex results). This makes two kinds of + * adjustments to errno: (A) If it looks like the platform libm set + * errno=ERANGE due to underflow, clear errno. (B) If it looks like the + * platform libm overflowed but didn't set errno, force errno to ERANGE. In + * effect, we're trying to force a useful implementation of C89 errno + * behavior. + * Caution: + * This isn't reliable. See Py_OVERFLOWED comments. + * X and Y may be evaluated more than once. + */ +#define Py_ADJUST_ERANGE1(X) \ + do { \ + if (errno == 0) { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL) \ + errno = ERANGE; \ + } \ + else if (errno == ERANGE && (X) == 0.0) \ + errno = 0; \ + } while(0) + +#define Py_ADJUST_ERANGE2(X, Y) \ + do { \ + if ((X) == Py_HUGE_VAL || (X) == -Py_HUGE_VAL || \ + (Y) == Py_HUGE_VAL || (Y) == -Py_HUGE_VAL) { \ + if (errno == 0) \ + errno = ERANGE; \ + } \ + else if (errno == ERANGE) \ + errno = 0; \ + } while(0) + +/* Py_DEPRECATED(version) + * Declare a variable, type, or function deprecated. + * Usage: + * extern int old_var Py_DEPRECATED(2.3); + * typedef int T1 Py_DEPRECATED(2.4); + * extern int x() Py_DEPRECATED(2.5); + */ +#if defined(__GNUC__) && ((__GNUC__ >= 4) || \ + (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1)) +#define Py_DEPRECATED(VERSION_UNUSED) __attribute__((__deprecated__)) +#else +#define Py_DEPRECATED(VERSION_UNUSED) +#endif + +/************************************************************************** +Prototypes that are missing from the standard include files on some systems +(and possibly only some versions of such systems.) + +Please be conservative with adding new ones, document them and enclose them +in platform-specific #ifdefs. +**************************************************************************/ + +#ifdef SOLARIS +/* Unchecked */ +extern int gethostname(char *, int); +#endif + +#ifdef __BEOS__ +/* Unchecked */ +/* It's in the libs, but not the headers... - [cjh] */ +int shutdown( int, int ); +#endif + +#ifdef HAVE__GETPTY +#include <sys/types.h> /* we need to import mode_t */ +extern char * _getpty(int *, int, mode_t, int); +#endif + +#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) +#if !defined(HAVE_PTY_H) && !defined(HAVE_LIBUTIL_H) +/* BSDI does not supply a prototype for the 'openpty' and 'forkpty' + functions, even though they are included in libutil. */ +#include <termios.h> +extern int openpty(int *, int *, char *, struct termios *, struct winsize *); +extern int forkpty(int *, char *, struct termios *, struct winsize *); +#endif /* !defined(HAVE_PTY_H) && !defined(HAVE_LIBUTIL_H) */ +#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) */ + + +/* These are pulled from various places. It isn't obvious on what platforms + they are necessary, nor what the exact prototype should look like (which + is likely to vary between platforms!) If you find you need one of these + declarations, please move them to a platform-specific block and include + proper prototypes. */ +#if 0 + +/* From Modules/resource.c */ +extern int getrusage(); +extern int getpagesize(); + +/* From Python/sysmodule.c and Modules/posixmodule.c */ +extern int fclose(FILE *); + +/* From Modules/posixmodule.c */ +extern int fdatasync(int); +#endif /* 0 */ + + +/************************ + * WRAPPER FOR <math.h> * + ************************/ + +#ifndef HAVE_HYPOT +extern double hypot(double, double); +#endif + + +/* On 4.4BSD-descendants, ctype functions serves the whole range of + * wchar_t character set rather than single byte code points only. + * This characteristic can break some operations of string object + * including str.upper() and str.split() on UTF-8 locales. This + * workaround was provided by Tim Robbins of FreeBSD project. + */ + +#ifdef __FreeBSD__ +#include <osreldate.h> +#if __FreeBSD_version > 500039 +#include <ctype.h> +#include <wctype.h> +#undef isalnum +#define isalnum(c) iswalnum(btowc(c)) +#undef isalpha +#define isalpha(c) iswalpha(btowc(c)) +#undef islower +#define islower(c) iswlower(btowc(c)) +#undef isspace +#define isspace(c) iswspace(btowc(c)) +#undef isupper +#define isupper(c) iswupper(btowc(c)) +#undef tolower +#define tolower(c) towlower(btowc(c)) +#undef toupper +#define toupper(c) towupper(btowc(c)) +#endif +#endif + + +/* Declarations for symbol visibility. + + PyAPI_FUNC(type): Declares a public Python API function and return type + PyAPI_DATA(type): Declares public Python data and its type + PyMODINIT_FUNC: A Python module init function. If these functions are + inside the Python core, they are private to the core. + If in an extension module, it may be declared with + external linkage depending on the platform. + + As a number of platforms support/require "__declspec(dllimport/dllexport)", + we support a HAVE_DECLSPEC_DLL macro to save duplication. +*/ + +/* + All windows ports, except cygwin, are handled in PC/pyconfig.h. + + BeOS and cygwin are the only other autoconf platform requiring special + linkage handling and both of these use __declspec(). +*/ +#if defined(__CYGWIN__) || defined(__BEOS__) +# define HAVE_DECLSPEC_DLL +#endif + +/* only get special linkage if built as shared or platform is Cygwin */ +#if defined(Py_ENABLE_SHARED) || defined(__CYGWIN__) +# if defined(HAVE_DECLSPEC_DLL) +# ifdef Py_BUILD_CORE +# define PyAPI_FUNC(RTYPE) __declspec(dllexport) RTYPE +# define PyAPI_DATA(RTYPE) extern __declspec(dllexport) RTYPE + /* module init functions inside the core need no external linkage */ + /* except for Cygwin to handle embedding (FIXME: BeOS too?) */ +# if defined(__CYGWIN__) +# define PyMODINIT_FUNC __declspec(dllexport) void +# else /* __CYGWIN__ */ +# define PyMODINIT_FUNC void +# endif /* __CYGWIN__ */ +# else /* Py_BUILD_CORE */ + /* Building an extension module, or an embedded situation */ + /* public Python functions and data are imported */ + /* Under Cygwin, auto-import functions to prevent compilation */ + /* failures similar to http://python.org/doc/FAQ.html#3.24 */ +# if !defined(__CYGWIN__) +# define PyAPI_FUNC(RTYPE) __declspec(dllimport) RTYPE +# endif /* !__CYGWIN__ */ +# define PyAPI_DATA(RTYPE) extern __declspec(dllimport) RTYPE + /* module init functions outside the core must be exported */ +# if defined(__cplusplus) +# define PyMODINIT_FUNC extern "C" __declspec(dllexport) void +# else /* __cplusplus */ +# define PyMODINIT_FUNC __declspec(dllexport) void +# endif /* __cplusplus */ +# endif /* Py_BUILD_CORE */ +# endif /* HAVE_DECLSPEC */ +#endif /* Py_ENABLE_SHARED */ + +/* If no external linkage macros defined by now, create defaults */ +#ifndef PyAPI_FUNC +# define PyAPI_FUNC(RTYPE) RTYPE +#endif +#ifndef PyAPI_DATA +# define PyAPI_DATA(RTYPE) extern RTYPE +#endif +#ifndef PyMODINIT_FUNC +# if defined(__cplusplus) +# define PyMODINIT_FUNC extern "C" void +# else /* __cplusplus */ +# define PyMODINIT_FUNC void +# endif /* __cplusplus */ +#endif + +/* Deprecated DL_IMPORT and DL_EXPORT macros */ +#if defined(Py_ENABLE_SHARED) && defined (HAVE_DECLSPEC_DLL) +# if defined(Py_BUILD_CORE) +# define DL_IMPORT(RTYPE) __declspec(dllexport) RTYPE +# define DL_EXPORT(RTYPE) __declspec(dllexport) RTYPE +# else +# define DL_IMPORT(RTYPE) __declspec(dllimport) RTYPE +# define DL_EXPORT(RTYPE) __declspec(dllexport) RTYPE +# endif +#endif +#ifndef DL_EXPORT +# define DL_EXPORT(RTYPE) RTYPE +#endif +#ifndef DL_IMPORT +# define DL_IMPORT(RTYPE) RTYPE +#endif +/* End of deprecated DL_* macros */ + +/* If the fd manipulation macros aren't defined, + here is a set that should do the job */ + +#if 0 /* disabled and probably obsolete */ + +#ifndef FD_SETSIZE +#define FD_SETSIZE 256 +#endif + +#ifndef FD_SET + +typedef long fd_mask; + +#define NFDBITS (sizeof(fd_mask) * NBBY) /* bits per mask */ +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif /* howmany */ + +typedef struct fd_set { + fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; +} fd_set; + +#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) +#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) +#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) +#define FD_ZERO(p) memset((char *)(p), '\0', sizeof(*(p))) + +#endif /* FD_SET */ + +#endif /* fd manipulation macros */ + + +/* limits.h constants that may be missing */ + +#ifndef INT_MAX +#define INT_MAX 2147483647 +#endif + +#ifndef LONG_MAX +#if SIZEOF_LONG == 4 +#define LONG_MAX 0X7FFFFFFFL +#elif SIZEOF_LONG == 8 +#define LONG_MAX 0X7FFFFFFFFFFFFFFFL +#else +#error "could not set LONG_MAX in pyport.h" +#endif +#endif + +#ifndef LONG_MIN +#define LONG_MIN (-LONG_MAX-1) +#endif + +#ifndef LONG_BIT +#define LONG_BIT (8 * SIZEOF_LONG) +#endif + +#if LONG_BIT != 8 * SIZEOF_LONG +/* 04-Oct-2000 LONG_BIT is apparently (mis)defined as 64 on some recent + * 32-bit platforms using gcc. We try to catch that here at compile-time + * rather than waiting for integer multiplication to trigger bogus + * overflows. + */ +#error "LONG_BIT definition appears wrong for platform (bad gcc/glibc config?)." +#endif + +#ifdef __cplusplus +} +#endif + +/* + * Hide GCC attributes from compilers that don't support them. + */ +#if (!defined(__GNUC__) || __GNUC__ < 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ < 7) ) && \ + !defined(RISCOS) +#define Py_GCC_ATTRIBUTE(x) +#else +#define Py_GCC_ATTRIBUTE(x) __attribute__(x) +#endif + +/* Eliminate end-of-loop code not reached warnings from SunPro C + * when using do{...}while(0) macros + */ +#ifdef __SUNPRO_C +#pragma error_messages (off,E_END_OF_LOOP_CODE_NOT_REACHED) +#endif + +/* + * Older Microsoft compilers don't support the C99 long long literal suffixes, + * so these will be defined in PC/pyconfig.h for those compilers. + */ +#ifndef Py_LL +#define Py_LL(x) x##LL +#endif + +#ifndef Py_ULL +#define Py_ULL(x) Py_LL(x##U) +#endif + +#endif /* Py_PYPORT_H */ diff --git a/sys/src/cmd/python/Include/pystate.h b/sys/src/cmd/python/Include/pystate.h new file mode 100644 index 000000000..4919d99b6 --- /dev/null +++ b/sys/src/cmd/python/Include/pystate.h @@ -0,0 +1,195 @@ + +/* Thread and interpreter state structures and their interfaces */ + + +#ifndef Py_PYSTATE_H +#define Py_PYSTATE_H +#ifdef __cplusplus +extern "C" { +#endif + +/* State shared between threads */ + +struct _ts; /* Forward */ +struct _is; /* Forward */ + +typedef struct _is { + + struct _is *next; + struct _ts *tstate_head; + + PyObject *modules; + PyObject *sysdict; + PyObject *builtins; + PyObject *modules_reloading; + + PyObject *codec_search_path; + PyObject *codec_search_cache; + PyObject *codec_error_registry; + +#ifdef HAVE_DLOPEN + int dlopenflags; +#endif +#ifdef WITH_TSC + int tscdump; +#endif + +} PyInterpreterState; + + +/* State unique per thread */ + +struct _frame; /* Avoid including frameobject.h */ + +/* Py_tracefunc return -1 when raising an exception, or 0 for success. */ +typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *); + +/* The following values are used for 'what' for tracefunc functions: */ +#define PyTrace_CALL 0 +#define PyTrace_EXCEPTION 1 +#define PyTrace_LINE 2 +#define PyTrace_RETURN 3 +#define PyTrace_C_CALL 4 +#define PyTrace_C_EXCEPTION 5 +#define PyTrace_C_RETURN 6 + +typedef struct _ts { + /* See Python/ceval.c for comments explaining most fields */ + + struct _ts *next; + PyInterpreterState *interp; + + struct _frame *frame; + int recursion_depth; + /* 'tracing' keeps track of the execution depth when tracing/profiling. + This is to prevent the actual trace/profile code from being recorded in + the trace/profile. */ + int tracing; + int use_tracing; + + Py_tracefunc c_profilefunc; + Py_tracefunc c_tracefunc; + PyObject *c_profileobj; + PyObject *c_traceobj; + + PyObject *curexc_type; + PyObject *curexc_value; + PyObject *curexc_traceback; + + PyObject *exc_type; + PyObject *exc_value; + PyObject *exc_traceback; + + PyObject *dict; /* Stores per-thread state */ + + /* tick_counter is incremented whenever the check_interval ticker + * reaches zero. The purpose is to give a useful measure of the number + * of interpreted bytecode instructions in a given thread. This + * extremely lightweight statistic collector may be of interest to + * profilers (like psyco.jit()), although nothing in the core uses it. + */ + int tick_counter; + + int gilstate_counter; + + PyObject *async_exc; /* Asynchronous exception to raise */ + long thread_id; /* Thread id where this tstate was created */ + + /* XXX signal handlers should also be here */ + +} PyThreadState; + + +PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void); +PyAPI_FUNC(void) PyInterpreterState_Clear(PyInterpreterState *); +PyAPI_FUNC(void) PyInterpreterState_Delete(PyInterpreterState *); + +PyAPI_FUNC(PyThreadState *) PyThreadState_New(PyInterpreterState *); +PyAPI_FUNC(void) PyThreadState_Clear(PyThreadState *); +PyAPI_FUNC(void) PyThreadState_Delete(PyThreadState *); +#ifdef WITH_THREAD +PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void); +#endif + +PyAPI_FUNC(PyThreadState *) PyThreadState_Get(void); +PyAPI_FUNC(PyThreadState *) PyThreadState_Swap(PyThreadState *); +PyAPI_FUNC(PyObject *) PyThreadState_GetDict(void); +PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *); + + +/* Variable and macro for in-line access to current thread state */ + +PyAPI_DATA(PyThreadState *) _PyThreadState_Current; + +#ifdef Py_DEBUG +#define PyThreadState_GET() PyThreadState_Get() +#else +#define PyThreadState_GET() (_PyThreadState_Current) +#endif + +typedef + enum {PyGILState_LOCKED, PyGILState_UNLOCKED} + PyGILState_STATE; + +/* Ensure that the current thread is ready to call the Python + C API, regardless of the current state of Python, or of its + thread lock. This may be called as many times as desired + by a thread so long as each call is matched with a call to + PyGILState_Release(). In general, other thread-state APIs may + be used between _Ensure() and _Release() calls, so long as the + thread-state is restored to its previous state before the Release(). + For example, normal use of the Py_BEGIN_ALLOW_THREADS/ + Py_END_ALLOW_THREADS macros are acceptable. + + The return value is an opaque "handle" to the thread state when + PyGILState_Ensure() was called, and must be passed to + PyGILState_Release() to ensure Python is left in the same state. Even + though recursive calls are allowed, these handles can *not* be shared - + each unique call to PyGILState_Ensure must save the handle for its + call to PyGILState_Release. + + When the function returns, the current thread will hold the GIL. + + Failure is a fatal error. +*/ +PyAPI_FUNC(PyGILState_STATE) PyGILState_Ensure(void); + +/* Release any resources previously acquired. After this call, Python's + state will be the same as it was prior to the corresponding + PyGILState_Ensure() call (but generally this state will be unknown to + the caller, hence the use of the GILState API.) + + Every call to PyGILState_Ensure must be matched by a call to + PyGILState_Release on the same thread. +*/ +PyAPI_FUNC(void) PyGILState_Release(PyGILState_STATE); + +/* Helper/diagnostic function - get the current thread state for + this thread. May return NULL if no GILState API has been used + on the current thread. Note the main thread always has such a + thread-state, even if no auto-thread-state call has been made + on the main thread. +*/ +PyAPI_FUNC(PyThreadState *) PyGILState_GetThisThreadState(void); + +/* The implementation of sys._current_frames() Returns a dict mapping + thread id to that thread's current frame. +*/ +PyAPI_FUNC(PyObject *) _PyThread_CurrentFrames(void); + +/* Routines for advanced debuggers, requested by David Beazley. + Don't use unless you know what you are doing! */ +PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Head(void); +PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Next(PyInterpreterState *); +PyAPI_FUNC(PyThreadState *) PyInterpreterState_ThreadHead(PyInterpreterState *); +PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *); + +typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_); + +/* hook for PyEval_GetFrame(), requested for Psyco */ +PyAPI_DATA(PyThreadFrameGetter) _PyThreadState_GetFrame; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYSTATE_H */ diff --git a/sys/src/cmd/python/Include/pystrtod.h b/sys/src/cmd/python/Include/pystrtod.h new file mode 100644 index 000000000..c6921da1a --- /dev/null +++ b/sys/src/cmd/python/Include/pystrtod.h @@ -0,0 +1,18 @@ +#ifndef Py_STRTOD_H +#define Py_STRTOD_H + +#ifdef __cplusplus +extern "C" { +#endif + + +PyAPI_FUNC(double) PyOS_ascii_strtod(const char *str, char **ptr); +PyAPI_FUNC(double) PyOS_ascii_atof(const char *str); +PyAPI_FUNC(char *) PyOS_ascii_formatd(char *buffer, size_t buf_len, const char *format, double d); + + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_STRTOD_H */ diff --git a/sys/src/cmd/python/Include/pythonrun.h b/sys/src/cmd/python/Include/pythonrun.h new file mode 100644 index 000000000..cfc40e3a2 --- /dev/null +++ b/sys/src/cmd/python/Include/pythonrun.h @@ -0,0 +1,171 @@ + +/* Interfaces to parse and execute pieces of python code */ + +#ifndef Py_PYTHONRUN_H +#define Py_PYTHONRUN_H +#ifdef __cplusplus +extern "C" { +#endif + +#define PyCF_MASK (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT | \ + CO_FUTURE_WITH_STATEMENT) +#define PyCF_MASK_OBSOLETE (CO_NESTED) +#define PyCF_SOURCE_IS_UTF8 0x0100 +#define PyCF_DONT_IMPLY_DEDENT 0x0200 +#define PyCF_ONLY_AST 0x0400 + +typedef struct { + int cf_flags; /* bitmask of CO_xxx flags relevant to future */ +} PyCompilerFlags; + +PyAPI_FUNC(void) Py_SetProgramName(char *); +PyAPI_FUNC(char *) Py_GetProgramName(void); + +PyAPI_FUNC(void) Py_SetPythonHome(char *); +PyAPI_FUNC(char *) Py_GetPythonHome(void); + +PyAPI_FUNC(void) Py_Initialize(void); +PyAPI_FUNC(void) Py_InitializeEx(int); +PyAPI_FUNC(void) Py_Finalize(void); +PyAPI_FUNC(int) Py_IsInitialized(void); +PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void); +PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *); + +PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *); +PyAPI_FUNC(int) PyRun_AnyFileExFlags(FILE *, const char *, int, PyCompilerFlags *); +PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *); +PyAPI_FUNC(int) PyRun_SimpleFileExFlags(FILE *, const char *, int, PyCompilerFlags *); +PyAPI_FUNC(int) PyRun_InteractiveOneFlags(FILE *, const char *, PyCompilerFlags *); +PyAPI_FUNC(int) PyRun_InteractiveLoopFlags(FILE *, const char *, PyCompilerFlags *); + +PyAPI_FUNC(struct _mod *) PyParser_ASTFromString(const char *, const char *, + int, PyCompilerFlags *flags, + PyArena *); +PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile(FILE *, const char *, int, + char *, char *, + PyCompilerFlags *, int *, + PyArena *); +#define PyParser_SimpleParseString(S, B) \ + PyParser_SimpleParseStringFlags(S, B, 0) +#define PyParser_SimpleParseFile(FP, S, B) \ + PyParser_SimpleParseFileFlags(FP, S, B, 0) +PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlags(const char *, int, + int); +PyAPI_FUNC(struct _node *) PyParser_SimpleParseFileFlags(FILE *, const char *, + int, int); + +PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *, + PyObject *, PyCompilerFlags *); + +PyAPI_FUNC(PyObject *) PyRun_FileExFlags(FILE *, const char *, int, + PyObject *, PyObject *, int, + PyCompilerFlags *); + +#define Py_CompileString(str, p, s) Py_CompileStringFlags(str, p, s, NULL) +PyAPI_FUNC(PyObject *) Py_CompileStringFlags(const char *, const char *, int, + PyCompilerFlags *); +PyAPI_FUNC(struct symtable *) Py_SymtableString(const char *, const char *, int); + +PyAPI_FUNC(void) PyErr_Print(void); +PyAPI_FUNC(void) PyErr_PrintEx(int); +PyAPI_FUNC(void) PyErr_Display(PyObject *, PyObject *, PyObject *); + +PyAPI_FUNC(int) Py_AtExit(void (*func)(void)); + +PyAPI_FUNC(void) Py_Exit(int); + +PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *); + +/* Bootstrap */ +PyAPI_FUNC(int) Py_Main(int argc, char **argv); + +/* Use macros for a bunch of old variants */ +#define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL) +#define PyRun_AnyFile(fp, name) PyRun_AnyFileExFlags(fp, name, 0, NULL) +#define PyRun_AnyFileEx(fp, name, closeit) \ + PyRun_AnyFileExFlags(fp, name, closeit, NULL) +#define PyRun_AnyFileFlags(fp, name, flags) \ + PyRun_AnyFileExFlags(fp, name, 0, flags) +#define PyRun_SimpleString(s) PyRun_SimpleStringFlags(s, NULL) +#define PyRun_SimpleFile(f, p) PyRun_SimpleFileExFlags(f, p, 0, NULL) +#define PyRun_SimpleFileEx(f, p, c) PyRun_SimpleFileExFlags(f, p, c, NULL) +#define PyRun_InteractiveOne(f, p) PyRun_InteractiveOneFlags(f, p, NULL) +#define PyRun_InteractiveLoop(f, p) PyRun_InteractiveLoopFlags(f, p, NULL) +#define PyRun_File(fp, p, s, g, l) \ + PyRun_FileExFlags(fp, p, s, g, l, 0, NULL) +#define PyRun_FileEx(fp, p, s, g, l, c) \ + PyRun_FileExFlags(fp, p, s, g, l, c, NULL) +#define PyRun_FileFlags(fp, p, s, g, l, flags) \ + PyRun_FileExFlags(fp, p, s, g, l, 0, flags) + +/* In getpath.c */ +PyAPI_FUNC(char *) Py_GetProgramFullPath(void); +PyAPI_FUNC(char *) Py_GetPrefix(void); +PyAPI_FUNC(char *) Py_GetExecPrefix(void); +PyAPI_FUNC(char *) Py_GetPath(void); + +/* In their own files */ +PyAPI_FUNC(const char *) Py_GetVersion(void); +PyAPI_FUNC(const char *) Py_GetPlatform(void); +PyAPI_FUNC(const char *) Py_GetCopyright(void); +PyAPI_FUNC(const char *) Py_GetCompiler(void); +PyAPI_FUNC(const char *) Py_GetBuildInfo(void); +PyAPI_FUNC(const char *) _Py_svnversion(void); +PyAPI_FUNC(const char *) Py_SubversionRevision(void); +PyAPI_FUNC(const char *) Py_SubversionShortBranch(void); + +/* Internal -- various one-time initializations */ +PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void); +PyAPI_FUNC(PyObject *) _PySys_Init(void); +PyAPI_FUNC(void) _PyImport_Init(void); +PyAPI_FUNC(void) _PyExc_Init(void); +PyAPI_FUNC(void) _PyImportHooks_Init(void); +PyAPI_FUNC(int) _PyFrame_Init(void); +PyAPI_FUNC(int) _PyInt_Init(void); +PyAPI_FUNC(void) _PyFloat_Init(void); + +/* Various internal finalizers */ +PyAPI_FUNC(void) _PyExc_Fini(void); +PyAPI_FUNC(void) _PyImport_Fini(void); +PyAPI_FUNC(void) PyMethod_Fini(void); +PyAPI_FUNC(void) PyFrame_Fini(void); +PyAPI_FUNC(void) PyCFunction_Fini(void); +PyAPI_FUNC(void) PyTuple_Fini(void); +PyAPI_FUNC(void) PyList_Fini(void); +PyAPI_FUNC(void) PySet_Fini(void); +PyAPI_FUNC(void) PyString_Fini(void); +PyAPI_FUNC(void) PyInt_Fini(void); +PyAPI_FUNC(void) PyFloat_Fini(void); +PyAPI_FUNC(void) PyOS_FiniInterrupts(void); + +/* Stuff with no proper home (yet) */ +PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *); +PyAPI_DATA(int) (*PyOS_InputHook)(void); +PyAPI_DATA(char) *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *); +PyAPI_DATA(PyThreadState*) _PyOS_ReadlineTState; + +/* Stack size, in "pointers" (so we get extra safety margins + on 64-bit platforms). On a 32-bit platform, this translates + to a 8k margin. */ +#define PYOS_STACK_MARGIN 2048 + +#if defined(WIN32) && !defined(MS_WIN64) && defined(_MSC_VER) +/* Enable stack checking under Microsoft C */ +#define USE_STACKCHECK +#endif + +#ifdef USE_STACKCHECK +/* Check that we aren't overflowing our stack */ +PyAPI_FUNC(int) PyOS_CheckStack(void); +#endif + +/* Signals */ +typedef void (*PyOS_sighandler_t)(int); +PyAPI_FUNC(PyOS_sighandler_t) PyOS_getsig(int); +PyAPI_FUNC(PyOS_sighandler_t) PyOS_setsig(int, PyOS_sighandler_t); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PYTHONRUN_H */ diff --git a/sys/src/cmd/python/Include/pythread.h b/sys/src/cmd/python/Include/pythread.h new file mode 100644 index 000000000..f26db160b --- /dev/null +++ b/sys/src/cmd/python/Include/pythread.h @@ -0,0 +1,47 @@ + +#ifndef Py_PYTHREAD_H +#define Py_PYTHREAD_H + +#define NO_EXIT_PROG /* don't define PyThread_exit_prog() */ + /* (the result is no use of signals on SGI) */ + +typedef void *PyThread_type_lock; +typedef void *PyThread_type_sema; + +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(void) PyThread_init_thread(void); +PyAPI_FUNC(long) PyThread_start_new_thread(void (*)(void *), void *); +PyAPI_FUNC(void) PyThread_exit_thread(void); +PyAPI_FUNC(void) PyThread__PyThread_exit_thread(void); +PyAPI_FUNC(long) PyThread_get_thread_ident(void); + +PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void); +PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock); +PyAPI_FUNC(int) PyThread_acquire_lock(PyThread_type_lock, int); +#define WAIT_LOCK 1 +#define NOWAIT_LOCK 0 +PyAPI_FUNC(void) PyThread_release_lock(PyThread_type_lock); + +PyAPI_FUNC(size_t) PyThread_get_stacksize(void); +PyAPI_FUNC(int) PyThread_set_stacksize(size_t); + +#ifndef NO_EXIT_PROG +PyAPI_FUNC(void) PyThread_exit_prog(int); +PyAPI_FUNC(void) PyThread__PyThread_exit_prog(int); +#endif + +/* Thread Local Storage (TLS) API */ +PyAPI_FUNC(int) PyThread_create_key(void); +PyAPI_FUNC(void) PyThread_delete_key(int); +PyAPI_FUNC(int) PyThread_set_key_value(int, void *); +PyAPI_FUNC(void *) PyThread_get_key_value(int); +PyAPI_FUNC(void) PyThread_delete_key_value(int key); + +#ifdef __cplusplus +} +#endif + +#endif /* !Py_PYTHREAD_H */ diff --git a/sys/src/cmd/python/Include/rangeobject.h b/sys/src/cmd/python/Include/rangeobject.h new file mode 100644 index 000000000..359bcb69f --- /dev/null +++ b/sys/src/cmd/python/Include/rangeobject.h @@ -0,0 +1,28 @@ + +/* Range object interface */ + +#ifndef Py_RANGEOBJECT_H +#define Py_RANGEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* This is about the type 'xrange', not the built-in function range(), which + returns regular lists. */ + +/* +A range object represents an integer range. This is an immutable object; +a range cannot change its value after creation. + +Range objects behave like the corresponding tuple objects except that +they are represented by a start, stop, and step datamembers. +*/ + +PyAPI_DATA(PyTypeObject) PyRange_Type; + +#define PyRange_Check(op) ((op)->ob_type == &PyRange_Type) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_RANGEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/setobject.h b/sys/src/cmd/python/Include/setobject.h new file mode 100644 index 000000000..750a2a8a2 --- /dev/null +++ b/sys/src/cmd/python/Include/setobject.h @@ -0,0 +1,93 @@ +/* Set object interface */ + +#ifndef Py_SETOBJECT_H +#define Py_SETOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* +There are three kinds of slots in the table: + +1. Unused: key == NULL +2. Active: key != NULL and key != dummy +3. Dummy: key == dummy + +Note: .pop() abuses the hash field of an Unused or Dummy slot to +hold a search finger. The hash field of Unused or Dummy slots has +no meaning otherwise. +*/ + +#define PySet_MINSIZE 8 + +typedef struct { + long hash; /* cached hash code for the entry key */ + PyObject *key; +} setentry; + + +/* +This data structure is shared by set and frozenset objects. +*/ + +typedef struct _setobject PySetObject; +struct _setobject { + PyObject_HEAD + + Py_ssize_t fill; /* # Active + # Dummy */ + Py_ssize_t used; /* # Active */ + + /* The table contains mask + 1 slots, and that's a power of 2. + * We store the mask instead of the size because the mask is more + * frequently needed. + */ + Py_ssize_t mask; + + /* table points to smalltable for small tables, else to + * additional malloc'ed memory. table is never NULL! This rule + * saves repeated runtime null-tests. + */ + setentry *table; + setentry *(*lookup)(PySetObject *so, PyObject *key, long hash); + setentry smalltable[PySet_MINSIZE]; + + long hash; /* only used by frozenset objects */ + PyObject *weakreflist; /* List of weak references */ +}; + +PyAPI_DATA(PyTypeObject) PySet_Type; +PyAPI_DATA(PyTypeObject) PyFrozenSet_Type; + +/* Invariants for frozensets: + * data is immutable. + * hash is the hash of the frozenset or -1 if not computed yet. + * Invariants for sets: + * hash is -1 + */ + +#define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type) +#define PyAnySet_CheckExact(ob) \ + ((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type) +#define PyAnySet_Check(ob) \ + ((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type || \ + PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \ + PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type)) + +PyAPI_FUNC(PyObject *) PySet_New(PyObject *); +PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *); +PyAPI_FUNC(Py_ssize_t) PySet_Size(PyObject *anyset); +#define PySet_GET_SIZE(so) (((PySetObject *)(so))->used) +PyAPI_FUNC(int) PySet_Clear(PyObject *set); +PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); +PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); +PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); +PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key); +PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash); +PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); +PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SETOBJECT_H */ diff --git a/sys/src/cmd/python/Include/sliceobject.h b/sys/src/cmd/python/Include/sliceobject.h new file mode 100644 index 000000000..dbc34b2ae --- /dev/null +++ b/sys/src/cmd/python/Include/sliceobject.h @@ -0,0 +1,43 @@ +#ifndef Py_SLICEOBJECT_H +#define Py_SLICEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* The unique ellipsis object "..." */ + +PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */ + +#define Py_Ellipsis (&_Py_EllipsisObject) + +/* Slice object interface */ + +/* + +A slice object containing start, stop, and step data members (the +names are from range). After much talk with Guido, it was decided to +let these be any arbitrary python type. Py_None stands for omitted values. +*/ + +typedef struct { + PyObject_HEAD + PyObject *start, *stop, *step; /* not NULL */ +} PySliceObject; + +PyAPI_DATA(PyTypeObject) PySlice_Type; + +#define PySlice_Check(op) ((op)->ob_type == &PySlice_Type) + +PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop, + PyObject* step); +PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop); +PyAPI_FUNC(int) PySlice_GetIndices(PySliceObject *r, Py_ssize_t length, + Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); +PyAPI_FUNC(int) PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length, + Py_ssize_t *start, Py_ssize_t *stop, + Py_ssize_t *step, Py_ssize_t *slicelength); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SLICEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/stringobject.h b/sys/src/cmd/python/Include/stringobject.h new file mode 100644 index 000000000..5f8a6f02a --- /dev/null +++ b/sys/src/cmd/python/Include/stringobject.h @@ -0,0 +1,183 @@ + +/* String object interface */ + +#ifndef Py_STRINGOBJECT_H +#define Py_STRINGOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdarg.h> + +/* +Type PyStringObject represents a character string. An extra zero byte is +reserved at the end to ensure it is zero-terminated, but a size is +present so strings with null bytes in them can be represented. This +is an immutable object type. + +There are functions to create new string objects, to test +an object for string-ness, and to get the +string value. The latter function returns a null pointer +if the object is not of the proper type. +There is a variant that takes an explicit size as well as a +variant that assumes a zero-terminated string. Note that none of the +functions should be applied to nil objects. +*/ + +/* Caching the hash (ob_shash) saves recalculation of a string's hash value. + Interning strings (ob_sstate) tries to ensure that only one string + object with a given value exists, so equality tests can be one pointer + comparison. This is generally restricted to strings that "look like" + Python identifiers, although the intern() builtin can be used to force + interning of any string. + Together, these sped the interpreter by up to 20%. */ + +typedef struct { + PyObject_VAR_HEAD + long ob_shash; + int ob_sstate; + char ob_sval[1]; + + /* Invariants: + * ob_sval contains space for 'ob_size+1' elements. + * ob_sval[ob_size] == 0. + * ob_shash is the hash of the string or -1 if not computed yet. + * ob_sstate != 0 iff the string object is in stringobject.c's + * 'interned' dictionary; in this case the two references + * from 'interned' to this object are *not counted* in ob_refcnt. + */ +} PyStringObject; + +#define SSTATE_NOT_INTERNED 0 +#define SSTATE_INTERNED_MORTAL 1 +#define SSTATE_INTERNED_IMMORTAL 2 + +PyAPI_DATA(PyTypeObject) PyBaseString_Type; +PyAPI_DATA(PyTypeObject) PyString_Type; + +#define PyString_Check(op) PyObject_TypeCheck(op, &PyString_Type) +#define PyString_CheckExact(op) ((op)->ob_type == &PyString_Type) + +PyAPI_FUNC(PyObject *) PyString_FromStringAndSize(const char *, Py_ssize_t); +PyAPI_FUNC(PyObject *) PyString_FromString(const char *); +PyAPI_FUNC(PyObject *) PyString_FromFormatV(const char*, va_list) + Py_GCC_ATTRIBUTE((format(printf, 1, 0))); +PyAPI_FUNC(PyObject *) PyString_FromFormat(const char*, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); +PyAPI_FUNC(Py_ssize_t) PyString_Size(PyObject *); +PyAPI_FUNC(char *) PyString_AsString(PyObject *); +PyAPI_FUNC(PyObject *) PyString_Repr(PyObject *, int); +PyAPI_FUNC(void) PyString_Concat(PyObject **, PyObject *); +PyAPI_FUNC(void) PyString_ConcatAndDel(PyObject **, PyObject *); +PyAPI_FUNC(int) _PyString_Resize(PyObject **, Py_ssize_t); +PyAPI_FUNC(int) _PyString_Eq(PyObject *, PyObject*); +PyAPI_FUNC(PyObject *) PyString_Format(PyObject *, PyObject *); +PyAPI_FUNC(PyObject *) _PyString_FormatLong(PyObject*, int, int, + int, char**, int*); +PyAPI_FUNC(PyObject *) PyString_DecodeEscape(const char *, Py_ssize_t, + const char *, Py_ssize_t, + const char *); + +PyAPI_FUNC(void) PyString_InternInPlace(PyObject **); +PyAPI_FUNC(void) PyString_InternImmortal(PyObject **); +PyAPI_FUNC(PyObject *) PyString_InternFromString(const char *); +PyAPI_FUNC(void) _Py_ReleaseInternedStrings(void); + +/* Use only if you know it's a string */ +#define PyString_CHECK_INTERNED(op) (((PyStringObject *)(op))->ob_sstate) + +/* Macro, trading safety for speed */ +#define PyString_AS_STRING(op) (((PyStringObject *)(op))->ob_sval) +#define PyString_GET_SIZE(op) (((PyStringObject *)(op))->ob_size) + +/* _PyString_Join(sep, x) is like sep.join(x). sep must be PyStringObject*, + x must be an iterable object. */ +PyAPI_FUNC(PyObject *) _PyString_Join(PyObject *sep, PyObject *x); + +/* --- Generic Codecs ----------------------------------------------------- */ + +/* Create an object by decoding the encoded string s of the + given size. */ + +PyAPI_FUNC(PyObject*) PyString_Decode( + const char *s, /* encoded string */ + Py_ssize_t size, /* size of buffer */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a char buffer of the given size and returns a + Python object. */ + +PyAPI_FUNC(PyObject*) PyString_Encode( + const char *s, /* string char buffer */ + Py_ssize_t size, /* number of chars to encode */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a string object and returns the result as Python + object. */ + +PyAPI_FUNC(PyObject*) PyString_AsEncodedObject( + PyObject *str, /* string object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a string object and returns the result as Python string + object. + + If the codec returns an Unicode object, the object is converted + back to a string using the default encoding. + + DEPRECATED - use PyString_AsEncodedObject() instead. */ + +PyAPI_FUNC(PyObject*) PyString_AsEncodedString( + PyObject *str, /* string object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Decodes a string object and returns the result as Python + object. */ + +PyAPI_FUNC(PyObject*) PyString_AsDecodedObject( + PyObject *str, /* string object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Decodes a string object and returns the result as Python string + object. + + If the codec returns an Unicode object, the object is converted + back to a string using the default encoding. + + DEPRECATED - use PyString_AsDecodedObject() instead. */ + +PyAPI_FUNC(PyObject*) PyString_AsDecodedString( + PyObject *str, /* string object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Provides access to the internal data buffer and size of a string + object or the default encoded version of an Unicode object. Passing + NULL as *len parameter will force the string buffer to be + 0-terminated (passing a string with embedded NULL characters will + cause an exception). */ + +PyAPI_FUNC(int) PyString_AsStringAndSize( + register PyObject *obj, /* string or Unicode object */ + register char **s, /* pointer to buffer variable */ + register Py_ssize_t *len /* pointer to length variable or NULL + (only possible for 0-terminated + strings) */ + ); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_STRINGOBJECT_H */ diff --git a/sys/src/cmd/python/Include/structmember.h b/sys/src/cmd/python/Include/structmember.h new file mode 100644 index 000000000..e761f6d96 --- /dev/null +++ b/sys/src/cmd/python/Include/structmember.h @@ -0,0 +1,93 @@ +#ifndef Py_STRUCTMEMBER_H +#define Py_STRUCTMEMBER_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Interface to map C struct members to Python object attributes */ + +#include <stddef.h> /* For offsetof */ + +/* The offsetof() macro calculates the offset of a structure member + in its structure. Unfortunately this cannot be written down + portably, hence it is provided by a Standard C header file. + For pre-Standard C compilers, here is a version that usually works + (but watch out!): */ + +#ifndef offsetof +#define offsetof(type, member) ( (int) & ((type*)0) -> member ) +#endif + +/* An array of memberlist structures defines the name, type and offset + of selected members of a C structure. These can be read by + PyMember_Get() and set by PyMember_Set() (except if their READONLY flag + is set). The array must be terminated with an entry whose name + pointer is NULL. */ + +struct memberlist { + /* Obsolete version, for binary backwards compatibility */ + char *name; + int type; + int offset; + int flags; +}; + +typedef struct PyMemberDef { + /* Current version, use this */ + char *name; + int type; + Py_ssize_t offset; + int flags; + char *doc; +} PyMemberDef; + +/* Types */ +#define T_SHORT 0 +#define T_INT 1 +#define T_LONG 2 +#define T_FLOAT 3 +#define T_DOUBLE 4 +#define T_STRING 5 +#define T_OBJECT 6 +/* XXX the ordering here is weird for binary compatibility */ +#define T_CHAR 7 /* 1-character string */ +#define T_BYTE 8 /* 8-bit signed int */ +/* unsigned variants: */ +#define T_UBYTE 9 +#define T_USHORT 10 +#define T_UINT 11 +#define T_ULONG 12 + +/* Added by Jack: strings contained in the structure */ +#define T_STRING_INPLACE 13 + +#define T_OBJECT_EX 16 /* Like T_OBJECT, but raises AttributeError + when the value is NULL, instead of + converting to None. */ +#ifdef HAVE_LONG_LONG +#define T_LONGLONG 17 +#define T_ULONGLONG 18 +#endif /* HAVE_LONG_LONG */ + +/* Flags */ +#define READONLY 1 +#define RO READONLY /* Shorthand */ +#define READ_RESTRICTED 2 +#define WRITE_RESTRICTED 4 +#define RESTRICTED (READ_RESTRICTED | WRITE_RESTRICTED) + + +/* Obsolete API, for binary backwards compatibility */ +PyAPI_FUNC(PyObject *) PyMember_Get(const char *, struct memberlist *, const char *); +PyAPI_FUNC(int) PyMember_Set(char *, struct memberlist *, const char *, PyObject *); + +/* Current API, use this */ +PyAPI_FUNC(PyObject *) PyMember_GetOne(const char *, struct PyMemberDef *); +PyAPI_FUNC(int) PyMember_SetOne(char *, struct PyMemberDef *, PyObject *); + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_STRUCTMEMBER_H */ diff --git a/sys/src/cmd/python/Include/structseq.h b/sys/src/cmd/python/Include/structseq.h new file mode 100644 index 000000000..e662916fe --- /dev/null +++ b/sys/src/cmd/python/Include/structseq.h @@ -0,0 +1,41 @@ + +/* Tuple object interface */ + +#ifndef Py_STRUCTSEQ_H +#define Py_STRUCTSEQ_H +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct PyStructSequence_Field { + char *name; + char *doc; +} PyStructSequence_Field; + +typedef struct PyStructSequence_Desc { + char *name; + char *doc; + struct PyStructSequence_Field *fields; + int n_in_sequence; +} PyStructSequence_Desc; + +extern char* PyStructSequence_UnnamedField; + +PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type, + PyStructSequence_Desc *desc); + +PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); + +typedef struct { + PyObject_VAR_HEAD + PyObject *ob_item[1]; +} PyStructSequence; + +/* Macro, *only* to be used to fill in brand new objects */ +#define PyStructSequence_SET_ITEM(op, i, v) \ + (((PyStructSequence *)(op))->ob_item[i] = v) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_STRUCTSEQ_H */ diff --git a/sys/src/cmd/python/Include/symtable.h b/sys/src/cmd/python/Include/symtable.h new file mode 100644 index 000000000..1e5996dc6 --- /dev/null +++ b/sys/src/cmd/python/Include/symtable.h @@ -0,0 +1,103 @@ +#ifndef Py_SYMTABLE_H +#define Py_SYMTABLE_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum _block_type { FunctionBlock, ClassBlock, ModuleBlock } + _Py_block_ty; + +struct _symtable_entry; + +struct symtable { + const char *st_filename; /* name of file being compiled */ + struct _symtable_entry *st_cur; /* current symbol table entry */ + struct _symtable_entry *st_top; /* module entry */ + PyObject *st_symbols; /* dictionary of symbol table entries */ + PyObject *st_stack; /* stack of namespace info */ + PyObject *st_global; /* borrowed ref to MODULE in st_symbols */ + int st_nblocks; /* number of blocks */ + PyObject *st_private; /* name of current class or NULL */ + int st_tmpname; /* temporary name counter */ + PyFutureFeatures *st_future; /* module's future features */ +}; + +typedef struct _symtable_entry { + PyObject_HEAD + PyObject *ste_id; /* int: key in st_symbols */ + PyObject *ste_symbols; /* dict: name to flags */ + PyObject *ste_name; /* string: name of block */ + PyObject *ste_varnames; /* list of variable names */ + PyObject *ste_children; /* list of child ids */ + _Py_block_ty ste_type; /* module, class, or function */ + int ste_unoptimized; /* false if namespace is optimized */ + unsigned ste_nested : 1; /* true if block is nested */ + unsigned ste_free : 1; /* true if block has free variables */ + unsigned ste_child_free : 1; /* true if a child block has free vars, + including free refs to globals */ + unsigned ste_generator : 1; /* true if namespace is a generator */ + unsigned ste_varargs : 1; /* true if block has varargs */ + unsigned ste_varkeywords : 1; /* true if block has varkeywords */ + unsigned ste_returns_value : 1; /* true if namespace uses return with + an argument */ + int ste_lineno; /* first line of block */ + int ste_opt_lineno; /* lineno of last exec or import * */ + int ste_tmpname; /* counter for listcomp temp vars */ + struct symtable *ste_table; +} PySTEntryObject; + +PyAPI_DATA(PyTypeObject) PySTEntry_Type; + +#define PySTEntry_Check(op) ((op)->ob_type == &PySTEntry_Type) + +PyAPI_FUNC(int) PyST_GetScope(PySTEntryObject *, PyObject *); + +PyAPI_FUNC(struct symtable *) PySymtable_Build(mod_ty, const char *, + PyFutureFeatures *); +PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *); + +PyAPI_FUNC(void) PySymtable_Free(struct symtable *); + +/* Flags for def-use information */ + +#define DEF_GLOBAL 1 /* global stmt */ +#define DEF_LOCAL 2 /* assignment in code block */ +#define DEF_PARAM 2<<1 /* formal parameter */ +#define USE 2<<2 /* name is used */ +#define DEF_STAR 2<<3 /* parameter is star arg */ +#define DEF_DOUBLESTAR 2<<4 /* parameter is star-star arg */ +#define DEF_INTUPLE 2<<5 /* name defined in tuple in parameters */ +#define DEF_FREE 2<<6 /* name used but not defined in nested block */ +#define DEF_FREE_GLOBAL 2<<7 /* free variable is actually implicit global */ +#define DEF_FREE_CLASS 2<<8 /* free variable from class's method */ +#define DEF_IMPORT 2<<9 /* assignment occurred via import */ + +#define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT) + +/* GLOBAL_EXPLICIT and GLOBAL_IMPLICIT are used internally by the symbol + table. GLOBAL is returned from PyST_GetScope() for either of them. + It is stored in ste_symbols at bits 12-14. +*/ +#define SCOPE_OFF 11 +#define SCOPE_MASK 7 + +#define LOCAL 1 +#define GLOBAL_EXPLICIT 2 +#define GLOBAL_IMPLICIT 3 +#define FREE 4 +#define CELL 5 + +/* The following three names are used for the ste_unoptimized bit field */ +#define OPT_IMPORT_STAR 1 +#define OPT_EXEC 2 +#define OPT_BARE_EXEC 4 +#define OPT_TOPLEVEL 8 /* top-level names, including eval and exec */ + +#define GENERATOR 1 +#define GENERATOR_EXPRESSION 2 + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SYMTABLE_H */ diff --git a/sys/src/cmd/python/Include/sysmodule.h b/sys/src/cmd/python/Include/sysmodule.h new file mode 100644 index 000000000..1c9b187f3 --- /dev/null +++ b/sys/src/cmd/python/Include/sysmodule.h @@ -0,0 +1,30 @@ + +/* System module interface */ + +#ifndef Py_SYSMODULE_H +#define Py_SYSMODULE_H +#ifdef __cplusplus +extern "C" { +#endif + +PyAPI_FUNC(PyObject *) PySys_GetObject(char *); +PyAPI_FUNC(int) PySys_SetObject(char *, PyObject *); +PyAPI_FUNC(FILE *) PySys_GetFile(char *, FILE *); +PyAPI_FUNC(void) PySys_SetArgv(int, char **); +PyAPI_FUNC(void) PySys_SetPath(char *); + +PyAPI_FUNC(void) PySys_WriteStdout(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); +PyAPI_FUNC(void) PySys_WriteStderr(const char *format, ...) + Py_GCC_ATTRIBUTE((format(printf, 1, 2))); + +PyAPI_DATA(PyObject *) _PySys_TraceFunc, *_PySys_ProfileFunc; +PyAPI_DATA(int) _PySys_CheckInterval; + +PyAPI_FUNC(void) PySys_ResetWarnOptions(void); +PyAPI_FUNC(void) PySys_AddWarnOption(char *); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_SYSMODULE_H */ diff --git a/sys/src/cmd/python/Include/timefuncs.h b/sys/src/cmd/python/Include/timefuncs.h new file mode 100644 index 000000000..553142dba --- /dev/null +++ b/sys/src/cmd/python/Include/timefuncs.h @@ -0,0 +1,23 @@ +/* timefuncs.h + */ + +/* Utility function related to timemodule.c. */ + +#ifndef TIMEFUNCS_H +#define TIMEFUNCS_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Cast double x to time_t, but raise ValueError if x is too large + * to fit in a time_t. ValueError is set on return iff the return + * value is (time_t)-1 and PyErr_Occurred(). + */ +PyAPI_FUNC(time_t) _PyTime_DoubleToTimet(double x); + + +#ifdef __cplusplus +} +#endif +#endif /* TIMEFUNCS_H */ diff --git a/sys/src/cmd/python/Include/token.h b/sys/src/cmd/python/Include/token.h new file mode 100644 index 000000000..4250000d1 --- /dev/null +++ b/sys/src/cmd/python/Include/token.h @@ -0,0 +1,83 @@ + +/* Token types */ + +#ifndef Py_TOKEN_H +#define Py_TOKEN_H +#ifdef __cplusplus +extern "C" { +#endif + +#define ENDMARKER 0 +#define NAME 1 +#define NUMBER 2 +#define STRING 3 +#define NEWLINE 4 +#define INDENT 5 +#define DEDENT 6 +#define LPAR 7 +#define RPAR 8 +#define LSQB 9 +#define RSQB 10 +#define COLON 11 +#define COMMA 12 +#define SEMI 13 +#define PLUS 14 +#define MINUS 15 +#define STAR 16 +#define SLASH 17 +#define VBAR 18 +#define AMPER 19 +#define LESS 20 +#define GREATER 21 +#define EQUAL 22 +#define DOT 23 +#define PERCENT 24 +#define BACKQUOTE 25 +#define LBRACE 26 +#define RBRACE 27 +#define EQEQUAL 28 +#define NOTEQUAL 29 +#define LESSEQUAL 30 +#define GREATEREQUAL 31 +#define TILDE 32 +#define CIRCUMFLEX 33 +#define LEFTSHIFT 34 +#define RIGHTSHIFT 35 +#define DOUBLESTAR 36 +#define PLUSEQUAL 37 +#define MINEQUAL 38 +#define STAREQUAL 39 +#define SLASHEQUAL 40 +#define PERCENTEQUAL 41 +#define AMPEREQUAL 42 +#define VBAREQUAL 43 +#define CIRCUMFLEXEQUAL 44 +#define LEFTSHIFTEQUAL 45 +#define RIGHTSHIFTEQUAL 46 +#define DOUBLESTAREQUAL 47 +#define DOUBLESLASH 48 +#define DOUBLESLASHEQUAL 49 +#define AT 50 +/* Don't forget to update the table _PyParser_TokenNames in tokenizer.c! */ +#define OP 51 +#define ERRORTOKEN 52 +#define N_TOKENS 53 + +/* Special definitions for cooperation with parser */ + +#define NT_OFFSET 256 + +#define ISTERMINAL(x) ((x) < NT_OFFSET) +#define ISNONTERMINAL(x) ((x) >= NT_OFFSET) +#define ISEOF(x) ((x) == ENDMARKER) + + +PyAPI_DATA(char *) _PyParser_TokenNames[]; /* Token names */ +PyAPI_FUNC(int) PyToken_OneChar(int); +PyAPI_FUNC(int) PyToken_TwoChars(int, int); +PyAPI_FUNC(int) PyToken_ThreeChars(int, int, int); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TOKEN_H */ diff --git a/sys/src/cmd/python/Include/traceback.h b/sys/src/cmd/python/Include/traceback.h new file mode 100644 index 000000000..6501600c0 --- /dev/null +++ b/sys/src/cmd/python/Include/traceback.h @@ -0,0 +1,30 @@ + +#ifndef Py_TRACEBACK_H +#define Py_TRACEBACK_H +#ifdef __cplusplus +extern "C" { +#endif + +struct _frame; + +/* Traceback interface */ + +typedef struct _traceback { + PyObject_HEAD + struct _traceback *tb_next; + struct _frame *tb_frame; + int tb_lasti; + int tb_lineno; +} PyTracebackObject; + +PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *); +PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *); + +/* Reveal traceback type so we can typecheck traceback objects */ +PyAPI_DATA(PyTypeObject) PyTraceBack_Type; +#define PyTraceBack_Check(v) ((v)->ob_type == &PyTraceBack_Type) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TRACEBACK_H */ diff --git a/sys/src/cmd/python/Include/tupleobject.h b/sys/src/cmd/python/Include/tupleobject.h new file mode 100644 index 000000000..8c37cabdc --- /dev/null +++ b/sys/src/cmd/python/Include/tupleobject.h @@ -0,0 +1,57 @@ + +/* Tuple object interface */ + +#ifndef Py_TUPLEOBJECT_H +#define Py_TUPLEOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + +/* +Another generally useful object type is a tuple of object pointers. +For Python, this is an immutable type. C code can change the tuple items +(but not their number), and even use tuples are general-purpose arrays of +object references, but in general only brand new tuples should be mutated, +not ones that might already have been exposed to Python code. + +*** WARNING *** PyTuple_SetItem does not increment the new item's reference +count, but does decrement the reference count of the item it replaces, +if not nil. It does *decrement* the reference count if it is *not* +inserted in the tuple. Similarly, PyTuple_GetItem does not increment the +returned item's reference count. +*/ + +typedef struct { + PyObject_VAR_HEAD + PyObject *ob_item[1]; + + /* ob_item contains space for 'ob_size' elements. + * Items must normally not be NULL, except during construction when + * the tuple is not yet visible outside the function that builds it. + */ +} PyTupleObject; + +PyAPI_DATA(PyTypeObject) PyTuple_Type; + +#define PyTuple_Check(op) PyObject_TypeCheck(op, &PyTuple_Type) +#define PyTuple_CheckExact(op) ((op)->ob_type == &PyTuple_Type) + +PyAPI_FUNC(PyObject *) PyTuple_New(Py_ssize_t size); +PyAPI_FUNC(Py_ssize_t) PyTuple_Size(PyObject *); +PyAPI_FUNC(PyObject *) PyTuple_GetItem(PyObject *, Py_ssize_t); +PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *); +PyAPI_FUNC(PyObject *) PyTuple_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t); +PyAPI_FUNC(int) _PyTuple_Resize(PyObject **, Py_ssize_t); +PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...); + +/* Macro, trading safety for speed */ +#define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i]) +#define PyTuple_GET_SIZE(op) (((PyTupleObject *)(op))->ob_size) + +/* Macro, *only* to be used to fill in brand new tuples */ +#define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v) + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TUPLEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/ucnhash.h b/sys/src/cmd/python/Include/ucnhash.h new file mode 100644 index 000000000..6231c98b3 --- /dev/null +++ b/sys/src/cmd/python/Include/ucnhash.h @@ -0,0 +1,31 @@ +/* Unicode name database interface */ + +#ifndef Py_UCNHASH_H +#define Py_UCNHASH_H +#ifdef __cplusplus +extern "C" { +#endif + +/* revised ucnhash CAPI interface (exported through a PyCObject) */ + +typedef struct { + + /* Size of this struct */ + int size; + + /* Get name for a given character code. Returns non-zero if + success, zero if not. Does not set Python exceptions. + If self is NULL, data come from the default version of the database. + If it is not NULL, it should be a unicodedata.ucd_X_Y_Z object */ + int (*getname)(PyObject *self, Py_UCS4 code, char* buffer, int buflen); + + /* Get character code for a given name. Same error handling + as for getname. */ + int (*getcode)(PyObject *self, const char* name, int namelen, Py_UCS4* code); + +} _PyUnicode_Name_CAPI; + +#ifdef __cplusplus +} +#endif +#endif /* !Py_UCNHASH_H */ diff --git a/sys/src/cmd/python/Include/unicodeobject.h b/sys/src/cmd/python/Include/unicodeobject.h new file mode 100644 index 000000000..33aa18581 --- /dev/null +++ b/sys/src/cmd/python/Include/unicodeobject.h @@ -0,0 +1,1265 @@ +#ifndef Py_UNICODEOBJECT_H +#define Py_UNICODEOBJECT_H + +/* + +Unicode implementation based on original code by Fredrik Lundh, +modified by Marc-Andre Lemburg (mal@lemburg.com) according to the +Unicode Integration Proposal (see file Misc/unicode.txt). + +Copyright (c) Corporation for National Research Initiatives. + + + Original header: + -------------------------------------------------------------------- + + * Yet another Unicode string type for Python. This type supports the + * 16-bit Basic Multilingual Plane (BMP) only. + * + * Written by Fredrik Lundh, January 1999. + * + * Copyright (c) 1999 by Secret Labs AB. + * Copyright (c) 1999 by Fredrik Lundh. + * + * fredrik@pythonware.com + * http://www.pythonware.com + * + * -------------------------------------------------------------------- + * This Unicode String Type is + * + * Copyright (c) 1999 by Secret Labs AB + * Copyright (c) 1999 by Fredrik Lundh + * + * By obtaining, using, and/or copying this software and/or its + * associated documentation, you agree that you have read, understood, + * and will comply with the following terms and conditions: + * + * Permission to use, copy, modify, and distribute this software and its + * associated documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appears in all + * copies, and that both that copyright notice and this permission notice + * appear in supporting documentation, and that the name of Secret Labs + * AB or the author not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. + * + * SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO + * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * -------------------------------------------------------------------- */ + +#include <ctype.h> + +/* === Internal API ======================================================= */ + +/* --- Internal Unicode Format -------------------------------------------- */ + +#ifndef Py_USING_UNICODE + +#define PyUnicode_Check(op) 0 +#define PyUnicode_CheckExact(op) 0 + +#else + +/* FIXME: MvL's new implementation assumes that Py_UNICODE_SIZE is + properly set, but the default rules below doesn't set it. I'll + sort this out some other day -- fredrik@pythonware.com */ + +#ifndef Py_UNICODE_SIZE +#error Must define Py_UNICODE_SIZE +#endif + +/* Setting Py_UNICODE_WIDE enables UCS-4 storage. Otherwise, Unicode + strings are stored as UCS-2 (with limited support for UTF-16) */ + +#if Py_UNICODE_SIZE >= 4 +#define Py_UNICODE_WIDE +#endif + +/* Set these flags if the platform has "wchar.h", "wctype.h" and the + wchar_t type is a 16-bit unsigned type */ +/* #define HAVE_WCHAR_H */ +/* #define HAVE_USABLE_WCHAR_T */ + +/* Defaults for various platforms */ +#ifndef PY_UNICODE_TYPE + +/* Windows has a usable wchar_t type (unless we're using UCS-4) */ +# if defined(MS_WIN32) && Py_UNICODE_SIZE == 2 +# define HAVE_USABLE_WCHAR_T +# define PY_UNICODE_TYPE wchar_t +# endif + +# if defined(Py_UNICODE_WIDE) +# define PY_UNICODE_TYPE Py_UCS4 +# endif + +#endif + +/* If the compiler provides a wchar_t type we try to support it + through the interface functions PyUnicode_FromWideChar() and + PyUnicode_AsWideChar(). */ + +#ifdef HAVE_USABLE_WCHAR_T +# ifndef HAVE_WCHAR_H +# define HAVE_WCHAR_H +# endif +#endif + +#ifdef HAVE_WCHAR_H +/* Work around a cosmetic bug in BSDI 4.x wchar.h; thanks to Thomas Wouters */ +# ifdef _HAVE_BSDI +# include <time.h> +# endif +# include <wchar.h> +#endif + +/* + * Use this typedef when you need to represent a UTF-16 surrogate pair + * as single unsigned integer. + */ +#if SIZEOF_INT >= 4 +typedef unsigned int Py_UCS4; +#elif SIZEOF_LONG >= 4 +typedef unsigned long Py_UCS4; +#endif + +typedef PY_UNICODE_TYPE Py_UNICODE; + +/* --- UCS-2/UCS-4 Name Mangling ------------------------------------------ */ + +/* Unicode API names are mangled to assure that UCS-2 and UCS-4 builds + produce different external names and thus cause import errors in + case Python interpreters and extensions with mixed compiled in + Unicode width assumptions are combined. */ + +#ifndef Py_UNICODE_WIDE + +# define PyUnicode_AsASCIIString PyUnicodeUCS2_AsASCIIString +# define PyUnicode_AsCharmapString PyUnicodeUCS2_AsCharmapString +# define PyUnicode_AsEncodedObject PyUnicodeUCS2_AsEncodedObject +# define PyUnicode_AsEncodedString PyUnicodeUCS2_AsEncodedString +# define PyUnicode_AsLatin1String PyUnicodeUCS2_AsLatin1String +# define PyUnicode_AsRawUnicodeEscapeString PyUnicodeUCS2_AsRawUnicodeEscapeString +# define PyUnicode_AsUTF16String PyUnicodeUCS2_AsUTF16String +# define PyUnicode_AsUTF8String PyUnicodeUCS2_AsUTF8String +# define PyUnicode_AsUnicode PyUnicodeUCS2_AsUnicode +# define PyUnicode_AsUnicodeEscapeString PyUnicodeUCS2_AsUnicodeEscapeString +# define PyUnicode_AsWideChar PyUnicodeUCS2_AsWideChar +# define PyUnicode_Compare PyUnicodeUCS2_Compare +# define PyUnicode_Concat PyUnicodeUCS2_Concat +# define PyUnicode_Contains PyUnicodeUCS2_Contains +# define PyUnicode_Count PyUnicodeUCS2_Count +# define PyUnicode_Decode PyUnicodeUCS2_Decode +# define PyUnicode_DecodeASCII PyUnicodeUCS2_DecodeASCII +# define PyUnicode_DecodeCharmap PyUnicodeUCS2_DecodeCharmap +# define PyUnicode_DecodeLatin1 PyUnicodeUCS2_DecodeLatin1 +# define PyUnicode_DecodeRawUnicodeEscape PyUnicodeUCS2_DecodeRawUnicodeEscape +# define PyUnicode_DecodeUTF16 PyUnicodeUCS2_DecodeUTF16 +# define PyUnicode_DecodeUTF16Stateful PyUnicodeUCS2_DecodeUTF16Stateful +# define PyUnicode_DecodeUTF8 PyUnicodeUCS2_DecodeUTF8 +# define PyUnicode_DecodeUTF8Stateful PyUnicodeUCS2_DecodeUTF8Stateful +# define PyUnicode_DecodeUnicodeEscape PyUnicodeUCS2_DecodeUnicodeEscape +# define PyUnicode_Encode PyUnicodeUCS2_Encode +# define PyUnicode_EncodeASCII PyUnicodeUCS2_EncodeASCII +# define PyUnicode_EncodeCharmap PyUnicodeUCS2_EncodeCharmap +# define PyUnicode_EncodeDecimal PyUnicodeUCS2_EncodeDecimal +# define PyUnicode_EncodeLatin1 PyUnicodeUCS2_EncodeLatin1 +# define PyUnicode_EncodeRawUnicodeEscape PyUnicodeUCS2_EncodeRawUnicodeEscape +# define PyUnicode_EncodeUTF16 PyUnicodeUCS2_EncodeUTF16 +# define PyUnicode_EncodeUTF8 PyUnicodeUCS2_EncodeUTF8 +# define PyUnicode_EncodeUnicodeEscape PyUnicodeUCS2_EncodeUnicodeEscape +# define PyUnicode_Find PyUnicodeUCS2_Find +# define PyUnicode_Format PyUnicodeUCS2_Format +# define PyUnicode_FromEncodedObject PyUnicodeUCS2_FromEncodedObject +# define PyUnicode_FromObject PyUnicodeUCS2_FromObject +# define PyUnicode_FromOrdinal PyUnicodeUCS2_FromOrdinal +# define PyUnicode_FromUnicode PyUnicodeUCS2_FromUnicode +# define PyUnicode_FromWideChar PyUnicodeUCS2_FromWideChar +# define PyUnicode_GetDefaultEncoding PyUnicodeUCS2_GetDefaultEncoding +# define PyUnicode_GetMax PyUnicodeUCS2_GetMax +# define PyUnicode_GetSize PyUnicodeUCS2_GetSize +# define PyUnicode_Join PyUnicodeUCS2_Join +# define PyUnicode_Partition PyUnicodeUCS2_Partition +# define PyUnicode_RPartition PyUnicodeUCS2_RPartition +# define PyUnicode_RSplit PyUnicodeUCS2_RSplit +# define PyUnicode_Replace PyUnicodeUCS2_Replace +# define PyUnicode_Resize PyUnicodeUCS2_Resize +# define PyUnicode_RichCompare PyUnicodeUCS2_RichCompare +# define PyUnicode_SetDefaultEncoding PyUnicodeUCS2_SetDefaultEncoding +# define PyUnicode_Split PyUnicodeUCS2_Split +# define PyUnicode_Splitlines PyUnicodeUCS2_Splitlines +# define PyUnicode_Tailmatch PyUnicodeUCS2_Tailmatch +# define PyUnicode_Translate PyUnicodeUCS2_Translate +# define PyUnicode_TranslateCharmap PyUnicodeUCS2_TranslateCharmap +# define _PyUnicode_AsDefaultEncodedString _PyUnicodeUCS2_AsDefaultEncodedString +# define _PyUnicode_Fini _PyUnicodeUCS2_Fini +# define _PyUnicode_Init _PyUnicodeUCS2_Init +# define _PyUnicode_IsAlpha _PyUnicodeUCS2_IsAlpha +# define _PyUnicode_IsDecimalDigit _PyUnicodeUCS2_IsDecimalDigit +# define _PyUnicode_IsDigit _PyUnicodeUCS2_IsDigit +# define _PyUnicode_IsLinebreak _PyUnicodeUCS2_IsLinebreak +# define _PyUnicode_IsLowercase _PyUnicodeUCS2_IsLowercase +# define _PyUnicode_IsNumeric _PyUnicodeUCS2_IsNumeric +# define _PyUnicode_IsTitlecase _PyUnicodeUCS2_IsTitlecase +# define _PyUnicode_IsUppercase _PyUnicodeUCS2_IsUppercase +# define _PyUnicode_IsWhitespace _PyUnicodeUCS2_IsWhitespace +# define _PyUnicode_ToDecimalDigit _PyUnicodeUCS2_ToDecimalDigit +# define _PyUnicode_ToDigit _PyUnicodeUCS2_ToDigit +# define _PyUnicode_ToLowercase _PyUnicodeUCS2_ToLowercase +# define _PyUnicode_ToNumeric _PyUnicodeUCS2_ToNumeric +# define _PyUnicode_ToTitlecase _PyUnicodeUCS2_ToTitlecase +# define _PyUnicode_ToUppercase _PyUnicodeUCS2_ToUppercase + +#else + +# define PyUnicode_AsASCIIString PyUnicodeUCS4_AsASCIIString +# define PyUnicode_AsCharmapString PyUnicodeUCS4_AsCharmapString +# define PyUnicode_AsEncodedObject PyUnicodeUCS4_AsEncodedObject +# define PyUnicode_AsEncodedString PyUnicodeUCS4_AsEncodedString +# define PyUnicode_AsLatin1String PyUnicodeUCS4_AsLatin1String +# define PyUnicode_AsRawUnicodeEscapeString PyUnicodeUCS4_AsRawUnicodeEscapeString +# define PyUnicode_AsUTF16String PyUnicodeUCS4_AsUTF16String +# define PyUnicode_AsUTF8String PyUnicodeUCS4_AsUTF8String +# define PyUnicode_AsUnicode PyUnicodeUCS4_AsUnicode +# define PyUnicode_AsUnicodeEscapeString PyUnicodeUCS4_AsUnicodeEscapeString +# define PyUnicode_AsWideChar PyUnicodeUCS4_AsWideChar +# define PyUnicode_Compare PyUnicodeUCS4_Compare +# define PyUnicode_Concat PyUnicodeUCS4_Concat +# define PyUnicode_Contains PyUnicodeUCS4_Contains +# define PyUnicode_Count PyUnicodeUCS4_Count +# define PyUnicode_Decode PyUnicodeUCS4_Decode +# define PyUnicode_DecodeASCII PyUnicodeUCS4_DecodeASCII +# define PyUnicode_DecodeCharmap PyUnicodeUCS4_DecodeCharmap +# define PyUnicode_DecodeLatin1 PyUnicodeUCS4_DecodeLatin1 +# define PyUnicode_DecodeRawUnicodeEscape PyUnicodeUCS4_DecodeRawUnicodeEscape +# define PyUnicode_DecodeUTF16 PyUnicodeUCS4_DecodeUTF16 +# define PyUnicode_DecodeUTF16Stateful PyUnicodeUCS4_DecodeUTF16Stateful +# define PyUnicode_DecodeUTF8 PyUnicodeUCS4_DecodeUTF8 +# define PyUnicode_DecodeUTF8Stateful PyUnicodeUCS4_DecodeUTF8Stateful +# define PyUnicode_DecodeUnicodeEscape PyUnicodeUCS4_DecodeUnicodeEscape +# define PyUnicode_Encode PyUnicodeUCS4_Encode +# define PyUnicode_EncodeASCII PyUnicodeUCS4_EncodeASCII +# define PyUnicode_EncodeCharmap PyUnicodeUCS4_EncodeCharmap +# define PyUnicode_EncodeDecimal PyUnicodeUCS4_EncodeDecimal +# define PyUnicode_EncodeLatin1 PyUnicodeUCS4_EncodeLatin1 +# define PyUnicode_EncodeRawUnicodeEscape PyUnicodeUCS4_EncodeRawUnicodeEscape +# define PyUnicode_EncodeUTF16 PyUnicodeUCS4_EncodeUTF16 +# define PyUnicode_EncodeUTF8 PyUnicodeUCS4_EncodeUTF8 +# define PyUnicode_EncodeUnicodeEscape PyUnicodeUCS4_EncodeUnicodeEscape +# define PyUnicode_Find PyUnicodeUCS4_Find +# define PyUnicode_Format PyUnicodeUCS4_Format +# define PyUnicode_FromEncodedObject PyUnicodeUCS4_FromEncodedObject +# define PyUnicode_FromObject PyUnicodeUCS4_FromObject +# define PyUnicode_FromOrdinal PyUnicodeUCS4_FromOrdinal +# define PyUnicode_FromUnicode PyUnicodeUCS4_FromUnicode +# define PyUnicode_FromWideChar PyUnicodeUCS4_FromWideChar +# define PyUnicode_GetDefaultEncoding PyUnicodeUCS4_GetDefaultEncoding +# define PyUnicode_GetMax PyUnicodeUCS4_GetMax +# define PyUnicode_GetSize PyUnicodeUCS4_GetSize +# define PyUnicode_Join PyUnicodeUCS4_Join +# define PyUnicode_Partition PyUnicodeUCS4_Partition +# define PyUnicode_RPartition PyUnicodeUCS4_RPartition +# define PyUnicode_RSplit PyUnicodeUCS4_RSplit +# define PyUnicode_Replace PyUnicodeUCS4_Replace +# define PyUnicode_Resize PyUnicodeUCS4_Resize +# define PyUnicode_RichCompare PyUnicodeUCS4_RichCompare +# define PyUnicode_SetDefaultEncoding PyUnicodeUCS4_SetDefaultEncoding +# define PyUnicode_Split PyUnicodeUCS4_Split +# define PyUnicode_Splitlines PyUnicodeUCS4_Splitlines +# define PyUnicode_Tailmatch PyUnicodeUCS4_Tailmatch +# define PyUnicode_Translate PyUnicodeUCS4_Translate +# define PyUnicode_TranslateCharmap PyUnicodeUCS4_TranslateCharmap +# define _PyUnicode_AsDefaultEncodedString _PyUnicodeUCS4_AsDefaultEncodedString +# define _PyUnicode_Fini _PyUnicodeUCS4_Fini +# define _PyUnicode_Init _PyUnicodeUCS4_Init +# define _PyUnicode_IsAlpha _PyUnicodeUCS4_IsAlpha +# define _PyUnicode_IsDecimalDigit _PyUnicodeUCS4_IsDecimalDigit +# define _PyUnicode_IsDigit _PyUnicodeUCS4_IsDigit +# define _PyUnicode_IsLinebreak _PyUnicodeUCS4_IsLinebreak +# define _PyUnicode_IsLowercase _PyUnicodeUCS4_IsLowercase +# define _PyUnicode_IsNumeric _PyUnicodeUCS4_IsNumeric +# define _PyUnicode_IsTitlecase _PyUnicodeUCS4_IsTitlecase +# define _PyUnicode_IsUppercase _PyUnicodeUCS4_IsUppercase +# define _PyUnicode_IsWhitespace _PyUnicodeUCS4_IsWhitespace +# define _PyUnicode_ToDecimalDigit _PyUnicodeUCS4_ToDecimalDigit +# define _PyUnicode_ToDigit _PyUnicodeUCS4_ToDigit +# define _PyUnicode_ToLowercase _PyUnicodeUCS4_ToLowercase +# define _PyUnicode_ToNumeric _PyUnicodeUCS4_ToNumeric +# define _PyUnicode_ToTitlecase _PyUnicodeUCS4_ToTitlecase +# define _PyUnicode_ToUppercase _PyUnicodeUCS4_ToUppercase + + +#endif + +/* --- Internal Unicode Operations ---------------------------------------- */ + +/* If you want Python to use the compiler's wctype.h functions instead + of the ones supplied with Python, define WANT_WCTYPE_FUNCTIONS or + configure Python using --with-wctype-functions. This reduces the + interpreter's code size. */ + +#if defined(HAVE_USABLE_WCHAR_T) && defined(WANT_WCTYPE_FUNCTIONS) + +#include <wctype.h> + +#define Py_UNICODE_ISSPACE(ch) iswspace(ch) + +#define Py_UNICODE_ISLOWER(ch) iswlower(ch) +#define Py_UNICODE_ISUPPER(ch) iswupper(ch) +#define Py_UNICODE_ISTITLE(ch) _PyUnicode_IsTitlecase(ch) +#define Py_UNICODE_ISLINEBREAK(ch) _PyUnicode_IsLinebreak(ch) + +#define Py_UNICODE_TOLOWER(ch) towlower(ch) +#define Py_UNICODE_TOUPPER(ch) towupper(ch) +#define Py_UNICODE_TOTITLE(ch) _PyUnicode_ToTitlecase(ch) + +#define Py_UNICODE_ISDECIMAL(ch) _PyUnicode_IsDecimalDigit(ch) +#define Py_UNICODE_ISDIGIT(ch) _PyUnicode_IsDigit(ch) +#define Py_UNICODE_ISNUMERIC(ch) _PyUnicode_IsNumeric(ch) + +#define Py_UNICODE_TODECIMAL(ch) _PyUnicode_ToDecimalDigit(ch) +#define Py_UNICODE_TODIGIT(ch) _PyUnicode_ToDigit(ch) +#define Py_UNICODE_TONUMERIC(ch) _PyUnicode_ToNumeric(ch) + +#define Py_UNICODE_ISALPHA(ch) iswalpha(ch) + +#else + +#define Py_UNICODE_ISSPACE(ch) _PyUnicode_IsWhitespace(ch) + +#define Py_UNICODE_ISLOWER(ch) _PyUnicode_IsLowercase(ch) +#define Py_UNICODE_ISUPPER(ch) _PyUnicode_IsUppercase(ch) +#define Py_UNICODE_ISTITLE(ch) _PyUnicode_IsTitlecase(ch) +#define Py_UNICODE_ISLINEBREAK(ch) _PyUnicode_IsLinebreak(ch) + +#define Py_UNICODE_TOLOWER(ch) _PyUnicode_ToLowercase(ch) +#define Py_UNICODE_TOUPPER(ch) _PyUnicode_ToUppercase(ch) +#define Py_UNICODE_TOTITLE(ch) _PyUnicode_ToTitlecase(ch) + +#define Py_UNICODE_ISDECIMAL(ch) _PyUnicode_IsDecimalDigit(ch) +#define Py_UNICODE_ISDIGIT(ch) _PyUnicode_IsDigit(ch) +#define Py_UNICODE_ISNUMERIC(ch) _PyUnicode_IsNumeric(ch) + +#define Py_UNICODE_TODECIMAL(ch) _PyUnicode_ToDecimalDigit(ch) +#define Py_UNICODE_TODIGIT(ch) _PyUnicode_ToDigit(ch) +#define Py_UNICODE_TONUMERIC(ch) _PyUnicode_ToNumeric(ch) + +#define Py_UNICODE_ISALPHA(ch) _PyUnicode_IsAlpha(ch) + +#endif + +#define Py_UNICODE_ISALNUM(ch) \ + (Py_UNICODE_ISALPHA(ch) || \ + Py_UNICODE_ISDECIMAL(ch) || \ + Py_UNICODE_ISDIGIT(ch) || \ + Py_UNICODE_ISNUMERIC(ch)) + +#define Py_UNICODE_COPY(target, source, length) \ + Py_MEMCPY((target), (source), (length)*sizeof(Py_UNICODE)) + +#define Py_UNICODE_FILL(target, value, length) do\ + {Py_ssize_t i_; Py_UNICODE *t_ = (target); Py_UNICODE v_ = (value);\ + for (i_ = 0; i_ < (length); i_++) t_[i_] = v_;\ + } while (0) + +/* check if substring matches at given offset. the offset must be + valid, and the substring must not be empty */ +#define Py_UNICODE_MATCH(string, offset, substring) \ + ((*((string)->str + (offset)) == *((substring)->str)) && \ + ((*((string)->str + (offset) + (substring)->length-1) == *((substring)->str + (substring)->length-1))) && \ + !memcmp((string)->str + (offset), (substring)->str, (substring)->length*sizeof(Py_UNICODE))) + +#ifdef __cplusplus +extern "C" { +#endif + +/* --- Unicode Type ------------------------------------------------------- */ + +typedef struct { + PyObject_HEAD + Py_ssize_t length; /* Length of raw Unicode data in buffer */ + Py_UNICODE *str; /* Raw Unicode buffer */ + long hash; /* Hash value; -1 if not set */ + PyObject *defenc; /* (Default) Encoded version as Python + string, or NULL; this is used for + implementing the buffer protocol */ +} PyUnicodeObject; + +PyAPI_DATA(PyTypeObject) PyUnicode_Type; + +#define PyUnicode_Check(op) PyObject_TypeCheck(op, &PyUnicode_Type) +#define PyUnicode_CheckExact(op) ((op)->ob_type == &PyUnicode_Type) + +/* Fast access macros */ +#define PyUnicode_GET_SIZE(op) \ + (((PyUnicodeObject *)(op))->length) +#define PyUnicode_GET_DATA_SIZE(op) \ + (((PyUnicodeObject *)(op))->length * sizeof(Py_UNICODE)) +#define PyUnicode_AS_UNICODE(op) \ + (((PyUnicodeObject *)(op))->str) +#define PyUnicode_AS_DATA(op) \ + ((const char *)((PyUnicodeObject *)(op))->str) + +/* --- Constants ---------------------------------------------------------- */ + +/* This Unicode character will be used as replacement character during + decoding if the errors argument is set to "replace". Note: the + Unicode character U+FFFD is the official REPLACEMENT CHARACTER in + Unicode 3.0. */ + +#define Py_UNICODE_REPLACEMENT_CHARACTER ((Py_UNICODE) 0xFFFD) + +/* === Public API ========================================================= */ + +/* --- Plain Py_UNICODE --------------------------------------------------- */ + +/* Create a Unicode Object from the Py_UNICODE buffer u of the given + size. + + u may be NULL which causes the contents to be undefined. It is the + user's responsibility to fill in the needed data afterwards. Note + that modifying the Unicode object contents after construction is + only allowed if u was set to NULL. + + The buffer is copied into the new object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_FromUnicode( + const Py_UNICODE *u, /* Unicode buffer */ + Py_ssize_t size /* size of buffer */ + ); + +/* Return a read-only pointer to the Unicode object's internal + Py_UNICODE buffer. */ + +PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode( + PyObject *unicode /* Unicode object */ + ); + +/* Get the length of the Unicode object. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_GetSize( + PyObject *unicode /* Unicode object */ + ); + +/* Get the maximum ordinal for a Unicode character. */ +PyAPI_FUNC(Py_UNICODE) PyUnicode_GetMax(void); + +/* Resize an already allocated Unicode object to the new size length. + + *unicode is modified to point to the new (resized) object and 0 + returned on success. + + This API may only be called by the function which also called the + Unicode constructor. The refcount on the object must be 1. Otherwise, + an error is returned. + + Error handling is implemented as follows: an exception is set, -1 + is returned and *unicode left untouched. + +*/ + +PyAPI_FUNC(int) PyUnicode_Resize( + PyObject **unicode, /* Pointer to the Unicode object */ + Py_ssize_t length /* New length */ + ); + +/* Coerce obj to an Unicode object and return a reference with + *incremented* refcount. + + Coercion is done in the following way: + + 1. String and other char buffer compatible objects are decoded + under the assumptions that they contain data using the current + default encoding. Decoding is done in "strict" mode. + + 2. All other objects (including Unicode objects) raise an + exception. + + The API returns NULL in case of an error. The caller is responsible + for decref'ing the returned objects. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_FromEncodedObject( + register PyObject *obj, /* Object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Coerce obj to an Unicode object and return a reference with + *incremented* refcount. + + Unicode objects are passed back as-is (subclasses are converted to + true Unicode objects), all other objects are delegated to + PyUnicode_FromEncodedObject(obj, NULL, "strict") which results in + using the default encoding as basis for decoding the object. + + The API returns NULL in case of an error. The caller is responsible + for decref'ing the returned objects. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_FromObject( + register PyObject *obj /* Object */ + ); + +/* --- wchar_t support for platforms which support it --------------------- */ + +#ifdef HAVE_WCHAR_H + +/* Create a Unicode Object from the whcar_t buffer w of the given + size. + + The buffer is copied into the new object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_FromWideChar( + register const wchar_t *w, /* wchar_t buffer */ + Py_ssize_t size /* size of buffer */ + ); + +/* Copies the Unicode Object contents into the wchar_t buffer w. At + most size wchar_t characters are copied. + + Note that the resulting wchar_t string may or may not be + 0-terminated. It is the responsibility of the caller to make sure + that the wchar_t string is 0-terminated in case this is required by + the application. + + Returns the number of wchar_t characters copied (excluding a + possibly trailing 0-termination character) or -1 in case of an + error. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_AsWideChar( + PyUnicodeObject *unicode, /* Unicode object */ + register wchar_t *w, /* wchar_t buffer */ + Py_ssize_t size /* size of buffer */ + ); + +#endif + +/* --- Unicode ordinals --------------------------------------------------- */ + +/* Create a Unicode Object from the given Unicode code point ordinal. + + The ordinal must be in range(0x10000) on narrow Python builds + (UCS2), and range(0x110000) on wide builds (UCS4). A ValueError is + raised in case it is not. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_FromOrdinal(int ordinal); + +/* === Builtin Codecs ===================================================== + + Many of these APIs take two arguments encoding and errors. These + parameters encoding and errors have the same semantics as the ones + of the builtin unicode() API. + + Setting encoding to NULL causes the default encoding to be used. + + Error handling is set by errors which may also be set to NULL + meaning to use the default handling defined for the codec. Default + error handling for all builtin codecs is "strict" (ValueErrors are + raised). + + The codecs all use a similar interface. Only deviation from the + generic ones are documented. + +*/ + +/* --- Manage the default encoding ---------------------------------------- */ + +/* Return a Python string holding the default encoded value of the + Unicode object. + + The resulting string is cached in the Unicode object for subsequent + usage by this function. The cached version is needed to implement + the character buffer interface and will live (at least) as long as + the Unicode object itself. + + The refcount of the string is *not* incremented. + + *** Exported for internal use by the interpreter only !!! *** + +*/ + +PyAPI_FUNC(PyObject *) _PyUnicode_AsDefaultEncodedString( + PyObject *, const char *); + +/* Returns the currently active default encoding. + + The default encoding is currently implemented as run-time settable + process global. This may change in future versions of the + interpreter to become a parameter which is managed on a per-thread + basis. + + */ + +PyAPI_FUNC(const char*) PyUnicode_GetDefaultEncoding(void); + +/* Sets the currently active default encoding. + + Returns 0 on success, -1 in case of an error. + + */ + +PyAPI_FUNC(int) PyUnicode_SetDefaultEncoding( + const char *encoding /* Encoding name in standard form */ + ); + +/* --- Generic Codecs ----------------------------------------------------- */ + +/* Create a Unicode object by decoding the encoded string s of the + given size. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Decode( + const char *s, /* encoded string */ + Py_ssize_t size, /* size of buffer */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a Py_UNICODE buffer of the given size and returns a + Python string object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Encode( + const Py_UNICODE *s, /* Unicode char buffer */ + Py_ssize_t size, /* number of Py_UNICODE chars to encode */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a Unicode object and returns the result as Python + object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedObject( + PyObject *unicode, /* Unicode object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +/* Encodes a Unicode object and returns the result as Python string + object. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsEncodedString( + PyObject *unicode, /* Unicode object */ + const char *encoding, /* encoding */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_BuildEncodingMap( + PyObject* string /* 256 character map */ + ); + + +/* --- UTF-7 Codecs ------------------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF7( + const char *string, /* UTF-7 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF7( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + int encodeSetO, /* force the encoder to encode characters in + Set O, as described in RFC2152 */ + int encodeWhiteSpace, /* force the encoder to encode space, tab, + carriage return and linefeed characters */ + const char *errors /* error handling */ + ); + +/* --- UTF-8 Codecs ------------------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8( + const char *string, /* UTF-8 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF8Stateful( + const char *string, /* UTF-8 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsUTF8String( + PyObject *unicode /* Unicode object */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF8( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); + +/* --- UTF-16 Codecs ------------------------------------------------------ */ + +/* Decodes length bytes from a UTF-16 encoded buffer string and returns + the corresponding Unicode object. + + errors (if non-NULL) defines the error handling. It defaults + to "strict". + + If byteorder is non-NULL, the decoder starts decoding using the + given byte order: + + *byteorder == -1: little endian + *byteorder == 0: native order + *byteorder == 1: big endian + + In native mode, the first two bytes of the stream are checked for a + BOM mark. If found, the BOM mark is analysed, the byte order + adjusted and the BOM skipped. In the other modes, no BOM mark + interpretation is done. After completion, *byteorder is set to the + current byte order at the end of input data. + + If byteorder is NULL, the codec starts in native order mode. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16( + const char *string, /* UTF-16 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + int *byteorder /* pointer to byteorder to use + 0=native;-1=LE,1=BE; updated on + exit */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUTF16Stateful( + const char *string, /* UTF-16 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + int *byteorder, /* pointer to byteorder to use + 0=native;-1=LE,1=BE; updated on + exit */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +/* Returns a Python string using the UTF-16 encoding in native byte + order. The string always starts with a BOM mark. */ + +PyAPI_FUNC(PyObject*) PyUnicode_AsUTF16String( + PyObject *unicode /* Unicode object */ + ); + +/* Returns a Python string object holding the UTF-16 encoded value of + the Unicode data. + + If byteorder is not 0, output is written according to the following + byte order: + + byteorder == -1: little endian + byteorder == 0: native byte order (writes a BOM mark) + byteorder == 1: big endian + + If byteorder is 0, the output string will always start with the + Unicode BOM mark (U+FEFF). In the other two modes, no BOM mark is + prepended. + + Note that Py_UNICODE data is being interpreted as UTF-16 reduced to + UCS-2. This trick makes it possible to add full UTF-16 capabilities + at a later point without compromising the APIs. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF16( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* number of Py_UNICODE chars to encode */ + const char *errors, /* error handling */ + int byteorder /* byteorder to use 0=BOM+native;-1=LE,1=BE */ + ); + +/* --- Unicode-Escape Codecs ---------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeUnicodeEscape( + const char *string, /* Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsUnicodeEscapeString( + PyObject *unicode /* Unicode object */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeUnicodeEscape( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length /* Number of Py_UNICODE chars to encode */ + ); + +/* --- Raw-Unicode-Escape Codecs ------------------------------------------ */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeRawUnicodeEscape( + const char *string, /* Raw-Unicode-Escape encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsRawUnicodeEscapeString( + PyObject *unicode /* Unicode object */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeRawUnicodeEscape( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length /* Number of Py_UNICODE chars to encode */ + ); + +/* --- Unicode Internal Codec --------------------------------------------- + + Only for internal use in _codecsmodule.c */ + +PyObject *_PyUnicode_DecodeUnicodeInternal( + const char *string, + Py_ssize_t length, + const char *errors + ); + +/* --- Latin-1 Codecs ----------------------------------------------------- + + Note: Latin-1 corresponds to the first 256 Unicode ordinals. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeLatin1( + const char *string, /* Latin-1 encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsLatin1String( + PyObject *unicode /* Unicode object */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeLatin1( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); + +/* --- ASCII Codecs ------------------------------------------------------- + + Only 7-bit ASCII data is excepted. All other codes generate errors. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeASCII( + const char *string, /* ASCII encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsASCIIString( + PyObject *unicode /* Unicode object */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeASCII( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); + +/* --- Character Map Codecs ----------------------------------------------- + + This codec uses mappings to encode and decode characters. + + Decoding mappings must map single string characters to single + Unicode characters, integers (which are then interpreted as Unicode + ordinals) or None (meaning "undefined mapping" and causing an + error). + + Encoding mappings must map single Unicode characters to single + string characters, integers (which are then interpreted as Latin-1 + ordinals) or None (meaning "undefined mapping" and causing an + error). + + If a character lookup fails with a LookupError, the character is + copied as-is meaning that its ordinal value will be interpreted as + Unicode or Latin-1 ordinal resp. Because of this mappings only need + to contain those mappings which map characters to different code + points. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeCharmap( + const char *string, /* Encoded string */ + Py_ssize_t length, /* size of string */ + PyObject *mapping, /* character mapping + (char ordinal -> unicode ordinal) */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsCharmapString( + PyObject *unicode, /* Unicode object */ + PyObject *mapping /* character mapping + (unicode ordinal -> char ordinal) */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeCharmap( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + PyObject *mapping, /* character mapping + (unicode ordinal -> char ordinal) */ + const char *errors /* error handling */ + ); + +/* Translate a Py_UNICODE buffer of the given length by applying a + character mapping table to it and return the resulting Unicode + object. + + The mapping table must map Unicode ordinal integers to Unicode + ordinal integers or None (causing deletion of the character). + + Mapping tables may be dictionaries or sequences. Unmapped character + ordinals (ones which cause a LookupError) are left untouched and + are copied as-is. + +*/ + +PyAPI_FUNC(PyObject *) PyUnicode_TranslateCharmap( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + PyObject *table, /* Translate table */ + const char *errors /* error handling */ + ); + +#ifdef MS_WIN32 + +/* --- MBCS codecs for Windows -------------------------------------------- */ + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCS( + const char *string, /* MBCS encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors /* error handling */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_DecodeMBCSStateful( + const char *string, /* MBCS encoded string */ + Py_ssize_t length, /* size of string */ + const char *errors, /* error handling */ + Py_ssize_t *consumed /* bytes consumed */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_AsMBCSString( + PyObject *unicode /* Unicode object */ + ); + +PyAPI_FUNC(PyObject*) PyUnicode_EncodeMBCS( + const Py_UNICODE *data, /* Unicode char buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + const char *errors /* error handling */ + ); + +#endif /* MS_WIN32 */ + +/* --- Decimal Encoder ---------------------------------------------------- */ + +/* Takes a Unicode string holding a decimal value and writes it into + an output buffer using standard ASCII digit codes. + + The output buffer has to provide at least length+1 bytes of storage + area. The output string is 0-terminated. + + The encoder converts whitespace to ' ', decimal characters to their + corresponding ASCII digit and all other Latin-1 characters except + \0 as-is. Characters outside this range (Unicode ordinals 1-256) + are treated as errors. This includes embedded NULL bytes. + + Error handling is defined by the errors argument: + + NULL or "strict": raise a ValueError + "ignore": ignore the wrong characters (these are not copied to the + output buffer) + "replace": replaces illegal characters with '?' + + Returns 0 on success, -1 on failure. + +*/ + +PyAPI_FUNC(int) PyUnicode_EncodeDecimal( + Py_UNICODE *s, /* Unicode buffer */ + Py_ssize_t length, /* Number of Py_UNICODE chars to encode */ + char *output, /* Output buffer; must have size >= length */ + const char *errors /* error handling */ + ); + +/* --- Methods & Slots ---------------------------------------------------- + + These are capable of handling Unicode objects and strings on input + (we refer to them as strings in the descriptions) and return + Unicode objects or integers as apporpriate. */ + +/* Concat two strings giving a new Unicode string. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Concat( + PyObject *left, /* Left string */ + PyObject *right /* Right string */ + ); + +/* Split a string giving a list of Unicode strings. + + If sep is NULL, splitting will be done at all whitespace + substrings. Otherwise, splits occur at the given separator. + + At most maxsplit splits will be done. If negative, no limit is set. + + Separators are not included in the resulting list. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_Split( + PyObject *s, /* String to split */ + PyObject *sep, /* String separator */ + Py_ssize_t maxsplit /* Maxsplit count */ + ); + +/* Dito, but split at line breaks. + + CRLF is considered to be one line break. Line breaks are not + included in the resulting list. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Splitlines( + PyObject *s, /* String to split */ + int keepends /* If true, line end markers are included */ + ); + +/* Partition a string using a given separator. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Partition( + PyObject *s, /* String to partition */ + PyObject *sep /* String separator */ + ); + +/* Partition a string using a given separator, searching from the end of the + string. */ + +PyAPI_FUNC(PyObject*) PyUnicode_RPartition( + PyObject *s, /* String to partition */ + PyObject *sep /* String separator */ + ); + +/* Split a string giving a list of Unicode strings. + + If sep is NULL, splitting will be done at all whitespace + substrings. Otherwise, splits occur at the given separator. + + At most maxsplit splits will be done. But unlike PyUnicode_Split + PyUnicode_RSplit splits from the end of the string. If negative, + no limit is set. + + Separators are not included in the resulting list. + +*/ + +PyAPI_FUNC(PyObject*) PyUnicode_RSplit( + PyObject *s, /* String to split */ + PyObject *sep, /* String separator */ + Py_ssize_t maxsplit /* Maxsplit count */ + ); + +/* Translate a string by applying a character mapping table to it and + return the resulting Unicode object. + + The mapping table must map Unicode ordinal integers to Unicode + ordinal integers or None (causing deletion of the character). + + Mapping tables may be dictionaries or sequences. Unmapped character + ordinals (ones which cause a LookupError) are left untouched and + are copied as-is. + +*/ + +PyAPI_FUNC(PyObject *) PyUnicode_Translate( + PyObject *str, /* String */ + PyObject *table, /* Translate table */ + const char *errors /* error handling */ + ); + +/* Join a sequence of strings using the given separator and return + the resulting Unicode string. */ + +PyAPI_FUNC(PyObject*) PyUnicode_Join( + PyObject *separator, /* Separator string */ + PyObject *seq /* Sequence object */ + ); + +/* Return 1 if substr matches str[start:end] at the given tail end, 0 + otherwise. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_Tailmatch( + PyObject *str, /* String */ + PyObject *substr, /* Prefix or Suffix string */ + Py_ssize_t start, /* Start index */ + Py_ssize_t end, /* Stop index */ + int direction /* Tail end: -1 prefix, +1 suffix */ + ); + +/* Return the first position of substr in str[start:end] using the + given search direction or -1 if not found. -2 is returned in case + an error occurred and an exception is set. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_Find( + PyObject *str, /* String */ + PyObject *substr, /* Substring to find */ + Py_ssize_t start, /* Start index */ + Py_ssize_t end, /* Stop index */ + int direction /* Find direction: +1 forward, -1 backward */ + ); + +/* Count the number of occurrences of substr in str[start:end]. */ + +PyAPI_FUNC(Py_ssize_t) PyUnicode_Count( + PyObject *str, /* String */ + PyObject *substr, /* Substring to count */ + Py_ssize_t start, /* Start index */ + Py_ssize_t end /* Stop index */ + ); + +/* Replace at most maxcount occurrences of substr in str with replstr + and return the resulting Unicode object. */ + +PyAPI_FUNC(PyObject *) PyUnicode_Replace( + PyObject *str, /* String */ + PyObject *substr, /* Substring to find */ + PyObject *replstr, /* Substring to replace */ + Py_ssize_t maxcount /* Max. number of replacements to apply; + -1 = all */ + ); + +/* Compare two strings and return -1, 0, 1 for less than, equal, + greater than resp. */ + +PyAPI_FUNC(int) PyUnicode_Compare( + PyObject *left, /* Left string */ + PyObject *right /* Right string */ + ); + +/* Rich compare two strings and return one of the following: + + - NULL in case an exception was raised + - Py_True or Py_False for successfuly comparisons + - Py_NotImplemented in case the type combination is unknown + + Note that Py_EQ and Py_NE comparisons can cause a UnicodeWarning in + case the conversion of the arguments to Unicode fails with a + UnicodeDecodeError. + + Possible values for op: + + Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE + +*/ + +PyAPI_FUNC(PyObject *) PyUnicode_RichCompare( + PyObject *left, /* Left string */ + PyObject *right, /* Right string */ + int op /* Operation: Py_EQ, Py_NE, Py_GT, etc. */ + ); + +/* Apply a argument tuple or dictionary to a format string and return + the resulting Unicode string. */ + +PyAPI_FUNC(PyObject *) PyUnicode_Format( + PyObject *format, /* Format string */ + PyObject *args /* Argument tuple or dictionary */ + ); + +/* Checks whether element is contained in container and return 1/0 + accordingly. + + element has to coerce to an one element Unicode string. -1 is + returned in case of an error. */ + +PyAPI_FUNC(int) PyUnicode_Contains( + PyObject *container, /* Container string */ + PyObject *element /* Element string */ + ); + +/* Externally visible for str.strip(unicode) */ +PyAPI_FUNC(PyObject *) _PyUnicode_XStrip( + PyUnicodeObject *self, + int striptype, + PyObject *sepobj + ); + +/* === Characters Type APIs =============================================== */ + +/* These should not be used directly. Use the Py_UNICODE_IS* and + Py_UNICODE_TO* macros instead. + + These APIs are implemented in Objects/unicodectype.c. + +*/ + +PyAPI_FUNC(int) _PyUnicode_IsLowercase( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsUppercase( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsTitlecase( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsWhitespace( + const Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsLinebreak( + const Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(Py_UNICODE) _PyUnicode_ToLowercase( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(Py_UNICODE) _PyUnicode_ToUppercase( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(Py_UNICODE) _PyUnicode_ToTitlecase( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_ToDecimalDigit( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_ToDigit( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(double) _PyUnicode_ToNumeric( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsDecimalDigit( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsDigit( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsNumeric( + Py_UNICODE ch /* Unicode character */ + ); + +PyAPI_FUNC(int) _PyUnicode_IsAlpha( + Py_UNICODE ch /* Unicode character */ + ); + +#ifdef __cplusplus +} +#endif +#endif /* Py_USING_UNICODE */ +#endif /* !Py_UNICODEOBJECT_H */ diff --git a/sys/src/cmd/python/Include/weakrefobject.h b/sys/src/cmd/python/Include/weakrefobject.h new file mode 100644 index 000000000..0a659b027 --- /dev/null +++ b/sys/src/cmd/python/Include/weakrefobject.h @@ -0,0 +1,75 @@ +/* Weak references objects for Python. */ + +#ifndef Py_WEAKREFOBJECT_H +#define Py_WEAKREFOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct _PyWeakReference PyWeakReference; + +/* PyWeakReference is the base struct for the Python ReferenceType, ProxyType, + * and CallableProxyType. + */ +struct _PyWeakReference { + PyObject_HEAD + + /* The object to which this is a weak reference, or Py_None if none. + * Note that this is a stealth reference: wr_object's refcount is + * not incremented to reflect this pointer. + */ + PyObject *wr_object; + + /* A callable to invoke when wr_object dies, or NULL if none. */ + PyObject *wr_callback; + + /* A cache for wr_object's hash code. As usual for hashes, this is -1 + * if the hash code isn't known yet. + */ + long hash; + + /* If wr_object is weakly referenced, wr_object has a doubly-linked NULL- + * terminated list of weak references to it. These are the list pointers. + * If wr_object goes away, wr_object is set to Py_None, and these pointers + * have no meaning then. + */ + PyWeakReference *wr_prev; + PyWeakReference *wr_next; +}; + +PyAPI_DATA(PyTypeObject) _PyWeakref_RefType; +PyAPI_DATA(PyTypeObject) _PyWeakref_ProxyType; +PyAPI_DATA(PyTypeObject) _PyWeakref_CallableProxyType; + +#define PyWeakref_CheckRef(op) PyObject_TypeCheck(op, &_PyWeakref_RefType) +#define PyWeakref_CheckRefExact(op) \ + ((op)->ob_type == &_PyWeakref_RefType) +#define PyWeakref_CheckProxy(op) \ + (((op)->ob_type == &_PyWeakref_ProxyType) || \ + ((op)->ob_type == &_PyWeakref_CallableProxyType)) + +/* This macro calls PyWeakref_CheckRef() last since that can involve a + function call; this makes it more likely that the function call + will be avoided. */ +#define PyWeakref_Check(op) \ + (PyWeakref_CheckRef(op) || PyWeakref_CheckProxy(op)) + + +PyAPI_FUNC(PyObject *) PyWeakref_NewRef(PyObject *ob, + PyObject *callback); +PyAPI_FUNC(PyObject *) PyWeakref_NewProxy(PyObject *ob, + PyObject *callback); +PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref); + +PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head); + +PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self); + +#define PyWeakref_GET_OBJECT(ref) (((PyWeakReference *)(ref))->wr_object) + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_WEAKREFOBJECT_H */ diff --git a/sys/src/cmd/python/LICENSE b/sys/src/cmd/python/LICENSE new file mode 100644 index 000000000..d8e1f80c5 --- /dev/null +++ b/sys/src/cmd/python/LICENSE @@ -0,0 +1,270 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations (now Zope +Corporation, see http://www.zope.com). In 2001, the Python Software +Foundation (PSF, see http://www.python.org/psf/) was formed, a +non-profit organization created specifically to own Python-related +Intellectual Property. Zope Corporation is a sponsoring member of +the PSF. + +All Python releases are Open Source (see http://www.opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.2 2.1.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2.1 2.2 2002 PSF yes + 2.2.2 2.2.1 2002 PSF yes + 2.2.3 2.2.2 2003 PSF yes + 2.3 2.2.2 2002-2003 PSF yes + 2.3.1 2.3 2002-2003 PSF yes + 2.3.2 2.3.1 2002-2003 PSF yes + 2.3.3 2.3.2 2002-2003 PSF yes + 2.3.4 2.3.3 2004 PSF yes + 2.3.5 2.3.4 2005 PSF yes + 2.4 2.3 2004 PSF yes + 2.4.1 2.4 2005 PSF yes + 2.4.2 2.4.1 2005 PSF yes + 2.4.3 2.4.2 2006 PSF yes + 2.5 2.4 2006 PSF yes + 2.5.1 2.5 2007 PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python +alone or in any derivative version, provided, however, that PSF's +License Agreement and PSF's notice of copyright, i.e., "Copyright (c) +2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative +version prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the Internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the Internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/sys/src/cmd/python/Misc/ACKS b/sys/src/cmd/python/Misc/ACKS new file mode 100644 index 000000000..7524baefc --- /dev/null +++ b/sys/src/cmd/python/Misc/ACKS @@ -0,0 +1,698 @@ +Acknowledgements +---------------- + +This list is not complete and not in any useful order, but I would +like to thank everybody who contributed in any way, with code, hints, +bug reports, ideas, moral support, endorsement, or even complaints.... +Without you I would've stopped working on Python long ago! + + --Guido + +PS: In the standard Python distribution this file is encoded in Latin-1. + +David Abrahams +Jim Ahlstrom +Jyrki Alakuijala +Billy G. Allie +Kevin Altis +Mark Anacker +Anders Andersen +Erik Andersén +John Anderson +Oliver Andrich +Ross Andrus +Jason Asbahr +David Ascher +Peter Åstrand +Chris AtLee +John Aycock +Donovan Baarda +Attila Babo +Alfonso Baciero +Stig Bakken +Greg Ball +Luigi Ballabio +Michael J. Barber +Chris Barker +Quentin Barnes +Cesar Eduardo Barros +Des Barry +Ulf Bartelt +Nick Bastin +Jeff Bauer +Michael R Bax +Anthony Baxter +Samuel L. Bayer +Donald Beaudry +David Beazley +Neal Becker +Robin Becker +Bill Bedford +Reimer Behrends +Ben Bell +Thomas Bellman +Juan M. Bello Rivas +Alexander Belopolsky +Andrew Bennetts +Andy Bensky +Michel Van den Bergh +Eric Beser +Steven Bethard +Stephen Bevan +Ron Bickers +Dominic Binks +Philippe Biondi +Stuart Bishop +Roy Bixler +Mike Bland +Martin Bless +Pablo Bleyer +Erik van Blokland +Eric Blossom +Finn Bock +Paul Boddie +Matthew Boedicker +David Bolen +Gregory Bond +Jurjen Bos +Peter Bosch +Eric Bouck +Thierry Bousch +Monty Brandenberg +Georg Brandl +Terrence Brannon +Dave Brennan +Tom Bridgman +Richard Brodie +Gary S. Brown +Daniel Brotsky +Oleg Broytmann +Dave Brueck +Stan Bubrouski +Erik de Bueger +Jan-Hein B"uhrman +Dick Bulterman +Bill Bumgarner +Jimmy Burgett +Tommy Burnette +Roger Burnham +Alastair Burt +Tarn Weisner Burton +Lee Busby +Ralph Butler +Jp Calderone +Daniel Calvelo +Tony Campbell +Brett Cannon +Mike Carlton +Terry Carroll +Luke Kenneth Casson Leighton +Donn Cave +Per Cederqvist +Octavian Cerna +Hye-Shik Chang +Jeffrey Chang +Brad Chapman +Greg Chapman +Mitch Chapman +David Chaum +Nicolas Chauvat +Michael Chermside +Albert Chin-A-Young +Adal Chiriliuc +Tom Christiansen +Vadim Chugunov +David Cinege +Mike Clarkson +Brad Clements +Steve Clift +Nick Coghlan +Josh Cogliati +Dave Cole +Benjamin Collar +Jeffery Collins +Matt Conway +David M. Cooke +Greg Copeland +Aldo Cortesi +David Costanzo +Scott Cotton +Greg Couch +Steve Cousins +Alex Coventry +Matthew Dixon Cowles +Christopher A. Craig +Laura Creighton +Drew Csillag +Tom Culliton +John Cugini +Andrew Dalke +Lars Damerow +Eric Daniel +Scott David Daniels +Ben Darnell +Jonathan Dasteel +John DeGood +Vincent Delft +Roger Dev +Toby Dickenson +Yves Dionne +Daniel Dittmar +Walter Dörwald +Jaromir Dolecek +Dima Dorfman +Cesar Douady +Dean Draayer +Fred L. Drake, Jr. +John DuBois +Paul Dubois +Quinn Dunkan +Robin Dunn +Luke Dunstan +Andy Dustman +Gary Duzan +Eugene Dvurechenski +Maxim Dzumanenko +Hans Eckardt +Grant Edwards +John Ehresman +Andrew Eland +Lance Ellinghaus +David Ely +Jeff Epler +Tom Epperly +Stoffel Erasmus +Jürgen A. Erhard +Michael Ernst +Ben Escoto +Andy Eskilsson +Stefan Esser +Carey Evans +Stephen D Evans +Tim Everett +Paul Everitt +David Everly +Greg Ewing +Martijn Faassen +Andreas Faerber +Bill Fancher +Mark Favas +Niels Ferguson +Sebastian Fernandez +Vincent Fiack +Russell Finn +Nils Fischbeck +Frederik Fix +Matt Fleming +Hernán Martínez Foffani +Doug Fort +John Fouhy +Martin Franklin +Robin Friedrich +Ivan Frohne +Jim Fulton +Tadayoshi Funaba +Gyro Funch +Peter Funk +Geoff Furnish +Lele Gaifax +Yitzchak Gale +Raymund Galvin +Nitin Ganatra +Fred Gansevles +Lars Marius Garshol +Dan Gass +Andrew Gaul +Stephen M. Gava +Harry Henry Gebel +Marius Gedminas +Thomas Gellekum +Christos Georgiou +Ben Gertzfield +Dinu Gherman +Jonathan Giddy +Johannes Gijsbers +Michael Gilfix +Chris Gonnerman +David Goodger +Hans de Graaff +Eddy De Greef +Duncan Grisby +Dag Gruneau +Michael Guravage +Lars Gustäbel +Barry Haddow +Václav Haisman +Paul ten Hagen +Rasmus Hahn +Peter Haight +Bob Halley +Jesse Hallio +Jun Hamano +Mark Hammond +Manus Hand +Milton L. Hankins +Stephen Hansen +Barry Hantman +Lynda Hardman +Derek Harland +Jason Harper +Gerhard Häring +Larry Hastings +Shane Hathaway +Rycharde Hawkes +Jochen Hayek +Thomas Heller +Lance Finn Helsten +Jonathan Hendry +James Henstridge +Chris Herborth +Ivan Herman +Jürgen Hermann +Gary Herron +Bernhard Herzog +Magnus L. Hetland +Raymond Hettinger +Kevan Heydon +Jason Hildebrand +Richie Hindle +Konrad Hinsen +David Hobley +Tim Hochberg +Joerg-Cyril Hoehle +Gregor Hoffleit +Chris Hoffman +Albert Hofkamp +Jonathan Hogg +Gerrit Holl +Rune Holm +Philip Homburg +Naofumi Honda +Jeffrey Honig +Rob Hooft +Brian Hooper +Randall Hopper +Nadav Horesh +Ken Howard +Brad Howes +Chih-Hao Huang +Lawrence Hudson +Michael Hudson +Jim Hugunin +Greg Humphreys +Eric Huss +Jeremy Hylton +Mihai Ibanescu +Juan David Ibáñez Palomar +Lars Immisch +Tony Ingraldi +John Interrante +Bob Ippolito +Ben Jackson +Paul Jackson +David Jacobs +Kevin Jacobs +Kjetil Jacobsen +Geert Jansen +Jack Jansen +Bill Janssen +Drew Jenkins +Flemming Kjær Jensen +Jiba +Orjan Johansen +Gregory K. Johnson +Simon Johnston +Evan Jones +Richard Jones +Irmen de Jong +Lucas de Jonge +Jens B. Jorgensen +John Jorgensen +Andreas Jung +Tattoo Mabonzo K. +Bob Kahn +Kurt B. Kaiser +Tamito Kajiyama +Peter van Kampen +Jacob Kaplan-Moss +Lou Kates +Sebastien Keim +Randall Kern +Robert Kern +Magnus Kessler +Lawrence Kesteloot +Vivek Khera +Mads Kiilerich +Steve Kirsch +Ron Klatchko +Bastian Kleineidam +Bob Kline +Matthias Klose +Kim Knapp +Lenny Kneler +Pat Knight +Greg Kochanski +Joseph Koshy +Bob Kras +Holger Krekel +Hannu Krosing +Andrew Kuchling +Vladimir Kushnir +Arnaud Mazin +Cameron Laird +Tino Lange +Andrew Langmead +Detlef Lannert +Soren Larsen +Piers Lauder +Ben Laurie +Simon Law +Chris Lawrence +Christopher Lee +Inyeol Lee +John J. Lee +Thomas Lee +Luc Lefebvre +Kip Lehman +Joerg Lehmann +Marc-Andre Lemburg +William Lewis +Robert van Liere +Martin Ligr +Christopher Lindblad +Eric Lindvall +Per Lindqvist +Nick Lockwood +Stephanie Lockwood +Martin von Löwis +Anne Lord +Tom Loredo +Jason Lowe +Tony Lownds +Ray Loyzaga +Loren Luke +Fredrik Lundh +Mark Lutz +Jim Lynch +Mikael Lyngvig +Alan McIntyre +Andrew I MacIntyre +Tim MacKenzie +Nick Maclaren +Steve Majewski +Grzegorz Makarewicz +Ken Manheimer +Vladimir Marangozov +Doug Marien +Alex Martelli +Anthony Martin +Roger Masse +Nick Mathewson +Graham Matthews +Dieter Maurer +Greg McFarlane +Michael McLay +Gordon McMillan +Jay T. Miller +Chris McDonough +Andrew McNamara +Caolan McNamara +Craig McPheeters +Lambert Meertens +Bill van Melle +Luke Mewburn +Mike Meyer +Steven Miale +Trent Mick +Chad Miller +Roman Milner +Dom Mitchell +Doug Moen +Paul Moore +The Dragon De Monsyne +Skip Montanaro +James A Morrison +Sape Mullender +Sjoerd Mullender +Michael Muller +Takahiro Nakayama +Travers Naran +Fredrik Nehr +Tony Nelson +Chad Netzer +Max Neunhöffer +George Neville-Neil +Johannes Nicolai +Samuel Nicolary +Gustavo Niemeyer +Oscar Nierstrasz +Hrvoje Niksic +Bill Noon +Stefan Norberg +Tim Northover +Joe Norton +Neal Norwitz +Nigel O'Brian +Kevin O'Connor +Tim O'Malley +Pascal Oberndoerfer +Jeffrey Ollie +Grant Olson +Piet van Oostrum +Jason Orendorff +Douglas Orr +Denis S. Otkidach +Russel Owen +Mike Pall +Todd R. Palmer +Jan Palus +Alexandre Parenteau +Dan Parisien +Harri Pasanen +Randy Pausch +Ondrej Palkovsky +M. Papillon +Marcel van der Peijl +Samuele Pedroni +Steven Pemberton +Eduardo Pérez +Fernando Pérez +Mark Perrego +Trevor Perrin +Tim Peters +Chris Petrilli +Bjorn Pettersen +Geoff Philbrick +Gavrie Philipson +Adrian Phillips +Christopher J. Phoenix +Neale Pickett +Jean-François Piéronne +Dan Pierson +Martijn Pieters +François Pinard +Zach Pincus +Michael Piotrowski +Iustin Pop +John Popplewell +Amrit Prem +Paul Prescod +Donovan Preston +Steve Purcell +Brian Quinlan +Anders Qvist +Burton Radons +Eric Raymond +Edward K. Ream +Marc Recht +John Redford +Terry Reedy +Steve Reeves +Ofir Reichenberg +Sean Reifschneider +Michael P. Reilly +Bernhard Reiter +Steven Reiz +Roeland Rengelink +Tim Rice +Jan Pieter Riegel +Armin Rigo +Nicholas Riley +Jean-Claude Rimbault +Anthony Roach +Andy Robinson +Jim Robinson +Kevin Rodgers +Mike Romberg +Case Roole +Timothy Roscoe +Craig Rowland +Jim Roskind +Erik van Blokland +Just van Rossum +Hugo van Rossum +Saskia van Rossum +Donald Wallace Rouse II +Liam Routt +Sam Ruby +Paul Rubin +Audun S. Runde +Jeff Rush +Sam Rushing +Mark Russell +Nick Russo +Hajime Saitou +Rich Salz +Kevin Samborn +Ty Sarna +Ben Sayer +Michael Scharf +Neil Schemenauer +David Scherer +Gregor Schmid +Ralf Schmitt +Peter Schneider-Kamp +Chad J. Schroeder +Sam Schulenburg +Stefan Schwarzer +Dietmar Schwertberger +Barry Scott +Steven Scott +Nick Seidenman +Žiga Seilnach +Fred Sells +Jiwon Seo +Denis Severson +Ha Shao +Bruce Sherwood +Pete Shinners +Michael Shiplett +John W. Shipman +Joel Shprentz +Itamar Shtull-Trauring +Eric Siegerman +Paul Sijben +Kirill Simonov +Nathan Paul Simons +Janne Sinkkonen +George Sipe +J. Sipprell +Kragen Sitaker +Christopher Smith +Gregory P. Smith +Rafal Smotrzyk +Dirk Soede +Paul Sokolovsky +Clay Spence +Per Spilling +Joshua Spoerri +Noah Spurrier +Nathan Srebro +RajGopal Srinivasan +Jim St. Pierre +Quentin Stafford-Fraser +Frank Stajano +Oliver Steele +Greg Stein +Chris Stern +Richard Stoakley +Peter Stoehr +Casper Stoel +Michael Stone +Ken Stox +Dan Stromberg +Daniel Stutzbach +Nathan Sullivan +Mark Summerfield +Hisao Suzuki +Kalle Svensson +Paul Swartz +Thenault Sylvain +Geoff Talvola +William Tanksley +Christian Tanzer +Steven Taschuk +Amy Taylor +Tobias Thelen +Robin Thomas +Eric Tiedemann +Tracy Tims +Oren Tirosh +Jason Tishler +Christian Tismer +Frank J. Tobin +R Lindsay Todd +Bennett Todd +Richard Townsend +Laurence Tratt +John Tromp +Jason Trowbridge +Anthony Tuininga +Christopher Tur Lesniewski-Laas +Stephen Turner +Bill Tutt +Doobee R. Tzeck +Lionel Ulmer +Michael Urman +Hector Urtubia +Dmitry Vasiliev +Frank Vercruesse +Jaap Vermeulen +Al Vezza +Jacques A. Vidrine +John Viega +Kannan Vijayan +Kurt Vile +Norman Vine +Frank Visser +Niki W. Waibel +Wojtek Walczak +Charles Waldman +Richard Walker +Larry Wall +Greg Ward +Barry Warsaw +Steve Waterbury +Bob Watson +Aaron Watters +Henrik Weber +Corran Webster +Zack Weinberg +Edward Welbourne +Cliff Wells +Rickard Westman +Mats Wichmann +Truida Wiedijk +Felix Wiemann +Gerry Wiener +Bryce "Zooko" Wilcox-O'Hearn +Gerald S. Williams +John Williams +Sue Williams +Frank Willison +Greg V. Wilson +Jody Winston +Collin Winter +Dik Winter +Blake Winton +Jean-Claude Wippler +Lars Wirzenius +Stefan Witzel +Klaus-Juergen Wolf +Dan Wolfe +Richard Wolff +Gordon Worley +Thomas Wouters +Doug Wyatt +Ka-Ping Yee +Bob Yodlowski +Danny Yoo +George Yoshida +Masazumi Yoshikawa +Bernard Yue +Moshe Zadka +Milan Zamazal +Artur Zaprzala +Mike Zarnstorff +Siebren van der Zee +Uwe Zessin diff --git a/sys/src/cmd/python/Misc/AIX-NOTES b/sys/src/cmd/python/Misc/AIX-NOTES new file mode 100644 index 000000000..613d501d4 --- /dev/null +++ b/sys/src/cmd/python/Misc/AIX-NOTES @@ -0,0 +1,155 @@ +Subject: AIX - Misc/AIX-NOTES +From: Vladimir Marangozov <Vladimir.Marangozov@imag.fr> +To: guido@CNRI.Reston.Va.US (Guido van Rossum) +Date: Wed, 6 Aug 1997 11:41:00 +0200 (EET) + +============================================================================== + COMPILER INFORMATION +------------------------------------------------------------------------------ + +(1) A problem has been reported with "make test" failing because of "weird + indentation." Searching the comp.lang.python newsgroup reveals several + threads on this subject, and it seems to be a compiler bug in an old + version of the AIX CC compiler. However, the compiler/OS combination + which has this problem is not identified. In preparation for the 1.4 + release, Vladimir Marangozov (Vladimir.Marangozov@imag.fr) and Manus Hand + (mhand@csn.net) reported no such troubles for the following compilers and + operating system versions: + AIX C compiler version 3.1.2 on AIX 4.1.3 and AIX 4.1.4 + AIX C compiler version 1.3.0 on AIX 3.2.5 + If you have this problem, please report the compiler/OS version. + +(2) Stefan Esser (se@MI.Uni-Koeln.DE), in work done to compile Python + 1.0.0 on AIX 3.2.4, reports that AIX compilers don't like the LANG + environment varaiable set to European locales. This makes the compiler + generate floating point constants using "," as the decimal seperator, + which the assembler doesn't understand (or perhaps it is the other way + around, with the assembler expecting, but not getting "," in float + numbers). "LANG=C; export LANG" solves the problem, as does + "LANG=C $(MAKE) ..." in the master Makefile. + +(3) The cc (or xlc) compiler considers "Python/ceval.c" too complex to + optimize, except when invoked with "-qmaxmem=4000" + +(4) Some problems (due to _AIX not being #defined) when python 1.0.0 was + compiled using 'gcc -ansi' were reported by Stefan Esser, but were not + investigated. + +(5) The cc compiler has internal variables named "__abs" and "__div". These + names are reserved and may not be used as program variables in compiled + source. (As an anecdote in support of this, the implementation of + Python/operator.c had this problem in the 1.4 beta releases, and the + solution was to re#define some core-source variables having these names, + to give these python variables different names if the build is being done + on AIX.) + +(6) As mentioned in the README, builds done immediately after previous builds + (without "make clean" or "make clobber") sometimes fail for mysterious + reasons. There are some unpredictable results when the configuration + is changed (that is, if you "configure" with different parameters) or if + intermediate changes are made to some files. Performing "make clean" or + "make clobber" resolves the problems. + +============================================================================== + THREAD SUPPORT +------------------------------------------------------------------------------ + +As of AIX version 4, there are two (incompatible) types of pthreads on AIX: + a) AIX DCE pthreads (on AIX 3.2.5) + b) AIX 4 pthreads (on AIX 4.1 and up) +Support has been added to Python to handle the distinction. + +The cc and gcc compilers do not initialize pthreads properly. The only +compilers that can initialize pthreads properly are IBM *_r* compilers, +which use the crt0_r.o module, and which invoke ld with the reentrant +version of libc (libc_r). + +In order to enable thread support, follow these steps: + 1. Uncomment the thread module in Modules/Setup + 2. configure --without-gcc --with-thread ... + 3. make CC="cc_r" OPT="-O -qmaxmem=4000" + +For example, to make with both threads and readline, use: + ./configure --without-gcc --with-thread --with-readline=/usr/local/lib + make CC=cc_r OPT="-O2 -qmaxmem=4000" + +If the "make" which is used ignores the "CC=cc_r" directive, one could alias +the cc command to cc_r (for example, in C-shell, perform an "alias cc cc_r"). + +Vladimir Marangozov (Vladimir.Marangozov@imag.fr) provided this information, +and he reports that a cc_r build initializes threads properly and that all +demos on threads run okay with cc_r. + +============================================================================== + SHARED LIBRARY SUPPORT +------------------------------------------------------------------------------ + +AIX shared library support was added to Python in the 1.4 release by Manus +Hand (mhand@csn.net) and Vladimir Marangozov (Vladimir.Marangozov@imag.fr). + +Python modules may now be built as shared libraries on AIX using the normal +process of uncommenting the "*shared*" line in Modules/Setup before the +build. + +AIX shared libraries require that an "export" and "import" file be provided +at compile time to list all extern symbols which may be shared between +modules. The "export" file (named python.exp) for the modules and the +libraries that belong to the Python core is created by the "makexp_aix" +script before performing the link of the python binary. It lists all global +symbols (exported during the link) of the modules and the libraries that +make up the python executable. + +When shared library modules (.so files) are made, a second shell script +is invoked. This script is named "ld_so_aix" and is also provided with +the distribution in the Modules subdirectory. This script acts as an "ld" +wrapper which hides the explicit management of "export" and "import" files; +it adds the appropriate arguments (in the appropriate order) to the link +command that creates the shared module. Among other things, it specifies +that the "python.exp" file is an "import" file for the shared module. + +At the time of this writing, neither the python.exp file nor the makexp_aix +or ld_so_aix scripts are installed by the make procedure, so you should +remember to keep these and/or copy them to a different location for +safekeeping if you wish to use them to add shared extension modules to +python. However, if the make process has been updated since this writing, +these files MAY have been installed for you during the make by the +LIBAINSTALL rule, in which case the need to make safe copies is obviated. + +If you wish to add a shared extension module to the language, you would follow +the steps given in the example below (the example adds the shared extension +module "spam" to python): + 1. Make sure that "ld_so_aix" and "makexp_aix" are in your path. + 2. The "python.exp" file should be in the current directory. + 3. Issue the following commands or include them in your Makefile: + cc -c spammodule.c + ld_so_aix cc spammodule.o -o spammodule.so + +For more detailed information on the shared library support, examine the +contents of the "ld_so_aix" and "makexp_aix" scripts or refer to the AIX +documentation. + +NOTE: If the extension module is written in C++ and contains templates, + an alternative to "ld_so_aix" is the /usr/lpp/xlC/bin/makeC++SharedLib + script. Chris Myers (myers@TC.Cornell.EDU) reports that ld_so_aix + works well for some C++ (including the C++ that is generated + automatically by the Python SWIG package [SWIG can be found at + http://www.cs.utah.edu/~beazley/SWIG/swig.html]). However, it is not + known whether makeC++SharedLib can be used as a complete substitute + for ld_so_aix. + +According to Gary Hook from IBM, the format of the export file changed +in AIX 4.2. For AIX 4.2 and later, a period "." is required on the +first line after "#!". If python crashes while importing a shared +library, you can try modifying the LINKCC variable in the Makefile. +It probably looks like this: + + LINKCC= $(srcdir)/Modules/makexp_aix Modules/python.exp \"\" $(LIBRARY); $(PURIFY) $(CXX) + +You should modify the \"\" to be a period: + + LINKCC= $(srcdir)/Modules/makexp_aix Modules/python.exp . $(LIBRARY); $(PURIFY) $(CXX) + +Using a period fixed the problem in the snake farm. YMMV. +This fix has been incorporated into Python 2.3. + +============================================================================== diff --git a/sys/src/cmd/python/Misc/BeOS-NOTES b/sys/src/cmd/python/Misc/BeOS-NOTES new file mode 100644 index 000000000..41f25a7f2 --- /dev/null +++ b/sys/src/cmd/python/Misc/BeOS-NOTES @@ -0,0 +1,43 @@ +Python for BeOS R5 + +In Python-2.1, the standard version of the new setup.py program +will not build the full complement of modules on BeOS. Instead, +please replace it with the special BeOS version in Misc/BeOS-setup.py. + +To build, + + 1) cp Misc/BeOS-setup.py setup.py + 2) ./configure --prefix=/boot/home/config + 3) make + +The modules will all build, except termios which assumes some flags +we don't have. Put a libreadline.a in /boot/home/config/lib to get +a readline.so for your interactive editing convenience; NB, not +libreadline.so, you want to link a static readline library into the +dynamically loaded Python module. + +Test: + + make test + + The BeOS is Not UNIX category: + - test_select crashed -- select.error : (-2147459072, 'Bad file descriptor') + - test_socket crashed -- exceptions.AttributeError : SOCK_RAW + - test_fcntl crashed -- exceptions.IOError: [Errno -2147483643] Invalid argument + + This one is funny! BeOS does support large files, and that's why + we get this error: the file is too big for my filesystem! + - test_largefile crashed -- exceptions.IOError: [Errno -2147459065] + No space left on device + + - test_pickle crashed. This is apparently a serious problem, "complex" + number objects reconstructed from a pickle don't compare equal to + their ancestors. But it happens on BeOS PPC only, not Intel. + +Install: + + make install + + +- Donn Cave (donn@oz.net) + October 4, 2000 diff --git a/sys/src/cmd/python/Misc/BeOS-setup.py b/sys/src/cmd/python/Misc/BeOS-setup.py new file mode 100644 index 000000000..991e608fa --- /dev/null +++ b/sys/src/cmd/python/Misc/BeOS-setup.py @@ -0,0 +1,574 @@ +# Autodetecting setup.py script for building the Python extensions +# +# Modified for BeOS build. Donn Cave, March 27 2001. + +__version__ = "special BeOS after 1.37" + +import sys, os, getopt +from distutils import sysconfig +from distutils import text_file +from distutils.errors import * +from distutils.core import Extension, setup +from distutils.command.build_ext import build_ext + +# This global variable is used to hold the list of modules to be disabled. +disabled_module_list = ['dbm', 'mmap', 'resource', 'nis'] + +def find_file(filename, std_dirs, paths): + """Searches for the directory where a given file is located, + and returns a possibly-empty list of additional directories, or None + if the file couldn't be found at all. + + 'filename' is the name of a file, such as readline.h or libcrypto.a. + 'std_dirs' is the list of standard system directories; if the + file is found in one of them, no additional directives are needed. + 'paths' is a list of additional locations to check; if the file is + found in one of them, the resulting list will contain the directory. + """ + + # Check the standard locations + for dir in std_dirs: + f = os.path.join(dir, filename) + if os.path.exists(f): return [] + + # Check the additional directories + for dir in paths: + f = os.path.join(dir, filename) + if os.path.exists(f): + return [dir] + + # Not found anywhere + return None + +def find_library_file(compiler, libname, std_dirs, paths): + filename = compiler.library_filename(libname, lib_type='shared') + result = find_file(filename, std_dirs, paths) + if result is not None: return result + + filename = compiler.library_filename(libname, lib_type='static') + result = find_file(filename, std_dirs, paths) + return result + +def module_enabled(extlist, modname): + """Returns whether the module 'modname' is present in the list + of extensions 'extlist'.""" + extlist = [ext for ext in extlist if ext.name == modname] + return len(extlist) + +class PyBuildExt(build_ext): + + def build_extensions(self): + + # Detect which modules should be compiled + self.detect_modules() + + # Remove modules that are present on the disabled list + self.extensions = [ext for ext in self.extensions + if ext.name not in disabled_module_list] + + # Fix up the autodetected modules, prefixing all the source files + # with Modules/ and adding Python's include directory to the path. + (srcdir,) = sysconfig.get_config_vars('srcdir') + + # Figure out the location of the source code for extension modules + moddir = os.path.join(os.getcwd(), srcdir, 'Modules') + moddir = os.path.normpath(moddir) + srcdir, tail = os.path.split(moddir) + srcdir = os.path.normpath(srcdir) + moddir = os.path.normpath(moddir) + + # Fix up the paths for scripts, too + self.distribution.scripts = [os.path.join(srcdir, filename) + for filename in self.distribution.scripts] + + for ext in self.extensions[:]: + ext.sources = [ os.path.join(moddir, filename) + for filename in ext.sources ] + ext.include_dirs.append( '.' ) # to get config.h + ext.include_dirs.append( os.path.join(srcdir, './Include') ) + + # If a module has already been built statically, + # don't build it here + if ext.name in sys.builtin_module_names: + self.extensions.remove(ext) + + # Parse Modules/Setup to figure out which modules are turned + # on in the file. + input = text_file.TextFile('Modules/Setup', join_lines=1) + remove_modules = [] + while 1: + line = input.readline() + if not line: break + line = line.split() + remove_modules.append( line[0] ) + input.close() + + for ext in self.extensions[:]: + if ext.name in remove_modules: + self.extensions.remove(ext) + + # When you run "make CC=altcc" or something similar, you really want + # those environment variables passed into the setup.py phase. Here's + # a small set of useful ones. + compiler = os.environ.get('CC') + linker_so = os.environ.get('LDSHARED') + args = {} + # unfortunately, distutils doesn't let us provide separate C and C++ + # compilers + if compiler is not None: + args['compiler_so'] = compiler + if linker_so is not None: + args['linker_so'] = linker_so + ' -shared' + self.compiler.set_executables(**args) + + build_ext.build_extensions(self) + + def build_extension(self, ext): + + try: + build_ext.build_extension(self, ext) + except (CCompilerError, DistutilsError), why: + self.announce('WARNING: building of extension "%s" failed: %s' % + (ext.name, sys.exc_info()[1])) + + def get_platform (self): + # Get value of sys.platform + platform = sys.platform + if platform[:6] =='cygwin': + platform = 'cygwin' + elif platform[:4] =='beos': + platform = 'beos' + + return platform + + def detect_modules(self): + try: + belibs = os.environ['BELIBRARIES'].split(';') + except KeyError: + belibs = ['/boot/beos/system/lib'] + belibs.append('/boot/home/config/lib') + self.compiler.library_dirs.append('/boot/home/config/lib') + try: + beincl = os.environ['BEINCLUDES'].split(';') + except KeyError: + beincl = [] + beincl.append('/boot/home/config/include') + self.compiler.include_dirs.append('/boot/home/config/include') + # lib_dirs and inc_dirs are used to search for files; + # if a file is found in one of those directories, it can + # be assumed that no additional -I,-L directives are needed. + lib_dirs = belibs + inc_dirs = beincl + exts = [] + + platform = self.get_platform() + + # Check for MacOS X, which doesn't need libm.a at all + math_libs = ['m'] + if platform in ['Darwin1.2', 'beos']: + math_libs = [] + + # XXX Omitted modules: gl, pure, dl, SGI-specific modules + + # + # The following modules are all pretty straightforward, and compile + # on pretty much any POSIXish platform. + # + + # Some modules that are normally always on: + exts.append( Extension('_weakref', ['_weakref.c']) ) + exts.append( Extension('_symtable', ['symtablemodule.c']) ) + + # array objects + exts.append( Extension('array', ['arraymodule.c']) ) + # complex math library functions + exts.append( Extension('cmath', ['cmathmodule.c'], + libraries=math_libs) ) + + # math library functions, e.g. sin() + exts.append( Extension('math', ['mathmodule.c'], + libraries=math_libs) ) + # fast string operations implemented in C + exts.append( Extension('strop', ['stropmodule.c']) ) + # time operations and variables + exts.append( Extension('time', ['timemodule.c'], + libraries=math_libs) ) + # operator.add() and similar goodies + exts.append( Extension('operator', ['operator.c']) ) + # access to the builtin codecs and codec registry + exts.append( Extension('_codecs', ['_codecsmodule.c']) ) + # Python C API test module + exts.append( Extension('_testcapi', ['_testcapimodule.c']) ) + # static Unicode character database + exts.append( Extension('unicodedata', ['unicodedata.c']) ) + # access to ISO C locale support + exts.append( Extension('_locale', ['_localemodule.c']) ) + + # Modules with some UNIX dependencies -- on by default: + # (If you have a really backward UNIX, select and socket may not be + # supported...) + + # fcntl(2) and ioctl(2) + exts.append( Extension('fcntl', ['fcntlmodule.c']) ) + # pwd(3) + exts.append( Extension('pwd', ['pwdmodule.c']) ) + # grp(3) + exts.append( Extension('grp', ['grpmodule.c']) ) + # posix (UNIX) errno values + exts.append( Extension('errno', ['errnomodule.c']) ) + # select(2); not on ancient System V + exts.append( Extension('select', ['selectmodule.c']) ) + + # The md5 module implements the RSA Data Security, Inc. MD5 + # Message-Digest Algorithm, described in RFC 1321. The necessary files + # md5c.c and md5.h are included here. + exts.append( Extension('md5', ['md5module.c', 'md5c.c']) ) + + # The sha module implements the SHA checksum algorithm. + # (NIST's Secure Hash Algorithm.) + exts.append( Extension('sha', ['shamodule.c']) ) + + # Helper module for various ascii-encoders + exts.append( Extension('binascii', ['binascii.c']) ) + + # Fred Drake's interface to the Python parser + exts.append( Extension('parser', ['parsermodule.c']) ) + + # cStringIO and cPickle + exts.append( Extension('cStringIO', ['cStringIO.c']) ) + exts.append( Extension('cPickle', ['cPickle.c']) ) + + # Memory-mapped files (also works on Win32). + exts.append( Extension('mmap', ['mmapmodule.c']) ) + + # Lance Ellinghaus's syslog daemon interface + exts.append( Extension('syslog', ['syslogmodule.c']) ) + + # George Neville-Neil's timing module: + exts.append( Extension('timing', ['timingmodule.c']) ) + + # + # Here ends the simple stuff. From here on, modules need certain + # libraries, are platform-specific, or present other surprises. + # + + # Multimedia modules + # These don't work for 64-bit platforms!!! + # These represent audio samples or images as strings: + + # Disabled on 64-bit platforms + if sys.maxint != 9223372036854775807L: + # Operations on audio samples + exts.append( Extension('audioop', ['audioop.c']) ) + # Operations on images + exts.append( Extension('imageop', ['imageop.c']) ) + # Read SGI RGB image files (but coded portably) + exts.append( Extension('rgbimg', ['rgbimgmodule.c']) ) + + # readline + if self.compiler.find_library_file(lib_dirs, 'readline'): + readline_libs = ['readline'] + if self.compiler.find_library_file(lib_dirs + + ['/usr/lib/termcap'], + 'termcap'): + readline_libs.append('termcap') + exts.append( Extension('readline', ['readline.c'], + library_dirs=['/usr/lib/termcap'], + libraries=readline_libs) ) + + # The crypt module is now disabled by default because it breaks builds + # on many systems (where -lcrypt is needed), e.g. Linux (I believe). + + if self.compiler.find_library_file(lib_dirs, 'crypt'): + libs = ['crypt'] + else: + libs = [] + exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) ) + + # socket(2) + # Detect SSL support for the socket module + ssl_incs = find_file('openssl/ssl.h', inc_dirs, + ['/usr/local/ssl/include', + '/usr/contrib/ssl/include/' + ] + ) + ssl_libs = find_library_file(self.compiler, 'ssl',lib_dirs, + ['/usr/local/ssl/lib', + '/usr/contrib/ssl/lib/' + ] ) + + if (ssl_incs is not None and + ssl_libs is not None): + exts.append( Extension('_socket', ['socketmodule.c'], + include_dirs = ssl_incs, + library_dirs = ssl_libs, + libraries = ['ssl', 'crypto'], + define_macros = [('USE_SSL',1)] ) ) + else: + exts.append( Extension('_socket', ['socketmodule.c']) ) + + # Modules that provide persistent dictionary-like semantics. You will + # probably want to arrange for at least one of them to be available on + # your machine, though none are defined by default because of library + # dependencies. The Python module anydbm.py provides an + # implementation independent wrapper for these; dumbdbm.py provides + # similar functionality (but slower of course) implemented in Python. + + # The standard Unix dbm module: + if platform not in ['cygwin']: + if (self.compiler.find_library_file(lib_dirs, 'ndbm')): + exts.append( Extension('dbm', ['dbmmodule.c'], + libraries = ['ndbm'] ) ) + else: + exts.append( Extension('dbm', ['dbmmodule.c']) ) + + # Anthony Baxter's gdbm module. GNU dbm(3) will require -lgdbm: + if (self.compiler.find_library_file(lib_dirs, 'gdbm')): + exts.append( Extension('gdbm', ['gdbmmodule.c'], + libraries = ['gdbm'] ) ) + + # Berkeley DB interface. + # + # This requires the Berkeley DB code, see + # ftp://ftp.cs.berkeley.edu/pub/4bsd/db.1.85.tar.gz + # + # Edit the variables DB and DBPORT to point to the db top directory + # and the subdirectory of PORT where you built it. + # + # (See http://electricrain.com/greg/python/bsddb3/ for an interface to + # BSD DB 3.x.) + + dblib = [] + if self.compiler.find_library_file(lib_dirs, 'db'): + dblib = ['db'] + + db185_incs = find_file('db_185.h', inc_dirs, + ['/usr/include/db3', '/usr/include/db2']) + db_inc = find_file('db.h', inc_dirs, ['/usr/include/db1']) + if db185_incs is not None: + exts.append( Extension('bsddb', ['bsddbmodule.c'], + include_dirs = db185_incs, + define_macros=[('HAVE_DB_185_H',1)], + libraries = dblib ) ) + elif db_inc is not None: + exts.append( Extension('bsddb', ['bsddbmodule.c'], + include_dirs = db_inc, + libraries = dblib) ) + + # Unix-only modules + if platform not in ['mac', 'win32']: + # Steen Lumholt's termios module + exts.append( Extension('termios', ['termios.c']) ) + # Jeremy Hylton's rlimit interface + if platform not in ['cygwin']: + exts.append( Extension('resource', ['resource.c']) ) + + # Generic dynamic loading module + #exts.append( Extension('dl', ['dlmodule.c']) ) + + # Sun yellow pages. Some systems have the functions in libc. + if platform not in ['cygwin']: + if (self.compiler.find_library_file(lib_dirs, 'nsl')): + libs = ['nsl'] + else: + libs = [] + exts.append( Extension('nis', ['nismodule.c'], + libraries = libs) ) + + # Curses support, requring the System V version of curses, often + # provided by the ncurses library. + if (self.compiler.find_library_file(lib_dirs, 'ncurses')): + curses_libs = ['ncurses'] + exts.append( Extension('_curses', ['_cursesmodule.c'], + libraries = curses_libs) ) + elif (self.compiler.find_library_file(lib_dirs, 'curses')): + if (self.compiler.find_library_file(lib_dirs, 'terminfo')): + curses_libs = ['curses', 'terminfo'] + else: + curses_libs = ['curses', 'termcap'] + + exts.append( Extension('_curses', ['_cursesmodule.c'], + libraries = curses_libs) ) + + # If the curses module is enabled, check for the panel module + if (os.path.exists('Modules/_curses_panel.c') and + module_enabled(exts, '_curses') and + self.compiler.find_library_file(lib_dirs, 'panel')): + exts.append( Extension('_curses_panel', ['_curses_panel.c'], + libraries = ['panel'] + curses_libs) ) + + + + # Lee Busby's SIGFPE modules. + # The library to link fpectl with is platform specific. + # Choose *one* of the options below for fpectl: + + if platform == 'irix5': + # For SGI IRIX (tested on 5.3): + exts.append( Extension('fpectl', ['fpectlmodule.c'], + libraries=['fpe']) ) + elif 0: # XXX how to detect SunPro? + # For Solaris with SunPro compiler (tested on Solaris 2.5 with SunPro C 4.2): + # (Without the compiler you don't have -lsunmath.) + #fpectl fpectlmodule.c -R/opt/SUNWspro/lib -lsunmath -lm + pass + else: + # For other systems: see instructions in fpectlmodule.c. + #fpectl fpectlmodule.c ... + exts.append( Extension('fpectl', ['fpectlmodule.c']) ) + + + # Andrew Kuchling's zlib module. + # This require zlib 1.1.3 (or later). + # See http://www.gzip.org/zlib/ + if (self.compiler.find_library_file(lib_dirs, 'z')): + exts.append( Extension('zlib', ['zlibmodule.c'], + libraries = ['z']) ) + + # Interface to the Expat XML parser + # + # Expat is written by James Clark and must be downloaded separately + # (see below). The pyexpat module was written by Paul Prescod after a + # prototype by Jack Jansen. + # + # The Expat dist includes Windows .lib and .dll files. Home page is + # at http://www.jclark.com/xml/expat.html, the current production + # release is always ftp://ftp.jclark.com/pub/xml/expat.zip. + # + # EXPAT_DIR, below, should point to the expat/ directory created by + # unpacking the Expat source distribution. + # + # Note: the expat build process doesn't yet build a libexpat.a; you + # can do this manually while we try convince the author to add it. To + # do so, cd to EXPAT_DIR, run "make" if you have not done so, then + # run: + # + # ar cr libexpat.a xmltok/*.o xmlparse/*.o + # + expat_defs = [] + expat_incs = find_file('expat.h', inc_dirs, []) + if expat_incs is not None: + # expat.h was found + expat_defs = [('HAVE_EXPAT_H', 1)] + else: + expat_incs = find_file('xmlparse.h', inc_dirs, []) + + if (expat_incs is not None and + self.compiler.find_library_file(lib_dirs, 'expat')): + exts.append( Extension('pyexpat', ['pyexpat.c'], + define_macros = expat_defs, + libraries = ['expat']) ) + + # Platform-specific libraries + if platform == 'linux2': + # Linux-specific modules + exts.append( Extension('linuxaudiodev', ['linuxaudiodev.c']) ) + + if platform == 'sunos5': + # SunOS specific modules + exts.append( Extension('sunaudiodev', ['sunaudiodev.c']) ) + + self.extensions.extend(exts) + + # Call the method for detecting whether _tkinter can be compiled + self.detect_tkinter(inc_dirs, lib_dirs) + + + def detect_tkinter(self, inc_dirs, lib_dirs): + # The _tkinter module. + + # Assume we haven't found any of the libraries or include files + tcllib = tklib = tcl_includes = tk_includes = None + for version in ['8.4', '8.3', '8.2', '8.1', '8.0']: + tklib = self.compiler.find_library_file(lib_dirs, + 'tk' + version ) + tcllib = self.compiler.find_library_file(lib_dirs, + 'tcl' + version ) + if tklib and tcllib: + # Exit the loop when we've found the Tcl/Tk libraries + break + + # Now check for the header files + if tklib and tcllib: + # Check for the include files on Debian, where + # they're put in /usr/include/{tcl,tk}X.Y + debian_tcl_include = [ '/usr/include/tcl' + version ] + debian_tk_include = [ '/usr/include/tk' + version ] + debian_tcl_include + tcl_includes = find_file('tcl.h', inc_dirs, debian_tcl_include) + tk_includes = find_file('tk.h', inc_dirs, debian_tk_include) + + if (tcllib is None or tklib is None and + tcl_includes is None or tk_includes is None): + # Something's missing, so give up + return + + # OK... everything seems to be present for Tcl/Tk. + + include_dirs = [] ; libs = [] ; defs = [] ; added_lib_dirs = [] + for dir in tcl_includes + tk_includes: + if dir not in include_dirs: + include_dirs.append(dir) + + # Check for various platform-specific directories + platform = self.get_platform() + if platform == 'sunos5': + include_dirs.append('/usr/openwin/include') + added_lib_dirs.append('/usr/openwin/lib') + elif os.path.exists('/usr/X11R6/include'): + include_dirs.append('/usr/X11R6/include') + added_lib_dirs.append('/usr/X11R6/lib') + elif os.path.exists('/usr/X11R5/include'): + include_dirs.append('/usr/X11R5/include') + added_lib_dirs.append('/usr/X11R5/lib') + else: + # Assume default location for X11 + include_dirs.append('/usr/X11/include') + added_lib_dirs.append('/usr/X11/lib') + + # Check for BLT extension + if self.compiler.find_library_file(lib_dirs + added_lib_dirs, 'BLT8.0'): + defs.append( ('WITH_BLT', 1) ) + libs.append('BLT8.0') + + # Add the Tcl/Tk libraries + libs.append('tk'+version) + libs.append('tcl'+version) + + if platform in ['aix3', 'aix4']: + libs.append('ld') + + # Finally, link with the X11 libraries + libs.append('X11') + + ext = Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'], + define_macros=[('WITH_APPINIT', 1)] + defs, + include_dirs = include_dirs, + libraries = libs, + library_dirs = added_lib_dirs, + ) + self.extensions.append(ext) + + # XXX handle these, but how to detect? + # *** Uncomment and edit for PIL (TkImaging) extension only: + # -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \ + # *** Uncomment and edit for TOGL extension only: + # -DWITH_TOGL togl.c \ + # *** Uncomment these for TOGL extension only: + # -lGL -lGLU -lXext -lXmu \ + +def main(): + setup(name = 'Python standard library', + version = '%d.%d' % sys.version_info[:2], + cmdclass = {'build_ext':PyBuildExt}, + # The struct module is defined here, because build_ext won't be + # called unless there's at least one extension module defined. + ext_modules=[Extension('struct', ['structmodule.c'])], + + # Scripts to install + scripts = ['Tools/scripts/pydoc'] + ) + +# --install-platlib +if __name__ == '__main__': + sysconfig.set_python_build() + main() diff --git a/sys/src/cmd/python/Misc/HISTORY b/sys/src/cmd/python/Misc/HISTORY new file mode 100644 index 000000000..ea242db3c --- /dev/null +++ b/sys/src/cmd/python/Misc/HISTORY @@ -0,0 +1,15303 @@ +Python History +-------------- + +This file contains the release messages for previous Python releases. +As you read on you go back to the dark ages of Python's history. + + +====================================================================== + + +What's New in Python 2.4 final? +=============================== + +*Release date: 30-NOV-2004* + +Core and builtins +----------------- + +- Bug 875692: Improve signal handling, especially when using threads, by + forcing an early re-execution of PyEval_EvalFrame() "periodic" code when + things_to_do is not cleared by Py_MakePendingCalls(). + + +What's New in Python 2.4 (release candidate 1) +============================================== + +*Release date: 18-NOV-2004* + +Core and builtins +----------------- + +- Bug 1061968: Fixes in 2.4a3 to address thread bug 1010677 reintroduced + the years-old thread shutdown race bug 225673. Numeric history lesson + aside, all bugs in all three reports are fixed now. + + +Library +------- + +- Bug 1052242: If exceptions are raised by an atexit handler function an + attempt is made to execute the remaining handlers. The last exception + raised is re-raised. + +- ``doctest``'s new support for adding ``pdb.set_trace()`` calls to + doctests was broken in a dramatic but shallow way. Fixed. + +- Bug 1065388: ``calendar``'s ``day_name``, ``day_abbr``, ``month_name``, + and ``month_abbr`` attributes emulate sequences of locale-correct + spellings of month and day names. Because the locale can change at + any time, the correct spelling is recomputed whenever one of these is + indexed. In the worst case, the index may be a slice object, so these + recomputed every day or month name each time they were indexed. This is + much slower than necessary in the usual case, when the index is just an + integer. In that case, only the single spelling needed is recomputed + now; and, when the index is a slice object, only the spellings needed + by the slice are recomputed now. + +- Patch 1061679: Added ``__all__`` to pickletools.py. + +Build +----- + +- Bug 1034277 / Patch 1035255: Remove compilation of core against CoreServices + and CoreFoundation on OS X. Involved removing PyMac_GetAppletScriptFile() + which has no known users. Thanks Bob Ippolito. + +C API +----- + +- The PyRange_New() function is deprecated. + + +What's New in Python 2.4 beta 2? +================================ + +*Release date: 03-NOV-2004* + +License +------- + +The Python Software Foundation changed the license under which Python +is released, to remove Python version numbers. There were no other +changes to the license. So, for example, wherever the license for +Python 2.3 said "Python 2.3", the new license says "Python". The +intent is to make it possible to refer to the PSF license in a more +durable way. For example, some people say they're confused by that +the Open Source Initiative's entry for the Python Software Foundation +License:: + + http://www.opensource.org/licenses/PythonSoftFoundation.php + +says "Python 2.1.1" all over it, wondering whether it applies only +to Python 2.1.1. + +The official name of the new license is the Python Software Foundation +License Version 2. + +Core and builtins +----------------- + +- Bug #1055820 Cyclic garbage collection was not protecting against that + calling a live weakref to a piece of cyclic trash could resurrect an + insane mutation of the trash if any Python code ran during gc (via + running a dead object's __del__ method, running another callback on a + weakref to a dead object, or via any Python code run in any other thread + that managed to obtain the GIL while a __del__ or callback was running + in the thread doing gc). The most likely symptom was "impossible" + ``AttributeError`` exceptions, appearing seemingly at random, on weakly + referenced objects. The cure was to clear all weakrefs to unreachable + objects before allowing any callbacks to run. + +- Bug #1054139 _PyString_Resize() now invalidates its cached hash value. + +Extension Modules +----------------- + +- Bug #1048870: the compiler now generates distinct code objects for + functions with identical bodies. This was producing confusing + traceback messages which pointed to the function where the code + object was first defined rather than the function being executed. + +Library +------- + +- Patch #1056967 changes the semantics of Template.safe_substitute() so that + no ValueError is raised on an 'invalid' match group. Now the delimiter is + returned. + +- Bug #1052503 pdb.runcall() was not passing along keyword arguments. + +- Bug #902037: XML.sax.saxutils.prepare_input_source() now combines relative + paths with a base path before checking os.path.isfile(). + +- The whichdb module can now be run from the command line. + +- Bug #1045381: time.strptime() can now infer the date using %U or %W (week of + the year) when the day of the week and year are also specified. + +- Bug #1048816: fix bug in Ctrl-K at start of line in curses.textpad.Textbox + +- Bug #1017553: fix bug in tarfile.filemode() + +- Patch #737473: fix bug that old source code is shown in tracebacks even if + the source code is updated and reloaded. + +Build +----- + +- Patch #1044395: --enable-shared is allowed in FreeBSD also. + +What's New in Python 2.4 beta 1? +================================ + +*Release date: 15-OCT-2004* + +Core and builtins +----------------- + +- Patch #975056: Restartable signals were not correctly disabled on + BSD systems. Consistently use PyOS_setsig() instead of signal(). + +- The internal portable implementation of thread-local storage (TLS), used + by the ``PyGILState_Ensure()``/``PyGILState_Release()`` API, was not + thread-correct. This could lead to a variety of problems, up to and + including segfaults. See bug 1041645 for an example. + +- Added a command line option, -m module, which searches sys.path for the + module and then runs it. (Contributed by Nick Coghlan.) + +- The bytecode optimizer now folds tuples of constants into a single + constant. + +- SF bug #513866: Float/long comparison anomaly. Prior to 2.4b1, when + an integer was compared to a float, the integer was coerced to a float. + That could yield spurious overflow errors (if the integer was very + large), and to anomalies such as + ``long(1e200)+1 == 1e200 == long(1e200)-1``. Coercion to float is no + longer performed, and cases like ``long(1e200)-1 < 1e200``, + ``long(1e200)+1 > 1e200`` and ``(1 << 20000) > 1e200`` are computed + correctly now. + +Extension modules +----------------- + +- ``collections.deque`` objects didn't play quite right with garbage + collection, which could lead to a segfault in a release build, or + an assert failure in a debug build. Also, added overflow checks, + better detection of mutation during iteration, and shielded deque + comparisons from unusual subclass overrides of the __iter__() method. + +Library +------- + +- Patch 1046644: distutils build_ext grew two new options - --swig for + specifying the swig executable to use, and --swig-opts to specify + options to pass to swig. --swig-opts="-c++" is the new way to spell + --swig-cpp. + +- Patch 983206: distutils now obeys environment variable LDSHARED, if + it is set. + +- Added Peter Astrand's subprocess.py module. See PEP 324 for details. + +- time.strptime() now properly escapes timezones and all other locale-specific + strings for regex-specific symbols. Was breaking under Japanese Windows when + the timezone was specified as "Tokyo (standard time)". + Closes bug #1039270. + +- Updates for the email package: + + + email.Utils.formatdate() grew a 'usegmt' argument for HTTP support. + + All deprecated APIs that in email 2.x issued warnings have been removed: + _encoder argument to the MIMEText constructor, Message.add_payload(), + Utils.dump_address_pair(), Utils.decode(), Utils.encode() + + New deprecations: Generator.__call__(), Message.get_type(), + Message.get_main_type(), Message.get_subtype(), the 'strict' argument to + the Parser constructor. These will be removed in email 3.1. + + Support for Python earlier than 2.3 has been removed (see PEP 291). + + All defect classes have been renamed to end in 'Defect'. + + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be + added to messages that claim to be multipart but really aren't. + + Updates to documentation. + +- re's findall() and finditer() functions now take an optional flags argument + just like the compile(), search(), and match() functions. Also, documented + the previously existing start and stop parameters for the findall() and + finditer() methods of regular expression objects. + +- rfc822 Messages now support iterating over the headers. + +- The (undocumented) tarfile.Tarfile.membernames has been removed; + applications should use the getmember function. + +- httplib now offers symbolic constants for the HTTP status codes. + +- SF bug #1028306: Trying to compare a ``datetime.date`` to a + ``datetime.datetime`` mistakenly compared only the year, month and day. + Now it acts like a mixed-type comparison: ``False`` for ``==``, + ``True`` for ``!=``, and raises ``TypeError`` for other comparison + operators. Because datetime is a subclass of date, comparing only the + base class (date) members can still be done, if that's desired, by + forcing using of the approprate date method; e.g., + ``a_date.__eq__(a_datetime)`` is true if and only if the year, month + and day members of ``a_date`` and ``a_datetime`` are equal. + +- bdist_rpm now supports command line options --force-arch, + {pre,post}-install, {pre,post}-uninstall, and + {prep,build,install,clean,verify}-script. + +- SF patch #998993: The UTF-8 and the UTF-16 stateful decoders now support + decoding incomplete input (when the input stream is temporarily exhausted). + ``codecs.StreamReader`` now implements buffering, which enables proper + readline support for the UTF-16 decoders. ``codecs.StreamReader.read()`` + has a new argument ``chars`` which specifies the number of characters to + return. ``codecs.StreamReader.readline()`` and + ``codecs.StreamReader.readlines()`` have a new argument ``keepends``. + Trailing "\n"s will be stripped from the lines if ``keepends`` is false. + +- The documentation for doctest is greatly expanded, and now covers all + the new public features (of which there are many). + +- ``doctest.master`` was put back in, and ``doctest.testmod()`` once again + updates it. This isn't good, because every ``testmod()`` call + contributes to bloating the "hidden" state of ``doctest.master``, but + some old code apparently relies on it. For now, all we can do is + encourage people to stitch doctests together via doctest's unittest + integration features instead. + +- httplib now handles ipv6 address/port pairs. + +- SF bug #1017864: ConfigParser now correctly handles default keys, + processing them with ``ConfigParser.optionxform`` when supplied, + consistent with the handling of config file entries and runtime-set + options. + +- SF bug #997050: Document, test, & check for non-string values in + ConfigParser. Moved the new string-only restriction added in + rev. 1.65 to the SafeConfigParser class, leaving existing + ConfigParser & RawConfigParser behavior alone, and documented the + conditions under which non-string values work. + +Build +----- + +- Building on darwin now includes /opt/local/include and /opt/local/lib for + building extension modules. This is so as to include software installed as + a DarwinPorts port <http://darwinports.opendarwin.org/> + +- pyport.h now defines a Py_IS_NAN macro. It works as-is when the + platform C computes true for ``x != x`` if and only if X is a NaN. + Other platforms can override the default definition with a platform- + specific spelling in that platform's pyconfig.h. You can also override + pyport.h's default Py_IS_INFINITY definition now. + +C API +----- + +- SF patch 1044089: New function ``PyEval_ThreadsInitialized()`` returns + non-zero if PyEval_InitThreads() has been called. + +- The undocumented and unused extern int ``_PyThread_Started`` was removed. + +- The C API calls ``PyInterpreterState_New()`` and ``PyThreadState_New()`` + are two of the very few advertised as being safe to call without holding + the GIL. However, this wasn't true in a debug build, as bug 1041645 + demonstrated. In a debug build, Python redirects the ``PyMem`` family + of calls to Python's small-object allocator, to get the benefit of + its extra debugging capabilities. But Python's small-object allocator + isn't threadsafe, relying on the GIL to avoid the expense of doing its + own locking. ``PyInterpreterState_New()`` and ``PyThreadState_New()`` + call the platform ``malloc()`` directly now, regardless of build type. + +- PyLong_AsUnsignedLong[Mask] now support int objects as well. + +- SF patch #998993: ``PyUnicode_DecodeUTF8Stateful`` and + ``PyUnicode_DecodeUTF16Stateful`` have been added, which implement stateful + decoding. + +Tests +----- + +- test__locale ported to unittest + +Mac +--- + +- ``plistlib`` now supports non-dict root objects. There is also a new + interface for reading and writing plist files: ``readPlist(pathOrFile)`` + and ``writePlist(rootObject, pathOrFile)`` + +Tools/Demos +----------- + +- The text file comparison scripts ``ndiff.py`` and ``diff.py`` now + read the input files in universal-newline mode. This spares them + from consuming a great deal of time to deduce the useless result that, + e.g., a file with Windows line ends and a file with Linux line ends + have no lines in common. + + +What's New in Python 2.4 alpha 3? +================================= + +*Release date: 02-SEP-2004* + +Core and builtins +----------------- + +- SF patch #1007189: ``from ... import ...`` statements now allow the name + list to be surrounded by parentheses. + +- Some speedups for long arithmetic, thanks to Trevor Perrin. Gradeschool + multiplication was sped a little by optimizing the C code. Gradeschool + squaring was sped by about a factor of 2, by exploiting that about half + the digit products are duplicates in a square. Because exponentiation + uses squaring often, this also speeds long power. For example, the time + to compute 17**1000000 dropped from about 14 seconds to 9 on my box due + to this much. The cutoff for Karatsuba multiplication was raised, + since gradeschool multiplication got quicker, and the cutoff was + aggressively small regardless. The exponentiation algorithm was switched + from right-to-left to left-to-right, which is more efficient for small + bases. In addition, if the exponent is large, the algorithm now does + 5 bits (instead of 1 bit) at a time. That cut the time to compute + 17**1000000 on my box in half again, down to about 4.5 seconds. + +- OverflowWarning is no longer generated. PEP 237 scheduled this to + occur in Python 2.3, but since OverflowWarning was disabled by default, + nobody realized it was still being generated. On the chance that user + code is still using them, the Python builtin OverflowWarning, and + corresponding C API PyExc_OverflowWarning, will exist until Python 2.5. + +- Py_InitializeEx has been added. + +- Fix the order of application of decorators. The proper order is bottom-up; + the first decorator listed is the last one called. + +- SF patch #1005778. Fix a seg fault if the list size changed while + calling list.index(). This could happen if a rich comparison function + modified the list. + +- The ``func_name`` (a.k.a. ``__name__``) attribute of user-defined + functions is now writable. + +- code_new (a.k.a new.code()) now checks its arguments sufficiently + carefully that passing them on to PyCode_New() won't trigger calls + to Py_FatalError() or PyErr_BadInternalCall(). It is still the case + that the returned code object might be entirely insane. + +- Subclasses of string can no longer be interned. The semantics of + interning were not clear here -- a subclass could be mutable, for + example -- and had bugs. Explicitly interning a subclass of string + via intern() will raise a TypeError. Internal operations that attempt + to intern a string subclass will have no effect. + +- Bug 1003935: xrange() could report bogus OverflowErrors. Documented + what xrange() intends, and repaired tests accordingly. + +Extension modules +----------------- + +- difflib now supports HTML side-by-side diff. + +- os.urandom has been added for systems that support sources of random + data. + +- Patch 1012740: truncate() on a writeable cStringIO now resets the + position to the end of the stream. This is consistent with the original + StringIO module and avoids inadvertently resurrecting data that was + supposed to have been truncated away. + +- Added socket.socketpair(). + +- Added CurrentByteIndex, CurrentColumnNumber, CurrentLineNumber + members to xml.parsers.expat.XMLParser object. + +- The mpz, rotor, and xreadlines modules, all deprecated in earlier + versions of Python, have now been removed. + +Library +------- + +- Patch #934356: if a module defines __all__, believe that rather than using + heuristics for filtering out imported names. + +- Patch #941486: added os.path.lexists(), which returns True for broken + symlinks, unlike os.path.exists(). + +- the random module now uses os.urandom() for seeding if it is available. + Added a new generator based on os.urandom(). + +- difflib and diff.py can now generate HTML. + +- bdist_rpm now includes version and release in the BuildRoot, and + replaces - by ``_`` in version and release. + +- distutils build/build_scripts now has an -e option to specify the + path to the Python interpreter for installed scripts. + +- PEP 292 classes Template and SafeTemplate are added to the string module. + +- tarfile now generates GNU tar files by default. + +- HTTPResponse has now a getheaders method. + +- Patch #1006219: let inspect.getsource handle '@' decorators. Thanks Simon + Percivall. + +- logging.handlers.SMTPHandler.date_time has been removed; + the class now uses email.Utils.formatdate to generate the time stamp. + +- A new function tkFont.nametofont was added to return an existing + font. The Font class constructor now has an additional exists argument + which, if True, requests to return/configure an existing font, rather + than creating a new one. + +- Updated the decimal package's min() and max() methods to match the + latest revision of the General Decimal Arithmetic Specification. + Quiet NaNs are ignored and equal values are sorted based on sign + and exponent. + +- The decimal package's Context.copy() method now returns deep copies. + +- Deprecated sys.exitfunc in favor of the atexit module. The sys.exitfunc + attribute will be kept around for backwards compatibility and atexit + will just become the one preferred way to do it. + +- patch #675551: Add get_history_item and replace_history_item functions + to the readline module. + +- bug #989672: pdb.doc and the help messages for the help_d and help_u methods + of the pdb.Pdb class gives have been corrected. d(own) goes to a newer + frame, u(p) to an older frame, not the other way around. + +- bug #990669: os.path.realpath() will resolve symlinks before normalizing the + path, as normalizing the path may alter the meaning of the path if it + contains symlinks. + +- bug #851123: shutil.copyfile will raise an exception when trying to copy a + file onto a link to itself. Thanks Gregory Ball. + +- bug #570300: Fix inspect to resolve file locations using os.path.realpath() + so as to properly list all functions in a module when the module itself is + reached through a symlink. Thanks Johannes Gijsbers. + +- doctest refactoring continued. See the docs for details. As part of + this effort, some old and little- (never?) used features are now + deprecated: the Tester class, the module is_private() function, and the + isprivate argument to testmod(). The Tester class supplied a feeble + "by hand" way to combine multiple doctests, if you knew exactly what + you were doing. The newer doctest features for unittest integration + already did a better job of that, are stronger now than ever, and the + new DocTestRunner class is a saner foundation if you want to do it by + hand. The "private name" filtering gimmick was a mistake from the + start, and testmod() changed long ago to ignore it by default. If + you want to filter out tests, the new DocTestFinder class can be used + to return a list of all doctests, and you can filter that list by + any computable criteria before passing it to a DocTestRunner instance. + +- Bug #891637, patch #1005466: fix inspect.getargs() crash on def foo((bar)). + +Tools/Demos +----------- + +- IDLE's shortcut keys for windows are now case insensitive so that + Control-V works the same as Control-v. + +- pygettext.py: Generate POT-Creation-Date header in ISO format. + +Build +----- + +- Backward incompatibility: longintrepr.h now triggers a compile-time + error if SHIFT (the number of bits in a Python long "digit") isn't + divisible by 5. This new requirement allows simple code for the new + 5-bits-at-a-time long_pow() implementation. If necessary, the + restriction could be removed (by complicating long_pow(), or by + falling back to the 1-bit-at-a-time algorithm), but there are no + plans to do so. + +- bug #991962: When building with --disable-toolbox-glue on Darwin no + attempt to build Mac-specific modules occurs. + +- The --with-tsc flag to configure to enable VM profiling with the + processor's timestamp counter now works on PPC platforms. + +- patch #1006629: Define _XOPEN_SOURCE to 500 on Solaris 8/9 to match + GCC's definition and avoid redefinition warnings. + +- Detect pthreads support (provided by gnu pth pthread emulation) on + GNU/k*BSD systems. + +- bug #1005737, #1007249: Fixed several build problems and warnings + found on old/legacy C compilers of HP-UX, IRIX and Tru64. + +C API +----- + +.. + +Documentation +------------- + +- patch #1005936, bug #1009373: fix index entries which contain + an underscore when viewed with Acrobat. + +- bug #990669: os.path.normpath may alter the meaning of a path if + it contains symbolic links. This has been documented in a comment + since 1992, but is now in the library reference as well. + +New platforms +------------- + +- FreeBSD 6 is now supported. + +Tests +----- + +.. + +Windows +------- + +- Boosted the stack reservation for python.exe and pythonw.exe from + the default 1MB to 2MB. Stack frames under VC 7.1 for 2.4 are enough + bigger than under VC 6.0 for 2.3.4 that deeply recursive progams + within the default sys.getrecursionlimit() default value of 1000 were + able to suffer undetected C stack overflows. The standard test program + test_compiler was one such program. If a Python process on Windows + "just vanishes" without a trace, and without an error message of any + kind, but with an exit code of 128, undetected stack overflow may be + the problem. + +Mac +--- + +.. + + +What's New in Python 2.4 alpha 2? +================================= + +*Release date: 05-AUG-2004* + +Core and builtins +----------------- + +- Patch #980695: Implements efficient string concatenation for statements + of the form s=s+t and s+=t. This will vary across implementations. + Accordingly, the str.join() method is strongly preferred for performance + sensitive code. + +- PEP-0318, Function Decorators have been added to the language. These are + implemented using the Java-style @decorator syntax, like so:: + + @staticmethod + def foo(bar): + + (The PEP needs to be updated to reflect the current state) + +- When importing a module M raises an exception, Python no longer leaves M + in sys.modules. Before 2.4a2 it did, and a subsequent import of M would + succeed, picking up a module object from sys.modules reflecting as much + of the initialization of M as completed before the exception was raised. + Subsequent imports got no indication that M was in a partially- + initialized state, and the importers could get into arbitrarily bad + trouble as a result (the M they got was in an unintended state, + arbitrarily far removed from M's author's intent). Now subsequent + imports of M will continue raising exceptions (but if, for example, the + source code for M is edited between import attempts, then perhaps later + attempts will succeed, or raise a different exception). + + This can break existing code, but in such cases the code was probably + working before by accident. In the Python source, the only case of + breakage discovered was in a test accidentally relying on a damaged + module remaining in sys.modules. Cases are also known where tests + deliberately provoking import errors remove damaged modules from + sys.modules themselves, and such tests will break now if they do an + unconditional del sys.modules[M]. + +- u'%s' % obj will now try obj.__unicode__() first and fallback to + obj.__str__() if no __unicode__ method can be found. + +- Patch #550732: Add PyArg_VaParseTupleAndKeywords(). Analogous to + PyArg_VaParse(). Both are now documented. Thanks Greg Chapman. + +- Allow string and unicode return types from .encode()/.decode() + methods on string and unicode objects. Added unicode.decode() + which was missing for no apparent reason. + +- An attempt to fix the mess that is Python's behaviour with + signal handlers and threads, complicated by readline's behaviour. + It's quite possible that there are still bugs here. + +- Added C macros Py_CLEAR and Py_VISIT to ease the implementation of + types that support garbage collection. + +- Compiler now treats None as a constant. + +- The type of values returned by __int__, __float__, __long__, + __oct__, and __hex__ are now checked. Returning an invalid type + will cause a TypeError to be raised. This matches the behavior of + Jython. + +- Implemented bind_textdomain_codeset() in locale module. + +- Added a workaround for proper string operations in BSDs. str.split + and str.is* methods can now work correctly with UTF-8 locales. + +- Bug #989185: unicode.iswide() and unicode.width() is dropped and + the East Asian Width support is moved to unicodedata extension + module. + +- Patch #941229: The source code encoding in interactive mode + now refers sys.stdin.encoding not just ISO-8859-1 anymore. This + allows for non-latin-1 users to write unicode strings directly. + +Extension modules +----------------- + +- cpickle now supports the same keyword arguments as pickle. + +Library +------- + +- Added new codecs and aliases for ISO_8859-11, ISO_8859-16 and + TIS-620 + +- Thanks to Edward Loper, doctest has been massively refactored, and + many new features were added. Full docs will appear later. For now + the doctest module comments and new test cases give good coverage. + The refactoring provides many hook points for customizing behavior + (such as how to report errors, and how to compare expected to actual + output). New features include a <BLANKLINE> marker for expected + output containing blank lines, options to produce unified or context + diffs when actual output doesn't match expectations, an option to + normalize whitespace before comparing, and an option to use an + ellipsis to signify "don't care" regions of output. + +- Tkinter now supports the wish -sync and -use options. + +- The following methods in time support passing of None: ctime(), gmtime(), + and localtime(). If None is provided, the current time is used (the + same as when the argument is omitted). + [SF bug 658254, patch 663482] + +- nntplib does now allow to ignore a .netrc file. + +- urllib2 now recognizes Basic authentication even if other authentication + schemes are offered. + +- Bug #1001053. wave.open() now accepts unicode filenames. + +- gzip.GzipFile has a new fileno() method, to retrieve the handle of the + underlying file object (provided it has a fileno() method). This is + needed if you want to use os.fsync() on a GzipFile. + +- imaplib has two new methods: deleteacl and myrights. + +- nntplib has two new methods: description and descriptions. They + use a more RFC-compliant way of getting a newsgroup description. + +- Bug #993394. Fix a possible red herring of KeyError in 'threading' being + raised during interpreter shutdown from a registered function with atexit + when dummy_threading is being used. + +- Bug #857297/Patch #916874. Fix an error when extracting a hard link + from a tarfile. + +- Patch #846659. Fix an error in tarfile.py when using + GNU longname/longlink creation. + +- The obsolete FCNTL.py has been deleted. The builtin fcntl module + has been available (on platforms that support fcntl) since Python + 1.5a3, and all FCNTL.py did is export fcntl's names, after generating + a deprecation warning telling you to use fcntl directly. + +- Several new unicode codecs are added: big5hkscs, euc_jis_2004, + iso2022_jp_2004, shift_jis_2004. + +- Bug #788520. Queue.{get, get_nowait, put, put_nowait} have new + implementations, exploiting Conditions (which didn't exist at the time + Queue was introduced). A minor semantic change is that the Full and + Empty exceptions raised by non-blocking calls now occur only if the + queue truly was full or empty at the instant the queue was checked (of + course the Queue may no longer be full or empty by the time a calling + thread sees those exceptions, though). Before, the exceptions could + also be raised if it was "merely inconvenient" for the implementation + to determine the true state of the Queue (because the Queue was locked + by some other method in progress). + +- Bugs #979794 and #980117: difflib.get_grouped_opcodes() now handles the + case of comparing two empty lists. This affected both context_diff() and + unified_diff(), + +- Bug #980938: smtplib now prints debug output to sys.stderr. + +- Bug #930024: posixpath.realpath() now handles infinite loops in symlinks by + returning the last point in the path that was not part of any loop. Thanks + AM Kuchling. + +- Bug #980327: ntpath not handles compressing erroneous slashes between the + drive letter and the rest of the path. Also clearly handles UNC addresses now + as well. Thanks Paul Moore. + +- bug #679953: zipfile.py should now work for files over 2 GB. The packed data + for file sizes (compressed and uncompressed) was being stored as signed + instead of unsigned. + +- decimal.py now only uses signals in the IBM spec. The other conditions are + no longer part of the public API. + +- codecs module now has two new generic APIs: encode() and decode() + which don't restrict the return types (unlike the unicode and + string methods of the same name). + +- Non-blocking SSL sockets work again; they were broken in Python 2.3. + SF patch 945642. + +- doctest unittest integration improvements: + + o Improved the unitest test output for doctest-based unit tests + + o Can now pass setUp and tearDown functions when creating + DocTestSuites. + +- The threading module has a new class, local, for creating objects + that provide thread-local data. + +- Bug #990307: when keep_empty_values is True, cgi.parse_qsl() + no longer returns spurious empty fields. + +- Implemented bind_textdomain_codeset() in gettext module. + +- Introduced in gettext module the l*gettext() family of functions, + which return translation strings encoded in the preferred encoding, + as informed by locale module's getpreferredencoding(). + +- optparse module (and tests) upgraded to Optik 1.5a1. Changes: + + - Add expansion of default values in help text: the string + "%default" in an option's help string is expanded to str() of + that option's default value, or "none" if no default value. + + - Bug #955889: option default values that happen to be strings are + now processed in the same way as values from the command line; this + allows generation of nicer help when using custom types. Can + be disabled with parser.set_process_default_values(False). + + - Bug #960515: don't crash when generating help for callback + options that specify 'type', but not 'dest' or 'metavar'. + + - Feature #815264: change the default help format for short options + that take an argument from e.g. "-oARG" to "-o ARG"; add + set_short_opt_delimiter() and set_long_opt_delimiter() methods to + HelpFormatter to allow (slight) customization of the formatting. + + - Patch #736940: internationalize Optik: all built-in user- + targeted literal strings are passed through gettext.gettext(). (If + you want translations (.po files), they're not included with Python + -- you'll find them in the Optik source distribution from + http://optik.sourceforge.net/ .) + + - Bug #878453: respect $COLUMNS environment variable for + wrapping help output. + + - Feature #988122: expand "%prog" in the 'description' passed + to OptionParser, just like in the 'usage' and 'version' strings. + (This is *not* done in the 'description' passed to OptionGroup.) + +C API +----- + +- PyImport_ExecCodeModule() and PyImport_ExecCodeModuleEx(): if an + error occurs while loading the module, these now delete the module's + entry from sys.modules. All ways of loading modules eventually call + one of these, so this is an error-case change in semantics for all + ways of loading modules. In rare cases, a module loader may wish + to keep a module object in sys.modules despite that the module's + code cannot be executed. In such cases, the module loader must + arrange to reinsert the name and module object in sys.modules. + PyImport_ReloadModule() has been changed to reinsert the original + module object into sys.modules if the module reload fails, so that + its visible semantics have not changed. + +- A large pile of datetime field-extraction macros is now documented, + thanks to Anthony Tuininga (patch #986010). + +Documentation +------------- + +- Improved the tutorial on creating types in C. + + - point out the importance of reassigning data members before + assigning their values + + - correct my misconception about return values from visitprocs. Sigh. + + - mention the labor saving Py_VISIT and Py_CLEAR macros. + +- Major rewrite of the math module docs, to address common confusions. + +Tests +----- + +- The test data files for the decimal test suite are now installed on + platforms that use the Makefile. + +- SF patch 995225: The test file testtar.tar accidentally contained + CVS keywords (like $Id: HISTORY 43159 2006-03-20 06:30:41Z anthony.baxter $), which could cause spurious failures in + test_tarfile.py depending on how the test file was checked out. + + +What's New in Python 2.4 alpha 1? +================================= + +*Release date: 08-JUL-2004* + +Core and builtins +----------------- + +- weakref.ref is now the type object also known as + weakref.ReferenceType; it can be subclassed like any other new-style + class. There's less per-entry overhead in WeakValueDictionary + objects now (one object instead of three). + +- Bug #951851: Python crashed when reading import table of certain + Windows DLLs. + +- Bug #215126. The locals argument to eval(), execfile(), and exec now + accept any mapping type. + +- marshal now shares interned strings. This change introduces + a new .pyc magic. + +- Bug #966623. classes created with type() in an exec(, {}) don't + have a __module__, but code in typeobject assumed it would always + be there. + +- Python no longer relies on the LC_NUMERIC locale setting to be + the "C" locale; as a result, it no longer tries to prevent changing + the LC_NUMERIC category. + +- Bug #952807: Unpickling pickled instances of subclasses of + datetime.date, datetime.datetime and datetime.time could yield insane + objects. Thanks to Jiwon Seo for a fix. + +- Bug #845802: Python crashes when __init__.py is a directory. + +- Unicode objects received two new methods: iswide() and width(). + These query East Asian width information, as specified in Unicode + TR11. + +- Improved the tuple hashing algorithm to give fewer collisions in + common cases. Fixes bug #942952. + +- Implemented generator expressions (PEP 289). Coded by Jiwon Seo. + +- Enabled the profiling of C extension functions (and builtins) - check + new documentation and modified profile and bdb modules for more details + +- Set file.name to the object passed to open (instead of a new string) + +- Moved tracebackobject into traceback.h and renamed to PyTracebackObject + +- Optimized the byte coding for multiple assignments like "a,b=b,a" and + "a,b,c=1,2,3". Improves their speed by 25% to 30%. + +- Limit the nested depth of a tuple for the second argument to isinstance() + and issubclass() to the recursion limit of the interpreter. + Fixes bug #858016 . + +- Optimized dict iterators, creating separate types for each + and having them reveal their length. Also optimized the + methods: keys(), values(), and items(). + +- Implemented a newcode opcode, LIST_APPEND, that simplifies + the generated bytecode for list comprehensions and further + improves their performance (about 35%). + +- Implemented rich comparisons for floats, which seems to make + comparisons involving NaNs somewhat less surprising when the + underlying C compiler actually implements C99 semantics. + +- Optimized list.extend() to save memory and no longer create + intermediate sequences. Also, extend() now pre-allocates the + needed memory whenever the length of the iterable is known in + advance -- this halves the time to extend the list. + +- Optimized list resize operations to make fewer calls to the system + realloc(). Significantly speeds up list appends, list pops, + list comprehensions, and the list constructor (when the input iterable + length is not known). + +- Changed the internal list over-allocation scheme. For larger lists, + overallocation ranged between 3% and 25%. Now, it is a constant 12%. + For smaller lists (n<8), overallocation was upto eight elements. Now, + the overallocation is no more than three elements -- this improves space + utilization for applications that have large numbers of small lists. + +- Most list bodies now get re-used rather than freed. Speeds up list + instantiation and deletion by saving calls to malloc() and free(). + +- The dict.update() method now accepts all the same argument forms + as the dict() constructor. This now includes item lists and/or + keyword arguments. + +- Support for arbitrary objects supporting the read-only buffer + interface as the co_code field of code objects (something that was + only possible to create from C code) has been removed. + +- Made omitted callback and None equivalent for weakref.ref() and + weakref.proxy(); the None case wasn't handled correctly in all + cases. + +- Fixed problem where PyWeakref_NewRef() and PyWeakref_NewProxy() + assumed that initial existing entries in an object's weakref list + would not be removed while allocating a new weakref object. Since + GC could be invoked at that time, however, that assumption was + invalid. In a truly obscure case of GC being triggered during + creation for a new weakref object for an referent which already + has a weakref without a callback which is only referenced from + cyclic trash, a memory error can occur. This consistently created a + segfault in a debug build, but provided less predictable behavior in + a release build. + +- input() builtin function now respects compiler flags such as + __future__ statements. SF patch 876178. + +- Removed PendingDeprecationWarning from apply(). apply() remains + deprecated, but the nuisance warning will not be issued. + +- At Python shutdown time (Py_Finalize()), 2.3 called cyclic garbage + collection twice, both before and after tearing down modules. The + call after tearing down modules has been disabled, because too much + of Python has been torn down then for __del__ methods and weakref + callbacks to execute sanely. The most common symptom was a sequence + of uninformative messages on stderr when Python shut down, produced + by threads trying to raise exceptions, but unable to report the nature + of their problems because too much of the sys module had already been + destroyed. + +- Removed FutureWarnings related to hex/oct literals and conversions + and left shifts. (Thanks to Kalle Svensson for SF patch 849227.) + This addresses most of the remaining semantic changes promised by + PEP 237, except for repr() of a long, which still shows the trailing + 'L'. The PEP appears to promise warnings for operations that + changed semantics compared to Python 2.3, but this is not + implemented; we've suffered through enough warnings related to + hex/oct literals and I think it's best to be silent now. + +- For str and unicode objects, the ljust(), center(), and rjust() + methods now accept an optional argument specifying a fill + character other than a space. + +- When method objects have an attribute that can be satisfied either + by the function object or by the method object, the function + object's attribute usually wins. Christian Tismer pointed out that + that this is really a mistake, because this only happens for special + methods (like __reduce__) where the method object's version is + really more appropriate than the function's attribute. So from now + on, all method attributes will have precedence over function + attributes with the same name. + +- Critical bugfix, for SF bug 839548: if a weakref with a callback, + its callback, and its weakly referenced object, all became part of + cyclic garbage during a single run of garbage collection, the order + in which they were torn down was unpredictable. It was possible for + the callback to see partially-torn-down objects, leading to immediate + segfaults, or, if the callback resurrected garbage objects, to + resurrect insane objects that caused segfaults (or other surprises) + later. In one sense this wasn't surprising, because Python's cyclic gc + had no knowledge of Python's weakref objects. It does now. When + weakrefs with callbacks become part of cyclic garbage now, those + weakrefs are cleared first. The callbacks don't trigger then, + preventing the problems. If you need callbacks to trigger, then just + as when cyclic gc is not involved, you need to write your code so + that weakref objects outlive the objects they weakly reference. + +- Critical bugfix, for SF bug 840829: if cyclic garbage collection + happened to occur during a weakref callback for a new-style class + instance, subtle memory corruption was the result (in a release build; + in a debug build, a segfault occurred reliably very soon after). + This has been repaired. + +- Compiler flags set in PYTHONSTARTUP are now active in __main__. + +- Added two builtin types, set() and frozenset(). + +- Added a reversed() builtin function that returns a reverse iterator + over a sequence. + +- Added a sorted() builtin function that returns a new sorted list + from any iterable. + +- CObjects are now mutable (on the C level) through PyCObject_SetVoidPtr. + +- list.sort() now supports three keyword arguments: cmp, key, and reverse. + The key argument can be a function of one argument that extracts a + comparison key from the original record: mylist.sort(key=str.lower). + The reverse argument is a boolean value and if True will change the + sort order as if the comparison arguments were reversed. In addition, + the documentation has been amended to provide a guarantee that all sorts + starting with Py2.3 are guaranteed to be stable (the relative order of + records with equal keys is unchanged). + +- Added test whether wchar_t is signed or not. A signed wchar_t is not + usable as internal unicode type base for Py_UNICODE since the + unicode implementation assumes an unsigned type. + +- Fixed a bug in the cache of length-one Unicode strings that could + lead to a seg fault. The specific problem occurred when an earlier, + non-fatal error left an uninitialized Unicode object in the + freelist. + +- The % formatting operator now supports '%F' which is equivalent to + '%f'. This has always been documented but never implemented. + +- complex(obj) could leak a little memory if obj wasn't a string or + number. + +- zip() with no arguments now returns an empty list instead of raising + a TypeError exception. + +- obj.__contains__() now returns True/False instead of 1/0. SF patch + 820195. + +- Python no longer tries to be smart about recursive comparisons. + When comparing containers with cyclic references to themselves it + will now just hit the recursion limit. See SF patch 825639. + +- str and unicode builtin types now have an rsplit() method that is + same as split() except that it scans the string from the end + working towards the beginning. See SF feature request 801847. + +- Fixed a bug in object.__reduce_ex__ when using protocol 2. Failure + to clear the error when attempts to get the __getstate__ attribute + fail caused intermittent errors and odd behavior. + +- buffer objects based on other objects no longer cache a pointer to + the data and the data length. Instead, the appropriate tp_as_buffer + method is called as necessary. + +- fixed: if a file is opened with an explicit buffer size >= 1, repeated + close() calls would attempt to free() the buffer already free()ed on + the first call. + + +Extension modules +----------------- + +- Added socket.getservbyport(), and make the second argument in + getservbyname() and getservbyport() optional. + +- time module code that deals with input POSIX timestamps will now raise + ValueError if more than a second is lost in precision when the + timestamp is cast to the platform C time_t type. There's no chance + that the platform will do anything sensible with the result in such + cases. This includes ctime(), localtime() and gmtime(). Assorted + fromtimestamp() and utcfromtimestamp() methods in the datetime module + were also protected. Closes bugs #919012 and 975996. + +- fcntl.ioctl now warns if the mutate flag is not specified. + +- nt now properly allows to refer to UNC roots, e.g. in nt.stat(). + +- the weakref module now supports additional objects: array.array, + sre.pattern_objects, file objects, and sockets. + +- operator.isMappingType() and operator.isSequenceType() now give + fewer false positives. + +- socket.sslerror is now a subclass of socket.error . Also added + socket.error to the socket module's C API. + +- Bug #920575: A problem where the _locale module segfaults on + nl_langinfo(ERA) caused by GNU libc's illegal NULL return is fixed. + +- array objects now support the copy module. Also, their resizing + scheme has been updated to match that used for list objects. This improves + the performance (speed and memory usage) of append() operations. + Also, array.array() and array.extend() now accept any iterable argument + for repeated appends without needing to create another temporary array. + +- cStringIO.writelines() now accepts any iterable argument and writes + the lines one at a time rather than joining them and writing once. + Made a parallel change to StringIO.writelines(). Saves memory and + makes suitable for use with generator expressions. + +- time.strftime() now checks that the values in its time tuple argument + are within the proper boundaries to prevent possible crashes from the + platform's C library implementation of strftime(). Can possibly + break code that uses values outside the range that didn't cause + problems previously (such as sitting day of year to 0). Fixes bug + #897625. + +- The socket module now supports Bluetooth sockets, if the + system has <bluetooth/bluetooth.h> + +- Added a collections module containing a new datatype, deque(), + offering high-performance, thread-safe, memory friendly appends + and pops on either side of the deque. + +- Several modules now take advantage of collections.deque() for + improved performance: Queue, mutex, shlex, threading, and pydoc. + +- The operator module has two new functions, attrgetter() and + itemgetter() which are useful for creating fast data extractor + functions for map(), list.sort(), itertools.groupby(), and + other functions that expect a function argument. + +- socket.SHUT_{RD,WR,RDWR} was added. + +- os.getsid was added. + +- The pwd module incorrectly advertised its struct type as + struct_pwent; this has been renamed to struct_passwd. (The old name + is still supported for backwards compatibility.) + +- The xml.parsers.expat module now provides Expat 1.95.7. + +- socket.IPPROTO_IPV6 was added. + +- readline.clear_history was added. + +- select.select() now accepts sequences for its first three arguments. + +- cStringIO now supports the f.closed attribute. + +- The signal module now exposes SIGRTMIN and SIGRTMAX (if available). + +- curses module now supports use_default_colors(). [patch #739124] + +- Bug #811028: ncurses.h breakage on FreeBSD/MacOS X + +- Bug #814613: INET_ADDRSTRLEN fix needed for all compilers on SGI + +- Implemented non-recursive SRE matching scheme (#757624). + +- Implemented (?(id/name)yes|no) support in SRE (#572936). + +- random.seed() with no arguments or None uses time.time() as a default + seed. Modified to match Py2.2 behavior and use fractional seconds so + that successive runs are more likely to produce different sequences. + +- random.Random has a new method, getrandbits(k), which returns an int + with k random bits. This method is now an optional part of the API + for user defined generators. Any generator that defines genrandbits() + can now use randrange() for ranges with a length >= 2**53. Formerly, + randrange would return only even numbers for ranges that large (see + SF bug #812202). Generators that do not define genrandbits() now + issue a warning when randrange() is called with a range that large. + +- itertools has a new function, groupby() for aggregating iterables + into groups sharing the same key (as determined by a key function). + It offers some of functionality of SQL's groupby keyword and of + the Unix uniq filter. + +- itertools now has a new tee() function which produces two independent + iterators from a single iterable. + +- itertools.izip() with no arguments now returns an empty iterator instead + of raising a TypeError exception. + +- Fixed #853061: allow BZ2Compressor.compress() to receive an empty string + as parameter. + +Library +------- + +- Added a new module: cProfile, a C profiler with the same interface as the + profile module. cProfile avoids some of the drawbacks of the hotshot + profiler and provides a bit more information than the other two profilers. + Based on "lsprof" (patch #1212837). + +- Bug #1266283: The new function "lexists" is now in os.path.__all__. + +- Bug #981530: Fix UnboundLocalError in shutil.rmtree(). This affects + the documented behavior: the function passed to the onerror() + handler can now also be os.listdir. + +- Bug #754449: threading.Thread objects no longer mask exceptions raised during + interpreter shutdown with another exception from attempting to handle the + original exception. + +- Added decimal.py per PEP 327. + +- Bug #981299: rsync is now a recognized protocol in urlparse that uses a + "netloc" portion of a URL. + +- Bug #919012: shutil.move() will not try to move a directory into itself. + Thanks Johannes Gijsbers. + +- Bug #934282: pydoc.stripid() is now case-insensitive. Thanks Robin Becker. + +- Bug #823209: cmath.log() now takes an optional base argument so that its + API matches math.log(). + +- Bug #957381: distutils bdist_rpm no longer fails on recent RPM versions + that generate a -debuginfo.rpm + +- os.path.devnull has been added for all supported platforms. + +- Fixed #877165: distutils now picks the right C++ compiler command + on cygwin and mingw32. + +- urllib.urlopen().readline() now handles HTTP/0.9 correctly. + +- refactored site.py into functions. Also wrote regression tests for the + module. + +- The distutils install command now supports the --home option and + installation scheme for all platforms. + +- asyncore.loop now has a repeat count parameter that defaults to + looping forever. + +- The distutils sdist command now ignores all .svn directories, in + addition to CVS and RCS directories. .svn directories hold + administrative files for the Subversion source control system. + +- Added a new module: cookielib. Automatic cookie handling for HTTP + clients. Also, support for cookielib has been added to urllib2, so + urllib2.urlopen() can transparently handle cookies. + +- stringprep.py now uses built-in set() instead of sets.Set(). + +- Bug #876278: Unbounded recursion in modulefinder + +- Bug #780300: Swap public and system ID in LexicalHandler.startDTD. + Applications relying on the wrong order need to be corrected. + +- Bug #926075: Fixed a bug that returns a wrong pattern object + for a string or unicode object in sre.compile() when a different + type pattern with the same value exists. + +- Added countcallers arg to trace.Trace class (--trackcalls command line arg + when run from the command prompt). + +- Fixed a caching bug in platform.platform() where the argument of 'terse' was + not taken into consideration when caching value. + +- Added two new command-line arguments for profile (output file and + default sort). + +- Added global runctx function to profile module + +- Add hlist missing entryconfigure and entrycget methods. + +- The ptcp154 codec was added for Kazakh character set support. + +- Support non-anonymous ftp URLs in urllib2. + +- The encodings package will now apply codec name aliases + first before starting to try the import of the codec module. + This simplifies overriding built-in codecs with external + packages, e.g. the included CJK codecs with the JapaneseCodecs + package, by adjusting the aliases dictionary in encodings.aliases + accordingly. + +- base64 now supports RFC 3548 Base16, Base32, and Base64 encoding and + decoding standards. + +- urllib2 now supports processors. A processor is a handler that + implements an xxx_request or xxx_response method. These methods are + called for all requests. + +- distutils compilers now compile source files in the same order as + they are passed to the compiler. + +- pprint.pprint() and pprint.pformat() now have additional parameters + indent, width and depth. + +- Patch #750542: pprint now will pretty print subclasses of list, tuple + and dict too, as long as they don't overwrite __repr__(). + +- Bug #848614: distutils' msvccompiler fails to find the MSVC6 + compiler because of incomplete registry entries. + +- httplib.HTTP.putrequest now offers to omit the implicit Accept-Encoding. + +- Patch #841977: modulefinder didn't find extension modules in packages + +- imaplib.IMAP4.thread was added. + +- Plugged a minor hole in tempfile.mktemp() due to the use of + os.path.exists(), switched to using os.lstat() directly if possible. + +- bisect.py and heapq.py now have underlying C implementations + for better performance. + +- heapq.py has two new functions, nsmallest() and nlargest(). + +- traceback.format_exc has been added (similar to print_exc but it returns + a string). + +- xmlrpclib.MultiCall has been added. + +- poplib.POP3_SSL has been added. + +- tmpfile.mkstemp now returns an absolute path even if dir is relative. + +- urlparse is RFC 2396 compliant. + +- The fieldnames argument to the csv module's DictReader constructor is now + optional. If omitted, the first row of the file will be used as the + list of fieldnames. + +- encodings.bz2_codec was added for access to bz2 compression + using "a long string".encode('bz2') + +- Various improvements to unittest.py, realigned with PyUnit CVS. + +- dircache now passes exceptions to the caller, instead of returning + empty lists. + +- The bsddb module and dbhash module now support the iterator and + mapping protocols which make them more substitutable for dictionaries + and shelves. + +- The csv module's DictReader and DictWriter classes now accept keyword + arguments. This was an omission in the initial implementation. + +- The email package handles some RFC 2231 parameters with missing + CHARSET fields better. It also includes a patch to parameter + parsing when semicolons appear inside quotes. + +- sets.py now runs under Py2.2. In addition, the argument restrictions + for most set methods (but not the operators) have been relaxed to + allow any iterable. + +- _strptime.py now has a behind-the-scenes caching mechanism for the most + recent TimeRE instance used along with the last five unique directive + patterns. The overall module was also made more thread-safe. + +- random.cunifvariate() and random.stdgamma() were deprecated in Py2.3 + and removed in Py2.4. + +- Bug #823328: urllib2.py's HTTP Digest Auth support works again. + +- Patch #873597: CJK codecs are imported into rank of default codecs. + +Tools/Demos +----------- + +- A hotshotmain script was added to the Tools/scripts directory that + makes it easy to run a script under control of the hotshot profiler. + +- The db2pickle and pickle2db scripts can now dump/load gdbm files. + +- The file order on the command line of the pickle2db script was reversed. + It is now [ picklefile ] dbfile. This provides better symmetry with + db2pickle. The file arguments to both scripts are now source followed by + destination in situations where both files are given. + +- The pydoc script will display a link to the module documentation for + modules determined to be part of the core distribution. The documentation + base directory defaults to http://www.python.org/doc/current/lib/ but can + be changed by setting the PYTHONDOCS environment variable. + +- texcheck.py now detects double word errors. + +- md5sum.py mistakenly opened input files in text mode by default, a + silent and dangerous change from previous releases. It once again + opens input files in binary mode by default. The -t and -b flags + remain for compatibility with the 2.3 release, but -b is the default + now. + +- py-electric-colon now works when pending-delete/delete-selection mode is + in effect + +- py-help-at-point is no longer bound to the F1 key - it's still bound to + C-c C-h + +- Pynche was fixed to not crash when there is no ~/.pynche file and no + -d option was given. + +Build +----- + +- Bug #978645: Modules/getpath.c now builds properly in --disable-framework + build under OS X. + +- Profiling using gprof is now available if Python is configured with + --enable-profiling. + +- Profiling the VM using the Pentium TSC is now possible if Python + is configured --with-tsc. + +- In order to find libraries, setup.py now also looks in /lib64, for use + on AMD64. + +- Bug #934635: Fixed a bug where the configure script couldn't detect + getaddrinfo() properly if the KAME stack had SCTP support. + +- Support for missing ANSI C header files (limits.h, stddef.h, etc) was + removed. + +- Systems requiring the D4, D6 or D7 variants of pthreads are no longer + supported (see PEP 11). + +- Universal newline support can no longer be disabled (see PEP 11). + +- Support for DGUX, SunOS 4, IRIX 4 and Minix was removed (see PEP 11). + +- Support for systems requiring --with-dl-dld or --with-sgi-dl was removed + (see PEP 11). + +- Tests for sizeof(char) were removed since ANSI C mandates that + sizeof(char) must be 1. + +C API +----- + +- Thanks to Anthony Tuininga, the datetime module now supplies a C API + containing type-check macros and constructors. See new docs in the + Python/C API Reference Manual for details. + +- Private function _PyTime_DoubleToTimet added, to convert a Python + timestamp (C double) to platform time_t with some out-of-bounds + checking. Declared in new header file timefuncs.h. It would be + good to expose some other internal timemodule.c functions there. + +- New public functions PyEval_EvaluateFrame and PyGen_New to expose + generator objects. + +- New public functions Py_IncRef() and Py_DecRef(), exposing the + functionality of the Py_XINCREF() and Py_XDECREF macros. Useful for + runtime dynamic embedding of Python. See patch #938302, by Bob + Ippolito. + +- Added a new macro, PySequence_Fast_ITEMS, which retrieves a fast sequence's + underlying array of PyObject pointers. Useful for high speed looping. + +- Created a new method flag, METH_COEXIST, which causes a method to be loaded + even if already defined by a slot wrapper. This allows a __contains__ + method, for example, to co-exist with a defined sq_contains slot. This + is helpful because the PyCFunction can take advantage of optimized calls + whenever METH_O or METH_NOARGS flags are defined. + +- Added a new function, PyDict_Contains(d, k) which is like + PySequence_Contains() but is specific to dictionaries and executes + about 10% faster. + +- Added three new macros: Py_RETURN_NONE, Py_RETURN_TRUE, and Py_RETURN_FALSE. + Each return the singleton they mention after Py_INCREF()ing them. + +- Added a new function, PyTuple_Pack(n, ...) for constructing tuples from a + variable length argument list of Python objects without having to invoke + the more complex machinery of Py_BuildValue(). PyTuple_Pack(3, a, b, c) + is equivalent to Py_BuildValue("(OOO)", a, b, c). + +Windows +------- + +- The _winreg module could segfault when reading very large registry + values, due to unchecked alloca() calls (SF bug 851056). The fix is + uses either PyMem_Malloc(n) or PyString_FromStringAndSize(NULL, n), + as appropriate, followed by a size check. + +- file.truncate() could misbehave if the file was open for update + (modes r+, rb+, w+, wb+), and the most recent file operation before + the truncate() call was an input operation. SF bug 801631. + + +What's New in Python 2.3 final? +=============================== + +*Release date: 29-Jul-2003* + +IDLE +---- + +- Bug 778400: IDLE hangs when selecting "Edit with IDLE" from explorer. + This was unique to Windows, and was fixed by adding an -n switch to + the command the Windows installer creates to execute "Edit with IDLE" + context-menu actions. + +- IDLE displays a new message upon startup: some "personal firewall" + kinds of programs (for example, ZoneAlarm) open a dialog of their + own when any program opens a socket. IDLE does use sockets, talking + on the computer's internal loopback interface. This connection is not + visible on any external interface and no data is sent to or received + from the Internet. So, if you get such a dialog when opening IDLE, + asking whether to let pythonw.exe talk to address 127.0.0.1, say yes, + and rest assured no communication external to your machine is taking + place. If you don't allow it, IDLE won't be able to start. + + +What's New in Python 2.3 release candidate 2? +============================================= + +*Release date: 24-Jul-2003* + +Core and builtins +----------------- + +- It is now possible to import from zipfiles containing additional + data bytes before the zip compatible archive. Zipfiles containing a + comment at the end are still unsupported. + +Extension modules +----------------- + +- A longstanding bug in the parser module's initialization could cause + fatal internal refcount confusion when the module got initialized more + than once. This has been fixed. + +- Fixed memory leak in pyexpat; using the parser's ParseFile() method + with open files that aren't instances of the standard file type + caused an instance of the bound .read() method to be leaked on every + call. + +- Fixed some leaks in the locale module. + +Library +------- + +- Lib/encodings/rot_13.py when used as a script, now more properly + uses the first Python interpreter on your path. + +- Removed caching of TimeRE (and thus LocaleTime) in _strptime.py to + fix a locale related bug in the test suite. Although another patch + was needed to actually fix the problem, the cache code was not + restored. + +IDLE +---- + +- Calltips patches. + +Build +----- + +- For MacOSX, added -mno-fused-madd to BASECFLAGS to fix test_coercion + on Panther (OSX 10.3). + +C API +----- + +Windows +------- + +- The tempfile module could do insane imports on Windows if PYTHONCASEOK + was set, making temp file creation impossible. Repaired. + +- Add a patch to workaround pthread_sigmask() bugs in Cygwin. + +Mac +--- + +- Various fixes to pimp. + +- Scripts runs with pythonw no longer had full window manager access. + +- Don't force boot-disk-only install, for reasons unknown it causes + more problems than it solves. + + +What's New in Python 2.3 release candidate 1? +============================================= + +*Release date: 18-Jul-2003* + +Core and builtins +----------------- + +- The new function sys.getcheckinterval() returns the last value set + by sys.setcheckinterval(). + +- Several bugs in the symbol table phase of the compiler have been + fixed. Errors could be lost and compilation could fail without + reporting an error. SF patch 763201. + +- The interpreter is now more robust about importing the warnings + module. In an executable generated by freeze or similar programs, + earlier versions of 2.3 would fail if the warnings module could + not be found on the file system. Fixes SF bug 771097. + +- A warning about assignments to module attributes that shadow + builtins, present in earlier releases of 2.3, has been removed. + +- It is not possible to create subclasses of builtin types like str + and tuple that define an itemsize. Earlier releases of Python 2.3 + allowed this by mistake, leading to crashes and other problems. + +- The thread_id is now initialized to 0 in a non-thread build. SF bug + 770247. + +- SF bug 762891: "del p[key]" on proxy object no longer raises SystemError. + +Extension modules +----------------- + +- weakref.proxy() can now handle "del obj[i]" for proxy objects + defining __delitem__. Formerly, it generated a SystemError. + +- SSL no longer crashes the interpreter when the remote side disconnects. + +- On Unix the mmap module can again be used to map device files. + +- time.strptime now exclusively uses the Python implementation + contained within the _strptime module. + +- The print slot of weakref proxy objects was removed, because it was + not consistent with the object's repr slot. + +- The mmap module only checks file size for regular files, not + character or block devices. SF patch 708374. + +- The cPickle Pickler garbage collection support was fixed to traverse + the find_class attribute, if present. + +- There are several fixes for the bsddb3 wrapper module. + + bsddb3 no longer crashes if an environment is closed before a cursor + (SF bug 763298). + + The DB and DBEnv set_get_returns_none function was extended to take + a level instead of a boolean flag. The new level 2 means that in + addition, cursor.set()/.get() methods return None instead of raising + an exception. + + A typo was fixed in DBCursor.join_item(), preventing a crash. + +Library +------- + +- distutils now supports MSVC 7.1 + +- doctest now examines all docstrings by default. Previously, it would + skip over functions with private names (as indicated by the underscore + naming convention). The old default created too much of a risk that + user tests were being skipped inadvertently. Note, this change could + break code in the unlikely case that someone had intentionally put + failing tests in the docstrings of private functions. The breakage + is easily fixable by specifying the old behavior when calling testmod() + or Tester(). + +- There were several fixes to the way dumbdbms are closed. It's vital + that a dumbdbm database be closed properly, else the on-disk data + and directory files can be left in mutually inconsistent states. + dumbdbm.py's _Database.__del__() method attempted to close the + database properly, but a shutdown race in _Database._commit() could + prevent this from working, so that a program trusting __del__() to + get the on-disk files in synch could be badly surprised. The race + has been repaired. A sync() method was also added so that shelve + can guarantee data is written to disk. + + The close() method can now be called more than once without complaint. + +- The classes in threading.py are now new-style classes. That they + weren't before was an oversight. + +- The urllib2 digest authentication handlers now define the correct + auth_header. The earlier versions would fail at runtime. + +- SF bug 763023: fix uncaught ZeroDivisionError in difflib ratio methods + when there are no lines. + +- SF bug 763637: fix exception in Tkinter with after_cancel + which could occur with Tk 8.4 + +- SF bug 770601: CGIHTTPServer.py now passes the entire environment + to child processes. + +- SF bug 765238: add filter to fnmatch's __all__. + +- SF bug 748201: make time.strptime() error messages more helpful. + +- SF patch 764470: Do not dump the args attribute of a Fault object in + xmlrpclib. + +- SF patch 549151: urllib and urllib2 now redirect POSTs on 301 + responses. + +- SF patch 766650: The whichdb module was fixed to recognize dbm files + generated by gdbm on OS/2 EMX. + +- SF bugs 763047 and 763052: fixes bug of timezone value being left as + -1 when ``time.tzname[0] == time.tzname[1] and not time.daylight`` + is true when it should only when time.daylight is true. + +- SF bug 764548: re now allows subclasses of str and unicode to be + used as patterns. + +- SF bug 763637: In Tkinter, change after_cancel() to handle tuples + of varying sizes. Tk 8.4 returns a different number of values + than Tk 8.3. + +- SF bug 763023: difflib.ratio() did not catch zero division. + +- The Queue module now has an __all__ attribute. + +Tools/Demos +----------- + +- See Lib/idlelib/NEWS.txt for IDLE news. + +- SF bug 753592: webchecker/wsgui now handles user supplied directories. + +- The trace.py script has been removed. It is now in the standard library. + +Build +----- + +- Python now compiles with -fno-strict-aliasing if possible (SF bug 766696). + +- The socket module compiles on IRIX 6.5.10. + +- An irix64 system is treated the same way as an irix6 system (SF + patch 764560). + +- Several definitions were missing on FreeBSD 5.x unless the + __BSD_VISIBLE symbol was defined. configure now defines it as + needed. + +C API +----- + +- Unicode objects now support mbcs as a built-in encoding, so the C + API can use it without deferring to the encodings package. + +Windows +------- + +- The Windows implementation of PyThread_start_new_thread() never + checked error returns from Windows functions correctly. As a result, + it could claim to start a new thread even when the Microsoft + _beginthread() function failed (due to "too many threads" -- this is + on the order of thousands when it happens). In these cases, the + Python exception :: + + thread.error: can't start new thread + + is raised now. + +- SF bug 766669: Prevent a GPF on interpreter exit when sockets are in + use. The interpreter now calls WSACleanup() from Py_Finalize() + instead of from DLL teardown. + +Mac +--- + +- Bundlebuilder now inherits default values in the right way. It was + previously possible for app bundles to get a type of "BNDL" instead + of "APPL." Other improvements include, a --build-id option to + specify the CFBundleIdentifier and using the --python option to set + the executable in the bundle. + +- Fixed two bugs in MacOSX framework handling. + +- pythonw did not allow user interaction in 2.3rc1, this has been fixed. + +- Python is now compiled with -mno-fused-madd, making all tests pass + on Panther. + +What's New in Python 2.3 beta 2? +================================ + +*Release date: 29-Jun-2003* + +Core and builtins +----------------- + +- A program can now set the environment variable PYTHONINSPECT to some + string value in Python, and cause the interpreter to enter the + interactive prompt at program exit, as if Python had been invoked + with the -i option. + +- list.index() now accepts optional start and stop arguments. Similar + changes were made to UserList.index(). SF feature request 754014. + +- SF patch 751998 fixes an unwanted side effect of the previous fix + for SF bug 742860 (the next item). + +- SF bug 742860: "WeakKeyDictionary __delitem__ uses iterkeys". This + wasn't threadsafe, was very inefficient (expected time O(len(dict)) + instead of O(1)), and could raise a spurious RuntimeError if another + thread mutated the dict during __delitem__, or if a comparison function + mutated it. It also neglected to raise KeyError when the key wasn't + present; didn't raise TypeError when the key wasn't of a weakly + referencable type; and broke various more-or-less obscure dict + invariants by using a sequence of equality comparisons over the whole + set of dict keys instead of computing the key's hash code to narrow + the search to those keys with the same hash code. All of these are + considered to be bugs. A new implementation of __delitem__ repairs all + that, but note that fixing these bugs may change visible behavior in + code relying (whether intentionally or accidentally) on old behavior. + +- SF bug 734869: Fixed a compiler bug that caused a fatal error when + compiling a list comprehension that contained another list comprehension + embedded in a lambda expression. + +- SF bug 705231: builtin pow() no longer lets the platform C pow() + raise -1.0 to integer powers, because (at least) glibc gets it wrong + in some cases. The result should be -1.0 if the power is odd and 1.0 + if the power is even, and any float with a sufficiently large exponent + is (mathematically) an exact even integer. + +- SF bug 759227: A new-style class that implements __nonzero__() must + return a bool or int (but not an int subclass) from that method. This + matches the restriction on classic classes. + +- The encoding attribute has been added for file objects, and set to + the terminal encoding on Unix and Windows. + +- The softspace attribute of file objects became read-only by oversight. + It's writable again. + +- Reverted a 2.3 beta 1 change to iterators for subclasses of list and + tuple. By default, the iterators now access data elements directly + instead of going through __getitem__. If __getitem__ access is + preferred, then __iter__ can be overridden. + +- SF bug 735247: The staticmethod and super types participate in + garbage collection. Before this change, it was possible for leaks to + occur in functions with non-global free variables that used these types. + +Extension modules +----------------- + +- the socket module has a new exception, socket.timeout, to allow + timeouts to be handled separately from other socket errors. + +- SF bug 751276: cPickle has fixed to propagate exceptions raised in + user code. In earlier versions, cPickle caught and ignored any + exception when it performed operations that it expected to raise + specific exceptions like AttributeError. + +- cPickle Pickler and Unpickler objects now participate in garbage + collection. + +- mimetools.choose_boundary() could return duplicate strings at times, + especially likely on Windows. The strings returned are now guaranteed + unique within a single program run. + +- thread.interrupt_main() raises KeyboardInterrupt in the main thread. + dummy_thread has also been modified to try to simulate the behavior. + +- array.array.insert() now treats negative indices as being relative + to the end of the array, just like list.insert() does. (SF bug #739313) + +- The datetime module classes datetime, time, and timedelta are now + properly subclassable. + +- _tkinter.{get|set}busywaitinterval was added. + +- itertools.islice() now accepts stop=None as documented. + Fixes SF bug #730685. + +- the bsddb185 module is built in one restricted instance - + /usr/include/db.h exists and defines HASHVERSION to be 2. This is true + for many BSD-derived systems. + + +Library +------- + +- Some happy doctest extensions from Jim Fulton have been added to + doctest.py. These are already being used in Zope3. The two + primary ones: + + doctest.debug(module, name) extracts the doctests from the named object + in the given module, puts them in a temp file, and starts pdb running + on that file. This is great when a doctest fails. + + doctest.DocTestSuite(module=None) returns a synthesized unittest + TestSuite instance, to be run by the unittest framework, which + runs all the doctests in the module. This allows writing tests in + doctest style (which can be clearer and shorter than writing tests + in unittest style), without losing unittest's powerful testing + framework features (which doctest lacks). + +- For compatibility with doctests created before 2.3, if an expected + output block consists solely of "1" and the actual output block + consists solely of "True", it's accepted as a match; similarly + for "0" and "False". This is quite un-doctest-like, but is practical. + The behavior can be disabled by passing the new doctest module + constant DONT_ACCEPT_TRUE_FOR_1 to the new optionflags optional + argument. + +- ZipFile.testzip() now only traps BadZipfile exceptions. Previously, + a bare except caught to much and reported all errors as a problem + in the archive. + +- The logging module now has a new function, makeLogRecord() making + LogHandler easier to interact with DatagramHandler and SocketHandler. + +- The cgitb module has been extended to support plain text display (SF patch + 569574). + +- A brand new version of IDLE (from the IDLEfork project at + SourceForge) is now included as Lib/idlelib. The old Tools/idle is + no more. + +- Added a new module: trace (documentation missing). This module used + to be distributed in Tools/scripts. It uses sys.settrace() to trace + code execution -- either function calls or individual lines. It can + generate tracing output during execution or a post-mortem report of + code coverage. + +- The threading module has new functions settrace() and setprofile() + that cooperate with the functions of the same name in the sys + module. A function registered with the threading module will + be used for all threads it creates. The new trace module uses this + to provide tracing for code running in threads. + +- copy.py: applied SF patch 707900, fixing bug 702858, by Steven + Taschuk. Copying a new-style class that had a reference to itself + didn't work. (The same thing worked fine for old-style classes.) + Builtin functions are now treated as atomic, fixing bug #746304. + +- difflib.py has two new functions: context_diff() and unified_diff(). + +- More fixes to urllib (SF 549151): (a) When redirecting, always use + GET. This is common practice and more-or-less sanctioned by the + HTTP standard. (b) Add a handler for 307 redirection, which becomes + an error for POST, but a regular redirect for GET and HEAD + +- Added optional 'onerror' argument to os.walk(), to control error + handling. + +- inspect.is{method|data}descriptor was added, to allow pydoc display + __doc__ of data descriptors. + +- Fixed socket speed loss caused by use of the _socketobject wrapper class + in socket.py. + +- timeit.py now checks the current directory for imports. + +- urllib2.py now knows how to order proxy classes, so the user doesn't + have to insert it in front of other classes, nor do dirty tricks like + inserting a "dummy" HTTPHandler after a ProxyHandler when building an + opener with proxy support. + +- Iterators have been added for dbm keys. + +- random.Random objects can now be pickled. + +Tools/Demos +----------- + +- pydoc now offers help on keywords and topics. + +- Tools/idle is gone; long live Lib/idlelib. + +- diff.py prints file diffs in context, unified, or ndiff formats, + providing a command line interface to difflib.py. + +- texcheck.py is a new script for making a rough validation of Python LaTeX + files. + +Build +----- + +- Setting DESTDIR during 'make install' now allows specifying a + different root directory. + +C API +----- + +- PyType_Ready(): If a type declares that it participates in gc + (Py_TPFLAGS_HAVE_GC), and its base class does not, and its base class's + tp_free slot is the default _PyObject_Del, and type does not define + a tp_free slot itself, _PyObject_GC_Del is assigned to type->tp_free. + Previously _PyObject_Del was inherited, which could at best lead to a + segfault. In addition, if even after this magic the type's tp_free + slot is _PyObject_Del or NULL, and the type is a base type + (Py_TPFLAGS_BASETYPE), TypeError is raised: since the type is a base + type, its dealloc function must call type->tp_free, and since the type + is gc'able, tp_free must not be NULL or _PyObject_Del. + +- PyThreadState_SetAsyncExc(): A new API (deliberately accessible only + from C) to interrupt a thread by sending it an exception. It is + intentional that you have to write your own C extension to call it + from Python. + + +New platforms +------------- + +None this time. + +Tests +----- + +- test_imp rewritten so that it doesn't raise RuntimeError if run as a + side effect of being imported ("import test.autotest"). + +Windows +------- + +- The Windows installer ships with Tcl/Tk 8.4.3 (upgraded from 8.4.1). + +- The installer always suggested that Python be installed on the C: + drive, due to a hardcoded "C:" generated by the Wise installation + wizard. People with machines where C: is not the system drive + usually want Python installed on whichever drive is their system drive + instead. We removed the hardcoded "C:", and two testers on machines + where C: is not the system drive report that the installer now + suggests their system drive. Note that you can always select the + directory you want in the "Select Destination Directory" dialog -- + that's what it's for. + +Mac +--- + +- There's a new module called "autoGIL", which offers a mechanism to + automatically release the Global Interpreter Lock when an event loop + goes to sleep, allowing other threads to run. It's currently only + supported on OSX, in the Mach-O version. +- The OSA modules now allow direct access to properties of the + toplevel application class (in AppleScript terminology). +- The Package Manager can now update itself. + +SourceForge Bugs and Patches Applied +------------------------------------ + +430160, 471893, 501716, 542562, 549151, 569574, 595837, 596434, +598163, 604210, 604716, 610332, 612627, 614770, 620190, 621891, +622042, 639139, 640236, 644345, 649742, 649742, 658233, 660022, +661318, 661676, 662807, 662923, 666219, 672855, 678325, 682347, +683486, 684981, 685773, 686254, 692776, 692959, 693094, 696777, +697989, 700827, 703666, 708495, 708604, 708901, 710733, 711902, +713722, 715782, 718286, 719359, 719367, 723136, 723831, 723962, +724588, 724767, 724767, 725942, 726150, 726446, 726869, 727051, +727719, 727719, 727805, 728277, 728563, 728656, 729096, 729103, +729293, 729297, 729300, 729317, 729395, 729622, 729817, 730170, +730296, 730594, 730685, 730826, 730963, 731209, 731403, 731504, +731514, 731626, 731635, 731643, 731644, 731644, 731689, 732124, +732143, 732234, 732284, 732284, 732479, 732761, 732783, 732951, +733667, 733781, 734118, 734231, 734869, 735051, 735293, 735527, +735613, 735694, 736962, 736962, 737970, 738066, 739313, 740055, +740234, 740301, 741806, 742126, 742741, 742860, 742860, 742911, +744041, 744104, 744238, 744687, 744877, 745055, 745478, 745525, +745620, 746012, 746304, 746366, 746801, 746953, 747348, 747667, +747954, 748846, 748849, 748973, 748975, 749191, 749210, 749759, +749831, 749911, 750008, 750092, 750542, 750595, 751038, 751107, +751276, 751451, 751916, 751941, 751956, 751998, 752671, 753451, +753602, 753617, 753845, 753925, 754014, 754340, 754447, 755031, +755087, 755147, 755245, 755683, 755987, 756032, 756996, 757058, +757229, 757818, 757821, 757822, 758112, 758910, 759227, 759889, +760257, 760703, 760792, 761104, 761337, 761519, 761830, 762455 + + +What's New in Python 2.3 beta 1? +================================ + +*Release date: 25-Apr-2003* + +Core and builtins +----------------- + +- New format codes B, H, I, k and K have been implemented for + PyArg_ParseTuple and PyBuild_Value. + +- New builtin function sum(seq, start=0) returns the sum of all the + items in iterable object seq, plus start (items are normally numbers, + and cannot be strings). + +- bool() called without arguments now returns False rather than + raising an exception. This is consistent with calling the + constructors for the other builtin types -- called without argument + they all return the false value of that type. (SF patch #724135) + +- In support of PEP 269 (making the pgen parser generator accessible + from Python), some changes to the pgen code structure were made; a + few files that used to be linked only with pgen are now linked with + Python itself. + +- The repr() of a weakref object now shows the __name__ attribute of + the referenced object, if it has one. + +- super() no longer ignores data descriptors, except __class__. See + the thread started at + http://mail.python.org/pipermail/python-dev/2003-April/034338.html + +- list.insert(i, x) now interprets negative i as it would be + interpreted by slicing, so negative values count from the end of the + list. This was the only place where such an interpretation was not + placed on a list index. + +- range() now works even if the arguments are longs with magnitude + larger than sys.maxint, as long as the total length of the sequence + fits. E.g., range(2**100, 2**101, 2**100) is the following list: + [1267650600228229401496703205376L]. (SF patch #707427.) + +- Some horridly obscure problems were fixed involving interaction + between garbage collection and old-style classes with "ambitious" + getattr hooks. If an old-style instance didn't have a __del__ method, + but did have a __getattr__ hook, and the instance became reachable + only from an unreachable cycle, and the hook resurrected or deleted + unreachable objects when asked to resolve "__del__", anything up to + a segfault could happen. That's been repaired. + +- dict.pop now takes an optional argument specifying a default + value to return if the key is not in the dict. If a default is not + given and the key is not found, a KeyError will still be raised. + Parallel changes were made to UserDict.UserDict and UserDict.DictMixin. + [SF patch #693753] (contributed by Michael Stone.) + +- sys.getfilesystemencoding() was added to expose + Py_FileSystemDefaultEncoding. + +- New function sys.exc_clear() clears the current exception. This is + rarely needed, but can sometimes be useful to release objects + referenced by the traceback held in sys.exc_info()[2]. (SF patch + #693195.) + +- On 64-bit systems, a dictionary could contain duplicate long/int keys + if the key value was larger than 2**32. See SF bug #689659. + +- Fixed SF bug #663074. The codec system was using global static + variables to store internal data. As a result, any attempts to use the + unicode system with multiple active interpreters, or successive + interpreter executions, would fail. + +- "%c" % u"a" now returns a unicode string instead of raising a + TypeError. u"%c" % 0xffffffff now raises a OverflowError instead + of a ValueError to be consistent with "%c" % 256. See SF patch #710127. + +Extension modules +----------------- + +- The socket module now provides the functions inet_pton and inet_ntop + for converting between string and packed representation of IP + addresses. There is also a new module variable, has_ipv6, which is + True iff the current Python has IPv6 support. See SF patch #658327. + +- Tkinter wrappers around Tcl variables now pass objects directly + to Tcl, instead of first converting them to strings. + +- The .*? pattern in the re module is now special-cased to avoid the + recursion limit. (SF patch #720991 -- many thanks to Gary Herron + and Greg Chapman.) + +- New function sys.call_tracing() allows pdb to debug code + recursively. + +- New function gc.get_referents(obj) returns a list of objects + directly referenced by obj. In effect, it exposes what the object's + tp_traverse slot does, and can be helpful when debugging memory + leaks. + +- The iconv module has been removed from this release. + +- The platform-independent routines for packing floats in IEEE formats + (struct.pack's <f, >f, <d, and >d codes; pickle and cPickle's protocol 1 + pickling of floats) ignored that rounding can cause a carry to + propagate. The worst consequence was that, in rare cases, <f and >f + could produce strings that, when unpacked again, were a factor of 2 + away from the original float. This has been fixed. See SF bug + #705836. + +- New function time.tzset() provides access to the C library tzset() + function, if supported. (SF patch #675422.) + +- Using createfilehandler, deletefilehandler, createtimerhandler functions + on Tkinter.tkinter (_tkinter module) no longer crashes the interpreter. + See SF bug #692416. + +- Modified the fcntl.ioctl() function to allow modification of a passed + mutable buffer (for details see the reference documentation). + +- Made user requested changes to the itertools module. + Subsumed the times() function into repeat(). + Added chain() and cycle(). + +- The rotor module is now deprecated; the encryption algorithm it uses + is not believed to be secure, and including crypto code with Python + has implications for exporting and importing it in various countries. + +- The socket module now always uses the _socketobject wrapper class, even on + platforms which have dup(2). The makefile() method is built directly + on top of the socket without duplicating the file descriptor, allowing + timeouts to work properly. + +Library +------- + +- New generator function os.walk() is an easy-to-use alternative to + os.path.walk(). See os module docs for details. os.path.walk() + isn't deprecated at this time, but may become deprecated in a + future release. + +- Added new module "platform" which provides a wide range of tools + for querying platform dependent features. + +- netrc now allows ASCII punctuation characters in passwords. + +- shelve now supports the optional writeback argument, and exposes + pickle protocol versions. + +- Several methods of nntplib.NNTP have grown an optional file argument + which specifies a file where to divert the command's output + (already supported by the body() method). (SF patch #720468) + +- The self-documenting XML server library DocXMLRPCServer was added. + +- Support for internationalized domain names has been added through + the 'idna' and 'punycode' encodings, the 'stringprep' module, the + 'mkstringprep' tool, and enhancements to the socket and httplib + modules. + +- htmlentitydefs has two new dictionaries: name2codepoint maps + HTML entity names to Unicode codepoints (as integers). + codepoint2name is the reverse mapping. See SF patch #722017. + +- pdb has a new command, "debug", which lets you step through + arbitrary code from the debugger's (pdb) prompt. + +- unittest.failUnlessEqual and its equivalent unittest.assertEqual now + return 'not a == b' rather than 'a != b'. This gives the desired + result for classes that define __eq__ without defining __ne__. + +- sgmllib now supports SGML marked sections, in particular the + MS Office extensions. + +- The urllib module now offers support for the iterator protocol. + SF patch 698520 contributed by Brett Cannon. + +- New module timeit provides a simple framework for timing the + execution speed of expressions and statements. + +- sets.Set objects now support mixed-type __eq__ and __ne__, instead + of raising TypeError. If x is a Set object and y is a non-Set object, + x == y is False, and x != y is True. This is akin to the change made + for mixed-type comparisons of datetime objects in 2.3a2; more info + about the rationale is in the NEWS entry for that. See also SF bug + report <http://www.python.org/sf/693121>. + +- On Unix platforms, if os.listdir() is called with a Unicode argument, + it now returns Unicode strings. (This behavior was added earlier + to the Windows NT/2k/XP version of os.listdir().) + +- Distutils: both 'py_modules' and 'packages' keywords can now be specified + in core.setup(). Previously you could supply one or the other, but + not both of them. (SF patch #695090 from Bernhard Herzog) + +- New csv package makes it easy to read/write CSV files. + +- Module shlex has been extended to allow posix-like shell parsings, + including a split() function for easy spliting of quoted strings and + commands. An iterator interface was also implemented. + +Tools/Demos +----------- + +- New script combinerefs.py helps analyze new PYTHONDUMPREFS output. + See the module docstring for details. + +Build +----- + +- Fix problem building on OSF1 because the compiler only accepted + preprocessor directives that start in column 1. (SF bug #691793.) + +C API +----- + +- Added PyGC_Collect(), equivalent to calling gc.collect(). + +- PyThreadState_GetDict() was changed not to raise an exception or + issue a fatal error when no current thread state is available. This + makes it possible to print dictionaries when no thread is active. + +- LONG_LONG was renamed to PY_LONG_LONG. Extensions that use this and + need compatibility with previous versions can use this: + + #ifndef PY_LONG_LONG + #define PY_LONG_LONG LONG_LONG + #endif + +- Added PyObject_SelfIter() to fill the tp_iter slot for the + typical case where the method returns its self argument. + +- The extended type structure used for heap types (new-style + classes defined by Python code using a class statement) is now + exported from object.h as PyHeapTypeObject. (SF patch #696193.) + +New platforms +------------- + +None this time. + +Tests +----- + +- test_timeout now requires -u network to be passed to regrtest to run. + See SF bug #692988. + +Windows +------- + +- os.fsync() now exists on Windows, and calls the Microsoft _commit() + function. + +- New function winsound.MessageBeep() wraps the Win32 API + MessageBeep(). + +Mac +--- + +- os.listdir() now returns Unicode strings on MacOS X when called with + a Unicode argument. See the general news item under "Library". + +- A new method MacOS.WMAvailable() returns true if it is safe to access + the window manager, false otherwise. + +- EasyDialogs dialogs are now movable-modal, and if the application is + currently in the background they will ask to be moved to the foreground + before displaying. + +- OSA Scripting support has improved a lot, and gensuitemodule.py can now + be used by mere mortals. The documentation is now also more or less + complete. + +- The IDE (in a framework build) now includes introductory documentation + in Apple Help Viewer format. + + +What's New in Python 2.3 alpha 2? +================================= + +*Release date: 19-Feb-2003* + +Core and builtins +----------------- + +- Negative positions returned from PEP 293 error callbacks are now + treated as being relative to the end of the input string. Positions + that are out of bounds raise an IndexError. + +- sys.path[0] (the directory from which the script is loaded) is now + turned into an absolute pathname, unless it is the empty string. + (SF patch #664376.) + +- Finally fixed the bug in compile() and exec where a string ending + with an indented code block but no newline would raise SyntaxError. + This would have been a four-line change in parsetok.c... Except + codeop.py depends on this behavior, so a compilation flag had to be + invented that causes the tokenizer to revert to the old behavior; + this required extra changes to 2 .h files, 2 .c files, and 2 .py + files. (Fixes SF bug #501622.) + +- If a new-style class defines neither __new__ nor __init__, its + constructor would ignore all arguments. This is changed now: the + constructor refuses arguments in this case. This might break code + that worked under Python 2.2. The simplest fix is to add a no-op + __init__: ``def __init__(self, *args, **kw): pass``. + +- Through a bytecode optimizer bug (and I bet you didn't even know + Python *had* a bytecode optimizer :-), "unsigned" hex/oct constants + with a leading minus sign would come out with the wrong sign. + ("Unsigned" hex/oct constants are those with a face value in the + range sys.maxint+1 through sys.maxint*2+1, inclusive; these have + always been interpreted as negative numbers through sign folding.) + E.g. 0xffffffff is -1, and -(0xffffffff) is 1, but -0xffffffff would + come out as -4294967295. This was the case in Python 2.2 through + 2.2.2 and 2.3a1, and in Python 2.4 it will once again have that + value, but according to PEP 237 it really needs to be 1 now. This + will be backported to Python 2.2.3 a well. (SF #660455) + +- int(s, base) sometimes sign-folds hex and oct constants; it only + does this when base is 0 and s.strip() starts with a '0'. When the + sign is actually folded, as in int("0xffffffff", 0) on a 32-bit + machine, which returns -1, a FutureWarning is now issued; in Python + 2.4, this will return 4294967295L, as do int("+0xffffffff", 0) and + int("0xffffffff", 16) right now. (PEP 347) + +- super(X, x): x may now be a proxy for an X instance, i.e. + issubclass(x.__class__, X) but not issubclass(type(x), X). + +- isinstance(x, X): if X is a new-style class, this is now equivalent + to issubclass(type(x), X) or issubclass(x.__class__, X). Previously + only type(x) was tested. (For classic classes this was already the + case.) + +- compile(), eval() and the exec statement now fully support source code + passed as unicode strings. + +- int subclasses can be initialized with longs if the value fits in an int. + See SF bug #683467. + +- long(string, base) takes time linear in len(string) when base is a power + of 2 now. It used to take time quadratic in len(string). + +- filter returns now Unicode results for Unicode arguments. + +- raw_input can now return Unicode objects. + +- List objects' sort() method now accepts None as the comparison function. + Passing None is semantically identical to calling sort() with no + arguments. + +- Fixed crash when printing a subclass of str and __str__ returned self. + See SF bug #667147. + +- Fixed an invalid RuntimeWarning and an undetected error when trying + to convert a long integer into a float which couldn't fit. + See SF bug #676155. + +- Function objects now have a __module__ attribute that is bound to + the name of the module in which the function was defined. This + applies for C functions and methods as well as functions and methods + defined in Python. This attribute is used by pickle.whichmodule(), + which changes the behavior of whichmodule slightly. In Python 2.2 + whichmodule() returns "__main__" for functions that are not defined + at the top-level of a module (examples: methods, nested functions). + Now whichmodule() will return the proper module name. + +Extension modules +----------------- + +- operator.isNumberType() now checks that the object has a nb_int or + nb_float slot, rather than simply checking whether it has a non-NULL + tp_as_number pointer. + +- The imp module now has ways to acquire and release the "import + lock": imp.acquire_lock() and imp.release_lock(). Note: this is a + reentrant lock, so releasing the lock only truly releases it when + this is the last release_lock() call. You can check with + imp.lock_held(). (SF bug #580952 and patch #683257.) + +- Change to cPickle to match pickle.py (see below and PEP 307). + +- Fix some bugs in the parser module. SF bug #678518. + +- Thanks to Scott David Daniels, a subtle bug in how the zlib + extension implemented flush() was fixed. Scott also rewrote the + zlib test suite using the unittest module. (SF bug #640230 and + patch #678531.) + +- Added an itertools module containing high speed, memory efficient + looping constructs inspired by tools from Haskell and SML. + +- The SSL module now handles sockets with a timeout set correctly (SF + patch #675750, fixing SF bug #675552). + +- os/posixmodule has grown the sysexits.h constants (EX_OK and friends). + +- Fixed broken threadstate swap in readline that could cause fatal + errors when a readline hook was being invoked while a background + thread was active. (SF bugs #660476 and #513033.) + +- fcntl now exposes the strops.h I_* constants. + +- Fix a crash on Solaris that occurred when calling close() on + an mmap'ed file which was already closed. (SF patch #665913) + +- Fixed several serious bugs in the zipimport implementation. + +- datetime changes: + + The date class is now properly subclassable. (SF bug #720908) + + The datetime and datetimetz classes have been collapsed into a single + datetime class, and likewise the time and timetz classes into a single + time class. Previously, a datetimetz object with tzinfo=None acted + exactly like a datetime object, and similarly for timetz. This wasn't + enough of a difference to justify distinct classes, and life is simpler + now. + + today() and now() now round system timestamps to the closest + microsecond <http://www.python.org/sf/661086>. This repairs an + irritation most likely seen on Windows systems. + + In dt.astimezone(tz), if tz.utcoffset(dt) returns a duration, + ValueError is raised if tz.dst(dt) returns None (2.3a1 treated it + as 0 instead, but a tzinfo subclass wishing to participate in + time zone conversion has to take a stand on whether it supports + DST; if you don't care about DST, then code dst() to return 0 minutes, + meaning that DST is never in effect). + + The tzinfo methods utcoffset() and dst() must return a timedelta object + (or None) now. In 2.3a1 they could also return an int or long, but that + was an unhelpfully redundant leftover from an earlier version wherein + they couldn't return a timedelta. TOOWTDI. + + The example tzinfo class for local time had a bug. It was replaced + by a later example coded by Guido. + + datetime.astimezone(tz) no longer raises an exception when the + input datetime has no UTC equivalent in tz. For typical "hybrid" time + zones (a single tzinfo subclass modeling both standard and daylight + time), this case can arise one hour per year, at the hour daylight time + ends. See new docs for details. In short, the new behavior mimics + the local wall clock's behavior of repeating an hour in local time. + + dt.astimezone() can no longer be used to convert between naive and aware + datetime objects. If you merely want to attach, or remove, a tzinfo + object, without any conversion of date and time members, use + dt.replace(tzinfo=whatever) instead, where "whatever" is None or a + tzinfo subclass instance. + + A new method tzinfo.fromutc(dt) can be overridden in tzinfo subclasses + to give complete control over how a UTC time is to be converted to + a local time. The default astimezone() implementation calls fromutc() + as its last step, so a tzinfo subclass can affect that too by overriding + fromutc(). It's expected that the default fromutc() implementation will + be suitable as-is for "almost all" time zone subclasses, but the + creativity of political time zone fiddling appears unbounded -- fromutc() + allows the highly motivated to emulate any scheme expressible in Python. + + datetime.now(): The optional tzinfo argument was undocumented (that's + repaired), and its name was changed to tz ("tzinfo" is overloaded enough + already). With a tz argument, now(tz) used to return the local date + and time, and attach tz to it, without any conversion of date and time + members. This was less than useful. Now now(tz) returns the current + date and time as local time in tz's time zone, akin to :: + + tz.fromutc(datetime.utcnow().replace(tzinfo=utc)) + + where "utc" is an instance of a tzinfo subclass modeling UTC. Without + a tz argument, now() continues to return the current local date and time, + as a naive datetime object. + + datetime.fromtimestamp(): Like datetime.now() above, this had less than + useful behavior when the optional tinzo argument was specified. See + also SF bug report <http://www.python.org/sf/660872>. + + date and datetime comparison: In order to prevent comparison from + falling back to the default compare-object-addresses strategy, these + raised TypeError whenever they didn't understand the other object type. + They still do, except when the other object has a "timetuple" attribute, + in which case they return NotImplemented now. This gives other + datetime objects (e.g., mxDateTime) a chance to intercept the + comparison. + + date, time, datetime and timedelta comparison: When the exception + for mixed-type comparisons in the last paragraph doesn't apply, if + the comparison is == then False is returned, and if the comparison is + != then True is returned. Because dict lookup and the "in" operator + only invoke __eq__, this allows, for example, :: + + if some_datetime in some_sequence: + + and :: + + some_dict[some_timedelta] = whatever + + to work as expected, without raising TypeError just because the + sequence is heterogeneous, or the dict has mixed-type keys. [This + seems like a good idea to implement for all mixed-type comparisons + that don't want to allow falling back to address comparison.] + + The constructors building a datetime from a timestamp could raise + ValueError if the platform C localtime()/gmtime() inserted "leap + seconds". Leap seconds are ignored now. On such platforms, it's + possible to have timestamps that differ by a second, yet where + datetimes constructed from them are equal. + + The pickle format of date, time and datetime objects has changed + completely. The undocumented pickler and unpickler functions no + longer exist. The undocumented __setstate__() and __getstate__() + methods no longer exist either. + +Library +------- + +- The logging module was updated slightly; the WARN level was renamed + to WARNING, and the matching function/method warn() to warning(). + +- The pickle and cPickle modules were updated with a new pickling + protocol (documented by pickletools.py, see below) and several + extensions to the pickle customization API (__reduce__, __setstate__ + etc.). The copy module now uses more of the pickle customization + API to copy objects that don't implement __copy__ or __deepcopy__. + See PEP 307 for details. + +- The distutils "register" command now uses http://www.python.org/pypi + as the default repository. (See PEP 301.) + +- the platform dependent path related variables sep, altsep, extsep, + pathsep, curdir, pardir and defpath are now defined in the platform + dependent path modules (e.g. ntpath.py) rather than os.py, so these + variables are now available via os.path. They continue to be + available from the os module. + (see <http://www.python.org/sf/680789>). + +- array.array was added to the types repr.py knows about (see + <http://www.python.org/sf/680789>). + +- The new pickletools.py contains lots of documentation about pickle + internals, and supplies some helpers for working with pickles, such as + a symbolic pickle disassembler. + +- Xmlrpclib.py now supports the builtin boolean type. + +- py_compile has a new 'doraise' flag and a new PyCompileError + exception. + +- SimpleXMLRPCServer now supports CGI through the CGIXMLRPCRequestHandler + class. + +- The sets module now raises TypeError in __cmp__, to clarify that + sets are not intended to be three-way-compared; the comparison + operators are overloaded as subset/superset tests. + +- Bastion.py and rexec.py are disabled. These modules are not safe in + Python 2.2. or 2.3. + +- realpath is now exported when doing ``from poxixpath import *``. + It is also exported for ntpath, macpath, and os2emxpath. + See SF bug #659228. + +- New module tarfile from Lars Gustäbel provides a comprehensive interface + to tar archive files with transparent gzip and bzip2 compression. + See SF patch #651082. + +- urlparse can now parse imap:// URLs. See SF feature request #618024. + +- Tkinter.Canvas.scan_dragto() provides an optional parameter to support + the gain value which is passed to Tk. SF bug# 602259. + +- Fix logging.handlers.SysLogHandler protocol when using UNIX domain sockets. + See SF patch #642974. + +- The dospath module was deleted. Use the ntpath module when manipulating + DOS paths from other platforms. + +Tools/Demos +----------- + +- Two new scripts (db2pickle.py and pickle2db.py) were added to the + Tools/scripts directory to facilitate conversion from the old bsddb module + to the new one. While the user-visible API of the new module is + compatible with the old one, it's likely that the version of the + underlying database library has changed. To convert from the old library, + run the db2pickle.py script using the old version of Python to convert it + to a pickle file. After upgrading Python, run the pickle2db.py script + using the new version of Python to reconstitute your database. For + example: + + % python2.2 db2pickle.py -h some.db > some.pickle + % python2.3 pickle2db.py -h some.db.new < some.pickle + + Run the scripts without any args to get a usage message. + + +Build +----- + +- The audio driver tests (test_ossaudiodev.py and + test_linuxaudiodev.py) are no longer run by default. This is + because they don't always work, depending on your hardware and + software. To run these tests, you must use an invocation like :: + + ./python Lib/test/regrtest.py -u audio test_ossaudiodev + +- On systems which build using the configure script, compiler flags which + used to be lumped together using the OPT flag have been split into two + groups, OPT and BASECFLAGS. OPT is meant to carry just optimization- and + debug-related flags like "-g" and "-O3". BASECFLAGS is meant to carry + compiler flags that are required to get a clean compile. On some + platforms (many Linux flavors in particular) BASECFLAGS will be empty by + default. On others, such as Mac OS X and SCO, it will contain required + flags. This change allows people building Python to override OPT without + fear of clobbering compiler flags which are required to get a clean build. + +- On Darwin/Mac OS X platforms, /sw/lib and /sw/include are added to the + relevant search lists in setup.py. This allows users building Python to + take advantage of the many packages available from the fink project + <http://fink.sf.net/>. + +- A new Makefile target, scriptsinstall, installs a number of useful scripts + from the Tools/scripts directory. + +C API +----- + +- PyEval_GetFrame() is now declared to return a ``PyFrameObject *`` + instead of a plain ``PyObject *``. (SF patch #686601.) + +- PyNumber_Check() now checks that the object has a nb_int or nb_float + slot, rather than simply checking whether it has a non-NULL + tp_as_number pointer. + +- A C type that inherits from a base type that defines tp_as_buffer + will now inherit the tp_as_buffer pointer if it doesn't define one. + (SF #681367) + +- The PyArg_Parse functions now issue a DeprecationWarning if a float + argument is provided when an integer is specified (this affects the 'b', + 'B', 'h', 'H', 'i', and 'l' codes). Future versions of Python will + raise a TypeError. + +Tests +----- + +- Several tests weren't being run from regrtest.py (test_timeout.py, + test_tarfile.py, test_netrc.py, test_multifile.py, + test_importhooks.py and test_imp.py). Now they are. (Note to + developers: please read Lib/test/README when creating a new test, to + make sure to do it right! All tests need to use either unittest or + pydoc.) + +- Added test_posix.py, a test suite for the posix module. + +- Added test_hexoct.py, a test suite for hex/oct constant folding. + +Windows +------- + +- The timeout code for socket connect() didn't work right; this has + now been fixed. test_timeout.py should pass (at least most of the + time). + +- distutils' msvccompiler class now passes the preprocessor options to + the resource compiler. See SF patch #669198. + +- The bsddb module now ships with Sleepycat's 4.1.25.NC, the latest + release without strong cryptography. + +- sys.path[0], if it contains a directory name, is now always an + absolute pathname. (SF patch #664376.) + +- The new logging package is now installed by the Windows installer. It + wasn't in 2.3a1 due to oversight. + +Mac +--- + +- There are new dialogs EasyDialogs.AskFileForOpen, AskFileForSave + and AskFolder. The old macfs.StandardGetFile and friends are deprecated. + +- Most of the standard library now uses pathnames or FSRefs in preference + of FSSpecs, and use the underlying Carbon.File and Carbon.Folder modules + in stead of macfs. macfs will probably be deprecated in the future. + +- Type Carbon.File.FSCatalogInfo and supporting methods have been implemented. + This also makes macfs.FSSpec.SetDates() work again. + +- There is a new module pimp, the package install manager for Python, and + accompanying applet PackageManager. These allow you to easily download + and install pretested extension packages either in source or binary + form. Only in MacPython-OSX. + +- Applets are now built with bundlebuilder in MacPython-OSX, which should make + them more robust and also provides a path towards BuildApplication. The + downside of this change is that applets can no longer be run from the + Terminal window, this will hopefully be fixed in the 2.3b1. + + +What's New in Python 2.3 alpha 1? +================================= + +*Release date: 31-Dec-2002* + +Type/class unification and new-style classes +-------------------------------------------- + +- One can now assign to __bases__ and __name__ of new-style classes. + +- dict() now accepts keyword arguments so that dict(one=1, two=2) + is the equivalent of {"one": 1, "two": 2}. Accordingly, + the existing (but undocumented) 'items' keyword argument has + been eliminated. This means that dict(items=someMapping) now has + a different meaning than before. + +- int() now returns a long object if the argument is outside the + integer range, so int("4" * 1000), int(1e200) and int(1L<<1000) will + all return long objects instead of raising an OverflowError. + +- Assignment to __class__ is disallowed if either the old or the new + class is a statically allocated type object (such as defined by an + extension module). This prevents anomalies like 2.__class__ = bool. + +- New-style object creation and deallocation have been sped up + significantly; they are now faster than classic instance creation + and deallocation. + +- The __slots__ variable can now mention "private" names, and the + right thing will happen (e.g. __slots__ = ["__foo"]). + +- The built-ins slice() and buffer() are now callable types. The + types classobj (formerly class), code, function, instance, and + instancemethod (formerly instance-method), which have no built-in + names but are accessible through the types module, are now also + callable. The type dict-proxy is renamed to dictproxy. + +- Cycles going through the __class__ link of a new-style instance are + now detected by the garbage collector. + +- Classes using __slots__ are now properly garbage collected. + [SF bug 519621] + +- Tightened the __slots__ rules: a slot name must be a valid Python + identifier. + +- The constructor for the module type now requires a name argument and + takes an optional docstring argument. Previously, this constructor + ignored its arguments. As a consequence, deriving a class from a + module (not from the module type) is now illegal; previously this + created an unnamed module, just like invoking the module type did. + [SF bug 563060] + +- A new type object, 'basestring', is added. This is a common base type + for 'str' and 'unicode', and can be used instead of + types.StringTypes, e.g. to test whether something is "a string": + isinstance(x, basestring) is True for Unicode and 8-bit strings. This + is an abstract base class and cannot be instantiated directly. + +- Changed new-style class instantiation so that when C's __new__ + method returns something that's not a C instance, its __init__ is + not called. [SF bug #537450] + +- Fixed super() to work correctly with class methods. [SF bug #535444] + +- If you try to pickle an instance of a class that has __slots__ but + doesn't define or override __getstate__, a TypeError is now raised. + This is done by adding a bozo __getstate__ to the class that always + raises TypeError. (Before, this would appear to be pickled, but the + state of the slots would be lost.) + +Core and builtins +----------------- + +- Import from zipfiles is now supported. The name of a zipfile placed + on sys.path causes the import statement to look for importable Python + modules (with .py, pyc and .pyo extensions) and packages inside the + zipfile. The zipfile import follows the specification (though not + the sample implementation) of PEP 273. The semantics of __path__ are + compatible with those that have been implemented in Jython since + Jython 2.1. + +- PEP 302 has been accepted. Although it was initially developed to + support zipimport, it offers a new, general import hook mechanism. + Several new variables have been added to the sys module: + sys.meta_path, sys.path_hooks, and sys.path_importer_cache; these + make extending the import statement much more convenient than + overriding the __import__ built-in function. For a description of + these, see PEP 302. + +- A frame object's f_lineno attribute can now be written to from a + trace function to change which line will execute next. A command to + exploit this from pdb has been added. [SF patch #643835] + +- The _codecs support module for codecs.py was turned into a builtin + module to assure that at least the builtin codecs are available + to the Python parser for source code decoding according to PEP 263. + +- issubclass now supports a tuple as the second argument, just like + isinstance does. ``issubclass(X, (A, B))`` is equivalent to + ``issubclass(X, A) or issubclass(X, B)``. + +- Thanks to Armin Rigo, the last known way to provoke a system crash + by cleverly arranging for a comparison function to mutate a list + during a list.sort() operation has been fixed. The effect of + attempting to mutate a list, or even to inspect its contents or + length, while a sort is in progress, is not defined by the language. + The C implementation of Python 2.3 attempts to detect mutations, + and raise ValueError if one occurs, but there's no guarantee that + all mutations will be caught, or that any will be caught across + releases or implementations. + +- Unicode file name processing for Windows (PEP 277) is implemented. + All platforms now have an os.path.supports_unicode_filenames attribute, + which is set to True on Windows NT/2000/XP, and False elsewhere. + +- Codec error handling callbacks (PEP 293) are implemented. + Error handling in unicode.encode or str.decode can now be customized. + +- A subtle change to the semantics of the built-in function intern(): + interned strings are no longer immortal. You must keep a reference + to the return value intern() around to get the benefit. + +- Use of 'None' as a variable, argument or attribute name now + issues a SyntaxWarning. In the future, None may become a keyword. + +- SET_LINENO is gone. co_lnotab is now consulted to determine when to + call the trace function. C code that accessed f_lineno should call + PyCode_Addr2Line instead (f_lineno is still there, but only kept up + to date when there is a trace function set). + +- There's a new warning category, FutureWarning. This is used to warn + about a number of situations where the value or sign of an integer + result will change in Python 2.4 as a result of PEP 237 (integer + unification). The warnings implement stage B0 mentioned in that + PEP. The warnings are about the following situations: + + - Octal and hex literals without 'L' prefix in the inclusive range + [0x80000000..0xffffffff]; these are currently negative ints, but + in Python 2.4 they will be positive longs with the same bit + pattern. + + - Left shifts on integer values that cause the outcome to lose + bits or have a different sign than the left operand. To be + precise: x<<n where this currently doesn't yield the same value + as long(x)<<n; in Python 2.4, the outcome will be long(x)<<n. + + - Conversions from ints to string that show negative values as + unsigned ints in the inclusive range [0x80000000..0xffffffff]; + this affects the functions hex() and oct(), and the string + formatting codes %u, %o, %x, and %X. In Python 2.4, these will + show signed values (e.g. hex(-1) currently returns "0xffffffff"; + in Python 2.4 it will return "-0x1"). + +- The bits manipulated under the cover by sys.setcheckinterval() have + been changed. Both the check interval and the ticker used to be + per-thread values. They are now just a pair of global variables. + In addition, the default check interval was boosted from 10 to 100 + bytecode instructions. This may have some effect on systems that + relied on the old default value. In particular, in multi-threaded + applications which try to be highly responsive, response time will + increase by some (perhaps imperceptible) amount. + +- When multiplying very large integers, a version of the so-called + Karatsuba algorithm is now used. This is most effective if the + inputs have roughly the same size. If they both have about N digits, + Karatsuba multiplication has O(N**1.58) runtime (the exponent is + log_base_2(3)) instead of the previous O(N**2). Measured results may + be better or worse than that, depending on platform quirks. Besides + the O() improvement in raw instruction count, the Karatsuba algorithm + appears to have much better cache behavior on extremely large integers + (starting in the ballpark of a million bits). Note that this is a + simple implementation, and there's no intent here to compete with, + e.g., GMP. It gives a very nice speedup when it applies, but a package + devoted to fast large-integer arithmetic should run circles around it. + +- u'%c' will now raise a ValueError in case the argument is an + integer outside the valid range of Unicode code point ordinals. + +- The tempfile module has been overhauled for enhanced security. The + mktemp() function is now deprecated; new, safe replacements are + mkstemp() (for files) and mkdtemp() (for directories), and the + higher-level functions NamedTemporaryFile() and TemporaryFile(). + Use of some global variables in this module is also deprecated; the + new functions have keyword arguments to provide the same + functionality. All Lib, Tools and Demo modules that used the unsafe + interfaces have been updated to use the safe replacements. Thanks + to Zack Weinberg! + +- When x is an object whose class implements __mul__ and __rmul__, + 1.0*x would correctly invoke __rmul__, but 1*x would erroneously + invoke __mul__. This was due to the sequence-repeat code in the int + type. This has been fixed now. + +- Previously, "str1 in str2" required str1 to be a string of length 1. + This restriction has been relaxed to allow str1 to be a string of + any length. Thus "'el' in 'hello world'" returns True now. + +- File objects are now their own iterators. For a file f, iter(f) now + returns f (unless f is closed), and f.next() is similar to + f.readline() when EOF is not reached; however, f.next() uses a + readahead buffer that messes up the file position, so mixing + f.next() and f.readline() (or other methods) doesn't work right. + Calling f.seek() drops the readahead buffer, but other operations + don't. It so happens that this gives a nice additional speed boost + to "for line in file:"; the xreadlines method and corresponding + module are now obsolete. Thanks to Oren Tirosh! + +- Encoding declarations (PEP 263, phase 1) have been implemented. A + comment of the form "# -*- coding: <encodingname> -*-" in the first + or second line of a Python source file indicates the encoding. + +- list.sort() has a new implementation. While cross-platform results + may vary, and in data-dependent ways, this is much faster on many + kinds of partially ordered lists than the previous implementation, + and reported to be just as fast on randomly ordered lists on + several major platforms. This sort is also stable (if A==B and A + precedes B in the list at the start, A precedes B after the sort too), + although the language definition does not guarantee stability. A + potential drawback is that list.sort() may require temp space of + len(list)*2 bytes (``*4`` on a 64-bit machine). It's therefore possible + for list.sort() to raise MemoryError now, even if a comparison function + does not. See <http://www.python.org/sf/587076> for full details. + +- All standard iterators now ensure that, once StopIteration has been + raised, all future calls to next() on the same iterator will also + raise StopIteration. There used to be various counterexamples to + this behavior, which could caused confusion or subtle program + breakage, without any benefits. (Note that this is still an + iterator's responsibility; the iterator framework does not enforce + this.) + +- Ctrl+C handling on Windows has been made more consistent with + other platforms. KeyboardInterrupt can now reliably be caught, + and Ctrl+C at an interactive prompt no longer terminates the + process under NT/2k/XP (it never did under Win9x). Ctrl+C will + interrupt time.sleep() in the main thread, and any child processes + created via the popen family (on win2k; we can't make win9x work + reliably) are also interrupted (as generally happens on for Linux/Unix.) + [SF bugs 231273, 439992 and 581232] + +- sys.getwindowsversion() has been added on Windows. This + returns a tuple with information about the version of Windows + currently running. + +- Slices and repetitions of buffer objects now consistently return + a string. Formerly, strings would be returned most of the time, + but a buffer object would be returned when the repetition count + was one or when the slice range was all inclusive. + +- Unicode objects in sys.path are no longer ignored but treated + as directory names. + +- Fixed string.startswith and string.endswith builtin methods + so they accept negative indices. [SF bug 493951] + +- Fixed a bug with a continue inside a try block and a yield in the + finally clause. [SF bug 567538] + +- Most builtin sequences now support "extended slices", i.e. slices + with a third "stride" parameter. For example, "hello world"[::-1] + gives "dlrow olleh". + +- A new warning PendingDeprecationWarning was added to provide + direction on features which are in the process of being deprecated. + The warning will not be printed by default. To see the pending + deprecations, use -Walways::PendingDeprecationWarning:: + as a command line option or warnings.filterwarnings() in code. + +- Deprecated features of xrange objects have been removed as + promised. The start, stop, and step attributes and the tolist() + method no longer exist. xrange repetition and slicing have been + removed. + +- New builtin function enumerate(x), from PEP 279. Example: + enumerate("abc") is an iterator returning (0,"a"), (1,"b"), (2,"c"). + The argument can be an arbitrary iterable object. + +- The assert statement no longer tests __debug__ at runtime. This means + that assert statements cannot be disabled by assigning a false value + to __debug__. + +- A method zfill() was added to str and unicode, that fills a numeric + string to the left with zeros. For example, + "+123".zfill(6) -> "+00123". + +- Complex numbers supported divmod() and the // and % operators, but + these make no sense. Since this was documented, they're being + deprecated now. + +- String and unicode methods lstrip(), rstrip() and strip() now take + an optional argument that specifies the characters to strip. For + example, "Foo!!!?!?!?".rstrip("?!") -> "Foo". + +- There's a new dictionary constructor (a class method of the dict + class), dict.fromkeys(iterable, value=None). It constructs a + dictionary with keys taken from the iterable and all values set to a + single value. It can be used for building sets and for removing + duplicates from sequences. + +- Added a new dict method pop(key). This removes and returns the + value corresponding to key. [SF patch #539949] + +- A new built-in type, bool, has been added, as well as built-in + names for its two values, True and False. Comparisons and sundry + other operations that return a truth value have been changed to + return a bool instead. Read PEP 285 for an explanation of why this + is backward compatible. + +- Fixed two bugs reported as SF #535905: under certain conditions, + deallocating a deeply nested structure could cause a segfault in the + garbage collector, due to interaction with the "trashcan" code; + access to the current frame during destruction of a local variable + could access a pointer to freed memory. + +- The optional object allocator ("pymalloc") has been enabled by + default. The recommended practice for memory allocation and + deallocation has been streamlined. A header file is included, + Misc/pymemcompat.h, which can be bundled with 3rd party extensions + and lets them use the same API with Python versions from 1.5.2 + onwards. + +- PyErr_Display will provide file and line information for all exceptions + that have an attribute print_file_and_line, not just SyntaxErrors. + +- The UTF-8 codec will now encode and decode Unicode surrogates + correctly and without raising exceptions for unpaired ones. + +- Universal newlines (PEP 278) is implemented. Briefly, using 'U' + instead of 'r' when opening a text file for reading changes the line + ending convention so that any of '\r', '\r\n', and '\n' is + recognized (even mixed in one file); all three are converted to + '\n', the standard Python line end character. + +- file.xreadlines() now raises a ValueError if the file is closed: + Previously, an xreadlines object was returned which would raise + a ValueError when the xreadlines.next() method was called. + +- sys.exit() inadvertently allowed more than one argument. + An exception will now be raised if more than one argument is used. + +- Changed evaluation order of dictionary literals to conform to the + general left to right evaluation order rule. Now {f1(): f2()} will + evaluate f1 first. + +- Fixed bug #521782: when a file was in non-blocking mode, file.read() + could silently lose data or wrongly throw an unknown error. + +- The sq_repeat, sq_inplace_repeat, sq_concat and sq_inplace_concat + slots are now always tried after trying the corresponding nb_* slots. + This fixes a number of minor bugs (see bug #624807). + +- Fix problem with dynamic loading on 64-bit AIX (see bug #639945). + +Extension modules +----------------- + +- Added three operators to the operator module: + operator.pow(a,b) which is equivalent to: a**b. + operator.is_(a,b) which is equivalent to: a is b. + operator.is_not(a,b) which is equivalent to: a is not b. + +- posix.openpty now works on all systems that have /dev/ptmx. + +- A module zipimport exists to support importing code from zip + archives. + +- The new datetime module supplies classes for manipulating dates and + times. The basic design came from the Zope "fishbowl process", and + favors practical commercial applications over calendar esoterica. See + + http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage + +- _tkinter now returns Tcl objects, instead of strings. Objects which + have Python equivalents are converted to Python objects, other objects + are wrapped. This can be configured through the wantobjects method, + or Tkinter.wantobjects. + +- The PyBSDDB wrapper around the Sleepycat Berkeley DB library has + been added as the package bsddb. The traditional bsddb module is + still available in source code, but not built automatically anymore, + and is now named bsddb185. This supports Berkeley DB versions from + 3.0 to 4.1. For help converting your databases from the old module (which + probably used an obsolete version of Berkeley DB) to the new module, see + the db2pickle.py and pickle2db.py scripts described in the Tools/Demos + section above. + +- unicodedata was updated to Unicode 3.2. It supports normalization + and names for Hangul syllables and CJK unified ideographs. + +- resource.getrlimit() now returns longs instead of ints. + +- readline now dynamically adjusts its input/output stream if + sys.stdin/stdout changes. + +- The _tkinter module (and hence Tkinter) has dropped support for + Tcl/Tk 8.0 and 8.1. Only Tcl/Tk versions 8.2, 8.3 and 8.4 are + supported. + +- cPickle.BadPickleGet is now a class. + +- The time stamps in os.stat_result are floating point numbers + after stat_float_times has been called. + +- If the size passed to mmap.mmap() is larger than the length of the + file on non-Windows platforms, a ValueError is raised. [SF bug 585792] + +- The xreadlines module is slated for obsolescence. + +- The strptime function in the time module is now always available (a + Python implementation is used when the C library doesn't define it). + +- The 'new' module is no longer an extension, but a Python module that + only exists for backwards compatibility. Its contents are no longer + functions but callable type objects. + +- The bsddb.*open functions can now take 'None' as a filename. + This will create a temporary in-memory bsddb that won't be + written to disk. + +- posix.getloadavg, posix.lchown, posix.killpg, posix.mknod, and + posix.getpgid have been added where available. + +- The locale module now exposes the C library's gettext interface. It + also has a new function getpreferredencoding. + +- A security hole ("double free") was found in zlib-1.1.3, a popular + third party compression library used by some Python modules. The + hole was quickly plugged in zlib-1.1.4, and the Windows build of + Python now ships with zlib-1.1.4. + +- pwd, grp, and resource return enhanced tuples now, with symbolic + field names. + +- array.array is now a type object. A new format character + 'u' indicates Py_UNICODE arrays. For those, .tounicode and + .fromunicode methods are available. Arrays now support __iadd__ + and __imul__. + +- dl now builds on every system that has dlfcn.h. Failure in case + of sizeof(int)!=sizeof(long)!=sizeof(void*) is delayed until dl.open + is called. + +- The sys module acquired a new attribute, api_version, which evaluates + to the value of the PYTHON_API_VERSION macro with which the + interpreter was compiled. + +- Fixed bug #470582: sre module would return a tuple (None, 'a', 'ab') + when applying the regular expression '^((a)c)?(ab)$' on 'ab'. It now + returns (None, None, 'ab'), as expected. Also fixed handling of + lastindex/lastgroup match attributes in similar cases. For example, + when running the expression r'(a)(b)?b' over 'ab', lastindex must be + 1, not 2. + +- Fixed bug #581080: sre scanner was not checking the buffer limit + before increasing the current pointer. This was creating an infinite + loop in the search function, once the pointer exceeded the buffer + limit. + +- The os.fdopen function now enforces a file mode starting with the + letter 'r', 'w' or 'a', otherwise a ValueError is raised. This fixes + bug #623464. + +- The linuxaudiodev module is now deprecated; it is being replaced by + ossaudiodev. The interface has been extended to cover a lot more of + OSS (see www.opensound.com), including most DSP ioctls and the + OSS mixer API. Documentation forthcoming in 2.3a2. + +Library +------- + +- imaplib.py now supports SSL (Tino Lange and Piers Lauder). + +- Freeze's modulefinder.py has been moved to the standard library; + slightly improved so it will issue less false missing submodule + reports (see sf path #643711 for details). Documentation will follow + with Python 2.3a2. + +- os.path exposes getctime. + +- unittest.py now has two additional methods called assertAlmostEqual() + and failIfAlmostEqual(). They implement an approximate comparison + by rounding the difference between the two arguments and comparing + the result to zero. Approximate comparison is essential for + unit tests of floating point results. + +- calendar.py now depends on the new datetime module rather than + the time module. As a result, the range of allowable dates + has been increased. + +- pdb has a new 'j(ump)' command to select the next line to be + executed. + +- The distutils created windows installers now can run a + postinstallation script. + +- doctest.testmod can now be called without argument, which means to + test the current module. + +- When canceling a server that implemented threading with a keyboard + interrupt, the server would shut down but not terminate (waiting on + client threads). A new member variable, daemon_threads, was added to + the ThreadingMixIn class in SocketServer.py to make it explicit that + this behavior needs to be controlled. + +- A new module, optparse, provides a fancy alternative to getopt for + command line parsing. It is a slightly modified version of Greg + Ward's Optik package. + +- UserDict.py now defines a DictMixin class which defines all dictionary + methods for classes that already have a minimum mapping interface. + This greatly simplifies writing classes that need to be substitutable + for dictionaries (such as the shelve module). + +- shelve.py now subclasses from UserDict.DictMixin. Now shelve supports + all dictionary methods. This eases the transition to persistent + storage for scripts originally written with dictionaries in mind. + +- shelve.open and the various classes in shelve.py now accept an optional + binary flag, which defaults to False. If True, the values stored in the + shelf are binary pickles. + +- A new package, logging, implements the logging API defined by PEP + 282. The code is written by Vinay Sajip. + +- StreamReader, StreamReaderWriter and StreamRecoder in the codecs + modules are iterators now. + +- gzip.py now handles files exceeding 2GB. Files over 4GB also work + now (provided the OS supports it, and Python is configured with large + file support), but in that case the underlying gzip file format can + record only the least-significant 32 bits of the file size, so that + some tools working with gzipped files may report an incorrect file + size. + +- xml.sax.saxutils.unescape has been added, to replace entity references + with their entity value. + +- Queue.Queue.{put,get} now support an optional timeout argument. + +- Various features of Tk 8.4 are exposed in Tkinter.py. The multiple + option of tkFileDialog is exposed as function askopenfile{,name}s. + +- Various configure methods of Tkinter have been stream-lined, so that + tag_configure, image_configure, window_configure now return a + dictionary when invoked with no argument. + +- Importing the readline module now no longer has the side effect of + calling setlocale(LC_CTYPE, ""). The initial "C" locale, or + whatever locale is explicitly set by the user, is preserved. If you + want repr() of 8-bit strings in your preferred encoding to preserve + all printable characters of that encoding, you have to add the + following code to your $PYTHONSTARTUP file or to your application's + main(): + + import locale + locale.setlocale(locale.LC_CTYPE, "") + +- shutil.move was added. shutil.copytree now reports errors as an + exception at the end, instead of printing error messages. + +- Encoding name normalization was generalized to not only + replace hyphens with underscores, but also all other non-alphanumeric + characters (with the exception of the dot which is used for Python + package names during lookup). The aliases.py mapping was updated + to the new standard. + +- mimetypes has two new functions: guess_all_extensions() which + returns a list of all known extensions for a mime type, and + add_type() which adds one mapping between a mime type and + an extension to the database. + +- New module: sets, defines the class Set that implements a mutable + set type using the keys of a dict to represent the set. There's + also a class ImmutableSet which is useful when you need sets of sets + or when you need to use sets as dict keys, and a class BaseSet which + is the base class of the two. + +- Added random.sample(population,k) for random sampling without replacement. + Returns a k length list of unique elements chosen from the population. + +- random.randrange(-sys.maxint-1, sys.maxint) no longer raises + OverflowError. That is, it now accepts any combination of 'start' + and 'stop' arguments so long as each is in the range of Python's + bounded integers. + +- Thanks to Raymond Hettinger, random.random() now uses a new core + generator. The Mersenne Twister algorithm is implemented in C, + threadsafe, faster than the previous generator, has an astronomically + large period (2**19937-1), creates random floats to full 53-bit + precision, and may be the most widely tested random number generator + in existence. + + The random.jumpahead(n) method has different semantics for the new + generator. Instead of jumping n steps ahead, it uses n and the + existing state to create a new state. This means that jumpahead() + continues to support multi-threaded code needing generators of + non-overlapping sequences. However, it will break code which relies + on jumpahead moving a specific number of steps forward. + + The attributes random.whseed and random.__whseed have no meaning for + the new generator. Code using these attributes should switch to a + new class, random.WichmannHill which is provided for backward + compatibility and to make an alternate generator available. + +- New "algorithms" module: heapq, implements a heap queue. Thanks to + Kevin O'Connor for the code and François Pinard for an entertaining + write-up explaining the theory and practical uses of heaps. + +- New encoding for the Palm OS character set: palmos. + +- binascii.crc32() and the zipfile module had problems on some 64-bit + platforms. These have been fixed. On a platform with 8-byte C longs, + crc32() now returns a signed-extended 4-byte result, so that its value + as a Python int is equal to the value computed a 32-bit platform. + +- xml.dom.minidom.toxml and toprettyxml now take an optional encoding + argument. + +- Some fixes in the copy module: when an object is copied through its + __reduce__ method, there was no check for a __setstate__ method on + the result [SF patch 565085]; deepcopy should treat instances of + custom metaclasses the same way it treats instances of type 'type' + [SF patch 560794]. + +- Sockets now support timeout mode. After s.settimeout(T), where T is + a float expressing seconds, subsequent operations raise an exception + if they cannot be completed within T seconds. To disable timeout + mode, use s.settimeout(None). There's also a module function, + socket.setdefaulttimeout(T), which sets the default for all sockets + created henceforth. + +- getopt.gnu_getopt was added. This supports GNU-style option + processing, where options can be mixed with non-option arguments. + +- Stop using strings for exceptions. String objects used for + exceptions are now classes deriving from Exception. The objects + changed were: Tkinter.TclError, bdb.BdbQuit, macpath.norm_error, + tabnanny.NannyNag, and xdrlib.Error. + +- Constants BOM_UTF8, BOM_UTF16, BOM_UTF16_LE, BOM_UTF16_BE, + BOM_UTF32, BOM_UTF32_LE and BOM_UTF32_BE that represent the Byte + Order Mark in UTF-8, UTF-16 and UTF-32 encodings for little and + big endian systems were added to the codecs module. The old names + BOM32_* and BOM64_* were off by a factor of 2. + +- Added conversion functions math.degrees() and math.radians(). + +- math.log() now takes an optional argument: math.log(x[, base]). + +- ftplib.retrlines() now tests for callback is None rather than testing + for False. Was causing an error when given a callback object which + was callable but also returned len() as zero. The change may + create new breakage if the caller relied on the undocumented behavior + and called with callback set to [] or some other False value not + identical to None. + +- random.gauss() uses a piece of hidden state used by nothing else, + and the .seed() and .whseed() methods failed to reset it. In other + words, setting the seed didn't completely determine the sequence of + results produced by random.gauss(). It does now. Programs repeatedly + mixing calls to a seed method with calls to gauss() may see different + results now. + +- The pickle.Pickler class grew a clear_memo() method to mimic that + provided by cPickle.Pickler. + +- difflib's SequenceMatcher class now does a dynamic analysis of + which elements are so frequent as to constitute noise. For + comparing files as sequences of lines, this generally works better + than the IS_LINE_JUNK function, and function ndiff's linejunk + argument defaults to None now as a result. A happy benefit is + that SequenceMatcher may run much faster now when applied + to large files with many duplicate lines (for example, C program + text with lots of repeated "}" and "return NULL;" lines). + +- New Text.dump() method in Tkinter module. + +- New distutils commands for building packagers were added to + support pkgtool on Solaris and swinstall on HP-UX. + +- distutils now has a new abstract binary packager base class + command/bdist_packager, which simplifies writing packagers. + This will hopefully provide the missing bits to encourage + people to submit more packagers, e.g. for Debian, FreeBSD + and other systems. + +- The UTF-16, -LE and -BE stream readers now raise a + NotImplementedError for all calls to .readline(). Previously, they + used to just produce garbage or fail with an encoding error -- + UTF-16 is a 2-byte encoding and the C lib's line reading APIs don't + work well with these. + +- compileall now supports quiet operation. + +- The BaseHTTPServer now implements optional HTTP/1.1 persistent + connections. + +- socket module: the SSL support was broken out of the main + _socket module C helper and placed into a new _ssl helper + which now gets imported by socket.py if available and working. + +- encodings package: added aliases for all supported IANA character + sets + +- ftplib: to safeguard the user's privacy, anonymous login will use + "anonymous@" as default password, rather than the real user and host + name. + +- webbrowser: tightened up the command passed to os.system() so that + arbitrary shell code can't be executed because a bogus URL was + passed in. + +- gettext.translation has an optional fallback argument, and + gettext.find an optional all argument. Translations will now fallback + on a per-message basis. The module supports plural forms, by means + of gettext.[d]ngettext and Translation.[u]ngettext. + +- distutils bdist commands now offer a --skip-build option. + +- warnings.warn now accepts a Warning instance as first argument. + +- The xml.sax.expatreader.ExpatParser class will no longer create + circular references by using itself as the locator that gets passed + to the content handler implementation. [SF bug #535474] + +- The email.Parser.Parser class now properly parses strings regardless + of their line endings, which can be any of \r, \n, or \r\n (CR, LF, + or CRLF). Also, the Header class's constructor default arguments + has changed slightly so that an explicit maxlinelen value is always + honored, and so unicode conversion error handling can be specified. + +- distutils' build_ext command now links C++ extensions with the C++ + compiler available in the Makefile or CXX environment variable, if + running under \*nix. + +- New module bz2: provides a comprehensive interface for the bz2 compression + library. It implements a complete file interface, one-shot (de)compression + functions, and types for sequential (de)compression. + +- New pdb command 'pp' which is like 'p' except that it pretty-prints + the value of its expression argument. + +- Now bdist_rpm distutils command understands a verify_script option in + the config file, including the contents of the referred filename in + the "%verifyscript" section of the rpm spec file. + +- Fixed bug #495695: webbrowser module would run graphic browsers in a + unix environment even if DISPLAY was not set. Also, support for + skipstone browser was included. + +- Fixed bug #636769: rexec would run unallowed code if subclasses of + strings were used as parameters for certain functions. + +Tools/Demos +----------- + +- pygettext.py now supports globbing on Windows, and accepts module + names in addition to accepting file names. + +- The SGI demos (Demo/sgi) have been removed. Nobody thought they + were interesting any more. (The SGI library modules and extensions + are still there; it is believed that at least some of these are + still used and useful.) + +- IDLE supports the new encoding declarations (PEP 263); it can also + deal with legacy 8-bit files if they use the locale's encoding. It + allows non-ASCII strings in the interactive shell and executes them + in the locale's encoding. + +- freeze.py now produces binaries which can import shared modules, + unlike before when this failed due to missing symbol exports in + the generated binary. + +Build +----- + +- On Unix, IDLE is now installed automatically. + +- The fpectl module is not built by default; it's dangerous or useless + except in the hands of experts. + +- The public Python C API will generally be declared using PyAPI_FUNC + and PyAPI_DATA macros, while Python extension module init functions + will be declared with PyMODINIT_FUNC. DL_EXPORT/DL_IMPORT macros + are deprecated. + +- A bug was fixed that could cause COUNT_ALLOCS builds to segfault, or + get into infinite loops, when a new-style class got garbage-collected. + Unfortunately, to avoid this, the way COUNT_ALLOCS works requires + that new-style classes be immortal in COUNT_ALLOCS builds. Note that + COUNT_ALLOCS is not enabled by default, in either release or debug + builds, and that new-style classes are immortal only in COUNT_ALLOCS + builds. + +- Compiling out the cyclic garbage collector is no longer an option. + The old symbol WITH_CYCLE_GC is now ignored, and Python.h arranges + that it's always defined (for the benefit of any extension modules + that may be conditionalizing on it). A bonus is that any extension + type participating in cyclic gc can choose to participate in the + Py_TRASHCAN mechanism now too; in the absence of cyclic gc, this used + to require editing the core to teach the trashcan mechanism about the + new type. + +- According to Annex F of the current C standard, + + The Standard C macro HUGE_VAL and its float and long double analogs, + HUGE_VALF and HUGE_VALL, expand to expressions whose values are + positive infinities. + + Python only uses the double HUGE_VAL, and only to #define its own symbol + Py_HUGE_VAL. Some platforms have incorrect definitions for HUGE_VAL. + pyport.h used to try to worm around that, but the workarounds triggered + other bugs on other platforms, so we gave up. If your platform defines + HUGE_VAL incorrectly, you'll need to #define Py_HUGE_VAL to something + that works on your platform. The only instance of this I'm sure about + is on an unknown subset of Cray systems, described here: + + http://www.cray.com/swpubs/manuals/SN-2194_2.0/html-SN-2194_2.0/x3138.htm + + Presumably 2.3a1 breaks such systems. If anyone uses such a system, help! + +- The configure option --without-doc-strings can be used to remove the + doc strings from the builtin functions and modules; this reduces the + size of the executable. + +- The universal newlines option (PEP 278) is on by default. On Unix + it can be disabled by passing --without-universal-newlines to the + configure script. On other platforms, remove + WITH_UNIVERSAL_NEWLINES from pyconfig.h. + +- On Unix, a shared libpython2.3.so can be created with --enable-shared. + +- All uses of the CACHE_HASH, INTERN_STRINGS, and DONT_SHARE_SHORT_STRINGS + preprocessor symbols were eliminated. The internal decisions they + controlled stopped being experimental long ago. + +- The tools used to build the documentation now work under Cygwin as + well as Unix. + +- The bsddb and dbm module builds have been changed to try and avoid version + skew problems and disable linkage with Berkeley DB 1.85 unless the + installer knows what s/he's doing. See the section on building these + modules in the README file for details. + +C API +----- + +- PyNumber_Check() now returns true for string and unicode objects. + This is a result of these types having a partially defined + tp_as_number slot. (This is not a feature, but an indication that + PyNumber_Check() is not very useful to determine numeric behavior. + It may be deprecated.) + +- The string object's layout has changed: the pointer member + ob_sinterned has been replaced by an int member ob_sstate. On some + platforms (e.g. most 64-bit systems) this may change the offset of + the ob_sval member, so as a precaution the API_VERSION has been + incremented. The apparently unused feature of "indirect interned + strings", supported by the ob_sinterned member, is gone. Interned + strings are now usually mortal; there is a new API, + PyString_InternImmortal() that creates immortal interned strings. + (The ob_sstate member can only take three values; however, while + making it a char saves a few bytes per string object on average, in + it also slowed things down a bit because ob_sval was no longer + aligned.) + +- The Py_InitModule*() functions now accept NULL for the 'methods' + argument. Modules without global functions are becoming more common + now that factories can be types rather than functions. + +- New C API PyUnicode_FromOrdinal() which exposes unichr() at C + level. + +- New functions PyErr_SetExcFromWindowsErr() and + PyErr_SetExcFromWindowsErrWithFilename(). Similar to + PyErr_SetFromWindowsErrWithFilename() and + PyErr_SetFromWindowsErr(), but they allow to specify + the exception type to raise. Available on Windows. + +- Py_FatalError() is now declared as taking a const char* argument. It + was previously declared without const. This should not affect working + code. + +- Added new macro PySequence_ITEM(o, i) that directly calls + sq_item without rechecking that o is a sequence and without + adjusting for negative indices. + +- PyRange_New() now raises ValueError if the fourth argument is not 1. + This is part of the removal of deprecated features of the xrange + object. + +- PyNumber_Coerce() and PyNumber_CoerceEx() now also invoke the type's + coercion if both arguments have the same type but this type has the + CHECKTYPES flag set. This is to better support proxies. + +- The type of tp_free has been changed from "``void (*)(PyObject *)``" to + "``void (*)(void *)``". + +- PyObject_Del, PyObject_GC_Del are now functions instead of macros. + +- A type can now inherit its metatype from its base type. Previously, + when PyType_Ready() was called, if ob_type was found to be NULL, it + was always set to &PyType_Type; now it is set to base->ob_type, + where base is tp_base, defaulting to &PyObject_Type. + +- PyType_Ready() accidentally did not inherit tp_is_gc; now it does. + +- The PyCore_* family of APIs have been removed. + +- The "u#" parser marker will now pass through Unicode objects as-is + without going through the buffer API. + +- The enumerators of cmp_op have been renamed to use the prefix ``PyCmp_``. + +- An old #define of ANY as void has been removed from pyport.h. This + hasn't been used since Python's pre-ANSI days, and the #define has + been marked as obsolete since then. SF bug 495548 says it created + conflicts with other packages, so keeping it around wasn't harmless. + +- Because Python's magic number scheme broke on January 1st, we decided + to stop Python development. Thanks for all the fish! + +- Some of us don't like fish, so we changed Python's magic number + scheme to a new one. See Python/import.c for details. + +New platforms +------------- + +- OpenVMS is now supported. + +- AtheOS is now supported. + +- the EMX runtime environment on OS/2 is now supported. + +- GNU/Hurd is now supported. + +Tests +----- + +- The regrtest.py script's -u option now provides a way to say "allow + all resources except this one." For example, to allow everything + except bsddb, give the option '-uall,-bsddb'. + +Windows +------- + +- The Windows distribution now ships with version 4.0.14 of the + Sleepycat Berkeley database library. This should be a huge + improvement over the previous Berkeley DB 1.85, which had many + bugs. + XXX What are the licensing issues here? + XXX If a user has a database created with a previous version of + XXX Python, what must they do to convert it? + XXX I'm still not sure how to link this thing (see PCbuild/readme.txt). + XXX The version # is likely to change before 2.3a1. + +- The Windows distribution now ships with a Secure Sockets Library (SLL) + module (_ssl.pyd) + +- The Windows distribution now ships with Tcl/Tk version 8.4.1 (it + previously shipped with Tcl/Tk 8.3.2). + +- When Python is built under a Microsoft compiler, sys.version now + includes the compiler version number (_MSC_VER). For example, under + MSVC 6, sys.version contains the substring "MSC v.1200 ". 1200 is + the value of _MSC_VER under MSVC 6. + +- Sometimes the uninstall executable (UNWISE.EXE) vanishes. One cause + of that has been fixed in the installer (disabled Wise's "delete in- + use files" uninstall option). + +- Fixed a bug in urllib's proxy handling in Windows. [SF bug #503031] + +- The installer now installs Start menu shortcuts under (the local + equivalent of) "All Users" when doing an Admin install. + +- file.truncate([newsize]) now works on Windows for all newsize values. + It used to fail if newsize didn't fit in 32 bits, reflecting a + limitation of MS _chsize (which is no longer used). + +- os.waitpid() is now implemented for Windows, and can be used to block + until a specified process exits. This is similar to, but not exactly + the same as, os.waitpid() on POSIX systems. If you're waiting for + a specific process whose pid was obtained from one of the spawn() + functions, the same Python os.waitpid() code works across platforms. + See the docs for details. The docs were changed to clarify that + spawn functions return, and waitpid requires, a process handle on + Windows (not the same thing as a Windows process id). + +- New tempfile.TemporaryFile implementation for Windows: this doesn't + need a TemporaryFileWrapper wrapper anymore, and should be immune + to a nasty problem: before 2.3, if you got a temp file on Windows, it + got wrapped in an object whose close() method first closed the + underlying file, then deleted the file. This usually worked fine. + However, the spawn family of functions on Windows create (at a low C + level) the same set of open files in the spawned process Q as were + open in the spawning process P. If a temp file f was among them, then + doing f.close() in P first closed P's C-level file handle on f, but Q's + C-level file handle on f remained open, so the attempt in P to delete f + blew up with a "Permission denied" error (Windows doesn't allow + deleting open files). This was surprising, subtle, and difficult to + work around. + +- The os module now exports all the symbolic constants usable with the + low-level os.open() on Windows: the new constants in 2.3 are + O_NOINHERIT, O_SHORT_LIVED, O_TEMPORARY, O_RANDOM and O_SEQUENTIAL. + The others were also available in 2.2: O_APPEND, O_BINARY, O_CREAT, + O_EXCL, O_RDONLY, O_RDWR, O_TEXT, O_TRUNC and O_WRONLY. Contrary + to Microsoft docs, O_SHORT_LIVED does not seem to imply O_TEMPORARY + (so specify both if you want both; note that neither is useful unless + specified with O_CREAT too). + +Mac +---- + +- Mac/Relnotes is gone, the release notes are now here. + +- Python (the OSX-only, unix-based version, not the OS9-compatible CFM + version) now fully supports unicode strings as arguments to various file + system calls, eg. open(), file(), os.stat() and os.listdir(). + +- The current naming convention for Python on the Macintosh is that MacPython + refers to the unix-based OSX-only version, and MacPython-OS9 refers to the + CFM-based version that runs on both OS9 and OSX. + +- All MacPython-OS9 functionality is now available in an OSX unix build, + including the Carbon modules, the IDE, OSA support, etc. A lot of this + will only work correctly in a framework build, though, because you cannot + talk to the window manager unless your application is run from a .app + bundle. There is a command line tool "pythonw" that runs your script + with an interpreter living in such a .app bundle, this interpreter should + be used to run any Python script using the window manager (including + Tkinter or wxPython scripts). + +- Most of Mac/Lib has moved to Lib/plat-mac, which is again used both in + MacPython-OSX and MacPython-OS9. The only modules remaining in Mac/Lib + are specifically for MacPython-OS9 (CFM support, preference resources, etc). + +- A new utility PythonLauncher will start a Python interpreter when a .py or + .pyw script is double-clicked in the Finder. By default .py scripts are + run with a normal Python interpreter in a Terminal window and .pyw + files are run with a window-aware pythonw interpreter without a Terminal + window, but all this can be customized. + +- MacPython-OS9 is now Carbon-only, so it runs on Mac OS 9 or Mac OS X and + possibly on Mac OS 8.6 with the right CarbonLib installed, but not on earlier + releases. + +- Many tools such as BuildApplet.py and gensuitemodule.py now support a command + line interface too. + +- All the Carbon classes are now PEP253 compliant, meaning that you can + subclass them from Python. Most of the attributes have gone, you should + now use the accessor function call API, which is also what Apple's + documentation uses. Some attributes such as grafport.visRgn are still + available for convenience. + +- New Carbon modules File (implementing the APIs in Files.h and Aliases.h) + and Folder (APIs from Folders.h). The old macfs builtin module is + gone, and replaced by a Python wrapper around the new modules. + +- Pathname handling should now be fully consistent: MacPython-OSX always uses + unix pathnames and MacPython-OS9 always uses colon-separated Mac pathnames + (also when running on Mac OS X). + +- New Carbon modules Help and AH give access to the Carbon Help Manager. + There are hooks in the IDE to allow accessing the Python documentation + (and Apple's Carbon and Cocoa documentation) through the Help Viewer. + See Mac/OSX/README for converting the Python documentation to a + Help Viewer compatible form and installing it. + +- OSA support has been redesigned and the generated Python classes now + mirror the inheritance defined by the underlying OSA classes. + +- MacPython no longer maps both \r and \n to \n on input for any text file. + This feature has been replaced by universal newline support (PEP278). + +- The default encoding for Python sourcefiles in MacPython-OS9 is no longer + mac-roman (or whatever your local Mac encoding was) but "ascii", like on + other platforms. If you really need sourcefiles with Mac characters in them + you can change this in site.py. + + +What's New in Python 2.2 final? +=============================== + +*Release date: 21-Dec-2001* + +Type/class unification and new-style classes +-------------------------------------------- + +- pickle.py, cPickle: allow pickling instances of new-style classes + with a custom metaclass. + +Core and builtins +----------------- + +- weakref proxy object: when comparing, unwrap both arguments if both + are proxies. + +Extension modules +----------------- + +- binascii.b2a_base64(): fix a potential buffer overrun when encoding + very short strings. + +- cPickle: the obscure "fast" mode was suspected of causing stack + overflows on the Mac. Hopefully fixed this by setting the recursion + limit much smaller. If the limit is too low (it only affects + performance), you can change it by defining PY_CPICKLE_FAST_LIMIT + when compiling cPickle.c (or in pyconfig.h). + +Library +------- + +- dumbdbm.py: fixed a dumb old bug (the file didn't get synched at + close or delete time). + +- rfc822.py: fixed a bug where the address '<>' was converted to None + instead of an empty string (also fixes the email.Utils module). + +- xmlrpclib.py: version 1.0.0; uses precision for doubles. + +- test suite: the pickle and cPickle tests were not executing any code + when run from the standard regression test. + +Tools/Demos +----------- + +Build +----- + +C API +----- + +New platforms +------------- + +Tests +----- + +Windows +------- + +- distutils package: fixed broken Windows installers (bdist_wininst). + +- tempfile.py: prevent mysterious warnings when TemporaryFileWrapper + instances are deleted at process exit time. + +- socket.py: prevent mysterious warnings when socket instances are + deleted at process exit time. + +- posixmodule.c: fix a Windows crash with stat() of a filename ending + in backslash. + +Mac +---- + +- The Carbon toolbox modules have been upgraded to Universal Headers + 3.4, and experimental CoreGraphics and CarbonEvents modules have + been added. All only for framework-enabled MacOSX. + + +What's New in Python 2.2c1? +=========================== + +*Release date: 14-Dec-2001* + +Type/class unification and new-style classes +-------------------------------------------- + +- Guido's tutorial introduction to the new type/class features has + been extensively updated. See + + http://www.python.org/2.2/descrintro.html + + That remains the primary documentation in this area. + +- Fixed a leak: instance variables declared with __slots__ were never + deleted! + +- The "delete attribute" method of descriptor objects is called + __delete__, not __del__. In previous releases, it was mistakenly + called __del__, which created an unfortunate overloading condition + with finalizers. (The "get attribute" and "set attribute" methods + are still called __get__ and __set__, respectively.) + +- Some subtle issues with the super built-in were fixed: + + (a) When super itself is subclassed, its __get__ method would still + return an instance of the base class (i.e., of super). + + (b) super(C, C()).__class__ would return C rather than super. This + is confusing. To fix this, I decided to change the semantics of + super so that it only applies to code attributes, not to data + attributes. After all, overriding data attributes is not + supported anyway. + + (c) The __get__ method didn't check whether the argument was an + instance of the type used in creation of the super instance. + +- Previously, hash() of an instance of a subclass of a mutable type + (list or dictionary) would return some value, rather than raising + TypeError. This has been fixed. Also, directly calling + dict.__hash__ and list.__hash__ now raises the same TypeError + (previously, these were the same as object.__hash__). + +- New-style objects now support deleting their __dict__. This is for + all intents and purposes equivalent to assigning a brand new empty + dictionary, but saves space if the object is not used further. + +Core and builtins +----------------- + +- -Qnew now works as documented in PEP 238: when -Qnew is passed on + the command line, all occurrences of "/" use true division instead + of classic division. See the PEP for details. Note that "all" + means all instances in library and 3rd-party modules, as well as in + your own code. As the PEP says, -Qnew is intended for use only in + educational environments with control over the libraries in use. + Note that test_coercion.py in the standard Python test suite fails + under -Qnew; this is expected, and won't be repaired until true + division becomes the default (in the meantime, test_coercion is + testing the current rules). + +- complex() now only allows the first argument to be a string + argument, and raises TypeError if either the second arg is a string + or if the second arg is specified when the first is a string. + +Extension modules +----------------- + +- gc.get_referents was renamed to gc.get_referrers. + +Library +------- + +- Functions in the os.spawn() family now release the global interpreter + lock around calling the platform spawn. They should always have done + this, but did not before 2.2c1. Multithreaded programs calling + an os.spawn function with P_WAIT will no longer block all Python threads + until the spawned program completes. It's possible that some programs + relies on blocking, although more likely by accident than by design. + +- webbrowser defaults to netscape.exe on OS/2 now. + +- Tix.ResizeHandle exposes detach_widget, hide, and show. + +- The charset alias windows_1252 has been added. + +- types.StringTypes is a tuple containing the defined string types; + usually this will be (str, unicode), but if Python was compiled + without Unicode support it will be just (str,). + +- The pulldom and minidom modules were synchronized to PyXML. + +Tools/Demos +----------- + +- A new script called Tools/scripts/google.py was added, which fires + off a search on Google. + +Build +----- + +- Note that release builds of Python should arrange to define the + preprocessor symbol NDEBUG on the command line (or equivalent). + In the 2.2 pre-release series we tried to define this by magic in + Python.h instead, but it proved to cause problems for extension + authors. The Unix, Windows and Mac builds now all define NDEBUG in + release builds via cmdline (or equivalent) instead. Ports to + other platforms should do likewise. + +- It is no longer necessary to use --with-suffix when building on a + case-insensitive file system (such as Mac OS X HFS+). In the build + directory an extension is used, but not in the installed python. + +C API +----- + +- New function PyDict_MergeFromSeq2() exposes the builtin dict + constructor's logic for updating a dictionary from an iterable object + producing key-value pairs. + +- PyArg_ParseTupleAndKeywords() requires that the number of entries in + the keyword list equal the number of argument specifiers. This + wasn't checked correctly, and PyArg_ParseTupleAndKeywords could even + dump core in some bad cases. This has been repaired. As a result, + PyArg_ParseTupleAndKeywords may raise RuntimeError in bad cases that + previously went unchallenged. + +New platforms +------------- + +Tests +----- + +Windows +------- + +Mac +---- + +- In unix-Python on Mac OS X (and darwin) sys.platform is now "darwin", + without any trailing digits. + +- Changed logic for finding python home in Mac OS X framework Pythons. + Now sys.executable points to the executable again, in stead of to + the shared library. The latter is used only for locating the python + home. + + +What's New in Python 2.2b2? +=========================== + +*Release date: 16-Nov-2001* + +Type/class unification and new-style classes +-------------------------------------------- + +- Multiple inheritance mixing new-style and classic classes in the + list of base classes is now allowed, so this works now: + + class Classic: pass + class Mixed(Classic, object): pass + + The MRO (method resolution order) for each base class is respected + according to its kind, but the MRO for the derived class is computed + using new-style MRO rules if any base class is a new-style class. + This needs to be documented. + +- The new builtin dictionary() constructor, and dictionary type, have + been renamed to dict. This reflects a decade of common usage. + +- dict() now accepts an iterable object producing 2-sequences. For + example, dict(d.items()) == d for any dictionary d. The argument, + and the elements of the argument, can be any iterable objects. + +- New-style classes can now have a __del__ method, which is called + when the instance is deleted (just like for classic classes). + +- Assignment to object.__dict__ is now possible, for objects that are + instances of new-style classes that have a __dict__ (unless the base + class forbids it). + +- Methods of built-in types now properly check for keyword arguments + (formerly these were silently ignored). The only built-in methods + that take keyword arguments are __call__, __init__ and __new__. + +- The socket function has been converted to a type; see below. + +Core and builtins +----------------- + +- Assignment to __debug__ raises SyntaxError at compile-time. This + was promised when 2.1c1 was released as "What's New in Python 2.1c1" + (see below) says. + +- Clarified the error messages for unsupported operands to an operator + (like 1 + ''). + +Extension modules +----------------- + +- mmap has a new keyword argument, "access", allowing a uniform way for + both Windows and Unix users to create read-only, write-through and + copy-on-write memory mappings. This was previously possible only on + Unix. A new keyword argument was required to support this in a + uniform way because the mmap() signatures had diverged across + platforms. Thanks to Jay T Miller for repairing this! + +- By default, the gc.garbage list now contains only those instances in + unreachable cycles that have __del__ methods; in 2.1 it contained all + instances in unreachable cycles. "Instances" here has been generalized + to include instances of both new-style and old-style classes. + +- The socket module defines a new method for socket objects, + sendall(). This is like send() but may make multiple calls to + send() until all data has been sent. Also, the socket function has + been converted to a subclassable type, like list and tuple (etc.) + before it; socket and SocketType are now the same thing. + +- Various bugfixes to the curses module. There is now a test suite + for the curses module (you have to run it manually). + +- binascii.b2a_base64 no longer places an arbitrary restriction of 57 + bytes on its input. + +Library +------- + +- tkFileDialog exposes a Directory class and askdirectory + convenience function. + +- Symbolic group names in regular expressions must be unique. For + example, the regexp r'(?P<abc>)(?P<abc>)' is not allowed, because a + single name can't mean both "group 1" and "group 2" simultaneously. + Python 2.2 detects this error at regexp compilation time; + previously, the error went undetected, and results were + unpredictable. Also in sre, the pattern.split(), pattern.sub(), and + pattern.subn() methods have been rewritten in C. Also, an + experimental function/method finditer() has been added, which works + like findall() but returns an iterator. + +- Tix exposes more commands through the classes DirSelectBox, + DirSelectDialog, ListNoteBook, Meter, CheckList, and the + methods tix_addbitmapdir, tix_cget, tix_configure, tix_filedialog, + tix_getbitmap, tix_getimage, tix_option_get, and tix_resetoptions. + +- Traceback objects are now scanned by cyclic garbage collection, so + cycles created by casual use of sys.exc_info() no longer cause + permanent memory leaks (provided garbage collection is enabled). + +- os.extsep -- a new variable needed by the RISCOS support. It is the + separator used by extensions, and is '.' on all platforms except + RISCOS, where it is '/'. There is no need to use this variable + unless you have a masochistic desire to port your code to RISCOS. + +- mimetypes.py has optional support for non-standard, but commonly + found types. guess_type() and guess_extension() now accept an + optional 'strict' flag, defaulting to true, which controls whether + recognize non-standard types or not. A few non-standard types we + know about have been added. Also, when run as a script, there are + new -l and -e options. + +- statcache is now deprecated. + +- email.Utils.formatdate() now produces the preferred RFC 2822 style + dates with numeric timezones (it used to produce obsolete dates + hard coded to "GMT" timezone). An optional 'localtime' flag is + added to produce dates in the local timezone, with daylight savings + time properly taken into account. + +- In pickle and cPickle, instead of masking errors in load() by + transforming them into SystemError, we let the original exception + propagate out. Also, implement support for __safe_for_unpickling__ + in pickle, as it already was supported in cPickle. + +Tools/Demos +----------- + +Build +----- + +- The dbm module is built using libdb1 if available. The bsddb module + is built with libdb3 if available. + +- Misc/Makefile.pre.in has been removed by BDFL pronouncement. + +C API +----- + +- New function PySequence_Fast_GET_SIZE() returns the size of a non- + NULL result from PySequence_Fast(), more quickly than calling + PySequence_Size(). + +- New argument unpacking function PyArg_UnpackTuple() added. + +- New functions PyObject_CallFunctionObjArgs() and + PyObject_CallMethodObjArgs() have been added to make it more + convenient and efficient to call functions and methods from C. + +- PyArg_ParseTupleAndKeywords() no longer masks errors, so it's + possible that this will propagate errors it didn't before. + +- New function PyObject_CheckReadBuffer(), which returns true if its + argument supports the single-segment readable buffer interface. + +New platforms +------------- + +- We've finally confirmed that this release builds on HP-UX 11.00, + *with* threads, and passes the test suite. + +- Thanks to a series of patches from Michael Muller, Python may build + again under OS/2 Visual Age C++. + +- Updated RISCOS port by Dietmar Schwertberger. + +Tests +----- + +- Added a test script for the curses module. It isn't run automatically; + regrtest.py must be run with '-u curses' to enable it. + +Windows +------- + +Mac +---- + +- PythonScript has been moved to unsupported and is slated to be + removed completely in the next release. + +- It should now be possible to build applets that work on both OS9 and + OSX. + +- The core is now linked with CoreServices not Carbon; as a side + result, default 8bit encoding on OSX is now ASCII. + +- Python should now build on OSX 10.1.1 + + +What's New in Python 2.2b1? +=========================== + +*Release date: 19-Oct-2001* + +Type/class unification and new-style classes +-------------------------------------------- + +- New-style classes are now always dynamic (except for built-in and + extension types). There is no longer a performance penalty, and I + no longer see another reason to keep this baggage around. One relic + remains: the __dict__ of a new-style class is a read-only proxy; you + must set the class's attribute to modify it. As a consequence, the + __defined__ attribute of new-style types no longer exists, for lack + of need: there is once again only one __dict__ (although in the + future a __cache__ may be resurrected with a similar function, if I + can prove that it actually speeds things up). + +- C.__doc__ now works as expected for new-style classes (in 2.2a4 it + always returned None, even when there was a class docstring). + +- doctest now finds and runs docstrings attached to new-style classes, + class methods, static methods, and properties. + +Core and builtins +----------------- + +- A very subtle syntactical pitfall in list comprehensions was fixed. + For example: [a+b for a in 'abc', for b in 'def']. The comma in + this example is a mistake. Previously, this would silently let 'a' + iterate over the singleton tuple ('abc',), yielding ['abcd', 'abce', + 'abcf'] rather than the intended ['ad', 'ae', 'af', 'bd', 'be', + 'bf', 'cd', 'ce', 'cf']. Now, this is flagged as a syntax error. + Note that [a for a in <singleton>] is a convoluted way to say + [<singleton>] anyway, so it's not like any expressiveness is lost. + +- getattr(obj, name, default) now only catches AttributeError, as + documented, rather than returning the default value for all + exceptions (which could mask bugs in a __getattr__ hook, for + example). + +- Weak reference objects are now part of the core and offer a C API. + A bug which could allow a core dump when binary operations involved + proxy reference has been fixed. weakref.ReferenceError is now a + built-in exception. + +- unicode(obj) now behaves more like str(obj), accepting arbitrary + objects, and calling a __unicode__ method if it exists. + unicode(obj, encoding) and unicode(obj, encoding, errors) still + require an 8-bit string or character buffer argument. + +- isinstance() now allows any object as the first argument and a + class, a type or something with a __bases__ tuple attribute for the + second argument. The second argument may also be a tuple of a + class, type, or something with __bases__, in which case isinstance() + will return true if the first argument is an instance of any of the + things contained in the second argument tuple. E.g. + + isinstance(x, (A, B)) + + returns true if x is an instance of A or B. + +Extension modules +----------------- + +- thread.start_new_thread() now returns the thread ID (previously None). + +- binascii has now two quopri support functions, a2b_qp and b2a_qp. + +- readline now supports setting the startup_hook and the + pre_event_hook, and adds the add_history() function. + +- os and posix supports chroot(), setgroups() and unsetenv() where + available. The stat(), fstat(), statvfs() and fstatvfs() functions + now return "pseudo-sequences" -- the various fields can now be + accessed as attributes (e.g. os.stat("/").st_mtime) but for + backwards compatibility they also behave as a fixed-length sequence. + Some platform-specific fields (e.g. st_rdev) are only accessible as + attributes. + +- time: localtime(), gmtime() and strptime() now return a + pseudo-sequence similar to the os.stat() return value, with + attributes like tm_year etc. + +- Decompression objects in the zlib module now accept an optional + second parameter to decompress() that specifies the maximum amount + of memory to use for the uncompressed data. + +- optional SSL support in the socket module now exports OpenSSL + functions RAND_add(), RAND_egd(), and RAND_status(). These calls + are useful on platforms like Solaris where OpenSSL does not + automatically seed its PRNG. Also, the keyfile and certfile + arguments to socket.ssl() are now optional. + +- posixmodule (and by extension, the os module on POSIX platforms) now + exports O_LARGEFILE, O_DIRECT, O_DIRECTORY, and O_NOFOLLOW. + +Library +------- + +- doctest now excludes functions and classes not defined by the module + being tested, thanks to Tim Hochberg. + +- HotShot, a new profiler implemented using a C-based callback, has + been added. This substantially reduces the overhead of profiling, + but it is still quite preliminary. Support modules and + documentation will be added in upcoming releases (before 2.2 final). + +- profile now produces correct output in situations where an exception + raised in Python is cleared by C code (e.g. hasattr()). This used + to cause wrong output, including spurious claims of recursive + functions and attribution of time spent to the wrong function. + + The code and documentation for the derived OldProfile and HotProfile + profiling classes was removed. The code hasn't worked for years (if + you tried to use them, they raised exceptions). OldProfile + intended to reproduce the behavior of the profiler Python used more + than 7 years ago, and isn't interesting anymore. HotProfile intended + to provide a faster profiler (but producing less information), and + that's a worthy goal we intend to meet via a different approach (but + without losing information). + +- Profile.calibrate() has a new implementation that should deliver + a much better system-specific calibration constant. The constant can + now be specified in an instance constructor, or as a Profile class or + instance variable, instead of by editing profile.py's source code. + Calibration must still be done manually (see the docs for the profile + module). + + Note that Profile.calibrate() must be overridden by subclasses. + Improving the accuracy required exploiting detailed knowledge of + profiler internals; the earlier method abstracted away the details + and measured a simplified model instead, but consequently computed + a constant too small by a factor of 2 on some modern machines. + +- quopri's encode and decode methods take an optional header parameter, + which indicates whether output is intended for the header 'Q' + encoding. + +- The SocketServer.ThreadingMixIn class now closes the request after + finish_request() returns. (Not when it errors out though.) + +- The nntplib module's NNTP.body() method has grown a 'file' argument + to allow saving the message body to a file. + +- The email package has added a class email.Parser.HeaderParser which + only parses headers and does not recurse into the message's body. + Also, the module/class MIMEAudio has been added for representing + audio data (contributed by Anthony Baxter). + +- ftplib should be able to handle files > 2GB. + +- ConfigParser.getboolean() now also interprets TRUE, FALSE, YES, NO, + ON, and OFF. + +- xml.dom.minidom NodeList objects now support the length attribute + and item() method as required by the DOM specifications. + +Tools/Demos +----------- + +- Demo/dns was removed. It no longer serves any purpose; a package + derived from it is now maintained by Anthony Baxter, see + http://PyDNS.SourceForge.net. + +- The freeze tool has been made more robust, and two new options have + been added: -X and -E. + +Build +----- + +- configure will use CXX in LINKCC if CXX is used to build main() and + the system requires to link a C++ main using the C++ compiler. + +C API +----- + +- The documentation for the tp_compare slot is updated to require that + the return value must be -1, 0, 1; an arbitrary number <0 or >0 is + not correct. This is not yet enforced but will be enforced in + Python 2.3; even later, we may use -2 to indicate errors and +2 for + "NotImplemented". Right now, -1 should be used for an error return. + +- PyLong_AsLongLong() now accepts int (as well as long) arguments. + Consequently, PyArg_ParseTuple's 'L' code also accepts int (as well + as long) arguments. + +- PyThread_start_new_thread() now returns a long int giving the thread + ID, if one can be calculated; it returns -1 for error, 0 if no + thread ID is calculated (this is an incompatible change, but only + the thread module used this API). This code has only really been + tested on Linux and Windows; other platforms please beware (and + report any bugs or strange behavior). + +- PyUnicode_FromEncodedObject() no longer accepts Unicode objects as + input. + +New platforms +------------- + +Tests +----- + +Windows +------- + +- Installer: If you install IDLE, and don't disable file-extension + registration, a new "Edit with IDLE" context (right-click) menu entry + is created for .py and .pyw files. + +- The signal module now supports SIGBREAK on Windows, thanks to Steven + Scott. Note that SIGBREAK is unique to Windows. The default SIGBREAK + action remains to call Win32 ExitProcess(). This can be changed via + signal.signal(). For example:: + + # Make Ctrl+Break raise KeyboardInterrupt, like Python's default Ctrl+C + # (SIGINT) behavior. + import signal + signal.signal(signal.SIGBREAK, signal.default_int_handler) + + try: + while 1: + pass + except KeyboardInterrupt: + # We get here on Ctrl+C or Ctrl+Break now; if we had not changed + # SIGBREAK, only on Ctrl+C (and Ctrl+Break would terminate the + # program without the possibility for any Python-level cleanup). + print "Clean exit" + + +What's New in Python 2.2a4? +=========================== + +*Release date: 28-Sep-2001* + +Type/class unification and new-style classes +-------------------------------------------- + +- pydoc and inspect are now aware of new-style classes; + e.g. help(list) at the interactive prompt now shows proper + documentation for all operations on list objects. + +- Applications using Jim Fulton's ExtensionClass module can now safely + be used with Python 2.2. In particular, Zope 2.4.1 now works with + Python 2.2 (as well as with Python 2.1.1). The Demo/metaclass + examples also work again. It is hoped that Gtk and Boost also work + with 2.2a4 and beyond. (If you can confirm this, please write + webmaster@python.org; if there are still problems, please open a bug + report on SourceForge.) + +- property() now takes 4 keyword arguments: fget, fset, fdel and doc. + These map to read-only attributes 'fget', 'fset', 'fdel', and '__doc__' + in the constructed property object. fget, fset and fdel weren't + discoverable from Python in 2.2a3. __doc__ is new, and allows to + associate a docstring with a property. + +- Comparison overloading is now more completely implemented. For + example, a str subclass instance can properly be compared to a str + instance, and it can properly overload comparison. Ditto for most + other built-in object types. + +- The repr() of new-style classes has changed; instead of <type + 'M.Foo'> a new-style class is now rendered as <class 'M.Foo'>, + *except* for built-in types, which are still rendered as <type + 'Foo'> (to avoid upsetting existing code that might parse or + otherwise rely on repr() of certain type objects). + +- The repr() of new-style objects is now always <Foo object at XXX>; + previously, it was sometimes <Foo instance at XXX>. + +- For new-style classes, what was previously called __getattr__ is now + called __getattribute__. This method, if defined, is called for + *every* attribute access. A new __getattr__ hook more similar to the + one in classic classes is defined which is called only if regular + attribute access raises AttributeError; to catch *all* attribute + access, you can use __getattribute__ (for new-style classes). If + both are defined, __getattribute__ is called first, and if it raises + AttributeError, __getattr__ is called. + +- The __class__ attribute of new-style objects can be assigned to. + The new class must have the same C-level object layout as the old + class. + +- The builtin file type can be subclassed now. In the usual pattern, + "file" is the name of the builtin type, and file() is a new builtin + constructor, with the same signature as the builtin open() function. + file() is now the preferred way to open a file. + +- Previously, __new__ would only see sequential arguments passed to + the type in a constructor call; __init__ would see both sequential + and keyword arguments. This made no sense whatsoever any more, so + now both __new__ and __init__ see all arguments. + +- Previously, hash() applied to an instance of a subclass of str or + unicode always returned 0. This has been repaired. + +- Previously, an operation on an instance of a subclass of an + immutable type (int, long, float, complex, tuple, str, unicode), + where the subtype didn't override the operation (and so the + operation was handled by the builtin type), could return that + instance instead a value of the base type. For example, if s was of + a str subclass type, s[:] returned s as-is. Now it returns a str + with the same value as s. + +- Provisional support for pickling new-style objects has been added. + +Core +---- + +- file.writelines() now accepts any iterable object producing strings. + +- PyUnicode_FromEncodedObject() now works very much like + PyObject_Str(obj) in that it tries to use __str__/tp_str + on the object if the object is not a string or buffer. This + makes unicode() behave like str() when applied to non-string/buffer + objects. + +- PyFile_WriteObject now passes Unicode objects to the file's write + method. As a result, all file-like objects which may be the target + of a print statement must support Unicode objects, i.e. they must + at least convert them into ASCII strings. + +- Thread scheduling on Solaris should be improved; it is no longer + necessary to insert a small sleep at the start of a thread in order + to let other runnable threads be scheduled. + +Library +------- + +- StringIO.StringIO instances and cStringIO.StringIO instances support + read character buffer compatible objects for their .write() methods. + These objects are converted to strings and then handled as such + by the instances. + +- The "email" package has been added. This is basically a port of the + mimelib package <http://sf.net/projects/mimelib> with API changes + and some implementations updated to use iterators and generators. + +- difflib.ndiff() and difflib.Differ.compare() are generators now. This + restores the ability of Tools/scripts/ndiff.py to start producing output + before the entire comparison is complete. + +- StringIO.StringIO instances and cStringIO.StringIO instances support + iteration just like file objects (i.e. their .readline() method is + called for each iteration until it returns an empty string). + +- The codecs module has grown four new helper APIs to access + builtin codecs: getencoder(), getdecoder(), getreader(), + getwriter(). + +- SimpleXMLRPCServer: a new module (based upon SimpleHTMLServer) + simplifies writing XML RPC servers. + +- os.path.realpath(): a new function that returns the absolute pathname + after interpretation of symbolic links. On non-Unix systems, this + is an alias for os.path.abspath(). + +- operator.indexOf() (PySequence_Index() in the C API) now works with any + iterable object. + +- smtplib now supports various authentication and security features of + the SMTP protocol through the new login() and starttls() methods. + +- hmac: a new module implementing keyed hashing for message + authentication. + +- mimetypes now recognizes more extensions and file types. At the + same time, some mappings not sanctioned by IANA were removed. + +- The "compiler" package has been brought up to date to the state of + Python 2.2 bytecode generation. It has also been promoted from a + Tool to a standard library package. (Tools/compiler still exists as + a sample driver.) + +Build +----- + +- Large file support (LFS) is now automatic when the platform supports + it; no more manual configuration tweaks are needed. On Linux, at + least, it's possible to have a system whose C library supports large + files but whose kernel doesn't; in this case, large file support is + still enabled but doesn't do you any good unless you upgrade your + kernel or share your Python executable with another system whose + kernel has large file support. + +- The configure script now supplies plausible defaults in a + cross-compilation environment. This doesn't mean that the supplied + values are always correct, or that cross-compilation now works + flawlessly -- but it's a first step (and it shuts up most of + autoconf's warnings about AC_TRY_RUN). + +- The Unix build is now a bit less chatty, courtesy of the parser + generator. The build is completely silent (except for errors) when + using "make -s", thanks to a -q option to setup.py. + +C API +----- + +- The "structmember" API now supports some new flag bits to deny read + and/or write access to attributes in restricted execution mode. + +New platforms +------------- + +- Compaq's iPAQ handheld, running the "familiar" Linux distribution + (http://familiar.handhelds.org). + +Tests +----- + +- The "classic" standard tests, which work by comparing stdout to + an expected-output file under Lib/test/output/, no longer stop at + the first mismatch. Instead the test is run to completion, and a + variant of ndiff-style comparison is used to report all differences. + This is much easier to understand than the previous style of reporting. + +- The unittest-based standard tests now use regrtest's test_main() + convention, instead of running as a side-effect of merely being + imported. This allows these tests to be run in more natural and + flexible ways as unittests, outside the regrtest framework. + +- regrtest.py is much better integrated with unittest and doctest now, + especially in regard to reporting errors. + +Windows +------- + +- Large file support now also works for files > 4GB, on filesystems + that support it (NTFS under Windows 2000). See "What's New in + Python 2.2a3" for more detail. + + +What's New in Python 2.2a3? +=========================== + +*Release Date: 07-Sep-2001* + +Core +---- + +- Conversion of long to float now raises OverflowError if the long is too + big to represent as a C double. + +- The 3-argument builtin pow() no longer allows a third non-None argument + if either of the first two arguments is a float, or if both are of + integer types and the second argument is negative (in which latter case + the arguments are converted to float, so this is really the same + restriction). + +- The builtin dir() now returns more information, and sometimes much + more, generally naming all attributes of an object, and all attributes + reachable from the object via its class, and from its class's base + classes, and so on from them too. Example: in 2.2a2, dir([]) returned + an empty list. In 2.2a3, + + >>> dir([]) + ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', + '__eq__', '__ge__', '__getattr__', '__getitem__', '__getslice__', + '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__le__', + '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__repr__', + '__rmul__', '__setattr__', '__setitem__', '__setslice__', '__str__', + 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', + 'reverse', 'sort'] + + dir(module) continues to return only the module's attributes, though. + +- Overflowing operations on plain ints now return a long int rather + than raising OverflowError. This is a partial implementation of PEP + 237. You can use -Wdefault::OverflowWarning to enable a warning for + this situation, and -Werror::OverflowWarning to revert to the old + OverflowError exception. + +- A new command line option, -Q<arg>, is added to control run-time + warnings for the use of classic division. (See PEP 238.) Possible + values are -Qold, -Qwarn, -Qwarnall, and -Qnew. The default is + -Qold, meaning the / operator has its classic meaning and no + warnings are issued. Using -Qwarn issues a run-time warning about + all uses of classic division for int and long arguments; -Qwarnall + also warns about classic division for float and complex arguments + (for use with fixdiv.py). + [Note: the remainder of this item (preserved below) became + obsolete in 2.2c1 -- -Qnew has global effect in 2.2] :: + + Using -Qnew is questionable; it turns on new division by default, but + only in the __main__ module. You can usefully combine -Qwarn or + -Qwarnall and -Qnew: this gives the __main__ module new division, and + warns about classic division everywhere else. + +- Many built-in types can now be subclassed. This applies to int, + long, float, str, unicode, and tuple. (The types complex, list and + dictionary can also be subclassed; this was introduced earlier.) + Note that restrictions apply when subclassing immutable built-in + types: you can only affect the value of the instance by overloading + __new__. You can add mutable attributes, and the subclass instances + will have a __dict__ attribute, but you cannot change the "value" + (as implemented by the base class) of an immutable subclass instance + once it is created. + +- The dictionary constructor now takes an optional argument, a + mapping-like object, and initializes the dictionary from its + (key, value) pairs. + +- A new built-in type, super, has been added. This facilitates making + "cooperative super calls" in a multiple inheritance setting. For an + explanation, see http://www.python.org/2.2/descrintro.html#cooperation + +- A new built-in type, property, has been added. This enables the + creation of "properties". These are attributes implemented by + getter and setter functions (or only one of these for read-only or + write-only attributes), without the need to override __getattr__. + See http://www.python.org/2.2/descrintro.html#property + +- The syntax of floating-point and imaginary literals has been + liberalized, to allow leading zeroes. Examples of literals now + legal that were SyntaxErrors before: + + 00.0 0e3 0100j 07.5 00000000000000000008. + +- An old tokenizer bug allowed floating point literals with an incomplete + exponent, such as 1e and 3.1e-. Such literals now raise SyntaxError. + +Library +------- + +- telnetlib includes symbolic names for the options, and support for + setting an option negotiation callback. It also supports processing + of suboptions. + +- The new C standard no longer requires that math libraries set errno to + ERANGE on overflow. For platform libraries that exploit this new + freedom, Python's overflow-checking was wholly broken. A new overflow- + checking scheme attempts to repair that, but may not be reliable on all + platforms (C doesn't seem to provide anything both useful and portable + in this area anymore). + +- Asynchronous timeout actions are available through the new class + threading.Timer. + +- math.log and math.log10 now return sensible results for even huge + long arguments. For example, math.log10(10 ** 10000) ~= 10000.0. + +- A new function, imp.lock_held(), returns 1 when the import lock is + currently held. See the docs for the imp module. + +- pickle, cPickle and marshal on 32-bit platforms can now correctly read + dumps containing ints written on platforms where Python ints are 8 bytes. + When read on a box where Python ints are 4 bytes, such values are + converted to Python longs. + +- In restricted execution mode (using the rexec module), unmarshalling + code objects is no longer allowed. This plugs a security hole. + +- unittest.TestResult instances no longer store references to tracebacks + generated by test failures. This prevents unexpected dangling references + to objects that should be garbage collected between tests. + +Tools +----- + +- Tools/scripts/fixdiv.py has been added which can be used to fix + division operators as per PEP 238. + +Build +----- + +- If you are an adventurous person using Mac OS X you may want to look at + Mac/OSX. There is a Makefile there that will build Python as a real Mac + application, which can be used for experimenting with Carbon or Cocoa. + Discussion of this on pythonmac-sig, please. + +C API +----- + +- New function PyObject_Dir(obj), like Python __builtin__.dir(obj). + +- Note that PyLong_AsDouble can fail! This has always been true, but no + callers checked for it. It's more likely to fail now, because overflow + errors are properly detected now. The proper way to check:: + + double x = PyLong_AsDouble(some_long_object); + if (x == -1.0 && PyErr_Occurred()) { + /* The conversion failed. */ + } + +- The GC API has been changed. Extensions that use the old API will still + compile but will not participate in GC. To upgrade an extension + module: + + - rename Py_TPFLAGS_GC to PyTPFLAGS_HAVE_GC + + - use PyObject_GC_New or PyObject_GC_NewVar to allocate objects and + PyObject_GC_Del to deallocate them + + - rename PyObject_GC_Init to PyObject_GC_Track and PyObject_GC_Fini + to PyObject_GC_UnTrack + + - remove PyGC_HEAD_SIZE from object size calculations + + - remove calls to PyObject_AS_GC and PyObject_FROM_GC + +- Two new functions: PyString_FromFormat() and PyString_FromFormatV(). + These can be used safely to construct string objects from a + sprintf-style format string (similar to the format string supported + by PyErr_Format()). + +New platforms +------------- + +- Stephen Hansen contributed patches sufficient to get a clean compile + under Borland C (Windows), but he reports problems running it and ran + out of time to complete the port. Volunteers? Expect a MemoryError + when importing the types module; this is probably shallow, and + causing later failures too. + +Tests +----- + +Windows +------- + +- Large file support is now enabled on Win32 platforms as well as on + Win64. This means that, for example, you can use f.tell() and f.seek() + to manipulate files larger than 2 gigabytes (provided you have enough + disk space, and are using a Windows filesystem that supports large + partitions). Windows filesystem limits: FAT has a 2GB (gigabyte) + filesize limit, and large file support makes no difference there. + FAT32's limit is 4GB, and files >= 2GB are easier to use from Python now. + NTFS has no practical limit on file size, and files of any size can be + used from Python now. + +- The w9xpopen hack is now used on Windows NT and 2000 too when COMPSPEC + points to command.com (patch from Brian Quinlan). + + +What's New in Python 2.2a2? +=========================== + +*Release Date: 22-Aug-2001* + +Build +----- + +- Tim Peters developed a brand new Windows installer using Wise 8.1, + generously donated to us by Wise Solutions. + +- configure supports a new option --enable-unicode, with the values + ucs2 and ucs4 (new in 2.2a1). With --disable-unicode, the Unicode + type and supporting code is completely removed from the interpreter. + +- A new configure option --enable-framework builds a Mac OS X framework, + which "make frameworkinstall" will install. This provides a starting + point for more mac-like functionality, join pythonmac-sig@python.org + if you are interested in helping. + +- The NeXT platform is no longer supported. + +- The 'new' module is now statically linked. + +Tools +----- + +- The new Tools/scripts/cleanfuture.py can be used to automatically + edit out obsolete future statements from Python source code. See + the module docstring for details. + +Tests +----- + +- regrtest.py now knows which tests are expected to be skipped on some + platforms, allowing to give clearer test result output. regrtest + also has optional --use/-u switch to run normally disabled tests + which require network access or consume significant disk resources. + +- Several new tests in the standard test suite, with special thanks to + Nick Mathewson. + +Core +---- + +- The floor division operator // has been added as outlined in PEP + 238. The / operator still provides classic division (and will until + Python 3.0) unless "from __future__ import division" is included, in + which case the / operator will provide true division. The operator + module provides truediv() and floordiv() functions. Augmented + assignment variants are included, as are the equivalent overloadable + methods and C API methods. See the PEP for a full discussion: + <http://python.sf.net/peps/pep-0238.html> + +- Future statements are now effective in simulated interactive shells + (like IDLE). This should "just work" by magic, but read Michael + Hudson's "Future statements in simulated shells" PEP 264 for full + details: <http://python.sf.net/peps/pep-0264.html>. + +- The type/class unification (PEP 252-253) was integrated into the + trunk and is not so tentative any more (the exact specification of + some features is still tentative). A lot of work has done on fixing + bugs and adding robustness and features (performance still has to + come a long way). + +- Warnings about a mismatch in the Python API during extension import + now use the Python warning framework (which makes it possible to + write filters for these warnings). + +- A function's __dict__ (aka func_dict) will now always be a + dictionary. It used to be possible to delete it or set it to None, + but now both actions raise TypeErrors. It is still legal to set it + to a dictionary object. Getting func.__dict__ before any attributes + have been assigned now returns an empty dictionary instead of None. + +- A new command line option, -E, was added which disables the use of + all environment variables, or at least those that are specifically + significant to Python. Usually those have a name starting with + "PYTHON". This was used to fix a problem where the tests fail if + the user happens to have PYTHONHOME or PYTHONPATH pointing to an + older distribution. + +Library +------- + +- New class Differ and new functions ndiff() and restore() in difflib.py. + These package the algorithms used by the popular Tools/scripts/ndiff.py, + for programmatic reuse. + +- New function xml.sax.saxutils.quoteattr(): Quote an XML attribute + value using the minimal quoting required for the value; more + reliable than using xml.sax.saxutils.escape() for attribute values. + +- Readline completion support for cmd.Cmd was added. + +- Calling os.tempnam() or os.tmpnam() generate RuntimeWarnings. + +- Added function threading.BoundedSemaphore() + +- Added Ka-Ping Yee's cgitb.py module. + +- The 'new' module now exposes the CO_xxx flags. + +- The gc module offers the get_referents function. + +New platforms +------------- + +C API +----- + +- Two new APIs PyOS_snprintf() and PyOS_vsnprintf() were added + which provide a cross-platform implementations for the + relatively new snprintf()/vsnprintf() C lib APIs. In contrast to + the standard sprintf() and vsprintf() C lib APIs, these versions + apply bounds checking on the used buffer which enhances protection + against buffer overruns. + +- Unicode APIs now use name mangling to assure that mixing interpreters + and extensions using different Unicode widths is rendered next to + impossible. Trying to import an incompatible Unicode-aware extension + will result in an ImportError. Unicode extensions writers must make + sure to check the Unicode width compatibility in their extensions by + using at least one of the mangled Unicode APIs in the extension. + +- Two new flags METH_NOARGS and METH_O are available in method definition + tables to simplify implementation of methods with no arguments and a + single untyped argument. Calling such methods is more efficient than + calling corresponding METH_VARARGS methods. METH_OLDARGS is now + deprecated. + +Windows +------- + +- "import module" now compiles module.pyw if it exists and nothing else + relevant is found. + + +What's New in Python 2.2a1? +=========================== + +*Release date: 18-Jul-2001* + +Core +---- + +- TENTATIVELY, a large amount of code implementing much of what's + described in PEP 252 (Making Types Look More Like Classes) and PEP + 253 (Subtyping Built-in Types) was added. This will be released + with Python 2.2a1. Documentation will be provided separately + through http://www.python.org/2.2/. The purpose of releasing this + with Python 2.2a1 is to test backwards compatibility. It is + possible, though not likely, that a decision is made not to release + this code as part of 2.2 final, if any serious backwards + incompatibilities are found during alpha testing that cannot be + repaired. + +- Generators were added; this is a new way to create an iterator (see + below) using what looks like a simple function containing one or + more 'yield' statements. See PEP 255. Since this adds a new + keyword to the language, this feature must be enabled by including a + future statement: "from __future__ import generators" (see PEP 236). + Generators will become a standard feature in a future release + (probably 2.3). Without this future statement, 'yield' remains an + ordinary identifier, but a warning is issued each time it is used. + (These warnings currently don't conform to the warnings framework of + PEP 230; we intend to fix this in 2.2a2.) + +- The UTF-16 codec was modified to be more RFC compliant. It will now + only remove BOM characters at the start of the string and then + only if running in native mode (UTF-16-LE and -BE won't remove a + leading BMO character). + +- Strings now have a new method .decode() to complement the already + existing .encode() method. These two methods provide direct access + to the corresponding decoders and encoders of the registered codecs. + + To enhance the usability of the .encode() method, the special + casing of Unicode object return values was dropped (Unicode objects + were auto-magically converted to string using the default encoding). + + Both methods will now return whatever the codec in charge of the + requested encoding returns as object, e.g. Unicode codecs will + return Unicode objects when decoding is requested ("äöü".decode("latin-1") + will return u"äöü"). This enables codec writer to create codecs + for various simple to use conversions. + + New codecs were added to demonstrate these new features (the .encode() + and .decode() columns indicate the type of the returned objects): + + +---------+-----------+-----------+-----------------------------+ + |Name | .encode() | .decode() | Description | + +=========+===========+===========+=============================+ + |uu | string | string | UU codec (e.g. for email) | + +---------+-----------+-----------+-----------------------------+ + |base64 | string | string | base64 codec | + +---------+-----------+-----------+-----------------------------+ + |quopri | string | string | quoted-printable codec | + +---------+-----------+-----------+-----------------------------+ + |zlib | string | string | zlib compression | + +---------+-----------+-----------+-----------------------------+ + |hex | string | string | 2-byte hex codec | + +---------+-----------+-----------+-----------------------------+ + |rot-13 | string | Unicode | ROT-13 Unicode charmap codec| + +---------+-----------+-----------+-----------------------------+ + +- Some operating systems now support the concept of a default Unicode + encoding for file system operations. Notably, Windows supports 'mbcs' + as the default. The Macintosh will also adopt this concept in the medium + term, although the default encoding for that platform will be other than + 'mbcs'. + + On operating system that support non-ASCII filenames, it is common for + functions that return filenames (such as os.listdir()) to return Python + string objects pre-encoded using the default file system encoding for + the platform. As this encoding is likely to be different from Python's + default encoding, converting this name to a Unicode object before passing + it back to the Operating System would result in a Unicode error, as Python + would attempt to use its default encoding (generally ASCII) rather than + the default encoding for the file system. + + In general, this change simply removes surprises when working with + Unicode and the file system, making these operations work as you expect, + increasing the transparency of Unicode objects in this context. + See [????] for more details, including examples. + +- Float (and complex) literals in source code were evaluated to full + precision only when running from a .py file; the same code loaded from a + .pyc (or .pyo) file could suffer numeric differences starting at about the + 12th significant decimal digit. For example, on a machine with IEEE-754 + floating arithmetic, + + x = 9007199254740992.0 + print long(x) + + printed 9007199254740992 if run directly from .py, but 9007199254740000 + if from a compiled (.pyc or .pyo) file. This was due to marshal using + str(float) instead of repr(float) when building code objects. marshal + now uses repr(float) instead, which should reproduce floats to full + machine precision (assuming the platform C float<->string I/O conversion + functions are of good quality). + + This may cause floating-point results to change in some cases, and + usually for the better, but may also cause numerically unstable + algorithms to break. + +- The implementation of dicts suffers fewer collisions, which has speed + benefits. However, the order in which dict entries appear in dict.keys(), + dict.values() and dict.items() may differ from previous releases for a + given dict. Nothing is defined about this order, so no program should + rely on it. Nevertheless, it's easy to write test cases that rely on the + order by accident, typically because of printing the str() or repr() of a + dict to an "expected results" file. See Lib/test/test_support.py's new + sortdict(dict) function for a simple way to display a dict in sorted + order. + +- Many other small changes to dicts were made, resulting in faster + operation along the most common code paths. + +- Dictionary objects now support the "in" operator: "x in dict" means + the same as dict.has_key(x). + +- The update() method of dictionaries now accepts generic mapping + objects. Specifically the argument object must support the .keys() + and __getitem__() methods. This allows you to say, for example, + {}.update(UserDict()) + +- Iterators were added; this is a generalized way of providing values + to a for loop. See PEP 234. There's a new built-in function iter() + to return an iterator. There's a new protocol to get the next value + from an iterator using the next() method (in Python) or the + tp_iternext slot (in C). There's a new protocol to get iterators + using the __iter__() method (in Python) or the tp_iter slot (in C). + Iterating (i.e. a for loop) over a dictionary generates its keys. + Iterating over a file generates its lines. + +- The following functions were generalized to work nicely with iterator + arguments:: + + map(), filter(), reduce(), zip() + list(), tuple() (PySequence_Tuple() and PySequence_Fast() in C API) + max(), min() + join() method of strings + extend() method of lists + 'x in y' and 'x not in y' (PySequence_Contains() in C API) + operator.countOf() (PySequence_Count() in C API) + right-hand side of assignment statements with multiple targets, such as :: + x, y, z = some_iterable_object_returning_exactly_3_values + +- Accessing module attributes is significantly faster (for example, + random.random or os.path or yourPythonModule.yourAttribute). + +- Comparing dictionary objects via == and != is faster, and now works even + if the keys and values don't support comparisons other than ==. + +- Comparing dictionaries in ways other than == and != is slower: there were + insecurities in the dict comparison implementation that could cause Python + to crash if the element comparison routines for the dict keys and/or + values mutated the dicts. Making the code bulletproof slowed it down. + +- Collisions in dicts are resolved via a new approach, which can help + dramatically in bad cases. For example, looking up every key in a dict + d with d.keys() == [i << 16 for i in range(20000)] is approximately 500x + faster now. Thanks to Christian Tismer for pointing out the cause and + the nature of an effective cure (last December! better late than never). + +- repr() is much faster for large containers (dict, list, tuple). + + +Library +------- + +- The constants ascii_letters, ascii_lowercase. and ascii_uppercase + were added to the string module. These a locale-independent + constants, unlike letters, lowercase, and uppercase. These are now + use in appropriate locations in the standard library. + +- The flags used in dlopen calls can now be configured using + sys.setdlopenflags and queried using sys.getdlopenflags. + +- Fredrik Lundh's xmlrpclib is now a standard library module. This + provides full client-side XML-RPC support. In addition, + Demo/xmlrpc/ contains two server frameworks (one SocketServer-based, + one asyncore-based). Thanks to Eric Raymond for the documentation. + +- The xrange() object is simplified: it no longer supports slicing, + repetition, comparisons, efficient 'in' checking, the tolist() + method, or the start, stop and step attributes. See PEP 260. + +- A new function fnmatch.filter to filter lists of file names was added. + +- calendar.py uses month and day names based on the current locale. + +- strop is now *really* obsolete (this was announced before with 1.6), + and issues DeprecationWarning when used (except for the four items + that are still imported into string.py). + +- Cookie.py now sorts key+value pairs by key in output strings. + +- pprint.isrecursive(object) didn't correctly identify recursive objects. + Now it does. + +- pprint functions now much faster for large containers (tuple, list, dict). + +- New 'q' and 'Q' format codes in the struct module, corresponding to C + types "long long" and "unsigned long long" (on Windows, __int64). In + native mode, these can be used only when the platform C compiler supports + these types (when HAVE_LONG_LONG is #define'd by the Python config + process), and then they inherit the sizes and alignments of the C types. + In standard mode, 'q' and 'Q' are supported on all platforms, and are + 8-byte integral types. + +- The site module installs a new built-in function 'help' that invokes + pydoc.help. It must be invoked as 'help()'; when invoked as 'help', + it displays a message reminding the user to use 'help()' or + 'help(object)'. + +Tests +----- + +- New test_mutants.py runs dict comparisons where the key and value + comparison operators mutate the dicts randomly during comparison. This + rapidly causes Python to crash under earlier releases (not for the faint + of heart: it can also cause Win9x to freeze or reboot!). + +- New test_pprint.py verifies that pprint.isrecursive() and + pprint.isreadable() return sensible results. Also verifies that simple + cases produce correct output. + +C API +----- + +- Removed the unused last_is_sticky argument from the internal + _PyTuple_Resize(). If this affects you, you were cheating. + +What's New in Python 2.1 (final)? +================================= + +We only changed a few things since the last release candidate, all in +Python library code: + +- A bug in the locale module was fixed that affected locales which + define no grouping for numeric formatting. + +- A few bugs in the weakref module's implementations of weak + dictionaries (WeakValueDictionary and WeakKeyDictionary) were fixed, + and the test suite was updated to check for these bugs. + +- An old bug in the os.path.walk() function (introduced in Python + 2.0!) was fixed: a non-existent file would cause an exception + instead of being ignored. + +- Fixed a few bugs in the new symtable module found by Neil Norwitz's + PyChecker. + + +What's New in Python 2.1c2? +=========================== + +A flurry of small changes, and one showstopper fixed in the nick of +time made it necessary to release another release candidate. The list +here is the *complete* list of patches (except version updates): + +Core + +- Tim discovered a nasty bug in the dictionary code, caused by + PyDict_Next() calling dict_resize(), and the GC code's use of + PyDict_Next() violating an assumption in dict_items(). This was + fixed with considerable amounts of band-aid, but the net effect is a + saner and more robust implementation. + +- Made a bunch of symbols static that were accidentally global. + +Build and Ports + +- The setup.py script didn't check for a new enough version of zlib + (1.1.3 is needed). Now it does. + +- Changed "make clean" target to also remove shared libraries. + +- Added a more general warning about the SGI Irix optimizer to README. + +Library + +- Fix a bug in urllib.basejoin("http://host", "../file.html") which + omitted the slash between host and file.html. + +- The mailbox module's _Mailbox class contained a completely broken + and undocumented seek() method. Ripped it out. + +- Fixed a bunch of typos in various library modules (urllib2, smtpd, + sgmllib, netrc, chunk) found by Neil Norwitz's PyChecker. + +- Fixed a few last-minute bugs in unittest. + +Extensions + +- Reverted the patch to the OpenSSL code in socketmodule.c to support + RAND_status() and the EGD, and the subsequent patch that tried to + fix it for pre-0.9.5 versions; the problem with the patch is that on + some systems it issues a warning whenever socket is imported, and + that's unacceptable. + +Tests + +- Fixed the pickle tests to work with "import test.test_pickle". + +- Tweaked test_locale.py to actually run the test Windows. + +- In distutils/archive_util.py, call zipfile.ZipFile() with mode "w", + not "wb" (which is not a valid mode at all). + +- Fix pstats browser crashes. Import readline if it exists to make + the user interface nicer. + +- Add "import thread" to the top of test modules that import the + threading module (test_asynchat and test_threadedtempfile). This + prevents test failures caused by a broken threading module resulting + from a previously caught failed import. + +- Changed test_asynchat.py to set the SO_REUSEADDR option; this was + needed on some platforms (e.g. Solaris 8) when the tests are run + twice in succession. + +- Skip rather than fail test_sunaudiodev if no audio device is found. + + +What's New in Python 2.1c1? +=========================== + +This list was significantly updated when 2.1c2 was released; the 2.1c1 +release didn't mention most changes that were actually part of 2.1c1: + +Legal + +- Copyright was assigned to the Python Software Foundation (PSF) and a + PSF license (very similar to the CNRI license) was added. + +- The CNRI copyright notice was updated to include 2001. + +Core + +- After a public outcry, assignment to __debug__ is no longer illegal; + instead, a warning is issued. It will become illegal in 2.2. + +- Fixed a core dump with "%#x" % 0, and changed the semantics so that + "%#x" now always prepends "0x", even if the value is zero. + +- Fixed some nits in the bytecode compiler. + +- Fixed core dumps when calling certain kinds of non-functions. + +- Fixed various core dumps caused by reference count bugs. + +Build and Ports + +- Use INSTALL_SCRIPT to install script files. + +- New port: SCO Unixware 7, by Billy G. Allie. + +- Updated RISCOS port. + +- Updated BeOS port and notes. + +- Various other porting problems resolved. + +Library + +- The TERMIOS and SOCKET modules are now truly obsolete and + unnecessary. Their symbols are incorporated in the termios and + socket modules. + +- Fixed some 64-bit bugs in pickle, cPickle, and struct, and added + better tests for pickling. + +- threading: make Condition.wait() robust against KeyboardInterrupt. + +- zipfile: add support to zipfile to support opening an archive + represented by an open file rather than a file name. Fix bug where + the archive was not properly closed. Fixed a bug in this bugfix + where flush() was called for a read-only file. + +- imputil: added an uninstall() method to the ImportManager. + +- Canvas: fixed bugs in lower() and tkraise() methods. + +- SocketServer: API change (added overridable close_request() method) + so that the TCP server can explicitly close the request. + +- pstats: Eric Raymond added a simple interactive statistics browser, + invoked when the module is run as a script. + +- locale: fixed a problem in format(). + +- webbrowser: made it work when the BROWSER environment variable has a + value like "/usr/bin/netscape". Made it auto-detect Konqueror for + KDE 2. Fixed some other nits. + +- unittest: changes to allow using a different exception than + AssertionError, and added a few more function aliases. Some other + small changes. + +- urllib, urllib2: fixed redirect problems and a coupleof other nits. + +- asynchat: fixed a critical bug in asynchat that slipped through the + 2.1b2 release. Fixed another rare bug. + +- Fix some unqualified except: clauses (always a bad code example). + +XML + +- pyexpat: new API get_version_string(). + +- Fixed some minidom bugs. + +Extensions + +- Fixed a core dump in _weakref. Removed the weakref.mapping() + function (it adds nothing to the API). + +- Rationalized the use of header files in the readline module, to make + it compile (albeit with some warnings) with the very recent readline + 4.2, without breaking for earlier versions. + +- Hopefully fixed a buffering problem in linuxaudiodev. + +- Attempted a fix to make the OpenSSL support in the socket module + work again with pre-0.9.5 versions of OpenSSL. + +Tests + +- Added a test case for asynchat and asyncore. + +- Removed coupling between tests where one test failing could break + another. + +Tools + +- Ping added an interactive help browser to pydoc, fixed some nits + in the rest of the pydoc code, and added some features to his + inspect module. + +- An updated python-mode.el version 4.1 which integrates Ken + Manheimer's pdbtrack.el. This makes debugging Python code via pdb + much nicer in XEmacs and Emacs. When stepping through your program + with pdb, in either the shell window or the *Python* window, the + source file and line will be tracked by an arrow. Very cool! + +- IDLE: syntax warnings in interactive mode are changed into errors. + +- Some improvements to Tools/webchecker (ignore some more URL types, + follow some more links). + +- Brought the Tools/compiler package up to date. + + +What's New in Python 2.1 beta 2? +================================ + +(Unlisted are many fixed bugs, more documentation, etc.) + +Core language, builtins, and interpreter + +- The nested scopes work (enabled by "from __future__ import + nested_scopes") is completed; in particular, the future now extends + into code executed through exec, eval() and execfile(), and into the + interactive interpreter. + +- When calling a base class method (e.g. BaseClass.__init__(self)), + this is now allowed even if self is not strictly spoken a class + instance (e.g. when using metaclasses or the Don Beaudry hook). + +- Slice objects are now comparable but not hashable; this prevents + dict[:] from being accepted but meaningless. + +- Complex division is now calculated using less braindead algorithms. + This doesn't change semantics except it's more likely to give useful + results in extreme cases. Complex repr() now uses full precision + like float repr(). + +- sgmllib.py now calls handle_decl() for simple <!...> declarations. + +- It is illegal to assign to the name __debug__, which is set when the + interpreter starts. It is effectively a compile-time constant. + +- A warning will be issued if a global statement for a variable + follows a use or assignment of that variable. + +Standard library + +- unittest.py, a unit testing framework by Steve Purcell (PyUNIT, + inspired by JUnit), is now part of the standard library. You now + have a choice of two testing frameworks: unittest requires you to + write testcases as separate code, doctest gathers them from + docstrings. Both approaches have their advantages and + disadvantages. + +- A new module Tix was added, which wraps the Tix extension library + for Tk. With that module, it is not necessary to statically link + Tix with _tkinter, since Tix will be loaded with Tcl's "package + require" command. See Demo/tix/. + +- tzparse.py is now obsolete. + +- In gzip.py, the seek() and tell() methods are removed -- they were + non-functional anyway, and it's better if callers can test for their + existence with hasattr(). + +Python/C API + +- PyDict_Next(): it is now safe to call PyDict_SetItem() with a key + that's already in the dictionary during a PyDict_Next() iteration. + This used to fail occasionally when a dictionary resize operation + could be triggered that would rehash all the keys. All other + modifications to the dictionary are still off-limits during a + PyDict_Next() iteration! + +- New extended APIs related to passing compiler variables around. + +- New abstract APIs PyObject_IsInstance(), PyObject_IsSubclass() + implement isinstance() and issubclass(). + +- Py_BuildValue() now has a "D" conversion to create a Python complex + number from a Py_complex C value. + +- Extensions types which support weak references must now set the + field allocated for the weak reference machinery to NULL themselves; + this is done to avoid the cost of checking each object for having a + weakly referencable type in PyObject_INIT(), since most types are + not weakly referencable. + +- PyFrame_FastToLocals() and PyFrame_LocalsToFast() copy bindings for + free variables and cell variables to and from the frame's f_locals. + +- Variants of several functions defined in pythonrun.h have been added + to support the nested_scopes future statement. The variants all end + in Flags and take an extra argument, a PyCompilerFlags *; examples: + PyRun_AnyFileExFlags(), PyRun_InteractiveLoopFlags(). These + variants may be removed in Python 2.2, when nested scopes are + mandatory. + +Distutils + +- the sdist command now writes a PKG-INFO file, as described in PEP 241, + into the release tree. + +- several enhancements to the bdist_wininst command from Thomas Heller + (an uninstaller, more customization of the installer's display) + +- from Jack Jansen: added Mac-specific code to generate a dialog for + users to specify the command-line (because providing a command-line with + MacPython is awkward). Jack also made various fixes for the Mac + and the Metrowerks compiler. + +- added 'platforms' and 'keywords' to the set of metadata that can be + specified for a distribution. + +- applied patches from Jason Tishler to make the compiler class work with + Cygwin. + + +What's New in Python 2.1 beta 1? +================================ + +Core language, builtins, and interpreter + +- Following an outcry from the community about the amount of code + broken by the nested scopes feature introduced in 2.1a2, we decided + to make this feature optional, and to wait until Python 2.2 (or at + least 6 months) to make it standard. The option can be enabled on a + per-module basis by adding "from __future__ import nested_scopes" at + the beginning of a module (before any other statements, but after + comments and an optional docstring). See PEP 236 (Back to the + __future__) for a description of the __future__ statement. PEP 227 + (Statically Nested Scopes) has been updated to reflect this change, + and to clarify the semantics in a number of endcases. + +- The nested scopes code, when enabled, has been hardened, and most + bugs and memory leaks in it have been fixed. + +- Compile-time warnings are now generated for a number of conditions + that will break or change in meaning when nested scopes are enabled: + + - Using "from...import *" or "exec" without in-clause in a function + scope that also defines a lambda or nested function with one or + more free (non-local) variables. The presence of the import* or + bare exec makes it impossible for the compiler to determine the + exact set of local variables in the outer scope, which makes it + impossible to determine the bindings for free variables in the + inner scope. To avoid the warning about import *, change it into + an import of explicitly name object, or move the import* statement + to the global scope; to avoid the warning about bare exec, use + exec...in... (a good idea anyway -- there's a possibility that + bare exec will be deprecated in the future). + + - Use of a global variable in a nested scope with the same name as a + local variable in a surrounding scope. This will change in + meaning with nested scopes: the name in the inner scope will + reference the variable in the outer scope rather than the global + of the same name. To avoid the warning, either rename the outer + variable, or use a global statement in the inner function. + +- An optional object allocator has been included. This allocator is + optimized for Python objects and should be faster and use less memory + than the standard system allocator. It is not enabled by default + because of possible thread safety problems. The allocator is only + protected by the Python interpreter lock and it is possible that some + extension modules require a thread safe allocator. The object + allocator can be enabled by providing the "--with-pymalloc" option to + configure. + +Standard library + +- pyexpat now detects the expat version if expat.h defines it. A + number of additional handlers are provided, which are only available + since expat 1.95. In addition, the methods SetParamEntityParsing and + GetInputContext of Parser objects are available with 1.95.x + only. Parser objects now provide the ordered_attributes and + specified_attributes attributes. A new module expat.model was added, + which offers a number of additional constants if 1.95.x is used. + +- xml.dom offers the new functions registerDOMImplementation and + getDOMImplementation. + +- xml.dom.minidom offers a toprettyxml method. A number of DOM + conformance issues have been resolved. In particular, Element now + has an hasAttributes method, and the handling of namespaces was + improved. + +- Ka-Ping Yee contributed two new modules: inspect.py, a module for + getting information about live Python code, and pydoc.py, a module + for interactively converting docstrings to HTML or text. + Tools/scripts/pydoc, which is now automatically installed into + <prefix>/bin, uses pydoc.py to display documentation; try running + "pydoc -h" for instructions. "pydoc -g" pops up a small GUI that + lets you browse the module docstrings using a web browser. + +- New library module difflib.py, primarily packaging the SequenceMatcher + class at the heart of the popular ndiff.py file-comparison tool. + +- doctest.py (a framework for verifying Python code examples in docstrings) + is now part of the std library. + +Windows changes + +- A new entry in the Start menu, "Module Docs", runs "pydoc -g" -- a + small GUI that lets you browse the module docstrings using your + default web browser. + +- Import is now case-sensitive. PEP 235 (Import on Case-Insensitive + Platforms) is implemented. See + + http://python.sourceforge.net/peps/pep-0235.html + + for full details, especially the "Current Lower-Left Semantics" section. + The new Windows import rules are simpler than before: + + A. If the PYTHONCASEOK environment variable exists, same as + before: silently accept the first case-insensitive match of any + kind; raise ImportError if none found. + + B. Else search sys.path for the first case-sensitive match; raise + ImportError if none found. + + The same rules have been implemented on other platforms with case- + insensitive but case-preserving filesystems too (including Cygwin, and + several flavors of Macintosh operating systems). + +- winsound module: Under Win9x, winsound.Beep() now attempts to simulate + what it's supposed to do (and does do under NT and 2000) via direct + port manipulation. It's unknown whether this will work on all systems, + but it does work on my Win98SE systems now and was known to be useless on + all Win9x systems before. + +- Build: Subproject _test (effectively) renamed to _testcapi. + +New platforms + +- 2.1 should compile and run out of the box under MacOS X, even using HFS+. + Thanks to Steven Majewski! + +- 2.1 should compile and run out of the box on Cygwin. Thanks to Jason + Tishler! + +- 2.1 contains new files and patches for RISCOS, thanks to Dietmar + Schwertberger! See RISCOS/README for more information -- it seems + that because of the bizarre filename conventions on RISCOS, no port + to that platform is easy. + + +What's New in Python 2.1 alpha 2? +================================= + +Core language, builtins, and interpreter + +- Scopes nest. If a name is used in a function or class, but is not + local, the definition in the nearest enclosing function scope will + be used. One consequence of this change is that lambda statements + could reference variables in the namespaces where the lambda is + defined. In some unusual cases, this change will break code. + + In all previous version of Python, names were resolved in exactly + three namespaces -- the local namespace, the global namespace, and + the builtin namespace. According to this old definition, if a + function A is defined within a function B, the names bound in B are + not visible in A. The new rules make names bound in B visible in A, + unless A contains a name binding that hides the binding in B. + + Section 4.1 of the reference manual describes the new scoping rules + in detail. The test script in Lib/test/test_scope.py demonstrates + some of the effects of the change. + + The new rules will cause existing code to break if it defines nested + functions where an outer function has local variables with the same + name as globals or builtins used by the inner function. Example: + + def munge(str): + def helper(x): + return str(x) + if type(str) != type(''): + str = helper(str) + return str.strip() + + Under the old rules, the name str in helper() is bound to the + builtin function str(). Under the new rules, it will be bound to + the argument named str and an error will occur when helper() is + called. + +- The compiler will report a SyntaxError if "from ... import *" occurs + in a function or class scope. The language reference has documented + that this case is illegal, but the compiler never checked for it. + The recent introduction of nested scope makes the meaning of this + form of name binding ambiguous. In a future release, the compiler + may allow this form when there is no possibility of ambiguity. + +- repr(string) is easier to read, now using hex escapes instead of octal, + and using \t, \n and \r instead of \011, \012 and \015 (respectively): + + >>> "\texample \r\n" + chr(0) + chr(255) + '\texample \r\n\x00\xff' # in 2.1 + '\011example \015\012\000\377' # in 2.0 + +- Functions are now compared and hashed by identity, not by value, since + the func_code attribute is writable. + +- Weak references (PEP 205) have been added. This involves a few + changes in the core, an extension module (_weakref), and a Python + module (weakref). The weakref module is the public interface. It + includes support for "explicit" weak references, proxy objects, and + mappings with weakly held values. + +- A 'continue' statement can now appear in a try block within the body + of a loop. It is still not possible to use continue in a finally + clause. + +Standard library + +- mailbox.py now has a new class, PortableUnixMailbox which is + identical to UnixMailbox but uses a more portable scheme for + determining From_ separators. Also, the constructors for all the + classes in this module have a new optional `factory' argument, which + is a callable used when new message classes must be instantiated by + the next() method. + +- random.py is now self-contained, and offers all the functionality of + the now-deprecated whrandom.py. See the docs for details. random.py + also supports new functions getstate() and setstate(), for saving + and restoring the internal state of the generator; and jumpahead(n), + for quickly forcing the internal state to be the same as if n calls to + random() had been made. The latter is particularly useful for multi- + threaded programs, creating one instance of the random.Random() class for + each thread, then using .jumpahead() to force each instance to use a + non-overlapping segment of the full period. + +- random.py's seed() function is new. For bit-for-bit compatibility with + prior releases, use the whseed function instead. The new seed function + addresses two problems: (1) The old function couldn't produce more than + about 2**24 distinct internal states; the new one about 2**45 (the best + that can be done in the Wichmann-Hill generator). (2) The old function + sometimes produced identical internal states when passed distinct + integers, and there was no simple way to predict when that would happen; + the new one guarantees to produce distinct internal states for all + arguments in [0, 27814431486576L). + +- The socket module now supports raw packets on Linux. The socket + family is AF_PACKET. + +- test_capi.py is a start at running tests of the Python C API. The tests + are implemented by the new Modules/_testmodule.c. + +- A new extension module, _symtable, provides provisional access to the + internal symbol table used by the Python compiler. A higher-level + interface will be added on top of _symtable in a future release. + +- Removed the obsolete soundex module. + +- xml.dom.minidom now uses the standard DOM exceptions. Node supports + the isSameNode method; NamedNodeMap the get method. + +- xml.sax.expatreader supports the lexical handler property; it + generates comment, startCDATA, and endCDATA events. + +Windows changes + +- Build procedure: the zlib project is built in a different way that + ensures the zlib header files used can no longer get out of synch with + the zlib binary used. See PCbuild\readme.txt for details. Your old + zlib-related directories can be deleted; you'll need to download fresh + source for zlib and unpack it into a new directory. + +- Build: New subproject _test for the benefit of test_capi.py (see above). + +- Build: New subproject _symtable, for new DLL _symtable.pyd (a nascent + interface to some Python compiler internals). + +- Build: Subproject ucnhash is gone, since the code was folded into the + unicodedata subproject. + +What's New in Python 2.1 alpha 1? +================================= + +Core language, builtins, and interpreter + +- There is a new Unicode companion to the PyObject_Str() API + called PyObject_Unicode(). It behaves in the same way as the + former, but assures that the returned value is an Unicode object + (applying the usual coercion if necessary). + +- The comparison operators support "rich comparison overloading" (PEP + 207). C extension types can provide a rich comparison function in + the new tp_richcompare slot in the type object. The cmp() function + and the C function PyObject_Compare() first try the new rich + comparison operators before trying the old 3-way comparison. There + is also a new C API PyObject_RichCompare() (which also falls back on + the old 3-way comparison, but does not constrain the outcome of the + rich comparison to a Boolean result). + + The rich comparison function takes two objects (at least one of + which is guaranteed to have the type that provided the function) and + an integer indicating the opcode, which can be Py_LT, Py_LE, Py_EQ, + Py_NE, Py_GT, Py_GE (for <, <=, ==, !=, >, >=), and returns a Python + object, which may be NotImplemented (in which case the tp_compare + slot function is used as a fallback, if defined). + + Classes can overload individual comparison operators by defining one + or more of the methods__lt__, __le__, __eq__, __ne__, __gt__, + __ge__. There are no explicit "reflected argument" versions of + these; instead, __lt__ and __gt__ are each other's reflection, + likewise for__le__ and __ge__; __eq__ and __ne__ are their own + reflection (similar at the C level). No other implications are + made; in particular, Python does not assume that == is the Boolean + inverse of !=, or that < is the Boolean inverse of >=. This makes + it possible to define types with partial orderings. + + Classes or types that want to implement (in)equality tests but not + the ordering operators (i.e. unordered types) should implement == + and !=, and raise an error for the ordering operators. + + It is possible to define types whose rich comparison results are not + Boolean; e.g. a matrix type might want to return a matrix of bits + for A < B, giving elementwise comparisons. Such types should ensure + that any interpretation of their value in a Boolean context raises + an exception, e.g. by defining __nonzero__ (or the tp_nonzero slot + at the C level) to always raise an exception. + +- Complex numbers use rich comparisons to define == and != but raise + an exception for <, <=, > and >=. Unfortunately, this also means + that cmp() of two complex numbers raises an exception when the two + numbers differ. Since it is not mathematically meaningful to compare + complex numbers except for equality, I hope that this doesn't break + too much code. + +- The outcome of comparing non-numeric objects of different types is + not defined by the language, other than that it's arbitrary but + consistent (see the Reference Manual). An implementation detail changed + in 2.1a1 such that None now compares less than any other object. Code + relying on this new behavior (like code that relied on the previous + behavior) does so at its own risk. + +- Functions and methods now support getting and setting arbitrarily + named attributes (PEP 232). Functions have a new __dict__ + (a.k.a. func_dict) which hold the function attributes. Methods get + and set attributes on their underlying im_func. It is a TypeError + to set an attribute on a bound method. + +- The xrange() object implementation has been improved so that + xrange(sys.maxint) can be used on 64-bit platforms. There's still a + limitation that in this case len(xrange(sys.maxint)) can't be + calculated, but the common idiom "for i in xrange(sys.maxint)" will + work fine as long as the index i doesn't actually reach 2**31. + (Python uses regular ints for sequence and string indices; fixing + that is much more work.) + +- Two changes to from...import: + + 1) "from M import X" now works even if (after loading module M) + sys.modules['M'] is not a real module; it's basically a getattr() + operation with AttributeError exceptions changed into ImportError. + + 2) "from M import *" now looks for M.__all__ to decide which names to + import; if M.__all__ doesn't exist, it uses M.__dict__.keys() but + filters out names starting with '_' as before. Whether or not + __all__ exists, there's no restriction on the type of M. + +- File objects have a new method, xreadlines(). This is the fastest + way to iterate over all lines in a file: + + for line in file.xreadlines(): + ...do something to line... + + See the xreadlines module (mentioned below) for how to do this for + other file-like objects. + +- Even if you don't use file.xreadlines(), you may expect a speedup on + line-by-line input. The file.readline() method has been optimized + quite a bit in platform-specific ways: on systems (like Linux) that + support flockfile(), getc_unlocked(), and funlockfile(), those are + used by default. On systems (like Windows) without getc_unlocked(), + a complicated (but still thread-safe) method using fgets() is used by + default. + + You can force use of the fgets() method by #define'ing + USE_FGETS_IN_GETLINE at build time (it may be faster than + getc_unlocked()). + + You can force fgets() not to be used by #define'ing + DONT_USE_FGETS_IN_GETLINE (this is the first thing to try if std test + test_bufio.py fails -- and let us know if it does!). + +- In addition, the fileinput module, while still slower than the other + methods on most platforms, has been sped up too, by using + file.readlines(sizehint). + +- Support for run-time warnings has been added, including a new + command line option (-W) to specify the disposition of warnings. + See the description of the warnings module below. + +- Extensive changes have been made to the coercion code. This mostly + affects extension modules (which can now implement mixed-type + numerical operators without having to use coercion), but + occasionally, in boundary cases the coercion semantics have changed + subtly. Since this was a terrible gray area of the language, this + is considered an improvement. Also note that __rcmp__ is no longer + supported -- instead of calling __rcmp__, __cmp__ is called with + reflected arguments. + +- In connection with the coercion changes, a new built-in singleton + object, NotImplemented is defined. This can be returned for + operations that wish to indicate they are not implemented for a + particular combination of arguments. From C, this is + Py_NotImplemented. + +- The interpreter accepts now bytecode files on the command line even + if they do not have a .pyc or .pyo extension. On Linux, after executing + +import imp,sys,string +magic = string.join(["\\x%.2x" % ord(c) for c in imp.get_magic()],"") +reg = ':pyc:M::%s::%s:' % (magic, sys.executable) +open("/proc/sys/fs/binfmt_misc/register","wb").write(reg) + + any byte code file can be used as an executable (i.e. as an argument + to execve(2)). + +- %[xXo] formats of negative Python longs now produce a sign + character. In 1.6 and earlier, they never produced a sign, + and raised an error if the value of the long was too large + to fit in a Python int. In 2.0, they produced a sign if and + only if too large to fit in an int. This was inconsistent + across platforms (because the size of an int varies across + platforms), and inconsistent with hex() and oct(). Example: + + >>> "%x" % -0x42L + '-42' # in 2.1 + 'ffffffbe' # in 2.0 and before, on 32-bit machines + >>> hex(-0x42L) + '-0x42L' # in all versions of Python + + The behavior of %d formats for negative Python longs remains + the same as in 2.0 (although in 1.6 and before, they raised + an error if the long didn't fit in a Python int). + + %u formats don't make sense for Python longs, but are allowed + and treated the same as %d in 2.1. In 2.0, a negative long + formatted via %u produced a sign if and only if too large to + fit in an int. In 1.6 and earlier, a negative long formatted + via %u raised an error if it was too big to fit in an int. + +- Dictionary objects have an odd new method, popitem(). This removes + an arbitrary item from the dictionary and returns it (in the form of + a (key, value) pair). This can be useful for algorithms that use a + dictionary as a bag of "to do" items and repeatedly need to pick one + item. Such algorithms normally end up running in quadratic time; + using popitem() they can usually be made to run in linear time. + +Standard library + +- In the time module, the time argument to the functions strftime, + localtime, gmtime, asctime and ctime is now optional, defaulting to + the current time (in the local timezone). + +- The ftplib module now defaults to passive mode, which is deemed a + more useful default given that clients are often inside firewalls + these days. Note that this could break if ftplib is used to connect + to a *server* that is inside a firewall, from outside; this is + expected to be a very rare situation. To fix that, you can call + ftp.set_pasv(0). + +- The module site now treats .pth files not only for path configuration, + but also supports extensions to the initialization code: Lines starting + with import are executed. + +- There's a new module, warnings, which implements a mechanism for + issuing and filtering warnings. There are some new built-in + exceptions that serve as warning categories, and a new command line + option, -W, to control warnings (e.g. -Wi ignores all warnings, -We + turns warnings into errors). warnings.warn(message[, category]) + issues a warning message; this can also be called from C as + PyErr_Warn(category, message). + +- A new module xreadlines was added. This exports a single factory + function, xreadlines(). The intention is that this code is the + absolutely fastest way to iterate over all lines in an open + file(-like) object: + + import xreadlines + for line in xreadlines.xreadlines(file): + ...do something to line... + + This is equivalent to the previous the speed record holder using + file.readlines(sizehint). Note that if file is a real file object + (as opposed to a file-like object), this is equivalent: + + for line in file.xreadlines(): + ...do something to line... + +- The bisect module has new functions bisect_left, insort_left, + bisect_right and insort_right. The old names bisect and insort + are now aliases for bisect_right and insort_right. XXX_right + and XXX_left methods differ in what happens when the new element + compares equal to one or more elements already in the list: the + XXX_left methods insert to the left, the XXX_right methods to the + right. Code that doesn't care where equal elements end up should + continue to use the old, short names ("bisect" and "insort"). + +- The new curses.panel module wraps the panel library that forms part + of SYSV curses and ncurses. Contributed by Thomas Gellekum. + +- The SocketServer module now sets the allow_reuse_address flag by + default in the TCPServer class. + +- A new function, sys._getframe(), returns the stack frame pointer of + the caller. This is intended only as a building block for + higher-level mechanisms such as string interpolation. + +- The pyexpat module supports a number of new handlers, which are + available only in expat 1.2. If invocation of a callback fails, it + will report an additional frame in the traceback. Parser objects + participate now in garbage collection. If expat reports an unknown + encoding, pyexpat will try to use a Python codec; that works only + for single-byte charsets. The parser type objects is exposed as + XMLParserObject. + +- xml.dom now offers standard definitions for symbolic node type and + exception code constants, and a hierarchy of DOM exceptions. minidom + was adjusted to use them. + +- The conformance of xml.dom.minidom to the DOM specification was + improved. It detects a number of additional error cases; the + previous/next relationship works even when the tree is modified; + Node supports the normalize() method; NamedNodeMap, DocumentType and + DOMImplementation classes were added; Element supports the + hasAttribute and hasAttributeNS methods; and Text supports the splitText + method. + +Build issues + +- For Unix (and Unix-compatible) builds, configuration and building of + extension modules is now greatly automated. Rather than having to + edit the Modules/Setup file to indicate which modules should be + built and where their include files and libraries are, a + distutils-based setup.py script now takes care of building most + extension modules. All extension modules built this way are built + as shared libraries. Only a few modules that must be linked + statically are still listed in the Setup file; you won't need to + edit their configuration. + +- Python should now build out of the box on Cygwin. If it doesn't, + mail to Jason Tishler (jlt63 at users.sourceforge.net). + +- Python now always uses its own (renamed) implementation of getopt() + -- there's too much variation among C library getopt() + implementations. + +- C++ compilers are better supported; the CXX macro is always set to a + C++ compiler if one is found. + +Windows changes + +- select module: By default under Windows, a select() call + can specify no more than 64 sockets. Python now boosts + this Microsoft default to 512. If you need even more than + that, see the MS docs (you'll need to #define FD_SETSIZE + and recompile Python from source). + +- Support for Windows 3.1, DOS and OS/2 is gone. The Lib/dos-8x3 + subdirectory is no more! + + +What's New in Python 2.0? +========================= + +Below is a list of all relevant changes since release 1.6. Older +changes are in the file HISTORY. If you are making the jump directly +from Python 1.5.2 to 2.0, make sure to read the section for 1.6 in the +HISTORY file! Many important changes listed there. + +Alternatively, a good overview of the changes between 1.5.2 and 2.0 is +the document "What's New in Python 2.0" by Kuchling and Moshe Zadka: +http://www.amk.ca/python/2.0/. + +--Guido van Rossum (home page: http://www.pythonlabs.com/~guido/) + +====================================================================== + +What's new in 2.0 (since release candidate 1)? +============================================== + +Standard library + +- The copy_reg module was modified to clarify its intended use: to + register pickle support for extension types, not for classes. + pickle() will raise a TypeError if it is passed a class. + +- Fixed a bug in gettext's "normalize and expand" code that prevented + it from finding an existing .mo file. + +- Restored support for HTTP/0.9 servers in httplib. + +- The math module was changed to stop raising OverflowError in case of + underflow, and return 0 instead in underflow cases. Whether Python + used to raise OverflowError in case of underflow was platform- + dependent (it did when the platform math library set errno to ERANGE + on underflow). + +- Fixed a bug in StringIO that occurred when the file position was not + at the end of the file and write() was called with enough data to + extend past the end of the file. + +- Fixed a bug that caused Tkinter error messages to get lost on + Windows. The bug was fixed by replacing direct use of + interp->result with Tcl_GetStringResult(interp). + +- Fixed bug in urllib2 that caused it to fail when it received an HTTP + redirect response. + +- Several changes were made to distutils: Some debugging code was + removed from util. Fixed the installer used when an external zip + program (like WinZip) is not found; the source code for this + installer is in Misc/distutils. check_lib() was modified to behave + more like AC_CHECK_LIB by add other_libraries() as a parameter. The + test for whether installed modules are on sys.path was changed to + use both normcase() and normpath(). + +- Several minor bugs were fixed in the xml package (the minidom, + pulldom, expatreader, and saxutils modules). + +- The regression test driver (regrtest.py) behavior when invoked with + -l changed: It now reports a count of objects that are recognized as + garbage but not freed by the garbage collector. + +- The regression test for the math module was changed to test + exceptional behavior when the test is run in verbose mode. Python + cannot yet guarantee consistent exception behavior across platforms, + so the exception part of test_math is run only in verbose mode, and + may fail on your platform. + +Internals + +- PyOS_CheckStack() has been disabled on Win64, where it caused + test_sre to fail. + +Build issues + +- Changed compiler flags, so that gcc is always invoked with -Wall and + -Wstrict-prototypes. Users compiling Python with GCC should see + exactly one warning, except if they have passed configure the + --with-pydebug flag. The expected warning is for getopt() in + Modules/main.c. This warning will be fixed for Python 2.1. + +- Fixed configure to add -threads argument during linking on OSF1. + +Tools and other miscellany + +- The compiler in Tools/compiler was updated to support the new + language features introduced in 2.0: extended print statement, list + comprehensions, and augmented assignments. The new compiler should + also be backwards compatible with Python 1.5.2; the compiler will + always generate code for the version of the interpreter it runs + under. + +What's new in 2.0 release candidate 1 (since beta 2)? +===================================================== + +What is release candidate 1? + +We believe that release candidate 1 will fix all known bugs that we +intend to fix for the 2.0 final release. This release should be a bit +more stable than the previous betas. We would like to see even more +widespread testing before the final release, so we are producing this +release candidate. The final release will be exactly the same unless +any show-stopping (or brown bag) bugs are found by testers of the +release candidate. + +All the changes since the last beta release are bug fixes or changes +to support building Python for specific platforms. + +Core language, builtins, and interpreter + +- A bug that caused crashes when __coerce__ was used with augmented + assignment, e.g. +=, was fixed. + +- Raise ZeroDivisionError when raising zero to a negative number, + e.g. 0.0 ** -2.0. Note that math.pow is unrelated to the builtin + power operator and the result of math.pow(0.0, -2.0) will vary by + platform. On Linux, it raises a ValueError. + +- A bug in Unicode string interpolation was fixed that occasionally + caused errors with formats including "%%". For example, the + following expression "%% %s" % u"abc" no longer raises a TypeError. + +- Compilation of deeply nested expressions raises MemoryError instead + of SyntaxError, e.g. eval("[" * 50 + "]" * 50). + +- In 2.0b2 on Windows, the interpreter wrote .pyc files in text mode, + rendering them useless. They are now written in binary mode again. + +Standard library + +- Keyword arguments are now accepted for most pattern and match object + methods in SRE, the standard regular expression engine. + +- In SRE, fixed error with negative lookahead and lookbehind that + manifested itself as a runtime error in patterns like "(?<!abc)(def)". + +- Several bugs in the Unicode handling and error handling in _tkinter + were fixed. + +- Fix memory management errors in Merge() and Tkapp_Call() routines. + +- Several changes were made to cStringIO to make it compatible with + the file-like object interface and with StringIO. If operations are + performed on a closed object, an exception is raised. The truncate + method now accepts a position argument and readline accepts a size + argument. + +- There were many changes made to the linuxaudiodev module and its + test suite; as a result, a short, unexpected audio sample should now + play when the regression test is run. + + Note that this module is named poorly, because it should work + correctly on any platform that supports the Open Sound System + (OSS). + + The module now raises exceptions when errors occur instead of + crashing. It also defines the AFMT_A_LAW format (logarithmic A-law + audio) and defines a getptr() method that calls the + SNDCTL_DSP_GETxPTR ioctl defined in the OSS Programmer's Guide. + +- The library_version attribute, introduced in an earlier beta, was + removed because it can not be supported with early versions of the C + readline library, which provides no way to determine the version at + compile-time. + +- The binascii module is now enabled on Win64. + +- tokenize.py no longer suffers "recursion depth" errors when parsing + programs with very long string literals. + +Internals + +- Fixed several buffer overflow vulnerabilities in calculate_path(), + which is called when the interpreter starts up to determine where + the standard library is installed. These vulnerabilities affect all + previous versions of Python and can be exploited by setting very + long values for PYTHONHOME or argv[0]. The risk is greatest for a + setuid Python script, although use of the wrapper in + Misc/setuid-prog.c will eliminate the vulnerability. + +- Fixed garbage collection bugs in instance creation that were + triggered when errors occurred during initialization. The solution, + applied in cPickle and in PyInstance_New(), is to call + PyObject_GC_Init() after the initialization of the object's + container attributes is complete. + +- pyexpat adds definitions of PyModule_AddStringConstant and + PyModule_AddObject if the Python version is less than 2.0, which + provides compatibility with PyXML on Python 1.5.2. + +- If the platform has a bogus definition for LONG_BIT (the number of + bits in a long), an error will be reported at compile time. + +- Fix bugs in _PyTuple_Resize() which caused hard-to-interpret garbage + collection crashes and possibly other, unreported crashes. + +- Fixed a memory leak in _PyUnicode_Fini(). + +Build issues + +- configure now accepts a --with-suffix option that specifies the + executable suffix. This is useful for builds on Cygwin and Mac OS + X, for example. + +- The mmap.PAGESIZE constant is now initialized using sysconf when + possible, which eliminates a dependency on -lucb for Reliant UNIX. + +- The md5 file should now compile on all platforms. + +- The select module now compiles on platforms that do not define + POLLRDNORM and related constants. + +- Darwin (Mac OS X): Initial support for static builds on this + platform. + +- BeOS: A number of changes were made to the build and installation + process. ar-fake now operates on a directory of object files. + dl_export.h is gone, and its macros now appear on the mwcc command + line during build on PPC BeOS. + +- Platform directory in lib/python2.0 is "plat-beos5" (or + "plat-beos4", if building on BeOS 4.5), rather than "plat-beos". + +- Cygwin: Support for shared libraries, Tkinter, and sockets. + +- SunOS 4.1.4_JL: Fix test for directory existence in configure. + +Tools and other miscellany + +- Removed debugging prints from main used with freeze. + +- IDLE auto-indent no longer crashes when it encounters Unicode + characters. + +What's new in 2.0 beta 2 (since beta 1)? +======================================== + +Core language, builtins, and interpreter + +- Add support for unbounded ints in %d,i,u,x,X,o formats; for example + "%d" % 2L**64 == "18446744073709551616". + +- Add -h and -V command line options to print the usage message and + Python version number and exit immediately. + +- eval() and exec accept Unicode objects as code parameters. + +- getattr() and setattr() now also accept Unicode objects for the + attribute name, which are converted to strings using the default + encoding before lookup. + +- Multiplication on string and Unicode now does proper bounds + checking; e.g. 'a' * 65536 * 65536 will raise ValueError, "repeated + string is too long." + +- Better error message when continue is found in try statement in a + loop. + + +Standard library and extensions + +- socket module: the OpenSSL code now adds support for RAND_status() + and EGD (Entropy Gathering Device). + +- array: reverse() method of array now works. buffer_info() now does + argument checking; it still takes no arguments. + +- asyncore/asynchat: Included most recent version from Sam Rushing. + +- cgi: Accept '&' or ';' as separator characters when parsing form data. + +- CGIHTTPServer: Now works on Windows (and perhaps even Mac). + +- ConfigParser: When reading the file, options spelled in upper case + letters are now correctly converted to lowercase. + +- copy: Copy Unicode objects atomically. + +- cPickle: Fail gracefully when copy_reg can't be imported. + +- cStringIO: Implemented readlines() method. + +- dbm: Add get() and setdefault() methods to dbm object. Add constant + `library' to module that names the library used. Added doc strings + and method names to error messages. Uses configure to determine + which ndbm.h file to include; Berkeley DB's nbdm and GDBM's ndbm is + now available options. + +- distutils: Update to version 0.9.3. + +- dl: Add several dl.RTLD_ constants. + +- fpectl: Now supported on FreeBSD. + +- gc: Add DEBUG_SAVEALL option. When enabled all garbage objects + found by the collector will be saved in gc.garbage. This is useful + for debugging a program that creates reference cycles. + +- httplib: Three changes: Restore support for set_debuglevel feature + of HTTP class. Do not close socket on zero-length response. Do not + crash when server sends invalid content-length header. + +- mailbox: Mailbox class conforms better to qmail specifications. + +- marshal: When reading a short, sign-extend on platforms where shorts + are bigger than 16 bits. When reading a long, repair the unportable + sign extension that was being done for 64-bit machines. (It assumed + that signed right shift sign-extends.) + +- operator: Add contains(), invert(), __invert__() as aliases for + __contains__(), inv(), and __inv__() respectively. + +- os: Add support for popen2() and popen3() on all platforms where + fork() exists. (popen4() is still in the works.) + +- os: (Windows only:) Add startfile() function that acts like double- + clicking on a file in Explorer (or passing the file name to the + DOS "start" command). + +- os.path: (Windows, DOS:) Treat trailing colon correctly in + os.path.join. os.path.join("a:", "b") yields "a:b". + +- pickle: Now raises ValueError when an invalid pickle that contains + a non-string repr where a string repr was expected. This behavior + matches cPickle. + +- posixfile: Remove broken __del__() method. + +- py_compile: support CR+LF line terminators in source file. + +- readline: Does not immediately exit when ^C is hit when readline and + threads are configured. Adds definition of rl_library_version. (The + latter addition requires GNU readline 2.2 or later.) + +- rfc822: Domain literals returned by AddrlistClass method + getdomainliteral() are now properly wrapped in brackets. + +- site: sys.setdefaultencoding() should only be called in case the + standard default encoding ("ascii") is changed. This saves quite a + few cycles during startup since the first call to + setdefaultencoding() will initialize the codec registry and the + encodings package. + +- socket: Support for size hint in readlines() method of object returned + by makefile(). + +- sre: Added experimental expand() method to match objects. Does not + use buffer interface on Unicode strings. Does not hang if group id + is followed by whitespace. + +- StringIO: Size hint in readlines() is now supported as documented. + +- struct: Check ranges for bytes and shorts. + +- urllib: Improved handling of win32 proxy settings. Fixed quote and + quote_plus functions so that the always encode a comma. + +- Tkinter: Image objects are now guaranteed to have unique ids. Set + event.delta to zero if Tk version doesn't support mousewheel. + Removed some debugging prints. + +- UserList: now implements __contains__(). + +- webbrowser: On Windows, use os.startfile() instead of os.popen(), + which works around a bug in Norton AntiVirus 2000 that leads directly + to a Blue Screen freeze. + +- xml: New version detection code allows PyXML to override standard + XML package if PyXML version is greater than 0.6.1. + +- xml.dom: DOM level 1 support for basic XML. Includes xml.dom.minidom + (conventional DOM), and xml.dom.pulldom, which allows building the DOM + tree only for nodes which are sufficiently interesting to a specific + application. Does not provide the HTML-specific extensions. Still + undocumented. + +- xml.sax: SAX 2 support for Python, including all the handler + interfaces needed to process XML 1.0 compliant XML. Some + documentation is already available. + +- pyexpat: Renamed to xml.parsers.expat since this is part of the new, + packagized XML support. + + +C API + +- Add three new convenience functions for module initialization -- + PyModule_AddObject(), PyModule_AddIntConstant(), and + PyModule_AddStringConstant(). + +- Cleaned up definition of NULL in C source code; all definitions were + removed and add #error to Python.h if NULL isn't defined after + #include of stdio.h. + +- Py_PROTO() macros that were removed in 2.0b1 have been restored for + backwards compatibility (at the source level) with old extensions. + +- A wrapper API was added for signal() and sigaction(). Instead of + either function, always use PyOS_getsig() to get a signal handler + and PyOS_setsig() to set one. A new convenience typedef + PyOS_sighandler_t is defined for the type of signal handlers. + +- Add PyString_AsStringAndSize() function that provides access to the + internal data buffer and size of a string object -- or the default + encoded version of a Unicode object. + +- PyString_Size() and PyString_AsString() accept Unicode objects. + +- The standard header <limits.h> is now included by Python.h (if it + exists). INT_MAX and LONG_MAX will always be defined, even if + <limits.h> is not available. + +- PyFloat_FromString takes a second argument, pend, that was + effectively useless. It is now officially useless but preserved for + backwards compatibility. If the pend argument is not NULL, *pend is + set to NULL. + +- PyObject_GetAttr() and PyObject_SetAttr() now accept Unicode objects + for the attribute name. See note on getattr() above. + +- A few bug fixes to argument processing for Unicode. + PyArg_ParseTupleAndKeywords() now accepts "es#" and "es". + PyArg_Parse() special cases "s#" for Unicode objects; it returns a + pointer to the default encoded string data instead of to the raw + UTF-16. + +- Py_BuildValue accepts B format (for bgen-generated code). + + +Internals + +- On Unix, fix code for finding Python installation directory so that + it works when argv[0] is a relative path. + +- Added a true unicode_internal_encode() function and fixed the + unicode_internal_decode function() to support Unicode objects directly + rather than by generating a copy of the object. + +- Several of the internal Unicode tables are much smaller now, and + the source code should be much friendlier to weaker compilers. + +- In the garbage collector: Fixed bug in collection of tuples. Fixed + bug that caused some instances to be removed from the container set + while they were still live. Fixed parsing in gc.set_debug() for + platforms where sizeof(long) > sizeof(int). + +- Fixed refcount problem in instance deallocation that only occurred + when Py_REF_DEBUG was defined and Py_TRACE_REFS was not. + +- On Windows, getpythonregpath is now protected against null data in + registry key. + +- On Unix, create .pyc/.pyo files with O_EXCL flag to avoid a race + condition. + + +Build and platform-specific issues + +- Better support of GNU Pth via --with-pth configure option. + +- Python/C API now properly exposed to dynamically-loaded extension + modules on Reliant UNIX. + +- Changes for the benefit of SunOS 4.1.4 (really!). mmapmodule.c: + Don't define MS_SYNC to be zero when it is undefined. Added missing + prototypes in posixmodule.c. + +- Improved support for HP-UX build. Threads should now be correctly + configured (on HP-UX 10.20 and 11.00). + +- Fix largefile support on older NetBSD systems and OpenBSD by adding + define for TELL64. + + +Tools and other miscellany + +- ftpmirror: Call to main() is wrapped in if __name__ == "__main__". + +- freeze: The modulefinder now works with 2.0 opcodes. + +- IDLE: + Move hackery of sys.argv until after the Tk instance has been + created, which allows the application-specific Tkinter + initialization to be executed if present; also pass an explicit + className parameter to the Tk() constructor. + + +What's new in 2.0 beta 1? +========================= + +Source Incompatibilities +------------------------ + +None. Note that 1.6 introduced several incompatibilities with 1.5.2, +such as single-argument append(), connect() and bind(), and changes to +str(long) and repr(float). + + +Binary Incompatibilities +------------------------ + +- Third party extensions built for Python 1.5.x or 1.6 cannot be used +with Python 2.0; these extensions will have to be rebuilt for Python +2.0. + +- On Windows, attempting to import a third party extension built for +Python 1.5.x or 1.6 results in an immediate crash; there's not much we +can do about this. Check your PYTHONPATH environment variable! + +- Python bytecode files (*.pyc and *.pyo) are not compatible between +releases. + + +Overview of Changes Since 1.6 +----------------------------- + +There are many new modules (including brand new XML support through +the xml package, and i18n support through the gettext module); a list +of all new modules is included below. Lots of bugs have been fixed. + +The process for making major new changes to the language has changed +since Python 1.6. Enhancements must now be documented by a Python +Enhancement Proposal (PEP) before they can be accepted. + +There are several important syntax enhancements, described in more +detail below: + + - Augmented assignment, e.g. x += 1 + + - List comprehensions, e.g. [x**2 for x in range(10)] + + - Extended import statement, e.g. import Module as Name + + - Extended print statement, e.g. print >> file, "Hello" + +Other important changes: + + - Optional collection of cyclical garbage + +Python Enhancement Proposal (PEP) +--------------------------------- + +PEP stands for Python Enhancement Proposal. A PEP is a design +document providing information to the Python community, or describing +a new feature for Python. The PEP should provide a concise technical +specification of the feature and a rationale for the feature. + +We intend PEPs to be the primary mechanisms for proposing new +features, for collecting community input on an issue, and for +documenting the design decisions that have gone into Python. The PEP +author is responsible for building consensus within the community and +documenting dissenting opinions. + +The PEPs are available at http://python.sourceforge.net/peps/. + +Augmented Assignment +-------------------- + +This must have been the most-requested feature of the past years! +Eleven new assignment operators were added: + + += -= *= /= %= **= <<= >>= &= ^= |= + +For example, + + A += B + +is similar to + + A = A + B + +except that A is evaluated only once (relevant when A is something +like dict[index].attr). + +However, if A is a mutable object, A may be modified in place. Thus, +if A is a number or a string, A += B has the same effect as A = A+B +(except A is only evaluated once); but if a is a list, A += B has the +same effect as A.extend(B)! + +Classes and built-in object types can override the new operators in +order to implement the in-place behavior; the not-in-place behavior is +used automatically as a fallback when an object doesn't implement the +in-place behavior. For classes, the method name is derived from the +method name for the corresponding not-in-place operator by inserting +an 'i' in front of the name, e.g. __iadd__ implements in-place +__add__. + +Augmented assignment was implemented by Thomas Wouters. + + +List Comprehensions +------------------- + +This is a flexible new notation for lists whose elements are computed +from another list (or lists). The simplest form is: + + [<expression> for <variable> in <sequence>] + +For example, [i**2 for i in range(4)] yields the list [0, 1, 4, 9]. +This is more efficient than a for loop with a list.append() call. + +You can also add a condition: + + [<expression> for <variable> in <sequence> if <condition>] + +For example, [w for w in words if w == w.lower()] would yield the list +of words that contain no uppercase characters. This is more efficient +than a for loop with an if statement and a list.append() call. + +You can also have nested for loops and more than one 'if' clause. For +example, here's a function that flattens a sequence of sequences:: + + def flatten(seq): + return [x for subseq in seq for x in subseq] + + flatten([[0], [1,2,3], [4,5], [6,7,8,9], []]) + +This prints + + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + +List comprehensions originated as a patch set from Greg Ewing; Skip +Montanaro and Thomas Wouters also contributed. Described by PEP 202. + + +Extended Import Statement +------------------------- + +Many people have asked for a way to import a module under a different +name. This can be accomplished like this: + + import foo + bar = foo + del foo + +but this common idiom gets old quickly. A simple extension of the +import statement now allows this to be written as follows: + + import foo as bar + +There's also a variant for 'from ... import': + + from foo import bar as spam + +This also works with packages; e.g. you can write this: + + import test.regrtest as regrtest + +Note that 'as' is not a new keyword -- it is recognized only in this +context (this is only possible because the syntax for the import +statement doesn't involve expressions). + +Implemented by Thomas Wouters. Described by PEP 221. + + +Extended Print Statement +------------------------ + +Easily the most controversial new feature, this extension to the print +statement adds an option to make the output go to a different file +than the default sys.stdout. + +For example, to write an error message to sys.stderr, you can now +write: + + print >> sys.stderr, "Error: bad dog!" + +As a special feature, if the expression used to indicate the file +evaluates to None, the current value of sys.stdout is used. Thus: + + print >> None, "Hello world" + +is equivalent to + + print "Hello world" + +Design and implementation by Barry Warsaw. Described by PEP 214. + + +Optional Collection of Cyclical Garbage +--------------------------------------- + +Python is now equipped with a garbage collector that can hunt down +cyclical references between Python objects. It's no replacement for +reference counting; in fact, it depends on the reference counts being +correct, and decides that a set of objects belong to a cycle if all +their reference counts can be accounted for from their references to +each other. This devious scheme was first proposed by Eric Tiedemann, +and brought to implementation by Neil Schemenauer. + +There's a module "gc" that lets you control some parameters of the +garbage collection. There's also an option to the configure script +that lets you enable or disable the garbage collection. In 2.0b1, +it's on by default, so that we (hopefully) can collect decent user +experience with this new feature. There are some questions about its +performance. If it proves to be too much of a problem, we'll turn it +off by default in the final 2.0 release. + + +Smaller Changes +--------------- + +A new function zip() was added. zip(seq1, seq2, ...) is equivalent to +map(None, seq1, seq2, ...) when the sequences have the same length; +i.e. zip([1,2,3], [10,20,30]) returns [(1,10), (2,20), (3,30)]. When +the lists are not all the same length, the shortest list wins: +zip([1,2,3], [10,20]) returns [(1,10), (2,20)]. See PEP 201. + +sys.version_info is a tuple (major, minor, micro, level, serial). + +Dictionaries have an odd new method, setdefault(key, default). +dict.setdefault(key, default) returns dict[key] if it exists; if not, +it sets dict[key] to default and returns that value. Thus: + + dict.setdefault(key, []).append(item) + +does the same work as this common idiom: + + if not dict.has_key(key): + dict[key] = [] + dict[key].append(item) + +There are two new variants of SyntaxError that are raised for +indentation-related errors: IndentationError and TabError. + +Changed \x to consume exactly two hex digits; see PEP 223. Added \U +escape that consumes exactly eight hex digits. + +The limits on the size of expressions and file in Python source code +have been raised from 2**16 to 2**32. Previous versions of Python +were limited because the maximum argument size the Python VM accepted +was 2**16. This limited the size of object constructor expressions, +e.g. [1,2,3] or {'a':1, 'b':2}, and the size of source files. This +limit was raised thanks to a patch by Charles Waldman that effectively +fixes the problem. It is now much more likely that you will be +limited by available memory than by an arbitrary limit in Python. + +The interpreter's maximum recursion depth can be modified by Python +programs using sys.getrecursionlimit and sys.setrecursionlimit. This +limit is the maximum number of recursive calls that can be made by +Python code. The limit exists to prevent infinite recursion from +overflowing the C stack and causing a core dump. The default value is +1000. The maximum safe value for a particular platform can be found +by running Misc/find_recursionlimit.py. + +New Modules and Packages +------------------------ + +atexit - for registering functions to be called when Python exits. + +imputil - Greg Stein's alternative API for writing custom import +hooks. + +pyexpat - an interface to the Expat XML parser, contributed by Paul +Prescod. + +xml - a new package with XML support code organized (so far) in three +subpackages: xml.dom, xml.sax, and xml.parsers. Describing these +would fill a volume. There's a special feature whereby a +user-installed package named _xmlplus overrides the standard +xmlpackage; this is intended to give the XML SIG a hook to distribute +backwards-compatible updates to the standard xml package. + +webbrowser - a platform-independent API to launch a web browser. + + +Changed Modules +--------------- + +array -- new methods for array objects: count, extend, index, pop, and +remove + +binascii -- new functions b2a_hex and a2b_hex that convert between +binary data and its hex representation + +calendar -- Many new functions that support features including control +over which day of the week is the first day, returning strings instead +of printing them. Also new symbolic constants for days of week, +e.g. MONDAY, ..., SUNDAY. + +cgi -- FieldStorage objects have a getvalue method that works like a +dictionary's get method and returns the value attribute of the object. + +ConfigParser -- The parser object has new methods has_option, +remove_section, remove_option, set, and write. They allow the module +to be used for writing config files as well as reading them. + +ftplib -- ntransfercmd(), transfercmd(), and retrbinary() all now +optionally support the RFC 959 REST command. + +gzip -- readline and readlines now accept optional size arguments + +httplib -- New interfaces and support for HTTP/1.1 by Greg Stein. See +the module doc strings for details. + +locale -- implement getdefaultlocale for Win32 and Macintosh + +marshal -- no longer dumps core when marshaling deeply nested or +recursive data structures + +os -- new functions isatty, seteuid, setegid, setreuid, setregid + +os/popen2 -- popen2/popen3/popen4 support under Windows. popen2/popen3 +support under Unix. + +os/pty -- support for openpty and forkpty + +os.path -- fix semantics of os.path.commonprefix + +smtplib -- support for sending very long messages + +socket -- new function getfqdn() + +readline -- new functions to read, write and truncate history files. +The readline section of the library reference manual contains an +example. + +select -- add interface to poll system call + +shutil -- new copyfileobj function + +SimpleHTTPServer, CGIHTTPServer -- Fix problems with buffering in the +HTTP server. + +Tkinter -- optimization of function flatten + +urllib -- scans environment variables for proxy configuration, +e.g. http_proxy. + +whichdb -- recognizes dumbdbm format + + +Obsolete Modules +---------------- + +None. However note that 1.6 made a whole slew of modules obsolete: +stdwin, soundex, cml, cmpcache, dircache, dump, find, grep, packmail, +poly, zmod, strop, util, whatsound. + + +Changed, New, Obsolete Tools +---------------------------- + +None. + + +C-level Changes +--------------- + +Several cleanup jobs were carried out throughout the source code. + +All C code was converted to ANSI C; we got rid of all uses of the +Py_PROTO() macro, which makes the header files a lot more readable. + +Most of the portability hacks were moved to a new header file, +pyport.h; several other new header files were added and some old +header files were removed, in an attempt to create a more rational set +of header files. (Few of these ever need to be included explicitly; +they are all included by Python.h.) + +Trent Mick ensured portability to 64-bit platforms, under both Linux +and Win64, especially for the new Intel Itanium processor. Mick also +added large file support for Linux64 and Win64. + +The C APIs to return an object's size have been update to consistently +use the form PyXXX_Size, e.g. PySequence_Size and PyDict_Size. In +previous versions, the abstract interfaces used PyXXX_Length and the +concrete interfaces used PyXXX_Size. The old names, +e.g. PyObject_Length, are still available for backwards compatibility +at the API level, but are deprecated. + +The PyOS_CheckStack function has been implemented on Windows by +Fredrik Lundh. It prevents Python from failing with a stack overflow +on Windows. + +The GC changes resulted in creation of two new slots on object, +tp_traverse and tp_clear. The augmented assignment changes result in +the creation of a new slot for each in-place operator. + +The GC API creates new requirements for container types implemented in +C extension modules. See Include/objimpl.h for details. + +PyErr_Format has been updated to automatically calculate the size of +the buffer needed to hold the formatted result string. This change +prevents crashes caused by programmer error. + +New C API calls: PyObject_AsFileDescriptor, PyErr_WriteUnraisable. + +PyRun_AnyFileEx, PyRun_SimpleFileEx, PyRun_FileEx -- New functions +that are the same as their non-Ex counterparts except they take an +extra flag argument that tells them to close the file when done. + +XXX There were other API changes that should be fleshed out here. + + +Windows Changes +--------------- + +New popen2/popen3/peopen4 in os module (see Changed Modules above). + +os.popen is much more usable on Windows 95 and 98. See Microsoft +Knowledge Base article Q150956. The Win9x workaround described there +is implemented by the new w9xpopen.exe helper in the root of your +Python installation. Note that Python uses this internally; it is not +a standalone program. + +Administrator privileges are no longer required to install Python +on Windows NT or Windows 2000. If you have administrator privileges, +Python's registry info will be written under HKEY_LOCAL_MACHINE. +Otherwise the installer backs off to writing Python's registry info +under HKEY_CURRENT_USER. The latter is sufficient for all "normal" +uses of Python, but will prevent some advanced uses from working +(for example, running a Python script as an NT service, or possibly +from CGI). + +[This was new in 1.6] The installer no longer runs a separate Tcl/Tk +installer; instead, it installs the needed Tcl/Tk files directly in the +Python directory. If you already have a Tcl/Tk installation, this +wastes some disk space (about 4 Megs) but avoids problems with +conflicting Tcl/Tk installations, and makes it much easier for Python +to ensure that Tcl/Tk can find all its files. + +[This was new in 1.6] The Windows installer now installs by default in +\Python20\ on the default volume, instead of \Program Files\Python-2.0\. + + +Updates to the changes between 1.5.2 and 1.6 +-------------------------------------------- + +The 1.6 NEWS file can't be changed after the release is done, so here +is some late-breaking news: + +New APIs in locale.py: normalize(), getdefaultlocale(), resetlocale(), +and changes to getlocale() and setlocale(). + +The new module is now enabled per default. + +It is not true that the encodings codecs cannot be used for normal +strings: the string.encode() (which is also present on 8-bit strings +!) allows using them for 8-bit strings too, e.g. to convert files from +cp1252 (Windows) to latin-1 or vice-versa. + +Japanese codecs are available from Tamito KAJIYAMA: +http://pseudo.grad.sccs.chukyo-u.ac.jp/~kajiyama/python/ + + +====================================================================== + + +======================================= +==> Release 1.6 (September 5, 2000) <== +======================================= + +What's new in release 1.6? +========================== + +Below is a list of all relevant changes since release 1.5.2. + + +Source Incompatibilities +------------------------ + +Several small incompatible library changes may trip you up: + + - The append() method for lists can no longer be invoked with more + than one argument. This used to append a single tuple made out of + all arguments, but was undocumented. To append a tuple, use + e.g. l.append((a, b, c)). + + - The connect(), connect_ex() and bind() methods for sockets require + exactly one argument. Previously, you could call s.connect(host, + port), but this was undocumented. You must now write + s.connect((host, port)). + + - The str() and repr() functions are now different more often. For + long integers, str() no longer appends a 'L'. Thus, str(1L) == '1', + which used to be '1L'; repr(1L) is unchanged and still returns '1L'. + For floats, repr() now gives 17 digits of precision, to ensure no + precision is lost (on all current hardware). + + - The -X option is gone. Built-in exceptions are now always + classes. Many more library modules also have been converted to + class-based exceptions. + + +Binary Incompatibilities +------------------------ + +- Third party extensions built for Python 1.5.x cannot be used with +Python 1.6; these extensions will have to be rebuilt for Python 1.6. + +- On Windows, attempting to import a third party extension built for +Python 1.5.x results in an immediate crash; there's not much we can do +about this. Check your PYTHONPATH environment variable! + + +Overview of Changes since 1.5.2 +------------------------------- + +For this overview, I have borrowed from the document "What's New in +Python 2.0" by Andrew Kuchling and Moshe Zadka: +http://www.amk.ca/python/2.0/ . + +There are lots of new modules and lots of bugs have been fixed. A +list of all new modules is included below. + +Probably the most pervasive change is the addition of Unicode support. +We've added a new fundamental datatype, the Unicode string, a new +build-in function unicode(), an numerous C APIs to deal with Unicode +and encodings. See the file Misc/unicode.txt for details, or +http://starship.python.net/crew/lemburg/unicode-proposal.txt. + +Two other big changes, related to the Unicode support, are the +addition of string methods and (yet another) new regular expression +engine. + + - String methods mean that you can now say s.lower() etc. instead of + importing the string module and saying string.lower(s) etc. One + peculiarity is that the equivalent of string.join(sequence, + delimiter) is delimiter.join(sequence). Use " ".join(sequence) for + the effect of string.join(sequence); to make this more readable, try + space=" " first. Note that the maxsplit argument defaults in + split() and replace() have changed from 0 to -1. + + - The new regular expression engine, SRE by Fredrik Lundh, is fully + backwards compatible with the old engine, and is in fact invoked + using the same interface (the "re" module). You can explicitly + invoke the old engine by import pre, or the SRE engine by importing + sre. SRE is faster than pre, and supports Unicode (which was the + main reason to put effort in yet another new regular expression + engine -- this is at least the fourth!). + + +Other Changes +------------- + +Other changes that won't break code but are nice to know about: + +Deleting objects is now safe even for deeply nested data structures. + +Long/int unifications: long integers can be used in seek() calls, as +slice indexes. + +String formatting (s % args) has a new formatting option, '%r', which +acts like '%s' but inserts repr(arg) instead of str(arg). (Not yet in +alpha 1.) + +Greg Ward's "distutils" package is included: this will make +installing, building and distributing third party packages much +simpler. + +There's now special syntax that you can use instead of the apply() +function. f(*args, **kwds) is equivalent to apply(f, args, kwds). +You can also use variations f(a1, a2, *args, **kwds) and you can leave +one or the other out: f(*args), f(**kwds). + +The built-ins int() and long() take an optional second argument to +indicate the conversion base -- of course only if the first argument +is a string. This makes string.atoi() and string.atol() obsolete. +(string.atof() was already obsolete). + +When a local variable is known to the compiler but undefined when +used, a new exception UnboundLocalError is raised. This is a class +derived from NameError so code catching NameError should still work. +The purpose is to provide better diagnostics in the following example: + x = 1 + def f(): + print x + x = x+1 +This used to raise a NameError on the print statement, which confused +even experienced Python programmers (especially if there are several +hundreds of lines of code between the reference and the assignment to +x :-). + +You can now override the 'in' operator by defining a __contains__ +method. Note that it has its arguments backwards: x in a causes +a.__contains__(x) to be called. That's why the name isn't __in__. + +The exception AttributeError will have a more friendly error message, +e.g.: <code>'Spam' instance has no attribute 'eggs'</code>. This may +<b>break code</b> that expects the message to be exactly the attribute +name. + + +New Modules in 1.6 +------------------ + +UserString - base class for deriving from the string type. + +distutils - tools for distributing Python modules. + +robotparser - parse a robots.txt file, for writing web spiders. +(Moved from Tools/webchecker/.) + +linuxaudiodev - audio for Linux. + +mmap - treat a file as a memory buffer. (Windows and Unix.) + +sre - regular expressions (fast, supports unicode). Currently, this +code is very rough. Eventually, the re module will be reimplemented +using sre (without changes to the re API). + +filecmp - supersedes the old cmp.py and dircmp.py modules. + +tabnanny - check Python sources for tab-width dependance. (Moved from +Tools/scripts/.) + +urllib2 - new and improved but incompatible version of urllib (still +experimental). + +zipfile - read and write zip archives. + +codecs - support for Unicode encoders/decoders. + +unicodedata - provides access to the Unicode 3.0 database. + +_winreg - Windows registry access. + +encodings - package which provides a large set of standard codecs -- +currently only for the new Unicode support. It has a drop-in extension +mechanism which allows you to add new codecs by simply copying them +into the encodings package directory. Asian codec support will +probably be made available as separate distribution package built upon +this technique and the new distutils package. + + +Changed Modules +--------------- + +readline, ConfigParser, cgi, calendar, posix, readline, xmllib, aifc, +chunk, wave, random, shelve, nntplib - minor enhancements. + +socket, httplib, urllib - optional OpenSSL support (Unix only). + +_tkinter - support for 8.0 up to 8.3. Support for versions older than +8.0 has been dropped. + +string - most of this module is deprecated now that strings have +methods. This no longer uses the built-in strop module, but takes +advantage of the new string methods to provide transparent support for +both Unicode and ordinary strings. + + +Changes on Windows +------------------ + +The installer no longer runs a separate Tcl/Tk installer; instead, it +installs the needed Tcl/Tk files directly in the Python directory. If +you already have a Tcl/Tk installation, this wastes some disk space +(about 4 Megs) but avoids problems with conflincting Tcl/Tk +installations, and makes it much easier for Python to ensure that +Tcl/Tk can find all its files. Note: the alpha installers don't +include the documentation. + +The Windows installer now installs by default in \Python16\ on the +default volume, instead of \Program Files\Python-1.6\. + + +Changed Tools +------------- + +IDLE - complete overhaul. See the <a href="../idle/">IDLE home +page</a> for more information. (Python 1.6 alpha 1 will come with +IDLE 0.6.) + +Tools/i18n/pygettext.py - Python equivalent of xgettext(1). A message +text extraction tool used for internationalizing applications written +in Python. + + +Obsolete Modules +---------------- + +stdwin and everything that uses it. (Get Python 1.5.2 if you need +it. :-) + +soundex. (Skip Montanaro has a version in Python but it won't be +included in the Python release.) + +cmp, cmpcache, dircmp. (Replaced by filecmp.) + +dump. (Use pickle.) + +find. (Easily coded using os.walk().) + +grep. (Not very useful as a library module.) + +packmail. (No longer has any use.) + +poly, zmod. (These were poor examples at best.) + +strop. (No longer needed by the string module.) + +util. (This functionality was long ago built in elsewhere). + +whatsound. (Use sndhdr.) + + +Detailed Changes from 1.6b1 to 1.6 +---------------------------------- + +- Slight changes to the CNRI license. A copyright notice has been +added; the requirement to indicate the nature of modifications now +applies when making a derivative work available "to others" instead of +just "to the public"; the version and date are updated. The new +license has a new handle. + +- Added the Tools/compiler package. This is a project led by Jeremy +Hylton to write the Python bytecode generator in Python. + +- The function math.rint() is removed. + +- In Python.h, "#define _GNU_SOURCE 1" was added. + +- Version 0.9.1 of Greg Ward's distutils is included (instead of +version 0.9). + +- A new version of SRE is included. It is more stable, and more +compatible with the old RE module. Non-matching ranges are indicated +by -1, not None. (The documentation said None, but the PRE +implementation used -1; changing to None would break existing code.) + +- The winreg module has been renamed to _winreg. (There are plans for +a higher-level API called winreg, but this has not yet materialized in +a form that is acceptable to the experts.) + +- The _locale module is enabled by default. + +- Fixed the configuration line for the _curses module. + +- A few crashes have been fixed, notably <file>.writelines() with a +list containing non-string objects would crash, and there were +situations where a lost SyntaxError could dump core. + +- The <list>.extend() method now accepts an arbitrary sequence +argument. + +- If __str__() or __repr__() returns a Unicode object, this is +converted to an 8-bit string. + +- Unicode string comparisons is no longer aware of UTF-16 +encoding peculiarities; it's a straight 16-bit compare. + +- The Windows installer now installs the LICENSE file and no longer +registers the Python DLL version in the registry (this is no longer +needed). It now uses Tcl/Tk 8.3.2. + +- A few portability problems have been fixed, in particular a +compilation error involving socklen_t. + +- The PC configuration is slightly friendlier to non-Microsoft +compilers. + + +====================================================================== + + +====================================== +==> Release 1.5.2 (April 13, 1999) <== +====================================== + +From 1.5.2c1 to 1.5.2 (final) +============================= + +Tue Apr 13 15:44:49 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * PCbuild/python15.wse: Bump version to 1.5.2 (final) + + * PCbuild/python15.dsp: Added shamodule.c + + * PC/config.c: Added sha module! + + * README, Include/patchlevel.h: Prepare for final release. + + * Misc/ACKS: + More (Cameron Laird is honorary; the others are 1.5.2c1 testers). + + * Python/thread_solaris.h: + While I can't really test this thoroughly, Pat Knight and the Solaris + man pages suggest that the proper thing to do is to add THR_NEW_LWP to + the flags on thr_create(), and that there really isn't a downside, so + I'll do that. + + * Misc/ACKS: + Bunch of new names who helped iron out the last wrinkles of 1.5.2. + + * PC/python_nt.rc: + Bump the myusterious M$ version number from 1,5,2,1 to 1,5,2,3. + (I can't even display this on NT, maybe Win/98 can?) + + * Lib/pstats.py: + Fix mysterious references to jprofile that were in the source since + its creation. I'm assuming these were once valid references to "Jim + Roskind's profile"... + + * Lib/Attic/threading_api.py: + Removed; since long subsumed in Doc/lib/libthreading.tex + + * Modules/socketmodule.c: + Put back __osf__ support for gethostbyname_r(); the real bug was that + it was being used even without threads. This of course might be an + all-platform problem so now we only use the _r variant when we are + using threads. + +Mon Apr 12 22:51:20 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Modules/cPickle.c: + Fix accidentally reversed NULL test in load_mark(). Suggested by + Tamito Kajiyama. (This caused a bug only on platforms where malloc(0) + returns NULL.) + + * README: + Add note about popen2 problem on Linux noticed by Pablo Bleyer. + + * README: Add note about -D_REENTRANT for HP-UX 10.20. + + * Modules/Makefile.pre.in: 'clean' target should remove hassignal. + + * PC/Attic/vc40.mak, PC/readme.txt: + Remove all VC++ info (except VC 1.5) from readme.txt; + remove the VC++ 4.0 project file; remove the unused _tkinter extern defs. + + * README: Clarify PC build instructions (point to PCbuild). + + * Modules/zlibmodule.c: Cast added by Jack Jansen (for Mac port). + + * Lib/plat-sunos5/CDIO.py, Lib/plat-linux2/CDROM.py: + Forgot to add this file. CDROM device parameters. + + * Lib/gzip.py: Two different changes. + + 1. Jack Jansen reports that on the Mac, the time may be negative, and + solves this by adding a write32u() function that writes an unsigned + long. + + 2. On 64-bit platforms the CRC comparison fails; I've fixed this by + casting both values to be compared to "unsigned long" i.e. modulo + 0x100000000L. + +Sat Apr 10 18:42:02 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * PC/Attic/_tkinter.def: No longer needed. + + * Misc/ACKS: Correct missed character in Andrew Dalke's name. + + * README: Add DEC Ultrix notes (from Donn Cave's email). + + * configure: The usual + + * configure.in: + Quote a bunch of shell variables used in test, related to long-long. + + * Objects/fileobject.c, Modules/shamodule.c, Modules/regexpr.c: + casts for picky compilers. + + * Modules/socketmodule.c: + 3-arg gethostbyname_r doesn't really work on OSF/1. + + * PC/vc15_w31/_.c, PC/vc15_lib/_.c, Tools/pynche/__init__.py: + Avoid totally empty files. + +Fri Apr 9 14:56:35 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Tools/scripts/fixps.py: Use re instead of regex. + Don't rewrite the file in place. + (Reported by Andy Dustman.) + + * Lib/netrc.py, Lib/shlex.py: Get rid of #! line + +Thu Apr 8 23:13:37 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * PCbuild/python15.wse: Use the Tcl 8.0.5 installer. + Add a variable %_TCL_% that makes it easier to switch to a different version. + + +====================================================================== + + +From 1.5.2b2 to 1.5.2c1 +======================= + +Thu Apr 8 23:13:37 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * PCbuild/python15.wse: + Release 1.5.2c1. Add IDLE and Uninstall to program group. + Don't distribute zlib.dll. Tweak some comments. + + * PCbuild/zlib.dsp: Now using static zlib 1.1.3 + + * Lib/dos-8x3/userdict.py, Lib/dos-8x3/userlist.py, Lib/dos-8x3/test_zli.py, Lib/dos-8x3/test_use.py, Lib/dos-8x3/test_pop.py, Lib/dos-8x3/test_pic.py, Lib/dos-8x3/test_ntp.py, Lib/dos-8x3/test_gzi.py, Lib/dos-8x3/test_fcn.py, Lib/dos-8x3/test_cpi.py, Lib/dos-8x3/test_bsd.py, Lib/dos-8x3/posixfil.py, Lib/dos-8x3/mimetype.py, Lib/dos-8x3/nturl2pa.py, Lib/dos-8x3/compilea.py, Lib/dos-8x3/exceptio.py, Lib/dos-8x3/basehttp.py: + The usual + + * Include/patchlevel.h: Release 1.5.2c1 + + * README: Release 1.5.2c1. + + * Misc/NEWS: News for the 1.5.2c1 release. + + * Lib/test/test_strftime.py: + On Windows, we suddenly find, strftime() may return "" for an + unsupported format string. (I guess this is because the logic for + deciding whether to reallocate the buffer or not has been improved.) + This caused the test code to crash on result[0]. Fix this by assuming + an empty result also means the format is not supported. + + * Demo/tkinter/matt/window-creation-w-location.py: + This demo imported some private code from Matt. Make it cripple along. + + * Lib/lib-tk/Tkinter.py: + Delete an accidentally checked-in feature that actually broke more + than was worth it: when deleting a canvas item, it would try to + automatically delete the bindings for that item. Since there's + nothing that says you can't reuse the tag and still have the bindings, + this is not correct. Also, it broke at least one demo + (Demo/tkinter/matt/rubber-band-box-demo-1.py). + + * Python/thread_wince.h: Win/CE thread support by Mark Hammond. + +Wed Apr 7 20:23:17 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Modules/zlibmodule.c: + Patch by Andrew Kuchling to unflush() (flush() for deflating). + Without this, if inflate() returned Z_BUF_ERROR asking for more output + space, we would report the error; now, we increase the buffer size and + try again, just as for Z_OK. + + * Lib/test/test_gzip.py: Use binary mode for all gzip files we open. + + * Tools/idle/ChangeLog: New change log. + + * Tools/idle/README.txt, Tools/idle/NEWS.txt: New version. + + * Python/pythonrun.c: + Alas, get rid of the Win specific hack to ask the user to press Return + before exiting when an error happened. This didn't work right when + Python is invoked from a daemon. + + * Tools/idle/idlever.py: Version bump awaiting impending new release. + (Not much has changed :-( ) + + * Lib/lib-tk/Tkinter.py: + lower, tkraise/lift hide Misc.lower, Misc.tkraise/lift, + so the preferred name for them is tag_lower, tag_raise + (similar to tag_bind, and similar to the Text widget); + unfortunately can't delete the old ones yet (maybe in 1.6) + + * Python/thread.c, Python/strtod.c, Python/mystrtoul.c, Python/import.c, Python/ceval.c: + Changes by Mark Hammond for Windows CE. Mostly of the form + #ifdef DONT_HAVE_header_H ... #endif around #include <header.h>. + + * Python/bltinmodule.c: + Remove unused variable from complex_from_string() code. + + * Include/patchlevel.h: + Add the possibility of a gamma release (release candidate). + Add '+' to string version number to indicate we're beyond b2 now. + + * Modules/posixmodule.c: Add extern decl for fsync() for SunOS 4.x. + + * Lib/smtplib.py: Changes by Per Cederquist and The Dragon. + + Per writes: + + """ + The application where Signum Support uses smtplib needs to be able to + report good error messages to the user when sending email fails. To + help in diagnosing problems it is useful to be able to report the + entire message sent by the server, not only the SMTP error code of the + offending command. + + A lot of the functions in sendmail.py unfortunately discards the + message, leaving only the code. The enclosed patch fixes that + problem. + + The enclosed patch also introduces a base class for exceptions that + include an SMTP error code and error message, and make the code and + message available on separate attributes, so that surrounding code can + deal with them in whatever way it sees fit. I've also added some + documentation to the exception classes. + + The constructor will now raise an exception if it cannot connect to + the SMTP server. + + The data() method will raise an SMTPDataError if it doesn't receive + the expected 354 code in the middle of the exchange. + + According to section 5.2.10 of RFC 1123 a smtp client must accept "any + text, including no text at all" after the error code. If the response + of a HELO command contains no text self.helo_resp will be set to the + empty string (""). The patch fixes the test in the sendmail() method + so that helo_resp is tested against None; if it has the empty string + as value the sendmail() method would invoke the helo() method again. + + The code no longer accepts a -1 reply from the ehlo() method in + sendmail(). + + [Text about removing SMTPRecipientsRefused deleted --GvR] + """ + + and also: + + """ + smtplib.py appends an extra blank line to the outgoing mail if the + `msg' argument to the sendmail method already contains a trailing + newline. This patch should fix the problem. + """ + + The Dragon writes: + + """ + Mostly I just re-added the SMTPRecipientsRefused exception + (the exeption object now has the appropriate info in it ) [Per had + removed this in his patch --GvR] and tweaked the behavior of the + sendmail method whence it throws the newly added SMTPHeloException (it + was closing the connection, which it shouldn't. whatever catches the + exception should do that. ) + + I pondered the change of the return values to tuples all around, + and after some thinking I decided that regularizing the return values was + too much of the Right Thing (tm) to not do. + + My one concern is that code expecting an integer & getting a tuple + may fail silently. + + (i.e. if it's doing : + + x.somemethod() >= 400: + expecting an integer, the expression will always be true if it gets a + tuple instead. ) + + However, most smtplib code I've seen only really uses the + sendmail() method, so this wouldn't bother it. Usually code I've seen + that calls the other methods usually only calls helo() and ehlo() for + doing ESMTP, a feature which was not in the smtplib included with 1.5.1, + and thus I would think not much code uses it yet. + """ + +Tue Apr 6 19:38:18 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/test/test_ntpath.py: + Fix the tests now that splitdrive() no longer treats UNC paths special. + (Some tests converted to splitunc() tests.) + + * Lib/ntpath.py: + Withdraw the UNC support from splitdrive(). Instead, a new function + splitunc() parses UNC paths. The contributor of the UNC parsing in + splitdrive() doesn't like it, but I haven't heard a good reason to + keep it, and it causes some problems. (I think there's a + philosophical problem -- to me, the split*() functions are purely + syntactical, and the fact that \\foo is not a valid path doesn't mean + that it shouldn't be considered an absolute path.) + + Also (quite separately, but strangely related to the philosophical + issue above) fix abspath() so that if win32api exists, it doesn't fail + when the path doesn't actually exist -- if GetFullPathName() fails, + fall back on the old strategy (join with getcwd() if neccessary, and + then use normpath()). + + * configure.in, configure, config.h.in, acconfig.h: + For BeOS PowerPC. Chris Herborth. + +Mon Apr 5 21:54:14 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Modules/timemodule.c: + Jonathan Giddy notes, and Chris Lawrence agrees, that some comments on + #else/#endif are wrong, and that #if HAVE_TM_ZONE should be #ifdef. + + * Misc/ACKS: + Bunch of new contributors, including 9 who contributed to the Docs, + reported by Fred. + +Mon Apr 5 18:37:59 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Lib/gzip.py: + Oops, missed mode parameter to open(). + + * Lib/gzip.py: + Made the default mode 'rb' instead of 'r', for better cross-platform + support. (Based on comment on the documentation by Bernhard Reiter + <bernhard@csd.uwm.edu>). + +Fri Apr 2 22:18:25 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Tools/scripts/dutree.py: + For reasons I dare not explain, this script should always execute + main() when imported (in other words, it is not usable as a module). + +Thu Apr 1 15:32:30 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/test/test_cpickle.py: Jonathan Giddy write: + + In test_cpickle.py, the module os got imported, but the line to remove + the temp file has gone missing. + +Tue Mar 30 20:17:31 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/BaseHTTPServer.py: Per Cederqvist writes: + + If you send something like "PUT / HTTP/1.0" to something derived from + BaseHTTPServer that doesn't define do_PUT, you will get a response + that begins like this: + + HTTP/1.0 501 Unsupported method ('do_PUT') + Server: SimpleHTTP/0.3 Python/1.5 + Date: Tue, 30 Mar 1999 18:53:53 GMT + + The server should complain about 'PUT' instead of 'do_PUT'. This + patch should fix the problem. + +Mon Mar 29 20:33:21 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/smtplib.py: Patch by Per Cederqvist, who writes: + + """ + - It needlessly used the makefile() method for each response that is + read from the SMTP server. + + - If the remote SMTP server closes the connection unexpectedly the + code raised an IndexError. It now raises an SMTPServerDisconnected + exception instead. + + - The code now checks that all lines in a multiline response actually + contains an error code. + """ + + The Dragon approves. + +Mon Mar 29 20:25:40 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Lib/compileall.py: + When run as a script, report failures in the exit code as well. + Patch largely based on changes by Andrew Dalke, as discussed in the + distutils-sig. + +Mon Mar 29 20:23:41 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/urllib.py: + Hack so that if a 302 or 301 redirect contains a relative URL, the + right thing "just happens" (basejoin() with old URL). + + * Modules/cPickle.c: + Protection against picling to/from closed (real) file. + The problem was reported by Moshe Zadka. + + * Lib/test/test_cpickle.py: + Test protection against picling to/from closed (real) file. + + * Modules/timemodule.c: Chris Lawrence writes: + + """ + The GNU folks, in their infinite wisdom, have decided not to implement + altzone in libc6; this would not be horrible, except that timezone + (which is implemented) includes the current DST setting (i.e. timezone + for Central is 18000 in summer and 21600 in winter). So Python's + timezone and altzone variables aren't set correctly during DST. + + Here's a patch relative to 1.5.2b2 that (a) makes timezone and altzone + show the "right" thing on Linux (by using the tm_gmtoff stuff + available in BSD, which is how the GLIBC manual claims things should + be done) and (b) should cope with the southern hemisphere. In pursuit + of (b), I also took the liberty of renaming the "summer" and "winter" + variables to "july" and "jan". This patch should also make certain + time calculations on Linux actually work right (like the tz-aware + functions in the rfc822 module). + + (It's hard to find DST that's currently being used in the southern + hemisphere; I tested using Africa/Windhoek.) + """ + + * Lib/test/output/test_gzip: + Jonathan Giddy discovered this file was missing. + + * Modules/shamodule.c: + Avoid warnings from AIX compiler. Reported by Vladimir (AIX is my + middlename) Marangozov, patch coded by Greg Stein. + + * Tools/idle/ScriptBinding.py, Tools/idle/PyShell.py: + At Tim Peters' recommendation, add a dummy flush() method to PseudoFile. + +Sun Mar 28 17:55:32 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Tools/scripts/ndiff.py: Tim Peters writes: + + I should have waited overnight <wink/sigh>. Nothing wrong with the one I + sent, but I couldn't resist going on to add new -r1 / -r2 cmdline options + for recreating the original files from ndiff's output. That's attached, if + you're game! Us Windows guys don't usually have a sed sitting around + <wink>. + +Sat Mar 27 13:34:01 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Tools/scripts/ndiff.py: Tim Peters writes: + + Attached is a cleaned-up version of ndiff (added useful module + docstring, now echo'ed in case of cmd line mistake); added -q option + to suppress initial file identification lines; + other minor cleanups, + & a slightly faster match engine. + +Fri Mar 26 22:36:00 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Tools/scripts/dutree.py: + During display, if EPIPE is raised, it's probably because a pager was + killed. Discard the error in that case, but propogate it otherwise. + +Fri Mar 26 16:20:45 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/test/output/test_userlist, Lib/test/test_userlist.py: + Test suite for UserList. + + * Lib/UserList.py: Use isinstance() where appropriate. + Reformatted with 4-space indent. + +Fri Mar 26 16:11:40 1999 Barry Warsaw <bwarsaw@eric.cnri.reston.va.us> + + * Tools/pynche/PyncheWidget.py: + Helpwin.__init__(): The text widget should get focus. + + * Tools/pynche/pyColorChooser.py: + Removed unnecessary import `from PyncheWidget import PyncheWidget' + +Fri Mar 26 15:32:05 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/test/output/test_userdict, Lib/test/test_userdict.py: + Test suite for UserDict + + * Lib/UserDict.py: Improved a bunch of things. + The constructor now takes an optional dictionary. + Use isinstance() where appropriate. + +Thu Mar 25 22:38:49 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/test/output/test_pickle, Lib/test/output/test_cpickle, Lib/test/test_pickle.py, Lib/test/test_cpickle.py: + Basic regr tests for pickle/cPickle + + * Lib/pickle.py: + Don't use "exec" in find_class(). It's slow, unnecessary, and (as AMK + points out) it doesn't work in JPython Applets. + +Thu Mar 25 21:50:27 1999 Andrew Kuchling <akuchlin@eric.cnri.reston.va.us> + + * Lib/test/test_gzip.py: + Added a simple test suite for gzip. It simply opens a temp file, + writes a chunk of compressed data, closes it, writes another chunk, and + reads the contents back to verify that they are the same. + + * Lib/gzip.py: + Based on a suggestion from bruce@hams.com, make a trivial change to + allow using the 'a' flag as a mode for opening a GzipFile. gzip + files, surprisingly enough, can be concatenated and then decompressed; + the effect is to concatenate the two chunks of data. + + If we support it on writing, it should also be supported on reading. + This *wasn't* trivial, and required rearranging the code in the + reading path, particularly the _read() method. + + Raise IOError instead of RuntimeError in two cases, 'Not a gzipped file' + and 'Unknown compression method' + +Thu Mar 25 21:25:01 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/test/test_b1.py: + Add tests for float() and complex() with string args (Nick/Stephanie + Lockwood). + +Thu Mar 25 21:21:08 1999 Andrew Kuchling <akuchlin@eric.cnri.reston.va.us> + + * Modules/zlibmodule.c: + Add an .unused_data attribute to decompressor objects. If .unused_data + is not an empty string, this means that you have arrived at the + end of the stream of compressed data, and the contents of .unused_data are + whatever follows the compressed stream. + +Thu Mar 25 21:16:07 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Python/bltinmodule.c: + Patch by Nick and Stephanie Lockwood to implement complex() with a string + argument. This closes TODO item 2.19. + +Wed Mar 24 19:09:00 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Tools/webchecker/wcnew.py: Added Samuel Bayer's new webchecker. + Unfortunately his code breaks wcgui.py in a way that's not easy + to fix. I expect that this is a temporary situation -- + eventually Sam's changes will be merged back in. + (The changes add a -t option to specify exceptions to the -x + option, and explicit checking for #foo style fragment ids.) + + * Objects/dictobject.c: + Vladimir Marangozov contributed updated comments. + + * Objects/bufferobject.c: Folded long lines. + + * Lib/test/output/test_sha, Lib/test/test_sha.py: + Added Jeremy's test code for the sha module. + + * Modules/shamodule.c, Modules/Setup.in: + Added Greg Stein and Andrew Kuchling's sha module. + Fix comments about zlib version and URL. + + * Lib/test/test_bsddb.py: Remove the temp file when we're done. + + * Include/pythread.h: Conform to standard boilerplate. + + * configure.in, configure, BeOS/linkmodule, BeOS/ar-fake: + Chris Herborth: the new compiler in R4.1 needs some new options to work... + + * Modules/socketmodule.c: + Implement two suggestions by Jonathan Giddy: (1) in AIX, clear the + data struct before calling gethostby{name,addr}_r(); (2) ignore the + 3/5/6 args determinations made by the configure script and switch on + platform identifiers instead: + + AIX, OSF have 3 args + Sun, SGI have 5 args + Linux has 6 args + + On all other platforms, undef HAVE_GETHOSTBYNAME_R altogether. + + * Modules/socketmodule.c: + Vladimir Marangozov implements the AIX 3-arg gethostbyname_r code. + + * Lib/mailbox.py: + Add readlines() to _Subfile class. Not clear who would need it, but + Chris Lawrence sent me a broken version; this one is a tad simpler and + more conforming to the standard. + +Tue Mar 23 23:05:34 1999 Jeremy Hylton <jhylton@eric.cnri.reston.va.us> + + * Lib/gzip.py: use struct instead of bit-manipulate in Python + +Tue Mar 23 19:00:55 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Modules/Makefile.pre.in: + Add $(EXE) to various occurrences of python so it will work on Cygwin + with egcs (after setting EXE=.exe). Patch by Norman Vine. + + * configure, configure.in: + Ack! It never defined HAVE_GETHOSTBYNAME_R so that code was never tested! + +Mon Mar 22 22:25:39 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Include/thread.h: + Adding thread.h -- unused but for b/w compatibility. + As requested by Bill Janssen. + + * configure.in, configure: + Add code to test for all sorts of gethostbyname_r variants, + donated by David Arnold. + + * config.h.in, acconfig.h: + Add symbols for gethostbyname_r variants (sigh). + + * Modules/socketmodule.c: Clean up pass for the previous patches. + + - Use HAVE_GETHOSTBYNAME_R_6_ARG instead of testing for Linux and + glibc2. + + - If gethostbyname takes 3 args, undefine HAVE_GETHOSTBYNAME_R -- + don't know what code should be used. + + - New symbol USE_GETHOSTBYNAME_LOCK defined iff the lock should be used. + + - Modify the gethostbyaddr() code to also hold on to the lock until + after it is safe to release, overlapping with the Python lock. + + (Note: I think that it could in theory be possible that Python code + executed while gethostbyname_lock is held could attempt to reacquire + the lock -- e.g. in a signal handler or destructor. I will simply say + "don't do that then.") + + * Modules/socketmodule.c: Jonathan Giddy writes: + + Here's a patch to fix the race condition, which wasn't fixed by Rob's + patch. It holds the gethostbyname lock until the results are copied out, + which means that this lock and the Python global lock are held at the same + time. This shouldn't be a problem as long as the gethostbyname lock is + always acquired when the global lock is not held. + +Mon Mar 22 19:25:30 1999 Andrew Kuchling <akuchlin@eric.cnri.reston.va.us> + + * Modules/zlibmodule.c: + Fixed the flush() method of compression objects; the test for + the end of loop was incorrect, and failed when the flushmode != Z_FINISH. + Logic cleaned up and commented. + + * Lib/test/test_zlib.py: + Added simple test for the flush() method of compression objects, trying the + different flush values Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH. + +Mon Mar 22 15:28:08 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/shlex.py: + Bug reported by Tobias Thelen: missing "self." in assignment target. + +Fri Mar 19 21:50:11 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Modules/arraymodule.c: + Use an unsigned cast to avoid a warning in VC++. + + * Lib/dospath.py, Lib/ntpath.py: + New code for split() by Tim Peters, behaves more like posixpath.split(). + + * Objects/floatobject.c: + Fix a problem with Vladimir's PyFloat_Fini code: clear the free list; if + a block cannot be freed, add its free items back to the free list. + This is necessary to avoid leaking when Python is reinitialized later. + + * Objects/intobject.c: + Fix a problem with Vladimir's PyInt_Fini code: clear the free list; if + a block cannot be freed, add its free items back to the free list, and + add its valid ints back to the small_ints array if they are in range. + This is necessary to avoid leaking when Python is reinitialized later. + + * Lib/types.py: + Added BufferType, the type returned by the new builtin buffer(). Greg Stein. + + * Python/bltinmodule.c: + New builtin buffer() creates a derived read-only buffer from any + object that supports the buffer interface (e.g. strings, arrays). + + * Objects/bufferobject.c: + Added check for negative offset for PyBuffer_FromObject and check for + negative size for PyBuffer_FromMemory. Greg Stein. + +Thu Mar 18 15:10:44 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/urlparse.py: Sjoerd Mullender writes: + + If a filename on Windows starts with \\, it is converted to a URL + which starts with ////. If this URL is passed to urlparse.urlparse + you get a path that starts with // (and an empty netloc). If you pass + the result back to urlparse.urlunparse, you get a URL that starts with + //, which is parsed differently by urlparse.urlparse. The fix is to + add the (empty) netloc with accompanying slashes if the path in + urlunparse starts with //. Do this for all schemes that use a netloc. + + * Lib/nturl2path.py: Sjoerd Mullender writes: + + Pathnames of files on other hosts in the same domain + (\\host\path\to\file) are not translated correctly to URLs and back. + The URL should be something like file:////host/path/to/file. + Note that a combination of drive letter and remote host is not + possible. + +Wed Mar 17 22:30:10 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/urlparse.py: + Delete non-standard-conforming code in urljoin() that would use the + netloc from the base url as the default netloc for the resulting url + even if the schemes differ. + + Once upon a time, when the web was wild, this was a valuable hack + because some people had a URL referencing an ftp server colocated with + an http server without having the host in the ftp URL (so they could + replicate it or change the hostname easily). + + More recently, after the file: scheme got added back to the list of + schemes that accept a netloc, it turns out that this caused weirdness + when joining an http: URL with a file: URL -- the resulting file: URL + would always inherit the host from the http: URL because the file: + scheme supports a netloc but in practice never has one. + + There are two reasons to get rid of the old, once-valuable hack, + instead of removing the file: scheme from the uses_netloc list. One, + the RFC says that file: uses the netloc syntax, and does not endorse + the old hack. Two, neither netscape 4.5 nor IE 4.0 support the old + hack. + + * Include/ceval.h, Include/abstract.h: + Add DLL level b/w compat for PySequence_In and PyEval_CallObject + +Tue Mar 16 21:54:50 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/lib-tk/Tkinter.py: Bug reported by Jim Robinson: + + An attempt to execute grid_slaves with arguments (0,0) results in + *all* of the slaves being returned, not just the slave associated with + row 0, column 0. This is because the test for arguments in the method + does not test to see if row (and column) does not equal None, but + rather just whether is evaluates to non-false. A value of 0 fails + this test. + +Tue Mar 16 14:17:48 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Modules/cmathmodule.c: + Docstring fix: acosh() returns the hyperbolic arccosine, not the + hyperbolic cosine. Problem report via David Ascher by one of his + students. + +Mon Mar 15 21:40:59 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * configure.in: + Should test for gethost*by*name_r, not for gethostname_r (which + doesn't exist and doesn't make sense). + + * Modules/socketmodule.c: + Patch by Rob Riggs for Linux -- glibc2 has a different argument + converntion for gethostbyname_r() etc. than Solaris! + + * Python/thread_pthread.h: Rob Riggs wrote: + + """ + Spec says that on success pthread_create returns 0. It does not say + that an error code will be < 0. Linux glibc2 pthread_create() returns + ENOMEM (12) when one exceed process limits. (It looks like it should + return EAGAIN, but that's another story.) + + For reference, see: + http://www.opengroup.org/onlinepubs/7908799/xsh/pthread_create.html + """ + + [I have a feeling that similar bugs were fixed before; perhaps someone + could check that all error checks no check for != 0?] + + * Tools/bgen/bgen/bgenObjectDefinition.py: + New mixin class that defines cmp and hash that use + the ob_itself pointer. This allows (when using the mixin) + different Python objects pointing to the same C object and + behaving well as dictionary keys. + + Or so sez Jack Jansen... + + * Lib/urllib.py: Yet another patch by Sjoerd Mullender: + + Don't convert URLs to URLs using pathname2url. + +Fri Mar 12 22:15:43 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/cmd.py: Patch by Michael Scharf. He writes: + + The module cmd requires for each do_xxx command a help_xxx + function. I think this is a little old fashioned. + + Here is a patch: use the docstring as help if no help_xxx + function can be found. + + [I'm tempted to rip out all the help_* functions from pdb, but I'll + resist it. Any takers? --Guido] + + * Tools/freeze/freeze.py: Bug submitted by Wayne Knowles, who writes: + + Under Windows, python freeze.py -o hello hello.py + creates all the correct files in the hello subdirectory, but the + Makefile has the directory prefix in it for frozen_extensions.c + nmake fails because it tries to locate hello/frozen_extensions.c + + (His fix adds a call to os.path.basename() in the appropriate place.) + + * Objects/floatobject.c, Objects/intobject.c: + Vladimir has restructured his code somewhat so that the blocks are now + represented by an explicit structure. (There are still too many casts + in the code, but that may be unavoidable.) + + Also added code so that with -vv it is very chatty about what it does. + + * Demo/zlib/zlibdemo.py, Demo/zlib/minigzip.py: + Change #! line to modern usage; also chmod +x + + * Demo/pdist/rrcs, Demo/pdist/rcvs, Demo/pdist/rcsbump: + Change #! line to modern usage + + * Lib/nturl2path.py, Lib/urllib.py: From: Sjoerd Mullender + + The filename to URL conversion didn't properly quote special + characters. + The URL to filename didn't properly unquote special chatacters. + + * Objects/floatobject.c: + OK, try again. Vladimir gave me a fix for the alignment bus error, + so here's his patch again. This time it works (at least on Solaris, + Linux and Irix). + +Thu Mar 11 23:21:23 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Tools/idle/PathBrowser.py: + Don't crash when sys.path contains an empty string. + + * Tools/idle/PathBrowser.py: + - Don't crash in the case where a superclass is a string instead of a + pyclbr.Class object; this can happen when the superclass is + unrecognizable (to pyclbr), e.g. when module renaming is used. + + - Show a watch cursor when calling pyclbr (since it may take a while + recursively parsing imported modules!). + +Thu Mar 11 16:04:04 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Lib/mimetypes.py: + Added .rdf and .xsl as application/xml types. (.rdf is for the + Resource Description Framework, a metadata encoding, and .xsl is for + the Extensible Stylesheet Language.) + +Thu Mar 11 13:26:23 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/test/output/test_popen2, Lib/test/test_popen2.py: + Test for popen2 module, by Chris Tismer. + + * Objects/floatobject.c: + Alas, Vladimir's patch caused a bus error (probably double + alignment?), and I didn't test it. Withdrawing it for now. + +Wed Mar 10 22:55:47 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Objects/floatobject.c: + Patch by Vladimir Marangoz to allow freeing of the allocated blocks of + floats on finalization. + + * Objects/intobject.c: + Patch by Vladimir Marangoz to allow freeing of the allocated blocks of + integers on finalization. + + * Tools/idle/EditorWindow.py, Tools/idle/Bindings.py: + Add PathBrowser to File module + + * Tools/idle/PathBrowser.py: + "Path browser" - 4 scrolled lists displaying: + directories on sys.path + modules in selected directory + classes in selected module + methods of selected class + + Sinlge clicking in a directory, module or class item updates the next + column with info about the selected item. Double clicking in a + module, class or method item opens the file (and selects the clicked + item if it is a class or method). + + I guess eventually I should be using a tree widget for this, but the + ones I've seen don't work well enough, so for now I use the old + Smalltalk or NeXT style multi-column hierarchical browser. + + * Tools/idle/MultiScrolledLists.py: + New utility: multiple scrolled lists in parallel + + * Tools/idle/ScrolledList.py: - White background. + - Display "(None)" (or text of your choosing) when empty. + - Don't set the focus. + +Tue Mar 9 19:31:21 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/urllib.py: + open_http also had the 'data is None' test backwards. don't call with the + extra argument if data is None. + + * Demo/embed/demo.c: + Call Py_SetProgramName() instead of redefining getprogramname(), + reflecting changes in the runtime around 1.5 or earlier. + + * Python/ceval.c: + Always test for an error return (usually NULL or -1) without setting + an exception. + + * Modules/timemodule.c: Patch by Chris Herborth for BeOS code. + He writes: + + I had an off-by-1000 error in floatsleep(), + and the problem with time.clock() is that it's not implemented properly + on QNX... ANSI says it's supposed to return _CPU_ time used by the + process, but on QNX it returns the amount of real time used... so I was + confused. + + * Tools/bgen/bgen/macsupport.py: Small change by Jack Jansen. + Test for self.returntype behaving like OSErr rather than being it. + +Thu Feb 25 16:14:58 1999 Jeremy Hylton <jhylton@eric.cnri.reston.va.us> + + * Lib/urllib.py: + http_error had the 'data is None' test backwards. don't call with the + extra argument if data is None. + + * Lib/urllib.py: change indentation from 8 spaces to 4 spaces + + * Lib/urllib.py: pleasing the tabnanny + +Thu Feb 25 14:26:02 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Lib/colorsys.py: + Oops, one more "x, y, z" to convert... + + * Lib/colorsys.py: + Adjusted comment at the top to be less confusing, following Fredrik + Lundh's example. + + Converted comment to docstring. + +Wed Feb 24 18:49:15 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Lib/toaiff.py: + Use sndhdr instead of the obsolete whatsound module. + +Wed Feb 24 18:42:38 1999 Jeremy Hylton <jhylton@eric.cnri.reston.va.us> + + * Lib/urllib.py: + When performing a POST request, i.e. when the second argument to + urlopen is used to specify form data, make sure the second argument is + threaded through all of the http_error_NNN calls. This allows error + handlers like the redirect and authorization handlers to properly + re-start the connection. + +Wed Feb 24 16:25:17 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/mhlib.py: Patch by Lars Wirzenius: + + o the initial comment is wrong: creating messages is already + implemented + + o Message.getbodytext: if the mail or it's part contains an + empty content-transfer-encoding header, the code used to + break; the change below treats an empty encoding value the same + as the other types that do not need decoding + + o SubMessage.getbodytext was missing the decode argument; the + change below adds it; I also made it unconditionally return + the raw text if decoding was not desired, because my own + routines needed that (and it was easier than rewriting my + own routines ;-) + +Wed Feb 24 00:35:43 1999 Barry Warsaw <bwarsaw@eric.cnri.reston.va.us> + + * Python/bltinmodule.c (initerrors): + Make sure that the exception tuples ("base-classes" when + string-based exceptions are used) reflect the real class hierarchy, + i.e. that SystemExit derives from Exception not StandardError. + + * Lib/exceptions.py: + Document the correct class hierarchy for SystemExit. It is not an + error and so it derives from Exception and not SystemError. The + docstring was incorrect but the implementation was fine. + +Tue Feb 23 23:07:51 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/shutil.py: + Add import sys, needed by reference to sys.exc_info() in rmtree(). + Discovered by Mitch Chapman. + + * config.h.in: + Now that we don't have AC_CHECK_LIB(m, pow), the HAVE_LIBM symbol + disappears. It wasn't used anywhere anyway... + + * Modules/arraymodule.c: + Carefully check for overflow when allocating the memory for fromfile + -- someone tried to pass in sys.maxint and got bitten by the bogus + calculations. + + * configure.in: + Get rid of AC_CHECK_LIB(m, pow) since this is taken care of later with + LIBM (from --with-libm=...); this actually broke the customizability + offered by the latter option. Thanks go to Clay Spence for reporting + this. + + * Lib/test/test_dl.py: + 1. Print the error message (carefully) when a dl.open() fails in verbose mode. + 2. When no test case worked, raise ImportError instead of failing. + + * Python/bltinmodule.c: + Patch by Tim Peters to improve the range checks for range() and + xrange(), especially for platforms where int and long are different + sizes (so sys.maxint isn't actually the theoretical limit for the + length of a list, but the largest C int is -- sys.maxint is the + largest Python int, which is actually a C long). + + * Makefile.in: + 1. Augment the DG/UX rule so it doesn't break the BeOS build. + 2. Add $(EXE) to various occurrences of python so it will work on + Cygwin with egcs (after setting EXE=.exe). These patches by + Norman Vine. + + * Lib/posixfile.py: + According to Jeffrey Honig, bsd/os 2.0 - 4.0 should be added to the + list (of bsd variants that have a different lock structure). + + * Lib/test/test_fcntl.py: + According to Jeffrey Honig, bsd/os 4.0 should be added to the list. + + * Modules/timemodule.c: + Patch by Tadayoshi Funaba (with some changes) to be smarter about + guessing what happened when strftime() returns 0. Is it buffer + overflow or was the result simply 0 bytes long? (This happens for an + empty format string, or when the format string is a single %Z and the + timezone is unknown.) if the buffer is at least 256 times as long as + the format, assume the latter. + +Mon Feb 22 19:01:42 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/urllib.py: + As Des Barry points out, we need to call pathname2url(file) in two + calls to addinfourl() in open_file(). + + * Modules/Setup.in: Document *static* -- in two places! + + * Modules/timemodule.c: + We don't support leap seconds, so the seconds field of a time 9-tuple + should be in the range [0-59]. Noted by Tadayoshi Funaba. + + * Modules/stropmodule.c: + In atoi(), don't use isxdigit() to test whether the last character + converted was a "digit" -- use isalnum(). This test is there only to + guard against "+" or "-" being interpreted as a valid int literal. + Reported by Takahiro Nakayama. + + * Lib/os.py: + As Finn Bock points out, _P_WAIT etc. don't have a leading underscore + so they don't need to be treated specially here. + +Mon Feb 22 15:38:58 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Misc/NEWS: + Typo: "apparentlt" --> "apparently" + +Mon Feb 22 15:38:46 1999 Guido van Rossum <guido@eric.cnri.reston.va.us> + + * Lib/urlparse.py: Steve Clift pointed out that 'file' allows a netloc. + + * Modules/posixmodule.c: + The docstring for ttyname(..) claims a second "mode" argument. The + actual code does not allow such an argument. (Finn Bock.) + + * Lib/lib-old/poly.py: + Dang. Even though this is obsolete code, somebody found a bug, and I + fix it. Oh well. + +Thu Feb 18 20:51:50 1999 Fred Drake <fdrake@eric.cnri.reston.va.us> + + * Lib/pyclbr.py: + Bow to font-lock at the end of the docstring, since it throws stuff + off. + + Make sure the path paramter to readmodule() is a list before adding it + with sys.path, or the addition could fail. + + +====================================================================== + + +From 1.5.2b1 to 1.5.2b2 +======================= + +General +------- + +- Many memory leaks fixed. + +- Many small bugs fixed. + +- Command line option -OO (or -O -O) suppresses inclusion of doc +strings in resulting bytecode. + +Windows-specific changes +------------------------ + +- New built-in module winsound provides an interface to the Win32 +PlaySound() call. + +- Re-enable the audioop module in the config.c file. + +- On Windows, support spawnv() and associated P_* symbols. + +- Fixed the conversion of times() return values on Windows. + +- Removed freeze from the installer -- it doesn't work without the +source tree. (See FAQ 8.11.) + +- On Windows 95/98, the Tkinter module now is smart enough to find +Tcl/Tk even when the PATH environment variable hasn't been set -- when +the import of _tkinter fails, it searches in a standard locations, +patches os.environ["PATH"], and tries again. When it still fails, a +clearer error message is produced. This should avoid most +installation problems with Tkinter use (e.g. in IDLE). + +- The -i option doesn't make any calls to set[v]buf() for stdin -- +this apparently screwed up _kbhit() and the _tkinter main loop. + +- The ntpath module (and hence, os.path on Windows) now parses out UNC +paths (e.g. \\host\mountpoint\dir\file) as "drive letters", so that +splitdrive() will \\host\mountpoint as the drive and \dir\file as the +path. ** EXPERIMENTAL ** + +- Added a hack to the exit code so that if (1) the exit status is +nonzero and (2) we think we have our own DOS box (i.e. we're not +started from a command line shell), we print a message and wait for +the user to hit a key before the DOS box is closed. + +- Updated the installer to WISE 5.0g. Added a dialog warning about +the imminent Tcl installation. Added a dialog to specify the program +group name in the start menu. Upgraded the Tcl installer to Tcl +8.0.4. + +Changes to intrinsics +--------------------- + +- The repr() or str() of a module object now shows the __file__ +attribute (i.e., the file which it was loaded), or the string +"(built-in)" if there is no __file__ attribute. + +- The range() function now avoids overflow during its calculations (if +at all possible). + +- New info string sys.hexversion, which is an integer encoding the +version in hexadecimal. In other words, hex(sys.hexversion) == +0x010502b2 for Python 1.5.2b2. + +New or improved ports +--------------------- + +- Support for Nextstep descendants (future Mac systems). + +- Improved BeOS support. + +- Support dynamic loading of shared libraries on NetBSD platforms that +use ELF (i.e., MIPS and Alpha systems). + +Configuration/build changes +--------------------------- + +- The Lib/test directory is no longer included in the default module +search path (sys.path) -- "test" has been a package ever since 1.5. + +- Now using autoconf 2.13. + +New library modules +------------------- + +- New library modules asyncore and asynchat: these form Sam Rushing's +famous asynchronous socket library. Sam has gracefully allowed me to +incorporate these in the standard Python library. + +- New module statvfs contains indexing constants for [f]statvfs() +return tuple. + +Changes to the library +---------------------- + +- The wave module (platform-independent support for Windows sound +files) has been fixed to actually make it work. + +- The sunau module (platform-independent support for Sun/NeXT sound +files) has been fixed to work across platforms. Also, a weird +encoding bug in the header of the audio test data file has been +corrected. + +- Fix a bug in the urllib module that occasionally tripped up +webchecker and other ftp retrieves. + +- ConfigParser's get() method now accepts an optional keyword argument +(vars) that is substituted on top of the defaults that were setup in +__init__. You can now also have recusive references in your +configuration file. + +- Some improvements to the Queue module, including a put_nowait() +module and an optional "block" second argument, to get() and put(), +defaulting to 1. + +- The updated xmllib module is once again compatible with the version +present in Python 1.5.1 (this was accidentally broken in 1.5.2b1). + +- The bdb module (base class for the debugger) now supports +canonicalizing pathnames used in breakpoints. The derived class must +override the new canonical() method for this to work. Also changed +clear_break() to the backwards compatible old signature, and added +clear_bpbynumber() for the new functionality. + +- In sgmllib (and hence htmllib), recognize attributes even if they +don't have space in front of them. I.e. '<a +name="foo"href="bar.html">' will now have two attributes recognized. + +- In the debugger (pdb), change clear syntax to support three +alternatives: clear; clear file:line; clear bpno bpno ... + +- The os.path module now pretends to be a submodule within the os +"package", so you can do things like "from os.path import exists". + +- The standard exceptions now have doc strings. + +- In the smtplib module, exceptions are now classes. Also avoid +inserting a non-standard space after "TO" in rcpt() command. + +- The rfc822 module's getaddrlist() method now uses all occurrences of +the specified header instead of just the first. Some other bugfixes +too (to handle more weird addresses found in a very large test set, +and to avoid crashes on certain invalid dates), and a small test +module has been added. + +- Fixed bug in urlparse in the common-case code for HTTP URLs; it +would lose the query, fragment, and/or parameter information. + +- The sndhdr module no longer supports whatraw() -- it depended on a +rare extenral program. + +- The UserList module/class now supports the extend() method, like +real list objects. + +- The uu module now deals better with trailing garbage generated by +some broke uuencoders. + +- The telnet module now has an my_interact() method which uses threads +instead of select. The interact() method uses this by default on +Windows (where the single-threaded version doesn't work). + +- Add a class to mailbox.py for dealing with qmail directory +mailboxes. The test code was extended to notice these being used as +well. + +Changes to extension modules +---------------------------- + +- Support for the [f]statvfs() system call, where it exists. + +- Fixed some bugs in cPickle where bad input could cause it to dump +core. + +- Fixed cStringIO to make the writelines() function actually work. + +- Added strop.expandtabs() so string.expandtabs() is now much faster. + +- Added fsync() and fdatasync(), if they appear to exist. + +- Support for "long files" (64-bit seek pointers). + +- Fixed a bug in the zlib module's flush() function. + +- Added access() system call. It returns 1 if access granted, 0 if +not. + +- The curses module implements an optional nlines argument to +w.scroll(). (It then calls wscrl(win, nlines) instead of scoll(win).) + +Changes to tools +---------------- + +- Some changes to IDLE; see Tools/idle/NEWS.txt. + +- Latest version of Misc/python-mode.el included. + +Changes to Tkinter +------------------ + +- Avoid tracebacks when an image is deleted after its root has been +destroyed. + +Changes to the Python/C API +--------------------------- + +- When parentheses are used in a PyArg_Parse[Tuple]() call, any +sequence is now accepted, instead of requiring a tuple. This is in +line with the general trend towards accepting arbitrary sequences. + +- Added PyModule_GetFilename(). + +- In PyNumber_Power(), remove unneeded and even harmful test for float +to the negative power (which is already and better done in +floatobject.c). + +- New version identification symbols; read patchlevel.h for info. The +version numbers are now exported by Python.h. + +- Rolled back the API version change -- it's back to 1007! + +- The frozenmain.c function calls PyInitFrozenExtensions(). + +- Added 'N' format character to Py_BuildValue -- like 'O' but doesn't +INCREF. + + +====================================================================== + + +From 1.5.2a2 to 1.5.2b1 +======================= + +Changes to intrinsics +--------------------- + +- New extension NotImplementedError, derived from RuntimeError. Not +used, but recommended use is for "abstract" methods to raise this. + +- The parser will now spit out a warning or error when -t or -tt is +used for parser input coming from a string, too. + +- The code generator now inserts extra SET_LINENO opcodes when +compiling multi-line argument lists. + +- When comparing bound methods, use identity test on the objects, not +equality test. + +New or improved ports +--------------------- + +- Chris Herborth has redone his BeOS port; it now works on PowerPC +(R3/R4) and x86 (R4 only). Threads work too in this port. + +Renaming +-------- + +- Thanks to Chris Herborth, the thread primitives now have proper Py* +names in the source code (they already had those for the linker, +through some smart macros; but the source still had the old, un-Py +names). + +Configuration/build changes +--------------------------- + +- Improved support for FreeBSD/3. + +- Check for pthread_detach instead of pthread_create in libc. + +- The makesetup script now searches EXECINCLUDEPY before INCLUDEPY. + +- Misc/Makefile.pre.in now also looks at Setup.thread and Setup.local. +Otherwise modules such as thread didn't get incorporated in extensions. + +New library modules +------------------- + +- shlex.py by Eric Raymond provides a lexical analyzer class for +simple shell-like syntaxes. + +- netrc.py by Eric Raymond provides a parser for .netrc files. (The +undocumented Netrc class in ftplib.py is now obsolete.) + +- codeop.py is a new module that contains the compile_command() +function that was previously in code.py. This is so that JPython can +provide its own version of this function, while still sharing the +higher-level classes in code.py. + +- turtle.py is a new module for simple turtle graphics. I'm still +working on it; let me know if you use this to teach Python to children +or other novices without prior programming experience. + +Obsoleted library modules +------------------------- + +- poly.py and zmod.py have been moved to Lib/lib-old to emphasize +their status of obsoleteness. They don't do a particularly good job +and don't seem particularly relevant to the Python core. + +New tools +--------- + +- I've added IDLE: my Integrated DeveLopment Environment for Python. +Requires Tcl/Tk (and Tkinter). Works on Windows and Unix (and should +work on Macintosh, but I haven't been able to test it there; it does +depend on new features in 1.5.2 and perhaps even new features in +1.5.2b1, especially the new code module). This is very much a work in +progress. I'd like to hear how people like it compared to PTUI (or +any other IDE they are familiar with). + +- New tools by Barry Warsaw: + + = audiopy: controls the Solaris Audio device + = pynche: The PYthonically Natural Color and Hue Editor + = world: Print mappings between country names and DNS country codes + +New demos +--------- + +- Demo/scripts/beer.py prints the lyrics to an arithmetic drinking +song. + +- Demo/tkinter/guido/optionmenu.py shows how to do an option menu in +Tkinter. (By Fredrik Lundh -- not by me!) + +Changes to the library +---------------------- + +- compileall.py now avoids recompiling .py files that haven't changed; +it adds a -f option to force recompilation. + +- New version of xmllib.py by Sjoerd Mullender (0.2 with latest +patches). + +- nntplib.py: statparse() no longer lowercases the message-id. + +- types.py: use type(__stdin__) for FileType. + +- urllib.py: fix translations for filenames with "funny" characters. +Patch by Sjoerd Mullender. Note that if you subclass one of the +URLopener classes, and you have copied code from the old urllib.py, +your subclass may stop working. A long-term solution is to provide +more methods so that you don't have to copy code. + +- cgi.py: In read_multi, allow a subclass to override the class we +instantiate when we create a recursive instance, by setting the class +variable 'FieldStorageClass' to the desired class. By default, this +is set to None, in which case we use self.__class__ (as before). +Also, a patch by Jim Fulton to pass additional arguments to recursive +calls to the FieldStorage constructor from its read_multi method. + +- UserList.py: In __getslice__, use self.__class__ instead of +UserList. + +- In SimpleHTTPServer.py, the server specified in test() should be +BaseHTTPServer.HTTPServer, in case the request handler should want to +reference the two attributes added by BaseHTTPServer.server_bind. (By +Jeff Rush, for Bobo). Also open the file in binary mode, so serving +images from a Windows box might actually work. + +- In CGIHTTPServer.py, the list of acceptable formats is -split- +on spaces but -joined- on commas, resulting in double commas +in the joined text. (By Jeff Rush.) + +- SocketServer.py, patch by Jeff Bauer: a minor change to declare two +new threaded versions of Unix Server classes, using the ThreadingMixIn +class: ThreadingUnixStreamServer, ThreadingUnixDatagramServer. + +- bdb.py: fix bomb on deleting a temporary breakpoint: there's no +method do_delete(); do_clear() was meant. By Greg Ward. + +- getopt.py: accept a non-list sequence for the long options (request +by Jack Jansen). Because it might be a common mistake to pass a +single string, this situation is treated separately. Also added +docstrings (copied from the library manual) and removed the (now +redundant) module comments. + +- tempfile.py: improvements to avoid security leaks. + +- code.py: moved compile_command() to new module codeop.py. + +- pickle.py: support pickle format 1.3 (binary float added). By Jim +Fulton. Also get rid of the undocumented obsolete Pickler dump_special +method. + +- uu.py: Move 'import sys' to top of module, as noted by Tim Peters. + +- imaplib.py: fix problem with some versions of IMAP4 servers that +choose to mix the case in their CAPABILITIES response. + +- cmp.py: use (f1, f2) as cache key instead of f1 + ' ' + f2. Noted +by Fredrik Lundh. + +Changes to extension modules +---------------------------- + +- More doc strings for several modules were contributed by Chris +Petrilli: math, cmath, fcntl. + +- Fixed a bug in zlibmodule.c that could cause core dumps on +decompression of rarely occurring input. + +- cPickle.c: new version from Jim Fulton, with Open Source copyright +notice. Also, initialize self->safe_constructors early on to prevent +crash in early dealloc. + +- cStringIO.c: new version from Jim Fulton, with Open Source copyright +notice. Also fixed a core dump in cStringIO.c when doing seeks. + +- mpzmodule.c: fix signed character usage in mpz.mpz(stringobjecty). + +- readline.c: Bernard Herzog pointed out that rl_parse_and_bind +modifies its argument string (bad function!), so we make a temporary +copy. + +- sunaudiodev.c: Barry Warsaw added more smarts to get the device and +control pseudo-device, per audio(7I). + +Changes to tools +---------------- + +- New, improved version of Barry Warsaw's Misc/python-mode.el (editing +support for Emacs). + +- tabnanny.py: added a -q ('quiet') option to tabnanny, which causes +only the names of offending files to be printed. + +- freeze: when printing missing modules, also print the module they +were imported from. + +- untabify.py: patch by Detlef Lannert to implement -t option +(set tab size). + +Changes to Tkinter +------------------ + +- grid_bbox(): support new Tk API: grid bbox ?column row? ?column2 +row2? + +- _tkinter.c: RajGopal Srinivasan noted that the latest code (1.5.2a2) +doesn't work when running in a non-threaded environment. He added +some #ifdefs that fix this. + +Changes to the Python/C API +--------------------------- + +- Bumped API version number to 1008 -- enough things have changed! + +- There's a new macro, PyThreadState_GET(), which does the same work +as PyThreadState_Get() without the overhead of a function call (it +also avoids the error check). The two top calling locations of +PyThreadState_Get() have been changed to use this macro. + +- All symbols intended for export from a DLL or shared library are now +marked as such (with the DL_IMPORT() macro) in the header file that +declares them. This was needed for the BeOS port, and should also +make some other ports easier. The PC port no longer needs the file +with exported symbols (PC/python_nt.def). There's also a DL_EXPORT +macro which is only used for init methods in extension modules, and +for Py_Main(). + +Invisible changes to internals +------------------------------ + +- Fixed a bug in new_buffersize() in fileobject.c which could +return a buffer size that was way too large. + +- Use PySys_WriteStderr instead of fprintf in most places. + +- dictobject.c: remove dead code discovered by Vladimir Marangozov. + +- tupleobject.c: make tuples less hungry -- an extra item was +allocated but never used. Tip by Vladimir Marangozov. + +- mymath.h: Metrowerks PRO4 finally fixes the hypot snafu. (Jack +Jansen) + +- import.c: Jim Fulton fixes a reference count bug in +PyEval_GetGlobals. + +- glmodule.c: check in the changed version after running the stubber +again -- this solves the conflict with curses over the 'clear' entry +point much nicer. (Jack Jansen had checked in the changes to cstubs +eons ago, but I never regenrated glmodule.c :-( ) + +- frameobject.c: fix reference count bug in PyFrame_New. Vladimir +Marangozov. + +- stropmodule.c: add a missing DECREF in an error exit. Submitted by +Jonathan Giddy. + + +====================================================================== + + +From 1.5.2a1 to 1.5.2a2 +======================= + +General +------- + +- It is now a syntax error to have a function argument without a +default following one with a default. + +- __file__ is now set to the .py file if it was parsed (it used to +always be the .pyc/.pyo file). + +- Don't exit with a fatal error during initialization when there's a +problem with the exceptions.py module. + +- New environment variable PYTHONOPTIMIZE can be used to set -O. + +- New version of python-mode.el for Emacs. + +Miscellaneous fixed bugs +------------------------ + +- No longer print the (confusing) error message about stack underflow +while compiling. + +- Some threading and locking bugs fixed. + +- When errno is zero, report "Error", not "Success". + +Documentation +------------- + +- Documentation will be released separately. + +- Doc strings added to array and md5 modules by Chris Petrilli. + +Ports and build procedure +------------------------- + +- Stop installing when a move or copy fails. + +- New version of the OS/2 port code by Jeff Rush. + +- The makesetup script handles absolute filenames better. + +- The 'new' module is now enabled by default in the Setup file. + +- I *think* I've solved the problem with the Linux build blowing up +sometimes due to a conflict between sigcheck/intrcheck and +signalmodule. + +Built-in functions +------------------ + +- The second argument to apply() can now be any sequence, not just a +tuple. + +Built-in types +-------------- + +- Lists have a new method: L1.extend(L2) is equivalent to the common +idiom L1[len(L1):] = L2. + +- Better error messages when a sequence is indexed with a non-integer. + +- Bettter error message when calling a non-callable object (include +the type in the message). + +Python services +--------------- + +- New version of cPickle.c fixes some bugs. + +- pickle.py: improved instantiation error handling. + +- code.py: reworked quite a bit. New base class +InteractiveInterpreter and derived class InteractiveConsole. Fixed +several problems in compile_command(). + +- py_compile.py: print error message and continue on syntax errors. +Also fixed an old bug with the fstat code (it was never used). + +- pyclbr.py: support submodules of packages. + +String Services +--------------- + +- StringIO.py: raise the right exception (ValueError) for attempted +I/O on closed StringIO objects. + +- re.py: fixed a bug in subn(), which caused .groups() to fail inside +the replacement function called by sub(). + +- The struct module has a new format 'P': void * in native mode. + +Generic OS Services +------------------- + +- Module time: Y2K robustness. 2-digit year acceptance depends on +value of time.accept2dyear, initialized from env var PYTHONY2K, +default 0. Years 00-68 mean 2000-2068, while 69-99 mean 1969-1999 +(POSIX or X/Open recommendation). + +- os.path: normpath(".//x") should return "x", not "/x". + +- getpass.py: fall back on default_getpass() when sys.stdin.fileno() +doesn't work. + +- tempfile.py: regenerate the template after a fork() call. + +Optional OS Services +-------------------- + +- In the signal module, disable restarting interrupted system calls +when we have siginterrupt(). + +Debugger +-------- + +- No longer set __args__; this feature is no longer supported and can +affect the debugged code. + +- cmd.py, pdb.py and bdb.py have been overhauled by Richard Wolff, who +added aliases and some other useful new features, e.g. much better +breakpoint support: temporary breakpoint, disabled breakpoints, +breakpoints with ignore counts, and conditions; breakpoints can be set +on a file before it is loaded. + +Profiler +-------- + +- Changes so that JPython can use it. Also fix the calibration code +so it actually works again +. +Internet Protocols and Support +------------------------------ + +- imaplib.py: new version from Piers Lauder. + +- smtplib.py: change sendmail() method to accept a single string or a +list or strings as the destination (commom newbie mistake). + +- poplib.py: LIST with a msg argument fixed. + +- urlparse.py: some optimizations for common case (http). + +- urllib.py: support content-length in info() for ftp protocol; +support for a progress meter through a third argument to +urlretrieve(); commented out gopher test (the test site is dead). + +Internet Data handling +---------------------- + +- sgmllib.py: support tags with - or . in their name. + +- mimetypes.py: guess_type() understands 'data' URLs. + +Restricted Execution +-------------------- + +- The classes rexec.RModuleLoader and rexec.RModuleImporter no +longer exist. + +Tkinter +------- + +- When reporting an exception, store its info in sys.last_*. Also, +write all of it to stderr. + +- Added NS, EW, and NSEW constants, for grid's sticky option. + +- Fixed last-minute bug in 1.5.2a1 release: need to include "mytime.h". + +- Make bind variants without a sequence return a tuple of sequences +(formerly it returned a string, which wasn't very convenient). + +- Add image commands to the Text widget (these are new in Tk 8.0). + +- Added new listbox and canvas methods: {xview,yview}_{scroll,moveto}.) + +- Improved the thread code (but you still can't call update() from +another thread on Windows). + +- Fixed unnecessary references to _default_root in the new dialog +modules. + +- Miscellaneous problems fixed. + + +Windows General +--------------- + +- Call LoadLibraryEx(..., ..., LOAD_WITH_ALTERED_SEARCH_PATH) to +search for dependent dlls in the directory containing the .pyd. + +- In debugging mode, call DebugBreak() in Py_FatalError(). + +Windows Installer +----------------- + +- Install zlib.dll in the DLLs directory instead of in the win32 +system directory, to avoid conflicts with other applications that have +their own zlib.dll. + +Test Suite +---------- + +- test_long.py: new test for long integers, by Tim Peters. + +- regrtest.py: improved so it can be used for other test suites as +well. + +- test_strftime.py: use re to compare test results, to support legal +variants (e.g. on Linux). + +Tools and Demos +--------------- + +- Four new scripts in Tools/scripts: crlf.py and lfcr.py (to +remove/add Windows style '\r\n' line endings), untabify.py (to remove +tabs), and rgrep.yp (reverse grep). + +- Improvements to Tools/freeze/. Each Python module is now written to +its own C file. This prevents some compilers or assemblers from +blowing up on large frozen programs, and saves recompilation time if +only a few modules are changed. Other changes too, e.g. new command +line options -x and -i. + +- Much improved (and smaller!) version of Tools/scripts/mailerdaemon.py. + +Python/C API +------------ + +- New mechanism to support extensions of the type object while +remaining backward compatible with extensions compiled for previous +versions of Python 1.5. A flags field indicates presence of certain +fields. + +- Addition to the buffer API to differentiate access to bytes and +8-bit characters (in anticipation of Unicode characters). + +- New argument parsing format t# ("text") to indicate 8-bit +characters; s# simply means 8-bit bytes, for backwards compatibility. + +- New object type, bufferobject.c is an example and can be used to +create buffers from memory. + +- Some support for 64-bit longs, including some MS platforms. + +- Many calls to fprintf(stderr, ...) have been replaced with calls to +PySys_WriteStderr(...). + +- The calling context for PyOS_Readline() has changed: it must now be +called with the interpreter lock held! It releases the lock around +the call to the function pointed to by PyOS_ReadlineFunctionPointer +(default PyOS_StdioReadline()). + +- New APIs PyLong_FromVoidPtr() and PyLong_AsVoidPtr(). + +- Renamed header file "thread.h" to "pythread.h". + +- The code string of code objects may now be anything that supports the +buffer API. + + +====================================================================== + + +From 1.5.1 to 1.5.2a1 +===================== + +General +------- + +- When searching for the library, a landmark that is a compiled module +(string.pyc or string.pyo) is also accepted. + +- When following symbolic links to the python executable, use a loop +so that a symlink to a symlink can work. + +- Added a hack so that when you type 'quit' or 'exit' at the +interpreter, you get a friendly explanation of how to press Ctrl-D (or +Ctrl-Z) to exit. + +- New and improved Misc/python-mode.el (Python mode for Emacs). + +- Revert a new feature in Unix dynamic loading: for one or two +revisions, modules were loaded using the RTLD_GLOBAL flag. It turned +out to be a bad idea. + +Miscellaneous fixed bugs +------------------------ + +- All patches on the patch page have been integrated. (But much more +has been done!) + +- Several memory leaks plugged (e.g. the one for classes with a +__getattr__ method). + +- Removed the only use of calloc(). This triggered an obscure bug on +multiprocessor Sparc Solaris 2.6. + +- Fix a peculiar bug that would allow "import sys.time" to succeed +(believing the built-in time module to be a part of the sys package). + +- Fix a bug in the overflow checking when converting a Python long to +a C long (failed to convert -2147483648L, and some other cases). + +Documentation +------------- + +- Doc strings have been added to many extension modules: __builtin__, +errno, select, signal, socket, sys, thread, time. Also to methods of +list objects (try [].append.__doc__). A doc string on a type will now +automatically be propagated to an instance if the instance has methods +that are accessed in the usual way. + +- The documentation has been expanded and the formatting improved. +(Remember that the documentation is now unbundled and has its own +release cycle though; see http://www.python.org/doc/.) + +- Added Misc/Porting -- a mini-FAQ on porting to a new platform. + +Ports and build procedure +------------------------- + +- The BeOS port is now integrated. Courtesy Chris Herborth. + +- Symbol files for FreeBSD 2.x and 3.x have been contributed +(Lib/plat-freebsd[23]/*). + +- Support HPUX 10.20 DCE threads. + +- Finally fixed the configure script so that (on SGI) if -OPT:Olimit=0 +works, it won't also use -Olimit 1500 (which gives a warning for every +file). Also support the SGI_ABI environment variable better. + +- The makesetup script now understands absolute pathnames ending in .o +in the module -- it assumes it's a file for which we have no source. + +- Other miscellaneous improvements to the configure script and +Makefiles. + +- The test suite now uses a different sound sample. + +Built-in functions +------------------ + +- Better checks for invalid input to int(), long(), string.atoi(), +string.atol(). (Formerly, a sign without digits would be accepted as +a legal ways to spell zero.) + +- Changes to map() and filter() to use the length of a sequence only +as a hint -- if an IndexError happens earlier, take that. (Formerly, +this was considered an error.) + +- Experimental feature in getattr(): a third argument can specify a +default (instead of raising AttributeError). + +- Implement round() slightly different, so that for negative ndigits +no additional errors happen in the last step. + +- The open() function now adds the filename to the exception when it +fails. + +Built-in exceptions +------------------- + +- New standard exceptions EnvironmentError and PosixError. +EnvironmentError is the base class for IOError and PosixError; +PosixError is the same as os.error. All this so that either exception +class can be instantiated with a third argument indicating a filename. +The built-in function open() and most os/posix functions that take a +filename argument now use this. + +Built-in types +-------------- + +- List objects now have an experimental pop() method; l.pop() returns +and removes the last item; l.pop(i) returns and removes the item at +i. Also, the sort() method is faster again. Sorting is now also +safer: it is impossible for the sorting function to modify the list +while the sort is going on (which could cause core dumps). + +- Changes to comparisons: numbers are now smaller than any other type. +This is done to prevent the circularity where [] < 0L < 1 < [] is +true. As a side effect, cmp(None, 0) is now positive instead of +negative. This *shouldn't* affect any working code, but I've found +that the change caused several "sleeping" bugs to become active, so +beware! + +- Instance methods may now have other callable objects than just +Python functions as their im_func. Use new.instancemethod() or write +your own C code to create them; new.instancemethod() may be called +with None for the instance to create an unbound method. + +- Assignment to __name__, __dict__ or __bases__ of a class object is +now allowed (with stringent type checks); also allow assignment to +__getattr__ etc. The cached values for __getattr__ etc. are +recomputed after such assignments (but not for derived classes :-( ). + +- Allow assignment to some attributes of function objects: func_code, +func_defaults and func_doc / __doc__. (With type checks except for +__doc__ / func_doc .) + +Python services +--------------- + +- New tests (in Lib/test): reperf.py (regular expression benchmark), +sortperf.py (list sorting benchmark), test_MimeWriter.py (test case +for the MimeWriter module). + +- Generalized test/regrtest.py so that it is useful for testing other +packages. + +- The ihooks.py module now understands package imports. + +- In code.py, add a class that subsumes Fredrik Lundh's +PythonInterpreter class. The interact() function now uses this. + +- In rlcompleter.py, in completer(), return None instead of raising an +IndexError when there are no more completions left. + +- Fixed the marshal module to test for certain common kinds of invalid +input. (It's still not foolproof!) + +- In the operator module, add an alias (now the preferred name) +"contains" for "sequenceincludes". + +String Services +--------------- + +- In the string and strop modules, in the replace() function, treat an +empty pattern as an error (since it's not clear what was meant!). + +- Some speedups to re.py, especially the string substitution and split +functions. Also added new function/method findall(), to find all +occurrences of a given substring. + +- In cStringIO, add better argument type checking and support the +readonly 'closed' attribute (like regular files). + +- In the struct module, unsigned 1-2 byte sized formats no longer +result in long integer values. + +Miscellaneous services +---------------------- + +- In whrandom.py, added new method and function randrange(), same as +choice(range(start, stop, step)) but faster. This addresses the +problem that randint() was accidentally defined as taking an inclusive +range. Also, randint(a, b) is now redefined as randrange(a, b+1), +adding extra range and type checking to its arguments! + +- Add some semi-thread-safety to random.gauss() (it used to be able to +crash when invoked from separate threads; now the worst it can do is +give a duplicate result occasionally). + +- Some restructuring and generalization done to cmd.py. + +- Major upgrade to ConfigParser.py; converted to using 're', added new +exceptions, support underscore in section header and option name. No +longer add 'name' option to every section; instead, add '__name__'. + +- In getpass.py, don't use raw_input() to ask for the password -- we +don't want it to show up in the readline history! Also don't catch +interrupts (the try-finally already does all necessary cleanup). + +Generic OS Services +------------------- + +- New functions in os.py: makedirs(), removedirs(), renames(). New +variable: linesep (the line separator as found in binary files, +i.e. '\n' on Unix, '\r\n' on DOS/Windows, '\r' on Mac. Do *not* use +this with files opened in (default) text mode; the line separator used +will always be '\n'! + +- Changes to the 'os.path' submodule of os.py: added getsize(), +getmtime(), getatime() -- these fetch the most popular items from the +stat return tuple. + +- In the time module, add strptime(), if it exists. (This parses a +time according to a format -- the inverse of strftime().) Also, +remove the call to mktime() from strftime() -- it messed up the +formatting of some non-local times. + +- In the socket module, added a new function gethostbyname_ex(). +Also, don't use #ifdef to test for some symbols that are enums on some +platforms (and should exist everywhere). + +Optional OS Services +-------------------- + +- Some fixes to gzip.py. In particular, the readlines() method now +returns the lines *with* trailing newline characters, like readlines() +of regular file objects. Also, it didn't work together with cPickle; +fixed that. + +- In whichdb.py, support byte-swapped dbhash (bsddb) files. + +- In anydbm.py, look at the type of an existing database to determine +which module to use to open it. (The anydbm.error exception is now a +tuple.) + +Unix Services +------------- + +- In the termios module, in tcsetattr(), initialize the structure vy +calling tcgetattr(). + +- Added some of the "wait status inspection" macros as functions to +the posix module (and thus to the os module): WEXITSTATUS(), +WIFEXITED(), WIFSIGNALED(), WIFSTOPPED(), WSTOPSIG(), WTERMSIG(). + +- In the syslog module, make the default facility more intuitive +(matching the docs). + +Debugger +-------- + +- In pdb.py, support for setting breaks on files/modules that haven't +been loaded yet. + +Internet Protocols and Support +------------------------------ + +- Changes in urllib.py; sped up unquote() and quote(). Fixed an +obscure bug in quote_plus(). Added urlencode(dict) -- convenience +function for sending a POST request with urlopen(). Use the getpass +module to ask for a password. Rewrote the (test) main program so that +when used as a script, it can retrieve one or more URLs to stdout. +Use -t to run the self-test. Made the proxy code work again. + +- In cgi.py, treat "HEAD" the same as "GET", so that CGI scripts don't +fail when someone asks for their HEAD. Also, for POST, set the +default content-type to application/x-www-form-urlencoded. Also, in +FieldStorage.__init__(), when method='GET', always get the query +string from environ['QUERY_STRING'] or sys.argv[1] -- ignore an +explicitly passed in fp. + +- The smtplib.py module now supports ESMTP and has improved standard +compliance, for picky servers. + +- Improved imaplib.py. + +- Fixed UDP support in SocketServer.py (it never worked). + +- Fixed a small bug in CGIHTTPServer.py. + +Internet Data handling +---------------------- + +- In rfc822.py, add a new class AddressList. Also support a new +overridable method, isheader(). Also add a get() method similar to +dictionaries (and make getheader() an alias for it). Also, be smarter +about seekable (test whether fp.tell() works) and test for presence of +unread() method before trying seeks. + +- In sgmllib.py, restore the call to report_unbalanced() that was lost +long ago. Also some other improvements: handle <? processing +instructions >, allow . and - in entity names, and allow \r\n as line +separator. + +- Some restructuring and generalization done to multifile.py; support +a 'seekable' flag. + +Restricted Execution +-------------------- + +- Improvements to rexec.py: package support; support a (minimal) +sys.exc_info(). Also made the (test) main program a bit fancier (you +can now use it to run arbitrary Python scripts in restricted mode). + +Tkinter +------- + +- On Unix, Tkinter can now safely be used from a multi-threaded +application. (Formerly, no threads would make progress while +Tkinter's mainloop() was active, because it didn't release the Python +interpreter lock.) Unfortunately, on Windows, threads other than the +main thread should not call update() or update_idletasks() because +this will deadlock the application. + +- An interactive interpreter that uses readline and Tkinter no longer +uses up all available CPU time. + +- Even if readline is not used, Tk windows created in an interactive +interpreter now get continuously updated. (This even works in Windows +as long as you don't hit a key.) + +- New demos in Demo/tkinter/guido/: brownian.py, redemo.py, switch.py. + +- No longer register Tcl_finalize() as a low-level exit handler. It +may call back into Python, and that's a bad idea. + +- Allow binding of Tcl commands (given as a string). + +- Some minor speedups; replace explicitly coded getint() with int() in +most places. + +- In FileDialog.py, remember the directory of the selected file, if +given. + +- Change the names of all methods in the Wm class: they are now +wm_title(), etc. The old names (title() etc.) are still defined as +aliases. + +- Add a new method of interpreter objects, interpaddr(). This returns +the address of the Tcl interpreter object, as an integer. Not very +useful for the Python programmer, but this can be called by another C +extension that needs to make calls into the Tcl/Tk C API and needs to +get the address of the Tcl interpreter object. A simple cast of the +return value to (Tcl_Interp *) will do the trick. + +Windows General +--------------- + +- Don't insist on proper case for module source files if the filename +is all uppercase (e.g. FOO.PY now matches foo; but FOO.py still +doesn't). This should address problems with this feature on +oldfashioned filesystems (Novell servers?). + +Windows Library +--------------- + +- os.environ is now all uppercase, but accesses are case insensitive, +and the putenv() calls made as a side effect of changing os.environ +are case preserving. + +- Removed samefile(), sameopenfile(), samestat() from os.path (aka +ntpath.py) -- these cannot be made to work reliably (at least I +wouldn't know how). + +- Fixed os.pipe() so that it returns file descriptors acceptable to +os.read() and os.write() (like it does on Unix), rather than Windows +file handles. + +- Added a table of WSA error codes to socket.py. + +- In the select module, put the (huge) file descriptor arrays on the +heap. + +- The getpass module now raises KeyboardInterrupt when it sees ^C. + +- In mailbox.py, fix tell/seek when using files opened in text mode. + +- In rfc822.py, fix tell/seek when using files opened in text mode. + +- In the msvcrt extension module, release the interpreter lock for +calls that may block: _locking(), _getch(), _getche(). Also fix a +bogus error return when open_osfhandle() doesn't have the right +argument list. + +Windows Installer +----------------- + +- The registry key used is now "1.5" instead of "1.5.x" -- so future +versions of 1.5 and Mark Hammond's win32all installer don't need to be +resynchronized. + +Windows Tools +------------- + +- Several improvements to freeze specifically for Windows. + +Windows Build Procedure +----------------------- + +- The VC++ project files and the WISE installer have been moved to the +PCbuild subdirectory, so they are distributed in the same subdirectory +where they must be used. This avoids confusion. + +- New project files for Windows 3.1 port by Jim Ahlstrom. + +- Got rid of the obsolete subdirectory PC/setup_nt/. + +- The projects now use distinct filenames for the .exe, .dll, .lib and +.pyd files built in debug mode (by appending "_d" to the base name, +before the extension). This makes it easier to switch between the two +and get the right versions. There's a pragma in config.h that directs +the linker to include the appropriate .lib file (so python15.lib no +longer needs to be explicit in your project). + +- The installer now installs more files (e.g. config.h). The idea is +that you shouldn't need the source distribution if you want build your +own extensions in C or C++. + +Tools and Demos +--------------- + +- New script nm2def.py by Marc-Andre Lemburg, to construct +PC/python_nt.def automatically (some hand editing still required). + +- New tool ndiff.py: Tim Peters' text diffing tool. + +- Various and sundry improvements to the freeze script. + +- The script texi2html.py (which was part of the Doc tree but is no +longer used there) has been moved to the Tools/scripts subdirectory. + +- Some generalizations in the webchecker code. There's now a +primnitive gui for websucker.py: wsgui.py. (In Tools/webchecker/.) + +- The ftpmirror.py script now handles symbolic links properly, and +also files with multiple spaces in their names. + +- The 1.5.1 tabnanny.py suffers an assert error if fed a script whose +last line is both indented and lacks a newline. This is now fixed. + +Python/C API +------------ + +- Added missing prototypes for PyEval_CallFunction() and +PyEval_CallMethod(). + +- New macro PyList_SET_ITEM(). + +- New macros to access object members for PyFunction, PyCFunction +objects. + +- New APIs PyImport_AppendInittab() an PyImport_ExtendInittab() to +dynamically add one or many entries to the table of built-in modules. + +- New macro Py_InitModule3(name, methods, doc) which calls +Py_InitModule4() with appropriate arguments. (The -4 variant requires +you to pass an obscure version number constant which is always the same.) + +- New APIs PySys_WriteStdout() and PySys_WriteStderr() to write to +sys.stdout or sys.stderr using a printf-like interface. (Used in +_tkinter.c, for example.) + +- New APIs for conversion between Python longs and C 'long long' if +your compiler supports it. + +- PySequence_In() is now called PySequence_Contains(). +(PySequence_In() is still supported for b/w compatibility; it is +declared obsolete because its argument order is confusing.) + +- PyDict_GetItem() and PyDict_GetItemString() are changed so that they +*never* raise an exception -- (even if the hash() fails, simply clear +the error). This was necessary because there is lots of code out +there that already assumes this. + +- Changes to PySequence_Tuple() and PySequence_List() to use the +length of a sequence only as a hint -- if an IndexError happens +earlier, take that. (Formerly, this was considered an error.) + +- Reformatted abstract.c to give it a more familiar "look" and fixed +many error checking bugs. + +- Add NULL pointer checks to all calls of a C function through a type +object and extensions (e.g. nb_add). + +- The code that initializes sys.path now calls Py_GetPythonHome() +instead of getenv("PYTHONHOME"). This, together with the new API +Py_SetPythonHome(), makes it easier for embedding applications to +change the notion of Python's "home" directory (where the libraries +etc. are sought). + +- Fixed a very old bug in the parsing of "O?" format specifiers. + + +====================================================================== + + +======================================== +==> Release 1.5.1 (October 31, 1998) <== +======================================== + +From 1.5 to 1.5.1 +================= + +General +------- + +- The documentation is now unbundled. It has also been extensively +modified (mostly to implement a new and more uniform formatting +style). We figure that most people will prefer to download one of the +preformatted documentation sets (HTML, PostScript or PDF) and that +only a minority have a need for the LaTeX or FrameMaker sources. Of +course, the unbundled documentation sources still released -- just not +in the same archive file, and perhaps not on the same date. + +- All bugs noted on the errors page (and many unnoted) are fixed. All +new bugs take their places. + +- No longer a core dump when attempting to print (or repr(), or str()) +a list or dictionary that contains an instance of itself; instead, the +recursive entry is printed as [...] or {...}. See Py_ReprEnter() and +Py_ReprLeave() below. Comparisons of such objects still go beserk, +since this requires a different kind of fix; fortunately, this is a +less common scenario in practice. + +Syntax change +------------- + +- The raise statement can now be used without arguments, to re-raise +a previously set exception. This should be used after catching an +exception with an except clause only, either in the except clause or +later in the same function. + +Import and module handling +-------------------------- + +- The implementation of import has changed to use a mutex (when +threading is supported). This means that when two threads +simultaneously import the same module, the import statements are +serialized. Recursive imports are not affected. + +- Rewrote the finalization code almost completely, to be much more +careful with the order in which modules are destroyed. Destructors +will now generally be able to reference built-in names such as None +without trouble. + +- Case-insensitive platforms such as Mac and Windows require the case +of a module's filename to match the case of the module name as +specified in the import statement (see below). + +- The code for figuring out the default path now distinguishes between +files, modules, executable files, and directories. When expecting a +module, we also look for the .pyc or .pyo file. + +Parser/tokenizer changes +------------------------ + +- The tokenizer can now warn you when your source code mixes tabs and +spaces for indentation in a manner that depends on how much a tab is +worth in spaces. Use "python -t" or "python -v" to enable this +option. Use "python -tt" to turn the warnings into errors. (See also +tabnanny.py and tabpolice.py below.) + +- Return unsigned characters from tok_nextc(), so '\377' isn't +mistaken for an EOF character. + +- Fixed two pernicious bugs in the tokenizer that only affected AIX. +One was actually a general bug that was triggered by AIX's smaller I/O +buffer size. The other was a bug in the AIX optimizer's loop +unrolling code; swapping two statements made the problem go away. + +Tools, demos and miscellaneous files +------------------------------------ + +- There's a new version of Misc/python-mode.el (the Emacs mode for +Python) which is much smarter about guessing the indentation style +used in a particular file. Lots of other cool features too! + +- There are two new tools in Tools/scripts: tabnanny.py and +tabpolice.py, implementing two different ways of checking whether a +file uses indentation in a way that is sensitive to the interpretation +of a tab. The preferred module is tabnanny.py (by Tim Peters). + +- Some new demo programs: + + Demo/tkinter/guido/paint.py -- Dave Mitchell + Demo/sockets/unixserver.py -- Piet van Oostrum + + +- Much better freeze support. The freeze script can now freeze +hierarchical module names (with a corresponding change to import.c), +and has a few extra options (e.g. to suppress freezing specific +modules). It also does much more on Windows NT. + +- Version 1.0 of the faq wizard is included (only very small changes +since version 0.9.0). + +- New feature for the ftpmirror script: when removing local files +(i.e., only when -r is used), do a recursive delete. + +Configuring and building Python +------------------------------- + +- Get rid of the check for -linet -- recent Sequent Dynix systems don't +need this any more and apparently it screws up their configuration. + +- Some changes because gcc on SGI doesn't support '-all'. + +- Changed the build rules to use $(LIBRARY) instead of + -L.. -lpython$(VERSION) +since the latter trips up the SunOS 4.1.x linker (sigh). + +- Fix the bug where the '# dgux is broken' comment in the Makefile +tripped over Make on some platforms. + +- Changes for AIX: install the python.exp file; properly use +$(srcdir); the makexp_aix script now removes C++ entries of the form +Class::method. + +- Deleted some Makefile targets only used by the (long obsolete) +gMakefile hacks. + +Extension modules +----------------- + +- Performance and threading improvements to the socket and bsddb +modules, by Christopher Lindblad of Infoseek. + +- Added operator.__not__ and operator.not_. + +- In the thread module, when a thread exits due to an unhandled +exception, don't store the exception information in sys.last_*; it +prevents proper calling of destructors of local variables. + +- Fixed a number of small bugs in the cPickle module. + +- Changed find() and rfind() in the strop module so that +find("x","",2) returns -1, matching the implementation in string.py. + +- In the time module, be more careful with the result of ctime(), and +test for HAVE_MKTIME before usinmg mktime(). + +- Doc strings contributed by Mitch Chapman to the termios, pwd, gdbm +modules. + +- Added the LOG_SYSLOG constant to the syslog module, if defined. + +Standard library modules +------------------------ + +- All standard library modules have been converted to an indentation +style using either only tabs or only spaces -- never a mixture -- if +they weren't already consistent according to tabnanny. This means +that the new -t option (see above) won't complain about standard +library modules. + +- New standard library modules: + + threading -- GvR and the thread-sig + Java style thread objects -- USE THIS!!! + + getpass -- Piers Lauder + simple utilities to prompt for a password and to + retrieve the current username + + imaplib -- Piers Lauder + interface for the IMAP4 protocol + + poplib -- David Ascher, Piers Lauder + interface for the POP3 protocol + + smtplib -- Dragon De Monsyne + interface for the SMTP protocol + +- Some obsolete modules moved to a separate directory (Lib/lib-old) +which is *not* in the default module search path: + + Para + addpack + codehack + fmt + lockfile + newdir + ni + rand + tb + +- New version of the PCRE code (Perl Compatible Regular Expressions -- +the re module and the supporting pcre extension) by Andrew Kuchling. +Incompatible new feature in re.sub(): the handling of escapes in the +replacement string has changed. + +- Interface change in the copy module: a __deepcopy__ method is now +called with the memo dictionary as an argument. + +- Feature change in the tokenize module: differentiate between NEWLINE +token (an official newline) and NL token (a newline that the grammar +ignores). + +- Several bugfixes to the urllib module. It is now truly thread-safe, +and several bugs and a portability problem have been fixed. New +features, all due to Sjoerd Mullender: When creating a temporary file, +it gives it an appropriate suffix. Support the "data:" URL scheme. +The open() method uses the tempcache. + +- New version of the xmllib module (this time with a test suite!) by +Sjoerd Mullender. + +- Added debugging code to the telnetlib module, to be able to trace +the actual traffic. + +- In the rfc822 module, added support for deleting a header (still no +support for adding headers, though). Also fixed a bug where an +illegal address would cause a crash in getrouteaddr(), fixed a +sign reversal in mktime_tz(), and use the local timezone by default +(the latter two due to Bill van Melle). + +- The normpath() function in the dospath and ntpath modules no longer +does case normalization -- for that, use the separate function +normcase() (which always existed); normcase() has been sped up and +fixed (it was the cause of a crash in Mark Hammond's installer in +certain locales). + +- New command supported by the ftplib module: rmd(); also fixed some +minor bugs. + +- The profile module now uses a different timer function by default -- +time.clock() is generally better than os.times(). This makes it work +better on Windows NT, too. + +- The tempfile module now recovers when os.getcwd() raises an +exception. + +- Fixed some bugs in the random module; gauss() was subtly wrong, and +vonmisesvariate() should return a full circle. Courtesy Mike Miller, +Lambert Meertens (gauss()), and Magnus Kessler (vonmisesvariate()). + +- Better default seed in the whrandom module, courtesy Andrew Kuchling. + +- Fix slow close() in shelve module. + +- The Unix mailbox class in the mailbox module is now more robust when +a line begins with the string "From " but is definitely not the start +of a new message. The pattern used can be changed by overriding a +method or class variable. + +- Added a rmtree() function to the copy module. + +- Fixed several typos in the pickle module. Also fixed problems when +unpickling in restricted execution environments. + +- Added docstrings and fixed a typo in the py_compile and compileall +modules. At Mark Hammond's repeated request, py_compile now append a +newline to the source if it needs one. Both modules support an extra +parameter to specify the purported source filename (to be used in +error messages). + +- Some performance tweaks by Jeremy Hylton to the gzip module. + +- Fixed a bug in the merge order of dictionaries in the ConfigParser +module. Courtesy Barry Warsaw. + +- In the multifile module, support the optional second parameter to +seek() when possible. + +- Several fixes to the gopherlib module by Lars Marius Garshol. Also, +urlparse now correctly handles Gopher URLs with query strings. + +- Fixed a tiny bug in format_exception() in the traceback module. +Also rewrite tb_lineno() to be compatible with JPython (and not +disturb the current exception!); by Jim Hugunin. + +- The httplib module is more robust when servers send a short response +-- courtesy Tim O'Malley. + +Tkinter and friends +------------------- + +- Various typos and bugs fixed. + +- New module Tkdnd implements a drag-and-drop protocol (within one +application only). + +- The event_*() widget methods have been restructured slightly -- they +no longer use the default root. + +- The interfaces for the bind*() and unbind() widget methods have been +redesigned; the bind*() methods now return the name of the Tcl command +created for the callback, and this can be passed as a optional +argument to unbind() in order to delete the command (normally, such +commands are automatically unbound when the widget is destroyed, but +for some applications this isn't enough). + +- Variable objects now have trace methods to interface to Tcl's +variable tracing facilities. + +- Image objects now have an optional keyword argument, 'master', to +specify a widget (tree) to which they belong. The image_names() and +image_types() calls are now also widget methods. + +- There's a new global call, Tkinter.NoDefaultRoot(), which disables +all use of the default root by the Tkinter library. This is useful to +debug applications that are in the process of being converted from +relying on the default root to explicit specification of the root +widget. + +- The 'exit' command is deleted from the Tcl interpreter, since it +provided a loophole by which one could (accidentally) exit the Python +interpreter without invoking any cleanup code. + +- Tcl_Finalize() is now registered as a Python low-level exit handle, +so Tcl will be finalized when Python exits. + +The Python/C API +---------------- + +- New function PyThreadState_GetDict() returns a per-thread dictionary +intended for storing thread-local global variables. + +- New functions Py_ReprEnter() and Py_ReprLeave() use the per-thread +dictionary to allow recursive container types to detect recursion in +their repr(), str() and print implementations. + +- New function PyObject_Not(x) calculates (not x) according to Python's +standard rules (basically, it negates the outcome PyObject_IsTrue(x). + +- New function _PyModule_Clear(), which clears a module's dictionary +carefully without removing the __builtins__ entry. This is implied +when a module object is deallocated (this used to clear the dictionary +completely). + +- New function PyImport_ExecCodeModuleEx(), which extends +PyImport_ExecCodeModule() by adding an extra parameter to pass it the +true file. + +- New functions Py_GetPythonHome() and Py_SetPythonHome(), intended to +allow embedded applications to force a different value for PYTHONHOME. + +- New global flag Py_FrozenFlag is set when this is a "frozen" Python +binary; it suppresses warnings about not being able to find the +standard library directories. + +- New global flag Py_TabcheckFlag is incremented by the -t option and +causes the tokenizer to issue warnings or errors about inconsistent +mixing of tabs and spaces for indentation. + +Miscellaneous minor changes and bug fixes +----------------------------------------- + +- Improved the error message when an attribute of an attribute-less +object is requested -- include the name of the attribute and the type +of the object in the message. + +- Sped up int(), long(), float() a bit. + +- Fixed a bug in list.sort() that would occasionally dump core. + +- Fixed a bug in PyNumber_Power() that caused numeric arrays to fail +when taken tothe real power. + +- Fixed a number of bugs in the file reading code, at least one of +which could cause a core dump on NT, and one of which would +occasionally cause file.read() to return less than the full contents +of the file. + +- Performance hack by Vladimir Marangozov for stack frame creation. + +- Make sure setvbuf() isn't used unless HAVE_SETVBUF is defined. + +Windows 95/NT +------------- + +- The .lib files are now part of the distribution; they are collected +in the subdirectory "libs" of the installation directory. + +- The extension modules (.pyd files) are now collected in a separate +subdirectory of the installation directory named "DLLs". + +- The case of a module's filename must now match the case of the +module name as specified in the import statement. This is an +experimental feature -- if it turns out to break in too many +situations, it will be removed (or disabled by default) in the future. +It can be disabled on a per-case basis by setting the environment +variable PYTHONCASEOK (to any value). + + +====================================================================== + + +===================================== +==> Release 1.5 (January 3, 1998) <== +===================================== + + +From 1.5b2 to 1.5 +================= + +- Newly documentated module: BaseHTTPServer.py, thanks to Greg Stein. + +- Added doc strings to string.py, stropmodule.c, structmodule.c, +thanks to Charles Waldman. + +- Many nits fixed in the manuals, thanks to Fred Drake and many others +(especially Rob Hooft and Andrew Kuchling). The HTML version now uses +HTML markup instead of inline GIF images for tables; only two images +are left (for obsure bits of math). The index of the HTML version has +also been much improved. Finally, it is once again possible to +generate an Emacs info file from the library manual (but I don't +commit to supporting this in future versions). + +- New module: telnetlib.py (a simple telnet client library). + +- New tool: Tools/versioncheck/, by Jack Jansen. + +- Ported zlibmodule.c and bsddbmodule.c to NT; The project file for MS +DevStudio 5.0 now includes new subprojects to build the zlib and bsddb +extension modules. + +- Many small changes again to Tkinter.py -- mostly bugfixes and adding +missing routines. Thanks to Greg McFarlane for reporting a bunch of +problems and proofreading my fixes. + +- The re module and its documentation are up to date with the latest +version released to the string-sig (Dec. 22). + +- Stop test_grp.py from failing when the /etc/group file is empty +(yes, this happens!). + +- Fix bug in integer conversion (mystrtoul.c) that caused +4294967296==0 to be true! + +- The VC++ 4.2 project file should be complete again. + +- In tempfile.py, use a better template on NT, and add a new optional +argument "suffix" with default "" to specify a specific extension for +the temporary filename (needed sometimes on NT but perhaps also handy +elsewhere). + +- Fixed some bugs in the FAQ wizard, and converted it to use re +instead of regex. + +- Fixed a mysteriously undetected error in dlmodule.c (it was using a +totally bogus routine name to raise an exception). + +- Fixed bug in import.c which wasn't using the new "dos-8x3" name yet. + +- Hopefully harmless changes to the build process to support shared +libraries on DG/UX. This adds a target to create +libpython$(VERSION).so; however this target is *only* for DG/UX. + +- Fixed a bug in the new format string error checking in getargs.c. + +- A simple fix for infinite recursion when printing __builtins__: +reset '_' to None before printing and set it to the printed variable +*after* printing (and only when printing is successful). + +- Fixed lib-tk/SimpleDialog.py to keep the dialog visible even if the +parent window is not (Skip Montanaro). + +- Fixed the two most annoying problems with ftp URLs in +urllib.urlopen(); an empty file now correctly raises an error, and it +is no longer required to explicitly close the returned "file" object +before opening another ftp URL to the same host and directory. + + +====================================================================== + + +From 1.5b1 to 1.5b2 +=================== + +- Fixed a bug in cPickle.c that caused it to crash right away because +the version string had a different format. + +- Changes in pickle.py and cPickle.c: when unpickling an instance of a +class that doesn't define the __getinitargs__() method, the __init__() +constructor is no longer called. This makes a much larger group of +classes picklable by default, but may occasionally change semantics. +To force calling __init__() on unpickling, define a __getinitargs__() +method. Other changes too, in particular cPickle now handles classes +defined in packages correctly. The same change applies to copying +instances with copy.py. The cPickle.c changes and some pickle.py +changes are courtesy Jim Fulton. + +- Locale support in he "re" (Perl regular expressions) module. Use +the flag re.L (or re.LOCALE) to enable locale-specific matching +rules for \w and \b. The in-line syntax for this flag is (?L). + +- The built-in function isinstance(x, y) now also succeeds when y is +a type object and type(x) is y. + +- repr() and str() of class and instance objects now reflect the +package/module in which the class is defined. + +- Module "ni" has been removed. (If you really need it, it's been +renamed to "ni1". Let me know if this causes any problems for you. +Package authors are encouraged to write __init__.py files that +support both ni and 1.5 package support, so the same version can be +used with Python 1.4 as well as 1.5.) + +- The thread module is now automatically included when threads are +configured. (You must remove it from your existing Setup file, +since it is now in its own Setup.thread file.) + +- New command line option "-x" to skip the first line of the script; +handy to make executable scripts on non-Unix platforms. + +- In importdl.c, add the RTLD_GLOBAL to the dlopen() flags. I +haven't checked how this affects things, but it should make symbols +in one shared library available to the next one. + +- The Windows installer now installs in the "Program Files" folder on +the proper volume by default. + +- The Windows configuration adds a new main program, "pythonw", and +registers a new extension, ".pyw" that invokes this. This is a +pstandard Python interpreter that does not pop up a console window; +handy for pure Tkinter applications. All output to the original +stdout and stderr is lost; reading from the original stdin yields +EOF. Also, both python.exe and pythonw.exe now have a pretty icon +(a green snake in a box, courtesy Mark Hammond). + +- Lots of improvements to emacs-mode.el again. See Barry's web page: +http://www.python.org/ftp/emacs/pmdetails.html. + +- Lots of improvements and additions to the library reference manual; +many by Fred Drake. + +- Doc strings for the following modules: rfc822.py, posixpath.py, +ntpath.py, httplib.py. Thanks to Mitch Chapman and Charles Waldman. + +- Some more regression testing. + +- An optional 4th (maxsplit) argument to strop.replace(). + +- Fixed handling of maxsplit in string.splitfields(). + +- Tweaked os.environ so it can be pickled and copied. + +- The portability problems caused by indented preprocessor commands +and C++ style comments should be gone now. + +- In random.py, added Pareto and Weibull distributions. + +- The crypt module is now disabled in Modules/Setup.in by default; it +is rarely needed and causes errors on some systems where users often +don't know how to deal with those. + +- Some improvements to the _tkinter build line suggested by Case Roole. + +- A full suite of platform specific files for NetBSD 1.x, submitted by +Anders Andersen. + +- New Solaris specific header STROPTS.py. + +- Moved a confusing occurrence of *shared* from the comments in +Modules/Setup.in (people would enable this one instead of the real +one, and get disappointing results). + +- Changed the default mode for directories to be group-writable when +the installation process creates them. + +- Check for pthread support in "-l_r" for FreeBSD/NetBSD, and support +shared libraries for both. + +- Support FreeBSD and NetBSD in posixfile.py. + +- Support for the "event" command, new in Tk 4.2. By Case Roole. + +- Add Tix_SafeInit() support to tkappinit.c. + +- Various bugs fixed in "re.py" and "pcre.c". + +- Fixed a bug (broken use of the syntax table) in the old "regexpr.c". + +- In frozenmain.c, stdin is made unbuffered too when PYTHONUNBUFFERED +is set. + +- Provide default blocksize for retrbinary in ftplib.py (Skip +Montanaro). + +- In NT, pick the username up from different places in user.py (Jeff +Bauer). + +- Patch to urlparse.urljoin() for ".." and "..#1", Marc Lemburg. + +- Many small improvements to Jeff Rush' OS/2 support. + +- ospath.py is gone; it's been obsolete for so many years now... + +- The reference manual is now set up to prepare better HTML (still +using webmaker, alas). + +- Add special handling to /Tools/freeze for Python modules that are +imported implicitly by the Python runtime: 'site' and 'exceptions'. + +- Tools/faqwiz 0.8.3 -- add an option to suppress URL processing +inside <PRE>, by "Scott". + +- Added ConfigParser.py, a generic parser for sectioned configuration +files. + +- In _localemodule.c, LC_MESSAGES is not always defined; put it +between #ifdefs. + +- Typo in resource.c: RUSAGE_CHILDERN -> RUSAGE_CHILDREN. + +- Demo/scripts/newslist.py: Fix the way the version number is gotten +out of the RCS revision. + +- PyArg_Parse[Tuple] now explicitly check for bad characters at the +end of the format string. + +- Revamped PC/example_nt to support VC++ 5.x. + +- <listobject>.sort() now uses a modified quicksort by Raymund Galvin, +after studying the GNU libg++ quicksort. This should be much faster +if there are lots of duplicates, and otherwise at least as good. + +- Added "uue" as an alias for "uuencode" to mimetools.py. (Hm, the +uudecode bug where it complaints about trailing garbage is still there +:-( ). + +- pickle.py requires integers in text mode to be in decimal notation +(it used to accept octal and hex, even though it would only generate +decimal numbers). + +- In string.atof(), don't fail when the "re" module is unavailable. +Plug the ensueing security leak by supplying an empty __builtins__ +directory to eval(). + +- A bunch of small fixes and improvements to Tkinter.py. + +- Fixed a buffer overrun in PC/getpathp.c. + + +====================================================================== + + +From 1.5a4 to 1.5b1 +=================== + +- The Windows NT/95 installer now includes full HTML of all manuals. +It also has a checkbox that lets you decide whether to install the +interpreter and library. The WISE installer script for the installer +is included in the source tree as PC/python15.wse, and so are the +icons used for Python files. The config.c file for the Windows build +is now complete with the pcre module. + +- sys.ps1 and sys.ps2 can now arbitrary objects; their str() is +evaluated for the prompt. + +- The reference manual is brought up to date (more or less -- it still +needs work, e.g. in the area of package import). + +- The icons used by latex2html are now included in the Doc +subdirectory (mostly so that tarring up the HTML files can be fully +automated). A simple index.html is also added to Doc (it only works +after you have successfully run latex2html). + +- For all you would-be proselytizers out there: a new version of +Misc/BLURB describes Python more concisely, and Misc/comparisons +compares Python to several other languages. Misc/BLURB.WINDOWS +contains a blurb specifically aimed at Windows programmers (by Mark +Hammond). + +- A new version of the Python mode for Emacs is included as +Misc/python-mode.el. There are too many new features to list here. +See http://www.python.org/ftp/emacs/pmdetails.html for more info. + +- New module fileinput makes iterating over the lines of a list of +files easier. (This still needs some more thinking to make it more +extensible.) + +- There's full OS/2 support, courtesy Jeff Rush. To build the OS/2 +version, see PC/readme.txt and PC/os2vacpp. This is for IBM's Visual +Age C++ compiler. I expect that Jeff will also provide a binary +release for this platform. + +- On Linux, the configure script now uses '-Xlinker -export-dynamic' +instead of '-rdynamic' to link the main program so that it exports its +symbols to shared libraries it loads dynamically. I hope this doesn't +break on older Linux versions; it is needed for mklinux and appears to +work on Linux 2.0.30. + +- Some Tkinter resstructuring: the geometry methods that apply to a +master are now properly usable on toplevel master widgets. There's a +new (internal) widget class, BaseWidget. New, longer "official" names +for the geometry manager methods have been added, +e.g. "grid_columnconfigure()" instead of "columnconfigure()". The old +shorter names still work, and where there's ambiguity, pack wins over +place wins over grid. Also, the bind_class method now returns its +value. + +- New, RFC-822 conformant parsing of email addresses and address lists +in the rfc822 module, courtesy Ben Escoto. + +- New, revamped tkappinit.c with support for popular packages (PIL, +TIX, BLT, TOGL). For the last three, you need to execute the Tcl +command "load {} Tix" (or Blt, or Togl) to gain access to them. +The Modules/Setup line for the _tkinter module has been rewritten +using the cool line-breaking feature of most Bourne shells. + +- New socket method connect_ex() returns the error code from connect() +instead of raising an exception on errors; this makes the logic +required for asynchronous connects simpler and more efficient. + +- New "locale" module with (still experimental) interface to the +standard C library locale interface, courtesy Martin von Loewis. This +does not repeat my mistake in 1.5a4 of always calling +setlocale(LC_ALL, ""). In fact, we've pretty much decided that +Python's standard numerical formatting operations should always use +the conventions for the C locale; the locale module contains utility +functions to format numbers according to the user specified locale. +(All this is accomplished by an explicit call to setlocale(LC_NUMERIC, +"C") after locale-changing calls.) See the library manual. (Alas, the +promised changes to the "re" module for locale support have not been +materialized yet. If you care, volunteer!) + +- Memory leak plugged in Py_BuildValue when building a dictionary. + +- Shared modules can now live inside packages (hierarchical module +namespaces). No changes to the shared module itself are needed. + +- Improved policy for __builtins__: this is a module in __main__ and a +dictionary everywhere else. + +- Python no longer catches SIGHUP and SIGTERM by default. This was +impossible to get right in the light of thread contexts. If you want +your program to clean up when a signal happens, use the signal module +to set up your own signal handler. + +- New Python/C API PyNumber_CoerceEx() does not return an exception +when no coercion is possible. This is used to fix a problem where +comparing incompatible numbers for equality would raise an exception +rather than return false as in Python 1.4 -- it once again will return +false. + +- The errno module is changed again -- the table of error messages +(errorstr) is removed. Instead, you can use os.strerror(). This +removes redundance and a potential locale dependency. + +- New module xmllib, to parse XML files. By Sjoerd Mullender. + +- New C API PyOS_AfterFork() is called after fork() in posixmodule.c. +It resets the signal module's notion of what the current process ID +and thread are, so that signal handlers will work after (and across) +calls to os.fork(). + +- Fixed most occurrences of fatal errors due to missing thread state. + +- For vgrind (a flexible source pretty printer) fans, there's a simple +Python definition in Misc/vgrindefs, courtesy Neale Pickett. + +- Fixed memory leak in exec statement. + +- The test.pystone module has a new function, pystones(loops=LOOPS), +which returns a (benchtime, stones) tuple. The main() function now +calls this and prints the report. + +- Package directories now *require* the presence of an __init__.py (or +__init__.pyc) file before they are considered as packages. This is +done to prevent accidental subdirectories with common names from +overriding modules with the same name. + +- Fixed some strange exceptions in __del__ methods in library modules +(e.g. urllib). This happens because the builtin names are already +deleted by the time __del__ is called. The solution (a hack, but it +works) is to set some instance variables to 0 instead of None. + +- The table of built-in module initializers is replaced by a pointer +variable. This makes it possible to switch to a different table at +run time, e.g. when a collection of modules is loaded from a shared +library. (No example code of how to do this is given, but it is +possible.) The table is still there of course, its name prefixed with +an underscore and used to initialize the pointer. + +- The warning about a thread still having a frame now only happens in +verbose mode. + +- Change the signal finialization so that it also resets the signal +handlers. After this has been called, our signal handlers are no +longer active! + +- New version of tokenize.py (by Ka-Ping Yee) recognizes raw string +literals. There's now also a test fort this module. + +- The copy module now also uses __dict__.update(state) instead of +going through individual attribute assignments, for class instances +without a __setstate__ method. + +- New module reconvert translates old-style (regex module) regular +expressions to new-style (re module, Perl-style) regular expressions. + +- Most modules that used to use the regex module now use the re +module. The grep module has a new pgrep() function which uses +Perl-style regular expressions. + +- The (very old, backwards compatibility) regexp.py module has been +deleted. + +- Restricted execution (rexec): added the pcre module (support for the +re module) to the list of trusted extension modules. + +- New version of Jim Fulton's CObject object type, adds +PyCObject_FromVoidPtrAndDesc() and PyCObject_GetDesc() APIs. + +- Some patches to Lee Busby's fpectl mods that accidentally didn't +make it into 1.5a4. + +- In the string module, add an optional 4th argument to count(), +matching find() etc. + +- Patch for the nntplib module by Charles Waldman to add optional user +and password arguments to NNTP.__init__(), for nntp servers that need +them. + +- The str() function for class objects now returns +"modulename.classname" instead of returning the same as repr(). + +- The parsing of \xXX escapes no longer relies on sscanf(). + +- The "sharedmodules" subdirectory of the installation is renamed to +"lib-dynload". (You may have to edit your Modules/Setup file to fix +this in an existing installation!) + +- Fixed Don Beaudry's mess-up with the OPT test in the configure +script. Certain SGI platforms will still issue a warning for each +compile; there's not much I can do about this since the compiler's +exit status doesn't indicate that I was using an obsolete option. + +- Fixed Barry's mess-up with {}.get(), and added test cases for it. + +- Shared libraries didn't quite work under AIX because of the change +in status of the GNU readline interface. Fix due to by Vladimir +Marangozov. + + +====================================================================== + + +From 1.5a3 to 1.5a4 +=================== + +- faqwiz.py: version 0.8; Recognize https:// as URL; <html>...</html> +feature; better install instructions; removed faqmain.py (which was an +older version). + +- nntplib.py: Fixed some bugs reported by Lars Wirzenius (to Debian) +about the treatment of lines starting with '.'. Added a minimal test +function. + +- struct module: ignore most whitespace in format strings. + +- urllib.py: close the socket and temp file in URLopener.retrieve() so +that multiple retrievals using the same connection work. + +- All standard exceptions are now classes by default; use -X to make +them strings (for backward compatibility only). + +- There's a new standard exception hierarchy, defined in the standard +library module exceptions.py (which you never need to import +explicitly). See +http://grail.cnri.reston.va.us/python/essays/stdexceptions.html for +more info. + +- Three new C API functions: + + - int PyErr_GivenExceptionMatches(obj1, obj2) + + Returns 1 if obj1 and obj2 are the same object, or if obj1 is an + instance of type obj2, or of a class derived from obj2 + + - int PyErr_ExceptionMatches(obj) + + Higher level wrapper around PyErr_GivenExceptionMatches() which uses + PyErr_Occurred() as obj1. This will be the more commonly called + function. + + - void PyErr_NormalizeException(typeptr, valptr, tbptr) + + Normalizes exceptions, and places the normalized values in the + arguments. If type is not a class, this does nothing. If type is a + class, then it makes sure that value is an instance of the class by: + + 1. if instance is of the type, or a class derived from type, it does + nothing. + + 2. otherwise it instantiates the class, using the value as an + argument. If value is None, it uses an empty arg tuple, and if + the value is a tuple, it uses just that. + +- Another new C API function: PyErr_NewException() creates a new +exception class derived from Exception; when -X is given, it creates a +new string exception. + +- core interpreter: remove the distinction between tuple and list +unpacking; allow an arbitrary sequence on the right hand side of any +unpack instruction. (UNPACK_LIST and UNPACK_TUPLE now do the same +thing, which should really be called UNPACK_SEQUENCE.) + +- classes: Allow assignments to an instance's __dict__ or __class__, +so you can change ivars (including shared ivars -- shock horror) and +change classes dynamically. Also make the check on read-only +attributes of classes less draconic -- only the specials names +__dict__, __bases__, __name__ and __{get,set,del}attr__ can't be +assigned. + +- Two new built-in functions: issubclass() and isinstance(). Both +take classes as their second arguments. The former takes a class as +the first argument and returns true iff first is second, or is a +subclass of second. The latter takes any object as the first argument +and returns true iff first is an instance of the second, or any +subclass of second. + +- configure: Added configuration tests for presence of alarm(), +pause(), and getpwent(). + +- Doc/Makefile: changed latex2html targets. + +- classes: Reverse the search order for the Don Beaudry hook so that +the first class with an applicable hook wins. Makes more sense. + +- Changed the checks made in Py_Initialize() and Py_Finalize(). It is +now legal to call these more than once. The first call to +Py_Initialize() initializes, the first call to Py_Finalize() +finalizes. There's also a new API, Py_IsInitalized() which checks +whether we are already initialized (in case you want to leave things +as they were). + +- Completely disable the declarations for malloc(), realloc() and +free(). Any 90's C compiler has these in header files, and the tests +to decide whether to suppress the declarations kept failing on some +platforms. + +- *Before* (instead of after) signalmodule.o is added, remove both +intrcheck.o and sigcheck.o. This should get rid of warnings in ar or +ld on various systems. + +- Added reop to PC/config.c + +- configure: Decided to use -Aa -D_HPUX_SOURCE on HP-UX platforms. +Removed outdated HP-UX comments from README. Added Cray T3E comments. + +- Various renames of statically defined functions that had name +conflicts on some systems, e.g. strndup (GNU libc), join (Cray), +roundup (sys/types.h). + +- urllib.py: Interpret three slashes in file: URL as local file (for +Netscape on Windows/Mac). + +- copy.py: Make sure the objects returned by __getinitargs__() are +kept alive (in the memo) to avoid a certain kind of nasty crash. (Not +easily reproducable because it requires a later call to +__getinitargs__() to return a tuple that happens to be allocated at +the same address.) + +- Added definition of AR to toplevel Makefile. Renamed @buildno temp +file to buildno1. + +- Moved Include/assert.h to Parser/assert.h, which seems to be the +only place where it's needed. + +- Tweaked the dictionary lookup code again for some more speed +(Vladimir Marangozov). + +- NT build: Changed the way python15.lib is included in the other +projects. Per Mark Hammond's suggestion, add it to the extra libs in +Settings instead of to the project's source files. + +- regrtest.py: Change default verbosity so that there are only three +levels left: -q, default and -v. In default mode, the name of each +test is now printed. -v is the same as the old -vv. -q is more quiet +than the old default mode. + +- Removed the old FAQ from the distribution. You now have to get it +from the web! + +- Removed the PC/make_nt.in file from the distribution; it is no +longer needed. + +- Changed the build sequence so that shared modules are built last. +This fixes things for AIX and doesn't hurt elsewhere. + +- Improved test for GNU MP v1 in mpzmodule.c + +- fileobject.c: ftell() on Linux discards all buffered data; changed +read() code to use lseek() instead to get the same effect + +- configure.in, configure, importdl.c: NeXT sharedlib fixes + +- tupleobject.c: PyTuple_SetItem asserts refcnt==1 + +- resource.c: Different strategy regarding whether to declare +getrusage() and getpagesize() -- #ifdef doesn't work, Linux has +conflicting decls in its headers. Choice: only declare the return +type, not the argument prototype, and not on Linux. + +- importdl.c, configure*: set sharedlib extensions properly for NeXT + +- configure*, Makefile.in, Modules/Makefile.pre.in: AIX shared libraries +fixed; moved addition of PURIFY to LINKCC to configure + +- reopmodule.c, regexmodule.c, regexpr.c, zlibmodule.c: needed casts +added to shup up various compilers. + +- _tkinter.c: removed buggy mac #ifndef + +- Doc: various Mac documentation changes, added docs for 'ic' module + +- PC/make_nt.in: deleted + +- test_time.py, test_strftime.py: tweaks to catch %Z (which may return +"") + +- test_rotor.py: print b -> print `b` + +- Tkinter.py: (tagOrId) -> (tagOrId,) + +- Tkinter.py: the Tk class now also has a configure() method and +friends (they have been moved to the Misc class to accomplish this). + +- dict.get(key[, default]) returns dict[key] if it exists, or default +if it doesn't. The default defaults to None. This is quicker for +some applications than using either has_key() or try:...except +KeyError:.... + +- Tools/webchecker/: some small changes to webchecker.py; added +websucker.py (a simple web site mirroring script). + +- Dictionary objects now have a get() method (also in UserDict.py). +dict.get(key, default) returns dict[key] if it exists and default +otherwise; default defaults to None. + +- Tools/scripts/logmerge.py: print the author, too. + +- Changes to import: support for "import a.b.c" is now built in. See +http://grail.cnri.reston.va.us/python/essays/packages.html +for more info. Most important deviations from "ni.py": __init__.py is +executed in the package's namespace instead of as a submodule; and +there's no support for "__" or "__domain__". Note that "ni.py" is not +changed to match this -- it is simply declared obsolete (while at the +same time, it is documented...:-( ). +Unfortunately, "ihooks.py" has not been upgraded (but see "knee.py" +for an example implementation of hierarchical module import written in +Python). + +- More changes to import: the site.py module is now imported by +default when Python is initialized; use -S to disable it. The site.py +module extends the path with several more directories: site-packages +inside the lib/python1.5/ directory, site-python in the lib/ +directory, and pathnames mentioned in *.pth files found in either of +those directories. See +http://grail.cnri.reston.va.us/python/essays/packages.html +for more info. + +- Changes to standard library subdirectory names: those subdirectories +that are not packages have been renamed with a hypen in their name, +e.g. lib-tk, lib-stdwin, plat-win, plat-linux2, plat-sunos5, dos-8x3. +The test suite is now a package -- to run a test, you must now use +"import test.test_foo". + +- A completely new re.py module is provided (thanks to Andrew +Kuchling, Tim Peters and Jeffrey Ollie) which uses Philip Hazel's +"pcre" re compiler and engine. For a while, the "old" re.py (which +was new in 1.5a3!) will be kept around as re1.py. The "old" regex +module and underlying parser and engine are still present -- while +regex is now officially obsolete, it will probably take several major +release cycles before it can be removed. + +- The posix module now has a strerror() function which translates an +error code to a string. + +- The emacs.py module (which was long obsolete) has been removed. + +- The universal makefile Misc/Makefile.pre.in now features an +"install" target. By default, installed shared libraries go into +$exec_prefix/lib/python$VERSION/site-packages/. + +- The install-sh script is installed with the other configuration +specific files (in the config/ subdirectory). + +- It turns out whatsound.py and sndhdr.py were identical modules. +Since there's also an imghdr.py file, I propose to make sndhdr.py the +official one. For compatibility, whatsound.py imports * from +sndhdr.py. + +- Class objects have a new attribute, __module__, giving the name of +the module in which they were declared. This is useful for pickle and +for printing the full name of a class exception. + +- Many extension modules no longer issue a fatal error when their +initialization fails; the importing code now checks whether an error +occurred during module initialization, and correctly propagates the +exception to the import statement. + +- Most extension modules now raise class-based exceptions (except when +-X is used). + +- Subtle changes to PyEval_{Save,Restore}Thread(): always swap the +thread state -- just don't manipulate the lock if it isn't there. + +- Fixed a bug in Python/getopt.c that made it do the wrong thing when +an option was a single '-'. Thanks to Andrew Kuchling. + +- New module mimetypes.py will guess a MIME type from a filename's +extension. + +- Windows: the DLL version is now settable via a resource rather than +being hardcoded. This can be used for "branding" a binary Python +distribution. + +- urllib.py is now threadsafe -- it now uses re instead of regex, and +sys.exc_info() instead of sys.exc_{type,value}. + +- Many other library modules that used to use +sys.exc_{type,value,traceback} are now more thread-safe by virtue of +using sys.exc_info(). + +- The functions in popen2 have an optional buffer size parameter. +Also, the command argument can now be either a string (passed to the +shell) or a list of arguments (passed directly to execv). + +- Alas, the thread support for _tkinter released with 1.5a3 didn't +work. It's been rewritten. The bad news is that it now requires a +modified version of a file in the standard Tcl distribution, which you +must compile with a -I option pointing to the standard Tcl source +tree. For this reason, the thread support is disabled by default. + +- The errno extension module adds two tables: errorcode maps errno +numbers to errno names (e.g. EINTR), and errorstr maps them to +message strings. (The latter is redundant because the new call +posix.strerror() now does the same, but alla...) (Marc-Andre Lemburg) + +- The readline extension module now provides some interfaces to +internal readline routines that make it possible to write a completer +in Python. An example completer, rlcompleter.py, is provided. + + When completing a simple identifier, it completes keywords, + built-ins and globals in __main__; when completing + NAME.NAME..., it evaluates (!) the expression up to the last + dot and completes its attributes. + + It's very cool to do "import string" type "string.", hit the + completion key (twice), and see the list of names defined by + the string module! + + Tip: to use the tab key as the completion key, call + + readline.parse_and_bind("tab: complete") + +- The traceback.py module has a new function tb_lineno() by Marc-Andre +Lemburg which extracts the line number from the linenumber table in +the code object. Apparently the traceback object doesn't contains the +right linenumber when -O is used. Rather than guessing whether -O is +on or off, the module itself uses tb_lineno() unconditionally. + +- Fixed Demo/tkinter/matt/canvas-moving-or-creating.py: change bind() +to tag_bind() so it works again. + +- The pystone script is now a standard library module. Example use: +"import test.pystone; test.pystone.main()". + +- The import of the readline module in interactive mode is now also +attempted when -i is specified. (Yes, I know, giving in to Marc-Andre +Lemburg, who asked for this. :-) + +- rfc822.py: Entirely rewritten parseaddr() function by Sjoerd +Mullender, to be closer to the standard. This fixes the getaddr() +method. Unfortunately, getaddrlist() is as broken as ever, since it +splits on commas without regard for RFC 822 quoting conventions. + +- pprint.py: correctly emit trailing "," in singleton tuples. + +- _tkinter.c: export names for its type objects, TkappType and +TkttType. + +- pickle.py: use __module__ when defined; fix a particularly hard to +reproduce bug that confuses the memo when temporary objects are +returned by custom pickling interfaces; and a semantic change: when +unpickling the instance variables of an instance, use +inst.__dict__.update(value) instead of a for loop with setattr() over +the value.keys(). This is more consistent (the pickling doesn't use +getattr() either but pickles inst.__dict__) and avoids problems with +instances that have a __setattr__ hook. But it *is* a semantic change +(because the setattr hook is no longer used). So beware! + +- config.h is now installed (at last) in +$exec_prefix/include/python1.5/. For most sites, this means that it +is actually in $prefix/include/python1.5/, with all the other Python +include files, since $prefix and $exec_prefix are the same by +default. + +- The imp module now supports parts of the functionality to implement +import of hierarchical module names. It now supports find_module() +and load_module() for all types of modules. Docstrings have been +added for those functions in the built-in imp module that are still +relevant (some old interfaces are obsolete). For a sample +implementation of hierarchical module import in Python, see the new +library module knee.py. + +- The % operator on string objects now allows arbitrary nested parens +in a %(...)X style format. (Brad Howes) + +- Reverse the order in which Setup and Setup.local are passed to the +makesetup script. This allows variable definitions in Setup.local to +override definitions in Setup. (But you'll still have to edit Setup +if you want to disable modules that are enabled by default, or if such +modules need non-standard options.) + +- Added PyImport_ImportModuleEx(name, globals, locals, fromlist); this +is like PyImport_ImporModule(name) but receives the globals and locals +dict and the fromlist arguments as well. (The name is a char*; the +others are PyObject*s). + +- The 'p' format in the struct extension module alloded to above is +new in 1.5a4. + +- The types.py module now uses try-except in a few places to make it +more likely that it can be imported in restricted mode. Some type +names are undefined in that case, e.g. CodeType (inaccessible), +FileType (not always accessible), and TracebackType and FrameType +(inaccessible). + +- In urllib.py: added separate administration of temporary files +created y URLopener.retrieve() so cleanup() can properly remove them. +The old code removed everything in tempcache which was a bad idea if +the user had passed a non-temp file into it. Also, in basejoin(), +interpret relative paths starting in "../". This is necessary if the +server uses symbolic links. + +- The Windows build procedure and project files are now based on +Microsoft Visual C++ 5.x. The build now takes place in the PCbuild +directory. It is much more robust, and properly builds separate Debug +and Release versions. (The installer will be added shortly.) + +- Added casts and changed some return types in regexpr.c to avoid +compiler warnings or errors on some platforms. + +- The AIX build tools for shared libraries now supports VPATH. (Donn +Cave) + +- By default, disable the "portable" multimedia modules audioop, +imageop, and rgbimg, since they don't work on 64-bit platforms. + +- Fixed a nasty bug in cStringIO.c when code was actually using the +close() method (the destructors would try to free certain fields a +second time). + +- For those who think they need it, there's a "user.py" module. This +is *not* imported by default, but can be imported to run user-specific +setup commands, ~/.pythonrc.py. + +- Various speedups suggested by Fredrik Lundh, Marc-Andre Lemburg, +Vladimir Marangozov, and others. + +- Added os.altsep; this is '/' on DOS/Windows, and None on systems +with a sane filename syntax. + +- os.py: Write out the dynamic OS choice, to avoid exec statements. +Adding support for a new OS is now a bit more work, but I bet that +'dos' or 'nt' will cover most situations... + +- The obsolete exception AccessError is now really gone. + +- Tools/faqwiz/: New installation instructions show how to maintain +multiple FAQs. Removed bootstrap script from end of faqwiz.py module. +Added instructions to bootstrap script, too. Version bumped to 0.8.1. +Added <html>...</html> feature suggested by Skip Montanaro. Added +leading text for Roulette, default to 'Hit Reload ...'. Fix typo in +default SRCDIR. + +- Documentation for the relatively new modules "keyword" and "symbol" +has been added (to the end of the section on the parser extension +module). + +- In module bisect.py, but functions have two optional argument 'lo' +and 'hi' which allow you to specify a subsequence of the array to +operate on. + +- In ftplib.py, changed most methods to return their status (even when +it is always "200 OK") rather than swallowing it. + +- main() now calls setlocale(LC_ALL, ""), if setlocale() and +<locale.h> are defined. + +- Changes to configure.in, the configure script, and both +Makefile.pre.in files, to support SGI's SGI_ABI platform selection +environment variable. + + +====================================================================== + + +From 1.4 to 1.5a3 +================= + +Security +-------- + +- If you are using the setuid script C wrapper (Misc/setuid-prog.c), +please use the new version. The old version has a huge security leak. + +Miscellaneous +------------- + +- Because of various (small) incompatible changes in the Python +bytecode interpreter, the magic number for .pyc files has changed +again. + +- The default module search path is now much saner. Both on Unix and +Windows, it is essentially derived from the path to the executable +(which can be overridden by setting the environment variable +$PYTHONHOME). The value of $PYTHONPATH on Windows is now inserted in +front of the default path, like in Unix (instead of overriding the +default path). On Windows, the directory containing the executable is +added to the end of the path. + +- A new version of python-mode.el for Emacs has been included. Also, +a new file ccpy-style.el has been added to configure Emacs cc-mode for +the preferred style in Python C sources. + +- On Unix, when using sys.argv[0] to insert the script directory in +front of sys.path, expand a symbolic link. You can now install a +program in a private directory and have a symbolic link to it in a +public bin directory, and it will put the private directory in the +module search path. Note that the symlink is expanded in sys.path[0] +but not in sys.argv[0], so you can still tell the name by which you +were invoked. + +- It is now recommended to use ``#!/usr/bin/env python'' instead of +``#!/usr/local/bin/python'' at the start of executable scripts, except +for CGI scripts. It has been determined that the use of /usr/bin/env +is more portable than that of /usr/local/bin/python -- scripts almost +never have to be edited when the Python interpreter lives in a +non-standard place. Note that this doesn't work for CGI scripts since +the python executable often doesn't live in the HTTP server's default +search path. + +- The silly -s command line option and the corresponding +PYTHONSUPPRESS environment variable (and the Py_SuppressPrint global +flag in the Python/C API) are gone. + +- Most problems on 64-bit platforms should now be fixed. Andrew +Kuchling helped. Some uncommon extension modules are still not +clean (image and audio ops?). + +- Fixed a bug where multiple anonymous tuple arguments would be mixed up +when using the debugger or profiler (reported by Just van Rossum). +The simplest example is ``def f((a,b),(c,d)): print a,b,c,d''; this +would print the wrong value when run under the debugger or profiler. + +- The hacks that the dictionary implementation used to speed up +repeated lookups of the same C string were removed; these were a +source of subtle problems and don't seem to serve much of a purpose +any longer. + +- All traces of support for the long dead access statement have been +removed from the sources. + +- Plugged the two-byte memory leak in the tokenizer when reading an +interactive EOF. + +- There's a -O option to the interpreter that removes SET_LINENO +instructions and assert statements (see below); it uses and produces +.pyo files instead of .pyc files. The speedup is only a few percent +in most cases. The line numbers are still available in the .pyo file, +as a separate table (which is also available in .pyc files). However, +the removal of the SET_LINENO instructions means that the debugger +(pdb) can't set breakpoints on lines in -O mode. The traceback module +contains a function to extract a line number from the code object +referenced in a traceback object. In the future it should be possible +to write external bytecode optimizers that create better optimized +.pyo files, and there should be more control over optimization; +consider the -O option a "teaser". Without -O, the assert statement +actually generates code that first checks __debug__; if this variable +is false, the assertion is not checked. __debug__ is a built-in +variable whose value is initialized to track the -O flag (it's true +iff -O is not specified). With -O, no code is generated for assert +statements, nor for code of the form ``if __debug__: <something>''. +Sorry, no further constant folding happens. + + +Performance +----------- + +- It's much faster (almost twice for pystone.py -- see +Tools/scripts). See the entry on string interning below. + +- Some speedup by using separate free lists for method objects (both +the C and the Python variety) and for floating point numbers. + +- Big speedup by allocating frame objects with a single malloc() call. +The Python/C API for frames is changed (you shouldn't be using this +anyway). + +- Significant speedup by inlining some common opcodes for common operand +types (e.g. i+i, i-i, and list[i]). Fredrik Lundh. + +- Small speedup by reordering the method tables of some common +objects (e.g. list.append is now first). + +- Big optimization to the read() method of file objects. A read() +without arguments now attempts to use fstat to allocate a buffer of +the right size; for pipes and sockets, it will fall back to doubling +the buffer size. While that the improvement is real on all systems, +it is most dramatic on Windows. + + +Documentation +------------- + +- Many new pieces of library documentation were contributed, mostly by +Andrew Kuchling. Even cmath is now documented! There's also a +chapter of the library manual, "libundoc.tex", which provides a +listing of all undocumented modules, plus their status (e.g. internal, +obsolete, or in need of documentation). Also contributions by Sue +Williams, Skip Montanaro, and some module authors who succumbed to +pressure to document their own contributed modules :-). Note that +printing the documentation now kills fewer trees -- the margins have +been reduced. + +- I have started documenting the Python/C API. Unfortunately this project +hasn't been completed yet. It will be complete before the final release of +Python 1.5, though. At the moment, it's better to read the LaTeX source +than to attempt to run it through LaTeX and print the resulting dvi file. + +- The posix module (and hence os.py) now has doc strings! Thanks to Neil +Schemenauer. I received a few other contributions of doc strings. In most +other places, doc strings are still wishful thinking... + + +Language changes +---------------- + +- Private variables with leading double underscore are now a permanent +feature of the language. (These were experimental in release 1.4. I have +favorable experience using them; I can't label them "experimental" +forever.) + +- There's new string literal syntax for "raw strings". Prefixing a string +literal with the letter r (or R) disables all escape processing in the +string; for example, r'\n' is a two-character string consisting of a +backslash followed by the letter n. This combines with all forms of string +quotes; it is actually useful for triple quoted doc strings which might +contain references to \n or \t. An embedded quote prefixed with a +backslash does not terminate the string, but the backslash is still +included in the string; for example, r'\'' is a two-character string +consisting of a backslash and a quote. (Raw strings are also +affectionately known as Robin strings, after their inventor, Robin +Friedrich.) + +- There's a simple assert statement, and a new exception +AssertionError. For example, ``assert foo > 0'' is equivalent to ``if +not foo > 0: raise AssertionError''. Sorry, the text of the asserted +condition is not available; it would be too complicated to generate +code for this (since the code is generated from a parse tree). +However, the text is displayed as part of the traceback! + +- The raise statement has a new feature: when using "raise SomeClass, +somevalue" where somevalue is not an instance of SomeClass, it +instantiates SomeClass(somevalue). In 1.5a4, if somevalue is an +instance of a *derived* class of SomeClass, the exception class raised +is set to somevalue.__class__, and SomeClass is ignored after that. + +- Duplicate keyword arguments are now detected at compile time; +f(a=1,a=2) is now a syntax error. + + +Changes to builtin features +--------------------------- + +- There's a new exception FloatingPointError (used only by Lee Busby's +patches to catch floating point exceptions, at the moment). + +- The obsolete exception ConflictError (presumably used by the long +obsolete access statement) has been deleted. + +- There's a new function sys.exc_info() which returns the tuple +(sys.exc_type, sys.exc_value, sys.exc_traceback) in a thread-safe way. + +- There's a new variable sys.executable, pointing to the executable file +for the Python interpreter. + +- The sort() methods for lists no longer uses the C library qsort(); I +wrote my own quicksort implementation, with lots of help (in the form +of a kind of competition) from Tim Peters. This solves a bug in +dictionary comparisons on some Solaris versions when Python is built +with threads, and makes sorting lists even faster. + +- The semantics of comparing two dictionaries have changed, to make +comparison of unequal dictionaries faster. A shorter dictionary is +always considered smaller than a larger dictionary. For dictionaries +of the same size, the smallest differing element determines the +outcome (which yields the same results as before in this case, without +explicit sorting). Thanks to Aaron Watters for suggesting something +like this. + +- The semantics of try-except have changed subtly so that calling a +function in an exception handler that itself raises and catches an +exception no longer overwrites the sys.exc_* variables. This also +alleviates the problem that objects referenced in a stack frame that +caught an exception are kept alive until another exception is caught +-- the sys.exc_* variables are restored to their previous value when +returning from a function that caught an exception. + +- There's a new "buffer" interface. Certain objects (e.g. strings and +arrays) now support the "buffer" protocol. Buffer objects are acceptable +whenever formerly a string was required for a write operation; mutable +buffer objects can be the target of a read operation using the call +f.readinto(buffer). A cool feature is that regular expression matching now +also work on array objects. Contribution by Jack Jansen. (Needs +documentation.) + +- String interning: dictionary lookups are faster when the lookup +string object is the same object as the key in the dictionary, not +just a string with the same value. This is done by having a pool of +"interned" strings. Most names generated by the interpreter are now +automatically interned, and there's a new built-in function intern(s) +that returns the interned version of a string. Interned strings are +not a different object type, and interning is totally optional, but by +interning most keys a speedup of about 15% was obtained for the +pystone benchmark. + +- Dictionary objects have several new methods; clear() and copy() have +the obvious semantics, while update(d) merges the contents of another +dictionary d into this one, overriding existing keys. The dictionary +implementation file is now called dictobject.c rather than the +confusing mappingobject.c. + +- The intrinsic function dir() is much smarter; it looks in __dict__, +__members__ and __methods__. + +- The intrinsic functions int(), long() and float() can now take a +string argument and then do the same thing as string.atoi(), +string.atol(), and string.atof(). No second 'base' argument is +allowed, and complex() does not take a string (nobody cared enough). + +- When a module is deleted, its globals are now deleted in two phases. +In the first phase, all variables whose name begins with exactly one +underscore are replaced by None; in the second phase, all variables +are deleted. This makes it possible to have global objects whose +destructors depend on other globals. The deletion order within each +phase is still random. + +- It is no longer an error for a function to be called without a +global variable __builtins__ -- an empty directory will be provided +by default. + +- Guido's corollary to the "Don Beaudry hook": it is now possible to +do metaprogramming by using an instance as a base class. Not for the +faint of heart; and undocumented as yet, but basically if a base class +is an instance, its class will be instantiated to create the new +class. Jim Fulton will love it -- it also works with instances of his +"extension classes", since it is triggered by the presence of a +__class__ attribute on the purported base class. See +Demo/metaclasses/index.html for an explanation and see that directory +for examples. + +- Another change is that the Don Beaudry hook is now invoked when +*any* base class is special. (Up to 1.5a3, the *last* special base +class is used; in 1.5a4, the more rational choice of the *first* +special base class is used.) + +- New optional parameter to the readlines() method of file objects. +This indicates the number of bytes to read (the actual number of bytes +read will be somewhat larger due to buffering reading until the end of +the line). Some optimizations have also been made to speed it up (but +not as much as read()). + +- Complex numbers no longer have the ".conj" pseudo attribute; use +z.conjugate() instead, or complex(z.real, -z.imag). Complex numbers +now *do* support the __members__ and __methods__ special attributes. + +- The complex() function now looks for a __complex__() method on class +instances before giving up. + +- Long integers now support arbitrary shift counts, so you can now +write 1L<<1000000, memory permitting. (Python 1.4 reports "outrageous +shift count for this.) + +- The hex() and oct() functions have been changed so that for regular +integers, they never emit a minus sign. For example, on a 32-bit +machine, oct(-1) now returns '037777777777' and hex(-1) returns +'0xffffffff'. While this may seem inconsistent, it is much more +useful. (For long integers, a minus sign is used as before, to fit +the result in memory :-) + +- The hash() function computes better hashes for several data types, +including strings, floating point numbers, and complex numbers. + + +New extension modules +--------------------- + +- New extension modules cStringIO.c and cPickle.c, written by Jim +Fulton and other folks at Digital Creations. These are much more +efficient than their Python counterparts StringIO.py and pickle.py, +but don't support subclassing. cPickle.c clocks up to 1000 times +faster than pickle.py; cStringIO.c's improvement is less dramatic but +still significant. + +- New extension module zlibmodule.c, interfacing to the free zlib +library (gzip compatible compression). There's also a module gzip.py +which provides a higher level interface. Written by Andrew Kuchling +and Jeremy Hylton. + +- New module readline; see the "miscellaneous" section above. + +- New Unix extension module resource.c, by Jeremy Hylton, provides +access to getrlimit(), getrusage(), setrusage(), getpagesize(), and +related symbolic constants. + +- New extension puremodule.c, by Barry Warsaw, which interfaces to the +Purify(TM) C API. See also the file Misc/PURIFY.README. It is also +possible to enable Purify by simply setting the PURIFY Makefile +variable in the Modules/Setup file. + + +Changes in extension modules +---------------------------- + +- The struct extension module has several new features to control byte +order and word size. It supports reading and writing IEEE floats even +on platforms where this is not the native format. It uses uppercase +format codes for unsigned integers of various sizes (always using +Python long ints for 'I' and 'L'), 's' with a size prefix for strings, +and 'p' for "Pascal strings" (with a leading length byte, included in +the size; blame Hannu Krosing; new in 1.5a4). A prefix '>' forces +big-endian data and '<' forces little-endian data; these also select +standard data sizes and disable automatic alignment (use pad bytes as +needed). + +- The array module supports uppercase format codes for unsigned data +formats (like the struct module). + +- The fcntl extension module now exports the needed symbolic +constants. (Formerly these were in FCNTL.py which was not available +or correct for all platforms.) + +- The extension modules dbm, gdbm and bsddb now check that the +database is still open before making any new calls. + +- The dbhash module is no more. Use bsddb instead. (There's a third +party interface for the BSD 2.x code somewhere on the web; support for +bsddb will be deprecated.) + +- The gdbm module now supports a sync() method. + +- The socket module now has some new functions: getprotobyname(), and +the set {ntoh,hton}{s,l}(). + +- Various modules now export their type object: socket.SocketType, +array.ArrayType. + +- The socket module's accept() method now returns unknown addresses as +a tuple rather than raising an exception. (This can happen in +promiscuous mode.) Theres' also a new function getprotobyname(). + +- The pthread support for the thread module now works on most platforms. + +- STDWIN is now officially obsolete. Support for it will eventually +be removed from the distribution. + +- The binascii extension module is now hopefully fully debugged. +(XXX Oops -- Fredrik Lundh promised me a uuencode fix that I never +received.) + +- audioop.c: added a ratecv() function; better handling of overflow in +add(). + +- posixmodule.c: now exports the O_* flags (O_APPEND etc.). On +Windows, also O_TEXT and O_BINARY. The 'error' variable (the +exception is raises) is renamed -- its string value is now "os.error", +so newbies don't believe they have to import posix (or nt) to catch +it when they see os.error reported as posix.error. The execve() +function now accepts any mapping object for the environment. + +- A new version of the al (audio library) module for SGI was +contributed by Sjoerd Mullender. + +- The regex module has a new function get_syntax() which retrieves the +syntax setting set by set_syntax(). The code was also sanitized, +removing worries about unclean error handling. See also below for its +successor, re.py. + +- The "new" module (which creates new objects of various types) once +again has a fully functioning new.function() method. Dangerous as +ever! Also, new.code() has several new arguments. + +- A problem has been fixed in the rotor module: on systems with signed +characters, rotor-encoded data was not portable when the key contained +8-bit characters. Also, setkey() now requires its argument rather +than having broken code to default it. + +- The sys.builtin_module_names variable is now a tuple. Another new +variables in sys is sys.executable (the full path to the Python +binary, if known). + +- The specs for time.strftime() have undergone some revisions. It +appears that not all format characters are supported in the same way +on all platforms. Rather than reimplement it, we note these +differences in the documentation, and emphasize the shared set of +features. There's also a thorough test set (that occasionally finds +problems in the C library implementation, e.g. on some Linuxes), +thanks to Skip Montanaro. + +- The nis module seems broken when used with NIS+; unfortunately +nobody knows how to fix it. It should still work with old NIS. + + +New library modules +------------------- + +- New (still experimental) Perl-style regular expression module, +re.py, which uses a new interface for matching as well as a new +syntax; the new interface avoids the thread-unsafety of the regex +interface. This comes with a helper extension reopmodule.c and vastly +rewritten regexpr.c. Most work on this was done by Jeffrey Ollie, Tim +Peters, and Andrew Kuchling. See the documentation libre.tex. In +1.5, the old regex module is still fully supported; in the future, it +will become obsolete. + +- New module gzip.py; see zlib above. + +- New module keyword.py exports knowledge about Python's built-in +keywords. (New version by Ka-Ping Yee.) + +- New module pprint.py (with documentation) which supports +pretty-printing of lists, tuples, & dictionaries recursively. By Fred +Drake. + +- New module code.py. The function code.compile_command() can +determine whether an interactively entered command is complete or not, +distinguishing incomplete from invalid input. (XXX Unfortunately, +this seems broken at this moment, and I don't have the time to fix +it. It's probably better to add an explicit interface to the parser +for this.) + +- There is now a library module xdrlib.py which can read and write the +XDR data format as used by Sun RPC, for example. It uses the struct +module. + + +Changes in library modules +-------------------------- + +- Module codehack.py is now completely obsolete. + +- The pickle.py module has been updated to make it compatible with the +new binary format that cPickle.c produces. By default it produces the +old all-ASCII format compatible with the old pickle.py, still much +faster than pickle.py; it will read both formats automatically. A few +other updates have been made. + +- A new helper module, copy_reg.py, is provided to register extensions +to the pickling code. + +- Revamped module tokenize.py is much more accurate and has an +interface that makes it a breeze to write code to colorize Python +source code. Contributed by Ka-Ping Yee. + +- In ihooks.py, ModuleLoader.load_module() now closes the file under +all circumstances. + +- The tempfile.py module has a new class, TemporaryFile, which creates +an open temporary file that will be deleted automatically when +closed. This works on Windows and MacOS as well as on Unix. (Jim +Fulton.) + +- Changes to the cgi.py module: Most imports are now done at the +top of the module, which provides a speedup when using ni (Jim +Fulton). The problem with file upload to a Windows platform is solved +by using the new tempfile.TemporaryFile class; temporary files are now +always opened in binary mode (Jim Fulton). The cgi.escape() function +now takes an optional flag argument that quotes '"' to '&quot;'. It +is now possible to invoke cgi.py from a command line script, to test +cgi scripts more easily outside an http server. There's an optional +limit to the size of uploads to POST (Skip Montanaro). Added a +'strict_parsing' option to all parsing functions (Jim Fulton). The +function parse_qs() now uses urllib.unquote() on the name as well as +the value of fields (Clarence Gardner). The FieldStorage class now +has a __len__() method. + +- httplib.py: the socket object is no longer closed; all HTTP/1.* +responses are now accepted; and it is now thread-safe (by not using +the regex module). + +- BaseHTTPModule.py: treat all HTTP/1.* versions the same. + +- The popen2.py module is now rewritten using a class, which makes +access to the standard error stream and the process id of the +subprocess possible. + +- Added timezone support to the rfc822.py module, in the form of a +getdate_tz() method and a parsedate_tz() function; also a mktime_tz(). +Also added recognition of some non-standard date formats, by Lars +Wirzenius, and RFC 850 dates (Chris Lawrence). + +- mhlib.py: various enhancements, including almost compatible parsing +of message sequence specifiers without invoking a subprocess. Also +added a createmessage() method by Lars Wirzenius. + +- The StringIO.StringIO class now supports readline(nbytes). (Lars +Wirzenius.) (Of course, you should be using cStringIO for performance.) + +- UserDict.py supports the new dictionary methods as well. + +- Improvements for whrandom.py by Tim Peters: use 32-bit arithmetic to +speed it up, and replace 0 seed values by 1 to avoid degeneration. +A bug was fixed in the test for invalid arguments. + +- Module ftplib.py: added support for parsing a .netrc file (Fred +Drake). Also added an ntransfercmd() method to the FTP class, which +allows access to the expected size of a transfer when available, and a +parse150() function to the module which parses the corresponding 150 +response. + +- urllib.py: the ftp cache is now limited to 10 entries. Added +quote_plus() and unquote_plus() functions which are like quote() and +unquote() but also replace spaces with '+' or vice versa, for +encoding/decoding CGI form arguments. Catch all errors from the ftp +module. HTTP requests now add the Host: header line. The proxy +variable names are now mapped to lower case, for Windows. The +spliturl() function no longer erroneously throws away all data past +the first newline. The basejoin() function now intereprets "../" +correctly. I *believe* that the problems with "exception raised in +__del__" under certain circumstances have been fixed (mostly by +changes elsewher in the interpreter). + +- In urlparse.py, there is a cache for results in urlparse.urlparse(); +its size limit is set to 20. Also, new URL schemes shttp, https, and +snews are "supported". + +- shelve.py: use cPickle and cStringIO when available. Also added +a sync() method, which calls the database's sync() method if there is +one. + +- The mimetools.py module now uses the available Python modules for +decoding quoted-printable, uuencode and base64 formats, rather than +creating a subprocess. + +- The python debugger (pdb.py, and its base class bdb.py) now support +conditional breakpoints. See the docs. + +- The modules base64.py, uu.py and quopri.py can now be used as simple +command line utilities. + +- Various small fixes to the nntplib.py module that I can't bother to +document in detail. + +- Sjoerd Mullender's mimify.py module now supports base64 encoding and +includes functions to handle the funny encoding you sometimes see in mail +headers. It is now documented. + +- mailbox.py: Added BabylMailbox. Improved the way the mailbox is +gotten from the environment. + +- Many more modules now correctly open files in binary mode when this +is necessary on non-Unix platforms. + +- The copying functions in the undocumented module shutil.py are +smarter. + +- The Writer classes in the formatter.py module now have a flush() +method. + +- The sgmllib.py module accepts hyphens and periods in the middle of +attribute names. While this is against the SGML standard, there is +some HTML out there that uses this... + +- The interface for the Python bytecode disassembler module, dis.py, +has been enhanced quite a bit. There's now one main function, +dis.dis(), which takes almost any kind of object (function, module, +class, instance, method, code object) and disassembles it; without +arguments it disassembles the last frame of the last traceback. The +other functions have changed slightly, too. + +- The imghdr.py module recognizes new image types: BMP, PNG. + +- The string.py module has a new function replace(str, old, new, +[maxsplit]) which does substring replacements. It is actually +implemented in C in the strop module. The functions [r]find() an +[r]index() have an optional 4th argument indicating the end of the +substring to search, alsoo implemented by their strop counterparts. +(Remember, never import strop -- import string uses strop when +available with zero overhead.) + +- The string.join() function now accepts any sequence argument, not +just lists and tuples. + +- The string.maketrans() requires its first two arguments to be +present. The old version didn't require them, but there's not much +point without them, and the documentation suggests that they are +required, so we fixed the code to match the documentation. + +- The regsub.py module has a function clear_cache(), which clears its +internal cache of compiled regular expressions. Also, the cache now +takes the current syntax setting into account. (However, this module +is now obsolete -- use the sub() or subn() functions or methods in the +re module.) + +- The undocumented module Complex.py has been removed, now that Python +has built-in complex numbers. A similar module remains as +Demo/classes/Complex.py, as an example. + + +Changes to the build process +---------------------------- + +- The way GNU readline is configured is totally different. The +--with-readline configure option is gone. It is now an extension +module, which may be loaded dynamically. You must enable it (and +specify the correct linraries to link with) in the Modules/Setup file. +Importing the module installs some hooks which enable command line +editing. When the interpreter shell is invoked interactively, it +attempts to import the readline module; when this fails, the default +input mechanism is used. The hook variables are PyOS_InputHook and +PyOS_ReadlineFunctionPointer. (Code contributed by Lee Busby, with +ideas from William Magro.) + +- New build procedure: a single library, libpython1.5.a, is now built, +which contains absolutely everything except for a one-line main() +program (which calls Py_Main(argc, argv) to start the interpreter +shell). This makes life much simpler for applications that need to +embed Python. The serial number of the build is now included in the +version string (sys.version). + +- As far as I can tell, neither gcc -Wall nor the Microsoft compiler +emits a single warning any more when compiling Python. + +- A number of new Makefile variables have been added for special +situations, e.g. LDLAST is appended to the link command. These are +used by editing the Makefile or passing them on the make command +line. + +- A set of patches from Lee Busby has been integrated that make it +possible to catch floating point exceptions. Use the configure option +--with-fpectl to enable the patches; the extension modules fpectl and +fpetest provide control to enable/disable and test the feature, +respectively. + +- The support for shared libraries under AIX is now simpler and more +robust. Thanks to Vladimir Marangozov for revamping his own patches! + +- The Modules/makesetup script now reads a file Setup.local as well as +a file Setup. Most changes to the Setup script can be done by editing +Setup.local instead, which makes it easier to carry a particular setup +over from one release to the next. + +- The Modules/makesetup script now copies any "include" lines it +encounters verbatim into the output Makefile. It also recognizes .cxx +and .cpp as C++ source files. + +- The configure script is smarter about C compiler options; e.g. with +gcc it uses -O2 and -g when possible, and on some other platforms it +uses -Olimit 1500 to avoid a warning from the optimizer about the main +loop in ceval.c (which has more than 1000 basic blocks). + +- The configure script now detects whether malloc(0) returns a NULL +pointer or a valid block (of length zero). This avoids the nonsense +of always adding one byte to all malloc() arguments on most platforms. + +- The configure script has a new option, --with-dec-threads, to enable +DEC threads on DEC Alpha platforms. Also, --with-threads is now an +alias for --with-thread (this was the Most Common Typo in configure +arguments). + +- Many changes in Doc/Makefile; amongst others, latex2html is now used +to generate HTML from all latex documents. + + +Change to the Python/C API +-------------------------- + +- Because some interfaces have changed, the PYTHON_API macro has been +bumped. Most extensions built for the old API version will still run, +but I can't guarantee this. Python prints a warning message on +version mismatches; it dumps core when the version mismatch causes a +serious problem :-) + +- I've completed the Grand Renaming, with the help of Roger Masse and +Barry Warsaw. This makes reading or debugging the code much easier. +Many other unrelated code reorganizations have also been carried out. +The allobjects.h header file is gone; instead, you would have to +include Python.h followed by rename2.h. But you're better off running +Tools/scripts/fixcid.py -s Misc/RENAME on your source, so you can omit +the rename2.h; it will disappear in the next release. + +- Various and sundry small bugs in the "abstract" interfaces have been +fixed. Thanks to all the (involuntary) testers of the Python 1.4 +version! Some new functions have been added, e.g. PySequence_List(o), +equivalent to list(o) in Python. + +- New API functions PyLong_FromUnsignedLong() and +PyLong_AsUnsignedLong(). + +- The API functions in the file cgensupport.c are no longer +supported. This file has been moved to Modules and is only ever +compiled when the SGI specific 'gl' module is built. + +- PyObject_Compare() can now raise an exception. Check with +PyErr_Occurred(). The comparison function in an object type may also +raise an exception. + +- The slice interface uses an upper bound of INT_MAX when no explicit +upper bound is given (e.x. for a[1:]). It used to ask the object for +its length and do the calculations. + +- Support for multiple independent interpreters. See Doc/api.tex, +functions Py_NewInterpreter() and Py_EndInterpreter(). Since the +documentation is incomplete, also see the new Demo/pysvr example +(which shows how to use these in a threaded application) and the +source code. + +- There is now a Py_Finalize() function which "de-initializes" +Python. It is possible to completely restart the interpreter +repeatedly by calling Py_Finalize() followed by Py_Initialize(). A +change of functionality in Py_Initialize() means that it is now a +fatal error to call it while the interpreter is already initialized. +The old, half-hearted Py_Cleanup() routine is gone. Use of Py_Exit() +is deprecated (it is nothing more than Py_Finalize() followed by +exit()). + +- There are no known memory leaks left. While Py_Finalize() doesn't +free *all* allocated memory (some of it is hard to track down), +repeated calls to Py_Finalize() and Py_Initialize() do not create +unaccessible heap blocks. + +- There is now explicit per-thread state. (Inspired by, but not the +same as, Greg Stein's free threading patches.) + +- There is now better support for threading C applications. There are +now explicit APIs to manipulate the interpreter lock. Read the source +or the Demo/pysvr example; the new functions are +PyEval_{Acquire,Release}{Lock,Thread}(). + +- The test macro DEBUG has changed to Py_DEBUG, to avoid interference +with other libraries' DEBUG macros. Likewise for any other test +macros that didn't yet start with Py_. + +- New wrappers around malloc() and friends: Py_Malloc() etc. call +malloc() and call PyErr_NoMemory() when it fails; PyMem_Malloc() call +just malloc(). Use of these wrappers could be essential if multiple +memory allocators exist (e.g. when using certain DLL setups under +Windows). (Idea by Jim Fulton.) + +- New C API PyImport_Import() which uses whatever __import__() hook +that is installed for the current execution environment. By Jim +Fulton. + +- It is now possible for an extension module's init function to fail +non-fatally, by calling one of the PyErr_* functions and returning. + +- The PyInt_AS_LONG() and PyFloat_AS_DOUBLE() macros now cast their +argument to the proper type, like the similar PyString macros already +did. (Suggestion by Marc-Andre Lemburg.) Similar for PyList_GET_SIZE +and PyList_GET_ITEM. + +- Some of the Py_Get* function, like Py_GetVersion() (but not yet +Py_GetPath()) are now declared as returning a const char *. (More +should follow.) + +- Changed the run-time library to check for exceptions after object +comparisons. PyObject_Compare() can now return an exception; use +PyErr_Occurred() to check (there is *no* special return value). + +- PyFile_WriteString() and Py_Flushline() now return error indicators +instead of clearing exceptions. This fixes an obscure bug where using +these would clear a pending exception, discovered by Just van Rossum. + +- There's a new function, PyArg_ParseTupleAndKeywords(), which parses +an argument list including keyword arguments. Contributed by Geoff +Philbrick. + +- PyArg_GetInt() is gone. + +- It's no longer necessary to include graminit.h when calling one of +the extended parser API functions. The three public grammar start +symbols are now in Python.h as Py_single_input, Py_file_input, and +Py_eval_input. + +- The CObject interface has a new function, +PyCObject_Import(module, name). It calls PyCObject_AsVoidPtr() +on the object referenced by "module.name". + + +Tkinter +------- + +- On popular demand, _tkinter once again installs a hook for readline +that processes certain Tk events while waiting for the user to type +(using PyOS_InputHook). + +- A patch by Craig McPheeters plugs the most obnoxious memory leaks, +caused by command definitions referencing widget objects beyond their +lifetime. + +- New standard dialog modules: tkColorChooser.py, tkCommonDialog.py, +tkMessageBox.py, tkFileDialog.py, tkSimpleDialog.py These interface +with the new Tk dialog scripts, and provide more "native platform" +style file selection dialog boxes on some platforms. Contributed by +Fredrik Lundh. + +- Tkinter.py: when the first Tk object is destroyed, it sets the +hiddel global _default_root to None, so that when another Tk object is +created it becomes the new default root. Other miscellaneous +changes and fixes. + +- The Image class now has a configure method. + +- Added a bunch of new winfo options to Tkinter.py; we should now be +up to date with Tk 4.2. The new winfo options supported are: +mananger, pointerx, pointerxy, pointery, server, viewable, visualid, +visualsavailable. + +- The broken bind() method on Canvas objects defined in the Canvas.py +module has been fixed. The CanvasItem and Group classes now also have +an unbind() method. + +- The problem with Tkinter.py falling back to trying to import +"tkinter" when "_tkinter" is not found has been fixed -- it no longer +tries "tkinter", ever. This makes diagnosing the problem "_tkinter +not configured" much easier and will hopefully reduce the newsgroup +traffic on this topic. + +- The ScrolledText module once again supports the 'cnf' parameter, to +be compatible with the examples in Mark Lutz' book (I know, I know, +too late...) + +- The _tkinter.c extension module has been revamped. It now support +Tk versions 4.1 through 8.0; support for 4.0 has been dropped. It +works well under Windows and Mac (with the latest Tk ports to those +platforms). It also supports threading -- it is safe for one +(Python-created) thread to be blocked in _tkinter.mainloop() while +other threads modify widgets. To make the changes visible, those +threads must use update_idletasks()method. (The patch for threading +in 1.5a3 was broken; in 1.5a4, it is back in a different version, +which requires access to the Tcl sources to get it to work -- hence it +is disabled by default.) + +- A bug in _tkinter.c has been fixed, where Split() with a string +containing an unmatched '"' could cause an exception or core dump. + +- Unfortunately, on Windows and Mac, Tk 8.0 no longer supports +CreateFileHandler, so _tkinter.createfilehandler is not available on +those platforms when using Tk 8.0 or later. I will have to rethink +how to interface with Tcl's lower-level event mechanism, or with its +channels (which are like Python's file-like objects). Jack Jansen has +provided a fix for the Mac, so createfilehandler *is* actually +supported there; maybe I can adapt his fix for Windows. + + +Tools and Demos +--------------- + +- A new regression test suite is provided, which tests most of the +standard and built-in modules. The regression test is run by invoking +the script Lib/test/regrtest.py. Barry Warsaw wrote the test harnass; +he and Roger Masse contributed most of the new tests. + +- New tool: faqwiz -- the CGI script that is used to maintain the +Python FAQ (http://grail.cnri.reston.va.us/cgi-bin/faqw.py). In +Tools/faqwiz. + +- New tool: webchecker -- a simple extensible web robot that, when +aimed at a web server, checks that server for dead links. Available +are a command line utility as well as a Tkinter based GUI version. In +Tools/webchecker. A simplified version of this program is dissected +in my article in O'Reilly's WWW Journal, the issue on Scripting +Languages (Vol 2, No 2); Scripting the Web with Python (pp 97-120). +Includes a parser for robots.txt files by Skip Montanaro. + +- New small tools: cvsfiles.py (prints a list of all files under CVS +n a particular directory tree), treesync.py (a rather Guido-specific +script to synchronize two source trees, one on Windows NT, the other +one on Unix under CVS but accessible from the NT box), and logmerge.py +(sort a collection of RCS or CVS logs by date). In Tools/scripts. + +- The freeze script now also works under Windows (NT). Another +feature allows the -p option to be pointed at the Python source tree +instead of the installation prefix. This was loosely based on part of +xfreeze by Sam Rushing and Bill Tutt. + +- New examples (Demo/extend) that show how to use the generic +extension makefile (Misc/Makefile.pre.in). + +- Tools/scripts/h2py.py now supports C++ comments. + +- Tools/scripts/pystone.py script is upgraded to version 1.1; there +was a bug in version 1.0 (distributed with Python 1.4) that leaked +memory. Also, in 1.1, the LOOPS variable is incremented to 10000. + +- Demo/classes/Rat.py completely rewritten by Sjoerd Mullender. + + +Windows (NT and 95) +------------------- + +- New project files for Developer Studio (Visual C++) 5.0 for Windows +NT (the old VC++ 4.2 Makefile is also still supported, but will +eventually be withdrawn due to its bulkiness). + +- See the note on the new module search path in the "Miscellaneous" section +above. + +- Support for Win32s (the 32-bit Windows API under Windows 3.1) is +basically withdrawn. If it still works for you, you're lucky. + +- There's a new extension module, msvcrt.c, which provides various +low-level operations defined in the Microsoft Visual C++ Runtime Library. +These include locking(), setmode(), get_osfhandle(), set_osfhandle(), and +console I/O functions like kbhit(), getch() and putch(). + +- The -u option not only sets the standard I/O streams to unbuffered +status, but also sets them in binary mode. (This can also be done +using msvcrt.setmode(), by the way.) + +- The, sys.prefix and sys.exec_prefix variables point to the directory +where Python is installed, or to the top of the source tree, if it was run +from there. + +- The various os.path modules (posixpath, ntpath, macpath) now support +passing more than two arguments to the join() function, so +os.path.join(a, b, c) is the same as os.path.join(a, os.path.join(b, +c)). + +- The ntpath module (normally used as os.path) supports ~ to $HOME +expansion in expanduser(). + +- The freeze tool now works on Windows. + +- See also the Tkinter category for a sad note on +_tkinter.createfilehandler(). + +- The truncate() method for file objects now works on Windows. + +- Py_Initialize() is no longer called when the DLL is loaded. You +must call it yourself. + +- The time module's clock() function now has good precision through +the use of the Win32 API QueryPerformanceCounter(). + +- Mark Hammond will release Python 1.5 versions of PythonWin and his +other Windows specific code: the win32api extensions, COM/ActiveX +support, and the MFC interface. + + +Mac +--- + +- As always, the Macintosh port will be done by Jack Jansen. He will +make a separate announcement for the Mac specific source code and the +binary distribution(s) when these are ready. + + +====================================================================== + + +===================================== +==> Release 1.4 (October 25 1996) <== +===================================== + +(Starting in reverse chronological order:) + +- Changed disclaimer notice. + +- Added SHELL=/bin/sh to Misc/Makefile.pre.in -- some Make versions +default to the user's login shell. + +- In Lib/tkinter/Tkinter.py, removed bogus binding of <Delete> in Text +widget, and bogus bspace() function. + +- In Lib/cgi.py, bumped __version__ to 2.0 and restored a truncated +paragraph. + +- Fixed the NT Makefile (PC/vc40.mak) for VC 4.0 to set /MD for all +subprojects, and to remove the (broken) experimental NumPy +subprojects. + +- In Lib/py_compile.py, cast mtime to long() so it will work on Mac +(where os.stat() returns mtimes as floats.) +- Set self.rfile unbuffered (like self.wfile) in SocketServer.py, to +fix POST in CGIHTTPServer.py. + +- Version 2.83 of Misc/python-mode.el for Emacs is included. + +- In Modules/regexmodule.c, fixed symcomp() to correctly handle a new +group starting immediately after a group tag. + +- In Lib/SocketServer.py, changed the mode for rfile to unbuffered. + +- In Objects/stringobject.c, fixed the compare function to do the +first char comparison in unsigned mode, for consistency with the way +other characters are compared by memcmp(). + +- In Lib/tkinter/Tkinter.py, fixed Scale.get() to support floats. + +- In Lib/urllib.py, fix another case where openedurl wasn't set. + +(XXX Sorry, the rest is in totally random order. No time to fix it.) + +- SyntaxError exceptions detected during code generation +(e.g. assignment to an expression) now include a line number. + +- Don't leave trailing / or \ in script directory inserted in front of +sys.path. + +- Added a note to Tools/scripts/classfix.py abouts its historical +importance. + +- Added Misc/Makefile.pre.in, a universal Makefile for extensions +built outside the distribution. + +- Rewritten Misc/faq2html.py, by Ka-Ping Yee. + +- Install shared modules with mode 555 (needed for performance on some +platforms). + +- Some changes to standard library modules to avoid calling append() +with more than one argument -- while supported, this should be +outlawed, and I don't want to set a bad example. + +- bdb.py (and hence pdb.py) supports calling run() with a code object +instead of a code string. + +- Fixed an embarrassing bug cgi.py which prevented correct uploading +of binary files from Netscape (which doesn't distinguish between +binary and text files). Also added dormant logging support, which +makes it easier to debug the cgi module itself. + +- Added default writer to constructor of NullFormatter class. + +- Use binary mode for socket.makefile() calls in ftplib.py. + +- The ihooks module no longer "installs" itself upon import -- this +was an experimental feature that helped ironing out some bugs but that +slowed down code that imported it without the need to install it +(e.g. the rexec module). Also close the file in some cases and add +the __file__ attribute to loaded modules. + +- The test program for mailbox.py is now more useful. + +- Added getparamnames() to Message class in mimetools.py -- it returns +the names of parameters to the content-type header. + +- Fixed a typo in ni that broke the loop stripping "__." from names. + +- Fix sys.path[0] for scripts run via pdb.py's new main program. + +- profile.py can now also run a script, like pdb. + +- Fix a small bug in pyclbr -- don't add names starting with _ when +emulating from ... import *. + +- Fixed a series of embarrassing typos in rexec's handling of standard +I/O redirection. Added some more "safe" built-in modules: cmath, +errno, operator. + +- Fixed embarrassing typo in shelve.py. + +- Added SliceType and EllipsisType to types.py. + +- In urllib.py, added handling for error 301 (same as 302); added +geturl() method to get the URL after redirection. + +- Fixed embarrassing typo in xdrlib.py. Also fixed typo in Setup.in +for _xdrmodule.c and removed redundant #include from _xdrmodule.c. + +- Fixed bsddbmodule.c to add binary mode indicator on platforms that +have it. This should make it working on Windows NT. + +- Changed last uses of #ifdef NT to #ifdef MS_WINDOWS or MS_WIN32, +whatever applies. Also rationalized some other tests for various MS +platforms. + +- Added the sources for the NT installer script used for Python +1.4beta3. Not tested with this release, but better than nothing. + +- A compromise in pickle's defenses against Trojan horses: a +user-defined function is now okay where a class is expected. A +built-in function is not okay, to prevent pickling something that +will execute os.system("rm -f *") when unpickling. + +- dis.py will print the name of local variables referenced by local +load/store/delete instructions. + +- Improved portability of SimpleHTTPServer module to non-Unix +platform. + +- The thread.h interface adds an extra argument to down_sema(). This +only affects other C code that uses thread.c; the Python thread module +doesn't use semaphores (which aren't provided on all platforms where +Python threads are supported). Note: on NT, this change is not +implemented. + +- Fixed some typos in abstract.h; corrected signature of +PyNumber_Coerce, added PyMapping_DelItem. Also fixed a bug in +abstract.c's PyObject_CallMethod(). + +- apply(classname, (), {}) now works even if the class has no +__init__() method. + +- Implemented complex remainder and divmod() (these would dump core!). +Conversion of complex numbers to int, long int or float now raises an +exception, since there is no meaningful way to do it without losing +information. + +- Fixed bug in built-in complex() function which gave the wrong result +for two real arguments. + +- Change the hash algorithm for strings -- the multiplier is now +1000003 instead of 3, which gives better spread for short strings. + +- New default path for Windows NT, the registry structure now supports +default paths for different install packages. (Mark Hammond -- the +next PythonWin release will use this.) + +- Added more symbols to the python_nt.def file. + +- When using GNU readline, set rl_readline_name to "python". + +- The Ellipses built-in name has been renamed to Ellipsis -- this is +the correct singular form. Thanks to Ka-Ping Yee, who saved us from +eternal embarrassment. + +- Bumped the PYTHON_API_VERSION to 1006, due to the Ellipses -> +Ellipsis name change. + +- Updated the library reference manual. Added documentation of +restricted mode (rexec, Bastion) and the formatter module (for use +with the htmllib module). Fixed the documentation of htmllib +(finally). + +- The reference manual is now maintained in FrameMaker. + +- Upgraded scripts Doc/partparse.py and Doc/texi2html.py. + +- Slight improvements to Doc/Makefile. + +- Added fcntl.lockf(). This should be used for Unix file locking +instead of the posixfile module; lockf() is more portable. + +- The getopt module now supports long option names, thanks to Lars +Wizenius. + +- Plenty of changes to Tkinter and Canvas, mostly due to Fred Drake +and Nils Fischbeck. + +- Use more bits of time.time() in whrandom's default seed(). + +- Performance hack for regex module's regs attribute. + +- Don't close already closed socket in socket module. + +- Correctly handle separators containing embedded nulls in +strop.split, strop.find and strop.rfind. Also added more detail to +error message for strop.atoi and friends. + +- Moved fallback definition for hypot() to Python/hypot.c. + +- Added fallback definition for strdup, in Python/strdup.c. + +- Fixed some bugs where a function would return 0 to indicate an error +where it should return -1. + +- Test for error returned by time.localtime(), and rationalized its MS +tests. + +- Added Modules/Setup.local file, which is processed after Setup. + +- Corrected bug in toplevel Makefile.in -- execution of regen script +would not use the right PATH and PYTHONPATH. + +- Various and sundry NeXT configuration changes (sigh). + +- Support systems where libreadline needs neither termcap nor curses. + +- Improved ld_so_aix script and python.exp file (for AIX). + +- More stringent test for working <stdarg.h> in configure script. + +- Removed Demo/www subdirectory -- it was totally out of date. + +- Improved demos and docs for Fred Drake's parser module; fixed one +typo in the module itself. + + +========================================= +==> Release 1.4beta3 (August 26 1996) <== +========================================= + + +(XXX This is less readable that it should. I promise to restructure +it for the final 1.4 release.) + + +What's new in 1.4beta3 (since beta2)? +------------------------------------- + +- Name mangling to implement a simple form of class-private variables. +A name of the form "__spam" can't easily be used outside the class. +(This was added in 1.4beta3, but left out of the 1.4beta3 release +message.) + +- In urllib.urlopen(): HTTP URLs containing user:passwd@host are now +handled correctly when using a proxy server. + +- In ntpath.normpath(): don't truncate to 8+3 format. + +- In mimetools.choose_boundary(): don't die when getuid() or getpid() +aren't defined. + +- Module urllib: some optimizations to (un)quoting. + +- New module MimeWriter for writing MIME documents. + +- More changes to formatter module. + +- The freeze script works once again and is much more robust (using +sys.prefix etc.). It also supports a -o option to specify an +output directory. + +- New module whichdb recognizes dbm, gdbm and bsddb/dbhash files. + +- The Doc/Makefile targets have been reorganized somewhat to remove the +insistence on always generating PostScript. + +- The texinfo to html filter (Doc/texi2html.py) has been improved somewhat. + +- "errors.h" has been renamed to "pyerrors.h" to resolve a long-standing +name conflict on the Mac. + +- Linking a module compiled with a different setting for Py_TRACE_REFS now +generates a linker error rather than a core dump. + +- The cgi module has a new convenience function print_exception(), which +formats a python exception using HTML. It also fixes a bug in the +compatibility code and adds a dubious feature which makes it possible to +have two query strings, one in the URL and one in the POST data. + +- A subtle change in the unpickling of class instances makes it possible +to unpickle in restricted execution mode, where the __dict__ attribute is +not available (but setattr() is). + +- Documentation for os.path.splitext() (== posixpath.splitext()) has been +cleared up. It splits at the *last* dot. + +- posixfile locking is now also correctly supported on AIX. + +- The tempfile module once again honors an initial setting of tmpdir. It +now works on Windows, too. + +- The traceback module has some new functions to extract, format and print +the active stack. + +- Some translation functions in the urllib module have been made a little +less sluggish. + +- The addtag_* methods for Canvas widgets in Tkinter as well as in the +separate Canvas class have been fixed so they actually do something +meaningful. + +- A tiny _test() function has been added to Tkinter.py. + +- A generic Makefile for dynamically loaded modules is provided in the Misc +subdirectory (Misc/gMakefile). + +- A new version of python-mode.el for Emacs is provided. See +http://www.python.org/ftp/emacs/pmdetails.html for details. The +separate file pyimenu.el is no longer needed, imenu support is folded +into python-mode.el. + +- The configure script can finally correctly find the readline library in a +non-standard location. The LDFLAGS variable is passed on the Makefiles +from the configure script. + +- Shared libraries are now installed as programs (i.e. with executable +permission). This is required on HP-UX and won't hurt on other systems. + +- The objc.c module is no longer part of the distribution. Objective-C +support may become available as contributed software on the ftp site. + +- The sybase module is no longer part of the distribution. A much +improved sybase module is available as contributed software from the +ftp site. + +- _tkinter is now compatible with Tcl 7.5 / Tk 4.1 patch1 on Windows and +Mac (don't use unpatched Tcl/Tk!). The default line in the Setup.in file +now links with Tcl 7.5 / Tk 4.1 rather than 7.4/4.0. + +- In Setup, you can now write "*shared*" instead of "*noconfig*", and you +can use *.so and *.sl as shared libraries. + +- Some more fidgeting for AIX shared libraries. + +- The mpz module is now compatible with GMP 2.x. (Not tested by me.) +(Note -- a complete replacement by Niels Mo"ller, called gpmodule, is +available from the contrib directory on the ftp site.) + +- A warning is written to sys.stderr when a __del__ method raises an +exception (formerly, such exceptions were completely ignored). + +- The configure script now defines HAVE_OLD_CPP if the C preprocessor is +incapable of ANSI style token concatenation and stringification. + +- All source files (except a few platform specific modules) are once again +compatible with K&R C compilers as well as ANSI compilers. In particular, +ANSI-isms have been removed or made conditional in complexobject.c, +getargs.c and operator.c. + +- The abstract object API has three new functions, PyObject_DelItem, +PySequence_DelItem, and PySequence_DelSlice. + +- The operator module has new functions delitem and delslice, and the +functions "or" and "and" are renamed to "or_" and "and_" (since "or" and +"and" are reserved words). ("__or__" and "__and__" are unchanged.) + +- The environment module is no longer supported; putenv() is now a function +in posixmodule (also under NT). + +- Error in filter(<function>, "") has been fixed. + +- Unrecognized keyword arguments raise TypeError, not KeyError. + +- Better portability, fewer bugs and memory leaks, fewer compiler warnings, +some more documentation. + +- Bug in float power boundary case (0.0 to the negative integer power) +fixed. + +- The test of negative number to the float power has been moved from the +built-in pow() functin to floatobject.c (so complex numbers can yield the +correct result). + +- The bug introduced in beta2 where shared libraries loaded (using +dlopen()) from the current directory would fail, has been fixed. + +- Modules imported as shared libraries now also have a __file__ attribute, +giving the filename from which they were loaded. The only modules without +a __file__ attribute now are built-in modules. + +- On the Mac, dynamically loaded modules can end in either ".slb" or +".<platform>.slb" where <platform> is either "CFM68K" or "ppc". The ".slb" +extension should only be used for "fat" binaries. + +- C API addition: marshal.c now supports +PyMarshal_WriteObjectToString(object). + +- C API addition: getargs.c now supports +PyArg_ParseTupleAndKeywords(args, kwdict, format, kwnames, ...) +to parse keyword arguments. + +- The PC versioning scheme (sys.winver) has changed once again. the +version number is now "<digit>.<digit>.<digit>.<apiversion>", where the +first three <digit>s are the Python version (e.g. "1.4.0" for Python 1.4, +"1.4.1" for Python 1.4.1 -- the beta level is not included) and +<apiversion> is the four-digit PYTHON_API_VERSION (currently 1005). + +- h2py.py accepts whitespace before the # in CPP directives + +- On Solaris 2.5, it should now be possible to use either Posix threads or +Solaris threads (XXX: how do you select which is used???). (Note: the +Python pthreads interface doesn't fully support semaphores yet -- anyone +care to fix this?) + +- Thread support should now work on AIX, using either DCE threads or +pthreads. + +- New file Demo/sockets/unicast.py + +- Working Mac port, with CFM68K support, with Tk 4.1 support (though not +both) (XXX) + +- New project setup for PC port, now compatible with PythonWin, with +_tkinter and NumPy support (XXX) + +- New module site.py (XXX) + +- New module xdrlib.py and optional support module _xdrmodule.c (XXX) + +- parser module adapted to new grammar, complete w/ Doc & Demo (XXX) + +- regen script fixed (XXX) + +- new machdep subdirectories Lib/{aix3,aix4,next3_3,freebsd2,linux2} (XXX) + +- testall now also tests math module (XXX) + +- string.atoi c.s. now raise an exception for an empty input string. + +- At last, it is no longer necessary to define HAVE_CONFIG_H in order to +have config.h included at various places. + +- Unrecognized keyword arguments now raise TypeError rather than KeyError. + +- The makesetup script recognizes files with extension .so or .sl as +(shared) libraries. + +- 'access' is no longer a reserved word, and all code related to its +implementation is gone (or at least #ifdef'ed out). This should make +Python a little speedier too! + +- Performance enhancements suggested by Sjoerd Mullender. This includes +the introduction of two new optional function pointers in type object, +getattro and setattro, which are like getattr and setattr but take a +string object instead of a C string pointer. + +- New operations in string module: lstrip(s) and rstrip(s) strip whitespace +only on the left or only on the right, A new optional third argument to +split() specifies the maximum number of separators honored (so +splitfields(s, sep, n) returns a list of at most n+1 elements). (Since +1.3, splitfields(s, None) is totally equivalent to split(s).) +string.capwords() has an optional second argument specifying the +separator (which is passed to split()). + +- regsub.split() has the same addition as string.split(). regsub.splitx(s, +sep, maxsep) implements the functionality that was regsub.split(s, 1) in +1.4beta2 (return a list containing the delimiters as well as the words). + +- Final touch for AIX loading, rewritten Misc/AIX-NOTES. + +- In Modules/_tkinter.c, when using Tk 4.1 or higher, use className +argument to _tkinter.create() to set Tcl's argv0 variable, so X +resources use the right resource class again. + +- Add #undef fabs to Modules/mathmodule.c for macintosh. + +- Added some macro renames for AIX in Modules/operator.c. + +- Removed spurious 'E' from Doc/liberrno.tex. + +- Got rid of some cruft in Misc/ (dlMakefile, pyimenu.el); added new +Misc/gMakefile and new version of Misc/python-mode.el. + +- Fixed typo in Lib/ntpath.py (islink has "return false" which gives a +NameError). + +- Added missing "from types import *" to Lib/tkinter/Canvas.py. + +- Added hint about using default args for __init__ to pickle docs. + +- Corrected typo in Inclide/abstract.h: PySequence_Lenth -> +PySequence_Length. + +- Some improvements to Doc/texi2html.py. + +- In Python/import.c, Cast unsigned char * in struct _frozen to char * +in calls to rds_object(). + +- In doc/ref4.tex, added note about scope of lambda bodies. + +What's new in 1.4beta2 (since beta1)? +------------------------------------- + +- Portability bug in the md5.h header solved. + +- The PC build procedure now really works, and sets sys.platform to a +meaningful value (a few things were botched in beta 1). Lib/dos_8x3 +is now a standard part of the distribution (alas). + +- More improvements to the installation procedure. Typing "make install" +now inserts the version number in the pathnames of almost everything +installed, and creates the machine dependent modules (FCNTL.py etc.) if not +supplied by the distribution. (XXX There's still a problem with the latter +because the "regen" script requires that Python is installed. Some manual +intervention may still be required.) (This has been fixed in 1.4beta3.) + +- New modules: errno, operator (XXX). + +- Changes for use with Numerical Python: builtin function slice() and +Ellipses object, and corresponding syntax: + + x[lo:hi:stride] == x[slice(lo, hi, stride)] + x[a, ..., z] == x[(a, Ellipses, z)] + +- New documentation for errno and cgi modules. + +- The directory containing the script passed to the interpreter is +inserted in from of sys.path; "." is no longer a default path +component. + +- Optional third string argument to string.translate() specifies +characters to delete. New function string.maketrans() creates a +translation table for translate() or for regex.compile(). + +- Module posix (and hence module os under Unix) now supports putenv(). +Moreover, module os is enhanced so that if putenv() is supported, +assignments to os.environ entries make the appropriate putenv() call. +(XXX the putenv() implementation can leak a small amount of memory per +call.) + +- pdb.py can now be invoked from the command line to debug a script: +python pdb.py <script> <arg> ... + +- Much improved parseaddr() in rfc822. + +- In cgi.py, you can now pass an alternative value for environ to +nearly all functions. + +- You can now assign to instance variables whose name begins and ends +with '__'. + +- New version of Fred Drake's parser module and associates (token, +symbol, AST). + +- New PYTHON_API_VERSION value and .pyc file magic number (again!). + +- The "complex" internal structure type is now called "Py_complex" to +avoid name conflicts. + +- Numerous small bugs fixed. + +- Slight pickle speedups. + +- Some slight speedups suggested by Sjoerd (more coming in 1.4 final). + +- NeXT portability mods by Bill Bumgarner integrated. + +- Modules regexmodule.c, bsddbmodule.c and xxmodule.c have been +converted to new naming style. + + +What's new in 1.4beta1 (since 1.3)? +----------------------------------- + +- Added sys.platform and sys.exec_platform for Bill Janssen. + +- Installation has been completely overhauled. "make install" now installs +everything, not just the python binary. Installation uses the install-sh +script (borrowed from X11) to install each file. + +- New functions in the posix module: mkfifo, plock, remove (== unlink), +and ftruncate. More functions are also available under NT. + +- New function in the fcntl module: flock. + +- Shared library support for FreeBSD. + +- The --with-readline option can now be used without a DIRECTORY argument, +for systems where libreadline.* is in one of the standard places. It is +also possible for it to be a shared library. + +- The extension tkinter has been renamed to _tkinter, to avoid confusion +with Tkinter.py oncase insensitive file systems. It now supports Tk 4.1 as +well as 4.0. + +- Author's change of address from CWI in Amsterdam, The Netherlands, to +CNRI in Reston, VA, USA. + +- The math.hypot() function is now always available (if it isn't found in +the C math library, Python provides its own implementation). + +- The latex documentation is now compatible with latex2e, thanks to David +Ascher. + +- The expression x**y is now equivalent to pow(x, y). + +- The indexing expression x[a, b, c] is now equivalent to x[(a, b, c)]. + +- Complex numbers are now supported. Imaginary constants are written with +a 'j' or 'J' prefix, general complex numbers can be formed by adding a real +part to an imaginary part, like 3+4j. Complex numbers are always stored in +floating point form, so this is equivalent to 3.0+4.0j. It is also +possible to create complex numbers with the new built-in function +complex(re, [im]). For the footprint-conscious, complex number support can +be disabled by defining the symbol WITHOUT_COMPLEX. + +- New built-in function list() is the long-awaited counterpart of tuple(). + +- There's a new "cmath" module which provides the same functions as the +"math" library but with complex arguments and results. (There are very +good reasons why math.sqrt(-1) still raises an exception -- you have to use +cmath.sqrt(-1) to get 1j for an answer.) + +- The Python.h header file (which is really the same as allobjects.h except +it disables support for old style names) now includes several more files, +so you have to have fewer #include statements in the average extension. + +- The NDEBUG symbol is no longer used. Code that used to be dependent on +the presence of NDEBUG is now present on the absence of DEBUG. TRACE_REFS +and REF_DEBUG have been renamed to Py_TRACE_REFS and Py_REF_DEBUG, +respectively. At long last, the source actually compiles and links without +errors when this symbol is defined. + +- Several symbols that didn't follow the new naming scheme have been +renamed (usually by adding to rename2.h) to use a Py or _Py prefix. There +are no external symbols left without a Py or _Py prefix, not even those +defined by sources that were incorporated from elsewhere (regexpr.c, +md5c.c). (Macros are a different story...) + +- There are now typedefs for the structures defined in config.c and +frozen.c. + +- New PYTHON_API_VERSION value and .pyc file magic number. + +- New module Bastion. (XXX) + +- Improved performance of StringIO module. + +- UserList module now supports + and * operators. + +- The binhex and binascii modules now actually work. + +- The cgi module has been almost totally rewritten and documented. +It now supports file upload and a new data type to handle forms more +flexibly. + +- The formatter module (for use with htmllib) has been overhauled (again). + +- The ftplib module now supports passive mode and has doc strings. + +- In (ideally) all places where binary files are read or written, the file +is now correctly opened in binary mode ('rb' or 'wb') so the code will work +on Mac or PC. + +- Dummy versions of os.path.expandvars() and expanduser() are now provided +on non-Unix platforms. + +- Module urllib now has two new functions url2pathname and pathname2url +which turn local filenames into "file:..." URLs using the same rules as +Netscape (why be different). it also supports urlretrieve() with a +pathname parameter, and honors the proxy environment variables (http_proxy +etc.). The URL parsing has been improved somewhat, too. + +- Micro improvements to urlparse. Added urlparse.urldefrag() which +removes a trailing ``#fragment'' if any. + +- The mailbox module now supports MH style message delimiters as well. + +- The mhlib module contains some new functionality: setcontext() to set the +current folder and parsesequence() to parse a sequence as commonly passed +to MH commands (e.g. 1-10 or last:5). + +- New module mimify for conversion to and from MIME format of email +messages. + +- Module ni now automatically installs itself when first imported -- this +is against the normal rule that modules should define classes and functions +but not invoke them, but appears more useful in the case that two +different, independent modules want to use ni's features. + +- Some small performance enhancements in module pickle. + +- Small interface change to the profile.run*() family of functions -- more +sensible handling of return values. + +- The officially registered Mac creator for Python files is 'Pyth'. This +replaces 'PYTH' which was used before but never registered. + +- Added regsub.capwords(). (XXX) + +- Added string.capwords(), string.capitalize() and string.translate(). +(XXX) + +- Fixed an interface bug in the rexec module: it was impossible to pass a +hooks instance to the RExec class. rexec now also supports the dynamic +loading of modules from shared libraries. Some other interfaces have been +added too. + +- Module rfc822 now caches the headers in a dictionary for more efficient +lookup. + +- The sgmllib module now understands a limited number of SGML "shorthands" +like <A/.../ for <A>...</A>. (It's not clear that this was a good idea...) + +- The tempfile module actually tries a number of different places to find a +usable temporary directory. (This was prompted by certain Linux +installations that appear to be missing a /usr/tmp directory.) [A bug in +the implementation that would ignore a pre-existing tmpdir global has been +fixed in beta3.] + +- Much improved and enhanved FileDialog module for Tkinter. + +- Many small changes to Tkinter, to bring it more in line with Tk 4.0 (as +well as Tk 4.1). + +- New socket interfaces include ntohs(), ntohl(), htons(), htonl(), and +s.dup(). Sockets now work correctly on Windows. On Windows, the built-in +extension is called _socket and a wrapper module win/socket.py provides +"makefile()" and "dup()" functionality. On Windows, the select module +works only with socket objects. + +- Bugs in bsddb module fixed (e.g. missing default argument values). + +- The curses extension now includes <ncurses.h> when available. + +- The gdbm module now supports opening databases in "fast" mode by +specifying 'f' as the second character or the mode string. + +- new variables sys.prefix and sys.exec_prefix pass corresponding +configuration options / Makefile variables to the Python programmer. + +- The ``new'' module now supports creating new user-defined classes as well +as instances thereof. + +- The soundex module now sports get_soundex() to get the soundex value for an +arbitrary string (formerly it would only do soundex-based string +comparison) as well as doc strings. + +- New object type "cobject" to safely wrap void pointers for passing them +between various extension modules. + +- More efficient computation of float**smallint. + +- The mysterious bug whereby "x.x" (two occurrences of the same +one-character name) typed from the commandline would sometimes fail +mysteriously. + +- The initialization of the readline function can now be invoked by a C +extension through PyOS_ReadlineInit(). + +- There's now an externally visible pointer PyImport_FrozenModules which +can be changed by an embedding application. + +- The argument parsing functions now support a new format character 'D' to +specify complex numbers. + +- Various memory leaks plugged and bugs fixed. + +- Improved support for posix threads (now that real implementations are +beginning to apepar). Still no fully functioning semaphores. + +- Some various and sundry improvements and new entries in the Tools +directory. + + +===================================== +==> Release 1.3 (13 October 1995) <== +===================================== + +Major change +============ + +Two words: Keyword Arguments. See the first section of Chapter 12 of +the Tutorial. + +(The rest of this file is textually the same as the remaining sections +of that chapter.) + + +Changes to the WWW and Internet tools +===================================== + +The "htmllib" module has been rewritten in an incompatible fashion. +The new version is considerably more complete (HTML 2.0 except forms, +but including all ISO-8859-1 entity definitions), and easy to use. +Small changes to "sgmllib" have also been made, to better match the +tokenization of HTML as recognized by other web tools. + +A new module "formatter" has been added, for use with the new +"htmllib" module. + +The "urllib"and "httplib" modules have been changed somewhat to allow +overriding unknown URL types and to support authentication. They now +use "mimetools.Message" instead of "rfc822.Message" to parse headers. +The "endrequest()" method has been removed from the HTTP class since +it breaks the interaction with some servers. + +The "rfc822.Message" class has been changed to allow a flag to be +passed in that says that the file is unseekable. + +The "ftplib" module has been fixed to be (hopefully) more robust on +Linux. + +Several new operations that are optionally supported by servers have +been added to "nntplib": "xover", "xgtitle", "xpath" and "date". + +Other Language Changes +====================== + +The "raise" statement now takes an optional argument which specifies +the traceback to be used when printing the exception's stack trace. +This must be a traceback object, such as found in "sys.exc_traceback". +When omitted or given as "None", the old behavior (to generate a stack +trace entry for the current stack frame) is used. + +The tokenizer is now more tolerant of alien whitespace. Control-L in +the leading whitespace of a line resets the column number to zero, +while Control-R just before the end of the line is ignored. + +Changes to Built-in Operations +============================== + +For file objects, "f.read(0)" and "f.readline(0)" now return an empty +string rather than reading an unlimited number of bytes. For the +latter, omit the argument altogether or pass a negative value. + +A new system variable, "sys.platform", has been added. It specifies +the current platform, e.g. "sunos5" or "linux1". + +The built-in functions "input()" and "raw_input()" now use the GNU +readline library when it has been configured (formerly, only +interactive input to the interpreter itself was read using GNU +readline). The GNU readline library provides elaborate line editing +and history. The Python debugger ("pdb") is the first beneficiary of +this change. + +Two new built-in functions, "globals()" and "locals()", provide access +to dictionaries containming current global and local variables, +respectively. (These augment rather than replace "vars()", which +returns the current local variables when called without an argument, +and a module's global variables when called with an argument of type +module.) + +The built-in function "compile()" now takes a third possible value for +the kind of code to be compiled: specifying "'single'" generates code +for a single interactive statement, which prints the output of +expression statements that evaluate to something else than "None". + +Library Changes +=============== + +There are new module "ni" and "ihooks" that support importing modules +with hierarchical names such as "A.B.C". This is enabled by writing +"import ni; ni.ni()" at the very top of the main program. These +modules are amply documented in the Python source. + +The module "rexec" has been rewritten (incompatibly) to define a class +and to use "ihooks". + +The "string.split()" and "string.splitfields()" functions are now the +same function (the presence or absence of the second argument +determines which operation is invoked); similar for "string.join()" +and "string.joinfields()". + +The "Tkinter" module and its helper "Dialog" have been revamped to use +keyword arguments. Tk 4.0 is now the standard. A new module +"FileDialog" has been added which implements standard file selection +dialogs. + +The optional built-in modules "dbm" and "gdbm" are more coordinated +--- their "open()" functions now take the same values for their "flag" +argument, and the "flag" and "mode" argument have default values (to +open the database for reading only, and to create the database with +mode "0666" minuse the umask, respectively). The memory leaks have +finally been fixed. + +A new dbm-like module, "bsddb", has been added, which uses the BSD DB +package's hash method. + +A portable (though slow) dbm-clone, implemented in Python, has been +added for systems where none of the above is provided. It is aptly +dubbed "dumbdbm". + +The module "anydbm" provides a unified interface to "bsddb", "gdbm", +"dbm", and "dumbdbm", choosing the first one available. + +A new extension module, "binascii", provides a variety of operations +for conversion of text-encoded binary data. + +There are three new or rewritten companion modules implemented in +Python that can encode and decode the most common such formats: "uu" +(uuencode), "base64" and "binhex". + +A module to handle the MIME encoding quoted-printable has also been +added: "quopri". + +The parser module (which provides an interface to the Python parser's +abstract syntax trees) has been rewritten (incompatibly) by Fred +Drake. It now lets you change the parse tree and compile the result! + +The \code{syslog} module has been upgraded and documented. + +Other Changes +============= + +The dynamic module loader recognizes the fact that different filenames +point to the same shared library and loads the library only once, so +you can have a single shared library that defines multiple modules. +(SunOS / SVR4 style shared libraries only.) + +Jim Fulton's ``abstract object interface'' has been incorporated into +the run-time API. For more detailes, read the files +"Include/abstract.h" and "Objects/abstract.c". + +The Macintosh version is much more robust now. + +Numerous things I have forgotten or that are so obscure no-one will +notice them anyway :-) + + +=================================== +==> Release 1.2 (13 April 1995) <== +=================================== + +- Changes to Misc/python-mode.el: + - Wrapping and indentation within triple quote strings should work + properly now. + - `Standard' bug reporting mechanism (use C-c C-b) + - py-mark-block was moved to C-c C-m + - C-c C-v shows you the python-mode version + - a basic python-font-lock-keywords has been added for Emacs 19 + font-lock colorizations. + - proper interaction with pending-del and del-sel modes. + - New py-electric-colon (:) command for improved outdenting. Also + py-indent-line (TAB) should handle outdented lines better. + - New commands py-outdent-left (C-c C-l) and py-indent-right (C-c C-r) + +- The Library Reference has been restructured, and many new and +existing modules are now documented, in particular the debugger and +the profiler, as well as the persistency and the WWW/Internet support +modules. + +- All known bugs have been fixed. For example the pow(2,2,3L) bug on +Linux has been fixed. Also the re-entrancy problems with __del__ have +been fixed. + +- All known memory leaks have been fixed. + +- Phase 2 of the Great Renaming has been executed. The header files +now use the new names (PyObject instead of object, etc.). The linker +also sees the new names. Most source files still use the old names, +by virtue of the rename2.h header file. If you include Python.h, you +only see the new names. Dynamically linked modules have to be +recompiled. (Phase 3, fixing the rest of the sources, will be +executed gradually with the release later versions.) + +- The hooks for implementing "safe-python" (better called "restricted +execution") are in place. Specifically, the import statement is +implemented by calling the built-in function __import__, and the +built-in names used in a particular scope are taken from the +dictionary __builtins__ in that scope's global dictionary. See also +the new (unsupported, undocumented) module rexec.py. + +- The import statement now supports the syntax "import a.b.c" and +"from a.b.c import name". No officially supported implementation +exists, but one can be prototyped by replacing the built-in __import__ +function. A proposal by Ken Manheimer is provided as newimp.py. + +- All machinery used by the import statement (or the built-in +__import__ function) is now exposed through the new built-in module +"imp" (see the library reference manual). All dynamic loading +machinery is moved to the new file importdl.c. + +- Persistent storage is supported through the use of the modules +"pickle" and "shelve" (implemented in Python). There's also a "copy" +module implementing deepcopy and normal (shallow) copy operations. +See the library reference manual. + +- Documentation strings for many objects types are accessible through +the __doc__ attribute. Modules, classes and functions support special +syntax to initialize the __doc__ attribute: if the first statement +consists of just a string literal, that string literal becomes the +value of the __doc__ attribute. The default __doc__ attribute is +None. Documentation strings are also supported for built-in +functions, types and modules; however this feature hasn't been widely +used yet. See the 'new' module for an example. (Basically, the type +object's tp_doc field contains the doc string for the type, and the +4th member of the methodlist structure contains the doc string for the +method.) + +- The __coerce__ and __cmp__ methods for user-defined classes once +again work as expected. As an example, there's a new standard class +Complex in the library. + +- The functions posix.popen() and posix.fdopen() now have an optional +third argument to specify the buffer size, and default their second +(mode) argument to 'r' -- in analogy to the builtin open() function. +The same applies to posixfile.open() and the socket method makefile(). + +- The thread.exit_thread() function now raises SystemExit so that +'finally' clauses are honored and a memory leak is plugged. + +- Improved X11 and Motif support, by Sjoerd Mullender. This extension +is being maintained and distributed separately. + +- Improved support for the Apple Macintosh, in part by Jack Jansen, +e.g. interfaces to (a few) resource mananger functions, get/set file +type and creator, gestalt, sound manager, speech manager, MacTCP, comm +toolbox, and the think C console library. This is being maintained +and distributed separately. + +- Improved version for Windows NT, by Mark Hammond. This is being +maintained and distributed separately. + +- Used autoconf 2.0 to generate the configure script. Adapted +configure.in to use the new features in autoconf 2.0. + +- It now builds on the NeXT without intervention, even on the 3.3 +Sparc pre-release. + +- Characters passed to isspace() and friends are masked to nonnegative +values. + +- Correctly compute pow(-3.0, 3). + +- Fix portability problems with getopt (configure now checks for a +non-GNU getopt). + +- Don't add frozenmain.o to libPython.a. + +- Exceptions can now be classes. ALl built-in exceptions are still +string objects, but this will change in the future. + +- The socket module exports a long list of socket related symbols. +(More built-in modules will export their symbolic constants instead of +relying on a separately generated Python module.) + +- When a module object is deleted, it clears out its own dictionary. +This fixes a circularity in the references between functions and +their global dictionary. + +- Changed the error handling by [new]getargs() e.g. for "O&". + +- Dynamic loading of modules using shared libraries is supported for +several new platforms. + +- Support "O&", "[...]" and "{...}" in mkvalue(). + +- Extension to findmethod(): findmethodinchain() (where a chain is a +linked list of methodlist arrays). The calling interface for +findmethod() has changed: it now gets a pointer to the (static!) +methodlist structure rather than just to the function name -- this +saves copying flags etc. into the (short-lived) method object. + +- The callable() function is now public. + +- Object types can define a few new operations by setting function +pointers in the type object structure: tp_call defines how an object +is called, and tp_str defines how an object's str() is computed. + + +=================================== +==> Release 1.1.1 (10 Nov 1994) <== +=================================== + +This is a pure bugfix release again. See the ChangeLog file for details. + +One exception: a few new features were added to tkinter. + + +================================= +==> Release 1.1 (11 Oct 1994) <== +================================= + +This release adds several new features, improved configuration and +portability, and fixes more bugs than I can list here (including some +memory leaks). + +The source compiles and runs out of the box on more platforms than +ever -- including Windows NT. Makefiles or projects for a variety of +non-UNIX platforms are provided. + +APOLOGY: some new features are badly documented or not at all. I had +the choice -- postpone the new release indefinitely, or release it +now, with working code but some undocumented areas. The problem with +postponing the release is that people continue to suffer from existing +bugs, and send me patches based on the previous release -- which I +can't apply directly because my own source has changed. Also, some +new modules (like signal) have been ready for release for quite some +time, and people are anxiously waiting for them. In the case of +signal, the interface is simple enough to figure out without +documentation (if you're anxious enough :-). In this case it was not +simple to release the module on its own, since it relies on many small +patches elsewhere in the source. + +For most new Python modules, the source code contains comments that +explain how to use them. Documentation for the Tk interface, written +by Matt Conway, is available as tkinter-doc.tar.gz from the Python +home and mirror ftp sites (see Misc/FAQ for ftp addresses). For the +new operator overloading facilities, have a look at Demo/classes: +Complex.py and Rat.py show how to implement a numeric type without and +with __coerce__ method. Also have a look at the end of the Tutorial +document (Doc/tut.tex). If you're still confused: use the newsgroup +or mailing list. + + +New language features: + + - More flexible operator overloading for user-defined classes + (INCOMPATIBLE WITH PREVIOUS VERSIONS!) See end of tutorial. + + - Classes can define methods named __getattr__, __setattr__ and + __delattr__ to trap attribute accesses. See end of tutorial. + + - Classes can define method __call__ so instances can be called + directly. See end of tutorial. + + +New support facilities: + + - The Makefiles (for the base interpreter as well as for extensions) + now support creating dynamically loadable modules if the platform + supports shared libraries. + + - Passing the interpreter a .pyc file as script argument will execute + the code in that file. (On the Mac such files can be double-clicked!) + + - New Freeze script, to create independently distributable "binaries" + of Python programs -- look in Demo/freeze + + - Improved h2py script (in Demo/scripts) follows #includes and + supports macros with one argument + + - New module compileall generates .pyc files for all modules in a + directory (tree) without also executing them + + - Threads should work on more platforms + + +New built-in modules: + + - tkinter (support for Tcl's Tk widget set) is now part of the base + distribution + + - signal allows catching or ignoring UNIX signals (unfortunately still + undocumented -- any taker?) + + - termios provides portable access to POSIX tty settings + + - curses provides an interface to the System V curses library + + - syslog provides an interface to the (BSD?) syslog daemon + + - 'new' provides interfaces to create new built-in object types + (e.g. modules and functions) + + - sybase provides an interface to SYBASE database + + +New/obsolete built-in methods: + + - callable(x) tests whether x can be called + + - sockets now have a setblocking() method + + - sockets no longer have an allowbroadcast() method + + - socket methods send() and sendto() return byte count + + +New standard library modules: + + - types.py defines standard names for built-in types, e.g. StringType + + - urlparse.py parses URLs according to the latest Internet draft + + - uu.py does uuencode/uudecode (not the fastest in the world, but + quicker than installing uuencode on a non-UNIX machine :-) + + - New, faster and more powerful profile module.py + + - mhlib.py provides interface to MH folders and messages + + +New facilities for extension writers (unfortunately still +undocumented): + + - newgetargs() supports optional arguments and improved error messages + + - O!, O& O? formats for getargs allow more versatile type checking of + non-standard types + + - can register pending asynchronous callback, to be called the next + time the Python VM begins a new instruction (Py_AddPendingCall) + + - can register cleanup routines to be called when Python exits + (Py_AtExit) + + - makesetup script understands C++ files in Setup file (use file.C + or file.cc) + + - Make variable OPT is passed on to sub-Makefiles + + - An init<module>() routine may signal an error by not entering + the module in the module table and raising an exception instead + + - For long module names, instead of foobarbletchmodule.c you can + use foobarbletch.c + + - getintvalue() and getfloatvalue() try to convert any object + instead of requiring an "intobject" or "floatobject" + + - All the [new]getargs() formats that retrieve an integer value + will now also work if a float is passed + + - C function listtuple() converts list to tuple, fast + + - You should now call sigcheck() instead of intrcheck(); + sigcheck() also sets an exception when it returns nonzero + + +==================================== +==> Release 1.0.3 (14 July 1994) <== +==================================== + +This release consists entirely of bug fixes to the C sources; see the +head of ../ChangeLog for a complete list. Most important bugs fixed: + +- Sometimes the format operator (string%expr) would drop the last +character of the format string + +- Tokenizer looped when last line did not end in \n + +- Bug when triple-quoted string ended in quote plus newline + +- Typo in socketmodule (listen) (== instead of =) + +- typing vars() at the >>> prompt would cause recursive output + + +================================== +==> Release 1.0.2 (4 May 1994) <== +================================== + +Overview of the most visible changes. Bug fixes are not listed. See +also ChangeLog. + +Tokens +------ + +* String literals follow Standard C rules: they may be continued on +the next line using a backslash; adjacent literals are concatenated +at compile time. + +* A new kind of string literals, surrounded by triple quotes (""" or +'''), can be continued on the next line without a backslash. + +Syntax +------ + +* Function arguments may have a default value, e.g. def f(a, b=1); +defaults are evaluated at function definition time. This also applies +to lambda. + +* The try-except statement has an optional else clause, which is +executed when no exception occurs in the try clause. + +Interpreter +----------- + +* The result of a statement-level expression is no longer printed, +except_ for expressions entered interactively. Consequently, the -k +command line option is gone. + +* The result of the last printed interactive expression is assigned to +the variable '_'. + +* Access to implicit global variables has been speeded up by removing +an always-failing dictionary lookup in the dictionary of local +variables (mod suggested by Steve Makewski and Tim Peters). + +* There is a new command line option, -u, to force stdout and stderr +to be unbuffered. + +* Incorporated Steve Majewski's mods to import.c for dynamic loading +under AIX. + +* Fewer chances of dumping core when trying to reload or re-import +static built-in, dynamically loaded built-in, or frozen modules. + +* Loops over sequences now don't ask for the sequence's length when +they start, but try to access items 0, 1, 2, and so on until they hit +an IndexError. This makes it possible to create classes that generate +infinite or indefinite sequences a la Steve Majewski. This affects +for loops, the (not) in operator, and the built-in functions filter(), +map(), max(), min(), reduce(). + +Changed Built-in operations +--------------------------- + +* The '%' operator on strings (printf-style formatting) supports a new +feature (adapted from a patch by Donald Beaudry) to allow +'%(<key>)<format>' % {...} to take values from a dictionary by name +instead of from a tuple by position (see also the new function +vars()). + +* The '%s' formatting operator is changed to accept any type and +convert it to a string using str(). + +* Dictionaries with more than 20,000 entries can now be created +(thanks to Steve Kirsch). + +New Built-in Functions +---------------------- + +* vars() returns a dictionary containing the local variables; vars(m) +returns a dictionary containing the variables of module m. Note: +dir(x) is now equivalent to vars(x).keys(). + +Changed Built-in Functions +-------------------------- + +* open() has an optional third argument to specify the buffer size: 0 +for unbuffered, 1 for line buffered, >1 for explicit buffer size, <0 +for default. + +* open()'s second argument is now optional; it defaults to "r". + +* apply() now checks that its second argument is indeed a tuple. + +New Built-in Modules +-------------------- + +Changed Built-in Modules +------------------------ + +The thread module no longer supports exit_prog(). + +New Python Modules +------------------ + +* Module addpack contains a standard interface to modify sys.path to +find optional packages (groups of related modules). + +* Module urllib contains a number of functions to access +World-Wide-Web files specified by their URL. + +* Module httplib implements the client side of the HTTP protocol used +by World-Wide-Web servers. + +* Module gopherlib implements the client side of the Gopher protocol. + +* Module mailbox (by Jack Jansen) contains a parser for UNIX and MMDF +style mailbox files. + +* Module random contains various random distributions, e.g. gauss(). + +* Module lockfile locks and unlocks open files using fcntl (inspired +by a similar module by Andy Bensky). + +* Module ntpath (by Jaap Vermeulen) implements path operations for +Windows/NT. + +* Module test_thread (in Lib/test) contains a small test set for the +thread module. + +Changed Python Modules +---------------------- + +* The string module's expandvars() function is now documented and is +implemented in Python (using regular expressions) instead of forking +off a shell process. + +* Module rfc822 now supports accessing the header fields using the +mapping/dictionary interface, e.g. h['subject']. + +* Module pdb now makes it possible to set a break on a function +(syntax: break <expression>, where <expression> yields a function +object). + +Changed Demos +------------- + +* The Demo/scripts/freeze.py script is working again (thanks to Jaap +Vermeulen). + +New Demos +--------- + +* Demo/threads/Generator.py is a proposed interface for restartable +functions a la Tim Peters. + +* Demo/scripts/newslist.py, by Quentin Stafford-Fraser, generates a +directory full of HTML pages which between them contain links to all +the newsgroups available on your server. + +* Demo/dns contains a DNS (Domain Name Server) client. + +* Demo/lutz contains miscellaneous demos by Mark Lutz (e.g. psh.py, a +nice enhanced Python shell!!!). + +* Demo/turing contains a Turing machine by Amrit Prem. + +Documentation +------------- + +* Documented new language features mentioned above (but not all new +modules). + +* Added a chapter to the Tutorial describing recent additions to +Python. + +* Clarified some sentences in the reference manual, +e.g. break/continue, local/global scope, slice assignment. + +Source Structure +---------------- + +* Moved Include/tokenizer.h to Parser/tokenizer.h. + +* Added Python/getopt.c for systems that don't have it. + +Emacs mode +---------- + +* Indentation of continuated lines is done more intelligently; +consequently the variable py-continuation-offset is gone. + + +======================================== +==> Release 1.0.1 (15 February 1994) <== +======================================== + +* Many portability fixes should make it painless to build Python on +several new platforms, e.g. NeXT, SEQUENT, WATCOM, DOS, and Windows. + +* Fixed test for <stdarg.h> -- this broke on some platforms. + +* Fixed test for shared library dynalic loading -- this broke on SunOS +4.x using the GNU loader. + +* Changed order and number of SVR4 networking libraries (it is now +-lsocket -linet -lnsl, if these libraries exist). + +* Installing the build intermediate stages with "make libainstall" now +also installs config.c.in, Setup and makesetup, which are used by the +new Extensions mechanism. + +* Improved README file contains more hints and new troubleshooting +section. + +* The built-in module strop now defines fast versions of three more +functions of the standard string module: atoi(), atol() and atof(). +The strop versions of atoi() and atol() support an optional second +argument to specify the base (default 10). NOTE: you don't have to +explicitly import strop to use the faster versions -- the string +module contains code to let versions from stop override the default +versions. + +* There is now a working Lib/dospath.py for those who use Python under +DOS (or Windows). Thanks, Jaap! + +* There is now a working Modules/dosmodule.c for DOS (or Windows) +system calls. + +* Lib.os.py has been reorganized (making it ready for more operating +systems). + +* Lib/ospath.py is now obsolete (use os.path instead). + +* Many fixes to the tutorial to make it match Python 1.0. Thanks, +Tim! + +* Fixed Doc/Makefile, Doc/README and various scripts there. + +* Added missing description of fdopen to Doc/libposix.tex. + +* Made cleanup() global, for the benefit of embedded applications. + +* Added parsing of addresses and dates to Lib/rfc822.py. + +* Small fixes to Lib/aifc.py, Lib/sunau.py, Lib/tzparse.py to make +them usable at all. + +* New module Lib/wave.py reads RIFF (*.wav) audio files. + +* Module Lib/filewin.py moved to Lib/stdwin/filewin.py where it +belongs. + +* New options and comments for Modules/makesetup (used by new +Extension mechanism). + +* Misc/HYPE contains text of announcement of 1.0.0 in comp.lang.misc +and elsewhere. + +* Fixed coredump in filter(None, 'abcdefg'). + + +======================================= +==> Release 1.0.0 (26 January 1994) <== +======================================= + +As is traditional, so many things have changed that I can't pretend to +be complete in these release notes, but I'll try anyway :-) + +Note that the very last section is labeled "remaining bugs". + + +Source organization and build process +------------------------------------- + +* The sources have finally been split: instead of a single src +subdirectory there are now separate directories Include, Parser, +Grammar, Objects, Python and Modules. Other directories also start +with a capital letter: Misc, Doc, Lib, Demo. + +* A few extensions (notably Amoeba and X support) have been moved to a +separate subtree Extensions, which is no longer in the core +distribution, but separately ftp'able as extensions.tar.Z. (The +distribution contains a placeholder Ext-dummy with a description of +the Extensions subtree as well as the most recent versions of the +scripts used there.) + +* A few large specialized demos (SGI video and www) have been +moved to a separate subdirectory Demo2, which is no longer in the core +distribution, but separately ftp'able as demo2.tar.Z. + +* Parts of the standard library have been moved to subdirectories: +there are now standard subdirectories stdwin, test, sgi and sun4. + +* The configuration process has radically changed: I now use GNU +autoconf. This makes it much easier to build on new Unix flavors, as +well as fully supporting VPATH (if your Make has it). The scripts +Configure.py and Addmodule.sh are no longer needed. Many source files +have been adapted in order to work with the symbols that the configure +script generated by autoconf defines (or not); the resulting source is +much more portable to different C compilers and operating systems, +even non Unix systems (a Mac port was done in an afternoon). See the +toplevel README file for a description of the new build process. + +* GNU readline (a slightly newer version) is now a subdirectory of the +Python toplevel. It is still not automatically configured (being +totally autoconf-unaware :-). One problem has been solved: typing +Control-C to a readline prompt will now work. The distribution no +longer contains a "super-level" directory (above the python toplevel +directory), and dl, dl-dld and GNU dld are no longer part of the +Python distribution (you can still ftp them from +ftp.cwi.nl:/pub/dynload). + +* The DOS functions have been taken out of posixmodule.c and moved +into a separate file dosmodule.c. + +* There's now a separate file version.c which contains nothing but +the version number. + +* The actual main program is now contained in config.c (unless NO_MAIN +is defined); pythonmain.c now contains a function realmain() which is +called from config.c's main(). + +* All files needed to use the built-in module md5 are now contained in +the distribution. The module has been cleaned up considerably. + + +Documentation +------------- + +* The library manual has been split into many more small latex files, +so it is easier to edit Doc/lib.tex file to create a custom library +manual, describing only those modules supported on your system. (This +is not automated though.) + +* A fourth manual has been added, titled "Extending and Embedding the +Python Interpreter" (Doc/ext.tex), which collects information about +the interpreter which was previously spread over several files in the +misc subdirectory. + +* The entire documentation is now also available on-line for those who +have a WWW browser (e.g. NCSA Mosaic). Point your browser to the URL +"http://www.cwi.nl/~guido/Python.html". + + +Syntax +------ + +* Strings may now be enclosed in double quotes as well as in single +quotes. There is no difference in interpretation. The repr() of +string objects will use double quotes if the string contains a single +quote and no double quotes. Thanks to Amrit Prem for these changes! + +* There is a new keyword 'exec'. This replaces the exec() built-in +function. If a function contains an exec statement, local variable +optimization is not performed for that particular function, thus +making assignment to local variables in exec statements less +confusing. (As a consequence, os.exec and python.exec have been +renamed to execv.) + +* There is a new keyword 'lambda'. An expression of the form + + lambda <parameters> : <expression> + +yields an anonymous function. This is really only syntactic sugar; +you can just as well define a local function using + + def some_temporary_name(<parameters>): return <expression> + +Lambda expressions are particularly useful in combination with map(), +filter() and reduce(), described below. Thanks to Amrit Prem for +submitting this code (as well as map(), filter(), reduce() and +xrange())! + + +Built-in functions +------------------ + +* The built-in module containing the built-in functions is called +__builtin__ instead of builtin. + +* New built-in functions map(), filter() and reduce() perform standard +functional programming operations (though not lazily): + +- map(f, seq) returns a new sequence whose items are the items from +seq with f() applied to them. + +- filter(f, seq) returns a subsequence of seq consisting of those +items for which f() is true. + +- reduce(f, seq, initial) returns a value computed as follows: + acc = initial + for item in seq: acc = f(acc, item) + return acc + +* New function xrange() creates a "range object". Its arguments are +the same as those of range(), and when used in a for loop a range +objects also behaves identical. The advantage of xrange() over +range() is that its representation (if the range contains many +elements) is much more compact than that of range(). The disadvantage +is that the result cannot be used to initialize a list object or for +the "Python idiom" [RED, GREEN, BLUE] = range(3). On some modern +architectures, benchmarks have shown that "for i in range(...): ..." +actually executes *faster* than "for i in xrange(...): ...", but on +memory starved machines like PCs running DOS range(100000) may be just +too big to be represented at all... + +* Built-in function exec() has been replaced by the exec statement -- +see above. + + +The interpreter +--------------- + +* Syntax errors are now not printed to stderr by the parser, but +rather the offending line and other relevant information are packed up +in the SyntaxError exception argument. When the main loop catches a +SyntaxError exception it will print the error in the same format as +previously, but at the proper position in the stack traceback. + +* You can now set a maximum to the number of traceback entries +printed by assigning to sys.tracebacklimit. The default is 1000. + +* The version number in .pyc files has changed yet again. + +* It is now possible to have a .pyc file without a corresponding .py +file. (Warning: this may break existing installations if you have an +old .pyc file lingering around somewhere on your module search path +without a corresponding .py file, when there is a .py file for a +module of the same name further down the path -- the new interpreter +will find the first .pyc file and complain about it, while the old +interpreter would ignore it and use the .py file further down.) + +* The list sys.builtin_module_names is now sorted and also contains +the names of a few hardwired built-in modules (sys, __main__ and +__builtin__). + +* A module can now find its own name by accessing the global variable +__name__. Assigning to this variable essentially renames the module +(it should also be stored under a different key in sys.modules). +A neat hack follows from this: a module that wants to execute a main +program when called as a script no longer needs to compare +sys.argv[0]; it can simply do "if __name__ == '__main__': main()". + +* When an object is printed by the print statement, its implementation +of str() is used. This means that classes can define __str__(self) to +direct how their instances are printed. This is different from +__repr__(self), which should define an unambigous string +representation of the instance. (If __str__() is not defined, it +defaults to __repr__().) + +* Functions and code objects can now be compared meaningfully. + +* On systems supporting SunOS or SVR4 style shared libraries, dynamic +loading of modules using shared libraries is automatically configured. +Thanks to Bill Jansen and Denis Severson for contributing this change! + + +Built-in objects +---------------- + +* File objects have acquired a new method writelines() which is the +reverse of readlines(). (It does not actually write lines, just a +list of strings, but the symmetry makes the choice of name OK.) + + +Built-in modules +---------------- + +* Socket objects no longer support the avail() method. Use the select +module instead, or use this function to replace it: + + def avail(f): + import select + return f in select.select([f], [], [], 0)[0] + +* Initialization of stdwin is done differently. It actually modifies +sys.argv (taking out the options the X version of stdwin recognizes) +the first time it is imported. + +* A new built-in module parser provides a rudimentary interface to the +python parser. Corresponding standard library modules token and symbol +defines the numeric values of tokens and non-terminal symbols. + +* The posix module has aquired new functions setuid(), setgid(), +execve(), and exec() has been renamed to execv(). + +* The array module is extended with 8-byte object swaps, the 'i' +format character, and a reverse() method. The read() and write() +methods are renamed to fromfile() and tofile(). + +* The rotor module has freed of portability bugs. This introduces a +backward compatibility problem: strings encoded with the old rotor +module can't be decoded by the new version. + +* For select.select(), a timeout (4th) argument of None means the same +as leaving the timeout argument out. + +* Module strop (and hence standard library module string) has aquired +a new function: rindex(). Thanks to Amrit Prem! + +* Module regex defines a new function symcomp() which uses an extended +regular expression syntax: parenthesized subexpressions may be labeled +using the form "\(<labelname>...\)", and the group() method can return +sub-expressions by name. Thanks to Tracy Tims for these changes! + +* Multiple threads are now supported on Solaris 2. Thanks to Sjoerd +Mullender! + + +Standard library modules +------------------------ + +* The library is now split in several subdirectories: all stuff using +stdwin is in Lib/stdwin, all SGI specific (or SGI Indigo or GL) stuff +is in Lib/sgi, all Sun Sparc specific stuff is in Lib/sun4, and all +test modules are in Lib/test. The default module search path will +include all relevant subdirectories by default. + +* Module os now knows about trying to import dos. It defines +functions execl(), execle(), execlp() and execvp(). + +* New module dospath (should be attacked by a DOS hacker though). + +* All modules defining classes now define __init__() constructors +instead of init() methods. THIS IS AN INCOMPATIBLE CHANGE! + +* Some minor changes and bugfixes module ftplib (mostly Steve +Majewski's suggestions); the debug() method is renamed to +set_debuglevel(). + +* Some new test modules (not run automatically by testall though): +test_audioop, test_md5, test_rgbimg, test_select. + +* Module string now defines rindex() and rfind() in analogy of index() +and find(). It also defines atof() and atol() (and corresponding +exceptions) in analogy to atoi(). + +* Added help() functions to modules profile and pdb. + +* The wdb debugger (now in Lib/stdwin) now shows class or instance +variables on a double click. Thanks to Sjoerd Mullender! + +* The (undocumented) module lambda has gone -- you couldn't import it +any more, and it was basically more a demo than a library module... + + +Multimedia extensions +--------------------- + +* The optional built-in modules audioop and imageop are now standard +parts of the interpreter. Thanks to Sjoerd Mullender and Jack Jansen +for contributing this code! + +* There's a new operation in audioop: minmax(). + +* There's a new built-in module called rgbimg which supports portable +efficient reading of SGI RCG image files. Thanks also to Paul +Haeberli for the original code! (Who will contribute a GIF reader?) + +* The module aifc is gone -- you should now always use aifc, which has +received a facelift. + +* There's a new module sunau., for reading Sun (and NeXT) audio files. + +* There's a new module audiodev which provides a uniform interface to +(SGI Indigo and Sun Sparc) audio hardware. + +* There's a new module sndhdr which recognizes various sound files by +looking in their header and checking for various magic words. + + +Optimizations +------------- + +* Most optimizations below can be configured by compile-time flags. +Thanks to Sjoerd Mullender for submitting these optimizations! + +* Small integers (default -1..99) are shared -- i.e. if two different +functions compute the same value it is possible (but not +guaranteed!!!) that they return the same *object*. Python programs +can detect this but should *never* rely on it. + +* Empty tuples (which all compare equal) are shared in the same +manner. + +* Tuples of size up to 20 (default) are put in separate free lists +when deallocated. + +* There is a compile-time option to cache a string's hash function, +but this appeared to have a negligeable effect, and as it costs 4 +bytes per string it is disabled by default. + + +Embedding Python +---------------- + +* The initialization interface has been simplified somewhat. You now +only call "initall()" to initialize the interpreter. + +* The previously announced renaming of externally visible identifiers +has not been carried out. It will happen in a later release. Sorry. + + +Miscellaneous bugs that have been fixed +--------------------------------------- + +* All known portability bugs. + +* Version 0.9.9 dumped core in <listobject>.sort() which has been +fixed. Thanks to Jaap Vermeulen for fixing this and posting the fix +on the mailing list while I was away! + +* Core dump on a format string ending in '%', e.g. in the expression +'%' % None. + +* The array module yielded a bogus result for concatenation (a+b would +yield a+a). + +* Some serious memory leaks in strop.split() and strop.splitfields(). + +* Several problems with the nis module. + +* Subtle problem when copying a class method from another class +through assignment (the method could not be called). + + +Remaining bugs +-------------- + +* One problem with 64-bit machines remains -- since .pyc files are +portable and use only 4 bytes to represent an integer object, 64-bit +integer literals are silently truncated when written into a .pyc file. +Work-around: use eval('123456789101112'). + +* The freeze script doesn't work any more. A new and more portable +one can probably be cooked up using tricks from Extensions/mkext.py. + +* The dos support hasn't been tested yet. (Really Soon Now we should +have a PC with a working C compiler!) + + +=================================== +==> Release 0.9.9 (29 Jul 1993) <== +=================================== + +I *believe* these are the main user-visible changes in this release, +but there may be others. SGI users may scan the {src,lib}/ChangeLog +files for improvements of some SGI specific modules, e.g. aifc and +cl. Developers of extension modules should also read src/ChangeLog. + + +Naming of C symbols used by the Python interpreter +-------------------------------------------------- + +* This is the last release using the current naming conventions. New +naming conventions are explained in the file misc/NAMING. +Summarizing, all externally visible symbols get (at least) a "Py" +prefix, and most functions are renamed to the standard form +PyModule_FunctionName. + +* Writers of extensions are urged to start using the new naming +conventions. The next release will use the new naming conventions +throughout (it will also have a different source directory +structure). + +* As a result of the preliminary work for the great renaming, many +functions that were accidentally global have been made static. + + +BETA X11 support +---------------- + +* There are now modules interfacing to the X11 Toolkit Intrinsics, the +Athena widgets, and the Motif 1.1 widget set. These are not yet +documented except through the examples and README file in the demo/x11 +directory. It is expected that this interface will be replaced by a +more powerful and correct one in the future, which may or may not be +backward compatible. In other words, this part of the code is at most +BETA level software! (Note: the rest of Python is rock solid as ever!) + +* I understand that the above may be a bit of a disappointment, +however my current schedule does not allow me to change this situation +before putting the release out of the door. By releasing it +undocumented and buggy, at least some of the (working!) demo programs, +like itr (my Internet Talk Radio browser) become available to a larger +audience. + +* There are also modules interfacing to SGI's "Glx" widget (a GL +window wrapped in a widget) and to NCSA's "HTML" widget (which can +format HyperText Markup Language, the document format used by the +World Wide Web). + +* I've experienced some problems when building the X11 support. In +particular, the Xm and Xaw widget sets don't go together, and it +appears that using X11R5 is better than using X11R4. Also the threads +module and its link time options may spoil things. My own strategy is +to build two Python binaries: one for use with X11 and one without +it, which can contain a richer set of built-in modules. Don't even +*think* of loading the X11 modules dynamically... + + +Environmental changes +--------------------- + +* Compiled files (*.pyc files) created by this Python version are +incompatible with those created by the previous version. Both +versions detect this and silently create a correct version, but it +means that it is not a good idea to use the same library directory for +an old and a new interpreter, since they will start to "fight" over +the *.pyc files... + +* When a stack trace is printed, the exception is printed last instead +of first. This means that if the beginning of the stack trace +scrolled out of your window you can still see what exception caused +it. + +* Sometimes interrupting a Python operation does not work because it +hangs in a blocking system call. You can now kill the interpreter by +interrupting it three times. The second time you interrupt it, a +message will be printed telling you that the third interrupt will kill +the interpreter. The "sys.exitfunc" feature still makes limited +clean-up possible in this case. + + +Changes to the command line interface +------------------------------------- + +* The python usage message is now much more informative. + +* New option -i enters interactive mode after executing a script -- +useful for debugging. + +* New option -k raises an exception when an expression statement +yields a value other than None. + +* For each option there is now also a corresponding environment +variable. + + +Using Python as an embedded language +------------------------------------ + +* The distribution now contains (some) documentation on the use of +Python as an "embedded language" in other applications, as well as a +simple example. See the file misc/EMBEDDING and the directory embed/. + + +Speed improvements +------------------ + +* Function local variables are now generally stored in an array and +accessed using an integer indexing operation, instead of through a +dictionary lookup. (This compensates the somewhat slower dictionary +lookup caused by the generalization of the dictionary module.) + + +Changes to the syntax +--------------------- + +* Continuation lines can now *sometimes* be written without a +backslash: if the continuation is contained within nesting (), [] or +{} brackets the \ may be omitted. There's a much improved +python-mode.el in the misc directory which knows about this as well. + +* You can no longer use an empty set of parentheses to define a class +without base classes. That is, you no longer write this: + + class Foo(): # syntax error + ... + +You must write this instead: + + class Foo: + ... + +This was already the preferred syntax in release 0.9.8 but many +people seemed not to have picked it up. There's a Python script that +fixes old code: demo/scripts/classfix.py. + +* There's a new reserved word: "access". The syntax and semantics are +still subject of of research and debate (as well as undocumented), but +the parser knows about the keyword so you must not use it as a +variable, function, or attribute name. + + +Changes to the semantics of the language proper +----------------------------------------------- + +* The following compatibility hack is removed: if a function was +defined with two or more arguments, and called with a single argument +that was a tuple with just as many arguments, the items of this tuple +would be used as the arguments. This is no longer supported. + + +Changes to the semantics of classes and instances +------------------------------------------------- + +* Class variables are now also accessible as instance variables for +reading (assignment creates an instance variable which overrides the +class variable of the same name though). + +* If a class attribute is a user-defined function, a new kind of +object is returned: an "unbound method". This contains a pointer to +the class and can only be called with a first argument which is a +member of that class (or a derived class). + +* If a class defines a method __init__(self, arg1, ...) then this +method is called when a class instance is created by the classname() +construct. Arguments passed to classname() are passed to the +__init__() method. The __init__() methods of base classes are not +automatically called; the derived __init__() method must call these if +necessary (this was done so the derived __init__() method can choose +the call order and arguments for the base __init__() methods). + +* If a class defines a method __del__(self) then this method is called +when an instance of the class is about to be destroyed. This makes it +possible to implement clean-up of external resources attached to the +instance. As with __init__(), the __del__() methods of base classes +are not automatically called. If __del__ manages to store a reference +to the object somewhere, its destruction is postponed; when the object +is again about to be destroyed its __del__() method will be called +again. + +* Classes may define a method __hash__(self) to allow their instances +to be used as dictionary keys. This must return a 32-bit integer. + + +Minor improvements +------------------ + +* Function and class objects now know their name (the name given in +the 'def' or 'class' statement that created them). + +* Class instances now know their class name. + + +Additions to built-in operations +-------------------------------- + +* The % operator with a string left argument implements formatting +similar to sprintf() in C. The right argument is either a single +value or a tuple of values. All features of Standard C sprintf() are +supported except %p. + +* Dictionaries now support almost any key type, instead of just +strings. (The key type must be an immutable type or must be a class +instance where the class defines a method __hash__(), in order to +avoid losing track of keys whose value may change.) + +* Built-in methods are now compared properly: when comparing x.meth1 +and y.meth2, if x is equal to y and the methods are defined by the +same function, x.meth1 compares equal to y.meth2. + + +Additions to built-in functions +------------------------------- + +* str(x) returns a string version of its argument. If the argument is +a string it is returned unchanged, otherwise it returns `x`. + +* repr(x) returns the same as `x`. (Some users found it easier to +have this as a function.) + +* round(x) returns the floating point number x rounded to an whole +number, represented as a floating point number. round(x, n) returns x +rounded to n digits. + +* hasattr(x, name) returns true when x has an attribute with the given +name. + +* hash(x) returns a hash code (32-bit integer) of an arbitrary +immutable object's value. + +* id(x) returns a unique identifier (32-bit integer) of an arbitrary +object. + +* compile() compiles a string to a Python code object. + +* exec() and eval() now support execution of code objects. + + +Changes to the documented part of the library (standard modules) +---------------------------------------------------------------- + +* os.path.normpath() (a.k.a. posixpath.normpath()) has been fixed so +the border case '/foo/..' returns '/' instead of ''. + +* A new function string.find() is added with similar semantics to +string.index(); however when it does not find the given substring it +returns -1 instead of raising string.index_error. + + +Changes to built-in modules +--------------------------- + +* New optional module 'array' implements operations on sequences of +integers or floating point numbers of a particular size. This is +useful to manipulate large numerical arrays or to read and write +binary files consisting of numerical data. + +* Regular expression objects created by module regex now support a new +method named group(), which returns one or more \(...\) groups by number. +The number of groups is increased from 10 to 100. + +* Function compile() in module regex now supports an optional mapping +argument; a variable casefold is added to the module which can be used +as a standard uppercase to lowercase mapping. + +* Module time now supports many routines that are defined in the +Standard C time interface (<time.h>): gmtime(), localtime(), +asctime(), ctime(), mktime(), as well as these variables (taken from +System V): timezone, altzone, daylight and tzname. (The corresponding +functions in the undocumented module calendar have been removed; the +undocumented and unfinished module tzparse is now obsolete and will +disappear in a future release.) + +* Module strop (the fast built-in version of standard module string) +now uses C's definition of whitespace instead of fixing it to space, +tab and newline; in practice this usually means that vertical tab, +form feed and return are now also considered whitespace. It exports +the string of characters that are considered whitespace as well as the +characters that are considered lowercase or uppercase. + +* Module sys now defines the variable builtin_module_names, a list of +names of modules built into the current interpreter (including not +yet imported, but excluding two special modules that always have to be +defined -- sys and builtin). + +* Objects created by module sunaudiodev now also support flush() and +close() methods. + +* Socket objects created by module socket now support an optional +flags argument for their methods sendto() and recvfrom(). + +* Module marshal now supports dumping to and loading from strings, +through the functions dumps() and loads(). + +* Module stdwin now supports some new functionality. You may have to +ftp the latest version: ftp.cwi.nl:/pub/stdwin/stdwinforviews.tar.Z.) + + +Bugs fixed +---------- + +* Fixed comparison of negative long integers. + +* The tokenizer no longer botches input lines longer than BUFSIZ. + +* Fixed several severe memory leaks in module select. + +* Fixed memory leaks in modules socket and sv. + +* Fixed memory leak in divmod() for long integers. + +* Problems with definition of floatsleep() on Suns fixed. + +* Many portability bugs fixed (and undoubtedly new ones added :-). + + +Changes to the build procedure +------------------------------ + +* The Makefile supports some new targets: "make default" and "make +all". Both are by normally equivalent to "make python". + +* The Makefile no longer uses $> since it's not supported by all +versions of Make. + +* The header files now all contain #ifdef constructs designed to make +it safe to include the same header file twice, as well as support for +inclusion from C++ programs (automatic extern "C" { ... } added). + + +Freezing Python scripts +----------------------- + +* There is now some support for "freezing" a Python script as a +stand-alone executable binary file. See the script +demo/scripts/freeze.py. It will require some site-specific tailoring +of the script to get this working, but is quite worthwhile if you write +Python code for other who may not have built and installed Python. + + +MS-DOS +------ + +* A new MS-DOS port has been done, using MSC 6.0 (I believe). Thanks, +Marcel van der Peijl! This requires fewer compatibility hacks in +posixmodule.c. The executable is not yet available but will be soon +(check the mailing list). + +* The default PYTHONPATH has changed. + + +Changes for developers of extension modules +------------------------------------------- + +* Read src/ChangeLog for full details. + + +SGI specific changes +-------------------- + +* Read src/ChangeLog for full details. + + +================================== +==> Release 0.9.8 (9 Jan 1993) <== +================================== + +I claim no completeness here, but I've tried my best to scan the log +files throughout my source tree for interesting bits of news. A more +complete account of the changes is to be found in the various +ChangeLog files. See also "News for release 0.9.7beta" below if you're +still using release 0.9.6, and the file HISTORY if you have an even +older release. + + --Guido + + +Changes to the language proper +------------------------------ + +There's only one big change: the conformance checking for function +argument lists (of user-defined functions only) is stricter. Earlier, +you could get away with the following: + + (a) define a function of one argument and call it with any + number of arguments; if the actual argument count wasn't + one, the function would receive a tuple containing the + arguments arguments (an empty tuple if there were none). + + (b) define a function of two arguments, and call it with more + than two arguments; if there were more than two arguments, + the second argument would be passed as a tuple containing + the second and further actual arguments. + +(Note that an argument (formal or actual) that is a tuple is counted as +one; these rules don't apply inside such tuples, only at the top level +of the argument list.) + +Case (a) was needed to accommodate variable-length argument lists; +there is now an explicit "varargs" feature (precede the last argument +with a '*'). Case (b) was needed for compatibility with old class +definitions: up to release 0.9.4 a method with more than one argument +had to be declared as "def meth(self, (arg1, arg2, ...)): ...". +Version 0.9.6 provide better ways to handle both casees, bot provided +backward compatibility; version 0.9.8 retracts the compatibility hacks +since they also cause confusing behavior if a function is called with +the wrong number of arguments. + +There's a script that helps converting classes that still rely on (b), +provided their methods' first argument is called "self": +demo/scripts/methfix.py. + +If this change breaks lots of code you have developed locally, try +#defining COMPAT_HACKS in ceval.c. + +(There's a third compatibility hack, which is the reverse of (a): if a +function is defined with two or more arguments, and called with a +single argument that is a tuple with just as many arguments, the items +of this tuple will be used as the arguments. Although this can (and +should!) be done using the built-in function apply() instead, it isn't +withdrawn yet.) + + +One minor change: comparing instance methods works like expected, so +that if x is an instance of a user-defined class and has a method m, +then (x.m==x.m) yields 1. + + +The following was already present in 0.9.7beta, but not explicitly +mentioned in the NEWS file: user-defined classes can now define types +that behave in almost allrespects like numbers. See +demo/classes/Rat.py for a simple example. + + +Changes to the build process +---------------------------- + +The Configure.py script and the Makefile has been made somewhat more +bullet-proof, after reports of (minor) trouble on certain platforms. + +There is now a script to patch Makefile and config.c to add a new +optional built-in module: Addmodule.sh. Read the script before using! + +Useing Addmodule.sh, all optional modules can now be configured at +compile time using Configure.py, so there are no modules left that +require dynamic loading. + +The Makefile has been fixed to make it easier to use with the VPATH +feature of some Make versions (e.g. SunOS). + + +Changes affecting portability +----------------------------- + +Several minor portability problems have been solved, e.g. "malloc.h" +has been renamed to "mymalloc.h", "strdup.c" is no longer used, and +the system now tolerates malloc(0) returning 0. + +For dynamic loading on the SGI, Jack Jansen's dl 1.6 is now +distributed with Python. This solves several minor problems, in +particular scripts invoked using #! can now use dynamic loading. + + +Changes to the interpreter interface +------------------------------------ + +On popular demand, there's finally a "profile" feature for interactive +use of the interpreter. If the environment variable $PYTHONSTARTUP is +set to the name of an existing file, Python statements in this file +are executed when the interpreter is started in interactive mode. + +There is a new clean-up mechanism, complementing try...finally: if you +assign a function object to sys.exitfunc, it will be called when +Python exits or receives a SIGTERM or SIGHUP signal. + +The interpreter is now generally assumed to live in +/usr/local/bin/python (as opposed to /usr/local/python). The script +demo/scripts/fixps.py will update old scripts in place (you can easily +modify it to do other similar changes). + +Most I/O that uses sys.stdin/stdout/stderr will now use any object +assigned to those names as long as the object supports readline() or +write() methods. + +The parser stack has been increased to 500 to accommodate more +complicated expressions (7 levels used to be the practical maximum, +it's now about 38). + +The limit on the size of the *run-time* stack has completely been +removed -- this means that tuple or list displays can contain any +number of elements (formerly more than 50 would crash the +interpreter). + + +Changes to existing built-in functions and methods +-------------------------------------------------- + +The built-in functions int(), long(), float(), oct() and hex() now +also apply to class instalces that define corresponding methods +(__int__ etc.). + + +New built-in functions +---------------------- + +The new functions str() and repr() convert any object to a string. +The function repr(x) is in all respects equivalent to `x` -- some +people prefer a function for this. The function str(x) does the same +except if x is already a string -- then it returns x unchanged +(repr(x) adds quotes and escapes "funny" characters as octal escapes). + +The new function cmp(x, y) returns -1 if x<y, 0 if x==y, 1 if x>y. + + +Changes to general built-in modules +----------------------------------- + +The time module's functions are more general: time() returns a +floating point number and sleep() accepts one. Their accuracies +depends on the precision of the system clock. Millisleep is no longer +needed (although it still exists for now), but millitimer is still +needed since on some systems wall clock time is only available with +seconds precision, while a source of more precise time exists that +isn't synchronized with the wall clock. (On UNIX systems that support +the BSD gettimeofday() function, time.time() is as time.millitimer().) + +The string representation of a file object now includes an address: +'<file 'filename', mode 'r' at #######>' where ###### is a hex number +(the object's address) to make it unique. + +New functions added to posix: nice(), setpgrp(), and if your system +supports them: setsid(), setpgid(), tcgetpgrp(), tcsetpgrp(). + +Improvements to the socket module: socket objects have new methods +getpeername() and getsockname(), and the {get,set}sockopt methods can +now get/set any kind of option using strings built with the new struct +module. And there's a new function fromfd() which creates a socket +object given a file descriptor (useful for servers started by inetd, +which have a socket connected to stdin and stdout). + + +Changes to SGI-specific built-in modules +---------------------------------------- + +The FORMS library interface (fl) now requires FORMS 2.1a. Some new +functions have been added and some bugs have been fixed. + +Additions to al (audio library interface): added getname(), +getdefault() and getminmax(). + +The gl modules doesn't call "foreground()" when initialized (this +caused some problems) like it dit in 0.9.7beta (but not before). +There's a new gl function 'gversion() which returns a version string. + +The interface to sv (Indigo video interface) has totally changed. +(Sorry, still no documentation, but see the examples in +demo/sgi/{sv,video}.) + + +Changes to standard library modules +----------------------------------- + +Most functions in module string are now much faster: they're actually +implemented in C. The module containing the C versions is called +"strop" but you should still import "string" since strop doesn't +provide all the interfaces defined in string (and strop may be renamed +to string when it is complete in a future release). + +string.index() now accepts an optional third argument giving an index +where to start searching in the first argument, so you can find second +and further occurrences (this is similar to the regular expression +functions in regex). + +The definition of what string.splitfields(anything, '') should return +is changed for the last time: it returns a singleton list containing +its whole first argument unchanged. This is compatible with +regsub.split() which also ignores empty delimiter matches. + +posixpath, macpath: added dirname() and normpath() (and basename() to +macpath). + +The mainloop module (for use with stdwin) can now demultiplex input +from other sources, as long as they can be polled with select(). + + +New built-in modules +-------------------- + +Module struct defines functions to pack/unpack values to/from strings +representing binary values in native byte order. + +Module strop implements C versions of many functions from string (see +above). + +Optional module fcntl defines interfaces to fcntl() and ioctl() -- +UNIX only. (Not yet properly documented -- see however src/fcntl.doc.) + +Optional module mpz defines an interface to an altaernative long +integer implementation, the GNU MPZ library. + +Optional module md5 uses the GNU MPZ library to calculate MD5 +signatures of strings. + +There are also optional new modules specific to SGI machines: imageop +defines some simple operations to images represented as strings; sv +interfaces to the Indigo video board; cl interfaces to the (yet +unreleased) compression library. + + +New standard library modules +---------------------------- + +(Unfortunately the following modules are not all documented; read the +sources to find out more about them!) + +autotest: run testall without showing any output unless it differs +from the expected output + +bisect: use bisection to insert or find an item in a sorted list + +colorsys: defines conversions between various color systems (e.g. RGB +<-> YUV) + +nntplib: a client interface to NNTP servers + +pipes: utility to construct pipeline from templates, e.g. for +conversion from one file format to another using several utilities. + +regsub: contains three functions that are more or less compatible with +awk functions of the same name: sub() and gsub() do string +substitution, split() splits a string using a regular expression to +define how separators are define. + +test_types: test operations on the built-in types of Python + +toaiff: convert various audio file formats to AIFF format + +tzparse: parse the TZ environment parameter (this may be less general +than it could be, let me know if you fix it). + +(Note that the obsolete module "path" no longer exists.) + + +New SGI-specific library modules +-------------------------------- + +CL: constants for use with the built-in compression library interface (cl) + +Queue: a multi-producer, multi-consumer queue class implemented for +use with the built-in thread module + +SOCKET: constants for use with built-in module socket, e.g. to set/get +socket options. This is SGI-specific because the constants to be +passed are system-dependent. You can generate a version for your own +system by running the script demo/scripts/h2py.py with +/usr/include/sys/socket.h as input. + +cddb: interface to the database used by the CD player + +torgb: convert various image file types to rgb format (requires pbmplus) + + +New demos +--------- + +There's an experimental interface to define Sun RPC clients and +servers in demo/rpc. + +There's a collection of interfaces to WWW, WAIS and Gopher (both +Python classes and program providing a user interface) in demo/www. +This includes a program texi2html.py which converts texinfo files to +HTML files (the format used hy WWW). + +The ibrowse demo has moved from demo/stdwin/ibrowse to demo/ibrowse. + +For SGI systems, there's a whole collection of programs and classes +that make use of the Indigo video board in demo/sgi/{sv,video}. This +represents a significant amount of work that we're giving away! + +There are demos "rsa" and "md5test" that exercise the mpz and md5 +modules, respectively. The rsa demo is a complete implementation of +the RSA public-key cryptosystem! + +A bunch of games and examples submitted by Stoffel Erasmus have been +included in demo/stoffel. + +There are miscellaneous new files in some existing demo +subdirectories: classes/bitvec.py, scripts/{fixps,methfix}.py, +sgi/al/cmpaf.py, sockets/{mcast,gopher}.py. + +There are also many minor changes to existing files, but I'm too lazy +to run a diff and note the differences -- you can do this yourself if +you save the old distribution's demos. One highlight: the +stdwin/python.py demo is much improved! + + +Changes to the documentation +---------------------------- + +The LaTeX source for the library uses different macros to enable it to +be converted to texinfo, and from there to INFO or HTML format so it +can be browsed as a hypertext. The net result is that you can now +read the Python library documentation in Emacs info mode! + + +Changes to the source code that affect C extension writers +---------------------------------------------------------- + +The function strdup() no longer exists (it was used only in one places +and is somewhat of a a portability problem sice some systems have the +same function in their C library. + +The functions NEW() and RENEW() allocate one spare byte to guard +against a NULL return from malloc(0) being taken for an error, but +this should not be relied upon. + + +========================= +==> Release 0.9.7beta <== +========================= + + +Changes to the language proper +------------------------------ + +User-defined classes can now implement operations invoked through +special syntax, such as x[i] or `x` by defining methods named +__getitem__(self, i) or __repr__(self), etc. + + +Changes to the build process +---------------------------- + +Instead of extensive manual editing of the Makefile to select +compile-time options, you can now run a Configure.py script. +The Makefile as distributed builds a minimal interpreter sufficient to +run Configure.py. See also misc/BUILD + +The Makefile now includes more "utility" targets, e.g. install and +tags/TAGS + +Using the provided strtod.c and strtol.c are now separate options, as +on the Sun the provided strtod.c dumps core :-( + +The regex module is now an option chosen by the Makefile, since some +(old) C compilers choke on regexpr.c + + +Changes affecting portability +----------------------------- + +You need STDWIN version 0.9.7 (released 30 June 1992) for the stdwin +interface + +Dynamic loading is now supported for Sun (and other non-COFF systems) +throug dld-3.2.3, as well as for SGI (a new version of Jack Jansen's +DL is out, 1.4) + +The system-dependent code for the use of the select() system call is +moved to one file: myselect.h + +Thanks to Jaap Vermeulen, the code should now port cleanly to the +SEQUENT + + +Changes to the interpreter interface +------------------------------------ + +The interpretation of $PYTHONPATH in the environment is different: it +is inserted in front of the default path instead of overriding it + + +Changes to existing built-in functions and methods +-------------------------------------------------- + +List objects now support an optional argument to their sort() method, +which is a comparison function similar to qsort(3) in C + +File objects now have a method fileno(), used by the new select module +(see below) + + +New built-in function +--------------------- + +coerce(x, y): take two numbers and return a tuple containing them +both converted to a common type + + +Changes to built-in modules +--------------------------- + +sys: fixed core dumps in settrace() and setprofile() + +socket: added socket methods setsockopt() and getsockopt(); and +fileno(), used by the new select module (see below) + +stdwin: added fileno() == connectionnumber(), in support of new module +select (see below) + +posix: added get{eg,eu,g,u}id(); waitpid() is now a separate function. + +gl: added qgetfd() + +fl: added several new functions, fixed several obscure bugs, adapted +to FORMS 2.1 + + +Changes to standard modules +--------------------------- + +posixpath: changed implementation of ismount() + +string: atoi() no longer mistakes leading zero for octal number + +... + + +New built-in modules +-------------------- + +Modules marked "dynamic only" are not configured at compile time but +can be loaded dynamically. You need to turn on the DL or DLD option in +the Makefile for support dynamic loading of modules (this requires +external code). + +select: interfaces to the BSD select() system call + +dbm: interfaces to the (new) dbm library (dynamic only) + +nis: interfaces to some NIS functions (aka yellow pages) + +thread: limited form of multiple threads (sgi only) + +audioop: operations useful for audio programs, e.g. u-LAW and ADPCM +coding (dynamic only) + +cd: interface to Indigo SCSI CDROM player audio library (sgi only) + +jpeg: read files in JPEG format (dynamic only, sgi only; needs +external code) + +imgfile: read SGI image files (dynamic only, sgi only) + +sunaudiodev: interface to sun's /dev/audio (dynamic only, sun only) + +sv: interface to Indigo video library (sgi only) + +pc: a minimal set of MS-DOS interfaces (MS-DOS only) + +rotor: encryption, by Lance Ellinghouse (dynamic only) + + +New standard modules +-------------------- + +Not all these modules are documented. Read the source: +lib/<modulename>.py. Sometimes a file lib/<modulename>.doc contains +additional documentation. + +imghdr: recognizes image file headers + +sndhdr: recognizes sound file headers + +profile: print run-time statistics of Python code + +readcd, cdplayer: companion modules for built-in module cd (sgi only) + +emacs: interface to Emacs using py-connect.el (see below). + +SOCKET: symbolic constant definitions for socket options + +SUNAUDIODEV: symbolic constant definitions for sunaudiodef (sun only) + +SV: symbolic constat definitions for sv (sgi only) + +CD: symbolic constat definitions for cd (sgi only) + + +New demos +--------- + +scripts/pp.py: execute Python as a filter with a Perl-like command +line interface + +classes/: examples using the new class features + +threads/: examples using the new thread module + +sgi/cd/: examples using the new cd module + + +Changes to the documentation +---------------------------- + +The last-minute syntax changes of release 0.9.6 are now reflected +everywhere in the manuals + +The reference manual has a new section (3.2) on implementing new kinds +of numbers, sequences or mappings with user classes + +Classes are now treated extensively in the tutorial (chapter 9) + +Slightly restructured the system-dependent chapters of the library +manual + +The file misc/EXTENDING incorporates documentation for mkvalue() and +a new section on error handling + +The files misc/CLASSES and misc/ERRORS are no longer necessary + +The doc/Makefile now creates PostScript files automatically + + +Miscellaneous changes +--------------------- + +Incorporated Tim Peters' changes to python-mode.el, it's now version +1.06 + +A python/Emacs bridge (provided by Terrence M. Brannon) lets a Python +program running in an Emacs buffer execute Emacs lisp code. The +necessary Python code is in lib/emacs.py. The Emacs code is +misc/py-connect.el (it needs some external Emacs lisp code) + + +Changes to the source code that affect C extension writers +---------------------------------------------------------- + +New service function mkvalue() to construct a Python object from C +values according to a "format" string a la getargs() + +Most functions from pythonmain.c moved to new pythonrun.c which is +in libpython.a. This should make embedded versions of Python easier + +ceval.h is split in eval.h (which needs compile.h and only declares +eval_code) and ceval.h (which doesn't need compile.hand declares the +rest) + +ceval.h defines macros BGN_SAVE / END_SAVE for use with threads (to +improve the parallellism of multi-threaded programs by letting other +Python code run when a blocking system call or something similar is +made) + +In structmember.[ch], new member types BYTE, CHAR and unsigned +variants have been added + +New file xxmodule.c is a template for new extension modules. + + +================================== +==> Release 0.9.6 (6 Apr 1992) <== +================================== + +Misc news in 0.9.6: +- Restructured the misc subdirectory +- Reference manual completed, library manual much extended (with indexes!) +- the GNU Readline library is now distributed standard with Python +- the script "../demo/scripts/classfix.py" fixes Python modules using old + class syntax +- Emacs python-mode.el (was python.el) vastly improved (thanks, Tim!) +- Because of the GNU copyleft business I am not using the GNU regular + expression implementation but a free re-implementation by Tatu Ylonen + that recently appeared in comp.sources.misc (Bravo, Tatu!) + +New features in 0.9.6: +- stricter try stmt syntax: cannot mix except and finally clauses on 1 try +- New module 'os' supplants modules 'mac' and 'posix' for most cases; + module 'path' is replaced by 'os.path' +- os.path.split() return value differs from that of old path.split() +- sys.exc_type, sys.exc_value, sys.exc_traceback are set to the exception + currently being handled +- sys.last_type, sys.last_value, sys.last_traceback remember last unhandled + exception +- New function string.expandtabs() expands tabs in a string +- Added times() interface to posix (user & sys time of process & children) +- Added uname() interface to posix (returns OS type, hostname, etc.) +- New built-in function execfile() is like exec() but from a file +- Functions exec() and eval() are less picky about whitespace/newlines +- New built-in functions getattr() and setattr() access arbitrary attributes +- More generic argument handling in built-in functions (see "./EXTENDING") +- Dynamic loading of modules written in C or C++ (see "./DYNLOAD") +- Division and modulo for long and plain integers with negative operands + have changed; a/b is now floor(float(a)/float(b)) and a%b is defined + as a-(a/b)*b. So now the outcome of divmod(a,b) is the same as + (a/b, a%b) for integers. For floats, % is also changed, but of course + / is unchanged, and divmod(x,y) does not yield (x/y, x%y)... +- A function with explicit variable-length argument list can be declared + like this: def f(*args): ...; or even like this: def f(a, b, *rest): ... +- Code tracing and profiling features have been added, and two source + code debuggers are provided in the library (pdb.py, tty-oriented, + and wdb, window-oriented); you can now step through Python programs! + See sys.settrace() and sys.setprofile(), and "../lib/pdb.doc" +- '==' is now the only equality operator; "../demo/scripts/eqfix.py" is + a script that fixes old Python modules +- Plain integer right shift now uses sign extension +- Long integer shift/mask operations now simulate 2's complement + to give more useful results for negative operands +- Changed/added range checks for long/plain integer shifts +- Options found after "-c command" are now passed to the command in sys.argv + (note subtle incompatiblity with "python -c command -- -options"!) +- Module stdwin is better protected against touching objects after they've + been closed; menus can now also be closed explicitly +- Stdwin now uses its own exception (stdwin.error) + +New features in 0.9.5 (released as Macintosh application only, 2 Jan 1992): +- dictionary objects can now be compared properly; e.g., {}=={} is true +- new exception SystemExit causes termination if not caught; + it is raised by sys.exit() so that 'finally' clauses can clean up, + and it may even be caught. It does work interactively! +- new module "regex" implements GNU Emacs style regular expressions; + module "regexp" is rewritten in Python for backward compatibility +- formal parameter lists may contain trailing commas + +Bugs fixed in 0.9.6: +- assigning to or deleting a list item with a negative index dumped core +- divmod(-10L,5L) returned (-3L, 5L) instead of (-2L, 0L) + +Bugs fixed in 0.9.5: +- masking operations involving negative long integers gave wrong results + + +=================================== +==> Release 0.9.4 (24 Dec 1991) <== +=================================== + +- new function argument handling (see below) +- built-in apply(func, args) means func(args[0], args[1], ...) +- new, more refined exceptions +- new exception string values (NameError = 'NameError' etc.) +- better checking for math exceptions +- for sequences (string/tuple/list), x[-i] is now equivalent to x[len(x)-i] +- fixed list assignment bug: "a[1:1] = a" now works correctly +- new class syntax, without extraneous parentheses +- new 'global' statement to assign global variables from within a function + + +New class syntax +---------------- + +You can now declare a base class as follows: + + class B: # Was: class B(): + def some_method(self): ... + ... + +and a derived class thusly: + + class D(B): # Was: class D() = B(): + def another_method(self, arg): ... + +Multiple inheritance looks like this: + + class M(B, D): # Was: class M() = B(), D(): + def this_or_that_method(self, arg): ... + +The old syntax is still accepted by Python 0.9.4, but will disappear +in Python 1.0 (to be posted to comp.sources). + + +New 'global' statement +---------------------- + +Every now and then you have a global variable in a module that you +want to change from within a function in that module -- say, a count +of calls to a function, or an option flag, etc. Until now this was +not directly possible. While several kludges are known that +circumvent the problem, and often the need for a global variable can +be avoided by rewriting the module as a class, this does not always +lead to clearer code. + +The 'global' statement solves this dilemma. Its occurrence in a +function body means that, for the duration of that function, the +names listed there refer to global variables. For instance: + + total = 0.0 + count = 0 + + def add_to_total(amount): + global total, count + total = total + amount + count = count + 1 + +'global' must be repeated in each function where it is needed. The +names listed in a 'global' statement must not be used in the function +before the statement is reached. + +Remember that you don't need to use 'global' if you only want to *use* +a global variable in a function; nor do you need ot for assignments to +parts of global variables (e.g., list or dictionary items or +attributes of class instances). This has not changed; in fact +assignment to part of a global variable was the standard workaround. + + +New exceptions +-------------- + +Several new exceptions have been defined, to distinguish more clearly +between different types of errors. + +name meaning was + +AttributeError reference to non-existing attribute NameError +IOError unexpected I/O error RuntimeError +ImportError import of non-existing module or name NameError +IndexError invalid string, tuple or list index RuntimeError +KeyError key not in dictionary RuntimeError +OverflowError numeric overflow RuntimeError +SyntaxError invalid syntax RuntimeError +ValueError invalid argument value RuntimeError +ZeroDivisionError division by zero RuntimeError + +The string value of each exception is now its name -- this makes it +easier to experimentally find out which operations raise which +exceptions; e.g.: + + >>> KeyboardInterrupt + 'KeyboardInterrupt' + >>> + + +New argument passing semantics +------------------------------ + +Off-line discussions with Steve Majewski and Daniel LaLiberte have +convinced me that Python's parameter mechanism could be changed in a +way that made both of them happy (I hope), kept me happy, fixed a +number of outstanding problems, and, given some backward compatibility +provisions, would only break a very small amount of existing code -- +probably all mine anyway. In fact I suspect that most Python users +will hardly notice the difference. And yet it has cost me at least +one sleepless night to decide to make the change... + +Philosophically, the change is quite radical (to me, anyway): a +function is no longer called with either zero or one argument, which +is a tuple if there appear to be more arguments. Every function now +has an argument list containing 0, 1 or more arguments. This list is +always implemented as a tuple, and it is a (run-time) error if a +function is called with a different number of arguments than expected. + +What's the difference? you may ask. The answer is, very little unless +you want to write variadic functions -- functions that may be called +with a variable number of arguments. Formerly, you could write a +function that accepted one or more arguments with little trouble, but +writing a function that could be called with either 0 or 1 argument +(or more) was next to impossible. This is now a piece of cake: you +can simply declare an argument that receives the entire argument +tuple, and check its length -- it will be of size 0 if there are no +arguments. + +Another anomaly of the old system was the way multi-argument methods +(in classes) had to be declared, e.g.: + + class Point(): + def init(self, (x, y, color)): ... + def setcolor(self, color): ... + dev moveto(self, (x, y)): ... + def draw(self): ... + +Using the new scheme there is no need to enclose the method arguments +in an extra set of parentheses, so the above class could become: + + class Point: + def init(self, x, y, color): ... + def setcolor(self, color): ... + dev moveto(self, x, y): ... + def draw(self): ... + +That is, the equivalence rule between methods and functions has +changed so that now p.moveto(x,y) is equivalent to Point.moveto(p,x,y) +while formerly it was equivalent to Point.moveto(p,(x,y)). + +A special backward compatibility rule makes that the old version also +still works: whenever a function with exactly two arguments (at the top +level) is called with more than two arguments, the second and further +arguments are packed into a tuple and passed as the second argument. +This rule is invoked independently of whether the function is actually a +method, so there is a slight chance that some erroneous calls of +functions expecting two arguments with more than that number of +arguments go undetected at first -- when the function tries to use the +second argument it may find it is a tuple instead of what was expected. +Note that this rule will be removed from future versions of the +language; it is a backward compatibility provision *only*. + +Two other rules and a new built-in function handle conversion between +tuples and argument lists: + +Rule (a): when a function with more than one argument is called with a +single argument that is a tuple of the right size, the tuple's items +are used as arguments. + +Rule (b): when a function with exactly one argument receives no +arguments or more than one, that one argument will receive a tuple +containing the arguments (the tuple will be empty if there were no +arguments). + + +A new built-in function, apply(), was added to support functions that +need to call other functions with a constructed argument list. The call + + apply(function, tuple) + +is equivalent to + + function(tuple[0], tuple[1], ..., tuple[len(tuple)-1]) + + +While no new argument syntax was added in this phase, it would now be +quite sensible to add explicit syntax to Python for default argument +values (as in C++ or Modula-3), or a "rest" argument to receive the +remaining arguments of a variable-length argument list. + + +======================================================== +==> Release 0.9.3 (never made available outside CWI) <== +======================================================== + +- string sys.version shows current version (also printed on interactive entry) +- more detailed exceptions, e.g., IOError, ZeroDivisionError, etc. +- 'global' statement to declare module-global variables assigned in functions. +- new class declaration syntax: class C(Base1, Base2, ...): suite + (the old syntax is still accepted -- be sure to convert your classes now!) +- C shifting and masking operators: << >> ~ & ^ | (for ints and longs). +- C comparison operators: == != (the old = and <> remain valid). +- floating point numbers may now start with a period (e.g., .14). +- definition of integer division tightened (always truncates towards zero). +- new builtins hex(x), oct(x) return hex/octal string from (long) integer. +- new list method l.count(x) returns the number of occurrences of x in l. +- new SGI module: al (Indigo and 4D/35 audio library). +- the FORMS interface (modules fl and FL) now uses FORMS 2.0 +- module gl: added lrect{read,write}, rectzoom and pixmode; + added (non-GL) functions (un)packrect. +- new socket method: s.allowbroadcast(flag). +- many objects support __dict__, __methods__ or __members__. +- dir() lists anything that has __dict__. +- class attributes are no longer read-only. +- classes support __bases__, instances support __class__ (and __dict__). +- divmod() now also works for floats. +- fixed obscure bug in eval('1 '). + + +=================================== +==> Release 0.9.2 (Autumn 1991) <== +=================================== + +Highlights +---------- + +- tutorial now (almost) complete; library reference reorganized +- new syntax: continue statement; semicolons; dictionary constructors; + restrictions on blank lines in source files removed +- dramatically improved module load time through precompiled modules +- arbitrary precision integers: compute 2 to the power 1000 and more... +- arithmetic operators now accept mixed type operands, e.g., 3.14/4 +- more operations on list: remove, index, reverse; repetition +- improved/new file operations: readlines, seek, tell, flush, ... +- process management added to the posix module: fork/exec/wait/kill etc. +- BSD socket operations (with example servers and clients!) +- many new STDWIN features (color, fonts, polygons, ...) +- new SGI modules: font manager and FORMS library interface + + +Extended list of changes in 0.9.2 +--------------------------------- + +Here is a summary of the most important user-visible changes in 0.9.2, +in somewhat arbitrary order. Changes in later versions are listed in +the "highlights" section above. + + +1. Changes to the interpreter proper + +- Simple statements can now be separated by semicolons. + If you write "if t: s1; s2", both s1 and s2 are executed + conditionally. +- The 'continue' statement was added, with semantics as in C. +- Dictionary displays are now allowed on input: {key: value, ...}. +- Blank lines and lines bearing only a comment no longer need to + be indented properly. (A completely empty line still ends a multi- + line statement interactively.) +- Mixed arithmetic is supported, 1 compares equal to 1.0, etc. +- Option "-c command" to execute statements from the command line +- Compiled versions of modules are cached in ".pyc" files, giving a + dramatic improvement of start-up time +- Other, smaller speed improvements, e.g., extracting characters from + strings, looking up single-character keys, and looking up global + variables +- Interrupting a print operation raises KeyboardInterrupt instead of + only cancelling the print operation +- Fixed various portability problems (it now passes gcc with only + warnings -- more Standard C compatibility will be provided in later + versions) +- Source is prepared for porting to MS-DOS +- Numeric constants are now checked for overflow (this requires + standard-conforming strtol() and strtod() functions; a correct + strtol() implementation is provided, but the strtod() provided + relies on atof() for everything, including error checking + + +2. Changes to the built-in types, functions and modules + +- New module socket: interface to BSD socket primitives +- New modules pwd and grp: access the UNIX password and group databases +- (SGI only:) New module "fm" interfaces to the SGI IRIX Font Manager +- (SGI only:) New module "fl" interfaces to Mark Overmars' FORMS library +- New numeric type: long integer, for unlimited precision + - integer constants suffixed with 'L' or 'l' are long integers + - new built-in function long(x) converts int or float to long + - int() and float() now also convert from long integers +- New built-in function: + - pow(x, y) returns x to the power y +- New operation and methods for lists: + - l*n returns a new list consisting of n concatenated copies of l + - l.remove(x) removes the first occurrence of the value x from l + - l.index(x) returns the index of the first occurrence of x in l + - l.reverse() reverses l in place +- New operation for tuples: + - t*n returns a tuple consisting of n concatenated copies of t +- Improved file handling: + - f.readline() no longer restricts the line length, is faster, + and isn't confused by null bytes; same for raw_input() + - f.read() without arguments reads the entire (rest of the) file + - mixing of print and sys.stdout.write() has different effect +- New methods for files: + - f.readlines() returns a list containing the lines of the file, + as read with f.readline() + - f.flush(), f.tell(), f.seek() call their stdio counterparts + - f.isatty() tests for "tty-ness" +- New posix functions: + - _exit(), exec(), fork(), getpid(), getppid(), kill(), wait() + - popen() returns a file object connected to a pipe + - utime() replaces utimes() (the latter is not a POSIX name) +- New stdwin features, including: + - font handling + - color drawing + - scroll bars made optional + - polygons + - filled and xor shapes + - text editing objects now have a 'settext' method + + +3. Changes to the standard library + +- Name change: the functions path.cat and macpath.cat are now called + path.join and macpath.join +- Added new modules: formatter, mutex, persist, sched, mainloop +- Added some modules and functionality to the "widget set" (which is + still under development, so please bear with me): + DirList, FormSplit, TextEdit, WindowSched +- Fixed module testall to work non-interactively +- Module string: + - added functions join() and joinfields() + - fixed center() to work correct and make it "transitive" +- Obsolete modules were removed: util, minmax +- Some modules were moved to the demo directory + + +4. Changes to the demonstration programs + +- Added new useful scipts: byteyears, eptags, fact, from, lfact, + objgraph, pdeps, pi, primes, ptags, which +- Added a bunch of socket demos +- Doubled the speed of ptags +- Added new stdwin demos: microedit, miniedit +- Added a windowing interface to the Python interpreter: python (most + useful on the Mac) +- Added a browser for Emacs info files: demo/stdwin/ibrowse + (yes, I plan to put all STDWIN and Python documentation in texinfo + form in the future) + + +5. Other changes to the distribution + +- An Emacs Lisp file "python.el" is provided to facilitate editing + Python programs in GNU Emacs (slightly improved since posted to + gnu.emacs.sources) +- Some info on writing an extension in C is provided +- Some info on building Python on non-UNIX platforms is provided + + +===================================== +==> Release 0.9.1 (February 1991) <== +===================================== + +- Micro changes only +- Added file "patchlevel.h" + + +===================================== +==> Release 0.9.0 (February 1991) <== +===================================== + +Original posting to alt.sources. diff --git a/sys/src/cmd/python/Misc/NEWS b/sys/src/cmd/python/Misc/NEWS new file mode 100644 index 000000000..6475b767d --- /dev/null +++ b/sys/src/cmd/python/Misc/NEWS @@ -0,0 +1,2782 @@ ++++++++++++ +Python News ++++++++++++ + +(editors: check NEWS.help for information about editing NEWS using ReST.) + +What's New in Python 2.5.1? +============================= + +*Release date: 18-APR-2007* + +Core and builtins +----------------- + +- Revert SF #1615701: dict.update() does *not* call __getitem__() or keys() + if subclassed. This is to remain consistent with 2.5. + Also revert revision 53667 with made a similar change to set.update(). + + +What's New in Python 2.5.1c1? +============================= + +*Release date: 05-APR-2007* + +Core and builtins +----------------- + +- Patch #1682205: a TypeError while unpacking an iterable is no longer + masked by a generic one with the message "unpack non-sequence". + +- Patch #1642547: Fix an error/crash when encountering syntax errors in + complex if statements. + +- Patch #1462488: Python no longer segfaults when ``object.__reduce_ex__()`` + is called with an object that is faking its type. + +- Patch #1680015: Don't modify __slots__ tuple if it contains an unicode + name. + +- Patch #922167: Python no longer segfaults when faced with infinitely + self-recursive reload() calls (as reported by bug #742342). + +- Patch #1675981: remove unreachable code from ``type.__new__()`` method. + +- Patch #1638879: don't accept strings with embedded NUL bytes in long(). + +- Bug #1674503: close the file opened by execfile() in an error condition. + +- Patch #1674228: when assigning a slice (old-style), check for the + sq_ass_slice instead of the sq_slice slot. + +- Bug #1669182: prevent crash when trying to print an unraisable error + from a string exception. + +- The peephole optimizer left None as a global in functions with a docstring + and an explicit return value. + +- Bug #1653736: Properly discard third argument to slot_nb_inplace_power. + +- SF #151204: enumerate() now raises an Overflow error at sys.maxint items. + +- Bug #1377858: Fix the segfaulting of the interpreter when an object created + a weakref on itself during a __del__ call for new-style classes (classic + classes still have the bug). + +- Bug #1648179: set.update() did not recognize an overridden __iter__ + method in subclasses of dict. + +- Bug #1579370: Make PyTraceBack_Here use the current thread, not the + frame's thread state. + +- patch #1630975: Fix crash when replacing sys.stdout in sitecustomize.py + +- Bug #1637022: Prefix AST symbols with _Py_. + +- Prevent seg fault on shutdown which could occur if an object + raised a warning. + +- Bug #1566280: Explicitly invoke threading._shutdown from Py_Main, + to avoid relying on atexit. + +- Bug #1590891: random.randrange don't return correct value for big number + +- Bug #1456209: In some obscure cases it was possible for a class with a + custom ``__eq__()`` method to confuse set internals when class instances + were used as a set's elements and the ``__eq__()`` method mutated the set. + +- The repr for self-referential sets and fronzensets now shows "..." instead + of falling into infinite recursion. + +- Eliminated unnecessary repeated calls to hash() by set.intersection() and + set.symmetric_difference_update(). + +- Bug #1591996: Correctly forward exception in instance_contains(). + +- Bug #1588287: fix invalid assertion for `1,2` in debug builds. + +- Bug #1576657: when setting a KeyError for a tuple key, make sure that + the tuple isn't used as the "exception arguments tuple". Applied to + both sets and dictionaries. + +- Bug #1565514, SystemError not raised on too many nested blocks. + +- Bug #1576174: WindowsError now displays the windows error code + again, no longer the posix error code. + +- Patch #1549049: Support long values in structmember. + +- Bug #1542016: make sys.callstats() match its docstring and return an + 11-tuple (only relevant when Python is compiled with -DCALL_PROFILE). + +- Bug #1545497: when given an explicit base, int() did ignore NULs + embedded in the string to convert. + +- Bug #1569998: break inside a try statement (outside a loop) is now + recognized and rejected. + +- Patch #1542451: disallow continue anywhere under a finally. + +- list.pop(x) accepts any object x following the __index__ protocol. + +- Fix some leftovers from the conversion from int to Py_ssize_t + (relevant to strings and sequences of more than 2**31 items). + +- A number of places, including integer negation and absolute value, + were fixed to not rely on undefined behaviour of the C compiler + anymore. + +- Bug #1566800: make sure that EnvironmentError can be called with any + number of arguments, as was the case in Python 2.4. + +- Patch #1567691: super() and new.instancemethod() now don't accept + keyword arguments any more (previously they accepted them, but didn't + use them). + +- Fix a bug in the parser's future statement handling that led to "with" + not being recognized as a keyword after, e.g., this statement: + from __future__ import division, with_statement + +- Bug #1557232: fix seg fault with def f((((x)))) and def f(((x),)). + +- Fix %zd string formatting on Mac OS X so it prints negative numbers. + +- Allow exception instances to be directly sliced again. + + +Extension Modules +----------------- + +- Bug #1563759: struct.unpack doens't support buffer protocol objects + +- Bug #1686475: Support stat'ing open files on Windows again. + +- Bug #1647541: Array module's buffer interface can now handle empty arrays. + +- Bug #1693079: The array module can now successfully pickle empty arrays. + +- Bug #1688393: Prevent crash in socket.recvfrom if length is negative. + +- Bug #1622896: fix a rare corner case where the bz2 module raised an + error in spite of a succesful compression. + +- Patch #1654417: make operator.{get,set,del}slice use the full range + of Py_ssize_t. + +- Patch #1646728: datetime.fromtimestamp fails with negative + fractional times. With unittest. + +- Patch #1494140: Add documentation for the new struct.Struct object. + +- Patch #1657276: Make NETLINK_DNRTMSG conditional. + +- Bug #1653736: Fix signature of time_isoformat. + +- operator.count() now raises an OverflowError when the count reaches sys.maxint. + +- Bug #1575169: operator.isSequenceType() now returns False for subclasses of dict. + +- collections.defaultdict() now verifies that the factory function is callable. + +- Bug #1486663: don't reject keyword arguments for subclasses of builtin + types. + +- The version number of the ctypes package was changed to "1.0.2". + +- Bug #1664966: Fix crash in exec if Unicode filename can't be decoded. + +- Patch #1544279: Improve thread-safety of the socket module by moving + the sock_addr_t storage out of the socket object. + +- Patch #1615868: make bz2.BZFile.seek() work for offsets >2GiB. + +- Bug #1563807: _ctypes built on AIX fails with ld ffi error. + +- Bug #1598620: A ctypes Structure cannot contain itself. + +- Bug #1588217: don't parse "= " as a soft line break in binascii's + a2b_qp() function, instead leave it in the string as quopri.decode() + does. + +- Patch #838546: Make terminal become controlling in pty.fork() + +- Patch #1560695: Add .note.GNU-stack to ctypes' sysv.S so that + ctypes isn't considered as requiring executable stacks. + +- Bug #1567666: Emulate GetFileAttributesExA for Win95. + +- Bug #1548891: The cStringIO.StringIO() constructor now encodes unicode + arguments with the system default encoding just like the write() + method does, instead of converting it to a raw buffer. + +- Bug #1565150: Fix subsecond processing for os.utime on Windows. + +- Patch #1572724: fix typo ('=' instead of '==') in _msi.c. + +- Bug #1572832: fix a bug in ISO-2022 codecs which may cause segfault + when encoding non-BMP unicode characters. + +- Bug #1556784: allow format strings longer than 127 characters in + datetime's strftime function. + +- Fix itertools.count(n) to work with negative numbers again. + +- Make regex engine raise MemoryError if allocating memory fails. + +- fixed a bug with bsddb.DB.stat: the flags and txn keyword arguments + were transposed. + +- Added support for linking the bsddb module against BerkeleyDB 4.5.x. + +- Modifying an empty deque during iteration now raises RuntimeError + instead of StopIteration. + +- Bug #1552726: fix polling at the interpreter prompt when certain + versions of the readline library are in use. + +- Bug #1633621: if curses.resizeterm() or curses.resize_term() is called, + update _curses.LINES, _curses.COLS, curses.LINES and curses.COLS. + +- Fix an off-by-one bug in locale.strxfrm(). + +Library +------- + +- Patch #1685563: remove (don't add) duplicate paths in distutils.MSVCCompiler. + +- Bug #978833: Revert r50844, as it broke _socketobject.dup. + +- Bug #1675967: re patterns pickled with Python 2.4 and earlier can + now be unpickled with Python 2.5. + +- Bug #1684254: webbrowser now uses shlex to split any command lines + given to get(). It also detects when you use '&' as the last argument + and creates a BackgroundBrowser then. + +- Patch #1681153: the wave module now closes a file object it opened if + initialization failed. + +- Bug #767111: fix long-standing bug in urllib which caused an + AttributeError instead of an IOError when the server's response didn't + contain a valid HTTP status line. + +- Bug #1629369: Correctly parse multiline comment in address field. + +- Bug #1582282: Fix email.header.decode_header() to properly treat encoded + words with no delimiting whitespace as a single word. + +- Patch #1449244: Support Unicode strings in + email.message.Message.{set_charset,get_content_charset}. + +- Patch #1542681: add entries for "with", "as" and "CONTEXTMANAGERS" to + pydoc's help keywords. + +- Patch #1192590: Fix pdb's "ignore" and "condition" commands so they trap + the IndexError caused by passing in an invalid breakpoint number. + +- Bug #1531963: Make SocketServer.TCPServer's server_address always + be equal to calling getsockname() on the server's socket. Fixed by patch + #1545011. + +- Bug #1651235: When a tuple was passed to a ctypes function call, + Python would crash instead of raising an error. + +- Fix bug #1646630: ctypes.string_at(buf, 0) and ctypes.wstring_at(buf, 0) + returned string up to the first NUL character. + +- Bug #1637850: make_table in difflib did not work with unicode + +- Bugs #1676321: the empty() function in sched.py returned the wrong result + +- unittest now verifies more of its assumptions. In particular, TestCase + and TestSuite subclasses (not instances) are no longer accepted in + TestSuite.addTest(). This should cause no incompatibility since it + never made sense with ordinary subclasses -- the failure just occurred + later, with a more cumbersome exception. + +- Patch #685268: Consider a package's __path__ in imputil. + +- Patch 1463026: Support default namespace in XMLGenerator. + +- Patch 1571379: Make trace's --ignore-dir facility work in the face of + relative directory names. + +- Bug #1600860: Search for shared python library in LIBDIR, not lib/python/config, + on "linux" and "gnu" systems. + +- Bug #1124861: Automatically create pipes if GetStdHandle fails in + subprocess. + +- Patch #783050: the pty.fork() function now closes the slave fd + correctly. + +- Patch #1638243: the compiler package is now able to correctly compile + a with statement; previously, executing code containing a with statement + compiled by the compiler package crashed the interpreter. + +- Bug #1643943: Fix %U handling for time.strptime. + +- Bug #1598181: Avoid O(N**2) bottleneck in subprocess communicate(). + +- Patch #1627441: close sockets properly in urllib2. + +- Bug #1610795: ctypes.util.find_library works now on BSD systems. + +- Fix sort stability in heapq.nlargest() and nsmallest(). + +- Patch #1504073: Fix tarfile.open() for mode "r" with a fileobj argument. + +- Patch #1262036: Prevent TarFiles from being added to themselves under + certain conditions. + +- Patch #1230446: tarfile.py: fix ExFileObject so that read() and tell() + work correctly together with readline(). + +- Bug #737202: Make CGIHTTPServer work for scripts in subdirectories. + Fix by Titus Brown. + +- Patch #827559: Make SimpleHTTPServer redirect when a directory URL + is missing the trailing slash, so that relative links work correctly. + Patch by Chris Gonnerman. + +- Patch #1608267: fix a race condition in os.makedirs() is the directory + to be created is already there. + +- Patch #1610437: fix a tarfile bug with long filename headers. + +- Patch #1472877: Fix Tix subwidget name resolution. + +- Patch #1594554: Always close a tkSimpleDialog on ok(), even + if an exception occurs. + +- Patch #1538878: Don't make tkSimpleDialog dialogs transient if + the parent window is withdrawn. + +- Patch #1360200: Use unmangled_version RPM spec field to deal with + file name mangling. + +- Patch #1359217: Process 2xx response in an ftplib transfer + that precedes an 1xx response. + +- Patch #1060577: Extract list of RPM files from spec file in + bdist_rpm + +- Bug #1586613: fix zlib and bz2 codecs' incremental en/decoders. + +- Patch #1583880: fix tarfile's problems with long names and posix/ + GNU modes. + +- Fix codecs.EncodedFile which did not use file_encoding in 2.5.0, and + fix all codecs file wrappers to work correctly with the "with" + statement (bug #1586513). + +- ctypes callback functions only support 'fundamental' data types as + result type. Raise an error when something else is used. This is a + partial fix for Bug #1574584. + +- Bug #813342: Start the IDLE subprocess with -Qnew if the parent + is started with that option. + +- Bug #1446043: correctly raise a LookupError if an encoding name given + to encodings.search_function() contains a dot. + +- Bug #1545341: The 'classifier' keyword argument to the Distutils setup() + function now accepts tuples as well as lists. + +- Bug #1560617: in pyclbr, return full module name not only for classes, + but also for functions. + +- Bug #1566602: correct failure of posixpath unittest when $HOME ends + with a slash. + +- Bug #1565661: in webbrowser, split() the command for the default + GNOME browser in case it is a command with args. + +- Bug #1569790: mailbox.py: Maildir.get_folder() and MH.get_folder() + weren't passing the message factory on to newly created Maildir/MH + objects. + +- Bug #1575506: mailbox.py: Single-file mailboxes didn't re-lock + properly in their flush() method. + +- Patch #1514543: mailbox.py: In the Maildir class, report errors if there's + a filename clash instead of possibly losing a message. (Patch by David + Watson.) + +- Patch #1514544: mailbox.py: Try to ensure that messages/indexes have + been physically written to disk after calling .flush() or + .close(). (Patch by David Watson.) + +- mailbox.py: Change MH.pack() to not lock individual message files; this + wasn't consistent with existing implementations of message packing, and + was buggy on some platforms. + +- Bug #1633678: change old mailbox.UnixMailbox class to parse + 'From' lines less strictly. + +- Bug #1576241: fix functools.wraps() to work on built-in functions. + +- Patch #1574068: fix urllib/urllib2 to not insert line breaks when + HTTP authentication data was very long. + +- Patch #1617413: fix urllib's support for HTTP Basic authentication via HTTPS + (patch by Dug Song). + +- Fix a bug in traceback.format_exception_only() that led to an error + being raised when print_exc() was called without an exception set. + In version 2.4, this printed "None", restored that behavior. + +- Make webbrowser.BackgroundBrowser usable in Windows (it wasn't because + the close_fds arg to subprocess.Popen is not supported). + + +Tools/Demos +----------- + +- Patch #1552024: add decorator support to unparse.py demo script. + +- idle: Honor the "Cancel" action in the save dialog (Debian bug #299092). + + +Tests +----- + +- Cause test.test_socket_ssl:test_basic to raise + test.test_support.ResourceDenied when an HTTPS connection times out. + +- Remove passwd.adjunct.byname from list of maps + for test_nis. + + +Build +----- + +- Bug #1655392: don't add -L/usr/lib/pythonX.Y/config to the LDFLAGS + returned by python-config if Python was built with --enable-shared + because that prevented the shared library from being used. + +- Patch #1569798: fix a bug in distutils when building Python from a + directory within sys.exec_prefix. + +- Bug #1675511: Use -Kpic instead of -xcode=pic32 on Solaris/x86. + +- Disable _XOPEN_SOURCE on NetBSD 1.x. + +- Bug #1578513: Cross compilation was broken by a change to configure. + Repair so that it's back to how it was in 2.4.3. + +- Patch #1576954: Update VC6 build directory; remove redundant + files in VC7. + +- Fix build failure on kfreebsd and on the hurd. + +- Fix the build of the library reference in info format. + + +Windows +------- + +- Conditionalize definition of _CRT_SECURE_NO_DEPRECATE + and _CRT_NONSTDC_NO_DEPRECATE. + + +Documentation +------------- + +- Patch #1489771: the syntax rules in Python Reference Manual were + updated to reflect the current Python syntax. + +- Patch #1686451: Fix return type for + PySequence_{Count,Index,Fast_GET_SIZE}. + + +What's New in Python 2.5 (final) +================================ + +*Release date: 19-SEP-2006* + +No changes since release candidate 2. + + +What's New in Python 2.5 release candidate 2? +============================================= + +*Release date: 12-SEP-2006* + +Core and builtins +----------------- + +- Make _PyGILState_NoteThreadState() static, it was not used anywhere + outside of pystate.c and should not be necessary. + +- Bug #1551432: Exceptions do not define an explicit __unicode__ method. This + allows calling unicode() on exceptions classes directly to succeed. + +- Bug #1542051: Exceptions now correctly call PyObject_GC_UnTrack. + Also make sure that every exception class has __module__ set to + 'exceptions'. + +- Bug #1550983: emit better error messages for erroneous relative + imports (if not in package and if beyond toplevel package). + +- Overflow checking code in integer division ran afoul of new gcc + optimizations. Changed to be more standard-conforming. + +- Patch #1541585: fix buffer overrun when performing repr() on + a unicode string in a build with wide unicode (UCS-4) support. + +- Patch #1546288: fix seg fault in dict_equal due to ref counting bug. + +- The return tuple from str.rpartition(sep) is (tail, sep, head) where + head is the original string if sep was not found. + +- Bug #1520864: unpacking singleton tuples in list comprehensions and + generator expressions (x for x, in ... ) works again. Fixing this problem + required changing the .pyc magic number. This means that .pyc files + generated before 2.5c2 will be regenerated. + + +Library +------- + +- Reverted patch #1504333 because it introduced an infinite loop. + +- Patch #1553314: Fix the inspect.py slowdown that was hurting IPython & SAGE + by adding smarter caching in inspect.getmodule(). + +- Fix missing import of the types module in logging.config. + +- Patch #1550886: Fix decimal module context management implementation + to match the localcontext() example from PEP 343. + +- Bug #1541863: uuid.uuid1 failed to generate unique identifiers + on systems with low clock resolution. + +- Bug #1543303, patch #1543897: remove NUL padding from tarfiles. + +- Bug #1531862: Do not close standard file descriptors in subprocess. + + +Extension Modules +----------------- + +- Bug #1599782: fix segfault on bsddb.db.DB().type(). + +- Fix bugs in ctypes: + - anonymous structure fields that have a bit-width specified did not work + - cast function did not accept c_char_p or c_wchar_p instances as first arg + +- Bug #1551427: fix a wrong NULL pointer check in the win32 version + of os.urandom(). + +- Bug #1548092: fix curses.tparm seg fault on invalid input. + +- Bug #1550714: fix SystemError from itertools.tee on negative value for n. + +- Fixed a few bugs on cjkcodecs: + - gbk and gb18030 codec now handle U+30FB KATAKANA MIDDLE DOT correctly. + - iso2022_jp_2 codec now encodes into G0 for KS X 1001, GB2312 + codepoints to conform the standard. + - iso2022_jp_3 and iso2022_jp_2004 codec can encode JIS X 0213:2 + codepoints now. + +Tests +----- + +- Patch #1559413: Fix test_cmd_line if sys.executable contains a space. + +- Fix bsddb test_basics.test06_Transactions to check the version + number properly. + + +Documentation +------------- + +- Patch #1679379: add documentation for fnmatch.translate(). + +- Patch #1671450: add a section about subclassing builtin types to the + "extending and embedding" tutorial. + +- Bug #1629125: fix wrong data type (int -> Py_ssize_t) in PyDict_Next + docs. + +- Bug #1565919: document set types in the Language Reference. + +- Bug #1546052: clarify that PyString_FromString(AndSize) copies the + string pointed to by its parameter. + +- Bug #1566663: remove obsolete example from datetime docs. + +- Bug #1541682: Fix example in the "Refcount details" API docs. + Additionally, remove a faulty example showing PySequence_SetItem applied + to a newly created list object and add notes that this isn't a good idea. + + +Tools +----- + +- Bug #1546372: Fixed small bugglet in pybench that caused a missing + file not to get reported properly. + + +Build +----- + +- Bug #1568842: Fix test for uintptr_t. + +- Patch #1540470, for OpenBSD 4.0. + +- Patch #1545507: Exclude ctypes package in Win64 MSI file. + +- Fix OpenSSL debug build process. + + +C API +----- + +- Bug #1542693: remove semi-colon at end of PyImport_ImportModuleEx macro + so it can be used as an expression. + + +What's New in Python 2.5 release candidate 1? +============================================= + +*Release date: 17-AUG-2006* + +Core and builtins +----------------- + +- Fix infinite recursion when subclassing long and overriding __hash__. + +- Fix concatenation (+=) of long strings. + +- Unicode objects will no longer raise an exception when being + compared equal or unequal to a string and a UnicodeDecodeError + exception occurs, e.g. as result of a decoding failure. + + Instead, the equal (==) and unequal (!=) comparison operators will + now issue a UnicodeWarning and interpret the two objects as + unequal. The UnicodeWarning can be filtered as desired using + the warning framework, e.g. silenced completely, turned into an + exception, logged, etc. + + Note that compare operators other than equal and unequal will still + raise UnicodeDecodeError exceptions as they've always done. + +- Fix segfault when doing string formatting on subclasses of long. + +- Fix bug related to __len__ functions using values > 2**32 on 64-bit machines + with new-style classes. + +- Fix bug related to __len__ functions returning negative values with + classic classes. + +- Patch #1538606, Fix __index__() clipping. There were some problems + discovered with the API and how integers that didn't fit into Py_ssize_t + were handled. This patch attempts to provide enough alternatives + to effectively use __index__. + +- Bug #1536021: __hash__ may now return long int; the final hash + value is obtained by invoking hash on the long int. + +- Bug #1536786: buffer comparison could emit a RuntimeWarning. + +- Bug #1535165: fixed a segfault in input() and raw_input() when + sys.stdin is closed. + +- On Windows, the PyErr_Warn function is now exported from + the Python dll again. + +- Bug #1191458: tracing over for loops now produces a line event + on each iteration. Fixing this problem required changing the .pyc + magic number. This means that .pyc files generated before 2.5c1 + will be regenerated. + +- Bug #1333982: string/number constants were inappropriately stored + in the byte code and co_consts even if they were not used, ie + immediately popped off the stack. + +- Fixed a reference-counting problem in property(). + + +Library +------- + +- Fix a bug in the ``compiler`` package that caused invalid code to be + generated for generator expressions. + +- The distutils version has been changed to 2.5.0. The change to + keep it programmatically in sync with the Python version running + the code (introduced in 2.5b3) has been reverted. It will continue + to be maintained manually as static string literal. + +- If the Python part of a ctypes callback function returns None, + and this cannot be converted to the required C type, an exception is + printed with PyErr_WriteUnraisable. Before this change, the C + callback returned arbitrary values to the calling code. + +- The __repr__ method of a NULL ctypes.py_object() no longer raises + an exception. + +- uuid.UUID now has a bytes_le attribute. This returns the UUID in + little-endian byte order for Windows. In addition, uuid.py gained some + workarounds for clocks with low resolution, to stop the code yielding + duplicate UUIDs. + +- Patch #1540892: site.py Quitter() class attempts to close sys.stdin + before raising SystemExit, allowing IDLE to honor quit() and exit(). + +- Bug #1224621: make tabnanny recognize IndentationErrors raised by tokenize. + +- Patch #1536071: trace.py should now find the full module name of a + file correctly even on Windows. + +- logging's atexit hook now runs even if the rest of the module has + already been cleaned up. + +- Bug #1112549, fix DoS attack on cgi.FieldStorage. + +- Bug #1531405, format_exception no longer raises an exception if + str(exception) raised an exception. + +- Fix a bug in the ``compiler`` package that caused invalid code to be + generated for nested functions. + + +Extension Modules +----------------- + +- Ignore data that arrives before the opening start tag in C etree. + +- Patch #1511317: don't crash on invalid hostname (alias) info. + +- Patch #1535500: fix segfault in BZ2File.writelines and make sure it + raises the correct exceptions. + +- Patch # 1536908: enable building ctypes on OpenBSD/AMD64. The + '-no-stack-protector' compiler flag for OpenBSD has been removed. + +- Patch #1532975 was applied, which fixes Bug #1533481: ctypes now + uses the _as_parameter_ attribute when objects are passed to foreign + function calls. The ctypes version number was changed to 1.0.1. + +- Bug #1530559, struct.pack raises TypeError where it used to convert. + Passing float arguments to struct.pack when integers are expected + now triggers a DeprecationWarning. + + +Tests +----- + +- test_socketserver should now work on cygwin and not fail sporadically + on other platforms. + +- test_mailbox should now work on cygwin versions 2006-08-10 and later. + +- Bug #1535182: really test the xreadlines() method of bz2 objects. + +- test_threading now skips testing alternate thread stack sizes on + platforms that don't support changing thread stack size. + + +Documentation +------------- + +- Patch #1534922: unittest docs were corrected and enhanced. + + +Build +----- + +- Bug #1535502, build _hashlib on Windows, and use masm assembler + code in OpenSSL. + +- Bug #1534738, win32 debug version of _msi should be _msi_d.pyd. + +- Bug #1530448, ctypes build failure on Solaris 10 was fixed. + + +C API +----- + +- New API for Unicode rich comparisons: PyUnicode_RichCompare() + +- Bug #1069160. Internal correctness changes were made to + ``PyThreadState_SetAsyncExc()``. A test case was added, and + the documentation was changed to state that the return value + is always 1 (normal) or 0 (if the specified thread wasn't found). + + +What's New in Python 2.5 beta 3? +================================ + +*Release date: 03-AUG-2006* + +Core and builtins +----------------- + +- _PyWeakref_GetWeakrefCount() now returns a Py_ssize_t; it previously + returned a long (see PEP 353). + +- Bug #1515471: string.replace() accepts character buffers again. + +- Add PyErr_WarnEx() so C code can pass the stacklevel to warnings.warn(). + This provides the proper warning for struct.pack(). + PyErr_Warn() is now deprecated in favor of PyErr_WarnEx(). + +- Patch #1531113: Fix augmented assignment with yield expressions. + Also fix a SystemError when trying to assign to yield expressions. + +- Bug #1529871: The speed enhancement patch #921466 broke Python's compliance + with PEP 302. This was fixed by adding an ``imp.NullImporter`` type that is + used in ``sys.path_importer_cache`` to cache non-directory paths and avoid + excessive filesystem operations during imports. + +- Bug #1521947: When checking for overflow, ``PyOS_strtol()`` used some + operations on signed longs that are formally undefined by C. + Unfortunately, at least one compiler now cares about that, so complicated + the code to make that compiler happy again. + +- Bug #1524310: Properly report errors from FindNextFile in os.listdir. + +- Patch #1232023: Stop including current directory in search + path on Windows. + +- Fix some potential crashes found with failmalloc. + +- Fix warnings reported by Klocwork's static analysis tool. + +- Bug #1512814, Fix incorrect lineno's when code within a function + had more than 255 blank lines. + +- Patch #1521179: Python now accepts the standard options ``--help`` and + ``--version`` as well as ``/?`` on Windows. + +- Bug #1520864: unpacking singleton tuples in a 'for' loop (for x, in) works + again. Fixing this problem required changing the .pyc magic number. + This means that .pyc files generated before 2.5b3 will be regenerated. + +- Bug #1524317: Compiling Python ``--without-threads`` failed. + The Python core compiles again, and, in a build without threads, the + new ``sys._current_frames()`` returns a dictionary with one entry, + mapping the faux "thread id" 0 to the current frame. + +- Bug #1525447: build on MacOS X on a case-sensitive filesystem. + + +Library +------- + +- Correction of patch #1455898: In the mbcs decoder, set final=False + for stream decoder, but final=True for the decode function. + +- os.urandom no longer masks unrelated exceptions like SystemExit or + KeyboardInterrupt. + +- Bug #1525866: Don't copy directory stat times in + shutil.copytree on Windows + +- Bug #1002398: The documentation for os.path.sameopenfile now correctly + refers to file descriptors, not file objects. + +- The renaming of the xml package to xmlcore, and the import hackery done + to make it appear at both names, has been removed. Bug #1511497, + #1513611, and probably others. + +- Bug #1441397: The compiler module now recognizes module and function + docstrings correctly as it did in Python 2.4. + +- Bug #1529297: The rewrite of doctest for Python 2.4 unintentionally + lost that tests are sorted by name before being run. This rarely + matters for well-written tests, but can create baffling symptoms if + side effects from one test to the next affect outcomes. ``DocTestFinder`` + has been changed to sort the list of tests it returns. + +- The distutils version has been changed to 2.5.0, and is now kept + in sync with sys.version_info[:3]. + +- Bug #978833: Really close underlying socket in _socketobject.close. + +- Bug #1459963: urllib and urllib2 now normalize HTTP header names with + title(). + +- Patch #1525766: In pkgutil.walk_packages, correctly pass the onerror callback + to recursive calls and call it with the failing package name. + +- Bug #1525817: Don't truncate short lines in IDLE's tool tips. + +- Patch #1515343: Fix printing of deprecated string exceptions with a + value in the traceback module. + +- Resync optparse with Optik 1.5.3: minor tweaks for/to tests. + +- Patch #1524429: Use repr() instead of backticks in Tkinter again. + +- Bug #1520914: Change time.strftime() to accept a zero for any position in its + argument tuple. For arguments where zero is illegal, the value is forced to + the minimum value that is correct. This is to support an undocumented but + common way people used to fill in inconsequential information in the time + tuple pre-2.4. + +- Patch #1220874: Update the binhex module for Mach-O. + +- The email package has improved RFC 2231 support, specifically for + recognizing the difference between encoded (name*0*=<blah>) and non-encoded + (name*0=<blah>) parameter continuations. This may change the types of + values returned from email.message.Message.get_param() and friends. + Specifically in some cases where non-encoded continuations were used, + get_param() used to return a 3-tuple of (None, None, string) whereas now it + will just return the string (since non-encoded continuations don't have + charset and language parts). + + Also, whereas % values were decoded in all parameter continuations, they are + now only decoded in encoded parameter parts. + +- Bug #1517990: IDLE keybindings on MacOS X now work correctly + +- Bug #1517996: IDLE now longer shows the default Tk menu when a + path browser, class browser or debugger is the frontmost window on MacOS X + +- Patch #1520294: Support for getset and member descriptors in types.py, + inspect.py, and pydoc.py. Specifically, this allows for querying the type + of an object against these built-in types and more importantly, for getting + their docstrings printed in the interactive interpreter's help() function. + + +Extension Modules +----------------- + +- Patch #1519025 and bug #926423: If a KeyboardInterrupt occurs during + a socket operation on a socket with a timeout, the exception will be + caught correctly. Previously, the exception was not caught. + +- Patch #1529514: The _ctypes extension is now compiled on more + openbsd target platforms. + +- The ``__reduce__()`` method of the new ``collections.defaultdict`` had + a memory leak, affecting pickles and deep copies. + +- Bug #1471938: Fix curses module build problem on Solaris 8; patch by + Paul Eggert. + +- Patch #1448199: Release interpreter lock in _winreg.ConnectRegistry. + +- Patch #1521817: Index range checking on ctypes arrays containing + exactly one element enabled again. This allows iterating over these + arrays, without the need to check the array size before. + +- Bug #1521375: When the code in ctypes.util.find_library was + run with root privileges, it could overwrite or delete + /dev/null in certain cases; this is now fixed. + +- Bug #1467450: On Mac OS X 10.3, RTLD_GLOBAL is now used as the + default mode for loading shared libraries in ctypes. + +- Because of a misspelled preprocessor symbol, ctypes was always + compiled without thread support; this is now fixed. + +- pybsddb Bug #1527939: bsddb module DBEnv dbremove and dbrename + methods now allow their database parameter to be None as the + sleepycat API allows. + +- Bug #1526460: Fix socketmodule compile on NetBSD as it has a different + bluetooth API compared with Linux and FreeBSD. + +Tests +----- + +- Bug #1501330: Change test_ossaudiodev to be much more tolerant in terms of + how long the test file should take to play. Now accepts taking 2.93 secs + (exact time) +/- 10% instead of the hard-coded 3.1 sec. + +- Patch #1529686: The standard tests ``test_defaultdict``, ``test_iterlen``, + ``test_uuid`` and ``test_email_codecs`` didn't actually run any tests when + run via ``regrtest.py``. Now they do. + +Build +----- + +- Bug #1439538: Drop usage of test -e in configure as it is not portable. + +Mac +--- + +- PythonLauncher now works correctly when the path to the script contains + characters that are treated specially by the shell (such as quotes). + +- Bug #1527397: PythonLauncher now launches scripts with the working directory + set to the directory that contains the script instead of the user home + directory. That latter was an implementation accident and not what users + expect. + + +What's New in Python 2.5 beta 2? +================================ + +*Release date: 11-JUL-2006* + +Core and builtins +----------------- + +- Bug #1441486: The literal representation of -(sys.maxint - 1) + again evaluates to a int object, not a long. + +- Bug #1501934: The scope of global variables that are locally assigned + using augmented assignment is now correctly determined. + +- Bug #927248: Recursive method-wrapper objects can now safely + be released. + +- Bug #1417699: Reject locale-specific decimal point in float() + and atof(). + +- Bug #1511381: codec_getstreamcodec() in codec.c is corrected to + omit a default "error" argument for NULL pointer. This allows + the parser to take a codec from cjkcodecs again. + +- Bug #1519018: 'as' is now validated properly in import statements. + +- On 64 bit systems, int literals that use less than 64 bits are + now ints rather than longs. + +- Bug #1512814, Fix incorrect lineno's when code at module scope + started after line 256. + +- New function ``sys._current_frames()`` returns a dict mapping thread + id to topmost thread stack frame. This is for expert use, and is + especially useful for debugging application deadlocks. The functionality + was previously available in Fazal Majid's ``threadframe`` extension + module, but it wasn't possible to do this in a wholly threadsafe way from + an extension. + +Library +------- + +- Bug #1257728: Mention Cygwin in distutils error message about a missing + VS 2003. + +- Patch #1519566: Update turtle demo, make begin_fill idempotent. + +- Bug #1508010: msvccompiler now requires the DISTUTILS_USE_SDK + environment variable to be set in order to the SDK environment + for finding the compiler, include files, etc. + +- Bug #1515998: Properly generate logical ids for files in bdist_msi. + +- warnings.py now ignores ImportWarning by default + +- string.Template() now correctly handles tuple-values. Previously, + multi-value tuples would raise an exception and single-value tuples would + be treated as the value they contain, instead. + +- Bug #822974: Honor timeout in telnetlib.{expect,read_until} + even if some data are received. + +- Bug #1267547: Put proper recursive setup.py call into the + spec file generated by bdist_rpm. + +- Bug #1514693: Update turtle's heading when switching between + degrees and radians. + +- Reimplement turtle.circle using a polyline, to allow correct + filling of arcs. + +- Bug #1514703: Only setup canvas window in turtle when the canvas + is created. + +- Bug #1513223: .close() of a _socketobj now releases the underlying + socket again, which then gets closed as it becomes unreferenced. + +- Bug #1504333: Make sgmllib support angle brackets in quoted + attribute values. + +- Bug #853506: Fix IPv6 address parsing in unquoted attributes in + sgmllib ('[' and ']' were not accepted). + +- Fix a bug in the turtle module's end_fill function. + +- Bug #1510580: The 'warnings' module improperly required that a Warning + category be either a types.ClassType and a subclass of Warning. The proper + check is just that it is a subclass with Warning as the documentation states. + +- The compiler module now correctly compiles the new try-except-finally + statement (bug #1509132). + +- The wsgiref package is now installed properly on Unix. + +- A bug was fixed in logging.config.fileConfig() which caused a crash on + shutdown when fileConfig() was called multiple times. + +- The sqlite3 module did cut off data from the SQLite database at the first + null character before sending it to a custom converter. This has been fixed + now. + +Extension Modules +----------------- + +- #1494314: Fix a regression with high-numbered sockets in 2.4.3. This + means that select() on sockets > FD_SETSIZE (typically 1024) work again. + The patch makes sockets use poll() internally where available. + +- Assigning None to pointer type fields in ctypes structures possible + overwrote the wrong fields, this is fixed now. + +- Fixed a segfault in _ctypes when ctypes.wintypes were imported + on non-Windows platforms. + +- Bug #1518190: The ctypes.c_void_p constructor now accepts any + integer or long, without range checking. + +- Patch #1517790: It is now possible to use custom objects in the ctypes + foreign function argtypes sequence as long as they provide a from_param + method, no longer is it required that the object is a ctypes type. + +- The '_ctypes' extension module now works when Python is configured + with the --without-threads option. + +- Bug #1513646: os.access on Windows now correctly determines write + access, again. + +- Bug #1512695: cPickle.loads could crash if it was interrupted with + a KeyboardInterrupt. + +- Bug #1296433: parsing XML with a non-default encoding and + a CharacterDataHandler could crash the interpreter in pyexpat. + +- Patch #1516912: improve Modules support for OpenVMS. + +Build +----- + +- Automate Windows build process for the Win64 SSL module. + +- 'configure' now detects the zlib library the same way as distutils. + Previously, the slight difference could cause compilation errors of the + 'zlib' module on systems with more than one version of zlib. + +- The MSI compileall step was fixed to also support a TARGETDIR + with spaces in it. + +- Bug #1517388: sqlite3.dll is now installed on Windows independent + of Tcl/Tk. + +- Bug #1513032: 'make install' failed on FreeBSD 5.3 due to lib-old + trying to be installed even though it's empty. + +Tests +----- + +- Call os.waitpid() at the end of tests that spawn child processes in order + to minimize resources (zombies). + +Documentation +------------- + +- Cover ImportWarning, PendingDeprecationWarning and simplefilter() in the + documentation for the warnings module. + +- Patch #1509163: MS Toolkit Compiler no longer available. + +- Patch #1504046: Add documentation for xml.etree. + + +What's New in Python 2.5 beta 1? +================================ + +*Release date: 20-JUN-2006* + +Core and builtins +----------------- + +- Patch #1507676: Error messages returned by invalid abstract object operations + (such as iterating over an integer) have been improved and now include the + type of the offending object to help with debugging. + +- Bug #992017: A classic class that defined a __coerce__() method that returned + its arguments swapped would infinitely recurse and segfault the interpreter. + +- Fix the socket tests so they can be run concurrently. + +- Removed 5 integers from C frame objects (PyFrameObject). + f_nlocals, f_ncells, f_nfreevars, f_stack_size, f_restricted. + +- Bug #532646: object.__call__() will continue looking for the __call__ + attribute on objects until one without one is found. This leads to recursion + when you take a class and set its __call__ attribute to an instance of the + class. Originally fixed for classic classes, but this fix is for new-style. + Removes the infinite_rec_3 crasher. + +- The string and unicode methods startswith() and endswith() now accept + a tuple of prefixes/suffixes to look for. Implements RFE #1491485. + +- Buffer objects, at the C level, never used the char buffer + implementation even when the char buffer for the wrapped object was + explicitly requested (originally returned the read or write buffer). + Now a TypeError is raised if the char buffer is not present but is + requested. + +- Patch #1346214: Statements like "if 0: suite" are now again optimized + away like they were in Python 2.4. + +- Builtin exceptions are now full-blown new-style classes instead of + instances pretending to be classes, which speeds up exception handling + by about 80% in comparison to 2.5a2. + +- Patch #1494554: Update unicodedata.numeric and unicode.isnumeric to + Unicode 4.1. + +- Patch #921466: sys.path_importer_cache is now used to cache valid and + invalid file paths for the built-in import machinery which leads to + fewer open calls on startup. + +- Patch #1442927: ``long(str, base)`` is now up to 6x faster for non-power- + of-2 bases. The largest speedup is for inputs with about 1000 decimal + digits. Conversion from non-power-of-2 bases remains quadratic-time in + the number of input digits (it was and remains linear-time for bases + 2, 4, 8, 16 and 32). + +- Bug #1334662: ``int(string, base)`` could deliver a wrong answer + when ``base`` was not 2, 4, 8, 10, 16 or 32, and ``string`` represented + an integer close to ``sys.maxint``. This was repaired by patch + #1335972, which also gives a nice speedup. + +- Patch #1337051: reduced size of frame objects. + +- PyErr_NewException now accepts a tuple of base classes as its + "base" parameter. + +- Patch #876206: function call speedup by retaining allocated frame + objects. + +- Bug #1462152: file() now checks more thoroughly for invalid mode + strings and removes a possible "U" before passing the mode to the + C library function. + +- Patch #1488312, Fix memory alignment problem on SPARC in unicode + +- Bug #1487966: Fix SystemError with conditional expression in assignment + +- WindowsError now has two error code attributes: errno, which carries + the error values from errno.h, and winerror, which carries the error + values from winerror.h. Previous versions put the winerror.h values + (from GetLastError()) into the errno attribute. + +- Patch #1475845: Raise IndentationError for unexpected indent. + +- Patch #1479181: split open() and file() from being aliases for each other. + +- Patch #1497053 & bug #1275608: Exceptions occurring in ``__eq__()`` + methods were always silently ignored by dictionaries when comparing keys. + They are now passed through (except when using the C API function + ``PyDict_GetItem()``, whose semantics did not change). + +- Bug #1456209: In some obscure cases it was possible for a class with a + custom ``__eq__()`` method to confuse dict internals when class instances + were used as a dict's keys and the ``__eq__()`` method mutated the dict. + No, you don't have any code that did this ;-) + +Extension Modules +----------------- + +- Bug #1295808: expat symbols should be namespaced in pyexpat + +- Patch #1462338: Upgrade pyexpat to expat 2.0.0 + +- Change binascii.hexlify to accept a read-only buffer instead of only a char + buffer and actually follow its documentation. + +- Fixed a potentially invalid memory access of CJKCodecs' shift-jis decoder. + +- Patch #1478788 (modified version): The functional extension module has + been renamed to _functools and a functools Python wrapper module added. + This provides a home for additional function related utilities that are + not specifically about functional programming. See PEP 309. + +- Patch #1493701: performance enhancements for struct module. + +- Patch #1490224: time.altzone is now set correctly on Cygwin. + +- Patch #1435422: zlib's compress and decompress objects now have a + copy() method. + +- Patch #1454481: thread stack size is now tunable at runtime for thread + enabled builds on Windows and systems with Posix threads support. + +- On Win32, os.listdir now supports arbitrarily-long Unicode path names + (up to the system limit of 32K characters). + +- Use Win32 API to implement os.{access,chdir,chmod,mkdir,remove,rename,rmdir,utime}. + As a result, these functions now raise WindowsError instead of OSError. + +- ``time.clock()`` on Win64 should use the high-performance Windows + ``QueryPerformanceCounter()`` now (as was already the case on 32-bit + Windows platforms). + +- Calling Tk_Init twice is refused if the first call failed as that + may deadlock. + +- bsddb: added the DB_ARCH_REMOVE flag and fixed db.DBEnv.log_archive() to + accept it without potentially using an uninitialized pointer. + +- bsddb: added support for the DBEnv.log_stat() and DBEnv.lsn_reset() methods + assuming BerkeleyDB >= 4.0 and 4.4 respectively. [pybsddb project SF + patch numbers 1494885 and 1494902] + +- bsddb: added an interface for the BerkeleyDB >= 4.3 DBSequence class. + [pybsddb project SF patch number 1466734] + +- bsddb: fix DBCursor.pget() bug with keyword argument names when no data + parameter is supplied. [SF pybsddb bug #1477863] + +- bsddb: the __len__ method of a DB object has been fixed to return correct + results. It could previously incorrectly return 0 in some cases. + Fixes SF bug 1493322 (pybsddb bug 1184012). + +- bsddb: the bsddb.dbtables Modify method now raises the proper error and + aborts the db transaction safely when a modifier callback fails. + Fixes SF python patch/bug #1408584. + +- bsddb: multithreaded DB access using the simple bsddb module interface + now works reliably. It has been updated to use automatic BerkeleyDB + deadlock detection and the bsddb.dbutils.DeadlockWrap wrapper to retry + database calls that would previously deadlock. [SF python bug #775414] + +- Patch #1446489: add support for the ZIP64 extensions to zipfile. + +- Patch #1506645: add Python wrappers for the curses functions + is_term_resized, resize_term and resizeterm. + +Library +------- + +- Patch #815924: Restore ability to pass type= and icon= in tkMessageBox + functions. + +- Patch #812986: Update turtle output even if not tracing. + +- Patch #1494750: Destroy master after deleting children in + Tkinter.BaseWidget. + +- Patch #1096231: Add ``default`` argument to Tkinter.Wm.wm_iconbitmap. + +- Patch #763580: Add name and value arguments to Tkinter variable + classes. + +- Bug #1117556: SimpleHTTPServer now tries to find and use the system's + mime.types file for determining MIME types. + +- Bug #1339007: Shelf objects now don't raise an exception in their + __del__ method when initialization failed. + +- Patch #1455898: The MBCS codec now supports the incremental mode for + double-byte encodings. + +- ``difflib``'s ``SequenceMatcher.get_matching_blocks()`` was changed to + guarantee that adjacent triples in the return list always describe + non-adjacent blocks. Previously, a pair of matching blocks could end + up being described by multiple adjacent triples that formed a partition + of the matching pair. + +- Bug #1498146: fix optparse to handle Unicode strings in option help, + description, and epilog. + +- Bug #1366250: minor optparse documentation error. + +- Bug #1361643: fix textwrap.dedent() so it handles tabs appropriately; + clarify docs. + +- The wsgiref package has been added to the standard library. + +- The functions update_wrapper() and wraps() have been added to the functools + module. These make it easier to copy relevant metadata from the original + function when writing wrapper functions. + +- The optional ``isprivate`` argument to ``doctest.testmod()``, and the + ``doctest.is_private()`` function, both deprecated in 2.4, were removed. + +- Patch #1359618: Speed up charmap encoder by using a trie structure + for lookup. + +- The functions in the ``pprint`` module now sort dictionaries by key + before computing the display. Before 2.5, ``pprint`` sorted a dictionary + if and only if its display required more than one line, although that + wasn't documented. The new behavior increases predictability; e.g., + using ``pprint.pprint(a_dict)`` in a doctest is now reliable. + +- Patch #1497027: try HTTP digest auth before basic auth in urllib2 + (thanks for J. J. Lee). + +- Patch #1496206: improve urllib2 handling of passwords with respect to + default HTTP and HTTPS ports. + +- Patch #1080727: add "encoding" parameter to doctest.DocFileSuite. + +- Patch #1281707: speed up gzip.readline. + +- Patch #1180296: Two new functions were added to the locale module: + format_string() to get the effect of "format % items" but locale-aware, + and currency() to format a monetary number with currency sign. + +- Patch #1486962: Several bugs in the turtle Tk demo module were fixed + and several features added, such as speed and geometry control. + +- Patch #1488881: add support for external file objects in bz2 compressed + tarfiles. + +- Patch #721464: pdb.Pdb instances can now be given explicit stdin and + stdout arguments, making it possible to redirect input and output + for remote debugging. + +- Patch #1484695: Update the tarfile module to version 0.8. This fixes + a couple of issues, notably handling of long file names using the + GNU LONGNAME extension. + +- Patch #1478292. ``doctest.register_optionflag(name)`` shouldn't create a + new flag when ``name`` is already the name of an option flag. + +- Bug #1385040: don't allow "def foo(a=1, b): pass" in the compiler + package. + +- Patch #1472854: make the rlcompleter.Completer class usable on non- + UNIX platforms. + +- Patch #1470846: fix urllib2 ProxyBasicAuthHandler. + +- Bug #1472827: correctly escape newlines and tabs in attribute values in + the saxutils.XMLGenerator class. + + +Build +----- + +- Bug #1502728: Correctly link against librt library on HP-UX. + +- OpenBSD 3.9 is supported now. + +- Patch #1492356: Port to Windows CE. + +- Bug/Patch #1481770: Use .so extension for shared libraries on HP-UX for ia64. + +- Patch #1471883: Add --enable-universalsdk. + +C API +----- + +Tests +----- + +Tools +----- + +Documentation +------------- + + + +What's New in Python 2.5 alpha 2? +================================= + +*Release date: 27-APR-2006* + +Core and builtins +----------------- + +- Bug #1465834: 'bdist_wininst preinstall script support' was fixed + by converting these apis from macros into exported functions again: + + PyParser_SimpleParseFile PyParser_SimpleParseString PyRun_AnyFile + PyRun_AnyFileEx PyRun_AnyFileFlags PyRun_File PyRun_FileEx + PyRun_FileFlags PyRun_InteractiveLoop PyRun_InteractiveOne + PyRun_SimpleFile PyRun_SimpleFileEx PyRun_SimpleString + PyRun_String Py_CompileString + +- Under COUNT_ALLOCS, types are not necessarily immortal anymore. + +- All uses of PyStructSequence_InitType have been changed to initialize + the type objects only once, even if the interpreter is initialized + multiple times. + +- Bug #1454485, array.array('u') could crash the interpreter. This was + due to PyArgs_ParseTuple(args, 'u#', ...) trying to convert buffers (strings) + to unicode when it didn't make sense. 'u#' now requires a unicode string. + +- Py_UNICODE is unsigned. It was always documented as unsigned, but + due to a bug had a signed value in previous versions. + +- Patch #837242: ``id()`` of any Python object always gives a positive + number now, which might be a long integer. ``PyLong_FromVoidPtr`` and + ``PyLong_AsVoidPtr`` have been changed accordingly. Note that it has + never been correct to implement a ``__hash()__`` method that returns the + ``id()`` of an object: + + def __hash__(self): + return id(self) # WRONG + + because a hash result must be a (short) Python int but it was always + possible for ``id()`` to return a Python long. However, because ``id()`` + could return negative values before, on a 32-bit box an ``id()`` result + was always usable as a hash value before this patch. That's no longer + necessarily so. + +- Python on OS X 10.3 and above now uses dlopen() (via dynload_shlib.c) + to load extension modules and now provides the dl module. As a result, + sys.setdlopenflags() now works correctly on these systems. (SF patch + #1454844) + +- Patch #1463867: enhanced garbage collection to allow cleanup of cycles + involving generators that have paused outside of any ``try`` or ``with`` + blocks. (In 2.5a1, a paused generator that was part of a reference + cycle could not be garbage collected, regardless of whether it was + paused in a ``try`` or ``with`` block.) + +Extension Modules +----------------- + +- Patch #1191065: Fix preprocessor problems on systems where recvfrom + is a macro. + +- Bug #1467952: os.listdir() now correctly raises an error if readdir() + fails with an error condition. + +- Fixed bsddb.db.DBError derived exceptions so they can be unpickled. + +- Bug #1117761: bsddb.*open() no longer raises an exception when using + the cachesize parameter. + +- Bug #1149413: bsddb.*open() no longer raises an exception when using + a temporary db (file=None) with the 'n' flag to truncate on open. + +- Bug #1332852: bsddb module minimum BerkeleyDB version raised to 3.3 + as older versions cause excessive test failures. + +- Patch #1062014: AF_UNIX sockets under Linux have a special + abstract namespace that is now fully supported. + +Library +------- + +- Bug #1223937: subprocess.CalledProcessError reports the exit status + of the process using the returncode attribute, instead of + abusing errno. + +- Patch #1475231: ``doctest`` has a new ``SKIP`` option, which causes + a doctest to be skipped (the code is not run, and the expected output + or exception is ignored). + +- Fixed contextlib.nested to cope with exceptions being raised and + caught inside exit handlers. + +- Updated optparse module to Optik 1.5.1 (allow numeric constants in + hex, octal, or binary; add ``append_const`` action; keep going if + gettext cannot be imported; added ``OptionParser.destroy()`` method; + added ``epilog`` for better help generation). + +- Bug #1473760: ``tempfile.TemporaryFile()`` could hang on Windows, when + called from a thread spawned as a side effect of importing a module. + +- The pydoc module now supports documenting packages contained in + .zip or .egg files. + +- The pkgutil module now has several new utility functions, such + as ``walk_packages()`` to support working with packages that are either + in the filesystem or zip files. + +- The mailbox module can now modify and delete messages from + mailboxes, in addition to simply reading them. Thanks to Gregory + K. Johnson for writing the code, and to the 2005 Google Summer of + Code for funding his work. + +- The ``__del__`` method of class ``local`` in module ``_threading_local`` + returned before accomplishing any of its intended cleanup. + +- Patch #790710: Add breakpoint command lists in pdb. + +- Patch #1063914: Add Tkinter.Misc.clipboard_get(). + +- Patch #1191700: Adjust column alignment in bdb breakpoint lists. + +- SimpleXMLRPCServer relied on the fcntl module, which is unavailable on + Windows. Bug #1469163. + +- The warnings, linecache, inspect, traceback, site, and doctest modules + were updated to work correctly with modules imported from zipfiles or + via other PEP 302 __loader__ objects. + +- Patch #1467770: Reduce usage of subprocess._active to processes which + the application hasn't waited on. + +- Patch #1462222: Fix Tix.Grid. + +- Fix exception when doing glob.glob('anything*/') + +- The pstats.Stats class accepts an optional stream keyword argument to + direct output to an alternate file-like object. + +Build +----- + +- The Makefile now has a reindent target, which runs reindent.py on + the library. + +- Patch #1470875: Building Python with MS Free Compiler + +- Patch #1161914: Add a python-config script. + +- Patch #1324762:Remove ccpython.cc; replace --with-cxx with + --with-cxx-main. Link with C++ compiler only if --with-cxx-main was + specified. (Can be overridden by explicitly setting LINKCC.) Decouple + CXX from --with-cxx-main, see description in README. + +- Patch #1429775: Link extension modules with the shared libpython. + +- Fixed a libffi build problem on MIPS systems. + +- ``PyString_FromFormat``, ``PyErr_Format``, and ``PyString_FromFormatV`` + now accept formats "%u" for unsigned ints, "%lu" for unsigned longs, + and "%zu" for unsigned integers of type ``size_t``. + +Tests +----- + +- test_contextlib now checks contextlib.nested can cope with exceptions + being raised and caught inside exit handlers. + +- test_cmd_line now checks operation of the -m and -c command switches + +- The test_contextlib test in 2.5a1 wasn't actually run unless you ran + it separately and by hand. It also wasn't cleaning up its changes to + the current Decimal context. + +- regrtest.py now has a -M option to run tests that test the new limits of + containers, on 64-bit architectures. Running these tests is only sensible + on 64-bit machines with more than two gigabytes of memory. The argument + passed is the maximum amount of memory for the tests to use. + +Tools +----- + +- Added the Python benchmark suite pybench to the Tools/ directory; + contributed by Marc-Andre Lemburg. + +Documentation +------------- + +- Patch #1473132: Improve docs for ``tp_clear`` and ``tp_traverse``. + +- PEP 343: Added Context Types section to the library reference + and attempted to bring other PEP 343 related documentation into + line with the implementation and/or python-dev discussions. + +- Bug #1337990: clarified that ``doctest`` does not support examples + requiring both expected output and an exception. + + +What's New in Python 2.5 alpha 1? +================================= + +*Release date: 05-APR-2006* + +Core and builtins +----------------- + +- PEP 338: -m command line switch now delegates to runpy.run_module + allowing it to support modules in packages and zipfiles + +- On Windows, .DLL is not an accepted file name extension for + extension modules anymore; extensions are only found if they + end in .PYD. + +- Bug #1421664: sys.stderr.encoding is now set to the same value as + sys.stdout.encoding. + +- __import__ accepts keyword arguments. + +- Patch #1460496: round() now accepts keyword arguments. + +- Fixed bug #1459029 - unicode reprs were double-escaped. + +- Patch #1396919: The system scope threads are reenabled on FreeBSD + 5.4 and later versions. + +- Bug #1115379: Compiling a Unicode string with an encoding declaration + now gives a SyntaxError. + +- Previously, Python code had no easy way to access the contents of a + cell object. Now, a ``cell_contents`` attribute has been added + (closes patch #1170323). + +- Patch #1123430: Python's small-object allocator now returns an arena to + the system ``free()`` when all memory within an arena becomes unused + again. Prior to Python 2.5, arenas (256KB chunks of memory) were never + freed. Some applications will see a drop in virtual memory size now, + especially long-running applications that, from time to time, temporarily + use a large number of small objects. Note that when Python returns an + arena to the platform C's ``free()``, there's no guarantee that the + platform C library will in turn return that memory to the operating system. + The effect of the patch is to stop making that impossible, and in tests it + appears to be effective at least on Microsoft C and gcc-based systems. + Thanks to Evan Jones for hard work and patience. + +- Patch #1434038: property() now uses the getter's docstring if there is + no "doc" argument given. This makes it possible to legitimately use + property() as a decorator to produce a read-only property. + +- PEP 357, patch 1436368: add an __index__ method to int/long and a matching + nb_index slot to the PyNumberMethods struct. The slot is consulted instead + of requiring an int or long in slicing and a few other contexts, enabling + other objects (e.g. Numeric Python's integers) to be used as slice indices. + +- Fixed various bugs reported by Coverity's Prevent tool. + +- PEP 352, patch #1104669: Make exceptions new-style objects. Introduced the + new exception base class, BaseException, which has a new message attribute. + KeyboardInterrupt and SystemExit to directly inherit from BaseException now. + Raising a string exception now raises a DeprecationWarning. + +- Patch #1438387, PEP 328: relative and absolute imports. Imports can now be + explicitly relative, using 'from .module import name' to mean 'from the same + package as this module is in. Imports without dots still default to the + old relative-then-absolute, unless 'from __future__ import + absolute_import' is used. + +- Properly check if 'warnings' raises an exception (usually when a filter set + to "error" is triggered) when raising a warning for raising string + exceptions. + +- CO_GENERATOR_ALLOWED is no longer defined. This behavior is the default. + The name was removed from Include/code.h. + +- PEP 308: conditional expressions were added: (x if cond else y). + +- Patch 1433928: + - The copy module now "copies" function objects (as atomic objects). + - dict.__getitem__ now looks for a __missing__ hook before raising + KeyError. + +- PEP 343: with statement implemented. Needs ``from __future__ import + with_statement``. Use of 'with' as a variable will generate a warning. + Use of 'as' as a variable will also generate a warning (unless it's + part of an import statement). + The following objects have __context__ methods: + - The built-in file type. + - The thread.LockType type. + - The following types defined by the threading module: + Lock, RLock, Condition, Semaphore, BoundedSemaphore. + - The decimal.Context class. + +- Fix the encodings package codec search function to only search + inside its own package. Fixes problem reported in patch #1433198. + + Note: Codec packages should implement and register their own + codec search function. PEP 100 has the details. + +- PEP 353: Using ``Py_ssize_t`` as the index type. + +- ``PYMALLOC_DEBUG`` builds now add ``4*sizeof(size_t)`` bytes of debugging + info to each allocated block, since the ``Py_ssize_t`` changes (PEP 353) + now allow Python to make use of memory blocks exceeding 2**32 bytes for + some purposes on 64-bit boxes. A ``PYMALLOC_DEBUG`` build was limited + to 4-byte allocations before. + +- Patch #1400181, fix unicode string formatting to not use the locale. + This is how string objects work. u'%f' could use , instead of . + for the decimal point. Now both strings and unicode always use periods. + +- Bug #1244610, #1392915, fix build problem on OpenBSD 3.7 and 3.8. + configure would break checking curses.h. + +- Bug #959576: The pwd module is now builtin. This allows Python to be + built on UNIX platforms without $HOME set. + +- Bug #1072182, fix some potential problems if characters are signed. + +- Bug #889500, fix line number on SyntaxWarning for global declarations. + +- Bug #1378022, UTF-8 files with a leading BOM crashed the interpreter. + +- Support for converting hex strings to floats no longer works. + This was not portable. float('0x3') now raises a ValueError. + +- Patch #1382163: Expose Subversion revision number to Python. New C API + function Py_GetBuildNumber(). New attribute sys.subversion. Build number + is now displayed in interactive prompt banner. + +- Implementation of PEP 341 - Unification of try/except and try/finally. + "except" clauses can now be written together with a "finally" clause in + one try statement instead of two nested ones. Patch #1355913. + +- Bug #1379994: Builtin unicode_escape and raw_unicode_escape codec + now encodes backslash correctly. + +- Patch #1350409: Work around signal handling bug in Visual Studio 2005. + +- Bug #1281408: Py_BuildValue now works correctly even with unsigned longs + and long longs. + +- SF Bug #1350188, "setdlopenflags" leads to crash upon "import" + It was possible for dlerror() to return a NULL pointer, so + it will now use a default error message in this case. + +- Replaced most Unicode charmap codecs with new ones using the + new Unicode translate string feature in the builtin charmap + codec; the codecs were created from the mapping tables available + at ftp.unicode.org and contain a few updates (e.g. the Mac OS + encodings now include a mapping for the Apple logo) + +- Added a few more codecs for Mac OS encodings + +- Sped up some Unicode operations. + +- A new AST parser implementation was completed. The abstract + syntax tree is available for read-only (non-compile) access + to Python code; an _ast module was added. + +- SF bug #1167751: fix incorrect code being produced for generator expressions. + The following code now raises a SyntaxError: foo(a = i for i in range(10)) + +- SF Bug #976608: fix SystemError when mtime of an imported file is -1. + +- SF Bug #887946: fix segfault when redirecting stdin from a directory. + Provide a warning when a directory is passed on the command line. + +- Fix segfault with invalid coding. + +- SF bug #772896: unknown encoding results in MemoryError. + +- All iterators now have a Boolean value of True. Formerly, some iterators + supported a __len__() method which evaluated to False when the iterator + was empty. + +- On 64-bit platforms, when __len__() returns a value that cannot be + represented as a C int, raise OverflowError. + +- test__locale is skipped on OS X < 10.4 (only partial locale support is + present). + +- SF bug #893549: parsing keyword arguments was broken with a few format + codes. + +- Changes donated by Elemental Security to make it work on AIX 5.3 + with IBM's 64-bit compiler (SF patch #1284289). This also closes SF + bug #105470: test_pwd fails on 64bit system (Opteron). + +- Changes donated by Elemental Security to make it work on HP-UX 11 on + Itanium2 with HP's 64-bit compiler (SF patch #1225212). + +- Disallow keyword arguments for type constructors that don't use them + (fixes bug #1119418). + +- Forward UnicodeDecodeError into SyntaxError for source encoding errors. + +- SF bug #900092: When tracing (e.g. for hotshot), restore 'return' events for + exceptions that cause a function to exit. + +- The implementation of set() and frozenset() was revised to use its + own internal data structure. Memory consumption is reduced by 1/3 + and there are modest speed-ups as well. The API is unchanged. + +- SF bug #1238681: freed pointer is used in longobject.c:long_pow(). + +- SF bug #1229429: PyObject_CallMethod failed to decrement some + reference counts in some error exit cases. + +- SF bug #1185883: Python's small-object memory allocator took over + a block managed by the platform C library whenever a realloc specified + a small new size. However, there's no portable way to know then how + much of the address space following the pointer is valid, so there's no + portable way to copy data from the C-managed block into Python's + small-object space without risking a memory fault. Python's small-object + realloc now leaves such blocks under the control of the platform C + realloc. + +- SF bug #1232517: An overflow error was not detected properly when + attempting to convert a large float to an int in os.utime(). + +- SF bug #1224347: hex longs now print with lowercase letters just + like their int counterparts. + +- SF bug #1163563: the original fix for bug #1010677 ("thread Module + Breaks PyGILState_Ensure()") broke badly in the case of multiple + interpreter states; back out that fix and do a better job (see + http://mail.python.org/pipermail/python-dev/2005-June/054258.html + for a longer write-up of the problem). + +- SF patch #1180995: marshal now uses a binary format by default when + serializing floats. + +- SF patch #1181301: on platforms that appear to use IEEE 754 floats, + the routines that promise to produce IEEE 754 binary representations + of floats now simply copy bytes around. + +- bug #967182: disallow opening files with 'wU' or 'aU' as specified by PEP + 278. + +- patch #1109424: int, long, float, complex, and unicode now check for the + proper magic slot for type conversions when subclassed. Previously the + magic slot was ignored during conversion. Semantics now match the way + subclasses of str always behaved. int/long/float, conversion of an instance + to the base class has been moved to the proper nb_* magic slot and out of + PyNumber_*(). + Thanks Walter D�rwald. + +- Descriptors defined in C with a PyGetSetDef structure, where the setter is + NULL, now raise an AttributeError when attempting to set or delete the + attribute. Previously a TypeError was raised, but this was inconsistent + with the equivalent pure-Python implementation. + +- It is now safe to call PyGILState_Release() before + PyEval_InitThreads() (note that if there is reason to believe there + are multiple threads around you still must call PyEval_InitThreads() + before using the Python API; this fix is for extension modules that + have no way of knowing if Python is multi-threaded yet). + +- Typing Ctrl-C whilst raw_input() was waiting in a build with threads + disabled caused a crash. + +- Bug #1165306: instancemethod_new allowed the creation of a method + with im_class == im_self == NULL, which caused a crash when called. + +- Move exception finalisation later in the shutdown process - this + fixes the crash seen in bug #1165761 + +- Added two new builtins, any() and all(). + +- Defining a class with empty parentheses is now allowed + (e.g., ``class C(): pass`` is no longer a syntax error). + Patch #1176012 added support to the 'parser' module and 'compiler' package + (thanks to logistix for that added support). + +- Patch #1115086: Support PY_LONGLONG in structmember. + +- Bug #1155938: new style classes did not check that __init__() was + returning None. + +- Patch #802188: Report characters after line continuation character + ('\') with a specific error message. + +- Bug #723201: Raise a TypeError for passing bad objects to 'L' format. + +- Bug #1124295: the __name__ attribute of file objects was + inadvertently made inaccessible in restricted mode. + +- Bug #1074011: closing sys.std{out,err} now causes a flush() and + an ferror() call. + +- min() and max() now support key= arguments with the same meaning as in + list.sort(). + +- The peephole optimizer now performs simple constant folding in expressions: + (2+3) --> (5). + +- set and frozenset objects can now be marshalled. SF #1098985. + +- Bug #1077106: Poor argument checking could cause memory corruption + in calls to os.read(). + +- The parser did not complain about future statements in illegal + positions. It once again reports a syntax error if a future + statement occurs after anything other than a doc string. + +- Change the %s format specifier for str objects so that it returns a + unicode instance if the argument is not an instance of basestring and + calling __str__ on the argument returns a unicode instance. + +- Patch #1413181: changed ``PyThreadState_Delete()`` to forget about the + current thread state when the auto-GIL-state machinery knows about + it (since the thread state is being deleted, continuing to remember it + can't help, but can hurt if another thread happens to get created with + the same thread id). + +Extension Modules +----------------- + +- Patch #1380952: fix SSL objects timing out on consecutive read()s + +- Patch #1309579: wait3 and wait4 were added to the posix module. + +- Patch #1231053: The audioop module now supports encoding/decoding of alaw. + In addition, the existing ulaw code was updated. + +- RFE #567972: Socket objects' family, type and proto properties are + now exposed via new attributes. + +- Everything under lib-old was removed. This includes the following modules: + Para, addpack, cmp, cmpcache, codehack, dircmp, dump, find, fmt, grep, + lockfile, newdir, ni, packmail, poly, rand, statcache, tb, tzparse, + util, whatsound, whrandom, zmod + +- The following modules were removed: regsub, reconvert, regex, regex_syntax. + +- re and sre were swapped, so help(re) provides full help. importing sre + is deprecated. The undocumented re.engine variable no longer exists. + +- Bug #1448490: Fixed a bug that ISO-2022 codecs could not handle + SS2 (single-shift 2) escape sequences correctly. + +- The unicodedata module was updated to the 4.1 version of the Unicode + database. The 3.2 version is still available as unicodedata.db_3_2_0 + for applications that require this specific version (such as IDNA). + +- The timing module is no longer built by default. It was deprecated + in PEP 4 in Python 2.0 or earlier. + +- Patch 1433928: Added a new type, defaultdict, to the collections module. + This uses the new __missing__ hook behavior added to dict (see above). + +- Bug #854823: socketmodule now builds on Sun platforms even when + INET_ADDRSTRLEN is not defined. + +- Patch #1393157: os.startfile() now has an optional argument to specify + a "command verb" to invoke on the file. + +- Bug #876637, prevent stack corruption when socket descriptor + is larger than FD_SETSIZE. + +- Patch #1407135, bug #1424041: harmonize mmap behavior of anonymous memory. + mmap.mmap(-1, size) now returns anonymous memory in both Unix and Windows. + mmap.mmap(0, size) should not be used on Windows for anonymous memory. + +- Patch #1422385: The nis module now supports access to domains other + than the system default domain. + +- Use Win32 API to implement os.stat/fstat. As a result, subsecond timestamps + are reported, the limit on path name lengths is removed, and stat reports + WindowsError now (instead of OSError). + +- Add bsddb.db.DBEnv.set_tx_timestamp allowing time based database recovery. + +- Bug #1413192, fix seg fault in bsddb if a transaction was deleted + before the env. + +- Patch #1103116: Basic AF_NETLINK support. + +- Bug #1402308, (possible) segfault when using mmap.mmap(-1, ...) + +- Bug #1400822, _curses over{lay,write} doesn't work when passing 6 ints. + Also fix ungetmouse() which did not accept arguments properly. + The code now conforms to the documented signature. + +- Bug #1400115, Fix segfault when calling curses.panel.userptr() + without prior setting of the userptr. + +- Fix 64-bit problems in bsddb. + +- Patch #1365916: fix some unsafe 64-bit mmap methods. + +- Bug #1290333: Added a workaround for cjkcodecs' _codecs_cn build + problem on AIX. + +- Bug #869197: os.setgroups rejects long integer arguments + +- Bug #1346533, select.poll() doesn't raise an error if timeout > sys.maxint + +- Bug #1344508, Fix UNIX mmap leaking file descriptors + +- Patch #1338314, Bug #1336623: fix tarfile so it can extract + REGTYPE directories from tarfiles written by old programs. + +- Patch #1407992, fixes broken bsddb module db associate when using + BerkeleyDB 3.3, 4.0 or 4.1. + +- Get bsddb module to build with BerkeleyDB version 4.4 + +- Get bsddb module to build with BerkeleyDB version 3.2 + +- Patch #1309009, Fix segfault in pyexpat when the XML document is in latin_1, + but Python incorrectly assumes it is in UTF-8 format + +- Fix parse errors in the readline module when compiling without threads. + +- Patch #1288833: Removed thread lock from socket.getaddrinfo on + FreeBSD 5.3 and later versions which got thread-safe getaddrinfo(3). + +- Patches #1298449 and #1298499: Add some missing checks for error + returns in cStringIO.c. + +- Patch #1297028: fix segfault if call type on MultibyteCodec, + MultibyteStreamReader, or MultibyteStreamWriter + +- Fix memory leak in posix.access(). + +- Patch #1213831: Fix typo in unicodedata._getcode. + +- Bug #1007046: os.startfile() did not accept unicode strings encoded in + the file system encoding. + +- Patch #756021: Special-case socket.inet_aton('255.255.255.255') for + platforms that don't have inet_aton(). + +- Bug #1215928: Fix bz2.BZ2File.seek() for 64-bit file offsets. + +- Bug #1191043: Fix bz2.BZ2File.(x)readlines for files containing one + line without newlines. + +- Bug #728515: mmap.resize() now resizes the file on Unix as it did + on Windows. + +- Patch #1180695: Add nanosecond stat resolution, and st_gen, + st_birthtime for FreeBSD. + +- Patch #1231069: The fcntl.ioctl function now uses the 'I' code for + the request code argument, which results in more C-like behaviour + for large or negative values. + +- Bug #1234979: For the argument of thread.Lock.acquire, the Windows + implementation treated all integer values except 1 as false. + +- Bug #1194181: bz2.BZ2File didn't handle mode 'U' correctly. + +- Patch #1212117: os.stat().st_flags is now accessible as a attribute + if available on the platform. + +- Patch #1103951: Expose O_SHLOCK and O_EXLOCK in the posix module if + available on the platform. + +- Bug #1166660: The readline module could segfault if hook functions + were set in a different thread than that which called readline. + +- collections.deque objects now support a remove() method. + +- operator.itemgetter() and operator.attrgetter() now support retrieving + multiple fields. This provides direct support for sorting on multiple + keys (primary, secondary, etc). + +- os.access now supports Unicode path names on non-Win32 systems. + +- Patches #925152, #1118602: Avoid reading after the end of the buffer + in pyexpat.GetInputContext. + +- Patches #749830, #1144555: allow UNIX mmap size to default to current + file size. + +- Added functional.partial(). See PEP309. + +- Patch #1093585: raise a ValueError for negative history items in readline. + {remove_history,replace_history} + +- The spwd module has been added, allowing access to the shadow password + database. + +- stat_float_times is now True. + +- array.array objects are now picklable. + +- the cPickle module no longer accepts the deprecated None option in the + args tuple returned by __reduce__(). + +- itertools.islice() now accepts None for the start and step arguments. + This allows islice() to work more readily with slices: + islice(s.start, s.stop, s.step) + +- datetime.datetime() now has a strptime class method which can be used to + create datetime object using a string and format. + +- Patch #1117961: Replace the MD5 implementation from RSA Data Security Inc + with the implementation from http://sourceforge.net/projects/libmd5-rfc/. + +Library +------- + +- Patch #1388073: Numerous __-prefixed attributes of unittest.TestCase have + been renamed to have only a single underscore prefix. This was done to + make subclassing easier. + +- PEP 338: new module runpy defines a run_module function to support + executing modules which provide access to source code or a code object + via the PEP 302 import mechanisms. + +- The email module's parsedate_tz function now sets the daylight savings + flag to -1 (unknown) since it can't tell from the date whether it should + be set. + +- Patch #624325: urlparse.urlparse() and urlparse.urlsplit() results + now sport attributes that provide access to the parts of the result. + +- Patch #1462498: sgmllib now handles entity and character references + in attribute values. + +- Added the sqlite3 package. This is based on pysqlite2.1.3, and provides + a DB-API interface in the standard library. You'll need sqlite 3.0.8 or + later to build this - if you have an earlier version, the C extension + module will not be built. + +- Bug #1460340: ``random.sample(dict)`` failed in various ways. Dicts + aren't officially supported here, and trying to use them will probably + raise an exception some day. But dicts have been allowed, and "mostly + worked", so support for them won't go away without warning. + +- Bug #1445068: getpass.getpass() can now be given an explicit stream + argument to specify where to write the prompt. + +- Patch #1462313, bug #1443328: the pickle modules now can handle classes + that have __private names in their __slots__. + +- Bug #1250170: mimetools now handles socket.gethostname() failures gracefully. + +- patch #1457316: "setup.py upload" now supports --identity to select the + key to be used for signing the uploaded code. + +- Queue.Queue objects now support .task_done() and .join() methods + to make it easier to monitor when daemon threads have completed + processing all enqueued tasks. Patch #1455676. + +- popen2.Popen objects now preserve the command in a .cmd attribute. + +- Added the ctypes ffi package. + +- email 4.0 package now integrated. This is largely the same as the email 3.0 + package that was included in Python 2.3, except that PEP 8 module names are + now used (e.g. mail.message instead of email.Message). The MIME classes + have been moved to a subpackage (e.g. email.mime.text instead of + email.MIMEText). The old names are still supported for now. Several + deprecated Message methods have been removed and lots of bugs have been + fixed. More details can be found in the email package documentation. + +- Patches #1436130/#1443155: codecs.lookup() now returns a CodecInfo object + (a subclass of tuple) that provides incremental decoders and encoders + (a way to use stateful codecs without the stream API). Python functions + codecs.getincrementaldecoder() and codecs.getincrementalencoder() as well + as C functions PyCodec_IncrementalEncoder() and PyCodec_IncrementalDecoder() + have been added. + +- Patch #1359365: Calling next() on a closed StringIO.String object raises + a ValueError instead of a StopIteration now (like file and cString.String do). + cStringIO.StringIO.isatty() will raise a ValueError now if close() has been + called before (like file and StringIO.StringIO do). + +- A regrtest option -w was added to re-run failed tests in verbose mode. + +- Patch #1446372: quit and exit can now be called from the interactive + interpreter to exit. + +- The function get_count() has been added to the gc module, and gc.collect() + grew an optional 'generation' argument. + +- A library msilib to generate Windows Installer files, and a distutils + command bdist_msi have been added. + +- PEP 343: new module contextlib.py defines decorator @contextmanager + and helpful context managers nested() and closing(). + +- The compiler package now supports future imports after the module docstring. + +- Bug #1413790: zipfile now sanitizes absolute archive names that are + not allowed by the specs. + +- Patch #1215184: FileInput now can be given an opening hook which can + be used to control how files are opened. + +- Patch #1212287: fileinput.input() now has a mode parameter for + specifying the file mode input files should be opened with. + +- Patch #1215184: fileinput now has a fileno() function for getting the + current file number. + +- Patch #1349274: gettext.install() now optionally installs additional + translation functions other than _() in the builtin namespace. + +- Patch #1337756: fileinput now accepts Unicode filenames. + +- Patch #1373643: The chunk module can now read chunks larger than + two gigabytes. + +- Patch #1417555: SimpleHTTPServer now returns Last-Modified headers. + +- Bug #1430298: It is now possible to send a mail with an empty + return address using smtplib. + +- Bug #1432260: The names of lambda functions are now properly displayed + in pydoc. + +- Patch #1412872: zipfile now sets the creator system to 3 (Unix) + unless the system is Win32. + +- Patch #1349118: urllib now supports user:pass@ style proxy + specifications, raises IOErrors when proxies for unsupported protocols + are defined, and uses the https proxy on https redirections. + +- Bug #902075: urllib2 now supports 'host:port' style proxy specifications. + +- Bug #1407902: Add support for sftp:// URIs to urlparse. + +- Bug #1371247: Update Windows locale identifiers in locale.py. + +- Bug #1394565: SimpleHTTPServer now doesn't choke on query parameters + any more. + +- Bug #1403410: The warnings module now doesn't get confused + when it can't find out the module name it generates a warning for. + +- Patch #1177307: Added a new codec utf_8_sig for UTF-8 with a BOM signature. + +- Patch #1157027: cookielib mishandles RFC 2109 cookies in Netscape mode + +- Patch #1117398: cookielib.LWPCookieJar and .MozillaCookieJar now raise + LoadError as documented, instead of IOError. For compatibility, + LoadError subclasses IOError. + +- Added the hashlib module. It provides secure hash functions for MD5 and + SHA1, 224, 256, 384, and 512. Note that recent developments make the + historic MD5 and SHA1 unsuitable for cryptographic-strength applications. + In <http://mail.python.org/pipermail/python-dev/2005-December/058850.html> + Ronald L. Rivest offered this advice for Python: + + "The consensus of researchers in this area (at least as + expressed at the NIST Hash Function Workshop 10/31/05), + is that SHA-256 is a good choice for the time being, but + that research should continue, and other alternatives may + arise from this research. The larger SHA's also seem OK." + +- Added a subset of Fredrik Lundh's ElementTree package. Available + modules are xml.etree.ElementTree, xml.etree.ElementPath, and + xml.etree.ElementInclude, from ElementTree 1.2.6. + +- Patch #1162825: Support non-ASCII characters in IDLE window titles. + +- Bug #1365984: urllib now opens "data:" URLs again. + +- Patch #1314396: prevent deadlock for threading.Thread.join() when an exception + is raised within the method itself on a previous call (e.g., passing in an + illegal argument) + +- Bug #1340337: change time.strptime() to always return ValueError when there + is an error in the format string. + +- Patch #754022: Greatly enhanced webbrowser.py (by Oleg Broytmann). + +- Bug #729103: pydoc.py: Fix docother() method to accept additional + "parent" argument. + +- Patch #1300515: xdrlib.py: Fix pack_fstring() to really use null bytes + for padding. + +- Bug #1296004: httplib.py: Limit maximal amount of data read from the + socket to avoid a MemoryError on Windows. + +- Patch #1166948: locale.py: Prefer LC_ALL, LC_CTYPE and LANG over LANGUAGE + to get the correct encoding. + +- Patch #1166938: locale.py: Parse LANGUAGE as a colon separated list of + languages. + +- Patch #1268314: Cache lines in StreamReader.readlines for performance. + +- Bug #1290505: Fix clearing the regex cache for time.strptime(). + +- Bug #1167128: Fix size of a symlink in a tarfile to be 0. + +- Patch #810023: Fix off-by-one bug in urllib.urlretrieve reporthook + functionality. + +- Bug #1163178: Make IDNA return an empty string when the input is empty. + +- Patch #848017: Make Cookie more RFC-compliant. Use CRLF as default output + separator and do not output trailing semicolon. + +- Patch #1062060: urllib.urlretrieve() now raises a new exception, named + ContentTooShortException, when the actually downloaded size does not + match the Content-Length header. + +- Bug #1121494: distutils.dir_utils.mkpath now accepts Unicode strings. + +- Bug #1178484: Return complete lines from codec stream readers + even if there is an exception in later lines, resulting in + correct line numbers for decoding errors in source code. + +- Bug #1192315: Disallow negative arguments to clear() in pdb. + +- Patch #827386: Support absolute source paths in msvccompiler.py. + +- Patch #1105730: Apply the new implementation of commonprefix in posixpath + to ntpath, macpath, os2emxpath and riscospath. + +- Fix a problem in Tkinter introduced by SF patch #869468: delete bogus + __hasattr__ and __delattr__ methods on class Tk that were breaking + Tkdnd. + +- Bug #1015140: disambiguated the term "article id" in nntplib docs and + docstrings to either "article number" or "message id". + +- Bug #1238170: threading.Thread.__init__ no longer has "kwargs={}" as a + parameter, but uses the usual "kwargs=None". + +- textwrap now processes text chunks at O(n) speed instead of O(n**2). + Patch #1209527 (Contributed by Connelly). + +- urllib2 has now an attribute 'httpresponses' mapping from HTTP status code + to W3C name (404 -> 'Not Found'). RFE #1216944. + +- Bug #1177468: Don't cache the /dev/urandom file descriptor for os.urandom, + as this can cause problems with apps closing all file descriptors. + +- Bug #839151: Fix an attempt to access sys.argv in the warnings module; + it can be missing in embedded interpreters + +- Bug #1155638: Fix a bug which affected HTTP 0.9 responses in httplib. + +- Bug #1100201: Cross-site scripting was possible on BaseHTTPServer via + error messages. + +- Bug #1108948: Cookie.py produced invalid JavaScript code. + +- The tokenize module now detects and reports indentation errors. + Bug #1224621. + +- The tokenize module has a new untokenize() function to support a full + roundtrip from lexed tokens back to Python source code. In addition, + the generate_tokens() function now accepts a callable argument that + terminates by raising StopIteration. + +- Bug #1196315: fix weakref.WeakValueDictionary constructor. + +- Bug #1213894: os.path.realpath didn't resolve symlinks that were the first + component of the path. + +- Patch #1120353: The xmlrpclib module provides better, more transparent, + support for datetime.{datetime,date,time} objects. With use_datetime set + to True, applications shouldn't have to fiddle with the DateTime wrapper + class at all. + +- distutils.commands.upload was added to support uploading distribution + files to PyPI. + +- distutils.commands.register now encodes the data as UTF-8 before posting + them to PyPI. + +- decimal operator and comparison methods now return NotImplemented + instead of raising a TypeError when interacting with other types. This + allows other classes to implement __radd__ style methods and have them + work as expected. + +- Bug #1163325: Decimal infinities failed to hash. Attempting to + hash a NaN raised an InvalidOperation instead of a TypeError. + +- Patch #918101: Add tarfile open mode r|* for auto-detection of the + stream compression; add, for symmetry reasons, r:* as a synonym of r. + +- Patch #1043890: Add extractall method to tarfile. + +- Patch #1075887: Don't require MSVC in distutils if there is nothing + to build. + +- Patch #1103407: Properly deal with tarfile iterators when untarring + symbolic links on Windows. + +- Patch #645894: Use getrusage for computing the time consumption in + profile.py if available. + +- Patch #1046831: Use get_python_version where appropriate in sysconfig.py. + +- Patch #1117454: Remove code to special-case cookies without values + in LWPCookieJar. + +- Patch #1117339: Add cookielib special name tests. + +- Patch #1112812: Make bsddb/__init__.py more friendly for modulefinder. + +- Patch #1110248: SYNC_FLUSH the zlib buffer for GZipFile.flush. + +- Patch #1107973: Allow to iterate over the lines of a tarfile.ExFileObject. + +- Patch #1104111: Alter setup.py --help and --help-commands. + +- Patch #1121234: Properly cleanup _exit and tkerror commands. + +- Patch #1049151: xdrlib now unpacks booleans as True or False. + +- Fixed bug in a NameError bug in cookielib. Patch #1116583. + +- Applied a security fix to SimpleXMLRPCserver (PSF-2005-001). This + disables recursive traversal through instance attributes, which can + be exploited in various ways. + +- Bug #1222790: in SimpleXMLRPCServer, set the reuse-address and close-on-exec + flags on the HTTP listening socket. + +- Bug #792570: SimpleXMLRPCServer had problems if the request grew too large. + Fixed by reading the HTTP body in chunks instead of one big socket.read(). + +- Patches #893642, #1039083: add allow_none, encoding arguments to + constructors of SimpleXMLRPCServer and CGIXMLRPCRequestHandler. + +- Bug #1110478: Revert os.environ.update to do putenv again. + +- Bug #1103844: fix distutils.install.dump_dirs() with negated options. + +- os.{SEEK_SET, SEEK_CUR, SEEK_END} have been added for convenience. + +- Enhancements to the csv module: + + + Dialects are now validated by the underlying C code, better + reflecting its capabilities, and improving its compliance with + PEP 305. + + Dialect parameter parsing has been re-implemented to improve error + reporting. + + quotechar=None and quoting=QUOTE_NONE now work the way PEP 305 + dictates. + + the parser now removes the escapechar prefix from escaped characters. + + when quoting=QUOTE_NONNUMERIC, the writer now tests for numeric + types, rather than any object that can be represented as a numeric. + + when quoting=QUOTE_NONNUMERIC, the reader now casts unquoted fields + to floats. + + reader now allows \r characters to be quoted (previously it only allowed + \n to be quoted). + + writer doublequote handling improved. + + Dialect classes passed to the module are no longer instantiated by + the module before being parsed (the former validation scheme required + this, but the mechanism was unreliable). + + The dialect registry now contains instances of the internal + C-coded dialect type, rather than references to python objects. + + the internal c-coded dialect type is now immutable. + + register_dialect now accepts the same keyword dialect specifications + as the reader and writer, allowing the user to register dialects + without first creating a dialect class. + + a configurable limit to the size of parsed fields has been added - + previously, an unmatched quote character could result in the entire + file being read into the field buffer before an error was reported. + + A new module method csv.field_size_limit() has been added that sets + the parser field size limit (returning the former limit). The initial + limit is 128kB. + + A line_num attribute has been added to the reader object, which tracks + the number of lines read from the source iterator. This is not + the same as the number of records returned, as records can span + multiple lines. + + reader and writer objects were not being registered with the cyclic-GC. + This has been fixed. + +- _DummyThread objects in the threading module now delete self.__block that is + inherited from _Thread since it uses up a lock allocated by 'thread'. The + lock primitives tend to be limited in number and thus should not be wasted on + a _DummyThread object. Fixes bug #1089632. + +- The imghdr module now detects Exif files. + +- StringIO.truncate() now correctly adjusts the size attribute. + (Bug #951915). + +- locale.py now uses an updated locale alias table (built using + Tools/i18n/makelocalealias.py, a tool to parse the X11 locale + alias file); the encoding lookup was enhanced to use Python's + encoding alias table. + +- moved deprecated modules to Lib/lib-old: whrandom, tzparse, statcache. + +- the pickle module no longer accepts the deprecated None option in the + args tuple returned by __reduce__(). + +- optparse now optionally imports gettext. This allows its use in setup.py. + +- the pickle module no longer uses the deprecated bin parameter. + +- the shelve module no longer uses the deprecated binary parameter. + +- the pstats module no longer uses the deprecated ignore() method. + +- the filecmp module no longer uses the deprecated use_statcache argument. + +- unittest.TestCase.run() and unittest.TestSuite.run() can now be successfully + extended or overridden by subclasses. Formerly, the subclassed method would + be ignored by the rest of the module. (Bug #1078905). + +- heapq.nsmallest() and heapq.nlargest() now support key= arguments with + the same meaning as in list.sort(). + +- Bug #1076985: ``codecs.StreamReader.readline()`` now calls ``read()`` only + once when a size argument is given. This prevents a buffer overflow in the + tokenizer with very long source lines. + +- Bug #1083110: ``zlib.decompress.flush()`` would segfault if called + immediately after creating the object, without any intervening + ``.decompress()`` calls. + +- The reconvert.quote function can now emit triple-quoted strings. The + reconvert module now has some simple documentation. + +- ``UserString.MutableString`` now supports negative indices in + ``__setitem__`` and ``__delitem__`` + +- Bug #1149508: ``textwrap`` now handles hyphenated numbers (eg. "2004-03-05") + correctly. + +- Partial fixes for SF bugs #1163244 and #1175396: If a chunk read by + ``codecs.StreamReader.readline()`` has a trailing "\r", read one more + character even if the user has passed a size parameter to get a proper + line ending. Remove the special handling of a "\r\n" that has been split + between two lines. + +- Bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain + about illegal code points. The codec now supports PEP 293 style error + handlers. + +- Bug #1235646: ``codecs.StreamRecoder.next()`` now reencodes the data it reads + from the input stream, so that the output is a byte string in the correct + encoding instead of a unicode string. + +- Bug #1202493: Fixing SRE parser to handle '{}' as perl does, rather than + considering it exactly like a '*'. + +- Bug #1245379: Add "unicode-1-1-utf-7" as an alias for "utf-7" to + ``encodings.aliases``. + +- ` uu.encode()`` and ``uu.decode()`` now support unicode filenames. + +- Patch #1413711: Certain patterns of differences were making difflib + touch the recursion limit. + +- Bug #947906: An object oriented interface has been added to the calendar + module. It's possible to generate HTML calendar now and the module can be + called as a script (e.g. via ``python -mcalendar``). Localized month and + weekday names can be ouput (even if an exotic encoding is used) using + special classes that use unicode. + +Build +----- + +- Fix test_float, test_long, and test_struct failures on Tru64 with gcc + by using -mieee gcc option. + +- Patch #1432345: Make python compile on DragonFly. + +- Build support for Win64-AMD64 was added. + +- Patch #1428494: Prefer linking against ncursesw over ncurses library. + +- Patch #881820: look for openpty and forkpty also in libbsd. + +- The sources of zlib are now part of the Python distribution (zlib 1.2.3). + The zlib module is now builtin on Windows. + +- Use -xcode=pic32 for CCSHARED on Solaris with SunPro. + +- Bug #1189330: configure did not correctly determine the necessary + value of LINKCC if python was built with GCC 4.0. + +- Upgrade Windows build to zlib 1.2.3 which eliminates a potential security + vulnerability in zlib 1.2.1 and 1.2.2. + +- EXTRA_CFLAGS has been introduced as an environment variable to hold compiler + flags that change binary compatibility. Changes were also made to + distutils.sysconfig to also use the environment variable when used during + compilation of the interpreter and of C extensions through distutils. + +- SF patch 1171735: Darwin 8's headers are anal about POSIX compliance, + and linking has changed (prebinding is now deprecated, and libcc_dynamic + no longer exists). This configure patch makes things right. + +- Bug #1158607: Build with --disable-unicode again. + +- spwdmodule.c is built only if either HAVE_GETSPNAM or HAVE_HAVE_GETSPENT is + defined. Discovered as a result of not being able to build on OS X. + +- setup.py now uses the directories specified in LDFLAGS using the -L option + and in CPPFLAGS using the -I option for adding library and include + directories, respectively, for compiling extension modules against. This has + led to the core being compiled using the values in CPPFLAGS. It also removes + the need for the special-casing of both DarwinPorts and Fink for darwin since + the proper directories can be specified in LDFLAGS (``-L/sw/lib`` for Fink, + ``-L/opt/local/lib`` for DarwinPorts) and CPPFLAGS (``-I/sw/include`` for + Fink, ``-I/opt/local/include`` for DarwinPorts). + +- Test in configure.in that checks for tzset no longer dependent on tm->tm_zone + to exist in the struct (not required by either ISO C nor the UNIX 2 spec). + Tests for sanity in tzname when HAVE_TZNAME defined were also defined. + Closes bug #1096244. Thanks Gregory Bond. + +C API +----- + +- ``PyMem_{Del, DEL}`` and ``PyMem_{Free, FREE}`` no longer map to + ``PyObject_{Free, FREE}``. They map to the system ``free()`` now. If memory + is obtained via the ``PyObject_`` family, it must be released via the + ``PyObject_`` family, and likewise for the ``PyMem_`` family. This has + always been officially true, but when Python's small-object allocator was + introduced, an attempt was made to cater to a few extension modules + discovered at the time that obtained memory via ``PyObject_New`` but + released it via ``PyMem_DEL``. It's years later, and if such code still + exists it will fail now (probably with segfaults, but calling wrong + low-level memory management functions can yield many symptoms). + +- Added a C API for set and frozenset objects. + +- Removed PyRange_New(). + +- Patch #1313939: PyUnicode_DecodeCharmap() accepts a unicode string as the + mapping argument now. This string is used as a mapping table. Byte values + greater than the length of the string and 0xFFFE are treated as undefined + mappings. + + +Tests +----- + +- In test_os, st_?time is now truncated before comparing it with ST_?TIME. + +- Patch #1276356: New resource "urlfetch" is implemented. This enables + even impatient people to run tests that require remote files. + + +Documentation +------------- + +- Bug #1402224: Add warning to dl docs about crashes. + +- Bug #1396471: Document that Windows' ftell() can return invalid + values for text files with UNIX-style line endings. + +- Bug #1274828: Document os.path.splitunc(). + +- Bug #1190204: Clarify which directories are searched by site.py. + +- Bug #1193849: Clarify os.path.expanduser() documentation. + +- Bug #1243192: re.UNICODE and re.LOCALE affect \d, \D, \s and \S. + +- Bug #755617: Document the effects of os.chown() on Windows. + +- Patch #1180012: The documentation for modulefinder is now in the library reference. + +- Patch #1213031: Document that os.chown() accepts argument values of -1. + +- Bug #1190563: Document os.waitpid() return value with WNOHANG flag. + +- Bug #1175022: Correct the example code for property(). + +- Document the IterableUserDict class in the UserDict module. + Closes bug #1166582. + +- Remove all latent references for "Macintosh" that referred to semantics for + Mac OS 9 and change to reflect the state for OS X. + Closes patch #1095802. Thanks Jack Jansen. + +Mac +--- + + +New platforms +------------- + +- FreeBSD 7 support is added. + + +Tools/Demos +----------- + +- Created Misc/Vim/vim_syntax.py to auto-generate a python.vim file in that + directory for syntax highlighting in Vim. Vim directory was added and placed + vimrc to it (was previous up a level). + +- Added two new files to Tools/scripts: pysource.py, which recursively + finds Python source files, and findnocoding.py, which finds Python + source files that need an encoding declaration. + Patch #784089, credits to Oleg Broytmann. + +- Bug #1072853: pindent.py used an uninitialized variable. + +- Patch #1177597: Correct Complex.__init__. + +- Fixed a display glitch in Pynche, which could cause the right arrow to + wiggle over by a pixel. + +---- + +**(For information about older versions, consult the HISTORY file.)** diff --git a/sys/src/cmd/python/Misc/NEWS.help b/sys/src/cmd/python/Misc/NEWS.help new file mode 100644 index 000000000..856785fa7 --- /dev/null +++ b/sys/src/cmd/python/Misc/NEWS.help @@ -0,0 +1,73 @@ + -*- text -*- + +If you edited Misc/NEWS before it was converted to ReST format skimming this +file should help make the transition a bit easier. For full details about +Docutils and ReST, go to the Docutils website: + + http://docutils.sourceforge.net/ + +To process Misc/NEWS using Docutils, you'll need the latest docutils +snapshot: + + http://docutils.sf.net/docutils-snapshot.tgz + +Docutils works with Python 2.2 or newer. + +To process NEWS into NEWS.html, first install Docutils, and then run +this command: + + python .../docutils/tools/rst2html.py NEWS NEWS.html + +Here ".../docutils" is the directory into which the above snapshot was +extracted. (I hope this recipe will change for the better.) + +David Goodger made a change to the allowable structure of internal +references which greatly simplified initial conversion of the file. + +The changes required fell into the following categories: + +* The top-level "What's New" section headers changed to: + + What's New in Python 2.3 alpha 1? + ================================= + + *Release date: DD-MMM-2002* + + Note that the release date line is emphasized, with a "*" at each + end. + +* Subsections are underlined with a single row of hyphens: + + Type/class unification and new-style classes + -------------------------------------------- + +* Places where "balanced" single quotes were used were changed to use + apostrophes as both the opening and closing quote (`string' -> 'string'). + +* In a few places asterisks needed to be escaped which would otherwise have + been interpreted as beginning blocks of italic or bold text, e.g.: + + - The type of tp_free has been changed from "``void (*)(PyObject *)``" + to "``void (*)(void *)``". + + Note that only the asterisks preceded by whitespace needed to be escaped. + +* One instance of a word ending with an underscore needed to be quoted + ("PyCmp_" became "``PyCmp_``"). + +* One table was converted to ReST form (search Misc/NEWS for "New codecs" + for this example). + +* A few places where chunks of code or indented text were displayed needed + to be properly introduced (preceding paragraph terminated by "::" and the + chunk of code or text indented w.r.t. the paragraph). For example: + + - Note that PyLong_AsDouble can fail! This has always been true, + but no callers checked for it. It's more likely to fail now, + because overflow errors are properly detected now. The proper way + to check:: + + double x = PyLong_AsDouble(some_long_object); + if (x == -1.0 && PyErr_Occurred()) { + /* The conversion failed. */ + } diff --git a/sys/src/cmd/python/Misc/PURIFY.README b/sys/src/cmd/python/Misc/PURIFY.README new file mode 100644 index 000000000..1e5d2ac19 --- /dev/null +++ b/sys/src/cmd/python/Misc/PURIFY.README @@ -0,0 +1,97 @@ +Purify (tm) and Quantify (tm) are commercial software quality +assurance tools available from IBM <http://www.ibm.com/software/rational/>. +Purify is essentially a memory access +verifier and leak detector; Quantify is a C level profiler. The rest +of this file assumes you generally know how to use Purify and +Quantify, and that you have installed valid licenses for these +products. If you haven't installed such licenses, you can ignore the +following since it won't help you a bit! + +You can easily build a Purify or Quantify instrumented version of the +Python interpreter by passing the PURIFY variable to the make command +at the top of the Python tree: + + make PURIFY=purify + +This assumes that the `purify' program is on your $PATH. Note that +you cannot both Purify and Quantify the Python interpreter (or any +program for that matter) at the same time. If you want to build a +Quantify'd interpreter, do this: + + make PURIFY=quantify + +Starting with Python 2.3, pymalloc is enabled by default. This +will cause many supurious warnings. Modify Objects/obmalloc.c +and enable Py_USING_MEMORY_DEBUGGER by uncommenting it. +README.valgrind has more details about why this is necessary. +See below about setting up suppressions. Some tests may not +run well with Purify due to heavy memory or CPU usage. These +tests may include: test_largefile, test_import, and test_long. + +Please report any findings (problems or no warnings) to python-dev@python.org. +It may be useful to submit a bug report for any problems. + +When running the regression test (make test), I have found it useful +to set my PURIFYOPTIONS environment variable using the following +(bash) shell function. Check out the Purify documentation for +details: + +p() { + chainlen='-chain-length=12' + ignoresigs='-ignore-signals="SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGTRAP,SIGAVRT,SIGEMT,SIGFPE,SIGKILL,SIGBUS,SIGSEGV,SIGPIPE,SIGTERM,SIGUSR1,SIGUSR2,SIGPOLL,SIGXCPU,SIGXFSZ,SIGFREEZE,SIGTHAW,SIGRTMIN,SIGRTMAX"' + followchild='-follow-child-processes=yes' + threads='-max-threads=50' + export PURIFYOPTIONS="$chainlen $ignoresigs $followchild $threads" + echo $PURIFYOPTIONS +} + +Note that you may want to crank -chain-length up even further. A +value of 20 should get you the entire stack up into the Python C code +in all situations. + +With the regression test on a fatly configured interpreter +(i.e. including as many modules as possible in your Modules/Setup +file), you'll probably get a gabillion UMR errors, and a few MLK +errors. I think most of these can be safely suppressed by putting the +following in your .purify file: + + suppress umr ...; "socketmodule.c" + suppress umr ...; time_strftime + suppress umr ...; "dbmmodule.c" + suppress umr ...; "gdbmmodule.c" + suppress umr ...; "grpmodule.c" + suppress umr ...; "nismodule.c" + suppress umr ...; "pwdmodule.c" + +Note: this list is very old and may not be accurate any longer. +It's possible some of these no longer need to be suppressed. +You will also need to suppress warnings (at least umr) +from Py_ADDRESS_IN_RANGE. + +This will still leave you with just a few UMR, mostly in the readline +library, which you can safely ignore. A lot of work has gone into +Python 1.5 to plug as many leaks as possible. + +Using Purify or Quantify in this way will give you coarse grained +reports on the whole Python interpreter. You can actually get more +fine grained control over both by linking with the optional `pure' +module, which exports (most of) the Purify and Quantify C API's into +Python. To link in this module (it must be statically linked), edit +your Modules/Setup file for your site, and rebuild the interpreter. +You might want to check out the comments in the Modules/puremodule.c +file for some idiosyncrasies. + +Using this module, you can actually profile or leak test a small +section of code, instead of the whole interpreter. Using this in +conjuction with pdb.py, dbx, or the profiler.py module really gives +you quite a bit of introspective power. + +Naturally there are a couple of caveats. This has only been tested +with Purify 4.0.1 and Quantify 2.1-beta on Solaris 2.5. Purify 4.0.1 +does not work with Solaris 2.6, but Purify 4.1 which reportedly will, +is currently in beta test. There are funky problems when Purify'ing a +Python interpreter build with threads. I've had a lot of problems +getting this to work, so I generally don't build with threads when I'm +Purify'ing. If you get this to work, let us know! + +-Barry Warsaw <bwarsaw@cnri.reston.va.us> diff --git a/sys/src/cmd/python/Misc/Porting b/sys/src/cmd/python/Misc/Porting new file mode 100644 index 000000000..60ce9a824 --- /dev/null +++ b/sys/src/cmd/python/Misc/Porting @@ -0,0 +1,42 @@ +Q. I want to port Python to a new platform. How do I begin? + +A. I guess the two things to start with is to familiarize yourself +with are the development system for your target platform and the +generic build process for Python. Make sure you can compile and run a +simple hello-world program on your target platform. Make sure you can +compile and run the Python interpreter on a platform to which it has +already been ported (preferably Unix, but Mac or Windows will do, +too). + +I also would never start something like this without at least +medium-level understanding of your target platform (i.e. how it is +generally used, how to write platform specific apps etc.) and Python +(or else you'll never know how to test the results). + +The build process for Python, in particular the Makefiles in the +source distribution, will give you a hint on which files to compile +for Python. Not all source files are relevant -- some are platform +specific, others are only used in emergencies (e.g. getopt.c). The +Makefiles tell the story. + +You'll also need a pyconfig.h file tailored for your platform. You can +start with pyconfig.h.in, read the comments and turn on definitions that +apply to your platform. + +And you'll need a config.c file, which lists the built-in modules you +support. Start with Modules/config.c.in. + +Finally, you'll run into some things that aren't supported on your +target platform. Forget about the posix module for now -- simply take +it out of the config.c file. + +Bang on it until you get a >>> prompt. (You may have to disable the +importing of "site.py" and "exceptions.py" by passing -X and -S +options. + +Then bang on it until it executes very simple Python statements. + +Now bang on it some more. At some point you'll want to use the os +module; this is the time to start thinking about what to to with the +posix module. It's okay to simply #ifdef out those functions that +cause problems; the remaining ones will be quite useful. diff --git a/sys/src/cmd/python/Misc/README b/sys/src/cmd/python/Misc/README new file mode 100644 index 000000000..af6e8e8f4 --- /dev/null +++ b/sys/src/cmd/python/Misc/README @@ -0,0 +1,33 @@ +Python Misc subdirectory +======================== + +This directory contains files that wouldn't fit in elsewhere. Some +documents are only of historic importance. + +Files found here +---------------- + +ACKS Acknowledgements +AIX-NOTES Notes for building Python on AIX +BeOS-NOTES Notes for building on BeOS +BeOS-setup.py setup.py replacement for BeOS, see BeOS-NOTES +cheatsheet Quick summary of Python by Ken Manheimer +find_recursionlimit.py Script to find a value for sys.maxrecursionlimit +gdbinit Handy stuff to put in your .gdbinit file, if you use gdb +HISTORY News from previous releases -- oldest last +HPUX-NOTES Notes about dynamic loading under HP-UX +indent.pro GNU indent profile approximating my C style +NEWS News for this release (for some meaning of "this") +Porting Mini-FAQ on porting to new platforms +PURIFY.README Information for Purify users +pymemcompat.h Memory interface compatibility file. +python.man UNIX man page for the python interpreter +python-mode.el Emacs mode for editing Python programs +README The file you're reading now +README.valgrind Information for Valgrind users, see valgrind-python.supp +RFD Request For Discussion about a Python newsgroup +RPM (Old) tools to build RPMs +SpecialBuilds.txt Describes extra symbols you can set for debug builds +setuid-prog.c C helper program for set-uid Python scripts +vgrindefs Python configuration for vgrind (a generic pretty printer) +valgrind-python.supp Valgrind suppression file, see README.valgrind diff --git a/sys/src/cmd/python/Misc/README.OpenBSD b/sys/src/cmd/python/Misc/README.OpenBSD new file mode 100644 index 000000000..b417ecc76 --- /dev/null +++ b/sys/src/cmd/python/Misc/README.OpenBSD @@ -0,0 +1,38 @@ + +2005-01-08 + +If you are have a problem building on OpenBSD and see output like this +while running configure: + +checking curses.h presence... yes +configure: WARNING: curses.h: present but cannot be compiled +configure: WARNING: curses.h: check for missing prerequisite headers? +configure: WARNING: curses.h: see the Autoconf documentation +configure: WARNING: curses.h: section "Present But Cannot Be Compiled" +configure: WARNING: curses.h: proceeding with the preprocessor's result +configure: WARNING: curses.h: in the future, the compiler will take precedence + +there is likely a problem that will prevent building python. +If you see the messages above and are able to completely build python, +please tell python-dev@python.org indicating your version of OpenBSD +and any other relevant system configuration. + +The build error that occurs while making may look something like this: + + /usr/include/sys/event.h:53: error: syntax error before "u_int" + /usr/include/sys/event.h:55: error: syntax error before "u_short" + +To fix this problem, you will probably need update Python's configure +script to disable certain options. Search for a line that looks like: + + OpenBSD/2.* | OpenBSD/3.@<:@012345678@:>@) + +If your version is not in that list, e.g., 3.9, add the version +number. In this case, you would just need to add a 9 after the 8. +If you modify configure.in, you will need to regenerate configure +with autoconf. + +If your version is already in the list, this is not a known problem. +Please submit a bug report here: + + http://sourceforge.net/tracker/?group_id=5470&atid=105470 diff --git a/sys/src/cmd/python/Misc/README.coverity b/sys/src/cmd/python/Misc/README.coverity new file mode 100644 index 000000000..f5e1bf6f2 --- /dev/null +++ b/sys/src/cmd/python/Misc/README.coverity @@ -0,0 +1,22 @@ + +Coverity has a static analysis tool (Prevent) which is similar to Klocwork. +They run their tool on the Python source code (SVN head) on a daily basis. +The results are available at: + + http://scan.coverity.com/ + +About 20 people have access to the analysis reports. Other +people can be added by request. + +Prevent was first run on the Python 2.5 source code in March 2006. +There were originally about 100 defects reported. Some of these +were false positives. Over 70 issues were uncovered. + +Each warning has a unique id and comments that can be made on it. +When checking in changes due to a warning, the unique id +as reported by the tool was added to the SVN commit message. + +False positives were annotated so that the comments can +be reviewed and reversed if the analysis was incorrect. + +Contact python-dev@python.org for more information. diff --git a/sys/src/cmd/python/Misc/README.klocwork b/sys/src/cmd/python/Misc/README.klocwork new file mode 100644 index 000000000..6d2f57fc7 --- /dev/null +++ b/sys/src/cmd/python/Misc/README.klocwork @@ -0,0 +1,30 @@ + +Klocwork has a static analysis tool (K7) which is similar to Coverity. +They will run their tool on the Python source code on demand. +The results are available at: + + https://opensource.klocwork.com/ + +Currently, only Neal Norwitz has access to the analysis reports. Other +people can be added by request. + +K7 was first run on the Python 2.5 source code in mid-July 2006. +This is after Coverity had been making their results available. +There were originally 175 defects reported. Most of these +were false positives. However, there were numerous real issues +also uncovered. + +Each warning has a unique id and comments that can be made on it. +When checking in changes due to a K7 report, the unique id +as reported by the tool was added to the SVN commit message. +A comment was added to the K7 warning indicating the SVN revision +in addition to any analysis. + +False positives were also annotated so that the comments can +be reviewed and reversed if the analysis was incorrect. + +A second run was performed on 10-Aug-2006. The tool was tuned to remove +some false positives and perform some additional checks. ~150 new +warnings were produced, primarily related to dereferencing NULL pointers. + +Contact python-dev@python.org for more information. diff --git a/sys/src/cmd/python/Misc/README.valgrind b/sys/src/cmd/python/Misc/README.valgrind new file mode 100644 index 000000000..b5a9a32e1 --- /dev/null +++ b/sys/src/cmd/python/Misc/README.valgrind @@ -0,0 +1,97 @@ +This document describes some caveats about the use of Valgrind with +Python. Valgrind is used periodically by Python developers to try +to ensure there are no memory leaks or invalid memory reads/writes. + +If you don't want to read about the details of using Valgrind, there +are still two things you must do to suppress the warnings. First, +you must use a suppressions file. One is supplied in +Misc/valgrind-python.supp. Second, you must do one of the following: + + * Uncomment Py_USING_MEMORY_DEBUGGER in Objects/obmalloc.c, + then rebuild Python + * Uncomment the lines in Misc/valgrind-python.supp that + suppress the warnings for PyObject_Free and PyObject_Realloc + +If you want to use Valgrind more effectively and catch even more +memory leaks, you will need to configure python --without-pymalloc. +PyMalloc allocates a few blocks in big chunks and most object +allocations don't call malloc, they use chunks doled about by PyMalloc +from the big blocks. This means Valgrind can't detect +many allocations (and frees), except for those that are forwarded +to the system malloc. Note: configuring python --without-pymalloc +makes Python run much slower, especially when running under Valgrind. +You may need to run the tests in batches under Valgrind to keep +the memory usage down to allow the tests to complete. It seems to take +about 5 times longer to run --without-pymalloc. + +Apr 15, 2006: + test_ctypes causes Valgrind 3.1.1 to fail (crash). + test_socket_ssl should be skipped when running valgrind. + The reason is that it purposely uses uninitialized memory. + This causes many spurious warnings, so it's easier to just skip it. + + +Details: +-------- +Python uses its own small-object allocation scheme on top of malloc, +called PyMalloc. + +Valgrind may show some unexpected results when PyMalloc is used. +Starting with Python 2.3, PyMalloc is used by default. You can disable +PyMalloc when configuring python by adding the --without-pymalloc option. +If you disable PyMalloc, most of the information in this document and +the supplied suppressions file will not be useful. As discussed above, +disabling PyMalloc can catch more problems. + +If you use valgrind on a default build of Python, you will see +many errors like: + + ==6399== Use of uninitialised value of size 4 + ==6399== at 0x4A9BDE7E: PyObject_Free (obmalloc.c:711) + ==6399== by 0x4A9B8198: dictresize (dictobject.c:477) + +These are expected and not a problem. Tim Peters explains +the situation: + + PyMalloc needs to know whether an arbitrary address is one + that's managed by it, or is managed by the system malloc. + The current scheme allows this to be determined in constant + time, regardless of how many memory areas are under pymalloc's + control. + + The memory pymalloc manages itself is in one or more "arenas", + each a large contiguous memory area obtained from malloc. + The base address of each arena is saved by pymalloc + in a vector. Each arena is carved into "pools", and a field at + the start of each pool contains the index of that pool's arena's + base address in that vector. + + Given an arbitrary address, pymalloc computes the pool base + address corresponding to it, then looks at "the index" stored + near there. If the index read up is out of bounds for the + vector of arena base addresses pymalloc maintains, then + pymalloc knows for certain that this address is not under + pymalloc's control. Otherwise the index is in bounds, and + pymalloc compares + + the arena base address stored at that index in the vector + + to + + the arbitrary address pymalloc is investigating + + pymalloc controls this arbitrary address if and only if it lies + in the arena the address's pool's index claims it lies in. + + It doesn't matter whether the memory pymalloc reads up ("the + index") is initialized. If it's not initialized, then + whatever trash gets read up will lead pymalloc to conclude + (correctly) that the address isn't controlled by it, either + because the index is out of bounds, or the index is in bounds + but the arena it represents doesn't contain the address. + + This determination has to be made on every call to one of + pymalloc's free/realloc entry points, so its speed is critical + (Python allocates and frees dynamic memory at a ferocious rate + -- everything in Python, from integers to "stack frames", + lives in the heap). diff --git a/sys/src/cmd/python/Misc/RFD b/sys/src/cmd/python/Misc/RFD new file mode 100644 index 000000000..fd278c4fa --- /dev/null +++ b/sys/src/cmd/python/Misc/RFD @@ -0,0 +1,114 @@ +To: python-list +Subject: comp.lang.python RFD again +From: Guido.van.Rossum@cwi.nl + +I've followed the recent discussion and trimmed the blurb RFD down a bit +(and added the word "object-oriented" to the blurb). + +I don't think it's too early to *try* to create the newsgroup -- +whether we will succeed may depend on how many Python supporters there +are outside the mailing list. + +I'm personally not worried about moderation, and anyway I haven't +heard from any volunteers for moderation (and I won't volunteer +myself) so I suggest that we'll continue to ask for one unmoderated +newsgroup. + +My next action will be to post an updated FAQ (which will hint at the +upcoming RFD) to comp.lang.misc; then finalize the 1.0.0 release and +put it on the ftp site. I'll also try to get it into +comp.sources.unix or .misc. And all this before the end of January! + +--Guido van Rossum, CWI, Amsterdam <Guido.van.Rossum@cwi.nl> +URL: <http://www.cwi.nl/cwi/people/Guido.van.Rossum.html> + +====================================================================== + +These are the steps required (in case you don't know about the +newsgroup creation process): + +First, we need to draw up an RFD (Request For Discussion). This is a +document that tells what the purpose of the group is, and gives a case +for its creation. We post this to relevant groups (comp.lang.misc, +the mailing list, news.groups, etc.) Discussion is held on +news.groups. + +Then, after a few weeks, we run the official CFV (Call For Votes). +The votes are then collected over a period of weeks. We need 100 more +yes votes than no votes, and a 2/3 majority, to get the group. + +There are some restrictions on the vote taker: [s]he cannot actively +campaign for/against the group during the vote process. So the main +benefit to Steve instead of me running the vote is that I will be free +to campaign for its creation! + +The following is our current draft for the RFD. + +====================================================================== + +Request For Discussion: comp.lang.python + + +Purpose +------- + +The newsgroup will be for discussion on the Python computer language. +Possible topics include requests for information, general programming, +development, and bug reports. The group will be unmoderated. + + +What is Python? +--------------- + +Python is a relatively new very-high-level language developed in +Amsterdam. Python is a simple, object-oriented procedural language, +with features taken from ABC, Icon, Modula-3, and C/C++. + +Its central goal is to provide the best of both worlds: the dynamic +nature of scripting languages like Perl/TCL/REXX, but also support for +general programming found in the more traditional languages like Icon, +C, Modula,... + +Python may be FTP'd from the following sites: + + ftp.cwi.nl in directory /pub/python (its "home site", also has a FAQ) + ftp.uu.net in directory /languages/python + gatekeeper.dec.com in directory /pub/plan/python/cwi + + +Rationale +--------- + +Currently there is a mailing list with over 130 subscribers. +The activity of this list is high, and to make handling the +traffic more reasonable, a newsgroup is being proposed. We +also feel that comp.lang.misc would not be a suitable forum +for this volume of discussion on a particular language. + + +Charter +------- + +Comp.lang.python is an unmoderated newsgroup which will serve +as a forum for discussing the Python computer language. The +group will serve both those who just program in Python and +those who work on developing the language. Topics that +may be discussed include: + + - announcements of new versions of the language and + applications written in Python. + + - discussion on the internals of the Python language. + + - general information about the language. + + - discussion on programming in Python. + + +Discussion +---------- + +Any objections to this RFD will be considered and, if determined +to be appropriate, will be incorporated. The discussion period +will be for a period of 21 days after which the first CFV will be +issued. diff --git a/sys/src/cmd/python/Misc/RPM/README b/sys/src/cmd/python/Misc/RPM/README new file mode 100644 index 000000000..f3a25575f --- /dev/null +++ b/sys/src/cmd/python/Misc/RPM/README @@ -0,0 +1,16 @@ +This directory contains support file used to build RPM releases of +Python. Its contents are maintained by Sean Reifschneider +<jafo@tummy.com>. + +It is recommended that RPM builders use the python*.src.rpm file +downloaded from the "ftp.python.org:/pub/python/<version>/rpms". These +may be more up to date than the files included in the base Python +release tar-file. + +If you wish to build RPMs from the base Python release tar-file, note +that you will have to download the +"doc/<version>/html-<version>.tar.bz2" +file from python.org and place it into your "SOURCES" directory for +the build to complete. This is the same directory that you place the +Python-2.3.1 release tar-file in. You can then use the ".spec" file in +this directory to build RPMs. diff --git a/sys/src/cmd/python/Misc/RPM/python-2.5.spec b/sys/src/cmd/python/Misc/RPM/python-2.5.spec new file mode 100644 index 000000000..399907463 --- /dev/null +++ b/sys/src/cmd/python/Misc/RPM/python-2.5.spec @@ -0,0 +1,395 @@ +########################## +# User-modifiable configs +########################## + +# Is the resulting package and the installed binary named "python" or +# "python2"? +#WARNING: Commenting out doesn't work. Last line is what's used. +%define config_binsuffix none +%define config_binsuffix 2.5 + +# Build tkinter? "auto" enables it if /usr/bin/wish exists. +#WARNING: Commenting out doesn't work. Last line is what's used. +%define config_tkinter no +%define config_tkinter yes +%define config_tkinter auto + +# Use pymalloc? The last line (commented or not) determines wether +# pymalloc is used. +#WARNING: Commenting out doesn't work. Last line is what's used. +%define config_pymalloc no +%define config_pymalloc yes + +# Enable IPV6? +#WARNING: Commenting out doesn't work. Last line is what's used. +%define config_ipv6 yes +%define config_ipv6 no + +# Location of the HTML directory. +%define config_htmldir /var/www/html/python + +################################# +# End of user-modifiable configs +################################# + +%define name python +%define version 2.5.1 +%define libvers 2.5 +%define release 1pydotorg +%define __prefix /usr + +# kludge to get around rpm <percent>define weirdness +%define ipv6 %(if [ "%{config_ipv6}" = yes ]; then echo --enable-ipv6; else echo --disable-ipv6; fi) +%define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) +%define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) +%define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) +%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) + +# detect if documentation is available +%define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) + +Summary: An interpreted, interactive, object-oriented programming language. +Name: %{name}%{binsuffix} +Version: %{version} +Release: %{release} +License: Python Software Foundation +Group: Development/Languages +Source: Python-%{version}.tar.bz2 +%if %{include_docs} +Source1: html-%{version}.tar.bz2 +%endif +BuildRoot: %{_tmppath}/%{name}-%{version}-root +BuildPrereq: expat-devel +BuildPrereq: db4-devel +BuildPrereq: gdbm-devel +BuildPrereq: sqlite-devel +Prefix: %{__prefix} +Packager: Sean Reifschneider <jafo-rpms@tummy.com> + +%description +Python is an interpreted, interactive, object-oriented programming +language. It incorporates modules, exceptions, dynamic typing, very high +level dynamic data types, and classes. Python combines remarkable power +with very clear syntax. It has interfaces to many system calls and +libraries, as well as to various window systems, and is extensible in C or +C++. It is also usable as an extension language for applications that need +a programmable interface. Finally, Python is portable: it runs on many +brands of UNIX, on PCs under Windows, MS-DOS, and OS/2, and on the +Mac. + +%package devel +Summary: The libraries and header files needed for Python extension development. +Prereq: python%{binsuffix} = %{PACKAGE_VERSION} +Group: Development/Libraries + +%description devel +The Python programming language's interpreter can be extended with +dynamically loaded extensions and can be embedded in other programs. +This package contains the header files and libraries needed to do +these types of tasks. + +Install python-devel if you want to develop Python extensions. The +python package will also need to be installed. You'll probably also +want to install the python-docs package, which contains Python +documentation. + +%if %{include_tkinter} +%package tkinter +Summary: A graphical user interface for the Python scripting language. +Group: Development/Languages +Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} + +%description tkinter +The Tkinter (Tk interface) program is an graphical user interface for +the Python scripting language. + +You should install the tkinter package if you'd like to use a graphical +user interface for Python programming. +%endif + +%package tools +Summary: A collection of development tools included with Python. +Group: Development/Tools +Prereq: python%{binsuffix} = %{PACKAGE_VERSION}-%{release} + +%description tools +The Python package includes several development tools that are used +to build python programs. This package contains a selection of those +tools, including the IDLE Python IDE. + +Install python-tools if you want to use these tools to develop +Python programs. You will also need to install the python and +tkinter packages. + +%if %{include_docs} +%package docs +Summary: Python-related documentation. +Group: Development/Documentation + +%description docs +Documentation relating to the Python programming language in HTML and info +formats. +%endif + +%changelog +* Mon Dec 20 2004 Sean Reifschneider <jafo-rpms@tummy.com> [2.4-2pydotorg] +- Changing the idle wrapper so that it passes arguments to idle. + +* Tue Oct 19 2004 Sean Reifschneider <jafo-rpms@tummy.com> [2.4b1-1pydotorg] +- Updating to 2.4. + +* Thu Jul 22 2004 Sean Reifschneider <jafo-rpms@tummy.com> [2.3.4-3pydotorg] +- Paul Tiemann fixes for %{prefix}. +- Adding permission changes for directory as suggested by reimeika.ca +- Adding code to detect when it should be using lib64. +- Adding a define for the location of /var/www/html for docs. + +* Thu May 27 2004 Sean Reifschneider <jafo-rpms@tummy.com> [2.3.4-2pydotorg] +- Including changes from Ian Holsman to build under Red Hat 7.3. +- Fixing some problems with the /usr/local path change. + +* Sat Mar 27 2004 Sean Reifschneider <jafo-rpms@tummy.com> [2.3.2-3pydotorg] +- Being more agressive about finding the paths to fix for + #!/usr/local/bin/python. + +* Sat Feb 07 2004 Sean Reifschneider <jafo-rpms@tummy.com> [2.3.3-2pydotorg] +- Adding code to remove "#!/usr/local/bin/python" from particular files and + causing the RPM build to terminate if there are any unexpected files + which have that line in them. + +* Mon Oct 13 2003 Sean Reifschneider <jafo-rpms@tummy.com> [2.3.2-1pydotorg] +- Adding code to detect wether documentation is available to build. + +* Fri Sep 19 2003 Sean Reifschneider <jafo-rpms@tummy.com> [2.3.1-1pydotorg] +- Updating to the 2.3.1 release. + +* Mon Feb 24 2003 Sean Reifschneider <jafo-rpms@tummy.com> [2.3b1-1pydotorg] +- Updating to 2.3b1 release. + +* Mon Feb 17 2003 Sean Reifschneider <jafo-rpms@tummy.com> [2.3a1-1] +- Updating to 2.3 release. + +* Sun Dec 23 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2-2] +- Added -docs package. +- Added "auto" config_tkinter setting which only enables tk if + /usr/bin/wish exists. + +* Sat Dec 22 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2-1] +- Updated to 2.2. +- Changed the extension to "2" from "2.2". + +* Tue Nov 18 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2c1-1] +- Updated to 2.2c1. + +* Thu Nov 1 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2b1-3] +- Changed the way the sed for fixing the #! in pydoc works. + +* Wed Oct 24 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2b1-2] +- Fixed missing "email" package, thanks to anonymous report on sourceforge. +- Fixed missing "compiler" package. + +* Mon Oct 22 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2b1-1] +- Updated to 2.2b1. + +* Mon Oct 9 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2a4-4] +- otto@balinor.mat.unimi.it mentioned that the license file is missing. + +* Sun Sep 30 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2a4-3] +- Ignacio Vazquez-Abrams pointed out that I had a spruious double-quote in + the spec files. Thanks. + +* Wed Jul 25 2001 Sean Reifschneider <jafo-rpms@tummy.com> +[Release 2.2a1-1] +- Updated to 2.2a1 release. +- Changed idle and pydoc to use binsuffix macro + +####### +# PREP +####### +%prep +%setup -n Python-%{version} + +######## +# BUILD +######## +%build +./configure --enable-unicode=ucs4 %{ipv6} %{pymalloc} --prefix=%{__prefix} +make + +########## +# INSTALL +########## +%install +# set the install path +echo '[install_scripts]' >setup.cfg +echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg + +[ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT +mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload +make prefix=$RPM_BUILD_ROOT%{__prefix} install + +# REPLACE PATH IN PYDOC +if [ ! -z "%{binsuffix}" ] +then + for file in pydoc python-config; do + ( + cd $RPM_BUILD_ROOT%{__prefix}/bin + mv "$file" "$file".old + sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ + "$file".old >"$file" + chmod 755 "$file" + rm -f "$file".old + ) + done +fi + +# add the binsuffix +if [ ! -z "%{binsuffix}" ] +then + ( cd $RPM_BUILD_ROOT%{__prefix}/bin; rm -f python[0-9a-zA-Z]*; + mv -f python python"%{binsuffix}" ) + ( cd $RPM_BUILD_ROOT%{__prefix}/man/man1; mv python.1 python%{binsuffix}.1 ) + ( cd $RPM_BUILD_ROOT%{__prefix}/bin; mv -f smtpd.py python-smtpd ) + for file in pydoc idle python-config python-smtpd; do + ( cd $RPM_BUILD_ROOT%{__prefix}/bin; mv -f "$file" "$file""%{binsuffix}" ) + done +fi + +######## +# Tools +echo '#!%{__prefix}/bin/env python%{binsuffix}' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} +echo 'import os, sys' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} +echo 'os.execvp("%{__prefix}/bin/python%{binsuffix}", ["%{__prefix}/bin/python%{binsuffix}", "%{__prefix}/lib/python%{libvers}/idlelib/idle.py"] + sys.argv[1:])' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} +echo 'print "Failed to exec Idle"' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} +echo 'sys.exit(1)' >>${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} +chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} +cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} + +# MAKE FILE LISTS +rm -f mainpkg.files +find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/lib-dynload -type f | + sed "s|^${RPM_BUILD_ROOT}|/|" | + grep -v -e '_tkinter.so$' >mainpkg.files +find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f | + sed "s|^${RPM_BUILD_ROOT}|/|" | + grep -v -e '/bin/setup-config%{binsuffix}$' | + grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files + +rm -f tools.files +find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ + "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | + grep -v -e '\.pyc$' -e '\.pyo$' | + sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files +echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files +grep '\.py$' tools.files | sed 's/$/c/' | grep -v /idlelib/ >tools.files.tmp +grep '\.py$' tools.files | sed 's/$/o/' | grep -v /idlelib/ >>tools.files.tmp +cat tools.files.tmp >>tools.files +rm tools.files.tmp + +###### +# Docs +%if %{include_docs} +mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} +( + cd "$RPM_BUILD_ROOT"%{config_htmldir} + bunzip2 < %{SOURCE1} | tar x +) +%endif + +# fix the #! line in installed files +find "$RPM_BUILD_ROOT" -type f -print0 | + xargs -0 grep -l /usr/local/bin/python | while read file +do + FIXFILE="$file" + sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ + "$FIXFILE" >/tmp/fix-python-path.$$ + cat /tmp/fix-python-path.$$ >"$FIXFILE" + rm -f /tmp/fix-python-path.$$ +done + +# check to see if there are any straggling #! lines +find "$RPM_BUILD_ROOT" -type f | xargs egrep -n '^#! */usr/local/bin/python' \ + | grep ':1:#!' >/tmp/python-rpm-files.$$ || true +if [ -s /tmp/python-rpm-files.$$ ] +then + echo '*****************************************************' + cat /tmp/python-rpm-files.$$ + cat <<@EOF + ***************************************************** + There are still files referencing /usr/local/bin/python in the + install directory. They are listed above. Please fix the .spec + file and try again. If you are an end-user, you probably want + to report this to jafo-rpms@tummy.com as well. + ***************************************************** +@EOF + rm -f /tmp/python-rpm-files.$$ + exit 1 +fi +rm -f /tmp/python-rpm-files.$$ + +######## +# CLEAN +######## +%clean +[ -n "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != / ] && rm -rf $RPM_BUILD_ROOT +rm -f mainpkg.files tools.files + +######## +# FILES +######## +%files -f mainpkg.files +%defattr(-,root,root) +%doc Misc/README Misc/cheatsheet Misc/Porting +%doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS +%{__prefix}/man/man1/python%{binsuffix}.1* + +%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} +%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ +%{__prefix}/%{libdirname}/python%{libvers}/*.txt +%{__prefix}/%{libdirname}/python%{libvers}/*.py* +%{__prefix}/%{libdirname}/python%{libvers}/pdb.doc +%{__prefix}/%{libdirname}/python%{libvers}/curses +%{__prefix}/%{libdirname}/python%{libvers}/distutils +%{__prefix}/%{libdirname}/python%{libvers}/encodings +%{__prefix}/%{libdirname}/python%{libvers}/plat-linux2 +%{__prefix}/%{libdirname}/python%{libvers}/site-packages +%{__prefix}/%{libdirname}/python%{libvers}/test +%{__prefix}/%{libdirname}/python%{libvers}/xml +%{__prefix}/%{libdirname}/python%{libvers}/email +%{__prefix}/%{libdirname}/python%{libvers}/sqlite3 +%{__prefix}/%{libdirname}/python%{libvers}/compiler +%{__prefix}/%{libdirname}/python%{libvers}/bsddb +%{__prefix}/%{libdirname}/python%{libvers}/hotshot +%{__prefix}/%{libdirname}/python%{libvers}/logging +%{__prefix}/%{libdirname}/python%{libvers}/wsgiref +%{__prefix}/%{libdirname}/python%{libvers}/ctypes +%{__prefix}/%{libdirname}/python%{libvers}/wsgiref.egg-info + +%files devel +%defattr(-,root,root) +%{__prefix}/include/python%{libvers}/*.h +%{__prefix}/%{libdirname}/python%{libvers}/config + +%files -f tools.files tools +%defattr(-,root,root) + +%if %{include_tkinter} +%files tkinter +%defattr(-,root,root) +%{__prefix}/%{libdirname}/python%{libvers}/lib-tk +%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* +%endif + +%if %{include_docs} +%files docs +%defattr(-,root,root) +%{config_htmldir}/* +%endif diff --git a/sys/src/cmd/python/Misc/SpecialBuilds.txt b/sys/src/cmd/python/Misc/SpecialBuilds.txt new file mode 100644 index 000000000..952ca42d9 --- /dev/null +++ b/sys/src/cmd/python/Misc/SpecialBuilds.txt @@ -0,0 +1,261 @@ +This file describes some special Python build types enabled via +compile-time preprocessor defines. + +It is best to define these options in the EXTRA_CFLAGS make variable; +``make EXTRA_CFLAGS="-DPy_REF_DEBUG"``. + +--------------------------------------------------------------------------- +Py_REF_DEBUG introduced in 1.4 + named REF_DEBUG before 1.4 + +Turn on aggregate reference counting. This arranges that extern +_Py_RefTotal hold a count of all references, the sum of ob_refcnt across +all objects. In a debug-mode build, this is where the "8288" comes from +in + + >>> 23 + 23 + [8288 refs] + >>> + +Note that if this count increases when you're not storing away new objects, +there's probably a leak. Remember, though, that in interactive mode the +special name "_" holds a reference to the last result displayed! + +Py_REF_DEBUG also checks after every decref to verify that the refcount +hasn't gone negative, and causes an immediate fatal error if it has. + +Special gimmicks: + +sys.gettotalrefcount() + Return current total of all refcounts. + Available under Py_REF_DEBUG in Python 2.3. + Before 2.3, Py_TRACE_REFS was required to enable this function. +--------------------------------------------------------------------------- +Py_TRACE_REFS introduced in 1.4 + named TRACE_REFS before 1.4 + +Turn on heavy reference debugging. This is major surgery. Every PyObject +grows two more pointers, to maintain a doubly-linked list of all live +heap-allocated objects. Most builtin type objects are not in this list, +as they're statically allocated. Starting in Python 2.3, if COUNT_ALLOCS +(see below) is also defined, a static type object T does appear in this +list if at least one object of type T has been created. + +Note that because the fundamental PyObject layout changes, Python modules +compiled with Py_TRACE_REFS are incompatible with modules compiled without +it. + +Py_TRACE_REFS implies Py_REF_DEBUG. + +Special gimmicks: + +sys.getobjects(max[, type]) + Return list of the (no more than) max most-recently allocated objects, + most recently allocated first in the list, least-recently allocated + last in the list. max=0 means no limit on list length. + If an optional type object is passed, the list is also restricted to + objects of that type. + The return list itself, and some temp objects created just to call + sys.getobjects(), are excluded from the return list. Note that the + list returned is just another object, though, so may appear in the + return list the next time you call getobjects(); note that every + object in the list is kept alive too, simply by virtue of being in + the list. + +envar PYTHONDUMPREFS + If this envar exists, Py_Finalize() arranges to print a list of + all still-live heap objects. This is printed twice, in different + formats, before and after Py_Finalize has cleaned up everything it + can clean up. The first output block produces the repr() of each + object so is more informative; however, a lot of stuff destined to + die is still alive then. The second output block is much harder + to work with (repr() can't be invoked anymore -- the interpreter + has been torn down too far), but doesn't list any objects that will + die. The tool script combinerefs.py can be run over this to combine + the info from both output blocks. The second output block, and + combinerefs.py, were new in Python 2.3b1. +--------------------------------------------------------------------------- +PYMALLOC_DEBUG introduced in 2.3 + +When pymalloc is enabled (WITH_PYMALLOC is defined), calls to the PyObject_ +memory routines are handled by Python's own small-object allocator, while +calls to the PyMem_ memory routines are directed to the system malloc/ +realloc/free. If PYMALLOC_DEBUG is also defined, calls to both PyObject_ +and PyMem_ memory routines are directed to a special debugging mode of +Python's small-object allocator. + +This mode fills dynamically allocated memory blocks with special, +recognizable bit patterns, and adds debugging info on each end of +dynamically allocated memory blocks. The special bit patterns are: + +#define CLEANBYTE 0xCB /* clean (newly allocated) memory */ +#define DEADBYTE 0xDB /* dead (newly freed) memory */ +#define FORBIDDENBYTE 0xFB /* fordidden -- untouchable bytes */ + +Strings of these bytes are unlikely to be valid addresses, floats, or 7-bit +ASCII strings. + +Let S = sizeof(size_t). 2*S bytes are added at each end of each block of N +bytes requested. The memory layout is like so, where p represents the +address returned by a malloc-like or realloc-like function (p[i:j] means +the slice of bytes from *(p+i) inclusive up to *(p+j) exclusive; note that +the treatment of negative indices differs from a Python slice): + +p[-2*S:-S] + Number of bytes originally asked for. This is a size_t, big-endian + (easier to read in a memory dump). +p[-S:0] + Copies of FORBIDDENBYTE. Used to catch under- writes and reads. +p[0:N] + The requested memory, filled with copies of CLEANBYTE, used to catch + reference to uninitialized memory. + When a realloc-like function is called requesting a larger memory + block, the new excess bytes are also filled with CLEANBYTE. + When a free-like function is called, these are overwritten with + DEADBYTE, to catch reference to freed memory. When a realloc- + like function is called requesting a smaller memory block, the excess + old bytes are also filled with DEADBYTE. +p[N:N+S] + Copies of FORBIDDENBYTE. Used to catch over- writes and reads. +p[N+S:N+2*S] + A serial number, incremented by 1 on each call to a malloc-like or + realloc-like function. + Big-endian size_t. + If "bad memory" is detected later, the serial number gives an + excellent way to set a breakpoint on the next run, to capture the + instant at which this block was passed out. The static function + bumpserialno() in obmalloc.c is the only place the serial number + is incremented, and exists so you can set such a breakpoint easily. + +A realloc-like or free-like function first checks that the FORBIDDENBYTEs +at each end are intact. If they've been altered, diagnostic output is +written to stderr, and the program is aborted via Py_FatalError(). The +other main failure mode is provoking a memory error when a program +reads up one of the special bit patterns and tries to use it as an address. +If you get in a debugger then and look at the object, you're likely +to see that it's entirely filled with 0xDB (meaning freed memory is +getting used) or 0xCB (meaning uninitialized memory is getting used). + +Note that PYMALLOC_DEBUG requires WITH_PYMALLOC. + +Special gimmicks: + +envar PYTHONMALLOCSTATS + If this envar exists, a report of pymalloc summary statistics is + printed to stderr whenever a new arena is allocated, and also + by Py_Finalize(). + +Changed in 2.5: The number of extra bytes allocated is 4*sizeof(size_t). +Before it was 16 on all boxes, reflecting that Python couldn't make use of +allocations >= 2**32 bytes even on 64-bit boxes before 2.5. +--------------------------------------------------------------------------- +Py_DEBUG introduced in 1.5 + named DEBUG before 1.5 + +This is what is generally meant by "a debug build" of Python. + +Py_DEBUG implies LLTRACE, Py_REF_DEBUG, Py_TRACE_REFS, and +PYMALLOC_DEBUG (if WITH_PYMALLOC is enabled). In addition, C +assert()s are enabled (via the C way: by not defining NDEBUG), and +some routines do additional sanity checks inside "#ifdef Py_DEBUG" +blocks. +--------------------------------------------------------------------------- +COUNT_ALLOCS introduced in 0.9.9 + partly broken in 2.2 and 2.2.1 + +Each type object grows three new members: + + /* Number of times an object of this type was allocated. */ + int tp_allocs; + + /* Number of times an object of this type was deallocated. */ + int tp_frees; + + /* Highwater mark: the maximum value of tp_allocs - tp_frees so + * far; or, IOW, the largest number of objects of this type alive at + * the same time. + */ + int tp_maxalloc; + +Allocation and deallocation code keeps these counts up to date. +Py_Finalize() displays a summary of the info returned by sys.getcounts() +(see below), along with assorted other special allocation counts (like +the number of tuple allocations satisfied by a tuple free-list, the number +of 1-character strings allocated, etc). + +Before Python 2.2, type objects were immortal, and the COUNT_ALLOCS +implementation relies on that. As of Python 2.2, heap-allocated type/ +class objects can go away. COUNT_ALLOCS can blow up in 2.2 and 2.2.1 +because of this; this was fixed in 2.2.2. Use of COUNT_ALLOCS makes +all heap-allocated type objects immortal, except for those for which no +object of that type is ever allocated. + +Starting with Python 2.3, If Py_TRACE_REFS is also defined, COUNT_ALLOCS +arranges to ensure that the type object for each allocated object +appears in the doubly-linked list of all objects maintained by +Py_TRACE_REFS. + +Special gimmicks: + +sys.getcounts() + Return a list of 4-tuples, one entry for each type object for which + at least one object of that type was allocated. Each tuple is of + the form: + + (tp_name, tp_allocs, tp_frees, tp_maxalloc) + + Each distinct type object gets a distinct entry in this list, even + if two or more type objects have the same tp_name (in which case + there's no way to distinguish them by looking at this list). The + list is ordered by time of first object allocation: the type object + for which the first allocation of an object of that type occurred + most recently is at the front of the list. +--------------------------------------------------------------------------- +LLTRACE introduced well before 1.0 + +Compile in support for Low Level TRACE-ing of the main interpreter loop. + +When this preprocessor symbol is defined, before PyEval_EvalFrame +(eval_frame in 2.3 and 2.2, eval_code2 before that) executes a frame's code +it checks the frame's global namespace for a variable "__lltrace__". If +such a variable is found, mounds of information about what the interpreter +is doing are sprayed to stdout, such as every opcode and opcode argument +and values pushed onto and popped off the value stack. + +Not useful very often, but very useful when needed. + +--------------------------------------------------------------------------- +CALL_PROFILE introduced for Python 2.3 + +Count the number of function calls executed. + +When this symbol is defined, the ceval mainloop and helper functions +count the number of function calls made. It keeps detailed statistics +about what kind of object was called and whether the call hit any of +the special fast paths in the code. + +--------------------------------------------------------------------------- +WITH_TSC introduced for Python 2.4 + +Super-lowlevel profiling of the interpreter. When enabled, the sys +module grows a new function: + +settscdump(bool) + If true, tell the Python interpreter to dump VM measurements to + stderr. If false, turn off dump. The measurements are based on the + processor's time-stamp counter. + +This build option requires a small amount of platform specific code. +Currently this code is present for linux/x86 and any PowerPC platform +that uses GCC (i.e. OS X and linux/ppc). + +On the PowerPC the rate at which the time base register is incremented +is not defined by the architecture specification, so you'll need to +find the manual for your specific processor. For the 750CX, 750CXe +and 750FX (all sold as the G3) we find: + + The time base counter is clocked at a frequency that is + one-fourth that of the bus clock. + +This build is enabled by the --with-tsc flag to configure. diff --git a/sys/src/cmd/python/Misc/Vim/python.vim b/sys/src/cmd/python/Misc/Vim/python.vim new file mode 100644 index 000000000..61d75e2ce --- /dev/null +++ b/sys/src/cmd/python/Misc/Vim/python.vim @@ -0,0 +1,147 @@ +" Auto-generated Vim syntax file for Python +" +" To use: copy or symlink to ~/.vim/syntax/python.vim + + +if exists("b:current_syntax") + finish +endif + +if exists("python_highlight_all") + let python_highlight_numbers = 1 + let python_highlight_builtins = 1 + let python_highlight_exceptions = 1 + let python_highlight_space_errors = 1 +endif + +syn keyword pythonStatement as assert break continue del except exec finally +syn keyword pythonStatement global lambda pass print raise return try with +syn keyword pythonStatement yield + +syn keyword pythonStatement def class nextgroup=pythonFunction skipwhite + +syn match pythonFunction "[a-zA-Z_][a-zA-Z0-9_]*" contained + +syn keyword pythonRepeat for while + +syn keyword pythonConditional if elif else + +syn keyword pythonOperator and in is not or + +syn keyword pythonPreCondit import from + +syn match pythonComment "#.*$" contains=pythonTodo + +syn keyword pythonTodo TODO FIXME XXX contained + +syn region pythonString matchgroup=Normal start=+[uU]\='+ end=+'+ skip=+\\\\\|\\'+ contains=pythonEscape +syn region pythonString matchgroup=Normal start=+[uU]\="+ end=+"+ skip=+\\\\\|\\"+ contains=pythonEscape +syn region pythonString matchgroup=Normal start=+[uU]\="""+ end=+"""+ contains=pythonEscape +syn region pythonString matchgroup=Normal start=+[uU]\='''+ end=+'''+ contains=pythonEscape +syn region pythonString matchgroup=Normal start=+[uU]\=[rR]'+ end=+'+ skip=+\\\\\|\\'+ +syn region pythonString matchgroup=Normal start=+[uU]\=[rR]"+ end=+"+ skip=+\\\\\|\\"+ +syn region pythonString matchgroup=Normal start=+[uU]\=[rR]"""+ end=+"""+ +syn region pythonString matchgroup=Normal start=+[uU]\=[rR]'''+ end=+'''+ + +syn match pythonEscape +\\[abfnrtv\'"\\]+ contained +syn match pythonEscape "\\\o\{1,3}" contained +syn match pythonEscape "\\x\x\{2}" contained +syn match pythonEscape "\(\\u\x\{4}\|\\U\x\{8}\)" contained + +syn match pythonEscape "\\$" + + +if exists("python_highlight_numbers") + syn match pythonNumber "\<0x\x\+[Ll]\=\>" + syn match pythonNumber "\<\d\+[LljJ]\=\>" + syn match pythonNumber "\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>" + syn match pythonNumber "\<\d\+\.\([eE][+-]\=\d\+\)\=[jJ]\=\>" + syn match pythonNumber "\<\d\+\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>" + +endif + + +if exists("python_highlight_builtins") + syn keyword pythonBuiltin unichr all set abs vars int __import__ unicode + syn keyword pythonBuiltin enumerate reduce coerce intern exit issubclass + syn keyword pythonBuiltin divmod file Ellipsis apply isinstance open any + syn keyword pythonBuiltin locals help filter basestring slice copyright min + syn keyword pythonBuiltin super sum tuple hex execfile long id xrange chr + syn keyword pythonBuiltin complex bool zip pow dict True oct NotImplemented + syn keyword pythonBuiltin map None float hash getattr buffer max reversed + syn keyword pythonBuiltin object quit len repr callable credits setattr + syn keyword pythonBuiltin eval frozenset sorted ord __debug__ hasattr + syn keyword pythonBuiltin delattr False input license classmethod type + syn keyword pythonBuiltin raw_input list iter compile reload range globals + syn keyword pythonBuiltin staticmethod str property round dir cmp + +endif + + +if exists("python_highlight_exceptions") + syn keyword pythonException GeneratorExit ImportError RuntimeError + syn keyword pythonException UnicodeTranslateError MemoryError StopIteration + syn keyword pythonException PendingDeprecationWarning EnvironmentError + syn keyword pythonException LookupError OSError DeprecationWarning + syn keyword pythonException UnicodeError UnicodeEncodeError + syn keyword pythonException FloatingPointError ReferenceError NameError + syn keyword pythonException IOError SyntaxError + syn keyword pythonException FutureWarning ImportWarning SystemExit + syn keyword pythonException Exception EOFError StandardError ValueError + syn keyword pythonException TabError KeyError ZeroDivisionError SystemError + syn keyword pythonException UnicodeDecodeError IndentationError + syn keyword pythonException AssertionError TypeError IndexError + syn keyword pythonException RuntimeWarning KeyboardInterrupt UserWarning + syn keyword pythonException SyntaxWarning UnboundLocalError ArithmeticError + syn keyword pythonException Warning NotImplementedError AttributeError + syn keyword pythonException OverflowError BaseException + +endif + + +if exists("python_highlight_space_errors") + syn match pythonSpaceError display excludenl "\S\s\+$"ms=s+1 + syn match pythonSpaceError display " \+\t" + syn match pythonSpaceError display "\t\+ " + +endif + + + hi def link pythonStatement Statement + hi def link pythonStatement Statement + hi def link pythonFunction Function + hi def link pythonRepeat Repeat + hi def link pythonConditional Conditional + hi def link pythonOperator Operator + hi def link pythonPreCondit PreCondit + hi def link pythonComment Comment + hi def link pythonTodo Todo + hi def link pythonString String + hi def link pythonEscape Special + hi def link pythonEscape Special + + if exists("python_highlight_numbers") + hi def link pythonNumber Number + endif + + if exists("python_highlight_builtins") + hi def link pythonBuiltin Function + endif + + if exists("python_highlight_exceptions") + hi def link pythonException Exception + endif + + if exists("python_highlight_space_errors") + hi def link pythonSpaceError Error + endif + + +" Uncomment the 'minlines' statement line and comment out the 'maxlines' +" statement line; changes behaviour to look at least 2000 lines previously for +" syntax matches instead of at most 200 lines +syn sync match pythonSync grouphere NONE "):$" +syn sync maxlines=200 +"syn sync minlines=2000 + +let b:current_syntax = "python" diff --git a/sys/src/cmd/python/Misc/Vim/syntax_test.py b/sys/src/cmd/python/Misc/Vim/syntax_test.py new file mode 100644 index 000000000..ccc7f309c --- /dev/null +++ b/sys/src/cmd/python/Misc/Vim/syntax_test.py @@ -0,0 +1,63 @@ +"""Test file for syntax highlighting of editors. + +Meant to cover a wide range of different types of statements and expressions. +Not necessarily sensical or comprehensive (assume that if one exception is +highlighted that all are, for instance). + +Highlighting extraneous whitespace at the end of the line is not represented +here as all trailing whitespace is automatically removed from .py files in the +repository. + +""" +# Comment +# OPTIONAL: XXX catch your attention + +# Statements +from __future__ import with_statement # Import +from sys import path as thing +assert True # keyword +def foo(): # function definition + return [] +class Bar(object): # Class definition + def __enter__(self): + pass + def __exit__(self, *args): + pass +foo() # UNCOLOURED: function call +while False: # 'while' + continue +for x in foo(): # 'for' + break +with Bar() as stuff: + pass +if False: pass # 'if' +elif False: pass +else: pass + +# Constants +'single-quote', u'unicode' # Strings of all kinds; prefixes not highlighted +"double-quote" +"""triple double-quote""" +'''triple single-quote''' +r'raw' +ur'unicode raw' +'escape\n' +'\04' # octal +'\xFF' # hex +'\u1111' # unicode character +1 # Integral +1L +1.0 # Float +.1 +1+2j # Complex + +# Expressions +1 and 2 or 3 # Boolean operators +2 < 3 # UNCOLOURED: comparison operators +spam = 42 # UNCOLOURED: assignment +2 + 3 # UNCOLOURED: number operators +[] # UNCOLOURED: list +{} # UNCOLOURED: dict +(1,) # UNCOLOURED: tuple +all # Built-in functions +GeneratorExit # Exceptions diff --git a/sys/src/cmd/python/Misc/Vim/vim_syntax.py b/sys/src/cmd/python/Misc/Vim/vim_syntax.py new file mode 100644 index 000000000..3f2a3d8a2 --- /dev/null +++ b/sys/src/cmd/python/Misc/Vim/vim_syntax.py @@ -0,0 +1,226 @@ +from __future__ import with_statement + +import keyword +import exceptions +import __builtin__ +from string import Template + +comment_header = """" Auto-generated Vim syntax file for Python +" +" To use: copy or symlink to ~/.vim/syntax/python.vim""" + +statement_header = """ +if exists("b:current_syntax") + finish +endif""" + +statement_footer = ''' +" Uncomment the 'minlines' statement line and comment out the 'maxlines' +" statement line; changes behaviour to look at least 2000 lines previously for +" syntax matches instead of at most 200 lines +syn sync match pythonSync grouphere NONE "):$" +syn sync maxlines=200 +"syn sync minlines=2000 + +let b:current_syntax = "python"''' + +looping = ('for', 'while') +conditionals = ('if', 'elif', 'else') +boolean_ops = ('and', 'in', 'is', 'not', 'or') +import_stmts = ('import', 'from') +object_defs = ('def', 'class') + +exception_names = frozenset(exc for exc in dir(exceptions) + if not exc.startswith('__')) + +# Need to include functions that start with '__' (e.g., __import__), but +# nothing that comes with modules (e.g., __name__), so just exclude anything in +# the 'exceptions' module since we want to ignore exceptions *and* what any +# module would have +builtin_names = frozenset(builtin for builtin in dir(__builtin__) + if builtin not in dir(exceptions)) + +escapes = (r'+\\[abfnrtv\'"\\]+', r'"\\\o\{1,3}"', r'"\\x\x\{2}"', + r'"\(\\u\x\{4}\|\\U\x\{8}\)"', r'"\\$"') + +todos = ("TODO", "FIXME", "XXX") + +# XXX codify? +numbers = (r'"\<0x\x\+[Ll]\=\>"', r'"\<\d\+[LljJ]\=\>"', + '"\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>"', + '"\<\d\+\.\([eE][+-]\=\d\+\)\=[jJ]\=\>"', + '"\<\d\+\.\d\+\([eE][+-]\=\d\+\)\=[jJ]\=\>"') + +contained = lambda x: "%s contained" % x + +def str_regexes(): + """Generator to yield various combinations of strings regexes""" + regex_template = Template('matchgroup=Normal ' + + 'start=+[uU]\=${raw}${sep}+ ' + + 'end=+${sep}+ ' + + '${skip} ' + + '${contains}') + skip_regex = Template(r'skip=+\\\\\|\\${sep}+') + for raw in ('', '[rR]'): + for separator in ("'", '"', '"""', "'''"): + if len(separator) == 1: + skip = skip_regex.substitute(sep=separator) + else: + skip = '' + contains = 'contains=pythonEscape' if not raw else '' + yield regex_template.substitute(raw=raw, sep=separator, skip=skip, + contains = contains) + +space_errors = (r'excludenl "\S\s\+$"ms=s+1', r'" \+\t"', r'"\t\+ "') + +statements = ( + ('', + # XXX Might need to change pythonStatement since have + # specific Repeat, Conditional, Operator, etc. for 'while', + # etc. + [("Statement", "pythonStatement", "keyword", + (kw for kw in keyword.kwlist + if kw not in (looping + conditionals + boolean_ops + + import_stmts + object_defs)) + ), + ("Statement", "pythonStatement", "keyword", + (' '.join(object_defs) + + ' nextgroup=pythonFunction skipwhite')), + ("Function","pythonFunction", "match", + contained('"[a-zA-Z_][a-zA-Z0-9_]*"')), + ("Repeat", "pythonRepeat", "keyword", looping), + ("Conditional", "pythonConditional", "keyword", + conditionals), + ("Operator", "pythonOperator", "keyword", boolean_ops), + ("PreCondit", "pythonPreCondit", "keyword", import_stmts), + ("Comment", "pythonComment", "match", + '"#.*$" contains=pythonTodo'), + ("Todo", "pythonTodo", "keyword", + contained(' '.join(todos))), + ("String", "pythonString", "region", str_regexes()), + ("Special", "pythonEscape", "match", + (contained(esc) for esc in escapes + if not '$' in esc)), + ("Special", "pythonEscape", "match", r'"\\$"'), + ] + ), + ("python_highlight_numbers", + [("Number", "pythonNumber", "match", numbers)] + ), + ("python_highlight_builtins", + [("Function", "pythonBuiltin", "keyword", builtin_names)] + ), + ("python_highlight_exceptions", + [("Exception", "pythonException", "keyword", + exception_names)] + ), + ("python_highlight_space_errors", + [("Error", "pythonSpaceError", "match", + ("display " + err for err in space_errors))] + ) + ) + +def syn_prefix(type_, kind): + return 'syn %s %s ' % (type_, kind) + +def fill_stmt(iterable, fill_len): + """Yield a string that fills at most fill_len characters with strings + returned by 'iterable' and separated by a space""" + # Deal with trailing char to handle ' '.join() calculation + fill_len += 1 + overflow = None + it = iter(iterable) + while True: + buffer_ = [] + total_len = 0 + if overflow: + buffer_.append(overflow) + total_len += len(overflow) + 1 + overflow = None + while total_len < fill_len: + try: + new_item = it.next() + buffer_.append(new_item) + total_len += len(new_item) + 1 + except StopIteration: + if buffer_: + break + if overflow: + yield overflow + return + if total_len > fill_len: + overflow = buffer_.pop() + total_len -= len(overflow) - 1 + ret = ' '.join(buffer_) + assert len(ret) <= fill_len + yield ret + +FILL = 80 + +def main(file_path): + with open(file_path, 'w') as FILE: + # Comment for file + print>>FILE, comment_header + print>>FILE, '' + # Statements at start of file + print>>FILE, statement_header + print>>FILE, '' + # Generate case for python_highlight_all + print>>FILE, 'if exists("python_highlight_all")' + for statement_var, statement_parts in statements: + if statement_var: + print>>FILE, ' let %s = 1' % statement_var + else: + print>>FILE, 'endif' + print>>FILE, '' + # Generate Python groups + for statement_var, statement_parts in statements: + if statement_var: + print>>FILE, 'if exists("%s")' % statement_var + indent = ' ' + else: + indent = '' + for colour_group, group, type_, arguments in statement_parts: + if not isinstance(arguments, basestring): + prefix = syn_prefix(type_, group) + if type_ == 'keyword': + stmt_iter = fill_stmt(arguments, + FILL - len(prefix) - len(indent)) + try: + while True: + print>>FILE, indent + prefix + stmt_iter.next() + except StopIteration: + print>>FILE, '' + else: + for argument in arguments: + print>>FILE, indent + prefix + argument + else: + print>>FILE, '' + + else: + print>>FILE, indent + syn_prefix(type_, group) + arguments + print>>FILE, '' + else: + if statement_var: + print>>FILE, 'endif' + print>>FILE, '' + print>>FILE, '' + # Associating Python group with Vim colour group + for statement_var, statement_parts in statements: + if statement_var: + print>>FILE, ' if exists("%s")' % statement_var + indent = ' ' + else: + indent = ' ' + for colour_group, group, type_, arguments in statement_parts: + print>>FILE, (indent + "hi def link %s %s" % + (group, colour_group)) + else: + if statement_var: + print>>FILE, ' endif' + print>>FILE, '' + # Statements at the end of the file + print>>FILE, statement_footer + +if __name__ == '__main__': + main("python.vim") diff --git a/sys/src/cmd/python/Misc/Vim/vimrc b/sys/src/cmd/python/Misc/Vim/vimrc new file mode 100644 index 000000000..af60614b1 --- /dev/null +++ b/sys/src/cmd/python/Misc/Vim/vimrc @@ -0,0 +1,95 @@ +" vimrc file for following the coding standards specified in PEP 7 & 8. +" +" To use this file, source it in your own personal .vimrc file (``source +" <filename>``) or, if you don't have a .vimrc file, you can just symlink to it +" (``ln -s <this file> ~/.vimrc``). All options are protected by autocmds +" (read below for an explanation of the command) so blind sourcing of this file +" is safe and will not affect your settings for non-Python or non-C files. +" +" +" All setting are protected by 'au' ('autocmd') statements. Only files ending +" in .py or .pyw will trigger the Python settings while files ending in *.c or +" *.h will trigger the C settings. This makes the file "safe" in terms of only +" adjusting settings for Python and C files. +" +" Only basic settings needed to enforce the style guidelines are set. +" Some suggested options are listed but commented out at the end of this file. + + +" Number of spaces to use for an indent. +" This will affect Ctrl-T and 'autoindent'. +" Python: 4 spaces +" C: tab (8 spaces) +au BufRead,BufNewFile *.py,*pyw set shiftwidth=4 +au BufRead,BufNewFile *.c,*.h set shiftwidth=4 + +" Number of spaces that a pre-existing tab is equal to. +" For the amount of space used for a new tab use shiftwidth. +" Python: 8 +" C: 8 +au BufRead,BufNewFile *py,*pyw,*.c,*.h set tabstop=8 + +" Replace tabs with the equivalent number of spaces. +" Also have an autocmd for Makefiles since they require hard tabs. +" Python: yes +" C: no +" Makefile: no +au BufRead,BufNewFile *.py,*.pyw set expandtab +au BufRead,BufNewFile *.c,*.h set noexpandtab +au BufRead,BufNewFile Makefile* set noexpandtab + +" Use the below highlight group when displaying bad whitespace is desired +highlight BadWhitespace ctermbg=red guibg=red + +" Display tabs at the beginning of a line in Python mode as bad +au BufRead,BufNewFile *.py,*.pyw match BadWhitespace /^\t\+/ + +" Wrap text after a certain number of characters +" Python: 79 +" C: 79 +au BufRead,BufNewFile *.py,*.pyw,*.c,*.h set textwidth=79 + +" Turn off settings in 'formatoptions' relating to comment formatting. +" - c : do not automatically insert the comment leader when wrapping based on +" 'textwidth' +" - o : do not insert the comment leader when using 'o' or 'O' from command mode +" - r : do not insert the comment leader when hitting <Enter> in insert mode +" Python: not needed +" C: prevents insertion of '*' at the beginning of every line in a comment +au BufRead,BufNewFile *.c,*.h set formatoptions-=c formatoptions-=o formatoptions-=r + +" Use UNIX (\n) line endings. +" Only used for new files so as to not force existing files to change their +" line endings. +" Python: yes +" C: yes +au BufNewFile *.py,*.pyw,*.c,*.h set fileformat=unix + + +" ---------------------------------------------------------------------------- +" The following section contains suggested settings. While in no way required +" to meet coding standards, they are helpful. + +" Set the default file encoding to UTF-8: ``set encoding=utf-8`` + +" Puts a marker at the beginning of the file to differentiate between UTF and +" UCS encoding (WARNING: can trick shells into thinking a text file is actually +" a binary file when executing the text file): ``set bomb`` + +" For full syntax highlighting: +"``let python_highlight_all=1`` +"``syntax on`` + +" Automatically indent based on file type: ``filetype indent on`` +" Keep indentation level from previous line: ``set autoindent`` + +" Folding based on indentation: ``set foldmethod=indent`` + +" Make trailing whitespace explicit (left off since this will automatically +" insert the highlight or characters *as you type*, which can get annoying): +"``match BadWhitespace /\s\+$/`` +" +" or, for a non-colored, character-based solution: +" +"``set list listchars=trail:-`` + diff --git a/sys/src/cmd/python/Misc/build.sh b/sys/src/cmd/python/Misc/build.sh new file mode 100755 index 000000000..ff46bbab0 --- /dev/null +++ b/sys/src/cmd/python/Misc/build.sh @@ -0,0 +1,227 @@ +#!/bin/sh + +## Script to build and test the latest python from svn. It basically +## does this: +## svn up ; ./configure ; make ; make test ; make install ; cd Doc ; make +## +## Logs are kept and rsync'ed to the host. If there are test failure(s), +## information about the failure(s) is mailed. +## +## This script is run on the PSF's machine as user neal via crontab. +## +## Yes, this script would probably be easier in python, but then +## there's a bootstrap problem. What if Python doesn't build? +## +## This script should be fairly clean Bourne shell, ie not too many +## bash-isms. We should try to keep it portable to other Unixes. +## Even though it will probably only run on Linux. I'm sure there are +## several GNU-isms currently (date +%s and readlink). +## +## Perhaps this script should be broken up into 2 (or more) components. +## Building doc is orthogonal to the rest of the python build/test. +## + +## FIXME: we should detect test hangs (eg, if they take more than 45 minutes) + +## FIXME: we should run valgrind +## FIXME: we should run code coverage + +## Utilities invoked in this script include: +## basename, date, dirname, expr, grep, readlink, uname +## cksum, make, mutt, rsync, svn + +## remember where did we started from +DIR=`dirname $0` +if [ "$DIR" = "" ]; then + DIR="." +fi + +## make directory absolute +DIR=`readlink -f $DIR` +FULLPATHNAME="$DIR/`basename $0`" +## we want Misc/.. +DIR=`dirname $DIR` + +## Configurable options + +FAILURE_SUBJECT="Python Regression Test Failures" +#FAILURE_MAILTO="YOUR_ACCOUNT@gmail.com" +FAILURE_MAILTO="python-checkins@python.org" + +REMOTE_SYSTEM="neal@dinsdale.python.org" +REMOTE_DIR="/data/ftp.python.org/pub/docs.python.org/dev/" +RESULT_FILE="$DIR/build/index.html" +INSTALL_DIR="/tmp/python-test/local" +RSYNC_OPTS="-aC -e ssh" + +# Always run the installed version of Python. +PYTHON=$INSTALL_DIR/bin/python + +# Python options and regression test program that should always be run. +REGRTEST_ARGS="-E -tt $INSTALL_DIR/lib/python2.5/test/regrtest.py" + +REFLOG="build/reflog.txt.out" +# These tests are not stable and falsely report leaks sometimes. +# The entire leak report will be mailed if any test not in this list leaks. +# Note: test_XXX (none currently) really leak, but are disabled +# so we don't send spam. Any test which really leaks should only +# be listed here if there are also test cases under Lib/test/leakers. +LEAKY_TESTS="test_(XXX)" # Currently no tests should report spurious leaks. + +# Skip these tests altogether when looking for leaks. These tests +# do not need to be stored above in LEAKY_TESTS too. +# test_compiler almost never finishes with the same number of refs +# since it depends on other modules, skip it. +# test_logging causes hangs, skip it. +LEAKY_SKIPS="-x test_compiler test_logging" + +# Change this flag to "yes" for old releases to only update/build the docs. +BUILD_DISABLED="no" + +## utility functions +current_time() { + date +%s +} + +update_status() { + now=`current_time` + time=`expr $now - $3` + echo "<li><a href=\"$2\">$1</a> <font size=\"-1\">($time seconds)</font></li>" >> $RESULT_FILE +} + +mail_on_failure() { + if [ "$NUM_FAILURES" != "0" ]; then + mutt -s "$FAILURE_SUBJECT $1 ($NUM_FAILURES)" $FAILURE_MAILTO < $2 + fi +} + +## setup +cd $DIR +mkdir -p build +rm -f $RESULT_FILE build/*.out +rm -rf $INSTALL_DIR + +## create results file +TITLE="Automated Python Build Results" +echo "<html>" >> $RESULT_FILE +echo " <head>" >> $RESULT_FILE +echo " <title>$TITLE</title>" >> $RESULT_FILE +echo " <meta http-equiv=\"refresh\" content=\"43200\">" >> $RESULT_FILE +echo " </head>" >> $RESULT_FILE +echo "<body>" >> $RESULT_FILE +echo "<h2>Automated Python Build Results</h2>" >> $RESULT_FILE +echo "<table>" >> $RESULT_FILE +echo " <tr>" >> $RESULT_FILE +echo " <td>Built on:</td><td>`date`</td>" >> $RESULT_FILE +echo " </tr><tr>" >> $RESULT_FILE +echo " <td>Hostname:</td><td>`uname -n`</td>" >> $RESULT_FILE +echo " </tr><tr>" >> $RESULT_FILE +echo " <td>Platform:</td><td>`uname -srmpo`</td>" >> $RESULT_FILE +echo " </tr>" >> $RESULT_FILE +echo "</table>" >> $RESULT_FILE +echo "<ul>" >> $RESULT_FILE + +## update, build, and test +ORIG_CHECKSUM=`cksum $FULLPATHNAME` +F=svn-update.out +start=`current_time` +svn update >& build/$F +err=$? +update_status "Updating" "$F" $start +if [ $err = 0 -a "$BUILD_DISABLED" != "yes" ]; then + ## FIXME: we should check if this file has changed. + ## If it has changed, we should re-run the script to pick up changes. + if [ "$ORIG_CHECKSUM" != "$ORIG_CHECKSUM" ]; then + exec $FULLPATHNAME $@ + fi + + F=svn-stat.out + start=`current_time` + svn stat >& build/$F + ## ignore some of the diffs + NUM_DIFFS=`egrep -vc '^. (@test|db_home|Lib/test/(regrtest\.py|db_home))$' build/$F` + update_status "svn stat ($NUM_DIFFS possibly important diffs)" "$F" $start + + F=configure.out + start=`current_time` + ./configure --prefix=$INSTALL_DIR --with-pydebug >& build/$F + err=$? + update_status "Configuring" "$F" $start + if [ $err = 0 ]; then + F=make.out + start=`current_time` + make >& build/$F + err=$? + warnings=`grep warning build/$F | egrep -vc "te?mpnam(_r|)' is dangerous,"` + update_status "Building ($warnings warnings)" "$F" $start + if [ $err = 0 ]; then + ## make install + F=make-install.out + start=`current_time` + make install >& build/$F + update_status "Installing" "$F" $start + + if [ ! -x $PYTHON ]; then + ln -s ${PYTHON}2.* $PYTHON + fi + + ## make and run basic tests + F=make-test.out + start=`current_time` + $PYTHON $REGRTEST_ARGS >& build/$F + NUM_FAILURES=`grep -ic " failed:" build/$F` + update_status "Testing basics ($NUM_FAILURES failures)" "$F" $start + mail_on_failure "basics" build/$F + + F=make-test-opt.out + start=`current_time` + $PYTHON -O $REGRTEST_ARGS >& build/$F + NUM_FAILURES=`grep -ic " failed:" build/$F` + update_status "Testing opt ($NUM_FAILURES failures)" "$F" $start + mail_on_failure "opt" build/$F + + ## run the tests looking for leaks + F=make-test-refleak.out + start=`current_time` + ## ensure that the reflog exists so the grep doesn't fail + touch $REFLOG + $PYTHON $REGRTEST_ARGS -R 4:3:$REFLOG -u network $LEAKY_SKIPS >& build/$F + NUM_FAILURES=`egrep -vc "$LEAKY_TESTS" $REFLOG` + update_status "Testing refleaks ($NUM_FAILURES failures)" "$F" $start + mail_on_failure "refleak" $REFLOG + + ## now try to run all the tests + F=make-testall.out + start=`current_time` + ## skip curses when running from cron since there's no terminal + ## skip sound since it's not setup on the PSF box (/dev/dsp) + $PYTHON $REGRTEST_ARGS -uall -x test_curses test_linuxaudiodev test_ossaudiodev >& build/$F + NUM_FAILURES=`grep -ic " failed:" build/$F` + update_status "Testing all except curses and sound ($NUM_FAILURES failures)" "$F" $start + mail_on_failure "all" build/$F + fi + fi +fi + + +## make doc +cd $DIR/Doc +F="make-doc.out" +start=`current_time` +make >& ../build/$F +err=$? +update_status "Making doc" "$F" $start +if [ $err != 0 ]; then + NUM_FAILURES=1 + mail_on_failure "doc" ../build/$F +fi + +echo "</ul>" >> $RESULT_FILE +echo "</body>" >> $RESULT_FILE +echo "</html>" >> $RESULT_FILE + +## copy results +rsync $RSYNC_OPTS html/* $REMOTE_SYSTEM:$REMOTE_DIR +cd ../build +rsync $RSYNC_OPTS index.html *.out $REMOTE_SYSTEM:$REMOTE_DIR/results/ + diff --git a/sys/src/cmd/python/Misc/cheatsheet b/sys/src/cmd/python/Misc/cheatsheet new file mode 100644 index 000000000..4b145ea57 --- /dev/null +++ b/sys/src/cmd/python/Misc/cheatsheet @@ -0,0 +1,2279 @@ + Python 2.3 Quick Reference + + + 25 Jan 2003 upgraded by Raymond Hettinger for Python 2.3 + 16 May 2001 upgraded by Richard Gruet and Simon Brunning for Python 2.0 + 2000/07/18 upgraded by Richard Gruet, rgruet@intraware.com for Python 1.5.2 +from V1.3 ref +1995/10/30, by Chris Hoffmann, choffman@vicorp.com + +Based on: + Python Bestiary, Author: Ken Manheimer, ken.manheimer@nist.gov + Python manuals, Authors: Guido van Rossum and Fred Drake + What's new in Python 2.0, Authors: A.M. Kuchling and Moshe Zadka + python-mode.el, Author: Tim Peters, tim_one@email.msn.com + + and the readers of comp.lang.python + +Python's nest: http://www.python.org Developement: http:// +python.sourceforge.net/ ActivePython : http://www.ActiveState.com/ASPN/ +Python/ +newsgroup: comp.lang.python Help desk: help@python.org +Resources: http://starship.python.net/ + http://www.vex.net/parnassus/ + http://aspn.activestate.com/ASPN/Cookbook/Python +FAQ: http://www.python.org/cgi-bin/faqw.py +Full documentation: http://www.python.org/doc/ +Excellent reference books: + Python Essential Reference by David Beazley (New Riders) + Python Pocket Reference by Mark Lutz (O'Reilly) + + +Invocation Options + +python [-diOStuUvxX?] [-c command | script | - ] [args] + + Invocation Options +Option Effect +-c cmd program passed in as string (terminates option list) +-d Outputs parser debugging information (also PYTHONDEBUG=x) +-E ignore environment variables (such as PYTHONPATH) +-h print this help message and exit +-i Inspect interactively after running script (also PYTHONINSPECT=x) and + force prompts, even if stdin appears not to be a terminal +-O optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x) +-OO remove doc-strings in addition to the -O optimizations +-Q arg division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew +-S Don't perform 'import site' on initialization +-t Issue warnings about inconsistent tab usage (-tt: issue errors) +-u Unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x). +-v Verbose (trace import statements) (also PYTHONVERBOSE=x) +-W arg : warning control (arg is action:message:category:module:lineno) +-x Skip first line of source, allowing use of non-unix Forms of #!cmd +-? Help! +-c Specify the command to execute (see next section). This terminates the +command option list (following options are passed as arguments to the command). + the name of a python file (.py) to execute read from stdin. +script Anything afterward is passed as options to python script or command, + not interpreted as an option to interpreter itself. +args passed to script or command (in sys.argv[1:]) + If no script or command, Python enters interactive mode. + + * Available IDEs in std distrib: IDLE (tkinter based, portable), Pythonwin + (Windows). + + + +Environment variables + + Environment variables + Variable Effect +PYTHONHOME Alternate prefix directory (or prefix;exec_prefix). The + default module search path uses prefix/lib + Augments the default search path for module files. The format + is the same as the shell's $PATH: one or more directory + pathnames separated by ':' or ';' without spaces around + (semi-)colons! +PYTHONPATH On Windows first search for Registry key HKEY_LOCAL_MACHINE\ + Software\Python\PythonCore\x.y\PythonPath (default value). You + may also define a key named after your application with a + default string value giving the root directory path of your + app. + If this is the name of a readable file, the Python commands in +PYTHONSTARTUP that file are executed before the first prompt is displayed in + interactive mode (no default). +PYTHONDEBUG If non-empty, same as -d option +PYTHONINSPECT If non-empty, same as -i option +PYTHONSUPPRESS If non-empty, same as -s option +PYTHONUNBUFFERED If non-empty, same as -u option +PYTHONVERBOSE If non-empty, same as -v option +PYTHONCASEOK If non-empty, ignore case in file/module names (imports) + + + + +Notable lexical entities + +Keywords + + and del for is raise + assert elif from lambda return + break else global not try + class except if or while + continue exec import pass yield + def finally in print + + * (list of keywords in std module: keyword) + * Illegitimate Tokens (only valid in strings): @ $ ? + * A statement must all be on a single line. To break a statement over + multiple lines use "\", as with the C preprocessor. + Exception: can always break when inside any (), [], or {} pair, or in + triple-quoted strings. + * More than one statement can appear on a line if they are separated with + semicolons (";"). + * Comments start with "#" and continue to end of line. + +Identifiers + + (letter | "_") (letter | digit | "_")* + + * Python identifiers keywords, attributes, etc. are case-sensitive. + * Special forms: _ident (not imported by 'from module import *'); __ident__ + (system defined name); + __ident (class-private name mangling) + +Strings + + "a string enclosed by double quotes" + 'another string delimited by single quotes and with a " inside' + '''a string containing embedded newlines and quote (') marks, can be + delimited with triple quotes.''' + """ may also use 3- double quotes as delimiters """ + u'a unicode string' U"Another unicode string" + r'a raw string where \ are kept (literalized): handy for regular + expressions and windows paths!' + R"another raw string" -- raw strings cannot end with a \ + ur'a unicode raw string' UR"another raw unicode" + + Use \ at end of line to continue a string on next line. + adjacent strings are concatened, e.g. 'Monty' ' Python' is the same as + 'Monty Python'. + u'hello' + ' world' --> u'hello world' (coerced to unicode) + + String Literal Escapes + + \newline Ignored (escape newline) + \\ Backslash (\) \e Escape (ESC) \v Vertical Tab (VT) + \' Single quote (') \f Formfeed (FF) \OOO char with octal value OOO + \" Double quote (") \n Linefeed (LF) + \a Bell (BEL) \r Carriage Return (CR) \xHH char with hex value HH + \b Backspace (BS) \t Horizontal Tab (TAB) + \uHHHH unicode char with hex value HHHH, can only be used in unicode string + \UHHHHHHHH unicode char with hex value HHHHHHHH, can only be used in unicode string + \AnyOtherChar is left as-is + + * NUL byte (\000) is NOT an end-of-string marker; NULs may be embedded in + strings. + * Strings (and tuples) are immutable: they cannot be modified. + +Numbers + + Decimal integer: 1234, 1234567890546378940L (or l) + Octal integer: 0177, 0177777777777777777 (begin with a 0) + Hex integer: 0xFF, 0XFFFFffffFFFFFFFFFF (begin with 0x or 0X) + Long integer (unlimited precision): 1234567890123456 + Float (double precision): 3.14e-10, .001, 10., 1E3 + Complex: 1J, 2+3J, 4+5j (ends with J or j, + separates (float) real and + imaginary parts) + +Sequences + + * String of length 0, 1, 2 (see above) + '', '1', "12", 'hello\n' + * Tuple of length 0, 1, 2, etc: + () (1,) (1,2) # parentheses are optional if len > 0 + * List of length 0, 1, 2, etc: + [] [1] [1,2] + +Indexing is 0-based. Negative indices (usually) mean count backwards from end +of sequence. + +Sequence slicing [starting-at-index : but-less-than-index]. Start defaults to +'0'; End defaults to 'sequence-length'. + +a = (0,1,2,3,4,5,6,7) + a[3] ==> 3 + a[-1] ==> 7 + a[2:4] ==> (2, 3) + a[1:] ==> (1, 2, 3, 4, 5, 6, 7) + a[:3] ==> (0, 1, 2) + a[:] ==> (0,1,2,3,4,5,6,7) # makes a copy of the sequence. + +Dictionaries (Mappings) + + {} # Zero length empty dictionary + {1 : 'first'} # Dictionary with one (key, value) pair + {1 : 'first', 'next': 'second'} + dict([('one',1),('two',2)]) # Construct a dict from an item list + dict('one'=1, 'two'=2) # Construct a dict using keyword args + dict.fromkeys(['one', 'keys']) # Construct a dict from a sequence + +Operators and their evaluation order + + Operators and their evaluation order +Highest Operator Comment + (...) [...] {...} `...` Tuple, list & dict. creation; string + conv. + s[i] s[i:j] s.attr f(...) indexing & slicing; attributes, fct + calls + +x, -x, ~x Unary operators + x**y Power + x*y x/y x%y x//y mult, division, modulo, floor division + x+y x-y addition, subtraction + x<<y x>>y Bit shifting + x&y Bitwise and + x^y Bitwise exclusive or + x|y Bitwise or + x<y x<=y x>y x>=y x==y x!=y Comparison, + x<>y identity, + x is y x is not y membership + x in s x not in s + not x boolean negation + x and y boolean and + x or y boolean or +Lowest lambda args: expr anonymous function + +Alternate names are defined in module operator (e.g. __add__ and add for +) +Most operators are overridable. + +Many binary operators also support augmented assignment: + x += 1 # Same as x = x + 1 + + +Basic Types and Their Operations + +Comparisons (defined between *any* types) + + Comparisons +Comparison Meaning Notes +< strictly less than (1) +<= less than or equal to +> strictly greater than +>= greater than or equal to +== equal to +!= or <> not equal to +is object identity (2) +is not negated object identity (2) + +Notes : + Comparison behavior can be overridden for a given class by defining special +method __cmp__. + The above comparisons return True or False which are of type bool +(a subclass of int) and behave exactly as 1 or 0 except for their type and +that they print as True or False instead of 1 or 0. + (1) X < Y < Z < W has expected meaning, unlike C + (2) Compare object identities (i.e. id(object)), not object values. + +Boolean values and operators + + Boolean values and operators + Value or Operator Returns Notes +None, numeric zeros, empty sequences and False +mappings +all other values True +not x True if x is False, else + True +x or y if x is False then y, else (1) + x +x and y if x is False then x, else (1) + y + +Notes : + Truth testing behavior can be overridden for a given class by defining +special method __nonzero__. + (1) Evaluate second arg only if necessary to determine outcome. + +None + + None is used as default return value on functions. Built-in single object + with type NoneType. + Input that evaluates to None does not print when running Python + interactively. + +Numeric types + +Floats, integers and long integers. + + Floats are implemented with C doubles. + Integers are implemented with C longs. + Long integers have unlimited size (only limit is system resources) + +Operators on all numeric types + + Operators on all numeric types + Operation Result +abs(x) the absolute value of x +int(x) x converted to integer +long(x) x converted to long integer +float(x) x converted to floating point +-x x negated ++x x unchanged +x + y the sum of x and y +x - y difference of x and y +x * y product of x and y +x / y quotient of x and y +x % y remainder of x / y +divmod(x, y) the tuple (x/y, x%y) +x ** y x to the power y (the same as pow(x, y)) + +Bit operators on integers and long integers + + Bit operators +Operation >Result +~x the bits of x inverted +x ^ y bitwise exclusive or of x and y +x & y bitwise and of x and y +x | y bitwise or of x and y +x << n x shifted left by n bits +x >> n x shifted right by n bits + +Complex Numbers + + * represented as a pair of machine-level double precision floating point + numbers. + * The real and imaginary value of a complex number z can be retrieved through + the attributes z.real and z.imag. + +Numeric exceptions + +TypeError + raised on application of arithmetic operation to non-number +OverflowError + numeric bounds exceeded +ZeroDivisionError + raised when zero second argument of div or modulo op +FloatingPointError + raised when a floating point operation fails + +Operations on all sequence types (lists, tuples, strings) + + Operations on all sequence types +Operation Result Notes +x in s True if an item of s is equal to x, else False +x not in s False if an item of s is equal to x, else True +for x in s: loops over the sequence +s + t the concatenation of s and t +s * n, n*s n copies of s concatenated +s[i] i'th item of s, origin 0 (1) +s[i:j] slice of s from i (included) to j (excluded) (1), (2) +len(s) length of s +min(s) smallest item of s +max(s) largest item of (s) +iter(s) returns an iterator over s. iterators define __iter__ and next() + +Notes : + (1) if i or j is negative, the index is relative to the end of the string, +ie len(s)+ i or len(s)+j is + substituted. But note that -0 is still 0. + (2) The slice of s from i to j is defined as the sequence of items with +index k such that i <= k < j. + If i or j is greater than len(s), use len(s). If i is omitted, use +len(s). If i is greater than or + equal to j, the slice is empty. + +Operations on mutable (=modifiable) sequences (lists) + + Operations on mutable sequences + Operation Result Notes +s[i] =x item i of s is replaced by x +s[i:j] = t slice of s from i to j is replaced by t +del s[i:j] same as s[i:j] = [] +s.append(x) same as s[len(s) : len(s)] = [x] +s.count(x) return number of i's for which s[i] == x +s.extend(x) same as s[len(s):len(s)]= x +s.index(x) return smallest i such that s[i] == x (1) +s.insert(i, x) same as s[i:i] = [x] if i >= 0 +s.pop([i]) same as x = s[i]; del s[i]; return x (4) +s.remove(x) same as del s[s.index(x)] (1) +s.reverse() reverse the items of s in place (3) +s.sort([cmpFct]) sort the items of s in place (2), (3) + +Notes : + (1) raise a ValueError exception when x is not found in s (i.e. out of +range). + (2) The sort() method takes an optional argument specifying a comparison +fct of 2 arguments (list items) which should + return -1, 0, or 1 depending on whether the 1st argument is +considered smaller than, equal to, or larger than the 2nd + argument. Note that this slows the sorting process down considerably. + (3) The sort() and reverse() methods modify the list in place for economy +of space when sorting or reversing a large list. + They don't return the sorted or reversed list to remind you of this +side effect. + (4) [New 1.5.2] The optional argument i defaults to -1, so that by default the last +item is removed and returned. + + + +Operations on mappings (dictionaries) + + Operations on mappings + Operation Result Notes +len(d) the number of items in d +d[k] the item of d with key k (1) +d[k] = x set d[k] to x +del d[k] remove d[k] from d (1) +d.clear() remove all items from d +d.copy() a shallow copy of d +d.get(k,defaultval) the item of d with key k (4) +d.has_key(k) True if d has key k, else False +d.items() a copy of d's list of (key, item) pairs (2) +d.iteritems() an iterator over (key, value) pairs (7) +d.iterkeys() an iterator over the keys of d (7) +d.itervalues() an iterator over the values of d (7) +d.keys() a copy of d's list of keys (2) +d1.update(d2) for k, v in d2.items(): d1[k] = v (3) +d.values() a copy of d's list of values (2) +d.pop(k) remove d[k] and return its value +d.popitem() remove and return an arbitrary (6) + (key, item) pair +d.setdefault(k,defaultval) the item of d with key k (5) + + Notes : + TypeError is raised if key is not acceptable + (1) KeyError is raised if key k is not in the map + (2) Keys and values are listed in random order + (3) d2 must be of the same type as d1 + (4) Never raises an exception if k is not in the map, instead it returns + defaultVal. + defaultVal is optional, when not provided and k is not in the map, + None is returned. + (5) Never raises an exception if k is not in the map, instead it returns + defaultVal, and adds k to map with value defaultVal. defaultVal is + optional. When not provided and k is not in the map, None is returned and + added to map. + (6) Raises a KeyError if the dictionary is emtpy. + (7) While iterating over a dictionary, the values may be updated but + the keys cannot be changed. + +Operations on strings + +Note that these string methods largely (but not completely) supersede the +functions available in the string module. + + + Operations on strings + Operation Result Notes +s.capitalize() return a copy of s with only its first character + capitalized. +s.center(width) return a copy of s centered in a string of length width (1) + . +s.count(sub[ return the number of occurrences of substring sub in (2) +,start[,end]]) string s. +s.decode(([ return a decoded version of s. (3) + encoding + [,errors]]) +s.encode([ return an encoded version of s. Default encoding is the + encoding current default string encoding. (3) + [,errors]]) +s.endswith(suffix return true if s ends with the specified suffix, (2) + [,start[,end]]) otherwise return False. +s.expandtabs([ return a copy of s where all tab characters are (4) +tabsize]) expanded using spaces. +s.find(sub[,start return the lowest index in s where substring sub is (2) +[,end]]) found. Return -1 if sub is not found. +s.index(sub[ like find(), but raise ValueError when the substring is (2) +,start[,end]]) not found. +s.isalnum() return True if all characters in s are alphanumeric, (5) + False otherwise. +s.isalpha() return True if all characters in s are alphabetic, (5) + False otherwise. +s.isdigit() return True if all characters in s are digit (5) + characters, False otherwise. +s.islower() return True if all characters in s are lowercase, False (6) + otherwise. +s.isspace() return True if all characters in s are whitespace (5) + characters, False otherwise. +s.istitle() return True if string s is a titlecased string, False (7) + otherwise. +s.isupper() return True if all characters in s are uppercase, False (6) + otherwise. +s.join(seq) return a concatenation of the strings in the sequence + seq, seperated by 's's. +s.ljust(width) return s left justified in a string of length width. (1), + (8) +s.lower() return a copy of s converted to lowercase. +s.lstrip() return a copy of s with leading whitespace removed. +s.replace(old, return a copy of s with all occurrences of substring (9) +new[, maxsplit]) old replaced by new. +s.rfind(sub[ return the highest index in s where substring sub is (2) +,start[,end]]) found. Return -1 if sub is not found. +s.rindex(sub[ like rfind(), but raise ValueError when the substring (2) +,start[,end]]) is not found. +s.rjust(width) return s right justified in a string of length width. (1), + (8) +s.rstrip() return a copy of s with trailing whitespace removed. +s.split([sep[ return a list of the words in s, using sep as the (10) +,maxsplit]]) delimiter string. +s.splitlines([ return a list of the lines in s, breaking at line (11) +keepends]) boundaries. +s.startswith return true if s starts with the specified prefix, +(prefix[,start[ otherwise return false. (2) +,end]]) +s.strip() return a copy of s with leading and trailing whitespace + removed. +s.swapcase() return a copy of s with uppercase characters converted + to lowercase and vice versa. + return a titlecased copy of s, i.e. words start with +s.title() uppercase characters, all remaining cased characters + are lowercase. +s.translate(table return a copy of s mapped through translation table (12) +[,deletechars]) table. +s.upper() return a copy of s converted to uppercase. +s.zfill(width) return a string padded with zeroes on the left side and + sliding a minus sign left if necessary. never truncates. + +Notes : + (1) Padding is done using spaces. + (2) If optional argument start is supplied, substring s[start:] is +processed. If optional arguments start and end are supplied, substring s[start: +end] is processed. + (3) Optional argument errors may be given to set a different error handling +scheme. The default for errors is 'strict', meaning that encoding errors raise +a ValueError. Other possible values are 'ignore' and 'replace'. + (4) If optional argument tabsize is not given, a tab size of 8 characters +is assumed. + (5) Returns false if string s does not contain at least one character. + (6) Returns false if string s does not contain at least one cased +character. + (7) A titlecased string is a string in which uppercase characters may only +follow uncased characters and lowercase characters only cased ones. + (8) s is returned if width is less than len(s). + (9) If the optional argument maxsplit is given, only the first maxsplit +occurrences are replaced. + (10) If sep is not specified or None, any whitespace string is a separator. +If maxsplit is given, at most maxsplit splits are done. + (11) Line breaks are not included in the resulting list unless keepends is +given and true. + (12) table must be a string of length 256. All characters occurring in the +optional argument deletechars are removed prior to translation. + +String formatting with the % operator + +formatString % args--> evaluates to a string + + * formatString uses C printf format codes : %, c, s, i, d, u, o, x, X, e, E, + f, g, G, r (details below). + * Width and precision may be a * to specify that an integer argument gives + the actual width or precision. + * The flag characters -, +, blank, # and 0 are understood. (details below) + * %s will convert any type argument to string (uses str() function) + * args may be a single arg or a tuple of args + + '%s has %03d quote types.' % ('Python', 2) # => 'Python has 002 quote types.' + + * Right-hand-side can also be a mapping: + + a = '%(lang)s has %(c)03d quote types.' % {'c':2, 'lang':'Python} +(vars() function very handy to use on right-hand-side.) + + Format codes +Conversion Meaning +d Signed integer decimal. +i Signed integer decimal. +o Unsigned octal. +u Unsigned decimal. +x Unsigned hexidecimal (lowercase). +X Unsigned hexidecimal (uppercase). +e Floating point exponential format (lowercase). +E Floating point exponential format (uppercase). +f Floating point decimal format. +F Floating point decimal format. +g Same as "e" if exponent is greater than -4 or less than precision, + "f" otherwise. +G Same as "E" if exponent is greater than -4 or less than precision, + "F" otherwise. +c Single character (accepts integer or single character string). +r String (converts any python object using repr()). +s String (converts any python object using str()). +% No argument is converted, results in a "%" character in the result. + (The complete specification is %%.) + + Conversion flag characters +Flag Meaning +# The value conversion will use the ``alternate form''. +0 The conversion will be zero padded. +- The converted value is left adjusted (overrides "-"). + (a space) A blank should be left before a positive number (or empty + string) produced by a signed conversion. ++ A sign character ("+" or "-") will precede the conversion (overrides a + "space" flag). + +File Objects + +Created with built-in function open; may be created by other modules' functions +as well. + +Operators on file objects + + File operations + Operation Result +f.close() Close file f. +f.fileno() Get fileno (fd) for file f. +f.flush() Flush file f's internal buffer. +f.isatty() True if file f is connected to a tty-like dev, else False. +f.read([size]) Read at most size bytes from file f and return as a string + object. If size omitted, read to EOF. +f.readline() Read one entire line from file f. +f.readlines() Read until EOF with readline() and return list of lines read. + Set file f's position, like "stdio's fseek()". +f.seek(offset[, whence == 0 then use absolute indexing. +whence=0]) whence == 1 then offset relative to current pos. + whence == 2 then offset relative to file end. +f.tell() Return file f's current position (byte offset). +f.write(str) Write string to file f. +f.writelines(list Write list of strings to file f. +) + +File Exceptions + + EOFError + End-of-file hit when reading (may be raised many times, e.g. if f is a + tty). + IOError + Other I/O-related I/O operation failure. + OSError + OS system call failed. + + + Advanced Types + + -See manuals for more details - + + Module objects + + Class objects + + Class instance objects + + Type objects (see module: types) + + File objects (see above) + + Slice objects + + XRange objects + + Callable types: + o User-defined (written in Python): + # User-defined Function objects + # User-defined Method objects + o Built-in (written in C): + # Built-in Function objects + # Built-in Method objects + + Internal Types: + o Code objects (byte-compile executable Python code: bytecode) + o Frame objects (execution frames) + o Traceback objects (stack trace of an exception) + + + Statements + + pass -- Null statement + del name[,name]* -- Unbind name(s) from object. Object will be indirectly + (and automatically) deleted only if no longer referenced. + print [>> fileobject,] [s1 [, s2 ]* [,] + -- Writes to sys.stdout, or to fileobject if supplied. + Puts spaces between arguments. Puts newline at end + unless statement ends with comma. + Print is not required when running interactively, + simply typing an expression will print its value, + unless the value is None. + exec x [in globals [,locals]] + -- Executes x in namespaces provided. Defaults + to current namespaces. x can be a string, file + object or a function object. + callable(value,... [id=value], [*args], [**kw]) + -- Call function callable with parameters. Parameters can + be passed by name or be omitted if function + defines default values. E.g. if callable is defined as + "def callable(p1=1, p2=2)" + "callable()" <=> "callable(1, 2)" + "callable(10)" <=> "callable(10, 2)" + "callable(p2=99)" <=> "callable(1, 99)" + *args is a tuple of positional arguments. + **kw is a dictionary of keyword arguments. + + Assignment operators + + Caption + Operator Result Notes + a = b Basic assignment - assign object b to label a (1) + a += b Roughly equivalent to a = a + b (2) + a -= b Roughly equivalent to a = a - b (2) + a *= b Roughly equivalent to a = a * b (2) + a /= b Roughly equivalent to a = a / b (2) + a %= b Roughly equivalent to a = a % b (2) + a **= b Roughly equivalent to a = a ** b (2) + a &= b Roughly equivalent to a = a & b (2) + a |= b Roughly equivalent to a = a | b (2) + a ^= b Roughly equivalent to a = a ^ b (2) + a >>= b Roughly equivalent to a = a >> b (2) + a <<= b Roughly equivalent to a = a << b (2) + + Notes : + (1) Can unpack tuples, lists, and strings. + first, second = a[0:2]; [f, s] = range(2); c1,c2,c3='abc' + Tip: x,y = y,x swaps x and y. + (2) Not exactly equivalent - a is evaluated only once. Also, where + possible, operation performed in-place - a is modified rather than + replaced. + + Control Flow + + if condition: suite + [elif condition: suite]* + [else: suite] -- usual if/else_if/else statement + while condition: suite + [else: suite] + -- usual while statement. "else" suite is executed + after loop exits, unless the loop is exited with + "break" + for element in sequence: suite + [else: suite] + -- iterates over sequence, assigning each element to element. + Use built-in range function to iterate a number of times. + "else" suite executed at end unless loop exited + with "break" + break -- immediately exits "for" or "while" loop + continue -- immediately does next iteration of "for" or "while" loop + return [result] -- Exits from function (or method) and returns result (use a tuple to + return more than one value). If no result given, then returns None. + yield result -- Freezes the execution frame of a generator and returns the result + to the iterator's .next() method. Upon the next call to next(), + resumes execution at the frozen point with all of the local variables + still intact. + + Exception Statements + + assert expr[, message] + -- expr is evaluated. if false, raises exception AssertionError + with message. Inhibited if __debug__ is 0. + try: suite1 + [except [exception [, value]: suite2]+ + [else: suite3] + -- statements in suite1 are executed. If an exception occurs, look + in "except" clauses for matching <exception>. If matches or bare + "except" execute suite of that clause. If no exception happens + suite in "else" clause is executed after suite1. + If exception has a value, it is put in value. + exception can also be tuple of exceptions, e.g. + "except (KeyError, NameError), val: print val" + try: suite1 + finally: suite2 + -- statements in suite1 are executed. If no + exception, execute suite2 (even if suite1 is + exited with a "return", "break" or "continue" + statement). If exception did occur, executes + suite2 and then immediately reraises exception. + raise exception [,value [, traceback]] + -- raises exception with optional value + value. Arg traceback specifies a traceback object to + use when printing the exception's backtrace. + raise -- a raise statement without arguments re-raises + the last exception raised in the current function +An exception is either a string (object) or a class instance. + Can create a new one simply by creating a new string: + + my_exception = 'You did something wrong' + try: + if bad: + raise my_exception, bad + except my_exception, value: + print 'Oops', value + +Exception classes must be derived from the predefined class: Exception, e.g.: + class text_exception(Exception): pass + try: + if bad: + raise text_exception() + # This is a shorthand for the form + # "raise <class>, <instance>" + except Exception: + print 'Oops' + # This will be printed because + # text_exception is a subclass of Exception +When an error message is printed for an unhandled exception which is a +class, the class name is printed, then a colon and a space, and +finally the instance converted to a string using the built-in function +str(). +All built-in exception classes derives from StandardError, itself +derived from Exception. + +Name Space Statements + +[1.51: On Mac & Windows, the case of module file names must now match the case +as used + in the import statement] +Packages (>1.5): a package is a name space which maps to a directory including + module(s) and the special initialization module '__init__.py' + (possibly empty). Packages/dirs can be nested. You address a + module's symbol via '[package.[package...]module.symbol's. +import module1 [as name1] [, module2]* + -- imports modules. Members of module must be + referred to by qualifying with [package.]module name: + "import sys; print sys.argv:" + "import package1.subpackage.module; package1.subpackage.module.foo()" + module1 renamed as name1, if supplied. +from module import name1 [as othername1] [, name2]* + -- imports names from module module in current namespace. + "from sys import argv; print argv" + "from package1 import module; module.foo()" + "from package1.module import foo; foo()" + name1 renamed as othername1, if supplied. +from module import * + -- imports all names in module, except those starting with "_"; + *to be used sparsely, beware of name clashes* : + "from sys import *; print argv" + "from package.module import *; print x' + NB: "from package import *" only imports the symbols defined + in the package's __init__.py file, not those in the + template modules! +global name1 [, name2]* + -- names are from global scope (usually meaning from module) + rather than local (usually meaning only in function). + -- E.g. in fct without "global" statements, assuming + "a" is name that hasn't been used in fct or module + so far: + -Try to read from "a" -> NameError + -Try to write to "a" -> creates "a" local to fcn + -If "a" not defined in fct, but is in module, then + -Try to read from "a", gets value from module + -Try to write to "a", creates "a" local to fct + But note "a[0]=3" starts with search for "a", + will use to global "a" if no local "a". + +Function Definition + +def func_id ([param_list]): suite + -- Creates a function object & binds it to name func_id. + + param_list ::= [id [, id]*] + id ::= value | id = value | *id | **id + [Args are passed by value.Thus only args representing a mutable object + can be modified (are inout parameters). Use a tuple to return more than + one value] + +Example: + def test (p1, p2 = 1+1, *rest, **keywords): + -- Parameters with "=" have default value (v is + evaluated when function defined). + If list has "*id" then id is assigned a tuple of + all remaining args passed to function (like C vararg) + If list has "**id" then id is assigned a dictionary of + all extra arguments passed as keywords. + +Class Definition + +class <class_id> [(<super_class1> [,<super_class2>]*)]: <suite> + -- Creates a class object and assigns it name <class_id> + <suite> may contain local "defs" of class methods and + assignments to class attributes. +Example: + class my_class (class1, class_list[3]): ... + Creates a class object inheriting from both "class1" and whatever + class object "class_list[3]" evaluates to. Assigns new + class object to name "my_class". + - First arg to class methods is always instance object, called 'self' + by convention. + - Special method __init__() is called when instance is created. + - Special method __del__() called when no more reference to object. + - Create instance by "calling" class object, possibly with arg + (thus instance=apply(aClassObject, args...) creates an instance!) + - In current implementation, can't subclass off built-in + classes. But can "wrap" them, see UserDict & UserList modules, + and see __getattr__() below. +Example: + class c (c_parent): + def __init__(self, name): self.name = name + def print_name(self): print "I'm", self.name + def call_parent(self): c_parent.print_name(self) + instance = c('tom') + print instance.name + 'tom' + instance.print_name() + "I'm tom" + Call parent's super class by accessing parent's method + directly and passing "self" explicitly (see "call_parent" + in example above). + Many other special methods available for implementing + arithmetic operators, sequence, mapping indexing, etc. + +Documentation Strings + +Modules, classes and functions may be documented by placing a string literal by +itself as the first statement in the suite. The documentation can be retrieved +by getting the '__doc__' attribute from the module, class or function. +Example: + class C: + "A description of C" + def __init__(self): + "A description of the constructor" + # etc. +Then c.__doc__ == "A description of C". +Then c.__init__.__doc__ == "A description of the constructor". + +Others + +lambda [param_list]: returnedExpr + -- Creates an anonymous function. returnedExpr must be + an expression, not a statement (e.g., not "if xx:...", + "print xxx", etc.) and thus can't contain newlines. + Used mostly for filter(), map(), reduce() functions, and GUI callbacks.. +List comprehensions +result = [expression for item1 in sequence1 [if condition1] + [for item2 in sequence2 ... for itemN in sequenceN] + ] +is equivalent to: +result = [] +for item1 in sequence1: + for item2 in sequence2: + ... + for itemN in sequenceN: + if (condition1) and furthur conditions: + result.append(expression) + + + +Built-In Functions + + Built-In Functions + Function Result +__import__(name[, Imports module within the given context (see lib ref for +globals[, locals[, more details) +fromlist]]]) +abs(x) Return the absolute value of number x. +apply(f, args[, Calls func/method f with arguments args and optional +keywords]) keywords. +bool(x) Returns True when the argument x is true and False otherwise. +buffer(obj) Creates a buffer reference to an object. +callable(x) Returns True if x callable, else False. +chr(i) Returns one-character string whose ASCII code isinteger i +classmethod(f) Converts a function f, into a method with the class as the + first argument. Useful for creating alternative constructors. +cmp(x,y) Returns negative, 0, positive if x <, ==, > to y +coerce(x,y) Returns a tuple of the two numeric arguments converted to a + common type. + Compiles string into a code object.filename is used in + error message, can be any string. It isusually the file +compile(string, from which the code was read, or eg. '<string>'if not read +filename, kind) from file.kind can be 'eval' if string is a single stmt, or + 'single' which prints the output of expression statements + thatevaluate to something else than None, or be 'exec'. +complex(real[, Builds a complex object (can also be done using J or j +image]) suffix,e.g. 1+3J) +delattr(obj, name) deletes attribute named name of object obj <=> del obj.name + If no args, returns the list of names in current +dict([items]) Create a new dictionary from the specified item list. +dir([object]) localsymbol table. With a module, class or class + instanceobject as arg, returns list of names in its attr. + dict. +divmod(a,b) Returns tuple of (a/b, a%b) +enumerate(seq) Return a iterator giving: (0, seq[0]), (1, seq[1]), ... +eval(s[, globals[, Eval string s in (optional) globals, locals contexts.s must +locals]]) have no NUL's or newlines. s can also be acode object. + Example: x = 1; incr_x = eval('x + 1') +execfile(file[, Executes a file without creating a new module, unlike +globals[, locals]]) import. +file() Synonym for open(). +filter(function, Constructs a list from those elements of sequence for which +sequence) function returns true. function takes one parameter. +float(x) Converts a number or a string to floating point. +getattr(object, [<default> arg added in 1.5.2]Gets attribute called name +name[, default])) from object,e.g. getattr(x, 'f') <=> x.f). If not found, + raisesAttributeError or returns default if specified. +globals() Returns a dictionary containing current global variables. +hasattr(object, Returns true if object has attr called name. +name) +hash(object) Returns the hash value of the object (if it has one) +help(f) Display documentation on object f. +hex(x) Converts a number x to a hexadecimal string. +id(object) Returns a unique 'identity' integer for an object. +input([prompt]) Prints prompt if given. Reads input and evaluates it. + Converts a number or a string to a plain integer. Optional +int(x[, base]) base paramenter specifies base from which to convert string + values. +intern(aString) Enters aString in the table of "interned strings" + andreturns the string. Interned strings are 'immortals'. +isinstance(obj, returns true if obj is an instance of class. Ifissubclass +class) (A,B) then isinstance(x,A) => isinstance(x,B) +issubclass(class1, returns true if class1 is derived from class2 +class2) + Returns the length (the number of items) of an object +iter(collection) Returns an iterator over the collection. +len(obj) (sequence, dictionary, or instance of class implementing + __len__). +list(sequence) Converts sequence into a list. If already a list,returns a + copy of it. +locals() Returns a dictionary containing current local variables. + Converts a number or a string to a long integer. Optional +long(x[, base]) base paramenter specifies base from which to convert string + values. + Applies function to every item of list and returns a listof +map(function, list, the results. If additional arguments are passed,function +...) must take that many arguments and it is givento function on + each call. +max(seq) Returns the largest item of the non-empty sequence seq. +min(seq) Returns the smallest item of a non-empty sequence seq. +oct(x) Converts a number to an octal string. +open(filename [, Returns a new file object. First two args are same asthose +mode='r', [bufsize= for C's "stdio open" function. bufsize is 0for unbuffered, +implementation 1 for line-buffered, negative forsys-default, all else, of +dependent]]) (about) given size. +ord(c) Returns integer ASCII value of c (a string of len 1). Works + with Unicode char. +object() Create a base type. Used as a superclass for new-style objects. +open(name Open a file. + [, mode + [, buffering]]) +pow(x, y [, z]) Returns x to power y [modulo z]. See also ** operator. +property() Created a property with access controlled by functions. +range(start [,end Returns list of ints from >= start and < end.With 1 arg, +[, step]]) list from 0..arg-1With 2 args, list from start..end-1With 3 + args, list from start up to end by step +raw_input([prompt]) Prints prompt if given, then reads string from stdinput (no + trailing \n). See also input(). +reduce(f, list [, Applies the binary function f to the items oflist so as to +init]) reduce the list to a single value.If init given, it is + "prepended" to list. + Re-parses and re-initializes an already imported module. + Useful in interactive mode, if you want to reload amodule +reload(module) after fixing it. If module was syntacticallycorrect but had + an error in initialization, mustimport it one more time + before calling reload(). + Returns a string containing a printable and if possible +repr(object) evaluable representation of an object. <=> `object` + (usingbackquotes). Class redefinissable (__repr__). See + also str() +round(x, n=0) Returns the floating point value x rounded to n digitsafter + the decimal point. +setattr(object, This is the counterpart of getattr().setattr(o, 'foobar', +name, value) 3) <=> o.foobar = 3Creates attribute if it doesn't exist! +slice([start,] stop Returns a slice object representing a range, with R/ +[, step]) Oattributes: start, stop, step. + Returns a string containing a nicely +staticmethod() Convert a function to method with no self or class + argument. Useful for methods associated with a class that + do not need access to an object's internal state. +str(object) printablerepresentation of an object. Class overridable + (__str__).See also repr(). +super(type) Create an unbound super object. Used to call cooperative + superclass methods. +sum(sequence, Add the values in the sequence and return the sum. + [start]) +tuple(sequence) Creates a tuple with same elements as sequence. If already + a tuple, return itself (not a copy). + Returns a type object [see module types] representing + thetype of obj. Example: import typesif type(x) == +type(obj) types.StringType: print 'It is a string'NB: it is + recommanded to use the following form:if isinstance(x, + types.StringType): etc... +unichr(code) code. +unicode(string[, Creates a Unicode string from a 8-bit string, using +encoding[, error thegiven encoding name and error treatment ('strict', +]]]) 'ignore',or 'replace'}. + Without arguments, returns a dictionary correspondingto the + current local symbol table. With a module,class or class +vars([object]) instance object as argumentreturns a dictionary + corresponding to the object'ssymbol table. Useful with "%" + formatting operator. +xrange(start [, end Like range(), but doesn't actually store entire listall at +[, step]]) once. Good to use in "for" loops when there is abig range + and little memory. +zip(seq1[, seq2, Returns a list of tuples where each tuple contains the nth +...]) element of each of the argument sequences. + + + + +Built-In Exceptions + +Exception> + Root class for all exceptions + SystemExit + On 'sys.exit()' + StopIteration + Signal the end from iterator.next() + StandardError + Base class for all built-in exceptions; derived from Exception + root class. + ArithmeticError + Base class for OverflowError, ZeroDivisionError, + FloatingPointError + FloatingPointError + When a floating point operation fails. + OverflowError + On excessively large arithmetic operation + ZeroDivisionError + On division or modulo operation with 0 as 2nd arg + AssertionError + When an assert statement fails. + AttributeError + On attribute reference or assignment failure + EnvironmentError [new in 1.5.2] + On error outside Python; error arg tuple is (errno, errMsg...) + IOError [changed in 1.5.2] + I/O-related operation failure + OSError [new in 1.5.2] + used by the os module's os.error exception. + EOFError + Immediate end-of-file hit by input() or raw_input() + ImportError + On failure of `import' to find module or name + KeyboardInterrupt + On user entry of the interrupt key (often `Control-C') + LookupError + base class for IndexError, KeyError + IndexError + On out-of-range sequence subscript + KeyError + On reference to a non-existent mapping (dict) key + MemoryError + On recoverable memory exhaustion + NameError + On failure to find a local or global (unqualified) name + RuntimeError + Obsolete catch-all; define a suitable error instead + NotImplementedError [new in 1.5.2] + On method not implemented + SyntaxError + On parser encountering a syntax error + IndentationError + On parser encountering an indentation syntax error + TabError + On parser encountering an indentation syntax error + SystemError + On non-fatal interpreter error - bug - report it + TypeError + On passing inappropriate type to built-in op or func + ValueError + On arg error not covered by TypeError or more precise + Warning + UserWarning + DeprecationWarning + PendingDeprecationWarning + SyntaxWarning + RuntimeWarning + FutureWarning + + + +Standard methods & operators redefinition in classes + +Standard methods & operators map to special '__methods__' and thus may be + redefined (mostly in in user-defined classes), e.g.: + class x: + def __init__(self, v): self.value = v + def __add__(self, r): return self.value + r + a = x(3) # sort of like calling x.__init__(a, 3) + a + 4 # is equivalent to a.__add__(4) + +Special methods for any class + +(s: self, o: other) + __init__(s, args) instance initialization (on construction) + __del__(s) called on object demise (refcount becomes 0) + __repr__(s) repr() and `...` conversions + __str__(s) str() and 'print' statement + __cmp__(s, o) Compares s to o and returns <0, 0, or >0. + Implements >, <, == etc... + __hash__(s) Compute a 32 bit hash code; hash() and dictionary ops + __nonzero__(s) Returns False or True for truth value testing + __getattr__(s, name) called when attr lookup doesn't find <name> + __setattr__(s, name, val) called when setting an attr + (inside, don't use "self.name = value" + use "self.__dict__[name] = val") + __delattr__(s, name) called to delete attr <name> + __call__(self, *args) called when an instance is called as function. + +Operators + + See list in the operator module. Operator function names are provided with + 2 variants, with or without + ading & trailing '__' (eg. __add__ or add). + + Numeric operations special methods + (s: self, o: other) + + s+o = __add__(s,o) s-o = __sub__(s,o) + s*o = __mul__(s,o) s/o = __div__(s,o) + s%o = __mod__(s,o) divmod(s,o) = __divmod__(s,o) + s**o = __pow__(s,o) + s&o = __and__(s,o) + s^o = __xor__(s,o) s|o = __or__(s,o) + s<<o = __lshift__(s,o) s>>o = __rshift__(s,o) + nonzero(s) = __nonzero__(s) (used in boolean testing) + -s = __neg__(s) +s = __pos__(s) + abs(s) = __abs__(s) ~s = __invert__(s) (bitwise) + s+=o = __iadd__(s,o) s-=o = __isub__(s,o) + s*=o = __imul__(s,o) s/=o = __idiv__(s,o) + s%=o = __imod__(s,o) + s**=o = __ipow__(s,o) + s&=o = __iand__(s,o) + s^=o = __ixor__(s,o) s|=o = __ior__(s,o) + s<<=o = __ilshift__(s,o) s>>=o = __irshift__(s,o) + Conversions + int(s) = __int__(s) long(s) = __long__(s) + float(s) = __float__(s) complex(s) = __complex__(s) + oct(s) = __oct__(s) hex(s) = __hex__(s) + coerce(s,o) = __coerce__(s,o) + Right-hand-side equivalents for all binary operators exist; + are called when class instance is on r-h-s of operator: + a + 3 calls __add__(a, 3) + 3 + a calls __radd__(a, 3) + + All seqs and maps, general operations plus: + (s: self, i: index or key) + + len(s) = __len__(s) length of object, >= 0. Length 0 == false + s[i] = __getitem__(s,i) Element at index/key i, origin 0 + + Sequences, general methods, plus: + s[i]=v = __setitem__(s,i,v) + del s[i] = __delitem__(s,i) + s[i:j] = __getslice__(s,i,j) + s[i:j]=seq = __setslice__(s,i,j,seq) + del s[i:j] = __delslice__(s,i,j) == s[i:j] = [] + seq * n = __repeat__(seq, n) + s1 + s2 = __concat__(s1, s2) + i in s = __contains__(s, i) + Mappings, general methods, plus + hash(s) = __hash__(s) - hash value for dictionary references + s[k]=v = __setitem__(s,k,v) + del s[k] = __delitem__(s,k) + +Special informative state attributes for some types: + + Modules: + __doc__ (string/None, R/O): doc string (<=> __dict__['__doc__']) + __name__(string, R/O): module name (also in __dict__['__name__']) + __dict__ (dict, R/O): module's name space + __file__(string/undefined, R/O): pathname of .pyc, .pyo or .pyd (undef for + modules statically linked to the interpreter) + + Classes: [in bold: writable since 1.5.2] + __doc__ (string/None, R/W): doc string (<=> __dict__['__doc__']) + __module__ is the module name in which the class was defined + __name__(string, R/W): class name (also in __dict__['__name__']) + __bases__ (tuple, R/W): parent classes + __dict__ (dict, R/W): attributes (class name space) + + Instances: + __class__ (class, R/W): instance's class + __dict__ (dict, R/W): attributes + + User-defined functions: [bold: writable since 1.5.2] + __doc__ (string/None, R/W): doc string + __name__(string, R/O): function name + func_doc (R/W): same as __doc__ + func_name (R/O): same as __name__ + func_defaults (tuple/None, R/W): default args values if any + func_code (code, R/W): code object representing the compiled function body + func_globals (dict, R/O): ref to dictionary of func global variables + func_dict (dict, R/W): same as __dict__ contains the namespace supporting + arbitrary function attributes + func_closure (R/O): None or a tuple of cells that contain bindings + for the function's free variables. + + + User-defined Methods: + __doc__ (string/None, R/O): doc string + __name__(string, R/O): method name (same as im_func.__name__) + im_class (class, R/O): class defining the method (may be a base class) + im_self (instance/None, R/O): target instance object (None if unbound) + im_func (function, R/O): function object + + Built-in Functions & methods: + __doc__ (string/None, R/O): doc string + __name__ (string, R/O): function name + __self__ : [methods only] target object + + Codes: + co_name (string, R/O): function name + co_argcount (int, R/0): number of positional args + co_nlocals (int, R/O): number of local vars (including args) + co_varnames (tuple, R/O): names of local vars (starting with args) + co_cellvars (tuple, R/O)) the names of local variables referenced by + nested functions + co_freevars (tuple, R/O)) names of free variables + co_code (string, R/O): sequence of bytecode instructions + co_consts (tuple, R/O): litterals used by the bytecode, 1st one is + fct doc (or None) + co_names (tuple, R/O): names used by the bytecode + co_filename (string, R/O): filename from which the code was compiled + co_firstlineno (int, R/O): first line number of the function + co_lnotab (string, R/O): string encoding bytecode offsets to line numbers. + co_stacksize (int, R/O): required stack size (including local vars) + co_flags (int, R/O): flags for the interpreter + bit 2 set if fct uses "*arg" syntax + bit 3 set if fct uses '**keywords' syntax + Frames: + f_back (frame/None, R/O): previous stack frame (toward the caller) + f_code (code, R/O): code object being executed in this frame + f_locals (dict, R/O): local vars + f_globals (dict, R/O): global vars + f_builtins (dict, R/O): built-in (intrinsic) names + f_restricted (int, R/O): flag indicating whether fct is executed in + restricted mode + f_lineno (int, R/O): current line number + f_lasti (int, R/O): precise instruction (index into bytecode) + f_trace (function/None, R/W): debug hook called at start of each source line + f_exc_type (Type/None, R/W): Most recent exception type + f_exc_value (any, R/W): Most recent exception value + f_exc_traceback (traceback/None, R/W): Most recent exception traceback + Tracebacks: + tb_next (frame/None, R/O): next level in stack trace (toward the frame where + the exception occurred) + tb_frame (frame, R/O): execution frame of the current level + tb_lineno (int, R/O): line number where the exception occurred + tb_lasti (int, R/O): precise instruction (index into bytecode) + + Slices: + start (any/None, R/O): lowerbound + stop (any/None, R/O): upperbound + step (any/None, R/O): step value + + Complex numbers: + real (float, R/O): real part + imag (float, R/O): imaginary part + + +Important Modules + + sys + + Some sys variables + Variable Content +argv The list of command line arguments passed to aPython + script. sys.argv[0] is the script name. +builtin_module_names A list of strings giving the names of all moduleswritten + in C that are linked into this interpreter. +check_interval How often to check for thread switches or signals(measured + in number of virtual machine instructions) +exc_type, exc_value, Deprecated since release 1.5. Use exc_info() instead. +exc_traceback +exitfunc User can set to a parameterless fcn. It will getcalled + before interpreter exits. +last_type, Set only when an exception not handled andinterpreter +last_value, prints an error. Used by debuggers. +last_traceback +maxint maximum positive value for integers +modules Dictionary of modules that have already been loaded. +path Search path for external modules. Can be modifiedby + program. sys.path[0] == dir of script executing +platform The current platform, e.g. "sunos5", "win32" +ps1, ps2 prompts to use in interactive mode. + File objects used for I/O. One can redirect byassigning a +stdin, stdout, new file object to them (or any object:.with a method +stderr write(string) for stdout/stderr,.with a method readline() + for stdin) +version string containing version info about Python interpreter. + (and also: copyright, dllhandle, exec_prefix, prefix) +version_info tuple containing Python version info - (major, minor, + micro, level, serial). + + Some sys functions + Function Result +exit(n) Exits with status n. Raises SystemExit exception.(Hence can + be caught and ignored by program) +getrefcount(object Returns the reference count of the object. Generally one +) higher than you might expect, because of object arg temp + reference. +setcheckinterval( Sets the interpreter's thread switching interval (in number +interval) of virtual code instructions, default:100). +settrace(func) Sets a trace function: called before each line ofcode is + exited. +setprofile(func) Sets a profile function for performance profiling. + Info on exception currently being handled; this is atuple + (exc_type, exc_value, exc_traceback).Warning: assigning the +exc_info() traceback return value to a loca variable in a + function handling an exception will cause a circular + reference. +setdefaultencoding Change default Unicode encoding - defaults to 7-bit ASCII. +(encoding) +getrecursionlimit Retrieve maximum recursion depth. +() +setrecursionlimit Set maximum recursion depth. (Defaults to 1000.) +() + + + + os +"synonym" for whatever O/S-specific module is proper for current environment. +this module uses posix whenever possible. +(see also M.A. Lemburg's utility http://www.lemburg.com/files/python/ +platform.py) + + Some os variables + Variable Meaning +name name of O/S-specific module (e.g. "posix", "mac", "nt") +path O/S-specific module for path manipulations. + On Unix, os.path.split() <=> posixpath.split() +curdir string used to represent current directory ('.') +pardir string used to represent parent directory ('..') +sep string used to separate directories ('/' or '\'). Tip: use + os.path.join() to build portable paths. +altsep Alternate sep +if applicable (None +otherwise) +pathsep character used to separate search path components (as in + $PATH), eg. ';' for windows. +linesep line separator as used in binary files, ie '\n' on Unix, '\ + r\n' on Dos/Win, '\r' + + Some os functions + Function Result +makedirs(path[, Recursive directory creation (create required intermediary +mode=0777]) dirs); os.error if fails. +removedirs(path) Recursive directory delete (delete intermediary empty + dirs); if fails. +renames(old, new) Recursive directory or file renaming; os.error if fails. + + + + posix +don't import this module directly, import os instead ! +(see also module: shutil for file copy & remove fcts) + + posix Variables +Variable Meaning +environ dictionary of environment variables, e.g.posix.environ['HOME']. +error exception raised on POSIX-related error. + Corresponding value is tuple of errno code and perror() string. + + Some posix functions + Function Result +chdir(path) Changes current directory to path. +chmod(path, Changes the mode of path to the numeric mode +mode) +close(fd) Closes file descriptor fd opened with posix.open. +_exit(n) Immediate exit, with no cleanups, no SystemExit,etc. Should use + this to exit a child process. +execv(p, args) "Become" executable p with args args +getcwd() Returns a string representing the current working directory +getpid() Returns the current process id +fork() Like C's fork(). Returns 0 to child, child pid to parent.[Not + on Windows] +kill(pid, Like C's kill [Not on Windows] +signal) +listdir(path) Lists (base)names of entries in directory path, excluding '.' + and '..' +lseek(fd, pos, Sets current position in file fd to position pos, expressedas +how) an offset relative to beginning of file (how=0), tocurrent + position (how=1), or to end of file (how=2) +mkdir(path[, Creates a directory named path with numeric mode (default 0777) +mode]) +open(file, Like C's open(). Returns file descriptor. Use file object +flags, mode) fctsrather than this low level ones. +pipe() Creates a pipe. Returns pair of file descriptors (r, w) [Not on + Windows]. +popen(command, Opens a pipe to or from command. Result is a file object to +mode='r', read to orwrite from, as indicated by mode being 'r' or 'w'. +bufSize=0) Use it to catch acommand output ('r' mode) or to feed it ('w' + mode). +remove(path) See unlink. +rename(src, dst Renames/moves the file or directory src to dst. [error iftarget +) name already exists] +rmdir(path) Removes the empty directory path +read(fd, n) Reads n bytes from file descriptor fd and return as string. + Returns st_mode, st_ino, st_dev, st_nlink, st_uid,st_gid, +stat(path) st_size, st_atime, st_mtime, st_ctime.[st_ino, st_uid, st_gid + are dummy on Windows] +system(command) Executes string command in a subshell. Returns exitstatus of + subshell (usually 0 means OK). + Returns accumulated CPU times in sec (user, system, children's +times() user,children's sys, elapsed real time). [3 last not on + Windows] +unlink(path) Unlinks ("deletes") the file (not dir!) path. same as: remove +utime(path, ( Sets the access & modified time of the file to the given tuple +aTime, mTime)) of values. +wait() Waits for child process completion. Returns tuple ofpid, + exit_status [Not on Windows] +waitpid(pid, Waits for process pid to complete. Returns tuple ofpid, +options) exit_status [Not on Windows] +write(fd, str) Writes str to file fd. Returns nb of bytes written. + + + + posixpath +Do not import this module directly, import os instead and refer to this module +as os.path. (e.g. os.path.exists(p)) ! + + Some posixpath functions + Function Result +abspath(p) Returns absolute path for path p, taking current working dir in + account. +dirname/ +basename(p directory and name parts of the path p. See also split. +) +exists(p) True if string p is an existing path (file or directory) +expanduser Returns string that is (a copy of) p with "~" expansion done. +(p) +expandvars Returns string that is (a copy of) p with environment vars expanded. +(p) [Windows: case significant; must use Unix: $var notation, not %var%] +getsize( return the size in bytes of filename. raise os.error. +filename) +getmtime( return last modification time of filename (integer nb of seconds +filename) since epoch). +getatime( return last access time of filename (integer nb of seconds since +filename) epoch). +isabs(p) True if string p is an absolute path. +isdir(p) True if string p is a directory. +islink(p) True if string p is a symbolic link. +ismount(p) True if string p is a mount point [true for all dirs on Windows]. +join(p[,q Joins one or more path components intelligently. +[,...]]) + Splits p into (head, tail) where tail is lastpathname component and +split(p) <head> is everything leadingup to that. <=> (dirname(p), basename + (p)) +splitdrive Splits path p in a pair ('drive:', tail) [Windows] +(p) +splitext(p Splits into (root, ext) where last comp of root contains no periods +) and ext is empty or startswith a period. + Calls the function visit with arguments(arg, dirname, names) for + each directory recursively inthe directory tree rooted at p +walk(p, (including p itself if it's a dir)The argument dirname specifies the +visit, arg visited directory, the argumentnames lists the files in the +) directory. The visit function maymodify names to influence the set + of directories visited belowdirname, e.g., to avoid visiting certain + parts of the tree. + + + + shutil +high-level file operations (copying, deleting). + + Main shutil functions + Function Result +copy(src, dst) Copies the contents of file src to file dst, retaining file + permissions. +copytree(src, dst Recursively copies an entire directory tree rooted at src +[, symlinks]) into dst (which should not already exist). If symlinks is + true, links insrc are kept as such in dst. +rmtree(path[, Deletes an entire directory tree, ignoring errors if +ignore_errors[, ignore_errors true,or calling onerror(func, path, +onerror]]) sys.exc_info()) if supplied with + +(and also: copyfile, copymode, copystat, copy2) + +time + + Variables +Variable Meaning +altzone signed offset of local DST timezone in sec west of the 0th meridian. +daylight nonzero if a DST timezone is specified + + Functions + Function Result +time() return a float representing UTC time in seconds since the epoch. +gmtime(secs), return a tuple representing time : (year aaaa, month(1-12),day +localtime( (1-31), hour(0-23), minute(0-59), second(0-59), weekday(0-6, 0 is +secs) monday), Julian day(1-366), daylight flag(-1,0 or 1)) +asctime( +timeTuple), +strftime( +format, return a formated string representing time. +timeTuple) +mktime(tuple) inverse of localtime(). Return a float. +strptime( parse a formated string representing time, return tuple as in +string[, gmtime(). +format]) +sleep(secs) Suspend execution for <secs> seconds. <secs> can be a float. + +and also: clock, ctime. + + string + +As of Python 2.0, much (though not all) of the functionality provided by the +string module have been superseded by built-in string methods - see Operations +on strings for details. + + Some string variables + Variable Meaning +digits The string '0123456789' +hexdigits, octdigits legal hexadecimal & octal digits +letters, uppercase, lowercase, Strings containing the appropriate +whitespace characters +index_error Exception raised by index() if substr not + found. + + Some string functions + Function Result +expandtabs(s, returns a copy of string <s> with tabs expanded. +tabSize) +find/rfind(s, sub Return the lowest/highest index in <s> where the substring +[, start=0[, end= <sub> is found such that <sub> is wholly contained ins +0]) [start:end]. Return -1 if <sub> not found. +ljust/rjust/center Return a copy of string <s> left/right justified/centerd in +(s, width) afield of given width, padded with spaces. <s> is + nevertruncated. +lower/upper(s) Return a string that is (a copy of) <s> in lowercase/ + uppercase +split(s[, sep= Return a list containing the words of the string <s>,using +whitespace[, the string <sep> as a separator. +maxsplit=0]]) +join(words[, sep=' Concatenate a list or tuple of words with +']) interveningseparators; inverse of split. +replace(s, old, Returns a copy of string <s> with all occurrences of +new[, maxsplit=0] substring<old> replaced by <new>. Limits to <maxsplit> + firstsubstitutions if specified. +strip(s) Return a string that is (a copy of) <s> without leadingand + trailing whitespace. see also lstrip, rstrip. + + + + re (sre) + +Handles Unicode strings. Implemented in new module sre, re now a mere front-end +for compatibility. +Patterns are specified as strings. Tip: Use raw strings (e.g. r'\w*') to +litteralize backslashes. + + + Regular expression syntax + Form Description +. matches any character (including newline if DOTALL flag specified) +^ matches start of the string (of every line in MULTILINE mode) +$ matches end of the string (of every line in MULTILINE mode) +* 0 or more of preceding regular expression (as many as possible) ++ 1 or more of preceding regular expression (as many as possible) +? 0 or 1 occurrence of preceding regular expression +*?, +?, ?? Same as *, + and ? but matches as few characters as possible +{m,n} matches from m to n repetitions of preceding RE +{m,n}? idem, attempting to match as few repetitions as possible +[ ] defines character set: e.g. '[a-zA-Z]' to match all letters(see also + \w \S) +[^ ] defines complemented character set: matches if char is NOT in set + escapes special chars '*?+&$|()' and introduces special sequences +\ (see below). Due to Python string rules, write as '\\' orr'\' in the + pattern string. +\\ matches a litteral '\'; due to Python string rules, write as '\\\\ + 'in pattern string, or better using raw string: r'\\'. +| specifies alternative: 'foo|bar' matches 'foo' or 'bar' +(...) matches any RE inside (), and delimits a group. +(?:...) idem but doesn't delimit a group. + matches if ... matches next, but doesn't consume any of the string +(?=...) e.g. 'Isaac (?=Asimov)' matches 'Isaac' only if followed by + 'Asimov'. +(?!...) matches if ... doesn't match next. Negative of (?=...) +(?P<name matches any RE inside (), and delimits a named group. (e.g. r'(?P +>...) <id>[a-zA-Z_]\w*)' defines a group named id) +(?P=name) matches whatever text was matched by the earlier group named name. +(?#...) A comment; ignored. +(?letter) letter is one of 'i','L', 'm', 's', 'x'. Set the corresponding flags + (re.I, re.L, re.M, re.S, re.X) for the entire RE. + + Special sequences +Sequence Description +number matches content of the group of the same number; groups are numbered + starting from 1 +\A matches only at the start of the string +\b empty str at beg or end of word: '\bis\b' matches 'is', but not 'his' +\B empty str NOT at beginning or end of word +\d any decimal digit (<=> [0-9]) +\D any non-decimal digit char (<=> [^O-9]) +\s any whitespace char (<=> [ \t\n\r\f\v]) +\S any non-whitespace char (<=> [^ \t\n\r\f\v]) +\w any alphaNumeric char (depends on LOCALE flag) +\W any non-alphaNumeric char (depends on LOCALE flag) +\Z matches only at the end of the string + + Variables +Variable Meaning +error Exception when pattern string isn't a valid regexp. + + Functions + Function Result + Compile a RE pattern string into a regular expression object. + Flags (combinable by |): + + I or IGNORECASE or (?i) + case insensitive matching +compile( L or LOCALE or (?L) +pattern[, make \w, \W, \b, \B dependent on thecurrent locale +flags=0]) M or MULTILINE or (?m) + matches every new line and not onlystart/end of the whole + string + S or DOTALL or (?s) + '.' matches ALL chars, including newline + X or VERBOSE or (?x) + Ignores whitespace outside character sets +escape(string) return (a copy of) string with all non-alphanumerics + backslashed. +match(pattern, if 0 or more chars at beginning of <string> match the RE pattern +string[, flags string,return a corresponding MatchObject instance, or None if +]) no match. +search(pattern scan thru <string> for a location matching <pattern>, return +, string[, acorresponding MatchObject instance, or None if no match. +flags]) +split(pattern, split <string> by occurrences of <pattern>. If capturing () are +string[, used inpattern, then occurrences of patterns or subpatterns are +maxsplit=0]) also returned. +findall( return a list of non-overlapping matches in <pattern>, either a +pattern, list ofgroups or a list of tuples if the pattern has more than 1 +string) group. + return string obtained by replacing the (<count> first) lefmost +sub(pattern, non-overlapping occurrences of <pattern> (a string or a RE +repl, string[, object) in <string>by <repl>; <repl> can be a string or a fct +count=0]) called with a single MatchObj arg, which must return the + replacement string. +subn(pattern, +repl, string[, same as sub(), but returns a tuple (newString, numberOfSubsMade) +count=0]) + +Regular Expression Objects + + +(RE objects are returned by the compile fct) + + re object attributes +Attribute Descrition +flags flags arg used when RE obj was compiled, or 0 if none provided +groupindex dictionary of {group name: group number} in pattern +pattern pattern string from which RE obj was compiled + + re object methods + Method Result + If zero or more characters at the beginning of string match this + regular expression, return a corresponding MatchObject instance. + Return None if the string does not match the pattern; note that + this is different from a zero-length match. + The optional second parameter pos gives an index in the string +match( where the search is to start; it defaults to 0. This is not +string[, completely equivalent to slicing the string; the '' pattern +pos][, character matches at the real beginning of the string and at +endpos]) positions just after a newline, but not necessarily at the index + where the search is to start. + The optional parameter endpos limits how far the string will be + searched; it will be as if the string is endpos characters long, so + only the characters from pos to endpos will be searched for a + match. + Scan through string looking for a location where this regular +search( expression produces a match, and return a corresponding MatchObject +string[, instance. Return None if no position in the string matches the +pos][, pattern; note that this is different from finding a zero-length +endpos]) match at some point in the string. + The optional pos and endpos parameters have the same meaning as for + the match() method. +split( +string[, Identical to the split() function, using the compiled pattern. +maxsplit= +0]) +findall( Identical to the findall() function, using the compiled pattern. +string) +sub(repl, +string[, Identical to the sub() function, using the compiled pattern. +count=0]) +subn(repl, +string[, Identical to the subn() function, using the compiled pattern. +count=0]) + +Match Objects + + +(Match objects are returned by the match & search functions) + + Match object attributes +Attribute Description +pos value of pos passed to search or match functions; index intostring at + which RE engine started search. +endpos value of endpos passed to search or match functions; index intostring + beyond which RE engine won't go. +re RE object whose match or search fct produced this MatchObj instance +string string passed to match() or search() + + Match object functions +Function Result + returns one or more groups of the match. If one arg, result is a +group([g1 string;if multiple args, result is a tuple with one item per arg. If +, g2, gi is 0,return value is entire matching string; if 1 <= gi <= 99, +...]) returnstring matching group #gi (or None if no such group); gi may + also bea group name. + returns a tuple of all groups of the match; groups not +groups() participatingto the match have a value of None. Returns a string + instead of tupleif len(tuple)=1 +start( +group), returns indices of start & end of substring matched by group (or +end(group Noneif group exists but doesn't contribute to the match) +) +span( returns the 2-tuple (start(group), end(group)); can be (None, None)if +group) group didn't contibute to the match. + + + + math + +Variables: +pi +e +Functions (see ordinary C man pages for info): +acos(x) +asin(x) +atan(x) +atan2(x, y) +ceil(x) +cos(x) +cosh(x) +degrees(x) +exp(x) +fabs(x) +floor(x) +fmod(x, y) +frexp(x) -- Unlike C: (float, int) = frexp(float) +ldexp(x, y) +log(x [,base]) +log10(x) +modf(x) -- Unlike C: (float, float) = modf(float) +pow(x, y) +radians(x) +sin(x) +sinh(x) +sqrt(x) +tan(x) +tanh(x) + + getopt + +Functions: +getopt(list, optstr) -- Similar to C. <optstr> is option + letters to look for. Put ':' after letter + if option takes arg. E.g. + # invocation was "python test.py -c hi -a arg1 arg2" + opts, args = getopt.getopt(sys.argv[1:], 'ab:c:') + # opts would be + [('-c', 'hi'), ('-a', '')] + # args would be + ['arg1', 'arg2'] + + +List of modules and packages in base distribution + +(built-ins and content of python Lib directory) +(Python NT distribution, may be slightly different in other distributions) + + Standard library modules + Operation Result +aifc Stuff to parse AIFF-C and AIFF files. +anydbm Generic interface to all dbm clones. (dbhash, gdbm, + dbm,dumbdbm) +asynchat Support for 'chat' style protocols +asyncore Asynchronous File I/O (in select style) +atexit Register functions to be called at exit of Python interpreter. +audiodev Audio support for a few platforms. +base64 Conversions to/from base64 RFC-MIME transport encoding . +BaseHTTPServer Base class forhttp services. +Bastion "Bastionification" utility (control access to instance vars) +bdb A generic Python debugger base class. +binhex Macintosh binhex compression/decompression. +bisect List bisection algorithms. +bz2 Support for bz2 compression/decompression. +calendar Calendar printing functions. +cgi Wraps the WWW Forms Common Gateway Interface (CGI). +cgitb Utility for handling CGI tracebacks. +CGIHTTPServer CGI http services. +cmd A generic class to build line-oriented command interpreters. +datetime Basic date and time types. +code Utilities needed to emulate Python's interactive interpreter +codecs Lookup existing Unicode encodings and register new ones. +colorsys Conversion functions between RGB and other color systems. +commands Tools for executing UNIX commands . +compileall Force "compilation" of all .py files in a directory. +ConfigParser Configuration file parser (much like windows .ini files) +copy Generic shallow and deep copying operations. +copy_reg Helper to provide extensibility for pickle/cPickle. +csv Read and write files with comma separated values. +dbhash (g)dbm-compatible interface to bsdhash.hashopen. +dircache Sorted list of files in a dir, using a cache. +[DEL:dircmp:DEL] [DEL:Defines a class to build directory diff tools on.:DEL] +difflib Tool for creating delta between sequences. +dis Bytecode disassembler. +distutils Package installation system. +doctest Tool for running and verifying tests inside doc strings. +dospath Common operations on DOS pathnames. +dumbdbm A dumb and slow but simple dbm clone. +[DEL:dump:DEL] [DEL:Print python code that reconstructs a variable.:DEL] +email Comprehensive support for internet email. +exceptions Class based built-in exception hierarchy. +filecmp File comparison. +fileinput Helper class to quickly write a loop over all standard input + files. +[DEL:find:DEL] [DEL:Find files directory hierarchy matching a pattern.:DEL] +fnmatch Filename matching with shell patterns. +formatter A test formatter. +fpformat General floating point formatting functions. +ftplib An FTP client class. Based on RFC 959. +gc Perform garbacge collection, obtain GC debug stats, and tune + GC parameters. +getopt Standard command line processing. See also ftp:// + www.pauahtun.org/pub/getargspy.zip +getpass Utilities to get a password and/or the current user name. +glob filename globbing. +gopherlib Gopher protocol client interface. +[DEL:grep:DEL] [DEL:'grep' utilities.:DEL] +gzip Read & write gzipped files. +heapq Priority queue implemented using lists organized as heaps. +HMAC Keyed-Hashing for Message Authentication -- RFC 2104. +htmlentitydefs Proposed entity definitions for HTML. +htmllib HTML parsing utilities. +HTMLParser A parser for HTML and XHTML. +httplib HTTP client class. +ihooks Hooks into the "import" mechanism. +imaplib IMAP4 client.Based on RFC 2060. +imghdr Recognizing image files based on their first few bytes. +imputil Privides a way of writing customised import hooks. +inspect Tool for probing live Python objects. +keyword List of Python keywords. +knee A Python re-implementation of hierarchical module import. +linecache Cache lines from files. +linuxaudiodev Lunix /dev/audio support. +locale Support for number formatting using the current locale + settings. +logging Python logging facility. +macpath Pathname (or related) operations for the Macintosh. +macurl2path Mac specific module for conversion between pathnames and URLs. +mailbox A class to handle a unix-style or mmdf-style mailbox. +mailcap Mailcap file handling (RFC 1524). +mhlib MH (mailbox) interface. +mimetools Various tools used by MIME-reading or MIME-writing programs. +mimetypes Guess the MIME type of a file. +MimeWriter Generic MIME writer. +mimify Mimification and unmimification of mail messages. +mmap Interface to memory-mapped files - they behave like mutable + strings./font> +multifile Class to make multi-file messages easier to handle. +mutex Mutual exclusion -- for use with module sched. +netrc +nntplib An NNTP client class. Based on RFC 977. +ntpath Common operations on DOS pathnames. +nturl2path Mac specific module for conversion between pathnames and URLs. +optparse A comprehensive tool for processing command line options. +os Either mac, dos or posix depending system. +[DEL:packmail: [DEL:Create a self-unpacking shell archive.:DEL] +DEL] +pdb A Python debugger. +pickle Pickling (save and restore) of Python objects (a faster + Cimplementation exists in built-in module: cPickle). +pipes Conversion pipeline templates. +pkgunil Utilities for working with Python packages. +popen2 variations on pipe open. +poplib A POP3 client class. Based on the J. Myers POP3 draft. +posixfile Extended (posix) file operations. +posixpath Common operations on POSIX pathnames. +pprint Support to pretty-print lists, tuples, & dictionaries + recursively. +profile Class for profiling python code. +pstats Class for printing reports on profiled python code. +pydoc Utility for generating documentation from source files. +pty Pseudo terminal utilities. +pyexpat Interface to the Expay XML parser. +py_compile Routine to "compile" a .py file to a .pyc file. +pyclbr Parse a Python file and retrieve classes and methods. +Queue A multi-producer, multi-consumer queue. +quopri Conversions to/from quoted-printable transport encoding. +rand Don't use unless you want compatibility with C's rand(). +random Random variable generators +re Regular Expressions. +repr Redo repr() but with limits on most sizes. +rexec Restricted execution facilities ("safe" exec, eval, etc). +rfc822 RFC-822 message manipulation class. +rlcompleter Word completion for GNU readline 2.0. +robotparser Parse robots.txt files, useful for web spiders. +sched A generally useful event scheduler class. +sets Module for a set datatype. +sgmllib A parser for SGML. +shelve Manage shelves of pickled objects. +shlex Lexical analyzer class for simple shell-like syntaxes. +shutil Utility functions usable in a shell-like program. +SimpleHTTPServer Simple extension to base http class +site Append module search paths for third-party packages to + sys.path. +smtplib SMTP Client class (RFC 821) +sndhdr Several routines that help recognizing sound. +SocketServer Generic socket server classes. +stat Constants and functions for interpreting stat/lstat struct. +statcache Maintain a cache of file stats. +statvfs Constants for interpreting statvfs struct as returned by + os.statvfs()and os.fstatvfs() (if they exist). +string A collection of string operations. +StringIO File-like objects that read/write a string buffer (a fasterC + implementation exists in built-in module: cStringIO). +sunau Stuff to parse Sun and NeXT audio files. +sunaudio Interpret sun audio headers. +symbol Non-terminal symbols of Python grammar (from "graminit.h"). +tabnanny,/font> Check Python source for ambiguous indentation. +tarfile Facility for reading and writing to the *nix tarfile format. +telnetlib TELNET client class. Based on RFC 854. +tempfile Temporary file name allocation. +textwrap Object for wrapping and filling text. +threading Proposed new higher-level threading interfaces +threading_api (doc of the threading module) +toaiff Convert "arbitrary" sound files to AIFF files . +token Tokens (from "token.h"). +tokenize Compiles a regular expression that recognizes Python tokens. +traceback Format and print Python stack traces. +tty Terminal utilities. +turtle LogoMation-like turtle graphics +types Define names for all type symbols in the std interpreter. +tzparse Parse a timezone specification. +unicodedata Interface to unicode properties. +urllib Open an arbitrary URL. +urlparse Parse URLs according to latest draft of standard. +user Hook to allow user-specified customization code to run. +UserDict A wrapper to allow subclassing of built-in dict class. +UserList A wrapper to allow subclassing of built-in list class. +UserString A wrapper to allow subclassing of built-in string class. +[DEL:util:DEL] [DEL:some useful functions that don't fit elsewhere !!:DEL] +uu UUencode/UUdecode. +unittest Utilities for implementing unit testing. +wave Stuff to parse WAVE files. +weakref Tools for creating and managing weakly referenced objects. +webbrowser Platform independent URL launcher. +[DEL:whatsound: [DEL:Several routines that help recognizing sound files.:DEL] +DEL] +whichdb Guess which db package to use to open a db file. +xdrlib Implements (a subset of) Sun XDR (eXternal Data + Representation) +xmllib A parser for XML, using the derived class as static DTD. +xml.dom Classes for processing XML using the Document Object Model. +xml.sax Classes for processing XML using the SAX API. +xmlrpclib Support for remote procedure calls using XML. +zipfile Read & write PK zipped files. +[DEL:zmod:DEL] [DEL:Demonstration of abstruse mathematical concepts.:DEL] + + + +* Built-ins * + + sys Interpreter state vars and functions + __built-in__ Access to all built-in python identifiers + __main__ Scope of the interpreters main program, script or stdin + array Obj efficiently representing arrays of basic values + math Math functions of C standard + time Time-related functions (also the newer datetime module) + marshal Read and write some python values in binary format + struct Convert between python values and C structs + +* Standard * + + getopt Parse cmd line args in sys.argv. A la UNIX 'getopt'. + os A more portable interface to OS dependent functionality + re Functions useful for working with regular expressions + string Useful string and characters functions and exceptions + random Mersenne Twister pseudo-random number generator + thread Low-level primitives for working with process threads + threading idem, new recommanded interface. + +* Unix/Posix * + + dbm Interface to Unix ndbm database library + grp Interface to Unix group database + posix OS functionality standardized by C and POSIX standards + posixpath POSIX pathname functions + pwd Access to the Unix password database + select Access to Unix select multiplex file synchronization + socket Access to BSD socket interface + +* Tk User-interface Toolkit * + + tkinter Main interface to Tk + +* Multimedia * + + audioop Useful operations on sound fragments + imageop Useful operations on images + jpeg Access to jpeg image compressor and decompressor + rgbimg Access SGI imglib image files + +* Cryptographic Extensions * + + md5 Interface to RSA's MD5 message digest algorithm + sha Interface to the SHA message digest algorithm + HMAC Keyed-Hashing for Message Authentication -- RFC 2104. + +* Stdwin * Standard Window System + + stdwin Standard Window System interface + stdwinevents Stdwin event, command, and selection constants + rect Rectangle manipulation operations + +* SGI IRIX * (4 & 5) + + al SGI audio facilities + AL al constants + fl Interface to FORMS library + FL fl constants + flp Functions for form designer + fm Access to font manager library + gl Access to graphics library + GL Constants for gl + DEVICE More constants for gl + imgfile Imglib image file interface + +* Suns * + + sunaudiodev Access to sun audio interface + + +Workspace exploration and idiom hints + + dir(<module>) list functions, variables in <module> + dir() get object keys, defaults to local name space + if __name__ == '__main__': main() invoke main if running as script + map(None, lst1, lst2, ...) merge lists + b = a[:] create copy of seq structure + _ in interactive mode, is last value printed + + + + + + + +Python Mode for Emacs + +(Not revised, possibly not up to date) +Type C-c ? when in python-mode for extensive help. +INDENTATION +Primarily for entering new code: + TAB indent line appropriately + LFD insert newline, then indent + DEL reduce indentation, or delete single character +Primarily for reindenting existing code: + C-c : guess py-indent-offset from file content; change locally + C-u C-c : ditto, but change globally + C-c TAB reindent region to match its context + C-c < shift region left by py-indent-offset + C-c > shift region right by py-indent-offset +MARKING & MANIPULATING REGIONS OF CODE +C-c C-b mark block of lines +M-C-h mark smallest enclosing def +C-u M-C-h mark smallest enclosing class +C-c # comment out region of code +C-u C-c # uncomment region of code +MOVING POINT +C-c C-p move to statement preceding point +C-c C-n move to statement following point +C-c C-u move up to start of current block +M-C-a move to start of def +C-u M-C-a move to start of class +M-C-e move to end of def +C-u M-C-e move to end of class +EXECUTING PYTHON CODE +C-c C-c sends the entire buffer to the Python interpreter +C-c | sends the current region +C-c ! starts a Python interpreter window; this will be used by + subsequent C-c C-c or C-c | commands +C-c C-w runs PyChecker + +VARIABLES +py-indent-offset indentation increment +py-block-comment-prefix comment string used by py-comment-region +py-python-command shell command to invoke Python interpreter +py-scroll-process-buffer t means always scroll Python process buffer +py-temp-directory directory used for temp files (if needed) +py-beep-if-tab-change ring the bell if tab-width is changed + + +The Python Debugger + +(Not revised, possibly not up to date, see 1.5.2 Library Ref section 9.1; in 1.5.2, you may also use debugger integrated in IDLE) + +Accessing + +import pdb (it's a module written in Python) + -- defines functions : + run(statement[,globals[, locals]]) + -- execute statement string under debugger control, with optional + global & local environment. + runeval(expression[,globals[, locals]]) + -- same as run, but evaluate expression and return value. + runcall(function[, argument, ...]) + -- run function object with given arg(s) + pm() -- run postmortem on last exception (like debugging a core file) + post_mortem(t) + -- run postmortem on traceback object <t> + + -- defines class Pdb : + use Pdb to create reusable debugger objects. Object + preserves state (i.e. break points) between calls. + + runs until a breakpoint hit, exception, or end of program + If exception, variable '__exception__' holds (exception,value). + +Commands + +h, help + brief reminder of commands +b, break [<arg>] + if <arg> numeric, break at line <arg> in current file + if <arg> is function object, break on entry to fcn <arg> + if no arg, list breakpoints +cl, clear [<arg>] + if <arg> numeric, clear breakpoint at <arg> in current file + if no arg, clear all breakpoints after confirmation +w, where + print current call stack +u, up + move up one stack frame (to top-level caller) +d, down + move down one stack frame +s, step + advance one line in the program, stepping into calls +n, next + advance one line, stepping over calls +r, return + continue execution until current function returns + (return value is saved in variable "__return__", which + can be printed or manipulated from debugger) +c, continue + continue until next breakpoint +j, jump lineno + Set the next line that will be executed +a, args + print args to current function +rv, retval + prints return value from last function that returned +p, print <arg> + prints value of <arg> in current stack frame +l, list [<first> [, <last>]] + List source code for the current file. + Without arguments, list 11 lines around the current line + or continue the previous listing. + With one argument, list 11 lines starting at that line. + With two arguments, list the given range; + if the second argument is less than the first, it is a count. +whatis <arg> + prints type of <arg> +! + executes rest of line as a Python statement in the current stack frame +q quit + immediately stop execution and leave debugger +<return> + executes last command again +Any input debugger doesn't recognize as a command is assumed to be a +Python statement to execute in the current stack frame, the same way +the exclamation mark ("!") command does. + +Example + +(1394) python +Python 1.0.3 (Sep 26 1994) +Copyright 1991-1994 Stichting Mathematisch Centrum, Amsterdam +>>> import rm +>>> rm.run() +Traceback (innermost last): + File "<stdin>", line 1 + File "./rm.py", line 7 + x = div(3) + File "./rm.py", line 2 + return a / r +ZeroDivisionError: integer division or modulo +>>> import pdb +>>> pdb.pm() +> ./rm.py(2)div: return a / r +(Pdb) list + 1 def div(a): + 2 -> return a / r + 3 + 4 def run(): + 5 global r + 6 r = 0 + 7 x = div(3) + 8 print x +[EOF] +(Pdb) print r +0 +(Pdb) q +>>> pdb.runcall(rm.run) +etc. + +Quirks + +Breakpoints are stored as filename, line number tuples. If a module is reloaded +after editing, any remembered breakpoints are likely to be wrong. + +Always single-steps through top-most stack frame. That is, "c" acts like "n". + + diff --git a/sys/src/cmd/python/Misc/developers.txt b/sys/src/cmd/python/Misc/developers.txt new file mode 100644 index 000000000..c08590815 --- /dev/null +++ b/sys/src/cmd/python/Misc/developers.txt @@ -0,0 +1,141 @@ +Developer Log +============= + +This file is a running log of developers given permissions on SourceForge. + +The purpose is to provide some institutional memory of who was given access +and why. + +The first entry starts in April 2005. In keeping with the style of +Misc/NEWS, newer entries should be added to the top. Any markup should +be in the form of ReST. Entries should include the initials of the +project admin who made the change or granted access. Feel free to revise +the format to accommodate documentation needs as they arise. + + + +Permissions History +------------------- + +- 2006 Summer of Code entries: SoC developers are expected to work + primarily in nondist/sandbox or on a branch of their own, and will + have their work reviewed before changes are accepted into the trunk. + + - Matt Fleming was added on 25 May 2006 by AMK; he'll be working on + enhancing the Python debugger. + + - Jackilyn Hoxworth was added on 25 May 2006 by AMK; she'll be adding logging + to the standard library. + + - Mateusz Rukowicz was added on 30 May 2006 by AMK; he'll be + translating the decimal module into C. + +- SVN access granted to the "Need for Speed" Iceland sprint attendees, + between May 17 and 21, 2006, by Tim Peters. All work is to be done + in new sandbox projects or on new branches, with merging to the + trunk as approved: + + Andrew Dalke + Christian Tismer + Jack Diederich + John Benediktsson + Kristján V. Jónsson + Martin Blais + Richard Emslie + Richard Jones + Runar Petursson + Steve Holden + Richard M. Tew + +- Steven Bethard was given SVN access on 27 Apr 2006 by DJG, for PEP + update access. + +- Talin was given SVN access on 27 Apr 2006 by DJG, for PEP update + access. + +- George Yoshida (SF name "quiver") added to the SourceForge Python + project 14 Apr 2006, by Tim Peters, as a tracker admin. See + contemporaneous python-checkins thread with the unlikely Subject: + + r45329 - python/trunk/Doc/whatsnew/whatsnew25.tex + +- Ronald Oussoren was given SVN access on 3 Mar 2006 by NCN, for Mac + related work. + +- Bob Ippolito was given SVN access on 2 Mar 2006 by NCN, for Mac + related work. + +- Nick Coghlan requested CVS access so he could update his PEP directly. + Granted by GvR on 16 Oct 2005. + +- Added two new developers for the Summer of Code project. 8 July 2005 + by RDH. Andrew Kuchling will be mentoring Gregory K Johnson for a + project to enhance mailbox. Brett Cannon requested access for Flovis + Bruynooghe (sirolf) to work on pstats, profile, and hotshot. Both users + are expected to work primarily in nondist/sandbox and have their work + reviewed before making updates to active code. + +- Georg Brandl was given SF tracker permissions on 28 May 2005 + by RDH. Since the beginning of 2005, he has been active in discussions + on python-dev and has submitted a dozen patch reviews. The permissions + add the ability to change tracker status and to attach patches. On + 3 June 2005, this was expanded by RDH to include checkin permissions. + +- Terry Reedy was given SF tracker permissions on 7 Apr 2005 by RDH. + +- Nick Coghlan was given SF tracker permissions on 5 Apr 2005 by RDH. + For several months, he has been active in reviewing and contributing + patches. The added permissions give him greater flexibility in + working with the tracker. + +- Eric Price was made a developer on 2 May 2003 by TGP. This was + specifically to work on the new ``decimal`` package, which lived in + ``nondist/sandbox/decimal/`` at the time. + +- Eric S. Raymond was made a developer on 2 Jul 2000 by TGP, for general + library work. His request is archived here: + + http://mail.python.org/pipermail/python-dev/2000-July/005314.html + + +Permissions Dropped on Request +------------------------------ + +- Per note from Andrew Kuchling, the permissions for Gregory K Johnson + and the Summer Of Code project are no longer needed. AMK will make + any future checkins directly. 16 Oct 2005 RDH + +- Johannes Gijsbers sent a drop request. 27 July 2005 RDH + +- Flovis Bruynooghe sent a drop request. 14 July 2005 RDH + +- Paul Prescod sent a drop request. 30 Apr 2005 RDH + +- Finn Bock sent a drop request. 13 Apr 2005 RDH + +- Eric Price sent a drop request. 10 Apr 2005 RDH + +- Irmen de Jong requested dropping CVS access while keeping tracker + access. 10 Apr 2005 RDH + +- Moshe Zadka and Ken Manheimer sent drop requests. 8 Apr 2005 by RDH + +- Steve Holden, Gerhard Haring, and David Cole sent email stating that + they no longer use their access. 7 Apr 2005 RDH + + +Permissions Dropped after Loss of Contact +----------------------------------------- + +- Several unsuccessful efforts were made to contact Charles G Waldman. + Removed on 8 Apr 2005 by RDH. + + +Initials of Project Admins +-------------------------- + +GvR: Guido van Rossum +NCN: Neal Norwitz +RDH: Raymond Hettinger +TGP: Tim Peters +DJG: David Goodger diff --git a/sys/src/cmd/python/Misc/find_recursionlimit.py b/sys/src/cmd/python/Misc/find_recursionlimit.py new file mode 100644 index 000000000..e6454c9c3 --- /dev/null +++ b/sys/src/cmd/python/Misc/find_recursionlimit.py @@ -0,0 +1,87 @@ +#! /usr/bin/env python +"""Find the maximum recursion limit that prevents core dumps + +This script finds the maximum safe recursion limit on a particular +platform. If you need to change the recursion limit on your system, +this script will tell you a safe upper bound. To use the new limit, +call sys.setrecursionlimit. + +This module implements several ways to create infinite recursion in +Python. Different implementations end up pushing different numbers of +C stack frames, depending on how many calls through Python's abstract +C API occur. + +After each round of tests, it prints a message +Limit of NNNN is fine. + +It ends when Python causes a segmentation fault because the limit is +too high. On platforms like Mac and Windows, it should exit with a +MemoryError. + +NB: A program that does not use __methods__ can set a higher limit. +""" + +import sys + +class RecursiveBlowup1: + def __init__(self): + self.__init__() + +def test_init(): + return RecursiveBlowup1() + +class RecursiveBlowup2: + def __repr__(self): + return repr(self) + +def test_repr(): + return repr(RecursiveBlowup2()) + +class RecursiveBlowup4: + def __add__(self, x): + return x + self + +def test_add(): + return RecursiveBlowup4() + RecursiveBlowup4() + +class RecursiveBlowup5: + def __getattr__(self, attr): + return getattr(self, attr) + +def test_getattr(): + return RecursiveBlowup5().attr + +class RecursiveBlowup6: + def __getitem__(self, item): + return self[item - 2] + self[item - 1] + +def test_getitem(): + return RecursiveBlowup6()[5] + +def test_recurse(): + return test_recurse() + +def check_limit(n, test_func_name): + sys.setrecursionlimit(n) + if test_func_name.startswith("test_"): + print test_func_name[5:] + else: + print test_func_name + test_func = globals()[test_func_name] + try: + test_func() + except RuntimeError: + pass + else: + print "Yikes!" + +limit = 1000 +while 1: + check_limit(limit, "test_recurse") + check_limit(limit, "test_add") + check_limit(limit, "test_repr") + check_limit(limit, "test_init") + check_limit(limit, "test_getattr") + check_limit(limit, "test_getitem") + print "Limit of %d is fine" % limit + limit = limit + 100 diff --git a/sys/src/cmd/python/Misc/gdbinit b/sys/src/cmd/python/Misc/gdbinit new file mode 100644 index 000000000..f3cb2ead0 --- /dev/null +++ b/sys/src/cmd/python/Misc/gdbinit @@ -0,0 +1,140 @@ +# -*- ksh -*- +# +# If you use the GNU debugger gdb to debug the Python C runtime, you +# might find some of the following commands useful. Copy this to your +# ~/.gdbinit file and it'll get loaded into gdb automatically when you +# start it up. Then, at the gdb prompt you can do things like: +# +# (gdb) pyo apyobjectptr +# <module 'foobar' (built-in)> +# refcounts: 1 +# address : 84a7a2c +# $1 = void +# (gdb) + +# Prints a representation of the object to stderr, along with the +# number of reference counts it current has and the hex address the +# object is allocated at. The argument must be a PyObject* +define pyo +print _PyObject_Dump($arg0) +end + +# Prints a representation of the object to stderr, along with the +# number of reference counts it current has and the hex address the +# object is allocated at. The argument must be a PyGC_Head* +define pyg +print _PyGC_Dump($arg0) +end + +# print the local variables of the current frame +define pylocals + set $_i = 0 + while $_i < f->f_nlocals + if f->f_localsplus + $_i != 0 + set $_names = co->co_varnames + set $_name = PyString_AsString(PyTuple_GetItem($_names, $_i)) + printf "%s:\n", $_name + # side effect of calling _PyObject_Dump is to dump the object's + # info - assigning just prevents gdb from printing the + # NULL return value + set $_val = _PyObject_Dump(f->f_localsplus[$_i]) + end + set $_i = $_i + 1 + end +end + +# A rewrite of the Python interpreter's line number calculator in GDB's +# command language +define lineno + set $__continue = 1 + set $__co = f->f_code + set $__lasti = f->f_lasti + set $__sz = ((PyStringObject *)$__co->co_lnotab)->ob_size/2 + set $__p = (unsigned char *)((PyStringObject *)$__co->co_lnotab)->ob_sval + set $__li = $__co->co_firstlineno + set $__ad = 0 + while ($__sz-1 >= 0 && $__continue) + set $__sz = $__sz - 1 + set $__ad = $__ad + *$__p + set $__p = $__p + 1 + if ($__ad > $__lasti) + set $__continue = 0 + end + set $__li = $__li + *$__p + set $__p = $__p + 1 + end + printf "%d", $__li +end + +# print the current frame - verbose +define pyframev + pyframe + pylocals +end + +define pyframe + set $__fn = (char *)((PyStringObject *)co->co_filename)->ob_sval + set $__n = (char *)((PyStringObject *)co->co_name)->ob_sval + printf "%s (", $__fn + lineno + printf "): %s\n", $__n +### Uncomment these lines when using from within Emacs/XEmacs so it will +### automatically track/display the current Python source line +# printf "%c%c%s:", 032, 032, $__fn +# lineno +# printf ":1\n" +end + +### Use these at your own risk. It appears that a bug in gdb causes it +### to crash in certain circumstances. + +#define up +# up-silently 1 +# printframe +#end + +#define down +# down-silently 1 +# printframe +#end + +define printframe + if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx + pyframe + else + frame + end +end + +# Here's a somewhat fragile way to print the entire Python stack from gdb. +# It's fragile because the tests for the value of $pc depend on the layout +# of specific functions in the C source code. + +# Explanation of while and if tests: We want to pop up the stack until we +# land in Py_Main (this is probably an incorrect assumption in an embedded +# interpreter, but the test can be extended by an interested party). If +# Py_Main <= $pc <= Py_GetArgcArv is true, $pc is in Py_Main(), so the while +# tests succeeds as long as it's not true. In a similar fashion the if +# statement tests to see if we are in PyEval_EvalFrame(). + +# print the entire Python call stack +define pystack + while $pc < Py_Main || $pc > Py_GetArgcArgv + if $pc > PyEval_EvalFrame && $pc < PyEval_EvalCodeEx + pyframe + end + up-silently 1 + end + select-frame 0 +end + +# print the entire Python call stack - verbose mode +define pystackv + while $pc < Py_Main || $pc > Py_GetArgcArgv + if $pc > PyEval_EvalFrame && $pc < PyEval_EvalCodeEx + pyframev + end + up-silently 1 + end + select-frame 0 +end diff --git a/sys/src/cmd/python/Misc/indent.pro b/sys/src/cmd/python/Misc/indent.pro new file mode 100644 index 000000000..3efac89b7 --- /dev/null +++ b/sys/src/cmd/python/Misc/indent.pro @@ -0,0 +1,15 @@ +-sob +-nbad +-bap +-br +-nce +-ncs +-npcs +-i8 +-ip8 +-c25 +-T PyObject + + + + diff --git a/sys/src/cmd/python/Misc/pymemcompat.h b/sys/src/cmd/python/Misc/pymemcompat.h new file mode 100644 index 000000000..2757e3acd --- /dev/null +++ b/sys/src/cmd/python/Misc/pymemcompat.h @@ -0,0 +1,85 @@ +/* The idea of this file is that you bundle it with your extension, + #include it, program to Python 2.3's memory API and have your + extension build with any version of Python from 1.5.2 through to + 2.3 (and hopefully beyond). */ + +#ifndef Py_PYMEMCOMPAT_H +#define Py_PYMEMCOMPAT_H + +#include "Python.h" + +/* There are three "families" of memory API: the "raw memory", "object + memory" and "object" families. (This is ignoring the matter of the + cycle collector, about which more is said below). + + Raw Memory: + + PyMem_Malloc, PyMem_Realloc, PyMem_Free + + Object Memory: + + PyObject_Malloc, PyObject_Realloc, PyObject_Free + + Object: + + PyObject_New, PyObject_NewVar, PyObject_Del + + The raw memory and object memory allocators both mimic the + malloc/realloc/free interface from ANSI C, but the object memory + allocator can (and, since 2.3, does by default) use a different + allocation strategy biased towards lots of "small" allocations. + + The object family is used for allocating Python objects, and the + initializers take care of some basic initialization (setting the + refcount to 1 and filling out the ob_type field) as well as having + a somewhat different interface. + + Do not mix the families! E.g. do not allocate memory with + PyMem_Malloc and free it with PyObject_Free. You may get away with + it quite a lot of the time, but there *are* scenarios where this + will break. You Have Been Warned. + + Also, in many versions of Python there are an insane amount of + memory interfaces to choose from. Use the ones described above. */ + +#if PY_VERSION_HEX < 0x01060000 +/* raw memory interface already present */ + +/* there is no object memory interface in 1.5.2 */ +#define PyObject_Malloc PyMem_Malloc +#define PyObject_Realloc PyMem_Realloc +#define PyObject_Free PyMem_Free + +/* the object interface is there, but the names have changed */ +#define PyObject_New PyObject_NEW +#define PyObject_NewVar PyObject_NEW_VAR +#define PyObject_Del PyMem_Free +#endif + +/* If your object is a container you probably want to support the + cycle collector, which was new in Python 2.0. + + Unfortunately, the interface to the collector that was present in + Python 2.0 and 2.1 proved to be tricky to use, and so changed in + 2.2 -- in a way that can't easily be papered over with macros. + + This file contains macros that let you program to the 2.2 GC API. + Your module will compile against any Python since version 1.5.2, + but the type will only participate in the GC in versions 2.2 and + up. Some work is still necessary on your part to only fill out the + tp_traverse and tp_clear fields when they exist and set tp_flags + appropriately. + + It is possible to support both the 2.0 and 2.2 GC APIs, but it's + not pretty and this comment block is too narrow to contain a + desciption of what's required... */ + +#if PY_VERSION_HEX < 0x020200B1 +#define PyObject_GC_New PyObject_New +#define PyObject_GC_NewVar PyObject_NewVar +#define PyObject_GC_Del PyObject_Del +#define PyObject_GC_Track(op) +#define PyObject_GC_UnTrack(op) +#endif + +#endif /* !Py_PYMEMCOMPAT_H */ diff --git a/sys/src/cmd/python/Misc/python-config.in b/sys/src/cmd/python/Misc/python-config.in new file mode 100644 index 000000000..9ac44146d --- /dev/null +++ b/sys/src/cmd/python/Misc/python-config.in @@ -0,0 +1,53 @@ +#!@EXENAME@ + +import sys +import os +import getopt +from distutils import sysconfig + +valid_opts = ['prefix', 'exec-prefix', 'includes', 'libs', 'cflags', + 'ldflags', 'help'] + +def exit_with_usage(code=1): + print >>sys.stderr, "Usage: %s [%s]" % (sys.argv[0], + '|'.join('--'+opt for opt in valid_opts)) + sys.exit(code) + +try: + opts, args = getopt.getopt(sys.argv[1:], '', valid_opts) +except getopt.error: + exit_with_usage() + +if not opts: + exit_with_usage() + +opt = opts[0][0] + +pyver = sysconfig.get_config_var('VERSION') +getvar = sysconfig.get_config_var + +if opt == '--help': + exit_with_usage(0) + +elif opt == '--prefix': + print sysconfig.PREFIX + +elif opt == '--exec-prefix': + print sysconfig.EXEC_PREFIX + +elif opt in ('--includes', '--cflags'): + flags = ['-I' + sysconfig.get_python_inc(), + '-I' + sysconfig.get_python_inc(plat_specific=True)] + if opt == '--cflags': + flags.extend(getvar('CFLAGS').split()) + print ' '.join(flags) + +elif opt in ('--libs', '--ldflags'): + libs = getvar('LIBS').split() + getvar('SYSLIBS').split() + libs.append('-lpython'+pyver) + # add the prefix/lib/pythonX.Y/config dir, but only if there is no + # shared library in prefix/lib/. + if opt == '--ldflags' and not getvar('Py_ENABLE_SHARED'): + libs.insert(0, '-L' + getvar('LIBPL')) + print ' '.join(libs) + diff --git a/sys/src/cmd/python/Misc/python-mode.el b/sys/src/cmd/python/Misc/python-mode.el new file mode 100644 index 000000000..995d40d2b --- /dev/null +++ b/sys/src/cmd/python/Misc/python-mode.el @@ -0,0 +1,3768 @@ +;;; python-mode.el --- Major mode for editing Python programs + +;; Copyright (C) 1992,1993,1994 Tim Peters + +;; Author: 1995-2002 Barry A. Warsaw +;; 1992-1994 Tim Peters +;; Maintainer: python-mode@python.org +;; Created: Feb 1992 +;; Keywords: python languages oop + +(defconst py-version "$Revision: 34960 $" + "`python-mode' version number.") + +;; This software is provided as-is, without express or implied +;; warranty. Permission to use, copy, modify, distribute or sell this +;; software, without fee, for any purpose and by any individual or +;; organization, is hereby granted, provided that the above copyright +;; notice and this paragraph appear in all copies. + +;;; Commentary: + +;; This is a major mode for editing Python programs. It was developed +;; by Tim Peters after an original idea by Michael A. Guravage. Tim +;; subsequently left the net; in 1995, Barry Warsaw inherited the mode +;; and is the current maintainer. Tim's now back but disavows all +;; responsibility for the mode. Smart Tim :-) + +;; pdbtrack support contributed by Ken Manheimer, April 2001. + +;; Please use the SourceForge Python project to submit bugs or +;; patches: +;; +;; http://sourceforge.net/projects/python + +;; FOR MORE INFORMATION: + +;; There is some information on python-mode.el at + +;; http://www.python.org/emacs/python-mode/ +;; +;; It does contain links to other packages that you might find useful, +;; such as pdb interfaces, OO-Browser links, etc. + +;; BUG REPORTING: + +;; As mentioned above, please use the SourceForge Python project for +;; submitting bug reports or patches. The old recommendation, to use +;; C-c C-b will still work, but those reports have a higher chance of +;; getting buried in my mailbox. Please include a complete, but +;; concise code sample and a recipe for reproducing the bug. Send +;; suggestions and other comments to python-mode@python.org. + +;; When in a Python mode buffer, do a C-h m for more help. It's +;; doubtful that a texinfo manual would be very useful, but if you +;; want to contribute one, I'll certainly accept it! + +;;; Code: + +(require 'comint) +(require 'custom) +(require 'cl) +(require 'compile) + + +;; user definable variables +;; vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + +(defgroup python nil + "Support for the Python programming language, <http://www.python.org/>" + :group 'languages + :prefix "py-") + +(defcustom py-python-command "python" + "*Shell command used to start Python interpreter." + :type 'string + :group 'python) + +(defcustom py-jpython-command "jpython" + "*Shell command used to start the JPython interpreter." + :type 'string + :group 'python + :tag "JPython Command") + +(defcustom py-default-interpreter 'cpython + "*Which Python interpreter is used by default. +The value for this variable can be either `cpython' or `jpython'. + +When the value is `cpython', the variables `py-python-command' and +`py-python-command-args' are consulted to determine the interpreter +and arguments to use. + +When the value is `jpython', the variables `py-jpython-command' and +`py-jpython-command-args' are consulted to determine the interpreter +and arguments to use. + +Note that this variable is consulted only the first time that a Python +mode buffer is visited during an Emacs session. After that, use +\\[py-toggle-shells] to change the interpreter shell." + :type '(choice (const :tag "Python (a.k.a. CPython)" cpython) + (const :tag "JPython" jpython)) + :group 'python) + +(defcustom py-python-command-args '("-i") + "*List of string arguments to be used when starting a Python shell." + :type '(repeat string) + :group 'python) + +(defcustom py-jpython-command-args '("-i") + "*List of string arguments to be used when starting a JPython shell." + :type '(repeat string) + :group 'python + :tag "JPython Command Args") + +(defcustom py-indent-offset 4 + "*Amount of offset per level of indentation. +`\\[py-guess-indent-offset]' can usually guess a good value when +you're editing someone else's Python code." + :type 'integer + :group 'python) + +(defcustom py-continuation-offset 4 + "*Additional amount of offset to give for some continuation lines. +Continuation lines are those that immediately follow a backslash +terminated line. Only those continuation lines for a block opening +statement are given this extra offset." + :type 'integer + :group 'python) + +(defcustom py-smart-indentation t + "*Should `python-mode' try to automagically set some indentation variables? +When this variable is non-nil, two things happen when a buffer is set +to `python-mode': + + 1. `py-indent-offset' is guessed from existing code in the buffer. + Only guessed values between 2 and 8 are considered. If a valid + guess can't be made (perhaps because you are visiting a new + file), then the value in `py-indent-offset' is used. + + 2. `indent-tabs-mode' is turned off if `py-indent-offset' does not + equal `tab-width' (`indent-tabs-mode' is never turned on by + Python mode). This means that for newly written code, tabs are + only inserted in indentation if one tab is one indentation + level, otherwise only spaces are used. + +Note that both these settings occur *after* `python-mode-hook' is run, +so if you want to defeat the automagic configuration, you must also +set `py-smart-indentation' to nil in your `python-mode-hook'." + :type 'boolean + :group 'python) + +(defcustom py-align-multiline-strings-p t + "*Flag describing how multi-line triple quoted strings are aligned. +When this flag is non-nil, continuation lines are lined up under the +preceding line's indentation. When this flag is nil, continuation +lines are aligned to column zero." + :type '(choice (const :tag "Align under preceding line" t) + (const :tag "Align to column zero" nil)) + :group 'python) + +(defcustom py-block-comment-prefix "##" + "*String used by \\[comment-region] to comment out a block of code. +This should follow the convention for non-indenting comment lines so +that the indentation commands won't get confused (i.e., the string +should be of the form `#x...' where `x' is not a blank or a tab, and +`...' is arbitrary). However, this string should not end in whitespace." + :type 'string + :group 'python) + +(defcustom py-honor-comment-indentation t + "*Controls how comment lines influence subsequent indentation. + +When nil, all comment lines are skipped for indentation purposes, and +if possible, a faster algorithm is used (i.e. X/Emacs 19 and beyond). + +When t, lines that begin with a single `#' are a hint to subsequent +line indentation. If the previous line is such a comment line (as +opposed to one that starts with `py-block-comment-prefix'), then its +indentation is used as a hint for this line's indentation. Lines that +begin with `py-block-comment-prefix' are ignored for indentation +purposes. + +When not nil or t, comment lines that begin with a single `#' are used +as indentation hints, unless the comment character is in column zero." + :type '(choice + (const :tag "Skip all comment lines (fast)" nil) + (const :tag "Single # `sets' indentation for next line" t) + (const :tag "Single # `sets' indentation except at column zero" + other) + ) + :group 'python) + +(defcustom py-temp-directory + (let ((ok '(lambda (x) + (and x + (setq x (expand-file-name x)) ; always true + (file-directory-p x) + (file-writable-p x) + x)))) + (or (funcall ok (getenv "TMPDIR")) + (funcall ok "/usr/tmp") + (funcall ok "/tmp") + (funcall ok "/var/tmp") + (funcall ok ".") + (error + "Couldn't find a usable temp directory -- set `py-temp-directory'"))) + "*Directory used for temporary files created by a *Python* process. +By default, the first directory from this list that exists and that you +can write into: the value (if any) of the environment variable TMPDIR, +/usr/tmp, /tmp, /var/tmp, or the current directory." + :type 'string + :group 'python) + +(defcustom py-beep-if-tab-change t + "*Ring the bell if `tab-width' is changed. +If a comment of the form + + \t# vi:set tabsize=<number>: + +is found before the first code line when the file is entered, and the +current value of (the general Emacs variable) `tab-width' does not +equal <number>, `tab-width' is set to <number>, a message saying so is +displayed in the echo area, and if `py-beep-if-tab-change' is non-nil +the Emacs bell is also rung as a warning." + :type 'boolean + :group 'python) + +(defcustom py-jump-on-exception t + "*Jump to innermost exception frame in *Python Output* buffer. +When this variable is non-nil and an exception occurs when running +Python code synchronously in a subprocess, jump immediately to the +source code of the innermost traceback frame." + :type 'boolean + :group 'python) + +(defcustom py-ask-about-save t + "If not nil, ask about which buffers to save before executing some code. +Otherwise, all modified buffers are saved without asking." + :type 'boolean + :group 'python) + +(defcustom py-backspace-function 'backward-delete-char-untabify + "*Function called by `py-electric-backspace' when deleting backwards." + :type 'function + :group 'python) + +(defcustom py-delete-function 'delete-char + "*Function called by `py-electric-delete' when deleting forwards." + :type 'function + :group 'python) + +(defcustom py-imenu-show-method-args-p nil + "*Controls echoing of arguments of functions & methods in the Imenu buffer. +When non-nil, arguments are printed." + :type 'boolean + :group 'python) +(make-variable-buffer-local 'py-indent-offset) + +(defcustom py-pdbtrack-do-tracking-p t + "*Controls whether the pdbtrack feature is enabled or not. +When non-nil, pdbtrack is enabled in all comint-based buffers, +e.g. shell buffers and the *Python* buffer. When using pdb to debug a +Python program, pdbtrack notices the pdb prompt and displays the +source file and line that the program is stopped at, much the same way +as gud-mode does for debugging C programs with gdb." + :type 'boolean + :group 'python) +(make-variable-buffer-local 'py-pdbtrack-do-tracking-p) + +(defcustom py-pdbtrack-minor-mode-string " PDB" + "*String to use in the minor mode list when pdbtrack is enabled." + :type 'string + :group 'python) + +(defcustom py-import-check-point-max + 20000 + "Maximum number of characters to search for a Java-ish import statement. +When `python-mode' tries to calculate the shell to use (either a +CPython or a JPython shell), it looks at the so-called `shebang' line +-- i.e. #! line. If that's not available, it looks at some of the +file heading imports to see if they look Java-like." + :type 'integer + :group 'python + ) + +(defcustom py-jpython-packages + '("java" "javax" "org" "com") + "Imported packages that imply `jpython-mode'." + :type '(repeat string) + :group 'python) + +;; Not customizable +(defvar py-master-file nil + "If non-nil, execute the named file instead of the buffer's file. +The intent is to allow you to set this variable in the file's local +variable section, e.g.: + + # Local Variables: + # py-master-file: \"master.py\" + # End: + +so that typing \\[py-execute-buffer] in that buffer executes the named +master file instead of the buffer's file. If the file name has a +relative path, the value of variable `default-directory' for the +buffer is prepended to come up with a file name.") +(make-variable-buffer-local 'py-master-file) + +(defcustom py-pychecker-command "pychecker" + "*Shell command used to run Pychecker." + :type 'string + :group 'python + :tag "Pychecker Command") + +(defcustom py-pychecker-command-args '("--stdlib") + "*List of string arguments to be passed to pychecker." + :type '(repeat string) + :group 'python + :tag "Pychecker Command Args") + +(defvar py-shell-alist + '(("jpython" . 'jpython) + ("jython" . 'jpython) + ("python" . 'cpython)) + "*Alist of interpreters and python shells. Used by `py-choose-shell' +to select the appropriate python interpreter mode for a file.") + + +;; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +;; NO USER DEFINABLE VARIABLES BEYOND THIS POINT + +(defconst py-emacs-features + (let (features) + features) + "A list of features extant in the Emacs you are using. +There are many flavors of Emacs out there, with different levels of +support for features needed by `python-mode'.") + +;; Face for None, True, False, self, and Ellipsis +(defvar py-pseudo-keyword-face 'py-pseudo-keyword-face + "Face for pseudo keywords in Python mode, like self, True, False, Ellipsis.") +(make-face 'py-pseudo-keyword-face) + +(defun py-font-lock-mode-hook () + (or (face-differs-from-default-p 'py-pseudo-keyword-face) + (copy-face 'font-lock-keyword-face 'py-pseudo-keyword-face))) +(add-hook 'font-lock-mode-hook 'py-font-lock-mode-hook) + +(defvar python-font-lock-keywords + (let ((kw1 (mapconcat 'identity + '("and" "assert" "break" "class" + "continue" "def" "del" "elif" + "else" "except" "exec" "for" + "from" "global" "if" "import" + "in" "is" "lambda" "not" + "or" "pass" "print" "raise" + "return" "while" "yield" + ) + "\\|")) + (kw2 (mapconcat 'identity + '("else:" "except:" "finally:" "try:") + "\\|")) + (kw3 (mapconcat 'identity + '("ArithmeticError" "AssertionError" + "AttributeError" "DeprecationWarning" "EOFError" + "Ellipsis" "EnvironmentError" "Exception" "False" + "FloatingPointError" "FutureWarning" "IOError" + "ImportError" "IndentationError" "IndexError" + "KeyError" "KeyboardInterrupt" "LookupError" + "MemoryError" "NameError" "None" "NotImplemented" + "NotImplementedError" "OSError" "OverflowError" + "OverflowWarning" "PendingDeprecationWarning" + "ReferenceError" "RuntimeError" "RuntimeWarning" + "StandardError" "StopIteration" "SyntaxError" + "SyntaxWarning" "SystemError" "SystemExit" + "TabError" "True" "TypeError" "UnboundLocalError" + "UnicodeDecodeError" "UnicodeEncodeError" + "UnicodeError" "UnicodeTranslateError" + "UserWarning" "ValueError" "Warning" + "ZeroDivisionError" "__debug__" + "__import__" "__name__" "abs" "apply" "basestring" + "bool" "buffer" "callable" "chr" "classmethod" + "cmp" "coerce" "compile" "complex" "copyright" + "delattr" "dict" "dir" "divmod" + "enumerate" "eval" "execfile" "exit" "file" + "filter" "float" "getattr" "globals" "hasattr" + "hash" "hex" "id" "input" "int" "intern" + "isinstance" "issubclass" "iter" "len" "license" + "list" "locals" "long" "map" "max" "min" "object" + "oct" "open" "ord" "pow" "property" "range" + "raw_input" "reduce" "reload" "repr" "round" + "setattr" "slice" "staticmethod" "str" "sum" + "super" "tuple" "type" "unichr" "unicode" "vars" + "xrange" "zip") + "\\|")) + ) + (list + ;; keywords + (cons (concat "\\b\\(" kw1 "\\)\\b[ \n\t(]") 1) + ;; builtins when they don't appear as object attributes + (cons (concat "\\(\\b\\|[.]\\)\\(" kw3 "\\)\\b[ \n\t(]") 2) + ;; block introducing keywords with immediately following colons. + ;; Yes "except" is in both lists. + (cons (concat "\\b\\(" kw2 "\\)[ \n\t(]") 1) + ;; `as' but only in "import foo as bar" + '("[ \t]*\\(\\bfrom\\b.*\\)?\\bimport\\b.*\\b\\(as\\)\\b" . 2) + ;; classes + '("\\bclass[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)" + 1 font-lock-type-face) + ;; functions + '("\\bdef[ \t]+\\([a-zA-Z_]+[a-zA-Z0-9_]*\\)" + 1 font-lock-function-name-face) + ;; pseudo-keywords + '("\\b\\(self\\|None\\|True\\|False\\|Ellipsis\\)\\b" + 1 py-pseudo-keyword-face) + )) + "Additional expressions to highlight in Python mode.") +(put 'python-mode 'font-lock-defaults '(python-font-lock-keywords)) + +;; have to bind py-file-queue before installing the kill-emacs-hook +(defvar py-file-queue nil + "Queue of Python temp files awaiting execution. +Currently-active file is at the head of the list.") + +(defvar py-pdbtrack-is-tracking-p nil) +(defvar py-pdbtrack-last-grubbed-buffer nil + "Record of the last buffer used when the source path was invalid. + +This buffer is consulted before the buffer-list history for satisfying +`py-pdbtrack-grub-for-buffer', since it's the most often the likely +prospect as debugging continues.") +(make-variable-buffer-local 'py-pdbtrack-last-grubbed-buffer) +(defvar py-pychecker-history nil) + + + +;; Constants + +(defconst py-stringlit-re + (concat + ;; These fail if backslash-quote ends the string (not worth + ;; fixing?). They precede the short versions so that the first two + ;; quotes don't look like an empty short string. + ;; + ;; (maybe raw), long single quoted triple quoted strings (SQTQ), + ;; with potential embedded single quotes + "[rR]?'''[^']*\\(\\('[^']\\|''[^']\\)[^']*\\)*'''" + "\\|" + ;; (maybe raw), long double quoted triple quoted strings (DQTQ), + ;; with potential embedded double quotes + "[rR]?\"\"\"[^\"]*\\(\\(\"[^\"]\\|\"\"[^\"]\\)[^\"]*\\)*\"\"\"" + "\\|" + "[rR]?'\\([^'\n\\]\\|\\\\.\\)*'" ; single-quoted + "\\|" ; or + "[rR]?\"\\([^\"\n\\]\\|\\\\.\\)*\"" ; double-quoted + ) + "Regular expression matching a Python string literal.") + +(defconst py-continued-re + ;; This is tricky because a trailing backslash does not mean + ;; continuation if it's in a comment + (concat + "\\(" "[^#'\"\n\\]" "\\|" py-stringlit-re "\\)*" + "\\\\$") + "Regular expression matching Python backslash continuation lines.") + +(defconst py-blank-or-comment-re "[ \t]*\\($\\|#\\)" + "Regular expression matching a blank or comment line.") + +(defconst py-outdent-re + (concat "\\(" (mapconcat 'identity + '("else:" + "except\\(\\s +.*\\)?:" + "finally:" + "elif\\s +.*:") + "\\|") + "\\)") + "Regular expression matching statements to be dedented one level.") + +(defconst py-block-closing-keywords-re + "\\(return\\|raise\\|break\\|continue\\|pass\\)" + "Regular expression matching keywords which typically close a block.") + +(defconst py-no-outdent-re + (concat + "\\(" + (mapconcat 'identity + (list "try:" + "except\\(\\s +.*\\)?:" + "while\\s +.*:" + "for\\s +.*:" + "if\\s +.*:" + "elif\\s +.*:" + (concat py-block-closing-keywords-re "[ \t\n]") + ) + "\\|") + "\\)") + "Regular expression matching lines not to dedent after.") + +(defconst py-defun-start-re + "^\\([ \t]*\\)def[ \t]+\\([a-zA-Z_0-9]+\\)\\|\\(^[a-zA-Z_0-9]+\\)[ \t]*=" + ;; If you change this, you probably have to change py-current-defun + ;; as well. This is only used by py-current-defun to find the name + ;; for add-log.el. + "Regular expression matching a function, method, or variable assignment.") + +(defconst py-class-start-re "^class[ \t]*\\([a-zA-Z_0-9]+\\)" + ;; If you change this, you probably have to change py-current-defun + ;; as well. This is only used by py-current-defun to find the name + ;; for add-log.el. + "Regular expression for finding a class name.") + +(defconst py-traceback-line-re + "[ \t]+File \"\\([^\"]+\\)\", line \\([0-9]+\\)" + "Regular expression that describes tracebacks.") + +;; pdbtrack contants +(defconst py-pdbtrack-stack-entry-regexp +; "^> \\([^(]+\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()" + "^> \\(.*\\)(\\([0-9]+\\))\\([?a-zA-Z0-9_]+\\)()" + "Regular expression pdbtrack uses to find a stack trace entry.") + +(defconst py-pdbtrack-input-prompt "\n[(<]*pdb[>)]+ " + "Regular expression pdbtrack uses to recognize a pdb prompt.") + +(defconst py-pdbtrack-track-range 10000 + "Max number of characters from end of buffer to search for stack entry.") + + + +;; Major mode boilerplate + +;; define a mode-specific abbrev table for those who use such things +(defvar python-mode-abbrev-table nil + "Abbrev table in use in `python-mode' buffers.") +(define-abbrev-table 'python-mode-abbrev-table nil) + +(defvar python-mode-hook nil + "*Hook called by `python-mode'.") + +(defvar jpython-mode-hook nil + "*Hook called by `jpython-mode'. `jpython-mode' also calls +`python-mode-hook'.") + +(defvar py-shell-hook nil + "*Hook called by `py-shell'.") + +;; In previous version of python-mode.el, the hook was incorrectly +;; called py-mode-hook, and was not defvar'd. Deprecate its use. +(and (fboundp 'make-obsolete-variable) + (make-obsolete-variable 'py-mode-hook 'python-mode-hook)) + +(defvar py-mode-map () + "Keymap used in `python-mode' buffers.") +(if py-mode-map + nil + (setq py-mode-map (make-sparse-keymap)) + ;; electric keys + (define-key py-mode-map ":" 'py-electric-colon) + ;; indentation level modifiers + (define-key py-mode-map "\C-c\C-l" 'py-shift-region-left) + (define-key py-mode-map "\C-c\C-r" 'py-shift-region-right) + (define-key py-mode-map "\C-c<" 'py-shift-region-left) + (define-key py-mode-map "\C-c>" 'py-shift-region-right) + ;; paragraph and string filling + (define-key py-mode-map "\eq" 'py-fill-paragraph) + ;; subprocess commands + (define-key py-mode-map "\C-c\C-c" 'py-execute-buffer) + (define-key py-mode-map "\C-c\C-m" 'py-execute-import-or-reload) + (define-key py-mode-map "\C-c\C-s" 'py-execute-string) + (define-key py-mode-map "\C-c|" 'py-execute-region) + (define-key py-mode-map "\e\C-x" 'py-execute-def-or-class) + (define-key py-mode-map "\C-c!" 'py-shell) + (define-key py-mode-map "\C-c\C-t" 'py-toggle-shells) + ;; Caution! Enter here at your own risk. We are trying to support + ;; several behaviors and it gets disgusting. :-( This logic ripped + ;; largely from CC Mode. + ;; + ;; In XEmacs 19, Emacs 19, and Emacs 20, we use this to bind + ;; backwards deletion behavior to DEL, which both Delete and + ;; Backspace get translated to. There's no way to separate this + ;; behavior in a clean way, so deal with it! Besides, it's been + ;; this way since the dawn of time. + (if (not (boundp 'delete-key-deletes-forward)) + (define-key py-mode-map "\177" 'py-electric-backspace) + ;; However, XEmacs 20 actually achieved enlightenment. It is + ;; possible to sanely define both backward and forward deletion + ;; behavior under X separately (TTYs are forever beyond hope, but + ;; who cares? XEmacs 20 does the right thing with these too). + (define-key py-mode-map [delete] 'py-electric-delete) + (define-key py-mode-map [backspace] 'py-electric-backspace)) + ;; Separate M-BS from C-M-h. The former should remain + ;; backward-kill-word. + (define-key py-mode-map [(control meta h)] 'py-mark-def-or-class) + (define-key py-mode-map "\C-c\C-k" 'py-mark-block) + ;; Miscellaneous + (define-key py-mode-map "\C-c:" 'py-guess-indent-offset) + (define-key py-mode-map "\C-c\t" 'py-indent-region) + (define-key py-mode-map "\C-c\C-d" 'py-pdbtrack-toggle-stack-tracking) + (define-key py-mode-map "\C-c\C-n" 'py-next-statement) + (define-key py-mode-map "\C-c\C-p" 'py-previous-statement) + (define-key py-mode-map "\C-c\C-u" 'py-goto-block-up) + (define-key py-mode-map "\C-c#" 'py-comment-region) + (define-key py-mode-map "\C-c?" 'py-describe-mode) + (define-key py-mode-map "\C-c\C-h" 'py-help-at-point) + (define-key py-mode-map "\e\C-a" 'py-beginning-of-def-or-class) + (define-key py-mode-map "\e\C-e" 'py-end-of-def-or-class) + (define-key py-mode-map "\C-c-" 'py-up-exception) + (define-key py-mode-map "\C-c=" 'py-down-exception) + ;; stuff that is `standard' but doesn't interface well with + ;; python-mode, which forces us to rebind to special commands + (define-key py-mode-map "\C-xnd" 'py-narrow-to-defun) + ;; information + (define-key py-mode-map "\C-c\C-b" 'py-submit-bug-report) + (define-key py-mode-map "\C-c\C-v" 'py-version) + (define-key py-mode-map "\C-c\C-w" 'py-pychecker-run) + ;; shadow global bindings for newline-and-indent w/ the py- version. + ;; BAW - this is extremely bad form, but I'm not going to change it + ;; for now. + (mapcar #'(lambda (key) + (define-key py-mode-map key 'py-newline-and-indent)) + (where-is-internal 'newline-and-indent)) + ;; Force RET to be py-newline-and-indent even if it didn't get + ;; mapped by the above code. motivation: Emacs' default binding for + ;; RET is `newline' and C-j is `newline-and-indent'. Most Pythoneers + ;; expect RET to do a `py-newline-and-indent' and any Emacsers who + ;; dislike this are probably knowledgeable enough to do a rebind. + ;; However, we do *not* change C-j since many Emacsers have already + ;; swapped RET and C-j and they don't want C-j bound to `newline' to + ;; change. + (define-key py-mode-map "\C-m" 'py-newline-and-indent) + ) + +(defvar py-mode-output-map nil + "Keymap used in *Python Output* buffers.") +(if py-mode-output-map + nil + (setq py-mode-output-map (make-sparse-keymap)) + (define-key py-mode-output-map [button2] 'py-mouseto-exception) + (define-key py-mode-output-map "\C-c\C-c" 'py-goto-exception) + ;; TBD: Disable all self-inserting keys. This is bogus, we should + ;; really implement this as *Python Output* buffer being read-only + (mapcar #' (lambda (key) + (define-key py-mode-output-map key + #'(lambda () (interactive) (beep)))) + (where-is-internal 'self-insert-command)) + ) + +(defvar py-shell-map nil + "Keymap used in *Python* shell buffers.") +(if py-shell-map + nil + (setq py-shell-map (copy-keymap comint-mode-map)) + (define-key py-shell-map [tab] 'tab-to-tab-stop) + (define-key py-shell-map "\C-c-" 'py-up-exception) + (define-key py-shell-map "\C-c=" 'py-down-exception) + ) + +(defvar py-mode-syntax-table nil + "Syntax table used in `python-mode' buffers.") +(when (not py-mode-syntax-table) + (setq py-mode-syntax-table (make-syntax-table)) + (modify-syntax-entry ?\( "()" py-mode-syntax-table) + (modify-syntax-entry ?\) ")(" py-mode-syntax-table) + (modify-syntax-entry ?\[ "(]" py-mode-syntax-table) + (modify-syntax-entry ?\] ")[" py-mode-syntax-table) + (modify-syntax-entry ?\{ "(}" py-mode-syntax-table) + (modify-syntax-entry ?\} "){" py-mode-syntax-table) + ;; Add operator symbols misassigned in the std table + (modify-syntax-entry ?\$ "." py-mode-syntax-table) + (modify-syntax-entry ?\% "." py-mode-syntax-table) + (modify-syntax-entry ?\& "." py-mode-syntax-table) + (modify-syntax-entry ?\* "." py-mode-syntax-table) + (modify-syntax-entry ?\+ "." py-mode-syntax-table) + (modify-syntax-entry ?\- "." py-mode-syntax-table) + (modify-syntax-entry ?\/ "." py-mode-syntax-table) + (modify-syntax-entry ?\< "." py-mode-syntax-table) + (modify-syntax-entry ?\= "." py-mode-syntax-table) + (modify-syntax-entry ?\> "." py-mode-syntax-table) + (modify-syntax-entry ?\| "." py-mode-syntax-table) + ;; For historical reasons, underscore is word class instead of + ;; symbol class. GNU conventions say it should be symbol class, but + ;; there's a natural conflict between what major mode authors want + ;; and what users expect from `forward-word' and `backward-word'. + ;; Guido and I have hashed this out and have decided to keep + ;; underscore in word class. If you're tempted to change it, try + ;; binding M-f and M-b to py-forward-into-nomenclature and + ;; py-backward-into-nomenclature instead. This doesn't help in all + ;; situations where you'd want the different behavior + ;; (e.g. backward-kill-word). + (modify-syntax-entry ?\_ "w" py-mode-syntax-table) + ;; Both single quote and double quote are string delimiters + (modify-syntax-entry ?\' "\"" py-mode-syntax-table) + (modify-syntax-entry ?\" "\"" py-mode-syntax-table) + ;; backquote is open and close paren + (modify-syntax-entry ?\` "$" py-mode-syntax-table) + ;; comment delimiters + (modify-syntax-entry ?\# "<" py-mode-syntax-table) + (modify-syntax-entry ?\n ">" py-mode-syntax-table) + ) + +;; An auxiliary syntax table which places underscore and dot in the +;; symbol class for simplicity +(defvar py-dotted-expression-syntax-table nil + "Syntax table used to identify Python dotted expressions.") +(when (not py-dotted-expression-syntax-table) + (setq py-dotted-expression-syntax-table + (copy-syntax-table py-mode-syntax-table)) + (modify-syntax-entry ?_ "_" py-dotted-expression-syntax-table) + (modify-syntax-entry ?. "_" py-dotted-expression-syntax-table)) + + + +;; Utilities +(defmacro py-safe (&rest body) + "Safely execute BODY, return nil if an error occurred." + (` (condition-case nil + (progn (,@ body)) + (error nil)))) + +(defsubst py-keep-region-active () + "Keep the region active in XEmacs." + ;; Ignore byte-compiler warnings you might see. Also note that + ;; FSF's Emacs 19 does it differently; its policy doesn't require us + ;; to take explicit action. + (and (boundp 'zmacs-region-stays) + (setq zmacs-region-stays t))) + +(defsubst py-point (position) + "Returns the value of point at certain commonly referenced POSITIONs. +POSITION can be one of the following symbols: + + bol -- beginning of line + eol -- end of line + bod -- beginning of def or class + eod -- end of def or class + bob -- beginning of buffer + eob -- end of buffer + boi -- back to indentation + bos -- beginning of statement + +This function does not modify point or mark." + (let ((here (point))) + (cond + ((eq position 'bol) (beginning-of-line)) + ((eq position 'eol) (end-of-line)) + ((eq position 'bod) (py-beginning-of-def-or-class)) + ((eq position 'eod) (py-end-of-def-or-class)) + ;; Kind of funny, I know, but useful for py-up-exception. + ((eq position 'bob) (beginning-of-buffer)) + ((eq position 'eob) (end-of-buffer)) + ((eq position 'boi) (back-to-indentation)) + ((eq position 'bos) (py-goto-initial-line)) + (t (error "Unknown buffer position requested: %s" position)) + ) + (prog1 + (point) + (goto-char here)))) + +(defsubst py-highlight-line (from to file line) + (cond + ((fboundp 'make-extent) + ;; XEmacs + (let ((e (make-extent from to))) + (set-extent-property e 'mouse-face 'highlight) + (set-extent-property e 'py-exc-info (cons file line)) + (set-extent-property e 'keymap py-mode-output-map))) + (t + ;; Emacs -- Please port this! + ) + )) + +(defun py-in-literal (&optional lim) + "Return non-nil if point is in a Python literal (a comment or string). +Optional argument LIM indicates the beginning of the containing form, +i.e. the limit on how far back to scan." + ;; This is the version used for non-XEmacs, which has a nicer + ;; interface. + ;; + ;; WARNING: Watch out for infinite recursion. + (let* ((lim (or lim (py-point 'bod))) + (state (parse-partial-sexp lim (point)))) + (cond + ((nth 3 state) 'string) + ((nth 4 state) 'comment) + (t nil)))) + +;; XEmacs has a built-in function that should make this much quicker. +;; In this case, lim is ignored +(defun py-fast-in-literal (&optional lim) + "Fast version of `py-in-literal', used only by XEmacs. +Optional LIM is ignored." + ;; don't have to worry about context == 'block-comment + (buffer-syntactic-context)) + +(if (fboundp 'buffer-syntactic-context) + (defalias 'py-in-literal 'py-fast-in-literal)) + + + +;; Menu definitions, only relevent if you have the easymenu.el package +;; (standard in the latest Emacs 19 and XEmacs 19 distributions). +(defvar py-menu nil + "Menu for Python Mode. +This menu will get created automatically if you have the `easymenu' +package. Note that the latest X/Emacs releases contain this package.") + +(and (py-safe (require 'easymenu) t) + (easy-menu-define + py-menu py-mode-map "Python Mode menu" + '("Python" + ["Comment Out Region" py-comment-region (mark)] + ["Uncomment Region" (py-comment-region (point) (mark) '(4)) (mark)] + "-" + ["Mark current block" py-mark-block t] + ["Mark current def" py-mark-def-or-class t] + ["Mark current class" (py-mark-def-or-class t) t] + "-" + ["Shift region left" py-shift-region-left (mark)] + ["Shift region right" py-shift-region-right (mark)] + "-" + ["Import/reload file" py-execute-import-or-reload t] + ["Execute buffer" py-execute-buffer t] + ["Execute region" py-execute-region (mark)] + ["Execute def or class" py-execute-def-or-class (mark)] + ["Execute string" py-execute-string t] + ["Start interpreter..." py-shell t] + "-" + ["Go to start of block" py-goto-block-up t] + ["Go to start of class" (py-beginning-of-def-or-class t) t] + ["Move to end of class" (py-end-of-def-or-class t) t] + ["Move to start of def" py-beginning-of-def-or-class t] + ["Move to end of def" py-end-of-def-or-class t] + "-" + ["Describe mode" py-describe-mode t] + ))) + + + +;; Imenu definitions +(defvar py-imenu-class-regexp + (concat ; <<classes>> + "\\(" ; + "^[ \t]*" ; newline and maybe whitespace + "\\(class[ \t]+[a-zA-Z0-9_]+\\)" ; class name + ; possibly multiple superclasses + "\\([ \t]*\\((\\([a-zA-Z0-9_,. \t\n]\\)*)\\)?\\)" + "[ \t]*:" ; and the final : + "\\)" ; >>classes<< + ) + "Regexp for Python classes for use with the Imenu package." + ) + +(defvar py-imenu-method-regexp + (concat ; <<methods and functions>> + "\\(" ; + "^[ \t]*" ; new line and maybe whitespace + "\\(def[ \t]+" ; function definitions start with def + "\\([a-zA-Z0-9_]+\\)" ; name is here + ; function arguments... +;; "[ \t]*(\\([-+/a-zA-Z0-9_=,\* \t\n.()\"'#]*\\))" + "[ \t]*(\\([^:#]*\\))" + "\\)" ; end of def + "[ \t]*:" ; and then the : + "\\)" ; >>methods and functions<< + ) + "Regexp for Python methods/functions for use with the Imenu package." + ) + +(defvar py-imenu-method-no-arg-parens '(2 8) + "Indices into groups of the Python regexp for use with Imenu. + +Using these values will result in smaller Imenu lists, as arguments to +functions are not listed. + +See the variable `py-imenu-show-method-args-p' for more +information.") + +(defvar py-imenu-method-arg-parens '(2 7) + "Indices into groups of the Python regexp for use with imenu. +Using these values will result in large Imenu lists, as arguments to +functions are listed. + +See the variable `py-imenu-show-method-args-p' for more +information.") + +;; Note that in this format, this variable can still be used with the +;; imenu--generic-function. Otherwise, there is no real reason to have +;; it. +(defvar py-imenu-generic-expression + (cons + (concat + py-imenu-class-regexp + "\\|" ; or... + py-imenu-method-regexp + ) + py-imenu-method-no-arg-parens) + "Generic Python expression which may be used directly with Imenu. +Used by setting the variable `imenu-generic-expression' to this value. +Also, see the function \\[py-imenu-create-index] for a better +alternative for finding the index.") + +;; These next two variables are used when searching for the Python +;; class/definitions. Just saving some time in accessing the +;; generic-python-expression, really. +(defvar py-imenu-generic-regexp nil) +(defvar py-imenu-generic-parens nil) + + +(defun py-imenu-create-index-function () + "Python interface function for the Imenu package. +Finds all Python classes and functions/methods. Calls function +\\[py-imenu-create-index-engine]. See that function for the details +of how this works." + (setq py-imenu-generic-regexp (car py-imenu-generic-expression) + py-imenu-generic-parens (if py-imenu-show-method-args-p + py-imenu-method-arg-parens + py-imenu-method-no-arg-parens)) + (goto-char (point-min)) + ;; Warning: When the buffer has no classes or functions, this will + ;; return nil, which seems proper according to the Imenu API, but + ;; causes an error in the XEmacs port of Imenu. Sigh. + (py-imenu-create-index-engine nil)) + +(defun py-imenu-create-index-engine (&optional start-indent) + "Function for finding Imenu definitions in Python. + +Finds all definitions (classes, methods, or functions) in a Python +file for the Imenu package. + +Returns a possibly nested alist of the form + + (INDEX-NAME . INDEX-POSITION) + +The second element of the alist may be an alist, producing a nested +list as in + + (INDEX-NAME . INDEX-ALIST) + +This function should not be called directly, as it calls itself +recursively and requires some setup. Rather this is the engine for +the function \\[py-imenu-create-index-function]. + +It works recursively by looking for all definitions at the current +indention level. When it finds one, it adds it to the alist. If it +finds a definition at a greater indentation level, it removes the +previous definition from the alist. In its place it adds all +definitions found at the next indentation level. When it finds a +definition that is less indented then the current level, it returns +the alist it has created thus far. + +The optional argument START-INDENT indicates the starting indentation +at which to continue looking for Python classes, methods, or +functions. If this is not supplied, the function uses the indentation +of the first definition found." + (let (index-alist + sub-method-alist + looking-p + def-name prev-name + cur-indent def-pos + (class-paren (first py-imenu-generic-parens)) + (def-paren (second py-imenu-generic-parens))) + (setq looking-p + (re-search-forward py-imenu-generic-regexp (point-max) t)) + (while looking-p + (save-excursion + ;; used to set def-name to this value but generic-extract-name + ;; is new to imenu-1.14. this way it still works with + ;; imenu-1.11 + ;;(imenu--generic-extract-name py-imenu-generic-parens)) + (let ((cur-paren (if (match-beginning class-paren) + class-paren def-paren))) + (setq def-name + (buffer-substring-no-properties (match-beginning cur-paren) + (match-end cur-paren)))) + (save-match-data + (py-beginning-of-def-or-class 'either)) + (beginning-of-line) + (setq cur-indent (current-indentation))) + ;; HACK: want to go to the next correct definition location. We + ;; explicitly list them here but it would be better to have them + ;; in a list. + (setq def-pos + (or (match-beginning class-paren) + (match-beginning def-paren))) + ;; if we don't have a starting indent level, take this one + (or start-indent + (setq start-indent cur-indent)) + ;; if we don't have class name yet, take this one + (or prev-name + (setq prev-name def-name)) + ;; what level is the next definition on? must be same, deeper + ;; or shallower indentation + (cond + ;; Skip code in comments and strings + ((py-in-literal)) + ;; at the same indent level, add it to the list... + ((= start-indent cur-indent) + (push (cons def-name def-pos) index-alist)) + ;; deeper indented expression, recurse + ((< start-indent cur-indent) + ;; the point is currently on the expression we're supposed to + ;; start on, so go back to the last expression. The recursive + ;; call will find this place again and add it to the correct + ;; list + (re-search-backward py-imenu-generic-regexp (point-min) 'move) + (setq sub-method-alist (py-imenu-create-index-engine cur-indent)) + (if sub-method-alist + ;; we put the last element on the index-alist on the start + ;; of the submethod alist so the user can still get to it. + (let ((save-elmt (pop index-alist))) + (push (cons prev-name + (cons save-elmt sub-method-alist)) + index-alist)))) + ;; found less indented expression, we're done. + (t + (setq looking-p nil) + (re-search-backward py-imenu-generic-regexp (point-min) t))) + ;; end-cond + (setq prev-name def-name) + (and looking-p + (setq looking-p + (re-search-forward py-imenu-generic-regexp + (point-max) 'move)))) + (nreverse index-alist))) + + + +(defun py-choose-shell-by-shebang () + "Choose CPython or JPython mode by looking at #! on the first line. +Returns the appropriate mode function. +Used by `py-choose-shell', and similar to but distinct from +`set-auto-mode', though it uses `auto-mode-interpreter-regexp' (if available)." + ;; look for an interpreter specified in the first line + ;; similar to set-auto-mode (files.el) + (let* ((re (if (boundp 'auto-mode-interpreter-regexp) + auto-mode-interpreter-regexp + ;; stolen from Emacs 21.2 + "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)")) + (interpreter (save-excursion + (goto-char (point-min)) + (if (looking-at re) + (match-string 2) + ""))) + elt) + ;; Map interpreter name to a mode. + (setq elt (assoc (file-name-nondirectory interpreter) + py-shell-alist)) + (and elt (caddr elt)))) + + + +(defun py-choose-shell-by-import () + "Choose CPython or JPython mode based imports. +If a file imports any packages in `py-jpython-packages', within +`py-import-check-point-max' characters from the start of the file, +return `jpython', otherwise return nil." + (let (mode) + (save-excursion + (goto-char (point-min)) + (while (and (not mode) + (search-forward-regexp + "^\\(\\(from\\)\\|\\(import\\)\\) \\([^ \t\n.]+\\)" + py-import-check-point-max t)) + (setq mode (and (member (match-string 4) py-jpython-packages) + 'jpython + )))) + mode)) + + +(defun py-choose-shell () + "Choose CPython or JPython mode. Returns the appropriate mode function. +This does the following: + - look for an interpreter with `py-choose-shell-by-shebang' + - examine imports using `py-choose-shell-by-import' + - default to the variable `py-default-interpreter'" + (interactive) + (or (py-choose-shell-by-shebang) + (py-choose-shell-by-import) + py-default-interpreter +; 'cpython ;; don't use to py-default-interpreter, because default +; ;; is only way to choose CPython + )) + + +;;;###autoload +(defun python-mode () + "Major mode for editing Python files. +To submit a problem report, enter `\\[py-submit-bug-report]' from a +`python-mode' buffer. Do `\\[py-describe-mode]' for detailed +documentation. To see what version of `python-mode' you are running, +enter `\\[py-version]'. + +This mode knows about Python indentation, tokens, comments and +continuation lines. Paragraphs are separated by blank lines only. + +COMMANDS +\\{py-mode-map} +VARIABLES + +py-indent-offset\t\tindentation increment +py-block-comment-prefix\t\tcomment string used by `comment-region' +py-python-command\t\tshell command to invoke Python interpreter +py-temp-directory\t\tdirectory used for temp files (if needed) +py-beep-if-tab-change\t\tring the bell if `tab-width' is changed" + (interactive) + ;; set up local variables + (kill-all-local-variables) + (make-local-variable 'font-lock-defaults) + (make-local-variable 'paragraph-separate) + (make-local-variable 'paragraph-start) + (make-local-variable 'require-final-newline) + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'comment-start-skip) + (make-local-variable 'comment-column) + (make-local-variable 'comment-indent-function) + (make-local-variable 'indent-region-function) + (make-local-variable 'indent-line-function) + (make-local-variable 'add-log-current-defun-function) + ;; + (set-syntax-table py-mode-syntax-table) + (setq major-mode 'python-mode + mode-name "Python" + local-abbrev-table python-mode-abbrev-table + font-lock-defaults '(python-font-lock-keywords) + paragraph-separate "^[ \t]*$" + paragraph-start "^[ \t]*$" + require-final-newline t + comment-start "# " + comment-end "" + comment-start-skip "# *" + comment-column 40 + comment-indent-function 'py-comment-indent-function + indent-region-function 'py-indent-region + indent-line-function 'py-indent-line + ;; tell add-log.el how to find the current function/method/variable + add-log-current-defun-function 'py-current-defun + ) + (use-local-map py-mode-map) + ;; add the menu + (if py-menu + (easy-menu-add py-menu)) + ;; Emacs 19 requires this + (if (boundp 'comment-multi-line) + (setq comment-multi-line nil)) + ;; Install Imenu if available + (when (py-safe (require 'imenu)) + (setq imenu-create-index-function #'py-imenu-create-index-function) + (setq imenu-generic-expression py-imenu-generic-expression) + (if (fboundp 'imenu-add-to-menubar) + (imenu-add-to-menubar (format "%s-%s" "IM" mode-name))) + ) + ;; Run the mode hook. Note that py-mode-hook is deprecated. + (if python-mode-hook + (run-hooks 'python-mode-hook) + (run-hooks 'py-mode-hook)) + ;; Now do the automagical guessing + (if py-smart-indentation + (let ((offset py-indent-offset)) + ;; It's okay if this fails to guess a good value + (if (and (py-safe (py-guess-indent-offset)) + (<= py-indent-offset 8) + (>= py-indent-offset 2)) + (setq offset py-indent-offset)) + (setq py-indent-offset offset) + ;; Only turn indent-tabs-mode off if tab-width != + ;; py-indent-offset. Never turn it on, because the user must + ;; have explicitly turned it off. + (if (/= tab-width py-indent-offset) + (setq indent-tabs-mode nil)) + )) + ;; Set the default shell if not already set + (when (null py-which-shell) + (py-toggle-shells (py-choose-shell)))) + + +(defun jpython-mode () + "Major mode for editing JPython/Jython files. +This is a simple wrapper around `python-mode'. +It runs `jpython-mode-hook' then calls `python-mode.' +It is added to `interpreter-mode-alist' and `py-choose-shell'. +" + (interactive) + (python-mode) + (py-toggle-shells 'jpython) + (when jpython-mode-hook + (run-hooks 'jpython-mode-hook))) + + +;; It's handy to add recognition of Python files to the +;; interpreter-mode-alist and to auto-mode-alist. With the former, we +;; can specify different `derived-modes' based on the #! line, but +;; with the latter, we can't. So we just won't add them if they're +;; already added. +(let ((modes '(("jpython" . jpython-mode) + ("jython" . jpython-mode) + ("python" . python-mode)))) + (while modes + (when (not (assoc (car modes) interpreter-mode-alist)) + (push (car modes) interpreter-mode-alist)) + (setq modes (cdr modes)))) + +(when (not (or (rassq 'python-mode auto-mode-alist) + (rassq 'jpython-mode auto-mode-alist))) + (push '("\\.py$" . python-mode) auto-mode-alist)) + + + +;; electric characters +(defun py-outdent-p () + "Returns non-nil if the current line should dedent one level." + (save-excursion + (and (progn (back-to-indentation) + (looking-at py-outdent-re)) + ;; short circuit infloop on illegal construct + (not (bobp)) + (progn (forward-line -1) + (py-goto-initial-line) + (back-to-indentation) + (while (or (looking-at py-blank-or-comment-re) + (bobp)) + (backward-to-indentation 1)) + (not (looking-at py-no-outdent-re))) + ))) + +(defun py-electric-colon (arg) + "Insert a colon. +In certain cases the line is dedented appropriately. If a numeric +argument ARG is provided, that many colons are inserted +non-electrically. Electric behavior is inhibited inside a string or +comment." + (interactive "*P") + (self-insert-command (prefix-numeric-value arg)) + ;; are we in a string or comment? + (if (save-excursion + (let ((pps (parse-partial-sexp (save-excursion + (py-beginning-of-def-or-class) + (point)) + (point)))) + (not (or (nth 3 pps) (nth 4 pps))))) + (save-excursion + (let ((here (point)) + (outdent 0) + (indent (py-compute-indentation t))) + (if (and (not arg) + (py-outdent-p) + (= indent (save-excursion + (py-next-statement -1) + (py-compute-indentation t))) + ) + (setq outdent py-indent-offset)) + ;; Don't indent, only dedent. This assumes that any lines + ;; that are already dedented relative to + ;; py-compute-indentation were put there on purpose. It's + ;; highly annoying to have `:' indent for you. Use TAB, C-c + ;; C-l or C-c C-r to adjust. TBD: Is there a better way to + ;; determine this??? + (if (< (current-indentation) indent) nil + (goto-char here) + (beginning-of-line) + (delete-horizontal-space) + (indent-to (- indent outdent)) + ))))) + + +;; Python subprocess utilities and filters +(defun py-execute-file (proc filename) + "Send to Python interpreter process PROC \"execfile('FILENAME')\". +Make that process's buffer visible and force display. Also make +comint believe the user typed this string so that +`kill-output-from-shell' does The Right Thing." + (let ((curbuf (current-buffer)) + (procbuf (process-buffer proc)) +; (comint-scroll-to-bottom-on-output t) + (msg (format "## working on region in file %s...\n" filename)) + (cmd (format "execfile(r'%s')\n" filename))) + (unwind-protect + (save-excursion + (set-buffer procbuf) + (goto-char (point-max)) + (move-marker (process-mark proc) (point)) + (funcall (process-filter proc) proc msg)) + (set-buffer curbuf)) + (process-send-string proc cmd))) + +(defun py-comint-output-filter-function (string) + "Watch output for Python prompt and exec next file waiting in queue. +This function is appropriate for `comint-output-filter-functions'." + ;; TBD: this should probably use split-string + (when (and (or (string-equal string ">>> ") + (and (>= (length string) 5) + (string-equal (substring string -5) "\n>>> "))) + py-file-queue) + (pop-to-buffer (current-buffer)) + (py-safe (delete-file (car py-file-queue))) + (setq py-file-queue (cdr py-file-queue)) + (if py-file-queue + (let ((pyproc (get-buffer-process (current-buffer)))) + (py-execute-file pyproc (car py-file-queue)))) + )) + +(defun py-pdbtrack-overlay-arrow (activation) + "Activate or de arrow at beginning-of-line in current buffer." + ;; This was derived/simplified from edebug-overlay-arrow + (cond (activation + (setq overlay-arrow-position (make-marker)) + (setq overlay-arrow-string "=>") + (set-marker overlay-arrow-position (py-point 'bol) (current-buffer)) + (setq py-pdbtrack-is-tracking-p t)) + (overlay-arrow-position + (setq overlay-arrow-position nil) + (setq py-pdbtrack-is-tracking-p nil)) + )) + +(defun py-pdbtrack-track-stack-file (text) + "Show the file indicated by the pdb stack entry line, in a separate window. + +Activity is disabled if the buffer-local variable +`py-pdbtrack-do-tracking-p' is nil. + +We depend on the pdb input prompt matching `py-pdbtrack-input-prompt' +at the beginning of the line. + +If the traceback target file path is invalid, we look for the most +recently visited python-mode buffer which either has the name of the +current function \(or class) or which defines the function \(or +class). This is to provide for remote scripts, eg, Zope's 'Script +(Python)' - put a _copy_ of the script in a buffer named for the +script, and set to python-mode, and pdbtrack will find it.)" + ;; Instead of trying to piece things together from partial text + ;; (which can be almost useless depending on Emacs version), we + ;; monitor to the point where we have the next pdb prompt, and then + ;; check all text from comint-last-input-end to process-mark. + ;; + ;; Also, we're very conservative about clearing the overlay arrow, + ;; to minimize residue. This means, for instance, that executing + ;; other pdb commands wipe out the highlight. You can always do a + ;; 'where' (aka 'w') command to reveal the overlay arrow. + (let* ((origbuf (current-buffer)) + (currproc (get-buffer-process origbuf))) + + (if (not (and currproc py-pdbtrack-do-tracking-p)) + (py-pdbtrack-overlay-arrow nil) + + (let* ((procmark (process-mark currproc)) + (block (buffer-substring (max comint-last-input-end + (- procmark + py-pdbtrack-track-range)) + procmark)) + target target_fname target_lineno) + + (if (not (string-match (concat py-pdbtrack-input-prompt "$") block)) + (py-pdbtrack-overlay-arrow nil) + + (setq target (py-pdbtrack-get-source-buffer block)) + + (if (stringp target) + (message "pdbtrack: %s" target) + + (setq target_lineno (car target)) + (setq target_buffer (cadr target)) + (setq target_fname (buffer-file-name target_buffer)) + (switch-to-buffer-other-window target_buffer) + (goto-line target_lineno) + (message "pdbtrack: line %s, file %s" target_lineno target_fname) + (py-pdbtrack-overlay-arrow t) + (pop-to-buffer origbuf t) + + ))))) + ) + +(defun py-pdbtrack-get-source-buffer (block) + "Return line number and buffer of code indicated by block's traceback text. + +We look first to visit the file indicated in the trace. + +Failing that, we look for the most recently visited python-mode buffer +with the same name or having +having the named function. + +If we're unable find the source code we return a string describing the +problem as best as we can determine." + + (if (not (string-match py-pdbtrack-stack-entry-regexp block)) + + "Traceback cue not found" + + (let* ((filename (match-string 1 block)) + (lineno (string-to-int (match-string 2 block))) + (funcname (match-string 3 block)) + funcbuffer) + + (cond ((file-exists-p filename) + (list lineno (find-file-noselect filename))) + + ((setq funcbuffer (py-pdbtrack-grub-for-buffer funcname lineno)) + (if (string-match "/Script (Python)$" filename) + ;; Add in number of lines for leading '##' comments: + (setq lineno + (+ lineno + (save-excursion + (set-buffer funcbuffer) + (count-lines + (point-min) + (max (point-min) + (string-match "^\\([^#]\\|#[^#]\\|#$\\)" + (buffer-substring (point-min) + (point-max))) + )))))) + (list lineno funcbuffer)) + + ((= (elt filename 0) ?\<) + (format "(Non-file source: '%s')" filename)) + + (t (format "Not found: %s(), %s" funcname filename))) + ) + ) + ) + +(defun py-pdbtrack-grub-for-buffer (funcname lineno) + "Find most recent buffer itself named or having function funcname. + +We first check the last buffer this function found, if any, then walk +throught the buffer-list history for python-mode buffers that are +named for funcname or define a function funcname." + (let ((buffers (buffer-list)) + curbuf + got) + (while (and buffers (not got)) + (setq buf (car buffers) + buffers (cdr buffers)) + (if (and (save-excursion (set-buffer buf) + (string= major-mode "python-mode")) + (or (string-match funcname (buffer-name buf)) + (string-match (concat "^\\s-*\\(def\\|class\\)\\s-+" + funcname "\\s-*(") + (save-excursion + (set-buffer buf) + (buffer-substring (point-min) + (point-max)))))) + (setq got buf))) + (setq py-pdbtrack-last-grubbed-buffer got))) + +(defun py-postprocess-output-buffer (buf) + "Highlight exceptions found in BUF. +If an exception occurred return t, otherwise return nil. BUF must exist." + (let (line file bol err-p) + (save-excursion + (set-buffer buf) + (beginning-of-buffer) + (while (re-search-forward py-traceback-line-re nil t) + (setq file (match-string 1) + line (string-to-int (match-string 2)) + bol (py-point 'bol)) + (py-highlight-line bol (py-point 'eol) file line))) + (when (and py-jump-on-exception line) + (beep) + (py-jump-to-exception file line) + (setq err-p t)) + err-p)) + + + +;;; Subprocess commands + +;; only used when (memq 'broken-temp-names py-emacs-features) +(defvar py-serial-number 0) +(defvar py-exception-buffer nil) +(defconst py-output-buffer "*Python Output*") +(make-variable-buffer-local 'py-output-buffer) + +;; for toggling between CPython and JPython +(defvar py-which-shell nil) +(defvar py-which-args py-python-command-args) +(defvar py-which-bufname "Python") +(make-variable-buffer-local 'py-which-shell) +(make-variable-buffer-local 'py-which-args) +(make-variable-buffer-local 'py-which-bufname) + +(defun py-toggle-shells (arg) + "Toggles between the CPython and JPython shells. + +With positive argument ARG (interactively \\[universal-argument]), +uses the CPython shell, with negative ARG uses the JPython shell, and +with a zero argument, toggles the shell. + +Programmatically, ARG can also be one of the symbols `cpython' or +`jpython', equivalent to positive arg and negative arg respectively." + (interactive "P") + ;; default is to toggle + (if (null arg) + (setq arg 0)) + ;; preprocess arg + (cond + ((equal arg 0) + ;; toggle + (if (string-equal py-which-bufname "Python") + (setq arg -1) + (setq arg 1))) + ((equal arg 'cpython) (setq arg 1)) + ((equal arg 'jpython) (setq arg -1))) + (let (msg) + (cond + ((< 0 arg) + ;; set to CPython + (setq py-which-shell py-python-command + py-which-args py-python-command-args + py-which-bufname "Python" + msg "CPython" + mode-name "Python")) + ((> 0 arg) + (setq py-which-shell py-jpython-command + py-which-args py-jpython-command-args + py-which-bufname "JPython" + msg "JPython" + mode-name "JPython")) + ) + (message "Using the %s shell" msg) + (setq py-output-buffer (format "*%s Output*" py-which-bufname)))) + +;;;###autoload +(defun py-shell (&optional argprompt) + "Start an interactive Python interpreter in another window. +This is like Shell mode, except that Python is running in the window +instead of a shell. See the `Interactive Shell' and `Shell Mode' +sections of the Emacs manual for details, especially for the key +bindings active in the `*Python*' buffer. + +With optional \\[universal-argument], the user is prompted for the +flags to pass to the Python interpreter. This has no effect when this +command is used to switch to an existing process, only when a new +process is started. If you use this, you will probably want to ensure +that the current arguments are retained (they will be included in the +prompt). This argument is ignored when this function is called +programmatically, or when running in Emacs 19.34 or older. + +Note: You can toggle between using the CPython interpreter and the +JPython interpreter by hitting \\[py-toggle-shells]. This toggles +buffer local variables which control whether all your subshell +interactions happen to the `*JPython*' or `*Python*' buffers (the +latter is the name used for the CPython buffer). + +Warning: Don't use an interactive Python if you change sys.ps1 or +sys.ps2 from their default values, or if you're running code that +prints `>>> ' or `... ' at the start of a line. `python-mode' can't +distinguish your output from Python's output, and assumes that `>>> ' +at the start of a line is a prompt from Python. Similarly, the Emacs +Shell mode code assumes that both `>>> ' and `... ' at the start of a +line are Python prompts. Bad things can happen if you fool either +mode. + +Warning: If you do any editing *in* the process buffer *while* the +buffer is accepting output from Python, do NOT attempt to `undo' the +changes. Some of the output (nowhere near the parts you changed!) may +be lost if you do. This appears to be an Emacs bug, an unfortunate +interaction between undo and process filters; the same problem exists in +non-Python process buffers using the default (Emacs-supplied) process +filter." + (interactive "P") + ;; Set the default shell if not already set + (when (null py-which-shell) + (py-toggle-shells py-default-interpreter)) + (let ((args py-which-args)) + (when (and argprompt + (interactive-p) + (fboundp 'split-string)) + ;; TBD: Perhaps force "-i" in the final list? + (setq args (split-string + (read-string (concat py-which-bufname + " arguments: ") + (concat + (mapconcat 'identity py-which-args " ") " ") + )))) + (switch-to-buffer-other-window + (apply 'make-comint py-which-bufname py-which-shell nil args)) + (make-local-variable 'comint-prompt-regexp) + (setq comint-prompt-regexp "^>>> \\|^[.][.][.] \\|^(pdb) ") + (add-hook 'comint-output-filter-functions + 'py-comint-output-filter-function) + ;; pdbtrack + (add-hook 'comint-output-filter-functions 'py-pdbtrack-track-stack-file) + (setq py-pdbtrack-do-tracking-p t) + (set-syntax-table py-mode-syntax-table) + (use-local-map py-shell-map) + (run-hooks 'py-shell-hook) + )) + +(defun py-clear-queue () + "Clear the queue of temporary files waiting to execute." + (interactive) + (let ((n (length py-file-queue))) + (mapcar 'delete-file py-file-queue) + (setq py-file-queue nil) + (message "%d pending files de-queued." n))) + + +(defun py-execute-region (start end &optional async) + "Execute the region in a Python interpreter. + +The region is first copied into a temporary file (in the directory +`py-temp-directory'). If there is no Python interpreter shell +running, this file is executed synchronously using +`shell-command-on-region'. If the program is long running, use +\\[universal-argument] to run the command asynchronously in its own +buffer. + +When this function is used programmatically, arguments START and END +specify the region to execute, and optional third argument ASYNC, if +non-nil, specifies to run the command asynchronously in its own +buffer. + +If the Python interpreter shell is running, the region is execfile()'d +in that shell. If you try to execute regions too quickly, +`python-mode' will queue them up and execute them one at a time when +it sees a `>>> ' prompt from Python. Each time this happens, the +process buffer is popped into a window (if it's not already in some +window) so you can see it, and a comment of the form + + \t## working on region in file <name>... + +is inserted at the end. See also the command `py-clear-queue'." + (interactive "r\nP") + ;; Skip ahead to the first non-blank line + (let* ((proc (get-process py-which-bufname)) + (temp (if (memq 'broken-temp-names py-emacs-features) + (let + ((sn py-serial-number) + (pid (and (fboundp 'emacs-pid) (emacs-pid)))) + (setq py-serial-number (1+ py-serial-number)) + (if pid + (format "python-%d-%d" sn pid) + (format "python-%d" sn))) + (make-temp-name "python-"))) + (file (concat (expand-file-name temp py-temp-directory) ".py")) + (cur (current-buffer)) + (buf (get-buffer-create file)) + shell) + ;; Write the contents of the buffer, watching out for indented regions. + (save-excursion + (goto-char start) + (beginning-of-line) + (while (and (looking-at "\\s *$") + (< (point) end)) + (forward-line 1)) + (setq start (point)) + (or (< start end) + (error "Region is empty")) + (let ((needs-if (/= (py-point 'bol) (py-point 'boi)))) + (set-buffer buf) + (python-mode) + (when needs-if + (insert "if 1:\n")) + (insert-buffer-substring cur start end) + ;; Set the shell either to the #! line command, or to the + ;; py-which-shell buffer local variable. + (setq shell (or (py-choose-shell-by-shebang) + (py-choose-shell-by-import) + py-which-shell)))) + (cond + ;; always run the code in its own asynchronous subprocess + (async + ;; User explicitly wants this to run in its own async subprocess + (save-excursion + (set-buffer buf) + (write-region (point-min) (point-max) file nil 'nomsg)) + (let* ((buf (generate-new-buffer-name py-output-buffer)) + ;; TBD: a horrible hack, but why create new Custom variables? + (arg (if (string-equal py-which-bufname "Python") + "-u" ""))) + (start-process py-which-bufname buf shell arg file) + (pop-to-buffer buf) + (py-postprocess-output-buffer buf) + ;; TBD: clean up the temporary file! + )) + ;; if the Python interpreter shell is running, queue it up for + ;; execution there. + (proc + ;; use the existing python shell + (save-excursion + (set-buffer buf) + (write-region (point-min) (point-max) file nil 'nomsg)) + (if (not py-file-queue) + (py-execute-file proc file) + (message "File %s queued for execution" file)) + (setq py-file-queue (append py-file-queue (list file))) + (setq py-exception-buffer (cons file (current-buffer)))) + (t + ;; TBD: a horrible hack, but why create new Custom variables? + (let ((cmd (concat shell (if (string-equal py-which-bufname "JPython") + " -" "")))) + ;; otherwise either run it synchronously in a subprocess + (save-excursion + (set-buffer buf) + (shell-command-on-region (point-min) (point-max) + cmd py-output-buffer)) + ;; shell-command-on-region kills the output buffer if it never + ;; existed and there's no output from the command + (if (not (get-buffer py-output-buffer)) + (message "No output.") + (setq py-exception-buffer (current-buffer)) + (let ((err-p (py-postprocess-output-buffer py-output-buffer))) + (pop-to-buffer py-output-buffer) + (if err-p + (pop-to-buffer py-exception-buffer))) + )) + )) + ;; Clean up after ourselves. + (kill-buffer buf))) + + +;; Code execution commands +(defun py-execute-buffer (&optional async) + "Send the contents of the buffer to a Python interpreter. +If the file local variable `py-master-file' is non-nil, execute the +named file instead of the buffer's file. + +If there is a *Python* process buffer it is used. If a clipping +restriction is in effect, only the accessible portion of the buffer is +sent. A trailing newline will be supplied if needed. + +See the `\\[py-execute-region]' docs for an account of some +subtleties, including the use of the optional ASYNC argument." + (interactive "P") + (if py-master-file + (let* ((filename (expand-file-name py-master-file)) + (buffer (or (get-file-buffer filename) + (find-file-noselect filename)))) + (set-buffer buffer))) + (py-execute-region (point-min) (point-max) async)) + +(defun py-execute-import-or-reload (&optional async) + "Import the current buffer's file in a Python interpreter. + +If the file has already been imported, then do reload instead to get +the latest version. + +If the file's name does not end in \".py\", then do execfile instead. + +If the current buffer is not visiting a file, do `py-execute-buffer' +instead. + +If the file local variable `py-master-file' is non-nil, import or +reload the named file instead of the buffer's file. The file may be +saved based on the value of `py-execute-import-or-reload-save-p'. + +See the `\\[py-execute-region]' docs for an account of some +subtleties, including the use of the optional ASYNC argument. + +This may be preferable to `\\[py-execute-buffer]' because: + + - Definitions stay in their module rather than appearing at top + level, where they would clutter the global namespace and not affect + uses of qualified names (MODULE.NAME). + + - The Python debugger gets line number information about the functions." + (interactive "P") + ;; Check file local variable py-master-file + (if py-master-file + (let* ((filename (expand-file-name py-master-file)) + (buffer (or (get-file-buffer filename) + (find-file-noselect filename)))) + (set-buffer buffer))) + (let ((file (buffer-file-name (current-buffer)))) + (if file + (progn + ;; Maybe save some buffers + (save-some-buffers (not py-ask-about-save) nil) + (py-execute-string + (if (string-match "\\.py$" file) + (let ((f (file-name-sans-extension + (file-name-nondirectory file)))) + (format "if globals().has_key('%s'):\n reload(%s)\nelse:\n import %s\n" + f f f)) + (format "execfile(r'%s')\n" file)) + async)) + ;; else + (py-execute-buffer async)))) + + +(defun py-execute-def-or-class (&optional async) + "Send the current function or class definition to a Python interpreter. + +If there is a *Python* process buffer it is used. + +See the `\\[py-execute-region]' docs for an account of some +subtleties, including the use of the optional ASYNC argument." + (interactive "P") + (save-excursion + (py-mark-def-or-class) + ;; mark is before point + (py-execute-region (mark) (point) async))) + + +(defun py-execute-string (string &optional async) + "Send the argument STRING to a Python interpreter. + +If there is a *Python* process buffer it is used. + +See the `\\[py-execute-region]' docs for an account of some +subtleties, including the use of the optional ASYNC argument." + (interactive "sExecute Python command: ") + (save-excursion + (set-buffer (get-buffer-create + (generate-new-buffer-name " *Python Command*"))) + (insert string) + (py-execute-region (point-min) (point-max) async))) + + + +(defun py-jump-to-exception (file line) + "Jump to the Python code in FILE at LINE." + (let ((buffer (cond ((string-equal file "<stdin>") + (if (consp py-exception-buffer) + (cdr py-exception-buffer) + py-exception-buffer)) + ((and (consp py-exception-buffer) + (string-equal file (car py-exception-buffer))) + (cdr py-exception-buffer)) + ((py-safe (find-file-noselect file))) + ;; could not figure out what file the exception + ;; is pointing to, so prompt for it + (t (find-file (read-file-name "Exception file: " + nil + file t)))))) + (pop-to-buffer buffer) + ;; Force Python mode + (if (not (eq major-mode 'python-mode)) + (python-mode)) + (goto-line line) + (message "Jumping to exception in file %s on line %d" file line))) + +(defun py-mouseto-exception (event) + "Jump to the code which caused the Python exception at EVENT. +EVENT is usually a mouse click." + (interactive "e") + (cond + ((fboundp 'event-point) + ;; XEmacs + (let* ((point (event-point event)) + (buffer (event-buffer event)) + (e (and point buffer (extent-at point buffer 'py-exc-info))) + (info (and e (extent-property e 'py-exc-info)))) + (message "Event point: %d, info: %s" point info) + (and info + (py-jump-to-exception (car info) (cdr info))) + )) + ;; Emacs -- Please port this! + )) + +(defun py-goto-exception () + "Go to the line indicated by the traceback." + (interactive) + (let (file line) + (save-excursion + (beginning-of-line) + (if (looking-at py-traceback-line-re) + (setq file (match-string 1) + line (string-to-int (match-string 2))))) + (if (not file) + (error "Not on a traceback line")) + (py-jump-to-exception file line))) + +(defun py-find-next-exception (start buffer searchdir errwhere) + "Find the next Python exception and jump to the code that caused it. +START is the buffer position in BUFFER from which to begin searching +for an exception. SEARCHDIR is a function, either +`re-search-backward' or `re-search-forward' indicating the direction +to search. ERRWHERE is used in an error message if the limit (top or +bottom) of the trackback stack is encountered." + (let (file line) + (save-excursion + (set-buffer buffer) + (goto-char (py-point start)) + (if (funcall searchdir py-traceback-line-re nil t) + (setq file (match-string 1) + line (string-to-int (match-string 2))))) + (if (and file line) + (py-jump-to-exception file line) + (error "%s of traceback" errwhere)))) + +(defun py-down-exception (&optional bottom) + "Go to the next line down in the traceback. +With \\[univeral-argument] (programmatically, optional argument +BOTTOM), jump to the bottom (innermost) exception in the exception +stack." + (interactive "P") + (let* ((proc (get-process "Python")) + (buffer (if proc "*Python*" py-output-buffer))) + (if bottom + (py-find-next-exception 'eob buffer 're-search-backward "Bottom") + (py-find-next-exception 'eol buffer 're-search-forward "Bottom")))) + +(defun py-up-exception (&optional top) + "Go to the previous line up in the traceback. +With \\[universal-argument] (programmatically, optional argument TOP) +jump to the top (outermost) exception in the exception stack." + (interactive "P") + (let* ((proc (get-process "Python")) + (buffer (if proc "*Python*" py-output-buffer))) + (if top + (py-find-next-exception 'bob buffer 're-search-forward "Top") + (py-find-next-exception 'bol buffer 're-search-backward "Top")))) + + +;; Electric deletion +(defun py-electric-backspace (arg) + "Delete preceding character or levels of indentation. +Deletion is performed by calling the function in `py-backspace-function' +with a single argument (the number of characters to delete). + +If point is at the leftmost column, delete the preceding newline. + +Otherwise, if point is at the leftmost non-whitespace character of a +line that is neither a continuation line nor a non-indenting comment +line, or if point is at the end of a blank line, this command reduces +the indentation to match that of the line that opened the current +block of code. The line that opened the block is displayed in the +echo area to help you keep track of where you are. With +\\[universal-argument] dedents that many blocks (but not past column +zero). + +Otherwise the preceding character is deleted, converting a tab to +spaces if needed so that only a single column position is deleted. +\\[universal-argument] specifies how many characters to delete; +default is 1. + +When used programmatically, argument ARG specifies the number of +blocks to dedent, or the number of characters to delete, as indicated +above." + (interactive "*p") + (if (or (/= (current-indentation) (current-column)) + (bolp) + (py-continuation-line-p) +; (not py-honor-comment-indentation) +; (looking-at "#[^ \t\n]") ; non-indenting # + ) + (funcall py-backspace-function arg) + ;; else indent the same as the colon line that opened the block + ;; force non-blank so py-goto-block-up doesn't ignore it + (insert-char ?* 1) + (backward-char) + (let ((base-indent 0) ; indentation of base line + (base-text "") ; and text of base line + (base-found-p nil)) + (save-excursion + (while (< 0 arg) + (condition-case nil ; in case no enclosing block + (progn + (py-goto-block-up 'no-mark) + (setq base-indent (current-indentation) + base-text (py-suck-up-leading-text) + base-found-p t)) + (error nil)) + (setq arg (1- arg)))) + (delete-char 1) ; toss the dummy character + (delete-horizontal-space) + (indent-to base-indent) + (if base-found-p + (message "Closes block: %s" base-text))))) + + +(defun py-electric-delete (arg) + "Delete preceding or following character or levels of whitespace. + +The behavior of this function depends on the variable +`delete-key-deletes-forward'. If this variable is nil (or does not +exist, as in older Emacsen and non-XEmacs versions), then this +function behaves identically to \\[c-electric-backspace]. + +If `delete-key-deletes-forward' is non-nil and is supported in your +Emacs, then deletion occurs in the forward direction, by calling the +function in `py-delete-function'. + +\\[universal-argument] (programmatically, argument ARG) specifies the +number of characters to delete (default is 1)." + (interactive "*p") + (if (or (and (fboundp 'delete-forward-p) ;XEmacs 21 + (delete-forward-p)) + (and (boundp 'delete-key-deletes-forward) ;XEmacs 20 + delete-key-deletes-forward)) + (funcall py-delete-function arg) + (py-electric-backspace arg))) + +;; required for pending-del and delsel modes +(put 'py-electric-colon 'delete-selection t) ;delsel +(put 'py-electric-colon 'pending-delete t) ;pending-del +(put 'py-electric-backspace 'delete-selection 'supersede) ;delsel +(put 'py-electric-backspace 'pending-delete 'supersede) ;pending-del +(put 'py-electric-delete 'delete-selection 'supersede) ;delsel +(put 'py-electric-delete 'pending-delete 'supersede) ;pending-del + + + +(defun py-indent-line (&optional arg) + "Fix the indentation of the current line according to Python rules. +With \\[universal-argument] (programmatically, the optional argument +ARG non-nil), ignore dedenting rules for block closing statements +(e.g. return, raise, break, continue, pass) + +This function is normally bound to `indent-line-function' so +\\[indent-for-tab-command] will call it." + (interactive "P") + (let* ((ci (current-indentation)) + (move-to-indentation-p (<= (current-column) ci)) + (need (py-compute-indentation (not arg)))) + ;; see if we need to dedent + (if (py-outdent-p) + (setq need (- need py-indent-offset))) + (if (/= ci need) + (save-excursion + (beginning-of-line) + (delete-horizontal-space) + (indent-to need))) + (if move-to-indentation-p (back-to-indentation)))) + +(defun py-newline-and-indent () + "Strives to act like the Emacs `newline-and-indent'. +This is just `strives to' because correct indentation can't be computed +from scratch for Python code. In general, deletes the whitespace before +point, inserts a newline, and takes an educated guess as to how you want +the new line indented." + (interactive) + (let ((ci (current-indentation))) + (if (< ci (current-column)) ; if point beyond indentation + (newline-and-indent) + ;; else try to act like newline-and-indent "normally" acts + (beginning-of-line) + (insert-char ?\n 1) + (move-to-column ci)))) + +(defun py-compute-indentation (honor-block-close-p) + "Compute Python indentation. +When HONOR-BLOCK-CLOSE-P is non-nil, statements such as `return', +`raise', `break', `continue', and `pass' force one level of +dedenting." + (save-excursion + (beginning-of-line) + (let* ((bod (py-point 'bod)) + (pps (parse-partial-sexp bod (point))) + (boipps (parse-partial-sexp bod (py-point 'boi))) + placeholder) + (cond + ;; are we inside a multi-line string or comment? + ((or (and (nth 3 pps) (nth 3 boipps)) + (and (nth 4 pps) (nth 4 boipps))) + (save-excursion + (if (not py-align-multiline-strings-p) 0 + ;; skip back over blank & non-indenting comment lines + ;; note: will skip a blank or non-indenting comment line + ;; that happens to be a continuation line too + (re-search-backward "^[ \t]*\\([^ \t\n#]\\|#[ \t\n]\\)" nil 'move) + (back-to-indentation) + (current-column)))) + ;; are we on a continuation line? + ((py-continuation-line-p) + (let ((startpos (point)) + (open-bracket-pos (py-nesting-level)) + endpos searching found state) + (if open-bracket-pos + (progn + ;; align with first item in list; else a normal + ;; indent beyond the line with the open bracket + (goto-char (1+ open-bracket-pos)) ; just beyond bracket + ;; is the first list item on the same line? + (skip-chars-forward " \t") + (if (null (memq (following-char) '(?\n ?# ?\\))) + ; yes, so line up with it + (current-column) + ;; first list item on another line, or doesn't exist yet + (forward-line 1) + (while (and (< (point) startpos) + (looking-at "[ \t]*[#\n\\\\]")) ; skip noise + (forward-line 1)) + (if (and (< (point) startpos) + (/= startpos + (save-excursion + (goto-char (1+ open-bracket-pos)) + (forward-comment (point-max)) + (point)))) + ;; again mimic the first list item + (current-indentation) + ;; else they're about to enter the first item + (goto-char open-bracket-pos) + (setq placeholder (point)) + (py-goto-initial-line) + (py-goto-beginning-of-tqs + (save-excursion (nth 3 (parse-partial-sexp + placeholder (point))))) + (+ (current-indentation) py-indent-offset)))) + + ;; else on backslash continuation line + (forward-line -1) + (if (py-continuation-line-p) ; on at least 3rd line in block + (current-indentation) ; so just continue the pattern + ;; else started on 2nd line in block, so indent more. + ;; if base line is an assignment with a start on a RHS, + ;; indent to 2 beyond the leftmost "="; else skip first + ;; chunk of non-whitespace characters on base line, + 1 more + ;; column + (end-of-line) + (setq endpos (point) + searching t) + (back-to-indentation) + (setq startpos (point)) + ;; look at all "=" from left to right, stopping at first + ;; one not nested in a list or string + (while searching + (skip-chars-forward "^=" endpos) + (if (= (point) endpos) + (setq searching nil) + (forward-char 1) + (setq state (parse-partial-sexp startpos (point))) + (if (and (zerop (car state)) ; not in a bracket + (null (nth 3 state))) ; & not in a string + (progn + (setq searching nil) ; done searching in any case + (setq found + (not (or + (eq (following-char) ?=) + (memq (char-after (- (point) 2)) + '(?< ?> ?!))))))))) + (if (or (not found) ; not an assignment + (looking-at "[ \t]*\\\\")) ; <=><spaces><backslash> + (progn + (goto-char startpos) + (skip-chars-forward "^ \t\n"))) + ;; if this is a continuation for a block opening + ;; statement, add some extra offset. + (+ (current-column) (if (py-statement-opens-block-p) + py-continuation-offset 0) + 1) + )))) + + ;; not on a continuation line + ((bobp) (current-indentation)) + + ;; Dfn: "Indenting comment line". A line containing only a + ;; comment, but which is treated like a statement for + ;; indentation calculation purposes. Such lines are only + ;; treated specially by the mode; they are not treated + ;; specially by the Python interpreter. + + ;; The rules for indenting comment lines are a line where: + ;; - the first non-whitespace character is `#', and + ;; - the character following the `#' is whitespace, and + ;; - the line is dedented with respect to (i.e. to the left + ;; of) the indentation of the preceding non-blank line. + + ;; The first non-blank line following an indenting comment + ;; line is given the same amount of indentation as the + ;; indenting comment line. + + ;; All other comment-only lines are ignored for indentation + ;; purposes. + + ;; Are we looking at a comment-only line which is *not* an + ;; indenting comment line? If so, we assume that it's been + ;; placed at the desired indentation, so leave it alone. + ;; Indenting comment lines are aligned as statements down + ;; below. + ((and (looking-at "[ \t]*#[^ \t\n]") + ;; NOTE: this test will not be performed in older Emacsen + (fboundp 'forward-comment) + (<= (current-indentation) + (save-excursion + (forward-comment (- (point-max))) + (current-indentation)))) + (current-indentation)) + + ;; else indentation based on that of the statement that + ;; precedes us; use the first line of that statement to + ;; establish the base, in case the user forced a non-std + ;; indentation for the continuation lines (if any) + (t + ;; skip back over blank & non-indenting comment lines note: + ;; will skip a blank or non-indenting comment line that + ;; happens to be a continuation line too. use fast Emacs 19 + ;; function if it's there. + (if (and (eq py-honor-comment-indentation nil) + (fboundp 'forward-comment)) + (forward-comment (- (point-max))) + (let ((prefix-re (concat py-block-comment-prefix "[ \t]*")) + done) + (while (not done) + (re-search-backward "^[ \t]*\\([^ \t\n#]\\|#\\)" nil 'move) + (setq done (or (bobp) + (and (eq py-honor-comment-indentation t) + (save-excursion + (back-to-indentation) + (not (looking-at prefix-re)) + )) + (and (not (eq py-honor-comment-indentation t)) + (save-excursion + (back-to-indentation) + (and (not (looking-at prefix-re)) + (or (looking-at "[^#]") + (not (zerop (current-column))) + )) + )) + )) + ))) + ;; if we landed inside a string, go to the beginning of that + ;; string. this handles triple quoted, multi-line spanning + ;; strings. + (py-goto-beginning-of-tqs (nth 3 (parse-partial-sexp bod (point)))) + ;; now skip backward over continued lines + (setq placeholder (point)) + (py-goto-initial-line) + ;; we may *now* have landed in a TQS, so find the beginning of + ;; this string. + (py-goto-beginning-of-tqs + (save-excursion (nth 3 (parse-partial-sexp + placeholder (point))))) + (+ (current-indentation) + (if (py-statement-opens-block-p) + py-indent-offset + (if (and honor-block-close-p (py-statement-closes-block-p)) + (- py-indent-offset) + 0))) + ))))) + +(defun py-guess-indent-offset (&optional global) + "Guess a good value for, and change, `py-indent-offset'. + +By default, make a buffer-local copy of `py-indent-offset' with the +new value, so that other Python buffers are not affected. With +\\[universal-argument] (programmatically, optional argument GLOBAL), +change the global value of `py-indent-offset'. This affects all +Python buffers (that don't have their own buffer-local copy), both +those currently existing and those created later in the Emacs session. + +Some people use a different value for `py-indent-offset' than you use. +There's no excuse for such foolishness, but sometimes you have to deal +with their ugly code anyway. This function examines the file and sets +`py-indent-offset' to what it thinks it was when they created the +mess. + +Specifically, it searches forward from the statement containing point, +looking for a line that opens a block of code. `py-indent-offset' is +set to the difference in indentation between that line and the Python +statement following it. If the search doesn't succeed going forward, +it's tried again going backward." + (interactive "P") ; raw prefix arg + (let (new-value + (start (point)) + (restart (point)) + (found nil) + colon-indent) + (py-goto-initial-line) + (while (not (or found (eobp))) + (when (and (re-search-forward ":[ \t]*\\($\\|[#\\]\\)" nil 'move) + (not (py-in-literal restart))) + (setq restart (point)) + (py-goto-initial-line) + (if (py-statement-opens-block-p) + (setq found t) + (goto-char restart)))) + (unless found + (goto-char start) + (py-goto-initial-line) + (while (not (or found (bobp))) + (setq found (and + (re-search-backward ":[ \t]*\\($\\|[#\\]\\)" nil 'move) + (or (py-goto-initial-line) t) ; always true -- side effect + (py-statement-opens-block-p))))) + (setq colon-indent (current-indentation) + found (and found (zerop (py-next-statement 1))) + new-value (- (current-indentation) colon-indent)) + (goto-char start) + (if (not found) + (error "Sorry, couldn't guess a value for py-indent-offset") + (funcall (if global 'kill-local-variable 'make-local-variable) + 'py-indent-offset) + (setq py-indent-offset new-value) + (or noninteractive + (message "%s value of py-indent-offset set to %d" + (if global "Global" "Local") + py-indent-offset))) + )) + +(defun py-comment-indent-function () + "Python version of `comment-indent-function'." + ;; This is required when filladapt is turned off. Without it, when + ;; filladapt is not used, comments which start in column zero + ;; cascade one character to the right + (save-excursion + (beginning-of-line) + (let ((eol (py-point 'eol))) + (and comment-start-skip + (re-search-forward comment-start-skip eol t) + (setq eol (match-beginning 0))) + (goto-char eol) + (skip-chars-backward " \t") + (max comment-column (+ (current-column) (if (bolp) 0 1))) + ))) + +(defun py-narrow-to-defun (&optional class) + "Make text outside current defun invisible. +The defun visible is the one that contains point or follows point. +Optional CLASS is passed directly to `py-beginning-of-def-or-class'." + (interactive "P") + (save-excursion + (widen) + (py-end-of-def-or-class class) + (let ((end (point))) + (py-beginning-of-def-or-class class) + (narrow-to-region (point) end)))) + + +(defun py-shift-region (start end count) + "Indent lines from START to END by COUNT spaces." + (save-excursion + (goto-char end) + (beginning-of-line) + (setq end (point)) + (goto-char start) + (beginning-of-line) + (setq start (point)) + (indent-rigidly start end count))) + +(defun py-shift-region-left (start end &optional count) + "Shift region of Python code to the left. +The lines from the line containing the start of the current region up +to (but not including) the line containing the end of the region are +shifted to the left, by `py-indent-offset' columns. + +If a prefix argument is given, the region is instead shifted by that +many columns. With no active region, dedent only the current line. +You cannot dedent the region if any line is already at column zero." + (interactive + (let ((p (point)) + (m (mark)) + (arg current-prefix-arg)) + (if m + (list (min p m) (max p m) arg) + (list p (save-excursion (forward-line 1) (point)) arg)))) + ;; if any line is at column zero, don't shift the region + (save-excursion + (goto-char start) + (while (< (point) end) + (back-to-indentation) + (if (and (zerop (current-column)) + (not (looking-at "\\s *$"))) + (error "Region is at left edge")) + (forward-line 1))) + (py-shift-region start end (- (prefix-numeric-value + (or count py-indent-offset)))) + (py-keep-region-active)) + +(defun py-shift-region-right (start end &optional count) + "Shift region of Python code to the right. +The lines from the line containing the start of the current region up +to (but not including) the line containing the end of the region are +shifted to the right, by `py-indent-offset' columns. + +If a prefix argument is given, the region is instead shifted by that +many columns. With no active region, indent only the current line." + (interactive + (let ((p (point)) + (m (mark)) + (arg current-prefix-arg)) + (if m + (list (min p m) (max p m) arg) + (list p (save-excursion (forward-line 1) (point)) arg)))) + (py-shift-region start end (prefix-numeric-value + (or count py-indent-offset))) + (py-keep-region-active)) + +(defun py-indent-region (start end &optional indent-offset) + "Reindent a region of Python code. + +The lines from the line containing the start of the current region up +to (but not including) the line containing the end of the region are +reindented. If the first line of the region has a non-whitespace +character in the first column, the first line is left alone and the +rest of the region is reindented with respect to it. Else the entire +region is reindented with respect to the (closest code or indenting +comment) statement immediately preceding the region. + +This is useful when code blocks are moved or yanked, when enclosing +control structures are introduced or removed, or to reformat code +using a new value for the indentation offset. + +If a numeric prefix argument is given, it will be used as the value of +the indentation offset. Else the value of `py-indent-offset' will be +used. + +Warning: The region must be consistently indented before this function +is called! This function does not compute proper indentation from +scratch (that's impossible in Python), it merely adjusts the existing +indentation to be correct in context. + +Warning: This function really has no idea what to do with +non-indenting comment lines, and shifts them as if they were indenting +comment lines. Fixing this appears to require telepathy. + +Special cases: whitespace is deleted from blank lines; continuation +lines are shifted by the same amount their initial line was shifted, +in order to preserve their relative indentation with respect to their +initial line; and comment lines beginning in column 1 are ignored." + (interactive "*r\nP") ; region; raw prefix arg + (save-excursion + (goto-char end) (beginning-of-line) (setq end (point-marker)) + (goto-char start) (beginning-of-line) + (let ((py-indent-offset (prefix-numeric-value + (or indent-offset py-indent-offset))) + (indents '(-1)) ; stack of active indent levels + (target-column 0) ; column to which to indent + (base-shifted-by 0) ; amount last base line was shifted + (indent-base (if (looking-at "[ \t\n]") + (py-compute-indentation t) + 0)) + ci) + (while (< (point) end) + (setq ci (current-indentation)) + ;; figure out appropriate target column + (cond + ((or (eq (following-char) ?#) ; comment in column 1 + (looking-at "[ \t]*$")) ; entirely blank + (setq target-column 0)) + ((py-continuation-line-p) ; shift relative to base line + (setq target-column (+ ci base-shifted-by))) + (t ; new base line + (if (> ci (car indents)) ; going deeper; push it + (setq indents (cons ci indents)) + ;; else we should have seen this indent before + (setq indents (memq ci indents)) ; pop deeper indents + (if (null indents) + (error "Bad indentation in region, at line %d" + (save-restriction + (widen) + (1+ (count-lines 1 (point))))))) + (setq target-column (+ indent-base + (* py-indent-offset + (- (length indents) 2)))) + (setq base-shifted-by (- target-column ci)))) + ;; shift as needed + (if (/= ci target-column) + (progn + (delete-horizontal-space) + (indent-to target-column))) + (forward-line 1)))) + (set-marker end nil)) + +(defun py-comment-region (beg end &optional arg) + "Like `comment-region' but uses double hash (`#') comment starter." + (interactive "r\nP") + (let ((comment-start py-block-comment-prefix)) + (comment-region beg end arg))) + + +;; Functions for moving point +(defun py-previous-statement (count) + "Go to the start of the COUNTth preceding Python statement. +By default, goes to the previous statement. If there is no such +statement, goes to the first statement. Return count of statements +left to move. `Statements' do not include blank, comment, or +continuation lines." + (interactive "p") ; numeric prefix arg + (if (< count 0) (py-next-statement (- count)) + (py-goto-initial-line) + (let (start) + (while (and + (setq start (point)) ; always true -- side effect + (> count 0) + (zerop (forward-line -1)) + (py-goto-statement-at-or-above)) + (setq count (1- count))) + (if (> count 0) (goto-char start))) + count)) + +(defun py-next-statement (count) + "Go to the start of next Python statement. +If the statement at point is the i'th Python statement, goes to the +start of statement i+COUNT. If there is no such statement, goes to the +last statement. Returns count of statements left to move. `Statements' +do not include blank, comment, or continuation lines." + (interactive "p") ; numeric prefix arg + (if (< count 0) (py-previous-statement (- count)) + (beginning-of-line) + (let (start) + (while (and + (setq start (point)) ; always true -- side effect + (> count 0) + (py-goto-statement-below)) + (setq count (1- count))) + (if (> count 0) (goto-char start))) + count)) + +(defun py-goto-block-up (&optional nomark) + "Move up to start of current block. +Go to the statement that starts the smallest enclosing block; roughly +speaking, this will be the closest preceding statement that ends with a +colon and is indented less than the statement you started on. If +successful, also sets the mark to the starting point. + +`\\[py-mark-block]' can be used afterward to mark the whole code +block, if desired. + +If called from a program, the mark will not be set if optional argument +NOMARK is not nil." + (interactive) + (let ((start (point)) + (found nil) + initial-indent) + (py-goto-initial-line) + ;; if on blank or non-indenting comment line, use the preceding stmt + (if (looking-at "[ \t]*\\($\\|#[^ \t\n]\\)") + (progn + (py-goto-statement-at-or-above) + (setq found (py-statement-opens-block-p)))) + ;; search back for colon line indented less + (setq initial-indent (current-indentation)) + (if (zerop initial-indent) + ;; force fast exit + (goto-char (point-min))) + (while (not (or found (bobp))) + (setq found + (and + (re-search-backward ":[ \t]*\\($\\|[#\\]\\)" nil 'move) + (or (py-goto-initial-line) t) ; always true -- side effect + (< (current-indentation) initial-indent) + (py-statement-opens-block-p)))) + (if found + (progn + (or nomark (push-mark start)) + (back-to-indentation)) + (goto-char start) + (error "Enclosing block not found")))) + +(defun py-beginning-of-def-or-class (&optional class count) + "Move point to start of `def' or `class'. + +Searches back for the closest preceding `def'. If you supply a prefix +arg, looks for a `class' instead. The docs below assume the `def' +case; just substitute `class' for `def' for the other case. +Programmatically, if CLASS is `either', then moves to either `class' +or `def'. + +When second optional argument is given programmatically, move to the +COUNTth start of `def'. + +If point is in a `def' statement already, and after the `d', simply +moves point to the start of the statement. + +Otherwise (i.e. when point is not in a `def' statement, or at or +before the `d' of a `def' statement), searches for the closest +preceding `def' statement, and leaves point at its start. If no such +statement can be found, leaves point at the start of the buffer. + +Returns t iff a `def' statement is found by these rules. + +Note that doing this command repeatedly will take you closer to the +start of the buffer each time. + +To mark the current `def', see `\\[py-mark-def-or-class]'." + (interactive "P") ; raw prefix arg + (setq count (or count 1)) + (let ((at-or-before-p (<= (current-column) (current-indentation))) + (start-of-line (goto-char (py-point 'bol))) + (start-of-stmt (goto-char (py-point 'bos))) + (start-re (cond ((eq class 'either) "^[ \t]*\\(class\\|def\\)\\>") + (class "^[ \t]*class\\>") + (t "^[ \t]*def\\>"))) + ) + ;; searching backward + (if (and (< 0 count) + (or (/= start-of-stmt start-of-line) + (not at-or-before-p))) + (end-of-line)) + ;; search forward + (if (and (> 0 count) + (zerop (current-column)) + (looking-at start-re)) + (end-of-line)) + (if (re-search-backward start-re nil 'move count) + (goto-char (match-beginning 0))))) + +;; Backwards compatibility +(defalias 'beginning-of-python-def-or-class 'py-beginning-of-def-or-class) + +(defun py-end-of-def-or-class (&optional class count) + "Move point beyond end of `def' or `class' body. + +By default, looks for an appropriate `def'. If you supply a prefix +arg, looks for a `class' instead. The docs below assume the `def' +case; just substitute `class' for `def' for the other case. +Programmatically, if CLASS is `either', then moves to either `class' +or `def'. + +When second optional argument is given programmatically, move to the +COUNTth end of `def'. + +If point is in a `def' statement already, this is the `def' we use. + +Else, if the `def' found by `\\[py-beginning-of-def-or-class]' +contains the statement you started on, that's the `def' we use. + +Otherwise, we search forward for the closest following `def', and use that. + +If a `def' can be found by these rules, point is moved to the start of +the line immediately following the `def' block, and the position of the +start of the `def' is returned. + +Else point is moved to the end of the buffer, and nil is returned. + +Note that doing this command repeatedly will take you closer to the +end of the buffer each time. + +To mark the current `def', see `\\[py-mark-def-or-class]'." + (interactive "P") ; raw prefix arg + (if (and count (/= count 1)) + (py-beginning-of-def-or-class (- 1 count))) + (let ((start (progn (py-goto-initial-line) (point))) + (which (cond ((eq class 'either) "\\(class\\|def\\)") + (class "class") + (t "def"))) + (state 'not-found)) + ;; move point to start of appropriate def/class + (if (looking-at (concat "[ \t]*" which "\\>")) ; already on one + (setq state 'at-beginning) + ;; else see if py-beginning-of-def-or-class hits container + (if (and (py-beginning-of-def-or-class class) + (progn (py-goto-beyond-block) + (> (point) start))) + (setq state 'at-end) + ;; else search forward + (goto-char start) + (if (re-search-forward (concat "^[ \t]*" which "\\>") nil 'move) + (progn (setq state 'at-beginning) + (beginning-of-line))))) + (cond + ((eq state 'at-beginning) (py-goto-beyond-block) t) + ((eq state 'at-end) t) + ((eq state 'not-found) nil) + (t (error "Internal error in `py-end-of-def-or-class'"))))) + +;; Backwards compabitility +(defalias 'end-of-python-def-or-class 'py-end-of-def-or-class) + + +;; Functions for marking regions +(defun py-mark-block (&optional extend just-move) + "Mark following block of lines. With prefix arg, mark structure. +Easier to use than explain. It sets the region to an `interesting' +block of succeeding lines. If point is on a blank line, it goes down to +the next non-blank line. That will be the start of the region. The end +of the region depends on the kind of line at the start: + + - If a comment, the region will include all succeeding comment lines up + to (but not including) the next non-comment line (if any). + + - Else if a prefix arg is given, and the line begins one of these + structures: + + if elif else try except finally for while def class + + the region will be set to the body of the structure, including + following blocks that `belong' to it, but excluding trailing blank + and comment lines. E.g., if on a `try' statement, the `try' block + and all (if any) of the following `except' and `finally' blocks + that belong to the `try' structure will be in the region. Ditto + for if/elif/else, for/else and while/else structures, and (a bit + degenerate, since they're always one-block structures) def and + class blocks. + + - Else if no prefix argument is given, and the line begins a Python + block (see list above), and the block is not a `one-liner' (i.e., + the statement ends with a colon, not with code), the region will + include all succeeding lines up to (but not including) the next + code statement (if any) that's indented no more than the starting + line, except that trailing blank and comment lines are excluded. + E.g., if the starting line begins a multi-statement `def' + structure, the region will be set to the full function definition, + but without any trailing `noise' lines. + + - Else the region will include all succeeding lines up to (but not + including) the next blank line, or code or indenting-comment line + indented strictly less than the starting line. Trailing indenting + comment lines are included in this case, but not trailing blank + lines. + +A msg identifying the location of the mark is displayed in the echo +area; or do `\\[exchange-point-and-mark]' to flip down to the end. + +If called from a program, optional argument EXTEND plays the role of +the prefix arg, and if optional argument JUST-MOVE is not nil, just +moves to the end of the block (& does not set mark or display a msg)." + (interactive "P") ; raw prefix arg + (py-goto-initial-line) + ;; skip over blank lines + (while (and + (looking-at "[ \t]*$") ; while blank line + (not (eobp))) ; & somewhere to go + (forward-line 1)) + (if (eobp) + (error "Hit end of buffer without finding a non-blank stmt")) + (let ((initial-pos (point)) + (initial-indent (current-indentation)) + last-pos ; position of last stmt in region + (followers + '((if elif else) (elif elif else) (else) + (try except finally) (except except) (finally) + (for else) (while else) + (def) (class) ) ) + first-symbol next-symbol) + + (cond + ;; if comment line, suck up the following comment lines + ((looking-at "[ \t]*#") + (re-search-forward "^[ \t]*[^ \t#]" nil 'move) ; look for non-comment + (re-search-backward "^[ \t]*#") ; and back to last comment in block + (setq last-pos (point))) + + ;; else if line is a block line and EXTEND given, suck up + ;; the whole structure + ((and extend + (setq first-symbol (py-suck-up-first-keyword) ) + (assq first-symbol followers)) + (while (and + (or (py-goto-beyond-block) t) ; side effect + (forward-line -1) ; side effect + (setq last-pos (point)) ; side effect + (py-goto-statement-below) + (= (current-indentation) initial-indent) + (setq next-symbol (py-suck-up-first-keyword)) + (memq next-symbol (cdr (assq first-symbol followers)))) + (setq first-symbol next-symbol))) + + ;; else if line *opens* a block, search for next stmt indented <= + ((py-statement-opens-block-p) + (while (and + (setq last-pos (point)) ; always true -- side effect + (py-goto-statement-below) + (> (current-indentation) initial-indent) + ))) + + ;; else plain code line; stop at next blank line, or stmt or + ;; indenting comment line indented < + (t + (while (and + (setq last-pos (point)) ; always true -- side effect + (or (py-goto-beyond-final-line) t) + (not (looking-at "[ \t]*$")) ; stop at blank line + (or + (>= (current-indentation) initial-indent) + (looking-at "[ \t]*#[^ \t\n]"))) ; ignore non-indenting # + nil))) + + ;; skip to end of last stmt + (goto-char last-pos) + (py-goto-beyond-final-line) + + ;; set mark & display + (if just-move + () ; just return + (push-mark (point) 'no-msg) + (forward-line -1) + (message "Mark set after: %s" (py-suck-up-leading-text)) + (goto-char initial-pos)))) + +(defun py-mark-def-or-class (&optional class) + "Set region to body of def (or class, with prefix arg) enclosing point. +Pushes the current mark, then point, on the mark ring (all language +modes do this, but although it's handy it's never documented ...). + +In most Emacs language modes, this function bears at least a +hallucinogenic resemblance to `\\[py-end-of-def-or-class]' and +`\\[py-beginning-of-def-or-class]'. + +And in earlier versions of Python mode, all 3 were tightly connected. +Turned out that was more confusing than useful: the `goto start' and +`goto end' commands are usually used to search through a file, and +people expect them to act a lot like `search backward' and `search +forward' string-search commands. But because Python `def' and `class' +can nest to arbitrary levels, finding the smallest def containing +point cannot be done via a simple backward search: the def containing +point may not be the closest preceding def, or even the closest +preceding def that's indented less. The fancy algorithm required is +appropriate for the usual uses of this `mark' command, but not for the +`goto' variations. + +So the def marked by this command may not be the one either of the +`goto' commands find: If point is on a blank or non-indenting comment +line, moves back to start of the closest preceding code statement or +indenting comment line. If this is a `def' statement, that's the def +we use. Else searches for the smallest enclosing `def' block and uses +that. Else signals an error. + +When an enclosing def is found: The mark is left immediately beyond +the last line of the def block. Point is left at the start of the +def, except that: if the def is preceded by a number of comment lines +followed by (at most) one optional blank line, point is left at the +start of the comments; else if the def is preceded by a blank line, +point is left at its start. + +The intent is to mark the containing def/class and its associated +documentation, to make moving and duplicating functions and classes +pleasant." + (interactive "P") ; raw prefix arg + (let ((start (point)) + (which (cond ((eq class 'either) "\\(class\\|def\\)") + (class "class") + (t "def")))) + (push-mark start) + (if (not (py-go-up-tree-to-keyword which)) + (progn (goto-char start) + (error "Enclosing %s not found" + (if (eq class 'either) + "def or class" + which))) + ;; else enclosing def/class found + (setq start (point)) + (py-goto-beyond-block) + (push-mark (point)) + (goto-char start) + (if (zerop (forward-line -1)) ; if there is a preceding line + (progn + (if (looking-at "[ \t]*$") ; it's blank + (setq start (point)) ; so reset start point + (goto-char start)) ; else try again + (if (zerop (forward-line -1)) + (if (looking-at "[ \t]*#") ; a comment + ;; look back for non-comment line + ;; tricky: note that the regexp matches a blank + ;; line, cuz \n is in the 2nd character class + (and + (re-search-backward "^[ \t]*[^ \t#]" nil 'move) + (forward-line 1)) + ;; no comment, so go back + (goto-char start))))))) + (exchange-point-and-mark) + (py-keep-region-active)) + +;; ripped from cc-mode +(defun py-forward-into-nomenclature (&optional arg) + "Move forward to end of a nomenclature section or word. +With \\[universal-argument] (programmatically, optional argument ARG), +do it that many times. + +A `nomenclature' is a fancy way of saying AWordWithMixedCaseNotUnderscores." + (interactive "p") + (let ((case-fold-search nil)) + (if (> arg 0) + (re-search-forward + "\\(\\W\\|[_]\\)*\\([A-Z]*[a-z0-9]*\\)" + (point-max) t arg) + (while (and (< arg 0) + (re-search-backward + "\\(\\W\\|[a-z0-9]\\)[A-Z]+\\|\\(\\W\\|[_]\\)\\w+" + (point-min) 0)) + (forward-char 1) + (setq arg (1+ arg))))) + (py-keep-region-active)) + +(defun py-backward-into-nomenclature (&optional arg) + "Move backward to beginning of a nomenclature section or word. +With optional ARG, move that many times. If ARG is negative, move +forward. + +A `nomenclature' is a fancy way of saying AWordWithMixedCaseNotUnderscores." + (interactive "p") + (py-forward-into-nomenclature (- arg)) + (py-keep-region-active)) + + + +;; pdbtrack functions +(defun py-pdbtrack-toggle-stack-tracking (arg) + (interactive "P") + (if (not (get-buffer-process (current-buffer))) + (error "No process associated with buffer '%s'" (current-buffer))) + ;; missing or 0 is toggle, >0 turn on, <0 turn off + (if (or (not arg) + (zerop (setq arg (prefix-numeric-value arg)))) + (setq py-pdbtrack-do-tracking-p (not py-pdbtrack-do-tracking-p)) + (setq py-pdbtrack-do-tracking-p (> arg 0))) + (message "%sabled Python's pdbtrack" + (if py-pdbtrack-do-tracking-p "En" "Dis"))) + +(defun turn-on-pdbtrack () + (interactive) + (py-pdbtrack-toggle-stack-tracking 1)) + +(defun turn-off-pdbtrack () + (interactive) + (py-pdbtrack-toggle-stack-tracking 0)) + + + +;; Pychecker +(defun py-pychecker-run (command) + "*Run pychecker (default on the file currently visited)." + (interactive + (let ((default + (format "%s %s %s" py-pychecker-command + (mapconcat 'identity py-pychecker-command-args " ") + (buffer-file-name))) + (last (when py-pychecker-history + (let* ((lastcmd (car py-pychecker-history)) + (cmd (cdr (reverse (split-string lastcmd)))) + (newcmd (reverse (cons (buffer-file-name) cmd)))) + (mapconcat 'identity newcmd " "))))) + + (list + (if (fboundp 'read-shell-command) + (read-shell-command "Run pychecker like this: " + (if last + last + default) + 'py-pychecker-history) + (read-string "Run pychecker like this: " + (if last + last + default) + 'py-pychecker-history)) + ))) + (save-some-buffers (not py-ask-about-save) nil) + (compile-internal command "No more errors")) + + + +;; pydoc commands. The guts of this function is stolen from XEmacs's +;; symbol-near-point, but without the useless regexp-quote call on the +;; results, nor the interactive bit. Also, we've added the temporary +;; syntax table setting, which Skip originally had broken out into a +;; separate function. Note that Emacs doesn't have the original +;; function. +(defun py-symbol-near-point () + "Return the first textual item to the nearest point." + ;; alg stolen from etag.el + (save-excursion + (with-syntax-table py-dotted-expression-syntax-table + (if (or (bobp) (not (memq (char-syntax (char-before)) '(?w ?_)))) + (while (not (looking-at "\\sw\\|\\s_\\|\\'")) + (forward-char 1))) + (while (looking-at "\\sw\\|\\s_") + (forward-char 1)) + (if (re-search-backward "\\sw\\|\\s_" nil t) + (progn (forward-char 1) + (buffer-substring (point) + (progn (forward-sexp -1) + (while (looking-at "\\s'") + (forward-char 1)) + (point)))) + nil)))) + +(defun py-help-at-point () + "Get help from Python based on the symbol nearest point." + (interactive) + (let* ((sym (py-symbol-near-point)) + (base (substring sym 0 (or (search "." sym :from-end t) 0))) + cmd) + (if (not (equal base "")) + (setq cmd (concat "import " base "\n"))) + (setq cmd (concat "import pydoc\n" + cmd + "try: pydoc.help('" sym "')\n" + "except: print 'No help available on:', \"" sym "\"")) + (message cmd) + (py-execute-string cmd) + (set-buffer "*Python Output*") + ;; BAW: Should we really be leaving the output buffer in help-mode? + (help-mode))) + + + +;; Documentation functions + +;; dump the long form of the mode blurb; does the usual doc escapes, +;; plus lines of the form ^[vc]:name$ to suck variable & command docs +;; out of the right places, along with the keys they're on & current +;; values +(defun py-dump-help-string (str) + (with-output-to-temp-buffer "*Help*" + (let ((locals (buffer-local-variables)) + funckind funcname func funcdoc + (start 0) mstart end + keys ) + (while (string-match "^%\\([vc]\\):\\(.+\\)\n" str start) + (setq mstart (match-beginning 0) end (match-end 0) + funckind (substring str (match-beginning 1) (match-end 1)) + funcname (substring str (match-beginning 2) (match-end 2)) + func (intern funcname)) + (princ (substitute-command-keys (substring str start mstart))) + (cond + ((equal funckind "c") ; command + (setq funcdoc (documentation func) + keys (concat + "Key(s): " + (mapconcat 'key-description + (where-is-internal func py-mode-map) + ", ")))) + ((equal funckind "v") ; variable + (setq funcdoc (documentation-property func 'variable-documentation) + keys (if (assq func locals) + (concat + "Local/Global values: " + (prin1-to-string (symbol-value func)) + " / " + (prin1-to-string (default-value func))) + (concat + "Value: " + (prin1-to-string (symbol-value func)))))) + (t ; unexpected + (error "Error in py-dump-help-string, tag `%s'" funckind))) + (princ (format "\n-> %s:\t%s\t%s\n\n" + (if (equal funckind "c") "Command" "Variable") + funcname keys)) + (princ funcdoc) + (terpri) + (setq start end)) + (princ (substitute-command-keys (substring str start)))) + (print-help-return-message))) + +(defun py-describe-mode () + "Dump long form of Python-mode docs." + (interactive) + (py-dump-help-string "Major mode for editing Python files. +Knows about Python indentation, tokens, comments and continuation lines. +Paragraphs are separated by blank lines only. + +Major sections below begin with the string `@'; specific function and +variable docs begin with `->'. + +@EXECUTING PYTHON CODE + +\\[py-execute-import-or-reload]\timports or reloads the file in the Python interpreter +\\[py-execute-buffer]\tsends the entire buffer to the Python interpreter +\\[py-execute-region]\tsends the current region +\\[py-execute-def-or-class]\tsends the current function or class definition +\\[py-execute-string]\tsends an arbitrary string +\\[py-shell]\tstarts a Python interpreter window; this will be used by +\tsubsequent Python execution commands +%c:py-execute-import-or-reload +%c:py-execute-buffer +%c:py-execute-region +%c:py-execute-def-or-class +%c:py-execute-string +%c:py-shell + +@VARIABLES + +py-indent-offset\tindentation increment +py-block-comment-prefix\tcomment string used by comment-region + +py-python-command\tshell command to invoke Python interpreter +py-temp-directory\tdirectory used for temp files (if needed) + +py-beep-if-tab-change\tring the bell if tab-width is changed +%v:py-indent-offset +%v:py-block-comment-prefix +%v:py-python-command +%v:py-temp-directory +%v:py-beep-if-tab-change + +@KINDS OF LINES + +Each physical line in the file is either a `continuation line' (the +preceding line ends with a backslash that's not part of a comment, or +the paren/bracket/brace nesting level at the start of the line is +non-zero, or both) or an `initial line' (everything else). + +An initial line is in turn a `blank line' (contains nothing except +possibly blanks or tabs), a `comment line' (leftmost non-blank +character is `#'), or a `code line' (everything else). + +Comment Lines + +Although all comment lines are treated alike by Python, Python mode +recognizes two kinds that act differently with respect to indentation. + +An `indenting comment line' is a comment line with a blank, tab or +nothing after the initial `#'. The indentation commands (see below) +treat these exactly as if they were code lines: a line following an +indenting comment line will be indented like the comment line. All +other comment lines (those with a non-whitespace character immediately +following the initial `#') are `non-indenting comment lines', and +their indentation is ignored by the indentation commands. + +Indenting comment lines are by far the usual case, and should be used +whenever possible. Non-indenting comment lines are useful in cases +like these: + +\ta = b # a very wordy single-line comment that ends up being +\t #... continued onto another line + +\tif a == b: +##\t\tprint 'panic!' # old code we've `commented out' +\t\treturn a + +Since the `#...' and `##' comment lines have a non-whitespace +character following the initial `#', Python mode ignores them when +computing the proper indentation for the next line. + +Continuation Lines and Statements + +The Python-mode commands generally work on statements instead of on +individual lines, where a `statement' is a comment or blank line, or a +code line and all of its following continuation lines (if any) +considered as a single logical unit. The commands in this mode +generally (when it makes sense) automatically move to the start of the +statement containing point, even if point happens to be in the middle +of some continuation line. + + +@INDENTATION + +Primarily for entering new code: +\t\\[indent-for-tab-command]\t indent line appropriately +\t\\[py-newline-and-indent]\t insert newline, then indent +\t\\[py-electric-backspace]\t reduce indentation, or delete single character + +Primarily for reindenting existing code: +\t\\[py-guess-indent-offset]\t guess py-indent-offset from file content; change locally +\t\\[universal-argument] \\[py-guess-indent-offset]\t ditto, but change globally + +\t\\[py-indent-region]\t reindent region to match its context +\t\\[py-shift-region-left]\t shift region left by py-indent-offset +\t\\[py-shift-region-right]\t shift region right by py-indent-offset + +Unlike most programming languages, Python uses indentation, and only +indentation, to specify block structure. Hence the indentation supplied +automatically by Python-mode is just an educated guess: only you know +the block structure you intend, so only you can supply correct +indentation. + +The \\[indent-for-tab-command] and \\[py-newline-and-indent] keys try to suggest plausible indentation, based on +the indentation of preceding statements. E.g., assuming +py-indent-offset is 4, after you enter +\tif a > 0: \\[py-newline-and-indent] +the cursor will be moved to the position of the `_' (_ is not a +character in the file, it's just used here to indicate the location of +the cursor): +\tif a > 0: +\t _ +If you then enter `c = d' \\[py-newline-and-indent], the cursor will move +to +\tif a > 0: +\t c = d +\t _ +Python-mode cannot know whether that's what you intended, or whether +\tif a > 0: +\t c = d +\t_ +was your intent. In general, Python-mode either reproduces the +indentation of the (closest code or indenting-comment) preceding +statement, or adds an extra py-indent-offset blanks if the preceding +statement has `:' as its last significant (non-whitespace and non- +comment) character. If the suggested indentation is too much, use +\\[py-electric-backspace] to reduce it. + +Continuation lines are given extra indentation. If you don't like the +suggested indentation, change it to something you do like, and Python- +mode will strive to indent later lines of the statement in the same way. + +If a line is a continuation line by virtue of being in an unclosed +paren/bracket/brace structure (`list', for short), the suggested +indentation depends on whether the current line contains the first item +in the list. If it does, it's indented py-indent-offset columns beyond +the indentation of the line containing the open bracket. If you don't +like that, change it by hand. The remaining items in the list will mimic +whatever indentation you give to the first item. + +If a line is a continuation line because the line preceding it ends with +a backslash, the third and following lines of the statement inherit their +indentation from the line preceding them. The indentation of the second +line in the statement depends on the form of the first (base) line: if +the base line is an assignment statement with anything more interesting +than the backslash following the leftmost assigning `=', the second line +is indented two columns beyond that `='. Else it's indented to two +columns beyond the leftmost solid chunk of non-whitespace characters on +the base line. + +Warning: indent-region should not normally be used! It calls \\[indent-for-tab-command] +repeatedly, and as explained above, \\[indent-for-tab-command] can't guess the block +structure you intend. +%c:indent-for-tab-command +%c:py-newline-and-indent +%c:py-electric-backspace + + +The next function may be handy when editing code you didn't write: +%c:py-guess-indent-offset + + +The remaining `indent' functions apply to a region of Python code. They +assume the block structure (equals indentation, in Python) of the region +is correct, and alter the indentation in various ways while preserving +the block structure: +%c:py-indent-region +%c:py-shift-region-left +%c:py-shift-region-right + +@MARKING & MANIPULATING REGIONS OF CODE + +\\[py-mark-block]\t mark block of lines +\\[py-mark-def-or-class]\t mark smallest enclosing def +\\[universal-argument] \\[py-mark-def-or-class]\t mark smallest enclosing class +\\[comment-region]\t comment out region of code +\\[universal-argument] \\[comment-region]\t uncomment region of code +%c:py-mark-block +%c:py-mark-def-or-class +%c:comment-region + +@MOVING POINT + +\\[py-previous-statement]\t move to statement preceding point +\\[py-next-statement]\t move to statement following point +\\[py-goto-block-up]\t move up to start of current block +\\[py-beginning-of-def-or-class]\t move to start of def +\\[universal-argument] \\[py-beginning-of-def-or-class]\t move to start of class +\\[py-end-of-def-or-class]\t move to end of def +\\[universal-argument] \\[py-end-of-def-or-class]\t move to end of class + +The first two move to one statement beyond the statement that contains +point. A numeric prefix argument tells them to move that many +statements instead. Blank lines, comment lines, and continuation lines +do not count as `statements' for these commands. So, e.g., you can go +to the first code statement in a file by entering +\t\\[beginning-of-buffer]\t to move to the top of the file +\t\\[py-next-statement]\t to skip over initial comments and blank lines +Or do `\\[py-previous-statement]' with a huge prefix argument. +%c:py-previous-statement +%c:py-next-statement +%c:py-goto-block-up +%c:py-beginning-of-def-or-class +%c:py-end-of-def-or-class + +@LITTLE-KNOWN EMACS COMMANDS PARTICULARLY USEFUL IN PYTHON MODE + +`\\[indent-new-comment-line]' is handy for entering a multi-line comment. + +`\\[set-selective-display]' with a `small' prefix arg is ideally suited for viewing the +overall class and def structure of a module. + +`\\[back-to-indentation]' moves point to a line's first non-blank character. + +`\\[indent-relative]' is handy for creating odd indentation. + +@OTHER EMACS HINTS + +If you don't like the default value of a variable, change its value to +whatever you do like by putting a `setq' line in your .emacs file. +E.g., to set the indentation increment to 4, put this line in your +.emacs: +\t(setq py-indent-offset 4) +To see the value of a variable, do `\\[describe-variable]' and enter the variable +name at the prompt. + +When entering a key sequence like `C-c C-n', it is not necessary to +release the CONTROL key after doing the `C-c' part -- it suffices to +press the CONTROL key, press and release `c' (while still holding down +CONTROL), press and release `n' (while still holding down CONTROL), & +then release CONTROL. + +Entering Python mode calls with no arguments the value of the variable +`python-mode-hook', if that value exists and is not nil; for backward +compatibility it also tries `py-mode-hook'; see the `Hooks' section of +the Elisp manual for details. + +Obscure: When python-mode is first loaded, it looks for all bindings +to newline-and-indent in the global keymap, and shadows them with +local bindings to py-newline-and-indent.")) + +(require 'info-look) +;; The info-look package does not always provide this function (it +;; appears this is the case with XEmacs 21.1) +(when (fboundp 'info-lookup-maybe-add-help) + (info-lookup-maybe-add-help + :mode 'python-mode + :regexp "[a-zA-Z0-9_]+" + :doc-spec '(("(python-lib)Module Index") + ("(python-lib)Class-Exception-Object Index") + ("(python-lib)Function-Method-Variable Index") + ("(python-lib)Miscellaneous Index"))) + ) + + +;; Helper functions +(defvar py-parse-state-re + (concat + "^[ \t]*\\(elif\\|else\\|while\\|def\\|class\\)\\>" + "\\|" + "^[^ #\t\n]")) + +(defun py-parse-state () + "Return the parse state at point (see `parse-partial-sexp' docs)." + (save-excursion + (let ((here (point)) + pps done) + (while (not done) + ;; back up to the first preceding line (if any; else start of + ;; buffer) that begins with a popular Python keyword, or a + ;; non- whitespace and non-comment character. These are good + ;; places to start parsing to see whether where we started is + ;; at a non-zero nesting level. It may be slow for people who + ;; write huge code blocks or huge lists ... tough beans. + (re-search-backward py-parse-state-re nil 'move) + (beginning-of-line) + ;; In XEmacs, we have a much better way to test for whether + ;; we're in a triple-quoted string or not. Emacs does not + ;; have this built-in function, which is its loss because + ;; without scanning from the beginning of the buffer, there's + ;; no accurate way to determine this otherwise. + (save-excursion (setq pps (parse-partial-sexp (point) here))) + ;; make sure we don't land inside a triple-quoted string + (setq done (or (not (nth 3 pps)) + (bobp))) + ;; Just go ahead and short circuit the test back to the + ;; beginning of the buffer. This will be slow, but not + ;; nearly as slow as looping through many + ;; re-search-backwards. + (if (not done) + (goto-char (point-min)))) + pps))) + +(defun py-nesting-level () + "Return the buffer position of the last unclosed enclosing list. +If nesting level is zero, return nil." + (let ((status (py-parse-state))) + (if (zerop (car status)) + nil ; not in a nest + (car (cdr status))))) ; char# of open bracket + +(defun py-backslash-continuation-line-p () + "Return t iff preceding line ends with backslash that is not in a comment." + (save-excursion + (beginning-of-line) + (and + ;; use a cheap test first to avoid the regexp if possible + ;; use 'eq' because char-after may return nil + (eq (char-after (- (point) 2)) ?\\ ) + ;; make sure; since eq test passed, there is a preceding line + (forward-line -1) ; always true -- side effect + (looking-at py-continued-re)))) + +(defun py-continuation-line-p () + "Return t iff current line is a continuation line." + (save-excursion + (beginning-of-line) + (or (py-backslash-continuation-line-p) + (py-nesting-level)))) + +(defun py-goto-beginning-of-tqs (delim) + "Go to the beginning of the triple quoted string we find ourselves in. +DELIM is the TQS string delimiter character we're searching backwards +for." + (let ((skip (and delim (make-string 1 delim))) + (continue t)) + (when skip + (save-excursion + (while continue + (py-safe (search-backward skip)) + (setq continue (and (not (bobp)) + (= (char-before) ?\\)))) + (if (and (= (char-before) delim) + (= (char-before (1- (point))) delim)) + (setq skip (make-string 3 delim)))) + ;; we're looking at a triple-quoted string + (py-safe (search-backward skip))))) + +(defun py-goto-initial-line () + "Go to the initial line of the current statement. +Usually this is the line we're on, but if we're on the 2nd or +following lines of a continuation block, we need to go up to the first +line of the block." + ;; Tricky: We want to avoid quadratic-time behavior for long + ;; continued blocks, whether of the backslash or open-bracket + ;; varieties, or a mix of the two. The following manages to do that + ;; in the usual cases. + ;; + ;; Also, if we're sitting inside a triple quoted string, this will + ;; drop us at the line that begins the string. + (let (open-bracket-pos) + (while (py-continuation-line-p) + (beginning-of-line) + (if (py-backslash-continuation-line-p) + (while (py-backslash-continuation-line-p) + (forward-line -1)) + ;; else zip out of nested brackets/braces/parens + (while (setq open-bracket-pos (py-nesting-level)) + (goto-char open-bracket-pos))))) + (beginning-of-line)) + +(defun py-goto-beyond-final-line () + "Go to the point just beyond the fine line of the current statement. +Usually this is the start of the next line, but if this is a +multi-line statement we need to skip over the continuation lines." + ;; Tricky: Again we need to be clever to avoid quadratic time + ;; behavior. + ;; + ;; XXX: Not quite the right solution, but deals with multi-line doc + ;; strings + (if (looking-at (concat "[ \t]*\\(" py-stringlit-re "\\)")) + (goto-char (match-end 0))) + ;; + (forward-line 1) + (let (state) + (while (and (py-continuation-line-p) + (not (eobp))) + ;; skip over the backslash flavor + (while (and (py-backslash-continuation-line-p) + (not (eobp))) + (forward-line 1)) + ;; if in nest, zip to the end of the nest + (setq state (py-parse-state)) + (if (and (not (zerop (car state))) + (not (eobp))) + (progn + (parse-partial-sexp (point) (point-max) 0 nil state) + (forward-line 1)))))) + +(defun py-statement-opens-block-p () + "Return t iff the current statement opens a block. +I.e., iff it ends with a colon that is not in a comment. Point should +be at the start of a statement." + (save-excursion + (let ((start (point)) + (finish (progn (py-goto-beyond-final-line) (1- (point)))) + (searching t) + (answer nil) + state) + (goto-char start) + (while searching + ;; look for a colon with nothing after it except whitespace, and + ;; maybe a comment + (if (re-search-forward ":\\([ \t]\\|\\\\\n\\)*\\(#.*\\)?$" + finish t) + (if (eq (point) finish) ; note: no `else' clause; just + ; keep searching if we're not at + ; the end yet + ;; sure looks like it opens a block -- but it might + ;; be in a comment + (progn + (setq searching nil) ; search is done either way + (setq state (parse-partial-sexp start + (match-beginning 0))) + (setq answer (not (nth 4 state))))) + ;; search failed: couldn't find another interesting colon + (setq searching nil))) + answer))) + +(defun py-statement-closes-block-p () + "Return t iff the current statement closes a block. +I.e., if the line starts with `return', `raise', `break', `continue', +and `pass'. This doesn't catch embedded statements." + (let ((here (point))) + (py-goto-initial-line) + (back-to-indentation) + (prog1 + (looking-at (concat py-block-closing-keywords-re "\\>")) + (goto-char here)))) + +(defun py-goto-beyond-block () + "Go to point just beyond the final line of block begun by the current line. +This is the same as where `py-goto-beyond-final-line' goes unless +we're on colon line, in which case we go to the end of the block. +Assumes point is at the beginning of the line." + (if (py-statement-opens-block-p) + (py-mark-block nil 'just-move) + (py-goto-beyond-final-line))) + +(defun py-goto-statement-at-or-above () + "Go to the start of the first statement at or preceding point. +Return t if there is such a statement, otherwise nil. `Statement' +does not include blank lines, comments, or continuation lines." + (py-goto-initial-line) + (if (looking-at py-blank-or-comment-re) + ;; skip back over blank & comment lines + ;; note: will skip a blank or comment line that happens to be + ;; a continuation line too + (if (re-search-backward "^[ \t]*[^ \t#\n]" nil t) + (progn (py-goto-initial-line) t) + nil) + t)) + +(defun py-goto-statement-below () + "Go to start of the first statement following the statement containing point. +Return t if there is such a statement, otherwise nil. `Statement' +does not include blank lines, comments, or continuation lines." + (beginning-of-line) + (let ((start (point))) + (py-goto-beyond-final-line) + (while (and + (or (looking-at py-blank-or-comment-re) + (py-in-literal)) + (not (eobp))) + (forward-line 1)) + (if (eobp) + (progn (goto-char start) nil) + t))) + +(defun py-go-up-tree-to-keyword (key) + "Go to begining of statement starting with KEY, at or preceding point. + +KEY is a regular expression describing a Python keyword. Skip blank +lines and non-indenting comments. If the statement found starts with +KEY, then stop, otherwise go back to first enclosing block starting +with KEY. If successful, leave point at the start of the KEY line and +return t. Otherwise, leav point at an undefined place and return nil." + ;; skip blanks and non-indenting # + (py-goto-initial-line) + (while (and + (looking-at "[ \t]*\\($\\|#[^ \t\n]\\)") + (zerop (forward-line -1))) ; go back + nil) + (py-goto-initial-line) + (let* ((re (concat "[ \t]*" key "\\b")) + (case-fold-search nil) ; let* so looking-at sees this + (found (looking-at re)) + (dead nil)) + (while (not (or found dead)) + (condition-case nil ; in case no enclosing block + (py-goto-block-up 'no-mark) + (error (setq dead t))) + (or dead (setq found (looking-at re)))) + (beginning-of-line) + found)) + +(defun py-suck-up-leading-text () + "Return string in buffer from start of indentation to end of line. +Prefix with \"...\" if leading whitespace was skipped." + (save-excursion + (back-to-indentation) + (concat + (if (bolp) "" "...") + (buffer-substring (point) (progn (end-of-line) (point)))))) + +(defun py-suck-up-first-keyword () + "Return first keyword on the line as a Lisp symbol. +`Keyword' is defined (essentially) as the regular expression +([a-z]+). Returns nil if none was found." + (let ((case-fold-search nil)) + (if (looking-at "[ \t]*\\([a-z]+\\)\\b") + (intern (buffer-substring (match-beginning 1) (match-end 1))) + nil))) + +(defun py-current-defun () + "Python value for `add-log-current-defun-function'. +This tells add-log.el how to find the current function/method/variable." + (save-excursion + (if (re-search-backward py-defun-start-re nil t) + (or (match-string 3) + (let ((method (match-string 2))) + (if (and (not (zerop (length (match-string 1)))) + (re-search-backward py-class-start-re nil t)) + (concat (match-string 1) "." method) + method))) + nil))) + + +(defconst py-help-address "python-mode@python.org" + "Address accepting submission of bug reports.") + +(defun py-version () + "Echo the current version of `python-mode' in the minibuffer." + (interactive) + (message "Using `python-mode' version %s" py-version) + (py-keep-region-active)) + +;; only works under Emacs 19 +;(eval-when-compile +; (require 'reporter)) + +(defun py-submit-bug-report (enhancement-p) + "Submit via mail a bug report on `python-mode'. +With \\[universal-argument] (programmatically, argument ENHANCEMENT-P +non-nil) just submit an enhancement request." + (interactive + (list (not (y-or-n-p + "Is this a bug report (hit `n' to send other comments)? ")))) + (let ((reporter-prompt-for-summary-p (if enhancement-p + "(Very) brief summary: " + t))) + (require 'reporter) + (reporter-submit-bug-report + py-help-address ;address + (concat "python-mode " py-version) ;pkgname + ;; varlist + (if enhancement-p nil + '(py-python-command + py-indent-offset + py-block-comment-prefix + py-temp-directory + py-beep-if-tab-change)) + nil ;pre-hooks + nil ;post-hooks + "Dear Barry,") ;salutation + (if enhancement-p nil + (set-mark (point)) + (insert +"Please replace this text with a sufficiently large code sample\n\ +and an exact recipe so that I can reproduce your problem. Failure\n\ +to do so may mean a greater delay in fixing your bug.\n\n") + (exchange-point-and-mark) + (py-keep-region-active)))) + + +(defun py-kill-emacs-hook () + "Delete files in `py-file-queue'. +These are Python temporary files awaiting execution." + (mapcar #'(lambda (filename) + (py-safe (delete-file filename))) + py-file-queue)) + +;; arrange to kill temp files when Emacs exists +(add-hook 'kill-emacs-hook 'py-kill-emacs-hook) +(add-hook 'comint-output-filter-functions 'py-pdbtrack-track-stack-file) + +;; Add a designator to the minor mode strings +(or (assq 'py-pdbtrack-minor-mode-string minor-mode-alist) + (push '(py-pdbtrack-is-tracking-p py-pdbtrack-minor-mode-string) + minor-mode-alist)) + + + +;;; paragraph and string filling code from Bernhard Herzog +;;; see http://mail.python.org/pipermail/python-list/2002-May/103189.html + +(defun py-fill-comment (&optional justify) + "Fill the comment paragraph around point" + (let (;; Non-nil if the current line contains a comment. + has-comment + + ;; If has-comment, the appropriate fill-prefix for the comment. + comment-fill-prefix) + + ;; Figure out what kind of comment we are looking at. + (save-excursion + (beginning-of-line) + (cond + ;; A line with nothing but a comment on it? + ((looking-at "[ \t]*#[# \t]*") + (setq has-comment t + comment-fill-prefix (buffer-substring (match-beginning 0) + (match-end 0)))) + + ;; A line with some code, followed by a comment? Remember that the hash + ;; which starts the comment shouldn't be part of a string or character. + ((progn + (while (not (looking-at "#\\|$")) + (skip-chars-forward "^#\n\"'\\") + (cond + ((eq (char-after (point)) ?\\) (forward-char 2)) + ((memq (char-after (point)) '(?\" ?')) (forward-sexp 1)))) + (looking-at "#+[\t ]*")) + (setq has-comment t) + (setq comment-fill-prefix + (concat (make-string (current-column) ? ) + (buffer-substring (match-beginning 0) (match-end 0))))))) + + (if (not has-comment) + (fill-paragraph justify) + + ;; Narrow to include only the comment, and then fill the region. + (save-restriction + (narrow-to-region + + ;; Find the first line we should include in the region to fill. + (save-excursion + (while (and (zerop (forward-line -1)) + (looking-at "^[ \t]*#"))) + + ;; We may have gone to far. Go forward again. + (or (looking-at "^[ \t]*#") + (forward-line 1)) + (point)) + + ;; Find the beginning of the first line past the region to fill. + (save-excursion + (while (progn (forward-line 1) + (looking-at "^[ \t]*#"))) + (point))) + + ;; Lines with only hashes on them can be paragraph boundaries. + (let ((paragraph-start (concat paragraph-start "\\|[ \t#]*$")) + (paragraph-separate (concat paragraph-separate "\\|[ \t#]*$")) + (fill-prefix comment-fill-prefix)) + ;;(message "paragraph-start %S paragraph-separate %S" + ;;paragraph-start paragraph-separate) + (fill-paragraph justify)))) + t)) + + +(defun py-fill-string (start &optional justify) + "Fill the paragraph around (point) in the string starting at start" + ;; basic strategy: narrow to the string and call the default + ;; implementation + (let (;; the start of the string's contents + string-start + ;; the end of the string's contents + string-end + ;; length of the string's delimiter + delim-length + ;; The string delimiter + delim + ) + + (save-excursion + (goto-char start) + (if (looking-at "\\('''\\|\"\"\"\\|'\\|\"\\)\\\\?\n?") + (setq string-start (match-end 0) + delim-length (- (match-end 1) (match-beginning 1)) + delim (buffer-substring-no-properties (match-beginning 1) + (match-end 1))) + (error "The parameter start is not the beginning of a python string")) + + ;; if the string is the first token on a line and doesn't start with + ;; a newline, fill as if the string starts at the beginning of the + ;; line. this helps with one line docstrings + (save-excursion + (beginning-of-line) + (and (/= (char-before string-start) ?\n) + (looking-at (concat "[ \t]*" delim)) + (setq string-start (point)))) + + (forward-sexp (if (= delim-length 3) 2 1)) + + ;; with both triple quoted strings and single/double quoted strings + ;; we're now directly behind the first char of the end delimiter + ;; (this doesn't work correctly when the triple quoted string + ;; contains the quote mark itself). The end of the string's contents + ;; is one less than point + (setq string-end (1- (point)))) + + ;; Narrow to the string's contents and fill the current paragraph + (save-restriction + (narrow-to-region string-start string-end) + (let ((ends-with-newline (= (char-before (point-max)) ?\n))) + (fill-paragraph justify) + (if (and (not ends-with-newline) + (= (char-before (point-max)) ?\n)) + ;; the default fill-paragraph implementation has inserted a + ;; newline at the end. Remove it again. + (save-excursion + (goto-char (point-max)) + (delete-char -1))))) + + ;; return t to indicate that we've done our work + t)) + +(defun py-fill-paragraph (&optional justify) + "Like \\[fill-paragraph], but handle Python comments and strings. +If any of the current line is a comment, fill the comment or the +paragraph of it that point is in, preserving the comment's indentation +and initial `#'s. +If point is inside a string, narrow to that string and fill. +" + (interactive "P") + (let* ((bod (py-point 'bod)) + (pps (parse-partial-sexp bod (point)))) + (cond + ;; are we inside a comment or on a line with only whitespace before + ;; the comment start? + ((or (nth 4 pps) + (save-excursion (beginning-of-line) (looking-at "[ \t]*#"))) + (py-fill-comment justify)) + ;; are we inside a string? + ((nth 3 pps) + (py-fill-string (nth 8 pps))) + ;; otherwise use the default + (t + (fill-paragraph justify))))) + + + +(provide 'python-mode) +;;; python-mode.el ends here diff --git a/sys/src/cmd/python/Misc/python.man b/sys/src/cmd/python/Misc/python.man new file mode 100644 index 000000000..865d6497c --- /dev/null +++ b/sys/src/cmd/python/Misc/python.man @@ -0,0 +1,397 @@ +.TH PYTHON "1" "$Date: 2005-03-21 01:16:03 +1100 (Mon, 21 Mar 2005) $" + +./" To view this file while editing, run it through groff: +./" groff -Tascii -man python.man | less + +.SH NAME +python \- an interpreted, interactive, object-oriented programming language +.SH SYNOPSIS +.B python +[ +.B \-d +] +[ +.B \-E +] +[ +.B \-h +] +[ +.B \-i +] +[ +.B \-m +.I module-name +] +[ +.B \-O +] +.br + [ +.B -Q +.I argument +] +[ +.B \-S +] +[ +.B \-t +] +[ +.B \-u +] +.br + [ +.B \-v +] +[ +.B \-V +] +[ +.B \-W +.I argument +] +[ +.B \-x +] +.br + [ +.B \-c +.I command +| +.I script +| +\- +] +[ +.I arguments +] +.SH DESCRIPTION +Python is an interpreted, interactive, object-oriented programming +language that combines remarkable power with very clear syntax. +For an introduction to programming in Python you are referred to the +Python Tutorial. +The Python Library Reference documents built-in and standard types, +constants, functions and modules. +Finally, the Python Reference Manual describes the syntax and +semantics of the core language in (perhaps too) much detail. +(These documents may be located via the +.B "INTERNET RESOURCES" +below; they may be installed on your system as well.) +.PP +Python's basic power can be extended with your own modules written in +C or C++. +On most systems such modules may be dynamically loaded. +Python is also adaptable as an extension language for existing +applications. +See the internal documentation for hints. +.PP +Documentation for installed Python modules and packages can be +viewed by running the +.B pydoc +program. +.SH COMMAND LINE OPTIONS +.TP +.BI "\-c " command +Specify the command to execute (see next section). +This terminates the option list (following options are passed as +arguments to the command). +.TP +.B \-d +Turn on parser debugging output (for wizards only, depending on +compilation options). +.TP +.B \-E +Ignore environment variables like PYTHONPATH and PYTHONHOME that modify +the behavior of the interpreter. +.TP +.B \-h +Prints the usage for the interpreter executable and exits. +.TP +.B \-i +When a script is passed as first argument or the \fB\-c\fP option is +used, enter interactive mode after executing the script or the +command. It does not read the $PYTHONSTARTUP file. This can be +useful to inspect global variables or a stack trace when a script +raises an exception. +.TP +.BI "\-m " module-name +Searches +.I sys.path +for the named module and runs the corresponding +.I .py +file as a script. +.TP +.B \-O +Turn on basic optimizations. This changes the filename extension for +compiled (bytecode) files from +.I .pyc +to \fI.pyo\fP. Given twice, causes docstrings to be discarded. +.TP +.BI "\-Q " argument +Division control; see PEP 238. The argument must be one of "old" (the +default, int/int and long/long return an int or long), "new" (new +division semantics, i.e. int/int and long/long returns a float), +"warn" (old division semantics with a warning for int/int and +long/long), or "warnall" (old division semantics with a warning for +all use of the division operator). For a use of "warnall", see the +Tools/scripts/fixdiv.py script. +.TP +.B \-S +Disable the import of the module +.I site +and the site-dependent manipulations of +.I sys.path +that it entails. +.TP +.B \-t +Issue a warning when a source file mixes tabs and spaces for +indentation in a way that makes it depend on the worth of a tab +expressed in spaces. Issue an error when the option is given twice. +.TP +.B \-u +Force stdin, stdout and stderr to be totally unbuffered. On systems +where it matters, also put stdin, stdout and stderr in binary mode. +Note that there is internal buffering in xreadlines(), readlines() and +file-object iterators ("for line in sys.stdin") which is not +influenced by this option. To work around this, you will want to use +"sys.stdin.readline()" inside a "while 1:" loop. +.TP +.B \-v +Print a message each time a module is initialized, showing the place +(filename or built-in module) from which it is loaded. When given +twice, print a message for each file that is checked for when +searching for a module. Also provides information on module cleanup +at exit. +.TP +.B \-V +Prints the Python version number of the executable and exits. +.TP +.BI "\-W " argument +Warning control. Python sometimes prints warning message to +.IR sys.stderr . +A typical warning message has the following form: +.IB file ":" line ": " category ": " message. +By default, each warning is printed once for each source line where it +occurs. This option controls how often warnings are printed. +Multiple +.B \-W +options may be given; when a warning matches more than one +option, the action for the last matching option is performed. +Invalid +.B \-W +options are ignored (a warning message is printed about invalid +options when the first warning is issued). Warnings can also be +controlled from within a Python program using the +.I warnings +module. + +The simplest form of +.I argument +is one of the following +.I action +strings (or a unique abbreviation): +.B ignore +to ignore all warnings; +.B default +to explicitly request the default behavior (printing each warning once +per source line); +.B all +to print a warning each time it occurs (this may generate many +messages if a warning is triggered repeatedly for the same source +line, such as inside a loop); +.B module +to print each warning only only the first time it occurs in each +module; +.B once +to print each warning only the first time it occurs in the program; or +.B error +to raise an exception instead of printing a warning message. + +The full form of +.I argument +is +.IB action : message : category : module : line. +Here, +.I action +is as explained above but only applies to messages that match the +remaining fields. Empty fields match all values; trailing empty +fields may be omitted. The +.I message +field matches the start of the warning message printed; this match is +case-insensitive. The +.I category +field matches the warning category. This must be a class name; the +match test whether the actual warning category of the message is a +subclass of the specified warning category. The full class name must +be given. The +.I module +field matches the (fully-qualified) module name; this match is +case-sensitive. The +.I line +field matches the line number, where zero matches all line numbers and +is thus equivalent to an omitted line number. +.TP +.B \-x +Skip the first line of the source. This is intended for a DOS +specific hack only. Warning: the line numbers in error messages will +be off by one! +.SH INTERPRETER INTERFACE +The interpreter interface resembles that of the UNIX shell: when +called with standard input connected to a tty device, it prompts for +commands and executes them until an EOF is read; when called with a +file name argument or with a file as standard input, it reads and +executes a +.I script +from that file; +when called with +.B \-c +.I command, +it executes the Python statement(s) given as +.I command. +Here +.I command +may contain multiple statements separated by newlines. +Leading whitespace is significant in Python statements! +In non-interactive mode, the entire input is parsed before it is +executed. +.PP +If available, the script name and additional arguments thereafter are +passed to the script in the Python variable +.I sys.argv , +which is a list of strings (you must first +.I import sys +to be able to access it). +If no script name is given, +.I sys.argv[0] +is an empty string; if +.B \-c +is used, +.I sys.argv[0] +contains the string +.I '-c'. +Note that options interpreted by the Python interpreter itself +are not placed in +.I sys.argv. +.PP +In interactive mode, the primary prompt is `>>>'; the second prompt +(which appears when a command is not complete) is `...'. +The prompts can be changed by assignment to +.I sys.ps1 +or +.I sys.ps2. +The interpreter quits when it reads an EOF at a prompt. +When an unhandled exception occurs, a stack trace is printed and +control returns to the primary prompt; in non-interactive mode, the +interpreter exits after printing the stack trace. +The interrupt signal raises the +.I Keyboard\%Interrupt +exception; other UNIX signals are not caught (except that SIGPIPE is +sometimes ignored, in favor of the +.I IOError +exception). Error messages are written to stderr. +.SH FILES AND DIRECTORIES +These are subject to difference depending on local installation +conventions; ${prefix} and ${exec_prefix} are installation-dependent +and should be interpreted as for GNU software; they may be the same. +The default for both is \fI/usr/local\fP. +.IP \fI${exec_prefix}/bin/python\fP +Recommended location of the interpreter. +.PP +.I ${prefix}/lib/python<version> +.br +.I ${exec_prefix}/lib/python<version> +.RS +Recommended locations of the directories containing the standard +modules. +.RE +.PP +.I ${prefix}/include/python<version> +.br +.I ${exec_prefix}/include/python<version> +.RS +Recommended locations of the directories containing the include files +needed for developing Python extensions and embedding the +interpreter. +.RE +.IP \fI~/.pythonrc.py\fP +User-specific initialization file loaded by the \fIuser\fP module; +not used by default or by most applications. +.SH ENVIRONMENT VARIABLES +.IP PYTHONHOME +Change the location of the standard Python libraries. By default, the +libraries are searched in ${prefix}/lib/python<version> and +${exec_prefix}/lib/python<version>, where ${prefix} and ${exec_prefix} +are installation-dependent directories, both defaulting to +\fI/usr/local\fP. When $PYTHONHOME is set to a single directory, its value +replaces both ${prefix} and ${exec_prefix}. To specify different values +for these, set $PYTHONHOME to ${prefix}:${exec_prefix}. +.IP PYTHONPATH +Augments the default search path for module files. +The format is the same as the shell's $PATH: one or more directory +pathnames separated by colons. +Non-existent directories are silently ignored. +The default search path is installation dependent, but generally +begins with ${prefix}/lib/python<version> (see PYTHONHOME above). +The default search path is always appended to $PYTHONPATH. +If a script argument is given, the directory containing the script is +inserted in the path in front of $PYTHONPATH. +The search path can be manipulated from within a Python program as the +variable +.I sys.path . +.IP PYTHONSTARTUP +If this is the name of a readable file, the Python commands in that +file are executed before the first prompt is displayed in interactive +mode. +The file is executed in the same name space where interactive commands +are executed so that objects defined or imported in it can be used +without qualification in the interactive session. +You can also change the prompts +.I sys.ps1 +and +.I sys.ps2 +in this file. +.IP PYTHONY2K +Set this to a non-empty string to cause the \fItime\fP module to +require dates specified as strings to include 4-digit years, otherwise +2-digit years are converted based on rules described in the \fItime\fP +module documentation. +.IP PYTHONOPTIMIZE +If this is set to a non-empty string it is equivalent to specifying +the \fB\-O\fP option. If set to an integer, it is equivalent to +specifying \fB\-O\fP multiple times. +.IP PYTHONDEBUG +If this is set to a non-empty string it is equivalent to specifying +the \fB\-d\fP option. If set to an integer, it is equivalent to +specifying \fB\-d\fP multiple times. +.IP PYTHONINSPECT +If this is set to a non-empty string it is equivalent to specifying +the \fB\-i\fP option. +.IP PYTHONUNBUFFERED +If this is set to a non-empty string it is equivalent to specifying +the \fB\-u\fP option. +.IP PYTHONVERBOSE +If this is set to a non-empty string it is equivalent to specifying +the \fB\-v\fP option. If set to an integer, it is equivalent to +specifying \fB\-v\fP multiple times. +.SH AUTHOR +The Python Software Foundation: http://www.python.org/psf +.SH INTERNET RESOURCES +Main website: http://www.python.org/ +.br +Documentation: http://docs.python.org/ +.br +Community website: http://starship.python.net/ +.br +Developer resources: http://www.python.org/dev/ +.br +FTP: ftp://ftp.python.org/pub/python/ +.br +Module repository: http://www.vex.net/parnassus/ +.br +Newsgroups: comp.lang.python, comp.lang.python.announce +.SH LICENSING +Python is distributed under an Open Source license. See the file +"LICENSE" in the Python source distribution for information on terms & +conditions for accessing and otherwise using Python and for a +DISCLAIMER OF ALL WARRANTIES. diff --git a/sys/src/cmd/python/Misc/setuid-prog.c b/sys/src/cmd/python/Misc/setuid-prog.c new file mode 100644 index 000000000..d850b47bc --- /dev/null +++ b/sys/src/cmd/python/Misc/setuid-prog.c @@ -0,0 +1,176 @@ +/* + Template for a setuid program that calls a script. + + The script should be in an unwritable directory and should itself + be unwritable. In fact all parent directories up to the root + should be unwritable. The script must not be setuid, that's what + this program is for. + + This is a template program. You need to fill in the name of the + script that must be executed. This is done by changing the + definition of FULL_PATH below. + + There are also some rules that should be adhered to when writing + the script itself. + + The first and most important rule is to never, ever trust that the + user of the program will behave properly. Program defensively. + Check your arguments for reasonableness. If the user is allowed to + create files, check the names of the files. If the program depends + on argv[0] for the action it should perform, check it. + + Assuming the script is a Bourne shell script, the first line of the + script should be + #!/bin/sh - + The - is important, don't omit it. If you're using esh, the first + line should be + #!/usr/local/bin/esh -f + and for ksh, the first line should be + #!/usr/local/bin/ksh -p + The script should then set the variable IFS to the string + consisting of <space>, <tab>, and <newline>. After this (*not* + before!), the PATH variable should be set to a reasonable value and + exported. Do not expect the PATH to have a reasonable value, so do + not trust the old value of PATH. You should then set the umask of + the program by calling + umask 077 # or 022 if you want the files to be readable + If you plan to change directories, you should either unset CDPATH + or set it to a good value. Setting CDPATH to just ``.'' (dot) is a + good idea. + If, for some reason, you want to use csh, the first line should be + #!/bin/csh -fb + You should then set the path variable to something reasonable, + without trusting the inherited path. Here too, you should set the + umask using the command + umask 077 # or 022 if you want the files to be readable +*/ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> + +/* CONFIGURATION SECTION */ + +#ifndef FULL_PATH /* so that this can be specified from the Makefile */ +/* Uncomment the following line: +#define FULL_PATH "/full/path/of/script" +* Then comment out the #error line. */ +#error "You must define FULL_PATH somewhere" +#endif +#ifndef UMASK +#define UMASK 077 +#endif + +/* END OF CONFIGURATION SECTION */ + +#if defined(__STDC__) && defined(__sgi) +#define environ _environ +#endif + +/* don't change def_IFS */ +char def_IFS[] = "IFS= \t\n"; +/* you may want to change def_PATH, but you should really change it in */ +/* your script */ +#ifdef __sgi +char def_PATH[] = "PATH=/usr/bsd:/usr/bin:/bin:/usr/local/bin:/usr/sbin"; +#else +char def_PATH[] = "PATH=/usr/ucb:/usr/bin:/bin:/usr/local/bin"; +#endif +/* don't change def_CDPATH */ +char def_CDPATH[] = "CDPATH=."; +/* don't change def_ENV */ +char def_ENV[] = "ENV=:"; + +/* + This function changes all environment variables that start with LD_ + into variables that start with XD_. This is important since we + don't want the script that is executed to use any funny shared + libraries. + + The other changes to the environment are, strictly speaking, not + needed here. They can safely be done in the script. They are done + here because we don't trust the script writer (just like the script + writer shouldn't trust the user of the script). + If IFS is set in the environment, set it to space,tab,newline. + If CDPATH is set in the environment, set it to ``.''. + Set PATH to a reasonable default. +*/ +void +clean_environ(void) +{ + char **p; + extern char **environ; + + for (p = environ; *p; p++) { + if (strncmp(*p, "LD_", 3) == 0) + **p = 'X'; + else if (strncmp(*p, "_RLD", 4) == 0) + **p = 'X'; + else if (strncmp(*p, "PYTHON", 6) == 0) + **p = 'X'; + else if (strncmp(*p, "IFS=", 4) == 0) + *p = def_IFS; + else if (strncmp(*p, "CDPATH=", 7) == 0) + *p = def_CDPATH; + else if (strncmp(*p, "ENV=", 4) == 0) + *p = def_ENV; + } + putenv(def_PATH); +} + +int +main(int argc, char **argv) +{ + struct stat statb; + gid_t egid = getegid(); + uid_t euid = geteuid(); + + /* + Sanity check #1. + This check should be made compile-time, but that's not possible. + If you're sure that you specified a full path name for FULL_PATH, + you can omit this check. + */ + if (FULL_PATH[0] != '/') { + fprintf(stderr, "%s: %s is not a full path name\n", argv[0], + FULL_PATH); + fprintf(stderr, "You can only use this wrapper if you\n"); + fprintf(stderr, "compile it with an absolute path.\n"); + exit(1); + } + + /* + Sanity check #2. + Check that the owner of the script is equal to either the + effective uid or the super user. + */ + if (stat(FULL_PATH, &statb) < 0) { + perror("stat"); + exit(1); + } + if (statb.st_uid != 0 && statb.st_uid != euid) { + fprintf(stderr, "%s: %s has the wrong owner\n", argv[0], + FULL_PATH); + fprintf(stderr, "The script should be owned by root,\n"); + fprintf(stderr, "and shouldn't be writeable by anyone.\n"); + exit(1); + } + + if (setregid(egid, egid) < 0) + perror("setregid"); + if (setreuid(euid, euid) < 0) + perror("setreuid"); + + clean_environ(); + + umask(UMASK); + + while (**argv == '-') /* don't let argv[0] start with '-' */ + (*argv)++; + execv(FULL_PATH, argv); + fprintf(stderr, "%s: could not execute the script\n", argv[0]); + exit(1); +} diff --git a/sys/src/cmd/python/Misc/valgrind-python.supp b/sys/src/cmd/python/Misc/valgrind-python.supp new file mode 100644 index 000000000..4a6710e74 --- /dev/null +++ b/sys/src/cmd/python/Misc/valgrind-python.supp @@ -0,0 +1,349 @@ +# +# This is a valgrind suppression file that should be used when using valgrind. +# +# Here's an example of running valgrind: +# +# cd python/dist/src +# valgrind --tool=memcheck --suppressions=Misc/valgrind-python.supp \ +# ./python -E -tt ./Lib/test/regrtest.py -u bsddb,network +# +# You must edit Objects/obmalloc.c and uncomment Py_USING_MEMORY_DEBUGGER +# to use the preferred suppressions with Py_ADDRESS_IN_RANGE. +# +# If you do not want to recompile Python, you can uncomment +# suppressions for PyObject_Free and PyObject_Realloc. +# +# See Misc/README.valgrind for more information. + +# all tool names: Addrcheck,Memcheck,cachegrind,helgrind,massif +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Addr4 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 4 + Memcheck:Value4 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Invalid read of size 8 (x86_64 aka amd64) + Memcheck:Value8 + fun:Py_ADDRESS_IN_RANGE +} + +{ + ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value + Memcheck:Cond + fun:Py_ADDRESS_IN_RANGE +} + +# +# Leaks (including possible leaks) +# Hmmm, I wonder if this masks some real leaks. I think it does. +# Will need to fix that. +# + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:realloc + fun:_PyObject_GC_Resize + fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_New + fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING +} + +{ + Handle PyMalloc confusing valgrind (possibly leaked) + Memcheck:Leak + fun:malloc + fun:_PyObject_GC_NewVar + fun:COMMENT_THIS_LINE_TO_DISABLE_LEAK_WARNING +} + +# +# Non-python specific leaks +# + +{ + Handle pthread issue (possibly leaked) + Memcheck:Leak + fun:calloc + fun:allocate_dtv + fun:_dl_allocate_tls_storage + fun:_dl_allocate_tls +} + +{ + Handle pthread issue (possibly leaked) + Memcheck:Leak + fun:memalign + fun:_dl_allocate_tls_storage + fun:_dl_allocate_tls +} + +###{ +### ADDRESS_IN_RANGE/Invalid read of size 4 +### Memcheck:Addr4 +### fun:PyObject_Free +###} +### +###{ +### ADDRESS_IN_RANGE/Invalid read of size 4 +### Memcheck:Value4 +### fun:PyObject_Free +###} +### +###{ +### ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value +### Memcheck:Cond +### fun:PyObject_Free +###} + +###{ +### ADDRESS_IN_RANGE/Invalid read of size 4 +### Memcheck:Addr4 +### fun:PyObject_Realloc +###} +### +###{ +### ADDRESS_IN_RANGE/Invalid read of size 4 +### Memcheck:Value4 +### fun:PyObject_Realloc +###} +### +###{ +### ADDRESS_IN_RANGE/Conditional jump or move depends on uninitialised value +### Memcheck:Cond +### fun:PyObject_Realloc +###} + +### +### All the suppressions below are for errors that occur within libraries +### that Python uses. The problems to not appear to be related to Python's +### use of the libraries. +### + +{ + Generic gentoo ld problems + Memcheck:Cond + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so + obj:/lib/ld-2.3.4.so +} + +{ + DBM problems, see test_dbm + Memcheck:Param + write(buf) + fun:write + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_close +} + +{ + DBM problems, see test_dbm + Memcheck:Value8 + fun:memmove + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_store + fun:dbm_ass_sub +} + +{ + DBM problems, see test_dbm + Memcheck:Cond + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_store + fun:dbm_ass_sub +} + +{ + DBM problems, see test_dbm + Memcheck:Cond + fun:memmove + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + obj:/usr/lib/libdb1.so.2 + fun:dbm_store + fun:dbm_ass_sub +} + +{ + GDBM problems, see test_gdbm + Memcheck:Param + write(buf) + fun:write + fun:gdbm_open + +} + +{ + ZLIB problems, see test_gzip + Memcheck:Cond + obj:/lib/libz.so.1.2.3 + obj:/lib/libz.so.1.2.3 + fun:deflate +} + +{ + Avoid problems w/readline doing a putenv and leaking on exit + Memcheck:Leak + fun:malloc + fun:xmalloc + fun:sh_set_lines_and_columns + fun:_rl_get_screen_size + fun:_rl_init_terminal_io + obj:/lib/libreadline.so.4.3 + fun:rl_initialize +} + +### +### These occur from somewhere within the SSL, when running +### test_socket_sll. They are too general to leave on by default. +### +###{ +### somewhere in SSL stuff +### Memcheck:Cond +### fun:memset +###} +###{ +### somewhere in SSL stuff +### Memcheck:Value4 +### fun:memset +###} +### +###{ +### somewhere in SSL stuff +### Memcheck:Cond +### fun:MD5_Update +###} +### +###{ +### somewhere in SSL stuff +### Memcheck:Value4 +### fun:MD5_Update +###} + +# +# All of these problems come from using test_socket_ssl +# +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_bin2bn +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_num_bits_word +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:BN_num_bits_word +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_mod_exp_mont_word +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BN_mod_exp_mont +} + +{ + from test_socket_ssl + Memcheck:Param + write(buf) + fun:write + obj:/usr/lib/libcrypto.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:RSA_verify +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:RSA_verify +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:DES_set_key_unchecked +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:DES_encrypt2 +} + +{ + from test_socket_ssl + Memcheck:Cond + obj:/usr/lib/libssl.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Value4 + obj:/usr/lib/libssl.so.0.9.7 +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:BUF_MEM_grow_clean +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:memcpy + fun:ssl3_read_bytes +} + +{ + from test_socket_ssl + Memcheck:Cond + fun:SHA1_Update +} + +{ + from test_socket_ssl + Memcheck:Value4 + fun:SHA1_Update +} + + diff --git a/sys/src/cmd/python/Misc/vgrindefs b/sys/src/cmd/python/Misc/vgrindefs new file mode 100644 index 000000000..bc6eba175 --- /dev/null +++ b/sys/src/cmd/python/Misc/vgrindefs @@ -0,0 +1,10 @@ +# vgrind is a pretty-printer that takes source code and outputs +# eye-pleasing postscript. The entry below should be added to your +# local vgrindefs file. Contributed by Neale Pickett <neale@lanl.gov>. + +python|Python|py:\ + :pb=^\d?(def|class)\d\p(\d|\\|\(|\:):\ + :cb=#:ce=$:sb=":se=\e":lb=':le=\e':\ + :kw=assert and break class continue def del elif else except\ + exec finally for from global if import in is lambda not or\ + pass print raise return try while yield: diff --git a/sys/src/cmd/python/Modules/Setup b/sys/src/cmd/python/Modules/Setup new file mode 100644 index 000000000..93aac7057 --- /dev/null +++ b/sys/src/cmd/python/Modules/Setup @@ -0,0 +1,488 @@ +# -*- makefile -*- +# The file Setup is used by the makesetup script to construct the files +# Makefile and config.c, from Makefile.pre and config.c.in, +# respectively. The file Setup itself is initially copied from +# Setup.dist; once it exists it will not be overwritten, so you can edit +# Setup to your heart's content. Note that Makefile.pre is created +# from Makefile.pre.in by the toplevel configure script. + +# (VPATH notes: Setup and Makefile.pre are in the build directory, as +# are Makefile and config.c; the *.in and *.dist files are in the source +# directory.) + +# Each line in this file describes one or more optional modules. +# Modules enabled here will not be compiled by the setup.py script, +# so the file can be used to override setup.py's behavior. + +# Lines have the following structure: +# +# <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...] +# +# <sourcefile> is anything ending in .c (.C, .cc, .c++ are C++ files) +# <cpparg> is anything starting with -I, -D, -U or -C +# <library> is anything ending in .a or beginning with -l or -L +# <module> is anything else but should be a valid Python +# identifier (letters, digits, underscores, beginning with non-digit) +# +# (As the makesetup script changes, it may recognize some other +# arguments as well, e.g. *.so and *.sl as libraries. See the big +# case statement in the makesetup script.) +# +# Lines can also have the form +# +# <name> = <value> +# +# which defines a Make variable definition inserted into Makefile.in +# +# Finally, if a line contains just the word "*shared*" (without the +# quotes but with the stars), then the following modules will not be +# built statically. The build process works like this: +# +# 1. Build all modules that are declared as static in Modules/Setup, +# combine them into libpythonxy.a, combine that into python. +# 2. Build all modules that are listed as shared in Modules/Setup. +# 3. Invoke setup.py. That builds all modules that +# a) are not builtin, and +# b) are not listed in Modules/Setup, and +# c) can be build on the target +# +# Therefore, modules declared to be shared will not be +# included in the config.c file, nor in the list of objects to be +# added to the library archive, and their linker options won't be +# added to the linker options. Rules to create their .o files and +# their shared libraries will still be added to the Makefile, and +# their names will be collected in the Make variable SHAREDMODS. This +# is used to build modules as shared libraries. (They can be +# installed using "make sharedinstall", which is implied by the +# toplevel "make install" target.) (For compatibility, +# *noconfig* has the same effect as *shared*.) +# +# In addition, *static* explicitly declares the following modules to +# be static. Lines containing "*static*" and "*shared*" may thus +# alternate throughout this file. + +# NOTE: As a standard policy, as many modules as can be supported by a +# platform should be present. The distribution comes with all modules +# enabled that are supported by most platforms and don't require you +# to ftp sources from elsewhere. + + +# Some special rules to define PYTHONPATH. +# Edit the definitions below to indicate which options you are using. +# Don't add any whitespace or comments! + +# Directories where library files get installed. +# DESTLIB is for Python modules; MACHDESTLIB for shared libraries. +DESTLIB=$(LIBDEST) +MACHDESTLIB=$(BINLIBDEST) + +# NOTE: all the paths are now relative to the prefix that is computed +# at run time! + +# Standard path -- don't edit. +# No leading colon since this is the first entry. +# Empty since this is now just the runtime prefix. +DESTPATH= + +# Site specific path components -- should begin with : if non-empty +SITEPATH= + +# Standard path components for test modules +TESTPATH= + +# Path components for machine- or system-dependent modules and shared libraries +MACHDEPPATH=:plat-$(MACHDEP) +EXTRAMACHDEPPATH= + +# Path component for the Tkinter-related modules +# The TKPATH variable is always enabled, to save you the effort. +TKPATH=:lib-tk + +COREPYTHONPATH=$(DESTPATH)$(SITEPATH)$(TESTPATH)$(MACHDEPPATH)$(EXTRAMACHDEPPATH)$(TKPATH) +PYTHONPATH=$(COREPYTHONPATH) + + +# The modules listed here can't be built as shared libraries for +# various reasons; therefore they are listed here instead of in the +# normal order. + +# This only contains the minimal set of modules required to run the +# setup.py script in the root of the Python source tree. + +posix posixmodule.c # posix (UNIX) system calls +errno errnomodule.c # posix (UNIX) errno values +pwd pwdmodule.c # this is needed to find out the user's home dir + # if $HOME is not set +_sre _sre.c # Fredrik Lundh's new regular expressions +_codecs _codecsmodule.c # access to the builtin codecs and codec registry +_ssl _ssl.c + +# The zipimport module is always imported at startup. Having it as a +# builtin module avoids some bootstrapping problems and reduces overhead. +zipimport zipimport.c + +# The rest of the modules listed in this file are all commented out by +# default. Usually they can be detected and built as dynamically +# loaded modules by the new setup.py script added in Python 2.1. If +# you're on a platform that doesn't support dynamic loading, want to +# compile modules statically into the Python binary, or need to +# specify some odd set of compiler switches, you can uncomment the +# appropriate lines below. + +# ====================================================================== + +# The Python symtable module depends on .h files that setup.py doesn't track +_symtable symtablemodule.c + +# The SGI specific GL module: + +GLHACK=-Dclear=__GLclear +#gl glmodule.c cgensupport.c -I$(srcdir) $(GLHACK) -lgl -lX11 + +# Pure module. Cannot be linked dynamically. +# -DWITH_QUANTIFY, -DWITH_PURIFY, or -DWITH_ALL_PURE +#WHICH_PURE_PRODUCTS=-DWITH_ALL_PURE +#PURE_INCLS=-I/usr/local/include +#PURE_STUBLIBS=-L/usr/local/lib -lpurify_stubs -lquantify_stubs +#pure puremodule.c $(WHICH_PURE_PRODUCTS) $(PURE_INCLS) $(PURE_STUBLIBS) + +# Uncommenting the following line tells makesetup that all following +# modules are to be built as shared libraries (see above for more +# detail; also note that *static* reverses this effect): + +#*shared* + +# GNU readline. Unlike previous Python incarnations, GNU readline is +# now incorporated in an optional module, configured in the Setup file +# instead of by a configure script switch. You may have to insert a +# -L option pointing to the directory where libreadline.* lives, +# and you may have to change -ltermcap to -ltermlib or perhaps remove +# it, depending on your system -- see the GNU readline instructions. +# It's okay for this to be a shared library, too. + +#readline readline.c -lreadline -ltermcap + + +# Modules that should always be present (non UNIX dependent): + +#array arraymodule.c # array objects +#cmath cmathmodule.c # -lm # complex math library functions +#math mathmodule.c # -lm # math library functions, e.g. sin() +#_struct _struct.c # binary structure packing/unpacking +#time timemodule.c # -lm # time operations and variables +#operator operator.c # operator.add() and similar goodies +#_weakref _weakref.c # basic weak reference support +#_testcapi _testcapimodule.c # Python C API test module +#_random _randommodule.c # Random number generator +#collections collectionsmodule.c # Container types +#itertools itertoolsmodule.c # Functions creating iterators for efficient looping +#strop stropmodule.c # String manipulations + +#unicodedata unicodedata.c # static Unicode character database + +# access to ISO C locale support +#_locale _localemodule.c # -lintl + + +# Modules with some UNIX dependencies -- on by default: +# (If you have a really backward UNIX, select and socket may not be +# supported...) + +#fcntl fcntlmodule.c # fcntl(2) and ioctl(2) +#spwd spwdmodule.c # spwd(3) +#grp grpmodule.c # grp(3) +#select selectmodule.c # select(2); not on ancient System V + +# Memory-mapped files (also works on Win32). +#mmap mmapmodule.c + +# CSV file helper +#_csv _csv.c + +# Socket module helper for socket(2) +#_socket socketmodule.c + +# Socket module helper for SSL support; you must comment out the other +# socket line above, and possibly edit the SSL variable: +#SSL=/usr/local/ssl +#_ssl _ssl.c \ +# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ +# -L$(SSL)/lib -lssl -lcrypto + +# The crypt module is now disabled by default because it breaks builds +# on many systems (where -lcrypt is needed), e.g. Linux (I believe). +# +# First, look at Setup.config; configure may have set this for you. + +#crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems + + +# Some more UNIX dependent modules -- off by default, since these +# are not supported by all UNIX systems: + +#nis nismodule.c -lnsl # Sun yellow pages -- not everywhere +#termios termios.c # Steen Lumholt's termios module +#resource resource.c # Jeremy Hylton's rlimit interface + + +# Multimedia modules -- off by default. +# These don't work for 64-bit platforms!!! +# #993173 says audioop works on 64-bit platforms, though. +# These represent audio samples or images as strings: + +#audioop audioop.c # Operations on audio samples +#imageop imageop.c # Operations on images +#rgbimg rgbimgmodule.c # Read SGI RGB image files (but coded portably) + + +# Note that the _md5 and _sha modules are normally only built if the +# system does not have the OpenSSL libs containing an optimized version. + +# The _md5 module implements the RSA Data Security, Inc. MD5 +# Message-Digest Algorithm, described in RFC 1321. The necessary files +# md5.c and md5.h are included here. + +#_md5 md5module.c md5.c + + +# The _sha module implements the SHA checksum algorithm. +# (NIST's Secure Hash Algorithm.) +#_sha shamodule.c + + +# SGI IRIX specific modules -- off by default. + +# These module work on any SGI machine: + +# *** gl must be enabled higher up in this file *** +#fm fmmodule.c $(GLHACK) -lfm -lgl # Font Manager +#sgi sgimodule.c # sgi.nap() and a few more + +# This module requires the header file +# /usr/people/4Dgifts/iristools/include/izoom.h: +#imgfile imgfile.c -limage -lgutil -lgl -lm # Image Processing Utilities + + +# These modules require the Multimedia Development Option (I think): + +#al almodule.c -laudio # Audio Library +#cd cdmodule.c -lcdaudio -lds -lmediad # CD Audio Library +#cl clmodule.c -lcl -lawareaudio # Compression Library +#sv svmodule.c yuvconvert.c -lsvideo -lXext -lX11 # Starter Video + + +# The FORMS library, by Mark Overmars, implements user interface +# components such as dialogs and buttons using SGI's GL and FM +# libraries. You must ftp the FORMS library separately from +# ftp://ftp.cs.ruu.nl/pub/SGI/FORMS. It was tested with FORMS 2.2a. +# NOTE: if you want to be able to use FORMS and curses simultaneously +# (or both link them statically into the same binary), you must +# compile all of FORMS with the cc option "-Dclear=__GLclear". + +# The FORMS variable must point to the FORMS subdirectory of the forms +# toplevel directory: + +#FORMS=/ufs/guido/src/forms/FORMS +#fl flmodule.c -I$(FORMS) $(GLHACK) $(FORMS)/libforms.a -lfm -lgl + + +# SunOS specific modules -- off by default: + +#sunaudiodev sunaudiodev.c + + +# A Linux specific module -- off by default; this may also work on +# some *BSDs. + +#linuxaudiodev linuxaudiodev.c + + +# George Neville-Neil's timing module: + +#timing timingmodule.c + + +# The _tkinter module. +# +# The command for _tkinter is long and site specific. Please +# uncomment and/or edit those parts as indicated. If you don't have a +# specific extension (e.g. Tix or BLT), leave the corresponding line +# commented out. (Leave the trailing backslashes in! If you +# experience strange errors, you may want to join all uncommented +# lines and remove the backslashes -- the backslash interpretation is +# done by the shell's "read" command and it may not be implemented on +# every system. + +# *** Always uncomment this (leave the leading underscore in!): +# _tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \ +# *** Uncomment and edit to reflect where your Tcl/Tk libraries are: +# -L/usr/local/lib \ +# *** Uncomment and edit to reflect where your Tcl/Tk headers are: +# -I/usr/local/include \ +# *** Uncomment and edit to reflect where your X11 header files are: +# -I/usr/X11R6/include \ +# *** Or uncomment this for Solaris: +# -I/usr/openwin/include \ +# *** Uncomment and edit for Tix extension only: +# -DWITH_TIX -ltix8.1.8.2 \ +# *** Uncomment and edit for BLT extension only: +# -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \ +# *** Uncomment and edit for PIL (TkImaging) extension only: +# (See http://www.pythonware.com/products/pil/ for more info) +# -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \ +# *** Uncomment and edit for TOGL extension only: +# -DWITH_TOGL togl.c \ +# *** Uncomment and edit to reflect your Tcl/Tk versions: +# -ltk8.2 -ltcl8.2 \ +# *** Uncomment and edit to reflect where your X11 libraries are: +# -L/usr/X11R6/lib \ +# *** Or uncomment this for Solaris: +# -L/usr/openwin/lib \ +# *** Uncomment these for TOGL extension only: +# -lGL -lGLU -lXext -lXmu \ +# *** Uncomment for AIX: +# -lld \ +# *** Always uncomment this; X11 libraries to link with: +# -lX11 + +# Lance Ellinghaus's syslog module +#syslog syslogmodule.c # syslog daemon interface + + +# Curses support, requring the System V version of curses, often +# provided by the ncurses library. e.g. on Linux, link with -lncurses +# instead of -lcurses). +# +# First, look at Setup.config; configure may have set this for you. + +#_curses _cursesmodule.c -lcurses -ltermcap +# Wrapper for the panel library that's part of ncurses and SYSV curses. +#_curses_panel _curses_panel.c -lpanel -lncurses + + +# Generic (SunOS / SVR4) dynamic loading module. +# This is not needed for dynamic loading of Python modules -- +# it is a highly experimental and dangerous device for calling +# *arbitrary* C functions in *arbitrary* shared libraries: + +#dl dlmodule.c + + +# Modules that provide persistent dictionary-like semantics. You will +# probably want to arrange for at least one of them to be available on +# your machine, though none are defined by default because of library +# dependencies. The Python module anydbm.py provides an +# implementation independent wrapper for these; dumbdbm.py provides +# similar functionality (but slower of course) implemented in Python. + +# The standard Unix dbm module has been moved to Setup.config so that +# it will be compiled as a shared library by default. Compiling it as +# a built-in module causes conflicts with the pybsddb3 module since it +# creates a static dependency on an out-of-date version of db.so. +# +# First, look at Setup.config; configure may have set this for you. + +#dbm dbmmodule.c # dbm(3) may require -lndbm or similar + +# Anthony Baxter's gdbm module. GNU dbm(3) will require -lgdbm: +# +# First, look at Setup.config; configure may have set this for you. + +#gdbm gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm + + +# Sleepycat Berkeley DB interface. +# +# This requires the Sleepycat DB code, see http://www.sleepycat.com/ +# The earliest supported version of that library is 3.0, the latest +# supported version is 4.0 (4.1 is specifically not supported, as that +# changes the semantics of transactional databases). A list of available +# releases can be found at +# +# http://www.sleepycat.com/update/index.html +# +# Edit the variables DB and DBLIBVERto point to the db top directory +# and the subdirectory of PORT where you built it. +#DB=/usr/local/BerkeleyDB.4.0 +#DBLIBVER=4.0 +#DBINC=$(DB)/include +#DBLIB=$(DB)/lib +#_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER) + +# Historical Berkeley DB 1.85 +# +# This module is deprecated; the 1.85 version of the Berkeley DB library has +# bugs that can cause data corruption. If you can, use later versions of the +# library instead, available from <http://www.sleepycat.com/>. + +#DB=/depot/sundry/src/berkeley-db/db.1.85 +#DBPORT=$(DB)/PORT/irix.5.3 +#bsddb185 bsddbmodule.c -I$(DBPORT)/include -I$(DBPORT) $(DBPORT)/libdb.a + + + +# Helper module for various ascii-encoders +#binascii binascii.c + +# Fred Drake's interface to the Python parser +#parser parsermodule.c + +# cStringIO and cPickle +#cStringIO cStringIO.c +#cPickle cPickle.c + + +# Lee Busby's SIGFPE modules. +# The library to link fpectl with is platform specific. +# Choose *one* of the options below for fpectl: + +# For SGI IRIX (tested on 5.3): +#fpectl fpectlmodule.c -lfpe + +# For Solaris with SunPro compiler (tested on Solaris 2.5 with SunPro C 4.2): +# (Without the compiler you don't have -lsunmath.) +#fpectl fpectlmodule.c -R/opt/SUNWspro/lib -lsunmath -lm + +# For other systems: see instructions in fpectlmodule.c. +#fpectl fpectlmodule.c ... + +# Test module for fpectl. No extra libraries needed. +#fpetest fpetestmodule.c + +# Andrew Kuchling's zlib module. +# This require zlib 1.1.3 (or later). +# See http://www.gzip.org/zlib/ +#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz + +# Interface to the Expat XML parser +# +# Expat was written by James Clark and is now maintained by a group of +# developers on SourceForge; see www.libexpat.org for more +# information. The pyexpat module was written by Paul Prescod after a +# prototype by Jack Jansen. Source of Expat 1.95.2 is included in +# Modules/expat/. Usage of a system shared libexpat.so/expat.dll is +# not advised. +# +# More information on Expat can be found at www.libexpat.org. +# +#EXPAT_DIR=/usr/local/src/expat-1.95.2 +#pyexpat pyexpat.c -DHAVE_EXPAT_H -I$(EXPAT_DIR)/lib -L$(EXPAT_DIR) -lexpat + + +# Hye-Shik Chang's CJKCodecs + +# multibytecodec is required for all the other CJK codec modules +#_multibytecodec cjkcodecs/multibytecodec.c + +#_codecs_cn cjkcodecs/_codecs_cn.c +#_codecs_hk cjkcodecs/_codecs_hk.c +#_codecs_iso2022 cjkcodecs/_codecs_iso2022.c +#_codecs_jp cjkcodecs/_codecs_jp.c +#_codecs_kr cjkcodecs/_codecs_kr.c +#_codecs_tw cjkcodecs/_codecs_tw.c + +# Example -- included for reference only: +# xx xxmodule.c + +# Another example -- the 'xxsubtype' module shows C-level subtyping in action +xxsubtype xxsubtype.c diff --git a/sys/src/cmd/python/Modules/Setup.config b/sys/src/cmd/python/Modules/Setup.config new file mode 100644 index 000000000..7dde386a0 --- /dev/null +++ b/sys/src/cmd/python/Modules/Setup.config @@ -0,0 +1,13 @@ +# This file is transmogrified into Setup.config by config.status. + +# The purpose of this file is to conditionally enable certain modules +# based on configure-time options. + +# Threading +#thread threadmodule.c + +# The signal module +signal signalmodule.c + +# The rest of the modules previously listed in this file are built +# by the setup.py script in Python 2.1 and later. diff --git a/sys/src/cmd/python/Modules/Setup.config.in b/sys/src/cmd/python/Modules/Setup.config.in new file mode 100644 index 000000000..fed62e9d8 --- /dev/null +++ b/sys/src/cmd/python/Modules/Setup.config.in @@ -0,0 +1,13 @@ +# This file is transmogrified into Setup.config by config.status. + +# The purpose of this file is to conditionally enable certain modules +# based on configure-time options. + +# Threading +@USE_THREAD_MODULE@thread threadmodule.c + +# The signal module +@USE_SIGNAL_MODULE@signal signalmodule.c + +# The rest of the modules previously listed in this file are built +# by the setup.py script in Python 2.1 and later. diff --git a/sys/src/cmd/python/Modules/Setup.dist b/sys/src/cmd/python/Modules/Setup.dist new file mode 100644 index 000000000..46f4253e1 --- /dev/null +++ b/sys/src/cmd/python/Modules/Setup.dist @@ -0,0 +1,487 @@ +# -*- makefile -*- +# The file Setup is used by the makesetup script to construct the files +# Makefile and config.c, from Makefile.pre and config.c.in, +# respectively. The file Setup itself is initially copied from +# Setup.dist; once it exists it will not be overwritten, so you can edit +# Setup to your heart's content. Note that Makefile.pre is created +# from Makefile.pre.in by the toplevel configure script. + +# (VPATH notes: Setup and Makefile.pre are in the build directory, as +# are Makefile and config.c; the *.in and *.dist files are in the source +# directory.) + +# Each line in this file describes one or more optional modules. +# Modules enabled here will not be compiled by the setup.py script, +# so the file can be used to override setup.py's behavior. + +# Lines have the following structure: +# +# <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...] +# +# <sourcefile> is anything ending in .c (.C, .cc, .c++ are C++ files) +# <cpparg> is anything starting with -I, -D, -U or -C +# <library> is anything ending in .a or beginning with -l or -L +# <module> is anything else but should be a valid Python +# identifier (letters, digits, underscores, beginning with non-digit) +# +# (As the makesetup script changes, it may recognize some other +# arguments as well, e.g. *.so and *.sl as libraries. See the big +# case statement in the makesetup script.) +# +# Lines can also have the form +# +# <name> = <value> +# +# which defines a Make variable definition inserted into Makefile.in +# +# Finally, if a line contains just the word "*shared*" (without the +# quotes but with the stars), then the following modules will not be +# built statically. The build process works like this: +# +# 1. Build all modules that are declared as static in Modules/Setup, +# combine them into libpythonxy.a, combine that into python. +# 2. Build all modules that are listed as shared in Modules/Setup. +# 3. Invoke setup.py. That builds all modules that +# a) are not builtin, and +# b) are not listed in Modules/Setup, and +# c) can be build on the target +# +# Therefore, modules declared to be shared will not be +# included in the config.c file, nor in the list of objects to be +# added to the library archive, and their linker options won't be +# added to the linker options. Rules to create their .o files and +# their shared libraries will still be added to the Makefile, and +# their names will be collected in the Make variable SHAREDMODS. This +# is used to build modules as shared libraries. (They can be +# installed using "make sharedinstall", which is implied by the +# toplevel "make install" target.) (For compatibility, +# *noconfig* has the same effect as *shared*.) +# +# In addition, *static* explicitly declares the following modules to +# be static. Lines containing "*static*" and "*shared*" may thus +# alternate throughout this file. + +# NOTE: As a standard policy, as many modules as can be supported by a +# platform should be present. The distribution comes with all modules +# enabled that are supported by most platforms and don't require you +# to ftp sources from elsewhere. + + +# Some special rules to define PYTHONPATH. +# Edit the definitions below to indicate which options you are using. +# Don't add any whitespace or comments! + +# Directories where library files get installed. +# DESTLIB is for Python modules; MACHDESTLIB for shared libraries. +DESTLIB=$(LIBDEST) +MACHDESTLIB=$(BINLIBDEST) + +# NOTE: all the paths are now relative to the prefix that is computed +# at run time! + +# Standard path -- don't edit. +# No leading colon since this is the first entry. +# Empty since this is now just the runtime prefix. +DESTPATH= + +# Site specific path components -- should begin with : if non-empty +SITEPATH= + +# Standard path components for test modules +TESTPATH= + +# Path components for machine- or system-dependent modules and shared libraries +MACHDEPPATH=:plat-$(MACHDEP) +EXTRAMACHDEPPATH= + +# Path component for the Tkinter-related modules +# The TKPATH variable is always enabled, to save you the effort. +TKPATH=:lib-tk + +COREPYTHONPATH=$(DESTPATH)$(SITEPATH)$(TESTPATH)$(MACHDEPPATH)$(EXTRAMACHDEPPATH)$(TKPATH) +PYTHONPATH=$(COREPYTHONPATH) + + +# The modules listed here can't be built as shared libraries for +# various reasons; therefore they are listed here instead of in the +# normal order. + +# This only contains the minimal set of modules required to run the +# setup.py script in the root of the Python source tree. + +posix posixmodule.c # posix (UNIX) system calls +errno errnomodule.c # posix (UNIX) errno values +pwd pwdmodule.c # this is needed to find out the user's home dir + # if $HOME is not set +_sre _sre.c # Fredrik Lundh's new regular expressions +_codecs _codecsmodule.c # access to the builtin codecs and codec registry + +# The zipimport module is always imported at startup. Having it as a +# builtin module avoids some bootstrapping problems and reduces overhead. +zipimport zipimport.c + +# The rest of the modules listed in this file are all commented out by +# default. Usually they can be detected and built as dynamically +# loaded modules by the new setup.py script added in Python 2.1. If +# you're on a platform that doesn't support dynamic loading, want to +# compile modules statically into the Python binary, or need to +# specify some odd set of compiler switches, you can uncomment the +# appropriate lines below. + +# ====================================================================== + +# The Python symtable module depends on .h files that setup.py doesn't track +_symtable symtablemodule.c + +# The SGI specific GL module: + +GLHACK=-Dclear=__GLclear +#gl glmodule.c cgensupport.c -I$(srcdir) $(GLHACK) -lgl -lX11 + +# Pure module. Cannot be linked dynamically. +# -DWITH_QUANTIFY, -DWITH_PURIFY, or -DWITH_ALL_PURE +#WHICH_PURE_PRODUCTS=-DWITH_ALL_PURE +#PURE_INCLS=-I/usr/local/include +#PURE_STUBLIBS=-L/usr/local/lib -lpurify_stubs -lquantify_stubs +#pure puremodule.c $(WHICH_PURE_PRODUCTS) $(PURE_INCLS) $(PURE_STUBLIBS) + +# Uncommenting the following line tells makesetup that all following +# modules are to be built as shared libraries (see above for more +# detail; also note that *static* reverses this effect): + +#*shared* + +# GNU readline. Unlike previous Python incarnations, GNU readline is +# now incorporated in an optional module, configured in the Setup file +# instead of by a configure script switch. You may have to insert a +# -L option pointing to the directory where libreadline.* lives, +# and you may have to change -ltermcap to -ltermlib or perhaps remove +# it, depending on your system -- see the GNU readline instructions. +# It's okay for this to be a shared library, too. + +#readline readline.c -lreadline -ltermcap + + +# Modules that should always be present (non UNIX dependent): + +#array arraymodule.c # array objects +#cmath cmathmodule.c # -lm # complex math library functions +#math mathmodule.c # -lm # math library functions, e.g. sin() +#_struct _struct.c # binary structure packing/unpacking +#time timemodule.c # -lm # time operations and variables +#operator operator.c # operator.add() and similar goodies +#_weakref _weakref.c # basic weak reference support +#_testcapi _testcapimodule.c # Python C API test module +#_random _randommodule.c # Random number generator +#collections collectionsmodule.c # Container types +#itertools itertoolsmodule.c # Functions creating iterators for efficient looping +#strop stropmodule.c # String manipulations + +#unicodedata unicodedata.c # static Unicode character database + +# access to ISO C locale support +#_locale _localemodule.c # -lintl + + +# Modules with some UNIX dependencies -- on by default: +# (If you have a really backward UNIX, select and socket may not be +# supported...) + +#fcntl fcntlmodule.c # fcntl(2) and ioctl(2) +#spwd spwdmodule.c # spwd(3) +#grp grpmodule.c # grp(3) +#select selectmodule.c # select(2); not on ancient System V + +# Memory-mapped files (also works on Win32). +#mmap mmapmodule.c + +# CSV file helper +#_csv _csv.c + +# Socket module helper for socket(2) +#_socket socketmodule.c + +# Socket module helper for SSL support; you must comment out the other +# socket line above, and possibly edit the SSL variable: +#SSL=/usr/local/ssl +#_ssl _ssl.c \ +# -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ +# -L$(SSL)/lib -lssl -lcrypto + +# The crypt module is now disabled by default because it breaks builds +# on many systems (where -lcrypt is needed), e.g. Linux (I believe). +# +# First, look at Setup.config; configure may have set this for you. + +#crypt cryptmodule.c # -lcrypt # crypt(3); needs -lcrypt on some systems + + +# Some more UNIX dependent modules -- off by default, since these +# are not supported by all UNIX systems: + +#nis nismodule.c -lnsl # Sun yellow pages -- not everywhere +#termios termios.c # Steen Lumholt's termios module +#resource resource.c # Jeremy Hylton's rlimit interface + + +# Multimedia modules -- off by default. +# These don't work for 64-bit platforms!!! +# #993173 says audioop works on 64-bit platforms, though. +# These represent audio samples or images as strings: + +#audioop audioop.c # Operations on audio samples +#imageop imageop.c # Operations on images +#rgbimg rgbimgmodule.c # Read SGI RGB image files (but coded portably) + + +# Note that the _md5 and _sha modules are normally only built if the +# system does not have the OpenSSL libs containing an optimized version. + +# The _md5 module implements the RSA Data Security, Inc. MD5 +# Message-Digest Algorithm, described in RFC 1321. The necessary files +# md5.c and md5.h are included here. + +#_md5 md5module.c md5.c + + +# The _sha module implements the SHA checksum algorithm. +# (NIST's Secure Hash Algorithm.) +#_sha shamodule.c + + +# SGI IRIX specific modules -- off by default. + +# These module work on any SGI machine: + +# *** gl must be enabled higher up in this file *** +#fm fmmodule.c $(GLHACK) -lfm -lgl # Font Manager +#sgi sgimodule.c # sgi.nap() and a few more + +# This module requires the header file +# /usr/people/4Dgifts/iristools/include/izoom.h: +#imgfile imgfile.c -limage -lgutil -lgl -lm # Image Processing Utilities + + +# These modules require the Multimedia Development Option (I think): + +#al almodule.c -laudio # Audio Library +#cd cdmodule.c -lcdaudio -lds -lmediad # CD Audio Library +#cl clmodule.c -lcl -lawareaudio # Compression Library +#sv svmodule.c yuvconvert.c -lsvideo -lXext -lX11 # Starter Video + + +# The FORMS library, by Mark Overmars, implements user interface +# components such as dialogs and buttons using SGI's GL and FM +# libraries. You must ftp the FORMS library separately from +# ftp://ftp.cs.ruu.nl/pub/SGI/FORMS. It was tested with FORMS 2.2a. +# NOTE: if you want to be able to use FORMS and curses simultaneously +# (or both link them statically into the same binary), you must +# compile all of FORMS with the cc option "-Dclear=__GLclear". + +# The FORMS variable must point to the FORMS subdirectory of the forms +# toplevel directory: + +#FORMS=/ufs/guido/src/forms/FORMS +#fl flmodule.c -I$(FORMS) $(GLHACK) $(FORMS)/libforms.a -lfm -lgl + + +# SunOS specific modules -- off by default: + +#sunaudiodev sunaudiodev.c + + +# A Linux specific module -- off by default; this may also work on +# some *BSDs. + +#linuxaudiodev linuxaudiodev.c + + +# George Neville-Neil's timing module: + +#timing timingmodule.c + + +# The _tkinter module. +# +# The command for _tkinter is long and site specific. Please +# uncomment and/or edit those parts as indicated. If you don't have a +# specific extension (e.g. Tix or BLT), leave the corresponding line +# commented out. (Leave the trailing backslashes in! If you +# experience strange errors, you may want to join all uncommented +# lines and remove the backslashes -- the backslash interpretation is +# done by the shell's "read" command and it may not be implemented on +# every system. + +# *** Always uncomment this (leave the leading underscore in!): +# _tkinter _tkinter.c tkappinit.c -DWITH_APPINIT \ +# *** Uncomment and edit to reflect where your Tcl/Tk libraries are: +# -L/usr/local/lib \ +# *** Uncomment and edit to reflect where your Tcl/Tk headers are: +# -I/usr/local/include \ +# *** Uncomment and edit to reflect where your X11 header files are: +# -I/usr/X11R6/include \ +# *** Or uncomment this for Solaris: +# -I/usr/openwin/include \ +# *** Uncomment and edit for Tix extension only: +# -DWITH_TIX -ltix8.1.8.2 \ +# *** Uncomment and edit for BLT extension only: +# -DWITH_BLT -I/usr/local/blt/blt8.0-unoff/include -lBLT8.0 \ +# *** Uncomment and edit for PIL (TkImaging) extension only: +# (See http://www.pythonware.com/products/pil/ for more info) +# -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \ +# *** Uncomment and edit for TOGL extension only: +# -DWITH_TOGL togl.c \ +# *** Uncomment and edit to reflect your Tcl/Tk versions: +# -ltk8.2 -ltcl8.2 \ +# *** Uncomment and edit to reflect where your X11 libraries are: +# -L/usr/X11R6/lib \ +# *** Or uncomment this for Solaris: +# -L/usr/openwin/lib \ +# *** Uncomment these for TOGL extension only: +# -lGL -lGLU -lXext -lXmu \ +# *** Uncomment for AIX: +# -lld \ +# *** Always uncomment this; X11 libraries to link with: +# -lX11 + +# Lance Ellinghaus's syslog module +#syslog syslogmodule.c # syslog daemon interface + + +# Curses support, requring the System V version of curses, often +# provided by the ncurses library. e.g. on Linux, link with -lncurses +# instead of -lcurses). +# +# First, look at Setup.config; configure may have set this for you. + +#_curses _cursesmodule.c -lcurses -ltermcap +# Wrapper for the panel library that's part of ncurses and SYSV curses. +#_curses_panel _curses_panel.c -lpanel -lncurses + + +# Generic (SunOS / SVR4) dynamic loading module. +# This is not needed for dynamic loading of Python modules -- +# it is a highly experimental and dangerous device for calling +# *arbitrary* C functions in *arbitrary* shared libraries: + +#dl dlmodule.c + + +# Modules that provide persistent dictionary-like semantics. You will +# probably want to arrange for at least one of them to be available on +# your machine, though none are defined by default because of library +# dependencies. The Python module anydbm.py provides an +# implementation independent wrapper for these; dumbdbm.py provides +# similar functionality (but slower of course) implemented in Python. + +# The standard Unix dbm module has been moved to Setup.config so that +# it will be compiled as a shared library by default. Compiling it as +# a built-in module causes conflicts with the pybsddb3 module since it +# creates a static dependency on an out-of-date version of db.so. +# +# First, look at Setup.config; configure may have set this for you. + +#dbm dbmmodule.c # dbm(3) may require -lndbm or similar + +# Anthony Baxter's gdbm module. GNU dbm(3) will require -lgdbm: +# +# First, look at Setup.config; configure may have set this for you. + +#gdbm gdbmmodule.c -I/usr/local/include -L/usr/local/lib -lgdbm + + +# Sleepycat Berkeley DB interface. +# +# This requires the Sleepycat DB code, see http://www.sleepycat.com/ +# The earliest supported version of that library is 3.0, the latest +# supported version is 4.0 (4.1 is specifically not supported, as that +# changes the semantics of transactional databases). A list of available +# releases can be found at +# +# http://www.sleepycat.com/update/index.html +# +# Edit the variables DB and DBLIBVERto point to the db top directory +# and the subdirectory of PORT where you built it. +#DB=/usr/local/BerkeleyDB.4.0 +#DBLIBVER=4.0 +#DBINC=$(DB)/include +#DBLIB=$(DB)/lib +#_bsddb _bsddb.c -I$(DBINC) -L$(DBLIB) -ldb-$(DBLIBVER) + +# Historical Berkeley DB 1.85 +# +# This module is deprecated; the 1.85 version of the Berkeley DB library has +# bugs that can cause data corruption. If you can, use later versions of the +# library instead, available from <http://www.sleepycat.com/>. + +#DB=/depot/sundry/src/berkeley-db/db.1.85 +#DBPORT=$(DB)/PORT/irix.5.3 +#bsddb185 bsddbmodule.c -I$(DBPORT)/include -I$(DBPORT) $(DBPORT)/libdb.a + + + +# Helper module for various ascii-encoders +#binascii binascii.c + +# Fred Drake's interface to the Python parser +#parser parsermodule.c + +# cStringIO and cPickle +#cStringIO cStringIO.c +#cPickle cPickle.c + + +# Lee Busby's SIGFPE modules. +# The library to link fpectl with is platform specific. +# Choose *one* of the options below for fpectl: + +# For SGI IRIX (tested on 5.3): +#fpectl fpectlmodule.c -lfpe + +# For Solaris with SunPro compiler (tested on Solaris 2.5 with SunPro C 4.2): +# (Without the compiler you don't have -lsunmath.) +#fpectl fpectlmodule.c -R/opt/SUNWspro/lib -lsunmath -lm + +# For other systems: see instructions in fpectlmodule.c. +#fpectl fpectlmodule.c ... + +# Test module for fpectl. No extra libraries needed. +#fpetest fpetestmodule.c + +# Andrew Kuchling's zlib module. +# This require zlib 1.1.3 (or later). +# See http://www.gzip.org/zlib/ +#zlib zlibmodule.c -I$(prefix)/include -L$(exec_prefix)/lib -lz + +# Interface to the Expat XML parser +# +# Expat was written by James Clark and is now maintained by a group of +# developers on SourceForge; see www.libexpat.org for more +# information. The pyexpat module was written by Paul Prescod after a +# prototype by Jack Jansen. Source of Expat 1.95.2 is included in +# Modules/expat/. Usage of a system shared libexpat.so/expat.dll is +# not advised. +# +# More information on Expat can be found at www.libexpat.org. +# +#EXPAT_DIR=/usr/local/src/expat-1.95.2 +#pyexpat pyexpat.c -DHAVE_EXPAT_H -I$(EXPAT_DIR)/lib -L$(EXPAT_DIR) -lexpat + + +# Hye-Shik Chang's CJKCodecs + +# multibytecodec is required for all the other CJK codec modules +#_multibytecodec cjkcodecs/multibytecodec.c + +#_codecs_cn cjkcodecs/_codecs_cn.c +#_codecs_hk cjkcodecs/_codecs_hk.c +#_codecs_iso2022 cjkcodecs/_codecs_iso2022.c +#_codecs_jp cjkcodecs/_codecs_jp.c +#_codecs_kr cjkcodecs/_codecs_kr.c +#_codecs_tw cjkcodecs/_codecs_tw.c + +# Example -- included for reference only: +# xx xxmodule.c + +# Another example -- the 'xxsubtype' module shows C-level subtyping in action +xxsubtype xxsubtype.c diff --git a/sys/src/cmd/python/Modules/Setup.local b/sys/src/cmd/python/Modules/Setup.local new file mode 100644 index 000000000..ca2983e22 --- /dev/null +++ b/sys/src/cmd/python/Modules/Setup.local @@ -0,0 +1 @@ +# Edit this file for local setup changes diff --git a/sys/src/cmd/python/Modules/_bisectmodule.c b/sys/src/cmd/python/Modules/_bisectmodule.c new file mode 100644 index 000000000..f8d412aba --- /dev/null +++ b/sys/src/cmd/python/Modules/_bisectmodule.c @@ -0,0 +1,235 @@ +/* Bisection algorithms. Drop in replacement for bisect.py + +Converted to C by Dmitry Vasiliev (dima at hlabs.spb.ru). +*/ + +#include "Python.h" + +static int +internal_bisect_right(PyObject *list, PyObject *item, Py_ssize_t lo, Py_ssize_t hi) +{ + PyObject *litem; + Py_ssize_t mid, res; + + if (hi == -1) { + hi = PySequence_Size(list); + if (hi < 0) + return -1; + } + while (lo < hi) { + mid = (lo + hi) / 2; + litem = PySequence_GetItem(list, mid); + if (litem == NULL) + return -1; + res = PyObject_RichCompareBool(item, litem, Py_LT); + Py_DECREF(litem); + if (res < 0) + return -1; + if (res) + hi = mid; + else + lo = mid + 1; + } + return lo; +} + +static PyObject * +bisect_right(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *list, *item; + int lo = 0; + int hi = -1; + int index; + static char *keywords[] = {"a", "x", "lo", "hi", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:bisect_right", + keywords, &list, &item, &lo, &hi)) + return NULL; + index = internal_bisect_right(list, item, lo, hi); + if (index < 0) + return NULL; + return PyInt_FromLong(index); +} + +PyDoc_STRVAR(bisect_right_doc, +"bisect_right(a, x[, lo[, hi]]) -> index\n\ +\n\ +Return the index where to insert item x in list a, assuming a is sorted.\n\ +\n\ +The return value i is such that all e in a[:i] have e <= x, and all e in\n\ +a[i:] have e > x. So if x already appears in the list, i points just\n\ +beyond the rightmost x already there\n\ +\n\ +Optional args lo (default 0) and hi (default len(a)) bound the\n\ +slice of a to be searched.\n"); + +static PyObject * +insort_right(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *list, *item, *result; + int lo = 0; + int hi = -1; + int index; + static char *keywords[] = {"a", "x", "lo", "hi", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:insort_right", + keywords, &list, &item, &lo, &hi)) + return NULL; + index = internal_bisect_right(list, item, lo, hi); + if (index < 0) + return NULL; + if (PyList_Check(list)) { + if (PyList_Insert(list, index, item) < 0) + return NULL; + } else { + result = PyObject_CallMethod(list, "insert", "iO", + index, item); + if (result == NULL) + return NULL; + Py_DECREF(result); + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(insort_right_doc, +"insort_right(a, x[, lo[, hi]])\n\ +\n\ +Insert item x in list a, and keep it sorted assuming a is sorted.\n\ +\n\ +If x is already in a, insert it to the right of the rightmost x.\n\ +\n\ +Optional args lo (default 0) and hi (default len(a)) bound the\n\ +slice of a to be searched.\n"); + +static int +internal_bisect_left(PyObject *list, PyObject *item, int lo, int hi) +{ + PyObject *litem; + int mid, res; + + if (hi == -1) { + hi = PySequence_Size(list); + if (hi < 0) + return -1; + } + while (lo < hi) { + mid = (lo + hi) / 2; + litem = PySequence_GetItem(list, mid); + if (litem == NULL) + return -1; + res = PyObject_RichCompareBool(litem, item, Py_LT); + Py_DECREF(litem); + if (res < 0) + return -1; + if (res) + lo = mid + 1; + else + hi = mid; + } + return lo; +} + +static PyObject * +bisect_left(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *list, *item; + int lo = 0; + int hi = -1; + int index; + static char *keywords[] = {"a", "x", "lo", "hi", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:bisect_left", + keywords, &list, &item, &lo, &hi)) + return NULL; + index = internal_bisect_left(list, item, lo, hi); + if (index < 0) + return NULL; + return PyInt_FromLong(index); +} + +PyDoc_STRVAR(bisect_left_doc, +"bisect_left(a, x[, lo[, hi]]) -> index\n\ +\n\ +Return the index where to insert item x in list a, assuming a is sorted.\n\ +\n\ +The return value i is such that all e in a[:i] have e < x, and all e in\n\ +a[i:] have e >= x. So if x already appears in the list, i points just\n\ +before the leftmost x already there.\n\ +\n\ +Optional args lo (default 0) and hi (default len(a)) bound the\n\ +slice of a to be searched.\n"); + +static PyObject * +insort_left(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *list, *item, *result; + int lo = 0; + int hi = -1; + int index; + static char *keywords[] = {"a", "x", "lo", "hi", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|ii:insort_left", + keywords, &list, &item, &lo, &hi)) + return NULL; + index = internal_bisect_left(list, item, lo, hi); + if (index < 0) + return NULL; + if (PyList_Check(list)) { + if (PyList_Insert(list, index, item) < 0) + return NULL; + } else { + result = PyObject_CallMethod(list, "insert", "iO", + index, item); + if (result == NULL) + return NULL; + Py_DECREF(result); + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(insort_left_doc, +"insort_left(a, x[, lo[, hi]])\n\ +\n\ +Insert item x in list a, and keep it sorted assuming a is sorted.\n\ +\n\ +If x is already in a, insert it to the left of the leftmost x.\n\ +\n\ +Optional args lo (default 0) and hi (default len(a)) bound the\n\ +slice of a to be searched.\n"); + +PyDoc_STRVAR(bisect_doc, "Alias for bisect_right().\n"); +PyDoc_STRVAR(insort_doc, "Alias for insort_right().\n"); + +static PyMethodDef bisect_methods[] = { + {"bisect_right", (PyCFunction)bisect_right, + METH_VARARGS|METH_KEYWORDS, bisect_right_doc}, + {"bisect", (PyCFunction)bisect_right, + METH_VARARGS|METH_KEYWORDS, bisect_doc}, + {"insort_right", (PyCFunction)insort_right, + METH_VARARGS|METH_KEYWORDS, insort_right_doc}, + {"insort", (PyCFunction)insort_right, + METH_VARARGS|METH_KEYWORDS, insort_doc}, + {"bisect_left", (PyCFunction)bisect_left, + METH_VARARGS|METH_KEYWORDS, bisect_left_doc}, + {"insort_left", (PyCFunction)insort_left, + METH_VARARGS|METH_KEYWORDS, insort_left_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(module_doc, +"Bisection algorithms.\n\ +\n\ +This module provides support for maintaining a list in sorted order without\n\ +having to sort the list after each insertion. For long lists of items with\n\ +expensive comparison operations, this can be an improvement over the more\n\ +common approach.\n"); + +PyMODINIT_FUNC +init_bisect(void) +{ + PyObject *m; + + m = Py_InitModule3("_bisect", bisect_methods, module_doc); +} diff --git a/sys/src/cmd/python/Modules/_bsddb.c b/sys/src/cmd/python/Modules/_bsddb.c new file mode 100644 index 000000000..b55c4e3eb --- /dev/null +++ b/sys/src/cmd/python/Modules/_bsddb.c @@ -0,0 +1,6047 @@ +/*---------------------------------------------------------------------- + Copyright (c) 1999-2001, Digital Creations, Fredericksburg, VA, USA + and Andrew Kuchling. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + o Redistributions of source code must retain the above copyright + notice, this list of conditions, and the disclaimer that follows. + + o Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + o Neither the name of Digital Creations nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS + IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL + CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. +------------------------------------------------------------------------*/ + + +/* + * Handwritten code to wrap version 3.x of the Berkeley DB library, + * written to replace a SWIG-generated file. It has since been updated + * to compile with BerkeleyDB versions 3.2 through 4.2. + * + * This module was started by Andrew Kuchling to remove the dependency + * on SWIG in a package by Gregory P. Smith <greg@electricrain.com> who + * based his work on a similar package by Robin Dunn <robin@alldunn.com> + * which wrapped Berkeley DB 2.7.x. + * + * Development of this module then returned full circle back to Robin Dunn + * who worked on behalf of Digital Creations to complete the wrapping of + * the DB 3.x API and to build a solid unit test suite. Robin has + * since gone onto other projects (wxPython). + * + * Gregory P. Smith <greg@electricrain.com> is once again the maintainer. + * + * Use the pybsddb-users@lists.sf.net mailing list for all questions. + * Things can change faster than the header of this file is updated. This + * file is shared with the PyBSDDB project at SourceForge: + * + * http://pybsddb.sf.net + * + * This file should remain backward compatible with Python 2.1, but see PEP + * 291 for the most current backward compatibility requirements: + * + * http://www.python.org/peps/pep-0291.html + * + * This module contains 6 types: + * + * DB (Database) + * DBCursor (Database Cursor) + * DBEnv (database environment) + * DBTxn (An explicit database transaction) + * DBLock (A lock handle) + * DBSequence (Sequence) + * + */ + +/* --------------------------------------------------------------------- */ + +/* + * Portions of this module, associated unit tests and build scripts are the + * result of a contract with The Written Word (http://thewrittenword.com/) + * Many thanks go out to them for causing me to raise the bar on quality and + * functionality, resulting in a better bsddb3 package for all of us to use. + * + * --Robin + */ + +/* --------------------------------------------------------------------- */ + +#include <stddef.h> /* for offsetof() */ +#include <Python.h> +#include <db.h> + +/* --------------------------------------------------------------------- */ +/* Various macro definitions */ + +/* 40 = 4.0, 33 = 3.3; this will break if the second number is > 9 */ +#define DBVER (DB_VERSION_MAJOR * 10 + DB_VERSION_MINOR) +#if DB_VERSION_MINOR > 9 +#error "eek! DBVER can't handle minor versions > 9" +#endif + +#define PY_BSDDB_VERSION "4.4.5.2" +static char *rcs_id = "$Id: _bsddb.c 53254 2007-01-05 02:09:06Z gregory.p.smith $"; + + +#if (PY_VERSION_HEX < 0x02050000) +typedef int Py_ssize_t; +#endif + +#ifdef WITH_THREAD + +/* These are for when calling Python --> C */ +#define MYDB_BEGIN_ALLOW_THREADS Py_BEGIN_ALLOW_THREADS; +#define MYDB_END_ALLOW_THREADS Py_END_ALLOW_THREADS; + +/* For 2.3, use the PyGILState_ calls */ +#if (PY_VERSION_HEX >= 0x02030000) +#define MYDB_USE_GILSTATE +#endif + +/* and these are for calling C --> Python */ +#if defined(MYDB_USE_GILSTATE) +#define MYDB_BEGIN_BLOCK_THREADS \ + PyGILState_STATE __savestate = PyGILState_Ensure(); +#define MYDB_END_BLOCK_THREADS \ + PyGILState_Release(__savestate); +#else /* MYDB_USE_GILSTATE */ +/* Pre GILState API - do it the long old way */ +static PyInterpreterState* _db_interpreterState = NULL; +#define MYDB_BEGIN_BLOCK_THREADS { \ + PyThreadState* prevState; \ + PyThreadState* newState; \ + PyEval_AcquireLock(); \ + newState = PyThreadState_New(_db_interpreterState); \ + prevState = PyThreadState_Swap(newState); + +#define MYDB_END_BLOCK_THREADS \ + newState = PyThreadState_Swap(prevState); \ + PyThreadState_Clear(newState); \ + PyEval_ReleaseLock(); \ + PyThreadState_Delete(newState); \ + } +#endif /* MYDB_USE_GILSTATE */ + +#else +/* Compiled without threads - avoid all this cruft */ +#define MYDB_BEGIN_ALLOW_THREADS +#define MYDB_END_ALLOW_THREADS +#define MYDB_BEGIN_BLOCK_THREADS +#define MYDB_END_BLOCK_THREADS + +#endif + +/* Should DB_INCOMPLETE be turned into a warning or an exception? */ +#define INCOMPLETE_IS_WARNING 1 + +/* --------------------------------------------------------------------- */ +/* Exceptions */ + +static PyObject* DBError; /* Base class, all others derive from this */ +static PyObject* DBCursorClosedError; /* raised when trying to use a closed cursor object */ +static PyObject* DBKeyEmptyError; /* DB_KEYEMPTY: also derives from KeyError */ +static PyObject* DBKeyExistError; /* DB_KEYEXIST */ +static PyObject* DBLockDeadlockError; /* DB_LOCK_DEADLOCK */ +static PyObject* DBLockNotGrantedError; /* DB_LOCK_NOTGRANTED */ +static PyObject* DBNotFoundError; /* DB_NOTFOUND: also derives from KeyError */ +static PyObject* DBOldVersionError; /* DB_OLD_VERSION */ +static PyObject* DBRunRecoveryError; /* DB_RUNRECOVERY */ +static PyObject* DBVerifyBadError; /* DB_VERIFY_BAD */ +static PyObject* DBNoServerError; /* DB_NOSERVER */ +static PyObject* DBNoServerHomeError; /* DB_NOSERVER_HOME */ +static PyObject* DBNoServerIDError; /* DB_NOSERVER_ID */ +#if (DBVER >= 33) +static PyObject* DBPageNotFoundError; /* DB_PAGE_NOTFOUND */ +static PyObject* DBSecondaryBadError; /* DB_SECONDARY_BAD */ +#endif + +#if !INCOMPLETE_IS_WARNING +static PyObject* DBIncompleteError; /* DB_INCOMPLETE */ +#endif + +static PyObject* DBInvalidArgError; /* EINVAL */ +static PyObject* DBAccessError; /* EACCES */ +static PyObject* DBNoSpaceError; /* ENOSPC */ +static PyObject* DBNoMemoryError; /* DB_BUFFER_SMALL (ENOMEM when < 4.3) */ +static PyObject* DBAgainError; /* EAGAIN */ +static PyObject* DBBusyError; /* EBUSY */ +static PyObject* DBFileExistsError; /* EEXIST */ +static PyObject* DBNoSuchFileError; /* ENOENT */ +static PyObject* DBPermissionsError; /* EPERM */ + +#if (DBVER < 43) +#define DB_BUFFER_SMALL ENOMEM +#endif + + +/* --------------------------------------------------------------------- */ +/* Structure definitions */ + +#if PYTHON_API_VERSION >= 1010 /* python >= 2.1 support weak references */ +#define HAVE_WEAKREF +#else +#undef HAVE_WEAKREF +#endif + +/* if Python >= 2.1 better support warnings */ +#if PYTHON_API_VERSION >= 1010 +#define HAVE_WARNINGS +#else +#undef HAVE_WARNINGS +#endif + +#if PYTHON_API_VERSION <= 1007 + /* 1.5 compatibility */ +#define PyObject_New PyObject_NEW +#define PyObject_Del PyMem_DEL +#endif + +struct behaviourFlags { + /* What is the default behaviour when DB->get or DBCursor->get returns a + DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise an exception? */ + unsigned int getReturnsNone : 1; + /* What is the default behaviour for DBCursor.set* methods when DBCursor->get + * returns a DB_NOTFOUND || DB_KEYEMPTY error? Return None or raise? */ + unsigned int cursorSetReturnsNone : 1; +}; + +#define DEFAULT_GET_RETURNS_NONE 1 +#define DEFAULT_CURSOR_SET_RETURNS_NONE 1 /* 0 in pybsddb < 4.2, python < 2.4 */ + +typedef struct { + PyObject_HEAD + DB_ENV* db_env; + u_int32_t flags; /* saved flags from open() */ + int closed; + struct behaviourFlags moduleFlags; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif +} DBEnvObject; + + +typedef struct { + PyObject_HEAD + DB* db; + DBEnvObject* myenvobj; /* PyObject containing the DB_ENV */ + u_int32_t flags; /* saved flags from open() */ + u_int32_t setflags; /* saved flags from set_flags() */ + int haveStat; + struct behaviourFlags moduleFlags; +#if (DBVER >= 33) + PyObject* associateCallback; + PyObject* btCompareCallback; + int primaryDBType; +#endif +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif +} DBObject; + + +typedef struct { + PyObject_HEAD + DBC* dbc; + DBObject* mydb; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif +} DBCursorObject; + + +typedef struct { + PyObject_HEAD + DB_TXN* txn; + PyObject *env; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif +} DBTxnObject; + + +typedef struct { + PyObject_HEAD + DB_LOCK lock; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif +} DBLockObject; + +#if (DBVER >= 43) +typedef struct { + PyObject_HEAD + DB_SEQUENCE* sequence; + DBObject* mydb; +#ifdef HAVE_WEAKREF + PyObject *in_weakreflist; /* List of weak references */ +#endif +} DBSequenceObject; +staticforward PyTypeObject DBSequence_Type; +#endif + +staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type, DBLock_Type; + +#define DBObject_Check(v) ((v)->ob_type == &DB_Type) +#define DBCursorObject_Check(v) ((v)->ob_type == &DBCursor_Type) +#define DBEnvObject_Check(v) ((v)->ob_type == &DBEnv_Type) +#define DBTxnObject_Check(v) ((v)->ob_type == &DBTxn_Type) +#define DBLockObject_Check(v) ((v)->ob_type == &DBLock_Type) +#if (DBVER >= 43) +#define DBSequenceObject_Check(v) ((v)->ob_type == &DBSequence_Type) +#endif + + +/* --------------------------------------------------------------------- */ +/* Utility macros and functions */ + +#define RETURN_IF_ERR() \ + if (makeDBError(err)) { \ + return NULL; \ + } + +#define RETURN_NONE() Py_INCREF(Py_None); return Py_None; + +#define _CHECK_OBJECT_NOT_CLOSED(nonNull, pyErrObj, name) \ + if ((nonNull) == NULL) { \ + PyObject *errTuple = NULL; \ + errTuple = Py_BuildValue("(is)", 0, #name " object has been closed"); \ + PyErr_SetObject((pyErrObj), errTuple); \ + Py_DECREF(errTuple); \ + return NULL; \ + } + +#define CHECK_DB_NOT_CLOSED(dbobj) \ + _CHECK_OBJECT_NOT_CLOSED(dbobj->db, DBError, DB) + +#define CHECK_ENV_NOT_CLOSED(env) \ + _CHECK_OBJECT_NOT_CLOSED(env->db_env, DBError, DBEnv) + +#define CHECK_CURSOR_NOT_CLOSED(curs) \ + _CHECK_OBJECT_NOT_CLOSED(curs->dbc, DBCursorClosedError, DBCursor) + +#if (DBVER >= 43) +#define CHECK_SEQUENCE_NOT_CLOSED(curs) \ + _CHECK_OBJECT_NOT_CLOSED(curs->sequence, DBError, DBSequence) +#endif + +#define CHECK_DBFLAG(mydb, flag) (((mydb)->flags & (flag)) || \ + (((mydb)->myenvobj != NULL) && ((mydb)->myenvobj->flags & (flag)))) + +#define CLEAR_DBT(dbt) (memset(&(dbt), 0, sizeof(dbt))) + +#define FREE_DBT(dbt) if ((dbt.flags & (DB_DBT_MALLOC|DB_DBT_REALLOC)) && \ + dbt.data != NULL) { free(dbt.data); dbt.data = NULL; } + + +static int makeDBError(int err); + + +/* Return the access method type of the DBObject */ +static int _DB_get_type(DBObject* self) +{ +#if (DBVER >= 33) + DBTYPE type; + int err; + err = self->db->get_type(self->db, &type); + if (makeDBError(err)) { + return -1; + } + return type; +#else + return self->db->get_type(self->db); +#endif +} + + +/* Create a DBT structure (containing key and data values) from Python + strings. Returns 1 on success, 0 on an error. */ +static int make_dbt(PyObject* obj, DBT* dbt) +{ + CLEAR_DBT(*dbt); + if (obj == Py_None) { + /* no need to do anything, the structure has already been zeroed */ + } + else if (!PyArg_Parse(obj, "s#", &dbt->data, &dbt->size)) { + PyErr_SetString(PyExc_TypeError, + "Data values must be of type string or None."); + return 0; + } + return 1; +} + + +/* Recno and Queue DBs can have integer keys. This function figures out + what's been given, verifies that it's allowed, and then makes the DBT. + + Caller MUST call FREE_DBT(key) when done. */ +static int +make_key_dbt(DBObject* self, PyObject* keyobj, DBT* key, int* pflags) +{ + db_recno_t recno; + int type; + + CLEAR_DBT(*key); + if (keyobj == Py_None) { + type = _DB_get_type(self); + if (type == -1) + return 0; + if (type == DB_RECNO || type == DB_QUEUE) { + PyErr_SetString( + PyExc_TypeError, + "None keys not allowed for Recno and Queue DB's"); + return 0; + } + /* no need to do anything, the structure has already been zeroed */ + } + + else if (PyString_Check(keyobj)) { + /* verify access method type */ + type = _DB_get_type(self); + if (type == -1) + return 0; + if (type == DB_RECNO || type == DB_QUEUE) { + PyErr_SetString( + PyExc_TypeError, + "String keys not allowed for Recno and Queue DB's"); + return 0; + } + + key->data = PyString_AS_STRING(keyobj); + key->size = PyString_GET_SIZE(keyobj); + } + + else if (PyInt_Check(keyobj)) { + /* verify access method type */ + type = _DB_get_type(self); + if (type == -1) + return 0; + if (type == DB_BTREE && pflags != NULL) { + /* if BTREE then an Integer key is allowed with the + * DB_SET_RECNO flag */ + *pflags |= DB_SET_RECNO; + } + else if (type != DB_RECNO && type != DB_QUEUE) { + PyErr_SetString( + PyExc_TypeError, + "Integer keys only allowed for Recno and Queue DB's"); + return 0; + } + + /* Make a key out of the requested recno, use allocated space so DB + * will be able to realloc room for the real key if needed. */ + recno = PyInt_AS_LONG(keyobj); + key->data = malloc(sizeof(db_recno_t)); + if (key->data == NULL) { + PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed"); + return 0; + } + key->ulen = key->size = sizeof(db_recno_t); + memcpy(key->data, &recno, sizeof(db_recno_t)); + key->flags = DB_DBT_REALLOC; + } + else { + PyErr_Format(PyExc_TypeError, + "String or Integer object expected for key, %s found", + keyobj->ob_type->tp_name); + return 0; + } + + return 1; +} + + +/* Add partial record access to an existing DBT data struct. + If dlen and doff are set, then the DB_DBT_PARTIAL flag will be set + and the data storage/retrieval will be done using dlen and doff. */ +static int add_partial_dbt(DBT* d, int dlen, int doff) { + /* if neither were set we do nothing (-1 is the default value) */ + if ((dlen == -1) && (doff == -1)) { + return 1; + } + + if ((dlen < 0) || (doff < 0)) { + PyErr_SetString(PyExc_TypeError, "dlen and doff must both be >= 0"); + return 0; + } + + d->flags = d->flags | DB_DBT_PARTIAL; + d->dlen = (unsigned int) dlen; + d->doff = (unsigned int) doff; + return 1; +} + +/* a safe strcpy() without the zeroing behaviour and semantics of strncpy. */ +/* TODO: make this use the native libc strlcpy() when available (BSD) */ +unsigned int our_strlcpy(char* dest, const char* src, unsigned int n) +{ + unsigned int srclen, copylen; + + srclen = strlen(src); + if (n <= 0) + return srclen; + copylen = (srclen > n-1) ? n-1 : srclen; + /* populate dest[0] thru dest[copylen-1] */ + memcpy(dest, src, copylen); + /* guarantee null termination */ + dest[copylen] = 0; + + return srclen; +} + +/* Callback used to save away more information about errors from the DB + * library. */ +static char _db_errmsg[1024]; +#if (DBVER <= 42) +static void _db_errorCallback(const char* prefix, char* msg) +#else +static void _db_errorCallback(const DB_ENV *db_env, + const char* prefix, const char* msg) +#endif +{ + our_strlcpy(_db_errmsg, msg, sizeof(_db_errmsg)); +} + + +/* make a nice exception object to raise for errors. */ +static int makeDBError(int err) +{ + char errTxt[2048]; /* really big, just in case... */ + PyObject *errObj = NULL; + PyObject *errTuple = NULL; + int exceptionRaised = 0; + unsigned int bytes_left; + + switch (err) { + case 0: /* successful, no error */ break; + +#if (DBVER < 41) + case DB_INCOMPLETE: +#if INCOMPLETE_IS_WARNING + bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); + /* Ensure that bytes_left never goes negative */ + if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) { + bytes_left = sizeof(errTxt) - bytes_left - 4 - 1; + assert(bytes_left >= 0); + strcat(errTxt, " -- "); + strncat(errTxt, _db_errmsg, bytes_left); + } + _db_errmsg[0] = 0; +#ifdef HAVE_WARNINGS + exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt); +#else + fprintf(stderr, errTxt); + fprintf(stderr, "\n"); +#endif + +#else /* do an exception instead */ + errObj = DBIncompleteError; +#endif + break; +#endif /* DBVER < 41 */ + + case DB_KEYEMPTY: errObj = DBKeyEmptyError; break; + case DB_KEYEXIST: errObj = DBKeyExistError; break; + case DB_LOCK_DEADLOCK: errObj = DBLockDeadlockError; break; + case DB_LOCK_NOTGRANTED: errObj = DBLockNotGrantedError; break; + case DB_NOTFOUND: errObj = DBNotFoundError; break; + case DB_OLD_VERSION: errObj = DBOldVersionError; break; + case DB_RUNRECOVERY: errObj = DBRunRecoveryError; break; + case DB_VERIFY_BAD: errObj = DBVerifyBadError; break; + case DB_NOSERVER: errObj = DBNoServerError; break; + case DB_NOSERVER_HOME: errObj = DBNoServerHomeError; break; + case DB_NOSERVER_ID: errObj = DBNoServerIDError; break; +#if (DBVER >= 33) + case DB_PAGE_NOTFOUND: errObj = DBPageNotFoundError; break; + case DB_SECONDARY_BAD: errObj = DBSecondaryBadError; break; +#endif + case DB_BUFFER_SMALL: errObj = DBNoMemoryError; break; + +#if (DBVER >= 43) + /* ENOMEM and DB_BUFFER_SMALL were one and the same until 4.3 */ + case ENOMEM: errObj = PyExc_MemoryError; break; +#endif + case EINVAL: errObj = DBInvalidArgError; break; + case EACCES: errObj = DBAccessError; break; + case ENOSPC: errObj = DBNoSpaceError; break; + case EAGAIN: errObj = DBAgainError; break; + case EBUSY : errObj = DBBusyError; break; + case EEXIST: errObj = DBFileExistsError; break; + case ENOENT: errObj = DBNoSuchFileError; break; + case EPERM : errObj = DBPermissionsError; break; + + default: errObj = DBError; break; + } + + if (errObj != NULL) { + bytes_left = our_strlcpy(errTxt, db_strerror(err), sizeof(errTxt)); + /* Ensure that bytes_left never goes negative */ + if (_db_errmsg[0] && bytes_left < (sizeof(errTxt) - 4)) { + bytes_left = sizeof(errTxt) - bytes_left - 4 - 1; + assert(bytes_left >= 0); + strcat(errTxt, " -- "); + strncat(errTxt, _db_errmsg, bytes_left); + } + _db_errmsg[0] = 0; + + errTuple = Py_BuildValue("(is)", err, errTxt); + PyErr_SetObject(errObj, errTuple); + Py_DECREF(errTuple); + } + + return ((errObj != NULL) || exceptionRaised); +} + + + +/* set a type exception */ +static void makeTypeError(char* expected, PyObject* found) +{ + PyErr_Format(PyExc_TypeError, "Expected %s argument, %s found.", + expected, found->ob_type->tp_name); +} + + +/* verify that an obj is either None or a DBTxn, and set the txn pointer */ +static int checkTxnObj(PyObject* txnobj, DB_TXN** txn) +{ + if (txnobj == Py_None || txnobj == NULL) { + *txn = NULL; + return 1; + } + if (DBTxnObject_Check(txnobj)) { + *txn = ((DBTxnObject*)txnobj)->txn; + return 1; + } + else + makeTypeError("DBTxn", txnobj); + return 0; +} + + +/* Delete a key from a database + Returns 0 on success, -1 on an error. */ +static int _DB_delete(DBObject* self, DB_TXN *txn, DBT *key, int flags) +{ + int err; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->del(self->db, txn, key, 0); + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + return -1; + } + self->haveStat = 0; + return 0; +} + + +/* Store a key into a database + Returns 0 on success, -1 on an error. */ +static int _DB_put(DBObject* self, DB_TXN *txn, DBT *key, DBT *data, int flags) +{ + int err; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->put(self->db, txn, key, data, flags); + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + return -1; + } + self->haveStat = 0; + return 0; +} + +/* Get a key/data pair from a cursor */ +static PyObject* _DBCursor_get(DBCursorObject* self, int extra_flags, + PyObject *args, PyObject *kwargs, char *format) +{ + int err; + PyObject* retval = NULL; + DBT key, data; + int dlen = -1; + int doff = -1; + int flags = 0; + static char* kwnames[] = { "flags", "dlen", "doff", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, kwnames, + &flags, &dlen, &doff)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + flags |= extra_flags; + CLEAR_DBT(key); + CLEAR_DBT(data); + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + key.flags = DB_DBT_MALLOC; + } + if (!add_partial_dbt(&data, dlen, doff)) + return NULL; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { /* otherwise, success! */ + + /* if Recno or Queue, return the key as an Int */ + switch (_DB_get_type(self->mydb)) { + case -1: + retval = NULL; + break; + + case DB_RECNO: + case DB_QUEUE: + retval = Py_BuildValue("is#", *((db_recno_t*)key.data), + data.data, data.size); + break; + case DB_HASH: + case DB_BTREE: + default: + retval = Py_BuildValue("s#s#", key.data, key.size, + data.data, data.size); + break; + } + } + if (!err) { + FREE_DBT(key); + FREE_DBT(data); + } + return retval; +} + + +/* add an integer to a dictionary using the given name as a key */ +static void _addIntToDict(PyObject* dict, char *name, int value) +{ + PyObject* v = PyInt_FromLong((long) value); + if (!v || PyDict_SetItemString(dict, name, v)) + PyErr_Clear(); + + Py_XDECREF(v); +} +#if (DBVER >= 43) +/* add an db_seq_t to a dictionary using the given name as a key */ +static void _addDb_seq_tToDict(PyObject* dict, char *name, db_seq_t value) +{ + PyObject* v = PyLong_FromLongLong(value); + if (!v || PyDict_SetItemString(dict, name, v)) + PyErr_Clear(); + + Py_XDECREF(v); +} +#endif + + + +/* --------------------------------------------------------------------- */ +/* Allocators and deallocators */ + +static DBObject* +newDBObject(DBEnvObject* arg, int flags) +{ + DBObject* self; + DB_ENV* db_env = NULL; + int err; + + self = PyObject_New(DBObject, &DB_Type); + if (self == NULL) + return NULL; + + self->haveStat = 0; + self->flags = 0; + self->setflags = 0; + self->myenvobj = NULL; +#if (DBVER >= 33) + self->associateCallback = NULL; + self->btCompareCallback = NULL; + self->primaryDBType = 0; +#endif +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif + + /* keep a reference to our python DBEnv object */ + if (arg) { + Py_INCREF(arg); + self->myenvobj = arg; + db_env = arg->db_env; + } + + if (self->myenvobj) + self->moduleFlags = self->myenvobj->moduleFlags; + else + self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE; + self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE; + + MYDB_BEGIN_ALLOW_THREADS; + err = db_create(&self->db, db_env, flags); + if (self->db != NULL) { + self->db->set_errcall(self->db, _db_errorCallback); +#if (DBVER >= 33) + self->db->app_private = (void*)self; +#endif + } + MYDB_END_ALLOW_THREADS; + /* TODO add a weakref(self) to the self->myenvobj->open_child_weakrefs + * list so that a DBEnv can refuse to close without aborting any open + * DBTxns and closing any open DBs first. */ + if (makeDBError(err)) { + if (self->myenvobj) { + Py_DECREF(self->myenvobj); + self->myenvobj = NULL; + } + PyObject_Del(self); + self = NULL; + } + return self; +} + + +static void +DB_dealloc(DBObject* self) +{ + if (self->db != NULL) { + /* avoid closing a DB when its DBEnv has been closed out from under + * it */ + if (!self->myenvobj || + (self->myenvobj && self->myenvobj->db_env)) + { + MYDB_BEGIN_ALLOW_THREADS; + self->db->close(self->db, 0); + MYDB_END_ALLOW_THREADS; +#ifdef HAVE_WARNINGS + } else { + PyErr_Warn(PyExc_RuntimeWarning, + "DB could not be closed in destructor: DBEnv already closed"); +#endif + } + self->db = NULL; + } +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + if (self->myenvobj) { + Py_DECREF(self->myenvobj); + self->myenvobj = NULL; + } +#if (DBVER >= 33) + if (self->associateCallback != NULL) { + Py_DECREF(self->associateCallback); + self->associateCallback = NULL; + } + if (self->btCompareCallback != NULL) { + Py_DECREF(self->btCompareCallback); + self->btCompareCallback = NULL; + } +#endif + PyObject_Del(self); +} + + +static DBCursorObject* +newDBCursorObject(DBC* dbc, DBObject* db) +{ + DBCursorObject* self = PyObject_New(DBCursorObject, &DBCursor_Type); + if (self == NULL) + return NULL; + + self->dbc = dbc; + self->mydb = db; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif + Py_INCREF(self->mydb); + return self; +} + + +static void +DBCursor_dealloc(DBCursorObject* self) +{ + int err; + +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + + if (self->dbc != NULL) { + MYDB_BEGIN_ALLOW_THREADS; + /* If the underlying database has been closed, we don't + need to do anything. If the environment has been closed + we need to leak, as BerkeleyDB will crash trying to access + the environment. There was an exception when the + user closed the environment even though there still was + a database open. */ + if (self->mydb->db && self->mydb->myenvobj && + !self->mydb->myenvobj->closed) + err = self->dbc->c_close(self->dbc); + self->dbc = NULL; + MYDB_END_ALLOW_THREADS; + } + Py_XDECREF( self->mydb ); + PyObject_Del(self); +} + + +static DBEnvObject* +newDBEnvObject(int flags) +{ + int err; + DBEnvObject* self = PyObject_New(DBEnvObject, &DBEnv_Type); + if (self == NULL) + return NULL; + + self->closed = 1; + self->flags = flags; + self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE; + self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif + + MYDB_BEGIN_ALLOW_THREADS; + err = db_env_create(&self->db_env, flags); + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + PyObject_Del(self); + self = NULL; + } + else { + self->db_env->set_errcall(self->db_env, _db_errorCallback); + } + return self; +} + + +static void +DBEnv_dealloc(DBEnvObject* self) +{ +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + + if (self->db_env && !self->closed) { + MYDB_BEGIN_ALLOW_THREADS; + self->db_env->close(self->db_env, 0); + MYDB_END_ALLOW_THREADS; + } + PyObject_Del(self); +} + + +static DBTxnObject* +newDBTxnObject(DBEnvObject* myenv, DB_TXN *parent, int flags) +{ + int err; + DBTxnObject* self = PyObject_New(DBTxnObject, &DBTxn_Type); + if (self == NULL) + return NULL; + Py_INCREF(myenv); + self->env = (PyObject*)myenv; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = myenv->db_env->txn_begin(myenv->db_env, parent, &(self->txn), flags); +#else + err = txn_begin(myenv->db_env, parent, &(self->txn), flags); +#endif + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + Py_DECREF(self->env); + PyObject_Del(self); + self = NULL; + } + return self; +} + + +static void +DBTxn_dealloc(DBTxnObject* self) +{ +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + +#ifdef HAVE_WARNINGS + if (self->txn) { + /* it hasn't been finalized, abort it! */ + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + self->txn->abort(self->txn); +#else + txn_abort(self->txn); +#endif + MYDB_END_ALLOW_THREADS; + PyErr_Warn(PyExc_RuntimeWarning, + "DBTxn aborted in destructor. No prior commit() or abort()."); + } +#endif + + Py_DECREF(self->env); + PyObject_Del(self); +} + + +static DBLockObject* +newDBLockObject(DBEnvObject* myenv, u_int32_t locker, DBT* obj, + db_lockmode_t lock_mode, int flags) +{ + int err; + DBLockObject* self = PyObject_New(DBLockObject, &DBLock_Type); + if (self == NULL) + return NULL; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = myenv->db_env->lock_get(myenv->db_env, locker, flags, obj, lock_mode, + &self->lock); +#else + err = lock_get(myenv->db_env, locker, flags, obj, lock_mode, &self->lock); +#endif + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + PyObject_Del(self); + self = NULL; + } + + return self; +} + + +static void +DBLock_dealloc(DBLockObject* self) +{ +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + /* TODO: is this lock held? should we release it? */ + + PyObject_Del(self); +} + + +#if (DBVER >= 43) +static DBSequenceObject* +newDBSequenceObject(DBObject* mydb, int flags) +{ + int err; + DBSequenceObject* self = PyObject_New(DBSequenceObject, &DBSequence_Type); + if (self == NULL) + return NULL; + Py_INCREF(mydb); + self->mydb = mydb; +#ifdef HAVE_WEAKREF + self->in_weakreflist = NULL; +#endif + + + MYDB_BEGIN_ALLOW_THREADS; + err = db_sequence_create(&self->sequence, self->mydb->db, flags); + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + Py_DECREF(self->mydb); + PyObject_Del(self); + self = NULL; + } + + return self; +} + + +static void +DBSequence_dealloc(DBSequenceObject* self) +{ +#ifdef HAVE_WEAKREF + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject *) self); + } +#endif + + Py_DECREF(self->mydb); + PyObject_Del(self); +} +#endif + +/* --------------------------------------------------------------------- */ +/* DB methods */ + +static PyObject* +DB_append(DBObject* self, PyObject* args) +{ + PyObject* txnobj = NULL; + PyObject* dataobj; + db_recno_t recno; + DBT key, data; + DB_TXN *txn = NULL; + + if (!PyArg_UnpackTuple(args, "append", 1, 2, &dataobj, &txnobj)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + + /* make a dummy key out of a recno */ + recno = 0; + CLEAR_DBT(key); + key.data = &recno; + key.size = sizeof(recno); + key.ulen = key.size; + key.flags = DB_DBT_USERMEM; + + if (!make_dbt(dataobj, &data)) return NULL; + if (!checkTxnObj(txnobj, &txn)) return NULL; + + if (-1 == _DB_put(self, txn, &key, &data, DB_APPEND)) + return NULL; + + return PyInt_FromLong(recno); +} + + +#if (DBVER >= 33) + +static int +_db_associateCallback(DB* db, const DBT* priKey, const DBT* priData, + DBT* secKey) +{ + int retval = DB_DONOTINDEX; + DBObject* secondaryDB = (DBObject*)db->app_private; + PyObject* callback = secondaryDB->associateCallback; + int type = secondaryDB->primaryDBType; + PyObject* args; + PyObject* result = NULL; + + + if (callback != NULL) { + MYDB_BEGIN_BLOCK_THREADS; + + if (type == DB_RECNO || type == DB_QUEUE) + args = Py_BuildValue("(ls#)", *((db_recno_t*)priKey->data), + priData->data, priData->size); + else + args = Py_BuildValue("(s#s#)", priKey->data, priKey->size, + priData->data, priData->size); + if (args != NULL) { + result = PyEval_CallObject(callback, args); + } + if (args == NULL || result == NULL) { + PyErr_Print(); + } + else if (result == Py_None) { + retval = DB_DONOTINDEX; + } + else if (PyInt_Check(result)) { + retval = PyInt_AsLong(result); + } + else if (PyString_Check(result)) { + char* data; + Py_ssize_t size; + + CLEAR_DBT(*secKey); +#if PYTHON_API_VERSION <= 1007 + /* 1.5 compatibility */ + size = PyString_Size(result); + data = PyString_AsString(result); +#else + PyString_AsStringAndSize(result, &data, &size); +#endif + secKey->flags = DB_DBT_APPMALLOC; /* DB will free */ + secKey->data = malloc(size); /* TODO, check this */ + if (secKey->data) { + memcpy(secKey->data, data, size); + secKey->size = size; + retval = 0; + } + else { + PyErr_SetString(PyExc_MemoryError, + "malloc failed in _db_associateCallback"); + PyErr_Print(); + } + } + else { + PyErr_SetString( + PyExc_TypeError, + "DB associate callback should return DB_DONOTINDEX or string."); + PyErr_Print(); + } + + Py_XDECREF(args); + Py_XDECREF(result); + + MYDB_END_BLOCK_THREADS; + } + return retval; +} + + +static PyObject* +DB_associate(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + DBObject* secondaryDB; + PyObject* callback; +#if (DBVER >= 41) + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = {"secondaryDB", "callback", "flags", "txn", + NULL}; +#else + static char* kwnames[] = {"secondaryDB", "callback", "flags", NULL}; +#endif + +#if (DBVER >= 41) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iO:associate", kwnames, + &secondaryDB, &callback, &flags, + &txnobj)) { +#else + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:associate", kwnames, + &secondaryDB, &callback, &flags)) { +#endif + return NULL; + } + +#if (DBVER >= 41) + if (!checkTxnObj(txnobj, &txn)) return NULL; +#endif + + CHECK_DB_NOT_CLOSED(self); + if (!DBObject_Check(secondaryDB)) { + makeTypeError("DB", (PyObject*)secondaryDB); + return NULL; + } + CHECK_DB_NOT_CLOSED(secondaryDB); + if (callback == Py_None) { + callback = NULL; + } + else if (!PyCallable_Check(callback)) { + makeTypeError("Callable", callback); + return NULL; + } + + /* Save a reference to the callback in the secondary DB. */ + Py_XDECREF(secondaryDB->associateCallback); + Py_XINCREF(callback); + secondaryDB->associateCallback = callback; + secondaryDB->primaryDBType = _DB_get_type(self); + + /* PyEval_InitThreads is called here due to a quirk in python 1.5 + * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>: + * The global interepreter lock is not initialized until the first + * thread is created using thread.start_new_thread() or fork() is + * called. that would cause the ALLOW_THREADS here to segfault due + * to a null pointer reference if no threads or child processes + * have been created. This works around that and is a no-op if + * threads have already been initialized. + * (see pybsddb-users mailing list post on 2002-08-07) + */ +#ifdef WITH_THREAD + PyEval_InitThreads(); +#endif + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 41) + err = self->db->associate(self->db, + txn, + secondaryDB->db, + _db_associateCallback, + flags); +#else + err = self->db->associate(self->db, + secondaryDB->db, + _db_associateCallback, + flags); +#endif + MYDB_END_ALLOW_THREADS; + + if (err) { + Py_XDECREF(secondaryDB->associateCallback); + secondaryDB->associateCallback = NULL; + secondaryDB->primaryDBType = 0; + } + + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +#endif + + +static PyObject* +DB_close(DBObject* self, PyObject* args) +{ + int err, flags=0; + if (!PyArg_ParseTuple(args,"|i:close", &flags)) + return NULL; + if (self->db != NULL) { + if (self->myenvobj) + CHECK_ENV_NOT_CLOSED(self->myenvobj); + err = self->db->close(self->db, flags); + self->db = NULL; + RETURN_IF_ERR(); + } + RETURN_NONE(); +} + + +#if (DBVER >= 32) +static PyObject* +_DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag) +{ + int err, flags=0, type; + PyObject* txnobj = NULL; + PyObject* retval = NULL; + DBT key, data; + DB_TXN *txn = NULL; + static char* kwnames[] = { "txn", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:consume", kwnames, + &txnobj, &flags)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + type = _DB_get_type(self); + if (type == -1) + return NULL; + if (type != DB_QUEUE) { + PyErr_SetString(PyExc_TypeError, + "Consume methods only allowed for Queue DB's"); + return NULL; + } + if (!checkTxnObj(txnobj, &txn)) + return NULL; + + CLEAR_DBT(key); + CLEAR_DBT(data); + if (CHECK_DBFLAG(self, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + key.flags = DB_DBT_MALLOC; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->get(self->db, txn, &key, &data, flags|consume_flag); + MYDB_END_ALLOW_THREADS; + + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { + err = 0; + Py_INCREF(Py_None); + retval = Py_None; + } + else if (!err) { + retval = Py_BuildValue("s#s#", key.data, key.size, data.data, + data.size); + FREE_DBT(key); + FREE_DBT(data); + } + + RETURN_IF_ERR(); + return retval; +} + +static PyObject* +DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag) +{ + return _DB_consume(self, args, kwargs, DB_CONSUME); +} + +static PyObject* +DB_consume_wait(DBObject* self, PyObject* args, PyObject* kwargs, + int consume_flag) +{ + return _DB_consume(self, args, kwargs, DB_CONSUME_WAIT); +} +#endif + + + +static PyObject* +DB_cursor(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + DBC* dbc; + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = { "txn", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames, + &txnobj, &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + if (!checkTxnObj(txnobj, &txn)) + return NULL; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->cursor(self->db, txn, &dbc, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + return (PyObject*) newDBCursorObject(dbc, self); +} + + +static PyObject* +DB_delete(DBObject* self, PyObject* args, PyObject* kwargs) +{ + PyObject* txnobj = NULL; + int flags = 0; + PyObject* keyobj; + DBT key; + DB_TXN *txn = NULL; + static char* kwnames[] = { "key", "txn", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:delete", kwnames, + &keyobj, &txnobj, &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, NULL)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); + return NULL; + } + + if (-1 == _DB_delete(self, txn, &key, 0)) { + FREE_DBT(key); + return NULL; + } + + FREE_DBT(key); + RETURN_NONE(); +} + + +static PyObject* +DB_fd(DBObject* self, PyObject* args) +{ + int err, the_fd; + + if (!PyArg_ParseTuple(args,":fd")) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->fd(self->db, &the_fd); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + return PyInt_FromLong(the_fd); +} + + +static PyObject* +DB_get(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + PyObject* txnobj = NULL; + PyObject* keyobj; + PyObject* dfltobj = NULL; + PyObject* retval = NULL; + int dlen = -1; + int doff = -1; + DBT key, data; + DB_TXN *txn = NULL; + static char* kwnames[] = {"key", "default", "txn", "flags", "dlen", + "doff", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:get", kwnames, + &keyobj, &dfltobj, &txnobj, &flags, &dlen, + &doff)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, &flags)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); + return NULL; + } + + CLEAR_DBT(data); + if (CHECK_DBFLAG(self, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + } + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->get(self->db, txn, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) { + err = 0; + Py_INCREF(dfltobj); + retval = dfltobj; + } + else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { + err = 0; + Py_INCREF(Py_None); + retval = Py_None; + } + else if (!err) { + if (flags & DB_SET_RECNO) /* return both key and data */ + retval = Py_BuildValue("s#s#", key.data, key.size, data.data, + data.size); + else /* return just the data */ + retval = PyString_FromStringAndSize((char*)data.data, data.size); + FREE_DBT(data); + } + FREE_DBT(key); + + RETURN_IF_ERR(); + return retval; +} + +#if (DBVER >= 33) +static PyObject* +DB_pget(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + PyObject* txnobj = NULL; + PyObject* keyobj; + PyObject* dfltobj = NULL; + PyObject* retval = NULL; + int dlen = -1; + int doff = -1; + DBT key, pkey, data; + DB_TXN *txn = NULL; + static char* kwnames[] = {"key", "default", "txn", "flags", "dlen", + "doff", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOiii:pget", kwnames, + &keyobj, &dfltobj, &txnobj, &flags, &dlen, + &doff)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, &flags)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); + return NULL; + } + + CLEAR_DBT(data); + if (CHECK_DBFLAG(self, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + } + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); + return NULL; + } + + CLEAR_DBT(pkey); + pkey.flags = DB_DBT_MALLOC; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->pget(self->db, txn, &key, &pkey, &data, flags); + MYDB_END_ALLOW_THREADS; + + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && (dfltobj != NULL)) { + err = 0; + Py_INCREF(dfltobj); + retval = dfltobj; + } + else if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { + err = 0; + Py_INCREF(Py_None); + retval = Py_None; + } + else if (!err) { + PyObject *pkeyObj; + PyObject *dataObj; + dataObj = PyString_FromStringAndSize(data.data, data.size); + + if (self->primaryDBType == DB_RECNO || + self->primaryDBType == DB_QUEUE) + pkeyObj = PyInt_FromLong(*(int *)pkey.data); + else + pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size); + + if (flags & DB_SET_RECNO) /* return key , pkey and data */ + { + PyObject *keyObj; + int type = _DB_get_type(self); + if (type == DB_RECNO || type == DB_QUEUE) + keyObj = PyInt_FromLong(*(int *)key.data); + else + keyObj = PyString_FromStringAndSize(key.data, key.size); +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj); +#else + retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj); +#endif + Py_DECREF(keyObj); + } + else /* return just the pkey and data */ + { +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(2, pkeyObj, dataObj); +#else + retval = Py_BuildValue("OO", pkeyObj, dataObj); +#endif + } + Py_DECREF(dataObj); + Py_DECREF(pkeyObj); + FREE_DBT(pkey); + FREE_DBT(data); + } + FREE_DBT(key); + + RETURN_IF_ERR(); + return retval; +} +#endif + + +/* Return size of entry */ +static PyObject* +DB_get_size(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + PyObject* txnobj = NULL; + PyObject* keyobj; + PyObject* retval = NULL; + DBT key, data; + DB_TXN *txn = NULL; + static char* kwnames[] = { "key", "txn", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:get_size", kwnames, + &keyobj, &txnobj)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, &flags)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); + return NULL; + } + CLEAR_DBT(data); + + /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and + thus getting the record size. */ + data.flags = DB_DBT_USERMEM; + data.ulen = 0; + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->get(self->db, txn, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + if (err == DB_BUFFER_SMALL) { + retval = PyInt_FromLong((long)data.size); + err = 0; + } + + FREE_DBT(key); + FREE_DBT(data); + RETURN_IF_ERR(); + return retval; +} + + +static PyObject* +DB_get_both(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + PyObject* txnobj = NULL; + PyObject* keyobj; + PyObject* dataobj; + PyObject* retval = NULL; + DBT key, data; + DB_TXN *txn = NULL; + static char* kwnames[] = { "key", "data", "txn", "flags", NULL }; + + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oi:get_both", kwnames, + &keyobj, &dataobj, &txnobj, &flags)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, NULL)) + return NULL; + if ( !make_dbt(dataobj, &data) || + !checkTxnObj(txnobj, &txn) ) + { + FREE_DBT(key); + return NULL; + } + + flags |= DB_GET_BOTH; + + if (CHECK_DBFLAG(self, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + /* TODO: Is this flag needed? We're passing a data object that should + match what's in the DB, so there should be no need to malloc. + We run the risk of freeing something twice! Check this. */ + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->get(self->db, txn, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->moduleFlags.getReturnsNone) { + err = 0; + Py_INCREF(Py_None); + retval = Py_None; + } + else if (!err) { + retval = PyString_FromStringAndSize((char*)data.data, data.size); + FREE_DBT(data); /* Only if retrieval was successful */ + } + + FREE_DBT(key); + RETURN_IF_ERR(); + return retval; +} + + +static PyObject* +DB_get_byteswapped(DBObject* self, PyObject* args) +{ +#if (DBVER >= 33) + int err = 0; +#endif + int retval = -1; + + if (!PyArg_ParseTuple(args,":get_byteswapped")) + return NULL; + CHECK_DB_NOT_CLOSED(self); + +#if (DBVER >= 33) + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->get_byteswapped(self->db, &retval); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); +#else + MYDB_BEGIN_ALLOW_THREADS; + retval = self->db->get_byteswapped(self->db); + MYDB_END_ALLOW_THREADS; +#endif + return PyInt_FromLong(retval); +} + + +static PyObject* +DB_get_type(DBObject* self, PyObject* args) +{ + int type; + + if (!PyArg_ParseTuple(args,":get_type")) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + type = _DB_get_type(self); + if (type == -1) + return NULL; + return PyInt_FromLong(type); +} + + +static PyObject* +DB_join(DBObject* self, PyObject* args) +{ + int err, flags=0; + int length, x; + PyObject* cursorsObj; + DBC** cursors; + DBC* dbc; + + if (!PyArg_ParseTuple(args,"O|i:join", &cursorsObj, &flags)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + + if (!PySequence_Check(cursorsObj)) { + PyErr_SetString(PyExc_TypeError, + "Sequence of DBCursor objects expected"); + return NULL; + } + + length = PyObject_Length(cursorsObj); + cursors = malloc((length+1) * sizeof(DBC*)); + if (!cursors) { + PyErr_NoMemory(); + return NULL; + } + + cursors[length] = NULL; + for (x=0; x<length; x++) { + PyObject* item = PySequence_GetItem(cursorsObj, x); + if (item == NULL) { + free(cursors); + return NULL; + } + if (!DBCursorObject_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "Sequence of DBCursor objects expected"); + free(cursors); + return NULL; + } + cursors[x] = ((DBCursorObject*)item)->dbc; + Py_DECREF(item); + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->join(self->db, cursors, &dbc, flags); + MYDB_END_ALLOW_THREADS; + free(cursors); + RETURN_IF_ERR(); + + /* FIXME: this is a buggy interface. The returned cursor + contains internal references to the passed in cursors + but does not hold python references to them or prevent + them from being closed prematurely. This can cause + python to crash when things are done in the wrong order. */ + return (PyObject*) newDBCursorObject(dbc, self); +} + + +static PyObject* +DB_key_range(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + PyObject* txnobj = NULL; + PyObject* keyobj; + DBT key; + DB_TXN *txn = NULL; + DB_KEY_RANGE range; + static char* kwnames[] = { "key", "txn", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:key_range", kwnames, + &keyobj, &txnobj, &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + if (!make_dbt(keyobj, &key)) + /* BTree only, don't need to allow for an int key */ + return NULL; + if (!checkTxnObj(txnobj, &txn)) + return NULL; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->key_range(self->db, txn, &key, &range, flags); + MYDB_END_ALLOW_THREADS; + + RETURN_IF_ERR(); + return Py_BuildValue("ddd", range.less, range.equal, range.greater); +} + + +static PyObject* +DB_open(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, type = DB_UNKNOWN, flags=0, mode=0660; + char* filename = NULL; + char* dbname = NULL; +#if (DBVER >= 41) + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + /* with dbname */ + static char* kwnames[] = { + "filename", "dbname", "dbtype", "flags", "mode", "txn", NULL}; + /* without dbname */ + static char* kwnames_basic[] = { + "filename", "dbtype", "flags", "mode", "txn", NULL}; +#else + /* with dbname */ + static char* kwnames[] = { + "filename", "dbname", "dbtype", "flags", "mode", NULL}; + /* without dbname */ + static char* kwnames_basic[] = { + "filename", "dbtype", "flags", "mode", NULL}; +#endif + +#if (DBVER >= 41) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziiiO:open", kwnames, + &filename, &dbname, &type, &flags, &mode, + &txnobj)) +#else + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|ziii:open", kwnames, + &filename, &dbname, &type, &flags, + &mode)) +#endif + { + PyErr_Clear(); + type = DB_UNKNOWN; flags = 0; mode = 0660; + filename = NULL; dbname = NULL; +#if (DBVER >= 41) + if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iiiO:open", + kwnames_basic, + &filename, &type, &flags, &mode, + &txnobj)) + return NULL; +#else + if (!PyArg_ParseTupleAndKeywords(args, kwargs,"z|iii:open", + kwnames_basic, + &filename, &type, &flags, &mode)) + return NULL; +#endif + } + +#if (DBVER >= 41) + if (!checkTxnObj(txnobj, &txn)) return NULL; +#endif + + if (NULL == self->db) { + PyObject *t = Py_BuildValue("(is)", 0, + "Cannot call open() twice for DB object"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return NULL; + } + +#if 0 && (DBVER >= 41) + if ((!txn) && (txnobj != Py_None) && self->myenvobj + && (self->myenvobj->flags & DB_INIT_TXN)) + { + /* If no 'txn' parameter was supplied (no DbTxn object and None was not + * explicitly passed) but we are in a transaction ready environment: + * add DB_AUTO_COMMIT to allow for older pybsddb apps using transactions + * to work on BerkeleyDB 4.1 without needing to modify their + * DBEnv or DB open calls. + * TODO make this behaviour of the library configurable. + */ + flags |= DB_AUTO_COMMIT; + } +#endif + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 41) + err = self->db->open(self->db, txn, filename, dbname, type, flags, mode); +#else + err = self->db->open(self->db, filename, dbname, type, flags, mode); +#endif + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + self->db->close(self->db, 0); + self->db = NULL; + return NULL; + } + + self->flags = flags; + RETURN_NONE(); +} + + +static PyObject* +DB_put(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int flags=0; + PyObject* txnobj = NULL; + int dlen = -1; + int doff = -1; + PyObject* keyobj, *dataobj, *retval; + DBT key, data; + DB_TXN *txn = NULL; + static char* kwnames[] = { "key", "data", "txn", "flags", "dlen", + "doff", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|Oiii:put", kwnames, + &keyobj, &dataobj, &txnobj, &flags, &dlen, &doff)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, NULL)) + return NULL; + if ( !make_dbt(dataobj, &data) || + !add_partial_dbt(&data, dlen, doff) || + !checkTxnObj(txnobj, &txn) ) + { + FREE_DBT(key); + return NULL; + } + + if (-1 == _DB_put(self, txn, &key, &data, flags)) { + FREE_DBT(key); + return NULL; + } + + if (flags & DB_APPEND) + retval = PyInt_FromLong(*((db_recno_t*)key.data)); + else { + retval = Py_None; + Py_INCREF(retval); + } + FREE_DBT(key); + return retval; +} + + + +static PyObject* +DB_remove(DBObject* self, PyObject* args, PyObject* kwargs) +{ + char* filename; + char* database = NULL; + int err, flags=0; + static char* kwnames[] = { "filename", "dbname", "flags", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zi:remove", kwnames, + &filename, &database, &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + err = self->db->remove(self->db, filename, database, flags); + self->db = NULL; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + + +static PyObject* +DB_rename(DBObject* self, PyObject* args) +{ + char* filename; + char* database; + char* newname; + int err, flags=0; + + if (!PyArg_ParseTuple(args, "sss|i:rename", &filename, &database, &newname, + &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->rename(self->db, filename, database, newname, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_bt_minkey(DBObject* self, PyObject* args) +{ + int err, minkey; + + if (!PyArg_ParseTuple(args,"i:set_bt_minkey", &minkey )) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_bt_minkey(self->db, minkey); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +#if (DBVER >= 33) +static int +_default_cmp(const DBT *leftKey, + const DBT *rightKey) +{ + int res; + int lsize = leftKey->size, rsize = rightKey->size; + + res = memcmp(leftKey->data, rightKey->data, + lsize < rsize ? lsize : rsize); + + if (res == 0) { + if (lsize < rsize) { + res = -1; + } + else if (lsize > rsize) { + res = 1; + } + } + return res; +} + +static int +_db_compareCallback(DB* db, + const DBT *leftKey, + const DBT *rightKey) +{ + int res = 0; + PyObject *args; + PyObject *result = NULL; + DBObject *self = (DBObject *)db->app_private; + + if (self == NULL || self->btCompareCallback == NULL) { + MYDB_BEGIN_BLOCK_THREADS; + PyErr_SetString(PyExc_TypeError, + (self == 0 + ? "DB_bt_compare db is NULL." + : "DB_bt_compare callback is NULL.")); + /* we're in a callback within the DB code, we can't raise */ + PyErr_Print(); + res = _default_cmp(leftKey, rightKey); + MYDB_END_BLOCK_THREADS; + } else { + MYDB_BEGIN_BLOCK_THREADS; + + args = Py_BuildValue("s#s#", leftKey->data, leftKey->size, + rightKey->data, rightKey->size); + if (args != NULL) { + /* XXX(twouters) I highly doubt this INCREF is correct */ + Py_INCREF(self); + result = PyEval_CallObject(self->btCompareCallback, args); + } + if (args == NULL || result == NULL) { + /* we're in a callback within the DB code, we can't raise */ + PyErr_Print(); + res = _default_cmp(leftKey, rightKey); + } else if (PyInt_Check(result)) { + res = PyInt_AsLong(result); + } else { + PyErr_SetString(PyExc_TypeError, + "DB_bt_compare callback MUST return an int."); + /* we're in a callback within the DB code, we can't raise */ + PyErr_Print(); + res = _default_cmp(leftKey, rightKey); + } + + Py_XDECREF(args); + Py_XDECREF(result); + + MYDB_END_BLOCK_THREADS; + } + return res; +} + +static PyObject* +DB_set_bt_compare(DBObject* self, PyObject* args) +{ + int err; + PyObject *comparator; + PyObject *tuple, *result; + + if (!PyArg_ParseTuple(args, "O:set_bt_compare", &comparator)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + + if (!PyCallable_Check(comparator)) { + makeTypeError("Callable", comparator); + return NULL; + } + + /* + * Perform a test call of the comparator function with two empty + * string objects here. verify that it returns an int (0). + * err if not. + */ + tuple = Py_BuildValue("(ss)", "", ""); + result = PyEval_CallObject(comparator, tuple); + Py_DECREF(tuple); + if (result == NULL) + return NULL; + if (!PyInt_Check(result)) { + PyErr_SetString(PyExc_TypeError, + "callback MUST return an int"); + return NULL; + } else if (PyInt_AsLong(result) != 0) { + PyErr_SetString(PyExc_TypeError, + "callback failed to return 0 on two empty strings"); + return NULL; + } + Py_DECREF(result); + + /* We don't accept multiple set_bt_compare operations, in order to + * simplify the code. This would have no real use, as one cannot + * change the function once the db is opened anyway */ + if (self->btCompareCallback != NULL) { + PyErr_SetString(PyExc_RuntimeError, "set_bt_compare() cannot be called more than once"); + return NULL; + } + + Py_INCREF(comparator); + self->btCompareCallback = comparator; + + /* This is to workaround a problem with un-initialized threads (see + comment in DB_associate) */ +#ifdef WITH_THREAD + PyEval_InitThreads(); +#endif + + err = self->db->set_bt_compare(self->db, _db_compareCallback); + + if (err) { + /* restore the old state in case of error */ + Py_DECREF(comparator); + self->btCompareCallback = NULL; + } + + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif /* DBVER >= 33 */ + + +static PyObject* +DB_set_cachesize(DBObject* self, PyObject* args) +{ + int err; + int gbytes = 0, bytes = 0, ncache = 0; + + if (!PyArg_ParseTuple(args,"ii|i:set_cachesize", + &gbytes,&bytes,&ncache)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_cachesize(self->db, gbytes, bytes, ncache); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_flags(DBObject* self, PyObject* args) +{ + int err, flags; + + if (!PyArg_ParseTuple(args,"i:set_flags", &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_flags(self->db, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + self->setflags |= flags; + RETURN_NONE(); +} + + +static PyObject* +DB_set_h_ffactor(DBObject* self, PyObject* args) +{ + int err, ffactor; + + if (!PyArg_ParseTuple(args,"i:set_h_ffactor", &ffactor)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_h_ffactor(self->db, ffactor); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_h_nelem(DBObject* self, PyObject* args) +{ + int err, nelem; + + if (!PyArg_ParseTuple(args,"i:set_h_nelem", &nelem)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_h_nelem(self->db, nelem); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_lorder(DBObject* self, PyObject* args) +{ + int err, lorder; + + if (!PyArg_ParseTuple(args,"i:set_lorder", &lorder)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_lorder(self->db, lorder); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_pagesize(DBObject* self, PyObject* args) +{ + int err, pagesize; + + if (!PyArg_ParseTuple(args,"i:set_pagesize", &pagesize)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_pagesize(self->db, pagesize); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_re_delim(DBObject* self, PyObject* args) +{ + int err; + char delim; + + if (!PyArg_ParseTuple(args,"b:set_re_delim", &delim)) { + PyErr_Clear(); + if (!PyArg_ParseTuple(args,"c:set_re_delim", &delim)) + return NULL; + } + + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_re_delim(self->db, delim); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DB_set_re_len(DBObject* self, PyObject* args) +{ + int err, len; + + if (!PyArg_ParseTuple(args,"i:set_re_len", &len)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_re_len(self->db, len); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_re_pad(DBObject* self, PyObject* args) +{ + int err; + char pad; + + if (!PyArg_ParseTuple(args,"b:set_re_pad", &pad)) { + PyErr_Clear(); + if (!PyArg_ParseTuple(args,"c:set_re_pad", &pad)) + return NULL; + } + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_re_pad(self->db, pad); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_re_source(DBObject* self, PyObject* args) +{ + int err; + char *re_source; + + if (!PyArg_ParseTuple(args,"s:set_re_source", &re_source)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_re_source(self->db, re_source); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +#if (DBVER >= 32) +static PyObject* +DB_set_q_extentsize(DBObject* self, PyObject* args) +{ + int err; + int extentsize; + + if (!PyArg_ParseTuple(args,"i:set_q_extentsize", &extentsize)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_q_extentsize(self->db, extentsize); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif + +static PyObject* +DB_stat(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags = 0, type; + void* sp; + PyObject* d; +#if (DBVER >= 43) + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = { "flags", "txn", NULL }; +#else + static char* kwnames[] = { "flags", NULL }; +#endif + +#if (DBVER >= 43) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iO:stat", kwnames, + &flags, &txnobj)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) + return NULL; +#else + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags)) + return NULL; +#endif + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 43) + err = self->db->stat(self->db, txn, &sp, flags); +#elif (DBVER >= 33) + err = self->db->stat(self->db, &sp, flags); +#else + err = self->db->stat(self->db, &sp, NULL, flags); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + self->haveStat = 1; + + /* Turn the stat structure into a dictionary */ + type = _DB_get_type(self); + if ((type == -1) || ((d = PyDict_New()) == NULL)) { + free(sp); + return NULL; + } + +#define MAKE_HASH_ENTRY(name) _addIntToDict(d, #name, ((DB_HASH_STAT*)sp)->hash_##name) +#define MAKE_BT_ENTRY(name) _addIntToDict(d, #name, ((DB_BTREE_STAT*)sp)->bt_##name) +#define MAKE_QUEUE_ENTRY(name) _addIntToDict(d, #name, ((DB_QUEUE_STAT*)sp)->qs_##name) + + switch (type) { + case DB_HASH: + MAKE_HASH_ENTRY(magic); + MAKE_HASH_ENTRY(version); + MAKE_HASH_ENTRY(nkeys); + MAKE_HASH_ENTRY(ndata); + MAKE_HASH_ENTRY(pagesize); +#if (DBVER < 41) + MAKE_HASH_ENTRY(nelem); +#endif + MAKE_HASH_ENTRY(ffactor); + MAKE_HASH_ENTRY(buckets); + MAKE_HASH_ENTRY(free); + MAKE_HASH_ENTRY(bfree); + MAKE_HASH_ENTRY(bigpages); + MAKE_HASH_ENTRY(big_bfree); + MAKE_HASH_ENTRY(overflows); + MAKE_HASH_ENTRY(ovfl_free); + MAKE_HASH_ENTRY(dup); + MAKE_HASH_ENTRY(dup_free); + break; + + case DB_BTREE: + case DB_RECNO: + MAKE_BT_ENTRY(magic); + MAKE_BT_ENTRY(version); + MAKE_BT_ENTRY(nkeys); + MAKE_BT_ENTRY(ndata); + MAKE_BT_ENTRY(pagesize); + MAKE_BT_ENTRY(minkey); + MAKE_BT_ENTRY(re_len); + MAKE_BT_ENTRY(re_pad); + MAKE_BT_ENTRY(levels); + MAKE_BT_ENTRY(int_pg); + MAKE_BT_ENTRY(leaf_pg); + MAKE_BT_ENTRY(dup_pg); + MAKE_BT_ENTRY(over_pg); + MAKE_BT_ENTRY(free); + MAKE_BT_ENTRY(int_pgfree); + MAKE_BT_ENTRY(leaf_pgfree); + MAKE_BT_ENTRY(dup_pgfree); + MAKE_BT_ENTRY(over_pgfree); + break; + + case DB_QUEUE: + MAKE_QUEUE_ENTRY(magic); + MAKE_QUEUE_ENTRY(version); + MAKE_QUEUE_ENTRY(nkeys); + MAKE_QUEUE_ENTRY(ndata); + MAKE_QUEUE_ENTRY(pagesize); + MAKE_QUEUE_ENTRY(pages); + MAKE_QUEUE_ENTRY(re_len); + MAKE_QUEUE_ENTRY(re_pad); + MAKE_QUEUE_ENTRY(pgfree); +#if (DBVER == 31) + MAKE_QUEUE_ENTRY(start); +#endif + MAKE_QUEUE_ENTRY(first_recno); + MAKE_QUEUE_ENTRY(cur_recno); + break; + + default: + PyErr_SetString(PyExc_TypeError, "Unknown DB type, unable to stat"); + Py_DECREF(d); + d = NULL; + } + +#undef MAKE_HASH_ENTRY +#undef MAKE_BT_ENTRY +#undef MAKE_QUEUE_ENTRY + + free(sp); + return d; +} + +static PyObject* +DB_sync(DBObject* self, PyObject* args) +{ + int err; + int flags = 0; + + if (!PyArg_ParseTuple(args,"|i:sync", &flags )) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->sync(self->db, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +#if (DBVER >= 33) +static PyObject* +DB_truncate(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + u_int32_t count=0; + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = { "txn", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:cursor", kwnames, + &txnobj, &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + if (!checkTxnObj(txnobj, &txn)) + return NULL; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->truncate(self->db, txn, &count, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + return PyInt_FromLong(count); +} +#endif + + +static PyObject* +DB_upgrade(DBObject* self, PyObject* args) +{ + int err, flags=0; + char *filename; + + if (!PyArg_ParseTuple(args,"s|i:upgrade", &filename, &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->upgrade(self->db, filename, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_verify(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags=0; + char* fileName; + char* dbName=NULL; + char* outFileName=NULL; + FILE* outFile=NULL; + static char* kwnames[] = { "filename", "dbname", "outfile", "flags", + NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zzi:verify", kwnames, + &fileName, &dbName, &outFileName, &flags)) + return NULL; + + CHECK_DB_NOT_CLOSED(self); + if (outFileName) + outFile = fopen(outFileName, "w"); + /* XXX(nnorwitz): it should probably be an exception if outFile + can't be opened. */ + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->verify(self->db, fileName, dbName, outFile, flags); + MYDB_END_ALLOW_THREADS; + if (outFile) + fclose(outFile); + + /* DB.verify acts as a DB handle destructor (like close); this was + * documented in BerkeleyDB 4.2 but had the undocumented effect + * of not being safe in prior versions while still requiring an explicit + * DB.close call afterwards. Lets call close for the user to emulate + * the safe 4.2 behaviour. */ +#if (DBVER <= 41) + self->db->close(self->db, 0); +#endif + self->db = NULL; + + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DB_set_get_returns_none(DBObject* self, PyObject* args) +{ + int flags=0; + int oldValue=0; + + if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + + if (self->moduleFlags.getReturnsNone) + ++oldValue; + if (self->moduleFlags.cursorSetReturnsNone) + ++oldValue; + self->moduleFlags.getReturnsNone = (flags >= 1); + self->moduleFlags.cursorSetReturnsNone = (flags >= 2); + return PyInt_FromLong(oldValue); +} + +#if (DBVER >= 41) +static PyObject* +DB_set_encrypt(DBObject* self, PyObject* args, PyObject* kwargs) +{ + int err; + u_int32_t flags=0; + char *passwd = NULL; + static char* kwnames[] = { "passwd", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames, + &passwd, &flags)) { + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->set_encrypt(self->db, passwd, flags); + MYDB_END_ALLOW_THREADS; + + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif /* DBVER >= 41 */ + + +/*-------------------------------------------------------------- */ +/* Mapping and Dictionary-like access routines */ + +Py_ssize_t DB_length(PyObject* _self) +{ + int err; + Py_ssize_t size = 0; + int flags = 0; + void* sp; + DBObject* self = (DBObject*)_self; + + if (self->db == NULL) { + PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return -1; + } + + if (self->haveStat) { /* Has the stat function been called recently? If + so, we can use the cached value. */ + flags = DB_FAST_STAT; + } + + MYDB_BEGIN_ALLOW_THREADS; +redo_stat_for_length: +#if (DBVER >= 43) + err = self->db->stat(self->db, /*txnid*/ NULL, &sp, flags); +#elif (DBVER >= 33) + err = self->db->stat(self->db, &sp, flags); +#else + err = self->db->stat(self->db, &sp, NULL, flags); +#endif + + /* All the stat structures have matching fields upto the ndata field, + so we can use any of them for the type cast */ + size = ((DB_BTREE_STAT*)sp)->bt_ndata; + + /* A size of 0 could mean that BerkeleyDB no longer had the stat values cached. + * redo a full stat to make sure. + * Fixes SF python bug 1493322, pybsddb bug 1184012 + */ + if (size == 0 && (flags & DB_FAST_STAT)) { + flags = 0; + if (!err) + free(sp); + goto redo_stat_for_length; + } + + MYDB_END_ALLOW_THREADS; + + if (err) + return -1; + + self->haveStat = 1; + + free(sp); + return size; +} + + +PyObject* DB_subscript(DBObject* self, PyObject* keyobj) +{ + int err; + PyObject* retval; + DBT key; + DBT data; + + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, NULL)) + return NULL; + + CLEAR_DBT(data); + if (CHECK_DBFLAG(self, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + } + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->get(self->db, NULL, &key, &data, 0); + MYDB_END_ALLOW_THREADS; + if (err == DB_NOTFOUND || err == DB_KEYEMPTY) { + PyErr_SetObject(PyExc_KeyError, keyobj); + retval = NULL; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { + retval = PyString_FromStringAndSize((char*)data.data, data.size); + FREE_DBT(data); + } + + FREE_DBT(key); + return retval; +} + + +static int +DB_ass_sub(DBObject* self, PyObject* keyobj, PyObject* dataobj) +{ + DBT key, data; + int retval; + int flags = 0; + + if (self->db == NULL) { + PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return -1; + } + + if (!make_key_dbt(self, keyobj, &key, NULL)) + return -1; + + if (dataobj != NULL) { + if (!make_dbt(dataobj, &data)) + retval = -1; + else { + if (self->setflags & (DB_DUP|DB_DUPSORT)) + /* dictionaries shouldn't have duplicate keys */ + flags = DB_NOOVERWRITE; + retval = _DB_put(self, NULL, &key, &data, flags); + + if ((retval == -1) && (self->setflags & (DB_DUP|DB_DUPSORT))) { + /* try deleting any old record that matches and then PUT it + * again... */ + _DB_delete(self, NULL, &key, 0); + PyErr_Clear(); + retval = _DB_put(self, NULL, &key, &data, flags); + } + } + } + else { + /* dataobj == NULL, so delete the key */ + retval = _DB_delete(self, NULL, &key, 0); + } + FREE_DBT(key); + return retval; +} + + +static PyObject* +DB_has_key(DBObject* self, PyObject* args) +{ + int err; + PyObject* keyobj; + DBT key, data; + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + + if (!PyArg_ParseTuple(args,"O|O:has_key", &keyobj, &txnobj)) + return NULL; + CHECK_DB_NOT_CLOSED(self); + if (!make_key_dbt(self, keyobj, &key, NULL)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) { + FREE_DBT(key); + return NULL; + } + + /* This causes DB_BUFFER_SMALL to be returned when the db has the key because + it has a record but can't allocate a buffer for the data. This saves + having to deal with data we won't be using. + */ + CLEAR_DBT(data); + data.flags = DB_DBT_USERMEM; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->get(self->db, txn, &key, &data, 0); + MYDB_END_ALLOW_THREADS; + FREE_DBT(key); + + if (err == DB_BUFFER_SMALL || err == 0) { + return PyInt_FromLong(1); + } else if (err == DB_NOTFOUND || err == DB_KEYEMPTY) { + return PyInt_FromLong(0); + } + + makeDBError(err); + return NULL; +} + + +#define _KEYS_LIST 1 +#define _VALUES_LIST 2 +#define _ITEMS_LIST 3 + +static PyObject* +_DB_make_list(DBObject* self, DB_TXN* txn, int type) +{ + int err, dbtype; + DBT key; + DBT data; + DBC *cursor; + PyObject* list; + PyObject* item = NULL; + + CHECK_DB_NOT_CLOSED(self); + CLEAR_DBT(key); + CLEAR_DBT(data); + + dbtype = _DB_get_type(self); + if (dbtype == -1) + return NULL; + + list = PyList_New(0); + if (list == NULL) + return NULL; + + /* get a cursor */ + MYDB_BEGIN_ALLOW_THREADS; + err = self->db->cursor(self->db, txn, &cursor, 0); + MYDB_END_ALLOW_THREADS; + if (makeDBError(err)) { + Py_DECREF(list); + return NULL; + } + + if (CHECK_DBFLAG(self, DB_THREAD)) { + key.flags = DB_DBT_REALLOC; + data.flags = DB_DBT_REALLOC; + } + + while (1) { /* use the cursor to traverse the DB, collecting items */ + MYDB_BEGIN_ALLOW_THREADS; + err = cursor->c_get(cursor, &key, &data, DB_NEXT); + MYDB_END_ALLOW_THREADS; + + if (err) { + /* for any error, break out of the loop */ + break; + } + + switch (type) { + case _KEYS_LIST: + switch(dbtype) { + case DB_BTREE: + case DB_HASH: + default: + item = PyString_FromStringAndSize((char*)key.data, key.size); + break; + case DB_RECNO: + case DB_QUEUE: + item = PyInt_FromLong(*((db_recno_t*)key.data)); + break; + } + break; + + case _VALUES_LIST: + item = PyString_FromStringAndSize((char*)data.data, data.size); + break; + + case _ITEMS_LIST: + switch(dbtype) { + case DB_BTREE: + case DB_HASH: + default: + item = Py_BuildValue("s#s#", key.data, key.size, data.data, + data.size); + break; + case DB_RECNO: + case DB_QUEUE: + item = Py_BuildValue("is#", *((db_recno_t*)key.data), + data.data, data.size); + break; + } + break; + default: + PyErr_Format(PyExc_ValueError, "Unknown key type 0x%x", type); + item = NULL; + break; + } + if (item == NULL) { + Py_DECREF(list); + list = NULL; + goto done; + } + PyList_Append(list, item); + Py_DECREF(item); + } + + /* DB_NOTFOUND || DB_KEYEMPTY is okay, it means we got to the end */ + if (err != DB_NOTFOUND && err != DB_KEYEMPTY && makeDBError(err)) { + Py_DECREF(list); + list = NULL; + } + + done: + FREE_DBT(key); + FREE_DBT(data); + MYDB_BEGIN_ALLOW_THREADS; + cursor->c_close(cursor); + MYDB_END_ALLOW_THREADS; + return list; +} + + +static PyObject* +DB_keys(DBObject* self, PyObject* args) +{ + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + + if (!PyArg_UnpackTuple(args, "keys", 0, 1, &txnobj)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) + return NULL; + return _DB_make_list(self, txn, _KEYS_LIST); +} + + +static PyObject* +DB_items(DBObject* self, PyObject* args) +{ + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + + if (!PyArg_UnpackTuple(args, "items", 0, 1, &txnobj)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) + return NULL; + return _DB_make_list(self, txn, _ITEMS_LIST); +} + + +static PyObject* +DB_values(DBObject* self, PyObject* args) +{ + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + + if (!PyArg_UnpackTuple(args, "values", 0, 1, &txnobj)) + return NULL; + if (!checkTxnObj(txnobj, &txn)) + return NULL; + return _DB_make_list(self, txn, _VALUES_LIST); +} + +/* --------------------------------------------------------------------- */ +/* DBCursor methods */ + + +static PyObject* +DBC_close(DBCursorObject* self, PyObject* args) +{ + int err = 0; + + if (!PyArg_ParseTuple(args, ":close")) + return NULL; + + if (self->dbc != NULL) { + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_close(self->dbc); + self->dbc = NULL; + MYDB_END_ALLOW_THREADS; + } + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBC_count(DBCursorObject* self, PyObject* args) +{ + int err = 0; + db_recno_t count; + int flags = 0; + + if (!PyArg_ParseTuple(args, "|i:count", &flags)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_count(self->dbc, &count, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + return PyInt_FromLong(count); +} + + +static PyObject* +DBC_current(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_CURRENT,args,kwargs,"|iii:current"); +} + + +static PyObject* +DBC_delete(DBCursorObject* self, PyObject* args) +{ + int err, flags=0; + + if (!PyArg_ParseTuple(args, "|i:delete", &flags)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_del(self->dbc, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + self->mydb->haveStat = 0; + RETURN_NONE(); +} + + +static PyObject* +DBC_dup(DBCursorObject* self, PyObject* args) +{ + int err, flags =0; + DBC* dbc = NULL; + + if (!PyArg_ParseTuple(args, "|i:dup", &flags)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_dup(self->dbc, &dbc, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + return (PyObject*) newDBCursorObject(dbc, self->mydb); +} + +static PyObject* +DBC_first(DBCursorObject* self, PyObject* args, PyObject* kwargs) +{ + return _DBCursor_get(self,DB_FIRST,args,kwargs,"|iii:first"); +} + + +static PyObject* +DBC_get(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + int err, flags=0; + PyObject* keyobj = NULL; + PyObject* dataobj = NULL; + PyObject* retval = NULL; + int dlen = -1; + int doff = -1; + DBT key, data; + static char* kwnames[] = { "key","data", "flags", "dlen", "doff", + NULL }; + + CLEAR_DBT(key); + CLEAR_DBT(data); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:get", &kwnames[2], + &flags, &dlen, &doff)) + { + PyErr_Clear(); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:get", + &kwnames[1], + &keyobj, &flags, &dlen, &doff)) + { + PyErr_Clear(); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:get", + kwnames, &keyobj, &dataobj, + &flags, &dlen, &doff)) + { + return NULL; + } + } + } + + CHECK_CURSOR_NOT_CLOSED(self); + + if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL)) + return NULL; + if ( (dataobj && !make_dbt(dataobj, &data)) || + (!add_partial_dbt(&data, dlen, doff)) ) + { + FREE_DBT(key); + return NULL; + } + + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + data.flags = DB_DBT_MALLOC; + if (!(key.flags & DB_DBT_REALLOC)) { + key.flags |= DB_DBT_MALLOC; + } + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { + switch (_DB_get_type(self->mydb)) { + case -1: + retval = NULL; + break; + case DB_BTREE: + case DB_HASH: + default: + retval = Py_BuildValue("s#s#", key.data, key.size, + data.data, data.size); + break; + case DB_RECNO: + case DB_QUEUE: + retval = Py_BuildValue("is#", *((db_recno_t*)key.data), + data.data, data.size); + break; + } + FREE_DBT(data); + } + FREE_DBT(key); + return retval; +} + +#if (DBVER >= 33) +static PyObject* +DBC_pget(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + int err, flags=0; + PyObject* keyobj = NULL; + PyObject* dataobj = NULL; + PyObject* retval = NULL; + int dlen = -1; + int doff = -1; + DBT key, pkey, data; + static char* kwnames_keyOnly[] = { "key", "flags", "dlen", "doff", NULL }; + static char* kwnames[] = { "key", "data", "flags", "dlen", "doff", NULL }; + + CLEAR_DBT(key); + CLEAR_DBT(data); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|ii:pget", &kwnames[2], + &flags, &dlen, &doff)) + { + PyErr_Clear(); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi|ii:pget", + kwnames_keyOnly, + &keyobj, &flags, &dlen, &doff)) + { + PyErr_Clear(); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOi|ii:pget", + kwnames, &keyobj, &dataobj, + &flags, &dlen, &doff)) + { + return NULL; + } + } + } + + CHECK_CURSOR_NOT_CLOSED(self); + + if (keyobj && !make_key_dbt(self->mydb, keyobj, &key, NULL)) + return NULL; + if ( (dataobj && !make_dbt(dataobj, &data)) || + (!add_partial_dbt(&data, dlen, doff)) ) { + FREE_DBT(key); + return NULL; + } + + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + data.flags = DB_DBT_MALLOC; + if (!(key.flags & DB_DBT_REALLOC)) { + key.flags |= DB_DBT_MALLOC; + } + } + + CLEAR_DBT(pkey); + pkey.flags = DB_DBT_MALLOC; + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_pget(self->dbc, &key, &pkey, &data, flags); + MYDB_END_ALLOW_THREADS; + + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { + PyObject *pkeyObj; + PyObject *dataObj; + dataObj = PyString_FromStringAndSize(data.data, data.size); + + if (self->mydb->primaryDBType == DB_RECNO || + self->mydb->primaryDBType == DB_QUEUE) + pkeyObj = PyInt_FromLong(*(int *)pkey.data); + else + pkeyObj = PyString_FromStringAndSize(pkey.data, pkey.size); + + if (key.data && key.size) /* return key, pkey and data */ + { + PyObject *keyObj; + int type = _DB_get_type(self->mydb); + if (type == DB_RECNO || type == DB_QUEUE) + keyObj = PyInt_FromLong(*(int *)key.data); + else + keyObj = PyString_FromStringAndSize(key.data, key.size); +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(3, keyObj, pkeyObj, dataObj); +#else + retval = Py_BuildValue("OOO", keyObj, pkeyObj, dataObj); +#endif + Py_DECREF(keyObj); + FREE_DBT(key); + } + else /* return just the pkey and data */ + { +#if (PY_VERSION_HEX >= 0x02040000) + retval = PyTuple_Pack(2, pkeyObj, dataObj); +#else + retval = Py_BuildValue("OO", pkeyObj, dataObj); +#endif + } + Py_DECREF(dataObj); + Py_DECREF(pkeyObj); + FREE_DBT(pkey); + FREE_DBT(data); + } + /* the only time REALLOC should be set is if we used an integer + * key that make_key_dbt malloc'd for us. always free these. */ + if (key.flags & DB_DBT_REALLOC) { + FREE_DBT(key); + } + return retval; +} +#endif + + +static PyObject* +DBC_get_recno(DBCursorObject* self, PyObject* args) +{ + int err; + db_recno_t recno; + DBT key; + DBT data; + + if (!PyArg_ParseTuple(args, ":get_recno")) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + CLEAR_DBT(key); + CLEAR_DBT(data); + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + key.flags = DB_DBT_MALLOC; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, DB_GET_RECNO); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + recno = *((db_recno_t*)data.data); + FREE_DBT(key); + FREE_DBT(data); + return PyInt_FromLong(recno); +} + + +static PyObject* +DBC_last(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_LAST,args,kwargs,"|iii:last"); +} + + +static PyObject* +DBC_next(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_NEXT,args,kwargs,"|iii:next"); +} + + +static PyObject* +DBC_prev(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_PREV,args,kwargs,"|iii:prev"); +} + + +static PyObject* +DBC_put(DBCursorObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags = 0; + PyObject* keyobj, *dataobj; + DBT key, data; + static char* kwnames[] = { "key", "data", "flags", "dlen", "doff", + NULL }; + int dlen = -1; + int doff = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|iii:put", kwnames, + &keyobj, &dataobj, &flags, &dlen, &doff)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) + return NULL; + if (!make_dbt(dataobj, &data) || + !add_partial_dbt(&data, dlen, doff) ) + { + FREE_DBT(key); + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_put(self->dbc, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + FREE_DBT(key); + RETURN_IF_ERR(); + self->mydb->haveStat = 0; + RETURN_NONE(); +} + + +static PyObject* +DBC_set(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + int err, flags = 0; + DBT key, data; + PyObject* retval, *keyobj; + static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; + int dlen = -1; + int doff = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set", kwnames, + &keyobj, &flags, &dlen, &doff)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) + return NULL; + + CLEAR_DBT(data); + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + } + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET); + MYDB_END_ALLOW_THREADS; + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.cursorSetReturnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { + switch (_DB_get_type(self->mydb)) { + case -1: + retval = NULL; + break; + case DB_BTREE: + case DB_HASH: + default: + retval = Py_BuildValue("s#s#", key.data, key.size, + data.data, data.size); + break; + case DB_RECNO: + case DB_QUEUE: + retval = Py_BuildValue("is#", *((db_recno_t*)key.data), + data.data, data.size); + break; + } + FREE_DBT(data); + FREE_DBT(key); + } + /* the only time REALLOC should be set is if we used an integer + * key that make_key_dbt malloc'd for us. always free these. */ + if (key.flags & DB_DBT_REALLOC) { + FREE_DBT(key); + } + + return retval; +} + + +static PyObject* +DBC_set_range(DBCursorObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags = 0; + DBT key, data; + PyObject* retval, *keyobj; + static char* kwnames[] = { "key", "flags", "dlen", "doff", NULL }; + int dlen = -1; + int doff = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|iii:set_range", kwnames, + &keyobj, &flags, &dlen, &doff)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) + return NULL; + + CLEAR_DBT(data); + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); + return NULL; + } + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags |= DB_DBT_MALLOC; + /* only BTREE databases will return anything in the key */ + if (!(key.flags & DB_DBT_REALLOC) && _DB_get_type(self->mydb) == DB_BTREE) { + key.flags |= DB_DBT_MALLOC; + } + } + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RANGE); + MYDB_END_ALLOW_THREADS; + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.cursorSetReturnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { + switch (_DB_get_type(self->mydb)) { + case -1: + retval = NULL; + break; + case DB_BTREE: + case DB_HASH: + default: + retval = Py_BuildValue("s#s#", key.data, key.size, + data.data, data.size); + break; + case DB_RECNO: + case DB_QUEUE: + retval = Py_BuildValue("is#", *((db_recno_t*)key.data), + data.data, data.size); + break; + } + FREE_DBT(key); + FREE_DBT(data); + } + /* the only time REALLOC should be set is if we used an integer + * key that make_key_dbt malloc'd for us. always free these. */ + if (key.flags & DB_DBT_REALLOC) { + FREE_DBT(key); + } + + return retval; +} + +static PyObject* +_DBC_get_set_both(DBCursorObject* self, PyObject* keyobj, PyObject* dataobj, + int flags, unsigned int returnsNone) +{ + int err; + DBT key, data; + PyObject* retval; + + /* the caller did this: CHECK_CURSOR_NOT_CLOSED(self); */ + if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) + return NULL; + if (!make_dbt(dataobj, &data)) { + FREE_DBT(key); + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_GET_BOTH); + MYDB_END_ALLOW_THREADS; + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) && returnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { + switch (_DB_get_type(self->mydb)) { + case -1: + retval = NULL; + break; + case DB_BTREE: + case DB_HASH: + default: + retval = Py_BuildValue("s#s#", key.data, key.size, + data.data, data.size); + break; + case DB_RECNO: + case DB_QUEUE: + retval = Py_BuildValue("is#", *((db_recno_t*)key.data), + data.data, data.size); + break; + } + } + + FREE_DBT(key); + return retval; +} + +static PyObject* +DBC_get_both(DBCursorObject* self, PyObject* args) +{ + int flags=0; + PyObject *keyobj, *dataobj; + + if (!PyArg_ParseTuple(args, "OO|i:get_both", &keyobj, &dataobj, &flags)) + return NULL; + + /* if the cursor is closed, self->mydb may be invalid */ + CHECK_CURSOR_NOT_CLOSED(self); + + return _DBC_get_set_both(self, keyobj, dataobj, flags, + self->mydb->moduleFlags.getReturnsNone); +} + +/* Return size of entry */ +static PyObject* +DBC_get_current_size(DBCursorObject* self, PyObject* args) +{ + int err, flags=DB_CURRENT; + PyObject* retval = NULL; + DBT key, data; + + if (!PyArg_ParseTuple(args, ":get_current_size")) + return NULL; + CHECK_CURSOR_NOT_CLOSED(self); + CLEAR_DBT(key); + CLEAR_DBT(data); + + /* We don't allocate any memory, forcing a DB_BUFFER_SMALL error and thus + getting the record size. */ + data.flags = DB_DBT_USERMEM; + data.ulen = 0; + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags); + MYDB_END_ALLOW_THREADS; + if (err == DB_BUFFER_SMALL || !err) { + /* DB_BUFFER_SMALL means positive size, !err means zero length value */ + retval = PyInt_FromLong((long)data.size); + err = 0; + } + + FREE_DBT(key); + FREE_DBT(data); + RETURN_IF_ERR(); + return retval; +} + +static PyObject* +DBC_set_both(DBCursorObject* self, PyObject* args) +{ + int flags=0; + PyObject *keyobj, *dataobj; + + if (!PyArg_ParseTuple(args, "OO|i:set_both", &keyobj, &dataobj, &flags)) + return NULL; + + /* if the cursor is closed, self->mydb may be invalid */ + CHECK_CURSOR_NOT_CLOSED(self); + + return _DBC_get_set_both(self, keyobj, dataobj, flags, + self->mydb->moduleFlags.cursorSetReturnsNone); +} + + +static PyObject* +DBC_set_recno(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + int err, irecno, flags=0; + db_recno_t recno; + DBT key, data; + PyObject* retval; + int dlen = -1; + int doff = -1; + static char* kwnames[] = { "recno","flags", "dlen", "doff", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iii:set_recno", kwnames, + &irecno, &flags, &dlen, &doff)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + CLEAR_DBT(key); + recno = (db_recno_t) irecno; + /* use allocated space so DB will be able to realloc room for the real + * key */ + key.data = malloc(sizeof(db_recno_t)); + if (key.data == NULL) { + PyErr_SetString(PyExc_MemoryError, "Key memory allocation failed"); + return NULL; + } + key.size = sizeof(db_recno_t); + key.ulen = key.size; + memcpy(key.data, &recno, sizeof(db_recno_t)); + key.flags = DB_DBT_REALLOC; + + CLEAR_DBT(data); + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + data.flags = DB_DBT_MALLOC; + } + if (!add_partial_dbt(&data, dlen, doff)) { + FREE_DBT(key); + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags|DB_SET_RECNO); + MYDB_END_ALLOW_THREADS; + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.cursorSetReturnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { /* Can only be used for BTrees, so no need to return int key */ + retval = Py_BuildValue("s#s#", key.data, key.size, + data.data, data.size); + FREE_DBT(data); + } + FREE_DBT(key); + + return retval; +} + + +static PyObject* +DBC_consume(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_CONSUME,args,kwargs,"|iii:consume"); +} + + +static PyObject* +DBC_next_dup(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_NEXT_DUP,args,kwargs,"|iii:next_dup"); +} + + +static PyObject* +DBC_next_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_NEXT_NODUP,args,kwargs,"|iii:next_nodup"); +} + + +static PyObject* +DBC_prev_nodup(DBCursorObject* self, PyObject* args, PyObject *kwargs) +{ + return _DBCursor_get(self,DB_PREV_NODUP,args,kwargs,"|iii:prev_nodup"); +} + + +static PyObject* +DBC_join_item(DBCursorObject* self, PyObject* args) +{ + int err, flags=0; + DBT key, data; + PyObject* retval; + + if (!PyArg_ParseTuple(args, "|i:join_item", &flags)) + return NULL; + + CHECK_CURSOR_NOT_CLOSED(self); + + CLEAR_DBT(key); + CLEAR_DBT(data); + if (CHECK_DBFLAG(self->mydb, DB_THREAD)) { + /* Tell BerkeleyDB to malloc the return value (thread safe) */ + key.flags = DB_DBT_MALLOC; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->dbc->c_get(self->dbc, &key, &data, flags | DB_JOIN_ITEM); + MYDB_END_ALLOW_THREADS; + if ((err == DB_NOTFOUND || err == DB_KEYEMPTY) + && self->mydb->moduleFlags.getReturnsNone) { + Py_INCREF(Py_None); + retval = Py_None; + } + else if (makeDBError(err)) { + retval = NULL; + } + else { + retval = Py_BuildValue("s#", key.data, key.size); + FREE_DBT(key); + } + + return retval; +} + + + +/* --------------------------------------------------------------------- */ +/* DBEnv methods */ + + +static PyObject* +DBEnv_close(DBEnvObject* self, PyObject* args) +{ + int err, flags = 0; + + if (!PyArg_ParseTuple(args, "|i:close", &flags)) + return NULL; + if (!self->closed) { /* Don't close more than once */ + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->close(self->db_env, flags); + MYDB_END_ALLOW_THREADS; + /* after calling DBEnv->close, regardless of error, this DBEnv + * may not be accessed again (BerkeleyDB docs). */ + self->closed = 1; + self->db_env = NULL; + RETURN_IF_ERR(); + } + RETURN_NONE(); +} + + +static PyObject* +DBEnv_open(DBEnvObject* self, PyObject* args) +{ + int err, flags=0, mode=0660; + char *db_home; + + if (!PyArg_ParseTuple(args, "z|ii:open", &db_home, &flags, &mode)) + return NULL; + + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->open(self->db_env, db_home, flags, mode); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + self->closed = 0; + self->flags = flags; + RETURN_NONE(); +} + + +static PyObject* +DBEnv_remove(DBEnvObject* self, PyObject* args) +{ + int err, flags=0; + char *db_home; + + if (!PyArg_ParseTuple(args, "s|i:remove", &db_home, &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->remove(self->db_env, db_home, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +#if (DBVER >= 41) +static PyObject* +DBEnv_dbremove(DBEnvObject* self, PyObject* args, PyObject* kwargs) +{ + int err; + u_int32_t flags=0; + char *file = NULL; + char *database = NULL; + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = { "file", "database", "txn", "flags", + NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|zOi:dbremove", kwnames, + &file, &database, &txnobj, &flags)) { + return NULL; + } + if (!checkTxnObj(txnobj, &txn)) { + return NULL; + } + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->dbremove(self->db_env, txn, file, database, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBEnv_dbrename(DBEnvObject* self, PyObject* args, PyObject* kwargs) +{ + int err; + u_int32_t flags=0; + char *file = NULL; + char *database = NULL; + char *newname = NULL; + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = { "file", "database", "newname", "txn", + "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "szs|Oi:dbrename", kwnames, + &file, &database, &newname, &txnobj, &flags)) { + return NULL; + } + if (!checkTxnObj(txnobj, &txn)) { + return NULL; + } + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->dbrename(self->db_env, txn, file, database, newname, + flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBEnv_set_encrypt(DBEnvObject* self, PyObject* args, PyObject* kwargs) +{ + int err; + u_int32_t flags=0; + char *passwd = NULL; + static char* kwnames[] = { "passwd", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i:set_encrypt", kwnames, + &passwd, &flags)) { + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_encrypt(self->db_env, passwd, flags); + MYDB_END_ALLOW_THREADS; + + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif /* DBVER >= 41 */ + +#if (DBVER >= 40) +static PyObject* +DBEnv_set_timeout(DBEnvObject* self, PyObject* args, PyObject* kwargs) +{ + int err; + u_int32_t flags=0; + u_int32_t timeout = 0; + static char* kwnames[] = { "timeout", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii:set_timeout", kwnames, + &timeout, &flags)) { + return NULL; + } + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_timeout(self->db_env, (db_timeout_t)timeout, flags); + MYDB_END_ALLOW_THREADS; + + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif /* DBVER >= 40 */ + +static PyObject* +DBEnv_set_shm_key(DBEnvObject* self, PyObject* args) +{ + int err; + long shm_key = 0; + + if (!PyArg_ParseTuple(args, "l:set_shm_key", &shm_key)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + err = self->db_env->set_shm_key(self->db_env, shm_key); + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBEnv_set_cachesize(DBEnvObject* self, PyObject* args) +{ + int err, gbytes=0, bytes=0, ncache=0; + + if (!PyArg_ParseTuple(args, "ii|i:set_cachesize", + &gbytes, &bytes, &ncache)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_cachesize(self->db_env, gbytes, bytes, ncache); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +#if (DBVER >= 32) +static PyObject* +DBEnv_set_flags(DBEnvObject* self, PyObject* args) +{ + int err, flags=0, onoff=0; + + if (!PyArg_ParseTuple(args, "ii:set_flags", + &flags, &onoff)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_flags(self->db_env, flags, onoff); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif + + +static PyObject* +DBEnv_set_data_dir(DBEnvObject* self, PyObject* args) +{ + int err; + char *dir; + + if (!PyArg_ParseTuple(args, "s:set_data_dir", &dir)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_data_dir(self->db_env, dir); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_lg_bsize(DBEnvObject* self, PyObject* args) +{ + int err, lg_bsize; + + if (!PyArg_ParseTuple(args, "i:set_lg_bsize", &lg_bsize)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lg_bsize(self->db_env, lg_bsize); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_lg_dir(DBEnvObject* self, PyObject* args) +{ + int err; + char *dir; + + if (!PyArg_ParseTuple(args, "s:set_lg_dir", &dir)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lg_dir(self->db_env, dir); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBEnv_set_lg_max(DBEnvObject* self, PyObject* args) +{ + int err, lg_max; + + if (!PyArg_ParseTuple(args, "i:set_lg_max", &lg_max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lg_max(self->db_env, lg_max); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +#if (DBVER >= 33) +static PyObject* +DBEnv_set_lg_regionmax(DBEnvObject* self, PyObject* args) +{ + int err, lg_max; + + if (!PyArg_ParseTuple(args, "i:set_lg_regionmax", &lg_max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lg_regionmax(self->db_env, lg_max); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif + + +static PyObject* +DBEnv_set_lk_detect(DBEnvObject* self, PyObject* args) +{ + int err, lk_detect; + + if (!PyArg_ParseTuple(args, "i:set_lk_detect", &lk_detect)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lk_detect(self->db_env, lk_detect); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +#if (DBVER < 45) +static PyObject* +DBEnv_set_lk_max(DBEnvObject* self, PyObject* args) +{ + int err, max; + + if (!PyArg_ParseTuple(args, "i:set_lk_max", &max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lk_max(self->db_env, max); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif + + +#if (DBVER >= 32) + +static PyObject* +DBEnv_set_lk_max_locks(DBEnvObject* self, PyObject* args) +{ + int err, max; + + if (!PyArg_ParseTuple(args, "i:set_lk_max_locks", &max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lk_max_locks(self->db_env, max); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_lk_max_lockers(DBEnvObject* self, PyObject* args) +{ + int err, max; + + if (!PyArg_ParseTuple(args, "i:set_lk_max_lockers", &max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lk_max_lockers(self->db_env, max); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_lk_max_objects(DBEnvObject* self, PyObject* args) +{ + int err, max; + + if (!PyArg_ParseTuple(args, "i:set_lk_max_objects", &max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_lk_max_objects(self->db_env, max); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +#endif + + +static PyObject* +DBEnv_set_mp_mmapsize(DBEnvObject* self, PyObject* args) +{ + int err, mp_mmapsize; + + if (!PyArg_ParseTuple(args, "i:set_mp_mmapsize", &mp_mmapsize)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_mp_mmapsize(self->db_env, mp_mmapsize); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_tmp_dir(DBEnvObject* self, PyObject* args) +{ + int err; + char *dir; + + if (!PyArg_ParseTuple(args, "s:set_tmp_dir", &dir)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->set_tmp_dir(self->db_env, dir); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_txn_begin(DBEnvObject* self, PyObject* args, PyObject* kwargs) +{ + int flags = 0; + PyObject* txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = { "parent", "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:txn_begin", kwnames, + &txnobj, &flags)) + return NULL; + + if (!checkTxnObj(txnobj, &txn)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + return (PyObject*)newDBTxnObject(self, txn, flags); +} + + +static PyObject* +DBEnv_txn_checkpoint(DBEnvObject* self, PyObject* args) +{ + int err, kbyte=0, min=0, flags=0; + + if (!PyArg_ParseTuple(args, "|iii:txn_checkpoint", &kbyte, &min, &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->db_env->txn_checkpoint(self->db_env, kbyte, min, flags); +#else + err = txn_checkpoint(self->db_env, kbyte, min, flags); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_tx_max(DBEnvObject* self, PyObject* args) +{ + int err, max; + + if (!PyArg_ParseTuple(args, "i:set_tx_max", &max)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + err = self->db_env->set_tx_max(self->db_env, max); + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_set_tx_timestamp(DBEnvObject* self, PyObject* args) +{ + int err; + long stamp; + time_t timestamp; + + if (!PyArg_ParseTuple(args, "l:set_tx_timestamp", &stamp)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + timestamp = (time_t)stamp; + err = self->db_env->set_tx_timestamp(self->db_env, &timestamp); + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBEnv_lock_detect(DBEnvObject* self, PyObject* args) +{ + int err, atype, flags=0; + int aborted = 0; + + if (!PyArg_ParseTuple(args, "i|i:lock_detect", &atype, &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->db_env->lock_detect(self->db_env, flags, atype, &aborted); +#else + err = lock_detect(self->db_env, flags, atype, &aborted); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + return PyInt_FromLong(aborted); +} + + +static PyObject* +DBEnv_lock_get(DBEnvObject* self, PyObject* args) +{ + int flags=0; + int locker, lock_mode; + DBT obj; + PyObject* objobj; + + if (!PyArg_ParseTuple(args, "iOi|i:lock_get", &locker, &objobj, &lock_mode, &flags)) + return NULL; + + + if (!make_dbt(objobj, &obj)) + return NULL; + + return (PyObject*)newDBLockObject(self, locker, &obj, lock_mode, flags); +} + + +static PyObject* +DBEnv_lock_id(DBEnvObject* self, PyObject* args) +{ + int err; + u_int32_t theID; + + if (!PyArg_ParseTuple(args, ":lock_id")) + return NULL; + + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->db_env->lock_id(self->db_env, &theID); +#else + err = lock_id(self->db_env, &theID); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + return PyInt_FromLong((long)theID); +} + + +static PyObject* +DBEnv_lock_put(DBEnvObject* self, PyObject* args) +{ + int err; + DBLockObject* dblockobj; + + if (!PyArg_ParseTuple(args, "O!:lock_put", &DBLock_Type, &dblockobj)) + return NULL; + + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->db_env->lock_put(self->db_env, &dblockobj->lock); +#else + err = lock_put(self->db_env, &dblockobj->lock); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +#if (DBVER >= 44) +static PyObject* +DBEnv_lsn_reset(DBEnvObject* self, PyObject* args, PyObject* kwargs) +{ + int err; + char *file; + u_int32_t flags = 0; + static char* kwnames[] = { "file", "flags", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|i:lsn_reset", kwnames, + &file, &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->lsn_reset(self->db_env, file, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} +#endif /* DBVER >= 4.4 */ + +#if (DBVER >= 40) +static PyObject* +DBEnv_log_stat(DBEnvObject* self, PyObject* args) +{ + int err; + DB_LOG_STAT* statp = NULL; + PyObject* d = NULL; + u_int32_t flags = 0; + + if (!PyArg_ParseTuple(args, "|i:log_stat", &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->db_env->log_stat(self->db_env, &statp, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + /* Turn the stat structure into a dictionary */ + d = PyDict_New(); + if (d == NULL) { + if (statp) + free(statp); + return NULL; + } + +#define MAKE_ENTRY(name) _addIntToDict(d, #name, statp->st_##name) + + MAKE_ENTRY(magic); + MAKE_ENTRY(version); + MAKE_ENTRY(mode); + MAKE_ENTRY(lg_bsize); +#if (DBVER >= 44) + MAKE_ENTRY(lg_size); + MAKE_ENTRY(record); +#endif +#if (DBVER <= 40) + MAKE_ENTRY(lg_max); +#endif + MAKE_ENTRY(w_mbytes); + MAKE_ENTRY(w_bytes); + MAKE_ENTRY(wc_mbytes); + MAKE_ENTRY(wc_bytes); + MAKE_ENTRY(wcount); + MAKE_ENTRY(wcount_fill); +#if (DBVER >= 44) + MAKE_ENTRY(rcount); +#endif + MAKE_ENTRY(scount); + MAKE_ENTRY(cur_file); + MAKE_ENTRY(cur_offset); + MAKE_ENTRY(disk_file); + MAKE_ENTRY(disk_offset); + MAKE_ENTRY(maxcommitperflush); + MAKE_ENTRY(mincommitperflush); + MAKE_ENTRY(regsize); + MAKE_ENTRY(region_wait); + MAKE_ENTRY(region_nowait); + +#undef MAKE_ENTRY + free(statp); + return d; +} /* DBEnv_log_stat */ +#endif /* DBVER >= 4.0 for log_stat method */ + + +static PyObject* +DBEnv_lock_stat(DBEnvObject* self, PyObject* args) +{ + int err; + DB_LOCK_STAT* sp; + PyObject* d = NULL; + u_int32_t flags = 0; + + if (!PyArg_ParseTuple(args, "|i:lock_stat", &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->db_env->lock_stat(self->db_env, &sp, flags); +#else +#if (DBVER >= 33) + err = lock_stat(self->db_env, &sp); +#else + err = lock_stat(self->db_env, &sp, NULL); +#endif +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + /* Turn the stat structure into a dictionary */ + d = PyDict_New(); + if (d == NULL) { + free(sp); + return NULL; + } + +#define MAKE_ENTRY(name) _addIntToDict(d, #name, sp->st_##name) + +#if (DBVER < 41) + MAKE_ENTRY(lastid); +#endif + MAKE_ENTRY(nmodes); +#if (DBVER >= 32) + MAKE_ENTRY(maxlocks); + MAKE_ENTRY(maxlockers); + MAKE_ENTRY(maxobjects); + MAKE_ENTRY(nlocks); + MAKE_ENTRY(maxnlocks); +#endif + MAKE_ENTRY(nlockers); + MAKE_ENTRY(maxnlockers); +#if (DBVER >= 32) + MAKE_ENTRY(nobjects); + MAKE_ENTRY(maxnobjects); +#endif + MAKE_ENTRY(nrequests); + MAKE_ENTRY(nreleases); +#if (DBVER < 44) + MAKE_ENTRY(nnowaits); /* these were renamed in 4.4 */ + MAKE_ENTRY(nconflicts); +#else + MAKE_ENTRY(lock_nowait); + MAKE_ENTRY(lock_wait); +#endif + MAKE_ENTRY(ndeadlocks); + MAKE_ENTRY(regsize); + MAKE_ENTRY(region_wait); + MAKE_ENTRY(region_nowait); + +#undef MAKE_ENTRY + free(sp); + return d; +} + + +static PyObject* +DBEnv_log_archive(DBEnvObject* self, PyObject* args) +{ + int flags=0; + int err; + char **log_list = NULL; + PyObject* list; + PyObject* item = NULL; + + if (!PyArg_ParseTuple(args, "|i:log_archive", &flags)) + return NULL; + + CHECK_ENV_NOT_CLOSED(self); + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->db_env->log_archive(self->db_env, &log_list, flags); +#elif (DBVER == 33) + err = log_archive(self->db_env, &log_list, flags); +#else + err = log_archive(self->db_env, &log_list, flags, NULL); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + list = PyList_New(0); + if (list == NULL) { + if (log_list) + free(log_list); + return NULL; + } + + if (log_list) { + char **log_list_start; + for (log_list_start = log_list; *log_list != NULL; ++log_list) { + item = PyString_FromString (*log_list); + if (item == NULL) { + Py_DECREF(list); + list = NULL; + break; + } + PyList_Append(list, item); + Py_DECREF(item); + } + free(log_list_start); + } + return list; +} + + +static PyObject* +DBEnv_txn_stat(DBEnvObject* self, PyObject* args) +{ + int err; + DB_TXN_STAT* sp; + PyObject* d = NULL; + u_int32_t flags=0; + + if (!PyArg_ParseTuple(args, "|i:txn_stat", &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->db_env->txn_stat(self->db_env, &sp, flags); +#elif (DBVER == 33) + err = txn_stat(self->db_env, &sp); +#else + err = txn_stat(self->db_env, &sp, NULL); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + /* Turn the stat structure into a dictionary */ + d = PyDict_New(); + if (d == NULL) { + free(sp); + return NULL; + } + +#define MAKE_ENTRY(name) _addIntToDict(d, #name, sp->st_##name) + + MAKE_ENTRY(time_ckp); + MAKE_ENTRY(last_txnid); + MAKE_ENTRY(maxtxns); + MAKE_ENTRY(nactive); + MAKE_ENTRY(maxnactive); + MAKE_ENTRY(nbegins); + MAKE_ENTRY(naborts); + MAKE_ENTRY(ncommits); + MAKE_ENTRY(regsize); + MAKE_ENTRY(region_wait); + MAKE_ENTRY(region_nowait); + +#undef MAKE_ENTRY + free(sp); + return d; +} + + +static PyObject* +DBEnv_set_get_returns_none(DBEnvObject* self, PyObject* args) +{ + int flags=0; + int oldValue=0; + + if (!PyArg_ParseTuple(args,"i:set_get_returns_none", &flags)) + return NULL; + CHECK_ENV_NOT_CLOSED(self); + + if (self->moduleFlags.getReturnsNone) + ++oldValue; + if (self->moduleFlags.cursorSetReturnsNone) + ++oldValue; + self->moduleFlags.getReturnsNone = (flags >= 1); + self->moduleFlags.cursorSetReturnsNone = (flags >= 2); + return PyInt_FromLong(oldValue); +} + + +/* --------------------------------------------------------------------- */ +/* DBTxn methods */ + + +static PyObject* +DBTxn_commit(DBTxnObject* self, PyObject* args) +{ + int flags=0, err; + DB_TXN *txn; + + if (!PyArg_ParseTuple(args, "|i:commit", &flags)) + return NULL; + + if (!self->txn) { + PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + "after txn_commit or txn_abort"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return NULL; + } + txn = self->txn; + self->txn = NULL; /* this DB_TXN is no longer valid after this call */ + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = txn->commit(txn, flags); +#else + err = txn_commit(txn, flags); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBTxn_prepare(DBTxnObject* self, PyObject* args) +{ +#if (DBVER >= 33) + int err; + char* gid=NULL; + int gid_size=0; + + if (!PyArg_ParseTuple(args, "s#:prepare", &gid, &gid_size)) + return NULL; + + if (gid_size != DB_XIDDATASIZE) { + PyErr_SetString(PyExc_TypeError, + "gid must be DB_XIDDATASIZE bytes long"); + return NULL; + } + + if (!self->txn) { + PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used " + "after txn_commit or txn_abort"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return NULL; + } + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = self->txn->prepare(self->txn, (u_int8_t*)gid); +#else + err = txn_prepare(self->txn, (u_int8_t*)gid); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +#else + int err; + + if (!PyArg_ParseTuple(args, ":prepare")) + return NULL; + + if (!self->txn) { + PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + "after txn_commit or txn_abort"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return NULL; + } + MYDB_BEGIN_ALLOW_THREADS; + err = txn_prepare(self->txn); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +#endif +} + + +static PyObject* +DBTxn_abort(DBTxnObject* self, PyObject* args) +{ + int err; + DB_TXN *txn; + + if (!PyArg_ParseTuple(args, ":abort")) + return NULL; + + if (!self->txn) { + PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + "after txn_commit or txn_abort"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return NULL; + } + txn = self->txn; + self->txn = NULL; /* this DB_TXN is no longer valid after this call */ + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + err = txn->abort(txn); +#else + err = txn_abort(txn); +#endif + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + RETURN_NONE(); +} + + +static PyObject* +DBTxn_id(DBTxnObject* self, PyObject* args) +{ + int id; + + if (!PyArg_ParseTuple(args, ":id")) + return NULL; + + if (!self->txn) { + PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + "after txn_commit or txn_abort"); + PyErr_SetObject(DBError, t); + Py_DECREF(t); + return NULL; + } + MYDB_BEGIN_ALLOW_THREADS; +#if (DBVER >= 40) + id = self->txn->id(self->txn); +#else + id = txn_id(self->txn); +#endif + MYDB_END_ALLOW_THREADS; + return PyInt_FromLong(id); +} + +#if (DBVER >= 43) +/* --------------------------------------------------------------------- */ +/* DBSequence methods */ + + +static PyObject* +DBSequence_close(DBSequenceObject* self, PyObject* args) +{ + int err, flags=0; + if (!PyArg_ParseTuple(args,"|i:close", &flags)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->close(self->sequence, flags); + self->sequence = NULL; + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + + RETURN_NONE(); +} + +static PyObject* +DBSequence_get(DBSequenceObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags = 0; + int delta = 1; + db_seq_t value; + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + static char* kwnames[] = {"delta", "txn", "flags", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iOi:get", kwnames, &delta, &txnobj, &flags)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + if (!checkTxnObj(txnobj, &txn)) + return NULL; + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->get(self->sequence, txn, delta, &value, flags); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + return PyLong_FromLongLong(value); + +} + +static PyObject* +DBSequence_get_dbp(DBSequenceObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args,":get_dbp")) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + Py_INCREF(self->mydb); + return (PyObject* )self->mydb; +} + +static PyObject* +DBSequence_get_key(DBSequenceObject* self, PyObject* args) +{ + int err; + DBT key; + CHECK_SEQUENCE_NOT_CLOSED(self) + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->get_key(self->sequence, &key); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + + return PyString_FromStringAndSize(key.data, key.size); +} + +static PyObject* +DBSequence_init_value(DBSequenceObject* self, PyObject* args) +{ + int err; + db_seq_t value; + if (!PyArg_ParseTuple(args,"L:init_value", &value)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->initial_value(self->sequence, value); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + + RETURN_NONE(); +} + +static PyObject* +DBSequence_open(DBSequenceObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags = 0; + PyObject* keyobj; + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + DBT key; + + static char* kwnames[] = {"key", "txn", "flags", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi:open", kwnames, &keyobj, &txnobj, &flags)) + return NULL; + + if (!checkTxnObj(txnobj, &txn)) + return NULL; + + if (!make_key_dbt(self->mydb, keyobj, &key, NULL)) + return NULL; + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->open(self->sequence, txn, &key, flags); + MYDB_END_ALLOW_THREADS + + CLEAR_DBT(key); + RETURN_IF_ERR(); + + RETURN_NONE(); +} + +static PyObject* +DBSequence_remove(DBSequenceObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags = 0; + PyObject *txnobj = NULL; + DB_TXN *txn = NULL; + + static char* kwnames[] = {"txn", "flags", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:remove", kwnames, &txnobj, &flags)) + return NULL; + + if (!checkTxnObj(txnobj, &txn)) + return NULL; + + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->remove(self->sequence, txn, flags); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBSequence_set_cachesize(DBSequenceObject* self, PyObject* args) +{ + int err, size; + if (!PyArg_ParseTuple(args,"i:set_cachesize", &size)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->set_cachesize(self->sequence, size); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBSequence_get_cachesize(DBSequenceObject* self, PyObject* args) +{ + int err, size; + if (!PyArg_ParseTuple(args,":get_cachesize")) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->get_cachesize(self->sequence, &size); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + return PyInt_FromLong(size); +} + +static PyObject* +DBSequence_set_flags(DBSequenceObject* self, PyObject* args) +{ + int err, flags = 0; + if (!PyArg_ParseTuple(args,"i:set_flags", &flags)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->set_flags(self->sequence, flags); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + RETURN_NONE(); + +} + +static PyObject* +DBSequence_get_flags(DBSequenceObject* self, PyObject* args) +{ + unsigned int flags; + int err; + if (!PyArg_ParseTuple(args,":get_flags")) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->get_flags(self->sequence, &flags); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + return PyInt_FromLong((int)flags); +} + +static PyObject* +DBSequence_set_range(DBSequenceObject* self, PyObject* args) +{ + int err; + db_seq_t min, max; + if (!PyArg_ParseTuple(args,"(LL):set_range", &min, &max)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->set_range(self->sequence, min, max); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + RETURN_NONE(); +} + +static PyObject* +DBSequence_get_range(DBSequenceObject* self, PyObject* args) +{ + int err; + db_seq_t min, max; + if (!PyArg_ParseTuple(args,":get_range")) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self) + + MYDB_BEGIN_ALLOW_THREADS + err = self->sequence->get_range(self->sequence, &min, &max); + MYDB_END_ALLOW_THREADS + + RETURN_IF_ERR(); + return Py_BuildValue("(LL)", min, max); +} + +static PyObject* +DBSequence_stat(DBSequenceObject* self, PyObject* args, PyObject* kwargs) +{ + int err, flags = 0; + DB_SEQUENCE_STAT* sp = NULL; + PyObject* dict_stat; + static char* kwnames[] = {"flags", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:stat", kwnames, &flags)) + return NULL; + CHECK_SEQUENCE_NOT_CLOSED(self); + + MYDB_BEGIN_ALLOW_THREADS; + err = self->sequence->stat(self->sequence, &sp, flags); + MYDB_END_ALLOW_THREADS; + RETURN_IF_ERR(); + + if ((dict_stat = PyDict_New()) == NULL) { + free(sp); + return NULL; + } + + +#define MAKE_INT_ENTRY(name) _addIntToDict(dict_stat, #name, sp->st_##name) +#define MAKE_LONG_LONG_ENTRY(name) _addDb_seq_tToDict(dict_stat, #name, sp->st_##name) + + MAKE_INT_ENTRY(wait); + MAKE_INT_ENTRY(nowait); + MAKE_LONG_LONG_ENTRY(current); + MAKE_LONG_LONG_ENTRY(value); + MAKE_LONG_LONG_ENTRY(last_value); + MAKE_LONG_LONG_ENTRY(min); + MAKE_LONG_LONG_ENTRY(max); + MAKE_INT_ENTRY(cache_size); + MAKE_INT_ENTRY(flags); + +#undef MAKE_INT_ENTRY +#undef MAKE_LONG_LONG_ENTRY + + free(sp); + return dict_stat; +} +#endif + + +/* --------------------------------------------------------------------- */ +/* Method definition tables and type objects */ + +static PyMethodDef DB_methods[] = { + {"append", (PyCFunction)DB_append, METH_VARARGS}, +#if (DBVER >= 33) + {"associate", (PyCFunction)DB_associate, METH_VARARGS|METH_KEYWORDS}, +#endif + {"close", (PyCFunction)DB_close, METH_VARARGS}, +#if (DBVER >= 32) + {"consume", (PyCFunction)DB_consume, METH_VARARGS|METH_KEYWORDS}, + {"consume_wait", (PyCFunction)DB_consume_wait, METH_VARARGS|METH_KEYWORDS}, +#endif + {"cursor", (PyCFunction)DB_cursor, METH_VARARGS|METH_KEYWORDS}, + {"delete", (PyCFunction)DB_delete, METH_VARARGS|METH_KEYWORDS}, + {"fd", (PyCFunction)DB_fd, METH_VARARGS}, + {"get", (PyCFunction)DB_get, METH_VARARGS|METH_KEYWORDS}, +#if (DBVER >= 33) + {"pget", (PyCFunction)DB_pget, METH_VARARGS|METH_KEYWORDS}, +#endif + {"get_both", (PyCFunction)DB_get_both, METH_VARARGS|METH_KEYWORDS}, + {"get_byteswapped", (PyCFunction)DB_get_byteswapped,METH_VARARGS}, + {"get_size", (PyCFunction)DB_get_size, METH_VARARGS|METH_KEYWORDS}, + {"get_type", (PyCFunction)DB_get_type, METH_VARARGS}, + {"join", (PyCFunction)DB_join, METH_VARARGS}, + {"key_range", (PyCFunction)DB_key_range, METH_VARARGS|METH_KEYWORDS}, + {"has_key", (PyCFunction)DB_has_key, METH_VARARGS}, + {"items", (PyCFunction)DB_items, METH_VARARGS}, + {"keys", (PyCFunction)DB_keys, METH_VARARGS}, + {"open", (PyCFunction)DB_open, METH_VARARGS|METH_KEYWORDS}, + {"put", (PyCFunction)DB_put, METH_VARARGS|METH_KEYWORDS}, + {"remove", (PyCFunction)DB_remove, METH_VARARGS|METH_KEYWORDS}, + {"rename", (PyCFunction)DB_rename, METH_VARARGS}, + {"set_bt_minkey", (PyCFunction)DB_set_bt_minkey, METH_VARARGS}, +#if (DBVER >= 33) + {"set_bt_compare", (PyCFunction)DB_set_bt_compare, METH_VARARGS}, +#endif + {"set_cachesize", (PyCFunction)DB_set_cachesize, METH_VARARGS}, +#if (DBVER >= 41) + {"set_encrypt", (PyCFunction)DB_set_encrypt, METH_VARARGS|METH_KEYWORDS}, +#endif + {"set_flags", (PyCFunction)DB_set_flags, METH_VARARGS}, + {"set_h_ffactor", (PyCFunction)DB_set_h_ffactor, METH_VARARGS}, + {"set_h_nelem", (PyCFunction)DB_set_h_nelem, METH_VARARGS}, + {"set_lorder", (PyCFunction)DB_set_lorder, METH_VARARGS}, + {"set_pagesize", (PyCFunction)DB_set_pagesize, METH_VARARGS}, + {"set_re_delim", (PyCFunction)DB_set_re_delim, METH_VARARGS}, + {"set_re_len", (PyCFunction)DB_set_re_len, METH_VARARGS}, + {"set_re_pad", (PyCFunction)DB_set_re_pad, METH_VARARGS}, + {"set_re_source", (PyCFunction)DB_set_re_source, METH_VARARGS}, +#if (DBVER >= 32) + {"set_q_extentsize",(PyCFunction)DB_set_q_extentsize,METH_VARARGS}, +#endif + {"stat", (PyCFunction)DB_stat, METH_VARARGS|METH_KEYWORDS}, + {"sync", (PyCFunction)DB_sync, METH_VARARGS}, +#if (DBVER >= 33) + {"truncate", (PyCFunction)DB_truncate, METH_VARARGS|METH_KEYWORDS}, +#endif + {"type", (PyCFunction)DB_get_type, METH_VARARGS}, + {"upgrade", (PyCFunction)DB_upgrade, METH_VARARGS}, + {"values", (PyCFunction)DB_values, METH_VARARGS}, + {"verify", (PyCFunction)DB_verify, METH_VARARGS|METH_KEYWORDS}, + {"set_get_returns_none",(PyCFunction)DB_set_get_returns_none, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + + +static PyMappingMethods DB_mapping = { + DB_length, /*mp_length*/ + (binaryfunc)DB_subscript, /*mp_subscript*/ + (objobjargproc)DB_ass_sub, /*mp_ass_subscript*/ +}; + + +static PyMethodDef DBCursor_methods[] = { + {"close", (PyCFunction)DBC_close, METH_VARARGS}, + {"count", (PyCFunction)DBC_count, METH_VARARGS}, + {"current", (PyCFunction)DBC_current, METH_VARARGS|METH_KEYWORDS}, + {"delete", (PyCFunction)DBC_delete, METH_VARARGS}, + {"dup", (PyCFunction)DBC_dup, METH_VARARGS}, + {"first", (PyCFunction)DBC_first, METH_VARARGS|METH_KEYWORDS}, + {"get", (PyCFunction)DBC_get, METH_VARARGS|METH_KEYWORDS}, +#if (DBVER >= 33) + {"pget", (PyCFunction)DBC_pget, METH_VARARGS|METH_KEYWORDS}, +#endif + {"get_recno", (PyCFunction)DBC_get_recno, METH_VARARGS}, + {"last", (PyCFunction)DBC_last, METH_VARARGS|METH_KEYWORDS}, + {"next", (PyCFunction)DBC_next, METH_VARARGS|METH_KEYWORDS}, + {"prev", (PyCFunction)DBC_prev, METH_VARARGS|METH_KEYWORDS}, + {"put", (PyCFunction)DBC_put, METH_VARARGS|METH_KEYWORDS}, + {"set", (PyCFunction)DBC_set, METH_VARARGS|METH_KEYWORDS}, + {"set_range", (PyCFunction)DBC_set_range, METH_VARARGS|METH_KEYWORDS}, + {"get_both", (PyCFunction)DBC_get_both, METH_VARARGS}, + {"get_current_size",(PyCFunction)DBC_get_current_size, METH_VARARGS}, + {"set_both", (PyCFunction)DBC_set_both, METH_VARARGS}, + {"set_recno", (PyCFunction)DBC_set_recno, METH_VARARGS|METH_KEYWORDS}, + {"consume", (PyCFunction)DBC_consume, METH_VARARGS|METH_KEYWORDS}, + {"next_dup", (PyCFunction)DBC_next_dup, METH_VARARGS|METH_KEYWORDS}, + {"next_nodup", (PyCFunction)DBC_next_nodup, METH_VARARGS|METH_KEYWORDS}, + {"prev_nodup", (PyCFunction)DBC_prev_nodup, METH_VARARGS|METH_KEYWORDS}, + {"join_item", (PyCFunction)DBC_join_item, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + + +static PyMethodDef DBEnv_methods[] = { + {"close", (PyCFunction)DBEnv_close, METH_VARARGS}, + {"open", (PyCFunction)DBEnv_open, METH_VARARGS}, + {"remove", (PyCFunction)DBEnv_remove, METH_VARARGS}, +#if (DBVER >= 41) + {"dbremove", (PyCFunction)DBEnv_dbremove, METH_VARARGS|METH_KEYWORDS}, + {"dbrename", (PyCFunction)DBEnv_dbrename, METH_VARARGS|METH_KEYWORDS}, + {"set_encrypt", (PyCFunction)DBEnv_set_encrypt, METH_VARARGS|METH_KEYWORDS}, +#endif +#if (DBVER >= 40) + {"set_timeout", (PyCFunction)DBEnv_set_timeout, METH_VARARGS|METH_KEYWORDS}, +#endif + {"set_shm_key", (PyCFunction)DBEnv_set_shm_key, METH_VARARGS}, + {"set_cachesize", (PyCFunction)DBEnv_set_cachesize, METH_VARARGS}, + {"set_data_dir", (PyCFunction)DBEnv_set_data_dir, METH_VARARGS}, +#if (DBVER >= 32) + {"set_flags", (PyCFunction)DBEnv_set_flags, METH_VARARGS}, +#endif + {"set_lg_bsize", (PyCFunction)DBEnv_set_lg_bsize, METH_VARARGS}, + {"set_lg_dir", (PyCFunction)DBEnv_set_lg_dir, METH_VARARGS}, + {"set_lg_max", (PyCFunction)DBEnv_set_lg_max, METH_VARARGS}, +#if (DBVER >= 33) + {"set_lg_regionmax",(PyCFunction)DBEnv_set_lg_regionmax, METH_VARARGS}, +#endif + {"set_lk_detect", (PyCFunction)DBEnv_set_lk_detect, METH_VARARGS}, +#if (DBVER < 45) + {"set_lk_max", (PyCFunction)DBEnv_set_lk_max, METH_VARARGS}, +#endif +#if (DBVER >= 32) + {"set_lk_max_locks", (PyCFunction)DBEnv_set_lk_max_locks, METH_VARARGS}, + {"set_lk_max_lockers", (PyCFunction)DBEnv_set_lk_max_lockers, METH_VARARGS}, + {"set_lk_max_objects", (PyCFunction)DBEnv_set_lk_max_objects, METH_VARARGS}, +#endif + {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize, METH_VARARGS}, + {"set_tmp_dir", (PyCFunction)DBEnv_set_tmp_dir, METH_VARARGS}, + {"txn_begin", (PyCFunction)DBEnv_txn_begin, METH_VARARGS|METH_KEYWORDS}, + {"txn_checkpoint", (PyCFunction)DBEnv_txn_checkpoint, METH_VARARGS}, + {"txn_stat", (PyCFunction)DBEnv_txn_stat, METH_VARARGS}, + {"set_tx_max", (PyCFunction)DBEnv_set_tx_max, METH_VARARGS}, + {"set_tx_timestamp", (PyCFunction)DBEnv_set_tx_timestamp, METH_VARARGS}, + {"lock_detect", (PyCFunction)DBEnv_lock_detect, METH_VARARGS}, + {"lock_get", (PyCFunction)DBEnv_lock_get, METH_VARARGS}, + {"lock_id", (PyCFunction)DBEnv_lock_id, METH_VARARGS}, + {"lock_put", (PyCFunction)DBEnv_lock_put, METH_VARARGS}, + {"lock_stat", (PyCFunction)DBEnv_lock_stat, METH_VARARGS}, + {"log_archive", (PyCFunction)DBEnv_log_archive, METH_VARARGS}, +#if (DBVER >= 40) + {"log_stat", (PyCFunction)DBEnv_log_stat, METH_VARARGS}, +#endif +#if (DBVER >= 44) + {"lsn_reset", (PyCFunction)DBEnv_lsn_reset, METH_VARARGS|METH_KEYWORDS}, +#endif + {"set_get_returns_none",(PyCFunction)DBEnv_set_get_returns_none, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + + +static PyMethodDef DBTxn_methods[] = { + {"commit", (PyCFunction)DBTxn_commit, METH_VARARGS}, + {"prepare", (PyCFunction)DBTxn_prepare, METH_VARARGS}, + {"abort", (PyCFunction)DBTxn_abort, METH_VARARGS}, + {"id", (PyCFunction)DBTxn_id, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + + +#if (DBVER >= 43) +static PyMethodDef DBSequence_methods[] = { + {"close", (PyCFunction)DBSequence_close, METH_VARARGS}, + {"get", (PyCFunction)DBSequence_get, METH_VARARGS|METH_KEYWORDS}, + {"get_dbp", (PyCFunction)DBSequence_get_dbp, METH_VARARGS}, + {"get_key", (PyCFunction)DBSequence_get_key, METH_VARARGS}, + {"init_value", (PyCFunction)DBSequence_init_value, METH_VARARGS}, + {"open", (PyCFunction)DBSequence_open, METH_VARARGS|METH_KEYWORDS}, + {"remove", (PyCFunction)DBSequence_remove, METH_VARARGS|METH_KEYWORDS}, + {"set_cachesize", (PyCFunction)DBSequence_set_cachesize, METH_VARARGS}, + {"get_cachesize", (PyCFunction)DBSequence_get_cachesize, METH_VARARGS}, + {"set_flags", (PyCFunction)DBSequence_set_flags, METH_VARARGS}, + {"get_flags", (PyCFunction)DBSequence_get_flags, METH_VARARGS}, + {"set_range", (PyCFunction)DBSequence_set_range, METH_VARARGS}, + {"get_range", (PyCFunction)DBSequence_get_range, METH_VARARGS}, + {"stat", (PyCFunction)DBSequence_stat, METH_VARARGS|METH_KEYWORDS}, + {NULL, NULL} /* sentinel */ +}; +#endif + + +static PyObject* +DB_getattr(DBObject* self, char *name) +{ + return Py_FindMethod(DB_methods, (PyObject* )self, name); +} + + +static PyObject* +DBEnv_getattr(DBEnvObject* self, char *name) +{ + if (!strcmp(name, "db_home")) { + CHECK_ENV_NOT_CLOSED(self); + if (self->db_env->db_home == NULL) { + RETURN_NONE(); + } + return PyString_FromString(self->db_env->db_home); + } + + return Py_FindMethod(DBEnv_methods, (PyObject* )self, name); +} + + +static PyObject* +DBCursor_getattr(DBCursorObject* self, char *name) +{ + return Py_FindMethod(DBCursor_methods, (PyObject* )self, name); +} + +static PyObject* +DBTxn_getattr(DBTxnObject* self, char *name) +{ + return Py_FindMethod(DBTxn_methods, (PyObject* )self, name); +} + +static PyObject* +DBLock_getattr(DBLockObject* self, char *name) +{ + return NULL; +} + +#if (DBVER >= 43) +static PyObject* +DBSequence_getattr(DBSequenceObject* self, char *name) +{ + return Py_FindMethod(DBSequence_methods, (PyObject* )self, name); +} +#endif + +statichere PyTypeObject DB_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "DB", /*tp_name*/ + sizeof(DBObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)DB_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)DB_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &DB_mapping,/*tp_as_mapping*/ + 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBObject, in_weakreflist), /* tp_weaklistoffset */ +#endif +}; + + +statichere PyTypeObject DBCursor_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "DBCursor", /*tp_name*/ + sizeof(DBCursorObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)DBCursor_dealloc,/*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)DBCursor_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBCursorObject, in_weakreflist), /* tp_weaklistoffset */ +#endif +}; + + +statichere PyTypeObject DBEnv_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "DBEnv", /*tp_name*/ + sizeof(DBEnvObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)DBEnv_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)DBEnv_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBEnvObject, in_weakreflist), /* tp_weaklistoffset */ +#endif +}; + +statichere PyTypeObject DBTxn_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "DBTxn", /*tp_name*/ + sizeof(DBTxnObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)DBTxn_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)DBTxn_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBTxnObject, in_weakreflist), /* tp_weaklistoffset */ +#endif +}; + + +statichere PyTypeObject DBLock_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "DBLock", /*tp_name*/ + sizeof(DBLockObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)DBLock_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)DBLock_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBLockObject, in_weakreflist), /* tp_weaklistoffset */ +#endif +}; + +#if (DBVER >= 43) +statichere PyTypeObject DBSequence_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "DBSequence", /*tp_name*/ + sizeof(DBSequenceObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)DBSequence_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)DBSequence_getattr,/*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +#ifdef HAVE_WEAKREF + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(DBSequenceObject, in_weakreflist), /* tp_weaklistoffset */ +#endif +}; +#endif + +/* --------------------------------------------------------------------- */ +/* Module-level functions */ + +static PyObject* +DB_construct(PyObject* self, PyObject* args, PyObject* kwargs) +{ + PyObject* dbenvobj = NULL; + int flags = 0; + static char* kwnames[] = { "dbEnv", "flags", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|Oi:DB", kwnames, + &dbenvobj, &flags)) + return NULL; + if (dbenvobj == Py_None) + dbenvobj = NULL; + else if (dbenvobj && !DBEnvObject_Check(dbenvobj)) { + makeTypeError("DBEnv", dbenvobj); + return NULL; + } + + return (PyObject* )newDBObject((DBEnvObject*)dbenvobj, flags); +} + + +static PyObject* +DBEnv_construct(PyObject* self, PyObject* args) +{ + int flags = 0; + if (!PyArg_ParseTuple(args, "|i:DbEnv", &flags)) return NULL; + return (PyObject* )newDBEnvObject(flags); +} + +#if (DBVER >= 43) +static PyObject* +DBSequence_construct(PyObject* self, PyObject* args, PyObject* kwargs) +{ + PyObject* dbobj; + int flags = 0; + static char* kwnames[] = { "db", "flags", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:DBSequence", kwnames, &dbobj, &flags)) + return NULL; + if (!DBObject_Check(dbobj)) { + makeTypeError("DB", dbobj); + return NULL; + } + return (PyObject* )newDBSequenceObject((DBObject*)dbobj, flags); +} +#endif + +static char bsddb_version_doc[] = +"Returns a tuple of major, minor, and patch release numbers of the\n\ +underlying DB library."; + +static PyObject* +bsddb_version(PyObject* self, PyObject* args) +{ + int major, minor, patch; + + if (!PyArg_ParseTuple(args, ":version")) + return NULL; + db_version(&major, &minor, &patch); + return Py_BuildValue("(iii)", major, minor, patch); +} + + +/* List of functions defined in the module */ + +static PyMethodDef bsddb_methods[] = { + {"DB", (PyCFunction)DB_construct, METH_VARARGS | METH_KEYWORDS }, + {"DBEnv", (PyCFunction)DBEnv_construct, METH_VARARGS}, +#if (DBVER >= 43) + {"DBSequence", (PyCFunction)DBSequence_construct, METH_VARARGS | METH_KEYWORDS }, +#endif + {"version", (PyCFunction)bsddb_version, METH_VARARGS, bsddb_version_doc}, + {NULL, NULL} /* sentinel */ +}; + + +/* --------------------------------------------------------------------- */ +/* Module initialization */ + + +/* Convenience routine to export an integer value. + * Errors are silently ignored, for better or for worse... + */ +#define ADD_INT(dict, NAME) _addIntToDict(dict, #NAME, NAME) + +#define MODULE_NAME_MAX_LEN 11 +static char _bsddbModuleName[MODULE_NAME_MAX_LEN+1] = "_bsddb"; + +DL_EXPORT(void) init_bsddb(void) +{ + PyObject* m; + PyObject* d; + PyObject* pybsddb_version_s = PyString_FromString( PY_BSDDB_VERSION ); + PyObject* db_version_s = PyString_FromString( DB_VERSION_STRING ); + PyObject* cvsid_s = PyString_FromString( rcs_id ); + + /* Initialize the type of the new type objects here; doing it here + is required for portability to Windows without requiring C++. */ + DB_Type.ob_type = &PyType_Type; + DBCursor_Type.ob_type = &PyType_Type; + DBEnv_Type.ob_type = &PyType_Type; + DBTxn_Type.ob_type = &PyType_Type; + DBLock_Type.ob_type = &PyType_Type; +#if (DBVER >= 43) + DBSequence_Type.ob_type = &PyType_Type; +#endif + + +#if defined(WITH_THREAD) && !defined(MYDB_USE_GILSTATE) + /* Save the current interpreter, so callbacks can do the right thing. */ + _db_interpreterState = PyThreadState_GET()->interp; +#endif + + /* Create the module and add the functions */ + m = Py_InitModule(_bsddbModuleName, bsddb_methods); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + PyDict_SetItemString(d, "__version__", pybsddb_version_s); + PyDict_SetItemString(d, "cvsid", cvsid_s); + PyDict_SetItemString(d, "DB_VERSION_STRING", db_version_s); + Py_DECREF(pybsddb_version_s); + pybsddb_version_s = NULL; + Py_DECREF(cvsid_s); + cvsid_s = NULL; + Py_DECREF(db_version_s); + db_version_s = NULL; + + ADD_INT(d, DB_VERSION_MAJOR); + ADD_INT(d, DB_VERSION_MINOR); + ADD_INT(d, DB_VERSION_PATCH); + + ADD_INT(d, DB_MAX_PAGES); + ADD_INT(d, DB_MAX_RECORDS); + +#if (DBVER >= 42) + ADD_INT(d, DB_RPCCLIENT); +#else + ADD_INT(d, DB_CLIENT); + /* allow apps to be written using DB_RPCCLIENT on older BerkeleyDB */ + _addIntToDict(d, "DB_RPCCLIENT", DB_CLIENT); +#endif + ADD_INT(d, DB_XA_CREATE); + + ADD_INT(d, DB_CREATE); + ADD_INT(d, DB_NOMMAP); + ADD_INT(d, DB_THREAD); + + ADD_INT(d, DB_FORCE); + ADD_INT(d, DB_INIT_CDB); + ADD_INT(d, DB_INIT_LOCK); + ADD_INT(d, DB_INIT_LOG); + ADD_INT(d, DB_INIT_MPOOL); + ADD_INT(d, DB_INIT_TXN); +#if (DBVER >= 32) + ADD_INT(d, DB_JOINENV); +#endif + + ADD_INT(d, DB_RECOVER); + ADD_INT(d, DB_RECOVER_FATAL); + ADD_INT(d, DB_TXN_NOSYNC); + ADD_INT(d, DB_USE_ENVIRON); + ADD_INT(d, DB_USE_ENVIRON_ROOT); + + ADD_INT(d, DB_LOCKDOWN); + ADD_INT(d, DB_PRIVATE); + ADD_INT(d, DB_SYSTEM_MEM); + + ADD_INT(d, DB_TXN_SYNC); + ADD_INT(d, DB_TXN_NOWAIT); + + ADD_INT(d, DB_EXCL); + ADD_INT(d, DB_FCNTL_LOCKING); + ADD_INT(d, DB_ODDFILESIZE); + ADD_INT(d, DB_RDWRMASTER); + ADD_INT(d, DB_RDONLY); + ADD_INT(d, DB_TRUNCATE); +#if (DBVER >= 32) + ADD_INT(d, DB_EXTENT); + ADD_INT(d, DB_CDB_ALLDB); + ADD_INT(d, DB_VERIFY); +#endif + ADD_INT(d, DB_UPGRADE); + + ADD_INT(d, DB_AGGRESSIVE); + ADD_INT(d, DB_NOORDERCHK); + ADD_INT(d, DB_ORDERCHKONLY); + ADD_INT(d, DB_PR_PAGE); +#if ! (DBVER >= 33) + ADD_INT(d, DB_VRFY_FLAGMASK); + ADD_INT(d, DB_PR_HEADERS); +#endif + ADD_INT(d, DB_PR_RECOVERYTEST); + ADD_INT(d, DB_SALVAGE); + + ADD_INT(d, DB_LOCK_NORUN); + ADD_INT(d, DB_LOCK_DEFAULT); + ADD_INT(d, DB_LOCK_OLDEST); + ADD_INT(d, DB_LOCK_RANDOM); + ADD_INT(d, DB_LOCK_YOUNGEST); +#if (DBVER >= 33) + ADD_INT(d, DB_LOCK_MAXLOCKS); + ADD_INT(d, DB_LOCK_MINLOCKS); + ADD_INT(d, DB_LOCK_MINWRITE); +#endif + + +#if (DBVER >= 33) + /* docs say to use zero instead */ + _addIntToDict(d, "DB_LOCK_CONFLICT", 0); +#else + ADD_INT(d, DB_LOCK_CONFLICT); +#endif + + ADD_INT(d, DB_LOCK_DUMP); + ADD_INT(d, DB_LOCK_GET); + ADD_INT(d, DB_LOCK_INHERIT); + ADD_INT(d, DB_LOCK_PUT); + ADD_INT(d, DB_LOCK_PUT_ALL); + ADD_INT(d, DB_LOCK_PUT_OBJ); + + ADD_INT(d, DB_LOCK_NG); + ADD_INT(d, DB_LOCK_READ); + ADD_INT(d, DB_LOCK_WRITE); + ADD_INT(d, DB_LOCK_NOWAIT); +#if (DBVER >= 32) + ADD_INT(d, DB_LOCK_WAIT); +#endif + ADD_INT(d, DB_LOCK_IWRITE); + ADD_INT(d, DB_LOCK_IREAD); + ADD_INT(d, DB_LOCK_IWR); +#if (DBVER >= 33) +#if (DBVER < 44) + ADD_INT(d, DB_LOCK_DIRTY); +#else + ADD_INT(d, DB_LOCK_READ_UNCOMMITTED); /* renamed in 4.4 */ +#endif + ADD_INT(d, DB_LOCK_WWRITE); +#endif + + ADD_INT(d, DB_LOCK_RECORD); + ADD_INT(d, DB_LOCK_UPGRADE); +#if (DBVER >= 32) + ADD_INT(d, DB_LOCK_SWITCH); +#endif +#if (DBVER >= 33) + ADD_INT(d, DB_LOCK_UPGRADE_WRITE); +#endif + + ADD_INT(d, DB_LOCK_NOWAIT); + ADD_INT(d, DB_LOCK_RECORD); + ADD_INT(d, DB_LOCK_UPGRADE); + +#if (DBVER >= 33) + ADD_INT(d, DB_LSTAT_ABORTED); +#if (DBVER < 43) + ADD_INT(d, DB_LSTAT_ERR); +#endif + ADD_INT(d, DB_LSTAT_FREE); + ADD_INT(d, DB_LSTAT_HELD); +#if (DBVER == 33) + ADD_INT(d, DB_LSTAT_NOGRANT); +#endif + ADD_INT(d, DB_LSTAT_PENDING); + ADD_INT(d, DB_LSTAT_WAITING); +#endif + + ADD_INT(d, DB_ARCH_ABS); + ADD_INT(d, DB_ARCH_DATA); + ADD_INT(d, DB_ARCH_LOG); +#if (DBVER >= 42) + ADD_INT(d, DB_ARCH_REMOVE); +#endif + + ADD_INT(d, DB_BTREE); + ADD_INT(d, DB_HASH); + ADD_INT(d, DB_RECNO); + ADD_INT(d, DB_QUEUE); + ADD_INT(d, DB_UNKNOWN); + + ADD_INT(d, DB_DUP); + ADD_INT(d, DB_DUPSORT); + ADD_INT(d, DB_RECNUM); + ADD_INT(d, DB_RENUMBER); + ADD_INT(d, DB_REVSPLITOFF); + ADD_INT(d, DB_SNAPSHOT); + + ADD_INT(d, DB_JOIN_NOSORT); + + ADD_INT(d, DB_AFTER); + ADD_INT(d, DB_APPEND); + ADD_INT(d, DB_BEFORE); +#if (DBVER < 45) + ADD_INT(d, DB_CACHED_COUNTS); +#endif +#if (DBVER >= 41) + _addIntToDict(d, "DB_CHECKPOINT", 0); +#else + ADD_INT(d, DB_CHECKPOINT); + ADD_INT(d, DB_CURLSN); +#endif +#if ((DBVER >= 33) && (DBVER <= 41)) + ADD_INT(d, DB_COMMIT); +#endif + ADD_INT(d, DB_CONSUME); +#if (DBVER >= 32) + ADD_INT(d, DB_CONSUME_WAIT); +#endif + ADD_INT(d, DB_CURRENT); +#if (DBVER >= 33) + ADD_INT(d, DB_FAST_STAT); +#endif + ADD_INT(d, DB_FIRST); + ADD_INT(d, DB_FLUSH); + ADD_INT(d, DB_GET_BOTH); + ADD_INT(d, DB_GET_RECNO); + ADD_INT(d, DB_JOIN_ITEM); + ADD_INT(d, DB_KEYFIRST); + ADD_INT(d, DB_KEYLAST); + ADD_INT(d, DB_LAST); + ADD_INT(d, DB_NEXT); + ADD_INT(d, DB_NEXT_DUP); + ADD_INT(d, DB_NEXT_NODUP); + ADD_INT(d, DB_NODUPDATA); + ADD_INT(d, DB_NOOVERWRITE); + ADD_INT(d, DB_NOSYNC); + ADD_INT(d, DB_POSITION); + ADD_INT(d, DB_PREV); + ADD_INT(d, DB_PREV_NODUP); +#if (DBVER < 45) + ADD_INT(d, DB_RECORDCOUNT); +#endif + ADD_INT(d, DB_SET); + ADD_INT(d, DB_SET_RANGE); + ADD_INT(d, DB_SET_RECNO); + ADD_INT(d, DB_WRITECURSOR); + + ADD_INT(d, DB_OPFLAGS_MASK); + ADD_INT(d, DB_RMW); +#if (DBVER >= 33) + ADD_INT(d, DB_DIRTY_READ); + ADD_INT(d, DB_MULTIPLE); + ADD_INT(d, DB_MULTIPLE_KEY); +#endif + +#if (DBVER >= 44) + ADD_INT(d, DB_READ_UNCOMMITTED); /* replaces DB_DIRTY_READ in 4.4 */ + ADD_INT(d, DB_READ_COMMITTED); +#endif + +#if (DBVER >= 33) + ADD_INT(d, DB_DONOTINDEX); +#endif + +#if (DBVER >= 41) + _addIntToDict(d, "DB_INCOMPLETE", 0); +#else + ADD_INT(d, DB_INCOMPLETE); +#endif + ADD_INT(d, DB_KEYEMPTY); + ADD_INT(d, DB_KEYEXIST); + ADD_INT(d, DB_LOCK_DEADLOCK); + ADD_INT(d, DB_LOCK_NOTGRANTED); + ADD_INT(d, DB_NOSERVER); + ADD_INT(d, DB_NOSERVER_HOME); + ADD_INT(d, DB_NOSERVER_ID); + ADD_INT(d, DB_NOTFOUND); + ADD_INT(d, DB_OLD_VERSION); + ADD_INT(d, DB_RUNRECOVERY); + ADD_INT(d, DB_VERIFY_BAD); +#if (DBVER >= 33) + ADD_INT(d, DB_PAGE_NOTFOUND); + ADD_INT(d, DB_SECONDARY_BAD); +#endif +#if (DBVER >= 40) + ADD_INT(d, DB_STAT_CLEAR); + ADD_INT(d, DB_REGION_INIT); + ADD_INT(d, DB_NOLOCKING); + ADD_INT(d, DB_YIELDCPU); + ADD_INT(d, DB_PANIC_ENVIRONMENT); + ADD_INT(d, DB_NOPANIC); +#endif + +#if (DBVER >= 42) + ADD_INT(d, DB_TIME_NOTGRANTED); + ADD_INT(d, DB_TXN_NOT_DURABLE); + ADD_INT(d, DB_TXN_WRITE_NOSYNC); + ADD_INT(d, DB_LOG_AUTOREMOVE); + ADD_INT(d, DB_DIRECT_LOG); + ADD_INT(d, DB_DIRECT_DB); + ADD_INT(d, DB_INIT_REP); + ADD_INT(d, DB_ENCRYPT); + ADD_INT(d, DB_CHKSUM); +#endif + +#if (DBVER >= 43) + ADD_INT(d, DB_LOG_INMEMORY); + ADD_INT(d, DB_BUFFER_SMALL); + ADD_INT(d, DB_SEQ_DEC); + ADD_INT(d, DB_SEQ_INC); + ADD_INT(d, DB_SEQ_WRAP); +#endif + +#if (DBVER >= 41) + ADD_INT(d, DB_ENCRYPT_AES); + ADD_INT(d, DB_AUTO_COMMIT); +#else + /* allow berkeleydb 4.1 aware apps to run on older versions */ + _addIntToDict(d, "DB_AUTO_COMMIT", 0); +#endif + + ADD_INT(d, EINVAL); + ADD_INT(d, EACCES); + ADD_INT(d, ENOSPC); + ADD_INT(d, ENOMEM); + ADD_INT(d, EAGAIN); + ADD_INT(d, EBUSY); + ADD_INT(d, EEXIST); + ADD_INT(d, ENOENT); + ADD_INT(d, EPERM); + +#if (DBVER >= 40) + ADD_INT(d, DB_SET_LOCK_TIMEOUT); + ADD_INT(d, DB_SET_TXN_TIMEOUT); +#endif + + /* The exception name must be correct for pickled exception * + * objects to unpickle properly. */ +#ifdef PYBSDDB_STANDALONE /* different value needed for standalone pybsddb */ +#define PYBSDDB_EXCEPTION_BASE "bsddb3.db." +#else +#define PYBSDDB_EXCEPTION_BASE "bsddb.db." +#endif + + /* All the rest of the exceptions derive only from DBError */ +#define MAKE_EX(name) name = PyErr_NewException(PYBSDDB_EXCEPTION_BASE #name, DBError, NULL); \ + PyDict_SetItemString(d, #name, name) + + /* The base exception class is DBError */ + DBError = NULL; /* used in MAKE_EX so that it derives from nothing */ + MAKE_EX(DBError); + + /* Some magic to make DBNotFoundError and DBKeyEmptyError derive + * from both DBError and KeyError, since the API only supports + * using one base class. */ + PyDict_SetItemString(d, "KeyError", PyExc_KeyError); + PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n" + "class DBKeyEmptyError(DBError, KeyError): pass", + Py_file_input, d, d); + DBNotFoundError = PyDict_GetItemString(d, "DBNotFoundError"); + DBKeyEmptyError = PyDict_GetItemString(d, "DBKeyEmptyError"); + PyDict_DelItemString(d, "KeyError"); + + +#if !INCOMPLETE_IS_WARNING + MAKE_EX(DBIncompleteError); +#endif + MAKE_EX(DBCursorClosedError); + MAKE_EX(DBKeyEmptyError); + MAKE_EX(DBKeyExistError); + MAKE_EX(DBLockDeadlockError); + MAKE_EX(DBLockNotGrantedError); + MAKE_EX(DBOldVersionError); + MAKE_EX(DBRunRecoveryError); + MAKE_EX(DBVerifyBadError); + MAKE_EX(DBNoServerError); + MAKE_EX(DBNoServerHomeError); + MAKE_EX(DBNoServerIDError); +#if (DBVER >= 33) + MAKE_EX(DBPageNotFoundError); + MAKE_EX(DBSecondaryBadError); +#endif + + MAKE_EX(DBInvalidArgError); + MAKE_EX(DBAccessError); + MAKE_EX(DBNoSpaceError); + MAKE_EX(DBNoMemoryError); + MAKE_EX(DBAgainError); + MAKE_EX(DBBusyError); + MAKE_EX(DBFileExistsError); + MAKE_EX(DBNoSuchFileError); + MAKE_EX(DBPermissionsError); + +#undef MAKE_EX + + /* Check for errors */ + if (PyErr_Occurred()) { + PyErr_Print(); + Py_FatalError("can't initialize module _bsddb"); + } +} + +/* allow this module to be named _pybsddb so that it can be installed + * and imported on top of python >= 2.3 that includes its own older + * copy of the library named _bsddb without importing the old version. */ +DL_EXPORT(void) init_pybsddb(void) +{ + strncpy(_bsddbModuleName, "_pybsddb", MODULE_NAME_MAX_LEN); + init_bsddb(); +} diff --git a/sys/src/cmd/python/Modules/_codecsmodule.c b/sys/src/cmd/python/Modules/_codecsmodule.c new file mode 100644 index 000000000..4dbceb78b --- /dev/null +++ b/sys/src/cmd/python/Modules/_codecsmodule.c @@ -0,0 +1,934 @@ +/* ------------------------------------------------------------------------ + + _codecs -- Provides access to the codec registry and the builtin + codecs. + + This module should never be imported directly. The standard library + module "codecs" wraps this builtin module for use within Python. + + The codec registry is accessible via: + + register(search_function) -> None + + lookup(encoding) -> (encoder, decoder, stream_reader, stream_writer) + + The builtin Unicode codecs use the following interface: + + <encoding>_encode(Unicode_object[,errors='strict']) -> + (string object, bytes consumed) + + <encoding>_decode(char_buffer_obj[,errors='strict']) -> + (Unicode object, bytes consumed) + + <encoding>_encode() interfaces also accept non-Unicode object as + input. The objects are then converted to Unicode using + PyUnicode_FromObject() prior to applying the conversion. + + These <encoding>s are available: utf_8, unicode_escape, + raw_unicode_escape, unicode_internal, latin_1, ascii (7-bit), + mbcs (on win32). + + +Written by Marc-Andre Lemburg (mal@lemburg.com). + +Copyright (c) Corporation for National Research Initiatives. + + ------------------------------------------------------------------------ */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" + +/* --- Registry ----------------------------------------------------------- */ + +PyDoc_STRVAR(register__doc__, +"register(search_function)\n\ +\n\ +Register a codec search function. Search functions are expected to take\n\ +one argument, the encoding name in all lower case letters, and return\n\ +a tuple of functions (encoder, decoder, stream_reader, stream_writer)."); + +static +PyObject *codec_register(PyObject *self, PyObject *search_function) +{ + if (PyCodec_Register(search_function)) + return NULL; + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(lookup__doc__, +"lookup(encoding) -> (encoder, decoder, stream_reader, stream_writer)\n\ +\n\ +Looks up a codec tuple in the Python codec registry and returns\n\ +a tuple of functions."); + +static +PyObject *codec_lookup(PyObject *self, PyObject *args) +{ + char *encoding; + + if (!PyArg_ParseTuple(args, "s:lookup", &encoding)) + return NULL; + + return _PyCodec_Lookup(encoding); +} + +PyDoc_STRVAR(encode__doc__, +"encode(obj, [encoding[,errors]]) -> object\n\ +\n\ +Encodes obj using the codec registered for encoding. encoding defaults\n\ +to the default encoding. errors may be given to set a different error\n\ +handling scheme. Default is 'strict' meaning that encoding errors raise\n\ +a ValueError. Other possible values are 'ignore', 'replace' and\n\ +'xmlcharrefreplace' as well as any other name registered with\n\ +codecs.register_error that can handle ValueErrors."); + +static PyObject * +codec_encode(PyObject *self, PyObject *args) +{ + const char *encoding = NULL; + const char *errors = NULL; + PyObject *v; + + if (!PyArg_ParseTuple(args, "O|ss:encode", &v, &encoding, &errors)) + return NULL; + +#ifdef Py_USING_UNICODE + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); +#else + if (encoding == NULL) { + PyErr_SetString(PyExc_ValueError, "no encoding specified"); + return NULL; + } +#endif + + /* Encode via the codec registry */ + return PyCodec_Encode(v, encoding, errors); +} + +PyDoc_STRVAR(decode__doc__, +"decode(obj, [encoding[,errors]]) -> object\n\ +\n\ +Decodes obj using the codec registered for encoding. encoding defaults\n\ +to the default encoding. errors may be given to set a different error\n\ +handling scheme. Default is 'strict' meaning that encoding errors raise\n\ +a ValueError. Other possible values are 'ignore' and 'replace'\n\ +as well as any other name registerd with codecs.register_error that is\n\ +able to handle ValueErrors."); + +static PyObject * +codec_decode(PyObject *self, PyObject *args) +{ + const char *encoding = NULL; + const char *errors = NULL; + PyObject *v; + + if (!PyArg_ParseTuple(args, "O|ss:decode", &v, &encoding, &errors)) + return NULL; + +#ifdef Py_USING_UNICODE + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); +#else + if (encoding == NULL) { + PyErr_SetString(PyExc_ValueError, "no encoding specified"); + return NULL; + } +#endif + + /* Decode via the codec registry */ + return PyCodec_Decode(v, encoding, errors); +} + +/* --- Helpers ------------------------------------------------------------ */ + +static +PyObject *codec_tuple(PyObject *unicode, + Py_ssize_t len) +{ + PyObject *v; + if (unicode == NULL) + return NULL; + v = Py_BuildValue("On", unicode, len); + Py_DECREF(unicode); + return v; +} + +/* --- String codecs ------------------------------------------------------ */ +static PyObject * +escape_decode(PyObject *self, + PyObject *args) +{ + const char *errors = NULL; + const char *data; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "s#|z:escape_decode", + &data, &size, &errors)) + return NULL; + return codec_tuple(PyString_DecodeEscape(data, size, errors, 0, NULL), + size); +} + +static PyObject * +escape_encode(PyObject *self, + PyObject *args) +{ + PyObject *str; + const char *errors = NULL; + char *buf; + Py_ssize_t len; + + if (!PyArg_ParseTuple(args, "O!|z:escape_encode", + &PyString_Type, &str, &errors)) + return NULL; + + str = PyString_Repr(str, 0); + if (!str) + return NULL; + + /* The string will be quoted. Unquote, similar to unicode-escape. */ + buf = PyString_AS_STRING (str); + len = PyString_GET_SIZE (str); + memmove(buf, buf+1, len-2); + if (_PyString_Resize(&str, len-2) < 0) + return NULL; + + return codec_tuple(str, PyString_Size(str)); +} + +#ifdef Py_USING_UNICODE +/* --- Decoder ------------------------------------------------------------ */ + +static PyObject * +unicode_internal_decode(PyObject *self, + PyObject *args) +{ + PyObject *obj; + const char *errors = NULL; + const char *data; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "O|z:unicode_internal_decode", + &obj, &errors)) + return NULL; + + if (PyUnicode_Check(obj)) { + Py_INCREF(obj); + return codec_tuple(obj, PyUnicode_GET_SIZE(obj)); + } + else { + if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) + return NULL; + + return codec_tuple(_PyUnicode_DecodeUnicodeInternal(data, size, errors), + size); + } +} + +static PyObject * +utf_7_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "t#|z:utf_7_decode", + &data, &size, &errors)) + return NULL; + + return codec_tuple(PyUnicode_DecodeUTF7(data, size, errors), + size); +} + +static PyObject * +utf_8_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int final = 0; + Py_ssize_t consumed; + PyObject *decoded = NULL; + + if (!PyArg_ParseTuple(args, "t#|zi:utf_8_decode", + &data, &size, &errors, &final)) + return NULL; + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative argument"); + return 0; + } + consumed = size; + + decoded = PyUnicode_DecodeUTF8Stateful(data, size, errors, + final ? NULL : &consumed); + if (decoded == NULL) + return NULL; + return codec_tuple(decoded, consumed); +} + +static PyObject * +utf_16_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder = 0; + int final = 0; + Py_ssize_t consumed; + PyObject *decoded; + + if (!PyArg_ParseTuple(args, "t#|zi:utf_16_decode", + &data, &size, &errors, &final)) + return NULL; + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative argument"); + return 0; + } + consumed = size; /* This is overwritten unless final is true. */ + decoded = PyUnicode_DecodeUTF16Stateful(data, size, errors, &byteorder, + final ? NULL : &consumed); + if (decoded == NULL) + return NULL; + return codec_tuple(decoded, consumed); +} + +static PyObject * +utf_16_le_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder = -1; + int final = 0; + Py_ssize_t consumed; + PyObject *decoded = NULL; + + if (!PyArg_ParseTuple(args, "t#|zi:utf_16_le_decode", + &data, &size, &errors, &final)) + return NULL; + + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative argument"); + return 0; + } + consumed = size; /* This is overwritten unless final is true. */ + decoded = PyUnicode_DecodeUTF16Stateful(data, size, errors, + &byteorder, final ? NULL : &consumed); + if (decoded == NULL) + return NULL; + return codec_tuple(decoded, consumed); + +} + +static PyObject * +utf_16_be_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder = 1; + int final = 0; + Py_ssize_t consumed; + PyObject *decoded = NULL; + + if (!PyArg_ParseTuple(args, "t#|zi:utf_16_be_decode", + &data, &size, &errors, &final)) + return NULL; + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative argument"); + return 0; + } + consumed = size; /* This is overwritten unless final is true. */ + decoded = PyUnicode_DecodeUTF16Stateful(data, size, errors, + &byteorder, final ? NULL : &consumed); + if (decoded == NULL) + return NULL; + return codec_tuple(decoded, consumed); +} + +/* This non-standard version also provides access to the byteorder + parameter of the builtin UTF-16 codec. + + It returns a tuple (unicode, bytesread, byteorder) with byteorder + being the value in effect at the end of data. + +*/ + +static PyObject * +utf_16_ex_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + int byteorder = 0; + PyObject *unicode, *tuple; + int final = 0; + Py_ssize_t consumed; + + if (!PyArg_ParseTuple(args, "t#|zii:utf_16_ex_decode", + &data, &size, &errors, &byteorder, &final)) + return NULL; + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "negative argument"); + return 0; + } + consumed = size; /* This is overwritten unless final is true. */ + unicode = PyUnicode_DecodeUTF16Stateful(data, size, errors, &byteorder, + final ? NULL : &consumed); + if (unicode == NULL) + return NULL; + tuple = Py_BuildValue("Oni", unicode, consumed, byteorder); + Py_DECREF(unicode); + return tuple; +} + +static PyObject * +unicode_escape_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "t#|z:unicode_escape_decode", + &data, &size, &errors)) + return NULL; + + return codec_tuple(PyUnicode_DecodeUnicodeEscape(data, size, errors), + size); +} + +static PyObject * +raw_unicode_escape_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "t#|z:raw_unicode_escape_decode", + &data, &size, &errors)) + return NULL; + + return codec_tuple(PyUnicode_DecodeRawUnicodeEscape(data, size, errors), + size); +} + +static PyObject * +latin_1_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "t#|z:latin_1_decode", + &data, &size, &errors)) + return NULL; + + return codec_tuple(PyUnicode_DecodeLatin1(data, size, errors), + size); +} + +static PyObject * +ascii_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "t#|z:ascii_decode", + &data, &size, &errors)) + return NULL; + + return codec_tuple(PyUnicode_DecodeASCII(data, size, errors), + size); +} + +static PyObject * +charmap_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + PyObject *mapping = NULL; + + if (!PyArg_ParseTuple(args, "t#|zO:charmap_decode", + &data, &size, &errors, &mapping)) + return NULL; + if (mapping == Py_None) + mapping = NULL; + + return codec_tuple(PyUnicode_DecodeCharmap(data, size, mapping, errors), + size); +} + +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) + +static PyObject * +mbcs_decode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size, consumed; + const char *errors = NULL; + int final = 0; + PyObject *decoded; + + if (!PyArg_ParseTuple(args, "t#|zi:mbcs_decode", + &data, &size, &errors, &final)) + return NULL; + + decoded = PyUnicode_DecodeMBCSStateful( + data, size, errors, final ? NULL : &consumed); + if (!decoded) + return NULL; + return codec_tuple(decoded, final ? size : consumed); +} + +#endif /* MS_WINDOWS */ + +/* --- Encoder ------------------------------------------------------------ */ + +static PyObject * +readbuffer_encode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "s#|z:readbuffer_encode", + &data, &size, &errors)) + return NULL; + + return codec_tuple(PyString_FromStringAndSize(data, size), + size); +} + +static PyObject * +charbuffer_encode(PyObject *self, + PyObject *args) +{ + const char *data; + Py_ssize_t size; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "t#|z:charbuffer_encode", + &data, &size, &errors)) + return NULL; + + return codec_tuple(PyString_FromStringAndSize(data, size), + size); +} + +static PyObject * +unicode_internal_encode(PyObject *self, + PyObject *args) +{ + PyObject *obj; + const char *errors = NULL; + const char *data; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, "O|z:unicode_internal_encode", + &obj, &errors)) + return NULL; + + if (PyUnicode_Check(obj)) { + data = PyUnicode_AS_DATA(obj); + size = PyUnicode_GET_DATA_SIZE(obj); + return codec_tuple(PyString_FromStringAndSize(data, size), + size); + } + else { + if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) + return NULL; + return codec_tuple(PyString_FromStringAndSize(data, size), + size); + } +} + +static PyObject * +utf_7_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:utf_7_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeUTF7(PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + 0, + 0, + errors), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +utf_8_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:utf_8_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + errors), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +/* This version provides access to the byteorder parameter of the + builtin UTF-16 codecs as optional third argument. It defaults to 0 + which means: use the native byte order and prepend the data with a + BOM mark. + +*/ + +static PyObject * +utf_16_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + int byteorder = 0; + + if (!PyArg_ParseTuple(args, "O|zi:utf_16_encode", + &str, &errors, &byteorder)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + errors, + byteorder), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +utf_16_le_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:utf_16_le_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + errors, + -1), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +utf_16_be_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:utf_16_be_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + errors, + +1), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +unicode_escape_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:unicode_escape_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeUnicodeEscape(PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str)), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +raw_unicode_escape_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:raw_unicode_escape_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeRawUnicodeEscape( + PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str)), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +latin_1_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:latin_1_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeLatin1( + PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + errors), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +ascii_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:ascii_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeASCII( + PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + errors), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject * +charmap_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + PyObject *mapping = NULL; + + if (!PyArg_ParseTuple(args, "O|zO:charmap_encode", + &str, &errors, &mapping)) + return NULL; + if (mapping == Py_None) + mapping = NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeCharmap( + PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + mapping, + errors), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +static PyObject* +charmap_build(PyObject *self, PyObject *args) +{ + PyObject *map; + if (!PyArg_ParseTuple(args, "U:charmap_build", &map)) + return NULL; + return PyUnicode_BuildEncodingMap(map); +} + +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) + +static PyObject * +mbcs_encode(PyObject *self, + PyObject *args) +{ + PyObject *str, *v; + const char *errors = NULL; + + if (!PyArg_ParseTuple(args, "O|z:mbcs_encode", + &str, &errors)) + return NULL; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return NULL; + v = codec_tuple(PyUnicode_EncodeMBCS( + PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + errors), + PyUnicode_GET_SIZE(str)); + Py_DECREF(str); + return v; +} + +#endif /* MS_WINDOWS */ +#endif /* Py_USING_UNICODE */ + +/* --- Error handler registry --------------------------------------------- */ + +PyDoc_STRVAR(register_error__doc__, +"register_error(errors, handler)\n\ +\n\ +Register the specified error handler under the name\n\ +errors. handler must be a callable object, that\n\ +will be called with an exception instance containing\n\ +information about the location of the encoding/decoding\n\ +error and must return a (replacement, new position) tuple."); + +static PyObject *register_error(PyObject *self, PyObject *args) +{ + const char *name; + PyObject *handler; + + if (!PyArg_ParseTuple(args, "sO:register_error", + &name, &handler)) + return NULL; + if (PyCodec_RegisterError(name, handler)) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(lookup_error__doc__, +"lookup_error(errors) -> handler\n\ +\n\ +Return the error handler for the specified error handling name\n\ +or raise a LookupError, if no handler exists under this name."); + +static PyObject *lookup_error(PyObject *self, PyObject *args) +{ + const char *name; + + if (!PyArg_ParseTuple(args, "s:lookup_error", + &name)) + return NULL; + return PyCodec_LookupError(name); +} + +/* --- Module API --------------------------------------------------------- */ + +static PyMethodDef _codecs_functions[] = { + {"register", codec_register, METH_O, + register__doc__}, + {"lookup", codec_lookup, METH_VARARGS, + lookup__doc__}, + {"encode", codec_encode, METH_VARARGS, + encode__doc__}, + {"decode", codec_decode, METH_VARARGS, + decode__doc__}, + {"escape_encode", escape_encode, METH_VARARGS}, + {"escape_decode", escape_decode, METH_VARARGS}, +#ifdef Py_USING_UNICODE + {"utf_8_encode", utf_8_encode, METH_VARARGS}, + {"utf_8_decode", utf_8_decode, METH_VARARGS}, + {"utf_7_encode", utf_7_encode, METH_VARARGS}, + {"utf_7_decode", utf_7_decode, METH_VARARGS}, + {"utf_16_encode", utf_16_encode, METH_VARARGS}, + {"utf_16_le_encode", utf_16_le_encode, METH_VARARGS}, + {"utf_16_be_encode", utf_16_be_encode, METH_VARARGS}, + {"utf_16_decode", utf_16_decode, METH_VARARGS}, + {"utf_16_le_decode", utf_16_le_decode, METH_VARARGS}, + {"utf_16_be_decode", utf_16_be_decode, METH_VARARGS}, + {"utf_16_ex_decode", utf_16_ex_decode, METH_VARARGS}, + {"unicode_escape_encode", unicode_escape_encode, METH_VARARGS}, + {"unicode_escape_decode", unicode_escape_decode, METH_VARARGS}, + {"unicode_internal_encode", unicode_internal_encode, METH_VARARGS}, + {"unicode_internal_decode", unicode_internal_decode, METH_VARARGS}, + {"raw_unicode_escape_encode", raw_unicode_escape_encode, METH_VARARGS}, + {"raw_unicode_escape_decode", raw_unicode_escape_decode, METH_VARARGS}, + {"latin_1_encode", latin_1_encode, METH_VARARGS}, + {"latin_1_decode", latin_1_decode, METH_VARARGS}, + {"ascii_encode", ascii_encode, METH_VARARGS}, + {"ascii_decode", ascii_decode, METH_VARARGS}, + {"charmap_encode", charmap_encode, METH_VARARGS}, + {"charmap_decode", charmap_decode, METH_VARARGS}, + {"charmap_build", charmap_build, METH_VARARGS}, + {"readbuffer_encode", readbuffer_encode, METH_VARARGS}, + {"charbuffer_encode", charbuffer_encode, METH_VARARGS}, +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) + {"mbcs_encode", mbcs_encode, METH_VARARGS}, + {"mbcs_decode", mbcs_decode, METH_VARARGS}, +#endif +#endif /* Py_USING_UNICODE */ + {"register_error", register_error, METH_VARARGS, + register_error__doc__}, + {"lookup_error", lookup_error, METH_VARARGS, + lookup_error__doc__}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +init_codecs(void) +{ + Py_InitModule("_codecs", _codecs_functions); +} diff --git a/sys/src/cmd/python/Modules/_csv.c b/sys/src/cmd/python/Modules/_csv.c new file mode 100644 index 000000000..5e0363559 --- /dev/null +++ b/sys/src/cmd/python/Modules/_csv.c @@ -0,0 +1,1604 @@ +/* csv module */ + +/* + +This module provides the low-level underpinnings of a CSV reading/writing +module. Users should not use this module directly, but import the csv.py +module instead. + +**** For people modifying this code, please note that as of this writing +**** (2003-03-23), it is intended that this code should work with Python +**** 2.2. + +*/ + +#define MODULE_VERSION "1.0" + +#include "Python.h" +#include "structmember.h" + + +/* begin 2.2 compatibility macros */ +#ifndef PyDoc_STRVAR +/* Define macros for inline documentation. */ +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#ifdef WITH_DOC_STRINGS +#define PyDoc_STR(str) str +#else +#define PyDoc_STR(str) "" +#endif +#endif /* ifndef PyDoc_STRVAR */ + +#ifndef PyMODINIT_FUNC +# if defined(__cplusplus) +# define PyMODINIT_FUNC extern "C" void +# else /* __cplusplus */ +# define PyMODINIT_FUNC void +# endif /* __cplusplus */ +#endif + +#ifndef Py_CLEAR +#define Py_CLEAR(op) \ + do { \ + if (op) { \ + PyObject *tmp = (PyObject *)(op); \ + (op) = NULL; \ + Py_DECREF(tmp); \ + } \ + } while (0) +#endif +#ifndef Py_VISIT +#define Py_VISIT(op) \ + do { \ + if (op) { \ + int vret = visit((PyObject *)(op), arg); \ + if (vret) \ + return vret; \ + } \ + } while (0) +#endif + +/* end 2.2 compatibility macros */ + +#define IS_BASESTRING(o) \ + PyObject_TypeCheck(o, &PyBaseString_Type) + +static PyObject *error_obj; /* CSV exception */ +static PyObject *dialects; /* Dialect registry */ +static long field_limit = 128 * 1024; /* max parsed field size */ + +typedef enum { + START_RECORD, START_FIELD, ESCAPED_CHAR, IN_FIELD, + IN_QUOTED_FIELD, ESCAPE_IN_QUOTED_FIELD, QUOTE_IN_QUOTED_FIELD, + EAT_CRNL +} ParserState; + +typedef enum { + QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE +} QuoteStyle; + +typedef struct { + QuoteStyle style; + char *name; +} StyleDesc; + +static StyleDesc quote_styles[] = { + { QUOTE_MINIMAL, "QUOTE_MINIMAL" }, + { QUOTE_ALL, "QUOTE_ALL" }, + { QUOTE_NONNUMERIC, "QUOTE_NONNUMERIC" }, + { QUOTE_NONE, "QUOTE_NONE" }, + { 0 } +}; + +typedef struct { + PyObject_HEAD + + int doublequote; /* is " represented by ""? */ + char delimiter; /* field separator */ + char quotechar; /* quote character */ + char escapechar; /* escape character */ + int skipinitialspace; /* ignore spaces following delimiter? */ + PyObject *lineterminator; /* string to write between records */ + int quoting; /* style of quoting to write */ + + int strict; /* raise exception on bad CSV */ +} DialectObj; + +staticforward PyTypeObject Dialect_Type; + +typedef struct { + PyObject_HEAD + + PyObject *input_iter; /* iterate over this for input lines */ + + DialectObj *dialect; /* parsing dialect */ + + PyObject *fields; /* field list for current record */ + ParserState state; /* current CSV parse state */ + char *field; /* build current field in here */ + int field_size; /* size of allocated buffer */ + int field_len; /* length of current field */ + int numeric_field; /* treat field as numeric */ + unsigned long line_num; /* Source-file line number */ +} ReaderObj; + +staticforward PyTypeObject Reader_Type; + +#define ReaderObject_Check(v) ((v)->ob_type == &Reader_Type) + +typedef struct { + PyObject_HEAD + + PyObject *writeline; /* write output lines to this file */ + + DialectObj *dialect; /* parsing dialect */ + + char *rec; /* buffer for parser.join */ + int rec_size; /* size of allocated record */ + int rec_len; /* length of record */ + int num_fields; /* number of fields in record */ +} WriterObj; + +staticforward PyTypeObject Writer_Type; + +/* + * DIALECT class + */ + +static PyObject * +get_dialect_from_registry(PyObject * name_obj) +{ + PyObject *dialect_obj; + + dialect_obj = PyDict_GetItem(dialects, name_obj); + if (dialect_obj == NULL) { + if (!PyErr_Occurred()) + PyErr_Format(error_obj, "unknown dialect"); + } + else + Py_INCREF(dialect_obj); + return dialect_obj; +} + +static PyObject * +get_string(PyObject *str) +{ + Py_XINCREF(str); + return str; +} + +static PyObject * +get_nullchar_as_None(char c) +{ + if (c == '\0') { + Py_INCREF(Py_None); + return Py_None; + } + else + return PyString_FromStringAndSize((char*)&c, 1); +} + +static PyObject * +Dialect_get_lineterminator(DialectObj *self) +{ + return get_string(self->lineterminator); +} + +static PyObject * +Dialect_get_escapechar(DialectObj *self) +{ + return get_nullchar_as_None(self->escapechar); +} + +static PyObject * +Dialect_get_quotechar(DialectObj *self) +{ + return get_nullchar_as_None(self->quotechar); +} + +static PyObject * +Dialect_get_quoting(DialectObj *self) +{ + return PyInt_FromLong(self->quoting); +} + +static int +_set_bool(const char *name, int *target, PyObject *src, int dflt) +{ + if (src == NULL) + *target = dflt; + else + *target = PyObject_IsTrue(src); + return 0; +} + +static int +_set_int(const char *name, int *target, PyObject *src, int dflt) +{ + if (src == NULL) + *target = dflt; + else { + if (!PyInt_Check(src)) { + PyErr_Format(PyExc_TypeError, + "\"%s\" must be an integer", name); + return -1; + } + *target = PyInt_AsLong(src); + } + return 0; +} + +static int +_set_char(const char *name, char *target, PyObject *src, char dflt) +{ + if (src == NULL) + *target = dflt; + else { + if (src == Py_None || PyString_Size(src) == 0) + *target = '\0'; + else if (!PyString_Check(src) || PyString_Size(src) != 1) { + PyErr_Format(PyExc_TypeError, + "\"%s\" must be an 1-character string", + name); + return -1; + } + else { + char *s = PyString_AsString(src); + if (s == NULL) + return -1; + *target = s[0]; + } + } + return 0; +} + +static int +_set_str(const char *name, PyObject **target, PyObject *src, const char *dflt) +{ + if (src == NULL) + *target = PyString_FromString(dflt); + else { + if (src == Py_None) + *target = NULL; + else if (!IS_BASESTRING(src)) { + PyErr_Format(PyExc_TypeError, + "\"%s\" must be an string", name); + return -1; + } + else { + Py_XDECREF(*target); + Py_INCREF(src); + *target = src; + } + } + return 0; +} + +static int +dialect_check_quoting(int quoting) +{ + StyleDesc *qs = quote_styles; + + for (qs = quote_styles; qs->name; qs++) { + if (qs->style == quoting) + return 0; + } + PyErr_Format(PyExc_TypeError, "bad \"quoting\" value"); + return -1; +} + +#define D_OFF(x) offsetof(DialectObj, x) + +static struct PyMemberDef Dialect_memberlist[] = { + { "delimiter", T_CHAR, D_OFF(delimiter), READONLY }, + { "skipinitialspace", T_INT, D_OFF(skipinitialspace), READONLY }, + { "doublequote", T_INT, D_OFF(doublequote), READONLY }, + { "strict", T_INT, D_OFF(strict), READONLY }, + { NULL } +}; + +static PyGetSetDef Dialect_getsetlist[] = { + { "escapechar", (getter)Dialect_get_escapechar}, + { "lineterminator", (getter)Dialect_get_lineterminator}, + { "quotechar", (getter)Dialect_get_quotechar}, + { "quoting", (getter)Dialect_get_quoting}, + {NULL}, +}; + +static void +Dialect_dealloc(DialectObj *self) +{ + Py_XDECREF(self->lineterminator); + self->ob_type->tp_free((PyObject *)self); +} + +static char *dialect_kws[] = { + "dialect", + "delimiter", + "doublequote", + "escapechar", + "lineterminator", + "quotechar", + "quoting", + "skipinitialspace", + "strict", + NULL +}; + +static PyObject * +dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + DialectObj *self; + PyObject *ret = NULL; + PyObject *dialect = NULL; + PyObject *delimiter = NULL; + PyObject *doublequote = NULL; + PyObject *escapechar = NULL; + PyObject *lineterminator = NULL; + PyObject *quotechar = NULL; + PyObject *quoting = NULL; + PyObject *skipinitialspace = NULL; + PyObject *strict = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "|OOOOOOOOO", dialect_kws, + &dialect, + &delimiter, + &doublequote, + &escapechar, + &lineterminator, + &quotechar, + &quoting, + &skipinitialspace, + &strict)) + return NULL; + + if (dialect != NULL) { + if (IS_BASESTRING(dialect)) { + dialect = get_dialect_from_registry(dialect); + if (dialect == NULL) + return NULL; + } + else + Py_INCREF(dialect); + /* Can we reuse this instance? */ + if (PyObject_TypeCheck(dialect, &Dialect_Type) && + delimiter == 0 && + doublequote == 0 && + escapechar == 0 && + lineterminator == 0 && + quotechar == 0 && + quoting == 0 && + skipinitialspace == 0 && + strict == 0) + return dialect; + } + + self = (DialectObj *)type->tp_alloc(type, 0); + if (self == NULL) { + Py_XDECREF(dialect); + return NULL; + } + self->lineterminator = NULL; + + Py_XINCREF(delimiter); + Py_XINCREF(doublequote); + Py_XINCREF(escapechar); + Py_XINCREF(lineterminator); + Py_XINCREF(quotechar); + Py_XINCREF(quoting); + Py_XINCREF(skipinitialspace); + Py_XINCREF(strict); + if (dialect != NULL) { +#define DIALECT_GETATTR(v, n) \ + if (v == NULL) \ + v = PyObject_GetAttrString(dialect, n) + DIALECT_GETATTR(delimiter, "delimiter"); + DIALECT_GETATTR(doublequote, "doublequote"); + DIALECT_GETATTR(escapechar, "escapechar"); + DIALECT_GETATTR(lineterminator, "lineterminator"); + DIALECT_GETATTR(quotechar, "quotechar"); + DIALECT_GETATTR(quoting, "quoting"); + DIALECT_GETATTR(skipinitialspace, "skipinitialspace"); + DIALECT_GETATTR(strict, "strict"); + PyErr_Clear(); + } + + /* check types and convert to C values */ +#define DIASET(meth, name, target, src, dflt) \ + if (meth(name, target, src, dflt)) \ + goto err + DIASET(_set_char, "delimiter", &self->delimiter, delimiter, ','); + DIASET(_set_bool, "doublequote", &self->doublequote, doublequote, 1); + DIASET(_set_char, "escapechar", &self->escapechar, escapechar, 0); + DIASET(_set_str, "lineterminator", &self->lineterminator, lineterminator, "\r\n"); + DIASET(_set_char, "quotechar", &self->quotechar, quotechar, '"'); + DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL); + DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, 0); + DIASET(_set_bool, "strict", &self->strict, strict, 0); + + /* validate options */ + if (dialect_check_quoting(self->quoting)) + goto err; + if (self->delimiter == 0) { + PyErr_SetString(PyExc_TypeError, "delimiter must be set"); + goto err; + } + if (quotechar == Py_None && quoting == NULL) + self->quoting = QUOTE_NONE; + if (self->quoting != QUOTE_NONE && self->quotechar == 0) { + PyErr_SetString(PyExc_TypeError, + "quotechar must be set if quoting enabled"); + goto err; + } + if (self->lineterminator == 0) { + PyErr_SetString(PyExc_TypeError, "lineterminator must be set"); + goto err; + } + + ret = (PyObject *)self; + Py_INCREF(self); +err: + Py_XDECREF(self); + Py_XDECREF(dialect); + Py_XDECREF(delimiter); + Py_XDECREF(doublequote); + Py_XDECREF(escapechar); + Py_XDECREF(lineterminator); + Py_XDECREF(quotechar); + Py_XDECREF(quoting); + Py_XDECREF(skipinitialspace); + Py_XDECREF(strict); + return ret; +} + + +PyDoc_STRVAR(Dialect_Type_doc, +"CSV dialect\n" +"\n" +"The Dialect type records CSV parsing and generation options.\n"); + +static PyTypeObject Dialect_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_csv.Dialect", /* tp_name */ + sizeof(DialectObj), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)Dialect_dealloc, /* tp_dealloc */ + (printfunc)0, /* tp_print */ + (getattrfunc)0, /* tp_getattr */ + (setattrfunc)0, /* tp_setattr */ + (cmpfunc)0, /* tp_compare */ + (reprfunc)0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)0, /* tp_hash */ + (ternaryfunc)0, /* tp_call */ + (reprfunc)0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Dialect_Type_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + Dialect_memberlist, /* tp_members */ + Dialect_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + dialect_new, /* tp_new */ + 0, /* tp_free */ +}; + +/* + * Return an instance of the dialect type, given a Python instance or kwarg + * description of the dialect + */ +static PyObject * +_call_dialect(PyObject *dialect_inst, PyObject *kwargs) +{ + PyObject *ctor_args; + PyObject *dialect; + + ctor_args = Py_BuildValue(dialect_inst ? "(O)" : "()", dialect_inst); + if (ctor_args == NULL) + return NULL; + dialect = PyObject_Call((PyObject *)&Dialect_Type, ctor_args, kwargs); + Py_DECREF(ctor_args); + return dialect; +} + +/* + * READER + */ +static int +parse_save_field(ReaderObj *self) +{ + PyObject *field; + + field = PyString_FromStringAndSize(self->field, self->field_len); + if (field == NULL) + return -1; + self->field_len = 0; + if (self->numeric_field) { + PyObject *tmp; + + self->numeric_field = 0; + tmp = PyNumber_Float(field); + if (tmp == NULL) { + Py_DECREF(field); + return -1; + } + Py_DECREF(field); + field = tmp; + } + PyList_Append(self->fields, field); + Py_DECREF(field); + return 0; +} + +static int +parse_grow_buff(ReaderObj *self) +{ + if (self->field_size == 0) { + self->field_size = 4096; + if (self->field != NULL) + PyMem_Free(self->field); + self->field = PyMem_Malloc(self->field_size); + } + else { + self->field_size *= 2; + self->field = PyMem_Realloc(self->field, self->field_size); + } + if (self->field == NULL) { + PyErr_NoMemory(); + return 0; + } + return 1; +} + +static int +parse_add_char(ReaderObj *self, char c) +{ + if (self->field_len >= field_limit) { + PyErr_Format(error_obj, "field larger than field limit (%ld)", + field_limit); + return -1; + } + if (self->field_len == self->field_size && !parse_grow_buff(self)) + return -1; + self->field[self->field_len++] = c; + return 0; +} + +static int +parse_process_char(ReaderObj *self, char c) +{ + DialectObj *dialect = self->dialect; + + switch (self->state) { + case START_RECORD: + /* start of record */ + if (c == '\0') + /* empty line - return [] */ + break; + else if (c == '\n' || c == '\r') { + self->state = EAT_CRNL; + break; + } + /* normal character - handle as START_FIELD */ + self->state = START_FIELD; + /* fallthru */ + case START_FIELD: + /* expecting field */ + if (c == '\n' || c == '\r' || c == '\0') { + /* save empty field - return [fields] */ + if (parse_save_field(self) < 0) + return -1; + self->state = (c == '\0' ? START_RECORD : EAT_CRNL); + } + else if (c == dialect->quotechar && + dialect->quoting != QUOTE_NONE) { + /* start quoted field */ + self->state = IN_QUOTED_FIELD; + } + else if (c == dialect->escapechar) { + /* possible escaped character */ + self->state = ESCAPED_CHAR; + } + else if (c == ' ' && dialect->skipinitialspace) + /* ignore space at start of field */ + ; + else if (c == dialect->delimiter) { + /* save empty field */ + if (parse_save_field(self) < 0) + return -1; + } + else { + /* begin new unquoted field */ + if (dialect->quoting == QUOTE_NONNUMERIC) + self->numeric_field = 1; + if (parse_add_char(self, c) < 0) + return -1; + self->state = IN_FIELD; + } + break; + + case ESCAPED_CHAR: + if (c == '\0') + c = '\n'; + if (parse_add_char(self, c) < 0) + return -1; + self->state = IN_FIELD; + break; + + case IN_FIELD: + /* in unquoted field */ + if (c == '\n' || c == '\r' || c == '\0') { + /* end of line - return [fields] */ + if (parse_save_field(self) < 0) + return -1; + self->state = (c == '\0' ? START_RECORD : EAT_CRNL); + } + else if (c == dialect->escapechar) { + /* possible escaped character */ + self->state = ESCAPED_CHAR; + } + else if (c == dialect->delimiter) { + /* save field - wait for new field */ + if (parse_save_field(self) < 0) + return -1; + self->state = START_FIELD; + } + else { + /* normal character - save in field */ + if (parse_add_char(self, c) < 0) + return -1; + } + break; + + case IN_QUOTED_FIELD: + /* in quoted field */ + if (c == '\0') + ; + else if (c == dialect->escapechar) { + /* Possible escape character */ + self->state = ESCAPE_IN_QUOTED_FIELD; + } + else if (c == dialect->quotechar && + dialect->quoting != QUOTE_NONE) { + if (dialect->doublequote) { + /* doublequote; " represented by "" */ + self->state = QUOTE_IN_QUOTED_FIELD; + } + else { + /* end of quote part of field */ + self->state = IN_FIELD; + } + } + else { + /* normal character - save in field */ + if (parse_add_char(self, c) < 0) + return -1; + } + break; + + case ESCAPE_IN_QUOTED_FIELD: + if (c == '\0') + c = '\n'; + if (parse_add_char(self, c) < 0) + return -1; + self->state = IN_QUOTED_FIELD; + break; + + case QUOTE_IN_QUOTED_FIELD: + /* doublequote - seen a quote in an quoted field */ + if (dialect->quoting != QUOTE_NONE && + c == dialect->quotechar) { + /* save "" as " */ + if (parse_add_char(self, c) < 0) + return -1; + self->state = IN_QUOTED_FIELD; + } + else if (c == dialect->delimiter) { + /* save field - wait for new field */ + if (parse_save_field(self) < 0) + return -1; + self->state = START_FIELD; + } + else if (c == '\n' || c == '\r' || c == '\0') { + /* end of line - return [fields] */ + if (parse_save_field(self) < 0) + return -1; + self->state = (c == '\0' ? START_RECORD : EAT_CRNL); + } + else if (!dialect->strict) { + if (parse_add_char(self, c) < 0) + return -1; + self->state = IN_FIELD; + } + else { + /* illegal */ + PyErr_Format(error_obj, "'%c' expected after '%c'", + dialect->delimiter, + dialect->quotechar); + return -1; + } + break; + + case EAT_CRNL: + if (c == '\n' || c == '\r') + ; + else if (c == '\0') + self->state = START_RECORD; + else { + PyErr_Format(error_obj, "new-line character seen in unquoted field - do you need to open the file in universal-newline mode?"); + return -1; + } + break; + + } + return 0; +} + +static int +parse_reset(ReaderObj *self) +{ + Py_XDECREF(self->fields); + self->fields = PyList_New(0); + if (self->fields == NULL) + return -1; + self->field_len = 0; + self->state = START_RECORD; + self->numeric_field = 0; + return 0; +} + +static PyObject * +Reader_iternext(ReaderObj *self) +{ + PyObject *lineobj; + PyObject *fields = NULL; + char *line, c; + int linelen; + + if (parse_reset(self) < 0) + return NULL; + do { + lineobj = PyIter_Next(self->input_iter); + if (lineobj == NULL) { + /* End of input OR exception */ + if (!PyErr_Occurred() && self->field_len != 0) + PyErr_Format(error_obj, + "newline inside string"); + return NULL; + } + ++self->line_num; + + line = PyString_AsString(lineobj); + linelen = PyString_Size(lineobj); + + if (line == NULL || linelen < 0) { + Py_DECREF(lineobj); + return NULL; + } + while (linelen--) { + c = *line++; + if (c == '\0') { + Py_DECREF(lineobj); + PyErr_Format(error_obj, + "line contains NULL byte"); + goto err; + } + if (parse_process_char(self, c) < 0) { + Py_DECREF(lineobj); + goto err; + } + } + Py_DECREF(lineobj); + if (parse_process_char(self, 0) < 0) + goto err; + } while (self->state != START_RECORD); + + fields = self->fields; + self->fields = NULL; +err: + return fields; +} + +static void +Reader_dealloc(ReaderObj *self) +{ + PyObject_GC_UnTrack(self); + Py_XDECREF(self->dialect); + Py_XDECREF(self->input_iter); + Py_XDECREF(self->fields); + if (self->field != NULL) + PyMem_Free(self->field); + PyObject_GC_Del(self); +} + +static int +Reader_traverse(ReaderObj *self, visitproc visit, void *arg) +{ + Py_VISIT(self->dialect); + Py_VISIT(self->input_iter); + Py_VISIT(self->fields); + return 0; +} + +static int +Reader_clear(ReaderObj *self) +{ + Py_CLEAR(self->dialect); + Py_CLEAR(self->input_iter); + Py_CLEAR(self->fields); + return 0; +} + +PyDoc_STRVAR(Reader_Type_doc, +"CSV reader\n" +"\n" +"Reader objects are responsible for reading and parsing tabular data\n" +"in CSV format.\n" +); + +static struct PyMethodDef Reader_methods[] = { + { NULL, NULL } +}; +#define R_OFF(x) offsetof(ReaderObj, x) + +static struct PyMemberDef Reader_memberlist[] = { + { "dialect", T_OBJECT, R_OFF(dialect), RO }, + { "line_num", T_ULONG, R_OFF(line_num), RO }, + { NULL } +}; + + +static PyTypeObject Reader_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_csv.reader", /*tp_name*/ + sizeof(ReaderObj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)Reader_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)0, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + Reader_Type_doc, /*tp_doc*/ + (traverseproc)Reader_traverse, /*tp_traverse*/ + (inquiry)Reader_clear, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + PyObject_SelfIter, /*tp_iter*/ + (getiterfunc)Reader_iternext, /*tp_iternext*/ + Reader_methods, /*tp_methods*/ + Reader_memberlist, /*tp_members*/ + 0, /*tp_getset*/ + +}; + +static PyObject * +csv_reader(PyObject *module, PyObject *args, PyObject *keyword_args) +{ + PyObject * iterator, * dialect = NULL; + ReaderObj * self = PyObject_GC_New(ReaderObj, &Reader_Type); + + if (!self) + return NULL; + + self->dialect = NULL; + self->fields = NULL; + self->input_iter = NULL; + self->field = NULL; + self->field_size = 0; + self->line_num = 0; + + if (parse_reset(self) < 0) { + Py_DECREF(self); + return NULL; + } + + if (!PyArg_UnpackTuple(args, "", 1, 2, &iterator, &dialect)) { + Py_DECREF(self); + return NULL; + } + self->input_iter = PyObject_GetIter(iterator); + if (self->input_iter == NULL) { + PyErr_SetString(PyExc_TypeError, + "argument 1 must be an iterator"); + Py_DECREF(self); + return NULL; + } + self->dialect = (DialectObj *)_call_dialect(dialect, keyword_args); + if (self->dialect == NULL) { + Py_DECREF(self); + return NULL; + } + + PyObject_GC_Track(self); + return (PyObject *)self; +} + +/* + * WRITER + */ +/* ---------------------------------------------------------------- */ +static void +join_reset(WriterObj *self) +{ + self->rec_len = 0; + self->num_fields = 0; +} + +#define MEM_INCR 32768 + +/* Calculate new record length or append field to record. Return new + * record length. + */ +static int +join_append_data(WriterObj *self, char *field, int quote_empty, + int *quoted, int copy_phase) +{ + DialectObj *dialect = self->dialect; + int i, rec_len; + char *lineterm; + +#define ADDCH(c) \ + do {\ + if (copy_phase) \ + self->rec[rec_len] = c;\ + rec_len++;\ + } while(0) + + lineterm = PyString_AsString(dialect->lineterminator); + if (lineterm == NULL) + return -1; + + rec_len = self->rec_len; + + /* If this is not the first field we need a field separator */ + if (self->num_fields > 0) + ADDCH(dialect->delimiter); + + /* Handle preceding quote */ + if (copy_phase && *quoted) + ADDCH(dialect->quotechar); + + /* Copy/count field data */ + for (i = 0;; i++) { + char c = field[i]; + int want_escape = 0; + + if (c == '\0') + break; + + if (c == dialect->delimiter || + c == dialect->escapechar || + c == dialect->quotechar || + strchr(lineterm, c)) { + if (dialect->quoting == QUOTE_NONE) + want_escape = 1; + else { + if (c == dialect->quotechar) { + if (dialect->doublequote) + ADDCH(dialect->quotechar); + else + want_escape = 1; + } + if (!want_escape) + *quoted = 1; + } + if (want_escape) { + if (!dialect->escapechar) { + PyErr_Format(error_obj, + "need to escape, but no escapechar set"); + return -1; + } + ADDCH(dialect->escapechar); + } + } + /* Copy field character into record buffer. + */ + ADDCH(c); + } + + /* If field is empty check if it needs to be quoted. + */ + if (i == 0 && quote_empty) { + if (dialect->quoting == QUOTE_NONE) { + PyErr_Format(error_obj, + "single empty field record must be quoted"); + return -1; + } + else + *quoted = 1; + } + + if (*quoted) { + if (copy_phase) + ADDCH(dialect->quotechar); + else + rec_len += 2; + } + return rec_len; +#undef ADDCH +} + +static int +join_check_rec_size(WriterObj *self, int rec_len) +{ + if (rec_len > self->rec_size) { + if (self->rec_size == 0) { + self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR; + if (self->rec != NULL) + PyMem_Free(self->rec); + self->rec = PyMem_Malloc(self->rec_size); + } + else { + char *old_rec = self->rec; + + self->rec_size = (rec_len / MEM_INCR + 1) * MEM_INCR; + self->rec = PyMem_Realloc(self->rec, self->rec_size); + if (self->rec == NULL) + PyMem_Free(old_rec); + } + if (self->rec == NULL) { + PyErr_NoMemory(); + return 0; + } + } + return 1; +} + +static int +join_append(WriterObj *self, char *field, int *quoted, int quote_empty) +{ + int rec_len; + + rec_len = join_append_data(self, field, quote_empty, quoted, 0); + if (rec_len < 0) + return 0; + + /* grow record buffer if necessary */ + if (!join_check_rec_size(self, rec_len)) + return 0; + + self->rec_len = join_append_data(self, field, quote_empty, quoted, 1); + self->num_fields++; + + return 1; +} + +static int +join_append_lineterminator(WriterObj *self) +{ + int terminator_len; + char *terminator; + + terminator_len = PyString_Size(self->dialect->lineterminator); + if (terminator_len == -1) + return 0; + + /* grow record buffer if necessary */ + if (!join_check_rec_size(self, self->rec_len + terminator_len)) + return 0; + + terminator = PyString_AsString(self->dialect->lineterminator); + if (terminator == NULL) + return 0; + memmove(self->rec + self->rec_len, terminator, terminator_len); + self->rec_len += terminator_len; + + return 1; +} + +PyDoc_STRVAR(csv_writerow_doc, +"writerow(sequence)\n" +"\n" +"Construct and write a CSV record from a sequence of fields. Non-string\n" +"elements will be converted to string."); + +static PyObject * +csv_writerow(WriterObj *self, PyObject *seq) +{ + DialectObj *dialect = self->dialect; + int len, i; + + if (!PySequence_Check(seq)) + return PyErr_Format(error_obj, "sequence expected"); + + len = PySequence_Length(seq); + if (len < 0) + return NULL; + + /* Join all fields in internal buffer. + */ + join_reset(self); + for (i = 0; i < len; i++) { + PyObject *field; + int append_ok; + int quoted; + + field = PySequence_GetItem(seq, i); + if (field == NULL) + return NULL; + + switch (dialect->quoting) { + case QUOTE_NONNUMERIC: + quoted = !PyNumber_Check(field); + break; + case QUOTE_ALL: + quoted = 1; + break; + default: + quoted = 0; + break; + } + + if (PyString_Check(field)) { + append_ok = join_append(self, + PyString_AS_STRING(field), + &quoted, len == 1); + Py_DECREF(field); + } + else if (field == Py_None) { + append_ok = join_append(self, "", &quoted, len == 1); + Py_DECREF(field); + } + else { + PyObject *str; + + str = PyObject_Str(field); + Py_DECREF(field); + if (str == NULL) + return NULL; + + append_ok = join_append(self, PyString_AS_STRING(str), + &quoted, len == 1); + Py_DECREF(str); + } + if (!append_ok) + return NULL; + } + + /* Add line terminator. + */ + if (!join_append_lineterminator(self)) + return 0; + + return PyObject_CallFunction(self->writeline, + "(s#)", self->rec, self->rec_len); +} + +PyDoc_STRVAR(csv_writerows_doc, +"writerows(sequence of sequences)\n" +"\n" +"Construct and write a series of sequences to a csv file. Non-string\n" +"elements will be converted to string."); + +static PyObject * +csv_writerows(WriterObj *self, PyObject *seqseq) +{ + PyObject *row_iter, *row_obj, *result; + + row_iter = PyObject_GetIter(seqseq); + if (row_iter == NULL) { + PyErr_SetString(PyExc_TypeError, + "writerows() argument must be iterable"); + return NULL; + } + while ((row_obj = PyIter_Next(row_iter))) { + result = csv_writerow(self, row_obj); + Py_DECREF(row_obj); + if (!result) { + Py_DECREF(row_iter); + return NULL; + } + else + Py_DECREF(result); + } + Py_DECREF(row_iter); + if (PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static struct PyMethodDef Writer_methods[] = { + { "writerow", (PyCFunction)csv_writerow, METH_O, csv_writerow_doc}, + { "writerows", (PyCFunction)csv_writerows, METH_O, csv_writerows_doc}, + { NULL, NULL } +}; + +#define W_OFF(x) offsetof(WriterObj, x) + +static struct PyMemberDef Writer_memberlist[] = { + { "dialect", T_OBJECT, W_OFF(dialect), RO }, + { NULL } +}; + +static void +Writer_dealloc(WriterObj *self) +{ + PyObject_GC_UnTrack(self); + Py_XDECREF(self->dialect); + Py_XDECREF(self->writeline); + if (self->rec != NULL) + PyMem_Free(self->rec); + PyObject_GC_Del(self); +} + +static int +Writer_traverse(WriterObj *self, visitproc visit, void *arg) +{ + Py_VISIT(self->dialect); + Py_VISIT(self->writeline); + return 0; +} + +static int +Writer_clear(WriterObj *self) +{ + Py_CLEAR(self->dialect); + Py_CLEAR(self->writeline); + return 0; +} + +PyDoc_STRVAR(Writer_Type_doc, +"CSV writer\n" +"\n" +"Writer objects are responsible for generating tabular data\n" +"in CSV format from sequence input.\n" +); + +static PyTypeObject Writer_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_csv.writer", /*tp_name*/ + sizeof(WriterObj), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)Writer_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)0, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + Writer_Type_doc, + (traverseproc)Writer_traverse, /*tp_traverse*/ + (inquiry)Writer_clear, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + (getiterfunc)0, /*tp_iter*/ + (getiterfunc)0, /*tp_iternext*/ + Writer_methods, /*tp_methods*/ + Writer_memberlist, /*tp_members*/ + 0, /*tp_getset*/ +}; + +static PyObject * +csv_writer(PyObject *module, PyObject *args, PyObject *keyword_args) +{ + PyObject * output_file, * dialect = NULL; + WriterObj * self = PyObject_GC_New(WriterObj, &Writer_Type); + + if (!self) + return NULL; + + self->dialect = NULL; + self->writeline = NULL; + + self->rec = NULL; + self->rec_size = 0; + self->rec_len = 0; + self->num_fields = 0; + + if (!PyArg_UnpackTuple(args, "", 1, 2, &output_file, &dialect)) { + Py_DECREF(self); + return NULL; + } + self->writeline = PyObject_GetAttrString(output_file, "write"); + if (self->writeline == NULL || !PyCallable_Check(self->writeline)) { + PyErr_SetString(PyExc_TypeError, + "argument 1 must have a \"write\" method"); + Py_DECREF(self); + return NULL; + } + self->dialect = (DialectObj *)_call_dialect(dialect, keyword_args); + if (self->dialect == NULL) { + Py_DECREF(self); + return NULL; + } + PyObject_GC_Track(self); + return (PyObject *)self; +} + +/* + * DIALECT REGISTRY + */ +static PyObject * +csv_list_dialects(PyObject *module, PyObject *args) +{ + return PyDict_Keys(dialects); +} + +static PyObject * +csv_register_dialect(PyObject *module, PyObject *args, PyObject *kwargs) +{ + PyObject *name_obj, *dialect_obj = NULL; + PyObject *dialect; + + if (!PyArg_UnpackTuple(args, "", 1, 2, &name_obj, &dialect_obj)) + return NULL; + if (!IS_BASESTRING(name_obj)) { + PyErr_SetString(PyExc_TypeError, + "dialect name must be a string or unicode"); + return NULL; + } + dialect = _call_dialect(dialect_obj, kwargs); + if (dialect == NULL) + return NULL; + if (PyDict_SetItem(dialects, name_obj, dialect) < 0) { + Py_DECREF(dialect); + return NULL; + } + Py_DECREF(dialect); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +csv_unregister_dialect(PyObject *module, PyObject *name_obj) +{ + if (PyDict_DelItem(dialects, name_obj) < 0) + return PyErr_Format(error_obj, "unknown dialect"); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +csv_get_dialect(PyObject *module, PyObject *name_obj) +{ + return get_dialect_from_registry(name_obj); +} + +static PyObject * +csv_field_size_limit(PyObject *module, PyObject *args) +{ + PyObject *new_limit = NULL; + long old_limit = field_limit; + + if (!PyArg_UnpackTuple(args, "field_size_limit", 0, 1, &new_limit)) + return NULL; + if (new_limit != NULL) { + if (!PyInt_Check(new_limit)) { + PyErr_Format(PyExc_TypeError, + "limit must be an integer"); + return NULL; + } + field_limit = PyInt_AsLong(new_limit); + } + return PyInt_FromLong(old_limit); +} + +/* + * MODULE + */ + +PyDoc_STRVAR(csv_module_doc, +"CSV parsing and writing.\n" +"\n" +"This module provides classes that assist in the reading and writing\n" +"of Comma Separated Value (CSV) files, and implements the interface\n" +"described by PEP 305. Although many CSV files are simple to parse,\n" +"the format is not formally defined by a stable specification and\n" +"is subtle enough that parsing lines of a CSV file with something\n" +"like line.split(\",\") is bound to fail. The module supports three\n" +"basic APIs: reading, writing, and registration of dialects.\n" +"\n" +"\n" +"DIALECT REGISTRATION:\n" +"\n" +"Readers and writers support a dialect argument, which is a convenient\n" +"handle on a group of settings. When the dialect argument is a string,\n" +"it identifies one of the dialects previously registered with the module.\n" +"If it is a class or instance, the attributes of the argument are used as\n" +"the settings for the reader or writer:\n" +"\n" +" class excel:\n" +" delimiter = ','\n" +" quotechar = '\"'\n" +" escapechar = None\n" +" doublequote = True\n" +" skipinitialspace = False\n" +" lineterminator = '\\r\\n'\n" +" quoting = QUOTE_MINIMAL\n" +"\n" +"SETTINGS:\n" +"\n" +" * quotechar - specifies a one-character string to use as the \n" +" quoting character. It defaults to '\"'.\n" +" * delimiter - specifies a one-character string to use as the \n" +" field separator. It defaults to ','.\n" +" * skipinitialspace - specifies how to interpret whitespace which\n" +" immediately follows a delimiter. It defaults to False, which\n" +" means that whitespace immediately following a delimiter is part\n" +" of the following field.\n" +" * lineterminator - specifies the character sequence which should \n" +" terminate rows.\n" +" * quoting - controls when quotes should be generated by the writer.\n" +" It can take on any of the following module constants:\n" +"\n" +" csv.QUOTE_MINIMAL means only when required, for example, when a\n" +" field contains either the quotechar or the delimiter\n" +" csv.QUOTE_ALL means that quotes are always placed around fields.\n" +" csv.QUOTE_NONNUMERIC means that quotes are always placed around\n" +" fields which do not parse as integers or floating point\n" +" numbers.\n" +" csv.QUOTE_NONE means that quotes are never placed around fields.\n" +" * escapechar - specifies a one-character string used to escape \n" +" the delimiter when quoting is set to QUOTE_NONE.\n" +" * doublequote - controls the handling of quotes inside fields. When\n" +" True, two consecutive quotes are interpreted as one during read,\n" +" and when writing, each quote character embedded in the data is\n" +" written as two quotes\n"); + +PyDoc_STRVAR(csv_reader_doc, +" csv_reader = reader(iterable [, dialect='excel']\n" +" [optional keyword args])\n" +" for row in csv_reader:\n" +" process(row)\n" +"\n" +"The \"iterable\" argument can be any object that returns a line\n" +"of input for each iteration, such as a file object or a list. The\n" +"optional \"dialect\" parameter is discussed below. The function\n" +"also accepts optional keyword arguments which override settings\n" +"provided by the dialect.\n" +"\n" +"The returned object is an iterator. Each iteration returns a row\n" +"of the CSV file (which can span multiple input lines):\n"); + +PyDoc_STRVAR(csv_writer_doc, +" csv_writer = csv.writer(fileobj [, dialect='excel']\n" +" [optional keyword args])\n" +" for row in sequence:\n" +" csv_writer.writerow(row)\n" +"\n" +" [or]\n" +"\n" +" csv_writer = csv.writer(fileobj [, dialect='excel']\n" +" [optional keyword args])\n" +" csv_writer.writerows(rows)\n" +"\n" +"The \"fileobj\" argument can be any object that supports the file API.\n"); + +PyDoc_STRVAR(csv_list_dialects_doc, +"Return a list of all know dialect names.\n" +" names = csv.list_dialects()"); + +PyDoc_STRVAR(csv_get_dialect_doc, +"Return the dialect instance associated with name.\n" +" dialect = csv.get_dialect(name)"); + +PyDoc_STRVAR(csv_register_dialect_doc, +"Create a mapping from a string name to a dialect class.\n" +" dialect = csv.register_dialect(name, dialect)"); + +PyDoc_STRVAR(csv_unregister_dialect_doc, +"Delete the name/dialect mapping associated with a string name.\n" +" csv.unregister_dialect(name)"); + +PyDoc_STRVAR(csv_field_size_limit_doc, +"Sets an upper limit on parsed fields.\n" +" csv.field_size_limit([limit])\n" +"\n" +"Returns old limit. If limit is not given, no new limit is set and\n" +"the old limit is returned"); + +static struct PyMethodDef csv_methods[] = { + { "reader", (PyCFunction)csv_reader, + METH_VARARGS | METH_KEYWORDS, csv_reader_doc}, + { "writer", (PyCFunction)csv_writer, + METH_VARARGS | METH_KEYWORDS, csv_writer_doc}, + { "list_dialects", (PyCFunction)csv_list_dialects, + METH_NOARGS, csv_list_dialects_doc}, + { "register_dialect", (PyCFunction)csv_register_dialect, + METH_VARARGS | METH_KEYWORDS, csv_register_dialect_doc}, + { "unregister_dialect", (PyCFunction)csv_unregister_dialect, + METH_O, csv_unregister_dialect_doc}, + { "get_dialect", (PyCFunction)csv_get_dialect, + METH_O, csv_get_dialect_doc}, + { "field_size_limit", (PyCFunction)csv_field_size_limit, + METH_VARARGS, csv_field_size_limit_doc}, + { NULL, NULL } +}; + +PyMODINIT_FUNC +init_csv(void) +{ + PyObject *module; + StyleDesc *style; + + if (PyType_Ready(&Dialect_Type) < 0) + return; + + if (PyType_Ready(&Reader_Type) < 0) + return; + + if (PyType_Ready(&Writer_Type) < 0) + return; + + /* Create the module and add the functions */ + module = Py_InitModule3("_csv", csv_methods, csv_module_doc); + if (module == NULL) + return; + + /* Add version to the module. */ + if (PyModule_AddStringConstant(module, "__version__", + MODULE_VERSION) == -1) + return; + + /* Add _dialects dictionary */ + dialects = PyDict_New(); + if (dialects == NULL) + return; + if (PyModule_AddObject(module, "_dialects", dialects)) + return; + + /* Add quote styles into dictionary */ + for (style = quote_styles; style->name; style++) { + if (PyModule_AddIntConstant(module, style->name, + style->style) == -1) + return; + } + + /* Add the Dialect type */ + Py_INCREF(&Dialect_Type); + if (PyModule_AddObject(module, "Dialect", (PyObject *)&Dialect_Type)) + return; + + /* Add the CSV exception object to the module. */ + error_obj = PyErr_NewException("_csv.Error", NULL, NULL); + if (error_obj == NULL) + return; + PyModule_AddObject(module, "Error", error_obj); +} diff --git a/sys/src/cmd/python/Modules/_ctypes/_ctypes.c b/sys/src/cmd/python/Modules/_ctypes/_ctypes.c new file mode 100644 index 000000000..4dd35c233 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/_ctypes.c @@ -0,0 +1,4859 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + + +/* + ToDo: + + Get rid of the checker (and also the converters) field in CFuncPtrObject and + StgDictObject, and replace them by slot functions in StgDictObject. + + think about a buffer-like object (memory? bytes?) + + Should POINTER(c_char) and POINTER(c_wchar) have a .value property? + What about c_char and c_wchar arrays then? + + Add from_mmap, from_file, from_string metaclass methods. + + Maybe we can get away with from_file (calls read) and with a from_buffer + method? + + And what about the to_mmap, to_file, to_str(?) methods? They would clobber + the namespace, probably. So, functions instead? And we already have memmove... +*/ + +/* + +Name methods, members, getsets +============================================================================== + +StructType_Type __new__(), from_address(), __mul__(), from_param() +UnionType_Type __new__(), from_address(), __mul__(), from_param() +PointerType_Type __new__(), from_address(), __mul__(), from_param(), set_type() +ArrayType_Type __new__(), from_address(), __mul__(), from_param() +SimpleType_Type __new__(), from_address(), __mul__(), from_param() + +CData_Type + Struct_Type __new__(), __init__() + Pointer_Type __new__(), __init__(), _as_parameter_, contents + Array_Type __new__(), __init__(), _as_parameter_, __get/setitem__(), __len__() + Simple_Type __new__(), __init__(), _as_parameter_ + +CField_Type +StgDict_Type + +============================================================================== + +class methods +------------- + +It has some similarity to the byref() construct compared to pointer() +from_address(addr) + - construct an instance from a given memory block (sharing this memory block) + +from_param(obj) + - typecheck and convert a Python object into a C function call parameter + the result may be an instance of the type, or an integer or tuple + (typecode, value[, obj]) + +instance methods/properties +--------------------------- + +_as_parameter_ + - convert self into a C function call parameter + This is either an integer, or a 3-tuple (typecode, value, obj) + +functions +--------- + +sizeof(cdata) + - return the number of bytes the buffer contains + +sizeof(ctype) + - return the number of bytes the buffer of an instance would contain + +byref(cdata) + +addressof(cdata) + +pointer(cdata) + +POINTER(ctype) + +bytes(cdata) + - return the buffer contents as a sequence of bytes (which is currently a string) + +*/ + +/* + * StgDict_Type + * StructType_Type + * UnionType_Type + * PointerType_Type + * ArrayType_Type + * SimpleType_Type + * + * CData_Type + * Struct_Type + * Union_Type + * Array_Type + * Simple_Type + * Pointer_Type + * CField_Type + * + */ + +#include "Python.h" +#include "structmember.h" + +#include <ffi.h> +#ifdef MS_WIN32 +#include <windows.h> +#include <malloc.h> +#ifndef IS_INTRESOURCE +#define IS_INTRESOURCE(x) (((size_t)(x) >> 16) == 0) +#endif +# ifdef _WIN32_WCE +/* Unlike desktop Windows, WinCE has both W and A variants of + GetProcAddress, but the default W version is not what we want */ +# undef GetProcAddress +# define GetProcAddress GetProcAddressA +# endif +#else +#include "ctypes_dlfcn.h" +#endif +#include "ctypes.h" + +PyObject *PyExc_ArgError; +static PyTypeObject Simple_Type; + +char *conversion_mode_encoding = NULL; +char *conversion_mode_errors = NULL; + + +/******************************************************************/ +/* + StructType_Type - a meta type/class. Creating a new class using this one as + __metaclass__ will call the contructor StructUnionType_new. It replaces the + tp_dict member with a new instance of StgDict, and initializes the C + accessible fields somehow. +*/ + +static PyCArgObject * +StructUnionType_paramfunc(CDataObject *self) +{ + PyCArgObject *parg; + StgDictObject *stgdict; + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + + parg->tag = 'V'; + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL for structure/union instances */ + parg->pffi_type = &stgdict->ffi_type_pointer; + /* For structure parameters (by value), parg->value doesn't contain the structure + data itself, instead parg->value.p *points* to the structure's data + See also _ctypes.c, function _call_function_pointer(). + */ + parg->value.p = self->b_ptr; + parg->size = self->b_size; + Py_INCREF(self); + parg->obj = (PyObject *)self; + return parg; +} + +static PyObject * +StructUnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds, int isStruct) +{ + PyTypeObject *result; + PyObject *fields; + StgDictObject *dict; + + /* create the new instance (which is a class, + since we are a metatype!) */ + result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); + if (!result) + return NULL; + + /* keep this for bw compatibility */ + if (PyDict_GetItemString(result->tp_dict, "_abstract_")) + return (PyObject *)result; + + dict = (StgDictObject *)PyObject_CallObject((PyObject *)&StgDict_Type, NULL); + if (!dict) { + Py_DECREF(result); + return NULL; + } + /* replace the class dict by our updated stgdict, which holds info + about storage requirements of the instances */ + if (-1 == PyDict_Update((PyObject *)dict, result->tp_dict)) { + Py_DECREF(result); + Py_DECREF((PyObject *)dict); + return NULL; + } + Py_DECREF(result->tp_dict); + result->tp_dict = (PyObject *)dict; + + dict->paramfunc = StructUnionType_paramfunc; + + fields = PyDict_GetItemString((PyObject *)dict, "_fields_"); + if (!fields) { + StgDictObject *basedict = PyType_stgdict((PyObject *)result->tp_base); + + if (basedict == NULL) + return (PyObject *)result; + /* copy base dict */ + if (-1 == StgDict_clone(dict, basedict)) { + Py_DECREF(result); + return NULL; + } + dict->flags &= ~DICTFLAG_FINAL; /* clear the 'final' flag in the subclass dict */ + basedict->flags |= DICTFLAG_FINAL; /* set the 'final' flag in the baseclass dict */ + return (PyObject *)result; + } + + if (-1 == PyObject_SetAttrString((PyObject *)result, "_fields_", fields)) { + Py_DECREF(result); + return NULL; + } + return (PyObject *)result; +} + +static PyObject * +StructType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return StructUnionType_new(type, args, kwds, 1); +} + +static PyObject * +UnionType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return StructUnionType_new(type, args, kwds, 0); +} + +static char from_address_doc[] = +"C.from_address(integer) -> C instance\naccess a C instance at the specified address"; + +static PyObject * +CDataType_from_address(PyObject *type, PyObject *value) +{ + void *buf; + if (!PyInt_Check(value) && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "integer expected"); + return NULL; + } + buf = (void *)PyLong_AsVoidPtr(value); + if (PyErr_Occurred()) + return NULL; + return CData_AtAddress(type, buf); +} + +static char in_dll_doc[] = +"C.in_dll(dll, name) -> C instance\naccess a C instance in a dll"; + +static PyObject * +CDataType_in_dll(PyObject *type, PyObject *args) +{ + PyObject *dll; + char *name; + PyObject *obj; + void *handle; + void *address; + + if (!PyArg_ParseTuple(args, "Os:in_dll", &dll, &name)) + return NULL; + + obj = PyObject_GetAttrString(dll, "_handle"); + if (!obj) + return NULL; + if (!PyInt_Check(obj) && !PyLong_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "the _handle attribute of the second argument must be an integer"); + Py_DECREF(obj); + return NULL; + } + handle = (void *)PyLong_AsVoidPtr(obj); + Py_DECREF(obj); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "could not convert the _handle attribute to a pointer"); + return NULL; + } + +#ifdef MS_WIN32 + address = (void *)GetProcAddress(handle, name); + if (!address) { + PyErr_Format(PyExc_ValueError, + "symbol '%s' not found", + name); + return NULL; + } +#else + address = (void *)ctypes_dlsym(handle, name); + if (!address) { + PyErr_Format(PyExc_ValueError, +#ifdef __CYGWIN__ +/* dlerror() isn't very helpful on cygwin */ + "symbol '%s' not found (%s) ", + name, +#endif + ctypes_dlerror()); + return NULL; + } +#endif + return CData_AtAddress(type, address); +} + +static char from_param_doc[] = +"Convert a Python object into a function call parameter."; + +static PyObject * +CDataType_from_param(PyObject *type, PyObject *value) +{ + PyObject *as_parameter; + if (1 == PyObject_IsInstance(value, type)) { + Py_INCREF(value); + return value; + } + if (PyCArg_CheckExact(value)) { + PyCArgObject *p = (PyCArgObject *)value; + PyObject *ob = p->obj; + const char *ob_name; + StgDictObject *dict; + dict = PyType_stgdict(type); + + /* If we got a PyCArgObject, we must check if the object packed in it + is an instance of the type's dict->proto */ + if(dict && ob + && PyObject_IsInstance(ob, dict->proto)) { + Py_INCREF(value); + return value; + } + ob_name = (ob) ? ob->ob_type->tp_name : "???"; + PyErr_Format(PyExc_TypeError, + "expected %s instance instead of pointer to %s", + ((PyTypeObject *)type)->tp_name, ob_name); + return NULL; + } + + as_parameter = PyObject_GetAttrString(value, "_as_parameter_"); + if (as_parameter) { + value = CDataType_from_param(type, as_parameter); + Py_DECREF(as_parameter); + return value; + } + PyErr_Format(PyExc_TypeError, + "expected %s instance instead of %s", + ((PyTypeObject *)type)->tp_name, + value->ob_type->tp_name); + return NULL; +} + +static PyMethodDef CDataType_methods[] = { + { "from_param", CDataType_from_param, METH_O, from_param_doc }, + { "from_address", CDataType_from_address, METH_O, from_address_doc }, + { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc }, + { NULL, NULL }, +}; + +static PyObject * +CDataType_repeat(PyObject *self, Py_ssize_t length) +{ + if (length < 0) + return PyErr_Format(PyExc_ValueError, +#if (PY_VERSION_HEX < 0x02050000) + "Array length must be >= 0, not %d", +#else + "Array length must be >= 0, not %zd", +#endif + length); + return CreateArrayType(self, length); +} + +static PySequenceMethods CDataType_as_sequence = { + 0, /* inquiry sq_length; */ + 0, /* binaryfunc sq_concat; */ + CDataType_repeat, /* intargfunc sq_repeat; */ + 0, /* intargfunc sq_item; */ + 0, /* intintargfunc sq_slice; */ + 0, /* intobjargproc sq_ass_item; */ + 0, /* intintobjargproc sq_ass_slice; */ + 0, /* objobjproc sq_contains; */ + + 0, /* binaryfunc sq_inplace_concat; */ + 0, /* intargfunc sq_inplace_repeat; */ +}; + +static int +CDataType_clear(PyTypeObject *self) +{ + StgDictObject *dict = PyType_stgdict((PyObject *)self); + if (dict) + Py_CLEAR(dict->proto); + return PyType_Type.tp_clear((PyObject *)self); +} + +static int +CDataType_traverse(PyTypeObject *self, visitproc visit, void *arg) +{ + StgDictObject *dict = PyType_stgdict((PyObject *)self); + if (dict) + Py_VISIT(dict->proto); + return PyType_Type.tp_traverse((PyObject *)self, visit, arg); +} + +static int +StructType_setattro(PyObject *self, PyObject *key, PyObject *value) +{ + /* XXX Should we disallow deleting _fields_? */ + if (-1 == PyObject_GenericSetAttr(self, key, value)) + return -1; + + if (value && PyString_Check(key) && + 0 == strcmp(PyString_AS_STRING(key), "_fields_")) + return StructUnionType_update_stgdict(self, value, 1); + return 0; +} + + +static int +UnionType_setattro(PyObject *self, PyObject *key, PyObject *value) +{ + /* XXX Should we disallow deleting _fields_? */ + if (-1 == PyObject_GenericSetAttr(self, key, value)) + return -1; + + if (PyString_Check(key) && + 0 == strcmp(PyString_AS_STRING(key), "_fields_")) + return StructUnionType_update_stgdict(self, value, 0); + return 0; +} + + +PyTypeObject StructType_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_ctypes.StructType", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &CDataType_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + StructType_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + "metatype for the CData Objects", /* tp_doc */ + (traverseproc)CDataType_traverse, /* tp_traverse */ + (inquiry)CDataType_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CDataType_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + StructType_new, /* tp_new */ + 0, /* tp_free */ +}; + +static PyTypeObject UnionType_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_ctypes.UnionType", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &CDataType_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + UnionType_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + "metatype for the CData Objects", /* tp_doc */ + (traverseproc)CDataType_traverse, /* tp_traverse */ + (inquiry)CDataType_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CDataType_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + UnionType_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/******************************************************************/ + +/* + +The PointerType_Type metaclass must ensure that the subclass of Pointer can be +created. It must check for a _type_ attribute in the class. Since are no +runtime created properties, a CField is probably *not* needed ? + +class IntPointer(Pointer): + _type_ = "i" + +The Pointer_Type provides the functionality: a contents method/property, a +size property/method, and the sequence protocol. + +*/ + +static int +PointerType_SetProto(StgDictObject *stgdict, PyObject *proto) +{ + if (!proto || !PyType_Check(proto)) { + PyErr_SetString(PyExc_TypeError, + "_type_ must be a type"); + return -1; + } + if (!PyType_stgdict(proto)) { + PyErr_SetString(PyExc_TypeError, + "_type_ must have storage info"); + return -1; + } + Py_INCREF(proto); + Py_XDECREF(stgdict->proto); + stgdict->proto = proto; + return 0; +} + +static PyCArgObject * +PointerType_paramfunc(CDataObject *self) +{ + PyCArgObject *parg; + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + + parg->tag = 'P'; + parg->pffi_type = &ffi_type_pointer; + Py_INCREF(self); + parg->obj = (PyObject *)self; + parg->value.p = *(void **)self->b_ptr; + return parg; +} + +static PyObject * +PointerType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyTypeObject *result; + StgDictObject *stgdict; + PyObject *proto; + PyObject *typedict; + + typedict = PyTuple_GetItem(args, 2); + if (!typedict) + return NULL; +/* + stgdict items size, align, length contain info about pointers itself, + stgdict->proto has info about the pointed to type! +*/ + stgdict = (StgDictObject *)PyObject_CallObject( + (PyObject *)&StgDict_Type, NULL); + if (!stgdict) + return NULL; + stgdict->size = sizeof(void *); + stgdict->align = getentry("P")->pffi_type->alignment; + stgdict->length = 1; + stgdict->ffi_type_pointer = ffi_type_pointer; + stgdict->paramfunc = PointerType_paramfunc; + + proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */ + if (proto && -1 == PointerType_SetProto(stgdict, proto)) { + Py_DECREF((PyObject *)stgdict); + return NULL; + } + + /* create the new instance (which is a class, + since we are a metatype!) */ + result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); + if (result == NULL) { + Py_DECREF((PyObject *)stgdict); + return NULL; + } + + /* replace the class dict by our updated spam dict */ + if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { + Py_DECREF(result); + Py_DECREF((PyObject *)stgdict); + return NULL; + } + Py_DECREF(result->tp_dict); + result->tp_dict = (PyObject *)stgdict; + + return (PyObject *)result; +} + + +static PyObject * +PointerType_set_type(PyTypeObject *self, PyObject *type) +{ + StgDictObject *dict; + + dict = PyType_stgdict((PyObject *)self); + assert(dict); + + if (-1 == PointerType_SetProto(dict, type)) + return NULL; + + if (-1 == PyDict_SetItemString((PyObject *)dict, "_type_", type)) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +staticforward PyObject *_byref(PyObject *); + +static PyObject * +PointerType_from_param(PyObject *type, PyObject *value) +{ + StgDictObject *typedict; + + if (value == Py_None) + return PyInt_FromLong(0); /* NULL pointer */ + + typedict = PyType_stgdict(type); + assert(typedict); /* Cannot be NULL for pointer types */ + + /* If we expect POINTER(<type>), but receive a <type> instance, accept + it by calling byref(<type>). + */ + switch (PyObject_IsInstance(value, typedict->proto)) { + case 1: + Py_INCREF(value); /* _byref steals a refcount */ + return _byref(value); + case -1: + PyErr_Clear(); + break; + default: + break; + } + + if (PointerObject_Check(value) || ArrayObject_Check(value)) { + /* Array instances are also pointers when + the item types are the same. + */ + StgDictObject *v = PyObject_stgdict(value); + assert(v); /* Cannot be NULL for pointer or array objects */ + if (PyObject_IsSubclass(v->proto, typedict->proto)) { + Py_INCREF(value); + return value; + } + } + return CDataType_from_param(type, value); +} + +static PyMethodDef PointerType_methods[] = { + { "from_address", CDataType_from_address, METH_O, from_address_doc }, + { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc}, + { "from_param", (PyCFunction)PointerType_from_param, METH_O, from_param_doc}, + { "set_type", (PyCFunction)PointerType_set_type, METH_O }, + { NULL, NULL }, +}; + +PyTypeObject PointerType_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_ctypes.PointerType", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &CDataType_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + "metatype for the Pointer Objects", /* tp_doc */ + (traverseproc)CDataType_traverse, /* tp_traverse */ + (inquiry)CDataType_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PointerType_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PointerType_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/******************************************************************/ +/* + ArrayType_Type +*/ +/* + ArrayType_new ensures that the new Array subclass created has a _length_ + attribute, and a _type_ attribute. +*/ + +static int +CharArray_set_raw(CDataObject *self, PyObject *value) +{ + char *ptr; + Py_ssize_t size; + if (PyBuffer_Check(value)) { + size = value->ob_type->tp_as_buffer->bf_getreadbuffer(value, 0, (void *)&ptr); + if (size < 0) + return -1; + } else if (-1 == PyString_AsStringAndSize(value, &ptr, &size)) { + return -1; + } + if (size > self->b_size) { + PyErr_SetString(PyExc_ValueError, + "string too long"); + return -1; + } + + memcpy(self->b_ptr, ptr, size); + + return 0; +} + +static PyObject * +CharArray_get_raw(CDataObject *self) +{ + return PyString_FromStringAndSize(self->b_ptr, self->b_size); +} + +static PyObject * +CharArray_get_value(CDataObject *self) +{ + int i; + char *ptr = self->b_ptr; + for (i = 0; i < self->b_size; ++i) + if (*ptr++ == '\0') + break; + return PyString_FromStringAndSize(self->b_ptr, i); +} + +static int +CharArray_set_value(CDataObject *self, PyObject *value) +{ + char *ptr; + int size; + + if (PyUnicode_Check(value)) { + value = PyUnicode_AsEncodedString(value, + conversion_mode_encoding, + conversion_mode_errors); + if (!value) + return -1; + } else if (!PyString_Check(value)) { + PyErr_Format(PyExc_TypeError, + "string expected instead of %s instance", + value->ob_type->tp_name); + return -1; + } else + Py_INCREF(value); + size = PyString_GET_SIZE(value); + if (size > self->b_size) { + PyErr_SetString(PyExc_ValueError, + "string too long"); + Py_DECREF(value); + return -1; + } + + ptr = PyString_AS_STRING(value); + memcpy(self->b_ptr, ptr, size); + if (size < self->b_size) + self->b_ptr[size] = '\0'; + Py_DECREF(value); + + return 0; +} + +static PyGetSetDef CharArray_getsets[] = { + { "raw", (getter)CharArray_get_raw, (setter)CharArray_set_raw, + "value", NULL }, + { "value", (getter)CharArray_get_value, (setter)CharArray_set_value, + "string value"}, + { NULL, NULL } +}; + +#ifdef CTYPES_UNICODE +static PyObject * +WCharArray_get_value(CDataObject *self) +{ + unsigned int i; + wchar_t *ptr = (wchar_t *)self->b_ptr; + for (i = 0; i < self->b_size/sizeof(wchar_t); ++i) + if (*ptr++ == (wchar_t)0) + break; + return PyUnicode_FromWideChar((wchar_t *)self->b_ptr, i); +} + +static int +WCharArray_set_value(CDataObject *self, PyObject *value) +{ + int result = 0; + + if (PyString_Check(value)) { + value = PyUnicode_FromEncodedObject(value, + conversion_mode_encoding, + conversion_mode_errors); + if (!value) + return -1; + } else if (!PyUnicode_Check(value)) { + PyErr_Format(PyExc_TypeError, + "unicode string expected instead of %s instance", + value->ob_type->tp_name); + return -1; + } else + Py_INCREF(value); + if ((unsigned)PyUnicode_GET_SIZE(value) > self->b_size/sizeof(wchar_t)) { + PyErr_SetString(PyExc_ValueError, + "string too long"); + result = -1; + goto done; + } + result = PyUnicode_AsWideChar((PyUnicodeObject *)value, + (wchar_t *)self->b_ptr, + self->b_size/sizeof(wchar_t)); + if (result >= 0 && (unsigned)result < self->b_size/sizeof(wchar_t)) + ((wchar_t *)self->b_ptr)[result] = (wchar_t)0; + if (result > 0) + result = 0; + done: + Py_DECREF(value); + + return result; +} + +static PyGetSetDef WCharArray_getsets[] = { + { "value", (getter)WCharArray_get_value, (setter)WCharArray_set_value, + "string value"}, + { NULL, NULL } +}; +#endif + +/* + The next three functions copied from Python's typeobject.c. + + They are used to attach methods, members, or getsets to a type *after* it + has been created: Arrays of characters have additional getsets to treat them + as strings. + */ +/* +static int +add_methods(PyTypeObject *type, PyMethodDef *meth) +{ + PyObject *dict = type->tp_dict; + for (; meth->ml_name != NULL; meth++) { + PyObject *descr; + descr = PyDescr_NewMethod(type, meth); + if (descr == NULL) + return -1; + if (PyDict_SetItemString(dict,meth->ml_name, descr) < 0) + return -1; + Py_DECREF(descr); + } + return 0; +} + +static int +add_members(PyTypeObject *type, PyMemberDef *memb) +{ + PyObject *dict = type->tp_dict; + for (; memb->name != NULL; memb++) { + PyObject *descr; + descr = PyDescr_NewMember(type, memb); + if (descr == NULL) + return -1; + if (PyDict_SetItemString(dict, memb->name, descr) < 0) + return -1; + Py_DECREF(descr); + } + return 0; +} +*/ + +static int +add_getset(PyTypeObject *type, PyGetSetDef *gsp) +{ + PyObject *dict = type->tp_dict; + for (; gsp->name != NULL; gsp++) { + PyObject *descr; + descr = PyDescr_NewGetSet(type, gsp); + if (descr == NULL) + return -1; + if (PyDict_SetItemString(dict, gsp->name, descr) < 0) + return -1; + Py_DECREF(descr); + } + return 0; +} + +static PyCArgObject * +ArrayType_paramfunc(CDataObject *self) +{ + PyCArgObject *p = new_CArgObject(); + if (p == NULL) + return NULL; + p->tag = 'P'; + p->pffi_type = &ffi_type_pointer; + p->value.p = (char *)self->b_ptr; + Py_INCREF(self); + p->obj = (PyObject *)self; + return p; +} + +static PyObject * +ArrayType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyTypeObject *result; + StgDictObject *stgdict; + StgDictObject *itemdict; + PyObject *proto; + PyObject *typedict; + int length; + + int itemsize, itemalign; + + typedict = PyTuple_GetItem(args, 2); + if (!typedict) + return NULL; + + proto = PyDict_GetItemString(typedict, "_length_"); /* Borrowed ref */ + if (!proto || !PyInt_Check(proto)) { + PyErr_SetString(PyExc_AttributeError, + "class must define a '_length_' attribute, " + "which must be a positive integer"); + return NULL; + } + length = PyInt_AS_LONG(proto); + + proto = PyDict_GetItemString(typedict, "_type_"); /* Borrowed ref */ + if (!proto) { + PyErr_SetString(PyExc_AttributeError, + "class must define a '_type_' attribute"); + return NULL; + } + + stgdict = (StgDictObject *)PyObject_CallObject( + (PyObject *)&StgDict_Type, NULL); + if (!stgdict) + return NULL; + + itemdict = PyType_stgdict(proto); + if (!itemdict) { + PyErr_SetString(PyExc_TypeError, + "_type_ must have storage info"); + Py_DECREF((PyObject *)stgdict); + return NULL; + } + + itemsize = itemdict->size; + if (length * itemsize < 0) { + PyErr_SetString(PyExc_OverflowError, + "array too large"); + return NULL; + } + + itemalign = itemdict->align; + + stgdict->size = itemsize * length; + stgdict->align = itemalign; + stgdict->length = length; + Py_INCREF(proto); + stgdict->proto = proto; + + stgdict->paramfunc = &ArrayType_paramfunc; + + /* Arrays are passed as pointers to function calls. */ + stgdict->ffi_type_pointer = ffi_type_pointer; + + /* create the new instance (which is a class, + since we are a metatype!) */ + result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); + if (result == NULL) + return NULL; + + /* replace the class dict by our updated spam dict */ + if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { + Py_DECREF(result); + Py_DECREF((PyObject *)stgdict); + return NULL; + } + Py_DECREF(result->tp_dict); + result->tp_dict = (PyObject *)stgdict; + + /* Special case for character arrays. + A permanent annoyance: char arrays are also strings! + */ + if (itemdict->getfunc == getentry("c")->getfunc) { + if (-1 == add_getset(result, CharArray_getsets)) + return NULL; +#ifdef CTYPES_UNICODE + } else if (itemdict->getfunc == getentry("u")->getfunc) { + if (-1 == add_getset(result, WCharArray_getsets)) + return NULL; +#endif + } + + return (PyObject *)result; +} + +PyTypeObject ArrayType_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_ctypes.ArrayType", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &CDataType_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "metatype for the Array Objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CDataType_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + ArrayType_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/******************************************************************/ +/* + SimpleType_Type +*/ +/* + +SimpleType_new ensures that the new Simple_Type subclass created has a valid +_type_ attribute. + +*/ + +static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv"; + +static PyObject * +c_wchar_p_from_param(PyObject *type, PyObject *value) +{ + PyObject *as_parameter; +#if (PYTHON_API_VERSION < 1012) +# error not supported +#endif + if (value == Py_None) { + Py_INCREF(Py_None); + return Py_None; + } + if (PyUnicode_Check(value) || PyString_Check(value)) { + PyCArgObject *parg; + struct fielddesc *fd = getentry("Z"); + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'Z'; + parg->obj = fd->setfunc(&parg->value, value, 0); + if (parg->obj == NULL) { + Py_DECREF(parg); + return NULL; + } + return (PyObject *)parg; + } + if (PyObject_IsInstance(value, type)) { + Py_INCREF(value); + return value; + } + if (ArrayObject_Check(value) || PointerObject_Check(value)) { + /* c_wchar array instance or pointer(c_wchar(...)) */ + StgDictObject *dt = PyObject_stgdict(value); + StgDictObject *dict; + assert(dt); /* Cannot be NULL for pointer or array objects */ + dict = dt && dt->proto ? PyType_stgdict(dt->proto) : NULL; + if (dict && (dict->setfunc == getentry("u")->setfunc)) { + Py_INCREF(value); + return value; + } + } + if (PyCArg_CheckExact(value)) { + /* byref(c_char(...)) */ + PyCArgObject *a = (PyCArgObject *)value; + StgDictObject *dict = PyObject_stgdict(a->obj); + if (dict && (dict->setfunc == getentry("u")->setfunc)) { + Py_INCREF(value); + return value; + } + } + + as_parameter = PyObject_GetAttrString(value, "_as_parameter_"); + if (as_parameter) { + value = c_wchar_p_from_param(type, as_parameter); + Py_DECREF(as_parameter); + return value; + } + /* XXX better message */ + PyErr_SetString(PyExc_TypeError, + "wrong type"); + return NULL; +} + +static PyObject * +c_char_p_from_param(PyObject *type, PyObject *value) +{ + PyObject *as_parameter; +#if (PYTHON_API_VERSION < 1012) +# error not supported +#endif + if (value == Py_None) { + Py_INCREF(Py_None); + return Py_None; + } + if (PyString_Check(value) || PyUnicode_Check(value)) { + PyCArgObject *parg; + struct fielddesc *fd = getentry("z"); + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'z'; + parg->obj = fd->setfunc(&parg->value, value, 0); + if (parg->obj == NULL) { + Py_DECREF(parg); + return NULL; + } + return (PyObject *)parg; + } + if (PyObject_IsInstance(value, type)) { + Py_INCREF(value); + return value; + } + if (ArrayObject_Check(value) || PointerObject_Check(value)) { + /* c_char array instance or pointer(c_char(...)) */ + StgDictObject *dt = PyObject_stgdict(value); + StgDictObject *dict; + assert(dt); /* Cannot be NULL for pointer or array objects */ + dict = dt && dt->proto ? PyType_stgdict(dt->proto) : NULL; + if (dict && (dict->setfunc == getentry("c")->setfunc)) { + Py_INCREF(value); + return value; + } + } + if (PyCArg_CheckExact(value)) { + /* byref(c_char(...)) */ + PyCArgObject *a = (PyCArgObject *)value; + StgDictObject *dict = PyObject_stgdict(a->obj); + if (dict && (dict->setfunc == getentry("c")->setfunc)) { + Py_INCREF(value); + return value; + } + } + + as_parameter = PyObject_GetAttrString(value, "_as_parameter_"); + if (as_parameter) { + value = c_char_p_from_param(type, as_parameter); + Py_DECREF(as_parameter); + return value; + } + /* XXX better message */ + PyErr_SetString(PyExc_TypeError, + "wrong type"); + return NULL; +} + +static PyObject * +c_void_p_from_param(PyObject *type, PyObject *value) +{ + StgDictObject *stgd; + PyObject *as_parameter; +#if (PYTHON_API_VERSION < 1012) +# error not supported +#endif + +/* None */ + if (value == Py_None) { + Py_INCREF(Py_None); + return Py_None; + } + /* Should probably allow buffer interface as well */ +/* int, long */ + if (PyInt_Check(value) || PyLong_Check(value)) { + PyCArgObject *parg; + struct fielddesc *fd = getentry("P"); + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'P'; + parg->obj = fd->setfunc(&parg->value, value, 0); + if (parg->obj == NULL) { + Py_DECREF(parg); + return NULL; + } + return (PyObject *)parg; + } +/* string */ + if (PyString_Check(value)) { + PyCArgObject *parg; + struct fielddesc *fd = getentry("z"); + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'z'; + parg->obj = fd->setfunc(&parg->value, value, 0); + if (parg->obj == NULL) { + Py_DECREF(parg); + return NULL; + } + return (PyObject *)parg; + } +/* unicode */ + if (PyUnicode_Check(value)) { + PyCArgObject *parg; + struct fielddesc *fd = getentry("Z"); + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'Z'; + parg->obj = fd->setfunc(&parg->value, value, 0); + if (parg->obj == NULL) { + Py_DECREF(parg); + return NULL; + } + return (PyObject *)parg; + } +/* c_void_p instance (or subclass) */ + if (PyObject_IsInstance(value, type)) { + /* c_void_p instances */ + Py_INCREF(value); + return value; + } +/* ctypes array or pointer instance */ + if (ArrayObject_Check(value) || PointerObject_Check(value)) { + /* Any array or pointer is accepted */ + Py_INCREF(value); + return value; + } +/* byref(...) */ + if (PyCArg_CheckExact(value)) { + /* byref(c_xxx()) */ + PyCArgObject *a = (PyCArgObject *)value; + if (a->tag == 'P') { + Py_INCREF(value); + return value; + } + } +/* function pointer */ + if (CFuncPtrObject_Check(value)) { + PyCArgObject *parg; + CFuncPtrObject *func; + func = (CFuncPtrObject *)value; + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'P'; + Py_INCREF(value); + parg->value.p = *(void **)func->b_ptr; + parg->obj = value; + return (PyObject *)parg; + } +/* c_char_p, c_wchar_p */ + stgd = PyObject_stgdict(value); + if (stgd && CDataObject_Check(value) && stgd->proto && PyString_Check(stgd->proto)) { + PyCArgObject *parg; + + switch (PyString_AS_STRING(stgd->proto)[0]) { + case 'z': /* c_char_p */ + case 'Z': /* c_wchar_p */ + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + parg->pffi_type = &ffi_type_pointer; + parg->tag = 'Z'; + Py_INCREF(value); + parg->obj = value; + /* Remember: b_ptr points to where the pointer is stored! */ + parg->value.p = *(void **)(((CDataObject *)value)->b_ptr); + return (PyObject *)parg; + } + } + + as_parameter = PyObject_GetAttrString(value, "_as_parameter_"); + if (as_parameter) { + value = c_void_p_from_param(type, as_parameter); + Py_DECREF(as_parameter); + return value; + } + /* XXX better message */ + PyErr_SetString(PyExc_TypeError, + "wrong type"); + return NULL; +} +#if (PYTHON_API_VERSION >= 1012) + +static PyMethodDef c_void_p_method = { "from_param", c_void_p_from_param, METH_O }; +static PyMethodDef c_char_p_method = { "from_param", c_char_p_from_param, METH_O }; +static PyMethodDef c_wchar_p_method = { "from_param", c_wchar_p_from_param, METH_O }; + +#else +#error +static PyMethodDef c_void_p_method = { "from_param", c_void_p_from_param, METH_VARARGS }; +static PyMethodDef c_char_p_method = { "from_param", c_char_p_from_param, METH_VARARGS }; +static PyMethodDef c_wchar_p_method = { "from_param", c_wchar_p_from_param, METH_VARARGS }; + +#endif + +static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject *kwds, + PyObject *proto, struct fielddesc *fmt) +{ + PyTypeObject *result; + StgDictObject *stgdict; + PyObject *name = PyTuple_GET_ITEM(args, 0); + PyObject *swapped_args; + static PyObject *suffix; + Py_ssize_t i; + + swapped_args = PyTuple_New(PyTuple_GET_SIZE(args)); + if (!swapped_args) + return NULL; + + if (suffix == NULL) +#ifdef WORDS_BIGENDIAN + suffix = PyString_FromString("_le"); +#else + suffix = PyString_FromString("_be"); +#endif + + Py_INCREF(name); + PyString_Concat(&name, suffix); + if (name == NULL) + return NULL; + + PyTuple_SET_ITEM(swapped_args, 0, name); + for (i=1; i<PyTuple_GET_SIZE(args); ++i) { + PyObject *v = PyTuple_GET_ITEM(args, i); + Py_INCREF(v); + PyTuple_SET_ITEM(swapped_args, i, v); + } + + /* create the new instance (which is a class, + since we are a metatype!) */ + result = (PyTypeObject *)PyType_Type.tp_new(type, swapped_args, kwds); + Py_DECREF(swapped_args); + if (result == NULL) + return NULL; + + stgdict = (StgDictObject *)PyObject_CallObject( + (PyObject *)&StgDict_Type, NULL); + if (!stgdict) /* XXX leaks result! */ + return NULL; + + stgdict->ffi_type_pointer = *fmt->pffi_type; + stgdict->align = fmt->pffi_type->alignment; + stgdict->length = 0; + stgdict->size = fmt->pffi_type->size; + stgdict->setfunc = fmt->setfunc_swapped; + stgdict->getfunc = fmt->getfunc_swapped; + + Py_INCREF(proto); + stgdict->proto = proto; + + /* replace the class dict by our updated spam dict */ + if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { + Py_DECREF(result); + Py_DECREF((PyObject *)stgdict); + return NULL; + } + Py_DECREF(result->tp_dict); + result->tp_dict = (PyObject *)stgdict; + + return (PyObject *)result; +} + +static PyCArgObject * +SimpleType_paramfunc(CDataObject *self) +{ + StgDictObject *dict; + char *fmt; + PyCArgObject *parg; + struct fielddesc *fd; + + dict = PyObject_stgdict((PyObject *)self); + assert(dict); /* Cannot be NULL for CDataObject instances */ + fmt = PyString_AsString(dict->proto); + assert(fmt); + + fd = getentry(fmt); + assert(fd); + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + + parg->tag = fmt[0]; + parg->pffi_type = fd->pffi_type; + Py_INCREF(self); + parg->obj = (PyObject *)self; + memcpy(&parg->value, self->b_ptr, self->b_size); + return parg; +} + +static PyObject * +SimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyTypeObject *result; + StgDictObject *stgdict; + PyObject *proto; + PyMethodDef *ml; + struct fielddesc *fmt; + + /* create the new instance (which is a class, + since we are a metatype!) */ + result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); + if (result == NULL) + return NULL; + + proto = PyObject_GetAttrString((PyObject *)result, "_type_"); /* new ref */ + if (!proto + || !PyString_Check(proto) + || 1 != strlen(PyString_AS_STRING(proto)) + || !strchr(SIMPLE_TYPE_CHARS, PyString_AS_STRING(proto)[0])) { + PyErr_Format(PyExc_AttributeError, + "class must define a '_type_' attribute which must be\n" + "a single character string containing one of '%s'.", + SIMPLE_TYPE_CHARS); + Py_XDECREF(proto); + Py_DECREF(result); + return NULL; + } + fmt = getentry(PyString_AS_STRING(proto)); + if (fmt == NULL) { + Py_DECREF(result); + PyErr_Format(PyExc_ValueError, + "_type_ '%s' not supported", + PyString_AS_STRING(proto)); + return NULL; + } + + stgdict = (StgDictObject *)PyObject_CallObject( + (PyObject *)&StgDict_Type, NULL); + if (!stgdict) + return NULL; + + stgdict->ffi_type_pointer = *fmt->pffi_type; + stgdict->align = fmt->pffi_type->alignment; + stgdict->length = 0; + stgdict->size = fmt->pffi_type->size; + stgdict->setfunc = fmt->setfunc; + stgdict->getfunc = fmt->getfunc; + + stgdict->paramfunc = SimpleType_paramfunc; +/* + if (result->tp_base != &Simple_Type) { + stgdict->setfunc = NULL; + stgdict->getfunc = NULL; + } +*/ + + /* This consumes the refcount on proto which we have */ + stgdict->proto = proto; + + /* replace the class dict by our updated spam dict */ + if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { + Py_DECREF(result); + Py_DECREF((PyObject *)stgdict); + return NULL; + } + Py_DECREF(result->tp_dict); + result->tp_dict = (PyObject *)stgdict; + + /* Install from_param class methods in ctypes base classes. + Overrides the SimpleType_from_param generic method. + */ + if (result->tp_base == &Simple_Type) { + switch (PyString_AS_STRING(proto)[0]) { + case 'z': /* c_char_p */ + ml = &c_char_p_method; + break; + case 'Z': /* c_wchar_p */ + ml = &c_wchar_p_method; + break; + case 'P': /* c_void_p */ + ml = &c_void_p_method; + break; + default: + ml = NULL; + break; + } + + if (ml) { +#if (PYTHON_API_VERSION >= 1012) + PyObject *meth; + int x; + meth = PyDescr_NewClassMethod(result, ml); + if (!meth) + return NULL; +#else +#error + PyObject *meth, *func; + int x; + func = PyCFunction_New(ml, NULL); + if (!func) + return NULL; + meth = PyObject_CallFunctionObjArgs( + (PyObject *)&PyClassMethod_Type, + func, NULL); + Py_DECREF(func); + if (!meth) { + return NULL; + } +#endif + x = PyDict_SetItemString(result->tp_dict, + ml->ml_name, + meth); + Py_DECREF(meth); + if (x == -1) { + Py_DECREF(result); + return NULL; + } + } + } + + if (type == &SimpleType_Type && fmt->setfunc_swapped && fmt->getfunc_swapped) { + PyObject *swapped = CreateSwappedType(type, args, kwds, + proto, fmt); + if (swapped == NULL) { + Py_DECREF(result); + return NULL; + } +#ifdef WORDS_BIGENDIAN + PyObject_SetAttrString((PyObject *)result, "__ctype_le__", swapped); + PyObject_SetAttrString((PyObject *)result, "__ctype_be__", (PyObject *)result); + PyObject_SetAttrString(swapped, "__ctype_be__", (PyObject *)result); + PyObject_SetAttrString(swapped, "__ctype_le__", swapped); +#else + PyObject_SetAttrString((PyObject *)result, "__ctype_be__", swapped); + PyObject_SetAttrString((PyObject *)result, "__ctype_le__", (PyObject *)result); + PyObject_SetAttrString(swapped, "__ctype_le__", (PyObject *)result); + PyObject_SetAttrString(swapped, "__ctype_be__", swapped); +#endif + Py_DECREF(swapped); + }; + + return (PyObject *)result; +} + +/* + * This is a *class method*. + * Convert a parameter into something that ConvParam can handle. + */ +static PyObject * +SimpleType_from_param(PyObject *type, PyObject *value) +{ + StgDictObject *dict; + char *fmt; + PyCArgObject *parg; + struct fielddesc *fd; + PyObject *as_parameter; + + /* If the value is already an instance of the requested type, + we can use it as is */ + if (1 == PyObject_IsInstance(value, type)) { + Py_INCREF(value); + return value; + } + + dict = PyType_stgdict(type); + assert(dict); + + /* I think we can rely on this being a one-character string */ + fmt = PyString_AsString(dict->proto); + assert(fmt); + + fd = getentry(fmt); + assert(fd); + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + + parg->tag = fmt[0]; + parg->pffi_type = fd->pffi_type; + parg->obj = fd->setfunc(&parg->value, value, 0); + if (parg->obj) + return (PyObject *)parg; + PyErr_Clear(); + Py_DECREF(parg); + + as_parameter = PyObject_GetAttrString(value, "_as_parameter_"); + if (as_parameter) { + value = SimpleType_from_param(type, as_parameter); + Py_DECREF(as_parameter); + return value; + } + PyErr_SetString(PyExc_TypeError, + "wrong type"); + return NULL; +} + +static PyMethodDef SimpleType_methods[] = { + { "from_param", SimpleType_from_param, METH_O, from_param_doc }, + { "from_address", CDataType_from_address, METH_O, from_address_doc }, + { "in_dll", CDataType_in_dll, METH_VARARGS, in_dll_doc}, + { NULL, NULL }, +}; + +PyTypeObject SimpleType_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_ctypes.SimpleType", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &CDataType_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "metatype for the SimpleType Objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + SimpleType_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + SimpleType_new, /* tp_new */ + 0, /* tp_free */ +}; + +/******************************************************************/ +/* + CFuncPtrType_Type + */ + +static PyObject * +converters_from_argtypes(PyObject *ob) +{ + PyObject *converters; + int i; + int nArgs; + + ob = PySequence_Tuple(ob); /* new reference */ + if (!ob) { + PyErr_SetString(PyExc_TypeError, + "_argtypes_ must be a sequence of types"); + return NULL; + } + + nArgs = PyTuple_GET_SIZE(ob); + converters = PyTuple_New(nArgs); + if (!converters) + return NULL; + + /* I have to check if this is correct. Using c_char, which has a size + of 1, will be assumed to be pushed as only one byte! + Aren't these promoted to integers by the C compiler and pushed as 4 bytes? + */ + + for (i = 0; i < nArgs; ++i) { + PyObject *tp = PyTuple_GET_ITEM(ob, i); + PyObject *cnv = PyObject_GetAttrString(tp, "from_param"); + if (!cnv) + goto argtypes_error_1; + PyTuple_SET_ITEM(converters, i, cnv); + } + Py_DECREF(ob); + return converters; + + argtypes_error_1: + Py_XDECREF(converters); + Py_DECREF(ob); + PyErr_Format(PyExc_TypeError, + "item %d in _argtypes_ has no from_param method", i+1); + return NULL; +} + +static int +make_funcptrtype_dict(StgDictObject *stgdict) +{ + PyObject *ob; + PyObject *converters = NULL; + + stgdict->align = getentry("P")->pffi_type->alignment; + stgdict->length = 1; + stgdict->size = sizeof(void *); + stgdict->setfunc = NULL; + stgdict->getfunc = NULL; + stgdict->ffi_type_pointer = ffi_type_pointer; + + ob = PyDict_GetItemString((PyObject *)stgdict, "_flags_"); + if (!ob || !PyInt_Check(ob)) { + PyErr_SetString(PyExc_TypeError, + "class must define _flags_ which must be an integer"); + return -1; + } + stgdict->flags = PyInt_AS_LONG(ob); + + /* _argtypes_ is optional... */ + ob = PyDict_GetItemString((PyObject *)stgdict, "_argtypes_"); + if (ob) { + converters = converters_from_argtypes(ob); + if (!converters) + goto error; + Py_INCREF(ob); + stgdict->argtypes = ob; + stgdict->converters = converters; + } + + ob = PyDict_GetItemString((PyObject *)stgdict, "_restype_"); + if (ob) { + if (ob != Py_None && !PyType_stgdict(ob) && !PyCallable_Check(ob)) { + PyErr_SetString(PyExc_TypeError, + "_restype_ must be a type, a callable, or None"); + return -1; + } + Py_INCREF(ob); + stgdict->restype = ob; + stgdict->checker = PyObject_GetAttrString(ob, "_check_retval_"); + if (stgdict->checker == NULL) + PyErr_Clear(); + } +/* XXX later, maybe. + ob = PyDict_GetItemString((PyObject *)stgdict, "_errcheck_"); + if (ob) { + if (!PyCallable_Check(ob)) { + PyErr_SetString(PyExc_TypeError, + "_errcheck_ must be callable"); + return -1; + } + Py_INCREF(ob); + stgdict->errcheck = ob; + } +*/ + return 0; + + error: + Py_XDECREF(converters); + return -1; + +} + +static PyCArgObject * +CFuncPtrType_paramfunc(CDataObject *self) +{ + PyCArgObject *parg; + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + + parg->tag = 'P'; + parg->pffi_type = &ffi_type_pointer; + Py_INCREF(self); + parg->obj = (PyObject *)self; + parg->value.p = *(void **)self->b_ptr; + return parg; +} + +static PyObject * +CFuncPtrType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyTypeObject *result; + StgDictObject *stgdict; + + stgdict = (StgDictObject *)PyObject_CallObject( + (PyObject *)&StgDict_Type, NULL); + if (!stgdict) + return NULL; + + stgdict->paramfunc = CFuncPtrType_paramfunc; + + /* create the new instance (which is a class, + since we are a metatype!) */ + result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); + if (result == NULL) { + Py_DECREF((PyObject *)stgdict); + return NULL; + } + + /* replace the class dict by our updated storage dict */ + if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { + Py_DECREF(result); + Py_DECREF((PyObject *)stgdict); + return NULL; + } + Py_DECREF(result->tp_dict); + result->tp_dict = (PyObject *)stgdict; + + if (-1 == make_funcptrtype_dict(stgdict)) { + Py_DECREF(result); + return NULL; + } + + return (PyObject *)result; +} + +PyTypeObject CFuncPtrType_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_ctypes.CFuncPtrType", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &CDataType_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + "metatype for C function pointers", /* tp_doc */ + (traverseproc)CDataType_traverse, /* tp_traverse */ + (inquiry)CDataType_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CDataType_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + CFuncPtrType_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/***************************************************************** + * Code to keep needed objects alive + */ + +static CDataObject * +CData_GetContainer(CDataObject *self) +{ + while (self->b_base) + self = self->b_base; + if (self->b_objects == NULL) { + if (self->b_length) { + self->b_objects = PyDict_New(); + } else { + Py_INCREF(Py_None); + self->b_objects = Py_None; + } + } + return self; +} + +static PyObject * +GetKeepedObjects(CDataObject *target) +{ + return CData_GetContainer(target)->b_objects; +} + +static PyObject * +unique_key(CDataObject *target, Py_ssize_t index) +{ + char string[256]; + char *cp = string; + size_t bytes_left; + + assert(sizeof(string) - 1 > sizeof(Py_ssize_t) * 2); +#if (PY_VERSION_HEX < 0x02050000) + cp += sprintf(cp, "%x", index); +#else + cp += sprintf(cp, "%x", Py_SAFE_DOWNCAST(index, Py_ssize_t, int)); +#endif + while (target->b_base) { + bytes_left = sizeof(string) - (cp - string) - 1; + /* Hex format needs 2 characters per byte */ + if (bytes_left < sizeof(Py_ssize_t) * 2) { + PyErr_SetString(PyExc_ValueError, + "ctypes object structure too deep"); + return NULL; + } +#if (PY_VERSION_HEX < 0x02050000) + cp += sprintf(cp, ":%x", (int)target->b_index); +#else + cp += sprintf(cp, ":%x", Py_SAFE_DOWNCAST(target->b_index, Py_ssize_t, int)); +#endif + target = target->b_base; + } + return PyString_FromStringAndSize(string, cp-string); +} + +/* + * Keep a reference to 'keep' in the 'target', at index 'index'. + * + * If 'keep' is None, do nothing. + * + * Otherwise create a dictionary (if it does not yet exist) id the root + * objects 'b_objects' item, which will store the 'keep' object under a unique + * key. + * + * The unique_key helper travels the target's b_base pointer down to the root, + * building a string containing hex-formatted indexes found during traversal, + * separated by colons. + * + * The index tuple is used as a key into the root object's b_objects dict. + * + * Note: This function steals a refcount of the third argument, even if it + * fails! + */ +static int +KeepRef(CDataObject *target, Py_ssize_t index, PyObject *keep) +{ + int result; + CDataObject *ob; + PyObject *key; + +/* Optimization: no need to store None */ + if (keep == Py_None) { + Py_DECREF(Py_None); + return 0; + } + ob = CData_GetContainer(target); + if (ob->b_objects == NULL || !PyDict_Check(ob->b_objects)) { + Py_XDECREF(ob->b_objects); + ob->b_objects = keep; /* refcount consumed */ + return 0; + } + key = unique_key(target, index); + if (key == NULL) { + Py_DECREF(keep); + return -1; + } + result = PyDict_SetItem(ob->b_objects, key, keep); + Py_DECREF(key); + Py_DECREF(keep); + return result; +} + +/******************************************************************/ +/* + CData_Type + */ +static int +CData_traverse(CDataObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->b_objects); + Py_VISIT((PyObject *)self->b_base); + return 0; +} + +static int +CData_clear(CDataObject *self) +{ + StgDictObject *dict = PyObject_stgdict((PyObject *)self); + assert(dict); /* Cannot be NULL for CDataObject instances */ + Py_CLEAR(self->b_objects); + if ((self->b_needsfree) + && ((size_t)dict->size > sizeof(self->b_value))) + PyMem_Free(self->b_ptr); + self->b_ptr = NULL; + Py_CLEAR(self->b_base); + return 0; +} + +static void +CData_dealloc(PyObject *self) +{ + CData_clear((CDataObject *)self); + self->ob_type->tp_free(self); +} + +static PyMemberDef CData_members[] = { + { "_b_base_", T_OBJECT, + offsetof(CDataObject, b_base), READONLY, + "the base object" }, + { "_b_needsfree_", T_INT, + offsetof(CDataObject, b_needsfree), READONLY, + "whether the object owns the memory or not" }, + { "_objects", T_OBJECT, + offsetof(CDataObject, b_objects), READONLY, + "internal objects tree (NEVER CHANGE THIS OBJECT!)"}, + { NULL }, +}; + +static Py_ssize_t CData_GetBuffer(PyObject *_self, Py_ssize_t seg, void **pptr) +{ + CDataObject *self = (CDataObject *)_self; + if (seg != 0) { + /* Hm. Must this set an exception? */ + return -1; + } + *pptr = self->b_ptr; + return self->b_size; +} + +static Py_ssize_t CData_GetSegcount(PyObject *_self, Py_ssize_t *lenp) +{ + if (lenp) + *lenp = 1; + return 1; +} + +static PyBufferProcs CData_as_buffer = { + CData_GetBuffer, + CData_GetBuffer, + CData_GetSegcount, + NULL, +}; + +/* + * CData objects are mutable, so they cannot be hashable! + */ +static long +CData_nohash(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "unhashable type"); + return -1; +} + +/* + * default __ctypes_from_outparam__ method returns self. + */ +static PyObject * +CData_from_outparam(PyObject *self, PyObject *args) +{ + Py_INCREF(self); + return self; +} + +static PyMethodDef CData_methods[] = { + { "__ctypes_from_outparam__", CData_from_outparam, METH_NOARGS, }, + { NULL, NULL }, +}; + +PyTypeObject CData_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "_ctypes._CData", + sizeof(CDataObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + CData_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + CData_nohash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &CData_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "XXX to be provided", /* tp_doc */ + (traverseproc)CData_traverse, /* tp_traverse */ + (inquiry)CData_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + CData_methods, /* tp_methods */ + CData_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ +}; + +static int CData_MallocBuffer(CDataObject *obj, StgDictObject *dict) +{ + if ((size_t)dict->size <= sizeof(obj->b_value)) { + /* No need to call malloc, can use the default buffer */ + obj->b_ptr = (char *)&obj->b_value; + /* The b_needsfree flag does not mean that we actually did + call PyMem_Malloc to allocate the memory block; instead it + means we are the *owner* of the memory and are responsible + for freeing resources associated with the memory. This is + also the reason that b_needsfree is exposed to Python. + */ + obj->b_needsfree = 1; + } else { + /* In python 2.4, and ctypes 0.9.6, the malloc call took about + 33% of the creation time for c_int(). + */ + obj->b_ptr = (char *)PyMem_Malloc(dict->size); + if (obj->b_ptr == NULL) { + PyErr_NoMemory(); + return -1; + } + obj->b_needsfree = 1; + memset(obj->b_ptr, 0, dict->size); + } + obj->b_size = dict->size; + return 0; +} + +PyObject * +CData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr) +{ + CDataObject *cmem; + StgDictObject *dict; + + assert(PyType_Check(type)); + dict = PyType_stgdict(type); + if (!dict) { + PyErr_SetString(PyExc_TypeError, + "abstract class"); + return NULL; + } + dict->flags |= DICTFLAG_FINAL; + cmem = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); + if (cmem == NULL) + return NULL; + assert(CDataObject_Check(cmem)); + + cmem->b_length = dict->length; + cmem->b_size = dict->size; + if (base) { /* use base's buffer */ + assert(CDataObject_Check(base)); + cmem->b_ptr = adr; + cmem->b_needsfree = 0; + Py_INCREF(base); + cmem->b_base = (CDataObject *)base; + cmem->b_index = index; + } else { /* copy contents of adr */ + if (-1 == CData_MallocBuffer(cmem, dict)) { + return NULL; + Py_DECREF(cmem); + } + memcpy(cmem->b_ptr, adr, dict->size); + cmem->b_index = index; + } + return (PyObject *)cmem; +} + +/* + Box a memory block into a CData instance. +*/ +PyObject * +CData_AtAddress(PyObject *type, void *buf) +{ + CDataObject *pd; + StgDictObject *dict; + + assert(PyType_Check(type)); + dict = PyType_stgdict(type); + if (!dict) { + PyErr_SetString(PyExc_TypeError, + "abstract class"); + return NULL; + } + dict->flags |= DICTFLAG_FINAL; + + pd = (CDataObject *)((PyTypeObject *)type)->tp_alloc((PyTypeObject *)type, 0); + if (!pd) + return NULL; + assert(CDataObject_Check(pd)); + pd->b_ptr = (char *)buf; + pd->b_length = dict->length; + pd->b_size = dict->size; + return (PyObject *)pd; +} + +/* + This function returns TRUE for c_int, c_void_p, and these kind of + classes. FALSE otherwise FALSE also for subclasses of c_int and + such. +*/ +int IsSimpleSubType(PyObject *obj) +{ + PyTypeObject *type = (PyTypeObject *)obj; + + if (SimpleTypeObject_Check(type)) + return type->tp_base != &Simple_Type; + return 0; +} + +PyObject * +CData_get(PyObject *type, GETFUNC getfunc, PyObject *src, + Py_ssize_t index, Py_ssize_t size, char *adr) +{ + StgDictObject *dict; + if (getfunc) + return getfunc(adr, size); + assert(type); + dict = PyType_stgdict(type); + if (dict && dict->getfunc && !IsSimpleSubType(type)) + return dict->getfunc(adr, size); + return CData_FromBaseObj(type, src, index, adr); +} + +/* + Helper function for CData_set below. +*/ +static PyObject * +_CData_set(CDataObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, + Py_ssize_t size, char *ptr) +{ + CDataObject *src; + + if (setfunc) + return setfunc(ptr, value, size); + + if (!CDataObject_Check(value)) { + StgDictObject *dict = PyType_stgdict(type); + if (dict && dict->setfunc) + return dict->setfunc(ptr, value, size); + /* + If value is a tuple, we try to call the type with the tuple + and use the result! + */ + assert(PyType_Check(type)); + if (PyTuple_Check(value)) { + PyObject *ob; + PyObject *result; + ob = PyObject_CallObject(type, value); + if (ob == NULL) { + Extend_Error_Info(PyExc_RuntimeError, "(%s) ", + ((PyTypeObject *)type)->tp_name); + return NULL; + } + result = _CData_set(dst, type, setfunc, ob, + size, ptr); + Py_DECREF(ob); + return result; + } else if (value == Py_None && PointerTypeObject_Check(type)) { + *(void **)ptr = NULL; + Py_INCREF(Py_None); + return Py_None; + } else { + PyErr_Format(PyExc_TypeError, + "expected %s instance, got %s", + ((PyTypeObject *)type)->tp_name, + value->ob_type->tp_name); + return NULL; + } + } + src = (CDataObject *)value; + + if (PyObject_IsInstance(value, type)) { + memcpy(ptr, + src->b_ptr, + size); + + if (PointerTypeObject_Check(type)) + /* XXX */; + + value = GetKeepedObjects(src); + Py_INCREF(value); + return value; + } + + if (PointerTypeObject_Check(type) + && ArrayObject_Check(value)) { + StgDictObject *p1, *p2; + PyObject *keep; + p1 = PyObject_stgdict(value); + assert(p1); /* Cannot be NULL for array instances */ + p2 = PyType_stgdict(type); + assert(p2); /* Cannot be NULL for pointer types */ + + if (p1->proto != p2->proto) { + PyErr_Format(PyExc_TypeError, + "incompatible types, %s instance instead of %s instance", + value->ob_type->tp_name, + ((PyTypeObject *)type)->tp_name); + return NULL; + } + *(void **)ptr = src->b_ptr; + + keep = GetKeepedObjects(src); + /* + We are assigning an array object to a field which represents + a pointer. This has the same effect as converting an array + into a pointer. So, again, we have to keep the whole object + pointed to (which is the array in this case) alive, and not + only it's object list. So we create a tuple, containing + b_objects list PLUS the array itself, and return that! + */ + return Py_BuildValue("(OO)", keep, value); + } + PyErr_Format(PyExc_TypeError, + "incompatible types, %s instance instead of %s instance", + value->ob_type->tp_name, + ((PyTypeObject *)type)->tp_name); + return NULL; +} + +/* + * Set a slice in object 'dst', which has the type 'type', + * to the value 'value'. + */ +int +CData_set(PyObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, + Py_ssize_t index, Py_ssize_t size, char *ptr) +{ + CDataObject *mem = (CDataObject *)dst; + PyObject *result; + + if (!CDataObject_Check(dst)) { + PyErr_SetString(PyExc_TypeError, + "not a ctype instance"); + return -1; + } + + result = _CData_set(mem, type, setfunc, value, + size, ptr); + if (result == NULL) + return -1; + + /* KeepRef steals a refcount from it's last argument */ + /* If KeepRef fails, we are stumped. The dst memory block has already + been changed */ + return KeepRef(mem, index, result); +} + + +/******************************************************************/ +static PyObject * +GenericCData_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CDataObject *obj; + StgDictObject *dict; + + dict = PyType_stgdict((PyObject *)type); + if (!dict) { + PyErr_SetString(PyExc_TypeError, + "abstract class"); + return NULL; + } + dict->flags |= DICTFLAG_FINAL; + + obj = (CDataObject *)type->tp_alloc(type, 0); + if (!obj) + return NULL; + + obj->b_base = NULL; + obj->b_index = 0; + obj->b_objects = NULL; + obj->b_length = dict->length; + + if (-1 == CData_MallocBuffer(obj, dict)) { + Py_DECREF(obj); + return NULL; + } + return (PyObject *)obj; +} +/*****************************************************************/ +/* + CFuncPtr_Type +*/ + +static int +CFuncPtr_set_errcheck(CFuncPtrObject *self, PyObject *ob) +{ + if (ob && !PyCallable_Check(ob)) { + PyErr_SetString(PyExc_TypeError, + "the errcheck attribute must be callable"); + return -1; + } + Py_XDECREF(self->errcheck); + Py_XINCREF(ob); + self->errcheck = ob; + return 0; +} + +static PyObject * +CFuncPtr_get_errcheck(CFuncPtrObject *self) +{ + if (self->errcheck) { + Py_INCREF(self->errcheck); + return self->errcheck; + } + Py_INCREF(Py_None); + return Py_None; +} + +static int +CFuncPtr_set_restype(CFuncPtrObject *self, PyObject *ob) +{ + if (ob == NULL) { + Py_XDECREF(self->restype); + self->restype = NULL; + Py_XDECREF(self->checker); + self->checker = NULL; + return 0; + } + if (ob != Py_None && !PyType_stgdict(ob) && !PyCallable_Check(ob)) { + PyErr_SetString(PyExc_TypeError, + "restype must be a type, a callable, or None"); + return -1; + } + Py_XDECREF(self->checker); + Py_XDECREF(self->restype); + Py_INCREF(ob); + self->restype = ob; + self->checker = PyObject_GetAttrString(ob, "_check_retval_"); + if (self->checker == NULL) + PyErr_Clear(); + return 0; +} + +static PyObject * +CFuncPtr_get_restype(CFuncPtrObject *self) +{ + StgDictObject *dict; + if (self->restype) { + Py_INCREF(self->restype); + return self->restype; + } + dict = PyObject_stgdict((PyObject *)self); + assert(dict); /* Cannot be NULL for CFuncPtrObject instances */ + if (dict->restype) { + Py_INCREF(dict->restype); + return dict->restype; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} + +static int +CFuncPtr_set_argtypes(CFuncPtrObject *self, PyObject *ob) +{ + PyObject *converters; + + if (ob == NULL || ob == Py_None) { + Py_XDECREF(self->converters); + self->converters = NULL; + Py_XDECREF(self->argtypes); + self->argtypes = NULL; + } else { + converters = converters_from_argtypes(ob); + if (!converters) + return -1; + Py_XDECREF(self->converters); + self->converters = converters; + Py_XDECREF(self->argtypes); + Py_INCREF(ob); + self->argtypes = ob; + } + return 0; +} + +static PyObject * +CFuncPtr_get_argtypes(CFuncPtrObject *self) +{ + StgDictObject *dict; + if (self->argtypes) { + Py_INCREF(self->argtypes); + return self->argtypes; + } + dict = PyObject_stgdict((PyObject *)self); + assert(dict); /* Cannot be NULL for CFuncPtrObject instances */ + if (dict->argtypes) { + Py_INCREF(dict->argtypes); + return dict->argtypes; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} + +static PyGetSetDef CFuncPtr_getsets[] = { + { "errcheck", (getter)CFuncPtr_get_errcheck, (setter)CFuncPtr_set_errcheck, + "a function to check for errors", NULL }, + { "restype", (getter)CFuncPtr_get_restype, (setter)CFuncPtr_set_restype, + "specify the result type", NULL }, + { "argtypes", (getter)CFuncPtr_get_argtypes, + (setter)CFuncPtr_set_argtypes, + "specify the argument types", NULL }, + { NULL, NULL } +}; + +#ifdef MS_WIN32 +static PPROC FindAddress(void *handle, char *name, PyObject *type) +{ + PPROC address; + char *mangled_name; + int i; + StgDictObject *dict = PyType_stgdict((PyObject *)type); + + address = (PPROC)GetProcAddress(handle, name); + if (address) + return address; + + if (((size_t)name & ~0xFFFF) == 0) { + return NULL; + } + + /* It should not happen that dict is NULL, but better be safe */ + if (dict==NULL || dict->flags & FUNCFLAG_CDECL) + return address; + + /* for stdcall, try mangled names: + funcname -> _funcname@<n> + where n is 0, 4, 8, 12, ..., 128 + */ + mangled_name = alloca(strlen(name) + 1 + 1 + 1 + 3); /* \0 _ @ %d */ + if (!mangled_name) + return NULL; + for (i = 0; i < 32; ++i) { + sprintf(mangled_name, "_%s@%d", name, i*4); + address = (PPROC)GetProcAddress(handle, mangled_name); + if (address) + return address; + } + return NULL; +} +#endif + +/* Return 1 if usable, 0 else and exception set. */ +static int +_check_outarg_type(PyObject *arg, int index) +{ + StgDictObject *dict; + + if (PointerTypeObject_Check(arg)) + return 1; + + if (ArrayTypeObject_Check(arg)) + return 1; + + dict = PyType_stgdict(arg); + if (dict + /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */ + && PyString_Check(dict->proto) +/* We only allow c_void_p, c_char_p and c_wchar_p as a simple output parameter type */ + && (strchr("PzZ", PyString_AS_STRING(dict->proto)[0]))) { + return 1; + } + + PyErr_Format(PyExc_TypeError, + "'out' parameter %d must be a pointer type, not %s", + index, + PyType_Check(arg) ? + ((PyTypeObject *)arg)->tp_name : + arg->ob_type->tp_name); + return 0; +} + +/* Returns 1 on success, 0 on error */ +static int +_validate_paramflags(PyTypeObject *type, PyObject *paramflags) +{ + int i, len; + StgDictObject *dict; + PyObject *argtypes; + + dict = PyType_stgdict((PyObject *)type); + assert(dict); /* Cannot be NULL. 'type' is a CFuncPtr type. */ + argtypes = dict->argtypes; + + if (paramflags == NULL || dict->argtypes == NULL) + return 1; + + if (!PyTuple_Check(paramflags)) { + PyErr_SetString(PyExc_TypeError, + "paramflags must be a tuple or None"); + return 0; + } + + len = PyTuple_GET_SIZE(paramflags); + if (len != PyTuple_GET_SIZE(dict->argtypes)) { + PyErr_SetString(PyExc_ValueError, + "paramflags must have the same length as argtypes"); + return 0; + } + + for (i = 0; i < len; ++i) { + PyObject *item = PyTuple_GET_ITEM(paramflags, i); + int flag; + char *name; + PyObject *defval; + PyObject *typ; + if (!PyArg_ParseTuple(item, "i|zO", &flag, &name, &defval)) { + PyErr_SetString(PyExc_TypeError, + "paramflags must be a sequence of (int [,string [,value]]) tuples"); + return 0; + } + typ = PyTuple_GET_ITEM(argtypes, i); + switch (flag & (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID)) { + case 0: + case PARAMFLAG_FIN: + case PARAMFLAG_FIN | PARAMFLAG_FLCID: + case PARAMFLAG_FIN | PARAMFLAG_FOUT: + break; + case PARAMFLAG_FOUT: + if (!_check_outarg_type(typ, i+1)) + return 0; + break; + default: + PyErr_Format(PyExc_TypeError, + "paramflag value %d not supported", + flag); + return 0; + } + } + return 1; +} + +static int +_get_name(PyObject *obj, char **pname) +{ +#ifdef MS_WIN32 + if (PyInt_Check(obj) || PyLong_Check(obj)) { + /* We have to use MAKEINTRESOURCEA for Windows CE. + Works on Windows as well, of course. + */ + *pname = MAKEINTRESOURCEA(PyInt_AsUnsignedLongMask(obj) & 0xFFFF); + return 1; + } +#endif + if (PyString_Check(obj) || PyUnicode_Check(obj)) { + *pname = PyString_AsString(obj); + return *pname ? 1 : 0; + } + PyErr_SetString(PyExc_TypeError, + "function name must be string or integer"); + return 0; +} + + +static PyObject * +CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + char *name; + int (* address)(void); + PyObject *dll; + PyObject *obj; + CFuncPtrObject *self; + void *handle; + PyObject *paramflags = NULL; + + if (!PyArg_ParseTuple(args, "(O&O)|O", _get_name, &name, &dll, &paramflags)) + return NULL; + if (paramflags == Py_None) + paramflags = NULL; + + obj = PyObject_GetAttrString(dll, "_handle"); + if (!obj) + return NULL; + if (!PyInt_Check(obj) && !PyLong_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "the _handle attribute of the second argument must be an integer"); + Py_DECREF(obj); + return NULL; + } + handle = (void *)PyLong_AsVoidPtr(obj); + Py_DECREF(obj); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_ValueError, + "could not convert the _handle attribute to a pointer"); + return NULL; + } + +#ifdef MS_WIN32 + address = FindAddress(handle, name, (PyObject *)type); + if (!address) { + if (!IS_INTRESOURCE(name)) + PyErr_Format(PyExc_AttributeError, + "function '%s' not found", + name); + else + PyErr_Format(PyExc_AttributeError, + "function ordinal %d not found", + (WORD)(size_t)name); + return NULL; + } +#else + address = (PPROC)ctypes_dlsym(handle, name); + if (!address) { + PyErr_Format(PyExc_AttributeError, +#ifdef __CYGWIN__ +/* dlerror() isn't very helpful on cygwin */ + "function '%s' not found (%s) ", + name, +#endif + ctypes_dlerror()); + return NULL; + } +#endif + if (!_validate_paramflags(type, paramflags)) + return NULL; + + self = (CFuncPtrObject *)GenericCData_new(type, args, kwds); + if (!self) + return NULL; + + Py_XINCREF(paramflags); + self->paramflags = paramflags; + + *(void **)self->b_ptr = address; + + Py_INCREF((PyObject *)dll); /* for KeepRef */ + if (-1 == KeepRef((CDataObject *)self, 0, dll)) { + Py_DECREF((PyObject *)self); + return NULL; + } + + Py_INCREF(self); + self->callable = (PyObject *)self; + return (PyObject *)self; +} + +#ifdef MS_WIN32 +static PyObject * +CFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CFuncPtrObject *self; + int index; + char *name = NULL; + PyObject *paramflags = NULL; + GUID *iid = NULL; + int iid_len = 0; + + if (!PyArg_ParseTuple(args, "is|Oz#", &index, &name, &paramflags, &iid, &iid_len)) + return NULL; + if (paramflags == Py_None) + paramflags = NULL; + + if (!_validate_paramflags(type, paramflags)) + return NULL; + + self = (CFuncPtrObject *)GenericCData_new(type, args, kwds); + self->index = index + 0x1000; + Py_XINCREF(paramflags); + self->paramflags = paramflags; + if (iid_len == sizeof(GUID)) + self->iid = iid; + return (PyObject *)self; +} +#endif + +/* + CFuncPtr_new accepts different argument lists in addition to the standard + _basespec_ keyword arg: + + one argument form + "i" - function address + "O" - must be a callable, creates a C callable function + + two or more argument forms (the third argument is a paramflags tuple) + "(sO)|..." - (function name, dll object (with an integer handle)), paramflags + "(iO)|..." - (function ordinal, dll object (with an integer handle)), paramflags + "is|..." - vtable index, method name, creates callable calling COM vtbl +*/ +static PyObject * +CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CFuncPtrObject *self; + PyObject *callable; + StgDictObject *dict; + ffi_info *thunk; + + if (PyTuple_GET_SIZE(args) == 0) + return GenericCData_new(type, args, kwds); + + if (1 <= PyTuple_GET_SIZE(args) && PyTuple_Check(PyTuple_GET_ITEM(args, 0))) + return CFuncPtr_FromDll(type, args, kwds); + +#ifdef MS_WIN32 + if (2 <= PyTuple_GET_SIZE(args) && PyInt_Check(PyTuple_GET_ITEM(args, 0))) + return CFuncPtr_FromVtblIndex(type, args, kwds); +#endif + + if (1 == PyTuple_GET_SIZE(args) + && (PyInt_Check(PyTuple_GET_ITEM(args, 0)) + || PyLong_Check(PyTuple_GET_ITEM(args, 0)))) { + CDataObject *ob; + void *ptr = PyLong_AsVoidPtr(PyTuple_GET_ITEM(args, 0)); + if (ptr == NULL) + return NULL; + ob = (CDataObject *)GenericCData_new(type, args, kwds); + if (ob == NULL) + return NULL; + *(void **)ob->b_ptr = ptr; + return (PyObject *)ob; + } + + if (!PyArg_ParseTuple(args, "O", &callable)) + return NULL; + if (!PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, + "argument must be callable or integer function address"); + return NULL; + } + + /* XXX XXX This would allow to pass additional options. For COM + method *implementations*, we would probably want different + behaviour than in 'normal' callback functions: return a HRESULT if + an exception occurrs in the callback, and print the traceback not + only on the console, but also to OutputDebugString() or something + like that. + */ +/* + if (kwds && PyDict_GetItemString(kwds, "options")) { + ... + } +*/ + + dict = PyType_stgdict((PyObject *)type); + /* XXXX Fails if we do: 'CFuncPtr(lambda x: x)' */ + if (!dict || !dict->argtypes) { + PyErr_SetString(PyExc_TypeError, + "cannot construct instance of this class:" + " no argtypes"); + return NULL; + } + + /*****************************************************************/ + /* The thunk keeps unowned references to callable and dict->argtypes + so we have to keep them alive somewhere else: callable is kept in self, + dict->argtypes is in the type's stgdict. + */ + thunk = AllocFunctionCallback(callable, + dict->argtypes, + dict->restype, + dict->flags & FUNCFLAG_CDECL); + if (!thunk) + return NULL; + + self = (CFuncPtrObject *)GenericCData_new(type, args, kwds); + if (self == NULL) + return NULL; + + Py_INCREF(callable); + self->callable = callable; + + self->thunk = thunk; + *(void **)self->b_ptr = *(void **)thunk; + + /* We store ourself in self->b_objects[0], because the whole instance + must be kept alive if stored in a structure field, for example. + Cycle GC to the rescue! And we have a unittest proving that this works + correctly... + */ + + Py_INCREF((PyObject *)self); /* for KeepRef */ + if (-1 == KeepRef((CDataObject *)self, 0, (PyObject *)self)) { + Py_DECREF((PyObject *)self); + return NULL; + } + + return (PyObject *)self; +} + + +/* + _byref consumes a refcount to its argument +*/ +static PyObject * +_byref(PyObject *obj) +{ + PyCArgObject *parg; + if (!CDataObject_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "expected CData instance"); + return NULL; + } + + parg = new_CArgObject(); + if (parg == NULL) { + Py_DECREF(obj); + return NULL; + } + + parg->tag = 'P'; + parg->pffi_type = &ffi_type_pointer; + parg->obj = obj; + parg->value.p = ((CDataObject *)obj)->b_ptr; + return (PyObject *)parg; +} + +static PyObject * +_get_arg(int *pindex, char *name, PyObject *defval, PyObject *inargs, PyObject *kwds) +{ + PyObject *v; + + if (*pindex < PyTuple_GET_SIZE(inargs)) { + v = PyTuple_GET_ITEM(inargs, *pindex); + ++*pindex; + Py_INCREF(v); + return v; + } + if (kwds && (v = PyDict_GetItemString(kwds, name))) { + ++*pindex; + Py_INCREF(v); + return v; + } + if (defval) { + Py_INCREF(defval); + return defval; + } + /* we can't currently emit a better error message */ + if (name) + PyErr_Format(PyExc_TypeError, + "required argument '%s' missing", name); + else + PyErr_Format(PyExc_TypeError, + "not enough arguments"); + return NULL; +} + +/* + This function implements higher level functionality plus the ability to call + functions with keyword arguments by looking at parameter flags. parameter + flags is a tuple of 1, 2 or 3-tuples. The first entry in each is an integer + specifying the direction of the data transfer for this parameter - 'in', + 'out' or 'inout' (zero means the same as 'in'). The second entry is the + parameter name, and the third is the default value if the parameter is + missing in the function call. + + This function builds and returns a new tuple 'callargs' which contains the + parameters to use in the call. Items on this tuple are copied from the + 'inargs' tuple for 'in' and 'in, out' parameters, and constructed from the + 'argtypes' tuple for 'out' parameters. It also calculates numretvals which + is the number of return values for the function, outmask/inoutmask are + bitmasks containing indexes into the callargs tuple specifying which + parameters have to be returned. _build_result builds the return value of the + function. +*/ +static PyObject * +_build_callargs(CFuncPtrObject *self, PyObject *argtypes, + PyObject *inargs, PyObject *kwds, + int *poutmask, int *pinoutmask, unsigned int *pnumretvals) +{ + PyObject *paramflags = self->paramflags; + PyObject *callargs; + StgDictObject *dict; + int i, len; + int inargs_index = 0; + /* It's a little bit difficult to determine how many arguments the + function call requires/accepts. For simplicity, we count the consumed + args and compare this to the number of supplied args. */ + int actual_args; + + *poutmask = 0; + *pinoutmask = 0; + *pnumretvals = 0; + + /* Trivial cases, where we either return inargs itself, or a slice of it. */ + if (argtypes == NULL || paramflags == NULL || PyTuple_GET_SIZE(argtypes) == 0) { +#ifdef MS_WIN32 + if (self->index) + return PyTuple_GetSlice(inargs, 1, PyTuple_GET_SIZE(inargs)); +#endif + Py_INCREF(inargs); + return inargs; + } + + len = PyTuple_GET_SIZE(argtypes); + callargs = PyTuple_New(len); /* the argument tuple we build */ + if (callargs == NULL) + return NULL; + +#ifdef MS_WIN32 + /* For a COM method, skip the first arg */ + if (self->index) { + inargs_index = 1; + } +#endif + for (i = 0; i < len; ++i) { + PyObject *item = PyTuple_GET_ITEM(paramflags, i); + PyObject *ob; + int flag; + char *name = NULL; + PyObject *defval = NULL; + + /* This way seems to be ~2 us faster than the PyArg_ParseTuple + calls below. */ + /* We HAVE already checked that the tuple can be parsed with "i|zO", so... */ + int tsize = PyTuple_GET_SIZE(item); + flag = PyInt_AS_LONG(PyTuple_GET_ITEM(item, 0)); + name = tsize > 1 ? PyString_AS_STRING(PyTuple_GET_ITEM(item, 1)) : NULL; + defval = tsize > 2 ? PyTuple_GET_ITEM(item, 2) : NULL; + + switch (flag & (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID)) { + case PARAMFLAG_FIN | PARAMFLAG_FLCID: + /* ['in', 'lcid'] parameter. Always taken from defval, + if given, else the integer 0. */ + if (defval == NULL) { + defval = PyInt_FromLong(0); + if (defval == NULL) + goto error; + } else + Py_INCREF(defval); + PyTuple_SET_ITEM(callargs, i, defval); + break; + case (PARAMFLAG_FIN | PARAMFLAG_FOUT): + *pinoutmask |= (1 << i); /* mark as inout arg */ + (*pnumretvals)++; + /* fall through to PARAMFLAG_FIN... */ + case 0: + case PARAMFLAG_FIN: + /* 'in' parameter. Copy it from inargs. */ + ob =_get_arg(&inargs_index, name, defval, inargs, kwds); + if (ob == NULL) + goto error; + PyTuple_SET_ITEM(callargs, i, ob); + break; + case PARAMFLAG_FOUT: + /* XXX Refactor this code into a separate function. */ + /* 'out' parameter. + argtypes[i] must be a POINTER to a c type. + + Cannot by supplied in inargs, but a defval will be used + if available. XXX Should we support getting it from kwds? + */ + if (defval) { + /* XXX Using mutable objects as defval will + make the function non-threadsafe, unless we + copy the object in each invocation */ + Py_INCREF(defval); + PyTuple_SET_ITEM(callargs, i, defval); + *poutmask |= (1 << i); /* mark as out arg */ + (*pnumretvals)++; + break; + } + ob = PyTuple_GET_ITEM(argtypes, i); + dict = PyType_stgdict(ob); + if (dict == NULL) { + /* Cannot happen: _validate_paramflags() + would not accept such an object */ + PyErr_Format(PyExc_RuntimeError, + "NULL stgdict unexpected"); + goto error; + } + if (PyString_Check(dict->proto)) { + PyErr_Format( + PyExc_TypeError, + "%s 'out' parameter must be passed as default value", + ((PyTypeObject *)ob)->tp_name); + goto error; + } + if (ArrayTypeObject_Check(ob)) + ob = PyObject_CallObject(ob, NULL); + else + /* Create an instance of the pointed-to type */ + ob = PyObject_CallObject(dict->proto, NULL); + /* + XXX Is the following correct any longer? + We must not pass a byref() to the array then but + the array instance itself. Then, we cannot retrive + the result from the PyCArgObject. + */ + if (ob == NULL) + goto error; + /* The .from_param call that will ocurr later will pass this + as a byref parameter. */ + PyTuple_SET_ITEM(callargs, i, ob); + *poutmask |= (1 << i); /* mark as out arg */ + (*pnumretvals)++; + break; + default: + PyErr_Format(PyExc_ValueError, + "paramflag %d not yet implemented", flag); + goto error; + break; + } + } + + /* We have counted the arguments we have consumed in 'inargs_index'. This + must be the same as len(inargs) + len(kwds), otherwise we have + either too much or not enough arguments. */ + + actual_args = PyTuple_GET_SIZE(inargs) + (kwds ? PyDict_Size(kwds) : 0); + if (actual_args != inargs_index) { + /* When we have default values or named parameters, this error + message is misleading. See unittests/test_paramflags.py + */ + PyErr_Format(PyExc_TypeError, + "call takes exactly %d arguments (%d given)", + inargs_index, actual_args); + goto error; + } + + /* outmask is a bitmask containing indexes into callargs. Items at + these indexes contain values to return. + */ + return callargs; + error: + Py_DECREF(callargs); + return NULL; +} + +/* See also: + http://msdn.microsoft.com/library/en-us/com/html/769127a1-1a14-4ed4-9d38-7cf3e571b661.asp +*/ +/* + Build return value of a function. + + Consumes the refcount on result and callargs. +*/ +static PyObject * +_build_result(PyObject *result, PyObject *callargs, + int outmask, int inoutmask, unsigned int numretvals) +{ + unsigned int i, index; + int bit; + PyObject *tup = NULL; + + if (callargs == NULL) + return result; + if (result == NULL || numretvals == 0) { + Py_DECREF(callargs); + return result; + } + Py_DECREF(result); + + /* tup will not be allocated if numretvals == 1 */ + /* allocate tuple to hold the result */ + if (numretvals > 1) { + tup = PyTuple_New(numretvals); + if (tup == NULL) { + Py_DECREF(callargs); + return NULL; + } + } + + index = 0; + for (bit = 1, i = 0; i < 32; ++i, bit <<= 1) { + PyObject *v; + if (bit & inoutmask) { + v = PyTuple_GET_ITEM(callargs, i); + Py_INCREF(v); + if (numretvals == 1) { + Py_DECREF(callargs); + return v; + } + PyTuple_SET_ITEM(tup, index, v); + index++; + } else if (bit & outmask) { + v = PyTuple_GET_ITEM(callargs, i); + v = PyObject_CallMethod(v, "__ctypes_from_outparam__", NULL); + if (v == NULL || numretvals == 1) { + Py_DECREF(callargs); + return v; + } + PyTuple_SET_ITEM(tup, index, v); + index++; + } + if (index == numretvals) + break; + } + + Py_DECREF(callargs); + return tup; +} + +static PyObject * +CFuncPtr_call(CFuncPtrObject *self, PyObject *inargs, PyObject *kwds) +{ + PyObject *restype; + PyObject *converters; + PyObject *checker; + PyObject *argtypes; + StgDictObject *dict = PyObject_stgdict((PyObject *)self); + PyObject *result; + PyObject *callargs; + PyObject *errcheck; +#ifdef MS_WIN32 + IUnknown *piunk = NULL; +#endif + void *pProc = NULL; + + int inoutmask; + int outmask; + unsigned int numretvals; + + assert(dict); /* Cannot be NULL for CFuncPtrObject instances */ + restype = self->restype ? self->restype : dict->restype; + converters = self->converters ? self->converters : dict->converters; + checker = self->checker ? self->checker : dict->checker; + argtypes = self->argtypes ? self->argtypes : dict->argtypes; +/* later, we probably want to have an errcheck field in stgdict */ + errcheck = self->errcheck /* ? self->errcheck : dict->errcheck */; + + + pProc = *(void **)self->b_ptr; +#ifdef MS_WIN32 + if (self->index) { + /* It's a COM method */ + CDataObject *this; + this = (CDataObject *)PyTuple_GetItem(inargs, 0); /* borrowed ref! */ + if (!this) { + PyErr_SetString(PyExc_ValueError, + "native com method call without 'this' parameter"); + return NULL; + } + if (!CDataObject_Check(this)) { + PyErr_SetString(PyExc_TypeError, + "Expected a COM this pointer as first argument"); + return NULL; + } + /* there should be more checks? No, in Python */ + /* First arg is an pointer to an interface instance */ + if (!this->b_ptr || *(void **)this->b_ptr == NULL) { + PyErr_SetString(PyExc_ValueError, + "NULL COM pointer access"); + return NULL; + } + piunk = *(IUnknown **)this->b_ptr; + if (NULL == piunk->lpVtbl) { + PyErr_SetString(PyExc_ValueError, + "COM method call without VTable"); + return NULL; + } + pProc = ((void **)piunk->lpVtbl)[self->index - 0x1000]; + } +#endif + callargs = _build_callargs(self, argtypes, + inargs, kwds, + &outmask, &inoutmask, &numretvals); + if (callargs == NULL) + return NULL; + + if (converters) { + int required = PyTuple_GET_SIZE(converters); + int actual = PyTuple_GET_SIZE(callargs); + + if ((dict->flags & FUNCFLAG_CDECL) == FUNCFLAG_CDECL) { + /* For cdecl functions, we allow more actual arguments + than the length of the argtypes tuple. + */ + if (required > actual) { + Py_DECREF(callargs); + PyErr_Format(PyExc_TypeError, + "this function takes at least %d argument%s (%d given)", + required, + required == 1 ? "" : "s", + actual); + return NULL; + } + } else if (required != actual) { + Py_DECREF(callargs); + PyErr_Format(PyExc_TypeError, + "this function takes %d argument%s (%d given)", + required, + required == 1 ? "" : "s", + actual); + return NULL; + } + } + + result = _CallProc(pProc, + callargs, +#ifdef MS_WIN32 + piunk, + self->iid, +#endif + dict->flags, + converters, + restype, + checker); +/* The 'errcheck' protocol */ + if (result != NULL && errcheck) { + PyObject *v = PyObject_CallFunctionObjArgs(errcheck, + result, + self, + callargs, + NULL); + /* If the errcheck funtion failed, return NULL. + If the errcheck function returned callargs unchanged, + continue normal processing. + If the errcheck function returned something else, + use that as result. + */ + if (v == NULL || v != callargs) { + Py_DECREF(result); + Py_DECREF(callargs); + return v; + } + Py_DECREF(v); + } + + return _build_result(result, callargs, + outmask, inoutmask, numretvals); +} + +static int +CFuncPtr_traverse(CFuncPtrObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->callable); + Py_VISIT(self->restype); + Py_VISIT(self->checker); + Py_VISIT(self->errcheck); + Py_VISIT(self->argtypes); + Py_VISIT(self->converters); + Py_VISIT(self->paramflags); + return CData_traverse((CDataObject *)self, visit, arg); +} + +static int +CFuncPtr_clear(CFuncPtrObject *self) +{ + Py_CLEAR(self->callable); + Py_CLEAR(self->restype); + Py_CLEAR(self->checker); + Py_CLEAR(self->errcheck); + Py_CLEAR(self->argtypes); + Py_CLEAR(self->converters); + Py_CLEAR(self->paramflags); + + if (self->thunk) { + FreeClosure(self->thunk->pcl); + PyMem_Free(self->thunk); + self->thunk = NULL; + } + + return CData_clear((CDataObject *)self); +} + +static void +CFuncPtr_dealloc(CFuncPtrObject *self) +{ + CFuncPtr_clear(self); + self->ob_type->tp_free((PyObject *)self); +} + +static PyObject * +CFuncPtr_repr(CFuncPtrObject *self) +{ +#ifdef MS_WIN32 + if (self->index) + return PyString_FromFormat("<COM method offset %d: %s at %p>", + self->index - 0x1000, + self->ob_type->tp_name, + self); +#endif + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, + self); +} + +PyTypeObject CFuncPtr_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "_ctypes.CFuncPtr", + sizeof(CFuncPtrObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)CFuncPtr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)CFuncPtr_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)CFuncPtr_call, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &CData_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Function Pointer", /* tp_doc */ + (traverseproc)CFuncPtr_traverse, /* tp_traverse */ + (inquiry)CFuncPtr_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + CFuncPtr_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + CFuncPtr_new, /* tp_new */ + 0, /* tp_free */ +}; + +/*****************************************************************/ +/* + Struct_Type +*/ +static int +IBUG(char *msg) +{ + PyErr_Format(PyExc_RuntimeError, + "inconsistent state in CDataObject (%s)", msg); + return -1; +} + +static int +Struct_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int i; + PyObject *fields; + +/* Optimization possible: Store the attribute names _fields_[x][0] + * in C accessible fields somewhere ? + */ + +/* Check this code again for correctness! */ + + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "args not a tuple?"); + return -1; + } + if (PyTuple_GET_SIZE(args)) { + fields = PyObject_GetAttrString(self, "_fields_"); + if (!fields) { + PyErr_Clear(); + fields = PyTuple_New(0); + if (!fields) + return -1; + } + + if (PyTuple_GET_SIZE(args) > PySequence_Length(fields)) { + Py_DECREF(fields); + PyErr_SetString(PyExc_ValueError, + "too many initializers"); + return -1; + } + + for (i = 0; i < PyTuple_GET_SIZE(args); ++i) { + PyObject *pair = PySequence_GetItem(fields, i); + PyObject *name; + PyObject *val; + if (!pair) { + Py_DECREF(fields); + return IBUG("_fields_[i] failed"); + } + + name = PySequence_GetItem(pair, 0); + if (!name) { + Py_DECREF(pair); + Py_DECREF(fields); + return IBUG("_fields_[i][0] failed"); + } + + val = PyTuple_GET_ITEM(args, i); + if (-1 == PyObject_SetAttr(self, name, val)) { + Py_DECREF(pair); + Py_DECREF(name); + Py_DECREF(fields); + return -1; + } + + Py_DECREF(name); + Py_DECREF(pair); + } + Py_DECREF(fields); + } + + if (kwds) { + PyObject *key, *value; + Py_ssize_t pos = 0; + while(PyDict_Next(kwds, &pos, &key, &value)) { + if (-1 == PyObject_SetAttr(self, key, value)) + return -1; + } + } + return 0; +} + +static PyTypeObject Struct_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "_ctypes.Structure", + sizeof(CDataObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &CData_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Structure base class", /* tp_doc */ + (traverseproc)CData_traverse, /* tp_traverse */ + (inquiry)CData_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + Struct_init, /* tp_init */ + 0, /* tp_alloc */ + GenericCData_new, /* tp_new */ + 0, /* tp_free */ +}; + +static PyTypeObject Union_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "_ctypes.Union", + sizeof(CDataObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &CData_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Union base class", /* tp_doc */ + (traverseproc)CData_traverse, /* tp_traverse */ + (inquiry)CData_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + Struct_init, /* tp_init */ + 0, /* tp_alloc */ + GenericCData_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/******************************************************************/ +/* + Array_Type +*/ +static int +Array_init(CDataObject *self, PyObject *args, PyObject *kw) +{ + int i; + int n; + + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "args not a tuple?"); + return -1; + } + n = PyTuple_GET_SIZE(args); + for (i = 0; i < n; ++i) { + PyObject *v; + v = PyTuple_GET_ITEM(args, i); + if (-1 == PySequence_SetItem((PyObject *)self, i, v)) + return -1; + } + return 0; +} + +static PyObject * +Array_item(PyObject *_self, Py_ssize_t index) +{ + CDataObject *self = (CDataObject *)_self; + int offset, size; + StgDictObject *stgdict; + + + if (index < 0 || index >= self->b_length) { + PyErr_SetString(PyExc_IndexError, + "invalid index"); + return NULL; + } + + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL for array instances */ + /* Would it be clearer if we got the item size from + stgdict->proto's stgdict? + */ + size = stgdict->size / stgdict->length; + offset = index * size; + + return CData_get(stgdict->proto, stgdict->getfunc, (PyObject *)self, + index, size, self->b_ptr + offset); +} + +static PyObject * +Array_slice(PyObject *_self, Py_ssize_t ilow, Py_ssize_t ihigh) +{ + CDataObject *self = (CDataObject *)_self; + StgDictObject *stgdict, *itemdict; + PyObject *proto; + PyListObject *np; + Py_ssize_t i, len; + + if (ilow < 0) + ilow = 0; + else if (ilow > self->b_length) + ilow = self->b_length; + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > self->b_length) + ihigh = self->b_length; + len = ihigh - ilow; + + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL for array object instances */ + proto = stgdict->proto; + itemdict = PyType_stgdict(proto); + assert(itemdict); /* proto is the item type of the array, a ctypes + type, so this cannot be NULL */ + if (itemdict->getfunc == getentry("c")->getfunc) { + char *ptr = (char *)self->b_ptr; + return PyString_FromStringAndSize(ptr + ilow, len); +#ifdef CTYPES_UNICODE + } else if (itemdict->getfunc == getentry("u")->getfunc) { + wchar_t *ptr = (wchar_t *)self->b_ptr; + return PyUnicode_FromWideChar(ptr + ilow, len); +#endif + } + + np = (PyListObject *) PyList_New(len); + if (np == NULL) + return NULL; + + for (i = 0; i < len; i++) { + PyObject *v = Array_item(_self, i+ilow); + PyList_SET_ITEM(np, i, v); + } + return (PyObject *)np; +} + +static int +Array_ass_item(PyObject *_self, Py_ssize_t index, PyObject *value) +{ + CDataObject *self = (CDataObject *)_self; + int size, offset; + StgDictObject *stgdict; + char *ptr; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "Array does not support item deletion"); + return -1; + } + + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL for array object instances */ + if (index < 0 || index >= stgdict->length) { + PyErr_SetString(PyExc_IndexError, + "invalid index"); + return -1; + } + size = stgdict->size / stgdict->length; + offset = index * size; + ptr = self->b_ptr + offset; + + return CData_set((PyObject *)self, stgdict->proto, stgdict->setfunc, value, + index, size, ptr); +} + +static int +Array_ass_slice(PyObject *_self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *value) +{ + CDataObject *self = (CDataObject *)_self; + int i, len; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "Array does not support item deletion"); + return -1; + } + + if (ilow < 0) + ilow = 0; + else if (ilow > self->b_length) + ilow = self->b_length; + if (ihigh < 0) + ihigh = 0; + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > self->b_length) + ihigh = self->b_length; + + len = PySequence_Length(value); + if (len != ihigh - ilow) { + PyErr_SetString(PyExc_ValueError, + "Can only assign sequence of same size"); + return -1; + } + for (i = 0; i < len; i++) { + PyObject *item = PySequence_GetItem(value, i); + int result; + if (item == NULL) + return -1; + result = Array_ass_item(_self, i+ilow, item); + Py_DECREF(item); + if (result == -1) + return -1; + } + return 0; +} + +static Py_ssize_t +Array_length(PyObject *_self) +{ + CDataObject *self = (CDataObject *)_self; + return self->b_length; +} + +static PySequenceMethods Array_as_sequence = { + Array_length, /* sq_length; */ + 0, /* sq_concat; */ + 0, /* sq_repeat; */ + Array_item, /* sq_item; */ + Array_slice, /* sq_slice; */ + Array_ass_item, /* sq_ass_item; */ + Array_ass_slice, /* sq_ass_slice; */ + 0, /* sq_contains; */ + + 0, /* sq_inplace_concat; */ + 0, /* sq_inplace_repeat; */ +}; + +PyTypeObject Array_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "_ctypes.Array", + sizeof(CDataObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &Array_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &CData_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "XXX to be provided", /* tp_doc */ + (traverseproc)CData_traverse, /* tp_traverse */ + (inquiry)CData_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Array_init, /* tp_init */ + 0, /* tp_alloc */ + GenericCData_new, /* tp_new */ + 0, /* tp_free */ +}; + +PyObject * +CreateArrayType(PyObject *itemtype, Py_ssize_t length) +{ + static PyObject *cache; + PyObject *key; + PyObject *result; + char name[256]; + + if (cache == NULL) { + cache = PyDict_New(); + if (cache == NULL) + return NULL; + } +#if (PY_VERSION_HEX < 0x02050000) + key = Py_BuildValue("(Oi)", itemtype, length); +#else + key = Py_BuildValue("(On)", itemtype, length); +#endif + if (!key) + return NULL; + result = PyDict_GetItem(cache, key); + if (result) { + Py_INCREF(result); + Py_DECREF(key); + return result; + } + + if (!PyType_Check(itemtype)) { + PyErr_SetString(PyExc_TypeError, + "Expected a type object"); + return NULL; + } +#ifdef MS_WIN64 + sprintf(name, "%.200s_Array_%Id", + ((PyTypeObject *)itemtype)->tp_name, length); +#else + sprintf(name, "%.200s_Array_%ld", + ((PyTypeObject *)itemtype)->tp_name, (long)length); +#endif + + result = PyObject_CallFunction((PyObject *)&ArrayType_Type, +#if (PY_VERSION_HEX < 0x02050000) + "s(O){s:i,s:O}", +#else + "s(O){s:n,s:O}", +#endif + name, + &Array_Type, + "_length_", + length, + "_type_", + itemtype + ); + if (!result) + return NULL; + PyDict_SetItem(cache, key, result); + Py_DECREF(key); + return result; +} + + +/******************************************************************/ +/* + Simple_Type +*/ + +static int +Simple_set_value(CDataObject *self, PyObject *value) +{ + PyObject *result; + StgDictObject *dict = PyObject_stgdict((PyObject *)self); + + assert(dict); /* Cannot be NULL for CDataObject instances */ + assert(dict->setfunc); + result = dict->setfunc(self->b_ptr, value, dict->size); + if (!result) + return -1; + + /* consumes the refcount the setfunc returns */ + return KeepRef(self, 0, result); +} + +static int +Simple_init(CDataObject *self, PyObject *args, PyObject *kw) +{ + PyObject *value = NULL; + if (!PyArg_UnpackTuple(args, "__init__", 0, 1, &value)) + return -1; + if (value) + return Simple_set_value(self, value); + return 0; +} + +static PyObject * +Simple_get_value(CDataObject *self) +{ + StgDictObject *dict; + dict = PyObject_stgdict((PyObject *)self); + assert(dict); /* Cannot be NULL for CDataObject instances */ + assert(dict->getfunc); + return dict->getfunc(self->b_ptr, self->b_size); +} + +static PyGetSetDef Simple_getsets[] = { + { "value", (getter)Simple_get_value, (setter)Simple_set_value, + "current value", NULL }, + { NULL, NULL } +}; + +static PyObject * +Simple_from_outparm(PyObject *self, PyObject *args) +{ + if (IsSimpleSubType((PyObject *)self->ob_type)) { + Py_INCREF(self); + return self; + } + /* call stgdict->getfunc */ + return Simple_get_value((CDataObject *)self); +} + +static PyMethodDef Simple_methods[] = { + { "__ctypes_from_outparam__", Simple_from_outparm, METH_NOARGS, }, + { NULL, NULL }, +}; + +static int Simple_nonzero(CDataObject *self) +{ + return memcmp(self->b_ptr, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", self->b_size); +} + +static PyNumberMethods Simple_as_number = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + (inquiry)Simple_nonzero, /* nb_nonzero */ +}; + +#if (PY_VERSION_HEX < 0x02040000) +/* Only in Python 2.4 and up */ +static PyObject * +PyTuple_Pack(int n, ...) +{ + int i; + PyObject *o; + PyObject *result; + PyObject **items; + va_list vargs; + + va_start(vargs, n); + result = PyTuple_New(n); + if (result == NULL) + return NULL; + items = ((PyTupleObject *)result)->ob_item; + for (i = 0; i < n; i++) { + o = va_arg(vargs, PyObject *); + Py_INCREF(o); + items[i] = o; + } + va_end(vargs); + return result; +} +#endif + +/* "%s(%s)" % (self.__class__.__name__, self.value) */ +static PyObject * +Simple_repr(CDataObject *self) +{ + PyObject *val, *name, *args, *result; + static PyObject *format; + + if (self->ob_type->tp_base != &Simple_Type) { + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); + } + + if (format == NULL) { + format = PyString_FromString("%s(%r)"); + if (format == NULL) + return NULL; + } + + val = Simple_get_value(self); + if (val == NULL) + return NULL; + + name = PyString_FromString(self->ob_type->tp_name); + if (name == NULL) { + Py_DECREF(val); + return NULL; + } + + args = PyTuple_Pack(2, name, val); + Py_DECREF(name); + Py_DECREF(val); + if (args == NULL) + return NULL; + + result = PyString_Format(format, args); + Py_DECREF(args); + return result; +} + +static PyTypeObject Simple_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "_ctypes._SimpleCData", + sizeof(CDataObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)&Simple_repr, /* tp_repr */ + &Simple_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &CData_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "XXX to be provided", /* tp_doc */ + (traverseproc)CData_traverse, /* tp_traverse */ + (inquiry)CData_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Simple_methods, /* tp_methods */ + 0, /* tp_members */ + Simple_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Simple_init, /* tp_init */ + 0, /* tp_alloc */ + GenericCData_new, /* tp_new */ + 0, /* tp_free */ +}; + +/******************************************************************/ +/* + Pointer_Type +*/ +static PyObject * +Pointer_item(PyObject *_self, Py_ssize_t index) +{ + CDataObject *self = (CDataObject *)_self; + int size; + Py_ssize_t offset; + StgDictObject *stgdict, *itemdict; + PyObject *proto; + + if (*(void **)self->b_ptr == NULL) { + PyErr_SetString(PyExc_ValueError, + "NULL pointer access"); + return NULL; + } + + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL for pointer object instances */ + + proto = stgdict->proto; + assert(proto); + itemdict = PyType_stgdict(proto); + assert(itemdict); /* proto is the item type of the pointer, a ctypes + type, so this cannot be NULL */ + + size = itemdict->size; + offset = index * itemdict->size; + + return CData_get(proto, stgdict->getfunc, (PyObject *)self, + index, size, (*(char **)self->b_ptr) + offset); +} + +static int +Pointer_ass_item(PyObject *_self, Py_ssize_t index, PyObject *value) +{ + CDataObject *self = (CDataObject *)_self; + int size; + Py_ssize_t offset; + StgDictObject *stgdict, *itemdict; + PyObject *proto; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "Pointer does not support item deletion"); + return -1; + } + + if (*(void **)self->b_ptr == NULL) { + PyErr_SetString(PyExc_ValueError, + "NULL pointer access"); + return -1; + } + + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL fr pointer instances */ + + proto = stgdict->proto; + assert(proto); + + itemdict = PyType_stgdict(proto); + assert(itemdict); /* Cannot be NULL because the itemtype of a pointer + is always a ctypes type */ + + size = itemdict->size; + offset = index * itemdict->size; + + return CData_set((PyObject *)self, proto, stgdict->setfunc, value, + index, size, (*(char **)self->b_ptr) + offset); +} + +static PyObject * +Pointer_get_contents(CDataObject *self, void *closure) +{ + StgDictObject *stgdict; + + if (*(void **)self->b_ptr == NULL) { + PyErr_SetString(PyExc_ValueError, + "NULL pointer access"); + return NULL; + } + + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL fr pointer instances */ + return CData_FromBaseObj(stgdict->proto, + (PyObject *)self, 0, + *(void **)self->b_ptr); +} + +static int +Pointer_set_contents(CDataObject *self, PyObject *value, void *closure) +{ + StgDictObject *stgdict; + CDataObject *dst; + PyObject *keep; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "Pointer does not support item deletion"); + return -1; + } + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL fr pointer instances */ + assert(stgdict->proto); + if (!CDataObject_Check(value) + || 0 == PyObject_IsInstance(value, stgdict->proto)) { + /* XXX PyObject_IsInstance could return -1! */ + PyErr_Format(PyExc_TypeError, + "expected %s instead of %s", + ((PyTypeObject *)(stgdict->proto))->tp_name, + value->ob_type->tp_name); + return -1; + } + + dst = (CDataObject *)value; + *(void **)self->b_ptr = dst->b_ptr; + + /* + A Pointer instance must keep a the value it points to alive. So, a + pointer instance has b_length set to 2 instead of 1, and we set + 'value' itself as the second item of the b_objects list, additionally. + */ + Py_INCREF(value); + if (-1 == KeepRef(self, 1, value)) + return -1; + + keep = GetKeepedObjects(dst); + Py_INCREF(keep); + return KeepRef(self, 0, keep); +} + +static PyGetSetDef Pointer_getsets[] = { + { "contents", (getter)Pointer_get_contents, + (setter)Pointer_set_contents, + "the object this pointer points to (read-write)", NULL }, + { NULL, NULL } +}; + +static int +Pointer_init(CDataObject *self, PyObject *args, PyObject *kw) +{ + PyObject *value = NULL; + + if (!PyArg_ParseTuple(args, "|O:POINTER", &value)) + return -1; + if (value == NULL) + return 0; + return Pointer_set_contents(self, value, NULL); +} + +static PyObject * +Pointer_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + StgDictObject *dict = PyType_stgdict((PyObject *)type); + if (!dict || !dict->proto) { + PyErr_SetString(PyExc_TypeError, + "Cannot create instance: has no _type_"); + return NULL; + } + return GenericCData_new(type, args, kw); +} + +static PyObject * +Pointer_slice(PyObject *_self, Py_ssize_t ilow, Py_ssize_t ihigh) +{ + CDataObject *self = (CDataObject *)_self; + PyListObject *np; + StgDictObject *stgdict, *itemdict; + PyObject *proto; + Py_ssize_t i, len; + + if (ilow < 0) + ilow = 0; + if (ihigh < ilow) + ihigh = ilow; + len = ihigh - ilow; + + stgdict = PyObject_stgdict((PyObject *)self); + assert(stgdict); /* Cannot be NULL fr pointer instances */ + proto = stgdict->proto; + assert(proto); + itemdict = PyType_stgdict(proto); + assert(itemdict); + if (itemdict->getfunc == getentry("c")->getfunc) { + char *ptr = *(char **)self->b_ptr; + return PyString_FromStringAndSize(ptr + ilow, len); +#ifdef CTYPES_UNICODE + } else if (itemdict->getfunc == getentry("u")->getfunc) { + wchar_t *ptr = *(wchar_t **)self->b_ptr; + return PyUnicode_FromWideChar(ptr + ilow, len); +#endif + } + + np = (PyListObject *) PyList_New(len); + if (np == NULL) + return NULL; + + for (i = 0; i < len; i++) { + PyObject *v = Pointer_item(_self, i+ilow); + PyList_SET_ITEM(np, i, v); + } + return (PyObject *)np; +} + +static PySequenceMethods Pointer_as_sequence = { + 0, /* inquiry sq_length; */ + 0, /* binaryfunc sq_concat; */ + 0, /* intargfunc sq_repeat; */ + Pointer_item, /* intargfunc sq_item; */ + Pointer_slice, /* intintargfunc sq_slice; */ + Pointer_ass_item, /* intobjargproc sq_ass_item; */ + 0, /* intintobjargproc sq_ass_slice; */ + 0, /* objobjproc sq_contains; */ + /* Added in release 2.0 */ + 0, /* binaryfunc sq_inplace_concat; */ + 0, /* intargfunc sq_inplace_repeat; */ +}; + +static int +Pointer_nonzero(CDataObject *self) +{ + return *(void **)self->b_ptr != NULL; +} + +static PyNumberMethods Pointer_as_number = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + (inquiry)Pointer_nonzero, /* nb_nonzero */ +}; + +PyTypeObject Pointer_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "_ctypes._Pointer", + sizeof(CDataObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + &Pointer_as_number, /* tp_as_number */ + &Pointer_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + &CData_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + "XXX to be provided", /* tp_doc */ + (traverseproc)CData_traverse, /* tp_traverse */ + (inquiry)CData_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + Pointer_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Pointer_init, /* tp_init */ + 0, /* tp_alloc */ + Pointer_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/******************************************************************/ +/* + * Module initialization. + */ + +static char *module_docs = +"Create and manipulate C compatible data types in Python."; + +#ifdef MS_WIN32 + +static char comerror_doc[] = "Raised when a COM method call failed."; + +static PyObject * +comerror_str(PyObject *ignored, PyObject *self) +{ + PyObject *args = PyObject_GetAttrString(self, "args"); + PyObject *result; + if (args == NULL) + return NULL; + result = PyObject_Str(args); + Py_DECREF(args); + return result; +} + +static PyObject * +comerror_init(PyObject *self, PyObject *args) +{ + PyObject *hresult, *text, *details; + PyObject *a; + int status; + + if (!PyArg_ParseTuple(args, "OOOO:COMError", &self, &hresult, &text, &details)) + return NULL; + + a = PySequence_GetSlice(args, 1, PySequence_Size(args)); + if (!a) + return NULL; + status = PyObject_SetAttrString(self, "args", a); + Py_DECREF(a); + if (status < 0) + return NULL; + + if (PyObject_SetAttrString(self, "hresult", hresult) < 0) + return NULL; + + if (PyObject_SetAttrString(self, "text", text) < 0) + return NULL; + + if (PyObject_SetAttrString(self, "details", details) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef comerror_methods[] = { + { "__str__", comerror_str, METH_O }, + { "__init__", comerror_init, METH_VARARGS }, + { NULL, NULL }, +}; + +PyObject *COMError; + +static int +create_comerror(void) +{ + PyObject *dict = PyDict_New(); + PyMethodDef *methods = comerror_methods; + PyObject *s; + int status; + + ComError = PyErr_NewException("_ctypes.COMError", + NULL, + dict); + if (ComError == NULL) + return -1; + while (methods->ml_name) { + /* get a wrapper for the built-in function */ + PyObject *func = PyCFunction_New(methods, NULL); + PyObject *meth; + if (func == NULL) + return -1; + meth = PyMethod_New(func, NULL, ComError); + Py_DECREF(func); + if (meth == NULL) + return -1; + PyDict_SetItemString(dict, methods->ml_name, meth); + Py_DECREF(meth); + ++methods; + } + Py_INCREF(ComError); + s = PyString_FromString(comerror_doc); + if (s == NULL) + return -1; + status = PyDict_SetItemString(dict, "__doc__", s); + Py_DECREF(s); + return status; +} + +#endif + +static PyObject * +string_at(const char *ptr, int size) +{ + if (size == -1) + return PyString_FromString(ptr); + return PyString_FromStringAndSize(ptr, size); +} + +static int +cast_check_pointertype(PyObject *arg) +{ + StgDictObject *dict; + + if (PointerTypeObject_Check(arg)) + return 1; + if (CFuncPtrTypeObject_Check(arg)) + return 1; + dict = PyType_stgdict(arg); + if (dict) { + if (PyString_Check(dict->proto) + && (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) { + /* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */ + return 1; + } + } + PyErr_Format(PyExc_TypeError, + "cast() argument 2 must be a pointer type, not %s", + PyType_Check(arg) + ? ((PyTypeObject *)arg)->tp_name + : arg->ob_type->tp_name); + return 0; +} + +static PyObject * +cast(void *ptr, PyObject *src, PyObject *ctype) +{ + CDataObject *result; + if (0 == cast_check_pointertype(ctype)) + return NULL; + result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL); + if (result == NULL) + return NULL; + + /* + The casted objects '_objects' member: + + It must certainly contain the source objects one. + It must contain the source object itself. + */ + if (CDataObject_Check(src)) { + CDataObject *obj = (CDataObject *)src; + /* CData_GetContainer will initialize src.b_objects, we need + this so it can be shared */ + CData_GetContainer(obj); + /* But we need a dictionary! */ + if (obj->b_objects == Py_None) { + Py_DECREF(Py_None); + obj->b_objects = PyDict_New(); + if (obj->b_objects == NULL) + goto failed; + } + Py_XINCREF(obj->b_objects); + result->b_objects = obj->b_objects; + if (result->b_objects && PyDict_Check(result->b_objects)) { + PyObject *index; + int rc; + index = PyLong_FromVoidPtr((void *)src); + if (index == NULL) + goto failed; + rc = PyDict_SetItem(result->b_objects, index, src); + Py_DECREF(index); + if (rc == -1) + goto failed; + } + } + /* Should we assert that result is a pointer type? */ + memcpy(result->b_ptr, &ptr, sizeof(void *)); + return (PyObject *)result; + + failed: + Py_DECREF(result); + return NULL; +} + +#ifdef CTYPES_UNICODE +static PyObject * +wstring_at(const wchar_t *ptr, int size) +{ + if (size == -1) + size = wcslen(ptr); + return PyUnicode_FromWideChar(ptr, size); +} +#endif + +PyMODINIT_FUNC +init_ctypes(void) +{ + PyObject *m; + +/* Note: + ob_type is the metatype (the 'type'), defaults to PyType_Type, + tp_base is the base type, defaults to 'object' aka PyBaseObject_Type. +*/ +#ifdef WITH_THREAD + PyEval_InitThreads(); +#endif + m = Py_InitModule3("_ctypes", module_methods, module_docs); + if (!m) + return; + + if (PyType_Ready(&PyCArg_Type) < 0) + return; + + /* StgDict is derived from PyDict_Type */ + StgDict_Type.tp_base = &PyDict_Type; + if (PyType_Ready(&StgDict_Type) < 0) + return; + + /************************************************* + * + * Metaclasses + */ + + StructType_Type.tp_base = &PyType_Type; + if (PyType_Ready(&StructType_Type) < 0) + return; + + UnionType_Type.tp_base = &PyType_Type; + if (PyType_Ready(&UnionType_Type) < 0) + return; + + PointerType_Type.tp_base = &PyType_Type; + if (PyType_Ready(&PointerType_Type) < 0) + return; + + ArrayType_Type.tp_base = &PyType_Type; + if (PyType_Ready(&ArrayType_Type) < 0) + return; + + SimpleType_Type.tp_base = &PyType_Type; + if (PyType_Ready(&SimpleType_Type) < 0) + return; + + CFuncPtrType_Type.tp_base = &PyType_Type; + if (PyType_Ready(&CFuncPtrType_Type) < 0) + return; + + /************************************************* + * + * Classes using a custom metaclass + */ + + if (PyType_Ready(&CData_Type) < 0) + return; + + Struct_Type.ob_type = &StructType_Type; + Struct_Type.tp_base = &CData_Type; + if (PyType_Ready(&Struct_Type) < 0) + return; + PyModule_AddObject(m, "Structure", (PyObject *)&Struct_Type); + + Union_Type.ob_type = &UnionType_Type; + Union_Type.tp_base = &CData_Type; + if (PyType_Ready(&Union_Type) < 0) + return; + PyModule_AddObject(m, "Union", (PyObject *)&Union_Type); + + Pointer_Type.ob_type = &PointerType_Type; + Pointer_Type.tp_base = &CData_Type; + if (PyType_Ready(&Pointer_Type) < 0) + return; + PyModule_AddObject(m, "_Pointer", (PyObject *)&Pointer_Type); + + Array_Type.ob_type = &ArrayType_Type; + Array_Type.tp_base = &CData_Type; + if (PyType_Ready(&Array_Type) < 0) + return; + PyModule_AddObject(m, "Array", (PyObject *)&Array_Type); + + Simple_Type.ob_type = &SimpleType_Type; + Simple_Type.tp_base = &CData_Type; + if (PyType_Ready(&Simple_Type) < 0) + return; + PyModule_AddObject(m, "_SimpleCData", (PyObject *)&Simple_Type); + + CFuncPtr_Type.ob_type = &CFuncPtrType_Type; + CFuncPtr_Type.tp_base = &CData_Type; + if (PyType_Ready(&CFuncPtr_Type) < 0) + return; + PyModule_AddObject(m, "CFuncPtr", (PyObject *)&CFuncPtr_Type); + + /************************************************* + * + * Simple classes + */ + + /* CField_Type is derived from PyBaseObject_Type */ + if (PyType_Ready(&CField_Type) < 0) + return; + + /************************************************* + * + * Other stuff + */ + +#ifdef MS_WIN32 + if (create_comerror() < 0) + return; + PyModule_AddObject(m, "COMError", ComError); + + PyModule_AddObject(m, "FUNCFLAG_HRESULT", PyInt_FromLong(FUNCFLAG_HRESULT)); + PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyInt_FromLong(FUNCFLAG_STDCALL)); +#endif + PyModule_AddObject(m, "FUNCFLAG_CDECL", PyInt_FromLong(FUNCFLAG_CDECL)); + PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyInt_FromLong(FUNCFLAG_PYTHONAPI)); + PyModule_AddStringConstant(m, "__version__", "1.0.2"); + + PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove)); + PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset)); + PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at)); + PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast)); +#ifdef CTYPES_UNICODE + PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at)); +#endif + +/* If RTLD_LOCAL is not defined (Windows!), set it to zero. */ +#ifndef RTLD_LOCAL +#define RTLD_LOCAL 0 +#endif + +/* If RTLD_GLOBAL is not defined (cygwin), set it to the same value as + RTLD_LOCAL. +*/ +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL RTLD_LOCAL +#endif + + PyModule_AddObject(m, "RTLD_LOCAL", PyInt_FromLong(RTLD_LOCAL)); + PyModule_AddObject(m, "RTLD_GLOBAL", PyInt_FromLong(RTLD_GLOBAL)); + + PyExc_ArgError = PyErr_NewException("ctypes.ArgumentError", NULL, NULL); + if (PyExc_ArgError) { + Py_INCREF(PyExc_ArgError); + PyModule_AddObject(m, "ArgumentError", PyExc_ArgError); + } + /************************************************* + * + * Others... + */ + init_callbacks_in_module(m); +} + +/***************************************************************** + * replacements for broken Python api functions (in Python 2.3). + * See #1047269 Buffer overwrite in PyUnicode_AsWideChar + */ + +#ifdef HAVE_WCHAR_H + +PyObject *My_PyUnicode_FromWideChar(register const wchar_t *w, + Py_ssize_t size) +{ + PyUnicodeObject *unicode; + + if (w == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + unicode = (PyUnicodeObject *)PyUnicode_FromUnicode(NULL, size); + if (!unicode) + return NULL; + + /* Copy the wchar_t data into the new object */ +#ifdef HAVE_USABLE_WCHAR_T + memcpy(unicode->str, w, size * sizeof(wchar_t)); +#else + { + register Py_UNICODE *u; + register int i; + u = PyUnicode_AS_UNICODE(unicode); + /* In Python, the following line has a one-off error */ + for (i = size; i > 0; i--) + *u++ = *w++; + } +#endif + + return (PyObject *)unicode; +} + +int My_PyUnicode_AsWideChar(PyUnicodeObject *unicode, + register wchar_t *w, + Py_ssize_t size) +{ + if (unicode == NULL) { + PyErr_BadInternalCall(); + return -1; + } + if (size > PyUnicode_GET_SIZE(unicode)) + size = PyUnicode_GET_SIZE(unicode); +#ifdef HAVE_USABLE_WCHAR_T + memcpy(w, unicode->str, size * sizeof(wchar_t)); +#else + { + register Py_UNICODE *u; + register int i; + u = PyUnicode_AS_UNICODE(unicode); + /* In Python, the following line has a one-off error */ + for (i = size; i > 0; i--) + *w++ = *u++; + } +#endif + + return size; +} + +#endif + +/* + Local Variables: + compile-command: "cd .. && python setup.py -q build -g && python setup.py -q build install --home ~" + End: +*/ diff --git a/sys/src/cmd/python/Modules/_ctypes/_ctypes_test.c b/sys/src/cmd/python/Modules/_ctypes/_ctypes_test.c new file mode 100644 index 000000000..c10da0d99 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/_ctypes_test.c @@ -0,0 +1,548 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + + +#include <Python.h> + +/* + Backwards compatibility: + Python2.2 used LONG_LONG instead of PY_LONG_LONG +*/ +#if defined(HAVE_LONG_LONG) && !defined(PY_LONG_LONG) +#define PY_LONG_LONG LONG_LONG +#endif + +#ifdef MS_WIN32 +#include <windows.h> +#endif + +#if defined(MS_WIN32) || defined(__CYGWIN__) +#define EXPORT(x) __declspec(dllexport) x +#else +#define EXPORT(x) x +#endif + +/* some functions handy for testing */ + +EXPORT(char *)my_strtok(char *token, const char *delim) +{ + return strtok(token, delim); +} + +EXPORT(char *)my_strchr(const char *s, int c) +{ + return strchr(s, c); +} + + +EXPORT(double) my_sqrt(double a) +{ + return sqrt(a); +} + +EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*)) +{ + qsort(base, num, width, compare); +} + +EXPORT(int *) _testfunc_ai8(int a[8]) +{ + return a; +} + +EXPORT(void) _testfunc_v(int a, int b, int *presult) +{ + *presult = a + b; +} + +EXPORT(int) _testfunc_i_bhilfd(signed char b, short h, int i, long l, float f, double d) +{ +/* printf("_testfunc_i_bhilfd got %d %d %d %ld %f %f\n", + b, h, i, l, f, d); +*/ + return (int)(b + h + i + l + f + d); +} + +EXPORT(float) _testfunc_f_bhilfd(signed char b, short h, int i, long l, float f, double d) +{ +/* printf("_testfunc_f_bhilfd got %d %d %d %ld %f %f\n", + b, h, i, l, f, d); +*/ + return (float)(b + h + i + l + f + d); +} + +EXPORT(double) _testfunc_d_bhilfd(signed char b, short h, int i, long l, float f, double d) +{ +/* printf("_testfunc_d_bhilfd got %d %d %d %ld %f %f\n", + b, h, i, l, f, d); +*/ + return (double)(b + h + i + l + f + d); +} + +EXPORT(char *) _testfunc_p_p(void *s) +{ + return (char *)s; +} + +EXPORT(void *) _testfunc_c_p_p(int *argcp, char **argv) +{ + return argv[(*argcp)-1]; +} + +EXPORT(void *) get_strchr(void) +{ + return (void *)strchr; +} + +EXPORT(char *) my_strdup(char *src) +{ + char *dst = (char *)malloc(strlen(src)+1); + if (!dst) + return NULL; + strcpy(dst, src); + return dst; +} + +EXPORT(void)my_free(void *ptr) +{ + free(ptr); +} + +#ifdef HAVE_WCHAR_H +EXPORT(wchar_t *) my_wcsdup(wchar_t *src) +{ + size_t len = wcslen(src); + wchar_t *ptr = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); + if (ptr == NULL) + return NULL; + memcpy(ptr, src, (len+1) * sizeof(wchar_t)); + return ptr; +} + +EXPORT(size_t) my_wcslen(wchar_t *src) +{ + return wcslen(src); +} +#endif + +#ifndef MS_WIN32 +# ifndef __stdcall +# define __stdcall /* */ +# endif +#endif + +typedef struct { + int (*c)(int, int); + int (__stdcall *s)(int, int); +} FUNCS; + +EXPORT(int) _testfunc_callfuncp(FUNCS *fp) +{ + fp->c(1, 2); + fp->s(3, 4); + return 0; +} + +EXPORT(int) _testfunc_deref_pointer(int *pi) +{ + return *pi; +} + +#ifdef MS_WIN32 +EXPORT(int) _testfunc_piunk(IUnknown FAR *piunk) +{ + piunk->lpVtbl->AddRef(piunk); + return piunk->lpVtbl->Release(piunk); +} +#endif + +EXPORT(int) _testfunc_callback_with_pointer(int (*func)(int *)) +{ + int table[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + return (*func)(table); +} + +#ifdef HAVE_LONG_LONG +EXPORT(PY_LONG_LONG) _testfunc_q_bhilfdq(signed char b, short h, int i, long l, float f, + double d, PY_LONG_LONG q) +{ + return (PY_LONG_LONG)(b + h + i + l + f + d + q); +} + +EXPORT(PY_LONG_LONG) _testfunc_q_bhilfd(signed char b, short h, int i, long l, float f, double d) +{ + return (PY_LONG_LONG)(b + h + i + l + f + d); +} + +EXPORT(int) _testfunc_callback_i_if(int value, int (*func)(int)) +{ + int sum = 0; + while (value != 0) { + sum += func(value); + value /= 2; + } + return sum; +} + +EXPORT(PY_LONG_LONG) _testfunc_callback_q_qf(PY_LONG_LONG value, + PY_LONG_LONG (*func)(PY_LONG_LONG)) +{ + PY_LONG_LONG sum = 0; + + while (value != 0) { + sum += func(value); + value /= 2; + } + return sum; +} + +#endif + +typedef struct { + char *name; + char *value; +} SPAM; + +typedef struct { + char *name; + int num_spams; + SPAM *spams; +} EGG; + +SPAM my_spams[2] = { + { "name1", "value1" }, + { "name2", "value2" }, +}; + +EGG my_eggs[1] = { + { "first egg", 1, my_spams } +}; + +EXPORT(int) getSPAMANDEGGS(EGG **eggs) +{ + *eggs = my_eggs; + return 1; +} + +typedef struct tagpoint { + int x; + int y; +} point; + +EXPORT(int) _testfunc_byval(point in, point *pout) +{ + if (pout) { + pout->x = in.x; + pout->y = in.y; + } + return in.x + in.y; +} + +EXPORT (int) an_integer = 42; + +EXPORT(int) get_an_integer(void) +{ + return an_integer; +} + +EXPORT(double) +integrate(double a, double b, double (*f)(double), long nstep) +{ + double x, sum=0.0, dx=(b-a)/(double)nstep; + for(x=a+0.5*dx; (b-x)*(x-a)>0.0; x+=dx) + sum += f(x); + return sum/(double)nstep; +} + +typedef struct { + void (*initialize)(void *(*)(int), void(*)(void *)); +} xxx_library; + +static void _xxx_init(void *(*Xalloc)(int), void (*Xfree)(void *)) +{ + void *ptr; + + printf("_xxx_init got %p %p\n", Xalloc, Xfree); + printf("calling\n"); + ptr = Xalloc(32); + Xfree(ptr); + printf("calls done, ptr was %p\n", ptr); +} + +xxx_library _xxx_lib = { + _xxx_init +}; + +EXPORT(xxx_library) *library_get(void) +{ + return &_xxx_lib; +} + +#ifdef MS_WIN32 +/* See Don Box (german), pp 79ff. */ +EXPORT(void) GetString(BSTR *pbstr) +{ + *pbstr = SysAllocString(L"Goodbye!"); +} +#endif + +/* + * Some do-nothing functions, for speed tests + */ +PyObject *py_func_si(PyObject *self, PyObject *args) +{ + char *name; + int i; + if (!PyArg_ParseTuple(args, "si", &name, &i)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +EXPORT(void) _py_func_si(char *s, int i) +{ +} + +PyObject *py_func(PyObject *self, PyObject *args) +{ + Py_INCREF(Py_None); + return Py_None; +} + +EXPORT(void) _py_func(void) +{ +} + +EXPORT(PY_LONG_LONG) last_tf_arg_s; +EXPORT(unsigned PY_LONG_LONG) last_tf_arg_u; + +struct BITS { + int A: 1, B:2, C:3, D:4, E: 5, F: 6, G: 7, H: 8, I: 9; + short M: 1, N: 2, O: 3, P: 4, Q: 5, R: 6, S: 7; +}; + +DL_EXPORT(void) set_bitfields(struct BITS *bits, char name, int value) +{ + switch (name) { + case 'A': bits->A = value; break; + case 'B': bits->B = value; break; + case 'C': bits->C = value; break; + case 'D': bits->D = value; break; + case 'E': bits->E = value; break; + case 'F': bits->F = value; break; + case 'G': bits->G = value; break; + case 'H': bits->H = value; break; + case 'I': bits->I = value; break; + + case 'M': bits->M = value; break; + case 'N': bits->N = value; break; + case 'O': bits->O = value; break; + case 'P': bits->P = value; break; + case 'Q': bits->Q = value; break; + case 'R': bits->R = value; break; + case 'S': bits->S = value; break; + } +} + +DL_EXPORT(int) unpack_bitfields(struct BITS *bits, char name) +{ + switch (name) { + case 'A': return bits->A; + case 'B': return bits->B; + case 'C': return bits->C; + case 'D': return bits->D; + case 'E': return bits->E; + case 'F': return bits->F; + case 'G': return bits->G; + case 'H': return bits->H; + case 'I': return bits->I; + + case 'M': return bits->M; + case 'N': return bits->N; + case 'O': return bits->O; + case 'P': return bits->P; + case 'Q': return bits->Q; + case 'R': return bits->R; + case 'S': return bits->S; + } + return 0; +} + +PyMethodDef module_methods[] = { +/* {"get_last_tf_arg_s", get_last_tf_arg_s, METH_NOARGS}, + {"get_last_tf_arg_u", get_last_tf_arg_u, METH_NOARGS}, +*/ + {"func_si", py_func_si, METH_VARARGS}, + {"func", py_func, METH_NOARGS}, + { NULL, NULL, 0, NULL}, +}; + +#define S last_tf_arg_s = (PY_LONG_LONG)c +#define U last_tf_arg_u = (unsigned PY_LONG_LONG)c + +EXPORT(signed char) tf_b(signed char c) { S; return c/3; } +EXPORT(unsigned char) tf_B(unsigned char c) { U; return c/3; } +EXPORT(short) tf_h(short c) { S; return c/3; } +EXPORT(unsigned short) tf_H(unsigned short c) { U; return c/3; } +EXPORT(int) tf_i(int c) { S; return c/3; } +EXPORT(unsigned int) tf_I(unsigned int c) { U; return c/3; } +EXPORT(long) tf_l(long c) { S; return c/3; } +EXPORT(unsigned long) tf_L(unsigned long c) { U; return c/3; } +EXPORT(PY_LONG_LONG) tf_q(PY_LONG_LONG c) { S; return c/3; } +EXPORT(unsigned PY_LONG_LONG) tf_Q(unsigned PY_LONG_LONG c) { U; return c/3; } +EXPORT(float) tf_f(float c) { S; return c/3; } +EXPORT(double) tf_d(double c) { S; return c/3; } + +#ifdef MS_WIN32 +EXPORT(signed char) __stdcall s_tf_b(signed char c) { S; return c/3; } +EXPORT(unsigned char) __stdcall s_tf_B(unsigned char c) { U; return c/3; } +EXPORT(short) __stdcall s_tf_h(short c) { S; return c/3; } +EXPORT(unsigned short) __stdcall s_tf_H(unsigned short c) { U; return c/3; } +EXPORT(int) __stdcall s_tf_i(int c) { S; return c/3; } +EXPORT(unsigned int) __stdcall s_tf_I(unsigned int c) { U; return c/3; } +EXPORT(long) __stdcall s_tf_l(long c) { S; return c/3; } +EXPORT(unsigned long) __stdcall s_tf_L(unsigned long c) { U; return c/3; } +EXPORT(PY_LONG_LONG) __stdcall s_tf_q(PY_LONG_LONG c) { S; return c/3; } +EXPORT(unsigned PY_LONG_LONG) __stdcall s_tf_Q(unsigned PY_LONG_LONG c) { U; return c/3; } +EXPORT(float) __stdcall s_tf_f(float c) { S; return c/3; } +EXPORT(double) __stdcall s_tf_d(double c) { S; return c/3; } +#endif +/*******/ + +EXPORT(signed char) tf_bb(signed char x, signed char c) { S; return c/3; } +EXPORT(unsigned char) tf_bB(signed char x, unsigned char c) { U; return c/3; } +EXPORT(short) tf_bh(signed char x, short c) { S; return c/3; } +EXPORT(unsigned short) tf_bH(signed char x, unsigned short c) { U; return c/3; } +EXPORT(int) tf_bi(signed char x, int c) { S; return c/3; } +EXPORT(unsigned int) tf_bI(signed char x, unsigned int c) { U; return c/3; } +EXPORT(long) tf_bl(signed char x, long c) { S; return c/3; } +EXPORT(unsigned long) tf_bL(signed char x, unsigned long c) { U; return c/3; } +EXPORT(PY_LONG_LONG) tf_bq(signed char x, PY_LONG_LONG c) { S; return c/3; } +EXPORT(unsigned PY_LONG_LONG) tf_bQ(signed char x, unsigned PY_LONG_LONG c) { U; return c/3; } +EXPORT(float) tf_bf(signed char x, float c) { S; return c/3; } +EXPORT(double) tf_bd(signed char x, double c) { S; return c/3; } +EXPORT(void) tv_i(int c) { S; return; } + +#ifdef MS_WIN32 +EXPORT(signed char) __stdcall s_tf_bb(signed char x, signed char c) { S; return c/3; } +EXPORT(unsigned char) __stdcall s_tf_bB(signed char x, unsigned char c) { U; return c/3; } +EXPORT(short) __stdcall s_tf_bh(signed char x, short c) { S; return c/3; } +EXPORT(unsigned short) __stdcall s_tf_bH(signed char x, unsigned short c) { U; return c/3; } +EXPORT(int) __stdcall s_tf_bi(signed char x, int c) { S; return c/3; } +EXPORT(unsigned int) __stdcall s_tf_bI(signed char x, unsigned int c) { U; return c/3; } +EXPORT(long) __stdcall s_tf_bl(signed char x, long c) { S; return c/3; } +EXPORT(unsigned long) __stdcall s_tf_bL(signed char x, unsigned long c) { U; return c/3; } +EXPORT(PY_LONG_LONG) __stdcall s_tf_bq(signed char x, PY_LONG_LONG c) { S; return c/3; } +EXPORT(unsigned PY_LONG_LONG) __stdcall s_tf_bQ(signed char x, unsigned PY_LONG_LONG c) { U; return c/3; } +EXPORT(float) __stdcall s_tf_bf(signed char x, float c) { S; return c/3; } +EXPORT(double) __stdcall s_tf_bd(signed char x, double c) { S; return c/3; } +EXPORT(void) __stdcall s_tv_i(int c) { S; return; } +#endif + +/********/ + +#ifndef MS_WIN32 + +typedef struct { + long x; + long y; +} POINT; + +typedef struct { + long left; + long top; + long right; + long bottom; +} RECT; + +#endif + +EXPORT(int) PointInRect(RECT *prc, POINT pt) +{ + if (pt.x < prc->left) + return 0; + if (pt.x > prc->right) + return 0; + if (pt.y < prc->top) + return 0; + if (pt.y > prc->bottom) + return 0; + return 1; +} + +typedef struct { + short x; + short y; +} S2H; + +EXPORT(S2H) ret_2h_func(S2H inp) +{ + inp.x *= 2; + inp.y *= 3; + return inp; +} + +typedef struct { + int a, b, c, d, e, f, g, h; +} S8I; + +EXPORT(S8I) ret_8i_func(S8I inp) +{ + inp.a *= 2; + inp.b *= 3; + inp.c *= 4; + inp.d *= 5; + inp.e *= 6; + inp.f *= 7; + inp.g *= 8; + inp.h *= 9; + return inp; +} + +EXPORT(int) GetRectangle(int flag, RECT *prect) +{ + if (flag == 0) + return 0; + prect->left = (int)flag; + prect->top = (int)flag + 1; + prect->right = (int)flag + 2; + prect->bottom = (int)flag + 3; + return 1; +} + +EXPORT(void) TwoOutArgs(int a, int *pi, int b, int *pj) +{ + *pi += a; + *pj += b; +} + +#ifdef MS_WIN32 +EXPORT(S2H) __stdcall s_ret_2h_func(S2H inp) { return ret_2h_func(inp); } +EXPORT(S8I) __stdcall s_ret_8i_func(S8I inp) { return ret_8i_func(inp); } +#endif + +#ifdef MS_WIN32 +/* Should port this */ +#include <stdlib.h> +#include <search.h> + +EXPORT (HRESULT) KeepObject(IUnknown *punk) +{ + static IUnknown *pobj; + if (punk) + punk->lpVtbl->AddRef(punk); + if (pobj) + pobj->lpVtbl->Release(pobj); + pobj = punk; + return S_OK; +} + +#endif + +DL_EXPORT(void) +init_ctypes_test(void) +{ + Py_InitModule("_ctypes_test", module_methods); +} diff --git a/sys/src/cmd/python/Modules/_ctypes/_ctypes_test.h b/sys/src/cmd/python/Modules/_ctypes/_ctypes_test.h new file mode 100644 index 000000000..060d4d69b --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/_ctypes_test.h @@ -0,0 +1 @@ +extern int _testfunc_i_bhilfd(char b, short h, int i, long l, float f, double d); diff --git a/sys/src/cmd/python/Modules/_ctypes/callbacks.c b/sys/src/cmd/python/Modules/_ctypes/callbacks.c new file mode 100644 index 000000000..e332f00e8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/callbacks.c @@ -0,0 +1,499 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + +#include "Python.h" +#include "compile.h" /* required only for 2.3, as it seems */ +#include "frameobject.h" + +#include <ffi.h> +#ifdef MS_WIN32 +#include <windows.h> +#endif +#include "ctypes.h" + +static void +PrintError(char *msg, ...) +{ + char buf[512]; + PyObject *f = PySys_GetObject("stderr"); + va_list marker; + + va_start(marker, msg); + vsnprintf(buf, sizeof(buf), msg, marker); + va_end(marker); + if (f) + PyFile_WriteString(buf, f); + PyErr_Print(); +} + + +/* after code that pyrex generates */ +void _AddTraceback(char *funcname, char *filename, int lineno) +{ + PyObject *py_srcfile = 0; + PyObject *py_funcname = 0; + PyObject *py_globals = 0; + PyObject *empty_tuple = 0; + PyObject *empty_string = 0; + PyCodeObject *py_code = 0; + PyFrameObject *py_frame = 0; + + py_srcfile = PyString_FromString(filename); + if (!py_srcfile) goto bad; + py_funcname = PyString_FromString(funcname); + if (!py_funcname) goto bad; + py_globals = PyDict_New(); + if (!py_globals) goto bad; + empty_tuple = PyTuple_New(0); + if (!empty_tuple) goto bad; + empty_string = PyString_FromString(""); + if (!empty_string) goto bad; + py_code = PyCode_New( + 0, /*int argcount,*/ + 0, /*int nlocals,*/ + 0, /*int stacksize,*/ + 0, /*int flags,*/ + empty_string, /*PyObject *code,*/ + empty_tuple, /*PyObject *consts,*/ + empty_tuple, /*PyObject *names,*/ + empty_tuple, /*PyObject *varnames,*/ + empty_tuple, /*PyObject *freevars,*/ + empty_tuple, /*PyObject *cellvars,*/ + py_srcfile, /*PyObject *filename,*/ + py_funcname, /*PyObject *name,*/ + lineno, /*int firstlineno,*/ + empty_string /*PyObject *lnotab*/ + ); + if (!py_code) goto bad; + py_frame = PyFrame_New( + PyThreadState_Get(), /*PyThreadState *tstate,*/ + py_code, /*PyCodeObject *code,*/ + py_globals, /*PyObject *globals,*/ + 0 /*PyObject *locals*/ + ); + if (!py_frame) goto bad; + py_frame->f_lineno = lineno; + PyTraceBack_Here(py_frame); + bad: + Py_XDECREF(py_globals); + Py_XDECREF(py_srcfile); + Py_XDECREF(py_funcname); + Py_XDECREF(empty_tuple); + Py_XDECREF(empty_string); + Py_XDECREF(py_code); + Py_XDECREF(py_frame); +} + +#ifdef MS_WIN32 +/* + * We must call AddRef() on non-NULL COM pointers we receive as arguments + * to callback functions - these functions are COM method implementations. + * The Python instances we create have a __del__ method which calls Release(). + * + * The presence of a class attribute named '_needs_com_addref_' triggers this + * behaviour. It would also be possible to call the AddRef() Python method, + * after checking for PyObject_IsTrue(), but this would probably be somewhat + * slower. + */ +static void +TryAddRef(StgDictObject *dict, CDataObject *obj) +{ + IUnknown *punk; + + if (NULL == PyDict_GetItemString((PyObject *)dict, "_needs_com_addref_")) + return; + + punk = *(IUnknown **)obj->b_ptr; + if (punk) + punk->lpVtbl->AddRef(punk); + return; +} +#endif + +/****************************************************************************** + * + * Call the python object with all arguments + * + */ +static void _CallPythonObject(void *mem, + ffi_type *restype, + SETFUNC setfunc, + PyObject *callable, + PyObject *converters, + void **pArgs) +{ + int i; + PyObject *result; + PyObject *arglist = NULL; + int nArgs; +#ifdef WITH_THREAD + PyGILState_STATE state = PyGILState_Ensure(); +#endif + + nArgs = PySequence_Length(converters); + /* Hm. What to return in case of error? + For COM, 0xFFFFFFFF seems better than 0. + */ + if (nArgs < 0) { + PrintError("BUG: PySequence_Length"); + goto Done; + } + + arglist = PyTuple_New(nArgs); + if (!arglist) { + PrintError("PyTuple_New()"); + goto Done; + } + for (i = 0; i < nArgs; ++i) { + /* Note: new reference! */ + PyObject *cnv = PySequence_GetItem(converters, i); + StgDictObject *dict; + if (cnv) + dict = PyType_stgdict(cnv); + else { + PrintError("Getting argument converter %d\n", i); + goto Done; + } + + if (dict && dict->getfunc && !IsSimpleSubType(cnv)) { + PyObject *v = dict->getfunc(*pArgs, dict->size); + if (!v) { + PrintError("create argument %d:\n", i); + Py_DECREF(cnv); + goto Done; + } + PyTuple_SET_ITEM(arglist, i, v); + /* XXX XXX XX + We have the problem that c_byte or c_short have dict->size of + 1 resp. 4, but these parameters are pushed as sizeof(int) bytes. + BTW, the same problem occurrs when they are pushed as parameters + */ + } else if (dict) { + /* Hm, shouldn't we use CData_AtAddress() or something like that instead? */ + CDataObject *obj = (CDataObject *)PyObject_CallFunctionObjArgs(cnv, NULL); + if (!obj) { + PrintError("create argument %d:\n", i); + Py_DECREF(cnv); + goto Done; + } + if (!CDataObject_Check(obj)) { + Py_DECREF(obj); + Py_DECREF(cnv); + PrintError("unexpected result of create argument %d:\n", i); + goto Done; + } + memcpy(obj->b_ptr, *pArgs, dict->size); + PyTuple_SET_ITEM(arglist, i, (PyObject *)obj); +#ifdef MS_WIN32 + TryAddRef(dict, obj); +#endif + } else { + PyErr_SetString(PyExc_TypeError, + "cannot build parameter"); + PrintError("Parsing argument %d\n", i); + Py_DECREF(cnv); + goto Done; + } + Py_DECREF(cnv); + /* XXX error handling! */ + pArgs++; + } + +#define CHECK(what, x) \ +if (x == NULL) _AddTraceback(what, __FILE__, __LINE__ - 1), PyErr_Print() + + result = PyObject_CallObject(callable, arglist); + CHECK("'calling callback function'", result); + if ((restype != &ffi_type_void) && result) { + PyObject *keep; + assert(setfunc); +#ifdef WORDS_BIGENDIAN + /* See the corresponding code in callproc.c, around line 961 */ + if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg)) + mem = (char *)mem + sizeof(ffi_arg) - restype->size; +#endif + keep = setfunc(mem, result, 0); + CHECK("'converting callback result'", keep); + /* keep is an object we have to keep alive so that the result + stays valid. If there is no such object, the setfunc will + have returned Py_None. + + If there is such an object, we have no choice than to keep + it alive forever - but a refcount and/or memory leak will + be the result. EXCEPT when restype is py_object - Python + itself knows how to manage the refcount of these objects. + */ + if (keep == NULL) /* Could not convert callback result. */ + PyErr_WriteUnraisable(callable); + else if (keep == Py_None) /* Nothing to keep */ + Py_DECREF(keep); + else if (setfunc != getentry("O")->setfunc) { + if (-1 == PyErr_Warn(PyExc_RuntimeWarning, + "memory leak in callback function.")) + PyErr_WriteUnraisable(callable); + } + } + Py_XDECREF(result); + Done: + Py_XDECREF(arglist); +#ifdef WITH_THREAD + PyGILState_Release(state); +#endif +} + +static void closure_fcn(ffi_cif *cif, + void *resp, + void **args, + void *userdata) +{ + ffi_info *p = userdata; + + _CallPythonObject(resp, + p->restype, + p->setfunc, + p->callable, + p->converters, + args); +} + +ffi_info *AllocFunctionCallback(PyObject *callable, + PyObject *converters, + PyObject *restype, + int is_cdecl) +{ + int result; + ffi_info *p; + int nArgs, i; + ffi_abi cc; + + nArgs = PySequence_Size(converters); + p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs + 1)); + if (p == NULL) { + PyErr_NoMemory(); + return NULL; + } + p->pcl = MallocClosure(); + if (p->pcl == NULL) { + PyErr_NoMemory(); + goto error; + } + + for (i = 0; i < nArgs; ++i) { + PyObject *cnv = PySequence_GetItem(converters, i); + if (cnv == NULL) + goto error; + p->atypes[i] = GetType(cnv); + Py_DECREF(cnv); + } + p->atypes[i] = NULL; + + if (restype == Py_None) { + p->setfunc = NULL; + p->restype = &ffi_type_void; + } else { + StgDictObject *dict = PyType_stgdict(restype); + if (dict == NULL || dict->setfunc == NULL) { + PyErr_SetString(PyExc_TypeError, + "invalid result type for callback function"); + goto error; + } + p->setfunc = dict->setfunc; + p->restype = &dict->ffi_type_pointer; + } + + cc = FFI_DEFAULT_ABI; +#if defined(MS_WIN32) && !defined(_WIN32_WCE) + if (is_cdecl == 0) + cc = FFI_STDCALL; +#endif + result = ffi_prep_cif(&p->cif, cc, nArgs, + GetType(restype), + &p->atypes[0]); + if (result != FFI_OK) { + PyErr_Format(PyExc_RuntimeError, + "ffi_prep_cif failed with %d", result); + goto error; + } + result = ffi_prep_closure(p->pcl, &p->cif, closure_fcn, p); + if (result != FFI_OK) { + PyErr_Format(PyExc_RuntimeError, + "ffi_prep_closure failed with %d", result); + goto error; + } + + p->converters = converters; + p->callable = callable; + return p; + + error: + if (p) { + if (p->pcl) + FreeClosure(p->pcl); + PyMem_Free(p); + } + return NULL; +} + +/**************************************************************************** + * + * callback objects: initialization + */ + +void init_callbacks_in_module(PyObject *m) +{ + if (PyType_Ready((PyTypeObject *)&PyType_Type) < 0) + return; +} + +#ifdef MS_WIN32 + +static void LoadPython(void) +{ + if (!Py_IsInitialized()) { +#ifdef WITH_THREAD + PyEval_InitThreads(); +#endif + Py_Initialize(); + } +} + +/******************************************************************/ + +long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) +{ + PyObject *mod, *func, *result; + long retval; + static PyObject *context; + + if (context == NULL) + context = PyString_FromString("_ctypes.DllGetClassObject"); + + mod = PyImport_ImportModule("ctypes"); + if (!mod) { + PyErr_WriteUnraisable(context ? context : Py_None); + /* There has been a warning before about this already */ + return E_FAIL; + } + + func = PyObject_GetAttrString(mod, "DllGetClassObject"); + Py_DECREF(mod); + if (!func) { + PyErr_WriteUnraisable(context ? context : Py_None); + return E_FAIL; + } + + result = PyObject_CallFunction(func, + "iii", rclsid, riid, ppv); + Py_DECREF(func); + if (!result) { + PyErr_WriteUnraisable(context ? context : Py_None); + return E_FAIL; + } + + retval = PyInt_AsLong(result); + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(context ? context : Py_None); + retval = E_FAIL; + } + Py_DECREF(result); + return retval; +} + +STDAPI DllGetClassObject(REFCLSID rclsid, + REFIID riid, + LPVOID *ppv) +{ + long result; +#ifdef WITH_THREAD + PyGILState_STATE state; +#endif + + LoadPython(); +#ifdef WITH_THREAD + state = PyGILState_Ensure(); +#endif + result = Call_GetClassObject(rclsid, riid, ppv); +#ifdef WITH_THREAD + PyGILState_Release(state); +#endif + return result; +} + +long Call_CanUnloadNow(void) +{ + PyObject *mod, *func, *result; + long retval; + static PyObject *context; + + if (context == NULL) + context = PyString_FromString("_ctypes.DllCanUnloadNow"); + + mod = PyImport_ImportModule("ctypes"); + if (!mod) { +/* OutputDebugString("Could not import ctypes"); */ + /* We assume that this error can only occur when shutting + down, so we silently ignore it */ + PyErr_Clear(); + return E_FAIL; + } + /* Other errors cannot be raised, but are printed to stderr */ + func = PyObject_GetAttrString(mod, "DllCanUnloadNow"); + Py_DECREF(mod); + if (!func) { + PyErr_WriteUnraisable(context ? context : Py_None); + return E_FAIL; + } + + result = PyObject_CallFunction(func, NULL); + Py_DECREF(func); + if (!result) { + PyErr_WriteUnraisable(context ? context : Py_None); + return E_FAIL; + } + + retval = PyInt_AsLong(result); + if (PyErr_Occurred()) { + PyErr_WriteUnraisable(context ? context : Py_None); + retval = E_FAIL; + } + Py_DECREF(result); + return retval; +} + +/* + DllRegisterServer and DllUnregisterServer still missing +*/ + +STDAPI DllCanUnloadNow(void) +{ + long result; +#ifdef WITH_THREAD + PyGILState_STATE state = PyGILState_Ensure(); +#endif + result = Call_CanUnloadNow(); +#ifdef WITH_THREAD + PyGILState_Release(state); +#endif + return result; +} + +#ifndef Py_NO_ENABLE_SHARED +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRes) +{ + switch(fdwReason) { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); + break; + } + return TRUE; +} +#endif + +#endif + +/* + Local Variables: + compile-command: "cd .. && python setup.py -q build_ext" + End: +*/ diff --git a/sys/src/cmd/python/Modules/_ctypes/callproc.c b/sys/src/cmd/python/Modules/_ctypes/callproc.c new file mode 100644 index 000000000..e0765e917 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/callproc.c @@ -0,0 +1,1581 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + + +/* + * History: First version dated from 3/97, derived from my SCMLIB version + * for win16. + */ +/* + * Related Work: + * - calldll http://www.nightmare.com/software.html + * - libffi http://sourceware.cygnus.com/libffi/ + * - ffcall http://clisp.cons.org/~haible/packages-ffcall.html + * and, of course, Don Beaudry's MESS package, but this is more ctypes + * related. + */ + + +/* + How are functions called, and how are parameters converted to C ? + + 1. _ctypes.c::CFuncPtr_call receives an argument tuple 'inargs' and a + keyword dictionary 'kwds'. + + 2. After several checks, _build_callargs() is called which returns another + tuple 'callargs'. This may be the same tuple as 'inargs', a slice of + 'inargs', or a completely fresh tuple, depending on several things (is is a + COM method, are 'paramflags' available). + + 3. _build_callargs also calculates bitarrays containing indexes into + the callargs tuple, specifying how to build the return value(s) of + the function. + + 4. _CallProc is then called with the 'callargs' tuple. _CallProc first + allocates two arrays. The first is an array of 'struct argument' items, the + second array has 'void *' entried. + + 5. If 'converters' are present (converters is a sequence of argtypes' + from_param methods), for each item in 'callargs' converter is called and the + result passed to ConvParam. If 'converters' are not present, each argument + is directly passed to ConvParm. + + 6. For each arg, ConvParam stores the contained C data (or a pointer to it, + for structures) into the 'struct argument' array. + + 7. Finally, a loop fills the 'void *' array so that each item points to the + data contained in or pointed to by the 'struct argument' array. + + 8. The 'void *' argument array is what _call_function_pointer + expects. _call_function_pointer then has very little to do - only some + libffi specific stuff, then it calls ffi_call. + + So, there are 4 data structures holding processed arguments: + - the inargs tuple (in CFuncPtr_call) + - the callargs tuple (in CFuncPtr_call) + - the 'struct argguments' array + - the 'void *' array + + */ + +#include "Python.h" +#include "structmember.h" + +#ifdef MS_WIN32 +#include <windows.h> +#else +#include "ctypes_dlfcn.h" +#endif + +#ifdef MS_WIN32 +#include <malloc.h> +#endif + +#include <ffi.h> +#include "ctypes.h" + +#if defined(_DEBUG) || defined(__MINGW32__) +/* Don't use structured exception handling on Windows if this is defined. + MingW, AFAIK, doesn't support it. +*/ +#define DONT_USE_SEH +#endif + +#ifdef MS_WIN32 +PyObject *ComError; + +static TCHAR *FormatError(DWORD code) +{ + TCHAR *lpMsgBuf; + DWORD n; + n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL); + if (n) { + while (isspace(lpMsgBuf[n-1])) + --n; + lpMsgBuf[n] = '\0'; /* rstrip() */ + } + return lpMsgBuf; +} + +#ifndef DONT_USE_SEH +void SetException(DWORD code, EXCEPTION_RECORD *pr) +{ + TCHAR *lpMsgBuf; + lpMsgBuf = FormatError(code); + if(lpMsgBuf) { + PyErr_SetFromWindowsErr(code); + LocalFree(lpMsgBuf); + } else { + switch (code) { + case EXCEPTION_ACCESS_VIOLATION: + /* The thread attempted to read from or write + to a virtual address for which it does not + have the appropriate access. */ + if (pr->ExceptionInformation[0] == 0) + PyErr_Format(PyExc_WindowsError, + "exception: access violation reading %p", + pr->ExceptionInformation[1]); + else + PyErr_Format(PyExc_WindowsError, + "exception: access violation writing %p", + pr->ExceptionInformation[1]); + break; + case EXCEPTION_BREAKPOINT: + /* A breakpoint was encountered. */ + PyErr_SetString(PyExc_WindowsError, + "exception: breakpoint encountered"); + break; + + case EXCEPTION_DATATYPE_MISALIGNMENT: + /* The thread attempted to read or write data that is + misaligned on hardware that does not provide + alignment. For example, 16-bit values must be + aligned on 2-byte boundaries, 32-bit values on + 4-byte boundaries, and so on. */ + PyErr_SetString(PyExc_WindowsError, + "exception: datatype misalignment"); + break; + + case EXCEPTION_SINGLE_STEP: + /* A trace trap or other single-instruction mechanism + signaled that one instruction has been executed. */ + PyErr_SetString(PyExc_WindowsError, + "exception: single step"); + break; + + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + /* The thread attempted to access an array element + that is out of bounds, and the underlying hardware + supports bounds checking. */ + PyErr_SetString(PyExc_WindowsError, + "exception: array bounds exceeded"); + break; + + case EXCEPTION_FLT_DENORMAL_OPERAND: + /* One of the operands in a floating-point operation + is denormal. A denormal value is one that is too + small to represent as a standard floating-point + value. */ + PyErr_SetString(PyExc_WindowsError, + "exception: floating-point operand denormal"); + break; + + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + /* The thread attempted to divide a floating-point + value by a floating-point divisor of zero. */ + PyErr_SetString(PyExc_WindowsError, + "exception: float divide by zero"); + break; + + case EXCEPTION_FLT_INEXACT_RESULT: + /* The result of a floating-point operation cannot be + represented exactly as a decimal fraction. */ + PyErr_SetString(PyExc_WindowsError, + "exception: float inexact"); + break; + + case EXCEPTION_FLT_INVALID_OPERATION: + /* This exception represents any floating-point + exception not included in this list. */ + PyErr_SetString(PyExc_WindowsError, + "exception: float invalid operation"); + break; + + case EXCEPTION_FLT_OVERFLOW: + /* The exponent of a floating-point operation is + greater than the magnitude allowed by the + corresponding type. */ + PyErr_SetString(PyExc_WindowsError, + "exception: float overflow"); + break; + + case EXCEPTION_FLT_STACK_CHECK: + /* The stack overflowed or underflowed as the result + of a floating-point operation. */ + PyErr_SetString(PyExc_WindowsError, + "exception: stack over/underflow"); + break; + + case EXCEPTION_STACK_OVERFLOW: + /* The stack overflowed or underflowed as the result + of a floating-point operation. */ + PyErr_SetString(PyExc_WindowsError, + "exception: stack overflow"); + break; + + case EXCEPTION_FLT_UNDERFLOW: + /* The exponent of a floating-point operation is less + than the magnitude allowed by the corresponding + type. */ + PyErr_SetString(PyExc_WindowsError, + "exception: float underflow"); + break; + + case EXCEPTION_INT_DIVIDE_BY_ZERO: + /* The thread attempted to divide an integer value by + an integer divisor of zero. */ + PyErr_SetString(PyExc_WindowsError, + "exception: integer divide by zero"); + break; + + case EXCEPTION_INT_OVERFLOW: + /* The result of an integer operation caused a carry + out of the most significant bit of the result. */ + PyErr_SetString(PyExc_WindowsError, + "exception: integer overflow"); + break; + + case EXCEPTION_PRIV_INSTRUCTION: + /* The thread attempted to execute an instruction + whose operation is not allowed in the current + machine mode. */ + PyErr_SetString(PyExc_WindowsError, + "exception: priviledged instruction"); + break; + + case EXCEPTION_NONCONTINUABLE_EXCEPTION: + /* The thread attempted to continue execution after a + noncontinuable exception occurred. */ + PyErr_SetString(PyExc_WindowsError, + "exception: nocontinuable"); + break; + default: + printf("error %d\n", code); + PyErr_Format(PyExc_WindowsError, + "exception code 0x%08x", + code); + break; + } + } +} + +static DWORD HandleException(EXCEPTION_POINTERS *ptrs, + DWORD *pdw, EXCEPTION_RECORD *record) +{ + *pdw = ptrs->ExceptionRecord->ExceptionCode; + *record = *ptrs->ExceptionRecord; + return EXCEPTION_EXECUTE_HANDLER; +} +#endif + +static PyObject * +check_hresult(PyObject *self, PyObject *args) +{ + HRESULT hr; + if (!PyArg_ParseTuple(args, "i", &hr)) + return NULL; + if (FAILED(hr)) + return PyErr_SetFromWindowsErr(hr); + return PyInt_FromLong(hr); +} + +#endif + +/**************************************************************/ + +PyCArgObject * +new_CArgObject(void) +{ + PyCArgObject *p; + p = PyObject_New(PyCArgObject, &PyCArg_Type); + if (p == NULL) + return NULL; + p->pffi_type = NULL; + p->tag = '\0'; + p->obj = NULL; + memset(&p->value, 0, sizeof(p->value)); + return p; +} + +static void +PyCArg_dealloc(PyCArgObject *self) +{ + Py_XDECREF(self->obj); + PyObject_Del(self); +} + +static PyObject * +PyCArg_repr(PyCArgObject *self) +{ + char buffer[256]; + switch(self->tag) { + case 'b': + case 'B': + sprintf(buffer, "<cparam '%c' (%d)>", + self->tag, self->value.b); + break; + case 'h': + case 'H': + sprintf(buffer, "<cparam '%c' (%d)>", + self->tag, self->value.h); + break; + case 'i': + case 'I': + sprintf(buffer, "<cparam '%c' (%d)>", + self->tag, self->value.i); + break; + case 'l': + case 'L': + sprintf(buffer, "<cparam '%c' (%ld)>", + self->tag, self->value.l); + break; + +#ifdef HAVE_LONG_LONG + case 'q': + case 'Q': + sprintf(buffer, +#ifdef MS_WIN32 + "<cparam '%c' (%I64d)>", +#else + "<cparam '%c' (%qd)>", +#endif + self->tag, self->value.q); + break; +#endif + case 'd': + sprintf(buffer, "<cparam '%c' (%f)>", + self->tag, self->value.d); + break; + case 'f': + sprintf(buffer, "<cparam '%c' (%f)>", + self->tag, self->value.f); + break; + + case 'c': + sprintf(buffer, "<cparam '%c' (%c)>", + self->tag, self->value.c); + break; + +/* Hm, are these 'z' and 'Z' codes useful at all? + Shouldn't they be replaced by the functionality of c_string + and c_wstring ? +*/ + case 'z': + case 'Z': + case 'P': + sprintf(buffer, "<cparam '%c' (%08lx)>", + self->tag, (long)self->value.p); + break; + + default: + sprintf(buffer, "<cparam '%c' at %08lx>", + self->tag, (long)self); + break; + } + return PyString_FromString(buffer); +} + +static PyMemberDef PyCArgType_members[] = { + { "_obj", T_OBJECT, + offsetof(PyCArgObject, obj), READONLY, + "the wrapped object" }, + { NULL }, +}; + +PyTypeObject PyCArg_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "CArgObject", + sizeof(PyCArgObject), + 0, + (destructor)PyCArg_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)PyCArg_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + PyCArgType_members, /* tp_members */ +}; + +/****************************************************************/ +/* + * Convert a PyObject * into a parameter suitable to pass to an + * C function call. + * + * 1. Python integers are converted to C int and passed by value. + * + * 2. 3-tuples are expected to have a format character in the first + * item, which must be 'i', 'f', 'd', 'q', or 'P'. + * The second item will have to be an integer, float, double, long long + * or integer (denoting an address void *), will be converted to the + * corresponding C data type and passed by value. + * + * 3. Other Python objects are tested for an '_as_parameter_' attribute. + * The value of this attribute must be an integer which will be passed + * by value, or a 2-tuple or 3-tuple which will be used according + * to point 2 above. The third item (if any), is ignored. It is normally + * used to keep the object alive where this parameter refers to. + * XXX This convention is dangerous - you can construct arbitrary tuples + * in Python and pass them. Would it be safer to use a custom container + * datatype instead of a tuple? + * + * 4. Other Python objects cannot be passed as parameters - an exception is raised. + * + * 5. ConvParam will store the converted result in a struct containing format + * and value. + */ + +union result { + char c; + char b; + short h; + int i; + long l; +#ifdef HAVE_LONG_LONG + PY_LONG_LONG q; +#endif + double d; + float f; + void *p; +}; + +struct argument { + ffi_type *ffi_type; + PyObject *keep; + union result value; +}; + +/* + * Convert a single Python object into a PyCArgObject and return it. + */ +static int ConvParam(PyObject *obj, int index, struct argument *pa) +{ + StgDictObject *dict; + pa->keep = NULL; /* so we cannot forget it later */ + + dict = PyObject_stgdict(obj); + if (dict) { + PyCArgObject *carg; + assert(dict->paramfunc); + /* If it has an stgdict, it is a CDataObject */ + carg = dict->paramfunc((CDataObject *)obj); + pa->ffi_type = carg->pffi_type; + memcpy(&pa->value, &carg->value, sizeof(pa->value)); + pa->keep = (PyObject *)carg; + return 0; + } + + if (PyCArg_CheckExact(obj)) { + PyCArgObject *carg = (PyCArgObject *)obj; + pa->ffi_type = carg->pffi_type; + Py_INCREF(obj); + pa->keep = obj; + memcpy(&pa->value, &carg->value, sizeof(pa->value)); + return 0; + } + + /* check for None, integer, string or unicode and use directly if successful */ + if (obj == Py_None) { + pa->ffi_type = &ffi_type_pointer; + pa->value.p = NULL; + return 0; + } + + if (PyInt_Check(obj)) { + pa->ffi_type = &ffi_type_sint; + pa->value.i = PyInt_AS_LONG(obj); + return 0; + } + + if (PyLong_Check(obj)) { + pa->ffi_type = &ffi_type_sint; + pa->value.i = (long)PyLong_AsUnsignedLong(obj); + if (pa->value.i == -1 && PyErr_Occurred()) { + PyErr_Clear(); + pa->value.i = PyLong_AsLong(obj); + if (pa->value.i == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_OverflowError, + "long int too long to convert"); + return -1; + } + } + return 0; + } + + if (PyString_Check(obj)) { + pa->ffi_type = &ffi_type_pointer; + pa->value.p = PyString_AS_STRING(obj); + Py_INCREF(obj); + pa->keep = obj; + return 0; + } + +#ifdef CTYPES_UNICODE + if (PyUnicode_Check(obj)) { +#ifdef HAVE_USABLE_WCHAR_T + pa->ffi_type = &ffi_type_pointer; + pa->value.p = PyUnicode_AS_UNICODE(obj); + Py_INCREF(obj); + pa->keep = obj; + return 0; +#else + int size = PyUnicode_GET_SIZE(obj); + size += 1; /* terminating NUL */ + size *= sizeof(wchar_t); + pa->value.p = PyMem_Malloc(size); + if (!pa->value.p) + return -1; + memset(pa->value.p, 0, size); + pa->keep = PyCObject_FromVoidPtr(pa->value.p, PyMem_Free); + if (!pa->keep) { + PyMem_Free(pa->value.p); + return -1; + } + if (-1 == PyUnicode_AsWideChar((PyUnicodeObject *)obj, + pa->value.p, PyUnicode_GET_SIZE(obj))) + return -1; + return 0; +#endif + } +#endif + + { + PyObject *arg; + arg = PyObject_GetAttrString(obj, "_as_parameter_"); + /* Which types should we exactly allow here? + integers are required for using Python classes + as parameters (they have to expose the '_as_parameter_' + attribute) + */ + if (arg) { + int result; + result = ConvParam(arg, index, pa); + Py_DECREF(arg); + return result; + } + PyErr_Format(PyExc_TypeError, + "Don't know how to convert parameter %d", index); + return -1; + } +} + + +ffi_type *GetType(PyObject *obj) +{ + StgDictObject *dict; + if (obj == NULL) + return &ffi_type_sint; + dict = PyType_stgdict(obj); + if (dict == NULL) + return &ffi_type_sint; +#if defined(MS_WIN32) && !defined(_WIN32_WCE) + /* This little trick works correctly with MSVC. + It returns small structures in registers + */ + if (dict->ffi_type_pointer.type == FFI_TYPE_STRUCT) { + if (dict->ffi_type_pointer.size <= 4) + return &ffi_type_sint32; + else if (dict->ffi_type_pointer.size <= 8) + return &ffi_type_sint64; + } +#endif + return &dict->ffi_type_pointer; +} + + +/* + * libffi uses: + * + * ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, + * unsigned int nargs, + * ffi_type *rtype, + * ffi_type **atypes); + * + * and then + * + * void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues); + */ +static int _call_function_pointer(int flags, + PPROC pProc, + void **avalues, + ffi_type **atypes, + ffi_type *restype, + void *resmem, + int argcount) +{ +#ifdef WITH_THREAD + PyThreadState *_save = NULL; /* For Py_BLOCK_THREADS and Py_UNBLOCK_THREADS */ +#endif + ffi_cif cif; + int cc; +#ifdef MS_WIN32 + int delta; +#ifndef DONT_USE_SEH + DWORD dwExceptionCode = 0; + EXCEPTION_RECORD record; +#endif +#endif + /* XXX check before here */ + if (restype == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "No ffi_type for result"); + return -1; + } + + cc = FFI_DEFAULT_ABI; +#if defined(MS_WIN32) && !defined(_WIN32_WCE) + if ((flags & FUNCFLAG_CDECL) == 0) + cc = FFI_STDCALL; +#endif + if (FFI_OK != ffi_prep_cif(&cif, + cc, + argcount, + restype, + atypes)) { + PyErr_SetString(PyExc_RuntimeError, + "ffi_prep_cif failed"); + return -1; + } + +#ifdef WITH_THREAD + if ((flags & FUNCFLAG_PYTHONAPI) == 0) + Py_UNBLOCK_THREADS +#endif +#ifdef MS_WIN32 +#ifndef DONT_USE_SEH + __try { +#endif + delta = +#endif + ffi_call(&cif, (void *)pProc, resmem, avalues); +#ifdef MS_WIN32 +#ifndef DONT_USE_SEH + } + __except (HandleException(GetExceptionInformation(), + &dwExceptionCode, &record)) { + ; + } +#endif +#endif +#ifdef WITH_THREAD + if ((flags & FUNCFLAG_PYTHONAPI) == 0) + Py_BLOCK_THREADS +#endif +#ifdef MS_WIN32 +#ifndef DONT_USE_SEH + if (dwExceptionCode) { + SetException(dwExceptionCode, &record); + return -1; + } +#endif + if (delta < 0) { + if (flags & FUNCFLAG_CDECL) + PyErr_Format(PyExc_ValueError, + "Procedure called with not enough " + "arguments (%d bytes missing) " + "or wrong calling convention", + -delta); + else + PyErr_Format(PyExc_ValueError, + "Procedure probably called with not enough " + "arguments (%d bytes missing)", + -delta); + return -1; + } else if (delta > 0) { + PyErr_Format(PyExc_ValueError, + "Procedure probably called with too many " + "arguments (%d bytes in excess)", + delta); + return -1; + } +#endif + if ((flags & FUNCFLAG_PYTHONAPI) && PyErr_Occurred()) + return -1; + return 0; +} + +/* + * Convert the C value in result into a Python object, depending on restype. + * + * - If restype is NULL, return a Python integer. + * - If restype is None, return None. + * - If restype is a simple ctypes type (c_int, c_void_p), call the type's getfunc, + * pass the result to checker and return the result. + * - If restype is another ctypes type, return an instance of that. + * - Otherwise, call restype and return the result. + */ +static PyObject *GetResult(PyObject *restype, void *result, PyObject *checker) +{ + StgDictObject *dict; + PyObject *retval, *v; + + if (restype == NULL) + return PyInt_FromLong(*(int *)result); + + if (restype == Py_None) { + Py_INCREF(Py_None); + return Py_None; + } + + dict = PyType_stgdict(restype); + if (dict == NULL) + return PyObject_CallFunction(restype, "i", *(int *)result); + + if (dict->getfunc && !IsSimpleSubType(restype)) { + retval = dict->getfunc(result, dict->size); + /* If restype is py_object (detected by comparing getfunc with + O_get), we have to call Py_DECREF because O_get has already + called Py_INCREF. + */ + if (dict->getfunc == getentry("O")->getfunc) { + Py_DECREF(retval); + } + } else + retval = CData_FromBaseObj(restype, NULL, 0, result); + + if (!checker || !retval) + return retval; + + v = PyObject_CallFunctionObjArgs(checker, retval, NULL); + if (v == NULL) + _AddTraceback("GetResult", __FILE__, __LINE__-2); + Py_DECREF(retval); + return v; +} + +/* + * Raise a new exception 'exc_class', adding additional text to the original + * exception string. + */ +void Extend_Error_Info(PyObject *exc_class, char *fmt, ...) +{ + va_list vargs; + PyObject *tp, *v, *tb, *s, *cls_str, *msg_str; + + va_start(vargs, fmt); + s = PyString_FromFormatV(fmt, vargs); + va_end(vargs); + if (!s) + return; + + PyErr_Fetch(&tp, &v, &tb); + PyErr_NormalizeException(&tp, &v, &tb); + cls_str = PyObject_Str(tp); + if (cls_str) { + PyString_ConcatAndDel(&s, cls_str); + PyString_ConcatAndDel(&s, PyString_FromString(": ")); + if (s == NULL) + goto error; + } else + PyErr_Clear(); + msg_str = PyObject_Str(v); + if (msg_str) + PyString_ConcatAndDel(&s, msg_str); + else { + PyErr_Clear(); + PyString_ConcatAndDel(&s, PyString_FromString("???")); + if (s == NULL) + goto error; + } + PyErr_SetObject(exc_class, s); +error: + Py_XDECREF(tp); + Py_XDECREF(v); + Py_XDECREF(tb); + Py_XDECREF(s); +} + + +#ifdef MS_WIN32 + +static PyObject * +GetComError(HRESULT errcode, GUID *riid, IUnknown *pIunk) +{ + HRESULT hr; + ISupportErrorInfo *psei = NULL; + IErrorInfo *pei = NULL; + BSTR descr=NULL, helpfile=NULL, source=NULL; + GUID guid; + DWORD helpcontext=0; + LPOLESTR progid; + PyObject *obj; + TCHAR *text; + + /* We absolutely have to release the GIL during COM method calls, + otherwise we may get a deadlock! + */ +#ifdef WITH_THREAD + Py_BEGIN_ALLOW_THREADS +#endif + + hr = pIunk->lpVtbl->QueryInterface(pIunk, &IID_ISupportErrorInfo, (void **)&psei); + if (FAILED(hr)) + goto failed; + + hr = psei->lpVtbl->InterfaceSupportsErrorInfo(psei, riid); + psei->lpVtbl->Release(psei); + if (FAILED(hr)) + goto failed; + + hr = GetErrorInfo(0, &pei); + if (hr != S_OK) + goto failed; + + pei->lpVtbl->GetDescription(pei, &descr); + pei->lpVtbl->GetGUID(pei, &guid); + pei->lpVtbl->GetHelpContext(pei, &helpcontext); + pei->lpVtbl->GetHelpFile(pei, &helpfile); + pei->lpVtbl->GetSource(pei, &source); + + pei->lpVtbl->Release(pei); + + failed: +#ifdef WITH_THREAD + Py_END_ALLOW_THREADS +#endif + + progid = NULL; + ProgIDFromCLSID(&guid, &progid); + + text = FormatError(errcode); + obj = Py_BuildValue( +#ifdef _UNICODE + "iu(uuuiu)", +#else + "is(uuuiu)", +#endif + errcode, + text, + descr, source, helpfile, helpcontext, + progid); + if (obj) { + PyErr_SetObject(ComError, obj); + Py_DECREF(obj); + } + LocalFree(text); + + if (descr) + SysFreeString(descr); + if (helpfile) + SysFreeString(helpfile); + if (source) + SysFreeString(source); + + return NULL; +} +#endif + +/* + * Requirements, must be ensured by the caller: + * - argtuple is tuple of arguments + * - argtypes is either NULL, or a tuple of the same size as argtuple + * + * - XXX various requirements for restype, not yet collected + */ +PyObject *_CallProc(PPROC pProc, + PyObject *argtuple, +#ifdef MS_WIN32 + IUnknown *pIunk, + GUID *iid, +#endif + int flags, + PyObject *argtypes, /* misleading name: This is a tuple of + methods, not types: the .from_param + class methods of the types */ + PyObject *restype, + PyObject *checker) +{ + int i, n, argcount, argtype_count; + void *resbuf; + struct argument *args, *pa; + ffi_type **atypes; + ffi_type *rtype; + void **avalues; + PyObject *retval = NULL; + + n = argcount = PyTuple_GET_SIZE(argtuple); +#ifdef MS_WIN32 + /* an optional COM object this pointer */ + if (pIunk) + ++argcount; +#endif + + args = (struct argument *)alloca(sizeof(struct argument) * argcount); + if (!args) { + PyErr_NoMemory(); + return NULL; + } + memset(args, 0, sizeof(struct argument) * argcount); + argtype_count = argtypes ? PyTuple_GET_SIZE(argtypes) : 0; +#ifdef MS_WIN32 + if (pIunk) { + args[0].ffi_type = &ffi_type_pointer; + args[0].value.p = pIunk; + pa = &args[1]; + } else +#endif + pa = &args[0]; + + /* Convert the arguments */ + for (i = 0; i < n; ++i, ++pa) { + PyObject *converter; + PyObject *arg; + int err; + + arg = PyTuple_GET_ITEM(argtuple, i); /* borrowed ref */ + /* For cdecl functions, we allow more actual arguments + than the length of the argtypes tuple. + This is checked in _ctypes::CFuncPtr_Call + */ + if (argtypes && argtype_count > i) { + PyObject *v; + converter = PyTuple_GET_ITEM(argtypes, i); + v = PyObject_CallFunctionObjArgs(converter, + arg, + NULL); + if (v == NULL) { + Extend_Error_Info(PyExc_ArgError, "argument %d: ", i+1); + goto cleanup; + } + + err = ConvParam(v, i+1, pa); + Py_DECREF(v); + if (-1 == err) { + Extend_Error_Info(PyExc_ArgError, "argument %d: ", i+1); + goto cleanup; + } + } else { + err = ConvParam(arg, i+1, pa); + if (-1 == err) { + Extend_Error_Info(PyExc_ArgError, "argument %d: ", i+1); + goto cleanup; /* leaking ? */ + } + } + } + + rtype = GetType(restype); + resbuf = alloca(max(rtype->size, sizeof(ffi_arg))); + + avalues = (void **)alloca(sizeof(void *) * argcount); + atypes = (ffi_type **)alloca(sizeof(ffi_type *) * argcount); + if (!resbuf || !avalues || !atypes) { + PyErr_NoMemory(); + goto cleanup; + } + for (i = 0; i < argcount; ++i) { + atypes[i] = args[i].ffi_type; + if (atypes[i]->type == FFI_TYPE_STRUCT) + avalues[i] = (void *)args[i].value.p; + else + avalues[i] = (void *)&args[i].value; + } + + if (-1 == _call_function_pointer(flags, pProc, avalues, atypes, + rtype, resbuf, argcount)) + goto cleanup; + +#ifdef WORDS_BIGENDIAN + /* libffi returns the result in a buffer with sizeof(ffi_arg). This + causes problems on big endian machines, since the result buffer + address cannot simply be used as result pointer, instead we must + adjust the pointer value: + */ + /* + XXX I should find out and clarify why this is needed at all, + especially why adjusting for ffi_type_float must be avoided on + 64-bit platforms. + */ + if (rtype->type != FFI_TYPE_FLOAT + && rtype->type != FFI_TYPE_STRUCT + && rtype->size < sizeof(ffi_arg)) + resbuf = (char *)resbuf + sizeof(ffi_arg) - rtype->size; +#endif + +#ifdef MS_WIN32 + if (iid && pIunk) { + if (*(int *)resbuf & 0x80000000) + retval = GetComError(*(HRESULT *)resbuf, iid, pIunk); + else + retval = PyInt_FromLong(*(int *)resbuf); + } else if (flags & FUNCFLAG_HRESULT) { + if (*(int *)resbuf & 0x80000000) + retval = PyErr_SetFromWindowsErr(*(int *)resbuf); + else + retval = PyInt_FromLong(*(int *)resbuf); + } else +#endif + retval = GetResult(restype, resbuf, checker); + cleanup: + for (i = 0; i < argcount; ++i) + Py_XDECREF(args[i].keep); + return retval; +} + +#ifdef MS_WIN32 + +#ifdef _UNICODE +# define PYBUILD_TSTR "u" +#else +# define PYBUILD_TSTR "s" +# ifndef _T +# define _T(text) text +# endif +#endif + +static char format_error_doc[] = +"FormatError([integer]) -> string\n\ +\n\ +Convert a win32 error code into a string. If the error code is not\n\ +given, the return value of a call to GetLastError() is used.\n"; +static PyObject *format_error(PyObject *self, PyObject *args) +{ + PyObject *result; + TCHAR *lpMsgBuf; + DWORD code = 0; + if (!PyArg_ParseTuple(args, "|i:FormatError", &code)) + return NULL; + if (code == 0) + code = GetLastError(); + lpMsgBuf = FormatError(code); + if (lpMsgBuf) { + result = Py_BuildValue(PYBUILD_TSTR, lpMsgBuf); + LocalFree(lpMsgBuf); + } else { + result = Py_BuildValue("s", "<no description>"); + } + return result; +} + +static char load_library_doc[] = +"LoadLibrary(name) -> handle\n\ +\n\ +Load an executable (usually a DLL), and return a handle to it.\n\ +The handle may be used to locate exported functions in this\n\ +module.\n"; +static PyObject *load_library(PyObject *self, PyObject *args) +{ + TCHAR *name; + PyObject *nameobj; + PyObject *ignored; + HMODULE hMod; + if (!PyArg_ParseTuple(args, "O|O:LoadLibrary", &nameobj, &ignored)) + return NULL; +#ifdef _UNICODE + name = alloca((PyString_Size(nameobj) + 1) * sizeof(WCHAR)); + if (!name) { + PyErr_NoMemory(); + return NULL; + } + + { + int r; + char *aname = PyString_AsString(nameobj); + if(!aname) + return NULL; + r = MultiByteToWideChar(CP_ACP, 0, aname, -1, name, PyString_Size(nameobj) + 1); + name[r] = 0; + } +#else + name = PyString_AsString(nameobj); + if(!name) + return NULL; +#endif + + hMod = LoadLibrary(name); + if (!hMod) + return PyErr_SetFromWindowsErr(GetLastError()); + return Py_BuildValue("i", hMod); +} + +static char free_library_doc[] = +"FreeLibrary(handle) -> void\n\ +\n\ +Free the handle of an executable previously loaded by LoadLibrary.\n"; +static PyObject *free_library(PyObject *self, PyObject *args) +{ + HMODULE hMod; + if (!PyArg_ParseTuple(args, "i:FreeLibrary", &hMod)) + return NULL; + if (!FreeLibrary(hMod)) + return PyErr_SetFromWindowsErr(GetLastError()); + Py_INCREF(Py_None); + return Py_None; +} + +/* obsolete, should be removed */ +/* Only used by sample code (in samples\Windows\COM.py) */ +static PyObject * +call_commethod(PyObject *self, PyObject *args) +{ + IUnknown *pIunk; + int index; + PyObject *arguments; + PPROC *lpVtbl; + PyObject *result; + CDataObject *pcom; + PyObject *argtypes = NULL; + + if (!PyArg_ParseTuple(args, + "OiO!|O!", + &pcom, &index, + &PyTuple_Type, &arguments, + &PyTuple_Type, &argtypes)) + return NULL; + + if (argtypes && (PyTuple_GET_SIZE(arguments) != PyTuple_GET_SIZE(argtypes))) { + PyErr_Format(PyExc_TypeError, + "Method takes %d arguments (%d given)", + PyTuple_GET_SIZE(argtypes), PyTuple_GET_SIZE(arguments)); + return NULL; + } + + if (!CDataObject_Check(pcom) || (pcom->b_size != sizeof(void *))) { + PyErr_Format(PyExc_TypeError, + "COM Pointer expected instead of %s instance", + pcom->ob_type->tp_name); + return NULL; + } + + if ((*(void **)(pcom->b_ptr)) == NULL) { + PyErr_SetString(PyExc_ValueError, + "The COM 'this' pointer is NULL"); + return NULL; + } + + pIunk = (IUnknown *)(*(void **)(pcom->b_ptr)); + lpVtbl = (PPROC *)(pIunk->lpVtbl); + + result = _CallProc(lpVtbl[index], + arguments, +#ifdef MS_WIN32 + pIunk, + NULL, +#endif + FUNCFLAG_HRESULT, /* flags */ + argtypes, /* self->argtypes */ + NULL, /* self->restype */ + NULL); /* checker */ + return result; +} + +static char copy_com_pointer_doc[] = +"CopyComPointer(src, dst) -> HRESULT value\n"; + +static PyObject * +copy_com_pointer(PyObject *self, PyObject *args) +{ + PyObject *p1, *p2, *r = NULL; + struct argument a, b; + IUnknown *src, **pdst; + if (!PyArg_ParseTuple(args, "OO:CopyComPointer", &p1, &p2)) + return NULL; + a.keep = b.keep = NULL; + + if (-1 == ConvParam(p1, 0, &a) || -1 == ConvParam(p2, 1, &b)) + goto done; + src = (IUnknown *)a.value.p; + pdst = (IUnknown **)b.value.p; + + if (pdst == NULL) + r = PyInt_FromLong(E_POINTER); + else { + if (src) + src->lpVtbl->AddRef(src); + *pdst = src; + r = PyInt_FromLong(S_OK); + } + done: + Py_XDECREF(a.keep); + Py_XDECREF(b.keep); + return r; +} +#else + +static PyObject *py_dl_open(PyObject *self, PyObject *args) +{ + char *name; + void * handle; +#ifdef RTLD_LOCAL + int mode = RTLD_NOW | RTLD_LOCAL; +#else + /* cygwin doesn't define RTLD_LOCAL */ + int mode = RTLD_NOW; +#endif + if (!PyArg_ParseTuple(args, "z|i:dlopen", &name, &mode)) + return NULL; + mode |= RTLD_NOW; + handle = ctypes_dlopen(name, mode); + if (!handle) { + PyErr_SetString(PyExc_OSError, + ctypes_dlerror()); + return NULL; + } + return PyLong_FromVoidPtr(handle); +} + +static PyObject *py_dl_close(PyObject *self, PyObject *args) +{ + void * handle; + + if (!PyArg_ParseTuple(args, "i:dlclose", &handle)) + return NULL; + if (dlclose(handle)) { + PyErr_SetString(PyExc_OSError, + ctypes_dlerror()); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *py_dl_sym(PyObject *self, PyObject *args) +{ + char *name; + void *handle; + void *ptr; + + if (!PyArg_ParseTuple(args, "is:dlsym", &handle, &name)) + return NULL; + ptr = ctypes_dlsym(handle, name); + if (!ptr) { + PyErr_SetString(PyExc_OSError, + ctypes_dlerror()); + return NULL; + } + return Py_BuildValue("i", ptr); +} +#endif + +/* + * Only for debugging so far: So that we can call CFunction instances + * + * XXX Needs to accept more arguments: flags, argtypes, restype + */ +static PyObject * +call_function(PyObject *self, PyObject *args) +{ + PPROC func; + PyObject *arguments; + PyObject *result; + + if (!PyArg_ParseTuple(args, + "iO!", + &func, + &PyTuple_Type, &arguments)) + return NULL; + + result = _CallProc(func, + arguments, +#ifdef MS_WIN32 + NULL, + NULL, +#endif + 0, /* flags */ + NULL, /* self->argtypes */ + NULL, /* self->restype */ + NULL); /* checker */ + return result; +} + +/* + * Only for debugging so far: So that we can call CFunction instances + * + * XXX Needs to accept more arguments: flags, argtypes, restype + */ +static PyObject * +call_cdeclfunction(PyObject *self, PyObject *args) +{ + PPROC func; + PyObject *arguments; + PyObject *result; + + if (!PyArg_ParseTuple(args, + "iO!", + &func, + &PyTuple_Type, &arguments)) + return NULL; + + result = _CallProc(func, + arguments, +#ifdef MS_WIN32 + NULL, + NULL, +#endif + FUNCFLAG_CDECL, /* flags */ + NULL, /* self->argtypes */ + NULL, /* self->restype */ + NULL); /* checker */ + return result; +} + +/***************************************************************** + * functions + */ +static char sizeof_doc[] = +"sizeof(C type) -> integer\n" +"sizeof(C instance) -> integer\n" +"Return the size in bytes of a C instance"; + +static PyObject * +sizeof_func(PyObject *self, PyObject *obj) +{ + StgDictObject *dict; + + dict = PyType_stgdict(obj); + if (dict) + return PyInt_FromLong(dict->size); + + if (CDataObject_Check(obj)) + return PyInt_FromLong(((CDataObject *)obj)->b_size); + PyErr_SetString(PyExc_TypeError, + "this type has no size"); + return NULL; +} + +static char alignment_doc[] = +"alignment(C type) -> integer\n" +"alignment(C instance) -> integer\n" +"Return the alignment requirements of a C instance"; + +static PyObject * +align_func(PyObject *self, PyObject *obj) +{ + StgDictObject *dict; + + dict = PyType_stgdict(obj); + if (dict) + return PyInt_FromLong(dict->align); + + dict = PyObject_stgdict(obj); + if (dict) + return PyInt_FromLong(dict->align); + + PyErr_SetString(PyExc_TypeError, + "no alignment info"); + return NULL; +} + +static char byref_doc[] = +"byref(C instance) -> byref-object\n" +"Return a pointer lookalike to a C instance, only usable\n" +"as function argument"; + +/* + * We must return something which can be converted to a parameter, + * but still has a reference to self. + */ +static PyObject * +byref(PyObject *self, PyObject *obj) +{ + PyCArgObject *parg; + if (!CDataObject_Check(obj)) { + PyErr_Format(PyExc_TypeError, + "byref() argument must be a ctypes instance, not '%s'", + obj->ob_type->tp_name); + return NULL; + } + + parg = new_CArgObject(); + if (parg == NULL) + return NULL; + + parg->tag = 'P'; + parg->pffi_type = &ffi_type_pointer; + Py_INCREF(obj); + parg->obj = obj; + parg->value.p = ((CDataObject *)obj)->b_ptr; + return (PyObject *)parg; +} + +static char addressof_doc[] = +"addressof(C instance) -> integer\n" +"Return the address of the C instance internal buffer"; + +static PyObject * +addressof(PyObject *self, PyObject *obj) +{ + if (CDataObject_Check(obj)) + return PyLong_FromVoidPtr(((CDataObject *)obj)->b_ptr); + PyErr_SetString(PyExc_TypeError, + "invalid type"); + return NULL; +} + +static int +converter(PyObject *obj, void **address) +{ + *address = PyLong_AsVoidPtr(obj); + return *address != NULL; +} + +static PyObject * +My_PyObj_FromPtr(PyObject *self, PyObject *args) +{ + PyObject *ob; + if (!PyArg_ParseTuple(args, "O&:PyObj_FromPtr", converter, &ob)) + return NULL; + Py_INCREF(ob); + return ob; +} + +static PyObject * +My_Py_INCREF(PyObject *self, PyObject *arg) +{ + Py_INCREF(arg); /* that's what this function is for */ + Py_INCREF(arg); /* that for returning it */ + return arg; +} + +static PyObject * +My_Py_DECREF(PyObject *self, PyObject *arg) +{ + Py_DECREF(arg); /* that's what this function is for */ + Py_INCREF(arg); /* that's for returning it */ + return arg; +} + +#ifdef CTYPES_UNICODE + +static char set_conversion_mode_doc[] = +"set_conversion_mode(encoding, errors) -> (previous-encoding, previous-errors)\n\ +\n\ +Set the encoding and error handling ctypes uses when converting\n\ +between unicode and strings. Returns the previous values.\n"; + +static PyObject * +set_conversion_mode(PyObject *self, PyObject *args) +{ + char *coding, *mode; + PyObject *result; + + if (!PyArg_ParseTuple(args, "zs:set_conversion_mode", &coding, &mode)) + return NULL; + result = Py_BuildValue("(zz)", conversion_mode_encoding, conversion_mode_errors); + if (coding) { + PyMem_Free(conversion_mode_encoding); + conversion_mode_encoding = PyMem_Malloc(strlen(coding) + 1); + strcpy(conversion_mode_encoding, coding); + } else { + conversion_mode_encoding = NULL; + } + PyMem_Free(conversion_mode_errors); + conversion_mode_errors = PyMem_Malloc(strlen(mode) + 1); + strcpy(conversion_mode_errors, mode); + return result; +} +#endif + +static PyObject * +resize(PyObject *self, PyObject *args) +{ + CDataObject *obj; + StgDictObject *dict; + Py_ssize_t size; + + if (!PyArg_ParseTuple(args, +#if (PY_VERSION_HEX < 0x02050000) + "Oi:resize", +#else + "On:resize", +#endif + (PyObject *)&obj, &size)) + return NULL; + + dict = PyObject_stgdict((PyObject *)obj); + if (dict == NULL) { + PyErr_SetString(PyExc_TypeError, + "excepted ctypes instance"); + return NULL; + } + if (size < dict->size) { + PyErr_Format(PyExc_ValueError, +#if PY_VERSION_HEX < 0x02050000 + "minimum size is %d", +#else + "minimum size is %zd", +#endif + dict->size); + return NULL; + } + if (obj->b_needsfree == 0) { + PyErr_Format(PyExc_ValueError, + "Memory cannot be resized because this object doesn't own it"); + return NULL; + } + if (size <= sizeof(obj->b_value)) { + /* internal default buffer is large enough */ + obj->b_size = size; + goto done; + } + if (obj->b_size <= sizeof(obj->b_value)) { + /* We are currently using the objects default buffer, but it + isn't large enough any more. */ + void *ptr = PyMem_Malloc(size); + if (ptr == NULL) + return PyErr_NoMemory(); + memset(ptr, 0, size); + memmove(ptr, obj->b_ptr, obj->b_size); + obj->b_ptr = ptr; + obj->b_size = size; + } else { + void * ptr = PyMem_Realloc(obj->b_ptr, size); + if (ptr == NULL) + return PyErr_NoMemory(); + obj->b_ptr = ptr; + obj->b_size = size; + } + done: + Py_INCREF(Py_None); + return Py_None; +} + +PyMethodDef module_methods[] = { + {"resize", resize, METH_VARARGS, "Resize the memory buffer of a ctypes instance"}, +#ifdef CTYPES_UNICODE + {"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc}, +#endif +#ifdef MS_WIN32 + {"CopyComPointer", copy_com_pointer, METH_VARARGS, copy_com_pointer_doc}, + {"FormatError", format_error, METH_VARARGS, format_error_doc}, + {"LoadLibrary", load_library, METH_VARARGS, load_library_doc}, + {"FreeLibrary", free_library, METH_VARARGS, free_library_doc}, + {"call_commethod", call_commethod, METH_VARARGS }, + {"_check_HRESULT", check_hresult, METH_VARARGS}, +#else + {"dlopen", py_dl_open, METH_VARARGS, + "dlopen(name, flag={RTLD_GLOBAL|RTLD_LOCAL}) open a shared library"}, + {"dlclose", py_dl_close, METH_VARARGS, "dlclose a library"}, + {"dlsym", py_dl_sym, METH_VARARGS, "find symbol in shared library"}, +#endif + {"alignment", align_func, METH_O, alignment_doc}, + {"sizeof", sizeof_func, METH_O, sizeof_doc}, + {"byref", byref, METH_O, byref_doc}, + {"addressof", addressof, METH_O, addressof_doc}, + {"call_function", call_function, METH_VARARGS }, + {"call_cdeclfunction", call_cdeclfunction, METH_VARARGS }, + {"PyObj_FromPtr", My_PyObj_FromPtr, METH_VARARGS }, + {"Py_INCREF", My_Py_INCREF, METH_O }, + {"Py_DECREF", My_Py_DECREF, METH_O }, + {NULL, NULL} /* Sentinel */ +}; + +/* + Local Variables: + compile-command: "cd .. && python setup.py -q build -g && python setup.py -q build install --home ~" + End: +*/ diff --git a/sys/src/cmd/python/Modules/_ctypes/cfield.c b/sys/src/cmd/python/Modules/_ctypes/cfield.c new file mode 100644 index 000000000..c16a38746 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/cfield.c @@ -0,0 +1,1668 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + +#include "Python.h" + +#include <ffi.h> +#ifdef MS_WIN32 +#include <windows.h> +#endif +#include "ctypes.h" + +/******************************************************************/ +/* + CField_Type +*/ +static PyObject * +CField_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + CFieldObject *obj; + obj = (CFieldObject *)type->tp_alloc(type, 0); + return (PyObject *)obj; +} + +/* + * Expects the size, index and offset for the current field in *psize and + * *poffset, stores the total size so far in *psize, the offset for the next + * field in *poffset, the alignment requirements for the current field in + * *palign, and returns a field desriptor for this field. + */ +/* + * bitfields extension: + * bitsize != 0: this is a bit field. + * pbitofs points to the current bit offset, this will be updated. + * prev_desc points to the type of the previous bitfield, if any. + */ +PyObject * +CField_FromDesc(PyObject *desc, int index, + int *pfield_size, int bitsize, int *pbitofs, + int *psize, int *poffset, int *palign, + int pack, int big_endian) +{ + CFieldObject *self; + PyObject *proto; + int size, align, length; + SETFUNC setfunc = NULL; + GETFUNC getfunc = NULL; + StgDictObject *dict; + int fieldtype; +#define NO_BITFIELD 0 +#define NEW_BITFIELD 1 +#define CONT_BITFIELD 2 +#define EXPAND_BITFIELD 3 + + self = (CFieldObject *)PyObject_CallObject((PyObject *)&CField_Type, + NULL); + if (self == NULL) + return NULL; + dict = PyType_stgdict(desc); + if (!dict) { + PyErr_SetString(PyExc_TypeError, + "has no _stginfo_"); + Py_DECREF(self); + return NULL; + } + if (bitsize /* this is a bitfield request */ + && *pfield_size /* we have a bitfield open */ +#if defined(MS_WIN32) && !defined(__MINGW32__) + && dict->size * 8 == *pfield_size /* MSVC */ +#else + && dict->size * 8 <= *pfield_size /* GCC, MINGW */ +#endif + && (*pbitofs + bitsize) <= *pfield_size) { + /* continue bit field */ + fieldtype = CONT_BITFIELD; +#ifndef MS_WIN32 + } else if (bitsize /* this is a bitfield request */ + && *pfield_size /* we have a bitfield open */ + && dict->size * 8 >= *pfield_size + && (*pbitofs + bitsize) <= dict->size * 8) { + /* expand bit field */ + fieldtype = EXPAND_BITFIELD; +#endif + } else if (bitsize) { + /* start new bitfield */ + fieldtype = NEW_BITFIELD; + *pbitofs = 0; + *pfield_size = dict->size * 8; + } else { + /* not a bit field */ + fieldtype = NO_BITFIELD; + *pbitofs = 0; + *pfield_size = 0; + } + + size = dict->size; + length = dict->length; + proto = desc; + + /* Field descriptors for 'c_char * n' are be scpecial cased to + return a Python string instead of an Array object instance... + */ + if (ArrayTypeObject_Check(proto)) { + StgDictObject *adict = PyType_stgdict(proto); + StgDictObject *idict; + if (adict && adict->proto) { + idict = PyType_stgdict(adict->proto); + if (!idict) { + PyErr_SetString(PyExc_TypeError, + "has no _stginfo_"); + Py_DECREF(self); + return NULL; + } + if (idict->getfunc == getentry("c")->getfunc) { + struct fielddesc *fd = getentry("s"); + getfunc = fd->getfunc; + setfunc = fd->setfunc; + } +#ifdef CTYPES_UNICODE + if (idict->getfunc == getentry("u")->getfunc) { + struct fielddesc *fd = getentry("U"); + getfunc = fd->getfunc; + setfunc = fd->setfunc; + } +#endif + } + } + + self->setfunc = setfunc; + self->getfunc = getfunc; + self->index = index; + + Py_INCREF(proto); + self->proto = proto; + + switch (fieldtype) { + case NEW_BITFIELD: + if (big_endian) + self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize; + else + self->size = (bitsize << 16) + *pbitofs; + *pbitofs = bitsize; + /* fall through */ + case NO_BITFIELD: + if (pack) + align = min(pack, dict->align); + else + align = dict->align; + if (align && *poffset % align) { + int delta = align - (*poffset % align); + *psize += delta; + *poffset += delta; + } + + if (bitsize == 0) + self->size = size; + *psize += size; + + self->offset = *poffset; + *poffset += size; + + *palign = align; + break; + + case EXPAND_BITFIELD: + /* XXX needs more */ + *psize += dict->size - *pfield_size/8; + + *pfield_size = dict->size * 8; + + if (big_endian) + self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize; + else + self->size = (bitsize << 16) + *pbitofs; + + self->offset = *poffset - size; /* poffset is already updated for the NEXT field */ + *pbitofs += bitsize; + break; + + case CONT_BITFIELD: + if (big_endian) + self->size = (bitsize << 16) + *pfield_size - *pbitofs - bitsize; + else + self->size = (bitsize << 16) + *pbitofs; + + self->offset = *poffset - size; /* poffset is already updated for the NEXT field */ + *pbitofs += bitsize; + break; + } + + return (PyObject *)self; +} + +static int +CField_set(CFieldObject *self, PyObject *inst, PyObject *value) +{ + CDataObject *dst; + char *ptr; + assert(CDataObject_Check(inst)); + dst = (CDataObject *)inst; + ptr = dst->b_ptr + self->offset; + return CData_set(inst, self->proto, self->setfunc, value, + self->index, self->size, ptr); +} + +static PyObject * +CField_get(CFieldObject *self, PyObject *inst, PyTypeObject *type) +{ + CDataObject *src; + if (inst == NULL) { + Py_INCREF(self); + return (PyObject *)self; + } + assert(CDataObject_Check(inst)); + src = (CDataObject *)inst; + return CData_get(self->proto, self->getfunc, inst, + self->index, self->size, src->b_ptr + self->offset); +} + +static PyObject * +CField_get_offset(PyObject *self, void *data) +{ +#if (PY_VERSION_HEX < 0x02050000) + return PyInt_FromLong(((CFieldObject *)self)->offset); +#else + return PyInt_FromSsize_t(((CFieldObject *)self)->offset); +#endif +} + +static PyObject * +CField_get_size(PyObject *self, void *data) +{ +#if (PY_VERSION_HEX < 0x02050000) + return PyInt_FromLong(((CFieldObject *)self)->size); +#else + return PyInt_FromSsize_t(((CFieldObject *)self)->size); +#endif +} + +static PyGetSetDef CField_getset[] = { + { "offset", CField_get_offset, NULL, "offset in bytes of this field" }, + { "size", CField_get_size, NULL, "size in bytes of this field" }, + { NULL, NULL, NULL, NULL }, +}; + +static int +CField_traverse(CFieldObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->proto); + return 0; +} + +static int +CField_clear(CFieldObject *self) +{ + Py_CLEAR(self->proto); + return 0; +} + +static void +CField_dealloc(PyObject *self) +{ + CField_clear((CFieldObject *)self); + self->ob_type->tp_free((PyObject *)self); +} + +static PyObject * +CField_repr(CFieldObject *self) +{ + PyObject *result; + int bits = self->size >> 16; + int size = self->size & 0xFFFF; + const char *name; + + name = ((PyTypeObject *)self->proto)->tp_name; + + if (bits) + result = PyString_FromFormat( +#if (PY_VERSION_HEX < 0x02050000) + "<Field type=%s, ofs=%d:%d, bits=%d>", +#else + "<Field type=%s, ofs=%zd:%d, bits=%d>", +#endif + name, self->offset, size, bits); + else + result = PyString_FromFormat( +#if (PY_VERSION_HEX < 0x02050000) + "<Field type=%s, ofs=%d, size=%d>", +#else + "<Field type=%s, ofs=%zd, size=%d>", +#endif + name, self->offset, size); + return result; +} + +PyTypeObject CField_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_ctypes.CField", /* tp_name */ + sizeof(CFieldObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + CField_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)CField_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + "Structure/Union member", /* tp_doc */ + (traverseproc)CField_traverse, /* tp_traverse */ + (inquiry)CField_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + CField_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)CField_get, /* tp_descr_get */ + (descrsetfunc)CField_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + CField_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/******************************************************************/ +/* + Accessor functions +*/ + +/* Derived from Modules/structmodule.c: + Helper routine to get a Python integer and raise the appropriate error + if it isn't one */ + +static int +get_long(PyObject *v, long *p) +{ + long x; + if (!PyInt_Check(v) && !PyLong_Check(v)) { + PyErr_Format(PyExc_TypeError, + "int expected instead of %s instance", + v->ob_type->tp_name); + return -1; + } + x = PyInt_AsUnsignedLongMask(v); + if (x == -1 && PyErr_Occurred()) + return -1; + *p = x; + return 0; +} + +/* Same, but handling unsigned long */ + +static int +get_ulong(PyObject *v, unsigned long *p) +{ + unsigned long x; + if (!PyInt_Check(v) && !PyLong_Check(v)) { + PyErr_Format(PyExc_TypeError, + "int expected instead of %s instance", + v->ob_type->tp_name); + return -1; + } + x = PyInt_AsUnsignedLongMask(v); + if (x == -1 && PyErr_Occurred()) + return -1; + *p = x; + return 0; +} + +#ifdef HAVE_LONG_LONG + +/* Same, but handling native long long. */ + +static int +get_longlong(PyObject *v, PY_LONG_LONG *p) +{ + PY_LONG_LONG x; + if (!PyInt_Check(v) && !PyLong_Check(v)) { + PyErr_Format(PyExc_TypeError, + "int expected instead of %s instance", + v->ob_type->tp_name); + return -1; + } + x = PyInt_AsUnsignedLongLongMask(v); + if (x == -1 && PyErr_Occurred()) + return -1; + *p = x; + return 0; +} + +/* Same, but handling native unsigned long long. */ + +static int +get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p) +{ + unsigned PY_LONG_LONG x; + if (!PyInt_Check(v) && !PyLong_Check(v)) { + PyErr_Format(PyExc_TypeError, + "int expected instead of %s instance", + v->ob_type->tp_name); + return -1; + } + x = PyInt_AsUnsignedLongLongMask(v); + if (x == -1 && PyErr_Occurred()) + return -1; + *p = x; + return 0; +} + +#endif + +/***************************************************************** + * Integer fields, with bitfield support + */ + +/* how to decode the size field, for integer get/set functions */ +#define LOW_BIT(x) ((x) & 0xFFFF) +#define NUM_BITS(x) ((x) >> 16) + +/* This seems nore a compiler issue than a Windows/non-Windows one */ +#ifdef MS_WIN32 +# define BIT_MASK(size) ((1 << NUM_BITS(size))-1) +#else +# define BIT_MASK(size) ((1LL << NUM_BITS(size))-1) +#endif + +/* This macro CHANGES the first parameter IN PLACE. For proper sign handling, + we must first shift left, then right. +*/ +#define GET_BITFIELD(v, size) \ + if (NUM_BITS(size)) { \ + v <<= (sizeof(v)*8 - LOW_BIT(size) - NUM_BITS(size)); \ + v >>= (sizeof(v)*8 - NUM_BITS(size)); \ + } + +/* This macro RETURNS the first parameter with the bit field CHANGED. */ +#define SET(x, v, size) \ + (NUM_BITS(size) ? \ + ( ( x & ~(BIT_MASK(size) << LOW_BIT(size)) ) | ( (v & BIT_MASK(size)) << LOW_BIT(size) ) ) \ + : v) + +/* byte swapping macros */ +#define SWAP_2(v) \ + ( ( (v >> 8) & 0x00FF) | \ + ( (v << 8) & 0xFF00) ) + +#define SWAP_4(v) \ + ( ( (v & 0x000000FF) << 24 ) | \ + ( (v & 0x0000FF00) << 8 ) | \ + ( (v & 0x00FF0000) >> 8 ) | \ + ( ((v >> 24) & 0xFF)) ) + +#ifdef _MSC_VER +#define SWAP_8(v) \ + ( ( (v & 0x00000000000000FFL) << 56 ) | \ + ( (v & 0x000000000000FF00L) << 40 ) | \ + ( (v & 0x0000000000FF0000L) << 24 ) | \ + ( (v & 0x00000000FF000000L) << 8 ) | \ + ( (v & 0x000000FF00000000L) >> 8 ) | \ + ( (v & 0x0000FF0000000000L) >> 24 ) | \ + ( (v & 0x00FF000000000000L) >> 40 ) | \ + ( ((v >> 56) & 0xFF)) ) +#else +#define SWAP_8(v) \ + ( ( (v & 0x00000000000000FFLL) << 56 ) | \ + ( (v & 0x000000000000FF00LL) << 40 ) | \ + ( (v & 0x0000000000FF0000LL) << 24 ) | \ + ( (v & 0x00000000FF000000LL) << 8 ) | \ + ( (v & 0x000000FF00000000LL) >> 8 ) | \ + ( (v & 0x0000FF0000000000LL) >> 24 ) | \ + ( (v & 0x00FF000000000000LL) >> 40 ) | \ + ( ((v >> 56) & 0xFF)) ) +#endif + +#define SWAP_INT SWAP_4 + +#if SIZEOF_LONG == 4 +# define SWAP_LONG SWAP_4 +#elif SIZEOF_LONG == 8 +# define SWAP_LONG SWAP_8 +#endif +/***************************************************************** + * The setter methods return an object which must be kept alive, to keep the + * data valid which has been stored in the memory block. The ctypes object + * instance inserts this object into its 'b_objects' list. + * + * For simple Python types like integers or characters, there is nothing that + * has to been kept alive, so Py_None is returned in these cases. But this + * makes inspecting the 'b_objects' list, which is accessible from Python for + * debugging, less useful. + * + * So, defining the _CTYPES_DEBUG_KEEP symbol returns the original value + * instead of Py_None. + */ + +#ifdef _CTYPES_DEBUG_KEEP +#define _RET(x) Py_INCREF(x); return x +#else +#define _RET(X) Py_INCREF(Py_None); return Py_None +#endif + +/***************************************************************** + * integer accessor methods, supporting bit fields + */ + +static PyObject * +b_set(void *ptr, PyObject *value, unsigned size) +{ + long val; + if (get_long(value, &val) < 0) + return NULL; + *(signed char *)ptr = (signed char)SET(*(signed char *)ptr, (signed char)val, size); + _RET(value); +} + + +static PyObject * +b_get(void *ptr, unsigned size) +{ + signed char val = *(signed char *)ptr; + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +B_set(void *ptr, PyObject *value, unsigned size) +{ + unsigned long val; + if (get_ulong(value, &val) < 0) + return NULL; + *(unsigned char *)ptr = (unsigned char)SET(*(unsigned char*)ptr, + (unsigned short)val, size); + _RET(value); +} + + +static PyObject * +B_get(void *ptr, unsigned size) +{ + unsigned char val = *(unsigned char *)ptr; + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +h_set(void *ptr, PyObject *value, unsigned size) +{ + long val; + short x; + if (get_long(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, (short)val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + + +static PyObject * +h_set_sw(void *ptr, PyObject *value, unsigned size) +{ + long val; + short field; + if (get_long(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = SWAP_2(field); + field = SET(field, (short)val, size); + field = SWAP_2(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + +static PyObject * +h_get(void *ptr, unsigned size) +{ + short val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyInt_FromLong((long)val); +} + +static PyObject * +h_get_sw(void *ptr, unsigned size) +{ + short val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_2(val); + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +H_set(void *ptr, PyObject *value, unsigned size) +{ + unsigned long val; + unsigned short x; + if (get_ulong(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, (unsigned short)val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +H_set_sw(void *ptr, PyObject *value, unsigned size) +{ + unsigned long val; + unsigned short field; + if (get_ulong(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = SWAP_2(field); + field = SET(field, (unsigned short)val, size); + field = SWAP_2(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + + +static PyObject * +H_get(void *ptr, unsigned size) +{ + unsigned short val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +H_get_sw(void *ptr, unsigned size) +{ + unsigned short val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_2(val); + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +i_set(void *ptr, PyObject *value, unsigned size) +{ + long val; + int x; + if (get_long(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, (int)val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +i_set_sw(void *ptr, PyObject *value, unsigned size) +{ + long val; + int field; + if (get_long(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = SWAP_INT(field); + field = SET(field, (int)val, size); + field = SWAP_INT(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + + +static PyObject * +i_get(void *ptr, unsigned size) +{ + int val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +i_get_sw(void *ptr, unsigned size) +{ + int val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_INT(val); + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +#ifdef MS_WIN32 +/* short BOOL - VARIANT_BOOL */ +static PyObject * +vBOOL_set(void *ptr, PyObject *value, unsigned size) +{ + switch (PyObject_IsTrue(value)) { + case -1: + return NULL; + case 0: + *(short int *)ptr = VARIANT_FALSE; + _RET(value); + default: + *(short int *)ptr = VARIANT_TRUE; + _RET(value); + } +} + +static PyObject * +vBOOL_get(void *ptr, unsigned size) +{ + return PyBool_FromLong((long)*(short int *)ptr); +} +#endif + +static PyObject * +I_set(void *ptr, PyObject *value, unsigned size) +{ + unsigned long val; + unsigned int x; + if (get_ulong(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, (unsigned int)val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +I_set_sw(void *ptr, PyObject *value, unsigned size) +{ + unsigned long val; + unsigned int field; + if (get_ulong(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = (unsigned int)SET(field, (unsigned int)val, size); + field = SWAP_INT(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + + +static PyObject * +I_get(void *ptr, unsigned size) +{ + unsigned int val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyLong_FromUnsignedLong(val); +} + +static PyObject * +I_get_sw(void *ptr, unsigned size) +{ + unsigned int val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_INT(val); + GET_BITFIELD(val, size); + return PyLong_FromUnsignedLong(val); +} + +static PyObject * +l_set(void *ptr, PyObject *value, unsigned size) +{ + long val; + long x; + if (get_long(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +l_set_sw(void *ptr, PyObject *value, unsigned size) +{ + long val; + long field; + if (get_long(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = SWAP_LONG(field); + field = (long)SET(field, val, size); + field = SWAP_LONG(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + + +static PyObject * +l_get(void *ptr, unsigned size) +{ + long val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +l_get_sw(void *ptr, unsigned size) +{ + long val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_LONG(val); + GET_BITFIELD(val, size); + return PyInt_FromLong(val); +} + +static PyObject * +L_set(void *ptr, PyObject *value, unsigned size) +{ + unsigned long val; + unsigned long x; + if (get_ulong(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +L_set_sw(void *ptr, PyObject *value, unsigned size) +{ + unsigned long val; + unsigned long field; + if (get_ulong(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = SWAP_LONG(field); + field = (unsigned long)SET(field, val, size); + field = SWAP_LONG(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + + +static PyObject * +L_get(void *ptr, unsigned size) +{ + unsigned long val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyLong_FromUnsignedLong(val); +} + +static PyObject * +L_get_sw(void *ptr, unsigned size) +{ + unsigned long val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_LONG(val); + GET_BITFIELD(val, size); + return PyLong_FromUnsignedLong(val); +} + +#ifdef HAVE_LONG_LONG +static PyObject * +q_set(void *ptr, PyObject *value, unsigned size) +{ + PY_LONG_LONG val; + PY_LONG_LONG x; + if (get_longlong(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +q_set_sw(void *ptr, PyObject *value, unsigned size) +{ + PY_LONG_LONG val; + PY_LONG_LONG field; + if (get_longlong(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = SWAP_8(field); + field = (PY_LONG_LONG)SET(field, val, size); + field = SWAP_8(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + +static PyObject * +q_get(void *ptr, unsigned size) +{ + PY_LONG_LONG val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyLong_FromLongLong(val); +} + +static PyObject * +q_get_sw(void *ptr, unsigned size) +{ + PY_LONG_LONG val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_8(val); + GET_BITFIELD(val, size); + return PyLong_FromLongLong(val); +} + +static PyObject * +Q_set(void *ptr, PyObject *value, unsigned size) +{ + unsigned PY_LONG_LONG val; + unsigned PY_LONG_LONG x; + if (get_ulonglong(value, &val) < 0) + return NULL; + memcpy(&x, ptr, sizeof(x)); + x = SET(x, val, size); + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +Q_set_sw(void *ptr, PyObject *value, unsigned size) +{ + unsigned PY_LONG_LONG val; + unsigned PY_LONG_LONG field; + if (get_ulonglong(value, &val) < 0) + return NULL; + memcpy(&field, ptr, sizeof(field)); + field = SWAP_8(field); + field = (unsigned PY_LONG_LONG)SET(field, val, size); + field = SWAP_8(field); + memcpy(ptr, &field, sizeof(field)); + _RET(value); +} + +static PyObject * +Q_get(void *ptr, unsigned size) +{ + unsigned PY_LONG_LONG val; + memcpy(&val, ptr, sizeof(val)); + GET_BITFIELD(val, size); + return PyLong_FromUnsignedLongLong(val); +} + +static PyObject * +Q_get_sw(void *ptr, unsigned size) +{ + unsigned PY_LONG_LONG val; + memcpy(&val, ptr, sizeof(val)); + val = SWAP_8(val); + GET_BITFIELD(val, size); + return PyLong_FromUnsignedLongLong(val); +} +#endif + +/***************************************************************** + * non-integer accessor methods, not supporting bit fields + */ + + + +static PyObject * +d_set(void *ptr, PyObject *value, unsigned size) +{ + double x; + + x = PyFloat_AsDouble(value); + if (x == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + " float expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } + memcpy(ptr, &x, sizeof(double)); + _RET(value); +} + +static PyObject * +d_get(void *ptr, unsigned size) +{ + double val; + memcpy(&val, ptr, sizeof(val)); + return PyFloat_FromDouble(val); +} + +static PyObject * +d_set_sw(void *ptr, PyObject *value, unsigned size) +{ + double x; + + x = PyFloat_AsDouble(value); + if (x == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + " float expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } +#ifdef WORDS_BIGENDIAN + if (_PyFloat_Pack8(x, (unsigned char *)ptr, 1)) + return NULL; +#else + if (_PyFloat_Pack8(x, (unsigned char *)ptr, 0)) + return NULL; +#endif + _RET(value); +} + +static PyObject * +d_get_sw(void *ptr, unsigned size) +{ +#ifdef WORDS_BIGENDIAN + return PyFloat_FromDouble(_PyFloat_Unpack8(ptr, 1)); +#else + return PyFloat_FromDouble(_PyFloat_Unpack8(ptr, 0)); +#endif +} + +static PyObject * +f_set(void *ptr, PyObject *value, unsigned size) +{ + float x; + + x = (float)PyFloat_AsDouble(value); + if (x == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + " float expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } + memcpy(ptr, &x, sizeof(x)); + _RET(value); +} + +static PyObject * +f_get(void *ptr, unsigned size) +{ + float val; + memcpy(&val, ptr, sizeof(val)); + return PyFloat_FromDouble(val); +} + +static PyObject * +f_set_sw(void *ptr, PyObject *value, unsigned size) +{ + float x; + + x = (float)PyFloat_AsDouble(value); + if (x == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + " float expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } +#ifdef WORDS_BIGENDIAN + if (_PyFloat_Pack4(x, (unsigned char *)ptr, 1)) + return NULL; +#else + if (_PyFloat_Pack4(x, (unsigned char *)ptr, 0)) + return NULL; +#endif + _RET(value); +} + +static PyObject * +f_get_sw(void *ptr, unsigned size) +{ +#ifdef WORDS_BIGENDIAN + return PyFloat_FromDouble(_PyFloat_Unpack4(ptr, 1)); +#else + return PyFloat_FromDouble(_PyFloat_Unpack4(ptr, 0)); +#endif +} + +/* + py_object refcounts: + + 1. If we have a py_object instance, O_get must Py_INCREF the returned + object, of course. If O_get is called from a function result, no py_object + instance is created - so callproc.c::GetResult has to call Py_DECREF. + + 2. The memory block in py_object owns a refcount. So, py_object must call + Py_DECREF on destruction. Maybe only when b_needsfree is non-zero. +*/ +static PyObject * +O_get(void *ptr, unsigned size) +{ + PyObject *ob = *(PyObject **)ptr; + if (ob == NULL) { + if (!PyErr_Occurred()) + /* Set an error if not yet set */ + PyErr_SetString(PyExc_ValueError, + "PyObject is NULL"); + return NULL; + } + Py_INCREF(ob); + return ob; +} + +static PyObject * +O_set(void *ptr, PyObject *value, unsigned size) +{ + /* Hm, does the memory block need it's own refcount or not? */ + *(PyObject **)ptr = value; + Py_INCREF(value); + return value; +} + + +static PyObject * +c_set(void *ptr, PyObject *value, unsigned size) +{ + if (!PyString_Check(value) || (1 != PyString_Size(value))) { + PyErr_Format(PyExc_TypeError, + "one character string expected"); + return NULL; + } + *(char *)ptr = PyString_AS_STRING(value)[0]; + _RET(value); +} + + +static PyObject * +c_get(void *ptr, unsigned size) +{ + return PyString_FromStringAndSize((char *)ptr, 1); +} + +#ifdef CTYPES_UNICODE +/* u - a single wchar_t character */ +static PyObject * +u_set(void *ptr, PyObject *value, unsigned size) +{ + int len; + + if (PyString_Check(value)) { + value = PyUnicode_FromEncodedObject(value, + conversion_mode_encoding, + conversion_mode_errors); + if (!value) + return NULL; + } else if (!PyUnicode_Check(value)) { + PyErr_Format(PyExc_TypeError, + "unicode string expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } else + Py_INCREF(value); + + len = PyUnicode_GET_SIZE(value); + if (len != 1) { + Py_DECREF(value); + PyErr_SetString(PyExc_TypeError, + "one character unicode string expected"); + return NULL; + } + + *(wchar_t *)ptr = PyUnicode_AS_UNICODE(value)[0]; + Py_DECREF(value); + + _RET(value); +} + + +static PyObject * +u_get(void *ptr, unsigned size) +{ + return PyUnicode_FromWideChar((wchar_t *)ptr, 1); +} + +/* U - a unicode string */ +static PyObject * +U_get(void *ptr, unsigned size) +{ + PyObject *result; + unsigned int len; + Py_UNICODE *p; + + size /= sizeof(wchar_t); /* we count character units here, not bytes */ + + result = PyUnicode_FromWideChar((wchar_t *)ptr, size); + if (!result) + return NULL; + /* We need 'result' to be able to count the characters with wcslen, + since ptr may not be NUL terminated. If the length is smaller (if + it was actually NUL terminated, we construct a new one and throw + away the result. + */ + /* chop off at the first NUL character, if any. */ + p = PyUnicode_AS_UNICODE(result); + for (len = 0; len < size; ++len) + if (!p[len]) + break; + + if (len < size) { + PyObject *ob = PyUnicode_FromWideChar((wchar_t *)ptr, len); + Py_DECREF(result); + return ob; + } + return result; +} + +static PyObject * +U_set(void *ptr, PyObject *value, unsigned length) +{ + unsigned int size; + + /* It's easier to calculate in characters than in bytes */ + length /= sizeof(wchar_t); + + if (PyString_Check(value)) { + value = PyUnicode_FromEncodedObject(value, + conversion_mode_encoding, + conversion_mode_errors); + if (!value) + return NULL; + } else if (!PyUnicode_Check(value)) { + PyErr_Format(PyExc_TypeError, + "unicode string expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } else + Py_INCREF(value); + size = PyUnicode_GET_SIZE(value); + if (size > length) { + PyErr_Format(PyExc_ValueError, + "string too long (%d, maximum length %d)", + size, length); + Py_DECREF(value); + return NULL; + } else if (size < length-1) + /* copy terminating NUL character if there is space */ + size += 1; + PyUnicode_AsWideChar((PyUnicodeObject *)value, (wchar_t *)ptr, size); + return value; +} + +#endif + +static PyObject * +s_get(void *ptr, unsigned size) +{ + PyObject *result; + + result = PyString_FromString((char *)ptr); + if (!result) + return NULL; + /* chop off at the first NUL character, if any. + * On error, result will be deallocated and set to NULL. + */ + size = min(size, strlen(PyString_AS_STRING(result))); + if (result->ob_refcnt == 1) { + /* shorten the result */ + _PyString_Resize(&result, size); + return result; + } else + /* cannot shorten the result */ + return PyString_FromStringAndSize(ptr, size); +} + +static PyObject * +s_set(void *ptr, PyObject *value, unsigned length) +{ + char *data; + unsigned size; + + data = PyString_AsString(value); + if (!data) + return NULL; + size = strlen(data); + if (size < length) { + /* This will copy the leading NUL character + * if there is space for it. + */ + ++size; + } else if (size > length) { + PyErr_Format(PyExc_ValueError, + "string too long (%d, maximum length %d)", + size, length); + return NULL; + } + /* Also copy the terminating NUL character if there is space */ + memcpy((char *)ptr, data, size); + _RET(value); +} + +static PyObject * +z_set(void *ptr, PyObject *value, unsigned size) +{ + if (value == Py_None) { + *(char **)ptr = NULL; + Py_INCREF(value); + return value; + } + if (PyString_Check(value)) { + *(char **)ptr = PyString_AS_STRING(value); + Py_INCREF(value); + return value; + } else if (PyUnicode_Check(value)) { + PyObject *str = PyUnicode_AsEncodedString(value, + conversion_mode_encoding, + conversion_mode_errors); + if (str == NULL) + return NULL; + *(char **)ptr = PyString_AS_STRING(str); + return str; + } else if (PyInt_Check(value) || PyLong_Check(value)) { + *(char **)ptr = (char *)PyInt_AsUnsignedLongMask(value); + _RET(value); + } + PyErr_Format(PyExc_TypeError, + "string or integer address expected instead of %s instance", + value->ob_type->tp_name); + return NULL; +} + +static PyObject * +z_get(void *ptr, unsigned size) +{ + /* XXX What about invalid pointers ??? */ + if (*(void **)ptr) { +#if defined(MS_WIN32) && !defined(_WIN32_WCE) + if (IsBadStringPtrA(*(char **)ptr, -1)) { + PyErr_Format(PyExc_ValueError, + "invalid string pointer %p", + ptr); + return NULL; + } +#endif + return PyString_FromString(*(char **)ptr); + } else { + Py_INCREF(Py_None); + return Py_None; + } +} + +#ifdef CTYPES_UNICODE +static PyObject * +Z_set(void *ptr, PyObject *value, unsigned size) +{ + if (value == Py_None) { + *(wchar_t **)ptr = NULL; + Py_INCREF(value); + return value; + } + if (PyString_Check(value)) { + value = PyUnicode_FromEncodedObject(value, + conversion_mode_encoding, + conversion_mode_errors); + if (!value) + return NULL; + } else if (PyInt_Check(value) || PyLong_Check(value)) { + *(wchar_t **)ptr = (wchar_t *)PyInt_AsUnsignedLongMask(value); + Py_INCREF(Py_None); + return Py_None; + } else if (!PyUnicode_Check(value)) { + PyErr_Format(PyExc_TypeError, + "unicode string or integer address expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } else + Py_INCREF(value); +#ifdef HAVE_USABLE_WCHAR_T + /* HAVE_USABLE_WCHAR_T means that Py_UNICODE and wchar_t is the same + type. So we can copy directly. Hm, are unicode objects always NUL + terminated in Python, internally? + */ + *(wchar_t **)ptr = PyUnicode_AS_UNICODE(value); + return value; +#else + { + /* We must create a wchar_t* buffer from the unicode object, + and keep it alive */ + PyObject *keep; + wchar_t *buffer; + + int size = PyUnicode_GET_SIZE(value); + size += 1; /* terminating NUL */ + size *= sizeof(wchar_t); + buffer = (wchar_t *)PyMem_Malloc(size); + if (!buffer) + return NULL; + memset(buffer, 0, size); + keep = PyCObject_FromVoidPtr(buffer, PyMem_Free); + if (!keep) { + PyMem_Free(buffer); + return NULL; + } + *(wchar_t **)ptr = (wchar_t *)buffer; + if (-1 == PyUnicode_AsWideChar((PyUnicodeObject *)value, + buffer, PyUnicode_GET_SIZE(value))) { + Py_DECREF(value); + Py_DECREF(keep); + return NULL; + } + Py_DECREF(value); + return keep; + } +#endif +} + +static PyObject * +Z_get(void *ptr, unsigned size) +{ + wchar_t *p; + p = *(wchar_t **)ptr; + if (p) + return PyUnicode_FromWideChar(p, wcslen(p)); + else { + Py_INCREF(Py_None); + return Py_None; + } +} +#endif + +#ifdef MS_WIN32 +static PyObject * +BSTR_set(void *ptr, PyObject *value, unsigned size) +{ + BSTR bstr; + + /* convert value into a PyUnicodeObject or NULL */ + if (Py_None == value) { + value = NULL; + } else if (PyString_Check(value)) { + value = PyUnicode_FromEncodedObject(value, + conversion_mode_encoding, + conversion_mode_errors); + if (!value) + return NULL; + } else if (PyUnicode_Check(value)) { + Py_INCREF(value); /* for the descref below */ + } else { + PyErr_Format(PyExc_TypeError, + "unicode string expected instead of %s instance", + value->ob_type->tp_name); + return NULL; + } + + /* create a BSTR from value */ + if (value) { + bstr = SysAllocStringLen(PyUnicode_AS_UNICODE(value), + PyUnicode_GET_SIZE(value)); + Py_DECREF(value); + } else + bstr = NULL; + + /* free the previous contents, if any */ + if (*(BSTR *)ptr) + SysFreeString(*(BSTR *)ptr); + + /* and store it */ + *(BSTR *)ptr = bstr; + + /* We don't need to keep any other object */ + _RET(value); +} + + +static PyObject * +BSTR_get(void *ptr, unsigned size) +{ + BSTR p; + p = *(BSTR *)ptr; + if (p) + return PyUnicode_FromWideChar(p, SysStringLen(p)); + else { + /* Hm, it seems NULL pointer and zero length string are the + same in BSTR, see Don Box, p 81 + */ + Py_INCREF(Py_None); + return Py_None; + } +} +#endif + +static PyObject * +P_set(void *ptr, PyObject *value, unsigned size) +{ + void *v; + if (value == Py_None) { + *(void **)ptr = NULL; + _RET(value); + } + + if (!PyInt_Check(value) && !PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "cannot be converted to pointer"); + return NULL; + } + +#if SIZEOF_VOID_P <= SIZEOF_LONG + v = (void *)PyInt_AsUnsignedLongMask(value); +#else +#ifndef HAVE_LONG_LONG +# error "PyLong_AsVoidPtr: sizeof(void*) > sizeof(long), but no long long" +#elif SIZEOF_LONG_LONG < SIZEOF_VOID_P +# error "PyLong_AsVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)" +#endif + v = (void *)PyInt_AsUnsignedLongLongMask(value); +#endif + + if (PyErr_Occurred()) + return NULL; + + *(void **)ptr = v; + _RET(value); +} + +static PyObject * +P_get(void *ptr, unsigned size) +{ + if (*(void **)ptr == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyLong_FromVoidPtr(*(void **)ptr); +} + +static struct fielddesc formattable[] = { + { 's', s_set, s_get, &ffi_type_pointer}, + { 'b', b_set, b_get, &ffi_type_schar}, + { 'B', B_set, B_get, &ffi_type_uchar}, + { 'c', c_set, c_get, &ffi_type_schar}, + { 'd', d_set, d_get, &ffi_type_double, d_set_sw, d_get_sw}, + { 'f', f_set, f_get, &ffi_type_float, f_set_sw, f_get_sw}, + { 'h', h_set, h_get, &ffi_type_sshort, h_set_sw, h_get_sw}, + { 'H', H_set, H_get, &ffi_type_ushort, H_set_sw, H_get_sw}, + { 'i', i_set, i_get, &ffi_type_sint, i_set_sw, i_get_sw}, + { 'I', I_set, I_get, &ffi_type_uint, I_set_sw, I_get_sw}, +/* XXX Hm, sizeof(int) == sizeof(long) doesn't hold on every platform */ +/* As soon as we can get rid of the type codes, this is no longer a problem */ +#if SIZEOF_LONG == 4 + { 'l', l_set, l_get, &ffi_type_sint, l_set_sw, l_get_sw}, + { 'L', L_set, L_get, &ffi_type_uint, L_set_sw, L_get_sw}, +#elif SIZEOF_LONG == 8 + { 'l', l_set, l_get, &ffi_type_slong, l_set_sw, l_get_sw}, + { 'L', L_set, L_get, &ffi_type_ulong, L_set_sw, L_get_sw}, +#else +# error +#endif +#ifdef HAVE_LONG_LONG + { 'q', q_set, q_get, &ffi_type_slong, q_set_sw, q_get_sw}, + { 'Q', Q_set, Q_get, &ffi_type_ulong, Q_set_sw, Q_get_sw}, +#endif + { 'P', P_set, P_get, &ffi_type_pointer}, + { 'z', z_set, z_get, &ffi_type_pointer}, +#ifdef CTYPES_UNICODE + { 'u', u_set, u_get, NULL}, /* ffi_type set later */ + { 'U', U_set, U_get, &ffi_type_pointer}, + { 'Z', Z_set, Z_get, &ffi_type_pointer}, +#endif +#ifdef MS_WIN32 + { 'X', BSTR_set, BSTR_get, &ffi_type_pointer}, + { 'v', vBOOL_set, vBOOL_get, &ffi_type_sshort}, +#endif + { 'O', O_set, O_get, &ffi_type_pointer}, + { 0, NULL, NULL, NULL}, +}; + +/* + Ideas: Implement VARIANT in this table, using 'V' code. + Use '?' as code for BOOL. +*/ + +struct fielddesc * +getentry(char *fmt) +{ + static int initialized = 0; + struct fielddesc *table = formattable; + + if (!initialized) { + initialized = 1; +#ifdef CTYPES_UNICODE + if (sizeof(wchar_t) == sizeof(short)) + getentry("u")->pffi_type = &ffi_type_sshort; + else if (sizeof(wchar_t) == sizeof(int)) + getentry("u")->pffi_type = &ffi_type_sint; + else if (sizeof(wchar_t) == sizeof(long)) + getentry("u")->pffi_type = &ffi_type_slong; +#endif + } + + for (; table->code; ++table) { + if (table->code == fmt[0]) + return table; + } + return NULL; +} + +typedef struct { char c; char x; } s_char; +typedef struct { char c; short x; } s_short; +typedef struct { char c; int x; } s_int; +typedef struct { char c; long x; } s_long; +typedef struct { char c; float x; } s_float; +typedef struct { char c; double x; } s_double; +typedef struct { char c; char *x; } s_char_p; +typedef struct { char c; void *x; } s_void_p; + +/* +#define CHAR_ALIGN (sizeof(s_char) - sizeof(char)) +#define SHORT_ALIGN (sizeof(s_short) - sizeof(short)) +#define INT_ALIGN (sizeof(s_int) - sizeof(int)) +#define LONG_ALIGN (sizeof(s_long) - sizeof(long)) +*/ +#define FLOAT_ALIGN (sizeof(s_float) - sizeof(float)) +#define DOUBLE_ALIGN (sizeof(s_double) - sizeof(double)) +/* #define CHAR_P_ALIGN (sizeof(s_char_p) - sizeof(char*)) */ +#define VOID_P_ALIGN (sizeof(s_void_p) - sizeof(void*)) + +/* +#ifdef HAVE_USABLE_WCHAR_T +typedef struct { char c; wchar_t x; } s_wchar; +typedef struct { char c; wchar_t *x; } s_wchar_p; + +#define WCHAR_ALIGN (sizeof(s_wchar) - sizeof(wchar_t)) +#define WCHAR_P_ALIGN (sizeof(s_wchar_p) - sizeof(wchar_t*)) +#endif +*/ + +#ifdef HAVE_LONG_LONG +typedef struct { char c; PY_LONG_LONG x; } s_long_long; +#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(PY_LONG_LONG)) +#endif + +/* from ffi.h: +typedef struct _ffi_type +{ + size_t size; + unsigned short alignment; + unsigned short type; + struct _ffi_type **elements; +} ffi_type; +*/ + +/* align and size are bogus for void, but they must not be zero */ +ffi_type ffi_type_void = { 1, 1, FFI_TYPE_VOID }; + +ffi_type ffi_type_uint8 = { 1, 1, FFI_TYPE_UINT8 }; +ffi_type ffi_type_sint8 = { 1, 1, FFI_TYPE_SINT8 }; + +ffi_type ffi_type_uint16 = { 2, 2, FFI_TYPE_UINT16 }; +ffi_type ffi_type_sint16 = { 2, 2, FFI_TYPE_SINT16 }; + +ffi_type ffi_type_uint32 = { 4, 4, FFI_TYPE_UINT32 }; +ffi_type ffi_type_sint32 = { 4, 4, FFI_TYPE_SINT32 }; + +ffi_type ffi_type_uint64 = { 8, LONG_LONG_ALIGN, FFI_TYPE_UINT64 }; +ffi_type ffi_type_sint64 = { 8, LONG_LONG_ALIGN, FFI_TYPE_SINT64 }; + +ffi_type ffi_type_float = { sizeof(float), FLOAT_ALIGN, FFI_TYPE_FLOAT }; +ffi_type ffi_type_double = { sizeof(double), DOUBLE_ALIGN, FFI_TYPE_DOUBLE }; + +/* ffi_type ffi_type_longdouble */ + +ffi_type ffi_type_pointer = { sizeof(void *), VOID_P_ALIGN, FFI_TYPE_POINTER }; + +/*---------------- EOF ----------------*/ diff --git a/sys/src/cmd/python/Modules/_ctypes/ctypes.h b/sys/src/cmd/python/Modules/_ctypes/ctypes.h new file mode 100644 index 000000000..0af785102 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/ctypes.h @@ -0,0 +1,407 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + +#if (PY_VERSION_HEX < 0x02050000) +typedef int Py_ssize_t; +#endif + +#ifndef MS_WIN32 +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) + +#define PARAMFLAG_FIN 0x1 +#define PARAMFLAG_FOUT 0x2 +#define PARAMFLAG_FLCID 0x4 +#endif + +/* + Backwards compatibility: + Python2.2 used LONG_LONG instead of PY_LONG_LONG +*/ +#if defined(HAVE_LONG_LONG) && !defined(PY_LONG_LONG) +#define PY_LONG_LONG LONG_LONG +#endif + +typedef struct tagPyCArgObject PyCArgObject; +typedef struct tagCDataObject CDataObject; +typedef PyObject *(* GETFUNC)(void *, unsigned size); +typedef PyObject *(* SETFUNC)(void *, PyObject *value, unsigned size); +typedef PyCArgObject *(* PARAMFUNC)(CDataObject *obj); + +/* A default buffer in CDataObject, which can be used for small C types. If +this buffer is too small, PyMem_Malloc will be called to create a larger one, +and this one is not used. + +Making CDataObject a variable size object would be a better solution, but more +difficult in the presence of CFuncPtrObject. Maybe later. +*/ +union value { + char c[16]; + short s; + int i; + long l; + float f; + double d; +#ifdef HAVE_LONG_LONG + PY_LONG_LONG ll; +#endif +}; + +/* + Hm. Are there CDataObject's which do not need the b_objects member? In + this case we probably should introduce b_flags to mark it as present... If + b_objects is not present/unused b_length is unneeded as well. +*/ + +struct tagCDataObject { + PyObject_HEAD + char *b_ptr; /* pointer to memory block */ + int b_needsfree; /* need _we_ free the memory? */ + CDataObject *b_base; /* pointer to base object or NULL */ + Py_ssize_t b_size; /* size of memory block in bytes */ + Py_ssize_t b_length; /* number of references we need */ + Py_ssize_t b_index; /* index of this object into base's + b_object list */ + PyObject *b_objects; /* dictionary of references we need to keep, or Py_None */ + union value b_value; +}; + +typedef struct { + ffi_closure *pcl; /* the C callable */ + ffi_cif cif; + PyObject *converters; + PyObject *callable; + SETFUNC setfunc; + ffi_type *restype; + ffi_type *atypes[0]; +} ffi_info; + +typedef struct { + /* First part identical to tagCDataObject */ + PyObject_HEAD + char *b_ptr; /* pointer to memory block */ + int b_needsfree; /* need _we_ free the memory? */ + CDataObject *b_base; /* pointer to base object or NULL */ + Py_ssize_t b_size; /* size of memory block in bytes */ + Py_ssize_t b_length; /* number of references we need */ + Py_ssize_t b_index; /* index of this object into base's + b_object list */ + PyObject *b_objects; /* list of references we need to keep */ + union value b_value; + /* end of tagCDataObject, additional fields follow */ + + ffi_info *thunk; + PyObject *callable; + + /* These two fields will override the ones in the type's stgdict if + they are set */ + PyObject *converters; + PyObject *argtypes; + PyObject *restype; + PyObject *checker; + PyObject *errcheck; +#ifdef MS_WIN32 + int index; + GUID *iid; +#endif + PyObject *paramflags; +} CFuncPtrObject; + +extern PyTypeObject StgDict_Type; +#define StgDict_CheckExact(v) ((v)->ob_type == &StgDict_Type) +#define StgDict_Check(v) PyObject_TypeCheck(v, &StgDict_Type) + +extern int StructUnionType_update_stgdict(PyObject *fields, PyObject *type, int isStruct); +extern int PyType_stginfo(PyTypeObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); +extern int PyObject_stginfo(PyObject *self, Py_ssize_t *psize, Py_ssize_t *palign, Py_ssize_t *plength); + + + +extern PyTypeObject CData_Type; +#define CDataObject_CheckExact(v) ((v)->ob_type == &CData_Type) +#define CDataObject_Check(v) PyObject_TypeCheck(v, &CData_Type) + +extern PyTypeObject SimpleType_Type; +#define SimpleTypeObject_CheckExact(v) ((v)->ob_type == &SimpleType_Type) +#define SimpleTypeObject_Check(v) PyObject_TypeCheck(v, &SimpleType_Type) + +extern PyTypeObject CField_Type; +extern struct fielddesc *getentry(char *fmt); + + +extern PyObject * +CField_FromDesc(PyObject *desc, int index, + int *pfield_size, int bitsize, int *pbitofs, + int *psize, int *poffset, int *palign, + int pack, int is_big_endian); + +extern PyObject *CData_AtAddress(PyObject *type, void *buf); +extern PyObject *CData_FromBytes(PyObject *type, char *data, Py_ssize_t length); + +extern PyTypeObject ArrayType_Type; +extern PyTypeObject Array_Type; +extern PyTypeObject PointerType_Type; +extern PyTypeObject Pointer_Type; +extern PyTypeObject CFuncPtr_Type; +extern PyTypeObject CFuncPtrType_Type; +extern PyTypeObject StructType_Type; + +#define ArrayTypeObject_Check(v) PyObject_TypeCheck(v, &ArrayType_Type) +#define ArrayObject_Check(v) PyObject_TypeCheck(v, &Array_Type) +#define PointerObject_Check(v) PyObject_TypeCheck(v, &Pointer_Type) +#define PointerTypeObject_Check(v) PyObject_TypeCheck(v, &PointerType_Type) +#define CFuncPtrObject_Check(v) PyObject_TypeCheck(v, &CFuncPtr_Type) +#define CFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, &CFuncPtrType_Type) +#define StructTypeObject_Check(v) PyObject_TypeCheck(v, &StructType_Type) + +extern PyObject * +CreateArrayType(PyObject *itemtype, Py_ssize_t length); + +extern void init_callbacks_in_module(PyObject *m); + +extern PyMethodDef module_methods[]; + +extern ffi_info *AllocFunctionCallback(PyObject *callable, + PyObject *converters, + PyObject *restype, + int stdcall); +/* a table entry describing a predefined ctypes type */ +struct fielddesc { + char code; + SETFUNC setfunc; + GETFUNC getfunc; + ffi_type *pffi_type; /* always statically allocated */ + SETFUNC setfunc_swapped; + GETFUNC getfunc_swapped; +}; + +typedef struct { + PyObject_HEAD + Py_ssize_t offset; + Py_ssize_t size; + Py_ssize_t index; /* Index into CDataObject's + object array */ + PyObject *proto; /* a type or NULL */ + GETFUNC getfunc; /* getter function if proto is NULL */ + SETFUNC setfunc; /* setter function if proto is NULL */ + int anonymous; +} CFieldObject; + +/* A subclass of PyDictObject, used as the instance dictionary of ctypes + metatypes */ +typedef struct { + PyDictObject dict; /* first part identical to PyDictObject */ +/* The size and align fields are unneeded, they are in ffi_type as well. As + an experiment shows, it's trivial to get rid of them, the only thing to + remember is that in ArrayType_new the ffi_type fields must be filled in - + so far it was unneeded because libffi doesn't support arrays at all + (because they are passed as pointers to function calls anyway). But it's + too much risk to change that now, and there are other fields which doen't + belong into this structure anyway. Maybe in ctypes 2.0... (ctypes 2000?) +*/ + Py_ssize_t size; /* number of bytes */ + Py_ssize_t align; /* alignment requirements */ + Py_ssize_t length; /* number of fields */ + ffi_type ffi_type_pointer; + PyObject *proto; /* Only for Pointer/ArrayObject */ + SETFUNC setfunc; /* Only for simple objects */ + GETFUNC getfunc; /* Only for simple objects */ + PARAMFUNC paramfunc; + + /* Following fields only used by CFuncPtrType_Type instances */ + PyObject *argtypes; /* tuple of CDataObjects */ + PyObject *converters; /* tuple([t.from_param for t in argtypes]) */ + PyObject *restype; /* CDataObject or NULL */ + PyObject *checker; + int flags; /* calling convention and such */ +} StgDictObject; + +/**************************************************************** + StgDictObject fields + + setfunc and getfunc is only set for simple data types, it is copied from the + corresponding fielddesc entry. These are functions to set and get the value + in a memory block. + They should probably by used by other types as well. + + proto is only used for Pointer and Array types - it points to the item type + object. + + Probably all the magic ctypes methods (like from_param) should have C + callable wrappers in the StgDictObject. For simple data type, for example, + the fielddesc table could have entries for C codec from_param functions or + other methods as well, if a subtype overrides this method in Python at + construction time, or assigns to it later, tp_setattro should update the + StgDictObject function to a generic one. + + Currently, CFuncPtr types have 'converters' and 'checker' entries in their + type dict. They are only used to cache attributes from other entries, whihc + is wrong. + + One use case is the .value attribute that all simple types have. But some + complex structures, like VARIANT, represent a single value also, and should + have this attribute. + + Another use case is a _check_retval_ function, which is called when a ctypes + type is used as return type of a function to validate and compute the return + value. + + Common ctypes protocol: + + - setfunc: store a python value in a memory block + - getfunc: convert data from a memory block into a python value + + - checkfunc: validate and convert a return value from a function call + - toparamfunc: convert a python value into a function argument + +*****************************************************************/ + +/* May return NULL, but does not set an exception! */ +extern StgDictObject *PyType_stgdict(PyObject *obj); + +/* May return NULL, but does not set an exception! */ +extern StgDictObject *PyObject_stgdict(PyObject *self); + +extern int StgDict_clone(StgDictObject *src, StgDictObject *dst); + +typedef int(* PPROC)(void); + +PyObject *_CallProc(PPROC pProc, + PyObject *arguments, +#ifdef MS_WIN32 + IUnknown *pIUnk, + GUID *iid, +#endif + int flags, + PyObject *argtypes, + PyObject *restype, + PyObject *checker); + + +#define FUNCFLAG_STDCALL 0x0 +#define FUNCFLAG_CDECL 0x1 +#define FUNCFLAG_HRESULT 0x2 +#define FUNCFLAG_PYTHONAPI 0x4 + +#define DICTFLAG_FINAL 0x1000 + +struct tagPyCArgObject { + PyObject_HEAD + ffi_type *pffi_type; + char tag; + union { + char c; + char b; + short h; + int i; + long l; +#ifdef HAVE_LONG_LONG + PY_LONG_LONG q; +#endif + double d; + float f; + void *p; + } value; + PyObject *obj; + int size; /* for the 'V' tag */ +}; + +extern PyTypeObject PyCArg_Type; +extern PyCArgObject *new_CArgObject(void); +#define PyCArg_CheckExact(v) ((v)->ob_type == &PyCArg_Type) +extern PyCArgObject *new_CArgObject(void); + +extern PyObject * +CData_get(PyObject *type, GETFUNC getfunc, PyObject *src, + Py_ssize_t index, Py_ssize_t size, char *ptr); + +extern int +CData_set(PyObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, + Py_ssize_t index, Py_ssize_t size, char *ptr); + +extern void Extend_Error_Info(PyObject *exc_class, char *fmt, ...); + +struct basespec { + CDataObject *base; + Py_ssize_t index; + char *adr; +}; + +extern char basespec_string[]; + +extern ffi_type *GetType(PyObject *obj); + +/* exception classes */ +extern PyObject *PyExc_ArgError; + +extern char *conversion_mode_encoding; +extern char *conversion_mode_errors; + +/* Python 2.4 macros, which are not available in Python 2.3 */ + +#ifndef Py_CLEAR +#define Py_CLEAR(op) \ + do { \ + if (op) { \ + PyObject *tmp = (PyObject *)(op); \ + (op) = NULL; \ + Py_DECREF(tmp); \ + } \ + } while (0) +#endif + +#ifndef Py_VISIT +/* Utility macro to help write tp_traverse functions. + * To use this macro, the tp_traverse function must name its arguments + * "visit" and "arg". This is intended to keep tp_traverse functions + * looking as much alike as possible. + */ +#define Py_VISIT(op) \ + do { \ + if (op) { \ + int vret = visit((op), arg); \ + if (vret) \ + return vret; \ + } \ + } while (0) +#endif + +/* Python's PyUnicode_*WideChar functions are broken ... */ +#if defined(Py_USING_UNICODE) && defined(HAVE_WCHAR_H) +# define CTYPES_UNICODE +#endif + + +#ifdef CTYPES_UNICODE +# undef PyUnicode_FromWideChar +# define PyUnicode_FromWideChar My_PyUnicode_FromWideChar + +# undef PyUnicode_AsWideChar +# define PyUnicode_AsWideChar My_PyUnicode_AsWideChar + +extern PyObject *My_PyUnicode_FromWideChar(const wchar_t *, Py_ssize_t); +extern int My_PyUnicode_AsWideChar(PyUnicodeObject *, wchar_t *, Py_ssize_t); + +#endif + +extern void FreeClosure(void *); +extern void *MallocClosure(void); + +extern void _AddTraceback(char *, char *, int); + +extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, Py_ssize_t index, char *adr); + +/* XXX better name needed! */ +extern int IsSimpleSubType(PyObject *obj); + + +#ifdef MS_WIN32 +extern PyObject *ComError; +#endif + +/* + Local Variables: + compile-command: "python setup.py -q build install --home ~" + End: +*/ diff --git a/sys/src/cmd/python/Modules/_ctypes/ctypes_dlfcn.h b/sys/src/cmd/python/Modules/_ctypes/ctypes_dlfcn.h new file mode 100644 index 000000000..d8bf904be --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/ctypes_dlfcn.h @@ -0,0 +1,31 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + +#ifndef _CTYPES_DLFCN_H_ +#define _CTYPES_DLFCN_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef MS_WIN32 + +#include <dlfcn.h> + +#ifndef CTYPES_DARWIN_DLFCN + +#define ctypes_dlsym dlsym +#define ctypes_dlerror dlerror +#define ctypes_dlopen dlopen +#define ctypes_dlclose dlclose +#define ctypes_dladdr dladdr + +#endif /* !CTYPES_DARWIN_DLFCN */ + +#endif /* !MS_WIN32 */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* _CTYPES_DLFCN_H_ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/darwin/LICENSE b/sys/src/cmd/python/Modules/_ctypes/darwin/LICENSE new file mode 100644 index 000000000..786fb5025 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/darwin/LICENSE @@ -0,0 +1,31 @@ +Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> & + Peter O'Gorman <ogorman@users.sourceforge.net> + +Portions may be copyright others, see the AUTHORS file included with this +distribution. + +Maintained by Peter O'Gorman <ogorman@users.sourceforge.net> + +Bug Reports and other queries should go to <ogorman@users.sourceforge.net> + + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/sys/src/cmd/python/Modules/_ctypes/darwin/README b/sys/src/cmd/python/Modules/_ctypes/darwin/README new file mode 100644 index 000000000..4d63f3dfa --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/darwin/README @@ -0,0 +1,95 @@ +dlcompat for Darwin +========================= + +This is dlcompat, a small library that emulates the dlopen() +interface on top of Darwin's dyld API. + +dlcompat allows loading a ".dylib" library (as long as the RTLD_LOCAL +flag isn't passed to dlopen()). It can be configured to yield a warning +when trying to close it (dynamic libraries cannot currently be unloaded). + +It automatically searches for modules in several directories when no +absolute path is specified and the module is not found in the current +directory. + +The paths searched are those specified in the environment variables +LD_LIBRARY_PATH and DYLD_LIBRARY_PATH plus /lib, /usr/local/lib and +/usr/lib or the path specified in the environment variable +DYLD_FALLBACK_LIBRARY_PATH. + +In the default install the behavior of dlsym is to automatically prepend +an underscore to passed in symbol names, this allows easier porting of +applications which were written specifically for ELF based lifeforms. + +Installation +-------------- +Type: + ./configure + make + sudo make install + +This will compile the source file, generate both a static and shared +library called libdl and install it into /usr/local/lib. The header +file dlfcn.h will be installed in /usr/local/include. + +If you want to place the files somewhere else, run + + make clean + ./configure --prefix=<prefix> + make + sudo make install + +where <prefix> is the hierarchy you want to install into, e.g. /usr +for /usr/lib and /usr/include (_NOT_ recommended!). + +To enable debugging output (useful for me), run + + make clean + ./configure --enable-debug + make + sudo make install + +If you want old dlcompat style behavior of not prepending the underscore +on calls to dlsym then type: + + make clean + ./configure --enable-fink + make + sudo make install + +Usage +------- +Software that uses GNU autoconf will likely check for a library called +libdl, that's why I named it that way. For software that doesn't find +the library on its own, you must add a '-ldl' to the appropriate +Makefile (or environment) variable, usually LIBS. + +If you installed dlcompat into a directory other than /usr/local/lib, +you must tell the compiler where to find it. Add '-L<prefix>/lib' to +LDFLAGS (or CFLAGS) and '-I<prefix>/include' to CPPFLAGS (or CFLAGS). + +Notes +----- +If you are writing new software and plan to have Mac OX X compatibility you +should look at the dyld api's in /usr/include/mach-o/dyld.h, rather than +using dlcompat, using the native api's is the supported method of loading +dynamically on Mac OS X, if you want an small example, look at dlfcn_simple.c, +which should help get you started. + +Also note that the functions in dlcompat are not thread safe, and while it is not +POSIX spec compliant, it is about as close to compliance as it is going to get though. + +You can always get the latest version from opendarwin cvs: + + cvs -d :pserver:anonymous@anoncvs.opendarwin.org:/cvs/od login + cvs -z3 -d :pserver:anonymous@anoncvs.opendarwin.org:/cvs/od \ + co -d dlcompat proj/dlcompat + + +It is hoped that this library will be useful, and as bug free as possible, if you find +any bugs please let us know about them so they can be fixed. + +Please send bug reports to Peter O'Gorman <ogorman@users.sourceforge.net> + +Thanks. + diff --git a/sys/src/cmd/python/Modules/_ctypes/darwin/README.ctypes b/sys/src/cmd/python/Modules/_ctypes/darwin/README.ctypes new file mode 100644 index 000000000..8520b01f4 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/darwin/README.ctypes @@ -0,0 +1,11 @@ +The files in this directory are taken from +http://www.opendarwin.org/cgi-bin/cvsweb.cgi/~checkout~/proj/dlcompat/ + +The LICENSE in this directory applies to these files. + +Thomas Heller, Jan 2003 + +These files have been modified so they fall back to the system +dlfcn calls if available in libSystem. + +Bob Ippolito, Feb 2006 diff --git a/sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn.h b/sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn.h new file mode 100644 index 000000000..a2afc3eeb --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn.h @@ -0,0 +1,84 @@ +/* +Copyright (c) 2002 Jorge Acereda <jacereda@users.sourceforge.net> & + Peter O'Gorman <ogorman@users.sourceforge.net> + +Portions may be copyright others, see the AUTHORS file included with this +distribution. + +Maintained by Peter O'Gorman <ogorman@users.sourceforge.net> + +Bug Reports and other queries should go to <ogorman@users.sourceforge.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef _DLFCN_H_ +#define _DLFCN_H_ + +#include <AvailabilityMacros.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + * Structure filled in by dladdr(). + */ + +typedef struct dl_info { + const char *dli_fname; /* Pathname of shared object */ + void *dli_fbase; /* Base address of shared object */ + const char *dli_sname; /* Name of nearest symbol */ + void *dli_saddr; /* Address of nearest symbol */ +} Dl_info; + + +#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_2 +#warning CTYPES_DARWIN_DLFCN +#define CTYPES_DARWIN_DLFCN +extern void * (*ctypes_dlopen)(const char *path, int mode); +extern void * (*ctypes_dlsym)(void * handle, const char *symbol); +extern const char * (*ctypes_dlerror)(void); +extern int (*ctypes_dlclose)(void * handle); +extern int (*ctypes_dladdr)(const void *, Dl_info *); +#else +extern void * dlopen(const char *path, int mode); +extern void * dlsym(void * handle, const char *symbol); +extern const char * dlerror(void); +extern int dlclose(void * handle); +extern int dladdr(const void *, Dl_info *); +#endif + +#define RTLD_LAZY 0x1 +#define RTLD_NOW 0x2 +#define RTLD_LOCAL 0x4 +#define RTLD_GLOBAL 0x8 +#define RTLD_NOLOAD 0x10 +#define RTLD_NODELETE 0x80 + +/* These are from the Mac OS X 10.4 headers */ +#define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */ +#define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */ + +#ifdef __cplusplus +} +#endif + +#endif /* _DLFCN_H_ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn_simple.c b/sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn_simple.c new file mode 100644 index 000000000..4b5532314 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/darwin/dlfcn_simple.c @@ -0,0 +1,272 @@ +/* +Copyright (c) 2002 Peter O'Gorman <ogorman@users.sourceforge.net> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +/* Just to prove that it isn't that hard to add Mac calls to your code :) + This works with pretty much everything, including kde3 xemacs and the gimp, + I'd guess that it'd work in at least 95% of cases, use this as your starting + point, rather than the mess that is dlfcn.c, assuming that your code does not + require ref counting or symbol lookups in dependent libraries +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdarg.h> +#include <limits.h> +#include <mach-o/dyld.h> +#include <AvailabilityMacros.h> +#include "dlfcn.h" + +#ifdef CTYPES_DARWIN_DLFCN + +#define ERR_STR_LEN 256 + +#ifndef MAC_OS_X_VERSION_10_3 +#define MAC_OS_X_VERSION_10_3 1030 +#endif + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 +#define DARWIN_HAS_DLOPEN +extern void * dlopen(const char *path, int mode) __attribute__((weak_import)); +extern void * dlsym(void * handle, const char *symbol) __attribute__((weak_import)); +extern const char * dlerror(void) __attribute__((weak_import)); +extern int dlclose(void * handle) __attribute__((weak_import)); +extern int dladdr(const void *, Dl_info *) __attribute__((weak_import)); +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 */ + +#ifndef DARWIN_HAS_DLOPEN +#define dlopen darwin_dlopen +#define dlsym darwin_dlsym +#define dlerror darwin_dlerror +#define dlclose darwin_dlclose +#define dladdr darwin_dladdr +#endif + +void * (*ctypes_dlopen)(const char *path, int mode); +void * (*ctypes_dlsym)(void * handle, const char *symbol); +const char * (*ctypes_dlerror)(void); +int (*ctypes_dlclose)(void * handle); +int (*ctypes_dladdr)(const void *, Dl_info *); + +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 +/* Mac OS X 10.3+ has dlopen, so strip all this dead code to avoid warnings */ + +static void *dlsymIntern(void *handle, const char *symbol); + +static const char *error(int setget, const char *str, ...); + +/* Set and get the error string for use by dlerror */ +static const char *error(int setget, const char *str, ...) +{ + static char errstr[ERR_STR_LEN]; + static int err_filled = 0; + const char *retval; + va_list arg; + if (setget == 0) + { + va_start(arg, str); + strncpy(errstr, "dlcompat: ", ERR_STR_LEN); + vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg); + va_end(arg); + err_filled = 1; + retval = NULL; + } + else + { + if (!err_filled) + retval = NULL; + else + retval = errstr; + err_filled = 0; + } + return retval; +} + +/* darwin_dlopen */ +static void *darwin_dlopen(const char *path, int mode) +{ + void *module = 0; + NSObjectFileImage ofi = 0; + NSObjectFileImageReturnCode ofirc; + + /* If we got no path, the app wants the global namespace, use -1 as the marker + in this case */ + if (!path) + return (void *)-1; + + /* Create the object file image, works for things linked with the -bundle arg to ld */ + ofirc = NSCreateObjectFileImageFromFile(path, &ofi); + switch (ofirc) + { + case NSObjectFileImageSuccess: + /* It was okay, so use NSLinkModule to link in the image */ + module = NSLinkModule(ofi, path, + NSLINKMODULE_OPTION_RETURN_ON_ERROR + | (mode & RTLD_GLOBAL) ? 0 : NSLINKMODULE_OPTION_PRIVATE + | (mode & RTLD_LAZY) ? 0 : NSLINKMODULE_OPTION_BINDNOW); + NSDestroyObjectFileImage(ofi); + break; + case NSObjectFileImageInappropriateFile: + /* It may have been a dynamic library rather than a bundle, try to load it */ + module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); + break; + default: + /* God knows what we got */ + error(0, "Can not open \"%s\"", path); + return 0; + } + if (!module) + error(0, "Can not open \"%s\"", path); + return module; + +} + +/* dlsymIntern is used by dlsym to find the symbol */ +static void *dlsymIntern(void *handle, const char *symbol) +{ + NSSymbol nssym = 0; + /* If the handle is -1, if is the app global context */ + if (handle == (void *)-1) + { + /* Global context, use NSLookupAndBindSymbol */ + if (NSIsSymbolNameDefined(symbol)) + { + nssym = NSLookupAndBindSymbol(symbol); + } + + } + /* Now see if the handle is a struch mach_header* or not, use NSLookupSymbol in image + for libraries, and NSLookupSymbolInModule for bundles */ + else + { + /* Check for both possible magic numbers depending on x86/ppc byte order */ + if ((((struct mach_header *)handle)->magic == MH_MAGIC) || + (((struct mach_header *)handle)->magic == MH_CIGAM)) + { + if (NSIsSymbolNameDefinedInImage((struct mach_header *)handle, symbol)) + { + nssym = NSLookupSymbolInImage((struct mach_header *)handle, + symbol, + NSLOOKUPSYMBOLINIMAGE_OPTION_BIND + | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); + } + + } + else + { + nssym = NSLookupSymbolInModule(handle, symbol); + } + } + if (!nssym) + { + error(0, "Symbol \"%s\" Not found", symbol); + return NULL; + } + return NSAddressOfSymbol(nssym); +} + +static const char *darwin_dlerror(void) +{ + return error(1, (char *)NULL); +} + +static int darwin_dlclose(void *handle) +{ + if ((((struct mach_header *)handle)->magic == MH_MAGIC) || + (((struct mach_header *)handle)->magic == MH_CIGAM)) + { + error(0, "Can't remove dynamic libraries on darwin"); + return 0; + } + if (!NSUnLinkModule(handle, 0)) + { + error(0, "unable to unlink module %s", NSNameOfModule(handle)); + return 1; + } + return 0; +} + + +/* dlsym, prepend the underscore and call dlsymIntern */ +static void *darwin_dlsym(void *handle, const char *symbol) +{ + static char undersym[257]; /* Saves calls to malloc(3) */ + int sym_len = strlen(symbol); + void *value = NULL; + char *malloc_sym = NULL; + + if (sym_len < 256) + { + snprintf(undersym, 256, "_%s", symbol); + value = dlsymIntern(handle, undersym); + } + else + { + malloc_sym = malloc(sym_len + 2); + if (malloc_sym) + { + sprintf(malloc_sym, "_%s", symbol); + value = dlsymIntern(handle, malloc_sym); + free(malloc_sym); + } + else + { + error(0, "Unable to allocate memory"); + } + } + return value; +} + +static int darwin_dladdr(const void *handle, Dl_info *info) { + return 0; +} +#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 */ + +#if __GNUC__ < 4 +#pragma CALL_ON_LOAD ctypes_dlfcn_init +#else +static void __attribute__ ((constructor)) ctypes_dlfcn_init(void); +static +#endif +void ctypes_dlfcn_init(void) { + if (dlopen != NULL) { + ctypes_dlsym = dlsym; + ctypes_dlopen = dlopen; + ctypes_dlerror = dlerror; + ctypes_dlclose = dlclose; + ctypes_dladdr = dladdr; + } else { +#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 + ctypes_dlsym = darwin_dlsym; + ctypes_dlopen = darwin_dlopen; + ctypes_dlerror = darwin_dlerror; + ctypes_dlclose = darwin_dlclose; + ctypes_dladdr = darwin_dladdr; +#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 */ + } +} + +#endif /* CTYPES_DARWIN_DLFCN */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/LICENSE b/sys/src/cmd/python/Modules/_ctypes/libffi/LICENSE new file mode 100644 index 000000000..f59179515 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/LICENSE @@ -0,0 +1,20 @@ +libffi - Copyright (c) 1996-2003 Red Hat, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +``Software''), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/README b/sys/src/cmd/python/Modules/_ctypes/libffi/README new file mode 100644 index 000000000..1fc27470d --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/README @@ -0,0 +1,500 @@ +This directory contains the libffi package, which is not part of GCC but +shipped with GCC as convenience. + +Status +====== + +libffi-2.00 has not been released yet! This is a development snapshot! + +libffi-1.20 was released on October 5, 1998. Check the libffi web +page for updates: <URL:http://sources.redhat.com/libffi/>. + + +What is libffi? +=============== + +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the "calling +convention". The "calling convention" is essentially a set of +assumptions made by the compiler about where function arguments will +be found on entry to a function. A "calling convention" also specifies +where the return value for a function is found. + +Some programs may not know at the time of compilation what arguments +are to be passed to a function. For instance, an interpreter may be +told at run-time about the number and types of arguments used to call +a given function. Libffi can be used in such programs to provide a +bridge from the interpreter program to compiled code. + +The libffi library provides a portable, high level programming +interface to various calling conventions. This allows a programmer to +call any function specified by a call interface description at run +time. + +Ffi stands for Foreign Function Interface. A foreign function +interface is the popular name for the interface that allows code +written in one language to call code written in another language. The +libffi library really only provides the lowest, machine dependent +layer of a fully featured foreign function interface. A layer must +exist above libffi that handles type conversions for values passed +between the two languages. + + +Supported Platforms and Prerequisites +===================================== + +Libffi has been ported to: + + SunOS 4.1.3 & Solaris 2.x (SPARC-V8, SPARC-V9) + + Irix 5.3 & 6.2 (System V/o32 & n32) + + Intel x86 - Linux (System V ABI) + + Alpha - Linux and OSF/1 + + m68k - Linux (System V ABI) + + PowerPC - Linux (System V ABI, Darwin, AIX) + + ARM - Linux (System V ABI) + +Libffi has been tested with the egcs 1.0.2 gcc compiler. Chances are +that other versions will work. Libffi has also been built and tested +with the SGI compiler tools. + +On PowerPC, the tests failed (see the note below). + +You must use GNU make to build libffi. SGI's make will not work. +Sun's probably won't either. + +If you port libffi to another platform, please let me know! I assume +that some will be easy (x86 NetBSD), and others will be more difficult +(HP). + + +Installing libffi +================= + +[Note: before actually performing any of these installation steps, + you may wish to read the "Platform Specific Notes" below.] + +First you must configure the distribution for your particular +system. Go to the directory you wish to build libffi in and run the +"configure" program found in the root directory of the libffi source +distribution. + +You may want to tell configure where to install the libffi library and +header files. To do that, use the --prefix configure switch. Libffi +will install under /usr/local by default. + +If you want to enable extra run-time debugging checks use the the +--enable-debug configure switch. This is useful when your program dies +mysteriously while using libffi. + +Another useful configure switch is --enable-purify-safety. Using this +will add some extra code which will suppress certain warnings when you +are using Purify with libffi. Only use this switch when using +Purify, as it will slow down the library. + +Configure has many other options. Use "configure --help" to see them all. + +Once configure has finished, type "make". Note that you must be using +GNU make. SGI's make will not work. Sun's probably won't either. +You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. + +To ensure that libffi is working as advertised, type "make test". + +To install the library and header files, type "make install". + + +Using libffi +============ + + The Basics + ---------- + +Libffi assumes that you have a pointer to the function you wish to +call and that you know the number and types of arguments to pass it, +as well as the return type of the function. + +The first thing you must do is create an ffi_cif object that matches +the signature of the function you wish to call. The cif in ffi_cif +stands for Call InterFace. To prepare a call interface object, use the +following function: + +ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, + unsigned int nargs, + ffi_type *rtype, ffi_type **atypes); + + CIF is a pointer to the call interface object you wish + to initialize. + + ABI is an enum that specifies the calling convention + to use for the call. FFI_DEFAULT_ABI defaults + to the system's native calling convention. Other + ABI's may be used with care. They are system + specific. + + NARGS is the number of arguments this function accepts. + libffi does not yet support vararg functions. + + RTYPE is a pointer to an ffi_type structure that represents + the return type of the function. Ffi_type objects + describe the types of values. libffi provides + ffi_type objects for many of the native C types: + signed int, unsigned int, signed char, unsigned char, + etc. There is also a pointer ffi_type object and + a void ffi_type. Use &ffi_type_void for functions that + don't return values. + + ATYPES is a vector of ffi_type pointers. ARGS must be NARGS long. + If NARGS is 0, this is ignored. + + +ffi_prep_cif will return a status code that you are responsible +for checking. It will be one of the following: + + FFI_OK - All is good. + + FFI_BAD_TYPEDEF - One of the ffi_type objects that ffi_prep_cif + came across is bad. + + +Before making the call, the VALUES vector should be initialized +with pointers to the appropriate argument values. + +To call the the function using the initialized ffi_cif, use the +ffi_call function: + +void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues); + + CIF is a pointer to the ffi_cif initialized specifically + for this function. + + FN is a pointer to the function you want to call. + + RVALUE is a pointer to a chunk of memory that is to hold the + result of the function call. Currently, it must be + at least one word in size (except for the n32 version + under Irix 6.x, which must be a pointer to an 8 byte + aligned value (a long long). It must also be at least + word aligned (depending on the return type, and the + system's alignment requirements). If RTYPE is + &ffi_type_void, this is ignored. If RVALUE is NULL, + the return value is discarded. + + AVALUES is a vector of void* that point to the memory locations + holding the argument values for a call. + If NARGS is 0, this is ignored. + + +If you are expecting a return value from FN it will have been stored +at RVALUE. + + + + An Example + ---------- + +Here is a trivial example that calls puts() a few times. + + #include <stdio.h> + #include <ffi.h> + + int main() + { + ffi_cif cif; + ffi_type *args[1]; + void *values[1]; + char *s; + int rc; + + /* Initialize the argument info vectors */ + args[0] = &ffi_type_uint; + values[0] = &s; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, args) == FFI_OK) + { + s = "Hello World!"; + ffi_call(&cif, puts, &rc, values); + /* rc now holds the result of the call to puts */ + + /* values holds a pointer to the function's arg, so to + call puts() again all we need to do is change the + value of s */ + s = "This is cool!"; + ffi_call(&cif, puts, &rc, values); + } + + return 0; + } + + + + Aggregate Types + --------------- + +Although libffi has no special support for unions or bit-fields, it is +perfectly happy passing structures back and forth. You must first +describe the structure to libffi by creating a new ffi_type object +for it. Here is the definition of ffi_type: + + typedef struct _ffi_type + { + unsigned size; + short alignment; + short type; + struct _ffi_type **elements; + } ffi_type; + +All structures must have type set to FFI_TYPE_STRUCT. You may set +size and alignment to 0. These will be calculated and reset to the +appropriate values by ffi_prep_cif(). + +elements is a NULL terminated array of pointers to ffi_type objects +that describe the type of the structure elements. These may, in turn, +be structure elements. + +The following example initializes a ffi_type object representing the +tm struct from Linux's time.h: + + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + /* Those are for future use. */ + long int __tm_gmtoff__; + __const char *__tm_zone__; + }; + + { + ffi_type tm_type; + ffi_type *tm_type_elements[12]; + int i; + + tm_type.size = tm_type.alignment = 0; + tm_type.elements = &tm_type_elements; + + for (i = 0; i < 9; i++) + tm_type_elements[i] = &ffi_type_sint; + + tm_type_elements[9] = &ffi_type_slong; + tm_type_elements[10] = &ffi_type_pointer; + tm_type_elements[11] = NULL; + + /* tm_type can now be used to represent tm argument types and + return types for ffi_prep_cif() */ + } + + + +Platform Specific Notes +======================= + + Intel x86 + --------- + +There are no known problems with the x86 port. + + Sun SPARC - SunOS 4.1.3 & Solaris 2.x + ------------------------------------- + +You must use GNU Make to build libffi on Sun platforms. + + MIPS - Irix 5.3 & 6.x + --------------------- + +Irix 6.2 and better supports three different calling conventions: o32, +n32 and n64. Currently, libffi only supports both o32 and n32 under +Irix 6.x, but only o32 under Irix 5.3. Libffi will automatically be +configured for whichever calling convention it was built for. + +By default, the configure script will try to build libffi with the GNU +development tools. To build libffi with the SGI development tools, set +the environment variable CC to either "cc -32" or "cc -n32" before +running configure under Irix 6.x (depending on whether you want an o32 +or n32 library), or just "cc" for Irix 5.3. + +With the n32 calling convention, when returning structures smaller +than 16 bytes, be sure to provide an RVALUE that is 8 byte aligned. +Here's one way of forcing this: + + double struct_storage[2]; + my_small_struct *s = (my_small_struct *) struct_storage; + /* Use s for RVALUE */ + +If you don't do this you are liable to get spurious bus errors. + +"long long" values are not supported yet. + +You must use GNU Make to build libffi on SGI platforms. + + ARM - System V ABI + ------------------ + +The ARM port was performed on a NetWinder running ARM Linux ELF +(2.0.31) and gcc 2.8.1. + + + + PowerPC System V ABI + -------------------- + +There are two `System V ABI's which libffi implements for PowerPC. +They differ only in how small structures are returned from functions. + +In the FFI_SYSV version, structures that are 8 bytes or smaller are +returned in registers. This is what GCC does when it is configured +for solaris, and is what the System V ABI I have (dated September +1995) says. + +In the FFI_GCC_SYSV version, all structures are returned the same way: +by passing a pointer as the first argument to the function. This is +what GCC does when it is configured for linux or a generic sysv +target. + +EGCS 1.0.1 (and probably other versions of EGCS/GCC) also has a +inconsistency with the SysV ABI: When a procedure is called with many +floating-point arguments, some of them get put on the stack. They are +all supposed to be stored in double-precision format, even if they are +only single-precision, but EGCS stores single-precision arguments as +single-precision anyway. This causes one test to fail (the `many +arguments' test). + + +What's With The Crazy Comments? +=============================== + +You might notice a number of cryptic comments in the code, delimited +by /*@ and @*/. These are annotations read by the program LCLint, a +tool for statically checking C programs. You can read all about it at +<http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>. + + +History +======= + +1.20 Oct-5-98 + Raffaele Sena produces ARM port. + +1.19 Oct-5-98 + Fixed x86 long double and long long return support. + m68k bug fixes from Andreas Schwab. + Patch for DU assembler compatibility for the Alpha from Richard + Henderson. + +1.18 Apr-17-98 + Bug fixes and MIPS configuration changes. + +1.17 Feb-24-98 + Bug fixes and m68k port from Andreas Schwab. PowerPC port from + Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes. + +1.16 Feb-11-98 + Richard Henderson produces Alpha port. + +1.15 Dec-4-97 + Fixed an n32 ABI bug. New libtool, auto* support. + +1.14 May-13-97 + libtool is now used to generate shared and static libraries. + Fixed a minor portability problem reported by Russ McManus + <mcmanr@eq.gs.com>. + +1.13 Dec-2-96 + Added --enable-purify-safety to keep Purify from complaining + about certain low level code. + Sparc fix for calling functions with < 6 args. + Linux x86 a.out fix. + +1.12 Nov-22-96 + Added missing ffi_type_void, needed for supporting void return + types. Fixed test case for non MIPS machines. Cygnus Support + is now Cygnus Solutions. + +1.11 Oct-30-96 + Added notes about GNU make. + +1.10 Oct-29-96 + Added configuration fix for non GNU compilers. + +1.09 Oct-29-96 + Added --enable-debug configure switch. Clean-ups based on LCLint + feedback. ffi_mips.h is always installed. Many configuration + fixes. Fixed ffitest.c for sparc builds. + +1.08 Oct-15-96 + Fixed n32 problem. Many clean-ups. + +1.07 Oct-14-96 + Gordon Irlam rewrites v8.S again. Bug fixes. + +1.06 Oct-14-96 + Gordon Irlam improved the sparc port. + +1.05 Oct-14-96 + Interface changes based on feedback. + +1.04 Oct-11-96 + Sparc port complete (modulo struct passing bug). + +1.03 Oct-10-96 + Passing struct args, and returning struct values works for + all architectures/calling conventions. Expanded tests. + +1.02 Oct-9-96 + Added SGI n32 support. Fixed bugs in both o32 and Linux support. + Added "make test". + +1.01 Oct-8-96 + Fixed float passing bug in mips version. Restructured some + of the code. Builds cleanly with SGI tools. + +1.00 Oct-7-96 + First release. No public announcement. + + +Authors & Credits +================= + +libffi was written by Anthony Green <green@cygnus.com>. + +Portions of libffi were derived from Gianni Mariani's free gencall +library for Silicon Graphics machines. + +The closure mechanism was designed and implemented by Kresten Krab +Thorup. + +The Sparc port was derived from code contributed by the fine folks at +Visible Decisions Inc <http://www.vdi.com>. Further enhancements were +made by Gordon Irlam at Cygnus Solutions <http://www.cygnus.com>. + +The Alpha port was written by Richard Henderson at Cygnus Solutions. + +Andreas Schwab ported libffi to m68k Linux and provided a number of +bug fixes. + +Geoffrey Keating ported libffi to the PowerPC. + +Raffaele Sena ported libffi to the ARM. + +Jesper Skov and Andrew Haley both did more than their fair share of +stepping through the code and tracking down bugs. + +Thanks also to Tom Tromey for bug fixes and configuration help. + +Thanks to Jim Blandy, who provided some useful feedback on the libffi +interface. + +If you have a problem, or have found a bug, please send a note to +green@cygnus.com. diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/aclocal.m4 b/sys/src/cmd/python/Modules/_ctypes/libffi/aclocal.m4 new file mode 100644 index 000000000..3e8f8ba57 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/aclocal.m4 @@ -0,0 +1,92 @@ +# mmap(2) blacklisting. Some platforms provide the mmap library routine +# but don't support all of the features we need from it. +AC_DEFUN([AC_FUNC_MMAP_BLACKLIST], +[ +AC_CHECK_HEADER([sys/mman.h], + [libffi_header_sys_mman_h=yes], [libffi_header_sys_mman_h=no]) +AC_CHECK_FUNC([mmap], [libffi_func_mmap=yes], [libffi_func_mmap=no]) +if test "$libffi_header_sys_mman_h" != yes \ + || test "$libffi_func_mmap" != yes; then + ac_cv_func_mmap_file=no + ac_cv_func_mmap_dev_zero=no + ac_cv_func_mmap_anon=no +else + AC_CACHE_CHECK([whether read-only mmap of a plain file works], + ac_cv_func_mmap_file, + [# Add a system to this blacklist if + # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a + # memory area containing the same data that you'd get if you applied + # read() to the same fd. The only system known to have a problem here + # is VMS, where text files have record structure. + case "$host_os" in + vms* | ultrix*) + ac_cv_func_mmap_file=no ;; + *) + ac_cv_func_mmap_file=yes;; + esac]) + AC_CACHE_CHECK([whether mmap from /dev/zero works], + ac_cv_func_mmap_dev_zero, + [# Add a system to this blacklist if it has mmap() but /dev/zero + # does not exist, or if mmapping /dev/zero does not give anonymous + # zeroed pages with both the following properties: + # 1. If you map N consecutive pages in with one call, and then + # unmap any subset of those pages, the pages that were not + # explicitly unmapped remain accessible. + # 2. If you map two adjacent blocks of memory and then unmap them + # both at once, they must both go away. + # Systems known to be in this category are Windows (all variants), + # VMS, and Darwin. + case "$host_os" in + vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) + ac_cv_func_mmap_dev_zero=no ;; + *) + ac_cv_func_mmap_dev_zero=yes;; + esac]) + + # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for. + AC_CACHE_CHECK([for MAP_ANON(YMOUS)], ac_cv_decl_map_anon, + [AC_TRY_COMPILE( +[#include <sys/types.h> +#include <sys/mman.h> +#include <unistd.h> + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +], +[int n = MAP_ANONYMOUS;], + ac_cv_decl_map_anon=yes, + ac_cv_decl_map_anon=no)]) + + if test $ac_cv_decl_map_anon = no; then + ac_cv_func_mmap_anon=no + else + AC_CACHE_CHECK([whether mmap with MAP_ANON(YMOUS) works], + ac_cv_func_mmap_anon, + [# Add a system to this blacklist if it has mmap() and MAP_ANON or + # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + # doesn't give anonymous zeroed pages with the same properties listed + # above for use of /dev/zero. + # Systems known to be in this category are Windows, VMS, and SCO Unix. + case "$host_os" in + vms* | cygwin* | pe | mingw* | sco* | udk* ) + ac_cv_func_mmap_anon=no ;; + *) + ac_cv_func_mmap_anon=yes;; + esac]) + fi +fi + +if test $ac_cv_func_mmap_file = yes; then + AC_DEFINE(HAVE_MMAP_FILE, 1, + [Define if read-only mmap of a plain file works.]) +fi +if test $ac_cv_func_mmap_dev_zero = yes; then + AC_DEFINE(HAVE_MMAP_DEV_ZERO, 1, + [Define if mmap of /dev/zero works.]) +fi +if test $ac_cv_func_mmap_anon = yes; then + AC_DEFINE(HAVE_MMAP_ANON, 1, + [Define if mmap with MAP_ANON(YMOUS) works.]) +fi +]) diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/config.guess b/sys/src/cmd/python/Modules/_ctypes/libffi/config.guess new file mode 100755 index 000000000..822947132 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/config.guess @@ -0,0 +1,1453 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + +timestamp='2004-11-12' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Per Bothner <per@bothner.com>. +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit 0 ;; + amd64:OpenBSD:*:*) + echo x86_64-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + cats:OpenBSD:*:*) + echo arm-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + luna88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + macppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvmeppc:OpenBSD:*:*) + echo powerpc-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips64-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit 0 ;; + macppc:MirBSD:*:*) + echo powerppc-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit 0 ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit 0 ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit 0;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit 0 ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit 0 ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit 0 ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit 0 ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7 && exit 0 ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit 0 ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit 0 ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit 0 ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit 0 ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c \ + && $dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && exit 0 + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit 0 ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + # avoid double evaluation of $set_cc_for_build + test -n "$CC_FOR_BUILD" || eval $set_cc_for_build + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E -) | grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && $dummy && exit 0 + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit 0 ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit 0 ;; + x86:Interix*:[34]*) + echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//' + exit 0 ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit 0 ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit 0 ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit 0 ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit 0 ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit 0 ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit 0 ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit 0 ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^CPU=` + test x"${CPU}" != x && echo "${CPU}-unknown-linux-gnu" && exit 0 + ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit 0 ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit 0 ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit 0 ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit 0 ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit 0 ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit 0 ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit 0 ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit 0 ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit 0 ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit 0 ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit 0 ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #ifdef __INTEL_COMPILER + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=` + test x"${LIBC}" != x && echo "${UNAME_MACHINE}-pc-linux-${LIBC}" && exit 0 + test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0 + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit 0 ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit 0 ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit 0 ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit 0 ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit 0 ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit 0 ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit 0 ;; + i*86:*:5:[78]*) + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit 0 ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit 0 ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit 0 ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit 0 ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit 0 ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit 0 ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit 0 ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + *86) UNAME_PROCESSOR=i686 ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit 0 ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit 0 ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit 0 ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit 0 ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit 0 ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit 0 ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit 0 ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit 0 ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit 0 ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit 0 ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit 0 ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit 0 ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit 0 ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit 0 ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit 0 ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms && exit 0 ;; + I*) echo ia64-dec-vms && exit 0 ;; + V*) echo vax-dec-vms && exit 0 ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && $dummy && exit 0 + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + ftp://ftp.gnu.org/pub/gnu/config/ + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/config.sub b/sys/src/cmd/python/Modules/_ctypes/libffi/config.sub new file mode 100644 index 000000000..04aeffed5 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/config.sub @@ -0,0 +1,1569 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. + +timestamp='2005-04-22' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit 0 ;; + --version | -v ) + echo "$version" ; exit 0 ;; + --help | --h* | -h ) + echo "$usage"; exit 0 ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit 0;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | \ + kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32r | m32rle | m68000 | m68k | m88k | maxq | mcore \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | msp430 \ + | ns16k | ns32k \ + | openrisc | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | sh | sh[1234] | sh[23]e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b \ + | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | msp430-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[23]e-* | sh[34]eb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + or32 | or32-*) + basic_machine=or32-unknown + os=-coff + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh3 | sh4 | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -plan9* | -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* | -openbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-uclibc* | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/configure b/sys/src/cmd/python/Modules/_ctypes/libffi/configure new file mode 100755 index 000000000..9808384ce --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/configure @@ -0,0 +1,6864 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.59 for libffi 2.1. +# +# Report bugs to <http://gcc.gnu.org/bugs.html>. +# +# Copyright (C) 2003 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2 + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +exec 6>&1 + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_config_libobj_dir=. +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Maximum number of lines to put in a shell here document. +# This variable seems obsolete. It should probably be removed, and +# only ac_max_sed_lines should be used. +: ${ac_max_here_lines=38} + +# Identity of this package. +PACKAGE_NAME='libffi' +PACKAGE_TARNAME='libffi' +PACKAGE_VERSION='2.1' +PACKAGE_STRING='libffi 2.1' +PACKAGE_BUGREPORT='http://gcc.gnu.org/bugs.html' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#if STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# if HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#if HAVE_INTTYPES_H +# include <inttypes.h> +#else +# if HAVE_STDINT_H +# include <stdint.h> +# endif +#endif +#if HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC ac_ct_CC EXEEXT OBJEXT CFLAGS CPP CPPFLAGS EGREP ALLOCA HAVE_LONG_DOUBLE TARGET TARGETDIR MKTARGET LIBOBJS LTLIBOBJS' +ac_subst_files='' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +ac_prev= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'` + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_option in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval "enable_$ac_feature=no" ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "enable_$ac_feature='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + case $ac_option in + *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;; + *) ac_optarg=yes ;; + esac + eval "with_$ac_package='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval "with_$ac_package=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` + eval "$ac_envvar='$ac_optarg'" + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute paths. +for ac_var in exec_prefix prefix +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* | NONE | '' ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# Be sure to have absolute paths. +for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \ + localstatedir libdir includedir oldincludedir infodir mandir +do + eval ac_val=$`echo $ac_var` + case $ac_val in + [\\/$]* | ?:[\\/]* ) ;; + *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; };; + esac +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_confdir=`(dirname "$0") 2>/dev/null || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 + { (exit 1); exit 1; }; } + else + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } + fi +fi +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || + { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 + { (exit 1); exit 1; }; } +srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` +ac_env_build_alias_set=${build_alias+set} +ac_env_build_alias_value=$build_alias +ac_cv_env_build_alias_set=${build_alias+set} +ac_cv_env_build_alias_value=$build_alias +ac_env_host_alias_set=${host_alias+set} +ac_env_host_alias_value=$host_alias +ac_cv_env_host_alias_set=${host_alias+set} +ac_cv_env_host_alias_value=$host_alias +ac_env_target_alias_set=${target_alias+set} +ac_env_target_alias_value=$target_alias +ac_cv_env_target_alias_set=${target_alias+set} +ac_cv_env_target_alias_value=$target_alias +ac_env_CPP_set=${CPP+set} +ac_env_CPP_value=$CPP +ac_cv_env_CPP_set=${CPP+set} +ac_cv_env_CPP_value=$CPP +ac_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_env_CPPFLAGS_value=$CPPFLAGS +ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set} +ac_cv_env_CPPFLAGS_value=$CPPFLAGS + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libffi 2.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +_ACEOF + + cat <<_ACEOF +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data [PREFIX/share] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --infodir=DIR info documentation [PREFIX/info] + --mandir=DIR man documentation [PREFIX/man] +_ACEOF + + cat <<\_ACEOF + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libffi 2.1:";; + esac + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have + headers in a nonstandard directory <include dir> + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to <http://gcc.gnu.org/bugs.html>. +_ACEOF +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + ac_popdir=`pwd` + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d $ac_dir || continue + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + cd $ac_dir + # Check for guested configure; otherwise get Cygnus style configure. + if test -f $ac_srcdir/configure.gnu; then + echo + $SHELL $ac_srcdir/configure.gnu --help=recursive + elif test -f $ac_srcdir/configure; then + echo + $SHELL $ac_srcdir/configure --help=recursive + elif test -f $ac_srcdir/configure.ac || + test -f $ac_srcdir/configure.in; then + echo + $ac_configure --help + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi + cd "$ac_popdir" + done +fi + +test -n "$ac_init_help" && exit 0 +if $ac_init_version; then + cat <<\_ACEOF +libffi configure 2.1 +generated by GNU Autoconf 2.59 + +Copyright (C) 2003 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit 0 +fi +exec 5>config.log +cat >&5 <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libffi $as_me 2.1, which was +generated by GNU Autoconf 2.59. Invocation command line was + + $ $0 $@ + +_ACEOF +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +hostinfo = `(hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_sep= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'" + # Get rid of the leading space. + ac_sep=" " + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Be sure not to use single quotes in there, as some shells, +# such as our DU 5.0 friend, will then `close' the trap. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +{ + (set) 2>&1 | + case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in + *ac_space=\ *) + sed -n \ + "s/'"'"'/'"'"'\\\\'"'"''"'"'/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p" + ;; + *) + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------- ## +## Output files. ## +## ------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=$`echo $ac_var` + echo "$ac_var='"'"'$ac_val'"'"'" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + sed "/^$/d" confdefs.h | sort + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core && + rm -rf conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status + ' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo >confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . $cache_file;; + *) . ./$cache_file;; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in `(set) 2>&1 | + sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val="\$ac_cv_env_${ac_var}_value" + eval ac_new_val="\$ac_env_${ac_var}_value" + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*) + ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + + + + + + + + + + + + + + + + + + + + + + ac_config_headers="$ac_config_headers fficonfig.h" + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f $ac_dir/shtool; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5 +echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;} + { (exit 1); exit 1; }; } +fi +ac_config_guess="$SHELL $ac_aux_dir/config.guess" +ac_config_sub="$SHELL $ac_aux_dir/config.sub" +ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure. + +# Make sure we can run config.sub. +$ac_config_sub sun4 >/dev/null 2>&1 || + { { echo "$as_me:$LINENO: error: cannot run $ac_config_sub" >&5 +echo "$as_me: error: cannot run $ac_config_sub" >&2;} + { (exit 1); exit 1; }; } + +echo "$as_me:$LINENO: checking build system type" >&5 +echo $ECHO_N "checking build system type... $ECHO_C" >&6 +if test "${ac_cv_build+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_build_alias=$build_alias +test -z "$ac_cv_build_alias" && + ac_cv_build_alias=`$ac_config_guess` +test -z "$ac_cv_build_alias" && + { { echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 +echo "$as_me: error: cannot guess build type; you must specify one" >&2;} + { (exit 1); exit 1; }; } +ac_cv_build=`$ac_config_sub $ac_cv_build_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_build_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_build" >&5 +echo "${ECHO_T}$ac_cv_build" >&6 +build=$ac_cv_build +build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking host system type" >&5 +echo $ECHO_N "checking host system type... $ECHO_C" >&6 +if test "${ac_cv_host+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_host_alias=$host_alias +test -z "$ac_cv_host_alias" && + ac_cv_host_alias=$ac_cv_build_alias +ac_cv_host=`$ac_config_sub $ac_cv_host_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_host_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_host" >&5 +echo "${ECHO_T}$ac_cv_host" >&6 +host=$ac_cv_host +host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +echo "$as_me:$LINENO: checking target system type" >&5 +echo $ECHO_N "checking target system type... $ECHO_C" >&6 +if test "${ac_cv_target+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_target_alias=$target_alias +test "x$ac_cv_target_alias" = "x" && + ac_cv_target_alias=$ac_cv_host_alias +ac_cv_target=`$ac_config_sub $ac_cv_target_alias` || + { { echo "$as_me:$LINENO: error: $ac_config_sub $ac_cv_target_alias failed" >&5 +echo "$as_me: error: $ac_config_sub $ac_cv_target_alias failed" >&2;} + { (exit 1); exit 1; }; } + +fi +echo "$as_me:$LINENO: result: $ac_cv_target" >&5 +echo "${ECHO_T}$ac_cv_target" >&6 +target=$ac_cv_target +target_cpu=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $ac_cv_target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- +target_alias=${target_alias-$host_alias} + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + CC=$ac_ct_CC +else + CC="$ac_cv_prog_CC" +fi + +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CC" && break +done + + CC=$ac_ct_CC +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5 + (eval $ac_compiler --version </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5 + (eval $ac_compiler -v </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5 + (eval $ac_compiler -V </dev/null >&5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6 +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5 + (eval $ac_link_default) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Find the output, starting from the most likely. This scheme is +# not robust to junk in `.', hence go to wildcards (a.*) only as a last +# resort. + +# Be careful to initialize this variable, since it used to be cached. +# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile. +ac_cv_exeext= +# b.out is created by i960 compilers. +for ac_file in a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) + ;; + conftest.$ac_ext ) + # This is the source file. + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + # FIXME: I believe we export ac_cv_exeext for Libtool, + # but it would be cool to find out if it's true. Does anybody + # maintain Libtool? --akim. + export ac_cv_exeext + break;; + * ) + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6 + +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6 +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6 +echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6 + +echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6 +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + export ac_cv_exeext + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6 + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6 +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6 +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6 +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6 +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +CFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cc_g=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6 +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5 +echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6 +if test "${ac_cv_prog_cc_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_stdc=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std1 is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std1. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX 10.20 and later -Ae +# HP-UX older versions -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_stdc=$ac_arg +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext +done +rm -f conftest.$ac_ext conftest.$ac_objext +CC=$ac_save_CC + +fi + +case "x$ac_cv_prog_cc_stdc" in + x|xno) + echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6 ;; + *) + echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6 + CC="$CC $ac_cv_prog_cc_stdc" ;; +esac + +# Some people use a C++ compiler to compile C. Since we use `exit', +# in C++ we need to declare it. In case someone uses the same compiler +# for both compiling C and C++ we need to have the C++ compiler decide +# the declaration of exit, since it's the most demanding environment. +cat >conftest.$ac_ext <<_ACEOF +#ifndef __cplusplus + choke me +#endif +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + for ac_declaration in \ + '' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +#include <stdlib.h> +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6 +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether non-existent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6 +if test "${ac_cv_prog_egrep+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | (grep -E '(a|b)') >/dev/null 2>&1 + then ac_cv_prog_egrep='grep -E' + else ac_cv_prog_egrep='egrep' + fi +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_egrep" >&5 +echo "${ECHO_T}$ac_cv_prog_egrep" >&6 + EGREP=$ac_cv_prog_egrep + + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_Header=no" +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +for ac_header in sys/mman.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------- ## +## Report this to http://gcc.gnu.org/bugs.html ## +## ------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6 +if eval "test \"\${$as_ac_Header+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6 + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_func in mmap +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +if test "${ac_cv_header_sys_mman_h+set}" = set; then + echo "$as_me:$LINENO: checking for sys/mman.h" >&5 +echo $ECHO_N "checking for sys/mman.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_mman_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_mman_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_mman_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking sys/mman.h usability" >&5 +echo $ECHO_N "checking sys/mman.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <sys/mman.h> +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking sys/mman.h presence" >&5 +echo $ECHO_N "checking sys/mman.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <sys/mman.h> +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: sys/mman.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: sys/mman.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: sys/mman.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: sys/mman.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: sys/mman.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: sys/mman.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: sys/mman.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: sys/mman.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: sys/mman.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: sys/mman.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## ------------------------------------------- ## +## Report this to http://gcc.gnu.org/bugs.html ## +## ------------------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for sys/mman.h" >&5 +echo $ECHO_N "checking for sys/mman.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_mman_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_sys_mman_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_mman_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_mman_h" >&6 + +fi +if test $ac_cv_header_sys_mman_h = yes; then + libffi_header_sys_mman_h=yes +else + libffi_header_sys_mman_h=no +fi + + +echo "$as_me:$LINENO: checking for mmap" >&5 +echo $ECHO_N "checking for mmap... $ECHO_C" >&6 +if test "${ac_cv_func_mmap+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define mmap to an innocuous variant, in case <limits.h> declares mmap. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define mmap innocuous_mmap + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char mmap (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef mmap + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char mmap (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_mmap) || defined (__stub___mmap) +choke me +#else +char (*f) () = mmap; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != mmap; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_mmap=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_mmap=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mmap" >&5 +echo "${ECHO_T}$ac_cv_func_mmap" >&6 +if test $ac_cv_func_mmap = yes; then + libffi_func_mmap=yes +else + libffi_func_mmap=no +fi + +if test "$libffi_header_sys_mman_h" != yes \ + || test "$libffi_func_mmap" != yes; then + ac_cv_func_mmap_file=no + ac_cv_func_mmap_dev_zero=no + ac_cv_func_mmap_anon=no +else + echo "$as_me:$LINENO: checking whether read-only mmap of a plain file works" >&5 +echo $ECHO_N "checking whether read-only mmap of a plain file works... $ECHO_C" >&6 +if test "${ac_cv_func_mmap_file+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Add a system to this blacklist if + # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a + # memory area containing the same data that you'd get if you applied + # read() to the same fd. The only system known to have a problem here + # is VMS, where text files have record structure. + case "$host_os" in + vms* | ultrix*) + ac_cv_func_mmap_file=no ;; + *) + ac_cv_func_mmap_file=yes;; + esac +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mmap_file" >&5 +echo "${ECHO_T}$ac_cv_func_mmap_file" >&6 + echo "$as_me:$LINENO: checking whether mmap from /dev/zero works" >&5 +echo $ECHO_N "checking whether mmap from /dev/zero works... $ECHO_C" >&6 +if test "${ac_cv_func_mmap_dev_zero+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Add a system to this blacklist if it has mmap() but /dev/zero + # does not exist, or if mmapping /dev/zero does not give anonymous + # zeroed pages with both the following properties: + # 1. If you map N consecutive pages in with one call, and then + # unmap any subset of those pages, the pages that were not + # explicitly unmapped remain accessible. + # 2. If you map two adjacent blocks of memory and then unmap them + # both at once, they must both go away. + # Systems known to be in this category are Windows (all variants), + # VMS, and Darwin. + case "$host_os" in + vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) + ac_cv_func_mmap_dev_zero=no ;; + *) + ac_cv_func_mmap_dev_zero=yes;; + esac +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mmap_dev_zero" >&5 +echo "${ECHO_T}$ac_cv_func_mmap_dev_zero" >&6 + + # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for. + echo "$as_me:$LINENO: checking for MAP_ANON(YMOUS)" >&5 +echo $ECHO_N "checking for MAP_ANON(YMOUS)... $ECHO_C" >&6 +if test "${ac_cv_decl_map_anon+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <sys/types.h> +#include <sys/mman.h> +#include <unistd.h> + +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +int +main () +{ +int n = MAP_ANONYMOUS; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_decl_map_anon=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_decl_map_anon=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_decl_map_anon" >&5 +echo "${ECHO_T}$ac_cv_decl_map_anon" >&6 + + if test $ac_cv_decl_map_anon = no; then + ac_cv_func_mmap_anon=no + else + echo "$as_me:$LINENO: checking whether mmap with MAP_ANON(YMOUS) works" >&5 +echo $ECHO_N "checking whether mmap with MAP_ANON(YMOUS) works... $ECHO_C" >&6 +if test "${ac_cv_func_mmap_anon+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Add a system to this blacklist if it has mmap() and MAP_ANON or + # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) + # doesn't give anonymous zeroed pages with the same properties listed + # above for use of /dev/zero. + # Systems known to be in this category are Windows, VMS, and SCO Unix. + case "$host_os" in + vms* | cygwin* | pe | mingw* | sco* | udk* ) + ac_cv_func_mmap_anon=no ;; + *) + ac_cv_func_mmap_anon=yes;; + esac +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mmap_anon" >&5 +echo "${ECHO_T}$ac_cv_func_mmap_anon" >&6 + fi +fi + +if test $ac_cv_func_mmap_file = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MMAP_FILE 1 +_ACEOF + +fi +if test $ac_cv_func_mmap_dev_zero = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MMAP_DEV_ZERO 1 +_ACEOF + +fi +if test $ac_cv_func_mmap_anon = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_MMAP_ANON 1 +_ACEOF + +fi + + +TARGETDIR="unknown" +case "$host" in +x86_64-*-openbsd*) TARGET=X86_64; TARGETDIR=x86;; +mips*-*-openbsd*) TARGET=MIPS; TARGETDIR=mips;; +sparc-*-openbsd*) TARGET=SPARC; TARGETDIR=sparc;; +sparc64-*-openbsd*) TARGET=SPARC; TARGETDIR=sparc;; +alpha*-*-openbsd*) TARGET=ALPHA; TARGETDIR=alpha;; +m68k-*-openbsd*) TARGET=M68K; TARGETDIR=m68k;; +powerpc-*-openbsd*) TARGET=POWERPC; TARGETDIR=powerpc;; +i*86-*-darwin*) TARGET=X86_DARWIN; TARGETDIR=x86;; +i*86-*-linux*) TARGET=X86; TARGETDIR=x86;; +i*86-*-gnu*) TARGET=X86; TARGETDIR=x86;; +i*86-*-solaris2.1[0-9]*) TARGET=X86_64; TARGETDIR=x86;; +i*86-*-solaris*) TARGET=X86; TARGETDIR=x86;; +i*86-*-beos*) TARGET=X86; TARGETDIR=x86;; +i*86-*-freebsd* | i*86-*-kfreebsd*-gnu) TARGET=X86; TARGETDIR=x86;; +i*86-*-netbsdelf* | i*86-*-knetbsd*-gnu) TARGET=X86; TARGETDIR=x86;; +i*86-*-openbsd*) TARGET=X86; TARGETDIR=x86;; +i*86-*-rtems*) TARGET=X86; TARGETDIR=x86;; +i*86-*-win32*) TARGET=X86_WIN32; TARGETDIR=x86;; +i*86-*-cygwin*) TARGET=X86_WIN32; TARGETDIR=x86;; +i*86-*-mingw*) TARGET=X86_WIN32; TARGETDIR=x86;; +frv-*-*) TARGET=FRV; TARGETDIR=frv;; +sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;; +sparc*-sun-*) TARGET=SPARC; TARGETDIR=sparc;; +sparc-*-linux* | sparc-*-netbsdelf* | sparc-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;; +sparc*-*-rtems*) TARGET=SPARC; TARGETDIR=sparc;; +sparc64-*-linux* | sparc64-*-freebsd* | sparc64-*-netbsd* | sparc64-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;; +alpha*-*-linux* | alpha*-*-osf* | alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-netbsd* | alpha*-*-knetbsd*-gnu) TARGET=ALPHA; TARGETDIR=alpha;; +ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;; +m32r*-*-linux* ) TARGET=M32R; TARGETDIR=m32r;; +m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;; +mips64*-*);; +mips-sgi-irix5.* | mips-sgi-irix6.*) TARGET=MIPS_IRIX; TARGETDIR=mips;; +mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;; +powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;; +powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;; +powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;; +powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; +powerpc-*-freebsd*) TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc;; +powerpc*-*-rtems*) TARGET=POWERPC; TARGETDIR=powerpc;; +rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; +arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;; +arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu) TARGET=ARM; TARGETDIR=arm;; +arm*-*-rtems*) TARGET=ARM; TARGETDIR=arm;; +cris-*-*) TARGET=LIBFFI_CRIS; TARGETDIR=cris;; +s390-*-linux-*) TARGET=S390; TARGETDIR=s390;; +s390x-*-linux-*) TARGET=S390; TARGETDIR=s390;; +x86_64-*-linux* | x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) TARGET=X86_64; TARGETDIR=x86;; +sh-*-linux* | sh[34]*-*-linux*) TARGET=SH; TARGETDIR=sh;; +sh-*-rtems*) TARGET=SH; TARGETDIR=sh;; +sh64-*-linux* | sh5*-*-linux*) TARGET=SH64; TARGETDIR=sh64;; +hppa-*-linux* | parisc-*-linux*) TARGET=PA; TARGETDIR=pa;; +esac + +if test $TARGETDIR = unknown; then + { { echo "$as_me:$LINENO: error: \"libffi has not been ported to $host.\"" >&5 +echo "$as_me: error: \"libffi has not been ported to $host.\"" >&2;} + { (exit 1); exit 1; }; } +fi + +MKTARGET=$TARGET + +case x$TARGET in + xMIPS*) TARGET=MIPS ;; + *) ;; +esac + +echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_header_stdc=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + exit(2); + exit (0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6 +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + +for ac_func in memcpy +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +echo "$as_me:$LINENO: checking for working alloca.h" >&5 +echo $ECHO_N "checking for working alloca.h... $ECHO_C" >&6 +if test "${ac_cv_working_alloca_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <alloca.h> +int +main () +{ +char *p = (char *) alloca (2 * sizeof (int)); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_working_alloca_h=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_working_alloca_h=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_working_alloca_h" >&5 +echo "${ECHO_T}$ac_cv_working_alloca_h" >&6 +if test $ac_cv_working_alloca_h = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ALLOCA_H 1 +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for alloca" >&5 +echo $ECHO_N "checking for alloca... $ECHO_C" >&6 +if test "${ac_cv_func_alloca_works+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include <malloc.h> +# define alloca _alloca +# else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +int +main () +{ +char *p = (char *) alloca (1); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_alloca_works=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_alloca_works=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_alloca_works" >&5 +echo "${ECHO_T}$ac_cv_func_alloca_works" >&6 + +if test $ac_cv_func_alloca_works = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_ALLOCA 1 +_ACEOF + +else + # The SVR3 libPW and SVR4 libucb both contain incompatible functions +# that cause trouble. Some versions do not even contain alloca or +# contain a buggy version. If you still want to use their alloca, +# use ar to extract alloca.o from them instead of compiling alloca.c. + +ALLOCA=alloca.$ac_objext + +cat >>confdefs.h <<\_ACEOF +#define C_ALLOCA 1 +_ACEOF + + +echo "$as_me:$LINENO: checking whether \`alloca.c' needs Cray hooks" >&5 +echo $ECHO_N "checking whether \`alloca.c' needs Cray hooks... $ECHO_C" >&6 +if test "${ac_cv_os_cray+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#if defined(CRAY) && ! defined(CRAY2) +webecray +#else +wenotbecray +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "webecray" >/dev/null 2>&1; then + ac_cv_os_cray=yes +else + ac_cv_os_cray=no +fi +rm -f conftest* + +fi +echo "$as_me:$LINENO: result: $ac_cv_os_cray" >&5 +echo "${ECHO_T}$ac_cv_os_cray" >&6 +if test $ac_cv_os_cray = yes; then + for ac_func in _getb67 GETB67 getb67; do + as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + +cat >>confdefs.h <<_ACEOF +#define CRAY_STACKSEG_END $ac_func +_ACEOF + + break +fi + + done +fi + +echo "$as_me:$LINENO: checking stack direction for C alloca" >&5 +echo $ECHO_N "checking stack direction for C alloca... $ECHO_C" >&6 +if test "${ac_cv_c_stack_direction+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + ac_cv_c_stack_direction=0 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +int +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} + +int +main () +{ + exit (find_stack_direction () < 0); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_stack_direction=1 +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_stack_direction=-1 +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_c_stack_direction" >&5 +echo "${ECHO_T}$ac_cv_c_stack_direction" >&6 + +cat >>confdefs.h <<_ACEOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +_ACEOF + + +fi + + +echo "$as_me:$LINENO: checking for double" >&5 +echo $ECHO_N "checking for double... $ECHO_C" >&6 +if test "${ac_cv_type_double+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((double *) 0) + return 0; +if (sizeof (double)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_double=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_double=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_double" >&5 +echo "${ECHO_T}$ac_cv_type_double" >&6 + +echo "$as_me:$LINENO: checking size of double" >&5 +echo $ECHO_N "checking size of double... $ECHO_C" >&6 +if test "${ac_cv_sizeof_double+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_double" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (double))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (double))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (double))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (double))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (double))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_double=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (double), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (double), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: internal error: not reached in cross-compile" >&5 +echo "$as_me: error: internal error: not reached in cross-compile" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (double)); } +unsigned long ulongval () { return (long) (sizeof (double)); } +#include <stdio.h> +#include <stdlib.h> +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (double))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (double)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (double)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_double=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (double), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (double), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_double=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_double" >&5 +echo "${ECHO_T}$ac_cv_sizeof_double" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_DOUBLE $ac_cv_sizeof_double +_ACEOF + + +echo "$as_me:$LINENO: checking for long double" >&5 +echo $ECHO_N "checking for long double... $ECHO_C" >&6 +if test "${ac_cv_type_long_double+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +if ((long double *) 0) + return 0; +if (sizeof (long double)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_long_double=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_type_long_double=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_type_long_double" >&5 +echo "${ECHO_T}$ac_cv_type_long_double" >&6 + +echo "$as_me:$LINENO: checking size of long double" >&5 +echo $ECHO_N "checking size of long double... $ECHO_C" >&6 +if test "${ac_cv_sizeof_long_double+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_long_double" = yes; then + # The cast to unsigned long works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long double))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long double))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long double))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long double))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo= ac_hi= +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !(((long) (sizeof (long double))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_lo=`expr '(' $ac_mid ')' + 1` +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long_double=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long double), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long double), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } ;; +esac +else + if test "$cross_compiling" = yes; then + { { echo "$as_me:$LINENO: error: internal error: not reached in cross-compile" >&5 +echo "$as_me: error: internal error: not reached in cross-compile" >&2;} + { (exit 1); exit 1; }; } +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +long longval () { return (long) (sizeof (long double)); } +unsigned long ulongval () { return (long) (sizeof (long double)); } +#include <stdio.h> +#include <stdlib.h> +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + exit (1); + if (((long) (sizeof (long double))) < 0) + { + long i = longval (); + if (i != ((long) (sizeof (long double)))) + exit (1); + fprintf (f, "%ld\n", i); + } + else + { + unsigned long i = ulongval (); + if (i != ((long) (sizeof (long double)))) + exit (1); + fprintf (f, "%lu\n", i); + } + exit (ferror (f) || fclose (f) != 0); + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long_double=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long double), 77 +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long double), 77 +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.val +else + ac_cv_sizeof_long_double=0 +fi +fi +echo "$as_me:$LINENO: result: $ac_cv_sizeof_long_double" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long_double" >&6 +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG_DOUBLE $ac_cv_sizeof_long_double +_ACEOF + + + +# Also AC_SUBST this variable for ffi.h. +HAVE_LONG_DOUBLE=0 +if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then + if test $ac_cv_sizeof_long_double != 0; then + HAVE_LONG_DOUBLE=1 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LONG_DOUBLE 1 +_ACEOF + + fi +fi + + +echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 +echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 +if test "${ac_cv_c_bigendian+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # See if sys/param.h defines the BYTE_ORDER macro. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <sys/types.h> +#include <sys/param.h> + +int +main () +{ +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + # It does; now see whether it defined to BIG_ENDIAN or not. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <sys/types.h> +#include <sys/param.h> + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_c_bigendian=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +# It does not; compile a test program. +if test "$cross_compiling" = yes; then + # try to guess the endianness by grepping values into an object file + ac_cv_c_bigendian=unknown + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +short ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; +short ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; +void _ascii () { char *s = (char *) ascii_mm; s = (char *) ascii_ii; } +short ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; +short ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; +void _ebcdic () { char *s = (char *) ebcdic_mm; s = (char *) ebcdic_ii; } +int +main () +{ + _ascii (); _ebcdic (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + if grep BIGenDianSyS conftest.$ac_objext >/dev/null ; then + ac_cv_c_bigendian=yes +fi +if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi +fi +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +int +main () +{ + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +} +_ACEOF +rm -f conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_bigendian=no +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_c_bigendian=yes +fi +rm -f core *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_c_bigendian" >&5 +echo "${ECHO_T}$ac_cv_c_bigendian" >&6 +case $ac_cv_c_bigendian in + yes) + +cat >>confdefs.h <<\_ACEOF +#define WORDS_BIGENDIAN 1 +_ACEOF + ;; + no) + ;; + *) + { { echo "$as_me:$LINENO: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&5 +echo "$as_me: error: unknown endianness +presetting ac_cv_c_bigendian=no (or yes) will help" >&2;} + { (exit 1); exit 1; }; } ;; +esac + + + + + +if test x$TARGET = xSPARC; then + echo "$as_me:$LINENO: checking assembler and linker support unaligned pc related relocs" >&5 +echo $ECHO_N "checking assembler and linker support unaligned pc related relocs... $ECHO_C" >&6 +if test "${libffi_cv_as_sparc_ua_pcrel+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + save_CFLAGS="$CFLAGS" + save_LDFLAGS="$LDFLAGS" + CFLAGS="$CFLAGS -fpic" + LDFLAGS="$LDFLAGS -shared" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text"); +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + libffi_cv_as_sparc_ua_pcrel=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +libffi_cv_as_sparc_ua_pcrel=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$save_CFLAGS" + LDFLAGS="$save_LDFLAGS" +fi +echo "$as_me:$LINENO: result: $libffi_cv_as_sparc_ua_pcrel" >&5 +echo "${ECHO_T}$libffi_cv_as_sparc_ua_pcrel" >&6 + if test "x$libffi_cv_as_sparc_ua_pcrel" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_AS_SPARC_UA_PCREL 1 +_ACEOF + + fi + + echo "$as_me:$LINENO: checking assembler .register pseudo-op support" >&5 +echo $ECHO_N "checking assembler .register pseudo-op support... $ECHO_C" >&6 +if test "${libffi_cv_as_register_pseudo_op+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + libffi_cv_as_register_pseudo_op=unknown + # Check if we have .register + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +asm (".register %g2, #scratch"); +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + libffi_cv_as_register_pseudo_op=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +libffi_cv_as_register_pseudo_op=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +echo "$as_me:$LINENO: result: $libffi_cv_as_register_pseudo_op" >&5 +echo "${ECHO_T}$libffi_cv_as_register_pseudo_op" >&6 + if test "x$libffi_cv_as_register_pseudo_op" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_AS_REGISTER_PSEUDO_OP 1 +_ACEOF + + fi +fi + +echo "$as_me:$LINENO: checking whether .eh_frame section should be read-only" >&5 +echo $ECHO_N "checking whether .eh_frame section should be read-only... $ECHO_C" >&6 +if test "${libffi_cv_ro_eh_frame+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + libffi_cv_ro_eh_frame=no + echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c + if $CC $CFLAGS -S -fpic -fexceptions -o conftest.s conftest.c > /dev/null 2>&1; then + if grep '.section.*eh_frame.*"a"' conftest.s > /dev/null; then + libffi_cv_ro_eh_frame=yes + elif grep '.section.*eh_frame.*#alloc' conftest.c \ + | grep -v '#write' > /dev/null; then + libffi_cv_ro_eh_frame=yes + fi + fi + rm -f conftest.* + +fi +echo "$as_me:$LINENO: result: $libffi_cv_ro_eh_frame" >&5 +echo "${ECHO_T}$libffi_cv_ro_eh_frame" >&6 +if test "x$libffi_cv_ro_eh_frame" = xyes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_RO_EH_FRAME 1 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define EH_FRAME_FLAGS "a" +_ACEOF + +else + +cat >>confdefs.h <<\_ACEOF +#define EH_FRAME_FLAGS "aw" +_ACEOF + +fi + +echo "$as_me:$LINENO: checking for __attribute__((visibility(\"hidden\")))" >&5 +echo $ECHO_N "checking for __attribute__((visibility(\"hidden\")))... $ECHO_C" >&6 +if test "${libffi_cv_hidden_visibility_attribute+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + echo 'int __attribute__ ((visibility ("hidden"))) foo (void) { return 1; }' > conftest.c + libffi_cv_hidden_visibility_attribute=no + if { ac_try='${CC-cc} -Werror -S conftest.c -o conftest.s 1>&5' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + if grep '\.hidden.*foo' conftest.s >/dev/null; then + libffi_cv_hidden_visibility_attribute=yes + fi + fi + rm -f conftest.* + +fi +echo "$as_me:$LINENO: result: $libffi_cv_hidden_visibility_attribute" >&5 +echo "${ECHO_T}$libffi_cv_hidden_visibility_attribute" >&6 +if test $libffi_cv_hidden_visibility_attribute = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_HIDDEN_VISIBILITY_ATTRIBUTE 1 +_ACEOF + +fi + + + + + + + + + + + +cat >>confdefs.h <<\_ACEOF +#define FFI_NO_RAW_API 1 +_ACEOF + + + ac_config_commands="$ac_config_commands include" + + ac_config_commands="$ac_config_commands src" + + +TARGETINCDIR=$TARGETDIR +case $host in +*-*-darwin*) + TARGETINCDIR="darwin" + ;; +esac + + + ac_config_links="$ac_config_links include/ffitarget.h:src/$TARGETINCDIR/ffitarget.h" + + ac_config_links="$ac_config_links include/ffi_common.h:include/ffi_common.h" + + + ac_config_files="$ac_config_files include/ffi.h fficonfig.py" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +{ + (set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n \ + "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p" + ;; + esac; +} | + sed ' + t clear + : clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + : end' >>confcache +if diff $cache_file confcache >/dev/null 2>&1; then :; else + if test -w $cache_file; then + test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file" + cat confcache >$cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/; +s/:*\${srcdir}:*/:/; +s/:*@srcdir@:*/:/; +s/^\([^=]*=[ ]*\):*/\1/; +s/:*$//; +s/^[^=]*=[ ]*$//; +}' +fi + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_i=`echo "$ac_i" | + sed 's/\$U\././;s/\.o$//;s/\.obj$//'` + # 2. Add them. + ac_libobjs="$ac_libobjs $ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs $ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' +elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then + set -o posix +fi +DUALCASE=1; export DUALCASE # for MKS sh + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# Work around bugs in pre-3.0 UWIN ksh. +$as_unset ENV MAIL MAILPATH +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)$' \| \ + . : '\(.\)' 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; } + /^X\/\(\/\/\)$/{ s//\1/; q; } + /^X\/\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + + +# PATH needs CR, and LINENO needs CR and PATH. +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" || { + # Find who we are. Look in the path if we contain no path at all + # relative or not. + case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done + + ;; + esac + # We did not find ourselves, most probably we were run as `sh COMMAND' + # in which case we are not to be found in the path. + if test "x$as_myself" = x; then + as_myself=$0 + fi + if test ! -f "$as_myself"; then + { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5 +echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;} + { (exit 1); exit 1; }; } + fi + case $CONFIG_SHELL in + '') + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for as_base in sh bash ksh sh5; do + case $as_dir in + /*) + if ("$as_dir/$as_base" -c ' + as_lineno_1=$LINENO + as_lineno_2=$LINENO + as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null` + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then + $as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; } + $as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; } + CONFIG_SHELL=$as_dir/$as_base + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$0" ${1+"$@"} + fi;; + esac + done +done +;; + esac + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line before each line; the second 'sed' does the real + # work. The second script uses 'N' to pair each line-number line + # with the numbered line, and appends trailing '-' during + # substitution so that $LINENO is not a special case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-) + sed '=' <$as_myself | + sed ' + N + s,$,-, + : loop + s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3, + t loop + s,-$,, + s,^['$as_cr_digits']*\n,, + ' >$as_me.lineno && + chmod +x $as_me.lineno || + { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5 +echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;} + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensible to this). + . ./$as_me.lineno + # Exit status is that of the last command. + exit +} + + +case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in + *c*,-n*) ECHO_N= ECHO_C=' +' ECHO_T=' ' ;; + *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; + *) ECHO_N= ECHO_C='\c' ECHO_T= ;; +esac + +if expr a : '\(a\)' >/dev/null 2>&1; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + # We could just check for DJGPP; but this test a) works b) is more generic + # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04). + if test -f conf$$.exe; then + # Don't use ln at all; we don't have any links + as_ln_s='cp -p' + else + as_ln_s='ln -s' + fi +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.file + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_executable_p="test -f" + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +# IFS +# We need space, tab and new line, in precisely that order. +as_nl=' +' +IFS=" $as_nl" + +# CDPATH. +$as_unset CDPATH + +exec 6>&1 + +# Open the log real soon, to keep \$[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. Logging --version etc. is OK. +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX +} >&5 +cat >&5 <<_CSEOF + +This file was extended by libffi $as_me 2.1, which was +generated by GNU Autoconf 2.59. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +_CSEOF +echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5 +echo >&5 +_ACEOF + +# Files that config.status was made for. +if test -n "$ac_config_files"; then + echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_headers"; then + echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_links"; then + echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS +fi + +if test -n "$ac_config_commands"; then + echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS +fi + +cat >>$CONFIG_STATUS <<\_ACEOF + +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration links: +$config_links + +Configuration commands: +$config_commands + +Report bugs to <bug-autoconf@gnu.org>." +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +libffi config.status 2.1 +configured by $0, generated by GNU Autoconf 2.59, + with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2003 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." +srcdir=$srcdir +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "x$1" : 'x\([^=]*\)='` + ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'` + ac_shift=: + ;; + -*) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + *) # This is not an option, so the user has probably given explicit + # arguments. + ac_option=$1 + ac_need_defaults=false;; + esac + + case $ac_option in + # Handling of the options. +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --vers* | -V ) + echo "$ac_cs_version"; exit 0 ;; + --he | --h) + # Conflict between --help and --header + { { echo "$as_me:$LINENO: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&5 +echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2;} + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running $SHELL $0 " $ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + exec $SHELL $0 $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS section. +# + +TARGETDIR="$TARGETDIR" + +_ACEOF + + + +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_config_target in $ac_config_targets +do + case "$ac_config_target" in + # Handling of arguments. + "include/ffi.h" ) CONFIG_FILES="$CONFIG_FILES include/ffi.h" ;; + "fficonfig.py" ) CONFIG_FILES="$CONFIG_FILES fficonfig.py" ;; + "include/ffitarget.h" ) CONFIG_LINKS="$CONFIG_LINKS include/ffitarget.h:src/$TARGETINCDIR/ffitarget.h" ;; + "include/ffi_common.h" ) CONFIG_LINKS="$CONFIG_LINKS include/ffi_common.h:include/ffi_common.h" ;; + "include" ) CONFIG_COMMANDS="$CONFIG_COMMANDS include" ;; + "src" ) CONFIG_COMMANDS="$CONFIG_COMMANDS src" ;; + "fficonfig.h" ) CONFIG_HEADERS="$CONFIG_HEADERS fficonfig.h" ;; + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_LINKS+set}" = set || CONFIG_LINKS=$config_links + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason to put it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Create a temporary directory, and hook for its removal unless debugging. +$debug || +{ + trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} + +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./confstat$$-$RANDOM + (umask 077 && mkdir $tmp) +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF + +# +# CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "\$CONFIG_FILES"; then + # Protect against being on the right side of a sed subst in config.status. + sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g; + s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF +s,@SHELL@,$SHELL,;t t +s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t +s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t +s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t +s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t +s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t +s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t +s,@exec_prefix@,$exec_prefix,;t t +s,@prefix@,$prefix,;t t +s,@program_transform_name@,$program_transform_name,;t t +s,@bindir@,$bindir,;t t +s,@sbindir@,$sbindir,;t t +s,@libexecdir@,$libexecdir,;t t +s,@datadir@,$datadir,;t t +s,@sysconfdir@,$sysconfdir,;t t +s,@sharedstatedir@,$sharedstatedir,;t t +s,@localstatedir@,$localstatedir,;t t +s,@libdir@,$libdir,;t t +s,@includedir@,$includedir,;t t +s,@oldincludedir@,$oldincludedir,;t t +s,@infodir@,$infodir,;t t +s,@mandir@,$mandir,;t t +s,@build_alias@,$build_alias,;t t +s,@host_alias@,$host_alias,;t t +s,@target_alias@,$target_alias,;t t +s,@DEFS@,$DEFS,;t t +s,@ECHO_C@,$ECHO_C,;t t +s,@ECHO_N@,$ECHO_N,;t t +s,@ECHO_T@,$ECHO_T,;t t +s,@LIBS@,$LIBS,;t t +s,@build@,$build,;t t +s,@build_cpu@,$build_cpu,;t t +s,@build_vendor@,$build_vendor,;t t +s,@build_os@,$build_os,;t t +s,@host@,$host,;t t +s,@host_cpu@,$host_cpu,;t t +s,@host_vendor@,$host_vendor,;t t +s,@host_os@,$host_os,;t t +s,@target@,$target,;t t +s,@target_cpu@,$target_cpu,;t t +s,@target_vendor@,$target_vendor,;t t +s,@target_os@,$target_os,;t t +s,@CC@,$CC,;t t +s,@ac_ct_CC@,$ac_ct_CC,;t t +s,@EXEEXT@,$EXEEXT,;t t +s,@OBJEXT@,$OBJEXT,;t t +s,@CFLAGS@,$CFLAGS,;t t +s,@CPP@,$CPP,;t t +s,@CPPFLAGS@,$CPPFLAGS,;t t +s,@EGREP@,$EGREP,;t t +s,@ALLOCA@,$ALLOCA,;t t +s,@HAVE_LONG_DOUBLE@,$HAVE_LONG_DOUBLE,;t t +s,@TARGET@,$TARGET,;t t +s,@TARGETDIR@,$TARGETDIR,;t t +s,@MKTARGET@,$MKTARGET,;t t +s,@LIBOBJS@,$LIBOBJS,;t t +s,@LTLIBOBJS@,$LTLIBOBJS,;t t +CEOF + +_ACEOF + + cat >>$CONFIG_STATUS <<\_ACEOF + # Split the substitutions into bite-sized pieces for seds with + # small command number limits, like on Digital OSF/1 and HP-UX. + ac_max_sed_lines=48 + ac_sed_frag=1 # Number of current file. + ac_beg=1 # First line for current file. + ac_end=$ac_max_sed_lines # Line after last line for current file. + ac_more_lines=: + ac_sed_cmds= + while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + else + sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag + fi + if test ! -s $tmp/subs.frag; then + ac_more_lines=false + else + # The purpose of the label and of the branching condition is to + # speed up the sed processing (if there are no `@' at all, there + # is no need to browse any of the substitutions). + # These are the two extra sed commands mentioned above. + (echo ':t + /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed" + else + ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed" + fi + ac_sed_frag=`expr $ac_sed_frag + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_lines` + fi + done + if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat + fi +fi # test -n "$CONFIG_FILES" + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories. + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + configure_input= + else + configure_input="$ac_file. " + fi + configure_input=$configure_input"Generated from `echo $ac_file_in | + sed 's,.*/,,'` by configure." + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + + if test x"$ac_file" != x-; then + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + rm -f "$ac_file" + fi +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s,@configure_input@,$configure_input,;t t +s,@srcdir@,$ac_srcdir,;t t +s,@abs_srcdir@,$ac_abs_srcdir,;t t +s,@top_srcdir@,$ac_top_srcdir,;t t +s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t +s,@builddir@,$ac_builddir,;t t +s,@abs_builddir@,$ac_abs_builddir,;t t +s,@top_builddir@,$ac_top_builddir,;t t +s,@abs_top_builddir@,$ac_abs_top_builddir,;t t +" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out + rm -f $tmp/stdin + if test x"$ac_file" != x-; then + mv $tmp/out $ac_file + else + cat $tmp/out + rm -f $tmp/out + fi + +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_HEADER section. +# + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='[ ].*$,\1#\2' +ac_dC=' ' +ac_dD=',;t' +# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='$,\1#\2define\3' +ac_uC=' ' +ac_uD=',;t' + +for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case $ac_file in + - | *:- | *:-:* ) # input from stdin + cat >$tmp/stdin + ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;; + * ) ac_file_in=$ac_file.in ;; + esac + + test x"$ac_file" != x- && { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + + # First look for the input files in the build tree, otherwise in the + # src tree. + ac_file_inputs=`IFS=: + for f in $ac_file_in; do + case $f in + -) echo $tmp/stdin ;; + [\\/$]*) + # Absolute (can't be DOS-style, as IFS=:) + test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + # Do quote $f, to prevent DOS paths from being IFS'd. + echo "$f";; + *) # Relative + if test -f "$f"; then + # Build tree + echo "$f" + elif test -f "$srcdir/$f"; then + # Source tree + echo "$srcdir/$f" + else + # /dev/null tree + { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5 +echo "$as_me: error: cannot find input file: $f" >&2;} + { (exit 1); exit 1; }; } + fi;; + esac + done` || { (exit 1); exit 1; } + # Remove the trailing spaces. + sed 's/[ ]*$//' $ac_file_inputs >$tmp/in + +_ACEOF + +# Transform confdefs.h into two sed scripts, `conftest.defines' and +# `conftest.undefs', that substitutes the proper values into +# config.h.in to produce config.h. The first handles `#define' +# templates, and the second `#undef' templates. +# And first: Protect against being on the right side of a sed subst in +# config.status. Protect against being in an unquoted here document +# in config.status. +rm -f conftest.defines conftest.undefs +# Using a here document instead of a string reduces the quoting nightmare. +# Putting comments in sed scripts is not portable. +# +# `end' is used to avoid that the second main sed command (meant for +# 0-ary CPP macros) applies to n-ary macro definitions. +# See the Autoconf documentation for `clear'. +cat >confdef2sed.sed <<\_ACEOF +s/[\\&,]/\\&/g +s,[\\$`],\\&,g +t clear +: clear +s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*\)\(([^)]*)\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1\2${ac_dC}\3${ac_dD},gp +t end +s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)$,${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD},gp +: end +_ACEOF +# If some macros were called several times there might be several times +# the same #defines, which is useless. Nevertheless, we may not want to +# sort them, since we want the *last* AC-DEFINE to be honored. +uniq confdefs.h | sed -n -f confdef2sed.sed >conftest.defines +sed 's/ac_d/ac_u/g' conftest.defines >conftest.undefs +rm -f confdef2sed.sed + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >>conftest.undefs <<\_ACEOF +s,^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*,/* & */, +_ACEOF + +# Break up conftest.defines because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #define templates only if necessary.' >>$CONFIG_STATUS +echo ' if grep "^[ ]*#[ ]*define" $tmp/in >/dev/null; then' >>$CONFIG_STATUS +echo ' # If there are no defines, we may have an empty if/fi' >>$CONFIG_STATUS +echo ' :' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.defines >/dev/null +do + # Write a limited-size here document to $tmp/defines.sed. + echo ' cat >$tmp/defines.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#define' lines. + echo '/^[ ]*#[ ]*define/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/defines.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.defines >conftest.tail + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines +echo ' fi # grep' >>$CONFIG_STATUS +echo >>$CONFIG_STATUS + +# Break up conftest.undefs because some shells have a limit on the size +# of here documents, and old seds have small limits too (100 cmds). +echo ' # Handle all the #undef templates' >>$CONFIG_STATUS +rm -f conftest.tail +while grep . conftest.undefs >/dev/null +do + # Write a limited-size here document to $tmp/undefs.sed. + echo ' cat >$tmp/undefs.sed <<CEOF' >>$CONFIG_STATUS + # Speed up: don't consider the non `#undef' + echo '/^[ ]*#[ ]*undef/!b' >>$CONFIG_STATUS + # Work around the forget-to-reset-the-flag bug. + echo 't clr' >>$CONFIG_STATUS + echo ': clr' >>$CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.undefs >>$CONFIG_STATUS + echo 'CEOF + sed -f $tmp/undefs.sed $tmp/in >$tmp/out + rm -f $tmp/in + mv $tmp/out $tmp/in +' >>$CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.undefs >conftest.tail + rm -f conftest.undefs + mv conftest.tail conftest.undefs +done +rm -f conftest.undefs + +cat >>$CONFIG_STATUS <<\_ACEOF + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + if test x"$ac_file" = x-; then + echo "/* Generated by configure. */" >$tmp/config.h + else + echo "/* $ac_file. Generated by configure. */" >$tmp/config.h + fi + cat $tmp/in >>$tmp/config.h + rm -f $tmp/in + if test x"$ac_file" != x-; then + if diff $ac_file $tmp/config.h >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + ac_dir=`(dirname "$ac_file") 2>/dev/null || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + rm -f $ac_file + mv $tmp/config.h $ac_file + fi + else + cat $tmp/config.h + rm -f $tmp/config.h + fi +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_LINKS section. +# + +for ac_file in : $CONFIG_LINKS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + + { echo "$as_me:$LINENO: linking $srcdir/$ac_source to $ac_dest" >&5 +echo "$as_me: linking $srcdir/$ac_source to $ac_dest" >&6;} + + if test ! -r $srcdir/$ac_source; then + { { echo "$as_me:$LINENO: error: $srcdir/$ac_source: file not found" >&5 +echo "$as_me: error: $srcdir/$ac_source: file not found" >&2;} + { (exit 1); exit 1; }; } + fi + rm -f $ac_dest + + # Make relative symlinks. + ac_dest_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dest_dir" + else + as_dir="$ac_dest_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dest_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dest_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dest_dir" != .; then + ac_dir_suffix=/`echo "$ac_dest_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dest_dir";; +*) + case "$ac_dest_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dest_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dest_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + case $srcdir in + [\\/$]* | ?:[\\/]* ) ac_rel_source=$srcdir/$ac_source ;; + *) ac_rel_source=$ac_top_builddir$srcdir/$ac_source ;; + esac + + # Try a symlink, then a hard link, then a copy. + ln -s $ac_rel_source $ac_dest 2>/dev/null || + ln $srcdir/$ac_source $ac_dest 2>/dev/null || + cp -p $srcdir/$ac_source $ac_dest || + { { echo "$as_me:$LINENO: error: cannot link or copy $srcdir/$ac_source to $ac_dest" >&5 +echo "$as_me: error: cannot link or copy $srcdir/$ac_source to $ac_dest" >&2;} + { (exit 1); exit 1; }; } +done +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF + +# +# CONFIG_COMMANDS section. +# +for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue + ac_dest=`echo "$ac_file" | sed 's,:.*,,'` + ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'` + ac_dir=`(dirname "$ac_dest") 2>/dev/null || +$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_dest" : 'X\(//\)[^/]' \| \ + X"$ac_dest" : 'X\(//\)$' \| \ + X"$ac_dest" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$ac_dest" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + { if $as_mkdir_p; then + mkdir -p "$ac_dir" + else + as_dir="$ac_dir" + as_dirs= + while test ! -d "$as_dir"; do + as_dirs="$as_dir $as_dirs" + as_dir=`(dirname "$as_dir") 2>/dev/null || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| \ + . : '\(.\)' 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; } + /^X\(\/\/\)[^/].*/{ s//\1/; q; } + /^X\(\/\/\)$/{ s//\1/; q; } + /^X\(\/\).*/{ s//\1/; q; } + s/.*/./; q'` + done + test ! -n "$as_dirs" || mkdir $as_dirs + fi || { { echo "$as_me:$LINENO: error: cannot create directory \"$ac_dir\"" >&5 +echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;} + { (exit 1); exit 1; }; }; } + + ac_builddir=. + +if test "$ac_dir" != .; then + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A "../" for each directory in $ac_dir_suffix. + ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'` +else + ac_dir_suffix= ac_top_builddir= +fi + +case $srcdir in + .) # No --srcdir option. We are building in place. + ac_srcdir=. + if test -z "$ac_top_builddir"; then + ac_top_srcdir=. + else + ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'` + fi ;; + [\\/]* | ?:[\\/]* ) # Absolute path. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir ;; + *) # Relative path. + ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_builddir$srcdir ;; +esac + +# Do not use `cd foo && pwd` to compute absolute paths, because +# the directories may not exist. +case `pwd` in +.) ac_abs_builddir="$ac_dir";; +*) + case "$ac_dir" in + .) ac_abs_builddir=`pwd`;; + [\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";; + *) ac_abs_builddir=`pwd`/"$ac_dir";; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_builddir=${ac_top_builddir}.;; +*) + case ${ac_top_builddir}. in + .) ac_abs_top_builddir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;; + *) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_srcdir=$ac_srcdir;; +*) + case $ac_srcdir in + .) ac_abs_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;; + *) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;; + esac;; +esac +case $ac_abs_builddir in +.) ac_abs_top_srcdir=$ac_top_srcdir;; +*) + case $ac_top_srcdir in + .) ac_abs_top_srcdir=$ac_abs_builddir;; + [\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;; + *) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;; + esac;; +esac + + + { echo "$as_me:$LINENO: executing $ac_dest commands" >&5 +echo "$as_me: executing $ac_dest commands" >&6;} + case $ac_dest in + include ) test -d include || mkdir include ;; + src ) +test -d src || mkdir src +test -d src/$TARGETDIR || mkdir src/$TARGETDIR + ;; + esac +done +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/configure.ac b/sys/src/cmd/python/Modules/_ctypes/libffi/configure.ac new file mode 100644 index 000000000..1308034ac --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/configure.ac @@ -0,0 +1,243 @@ +dnl Process this with autoconf to create configure + +AC_PREREQ(2.59) + +AC_INIT([libffi], [2.1], [http://gcc.gnu.org/bugs.html]) +AC_CONFIG_HEADERS([fficonfig.h]) + +AC_CANONICAL_SYSTEM +target_alias=${target_alias-$host_alias} + +m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) +m4_define([_AC_ARG_VAR_PRECIOUS],[]) +AC_PROG_CC +m4_rename([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) + +AC_SUBST(CFLAGS) + +AC_CHECK_HEADERS(sys/mman.h) +AC_CHECK_FUNCS(mmap) +AC_FUNC_MMAP_BLACKLIST + +TARGETDIR="unknown" +case "$host" in +x86_64-*-openbsd*) TARGET=X86_64; TARGETDIR=x86;; +mips*-*-openbsd*) TARGET=MIPS; TARGETDIR=mips;; +sparc-*-openbsd*) TARGET=SPARC; TARGETDIR=sparc;; +sparc64-*-openbsd*) TARGET=SPARC; TARGETDIR=sparc;; +alpha*-*-openbsd*) TARGET=ALPHA; TARGETDIR=alpha;; +m68k-*-openbsd*) TARGET=M68K; TARGETDIR=m68k;; +powerpc-*-openbsd*) TARGET=POWERPC; TARGETDIR=powerpc;; +i*86-*-darwin*) TARGET=X86_DARWIN; TARGETDIR=x86;; +i*86-*-linux*) TARGET=X86; TARGETDIR=x86;; +i*86-*-gnu*) TARGET=X86; TARGETDIR=x86;; +i*86-*-solaris2.1[[0-9]]*) TARGET=X86_64; TARGETDIR=x86;; +i*86-*-solaris*) TARGET=X86; TARGETDIR=x86;; +i*86-*-beos*) TARGET=X86; TARGETDIR=x86;; +i*86-*-freebsd* | i*86-*-kfreebsd*-gnu) TARGET=X86; TARGETDIR=x86;; +i*86-*-netbsdelf* | i*86-*-knetbsd*-gnu) TARGET=X86; TARGETDIR=x86;; +i*86-*-openbsd*) TARGET=X86; TARGETDIR=x86;; +i*86-*-rtems*) TARGET=X86; TARGETDIR=x86;; +i*86-*-win32*) TARGET=X86_WIN32; TARGETDIR=x86;; +i*86-*-cygwin*) TARGET=X86_WIN32; TARGETDIR=x86;; +i*86-*-mingw*) TARGET=X86_WIN32; TARGETDIR=x86;; +frv-*-*) TARGET=FRV; TARGETDIR=frv;; +sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;; +sparc*-sun-*) TARGET=SPARC; TARGETDIR=sparc;; +sparc-*-linux* | sparc-*-netbsdelf* | sparc-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;; +sparc*-*-rtems*) TARGET=SPARC; TARGETDIR=sparc;; +sparc64-*-linux* | sparc64-*-freebsd* | sparc64-*-netbsd* | sparc64-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;; +alpha*-*-linux* | alpha*-*-osf* | alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-netbsd* | alpha*-*-knetbsd*-gnu) TARGET=ALPHA; TARGETDIR=alpha;; +ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;; +m32r*-*-linux* ) TARGET=M32R; TARGETDIR=m32r;; +m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;; +mips64*-*);; +mips-sgi-irix5.* | mips-sgi-irix6.*) TARGET=MIPS_IRIX; TARGETDIR=mips;; +mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;; +powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;; +powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;; +powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;; +powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; +powerpc-*-freebsd*) TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc;; +powerpc*-*-rtems*) TARGET=POWERPC; TARGETDIR=powerpc;; +rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; +arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;; +arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu) TARGET=ARM; TARGETDIR=arm;; +arm*-*-rtems*) TARGET=ARM; TARGETDIR=arm;; +cris-*-*) TARGET=LIBFFI_CRIS; TARGETDIR=cris;; +s390-*-linux-*) TARGET=S390; TARGETDIR=s390;; +s390x-*-linux-*) TARGET=S390; TARGETDIR=s390;; +x86_64-*-linux* | x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) TARGET=X86_64; TARGETDIR=x86;; +sh-*-linux* | sh[[34]]*-*-linux*) TARGET=SH; TARGETDIR=sh;; +sh-*-rtems*) TARGET=SH; TARGETDIR=sh;; +sh64-*-linux* | sh5*-*-linux*) TARGET=SH64; TARGETDIR=sh64;; +hppa-*-linux* | parisc-*-linux*) TARGET=PA; TARGETDIR=pa;; +esac + +if test $TARGETDIR = unknown; then + AC_MSG_ERROR(["libffi has not been ported to $host."]) +fi + +dnl libffi changes TARGET for MIPS to define a such macro in the header +dnl while MIPS_IRIX or MIPS_LINUX is separatedly used to decide which +dnl files will be compiled. So, we need to keep the original decision +dnl of TARGET to use in fficonfig.py.in. +MKTARGET=$TARGET + +case x$TARGET in + xMIPS*) TARGET=MIPS ;; + *) ;; +esac + +AC_HEADER_STDC +AC_CHECK_FUNCS(memcpy) +AC_FUNC_ALLOCA + +AC_CHECK_SIZEOF(double) +AC_CHECK_SIZEOF(long double) + +# Also AC_SUBST this variable for ffi.h. +HAVE_LONG_DOUBLE=0 +if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then + if test $ac_cv_sizeof_long_double != 0; then + HAVE_LONG_DOUBLE=1 + AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double]) + fi +fi +AC_SUBST(HAVE_LONG_DOUBLE) + +AC_C_BIGENDIAN +AH_VERBATIM([WORDS_BIGENDIAN], +[ +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). + + The block below does compile-time checking for endianness on platforms + that use GCC and therefore allows compiling fat binaries on OSX by using + '-arch ppc -arch i386' as the compile flags. The phrasing was choosen + such that the configure-result is used on systems that don't use GCC. +*/ +#ifdef __BIG_ENDIAN__ +#define WORDS_BIGENDIAN 1 +#else +#ifndef __LITTLE_ENDIAN__ +#undef WORDS_BIGENDIAN +#endif +#endif]) + + +if test x$TARGET = xSPARC; then + AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs], + libffi_cv_as_sparc_ua_pcrel, [ + save_CFLAGS="$CFLAGS" + save_LDFLAGS="$LDFLAGS" + CFLAGS="$CFLAGS -fpic" + LDFLAGS="$LDFLAGS -shared" + AC_TRY_LINK([asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text");],, + [libffi_cv_as_sparc_ua_pcrel=yes], + [libffi_cv_as_sparc_ua_pcrel=no]) + CFLAGS="$save_CFLAGS" + LDFLAGS="$save_LDFLAGS"]) + if test "x$libffi_cv_as_sparc_ua_pcrel" = xyes; then + AC_DEFINE(HAVE_AS_SPARC_UA_PCREL, 1, + [Define if your assembler and linker support unaligned PC relative relocs.]) + fi + + AC_CACHE_CHECK([assembler .register pseudo-op support], + libffi_cv_as_register_pseudo_op, [ + libffi_cv_as_register_pseudo_op=unknown + # Check if we have .register + AC_TRY_COMPILE([asm (".register %g2, #scratch");],, + [libffi_cv_as_register_pseudo_op=yes], + [libffi_cv_as_register_pseudo_op=no]) + ]) + if test "x$libffi_cv_as_register_pseudo_op" = xyes; then + AC_DEFINE(HAVE_AS_REGISTER_PSEUDO_OP, 1, + [Define if your assembler supports .register.]) + fi +fi + +AC_CACHE_CHECK([whether .eh_frame section should be read-only], + libffi_cv_ro_eh_frame, [ + libffi_cv_ro_eh_frame=no + echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c + if $CC $CFLAGS -S -fpic -fexceptions -o conftest.s conftest.c > /dev/null 2>&1; then + if grep '.section.*eh_frame.*"a"' conftest.s > /dev/null; then + libffi_cv_ro_eh_frame=yes + elif grep '.section.*eh_frame.*#alloc' conftest.c \ + | grep -v '#write' > /dev/null; then + libffi_cv_ro_eh_frame=yes + fi + fi + rm -f conftest.* + ]) +if test "x$libffi_cv_ro_eh_frame" = xyes; then + AC_DEFINE(HAVE_RO_EH_FRAME, 1, + [Define if .eh_frame sections should be read-only.]) + AC_DEFINE(EH_FRAME_FLAGS, "a", + [Define to the flags needed for the .section .eh_frame directive.]) +else + AC_DEFINE(EH_FRAME_FLAGS, "aw", + [Define to the flags needed for the .section .eh_frame directive.]) +fi + +AC_CACHE_CHECK([for __attribute__((visibility("hidden")))], + libffi_cv_hidden_visibility_attribute, [ + echo 'int __attribute__ ((visibility ("hidden"))) foo (void) { return 1; }' > conftest.c + libffi_cv_hidden_visibility_attribute=no + if AC_TRY_COMMAND(${CC-cc} -Werror -S conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then + if grep '\.hidden.*foo' conftest.s >/dev/null; then + libffi_cv_hidden_visibility_attribute=yes + fi + fi + rm -f conftest.* + ]) +if test $libffi_cv_hidden_visibility_attribute = yes; then + AC_DEFINE(HAVE_HIDDEN_VISIBILITY_ATTRIBUTE, 1, + [Define if __attribute__((visibility("hidden"))) is supported.]) +fi + +AH_BOTTOM([ +#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) .hidden name +#else +#define FFI_HIDDEN __attribute__ ((visibility ("hidden"))) +#endif +#else +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) +#else +#define FFI_HIDDEN +#endif +#endif +]) + +AC_SUBST(TARGET) +AC_SUBST(TARGETDIR) +AC_SUBST(MKTARGET) + +AC_SUBST(SHELL) + +AC_DEFINE(FFI_NO_RAW_API, 1, [Define this is you do not want support for the raw API.]) + +AC_CONFIG_COMMANDS(include, [test -d include || mkdir include]) +AC_CONFIG_COMMANDS(src, [ +test -d src || mkdir src +test -d src/$TARGETDIR || mkdir src/$TARGETDIR +], [TARGETDIR="$TARGETDIR"]) + +TARGETINCDIR=$TARGETDIR +case $host in +*-*-darwin*) + TARGETINCDIR="darwin" + ;; +esac + + +AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETINCDIR/ffitarget.h) +AC_CONFIG_LINKS(include/ffi_common.h:include/ffi_common.h) + +AC_CONFIG_FILES(include/ffi.h fficonfig.py) + +AC_OUTPUT diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.h.in b/sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.h.in new file mode 100644 index 000000000..bcc5a58d4 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.h.in @@ -0,0 +1,148 @@ +/* fficonfig.h.in. Generated from configure.ac by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to the flags needed for the .section .eh_frame directive. */ +#undef EH_FRAME_FLAGS + +/* Define this is you do not want support for the raw API. */ +#undef FFI_NO_RAW_API + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define if your assembler supports .register. */ +#undef HAVE_AS_REGISTER_PSEUDO_OP + +/* Define if your assembler and linker support unaligned PC relative relocs. + */ +#undef HAVE_AS_SPARC_UA_PCREL + +/* Define if __attribute__((visibility("hidden"))) is supported. */ +#undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define if you have the long double type and it is bigger than a double */ +#undef HAVE_LONG_DOUBLE + +/* Define to 1 if you have the `memcpy' function. */ +#undef HAVE_MEMCPY + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +#undef HAVE_MMAP_ANON + +/* Define if mmap of /dev/zero works. */ +#undef HAVE_MMAP_DEV_ZERO + +/* Define if read-only mmap of a plain file works. */ +#undef HAVE_MMAP_FILE + +/* Define if .eh_frame sections should be read-only. */ +#undef HAVE_RO_EH_FRAME + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sys/mman.h> header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* The size of a `double', as computed by sizeof. */ +#undef SIZEOF_DOUBLE + +/* The size of a `long double', as computed by sizeof. */ +#undef SIZEOF_LONG_DOUBLE + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). + + The block below does compile-time checking for endianness on platforms + that use GCC and therefore allows compiling fat binaries on OSX by using + '-arch ppc -arch i386' as the compile flags. The phrasing was choosen + such that the configure-result is used on systems that don't use GCC. +*/ +#ifdef __BIG_ENDIAN__ +#define WORDS_BIGENDIAN 1 +#else +#ifndef __LITTLE_ENDIAN__ +#undef WORDS_BIGENDIAN +#endif +#endif + + +#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) .hidden name +#else +#define FFI_HIDDEN __attribute__ ((visibility ("hidden"))) +#endif +#else +#ifdef LIBFFI_ASM +#define FFI_HIDDEN(name) +#else +#define FFI_HIDDEN +#endif +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.py.in b/sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.py.in new file mode 100644 index 000000000..7a9821691 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/fficonfig.py.in @@ -0,0 +1,45 @@ +ffi_sources = """ +src/prep_cif.c +""".split() + +ffi_platforms = { + 'MIPS_IRIX': ['src/mips/ffi.c', 'src/mips/o32.S', 'src/mips/n32.S'], + 'MIPS_LINUX': ['src/mips/ffi.c', 'src/mips/o32.S'], + 'X86': ['src/x86/ffi.c', 'src/x86/sysv.S'], + 'X86_DARWIN': ['src/x86/ffi_darwin.c', 'src/x86/darwin.S'], + 'X86_WIN32': ['src/x86/ffi.c', 'src/x86/win32.S'], + 'SPARC': ['src/sparc/ffi.c', 'src/sparc/v8.S', 'src/sparc/v9.S'], + 'ALPHA': ['src/alpha/ffi.c', 'src/alpha/osf.S'], + 'IA64': ['src/ia64/ffi.c', 'src/ia64/unix.S'], + 'M32R': ['src/m32r/sysv.S', 'src/m32r/ffi.c'], + 'M68K': ['src/m68k/ffi.c', 'src/m68k/sysv.S'], + 'POWERPC': ['src/powerpc/ffi.c', 'src/powerpc/sysv.S', 'src/powerpc/ppc_closure.S', 'src/powerpc/linux64.S', 'src/powerpc/linux64_closure.S'], + 'POWERPC_AIX': ['src/powerpc/ffi_darwin.c', 'src/powerpc/aix.S', 'src/powerpc/aix_closure.S'], + 'POWERPC_DARWIN': ['src/powerpc/ffi_darwin.c', 'src/powerpc/darwin.S', 'src/powerpc/darwin_closure.S'], + 'POWERPC_FREEBSD': ['src/powerpc/ffi.c', 'src/powerpc/sysv.S', 'src/powerpc/ppc_closure.S'], + 'ARM': ['src/arm/sysv.S', 'src/arm/ffi.c'], + 'LIBFFI_CRIS': ['src/cris/sysv.S', 'src/cris/ffi.c'], + 'FRV': ['src/frv/eabi.S', 'src/frv/ffi.c'], + 'S390': ['src/s390/sysv.S', 'src/s390/ffi.c'], + 'X86_64': ['src/x86/ffi64.c', 'src/x86/unix64.S', 'src/x86/ffi.c', 'src/x86/sysv.S'], + 'SH': ['src/sh/sysv.S', 'src/sh/ffi.c'], + 'SH64': ['src/sh64/sysv.S', 'src/sh64/ffi.c'], + 'PA': ['src/pa/linux.S', 'src/pa/ffi.c'], +} + +# Build all darwin related files on all supported darwin architectures, this +# makes it easier to build universal binaries. +if 1: + all_darwin = ('X86_DARWIN', 'POWERPC_DARWIN') + all_darwin_files = [] + for pn in all_darwin: + all_darwin_files.extend(ffi_platforms[pn]) + for pn in all_darwin: + ffi_platforms[pn] = all_darwin_files + del all_darwin, all_darwin_files, pn + +ffi_srcdir = '@srcdir@' +ffi_sources += ffi_platforms['@MKTARGET@'] +ffi_sources = [os.path.join('@srcdir@', f) for f in ffi_sources] + +ffi_cflags = '@CFLAGS@' diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi.h.in b/sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi.h.in new file mode 100644 index 000000000..5ddda7901 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi.h.in @@ -0,0 +1,313 @@ +/* -----------------------------------------------------------------*-C-*- + libffi @VERSION@ - Copyright (c) 1996-2003 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------- + The basic API is described in the README file. + + The raw API is designed to bypass some of the argument packing + and unpacking on architectures for which it can be avoided. + + The closure API allows interpreted functions to be packaged up + inside a C function pointer, so that they can be called as C functions, + with no understanding on the client side that they are interpreted. + It can also be used in other cases in which it is necessary to package + up a user specified parameter and a function pointer as a single + function pointer. + + The closure API must be implemented in order to get its functionality, + e.g. for use by gij. Routines are provided to emulate the raw API + if the underlying platform doesn't allow faster implementation. + + More details on the raw and cloure API can be found in: + + http://gcc.gnu.org/ml/java/1999-q3/msg00138.html + + and + + http://gcc.gnu.org/ml/java/1999-q3/msg00174.html + -------------------------------------------------------------------- */ + +#ifndef LIBFFI_H +#define LIBFFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Specify which architecture libffi is configured for. */ +#define @TARGET@ + +/* ---- System configuration information --------------------------------- */ + +#include <ffitarget.h> + +#ifndef LIBFFI_ASM + +#include <stddef.h> +#include <limits.h> + +/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). + But we can find it either under the correct ANSI name, or under GNU + C's internal name. */ +#ifdef LONG_LONG_MAX +# define FFI_LONG_LONG_MAX LONG_LONG_MAX +#else +# ifdef LLONG_MAX +# define FFI_LONG_LONG_MAX LLONG_MAX +# else +# ifdef __GNUC__ +# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ +# endif +# endif +#endif + +#if SCHAR_MAX == 127 +# define ffi_type_uchar ffi_type_uint8 +# define ffi_type_schar ffi_type_sint8 +#else + #error "char size not supported" +#endif + +#if SHRT_MAX == 32767 +# define ffi_type_ushort ffi_type_uint16 +# define ffi_type_sshort ffi_type_sint16 +#elif SHRT_MAX == 2147483647 +# define ffi_type_ushort ffi_type_uint32 +# define ffi_type_sshort ffi_type_sint32 +#else + #error "short size not supported" +#endif + +#if INT_MAX == 32767 +# define ffi_type_uint ffi_type_uint16 +# define ffi_type_sint ffi_type_sint16 +#elif INT_MAX == 2147483647 +# define ffi_type_uint ffi_type_uint32 +# define ffi_type_sint ffi_type_sint32 +#elif INT_MAX == 9223372036854775807 +# define ffi_type_uint ffi_type_uint64 +# define ffi_type_sint ffi_type_sint64 +#else + #error "int size not supported" +#endif + +#define ffi_type_ulong ffi_type_uint64 +#define ffi_type_slong ffi_type_sint64 +#if LONG_MAX == 2147483647 +# if FFI_LONG_LONG_MAX != 9223372036854775807 + #error "no 64-bit data type supported" +# endif +#elif LONG_MAX != 9223372036854775807 + #error "long size not supported" +#endif + +/* The closure code assumes that this works on pointers, i.e. a size_t */ +/* can hold a pointer. */ + +typedef struct _ffi_type +{ + size_t size; + unsigned short alignment; + unsigned short type; + /*@null@*/ struct _ffi_type **elements; +} ffi_type; + +/* These are defined in types.c */ +extern ffi_type ffi_type_void; +extern ffi_type ffi_type_uint8; +extern ffi_type ffi_type_sint8; +extern ffi_type ffi_type_uint16; +extern ffi_type ffi_type_sint16; +extern ffi_type ffi_type_uint32; +extern ffi_type ffi_type_sint32; +extern ffi_type ffi_type_uint64; +extern ffi_type ffi_type_sint64; +extern ffi_type ffi_type_float; +extern ffi_type ffi_type_double; +extern ffi_type ffi_type_longdouble; +extern ffi_type ffi_type_pointer; + + +typedef enum { + FFI_OK = 0, + FFI_BAD_TYPEDEF, + FFI_BAD_ABI +} ffi_status; + +typedef unsigned FFI_TYPE; + +typedef struct { + ffi_abi abi; + unsigned nargs; + /*@dependent@*/ ffi_type **arg_types; + /*@dependent@*/ ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; + +/* ---- Definitions for the raw API -------------------------------------- */ + +#ifndef FFI_SIZEOF_ARG +# if LONG_MAX == 2147483647 +# define FFI_SIZEOF_ARG 4 +# elif LONG_MAX == 9223372036854775807 +# define FFI_SIZEOF_ARG 8 +# endif +#endif + +typedef union { + ffi_sarg sint; + ffi_arg uint; + float flt; + char data[FFI_SIZEOF_ARG]; + void* ptr; +} ffi_raw; + +void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(void), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_raw_size (ffi_cif *cif); + +/* This is analogous to the raw API, except it uses Java parameter */ +/* packing, even on 64-bit machines. I.e. on 64-bit machines */ +/* longs and doubles are followed by an empty 64-bit word. */ + +void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(void), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_java_raw_size (ffi_cif *cif); + +/* ---- Definitions for closures ----------------------------------------- */ + +#if FFI_CLOSURES + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + ffi_cif *cif; + void (*fun)(ffi_cif*,void*,void**,void*); + void *user_data; +} ffi_closure __attribute__((aligned (8))); + +ffi_status +ffi_prep_closure (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data); + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + + ffi_cif *cif; + +#if !FFI_NATIVE_RAW_API + + /* if this is enabled, then a raw closure has the same layout + as a regular closure. We use this to install an intermediate + handler to do the transaltion, void** -> ffi_raw*. */ + + void (*translate_args)(ffi_cif*,void*,void**,void*); + void *this_closure; + +#endif + + void (*fun)(ffi_cif*,void*,ffi_raw*,void*); + void *user_data; + +} ffi_raw_closure; + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +ffi_status +ffi_prep_java_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +#endif /* FFI_CLOSURES */ + +/* ---- Public interface definition -------------------------------------- */ + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes); + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(void), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue); + +/* Useful for eliminating compiler warnings */ +#define FFI_FN(f) ((void (*)())f) + +/* ---- Definitions shared with assembly code ---------------------------- */ + +#endif + +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 +#if @HAVE_LONG_DOUBLE@ +#define FFI_TYPE_LONGDOUBLE 4 +#else +#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 + +/* This should always refer to the last type code (for sanity checks) */ +#define FFI_TYPE_LAST FFI_TYPE_POINTER + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi_common.h b/sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi_common.h new file mode 100644 index 000000000..da15ab8ec --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/include/ffi_common.h @@ -0,0 +1,95 @@ +/* ----------------------------------------------------------------------- + ffi_common.h - Copyright (c) 1996 Red Hat, Inc. + + Common internal definitions and macros. Only necessary for building + libffi. + ----------------------------------------------------------------------- */ + +#ifndef FFI_COMMON_H +#define FFI_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <fficonfig.h> + +/* Do not move this. Some versions of AIX are very picky about where + this is positioned. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +#endif + +/* Check for the existence of memcpy. */ +#if STDC_HEADERS +# include <string.h> +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#if defined(FFI_DEBUG) +#include <stdio.h> +#endif + +#ifdef FFI_DEBUG +/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); +void ffi_stop_here(void); +void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); + +#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) +#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) +#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) +#else +#define FFI_ASSERT(x) +#define FFI_ASSERT_AT(x, f, l) +#define FFI_ASSERT_VALID_TYPE(x) +#endif + +#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) +#define ALIGN_DOWN(v, a) (((size_t) (v)) & -a) + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif); + +/* Extended cif, used in callback from assembly routine */ +typedef struct +{ + /*@dependent@*/ ffi_cif *cif; + /*@dependent@*/ void *rvalue; + /*@dependent@*/ void **avalue; +} extended_cif; + +/* Terse sized type definitions. */ +typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); +typedef signed int SINT8 __attribute__((__mode__(__QI__))); +typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); +typedef signed int SINT16 __attribute__((__mode__(__HI__))); +typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); +typedef signed int SINT32 __attribute__((__mode__(__SI__))); +typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); +typedef signed int SINT64 __attribute__((__mode__(__DI__))); + +typedef float FLOAT32; + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/install-sh b/sys/src/cmd/python/Modules/_ctypes/libffi/install-sh new file mode 100755 index 000000000..0ec27bcd4 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/install-sh @@ -0,0 +1,294 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd=$cpprog + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "$0: no input file specified" >&2 + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d "$dst" ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$src" ] || [ -d "$src" ] + then + : + else + echo "$0: $src does not exist" >&2 + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "$0: no destination specified" >&2 + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d "$dst" ] + then + dst=$dst/`basename "$src"` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-$defaultIFS}" + +oIFS=$IFS +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS=$oIFS + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp=$pathcomp$1 + shift + + if [ ! -d "$pathcomp" ] ; + then + $mkdirprog "$pathcomp" + else + : + fi + + pathcomp=$pathcomp/ +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd "$dst" && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename "$dst"` + else + dstfile=`basename "$dst" $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename "$dst"` + else + : + fi + +# Make a couple of temp file names in the proper directory. + + dsttmp=$dstdir/#inst.$$# + rmtmp=$dstdir/#rm.$$# + +# Trap to clean up temp files at exit. + + trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 + trap '(exit $?); exit' 1 2 13 15 + +# Move or copy the file name to the temp name + + $doit $instcmd "$src" "$dsttmp" && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && + +# Now remove or move aside any old file at destination location. We try this +# two ways since rm can't unlink itself on some systems and the destination +# file might be busy for other reasons. In this case, the final cleanup +# might fail but the new file should still install successfully. + +{ + if [ -f "$dstdir/$dstfile" ] + then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || + $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || + { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit + } + else + : + fi +} && + +# Now rename the file to the real destination. + + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + +fi && + +# The final little trick to "correctly" pass the exit status to the exit trap. + +{ + (exit 0); exit +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffi.c new file mode 100644 index 000000000..00d337901 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffi.c @@ -0,0 +1,252 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998, 2001 Red Hat, Inc. + + Alpha Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)()); +extern void ffi_closure_osf(void); + + +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Adjust cif->bytes to represent a minimum 6 words for the temporary + register argument loading area. */ + if (cif->bytes < 6*FFI_SIZEOF_ARG) + cif->bytes = 6*FFI_SIZEOF_ARG; + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = cif->rtype->type; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +void +ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) +{ + unsigned long *stack, *argp; + long i, avn; + ffi_type **arg_types; + + FFI_ASSERT (cif->abi == FFI_OSF); + + /* If the return value is a struct and we don't have a return + value address then we need to make one. */ + if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT) + rvalue = alloca(cif->rtype->size); + + /* Allocate the space for the arguments, plus 4 words of temp + space for ffi_call_osf. */ + argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); + + if (cif->flags == FFI_TYPE_STRUCT) + *(void **) argp++ = rvalue; + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + while (i < avn) + { + switch ((*arg_types)->type) + { + case FFI_TYPE_SINT8: + *(SINT64 *) argp = *(SINT8 *)(* avalue); + break; + + case FFI_TYPE_UINT8: + *(SINT64 *) argp = *(UINT8 *)(* avalue); + break; + + case FFI_TYPE_SINT16: + *(SINT64 *) argp = *(SINT16 *)(* avalue); + break; + + case FFI_TYPE_UINT16: + *(SINT64 *) argp = *(UINT16 *)(* avalue); + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + /* Note that unsigned 32-bit quantities are sign extended. */ + *(SINT64 *) argp = *(SINT32 *)(* avalue); + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + *(UINT64 *) argp = *(UINT64 *)(* avalue); + break; + + case FFI_TYPE_FLOAT: + if (argp - stack < 6) + { + /* Note the conversion -- all the fp regs are loaded as + doubles. The in-register format is the same. */ + *(double *) argp = *(float *)(* avalue); + } + else + *(float *) argp = *(float *)(* avalue); + break; + + case FFI_TYPE_DOUBLE: + *(double *) argp = *(double *)(* avalue); + break; + + case FFI_TYPE_STRUCT: + memcpy(argp, *avalue, (*arg_types)->size); + break; + + default: + FFI_ASSERT(0); + } + + argp += ALIGN((*arg_types)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + i++, arg_types++, avalue++; + } + + ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn); +} + + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp; + + FFI_ASSERT (cif->abi == FFI_OSF); + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x47fb0401; /* mov $27,$1 */ + tramp[1] = 0xa77b0010; /* ldq $27,16($27) */ + tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */ + tramp[3] = 0x47ff041f; /* nop */ + *(void **) &tramp[4] = ffi_closure_osf; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the Icache. + + Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal + instead, since both Compaq as and gas can handle it. + + 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */ + asm volatile ("call_pal 0x86" : : : "memory"); + + return FFI_OK; +} + +int +ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + long i, avn, argn; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + argn = 0; + + /* Copy the caller's structure return address to that the closure + returns the data directly to the caller. */ + if (cif->flags == FFI_TYPE_STRUCT) + { + rvalue = (void *) argp[0]; + argn = 1; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + case FFI_TYPE_STRUCT: + avalue[i] = &argp[argn]; + break; + + case FFI_TYPE_FLOAT: + if (argn < 6) + { + /* Floats coming from registers need conversion from double + back to float format. */ + *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6]; + avalue[i] = &argp[argn - 6]; + } + else + avalue[i] = &argp[argn]; + break; + + case FFI_TYPE_DOUBLE: + avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)]; + break; + + default: + FFI_ASSERT(0); + } + + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_osf how to perform return type promotions. */ + return cif->rtype->type; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffitarget.h new file mode 100644 index 000000000..00a121718 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/ffitarget.h @@ -0,0 +1,48 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for Alpha. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_OSF, + FFI_DEFAULT_ABI = FFI_OSF, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/osf.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/osf.S new file mode 100644 index 000000000..95b30fae8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/alpha/osf.S @@ -0,0 +1,359 @@ +/* ----------------------------------------------------------------------- + osf.S - Copyright (c) 1998, 2001 Red Hat + + Alpha/OSF Foreign Function Interface + + $Id: osf.S,v 1.2 2006/03/03 20:24:26 theller Exp $ + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .arch ev6 + .text + +/* ffi_call_osf (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)()); + + Bit o trickiness here -- ARGS+BYTES is the base of the stack frame + for this function. This has been allocated by ffi_call. We also + deallocate some of the stack that has been alloca'd. */ + + .align 3 + .globl ffi_call_osf + .ent ffi_call_osf +ffi_call_osf: + .frame $15, 32, $26, 0 + .mask 0x4008000, -32 +$LFB1: + addq $16,$17,$1 + mov $16, $30 + stq $26, 0($1) + stq $15, 8($1) + stq $18, 16($1) + mov $1, $15 +$LCFI1: + .prologue 0 + + stq $19, 24($1) + mov $20, $27 + + # Load up all of the (potential) argument registers. + ldq $16, 0($30) + ldt $f16, 0($30) + ldt $f17, 8($30) + ldq $17, 8($30) + ldt $f18, 16($30) + ldq $18, 16($30) + ldt $f19, 24($30) + ldq $19, 24($30) + ldt $f20, 32($30) + ldq $20, 32($30) + ldt $f21, 40($30) + ldq $21, 40($30) + + # Deallocate the register argument area. + lda $30, 48($30) + + jsr $26, ($27), 0 + ldgp $29, 0($26) + + # If the return value pointer is NULL, assume no return value. + ldq $19, 24($15) + ldq $18, 16($15) + ldq $26, 0($15) +$LCFI2: + beq $19, $noretval + + # Store the return value out in the proper type. + cmpeq $18, FFI_TYPE_INT, $1 + bne $1, $retint + cmpeq $18, FFI_TYPE_FLOAT, $2 + bne $2, $retfloat + cmpeq $18, FFI_TYPE_DOUBLE, $3 + bne $3, $retdouble + + .align 3 +$noretval: + ldq $15, 8($15) + ret + + .align 4 +$retint: + stq $0, 0($19) + nop + ldq $15, 8($15) + ret + + .align 4 +$retfloat: + sts $f0, 0($19) + nop + ldq $15, 8($15) + ret + + .align 4 +$retdouble: + stt $f0, 0($19) + nop + ldq $15, 8($15) + ret +$LFE1: + + .end ffi_call_osf + +/* ffi_closure_osf(...) + + Receives the closure argument in $1. */ + + .align 3 + .globl ffi_closure_osf + .ent ffi_closure_osf +ffi_closure_osf: + .frame $30, 16*8, $26, 0 + .mask 0x4000000, -16*8 +$LFB2: + ldgp $29, 0($27) + subq $30, 16*8, $30 +$LCFI5: + stq $26, 0($30) +$LCFI6: + .prologue 1 + + # Store all of the potential argument registers in va_list format. + stt $f16, 4*8($30) + stt $f17, 5*8($30) + stt $f18, 6*8($30) + stt $f19, 7*8($30) + stt $f20, 8*8($30) + stt $f21, 9*8($30) + stq $16, 10*8($30) + stq $17, 11*8($30) + stq $18, 12*8($30) + stq $19, 13*8($30) + stq $20, 14*8($30) + stq $21, 15*8($30) + + # Call ffi_closure_osf_inner to do the bulk of the work. + mov $1, $16 + lda $17, 2*8($30) + lda $18, 10*8($30) + jsr $26, ffi_closure_osf_inner + ldgp $29, 0($26) + ldq $26, 0($30) + + # Load up the return value in the proper type. + lda $1, $load_table + s4addq $0, $1, $1 + ldl $1, 0($1) + addq $1, $29, $1 + jmp $31, ($1), $load_32 + + .align 4 +$load_none: + addq $30, 16*8, $30 + ret + + .align 4 +$load_float: + lds $f0, 16($30) + nop + addq $30, 16*8, $30 + ret + + .align 4 +$load_double: + ldt $f0, 16($30) + nop + addq $30, 16*8, $30 + ret + + .align 4 +$load_u8: +#ifdef __alpha_bwx__ + ldbu $0, 16($30) + nop +#else + ldq $0, 16($30) + and $0, 255, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_s8: +#ifdef __alpha_bwx__ + ldbu $0, 16($30) + sextb $0, $0 +#else + ldq $0, 16($30) + sll $0, 56, $0 + sra $0, 56, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_u16: +#ifdef __alpha_bwx__ + ldwu $0, 16($30) + nop +#else + ldq $0, 16($30) + zapnot $0, 3, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_s16: +#ifdef __alpha_bwx__ + ldwu $0, 16($30) + sextw $0, $0 +#else + ldq $0, 16($30) + sll $0, 48, $0 + sra $0, 48, $0 +#endif + addq $30, 16*8, $30 + ret + + .align 4 +$load_32: + ldl $0, 16($30) + nop + addq $30, 16*8, $30 + ret + + .align 4 +$load_64: + ldq $0, 16($30) + nop + addq $30, 16*8, $30 + ret +$LFE2: + + .end ffi_closure_osf + +#ifdef __ELF__ +.section .rodata +#else +.rdata +#endif +$load_table: + .gprel32 $load_none # FFI_TYPE_VOID + .gprel32 $load_32 # FFI_TYPE_INT + .gprel32 $load_float # FFI_TYPE_FLOAT + .gprel32 $load_double # FFI_TYPE_DOUBLE + .gprel32 $load_double # FFI_TYPE_LONGDOUBLE + .gprel32 $load_u8 # FFI_TYPE_UINT8 + .gprel32 $load_s8 # FFI_TYPE_SINT8 + .gprel32 $load_u16 # FFI_TYPE_UINT16 + .gprel32 $load_s16 # FFI_TYPE_SINT16 + .gprel32 $load_32 # FFI_TYPE_UINT32 + .gprel32 $load_32 # FFI_TYPE_SINT32 + .gprel32 $load_64 # FFI_TYPE_UINT64 + .gprel32 $load_64 # FFI_TYPE_SINT64 + .gprel32 $load_none # FFI_TYPE_STRUCT + .gprel32 $load_64 # FFI_TYPE_POINTER + +/* Assert that the table above is in sync with ffi.h. */ + +#if FFI_TYPE_FLOAT != 2 \ + || FFI_TYPE_DOUBLE != 3 \ + || FFI_TYPE_UINT8 != 5 \ + || FFI_TYPE_SINT8 != 6 \ + || FFI_TYPE_UINT16 != 7 \ + || FFI_TYPE_SINT16 != 8 \ + || FFI_TYPE_UINT32 != 9 \ + || FFI_TYPE_SINT32 != 10 \ + || FFI_TYPE_UINT64 != 11 \ + || FFI_TYPE_SINT64 != 12 \ + || FFI_TYPE_STRUCT != 13 \ + || FFI_TYPE_POINTER != 14 \ + || FFI_TYPE_LAST != 14 +#error "osf.S out of sync with ffi.h" +#endif + +#ifdef __ELF__ + .section .eh_frame,EH_FRAME_FLAGS,@progbits +__FRAME_BEGIN__: + .4byte $LECIE1-$LSCIE1 # Length of Common Information Entry +$LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor + .byte 0x78 # sleb128 -8; CIE Data Alignment Factor + .byte 26 # CIE RA Column + .byte 0x1 # uleb128 0x1; Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) + .byte 0xc # DW_CFA_def_cfa + .byte 30 # uleb128 column 30 + .byte 0 # uleb128 offset 0 + .align 3 +$LECIE1: +$LSFDE1: + .4byte $LEFDE1-$LASFDE1 # FDE Length +$LASFDE1: + .4byte $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset + .4byte $LFB1-. # FDE initial location + .4byte $LFE1-$LFB1 # FDE address range + .byte 0x0 # uleb128 0x0; Augmentation size + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI1-$LFB1 + .byte 0x9a # DW_CFA_offset, column 26 + .byte 4 # uleb128 4*-8 + .byte 0x8f # DW_CFA_offset, column 15 + .byte 0x3 # uleb128 3*-8 + .byte 0xc # DW_CFA_def_cfa + .byte 15 # uleb128 column 15 + .byte 32 # uleb128 offset 32 + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI2-$LCFI1 + .byte 0xda # DW_CFA_restore, column 26 + .align 3 +$LEFDE1: + +$LSFDE3: + .4byte $LEFDE3-$LASFDE3 # FDE Length +$LASFDE3: + .4byte $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset + .4byte $LFB2-. # FDE initial location + .4byte $LFE2-$LFB2 # FDE address range + .byte 0x0 # uleb128 0x0; Augmentation size + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI5-$LFB2 + .byte 0xe # DW_CFA_def_cfa_offset + .byte 0x80,0x1 # uleb128 128 + + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI6-$LCFI5 + .byte 0x9a # DW_CFA_offset, column 26 + .byte 16 # uleb128 offset 16*-8 + .align 3 +$LEFDE3: +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffi.c new file mode 100644 index 000000000..1f58d93ef --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffi.c @@ -0,0 +1,185 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Red Hat, Inc. + + ARM Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, (*p_arg)->alignment); + } + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Round the stack up to a multiple of 8 bytes. This isn't needed + everywhere, but it is on some platforms, and it doesn't harm anything + when it isn't needed. */ + cif->bytes = (cif->bytes + 7) & ~7; + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned) FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + default: + FFI_ASSERT(0); + break; + } +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffitarget.h new file mode 100644 index 000000000..96f4bb2f2 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/ffitarget.h @@ -0,0 +1,47 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for ARM. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 0 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/sysv.S new file mode 100644 index 000000000..c3471a8a2 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/arm/sysv.S @@ -0,0 +1,209 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1998 Red Hat, Inc. + + ARM Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +#ifdef __USER_LABEL_PREFIX__ +#define CONCAT1(a, b) CONCAT2(a, b) +#define CONCAT2(a, b) a ## b + +/* Use the right prefix for global labels. */ +#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) +#else +#define CNAME(x) x +#endif +#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): +#endif + +#ifdef __ELF__ +#define LSYM(x) .x +#else +#define LSYM(x) x +#endif + +/* We need a better way of testing for this, but for now, this is all + we can do. */ +@ This selects the minimum architecture level required. +#define __ARM_ARCH__ 3 + +#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 4 +#endif + +#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 5 +#endif + +#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) +# undef __ARM_ARCH__ +# define __ARM_ARCH__ 6 +#endif + +#if __ARM_ARCH__ >= 5 +# define call_reg(x) blx x +#elif defined (__ARM_ARCH_4T__) +# define call_reg(x) mov lr, pc ; bx x +# if defined(__thumb__) || defined(__THUMB_INTERWORK__) +# define __INTERWORKING__ +# endif +#else +# define call_reg(x) mov lr, pc ; mov pc, x +#endif + +#if defined(__thumb__) && !defined(__THUMB_INTERWORK__) +.macro ARM_FUNC_START name + .text + .align 0 + .thumb + .thumb_func + ENTRY(\name) + bx pc + nop + .arm +/* A hook to tell gdb that we've switched to ARM mode. Also used to call + directly from other local arm routines. */ +_L__\name: +.endm +#else +.macro ARM_FUNC_START name + .text + .align 0 + .arm + ENTRY(\name) +.endm +#endif + +.macro RETLDM regs=, cond=, dirn=ia +#if defined (__INTERWORKING__) + .ifc "\regs","" + ldr\cond lr, [sp], #4 + .else + ldm\cond\dirn sp!, {\regs, lr} + .endif + bx\cond lr +#else + .ifc "\regs","" + ldr\cond pc, [sp], #4 + .else + ldm\cond\dirn sp!, {\regs, pc} + .endif +#endif +.endm + + + @ r0: ffi_prep_args + @ r1: &ecif + @ r2: cif->bytes + @ r3: fig->flags + @ sp+0: ecif.rvalue + @ sp+4: fn + + @ This assumes we are using gas. +ARM_FUNC_START ffi_call_SYSV + @ Save registers + stmfd sp!, {r0-r3, fp, lr} + mov fp, sp + + @ Make room for all of the new args. + sub sp, fp, r2 + + @ Place all of the ffi_prep_args in position + mov ip, r0 + mov r0, sp + @ r1 already set + + @ Call ffi_prep_args(stack, &ecif) + call_reg(ip) + + @ move first 4 parameters in registers + ldmia sp, {r0-r3} + + @ and adjust stack + ldr ip, [fp, #8] + cmp ip, #16 + movhs ip, #16 + add sp, sp, ip + + @ call (fn) (...) + ldr ip, [fp, #28] + call_reg(ip) + + @ Remove the space we pushed for the args + mov sp, fp + + @ Load r2 with the pointer to storage for the return value + ldr r2, [sp, #24] + + @ Load r3 with the return type code + ldr r3, [sp, #12] + + @ If the return value pointer is NULL, assume no return value. + cmp r2, #0 + beq LSYM(Lepilogue) + +@ return INT + cmp r3, #FFI_TYPE_INT +#ifdef __SOFTFP__ + cmpne r3, #FFI_TYPE_FLOAT +#endif + streq r0, [r2] + beq LSYM(Lepilogue) + + @ return INT64 + cmp r3, #FFI_TYPE_SINT64 +#ifdef __SOFTFP__ + cmpne r3, #FFI_TYPE_DOUBLE +#endif + stmeqia r2, {r0, r1} + +#ifndef __SOFTFP__ + beq LSYM(Lepilogue) + +@ return FLOAT + cmp r3, #FFI_TYPE_FLOAT + stfeqs f0, [r2] + beq LSYM(Lepilogue) + +@ return DOUBLE or LONGDOUBLE + cmp r3, #FFI_TYPE_DOUBLE + stfeqd f0, [r2] +#endif + +LSYM(Lepilogue): + RETLDM "r0-r3,fp" + +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffi.c new file mode 100644 index 000000000..364c990f6 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffi.c @@ -0,0 +1,381 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Cygnus Solutions + Copyright (c) 2004 Simon Posnjak + Copyright (c) 2005 Axis Communications AB + + CRIS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) + +static ffi_status +initialize_aggregate_packed_struct (ffi_type * arg) +{ + ffi_type **ptr; + + FFI_ASSERT (arg != NULL); + + FFI_ASSERT (arg->elements != NULL); + FFI_ASSERT (arg->size == 0); + FFI_ASSERT (arg->alignment == 0); + + ptr = &(arg->elements[0]); + + while ((*ptr) != NULL) + { + if (((*ptr)->size == 0) + && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + FFI_ASSERT (ffi_type_test ((*ptr))); + + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; + + ptr++; + } + + if (arg->size == 0) + return FFI_BAD_TYPEDEF; + else + return FFI_OK; +} + +int +ffi_prep_args (char *stack, extended_cif * ecif) +{ + unsigned int i; + unsigned int struct_count = 0; + void **p_argv; + char *argp; + ffi_type **p_arg; + + argp = stack; + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); i--, p_arg++) + { + size_t z; + + switch ((*p_arg)->type) + { + case FFI_TYPE_STRUCT: + { + z = (*p_arg)->size; + if (z <= 4) + { + memcpy (argp, *p_argv, z); + z = 4; + } + else if (z <= 8) + { + memcpy (argp, *p_argv, z); + z = 8; + } + else + { + unsigned int uiLocOnStack; + z = sizeof (void *); + uiLocOnStack = 4 * ecif->cif->nargs + struct_count; + struct_count = struct_count + (*p_arg)->size; + *(unsigned int *) argp = + (unsigned int) (UINT32 *) (stack + uiLocOnStack); + memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size); + } + break; + } + default: + z = (*p_arg)->size; + if (z < sizeof (int)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = + (unsigned int) *(UINT8 *) (*p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = + (unsigned int) *(UINT16 *) (*p_argv); + break; + + default: + FFI_ASSERT (0); + } + z = sizeof (int); + } + else if (z == sizeof (int)) + *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv); + else + memcpy (argp, *p_argv, z); + break; + } + p_argv++; + argp += z; + } + + return (struct_count); +} + +ffi_status +ffi_prep_cif (ffi_cif * cif, + ffi_abi abi, unsigned int nargs, + ffi_type * rtype, ffi_type ** atypes) +{ + unsigned bytes = 0; + unsigned int i; + ffi_type **ptr; + + FFI_ASSERT (cif != NULL); + FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); + + cif->abi = abi; + cif->arg_types = atypes; + cif->nargs = nargs; + cif->rtype = rtype; + + cif->flags = 0; + + if ((cif->rtype->size == 0) + && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + FFI_ASSERT_VALID_TYPE (cif->rtype); + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + if (((*ptr)->size == 0) + && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + FFI_ASSERT_VALID_TYPE (*ptr); + + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN (bytes, (*ptr)->alignment); + if ((*ptr)->type == FFI_TYPE_STRUCT) + { + if ((*ptr)->size > 8) + { + bytes += (*ptr)->size; + bytes += sizeof (void *); + } + else + { + if ((*ptr)->size > 4) + bytes += 8; + else + bytes += 4; + } + } + else + bytes += STACK_ARG_SIZE ((*ptr)->size); + } + + cif->bytes = bytes; + + return ffi_prep_cif_machdep (cif); +} + +ffi_status +ffi_prep_cif_machdep (ffi_cif * cif) +{ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = (unsigned) cif->rtype->type; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +extern void ffi_call_SYSV (int (*)(char *, extended_cif *), + extended_cif *, + unsigned, unsigned, unsigned *, void (*fn) ()) + __attribute__ ((__visibility__ ("hidden"))); + +void +ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca (cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + default: + FFI_ASSERT (0); + break; + } +} + +/* Because the following variables are not exported outside libffi, we + mark them hidden. */ + +/* Assembly code for the jump stub. */ +extern const char ffi_cris_trampoline_template[] + __attribute__ ((__visibility__ ("hidden"))); + +/* Offset into ffi_cris_trampoline_template of where to put the + ffi_prep_closure_inner function. */ +extern const int ffi_cris_trampoline_fn_offset + __attribute__ ((__visibility__ ("hidden"))); + +/* Offset into ffi_cris_trampoline_template of where to put the + closure data. */ +extern const int ffi_cris_trampoline_closure_offset + __attribute__ ((__visibility__ ("hidden"))); + +/* This function is sibling-called (jumped to) by the closure + trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at + PARAMS[4] to simplify handling of a straddling parameter. A copy + of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are + put at the appropriate place in CLOSURE which is then executed and + the return value is passed back to the caller. */ + +static unsigned long long +ffi_prep_closure_inner (void **params, ffi_closure* closure) +{ + char *register_args = (char *) params; + void *struct_ret = params[5]; + char *stack_args = params[6]; + char *ptr = register_args; + ffi_cif *cif = closure->cif; + ffi_type **arg_types = cif->arg_types; + + /* Max room needed is number of arguments as 64-bit values. */ + void **avalue = alloca (closure->cif->nargs * sizeof(void *)); + int i; + int doing_regs; + long long llret = 0; + + /* Find the address of each argument. */ + for (i = 0, doing_regs = 1; i < cif->nargs; i++) + { + /* Types up to and including 8 bytes go by-value. */ + if (arg_types[i]->size <= 4) + { + avalue[i] = ptr; + ptr += 4; + } + else if (arg_types[i]->size <= 8) + { + avalue[i] = ptr; + ptr += 8; + } + else + { + FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT); + + /* Passed by-reference, so copy the pointer. */ + avalue[i] = *(void **) ptr; + ptr += 4; + } + + /* If we've handled more arguments than fit in registers, start + looking at the those passed on the stack. Step over the + first one if we had a straddling parameter. */ + if (doing_regs && ptr >= register_args + 4*4) + { + ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0); + doing_regs = 0; + } + } + + /* Invoke the closure. */ + (closure->fun) (cif, + + cif->rtype->type == FFI_TYPE_STRUCT + /* The caller allocated space for the return + structure, and passed a pointer to this space in + R9. */ + ? struct_ret + + /* We take advantage of being able to ignore that + the high part isn't set if the return value is + not in R10:R11, but in R10 only. */ + : (void *) &llret, + + avalue, closure->user_data); + + return llret; +} + +/* API function: Prepare the trampoline. */ + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif *, void *, void **, void*), + void *user_data) +{ + void *innerfn = ffi_prep_closure_inner; + FFI_ASSERT (cif->abi == FFI_SYSV); + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + memcpy (closure->tramp, ffi_cris_trampoline_template, + FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE); + memcpy (closure->tramp + ffi_cris_trampoline_fn_offset, + &innerfn, sizeof (void *)); + memcpy (closure->tramp + ffi_cris_trampoline_closure_offset, + &closure, sizeof (void *)); + + return FFI_OK; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffitarget.h new file mode 100644 index 000000000..3fb937c16 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/ffitarget.h @@ -0,0 +1,50 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for CRIS. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE 36 +#define FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE (7*4) +#define FFI_TRAMPOLINE_SIZE \ + (FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE + FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE) +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/sysv.S new file mode 100644 index 000000000..79abaee4d --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/cris/sysv.S @@ -0,0 +1,215 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2004 Simon Posnjak + Copyright (c) 2005 Axis Communications AB + + CRIS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <ffi.h> +#define CONCAT(x,y) x ## y +#define XCONCAT(x,y) CONCAT (x, y) +#define L(x) XCONCAT (__USER_LABEL_PREFIX__, x) + + .text + + ;; OK, when we get called we should have this (according to + ;; AXIS ETRAX 100LX Programmer's Manual chapter 6.3). + ;; + ;; R10: ffi_prep_args (func. pointer) + ;; R11: &ecif + ;; R12: cif->bytes + ;; R13: fig->flags + ;; sp+0: ecif.rvalue + ;; sp+4: fn (function pointer to the function that we need to call) + + .globl L(ffi_call_SYSV) + .type L(ffi_call_SYSV),@function + .hidden L(ffi_call_SYSV) + +L(ffi_call_SYSV): + ;; Save the regs to the stack. + push $srp + ;; Used for stack pointer saving. + push $r6 + ;; Used for function address pointer. + push $r7 + ;; Used for stack pointer saving. + push $r8 + ;; We save fig->flags to stack we will need them after we + ;; call The Function. + push $r13 + + ;; Saving current stack pointer. + move.d $sp,$r8 + move.d $sp,$r6 + + ;; Move address of ffi_prep_args to r13. + move.d $r10,$r13 + + ;; Make room on the stack for the args of fn. + sub.d $r12,$sp + + ;; Function void ffi_prep_args(char *stack, extended_cif *ecif) parameters are: + ;; r10 <-- stack pointer + ;; r11 <-- &ecif (already there) + move.d $sp,$r10 + + ;; Call the function. + jsr $r13 + + ;; Save the size of the structures which are passed on stack. + move.d $r10,$r7 + + ;; Move first four args in to r10..r13. + move.d [$sp+0],$r10 + move.d [$sp+4],$r11 + move.d [$sp+8],$r12 + move.d [$sp+12],$r13 + + ;; Adjust the stack and check if any parameters are given on stack. + addq 16,$sp + sub.d $r7,$r6 + cmp.d $sp,$r6 + + bpl go_on + nop + +go_on_no_params_on_stack: + move.d $r6,$sp + +go_on: + ;; Discover if we need to put rval address in to r9. + move.d [$r8+0],$r7 + cmpq FFI_TYPE_STRUCT,$r7 + bne call_now + nop + + ;; Move rval address to $r9. + move.d [$r8+20],$r9 + +call_now: + ;; Move address of The Function in to r7. + move.d [$r8+24],$r7 + + ;; Call The Function. + jsr $r7 + + ;; Reset stack. + move.d $r8,$sp + + ;; Load rval type (fig->flags) in to r13. + pop $r13 + + ;; Detect rval type. + cmpq FFI_TYPE_VOID,$r13 + beq epilogue + + cmpq FFI_TYPE_STRUCT,$r13 + beq epilogue + + cmpq FFI_TYPE_DOUBLE,$r13 + beq return_double_or_longlong + + cmpq FFI_TYPE_UINT64,$r13 + beq return_double_or_longlong + + cmpq FFI_TYPE_SINT64,$r13 + beq return_double_or_longlong + nop + + ;; Just return the 32 bit value. + ba return + nop + +return_double_or_longlong: + ;; Load half of the rval to r10 and the other half to r11. + move.d [$sp+16],$r13 + move.d $r10,[$r13] + addq 4,$r13 + move.d $r11,[$r13] + ba epilogue + nop + +return: + ;; Load the rval to r10. + move.d [$sp+16],$r13 + move.d $r10,[$r13] + +epilogue: + pop $r8 + pop $r7 + pop $r6 + Jump [$sp+] + + .size ffi_call_SYSV,.-ffi_call_SYSV + +/* Save R10..R13 into an array, somewhat like varargs. Copy the next + argument too, to simplify handling of any straddling parameter. + Save R9 and SP after those. Jump to function handling the rest. + Since this is a template, copied and the main function filled in by + the user. */ + + .globl L(ffi_cris_trampoline_template) + .type L(ffi_cris_trampoline_template),@function + .hidden L(ffi_cris_trampoline_template) + +L(ffi_cris_trampoline_template): +0: + /* The value we get for "PC" is right after the prefix instruction, + two bytes from the beginning, i.e. 0b+2. */ + move.d $r10,[$pc+2f-(0b+2)] + move.d $pc,$r10 +1: + addq 2f-1b+4,$r10 + move.d $r11,[$r10+] + move.d $r12,[$r10+] + move.d $r13,[$r10+] + move.d [$sp],$r11 + move.d $r11,[$r10+] + move.d $r9,[$r10+] + move.d $sp,[$r10+] + subq FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE,$r10 + move.d 0,$r11 +3: + jump 0 +2: + .size ffi_cris_trampoline_template,.-0b + +/* This macro create a constant usable as "extern const int \name" in + C from within libffi, when \name has no prefix decoration. */ + + .macro const name,value + .globl \name + .type \name,@object + .hidden \name +\name: + .dword \value + .size \name,4 + .endm + +/* Constants for offsets within the trampoline. We could do this with + just symbols, avoiding memory contents and memory accesses, but the + C usage code would look a bit stranger. */ + + const L(ffi_cris_trampoline_fn_offset),2b-4-0b + const L(ffi_cris_trampoline_closure_offset),3b-4-0b diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/darwin/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/darwin/ffitarget.h new file mode 100644 index 000000000..2dc308ac3 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/darwin/ffitarget.h @@ -0,0 +1,25 @@ +/* + * This file is for MacOSX only. Dispatch to the right architecture include + * file based on the current archictecture (instead of relying on a symlink + * created by configure). This makes is possible to build a univeral binary + * of ctypes in one go. + */ +#if defined(__i386__) + +#ifndef X86_DARWIN +#define X86_DARWIN +#endif +#undef POWERPC_DARWIN + +#include "../src/x86/ffitarget.h" + +#elif defined(__ppc__) + +#ifndef POWERPC_DARWIN +#define POWERPC_DARWIN +#endif +#undef X86_DARWIN + +#include "../src/powerpc/ffitarget.h" + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/eabi.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/eabi.S new file mode 100644 index 000000000..9530ca52e --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/eabi.S @@ -0,0 +1,130 @@ +/* ----------------------------------------------------------------------- + eabi.S - Copyright (c) 2004 Anthony Green + + FR-V Assembly glue. + + $Id: eabi.S,v 1.2 2006/03/03 20:24:46 theller Exp $ + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .globl ffi_prep_args_EABI + + .text + .p2align 4 + .globl ffi_call_EABI + .type ffi_call_EABI, @function + + # gr8 : ffi_prep_args + # gr9 : &ecif + # gr10: cif->bytes + # gr11: fig->flags + # gr12: ecif.rvalue + # gr13: fn + +ffi_call_EABI: + addi sp, #-80, sp + sti fp, @(sp, #24) + addi sp, #24, fp + movsg lr, gr5 + + /* Make room for the new arguments. */ + /* subi sp, fp, gr10 */ + + /* Store return address and incoming args on stack. */ + sti gr5, @(fp, #8) + sti gr8, @(fp, #-4) + sti gr9, @(fp, #-8) + sti gr10, @(fp, #-12) + sti gr11, @(fp, #-16) + sti gr12, @(fp, #-20) + sti gr13, @(fp, #-24) + + sub sp, gr10, sp + + /* Call ffi_prep_args. */ + ldi @(fp, #-4), gr4 + addi sp, #0, gr8 + ldi @(fp, #-8), gr9 +#ifdef __FRV_FDPIC__ + ldd @(gr4, gr0), gr14 + calll @(gr14, gr0) +#else + calll @(gr4, gr0) +#endif + + /* ffi_prep_args returns the new stack pointer. */ + mov gr8, gr4 + + ldi @(sp, #0), gr8 + ldi @(sp, #4), gr9 + ldi @(sp, #8), gr10 + ldi @(sp, #12), gr11 + ldi @(sp, #16), gr12 + ldi @(sp, #20), gr13 + + /* Always copy the return value pointer into the hidden + parameter register. This is only strictly necessary + when we're returning an aggregate type, but it doesn't + hurt to do this all the time, and it saves a branch. */ + ldi @(fp, #-20), gr3 + + /* Use the ffi_prep_args return value for the new sp. */ + mov gr4, sp + + /* Call the target function. */ + ldi @(fp, -24), gr4 +#ifdef __FRV_FDPIC__ + ldd @(gr4, gr0), gr14 + calll @(gr14, gr0) +#else + calll @(gr4, gr0) +#endif + + /* Store the result. */ + ldi @(fp, #-16), gr10 /* fig->flags */ + ldi @(fp, #-20), gr4 /* ecif.rvalue */ + + /* Is the return value stored in two registers? */ + cmpi gr10, #8, icc0 + bne icc0, 0, .L2 + /* Yes, save them. */ + sti gr8, @(gr4, #0) + sti gr9, @(gr4, #4) + bra .L3 +.L2: + /* Is the return value a structure? */ + cmpi gr10, #-1, icc0 + beq icc0, 0, .L3 + /* No, save a 4 byte return value. */ + sti gr8, @(gr4, #0) +.L3: + + /* Restore the stack, and return. */ + ldi @(fp, 8), gr5 + ld @(fp, gr0), fp + addi sp,#80,sp + jmpl @(gr5,gr0) + .size ffi_call_EABI, .-ffi_call_EABI + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffi.c new file mode 100644 index 000000000..6e2ac6873 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffi.c @@ -0,0 +1,287 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2004 Anthony Green + + FR-V Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void *ffi_prep_args(char *stack, extended_cif *ecif) +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + register int count = 0; + + p_argv = ecif->avalue; + argp = stack; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + + if ((*p_arg)->type == FFI_TYPE_STRUCT) + { + z = sizeof(void*); + *(void **) argp = *p_argv; + } + /* if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (count > 24) + { + // This is going on the stack. Turn it into a double. + *(double *) argp = (double) *(float*)(* p_argv); + z = sizeof(double); + } + else + *(void **) argp = *(void **)(* p_argv); + } */ + else if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + count += z; + } + + return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8))); +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + if (cif->rtype->type == FFI_TYPE_STRUCT) + cif->flags = -1; + else + cif->flags = cif->rtype->size; + + cif->bytes = ALIGN (cif->bytes, 8); + + return FFI_OK; +} + +extern void ffi_call_EABI(void *(*)(char *, extended_cif *), + extended_cif *, + unsigned, unsigned, + unsigned *, + void (*fn)()); + +void ffi_call(ffi_cif *cif, + void (*fn)(), + void *rvalue, + void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + ecif.rvalue = alloca(cif->rtype->size); + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_EABI: + ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; + default: + FFI_ASSERT(0); + break; + } +} + +void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3, + unsigned arg4, unsigned arg5, unsigned arg6) +{ + /* This function is called by a trampoline. The trampoline stows a + pointer to the ffi_closure object in gr7. We must save this + pointer in a place that will persist while we do our work. */ + register ffi_closure *creg __asm__ ("gr7"); + ffi_closure *closure = creg; + + /* Arguments that don't fit in registers are found on the stack + at a fixed offset above the current frame pointer. */ + register char *frame_pointer __asm__ ("fp"); + char *stack_args = frame_pointer + 16; + + /* Lay the register arguments down in a continuous chunk of memory. */ + unsigned register_args[6] = + { arg1, arg2, arg3, arg4, arg5, arg6 }; + + ffi_cif *cif = closure->cif; + ffi_type **arg_types = cif->arg_types; + void **avalue = alloca (cif->nargs * sizeof(void *)); + char *ptr = (char *) register_args; + int i; + + /* Find the address of each argument. */ + for (i = 0; i < cif->nargs; i++) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = ptr + 3; + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = ptr + 2; + break; + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_FLOAT: + avalue[i] = ptr; + break; + case FFI_TYPE_STRUCT: + avalue[i] = *(void**)ptr; + break; + default: + /* This is an 8-byte value. */ + avalue[i] = ptr; + ptr += 4; + break; + } + ptr += 4; + + /* If we've handled more arguments than fit in registers, + start looking at the those passed on the stack. */ + if (ptr == ((char *)register_args + (6*4))) + ptr = stack_args; + } + + /* Invoke the closure. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + /* The caller allocates space for the return structure, and + passes a pointer to this space in gr3. Use this value directly + as the return value. */ + register void *return_struct_ptr __asm__("gr3"); + (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data); + } + else + { + /* Allocate space for the return value and call the function. */ + long long rvalue; + (closure->fun) (cif, &rvalue, avalue, closure->user_data); + + /* Functions return 4-byte or smaller results in gr8. 8-byte + values also use gr9. We fill the both, even for small return + values, just to avoid a branch. */ + asm ("ldi @(%0, #0), gr8" : : "r" (&rvalue)); + asm ("ldi @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1])); + } +} + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned long fn = (long) ffi_closure_eabi; + unsigned long cls = (long) closure; +#ifdef __FRV_FDPIC__ + register void *got __asm__("gr15"); +#endif + int i; + + fn = (unsigned long) ffi_closure_eabi; + +#ifdef __FRV_FDPIC__ + tramp[0] = &tramp[2]; + tramp[1] = got; + tramp[2] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */ + tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */ + tramp[4] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */ + tramp[5] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */ + tramp[6] = 0x9cc86000; /* ldi @(gr6, #0), gr14 */ + tramp[7] = 0x8030e000; /* jmpl @(gr14, gr0) */ +#else + tramp[0] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */ + tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */ + tramp[2] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */ + tramp[3] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */ + tramp[4] = 0x80300006; /* jmpl @(gr0, gr6) */ +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Cache flushing. */ + for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++) + __asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (tramp), "r" (i)); + + return FFI_OK; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffitarget.h new file mode 100644 index 000000000..d235697d6 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/frv/ffitarget.h @@ -0,0 +1,60 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2004 Red Hat, Inc. + Target configuration macros for FR-V + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + +#ifdef FRV + FFI_EABI, + FFI_DEFAULT_ABI = FFI_EABI, +#endif + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#ifdef __FRV_FDPIC__ +/* Trampolines are 8 4-byte instructions long. */ +#define FFI_TRAMPOLINE_SIZE (8*4) +#else +/* Trampolines are 5 4-byte instructions long. */ +#define FFI_TRAMPOLINE_SIZE (5*4) +#endif + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffi.c new file mode 100644 index 000000000..e810827a8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffi.c @@ -0,0 +1,562 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Red Hat, Inc. + Copyright (c) 2000 Hewlett Packard Company + + IA64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <stdbool.h> +#include <float.h> + +#include "ia64_flags.h" + +/* A 64-bit pointer value. In LP64 mode, this is effectively a plain + pointer. In ILP32 mode, it's a pointer that's been extended to + 64 bits by "addp4". */ +typedef void *PTR64 __attribute__((mode(DI))); + +/* Memory image of fp register contents. This is the implementation + specific format used by ldf.fill/stf.spill. All we care about is + that it wants a 16 byte aligned slot. */ +typedef struct +{ + UINT64 x[2] __attribute__((aligned(16))); +} fpreg; + + +/* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */ + +struct ia64_args +{ + fpreg fp_regs[8]; /* Contents of 8 fp arg registers. */ + UINT64 gp_regs[8]; /* Contents of 8 gp arg registers. */ + UINT64 other_args[]; /* Arguments passed on stack, variable size. */ +}; + + +/* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */ + +static inline void * +endian_adjust (void *addr, size_t len) +{ +#ifdef __BIG_ENDIAN__ + return addr + (8 - len); +#else + return addr; +#endif +} + +/* Store VALUE to ADDR in the current cpu implementation's fp spill format. */ + +static inline void +stf_spill(fpreg *addr, __float80 value) +{ + asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value)); +} + +/* Load a value from ADDR, which is in the current cpu implementation's + fp spill format. */ + +static inline __float80 +ldf_fill(fpreg *addr) +{ + __float80 ret; + asm ("ldf.fill %0 = %1%P1" : "=f"(ret) : "m"(*addr)); + return ret; +} + +/* Return the size of the C type associated with with TYPE. Which will + be one of the FFI_IA64_TYPE_HFA_* values. */ + +static size_t +hfa_type_size (int type) +{ + switch (type) + { + case FFI_IA64_TYPE_HFA_FLOAT: + return sizeof(float); + case FFI_IA64_TYPE_HFA_DOUBLE: + return sizeof(double); + case FFI_IA64_TYPE_HFA_LDOUBLE: + return sizeof(__float80); + default: + abort (); + } +} + +/* Load from ADDR a value indicated by TYPE. Which will be one of + the FFI_IA64_TYPE_HFA_* values. */ + +static __float80 +hfa_type_load (int type, void *addr) +{ + switch (type) + { + case FFI_IA64_TYPE_HFA_FLOAT: + return *(float *) addr; + case FFI_IA64_TYPE_HFA_DOUBLE: + return *(double *) addr; + case FFI_IA64_TYPE_HFA_LDOUBLE: + return *(__float80 *) addr; + default: + abort (); + } +} + +/* Load VALUE into ADDR as indicated by TYPE. Which will be one of + the FFI_IA64_TYPE_HFA_* values. */ + +static void +hfa_type_store (int type, void *addr, __float80 value) +{ + switch (type) + { + case FFI_IA64_TYPE_HFA_FLOAT: + *(float *) addr = value; + break; + case FFI_IA64_TYPE_HFA_DOUBLE: + *(double *) addr = value; + break; + case FFI_IA64_TYPE_HFA_LDOUBLE: + *(__float80 *) addr = value; + break; + default: + abort (); + } +} + +/* Is TYPE a struct containing floats, doubles, or extended doubles, + all of the same fp type? If so, return the element type. Return + FFI_TYPE_VOID if not. */ + +static int +hfa_element_type (ffi_type *type, int nested) +{ + int element = FFI_TYPE_VOID; + + switch (type->type) + { + case FFI_TYPE_FLOAT: + /* We want to return VOID for raw floating-point types, but the + synthetic HFA type if we're nested within an aggregate. */ + if (nested) + element = FFI_IA64_TYPE_HFA_FLOAT; + break; + + case FFI_TYPE_DOUBLE: + /* Similarly. */ + if (nested) + element = FFI_IA64_TYPE_HFA_DOUBLE; + break; + + case FFI_TYPE_LONGDOUBLE: + /* Similarly, except that that HFA is true for double extended, + but not quad precision. Both have sizeof == 16, so tell the + difference based on the precision. */ + if (LDBL_MANT_DIG == 64 && nested) + element = FFI_IA64_TYPE_HFA_LDOUBLE; + break; + + case FFI_TYPE_STRUCT: + { + ffi_type **ptr = &type->elements[0]; + + for (ptr = &type->elements[0]; *ptr ; ptr++) + { + int sub_element = hfa_element_type (*ptr, 1); + if (sub_element == FFI_TYPE_VOID) + return FFI_TYPE_VOID; + + if (element == FFI_TYPE_VOID) + element = sub_element; + else if (element != sub_element) + return FFI_TYPE_VOID; + } + } + break; + + default: + return FFI_TYPE_VOID; + } + + return element; +} + + +/* Perform machine dependent cif processing. */ + +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + int flags; + + /* Adjust cif->bytes to include space for the bits of the ia64_args frame + that preceeds the integer register portion. The estimate that the + generic bits did for the argument space required is good enough for the + integer component. */ + cif->bytes += offsetof(struct ia64_args, gp_regs[0]); + if (cif->bytes < sizeof(struct ia64_args)) + cif->bytes = sizeof(struct ia64_args); + + /* Set the return type flag. */ + flags = cif->rtype->type; + switch (cif->rtype->type) + { + case FFI_TYPE_LONGDOUBLE: + /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision, + and encode quad precision as a two-word integer structure. */ + if (LDBL_MANT_DIG != 64) + flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8); + break; + + case FFI_TYPE_STRUCT: + { + size_t size = cif->rtype->size; + int hfa_type = hfa_element_type (cif->rtype, 0); + + if (hfa_type != FFI_TYPE_VOID) + { + size_t nelts = size / hfa_type_size (hfa_type); + if (nelts <= 8) + flags = hfa_type | (size << 8); + } + else + { + if (size <= 32) + flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8); + } + } + break; + + default: + break; + } + cif->flags = flags; + + return FFI_OK; +} + +extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(), UINT64); + +void +ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) +{ + struct ia64_args *stack; + long i, avn, gpcount, fpcount; + ffi_type **p_arg; + + FFI_ASSERT (cif->abi == FFI_UNIX); + + /* If we have no spot for a return value, make one. */ + if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID) + rvalue = alloca (cif->rtype->size); + + /* Allocate the stack frame. */ + stack = alloca (cif->bytes); + + gpcount = fpcount = 0; + avn = cif->nargs; + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i]; + break; + case FFI_TYPE_UINT8: + stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i]; + break; + case FFI_TYPE_SINT16: + stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i]; + break; + case FFI_TYPE_UINT16: + stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i]; + break; + case FFI_TYPE_SINT32: + stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i]; + break; + case FFI_TYPE_UINT32: + stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; + break; + + case FFI_TYPE_POINTER: + stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i]; + break; + + case FFI_TYPE_FLOAT: + if (gpcount < 8 && fpcount < 8) + stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]); + stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; + break; + + case FFI_TYPE_DOUBLE: + if (gpcount < 8 && fpcount < 8) + stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]); + stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; + break; + + case FFI_TYPE_LONGDOUBLE: + if (gpcount & 1) + gpcount++; + if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) + stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]); + memcpy (&stack->gp_regs[gpcount], avalue[i], 16); + gpcount += 2; + break; + + case FFI_TYPE_STRUCT: + { + size_t size = (*p_arg)->size; + size_t align = (*p_arg)->alignment; + int hfa_type = hfa_element_type (*p_arg, 0); + + FFI_ASSERT (align <= 16); + if (align == 16 && (gpcount & 1)) + gpcount++; + + if (hfa_type != FFI_TYPE_VOID) + { + size_t hfa_size = hfa_type_size (hfa_type); + size_t offset = 0; + size_t gp_offset = gpcount * 8; + + while (fpcount < 8 + && offset < size + && gp_offset < 8 * 8) + { + stf_spill (&stack->fp_regs[fpcount], + hfa_type_load (hfa_type, avalue[i] + offset)); + offset += hfa_size; + gp_offset += hfa_size; + fpcount += 1; + } + } + + memcpy (&stack->gp_regs[gpcount], avalue[i], size); + gpcount += (size + 7) / 8; + } + break; + + default: + abort (); + } + } + + ffi_call_unix (stack, rvalue, fn, cif->flags); +} + +/* Closures represent a pair consisting of a function pointer, and + some user data. A closure is invoked by reinterpreting the closure + as a function pointer, and branching to it. Thus we can make an + interpreted function callable as a C function: We turn the + interpreter itself, together with a pointer specifying the + interpreted procedure, into a closure. + + For IA64, function pointer are already pairs consisting of a code + pointer, and a gp pointer. The latter is needed to access global + variables. Here we set up such a pair as the first two words of + the closure (in the "trampoline" area), but we replace the gp + pointer with a pointer to the closure itself. We also add the real + gp pointer to the closure. This allows the function entry code to + both retrieve the user data, and to restire the correct gp pointer. */ + +extern void ffi_closure_unix (); + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + /* The layout of a function descriptor. A C function pointer really + points to one of these. */ + struct ia64_fd + { + UINT64 code_pointer; + UINT64 gp; + }; + + struct ffi_ia64_trampoline_struct + { + UINT64 code_pointer; /* Pointer to ffi_closure_unix. */ + UINT64 fake_gp; /* Pointer to closure, installed as gp. */ + UINT64 real_gp; /* Real gp value. */ + }; + + struct ffi_ia64_trampoline_struct *tramp; + struct ia64_fd *fd; + + FFI_ASSERT (cif->abi == FFI_UNIX); + + tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp; + fd = (struct ia64_fd *)(void *)ffi_closure_unix; + + tramp->code_pointer = fd->code_pointer; + tramp->real_gp = fd->gp; + tramp->fake_gp = (UINT64)(PTR64)closure; + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + + +UINT64 +ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack, + void *rvalue, void *r8) +{ + ffi_cif *cif; + void **avalue; + ffi_type **p_arg; + long i, avn, gpcount, fpcount; + + cif = closure->cif; + avn = cif->nargs; + avalue = alloca (avn * sizeof (void *)); + + /* If the structure return value is passed in memory get that location + from r8 so as to pass the value directly back to the caller. */ + if (cif->flags == FFI_TYPE_STRUCT) + rvalue = r8; + + gpcount = fpcount = 0; + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1); + break; + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2); + break; + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4); + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + avalue[i] = &stack->gp_regs[gpcount++]; + break; + case FFI_TYPE_POINTER: + avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*)); + break; + + case FFI_TYPE_FLOAT: + if (gpcount < 8 && fpcount < 8) + { + void *addr = &stack->fp_regs[fpcount++]; + avalue[i] = addr; + *(float *)addr = ldf_fill (addr); + } + else + avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4); + gpcount++; + break; + + case FFI_TYPE_DOUBLE: + if (gpcount < 8 && fpcount < 8) + { + void *addr = &stack->fp_regs[fpcount++]; + avalue[i] = addr; + *(double *)addr = ldf_fill (addr); + } + else + avalue[i] = &stack->gp_regs[gpcount]; + gpcount++; + break; + + case FFI_TYPE_LONGDOUBLE: + if (gpcount & 1) + gpcount++; + if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) + { + void *addr = &stack->fp_regs[fpcount++]; + avalue[i] = addr; + *(__float80 *)addr = ldf_fill (addr); + } + else + avalue[i] = &stack->gp_regs[gpcount]; + gpcount += 2; + break; + + case FFI_TYPE_STRUCT: + { + size_t size = (*p_arg)->size; + size_t align = (*p_arg)->alignment; + int hfa_type = hfa_element_type (*p_arg, 0); + + FFI_ASSERT (align <= 16); + if (align == 16 && (gpcount & 1)) + gpcount++; + + if (hfa_type != FFI_TYPE_VOID) + { + size_t hfa_size = hfa_type_size (hfa_type); + size_t offset = 0; + size_t gp_offset = gpcount * 8; + void *addr = alloca (size); + + avalue[i] = addr; + + while (fpcount < 8 + && offset < size + && gp_offset < 8 * 8) + { + hfa_type_store (hfa_type, addr + offset, + ldf_fill (&stack->fp_regs[fpcount])); + offset += hfa_size; + gp_offset += hfa_size; + fpcount += 1; + } + + if (offset < size) + memcpy (addr + offset, (char *)stack->gp_regs + gp_offset, + size - offset); + } + else + avalue[i] = &stack->gp_regs[gpcount]; + + gpcount += (size + 7) / 8; + } + break; + + default: + abort (); + } + } + + closure->fun (cif, rvalue, avalue, closure->user_data); + + return cif->flags; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffitarget.h new file mode 100644 index 000000000..0d820b3a5 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ffitarget.h @@ -0,0 +1,49 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for IA-64. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long long ffi_arg; +typedef signed long long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_UNIX, /* Linux and all Unix variants use the same conventions */ + FFI_DEFAULT_ABI = FFI_UNIX, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */ + /* can be interpreted as a C function */ + /* descriptor: */ + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ia64_flags.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ia64_flags.h new file mode 100644 index 000000000..1dd6d7e3f --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/ia64_flags.h @@ -0,0 +1,39 @@ +/* ----------------------------------------------------------------------- + ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company + + IA64/unix Foreign Function Interface + + Original author: Hans Boehm, HP Labs + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* "Type" codes used between assembly and C. When used as a part of + a cfi->flags value, the low byte will be these extra type codes, + and bits 8-31 will be the actual size of the type. */ + +/* Small structures containing N words in integer registers. */ +#define FFI_IA64_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 1) + +/* Homogeneous Floating Point Aggregates (HFAs) which are returned + in FP registers. */ +#define FFI_IA64_TYPE_HFA_FLOAT (FFI_TYPE_LAST + 2) +#define FFI_IA64_TYPE_HFA_DOUBLE (FFI_TYPE_LAST + 3) +#define FFI_IA64_TYPE_HFA_LDOUBLE (FFI_TYPE_LAST + 4) diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/unix.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/unix.S new file mode 100644 index 000000000..45dabb74c --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/ia64/unix.S @@ -0,0 +1,555 @@ +/* ----------------------------------------------------------------------- + unix.S - Copyright (c) 1998 Red Hat, Inc. + Copyright (c) 2000 Hewlett Packard Company + + IA64/unix Foreign Function Interface + + Primary author: Hans Boehm, HP Labs + + Loosely modeled on Cygnus code for other platforms. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#include "ia64_flags.h" + + .pred.safe_across_calls p1-p5,p16-p63 +.text + +/* int ffi_call_unix (struct ia64_args *stack, PTR64 rvalue, + void (*fn)(), int flags); + */ + + .align 16 + .global ffi_call_unix + .proc ffi_call_unix +ffi_call_unix: + .prologue + /* Bit o trickiness. We actually share a stack frame with ffi_call. + Rely on the fact that ffi_call uses a vframe and don't bother + tracking one here at all. */ + .fframe 0 + .save ar.pfs, r36 // loc0 + alloc loc0 = ar.pfs, 4, 3, 8, 0 + .save rp, loc1 + mov loc1 = b0 + .body + add r16 = 16, in0 + mov loc2 = gp + mov r8 = in1 + ;; + + /* Load up all of the argument registers. */ + ldf.fill f8 = [in0], 32 + ldf.fill f9 = [r16], 32 + ;; + ldf.fill f10 = [in0], 32 + ldf.fill f11 = [r16], 32 + ;; + ldf.fill f12 = [in0], 32 + ldf.fill f13 = [r16], 32 + ;; + ldf.fill f14 = [in0], 32 + ldf.fill f15 = [r16], 24 + ;; + ld8 out0 = [in0], 16 + ld8 out1 = [r16], 16 + ;; + ld8 out2 = [in0], 16 + ld8 out3 = [r16], 16 + ;; + ld8 out4 = [in0], 16 + ld8 out5 = [r16], 16 + ;; + ld8 out6 = [in0] + ld8 out7 = [r16] + ;; + + /* Deallocate the register save area from the stack frame. */ + mov sp = in0 + + /* Call the target function. */ + ld8 r16 = [in2], 8 + ;; + ld8 gp = [in2] + mov b6 = r16 + br.call.sptk.many b0 = b6 + ;; + + /* Dispatch to handle return value. */ + mov gp = loc2 + zxt1 r16 = in3 + ;; + mov ar.pfs = loc0 + addl r18 = @ltoffx(.Lst_table), gp + ;; + ld8.mov r18 = [r18], .Lst_table + mov b0 = loc1 + ;; + shladd r18 = r16, 3, r18 + ;; + ld8 r17 = [r18] + shr in3 = in3, 8 + ;; + add r17 = r17, r18 + ;; + mov b6 = r17 + br b6 + ;; + +.Lst_void: + br.ret.sptk.many b0 + ;; +.Lst_uint8: + zxt1 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_sint8: + sxt1 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_uint16: + zxt2 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_sint16: + sxt2 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_uint32: + zxt4 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_sint32: + sxt4 r8 = r8 + ;; + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_int64: + st8 [in1] = r8 + br.ret.sptk.many b0 + ;; +.Lst_float: + stfs [in1] = f8 + br.ret.sptk.many b0 + ;; +.Lst_double: + stfd [in1] = f8 + br.ret.sptk.many b0 + ;; +.Lst_ldouble: + stfe [in1] = f8 + br.ret.sptk.many b0 + ;; + +.Lst_small_struct: + add sp = -16, sp + cmp.lt p6, p0 = 8, in3 + cmp.lt p7, p0 = 16, in3 + cmp.lt p8, p0 = 24, in3 + ;; + add r16 = 8, sp + add r17 = 16, sp + add r18 = 24, sp + ;; + st8 [sp] = r8 +(p6) st8 [r16] = r9 + mov out0 = in1 +(p7) st8 [r17] = r10 +(p8) st8 [r18] = r11 + mov out1 = sp + mov out2 = in3 + br.call.sptk.many b0 = memcpy# + ;; + mov ar.pfs = loc0 + mov b0 = loc1 + mov gp = loc2 + br.ret.sptk.many b0 + +.Lst_hfa_float: + add r16 = 4, in1 + cmp.lt p6, p0 = 4, in3 + ;; + stfs [in1] = f8, 8 +(p6) stfs [r16] = f9, 8 + cmp.lt p7, p0 = 8, in3 + cmp.lt p8, p0 = 12, in3 + ;; +(p7) stfs [in1] = f10, 8 +(p8) stfs [r16] = f11, 8 + cmp.lt p9, p0 = 16, in3 + cmp.lt p10, p0 = 20, in3 + ;; +(p9) stfs [in1] = f12, 8 +(p10) stfs [r16] = f13, 8 + cmp.lt p6, p0 = 24, in3 + cmp.lt p7, p0 = 28, in3 + ;; +(p6) stfs [in1] = f14 +(p7) stfs [r16] = f15 + br.ret.sptk.many b0 + ;; + +.Lst_hfa_double: + add r16 = 8, in1 + cmp.lt p6, p0 = 8, in3 + ;; + stfd [in1] = f8, 16 +(p6) stfd [r16] = f9, 16 + cmp.lt p7, p0 = 16, in3 + cmp.lt p8, p0 = 24, in3 + ;; +(p7) stfd [in1] = f10, 16 +(p8) stfd [r16] = f11, 16 + cmp.lt p9, p0 = 32, in3 + cmp.lt p10, p0 = 40, in3 + ;; +(p9) stfd [in1] = f12, 16 +(p10) stfd [r16] = f13, 16 + cmp.lt p6, p0 = 48, in3 + cmp.lt p7, p0 = 56, in3 + ;; +(p6) stfd [in1] = f14 +(p7) stfd [r16] = f15 + br.ret.sptk.many b0 + ;; + +.Lst_hfa_ldouble: + add r16 = 16, in1 + cmp.lt p6, p0 = 16, in3 + ;; + stfe [in1] = f8, 32 +(p6) stfe [r16] = f9, 32 + cmp.lt p7, p0 = 32, in3 + cmp.lt p8, p0 = 48, in3 + ;; +(p7) stfe [in1] = f10, 32 +(p8) stfe [r16] = f11, 32 + cmp.lt p9, p0 = 64, in3 + cmp.lt p10, p0 = 80, in3 + ;; +(p9) stfe [in1] = f12, 32 +(p10) stfe [r16] = f13, 32 + cmp.lt p6, p0 = 96, in3 + cmp.lt p7, p0 = 112, in3 + ;; +(p6) stfe [in1] = f14 +(p7) stfe [r16] = f15 + br.ret.sptk.many b0 + ;; + + .endp ffi_call_unix + + .align 16 + .global ffi_closure_unix + .proc ffi_closure_unix + +#define FRAME_SIZE (8*16 + 8*8 + 8*16) + +ffi_closure_unix: + .prologue + .save ar.pfs, r40 // loc0 + alloc loc0 = ar.pfs, 8, 4, 4, 0 + .fframe FRAME_SIZE + add r12 = -FRAME_SIZE, r12 + .save rp, loc1 + mov loc1 = b0 + .save ar.unat, loc2 + mov loc2 = ar.unat + .body + + /* Retrieve closure pointer and real gp. */ +#ifdef _ILP32 + addp4 out0 = 0, gp + addp4 gp = 16, gp +#else + mov out0 = gp + add gp = 16, gp +#endif + ;; + ld8 gp = [gp] + + /* Spill all of the possible argument registers. */ + add r16 = 16 + 8*16, sp + add r17 = 16 + 8*16 + 16, sp + ;; + stf.spill [r16] = f8, 32 + stf.spill [r17] = f9, 32 + mov loc3 = gp + ;; + stf.spill [r16] = f10, 32 + stf.spill [r17] = f11, 32 + ;; + stf.spill [r16] = f12, 32 + stf.spill [r17] = f13, 32 + ;; + stf.spill [r16] = f14, 32 + stf.spill [r17] = f15, 24 + ;; + .mem.offset 0, 0 + st8.spill [r16] = in0, 16 + .mem.offset 8, 0 + st8.spill [r17] = in1, 16 + add out1 = 16 + 8*16, sp + ;; + .mem.offset 0, 0 + st8.spill [r16] = in2, 16 + .mem.offset 8, 0 + st8.spill [r17] = in3, 16 + add out2 = 16, sp + ;; + .mem.offset 0, 0 + st8.spill [r16] = in4, 16 + .mem.offset 8, 0 + st8.spill [r17] = in5, 16 + mov out3 = r8 + ;; + .mem.offset 0, 0 + st8.spill [r16] = in6 + .mem.offset 8, 0 + st8.spill [r17] = in7 + + /* Invoke ffi_closure_unix_inner for the hard work. */ + br.call.sptk.many b0 = ffi_closure_unix_inner + ;; + + /* Dispatch to handle return value. */ + mov gp = loc3 + zxt1 r16 = r8 + ;; + addl r18 = @ltoffx(.Lld_table), gp + mov ar.pfs = loc0 + ;; + ld8.mov r18 = [r18], .Lld_table + mov b0 = loc1 + ;; + shladd r18 = r16, 3, r18 + mov ar.unat = loc2 + ;; + ld8 r17 = [r18] + shr r8 = r8, 8 + ;; + add r17 = r17, r18 + add r16 = 16, sp + ;; + mov b6 = r17 + br b6 + ;; + .label_state 1 + +.Lld_void: + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_int: + .body + .copy_state 1 + ld8 r8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_float: + .body + .copy_state 1 + ldfs f8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_double: + .body + .copy_state 1 + ldfd f8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; +.Lld_ldouble: + .body + .copy_state 1 + ldfe f8 = [r16] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_small_struct: + .body + .copy_state 1 + add r17 = 8, r16 + cmp.lt p6, p0 = 8, r8 + cmp.lt p7, p0 = 16, r8 + cmp.lt p8, p0 = 24, r8 + ;; + ld8 r8 = [r16], 16 +(p6) ld8 r9 = [r17], 16 + ;; +(p7) ld8 r10 = [r16] +(p8) ld8 r11 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_hfa_float: + .body + .copy_state 1 + add r17 = 4, r16 + cmp.lt p6, p0 = 4, r8 + ;; + ldfs f8 = [r16], 8 +(p6) ldfs f9 = [r17], 8 + cmp.lt p7, p0 = 8, r8 + cmp.lt p8, p0 = 12, r8 + ;; +(p7) ldfs f10 = [r16], 8 +(p8) ldfs f11 = [r17], 8 + cmp.lt p9, p0 = 16, r8 + cmp.lt p10, p0 = 20, r8 + ;; +(p9) ldfs f12 = [r16], 8 +(p10) ldfs f13 = [r17], 8 + cmp.lt p6, p0 = 24, r8 + cmp.lt p7, p0 = 28, r8 + ;; +(p6) ldfs f14 = [r16] +(p7) ldfs f15 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_hfa_double: + .body + .copy_state 1 + add r17 = 8, r16 + cmp.lt p6, p0 = 8, r8 + ;; + ldfd f8 = [r16], 16 +(p6) ldfd f9 = [r17], 16 + cmp.lt p7, p0 = 16, r8 + cmp.lt p8, p0 = 24, r8 + ;; +(p7) ldfd f10 = [r16], 16 +(p8) ldfd f11 = [r17], 16 + cmp.lt p9, p0 = 32, r8 + cmp.lt p10, p0 = 40, r8 + ;; +(p9) ldfd f12 = [r16], 16 +(p10) ldfd f13 = [r17], 16 + cmp.lt p6, p0 = 48, r8 + cmp.lt p7, p0 = 56, r8 + ;; +(p6) ldfd f14 = [r16] +(p7) ldfd f15 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + +.Lld_hfa_ldouble: + .body + .copy_state 1 + add r17 = 16, r16 + cmp.lt p6, p0 = 16, r8 + ;; + ldfe f8 = [r16], 32 +(p6) ldfe f9 = [r17], 32 + cmp.lt p7, p0 = 32, r8 + cmp.lt p8, p0 = 48, r8 + ;; +(p7) ldfe f10 = [r16], 32 +(p8) ldfe f11 = [r17], 32 + cmp.lt p9, p0 = 64, r8 + cmp.lt p10, p0 = 80, r8 + ;; +(p9) ldfe f12 = [r16], 32 +(p10) ldfe f13 = [r17], 32 + cmp.lt p6, p0 = 96, r8 + cmp.lt p7, p0 = 112, r8 + ;; +(p6) ldfe f14 = [r16] +(p7) ldfe f15 = [r17] + .restore sp + add sp = FRAME_SIZE, sp + br.ret.sptk.many b0 + ;; + + .endp ffi_closure_unix + + .section .rodata + .align 8 +.Lst_table: + data8 @pcrel(.Lst_void) // FFI_TYPE_VOID + data8 @pcrel(.Lst_sint32) // FFI_TYPE_INT + data8 @pcrel(.Lst_float) // FFI_TYPE_FLOAT + data8 @pcrel(.Lst_double) // FFI_TYPE_DOUBLE + data8 @pcrel(.Lst_ldouble) // FFI_TYPE_LONGDOUBLE + data8 @pcrel(.Lst_uint8) // FFI_TYPE_UINT8 + data8 @pcrel(.Lst_sint8) // FFI_TYPE_SINT8 + data8 @pcrel(.Lst_uint16) // FFI_TYPE_UINT16 + data8 @pcrel(.Lst_sint16) // FFI_TYPE_SINT16 + data8 @pcrel(.Lst_uint32) // FFI_TYPE_UINT32 + data8 @pcrel(.Lst_sint32) // FFI_TYPE_SINT32 + data8 @pcrel(.Lst_int64) // FFI_TYPE_UINT64 + data8 @pcrel(.Lst_int64) // FFI_TYPE_SINT64 + data8 @pcrel(.Lst_void) // FFI_TYPE_STRUCT + data8 @pcrel(.Lst_int64) // FFI_TYPE_POINTER + data8 @pcrel(.Lst_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT + data8 @pcrel(.Lst_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT + data8 @pcrel(.Lst_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE + data8 @pcrel(.Lst_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE + +.Lld_table: + data8 @pcrel(.Lld_void) // FFI_TYPE_VOID + data8 @pcrel(.Lld_int) // FFI_TYPE_INT + data8 @pcrel(.Lld_float) // FFI_TYPE_FLOAT + data8 @pcrel(.Lld_double) // FFI_TYPE_DOUBLE + data8 @pcrel(.Lld_ldouble) // FFI_TYPE_LONGDOUBLE + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT8 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT8 + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT16 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT16 + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT32 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT32 + data8 @pcrel(.Lld_int) // FFI_TYPE_UINT64 + data8 @pcrel(.Lld_int) // FFI_TYPE_SINT64 + data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT + data8 @pcrel(.Lld_int) // FFI_TYPE_POINTER + data8 @pcrel(.Lld_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT + data8 @pcrel(.Lld_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT + data8 @pcrel(.Lld_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE + data8 @pcrel(.Lld_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffi.c new file mode 100644 index 000000000..9a3b55095 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffi.c @@ -0,0 +1,247 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2004 Renesas Technology + + M32R Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack + space has been allocated for the function's arguments. */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + unsigned int i; + int tmp; + unsigned int avn; + void **p_argv; + char *argp; + ffi_type **p_arg; + + tmp = 0; + argp = stack; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8) + { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0) && (avn != 0); + i--, p_arg++) + { + size_t z; + + /* Align if necessary. */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) + argp = (char *) ALIGN (argp, (*p_arg)->alignment); + + if (avn != 0) + { + avn--; + z = (*p_arg)->size; + if (z < sizeof (int)) + { + z = sizeof (int); + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + z = (*p_arg)->size; + if ((*p_arg)->alignment != 1) + memcpy (argp, *p_argv, z); + else + memcpy (argp + 4 - z, *p_argv, z); + z = sizeof (int); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof (int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + if ((*p_arg)->type == FFI_TYPE_STRUCT) + { + if (z > 8) + { + *(unsigned int *) argp = (unsigned int)(void *)(* p_argv); + z = sizeof(void *); + } + else + { + memcpy(argp, *p_argv, z); + z = 8; + } + } + else + { + /* Double or long long 64bit. */ + memcpy (argp, *p_argv, z); + } + } + p_argv++; + argp += z; + } + } + + return; +} + +/* Perform machine dependent cif processing. */ +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag. */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + if (cif->rtype->size <= 4) + cif->flags = FFI_TYPE_INT; + + else if (cif->rtype->size <= 8) + cif->flags = FFI_TYPE_DOUBLE; + + else + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_DOUBLE: + cif->flags = FFI_TYPE_DOUBLE; + break; + + case FFI_TYPE_FLOAT: + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have + a return value address then we need to make one. */ + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca (cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + int size = cif->rtype->size; + int align = cif->rtype->alignment; + + if (size < 4) + { + if (align == 1) + *(unsigned long *)(ecif.rvalue) <<= (4 - size) * 8; + } + else if (4 < size && size < 8) + { + if (align == 1) + { + memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); + } + else if (align == 2) + { + if (size & 1) + size += 1; + + if (size != 8) + memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); + } + } + } + /*@=usedef@*/ + break; + + default: + FFI_ASSERT(0); + break; + } +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffitarget.h new file mode 100644 index 000000000..6a761f659 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/ffitarget.h @@ -0,0 +1,48 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 2004 Renesas Technology. + Target configuration macros for M32R. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi + { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 + } ffi_abi; +#endif + +#define FFI_CLOSURES 0 +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/sysv.S new file mode 100644 index 000000000..06b75c226 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m32r/sysv.S @@ -0,0 +1,121 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2004 Renesas Technology + + M32R Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +/* XXX these lose for some platforms, I'm sure. */ +#define CNAME(x) x +#define ENTRY(x) .globl CNAME(x)! .type CNAME(x),%function! CNAME(x): +#endif + +.text + + /* R0: ffi_prep_args */ + /* R1: &ecif */ + /* R2: cif->bytes */ + /* R3: fig->flags */ + /* sp+0: ecif.rvalue */ + /* sp+4: fn */ + + /* This assumes we are using gas. */ +ENTRY(ffi_call_SYSV) + /* Save registers. */ + push fp + push lr + push r3 + push r2 + push r1 + push r0 + mv fp, sp + + /* Make room for all of the new args. */ + sub sp, r2 + + /* Place all of the ffi_prep_args in position. */ + mv lr, r0 + mv r0, sp + /* R1 already set. */ + + /* And call. */ + jl lr + + /* Move first 4 parameters in registers... */ + ld r0, @(0,sp) + ld r1, @(4,sp) + ld r2, @(8,sp) + ld r3, @(12,sp) + + /* ...and adjust the stack. */ + ld lr, @(8,fp) + cmpi lr, #16 + bc adjust_stack + ldi lr, #16 +adjust_stack: + add sp, lr + + /* Call the function. */ + ld lr, @(28,fp) + jl lr + + /* Remove the space we pushed for the args. */ + mv sp, fp + + /* Load R2 with the pointer to storage for the return value. */ + ld r2, @(24,sp) + + /* Load R3 with the return type code. */ + ld r3, @(12,sp) + + /* If the return value pointer is NULL, assume no return value. */ + beqz r2, epilogue + + /* Return INT. */ + ldi r4, #FFI_TYPE_INT + bne r3, r4, return_double + st r0, @r2 + bra epilogue + +return_double: + /* Return DOUBLE or LONGDOUBLE. */ + ldi r4, #FFI_TYPE_DOUBLE + bne r3, r4, epilogue + st r0, @r2 + st r1, @(4,r2) + +epilogue: + pop r0 + pop r1 + pop r2 + pop r3 + pop lr + pop fp + jmp lr + +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffi.c new file mode 100644 index 000000000..55f3a988b --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffi.c @@ -0,0 +1,176 @@ +/* ----------------------------------------------------------------------- + ffi.c + + m68k Foreign Function Interface + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space has + been allocated for the function's arguments. */ + +static void * +ffi_prep_args (void *stack, extended_cif *ecif) +{ + unsigned int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + void *struct_value_ptr; + + argp = stack; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT + && ecif->cif->rtype->size > 8) + struct_value_ptr = ecif->rvalue; + else + struct_value_ptr = NULL; + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + /* Align if necessary. */ + if (((*p_arg)->alignment - 1) & (unsigned) argp) + argp = (char *) ALIGN (argp, (*p_arg)->alignment); + + z = (*p_arg)->size; + if (z < sizeof (int)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; + break; + + case FFI_TYPE_STRUCT: + memcpy (argp + sizeof (int) - z, *p_argv, z); + break; + + default: + FFI_ASSERT (0); + } + z = sizeof (int); + } + else + memcpy (argp, *p_argv, z); + p_argv++; + argp += z; + } + + return struct_value_ptr; +} + +#define CIF_FLAGS_INT 1 +#define CIF_FLAGS_DINT 2 +#define CIF_FLAGS_FLOAT 4 +#define CIF_FLAGS_DOUBLE 8 +#define CIF_FLAGS_LDOUBLE 16 +#define CIF_FLAGS_POINTER 32 +#define CIF_FLAGS_STRUCT 64 + +/* Perform machine dependent cif processing */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + cif->flags = 0; + break; + + case FFI_TYPE_STRUCT: + if (cif->rtype->size > 4 && cif->rtype->size <= 8) + cif->flags = CIF_FLAGS_DINT; + else if (cif->rtype->size <= 4) + cif->flags = CIF_FLAGS_STRUCT; + else + cif->flags = 0; + break; + + case FFI_TYPE_FLOAT: + cif->flags = CIF_FLAGS_FLOAT; + break; + + case FFI_TYPE_DOUBLE: + cif->flags = CIF_FLAGS_DOUBLE; + break; + + case FFI_TYPE_LONGDOUBLE: + cif->flags = CIF_FLAGS_LDOUBLE; + break; + + case FFI_TYPE_POINTER: + cif->flags = CIF_FLAGS_POINTER; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = CIF_FLAGS_DINT; + break; + + default: + cif->flags = CIF_FLAGS_INT; + break; + } + + return FFI_OK; +} + +extern void ffi_call_SYSV (void *(*) (void *, extended_cif *), + extended_cif *, + unsigned, unsigned, unsigned, + void *, void (*fn) ()); + +void +ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return value + address then we need to make one. */ + + if (rvalue == NULL + && cif->rtype->type == FFI_TYPE_STRUCT + && cif->rtype->size > 8) + ecif.rvalue = alloca (cif->rtype->size); + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, + cif->flags, cif->rtype->size * 8, + ecif.rvalue, fn); + break; + + default: + FFI_ASSERT (0); + break; + } +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffitarget.h new file mode 100644 index 000000000..aca7facc5 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/ffitarget.h @@ -0,0 +1,47 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for Motorola 68K. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 0 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/sysv.S new file mode 100644 index 000000000..d019a377e --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/m68k/sysv.S @@ -0,0 +1,97 @@ +/* ----------------------------------------------------------------------- + sysv.S + + m68k Foreign Function Interface + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .text + + .globl ffi_call_SYSV + .type ffi_call_SYSV,@function + +ffi_call_SYSV: + link %fp,#0 + move.l %d2,-(%sp) + + | Make room for all of the new args. + sub.l 16(%fp),%sp + + | Call ffi_prep_args + move.l 12(%fp),-(%sp) + pea 4(%sp) + move.l 8(%fp),%a0 + jsr (%a0) + addq.l #8,%sp + + | Pass pointer to struct value, if any + move.l %a0,%a1 + + | Call the function + move.l 32(%fp),%a0 + jsr (%a0) + + | Remove the space we pushed for the args + add.l 16(%fp),%sp + + | Load the pointer to storage for the return value + move.l 28(%fp),%a1 + + | Load the return type code + move.l 20(%fp),%d2 + + | If the return value pointer is NULL, assume no return value. + tst.l %a1 + jbeq noretval + + btst #0,%d2 + jbeq retlongint + move.l %d0,(%a1) + jbra epilogue + +retlongint: + btst #1,%d2 + jbeq retfloat + move.l %d0,(%a1) + move.l %d1,4(%a1) + jbra epilogue + +retfloat: + btst #2,%d2 + jbeq retdouble + fmove.s %fp0,(%a1) + jbra epilogue + +retdouble: + btst #3,%d2 + jbeq retlongdouble + fmove.d %fp0,(%a1) + jbra epilogue + +retlongdouble: + btst #4,%d2 + jbeq retpointer + fmove.x %fp0,(%a1) + jbra epilogue + +retpointer: + btst #5,%d2 + jbeq retstruct + move.l %a0,(%a1) + jbra epilogue + +retstruct: + btst #6,%d2 + jbeq noretval + move.l 24(%fp),%d2 + bfins %d0,(%a1){#0,%d2} + +noretval: +epilogue: + move.l (%sp)+,%d2 + unlk %a6 + rts + .size ffi_call_SYSV,.-ffi_call_SYSV diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffi.c new file mode 100644 index 000000000..73bc95218 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffi.c @@ -0,0 +1,648 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996 Red Hat, Inc. + + MIPS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <sys/cachectl.h> + +#if _MIPS_SIM == _ABIN32 +#define FIX_ARGP \ +FFI_ASSERT(argp <= &stack[bytes]); \ +if (argp == &stack[bytes]) \ +{ \ + argp = stack; \ + ffi_stop_here(); \ +} +#else +#define FIX_ARGP +#endif + + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +static void ffi_prep_args(char *stack, + extended_cif *ecif, + int bytes, + int flags) +{ + int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + +#if _MIPS_SIM == _ABIN32 + /* If more than 8 double words are used, the remainder go + on the stack. We reorder stuff on the stack here to + support this easily. */ + if (bytes > 8 * sizeof(ffi_arg)) + argp = &stack[bytes - (8 * sizeof(ffi_arg))]; + else + argp = stack; +#else + argp = stack; +#endif + + memset(stack, 0, bytes); + +#if _MIPS_SIM == _ABIN32 + if ( ecif->cif->rstruct_flag != 0 ) +#else + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) +#endif + { + *(ffi_arg *) argp = (ffi_arg) ecif->rvalue; + argp += sizeof(ffi_arg); + FIX_ARGP; + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) + { + size_t z; + unsigned int a; + + /* Align if necessary. */ + a = (*p_arg)->alignment; + if (a < sizeof(ffi_arg)) + a = sizeof(ffi_arg); + + if ((a - 1) & (unsigned int) argp) + { + argp = (char *) ALIGN(argp, a); + FIX_ARGP; + } + + z = (*p_arg)->size; + if (z <= sizeof(ffi_arg)) + { + z = sizeof(ffi_arg); + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(ffi_arg *)argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(ffi_arg *)argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(ffi_arg *)argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(ffi_arg *)argp = *(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(ffi_arg *)argp = *(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + *(ffi_arg *)argp = *(UINT32 *)(* p_argv); + break; + + /* This can only happen with 64bit slots. */ + case FFI_TYPE_FLOAT: + *(float *) argp = *(float *)(* p_argv); + break; + + /* Handle small structures. */ + case FFI_TYPE_STRUCT: + default: + memcpy(argp, *p_argv, (*p_arg)->size); + break; + } + } + else + { +#if _MIPS_SIM == _ABIO32 + memcpy(argp, *p_argv, z); +#else + { + unsigned end = (unsigned) argp+z; + unsigned cap = (unsigned) stack+bytes; + + /* Check if the data will fit within the register space. + Handle it if it doesn't. */ + + if (end <= cap) + memcpy(argp, *p_argv, z); + else + { + unsigned portion = end - cap; + + memcpy(argp, *p_argv, portion); + argp = stack; + memcpy(argp, + (void*)((unsigned)(*p_argv)+portion), z - portion); + } + } +#endif + } + p_argv++; + argp += z; + FIX_ARGP; + } +} + +#if _MIPS_SIM == _ABIN32 + +/* The n32 spec says that if "a chunk consists solely of a double + float field (but not a double, which is part of a union), it + is passed in a floating point register. Any other chunk is + passed in an integer register". This code traverses structure + definitions and generates the appropriate flags. */ + +unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift) +{ + unsigned flags = 0; + unsigned index = 0; + + ffi_type *e; + + while (e = arg->elements[index]) + { + if (e->type == FFI_TYPE_DOUBLE) + { + flags += (FFI_TYPE_DOUBLE << *shift); + *shift += FFI_FLAG_BITS; + } + else if (e->type == FFI_TYPE_STRUCT) + flags += calc_n32_struct_flags(e, shift); + else + *shift += FFI_FLAG_BITS; + + index++; + } + + return flags; +} + +unsigned calc_n32_return_struct_flags(ffi_type *arg) +{ + unsigned flags = 0; + unsigned index = 0; + unsigned small = FFI_TYPE_SMALLSTRUCT; + ffi_type *e; + + /* Returning structures under n32 is a tricky thing. + A struct with only one or two floating point fields + is returned in $f0 (and $f2 if necessary). Any other + struct results at most 128 bits are returned in $2 + (the first 64 bits) and $3 (remainder, if necessary). + Larger structs are handled normally. */ + + if (arg->size > 16) + return 0; + + if (arg->size > 8) + small = FFI_TYPE_SMALLSTRUCT2; + + e = arg->elements[0]; + if (e->type == FFI_TYPE_DOUBLE) + flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS; + else if (e->type == FFI_TYPE_FLOAT) + flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS; + + if (flags && (e = arg->elements[1])) + { + if (e->type == FFI_TYPE_DOUBLE) + flags += FFI_TYPE_DOUBLE; + else if (e->type == FFI_TYPE_FLOAT) + flags += FFI_TYPE_FLOAT; + else + return small; + + if (flags && (arg->elements[2])) + { + /* There are three arguments and the first two are + floats! This must be passed the old way. */ + return small; + } + } + else + if (!flags) + return small; + + return flags; +} + +#endif + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + cif->flags = 0; + +#if _MIPS_SIM == _ABIO32 + /* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT + * does not have special handling for floating point args. + */ + + if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32) + { + if (cif->nargs > 0) + { + switch ((cif->arg_types)[0]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += (cif->arg_types)[0]->type; + break; + + default: + break; + } + + if (cif->nargs > 1) + { + /* Only handle the second argument if the first + is a float or double. */ + if (cif->flags) + { + switch ((cif->arg_types)[1]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS; + break; + + default: + break; + } + } + } + } + } + + /* Set the return type flag */ + + if (cif->abi == FFI_O32_SOFT_FLOAT) + { + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_DOUBLE: + cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); + break; + + case FFI_TYPE_FLOAT: + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); + break; + } + } + else + { + /* FFI_O32 */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); + break; + + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); + break; + } + } +#endif + +#if _MIPS_SIM == _ABIN32 + /* Set the flags necessary for N32 processing */ + { + unsigned shift = 0; + unsigned count = (cif->nargs < 8) ? cif->nargs : 8; + unsigned index = 0; + + unsigned struct_flags = 0; + + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + struct_flags = calc_n32_return_struct_flags(cif->rtype); + + if (struct_flags == 0) + { + /* This means that the structure is being passed as + a hidden argument */ + + shift = FFI_FLAG_BITS; + count = (cif->nargs < 7) ? cif->nargs : 7; + + cif->rstruct_flag = !0; + } + else + cif->rstruct_flag = 0; + } + else + cif->rstruct_flag = 0; + + while (count-- > 0) + { + switch ((cif->arg_types)[index]->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += ((cif->arg_types)[index]->type << shift); + shift += FFI_FLAG_BITS; + break; + + case FFI_TYPE_STRUCT: + cif->flags += calc_n32_struct_flags((cif->arg_types)[index], + &shift); + break; + + default: + shift += FFI_FLAG_BITS; + } + + index++; + } + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + { + if (struct_flags == 0) + { + /* The structure is returned through a hidden + first argument. Do nothing, 'cause FFI_TYPE_VOID + is 0 */ + } + else + { + /* The structure is returned via some tricky + mechanism */ + cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); + cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8)); + } + break; + } + + case FFI_TYPE_VOID: + /* Do nothing, 'cause FFI_TYPE_VOID is 0 */ + break; + + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8); + break; + + default: + cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); + break; + } + } +#endif + + return FFI_OK; +} + +/* Low level routine for calling O32 functions */ +extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), + extended_cif *, unsigned, + unsigned, unsigned *, void (*)()); + +/* Low level routine for calling N32 functions */ +extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), + extended_cif *, unsigned, + unsigned, unsigned *, void (*)()); + +void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + ecif.rvalue = alloca(cif->rtype->size); + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { +#if _MIPS_SIM == _ABIO32 + case FFI_O32: + case FFI_O32_SOFT_FLOAT: + ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#endif + +#if _MIPS_SIM == _ABIN32 + case FFI_N32: + ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + break; +#endif + + default: + FFI_ASSERT(0); + break; + } +} + +#if FFI_CLOSURES /* N32 not implemented yet, FFI_CLOSURES not defined */ +#if defined(FFI_MIPS_O32) +extern void ffi_closure_O32(void); +#endif /* FFI_MIPS_O32 */ + +ffi_status +ffi_prep_closure (ffi_closure *closure, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned int fn; + unsigned int ctx = (unsigned int) closure; + +#if defined(FFI_MIPS_O32) + FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT); + fn = (unsigned int) ffi_closure_O32; +#else /* FFI_MIPS_N32 */ + FFI_ASSERT(cif->abi == FFI_N32); + FFI_ASSERT(!"not implemented"); +#endif /* FFI_MIPS_O32 */ + + tramp[0] = 0x3c190000 | (fn >> 16); /* lui $25,high(fn) */ + tramp[1] = 0x37390000 | (fn & 0xffff); /* ori $25,low(fn) */ + tramp[2] = 0x3c080000 | (ctx >> 16); /* lui $8,high(ctx) */ + tramp[3] = 0x03200008; /* jr $25 */ + tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori $8,low(ctx) */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* XXX this is available on Linux, but anything else? */ + cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE); + + return FFI_OK; +} + +/* + * Decodes the arguments to a function, which will be stored on the + * stack. AR is the pointer to the beginning of the integer arguments + * (and, depending upon the arguments, some floating-point arguments + * as well). FPR is a pointer to the area where floating point + * registers have been saved, if any. + * + * RVALUE is the location where the function return value will be + * stored. CLOSURE is the prepared closure to invoke. + * + * This function should only be called from assembly, which is in + * turn called from a trampoline. + * + * Returns the function return type. + * + * Based on the similar routine for sparc. + */ +int +ffi_closure_mips_inner_O32 (ffi_closure *closure, + void *rvalue, ffi_arg *ar, + double *fpr) +{ + ffi_cif *cif; + void **avaluep; + ffi_arg *avalue; + ffi_type **arg_types; + int i, avn, argn, seen_int; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (ffi_arg)); + avaluep = alloca (cif->nargs * sizeof (ffi_arg)); + + seen_int = (cif->abi == FFI_O32_SOFT_FLOAT); + argn = 0; + + if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT) + { + rvalue = (void *) ar[0]; + argn = 1; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + while (i < avn) + { + if (i < 2 && !seen_int && + (arg_types[i]->type == FFI_TYPE_FLOAT || + arg_types[i]->type == FFI_TYPE_DOUBLE)) + { +#ifdef __MIPSEB__ + if (arg_types[i]->type == FFI_TYPE_FLOAT) + avaluep[i] = ((char *) &fpr[i]) + sizeof (float); + else +#endif + avaluep[i] = (char *) &fpr[i]; + } + else + { + if (arg_types[i]->alignment == 8 && (argn & 0x1)) + argn++; + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + avaluep[i] = &avalue[i]; + *(SINT8 *) &avalue[i] = (SINT8) ar[argn]; + break; + + case FFI_TYPE_UINT8: + avaluep[i] = &avalue[i]; + *(UINT8 *) &avalue[i] = (UINT8) ar[argn]; + break; + + case FFI_TYPE_SINT16: + avaluep[i] = &avalue[i]; + *(SINT16 *) &avalue[i] = (SINT16) ar[argn]; + break; + + case FFI_TYPE_UINT16: + avaluep[i] = &avalue[i]; + *(UINT16 *) &avalue[i] = (UINT16) ar[argn]; + break; + + default: + avaluep[i] = (char *) &ar[argn]; + break; + } + seen_int = 1; + } + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + i++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avaluep, closure->user_data); + + if (cif->abi == FFI_O32_SOFT_FLOAT) + { + switch (cif->rtype->type) + { + case FFI_TYPE_FLOAT: + return FFI_TYPE_INT; + case FFI_TYPE_DOUBLE: + return FFI_TYPE_UINT64; + default: + return cif->rtype->type; + } + } + else + { + return cif->rtype->type; + } +} + +#endif /* FFI_CLOSURES */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffitarget.h new file mode 100644 index 000000000..e61074569 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/ffitarget.h @@ -0,0 +1,167 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for MIPS. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#if !defined(_MIPS_SIM) +-- something is very wrong -- +#else +# if (_MIPS_SIM==_ABIN32 && defined(_ABIN32)) || (_MIPS_SIM==_ABI64 && defined(_ABI64)) +# define FFI_MIPS_N32 +# else +# if (_MIPS_SIM==_ABIO32 && defined(_ABIO32)) +# define FFI_MIPS_O32 +# else +-- this is an unsupported platform -- +# endif +# endif +#endif + +#ifdef FFI_MIPS_O32 +/* O32 stack frames have 32bit integer args */ +#define FFI_SIZEOF_ARG 4 +#else +/* N32 and N64 frames have 64bit integer args */ +#define FFI_SIZEOF_ARG 8 +#endif + +#define FFI_FLAG_BITS 2 + +/* SGI's strange assembler requires that we multiply by 4 rather + than shift left by FFI_FLAG_BITS */ + +#define FFI_ARGS_D FFI_TYPE_DOUBLE +#define FFI_ARGS_F FFI_TYPE_FLOAT +#define FFI_ARGS_DD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_DOUBLE +#define FFI_ARGS_FF FFI_TYPE_FLOAT * 4 + FFI_TYPE_FLOAT +#define FFI_ARGS_FD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_FLOAT +#define FFI_ARGS_DF FFI_TYPE_FLOAT * 4 + FFI_TYPE_DOUBLE + +/* Needed for N32 structure returns */ +#define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8 +#define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8 + +#if 0 +/* The SGI assembler can't handle this.. */ +#define FFI_TYPE_STRUCT_DD (( FFI_ARGS_DD ) << 4) + FFI_TYPE_STRUCT +/* (and so on) */ +#else +/* ...so we calculate these by hand! */ +#define FFI_TYPE_STRUCT_D 61 +#define FFI_TYPE_STRUCT_F 45 +#define FFI_TYPE_STRUCT_DD 253 +#define FFI_TYPE_STRUCT_FF 173 +#define FFI_TYPE_STRUCT_FD 237 +#define FFI_TYPE_STRUCT_DF 189 +#define FFI_TYPE_STRUCT_SMALL 93 +#define FFI_TYPE_STRUCT_SMALL2 109 +#endif + +#ifdef LIBFFI_ASM +#define v0 $2 +#define v1 $3 +#define a0 $4 +#define a1 $5 +#define a2 $6 +#define a3 $7 +#define a4 $8 +#define a5 $9 +#define a6 $10 +#define a7 $11 +#define t0 $8 +#define t1 $9 +#define t2 $10 +#define t3 $11 +#define t4 $12 +#define t5 $13 +#define t6 $14 +#define t7 $15 +#define t8 $24 +#define t9 $25 +#define ra $31 + +#ifdef FFI_MIPS_O32 +#define REG_L lw +#define REG_S sw +#define SUBU subu +#define ADDU addu +#define SRL srl +#define LI li +#else /* !FFI_MIPS_O32 */ +#define REG_L ld +#define REG_S sd +#define SUBU dsubu +#define ADDU daddu +#define SRL dsrl +#define LI dli +#endif /* !FFI_MIPS_O32 */ +#else /* !LIBFFI_ASM */ +#ifdef FFI_MIPS_O32 +/* O32 stack frames have 32bit integer args */ +typedef unsigned int ffi_arg __attribute__((__mode__(__SI__))); +typedef signed int ffi_sarg __attribute__((__mode__(__SI__))); +#else +/* N32 and N64 frames have 64bit integer args */ +typedef unsigned int ffi_arg __attribute__((__mode__(__DI__))); +typedef signed int ffi_sarg __attribute__((__mode__(__DI__))); +#endif + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_O32, + FFI_N32, + FFI_N64, + FFI_O32_SOFT_FLOAT, + +#ifdef FFI_MIPS_O32 +#ifdef __mips_soft_float + FFI_DEFAULT_ABI = FFI_O32_SOFT_FLOAT, +#else + FFI_DEFAULT_ABI = FFI_O32, +#endif +#else + FFI_DEFAULT_ABI = FFI_N32, +#endif + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; + +#define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag +#endif /* !LIBFFI_ASM */ + +/* ---- Definitions for closures ----------------------------------------- */ + +#if defined(FFI_MIPS_O32) +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 20 +#else +/* N32/N64 not implemented yet. */ +#define FFI_CLOSURES 0 +#endif /* FFI_MIPS_O32 */ +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/n32.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/n32.S new file mode 100644 index 000000000..358cfd7e4 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/n32.S @@ -0,0 +1,320 @@ +/* ----------------------------------------------------------------------- + n32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc. + + MIPS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +/* Only build this code if we are compiling for n32 */ + +#if defined(FFI_MIPS_N32) + +#define callback a0 +#define bytes a2 +#define flags a3 +#define raddr a4 +#define fn a5 + +#define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG ) + + .abicalls + .text + .align 2 + .globl ffi_call_N32 + .ent ffi_call_N32 +ffi_call_N32: + + # Prologue + SUBU $sp, SIZEOF_FRAME # Frame size + REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer + REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address + move $fp, $sp + + move t9, callback # callback function pointer + REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes + REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags + REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr + REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn + + # Allocate at least 4 words in the argstack + move v0, bytes + bge bytes, 4 * FFI_SIZEOF_ARG, bigger + LI v0, 4 * FFI_SIZEOF_ARG + b sixteen + + bigger: + ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned + and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry. + +sixteen: + SUBU $sp, $sp, v0 # move the stack pointer to reflect the + # arg space + + ADDU a0, $sp, 0 # 4 * FFI_SIZEOF_ARG + ADDU a3, $fp, 3 * FFI_SIZEOF_ARG + + # Call ffi_prep_args + jal t9 + + # ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args + + # Copy the stack pointer to t9 + move t9, $sp + + # Fix the stack if there are more than 8 64bit slots worth + # of arguments. + + # Load the number of bytes + REG_L t6, 2*FFI_SIZEOF_ARG($fp) + + # Is it bigger than 8 * FFI_SIZEOF_ARG? + dadd t7, $0, 8 * FFI_SIZEOF_ARG + dsub t8, t6, t7 + bltz t8, loadregs + + add t9, t9, t8 + +loadregs: + + REG_L t4, 3*FFI_SIZEOF_ARG($fp) # load the flags word + add t6, t4, 0 # and copy it into t6 + + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg1_floatp + REG_L a0, 0*FFI_SIZEOF_ARG(t9) + b arg1_next +arg1_floatp: + bne t4, FFI_TYPE_FLOAT, arg1_doublep + l.s $f12, 0*FFI_SIZEOF_ARG(t9) + b arg1_next +arg1_doublep: + l.d $f12, 0*FFI_SIZEOF_ARG(t9) +arg1_next: + + add t4, t6, 0 + SRL t4, 1*FFI_FLAG_BITS + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg2_floatp + REG_L a1, 1*FFI_SIZEOF_ARG(t9) + b arg2_next +arg2_floatp: + bne t4, FFI_TYPE_FLOAT, arg2_doublep + l.s $f13, 1*FFI_SIZEOF_ARG(t9) + b arg2_next +arg2_doublep: + l.d $f13, 1*FFI_SIZEOF_ARG(t9) +arg2_next: + + add t4, t6, 0 + SRL t4, 2*FFI_FLAG_BITS + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg3_floatp + REG_L a2, 2*FFI_SIZEOF_ARG(t9) + b arg3_next +arg3_floatp: + bne t4, FFI_TYPE_FLOAT, arg3_doublep + l.s $f14, 2*FFI_SIZEOF_ARG(t9) + b arg3_next +arg3_doublep: + l.d $f14, 2*FFI_SIZEOF_ARG(t9) +arg3_next: + + add t4, t6, 0 + SRL t4, 3*FFI_FLAG_BITS + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg4_floatp + REG_L a3, 3*FFI_SIZEOF_ARG(t9) + b arg4_next +arg4_floatp: + bne t4, FFI_TYPE_FLOAT, arg4_doublep + l.s $f15, 3*FFI_SIZEOF_ARG(t9) + b arg4_next +arg4_doublep: + l.d $f15, 3*FFI_SIZEOF_ARG(t9) +arg4_next: + + add t4, t6, 0 + SRL t4, 4*FFI_FLAG_BITS + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg5_floatp + REG_L a4, 4*FFI_SIZEOF_ARG(t9) + b arg5_next +arg5_floatp: + bne t4, FFI_TYPE_FLOAT, arg5_doublep + l.s $f16, 4*FFI_SIZEOF_ARG(t9) + b arg5_next +arg5_doublep: + l.d $f16, 4*FFI_SIZEOF_ARG(t9) +arg5_next: + + add t4, t6, 0 + SRL t4, 5*FFI_FLAG_BITS + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg6_floatp + REG_L a5, 5*FFI_SIZEOF_ARG(t9) + b arg6_next +arg6_floatp: + bne t4, FFI_TYPE_FLOAT, arg6_doublep + l.s $f17, 5*FFI_SIZEOF_ARG(t9) + b arg6_next +arg6_doublep: + l.d $f17, 5*FFI_SIZEOF_ARG(t9) +arg6_next: + + add t4, t6, 0 + SRL t4, 6*FFI_FLAG_BITS + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg7_floatp + REG_L a6, 6*FFI_SIZEOF_ARG(t9) + b arg7_next +arg7_floatp: + bne t4, FFI_TYPE_FLOAT, arg7_doublep + l.s $f18, 6*FFI_SIZEOF_ARG(t9) + b arg7_next +arg7_doublep: + l.d $f18, 6*FFI_SIZEOF_ARG(t9) +arg7_next: + + add t4, t6, 0 + SRL t4, 7*FFI_FLAG_BITS + and t4, ((1<<FFI_FLAG_BITS)-1) + bnez t4, arg8_floatp + REG_L a7, 7*FFI_SIZEOF_ARG(t9) + b arg8_next +arg8_floatp: + bne t4, FFI_TYPE_FLOAT, arg8_doublep + l.s $f19, 7*FFI_SIZEOF_ARG(t9) + b arg8_next +arg8_doublep: + l.d $f19, 7*FFI_SIZEOF_ARG(t9) +arg8_next: + +callit: + # Load the function pointer + REG_L t9, 5*FFI_SIZEOF_ARG($fp) + + # If the return value pointer is NULL, assume no return value. + REG_L t5, 4*FFI_SIZEOF_ARG($fp) + beqz t5, noretval + + # Shift the return type flag over + SRL t6, 8*FFI_FLAG_BITS + + bne t6, FFI_TYPE_INT, retfloat + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + REG_S v0, 0(t4) + b epilogue + +retfloat: + bne t6, FFI_TYPE_FLOAT, retdouble + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.s $f0, 0(t4) + b epilogue + +retdouble: + bne t6, FFI_TYPE_DOUBLE, retstruct_d + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.d $f0, 0(t4) + b epilogue + +retstruct_d: + bne t6, FFI_TYPE_STRUCT_D, retstruct_f + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.d $f0, 0(t4) + b epilogue + +retstruct_f: + bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.s $f0, 0(t4) + b epilogue + +retstruct_d_d: + bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.d $f0, 0(t4) + s.d $f2, 8(t4) + b epilogue + +retstruct_f_f: + bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.s $f0, 0(t4) + s.s $f2, 4(t4) + b epilogue + +retstruct_d_f: + bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.d $f0, 0(t4) + s.s $f2, 8(t4) + b epilogue + +retstruct_f_d: + bne t6, FFI_TYPE_STRUCT_FD, retstruct_small + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + s.s $f0, 0(t4) + s.d $f2, 8(t4) + b epilogue + +retstruct_small: + bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2 + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + REG_S v0, 0(t4) + b epilogue + +retstruct_small2: + bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct + jal t9 + REG_L t4, 4*FFI_SIZEOF_ARG($fp) + REG_S v0, 0(t4) + REG_S v1, 8(t4) + b epilogue + +retstruct: +noretval: + jal t9 + + # Epilogue +epilogue: + move $sp, $fp + REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer + REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address + ADDU $sp, SIZEOF_FRAME # Fix stack pointer + j ra + + .end ffi_call_N32 + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/o32.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/o32.S new file mode 100644 index 000000000..63f3d1463 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/mips/o32.S @@ -0,0 +1,377 @@ +/* ----------------------------------------------------------------------- + o32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc. + + MIPS Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +/* Only build this code if we are compiling for o32 */ + +#if defined(FFI_MIPS_O32) + +#define callback a0 +#define bytes a2 +#define flags a3 + +#define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG) +#define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG) +#define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG) +#define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG) + + .abicalls + .text + .align 2 + .globl ffi_call_O32 + .ent ffi_call_O32 +ffi_call_O32: +$LFB0: + # Prologue + SUBU $sp, SIZEOF_FRAME # Frame size +$LCFI0: + REG_S $fp, FP_OFF($sp) # Save frame pointer +$LCFI1: + REG_S ra, RA_OFF($sp) # Save return address +$LCFI2: + move $fp, $sp + +$LCFI3: + move t9, callback # callback function pointer + REG_S flags, A3_OFF($fp) # flags + + # Allocate at least 4 words in the argstack + LI v0, 4 * FFI_SIZEOF_ARG + blt bytes, v0, sixteen + + ADDU v0, bytes, 7 # make sure it is aligned + and v0, -8 # to an 8 byte boundry + +sixteen: + SUBU $sp, v0 # move the stack pointer to reflect the + # arg space + + ADDU a0, $sp, 4 * FFI_SIZEOF_ARG + + jalr t9 + + REG_L t0, A3_OFF($fp) # load the flags word + SRL t2, t0, 4 # shift our arg info + and t0, ((1<<4)-1) # mask out the return type + + ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args + + bnez t0, pass_d # make it quick for int + REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the + REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs. + REG_L a2, 2*FFI_SIZEOF_ARG($sp) + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_d: + bne t0, FFI_ARGS_D, pass_f + l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_f: + bne t0, FFI_ARGS_F, pass_d_d + l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float + REG_L a2, 2*FFI_SIZEOF_ARG($sp) + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_d_d: + bne t0, FFI_ARGS_DD, pass_f_f + l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles + b call_it + +pass_f_f: + bne t0, FFI_ARGS_FF, pass_d_f + l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats + REG_L a2, 2*FFI_SIZEOF_ARG($sp) + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_d_f: + bne t0, FFI_ARGS_DF, pass_f_d + l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float + REG_L a3, 3*FFI_SIZEOF_ARG($sp) + b call_it + +pass_f_d: + # assume that the only other combination must be float then double + # bne t0, FFI_ARGS_F_D, call_it + l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args + l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float + +call_it: + # Load the function pointer + REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp) + + # If the return value pointer is NULL, assume no return value. + REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + beqz t1, noretval + + bne t2, FFI_TYPE_INT, retlonglong + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + REG_S v0, 0(t0) + b epilogue + +retlonglong: + # Really any 64-bit int, signed or not. + bne t2, FFI_TYPE_UINT64, retfloat + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + REG_S v1, 4(t0) + REG_S v0, 0(t0) + b epilogue + +retfloat: + bne t2, FFI_TYPE_FLOAT, retdouble + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + s.s $f0, 0(t0) + b epilogue + +retdouble: + bne t2, FFI_TYPE_DOUBLE, noretval + jalr t9 + REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) + s.d $f0, 0(t0) + b epilogue + +noretval: + jalr t9 + + # Epilogue +epilogue: + move $sp, $fp + REG_L $fp, FP_OFF($sp) # Restore frame pointer + REG_L ra, RA_OFF($sp) # Restore return address + ADDU $sp, SIZEOF_FRAME # Fix stack pointer + j ra + +$LFE0: + .end ffi_call_O32 + + +/* ffi_closure_O32. Expects address of the passed-in ffi_closure + in t0. Stores any arguments passed in registers onto the + stack, then calls ffi_closure_mips_inner_O32, which + then decodes them. + + Stack layout: + + 14 - Start of parameters, original sp + 13 - ra save + 12 - fp save + 11 - $16 (s0) save + 10 - cprestore + 9 - return value high (v1) + 8 - return value low (v0) + 7 - f14 (le high, be low) + 6 - f14 (le low, be high) + 5 - f12 (le high, be low) + 4 - f12 (le low, be high) + 3 - Called function a3 save + 2 - Called function a2 save + 1 - Called function a1 save + 0 - Called function a0 save our sp, fp point here + */ + +#define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG) +#define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG) +#define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG) +#define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG) +#define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG) +#define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG) +#define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG) +#define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG) +#define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG) +#define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG) +#define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG) +#define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG) +#define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG) +#define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG) +#define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG) + + .text + .align 2 + .globl ffi_closure_O32 + .ent ffi_closure_O32 +ffi_closure_O32: +$LFB1: + # Prologue + .frame $fp, SIZEOF_FRAME2, ra + .set noreorder + .cpload t9 + .set reorder + SUBU $sp, SIZEOF_FRAME2 + .cprestore GP_OFF2 +$LCFI4: + REG_S $16, S0_OFF2($sp) # Save s0 + REG_S $fp, FP_OFF2($sp) # Save frame pointer + REG_S ra, RA_OFF2($sp) # Save return address +$LCFI6: + move $fp, $sp + +$LCFI7: + # Store all possible argument registers. If there are more than + # four arguments, then they are stored above where we put a3. + REG_S a0, A0_OFF2($fp) + REG_S a1, A1_OFF2($fp) + REG_S a2, A2_OFF2($fp) + REG_S a3, A3_OFF2($fp) + + # Load ABI enum to s0 + REG_L $16, 20($8) # cif pointer follows tramp. + REG_L $16, 0($16) # abi is first member. + + li $13, 1 # FFI_O32 + bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT + + # Store all possible float/double registers. + s.d $f12, FA_0_0_OFF2($fp) + s.d $f14, FA_1_0_OFF2($fp) +1: + # Call ffi_closure_mips_inner_O32 to do the work. + la t9, ffi_closure_mips_inner_O32 + move a0, $8 # Pointer to the ffi_closure + addu a1, $fp, V0_OFF2 + addu a2, $fp, A0_OFF2 + addu a3, $fp, FA_0_0_OFF2 + jalr t9 + + # Load the return value into the appropriate register. + move $8, $2 + li $9, FFI_TYPE_VOID + beq $8, $9, closure_done + + li $13, 1 # FFI_O32 + bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT + + li $9, FFI_TYPE_FLOAT + l.s $f0, V0_OFF2($fp) + beq $8, $9, closure_done + + li $9, FFI_TYPE_DOUBLE + l.d $f0, V0_OFF2($fp) + beq $8, $9, closure_done +1: + REG_L $3, V1_OFF2($fp) + REG_L $2, V0_OFF2($fp) + +closure_done: + # Epilogue + move $sp, $fp + REG_L $16, S0_OFF2($sp) # Restore s0 + REG_L $fp, FP_OFF2($sp) # Restore frame pointer + REG_L ra, RA_OFF2($sp) # Restore return address + ADDU $sp, SIZEOF_FRAME2 + j ra +$LFE1: + .end ffi_closure_O32 + +/* DWARF-2 unwind info. */ + + .section .eh_frame,"a",@progbits +$Lframe0: + .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry +$LSCIE0: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 4 # CIE Data Alignment Factor + .byte 0x1f # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x00 # FDE Encoding (absptr) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1d + .uleb128 0x0 + .align 2 +$LECIE0: +$LSFDE0: + .4byte $LEFDE0-$LASFDE0 # FDE Length +$LASFDE0: + .4byte $LASFDE0-$Lframe0 # FDE CIE offset + .4byte $LFB0 # FDE initial location + .4byte $LFE0-$LFB0 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI0-$LFB0 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x18 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI2-$LCFI0 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1e # $fp + .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1f # $ra + .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI3-$LCFI2 + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x18 + .align 2 +$LEFDE0: +$LSFDE1: + .4byte $LEFDE1-$LASFDE1 # FDE Length +$LASFDE1: + .4byte $LASFDE1-$Lframe0 # FDE CIE offset + .4byte $LFB1 # FDE initial location + .4byte $LFE1-$LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI4-$LFB1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x38 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI6-$LCFI4 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x10 # $16 + .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1e # $fp + .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x1f # $ra + .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) + .byte 0x4 # DW_CFA_advance_loc4 + .4byte $LCFI7-$LCFI6 + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x38 + .align 2 +$LEFDE1: + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffi.c new file mode 100644 index 000000000..f6264dbc5 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffi.c @@ -0,0 +1,625 @@ +/* ----------------------------------------------------------------------- + ffi.c - (c) 2003-2004 Randolph Chung <tausq@debian.org> + + HPPA Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <stdio.h> + +#define ROUND_UP(v, a) (((size_t)(v) + (a) - 1) & ~((a) - 1)) +#define ROUND_DOWN(v, a) (((size_t)(v) - (a) + 1) & ~((a) - 1)) +#define MIN_STACK_SIZE 64 +#define FIRST_ARG_SLOT 9 +#define DEBUG_LEVEL 0 + +#define fldw(addr, fpreg) asm volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg) +#define fstw(fpreg, addr) asm volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr)) +#define fldd(addr, fpreg) asm volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg) +#define fstd(fpreg, addr) asm volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr)) + +#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0) + +static inline int ffi_struct_type(ffi_type *t) +{ + size_t sz = t->size; + + /* Small structure results are passed in registers, + larger ones are passed by pointer. */ + + if (sz <= 1) + return FFI_TYPE_UINT8; + else if (sz == 2) + return FFI_TYPE_UINT16; + else if (sz == 3) + return FFI_TYPE_SMALL_STRUCT3; + else if (sz == 4) + return FFI_TYPE_UINT32; + else if (sz == 5) + return FFI_TYPE_SMALL_STRUCT5; + else if (sz == 6) + return FFI_TYPE_SMALL_STRUCT6; + else if (sz == 7) + return FFI_TYPE_SMALL_STRUCT7; + else if (sz <= 8) + return FFI_TYPE_UINT64; + else + return FFI_TYPE_STRUCT; /* else, we pass it by pointer. */ +} + +/* PA has a downward growing stack, which looks like this: + + Offset + [ Variable args ] + SP = (4*(n+9)) arg word N + ... + SP-52 arg word 4 + [ Fixed args ] + SP-48 arg word 3 + SP-44 arg word 2 + SP-40 arg word 1 + SP-36 arg word 0 + [ Frame marker ] + ... + SP-20 RP + SP-4 previous SP + + First 4 non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23 + First 2 non-FP 64-bit args are passed in register pairs, starting + on an even numbered register (i.e. r26/r25 and r24+r23) + First 4 FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L + First 2 FP 64-bit arguments are passed in fr5 and fr7 + The rest are passed on the stack starting at SP-52, but 64-bit + arguments need to be aligned to an 8-byte boundary + + This means we can have holes either in the register allocation, + or in the stack. */ + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments + + The following code will put everything into the stack frame + (which was allocated by the asm routine), and on return + the asm routine will load the arguments that should be + passed by register into the appropriate registers + + NOTE: We load floating point args in this function... that means we + assume gcc will not mess with fp regs in here. */ + +/*@-exportheader@*/ +void ffi_prep_args_LINUX(UINT32 *stack, extended_cif *ecif, unsigned bytes) +/*@=exportheader@*/ +{ + register unsigned int i; + register ffi_type **p_arg; + register void **p_argv; + unsigned int slot = FIRST_ARG_SLOT - 1; + char *dest_cpy; + + debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack, ecif, bytes); + + p_arg = ecif->cif->arg_types; + p_argv = ecif->avalue; + + for (i = 0; i < ecif->cif->nargs; i++) + { + int type = (*p_arg)->type; + + switch (type) + { + case FFI_TYPE_SINT8: + slot++; + *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv); + break; + + case FFI_TYPE_UINT8: + slot++; + *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv); + break; + + case FFI_TYPE_SINT16: + slot++; + *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT16: + slot++; + *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + slot++; + debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv), slot); + *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv); + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + slot += 2; + if (slot & 1) + slot++; + + *(UINT32 *)(stack - slot) = (*(UINT64 *)(*p_argv)) >> 32; + *(UINT32 *)(stack - slot + 1) = (*(UINT64 *)(*p_argv)) & 0xffffffffUL; + break; + + case FFI_TYPE_FLOAT: + /* First 4 args go in fr4L - fr7L */ + slot++; + switch (slot - FIRST_ARG_SLOT) + { + case 0: fldw(*p_argv, fr4); break; + case 1: fldw(*p_argv, fr5); break; + case 2: fldw(*p_argv, fr6); break; + case 3: fldw(*p_argv, fr7); break; + default: + /* Other ones are just passed on the stack. */ + debug(3, "Storing UINT32(float) in slot %u\n", slot); + *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv); + break; + } + break; + + case FFI_TYPE_DOUBLE: + slot += 2; + if (slot & 1) + slot++; + switch (slot - FIRST_ARG_SLOT + 1) + { + /* First 2 args go in fr5, fr7 */ + case 2: fldd(*p_argv, fr5); break; + case 4: fldd(*p_argv, fr7); break; + default: + debug(3, "Storing UINT64(double) at slot %u\n", slot); + *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv); + break; + } + break; + + case FFI_TYPE_STRUCT: + + /* Structs smaller or equal than 4 bytes are passed in one + register. Structs smaller or equal 8 bytes are passed in two + registers. Larger structures are passed by pointer. */ + + if((*p_arg)->size <= 4) + { + slot++; + dest_cpy = (char *)(stack - slot); + dest_cpy += 4 - (*p_arg)->size; + memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size); + } + else if ((*p_arg)->size <= 8) + { + slot += 2; + if (slot & 1) + slot++; + dest_cpy = (char *)(stack - slot); + dest_cpy += 8 - (*p_arg)->size; + memcpy((char *)dest_cpy, (char *)*p_argv, (*p_arg)->size); + } + else + { + slot++; + *(UINT32 *)(stack - slot) = (UINT32)(*p_argv); + } + break; + + default: + FFI_ASSERT(0); + } + + p_arg++; + p_argv++; + } + + /* Make sure we didn't mess up and scribble on the stack. */ + { + int n; + + debug(5, "Stack setup:\n"); + for (n = 0; n < (bytes + 3) / 4; n++) + { + if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); } + debug(5, "%08x ", *(stack - n)); + } + debug(5, "\n"); + } + + FFI_ASSERT(slot * 4 <= bytes); + + return; +} + +static void ffi_size_stack_LINUX(ffi_cif *cif) +{ + ffi_type **ptr; + int i; + int z = 0; /* # stack slots */ + + for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++) + { + int type = (*ptr)->type; + + switch (type) + { + case FFI_TYPE_DOUBLE: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + z += 2 + (z & 1); /* must start on even regs, so we may waste one */ + break; + + case FFI_TYPE_STRUCT: + z += 1; /* pass by ptr, callee will copy */ + break; + + default: /* <= 32-bit values */ + z++; + } + } + + /* We can fit up to 6 args in the default 64-byte stack frame, + if we need more, we need more stack. */ + if (z <= 6) + cif->bytes = MIN_STACK_SIZE; /* min stack size */ + else + cif->bytes = 64 + ROUND_UP((z - 6) * sizeof(UINT32), MIN_STACK_SIZE); + + debug(3, "Calculated stack size is %u bytes\n", cif->bytes); +} + +/* Perform machine dependent cif processing. */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + /* For the return type we have to check the size of the structures. + If the size is smaller or equal 4 bytes, the result is given back + in one register. If the size is smaller or equal 8 bytes than we + return the result in two registers. But if the size is bigger than + 8 bytes, we work with pointers. */ + cif->flags = ffi_struct_type(cif->rtype); + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + cif->flags = FFI_TYPE_UINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + /* Lucky us, because of the unique PA ABI we get to do our + own stack sizing. */ + switch (cif->abi) + { + case FFI_LINUX: + ffi_size_stack_LINUX(cif); + break; + + default: + FFI_ASSERT(0); + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_LINUX(void (*)(UINT32 *, extended_cif *, unsigned), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return + value address then we need to make one. */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_LINUX: + /*@-usedef@*/ + debug(2, "Calling ffi_call_LINUX: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn); + ffi_call_LINUX(ffi_prep_args_LINUX, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + + default: + FFI_ASSERT(0); + break; + } +} + +#if FFI_CLOSURES +/* This is more-or-less an inverse of ffi_call -- we have arguments on + the stack, and we need to fill them into a cif structure and invoke + the user function. This really ought to be in asm to make sure + the compiler doesn't do things we don't expect. */ +UINT32 ffi_closure_inner_LINUX(ffi_closure *closure, UINT32 *stack) +{ + ffi_cif *cif; + void **avalue; + void *rvalue; + UINT32 ret[2]; /* function can return up to 64-bits in registers */ + ffi_type **p_arg; + char *tmp; + int i, avn, slot = FIRST_ARG_SLOT - 1; + register UINT32 r28 asm("r28"); + + cif = closure->cif; + + /* If returning via structure, callee will write to our pointer. */ + if (cif->flags == FFI_TYPE_STRUCT) + rvalue = (void *)r28; + else + rvalue = &ret[0]; + + avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG); + avn = cif->nargs; + p_arg = cif->arg_types; + + for (i = 0; i < avn; i++) + { + int type = (*p_arg)->type; + + switch (type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + slot++; + avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + slot += 2; + if (slot & 1) + slot++; + avalue[i] = (void *)(stack - slot); + break; + + case FFI_TYPE_FLOAT: + slot++; + switch (slot - FIRST_ARG_SLOT) + { + case 0: fstw(fr4, (void *)(stack - slot)); break; + case 1: fstw(fr5, (void *)(stack - slot)); break; + case 2: fstw(fr6, (void *)(stack - slot)); break; + case 3: fstw(fr7, (void *)(stack - slot)); break; + } + avalue[i] = (void *)(stack - slot); + break; + + case FFI_TYPE_DOUBLE: + slot += 2; + if (slot & 1) + slot++; + switch (slot - FIRST_ARG_SLOT + 1) + { + case 2: fstd(fr5, (void *)(stack - slot)); break; + case 4: fstd(fr7, (void *)(stack - slot)); break; + } + avalue[i] = (void *)(stack - slot); + break; + + case FFI_TYPE_STRUCT: + /* Structs smaller or equal than 4 bytes are passed in one + register. Structs smaller or equal 8 bytes are passed in two + registers. Larger structures are passed by pointer. */ + if((*p_arg)->size <= 4) { + slot++; + avalue[i] = (void *)(stack - slot) + sizeof(UINT32) - + (*p_arg)->size; + } else if ((*p_arg)->size <= 8) { + slot += 2; + if (slot & 1) + slot++; + avalue[i] = (void *)(stack - slot) + sizeof(UINT64) - + (*p_arg)->size; + } else { + slot++; + avalue[i] = (void *) *(stack - slot); + } + break; + + default: + FFI_ASSERT(0); + } + + p_arg++; + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0], ret[1]); + + /* Store the result */ + switch (cif->flags) + { + case FFI_TYPE_UINT8: + *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24); + break; + case FFI_TYPE_SINT8: + *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24); + break; + case FFI_TYPE_UINT16: + *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16); + break; + case FFI_TYPE_SINT16: + *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16); + break; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + *(stack - FIRST_ARG_SLOT) = ret[0]; + break; + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + *(stack - FIRST_ARG_SLOT) = ret[0]; + *(stack - FIRST_ARG_SLOT - 1) = ret[1]; + break; + + case FFI_TYPE_DOUBLE: + fldd(rvalue, fr4); + break; + + case FFI_TYPE_FLOAT: + fldw(rvalue, fr4); + break; + + case FFI_TYPE_STRUCT: + /* Don't need a return value, done by caller. */ + break; + + case FFI_TYPE_SMALL_STRUCT3: + tmp = (void*)(stack - FIRST_ARG_SLOT); + tmp += 4 - cif->rtype->size; + memcpy((void*)tmp, &ret[0], cif->rtype->size); + break; + + case FFI_TYPE_SMALL_STRUCT5: + case FFI_TYPE_SMALL_STRUCT6: + case FFI_TYPE_SMALL_STRUCT7: + { + unsigned int ret2[2]; + int off; + + /* Right justify ret[0] and ret[1] */ + switch (cif->flags) + { + case FFI_TYPE_SMALL_STRUCT5: off = 3; break; + case FFI_TYPE_SMALL_STRUCT6: off = 2; break; + case FFI_TYPE_SMALL_STRUCT7: off = 1; break; + default: off = 0; break; + } + + memset (ret2, 0, sizeof (ret2)); + memcpy ((char *)ret2 + off, ret, 8 - off); + + *(stack - FIRST_ARG_SLOT) = ret2[0]; + *(stack - FIRST_ARG_SLOT - 1) = ret2[1]; + } + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_VOID: + break; + + default: + debug(0, "assert with cif->flags: %d\n",cif->flags); + FFI_ASSERT(0); + break; + } + return FFI_OK; +} + +/* Fill in a closure to refer to the specified fun and user_data. + cif specifies the argument and result types for fun. + The cif must already be prep'ed. */ + +void ffi_closure_LINUX(void); + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + UINT32 *tramp = (UINT32 *)(closure->tramp); + + FFI_ASSERT (cif->abi == FFI_LINUX); + + /* Make a small trampoline that will branch to our + handler function. Use PC-relative addressing. */ + + tramp[0] = 0xeaa00000; /* b,l .+8, %r21 ; %r21 <- pc+8 */ + tramp[1] = 0xd6a01c1e; /* depi 0,31,2, %r21 ; mask priv bits */ + tramp[2] = 0x4aa10028; /* ldw 20(%r21), %r1 ; load plabel */ + tramp[3] = 0x36b53ff1; /* ldo -8(%r21), %r21 ; get closure addr */ + tramp[4] = 0x0c201096; /* ldw 0(%r1), %r22 ; address of handler */ + tramp[5] = 0xeac0c000; /* bv %r0(%r22) ; branch to handler */ + tramp[6] = 0x0c281093; /* ldw 4(%r1), %r19 ; GP of handler */ + tramp[7] = ((UINT32)(ffi_closure_LINUX) & ~2); + + /* Flush d/icache -- have to flush up 2 two lines because of + alignment. */ + asm volatile ( + "fdc 0(%0)\n" + "fdc %1(%0)\n" + "fic 0(%%sr4, %0)\n" + "fic %1(%%sr4, %0)\n" + "sync\n" + : : "r"((unsigned long)tramp & ~31), "r"(32 /* stride */)); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffitarget.h new file mode 100644 index 000000000..562069623 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/ffitarget.h @@ -0,0 +1,59 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for hppa. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + +#ifdef PA + FFI_LINUX, + FFI_DEFAULT_ABI = FFI_LINUX, +#endif + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#define FFI_TRAMPOLINE_SIZE 32 + +#define FFI_TYPE_SMALL_STRUCT3 -1 +#define FFI_TYPE_SMALL_STRUCT5 -2 +#define FFI_TYPE_SMALL_STRUCT6 -3 +#define FFI_TYPE_SMALL_STRUCT7 -4 +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/linux.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/linux.S new file mode 100644 index 000000000..267cff7b8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/pa/linux.S @@ -0,0 +1,307 @@ +/* ----------------------------------------------------------------------- + linux.S - (c) 2003-2004 Randolph Chung <tausq@debian.org> + + HPPA Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .text + .level 1.1 + .align 4 + + /* void ffi_call_LINUX(void (*)(char *, extended_cif *), + extended_cif *ecif, + unsigned bytes, + unsigned flags, + unsigned *rvalue, + void (*fn)()); + */ + + .export ffi_call_LINUX,code + .import ffi_prep_args_LINUX,code + + .type ffi_call_LINUX, @function +.LFB1: +ffi_call_LINUX: + .proc + .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4 + .entry + stw %rp, -20(%sp) + copy %r3, %r1 +.LCFI11: + + copy %sp, %r3 +.LCFI12: + + /* Setup the stack for calling prep_args... + We want the stack to look like this: + + [ Previous stack ] <- %r3 + + [ 64-bytes register save area ] <- %r4 + + [ Stack space for actual call, passed as ] <- %arg0 + [ arg0 to ffi_prep_args_LINUX ] + + [ Stack for calling prep_args ] <- %sp + */ + + stwm %r1, 64(%sp) + stw %r4, 12(%r3) +.LCFI13: + copy %sp, %r4 + + addl %arg2, %r4, %arg0 /* arg stack */ + stw %arg3, -48(%r3) /* save flags; we need it later */ + + /* Call prep_args: + %arg0(stack) -- set up above + %arg1(ecif) -- same as incoming param + %arg2(bytes) -- same as incoming param */ + bl ffi_prep_args_LINUX,%r2 + ldo 64(%arg0), %sp + ldo -64(%sp), %sp + + /* now %sp should point where %arg0 was pointing. */ + + /* Load the arguments that should be passed in registers + The fp args were loaded by the prep_args function. */ + ldw -36(%sp), %arg0 + ldw -40(%sp), %arg1 + ldw -44(%sp), %arg2 + ldw -48(%sp), %arg3 + + /* in case the function is going to return a structure + we need to give it a place to put the result. */ + ldw -52(%r3), %ret0 /* %ret0 <- rvalue */ + ldw -56(%r3), %r22 /* %r22 <- function to call */ + bl $$dyncall, %r31 /* Call the user function */ + copy %r31, %rp + + /* Prepare to store the result; we need to recover flags and rvalue. */ + ldw -48(%r3), %r21 /* r21 <- flags */ + ldw -52(%r3), %r20 /* r20 <- rvalue */ + + /* Store the result according to the return type. */ + +checksmst3: + comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, checksmst567 + /* 3-byte structs are returned in ret0 as ??xxyyzz. Shift + left 8 bits to write to the result structure. */ + zdep %ret0, 23, 24, %r22 + b done + stw %r22, 0(%r20) + +checksmst567: + /* 5-7 byte values are returned right justified: + ret0 ret1 + 5: ??????aa bbccddee + 6: ????aabb ccddeeff + 7: ??aabbcc ddeeffgg + + To store this in the result, write the first 4 bytes into a temp + register using shrpw (t1 = aabbccdd), followed by a rotation of + ret1: + + ret0 ret1 ret1 + 5: ??????aa bbccddee -> eebbccdd (rotate 8) + 6: ????aabb ccddeeff -> eeffccdd (rotate 16) + 7: ??aabbcc ddeeffgg -> eeffggdd (rotate 24) + + then we write (t1, ret1) into the result. */ + + addi,<> -FFI_TYPE_SMALL_STRUCT5,%r21,%r0 + ldi 8, %r22 + addi,<> -FFI_TYPE_SMALL_STRUCT6,%r21,%r0 + ldi 16, %r22 + addi,<> -FFI_TYPE_SMALL_STRUCT7,%r21,%r0 + ldi 24, %r22 + + /* This relies on all the FFI_TYPE_*_STRUCT* defines being <0 */ + cmpib,<=,n 0, %r21, checkint8 + mtsar %r22 + + shrpw %ret0, %ret1, %sar, %ret0 /* ret0 = aabbccdd */ + shrpw %ret1, %ret1, %sar, %ret1 /* rotate ret1 */ + + stw %ret0, 0(%r20) + b done + stw %ret1, 4(%r20) + +checkint8: + comib,<>,n FFI_TYPE_UINT8, %r21, checkint16 + b done + stb %ret0, 0(%r20) + +checkint16: + comib,<>,n FFI_TYPE_UINT16, %r21, checkint32 + b done + sth %ret0, 0(%r20) + +checkint32: + comib,<>,n FFI_TYPE_UINT32, %r21, checkint + b done + stw %ret0, 0(%r20) + +checkint: + comib,<>,n FFI_TYPE_INT, %r21, checkll + b done + stw %ret0, 0(%r20) + +checkll: + comib,<>,n FFI_TYPE_UINT64, %r21, checkdbl + stw %ret0, 0(%r20) + b done + stw %ret1, 4(%r20) + +checkdbl: + comib,<>,n FFI_TYPE_DOUBLE, %r21, checkfloat + b done + fstd %fr4,0(%r20) + +checkfloat: + comib,<>,n FFI_TYPE_FLOAT, %r21, done + fstw %fr4L,0(%r20) + + /* structure returns are either handled by one of the + INT/UINT64 cases above, or, if passed by pointer, + is handled by the callee. */ + +done: + /* all done, return */ + copy %r4, %sp /* pop arg stack */ + ldw 12(%r3), %r4 + ldwm -64(%sp), %r3 /* .. and pop stack */ + ldw -20(%sp), %rp + bv %r0(%rp) + nop + .exit + .procend +.LFE1: + + /* void ffi_closure_LINUX(void); + Called with closure argument in %r21 */ + .export ffi_closure_LINUX,code + .import ffi_closure_inner_LINUX,code + + .type ffi_closure_LINUX, @function +.LFB2: +ffi_closure_LINUX: + .proc + .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 + .entry + + stw %rp, -20(%sp) +.LCFI20: + copy %r3, %r1 +.LCFI21: + copy %sp, %r3 +.LCFI22: + stwm %r1, 64(%sp) + + /* Put arguments onto the stack and call ffi_closure_inner. */ + stw %arg0, -36(%r3) + stw %arg1, -40(%r3) + stw %arg2, -44(%r3) + stw %arg3, -48(%r3) + + copy %r21, %arg0 + bl ffi_closure_inner_LINUX, %r2 + copy %r3, %arg1 + + ldwm -64(%sp), %r3 + ldw -20(%sp), %rp + ldw -36(%sp), %ret0 + bv %r0(%r2) + ldw -40(%sp), %ret1 + + .exit + .procend +.LFE2: + + .section ".eh_frame",EH_FRAME_FLAGS,@progbits +.Lframe1: + .word .LECIE1-.LSCIE1 ;# Length of Common Information Entry +.LSCIE1: + .word 0x0 ;# CIE Identifier Tag + .byte 0x1 ;# CIE Version + .ascii "\0" ;# CIE Augmentation + .uleb128 0x1 ;# CIE Code Alignment Factor + .sleb128 4 ;# CIE Data Alignment Factor + .byte 0x2 ;# CIE RA Column + .byte 0xc ;# DW_CFA_def_cfa + .uleb128 0x1e + .uleb128 0x0 + .align 4 +.LECIE1: +.LSFDE1: + .word .LEFDE1-.LASFDE1 ;# FDE Length +.LASFDE1: + .word .LASFDE1-.Lframe1 ;# FDE CIE offset + .word .LFB1 ;# FDE initial location + .word .LFE1-.LFB1 ;# FDE address range + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI11-.LFB1 + .byte 0x83 ;# DW_CFA_offset, column 0x3 + .uleb128 0x0 + .byte 0x11 ;# DW_CFA_offset_extended_sf; save r2 at [r30-20] + .uleb128 0x2 + .sleb128 -5 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI12-.LCFI11 + .byte 0xd ;# DW_CFA_def_cfa_register = r3 + .uleb128 0x3 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI13-.LCFI12 + .byte 0x84 ;# DW_CFA_offset, column 0x4 + .uleb128 0x3 + + .align 4 +.LEFDE1: + +.LSFDE2: + .word .LEFDE2-.LASFDE2 ;# FDE Length +.LASFDE2: + .word .LASFDE2-.Lframe1 ;# FDE CIE offset + .word .LFB2 ;# FDE initial location + .word .LFE2-.LFB2 ;# FDE address range + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI21-.LFB2 + .byte 0x83 ;# DW_CFA_offset, column 0x3 + .uleb128 0x0 + .byte 0x11 ;# DW_CFA_offset_extended_sf + .uleb128 0x2 + .sleb128 -5 + + .byte 0x4 ;# DW_CFA_advance_loc4 + .word .LCFI12-.LCFI11 + .byte 0xd ;# DW_CFA_def_cfa_register = r3 + .uleb128 0x3 + + .align 4 +.LEFDE2: diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix.S new file mode 100644 index 000000000..45502f796 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix.S @@ -0,0 +1,225 @@ +/* ----------------------------------------------------------------------- + aix.S - Copyright (c) 2002 Free Software Foundation, Inc. + based on darwin.S by John Hornkvist + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + + .set r0,0 + .set r1,1 + .set r2,2 + .set r3,3 + .set r4,4 + .set r5,5 + .set r6,6 + .set r7,7 + .set r8,8 + .set r9,9 + .set r10,10 + .set r11,11 + .set r12,12 + .set r13,13 + .set r14,14 + .set r15,15 + .set r16,16 + .set r17,17 + .set r18,18 + .set r19,19 + .set r20,20 + .set r21,21 + .set r22,22 + .set r23,23 + .set r24,24 + .set r25,25 + .set r26,26 + .set r27,27 + .set r28,28 + .set r29,29 + .set r30,30 + .set r31,31 + .set f0,0 + .set f1,1 + .set f2,2 + .set f3,3 + .set f4,4 + .set f5,5 + .set f6,6 + .set f7,7 + .set f8,8 + .set f9,9 + .set f10,10 + .set f11,11 + .set f12,12 + .set f13,13 + .set f14,14 + .set f15,15 + .set f16,16 + .set f17,17 + .set f18,18 + .set f19,19 + .set f20,20 + .set f21,21 + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#define JUMPTARGET(name) name +#define L(x) x + .file "aix.S" + .toc + .csect .text[PR] + .align 2 +.globl ffi_prep_args + +.csect .text[PR] + .align 2 + .globl ffi_call_AIX + .globl .ffi_call_AIX +.csect ffi_call_AIX[DS] +ffi_call_AIX: + .long .ffi_call_AIX, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_AIX: + mr r12,r8 // We only need r12 until the call, so it doesn't have to be saved... + /* Save the old stack pointer as AP. */ + mr r8,r1 + + /* Allocate the stack space we need. */ + stwux r1,r1,r4 + + /* Save registers we use. */ + mflr r9 + + stw r28,-16(r8) + stw r29,-12(r8) + stw r30, -8(r8) + stw r31, -4(r8) + + stw r9, 8(r8) + stw r2, 20(r1) + + /* Save arguments over call... */ + mr r31,r5 /* flags, */ + mr r30,r6 /* rvalue, */ + mr r29,r7 /* function address, */ + mr r28,r8 /* our AP. */ + + /* Call ffi_prep_args. */ + mr r4,r1 + li r9,0 + + lwz r2,4(r12) + lwz r12,0(r12) + mtctr r12 // r12 holds address of _ffi_prep_args + bctrl + lwz r2,20(r1) + + /* Now do the call. */ + lwz r12,0(r29) + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40,r31 + stw r2,20(r1) + mtctr r12 + lwz r2,4(r29) + /* Load all those argument registers. */ + // We have set up a nice stack frame, just load it into registers. + lwz r3, 20+(1*4)(r1) + lwz r4, 20+(2*4)(r1) + lwz r5, 20+(3*4)(r1) + lwz r6, 20+(4*4)(r1) + nop + lwz r7, 20+(5*4)(r1) + lwz r8, 20+(6*4)(r1) + lwz r9, 20+(7*4)(r1) + lwz r10,20+(8*4)(r1) + +L1: + /* Load all the FP registers. */ + bf 6,L2 // 2f + 0x18 + lfd f1,-16-(13*8)(r28) + lfd f2,-16-(12*8)(r28) + lfd f3,-16-(11*8)(r28) + lfd f4,-16-(10*8)(r28) + nop + lfd f5,-16-(9*8)(r28) + lfd f6,-16-(8*8)(r28) + lfd f7,-16-(7*8)(r28) + lfd f8,-16-(6*8)(r28) + nop + lfd f9,-16-(5*8)(r28) + lfd f10,-16-(4*8)(r28) + lfd f11,-16-(3*8)(r28) + lfd f12,-16-(2*8)(r28) + nop + lfd f13,-16-(1*8)(r28) + +L2: + /* Make the call. */ + bctrl + lwz r2,20(r1) + + /* Now, deal with the return value. */ + mtcrf 0x01,r31 + + bt 30,L(done_return_value) + bt 29,L(fp_return_value) + stw r3,0(r30) + bf 28,L(done_return_value) + stw r4,4(r30) + + /* Fall through... */ + +L(done_return_value): + /* Restore the registers we used and return. */ + lwz r9, 8(r28) + lwz r31, -4(r28) + mtlr r9 + lwz r30, -8(r28) + lwz r29,-12(r28) + lwz r28,-16(r28) + lwz r1,0(r1) + blr + +L(fp_return_value): + bf 28,L(float_return_value) + stfd f1,0(r30) + b L(done_return_value) +L(float_return_value): + stfs f1,0(r30) + b L(done_return_value) + .long 0 + .byte 0,0,0,1,128,4,0,0 +//END(ffi_call_AIX) + +.csect .text[PR] + .align 2 + .globl ffi_call_DARWIN + .globl .ffi_call_DARWIN +.csect ffi_call_DARWIN[DS] +ffi_call_DARWIN: + .long .ffi_call_DARWIN, TOC[tc0], 0 + .csect .text[PR] +.ffi_call_DARWIN: + blr + .long 0 + .byte 0,0,0,0,0,0,0,0 +//END(ffi_call_DARWIN) diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix_closure.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix_closure.S new file mode 100644 index 000000000..7bf5c6560 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/aix_closure.S @@ -0,0 +1,247 @@ +/* ----------------------------------------------------------------------- + aix_closure.S - Copyright (c) 2002 2003 Free Software Foundation, Inc. + based on darwin_closure.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + + .set r0,0 + .set r1,1 + .set r2,2 + .set r3,3 + .set r4,4 + .set r5,5 + .set r6,6 + .set r7,7 + .set r8,8 + .set r9,9 + .set r10,10 + .set r11,11 + .set r12,12 + .set r13,13 + .set r14,14 + .set r15,15 + .set r16,16 + .set r17,17 + .set r18,18 + .set r19,19 + .set r20,20 + .set r21,21 + .set r22,22 + .set r23,23 + .set r24,24 + .set r25,25 + .set r26,26 + .set r27,27 + .set r28,28 + .set r29,29 + .set r30,30 + .set r31,31 + .set f0,0 + .set f1,1 + .set f2,2 + .set f3,3 + .set f4,4 + .set f5,5 + .set f6,6 + .set f7,7 + .set f8,8 + .set f9,9 + .set f10,10 + .set f11,11 + .set f12,12 + .set f13,13 + .set f14,14 + .set f15,15 + .set f16,16 + .set f17,17 + .set f18,18 + .set f19,19 + .set f20,20 + .set f21,21 + +#define LIBFFI_ASM +#define JUMPTARGET(name) name +#define L(x) x + .file "aix_closure.S" + .toc +LC..60: + .tc L..60[TC],L..60 + .csect .text[PR] + .align 2 + +.csect .text[PR] + .align 2 + .globl ffi_closure_ASM + .globl .ffi_closure_ASM +.csect ffi_closure_ASM[DS] + +ffi_closure_ASM: + .long .ffi_closure_ASM, TOC[tc0], 0 + .csect .text[PR] +.ffi_closure_ASM: + + mflr r0 /* extract return address */ + stw r0, 8(r1) /* save the return address */ + + /* 24 Bytes (Linkage Area) */ + /* 32 Bytes (params) */ + /* 104 Bytes (13*8 from FPR) */ + /* 8 Bytes (result) */ + /* 168 Bytes */ + + stwu r1,-176(r1) /* skip over caller save area + keep stack aligned to 16 */ + +/* we want to build up an area for the parameters passed */ +/* in registers (both floating point and integer) */ + + /* we store gpr 3 to gpr 10 (aligned to 4) + in the parents outgoing area */ + stw r3, 200(r1) + stw r4, 204(r1) + stw r5, 208(r1) + stw r6, 212(r1) + stw r7, 216(r1) + stw r8, 220(r1) + stw r9, 224(r1) + stw r10, 228(r1) + + /* next save fpr 1 to fpr 13 (aligned to 8) */ + stfd f1, 56(r1) + stfd f2, 64(r1) + stfd f3, 72(r1) + stfd f4, 80(r1) + stfd f5, 88(r1) + stfd f6, 96(r1) + stfd f7, 104(r1) + stfd f8, 112(r1) + stfd f9, 120(r1) + stfd f10, 128(r1) + stfd f11, 136(r1) + stfd f12, 144(r1) + stfd f13, 152(r1) + + /* set up registers for the routine that actually does the work */ + /* get the context pointer from the trampoline */ + mr r3,r11 + + /* now load up the pointer to the result storage */ + addi r4,r1,160 + + /* now load up the pointer to the saved gpr registers */ + addi r5,r1,200 + + /* now load up the pointer to the saved fpr registers */ + addi r6,r1,56 + + /* make the call */ + bl .ffi_closure_helper_DARWIN + nop + + /* now r3 contains the return type */ + /* so use it to look up in a table */ + /* so we know how to deal with each type */ + + /* look up the proper starting point in table */ + /* by using return type as offset */ + addi r5,r1,160 /* get pointer to results area */ + lwz r4,LC..60(2) /* get address of jump table */ + slwi r3,r3,2 /* now multiply return type by 4 */ + lwzx r3,r4,r3 /* get the contents of that table value */ + add r3,r3,r4 /* add contents of table to table address */ + mtctr r3 + bctr /* jump to it */ + +L..60: + .long L..44-L..60 /* FFI_TYPE_VOID */ + .long L..50-L..60 /* FFI_TYPE_INT */ + .long L..47-L..60 /* FFI_TYPE_FLOAT */ + .long L..46-L..60 /* FFI_TYPE_DOUBLE */ + .long L..46-L..60 /* FFI_TYPE_LONGDOUBLE */ + .long L..56-L..60 /* FFI_TYPE_UINT8 */ + .long L..55-L..60 /* FFI_TYPE_SINT8 */ + .long L..58-L..60 /* FFI_TYPE_UINT16 */ + .long L..57-L..60 /* FFI_TYPE_SINT16 */ + .long L..50-L..60 /* FFI_TYPE_UINT32 */ + .long L..50-L..60 /* FFI_TYPE_SINT32 */ + .long L..48-L..60 /* FFI_TYPE_UINT64 */ + .long L..48-L..60 /* FFI_TYPE_SINT64 */ + .long L..44-L..60 /* FFI_TYPE_STRUCT */ + .long L..50-L..60 /* FFI_TYPE_POINTER */ + + +/* case double */ +L..46: + lfd f1,0(r5) + b L..44 + +/* case float */ +L..47: + lfs f1,0(r5) + b L..44 + +/* case long long */ +L..48: + lwz r3,0(r5) + lwz r4,4(r5) + b L..44 + +/* case default / int32 / pointer */ +L..50: + lwz r3,0(r5) + b L..44 + +/* case signed int8 */ +L..55: + addi r5,r5,3 + lbz r3,0(r5) + slwi r3,r3,24 + srawi r3,r3,24 + b L..44 + +/* case unsigned int8 */ +L..56: + addi r5,r5,3 + lbz r3,0(r5) + b L..44 + +/* case signed int16 */ +L..57: + addi r5,r5,2 + lhz r3,0(r5) + extsh r3,r3 + b L..44 + +/* case unsigned int16 */ +L..58: + addi r5,r5,2 + lhz r3,0(r5) + +/* case void / done */ +L..44: + addi r1,r1,176 /* restore stack pointer */ + lwz r0,8(r1) /* get return address */ + mtlr r0 /* reset link register */ + blr + +/* END(ffi_closure_ASM) */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/asm.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/asm.h new file mode 100644 index 000000000..e86e6b091 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/asm.h @@ -0,0 +1,125 @@ +/* ----------------------------------------------------------------------- + asm.h - Copyright (c) 1998 Geoffrey Keating + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define ASM_GLOBAL_DIRECTIVE .globl + + +#define C_SYMBOL_NAME(name) name +/* Macro for a label. */ +#ifdef __STDC__ +#define C_LABEL(name) name##: +#else +#define C_LABEL(name) name/**/: +#endif + +/* This seems to always be the case on PPC. */ +#define ALIGNARG(log2) log2 +/* For ELF we need the `.type' directive to make shared libs work right. */ +#define ASM_TYPE_DIRECTIVE(name,typearg) .type name,typearg; +#define ASM_SIZE_DIRECTIVE(name) .size name,.-name + +/* If compiled for profiling, call `_mcount' at the start of each function. */ +#ifdef PROF +/* The mcount code relies on a the return address being on the stack + to locate our caller and so it can restore it; so store one just + for its benefit. */ +#ifdef PIC +#define CALL_MCOUNT \ + .pushsection; \ + .section ".data"; \ + .align ALIGNARG(2); \ +0:.long 0; \ + .previous; \ + mflr %r0; \ + stw %r0,4(%r1); \ + bl _GLOBAL_OFFSET_TABLE_@local-4; \ + mflr %r11; \ + lwz %r0,0b@got(%r11); \ + bl JUMPTARGET(_mcount); +#else /* PIC */ +#define CALL_MCOUNT \ + .section ".data"; \ + .align ALIGNARG(2); \ +0:.long 0; \ + .previous; \ + mflr %r0; \ + lis %r11,0b@ha; \ + stw %r0,4(%r1); \ + addi %r0,%r11,0b@l; \ + bl JUMPTARGET(_mcount); +#endif /* PIC */ +#else /* PROF */ +#define CALL_MCOUNT /* Do nothing. */ +#endif /* PROF */ + +#define ENTRY(name) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(2); \ + C_LABEL(name) \ + CALL_MCOUNT + +#define EALIGN_W_0 /* No words to insert. */ +#define EALIGN_W_1 nop +#define EALIGN_W_2 nop;nop +#define EALIGN_W_3 nop;nop;nop +#define EALIGN_W_4 EALIGN_W_3;nop +#define EALIGN_W_5 EALIGN_W_4;nop +#define EALIGN_W_6 EALIGN_W_5;nop +#define EALIGN_W_7 EALIGN_W_6;nop + +/* EALIGN is like ENTRY, but does alignment to 'words'*4 bytes + past a 2^align boundary. */ +#ifdef PROF +#define EALIGN(name, alignt, words) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(2); \ + C_LABEL(name) \ + CALL_MCOUNT \ + b 0f; \ + .align ALIGNARG(alignt); \ + EALIGN_W_##words; \ + 0: +#else /* PROF */ +#define EALIGN(name, alignt, words) \ + ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ + ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name),@function) \ + .align ALIGNARG(alignt); \ + EALIGN_W_##words; \ + C_LABEL(name) +#endif + +#define END(name) \ + ASM_SIZE_DIRECTIVE(name) + +#ifdef PIC +#define JUMPTARGET(name) name##@plt +#else +#define JUMPTARGET(name) name +#endif + +/* Local labels stripped out by the linker. */ +#define L(x) .L##x diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin.S new file mode 100644 index 000000000..917dc9328 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin.S @@ -0,0 +1,247 @@ +#ifdef __ppc__ +/* ----------------------------------------------------------------------- + darwin.S - Copyright (c) 2000 John Hornkvist + Copyright (c) 2004 Free Software Foundation, Inc. + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#if defined(__ppc64__) +#define MODE_CHOICE(x, y) y +#else +#define MODE_CHOICE(x, y) x +#endif + +#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ + +#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#define JUMPTARGET(name) name +#define L(x) x +.text + .align 2 +.globl _ffi_prep_args + +.text + .align 2 +.globl _ffi_call_DARWIN +.text + .align 2 +_ffi_call_DARWIN: +LFB0: + mr r12,r8 /* We only need r12 until the call, + so it doesn't have to be saved. */ +LFB1: + /* Save the old stack pointer as AP. */ + mr r8,r1 +LCFI0: + /* Allocate the stack space we need. */ + stwux r1,r1,r4 + + /* Save registers we use. */ + mflr r9 + + stw r28,-16(r8) + stw r29,-12(r8) + stw r30,-8(r8) + stw r31,-4(r8) + + stw r9,8(r8) + stw r2,20(r1) +LCFI1: + + /* Save arguments over call. */ + mr r31,r5 /* flags, */ + mr r30,r6 /* rvalue, */ + mr r29,r7 /* function address, */ + mr r28,r8 /* our AP. */ +LCFI2: + /* Call ffi_prep_args. */ + mr r4,r1 + li r9,0 + + mtctr r12 /* r12 holds address of _ffi_prep_args. */ + bctrl + lwz r2,20(r1) + + /* Now do the call. + Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40,r31 + /* Get the address to call into CTR. */ + mtctr r29 + /* Load all those argument registers. + We have set up a nice stack frame, just load it into registers. */ + lwz r3,20+(1*4)(r1) + lwz r4,20+(2*4)(r1) + lwz r5,20+(3*4)(r1) + lwz r6,20+(4*4)(r1) + nop + lwz r7,20+(5*4)(r1) + lwz r8,20+(6*4)(r1) + lwz r9,20+(7*4)(r1) + lwz r10,20+(8*4)(r1) + +L1: + /* Load all the FP registers. */ + bf 6,L2 /* No floats to load. */ + lfd f1,-16-(13*8)(r28) + lfd f2,-16-(12*8)(r28) + lfd f3,-16-(11*8)(r28) + lfd f4,-16-(10*8)(r28) + nop + lfd f5,-16-(9*8)(r28) + lfd f6,-16-(8*8)(r28) + lfd f7,-16-(7*8)(r28) + lfd f8,-16-(6*8)(r28) + nop + lfd f9,-16-(5*8)(r28) + lfd f10,-16-(4*8)(r28) + lfd f11,-16-(3*8)(r28) + lfd f12,-16-(2*8)(r28) + nop + lfd f13,-16-(1*8)(r28) + +L2: + mr r12,r29 /* Put the target address in r12 as specified. */ + mtctr r12 + nop + nop + /* Make the call. */ + bctrl + + /* Now, deal with the return value. */ + mtcrf 0x01,r31 + + bt 30,L(done_return_value) + bt 29,L(fp_return_value) + stw r3,0(r30) + bf 28,L(done_return_value) + stw r4,4(r30) + + /* Fall through. */ + +L(done_return_value): + /* Restore the registers we used and return. */ + lwz r9,8(r28) + lwz r31,-4(r28) + mtlr r9 + lwz r30,-8(r28) + lwz r29,-12(r28) + lwz r28,-16(r28) + lwz r1,0(r1) + blr + +L(fp_return_value): + /* Do we have long double to store? */ + bf 31,L(fd_return_value) + stfd f1,0(r30) + stfd f2,8(r30) + b L(done_return_value) + +L(fd_return_value): + /* Do we have double to store? */ + bf 28,L(float_return_value) + stfd f1,0(r30) + b L(done_return_value) + +L(float_return_value): + /* We only have a float to store. */ + stfs f1,0(r30) + b L(done_return_value) + +LFE1: +/* END(_ffi_call_DARWIN) */ + +/* Provide a null definition of _ffi_call_AIX. */ +.text + .align 2 +.globl _ffi_call_AIX +.text + .align 2 +_ffi_call_AIX: + blr +/* END(_ffi_call_AIX) */ + +.data +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 ; Length of Common Information Entry +LSCIE1: + .long 0x0 ; CIE Identifier Tag + .byte 0x1 ; CIE Version + .ascii "zR\0" ; CIE Augmentation + .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor + .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x90 ; FDE Encoding (indirect pcrel) + .byte 0xc ; DW_CFA_def_cfa + .byte 0x1 ; uleb128 0x1 + .byte 0x0 ; uleb128 0x0 + .align LOG2_GPR_BYTES +LECIE1: +.globl _ffi_call_DARWIN.eh +_ffi_call_DARWIN.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 ; FDE Length +LASFDE1: + .long LASFDE1-EH_frame1 ; FDE CIE offset + .g_long LLFB0$non_lazy_ptr-. ; FDE initial location + .set L$set$3,LFE1-LFB0 + .g_long L$set$3 ; FDE address range + .byte 0x0 ; uleb128 0x0; Augmentation size + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-LFB1 + .long L$set$4 + .byte 0xd ; DW_CFA_def_cfa_register + .byte 0x08 ; uleb128 0x08 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$5,LCFI1-LCFI0 + .long L$set$5 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .byte 0x9f ; DW_CFA_offset, column 0x1f + .byte 0x1 ; uleb128 0x1 + .byte 0x9e ; DW_CFA_offset, column 0x1e + .byte 0x2 ; uleb128 0x2 + .byte 0x9d ; DW_CFA_offset, column 0x1d + .byte 0x3 ; uleb128 0x3 + .byte 0x9c ; DW_CFA_offset, column 0x1c + .byte 0x4 ; uleb128 0x4 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$6,LCFI2-LCFI1 + .long L$set$6 + .byte 0xd ; DW_CFA_def_cfa_register + .byte 0x1c ; uleb128 0x1c + .align LOG2_GPR_BYTES +LEFDE1: +.data + .align LOG2_GPR_BYTES +LLFB0$non_lazy_ptr: + .g_long LFB0 +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin_closure.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin_closure.S new file mode 100644 index 000000000..71054f5f0 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/darwin_closure.S @@ -0,0 +1,319 @@ +#ifdef __ppc__ +/* ----------------------------------------------------------------------- + darwin_closure.S - Copyright (c) 2002, 2003, 2004, Free Software Foundation, + Inc. based on ppc_closure.S + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#define L(x) x + +#if defined(__ppc64__) +#define MODE_CHOICE(x, y) y +#else +#define MODE_CHOICE(x, y) x +#endif + +#define lgu MODE_CHOICE(lwzu, ldu) + +#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */ + +#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */ + + .file "darwin_closure.S" +.text + .align LOG2_GPR_BYTES +.globl _ffi_closure_ASM + +.text + .align LOG2_GPR_BYTES +_ffi_closure_ASM: +LFB1: + mflr r0 /* extract return address */ + stw r0,8(r1) /* save the return address */ +LCFI0: + /* 24 Bytes (Linkage Area) + 32 Bytes (outgoing parameter area, always reserved) + 104 Bytes (13*8 from FPR) + 16 Bytes (result) + 176 Bytes */ + + stwu r1,-176(r1) /* skip over caller save area + keep stack aligned to 16. */ +LCFI1: + /* We want to build up an area for the parameters passed + in registers. (both floating point and integer) */ + + /* We store gpr 3 to gpr 10 (aligned to 4) + in the parents outgoing area. */ + stw r3,200(r1) + stw r4,204(r1) + stw r5,208(r1) + stw r6,212(r1) + stw r7,216(r1) + stw r8,220(r1) + stw r9,224(r1) + stw r10,228(r1) + + /* We save fpr 1 to fpr 13. (aligned to 8) */ + stfd f1,56(r1) + stfd f2,64(r1) + stfd f3,72(r1) + stfd f4,80(r1) + stfd f5,88(r1) + stfd f6,96(r1) + stfd f7,104(r1) + stfd f8,112(r1) + stfd f9,120(r1) + stfd f10,128(r1) + stfd f11,136(r1) + stfd f12,144(r1) + stfd f13,152(r1) + + /* Set up registers for the routine that actually does the work + get the context pointer from the trampoline. */ + mr r3,r11 + + /* Now load up the pointer to the result storage. */ + addi r4,r1,160 + + /* Now load up the pointer to the saved gpr registers. */ + addi r5,r1,200 + + /* Now load up the pointer to the saved fpr registers. */ + addi r6,r1,56 + + /* Make the call. */ + bl Lffi_closure_helper_DARWIN$stub + + /* Now r3 contains the return type + so use it to look up in a table + so we know how to deal with each type. */ + + /* Look up the proper starting point in table + by using return type as offset. */ + addi r5,r1,160 /* Get pointer to results area. */ + bl Lget_ret_type0_addr /* Get pointer to Lret_type0 into LR. */ + mflr r4 /* Move to r4. */ + slwi r3,r3,4 /* Now multiply return type by 16. */ + add r3,r3,r4 /* Add contents of table to table address. */ + mtctr r3 + bctr /* Jump to it. */ +LFE1: +/* Each of the ret_typeX code fragments has to be exactly 16 bytes long + (4 instructions). For cache effectiveness we align to a 16 byte boundary + first. */ + + .align 4 + + nop + nop + nop +Lget_ret_type0_addr: + blrl + +/* case FFI_TYPE_VOID */ +Lret_type0: + b Lfinish + nop + nop + nop + +/* case FFI_TYPE_INT */ +Lret_type1: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_FLOAT */ +Lret_type2: + lfs f1,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_DOUBLE */ +Lret_type3: + lfd f1,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_LONGDOUBLE */ +Lret_type4: + lfd f1,0(r5) + lfd f2,8(r5) + b Lfinish + nop + +/* case FFI_TYPE_UINT8 */ +Lret_type5: + lbz r3,3(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT8 */ +Lret_type6: + lbz r3,3(r5) + extsb r3,r3 + b Lfinish + nop + +/* case FFI_TYPE_UINT16 */ +Lret_type7: + lhz r3,2(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT16 */ +Lret_type8: + lha r3,2(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_UINT32 */ +Lret_type9: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_SINT32 */ +Lret_type10: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case FFI_TYPE_UINT64 */ +Lret_type11: + lwz r3,0(r5) + lwz r4,4(r5) + b Lfinish + nop + +/* case FFI_TYPE_SINT64 */ +Lret_type12: + lwz r3,0(r5) + lwz r4,4(r5) + b Lfinish + nop + +/* case FFI_TYPE_STRUCT */ +Lret_type13: + b Lfinish + nop + nop + nop + +/* case FFI_TYPE_POINTER */ +Lret_type14: + lwz r3,0(r5) + b Lfinish + nop + nop + +/* case done */ +Lfinish: + addi r1,r1,176 /* Restore stack pointer. */ + lwz r0,8(r1) /* Get return address. */ + mtlr r0 /* Reset link register. */ + blr + +/* END(ffi_closure_ASM) */ + +.data +.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms +EH_frame1: + .set L$set$0,LECIE1-LSCIE1 + .long L$set$0 ; Length of Common Information Entry +LSCIE1: + .long 0x0 ; CIE Identifier Tag + .byte 0x1 ; CIE Version + .ascii "zR\0" ; CIE Augmentation + .byte 0x1 ; uleb128 0x1; CIE Code Alignment Factor + .byte 0x7c ; sleb128 -4; CIE Data Alignment Factor + .byte 0x41 ; CIE RA Column + .byte 0x1 ; uleb128 0x1; Augmentation size + .byte 0x90 ; FDE Encoding (indirect pcrel) + .byte 0xc ; DW_CFA_def_cfa + .byte 0x1 ; uleb128 0x1 + .byte 0x0 ; uleb128 0x0 + .align LOG2_GPR_BYTES +LECIE1: +.globl _ffi_closure_ASM.eh +_ffi_closure_ASM.eh: +LSFDE1: + .set L$set$1,LEFDE1-LASFDE1 + .long L$set$1 ; FDE Length + +LASFDE1: + .long LASFDE1-EH_frame1 ; FDE CIE offset + .g_long LLFB1$non_lazy_ptr-. ; FDE initial location + .set L$set$3,LFE1-LFB1 + .g_long L$set$3 ; FDE address range + .byte 0x0 ; uleb128 0x0; Augmentation size + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$3,LCFI1-LCFI0 + .long L$set$3 + .byte 0xe ; DW_CFA_def_cfa_offset + .byte 176,1 ; uleb128 176 + .byte 0x4 ; DW_CFA_advance_loc4 + .set L$set$4,LCFI0-LFB1 + .long L$set$4 + .byte 0x11 ; DW_CFA_offset_extended_sf + .byte 0x41 ; uleb128 0x41 + .byte 0x7e ; sleb128 -2 + .align LOG2_GPR_BYTES +LEFDE1: +.data + .align LOG2_GPR_BYTES +LDFCM0: +.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32 + .align LOG2_GPR_BYTES +Lffi_closure_helper_DARWIN$stub: +#if 1 + .indirect_symbol _ffi_closure_helper_DARWIN + mflr r0 + bcl 20,31,LO$ffi_closure_helper_DARWIN +LO$ffi_closure_helper_DARWIN: + mflr r11 + addis r11,r11,ha16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN) + mtlr r0 + lgu r12,lo16(L_ffi_closure_helper_DARWIN$lazy_ptr - LO$ffi_closure_helper_DARWIN)(r11) + mtctr r12 + bctr +.lazy_symbol_pointer +L_ffi_closure_helper_DARWIN$lazy_ptr: + .indirect_symbol _ffi_closure_helper_DARWIN + .g_long dyld_stub_binding_helper +#endif +.data + .align LOG2_GPR_BYTES +LLFB1$non_lazy_ptr: + .g_long LFB1 +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi.c new file mode 100644 index 000000000..bfd7ab676 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi.c @@ -0,0 +1,1249 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Geoffrey Keating + + PowerPC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <stdio.h> + + +extern void ffi_closure_SYSV (void); +extern void FFI_HIDDEN ffi_closure_LINUX64 (void); + +enum { + /* The assembly depends on these exact flags. */ + FLAG_RETURNS_SMST = 1 << (31-31), /* Used for FFI_SYSV small structs. */ + FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */ + FLAG_RETURNS_FP = 1 << (31-29), + FLAG_RETURNS_64BITS = 1 << (31-28), + FLAG_RETURNS_128BITS = 1 << (31-27), + + FLAG_ARG_NEEDS_COPY = 1 << (31- 7), + FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ + FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), + FLAG_RETVAL_REFERENCE = 1 << (31- 4) +}; + +/* About the SYSV ABI. */ +enum { + NUM_GPR_ARG_REGISTERS = 8, + NUM_FPR_ARG_REGISTERS = 8 +}; +enum { ASM_NEEDS_REGISTERS = 4 }; + +/* ffi_prep_args_SYSV is called by the assembly routine once stack space + has been allocated for the function's arguments. + + The stack layout we want looks like this: + + | Return address from ffi_call_SYSV 4bytes | higher addresses + |--------------------------------------------| + | Previous backchain pointer 4 | stack pointer here + |--------------------------------------------|<+ <<< on entry to + | Saved r28-r31 4*4 | | ffi_call_SYSV + |--------------------------------------------| | + | GPR registers r3-r10 8*4 | | ffi_call_SYSV + |--------------------------------------------| | + | FPR registers f1-f8 (optional) 8*8 | | + |--------------------------------------------| | stack | + | Space for copied structures | | grows | + |--------------------------------------------| | down V + | Parameters that didn't fit in registers | | + |--------------------------------------------| | lower addresses + | Space for callee's LR 4 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4 |-/ during + |--------------------------------------------| <<< ffi_call_SYSV + +*/ + +/*@-exportheader@*/ +void +ffi_prep_args_SYSV (extended_cif *ecif, unsigned *const stack) +/*@=exportheader@*/ +{ + const unsigned bytes = ecif->cif->bytes; + const unsigned flags = ecif->cif->flags; + + typedef union { + char *c; + unsigned *u; + long long *ll; + float *f; + double *d; + } valp; + + /* 'stacktop' points at the previous backchain pointer. */ + valp stacktop; + + /* 'gpr_base' points at the space for gpr3, and grows upwards as + we use GPR registers. */ + valp gpr_base; + int intarg_count; + + /* 'fpr_base' points at the space for fpr1, and grows upwards as + we use FPR registers. */ + valp fpr_base; + int fparg_count; + + /* 'copy_space' grows down as we put structures in it. It should + stay 16-byte aligned. */ + valp copy_space; + + /* 'next_arg' grows up as we put parameters in it. */ + valp next_arg; + + int i; + ffi_type **ptr; + double double_tmp; + union { + void **v; + char **c; + signed char **sc; + unsigned char **uc; + signed short **ss; + unsigned short **us; + unsigned int **ui; + long long **ll; + float **f; + double **d; + } p_argv; + size_t struct_copy_size; + unsigned gprvalue; + + stacktop.c = (char *) stack + bytes; + gpr_base.u = stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS; + intarg_count = 0; + fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS; + fparg_count = 0; + copy_space.c = ((flags & FLAG_FP_ARGUMENTS) ? fpr_base.c : gpr_base.c); + next_arg.u = stack + 2; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT (((unsigned) (char *) stack & 0xF) == 0); + FFI_ASSERT (((unsigned) copy_space.c & 0xF) == 0); + FFI_ASSERT (((unsigned) stacktop.c & 0xF) == 0); + FFI_ASSERT ((bytes & 0xF) == 0); + FFI_ASSERT (copy_space.c >= next_arg.c); + + /* Deal with return values that are actually pass-by-reference. */ + if (flags & FLAG_RETVAL_REFERENCE) + { + *gpr_base.u++ = (unsigned long) (char *) ecif->rvalue; + intarg_count++; + } + + /* Now for the arguments. */ + p_argv.v = ecif->avalue; + for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; + i > 0; + i--, ptr++, p_argv.v++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + double_tmp = **p_argv.f; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + { + *next_arg.f = (float) double_tmp; + next_arg.u += 1; + } + else + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_DOUBLE: + double_tmp = **p_argv.d; + + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + { + if (intarg_count >= NUM_GPR_ARG_REGISTERS + && intarg_count % 2 != 0) + { + intarg_count++; + next_arg.u++; + } + *next_arg.d = double_tmp; + next_arg.u += 2; + } + else + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + if (intarg_count == NUM_GPR_ARG_REGISTERS-1) + intarg_count++; + if (intarg_count >= NUM_GPR_ARG_REGISTERS) + { + if (intarg_count % 2 != 0) + { + intarg_count++; + next_arg.u++; + } + *next_arg.ll = **p_argv.ll; + next_arg.u += 2; + } + else + { + /* whoops: abi states only certain register pairs + * can be used for passing long long int + * specifically (r3,r4), (r5,r6), (r7,r8), + * (r9,r10) and if next arg is long long but + * not correct starting register of pair then skip + * until the proper starting register + */ + if (intarg_count % 2 != 0) + { + intarg_count ++; + gpr_base.u++; + } + *gpr_base.ll++ = **p_argv.ll; + } + intarg_count += 2; + break; + + case FFI_TYPE_STRUCT: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + struct_copy_size = ((*ptr)->size + 15) & ~0xF; + copy_space.c -= struct_copy_size; + memcpy (copy_space.c, *p_argv.c, (*ptr)->size); + + gprvalue = (unsigned long) copy_space.c; + + FFI_ASSERT (copy_space.c > next_arg.c); + FFI_ASSERT (flags & FLAG_ARG_NEEDS_COPY); + goto putgpr; + + case FFI_TYPE_UINT8: + gprvalue = **p_argv.uc; + goto putgpr; + case FFI_TYPE_SINT8: + gprvalue = **p_argv.sc; + goto putgpr; + case FFI_TYPE_UINT16: + gprvalue = **p_argv.us; + goto putgpr; + case FFI_TYPE_SINT16: + gprvalue = **p_argv.ss; + goto putgpr; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + gprvalue = **p_argv.ui; + + putgpr: + if (intarg_count >= NUM_GPR_ARG_REGISTERS) + *next_arg.u++ = gprvalue; + else + *gpr_base.u++ = gprvalue; + intarg_count++; + break; + } + } + + /* Check that we didn't overrun the stack... */ + FFI_ASSERT (copy_space.c >= next_arg.c); + FFI_ASSERT (gpr_base.u <= stacktop.u - ASM_NEEDS_REGISTERS); + FFI_ASSERT (fpr_base.u + <= stacktop.u - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); + FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); +} + +/* About the LINUX64 ABI. */ +enum { + NUM_GPR_ARG_REGISTERS64 = 8, + NUM_FPR_ARG_REGISTERS64 = 13 +}; +enum { ASM_NEEDS_REGISTERS64 = 4 }; + +/* ffi_prep_args64 is called by the assembly routine once stack space + has been allocated for the function's arguments. + + The stack layout we want looks like this: + + | Ret addr from ffi_call_LINUX64 8bytes | higher addresses + |--------------------------------------------| + | CR save area 8bytes | + |--------------------------------------------| + | Previous backchain pointer 8 | stack pointer here + |--------------------------------------------|<+ <<< on entry to + | Saved r28-r31 4*8 | | ffi_call_LINUX64 + |--------------------------------------------| | + | GPR registers r3-r10 8*8 | | + |--------------------------------------------| | + | FPR registers f1-f13 (optional) 13*8 | | + |--------------------------------------------| | + | Parameter save area | | + |--------------------------------------------| | + | TOC save area 8 | | + |--------------------------------------------| | stack | + | Linker doubleword 8 | | grows | + |--------------------------------------------| | down V + | Compiler doubleword 8 | | + |--------------------------------------------| | lower addresses + | Space for callee's LR 8 | | + |--------------------------------------------| | + | CR save area 8 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 8 |-/ during + |--------------------------------------------| <<< ffi_call_LINUX64 + +*/ + +/*@-exportheader@*/ +void FFI_HIDDEN +ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack) +/*@=exportheader@*/ +{ + const unsigned long bytes = ecif->cif->bytes; + const unsigned long flags = ecif->cif->flags; + + typedef union { + char *c; + unsigned long *ul; + float *f; + double *d; + } valp; + + /* 'stacktop' points at the previous backchain pointer. */ + valp stacktop; + + /* 'next_arg' points at the space for gpr3, and grows upwards as + we use GPR registers, then continues at rest. */ + valp gpr_base; + valp gpr_end; + valp rest; + valp next_arg; + + /* 'fpr_base' points at the space for fpr3, and grows upwards as + we use FPR registers. */ + valp fpr_base; + int fparg_count; + + int i, words; + ffi_type **ptr; + double double_tmp; + union { + void **v; + char **c; + signed char **sc; + unsigned char **uc; + signed short **ss; + unsigned short **us; + signed int **si; + unsigned int **ui; + unsigned long **ul; + float **f; + double **d; + } p_argv; + unsigned long gprvalue; + + stacktop.c = (char *) stack + bytes; + gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64; + gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64; + rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64; + fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64; + fparg_count = 0; + next_arg.ul = gpr_base.ul; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0); + FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0); + FFI_ASSERT ((bytes & 0xF) == 0); + + /* Deal with return values that are actually pass-by-reference. */ + if (flags & FLAG_RETVAL_REFERENCE) + *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue; + + /* Now for the arguments. */ + p_argv.v = ecif->avalue; + for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; + i > 0; + i--, ptr++, p_argv.v++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + double_tmp = **p_argv.f; + *next_arg.f = (float) double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_DOUBLE: + double_tmp = **p_argv.d; + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + double_tmp = (*p_argv.d)[0]; + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + double_tmp = (*p_argv.d)[1]; + *next_arg.d = double_tmp; + if (++next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + if (fparg_count < NUM_FPR_ARG_REGISTERS64) + *fpr_base.d++ = double_tmp; + fparg_count++; + FFI_ASSERT (flags & FLAG_FP_ARGUMENTS); + break; +#endif + + case FFI_TYPE_STRUCT: + words = ((*ptr)->size + 7) / 8; + if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul) + { + size_t first = gpr_end.c - next_arg.c; + memcpy (next_arg.c, *p_argv.c, first); + memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first); + next_arg.c = rest.c + words * 8 - first; + } + else + { + char *where = next_arg.c; + + /* Structures with size less than eight bytes are passed + left-padded. */ + if ((*ptr)->size < 8) + where += 8 - (*ptr)->size; + + memcpy (where, *p_argv.c, (*ptr)->size); + next_arg.ul += words; + if (next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + } + break; + + case FFI_TYPE_UINT8: + gprvalue = **p_argv.uc; + goto putgpr; + case FFI_TYPE_SINT8: + gprvalue = **p_argv.sc; + goto putgpr; + case FFI_TYPE_UINT16: + gprvalue = **p_argv.us; + goto putgpr; + case FFI_TYPE_SINT16: + gprvalue = **p_argv.ss; + goto putgpr; + case FFI_TYPE_UINT32: + gprvalue = **p_argv.ui; + goto putgpr; + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + gprvalue = **p_argv.si; + goto putgpr; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + gprvalue = **p_argv.ul; + putgpr: + *next_arg.ul++ = gprvalue; + if (next_arg.ul == gpr_end.ul) + next_arg.ul = rest.ul; + break; + } + } + + FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS + || (next_arg.ul >= gpr_base.ul + && next_arg.ul <= gpr_base.ul + 4)); +} + + + +/* Perform machine dependent cif processing */ +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + /* All this is for the SYSV and LINUX64 ABI. */ + int i; + ffi_type **ptr; + unsigned bytes; + int fparg_count = 0, intarg_count = 0; + unsigned flags = 0; + unsigned struct_copy_size = 0; + unsigned type = cif->rtype->type; + unsigned size = cif->rtype->size; + + if (cif->abi != FFI_LINUX64) + { + /* All the machine-independent calculation of cif->bytes will be wrong. + Redo the calculation for SYSV. */ + + /* Space for the frame pointer, callee's LR, and the asm's temp regs. */ + bytes = (2 + ASM_NEEDS_REGISTERS) * sizeof (int); + + /* Space for the GPR registers. */ + bytes += NUM_GPR_ARG_REGISTERS * sizeof (int); + } + else + { + /* 64-bit ABI. */ + + /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp + regs. */ + bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long); + + /* Space for the mandatory parm save area and general registers. */ + bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long); + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + if (type == FFI_TYPE_LONGDOUBLE) + type = FFI_TYPE_DOUBLE; +#endif + } + + /* Return value handling. The rules for SYSV are as follows: + - 32-bit (or less) integer values are returned in gpr3; + - Structures of size <= 4 bytes also returned in gpr3; + - 64-bit integer values and structures between 5 and 8 bytes are returned + in gpr3 and gpr4; + - Single/double FP values are returned in fpr1; + - Larger structures and long double (if not equivalent to double) values + are allocated space and a pointer is passed as the first argument. + For LINUX64: + - integer values in gpr3; + - Structures/Unions by reference; + - Single/double FP values in fpr1, long double in fpr1,fpr2. */ + switch (type) + { + case FFI_TYPE_DOUBLE: + flags |= FLAG_RETURNS_64BITS; + /* Fall through. */ + case FFI_TYPE_FLOAT: + flags |= FLAG_RETURNS_FP; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_SYSV) + { + /* The final SYSV ABI says that structures smaller or equal 8 bytes + are returned in r3/r4. The FFI_GCC_SYSV ABI instead returns them + in memory. */ + + /* Treat structs with size <= 8 bytes. */ + if (size <= 8) + { + flags |= FLAG_RETURNS_SMST; + /* These structs are returned in r3. We pack the type and the + precalculated shift value (needed in the sysv.S) into flags. + The same applies for the structs returned in r3/r4. */ + if (size <= 4) + { + flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 1); + flags |= 8 * (4 - size) << 4; + break; + } + /* These structs are returned in r3 and r4. See above. */ + if (size <= 8) + { + flags |= 1 << (31 - FFI_SYSV_TYPE_SMALL_STRUCT - 2); + flags |= 8 * (8 - size) << 4; + break; + } + } + } + /* else fall through. */ +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (type == FFI_TYPE_LONGDOUBLE && cif->abi == FFI_LINUX64) + { + flags |= FLAG_RETURNS_128BITS; + flags |= FLAG_RETURNS_FP; + break; + } +#endif + intarg_count++; + flags |= FLAG_RETVAL_REFERENCE; + /* Fall through. */ + case FFI_TYPE_VOID: + flags |= FLAG_RETURNS_NOTHING; + break; + + default: + /* Returns 32-bit integer, or similar. Nothing to do here. */ + break; + } + + if (cif->abi != FFI_LINUX64) + /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the + first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest + goes on the stack. Structures and long doubles (if not equivalent + to double) are passed as a pointer to a copy of the structure. + Stuff on the stack needs to keep proper alignment. */ + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + fparg_count++; + /* floating singles are not 8-aligned on stack */ + break; + + case FFI_TYPE_DOUBLE: + fparg_count++; + /* If this FP arg is going on the stack, it must be + 8-byte-aligned. */ + if (fparg_count > NUM_FPR_ARG_REGISTERS + && intarg_count >= NUM_GPR_ARG_REGISTERS + && intarg_count % 2 != 0) + intarg_count++; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + /* 'long long' arguments are passed as two words, but + either both words must fit in registers or both go + on the stack. If they go on the stack, they must + be 8-byte-aligned. + + Also, only certain register pairs can be used for + passing long long int -- specifically (r3,r4), (r5,r6), + (r7,r8), (r9,r10). + */ + if (intarg_count == NUM_GPR_ARG_REGISTERS-1 + || intarg_count % 2 != 0) + intarg_count++; + intarg_count += 2; + break; + + case FFI_TYPE_STRUCT: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + /* We must allocate space for a copy of these to enforce + pass-by-value. Pad the space up to a multiple of 16 + bytes (the maximum alignment required for anything under + the SYSV ABI). */ + struct_copy_size += ((*ptr)->size + 15) & ~0xF; + /* Fall through (allocate space for the pointer). */ + + default: + /* Everything else is passed as a 4-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + break; + } + } + else + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + switch ((*ptr)->type) + { +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + fparg_count += 2; + intarg_count += 2; + break; +#endif + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + fparg_count++; + intarg_count++; + break; + + case FFI_TYPE_STRUCT: + intarg_count += ((*ptr)->size + 7) / 8; + break; + + default: + /* Everything else is passed as a 8-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + break; + } + } + + if (fparg_count != 0) + flags |= FLAG_FP_ARGUMENTS; + if (intarg_count > 4) + flags |= FLAG_4_GPR_ARGUMENTS; + if (struct_copy_size != 0) + flags |= FLAG_ARG_NEEDS_COPY; + + if (cif->abi != FFI_LINUX64) + { + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS * sizeof (double); + + /* Stack space. */ + if (intarg_count > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count - NUM_GPR_ARG_REGISTERS) * sizeof (int); + if (fparg_count > NUM_FPR_ARG_REGISTERS) + bytes += (fparg_count - NUM_FPR_ARG_REGISTERS) * sizeof (double); + } + else + { + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double); + + /* Stack space. */ + if (intarg_count > NUM_GPR_ARG_REGISTERS64) + bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long); + } + + /* The stack space allocated needs to be a multiple of 16 bytes. */ + bytes = (bytes + 15) & ~0xF; + + /* Add in the space for the copied structures. */ + bytes += struct_copy_size; + + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(/*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +extern void FFI_HIDDEN ffi_call_LINUX64(/*@out@*/ extended_cif *, + unsigned long, unsigned long, + /*@out@*/ unsigned long *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void +ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { +#ifndef POWERPC64 + case FFI_SYSV: + case FFI_GCC_SYSV: + /*@-usedef@*/ + ffi_call_SYSV (&ecif, -cif->bytes, cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#else + case FFI_LINUX64: + /*@-usedef@*/ + ffi_call_LINUX64 (&ecif, -(long) cif->bytes, cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif + default: + FFI_ASSERT (0); + break; + } +} + + +#ifndef POWERPC64 +#define MIN_CACHE_LINE_SIZE 8 + +static void +flush_icache (char *addr1, int size) +{ + int i; + char * addr; + for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE) + { + addr = addr1 + i; + __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" + : : "r" (addr) : "memory"); + } + addr = addr1 + size - 1; + __asm__ volatile ("icbi 0,%0;" "dcbf 0,%0;" "sync;" "isync;" + : : "r"(addr) : "memory"); +} +#endif + +ffi_status +ffi_prep_closure (ffi_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data) +{ +#ifdef POWERPC64 + void **tramp = (void **) &closure->tramp[0]; + + FFI_ASSERT (cif->abi == FFI_LINUX64); + /* Copy function address and TOC from ffi_closure_LINUX64. */ + memcpy (tramp, (char *) ffi_closure_LINUX64, 16); + tramp[2] = (void *) closure; +#else + unsigned int *tramp; + + FFI_ASSERT (cif->abi == FFI_GCC_SYSV || cif->abi == FFI_SYSV); + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x4800000d; /* bl 10 <trampoline_initial+0x10> */ + tramp[4] = 0x7d6802a6; /* mflr r11 */ + tramp[5] = 0x7c0803a6; /* mtlr r0 */ + tramp[6] = 0x800b0000; /* lwz r0,0(r11) */ + tramp[7] = 0x816b0004; /* lwz r11,4(r11) */ + tramp[8] = 0x7c0903a6; /* mtctr r0 */ + tramp[9] = 0x4e800420; /* bctr */ + *(void **) &tramp[2] = (void *) ffi_closure_SYSV; /* function */ + *(void **) &tramp[3] = (void *) closure; /* context */ + + /* Flush the icache. */ + flush_icache (&closure->tramp[0],FFI_TRAMPOLINE_SIZE); +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +typedef union +{ + float f; + double d; +} ffi_dblfl; + +int ffi_closure_helper_SYSV (ffi_closure *, void *, unsigned long *, + ffi_dblfl *, unsigned long *); + +/* Basically the trampoline invokes ffi_closure_SYSV, and on + * entry, r11 holds the address of the closure. + * After storing the registers that could possibly contain + * parameters to be passed into the stack frame and setting + * up space for a return value, ffi_closure_SYSV invokes the + * following helper function to do most of the work + */ + +int +ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, + unsigned long *pgr, ffi_dblfl *pfr, + unsigned long *pst) +{ + /* rvalue is the pointer to space for return value in closure assembly */ + /* pgr is the pointer to where r3-r10 are stored in ffi_closure_SYSV */ + /* pfr is the pointer to where f1-f8 are stored in ffi_closure_SYSV */ + /* pst is the pointer to outgoing parameter stack in original caller */ + + void ** avalue; + ffi_type ** arg_types; + long i, avn; + long nf; /* number of floating registers already used */ + long ng; /* number of general registers already used */ + ffi_cif * cif; + double temp; + unsigned size; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + size = cif->rtype->size; + + nf = 0; + ng = 0; + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. + For FFI_SYSV the result is passed in r3/r4 if the struct size is less + or equal 8 bytes. */ + + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + if (!((cif->abi == FFI_SYSV) && (size <= 8))) + { + rvalue = (void *) *pgr; + ng++; + pgr++; + } + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { + avalue[i] = (char *) pgr + 3; + ng++; + pgr++; + } + else + { + avalue[i] = (char *) pst + 3; + pst++; + } + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { + avalue[i] = (char *) pgr + 2; + ng++; + pgr++; + } + else + { + avalue[i] = (char *) pst + 2; + pst++; + } + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + /* there are 8 gpr registers used to pass values */ + if (ng < 8) + { + avalue[i] = pgr; + ng++; + pgr++; + } + else + { + avalue[i] = pst; + pst++; + } + break; + + case FFI_TYPE_STRUCT: + /* Structs are passed by reference. The address will appear in a + gpr if it is one of the first 8 arguments. */ + if (ng < 8) + { + avalue[i] = (void *) *pgr; + ng++; + pgr++; + } + else + { + avalue[i] = (void *) *pst; + pst++; + } + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* passing long long ints are complex, they must + * be passed in suitable register pairs such as + * (r3,r4) or (r5,r6) or (r6,r7), or (r7,r8) or (r9,r10) + * and if the entire pair aren't available then the outgoing + * parameter stack is used for both but an alignment of 8 + * must will be kept. So we must either look in pgr + * or pst to find the correct address for this type + * of parameter. + */ + if (ng < 7) + { + if (ng & 0x01) + { + /* skip r4, r6, r8 as starting points */ + ng++; + pgr++; + } + avalue[i] = pgr; + ng += 2; + pgr += 2; + } + else + { + if (((long) pst) & 4) + pst++; + avalue[i] = pst; + pst += 2; + } + break; + + case FFI_TYPE_FLOAT: + /* unfortunately float values are stored as doubles + * in the ffi_closure_SYSV code (since we don't check + * the type in that routine). + */ + + /* there are 8 64bit floating point registers */ + + if (nf < 8) + { + temp = pfr->d; + pfr->f = (float) temp; + avalue[i] = pfr; + nf++; + pfr++; + } + else + { + /* FIXME? here we are really changing the values + * stored in the original calling routines outgoing + * parameter stack. This is probably a really + * naughty thing to do but... + */ + avalue[i] = pst; + nf++; + pst += 1; + } + break; + + case FFI_TYPE_DOUBLE: + /* On the outgoing stack all values are aligned to 8 */ + /* there are 8 64bit floating point registers */ + + if (nf < 8) + { + avalue[i] = pfr; + nf++; + pfr++; + } + else + { + if (((long) pst) & 4) + pst++; + avalue[i] = pst; + nf++; + pst += 2; + } + break; + + default: + FFI_ASSERT (0); + } + + i++; + } + + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_SYSV how to perform return type promotions. + Because the FFI_SYSV ABI returns the structures <= 8 bytes in r3/r4 + we have to tell ffi_closure_SYSV how to treat them. */ + if (cif->abi == FFI_SYSV && cif->rtype->type == FFI_TYPE_STRUCT + && size <= 8) + return FFI_SYSV_TYPE_SMALL_STRUCT + size; + return cif->rtype->type; + +} + +int FFI_HIDDEN ffi_closure_helper_LINUX64 (ffi_closure *, void *, + unsigned long *, ffi_dblfl *); + +int FFI_HIDDEN +ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue, + unsigned long *pst, ffi_dblfl *pfr) +{ + /* rvalue is the pointer to space for return value in closure assembly */ + /* pst is the pointer to parameter save area + (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */ + /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */ + + void **avalue; + ffi_type **arg_types; + long i, avn; + ffi_cif *cif; + ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + rvalue = (void *) *pst; + pst++; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (char *) pst + 7; + pst++; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (char *) pst + 6; + pst++; + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + avalue[i] = (char *) pst + 4; + pst++; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + case FFI_TYPE_POINTER: + avalue[i] = pst; + pst++; + break; + + case FFI_TYPE_STRUCT: + /* Structures with size less than eight bytes are passed + left-padded. */ + if (arg_types[i]->size < 8) + avalue[i] = (char *) pst + 8 - arg_types[i]->size; + else + avalue[i] = pst; + pst += (arg_types[i]->size + 7) / 8; + break; + + case FFI_TYPE_FLOAT: + /* unfortunately float values are stored as doubles + * in the ffi_closure_LINUX64 code (since we don't check + * the type in that routine). + */ + + /* there are 13 64bit floating point registers */ + + if (pfr < end_pfr) + { + double temp = pfr->d; + pfr->f = (float) temp; + avalue[i] = pfr; + pfr++; + } + else + avalue[i] = pst; + pst++; + break; + + case FFI_TYPE_DOUBLE: + /* On the outgoing stack all values are aligned to 8 */ + /* there are 13 64bit floating point registers */ + + if (pfr < end_pfr) + { + avalue[i] = pfr; + pfr++; + } + else + avalue[i] = pst; + pst++; + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + if (pfr + 1 < end_pfr) + { + avalue[i] = pfr; + pfr += 2; + } + else + { + if (pfr < end_pfr) + { + /* Passed partly in f13 and partly on the stack. + Move it all to the stack. */ + *pst = *(unsigned long *) pfr; + pfr++; + } + avalue[i] = pst; + } + pst += 2; + break; +#endif + + default: + FFI_ASSERT (0); + } + + i++; + } + + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_LINUX64 how to perform return type promotions. */ + return cif->rtype->type; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi_darwin.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi_darwin.c new file mode 100644 index 000000000..55af70cd8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffi_darwin.c @@ -0,0 +1,771 @@ +#if !(defined(__APPLE__) && !defined(__ppc__)) +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Geoffrey Keating + + PowerPC Foreign Function Interface + + Darwin ABI support (c) 2001 John Hornkvist + AIX ABI support (c) 2002 Free Software Foundation, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +extern void ffi_closure_ASM(void); + +enum { + /* The assembly depends on these exact flags. */ + FLAG_RETURNS_NOTHING = 1 << (31-30), /* These go in cr7 */ + FLAG_RETURNS_FP = 1 << (31-29), + FLAG_RETURNS_64BITS = 1 << (31-28), + FLAG_RETURNS_128BITS = 1 << (31-31), + + FLAG_ARG_NEEDS_COPY = 1 << (31- 7), + FLAG_FP_ARGUMENTS = 1 << (31- 6), /* cr1.eq; specified by ABI */ + FLAG_4_GPR_ARGUMENTS = 1 << (31- 5), + FLAG_RETVAL_REFERENCE = 1 << (31- 4) +}; + +/* About the DARWIN ABI. */ +enum { + NUM_GPR_ARG_REGISTERS = 8, + NUM_FPR_ARG_REGISTERS = 13 +}; +enum { ASM_NEEDS_REGISTERS = 4 }; + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments. + + The stack layout we want looks like this: + + | Return address from ffi_call_DARWIN | higher addresses + |--------------------------------------------| + | Previous backchain pointer 4 | stack pointer here + |--------------------------------------------|<+ <<< on entry to + | Saved r28-r31 4*4 | | ffi_call_DARWIN + |--------------------------------------------| | + | Parameters (at least 8*4=32) | | + |--------------------------------------------| | + | Space for GPR2 4 | | + |--------------------------------------------| | stack | + | Reserved 2*4 | | grows | + |--------------------------------------------| | down V + | Space for callee's LR 4 | | + |--------------------------------------------| | lower addresses + | Saved CR 4 | | + |--------------------------------------------| | stack pointer here + | Current backchain pointer 4 |-/ during + |--------------------------------------------| <<< ffi_call_DARWIN + + */ + +/*@-exportheader@*/ +void ffi_prep_args(extended_cif *ecif, unsigned *const stack) +/*@=exportheader@*/ +{ + const unsigned bytes = ecif->cif->bytes; + const unsigned flags = ecif->cif->flags; + + /* 'stacktop' points at the previous backchain pointer. */ + unsigned *const stacktop = stack + (bytes / sizeof(unsigned)); + + /* 'fpr_base' points at the space for fpr1, and grows upwards as + we use FPR registers. */ + double *fpr_base = (double*) (stacktop - ASM_NEEDS_REGISTERS) - NUM_FPR_ARG_REGISTERS; + int fparg_count = 0; + + + /* 'next_arg' grows up as we put parameters in it. */ + unsigned *next_arg = stack + 6; /* 6 reserved positions. */ + + int i = ecif->cif->nargs; + double double_tmp; + void **p_argv = ecif->avalue; + unsigned gprvalue; + ffi_type** ptr = ecif->cif->arg_types; + char *dest_cpy; + unsigned size_al = 0; + + /* Check that everything starts aligned properly. */ + FFI_ASSERT(((unsigned)(char *)stack & 0xF) == 0); + FFI_ASSERT(((unsigned)(char *)stacktop & 0xF) == 0); + FFI_ASSERT((bytes & 0xF) == 0); + + /* Deal with return values that are actually pass-by-reference. + Rule: + Return values are referenced by r3, so r4 is the first parameter. */ + + if (flags & FLAG_RETVAL_REFERENCE) + *next_arg++ = (unsigned)(char *)ecif->rvalue; + + /* Now for the arguments. */ + for (; + i > 0; + i--, ptr++, p_argv++) + { + switch ((*ptr)->type) + { + /* If a floating-point parameter appears before all of the general- + purpose registers are filled, the corresponding GPRs that match + the size of the floating-point parameter are skipped. */ + case FFI_TYPE_FLOAT: + double_tmp = *(float *)*p_argv; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + *(double *)next_arg = double_tmp; + else + *fpr_base++ = double_tmp; + next_arg++; + fparg_count++; + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; + + case FFI_TYPE_DOUBLE: + double_tmp = *(double *)*p_argv; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + *(double *)next_arg = double_tmp; + else + *fpr_base++ = double_tmp; + next_arg += 2; + fparg_count++; + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: + double_tmp = ((double *)*p_argv)[0]; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + *(double *)next_arg = double_tmp; + else + *fpr_base++ = double_tmp; + next_arg += 2; + fparg_count++; + double_tmp = ((double *)*p_argv)[1]; + if (fparg_count >= NUM_FPR_ARG_REGISTERS) + *(double *)next_arg = double_tmp; + else + *fpr_base++ = double_tmp; + next_arg += 2; + fparg_count++; + FFI_ASSERT(flags & FLAG_FP_ARGUMENTS); + break; +#endif + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + *(long long *)next_arg = *(long long *)*p_argv; + next_arg+=2; + break; + case FFI_TYPE_UINT8: + gprvalue = *(unsigned char *)*p_argv; + goto putgpr; + case FFI_TYPE_SINT8: + gprvalue = *(signed char *)*p_argv; + goto putgpr; + case FFI_TYPE_UINT16: + gprvalue = *(unsigned short *)*p_argv; + goto putgpr; + case FFI_TYPE_SINT16: + gprvalue = *(signed short *)*p_argv; + goto putgpr; + + case FFI_TYPE_STRUCT: + dest_cpy = (char *) next_arg; + + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. + Structures with 3 byte in size are padded upwards. */ + size_al = (*ptr)->size; + /* If the first member of the struct is a double, then align + the struct to double-word. + Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */ + if ((*ptr)->elements[0]->type == 3) + size_al = ALIGN((*ptr)->size, 8); + if (size_al < 3 && ecif->cif->abi == FFI_DARWIN) + dest_cpy += 4 - size_al; + + memcpy((char *)dest_cpy, (char *)*p_argv, size_al); + next_arg += (size_al + 3) / 4; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_POINTER: + gprvalue = *(unsigned *)*p_argv; + putgpr: + *next_arg++ = gprvalue; + break; + default: + break; + } + } + + /* Check that we didn't overrun the stack... */ + //FFI_ASSERT(gpr_base <= stacktop - ASM_NEEDS_REGISTERS); + //FFI_ASSERT((unsigned *)fpr_base + // <= stacktop - ASM_NEEDS_REGISTERS - NUM_GPR_ARG_REGISTERS); + //FFI_ASSERT(flags & FLAG_4_GPR_ARGUMENTS || intarg_count <= 4); +} + +/* Perform machine dependent cif processing. */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* All this is for the DARWIN ABI. */ + int i; + ffi_type **ptr; + unsigned bytes; + int fparg_count = 0, intarg_count = 0; + unsigned flags = 0; + unsigned size_al = 0; + + /* All the machine-independent calculation of cif->bytes will be wrong. + Redo the calculation for DARWIN. */ + + /* Space for the frame pointer, callee's LR, CR, etc, and for + the asm's temp regs. */ + + bytes = (6 + ASM_NEEDS_REGISTERS) * sizeof(long); + + /* Return value handling. The rules are as follows: + - 32-bit (or less) integer values are returned in gpr3; + - Structures of size <= 4 bytes also returned in gpr3; + - 64-bit integer values and structures between 5 and 8 bytes are returned + in gpr3 and gpr4; + - Single/double FP values are returned in fpr1; + - Long double FP (if not equivalent to double) values are returned in + fpr1 and fpr2; + - Larger structures values are allocated space and a pointer is passed + as the first argument. */ + switch (cif->rtype->type) + { + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: + flags |= FLAG_RETURNS_128BITS; + flags |= FLAG_RETURNS_FP; + break; +#endif + + case FFI_TYPE_DOUBLE: + flags |= FLAG_RETURNS_64BITS; + /* Fall through. */ + case FFI_TYPE_FLOAT: + flags |= FLAG_RETURNS_FP; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + flags |= FLAG_RETURNS_64BITS; + break; + + case FFI_TYPE_STRUCT: + flags |= FLAG_RETVAL_REFERENCE; + flags |= FLAG_RETURNS_NOTHING; + intarg_count++; + break; + case FFI_TYPE_VOID: + flags |= FLAG_RETURNS_NOTHING; + break; + + default: + /* Returns 32-bit integer, or similar. Nothing to do here. */ + break; + } + + /* The first NUM_GPR_ARG_REGISTERS words of integer arguments, and the + first NUM_FPR_ARG_REGISTERS fp arguments, go in registers; the rest + goes on the stack. Structures are passed as a pointer to a copy of + the structure. Stuff on the stack needs to keep proper alignment. */ + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + switch ((*ptr)->type) + { + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + fparg_count++; + /* If this FP arg is going on the stack, it must be + 8-byte-aligned. */ + if (fparg_count > NUM_FPR_ARG_REGISTERS + && intarg_count%2 != 0) + intarg_count++; + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: + fparg_count += 2; + /* If this FP arg is going on the stack, it must be + 8-byte-aligned. */ + if (fparg_count > NUM_FPR_ARG_REGISTERS + && intarg_count%2 != 0) + intarg_count++; + intarg_count +=2; + break; +#endif + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + /* 'long long' arguments are passed as two words, but + either both words must fit in registers or both go + on the stack. If they go on the stack, they must + be 8-byte-aligned. */ + if (intarg_count == NUM_GPR_ARG_REGISTERS-1 + || (intarg_count >= NUM_GPR_ARG_REGISTERS && intarg_count%2 != 0)) + intarg_count++; + intarg_count += 2; + break; + + case FFI_TYPE_STRUCT: + size_al = (*ptr)->size; + /* If the first member of the struct is a double, then align + the struct to double-word. + Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */ + if ((*ptr)->elements[0]->type == 3) + size_al = ALIGN((*ptr)->size, 8); + intarg_count += (size_al + 3) / 4; + break; + + default: + /* Everything else is passed as a 4-byte word in a GPR, either + the object itself or a pointer to it. */ + intarg_count++; + break; + } + } + + if (fparg_count != 0) + flags |= FLAG_FP_ARGUMENTS; + + /* Space for the FPR registers, if needed. */ + if (fparg_count != 0) + bytes += NUM_FPR_ARG_REGISTERS * sizeof(double); + + /* Stack space. */ + if ((intarg_count + 2 * fparg_count) > NUM_GPR_ARG_REGISTERS) + bytes += (intarg_count + 2 * fparg_count) * sizeof(long); + else + bytes += NUM_GPR_ARG_REGISTERS * sizeof(long); + + /* The stack space allocated needs to be a multiple of 16 bytes. */ + bytes = (bytes + 15) & ~0xF; + + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_AIX(/*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)(void), + void (*fn2)(extended_cif *, unsigned *const)); +extern void ffi_call_DARWIN(/*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)(void), + void (*fn2)(extended_cif *, unsigned *const)); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(void), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return + value address then we need to make one. */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_AIX: + /*@-usedef@*/ + ffi_call_AIX(&ecif, -cif->bytes, + cif->flags, ecif.rvalue, fn, ffi_prep_args); + /*@=usedef@*/ + break; + case FFI_DARWIN: + /*@-usedef@*/ + ffi_call_DARWIN(&ecif, -cif->bytes, + cif->flags, ecif.rvalue, fn, ffi_prep_args); + /*@=usedef@*/ + break; + default: + FFI_ASSERT(0); + break; + } +} + +static void flush_icache(char *); +static void flush_range(char *, int); + +/* The layout of a function descriptor. A C function pointer really + points to one of these. */ + +typedef struct aix_fd_struct { + void *code_pointer; + void *toc; +} aix_fd; + +/* here I'd like to add the stack frame layout we use in darwin_closure.S + and aix_clsoure.S + + SP previous -> +---------------------------------------+ <--- child frame + | back chain to caller 4 | + +---------------------------------------+ 4 + | saved CR 4 | + +---------------------------------------+ 8 + | saved LR 4 | + +---------------------------------------+ 12 + | reserved for compilers 4 | + +---------------------------------------+ 16 + | reserved for binders 4 | + +---------------------------------------+ 20 + | saved TOC pointer 4 | + +---------------------------------------+ 24 + | always reserved 8*4=32 (previous GPRs)| + | according to the linkage convention | + | from AIX | + +---------------------------------------+ 56 + | our FPR area 13*8=104 | + | f1 | + | . | + | f13 | + +---------------------------------------+ 160 + | result area 8 | + +---------------------------------------+ 168 + | alignement to the next multiple of 16 | +SP current --> +---------------------------------------+ 176 <- parent frame + | back chain to caller 4 | + +---------------------------------------+ 180 + | saved CR 4 | + +---------------------------------------+ 184 + | saved LR 4 | + +---------------------------------------+ 188 + | reserved for compilers 4 | + +---------------------------------------+ 192 + | reserved for binders 4 | + +---------------------------------------+ 196 + | saved TOC pointer 4 | + +---------------------------------------+ 200 + | always reserved 8*4=32 we store our | + | GPRs here | + | r3 | + | . | + | r10 | + +---------------------------------------+ 232 + | overflow part | + +---------------------------------------+ xxx + | ???? | + +---------------------------------------+ xxx + +*/ +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp; + struct ffi_aix_trampoline_struct *tramp_aix; + aix_fd *fd; + + switch (cif->abi) + { + case FFI_DARWIN: + + FFI_ASSERT (cif->abi == FFI_DARWIN); + + tramp = (unsigned int *) &closure->tramp[0]; + tramp[0] = 0x7c0802a6; /* mflr r0 */ + tramp[1] = 0x429f000d; /* bcl- 20,4*cr7+so,0x10 */ + tramp[4] = 0x7d6802a6; /* mflr r11 */ + tramp[5] = 0x818b0000; /* lwz r12,0(r11) function address */ + tramp[6] = 0x7c0803a6; /* mtlr r0 */ + tramp[7] = 0x7d8903a6; /* mtctr r12 */ + tramp[8] = 0x816b0004; /* lwz r11,4(r11) static chain */ + tramp[9] = 0x4e800420; /* bctr */ + tramp[2] = (unsigned long) ffi_closure_ASM; /* function */ + tramp[3] = (unsigned long) closure; /* context */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the icache. Only necessary on Darwin. */ + flush_range(&closure->tramp[0],FFI_TRAMPOLINE_SIZE); + + break; + + case FFI_AIX: + + tramp_aix = (struct ffi_aix_trampoline_struct *) (closure->tramp); + fd = (aix_fd *)(void *)ffi_closure_ASM; + + FFI_ASSERT (cif->abi == FFI_AIX); + + tramp_aix->code_pointer = fd->code_pointer; + tramp_aix->toc = fd->toc; + tramp_aix->static_chain = closure; + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + default: + + FFI_ASSERT(0); + break; + } + return FFI_OK; +} + +static void +flush_icache(char *addr) +{ +#ifndef _AIX + __asm__ volatile ( + "dcbf 0,%0\n" + "\tsync\n" + "\ticbi 0,%0\n" + "\tsync\n" + "\tisync" + : : "r"(addr) : "memory"); +#endif +} + +static void +flush_range(char * addr1, int size) +{ +#define MIN_LINE_SIZE 32 + int i; + for (i = 0; i < size; i += MIN_LINE_SIZE) + flush_icache(addr1+i); + flush_icache(addr1+size-1); +} + +typedef union +{ + float f; + double d; +} ffi_dblfl; + +int ffi_closure_helper_DARWIN (ffi_closure*, void*, + unsigned long*, ffi_dblfl*); + +/* Basically the trampoline invokes ffi_closure_ASM, and on + entry, r11 holds the address of the closure. + After storing the registers that could possibly contain + parameters to be passed into the stack frame and setting + up space for a return value, ffi_closure_ASM invokes the + following helper function to do most of the work. */ + +int ffi_closure_helper_DARWIN (ffi_closure* closure, void * rvalue, + unsigned long * pgr, ffi_dblfl * pfr) +{ + /* rvalue is the pointer to space for return value in closure assembly + pgr is the pointer to where r3-r10 are stored in ffi_closure_ASM + pfr is the pointer to where f1-f13 are stored in ffi_closure_ASM. */ + + typedef double ldbits[2]; + + union ldu + { + ldbits lb; + long double ld; + }; + + void ** avalue; + ffi_type ** arg_types; + long i, avn; + long nf; /* number of floating registers already used. */ + long ng; /* number of general registers already used. */ + ffi_cif * cif; + double temp; + unsigned size_al; + union ldu temp_ld; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + nf = 0; + ng = 0; + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + rvalue = (void *) *pgr; + pgr++; + ng++; + } + + i = 0; + avn = cif->nargs; + arg_types = cif->arg_types; + + /* Grab the addresses of the arguments from the stack frame. */ + while (i < avn) + { + switch (arg_types[i]->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (char *) pgr + 3; + ng++; + pgr++; + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (char *) pgr + 2; + ng++; + pgr++; + break; + + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_POINTER: + avalue[i] = pgr; + ng++; + pgr++; + break; + + case FFI_TYPE_STRUCT: + /* Structures that match the basic modes (QI 1 byte, HI 2 bytes, + SI 4 bytes) are aligned as if they were those modes. */ + size_al = arg_types[i]->size; + /* If the first member of the struct is a double, then align + the struct to double-word. + Type 3 is defined in include/ffi.h. #define FFI_TYPE_DOUBLE 3. */ + if (arg_types[i]->elements[0]->type == 3) + size_al = ALIGN(arg_types[i]->size, 8); + if (size_al < 3 && cif->abi == FFI_DARWIN) + avalue[i] = (void*) pgr + 4 - size_al; + else + avalue[i] = (void*) pgr; + ng += (size_al + 3) / 4; + pgr += (size_al + 3) / 4; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + /* Long long ints are passed in two gpr's. */ + avalue[i] = pgr; + ng += 2; + pgr += 2; + break; + + case FFI_TYPE_FLOAT: + /* A float value consumes a GPR. + There are 13 64bit floating point registers. */ + if (nf < NUM_FPR_ARG_REGISTERS) + { + temp = pfr->d; + pfr->f = (float)temp; + avalue[i] = pfr; + pfr++; + } + else + { + avalue[i] = pgr; + } + nf++; + ng++; + pgr++; + break; + + case FFI_TYPE_DOUBLE: + /* A double value consumes two GPRs. + There are 13 64bit floating point registers. */ + if (nf < NUM_FPR_ARG_REGISTERS) + { + avalue[i] = pfr; + pfr++; + } + else + { + avalue[i] = pgr; + } + nf++; + ng += 2; + pgr += 2; + break; + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + + case FFI_TYPE_LONGDOUBLE: + /* A long double value consumes four GPRs and two FPRs. + There are 13 64bit floating point registers. */ + if (nf < NUM_FPR_ARG_REGISTERS - 1) + { + avalue[i] = pfr; + pfr += 2; + } + /* Here we have the situation where one part of the long double + is stored in fpr13 and the other part is already on the stack. + We use a union to pass the long double to avalue[i]. */ + else if (nf == NUM_FPR_ARG_REGISTERS - 1) + { + memcpy (&temp_ld.lb[0], pfr, sizeof(ldbits)); + memcpy (&temp_ld.lb[1], pgr + 2, sizeof(ldbits)); + avalue[i] = &temp_ld.ld; + } + else + { + avalue[i] = pgr; + } + nf += 2; + ng += 4; + pgr += 4; + break; +#endif + default: + FFI_ASSERT(0); + } + i++; + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_ASM to perform return type promotions. */ + return cif->rtype->type; +} +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffitarget.h new file mode 100644 index 000000000..af63796c7 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ffitarget.h @@ -0,0 +1,100 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for PowerPC. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#if defined (POWERPC) && defined (__powerpc64__) +#define POWERPC64 +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + +#ifdef POWERPC + FFI_SYSV, + FFI_GCC_SYSV, + FFI_LINUX64, +# ifdef POWERPC64 + FFI_DEFAULT_ABI = FFI_LINUX64, +# else + FFI_DEFAULT_ABI = FFI_GCC_SYSV, +# endif +#endif + +#ifdef POWERPC_AIX + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_AIX, +#endif + +#ifdef POWERPC_DARWIN + FFI_AIX, + FFI_DARWIN, + FFI_DEFAULT_ABI = FFI_DARWIN, +#endif + +#ifdef POWERPC_FREEBSD + FFI_SYSV, + FFI_GCC_SYSV, + FFI_LINUX64, + FFI_DEFAULT_ABI = FFI_SYSV, +#endif + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +/* Needed for FFI_SYSV small structure returns. */ +#define FFI_SYSV_TYPE_SMALL_STRUCT (FFI_TYPE_LAST) + +#if defined(POWERPC64) || defined(POWERPC_AIX) +#define FFI_TRAMPOLINE_SIZE 24 +#else /* POWERPC || POWERPC_AIX */ +#define FFI_TRAMPOLINE_SIZE 40 +#endif + +#ifndef LIBFFI_ASM +#if defined(POWERPC_DARWIN) || defined(POWERPC_AIX) +struct ffi_aix_trampoline_struct { + void * code_pointer; /* Pointer to ffi_closure_ASM */ + void * toc; /* TOC */ + void * static_chain; /* Pointer to closure */ +}; +#endif +#endif + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64.S new file mode 100644 index 000000000..25b2c4f45 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64.S @@ -0,0 +1,180 @@ +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com> + + PowerPC64 Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#ifdef __powerpc64__ + .hidden ffi_call_LINUX64, .ffi_call_LINUX64 + .globl ffi_call_LINUX64, .ffi_call_LINUX64 + .section ".opd","aw" + .align 3 +ffi_call_LINUX64: + .quad .ffi_call_LINUX64,.TOC.@tocbase,0 + .size ffi_call_LINUX64,24 + .type .ffi_call_LINUX64,@function + .text +.ffi_call_LINUX64: +.LFB1: + mflr %r0 + std %r28, -32(%r1) + std %r29, -24(%r1) + std %r30, -16(%r1) + std %r31, -8(%r1) + std %r0, 16(%r1) + + mr %r28, %r1 /* our AP. */ + stdux %r1, %r1, %r4 +.LCFI0: + mr %r31, %r5 /* flags, */ + mr %r30, %r6 /* rvalue, */ + mr %r29, %r7 /* function address. */ + std %r2, 40(%r1) + + /* Call ffi_prep_args64. */ + mr %r4, %r1 + bl .ffi_prep_args64 + + ld %r0, 0(%r29) + ld %r2, 8(%r29) + ld %r11, 16(%r29) + + /* Now do the call. */ + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40, %r31 + + /* Get the address to call into CTR. */ + mtctr %r0 + /* Load all those argument registers. */ + ld %r3, -32-(8*8)(%r28) + ld %r4, -32-(7*8)(%r28) + ld %r5, -32-(6*8)(%r28) + ld %r6, -32-(5*8)(%r28) + bf- 5, 1f + ld %r7, -32-(4*8)(%r28) + ld %r8, -32-(3*8)(%r28) + ld %r9, -32-(2*8)(%r28) + ld %r10, -32-(1*8)(%r28) +1: + + /* Load all the FP registers. */ + bf- 6, 2f + lfd %f1, -32-(21*8)(%r28) + lfd %f2, -32-(20*8)(%r28) + lfd %f3, -32-(19*8)(%r28) + lfd %f4, -32-(18*8)(%r28) + lfd %f5, -32-(17*8)(%r28) + lfd %f6, -32-(16*8)(%r28) + lfd %f7, -32-(15*8)(%r28) + lfd %f8, -32-(14*8)(%r28) + lfd %f9, -32-(13*8)(%r28) + lfd %f10, -32-(12*8)(%r28) + lfd %f11, -32-(11*8)(%r28) + lfd %f12, -32-(10*8)(%r28) + lfd %f13, -32-(9*8)(%r28) +2: + + /* Make the call. */ + bctrl + + /* Now, deal with the return value. */ + mtcrf 0x01, %r31 + bt- 30, .Ldone_return_value + bt- 29, .Lfp_return_value + std %r3, 0(%r30) + /* Fall through... */ + +.Ldone_return_value: + /* Restore the registers we used and return. */ + ld %r2, 40(%r1) + mr %r1, %r28 + ld %r0, 16(%r28) + ld %r28, -32(%r1) + mtlr %r0 + ld %r29, -24(%r1) + ld %r30, -16(%r1) + ld %r31, -8(%r1) + blr + +.Lfp_return_value: + bt 27, .Lfd_return_value + bf 28, .Lfloat_return_value + stfd %f1, 0(%r30) + b .Ldone_return_value +.Lfd_return_value: + stfd %f1, 0(%r30) + stfd %f2, 8(%r30) + b .Ldone_return_value +.Lfloat_return_value: + stfs %f1, 0(%r30) + b .Ldone_return_value +.LFE1: + .long 0 + .byte 0,12,0,1,128,4,0,0 + .size .ffi_call_LINUX64,.-.ffi_call_LINUX64 + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -8 # CIE Data Alignment Factor + .byte 0x41 # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x14 # FDE Encoding (pcrel udata8) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1 + .uleb128 0x0 + .align 3 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .8byte .LFB1-. # FDE initial location + .8byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x2 # DW_CFA_advance_loc1 + .byte .LCFI0-.LFB1 + .byte 0xd # DW_CFA_def_cfa_register + .uleb128 0x1c + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x41 + .sleb128 -2 + .byte 0x9f # DW_CFA_offset, column 0x1f + .uleb128 0x1 + .byte 0x9e # DW_CFA_offset, column 0x1e + .uleb128 0x2 + .byte 0x9d # DW_CFA_offset, column 0x1d + .uleb128 0x3 + .byte 0x9c # DW_CFA_offset, column 0x1c + .uleb128 0x4 + .align 3 +.LEFDE1: +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64_closure.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64_closure.S new file mode 100644 index 000000000..b19bc718b --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/linux64_closure.S @@ -0,0 +1,206 @@ +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + + .file "linux64_closure.S" + +#ifdef __powerpc64__ + FFI_HIDDEN (ffi_closure_LINUX64) + FFI_HIDDEN (.ffi_closure_LINUX64) + .globl ffi_closure_LINUX64, .ffi_closure_LINUX64 + .section ".opd","aw" + .align 3 +ffi_closure_LINUX64: + .quad .ffi_closure_LINUX64,.TOC.@tocbase,0 + .size ffi_closure_LINUX64,24 + .type .ffi_closure_LINUX64,@function + .text +.ffi_closure_LINUX64: +.LFB1: + # save general regs into parm save area + std %r3, 48(%r1) + std %r4, 56(%r1) + std %r5, 64(%r1) + std %r6, 72(%r1) + mflr %r0 + + std %r7, 80(%r1) + std %r8, 88(%r1) + std %r9, 96(%r1) + std %r10, 104(%r1) + std %r0, 16(%r1) + + # mandatory 48 bytes special reg save area + 64 bytes parm save area + # + 16 bytes retval area + 13*8 bytes fpr save area + round to 16 + stdu %r1, -240(%r1) +.LCFI0: + + # next save fpr 1 to fpr 13 + stfd %f1, 128+(0*8)(%r1) + stfd %f2, 128+(1*8)(%r1) + stfd %f3, 128+(2*8)(%r1) + stfd %f4, 128+(3*8)(%r1) + stfd %f5, 128+(4*8)(%r1) + stfd %f6, 128+(5*8)(%r1) + stfd %f7, 128+(6*8)(%r1) + stfd %f8, 128+(7*8)(%r1) + stfd %f9, 128+(8*8)(%r1) + stfd %f10, 128+(9*8)(%r1) + stfd %f11, 128+(10*8)(%r1) + stfd %f12, 128+(11*8)(%r1) + stfd %f13, 128+(12*8)(%r1) + + # set up registers for the routine that actually does the work + # get the context pointer from the trampoline + mr %r3, %r11 + + # now load up the pointer to the result storage + addi %r4, %r1, 112 + + # now load up the pointer to the parameter save area + # in the previous frame + addi %r5, %r1, 240 + 48 + + # now load up the pointer to the saved fpr registers */ + addi %r6, %r1, 128 + + # make the call + bl .ffi_closure_helper_LINUX64 +.Lret: + + # now r3 contains the return type + # so use it to look up in a table + # so we know how to deal with each type + + # look up the proper starting point in table + # by using return type as offset + mflr %r4 # move address of .Lret to r4 + sldi %r3, %r3, 4 # now multiply return type by 16 + addi %r4, %r4, .Lret_type0 - .Lret + ld %r0, 240+16(%r1) + add %r3, %r3, %r4 # add contents of table to table address + mtctr %r3 + bctr # jump to it + +# Each of the ret_typeX code fragments has to be exactly 16 bytes long +# (4 instructions). For cache effectiveness we align to a 16 byte boundary +# first. + .align 4 + +.Lret_type0: +# case FFI_TYPE_VOID + mtlr %r0 + addi %r1, %r1, 240 + blr + nop +# case FFI_TYPE_INT + lwa %r3, 112+4(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_FLOAT + lfs %f1, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_DOUBLE + lfd %f1, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_LONGDOUBLE + lfd %f1, 112+0(%r1) + mtlr %r0 + lfd %f2, 112+8(%r1) + b .Lfinish +# case FFI_TYPE_UINT8 + lbz %r3, 112+7(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT8 + lbz %r3, 112+7(%r1) + extsb %r3,%r3 + mtlr %r0 + b .Lfinish +# case FFI_TYPE_UINT16 + lhz %r3, 112+6(%r1) + mtlr %r0 +.Lfinish: + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT16 + lha %r3, 112+6(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_UINT32 + lwz %r3, 112+4(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT32 + lwa %r3, 112+4(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_UINT64 + ld %r3, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_SINT64 + ld %r3, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# case FFI_TYPE_STRUCT + mtlr %r0 + addi %r1, %r1, 240 + blr + nop +# case FFI_TYPE_POINTER + ld %r3, 112+0(%r1) + mtlr %r0 + addi %r1, %r1, 240 + blr +# esac +.LFE1: + .long 0 + .byte 0,12,0,1,128,0,0,0 + .size .ffi_closure_LINUX64,.-.ffi_closure_LINUX64 + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -8 # CIE Data Alignment Factor + .byte 0x41 # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x14 # FDE Encoding (pcrel udata8) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1 + .uleb128 0x0 + .align 3 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .8byte .LFB1-. # FDE initial location + .8byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x2 # DW_CFA_advance_loc1 + .byte .LCFI0-.LFB1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 240 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x41 + .sleb128 -2 + .align 3 +.LEFDE1: +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ppc_closure.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ppc_closure.S new file mode 100644 index 000000000..370381378 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/ppc_closure.S @@ -0,0 +1,323 @@ +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#include <powerpc/asm.h> + + .file "ppc_closure.S" + +#ifndef __powerpc64__ + +ENTRY(ffi_closure_SYSV) +.LFB1: + stwu %r1,-144(%r1) +.LCFI0: + mflr %r0 +.LCFI1: + stw %r0,148(%r1) + +# we want to build up an areas for the parameters passed +# in registers (both floating point and integer) + + # so first save gpr 3 to gpr 10 (aligned to 4) + stw %r3, 16(%r1) + stw %r4, 20(%r1) + stw %r5, 24(%r1) + stw %r6, 28(%r1) + stw %r7, 32(%r1) + stw %r8, 36(%r1) + stw %r9, 40(%r1) + stw %r10,44(%r1) + + # next save fpr 1 to fpr 8 (aligned to 8) + stfd %f1, 48(%r1) + stfd %f2, 56(%r1) + stfd %f3, 64(%r1) + stfd %f4, 72(%r1) + stfd %f5, 80(%r1) + stfd %f6, 88(%r1) + stfd %f7, 96(%r1) + stfd %f8, 104(%r1) + + # set up registers for the routine that actually does the work + # get the context pointer from the trampoline + mr %r3,%r11 + + # now load up the pointer to the result storage + addi %r4,%r1,112 + + # now load up the pointer to the saved gpr registers + addi %r5,%r1,16 + + # now load up the pointer to the saved fpr registers */ + addi %r6,%r1,48 + + # now load up the pointer to the outgoing parameter + # stack in the previous frame + # i.e. the previous frame pointer + 8 + addi %r7,%r1,152 + + # make the call + bl ffi_closure_helper_SYSV@local + + # now r3 contains the return type + # so use it to look up in a table + # so we know how to deal with each type + + # look up the proper starting point in table + # by using return type as offset + addi %r6,%r1,112 # get pointer to results area + bl .Lget_ret_type0_addr # get pointer to .Lret_type0 into LR + mflr %r4 # move to r4 + slwi %r3,%r3,4 # now multiply return type by 16 + add %r3,%r3,%r4 # add contents of table to table address + mtctr %r3 + bctr # jump to it +.LFE1: + +# Each of the ret_typeX code fragments has to be exactly 16 bytes long +# (4 instructions). For cache effectiveness we align to a 16 byte boundary +# first. + .align 4 + + nop + nop + nop +.Lget_ret_type0_addr: + blrl + +# case FFI_TYPE_VOID +.Lret_type0: + b .Lfinish + nop + nop + nop + +# case FFI_TYPE_INT +.Lret_type1: + lwz %r3,0(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_FLOAT +.Lret_type2: + lfs %f1,0(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_DOUBLE +.Lret_type3: + lfd %f1,0(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_LONGDOUBLE +.Lret_type4: + lfd %f1,0(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_UINT8 +.Lret_type5: + lbz %r3,3(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_SINT8 +.Lret_type6: + lbz %r3,3(%r6) + extsb %r3,%r3 + b .Lfinish + nop + +# case FFI_TYPE_UINT16 +.Lret_type7: + lhz %r3,2(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_SINT16 +.Lret_type8: + lha %r3,2(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_UINT32 +.Lret_type9: + lwz %r3,0(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_SINT32 +.Lret_type10: + lwz %r3,0(%r6) + b .Lfinish + nop + nop + +# case FFI_TYPE_UINT64 +.Lret_type11: + lwz %r3,0(%r6) + lwz %r4,4(%r6) + b .Lfinish + nop + +# case FFI_TYPE_SINT64 +.Lret_type12: + lwz %r3,0(%r6) + lwz %r4,4(%r6) + b .Lfinish + nop + +# case FFI_TYPE_STRUCT +.Lret_type13: + b .Lfinish + nop + nop + nop + +# case FFI_TYPE_POINTER +.Lret_type14: + lwz %r3,0(%r6) + b .Lfinish + nop + nop + +# The return types below are only used when the ABI type is FFI_SYSV. +# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct. +.Lret_type15: +# fall through. + lbz %r3,0(%r6) + b .Lfinish + nop + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct. +.Lret_type16: +# fall through. + lhz %r3,0(%r6) + b .Lfinish + nop + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct. +.Lret_type17: +# fall through. + lwz %r3,0(%r6) + srwi %r3,%r3,8 + b .Lfinish + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct. +.Lret_type18: +# this one handles the structs from above too. + lwz %r3,0(%r6) + b .Lfinish + nop + nop + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct. +.Lret_type19: +# fall through. + lwz %r3,0(%r6) + lwz %r4,4(%r6) + li %r5,24 + b .Lstruct567 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct. +.Lret_type20: +# fall through. + lwz %r3,0(%r6) + lwz %r4,4(%r6) + li %r5,16 + b .Lstruct567 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct. +.Lret_type21: +# fall through. + lwz %r3,0(%r6) + lwz %r4,4(%r6) + li %r5,8 + b .Lstruct567 + +# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct. +.Lret_type22: +# this one handles the above unhandled structs. + lwz %r3,0(%r6) + lwz %r4,4(%r6) + b .Lfinish + nop + +# case done +.Lfinish: + + lwz %r0,148(%r1) + mtlr %r0 + addi %r1,%r1,144 + blr + +.Lstruct567: + subfic %r0,%r5,32 + srw %r4,%r4,%r5 + slw %r0,%r3,%r0 + srw %r3,%r3,%r5 + or %r4,%r0,%r4 + b .Lfinish +END(ffi_closure_SYSV) + + .section ".eh_frame",EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version +#if defined _RELOCATABLE || defined __PIC__ + .ascii "zR\0" # CIE Augmentation +#else + .ascii "\0" # CIE Augmentation +#endif + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -4 # CIE Data Alignment Factor + .byte 0x41 # CIE RA Column +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x1 # Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) +#endif + .byte 0xc # DW_CFA_def_cfa + .uleb128 0x1 + .uleb128 0x0 + .align 2 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset +#if defined _RELOCATABLE || defined __PIC__ + .4byte .LFB1-. # FDE initial location +#else + .4byte .LFB1 # FDE initial location +#endif + .4byte .LFE1-.LFB1 # FDE address range +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x0 # Augmentation size +#endif + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 144 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 + .byte 0x11 # DW_CFA_offset_extended_sf + .uleb128 0x41 + .sleb128 -1 + .align 2 +.LEFDE1: + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/sysv.S new file mode 100644 index 000000000..6d5a707ec --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/powerpc/sysv.S @@ -0,0 +1,217 @@ +/* ----------------------------------------------------------------------- + sysv.h - Copyright (c) 1998 Geoffrey Keating + + PowerPC Assembly glue. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#include <powerpc/asm.h> + +#ifndef __powerpc64__ + .globl ffi_prep_args_SYSV +ENTRY(ffi_call_SYSV) +.LFB1: + /* Save the old stack pointer as AP. */ + mr %r8,%r1 + +.LCFI0: + /* Allocate the stack space we need. */ + stwux %r1,%r1,%r4 + /* Save registers we use. */ + mflr %r9 + stw %r28,-16(%r8) +.LCFI1: + stw %r29,-12(%r8) +.LCFI2: + stw %r30, -8(%r8) +.LCFI3: + stw %r31, -4(%r8) +.LCFI4: + stw %r9, 4(%r8) +.LCFI5: + + /* Save arguments over call... */ + mr %r31,%r5 /* flags, */ + mr %r30,%r6 /* rvalue, */ + mr %r29,%r7 /* function address, */ + mr %r28,%r8 /* our AP. */ +.LCFI6: + + /* Call ffi_prep_args_SYSV. */ + mr %r4,%r1 + bl ffi_prep_args_SYSV@local + + /* Now do the call. */ + /* Set up cr1 with bits 4-7 of the flags. */ + mtcrf 0x40,%r31 + /* Get the address to call into CTR. */ + mtctr %r29 + /* Load all those argument registers. */ + lwz %r3,-16-(8*4)(%r28) + lwz %r4,-16-(7*4)(%r28) + lwz %r5,-16-(6*4)(%r28) + lwz %r6,-16-(5*4)(%r28) + bf- 5,1f + nop + lwz %r7,-16-(4*4)(%r28) + lwz %r8,-16-(3*4)(%r28) + lwz %r9,-16-(2*4)(%r28) + lwz %r10,-16-(1*4)(%r28) + nop +1: + + /* Load all the FP registers. */ + bf- 6,2f + lfd %f1,-16-(8*4)-(8*8)(%r28) + lfd %f2,-16-(8*4)-(7*8)(%r28) + lfd %f3,-16-(8*4)-(6*8)(%r28) + lfd %f4,-16-(8*4)-(5*8)(%r28) + nop + lfd %f5,-16-(8*4)-(4*8)(%r28) + lfd %f6,-16-(8*4)-(3*8)(%r28) + lfd %f7,-16-(8*4)-(2*8)(%r28) + lfd %f8,-16-(8*4)-(1*8)(%r28) +2: + + /* Make the call. */ + bctrl + + /* Now, deal with the return value. */ + mtcrf 0x01,%r31 + bt- 31,L(small_struct_return_value) + bt- 30,L(done_return_value) + bt- 29,L(fp_return_value) + stw %r3,0(%r30) + bf+ 28,L(done_return_value) + stw %r4,4(%r30) + /* Fall through... */ + +L(done_return_value): + /* Restore the registers we used and return. */ + lwz %r9, 4(%r28) + lwz %r31, -4(%r28) + mtlr %r9 + lwz %r30, -8(%r28) + lwz %r29,-12(%r28) + lwz %r28,-16(%r28) + lwz %r1,0(%r1) + blr + +L(fp_return_value): + bf 28,L(float_return_value) + stfd %f1,0(%r30) + b L(done_return_value) +L(float_return_value): + stfs %f1,0(%r30) + b L(done_return_value) + +L(small_struct_return_value): + mtcrf 0x10,%r31 /* cr3 */ + bt- 15,L(smst_one_register) + mtcrf 0x08,%r31 /* cr4 */ + bt- 16,L(smst_two_register) + b L(done_return_value) + +L(smst_one_register): + rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */ + slw %r3,%r3,%r5 + stw %r3,0(%r30) + b L(done_return_value) +L(smst_two_register): + rlwinm %r5,%r31,5+23,32-5,31 /* Extract the value to shift. */ + cmpwi %r5,0 + subfic %r9,%r5,32 + slw %r29,%r3,%r5 + srw %r9,%r4,%r9 + beq- L(smst_8byte) + or %r3,%r9,%r29 + slw %r4,%r4,%r5 +L(smst_8byte): + stw %r3,0(%r30) + stw %r4,4(%r30) + b L(done_return_value) + +.LFE1: +END(ffi_call_SYSV) + + .section ".eh_frame",EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .4byte 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#if defined _RELOCATABLE || defined __PIC__ + .ascii "zR\0" /* CIE Augmentation */ +#else + .ascii "\0" /* CIE Augmentation */ +#endif + .uleb128 0x1 /* CIE Code Alignment Factor */ + .sleb128 -4 /* CIE Data Alignment Factor */ + .byte 0x41 /* CIE RA Column */ +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x1 /* Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .uleb128 0x1 + .uleb128 0x0 + .align 2 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .4byte .LASFDE1-.Lframe1 /* FDE CIE offset */ +#if defined _RELOCATABLE || defined __PIC__ + .4byte .LFB1-. /* FDE initial location */ +#else + .4byte .LFB1 /* FDE initial location */ +#endif + .4byte .LFE1-.LFB1 /* FDE address range */ +#if defined _RELOCATABLE || defined __PIC__ + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI0-.LFB1 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0x08 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI5-.LCFI0 + .byte 0x11 /* DW_CFA_offset_extended_sf */ + .uleb128 0x41 + .sleb128 -1 + .byte 0x9f /* DW_CFA_offset, column 0x1f */ + .uleb128 0x1 + .byte 0x9e /* DW_CFA_offset, column 0x1e */ + .uleb128 0x2 + .byte 0x9d /* DW_CFA_offset, column 0x1d */ + .uleb128 0x3 + .byte 0x9c /* DW_CFA_offset, column 0x1c */ + .uleb128 0x4 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI6-.LCFI5 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0x1c + .align 2 +.LEFDE1: +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/prep_cif.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/prep_cif.c new file mode 100644 index 000000000..2db65ce4d --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/prep_cif.c @@ -0,0 +1,210 @@ +/* ----------------------------------------------------------------------- + prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> + + +/* Round up to FFI_SIZEOF_ARG. */ + +#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) + +/* Perform machine independent initialization of aggregate type + specifications. */ + +static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) +{ + ffi_type **ptr; + + FFI_ASSERT(arg != NULL); + + /*@-usedef@*/ + + FFI_ASSERT(arg->elements != NULL); + FFI_ASSERT(arg->size == 0); + FFI_ASSERT(arg->alignment == 0); + + ptr = &(arg->elements[0]); + + while ((*ptr) != NULL) + { + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type */ + FFI_ASSERT_VALID_TYPE(*ptr); + +#ifdef POWERPC_DARWIN + { + int curalign; + + curalign = (*ptr)->alignment; + if (ptr != &(arg->elements[0])) { + if (curalign > 4 && curalign != 16) { + curalign = 4; + } + } + arg->size = ALIGN(arg->size, curalign); + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > curalign) ? + arg->alignment : curalign; + } +#else + arg->size = ALIGN(arg->size, (*ptr)->alignment); + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; +#endif + + ptr++; + } + + /* Structure size includes tail padding. This is important for + structures that fit in one register on ABIs like the PowerPC64 + Linux ABI that right justify small structs in a register. + It's also needed for nested structure layout, for example + struct A { long a; char b; }; struct B { struct A x; char y; }; + should find y at an offset of 2*sizeof(long) and result in a + total size of 3*sizeof(long). */ + arg->size = ALIGN (arg->size, arg->alignment); + + if (arg->size == 0) + return FFI_BAD_TYPEDEF; + else + return FFI_OK; + + /*@=usedef@*/ +} + +#ifndef __CRIS__ +/* The CRIS ABI specifies structure elements to have byte + alignment only, so it completely overrides this functions, + which assumes "natural" alignment and padding. */ + +/* Perform machine independent ffi_cif preparation, then call + machine dependent routine. */ + +#ifdef X86_DARWIN +static inline int struct_on_stack(int size) +{ + if (size > 8) return 1; + /* This is not what the ABI says, but is what is really implemented */ + switch (size) { + case 1: case 2: case 4: case 8: return 0; + } + return 1; +} +#endif + + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes) +{ + unsigned bytes = 0; + unsigned int i; + ffi_type **ptr; + + FFI_ASSERT(cif != NULL); + FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); + + cif->abi = abi; + cif->arg_types = atypes; + cif->nargs = nargs; + cif->rtype = rtype; + + cif->flags = 0; + + /* Initialize the return type if necessary */ + /*@-usedef@*/ + if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; + /*@=usedef@*/ + + /* Perform a sanity check on the return type */ + FFI_ASSERT_VALID_TYPE(cif->rtype); + + /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ +#if !defined M68K && !defined __x86_64__ && !defined S390 && !defined PA + /* Make space for the return structure pointer */ + if (cif->rtype->type == FFI_TYPE_STRUCT +#ifdef SPARC + && (cif->abi != FFI_V9 || cif->rtype->size > 32) +#endif +#ifdef X86_DARWIN + + && (struct_on_stack(cif->rtype->size)) +#endif + ) + bytes = STACK_ARG_SIZE(sizeof(void*)); +#endif + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + + /* Initialize any uninitialized aggregate type definitions */ + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type, do this + check after the initialization. */ + FFI_ASSERT_VALID_TYPE(*ptr); + +#if defined(X86_DARWIN) + { + int align = (*ptr)->alignment; + if (align > 4) align = 4; + if ((align - 1) & bytes) + bytes = ALIGN(bytes, align); + bytes += STACK_ARG_SIZE((*ptr)->size); + } + +#elif !defined __x86_64__ && !defined S390 && !defined PA +#ifdef SPARC + if (((*ptr)->type == FFI_TYPE_STRUCT + && ((*ptr)->size > 16 || cif->abi != FFI_V9)) + || ((*ptr)->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_V9)) + bytes += sizeof(void*); + else +#endif + { + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + + bytes += STACK_ARG_SIZE((*ptr)->size); + } +#endif + } + + cif->bytes = bytes; + + /* Perform machine dependent cif processing */ + return ffi_prep_cif_machdep(cif); +} +#endif /* not __CRIS__ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffi.c new file mode 100644 index 000000000..399fa2a91 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffi.c @@ -0,0 +1,751 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2000 Software AG + + S390 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ +/*====================================================================*/ +/* Includes */ +/* -------- */ +/*====================================================================*/ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <stdio.h> + +/*====================== End of Includes =============================*/ + +/*====================================================================*/ +/* Defines */ +/* ------- */ +/*====================================================================*/ + +/* Maximum number of GPRs available for argument passing. */ +#define MAX_GPRARGS 5 + +/* Maximum number of FPRs available for argument passing. */ +#ifdef __s390x__ +#define MAX_FPRARGS 4 +#else +#define MAX_FPRARGS 2 +#endif + +/* Round to multiple of 16. */ +#define ROUND_SIZE(size) (((size) + 15) & ~15) + +/* If these values change, sysv.S must be adapted! */ +#define FFI390_RET_VOID 0 +#define FFI390_RET_STRUCT 1 +#define FFI390_RET_FLOAT 2 +#define FFI390_RET_DOUBLE 3 +#define FFI390_RET_INT32 4 +#define FFI390_RET_INT64 5 + +/*===================== End of Defines ===============================*/ + +/*====================================================================*/ +/* Prototypes */ +/* ---------- */ +/*====================================================================*/ + +static void ffi_prep_args (unsigned char *, extended_cif *); +void +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2) +__attribute__ ((visibility ("hidden"))) +#endif +ffi_closure_helper_SYSV (ffi_closure *, unsigned long *, + unsigned long long *, unsigned long *); + +/*====================== End of Prototypes ===========================*/ + +/*====================================================================*/ +/* Externals */ +/* --------- */ +/*====================================================================*/ + +extern void ffi_call_SYSV(unsigned, + extended_cif *, + void (*)(unsigned char *, extended_cif *), + unsigned, + void *, + void (*fn)()); + +extern void ffi_closure_SYSV(void); + +/*====================== End of Externals ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_check_struct_type. */ +/* */ +/* Function - Determine if a structure can be passed within a */ +/* general purpose or floating point register. */ +/* */ +/*====================================================================*/ + +static int +ffi_check_struct_type (ffi_type *arg) +{ + size_t size = arg->size; + + /* If the struct has just one element, look at that element + to find out whether to consider the struct as floating point. */ + while (arg->type == FFI_TYPE_STRUCT + && arg->elements[0] && !arg->elements[1]) + arg = arg->elements[0]; + + /* Structs of size 1, 2, 4, and 8 are passed in registers, + just like the corresponding int/float types. */ + switch (size) + { + case 1: + return FFI_TYPE_UINT8; + + case 2: + return FFI_TYPE_UINT16; + + case 4: + if (arg->type == FFI_TYPE_FLOAT) + return FFI_TYPE_FLOAT; + else + return FFI_TYPE_UINT32; + + case 8: + if (arg->type == FFI_TYPE_DOUBLE) + return FFI_TYPE_DOUBLE; + else + return FFI_TYPE_UINT64; + + default: + break; + } + + /* Other structs are passed via a pointer to the data. */ + return FFI_TYPE_POINTER; +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_args. */ +/* */ +/* Function - Prepare parameters for call to function. */ +/* */ +/* ffi_prep_args is called by the assembly routine once stack space */ +/* has been allocated for the function's arguments. */ +/* */ +/*====================================================================*/ + +static void +ffi_prep_args (unsigned char *stack, extended_cif *ecif) +{ + /* The stack space will be filled with those areas: + + FPR argument register save area (highest addresses) + GPR argument register save area + temporary struct copies + overflow argument area (lowest addresses) + + We set up the following pointers: + + p_fpr: bottom of the FPR area (growing upwards) + p_gpr: bottom of the GPR area (growing upwards) + p_ov: bottom of the overflow area (growing upwards) + p_struct: top of the struct copy area (growing downwards) + + All areas are kept aligned to twice the word size. */ + + int gpr_off = ecif->cif->bytes; + int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long)); + + unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off); + unsigned long *p_gpr = (unsigned long *)(stack + gpr_off); + unsigned char *p_struct = (unsigned char *)p_gpr; + unsigned long *p_ov = (unsigned long *)stack; + + int n_fpr = 0; + int n_gpr = 0; + int n_ov = 0; + + ffi_type **ptr; + void **p_argv = ecif->avalue; + int i; + + /* If we returning a structure then we set the first parameter register + to the address of where we are returning this structure. */ + + if (ecif->cif->flags == FFI390_RET_STRUCT) + p_gpr[n_gpr++] = (unsigned long) ecif->rvalue; + + /* Now for the arguments. */ + + for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs; + i > 0; + i--, ptr++, p_argv++) + { + void *arg = *p_argv; + int type = (*ptr)->type; + + /* Check how a structure type is passed. */ + if (type == FFI_TYPE_STRUCT) + { + type = ffi_check_struct_type (*ptr); + + /* If we pass the struct via pointer, copy the data. */ + if (type == FFI_TYPE_POINTER) + { + p_struct -= ROUND_SIZE ((*ptr)->size); + memcpy (p_struct, (char *)arg, (*ptr)->size); + arg = &p_struct; + } + } + + /* Now handle all primitive int/pointer/float data types. */ + switch (type) + { + case FFI_TYPE_DOUBLE: + if (n_fpr < MAX_FPRARGS) + p_fpr[n_fpr++] = *(unsigned long long *) arg; + else +#ifdef __s390x__ + p_ov[n_ov++] = *(unsigned long *) arg; +#else + p_ov[n_ov++] = ((unsigned long *) arg)[0], + p_ov[n_ov++] = ((unsigned long *) arg)[1]; +#endif + break; + + case FFI_TYPE_FLOAT: + if (n_fpr < MAX_FPRARGS) + p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32; + else + p_ov[n_ov++] = *(unsigned int *) arg; + break; + + case FFI_TYPE_POINTER: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg; + else + p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef __s390x__ + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned long *) arg; + else + p_ov[n_ov++] = *(unsigned long *) arg; +#else + if (n_gpr == MAX_GPRARGS-1) + n_gpr = MAX_GPRARGS; + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = ((unsigned long *) arg)[0], + p_gpr[n_gpr++] = ((unsigned long *) arg)[1]; + else + p_ov[n_ov++] = ((unsigned long *) arg)[0], + p_ov[n_ov++] = ((unsigned long *) arg)[1]; +#endif + break; + + case FFI_TYPE_UINT32: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned int *) arg; + else + p_ov[n_ov++] = *(unsigned int *) arg; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(signed int *) arg; + else + p_ov[n_ov++] = *(signed int *) arg; + break; + + case FFI_TYPE_UINT16: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned short *) arg; + else + p_ov[n_ov++] = *(unsigned short *) arg; + break; + + case FFI_TYPE_SINT16: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(signed short *) arg; + else + p_ov[n_ov++] = *(signed short *) arg; + break; + + case FFI_TYPE_UINT8: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(unsigned char *) arg; + else + p_ov[n_ov++] = *(unsigned char *) arg; + break; + + case FFI_TYPE_SINT8: + if (n_gpr < MAX_GPRARGS) + p_gpr[n_gpr++] = *(signed char *) arg; + else + p_ov[n_ov++] = *(signed char *) arg; + break; + + default: + FFI_ASSERT (0); + break; + } + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_cif_machdep. */ +/* */ +/* Function - Perform machine dependent CIF processing. */ +/* */ +/*====================================================================*/ + +ffi_status +ffi_prep_cif_machdep(ffi_cif *cif) +{ + size_t struct_size = 0; + int n_gpr = 0; + int n_fpr = 0; + int n_ov = 0; + + ffi_type **ptr; + int i; + + /* Determine return value handling. */ + + switch (cif->rtype->type) + { + /* Void is easy. */ + case FFI_TYPE_VOID: + cif->flags = FFI390_RET_VOID; + break; + + /* Structures are returned via a hidden pointer. */ + case FFI_TYPE_STRUCT: + cif->flags = FFI390_RET_STRUCT; + n_gpr++; /* We need one GPR to pass the pointer. */ + break; + + /* Floating point values are returned in fpr 0. */ + case FFI_TYPE_FLOAT: + cif->flags = FFI390_RET_FLOAT; + break; + + case FFI_TYPE_DOUBLE: + cif->flags = FFI390_RET_DOUBLE; + break; + + /* Integer values are returned in gpr 2 (and gpr 3 + for 64-bit values on 31-bit machines). */ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + cif->flags = FFI390_RET_INT64; + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + /* These are to be extended to word size. */ +#ifdef __s390x__ + cif->flags = FFI390_RET_INT64; +#else + cif->flags = FFI390_RET_INT32; +#endif + break; + + default: + FFI_ASSERT (0); + break; + } + + /* Now for the arguments. */ + + for (ptr = cif->arg_types, i = cif->nargs; + i > 0; + i--, ptr++) + { + int type = (*ptr)->type; + + /* Check how a structure type is passed. */ + if (type == FFI_TYPE_STRUCT) + { + type = ffi_check_struct_type (*ptr); + + /* If we pass the struct via pointer, we must reserve space + to copy its data for proper call-by-value semantics. */ + if (type == FFI_TYPE_POINTER) + struct_size += ROUND_SIZE ((*ptr)->size); + } + + /* Now handle all primitive int/float data types. */ + switch (type) + { + /* The first MAX_FPRARGS floating point arguments + go in FPRs, the rest overflow to the stack. */ + + case FFI_TYPE_DOUBLE: + if (n_fpr < MAX_FPRARGS) + n_fpr++; + else + n_ov += sizeof (double) / sizeof (long); + break; + + case FFI_TYPE_FLOAT: + if (n_fpr < MAX_FPRARGS) + n_fpr++; + else + n_ov++; + break; + + /* On 31-bit machines, 64-bit integers are passed in GPR pairs, + if one is still available, or else on the stack. If only one + register is free, skip the register (it won't be used for any + subsequent argument either). */ + +#ifndef __s390x__ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + if (n_gpr == MAX_GPRARGS-1) + n_gpr = MAX_GPRARGS; + if (n_gpr < MAX_GPRARGS) + n_gpr += 2; + else + n_ov += 2; + break; +#endif + + /* Everything else is passed in GPRs (until MAX_GPRARGS + have been used) or overflows to the stack. */ + + default: + if (n_gpr < MAX_GPRARGS) + n_gpr++; + else + n_ov++; + break; + } + } + + /* Total stack space as required for overflow arguments + and temporary structure copies. */ + + cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size; + + return FFI_OK; +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_call. */ +/* */ +/* Function - Call the FFI routine. */ +/* */ +/*====================================================================*/ + +void +ffi_call(ffi_cif *cif, + void (*fn)(), + void *rvalue, + void **avalue) +{ + int ret_type = cif->flags; + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + ecif.rvalue = rvalue; + + /* If we don't have a return value, we need to fake one. */ + if (rvalue == NULL) + { + if (ret_type == FFI390_RET_STRUCT) + ecif.rvalue = alloca (cif->rtype->size); + else + ret_type = FFI390_RET_VOID; + } + + switch (cif->abi) + { + case FFI_SYSV: + ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args, + ret_type, ecif.rvalue, fn); + break; + + default: + FFI_ASSERT (0); + break; + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_closure_helper_SYSV. */ +/* */ +/* Function - Call a FFI closure target function. */ +/* */ +/*====================================================================*/ + +void +ffi_closure_helper_SYSV (ffi_closure *closure, + unsigned long *p_gpr, + unsigned long long *p_fpr, + unsigned long *p_ov) +{ + unsigned long long ret_buffer; + + void *rvalue = &ret_buffer; + void **avalue; + void **p_arg; + + int n_gpr = 0; + int n_fpr = 0; + int n_ov = 0; + + ffi_type **ptr; + int i; + + /* Allocate buffer for argument list pointers. */ + + p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *)); + + /* If we returning a structure, pass the structure address + directly to the target function. Otherwise, have the target + function store the return value to the GPR save area. */ + + if (closure->cif->flags == FFI390_RET_STRUCT) + rvalue = (void *) p_gpr[n_gpr++]; + + /* Now for the arguments. */ + + for (ptr = closure->cif->arg_types, i = closure->cif->nargs; + i > 0; + i--, p_arg++, ptr++) + { + int deref_struct_pointer = 0; + int type = (*ptr)->type; + + /* Check how a structure type is passed. */ + if (type == FFI_TYPE_STRUCT) + { + type = ffi_check_struct_type (*ptr); + + /* If we pass the struct via pointer, remember to + retrieve the pointer later. */ + if (type == FFI_TYPE_POINTER) + deref_struct_pointer = 1; + } + + /* Pointers are passed like UINTs of the same size. */ + if (type == FFI_TYPE_POINTER) +#ifdef __s390x__ + type = FFI_TYPE_UINT64; +#else + type = FFI_TYPE_UINT32; +#endif + + /* Now handle all primitive int/float data types. */ + switch (type) + { + case FFI_TYPE_DOUBLE: + if (n_fpr < MAX_FPRARGS) + *p_arg = &p_fpr[n_fpr++]; + else + *p_arg = &p_ov[n_ov], + n_ov += sizeof (double) / sizeof (long); + break; + + case FFI_TYPE_FLOAT: + if (n_fpr < MAX_FPRARGS) + *p_arg = &p_fpr[n_fpr++]; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; + break; + + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef __s390x__ + if (n_gpr < MAX_GPRARGS) + *p_arg = &p_gpr[n_gpr++]; + else + *p_arg = &p_ov[n_ov++]; +#else + if (n_gpr == MAX_GPRARGS-1) + n_gpr = MAX_GPRARGS; + if (n_gpr < MAX_GPRARGS) + *p_arg = &p_gpr[n_gpr], n_gpr += 2; + else + *p_arg = &p_ov[n_ov], n_ov += 2; +#endif + break; + + case FFI_TYPE_INT: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + if (n_gpr < MAX_GPRARGS) + *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4; + break; + + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + if (n_gpr < MAX_GPRARGS) + *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2; + break; + + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + if (n_gpr < MAX_GPRARGS) + *p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1; + else + *p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1; + break; + + default: + FFI_ASSERT (0); + break; + } + + /* If this is a struct passed via pointer, we need to + actually retrieve that pointer. */ + if (deref_struct_pointer) + *p_arg = *(void **)*p_arg; + } + + + /* Call the target function. */ + (closure->fun) (closure->cif, rvalue, avalue, closure->user_data); + + /* Convert the return value. */ + switch (closure->cif->rtype->type) + { + /* Void is easy, and so is struct. */ + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + break; + + /* Floating point values are returned in fpr 0. */ + case FFI_TYPE_FLOAT: + p_fpr[0] = (long long) *(unsigned int *) rvalue << 32; + break; + + case FFI_TYPE_DOUBLE: + p_fpr[0] = *(unsigned long long *) rvalue; + break; + + /* Integer values are returned in gpr 2 (and gpr 3 + for 64-bit values on 31-bit machines). */ + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: +#ifdef __s390x__ + p_gpr[0] = *(unsigned long *) rvalue; +#else + p_gpr[0] = ((unsigned long *) rvalue)[0], + p_gpr[1] = ((unsigned long *) rvalue)[1]; +#endif + break; + + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT32: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT8: + p_gpr[0] = *(unsigned long *) rvalue; + break; + + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT8: + p_gpr[0] = *(signed long *) rvalue; + break; + + default: + FFI_ASSERT (0); + break; + } +} + +/*======================== End of Routine ============================*/ + +/*====================================================================*/ +/* */ +/* Name - ffi_prep_closure. */ +/* */ +/* Function - Prepare a FFI closure. */ +/* */ +/*====================================================================*/ + +ffi_status +ffi_prep_closure (ffi_closure *closure, + ffi_cif *cif, + void (*fun) (ffi_cif *, void *, void **, void *), + void *user_data) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + +#ifndef __s390x__ + *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ + *(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */ + *(short *)&closure->tramp [4] = 0x1006; + *(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */ + *(long *)&closure->tramp [8] = (long)closure; + *(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV; +#else + *(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */ + *(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */ + *(short *)&closure->tramp [4] = 0x100e; + *(short *)&closure->tramp [6] = 0x0004; + *(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */ + *(long *)&closure->tramp[16] = (long)closure; + *(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV; +#endif + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/*======================== End of Routine ============================*/ + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffitarget.h new file mode 100644 index 000000000..5ec8ade02 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/ffitarget.h @@ -0,0 +1,59 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for S390. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#if defined (__s390x__) +#define S390X +#endif + +/* ---- System specific configurations ----------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#ifdef S390X +#define FFI_TRAMPOLINE_SIZE 32 +#else +#define FFI_TRAMPOLINE_SIZE 16 +#endif +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/sysv.S new file mode 100644 index 000000000..e9cbed977 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/s390/sysv.S @@ -0,0 +1,429 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2000 Software AG + + S390 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#ifndef __s390x__ + +.text + + # r2: cif->bytes + # r3: &ecif + # r4: ffi_prep_args + # r5: ret_type + # r6: ecif.rvalue + # ov: fn + + # This assumes we are using gas. + .globl ffi_call_SYSV + .type ffi_call_SYSV,%function +ffi_call_SYSV: +.LFB1: + stm %r6,%r15,24(%r15) # Save registers +.LCFI0: + basr %r13,0 # Set up base register +.Lbase: + lr %r11,%r15 # Set up frame pointer +.LCFI1: + sr %r15,%r2 + ahi %r15,-96-48 # Allocate stack + lr %r8,%r6 # Save ecif.rvalue + sr %r9,%r9 + ic %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address + l %r7,96(%r11) # Load function address + st %r11,0(%r15) # Set up back chain + ahi %r11,-48 # Register save area +.LCFI2: + + la %r2,96(%r15) # Save area + # r3 already holds &ecif + basr %r14,%r4 # Call ffi_prep_args + + lm %r2,%r6,0(%r11) # Load arguments + ld %f0,32(%r11) + ld %f2,40(%r11) + la %r14,0(%r13,%r9) # Set return address + br %r7 # ... and call function + +.LretNone: # Return void + l %r4,48+56(%r11) + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretFloat: + l %r4,48+56(%r11) + ste %f0,0(%r8) # Return float + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretDouble: + l %r4,48+56(%r11) + std %f0,0(%r8) # Return double + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretInt32: + l %r4,48+56(%r11) + st %r2,0(%r8) # Return int + lm %r6,%r15,48+24(%r11) + br %r4 + +.LretInt64: + l %r4,48+56(%r11) + stm %r2,%r3,0(%r8) # Return long long + lm %r6,%r15,48+24(%r11) + br %r4 + +.Ltable: + .byte .LretNone-.Lbase # FFI390_RET_VOID + .byte .LretNone-.Lbase # FFI390_RET_STRUCT + .byte .LretFloat-.Lbase # FFI390_RET_FLOAT + .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE + .byte .LretInt32-.Lbase # FFI390_RET_INT32 + .byte .LretInt64-.Lbase # FFI390_RET_INT64 + +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + + .globl ffi_closure_SYSV + .type ffi_closure_SYSV,%function +ffi_closure_SYSV: +.LFB2: + stm %r12,%r15,48(%r15) # Save registers +.LCFI10: + basr %r13,0 # Set up base register +.Lcbase: + stm %r2,%r6,8(%r15) # Save arguments + std %f0,64(%r15) + std %f2,72(%r15) + lr %r1,%r15 # Set up stack frame + ahi %r15,-96 +.LCFI11: + l %r12,.Lchelper-.Lcbase(%r13) # Get helper function + lr %r2,%r0 # Closure + la %r3,8(%r1) # GPRs + la %r4,64(%r1) # FPRs + la %r5,96(%r1) # Overflow + st %r1,0(%r15) # Set up back chain + + bas %r14,0(%r12,%r13) # Call helper + + l %r4,96+56(%r15) + ld %f0,96+64(%r15) # Load return registers + lm %r2,%r3,96+8(%r15) + lm %r12,%r15,96+48(%r15) + br %r4 + + .align 4 +.Lchelper: + .long ffi_closure_helper_SYSV-.Lcbase + +.LFE2: + +.ffi_closure_SYSV_end: + .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV + + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -4 # CIE Data Alignment Factor + .byte 0xe # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0x60 + .align 4 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .4byte .LFB1-. # FDE initial location + .4byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB1 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x9 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0xa + .byte 0x8d # DW_CFA_offset, column 0xd + .uleb128 0xb + .byte 0x8c # DW_CFA_offset, column 0xc + .uleb128 0xc + .byte 0x8b # DW_CFA_offset, column 0xb + .uleb128 0xd + .byte 0x8a # DW_CFA_offset, column 0xa + .uleb128 0xe + .byte 0x89 # DW_CFA_offset, column 0x9 + .uleb128 0xf + .byte 0x88 # DW_CFA_offset, column 0x8 + .uleb128 0x10 + .byte 0x87 # DW_CFA_offset, column 0x7 + .uleb128 0x11 + .byte 0x86 # DW_CFA_offset, column 0x6 + .uleb128 0x12 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 + .byte 0xd # DW_CFA_def_cfa_register + .uleb128 0xb + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI2-.LCFI1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x90 + .align 4 +.LEFDE1: +.LSFDE2: + .4byte .LEFDE2-.LASFDE2 # FDE Length +.LASFDE2: + .4byte .LASFDE2-.Lframe1 # FDE CIE offset + .4byte .LFB2-. # FDE initial location + .4byte .LFE2-.LFB2 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI10-.LFB2 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x9 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0xa + .byte 0x8d # DW_CFA_offset, column 0xd + .uleb128 0xb + .byte 0x8c # DW_CFA_offset, column 0xc + .uleb128 0xc + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI11-.LCFI10 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0xc0 + .align 4 +.LEFDE2: + +#else + +.text + + # r2: cif->bytes + # r3: &ecif + # r4: ffi_prep_args + # r5: ret_type + # r6: ecif.rvalue + # ov: fn + + # This assumes we are using gas. + .globl ffi_call_SYSV + .type ffi_call_SYSV,%function +ffi_call_SYSV: +.LFB1: + stmg %r6,%r15,48(%r15) # Save registers +.LCFI0: + larl %r13,.Lbase # Set up base register + lgr %r11,%r15 # Set up frame pointer +.LCFI1: + sgr %r15,%r2 + aghi %r15,-160-80 # Allocate stack + lgr %r8,%r6 # Save ecif.rvalue + llgc %r9,.Ltable-.Lbase(%r13,%r5) # Load epilog address + lg %r7,160(%r11) # Load function address + stg %r11,0(%r15) # Set up back chain + aghi %r11,-80 # Register save area +.LCFI2: + + la %r2,160(%r15) # Save area + # r3 already holds &ecif + basr %r14,%r4 # Call ffi_prep_args + + lmg %r2,%r6,0(%r11) # Load arguments + ld %f0,48(%r11) + ld %f2,56(%r11) + ld %f4,64(%r11) + ld %f6,72(%r11) + la %r14,0(%r13,%r9) # Set return address + br %r7 # ... and call function + +.Lbase: +.LretNone: # Return void + lg %r4,80+112(%r11) + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretFloat: + lg %r4,80+112(%r11) + ste %f0,0(%r8) # Return float + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretDouble: + lg %r4,80+112(%r11) + std %f0,0(%r8) # Return double + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretInt32: + lg %r4,80+112(%r11) + st %r2,0(%r8) # Return int + lmg %r6,%r15,80+48(%r11) + br %r4 + +.LretInt64: + lg %r4,80+112(%r11) + stg %r2,0(%r8) # Return long + lmg %r6,%r15,80+48(%r11) + br %r4 + +.Ltable: + .byte .LretNone-.Lbase # FFI390_RET_VOID + .byte .LretNone-.Lbase # FFI390_RET_STRUCT + .byte .LretFloat-.Lbase # FFI390_RET_FLOAT + .byte .LretDouble-.Lbase # FFI390_RET_DOUBLE + .byte .LretInt32-.Lbase # FFI390_RET_INT32 + .byte .LretInt64-.Lbase # FFI390_RET_INT64 + +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + + .globl ffi_closure_SYSV + .type ffi_closure_SYSV,%function +ffi_closure_SYSV: +.LFB2: + stmg %r14,%r15,112(%r15) # Save registers +.LCFI10: + stmg %r2,%r6,16(%r15) # Save arguments + std %f0,128(%r15) + std %f2,136(%r15) + std %f4,144(%r15) + std %f6,152(%r15) + lgr %r1,%r15 # Set up stack frame + aghi %r15,-160 +.LCFI11: + lgr %r2,%r0 # Closure + la %r3,16(%r1) # GPRs + la %r4,128(%r1) # FPRs + la %r5,160(%r1) # Overflow + stg %r1,0(%r15) # Set up back chain + + brasl %r14,ffi_closure_helper_SYSV # Call helper + + lg %r14,160+112(%r15) + ld %f0,160+128(%r15) # Load return registers + lg %r2,160+16(%r15) + la %r15,160(%r15) + br %r14 +.LFE2: + +.ffi_closure_SYSV_end: + .size ffi_closure_SYSV,.ffi_closure_SYSV_end-ffi_closure_SYSV + + + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .4byte .LECIE1-.LSCIE1 # Length of Common Information Entry +.LSCIE1: + .4byte 0x0 # CIE Identifier Tag + .byte 0x1 # CIE Version + .ascii "zR\0" # CIE Augmentation + .uleb128 0x1 # CIE Code Alignment Factor + .sleb128 -8 # CIE Data Alignment Factor + .byte 0xe # CIE RA Column + .uleb128 0x1 # Augmentation size + .byte 0x1b # FDE Encoding (pcrel sdata4) + .byte 0xc # DW_CFA_def_cfa + .uleb128 0xf + .uleb128 0xa0 + .align 8 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 # FDE Length +.LASFDE1: + .4byte .LASFDE1-.Lframe1 # FDE CIE offset + .4byte .LFB1-. # FDE initial location + .4byte .LFE1-.LFB1 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI0-.LFB1 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x5 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0x6 + .byte 0x8d # DW_CFA_offset, column 0xd + .uleb128 0x7 + .byte 0x8c # DW_CFA_offset, column 0xc + .uleb128 0x8 + .byte 0x8b # DW_CFA_offset, column 0xb + .uleb128 0x9 + .byte 0x8a # DW_CFA_offset, column 0xa + .uleb128 0xa + .byte 0x89 # DW_CFA_offset, column 0x9 + .uleb128 0xb + .byte 0x88 # DW_CFA_offset, column 0x8 + .uleb128 0xc + .byte 0x87 # DW_CFA_offset, column 0x7 + .uleb128 0xd + .byte 0x86 # DW_CFA_offset, column 0x6 + .uleb128 0xe + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI1-.LCFI0 + .byte 0xd # DW_CFA_def_cfa_register + .uleb128 0xb + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI2-.LCFI1 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0xf0 + .align 8 +.LEFDE1: +.LSFDE2: + .4byte .LEFDE2-.LASFDE2 # FDE Length +.LASFDE2: + .4byte .LASFDE2-.Lframe1 # FDE CIE offset + .4byte .LFB2-. # FDE initial location + .4byte .LFE2-.LFB2 # FDE address range + .uleb128 0x0 # Augmentation size + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI10-.LFB2 + .byte 0x8f # DW_CFA_offset, column 0xf + .uleb128 0x5 + .byte 0x8e # DW_CFA_offset, column 0xe + .uleb128 0x6 + .byte 0x4 # DW_CFA_advance_loc4 + .4byte .LCFI11-.LCFI10 + .byte 0xe # DW_CFA_def_cfa_offset + .uleb128 0x140 + .align 8 +.LEFDE2: + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffi.c new file mode 100644 index 000000000..38449e9e6 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffi.c @@ -0,0 +1,728 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2002, 2003, 2004, 2005 Kaz Kojima + + SuperH Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +#define NGREGARG 4 +#if defined(__SH4__) +#define NFREGARG 8 +#endif + +#if defined(__HITACHI__) +#define STRUCT_VALUE_ADDRESS_WITH_ARG 1 +#else +#define STRUCT_VALUE_ADDRESS_WITH_ARG 0 +#endif + +/* If the structure has essentialy an unique element, return its type. */ +static int +simple_type (ffi_type *arg) +{ + if (arg->type != FFI_TYPE_STRUCT) + return arg->type; + else if (arg->elements[1]) + return FFI_TYPE_STRUCT; + + return simple_type (arg->elements[0]); +} + +static int +return_type (ffi_type *arg) +{ + unsigned short type; + + if (arg->type != FFI_TYPE_STRUCT) + return arg->type; + + type = simple_type (arg->elements[0]); + if (! arg->elements[1]) + { + switch (type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + return FFI_TYPE_INT; + + default: + return type; + } + } + + /* gcc uses r0/r1 pair for some kind of structures. */ + if (arg->size <= 2 * sizeof (int)) + { + int i = 0; + ffi_type *e; + + while ((e = arg->elements[i++])) + { + type = simple_type (e); + switch (type) + { + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT32: + case FFI_TYPE_INT: + case FFI_TYPE_FLOAT: + return FFI_TYPE_UINT64; + + default: + break; + } + } + } + + return FFI_TYPE_STRUCT; +} + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register int tmp; + register unsigned int avn; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + int greg, ireg; +#if defined(__SH4__) + int freg = 0; +#endif + + tmp = 0; + argp = stack; + + if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += 4; + ireg = STRUCT_VALUE_ADDRESS_WITH_ARG ? 1 : 0; + } + else + ireg = 0; + + /* Set arguments for registers. */ + greg = ireg; + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ >= NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + argp += z; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ >= NFREGARG) + continue; + } + else +#endif + { + if (greg++ >= NGREGARG) + continue; + } + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + argp += z; + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 >= NFREGARG) + continue; + freg = (freg + 1) & ~1; + freg += 2; + memcpy (argp, *p_argv, z); + argp += z; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); +#if defined(__SH4__) + if (greg + n - 1 >= NGREGARG) + continue; +#else + if (greg >= NGREGARG) + continue; +#endif + greg += n; + memcpy (argp, *p_argv, z); + argp += n * sizeof (int); + } + } + + /* Set arguments on stack. */ + greg = ireg; +#if defined(__SH4__) + freg = 0; +#endif + p_argv = ecif->avalue; + + for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ < NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + argp += z; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ < NFREGARG) + continue; + } + else +#endif + { + if (greg++ < NGREGARG) + continue; + } + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + argp += z; + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 < NFREGARG) + { + freg = (freg + 1) & ~1; + freg += 2; + continue; + } + memcpy (argp, *p_argv, z); + argp += z; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); + if (greg + n - 1 < NGREGARG) + { + greg += n; + continue; + } +#if (! defined(__SH4__)) + else if (greg < NGREGARG) + { + greg = NGREGARG; + continue; + } +#endif + memcpy (argp, *p_argv, z); + argp += n * sizeof (int); + } + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int i, j; + int size, type; + int n, m; + int greg; +#if defined(__SH4__) + int freg = 0; +#endif + + cif->flags = 0; + + greg = ((return_type (cif->rtype) == FFI_TYPE_STRUCT) && + STRUCT_VALUE_ADDRESS_WITH_ARG) ? 1 : 0; + +#if defined(__SH4__) + for (i = j = 0; i < cif->nargs && j < 12; i++) + { + type = (cif->arg_types)[i]->type; + switch (type) + { + case FFI_TYPE_FLOAT: + if (freg >= NFREGARG) + continue; + freg++; + cif->flags += ((cif->arg_types)[i]->type) << (2 * j); + j++; + break; + + case FFI_TYPE_DOUBLE: + if ((freg + 1) >= NFREGARG) + continue; + freg = (freg + 1) & ~1; + freg += 2; + cif->flags += ((cif->arg_types)[i]->type) << (2 * j); + j++; + break; + + default: + size = (cif->arg_types)[i]->size; + n = (size + sizeof (int) - 1) / sizeof (int); + if (greg + n - 1 >= NGREGARG) + continue; + greg += n; + for (m = 0; m < n; m++) + cif->flags += FFI_TYPE_INT << (2 * j++); + break; + } + } +#else + for (i = j = 0; i < cif->nargs && j < 4; i++) + { + size = (cif->arg_types)[i]->size; + n = (size + sizeof (int) - 1) / sizeof (int); + if (greg >= NGREGARG) + continue; + else if (greg + n - 1 >= NGREGARG) + n = NGREGARG - greg; + greg += n; + for (m = 0; m < n; m++) + cif->flags += FFI_TYPE_INT << (2 * j++); + } +#endif + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + cif->flags += (unsigned) (return_type (cif->rtype)) << 24; + break; + + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags += (unsigned) cif->rtype->type << 24; + break; + + default: + cif->flags += FFI_TYPE_INT << 24; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + UINT64 trvalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if (cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + ecif.rvalue = &trvalue; + else if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + default: + FFI_ASSERT(0); + break; + } + + if (rvalue + && cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + memcpy (rvalue, &trvalue, cif->rtype->size); +} + +extern void ffi_closure_SYSV (void); +#if defined(__SH4__) +extern void __ic_invalidate (void *line); +#endif + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp; + unsigned short insn; + + FFI_ASSERT (cif->abi == FFI_GCC_SYSV); + + tramp = (unsigned int *) &closure->tramp[0]; + /* Set T bit if the function returns a struct pointed with R2. */ + insn = (return_type (cif->rtype) == FFI_TYPE_STRUCT + ? 0x0018 /* sett */ + : 0x0008 /* clrt */); + +#ifdef __LITTLE_ENDIAN__ + tramp[0] = 0xd301d102; + tramp[1] = 0x0000412b | (insn << 16); +#else + tramp[0] = 0xd102d301; + tramp[1] = 0x412b0000 | insn; +#endif + *(void **) &tramp[2] = (void *)closure; /* ctx */ + *(void **) &tramp[3] = (void *)ffi_closure_SYSV; /* funaddr */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + +#if defined(__SH4__) + /* Flush the icache. */ + __ic_invalidate(&closure->tramp[0]); +#endif + + return FFI_OK; +} + +/* Basically the trampoline invokes ffi_closure_SYSV, and on + * entry, r3 holds the address of the closure. + * After storing the registers that could possibly contain + * parameters to be passed into the stack frame and setting + * up space for a return value, ffi_closure_SYSV invokes the + * following helper function to do most of the work. + */ + +#ifdef __LITTLE_ENDIAN__ +#define OFS_INT8 0 +#define OFS_INT16 0 +#else +#define OFS_INT8 3 +#define OFS_INT16 2 +#endif + +int +ffi_closure_helper_SYSV (ffi_closure *closure, void *rvalue, + unsigned long *pgr, unsigned long *pfr, + unsigned long *pst) +{ + void **avalue; + ffi_type **p_arg; + int i, avn; + int ireg, greg = 0; +#if defined(__SH4__) + int freg = 0; +#endif + ffi_cif *cif; + double temp; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (cif->rtype->type == FFI_TYPE_STRUCT && STRUCT_VALUE_ADDRESS_WITH_ARG) + { + rvalue = *pgr++; + ireg = 1; + } + else + ireg = 0; + + cif = closure->cif; + greg = ireg; + avn = cif->nargs; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ >= NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (((char *)pgr) + OFS_INT8); + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (((char *)pgr) + OFS_INT16); + break; + + case FFI_TYPE_STRUCT: + avalue[i] = pgr; + break; + + default: + FFI_ASSERT(0); + } + pgr++; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ >= NFREGARG) + continue; + avalue[i] = pfr; + pfr++; + } + else +#endif + { + if (greg++ >= NGREGARG) + continue; + avalue[i] = pgr; + pgr++; + } + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 >= NFREGARG) + continue; + freg = (freg + 1) & ~1; + freg += 2; + avalue[i] = pfr; + pfr += 2; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); +#if defined(__SH4__) + if (greg + n - 1 >= NGREGARG) + continue; +#else + if (greg >= NGREGARG) + continue; +#endif + greg += n; + avalue[i] = pgr; + pgr += n; + } + } + + greg = ireg; +#if defined(__SH4__) + freg = 0; +#endif + + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + if (greg++ < NGREGARG) + continue; + + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + avalue[i] = (((char *)pst) + OFS_INT8); + break; + + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + avalue[i] = (((char *)pst) + OFS_INT16); + break; + + case FFI_TYPE_STRUCT: + avalue[i] = pst; + break; + + default: + FFI_ASSERT(0); + } + pst++; + } + else if (z == sizeof(int)) + { +#if defined(__SH4__) + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg++ < NFREGARG) + continue; + } + else +#endif + { + if (greg++ < NGREGARG) + continue; + } + avalue[i] = pst; + pst++; + } +#if defined(__SH4__) + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 < NFREGARG) + { + freg = (freg + 1) & ~1; + freg += 2; + continue; + } + avalue[i] = pst; + pst += 2; + } +#endif + else + { + int n = (z + sizeof (int) - 1) / sizeof (int); + if (greg + n - 1 < NGREGARG) + { + greg += n; + continue; + } +#if (! defined(__SH4__)) + else if (greg < NGREGARG) + { + greg += n; + pst += greg - NGREGARG; + continue; + } +#endif + avalue[i] = pst; + pst += n; + } + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_SYSV how to perform return type promotions. */ + return return_type (cif->rtype); +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffitarget.h new file mode 100644 index 000000000..f8492a1c0 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/ffitarget.h @@ -0,0 +1,48 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for SuperH. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 16 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/sysv.S new file mode 100644 index 000000000..c9002a750 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh/sysv.S @@ -0,0 +1,845 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2002, 2003, 2004 Kaz Kojima + + SuperH Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +/* XXX these lose for some platforms, I'm sure. */ +#define CNAME(x) x +#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): +#endif + +#if defined(__HITACHI__) +#define STRUCT_VALUE_ADDRESS_WITH_ARG 1 +#else +#define STRUCT_VALUE_ADDRESS_WITH_ARG 0 +#endif + +.text + + # r4: ffi_prep_args + # r5: &ecif + # r6: bytes + # r7: flags + # sp+0: rvalue + # sp+4: fn + + # This assumes we are using gas. +ENTRY(ffi_call_SYSV) + # Save registers +.LFB1: + mov.l r8,@-r15 +.LCFI0: + mov.l r9,@-r15 +.LCFI1: + mov.l r10,@-r15 +.LCFI2: + mov.l r12,@-r15 +.LCFI3: + mov.l r14,@-r15 +.LCFI4: + sts.l pr,@-r15 +.LCFI5: + mov r15,r14 +.LCFI6: +#if defined(__SH4__) + mov r6,r8 + mov r7,r9 + + sub r6,r15 + add #-16,r15 + mov #~7,r0 + and r0,r15 + + mov r4,r0 + jsr @r0 + mov r15,r4 + + mov r9,r1 + shlr8 r9 + shlr8 r9 + shlr8 r9 + + mov #FFI_TYPE_STRUCT,r2 + cmp/eq r2,r9 + bf 1f +#if STRUCT_VALUE_ADDRESS_WITH_ARG + mov.l @r15+,r4 + bra 2f + mov #5,r2 +#else + mov.l @r15+,r10 +#endif +1: + mov #4,r2 +2: + mov #4,r3 + +L_pass: + cmp/pl r8 + bf L_call_it + + mov r1,r0 + and #3,r0 + +L_pass_d: + cmp/eq #FFI_TYPE_DOUBLE,r0 + bf L_pass_f + + mov r3,r0 + and #1,r0 + tst r0,r0 + bt 1f + add #1,r3 +1: + mov #12,r0 + cmp/hs r0,r3 + bt/s 3f + shlr2 r1 + bsr L_pop_d + nop +3: + add #2,r3 + bra L_pass + add #-8,r8 + +L_pop_d: + mov r3,r0 + add r0,r0 + add r3,r0 + add #-12,r0 + braf r0 + nop +#ifdef __LITTLE_ENDIAN__ + fmov.s @r15+,fr5 + rts + fmov.s @r15+,fr4 + fmov.s @r15+,fr7 + rts + fmov.s @r15+,fr6 + fmov.s @r15+,fr9 + rts + fmov.s @r15+,fr8 + fmov.s @r15+,fr11 + rts + fmov.s @r15+,fr10 +#else + fmov.s @r15+,fr4 + rts + fmov.s @r15+,fr5 + fmov.s @r15+,fr6 + rts + fmov.s @r15+,fr7 + fmov.s @r15+,fr8 + rts + fmov.s @r15+,fr9 + fmov.s @r15+,fr10 + rts + fmov.s @r15+,fr11 +#endif + +L_pass_f: + cmp/eq #FFI_TYPE_FLOAT,r0 + bf L_pass_i + + mov #12,r0 + cmp/hs r0,r3 + bt/s 2f + shlr2 r1 + bsr L_pop_f + nop +2: + add #1,r3 + bra L_pass + add #-4,r8 + +L_pop_f: + mov r3,r0 + shll2 r0 + add #-16,r0 + braf r0 + nop +#ifdef __LITTLE_ENDIAN__ + rts + fmov.s @r15+,fr5 + rts + fmov.s @r15+,fr4 + rts + fmov.s @r15+,fr7 + rts + fmov.s @r15+,fr6 + rts + fmov.s @r15+,fr9 + rts + fmov.s @r15+,fr8 + rts + fmov.s @r15+,fr11 + rts + fmov.s @r15+,fr10 +#else + rts + fmov.s @r15+,fr4 + rts + fmov.s @r15+,fr5 + rts + fmov.s @r15+,fr6 + rts + fmov.s @r15+,fr7 + rts + fmov.s @r15+,fr8 + rts + fmov.s @r15+,fr9 + rts + fmov.s @r15+,fr10 + rts + fmov.s @r15+,fr11 +#endif + +L_pass_i: + cmp/eq #FFI_TYPE_INT,r0 + bf L_call_it + + mov #8,r0 + cmp/hs r0,r2 + bt/s 2f + shlr2 r1 + bsr L_pop_i + nop +2: + add #1,r2 + bra L_pass + add #-4,r8 + +L_pop_i: + mov r2,r0 + shll2 r0 + add #-16,r0 + braf r0 + nop + rts + mov.l @r15+,r4 + rts + mov.l @r15+,r5 + rts + mov.l @r15+,r6 + rts + mov.l @r15+,r7 + +L_call_it: + # call function +#if (! STRUCT_VALUE_ADDRESS_WITH_ARG) + mov r10, r2 +#endif + mov.l @(28,r14),r1 + jsr @r1 + nop + +L_ret_d: + mov #FFI_TYPE_DOUBLE,r2 + cmp/eq r2,r9 + bf L_ret_ll + + mov.l @(24,r14),r1 +#ifdef __LITTLE_ENDIAN__ + fmov.s fr1,@r1 + add #4,r1 + bra L_epilogue + fmov.s fr0,@r1 +#else + fmov.s fr0,@r1 + add #4,r1 + bra L_epilogue + fmov.s fr1,@r1 +#endif + +L_ret_ll: + mov #FFI_TYPE_SINT64,r2 + cmp/eq r2,r9 + bt/s 1f + mov #FFI_TYPE_UINT64,r2 + cmp/eq r2,r9 + bf L_ret_f + +1: + mov.l @(24,r14),r2 + mov.l r0,@r2 + bra L_epilogue + mov.l r1,@(4,r2) + +L_ret_f: + mov #FFI_TYPE_FLOAT,r2 + cmp/eq r2,r9 + bf L_ret_i + + mov.l @(24,r14),r1 + bra L_epilogue + fmov.s fr0,@r1 + +L_ret_i: + mov #FFI_TYPE_INT,r2 + cmp/eq r2,r9 + bf L_epilogue + + mov.l @(24,r14),r1 + bra L_epilogue + mov.l r0,@r1 + +L_epilogue: + # Remove the space we pushed for the args + mov r14,r15 + + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r12 + mov.l @r15+,r10 + mov.l @r15+,r9 + rts + mov.l @r15+,r8 +#else + mov r6,r8 + mov r7,r9 + + sub r6,r15 + add #-16,r15 + mov #~7,r0 + and r0,r15 + + mov r4,r0 + jsr @r0 + mov r15,r4 + + mov r9,r3 + shlr8 r9 + shlr8 r9 + shlr8 r9 + + mov #FFI_TYPE_STRUCT,r2 + cmp/eq r2,r9 + bf 1f +#if STRUCT_VALUE_ADDRESS_WITH_ARG + mov.l @r15+,r4 + bra 2f + mov #5,r2 +#else + mov.l @r15+,r10 +#endif +1: + mov #4,r2 +2: + +L_pass: + cmp/pl r8 + bf L_call_it + + mov r3,r0 + and #3,r0 + +L_pass_d: + cmp/eq #FFI_TYPE_DOUBLE,r0 + bf L_pass_i + + mov r15,r0 + and #7,r0 + tst r0,r0 + bt 1f + add #4,r15 +1: + mov #8,r0 + cmp/hs r0,r2 + bt/s 2f + shlr2 r3 + bsr L_pop_d + nop +2: + add #2,r2 + bra L_pass + add #-8,r8 + +L_pop_d: + mov r2,r0 + add r0,r0 + add r2,r0 + add #-12,r0 + add r0,r0 + braf r0 + nop + mov.l @r15+,r4 + rts + mov.l @r15+,r5 + mov.l @r15+,r5 + rts + mov.l @r15+,r6 + mov.l @r15+,r6 + rts + mov.l @r15+,r7 + rts + mov.l @r15+,r7 + +L_pass_i: + cmp/eq #FFI_TYPE_INT,r0 + bf L_call_it + + mov #8,r0 + cmp/hs r0,r2 + bt/s 2f + shlr2 r3 + bsr L_pop_i + nop +2: + add #1,r2 + bra L_pass + add #-4,r8 + +L_pop_i: + mov r2,r0 + shll2 r0 + add #-16,r0 + braf r0 + nop + rts + mov.l @r15+,r4 + rts + mov.l @r15+,r5 + rts + mov.l @r15+,r6 + rts + mov.l @r15+,r7 + +L_call_it: + # call function +#if (! STRUCT_VALUE_ADDRESS_WITH_ARG) + mov r10, r2 +#endif + mov.l @(28,r14),r1 + jsr @r1 + nop + +L_ret_d: + mov #FFI_TYPE_DOUBLE,r2 + cmp/eq r2,r9 + bf L_ret_ll + + mov.l @(24,r14),r2 + mov.l r0,@r2 + bra L_epilogue + mov.l r1,@(4,r2) + +L_ret_ll: + mov #FFI_TYPE_SINT64,r2 + cmp/eq r2,r9 + bt/s 1f + mov #FFI_TYPE_UINT64,r2 + cmp/eq r2,r9 + bf L_ret_i + +1: + mov.l @(24,r14),r2 + mov.l r0,@r2 + bra L_epilogue + mov.l r1,@(4,r2) + +L_ret_i: + mov #FFI_TYPE_FLOAT,r2 + cmp/eq r2,r9 + bt 1f + mov #FFI_TYPE_INT,r2 + cmp/eq r2,r9 + bf L_epilogue +1: + mov.l @(24,r14),r1 + bra L_epilogue + mov.l r0,@r1 + +L_epilogue: + # Remove the space we pushed for the args + mov r14,r15 + + lds.l @r15+,pr + mov.l @r15+,r14 + mov.l @r15+,r12 + mov.l @r15+,r10 + mov.l @r15+,r9 + rts + mov.l @r15+,r8 +#endif +.LFE1: +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + +.globl ffi_closure_helper_SYSV + +ENTRY(ffi_closure_SYSV) +.LFB2: + mov.l r7,@-r15 +.LCFI7: + mov.l r6,@-r15 +.LCFI8: + mov.l r5,@-r15 +.LCFI9: + mov.l r4,@-r15 +.LCFIA: + mov.l r14,@-r15 +.LCFIB: + sts.l pr,@-r15 + + /* Stack layout: + xx bytes (on stack parameters) + 16 bytes (register parameters) + 4 bytes (saved frame pointer) + 4 bytes (saved return address) + 32 bytes (floating register parameters, SH-4 only) + 8 bytes (result) + 4 bytes (pad) + 4 bytes (5th arg) + <- new stack pointer + */ +.LCFIC: +#if defined(__SH4__) + add #-48,r15 +#else + add #-16,r15 +#endif +.LCFID: + mov r15,r14 +.LCFIE: + +#if defined(__SH4__) + mov r14,r1 + add #48,r1 +#ifdef __LITTLE_ENDIAN__ + fmov.s fr10,@-r1 + fmov.s fr11,@-r1 + fmov.s fr8,@-r1 + fmov.s fr9,@-r1 + fmov.s fr6,@-r1 + fmov.s fr7,@-r1 + fmov.s fr4,@-r1 + fmov.s fr5,@-r1 +#else + fmov.s fr11,@-r1 + fmov.s fr10,@-r1 + fmov.s fr9,@-r1 + fmov.s fr8,@-r1 + fmov.s fr7,@-r1 + fmov.s fr6,@-r1 + fmov.s fr5,@-r1 + fmov.s fr4,@-r1 +#endif + mov r1,r7 + mov r14,r6 + add #56,r6 +#else + mov r14,r6 + add #24,r6 +#endif + + bt/s 10f + mov r2, r5 + mov r14,r1 + add #8,r1 + mov r1,r5 +10: + + mov r14,r1 +#if defined(__SH4__) + add #72,r1 +#else + add #40,r1 +#endif + mov.l r1,@r14 + +#ifdef PIC + mov.l L_got,r1 + mova L_got,r0 + add r0,r1 + mov.l L_helper,r0 + add r1,r0 +#else + mov.l L_helper,r0 +#endif + jsr @r0 + mov r3,r4 + + shll r0 + mov r0,r1 + mova L_table,r0 + add r1,r0 + mov.w @r0,r0 + mov r14,r2 + braf r0 + add #8,r2 +0: + .align 2 +#ifdef PIC +L_got: + .long _GLOBAL_OFFSET_TABLE_ +L_helper: + .long ffi_closure_helper_SYSV@GOTOFF +#else +L_helper: + .long ffi_closure_helper_SYSV +#endif +L_table: + .short L_case_v - 0b /* FFI_TYPE_VOID */ + .short L_case_i - 0b /* FFI_TYPE_INT */ +#if defined(__SH4__) + .short L_case_f - 0b /* FFI_TYPE_FLOAT */ + .short L_case_d - 0b /* FFI_TYPE_DOUBLE */ + .short L_case_d - 0b /* FFI_TYPE_LONGDOUBLE */ +#else + .short L_case_i - 0b /* FFI_TYPE_FLOAT */ + .short L_case_ll - 0b /* FFI_TYPE_DOUBLE */ + .short L_case_ll - 0b /* FFI_TYPE_LONGDOUBLE */ +#endif + .short L_case_uq - 0b /* FFI_TYPE_UINT8 */ + .short L_case_q - 0b /* FFI_TYPE_SINT8 */ + .short L_case_uh - 0b /* FFI_TYPE_UINT16 */ + .short L_case_h - 0b /* FFI_TYPE_SINT16 */ + .short L_case_i - 0b /* FFI_TYPE_UINT32 */ + .short L_case_i - 0b /* FFI_TYPE_SINT32 */ + .short L_case_ll - 0b /* FFI_TYPE_UINT64 */ + .short L_case_ll - 0b /* FFI_TYPE_SINT64 */ + .short L_case_v - 0b /* FFI_TYPE_STRUCT */ + .short L_case_i - 0b /* FFI_TYPE_POINTER */ + +#if defined(__SH4__) +L_case_d: +#ifdef __LITTLE_ENDIAN__ + fmov.s @r2+,fr1 + bra L_case_v + fmov.s @r2,fr0 +#else + fmov.s @r2+,fr0 + bra L_case_v + fmov.s @r2,fr1 +#endif + +L_case_f: + bra L_case_v + fmov.s @r2,fr0 +#endif + +L_case_ll: + mov.l @r2+,r0 + bra L_case_v + mov.l @r2,r1 + +L_case_i: + bra L_case_v + mov.l @r2,r0 + +L_case_q: +#ifdef __LITTLE_ENDIAN__ +#else + add #3,r2 +#endif + bra L_case_v + mov.b @r2,r0 + +L_case_uq: +#ifdef __LITTLE_ENDIAN__ +#else + add #3,r2 +#endif + mov.b @r2,r0 + bra L_case_v + extu.b r0,r0 + +L_case_h: +#ifdef __LITTLE_ENDIAN__ +#else + add #2,r2 +#endif + bra L_case_v + mov.w @r2,r0 + +L_case_uh: +#ifdef __LITTLE_ENDIAN__ +#else + add #2,r2 +#endif + mov.w @r2,r0 + extu.w r0,r0 + /* fall through */ + +L_case_v: +#if defined(__SH4__) + add #48,r15 +#else + add #16,r15 +#endif + lds.l @r15+,pr + mov.l @r15+,r14 + rts + add #16,r15 +.LFE2: +.ffi_closure_SYSV_end: + .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + + .section ".eh_frame","aw",@progbits +__FRAME_BEGIN__: + .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .4byte 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef PIC + .ascii "zR\0" /* CIE Augmentation */ +#else + .byte 0x0 /* CIE Augmentation */ +#endif + .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x7c /* sleb128 -4; CIE Data Alignment Factor */ + .byte 0x11 /* CIE RA Column */ +#ifdef PIC + .uleb128 0x1 /* Augmentation size */ + .byte 0x10 /* FDE Encoding (pcrel) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0xf /* uleb128 0xf */ + .byte 0x0 /* uleb128 0x0 */ + .align 2 +.LECIE1: +.LSFDE1: + .4byte .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .4byte .LASFDE1-__FRAME_BEGIN__ /* FDE CIE offset */ +#ifdef PIC + .4byte .LFB1-. /* FDE initial location */ +#else + .4byte .LFB1 /* FDE initial location */ +#endif + .4byte .LFE1-.LFB1 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI0-.LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI1-.LCFI0 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI2-.LCFI1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0xc /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI3-.LCFI2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x10 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI4-.LCFI3 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x14 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI5-.LCFI4 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x18 /* uleb128 0x4 */ + .byte 0x91 /* DW_CFA_offset, column 0x11 */ + .byte 0x6 /* uleb128 0x6 */ + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .byte 0x5 /* uleb128 0x5 */ + .byte 0x8c /* DW_CFA_offset, column 0xc */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x8a /* DW_CFA_offset, column 0xa */ + .byte 0x3 /* uleb128 0x3 */ + .byte 0x89 /* DW_CFA_offset, column 0x9 */ + .byte 0x2 /* uleb128 0x2 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .byte 0x1 /* uleb128 0x1 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI6-.LCFI5 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0xe /* uleb128 0xe */ + .align 2 +.LEFDE1: + +.LSFDE3: + .4byte .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .4byte .LASFDE3-__FRAME_BEGIN__ /* FDE CIE offset */ +#ifdef PIC + .4byte .LFB2-. /* FDE initial location */ +#else + .4byte .LFB2 /* FDE initial location */ +#endif + .4byte .LFE2-.LFB2 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI7-.LFB2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI8-.LCFI7 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFI9-.LCFI8 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0xc /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIA-.LCFI9 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x10 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIB-.LCFIA + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x14 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIC-.LCFIB + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x18 /* uleb128 0x4 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFID-.LCFIC + .byte 0xe /* DW_CFA_def_cfa_offset */ +#if defined(__SH4__) + .byte 24+48 /* uleb128 24+48 */ +#else + .byte 24+16 /* uleb128 24+16 */ +#endif + .byte 0x91 /* DW_CFA_offset, column 0x11 */ + .byte 0x6 /* uleb128 0x6 */ + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .byte 0x5 /* uleb128 0x5 */ + .byte 0x8b /* DW_CFA_offset, column 0xb */ + .byte 0x4 /* uleb128 0x4 */ + .byte 0x8a /* DW_CFA_offset, column 0xa */ + .byte 0x3 /* uleb128 0x3 */ + .byte 0x89 /* DW_CFA_offset, column 0x9 */ + .byte 0x2 /* uleb128 0x2 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .byte 0x1 /* uleb128 0x1 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte .LCFIE-.LCFID + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0xe /* uleb128 0xe */ + .align 2 +.LEFDE3: diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffi.c new file mode 100644 index 000000000..abf3f0d71 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffi.c @@ -0,0 +1,451 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2003, 2004 Kaz Kojima + + SuperH SHmedia Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +#define NGREGARG 8 +#define NFREGARG 12 + +static int +return_type (ffi_type *arg) +{ + + if (arg->type != FFI_TYPE_STRUCT) + return arg->type; + + /* gcc uses r2 if the result can be packed in on register. */ + if (arg->size <= sizeof (UINT8)) + return FFI_TYPE_UINT8; + else if (arg->size <= sizeof (UINT16)) + return FFI_TYPE_UINT16; + else if (arg->size <= sizeof (UINT32)) + return FFI_TYPE_UINT32; + else if (arg->size <= sizeof (UINT64)) + return FFI_TYPE_UINT64; + + return FFI_TYPE_STRUCT; +} + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register unsigned int avn; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += sizeof (UINT64); + } + + avn = ecif->cif->nargs; + p_argv = ecif->avalue; + + for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++) + { + size_t z; + int align; + + z = (*p_arg)->size; + align = (*p_arg)->alignment; + if (z < sizeof (UINT32)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv); + break; + + case FFI_TYPE_UINT8: + *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv); + break; + + case FFI_TYPE_SINT16: + *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv); + break; + + case FFI_TYPE_UINT16: + *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv); + break; + + case FFI_TYPE_STRUCT: + memcpy (argp, *p_argv, z); + break; + + default: + FFI_ASSERT(0); + } + argp += sizeof (UINT64); + } + else if (z == sizeof (UINT32) && align == sizeof (UINT32)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_INT: + case FFI_TYPE_SINT32: + *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv); + break; + + case FFI_TYPE_FLOAT: + case FFI_TYPE_POINTER: + case FFI_TYPE_UINT32: + case FFI_TYPE_STRUCT: + *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv); + break; + + default: + FFI_ASSERT(0); + break; + } + argp += sizeof (UINT64); + } + else if (z == sizeof (UINT64) + && align == sizeof (UINT64) + && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0) + { + *(UINT64 *) argp = *(UINT64 *) (*p_argv); + argp += sizeof (UINT64); + } + else + { + int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64); + + memcpy (argp, *p_argv, z); + argp += n * sizeof (UINT64); + } + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int i, j; + int size, type; + int n, m; + int greg; + int freg; + + greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0); + freg = 0; + cif->flags2 = 0; + + for (i = j = 0; i < cif->nargs; i++) + { + type = (cif->arg_types)[i]->type; + switch (type) + { + case FFI_TYPE_FLOAT: + greg++; + cif->bytes += sizeof (UINT64) - sizeof (float); + if (freg >= NFREGARG - 1) + continue; + freg++; + cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++); + break; + + case FFI_TYPE_DOUBLE: + if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG) + continue; + if ((freg + 1) < NFREGARG) + { + freg = (freg + 1) & ~1; + freg += 2; + cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++); + } + else + cif->flags2 += FFI_TYPE_INT << (2 * j++); + break; + + default: + size = (cif->arg_types)[i]->size; + if (size < sizeof (UINT64)) + cif->bytes += sizeof (UINT64) - size; + n = (size + sizeof (UINT64) - 1) / sizeof (UINT64); + if (greg >= NGREGARG) + continue; + else if (greg + n - 1 >= NGREGARG) + greg = NGREGARG; + else + greg += n; + for (m = 0; m < n; m++) + cif->flags2 += FFI_TYPE_INT << (2 * j++); + break; + } + } + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_STRUCT: + cif->flags = return_type (cif->rtype); + break; + + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + cif->flags = cif->rtype->type; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, long long, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + UINT64 trvalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if (cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + ecif.rvalue = &trvalue; + else if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, cif->flags2, ecif.rvalue, fn); + /*@=usedef@*/ + break; + default: + FFI_ASSERT(0); + break; + } + + if (rvalue + && cif->rtype->type == FFI_TYPE_STRUCT + && return_type (cif->rtype) != FFI_TYPE_STRUCT) + memcpy (rvalue, &trvalue, cif->rtype->size); +} + +extern void ffi_closure_SYSV (void); +extern void __ic_invalidate (void *line); + +ffi_status +ffi_prep_closure (ffi_closure *closure, + ffi_cif *cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp; + + FFI_ASSERT (cif->abi == FFI_GCC_SYSV); + + tramp = (unsigned int *) &closure->tramp[0]; + /* Since ffi_closure is an aligned object, the ffi trampoline is + called as an SHcompact code. Sigh. + SHcompact part: + mova @(1,pc),r0; add #1,r0; jmp @r0; nop; + SHmedia part: + movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0 + movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */ +#ifdef __LITTLE_ENDIAN__ + tramp[0] = 0x7001c701; + tramp[1] = 0x0009402b; +#else + tramp[0] = 0xc7017001; + tramp[1] = 0x402b0009; +#endif + tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10; + tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10; + tramp[4] = 0x6bf10600; + tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10; + tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10; + tramp[7] = 0x4401fff0; + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the icache. */ + asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp)); + + return FFI_OK; +} + +/* Basically the trampoline invokes ffi_closure_SYSV, and on + * entry, r3 holds the address of the closure. + * After storing the registers that could possibly contain + * parameters to be passed into the stack frame and setting + * up space for a return value, ffi_closure_SYSV invokes the + * following helper function to do most of the work. + */ + +int +ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue, + UINT64 *pgr, UINT64 *pfr, UINT64 *pst) +{ + void **avalue; + ffi_type **p_arg; + int i, avn; + int greg, freg; + ffi_cif *cif; + + cif = closure->cif; + avalue = alloca (cif->nargs * sizeof (void *)); + + /* Copy the caller's structure return value address so that the closure + returns the data directly to the caller. */ + if (return_type (cif->rtype) == FFI_TYPE_STRUCT) + { + rvalue = *pgr; + greg = 1; + } + else + greg = 0; + + freg = 0; + cif = closure->cif; + avn = cif->nargs; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) + { + size_t z; + void *p; + + z = (*p_arg)->size; + if (z < sizeof (UINT32)) + { + p = pgr + greg++; + + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT16: + case FFI_TYPE_STRUCT: +#ifdef __LITTLE_ENDIAN__ + avalue[i] = p; +#else + avalue[i] = ((char *) p) + sizeof (UINT32) - z; +#endif + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof (UINT32)) + { + if ((*p_arg)->type == FFI_TYPE_FLOAT) + { + if (freg < NFREGARG - 1) +#ifdef __LITTLE_ENDIAN__ + avalue[i] = (UINT32 *) pfr + (1 ^ freg++); +#else + avalue[i] = (UINT32 *) pfr + freg++; +#endif + else +#ifdef __LITTLE_ENDIAN__ + avalue[i] = pgr + greg; +#else + avalue[i] = (UINT32 *) (pgr + greg) + 1; +#endif + } + else +#ifdef __LITTLE_ENDIAN__ + avalue[i] = pgr + greg; +#else + avalue[i] = (UINT32 *) (pgr + greg) + 1; +#endif + greg++; + } + else if ((*p_arg)->type == FFI_TYPE_DOUBLE) + { + if (freg + 1 >= NFREGARG) + avalue[i] = pgr + greg; + else + { + freg = (freg + 1) & ~1; + avalue[i] = pfr + (freg >> 1); + freg += 2; + } + greg++; + } + else + { + int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64); + + avalue[i] = pgr + greg; + greg += n; + } + } + + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_SYSV how to perform return type promotions. */ + return return_type (cif->rtype); +} + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffitarget.h new file mode 100644 index 000000000..a174d09b9 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/ffitarget.h @@ -0,0 +1,52 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for SuperH - SHmedia. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; + +#define FFI_EXTRA_CIF_FIELDS long long flags2 +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 32 +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/sysv.S new file mode 100644 index 000000000..19f1b51b9 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sh64/sysv.S @@ -0,0 +1,525 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 2003, 2004 Kaz Kojima + + SuperH SHmedia Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> +#ifdef HAVE_MACHINE_ASM_H +#include <machine/asm.h> +#else +/* XXX these lose for some platforms, I'm sure. */ +#define CNAME(x) x +#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): +#endif + +#ifdef __LITTLE_ENDIAN__ +#define OFS_FLT 0 +#else +#define OFS_FLT 4 +#endif + + .section .text..SHmedia32,"ax" + + # r2: ffi_prep_args + # r3: &ecif + # r4: bytes + # r5: flags + # r6: flags2 + # r7: rvalue + # r8: fn + + # This assumes we are using gas. + .align 5 +ENTRY(ffi_call_SYSV) + # Save registers +.LFB1: + addi.l r15, -48, r15 +.LCFI0: + st.q r15, 40, r32 + st.q r15, 32, r31 + st.q r15, 24, r30 + st.q r15, 16, r29 + st.q r15, 8, r28 + st.l r15, 4, r18 + st.l r15, 0, r14 +.LCFI1: + add.l r15, r63, r14 +.LCFI2: +# add r4, r63, r28 + add r5, r63, r29 + add r6, r63, r30 + add r7, r63, r31 + add r8, r63, r32 + + addi r4, (64 + 7), r4 + andi r4, ~7, r4 + sub.l r15, r4, r15 + + ptabs/l r2, tr0 + add r15, r63, r2 + blink tr0, r18 + + addi r15, 64, r22 + movi 0, r0 + movi 0, r1 + + pt/l 1f, tr1 + bnei/l r29, FFI_TYPE_STRUCT, tr1 + ld.l r15, 0, r19 + addi r15, 8, r15 + addi r0, 1, r0 +1: + +.L_pass: + andi r30, 3, r20 + shlri r30, 2, r30 + + pt/l .L_call_it, tr0 + pt/l .L_pass_i, tr1 + pt/l .L_pass_f, tr2 + + beqi/l r20, FFI_TYPE_VOID, tr0 + beqi/l r20, FFI_TYPE_INT, tr1 + beqi/l r20, FFI_TYPE_FLOAT, tr2 + +.L_pass_d: + addi r0, 1, r0 + addi r1, 1, r1 + andi r1, ~1, r1 + + pt/l 3f, tr0 + movi 12, r20 + bge/l r1, r20, tr0 + + pt/l .L_pop_d, tr1 + pt/l 2f, tr0 + blink tr1, r63 +2: + addi.l r15, 8, r15 +3: + pt/l .L_pass, tr0 + addi r1, 2, r1 + blink tr0, r63 + +.L_pop_d: + pt/l .L_pop_d_tbl, tr1 + gettr tr1, r20 + shlli r1, 2, r21 + add r20, r21, r20 + ptabs/l r20, tr1 + blink tr1, r63 + +.L_pop_d_tbl: + fld.d r15, 0, dr0 + blink tr0, r63 + fld.d r15, 0, dr2 + blink tr0, r63 + fld.d r15, 0, dr4 + blink tr0, r63 + fld.d r15, 0, dr6 + blink tr0, r63 + fld.d r15, 0, dr8 + blink tr0, r63 + fld.d r15, 0, dr10 + blink tr0, r63 + +.L_pass_f: + addi r0, 1, r0 + pt/l 3f, tr0 + movi 12, r20 + bge/l r1, r20, tr0 + + pt/l .L_pop_f, tr1 + pt/l 2f, tr0 + blink tr1, r63 +2: + addi.l r15, 8, r15 +3: + pt/l .L_pass, tr0 + addi r1, 1, r1 + blink tr0, r63 + +.L_pop_f: + pt/l .L_pop_f_tbl, tr1 + gettr tr1, r20 + shlli r1, 3, r21 + add r20, r21, r20 + ptabs/l r20, tr1 + blink tr1, r63 + +.L_pop_f_tbl: + fld.s r15, OFS_FLT, fr0 + blink tr0, r63 + fld.s r15, OFS_FLT, fr1 + blink tr0, r63 + fld.s r15, OFS_FLT, fr2 + blink tr0, r63 + fld.s r15, OFS_FLT, fr3 + blink tr0, r63 + fld.s r15, OFS_FLT, fr4 + blink tr0, r63 + fld.s r15, OFS_FLT, fr5 + blink tr0, r63 + fld.s r15, OFS_FLT, fr6 + blink tr0, r63 + fld.s r15, OFS_FLT, fr7 + blink tr0, r63 + fld.s r15, OFS_FLT, fr8 + blink tr0, r63 + fld.s r15, OFS_FLT, fr9 + blink tr0, r63 + fld.s r15, OFS_FLT, fr10 + blink tr0, r63 + fld.s r15, OFS_FLT, fr11 + blink tr0, r63 + +.L_pass_i: + pt/l 3f, tr0 + movi 8, r20 + bge/l r0, r20, tr0 + + pt/l .L_pop_i, tr1 + pt/l 2f, tr0 + blink tr1, r63 +2: + addi.l r15, 8, r15 +3: + pt/l .L_pass, tr0 + addi r0, 1, r0 + blink tr0, r63 + +.L_pop_i: + pt/l .L_pop_i_tbl, tr1 + gettr tr1, r20 + shlli r0, 3, r21 + add r20, r21, r20 + ptabs/l r20, tr1 + blink tr1, r63 + +.L_pop_i_tbl: + ld.q r15, 0, r2 + blink tr0, r63 + ld.q r15, 0, r3 + blink tr0, r63 + ld.q r15, 0, r4 + blink tr0, r63 + ld.q r15, 0, r5 + blink tr0, r63 + ld.q r15, 0, r6 + blink tr0, r63 + ld.q r15, 0, r7 + blink tr0, r63 + ld.q r15, 0, r8 + blink tr0, r63 + ld.q r15, 0, r9 + blink tr0, r63 + +.L_call_it: + # call function + pt/l 1f, tr1 + bnei/l r29, FFI_TYPE_STRUCT, tr1 + add r19, r63, r2 +1: + add r22, r63, r15 + ptabs/l r32, tr0 + blink tr0, r18 + + pt/l .L_ret_i, tr0 + pt/l .L_ret_ll, tr1 + pt/l .L_ret_d, tr2 + pt/l .L_ret_f, tr3 + pt/l .L_epilogue, tr4 + + beqi/l r29, FFI_TYPE_INT, tr0 + beqi/l r29, FFI_TYPE_UINT32, tr0 + beqi/l r29, FFI_TYPE_SINT64, tr1 + beqi/l r29, FFI_TYPE_UINT64, tr1 + beqi/l r29, FFI_TYPE_DOUBLE, tr2 + beqi/l r29, FFI_TYPE_FLOAT, tr3 + + pt/l .L_ret_q, tr0 + pt/l .L_ret_h, tr1 + + beqi/l r29, FFI_TYPE_UINT8, tr0 + beqi/l r29, FFI_TYPE_UINT16, tr1 + blink tr4, r63 + +.L_ret_d: + fst.d r31, 0, dr0 + blink tr4, r63 + +.L_ret_ll: + st.q r31, 0, r2 + blink tr4, r63 + +.L_ret_f: + fst.s r31, OFS_FLT, fr0 + blink tr4, r63 + +.L_ret_q: + st.b r31, 0, r2 + blink tr4, r63 + +.L_ret_h: + st.w r31, 0, r2 + blink tr4, r63 + +.L_ret_i: + st.l r31, 0, r2 + # Fall + +.L_epilogue: + # Remove the space we pushed for the args + add r14, r63, r15 + + ld.l r15, 0, r14 + ld.l r15, 4, r18 + ld.q r15, 8, r28 + ld.q r15, 16, r29 + ld.q r15, 24, r30 + ld.q r15, 32, r31 + ld.q r15, 40, r32 + addi.l r15, 48, r15 + ptabs r18, tr0 + blink tr0, r63 + +.LFE1: +.ffi_call_SYSV_end: + .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + + .align 5 +ENTRY(ffi_closure_SYSV) +.LFB2: + addi.l r15, -136, r15 +.LCFI3: + st.l r15, 12, r18 + st.l r15, 8, r14 + st.l r15, 4, r12 +.LCFI4: + add r15, r63, r14 +.LCFI5: + /* Stack layout: + ... + 64 bytes (register parameters) + 48 bytes (floating register parameters) + 8 bytes (result) + 4 bytes (r18) + 4 bytes (r14) + 4 bytes (r12) + 4 bytes (for align) + <- new stack pointer + */ + fst.d r14, 24, dr0 + fst.d r14, 32, dr2 + fst.d r14, 40, dr4 + fst.d r14, 48, dr6 + fst.d r14, 56, dr8 + fst.d r14, 64, dr10 + st.q r14, 72, r2 + st.q r14, 80, r3 + st.q r14, 88, r4 + st.q r14, 96, r5 + st.q r14, 104, r6 + st.q r14, 112, r7 + st.q r14, 120, r8 + st.q r14, 128, r9 + + add r1, r63, r2 + addi r14, 16, r3 + addi r14, 72, r4 + addi r14, 24, r5 + addi r14, 136, r6 +#ifdef PIC + movi (((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) >> 16) & 65535), r12 + shori ((datalabel _GLOBAL_OFFSET_TABLE_-(.LPCS0-.)) & 65535), r12 +.LPCS0: ptrel/u r12, tr0 + movi ((ffi_closure_helper_SYSV@GOTPLT) & 65535), r1 + gettr tr0, r12 + ldx.l r1, r12, r1 + ptabs r1, tr0 +#else + pt/l ffi_closure_helper_SYSV, tr0 +#endif + blink tr0, r18 + + shlli r2, 1, r1 + movi (((datalabel .L_table) >> 16) & 65535), r2 + shori ((datalabel .L_table) & 65535), r2 + ldx.w r2, r1, r1 + add r1, r2, r1 + pt/l .L_case_v, tr1 + ptabs r1, tr0 + blink tr0, r63 + + .align 2 +.L_table: + .word .L_case_v - datalabel .L_table /* FFI_TYPE_VOID */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_INT */ + .word .L_case_f - datalabel .L_table /* FFI_TYPE_FLOAT */ + .word .L_case_d - datalabel .L_table /* FFI_TYPE_DOUBLE */ + .word .L_case_d - datalabel .L_table /* FFI_TYPE_LONGDOUBLE */ + .word .L_case_uq - datalabel .L_table /* FFI_TYPE_UINT8 */ + .word .L_case_q - datalabel .L_table /* FFI_TYPE_SINT8 */ + .word .L_case_uh - datalabel .L_table /* FFI_TYPE_UINT16 */ + .word .L_case_h - datalabel .L_table /* FFI_TYPE_SINT16 */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_UINT32 */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_SINT32 */ + .word .L_case_ll - datalabel .L_table /* FFI_TYPE_UINT64 */ + .word .L_case_ll - datalabel .L_table /* FFI_TYPE_SINT64 */ + .word .L_case_v - datalabel .L_table /* FFI_TYPE_STRUCT */ + .word .L_case_i - datalabel .L_table /* FFI_TYPE_POINTER */ + + .align 2 +.L_case_d: + fld.d r14, 16, dr0 + blink tr1, r63 +.L_case_f: + fld.s r14, 16, fr0 + blink tr1, r63 +.L_case_ll: + ld.q r14, 16, r2 + blink tr1, r63 +.L_case_i: + ld.l r14, 16, r2 + blink tr1, r63 +.L_case_q: + ld.b r14, 16, r2 + blink tr1, r63 +.L_case_uq: + ld.ub r14, 16, r2 + blink tr1, r63 +.L_case_h: + ld.w r14, 16, r2 + blink tr1, r63 +.L_case_uh: + ld.uw r14, 16, r2 + blink tr1, r63 +.L_case_v: + add.l r14, r63, r15 + ld.l r15, 4, r12 + ld.l r15, 8, r14 + ld.l r15, 12, r18 + addi.l r15, 136, r15 + ptabs r18, tr0 + blink tr0, r63 + +.LFE2: +.ffi_closure_SYSV_end: + .size CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV) + + .section ".eh_frame","aw",@progbits +__FRAME_BEGIN__: + .4byte .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .4byte 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef PIC + .ascii "zR\0" /* CIE Augmentation */ +#else + .byte 0x0 /* CIE Augmentation */ +#endif + .uleb128 0x1 /* CIE Code Alignment Factor */ + .sleb128 -4 /* CIE Data Alignment Factor */ + .byte 0x12 /* CIE RA Column */ +#ifdef PIC + .uleb128 0x1 /* Augmentation size */ + .byte 0x10 /* FDE Encoding (pcrel) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .uleb128 0xf + .uleb128 0x0 + .align 2 +.LECIE1: +.LSFDE1: + .4byte datalabel .LEFDE1-datalabel .LASFDE1 /* FDE Length */ +.LASFDE1: + .4byte datalabel .LASFDE1-datalabel __FRAME_BEGIN__ +#ifdef PIC + .4byte .LFB1-. /* FDE initial location */ +#else + .4byte .LFB1 /* FDE initial location */ +#endif + .4byte datalabel .LFE1-datalabel .LFB1 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI0-datalabel .LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 0x30 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI1-datalabel .LCFI0 + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .uleb128 0xc + .byte 0x92 /* DW_CFA_offset, column 0x12 */ + .uleb128 0xb + .byte 0x9c /* DW_CFA_offset, column 0x1c */ + .uleb128 0xa + .byte 0x9d /* DW_CFA_offset, column 0x1d */ + .uleb128 0x8 + .byte 0x9e /* DW_CFA_offset, column 0x1e */ + .uleb128 0x6 + .byte 0x9f /* DW_CFA_offset, column 0x1f */ + .uleb128 0x4 + .byte 0xa0 /* DW_CFA_offset, column 0x20 */ + .uleb128 0x2 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI2-datalabel .LCFI1 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0xe + .align 2 +.LEFDE1: + +.LSFDE3: + .4byte datalabel .LEFDE3-datalabel .LASFDE3 /* FDE Length */ +.LASFDE3: + .4byte datalabel .LASFDE3-datalabel __FRAME_BEGIN__ +#ifdef PIC + .4byte .LFB2-. /* FDE initial location */ +#else + .4byte .LFB2 /* FDE initial location */ +#endif + .4byte datalabel .LFE2-datalabel .LFB2 /* FDE address range */ +#ifdef PIC + .uleb128 0x0 /* Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI3-datalabel .LFB2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 0x88 + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI4-datalabel .LCFI3 + .byte 0x8c /* DW_CFA_offset, column 0xc */ + .uleb128 0x21 + .byte 0x8e /* DW_CFA_offset, column 0xe */ + .uleb128 0x20 + .byte 0x92 /* DW_CFA_offset, column 0x12 */ + .uleb128 0x1f + .byte 0x4 /* DW_CFA_advance_loc4 */ + .4byte datalabel .LCFI5-datalabel .LCFI4 + .byte 0xd /* DW_CFA_def_cfa_register */ + .uleb128 0xe + .align 2 +.LEFDE3: diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffi.c new file mode 100644 index 000000000..b83d63ded --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffi.c @@ -0,0 +1,608 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 2003, 2004 Red Hat, Inc. + + SPARC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +void ffi_prep_args_v8(char *stack, extended_cif *ecif) +{ + int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + + /* Skip 16 words for the window save area */ + argp = stack + 16*sizeof(int); + + /* This should only really be done when we are returning a structure, + however, it's faster just to do it all the time... + + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */ + *(int *) argp = (long)ecif->rvalue; + + /* And 1 word for the structure return value. */ + argp += sizeof(int); + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, unless we + zero out this memory. */ + + ((int*)argp)[0] = 0; + ((int*)argp)[1] = 0; + ((int*)argp)[2] = 0; + ((int*)argp)[3] = 0; + ((int*)argp)[4] = 0; + ((int*)argp)[5] = 0; +#endif + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) + { + size_t z; + + if ((*p_arg)->type == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || (*p_arg)->type == FFI_TYPE_LONGDOUBLE +#endif + ) + { + *(unsigned int *) argp = (unsigned long)(* p_argv); + z = sizeof(int); + } + else + { + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = *(UINT16 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + } + p_argv++; + argp += z; + } + + return; +} + +int ffi_prep_args_v9(char *stack, extended_cif *ecif) +{ + int i, ret = 0; + int tmp; + void **p_argv; + char *argp; + ffi_type **p_arg; + + tmp = 0; + + /* Skip 16 words for the window save area */ + argp = stack + 16*sizeof(long long); + +#ifdef USING_PURIFY + /* Purify will probably complain in our assembly routine, unless we + zero out this memory. */ + + ((long long*)argp)[0] = 0; + ((long long*)argp)[1] = 0; + ((long long*)argp)[2] = 0; + ((long long*)argp)[3] = 0; + ((long long*)argp)[4] = 0; + ((long long*)argp)[5] = 0; +#endif + + p_argv = ecif->avalue; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && + ecif->cif->rtype->size > 32) + { + *(unsigned long long *) argp = (unsigned long)ecif->rvalue; + argp += sizeof(long long); + tmp = 1; + } + + for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; + i++, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + switch ((*p_arg)->type) + { + case FFI_TYPE_STRUCT: + if (z > 16) + { + /* For structures larger than 16 bytes we pass reference. */ + *(unsigned long long *) argp = (unsigned long)* p_argv; + argp += sizeof(long long); + tmp++; + p_argv++; + continue; + } + /* FALLTHROUGH */ + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + ret = 1; /* We should promote into FP regs as well as integer. */ + break; + } + if (z < sizeof(long long)) + { + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed long long *) argp = *(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned long long *) argp = *(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed long long *) argp = *(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned long long *) argp = *(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(signed long long *) argp = *(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned long long *) argp = *(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_FLOAT: + *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */ + break; + + case FFI_TYPE_STRUCT: + memcpy(argp, *p_argv, z); + break; + + default: + FFI_ASSERT(0); + } + z = sizeof(long long); + tmp++; + } + else if (z == sizeof(long long)) + { + memcpy(argp, *p_argv, z); + z = sizeof(long long); + tmp++; + } + else + { + if ((tmp & 1) && (*p_arg)->alignment > 8) + { + tmp++; + argp += sizeof(long long); + } + memcpy(argp, *p_argv, z); + z = 2 * sizeof(long long); + tmp += 2; + } + p_argv++; + argp += z; + } + + return ret; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + int wordsize; + + if (cif->abi != FFI_V9) + { + wordsize = 4; + + /* If we are returning a struct, this will already have been added. + Otherwise we need to add it because it's always got to be there! */ + + if (cif->rtype->type != FFI_TYPE_STRUCT) + cif->bytes += wordsize; + + /* sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + + if (cif->bytes < 4*6+4) + cif->bytes = 4*6+4; + } + else + { + wordsize = 8; + + /* sparc call frames require that space is allocated for 6 args, + even if they aren't used. Make that space if necessary. */ + + if (cif->bytes < 8*6) + cif->bytes = 8*6; + } + + /* Adjust cif->bytes. to include 16 words for the window save area, + and maybe the struct/union return pointer area, */ + + cif->bytes += 16 * wordsize; + + /* The stack must be 2 word aligned, so round bytes up + appropriately. */ + + cif->bytes = ALIGN(cif->bytes, 2 * wordsize); + + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + cif->flags = cif->rtype->type; + break; + + case FFI_TYPE_STRUCT: + if (cif->abi == FFI_V9 && cif->rtype->size > 32) + cif->flags = FFI_TYPE_VOID; + else + cif->flags = FFI_TYPE_STRUCT; + break; + + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + if (cif->abi != FFI_V9) + { + cif->flags = FFI_TYPE_SINT64; + break; + } + /* FALLTHROUGH */ + default: + cif->flags = FFI_TYPE_INT; + break; + } + return FFI_OK; +} + +int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt) +{ + ffi_type **ptr = &arg->elements[0]; + + while (*ptr != NULL) + { + if (off & ((*ptr)->alignment - 1)) + off = ALIGN(off, (*ptr)->alignment); + + switch ((*ptr)->type) + { + case FFI_TYPE_STRUCT: + off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt); + off = ALIGN(off, FFI_SIZEOF_ARG); + break; + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + case FFI_TYPE_LONGDOUBLE: +#endif + memmove(ret + off, flt + off, (*ptr)->size); + off += (*ptr)->size; + break; + default: + memmove(ret + off, intg + off, (*ptr)->size); + off += (*ptr)->size; + break; + } + ptr++; + } + return off; +} + + +#ifdef SPARC64 +extern int ffi_call_v9(void *, extended_cif *, unsigned, + unsigned, unsigned *, void (*fn)()); +#else +extern int ffi_call_v8(void *, extended_cif *, unsigned, + unsigned, unsigned *, void (*fn)()); +#endif + +void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) +{ + extended_cif ecif; + void *rval = rvalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + ecif.rvalue = rvalue; + if (cif->rtype->type == FFI_TYPE_STRUCT) + { + if (cif->rtype->size <= 32) + rval = alloca(64); + else + { + rval = NULL; + if (rvalue == NULL) + ecif.rvalue = alloca(cif->rtype->size); + } + } + + switch (cif->abi) + { + case FFI_V8: +#ifdef SPARC64 + /* We don't yet support calling 32bit code from 64bit */ + FFI_ASSERT(0); +#else + ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes, + cif->flags, rvalue, fn); +#endif + break; + case FFI_V9: +#ifdef SPARC64 + ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes, + cif->flags, rval, fn); + if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT) + ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32); +#else + /* And vice versa */ + FFI_ASSERT(0); +#endif + break; + default: + FFI_ASSERT(0); + break; + } + +} + + +#ifdef SPARC64 +extern void ffi_closure_v9(void); +#else +extern void ffi_closure_v8(void); +#endif + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + unsigned int *tramp = (unsigned int *) &closure->tramp[0]; + unsigned long fn; +#ifdef SPARC64 + /* Trampoline address is equal to the closure address. We take advantage + of that to reduce the trampoline size by 8 bytes. */ + FFI_ASSERT (cif->abi == FFI_V9); + fn = (unsigned long) ffi_closure_v9; + tramp[0] = 0x83414000; /* rd %pc, %g1 */ + tramp[1] = 0xca586010; /* ldx [%g1+16], %g5 */ + tramp[2] = 0x81c14000; /* jmp %g5 */ + tramp[3] = 0x01000000; /* nop */ + *((unsigned long *) &tramp[4]) = fn; +#else + unsigned long ctx = (unsigned long) closure; + FFI_ASSERT (cif->abi == FFI_V8); + fn = (unsigned long) ffi_closure_v8; + tramp[0] = 0x03000000 | fn >> 10; /* sethi %hi(fn), %g1 */ + tramp[1] = 0x05000000 | ctx >> 10; /* sethi %hi(ctx), %g2 */ + tramp[2] = 0x81c06000 | (fn & 0x3ff); /* jmp %g1+%lo(fn) */ + tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or %g2, %lo(ctx) */ +#endif + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + /* Flush the Icache. FIXME: alignment isn't certain, assume 8 bytes */ +#ifdef SPARC64 + asm volatile ("flush %0" : : "r" (closure) : "memory"); + asm volatile ("flush %0" : : "r" (((char *) closure) + 8) : "memory"); +#else + asm volatile ("iflush %0" : : "r" (closure) : "memory"); + asm volatile ("iflush %0" : : "r" (((char *) closure) + 8) : "memory"); +#endif + + return FFI_OK; +} + +int +ffi_closure_sparc_inner_v8(ffi_closure *closure, + void *rvalue, unsigned long *gpr, unsigned long *scratch) +{ + ffi_cif *cif; + ffi_type **arg_types; + void **avalue; + int i, argn; + + cif = closure->cif; + arg_types = cif->arg_types; + avalue = alloca(cif->nargs * sizeof(void *)); + + /* Copy the caller's structure return address so that the closure + returns the data directly to the caller. */ + if (cif->flags == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || cif->flags == FFI_TYPE_LONGDOUBLE +#endif + ) + rvalue = (void *) gpr[0]; + + /* Always skip the structure return address. */ + argn = 1; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < cif->nargs; i++) + { + if (arg_types[i]->type == FFI_TYPE_STRUCT +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_LONGDOUBLE +#endif + ) + { + /* Straight copy of invisible reference. */ + avalue[i] = (void *)gpr[argn++]; + } + else if ((arg_types[i]->type == FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_SINT64 + || arg_types[i]->type == FFI_TYPE_UINT64) + /* gpr is 8-byte aligned. */ + && (argn % 2) != 0) + { + /* Align on a 8-byte boundary. */ + scratch[0] = gpr[argn]; + scratch[1] = gpr[argn+1]; + avalue[i] = scratch; + scratch -= 2; + argn += 2; + } + else + { + /* Always right-justify. */ + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; + } + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_sparc how to perform return type promotions. */ + return cif->rtype->type; +} + +int +ffi_closure_sparc_inner_v9(ffi_closure *closure, + void *rvalue, unsigned long *gpr, double *fpr) +{ + ffi_cif *cif; + ffi_type **arg_types; + void **avalue; + int i, argn, fp_slot_max; + + cif = closure->cif; + arg_types = cif->arg_types; + avalue = alloca(cif->nargs * sizeof(void *)); + + /* Copy the caller's structure return address so that the closure + returns the data directly to the caller. */ + if (cif->flags == FFI_TYPE_VOID + && cif->rtype->type == FFI_TYPE_STRUCT) + { + rvalue = (void *) gpr[0]; + /* Skip the structure return address. */ + argn = 1; + } + else + argn = 0; + + fp_slot_max = 16 - argn; + + /* Grab the addresses of the arguments from the stack frame. */ + for (i = 0; i < cif->nargs; i++) + { + if (arg_types[i]->type == FFI_TYPE_STRUCT) + { + if (arg_types[i]->size > 16) + { + /* Straight copy of invisible reference. */ + avalue[i] = (void *)gpr[argn++]; + } + else + { + /* Left-justify. */ + ffi_v9_layout_struct(arg_types[i], + 0, + (char *) &gpr[argn], + (char *) &gpr[argn], + (char *) &fpr[argn]); + avalue[i] = &gpr[argn]; + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + } + } + else + { + /* Right-justify. */ + argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; + + if (i < fp_slot_max + && (arg_types[i]->type == FFI_TYPE_FLOAT + || arg_types[i]->type == FFI_TYPE_DOUBLE +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + || arg_types[i]->type == FFI_TYPE_LONGDOUBLE +#endif + )) + avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size; + else + avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size; + } + } + + /* Invoke the closure. */ + (closure->fun) (cif, rvalue, avalue, closure->user_data); + + /* Tell ffi_closure_sparc how to perform return type promotions. */ + return cif->rtype->type; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffitarget.h new file mode 100644 index 000000000..f4514e55d --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/ffitarget.h @@ -0,0 +1,65 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for SPARC. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#if defined(__arch64__) || defined(__sparcv9) +#define SPARC64 +#endif + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_V8, + FFI_V8PLUS, + FFI_V9, +#ifdef SPARC64 + FFI_DEFAULT_ABI = FFI_V9, +#else + FFI_DEFAULT_ABI = FFI_V8, +#endif + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_NATIVE_RAW_API 0 + +#ifdef SPARC64 +#define FFI_TRAMPOLINE_SIZE 24 +#else +#define FFI_TRAMPOLINE_SIZE 16 +#endif + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v8.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v8.S new file mode 100644 index 000000000..709423ce9 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v8.S @@ -0,0 +1,267 @@ +/* ----------------------------------------------------------------------- + v8.S - Copyright (c) 1996, 1997, 2003, 2004 Red Hat, Inc. + + SPARC Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#define STACKFRAME 96 /* Minimum stack framesize for SPARC */ +#define ARGS (64+4) /* Offset of register area in frame */ + +.text + .align 8 +.globl ffi_call_v8 +.globl _ffi_call_v8 + +ffi_call_v8: +_ffi_call_v8: +.LLFB1: + save %sp, -STACKFRAME, %sp +.LLCFI0: + + sub %sp, %i2, %sp ! alloca() space in stack for frame to set up + add %sp, STACKFRAME, %l0 ! %l0 has start of + ! frame to set up + + mov %l0, %o0 ! call routine to set up frame + call %i0 + mov %i1, %o1 ! (delay) + + ld [%l0+ARGS], %o0 ! call foreign function + ld [%l0+ARGS+4], %o1 + ld [%l0+ARGS+8], %o2 + ld [%l0+ARGS+12], %o3 + ld [%l0+ARGS+16], %o4 + ld [%l0+ARGS+20], %o5 + call %i5 + mov %l0, %sp ! (delay) switch to frame + nop ! STRUCT returning functions skip 12 instead of 8 bytes + + ! If the return value pointer is NULL, assume no return value. + tst %i4 + bz done + nop + + cmp %i3, FFI_TYPE_INT + be,a done + st %o0, [%i4] ! (delay) + + cmp %i3, FFI_TYPE_FLOAT + be,a done + st %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_SINT64 + be longlong + + cmp %i3, FFI_TYPE_DOUBLE + bne done + nop + st %f0, [%i4+0] + st %f1, [%i4+4] + +done: + ret + restore + +longlong: + st %o0, [%i4+0] + st %o1, [%i4+4] + ret + restore +.LLFE1: + +.ffi_call_v8_end: + .size ffi_call_v8,.ffi_call_v8_end-ffi_call_v8 + + +#undef STACKFRAME +#define STACKFRAME 104 /* 16*4 register window + + 1*4 struct return + + 6*4 args backing store + + 3*4 locals */ + +/* ffi_closure_v8(...) + + Receives the closure argument in %g2. */ + + .text + .align 8 + .globl ffi_closure_v8 + +ffi_closure_v8: +#ifdef HAVE_AS_REGISTER_PSEUDO_OP + .register %g2, #scratch +#endif +.LLFB2: + ! Reserve frame space for all arguments in case + ! we need to align them on a 8-byte boundary. + ld [%g2+FFI_TRAMPOLINE_SIZE], %g1 + ld [%g1+4], %g1 + sll %g1, 3, %g1 + add %g1, STACKFRAME, %g1 + ! %g1 == STACKFRAME + 8*nargs + neg %g1 + save %sp, %g1, %sp +.LLCFI1: + + ! Store all of the potential argument registers in va_list format. + st %i0, [%fp+68+0] + st %i1, [%fp+68+4] + st %i2, [%fp+68+8] + st %i3, [%fp+68+12] + st %i4, [%fp+68+16] + st %i5, [%fp+68+20] + + ! Call ffi_closure_sparc_inner to do the bulk of the work. + mov %g2, %o0 + add %fp, -8, %o1 + add %fp, 64, %o2 + call ffi_closure_sparc_inner_v8 + add %fp, -16, %o3 + + ! Load up the return value in the proper type. + ! See ffi_prep_cif_machdep for the list of cases. + cmp %o0, FFI_TYPE_VOID + be done1 + + cmp %o0, FFI_TYPE_INT + be integer + + cmp %o0, FFI_TYPE_FLOAT + be,a done1 + ld [%fp-8], %f0 + + cmp %o0, FFI_TYPE_DOUBLE + be,a done1 + ldd [%fp-8], %f0 + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + cmp %o0, FFI_TYPE_LONGDOUBLE + be done2 +#endif + + cmp %o0, FFI_TYPE_STRUCT + be done2 + + ! FFI_TYPE_SINT64 + ! FFI_TYPE_UINT64 + ld [%fp-4], %i1 + +integer: + ld [%fp-8], %i0 + +done1: + jmp %i7+8 + restore +done2: + ! Skip 'unimp'. + jmp %i7+12 + restore +.LLFE2: + +.ffi_closure_v8_end: + .size ffi_closure_v8,.ffi_closure_v8_end-ffi_closure_v8 + +#ifdef SPARC64 +#define WS 8 +#define nword xword +#define uanword uaxword +#else +#define WS 4 +#define nword long +#define uanword uaword +#endif + +#ifdef HAVE_RO_EH_FRAME + .section ".eh_frame",#alloc +#else + .section ".eh_frame",#alloc,#write +#endif +.LLframe1: + .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry +.LLSCIE1: + .uaword 0x0 ! CIE Identifier Tag + .byte 0x1 ! CIE Version + .ascii "zR\0" ! CIE Augmentation + .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor + .byte 0x80-WS ! sleb128 -WS; CIE Data Alignment Factor + .byte 0xf ! CIE RA Column + .byte 0x1 ! uleb128 0x1; Augmentation size +#ifdef HAVE_AS_SPARC_UA_PCREL + .byte 0x1b ! FDE Encoding (pcrel sdata4) +#else + .byte 0x50 ! FDE Encoding (aligned absolute) +#endif + .byte 0xc ! DW_CFA_def_cfa + .byte 0xe ! uleb128 0xe + .byte 0x0 ! uleb128 0x0 + .align WS +.LLECIE1: +.LLSFDE1: + .uaword .LLEFDE1-.LLASFDE1 ! FDE Length +.LLASFDE1: + .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB1) + .uaword .LLFE1-.LLFB1 ! FDE address range +#else + .align WS + .nword .LLFB1 + .uanword .LLFE1-.LLFB1 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI0-.LLFB1 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align WS +.LLEFDE1: +.LLSFDE2: + .uaword .LLEFDE2-.LLASFDE2 ! FDE Length +.LLASFDE2: + .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB2) + .uaword .LLFE2-.LLFB2 ! FDE address range +#else + .align WS + .nword .LLFB2 + .uanword .LLFE2-.LLFB2 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI1-.LLFB2 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align WS +.LLEFDE2: diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v9.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v9.S new file mode 100644 index 000000000..d640e0232 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/sparc/v9.S @@ -0,0 +1,302 @@ +/* ----------------------------------------------------------------------- + v9.S - Copyright (c) 2000, 2003, 2004 Red Hat, Inc. + + SPARC 64-bit Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#ifdef SPARC64 +/* Only compile this in for 64bit builds, because otherwise the object file + will have inproper architecture due to used instructions. */ + +#define STACKFRAME 128 /* Minimum stack framesize for SPARC */ +#define STACK_BIAS 2047 +#define ARGS (128) /* Offset of register area in frame */ + +.text + .align 8 +.globl ffi_call_v9 +.globl _ffi_call_v9 + +ffi_call_v9: +_ffi_call_v9: +.LLFB1: + save %sp, -STACKFRAME, %sp +.LLCFI0: + + sub %sp, %i2, %sp ! alloca() space in stack for frame to set up + add %sp, STACKFRAME+STACK_BIAS, %l0 ! %l0 has start of + ! frame to set up + + mov %l0, %o0 ! call routine to set up frame + call %i0 + mov %i1, %o1 ! (delay) + brz,pt %o0, 1f + ldx [%l0+ARGS], %o0 ! call foreign function + + ldd [%l0+ARGS], %f0 + ldd [%l0+ARGS+8], %f2 + ldd [%l0+ARGS+16], %f4 + ldd [%l0+ARGS+24], %f6 + ldd [%l0+ARGS+32], %f8 + ldd [%l0+ARGS+40], %f10 + ldd [%l0+ARGS+48], %f12 + ldd [%l0+ARGS+56], %f14 + ldd [%l0+ARGS+64], %f16 + ldd [%l0+ARGS+72], %f18 + ldd [%l0+ARGS+80], %f20 + ldd [%l0+ARGS+88], %f22 + ldd [%l0+ARGS+96], %f24 + ldd [%l0+ARGS+104], %f26 + ldd [%l0+ARGS+112], %f28 + ldd [%l0+ARGS+120], %f30 + +1: ldx [%l0+ARGS+8], %o1 + ldx [%l0+ARGS+16], %o2 + ldx [%l0+ARGS+24], %o3 + ldx [%l0+ARGS+32], %o4 + ldx [%l0+ARGS+40], %o5 + call %i5 + sub %l0, STACK_BIAS, %sp ! (delay) switch to frame + + ! If the return value pointer is NULL, assume no return value. + brz,pn %i4, done + nop + + cmp %i3, FFI_TYPE_INT + be,a,pt %icc, done + stx %o0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_FLOAT + be,a,pn %icc, done + st %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_DOUBLE + be,a,pn %icc, done + std %f0, [%i4+0] ! (delay) + + cmp %i3, FFI_TYPE_STRUCT + be,pn %icc, dostruct + + cmp %i3, FFI_TYPE_LONGDOUBLE + bne,pt %icc, done + nop + std %f0, [%i4+0] + std %f2, [%i4+8] + +done: ret + restore + +dostruct: + /* This will not work correctly for unions. */ + stx %o0, [%i4+0] + stx %o1, [%i4+8] + stx %o2, [%i4+16] + stx %o3, [%i4+24] + std %f0, [%i4+32] + std %f2, [%i4+40] + std %f4, [%i4+48] + std %f6, [%i4+56] + ret + restore +.LLFE1: + +.ffi_call_v9_end: + .size ffi_call_v9,.ffi_call_v9_end-ffi_call_v9 + + +#undef STACKFRAME +#define STACKFRAME 336 /* 16*8 register window + + 6*8 args backing store + + 20*8 locals */ +#define FP %fp+STACK_BIAS + +/* ffi_closure_v9(...) + + Receives the closure argument in %g1. */ + + .text + .align 8 + .globl ffi_closure_v9 + +ffi_closure_v9: +.LLFB2: + save %sp, -STACKFRAME, %sp +.LLCFI1: + + ! Store all of the potential argument registers in va_list format. + stx %i0, [FP+128+0] + stx %i1, [FP+128+8] + stx %i2, [FP+128+16] + stx %i3, [FP+128+24] + stx %i4, [FP+128+32] + stx %i5, [FP+128+40] + + ! Store possible floating point argument registers too. + std %f0, [FP-128] + std %f2, [FP-120] + std %f4, [FP-112] + std %f6, [FP-104] + std %f8, [FP-96] + std %f10, [FP-88] + std %f12, [FP-80] + std %f14, [FP-72] + std %f16, [FP-64] + std %f18, [FP-56] + std %f20, [FP-48] + std %f22, [FP-40] + std %f24, [FP-32] + std %f26, [FP-24] + std %f28, [FP-16] + std %f30, [FP-8] + + ! Call ffi_closure_sparc_inner to do the bulk of the work. + mov %g1, %o0 + add %fp, STACK_BIAS-160, %o1 + add %fp, STACK_BIAS+128, %o2 + call ffi_closure_sparc_inner_v9 + add %fp, STACK_BIAS-128, %o3 + + ! Load up the return value in the proper type. + ! See ffi_prep_cif_machdep for the list of cases. + cmp %o0, FFI_TYPE_VOID + be,pn %icc, done1 + + cmp %o0, FFI_TYPE_INT + be,pn %icc, integer + + cmp %o0, FFI_TYPE_FLOAT + be,a,pn %icc, done1 + ld [FP-160], %f0 + + cmp %o0, FFI_TYPE_DOUBLE + be,a,pn %icc, done1 + ldd [FP-160], %f0 + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE + cmp %o0, FFI_TYPE_LONGDOUBLE + be,a,pn %icc, longdouble1 + ldd [FP-160], %f0 +#endif + + ! FFI_TYPE_STRUCT + ldx [FP-152], %i1 + ldx [FP-144], %i2 + ldx [FP-136], %i3 + ldd [FP-160], %f0 + ldd [FP-152], %f2 + ldd [FP-144], %f4 + ldd [FP-136], %f6 + +integer: + ldx [FP-160], %i0 + +done1: + ret + restore + +#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE +longdouble1: + ldd [FP-152], %f2 + ret + restore +#endif +.LLFE2: + +.ffi_closure_v9_end: + .size ffi_closure_v9,.ffi_closure_v9_end-ffi_closure_v9 + +#ifdef HAVE_RO_EH_FRAME + .section ".eh_frame",#alloc +#else + .section ".eh_frame",#alloc,#write +#endif +.LLframe1: + .uaword .LLECIE1-.LLSCIE1 ! Length of Common Information Entry +.LLSCIE1: + .uaword 0x0 ! CIE Identifier Tag + .byte 0x1 ! CIE Version + .ascii "zR\0" ! CIE Augmentation + .byte 0x1 ! uleb128 0x1; CIE Code Alignment Factor + .byte 0x78 ! sleb128 -8; CIE Data Alignment Factor + .byte 0xf ! CIE RA Column + .byte 0x1 ! uleb128 0x1; Augmentation size +#ifdef HAVE_AS_SPARC_UA_PCREL + .byte 0x1b ! FDE Encoding (pcrel sdata4) +#else + .byte 0x50 ! FDE Encoding (aligned absolute) +#endif + .byte 0xc ! DW_CFA_def_cfa + .byte 0xe ! uleb128 0xe + .byte 0xff,0xf ! uleb128 0x7ff + .align 8 +.LLECIE1: +.LLSFDE1: + .uaword .LLEFDE1-.LLASFDE1 ! FDE Length +.LLASFDE1: + .uaword .LLASFDE1-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB1) + .uaword .LLFE1-.LLFB1 ! FDE address range +#else + .align 8 + .xword .LLFB1 + .uaxword .LLFE1-.LLFB1 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI0-.LLFB1 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align 8 +.LLEFDE1: +.LLSFDE2: + .uaword .LLEFDE2-.LLASFDE2 ! FDE Length +.LLASFDE2: + .uaword .LLASFDE2-.LLframe1 ! FDE CIE offset +#ifdef HAVE_AS_SPARC_UA_PCREL + .uaword %r_disp32(.LLFB2) + .uaword .LLFE2-.LLFB2 ! FDE address range +#else + .align 8 + .xword .LLFB2 + .uaxword .LLFE2-.LLFB2 ! FDE address range +#endif + .byte 0x0 ! uleb128 0x0; Augmentation size + .byte 0x4 ! DW_CFA_advance_loc4 + .uaword .LLCFI1-.LLFB2 + .byte 0xd ! DW_CFA_def_cfa_register + .byte 0x1e ! uleb128 0x1e + .byte 0x2d ! DW_CFA_GNU_window_save + .byte 0x9 ! DW_CFA_register + .byte 0xf ! uleb128 0xf + .byte 0x1f ! uleb128 0x1f + .align 8 +.LLEFDE2: +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/darwin.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/darwin.S new file mode 100644 index 000000000..d91bdc084 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/darwin.S @@ -0,0 +1,243 @@ +#ifdef __i386__ +/* ----------------------------------------------------------------------- + darwin.S - Copyright (c) 1996, 1998, 2001, 2002, 2003 Red Hat, Inc. + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* + * This file is based on sysv.S and then hacked up by Ronald who hasn't done + * assembly programming in 8 years. + */ + +#ifndef __x86_64__ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +#ifdef PyObjC_STRICT_DEBUGGING + /* XXX: Debugging of stack alignment, to be removed */ +#define ASSERT_STACK_ALIGNED movdqa -16(%esp), %xmm0 +#else +#define ASSERT_STACK_ALIGNED +#endif + +.text + +.globl _ffi_prep_args + +.align 4 +.globl _ffi_call_SYSV + +_ffi_call_SYSV: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp + subl $8,%esp + ASSERT_STACK_ALIGNED +.LCFI1: + /* Make room for all of the new args. */ + movl 16(%ebp),%ecx + subl %ecx,%esp + + ASSERT_STACK_ALIGNED + + movl %esp,%eax + + /* Place all of the ffi_prep_args in position */ + subl $8,%esp + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + ASSERT_STACK_ALIGNED + + /* Return stack to previous state and call the function */ + addl $16,%esp + + ASSERT_STACK_ALIGNED + + call *28(%ebp) + + /* XXX: return returns return with 'ret $4', that upsets the stack! */ + movl 16(%ebp),%ecx + addl %ecx,%esp + + + /* Load %ecx with the return type code */ + movl 20(%ebp),%ecx + + + /* If the return value pointer is NULL, assume no return value. */ + cmpl $0,24(%ebp) + jne retint + + /* Even if there is no space for the return value, we are + obliged to handle floating-point values. */ + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +retint: + cmpl $FFI_TYPE_INT,%ecx + jne retfloat + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp epilogue + +retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne retdouble + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne retlongdouble + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne retint64 + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne retstruct1b + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + jmp epilogue + +retstruct1b: + cmpl $FFI_TYPE_SINT8,%ecx + jne retstruct2b + movl 24(%ebp),%ecx + movb %al,0(%ecx) + jmp epilogue + +retstruct2b: + cmpl $FFI_TYPE_SINT16,%ecx + jne retstruct + movl 24(%ebp),%ecx + movw %ax,0(%ecx) + jmp epilogue + +retstruct: + cmpl $FFI_TYPE_STRUCT,%ecx + jne noretval + /* Nothing to do! */ + + subl $4,%esp + + ASSERT_STACK_ALIGNED + + addl $8,%esp + movl %ebp, %esp + popl %ebp + ret + +noretval: +epilogue: + ASSERT_STACK_ALIGNED + addl $8, %esp + + + movl %ebp,%esp + popl %ebp + ret +.LFE1: +.ffi_call_SYSV_end: +#if 0 + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV +#endif + +#if 0 + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .long 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef __PIC__ + .ascii "zR\0" /* CIE Augmentation */ +#else + .ascii "\0" /* CIE Augmentation */ +#endif + .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ + .byte 0x8 /* CIE RA Column */ +#ifdef __PIC__ + .byte 0x1 /* .uleb128 0x1; Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .byte 0x1 /* .uleb128 0x1 */ + .align 4 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .long .LASFDE1-.Lframe1 /* FDE CIE offset */ +#ifdef __PIC__ + .long .LFB1-. /* FDE initial location */ +#else + .long .LFB1 /* FDE initial location */ +#endif + .long .LFE1-.LFB1 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI0-.LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI1-.LCFI0 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ + .align 4 +.LEFDE1: +#endif + +#endif /* ifndef __x86_64__ */ + +#endif /* defined __i386__ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi.c new file mode 100644 index 000000000..7f792b7a9 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi.c @@ -0,0 +1,469 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2002 Bo Thorsen + Copyright (c) 2002 Roger Sayle + + x86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifndef __x86_64__ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if (ecif->cif->flags == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(int) - 1) & (unsigned) argp) + argp = (char *) ALIGN(argp, sizeof(int)); + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: +#if !defined(X86_WIN32) && !defined(__OpenBSD__) && !defined(__FreeBSD__) + case FFI_TYPE_STRUCT: +#endif + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + +#if defined(X86_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__) + case FFI_TYPE_STRUCT: + if (cif->rtype->size == 1) + { + cif->flags = FFI_TYPE_SINT8; /* same as char size */ + } + else if (cif->rtype->size == 2) + { + cif->flags = FFI_TYPE_SINT16; /* same as short size */ + } + else if (cif->rtype->size == 4) + { + cif->flags = FFI_TYPE_INT; /* same as int type */ + } + else if (cif->rtype->size == 8) + { + cif->flags = FFI_TYPE_SINT64; /* same as int64 type */ + } + else + { + cif->flags = FFI_TYPE_STRUCT; + } + break; +#endif + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +#ifdef X86_WIN32 +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ +#endif /* X86_WIN32 */ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->flags == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#ifdef X86_WIN32 + case FFI_STDCALL: + /*@-usedef@*/ + ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif /* X86_WIN32 */ + default: + FFI_ASSERT(0); + break; + } +} + + +/** private members **/ + +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif); +void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *) + __attribute__ ((regparm(1))); +unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *) + __attribute__ ((regparm(1))); +void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *) + __attribute__ ((regparm(1))); + +/* This function is jumped to by the trampoline */ + +unsigned int FFI_HIDDEN +ffi_closure_SYSV_inner (closure, respp, args) + ffi_closure *closure; + void **respp; + void *args; +{ + // our various things... + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif); + + (closure->fun) (cif, *respp, arg_area, closure->user_data); + + return cif->flags; +} + +/*@-exportheader@*/ +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( cif->flags == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(int) - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, sizeof(int)); + } + + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } + + return; +} + +/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ + +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ +({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \ + *(unsigned char*) &__tramp[0] = 0xb8; \ + *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[5] = 0xe9; \ + *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ + }) + + +/* the cif must already be prep'ed */ + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ + &ffi_closure_SYSV, \ + (void*)closure); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/* ------- Native raw API support -------------------------------- */ + +#if !FFI_NO_RAW_API + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data) +{ + int i; + + FFI_ASSERT (cif->abi == FFI_SYSV); + + // we currently don't support certain kinds of arguments for raw + // closures. This should be implemented by a separate assembly language + // routine, since it would require argument processing, something we + // don't do now for performance. + + for (i = cif->nargs-1; i >= 0; i--) + { + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); + } + + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, + (void*)closure); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +static void +ffi_prep_args_raw(char *stack, extended_cif *ecif) +{ + memcpy (stack, ecif->avalue, ecif->cif->bytes); +} + +/* we borrow this routine from libffi (it must be changed, though, to + * actually call the function passed in the first argument. as of + * libffi-1.20, this is not the case.) + */ + +extern void +ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); + +#ifdef X86_WIN32 +extern void +ffi_call_STDCALL(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +#endif /* X86_WIN32 */ + +void +ffi_raw_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *fake_avalue) +{ + extended_cif ecif; + void **avalue = (void **)fake_avalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#ifdef X86_WIN32 + case FFI_STDCALL: + /*@-usedef@*/ + ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif /* X86_WIN32 */ + default: + FFI_ASSERT(0); + break; + } +} + +#endif + +#endif /* __x86_64__ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi64.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi64.c new file mode 100644 index 000000000..c6cf330c2 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi64.c @@ -0,0 +1,569 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 2002 Bo Thorsen <bo@suse.de> + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> +#include <stdarg.h> + +#ifdef __x86_64__ + +#define MAX_GPR_REGS 6 +#define MAX_SSE_REGS 8 + +struct register_args +{ + /* Registers for argument passing. */ + UINT64 gpr[MAX_GPR_REGS]; + __int128_t sse[MAX_SSE_REGS]; +}; + +extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)(), unsigned ssecount); + +/* All reference to register classes here is identical to the code in + gcc/config/i386/i386.c. Do *not* change one without the other. */ + +/* Register class used for passing given 64bit part of the argument. + These represent classes as documented by the PS ABI, with the exception + of SSESF, SSEDF classes, that are basically SSE class, just gcc will + use SF or DFmode move instead of DImode to avoid reformating penalties. + + Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves + whenever possible (upper half does contain padding). */ +enum x86_64_reg_class + { + X86_64_NO_CLASS, + X86_64_INTEGER_CLASS, + X86_64_INTEGERSI_CLASS, + X86_64_SSE_CLASS, + X86_64_SSESF_CLASS, + X86_64_SSEDF_CLASS, + X86_64_SSEUP_CLASS, + X86_64_X87_CLASS, + X86_64_X87UP_CLASS, + X86_64_COMPLEX_X87_CLASS, + X86_64_MEMORY_CLASS + }; + +#define MAX_CLASSES 4 + +#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS) + +/* x86-64 register passing implementation. See x86-64 ABI for details. Goal + of this code is to classify each 8bytes of incoming argument by the register + class and assign registers accordingly. */ + +/* Return the union class of CLASS1 and CLASS2. + See the x86-64 PS ABI for details. */ + +static enum x86_64_reg_class +merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2) +{ + /* Rule #1: If both classes are equal, this is the resulting class. */ + if (class1 == class2) + return class1; + + /* Rule #2: If one of the classes is NO_CLASS, the resulting class is + the other class. */ + if (class1 == X86_64_NO_CLASS) + return class2; + if (class2 == X86_64_NO_CLASS) + return class1; + + /* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */ + if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */ + if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS) + || (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS)) + return X86_64_INTEGERSI_CLASS; + if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS + || class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS) + return X86_64_INTEGER_CLASS; + + /* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class, + MEMORY is used. */ + if (class1 == X86_64_X87_CLASS + || class1 == X86_64_X87UP_CLASS + || class1 == X86_64_COMPLEX_X87_CLASS + || class2 == X86_64_X87_CLASS + || class2 == X86_64_X87UP_CLASS + || class2 == X86_64_COMPLEX_X87_CLASS) + return X86_64_MEMORY_CLASS; + + /* Rule #6: Otherwise class SSE is used. */ + return X86_64_SSE_CLASS; +} + +/* Classify the argument of type TYPE and mode MODE. + CLASSES will be filled by the register class used to pass each word + of the operand. The number of words is returned. In case the parameter + should be passed in memory, 0 is returned. As a special case for zero + sized containers, classes[0] will be NO_CLASS and 1 is returned. + + See the x86-64 PS ABI for details. +*/ +static int +classify_argument (ffi_type *type, enum x86_64_reg_class classes[], + size_t byte_offset) +{ + switch (type->type) + { + case FFI_TYPE_UINT8: + case FFI_TYPE_SINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_SINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT32: + case FFI_TYPE_UINT64: + case FFI_TYPE_SINT64: + case FFI_TYPE_POINTER: + if (byte_offset + type->size <= 4) + classes[0] = X86_64_INTEGERSI_CLASS; + else + classes[0] = X86_64_INTEGER_CLASS; + return 1; + case FFI_TYPE_FLOAT: + if (byte_offset == 0) + classes[0] = X86_64_SSESF_CLASS; + else + classes[0] = X86_64_SSE_CLASS; + return 1; + case FFI_TYPE_DOUBLE: + classes[0] = X86_64_SSEDF_CLASS; + return 1; + case FFI_TYPE_LONGDOUBLE: + classes[0] = X86_64_X87_CLASS; + classes[1] = X86_64_X87UP_CLASS; + return 2; + case FFI_TYPE_STRUCT: + { + const int UNITS_PER_WORD = 8; + int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + ffi_type **ptr; + int i; + enum x86_64_reg_class subclasses[MAX_CLASSES]; + + /* If the struct is larger than 16 bytes, pass it on the stack. */ + if (type->size > 16) + return 0; + + for (i = 0; i < words; i++) + classes[i] = X86_64_NO_CLASS; + + /* Merge the fields of structure. */ + for (ptr = type->elements; *ptr != NULL; ptr++) + { + int num; + + byte_offset = ALIGN (byte_offset, (*ptr)->alignment); + + num = classify_argument (*ptr, subclasses, byte_offset % 8); + if (num == 0) + return 0; + for (i = 0; i < num; i++) + { + int pos = byte_offset / 8; + classes[i + pos] = + merge_classes (subclasses[i], classes[i + pos]); + } + + byte_offset += (*ptr)->size; + } + + /* Final merger cleanup. */ + for (i = 0; i < words; i++) + { + /* If one class is MEMORY, everything should be passed in + memory. */ + if (classes[i] == X86_64_MEMORY_CLASS) + return 0; + + /* The X86_64_SSEUP_CLASS should be always preceded by + X86_64_SSE_CLASS. */ + if (classes[i] == X86_64_SSEUP_CLASS + && (i == 0 || classes[i - 1] != X86_64_SSE_CLASS)) + classes[i] = X86_64_SSE_CLASS; + + /* X86_64_X87UP_CLASS should be preceded by X86_64_X87_CLASS. */ + if (classes[i] == X86_64_X87UP_CLASS + && (i == 0 || classes[i - 1] != X86_64_X87_CLASS)) + classes[i] = X86_64_SSE_CLASS; + } + return words; + } + + default: + FFI_ASSERT(0); + } + return 0; /* Never reached. */ +} + +/* Examine the argument and return set number of register required in each + class. Return zero iff parameter should be passed in memory, otherwise + the number of registers. */ + +static int +examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES], + _Bool in_return, int *pngpr, int *pnsse) +{ + int i, n, ngpr, nsse; + + n = classify_argument (type, classes, 0); + if (n == 0) + return 0; + + ngpr = nsse = 0; + for (i = 0; i < n; ++i) + switch (classes[i]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + ngpr++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSESF_CLASS: + case X86_64_SSEDF_CLASS: + nsse++; + break; + case X86_64_NO_CLASS: + case X86_64_SSEUP_CLASS: + break; + case X86_64_X87_CLASS: + case X86_64_X87UP_CLASS: + case X86_64_COMPLEX_X87_CLASS: + return in_return != 0; + default: + abort (); + } + + *pngpr = ngpr; + *pnsse = nsse; + + return n; +} + +/* Perform machine dependent cif processing. */ + +ffi_status +ffi_prep_cif_machdep (ffi_cif *cif) +{ + int gprcount, ssecount, i, avn, n, ngpr, nsse, flags; + enum x86_64_reg_class classes[MAX_CLASSES]; + size_t bytes; + + gprcount = ssecount = 0; + + flags = cif->rtype->type; + if (flags != FFI_TYPE_VOID) + { + n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + if (n == 0) + { + /* The return value is passed in memory. A pointer to that + memory is the first argument. Allocate a register for it. */ + gprcount++; + /* We don't have to do anything in asm for the return. */ + flags = FFI_TYPE_VOID; + } + else if (flags == FFI_TYPE_STRUCT) + { + /* Mark which registers the result appears in. */ + _Bool sse0 = SSE_CLASS_P (classes[0]); + _Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]); + if (sse0 && !sse1) + flags |= 1 << 8; + else if (!sse0 && sse1) + flags |= 1 << 9; + else if (sse0 && sse1) + flags |= 1 << 10; + /* Mark the true size of the structure. */ + flags |= cif->rtype->size << 12; + } + } + + /* Go over all arguments and determine the way they should be passed. + If it's in a register and there is space for it, let that be so. If + not, add it's size to the stack byte count. */ + for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++) + { + if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = cif->arg_types[i]->alignment; + + if (align < 8) + align = 8; + + bytes = ALIGN(bytes, align); + bytes += cif->arg_types[i]->size; + } + else + { + gprcount += ngpr; + ssecount += nsse; + } + } + if (ssecount) + flags |= 1 << 11; + cif->flags = flags; + cif->bytes = bytes; + + return FFI_OK; +} + +void +ffi_call (ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) +{ + enum x86_64_reg_class classes[MAX_CLASSES]; + char *stack, *argp; + ffi_type **arg_types; + int gprcount, ssecount, ngpr, nsse, i, avn; + _Bool ret_in_memory; + struct register_args *reg_args; + + /* Can't call 32-bit mode from 64-bit mode. */ + FFI_ASSERT (cif->abi == FFI_UNIX64); + + /* If the return value is a struct and we don't have a return value + address then we need to make one. Note the setting of flags to + VOID above in ffi_prep_cif_machdep. */ + ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT + && (cif->flags & 0xff) == FFI_TYPE_VOID); + if (rvalue == NULL && ret_in_memory) + rvalue = alloca (cif->rtype->size); + + /* Allocate the space for the arguments, plus 4 words of temp space. */ + stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8); + reg_args = (struct register_args *) stack; + argp = stack + sizeof (struct register_args); + + gprcount = ssecount = 0; + + /* If the return value is passed in memory, add the pointer as the + first integer argument. */ + if (ret_in_memory) + reg_args->gpr[gprcount++] = (long) rvalue; + + avn = cif->nargs; + arg_types = cif->arg_types; + + for (i = 0; i < avn; ++i) + { + size_t size = arg_types[i]->size; + int n; + + n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); + if (n == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = arg_types[i]->alignment; + + /* Stack arguments are *always* at least 8 byte aligned. */ + if (align < 8) + align = 8; + + /* Pass this argument in memory. */ + argp = (void *) ALIGN (argp, align); + memcpy (argp, avalue[i], size); + argp += size; + } + else + { + /* The argument is passed entirely in registers. */ + char *a = (char *) avalue[i]; + int j; + + for (j = 0; j < n; j++, a += 8, size -= 8) + { + switch (classes[j]) + { + case X86_64_INTEGER_CLASS: + case X86_64_INTEGERSI_CLASS: + reg_args->gpr[gprcount] = 0; + memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8); + gprcount++; + break; + case X86_64_SSE_CLASS: + case X86_64_SSEDF_CLASS: + reg_args->sse[ssecount++] = *(UINT64 *) a; + break; + case X86_64_SSESF_CLASS: + reg_args->sse[ssecount++] = *(UINT32 *) a; + break; + default: + abort(); + } + } + } + } + + ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args), + cif->flags, rvalue, fn, ssecount); +} + + +extern void ffi_closure_unix64(void); + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*, void*, void**, void*), + void *user_data) +{ + volatile unsigned short *tramp; + + tramp = (volatile unsigned short *) &closure->tramp[0]; + + tramp[0] = 0xbb49; /* mov <code>, %r11 */ + *(void * volatile *) &tramp[1] = ffi_closure_unix64; + tramp[5] = 0xba49; /* mov <data>, %r10 */ + *(void * volatile *) &tramp[6] = closure; + + /* Set the carry bit iff the function uses any sse registers. + This is clc or stc, together with the first byte of the jmp. */ + tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8; + + tramp[11] = 0xe3ff; /* jmp *%r11 */ + + closure->cif = cif; + closure->fun = fun; + closure->user_data = user_data; + + return FFI_OK; +} + +int +ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue, + struct register_args *reg_args, char *argp) +{ + ffi_cif *cif; + void **avalue; + ffi_type **arg_types; + long i, avn; + int gprcount, ssecount, ngpr, nsse; + int ret; + + cif = closure->cif; + avalue = alloca(cif->nargs * sizeof(void *)); + gprcount = ssecount = 0; + + ret = cif->rtype->type; + if (ret != FFI_TYPE_VOID) + { + enum x86_64_reg_class classes[MAX_CLASSES]; + int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse); + if (n == 0) + { + /* The return value goes in memory. Arrange for the closure + return value to go directly back to the original caller. */ + rvalue = (void *) reg_args->gpr[gprcount++]; + /* We don't have to do anything in asm for the return. */ + ret = FFI_TYPE_VOID; + } + else if (ret == FFI_TYPE_STRUCT && n == 2) + { + /* Mark which register the second word of the structure goes in. */ + _Bool sse0 = SSE_CLASS_P (classes[0]); + _Bool sse1 = SSE_CLASS_P (classes[1]); + if (!sse0 && sse1) + ret |= 1 << 8; + else if (sse0 && !sse1) + ret |= 1 << 9; + } + } + + avn = cif->nargs; + arg_types = cif->arg_types; + + for (i = 0; i < avn; ++i) + { + enum x86_64_reg_class classes[MAX_CLASSES]; + int n; + + n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse); + if (n == 0 + || gprcount + ngpr > MAX_GPR_REGS + || ssecount + nsse > MAX_SSE_REGS) + { + long align = arg_types[i]->alignment; + + /* Stack arguments are *always* at least 8 byte aligned. */ + if (align < 8) + align = 8; + + /* Pass this argument in memory. */ + argp = (void *) ALIGN (argp, align); + avalue[i] = argp; + argp += arg_types[i]->size; + } + /* If the argument is in a single register, or two consecutive + registers, then we can use that address directly. */ + else if (n == 1 + || (n == 2 + && SSE_CLASS_P (classes[0]) == SSE_CLASS_P (classes[1]))) + { + /* The argument is in a single register. */ + if (SSE_CLASS_P (classes[0])) + { + avalue[i] = &reg_args->sse[ssecount]; + ssecount += n; + } + else + { + avalue[i] = &reg_args->gpr[gprcount]; + gprcount += n; + } + } + /* Otherwise, allocate space to make them consecutive. */ + else + { + char *a = alloca (16); + int j; + + avalue[i] = a; + for (j = 0; j < n; j++, a += 8) + { + if (SSE_CLASS_P (classes[j])) + memcpy (a, &reg_args->sse[ssecount++], 8); + else + memcpy (a, &reg_args->gpr[gprcount++], 8); + } + } + } + + /* Invoke the closure. */ + closure->fun (cif, rvalue, avalue, closure->user_data); + + /* Tell assembly how to perform return type promotions. */ + return ret; +} + +#endif /* __x86_64__ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi_darwin.c b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi_darwin.c new file mode 100644 index 000000000..c9742d876 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffi_darwin.c @@ -0,0 +1,594 @@ +# ifdef __i386__ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2002 Bo Thorsen + Copyright (c) 2002 Roger Sayle + + x86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifndef __x86_64__ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif); + +static inline int retval_on_stack(ffi_type* tp) +{ + if (tp->type == FFI_TYPE_STRUCT) { + int sz = tp->size; + if (sz > 8) { + return 1; + } + switch (sz) { + case 1: case 2: case 4: case 8: return 0; + default: return 1; + } + } + return 0; +} + + +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if (retval_on_stack(ecif->cif->rtype)) { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(int) - 1) & (unsigned) argp) + argp = (char *) ALIGN(argp, sizeof(int)); + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: +#if !defined(X86_WIN32) && !defined(X86_DARWIN) + case FFI_TYPE_STRUCT: +#endif + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + +#if defined(X86_WIN32) || defined(X86_DARWIN) + + case FFI_TYPE_STRUCT: + if (cif->rtype->size == 1) + { + cif->flags = FFI_TYPE_SINT8; /* same as char size */ + } + else if (cif->rtype->size == 2) + { + cif->flags = FFI_TYPE_SINT16; /* same as short size */ + } + else if (cif->rtype->size == 4) + { + cif->flags = FFI_TYPE_INT; /* same as int type */ + } + else if (cif->rtype->size == 8) + { + cif->flags = FFI_TYPE_SINT64; /* same as int64 type */ + } + else + { + cif->flags = FFI_TYPE_STRUCT; + } + break; +#endif + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + /* Darwin: The stack needs to be aligned to a multiple of 16 bytes */ +#if 1 + cif->bytes = (cif->bytes + 15) & ~0xF; +#endif + + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)(void)); +/*@=declundef@*/ +/*@=exportheader@*/ + +#ifdef X86_WIN32 +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_STDCALL(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)(void)); +/*@=declundef@*/ +/*@=exportheader@*/ +#endif /* X86_WIN32 */ + +void ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && retval_on_stack(cif->rtype)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + /* To avoid changing the assembly code make sure the size of the argument + * block is a multiple of 16. Then add 8 to compensate for local variables + * in ffi_call_SYSV. + */ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#ifdef X86_WIN32 + case FFI_STDCALL: + /*@-usedef@*/ + ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif /* X86_WIN32 */ + default: + FFI_ASSERT(0); + break; + } +} + + +/** private members **/ + +static void ffi_closure_SYSV (ffi_closure *) + __attribute__ ((regparm(1))); +#if !FFI_NO_RAW_API +static void ffi_closure_raw_SYSV (ffi_raw_closure *) + __attribute__ ((regparm(1))); +#endif + +/*@-exportheader@*/ +static inline void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if (retval_on_stack(cif->rtype)) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(int) - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, sizeof(int)); + } + + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } + + return; +} + +/* This function is jumped to by the trampoline */ + +static void +ffi_closure_SYSV (closure) + ffi_closure *closure; +{ + // this is our return value storage + long double res; + + // our various things... + ffi_cif *cif; + void **arg_area; + void *resp = (void*)&res; + void *args = __builtin_dwarf_cfa (); + + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + /* now, do a generic return based on the value of rtype */ + if (cif->flags == FFI_TYPE_INT) + { + asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); + } + else if (cif->flags == FFI_TYPE_FLOAT) + { + asm ("flds (%0)" : : "r" (resp) : "st" ); + } + else if (cif->flags == FFI_TYPE_DOUBLE) + { + asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (cif->flags == FFI_TYPE_LONGDOUBLE) + { + asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (cif->flags == FFI_TYPE_SINT64) + { + asm ("movl 0(%0),%%eax;" + "movl 4(%0),%%edx" + : : "r"(resp) + : "eax", "edx"); + } +#if defined(X86_WIN32) || defined(X86_DARWIN) + else if (cif->flags == FFI_TYPE_SINT8) /* 1-byte struct */ + { + asm ("movsbl (%0),%%eax" : : "r" (resp) : "eax"); + } + else if (cif->flags == FFI_TYPE_SINT16) /* 2-bytes struct */ + { + asm ("movswl (%0),%%eax" : : "r" (resp) : "eax"); + } +#endif + + else if (cif->flags == FFI_TYPE_STRUCT) + { + asm ("lea -8(%ebp),%esp;" + "pop %esi;" + "pop %edi;" + "pop %ebp;" + "ret $4"); + } +} + + +/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ + +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \ +({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \ + *(unsigned char*) &__tramp[0] = 0xb8; \ + *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ + *(unsigned char *) &__tramp[5] = 0xe9; \ + *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ + }) + + +/* the cif must already be prep'ed */ + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], \ + &ffi_closure_SYSV, \ + (void*)closure); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +/* ------- Native raw API support -------------------------------- */ + +#if !FFI_NO_RAW_API + +static void +ffi_closure_raw_SYSV (closure) + ffi_raw_closure *closure; +{ + // this is our return value storage + long double res; + + // our various things... + ffi_raw *raw_args; + ffi_cif *cif; + unsigned short rtype; + void *resp = (void*)&res; + + /* get the cif */ + cif = closure->cif; + + /* the SYSV/X86 abi matches the RAW API exactly, well.. almost */ + raw_args = (ffi_raw*) __builtin_dwarf_cfa (); + + (closure->fun) (cif, resp, raw_args, closure->user_data); + + rtype = cif->flags; + + /* now, do a generic return based on the value of rtype */ + if (rtype == FFI_TYPE_INT) + { + asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); + } + else if (rtype == FFI_TYPE_FLOAT) + { + asm ("flds (%0)" : : "r" (resp) : "st" ); + } + else if (rtype == FFI_TYPE_DOUBLE) + { + asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_LONGDOUBLE) + { + asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_SINT64) + { + asm ("movl 0(%0),%%eax; movl 4(%0),%%edx" + : : "r"(resp) + : "eax", "edx"); + } +} + + + + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data) +{ + int i; + + FFI_ASSERT (cif->abi == FFI_SYSV); + + // we currently don't support certain kinds of arguments for raw + // closures. This should be implemented by a separate assembly language + // routine, since it would require argument processing, something we + // don't do now for performance. + + for (i = cif->nargs-1; i >= 0; i--) + { + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT); + FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE); + } + + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV, + (void*)closure); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + +static void +ffi_prep_args_raw(char *stack, extended_cif *ecif) +{ + memcpy (stack, ecif->avalue, ecif->cif->bytes); +} + +/* we borrow this routine from libffi (it must be changed, though, to + * actually call the function passed in the first argument. as of + * libffi-1.20, this is not the case.) + */ + +extern void +ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); + +#ifdef X86_WIN32 +extern void +ffi_call_STDCALL(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +#endif /* X86_WIN32 */ + +void +ffi_raw_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *fake_avalue) +{ + extended_cif ecif; + void **avalue = (void **)fake_avalue; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && retval_on_stack(cif->rtype)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#ifdef X86_WIN32 + case FFI_STDCALL: + /*@-usedef@*/ + ffi_call_STDCALL(ffi_prep_args_raw, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; +#endif /* X86_WIN32 */ + default: + FFI_ASSERT(0); + break; + } +} + +#endif + +#endif /* __x86_64__ */ + +#endif /* __i386__ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffitarget.h new file mode 100644 index 000000000..8b20d3c7a --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/ffitarget.h @@ -0,0 +1,81 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for x86 and x86-64. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#if defined (X86_64) && defined (__i386__) +#undef X86_64 +#define X86 +#endif + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + + /* ---- Intel x86 Win32 ---------- */ +#ifdef X86_WIN32 + FFI_SYSV, + FFI_STDCALL, + /* TODO: Add fastcall support for the sake of completeness */ + FFI_DEFAULT_ABI = FFI_SYSV, +#endif + + /* ---- Intel x86 and AMD x86-64 - */ +#if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__)) + FFI_SYSV, + FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ +#ifdef __i386__ + FFI_DEFAULT_ABI = FFI_SYSV, +#else + FFI_DEFAULT_ABI = FFI_UNIX64, +#endif +#endif + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 + +#ifdef X86_64 +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 +#else +#define FFI_TRAMPOLINE_SIZE 10 +#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ +#endif + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/sysv.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/sysv.S new file mode 100644 index 000000000..9542fba1a --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/sysv.S @@ -0,0 +1,382 @@ +/* ----------------------------------------------------------------------- + sysv.S - Copyright (c) 1996, 1998, 2001, 2002, 2003, 2005 Red Hat, Inc. + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifndef __x86_64__ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +.text + +.globl ffi_prep_args + + .align 4 +.globl ffi_call_SYSV + .type ffi_call_SYSV,@function + +ffi_call_SYSV: +.LFB1: + pushl %ebp +.LCFI0: + movl %esp,%ebp +.LCFI1: + /* Make room for all of the new args. */ + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + /* Place all of the ffi_prep_args in position */ + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + /* Return stack to previous state and call the function */ + addl $8,%esp + + call *28(%ebp) + + /* Remove the space we pushed for the args */ + movl 16(%ebp),%ecx + addl %ecx,%esp + + /* Load %ecx with the return type code */ + movl 20(%ebp),%ecx + + /* If the return value pointer is NULL, assume no return value. */ + cmpl $0,24(%ebp) + jne retint + + /* Even if there is no space for the return value, we are + obliged to handle floating-point values. */ + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +retint: + cmpl $FFI_TYPE_INT,%ecx + jne retfloat + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp epilogue + +retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne retdouble + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne retlongdouble + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne retint64 + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne retstruct + /* Load %ecx with the pointer to storage for the return value */ + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +retstruct: + /* Nothing to do! */ + +noretval: +epilogue: + movl %ebp,%esp + popl %ebp + ret +.LFE1: +.ffi_call_SYSV_end: + .size ffi_call_SYSV,.ffi_call_SYSV_end-ffi_call_SYSV + + .align 4 +FFI_HIDDEN (ffi_closure_SYSV) +.globl ffi_closure_SYSV + .type ffi_closure_SYSV, @function + +ffi_closure_SYSV: +.LFB2: + pushl %ebp +.LCFI2: + movl %esp, %ebp +.LCFI3: + subl $40, %esp + leal -24(%ebp), %edx + movl %edx, -12(%ebp) /* resp */ + leal 8(%ebp), %edx + movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ + leal -12(%ebp), %edx + movl %edx, (%esp) /* &resp */ +#if defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE || !defined __PIC__ + call ffi_closure_SYSV_inner +#else + movl %ebx, 8(%esp) +.LCFI7: + call 1f +1: popl %ebx + addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx + call ffi_closure_SYSV_inner@PLT + movl 8(%esp), %ebx +#endif + movl -12(%ebp), %ecx + cmpl $FFI_TYPE_INT, %eax + je .Lcls_retint + cmpl $FFI_TYPE_FLOAT, %eax + je .Lcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lcls_retllong +.Lcls_epilogue: + movl %ebp, %esp + popl %ebp + ret +.Lcls_retint: + movl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retfloat: + flds (%ecx) + jmp .Lcls_epilogue +.Lcls_retdouble: + fldl (%ecx) + jmp .Lcls_epilogue +.Lcls_retldouble: + fldt (%ecx) + jmp .Lcls_epilogue +.Lcls_retllong: + movl (%ecx), %eax + movl 4(%ecx), %edx + jmp .Lcls_epilogue +.LFE2: + .size ffi_closure_SYSV, .-ffi_closure_SYSV + +#if !FFI_NO_RAW_API + +#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) +#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) +#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) +#define CIF_FLAGS_OFFSET 20 + + .align 4 +FFI_HIDDEN (ffi_closure_raw_SYSV) +.globl ffi_closure_raw_SYSV + .type ffi_closure_raw_SYSV, @function + +ffi_closure_raw_SYSV: +.LFB3: + pushl %ebp +.LCFI4: + movl %esp, %ebp +.LCFI5: + pushl %esi +.LCFI6: + subl $36, %esp + movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ + movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ + movl %edx, 12(%esp) /* user_data */ + leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ + movl %edx, 8(%esp) /* raw_args */ + leal -24(%ebp), %edx + movl %edx, 4(%esp) /* &res */ + movl %esi, (%esp) /* cif */ + call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ + movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ + cmpl $FFI_TYPE_INT, %eax + je .Lrcls_retint + cmpl $FFI_TYPE_FLOAT, %eax + je .Lrcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lrcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lrcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lrcls_retllong +.Lrcls_epilogue: + addl $36, %esp + popl %esi + popl %ebp + ret +.Lrcls_retint: + movl -24(%ebp), %eax + jmp .Lrcls_epilogue +.Lrcls_retfloat: + flds -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retdouble: + fldl -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retldouble: + fldt -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retllong: + movl -24(%ebp), %eax + movl -20(%ebp), %edx + jmp .Lrcls_epilogue +.LFE3: + .size ffi_closure_raw_SYSV, .-ffi_closure_raw_SYSV +#endif + + .section .eh_frame,EH_FRAME_FLAGS,@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 /* Length of Common Information Entry */ +.LSCIE1: + .long 0x0 /* CIE Identifier Tag */ + .byte 0x1 /* CIE Version */ +#ifdef __PIC__ + .ascii "zR\0" /* CIE Augmentation */ +#else + .ascii "\0" /* CIE Augmentation */ +#endif + .byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */ + .byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */ + .byte 0x8 /* CIE RA Column */ +#ifdef __PIC__ + .byte 0x1 /* .uleb128 0x1; Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ +#endif + .byte 0xc /* DW_CFA_def_cfa */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x4 /* .uleb128 0x4 */ + .byte 0x88 /* DW_CFA_offset, column 0x8 */ + .byte 0x1 /* .uleb128 0x1 */ + .align 4 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .long .LASFDE1-.Lframe1 /* FDE CIE offset */ +#ifdef __PIC__ + .long .LFB1-. /* FDE initial location */ +#else + .long .LFB1 /* FDE initial location */ +#endif + .long .LFE1-.LFB1 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI0-.LFB1 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI1-.LCFI0 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ + .align 4 +.LEFDE1: +.LSFDE2: + .long .LEFDE2-.LASFDE2 /* FDE Length */ +.LASFDE2: + .long .LASFDE2-.Lframe1 /* FDE CIE offset */ +#ifdef __PIC__ + .long .LFB2-. /* FDE initial location */ +#else + .long .LFB2 +#endif + .long .LFE2-.LFB2 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI2-.LFB2 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI3-.LCFI2 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ +#if !defined HAVE_HIDDEN_VISIBILITY_ATTRIBUTE && defined __PIC__ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI7-.LCFI3 + .byte 0x83 /* DW_CFA_offset, column 0x3 */ + .byte 0xa /* .uleb128 0xa */ +#endif + .align 4 +.LEFDE2: + +#if !FFI_NO_RAW_API + +.LSFDE3: + .long .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .long .LASFDE3-.Lframe1 /* FDE CIE offset */ +#ifdef __PIC__ + .long .LFB3-. /* FDE initial location */ +#else + .long .LFB3 +#endif + .long .LFE3-.LFB3 /* FDE address range */ +#ifdef __PIC__ + .byte 0x0 /* .uleb128 0x0; Augmentation size */ +#endif + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI4-.LFB3 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .byte 0x8 /* .uleb128 0x8 */ + .byte 0x85 /* DW_CFA_offset, column 0x5 */ + .byte 0x2 /* .uleb128 0x2 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI5-.LCFI4 + .byte 0xd /* DW_CFA_def_cfa_register */ + .byte 0x5 /* .uleb128 0x5 */ + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LCFI6-.LCFI5 + .byte 0x86 /* DW_CFA_offset, column 0x6 */ + .byte 0x3 /* .uleb128 0x3 */ + .align 4 +.LEFDE3: + +#endif + +#endif /* ifndef __x86_64__ */ + +#ifdef __ELF__ +.section .note.GNU-stack,"",%progbits +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/unix64.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/unix64.S new file mode 100644 index 000000000..831e1d713 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/unix64.S @@ -0,0 +1,412 @@ +/* ----------------------------------------------------------------------- + unix64.S - Copyright (c) 2002 Bo Thorsen <bo@suse.de> + + x86-64 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#ifdef __x86_64__ +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +.text + +/* ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags, + void *raddr, void (*fnaddr)()); + + Bit o trickiness here -- ARGS+BYTES is the base of the stack frame + for this function. This has been allocated by ffi_call. We also + deallocate some of the stack that has been alloca'd. */ + + .align 2 + .globl ffi_call_unix64 + .type ffi_call_unix64,@function + +ffi_call_unix64: +.LUW0: + movq (%rsp), %r10 /* Load return address. */ + leaq (%rdi, %rsi), %rax /* Find local stack base. */ + movq %rdx, (%rax) /* Save flags. */ + movq %rcx, 8(%rax) /* Save raddr. */ + movq %rbp, 16(%rax) /* Save old frame pointer. */ + movq %r10, 24(%rax) /* Relocate return address. */ + movq %rax, %rbp /* Finalize local stack frame. */ +.LUW1: + movq %rdi, %r10 /* Save a copy of the register area. */ + movq %r8, %r11 /* Save a copy of the target fn. */ + movl %r9d, %eax /* Set number of SSE registers. */ + + /* Load up all argument registers. */ + movq (%r10), %rdi + movq 8(%r10), %rsi + movq 16(%r10), %rdx + movq 24(%r10), %rcx + movq 32(%r10), %r8 + movq 40(%r10), %r9 + testl %eax, %eax + jnz .Lload_sse +.Lret_from_load_sse: + + /* Deallocate the reg arg area. */ + leaq 176(%r10), %rsp + + /* Call the user function. */ + call *%r11 + + /* Deallocate stack arg area; local stack frame in redzone. */ + leaq 24(%rbp), %rsp + + movq 0(%rbp), %rcx /* Reload flags. */ + movq 8(%rbp), %rdi /* Reload raddr. */ + movq 16(%rbp), %rbp /* Reload old frame pointer. */ +.LUW2: + + /* The first byte of the flags contains the FFI_TYPE. */ + movzbl %cl, %r10d + leaq .Lstore_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + + .section .rodata +.Lstore_table: + .long .Lst_void-.Lstore_table /* FFI_TYPE_VOID */ + .long .Lst_sint32-.Lstore_table /* FFI_TYPE_INT */ + .long .Lst_float-.Lstore_table /* FFI_TYPE_FLOAT */ + .long .Lst_double-.Lstore_table /* FFI_TYPE_DOUBLE */ + .long .Lst_ldouble-.Lstore_table /* FFI_TYPE_LONGDOUBLE */ + .long .Lst_uint8-.Lstore_table /* FFI_TYPE_UINT8 */ + .long .Lst_sint8-.Lstore_table /* FFI_TYPE_SINT8 */ + .long .Lst_uint16-.Lstore_table /* FFI_TYPE_UINT16 */ + .long .Lst_sint16-.Lstore_table /* FFI_TYPE_SINT16 */ + .long .Lst_uint32-.Lstore_table /* FFI_TYPE_UINT32 */ + .long .Lst_sint32-.Lstore_table /* FFI_TYPE_SINT32 */ + .long .Lst_int64-.Lstore_table /* FFI_TYPE_UINT64 */ + .long .Lst_int64-.Lstore_table /* FFI_TYPE_SINT64 */ + .long .Lst_struct-.Lstore_table /* FFI_TYPE_STRUCT */ + .long .Lst_int64-.Lstore_table /* FFI_TYPE_POINTER */ + + .text + .align 2 +.Lst_void: + ret + .align 2 + +.Lst_uint8: + movzbq %al, %rax + movq %rax, (%rdi) + ret + .align 2 +.Lst_sint8: + movsbq %al, %rax + movq %rax, (%rdi) + ret + .align 2 +.Lst_uint16: + movzwq %ax, %rax + movq %rax, (%rdi) + .align 2 +.Lst_sint16: + movswq %ax, %rax + movq %rax, (%rdi) + ret + .align 2 +.Lst_uint32: + movl %eax, %eax + movq %rax, (%rdi) + .align 2 +.Lst_sint32: + cltq + movq %rax, (%rdi) + ret + .align 2 +.Lst_int64: + movq %rax, (%rdi) + ret + + .align 2 +.Lst_float: + movss %xmm0, (%rdi) + ret + .align 2 +.Lst_double: + movsd %xmm0, (%rdi) + ret +.Lst_ldouble: + fstpt (%rdi) + ret + + .align 2 +.Lst_struct: + leaq -20(%rsp), %rsi /* Scratch area in redzone. */ + + /* We have to locate the values now, and since we don't want to + write too much data into the user's return value, we spill the + value to a 16 byte scratch area first. Bits 8, 9, and 10 + control where the values are located. Only one of the three + bits will be set; see ffi_prep_cif_machdep for the pattern. */ + movd %xmm0, %r10 + movd %xmm1, %r11 + testl $0x100, %ecx + cmovnz %rax, %rdx + cmovnz %r10, %rax + testl $0x200, %ecx + cmovnz %r10, %rdx + testl $0x400, %ecx + cmovnz %r10, %rax + cmovnz %r11, %rdx + movq %rax, (%rsi) + movq %rdx, 8(%rsi) + + /* Bits 12-31 contain the true size of the structure. Copy from + the scratch area to the true destination. */ + shrl $12, %ecx + rep movsb + ret + + /* Many times we can avoid loading any SSE registers at all. + It's not worth an indirect jump to load the exact set of + SSE registers needed; zero or all is a good compromise. */ + .align 2 +.LUW3: +.Lload_sse: + movdqa 48(%r10), %xmm0 + movdqa 64(%r10), %xmm1 + movdqa 80(%r10), %xmm2 + movdqa 96(%r10), %xmm3 + movdqa 112(%r10), %xmm4 + movdqa 128(%r10), %xmm5 + movdqa 144(%r10), %xmm6 + movdqa 160(%r10), %xmm7 + jmp .Lret_from_load_sse + +.LUW4: + .size ffi_call_unix64,.-ffi_call_unix64 + + .align 2 + .globl ffi_closure_unix64 + .type ffi_closure_unix64,@function + +ffi_closure_unix64: +.LUW5: + /* The carry flag is set by the trampoline iff SSE registers + are used. Don't clobber it before the branch instruction. */ + leaq -200(%rsp), %rsp +.LUW6: + movq %rdi, (%rsp) + movq %rsi, 8(%rsp) + movq %rdx, 16(%rsp) + movq %rcx, 24(%rsp) + movq %r8, 32(%rsp) + movq %r9, 40(%rsp) + jc .Lsave_sse +.Lret_from_save_sse: + + movq %r10, %rdi + leaq 176(%rsp), %rsi + movq %rsp, %rdx + leaq 208(%rsp), %rcx + call ffi_closure_unix64_inner@PLT + + /* Deallocate stack frame early; return value is now in redzone. */ + addq $200, %rsp +.LUW7: + + /* The first byte of the return value contains the FFI_TYPE. */ + movzbl %al, %r10d + leaq .Lload_table(%rip), %r11 + movslq (%r11, %r10, 4), %r10 + addq %r11, %r10 + jmp *%r10 + + .section .rodata +.Lload_table: + .long .Lld_void-.Lload_table /* FFI_TYPE_VOID */ + .long .Lld_int32-.Lload_table /* FFI_TYPE_INT */ + .long .Lld_float-.Lload_table /* FFI_TYPE_FLOAT */ + .long .Lld_double-.Lload_table /* FFI_TYPE_DOUBLE */ + .long .Lld_ldouble-.Lload_table /* FFI_TYPE_LONGDOUBLE */ + .long .Lld_int8-.Lload_table /* FFI_TYPE_UINT8 */ + .long .Lld_int8-.Lload_table /* FFI_TYPE_SINT8 */ + .long .Lld_int16-.Lload_table /* FFI_TYPE_UINT16 */ + .long .Lld_int16-.Lload_table /* FFI_TYPE_SINT16 */ + .long .Lld_int32-.Lload_table /* FFI_TYPE_UINT32 */ + .long .Lld_int32-.Lload_table /* FFI_TYPE_SINT32 */ + .long .Lld_int64-.Lload_table /* FFI_TYPE_UINT64 */ + .long .Lld_int64-.Lload_table /* FFI_TYPE_SINT64 */ + .long .Lld_struct-.Lload_table /* FFI_TYPE_STRUCT */ + .long .Lld_int64-.Lload_table /* FFI_TYPE_POINTER */ + + .text + .align 2 +.Lld_void: + ret + + .align 2 +.Lld_int8: + movzbl -24(%rsp), %eax + ret + .align 2 +.Lld_int16: + movzwl -24(%rsp), %eax + ret + .align 2 +.Lld_int32: + movl -24(%rsp), %eax + ret + .align 2 +.Lld_int64: + movq -24(%rsp), %rax + ret + + .align 2 +.Lld_float: + movss -24(%rsp), %xmm0 + ret + .align 2 +.Lld_double: + movsd -24(%rsp), %xmm0 + ret + .align 2 +.Lld_ldouble: + fldt -24(%rsp) + ret + + .align 2 +.Lld_struct: + /* There are four possibilities here, %rax/%rdx, %xmm0/%rax, + %rax/%xmm0, %xmm0/%xmm1. We collapse two by always loading + both rdx and xmm1 with the second word. For the remaining, + bit 8 set means xmm0 gets the second word, and bit 9 means + that rax gets the second word. */ + movq -24(%rsp), %rcx + movq -16(%rsp), %rdx + movq -16(%rsp), %xmm1 + testl $0x100, %eax + cmovnz %rdx, %rcx + movd %rcx, %xmm0 + testl $0x200, %eax + movq -24(%rsp), %rax + cmovnz %rdx, %rax + ret + + /* See the comment above .Lload_sse; the same logic applies here. */ + .align 2 +.LUW8: +.Lsave_sse: + movdqa %xmm0, 48(%rsp) + movdqa %xmm1, 64(%rsp) + movdqa %xmm2, 80(%rsp) + movdqa %xmm3, 96(%rsp) + movdqa %xmm4, 112(%rsp) + movdqa %xmm5, 128(%rsp) + movdqa %xmm6, 144(%rsp) + movdqa %xmm7, 160(%rsp) + jmp .Lret_from_save_sse + +.LUW9: + .size ffi_closure_unix64,.-ffi_closure_unix64 + + .section .eh_frame,"a",@progbits +.Lframe1: + .long .LECIE1-.LSCIE1 /* CIE Length */ +.LSCIE1: + .long 0 /* CIE Identifier Tag */ + .byte 1 /* CIE Version */ + .ascii "zR\0" /* CIE Augmentation */ + .uleb128 1 /* CIE Code Alignment Factor */ + .sleb128 -8 /* CIE Data Alignment Factor */ + .byte 0x10 /* CIE RA Column */ + .uleb128 1 /* Augmentation size */ + .byte 0x1b /* FDE Encoding (pcrel sdata4) */ + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .uleb128 7 + .uleb128 8 + .byte 0x80+16 /* DW_CFA_offset, %rip offset 1*-8 */ + .uleb128 1 + .align 8 +.LECIE1: +.LSFDE1: + .long .LEFDE1-.LASFDE1 /* FDE Length */ +.LASFDE1: + .long .LASFDE1-.Lframe1 /* FDE CIE offset */ + .long .LUW0-. /* FDE initial location */ + .long .LUW4-.LUW0 /* FDE address range */ + .uleb128 0x0 /* Augmentation size */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW1-.LUW0 + + /* New stack frame based off rbp. This is a itty bit of unwind + trickery in that the CFA *has* changed. There is no easy way + to describe it correctly on entry to the function. Fortunately, + it doesn't matter too much since at all points we can correctly + unwind back to ffi_call. Note that the location to which we + moved the return address is (the new) CFA-8, so from the + perspective of the unwind info, it hasn't moved. */ + .byte 0xc /* DW_CFA_def_cfa, %rbp offset 32 */ + .uleb128 6 + .uleb128 32 + .byte 0x80+6 /* DW_CFA_offset, %rbp offset 2*-8 */ + .uleb128 2 + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW2-.LUW1 + .byte 0xc /* DW_CFA_def_cfa, %rsp offset 8 */ + .uleb128 7 + .uleb128 8 + .byte 0xc0+6 /* DW_CFA_restore, %rbp */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW3-.LUW2 + .byte 0xb /* DW_CFA_restore_state */ + + .align 8 +.LEFDE1: +.LSFDE3: + .long .LEFDE3-.LASFDE3 /* FDE Length */ +.LASFDE3: + .long .LASFDE3-.Lframe1 /* FDE CIE offset */ + .long .LUW5-. /* FDE initial location */ + .long .LUW9-.LUW5 /* FDE address range */ + .uleb128 0x0 /* Augmentation size */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW6-.LUW5 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 208 + .byte 0xa /* DW_CFA_remember_state */ + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW7-.LUW6 + .byte 0xe /* DW_CFA_def_cfa_offset */ + .uleb128 8 + + .byte 0x4 /* DW_CFA_advance_loc4 */ + .long .LUW8-.LUW7 + .byte 0xb /* DW_CFA_restore_state */ + + .align 8 +.LEFDE3: + +#endif /* __x86_64__ */ diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/win32.S b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/win32.S new file mode 100644 index 000000000..496953e43 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi/src/x86/win32.S @@ -0,0 +1,373 @@ +/* ----------------------------------------------------------------------- + win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. + Copyright (c) 2001 John Beniton + Copyright (c) 2002 Ranjit Mathew + + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +.text + +.globl ffi_prep_args + + # This assumes we are using gas. + .balign 16 +.globl _ffi_call_SYSV + +_ffi_call_SYSV: + pushl %ebp + movl %esp,%ebp + + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + # FIXME: Align the stack to a 128-bit boundary to avoid + # potential performance hits. + + call *28(%ebp) + + # Remove the space we pushed for the args + movl 16(%ebp),%ecx + addl %ecx,%esp + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne retint + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +retint: + cmpl $FFI_TYPE_INT,%ecx + jne retfloat + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp epilogue + +retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne retdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne retlongdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne retint64 + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne retstruct1b + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +retstruct1b: + cmpl $FFI_TYPE_SINT8,%ecx + jne retstruct2b + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movb %al,0(%ecx) + jmp epilogue + +retstruct2b: + cmpl $FFI_TYPE_SINT16,%ecx + jne retstruct + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movw %ax,0(%ecx) + jmp epilogue + +retstruct: + # Nothing to do! + +noretval: +epilogue: + movl %ebp,%esp + popl %ebp + ret + +.ffi_call_SYSV_end: + + # This assumes we are using gas. + .balign 16 +.globl _ffi_call_STDCALL + +_ffi_call_STDCALL: + pushl %ebp + movl %esp,%ebp + + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + # FIXME: Align the stack to a 128-bit boundary to avoid + # potential performance hits. + + call *28(%ebp) + + # stdcall functions pop arguments off the stack themselves + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne sc_retint + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne sc_noretval + fstp %st(0) + + jmp sc_epilogue + +sc_retint: + cmpl $FFI_TYPE_INT,%ecx + jne sc_retfloat + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp sc_epilogue + +sc_retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne sc_retdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp sc_epilogue + +sc_retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne sc_retlongdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp sc_epilogue + +sc_retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne sc_retint64 + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp sc_epilogue + +sc_retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne sc_retstruct1b + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +sc_retstruct1b: + cmpl $FFI_TYPE_SINT8,%ecx + jne sc_retstruct2b + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movb %al,0(%ecx) + jmp sc_epilogue + +sc_retstruct2b: + cmpl $FFI_TYPE_SINT16,%ecx + jne sc_retstruct + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movw %ax,0(%ecx) + jmp sc_epilogue + +sc_retstruct: + # Nothing to do! + +sc_noretval: +sc_epilogue: + movl %ebp,%esp + popl %ebp + ret + +.ffi_call_STDCALL_end: + + .globl _ffi_closure_SYSV +_ffi_closure_SYSV: + pushl %ebp + movl %esp, %ebp + subl $40, %esp + leal -24(%ebp), %edx + movl %edx, -12(%ebp) /* resp */ + leal 8(%ebp), %edx + movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */ + leal -12(%ebp), %edx + movl %edx, (%esp) /* &resp */ + call _ffi_closure_SYSV_inner + movl -12(%ebp), %ecx + cmpl $FFI_TYPE_INT, %eax + je .Lcls_retint + cmpl $FFI_TYPE_FLOAT, %eax + je .Lcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lcls_retllong + cmpl $FFI_TYPE_SINT8, %eax /* 1-byte struct */ + je .Lcls_retstruct1 + cmpl $FFI_TYPE_SINT16, %eax /* 2-bytes struct */ + je .Lcls_retstruct2 +.Lcls_epilogue: + movl %ebp, %esp + popl %ebp + ret +.Lcls_retint: + movl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retfloat: + flds (%ecx) + jmp .Lcls_epilogue +.Lcls_retdouble: + fldl (%ecx) + jmp .Lcls_epilogue +.Lcls_retldouble: + fldt (%ecx) + jmp .Lcls_epilogue +.Lcls_retllong: + movl (%ecx), %eax + movl 4(%ecx), %edx + jmp .Lcls_epilogue +.Lcls_retstruct1: + movsbl (%ecx), %eax + jmp .Lcls_epilogue +.Lcls_retstruct2: + movswl (%ecx), %eax + jmp .Lcls_epilogue +.ffi_closure_SYSV_end: + +#if !FFI_NO_RAW_API + +#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3) +#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4) +#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4) +#define CIF_FLAGS_OFFSET 20 + + .balign 16 + .globl _ffi_closure_raw_SYSV +_ffi_closure_raw_SYSV: + pushl %ebp + movl %esp, %ebp + pushl %esi + subl $36, %esp + movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */ + movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */ + movl %edx, 12(%esp) /* user_data */ + leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */ + movl %edx, 8(%esp) /* raw_args */ + leal -24(%ebp), %edx + movl %edx, 4(%esp) /* &res */ + movl %esi, (%esp) /* cif */ + call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */ + movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */ + cmpl $FFI_TYPE_INT, %eax + je .Lrcls_retint + cmpl $FFI_TYPE_FLOAT, %eax + je .Lrcls_retfloat + cmpl $FFI_TYPE_DOUBLE, %eax + je .Lrcls_retdouble + cmpl $FFI_TYPE_LONGDOUBLE, %eax + je .Lrcls_retldouble + cmpl $FFI_TYPE_SINT64, %eax + je .Lrcls_retllong +.Lrcls_epilogue: + addl $36, %esp + popl %esi + popl %ebp + ret +.Lrcls_retint: + movl -24(%ebp), %eax + jmp .Lrcls_epilogue +.Lrcls_retfloat: + flds -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retdouble: + fldl -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retldouble: + fldt -24(%ebp) + jmp .Lrcls_epilogue +.Lrcls_retllong: + movl -24(%ebp), %eax + movl -20(%ebp), %edx + jmp .Lrcls_epilogue +.ffi_closure_raw_SYSV_end: + +#endif diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/debug.c b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/debug.c new file mode 100644 index 000000000..98f1f9f0b --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/debug.c @@ -0,0 +1,59 @@ +/* ----------------------------------------------------------------------- + debug.c - Copyright (c) 1996 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> +#include <stdio.h> + +/* General debugging routines */ + +void ffi_stop_here(void) +{ + /* This function is only useful for debugging purposes. + Place a breakpoint on ffi_stop_here to be notified of + significant events. */ +} + +/* This function should only be called via the FFI_ASSERT() macro */ + +void ffi_assert(char *expr, char *file, int line) +{ + fprintf(stderr, "ASSERTION FAILURE: %s at %s:%d\n", expr, file, line); + ffi_stop_here(); + abort(); +} + +/* Perform a sanity check on an ffi_type structure */ + +void ffi_type_test(ffi_type *a, char *file, int line) +{ + FFI_ASSERT_AT(a != NULL, file, line); + + /*@-usedef@*/ + FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line); + FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line); + FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line); + FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line); + /*@=usedef@*/ +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.c new file mode 100644 index 000000000..1193aaac6 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.c @@ -0,0 +1,310 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1998 Red Hat, Inc. + + ARM Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +#ifdef _WIN32_WCE +#pragma warning (disable : 4142) /* benign redefinition of type */ +#include <windows.h> +#endif + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + (i != 0); + i--, p_arg++) + { + size_t z; + size_t argalign = (*p_arg)->alignment; + +#ifdef _WIN32_WCE + if (argalign > 4) + argalign = 4; +#endif + /* Align if necessary */ + if ((argalign - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, argalign); + } + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + /* *p_argv may not be aligned for a UINT32 */ + memcpy(argp, *p_argv, z); + break; + + default: + FFI_ASSERT(0); + } + } + else if (z == sizeof(int)) + { + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_SINT64: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern void ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +/* Return type changed from void for ctypes */ +int ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + default: + FFI_ASSERT(0); + break; + } + /* I think calculating the real stack pointer delta is not useful + because stdcall is not supported */ + return 0; +} + +/** private members **/ + +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif); + +/* This function is called by ffi_closure_SYSV in sysv.asm */ + +unsigned int +ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue) +{ + ffi_cif *cif = closure->cif; + void **out_args; + + out_args = (void **) alloca(cif->nargs * sizeof (void *)); + + /* this call will initialize out_args, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set rvalue to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(in_args, &rvalue, out_args, cif); + + (closure->fun)(cif, rvalue, out_args, closure->user_data); + + /* Tell ffi_closure_SYSV what the returntype is */ + return cif->flags; +} + +/*@-exportheader@*/ +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif) +/*@=exportheader@*/ +{ + unsigned int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + + argp = stack; + + if ( cif->rtype->type == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + size_t argalign = (*p_arg)->alignment; + +#ifdef _WIN32_WCE + if (argalign > 4) + argalign = 4; +#endif + /* Align if necessary */ + if ((argalign - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, argalign); + } + + z = (*p_arg)->size; + if (z < sizeof(int)) + z = sizeof(int); + + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } +} + +/* + add ip, pc, #-8 ; ip = address of this trampoline == address of ffi_closure + ldr pc, [pc, #-4] ; jump to __fun + DCD __fun +*/ +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN) \ +{ \ + unsigned int *__tramp = (unsigned int *)(TRAMP); \ + __tramp[0] = 0xe24fc008; /* add ip, pc, #-8 */ \ + __tramp[1] = 0xe51ff004; /* ldr pc, [pc, #-4] */ \ + __tramp[2] = (unsigned int)(FUN); \ + } + +/* the cif must already be prep'ed */ + +/* defined in sysv.asm */ +void ffi_closure_SYSV(void); + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + +#ifdef _WIN32_WCE + /* This is important to allow calling the trampoline safely */ + FlushInstructionCache(GetCurrentProcess(), 0, 0); +#endif + + return FFI_OK; +} + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.h b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.h new file mode 100644 index 000000000..67975b6b4 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi.h @@ -0,0 +1,317 @@ +/* -----------------------------------------------------------------*-C-*- + libffi 2.00-beta-wince - Copyright (c) 1996-2003 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------- + The basic API is described in the README file. + + The raw API is designed to bypass some of the argument packing + and unpacking on architectures for which it can be avoided. + + The closure API allows interpreted functions to be packaged up + inside a C function pointer, so that they can be called as C functions, + with no understanding on the client side that they are interpreted. + It can also be used in other cases in which it is necessary to package + up a user specified parameter and a function pointer as a single + function pointer. + + The closure API must be implemented in order to get its functionality, + e.g. for use by gij. Routines are provided to emulate the raw API + if the underlying platform doesn't allow faster implementation. + + More details on the raw and cloure API can be found in: + + http://gcc.gnu.org/ml/java/1999-q3/msg00138.html + + and + + http://gcc.gnu.org/ml/java/1999-q3/msg00174.html + -------------------------------------------------------------------- */ + +#ifndef LIBFFI_H +#define LIBFFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Specify which architecture libffi is configured for. */ +/*#define @TARGET@*/ + +/* ---- System configuration information --------------------------------- */ + +#include <ffitarget.h> + +#ifndef LIBFFI_ASM + +#include <stddef.h> +#include <limits.h> + +/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). + But we can find it either under the correct ANSI name, or under GNU + C's internal name. */ +#ifdef LONG_LONG_MAX +# define FFI_LONG_LONG_MAX LONG_LONG_MAX +#else +# ifdef LLONG_MAX +# define FFI_LONG_LONG_MAX LLONG_MAX +# else +# ifdef __GNUC__ +# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ +# endif +# ifdef _MSC_VER +# define FFI_LONG_LONG_MAX _I64_MAX +# endif +# endif +#endif + +#if SCHAR_MAX == 127 +# define ffi_type_uchar ffi_type_uint8 +# define ffi_type_schar ffi_type_sint8 +#else + #error "char size not supported" +#endif + +#if SHRT_MAX == 32767 +# define ffi_type_ushort ffi_type_uint16 +# define ffi_type_sshort ffi_type_sint16 +#elif SHRT_MAX == 2147483647 +# define ffi_type_ushort ffi_type_uint32 +# define ffi_type_sshort ffi_type_sint32 +#else + #error "short size not supported" +#endif + +#if INT_MAX == 32767 +# define ffi_type_uint ffi_type_uint16 +# define ffi_type_sint ffi_type_sint16 +#elif INT_MAX == 2147483647 +# define ffi_type_uint ffi_type_uint32 +# define ffi_type_sint ffi_type_sint32 +#elif INT_MAX == 9223372036854775807 +# define ffi_type_uint ffi_type_uint64 +# define ffi_type_sint ffi_type_sint64 +#else + #error "int size not supported" +#endif + +#define ffi_type_ulong ffi_type_uint64 +#define ffi_type_slong ffi_type_sint64 +#if LONG_MAX == 2147483647 +# if FFI_LONG_LONG_MAX != 9223372036854775807 + #error "no 64-bit data type supported" +# endif +#elif LONG_MAX != 9223372036854775807 + #error "long size not supported" +#endif + +/* The closure code assumes that this works on pointers, i.e. a size_t */ +/* can hold a pointer. */ + +typedef struct _ffi_type +{ + size_t size; + unsigned short alignment; + unsigned short type; + /*@null@*/ struct _ffi_type **elements; +} ffi_type; + +/* These are defined in types.c */ +extern ffi_type ffi_type_void; +extern ffi_type ffi_type_uint8; +extern ffi_type ffi_type_sint8; +extern ffi_type ffi_type_uint16; +extern ffi_type ffi_type_sint16; +extern ffi_type ffi_type_uint32; +extern ffi_type ffi_type_sint32; +extern ffi_type ffi_type_uint64; +extern ffi_type ffi_type_sint64; +extern ffi_type ffi_type_float; +extern ffi_type ffi_type_double; +extern ffi_type ffi_type_longdouble; +extern ffi_type ffi_type_pointer; + + +typedef enum { + FFI_OK = 0, + FFI_BAD_TYPEDEF, + FFI_BAD_ABI +} ffi_status; + +typedef unsigned FFI_TYPE; + +typedef struct { + ffi_abi abi; + unsigned nargs; + /*@dependent@*/ ffi_type **arg_types; + /*@dependent@*/ ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; + +/* ---- Definitions for the raw API -------------------------------------- */ + +#ifndef FFI_SIZEOF_ARG +# if LONG_MAX == 2147483647 +# define FFI_SIZEOF_ARG 4 +# elif LONG_MAX == 9223372036854775807 +# define FFI_SIZEOF_ARG 8 +# endif +#endif + +typedef union { + ffi_sarg sint; + ffi_arg uint; + float flt; + char data[FFI_SIZEOF_ARG]; + void* ptr; +} ffi_raw; + +void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_raw_size (ffi_cif *cif); + +/* This is analogous to the raw API, except it uses Java parameter */ +/* packing, even on 64-bit machines. I.e. on 64-bit machines */ +/* longs and doubles are followed by an empty 64-bit word. */ + +void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_java_raw_size (ffi_cif *cif); + +/* ---- Definitions for closures ----------------------------------------- */ + +#if FFI_CLOSURES + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + ffi_cif *cif; + void (*fun)(ffi_cif*,void*,void**,void*); + void *user_data; +} ffi_closure; + +ffi_status +ffi_prep_closure (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data); + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + + ffi_cif *cif; + +#if !FFI_NATIVE_RAW_API + + /* if this is enabled, then a raw closure has the same layout + as a regular closure. We use this to install an intermediate + handler to do the transaltion, void** -> ffi_raw*. */ + + void (*translate_args)(ffi_cif*,void*,void**,void*); + void *this_closure; + +#endif + + void (*fun)(ffi_cif*,void*,ffi_raw*,void*); + void *user_data; + +} ffi_raw_closure; + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +ffi_status +ffi_prep_java_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +#endif /* FFI_CLOSURES */ + +/* ---- Public interface definition -------------------------------------- */ + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes); + +/* Return type changed from void for ctypes */ +int ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue); + +/* Useful for eliminating compiler warnings */ +#define FFI_FN(f) ((void (*)())f) + +/* ---- Definitions shared with assembly code ---------------------------- */ + +#endif + +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 +#if 0 /*@HAVE_LONG_DOUBLE@*/ +#define FFI_TYPE_LONGDOUBLE 4 +#else +#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 + +/* This should always refer to the last type code (for sanity checks) */ +#define FFI_TYPE_LAST FFI_TYPE_POINTER + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi_common.h b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi_common.h new file mode 100644 index 000000000..bf879d11d --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffi_common.h @@ -0,0 +1,111 @@ +/* ----------------------------------------------------------------------- + ffi_common.h - Copyright (c) 1996 Red Hat, Inc. + + Common internal definitions and macros. Only necessary for building + libffi. + ----------------------------------------------------------------------- */ + +#ifndef FFI_COMMON_H +#define FFI_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <fficonfig.h> + +/* Do not move this. Some versions of AIX are very picky about where + this is positioned. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +char *alloca (); +# endif +# endif +# endif +#endif + +/* Check for the existence of memcpy. */ +#if STDC_HEADERS +# include <string.h> +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#if defined(FFI_DEBUG) +#include <stdio.h> +#endif + +#ifdef FFI_DEBUG +/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); +void ffi_stop_here(void); +void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); + +#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) +#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) +#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) +#else +#define FFI_ASSERT(x) +#define FFI_ASSERT_AT(x, f, l) +#define FFI_ASSERT_VALID_TYPE(x) +#endif + +#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif); + +/* Extended cif, used in callback from assembly routine */ +typedef struct +{ + /*@dependent@*/ ffi_cif *cif; + /*@dependent@*/ void *rvalue; + /*@dependent@*/ void **avalue; +} extended_cif; + +/* Terse sized type definitions. */ +#if defined(__GNUC__) + +typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); +typedef signed int SINT8 __attribute__((__mode__(__QI__))); +typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); +typedef signed int SINT16 __attribute__((__mode__(__HI__))); +typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); +typedef signed int SINT32 __attribute__((__mode__(__SI__))); +typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); +typedef signed int SINT64 __attribute__((__mode__(__DI__))); + +#elif defined(_MSC_VER) + +typedef unsigned __int8 UINT8; +typedef signed __int8 SINT8; +typedef unsigned __int16 UINT16; +typedef signed __int16 SINT16; +typedef unsigned __int32 UINT32; +typedef signed __int32 SINT32; +typedef unsigned __int64 UINT64; +typedef signed __int64 SINT64; + +#else +#error "Need typedefs here" +#endif + +typedef float FLOAT32; + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/fficonfig.h b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/fficonfig.h new file mode 100644 index 000000000..3c7964c93 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/fficonfig.h @@ -0,0 +1,152 @@ +/* fficonfig.h created manually for Windows CE on ARM */ +/* fficonfig.h.in. Generated from configure.ac by autoheader. */ + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 1234 + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to the flags needed for the .section .eh_frame directive. */ +/* #undef EH_FRAME_FLAGS */ + +/* Define this if you want extra debugging. */ +#ifdef DEBUG /* Defined by the project settings for Debug builds */ +#define FFI_DEBUG +#else +#undef FFI_DEBUG +#endif + +/* Define this is you do not want support for the raw API. */ +/* #undef FFI_NO_RAW_API */ + +/* Define this is you do not want support for aggregate types. */ +/* #undef FFI_NO_STRUCTS */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). + */ +/* #undef HAVE_ALLOCA_H */ + +/* Define if your assembler supports .register. */ +/* #undef HAVE_AS_REGISTER_PSEUDO_OP */ + +/* Define if your assembler and linker support unaligned PC relative relocs. + */ +/* #undef HAVE_AS_SPARC_UA_PCREL */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +/* #undef HAVE_INTTYPES_H */ + +/* Define if you have the long double type and it is bigger than a double */ +/* This differs from the MSVC build, but even there it should not be defined */ +/* #undef HAVE_LONG_DOUBLE */ + +/* Define to 1 if you have the `memcpy' function. */ +#define HAVE_MEMCPY 1 + +/* Define to 1 if you have the <memory.h> header file. */ +/* WinCE has this but I don't think we need to use it */ +/* #undef HAVE_MEMORY_H */ + +/* Define to 1 if you have the `mmap' function. */ +/* #undef HAVE_MMAP */ + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +/* #undef HAVE_MMAP_ANON */ + +/* Define if mmap of /dev/zero works. */ +/* #undef HAVE_MMAP_DEV_ZERO */ + +/* Define if read-only mmap of a plain file works. */ +/* #undef HAVE_MMAP_FILE */ + +/* Define if .eh_frame sections should be read-only. */ +/* #undef HAVE_RO_EH_FRAME */ + +/* Define to 1 if you have the <stdint.h> header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/mman.h> header file. */ +/* #undef HAVE_SYS_MMAN_H */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +/* #undef HAVE_SYS_STAT_H */ + +/* Define to 1 if you have the <sys/types.h> header file. */ +/* #undef HAVE_SYS_TYPES_H */ + +/* Define to 1 if you have the <unistd.h> header file. */ +/* #undef HAVE_UNISTD_H */ + +/* Define if the host machine stores words of multi-word integers in + big-endian order. */ +/* #undef HOST_WORDS_BIG_ENDIAN */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Name of package */ +/* #undef PACKAGE */ + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Define to the full name of this package. */ +/* #undef PACKAGE_NAME */ + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the version of this package. */ +/* #undef PACKAGE_VERSION */ + +/* The number of bytes in type double */ +#define SIZEOF_DOUBLE 8 + +/* The number of bytes in type long double */ +#define SIZEOF_LONG_DOUBLE 8 + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define this if you are using Purify and want to suppress spurious messages. + */ +/* #undef USING_PURIFY */ + +/* Version number of package */ +/* #undef VERSION */ + +/* whether byteorder is bigendian */ +/* #undef WORDS_BIGENDIAN */ + +#define alloca _alloca + +#define abort() exit(999) diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffitarget.h new file mode 100644 index 000000000..2627b2577 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/ffitarget.h @@ -0,0 +1,49 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for ARM. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + FFI_SYSV, + FFI_DEFAULT_ABI = FFI_SYSV, + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 +#define FFI_TRAMPOLINE_SIZE 12 + +#define FFI_NATIVE_RAW_API 0 + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/prep_cif.c b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/prep_cif.c new file mode 100644 index 000000000..9edce2f65 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/prep_cif.c @@ -0,0 +1,175 @@ +/* ----------------------------------------------------------------------- + prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> + + +/* Round up to FFI_SIZEOF_ARG. */ + +#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) + +/* Perform machine independent initialization of aggregate type + specifications. */ + +static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) +{ + ffi_type **ptr; + + FFI_ASSERT(arg != NULL); + + /*@-usedef@*/ + + FFI_ASSERT(arg->elements != NULL); + FFI_ASSERT(arg->size == 0); + FFI_ASSERT(arg->alignment == 0); + + ptr = &(arg->elements[0]); + + while ((*ptr) != NULL) + { + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type */ + FFI_ASSERT_VALID_TYPE(*ptr); + + arg->size = ALIGN(arg->size, (*ptr)->alignment); + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; + + ptr++; + } + + /* Structure size includes tail padding. This is important for + structures that fit in one register on ABIs like the PowerPC64 + Linux ABI that right justify small structs in a register. + It's also needed for nested structure layout, for example + struct A { long a; char b; }; struct B { struct A x; char y; }; + should find y at an offset of 2*sizeof(long) and result in a + total size of 3*sizeof(long). */ + arg->size = ALIGN (arg->size, arg->alignment); + + if (arg->size == 0) + return FFI_BAD_TYPEDEF; + else + return FFI_OK; + + /*@=usedef@*/ +} + +/* Perform machine independent ffi_cif preparation, then call + machine dependent routine. */ + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes) +{ + unsigned bytes = 0; + unsigned int i; + ffi_type **ptr; + + FFI_ASSERT(cif != NULL); + FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); + + cif->abi = abi; + cif->arg_types = atypes; + cif->nargs = nargs; + cif->rtype = rtype; + + cif->flags = 0; + + /* Initialize the return type if necessary */ + /*@-usedef@*/ + if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; + /*@=usedef@*/ + + /* Perform a sanity check on the return type */ + FFI_ASSERT_VALID_TYPE(cif->rtype); + + /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ +#if !defined M68K && !defined __x86_64__ && !defined S390 + /* Make space for the return structure pointer */ + if (cif->rtype->type == FFI_TYPE_STRUCT + /* MSVC returns small structures in registers. But we have a different + workaround: pretend int32 or int64 return type, and converting to + structure afterwards. */ +#ifdef SPARC + && (cif->abi != FFI_V9 || cif->rtype->size > 32) +#endif + ) + bytes = STACK_ARG_SIZE(sizeof(void*)); +#endif + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + + /* Initialize any uninitialized aggregate type definitions */ + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type, do this + check after the initialization. */ + FFI_ASSERT_VALID_TYPE(*ptr); + +#if !defined __x86_64__ && !defined S390 +#ifdef SPARC + if (((*ptr)->type == FFI_TYPE_STRUCT + && ((*ptr)->size > 16 || cif->abi != FFI_V9)) + || ((*ptr)->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_V9)) + bytes += sizeof(void*); + else +#endif + { +#ifndef _MSC_VER + /* Don't know if this is a libffi bug or not. At least on + Windows with MSVC, function call parameters are *not* + aligned in the same way as structure fields are, they are + only aligned in integer boundaries. + + This doesn't do any harm for cdecl functions and closures, + since the caller cleans up the stack, but it is wrong for + stdcall functions where the callee cleans. + */ + + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + +#endif + bytes += STACK_ARG_SIZE((*ptr)->size); + } +#endif + } + + cif->bytes = bytes; + + /* Perform machine dependent cif processing */ + return ffi_prep_cif_machdep(cif); +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/sysv.asm b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/sysv.asm new file mode 100644 index 000000000..db78b9085 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_arm_wince/sysv.asm @@ -0,0 +1,228 @@ +; ----------------------------------------------------------------------- +; sysv.S - Copyright (c) 1998 Red Hat, Inc. +; +; ARM Foreign Function Interface +; +; Permission is hereby granted, free of charge, to any person obtaining +; a copy of this software and associated documentation files (the +; ``Software''), to deal in the Software without restriction, including +; without limitation the rights to use, copy, modify, merge, publish, +; distribute, sublicense, and/or sell copies of the Software, and to +; permit persons to whom the Software is furnished to do so, subject to +; the following conditions: +; +; The above copyright notice and this permission notice shall be included +; in all copies or substantial portions of the Software. +; +; THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS +; OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +; IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR +; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +; OTHER DEALINGS IN THE SOFTWARE. +; ----------------------------------------------------------------------- */ + +;#define LIBFFI_ASM +;#include <fficonfig.h> +;#include <ffi.h> +;#ifdef HAVE_MACHINE_ASM_H +;#include <machine/asm.h> +;#else +;#ifdef __USER_LABEL_PREFIX__ +;#define CONCAT1(a, b) CONCAT2(a, b) +;#define CONCAT2(a, b) a ## b + +;/* Use the right prefix for global labels. */ +;#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) +;#else +;#define CNAME(x) x +;#endif +;#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): +;#endif + + +FFI_TYPE_VOID EQU 0 +FFI_TYPE_INT EQU 1 +FFI_TYPE_FLOAT EQU 2 +FFI_TYPE_DOUBLE EQU 3 +;FFI_TYPE_LONGDOUBLE EQU 4 +FFI_TYPE_UINT8 EQU 5 +FFI_TYPE_SINT8 EQU 6 +FFI_TYPE_UINT16 EQU 7 +FFI_TYPE_SINT16 EQU 8 +FFI_TYPE_UINT32 EQU 9 +FFI_TYPE_SINT32 EQU 10 +FFI_TYPE_UINT64 EQU 11 +FFI_TYPE_SINT64 EQU 12 +FFI_TYPE_STRUCT EQU 13 +FFI_TYPE_POINTER EQU 14 + +; WinCE always uses software floating point (I think) +__SOFTFP__ EQU {TRUE} + + + AREA |.text|, CODE, ARM ; .text + + + ; a1: ffi_prep_args + ; a2: &ecif + ; a3: cif->bytes + ; a4: fig->flags + ; sp+0: ecif.rvalue + ; sp+4: fn + + ; This assumes we are using gas. +;ENTRY(ffi_call_SYSV) + + EXPORT |ffi_call_SYSV| + +|ffi_call_SYSV| PROC + + ; Save registers + stmfd sp!, {a1-a4, fp, lr} + mov fp, sp + + ; Make room for all of the new args. + sub sp, fp, a3 + + ; Place all of the ffi_prep_args in position + mov ip, a1 + mov a1, sp + ; a2 already set + + ; And call + mov lr, pc + mov pc, ip + + ; move first 4 parameters in registers + ldr a1, [sp, #0] + ldr a2, [sp, #4] + ldr a3, [sp, #8] + ldr a4, [sp, #12] + + ; and adjust stack + ldr ip, [fp, #8] + cmp ip, #16 + movge ip, #16 + add sp, sp, ip + + ; call function + mov lr, pc + ldr pc, [fp, #28] + + ; Remove the space we pushed for the args + mov sp, fp + + ; Load a3 with the pointer to storage for the return value + ldr a3, [sp, #24] + + ; Load a4 with the return type code + ldr a4, [sp, #12] + + ; If the return value pointer is NULL, assume no return value. + cmp a3, #0 + beq call_epilogue + +; return INT + cmp a4, #FFI_TYPE_INT + streq a1, [a3] + beq call_epilogue + +; return FLOAT + cmp a4, #FFI_TYPE_FLOAT + [ __SOFTFP__ ;ifdef __SOFTFP__ + streq a1, [a3] + | ;else + stfeqs f0, [a3] + ] ;endif + beq call_epilogue + +; return DOUBLE or LONGDOUBLE + cmp a4, #FFI_TYPE_DOUBLE + [ __SOFTFP__ ;ifdef __SOFTFP__ + stmeqia a3, {a1, a2} + | ;else + stfeqd f0, [a3] + ] ;endif + beq call_epilogue + +; return SINT64 or UINT64 + cmp a4, #FFI_TYPE_SINT64 + stmeqia a3, {a1, a2} + +call_epilogue + ldmfd sp!, {a1-a4, fp, pc} + +;.ffi_call_SYSV_end: + ;.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) + ENDP + + +RESERVE_RETURN EQU 16 + + ; This function is called by the trampoline + ; It is NOT callable from C + ; ip = pointer to struct ffi_closure + + IMPORT |ffi_closure_SYSV_inner| + + EXPORT |ffi_closure_SYSV| +|ffi_closure_SYSV| PROC + + ; Store the argument registers on the stack + stmfd sp!, {a1-a4} + ; Push the return address onto the stack + stmfd sp!, {lr} + + mov a1, ip ; first arg = address of ffi_closure + add a2, sp, #4 ; second arg = sp+4 (points to saved a1) + + ; Allocate space for a non-struct return value + sub sp, sp, #RESERVE_RETURN + mov a3, sp ; third arg = return value address + + ; static unsigned int + ; ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue) + bl ffi_closure_SYSV_inner + ; a1 now contains the return type code + + ; At this point the return value is on the stack + ; Transfer it to the correct registers if necessary + +; return INT + cmp a1, #FFI_TYPE_INT + ldreq a1, [sp] + beq closure_epilogue + +; return FLOAT + cmp a1, #FFI_TYPE_FLOAT + [ __SOFTFP__ ;ifdef __SOFTFP__ + ldreq a1, [sp] + | ;else + stfeqs f0, [sp] + ] ;endif + beq closure_epilogue + +; return DOUBLE or LONGDOUBLE + cmp a1, #FFI_TYPE_DOUBLE + [ __SOFTFP__ ;ifdef __SOFTFP__ + ldmeqia sp, {a1, a2} + | ;else + stfeqd f0, [sp] + ] ;endif + beq closure_epilogue + +; return SINT64 or UINT64 + cmp a1, #FFI_TYPE_SINT64 + ldmeqia sp, {a1, a2} + +closure_epilogue + add sp, sp, #RESERVE_RETURN ; remove return value buffer + ldmfd sp!, {ip} ; ip = pop return address + add sp, sp, #16 ; remove saved argument registers {a1-a4} from the stack + mov pc, ip ; return + + ENDP ; ffi_closure_SYSV + + END diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/LICENSE b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/LICENSE new file mode 100644 index 000000000..f59179515 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/LICENSE @@ -0,0 +1,20 @@ +libffi - Copyright (c) 1996-2003 Red Hat, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +``Software''), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README new file mode 100644 index 000000000..1fc27470d --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README @@ -0,0 +1,500 @@ +This directory contains the libffi package, which is not part of GCC but +shipped with GCC as convenience. + +Status +====== + +libffi-2.00 has not been released yet! This is a development snapshot! + +libffi-1.20 was released on October 5, 1998. Check the libffi web +page for updates: <URL:http://sources.redhat.com/libffi/>. + + +What is libffi? +=============== + +Compilers for high level languages generate code that follow certain +conventions. These conventions are necessary, in part, for separate +compilation to work. One such convention is the "calling +convention". The "calling convention" is essentially a set of +assumptions made by the compiler about where function arguments will +be found on entry to a function. A "calling convention" also specifies +where the return value for a function is found. + +Some programs may not know at the time of compilation what arguments +are to be passed to a function. For instance, an interpreter may be +told at run-time about the number and types of arguments used to call +a given function. Libffi can be used in such programs to provide a +bridge from the interpreter program to compiled code. + +The libffi library provides a portable, high level programming +interface to various calling conventions. This allows a programmer to +call any function specified by a call interface description at run +time. + +Ffi stands for Foreign Function Interface. A foreign function +interface is the popular name for the interface that allows code +written in one language to call code written in another language. The +libffi library really only provides the lowest, machine dependent +layer of a fully featured foreign function interface. A layer must +exist above libffi that handles type conversions for values passed +between the two languages. + + +Supported Platforms and Prerequisites +===================================== + +Libffi has been ported to: + + SunOS 4.1.3 & Solaris 2.x (SPARC-V8, SPARC-V9) + + Irix 5.3 & 6.2 (System V/o32 & n32) + + Intel x86 - Linux (System V ABI) + + Alpha - Linux and OSF/1 + + m68k - Linux (System V ABI) + + PowerPC - Linux (System V ABI, Darwin, AIX) + + ARM - Linux (System V ABI) + +Libffi has been tested with the egcs 1.0.2 gcc compiler. Chances are +that other versions will work. Libffi has also been built and tested +with the SGI compiler tools. + +On PowerPC, the tests failed (see the note below). + +You must use GNU make to build libffi. SGI's make will not work. +Sun's probably won't either. + +If you port libffi to another platform, please let me know! I assume +that some will be easy (x86 NetBSD), and others will be more difficult +(HP). + + +Installing libffi +================= + +[Note: before actually performing any of these installation steps, + you may wish to read the "Platform Specific Notes" below.] + +First you must configure the distribution for your particular +system. Go to the directory you wish to build libffi in and run the +"configure" program found in the root directory of the libffi source +distribution. + +You may want to tell configure where to install the libffi library and +header files. To do that, use the --prefix configure switch. Libffi +will install under /usr/local by default. + +If you want to enable extra run-time debugging checks use the the +--enable-debug configure switch. This is useful when your program dies +mysteriously while using libffi. + +Another useful configure switch is --enable-purify-safety. Using this +will add some extra code which will suppress certain warnings when you +are using Purify with libffi. Only use this switch when using +Purify, as it will slow down the library. + +Configure has many other options. Use "configure --help" to see them all. + +Once configure has finished, type "make". Note that you must be using +GNU make. SGI's make will not work. Sun's probably won't either. +You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. + +To ensure that libffi is working as advertised, type "make test". + +To install the library and header files, type "make install". + + +Using libffi +============ + + The Basics + ---------- + +Libffi assumes that you have a pointer to the function you wish to +call and that you know the number and types of arguments to pass it, +as well as the return type of the function. + +The first thing you must do is create an ffi_cif object that matches +the signature of the function you wish to call. The cif in ffi_cif +stands for Call InterFace. To prepare a call interface object, use the +following function: + +ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, + unsigned int nargs, + ffi_type *rtype, ffi_type **atypes); + + CIF is a pointer to the call interface object you wish + to initialize. + + ABI is an enum that specifies the calling convention + to use for the call. FFI_DEFAULT_ABI defaults + to the system's native calling convention. Other + ABI's may be used with care. They are system + specific. + + NARGS is the number of arguments this function accepts. + libffi does not yet support vararg functions. + + RTYPE is a pointer to an ffi_type structure that represents + the return type of the function. Ffi_type objects + describe the types of values. libffi provides + ffi_type objects for many of the native C types: + signed int, unsigned int, signed char, unsigned char, + etc. There is also a pointer ffi_type object and + a void ffi_type. Use &ffi_type_void for functions that + don't return values. + + ATYPES is a vector of ffi_type pointers. ARGS must be NARGS long. + If NARGS is 0, this is ignored. + + +ffi_prep_cif will return a status code that you are responsible +for checking. It will be one of the following: + + FFI_OK - All is good. + + FFI_BAD_TYPEDEF - One of the ffi_type objects that ffi_prep_cif + came across is bad. + + +Before making the call, the VALUES vector should be initialized +with pointers to the appropriate argument values. + +To call the the function using the initialized ffi_cif, use the +ffi_call function: + +void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues); + + CIF is a pointer to the ffi_cif initialized specifically + for this function. + + FN is a pointer to the function you want to call. + + RVALUE is a pointer to a chunk of memory that is to hold the + result of the function call. Currently, it must be + at least one word in size (except for the n32 version + under Irix 6.x, which must be a pointer to an 8 byte + aligned value (a long long). It must also be at least + word aligned (depending on the return type, and the + system's alignment requirements). If RTYPE is + &ffi_type_void, this is ignored. If RVALUE is NULL, + the return value is discarded. + + AVALUES is a vector of void* that point to the memory locations + holding the argument values for a call. + If NARGS is 0, this is ignored. + + +If you are expecting a return value from FN it will have been stored +at RVALUE. + + + + An Example + ---------- + +Here is a trivial example that calls puts() a few times. + + #include <stdio.h> + #include <ffi.h> + + int main() + { + ffi_cif cif; + ffi_type *args[1]; + void *values[1]; + char *s; + int rc; + + /* Initialize the argument info vectors */ + args[0] = &ffi_type_uint; + values[0] = &s; + + /* Initialize the cif */ + if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, + &ffi_type_uint, args) == FFI_OK) + { + s = "Hello World!"; + ffi_call(&cif, puts, &rc, values); + /* rc now holds the result of the call to puts */ + + /* values holds a pointer to the function's arg, so to + call puts() again all we need to do is change the + value of s */ + s = "This is cool!"; + ffi_call(&cif, puts, &rc, values); + } + + return 0; + } + + + + Aggregate Types + --------------- + +Although libffi has no special support for unions or bit-fields, it is +perfectly happy passing structures back and forth. You must first +describe the structure to libffi by creating a new ffi_type object +for it. Here is the definition of ffi_type: + + typedef struct _ffi_type + { + unsigned size; + short alignment; + short type; + struct _ffi_type **elements; + } ffi_type; + +All structures must have type set to FFI_TYPE_STRUCT. You may set +size and alignment to 0. These will be calculated and reset to the +appropriate values by ffi_prep_cif(). + +elements is a NULL terminated array of pointers to ffi_type objects +that describe the type of the structure elements. These may, in turn, +be structure elements. + +The following example initializes a ffi_type object representing the +tm struct from Linux's time.h: + + struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; + /* Those are for future use. */ + long int __tm_gmtoff__; + __const char *__tm_zone__; + }; + + { + ffi_type tm_type; + ffi_type *tm_type_elements[12]; + int i; + + tm_type.size = tm_type.alignment = 0; + tm_type.elements = &tm_type_elements; + + for (i = 0; i < 9; i++) + tm_type_elements[i] = &ffi_type_sint; + + tm_type_elements[9] = &ffi_type_slong; + tm_type_elements[10] = &ffi_type_pointer; + tm_type_elements[11] = NULL; + + /* tm_type can now be used to represent tm argument types and + return types for ffi_prep_cif() */ + } + + + +Platform Specific Notes +======================= + + Intel x86 + --------- + +There are no known problems with the x86 port. + + Sun SPARC - SunOS 4.1.3 & Solaris 2.x + ------------------------------------- + +You must use GNU Make to build libffi on Sun platforms. + + MIPS - Irix 5.3 & 6.x + --------------------- + +Irix 6.2 and better supports three different calling conventions: o32, +n32 and n64. Currently, libffi only supports both o32 and n32 under +Irix 6.x, but only o32 under Irix 5.3. Libffi will automatically be +configured for whichever calling convention it was built for. + +By default, the configure script will try to build libffi with the GNU +development tools. To build libffi with the SGI development tools, set +the environment variable CC to either "cc -32" or "cc -n32" before +running configure under Irix 6.x (depending on whether you want an o32 +or n32 library), or just "cc" for Irix 5.3. + +With the n32 calling convention, when returning structures smaller +than 16 bytes, be sure to provide an RVALUE that is 8 byte aligned. +Here's one way of forcing this: + + double struct_storage[2]; + my_small_struct *s = (my_small_struct *) struct_storage; + /* Use s for RVALUE */ + +If you don't do this you are liable to get spurious bus errors. + +"long long" values are not supported yet. + +You must use GNU Make to build libffi on SGI platforms. + + ARM - System V ABI + ------------------ + +The ARM port was performed on a NetWinder running ARM Linux ELF +(2.0.31) and gcc 2.8.1. + + + + PowerPC System V ABI + -------------------- + +There are two `System V ABI's which libffi implements for PowerPC. +They differ only in how small structures are returned from functions. + +In the FFI_SYSV version, structures that are 8 bytes or smaller are +returned in registers. This is what GCC does when it is configured +for solaris, and is what the System V ABI I have (dated September +1995) says. + +In the FFI_GCC_SYSV version, all structures are returned the same way: +by passing a pointer as the first argument to the function. This is +what GCC does when it is configured for linux or a generic sysv +target. + +EGCS 1.0.1 (and probably other versions of EGCS/GCC) also has a +inconsistency with the SysV ABI: When a procedure is called with many +floating-point arguments, some of them get put on the stack. They are +all supposed to be stored in double-precision format, even if they are +only single-precision, but EGCS stores single-precision arguments as +single-precision anyway. This causes one test to fail (the `many +arguments' test). + + +What's With The Crazy Comments? +=============================== + +You might notice a number of cryptic comments in the code, delimited +by /*@ and @*/. These are annotations read by the program LCLint, a +tool for statically checking C programs. You can read all about it at +<http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>. + + +History +======= + +1.20 Oct-5-98 + Raffaele Sena produces ARM port. + +1.19 Oct-5-98 + Fixed x86 long double and long long return support. + m68k bug fixes from Andreas Schwab. + Patch for DU assembler compatibility for the Alpha from Richard + Henderson. + +1.18 Apr-17-98 + Bug fixes and MIPS configuration changes. + +1.17 Feb-24-98 + Bug fixes and m68k port from Andreas Schwab. PowerPC port from + Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes. + +1.16 Feb-11-98 + Richard Henderson produces Alpha port. + +1.15 Dec-4-97 + Fixed an n32 ABI bug. New libtool, auto* support. + +1.14 May-13-97 + libtool is now used to generate shared and static libraries. + Fixed a minor portability problem reported by Russ McManus + <mcmanr@eq.gs.com>. + +1.13 Dec-2-96 + Added --enable-purify-safety to keep Purify from complaining + about certain low level code. + Sparc fix for calling functions with < 6 args. + Linux x86 a.out fix. + +1.12 Nov-22-96 + Added missing ffi_type_void, needed for supporting void return + types. Fixed test case for non MIPS machines. Cygnus Support + is now Cygnus Solutions. + +1.11 Oct-30-96 + Added notes about GNU make. + +1.10 Oct-29-96 + Added configuration fix for non GNU compilers. + +1.09 Oct-29-96 + Added --enable-debug configure switch. Clean-ups based on LCLint + feedback. ffi_mips.h is always installed. Many configuration + fixes. Fixed ffitest.c for sparc builds. + +1.08 Oct-15-96 + Fixed n32 problem. Many clean-ups. + +1.07 Oct-14-96 + Gordon Irlam rewrites v8.S again. Bug fixes. + +1.06 Oct-14-96 + Gordon Irlam improved the sparc port. + +1.05 Oct-14-96 + Interface changes based on feedback. + +1.04 Oct-11-96 + Sparc port complete (modulo struct passing bug). + +1.03 Oct-10-96 + Passing struct args, and returning struct values works for + all architectures/calling conventions. Expanded tests. + +1.02 Oct-9-96 + Added SGI n32 support. Fixed bugs in both o32 and Linux support. + Added "make test". + +1.01 Oct-8-96 + Fixed float passing bug in mips version. Restructured some + of the code. Builds cleanly with SGI tools. + +1.00 Oct-7-96 + First release. No public announcement. + + +Authors & Credits +================= + +libffi was written by Anthony Green <green@cygnus.com>. + +Portions of libffi were derived from Gianni Mariani's free gencall +library for Silicon Graphics machines. + +The closure mechanism was designed and implemented by Kresten Krab +Thorup. + +The Sparc port was derived from code contributed by the fine folks at +Visible Decisions Inc <http://www.vdi.com>. Further enhancements were +made by Gordon Irlam at Cygnus Solutions <http://www.cygnus.com>. + +The Alpha port was written by Richard Henderson at Cygnus Solutions. + +Andreas Schwab ported libffi to m68k Linux and provided a number of +bug fixes. + +Geoffrey Keating ported libffi to the PowerPC. + +Raffaele Sena ported libffi to the ARM. + +Jesper Skov and Andrew Haley both did more than their fair share of +stepping through the code and tracking down bugs. + +Thanks also to Tom Tromey for bug fixes and configuration help. + +Thanks to Jim Blandy, who provided some useful feedback on the libffi +interface. + +If you have a problem, or have found a bug, please send a note to +green@cygnus.com. diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README.ctypes b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README.ctypes new file mode 100644 index 000000000..17e8a40b8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/README.ctypes @@ -0,0 +1,7 @@ +The purpose is to hack the libffi sources so that they can be compiled +with MSVC, and to extend them so that they have the features I need +for ctypes. + +I retrieved the libffi sources from the gcc cvs repository on +2004-01-27. Then I did 'configure' in a 'build' subdirectory on a x86 +linux system, and copied the files I found useful. diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.c b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.c new file mode 100644 index 000000000..9af6b716d --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.c @@ -0,0 +1,394 @@ +/* ----------------------------------------------------------------------- + ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. + Copyright (c) 2002 Ranjit Mathew + Copyright (c) 2002 Bo Thorsen + Copyright (c) 2002 Roger Sayle + + x86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +#include <stdlib.h> + +/* ffi_prep_args is called by the assembly routine once stack space + has been allocated for the function's arguments */ + +/*@-exportheader@*/ +void ffi_prep_args(char *stack, extended_cif *ecif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if (ecif->cif->rtype->type == FFI_TYPE_STRUCT) + { + *(void **) argp = ecif->rvalue; + argp += 4; + } + + p_argv = ecif->avalue; + + for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; + i != 0; + i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(int) - 1) & (unsigned) argp) + argp = (char *) ALIGN(argp, sizeof(int)); + + z = (*p_arg)->size; + if (z < sizeof(int)) + { + z = sizeof(int); + switch ((*p_arg)->type) + { + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); + break; + + case FFI_TYPE_SINT32: + *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); + break; + + case FFI_TYPE_UINT32: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + case FFI_TYPE_STRUCT: + *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); + break; + + default: + FFI_ASSERT(0); + } + } + else + { + memcpy(argp, *p_argv, z); + } + p_argv++; + argp += z; + } + + return; +} + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif) +{ + /* Set the return type flag */ + switch (cif->rtype->type) + { + case FFI_TYPE_VOID: + case FFI_TYPE_STRUCT: + case FFI_TYPE_SINT64: + case FFI_TYPE_FLOAT: + case FFI_TYPE_DOUBLE: + case FFI_TYPE_LONGDOUBLE: + cif->flags = (unsigned) cif->rtype->type; + break; + + case FFI_TYPE_UINT64: + cif->flags = FFI_TYPE_SINT64; + break; + + default: + cif->flags = FFI_TYPE_INT; + break; + } + + return FFI_OK; +} + +/*@-declundef@*/ +/*@-exportheader@*/ +extern int +ffi_call_SYSV(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +/*@-declundef@*/ +/*@-exportheader@*/ +extern int +ffi_call_STDCALL(void (*)(char *, extended_cif *), + /*@out@*/ extended_cif *, + unsigned, unsigned, + /*@out@*/ unsigned *, + void (*fn)()); +/*@=declundef@*/ +/*@=exportheader@*/ + +int +ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue) +{ + extended_cif ecif; + + ecif.cif = cif; + ecif.avalue = avalue; + + /* If the return value is a struct and we don't have a return */ + /* value address then we need to make one */ + + if ((rvalue == NULL) && + (cif->rtype->type == FFI_TYPE_STRUCT)) + { + /*@-sysunrecog@*/ + ecif.rvalue = alloca(cif->rtype->size); + /*@=sysunrecog@*/ + } + else + ecif.rvalue = rvalue; + + + switch (cif->abi) + { + case FFI_SYSV: + /*@-usedef@*/ + return ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + + case FFI_STDCALL: + /*@-usedef@*/ + return ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, + cif->flags, ecif.rvalue, fn); + /*@=usedef@*/ + break; + + default: + FFI_ASSERT(0); + break; + } + return -1; /* theller: Hrm. */ +} + + +/** private members **/ + +static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, + void** args, ffi_cif* cif); +/* This function is jumped to by the trampoline */ + +static void __fastcall +ffi_closure_SYSV (ffi_closure *closure, int *argp) +{ + // this is our return value storage + long double res; + + // our various things... + ffi_cif *cif; + void **arg_area; + unsigned short rtype; + void *resp = (void*)&res; + void *args = &argp[1]; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void*)); + + /* this call will initialize ARG_AREA, such that each + * element in that array points to the corresponding + * value on the stack; and if the function returns + * a structure, it will re-set RESP to point to the + * structure return address. */ + + ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + rtype = cif->flags; + +#ifdef _MSC_VER + /* now, do a generic return based on the value of rtype */ + if (rtype == FFI_TYPE_INT) + { + _asm mov eax, resp ; + _asm mov eax, [eax] ; + } + else if (rtype == FFI_TYPE_FLOAT) + { + _asm mov eax, resp ; + _asm fld DWORD PTR [eax] ; +// asm ("flds (%0)" : : "r" (resp) : "st" ); + } + else if (rtype == FFI_TYPE_DOUBLE) + { + _asm mov eax, resp ; + _asm fld QWORD PTR [eax] ; +// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_LONGDOUBLE) + { +// asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_SINT64) + { + _asm mov edx, resp ; + _asm mov eax, [edx] ; + _asm mov edx, [edx + 4] ; +// asm ("movl 0(%0),%%eax;" +// "movl 4(%0),%%edx" +// : : "r"(resp) +// : "eax", "edx"); + } +#else + /* now, do a generic return based on the value of rtype */ + if (rtype == FFI_TYPE_INT) + { + asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); + } + else if (rtype == FFI_TYPE_FLOAT) + { + asm ("flds (%0)" : : "r" (resp) : "st" ); + } + else if (rtype == FFI_TYPE_DOUBLE) + { + asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_LONGDOUBLE) + { + asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); + } + else if (rtype == FFI_TYPE_SINT64) + { + asm ("movl 0(%0),%%eax;" + "movl 4(%0),%%edx" + : : "r"(resp) + : "eax", "edx"); + } +#endif +} + +/*@-exportheader@*/ +static void +ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, + void **avalue, ffi_cif *cif) +/*@=exportheader@*/ +{ + register unsigned int i; + register void **p_argv; + register char *argp; + register ffi_type **p_arg; + + argp = stack; + + if ( cif->rtype->type == FFI_TYPE_STRUCT ) { + *rvalue = *(void **) argp; + argp += 4; + } + + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + /* Align if necessary */ + if ((sizeof(int) - 1) & (unsigned) argp) { + argp = (char *) ALIGN(argp, sizeof(int)); + } + + z = (*p_arg)->size; + + /* because we're little endian, this is what it turns into. */ + + *p_argv = (void*) argp; + + p_argv++; + argp += z; + } + + return; +} + +/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ + +#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,BYTES) \ +{ unsigned char *__tramp = (unsigned char*)(TRAMP); \ + unsigned int __fun = (unsigned int)(FUN); \ + unsigned int __ctx = (unsigned int)(CTX); \ + unsigned int __dis = __fun - ((unsigned int) __tramp + 8 + 4); \ + *(unsigned char*) &__tramp[0] = 0xb9; \ + *(unsigned int*) &__tramp[1] = __ctx; /* mov ecx, __ctx */ \ + *(unsigned char*) &__tramp[5] = 0x8b; \ + *(unsigned char*) &__tramp[6] = 0xd4; /* mov edx, esp */ \ + *(unsigned char*) &__tramp[7] = 0xe8; \ + *(unsigned int*) &__tramp[8] = __dis; /* call __fun */ \ + *(unsigned char*) &__tramp[12] = 0xC2; /* ret BYTES */ \ + *(unsigned short*) &__tramp[13] = BYTES; \ + } + +/* the cif must already be prep'ed */ + +ffi_status +ffi_prep_closure (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data) +{ + short bytes; + FFI_ASSERT (cif->abi == FFI_SYSV); + + if (cif->abi == FFI_SYSV) + bytes = 0; + else if (cif->abi == FFI_STDCALL) + bytes = cif->bytes; + else + return FFI_BAD_ABI; + + FFI_INIT_TRAMPOLINE (&closure->tramp[0], + &ffi_closure_SYSV, + (void*)closure, + bytes); + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.h b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.h new file mode 100644 index 000000000..203142d9c --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi.h @@ -0,0 +1,317 @@ +/* -----------------------------------------------------------------*-C-*- + libffi 2.00-beta - Copyright (c) 1996-2003 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------- + The basic API is described in the README file. + + The raw API is designed to bypass some of the argument packing + and unpacking on architectures for which it can be avoided. + + The closure API allows interpreted functions to be packaged up + inside a C function pointer, so that they can be called as C functions, + with no understanding on the client side that they are interpreted. + It can also be used in other cases in which it is necessary to package + up a user specified parameter and a function pointer as a single + function pointer. + + The closure API must be implemented in order to get its functionality, + e.g. for use by gij. Routines are provided to emulate the raw API + if the underlying platform doesn't allow faster implementation. + + More details on the raw and cloure API can be found in: + + http://gcc.gnu.org/ml/java/1999-q3/msg00138.html + + and + + http://gcc.gnu.org/ml/java/1999-q3/msg00174.html + -------------------------------------------------------------------- */ + +#ifndef LIBFFI_H +#define LIBFFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Specify which architecture libffi is configured for. */ +//XXX #define X86 + +/* ---- System configuration information --------------------------------- */ + +#include <ffitarget.h> + +#ifndef LIBFFI_ASM + +#include <stddef.h> +#include <limits.h> + +/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). + But we can find it either under the correct ANSI name, or under GNU + C's internal name. */ +#ifdef LONG_LONG_MAX +# define FFI_LONG_LONG_MAX LONG_LONG_MAX +#else +# ifdef LLONG_MAX +# define FFI_LONG_LONG_MAX LLONG_MAX +# else +# ifdef __GNUC__ +# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ +# endif +# ifdef _MSC_VER +# define FFI_LONG_LONG_MAX _I64_MAX +# endif +# endif +#endif + +#if SCHAR_MAX == 127 +# define ffi_type_uchar ffi_type_uint8 +# define ffi_type_schar ffi_type_sint8 +#else + #error "char size not supported" +#endif + +#if SHRT_MAX == 32767 +# define ffi_type_ushort ffi_type_uint16 +# define ffi_type_sshort ffi_type_sint16 +#elif SHRT_MAX == 2147483647 +# define ffi_type_ushort ffi_type_uint32 +# define ffi_type_sshort ffi_type_sint32 +#else + #error "short size not supported" +#endif + +#if INT_MAX == 32767 +# define ffi_type_uint ffi_type_uint16 +# define ffi_type_sint ffi_type_sint16 +#elif INT_MAX == 2147483647 +# define ffi_type_uint ffi_type_uint32 +# define ffi_type_sint ffi_type_sint32 +#elif INT_MAX == 9223372036854775807 +# define ffi_type_uint ffi_type_uint64 +# define ffi_type_sint ffi_type_sint64 +#else + #error "int size not supported" +#endif + +#define ffi_type_ulong ffi_type_uint64 +#define ffi_type_slong ffi_type_sint64 +#if LONG_MAX == 2147483647 +# if FFI_LONG_LONG_MAX != 9223372036854775807 + #error "no 64-bit data type supported" +# endif +#elif LONG_MAX != 9223372036854775807 + #error "long size not supported" +#endif + +/* The closure code assumes that this works on pointers, i.e. a size_t */ +/* can hold a pointer. */ + +typedef struct _ffi_type +{ + size_t size; + unsigned short alignment; + unsigned short type; + /*@null@*/ struct _ffi_type **elements; +} ffi_type; + +/* These are defined in types.c */ +extern ffi_type ffi_type_void; +extern ffi_type ffi_type_uint8; +extern ffi_type ffi_type_sint8; +extern ffi_type ffi_type_uint16; +extern ffi_type ffi_type_sint16; +extern ffi_type ffi_type_uint32; +extern ffi_type ffi_type_sint32; +extern ffi_type ffi_type_uint64; +extern ffi_type ffi_type_sint64; +extern ffi_type ffi_type_float; +extern ffi_type ffi_type_double; +extern ffi_type ffi_type_longdouble; +extern ffi_type ffi_type_pointer; + + +typedef enum { + FFI_OK = 0, + FFI_BAD_TYPEDEF, + FFI_BAD_ABI +} ffi_status; + +typedef unsigned FFI_TYPE; + +typedef struct { + ffi_abi abi; + unsigned nargs; + /*@dependent@*/ ffi_type **arg_types; + /*@dependent@*/ ffi_type *rtype; + unsigned bytes; + unsigned flags; +#ifdef FFI_EXTRA_CIF_FIELDS + FFI_EXTRA_CIF_FIELDS; +#endif +} ffi_cif; + +/* ---- Definitions for the raw API -------------------------------------- */ + +#ifndef FFI_SIZEOF_ARG +# if LONG_MAX == 2147483647 +# define FFI_SIZEOF_ARG 4 +# elif LONG_MAX == 9223372036854775807 +# define FFI_SIZEOF_ARG 8 +# endif +#endif + +typedef union { + ffi_sarg sint; + ffi_arg uint; + float flt; + char data[FFI_SIZEOF_ARG]; + void* ptr; +} ffi_raw; + +void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_raw_size (ffi_cif *cif); + +/* This is analogous to the raw API, except it uses Java parameter */ +/* packing, even on 64-bit machines. I.e. on 64-bit machines */ +/* longs and doubles are followed by an empty 64-bit word. */ + +void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ ffi_raw *avalue); + +void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); +void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); +size_t ffi_java_raw_size (ffi_cif *cif); + +/* ---- Definitions for closures ----------------------------------------- */ + +#if FFI_CLOSURES + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + ffi_cif *cif; + void (*fun)(ffi_cif*,void*,void**,void*); + void *user_data; +} ffi_closure; + +ffi_status +ffi_prep_closure (ffi_closure*, + ffi_cif *, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data); + +typedef struct { + char tramp[FFI_TRAMPOLINE_SIZE]; + + ffi_cif *cif; + +#if !FFI_NATIVE_RAW_API + + /* if this is enabled, then a raw closure has the same layout + as a regular closure. We use this to install an intermediate + handler to do the transaltion, void** -> ffi_raw*. */ + + void (*translate_args)(ffi_cif*,void*,void**,void*); + void *this_closure; + +#endif + + void (*fun)(ffi_cif*,void*,ffi_raw*,void*); + void *user_data; + +} ffi_raw_closure; + +ffi_status +ffi_prep_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +ffi_status +ffi_prep_java_raw_closure (ffi_raw_closure*, + ffi_cif *cif, + void (*fun)(ffi_cif*,void*,ffi_raw*,void*), + void *user_data); + +#endif /* FFI_CLOSURES */ + +/* ---- Public interface definition -------------------------------------- */ + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, + unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes); + +int +ffi_call(/*@dependent@*/ ffi_cif *cif, + void (*fn)(), + /*@out@*/ void *rvalue, + /*@dependent@*/ void **avalue); + +/* Useful for eliminating compiler warnings */ +#define FFI_FN(f) ((void (*)())f) + +/* ---- Definitions shared with assembly code ---------------------------- */ + +#endif + +/* If these change, update src/mips/ffitarget.h. */ +#define FFI_TYPE_VOID 0 +#define FFI_TYPE_INT 1 +#define FFI_TYPE_FLOAT 2 +#define FFI_TYPE_DOUBLE 3 +#if 1 +#define FFI_TYPE_LONGDOUBLE 4 +#else +#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE +#endif +#define FFI_TYPE_UINT8 5 +#define FFI_TYPE_SINT8 6 +#define FFI_TYPE_UINT16 7 +#define FFI_TYPE_SINT16 8 +#define FFI_TYPE_UINT32 9 +#define FFI_TYPE_SINT32 10 +#define FFI_TYPE_UINT64 11 +#define FFI_TYPE_SINT64 12 +#define FFI_TYPE_STRUCT 13 +#define FFI_TYPE_POINTER 14 + +/* This should always refer to the last type code (for sanity checks) */ +#define FFI_TYPE_LAST FFI_TYPE_POINTER + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi_common.h b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi_common.h new file mode 100644 index 000000000..43fb83b48 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffi_common.h @@ -0,0 +1,77 @@ +/* ----------------------------------------------------------------------- + ffi_common.h - Copyright (c) 1996 Red Hat, Inc. + + Common internal definitions and macros. Only necessary for building + libffi. + ----------------------------------------------------------------------- */ + +#ifndef FFI_COMMON_H +#define FFI_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <fficonfig.h> +#include <malloc.h> + +/* Check for the existence of memcpy. */ +#if STDC_HEADERS +# include <string.h> +#else +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +#if defined(FFI_DEBUG) +#include <stdio.h> +#endif + +#ifdef FFI_DEBUG +/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); +void ffi_stop_here(void); +void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); + +#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) +#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) +#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) +#else +#define FFI_ASSERT(x) +#define FFI_ASSERT_AT(x, f, l) +#define FFI_ASSERT_VALID_TYPE(x) +#endif + +#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) + +/* Perform machine dependent cif processing */ +ffi_status ffi_prep_cif_machdep(ffi_cif *cif); + +/* Extended cif, used in callback from assembly routine */ +typedef struct +{ + /*@dependent@*/ ffi_cif *cif; + /*@dependent@*/ void *rvalue; + /*@dependent@*/ void **avalue; +} extended_cif; + +/* Terse sized type definitions. */ +typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); +typedef signed int SINT8 __attribute__((__mode__(__QI__))); +typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); +typedef signed int SINT16 __attribute__((__mode__(__HI__))); +typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); +typedef signed int SINT32 __attribute__((__mode__(__SI__))); +typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); +typedef signed int SINT64 __attribute__((__mode__(__DI__))); + +typedef float FLOAT32; + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/fficonfig.h b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/fficonfig.h new file mode 100644 index 000000000..c14f653ec --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/fficonfig.h @@ -0,0 +1,96 @@ +/* fficonfig.h. Originally created by configure, now hand_maintained for MSVC. */ + +/* fficonfig.h. Generated automatically by configure. */ +/* fficonfig.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define this for MSVC, but not for mingw32! */ +#ifdef _MSC_VER +#define __attribute__(x) /* */ +#endif +#define alloca _alloca + +/*----------------------------------------------------------------*/ + +/* Define if using alloca.c. */ +/* #undef C_ALLOCA */ + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +/* #undef CRAY_STACKSEG_END */ + +/* Define if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ +/* #define HAVE_ALLOCA_H 1 */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +/* #undef STACK_DIRECTION */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you have the memcpy function. */ +#define HAVE_MEMCPY 1 + +/* Define if read-only mmap of a plain file works. */ +//#define HAVE_MMAP_FILE 1 + +/* Define if mmap of /dev/zero works. */ +//#define HAVE_MMAP_DEV_ZERO 1 + +/* Define if mmap with MAP_ANON(YMOUS) works. */ +//#define HAVE_MMAP_ANON 1 + +/* The number of bytes in type double */ +#define SIZEOF_DOUBLE 8 + +/* The number of bytes in type long double */ +#define SIZEOF_LONG_DOUBLE 12 + +/* Define if you have the long double type and it is bigger than a double */ +#define HAVE_LONG_DOUBLE 1 + +/* whether byteorder is bigendian */ +/* #undef WORDS_BIGENDIAN */ + +/* Define if the host machine stores words of multi-word integers in + big-endian order. */ +/* #undef HOST_WORDS_BIG_ENDIAN */ + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 1234 + +/* Define if your assembler and linker support unaligned PC relative relocs. */ +/* #undef HAVE_AS_SPARC_UA_PCREL */ + +/* Define if your assembler supports .register. */ +/* #undef HAVE_AS_REGISTER_PSEUDO_OP */ + +/* Define if .eh_frame sections should be read-only. */ +/* #undef HAVE_RO_EH_FRAME */ + +/* Define to the flags needed for the .section .eh_frame directive. */ +/* #define EH_FRAME_FLAGS "aw" */ + +/* Define to the flags needed for the .section .eh_frame directive. */ +/* #define EH_FRAME_FLAGS "aw" */ + +/* Define this if you want extra debugging. */ +/* #undef FFI_DEBUG */ + +/* Define this is you do not want support for aggregate types. */ +/* #undef FFI_NO_STRUCTS */ + +/* Define this is you do not want support for the raw API. */ +/* #undef FFI_NO_RAW_API */ + +/* Define this if you are using Purify and want to suppress spurious messages. */ +/* #undef USING_PURIFY */ + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffitarget.h b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffitarget.h new file mode 100644 index 000000000..78c0c37ca --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/ffitarget.h @@ -0,0 +1,79 @@ +/* -----------------------------------------------------------------*-C-*- + ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. + Target configuration macros for x86 and x86-64. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + ----------------------------------------------------------------------- */ + +#ifndef LIBFFI_TARGET_H +#define LIBFFI_TARGET_H + +/* ---- System specific configurations ----------------------------------- */ + +#if defined (X86_64) && defined (__i386__) +#undef X86_64 +#define X86 +#endif + +/* ---- Generic type definitions ----------------------------------------- */ + +#ifndef LIBFFI_ASM +typedef unsigned long ffi_arg; +typedef signed long ffi_sarg; + +typedef enum ffi_abi { + FFI_FIRST_ABI = 0, + + /* ---- Intel x86 Win32 ---------- */ + FFI_SYSV, + FFI_STDCALL, + /* TODO: Add fastcall support for the sake of completeness */ + FFI_DEFAULT_ABI = FFI_SYSV, + + /* ---- Intel x86 and AMD x86-64 - */ +/* #if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__)) */ +/* FFI_SYSV, */ +/* FFI_UNIX64,*/ /* Unix variants all use the same ABI for x86-64 */ +/* #ifdef __i386__ */ +/* FFI_DEFAULT_ABI = FFI_SYSV, */ +/* #else */ +/* FFI_DEFAULT_ABI = FFI_UNIX64, */ +/* #endif */ +/* #endif */ + + FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 +} ffi_abi; +#endif + +/* ---- Definitions for closures ----------------------------------------- */ + +#define FFI_CLOSURES 1 + +#ifdef X86_64 +#define FFI_TRAMPOLINE_SIZE 24 +#define FFI_NATIVE_RAW_API 0 +#else +#define FFI_TRAMPOLINE_SIZE 15 +#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ +#endif + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/prep_cif.c b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/prep_cif.c new file mode 100644 index 000000000..2650fa052 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/prep_cif.c @@ -0,0 +1,175 @@ +/* ----------------------------------------------------------------------- + prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> +#include <stdlib.h> + + +/* Round up to FFI_SIZEOF_ARG. */ + +#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) + +/* Perform machine independent initialization of aggregate type + specifications. */ + +static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) +{ + ffi_type **ptr; + + FFI_ASSERT(arg != NULL); + + /*@-usedef@*/ + + FFI_ASSERT(arg->elements != NULL); + FFI_ASSERT(arg->size == 0); + FFI_ASSERT(arg->alignment == 0); + + ptr = &(arg->elements[0]); + + while ((*ptr) != NULL) + { + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type */ + FFI_ASSERT_VALID_TYPE(*ptr); + + arg->size = ALIGN(arg->size, (*ptr)->alignment); + arg->size += (*ptr)->size; + + arg->alignment = (arg->alignment > (*ptr)->alignment) ? + arg->alignment : (*ptr)->alignment; + + ptr++; + } + + /* Structure size includes tail padding. This is important for + structures that fit in one register on ABIs like the PowerPC64 + Linux ABI that right justify small structs in a register. + It's also needed for nested structure layout, for example + struct A { long a; char b; }; struct B { struct A x; char y; }; + should find y at an offset of 2*sizeof(long) and result in a + total size of 3*sizeof(long). */ + arg->size = ALIGN (arg->size, arg->alignment); + + if (arg->size == 0) + return FFI_BAD_TYPEDEF; + else + return FFI_OK; + + /*@=usedef@*/ +} + +/* Perform machine independent ffi_cif preparation, then call + machine dependent routine. */ + +ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, + ffi_abi abi, unsigned int nargs, + /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, + /*@dependent@*/ ffi_type **atypes) +{ + unsigned bytes = 0; + unsigned int i; + ffi_type **ptr; + + FFI_ASSERT(cif != NULL); + FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); + + cif->abi = abi; + cif->arg_types = atypes; + cif->nargs = nargs; + cif->rtype = rtype; + + cif->flags = 0; + + /* Initialize the return type if necessary */ + /*@-usedef@*/ + if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) + return FFI_BAD_TYPEDEF; + /*@=usedef@*/ + + /* Perform a sanity check on the return type */ + FFI_ASSERT_VALID_TYPE(cif->rtype); + + /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ +#if !defined M68K && !defined __x86_64__ && !defined S390 + /* Make space for the return structure pointer */ + if (cif->rtype->type == FFI_TYPE_STRUCT + /* MSVC returns small structures in registers. But we have a different + workaround: pretend int32 or int64 return type, and converting to + structure afterwards. */ +#ifdef SPARC + && (cif->abi != FFI_V9 || cif->rtype->size > 32) +#endif + ) + bytes = STACK_ARG_SIZE(sizeof(void*)); +#endif + + for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) + { + + /* Initialize any uninitialized aggregate type definitions */ + if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) + return FFI_BAD_TYPEDEF; + + /* Perform a sanity check on the argument type, do this + check after the initialization. */ + FFI_ASSERT_VALID_TYPE(*ptr); + +#if !defined __x86_64__ && !defined S390 +#ifdef SPARC + if (((*ptr)->type == FFI_TYPE_STRUCT + && ((*ptr)->size > 16 || cif->abi != FFI_V9)) + || ((*ptr)->type == FFI_TYPE_LONGDOUBLE + && cif->abi != FFI_V9)) + bytes += sizeof(void*); + else +#endif + { +#if !defined(_MSC_VER) && !defined(__MINGW32__) + /* Don't know if this is a libffi bug or not. At least on + Windows with MSVC, function call parameters are *not* + aligned in the same way as structure fields are, they are + only aligned in integer boundaries. + + This doesn't do any harm for cdecl functions and closures, + since the caller cleans up the stack, but it is wrong for + stdcall functions where the callee cleans. + */ + + /* Add any padding if necessary */ + if (((*ptr)->alignment - 1) & bytes) + bytes = ALIGN(bytes, (*ptr)->alignment); + +#endif + bytes += STACK_ARG_SIZE((*ptr)->size); + } +#endif + } + + cif->bytes = bytes; + + /* Perform machine dependent cif processing */ + return ffi_prep_cif_machdep(cif); +} diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/types.c b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/types.c new file mode 100644 index 000000000..df32190d1 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/types.c @@ -0,0 +1,104 @@ +/* ----------------------------------------------------------------------- + types.c - Copyright (c) 1996, 1998 Red Hat, Inc. + + Predefined ffi_types needed by libffi. + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#include <ffi.h> +#include <ffi_common.h> + +/* Type definitions */ + +#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL } +#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e } + +/* Size and alignment are fake here. They must not be 0. */ +FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID); + +FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8); +FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8); +FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); +FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); +FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); +FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); +FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); + +#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ + || defined IA64 + +FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); + +#else + +FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); + +#endif + +#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K + +FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); + +#elif defined SH + +FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); + +#else + +FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); +FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); + +#endif + + +#if defined X86 || defined X86_WIN32 || defined M68K + +FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); + +#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN + +FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); + +#elif defined SPARC + +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +#ifdef SPARC64 +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); +#else +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); +#endif + +#elif defined X86_64 + +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); + +#else + +FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); +FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); + +#endif + diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.S b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.S new file mode 100644 index 000000000..cc82ab91e --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.S @@ -0,0 +1,243 @@ +/* ----------------------------------------------------------------------- + win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. + Copyright (c) 2001 John Beniton + Copyright (c) 2002 Ranjit Mathew + + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +#define LIBFFI_ASM +#include <fficonfig.h> +#include <ffi.h> + +.text + +.globl ffi_prep_args + + # This assumes we are using gas. + .balign 16 +.globl _ffi_call_SYSV + +_ffi_call_SYSV: + pushl %ebp + movl %esp,%ebp + + #THe: save previous %esi, and store the current stack pointer in %esi + pushl %esi + movl %esp,%esi + + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + # FIXME: Align the stack to a 128-bit boundary to avoid + # potential performance hits. + + call *28(%ebp) + + # Remove the space we pushed for the args + movl 16(%ebp),%ecx + addl %ecx,%esp + + sub %esp,%esi # calculate stack pointer difference + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne retint + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne noretval + fstp %st(0) + + jmp epilogue + +retint: + cmpl $FFI_TYPE_INT,%ecx + jne retfloat + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp epilogue + +retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne retdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp epilogue + +retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne retlongdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp epilogue + +retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne retint64 + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp epilogue + +retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne retstruct + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +retstruct: + # Nothing to do! + +noretval: +epilogue: + movl %esi,%eax # return the stack pointer detlta in %eax + popl %esi # restore previous %esi + movl %ebp,%esp + popl %ebp + ret + +.ffi_call_SYSV_end: + + # This assumes we are using gas. + .balign 16 +.globl _ffi_call_STDCALL + +_ffi_call_STDCALL: + pushl %ebp + movl %esp,%ebp + + #THe: save previous %esi, and store the current stack pointer in %esi + pushl %esi + movl %esp,%esi + + # Make room for all of the new args. + movl 16(%ebp),%ecx + subl %ecx,%esp + + movl %esp,%eax + + # Place all of the ffi_prep_args in position + pushl 12(%ebp) + pushl %eax + call *8(%ebp) + + # Return stack to previous state and call the function + addl $8,%esp + + # FIXME: Align the stack to a 128-bit boundary to avoid + # potential performance hits. + + call *28(%ebp) + + sub %esp,%esi # difference in stack + + # stdcall functions pop arguments off the stack themselves + + # Load %ecx with the return type code + movl 20(%ebp),%ecx + + # If the return value pointer is NULL, assume no return value. + cmpl $0,24(%ebp) + jne sc_retint + + # Even if there is no space for the return value, we are + # obliged to handle floating-point values. + cmpl $FFI_TYPE_FLOAT,%ecx + jne sc_noretval + fstp %st(0) + + jmp sc_epilogue + +sc_retint: + cmpl $FFI_TYPE_INT,%ecx + jne sc_retfloat + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + jmp sc_epilogue + +sc_retfloat: + cmpl $FFI_TYPE_FLOAT,%ecx + jne sc_retdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstps (%ecx) + jmp sc_epilogue + +sc_retdouble: + cmpl $FFI_TYPE_DOUBLE,%ecx + jne sc_retlongdouble + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpl (%ecx) + jmp sc_epilogue + +sc_retlongdouble: + cmpl $FFI_TYPE_LONGDOUBLE,%ecx + jne sc_retint64 + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + fstpt (%ecx) + jmp sc_epilogue + +sc_retint64: + cmpl $FFI_TYPE_SINT64,%ecx + jne sc_retstruct + # Load %ecx with the pointer to storage for the return value + movl 24(%ebp),%ecx + movl %eax,0(%ecx) + movl %edx,4(%ecx) + +sc_retstruct: + # Nothing to do! + +sc_noretval: +sc_epilogue: + movl %esi,%eax # return the stack difference + popl %esi # restore previous %esi value + movl %ebp,%esp + popl %ebp + ret + +.ffi_call_STDCALL_end: diff --git a/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.c b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.c new file mode 100644 index 000000000..0670c8ccf --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/libffi_msvc/win32.c @@ -0,0 +1,267 @@ +/* ----------------------------------------------------------------------- + win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. + Copyright (c) 2001 John Beniton + Copyright (c) 2002 Ranjit Mathew + + + X86 Foreign Function Interface + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + ``Software''), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ----------------------------------------------------------------------- */ + +/* theller: almost verbatim translation from gas syntax to MSVC inline + assembler code. */ + +/* theller: ffi_call_SYSV and ffi_call_STDCALL now return an integer - the + difference of the stack pointer before and after the function call. If + everything is ok, zero is returned. If stdcall functions are passed the + wrong number of arguments, the difference will be nonzero. */ + +#include <ffi.h> +#include <ffi_common.h> + +__declspec(naked) int +ffi_call_SYSV(void (* prepfunc)(char *, extended_cif *), /* 8 */ + extended_cif *ecif, /* 12 */ + unsigned bytes, /* 16 */ + unsigned flags, /* 20 */ + unsigned *rvalue, /* 24 */ + void (*fn)()) /* 28 */ +{ + _asm { + push ebp + mov ebp, esp + + push esi // NEW: this register must be preserved across function calls +// XXX SAVE ESP NOW! + mov esi, esp // save stack pointer before the call + +// Make room for all of the new args. + mov ecx, [ebp+16] + sub esp, ecx // sub esp, bytes + + mov eax, esp + +// Place all of the ffi_prep_args in position + push [ebp + 12] // ecif + push eax + call [ebp + 8] // prepfunc + +// Return stack to previous state and call the function + add esp, 8 +// FIXME: Align the stack to a 128-bit boundary to avoid +// potential performance hits. + call [ebp + 28] +// Remove the space we pushed for the args + mov ecx, [ebp + 16] + add esp, ecx + +// XXX ASSERT THAT ESP IS THE SAME NOW THAN BEFORE! + sub esi, esp + +// Load %ecx with the return type code + mov ecx, [ebp + 20] + +// If the return value pointer is NULL, assume no return value. +/* + Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, + otherwise only one BYTE will be compared (instead of a DWORD)! + */ + cmp DWORD PTR [ebp + 24], 0 + jne sc_retint + +// Even if there is no space for the return value, we are +// obliged to handle floating-point values. + cmp ecx, FFI_TYPE_FLOAT + jne sc_noretval +// fstp %st(0) + fstp st(0) + + jmp sc_epilogue + +sc_retint: + cmp ecx, FFI_TYPE_INT + jne sc_retfloat +// # Load %ecx with the pointer to storage for the return value + mov ecx, [ebp + 24] + mov [ecx + 0], eax + jmp sc_epilogue + +sc_retfloat: + cmp ecx, FFI_TYPE_FLOAT + jne sc_retdouble +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] +// fstps (%ecx) + fstp DWORD PTR [ecx] + jmp sc_epilogue + +sc_retdouble: + cmp ecx, FFI_TYPE_DOUBLE + jne sc_retlongdouble +// movl 24(%ebp),%ecx + mov ecx, [ebp+24] + fstp QWORD PTR [ecx] + jmp sc_epilogue + + jmp sc_retlongdouble // avoid warning about unused label +sc_retlongdouble: + cmp ecx, FFI_TYPE_LONGDOUBLE + jne sc_retint64 +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] +// fstpt (%ecx) + fstp QWORD PTR [ecx] /* XXX ??? */ + jmp sc_epilogue + +sc_retint64: + cmp ecx, FFI_TYPE_SINT64 + jne sc_retstruct +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] + mov [ecx+0], eax + mov [ecx+4], edx + +sc_retstruct: +// Nothing to do! + +sc_noretval: +sc_epilogue: + mov eax, esi + pop esi // NEW restore: must be preserved across function calls + mov esp, ebp + pop ebp + ret + } +} + +__declspec(naked) int +ffi_call_STDCALL(void (* prepfunc)(char *, extended_cif *), /* 8 */ + extended_cif *ecif, /* 12 */ + unsigned bytes, /* 16 */ + unsigned flags, /* 20 */ + unsigned *rvalue, /* 24 */ + void (*fn)()) /* 28 */ +{ + _asm { + push ebp + mov ebp, esp + + push esi // NEW: this register must be preserved across function calls + +// XXX SAVE ESP NOW! + mov esi, esp + +// Make room for all of the new args. + mov ecx, [ebp+16] + sub esp, ecx + + mov eax, esp + +// Place all of the ffi_prep_args in position + push [ebp + 12] // ecif + push eax + call [ebp + 8] // prepfunc + +// Return stack to previous state and call the function + add esp, 8 +// FIXME: Align the stack to a 128-bit boundary to avoid +// potential performance hits. + call [ebp + 28] +// stdcall functions pop arguments off the stack themselves + +// XXX IS ESP NOW THE SAME AS BEFORE? + sub esi, esp + +// Load %ecx with the return type code + mov ecx, [ebp + 20] + +// If the return value pointer is NULL, assume no return value. +/* + Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, + otherwise only one BYTE will be compared (instead of a DWORD)! + */ + cmp DWORD PTR [ebp + 24], 0 + jne sc_retint + +// Even if there is no space for the return value, we are +// obliged to handle floating-point values. + cmp ecx, FFI_TYPE_FLOAT + jne sc_noretval +// fstp %st(0) + fstp st(0) + + jmp sc_epilogue + +sc_retint: + cmp ecx, FFI_TYPE_INT + jne sc_retfloat +// # Load %ecx with the pointer to storage for the return value + mov ecx, [ebp + 24] + mov [ecx + 0], eax + jmp sc_epilogue + +sc_retfloat: + cmp ecx, FFI_TYPE_FLOAT + jne sc_retdouble +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] +// fstps (%ecx) + fstp DWORD PTR [ecx] + jmp sc_epilogue + +sc_retdouble: + cmp ecx, FFI_TYPE_DOUBLE + jne sc_retlongdouble +// movl 24(%ebp),%ecx + mov ecx, [ebp+24] + fstp QWORD PTR [ecx] + jmp sc_epilogue + + jmp sc_retlongdouble // avoid warning about unused label +sc_retlongdouble: + cmp ecx, FFI_TYPE_LONGDOUBLE + jne sc_retint64 +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] +// fstpt (%ecx) + fstp QWORD PTR [ecx] /* XXX ??? */ + jmp sc_epilogue + +sc_retint64: + cmp ecx, FFI_TYPE_SINT64 + jne sc_retstruct +// Load %ecx with the pointer to storage for the return value + mov ecx, [ebp+24] + mov [ecx+0], eax + mov [ecx+4], edx + +sc_retstruct: +// Nothing to do! + +sc_noretval: +sc_epilogue: + mov eax, esi + pop esi // NEW restore: must be preserved across function calls + mov esp, ebp + pop ebp + ret + } +} diff --git a/sys/src/cmd/python/Modules/_ctypes/malloc_closure.c b/sys/src/cmd/python/Modules/_ctypes/malloc_closure.c new file mode 100644 index 000000000..4cd5dd6f5 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/malloc_closure.c @@ -0,0 +1,110 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + +#include <Python.h> +#include <ffi.h> +#ifdef MS_WIN32 +#include <windows.h> +#else +#include <sys/mman.h> +#include <unistd.h> +# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +# endif +#endif +#include "ctypes.h" + +/* BLOCKSIZE can be adjusted. Larger blocksize will take a larger memory + overhead, but allocate less blocks from the system. It may be that some + systems have a limit of how many mmap'd blocks can be open. +*/ + +#define BLOCKSIZE _pagesize + +/* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */ + +/******************************************************************/ + +typedef union _tagITEM { + ffi_closure closure; + union _tagITEM *next; +} ITEM; + +static ITEM *free_list; +int _pagesize; + +static void more_core(void) +{ + ITEM *item; + int count, i; + +/* determine the pagesize */ +#ifdef MS_WIN32 + if (!_pagesize) { + SYSTEM_INFO systeminfo; + GetSystemInfo(&systeminfo); + _pagesize = systeminfo.dwPageSize; + } +#else + if (!_pagesize) { + _pagesize = getpagesize(); + } +#endif + + /* calculate the number of nodes to allocate */ + count = BLOCKSIZE / sizeof(ITEM); + + /* allocate a memory block */ +#ifdef MS_WIN32 + item = (ITEM *)VirtualAlloc(NULL, + count * sizeof(ITEM), + MEM_COMMIT, + PAGE_EXECUTE_READWRITE); + if (item == NULL) + return; +#else + item = (ITEM *)mmap(NULL, + count * sizeof(ITEM), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, + 0); + if (item == (void *)MAP_FAILED) + return; +#endif + +#ifdef MALLOC_CLOSURE_DEBUG + printf("block at %p allocated (%d bytes), %d ITEMs\n", + item, count * sizeof(ITEM), count); +#endif + /* put them into the free list */ + for (i = 0; i < count; ++i) { + item->next = free_list; + free_list = item; + ++item; + } +} + +/******************************************************************/ + +/* put the item back into the free list */ +void FreeClosure(void *p) +{ + ITEM *item = (ITEM *)p; + item->next = free_list; + free_list = item; +} + +/* return one item from the free list, allocating more if needed */ +void *MallocClosure(void) +{ + ITEM *item; + if (!free_list) + more_core(); + if (!free_list) + return NULL; + item = free_list; + free_list = item->next; + return item; +} diff --git a/sys/src/cmd/python/Modules/_ctypes/stgdict.c b/sys/src/cmd/python/Modules/_ctypes/stgdict.c new file mode 100644 index 000000000..8fd9a1e57 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ctypes/stgdict.c @@ -0,0 +1,494 @@ +/***************************************************************** + This file should be kept compatible with Python 2.3, see PEP 291. + *****************************************************************/ + +#include "Python.h" +#include <ffi.h> +#ifdef MS_WIN32 +#include <windows.h> +#endif +#include "ctypes.h" + +/******************************************************************/ +/* + StdDict - a dictionary subclass, containing additional C accessible fields + + XXX blabla more +*/ + +/* Seems we need this, otherwise we get problems when calling + * PyDict_SetItem() (ma_lookup is NULL) + */ +static int +StgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds) +{ + if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + return 0; +} + +static int +StgDict_clear(StgDictObject *self) +{ + Py_CLEAR(self->proto); + Py_CLEAR(self->argtypes); + Py_CLEAR(self->converters); + Py_CLEAR(self->restype); + Py_CLEAR(self->checker); + return 0; +} + +static void +StgDict_dealloc(StgDictObject *self) +{ + StgDict_clear(self); + PyMem_Free(self->ffi_type_pointer.elements); + PyDict_Type.tp_dealloc((PyObject *)self); +} + +int +StgDict_clone(StgDictObject *dst, StgDictObject *src) +{ + char *d, *s; + int size; + + StgDict_clear(dst); + PyMem_Free(dst->ffi_type_pointer.elements); + dst->ffi_type_pointer.elements = NULL; + + d = (char *)dst; + s = (char *)src; + memcpy(d + sizeof(PyDictObject), + s + sizeof(PyDictObject), + sizeof(StgDictObject) - sizeof(PyDictObject)); + + Py_XINCREF(dst->proto); + Py_XINCREF(dst->argtypes); + Py_XINCREF(dst->converters); + Py_XINCREF(dst->restype); + Py_XINCREF(dst->checker); + + if (src->ffi_type_pointer.elements == NULL) + return 0; + size = sizeof(ffi_type *) * (src->length + 1); + dst->ffi_type_pointer.elements = PyMem_Malloc(size); + if (dst->ffi_type_pointer.elements == NULL) + return -1; + memcpy(dst->ffi_type_pointer.elements, + src->ffi_type_pointer.elements, + size); + return 0; +} + +PyTypeObject StgDict_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "StgDict", + sizeof(StgDictObject), + 0, + (destructor)StgDict_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)StgDict_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ +}; + +/* May return NULL, but does not set an exception! */ +StgDictObject * +PyType_stgdict(PyObject *obj) +{ + PyTypeObject *type; + + if (!PyType_Check(obj)) + return NULL; + type = (PyTypeObject *)obj; + if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS)) + return NULL; + if (!type->tp_dict || !StgDict_CheckExact(type->tp_dict)) + return NULL; + return (StgDictObject *)type->tp_dict; +} + +/* May return NULL, but does not set an exception! */ +/* + This function should be as fast as possible, so we don't call PyType_stgdict + above but inline the code, and avoid the PyType_Check(). +*/ +StgDictObject * +PyObject_stgdict(PyObject *self) +{ + PyTypeObject *type = self->ob_type; + if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS)) + return NULL; + if (!type->tp_dict || !StgDict_CheckExact(type->tp_dict)) + return NULL; + return (StgDictObject *)type->tp_dict; +} + +/* descr is the descriptor for a field marked as anonymous. Get all the + _fields_ descriptors from descr->proto, create new descriptors with offset + and index adjusted, and stuff them into type. + */ +static int +MakeFields(PyObject *type, CFieldObject *descr, + Py_ssize_t index, Py_ssize_t offset) +{ + Py_ssize_t i; + PyObject *fields; + PyObject *fieldlist; + + fields = PyObject_GetAttrString(descr->proto, "_fields_"); + if (fields == NULL) + return -1; + fieldlist = PySequence_Fast(fields, "_fields_ must be a sequence"); + Py_DECREF(fields); + if (fieldlist == NULL) + return -1; + + for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) { + PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */ + PyObject *fname, *ftype, *bits; + CFieldObject *fdescr; + CFieldObject *new_descr; + /* Convert to PyArg_UnpackTuple... */ + if (!PyArg_ParseTuple(pair, "OO|O", &fname, &ftype, &bits)) { + Py_DECREF(fieldlist); + return -1; + } + fdescr = (CFieldObject *)PyObject_GetAttr(descr->proto, fname); + if (fdescr == NULL) { + Py_DECREF(fieldlist); + return -1; + } + if (fdescr->ob_type != &CField_Type) { + PyErr_SetString(PyExc_TypeError, "unexpected type"); + Py_DECREF(fdescr); + Py_DECREF(fieldlist); + return -1; + } + if (fdescr->anonymous) { + int rc = MakeFields(type, fdescr, + index + fdescr->index, + offset + fdescr->offset); + Py_DECREF(fdescr); + if (rc == -1) { + Py_DECREF(fieldlist); + return -1; + } + continue; + } + new_descr = (CFieldObject *)PyObject_CallObject((PyObject *)&CField_Type, NULL); + if (new_descr == NULL) { + Py_DECREF(fdescr); + Py_DECREF(fieldlist); + return -1; + } + assert(new_descr->ob_type == &CField_Type); + new_descr->size = fdescr->size; + new_descr->offset = fdescr->offset + offset; + new_descr->index = fdescr->index + index; + new_descr->proto = fdescr->proto; + Py_XINCREF(new_descr->proto); + new_descr->getfunc = fdescr->getfunc; + new_descr->setfunc = fdescr->setfunc; + + Py_DECREF(fdescr); + + if (-1 == PyObject_SetAttr(type, fname, (PyObject *)new_descr)) { + Py_DECREF(fieldlist); + Py_DECREF(new_descr); + return -1; + } + Py_DECREF(new_descr); + } + Py_DECREF(fieldlist); + return 0; +} + +/* Iterate over the names in the type's _anonymous_ attribute, if present, + */ +static int +MakeAnonFields(PyObject *type) +{ + PyObject *anon; + PyObject *anon_names; + Py_ssize_t i; + + anon = PyObject_GetAttrString(type, "_anonymous_"); + if (anon == NULL) { + PyErr_Clear(); + return 0; + } + anon_names = PySequence_Fast(anon, "_anonymous_ must be a sequence"); + Py_DECREF(anon); + if (anon_names == NULL) + return -1; + + for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) { + PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */ + CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname); + if (descr == NULL) { + Py_DECREF(anon_names); + return -1; + } + assert(descr->ob_type == &CField_Type); + descr->anonymous = 1; + + /* descr is in the field descriptor. */ + if (-1 == MakeFields(type, (CFieldObject *)descr, + ((CFieldObject *)descr)->index, + ((CFieldObject *)descr)->offset)) { + Py_DECREF(descr); + Py_DECREF(anon_names); + return -1; + } + Py_DECREF(descr); + } + + Py_DECREF(anon_names); + return 0; +} + +/* + Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute, + and create an StgDictObject. Used for Structure and Union subclasses. +*/ +int +StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) +{ + StgDictObject *stgdict, *basedict; + int len, offset, size, align, i; + int union_size, total_align; + int field_size = 0; + int bitofs; + PyObject *isPacked; + int pack = 0; + int ffi_ofs; + int big_endian; + + /* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to + be a way to use the old, broken sematics: _fields_ are not extended + but replaced in subclasses. + + XXX Remove this in ctypes 1.0! + */ + int use_broken_old_ctypes_semantics; + + if (fields == NULL) + return 0; + +#ifdef WORDS_BIGENDIAN + big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 0 : 1; +#else + big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 1 : 0; +#endif + + use_broken_old_ctypes_semantics = \ + PyObject_HasAttrString(type, "_use_broken_old_ctypes_structure_semantics_"); + + isPacked = PyObject_GetAttrString(type, "_pack_"); + if (isPacked) { + pack = PyInt_AsLong(isPacked); + if (pack < 0 || PyErr_Occurred()) { + Py_XDECREF(isPacked); + PyErr_SetString(PyExc_ValueError, + "_pack_ must be a non-negative integer"); + return -1; + } + Py_DECREF(isPacked); + } else + PyErr_Clear(); + + len = PySequence_Length(fields); + if (len == -1) { + PyErr_SetString(PyExc_TypeError, + "'_fields_' must be a sequence of pairs"); + return -1; + } + + stgdict = PyType_stgdict(type); + if (!stgdict) + return -1; + /* If this structure/union is already marked final we cannot assign + _fields_ anymore. */ + + if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */ + PyErr_SetString(PyExc_AttributeError, + "_fields_ is final"); + return -1; + } + + if (stgdict->ffi_type_pointer.elements) + PyMem_Free(stgdict->ffi_type_pointer.elements); + + basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base); + if (basedict && !use_broken_old_ctypes_semantics) { + size = offset = basedict->size; + align = basedict->align; + union_size = 0; + total_align = align ? align : 1; + stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; + stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); + memset(stgdict->ffi_type_pointer.elements, 0, + sizeof(ffi_type *) * (basedict->length + len + 1)); + memcpy(stgdict->ffi_type_pointer.elements, + basedict->ffi_type_pointer.elements, + sizeof(ffi_type *) * (basedict->length)); + ffi_ofs = basedict->length; + } else { + offset = 0; + size = 0; + align = 0; + union_size = 0; + total_align = 1; + stgdict->ffi_type_pointer.type = FFI_TYPE_STRUCT; + stgdict->ffi_type_pointer.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); + memset(stgdict->ffi_type_pointer.elements, 0, + sizeof(ffi_type *) * (len + 1)); + ffi_ofs = 0; + } + +#define realdict ((PyObject *)&stgdict->dict) + for (i = 0; i < len; ++i) { + PyObject *name = NULL, *desc = NULL; + PyObject *pair = PySequence_GetItem(fields, i); + PyObject *prop; + StgDictObject *dict; + int bitsize = 0; + + if (!pair || !PyArg_ParseTuple(pair, "OO|i", &name, &desc, &bitsize)) { + PyErr_SetString(PyExc_AttributeError, + "'_fields_' must be a sequence of pairs"); + Py_XDECREF(pair); + return -1; + } + dict = PyType_stgdict(desc); + if (dict == NULL) { + Py_DECREF(pair); + PyErr_Format(PyExc_TypeError, + "second item in _fields_ tuple (index %d) must be a C type", + i); + return -1; + } + stgdict->ffi_type_pointer.elements[ffi_ofs + i] = &dict->ffi_type_pointer; + dict->flags |= DICTFLAG_FINAL; /* mark field type final */ + if (PyTuple_Size(pair) == 3) { /* bits specified */ + switch(dict->ffi_type_pointer.type) { + case FFI_TYPE_UINT8: + case FFI_TYPE_UINT16: + case FFI_TYPE_UINT32: + case FFI_TYPE_SINT64: + case FFI_TYPE_UINT64: + break; + + case FFI_TYPE_SINT8: + case FFI_TYPE_SINT16: + case FFI_TYPE_SINT32: + if (dict->getfunc != getentry("c")->getfunc +#ifdef CTYPES_UNICODE + && dict->getfunc != getentry("u")->getfunc +#endif + ) + break; + /* else fall through */ + default: + PyErr_Format(PyExc_TypeError, + "bit fields not allowed for type %s", + ((PyTypeObject *)desc)->tp_name); + Py_DECREF(pair); + return -1; + } + if (bitsize <= 0 || bitsize > dict->size * 8) { + PyErr_SetString(PyExc_ValueError, + "number of bits invalid for bit field"); + Py_DECREF(pair); + return -1; + } + } else + bitsize = 0; + if (isStruct) { + prop = CField_FromDesc(desc, i, + &field_size, bitsize, &bitofs, + &size, &offset, &align, + pack, big_endian); + } else /* union */ { + size = 0; + offset = 0; + align = 0; + prop = CField_FromDesc(desc, i, + &field_size, bitsize, &bitofs, + &size, &offset, &align, + pack, big_endian); + union_size = max(size, union_size); + } + total_align = max(align, total_align); + + if (!prop) { + Py_DECREF(pair); + Py_DECREF((PyObject *)stgdict); + return -1; + } + if (-1 == PyDict_SetItem(realdict, name, prop)) { + Py_DECREF(prop); + Py_DECREF(pair); + Py_DECREF((PyObject *)stgdict); + return -1; + } + Py_DECREF(pair); + Py_DECREF(prop); + } +#undef realdict + if (!isStruct) + size = union_size; + + /* Adjust the size according to the alignment requirements */ + size = ((size + total_align - 1) / total_align) * total_align; + + stgdict->ffi_type_pointer.alignment = total_align; + stgdict->ffi_type_pointer.size = size; + + stgdict->size = size; + stgdict->align = total_align; + stgdict->length = len; /* ADD ffi_ofs? */ + + /* We did check that this flag was NOT set above, it must not + have been set until now. */ + if (stgdict->flags & DICTFLAG_FINAL) { + PyErr_SetString(PyExc_AttributeError, + "Structure or union cannot contain itself"); + return -1; + } + stgdict->flags |= DICTFLAG_FINAL; + + return MakeAnonFields(type); +} diff --git a/sys/src/cmd/python/Modules/_curses_panel.c b/sys/src/cmd/python/Modules/_curses_panel.c new file mode 100644 index 000000000..0acf3fdee --- /dev/null +++ b/sys/src/cmd/python/Modules/_curses_panel.c @@ -0,0 +1,480 @@ +/* + * Interface to the ncurses panel library + * + * Original version by Thomas Gellekum + */ + +/* Release Number */ + +static char *PyCursesVersion = "2.1"; + +/* Includes */ + +#include "Python.h" + +#include "py_curses.h" + +#include <panel.h> + +static PyObject *PyCursesError; + + +/* Utility Functions */ + +/* + * Check the return code from a curses function and return None + * or raise an exception as appropriate. + */ + +static PyObject * +PyCursesCheckERR(int code, char *fname) +{ + if (code != ERR) { + Py_INCREF(Py_None); + return Py_None; + } else { + if (fname == NULL) { + PyErr_SetString(PyCursesError, catchall_ERR); + } else { + PyErr_Format(PyCursesError, "%s() returned ERR", fname); + } + return NULL; + } +} + +/***************************************************************************** + The Panel Object +******************************************************************************/ + +/* Definition of the panel object and panel type */ + +typedef struct { + PyObject_HEAD + PANEL *pan; + PyCursesWindowObject *wo; /* for reference counts */ +} PyCursesPanelObject; + +PyTypeObject PyCursesPanel_Type; + +#define PyCursesPanel_Check(v) ((v)->ob_type == &PyCursesPanel_Type) + +/* Some helper functions. The problem is that there's always a window + associated with a panel. To ensure that Python's GC doesn't pull + this window from under our feet we need to keep track of references + to the corresponding window object within Python. We can't use + dupwin(oldwin) to keep a copy of the curses WINDOW because the + contents of oldwin is copied only once; code like + + win = newwin(...) + pan = win.panel() + win.addstr(some_string) + pan.window().addstr(other_string) + + will fail. */ + +/* We keep a linked list of PyCursesPanelObjects, lop. A list should + suffice, I don't expect more than a handful or at most a few + dozens of panel objects within a typical program. */ +typedef struct _list_of_panels { + PyCursesPanelObject *po; + struct _list_of_panels *next; +} list_of_panels; + +/* list anchor */ +static list_of_panels *lop; + +/* Insert a new panel object into lop */ +static int +insert_lop(PyCursesPanelObject *po) +{ + list_of_panels *new; + + if ((new = (list_of_panels *)malloc(sizeof(list_of_panels))) == NULL) { + PyErr_NoMemory(); + return -1; + } + new->po = po; + new->next = lop; + lop = new; + return 0; +} + +/* Remove the panel object from lop */ +static void +remove_lop(PyCursesPanelObject *po) +{ + list_of_panels *temp, *n; + + temp = lop; + if (temp->po == po) { + lop = temp->next; + free(temp); + return; + } + while (temp->next == NULL || temp->next->po != po) { + if (temp->next == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "remove_lop: can't find Panel Object"); + return; + } + temp = temp->next; + } + n = temp->next->next; + free(temp->next); + temp->next = n; + return; +} + +/* Return the panel object that corresponds to pan */ +static PyCursesPanelObject * +find_po(PANEL *pan) +{ + list_of_panels *temp; + for (temp = lop; temp->po->pan != pan; temp = temp->next) + if (temp->next == NULL) return NULL; /* not found!? */ + return temp->po; +} + +/* Function Prototype Macros - They are ugly but very, very useful. ;-) + + X - function name + TYPE - parameter Type + ERGSTR - format string for construction of the return value + PARSESTR - format string for argument parsing */ + +#define Panel_NoArgNoReturnFunction(X) \ +static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self) \ +{ return PyCursesCheckERR(X(self->pan), # X); } + +#define Panel_NoArgTrueFalseFunction(X) \ +static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self) \ +{ \ + if (X (self->pan) == FALSE) { Py_INCREF(Py_False); return Py_False; } \ + else { Py_INCREF(Py_True); return Py_True; } } + +#define Panel_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ +static PyObject *PyCursesPanel_##X(PyCursesPanelObject *self, PyObject *args) \ +{ \ + TYPE arg1, arg2; \ + if (!PyArg_ParseTuple(args, PARSESTR, &arg1, &arg2)) return NULL; \ + return PyCursesCheckERR(X(self->pan, arg1, arg2), # X); } + +/* ------------- PANEL routines --------------- */ + +Panel_NoArgNoReturnFunction(bottom_panel) +Panel_NoArgNoReturnFunction(hide_panel) +Panel_NoArgNoReturnFunction(show_panel) +Panel_NoArgNoReturnFunction(top_panel) +Panel_NoArgTrueFalseFunction(panel_hidden) +Panel_TwoArgNoReturnFunction(move_panel, int, "ii;y,x") + +/* Allocation and deallocation of Panel Objects */ + +static PyObject * +PyCursesPanel_New(PANEL *pan, PyCursesWindowObject *wo) +{ + PyCursesPanelObject *po; + + po = PyObject_NEW(PyCursesPanelObject, &PyCursesPanel_Type); + if (po == NULL) return NULL; + po->pan = pan; + po->wo = wo; + Py_INCREF(wo); + if (insert_lop(po) < 0) { + PyObject_DEL(po); + return NULL; + } + return (PyObject *)po; +} + +static void +PyCursesPanel_Dealloc(PyCursesPanelObject *po) +{ + (void)del_panel(po->pan); + Py_DECREF(po->wo); + remove_lop(po); + PyObject_DEL(po); +} + +/* panel_above(NULL) returns the bottom panel in the stack. To get + this behaviour we use curses.panel.bottom_panel(). */ +static PyObject * +PyCursesPanel_above(PyCursesPanelObject *self) +{ + PANEL *pan; + PyCursesPanelObject *po; + + pan = panel_above(self->pan); + + if (pan == NULL) { /* valid output, it means the calling panel + is on top of the stack */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_above: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +/* panel_below(NULL) returns the top panel in the stack. To get + this behaviour we use curses.panel.top_panel(). */ +static PyObject * +PyCursesPanel_below(PyCursesPanelObject *self) +{ + PANEL *pan; + PyCursesPanelObject *po; + + pan = panel_below(self->pan); + + if (pan == NULL) { /* valid output, it means the calling panel + is on the bottom of the stack */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_below: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +static PyObject * +PyCursesPanel_window(PyCursesPanelObject *self) +{ + Py_INCREF(self->wo); + return (PyObject *)self->wo; +} + +static PyObject * +PyCursesPanel_replace_panel(PyCursesPanelObject *self, PyObject *args) +{ + PyCursesPanelObject *po; + PyCursesWindowObject *temp; + int rtn; + + if (PyTuple_Size(args) != 1) { + PyErr_SetString(PyExc_TypeError, "replace requires one argument"); + return NULL; + } + if (!PyArg_ParseTuple(args, "O!;window object", + &PyCursesWindow_Type, &temp)) + return NULL; + + po = find_po(self->pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "replace_panel: can't find Panel Object"); + return NULL; + } + + rtn = replace_panel(self->pan, temp->win); + if (rtn == ERR) { + PyErr_SetString(PyCursesError, "replace_panel() returned ERR"); + return NULL; + } + Py_DECREF(po->wo); + po->wo = temp; + Py_INCREF(po->wo); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyCursesPanel_set_panel_userptr(PyCursesPanelObject *self, PyObject *obj) +{ + Py_INCREF(obj); + return PyCursesCheckERR(set_panel_userptr(self->pan, (void*)obj), + "set_panel_userptr"); +} + +static PyObject * +PyCursesPanel_userptr(PyCursesPanelObject *self) +{ + PyObject *obj; + PyCursesInitialised; + obj = (PyObject *) panel_userptr(self->pan); + if (obj == NULL) { + PyErr_SetString(PyCursesError, "no userptr set"); + return NULL; + } + + Py_INCREF(obj); + return obj; +} + + +/* Module interface */ + +static PyMethodDef PyCursesPanel_Methods[] = { + {"above", (PyCFunction)PyCursesPanel_above, METH_NOARGS}, + {"below", (PyCFunction)PyCursesPanel_below, METH_NOARGS}, + {"bottom", (PyCFunction)PyCursesPanel_bottom_panel, METH_NOARGS}, + {"hidden", (PyCFunction)PyCursesPanel_panel_hidden, METH_NOARGS}, + {"hide", (PyCFunction)PyCursesPanel_hide_panel, METH_NOARGS}, + {"move", (PyCFunction)PyCursesPanel_move_panel, METH_VARARGS}, + {"replace", (PyCFunction)PyCursesPanel_replace_panel, METH_VARARGS}, + {"set_userptr", (PyCFunction)PyCursesPanel_set_panel_userptr, METH_O}, + {"show", (PyCFunction)PyCursesPanel_show_panel, METH_NOARGS}, + {"top", (PyCFunction)PyCursesPanel_top_panel, METH_NOARGS}, + {"userptr", (PyCFunction)PyCursesPanel_userptr, METH_NOARGS}, + {"window", (PyCFunction)PyCursesPanel_window, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +PyCursesPanel_GetAttr(PyCursesPanelObject *self, char *name) +{ + return Py_FindMethod(PyCursesPanel_Methods, (PyObject *)self, name); +} + +/* -------------------------------------------------------*/ + +PyTypeObject PyCursesPanel_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_curses_panel.curses panel", /*tp_name*/ + sizeof(PyCursesPanelObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyCursesPanel_Dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)PyCursesPanel_GetAttr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +/* Wrapper for panel_above(NULL). This function returns the bottom + panel of the stack, so it's renamed to bottom_panel(). + panel.above() *requires* a panel object in the first place which + may be undesirable. */ +static PyObject * +PyCurses_bottom_panel(PyObject *self) +{ + PANEL *pan; + PyCursesPanelObject *po; + + PyCursesInitialised; + + pan = panel_above(NULL); + + if (pan == NULL) { /* valid output, it means + there's no panel at all */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_above: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +static PyObject * +PyCurses_new_panel(PyObject *self, PyObject *args) +{ + PyCursesWindowObject *win; + PANEL *pan; + + if (!PyArg_ParseTuple(args, "O!", &PyCursesWindow_Type, &win)) + return NULL; + pan = new_panel(win->win); + if (pan == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + return (PyObject *)PyCursesPanel_New(pan, win); +} + + +/* Wrapper for panel_below(NULL). This function returns the top panel + of the stack, so it's renamed to top_panel(). panel.below() + *requires* a panel object in the first place which may be + undesirable. */ +static PyObject * +PyCurses_top_panel(PyObject *self) +{ + PANEL *pan; + PyCursesPanelObject *po; + + PyCursesInitialised; + + pan = panel_below(NULL); + + if (pan == NULL) { /* valid output, it means + there's no panel at all */ + Py_INCREF(Py_None); + return Py_None; + } + po = find_po(pan); + if (po == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "panel_below: can't find Panel Object"); + return NULL; + } + Py_INCREF(po); + return (PyObject *)po; +} + +static PyObject *PyCurses_update_panels(PyObject *self) +{ + PyCursesInitialised; + update_panels(); + Py_INCREF(Py_None); + return Py_None; +} + + +/* List of functions defined in the module */ + +static PyMethodDef PyCurses_methods[] = { + {"bottom_panel", (PyCFunction)PyCurses_bottom_panel, METH_NOARGS}, + {"new_panel", (PyCFunction)PyCurses_new_panel, METH_VARARGS}, + {"top_panel", (PyCFunction)PyCurses_top_panel, METH_NOARGS}, + {"update_panels", (PyCFunction)PyCurses_update_panels, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Initialization function for the module */ + +PyMODINIT_FUNC +init_curses_panel(void) +{ + PyObject *m, *d, *v; + + /* Initialize object type */ + PyCursesPanel_Type.ob_type = &PyType_Type; + + import_curses(); + + /* Create the module and add the functions */ + m = Py_InitModule("_curses_panel", PyCurses_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + /* For exception _curses_panel.error */ + PyCursesError = PyErr_NewException("_curses_panel.error", NULL, NULL); + PyDict_SetItemString(d, "error", PyCursesError); + + /* Make the version available */ + v = PyString_FromString(PyCursesVersion); + PyDict_SetItemString(d, "version", v); + PyDict_SetItemString(d, "__version__", v); + Py_DECREF(v); +} diff --git a/sys/src/cmd/python/Modules/_cursesmodule.c b/sys/src/cmd/python/Modules/_cursesmodule.c new file mode 100644 index 000000000..c331353df --- /dev/null +++ b/sys/src/cmd/python/Modules/_cursesmodule.c @@ -0,0 +1,2760 @@ +/* + * This is a curses module for Python. + * + * Based on prior work by Lance Ellinghaus and Oliver Andrich + * Version 1.2 of this module: Copyright 1994 by Lance Ellinghouse, + * Cathedral City, California Republic, United States of America. + * + * Version 1.5b1, heavily extended for ncurses by Oliver Andrich: + * Copyright 1996,1997 by Oliver Andrich, Koblenz, Germany. + * + * Tidied for Python 1.6, and currently maintained by <amk@amk.ca>. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this source file to use, copy, modify, merge, or publish it + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or in any new file that contains a substantial portion of + * this file. + * + * THE AUTHOR MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF + * THE SOFTWARE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT + * EXPRESS OR IMPLIED WARRANTY. THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE, STRICT LIABILITY OR + * ANY OTHER ACTION ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* CVS: $Id: _cursesmodule.c 54181 2007-03-06 20:46:26Z walter.doerwald $ */ + +/* + +A number of SysV or ncurses functions don't have wrappers yet; if you need +a given function, add it and send a patch. Here's a list of currently +unsupported functions: + + addchnstr addchstr chgat color_set define_key + del_curterm delscreen dupwin inchnstr inchstr innstr keyok + mcprint mvaddchnstr mvaddchstr mvchgat mvcur mvinchnstr + mvinchstr mvinnstr mmvwaddchnstr mvwaddchstr mvwchgat + mvwinchnstr mvwinchstr mvwinnstr newterm + restartterm ripoffline scr_dump + scr_init scr_restore scr_set scrl set_curterm set_term setterm + tgetent tgetflag tgetnum tgetstr tgoto timeout tputs + vidattr vidputs waddchnstr waddchstr wchgat + wcolor_set winchnstr winchstr winnstr wmouse_trafo wscrl + +Low-priority: + slk_attr slk_attr_off slk_attr_on slk_attr_set slk_attroff + slk_attron slk_attrset slk_clear slk_color slk_init slk_label + slk_noutrefresh slk_refresh slk_restore slk_set slk_touch + +Menu extension (ncurses and probably SYSV): + current_item free_item free_menu item_count item_description + item_index item_init item_name item_opts item_opts_off + item_opts_on item_term item_userptr item_value item_visible + menu_back menu_driver menu_fore menu_format menu_grey + menu_init menu_items menu_mark menu_opts menu_opts_off + menu_opts_on menu_pad menu_pattern menu_request_by_name + menu_request_name menu_spacing menu_sub menu_term menu_userptr + menu_win new_item new_menu pos_menu_cursor post_menu + scale_menu set_current_item set_item_init set_item_opts + set_item_term set_item_userptr set_item_value set_menu_back + set_menu_fore set_menu_format set_menu_grey set_menu_init + set_menu_items set_menu_mark set_menu_opts set_menu_pad + set_menu_pattern set_menu_spacing set_menu_sub set_menu_term + set_menu_userptr set_menu_win set_top_row top_row unpost_menu + +Form extension (ncurses and probably SYSV): + current_field data_ahead data_behind dup_field + dynamic_fieldinfo field_arg field_back field_buffer + field_count field_fore field_index field_info field_init + field_just field_opts field_opts_off field_opts_on field_pad + field_status field_term field_type field_userptr form_driver + form_fields form_init form_opts form_opts_off form_opts_on + form_page form_request_by_name form_request_name form_sub + form_term form_userptr form_win free_field free_form + link_field link_fieldtype move_field new_field new_form + new_page pos_form_cursor post_form scale_form + set_current_field set_field_back set_field_buffer + set_field_fore set_field_init set_field_just set_field_opts + set_field_pad set_field_status set_field_term set_field_type + set_field_userptr set_fieldtype_arg set_fieldtype_choice + set_form_fields set_form_init set_form_opts set_form_page + set_form_sub set_form_term set_form_userptr set_form_win + set_max_field set_new_page unpost_form + + + */ + +/* Release Number */ + +char *PyCursesVersion = "2.2"; + +/* Includes */ + +#include "Python.h" + +#ifdef __osf__ +#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */ +#endif + +#ifdef __hpux +#define STRICT_SYSV_CURSES +#endif + +#define CURSES_MODULE +#include "py_curses.h" + +/* These prototypes are in <term.h>, but including this header + #defines many common symbols (such as "lines") which breaks the + curses module in other ways. So the code will just specify + explicit prototypes here. */ +extern int setupterm(char *,int,int *); +#ifdef __sgi +#include <term.h> +#endif + +#if !defined(HAVE_NCURSES_H) && (defined(sgi) || defined(__sun) || defined(SCO5)) +#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */ +typedef chtype attr_t; /* No attr_t type is available */ +#endif + +#if defined(_AIX) +#define STRICT_SYSV_CURSES +#endif + +/* Definition of exception curses.error */ + +static PyObject *PyCursesError; + +/* Tells whether setupterm() has been called to initialise terminfo. */ +static int initialised_setupterm = FALSE; + +/* Tells whether initscr() has been called to initialise curses. */ +static int initialised = FALSE; + +/* Tells whether start_color() has been called to initialise color usage. */ +static int initialisedcolors = FALSE; + +/* Utility Macros */ +#define PyCursesSetupTermCalled \ + if (initialised_setupterm != TRUE) { \ + PyErr_SetString(PyCursesError, \ + "must call (at least) setupterm() first"); \ + return 0; } + +#define PyCursesInitialised \ + if (initialised != TRUE) { \ + PyErr_SetString(PyCursesError, \ + "must call initscr() first"); \ + return 0; } + +#define PyCursesInitialisedColor \ + if (initialisedcolors != TRUE) { \ + PyErr_SetString(PyCursesError, \ + "must call start_color() first"); \ + return 0; } + +#ifndef MIN +#define MIN(x,y) ((x) < (y) ? (x) : (y)) +#endif + +/* Utility Functions */ + +/* + * Check the return code from a curses function and return None + * or raise an exception as appropriate. These are exported using the + * CObject API. + */ + +static PyObject * +PyCursesCheckERR(int code, char *fname) +{ + if (code != ERR) { + Py_INCREF(Py_None); + return Py_None; + } else { + if (fname == NULL) { + PyErr_SetString(PyCursesError, catchall_ERR); + } else { + PyErr_Format(PyCursesError, "%s() returned ERR", fname); + } + return NULL; + } +} + +static int +PyCurses_ConvertToChtype(PyObject *obj, chtype *ch) +{ + if (PyInt_Check(obj)) { + *ch = (chtype) PyInt_AsLong(obj); + } else if(PyString_Check(obj) + && (PyString_Size(obj) == 1)) { + *ch = (chtype) *PyString_AsString(obj); + } else { + return 0; + } + return 1; +} + +/* Function versions of the 3 functions for tested whether curses has been + initialised or not. */ + +static int func_PyCursesSetupTermCalled(void) +{ + PyCursesSetupTermCalled; + return 1; +} + +static int func_PyCursesInitialised(void) +{ + PyCursesInitialised; + return 1; +} + +static int func_PyCursesInitialisedColor(void) +{ + PyCursesInitialisedColor; + return 1; +} + +/***************************************************************************** + The Window Object +******************************************************************************/ + +/* Definition of the window type */ + +PyTypeObject PyCursesWindow_Type; + +/* Function prototype macros for Window object + + X - function name + TYPE - parameter Type + ERGSTR - format string for construction of the return value + PARSESTR - format string for argument parsing + */ + +#define Window_NoArgNoReturnFunction(X) \ +static PyObject *PyCursesWindow_ ## X (PyCursesWindowObject *self, PyObject *args) \ +{ return PyCursesCheckERR(X(self->win), # X); } + +#define Window_NoArgTrueFalseFunction(X) \ +static PyObject * PyCursesWindow_ ## X (PyCursesWindowObject *self) \ +{ \ + if (X (self->win) == FALSE) { Py_INCREF(Py_False); return Py_False; } \ + else { Py_INCREF(Py_True); return Py_True; } } + +#define Window_NoArgNoReturnVoidFunction(X) \ +static PyObject * PyCursesWindow_ ## X (PyCursesWindowObject *self) \ +{ \ + X(self->win); Py_INCREF(Py_None); return Py_None; } + +#define Window_NoArg2TupleReturnFunction(X, TYPE, ERGSTR) \ +static PyObject * PyCursesWindow_ ## X (PyCursesWindowObject *self) \ +{ \ + TYPE arg1, arg2; \ + X(self->win,arg1,arg2); return Py_BuildValue(ERGSTR, arg1, arg2); } + +#define Window_OneArgNoReturnVoidFunction(X, TYPE, PARSESTR) \ +static PyObject * PyCursesWindow_ ## X (PyCursesWindowObject *self, PyObject *args) \ +{ \ + TYPE arg1; \ + if (!PyArg_ParseTuple(args, PARSESTR, &arg1)) return NULL; \ + X(self->win,arg1); Py_INCREF(Py_None); return Py_None; } + +#define Window_OneArgNoReturnFunction(X, TYPE, PARSESTR) \ +static PyObject * PyCursesWindow_ ## X (PyCursesWindowObject *self, PyObject *args) \ +{ \ + TYPE arg1; \ + if (!PyArg_ParseTuple(args,PARSESTR, &arg1)) return NULL; \ + return PyCursesCheckERR(X(self->win, arg1), # X); } + +#define Window_TwoArgNoReturnFunction(X, TYPE, PARSESTR) \ +static PyObject * PyCursesWindow_ ## X (PyCursesWindowObject *self, PyObject *args) \ +{ \ + TYPE arg1, arg2; \ + if (!PyArg_ParseTuple(args,PARSESTR, &arg1, &arg2)) return NULL; \ + return PyCursesCheckERR(X(self->win, arg1, arg2), # X); } + +/* ------------- WINDOW routines --------------- */ + +Window_NoArgNoReturnFunction(untouchwin) +Window_NoArgNoReturnFunction(touchwin) +Window_NoArgNoReturnFunction(redrawwin) +Window_NoArgNoReturnFunction(winsertln) +Window_NoArgNoReturnFunction(werase) +Window_NoArgNoReturnFunction(wdeleteln) + +Window_NoArgTrueFalseFunction(is_wintouched) + +Window_NoArgNoReturnVoidFunction(wsyncup) +Window_NoArgNoReturnVoidFunction(wsyncdown) +Window_NoArgNoReturnVoidFunction(wstandend) +Window_NoArgNoReturnVoidFunction(wstandout) +Window_NoArgNoReturnVoidFunction(wcursyncup) +Window_NoArgNoReturnVoidFunction(wclrtoeol) +Window_NoArgNoReturnVoidFunction(wclrtobot) +Window_NoArgNoReturnVoidFunction(wclear) + +Window_OneArgNoReturnVoidFunction(idcok, int, "i;True(1) or False(0)") +Window_OneArgNoReturnVoidFunction(immedok, int, "i;True(1) or False(0)") +Window_OneArgNoReturnVoidFunction(wtimeout, int, "i;delay") + +Window_NoArg2TupleReturnFunction(getyx, int, "ii") +Window_NoArg2TupleReturnFunction(getbegyx, int, "ii") +Window_NoArg2TupleReturnFunction(getmaxyx, int, "ii") +Window_NoArg2TupleReturnFunction(getparyx, int, "ii") + +Window_OneArgNoReturnFunction(wattron, attr_t, "l;attr") +Window_OneArgNoReturnFunction(wattroff, attr_t, "l;attr") +Window_OneArgNoReturnFunction(wattrset, attr_t, "l;attr") +Window_OneArgNoReturnFunction(clearok, int, "i;True(1) or False(0)") +Window_OneArgNoReturnFunction(idlok, int, "i;True(1) or False(0)") +#if defined(__NetBSD__) +Window_OneArgNoReturnVoidFunction(keypad, int, "i;True(1) or False(0)") +#else +Window_OneArgNoReturnFunction(keypad, int, "i;True(1) or False(0)") +#endif +Window_OneArgNoReturnFunction(leaveok, int, "i;True(1) or False(0)") +#if defined(__NetBSD__) +Window_OneArgNoReturnVoidFunction(nodelay, int, "i;True(1) or False(0)") +#else +Window_OneArgNoReturnFunction(nodelay, int, "i;True(1) or False(0)") +#endif +Window_OneArgNoReturnFunction(notimeout, int, "i;True(1) or False(0)") +Window_OneArgNoReturnFunction(scrollok, int, "i;True(1) or False(0)") +Window_OneArgNoReturnFunction(winsdelln, int, "i;nlines") +Window_OneArgNoReturnFunction(syncok, int, "i;True(1) or False(0)") + +Window_TwoArgNoReturnFunction(mvwin, int, "ii;y,x") +Window_TwoArgNoReturnFunction(mvderwin, int, "ii;y,x") +Window_TwoArgNoReturnFunction(wmove, int, "ii;y,x") +#ifndef STRICT_SYSV_CURSES +Window_TwoArgNoReturnFunction(wresize, int, "ii;lines,columns") +#endif + +/* Allocation and deallocation of Window Objects */ + +static PyObject * +PyCursesWindow_New(WINDOW *win) +{ + PyCursesWindowObject *wo; + + wo = PyObject_NEW(PyCursesWindowObject, &PyCursesWindow_Type); + if (wo == NULL) return NULL; + wo->win = win; + return (PyObject *)wo; +} + +static void +PyCursesWindow_Dealloc(PyCursesWindowObject *wo) +{ + if (wo->win != stdscr) delwin(wo->win); + PyObject_DEL(wo); +} + +/* Addch, Addstr, Addnstr */ + +static PyObject * +PyCursesWindow_AddCh(PyCursesWindowObject *self, PyObject *args) +{ + int rtn, x, y, use_xy = FALSE; + PyObject *temp; + chtype ch = 0; + attr_t attr = A_NORMAL; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "O;ch or int", &temp)) + return NULL; + break; + case 2: + if (!PyArg_ParseTuple(args, "Ol;ch or int,attr", &temp, &attr)) + return NULL; + break; + case 3: + if (!PyArg_ParseTuple(args,"iiO;y,x,ch or int", &y, &x, &temp)) + return NULL; + use_xy = TRUE; + break; + case 4: + if (!PyArg_ParseTuple(args,"iiOl;y,x,ch or int, attr", + &y, &x, &temp, &attr)) + return NULL; + use_xy = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, "addch requires 1 to 4 arguments"); + return NULL; + } + + if (!PyCurses_ConvertToChtype(temp, &ch)) { + PyErr_SetString(PyExc_TypeError, "argument 1 or 3 must be a ch or an int"); + return NULL; + } + + if (use_xy == TRUE) + rtn = mvwaddch(self->win,y,x, ch | attr); + else { + rtn = waddch(self->win, ch | attr); + } + return PyCursesCheckERR(rtn, "addch"); +} + +static PyObject * +PyCursesWindow_AddStr(PyCursesWindowObject *self, PyObject *args) +{ + int rtn; + int x, y; + char *str; + attr_t attr = A_NORMAL , attr_old = A_NORMAL; + int use_xy = FALSE, use_attr = FALSE; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args,"s;str", &str)) + return NULL; + break; + case 2: + if (!PyArg_ParseTuple(args,"sl;str,attr", &str, &attr)) + return NULL; + use_attr = TRUE; + break; + case 3: + if (!PyArg_ParseTuple(args,"iis;int,int,str", &y, &x, &str)) + return NULL; + use_xy = TRUE; + break; + case 4: + if (!PyArg_ParseTuple(args,"iisl;int,int,str,attr", &y, &x, &str, &attr)) + return NULL; + use_xy = use_attr = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, "addstr requires 1 to 4 arguments"); + return NULL; + } + + if (use_attr == TRUE) { + attr_old = getattrs(self->win); + wattrset(self->win,attr); + } + if (use_xy == TRUE) + rtn = mvwaddstr(self->win,y,x,str); + else + rtn = waddstr(self->win,str); + if (use_attr == TRUE) + wattrset(self->win,attr_old); + return PyCursesCheckERR(rtn, "addstr"); +} + +static PyObject * +PyCursesWindow_AddNStr(PyCursesWindowObject *self, PyObject *args) +{ + int rtn, x, y, n; + char *str; + attr_t attr = A_NORMAL , attr_old = A_NORMAL; + int use_xy = FALSE, use_attr = FALSE; + + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args,"si;str,n", &str, &n)) + return NULL; + break; + case 3: + if (!PyArg_ParseTuple(args,"sil;str,n,attr", &str, &n, &attr)) + return NULL; + use_attr = TRUE; + break; + case 4: + if (!PyArg_ParseTuple(args,"iisi;y,x,str,n", &y, &x, &str, &n)) + return NULL; + use_xy = TRUE; + break; + case 5: + if (!PyArg_ParseTuple(args,"iisil;y,x,str,n,attr", &y, &x, &str, &n, &attr)) + return NULL; + use_xy = use_attr = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, "addnstr requires 2 to 5 arguments"); + return NULL; + } + + if (use_attr == TRUE) { + attr_old = getattrs(self->win); + wattrset(self->win,attr); + } + if (use_xy == TRUE) + rtn = mvwaddnstr(self->win,y,x,str,n); + else + rtn = waddnstr(self->win,str,n); + if (use_attr == TRUE) + wattrset(self->win,attr_old); + return PyCursesCheckERR(rtn, "addnstr"); +} + +static PyObject * +PyCursesWindow_Bkgd(PyCursesWindowObject *self, PyObject *args) +{ + PyObject *temp; + chtype bkgd; + attr_t attr = A_NORMAL; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "O;ch or int", &temp)) + return NULL; + break; + case 2: + if (!PyArg_ParseTuple(args,"Ol;ch or int,attr", &temp, &attr)) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "bkgd requires 1 or 2 arguments"); + return NULL; + } + + if (!PyCurses_ConvertToChtype(temp, &bkgd)) { + PyErr_SetString(PyExc_TypeError, "argument 1 or 3 must be a ch or an int"); + return NULL; + } + + return PyCursesCheckERR(wbkgd(self->win, bkgd | attr), "bkgd"); +} + +static PyObject * +PyCursesWindow_BkgdSet(PyCursesWindowObject *self, PyObject *args) +{ + PyObject *temp; + chtype bkgd; + attr_t attr = A_NORMAL; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "O;ch or int", &temp)) + return NULL; + break; + case 2: + if (!PyArg_ParseTuple(args,"Ol;ch or int,attr", &temp, &attr)) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "bkgdset requires 1 or 2 arguments"); + return NULL; + } + + if (!PyCurses_ConvertToChtype(temp, &bkgd)) { + PyErr_SetString(PyExc_TypeError, "argument 1 must be a ch or an int"); + return NULL; + } + + wbkgdset(self->win, bkgd | attr); + return PyCursesCheckERR(0, "bkgdset"); +} + +static PyObject * +PyCursesWindow_Border(PyCursesWindowObject *self, PyObject *args) +{ + PyObject *temp[8]; + chtype ch[8]; + int i; + + /* Clear the array of parameters */ + for(i=0; i<8; i++) { + temp[i] = NULL; + ch[i] = 0; + } + + if (!PyArg_ParseTuple(args,"|OOOOOOOO;ls,rs,ts,bs,tl,tr,bl,br", + &temp[0], &temp[1], &temp[2], &temp[3], + &temp[4], &temp[5], &temp[6], &temp[7])) + return NULL; + + for(i=0; i<8; i++) { + if (temp[i] != NULL && !PyCurses_ConvertToChtype(temp[i], &ch[i])) { + PyErr_Format(PyExc_TypeError, + "argument %i must be a ch or an int", i+1); + return NULL; + } + } + + wborder(self->win, + ch[0], ch[1], ch[2], ch[3], + ch[4], ch[5], ch[6], ch[7]); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyCursesWindow_Box(PyCursesWindowObject *self, PyObject *args) +{ + chtype ch1=0,ch2=0; + switch(PyTuple_Size(args)){ + case 0: break; + default: + if (!PyArg_ParseTuple(args,"ll;vertint,horint", &ch1, &ch2)) + return NULL; + } + box(self->win,ch1,ch2); + Py_INCREF(Py_None); + return Py_None; +} + +#if defined(HAVE_NCURSES_H) || defined(MVWDELCH_IS_EXPRESSION) +#define py_mvwdelch mvwdelch +#else +int py_mvwdelch(WINDOW *w, int y, int x) +{ + mvwdelch(w,y,x); + /* On HP/UX, mvwdelch already returns. On other systems, + we may well run into this return statement. */ + return 0; +} +#endif + + +static PyObject * +PyCursesWindow_DelCh(PyCursesWindowObject *self, PyObject *args) +{ + int rtn; + int x, y; + + switch (PyTuple_Size(args)) { + case 0: + rtn = wdelch(self->win); + break; + case 2: + if (!PyArg_ParseTuple(args,"ii;y,x", &y, &x)) + return NULL; + rtn = py_mvwdelch(self->win,y,x); + break; + default: + PyErr_SetString(PyExc_TypeError, "delch requires 0 or 2 arguments"); + return NULL; + } + return PyCursesCheckERR(rtn, "[mv]wdelch"); +} + +static PyObject * +PyCursesWindow_DerWin(PyCursesWindowObject *self, PyObject *args) +{ + WINDOW *win; + int nlines, ncols, begin_y, begin_x; + + nlines = 0; + ncols = 0; + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args,"ii;begin_y,begin_x",&begin_y,&begin_x)) + return NULL; + break; + case 4: + if (!PyArg_ParseTuple(args, "iiii;nlines,ncols,begin_y,begin_x", + &nlines,&ncols,&begin_y,&begin_x)) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "derwin requires 2 or 4 arguments"); + return NULL; + } + + win = derwin(self->win,nlines,ncols,begin_y,begin_x); + + if (win == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + + return (PyObject *)PyCursesWindow_New(win); +} + +static PyObject * +PyCursesWindow_EchoChar(PyCursesWindowObject *self, PyObject *args) +{ + PyObject *temp; + chtype ch; + attr_t attr = A_NORMAL; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args,"O;ch or int", &temp)) + return NULL; + break; + case 2: + if (!PyArg_ParseTuple(args,"Ol;ch or int,attr", &temp, &attr)) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "echochar requires 1 or 2 arguments"); + + + return NULL; + } + + if (!PyCurses_ConvertToChtype(temp, &ch)) { + PyErr_SetString(PyExc_TypeError, "argument 1 must be a ch or an int"); + return NULL; + } + +#ifdef WINDOW_HAS_FLAGS + if (self->win->_flags & _ISPAD) + return PyCursesCheckERR(pechochar(self->win, ch | attr), + "echochar"); + else +#endif + return PyCursesCheckERR(wechochar(self->win, ch | attr), + "echochar"); +} + +#ifdef NCURSES_MOUSE_VERSION +static PyObject * +PyCursesWindow_Enclose(PyCursesWindowObject *self, PyObject *args) +{ + int x, y; + if (!PyArg_ParseTuple(args,"ii;y,x", &y, &x)) + return NULL; + + return PyInt_FromLong( wenclose(self->win,y,x) ); +} +#endif + +static PyObject * +PyCursesWindow_GetBkgd(PyCursesWindowObject *self) +{ + return PyInt_FromLong((long) getbkgd(self->win)); +} + +static PyObject * +PyCursesWindow_GetCh(PyCursesWindowObject *self, PyObject *args) +{ + int x, y; + int rtn; + + switch (PyTuple_Size(args)) { + case 0: + Py_BEGIN_ALLOW_THREADS + rtn = wgetch(self->win); + Py_END_ALLOW_THREADS + break; + case 2: + if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rtn = mvwgetch(self->win,y,x); + Py_END_ALLOW_THREADS + break; + default: + PyErr_SetString(PyExc_TypeError, "getch requires 0 or 2 arguments"); + return NULL; + } + return PyInt_FromLong((long)rtn); +} + +static PyObject * +PyCursesWindow_GetKey(PyCursesWindowObject *self, PyObject *args) +{ + int x, y; + int rtn; + + switch (PyTuple_Size(args)) { + case 0: + Py_BEGIN_ALLOW_THREADS + rtn = wgetch(self->win); + Py_END_ALLOW_THREADS + break; + case 2: + if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rtn = mvwgetch(self->win,y,x); + Py_END_ALLOW_THREADS + break; + default: + PyErr_SetString(PyExc_TypeError, "getkey requires 0 or 2 arguments"); + return NULL; + } + if (rtn == ERR) { + /* getch() returns ERR in nodelay mode */ + PyErr_SetString(PyCursesError, "no input"); + return NULL; + } else if (rtn<=255) + return Py_BuildValue("c", rtn); + else +#if defined(__NetBSD__) + return PyString_FromString(unctrl(rtn)); +#else + return PyString_FromString((char *)keyname(rtn)); +#endif +} + +static PyObject * +PyCursesWindow_GetStr(PyCursesWindowObject *self, PyObject *args) +{ + int x, y, n; + char rtn[1024]; /* This should be big enough.. I hope */ + int rtn2; + + switch (PyTuple_Size(args)) { + case 0: + Py_BEGIN_ALLOW_THREADS + rtn2 = wgetnstr(self->win,rtn, 1023); + Py_END_ALLOW_THREADS + break; + case 1: + if (!PyArg_ParseTuple(args,"i;n", &n)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rtn2 = wgetnstr(self->win,rtn,MIN(n, 1023)); + Py_END_ALLOW_THREADS + break; + case 2: + if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x)) + return NULL; + Py_BEGIN_ALLOW_THREADS +#ifdef STRICT_SYSV_CURSES + rtn2 = wmove(self->win,y,x)==ERR ? ERR : wgetnstr(self->win, rtn, 1023); +#else + rtn2 = mvwgetnstr(self->win,y,x,rtn, 1023); +#endif + Py_END_ALLOW_THREADS + break; + case 3: + if (!PyArg_ParseTuple(args,"iii;y,x,n", &y, &x, &n)) + return NULL; +#ifdef STRICT_SYSV_CURSES + Py_BEGIN_ALLOW_THREADS + rtn2 = wmove(self->win,y,x)==ERR ? ERR : + wgetnstr(self->win, rtn, MIN(n, 1023)); + Py_END_ALLOW_THREADS +#else + Py_BEGIN_ALLOW_THREADS + rtn2 = mvwgetnstr(self->win, y, x, rtn, MIN(n, 1023)); + Py_END_ALLOW_THREADS +#endif + break; + default: + PyErr_SetString(PyExc_TypeError, "getstr requires 0 to 3 arguments"); + return NULL; + } + if (rtn2 == ERR) + rtn[0] = 0; + return PyString_FromString(rtn); +} + +static PyObject * +PyCursesWindow_Hline(PyCursesWindowObject *self, PyObject *args) +{ + PyObject *temp; + chtype ch; + int n, x, y, code = OK; + attr_t attr = A_NORMAL; + + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args, "Oi;ch or int,n", &temp, &n)) + return NULL; + break; + case 3: + if (!PyArg_ParseTuple(args, "Oil;ch or int,n,attr", &temp, &n, &attr)) + return NULL; + break; + case 4: + if (!PyArg_ParseTuple(args, "iiOi;y,x,ch or int,n", &y, &x, &temp, &n)) + return NULL; + code = wmove(self->win, y, x); + break; + case 5: + if (!PyArg_ParseTuple(args, "iiOil; y,x,ch or int,n,attr", + &y, &x, &temp, &n, &attr)) + return NULL; + code = wmove(self->win, y, x); + break; + default: + PyErr_SetString(PyExc_TypeError, "hline requires 2 to 5 arguments"); + return NULL; + } + + if (code != ERR) { + if (!PyCurses_ConvertToChtype(temp, &ch)) { + PyErr_SetString(PyExc_TypeError, + "argument 1 or 3 must be a ch or an int"); + return NULL; + } + return PyCursesCheckERR(whline(self->win, ch | attr, n), "hline"); + } else + return PyCursesCheckERR(code, "wmove"); +} + +static PyObject * +PyCursesWindow_InsCh(PyCursesWindowObject *self, PyObject *args) +{ + int rtn, x, y, use_xy = FALSE; + PyObject *temp; + chtype ch = 0; + attr_t attr = A_NORMAL; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "O;ch or int", &temp)) + return NULL; + break; + case 2: + if (!PyArg_ParseTuple(args, "Ol;ch or int,attr", &temp, &attr)) + return NULL; + break; + case 3: + if (!PyArg_ParseTuple(args,"iiO;y,x,ch or int", &y, &x, &temp)) + return NULL; + use_xy = TRUE; + break; + case 4: + if (!PyArg_ParseTuple(args,"iiOl;y,x,ch or int, attr", &y, &x, &temp, &attr)) + return NULL; + use_xy = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, "insch requires 1 or 4 arguments"); + return NULL; + } + + if (!PyCurses_ConvertToChtype(temp, &ch)) { + PyErr_SetString(PyExc_TypeError, + "argument 1 or 3 must be a ch or an int"); + return NULL; + } + + if (use_xy == TRUE) + rtn = mvwinsch(self->win,y,x, ch | attr); + else { + rtn = winsch(self->win, ch | attr); + } + return PyCursesCheckERR(rtn, "insch"); +} + +static PyObject * +PyCursesWindow_InCh(PyCursesWindowObject *self, PyObject *args) +{ + int x, y, rtn; + + switch (PyTuple_Size(args)) { + case 0: + rtn = winch(self->win); + break; + case 2: + if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x)) + return NULL; + rtn = mvwinch(self->win,y,x); + break; + default: + PyErr_SetString(PyExc_TypeError, "inch requires 0 or 2 arguments"); + return NULL; + } + return PyInt_FromLong((long) rtn); +} + +static PyObject * +PyCursesWindow_InStr(PyCursesWindowObject *self, PyObject *args) +{ + int x, y, n; + char rtn[1024]; /* This should be big enough.. I hope */ + int rtn2; + + switch (PyTuple_Size(args)) { + case 0: + rtn2 = winnstr(self->win,rtn, 1023); + break; + case 1: + if (!PyArg_ParseTuple(args,"i;n", &n)) + return NULL; + rtn2 = winnstr(self->win,rtn,MIN(n,1023)); + break; + case 2: + if (!PyArg_ParseTuple(args,"ii;y,x",&y,&x)) + return NULL; + rtn2 = mvwinnstr(self->win,y,x,rtn,1023); + break; + case 3: + if (!PyArg_ParseTuple(args, "iii;y,x,n", &y, &x, &n)) + return NULL; + rtn2 = mvwinnstr(self->win, y, x, rtn, MIN(n,1023)); + break; + default: + PyErr_SetString(PyExc_TypeError, "instr requires 0 or 3 arguments"); + return NULL; + } + if (rtn2 == ERR) + rtn[0] = 0; + return PyString_FromString(rtn); +} + +static PyObject * +PyCursesWindow_InsStr(PyCursesWindowObject *self, PyObject *args) +{ + int rtn; + int x, y; + char *str; + attr_t attr = A_NORMAL , attr_old = A_NORMAL; + int use_xy = FALSE, use_attr = FALSE; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args,"s;str", &str)) + return NULL; + break; + case 2: + if (!PyArg_ParseTuple(args,"sl;str,attr", &str, &attr)) + return NULL; + use_attr = TRUE; + break; + case 3: + if (!PyArg_ParseTuple(args,"iis;y,x,str", &y, &x, &str)) + return NULL; + use_xy = TRUE; + break; + case 4: + if (!PyArg_ParseTuple(args,"iisl;y,x,str,attr", &y, &x, &str, &attr)) + return NULL; + use_xy = use_attr = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, "insstr requires 1 to 4 arguments"); + return NULL; + } + + if (use_attr == TRUE) { + attr_old = getattrs(self->win); + wattrset(self->win,attr); + } + if (use_xy == TRUE) + rtn = mvwinsstr(self->win,y,x,str); + else + rtn = winsstr(self->win,str); + if (use_attr == TRUE) + wattrset(self->win,attr_old); + return PyCursesCheckERR(rtn, "insstr"); +} + +static PyObject * +PyCursesWindow_InsNStr(PyCursesWindowObject *self, PyObject *args) +{ + int rtn, x, y, n; + char *str; + attr_t attr = A_NORMAL , attr_old = A_NORMAL; + int use_xy = FALSE, use_attr = FALSE; + + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args,"si;str,n", &str, &n)) + return NULL; + break; + case 3: + if (!PyArg_ParseTuple(args,"sil;str,n,attr", &str, &n, &attr)) + return NULL; + use_attr = TRUE; + break; + case 4: + if (!PyArg_ParseTuple(args,"iisi;y,x,str,n", &y, &x, &str, &n)) + return NULL; + use_xy = TRUE; + break; + case 5: + if (!PyArg_ParseTuple(args,"iisil;y,x,str,n,attr", &y, &x, &str, &n, &attr)) + return NULL; + use_xy = use_attr = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, "insnstr requires 2 to 5 arguments"); + return NULL; + } + + if (use_attr == TRUE) { + attr_old = getattrs(self->win); + wattrset(self->win,attr); + } + if (use_xy == TRUE) + rtn = mvwinsnstr(self->win,y,x,str,n); + else + rtn = winsnstr(self->win,str,n); + if (use_attr == TRUE) + wattrset(self->win,attr_old); + return PyCursesCheckERR(rtn, "insnstr"); +} + +static PyObject * +PyCursesWindow_Is_LineTouched(PyCursesWindowObject *self, PyObject *args) +{ + int line, erg; + if (!PyArg_ParseTuple(args,"i;line", &line)) + return NULL; + erg = is_linetouched(self->win, line); + if (erg == ERR) { + PyErr_SetString(PyExc_TypeError, + "is_linetouched: line number outside of boundaries"); + return NULL; + } else + if (erg == FALSE) { + Py_INCREF(Py_False); + return Py_False; + } else { + Py_INCREF(Py_True); + return Py_True; + } +} + +static PyObject * +PyCursesWindow_NoOutRefresh(PyCursesWindowObject *self, PyObject *args) +{ + int pminrow,pmincol,sminrow,smincol,smaxrow,smaxcol; + int rtn; + +#ifndef WINDOW_HAS_FLAGS + if (0) { +#else + if (self->win->_flags & _ISPAD) { +#endif + switch(PyTuple_Size(args)) { + case 6: + if (!PyArg_ParseTuple(args, + "iiiiii;" \ + "pminrow,pmincol,sminrow,smincol,smaxrow,smaxcol", + &pminrow, &pmincol, &sminrow, + &smincol, &smaxrow, &smaxcol)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rtn = pnoutrefresh(self->win, + pminrow, pmincol, sminrow, + smincol, smaxrow, smaxcol); + Py_END_ALLOW_THREADS + return PyCursesCheckERR(rtn, "pnoutrefresh"); + default: + PyErr_SetString(PyCursesError, + "noutrefresh() called for a pad " + "requires 6 arguments"); + return NULL; + } + } else { + if (!PyArg_ParseTuple(args, ":noutrefresh")) + return NULL; + + Py_BEGIN_ALLOW_THREADS + rtn = wnoutrefresh(self->win); + Py_END_ALLOW_THREADS + return PyCursesCheckERR(rtn, "wnoutrefresh"); + } +} + +static PyObject * +PyCursesWindow_Overlay(PyCursesWindowObject *self, PyObject *args) +{ + PyCursesWindowObject *temp; + int use_copywin = FALSE; + int sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol; + int rtn; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "O!;window object", + &PyCursesWindow_Type, &temp)) + return NULL; + break; + case 7: + if (!PyArg_ParseTuple(args, "O!iiiiii;window object, int, int, int, int, int, int", + &PyCursesWindow_Type, &temp, &sminrow, &smincol, + &dminrow, &dmincol, &dmaxrow, &dmaxcol)) + return NULL; + use_copywin = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, + "overlay requires one or seven arguments"); + return NULL; + } + + if (use_copywin == TRUE) { + rtn = copywin(self->win, temp->win, sminrow, smincol, + dminrow, dmincol, dmaxrow, dmaxcol, TRUE); + return PyCursesCheckERR(rtn, "copywin"); + } + else { + rtn = overlay(self->win, temp->win); + return PyCursesCheckERR(rtn, "overlay"); + } +} + +static PyObject * +PyCursesWindow_Overwrite(PyCursesWindowObject *self, PyObject *args) +{ + PyCursesWindowObject *temp; + int use_copywin = FALSE; + int sminrow, smincol, dminrow, dmincol, dmaxrow, dmaxcol; + int rtn; + + switch (PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "O!;window object", + &PyCursesWindow_Type, &temp)) + return NULL; + break; + case 7: + if (!PyArg_ParseTuple(args, "O!iiiiii;window object, int, int, int, int, int, int", + &PyCursesWindow_Type, &temp, &sminrow, &smincol, + &dminrow, &dmincol, &dmaxrow, &dmaxcol)) + return NULL; + use_copywin = TRUE; + break; + default: + PyErr_SetString(PyExc_TypeError, + "overwrite requires one or seven arguments"); + return NULL; + } + + if (use_copywin == TRUE) { + rtn = copywin(self->win, temp->win, sminrow, smincol, + dminrow, dmincol, dmaxrow, dmaxcol, FALSE); + return PyCursesCheckERR(rtn, "copywin"); + } + else { + rtn = overwrite(self->win, temp->win); + return PyCursesCheckERR(rtn, "overwrite"); + } +} + +static PyObject * +PyCursesWindow_PutWin(PyCursesWindowObject *self, PyObject *args) +{ + PyObject *temp; + + if (!PyArg_ParseTuple(args, "O;fileobj", &temp)) + return NULL; + if (!PyFile_Check(temp)) { + PyErr_SetString(PyExc_TypeError, "argument must be a file object"); + return NULL; + } + return PyCursesCheckERR(putwin(self->win, PyFile_AsFile(temp)), + "putwin"); +} + +static PyObject * +PyCursesWindow_RedrawLine(PyCursesWindowObject *self, PyObject *args) +{ + int beg, num; + if (!PyArg_ParseTuple(args,"ii;beg,num", &beg, &num)) + return NULL; + return PyCursesCheckERR(wredrawln(self->win,beg,num), "redrawln"); +} + +static PyObject * +PyCursesWindow_Refresh(PyCursesWindowObject *self, PyObject *args) +{ + int pminrow,pmincol,sminrow,smincol,smaxrow,smaxcol; + int rtn; + +#ifndef WINDOW_HAS_FLAGS + if (0) { +#else + if (self->win->_flags & _ISPAD) { +#endif + switch(PyTuple_Size(args)) { + case 6: + if (!PyArg_ParseTuple(args, + "iiiiii;" \ + "pminrow,pmincol,sminrow,smincol,smaxrow,smaxcol", + &pminrow, &pmincol, &sminrow, + &smincol, &smaxrow, &smaxcol)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + rtn = prefresh(self->win, + pminrow, pmincol, sminrow, + smincol, smaxrow, smaxcol); + Py_END_ALLOW_THREADS + return PyCursesCheckERR(rtn, "prefresh"); + default: + PyErr_SetString(PyCursesError, + "refresh() for a pad requires 6 arguments"); + return NULL; + } + } else { + if (!PyArg_ParseTuple(args, ":refresh")) + return NULL; + Py_BEGIN_ALLOW_THREADS + rtn = wrefresh(self->win); + Py_END_ALLOW_THREADS + return PyCursesCheckERR(rtn, "prefresh"); + } +} + +static PyObject * +PyCursesWindow_SetScrollRegion(PyCursesWindowObject *self, PyObject *args) +{ + int x, y; + if (!PyArg_ParseTuple(args,"ii;top, bottom",&y,&x)) + return NULL; + return PyCursesCheckERR(wsetscrreg(self->win,y,x), "wsetscrreg"); +} + +static PyObject * +PyCursesWindow_SubWin(PyCursesWindowObject *self, PyObject *args) +{ + WINDOW *win; + int nlines, ncols, begin_y, begin_x; + + nlines = 0; + ncols = 0; + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args,"ii;begin_y,begin_x",&begin_y,&begin_x)) + return NULL; + break; + case 4: + if (!PyArg_ParseTuple(args, "iiii;nlines,ncols,begin_y,begin_x", + &nlines,&ncols,&begin_y,&begin_x)) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "subwin requires 2 or 4 arguments"); + return NULL; + } + + /* printf("Subwin: %i %i %i %i \n", nlines, ncols, begin_y, begin_x); */ +#ifdef WINDOW_HAS_FLAGS + if (self->win->_flags & _ISPAD) + win = subpad(self->win, nlines, ncols, begin_y, begin_x); + else +#endif + win = subwin(self->win, nlines, ncols, begin_y, begin_x); + + if (win == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + + return (PyObject *)PyCursesWindow_New(win); +} + +static PyObject * +PyCursesWindow_Scroll(PyCursesWindowObject *self, PyObject *args) +{ + int nlines; + switch(PyTuple_Size(args)) { + case 0: + return PyCursesCheckERR(scroll(self->win), "scroll"); + case 1: + if (!PyArg_ParseTuple(args, "i;nlines", &nlines)) + return NULL; + return PyCursesCheckERR(wscrl(self->win, nlines), "scroll"); + default: + PyErr_SetString(PyExc_TypeError, "scroll requires 0 or 1 arguments"); + return NULL; + } +} + +static PyObject * +PyCursesWindow_TouchLine(PyCursesWindowObject *self, PyObject *args) +{ + int st, cnt, val; + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args,"ii;start,count",&st,&cnt)) + return NULL; + return PyCursesCheckERR(touchline(self->win,st,cnt), "touchline"); + case 3: + if (!PyArg_ParseTuple(args, "iii;start,count,val", &st, &cnt, &val)) + return NULL; + return PyCursesCheckERR(wtouchln(self->win, st, cnt, val), "touchline"); + default: + PyErr_SetString(PyExc_TypeError, "touchline requires 2 or 3 arguments"); + return NULL; + } +} + +static PyObject * +PyCursesWindow_Vline(PyCursesWindowObject *self, PyObject *args) +{ + PyObject *temp; + chtype ch; + int n, x, y, code = OK; + attr_t attr = A_NORMAL; + + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args, "Oi;ch or int,n", &temp, &n)) + return NULL; + break; + case 3: + if (!PyArg_ParseTuple(args, "Oil;ch or int,n,attr", &temp, &n, &attr)) + return NULL; + break; + case 4: + if (!PyArg_ParseTuple(args, "iiOi;y,x,ch or int,n", &y, &x, &temp, &n)) + return NULL; + code = wmove(self->win, y, x); + break; + case 5: + if (!PyArg_ParseTuple(args, "iiOil; y,x,ch or int,n,attr", + &y, &x, &temp, &n, &attr)) + return NULL; + code = wmove(self->win, y, x); + break; + default: + PyErr_SetString(PyExc_TypeError, "vline requires 2 to 5 arguments"); + return NULL; + } + + if (code != ERR) { + if (!PyCurses_ConvertToChtype(temp, &ch)) { + PyErr_SetString(PyExc_TypeError, + "argument 1 or 3 must be a ch or an int"); + return NULL; + } + return PyCursesCheckERR(wvline(self->win, ch | attr, n), "vline"); + } else + return PyCursesCheckERR(code, "wmove"); +} + +static PyMethodDef PyCursesWindow_Methods[] = { + {"addch", (PyCFunction)PyCursesWindow_AddCh, METH_VARARGS}, + {"addnstr", (PyCFunction)PyCursesWindow_AddNStr, METH_VARARGS}, + {"addstr", (PyCFunction)PyCursesWindow_AddStr, METH_VARARGS}, + {"attroff", (PyCFunction)PyCursesWindow_wattroff, METH_VARARGS}, + {"attron", (PyCFunction)PyCursesWindow_wattron, METH_VARARGS}, + {"attrset", (PyCFunction)PyCursesWindow_wattrset, METH_VARARGS}, + {"bkgd", (PyCFunction)PyCursesWindow_Bkgd, METH_VARARGS}, + {"bkgdset", (PyCFunction)PyCursesWindow_BkgdSet, METH_VARARGS}, + {"border", (PyCFunction)PyCursesWindow_Border, METH_VARARGS}, + {"box", (PyCFunction)PyCursesWindow_Box, METH_VARARGS}, + {"clear", (PyCFunction)PyCursesWindow_wclear, METH_NOARGS}, + {"clearok", (PyCFunction)PyCursesWindow_clearok, METH_VARARGS}, + {"clrtobot", (PyCFunction)PyCursesWindow_wclrtobot, METH_NOARGS}, + {"clrtoeol", (PyCFunction)PyCursesWindow_wclrtoeol, METH_NOARGS}, + {"cursyncup", (PyCFunction)PyCursesWindow_wcursyncup, METH_NOARGS}, + {"delch", (PyCFunction)PyCursesWindow_DelCh, METH_VARARGS}, + {"deleteln", (PyCFunction)PyCursesWindow_wdeleteln, METH_NOARGS}, + {"derwin", (PyCFunction)PyCursesWindow_DerWin, METH_VARARGS}, + {"echochar", (PyCFunction)PyCursesWindow_EchoChar, METH_VARARGS}, +#ifdef NCURSES_MOUSE_VERSION + {"enclose", (PyCFunction)PyCursesWindow_Enclose, METH_VARARGS}, +#endif + {"erase", (PyCFunction)PyCursesWindow_werase, METH_NOARGS}, + {"getbegyx", (PyCFunction)PyCursesWindow_getbegyx, METH_NOARGS}, + {"getbkgd", (PyCFunction)PyCursesWindow_GetBkgd, METH_NOARGS}, + {"getch", (PyCFunction)PyCursesWindow_GetCh, METH_VARARGS}, + {"getkey", (PyCFunction)PyCursesWindow_GetKey, METH_VARARGS}, + {"getmaxyx", (PyCFunction)PyCursesWindow_getmaxyx, METH_NOARGS}, + {"getparyx", (PyCFunction)PyCursesWindow_getparyx, METH_NOARGS}, + {"getstr", (PyCFunction)PyCursesWindow_GetStr, METH_VARARGS}, + {"getyx", (PyCFunction)PyCursesWindow_getyx, METH_NOARGS}, + {"hline", (PyCFunction)PyCursesWindow_Hline, METH_VARARGS}, + {"idcok", (PyCFunction)PyCursesWindow_idcok, METH_VARARGS}, + {"idlok", (PyCFunction)PyCursesWindow_idlok, METH_VARARGS}, + {"immedok", (PyCFunction)PyCursesWindow_immedok, METH_VARARGS}, + {"inch", (PyCFunction)PyCursesWindow_InCh, METH_VARARGS}, + {"insch", (PyCFunction)PyCursesWindow_InsCh, METH_VARARGS}, + {"insdelln", (PyCFunction)PyCursesWindow_winsdelln, METH_VARARGS}, + {"insertln", (PyCFunction)PyCursesWindow_winsertln, METH_NOARGS}, + {"insnstr", (PyCFunction)PyCursesWindow_InsNStr, METH_VARARGS}, + {"insstr", (PyCFunction)PyCursesWindow_InsStr, METH_VARARGS}, + {"instr", (PyCFunction)PyCursesWindow_InStr, METH_VARARGS}, + {"is_linetouched", (PyCFunction)PyCursesWindow_Is_LineTouched, METH_VARARGS}, + {"is_wintouched", (PyCFunction)PyCursesWindow_is_wintouched, METH_NOARGS}, + {"keypad", (PyCFunction)PyCursesWindow_keypad, METH_VARARGS}, + {"leaveok", (PyCFunction)PyCursesWindow_leaveok, METH_VARARGS}, + {"move", (PyCFunction)PyCursesWindow_wmove, METH_VARARGS}, + {"mvderwin", (PyCFunction)PyCursesWindow_mvderwin, METH_VARARGS}, + {"mvwin", (PyCFunction)PyCursesWindow_mvwin, METH_VARARGS}, + {"nodelay", (PyCFunction)PyCursesWindow_nodelay, METH_VARARGS}, + {"notimeout", (PyCFunction)PyCursesWindow_notimeout, METH_VARARGS}, + {"noutrefresh", (PyCFunction)PyCursesWindow_NoOutRefresh, METH_VARARGS}, + /* Backward compatibility alias -- remove in Python 2.3 */ + {"nooutrefresh", (PyCFunction)PyCursesWindow_NoOutRefresh, METH_VARARGS}, + {"overlay", (PyCFunction)PyCursesWindow_Overlay, METH_VARARGS}, + {"overwrite", (PyCFunction)PyCursesWindow_Overwrite, + METH_VARARGS}, + {"putwin", (PyCFunction)PyCursesWindow_PutWin, METH_VARARGS}, + {"redrawln", (PyCFunction)PyCursesWindow_RedrawLine}, + {"redrawwin", (PyCFunction)PyCursesWindow_redrawwin, METH_NOARGS}, + {"refresh", (PyCFunction)PyCursesWindow_Refresh, METH_VARARGS}, +#ifndef STRICT_SYSV_CURSES + {"resize", (PyCFunction)PyCursesWindow_wresize, METH_VARARGS}, +#endif + {"scroll", (PyCFunction)PyCursesWindow_Scroll, METH_VARARGS}, + {"scrollok", (PyCFunction)PyCursesWindow_scrollok, METH_VARARGS}, + {"setscrreg", (PyCFunction)PyCursesWindow_SetScrollRegion, METH_VARARGS}, + {"standend", (PyCFunction)PyCursesWindow_wstandend, METH_NOARGS}, + {"standout", (PyCFunction)PyCursesWindow_wstandout, METH_NOARGS}, + {"subpad", (PyCFunction)PyCursesWindow_SubWin, METH_VARARGS}, + {"subwin", (PyCFunction)PyCursesWindow_SubWin, METH_VARARGS}, + {"syncdown", (PyCFunction)PyCursesWindow_wsyncdown, METH_NOARGS}, + {"syncok", (PyCFunction)PyCursesWindow_syncok, METH_VARARGS}, + {"syncup", (PyCFunction)PyCursesWindow_wsyncup, METH_NOARGS}, + {"timeout", (PyCFunction)PyCursesWindow_wtimeout, METH_VARARGS}, + {"touchline", (PyCFunction)PyCursesWindow_TouchLine, METH_VARARGS}, + {"touchwin", (PyCFunction)PyCursesWindow_touchwin, METH_NOARGS}, + {"untouchwin", (PyCFunction)PyCursesWindow_untouchwin, METH_NOARGS}, + {"vline", (PyCFunction)PyCursesWindow_Vline, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +PyCursesWindow_GetAttr(PyCursesWindowObject *self, char *name) +{ + return Py_FindMethod(PyCursesWindow_Methods, (PyObject *)self, name); +} + +/* -------------------------------------------------------*/ + +PyTypeObject PyCursesWindow_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_curses.curses window", /*tp_name*/ + sizeof(PyCursesWindowObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyCursesWindow_Dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)PyCursesWindow_GetAttr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +/********************************************************************* + Global Functions +**********************************************************************/ + +NoArgNoReturnFunction(beep) +NoArgNoReturnFunction(def_prog_mode) +NoArgNoReturnFunction(def_shell_mode) +NoArgNoReturnFunction(doupdate) +NoArgNoReturnFunction(endwin) +NoArgNoReturnFunction(flash) +NoArgNoReturnFunction(nocbreak) +NoArgNoReturnFunction(noecho) +NoArgNoReturnFunction(nonl) +NoArgNoReturnFunction(noraw) +NoArgNoReturnFunction(reset_prog_mode) +NoArgNoReturnFunction(reset_shell_mode) +NoArgNoReturnFunction(resetty) +NoArgNoReturnFunction(savetty) + +NoArgOrFlagNoReturnFunction(cbreak) +NoArgOrFlagNoReturnFunction(echo) +NoArgOrFlagNoReturnFunction(nl) +NoArgOrFlagNoReturnFunction(raw) + +NoArgReturnIntFunction(baudrate) +NoArgReturnIntFunction(termattrs) + +NoArgReturnStringFunction(termname) +NoArgReturnStringFunction(longname) + +NoArgTrueFalseFunction(can_change_color) +NoArgTrueFalseFunction(has_colors) +NoArgTrueFalseFunction(has_ic) +NoArgTrueFalseFunction(has_il) +NoArgTrueFalseFunction(isendwin) +NoArgNoReturnVoidFunction(filter) +NoArgNoReturnVoidFunction(flushinp) +NoArgNoReturnVoidFunction(noqiflush) + +static PyObject * +PyCurses_Color_Content(PyObject *self, PyObject *args) +{ + short color,r,g,b; + + PyCursesInitialised + PyCursesInitialisedColor + + if (!PyArg_ParseTuple(args, "h:color_content", &color)) return NULL; + + if (color_content(color, &r, &g, &b) != ERR) + return Py_BuildValue("(iii)", r, g, b); + else { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. Check value of COLORS."); + return NULL; + } +} + +static PyObject * +PyCurses_color_pair(PyObject *self, PyObject *args) +{ + int n; + + PyCursesInitialised + PyCursesInitialisedColor + + if (!PyArg_ParseTuple(args, "i:color_pair", &n)) return NULL; + return PyInt_FromLong((long) (n << 8)); +} + +static PyObject * +PyCurses_Curs_Set(PyObject *self, PyObject *args) +{ + int vis,erg; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args, "i:curs_set", &vis)) return NULL; + + erg = curs_set(vis); + if (erg == ERR) return PyCursesCheckERR(erg, "curs_set"); + + return PyInt_FromLong((long) erg); +} + +static PyObject * +PyCurses_Delay_Output(PyObject *self, PyObject *args) +{ + int ms; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args, "i:delay_output", &ms)) return NULL; + + return PyCursesCheckERR(delay_output(ms), "delay_output"); +} + +static PyObject * +PyCurses_EraseChar(PyObject *self) +{ + char ch; + + PyCursesInitialised + + ch = erasechar(); + + return PyString_FromStringAndSize(&ch, 1); +} + +static PyObject * +PyCurses_getsyx(PyObject *self) +{ + int x,y; + + PyCursesInitialised + + getsyx(y, x); + + return Py_BuildValue("(ii)", y, x); +} + +#ifdef NCURSES_MOUSE_VERSION +static PyObject * +PyCurses_GetMouse(PyObject *self) +{ + int rtn; + MEVENT event; + + PyCursesInitialised + + rtn = getmouse( &event ); + if (rtn == ERR) { + PyErr_SetString(PyCursesError, "getmouse() returned ERR"); + return NULL; + } + return Py_BuildValue("(hiiil)", + (short)event.id, + event.x, event.y, event.z, + (long) event.bstate); +} + +static PyObject * +PyCurses_UngetMouse(PyObject *self, PyObject *args) +{ + MEVENT event; + + PyCursesInitialised + if (!PyArg_ParseTuple(args, "hiiil", + &event.id, + &event.x, &event.y, &event.z, + (int *) &event.bstate)) + return NULL; + + return PyCursesCheckERR(ungetmouse(&event), "ungetmouse"); +} +#endif + +static PyObject * +PyCurses_GetWin(PyCursesWindowObject *self, PyObject *temp) +{ + WINDOW *win; + + PyCursesInitialised + + if (!PyFile_Check(temp)) { + PyErr_SetString(PyExc_TypeError, "argument must be a file object"); + return NULL; + } + + win = getwin(PyFile_AsFile(temp)); + + if (win == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + + return PyCursesWindow_New(win); +} + +static PyObject * +PyCurses_HalfDelay(PyObject *self, PyObject *args) +{ + unsigned char tenths; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args, "b:halfdelay", &tenths)) return NULL; + + return PyCursesCheckERR(halfdelay(tenths), "halfdelay"); +} + +#ifndef STRICT_SYSV_CURSES + /* No has_key! */ +static PyObject * PyCurses_has_key(PyObject *self, PyObject *args) +{ + int ch; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"i",&ch)) return NULL; + + if (has_key(ch) == FALSE) { + Py_INCREF(Py_False); + return Py_False; + } + Py_INCREF(Py_True); + return Py_True; +} +#endif /* STRICT_SYSV_CURSES */ + +static PyObject * +PyCurses_Init_Color(PyObject *self, PyObject *args) +{ + short color, r, g, b; + + PyCursesInitialised + PyCursesInitialisedColor + + switch(PyTuple_Size(args)) { + case 4: + if (!PyArg_ParseTuple(args, "hhhh;color,r,g,b", &color, &r, &g, &b)) return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "init_color requires 4 arguments"); + return NULL; + } + + return PyCursesCheckERR(init_color(color, r, g, b), "init_color"); +} + +static PyObject * +PyCurses_Init_Pair(PyObject *self, PyObject *args) +{ + short pair, f, b; + + PyCursesInitialised + PyCursesInitialisedColor + + if (PyTuple_Size(args) != 3) { + PyErr_SetString(PyExc_TypeError, "init_pair requires 3 arguments"); + return NULL; + } + + if (!PyArg_ParseTuple(args, "hhh;pair, f, b", &pair, &f, &b)) return NULL; + + return PyCursesCheckERR(init_pair(pair, f, b), "init_pair"); +} + +static PyObject *ModDict; + +static PyObject * +PyCurses_InitScr(PyObject *self) +{ + WINDOW *win; + + if (initialised == TRUE) { + wrefresh(stdscr); + return (PyObject *)PyCursesWindow_New(stdscr); + } + + win = initscr(); + + if (win == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + + initialised = initialised_setupterm = TRUE; + +/* This was moved from initcurses() because it core dumped on SGI, + where they're not defined until you've called initscr() */ +#define SetDictInt(string,ch) \ + do { \ + PyObject *o = PyInt_FromLong((long) (ch)); \ + if (o && PyDict_SetItemString(ModDict, string, o) == 0) { \ + Py_DECREF(o); \ + } \ + } while (0) + + /* Here are some graphic symbols you can use */ + SetDictInt("ACS_ULCORNER", (ACS_ULCORNER)); + SetDictInt("ACS_LLCORNER", (ACS_LLCORNER)); + SetDictInt("ACS_URCORNER", (ACS_URCORNER)); + SetDictInt("ACS_LRCORNER", (ACS_LRCORNER)); + SetDictInt("ACS_LTEE", (ACS_LTEE)); + SetDictInt("ACS_RTEE", (ACS_RTEE)); + SetDictInt("ACS_BTEE", (ACS_BTEE)); + SetDictInt("ACS_TTEE", (ACS_TTEE)); + SetDictInt("ACS_HLINE", (ACS_HLINE)); + SetDictInt("ACS_VLINE", (ACS_VLINE)); + SetDictInt("ACS_PLUS", (ACS_PLUS)); +#if !defined(__hpux) || defined(HAVE_NCURSES_H) + /* On HP/UX 11, these are of type cchar_t, which is not an + integral type. If this is a problem on more platforms, a + configure test should be added to determine whether ACS_S1 + is of integral type. */ + SetDictInt("ACS_S1", (ACS_S1)); + SetDictInt("ACS_S9", (ACS_S9)); + SetDictInt("ACS_DIAMOND", (ACS_DIAMOND)); + SetDictInt("ACS_CKBOARD", (ACS_CKBOARD)); + SetDictInt("ACS_DEGREE", (ACS_DEGREE)); + SetDictInt("ACS_PLMINUS", (ACS_PLMINUS)); + SetDictInt("ACS_BULLET", (ACS_BULLET)); + SetDictInt("ACS_LARROW", (ACS_LARROW)); + SetDictInt("ACS_RARROW", (ACS_RARROW)); + SetDictInt("ACS_DARROW", (ACS_DARROW)); + SetDictInt("ACS_UARROW", (ACS_UARROW)); + SetDictInt("ACS_BOARD", (ACS_BOARD)); + SetDictInt("ACS_LANTERN", (ACS_LANTERN)); + SetDictInt("ACS_BLOCK", (ACS_BLOCK)); +#endif + SetDictInt("ACS_BSSB", (ACS_ULCORNER)); + SetDictInt("ACS_SSBB", (ACS_LLCORNER)); + SetDictInt("ACS_BBSS", (ACS_URCORNER)); + SetDictInt("ACS_SBBS", (ACS_LRCORNER)); + SetDictInt("ACS_SBSS", (ACS_RTEE)); + SetDictInt("ACS_SSSB", (ACS_LTEE)); + SetDictInt("ACS_SSBS", (ACS_BTEE)); + SetDictInt("ACS_BSSS", (ACS_TTEE)); + SetDictInt("ACS_BSBS", (ACS_HLINE)); + SetDictInt("ACS_SBSB", (ACS_VLINE)); + SetDictInt("ACS_SSSS", (ACS_PLUS)); + + /* The following are never available with strict SYSV curses */ +#ifdef ACS_S3 + SetDictInt("ACS_S3", (ACS_S3)); +#endif +#ifdef ACS_S7 + SetDictInt("ACS_S7", (ACS_S7)); +#endif +#ifdef ACS_LEQUAL + SetDictInt("ACS_LEQUAL", (ACS_LEQUAL)); +#endif +#ifdef ACS_GEQUAL + SetDictInt("ACS_GEQUAL", (ACS_GEQUAL)); +#endif +#ifdef ACS_PI + SetDictInt("ACS_PI", (ACS_PI)); +#endif +#ifdef ACS_NEQUAL + SetDictInt("ACS_NEQUAL", (ACS_NEQUAL)); +#endif +#ifdef ACS_STERLING + SetDictInt("ACS_STERLING", (ACS_STERLING)); +#endif + + SetDictInt("LINES", LINES); + SetDictInt("COLS", COLS); + + return (PyObject *)PyCursesWindow_New(win); +} + +static PyObject * +PyCurses_setupterm(PyObject* self, PyObject *args, PyObject* keywds) +{ + int fd = -1; + int err; + char* termstr = NULL; + + static char *kwlist[] = {"term", "fd", NULL}; + + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|zi:setupterm", kwlist, &termstr, &fd)) { + return NULL; + } + + if (fd == -1) { + PyObject* sys_stdout; + + sys_stdout = PySys_GetObject("stdout"); + + if (sys_stdout == NULL) { + PyErr_SetString( + PyCursesError, + "lost sys.stdout"); + return NULL; + } + + fd = PyObject_AsFileDescriptor(sys_stdout); + + if (fd == -1) { + return NULL; + } + } + + if (setupterm(termstr,fd,&err) == ERR) { + char* s = "setupterm: unknown error"; + + if (err == 0) { + s = "setupterm: could not find terminal"; + } else if (err == -1) { + s = "setupterm: could not find terminfo database"; + } + + PyErr_SetString(PyCursesError,s); + return NULL; + } + + initialised_setupterm = TRUE; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyCurses_IntrFlush(PyObject *self, PyObject *args) +{ + int ch; + + PyCursesInitialised + + switch(PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args,"i;True(1), False(0)",&ch)) return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "intrflush requires 1 argument"); + return NULL; + } + + return PyCursesCheckERR(intrflush(NULL,ch), "intrflush"); +} + +#ifdef HAVE_CURSES_IS_TERM_RESIZED +static PyObject * +PyCurses_Is_Term_Resized(PyObject *self, PyObject *args) +{ + int lines; + int columns; + int result; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"ii:is_term_resized", &lines, &columns)) + return NULL; + result = is_term_resized(lines, columns); + if (result == TRUE) { + Py_INCREF(Py_True); + return Py_True; + } else { + Py_INCREF(Py_False); + return Py_False; + } +} +#endif /* HAVE_CURSES_IS_TERM_RESIZED */ + +#if !defined(__NetBSD__) +static PyObject * +PyCurses_KeyName(PyObject *self, PyObject *args) +{ + const char *knp; + int ch; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"i",&ch)) return NULL; + + if (ch < 0) { + PyErr_SetString(PyExc_ValueError, "invalid key number"); + return NULL; + } + knp = keyname(ch); + + return PyString_FromString((knp == NULL) ? "" : (char *)knp); +} +#endif + +static PyObject * +PyCurses_KillChar(PyObject *self) +{ + char ch; + + ch = killchar(); + + return PyString_FromStringAndSize(&ch, 1); +} + +static PyObject * +PyCurses_Meta(PyObject *self, PyObject *args) +{ + int ch; + + PyCursesInitialised + + switch(PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args,"i;True(1), False(0)",&ch)) return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "meta requires 1 argument"); + return NULL; + } + + return PyCursesCheckERR(meta(stdscr, ch), "meta"); +} + +#ifdef NCURSES_MOUSE_VERSION +static PyObject * +PyCurses_MouseInterval(PyObject *self, PyObject *args) +{ + int interval; + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"i;interval",&interval)) + return NULL; + return PyCursesCheckERR(mouseinterval(interval), "mouseinterval"); +} + +static PyObject * +PyCurses_MouseMask(PyObject *self, PyObject *args) +{ + int newmask; + mmask_t oldmask, availmask; + + PyCursesInitialised + if (!PyArg_ParseTuple(args,"i;mousemask",&newmask)) + return NULL; + availmask = mousemask(newmask, &oldmask); + return Py_BuildValue("(ll)", (long)availmask, (long)oldmask); +} +#endif + +static PyObject * +PyCurses_Napms(PyObject *self, PyObject *args) +{ + int ms; + + PyCursesInitialised + if (!PyArg_ParseTuple(args, "i;ms", &ms)) return NULL; + + return Py_BuildValue("i", napms(ms)); +} + + +static PyObject * +PyCurses_NewPad(PyObject *self, PyObject *args) +{ + WINDOW *win; + int nlines, ncols; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"ii;nlines,ncols",&nlines,&ncols)) return NULL; + + win = newpad(nlines, ncols); + + if (win == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + + return (PyObject *)PyCursesWindow_New(win); +} + +static PyObject * +PyCurses_NewWindow(PyObject *self, PyObject *args) +{ + WINDOW *win; + int nlines, ncols, begin_y=0, begin_x=0; + + PyCursesInitialised + + switch (PyTuple_Size(args)) { + case 2: + if (!PyArg_ParseTuple(args,"ii;nlines,ncols",&nlines,&ncols)) + return NULL; + break; + case 4: + if (!PyArg_ParseTuple(args, "iiii;nlines,ncols,begin_y,begin_x", + &nlines,&ncols,&begin_y,&begin_x)) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "newwin requires 2 or 4 arguments"); + return NULL; + } + + win = newwin(nlines,ncols,begin_y,begin_x); + if (win == NULL) { + PyErr_SetString(PyCursesError, catchall_NULL); + return NULL; + } + + return (PyObject *)PyCursesWindow_New(win); +} + +static PyObject * +PyCurses_Pair_Content(PyObject *self, PyObject *args) +{ + short pair,f,b; + + PyCursesInitialised + PyCursesInitialisedColor + + switch(PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "h;pair", &pair)) return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "pair_content requires 1 argument"); + return NULL; + } + + if (pair_content(pair, &f, &b)==ERR) { + PyErr_SetString(PyCursesError, + "Argument 1 was out of range. (1..COLOR_PAIRS-1)"); + return NULL; + } + + return Py_BuildValue("(ii)", f, b); +} + +static PyObject * +PyCurses_pair_number(PyObject *self, PyObject *args) +{ + int n; + + PyCursesInitialised + PyCursesInitialisedColor + + switch(PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args, "i;pairvalue", &n)) return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, + "pair_number requires 1 argument"); + return NULL; + } + + return PyInt_FromLong((long) ((n & A_COLOR) >> 8)); +} + +static PyObject * +PyCurses_Putp(PyObject *self, PyObject *args) +{ + char *str; + + if (!PyArg_ParseTuple(args,"s;str", &str)) return NULL; + return PyCursesCheckERR(putp(str), "putp"); +} + +static PyObject * +PyCurses_QiFlush(PyObject *self, PyObject *args) +{ + int flag = 0; + + PyCursesInitialised + + switch(PyTuple_Size(args)) { + case 0: + qiflush(); + Py_INCREF(Py_None); + return Py_None; + case 1: + if (!PyArg_ParseTuple(args, "i;True(1) or False(0)", &flag)) return NULL; + if (flag) qiflush(); + else noqiflush(); + Py_INCREF(Py_None); + return Py_None; + default: + PyErr_SetString(PyExc_TypeError, "qiflush requires 0 or 1 arguments"); + return NULL; + } +} + +/* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES + * and _curses.COLS */ +static int +update_lines_cols(void) +{ + PyObject *o; + PyObject *m = PyImport_ImportModule("curses"); + + if (!m) + return 0; + + o = PyInt_FromLong(LINES); + if (!o) { + Py_DECREF(m); + return 0; + } + if (PyObject_SetAttrString(m, "LINES", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + if (PyDict_SetItemString(ModDict, "LINES", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + Py_DECREF(o); + o = PyInt_FromLong(COLS); + if (!o) { + Py_DECREF(m); + return 0; + } + if (PyObject_SetAttrString(m, "COLS", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + if (PyDict_SetItemString(ModDict, "COLS", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + Py_DECREF(o); + Py_DECREF(m); + return 1; +} + +#ifdef HAVE_CURSES_RESIZETERM +static PyObject * +PyCurses_ResizeTerm(PyObject *self, PyObject *args) +{ + int lines; + int columns; + PyObject *result; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns)) + return NULL; + + result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm"); + if (!result) + return NULL; + if (!update_lines_cols()) + return NULL; + return result; +} + +#endif + +#ifdef HAVE_CURSES_RESIZE_TERM +static PyObject * +PyCurses_Resize_Term(PyObject *self, PyObject *args) +{ + int lines; + int columns; + + PyObject *result; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns)) + return NULL; + + result = PyCursesCheckERR(resize_term(lines, columns), "resize_term"); + if (!result) + return NULL; + if (!update_lines_cols()) + return NULL; + return result; +} +#endif /* HAVE_CURSES_RESIZE_TERM */ + +static PyObject * +PyCurses_setsyx(PyObject *self, PyObject *args) +{ + int y,x; + + PyCursesInitialised + + if (PyTuple_Size(args)!=2) { + PyErr_SetString(PyExc_TypeError, "setsyx requires 2 arguments"); + return NULL; + } + + if (!PyArg_ParseTuple(args, "ii;y, x", &y, &x)) return NULL; + + setsyx(y,x); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +PyCurses_Start_Color(PyObject *self) +{ + int code; + PyObject *c, *cp; + + PyCursesInitialised + + code = start_color(); + if (code != ERR) { + initialisedcolors = TRUE; + c = PyInt_FromLong((long) COLORS); + PyDict_SetItemString(ModDict, "COLORS", c); + Py_DECREF(c); + cp = PyInt_FromLong((long) COLOR_PAIRS); + PyDict_SetItemString(ModDict, "COLOR_PAIRS", cp); + Py_DECREF(cp); + Py_INCREF(Py_None); + return Py_None; + } else { + PyErr_SetString(PyCursesError, "start_color() returned ERR"); + return NULL; + } +} + +static PyObject * +PyCurses_tigetflag(PyObject *self, PyObject *args) +{ + char *capname; + + PyCursesSetupTermCalled; + + if (!PyArg_ParseTuple(args, "z", &capname)) + return NULL; + + return PyInt_FromLong( (long) tigetflag( capname ) ); +} + +static PyObject * +PyCurses_tigetnum(PyObject *self, PyObject *args) +{ + char *capname; + + PyCursesSetupTermCalled; + + if (!PyArg_ParseTuple(args, "z", &capname)) + return NULL; + + return PyInt_FromLong( (long) tigetnum( capname ) ); +} + +static PyObject * +PyCurses_tigetstr(PyObject *self, PyObject *args) +{ + char *capname; + + PyCursesSetupTermCalled; + + if (!PyArg_ParseTuple(args, "z", &capname)) + return NULL; + + capname = tigetstr( capname ); + if (capname == 0 || capname == (char*) -1) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString( capname ); +} + +static PyObject * +PyCurses_tparm(PyObject *self, PyObject *args) +{ + char* fmt; + char* result = NULL; + int i1=0,i2=0,i3=0,i4=0,i5=0,i6=0,i7=0,i8=0,i9=0; + + PyCursesSetupTermCalled; + + if (!PyArg_ParseTuple(args, "s|iiiiiiiii:tparm", + &fmt, &i1, &i2, &i3, &i4, + &i5, &i6, &i7, &i8, &i9)) { + return NULL; + } + + result = tparm(fmt,i1,i2,i3,i4,i5,i6,i7,i8,i9); + if (!result) { + PyErr_SetString(PyCursesError, "tparm() returned NULL"); + return NULL; + } + + return PyString_FromString(result); +} + +static PyObject * +PyCurses_TypeAhead(PyObject *self, PyObject *args) +{ + int fd; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"i;fd",&fd)) return NULL; + + return PyCursesCheckERR(typeahead( fd ), "typeahead"); +} + +static PyObject * +PyCurses_UnCtrl(PyObject *self, PyObject *args) +{ + PyObject *temp; + chtype ch; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"O;ch or int",&temp)) return NULL; + + if (PyInt_Check(temp)) + ch = (chtype) PyInt_AsLong(temp); + else if (PyString_Check(temp)) + ch = (chtype) *PyString_AsString(temp); + else { + PyErr_SetString(PyExc_TypeError, "argument must be a ch or an int"); + return NULL; + } + + return PyString_FromString(unctrl(ch)); +} + +static PyObject * +PyCurses_UngetCh(PyObject *self, PyObject *args) +{ + PyObject *temp; + int ch; + + PyCursesInitialised + + if (!PyArg_ParseTuple(args,"O;ch or int",&temp)) return NULL; + + if (PyInt_Check(temp)) + ch = (int) PyInt_AsLong(temp); + else if (PyString_Check(temp)) + ch = (int) *PyString_AsString(temp); + else { + PyErr_SetString(PyExc_TypeError, "argument must be a ch or an int"); + return NULL; + } + + return PyCursesCheckERR(ungetch(ch), "ungetch"); +} + +static PyObject * +PyCurses_Use_Env(PyObject *self, PyObject *args) +{ + int flag; + + PyCursesInitialised + + switch(PyTuple_Size(args)) { + case 1: + if (!PyArg_ParseTuple(args,"i;True(1), False(0)",&flag)) + return NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "use_env requires 1 argument"); + return NULL; + } + use_env(flag); + Py_INCREF(Py_None); + return Py_None; +} + +#ifndef STRICT_SYSV_CURSES +static PyObject * +PyCurses_Use_Default_Colors(PyObject *self) +{ + int code; + + PyCursesInitialised + PyCursesInitialisedColor + + code = use_default_colors(); + if (code != ERR) { + Py_INCREF(Py_None); + return Py_None; + } else { + PyErr_SetString(PyCursesError, "use_default_colors() returned ERR"); + return NULL; + } +} +#endif /* STRICT_SYSV_CURSES */ + +/* List of functions defined in the module */ + +static PyMethodDef PyCurses_methods[] = { + {"baudrate", (PyCFunction)PyCurses_baudrate, METH_NOARGS}, + {"beep", (PyCFunction)PyCurses_beep, METH_NOARGS}, + {"can_change_color", (PyCFunction)PyCurses_can_change_color, METH_NOARGS}, + {"cbreak", (PyCFunction)PyCurses_cbreak, METH_VARARGS}, + {"color_content", (PyCFunction)PyCurses_Color_Content, METH_VARARGS}, + {"color_pair", (PyCFunction)PyCurses_color_pair, METH_VARARGS}, + {"curs_set", (PyCFunction)PyCurses_Curs_Set, METH_VARARGS}, + {"def_prog_mode", (PyCFunction)PyCurses_def_prog_mode, METH_NOARGS}, + {"def_shell_mode", (PyCFunction)PyCurses_def_shell_mode, METH_NOARGS}, + {"delay_output", (PyCFunction)PyCurses_Delay_Output, METH_VARARGS}, + {"doupdate", (PyCFunction)PyCurses_doupdate, METH_NOARGS}, + {"echo", (PyCFunction)PyCurses_echo, METH_VARARGS}, + {"endwin", (PyCFunction)PyCurses_endwin, METH_NOARGS}, + {"erasechar", (PyCFunction)PyCurses_EraseChar, METH_NOARGS}, + {"filter", (PyCFunction)PyCurses_filter, METH_NOARGS}, + {"flash", (PyCFunction)PyCurses_flash, METH_NOARGS}, + {"flushinp", (PyCFunction)PyCurses_flushinp, METH_NOARGS}, +#ifdef NCURSES_MOUSE_VERSION + {"getmouse", (PyCFunction)PyCurses_GetMouse, METH_NOARGS}, + {"ungetmouse", (PyCFunction)PyCurses_UngetMouse, METH_VARARGS}, +#endif + {"getsyx", (PyCFunction)PyCurses_getsyx, METH_NOARGS}, + {"getwin", (PyCFunction)PyCurses_GetWin, METH_O}, + {"has_colors", (PyCFunction)PyCurses_has_colors, METH_NOARGS}, + {"has_ic", (PyCFunction)PyCurses_has_ic, METH_NOARGS}, + {"has_il", (PyCFunction)PyCurses_has_il, METH_NOARGS}, +#ifndef STRICT_SYSV_CURSES + {"has_key", (PyCFunction)PyCurses_has_key, METH_VARARGS}, +#endif + {"halfdelay", (PyCFunction)PyCurses_HalfDelay, METH_VARARGS}, + {"init_color", (PyCFunction)PyCurses_Init_Color, METH_VARARGS}, + {"init_pair", (PyCFunction)PyCurses_Init_Pair, METH_VARARGS}, + {"initscr", (PyCFunction)PyCurses_InitScr, METH_NOARGS}, + {"intrflush", (PyCFunction)PyCurses_IntrFlush, METH_VARARGS}, + {"isendwin", (PyCFunction)PyCurses_isendwin, METH_NOARGS}, +#ifdef HAVE_CURSES_IS_TERM_RESIZED + {"is_term_resized", (PyCFunction)PyCurses_Is_Term_Resized, METH_VARARGS}, +#endif +#if !defined(__NetBSD__) + {"keyname", (PyCFunction)PyCurses_KeyName, METH_VARARGS}, +#endif + {"killchar", (PyCFunction)PyCurses_KillChar, METH_NOARGS}, + {"longname", (PyCFunction)PyCurses_longname, METH_NOARGS}, + {"meta", (PyCFunction)PyCurses_Meta, METH_VARARGS}, +#ifdef NCURSES_MOUSE_VERSION + {"mouseinterval", (PyCFunction)PyCurses_MouseInterval, METH_VARARGS}, + {"mousemask", (PyCFunction)PyCurses_MouseMask, METH_VARARGS}, +#endif + {"napms", (PyCFunction)PyCurses_Napms, METH_VARARGS}, + {"newpad", (PyCFunction)PyCurses_NewPad, METH_VARARGS}, + {"newwin", (PyCFunction)PyCurses_NewWindow, METH_VARARGS}, + {"nl", (PyCFunction)PyCurses_nl, METH_VARARGS}, + {"nocbreak", (PyCFunction)PyCurses_nocbreak, METH_NOARGS}, + {"noecho", (PyCFunction)PyCurses_noecho, METH_NOARGS}, + {"nonl", (PyCFunction)PyCurses_nonl, METH_NOARGS}, + {"noqiflush", (PyCFunction)PyCurses_noqiflush, METH_NOARGS}, + {"noraw", (PyCFunction)PyCurses_noraw, METH_NOARGS}, + {"pair_content", (PyCFunction)PyCurses_Pair_Content, METH_VARARGS}, + {"pair_number", (PyCFunction)PyCurses_pair_number, METH_VARARGS}, + {"putp", (PyCFunction)PyCurses_Putp, METH_VARARGS}, + {"qiflush", (PyCFunction)PyCurses_QiFlush, METH_VARARGS}, + {"raw", (PyCFunction)PyCurses_raw, METH_VARARGS}, + {"reset_prog_mode", (PyCFunction)PyCurses_reset_prog_mode, METH_NOARGS}, + {"reset_shell_mode", (PyCFunction)PyCurses_reset_shell_mode, METH_NOARGS}, + {"resetty", (PyCFunction)PyCurses_resetty, METH_NOARGS}, +#ifdef HAVE_CURSES_RESIZETERM + {"resizeterm", (PyCFunction)PyCurses_ResizeTerm, METH_VARARGS}, +#endif +#ifdef HAVE_CURSES_RESIZE_TERM + {"resize_term", (PyCFunction)PyCurses_Resize_Term, METH_VARARGS}, +#endif + {"savetty", (PyCFunction)PyCurses_savetty, METH_NOARGS}, + {"setsyx", (PyCFunction)PyCurses_setsyx, METH_VARARGS}, + {"setupterm", (PyCFunction)PyCurses_setupterm, + METH_VARARGS|METH_KEYWORDS}, + {"start_color", (PyCFunction)PyCurses_Start_Color, METH_NOARGS}, + {"termattrs", (PyCFunction)PyCurses_termattrs, METH_NOARGS}, + {"termname", (PyCFunction)PyCurses_termname, METH_NOARGS}, + {"tigetflag", (PyCFunction)PyCurses_tigetflag, METH_VARARGS}, + {"tigetnum", (PyCFunction)PyCurses_tigetnum, METH_VARARGS}, + {"tigetstr", (PyCFunction)PyCurses_tigetstr, METH_VARARGS}, + {"tparm", (PyCFunction)PyCurses_tparm, METH_VARARGS}, + {"typeahead", (PyCFunction)PyCurses_TypeAhead, METH_VARARGS}, + {"unctrl", (PyCFunction)PyCurses_UnCtrl, METH_VARARGS}, + {"ungetch", (PyCFunction)PyCurses_UngetCh, METH_VARARGS}, + {"use_env", (PyCFunction)PyCurses_Use_Env, METH_VARARGS}, +#ifndef STRICT_SYSV_CURSES + {"use_default_colors", (PyCFunction)PyCurses_Use_Default_Colors, METH_NOARGS}, +#endif + {NULL, NULL} /* sentinel */ +}; + +/* Initialization function for the module */ + +PyMODINIT_FUNC +init_curses(void) +{ + PyObject *m, *d, *v, *c_api_object; + static void *PyCurses_API[PyCurses_API_pointers]; + + /* Initialize object type */ + PyCursesWindow_Type.ob_type = &PyType_Type; + + /* Initialize the C API pointer array */ + PyCurses_API[0] = (void *)&PyCursesWindow_Type; + PyCurses_API[1] = (void *)func_PyCursesSetupTermCalled; + PyCurses_API[2] = (void *)func_PyCursesInitialised; + PyCurses_API[3] = (void *)func_PyCursesInitialisedColor; + + /* Create the module and add the functions */ + m = Py_InitModule("_curses", PyCurses_methods); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + if (d == NULL) + return; + ModDict = d; /* For PyCurses_InitScr to use later */ + + /* Add a CObject for the C API */ + c_api_object = PyCObject_FromVoidPtr((void *)PyCurses_API, NULL); + PyDict_SetItemString(d, "_C_API", c_api_object); + Py_DECREF(c_api_object); + + /* For exception curses.error */ + PyCursesError = PyErr_NewException("_curses.error", NULL, NULL); + PyDict_SetItemString(d, "error", PyCursesError); + + /* Make the version available */ + v = PyString_FromString(PyCursesVersion); + PyDict_SetItemString(d, "version", v); + PyDict_SetItemString(d, "__version__", v); + Py_DECREF(v); + + SetDictInt("ERR", ERR); + SetDictInt("OK", OK); + + /* Here are some attributes you can add to chars to print */ + + SetDictInt("A_ATTRIBUTES", A_ATTRIBUTES); + SetDictInt("A_NORMAL", A_NORMAL); + SetDictInt("A_STANDOUT", A_STANDOUT); + SetDictInt("A_UNDERLINE", A_UNDERLINE); + SetDictInt("A_REVERSE", A_REVERSE); + SetDictInt("A_BLINK", A_BLINK); + SetDictInt("A_DIM", A_DIM); + SetDictInt("A_BOLD", A_BOLD); + SetDictInt("A_ALTCHARSET", A_ALTCHARSET); +#if !defined(__NetBSD__) + SetDictInt("A_INVIS", A_INVIS); +#endif + SetDictInt("A_PROTECT", A_PROTECT); + SetDictInt("A_CHARTEXT", A_CHARTEXT); + SetDictInt("A_COLOR", A_COLOR); + + /* The following are never available with strict SYSV curses */ +#ifdef A_HORIZONTAL + SetDictInt("A_HORIZONTAL", A_HORIZONTAL); +#endif +#ifdef A_LEFT + SetDictInt("A_LEFT", A_LEFT); +#endif +#ifdef A_LOW + SetDictInt("A_LOW", A_LOW); +#endif +#ifdef A_RIGHT + SetDictInt("A_RIGHT", A_RIGHT); +#endif +#ifdef A_TOP + SetDictInt("A_TOP", A_TOP); +#endif +#ifdef A_VERTICAL + SetDictInt("A_VERTICAL", A_VERTICAL); +#endif + + SetDictInt("COLOR_BLACK", COLOR_BLACK); + SetDictInt("COLOR_RED", COLOR_RED); + SetDictInt("COLOR_GREEN", COLOR_GREEN); + SetDictInt("COLOR_YELLOW", COLOR_YELLOW); + SetDictInt("COLOR_BLUE", COLOR_BLUE); + SetDictInt("COLOR_MAGENTA", COLOR_MAGENTA); + SetDictInt("COLOR_CYAN", COLOR_CYAN); + SetDictInt("COLOR_WHITE", COLOR_WHITE); + +#ifdef NCURSES_MOUSE_VERSION + /* Mouse-related constants */ + SetDictInt("BUTTON1_PRESSED", BUTTON1_PRESSED); + SetDictInt("BUTTON1_RELEASED", BUTTON1_RELEASED); + SetDictInt("BUTTON1_CLICKED", BUTTON1_CLICKED); + SetDictInt("BUTTON1_DOUBLE_CLICKED", BUTTON1_DOUBLE_CLICKED); + SetDictInt("BUTTON1_TRIPLE_CLICKED", BUTTON1_TRIPLE_CLICKED); + + SetDictInt("BUTTON2_PRESSED", BUTTON2_PRESSED); + SetDictInt("BUTTON2_RELEASED", BUTTON2_RELEASED); + SetDictInt("BUTTON2_CLICKED", BUTTON2_CLICKED); + SetDictInt("BUTTON2_DOUBLE_CLICKED", BUTTON2_DOUBLE_CLICKED); + SetDictInt("BUTTON2_TRIPLE_CLICKED", BUTTON2_TRIPLE_CLICKED); + + SetDictInt("BUTTON3_PRESSED", BUTTON3_PRESSED); + SetDictInt("BUTTON3_RELEASED", BUTTON3_RELEASED); + SetDictInt("BUTTON3_CLICKED", BUTTON3_CLICKED); + SetDictInt("BUTTON3_DOUBLE_CLICKED", BUTTON3_DOUBLE_CLICKED); + SetDictInt("BUTTON3_TRIPLE_CLICKED", BUTTON3_TRIPLE_CLICKED); + + SetDictInt("BUTTON4_PRESSED", BUTTON4_PRESSED); + SetDictInt("BUTTON4_RELEASED", BUTTON4_RELEASED); + SetDictInt("BUTTON4_CLICKED", BUTTON4_CLICKED); + SetDictInt("BUTTON4_DOUBLE_CLICKED", BUTTON4_DOUBLE_CLICKED); + SetDictInt("BUTTON4_TRIPLE_CLICKED", BUTTON4_TRIPLE_CLICKED); + + SetDictInt("BUTTON_SHIFT", BUTTON_SHIFT); + SetDictInt("BUTTON_CTRL", BUTTON_CTRL); + SetDictInt("BUTTON_ALT", BUTTON_ALT); + + SetDictInt("ALL_MOUSE_EVENTS", ALL_MOUSE_EVENTS); + SetDictInt("REPORT_MOUSE_POSITION", REPORT_MOUSE_POSITION); +#endif + /* Now set everything up for KEY_ variables */ + { + int key; + char *key_n; + char *key_n2; +#if !defined(__NetBSD__) + for (key=KEY_MIN;key < KEY_MAX; key++) { + key_n = (char *)keyname(key); + if (key_n == NULL || strcmp(key_n,"UNKNOWN KEY")==0) + continue; + if (strncmp(key_n,"KEY_F(",6)==0) { + char *p1, *p2; + key_n2 = malloc(strlen(key_n)+1); + if (!key_n2) { + PyErr_NoMemory(); + break; + } + p1 = key_n; + p2 = key_n2; + while (*p1) { + if (*p1 != '(' && *p1 != ')') { + *p2 = *p1; + p2++; + } + p1++; + } + *p2 = (char)0; + } else + key_n2 = key_n; + SetDictInt(key_n2,key); + if (key_n2 != key_n) + free(key_n2); + } +#endif + SetDictInt("KEY_MIN", KEY_MIN); + SetDictInt("KEY_MAX", KEY_MAX); + } +} diff --git a/sys/src/cmd/python/Modules/_elementtree.c b/sys/src/cmd/python/Modules/_elementtree.c new file mode 100644 index 000000000..f21cf5685 --- /dev/null +++ b/sys/src/cmd/python/Modules/_elementtree.c @@ -0,0 +1,2815 @@ +/* + * ElementTree + * $Id: _elementtree.c 2657 2006-03-12 20:50:32Z fredrik $ + * + * elementtree accelerator + * + * History: + * 1999-06-20 fl created (as part of sgmlop) + * 2001-05-29 fl effdom edition + * 2001-06-05 fl backported to unix; fixed bogus free in clear + * 2001-07-10 fl added findall helper + * 2003-02-27 fl elementtree edition (alpha) + * 2004-06-03 fl updates for elementtree 1.2 + * 2005-01-05 fl added universal name cache, Element/SubElement factories + * 2005-01-06 fl moved python helpers into C module; removed 1.5.2 support + * 2005-01-07 fl added 2.1 support; work around broken __copy__ in 2.3 + * 2005-01-08 fl added makeelement method; fixed path support + * 2005-01-10 fl optimized memory usage + * 2005-01-11 fl first public release (cElementTree 0.8) + * 2005-01-12 fl split element object into base and extras + * 2005-01-13 fl use tagged pointers for tail/text (cElementTree 0.9) + * 2005-01-17 fl added treebuilder close method + * 2005-01-17 fl fixed crash in getchildren + * 2005-01-18 fl removed observer api, added iterparse (cElementTree 0.9.3) + * 2005-01-23 fl revised iterparse api; added namespace event support (0.9.8) + * 2005-01-26 fl added VERSION module property (cElementTree 1.0) + * 2005-01-28 fl added remove method (1.0.1) + * 2005-03-01 fl added iselement function; fixed makeelement aliasing (1.0.2) + * 2005-03-13 fl export Comment and ProcessingInstruction/PI helpers + * 2005-03-26 fl added Comment and PI support to XMLParser + * 2005-03-27 fl event optimizations; complain about bogus events + * 2005-08-08 fl fixed read error handling in parse + * 2005-08-11 fl added runtime test for copy workaround (1.0.3) + * 2005-12-13 fl added expat_capi support (for xml.etree) (1.0.4) + * 2005-12-16 fl added support for non-standard encodings + * 2006-03-08 fl fixed a couple of potential null-refs and leaks + * 2006-03-12 fl merge in 2.5 ssize_t changes + * + * Copyright (c) 1999-2006 by Secret Labs AB. All rights reserved. + * Copyright (c) 1999-2006 by Fredrik Lundh. + * + * info@pythonware.com + * http://www.pythonware.com + */ + +/* Licensed to PSF under a Contributor Agreement. */ +/* See http://www.python.org/2.4/license for licensing details. */ + +#include "Python.h" + +#define VERSION "1.0.6" + +/* -------------------------------------------------------------------- */ +/* configuration */ + +/* Leave defined to include the expat-based XMLParser type */ +#define USE_EXPAT + +/* Define to to all expat calls via pyexpat's embedded expat library */ +/* #define USE_PYEXPAT_CAPI */ + +/* An element can hold this many children without extra memory + allocations. */ +#define STATIC_CHILDREN 4 + +/* For best performance, chose a value so that 80-90% of all nodes + have no more than the given number of children. Set this to zero + to minimize the size of the element structure itself (this only + helps if you have lots of leaf nodes with attributes). */ + +/* Also note that pymalloc always allocates blocks in multiples of + eight bytes. For the current version of cElementTree, this means + that the number of children should be an even number, at least on + 32-bit platforms. */ + +/* -------------------------------------------------------------------- */ + +#if 0 +static int memory = 0; +#define ALLOC(size, comment)\ +do { memory += size; printf("%8d - %s\n", memory, comment); } while (0) +#define RELEASE(size, comment)\ +do { memory -= size; printf("%8d - %s\n", memory, comment); } while (0) +#else +#define ALLOC(size, comment) +#define RELEASE(size, comment) +#endif + +/* compiler tweaks */ +#if defined(_MSC_VER) +#define LOCAL(type) static __inline type __fastcall +#else +#define LOCAL(type) static type +#endif + +/* compatibility macros */ +#if (PY_VERSION_HEX < 0x02050000) +typedef int Py_ssize_t; +#define lenfunc inquiry +#endif + +#if (PY_VERSION_HEX < 0x02040000) +#define PyDict_CheckExact PyDict_Check +#if (PY_VERSION_HEX < 0x02020000) +#define PyList_CheckExact PyList_Check +#define PyString_CheckExact PyString_Check +#if (PY_VERSION_HEX >= 0x01060000) +#define Py_USING_UNICODE /* always enabled for 2.0 and 2.1 */ +#endif +#endif +#endif + +#if !defined(Py_RETURN_NONE) +#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +#endif + +/* macros used to store 'join' flags in string object pointers. note + that all use of text and tail as object pointers must be wrapped in + JOIN_OBJ. see comments in the ElementObject definition for more + info. */ +#define JOIN_GET(p) ((Py_uintptr_t) (p) & 1) +#define JOIN_SET(p, flag) ((void*) ((Py_uintptr_t) (JOIN_OBJ(p)) | (flag))) +#define JOIN_OBJ(p) ((PyObject*) ((Py_uintptr_t) (p) & ~1)) + +/* glue functions (see the init function for details) */ +static PyObject* elementtree_copyelement_obj; +static PyObject* elementtree_deepcopy_obj; +static PyObject* elementtree_getiterator_obj; +static PyObject* elementpath_obj; + +/* helpers */ + +LOCAL(PyObject*) +deepcopy(PyObject* object, PyObject* memo) +{ + /* do a deep copy of the given object */ + + PyObject* args; + PyObject* result; + + if (!elementtree_deepcopy_obj) { + PyErr_SetString( + PyExc_RuntimeError, + "deepcopy helper not found" + ); + return NULL; + } + + args = PyTuple_New(2); + if (!args) + return NULL; + + Py_INCREF(object); PyTuple_SET_ITEM(args, 0, (PyObject*) object); + Py_INCREF(memo); PyTuple_SET_ITEM(args, 1, (PyObject*) memo); + + result = PyObject_CallObject(elementtree_deepcopy_obj, args); + + Py_DECREF(args); + + return result; +} + +LOCAL(PyObject*) +list_join(PyObject* list) +{ + /* join list elements (destroying the list in the process) */ + + PyObject* joiner; + PyObject* function; + PyObject* args; + PyObject* result; + + switch (PyList_GET_SIZE(list)) { + case 0: + Py_DECREF(list); + return PyString_FromString(""); + case 1: + result = PyList_GET_ITEM(list, 0); + Py_INCREF(result); + Py_DECREF(list); + return result; + } + + /* two or more elements: slice out a suitable separator from the + first member, and use that to join the entire list */ + + joiner = PySequence_GetSlice(PyList_GET_ITEM(list, 0), 0, 0); + if (!joiner) + return NULL; + + function = PyObject_GetAttrString(joiner, "join"); + if (!function) { + Py_DECREF(joiner); + return NULL; + } + + args = PyTuple_New(1); + if (!args) + return NULL; + + PyTuple_SET_ITEM(args, 0, list); + + result = PyObject_CallObject(function, args); + + Py_DECREF(args); /* also removes list */ + Py_DECREF(function); + Py_DECREF(joiner); + + return result; +} + +#if (PY_VERSION_HEX < 0x02020000) +LOCAL(int) +PyDict_Update(PyObject* dict, PyObject* other) +{ + /* PyDict_Update emulation for 2.1 and earlier */ + + PyObject* res; + + res = PyObject_CallMethod(dict, "update", "O", other); + if (!res) + return -1; + + Py_DECREF(res); + return 0; +} +#endif + +/* -------------------------------------------------------------------- */ +/* the element type */ + +typedef struct { + + /* attributes (a dictionary object), or None if no attributes */ + PyObject* attrib; + + /* child elements */ + int length; /* actual number of items */ + int allocated; /* allocated items */ + + /* this either points to _children or to a malloced buffer */ + PyObject* *children; + + PyObject* _children[STATIC_CHILDREN]; + +} ElementObjectExtra; + +typedef struct { + PyObject_HEAD + + /* element tag (a string). */ + PyObject* tag; + + /* text before first child. note that this is a tagged pointer; + use JOIN_OBJ to get the object pointer. the join flag is used + to distinguish lists created by the tree builder from lists + assigned to the attribute by application code; the former + should be joined before being returned to the user, the latter + should be left intact. */ + PyObject* text; + + /* text after this element, in parent. note that this is a tagged + pointer; use JOIN_OBJ to get the object pointer. */ + PyObject* tail; + + ElementObjectExtra* extra; + +} ElementObject; + +staticforward PyTypeObject Element_Type; + +#define Element_CheckExact(op) ((op)->ob_type == &Element_Type) + +/* -------------------------------------------------------------------- */ +/* element constructor and destructor */ + +LOCAL(int) +element_new_extra(ElementObject* self, PyObject* attrib) +{ + self->extra = PyObject_Malloc(sizeof(ElementObjectExtra)); + if (!self->extra) + return -1; + + if (!attrib) + attrib = Py_None; + + Py_INCREF(attrib); + self->extra->attrib = attrib; + + self->extra->length = 0; + self->extra->allocated = STATIC_CHILDREN; + self->extra->children = self->extra->_children; + + return 0; +} + +LOCAL(void) +element_dealloc_extra(ElementObject* self) +{ + int i; + + Py_DECREF(self->extra->attrib); + + for (i = 0; i < self->extra->length; i++) + Py_DECREF(self->extra->children[i]); + + if (self->extra->children != self->extra->_children) + PyObject_Free(self->extra->children); + + PyObject_Free(self->extra); +} + +LOCAL(PyObject*) +element_new(PyObject* tag, PyObject* attrib) +{ + ElementObject* self; + + self = PyObject_New(ElementObject, &Element_Type); + if (self == NULL) + return NULL; + + /* use None for empty dictionaries */ + if (PyDict_CheckExact(attrib) && !PyDict_Size(attrib)) + attrib = Py_None; + + self->extra = NULL; + + if (attrib != Py_None) { + + if (element_new_extra(self, attrib) < 0) { + PyObject_Del(self); + return NULL; + } + + self->extra->length = 0; + self->extra->allocated = STATIC_CHILDREN; + self->extra->children = self->extra->_children; + + } + + Py_INCREF(tag); + self->tag = tag; + + Py_INCREF(Py_None); + self->text = Py_None; + + Py_INCREF(Py_None); + self->tail = Py_None; + + ALLOC(sizeof(ElementObject), "create element"); + + return (PyObject*) self; +} + +LOCAL(int) +element_resize(ElementObject* self, int extra) +{ + int size; + PyObject* *children; + + /* make sure self->children can hold the given number of extra + elements. set an exception and return -1 if allocation failed */ + + if (!self->extra) + element_new_extra(self, NULL); + + size = self->extra->length + extra; + + if (size > self->extra->allocated) { + /* use Python 2.4's list growth strategy */ + size = (size >> 3) + (size < 9 ? 3 : 6) + size; + if (self->extra->children != self->extra->_children) { + children = PyObject_Realloc(self->extra->children, + size * sizeof(PyObject*)); + if (!children) + goto nomemory; + } else { + children = PyObject_Malloc(size * sizeof(PyObject*)); + if (!children) + goto nomemory; + /* copy existing children from static area to malloc buffer */ + memcpy(children, self->extra->children, + self->extra->length * sizeof(PyObject*)); + } + self->extra->children = children; + self->extra->allocated = size; + } + + return 0; + + nomemory: + PyErr_NoMemory(); + return -1; +} + +LOCAL(int) +element_add_subelement(ElementObject* self, PyObject* element) +{ + /* add a child element to a parent */ + + if (element_resize(self, 1) < 0) + return -1; + + Py_INCREF(element); + self->extra->children[self->extra->length] = element; + + self->extra->length++; + + return 0; +} + +LOCAL(PyObject*) +element_get_attrib(ElementObject* self) +{ + /* return borrowed reference to attrib dictionary */ + /* note: this function assumes that the extra section exists */ + + PyObject* res = self->extra->attrib; + + if (res == Py_None) { + /* create missing dictionary */ + res = PyDict_New(); + if (!res) + return NULL; + self->extra->attrib = res; + } + + return res; +} + +LOCAL(PyObject*) +element_get_text(ElementObject* self) +{ + /* return borrowed reference to text attribute */ + + PyObject* res = self->text; + + if (JOIN_GET(res)) { + res = JOIN_OBJ(res); + if (PyList_CheckExact(res)) { + res = list_join(res); + if (!res) + return NULL; + self->text = res; + } + } + + return res; +} + +LOCAL(PyObject*) +element_get_tail(ElementObject* self) +{ + /* return borrowed reference to text attribute */ + + PyObject* res = self->tail; + + if (JOIN_GET(res)) { + res = JOIN_OBJ(res); + if (PyList_CheckExact(res)) { + res = list_join(res); + if (!res) + return NULL; + self->tail = res; + } + } + + return res; +} + +static PyObject* +element(PyObject* self, PyObject* args, PyObject* kw) +{ + PyObject* elem; + + PyObject* tag; + PyObject* attrib = NULL; + if (!PyArg_ParseTuple(args, "O|O!:Element", &tag, + &PyDict_Type, &attrib)) + return NULL; + + if (attrib || kw) { + attrib = (attrib) ? PyDict_Copy(attrib) : PyDict_New(); + if (!attrib) + return NULL; + if (kw) + PyDict_Update(attrib, kw); + } else { + Py_INCREF(Py_None); + attrib = Py_None; + } + + elem = element_new(tag, attrib); + + Py_DECREF(attrib); + + return elem; +} + +static PyObject* +subelement(PyObject* self, PyObject* args, PyObject* kw) +{ + PyObject* elem; + + ElementObject* parent; + PyObject* tag; + PyObject* attrib = NULL; + if (!PyArg_ParseTuple(args, "O!O|O!:SubElement", + &Element_Type, &parent, &tag, + &PyDict_Type, &attrib)) + return NULL; + + if (attrib || kw) { + attrib = (attrib) ? PyDict_Copy(attrib) : PyDict_New(); + if (!attrib) + return NULL; + if (kw) + PyDict_Update(attrib, kw); + } else { + Py_INCREF(Py_None); + attrib = Py_None; + } + + elem = element_new(tag, attrib); + + Py_DECREF(attrib); + + if (element_add_subelement(parent, elem) < 0) { + Py_DECREF(elem); + return NULL; + } + + return elem; +} + +static void +element_dealloc(ElementObject* self) +{ + if (self->extra) + element_dealloc_extra(self); + + /* discard attributes */ + Py_DECREF(self->tag); + Py_DECREF(JOIN_OBJ(self->text)); + Py_DECREF(JOIN_OBJ(self->tail)); + + RELEASE(sizeof(ElementObject), "destroy element"); + + PyObject_Del(self); +} + +/* -------------------------------------------------------------------- */ +/* methods (in alphabetical order) */ + +static PyObject* +element_append(ElementObject* self, PyObject* args) +{ + PyObject* element; + if (!PyArg_ParseTuple(args, "O!:append", &Element_Type, &element)) + return NULL; + + if (element_add_subelement(self, element) < 0) + return NULL; + + Py_RETURN_NONE; +} + +static PyObject* +element_clear(ElementObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, ":clear")) + return NULL; + + if (self->extra) { + element_dealloc_extra(self); + self->extra = NULL; + } + + Py_INCREF(Py_None); + Py_DECREF(JOIN_OBJ(self->text)); + self->text = Py_None; + + Py_INCREF(Py_None); + Py_DECREF(JOIN_OBJ(self->tail)); + self->tail = Py_None; + + Py_RETURN_NONE; +} + +static PyObject* +element_copy(ElementObject* self, PyObject* args) +{ + int i; + ElementObject* element; + + if (!PyArg_ParseTuple(args, ":__copy__")) + return NULL; + + element = (ElementObject*) element_new( + self->tag, (self->extra) ? self->extra->attrib : Py_None + ); + if (!element) + return NULL; + + Py_DECREF(JOIN_OBJ(element->text)); + element->text = self->text; + Py_INCREF(JOIN_OBJ(element->text)); + + Py_DECREF(JOIN_OBJ(element->tail)); + element->tail = self->tail; + Py_INCREF(JOIN_OBJ(element->tail)); + + if (self->extra) { + + if (element_resize(element, self->extra->length) < 0) { + Py_DECREF(element); + return NULL; + } + + for (i = 0; i < self->extra->length; i++) { + Py_INCREF(self->extra->children[i]); + element->extra->children[i] = self->extra->children[i]; + } + + element->extra->length = self->extra->length; + + } + + return (PyObject*) element; +} + +static PyObject* +element_deepcopy(ElementObject* self, PyObject* args) +{ + int i; + ElementObject* element; + PyObject* tag; + PyObject* attrib; + PyObject* text; + PyObject* tail; + PyObject* id; + + PyObject* memo; + if (!PyArg_ParseTuple(args, "O:__deepcopy__", &memo)) + return NULL; + + tag = deepcopy(self->tag, memo); + if (!tag) + return NULL; + + if (self->extra) { + attrib = deepcopy(self->extra->attrib, memo); + if (!attrib) { + Py_DECREF(tag); + return NULL; + } + } else { + Py_INCREF(Py_None); + attrib = Py_None; + } + + element = (ElementObject*) element_new(tag, attrib); + + Py_DECREF(tag); + Py_DECREF(attrib); + + if (!element) + return NULL; + + text = deepcopy(JOIN_OBJ(self->text), memo); + if (!text) + goto error; + Py_DECREF(element->text); + element->text = JOIN_SET(text, JOIN_GET(self->text)); + + tail = deepcopy(JOIN_OBJ(self->tail), memo); + if (!tail) + goto error; + Py_DECREF(element->tail); + element->tail = JOIN_SET(tail, JOIN_GET(self->tail)); + + if (self->extra) { + + if (element_resize(element, self->extra->length) < 0) + goto error; + + for (i = 0; i < self->extra->length; i++) { + PyObject* child = deepcopy(self->extra->children[i], memo); + if (!child) { + element->extra->length = i; + goto error; + } + element->extra->children[i] = child; + } + + element->extra->length = self->extra->length; + + } + + /* add object to memo dictionary (so deepcopy won't visit it again) */ + id = PyInt_FromLong((Py_uintptr_t) self); + + i = PyDict_SetItem(memo, id, (PyObject*) element); + + Py_DECREF(id); + + if (i < 0) + goto error; + + return (PyObject*) element; + + error: + Py_DECREF(element); + return NULL; +} + +LOCAL(int) +checkpath(PyObject* tag) +{ + Py_ssize_t i; + int check = 1; + + /* check if a tag contains an xpath character */ + +#define PATHCHAR(ch) (ch == '/' || ch == '*' || ch == '[' || ch == '@') + +#if defined(Py_USING_UNICODE) + if (PyUnicode_Check(tag)) { + Py_UNICODE *p = PyUnicode_AS_UNICODE(tag); + for (i = 0; i < PyUnicode_GET_SIZE(tag); i++) { + if (p[i] == '{') + check = 0; + else if (p[i] == '}') + check = 1; + else if (check && PATHCHAR(p[i])) + return 1; + } + return 0; + } +#endif + if (PyString_Check(tag)) { + char *p = PyString_AS_STRING(tag); + for (i = 0; i < PyString_GET_SIZE(tag); i++) { + if (p[i] == '{') + check = 0; + else if (p[i] == '}') + check = 1; + else if (check && PATHCHAR(p[i])) + return 1; + } + return 0; + } + + return 1; /* unknown type; might be path expression */ +} + +static PyObject* +element_find(ElementObject* self, PyObject* args) +{ + int i; + + PyObject* tag; + if (!PyArg_ParseTuple(args, "O:find", &tag)) + return NULL; + + if (checkpath(tag)) + return PyObject_CallMethod( + elementpath_obj, "find", "OO", self, tag + ); + + if (!self->extra) + Py_RETURN_NONE; + + for (i = 0; i < self->extra->length; i++) { + PyObject* item = self->extra->children[i]; + if (Element_CheckExact(item) && + PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) { + Py_INCREF(item); + return item; + } + } + + Py_RETURN_NONE; +} + +static PyObject* +element_findtext(ElementObject* self, PyObject* args) +{ + int i; + + PyObject* tag; + PyObject* default_value = Py_None; + if (!PyArg_ParseTuple(args, "O|O:findtext", &tag, &default_value)) + return NULL; + + if (checkpath(tag)) + return PyObject_CallMethod( + elementpath_obj, "findtext", "OOO", self, tag, default_value + ); + + if (!self->extra) { + Py_INCREF(default_value); + return default_value; + } + + for (i = 0; i < self->extra->length; i++) { + ElementObject* item = (ElementObject*) self->extra->children[i]; + if (Element_CheckExact(item) && !PyObject_Compare(item->tag, tag)) { + PyObject* text = element_get_text(item); + if (text == Py_None) + return PyString_FromString(""); + Py_XINCREF(text); + return text; + } + } + + Py_INCREF(default_value); + return default_value; +} + +static PyObject* +element_findall(ElementObject* self, PyObject* args) +{ + int i; + PyObject* out; + + PyObject* tag; + if (!PyArg_ParseTuple(args, "O:findall", &tag)) + return NULL; + + if (checkpath(tag)) + return PyObject_CallMethod( + elementpath_obj, "findall", "OO", self, tag + ); + + out = PyList_New(0); + if (!out) + return NULL; + + if (!self->extra) + return out; + + for (i = 0; i < self->extra->length; i++) { + PyObject* item = self->extra->children[i]; + if (Element_CheckExact(item) && + PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) { + if (PyList_Append(out, item) < 0) { + Py_DECREF(out); + return NULL; + } + } + } + + return out; +} + +static PyObject* +element_get(ElementObject* self, PyObject* args) +{ + PyObject* value; + + PyObject* key; + PyObject* default_value = Py_None; + if (!PyArg_ParseTuple(args, "O|O:get", &key, &default_value)) + return NULL; + + if (!self->extra || self->extra->attrib == Py_None) + value = default_value; + else { + value = PyDict_GetItem(self->extra->attrib, key); + if (!value) + value = default_value; + } + + Py_INCREF(value); + return value; +} + +static PyObject* +element_getchildren(ElementObject* self, PyObject* args) +{ + int i; + PyObject* list; + + if (!PyArg_ParseTuple(args, ":getchildren")) + return NULL; + + if (!self->extra) + return PyList_New(0); + + list = PyList_New(self->extra->length); + if (!list) + return NULL; + + for (i = 0; i < self->extra->length; i++) { + PyObject* item = self->extra->children[i]; + Py_INCREF(item); + PyList_SET_ITEM(list, i, item); + } + + return list; +} + +static PyObject* +element_getiterator(ElementObject* self, PyObject* args) +{ + PyObject* result; + + PyObject* tag = Py_None; + if (!PyArg_ParseTuple(args, "|O:getiterator", &tag)) + return NULL; + + if (!elementtree_getiterator_obj) { + PyErr_SetString( + PyExc_RuntimeError, + "getiterator helper not found" + ); + return NULL; + } + + args = PyTuple_New(2); + if (!args) + return NULL; + + Py_INCREF(self); PyTuple_SET_ITEM(args, 0, (PyObject*) self); + Py_INCREF(tag); PyTuple_SET_ITEM(args, 1, (PyObject*) tag); + + result = PyObject_CallObject(elementtree_getiterator_obj, args); + + Py_DECREF(args); + + return result; +} + +static PyObject* +element_getitem(PyObject* self_, Py_ssize_t index) +{ + ElementObject* self = (ElementObject*) self_; + + if (!self->extra || index < 0 || index >= self->extra->length) { + PyErr_SetString( + PyExc_IndexError, + "child index out of range" + ); + return NULL; + } + + Py_INCREF(self->extra->children[index]); + return self->extra->children[index]; +} + +static PyObject* +element_getslice(PyObject* self_, Py_ssize_t start, Py_ssize_t end) +{ + ElementObject* self = (ElementObject*) self_; + Py_ssize_t i; + PyObject* list; + + if (!self->extra) + return PyList_New(0); + + /* standard clamping */ + if (start < 0) + start = 0; + if (end < 0) + end = 0; + if (end > self->extra->length) + end = self->extra->length; + if (start > end) + start = end; + + list = PyList_New(end - start); + if (!list) + return NULL; + + for (i = start; i < end; i++) { + PyObject* item = self->extra->children[i]; + Py_INCREF(item); + PyList_SET_ITEM(list, i - start, item); + } + + return list; +} + +static PyObject* +element_insert(ElementObject* self, PyObject* args) +{ + int i; + + int index; + PyObject* element; + if (!PyArg_ParseTuple(args, "iO!:insert", &index, + &Element_Type, &element)) + return NULL; + + if (!self->extra) + element_new_extra(self, NULL); + + if (index < 0) + index = 0; + if (index > self->extra->length) + index = self->extra->length; + + if (element_resize(self, 1) < 0) + return NULL; + + for (i = self->extra->length; i > index; i--) + self->extra->children[i] = self->extra->children[i-1]; + + Py_INCREF(element); + self->extra->children[index] = element; + + self->extra->length++; + + Py_RETURN_NONE; +} + +static PyObject* +element_items(ElementObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, ":items")) + return NULL; + + if (!self->extra || self->extra->attrib == Py_None) + return PyList_New(0); + + return PyDict_Items(self->extra->attrib); +} + +static PyObject* +element_keys(ElementObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, ":keys")) + return NULL; + + if (!self->extra || self->extra->attrib == Py_None) + return PyList_New(0); + + return PyDict_Keys(self->extra->attrib); +} + +static Py_ssize_t +element_length(ElementObject* self) +{ + if (!self->extra) + return 0; + + return self->extra->length; +} + +static PyObject* +element_makeelement(PyObject* self, PyObject* args, PyObject* kw) +{ + PyObject* elem; + + PyObject* tag; + PyObject* attrib; + if (!PyArg_ParseTuple(args, "OO:makeelement", &tag, &attrib)) + return NULL; + + attrib = PyDict_Copy(attrib); + if (!attrib) + return NULL; + + elem = element_new(tag, attrib); + + Py_DECREF(attrib); + + return elem; +} + +static PyObject* +element_reduce(ElementObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, ":__reduce__")) + return NULL; + + /* Hack alert: This method is used to work around a __copy__ + problem on certain 2.3 and 2.4 versions. To save time and + simplify the code, we create the copy in here, and use a dummy + copyelement helper to trick the copy module into doing the + right thing. */ + + if (!elementtree_copyelement_obj) { + PyErr_SetString( + PyExc_RuntimeError, + "copyelement helper not found" + ); + return NULL; + } + + return Py_BuildValue( + "O(N)", elementtree_copyelement_obj, element_copy(self, args) + ); +} + +static PyObject* +element_remove(ElementObject* self, PyObject* args) +{ + int i; + + PyObject* element; + if (!PyArg_ParseTuple(args, "O!:remove", &Element_Type, &element)) + return NULL; + + if (!self->extra) { + /* element has no children, so raise exception */ + PyErr_SetString( + PyExc_ValueError, + "list.remove(x): x not in list" + ); + return NULL; + } + + for (i = 0; i < self->extra->length; i++) { + if (self->extra->children[i] == element) + break; + if (PyObject_Compare(self->extra->children[i], element) == 0) + break; + } + + if (i == self->extra->length) { + /* element is not in children, so raise exception */ + PyErr_SetString( + PyExc_ValueError, + "list.remove(x): x not in list" + ); + return NULL; + } + + Py_DECREF(self->extra->children[i]); + + self->extra->length--; + + for (; i < self->extra->length; i++) + self->extra->children[i] = self->extra->children[i+1]; + + Py_RETURN_NONE; +} + +static PyObject* +element_repr(ElementObject* self) +{ + PyObject* repr; + char buffer[100]; + + repr = PyString_FromString("<Element "); + + PyString_ConcatAndDel(&repr, PyObject_Repr(self->tag)); + + sprintf(buffer, " at %p>", self); + PyString_ConcatAndDel(&repr, PyString_FromString(buffer)); + + return repr; +} + +static PyObject* +element_set(ElementObject* self, PyObject* args) +{ + PyObject* attrib; + + PyObject* key; + PyObject* value; + if (!PyArg_ParseTuple(args, "OO:set", &key, &value)) + return NULL; + + if (!self->extra) + element_new_extra(self, NULL); + + attrib = element_get_attrib(self); + if (!attrib) + return NULL; + + if (PyDict_SetItem(attrib, key, value) < 0) + return NULL; + + Py_RETURN_NONE; +} + +static int +element_setslice(PyObject* self_, Py_ssize_t start, Py_ssize_t end, PyObject* item) +{ + ElementObject* self = (ElementObject*) self_; + Py_ssize_t i, new, old; + PyObject* recycle = NULL; + + if (!self->extra) + element_new_extra(self, NULL); + + /* standard clamping */ + if (start < 0) + start = 0; + if (end < 0) + end = 0; + if (end > self->extra->length) + end = self->extra->length; + if (start > end) + start = end; + + old = end - start; + + if (item == NULL) + new = 0; + else if (PyList_CheckExact(item)) { + new = PyList_GET_SIZE(item); + } else { + /* FIXME: support arbitrary sequences? */ + PyErr_Format( + PyExc_TypeError, + "expected list, not \"%.200s\"", item->ob_type->tp_name + ); + return -1; + } + + if (old > 0) { + /* to avoid recursive calls to this method (via decref), move + old items to the recycle bin here, and get rid of them when + we're done modifying the element */ + recycle = PyList_New(old); + for (i = 0; i < old; i++) + PyList_SET_ITEM(recycle, i, self->extra->children[i + start]); + } + + if (new < old) { + /* delete slice */ + for (i = end; i < self->extra->length; i++) + self->extra->children[i + new - old] = self->extra->children[i]; + } else if (new > old) { + /* insert slice */ + if (element_resize(self, new - old) < 0) + return -1; + for (i = self->extra->length-1; i >= end; i--) + self->extra->children[i + new - old] = self->extra->children[i]; + } + + /* replace the slice */ + for (i = 0; i < new; i++) { + PyObject* element = PyList_GET_ITEM(item, i); + Py_INCREF(element); + self->extra->children[i + start] = element; + } + + self->extra->length += new - old; + + /* discard the recycle bin, and everything in it */ + Py_XDECREF(recycle); + + return 0; +} + +static int +element_setitem(PyObject* self_, Py_ssize_t index, PyObject* item) +{ + ElementObject* self = (ElementObject*) self_; + int i; + PyObject* old; + + if (!self->extra || index < 0 || index >= self->extra->length) { + PyErr_SetString( + PyExc_IndexError, + "child assignment index out of range"); + return -1; + } + + old = self->extra->children[index]; + + if (item) { + Py_INCREF(item); + self->extra->children[index] = item; + } else { + self->extra->length--; + for (i = index; i < self->extra->length; i++) + self->extra->children[i] = self->extra->children[i+1]; + } + + Py_DECREF(old); + + return 0; +} + +static PyMethodDef element_methods[] = { + + {"clear", (PyCFunction) element_clear, METH_VARARGS}, + + {"get", (PyCFunction) element_get, METH_VARARGS}, + {"set", (PyCFunction) element_set, METH_VARARGS}, + + {"find", (PyCFunction) element_find, METH_VARARGS}, + {"findtext", (PyCFunction) element_findtext, METH_VARARGS}, + {"findall", (PyCFunction) element_findall, METH_VARARGS}, + + {"append", (PyCFunction) element_append, METH_VARARGS}, + {"insert", (PyCFunction) element_insert, METH_VARARGS}, + {"remove", (PyCFunction) element_remove, METH_VARARGS}, + + {"getiterator", (PyCFunction) element_getiterator, METH_VARARGS}, + {"getchildren", (PyCFunction) element_getchildren, METH_VARARGS}, + + {"items", (PyCFunction) element_items, METH_VARARGS}, + {"keys", (PyCFunction) element_keys, METH_VARARGS}, + + {"makeelement", (PyCFunction) element_makeelement, METH_VARARGS}, + + {"__copy__", (PyCFunction) element_copy, METH_VARARGS}, + {"__deepcopy__", (PyCFunction) element_deepcopy, METH_VARARGS}, + + /* Some 2.3 and 2.4 versions do not handle the __copy__ method on + C objects correctly, so we have to fake it using a __reduce__- + based hack (see the element_reduce implementation above for + details). */ + + /* The behaviour has been changed in 2.3.5 and 2.4.1, so we're + using a runtime test to figure out if we need to fake things + or now (see the init code below). The following entry is + enabled only if the hack is needed. */ + + {"!__reduce__", (PyCFunction) element_reduce, METH_VARARGS}, + + {NULL, NULL} +}; + +static PyObject* +element_getattr(ElementObject* self, char* name) +{ + PyObject* res; + + res = Py_FindMethod(element_methods, (PyObject*) self, name); + if (res) + return res; + + PyErr_Clear(); + + if (strcmp(name, "tag") == 0) + res = self->tag; + else if (strcmp(name, "text") == 0) + res = element_get_text(self); + else if (strcmp(name, "tail") == 0) { + res = element_get_tail(self); + } else if (strcmp(name, "attrib") == 0) { + if (!self->extra) + element_new_extra(self, NULL); + res = element_get_attrib(self); + } else { + PyErr_SetString(PyExc_AttributeError, name); + return NULL; + } + + if (!res) + return NULL; + + Py_INCREF(res); + return res; +} + +static int +element_setattr(ElementObject* self, const char* name, PyObject* value) +{ + if (value == NULL) { + PyErr_SetString( + PyExc_AttributeError, + "can't delete element attributes" + ); + return -1; + } + + if (strcmp(name, "tag") == 0) { + Py_DECREF(self->tag); + self->tag = value; + Py_INCREF(self->tag); + } else if (strcmp(name, "text") == 0) { + Py_DECREF(JOIN_OBJ(self->text)); + self->text = value; + Py_INCREF(self->text); + } else if (strcmp(name, "tail") == 0) { + Py_DECREF(JOIN_OBJ(self->tail)); + self->tail = value; + Py_INCREF(self->tail); + } else if (strcmp(name, "attrib") == 0) { + if (!self->extra) + element_new_extra(self, NULL); + Py_DECREF(self->extra->attrib); + self->extra->attrib = value; + Py_INCREF(self->extra->attrib); + } else { + PyErr_SetString(PyExc_AttributeError, name); + return -1; + } + + return 0; +} + +static PySequenceMethods element_as_sequence = { + (lenfunc) element_length, + 0, /* sq_concat */ + 0, /* sq_repeat */ + element_getitem, + element_getslice, + element_setitem, + element_setslice, +}; + +statichere PyTypeObject Element_Type = { + PyObject_HEAD_INIT(NULL) + 0, "Element", sizeof(ElementObject), 0, + /* methods */ + (destructor)element_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)element_getattr, /* tp_getattr */ + (setattrfunc)element_setattr, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)element_repr, /* tp_repr */ + 0, /* tp_as_number */ + &element_as_sequence, /* tp_as_sequence */ +}; + +/* ==================================================================== */ +/* the tree builder type */ + +typedef struct { + PyObject_HEAD + + PyObject* root; /* root node (first created node) */ + + ElementObject* this; /* current node */ + ElementObject* last; /* most recently created node */ + + PyObject* data; /* data collector (string or list), or NULL */ + + PyObject* stack; /* element stack */ + Py_ssize_t index; /* current stack size (0=empty) */ + + /* element tracing */ + PyObject* events; /* list of events, or NULL if not collecting */ + PyObject* start_event_obj; /* event objects (NULL to ignore) */ + PyObject* end_event_obj; + PyObject* start_ns_event_obj; + PyObject* end_ns_event_obj; + +} TreeBuilderObject; + +staticforward PyTypeObject TreeBuilder_Type; + +#define TreeBuilder_CheckExact(op) ((op)->ob_type == &TreeBuilder_Type) + +/* -------------------------------------------------------------------- */ +/* constructor and destructor */ + +LOCAL(PyObject*) +treebuilder_new(void) +{ + TreeBuilderObject* self; + + self = PyObject_New(TreeBuilderObject, &TreeBuilder_Type); + if (self == NULL) + return NULL; + + self->root = NULL; + + Py_INCREF(Py_None); + self->this = (ElementObject*) Py_None; + + Py_INCREF(Py_None); + self->last = (ElementObject*) Py_None; + + self->data = NULL; + + self->stack = PyList_New(20); + self->index = 0; + + self->events = NULL; + self->start_event_obj = self->end_event_obj = NULL; + self->start_ns_event_obj = self->end_ns_event_obj = NULL; + + ALLOC(sizeof(TreeBuilderObject), "create treebuilder"); + + return (PyObject*) self; +} + +static PyObject* +treebuilder(PyObject* self_, PyObject* args) +{ + if (!PyArg_ParseTuple(args, ":TreeBuilder")) + return NULL; + + return treebuilder_new(); +} + +static void +treebuilder_dealloc(TreeBuilderObject* self) +{ + Py_XDECREF(self->end_ns_event_obj); + Py_XDECREF(self->start_ns_event_obj); + Py_XDECREF(self->end_event_obj); + Py_XDECREF(self->start_event_obj); + Py_XDECREF(self->events); + Py_DECREF(self->stack); + Py_XDECREF(self->data); + Py_DECREF(self->last); + Py_DECREF(self->this); + Py_XDECREF(self->root); + + RELEASE(sizeof(TreeBuilderObject), "destroy treebuilder"); + + PyObject_Del(self); +} + +/* -------------------------------------------------------------------- */ +/* handlers */ + +LOCAL(PyObject*) +treebuilder_handle_xml(TreeBuilderObject* self, PyObject* encoding, + PyObject* standalone) +{ + Py_RETURN_NONE; +} + +LOCAL(PyObject*) +treebuilder_handle_start(TreeBuilderObject* self, PyObject* tag, + PyObject* attrib) +{ + PyObject* node; + PyObject* this; + + if (self->data) { + if (self->this == self->last) { + Py_DECREF(JOIN_OBJ(self->last->text)); + self->last->text = JOIN_SET( + self->data, PyList_CheckExact(self->data) + ); + } else { + Py_DECREF(JOIN_OBJ(self->last->tail)); + self->last->tail = JOIN_SET( + self->data, PyList_CheckExact(self->data) + ); + } + self->data = NULL; + } + + node = element_new(tag, attrib); + if (!node) + return NULL; + + this = (PyObject*) self->this; + + if (this != Py_None) { + if (element_add_subelement((ElementObject*) this, node) < 0) + goto error; + } else { + if (self->root) { + PyErr_SetString( + PyExc_SyntaxError, + "multiple elements on top level" + ); + goto error; + } + Py_INCREF(node); + self->root = node; + } + + if (self->index < PyList_GET_SIZE(self->stack)) { + if (PyList_SetItem(self->stack, self->index, this) < 0) + goto error; + Py_INCREF(this); + } else { + if (PyList_Append(self->stack, this) < 0) + goto error; + } + self->index++; + + Py_DECREF(this); + Py_INCREF(node); + self->this = (ElementObject*) node; + + Py_DECREF(self->last); + Py_INCREF(node); + self->last = (ElementObject*) node; + + if (self->start_event_obj) { + PyObject* res; + PyObject* action = self->start_event_obj; + res = PyTuple_New(2); + if (res) { + Py_INCREF(action); PyTuple_SET_ITEM(res, 0, (PyObject*) action); + Py_INCREF(node); PyTuple_SET_ITEM(res, 1, (PyObject*) node); + PyList_Append(self->events, res); + Py_DECREF(res); + } else + PyErr_Clear(); /* FIXME: propagate error */ + } + + return node; + + error: + Py_DECREF(node); + return NULL; +} + +LOCAL(PyObject*) +treebuilder_handle_data(TreeBuilderObject* self, PyObject* data) +{ + if (!self->data) { + if (self->last == (ElementObject*) Py_None) { + /* ignore calls to data before the first call to start */ + Py_RETURN_NONE; + } + /* store the first item as is */ + Py_INCREF(data); self->data = data; + } else { + /* more than one item; use a list to collect items */ + if (PyString_CheckExact(self->data) && self->data->ob_refcnt == 1 && + PyString_CheckExact(data) && PyString_GET_SIZE(data) == 1) { + /* expat often generates single character data sections; handle + the most common case by resizing the existing string... */ + Py_ssize_t size = PyString_GET_SIZE(self->data); + if (_PyString_Resize(&self->data, size + 1) < 0) + return NULL; + PyString_AS_STRING(self->data)[size] = PyString_AS_STRING(data)[0]; + } else if (PyList_CheckExact(self->data)) { + if (PyList_Append(self->data, data) < 0) + return NULL; + } else { + PyObject* list = PyList_New(2); + if (!list) + return NULL; + PyList_SET_ITEM(list, 0, self->data); + Py_INCREF(data); PyList_SET_ITEM(list, 1, data); + self->data = list; + } + } + + Py_RETURN_NONE; +} + +LOCAL(PyObject*) +treebuilder_handle_end(TreeBuilderObject* self, PyObject* tag) +{ + PyObject* item; + + if (self->data) { + if (self->this == self->last) { + Py_DECREF(JOIN_OBJ(self->last->text)); + self->last->text = JOIN_SET( + self->data, PyList_CheckExact(self->data) + ); + } else { + Py_DECREF(JOIN_OBJ(self->last->tail)); + self->last->tail = JOIN_SET( + self->data, PyList_CheckExact(self->data) + ); + } + self->data = NULL; + } + + if (self->index == 0) { + PyErr_SetString( + PyExc_IndexError, + "pop from empty stack" + ); + return NULL; + } + + self->index--; + + item = PyList_GET_ITEM(self->stack, self->index); + Py_INCREF(item); + + Py_DECREF(self->last); + + self->last = (ElementObject*) self->this; + self->this = (ElementObject*) item; + + if (self->end_event_obj) { + PyObject* res; + PyObject* action = self->end_event_obj; + PyObject* node = (PyObject*) self->last; + res = PyTuple_New(2); + if (res) { + Py_INCREF(action); PyTuple_SET_ITEM(res, 0, (PyObject*) action); + Py_INCREF(node); PyTuple_SET_ITEM(res, 1, (PyObject*) node); + PyList_Append(self->events, res); + Py_DECREF(res); + } else + PyErr_Clear(); /* FIXME: propagate error */ + } + + Py_INCREF(self->last); + return (PyObject*) self->last; +} + +LOCAL(void) +treebuilder_handle_namespace(TreeBuilderObject* self, int start, + const char* prefix, const char *uri) +{ + PyObject* res; + PyObject* action; + PyObject* parcel; + + if (!self->events) + return; + + if (start) { + if (!self->start_ns_event_obj) + return; + action = self->start_ns_event_obj; + /* FIXME: prefix and uri use utf-8 encoding! */ + parcel = Py_BuildValue("ss", (prefix) ? prefix : "", uri); + if (!parcel) + return; + Py_INCREF(action); + } else { + if (!self->end_ns_event_obj) + return; + action = self->end_ns_event_obj; + Py_INCREF(action); + parcel = Py_None; + Py_INCREF(parcel); + } + + res = PyTuple_New(2); + + if (res) { + PyTuple_SET_ITEM(res, 0, action); + PyTuple_SET_ITEM(res, 1, parcel); + PyList_Append(self->events, res); + Py_DECREF(res); + } else + PyErr_Clear(); /* FIXME: propagate error */ +} + +/* -------------------------------------------------------------------- */ +/* methods (in alphabetical order) */ + +static PyObject* +treebuilder_data(TreeBuilderObject* self, PyObject* args) +{ + PyObject* data; + if (!PyArg_ParseTuple(args, "O:data", &data)) + return NULL; + + return treebuilder_handle_data(self, data); +} + +static PyObject* +treebuilder_end(TreeBuilderObject* self, PyObject* args) +{ + PyObject* tag; + if (!PyArg_ParseTuple(args, "O:end", &tag)) + return NULL; + + return treebuilder_handle_end(self, tag); +} + +LOCAL(PyObject*) +treebuilder_done(TreeBuilderObject* self) +{ + PyObject* res; + + /* FIXME: check stack size? */ + + if (self->root) + res = self->root; + else + res = Py_None; + + Py_INCREF(res); + return res; +} + +static PyObject* +treebuilder_close(TreeBuilderObject* self, PyObject* args) +{ + if (!PyArg_ParseTuple(args, ":close")) + return NULL; + + return treebuilder_done(self); +} + +static PyObject* +treebuilder_start(TreeBuilderObject* self, PyObject* args) +{ + PyObject* tag; + PyObject* attrib = Py_None; + if (!PyArg_ParseTuple(args, "O|O:start", &tag, &attrib)) + return NULL; + + return treebuilder_handle_start(self, tag, attrib); +} + +static PyObject* +treebuilder_xml(TreeBuilderObject* self, PyObject* args) +{ + PyObject* encoding; + PyObject* standalone; + if (!PyArg_ParseTuple(args, "OO:xml", &encoding, &standalone)) + return NULL; + + return treebuilder_handle_xml(self, encoding, standalone); +} + +static PyMethodDef treebuilder_methods[] = { + {"data", (PyCFunction) treebuilder_data, METH_VARARGS}, + {"start", (PyCFunction) treebuilder_start, METH_VARARGS}, + {"end", (PyCFunction) treebuilder_end, METH_VARARGS}, + {"xml", (PyCFunction) treebuilder_xml, METH_VARARGS}, + {"close", (PyCFunction) treebuilder_close, METH_VARARGS}, + {NULL, NULL} +}; + +static PyObject* +treebuilder_getattr(TreeBuilderObject* self, char* name) +{ + return Py_FindMethod(treebuilder_methods, (PyObject*) self, name); +} + +statichere PyTypeObject TreeBuilder_Type = { + PyObject_HEAD_INIT(NULL) + 0, "TreeBuilder", sizeof(TreeBuilderObject), 0, + /* methods */ + (destructor)treebuilder_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)treebuilder_getattr, /* tp_getattr */ +}; + +/* ==================================================================== */ +/* the expat interface */ + +#if defined(USE_EXPAT) + +#include "expat.h" + +#if defined(USE_PYEXPAT_CAPI) +#include "pyexpat.h" +static struct PyExpat_CAPI* expat_capi; +#define EXPAT(func) (expat_capi->func) +#else +#define EXPAT(func) (XML_##func) +#endif + +typedef struct { + PyObject_HEAD + + XML_Parser parser; + + PyObject* target; + PyObject* entity; + + PyObject* names; + + PyObject* handle_xml; + PyObject* handle_start; + PyObject* handle_data; + PyObject* handle_end; + + PyObject* handle_comment; + PyObject* handle_pi; + +} XMLParserObject; + +staticforward PyTypeObject XMLParser_Type; + +/* helpers */ + +#if defined(Py_USING_UNICODE) +LOCAL(int) +checkstring(const char* string, int size) +{ + int i; + + /* check if an 8-bit string contains UTF-8 characters */ + for (i = 0; i < size; i++) + if (string[i] & 0x80) + return 1; + + return 0; +} +#endif + +LOCAL(PyObject*) +makestring(const char* string, int size) +{ + /* convert a UTF-8 string to either a 7-bit ascii string or a + Unicode string */ + +#if defined(Py_USING_UNICODE) + if (checkstring(string, size)) + return PyUnicode_DecodeUTF8(string, size, "strict"); +#endif + + return PyString_FromStringAndSize(string, size); +} + +LOCAL(PyObject*) +makeuniversal(XMLParserObject* self, const char* string) +{ + /* convert a UTF-8 tag/attribute name from the expat parser + to a universal name string */ + + int size = strlen(string); + PyObject* key; + PyObject* value; + + /* look the 'raw' name up in the names dictionary */ + key = PyString_FromStringAndSize(string, size); + if (!key) + return NULL; + + value = PyDict_GetItem(self->names, key); + + if (value) { + Py_INCREF(value); + } else { + /* new name. convert to universal name, and decode as + necessary */ + + PyObject* tag; + char* p; + int i; + + /* look for namespace separator */ + for (i = 0; i < size; i++) + if (string[i] == '}') + break; + if (i != size) { + /* convert to universal name */ + tag = PyString_FromStringAndSize(NULL, size+1); + p = PyString_AS_STRING(tag); + p[0] = '{'; + memcpy(p+1, string, size); + size++; + } else { + /* plain name; use key as tag */ + Py_INCREF(key); + tag = key; + } + + /* decode universal name */ +#if defined(Py_USING_UNICODE) + /* inline makestring, to avoid duplicating the source string if + it's not an utf-8 string */ + p = PyString_AS_STRING(tag); + if (checkstring(p, size)) { + value = PyUnicode_DecodeUTF8(p, size, "strict"); + Py_DECREF(tag); + if (!value) { + Py_DECREF(key); + return NULL; + } + } else +#endif + value = tag; /* use tag as is */ + + /* add to names dictionary */ + if (PyDict_SetItem(self->names, key, value) < 0) { + Py_DECREF(key); + Py_DECREF(value); + return NULL; + } + } + + Py_DECREF(key); + return value; +} + +/* -------------------------------------------------------------------- */ +/* handlers */ + +static void +expat_default_handler(XMLParserObject* self, const XML_Char* data_in, + int data_len) +{ + PyObject* key; + PyObject* value; + PyObject* res; + + if (data_len < 2 || data_in[0] != '&') + return; + + key = makestring(data_in + 1, data_len - 2); + if (!key) + return; + + value = PyDict_GetItem(self->entity, key); + + if (value) { + if (TreeBuilder_CheckExact(self->target)) + res = treebuilder_handle_data( + (TreeBuilderObject*) self->target, value + ); + else if (self->handle_data) + res = PyObject_CallFunction(self->handle_data, "O", value); + else + res = NULL; + Py_XDECREF(res); + } else { + PyErr_Format( + PyExc_SyntaxError, "undefined entity &%s;: line %ld, column %ld", + PyString_AS_STRING(key), + EXPAT(GetErrorLineNumber)(self->parser), + EXPAT(GetErrorColumnNumber)(self->parser) + ); + } + + Py_DECREF(key); +} + +static void +expat_start_handler(XMLParserObject* self, const XML_Char* tag_in, + const XML_Char **attrib_in) +{ + PyObject* res; + PyObject* tag; + PyObject* attrib; + int ok; + + /* tag name */ + tag = makeuniversal(self, tag_in); + if (!tag) + return; /* parser will look for errors */ + + /* attributes */ + if (attrib_in[0]) { + attrib = PyDict_New(); + if (!attrib) + return; + while (attrib_in[0] && attrib_in[1]) { + PyObject* key = makeuniversal(self, attrib_in[0]); + PyObject* value = makestring(attrib_in[1], strlen(attrib_in[1])); + if (!key || !value) { + Py_XDECREF(value); + Py_XDECREF(key); + Py_DECREF(attrib); + return; + } + ok = PyDict_SetItem(attrib, key, value); + Py_DECREF(value); + Py_DECREF(key); + if (ok < 0) { + Py_DECREF(attrib); + return; + } + attrib_in += 2; + } + } else { + Py_INCREF(Py_None); + attrib = Py_None; + } + + if (TreeBuilder_CheckExact(self->target)) + /* shortcut */ + res = treebuilder_handle_start((TreeBuilderObject*) self->target, + tag, attrib); + else if (self->handle_start) + res = PyObject_CallFunction(self->handle_start, "OO", tag, attrib); + else + res = NULL; + + Py_DECREF(tag); + Py_DECREF(attrib); + + Py_XDECREF(res); +} + +static void +expat_data_handler(XMLParserObject* self, const XML_Char* data_in, + int data_len) +{ + PyObject* data; + PyObject* res; + + data = makestring(data_in, data_len); + if (!data) + return; /* parser will look for errors */ + + if (TreeBuilder_CheckExact(self->target)) + /* shortcut */ + res = treebuilder_handle_data((TreeBuilderObject*) self->target, data); + else if (self->handle_data) + res = PyObject_CallFunction(self->handle_data, "O", data); + else + res = NULL; + + Py_DECREF(data); + + Py_XDECREF(res); +} + +static void +expat_end_handler(XMLParserObject* self, const XML_Char* tag_in) +{ + PyObject* tag; + PyObject* res = NULL; + + if (TreeBuilder_CheckExact(self->target)) + /* shortcut */ + /* the standard tree builder doesn't look at the end tag */ + res = treebuilder_handle_end( + (TreeBuilderObject*) self->target, Py_None + ); + else if (self->handle_end) { + tag = makeuniversal(self, tag_in); + if (tag) { + res = PyObject_CallFunction(self->handle_end, "O", tag); + Py_DECREF(tag); + } + } + + Py_XDECREF(res); +} + +static void +expat_start_ns_handler(XMLParserObject* self, const XML_Char* prefix, + const XML_Char *uri) +{ + treebuilder_handle_namespace( + (TreeBuilderObject*) self->target, 1, prefix, uri + ); +} + +static void +expat_end_ns_handler(XMLParserObject* self, const XML_Char* prefix_in) +{ + treebuilder_handle_namespace( + (TreeBuilderObject*) self->target, 0, NULL, NULL + ); +} + +static void +expat_comment_handler(XMLParserObject* self, const XML_Char* comment_in) +{ + PyObject* comment; + PyObject* res; + + if (self->handle_comment) { + comment = makestring(comment_in, strlen(comment_in)); + if (comment) { + res = PyObject_CallFunction(self->handle_comment, "O", comment); + Py_XDECREF(res); + Py_DECREF(comment); + } + } +} + +static void +expat_pi_handler(XMLParserObject* self, const XML_Char* target_in, + const XML_Char* data_in) +{ + PyObject* target; + PyObject* data; + PyObject* res; + + if (self->handle_pi) { + target = makestring(target_in, strlen(target_in)); + data = makestring(data_in, strlen(data_in)); + if (target && data) { + res = PyObject_CallFunction(self->handle_pi, "OO", target, data); + Py_XDECREF(res); + Py_DECREF(data); + Py_DECREF(target); + } else { + Py_XDECREF(data); + Py_XDECREF(target); + } + } +} + +#if defined(Py_USING_UNICODE) +static int +expat_unknown_encoding_handler(XMLParserObject *self, const XML_Char *name, + XML_Encoding *info) +{ + PyObject* u; + Py_UNICODE* p; + unsigned char s[256]; + int i; + + memset(info, 0, sizeof(XML_Encoding)); + + for (i = 0; i < 256; i++) + s[i] = i; + + u = PyUnicode_Decode((char*) s, 256, name, "replace"); + if (!u) + return XML_STATUS_ERROR; + + if (PyUnicode_GET_SIZE(u) != 256) { + Py_DECREF(u); + return XML_STATUS_ERROR; + } + + p = PyUnicode_AS_UNICODE(u); + + for (i = 0; i < 256; i++) { + if (p[i] != Py_UNICODE_REPLACEMENT_CHARACTER) + info->map[i] = p[i]; + else + info->map[i] = -1; + } + + Py_DECREF(u); + + return XML_STATUS_OK; +} +#endif + +/* -------------------------------------------------------------------- */ +/* constructor and destructor */ + +static PyObject* +xmlparser(PyObject* self_, PyObject* args, PyObject* kw) +{ + XMLParserObject* self; + /* FIXME: does this need to be static? */ + static XML_Memory_Handling_Suite memory_handler; + + PyObject* target = NULL; + char* encoding = NULL; + static char* kwlist[] = { "target", "encoding", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "|Oz:XMLParser", kwlist, + &target, &encoding)) + return NULL; + +#if defined(USE_PYEXPAT_CAPI) + if (!expat_capi) { + PyErr_SetString( + PyExc_RuntimeError, "cannot load dispatch table from pyexpat" + ); + return NULL; + } +#endif + + self = PyObject_New(XMLParserObject, &XMLParser_Type); + if (self == NULL) + return NULL; + + self->entity = PyDict_New(); + if (!self->entity) { + PyObject_Del(self); + return NULL; + } + + self->names = PyDict_New(); + if (!self->names) { + PyObject_Del(self->entity); + PyObject_Del(self); + return NULL; + } + + memory_handler.malloc_fcn = PyObject_Malloc; + memory_handler.realloc_fcn = PyObject_Realloc; + memory_handler.free_fcn = PyObject_Free; + + self->parser = EXPAT(ParserCreate_MM)(encoding, &memory_handler, "}"); + if (!self->parser) { + PyObject_Del(self->names); + PyObject_Del(self->entity); + PyObject_Del(self); + PyErr_NoMemory(); + return NULL; + } + + /* setup target handlers */ + if (!target) { + target = treebuilder_new(); + if (!target) { + EXPAT(ParserFree)(self->parser); + PyObject_Del(self->names); + PyObject_Del(self->entity); + PyObject_Del(self); + return NULL; + } + } else + Py_INCREF(target); + self->target = target; + + self->handle_xml = PyObject_GetAttrString(target, "xml"); + self->handle_start = PyObject_GetAttrString(target, "start"); + self->handle_data = PyObject_GetAttrString(target, "data"); + self->handle_end = PyObject_GetAttrString(target, "end"); + self->handle_comment = PyObject_GetAttrString(target, "comment"); + self->handle_pi = PyObject_GetAttrString(target, "pi"); + + PyErr_Clear(); + + /* configure parser */ + EXPAT(SetUserData)(self->parser, self); + EXPAT(SetElementHandler)( + self->parser, + (XML_StartElementHandler) expat_start_handler, + (XML_EndElementHandler) expat_end_handler + ); + EXPAT(SetDefaultHandlerExpand)( + self->parser, + (XML_DefaultHandler) expat_default_handler + ); + EXPAT(SetCharacterDataHandler)( + self->parser, + (XML_CharacterDataHandler) expat_data_handler + ); + if (self->handle_comment) + EXPAT(SetCommentHandler)( + self->parser, + (XML_CommentHandler) expat_comment_handler + ); + if (self->handle_pi) + EXPAT(SetProcessingInstructionHandler)( + self->parser, + (XML_ProcessingInstructionHandler) expat_pi_handler + ); +#if defined(Py_USING_UNICODE) + EXPAT(SetUnknownEncodingHandler)( + self->parser, + (XML_UnknownEncodingHandler) expat_unknown_encoding_handler, NULL + ); +#endif + + ALLOC(sizeof(XMLParserObject), "create expatparser"); + + return (PyObject*) self; +} + +static void +xmlparser_dealloc(XMLParserObject* self) +{ + EXPAT(ParserFree)(self->parser); + + Py_XDECREF(self->handle_pi); + Py_XDECREF(self->handle_comment); + Py_XDECREF(self->handle_end); + Py_XDECREF(self->handle_data); + Py_XDECREF(self->handle_start); + Py_XDECREF(self->handle_xml); + + Py_DECREF(self->target); + Py_DECREF(self->entity); + Py_DECREF(self->names); + + RELEASE(sizeof(XMLParserObject), "destroy expatparser"); + + PyObject_Del(self); +} + +/* -------------------------------------------------------------------- */ +/* methods (in alphabetical order) */ + +LOCAL(PyObject*) +expat_parse(XMLParserObject* self, char* data, int data_len, int final) +{ + int ok; + + ok = EXPAT(Parse)(self->parser, data, data_len, final); + + if (PyErr_Occurred()) + return NULL; + + if (!ok) { + PyErr_Format( + PyExc_SyntaxError, "%s: line %ld, column %ld", + EXPAT(ErrorString)(EXPAT(GetErrorCode)(self->parser)), + EXPAT(GetErrorLineNumber)(self->parser), + EXPAT(GetErrorColumnNumber)(self->parser) + ); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject* +xmlparser_close(XMLParserObject* self, PyObject* args) +{ + /* end feeding data to parser */ + + PyObject* res; + if (!PyArg_ParseTuple(args, ":close")) + return NULL; + + res = expat_parse(self, "", 0, 1); + + if (res && TreeBuilder_CheckExact(self->target)) { + Py_DECREF(res); + return treebuilder_done((TreeBuilderObject*) self->target); + } + + return res; +} + +static PyObject* +xmlparser_feed(XMLParserObject* self, PyObject* args) +{ + /* feed data to parser */ + + char* data; + int data_len; + if (!PyArg_ParseTuple(args, "s#:feed", &data, &data_len)) + return NULL; + + return expat_parse(self, data, data_len, 0); +} + +static PyObject* +xmlparser_parse(XMLParserObject* self, PyObject* args) +{ + /* (internal) parse until end of input stream */ + + PyObject* reader; + PyObject* buffer; + PyObject* res; + + PyObject* fileobj; + if (!PyArg_ParseTuple(args, "O:_parse", &fileobj)) + return NULL; + + reader = PyObject_GetAttrString(fileobj, "read"); + if (!reader) + return NULL; + + /* read from open file object */ + for (;;) { + + buffer = PyObject_CallFunction(reader, "i", 64*1024); + + if (!buffer) { + /* read failed (e.g. due to KeyboardInterrupt) */ + Py_DECREF(reader); + return NULL; + } + + if (!PyString_CheckExact(buffer) || PyString_GET_SIZE(buffer) == 0) { + Py_DECREF(buffer); + break; + } + + res = expat_parse( + self, PyString_AS_STRING(buffer), PyString_GET_SIZE(buffer), 0 + ); + + Py_DECREF(buffer); + + if (!res) { + Py_DECREF(reader); + return NULL; + } + Py_DECREF(res); + + } + + Py_DECREF(reader); + + res = expat_parse(self, "", 0, 1); + + if (res && TreeBuilder_CheckExact(self->target)) { + Py_DECREF(res); + return treebuilder_done((TreeBuilderObject*) self->target); + } + + return res; +} + +static PyObject* +xmlparser_setevents(XMLParserObject* self, PyObject* args) +{ + /* activate element event reporting */ + + Py_ssize_t i; + TreeBuilderObject* target; + + PyObject* events; /* event collector */ + PyObject* event_set = Py_None; + if (!PyArg_ParseTuple(args, "O!|O:_setevents", &PyList_Type, &events, + &event_set)) + return NULL; + + if (!TreeBuilder_CheckExact(self->target)) { + PyErr_SetString( + PyExc_TypeError, + "event handling only supported for cElementTree.Treebuilder " + "targets" + ); + return NULL; + } + + target = (TreeBuilderObject*) self->target; + + Py_INCREF(events); + Py_XDECREF(target->events); + target->events = events; + + /* clear out existing events */ + Py_XDECREF(target->start_event_obj); target->start_event_obj = NULL; + Py_XDECREF(target->end_event_obj); target->end_event_obj = NULL; + Py_XDECREF(target->start_ns_event_obj); target->start_ns_event_obj = NULL; + Py_XDECREF(target->end_ns_event_obj); target->end_ns_event_obj = NULL; + + if (event_set == Py_None) { + /* default is "end" only */ + target->end_event_obj = PyString_FromString("end"); + Py_RETURN_NONE; + } + + if (!PyTuple_Check(event_set)) /* FIXME: handle arbitrary sequences */ + goto error; + + for (i = 0; i < PyTuple_GET_SIZE(event_set); i++) { + PyObject* item = PyTuple_GET_ITEM(event_set, i); + char* event; + if (!PyString_Check(item)) + goto error; + event = PyString_AS_STRING(item); + if (strcmp(event, "start") == 0) { + Py_INCREF(item); + target->start_event_obj = item; + } else if (strcmp(event, "end") == 0) { + Py_INCREF(item); + Py_XDECREF(target->end_event_obj); + target->end_event_obj = item; + } else if (strcmp(event, "start-ns") == 0) { + Py_INCREF(item); + Py_XDECREF(target->start_ns_event_obj); + target->start_ns_event_obj = item; + EXPAT(SetNamespaceDeclHandler)( + self->parser, + (XML_StartNamespaceDeclHandler) expat_start_ns_handler, + (XML_EndNamespaceDeclHandler) expat_end_ns_handler + ); + } else if (strcmp(event, "end-ns") == 0) { + Py_INCREF(item); + Py_XDECREF(target->end_ns_event_obj); + target->end_ns_event_obj = item; + EXPAT(SetNamespaceDeclHandler)( + self->parser, + (XML_StartNamespaceDeclHandler) expat_start_ns_handler, + (XML_EndNamespaceDeclHandler) expat_end_ns_handler + ); + } else { + PyErr_Format( + PyExc_ValueError, + "unknown event '%s'", event + ); + return NULL; + } + } + + Py_RETURN_NONE; + + error: + PyErr_SetString( + PyExc_TypeError, + "invalid event tuple" + ); + return NULL; +} + +static PyMethodDef xmlparser_methods[] = { + {"feed", (PyCFunction) xmlparser_feed, METH_VARARGS}, + {"close", (PyCFunction) xmlparser_close, METH_VARARGS}, + {"_parse", (PyCFunction) xmlparser_parse, METH_VARARGS}, + {"_setevents", (PyCFunction) xmlparser_setevents, METH_VARARGS}, + {NULL, NULL} +}; + +static PyObject* +xmlparser_getattr(XMLParserObject* self, char* name) +{ + PyObject* res; + + res = Py_FindMethod(xmlparser_methods, (PyObject*) self, name); + if (res) + return res; + + PyErr_Clear(); + + if (strcmp(name, "entity") == 0) + res = self->entity; + else if (strcmp(name, "target") == 0) + res = self->target; + else if (strcmp(name, "version") == 0) { + char buffer[100]; + sprintf(buffer, "Expat %d.%d.%d", XML_MAJOR_VERSION, + XML_MINOR_VERSION, XML_MICRO_VERSION); + return PyString_FromString(buffer); + } else { + PyErr_SetString(PyExc_AttributeError, name); + return NULL; + } + + Py_INCREF(res); + return res; +} + +statichere PyTypeObject XMLParser_Type = { + PyObject_HEAD_INIT(NULL) + 0, "XMLParser", sizeof(XMLParserObject), 0, + /* methods */ + (destructor)xmlparser_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)xmlparser_getattr, /* tp_getattr */ +}; + +#endif + +/* ==================================================================== */ +/* python module interface */ + +static PyMethodDef _functions[] = { + {"Element", (PyCFunction) element, METH_VARARGS|METH_KEYWORDS}, + {"SubElement", (PyCFunction) subelement, METH_VARARGS|METH_KEYWORDS}, + {"TreeBuilder", (PyCFunction) treebuilder, METH_VARARGS}, +#if defined(USE_EXPAT) + {"XMLParser", (PyCFunction) xmlparser, METH_VARARGS|METH_KEYWORDS}, + {"XMLTreeBuilder", (PyCFunction) xmlparser, METH_VARARGS|METH_KEYWORDS}, +#endif + {NULL, NULL} +}; + +DL_EXPORT(void) +init_elementtree(void) +{ + PyObject* m; + PyObject* g; + char* bootstrap; +#if defined(USE_PYEXPAT_CAPI) + struct PyExpat_CAPI* capi; +#endif + + /* Patch object type */ + Element_Type.ob_type = TreeBuilder_Type.ob_type = &PyType_Type; +#if defined(USE_EXPAT) + XMLParser_Type.ob_type = &PyType_Type; +#endif + + m = Py_InitModule("_elementtree", _functions); + if (!m) + return; + + /* python glue code */ + + g = PyDict_New(); + if (!g) + return; + + PyDict_SetItemString(g, "__builtins__", PyEval_GetBuiltins()); + + bootstrap = ( + +#if (PY_VERSION_HEX >= 0x02020000 && PY_VERSION_HEX < 0x02030000) + "from __future__ import generators\n" /* enable yield under 2.2 */ +#endif + + "from copy import copy, deepcopy\n" + + "try:\n" + " from xml.etree import ElementTree\n" + "except ImportError:\n" + " import ElementTree\n" + "ET = ElementTree\n" + "del ElementTree\n" + + "import _elementtree as cElementTree\n" + + "try:\n" /* check if copy works as is */ + " copy(cElementTree.Element('x'))\n" + "except:\n" + " def copyelement(elem):\n" + " return elem\n" + + "def Comment(text=None):\n" /* public */ + " element = cElementTree.Element(ET.Comment)\n" + " element.text = text\n" + " return element\n" + "cElementTree.Comment = Comment\n" + + "class ElementTree(ET.ElementTree):\n" /* public */ + " def parse(self, source, parser=None):\n" + " if not hasattr(source, 'read'):\n" + " source = open(source, 'rb')\n" + " if parser is not None:\n" + " while 1:\n" + " data = source.read(65536)\n" + " if not data:\n" + " break\n" + " parser.feed(data)\n" + " self._root = parser.close()\n" + " else:\n" + " parser = cElementTree.XMLParser()\n" + " self._root = parser._parse(source)\n" + " return self._root\n" + "cElementTree.ElementTree = ElementTree\n" + + "def getiterator(node, tag=None):\n" /* helper */ + " if tag == '*':\n" + " tag = None\n" +#if (PY_VERSION_HEX < 0x02020000) + " nodes = []\n" /* 2.1 doesn't have yield */ + " if tag is None or node.tag == tag:\n" + " nodes.append(node)\n" + " for node in node:\n" + " nodes.extend(getiterator(node, tag))\n" + " return nodes\n" +#else + " if tag is None or node.tag == tag:\n" + " yield node\n" + " for node in node:\n" + " for node in getiterator(node, tag):\n" + " yield node\n" +#endif + + "def parse(source, parser=None):\n" /* public */ + " tree = ElementTree()\n" + " tree.parse(source, parser)\n" + " return tree\n" + "cElementTree.parse = parse\n" + +#if (PY_VERSION_HEX < 0x02020000) + "if hasattr(ET, 'iterparse'):\n" + " cElementTree.iterparse = ET.iterparse\n" /* delegate on 2.1 */ +#else + "class iterparse(object):\n" + " root = None\n" + " def __init__(self, file, events=None):\n" + " if not hasattr(file, 'read'):\n" + " file = open(file, 'rb')\n" + " self._file = file\n" + " self._events = events\n" + " def __iter__(self):\n" + " events = []\n" + " b = cElementTree.TreeBuilder()\n" + " p = cElementTree.XMLParser(b)\n" + " p._setevents(events, self._events)\n" + " while 1:\n" + " data = self._file.read(16384)\n" + " if not data:\n" + " break\n" + " p.feed(data)\n" + " for event in events:\n" + " yield event\n" + " del events[:]\n" + " root = p.close()\n" + " for event in events:\n" + " yield event\n" + " self.root = root\n" + "cElementTree.iterparse = iterparse\n" +#endif + + "def PI(target, text=None):\n" /* public */ + " element = cElementTree.Element(ET.ProcessingInstruction)\n" + " element.text = target\n" + " if text:\n" + " element.text = element.text + ' ' + text\n" + " return element\n" + + " elem = cElementTree.Element(ET.PI)\n" + " elem.text = text\n" + " return elem\n" + "cElementTree.PI = cElementTree.ProcessingInstruction = PI\n" + + "def XML(text):\n" /* public */ + " parser = cElementTree.XMLParser()\n" + " parser.feed(text)\n" + " return parser.close()\n" + "cElementTree.XML = cElementTree.fromstring = XML\n" + + "def XMLID(text):\n" /* public */ + " tree = XML(text)\n" + " ids = {}\n" + " for elem in tree.getiterator():\n" + " id = elem.get('id')\n" + " if id:\n" + " ids[id] = elem\n" + " return tree, ids\n" + "cElementTree.XMLID = XMLID\n" + + "cElementTree.dump = ET.dump\n" + "cElementTree.ElementPath = ElementPath = ET.ElementPath\n" + "cElementTree.iselement = ET.iselement\n" + "cElementTree.QName = ET.QName\n" + "cElementTree.tostring = ET.tostring\n" + "cElementTree.VERSION = '" VERSION "'\n" + "cElementTree.__version__ = '" VERSION "'\n" + "cElementTree.XMLParserError = SyntaxError\n" + + ); + + PyRun_String(bootstrap, Py_file_input, g, NULL); + + elementpath_obj = PyDict_GetItemString(g, "ElementPath"); + + elementtree_copyelement_obj = PyDict_GetItemString(g, "copyelement"); + if (elementtree_copyelement_obj) { + /* reduce hack needed; enable reduce method */ + PyMethodDef* mp; + for (mp = element_methods; mp->ml_name; mp++) + if (mp->ml_meth == (PyCFunction) element_reduce) { + mp->ml_name = "__reduce__"; + break; + } + } else + PyErr_Clear(); + elementtree_deepcopy_obj = PyDict_GetItemString(g, "deepcopy"); + elementtree_getiterator_obj = PyDict_GetItemString(g, "getiterator"); + +#if defined(USE_PYEXPAT_CAPI) + /* link against pyexpat, if possible */ + capi = PyCObject_Import("pyexpat", "expat_CAPI"); + if (capi && + strcmp(capi->magic, PyExpat_CAPI_MAGIC) == 0 && + capi->size <= sizeof(*expat_capi) && + capi->MAJOR_VERSION == XML_MAJOR_VERSION && + capi->MINOR_VERSION == XML_MINOR_VERSION && + capi->MICRO_VERSION == XML_MICRO_VERSION) + expat_capi = capi; + else + expat_capi = NULL; +#endif + +} diff --git a/sys/src/cmd/python/Modules/_functoolsmodule.c b/sys/src/cmd/python/Modules/_functoolsmodule.c new file mode 100644 index 000000000..54abb89d8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_functoolsmodule.c @@ -0,0 +1,277 @@ + +#include "Python.h" +#include "structmember.h" + +/* _functools module written and maintained + by Hye-Shik Chang <perky@FreeBSD.org> + with adaptations by Raymond Hettinger <python@rcn.com> + Copyright (c) 2004, 2005, 2006 Python Software Foundation. + All rights reserved. +*/ + +/* partial object **********************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *fn; + PyObject *args; + PyObject *kw; + PyObject *dict; + PyObject *weakreflist; /* List of weak references */ +} partialobject; + +static PyTypeObject partial_type; + +static PyObject * +partial_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *func; + partialobject *pto; + + if (PyTuple_GET_SIZE(args) < 1) { + PyErr_SetString(PyExc_TypeError, + "type 'partial' takes at least one argument"); + return NULL; + } + + func = PyTuple_GET_ITEM(args, 0); + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "the first argument must be callable"); + return NULL; + } + + /* create partialobject structure */ + pto = (partialobject *)type->tp_alloc(type, 0); + if (pto == NULL) + return NULL; + + pto->fn = func; + Py_INCREF(func); + pto->args = PyTuple_GetSlice(args, 1, PY_SSIZE_T_MAX); + if (pto->args == NULL) { + pto->kw = NULL; + Py_DECREF(pto); + return NULL; + } + if (kw != NULL) { + pto->kw = PyDict_Copy(kw); + if (pto->kw == NULL) { + Py_DECREF(pto); + return NULL; + } + } else { + pto->kw = Py_None; + Py_INCREF(Py_None); + } + + pto->weakreflist = NULL; + pto->dict = NULL; + + return (PyObject *)pto; +} + +static void +partial_dealloc(partialobject *pto) +{ + PyObject_GC_UnTrack(pto); + if (pto->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) pto); + Py_XDECREF(pto->fn); + Py_XDECREF(pto->args); + Py_XDECREF(pto->kw); + Py_XDECREF(pto->dict); + pto->ob_type->tp_free(pto); +} + +static PyObject * +partial_call(partialobject *pto, PyObject *args, PyObject *kw) +{ + PyObject *ret; + PyObject *argappl = NULL, *kwappl = NULL; + + assert (PyCallable_Check(pto->fn)); + assert (PyTuple_Check(pto->args)); + assert (pto->kw == Py_None || PyDict_Check(pto->kw)); + + if (PyTuple_GET_SIZE(pto->args) == 0) { + argappl = args; + Py_INCREF(args); + } else if (PyTuple_GET_SIZE(args) == 0) { + argappl = pto->args; + Py_INCREF(pto->args); + } else { + argappl = PySequence_Concat(pto->args, args); + if (argappl == NULL) + return NULL; + } + + if (pto->kw == Py_None) { + kwappl = kw; + Py_XINCREF(kw); + } else { + kwappl = PyDict_Copy(pto->kw); + if (kwappl == NULL) { + Py_DECREF(argappl); + return NULL; + } + if (kw != NULL) { + if (PyDict_Merge(kwappl, kw, 1) != 0) { + Py_DECREF(argappl); + Py_DECREF(kwappl); + return NULL; + } + } + } + + ret = PyObject_Call(pto->fn, argappl, kwappl); + Py_DECREF(argappl); + Py_XDECREF(kwappl); + return ret; +} + +static int +partial_traverse(partialobject *pto, visitproc visit, void *arg) +{ + Py_VISIT(pto->fn); + Py_VISIT(pto->args); + Py_VISIT(pto->kw); + Py_VISIT(pto->dict); + return 0; +} + +PyDoc_STRVAR(partial_doc, +"partial(func, *args, **keywords) - new function with partial application\n\ + of the given arguments and keywords.\n"); + +#define OFF(x) offsetof(partialobject, x) +static PyMemberDef partial_memberlist[] = { + {"func", T_OBJECT, OFF(fn), READONLY, + "function object to use in future partial calls"}, + {"args", T_OBJECT, OFF(args), READONLY, + "tuple of arguments to future partial calls"}, + {"keywords", T_OBJECT, OFF(kw), READONLY, + "dictionary of keyword arguments to future partial calls"}, + {NULL} /* Sentinel */ +}; + +static PyObject * +partial_get_dict(partialobject *pto) +{ + if (pto->dict == NULL) { + pto->dict = PyDict_New(); + if (pto->dict == NULL) + return NULL; + } + Py_INCREF(pto->dict); + return pto->dict; +} + +static int +partial_set_dict(partialobject *pto, PyObject *value) +{ + PyObject *tmp; + + /* It is illegal to del p.__dict__ */ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "a partial object's dictionary may not be deleted"); + return -1; + } + /* Can only set __dict__ to a dictionary */ + if (!PyDict_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "setting partial object's dictionary to a non-dict"); + return -1; + } + tmp = pto->dict; + Py_INCREF(value); + pto->dict = value; + Py_XDECREF(tmp); + return 0; +} + +static PyGetSetDef partial_getsetlist[] = { + {"__dict__", (getter)partial_get_dict, (setter)partial_set_dict}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject partial_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "functools.partial", /* tp_name */ + sizeof(partialobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)partial_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)partial_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + partial_doc, /* tp_doc */ + (traverseproc)partial_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(partialobject, weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + partial_memberlist, /* tp_members */ + partial_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(partialobject, dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + partial_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* module level code ********************************************************/ + +PyDoc_STRVAR(module_doc, +"Tools that operate on functions."); + +static PyMethodDef module_methods[] = { + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +init_functools(void) +{ + int i; + PyObject *m; + char *name; + PyTypeObject *typelist[] = { + &partial_type, + NULL + }; + + m = Py_InitModule3("_functools", module_methods, module_doc); + if (m == NULL) + return; + + for (i=0 ; typelist[i] != NULL ; i++) { + if (PyType_Ready(typelist[i]) < 0) + return; + name = strchr(typelist[i]->tp_name, '.'); + assert (name != NULL); + Py_INCREF(typelist[i]); + PyModule_AddObject(m, name+1, (PyObject *)typelist[i]); + } +} diff --git a/sys/src/cmd/python/Modules/_hashopenssl.c b/sys/src/cmd/python/Modules/_hashopenssl.c new file mode 100644 index 000000000..859644fc7 --- /dev/null +++ b/sys/src/cmd/python/Modules/_hashopenssl.c @@ -0,0 +1,487 @@ +/* Module that wraps all OpenSSL hash algorithms */ + +/* + * Copyright (C) 2005 Gregory P. Smith (greg@electricrain.com) + * Licensed to PSF under a Contributor Agreement. + * + * Derived from a skeleton of shamodule.c containing work performed by: + * + * Andrew Kuchling (amk@amk.ca) + * Greg Stein (gstein@lyra.org) + * + */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" +#include "structmember.h" + +/* EVP is the preferred interface to hashing in OpenSSL */ +#include <openssl/evp.h> + + +#ifndef HASH_OBJ_CONSTRUCTOR +#define HASH_OBJ_CONSTRUCTOR 0 +#endif + +typedef struct { + PyObject_HEAD + PyObject *name; /* name of this hash algorithm */ + EVP_MD_CTX ctx; /* OpenSSL message digest context */ +} EVPobject; + + +static PyTypeObject EVPtype; + + +#define DEFINE_CONSTS_FOR_NEW(Name) \ + static PyObject *CONST_ ## Name ## _name_obj; \ + static EVP_MD_CTX CONST_new_ ## Name ## _ctx; \ + static EVP_MD_CTX *CONST_new_ ## Name ## _ctx_p = NULL; + +DEFINE_CONSTS_FOR_NEW(md5) +DEFINE_CONSTS_FOR_NEW(sha1) +DEFINE_CONSTS_FOR_NEW(sha224) +DEFINE_CONSTS_FOR_NEW(sha256) +DEFINE_CONSTS_FOR_NEW(sha384) +DEFINE_CONSTS_FOR_NEW(sha512) + + +static EVPobject * +newEVPobject(PyObject *name) +{ + EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype); + + /* save the name for .name to return */ + if (retval != NULL) { + Py_INCREF(name); + retval->name = name; + } + + return retval; +} + +/* Internal methods for a hash object */ + +static void +EVP_dealloc(PyObject *ptr) +{ + EVP_MD_CTX_cleanup(&((EVPobject *)ptr)->ctx); + Py_XDECREF(((EVPobject *)ptr)->name); + PyObject_Del(ptr); +} + + +/* External methods for a hash object */ + +PyDoc_STRVAR(EVP_copy__doc__, "Return a copy of the hash object."); + +static PyObject * +EVP_copy(EVPobject *self, PyObject *unused) +{ + EVPobject *newobj; + + if ( (newobj = newEVPobject(self->name))==NULL) + return NULL; + + EVP_MD_CTX_copy(&newobj->ctx, &self->ctx); + return (PyObject *)newobj; +} + +PyDoc_STRVAR(EVP_digest__doc__, +"Return the digest value as a string of binary data."); + +static PyObject * +EVP_digest(EVPobject *self, PyObject *unused) +{ + unsigned char digest[EVP_MAX_MD_SIZE]; + EVP_MD_CTX temp_ctx; + PyObject *retval; + unsigned int digest_size; + + EVP_MD_CTX_copy(&temp_ctx, &self->ctx); + digest_size = EVP_MD_CTX_size(&temp_ctx); + EVP_DigestFinal(&temp_ctx, digest, NULL); + + retval = PyString_FromStringAndSize((const char *)digest, digest_size); + EVP_MD_CTX_cleanup(&temp_ctx); + return retval; +} + +PyDoc_STRVAR(EVP_hexdigest__doc__, +"Return the digest value as a string of hexadecimal digits."); + +static PyObject * +EVP_hexdigest(EVPobject *self, PyObject *unused) +{ + unsigned char digest[EVP_MAX_MD_SIZE]; + EVP_MD_CTX temp_ctx; + PyObject *retval; + char *hex_digest; + unsigned int i, j, digest_size; + + /* Get the raw (binary) digest value */ + EVP_MD_CTX_copy(&temp_ctx, &self->ctx); + digest_size = EVP_MD_CTX_size(&temp_ctx); + EVP_DigestFinal(&temp_ctx, digest, NULL); + + EVP_MD_CTX_cleanup(&temp_ctx); + + /* Create a new string */ + /* NOTE: not thread safe! modifying an already created string object */ + /* (not a problem because we hold the GIL by default) */ + retval = PyString_FromStringAndSize(NULL, digest_size * 2); + if (!retval) + return NULL; + hex_digest = PyString_AsString(retval); + if (!hex_digest) { + Py_DECREF(retval); + return NULL; + } + + /* Make hex version of the digest */ + for(i=j=0; i<digest_size; i++) { + char c; + c = (digest[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + c = (digest[i] & 0xf); + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + } + return retval; +} + +PyDoc_STRVAR(EVP_update__doc__, +"Update this hash object's state with the provided string."); + +static PyObject * +EVP_update(EVPobject *self, PyObject *args) +{ + unsigned char *cp; + Py_ssize_t len; + + if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + return NULL; + + EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, + unsigned int)); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef EVP_methods[] = { + {"update", (PyCFunction)EVP_update, METH_VARARGS, EVP_update__doc__}, + {"digest", (PyCFunction)EVP_digest, METH_NOARGS, EVP_digest__doc__}, + {"hexdigest", (PyCFunction)EVP_hexdigest, METH_NOARGS, EVP_hexdigest__doc__}, + {"copy", (PyCFunction)EVP_copy, METH_NOARGS, EVP_copy__doc__}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +EVP_get_block_size(EVPobject *self, void *closure) +{ + return PyInt_FromLong(EVP_MD_CTX_block_size(&((EVPobject *)self)->ctx)); +} + +static PyObject * +EVP_get_digest_size(EVPobject *self, void *closure) +{ + return PyInt_FromLong(EVP_MD_CTX_size(&((EVPobject *)self)->ctx)); +} + +static PyMemberDef EVP_members[] = { + {"name", T_OBJECT, offsetof(EVPobject, name), READONLY, PyDoc_STR("algorithm name.")}, + {NULL} /* Sentinel */ +}; + +static PyGetSetDef EVP_getseters[] = { + {"digest_size", + (getter)EVP_get_digest_size, NULL, + NULL, + NULL}, + {"block_size", + (getter)EVP_get_block_size, NULL, + NULL, + NULL}, + /* the old md5 and sha modules support 'digest_size' as in PEP 247. + * the old sha module also supported 'digestsize'. ugh. */ + {"digestsize", + (getter)EVP_get_digest_size, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +}; + + +static PyObject * +EVP_repr(PyObject *self) +{ + char buf[100]; + PyOS_snprintf(buf, sizeof(buf), "<%s HASH object @ %p>", + PyString_AsString(((EVPobject *)self)->name), self); + return PyString_FromString(buf); +} + +#if HASH_OBJ_CONSTRUCTOR +static int +EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"name", "string", NULL}; + PyObject *name_obj = NULL; + char *nameStr; + unsigned char *cp = NULL; + Py_ssize_t len = 0; + const EVP_MD *digest; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s#:HASH", kwlist, + &name_obj, &cp, &len)) { + return -1; + } + + if (!PyArg_Parse(name_obj, "s", &nameStr)) { + PyErr_SetString(PyExc_TypeError, "name must be a string"); + return -1; + } + + digest = EVP_get_digestbyname(nameStr); + if (!digest) { + PyErr_SetString(PyExc_ValueError, "unknown hash function"); + return -1; + } + EVP_DigestInit(&self->ctx, digest); + + self->name = name_obj; + Py_INCREF(self->name); + + if (cp && len) + EVP_DigestUpdate(&self->ctx, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, + unsigned int)); + + return 0; +} +#endif + + +PyDoc_STRVAR(hashtype_doc, +"A hash represents the object used to calculate a checksum of a\n\ +string of information.\n\ +\n\ +Methods:\n\ +\n\ +update() -- updates the current digest with an additional string\n\ +digest() -- return the current digest value\n\ +hexdigest() -- return the current digest as a string of hexadecimal digits\n\ +copy() -- return a copy of the current hash object\n\ +\n\ +Attributes:\n\ +\n\ +name -- the hash algorithm being used by this object\n\ +digest_size -- number of bytes in this hashes output\n"); + +static PyTypeObject EVPtype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_hashlib.HASH", /*tp_name*/ + sizeof(EVPobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + EVP_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + EVP_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + hashtype_doc, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + EVP_methods, /* tp_methods */ + EVP_members, /* tp_members */ + EVP_getseters, /* tp_getset */ +#if 1 + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ +#endif +#if HASH_OBJ_CONSTRUCTOR + (initproc)EVP_tp_init, /* tp_init */ +#endif +}; + +static PyObject * +EVPnew(PyObject *name_obj, + const EVP_MD *digest, const EVP_MD_CTX *initial_ctx, + const unsigned char *cp, unsigned int len) +{ + EVPobject *self; + + if (!digest && !initial_ctx) { + PyErr_SetString(PyExc_ValueError, "unsupported hash type"); + return NULL; + } + + if ((self = newEVPobject(name_obj)) == NULL) + return NULL; + + if (initial_ctx) { + EVP_MD_CTX_copy(&self->ctx, initial_ctx); + } else { + EVP_DigestInit(&self->ctx, digest); + } + + if (cp && len) + EVP_DigestUpdate(&self->ctx, cp, len); + + return (PyObject *)self; +} + + +/* The module-level function: new() */ + +PyDoc_STRVAR(EVP_new__doc__, +"Return a new hash object using the named algorithm.\n\ +An optional string argument may be provided and will be\n\ +automatically hashed.\n\ +\n\ +The MD5 and SHA1 algorithms are always supported.\n"); + +static PyObject * +EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) +{ + static char *kwlist[] = {"name", "string", NULL}; + PyObject *name_obj = NULL; + char *name; + const EVP_MD *digest; + unsigned char *cp = NULL; + Py_ssize_t len = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s#:new", kwlist, + &name_obj, &cp, &len)) { + return NULL; + } + + if (!PyArg_Parse(name_obj, "s", &name)) { + PyErr_SetString(PyExc_TypeError, "name must be a string"); + return NULL; + } + + digest = EVP_get_digestbyname(name); + + return EVPnew(name_obj, digest, NULL, cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, + unsigned int)); +} + +/* + * This macro generates constructor function definitions for specific + * hash algorithms. These constructors are much faster than calling + * the generic one passing it a python string and are noticably + * faster than calling a python new() wrapper. Thats important for + * code that wants to make hashes of a bunch of small strings. + */ +#define GEN_CONSTRUCTOR(NAME) \ + static PyObject * \ + EVP_new_ ## NAME (PyObject *self, PyObject *args) \ + { \ + unsigned char *cp = NULL; \ + Py_ssize_t len = 0; \ + \ + if (!PyArg_ParseTuple(args, "|s#:" #NAME , &cp, &len)) { \ + return NULL; \ + } \ + \ + return EVPnew( \ + CONST_ ## NAME ## _name_obj, \ + NULL, \ + CONST_new_ ## NAME ## _ctx_p, \ + cp, Py_SAFE_DOWNCAST(len, Py_ssize_t, unsigned int)); \ + } + +/* a PyMethodDef structure for the constructor */ +#define CONSTRUCTOR_METH_DEF(NAME) \ + {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \ + PyDoc_STR("Returns a " #NAME \ + " hash object; optionally initialized with a string") \ + } + +/* used in the init function to setup a constructor */ +#define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ + CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \ + if (EVP_get_digestbyname(#NAME)) { \ + CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \ + EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \ + } \ +} while (0); + +GEN_CONSTRUCTOR(md5) +GEN_CONSTRUCTOR(sha1) +GEN_CONSTRUCTOR(sha224) +GEN_CONSTRUCTOR(sha256) +GEN_CONSTRUCTOR(sha384) +GEN_CONSTRUCTOR(sha512) + +/* List of functions exported by this module */ + +static struct PyMethodDef EVP_functions[] = { + {"new", (PyCFunction)EVP_new, METH_VARARGS|METH_KEYWORDS, EVP_new__doc__}, + CONSTRUCTOR_METH_DEF(md5), + CONSTRUCTOR_METH_DEF(sha1), + CONSTRUCTOR_METH_DEF(sha224), + CONSTRUCTOR_METH_DEF(sha256), + CONSTRUCTOR_METH_DEF(sha384), + CONSTRUCTOR_METH_DEF(sha512), + {NULL, NULL} /* Sentinel */ +}; + + +/* Initialize this module. */ + +PyMODINIT_FUNC +init_hashlib(void) +{ + PyObject *m; + + OpenSSL_add_all_digests(); + + /* TODO build EVP_functions openssl_* entries dynamically based + * on what hashes are supported rather than listing many + * but having some be unsupported. Only init appropriate + * constants. */ + + EVPtype.ob_type = &PyType_Type; + if (PyType_Ready(&EVPtype) < 0) + return; + + m = Py_InitModule("_hashlib", EVP_functions); + if (m == NULL) + return; + +#if HASH_OBJ_CONSTRUCTOR + Py_INCREF(&EVPtype); + PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype); +#endif + + /* these constants are used by the convenience constructors */ + INIT_CONSTRUCTOR_CONSTANTS(md5); + INIT_CONSTRUCTOR_CONSTANTS(sha1); + INIT_CONSTRUCTOR_CONSTANTS(sha224); + INIT_CONSTRUCTOR_CONSTANTS(sha256); + INIT_CONSTRUCTOR_CONSTANTS(sha384); + INIT_CONSTRUCTOR_CONSTANTS(sha512); +} diff --git a/sys/src/cmd/python/Modules/_heapqmodule.c b/sys/src/cmd/python/Modules/_heapqmodule.c new file mode 100644 index 000000000..3f902cab5 --- /dev/null +++ b/sys/src/cmd/python/Modules/_heapqmodule.c @@ -0,0 +1,619 @@ +/* Drop in replacement for heapq.py + +C implementation derived directly from heapq.py in Py2.3 +which was written by Kevin O'Connor, augmented by Tim Peters, +annotated by Fran�ois Pinard, and converted to C by Raymond Hettinger. + +*/ + +#include "Python.h" + +static int +_siftdown(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) +{ + PyObject *newitem, *parent; + int cmp; + Py_ssize_t parentpos; + + assert(PyList_Check(heap)); + if (pos >= PyList_GET_SIZE(heap)) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return -1; + } + + newitem = PyList_GET_ITEM(heap, pos); + Py_INCREF(newitem); + /* Follow the path to the root, moving parents down until finding + a place newitem fits. */ + while (pos > startpos){ + parentpos = (pos - 1) >> 1; + parent = PyList_GET_ITEM(heap, parentpos); + cmp = PyObject_RichCompareBool(parent, newitem, Py_LE); + if (cmp == -1) { + Py_DECREF(newitem); + return -1; + } + if (cmp == 1) + break; + Py_INCREF(parent); + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, parent); + pos = parentpos; + } + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, newitem); + return 0; +} + +static int +_siftup(PyListObject *heap, Py_ssize_t pos) +{ + Py_ssize_t startpos, endpos, childpos, rightpos; + int cmp; + PyObject *newitem, *tmp; + + assert(PyList_Check(heap)); + endpos = PyList_GET_SIZE(heap); + startpos = pos; + if (pos >= endpos) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return -1; + } + newitem = PyList_GET_ITEM(heap, pos); + Py_INCREF(newitem); + + /* Bubble up the smaller child until hitting a leaf. */ + childpos = 2*pos + 1; /* leftmost child position */ + while (childpos < endpos) { + /* Set childpos to index of smaller child. */ + rightpos = childpos + 1; + if (rightpos < endpos) { + cmp = PyObject_RichCompareBool( + PyList_GET_ITEM(heap, rightpos), + PyList_GET_ITEM(heap, childpos), + Py_LE); + if (cmp == -1) { + Py_DECREF(newitem); + return -1; + } + if (cmp == 1) + childpos = rightpos; + } + /* Move the smaller child up. */ + tmp = PyList_GET_ITEM(heap, childpos); + Py_INCREF(tmp); + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, tmp); + pos = childpos; + childpos = 2*pos + 1; + } + + /* The leaf at pos is empty now. Put newitem there, and and bubble + it up to its final resting place (by sifting its parents down). */ + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, newitem); + return _siftdown(heap, startpos, pos); +} + +static PyObject * +heappush(PyObject *self, PyObject *args) +{ + PyObject *heap, *item; + + if (!PyArg_UnpackTuple(args, "heappush", 2, 2, &heap, &item)) + return NULL; + + if (!PyList_Check(heap)) { + PyErr_SetString(PyExc_TypeError, "heap argument must be a list"); + return NULL; + } + + if (PyList_Append(heap, item) == -1) + return NULL; + + if (_siftdown((PyListObject *)heap, 0, PyList_GET_SIZE(heap)-1) == -1) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(heappush_doc, +"Push item onto heap, maintaining the heap invariant."); + +static PyObject * +heappop(PyObject *self, PyObject *heap) +{ + PyObject *lastelt, *returnitem; + Py_ssize_t n; + + if (!PyList_Check(heap)) { + PyErr_SetString(PyExc_TypeError, "heap argument must be a list"); + return NULL; + } + + /* # raises appropriate IndexError if heap is empty */ + n = PyList_GET_SIZE(heap); + if (n == 0) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return NULL; + } + + lastelt = PyList_GET_ITEM(heap, n-1) ; + Py_INCREF(lastelt); + PyList_SetSlice(heap, n-1, n, NULL); + n--; + + if (!n) + return lastelt; + returnitem = PyList_GET_ITEM(heap, 0); + PyList_SET_ITEM(heap, 0, lastelt); + if (_siftup((PyListObject *)heap, 0) == -1) { + Py_DECREF(returnitem); + return NULL; + } + return returnitem; +} + +PyDoc_STRVAR(heappop_doc, +"Pop the smallest item off the heap, maintaining the heap invariant."); + +static PyObject * +heapreplace(PyObject *self, PyObject *args) +{ + PyObject *heap, *item, *returnitem; + + if (!PyArg_UnpackTuple(args, "heapreplace", 2, 2, &heap, &item)) + return NULL; + + if (!PyList_Check(heap)) { + PyErr_SetString(PyExc_TypeError, "heap argument must be a list"); + return NULL; + } + + if (PyList_GET_SIZE(heap) < 1) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return NULL; + } + + returnitem = PyList_GET_ITEM(heap, 0); + Py_INCREF(item); + PyList_SET_ITEM(heap, 0, item); + if (_siftup((PyListObject *)heap, 0) == -1) { + Py_DECREF(returnitem); + return NULL; + } + return returnitem; +} + +PyDoc_STRVAR(heapreplace_doc, +"Pop and return the current smallest value, and add the new item.\n\ +\n\ +This is more efficient than heappop() followed by heappush(), and can be\n\ +more appropriate when using a fixed-size heap. Note that the value\n\ +returned may be larger than item! That constrains reasonable uses of\n\ +this routine unless written as part of a conditional replacement:\n\n\ + if item > heap[0]:\n\ + item = heapreplace(heap, item)\n"); + +static PyObject * +heapify(PyObject *self, PyObject *heap) +{ + Py_ssize_t i, n; + + if (!PyList_Check(heap)) { + PyErr_SetString(PyExc_TypeError, "heap argument must be a list"); + return NULL; + } + + n = PyList_GET_SIZE(heap); + /* Transform bottom-up. The largest index there's any point to + looking at is the largest with a child index in-range, so must + have 2*i + 1 < n, or i < (n-1)/2. If n is even = 2*j, this is + (2*j-1)/2 = j-1/2 so j-1 is the largest, which is n//2 - 1. If + n is odd = 2*j+1, this is (2*j+1-1)/2 = j so j-1 is the largest, + and that's again n//2-1. + */ + for (i=n/2-1 ; i>=0 ; i--) + if(_siftup((PyListObject *)heap, i) == -1) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(heapify_doc, +"Transform list into a heap, in-place, in O(len(heap)) time."); + +static PyObject * +nlargest(PyObject *self, PyObject *args) +{ + PyObject *heap=NULL, *elem, *iterable, *sol, *it, *oldelem; + Py_ssize_t i, n; + + if (!PyArg_ParseTuple(args, "nO:nlargest", &n, &iterable)) + return NULL; + + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + + heap = PyList_New(0); + if (heap == NULL) + goto fail; + + for (i=0 ; i<n ; i++ ){ + elem = PyIter_Next(it); + if (elem == NULL) { + if (PyErr_Occurred()) + goto fail; + else + goto sortit; + } + if (PyList_Append(heap, elem) == -1) { + Py_DECREF(elem); + goto fail; + } + Py_DECREF(elem); + } + if (PyList_GET_SIZE(heap) == 0) + goto sortit; + + for (i=n/2-1 ; i>=0 ; i--) + if(_siftup((PyListObject *)heap, i) == -1) + goto fail; + + sol = PyList_GET_ITEM(heap, 0); + while (1) { + elem = PyIter_Next(it); + if (elem == NULL) { + if (PyErr_Occurred()) + goto fail; + else + goto sortit; + } + if (PyObject_RichCompareBool(elem, sol, Py_LE)) { + Py_DECREF(elem); + continue; + } + oldelem = PyList_GET_ITEM(heap, 0); + PyList_SET_ITEM(heap, 0, elem); + Py_DECREF(oldelem); + if (_siftup((PyListObject *)heap, 0) == -1) + goto fail; + sol = PyList_GET_ITEM(heap, 0); + } +sortit: + if (PyList_Sort(heap) == -1) + goto fail; + if (PyList_Reverse(heap) == -1) + goto fail; + Py_DECREF(it); + return heap; + +fail: + Py_DECREF(it); + Py_XDECREF(heap); + return NULL; +} + +PyDoc_STRVAR(nlargest_doc, +"Find the n largest elements in a dataset.\n\ +\n\ +Equivalent to: sorted(iterable, reverse=True)[:n]\n"); + +static int +_siftdownmax(PyListObject *heap, Py_ssize_t startpos, Py_ssize_t pos) +{ + PyObject *newitem, *parent; + int cmp; + Py_ssize_t parentpos; + + assert(PyList_Check(heap)); + if (pos >= PyList_GET_SIZE(heap)) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return -1; + } + + newitem = PyList_GET_ITEM(heap, pos); + Py_INCREF(newitem); + /* Follow the path to the root, moving parents down until finding + a place newitem fits. */ + while (pos > startpos){ + parentpos = (pos - 1) >> 1; + parent = PyList_GET_ITEM(heap, parentpos); + cmp = PyObject_RichCompareBool(newitem, parent, Py_LE); + if (cmp == -1) { + Py_DECREF(newitem); + return -1; + } + if (cmp == 1) + break; + Py_INCREF(parent); + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, parent); + pos = parentpos; + } + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, newitem); + return 0; +} + +static int +_siftupmax(PyListObject *heap, Py_ssize_t pos) +{ + Py_ssize_t startpos, endpos, childpos, rightpos; + int cmp; + PyObject *newitem, *tmp; + + assert(PyList_Check(heap)); + endpos = PyList_GET_SIZE(heap); + startpos = pos; + if (pos >= endpos) { + PyErr_SetString(PyExc_IndexError, "index out of range"); + return -1; + } + newitem = PyList_GET_ITEM(heap, pos); + Py_INCREF(newitem); + + /* Bubble up the smaller child until hitting a leaf. */ + childpos = 2*pos + 1; /* leftmost child position */ + while (childpos < endpos) { + /* Set childpos to index of smaller child. */ + rightpos = childpos + 1; + if (rightpos < endpos) { + cmp = PyObject_RichCompareBool( + PyList_GET_ITEM(heap, childpos), + PyList_GET_ITEM(heap, rightpos), + Py_LE); + if (cmp == -1) { + Py_DECREF(newitem); + return -1; + } + if (cmp == 1) + childpos = rightpos; + } + /* Move the smaller child up. */ + tmp = PyList_GET_ITEM(heap, childpos); + Py_INCREF(tmp); + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, tmp); + pos = childpos; + childpos = 2*pos + 1; + } + + /* The leaf at pos is empty now. Put newitem there, and and bubble + it up to its final resting place (by sifting its parents down). */ + Py_DECREF(PyList_GET_ITEM(heap, pos)); + PyList_SET_ITEM(heap, pos, newitem); + return _siftdownmax(heap, startpos, pos); +} + +static PyObject * +nsmallest(PyObject *self, PyObject *args) +{ + PyObject *heap=NULL, *elem, *iterable, *los, *it, *oldelem; + Py_ssize_t i, n; + + if (!PyArg_ParseTuple(args, "nO:nsmallest", &n, &iterable)) + return NULL; + + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + + heap = PyList_New(0); + if (heap == NULL) + goto fail; + + for (i=0 ; i<n ; i++ ){ + elem = PyIter_Next(it); + if (elem == NULL) { + if (PyErr_Occurred()) + goto fail; + else + goto sortit; + } + if (PyList_Append(heap, elem) == -1) { + Py_DECREF(elem); + goto fail; + } + Py_DECREF(elem); + } + n = PyList_GET_SIZE(heap); + if (n == 0) + goto sortit; + + for (i=n/2-1 ; i>=0 ; i--) + if(_siftupmax((PyListObject *)heap, i) == -1) + goto fail; + + los = PyList_GET_ITEM(heap, 0); + while (1) { + elem = PyIter_Next(it); + if (elem == NULL) { + if (PyErr_Occurred()) + goto fail; + else + goto sortit; + } + if (PyObject_RichCompareBool(los, elem, Py_LE)) { + Py_DECREF(elem); + continue; + } + + oldelem = PyList_GET_ITEM(heap, 0); + PyList_SET_ITEM(heap, 0, elem); + Py_DECREF(oldelem); + if (_siftupmax((PyListObject *)heap, 0) == -1) + goto fail; + los = PyList_GET_ITEM(heap, 0); + } + +sortit: + if (PyList_Sort(heap) == -1) + goto fail; + Py_DECREF(it); + return heap; + +fail: + Py_DECREF(it); + Py_XDECREF(heap); + return NULL; +} + +PyDoc_STRVAR(nsmallest_doc, +"Find the n smallest elements in a dataset.\n\ +\n\ +Equivalent to: sorted(iterable)[:n]\n"); + +static PyMethodDef heapq_methods[] = { + {"heappush", (PyCFunction)heappush, + METH_VARARGS, heappush_doc}, + {"heappop", (PyCFunction)heappop, + METH_O, heappop_doc}, + {"heapreplace", (PyCFunction)heapreplace, + METH_VARARGS, heapreplace_doc}, + {"heapify", (PyCFunction)heapify, + METH_O, heapify_doc}, + {"nlargest", (PyCFunction)nlargest, + METH_VARARGS, nlargest_doc}, + {"nsmallest", (PyCFunction)nsmallest, + METH_VARARGS, nsmallest_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(module_doc, +"Heap queue algorithm (a.k.a. priority queue).\n\ +\n\ +Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\ +all k, counting elements from 0. For the sake of comparison,\n\ +non-existing elements are considered to be infinite. The interesting\n\ +property of a heap is that a[0] is always its smallest element.\n\ +\n\ +Usage:\n\ +\n\ +heap = [] # creates an empty heap\n\ +heappush(heap, item) # pushes a new item on the heap\n\ +item = heappop(heap) # pops the smallest item from the heap\n\ +item = heap[0] # smallest item on the heap without popping it\n\ +heapify(x) # transforms list into a heap, in-place, in linear time\n\ +item = heapreplace(heap, item) # pops and returns smallest item, and adds\n\ + # new item; the heap size is unchanged\n\ +\n\ +Our API differs from textbook heap algorithms as follows:\n\ +\n\ +- We use 0-based indexing. This makes the relationship between the\n\ + index for a node and the indexes for its children slightly less\n\ + obvious, but is more suitable since Python uses 0-based indexing.\n\ +\n\ +- Our heappop() method returns the smallest item, not the largest.\n\ +\n\ +These two make it possible to view the heap as a regular Python list\n\ +without surprises: heap[0] is the smallest item, and heap.sort()\n\ +maintains the heap invariant!\n"); + + +PyDoc_STRVAR(__about__,\ +"Heap queues\n\ +\n\ +[explanation by Fran�ois Pinard]\n\ +\n\ +Heaps are arrays for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for\n\ +all k, counting elements from 0. For the sake of comparison,\n\ +non-existing elements are considered to be infinite. The interesting\n\ +property of a heap is that a[0] is always its smallest element.\n" +"\n\ +The strange invariant above is meant to be an efficient memory\n\ +representation for a tournament. The numbers below are `k', not a[k]:\n\ +\n\ + 0\n\ +\n\ + 1 2\n\ +\n\ + 3 4 5 6\n\ +\n\ + 7 8 9 10 11 12 13 14\n\ +\n\ + 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30\n\ +\n\ +\n\ +In the tree above, each cell `k' is topping `2*k+1' and `2*k+2'. In\n\ +an usual binary tournament we see in sports, each cell is the winner\n\ +over the two cells it tops, and we can trace the winner down the tree\n\ +to see all opponents s/he had. However, in many computer applications\n\ +of such tournaments, we do not need to trace the history of a winner.\n\ +To be more memory efficient, when a winner is promoted, we try to\n\ +replace it by something else at a lower level, and the rule becomes\n\ +that a cell and the two cells it tops contain three different items,\n\ +but the top cell \"wins\" over the two topped cells.\n" +"\n\ +If this heap invariant is protected at all time, index 0 is clearly\n\ +the overall winner. The simplest algorithmic way to remove it and\n\ +find the \"next\" winner is to move some loser (let's say cell 30 in the\n\ +diagram above) into the 0 position, and then percolate this new 0 down\n\ +the tree, exchanging values, until the invariant is re-established.\n\ +This is clearly logarithmic on the total number of items in the tree.\n\ +By iterating over all items, you get an O(n ln n) sort.\n" +"\n\ +A nice feature of this sort is that you can efficiently insert new\n\ +items while the sort is going on, provided that the inserted items are\n\ +not \"better\" than the last 0'th element you extracted. This is\n\ +especially useful in simulation contexts, where the tree holds all\n\ +incoming events, and the \"win\" condition means the smallest scheduled\n\ +time. When an event schedule other events for execution, they are\n\ +scheduled into the future, so they can easily go into the heap. So, a\n\ +heap is a good structure for implementing schedulers (this is what I\n\ +used for my MIDI sequencer :-).\n" +"\n\ +Various structures for implementing schedulers have been extensively\n\ +studied, and heaps are good for this, as they are reasonably speedy,\n\ +the speed is almost constant, and the worst case is not much different\n\ +than the average case. However, there are other representations which\n\ +are more efficient overall, yet the worst cases might be terrible.\n" +"\n\ +Heaps are also very useful in big disk sorts. You most probably all\n\ +know that a big sort implies producing \"runs\" (which are pre-sorted\n\ +sequences, which size is usually related to the amount of CPU memory),\n\ +followed by a merging passes for these runs, which merging is often\n\ +very cleverly organised[1]. It is very important that the initial\n\ +sort produces the longest runs possible. Tournaments are a good way\n\ +to that. If, using all the memory available to hold a tournament, you\n\ +replace and percolate items that happen to fit the current run, you'll\n\ +produce runs which are twice the size of the memory for random input,\n\ +and much better for input fuzzily ordered.\n" +"\n\ +Moreover, if you output the 0'th item on disk and get an input which\n\ +may not fit in the current tournament (because the value \"wins\" over\n\ +the last output value), it cannot fit in the heap, so the size of the\n\ +heap decreases. The freed memory could be cleverly reused immediately\n\ +for progressively building a second heap, which grows at exactly the\n\ +same rate the first heap is melting. When the first heap completely\n\ +vanishes, you switch heaps and start a new run. Clever and quite\n\ +effective!\n\ +\n\ +In a word, heaps are useful memory structures to know. I use them in\n\ +a few applications, and I think it is good to keep a `heap' module\n\ +around. :-)\n" +"\n\ +--------------------\n\ +[1] The disk balancing algorithms which are current, nowadays, are\n\ +more annoying than clever, and this is a consequence of the seeking\n\ +capabilities of the disks. On devices which cannot seek, like big\n\ +tape drives, the story was quite different, and one had to be very\n\ +clever to ensure (far in advance) that each tape movement will be the\n\ +most effective possible (that is, will best participate at\n\ +\"progressing\" the merge). Some tapes were even able to read\n\ +backwards, and this was also used to avoid the rewinding time.\n\ +Believe me, real good tape sorts were quite spectacular to watch!\n\ +From all times, sorting has always been a Great Art! :-)\n"); + +PyMODINIT_FUNC +init_heapq(void) +{ + PyObject *m; + + m = Py_InitModule3("_heapq", heapq_methods, module_doc); + if (m == NULL) + return; + PyModule_AddObject(m, "__about__", PyString_FromString(__about__)); +} + diff --git a/sys/src/cmd/python/Modules/_hotshot.c b/sys/src/cmd/python/Modules/_hotshot.c new file mode 100644 index 000000000..065827f8e --- /dev/null +++ b/sys/src/cmd/python/Modules/_hotshot.c @@ -0,0 +1,1647 @@ +/* + * This is the High Performance Python Profiler portion of HotShot. + */ + +#include "Python.h" +#include "code.h" +#include "eval.h" +#include "frameobject.h" +#include "structmember.h" + +/* + * Which timer to use should be made more configurable, but that should not + * be difficult. This will do for now. + */ +#ifdef MS_WINDOWS +#include <windows.h> + +#ifdef HAVE_DIRECT_H +#include <direct.h> /* for getcwd() */ +#endif + +typedef __int64 hs_time; +#define GETTIMEOFDAY(P_HS_TIME) \ + { LARGE_INTEGER _temp; \ + QueryPerformanceCounter(&_temp); \ + *(P_HS_TIME) = _temp.QuadPart; } + + +#else +#ifndef HAVE_GETTIMEOFDAY +#error "This module requires gettimeofday() on non-Windows platforms!" +#endif +#if (defined(PYOS_OS2) && defined(PYCC_GCC)) || defined(__QNX__) +#include <sys/time.h> +#else +#include <sys/resource.h> +#include <sys/times.h> +#endif +typedef struct timeval hs_time; +#endif + +#if !defined(__cplusplus) && !defined(inline) +#ifdef __GNUC__ +#define inline __inline +#endif +#endif + +#ifndef inline +#define inline +#endif + +#define BUFFERSIZE 10240 + +#if defined(PYOS_OS2) && defined(PYCC_GCC) +#define PATH_MAX 260 +#endif + +#if defined(__sgi) && _COMPILER_VERSION>700 && !defined(PATH_MAX) +/* fix PATH_MAX not being defined with MIPSPro 7.x + if mode is ANSI C (default) */ +#define PATH_MAX 1024 +#endif + +#ifndef PATH_MAX +# ifdef MAX_PATH +# define PATH_MAX MAX_PATH +# elif defined (_POSIX_PATH_MAX) +# define PATH_MAX _POSIX_PATH_MAX +# else +# error "Need a defn. for PATH_MAX in _hotshot.c" +# endif +#endif + +typedef struct { + PyObject_HEAD + PyObject *filemap; + PyObject *logfilename; + Py_ssize_t index; + unsigned char buffer[BUFFERSIZE]; + FILE *logfp; + int lineevents; + int linetimings; + int frametimings; + /* size_t filled; */ + int active; + int next_fileno; + hs_time prev_timeofday; +} ProfilerObject; + +typedef struct { + PyObject_HEAD + PyObject *info; + FILE *logfp; + int linetimings; + int frametimings; +} LogReaderObject; + +static PyObject * ProfilerError = NULL; + + +#ifndef MS_WINDOWS +#ifdef GETTIMEOFDAY_NO_TZ +#define GETTIMEOFDAY(ptv) gettimeofday((ptv)) +#else +#define GETTIMEOFDAY(ptv) gettimeofday((ptv), (struct timezone *)NULL) +#endif +#endif + + +/* The log reader... */ + +PyDoc_STRVAR(logreader_close__doc__, +"close()\n" +"Close the log file, preventing additional records from being read."); + +static PyObject * +logreader_close(LogReaderObject *self, PyObject *args) +{ + if (self->logfp != NULL) { + fclose(self->logfp); + self->logfp = NULL; + } + Py_INCREF(Py_None); + + return Py_None; +} + +PyDoc_STRVAR(logreader_fileno__doc__, +"fileno() -> file descriptor\n" +"Returns the file descriptor for the log file, if open.\n" +"Raises ValueError if the log file is closed."); + +static PyObject * +logreader_fileno(LogReaderObject *self) +{ + if (self->logfp == NULL) { + PyErr_SetString(PyExc_ValueError, + "logreader's file object already closed"); + return NULL; + } + return PyInt_FromLong(fileno(self->logfp)); +} + + +/* Log File Format + * --------------- + * + * The log file consists of a sequence of variable-length records. + * Each record is identified with a record type identifier in two + * bits of the first byte. The two bits are the "least significant" + * bits of the byte. + * + * Low bits: Opcode: Meaning: + * 0x00 ENTER enter a frame + * 0x01 EXIT exit a frame + * 0x02 LINENO execution moved onto a different line + * 0x03 OTHER more bits are needed to deecode + * + * If the type is OTHER, the record is not packed so tightly, and the + * remaining bits are used to disambiguate the record type. These + * records are not used as frequently so compaction is not an issue. + * Each of the first three record types has a highly tailored + * structure that allows it to be packed tightly. + * + * The OTHER records have the following identifiers: + * + * First byte: Opcode: Meaning: + * 0x13 ADD_INFO define a key/value pair + * 0x23 DEFINE_FILE define an int->filename mapping + * 0x33 LINE_TIMES indicates if LINENO events have tdeltas + * 0x43 DEFINE_FUNC define a (fileno,lineno)->funcname mapping + * 0x53 FRAME_TIMES indicates if ENTER/EXIT events have tdeltas + * + * Packed Integers + * + * "Packed integers" are non-negative integer values encoded as a + * sequence of bytes. Each byte is encoded such that the most + * significant bit is set if the next byte is also part of the + * integer. Each byte provides bits to the least-significant end of + * the result; the accumulated value must be shifted up to place the + * new bits into the result. + * + * "Modified packed integers" are packed integers where only a portion + * of the first byte is used. In the rest of the specification, these + * are referred to as "MPI(n,name)", where "n" is the number of bits + * discarded from the least-signicant positions of the byte, and + * "name" is a name being given to those "discarded" bits, since they + * are a field themselves. + * + * ENTER records: + * + * MPI(2,type) fileno -- type is 0x00 + * PI lineno + * PI tdelta -- iff frame times are enabled + * + * EXIT records + * + * MPI(2,type) tdelta -- type is 0x01; tdelta will be 0 + * if frame times are disabled + * + * LINENO records + * + * MPI(2,type) lineno -- type is 0x02 + * PI tdelta -- iff LINENO includes it + * + * ADD_INFO records + * + * BYTE type -- always 0x13 + * PI len1 -- length of first string + * BYTE string1[len1] -- len1 bytes of string data + * PI len2 -- length of second string + * BYTE string2[len2] -- len2 bytes of string data + * + * DEFINE_FILE records + * + * BYTE type -- always 0x23 + * PI fileno + * PI len -- length of filename + * BYTE filename[len] -- len bytes of string data + * + * DEFINE_FUNC records + * + * BYTE type -- always 0x43 + * PI fileno + * PI lineno + * PI len -- length of funcname + * BYTE funcname[len] -- len bytes of string data + * + * LINE_TIMES records + * + * This record can be used only before the start of ENTER/EXIT/LINENO + * records. If have_tdelta is true, LINENO records will include the + * tdelta field, otherwise it will be omitted. If this record is not + * given, LINENO records will not contain the tdelta field. + * + * BYTE type -- always 0x33 + * BYTE have_tdelta -- 0 if LINENO does *not* have + * timing information + * FRAME_TIMES records + * + * This record can be used only before the start of ENTER/EXIT/LINENO + * records. If have_tdelta is true, ENTER and EXIT records will + * include the tdelta field, otherwise it will be omitted. If this + * record is not given, ENTER and EXIT records will contain the tdelta + * field. + * + * BYTE type -- always 0x53 + * BYTE have_tdelta -- 0 if ENTER/EXIT do *not* have + * timing information + */ + +#define WHAT_ENTER 0x00 +#define WHAT_EXIT 0x01 +#define WHAT_LINENO 0x02 +#define WHAT_OTHER 0x03 /* only used in decoding */ +#define WHAT_ADD_INFO 0x13 +#define WHAT_DEFINE_FILE 0x23 +#define WHAT_LINE_TIMES 0x33 +#define WHAT_DEFINE_FUNC 0x43 +#define WHAT_FRAME_TIMES 0x53 + +#define ERR_NONE 0 +#define ERR_EOF -1 +#define ERR_EXCEPTION -2 +#define ERR_BAD_RECTYPE -3 + +#define PISIZE (sizeof(int) + 1) +#define MPISIZE (PISIZE + 1) + +/* Maximum size of "normal" events -- nothing that contains string data */ +#define MAXEVENTSIZE (MPISIZE + PISIZE*2) + + +/* Unpack a packed integer; if "discard" is non-zero, unpack a modified + * packed integer with "discard" discarded bits. + */ +static int +unpack_packed_int(LogReaderObject *self, int *pvalue, int discard) +{ + int c; + int accum = 0; + int bits = 0; + int cont; + + do { + /* read byte */ + if ((c = fgetc(self->logfp)) == EOF) + return ERR_EOF; + accum |= ((c & 0x7F) >> discard) << bits; + bits += (7 - discard); + cont = c & 0x80; + discard = 0; + } while (cont); + + *pvalue = accum; + + return 0; +} + +/* Unpack a string, which is encoded as a packed integer giving the + * length of the string, followed by the string data. + */ +static int +unpack_string(LogReaderObject *self, PyObject **pvalue) +{ + int i; + int len; + int err; + int ch; + char *buf; + + if ((err = unpack_packed_int(self, &len, 0))) + return err; + + buf = (char *)malloc(len); + if (!buf) { + PyErr_NoMemory(); + return ERR_EXCEPTION; + } + + for (i=0; i < len; i++) { + ch = fgetc(self->logfp); + buf[i] = ch; + if (ch == EOF) { + free(buf); + return ERR_EOF; + } + } + *pvalue = PyString_FromStringAndSize(buf, len); + free(buf); + if (*pvalue == NULL) { + return ERR_EXCEPTION; + } + return 0; +} + + +static int +unpack_add_info(LogReaderObject *self) +{ + PyObject *key; + PyObject *value = NULL; + int err; + + err = unpack_string(self, &key); + if (!err) { + err = unpack_string(self, &value); + if (err) + Py_DECREF(key); + else { + PyObject *list = PyDict_GetItem(self->info, key); + if (list == NULL) { + list = PyList_New(0); + if (list == NULL) { + err = ERR_EXCEPTION; + goto finally; + } + if (PyDict_SetItem(self->info, key, list)) { + Py_DECREF(list); + err = ERR_EXCEPTION; + goto finally; + } + Py_DECREF(list); + } + if (PyList_Append(list, value)) + err = ERR_EXCEPTION; + } + } + finally: + Py_XDECREF(key); + Py_XDECREF(value); + return err; +} + + +static void +eof_error(LogReaderObject *self) +{ + fclose(self->logfp); + self->logfp = NULL; + PyErr_SetString(PyExc_EOFError, + "end of file with incomplete profile record"); +} + +static PyObject * +logreader_tp_iternext(LogReaderObject *self) +{ + int c; + int what; + int err = ERR_NONE; + int lineno = -1; + int fileno = -1; + int tdelta = -1; + PyObject *s1 = NULL, *s2 = NULL; + PyObject *result = NULL; +#if 0 + unsigned char b0, b1; +#endif + + if (self->logfp == NULL) { + PyErr_SetString(ProfilerError, + "cannot iterate over closed LogReader object"); + return NULL; + } + +restart: + /* decode the record type */ + if ((c = fgetc(self->logfp)) == EOF) { + fclose(self->logfp); + self->logfp = NULL; + return NULL; + } + what = c & WHAT_OTHER; + if (what == WHAT_OTHER) + what = c; /* need all the bits for type */ + else + ungetc(c, self->logfp); /* type byte includes packed int */ + + switch (what) { + case WHAT_ENTER: + err = unpack_packed_int(self, &fileno, 2); + if (!err) { + err = unpack_packed_int(self, &lineno, 0); + if (self->frametimings && !err) + err = unpack_packed_int(self, &tdelta, 0); + } + break; + case WHAT_EXIT: + err = unpack_packed_int(self, &tdelta, 2); + break; + case WHAT_LINENO: + err = unpack_packed_int(self, &lineno, 2); + if (self->linetimings && !err) + err = unpack_packed_int(self, &tdelta, 0); + break; + case WHAT_ADD_INFO: + err = unpack_add_info(self); + break; + case WHAT_DEFINE_FILE: + err = unpack_packed_int(self, &fileno, 0); + if (!err) { + err = unpack_string(self, &s1); + if (!err) { + Py_INCREF(Py_None); + s2 = Py_None; + } + } + break; + case WHAT_DEFINE_FUNC: + err = unpack_packed_int(self, &fileno, 0); + if (!err) { + err = unpack_packed_int(self, &lineno, 0); + if (!err) + err = unpack_string(self, &s1); + } + break; + case WHAT_LINE_TIMES: + if ((c = fgetc(self->logfp)) == EOF) + err = ERR_EOF; + else { + self->linetimings = c ? 1 : 0; + goto restart; + } + break; + case WHAT_FRAME_TIMES: + if ((c = fgetc(self->logfp)) == EOF) + err = ERR_EOF; + else { + self->frametimings = c ? 1 : 0; + goto restart; + } + break; + default: + err = ERR_BAD_RECTYPE; + } + if (err == ERR_BAD_RECTYPE) { + PyErr_SetString(PyExc_ValueError, + "unknown record type in log file"); + } + else if (err == ERR_EOF) { + eof_error(self); + } + else if (!err) { + result = PyTuple_New(4); + if (result == NULL) + return NULL; + PyTuple_SET_ITEM(result, 0, PyInt_FromLong(what)); + PyTuple_SET_ITEM(result, 2, PyInt_FromLong(fileno)); + if (s1 == NULL) + PyTuple_SET_ITEM(result, 1, PyInt_FromLong(tdelta)); + else + PyTuple_SET_ITEM(result, 1, s1); + if (s2 == NULL) + PyTuple_SET_ITEM(result, 3, PyInt_FromLong(lineno)); + else + PyTuple_SET_ITEM(result, 3, s2); + } + /* The only other case is err == ERR_EXCEPTION, in which case the + * exception is already set. + */ +#if 0 + b0 = self->buffer[self->index]; + b1 = self->buffer[self->index + 1]; + if (b0 & 1) { + /* This is a line-number event. */ + what = PyTrace_LINE; + lineno = ((b0 & ~1) << 7) + b1; + self->index += 2; + } + else { + what = (b0 & 0x0E) >> 1; + tdelta = ((b0 & 0xF0) << 4) + b1; + if (what == PyTrace_CALL) { + /* we know there's a 2-byte file ID & 2-byte line number */ + fileno = ((self->buffer[self->index + 2] << 8) + + self->buffer[self->index + 3]); + lineno = ((self->buffer[self->index + 4] << 8) + + self->buffer[self->index + 5]); + self->index += 6; + } + else + self->index += 2; + } +#endif + return result; +} + +static void +logreader_dealloc(LogReaderObject *self) +{ + if (self->logfp != NULL) { + fclose(self->logfp); + self->logfp = NULL; + } + Py_XDECREF(self->info); + PyObject_Del(self); +} + +static PyObject * +logreader_sq_item(LogReaderObject *self, Py_ssize_t index) +{ + PyObject *result = logreader_tp_iternext(self); + if (result == NULL && !PyErr_Occurred()) { + PyErr_SetString(PyExc_IndexError, "no more events in log"); + return NULL; + } + return result; +} + +static void +do_stop(ProfilerObject *self); + +static int +flush_data(ProfilerObject *self) +{ + /* Need to dump data to the log file... */ + size_t written = fwrite(self->buffer, 1, self->index, self->logfp); + if (written == (size_t)self->index) + self->index = 0; + else { + memmove(self->buffer, &self->buffer[written], + self->index - written); + self->index -= written; + if (written == 0) { + char *s = PyString_AsString(self->logfilename); + PyErr_SetFromErrnoWithFilename(PyExc_IOError, s); + do_stop(self); + return -1; + } + } + if (written > 0) { + if (fflush(self->logfp)) { + char *s = PyString_AsString(self->logfilename); + PyErr_SetFromErrnoWithFilename(PyExc_IOError, s); + do_stop(self); + return -1; + } + } + return 0; +} + +static inline int +pack_packed_int(ProfilerObject *self, int value) +{ + unsigned char partial; + + do { + partial = value & 0x7F; + value >>= 7; + if (value) + partial |= 0x80; + self->buffer[self->index] = partial; + self->index++; + } while (value); + return 0; +} + +/* Encode a modified packed integer, with a subfield of modsize bits + * containing the value "subfield". The value of subfield is not + * checked to ensure it actually fits in modsize bits. + */ +static inline int +pack_modified_packed_int(ProfilerObject *self, int value, + int modsize, int subfield) +{ + const int maxvalues[] = {-1, 1, 3, 7, 15, 31, 63, 127}; + + int bits = 7 - modsize; + int partial = value & maxvalues[bits]; + unsigned char b = subfield | (partial << modsize); + + if (partial != value) { + b |= 0x80; + self->buffer[self->index] = b; + self->index++; + return pack_packed_int(self, value >> bits); + } + self->buffer[self->index] = b; + self->index++; + return 0; +} + +static int +pack_string(ProfilerObject *self, const char *s, Py_ssize_t len) +{ + if (len + PISIZE + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + assert(len < INT_MAX); + if (pack_packed_int(self, (int)len) < 0) + return -1; + memcpy(self->buffer + self->index, s, len); + self->index += len; + return 0; +} + +static int +pack_add_info(ProfilerObject *self, const char *s1, const char *s2) +{ + Py_ssize_t len1 = strlen(s1); + Py_ssize_t len2 = strlen(s2); + + if (len1 + len2 + PISIZE*2 + 1 + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + self->buffer[self->index] = WHAT_ADD_INFO; + self->index++; + if (pack_string(self, s1, len1) < 0) + return -1; + return pack_string(self, s2, len2); +} + +static int +pack_define_file(ProfilerObject *self, int fileno, const char *filename) +{ + Py_ssize_t len = strlen(filename); + + if (len + PISIZE*2 + 1 + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + self->buffer[self->index] = WHAT_DEFINE_FILE; + self->index++; + if (pack_packed_int(self, fileno) < 0) + return -1; + return pack_string(self, filename, len); +} + +static int +pack_define_func(ProfilerObject *self, int fileno, int lineno, + const char *funcname) +{ + Py_ssize_t len = strlen(funcname); + + if (len + PISIZE*3 + 1 + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + self->buffer[self->index] = WHAT_DEFINE_FUNC; + self->index++; + if (pack_packed_int(self, fileno) < 0) + return -1; + if (pack_packed_int(self, lineno) < 0) + return -1; + return pack_string(self, funcname, len); +} + +static int +pack_line_times(ProfilerObject *self) +{ + if (2 + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + self->buffer[self->index] = WHAT_LINE_TIMES; + self->buffer[self->index + 1] = self->linetimings ? 1 : 0; + self->index += 2; + return 0; +} + +static int +pack_frame_times(ProfilerObject *self) +{ + if (2 + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + self->buffer[self->index] = WHAT_FRAME_TIMES; + self->buffer[self->index + 1] = self->frametimings ? 1 : 0; + self->index += 2; + return 0; +} + +static inline int +pack_enter(ProfilerObject *self, int fileno, int tdelta, int lineno) +{ + if (MPISIZE + PISIZE*2 + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + pack_modified_packed_int(self, fileno, 2, WHAT_ENTER); + pack_packed_int(self, lineno); + if (self->frametimings) + return pack_packed_int(self, tdelta); + else + return 0; +} + +static inline int +pack_exit(ProfilerObject *self, int tdelta) +{ + if (MPISIZE + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + if (self->frametimings) + return pack_modified_packed_int(self, tdelta, 2, WHAT_EXIT); + self->buffer[self->index] = WHAT_EXIT; + self->index++; + return 0; +} + +static inline int +pack_lineno(ProfilerObject *self, int lineno) +{ + if (MPISIZE + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return -1; + } + return pack_modified_packed_int(self, lineno, 2, WHAT_LINENO); +} + +static inline int +pack_lineno_tdelta(ProfilerObject *self, int lineno, int tdelta) +{ + if (MPISIZE + PISIZE + self->index >= BUFFERSIZE) { + if (flush_data(self) < 0) + return 0; + } + if (pack_modified_packed_int(self, lineno, 2, WHAT_LINENO) < 0) + return -1; + return pack_packed_int(self, tdelta); +} + +static inline int +get_fileno(ProfilerObject *self, PyCodeObject *fcode) +{ + /* This is only used for ENTER events. */ + + PyObject *obj; + PyObject *dict; + int fileno; + + obj = PyDict_GetItem(self->filemap, fcode->co_filename); + if (obj == NULL) { + /* first sighting of this file */ + dict = PyDict_New(); + if (dict == NULL) { + return -1; + } + fileno = self->next_fileno; + obj = Py_BuildValue("iN", fileno, dict); + if (obj == NULL) { + return -1; + } + if (PyDict_SetItem(self->filemap, fcode->co_filename, obj)) { + Py_DECREF(obj); + return -1; + } + self->next_fileno++; + Py_DECREF(obj); + if (pack_define_file(self, fileno, + PyString_AS_STRING(fcode->co_filename)) < 0) + return -1; + } + else { + /* already know this ID */ + fileno = PyInt_AS_LONG(PyTuple_GET_ITEM(obj, 0)); + dict = PyTuple_GET_ITEM(obj, 1); + } + /* make sure we save a function name for this (fileno, lineno) */ + obj = PyInt_FromLong(fcode->co_firstlineno); + if (obj == NULL) { + /* We just won't have it saved; too bad. */ + PyErr_Clear(); + } + else { + PyObject *name = PyDict_GetItem(dict, obj); + if (name == NULL) { + if (pack_define_func(self, fileno, fcode->co_firstlineno, + PyString_AS_STRING(fcode->co_name)) < 0) { + Py_DECREF(obj); + return -1; + } + if (PyDict_SetItem(dict, obj, fcode->co_name)) { + Py_DECREF(obj); + return -1; + } + } + Py_DECREF(obj); + } + return fileno; +} + +static inline int +get_tdelta(ProfilerObject *self) +{ + int tdelta; +#ifdef MS_WINDOWS + hs_time tv; + hs_time diff; + + GETTIMEOFDAY(&tv); + diff = tv - self->prev_timeofday; + tdelta = (int)diff; +#else + struct timeval tv; + + GETTIMEOFDAY(&tv); + + tdelta = tv.tv_usec - self->prev_timeofday.tv_usec; + if (tv.tv_sec != self->prev_timeofday.tv_sec) + tdelta += (tv.tv_sec - self->prev_timeofday.tv_sec) * 1000000; +#endif + /* time can go backwards on some multiprocessor systems or by NTP */ + if (tdelta < 0) + return 0; + + self->prev_timeofday = tv; + return tdelta; +} + + +/* The workhorse: the profiler callback function. */ + +static int +tracer_callback(ProfilerObject *self, PyFrameObject *frame, int what, + PyObject *arg) +{ + int fileno; + + switch (what) { + case PyTrace_CALL: + fileno = get_fileno(self, frame->f_code); + if (fileno < 0) + return -1; + return pack_enter(self, fileno, + self->frametimings ? get_tdelta(self) : -1, + frame->f_code->co_firstlineno); + + case PyTrace_RETURN: + return pack_exit(self, get_tdelta(self)); + + case PyTrace_LINE: /* we only get these events if we asked for them */ + if (self->linetimings) + return pack_lineno_tdelta(self, frame->f_lineno, + get_tdelta(self)); + else + return pack_lineno(self, frame->f_lineno); + + default: + /* ignore PyTrace_EXCEPTION */ + break; + } + return 0; +} + + +/* A couple of useful helper functions. */ + +#ifdef MS_WINDOWS +static LARGE_INTEGER frequency = {0, 0}; +#endif + +static unsigned long timeofday_diff = 0; +static unsigned long rusage_diff = 0; + +static void +calibrate(void) +{ + hs_time tv1, tv2; + +#ifdef MS_WINDOWS + hs_time diff; + QueryPerformanceFrequency(&frequency); +#endif + + GETTIMEOFDAY(&tv1); + while (1) { + GETTIMEOFDAY(&tv2); +#ifdef MS_WINDOWS + diff = tv2 - tv1; + if (diff != 0) { + timeofday_diff = (unsigned long)diff; + break; + } +#else + if (tv1.tv_sec != tv2.tv_sec || tv1.tv_usec != tv2.tv_usec) { + if (tv1.tv_sec == tv2.tv_sec) + timeofday_diff = tv2.tv_usec - tv1.tv_usec; + else + timeofday_diff = (1000000 - tv1.tv_usec) + tv2.tv_usec; + break; + } +#endif + } +#if defined(MS_WINDOWS) || defined(PYOS_OS2) || \ + defined(__VMS) || defined (__QNX__) + rusage_diff = -1; +#else + { + struct rusage ru1, ru2; + + getrusage(RUSAGE_SELF, &ru1); + while (1) { + getrusage(RUSAGE_SELF, &ru2); + if (ru1.ru_utime.tv_sec != ru2.ru_utime.tv_sec) { + rusage_diff = ((1000000 - ru1.ru_utime.tv_usec) + + ru2.ru_utime.tv_usec); + break; + } + else if (ru1.ru_utime.tv_usec != ru2.ru_utime.tv_usec) { + rusage_diff = ru2.ru_utime.tv_usec - ru1.ru_utime.tv_usec; + break; + } + else if (ru1.ru_stime.tv_sec != ru2.ru_stime.tv_sec) { + rusage_diff = ((1000000 - ru1.ru_stime.tv_usec) + + ru2.ru_stime.tv_usec); + break; + } + else if (ru1.ru_stime.tv_usec != ru2.ru_stime.tv_usec) { + rusage_diff = ru2.ru_stime.tv_usec - ru1.ru_stime.tv_usec; + break; + } + } + } +#endif +} + +static void +do_start(ProfilerObject *self) +{ + self->active = 1; + GETTIMEOFDAY(&self->prev_timeofday); + if (self->lineevents) + PyEval_SetTrace((Py_tracefunc) tracer_callback, (PyObject *)self); + else + PyEval_SetProfile((Py_tracefunc) tracer_callback, (PyObject *)self); +} + +static void +do_stop(ProfilerObject *self) +{ + if (self->active) { + self->active = 0; + if (self->lineevents) + PyEval_SetTrace(NULL, NULL); + else + PyEval_SetProfile(NULL, NULL); + } + if (self->index > 0) { + /* Best effort to dump out any remaining data. */ + flush_data(self); + } +} + +static int +is_available(ProfilerObject *self) +{ + if (self->active) { + PyErr_SetString(ProfilerError, "profiler already active"); + return 0; + } + if (self->logfp == NULL) { + PyErr_SetString(ProfilerError, "profiler already closed"); + return 0; + } + return 1; +} + + +/* Profiler object interface methods. */ + +PyDoc_STRVAR(addinfo__doc__, +"addinfo(key, value)\n" +"Insert an ADD_INFO record into the log."); + +static PyObject * +profiler_addinfo(ProfilerObject *self, PyObject *args) +{ + PyObject *result = NULL; + char *key, *value; + + if (PyArg_ParseTuple(args, "ss:addinfo", &key, &value)) { + if (self->logfp == NULL) + PyErr_SetString(ProfilerError, "profiler already closed"); + else { + if (pack_add_info(self, key, value) == 0) { + result = Py_None; + Py_INCREF(result); + } + } + } + return result; +} + +PyDoc_STRVAR(close__doc__, +"close()\n" +"Shut down this profiler and close the log files, even if its active."); + +static PyObject * +profiler_close(ProfilerObject *self) +{ + do_stop(self); + if (self->logfp != NULL) { + fclose(self->logfp); + self->logfp = NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +#define fileno__doc__ logreader_fileno__doc__ + +static PyObject * +profiler_fileno(ProfilerObject *self) +{ + if (self->logfp == NULL) { + PyErr_SetString(PyExc_ValueError, + "profiler's file object already closed"); + return NULL; + } + return PyInt_FromLong(fileno(self->logfp)); +} + +PyDoc_STRVAR(runcall__doc__, +"runcall(callable[, args[, kw]]) -> callable()\n" +"Profile a specific function call, returning the result of that call."); + +static PyObject * +profiler_runcall(ProfilerObject *self, PyObject *args) +{ + PyObject *result = NULL; + PyObject *callargs = NULL; + PyObject *callkw = NULL; + PyObject *callable; + + if (PyArg_UnpackTuple(args, "runcall", 1, 3, + &callable, &callargs, &callkw)) { + if (is_available(self)) { + do_start(self); + result = PyEval_CallObjectWithKeywords(callable, callargs, callkw); + do_stop(self); + } + } + return result; +} + +PyDoc_STRVAR(runcode__doc__, +"runcode(code, globals[, locals])\n" +"Execute a code object while collecting profile data. If locals is\n" +"omitted, globals is used for the locals as well."); + +static PyObject * +profiler_runcode(ProfilerObject *self, PyObject *args) +{ + PyObject *result = NULL; + PyCodeObject *code; + PyObject *globals; + PyObject *locals = NULL; + + if (PyArg_ParseTuple(args, "O!O!|O:runcode", + &PyCode_Type, &code, + &PyDict_Type, &globals, + &locals)) { + if (is_available(self)) { + if (locals == NULL || locals == Py_None) + locals = globals; + else if (!PyDict_Check(locals)) { + PyErr_SetString(PyExc_TypeError, + "locals must be a dictionary or None"); + return NULL; + } + do_start(self); + result = PyEval_EvalCode(code, globals, locals); + do_stop(self); +#if 0 + if (!PyErr_Occurred()) { + result = Py_None; + Py_INCREF(result); + } +#endif + } + } + return result; +} + +PyDoc_STRVAR(start__doc__, +"start()\n" +"Install this profiler for the current thread."); + +static PyObject * +profiler_start(ProfilerObject *self, PyObject *args) +{ + PyObject *result = NULL; + + if (is_available(self)) { + do_start(self); + result = Py_None; + Py_INCREF(result); + } + return result; +} + +PyDoc_STRVAR(stop__doc__, +"stop()\n" +"Remove this profiler from the current thread."); + +static PyObject * +profiler_stop(ProfilerObject *self, PyObject *args) +{ + PyObject *result = NULL; + + if (!self->active) + PyErr_SetString(ProfilerError, "profiler not active"); + else { + do_stop(self); + result = Py_None; + Py_INCREF(result); + } + return result; +} + + +/* Python API support. */ + +static void +profiler_dealloc(ProfilerObject *self) +{ + do_stop(self); + if (self->logfp != NULL) + fclose(self->logfp); + Py_XDECREF(self->filemap); + Py_XDECREF(self->logfilename); + PyObject_Del((PyObject *)self); +} + +static PyMethodDef profiler_methods[] = { + {"addinfo", (PyCFunction)profiler_addinfo, METH_VARARGS, addinfo__doc__}, + {"close", (PyCFunction)profiler_close, METH_NOARGS, close__doc__}, + {"fileno", (PyCFunction)profiler_fileno, METH_NOARGS, fileno__doc__}, + {"runcall", (PyCFunction)profiler_runcall, METH_VARARGS, runcall__doc__}, + {"runcode", (PyCFunction)profiler_runcode, METH_VARARGS, runcode__doc__}, + {"start", (PyCFunction)profiler_start, METH_NOARGS, start__doc__}, + {"stop", (PyCFunction)profiler_stop, METH_NOARGS, stop__doc__}, + {NULL, NULL} +}; + +static PyMemberDef profiler_members[] = { + {"frametimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY}, + {"lineevents", T_LONG, offsetof(ProfilerObject, lineevents), READONLY}, + {"linetimings", T_LONG, offsetof(ProfilerObject, linetimings), READONLY}, + {NULL} +}; + +static PyObject * +profiler_get_closed(ProfilerObject *self, void *closure) +{ + PyObject *result = (self->logfp == NULL) ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +static PyGetSetDef profiler_getsets[] = { + {"closed", (getter)profiler_get_closed, NULL, + PyDoc_STR("True if the profiler's output file has already been closed.")}, + {NULL} +}; + + +PyDoc_STRVAR(profiler_object__doc__, +"High-performance profiler object.\n" +"\n" +"Methods:\n" +"\n" +"close(): Stop the profiler and close the log files.\n" +"fileno(): Returns the file descriptor of the log file.\n" +"runcall(): Run a single function call with profiling enabled.\n" +"runcode(): Execute a code object with profiling enabled.\n" +"start(): Install the profiler and return.\n" +"stop(): Remove the profiler.\n" +"\n" +"Attributes (read-only):\n" +"\n" +"closed: True if the profiler has already been closed.\n" +"frametimings: True if ENTER/EXIT events collect timing information.\n" +"lineevents: True if line events are reported to the profiler.\n" +"linetimings: True if line events collect timing information."); + +static PyTypeObject ProfilerType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_hotshot.ProfilerType", /* tp_name */ + (int) sizeof(ProfilerObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)profiler_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + profiler_object__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + profiler_methods, /* tp_methods */ + profiler_members, /* tp_members */ + profiler_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + + +static PyMethodDef logreader_methods[] = { + {"close", (PyCFunction)logreader_close, METH_NOARGS, + logreader_close__doc__}, + {"fileno", (PyCFunction)logreader_fileno, METH_NOARGS, + logreader_fileno__doc__}, + {NULL, NULL} +}; + +static PyMemberDef logreader_members[] = { + {"info", T_OBJECT, offsetof(LogReaderObject, info), RO, + PyDoc_STR("Dictionary mapping informational keys to lists of values.")}, + {NULL} +}; + + +PyDoc_STRVAR(logreader__doc__, +"logreader(filename) --> log-iterator\n\ +Create a log-reader for the timing information file."); + +static PySequenceMethods logreader_as_sequence = { + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)logreader_sq_item, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyObject * +logreader_get_closed(LogReaderObject *self, void *closure) +{ + PyObject *result = (self->logfp == NULL) ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +static PyGetSetDef logreader_getsets[] = { + {"closed", (getter)logreader_get_closed, NULL, + PyDoc_STR("True if the logreader's input file has already been closed.")}, + {NULL} +}; + +static PyTypeObject LogReaderType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_hotshot.LogReaderType", /* tp_name */ + (int) sizeof(LogReaderObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)logreader_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &logreader_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + logreader__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)logreader_tp_iternext,/* tp_iternext */ + logreader_methods, /* tp_methods */ + logreader_members, /* tp_members */ + logreader_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +static PyObject * +hotshot_logreader(PyObject *unused, PyObject *args) +{ + LogReaderObject *self = NULL; + char *filename; + int c; + int err = 0; + + if (PyArg_ParseTuple(args, "s:logreader", &filename)) { + self = PyObject_New(LogReaderObject, &LogReaderType); + if (self != NULL) { + self->frametimings = 1; + self->linetimings = 0; + self->info = NULL; + self->logfp = fopen(filename, "rb"); + if (self->logfp == NULL) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); + Py_DECREF(self); + self = NULL; + goto finally; + } + self->info = PyDict_New(); + if (self->info == NULL) { + Py_DECREF(self); + goto finally; + } + /* read initial info */ + for (;;) { + if ((c = fgetc(self->logfp)) == EOF) { + eof_error(self); + break; + } + if (c != WHAT_ADD_INFO) { + ungetc(c, self->logfp); + break; + } + err = unpack_add_info(self); + if (err) { + if (err == ERR_EOF) + eof_error(self); + else + PyErr_SetString(PyExc_RuntimeError, + "unexpected error"); + break; + } + } + } + } + finally: + return (PyObject *) self; +} + + +/* Return a Python string that represents the version number without the + * extra cruft added by revision control, even if the right options were + * given to the "cvs export" command to make it not include the extra + * cruft. + */ +static char * +get_version_string(void) +{ + static char *rcsid = "$Revision: 51218 $"; + char *rev = rcsid; + char *buffer; + int i = 0; + + while (*rev && !isdigit(Py_CHARMASK(*rev))) + ++rev; + while (rev[i] != ' ' && rev[i] != '\0') + ++i; + buffer = (char *)malloc(i + 1); + if (buffer != NULL) { + memmove(buffer, rev, i); + buffer[i] = '\0'; + } + return buffer; +} + +/* Write out a RFC 822-style header with various useful bits of + * information to make the output easier to manage. + */ +static int +write_header(ProfilerObject *self) +{ + char *buffer; + char cwdbuffer[PATH_MAX]; + PyObject *temp; + Py_ssize_t i, len; + + buffer = get_version_string(); + if (buffer == NULL) { + PyErr_NoMemory(); + return -1; + } + pack_add_info(self, "hotshot-version", buffer); + pack_add_info(self, "requested-frame-timings", + (self->frametimings ? "yes" : "no")); + pack_add_info(self, "requested-line-events", + (self->lineevents ? "yes" : "no")); + pack_add_info(self, "requested-line-timings", + (self->linetimings ? "yes" : "no")); + pack_add_info(self, "platform", Py_GetPlatform()); + pack_add_info(self, "executable", Py_GetProgramFullPath()); + free(buffer); + buffer = (char *) Py_GetVersion(); + if (buffer == NULL) + PyErr_Clear(); + else + pack_add_info(self, "executable-version", buffer); + +#ifdef MS_WINDOWS + PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%I64d", frequency.QuadPart); + pack_add_info(self, "reported-performance-frequency", cwdbuffer); +#else + PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", rusage_diff); + pack_add_info(self, "observed-interval-getrusage", cwdbuffer); + PyOS_snprintf(cwdbuffer, sizeof(cwdbuffer), "%lu", timeofday_diff); + pack_add_info(self, "observed-interval-gettimeofday", cwdbuffer); +#endif + + pack_add_info(self, "current-directory", + getcwd(cwdbuffer, sizeof cwdbuffer)); + + temp = PySys_GetObject("path"); + if (temp == NULL || !PyList_Check(temp)) { + PyErr_SetString(PyExc_RuntimeError, "sys.path must be a list"); + return -1; + } + len = PyList_GET_SIZE(temp); + for (i = 0; i < len; ++i) { + PyObject *item = PyList_GET_ITEM(temp, i); + buffer = PyString_AsString(item); + if (buffer == NULL) { + pack_add_info(self, "sys-path-entry", "<non-string-path-entry>"); + PyErr_Clear(); + } + else { + pack_add_info(self, "sys-path-entry", buffer); + } + } + pack_frame_times(self); + pack_line_times(self); + + return 0; +} + +PyDoc_STRVAR(profiler__doc__, +"profiler(logfilename[, lineevents[, linetimes]]) -> profiler\n\ +Create a new profiler object."); + +static PyObject * +hotshot_profiler(PyObject *unused, PyObject *args) +{ + char *logfilename; + ProfilerObject *self = NULL; + int lineevents = 0; + int linetimings = 1; + + if (PyArg_ParseTuple(args, "s|ii:profiler", &logfilename, + &lineevents, &linetimings)) { + self = PyObject_New(ProfilerObject, &ProfilerType); + if (self == NULL) + return NULL; + self->frametimings = 1; + self->lineevents = lineevents ? 1 : 0; + self->linetimings = (lineevents && linetimings) ? 1 : 0; + self->index = 0; + self->active = 0; + self->next_fileno = 0; + self->logfp = NULL; + self->logfilename = PyTuple_GET_ITEM(args, 0); + Py_INCREF(self->logfilename); + self->filemap = PyDict_New(); + if (self->filemap == NULL) { + Py_DECREF(self); + return NULL; + } + self->logfp = fopen(logfilename, "wb"); + if (self->logfp == NULL) { + Py_DECREF(self); + PyErr_SetFromErrnoWithFilename(PyExc_IOError, logfilename); + return NULL; + } + if (timeofday_diff == 0) { + /* Run this several times since sometimes the first + * doesn't give the lowest values, and we're really trying + * to determine the lowest. + */ + calibrate(); + calibrate(); + calibrate(); + } + if (write_header(self)) { + /* some error occurred, exception has been set */ + Py_DECREF(self); + self = NULL; + } + } + return (PyObject *) self; +} + +PyDoc_STRVAR(coverage__doc__, +"coverage(logfilename) -> profiler\n\ +Returns a profiler that doesn't collect any timing information, which is\n\ +useful in building a coverage analysis tool."); + +static PyObject * +hotshot_coverage(PyObject *unused, PyObject *args) +{ + char *logfilename; + PyObject *result = NULL; + + if (PyArg_ParseTuple(args, "s:coverage", &logfilename)) { + result = hotshot_profiler(unused, args); + if (result != NULL) { + ProfilerObject *self = (ProfilerObject *) result; + self->frametimings = 0; + self->linetimings = 0; + self->lineevents = 1; + } + } + return result; +} + +PyDoc_VAR(resolution__doc__) = +#ifdef MS_WINDOWS +PyDoc_STR( +"resolution() -> (performance-counter-ticks, update-frequency)\n" +"Return the resolution of the timer provided by the QueryPerformanceCounter()\n" +"function. The first value is the smallest observed change, and the second\n" +"is the result of QueryPerformanceFrequency()." +) +#else +PyDoc_STR( +"resolution() -> (gettimeofday-usecs, getrusage-usecs)\n" +"Return the resolution of the timers provided by the gettimeofday() and\n" +"getrusage() system calls, or -1 if the call is not supported." +) +#endif +; + +static PyObject * +hotshot_resolution(PyObject *self, PyObject *unused) +{ + if (timeofday_diff == 0) { + calibrate(); + calibrate(); + calibrate(); + } +#ifdef MS_WINDOWS + return Py_BuildValue("ii", timeofday_diff, frequency.LowPart); +#else + return Py_BuildValue("ii", timeofday_diff, rusage_diff); +#endif +} + + +static PyMethodDef functions[] = { + {"coverage", hotshot_coverage, METH_VARARGS, coverage__doc__}, + {"profiler", hotshot_profiler, METH_VARARGS, profiler__doc__}, + {"logreader", hotshot_logreader, METH_VARARGS, logreader__doc__}, + {"resolution", hotshot_resolution, METH_NOARGS, resolution__doc__}, + {NULL, NULL} +}; + + +void +init_hotshot(void) +{ + PyObject *module; + + LogReaderType.ob_type = &PyType_Type; + ProfilerType.ob_type = &PyType_Type; + module = Py_InitModule("_hotshot", functions); + if (module != NULL) { + char *s = get_version_string(); + + PyModule_AddStringConstant(module, "__version__", s); + free(s); + Py_INCREF(&LogReaderType); + PyModule_AddObject(module, "LogReaderType", + (PyObject *)&LogReaderType); + Py_INCREF(&ProfilerType); + PyModule_AddObject(module, "ProfilerType", + (PyObject *)&ProfilerType); + + if (ProfilerError == NULL) + ProfilerError = PyErr_NewException("hotshot.ProfilerError", + NULL, NULL); + if (ProfilerError != NULL) { + Py_INCREF(ProfilerError); + PyModule_AddObject(module, "ProfilerError", ProfilerError); + } + PyModule_AddIntConstant(module, "WHAT_ENTER", WHAT_ENTER); + PyModule_AddIntConstant(module, "WHAT_EXIT", WHAT_EXIT); + PyModule_AddIntConstant(module, "WHAT_LINENO", WHAT_LINENO); + PyModule_AddIntConstant(module, "WHAT_OTHER", WHAT_OTHER); + PyModule_AddIntConstant(module, "WHAT_ADD_INFO", WHAT_ADD_INFO); + PyModule_AddIntConstant(module, "WHAT_DEFINE_FILE", WHAT_DEFINE_FILE); + PyModule_AddIntConstant(module, "WHAT_DEFINE_FUNC", WHAT_DEFINE_FUNC); + PyModule_AddIntConstant(module, "WHAT_LINE_TIMES", WHAT_LINE_TIMES); + } +} diff --git a/sys/src/cmd/python/Modules/_localemodule.c b/sys/src/cmd/python/Modules/_localemodule.c new file mode 100644 index 000000000..7023bcf85 --- /dev/null +++ b/sys/src/cmd/python/Modules/_localemodule.c @@ -0,0 +1,788 @@ +/*********************************************************** +Copyright (C) 1997, 2002, 2003 Martin von Loewis + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies. + +This software comes with no warranty. Use at your own risk. + +******************************************************************/ + +#include "Python.h" + +#include <stdio.h> +#include <locale.h> +#include <string.h> +#include <ctype.h> + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif + +#ifdef HAVE_LIBINTL_H +#include <libintl.h> +#endif + +#ifdef HAVE_WCHAR_H +#include <wchar.h> +#endif + +#if defined(__APPLE__) +#include <CoreFoundation/CoreFoundation.h> +#endif + +#if defined(MS_WINDOWS) +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#ifdef RISCOS +char *strdup(const char *); +#endif + +PyDoc_STRVAR(locale__doc__, "Support for POSIX locales."); + +static PyObject *Error; + +/* support functions for formatting floating point numbers */ + +PyDoc_STRVAR(setlocale__doc__, +"(integer,string=None) -> string. Activates/queries locale processing."); + +/* the grouping is terminated by either 0 or CHAR_MAX */ +static PyObject* +copy_grouping(char* s) +{ + int i; + PyObject *result, *val = NULL; + + if (s[0] == '\0') + /* empty string: no grouping at all */ + return PyList_New(0); + + for (i = 0; s[i] != '\0' && s[i] != CHAR_MAX; i++) + ; /* nothing */ + + result = PyList_New(i+1); + if (!result) + return NULL; + + i = -1; + do { + i++; + val = PyInt_FromLong(s[i]); + if (!val) + break; + if (PyList_SetItem(result, i, val)) { + Py_DECREF(val); + val = NULL; + break; + } + } while (s[i] != '\0' && s[i] != CHAR_MAX); + + if (!val) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static void +fixup_ulcase(void) +{ + PyObject *mods, *strop, *string, *ulo; + unsigned char ul[256]; + int n, c; + + /* find the string and strop modules */ + mods = PyImport_GetModuleDict(); + if (!mods) + return; + string = PyDict_GetItemString(mods, "string"); + if (string) + string = PyModule_GetDict(string); + strop=PyDict_GetItemString(mods, "strop"); + if (strop) + strop = PyModule_GetDict(strop); + if (!string && !strop) + return; + + /* create uppercase map string */ + n = 0; + for (c = 0; c < 256; c++) { + if (isupper(c)) + ul[n++] = c; + } + ulo = PyString_FromStringAndSize((const char *)ul, n); + if (!ulo) + return; + if (string) + PyDict_SetItemString(string, "uppercase", ulo); + if (strop) + PyDict_SetItemString(strop, "uppercase", ulo); + Py_DECREF(ulo); + + /* create lowercase string */ + n = 0; + for (c = 0; c < 256; c++) { + if (islower(c)) + ul[n++] = c; + } + ulo = PyString_FromStringAndSize((const char *)ul, n); + if (!ulo) + return; + if (string) + PyDict_SetItemString(string, "lowercase", ulo); + if (strop) + PyDict_SetItemString(strop, "lowercase", ulo); + Py_DECREF(ulo); + + /* create letters string */ + n = 0; + for (c = 0; c < 256; c++) { + if (isalpha(c)) + ul[n++] = c; + } + ulo = PyString_FromStringAndSize((const char *)ul, n); + if (!ulo) + return; + if (string) + PyDict_SetItemString(string, "letters", ulo); + Py_DECREF(ulo); +} + +static PyObject* +PyLocale_setlocale(PyObject* self, PyObject* args) +{ + int category; + char *locale = NULL, *result; + PyObject *result_object; + + if (!PyArg_ParseTuple(args, "i|z:setlocale", &category, &locale)) + return NULL; + + if (locale) { + /* set locale */ + result = setlocale(category, locale); + if (!result) { + /* operation failed, no setting was changed */ + PyErr_SetString(Error, "unsupported locale setting"); + return NULL; + } + result_object = PyString_FromString(result); + if (!result_object) + return NULL; + /* record changes to LC_CTYPE */ + if (category == LC_CTYPE || category == LC_ALL) + fixup_ulcase(); + /* things that got wrong up to here are ignored */ + PyErr_Clear(); + } else { + /* get locale */ + result = setlocale(category, NULL); + if (!result) { + PyErr_SetString(Error, "locale query failed"); + return NULL; + } + result_object = PyString_FromString(result); + } + return result_object; +} + +PyDoc_STRVAR(localeconv__doc__, +"() -> dict. Returns numeric and monetary locale-specific parameters."); + +static PyObject* +PyLocale_localeconv(PyObject* self) +{ + PyObject* result; + struct lconv *l; + PyObject *x; + + result = PyDict_New(); + if (!result) + return NULL; + + /* if LC_NUMERIC is different in the C library, use saved value */ + l = localeconv(); + + /* hopefully, the localeconv result survives the C library calls + involved herein */ + +#define RESULT_STRING(s)\ + x = PyString_FromString(l->s);\ + if (!x) goto failed;\ + PyDict_SetItemString(result, #s, x);\ + Py_XDECREF(x) + +#define RESULT_INT(i)\ + x = PyInt_FromLong(l->i);\ + if (!x) goto failed;\ + PyDict_SetItemString(result, #i, x);\ + Py_XDECREF(x) + + /* Numeric information */ + RESULT_STRING(decimal_point); + RESULT_STRING(thousands_sep); + x = copy_grouping(l->grouping); + if (!x) + goto failed; + PyDict_SetItemString(result, "grouping", x); + Py_XDECREF(x); + + /* Monetary information */ + RESULT_STRING(int_curr_symbol); + RESULT_STRING(currency_symbol); + RESULT_STRING(mon_decimal_point); + RESULT_STRING(mon_thousands_sep); + x = copy_grouping(l->mon_grouping); + if (!x) + goto failed; + PyDict_SetItemString(result, "mon_grouping", x); + Py_XDECREF(x); + RESULT_STRING(positive_sign); + RESULT_STRING(negative_sign); + RESULT_INT(int_frac_digits); + RESULT_INT(frac_digits); + RESULT_INT(p_cs_precedes); + RESULT_INT(p_sep_by_space); + RESULT_INT(n_cs_precedes); + RESULT_INT(n_sep_by_space); + RESULT_INT(p_sign_posn); + RESULT_INT(n_sign_posn); + return result; + + failed: + Py_XDECREF(result); + Py_XDECREF(x); + return NULL; +} + +PyDoc_STRVAR(strcoll__doc__, +"string,string -> int. Compares two strings according to the locale."); + +static PyObject* +PyLocale_strcoll(PyObject* self, PyObject* args) +{ +#if !defined(HAVE_WCSCOLL) || !defined(Py_USING_UNICODE) + char *s1,*s2; + + if (!PyArg_ParseTuple(args, "ss:strcoll", &s1, &s2)) + return NULL; + return PyInt_FromLong(strcoll(s1, s2)); +#else + PyObject *os1, *os2, *result = NULL; + wchar_t *ws1 = NULL, *ws2 = NULL; + int rel1 = 0, rel2 = 0, len1, len2; + + if (!PyArg_UnpackTuple(args, "strcoll", 2, 2, &os1, &os2)) + return NULL; + /* If both arguments are byte strings, use strcoll. */ + if (PyString_Check(os1) && PyString_Check(os2)) + return PyInt_FromLong(strcoll(PyString_AS_STRING(os1), + PyString_AS_STRING(os2))); + /* If neither argument is unicode, it's an error. */ + if (!PyUnicode_Check(os1) && !PyUnicode_Check(os2)) { + PyErr_SetString(PyExc_ValueError, "strcoll arguments must be strings"); + } + /* Convert the non-unicode argument to unicode. */ + if (!PyUnicode_Check(os1)) { + os1 = PyUnicode_FromObject(os1); + if (!os1) + return NULL; + rel1 = 1; + } + if (!PyUnicode_Check(os2)) { + os2 = PyUnicode_FromObject(os2); + if (!os2) { + Py_DECREF(os1); + return NULL; + } + rel2 = 1; + } + /* Convert the unicode strings to wchar[]. */ + len1 = PyUnicode_GET_SIZE(os1) + 1; + ws1 = PyMem_MALLOC(len1 * sizeof(wchar_t)); + if (!ws1) { + PyErr_NoMemory(); + goto done; + } + if (PyUnicode_AsWideChar((PyUnicodeObject*)os1, ws1, len1) == -1) + goto done; + ws1[len1 - 1] = 0; + len2 = PyUnicode_GET_SIZE(os2) + 1; + ws2 = PyMem_MALLOC(len2 * sizeof(wchar_t)); + if (!ws2) { + PyErr_NoMemory(); + goto done; + } + if (PyUnicode_AsWideChar((PyUnicodeObject*)os2, ws2, len2) == -1) + goto done; + ws2[len2 - 1] = 0; + /* Collate the strings. */ + result = PyInt_FromLong(wcscoll(ws1, ws2)); + done: + /* Deallocate everything. */ + if (ws1) PyMem_FREE(ws1); + if (ws2) PyMem_FREE(ws2); + if (rel1) { + Py_DECREF(os1); + } + if (rel2) { + Py_DECREF(os2); + } + return result; +#endif +} + + +PyDoc_STRVAR(strxfrm__doc__, +"string -> string. Returns a string that behaves for cmp locale-aware."); + +static PyObject* +PyLocale_strxfrm(PyObject* self, PyObject* args) +{ + char *s, *buf; + size_t n1, n2; + PyObject *result; + + if (!PyArg_ParseTuple(args, "s:strxfrm", &s)) + return NULL; + + /* assume no change in size, first */ + n1 = strlen(s) + 1; + buf = PyMem_Malloc(n1); + if (!buf) + return PyErr_NoMemory(); + n2 = strxfrm(buf, s, n1) + 1; + if (n2 > n1) { + /* more space needed */ + buf = PyMem_Realloc(buf, n2); + if (!buf) + return PyErr_NoMemory(); + strxfrm(buf, s, n2); + } + result = PyString_FromString(buf); + PyMem_Free(buf); + return result; +} + +#if defined(PLAN9APE) +static PyObject* +PyLocale_getdefaultlocale(PyObject *self) +{ + return Py_BuildValue("ss", Py_None, "UTF-8"); +} +#endif + +#if defined(MS_WINDOWS) +static PyObject* +PyLocale_getdefaultlocale(PyObject* self) +{ + char encoding[100]; + char locale[100]; + + PyOS_snprintf(encoding, sizeof(encoding), "cp%d", GetACP()); + + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SISO639LANGNAME, + locale, sizeof(locale))) { + Py_ssize_t i = strlen(locale); + locale[i++] = '_'; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_SISO3166CTRYNAME, + locale+i, (int)(sizeof(locale)-i))) + return Py_BuildValue("ss", locale, encoding); + } + + /* If we end up here, this windows version didn't know about + ISO639/ISO3166 names (it's probably Windows 95). Return the + Windows language identifier instead (a hexadecimal number) */ + + locale[0] = '0'; + locale[1] = 'x'; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IDEFAULTLANGUAGE, + locale+2, sizeof(locale)-2)) { + return Py_BuildValue("ss", locale, encoding); + } + + /* cannot determine the language code (very unlikely) */ + Py_INCREF(Py_None); + return Py_BuildValue("Os", Py_None, encoding); +} +#endif + +#if defined(__APPLE__) +/* +** Find out what the current script is. +** Donated by Fredrik Lundh. +*/ +static char *mac_getscript(void) +{ + CFStringEncoding enc = CFStringGetSystemEncoding(); + static CFStringRef name = NULL; + /* Return the code name for the encodings for which we have codecs. */ + switch(enc) { + case kCFStringEncodingMacRoman: return "mac-roman"; + case kCFStringEncodingMacGreek: return "mac-greek"; + case kCFStringEncodingMacCyrillic: return "mac-cyrillic"; + case kCFStringEncodingMacTurkish: return "mac-turkish"; + case kCFStringEncodingMacIcelandic: return "mac-icelandic"; + /* XXX which one is mac-latin2? */ + } + if (!name) { + /* This leaks an object. */ + name = CFStringConvertEncodingToIANACharSetName(enc); + } + return (char *)CFStringGetCStringPtr(name, 0); +} + +static PyObject* +PyLocale_getdefaultlocale(PyObject* self) +{ + return Py_BuildValue("Os", Py_None, mac_getscript()); +} +#endif + +#ifdef HAVE_LANGINFO_H +#define LANGINFO(X) {#X, X} +struct langinfo_constant{ + char* name; + int value; +} langinfo_constants[] = +{ + /* These constants should exist on any langinfo implementation */ + LANGINFO(DAY_1), + LANGINFO(DAY_2), + LANGINFO(DAY_3), + LANGINFO(DAY_4), + LANGINFO(DAY_5), + LANGINFO(DAY_6), + LANGINFO(DAY_7), + + LANGINFO(ABDAY_1), + LANGINFO(ABDAY_2), + LANGINFO(ABDAY_3), + LANGINFO(ABDAY_4), + LANGINFO(ABDAY_5), + LANGINFO(ABDAY_6), + LANGINFO(ABDAY_7), + + LANGINFO(MON_1), + LANGINFO(MON_2), + LANGINFO(MON_3), + LANGINFO(MON_4), + LANGINFO(MON_5), + LANGINFO(MON_6), + LANGINFO(MON_7), + LANGINFO(MON_8), + LANGINFO(MON_9), + LANGINFO(MON_10), + LANGINFO(MON_11), + LANGINFO(MON_12), + + LANGINFO(ABMON_1), + LANGINFO(ABMON_2), + LANGINFO(ABMON_3), + LANGINFO(ABMON_4), + LANGINFO(ABMON_5), + LANGINFO(ABMON_6), + LANGINFO(ABMON_7), + LANGINFO(ABMON_8), + LANGINFO(ABMON_9), + LANGINFO(ABMON_10), + LANGINFO(ABMON_11), + LANGINFO(ABMON_12), + +#ifdef RADIXCHAR + /* The following are not available with glibc 2.0 */ + LANGINFO(RADIXCHAR), + LANGINFO(THOUSEP), + /* YESSTR and NOSTR are deprecated in glibc, since they are + a special case of message translation, which should be rather + done using gettext. So we don't expose it to Python in the + first place. + LANGINFO(YESSTR), + LANGINFO(NOSTR), + */ + LANGINFO(CRNCYSTR), +#endif + + LANGINFO(D_T_FMT), + LANGINFO(D_FMT), + LANGINFO(T_FMT), + LANGINFO(AM_STR), + LANGINFO(PM_STR), + + /* The following constants are available only with XPG4, but... + AIX 3.2. only has CODESET. + OpenBSD doesn't have CODESET but has T_FMT_AMPM, and doesn't have + a few of the others. + Solution: ifdef-test them all. */ +#ifdef CODESET + LANGINFO(CODESET), +#endif +#ifdef T_FMT_AMPM + LANGINFO(T_FMT_AMPM), +#endif +#ifdef ERA + LANGINFO(ERA), +#endif +#ifdef ERA_D_FMT + LANGINFO(ERA_D_FMT), +#endif +#ifdef ERA_D_T_FMT + LANGINFO(ERA_D_T_FMT), +#endif +#ifdef ERA_T_FMT + LANGINFO(ERA_T_FMT), +#endif +#ifdef ALT_DIGITS + LANGINFO(ALT_DIGITS), +#endif +#ifdef YESEXPR + LANGINFO(YESEXPR), +#endif +#ifdef NOEXPR + LANGINFO(NOEXPR), +#endif +#ifdef _DATE_FMT + /* This is not available in all glibc versions that have CODESET. */ + LANGINFO(_DATE_FMT), +#endif + {0, 0} +}; + +PyDoc_STRVAR(nl_langinfo__doc__, +"nl_langinfo(key) -> string\n" +"Return the value for the locale information associated with key."); + +static PyObject* +PyLocale_nl_langinfo(PyObject* self, PyObject* args) +{ + int item, i; + if (!PyArg_ParseTuple(args, "i:nl_langinfo", &item)) + return NULL; + /* Check whether this is a supported constant. GNU libc sometimes + returns numeric values in the char* return value, which would + crash PyString_FromString. */ + for (i = 0; langinfo_constants[i].name; i++) + if (langinfo_constants[i].value == item) { + /* Check NULL as a workaround for GNU libc's returning NULL + instead of an empty string for nl_langinfo(ERA). */ + const char *result = nl_langinfo(item); + return PyString_FromString(result != NULL ? result : ""); + } + PyErr_SetString(PyExc_ValueError, "unsupported langinfo constant"); + return NULL; +} +#endif /* HAVE_LANGINFO_H */ + +#ifdef HAVE_LIBINTL_H + +PyDoc_STRVAR(gettext__doc__, +"gettext(msg) -> string\n" +"Return translation of msg."); + +static PyObject* +PyIntl_gettext(PyObject* self, PyObject *args) +{ + char *in; + if (!PyArg_ParseTuple(args, "z", &in)) + return 0; + return PyString_FromString(gettext(in)); +} + +PyDoc_STRVAR(dgettext__doc__, +"dgettext(domain, msg) -> string\n" +"Return translation of msg in domain."); + +static PyObject* +PyIntl_dgettext(PyObject* self, PyObject *args) +{ + char *domain, *in; + if (!PyArg_ParseTuple(args, "zz", &domain, &in)) + return 0; + return PyString_FromString(dgettext(domain, in)); +} + +PyDoc_STRVAR(dcgettext__doc__, +"dcgettext(domain, msg, category) -> string\n" +"Return translation of msg in domain and category."); + +static PyObject* +PyIntl_dcgettext(PyObject *self, PyObject *args) +{ + char *domain, *msgid; + int category; + if (!PyArg_ParseTuple(args, "zzi", &domain, &msgid, &category)) + return 0; + return PyString_FromString(dcgettext(domain,msgid,category)); +} + +PyDoc_STRVAR(textdomain__doc__, +"textdomain(domain) -> string\n" +"Set the C library's textdmain to domain, returning the new domain."); + +static PyObject* +PyIntl_textdomain(PyObject* self, PyObject* args) +{ + char *domain; + if (!PyArg_ParseTuple(args, "z", &domain)) + return 0; + domain = textdomain(domain); + if (!domain) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return PyString_FromString(domain); +} + +PyDoc_STRVAR(bindtextdomain__doc__, +"bindtextdomain(domain, dir) -> string\n" +"Bind the C library's domain to dir."); + +static PyObject* +PyIntl_bindtextdomain(PyObject* self,PyObject*args) +{ + char *domain,*dirname; + if (!PyArg_ParseTuple(args, "zz", &domain, &dirname)) + return 0; + dirname = bindtextdomain(domain, dirname); + if (!dirname) { + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + } + return PyString_FromString(dirname); +} + +#ifdef HAVE_BIND_TEXTDOMAIN_CODESET +PyDoc_STRVAR(bind_textdomain_codeset__doc__, +"bind_textdomain_codeset(domain, codeset) -> string\n" +"Bind the C library's domain to codeset."); + +static PyObject* +PyIntl_bind_textdomain_codeset(PyObject* self,PyObject*args) +{ + char *domain,*codeset; + if (!PyArg_ParseTuple(args, "sz", &domain, &codeset)) + return NULL; + codeset = bind_textdomain_codeset(domain, codeset); + if (codeset) + return PyString_FromString(codeset); + Py_RETURN_NONE; +} +#endif + +#endif + +static struct PyMethodDef PyLocale_Methods[] = { + {"setlocale", (PyCFunction) PyLocale_setlocale, + METH_VARARGS, setlocale__doc__}, + {"localeconv", (PyCFunction) PyLocale_localeconv, + METH_NOARGS, localeconv__doc__}, + {"strcoll", (PyCFunction) PyLocale_strcoll, + METH_VARARGS, strcoll__doc__}, + {"strxfrm", (PyCFunction) PyLocale_strxfrm, + METH_VARARGS, strxfrm__doc__}, +#if defined(MS_WINDOWS) || defined(__APPLE__) || defined(PLAN9APE) + {"_getdefaultlocale", (PyCFunction) PyLocale_getdefaultlocale, METH_NOARGS}, +#endif +#ifdef HAVE_LANGINFO_H + {"nl_langinfo", (PyCFunction) PyLocale_nl_langinfo, + METH_VARARGS, nl_langinfo__doc__}, +#endif +#ifdef HAVE_LIBINTL_H + {"gettext",(PyCFunction)PyIntl_gettext,METH_VARARGS, + gettext__doc__}, + {"dgettext",(PyCFunction)PyIntl_dgettext,METH_VARARGS, + dgettext__doc__}, + {"dcgettext",(PyCFunction)PyIntl_dcgettext,METH_VARARGS, + dcgettext__doc__}, + {"textdomain",(PyCFunction)PyIntl_textdomain,METH_VARARGS, + textdomain__doc__}, + {"bindtextdomain",(PyCFunction)PyIntl_bindtextdomain,METH_VARARGS, + bindtextdomain__doc__}, +#ifdef HAVE_BIND_TEXTDOMAIN_CODESET + {"bind_textdomain_codeset",(PyCFunction)PyIntl_bind_textdomain_codeset, + METH_VARARGS, bind_textdomain_codeset__doc__}, +#endif +#endif + {NULL, NULL} +}; + +PyMODINIT_FUNC +init_locale(void) +{ + PyObject *m, *d, *x; +#ifdef HAVE_LANGINFO_H + int i; +#endif + + m = Py_InitModule("_locale", PyLocale_Methods); + if (m == NULL) + return; + + d = PyModule_GetDict(m); + + x = PyInt_FromLong(LC_CTYPE); + PyDict_SetItemString(d, "LC_CTYPE", x); + Py_XDECREF(x); + + x = PyInt_FromLong(LC_TIME); + PyDict_SetItemString(d, "LC_TIME", x); + Py_XDECREF(x); + + x = PyInt_FromLong(LC_COLLATE); + PyDict_SetItemString(d, "LC_COLLATE", x); + Py_XDECREF(x); + + x = PyInt_FromLong(LC_MONETARY); + PyDict_SetItemString(d, "LC_MONETARY", x); + Py_XDECREF(x); + +#ifdef LC_MESSAGES + x = PyInt_FromLong(LC_MESSAGES); + PyDict_SetItemString(d, "LC_MESSAGES", x); + Py_XDECREF(x); +#endif /* LC_MESSAGES */ + + x = PyInt_FromLong(LC_NUMERIC); + PyDict_SetItemString(d, "LC_NUMERIC", x); + Py_XDECREF(x); + + x = PyInt_FromLong(LC_ALL); + PyDict_SetItemString(d, "LC_ALL", x); + Py_XDECREF(x); + + x = PyInt_FromLong(CHAR_MAX); + PyDict_SetItemString(d, "CHAR_MAX", x); + Py_XDECREF(x); + + Error = PyErr_NewException("locale.Error", NULL, NULL); + PyDict_SetItemString(d, "Error", Error); + + x = PyString_FromString(locale__doc__); + PyDict_SetItemString(d, "__doc__", x); + Py_XDECREF(x); + +#ifdef HAVE_LANGINFO_H + for (i = 0; langinfo_constants[i].name; i++) { + PyModule_AddIntConstant(m, langinfo_constants[i].name, + langinfo_constants[i].value); + } +#endif +} + +/* +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/sys/src/cmd/python/Modules/_lsprof.c b/sys/src/cmd/python/Modules/_lsprof.c new file mode 100644 index 000000000..d35c894c5 --- /dev/null +++ b/sys/src/cmd/python/Modules/_lsprof.c @@ -0,0 +1,875 @@ +#include "Python.h" +#include "compile.h" +#include "frameobject.h" +#include "structseq.h" +#include "rotatingtree.h" + +#if !defined(HAVE_LONG_LONG) +#error "This module requires long longs!" +#endif + +/*** Selection of a high-precision timer ***/ + +#ifdef MS_WINDOWS + +#include <windows.h> + +static PY_LONG_LONG +hpTimer(void) +{ + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + return li.QuadPart; +} + +static double +hpTimerUnit(void) +{ + LARGE_INTEGER li; + if (QueryPerformanceFrequency(&li)) + return 1.0 / li.QuadPart; + else + return 0.000001; /* unlikely */ +} + +#else /* !MS_WINDOWS */ + +#ifndef HAVE_GETTIMEOFDAY +#error "This module requires gettimeofday() on non-Windows platforms!" +#endif + +#if (defined(PYOS_OS2) && defined(PYCC_GCC)) +#include <sys/time.h> +#else +#include <sys/resource.h> +#include <sys/times.h> +#endif + +static PY_LONG_LONG +hpTimer(void) +{ + struct timeval tv; + PY_LONG_LONG ret; +#ifdef GETTIMEOFDAY_NO_TZ + gettimeofday(&tv); +#else + gettimeofday(&tv, (struct timezone *)NULL); +#endif + ret = tv.tv_sec; + ret = ret * 1000000 + tv.tv_usec; + return ret; +} + +static double +hpTimerUnit(void) +{ + return 0.000001; +} + +#endif /* MS_WINDOWS */ + +/************************************************************/ +/* Written by Brett Rosen and Ted Czotter */ + +struct _ProfilerEntry; + +/* represents a function called from another function */ +typedef struct _ProfilerSubEntry { + rotating_node_t header; + PY_LONG_LONG tt; + PY_LONG_LONG it; + long callcount; + long recursivecallcount; + long recursionLevel; +} ProfilerSubEntry; + +/* represents a function or user defined block */ +typedef struct _ProfilerEntry { + rotating_node_t header; + PyObject *userObj; /* PyCodeObject, or a descriptive str for builtins */ + PY_LONG_LONG tt; /* total time in this entry */ + PY_LONG_LONG it; /* inline time in this entry (not in subcalls) */ + long callcount; /* how many times this was called */ + long recursivecallcount; /* how many times called recursively */ + long recursionLevel; + rotating_node_t *calls; +} ProfilerEntry; + +typedef struct _ProfilerContext { + PY_LONG_LONG t0; + PY_LONG_LONG subt; + struct _ProfilerContext *previous; + ProfilerEntry *ctxEntry; +} ProfilerContext; + +typedef struct { + PyObject_HEAD + rotating_node_t *profilerEntries; + ProfilerContext *currentProfilerContext; + ProfilerContext *freelistProfilerContext; + int flags; + PyObject *externalTimer; + double externalTimerUnit; +} ProfilerObject; + +#define POF_ENABLED 0x001 +#define POF_SUBCALLS 0x002 +#define POF_BUILTINS 0x004 +#define POF_NOMEMORY 0x100 + +staticforward PyTypeObject PyProfiler_Type; + +#define PyProfiler_Check(op) PyObject_TypeCheck(op, &PyProfiler_Type) +#define PyProfiler_CheckExact(op) ((op)->ob_type == &PyProfiler_Type) + +/*** External Timers ***/ + +#define DOUBLE_TIMER_PRECISION 4294967296.0 +static PyObject *empty_tuple; + +static PY_LONG_LONG CallExternalTimer(ProfilerObject *pObj) +{ + PY_LONG_LONG result; + PyObject *o = PyObject_Call(pObj->externalTimer, empty_tuple, NULL); + if (o == NULL) { + PyErr_WriteUnraisable(pObj->externalTimer); + return 0; + } + if (pObj->externalTimerUnit > 0.0) { + /* interpret the result as an integer that will be scaled + in profiler_getstats() */ + result = PyLong_AsLongLong(o); + } + else { + /* interpret the result as a double measured in seconds. + As the profiler works with PY_LONG_LONG internally + we convert it to a large integer */ + double val = PyFloat_AsDouble(o); + /* error handling delayed to the code below */ + result = (PY_LONG_LONG) (val * DOUBLE_TIMER_PRECISION); + } + Py_DECREF(o); + if (PyErr_Occurred()) { + PyErr_WriteUnraisable((PyObject *) pObj); + return 0; + } + return result; +} + +#define CALL_TIMER(pObj) ((pObj)->externalTimer ? \ + CallExternalTimer(pObj) : \ + hpTimer()) + +/*** ProfilerObject ***/ + +static PyObject * +normalizeUserObj(PyObject *obj) +{ + PyCFunctionObject *fn; + if (!PyCFunction_Check(obj)) { + Py_INCREF(obj); + return obj; + } + /* Replace built-in function objects with a descriptive string + because of built-in methods -- keeping a reference to + __self__ is probably not a good idea. */ + fn = (PyCFunctionObject *)obj; + + if (fn->m_self == NULL) { + /* built-in function: look up the module name */ + PyObject *mod = fn->m_module; + char *modname; + if (mod && PyString_Check(mod)) { + modname = PyString_AS_STRING(mod); + } + else if (mod && PyModule_Check(mod)) { + modname = PyModule_GetName(mod); + if (modname == NULL) { + PyErr_Clear(); + modname = "__builtin__"; + } + } + else { + modname = "__builtin__"; + } + if (strcmp(modname, "__builtin__") != 0) + return PyString_FromFormat("<%s.%s>", + modname, + fn->m_ml->ml_name); + else + return PyString_FromFormat("<%s>", + fn->m_ml->ml_name); + } + else { + /* built-in method: try to return + repr(getattr(type(__self__), __name__)) + */ + PyObject *self = fn->m_self; + PyObject *name = PyString_FromString(fn->m_ml->ml_name); + if (name != NULL) { + PyObject *mo = _PyType_Lookup(self->ob_type, name); + Py_XINCREF(mo); + Py_DECREF(name); + if (mo != NULL) { + PyObject *res = PyObject_Repr(mo); + Py_DECREF(mo); + if (res != NULL) + return res; + } + } + PyErr_Clear(); + return PyString_FromFormat("<built-in method %s>", + fn->m_ml->ml_name); + } +} + +static ProfilerEntry* +newProfilerEntry(ProfilerObject *pObj, void *key, PyObject *userObj) +{ + ProfilerEntry *self; + self = (ProfilerEntry*) malloc(sizeof(ProfilerEntry)); + if (self == NULL) { + pObj->flags |= POF_NOMEMORY; + return NULL; + } + userObj = normalizeUserObj(userObj); + if (userObj == NULL) { + PyErr_Clear(); + free(self); + pObj->flags |= POF_NOMEMORY; + return NULL; + } + self->header.key = key; + self->userObj = userObj; + self->tt = 0; + self->it = 0; + self->callcount = 0; + self->recursivecallcount = 0; + self->recursionLevel = 0; + self->calls = EMPTY_ROTATING_TREE; + RotatingTree_Add(&pObj->profilerEntries, &self->header); + return self; +} + +static ProfilerEntry* +getEntry(ProfilerObject *pObj, void *key) +{ + return (ProfilerEntry*) RotatingTree_Get(&pObj->profilerEntries, key); +} + +static ProfilerSubEntry * +getSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry) +{ + return (ProfilerSubEntry*) RotatingTree_Get(&caller->calls, + (void *)entry); +} + +static ProfilerSubEntry * +newSubEntry(ProfilerObject *pObj, ProfilerEntry *caller, ProfilerEntry* entry) +{ + ProfilerSubEntry *self; + self = (ProfilerSubEntry*) malloc(sizeof(ProfilerSubEntry)); + if (self == NULL) { + pObj->flags |= POF_NOMEMORY; + return NULL; + } + self->header.key = (void *)entry; + self->tt = 0; + self->it = 0; + self->callcount = 0; + self->recursivecallcount = 0; + self->recursionLevel = 0; + RotatingTree_Add(&caller->calls, &self->header); + return self; +} + +static int freeSubEntry(rotating_node_t *header, void *arg) +{ + ProfilerSubEntry *subentry = (ProfilerSubEntry*) header; + free(subentry); + return 0; +} + +static int freeEntry(rotating_node_t *header, void *arg) +{ + ProfilerEntry *entry = (ProfilerEntry*) header; + RotatingTree_Enum(entry->calls, freeSubEntry, NULL); + Py_DECREF(entry->userObj); + free(entry); + return 0; +} + +static void clearEntries(ProfilerObject *pObj) +{ + RotatingTree_Enum(pObj->profilerEntries, freeEntry, NULL); + pObj->profilerEntries = EMPTY_ROTATING_TREE; + /* release the memory hold by the free list of ProfilerContexts */ + while (pObj->freelistProfilerContext) { + ProfilerContext *c = pObj->freelistProfilerContext; + pObj->freelistProfilerContext = c->previous; + free(c); + } +} + +static void +initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) +{ + self->ctxEntry = entry; + self->subt = 0; + self->previous = pObj->currentProfilerContext; + pObj->currentProfilerContext = self; + ++entry->recursionLevel; + if ((pObj->flags & POF_SUBCALLS) && self->previous) { + /* find or create an entry for me in my caller's entry */ + ProfilerEntry *caller = self->previous->ctxEntry; + ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry); + if (subentry == NULL) + subentry = newSubEntry(pObj, caller, entry); + if (subentry) + ++subentry->recursionLevel; + } + self->t0 = CALL_TIMER(pObj); +} + +static void +Stop(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry) +{ + PY_LONG_LONG tt = CALL_TIMER(pObj) - self->t0; + PY_LONG_LONG it = tt - self->subt; + if (self->previous) + self->previous->subt += tt; + pObj->currentProfilerContext = self->previous; + if (--entry->recursionLevel == 0) + entry->tt += tt; + else + ++entry->recursivecallcount; + entry->it += it; + entry->callcount++; + if ((pObj->flags & POF_SUBCALLS) && self->previous) { + /* find or create an entry for me in my caller's entry */ + ProfilerEntry *caller = self->previous->ctxEntry; + ProfilerSubEntry *subentry = getSubEntry(pObj, caller, entry); + if (subentry) { + if (--subentry->recursionLevel == 0) + subentry->tt += tt; + else + ++subentry->recursivecallcount; + subentry->it += it; + ++subentry->callcount; + } + } +} + +static void +ptrace_enter_call(PyObject *self, void *key, PyObject *userObj) +{ + /* entering a call to the function identified by 'key' + (which can be a PyCodeObject or a PyMethodDef pointer) */ + ProfilerObject *pObj = (ProfilerObject*)self; + ProfilerEntry *profEntry; + ProfilerContext *pContext; + + profEntry = getEntry(pObj, key); + if (profEntry == NULL) { + profEntry = newProfilerEntry(pObj, key, userObj); + if (profEntry == NULL) + return; + } + /* grab a ProfilerContext out of the free list */ + pContext = pObj->freelistProfilerContext; + if (pContext) { + pObj->freelistProfilerContext = pContext->previous; + } + else { + /* free list exhausted, allocate a new one */ + pContext = (ProfilerContext*) + malloc(sizeof(ProfilerContext)); + if (pContext == NULL) { + pObj->flags |= POF_NOMEMORY; + return; + } + } + initContext(pObj, pContext, profEntry); +} + +static void +ptrace_leave_call(PyObject *self, void *key) +{ + /* leaving a call to the function identified by 'key' */ + ProfilerObject *pObj = (ProfilerObject*)self; + ProfilerEntry *profEntry; + ProfilerContext *pContext; + + pContext = pObj->currentProfilerContext; + if (pContext == NULL) + return; + profEntry = getEntry(pObj, key); + if (profEntry) { + Stop(pObj, pContext, profEntry); + } + else { + pObj->currentProfilerContext = pContext->previous; + } + /* put pContext into the free list */ + pContext->previous = pObj->freelistProfilerContext; + pObj->freelistProfilerContext = pContext; +} + +static int +profiler_callback(PyObject *self, PyFrameObject *frame, int what, + PyObject *arg) +{ + switch (what) { + + /* the 'frame' of a called function is about to start its execution */ + case PyTrace_CALL: + ptrace_enter_call(self, (void *)frame->f_code, + (PyObject *)frame->f_code); + break; + + /* the 'frame' of a called function is about to finish + (either normally or with an exception) */ + case PyTrace_RETURN: + ptrace_leave_call(self, (void *)frame->f_code); + break; + + /* case PyTrace_EXCEPTION: + If the exception results in the function exiting, a + PyTrace_RETURN event will be generated, so we don't need to + handle it. */ + +#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */ + /* the Python function 'frame' is issuing a call to the built-in + function 'arg' */ + case PyTrace_C_CALL: + if ((((ProfilerObject *)self)->flags & POF_BUILTINS) + && PyCFunction_Check(arg)) { + ptrace_enter_call(self, + ((PyCFunctionObject *)arg)->m_ml, + arg); + } + break; + + /* the call to the built-in function 'arg' is returning into its + caller 'frame' */ + case PyTrace_C_RETURN: /* ...normally */ + case PyTrace_C_EXCEPTION: /* ...with an exception set */ + if ((((ProfilerObject *)self)->flags & POF_BUILTINS) + && PyCFunction_Check(arg)) { + ptrace_leave_call(self, + ((PyCFunctionObject *)arg)->m_ml); + } + break; +#endif + + default: + break; + } + return 0; +} + +static int +pending_exception(ProfilerObject *pObj) +{ + if (pObj->flags & POF_NOMEMORY) { + pObj->flags -= POF_NOMEMORY; + PyErr_SetString(PyExc_MemoryError, + "memory was exhausted while profiling"); + return -1; + } + return 0; +} + +/************************************************************/ + +static PyStructSequence_Field profiler_entry_fields[] = { + {"code", "code object or built-in function name"}, + {"callcount", "how many times this was called"}, + {"reccallcount", "how many times called recursively"}, + {"totaltime", "total time in this entry"}, + {"inlinetime", "inline time in this entry (not in subcalls)"}, + {"calls", "details of the calls"}, + {0} +}; + +static PyStructSequence_Field profiler_subentry_fields[] = { + {"code", "called code object or built-in function name"}, + {"callcount", "how many times this is called"}, + {"reccallcount", "how many times this is called recursively"}, + {"totaltime", "total time spent in this call"}, + {"inlinetime", "inline time (not in further subcalls)"}, + {0} +}; + +static PyStructSequence_Desc profiler_entry_desc = { + "_lsprof.profiler_entry", /* name */ + NULL, /* doc */ + profiler_entry_fields, + 6 +}; + +static PyStructSequence_Desc profiler_subentry_desc = { + "_lsprof.profiler_subentry", /* name */ + NULL, /* doc */ + profiler_subentry_fields, + 5 +}; + +static int initialized; +static PyTypeObject StatsEntryType; +static PyTypeObject StatsSubEntryType; + + +typedef struct { + PyObject *list; + PyObject *sublist; + double factor; +} statscollector_t; + +static int statsForSubEntry(rotating_node_t *node, void *arg) +{ + ProfilerSubEntry *sentry = (ProfilerSubEntry*) node; + statscollector_t *collect = (statscollector_t*) arg; + ProfilerEntry *entry = (ProfilerEntry*) sentry->header.key; + int err; + PyObject *sinfo; + sinfo = PyObject_CallFunction((PyObject*) &StatsSubEntryType, + "((Olldd))", + entry->userObj, + sentry->callcount, + sentry->recursivecallcount, + collect->factor * sentry->tt, + collect->factor * sentry->it); + if (sinfo == NULL) + return -1; + err = PyList_Append(collect->sublist, sinfo); + Py_DECREF(sinfo); + return err; +} + +static int statsForEntry(rotating_node_t *node, void *arg) +{ + ProfilerEntry *entry = (ProfilerEntry*) node; + statscollector_t *collect = (statscollector_t*) arg; + PyObject *info; + int err; + if (entry->callcount == 0) + return 0; /* skip */ + + if (entry->calls != EMPTY_ROTATING_TREE) { + collect->sublist = PyList_New(0); + if (collect->sublist == NULL) + return -1; + if (RotatingTree_Enum(entry->calls, + statsForSubEntry, collect) != 0) { + Py_DECREF(collect->sublist); + return -1; + } + } + else { + Py_INCREF(Py_None); + collect->sublist = Py_None; + } + + info = PyObject_CallFunction((PyObject*) &StatsEntryType, + "((OllddO))", + entry->userObj, + entry->callcount, + entry->recursivecallcount, + collect->factor * entry->tt, + collect->factor * entry->it, + collect->sublist); + Py_DECREF(collect->sublist); + if (info == NULL) + return -1; + err = PyList_Append(collect->list, info); + Py_DECREF(info); + return err; +} + +PyDoc_STRVAR(getstats_doc, "\ +getstats() -> list of profiler_entry objects\n\ +\n\ +Return all information collected by the profiler.\n\ +Each profiler_entry is a tuple-like object with the\n\ +following attributes:\n\ +\n\ + code code object\n\ + callcount how many times this was called\n\ + reccallcount how many times called recursively\n\ + totaltime total time in this entry\n\ + inlinetime inline time in this entry (not in subcalls)\n\ + calls details of the calls\n\ +\n\ +The calls attribute is either None or a list of\n\ +profiler_subentry objects:\n\ +\n\ + code called code object\n\ + callcount how many times this is called\n\ + reccallcount how many times this is called recursively\n\ + totaltime total time spent in this call\n\ + inlinetime inline time (not in further subcalls)\n\ +"); + +static PyObject* +profiler_getstats(ProfilerObject *pObj, PyObject* noarg) +{ + statscollector_t collect; + if (pending_exception(pObj)) + return NULL; + if (!pObj->externalTimer) + collect.factor = hpTimerUnit(); + else if (pObj->externalTimerUnit > 0.0) + collect.factor = pObj->externalTimerUnit; + else + collect.factor = 1.0 / DOUBLE_TIMER_PRECISION; + collect.list = PyList_New(0); + if (collect.list == NULL) + return NULL; + if (RotatingTree_Enum(pObj->profilerEntries, statsForEntry, &collect) + != 0) { + Py_DECREF(collect.list); + return NULL; + } + return collect.list; +} + +static int +setSubcalls(ProfilerObject *pObj, int nvalue) +{ + if (nvalue == 0) + pObj->flags &= ~POF_SUBCALLS; + else if (nvalue > 0) + pObj->flags |= POF_SUBCALLS; + return 0; +} + +static int +setBuiltins(ProfilerObject *pObj, int nvalue) +{ + if (nvalue == 0) + pObj->flags &= ~POF_BUILTINS; + else if (nvalue > 0) { +#ifndef PyTrace_C_CALL + PyErr_SetString(PyExc_ValueError, + "builtins=True requires Python >= 2.4"); + return -1; +#else + pObj->flags |= POF_BUILTINS; +#endif + } + return 0; +} + +PyDoc_STRVAR(enable_doc, "\ +enable(subcalls=True, builtins=True)\n\ +\n\ +Start collecting profiling information.\n\ +If 'subcalls' is True, also records for each function\n\ +statistics separated according to its current caller.\n\ +If 'builtins' is True, records the time spent in\n\ +built-in functions separately from their caller.\n\ +"); + +static PyObject* +profiler_enable(ProfilerObject *self, PyObject *args, PyObject *kwds) +{ + int subcalls = -1; + int builtins = -1; + static char *kwlist[] = {"subcalls", "builtins", 0}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable", + kwlist, &subcalls, &builtins)) + return NULL; + if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) + return NULL; + PyEval_SetProfile(profiler_callback, (PyObject*)self); + self->flags |= POF_ENABLED; + Py_INCREF(Py_None); + return Py_None; +} + +static void +flush_unmatched(ProfilerObject *pObj) +{ + while (pObj->currentProfilerContext) { + ProfilerContext *pContext = pObj->currentProfilerContext; + ProfilerEntry *profEntry= pContext->ctxEntry; + if (profEntry) + Stop(pObj, pContext, profEntry); + else + pObj->currentProfilerContext = pContext->previous; + if (pContext) + free(pContext); + } + +} + +PyDoc_STRVAR(disable_doc, "\ +disable()\n\ +\n\ +Stop collecting profiling information.\n\ +"); + +static PyObject* +profiler_disable(ProfilerObject *self, PyObject* noarg) +{ + self->flags &= ~POF_ENABLED; + PyEval_SetProfile(NULL, NULL); + flush_unmatched(self); + if (pending_exception(self)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(clear_doc, "\ +clear()\n\ +\n\ +Clear all profiling information collected so far.\n\ +"); + +static PyObject* +profiler_clear(ProfilerObject *pObj, PyObject* noarg) +{ + clearEntries(pObj); + Py_INCREF(Py_None); + return Py_None; +} + +static void +profiler_dealloc(ProfilerObject *op) +{ + if (op->flags & POF_ENABLED) + PyEval_SetProfile(NULL, NULL); + flush_unmatched(op); + clearEntries(op); + Py_XDECREF(op->externalTimer); + op->ob_type->tp_free(op); +} + +static int +profiler_init(ProfilerObject *pObj, PyObject *args, PyObject *kw) +{ + PyObject *o; + PyObject *timer = NULL; + double timeunit = 0.0; + int subcalls = 1; +#ifdef PyTrace_C_CALL + int builtins = 1; +#else + int builtins = 0; +#endif + static char *kwlist[] = {"timer", "timeunit", + "subcalls", "builtins", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|Odii:Profiler", kwlist, + &timer, &timeunit, + &subcalls, &builtins)) + return -1; + + if (setSubcalls(pObj, subcalls) < 0 || setBuiltins(pObj, builtins) < 0) + return -1; + o = pObj->externalTimer; + pObj->externalTimer = timer; + Py_XINCREF(timer); + Py_XDECREF(o); + pObj->externalTimerUnit = timeunit; + return 0; +} + +static PyMethodDef profiler_methods[] = { + {"getstats", (PyCFunction)profiler_getstats, + METH_NOARGS, getstats_doc}, + {"enable", (PyCFunction)profiler_enable, + METH_VARARGS | METH_KEYWORDS, enable_doc}, + {"disable", (PyCFunction)profiler_disable, + METH_NOARGS, disable_doc}, + {"clear", (PyCFunction)profiler_clear, + METH_NOARGS, clear_doc}, + {NULL, NULL} +}; + +PyDoc_STRVAR(profiler_doc, "\ +Profiler(custom_timer=None, time_unit=None, subcalls=True, builtins=True)\n\ +\n\ + Builds a profiler object using the specified timer function.\n\ + The default timer is a fast built-in one based on real time.\n\ + For custom timer functions returning integers, time_unit can\n\ + be a float specifying a scale (i.e. how long each integer unit\n\ + is, in seconds).\n\ +"); + +statichere PyTypeObject PyProfiler_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_lsprof.Profiler", /* tp_name */ + sizeof(ProfilerObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)profiler_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + profiler_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + profiler_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)profiler_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + +static PyMethodDef moduleMethods[] = { + {NULL, NULL} +}; + +PyMODINIT_FUNC +init_lsprof(void) +{ + PyObject *module, *d; + module = Py_InitModule3("_lsprof", moduleMethods, "Fast profiler"); + if (module == NULL) + return; + d = PyModule_GetDict(module); + if (PyType_Ready(&PyProfiler_Type) < 0) + return; + PyDict_SetItemString(d, "Profiler", (PyObject *)&PyProfiler_Type); + + if (!initialized) { + PyStructSequence_InitType(&StatsEntryType, + &profiler_entry_desc); + PyStructSequence_InitType(&StatsSubEntryType, + &profiler_subentry_desc); + } + Py_INCREF((PyObject*) &StatsEntryType); + Py_INCREF((PyObject*) &StatsSubEntryType); + PyModule_AddObject(module, "profiler_entry", + (PyObject*) &StatsEntryType); + PyModule_AddObject(module, "profiler_subentry", + (PyObject*) &StatsSubEntryType); + empty_tuple = PyTuple_New(0); + initialized = 1; +} diff --git a/sys/src/cmd/python/Modules/_randommodule.c b/sys/src/cmd/python/Modules/_randommodule.c new file mode 100644 index 000000000..591947e47 --- /dev/null +++ b/sys/src/cmd/python/Modules/_randommodule.c @@ -0,0 +1,580 @@ +/* Random objects */ + +/* ------------------------------------------------------------------ + The code in this module was based on a download from: + http://www.math.keio.ac.jp/~matumoto/MT2002/emt19937ar.html + + It was modified in 2002 by Raymond Hettinger as follows: + + * the principal computational lines untouched except for tabbing. + + * renamed genrand_res53() to random_random() and wrapped + in python calling/return code. + + * genrand_int32() and the helper functions, init_genrand() + and init_by_array(), were declared static, wrapped in + Python calling/return code. also, their global data + references were replaced with structure references. + + * unused functions from the original were deleted. + new, original C python code was added to implement the + Random() interface. + + The following are the verbatim comments from the original code: + + A C-program for MT19937, with initialization improved 2002/1/26. + Coded by Takuji Nishimura and Makoto Matsumoto. + + Before using, initialize the state by using init_genrand(seed) + or init_by_array(init_key, key_length). + + Copyright (C) 1997 - 2002, Makoto Matsumoto and Takuji Nishimura, + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. The names of its contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + Any feedback is very welcome. + http://www.math.keio.ac.jp/matumoto/emt.html + email: matumoto@math.keio.ac.jp +*/ + +/* ---------------------------------------------------------------*/ + +#include "Python.h" +#include <time.h> /* for seeding to current time */ + +/* Period parameters -- These are all magic. Don't change. */ +#define N 624 +#define M 397 +#define MATRIX_A 0x9908b0dfUL /* constant vector a */ +#define UPPER_MASK 0x80000000UL /* most significant w-r bits */ +#define LOWER_MASK 0x7fffffffUL /* least significant r bits */ + +typedef struct { + PyObject_HEAD + unsigned long state[N]; + int index; +} RandomObject; + +static PyTypeObject Random_Type; + +#define RandomObject_Check(v) ((v)->ob_type == &Random_Type) + + +/* Random methods */ + + +/* generates a random number on [0,0xffffffff]-interval */ +static unsigned long +genrand_int32(RandomObject *self) +{ + unsigned long y; + static unsigned long mag01[2]={0x0UL, MATRIX_A}; + /* mag01[x] = x * MATRIX_A for x=0,1 */ + unsigned long *mt; + + mt = self->state; + if (self->index >= N) { /* generate N words at one time */ + int kk; + + for (kk=0;kk<N-M;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + for (;kk<N-1;kk++) { + y = (mt[kk]&UPPER_MASK)|(mt[kk+1]&LOWER_MASK); + mt[kk] = mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL]; + } + y = (mt[N-1]&UPPER_MASK)|(mt[0]&LOWER_MASK); + mt[N-1] = mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL]; + + self->index = 0; + } + + y = mt[self->index++]; + y ^= (y >> 11); + y ^= (y << 7) & 0x9d2c5680UL; + y ^= (y << 15) & 0xefc60000UL; + y ^= (y >> 18); + return y; +} + +/* random_random is the function named genrand_res53 in the original code; + * generates a random number on [0,1) with 53-bit resolution; note that + * 9007199254740992 == 2**53; I assume they're spelling "/2**53" as + * multiply-by-reciprocal in the (likely vain) hope that the compiler will + * optimize the division away at compile-time. 67108864 is 2**26. In + * effect, a contains 27 random bits shifted left 26, and b fills in the + * lower 26 bits of the 53-bit numerator. + * The orginal code credited Isaku Wada for this algorithm, 2002/01/09. + */ +static PyObject * +random_random(RandomObject *self) +{ + unsigned long a=genrand_int32(self)>>5, b=genrand_int32(self)>>6; + return PyFloat_FromDouble((a*67108864.0+b)*(1.0/9007199254740992.0)); +} + +/* initializes mt[N] with a seed */ +static void +init_genrand(RandomObject *self, unsigned long s) +{ + int mti; + unsigned long *mt; + + mt = self->state; + mt[0]= s & 0xffffffffUL; + for (mti=1; mti<N; mti++) { + mt[mti] = + (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti); + /* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */ + /* In the previous versions, MSBs of the seed affect */ + /* only MSBs of the array mt[]. */ + /* 2002/01/09 modified by Makoto Matsumoto */ + mt[mti] &= 0xffffffffUL; + /* for >32 bit machines */ + } + self->index = mti; + return; +} + +/* initialize by an array with array-length */ +/* init_key is the array for initializing keys */ +/* key_length is its length */ +static PyObject * +init_by_array(RandomObject *self, unsigned long init_key[], unsigned long key_length) +{ + unsigned int i, j, k; /* was signed in the original code. RDH 12/16/2002 */ + unsigned long *mt; + + mt = self->state; + init_genrand(self, 19650218UL); + i=1; j=0; + k = (N>key_length ? N : key_length); + for (; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + + init_key[j] + j; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; j++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + if (j>=key_length) j=0; + } + for (k=N-1; k; k--) { + mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) + - i; /* non linear */ + mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ + i++; + if (i>=N) { mt[0] = mt[N-1]; i=1; } + } + + mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */ + Py_INCREF(Py_None); + return Py_None; +} + +/* + * The rest is Python-specific code, neither part of, nor derived from, the + * Twister download. + */ + +static PyObject * +random_seed(RandomObject *self, PyObject *args) +{ + PyObject *result = NULL; /* guilty until proved innocent */ + PyObject *masklower = NULL; + PyObject *thirtytwo = NULL; + PyObject *n = NULL; + unsigned long *key = NULL; + unsigned long keymax; /* # of allocated slots in key */ + unsigned long keyused; /* # of used slots in key */ + int err; + + PyObject *arg = NULL; + + if (!PyArg_UnpackTuple(args, "seed", 0, 1, &arg)) + return NULL; + + if (arg == NULL || arg == Py_None) { + time_t now; + + time(&now); + init_genrand(self, (unsigned long)now); + Py_INCREF(Py_None); + return Py_None; + } + /* If the arg is an int or long, use its absolute value; else use + * the absolute value of its hash code. + */ + if (PyInt_Check(arg) || PyLong_Check(arg)) + n = PyNumber_Absolute(arg); + else { + long hash = PyObject_Hash(arg); + if (hash == -1) + goto Done; + n = PyLong_FromUnsignedLong((unsigned long)hash); + } + if (n == NULL) + goto Done; + + /* Now split n into 32-bit chunks, from the right. Each piece is + * stored into key, which has a capacity of keymax chunks, of which + * keyused are filled. Alas, the repeated shifting makes this a + * quadratic-time algorithm; we'd really like to use + * _PyLong_AsByteArray here, but then we'd have to break into the + * long representation to figure out how big an array was needed + * in advance. + */ + keymax = 8; /* arbitrary; grows later if needed */ + keyused = 0; + key = (unsigned long *)PyMem_Malloc(keymax * sizeof(*key)); + if (key == NULL) + goto Done; + + masklower = PyLong_FromUnsignedLong(0xffffffffU); + if (masklower == NULL) + goto Done; + thirtytwo = PyInt_FromLong(32L); + if (thirtytwo == NULL) + goto Done; + while ((err=PyObject_IsTrue(n))) { + PyObject *newn; + PyObject *pychunk; + unsigned long chunk; + + if (err == -1) + goto Done; + pychunk = PyNumber_And(n, masklower); + if (pychunk == NULL) + goto Done; + chunk = PyLong_AsUnsignedLong(pychunk); + Py_DECREF(pychunk); + if (chunk == (unsigned long)-1 && PyErr_Occurred()) + goto Done; + newn = PyNumber_Rshift(n, thirtytwo); + if (newn == NULL) + goto Done; + Py_DECREF(n); + n = newn; + if (keyused >= keymax) { + unsigned long bigger = keymax << 1; + if ((bigger >> 1) != keymax) { + PyErr_NoMemory(); + goto Done; + } + key = (unsigned long *)PyMem_Realloc(key, + bigger * sizeof(*key)); + if (key == NULL) + goto Done; + keymax = bigger; + } + assert(keyused < keymax); + key[keyused++] = chunk; + } + + if (keyused == 0) + key[keyused++] = 0UL; + result = init_by_array(self, key, keyused); +Done: + Py_XDECREF(masklower); + Py_XDECREF(thirtytwo); + Py_XDECREF(n); + PyMem_Free(key); + return result; +} + +static PyObject * +random_getstate(RandomObject *self) +{ + PyObject *state; + PyObject *element; + int i; + + state = PyTuple_New(N+1); + if (state == NULL) + return NULL; + for (i=0; i<N ; i++) { + element = PyInt_FromLong((long)(self->state[i])); + if (element == NULL) + goto Fail; + PyTuple_SET_ITEM(state, i, element); + } + element = PyInt_FromLong((long)(self->index)); + if (element == NULL) + goto Fail; + PyTuple_SET_ITEM(state, i, element); + return state; + +Fail: + Py_DECREF(state); + return NULL; +} + +static PyObject * +random_setstate(RandomObject *self, PyObject *state) +{ + int i; + long element; + + if (!PyTuple_Check(state)) { + PyErr_SetString(PyExc_TypeError, + "state vector must be a tuple"); + return NULL; + } + if (PyTuple_Size(state) != N+1) { + PyErr_SetString(PyExc_ValueError, + "state vector is the wrong size"); + return NULL; + } + + for (i=0; i<N ; i++) { + element = PyInt_AsLong(PyTuple_GET_ITEM(state, i)); + if (element == -1 && PyErr_Occurred()) + return NULL; + self->state[i] = (unsigned long)element; + } + + element = PyInt_AsLong(PyTuple_GET_ITEM(state, i)); + if (element == -1 && PyErr_Occurred()) + return NULL; + self->index = (int)element; + + Py_INCREF(Py_None); + return Py_None; +} + +/* +Jumpahead should be a fast way advance the generator n-steps ahead, but +lacking a formula for that, the next best is to use n and the existing +state to create a new state far away from the original. + +The generator uses constant spaced additive feedback, so shuffling the +state elements ought to produce a state which would not be encountered +(in the near term) by calls to random(). Shuffling is normally +implemented by swapping the ith element with another element ranging +from 0 to i inclusive. That allows the element to have the possibility +of not being moved. Since the goal is to produce a new, different +state, the swap element is ranged from 0 to i-1 inclusive. This assures +that each element gets moved at least once. + +To make sure that consecutive calls to jumpahead(n) produce different +states (even in the rare case of involutory shuffles), i+1 is added to +each element at position i. Successive calls are then guaranteed to +have changing (growing) values as well as shuffled positions. + +Finally, the self->index value is set to N so that the generator itself +kicks in on the next call to random(). This assures that all results +have been through the generator and do not just reflect alterations to +the underlying state. +*/ + +static PyObject * +random_jumpahead(RandomObject *self, PyObject *n) +{ + long i, j; + PyObject *iobj; + PyObject *remobj; + unsigned long *mt, tmp; + + if (!PyInt_Check(n) && !PyLong_Check(n)) { + PyErr_Format(PyExc_TypeError, "jumpahead requires an " + "integer, not '%s'", + n->ob_type->tp_name); + return NULL; + } + + mt = self->state; + for (i = N-1; i > 1; i--) { + iobj = PyInt_FromLong(i); + if (iobj == NULL) + return NULL; + remobj = PyNumber_Remainder(n, iobj); + Py_DECREF(iobj); + if (remobj == NULL) + return NULL; + j = PyInt_AsLong(remobj); + Py_DECREF(remobj); + if (j == -1L && PyErr_Occurred()) + return NULL; + tmp = mt[i]; + mt[i] = mt[j]; + mt[j] = tmp; + } + + for (i = 0; i < N; i++) + mt[i] += i+1; + + self->index = N; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +random_getrandbits(RandomObject *self, PyObject *args) +{ + int k, i, bytes; + unsigned long r; + unsigned char *bytearray; + PyObject *result; + + if (!PyArg_ParseTuple(args, "i:getrandbits", &k)) + return NULL; + + if (k <= 0) { + PyErr_SetString(PyExc_ValueError, + "number of bits must be greater than zero"); + return NULL; + } + + bytes = ((k - 1) / 32 + 1) * 4; + bytearray = (unsigned char *)PyMem_Malloc(bytes); + if (bytearray == NULL) { + PyErr_NoMemory(); + return NULL; + } + + /* Fill-out whole words, byte-by-byte to avoid endianness issues */ + for (i=0 ; i<bytes ; i+=4, k-=32) { + r = genrand_int32(self); + if (k < 32) + r >>= (32 - k); + bytearray[i+0] = (unsigned char)r; + bytearray[i+1] = (unsigned char)(r >> 8); + bytearray[i+2] = (unsigned char)(r >> 16); + bytearray[i+3] = (unsigned char)(r >> 24); + } + + /* little endian order to match bytearray assignment order */ + result = _PyLong_FromByteArray(bytearray, bytes, 1, 0); + PyMem_Free(bytearray); + return result; +} + +static PyObject * +random_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + RandomObject *self; + PyObject *tmp; + + if (type == &Random_Type && !_PyArg_NoKeywords("Random()", kwds)) + return NULL; + + self = (RandomObject *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + tmp = random_seed(self, args); + if (tmp == NULL) { + Py_DECREF(self); + return NULL; + } + Py_DECREF(tmp); + return (PyObject *)self; +} + +static PyMethodDef random_methods[] = { + {"random", (PyCFunction)random_random, METH_NOARGS, + PyDoc_STR("random() -> x in the interval [0, 1).")}, + {"seed", (PyCFunction)random_seed, METH_VARARGS, + PyDoc_STR("seed([n]) -> None. Defaults to current time.")}, + {"getstate", (PyCFunction)random_getstate, METH_NOARGS, + PyDoc_STR("getstate() -> tuple containing the current state.")}, + {"setstate", (PyCFunction)random_setstate, METH_O, + PyDoc_STR("setstate(state) -> None. Restores generator state.")}, + {"jumpahead", (PyCFunction)random_jumpahead, METH_O, + PyDoc_STR("jumpahead(int) -> None. Create new state from " + "existing state and integer.")}, + {"getrandbits", (PyCFunction)random_getrandbits, METH_VARARGS, + PyDoc_STR("getrandbits(k) -> x. Generates a long int with " + "k random bits.")}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(random_doc, +"Random() -> create a random number generator with its own internal state."); + +static PyTypeObject Random_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_random.Random", /*tp_name*/ + sizeof(RandomObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + random_doc, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + random_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + random_new, /*tp_new*/ + _PyObject_Del, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +PyDoc_STRVAR(module_doc, +"Module implements the Mersenne Twister random number generator."); + +PyMODINIT_FUNC +init_random(void) +{ + PyObject *m; + + if (PyType_Ready(&Random_Type) < 0) + return; + m = Py_InitModule3("_random", NULL, module_doc); + if (m == NULL) + return; + Py_INCREF(&Random_Type); + PyModule_AddObject(m, "Random", (PyObject *)&Random_Type); +} diff --git a/sys/src/cmd/python/Modules/_sqlite/cache.c b/sys/src/cmd/python/Modules/_sqlite/cache.c new file mode 100644 index 000000000..6962695c8 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/cache.c @@ -0,0 +1,375 @@ +/* cache .c - a LRU cache + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "cache.h" +#include <limits.h> + +/* only used internally */ +Node* new_node(PyObject* key, PyObject* data) +{ + Node* node; + + node = (Node*) (NodeType.tp_alloc(&NodeType, 0)); + if (!node) { + return NULL; + } + + Py_INCREF(key); + node->key = key; + + Py_INCREF(data); + node->data = data; + + node->prev = NULL; + node->next = NULL; + + return node; +} + +void node_dealloc(Node* self) +{ + Py_DECREF(self->key); + Py_DECREF(self->data); + + self->ob_type->tp_free((PyObject*)self); +} + +int cache_init(Cache* self, PyObject* args, PyObject* kwargs) +{ + PyObject* factory; + int size = 10; + + self->factory = NULL; + + if (!PyArg_ParseTuple(args, "O|i", &factory, &size)) { + return -1; + } + + /* minimum cache size is 5 entries */ + if (size < 5) { + size = 5; + } + self->size = size; + self->first = NULL; + self->last = NULL; + + self->mapping = PyDict_New(); + if (!self->mapping) { + return -1; + } + + Py_INCREF(factory); + self->factory = factory; + + self->decref_factory = 1; + + return 0; +} + +void cache_dealloc(Cache* self) +{ + Node* node; + Node* delete_node; + + if (!self->factory) { + /* constructor failed, just get out of here */ + return; + } + + /* iterate over all nodes and deallocate them */ + node = self->first; + while (node) { + delete_node = node; + node = node->next; + Py_DECREF(delete_node); + } + + if (self->decref_factory) { + Py_DECREF(self->factory); + } + Py_DECREF(self->mapping); + + self->ob_type->tp_free((PyObject*)self); +} + +PyObject* cache_get(Cache* self, PyObject* args) +{ + PyObject* key = args; + Node* node; + Node* ptr; + PyObject* data; + + node = (Node*)PyDict_GetItem(self->mapping, key); + if (node) { + /* an entry for this key already exists in the cache */ + + /* increase usage counter of the node found */ + if (node->count < LONG_MAX) { + node->count++; + } + + /* if necessary, reorder entries in the cache by swapping positions */ + if (node->prev && node->count > node->prev->count) { + ptr = node->prev; + + while (ptr->prev && node->count > ptr->prev->count) { + ptr = ptr->prev; + } + + if (node->next) { + node->next->prev = node->prev; + } else { + self->last = node->prev; + } + if (node->prev) { + node->prev->next = node->next; + } + if (ptr->prev) { + ptr->prev->next = node; + } else { + self->first = node; + } + + node->next = ptr; + node->prev = ptr->prev; + if (!node->prev) { + self->first = node; + } + ptr->prev = node; + } + } else { + /* There is no entry for this key in the cache, yet. We'll insert a new + * entry in the cache, and make space if necessary by throwing the + * least used item out of the cache. */ + + if (PyDict_Size(self->mapping) == self->size) { + if (self->last) { + node = self->last; + + if (PyDict_DelItem(self->mapping, self->last->key) != 0) { + return NULL; + } + + if (node->prev) { + node->prev->next = NULL; + } + self->last = node->prev; + node->prev = NULL; + + Py_DECREF(node); + } + } + + data = PyObject_CallFunction(self->factory, "O", key); + + if (!data) { + return NULL; + } + + node = new_node(key, data); + if (!node) { + return NULL; + } + node->prev = self->last; + + Py_DECREF(data); + + if (PyDict_SetItem(self->mapping, key, (PyObject*)node) != 0) { + Py_DECREF(node); + return NULL; + } + + if (self->last) { + self->last->next = node; + } else { + self->first = node; + } + self->last = node; + } + + Py_INCREF(node->data); + return node->data; +} + +PyObject* cache_display(Cache* self, PyObject* args) +{ + Node* ptr; + PyObject* prevkey; + PyObject* nextkey; + PyObject* fmt_args; + PyObject* template; + PyObject* display_str; + + ptr = self->first; + + while (ptr) { + if (ptr->prev) { + prevkey = ptr->prev->key; + } else { + prevkey = Py_None; + } + Py_INCREF(prevkey); + + if (ptr->next) { + nextkey = ptr->next->key; + } else { + nextkey = Py_None; + } + Py_INCREF(nextkey); + + fmt_args = Py_BuildValue("OOO", prevkey, ptr->key, nextkey); + if (!fmt_args) { + return NULL; + } + template = PyString_FromString("%s <- %s ->%s\n"); + if (!template) { + return NULL; + } + display_str = PyString_Format(template, fmt_args); + Py_DECREF(template); + Py_DECREF(fmt_args); + if (!display_str) { + return NULL; + } + PyObject_Print(display_str, stdout, Py_PRINT_RAW); + Py_DECREF(display_str); + + Py_DECREF(prevkey); + Py_DECREF(nextkey); + + ptr = ptr->next; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef cache_methods[] = { + {"get", (PyCFunction)cache_get, METH_O, + PyDoc_STR("Gets an entry from the cache or calls the factory function to produce one.")}, + {"display", (PyCFunction)cache_display, METH_NOARGS, + PyDoc_STR("For debugging only.")}, + {NULL, NULL} +}; + +PyTypeObject NodeType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + MODULE_NAME "Node", /* tp_name */ + sizeof(Node), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)node_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +PyTypeObject CacheType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + MODULE_NAME ".Cache", /* tp_name */ + sizeof(Cache), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)cache_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + cache_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)cache_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +extern int cache_setup_types(void) +{ + int rc; + + NodeType.tp_new = PyType_GenericNew; + CacheType.tp_new = PyType_GenericNew; + + rc = PyType_Ready(&NodeType); + if (rc < 0) { + return rc; + } + + rc = PyType_Ready(&CacheType); + return rc; +} diff --git a/sys/src/cmd/python/Modules/_sqlite/cache.h b/sys/src/cmd/python/Modules/_sqlite/cache.h new file mode 100644 index 000000000..1f13907b7 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/cache.h @@ -0,0 +1,73 @@ +/* cache.h - definitions for the LRU cache + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_CACHE_H +#define PYSQLITE_CACHE_H +#include "Python.h" + +/* The LRU cache is implemented as a combination of a doubly-linked with a + * dictionary. The list items are of type 'Node' and the dictionary has the + * nodes as values. */ + +typedef struct _Node +{ + PyObject_HEAD + PyObject* key; + PyObject* data; + long count; + struct _Node* prev; + struct _Node* next; +} Node; + +typedef struct +{ + PyObject_HEAD + int size; + + /* a dictionary mapping keys to Node entries */ + PyObject* mapping; + + /* the factory callable */ + PyObject* factory; + + Node* first; + Node* last; + + /* if set, decrement the factory function when the Cache is deallocated. + * this is almost always desirable, but not in the pysqlite context */ + int decref_factory; +} Cache; + +extern PyTypeObject NodeType; +extern PyTypeObject CacheType; + +int node_init(Node* self, PyObject* args, PyObject* kwargs); +void node_dealloc(Node* self); + +int cache_init(Cache* self, PyObject* args, PyObject* kwargs); +void cache_dealloc(Cache* self); +PyObject* cache_get(Cache* self, PyObject* args); + +int cache_setup_types(void); + +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/connection.c b/sys/src/cmd/python/Modules/_sqlite/connection.c new file mode 100644 index 000000000..703af15fa --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/connection.c @@ -0,0 +1,1255 @@ +/* connection.c - the connection type + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "cache.h" +#include "module.h" +#include "connection.h" +#include "statement.h" +#include "cursor.h" +#include "prepare_protocol.h" +#include "util.h" +#include "sqlitecompat.h" + +#include "pythread.h" + +static int connection_set_isolation_level(Connection* self, PyObject* isolation_level); + + +void _sqlite3_result_error(sqlite3_context* ctx, const char* errmsg, int len) +{ + /* in older SQLite versions, calling sqlite3_result_error in callbacks + * triggers a bug in SQLite that leads either to irritating results or + * segfaults, depending on the SQLite version */ +#if SQLITE_VERSION_NUMBER >= 3003003 + sqlite3_result_error(ctx, errmsg, len); +#else + PyErr_SetString(OperationalError, errmsg); +#endif +} + +int connection_init(Connection* self, PyObject* args, PyObject* kwargs) +{ + static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", NULL, NULL}; + + char* database; + int detect_types = 0; + PyObject* isolation_level = NULL; + PyObject* factory = NULL; + int check_same_thread = 1; + int cached_statements = 100; + double timeout = 5.0; + int rc; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist, + &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements)) + { + return -1; + } + + self->begin_statement = NULL; + + self->statement_cache = NULL; + self->statements = NULL; + + Py_INCREF(Py_None); + self->row_factory = Py_None; + + Py_INCREF(&PyUnicode_Type); + self->text_factory = (PyObject*)&PyUnicode_Type; + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_open(database, &self->db); + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { + _seterror(self->db); + return -1; + } + + if (!isolation_level) { + isolation_level = PyString_FromString(""); + if (!isolation_level) { + return -1; + } + } else { + Py_INCREF(isolation_level); + } + self->isolation_level = NULL; + connection_set_isolation_level(self, isolation_level); + Py_DECREF(isolation_level); + + self->statement_cache = (Cache*)PyObject_CallFunction((PyObject*)&CacheType, "Oi", self, cached_statements); + if (PyErr_Occurred()) { + return -1; + } + + self->statements = PyList_New(0); + if (!self->statements) { + return -1; + } + self->created_statements = 0; + + /* By default, the Cache class INCREFs the factory in its initializer, and + * decrefs it in its deallocator method. Since this would create a circular + * reference here, we're breaking it by decrementing self, and telling the + * cache class to not decref the factory (self) in its deallocator. + */ + self->statement_cache->decref_factory = 0; + Py_DECREF(self); + + self->inTransaction = 0; + self->detect_types = detect_types; + self->timeout = timeout; + (void)sqlite3_busy_timeout(self->db, (int)(timeout*1000)); + + self->thread_ident = PyThread_get_thread_ident(); + self->check_same_thread = check_same_thread; + + self->function_pinboard = PyDict_New(); + if (!self->function_pinboard) { + return -1; + } + + self->collations = PyDict_New(); + if (!self->collations) { + return -1; + } + + self->Warning = Warning; + self->Error = Error; + self->InterfaceError = InterfaceError; + self->DatabaseError = DatabaseError; + self->DataError = DataError; + self->OperationalError = OperationalError; + self->IntegrityError = IntegrityError; + self->InternalError = InternalError; + self->ProgrammingError = ProgrammingError; + self->NotSupportedError = NotSupportedError; + + return 0; +} + +/* Empty the entire statement cache of this connection */ +void flush_statement_cache(Connection* self) +{ + Node* node; + Statement* statement; + + node = self->statement_cache->first; + + while (node) { + statement = (Statement*)(node->data); + (void)statement_finalize(statement); + node = node->next; + } + + Py_DECREF(self->statement_cache); + self->statement_cache = (Cache*)PyObject_CallFunction((PyObject*)&CacheType, "O", self); + Py_DECREF(self); + self->statement_cache->decref_factory = 0; +} + +void reset_all_statements(Connection* self) +{ + int i; + PyObject* weakref; + PyObject* statement; + + for (i = 0; i < PyList_Size(self->statements); i++) { + weakref = PyList_GetItem(self->statements, i); + statement = PyWeakref_GetObject(weakref); + if (statement != Py_None) { + (void)statement_reset((Statement*)statement); + } + } +} + +void connection_dealloc(Connection* self) +{ + Py_XDECREF(self->statement_cache); + + /* Clean up if user has not called .close() explicitly. */ + if (self->db) { + Py_BEGIN_ALLOW_THREADS + sqlite3_close(self->db); + Py_END_ALLOW_THREADS + } + + if (self->begin_statement) { + PyMem_Free(self->begin_statement); + } + Py_XDECREF(self->isolation_level); + Py_XDECREF(self->function_pinboard); + Py_XDECREF(self->row_factory); + Py_XDECREF(self->text_factory); + Py_XDECREF(self->collations); + Py_XDECREF(self->statements); + + self->ob_type->tp_free((PyObject*)self); +} + +PyObject* connection_cursor(Connection* self, PyObject* args, PyObject* kwargs) +{ + static char *kwlist[] = {"factory", NULL, NULL}; + PyObject* factory = NULL; + PyObject* cursor; + + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, + &factory)) { + return NULL; + } + + if (!check_thread(self) || !check_connection(self)) { + return NULL; + } + + if (factory == NULL) { + factory = (PyObject*)&CursorType; + } + + cursor = PyObject_CallFunction(factory, "O", self); + + if (cursor && self->row_factory != Py_None) { + Py_XDECREF(((Cursor*)cursor)->row_factory); + Py_INCREF(self->row_factory); + ((Cursor*)cursor)->row_factory = self->row_factory; + } + + return cursor; +} + +PyObject* connection_close(Connection* self, PyObject* args) +{ + int rc; + + if (!check_thread(self)) { + return NULL; + } + + flush_statement_cache(self); + + if (self->db) { + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_close(self->db); + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { + _seterror(self->db); + return NULL; + } else { + self->db = NULL; + } + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* + * Checks if a connection object is usable (i. e. not closed). + * + * 0 => error; 1 => ok + */ +int check_connection(Connection* con) +{ + if (!con->db) { + PyErr_SetString(ProgrammingError, "Cannot operate on a closed database."); + return 0; + } else { + return 1; + } +} + +PyObject* _connection_begin(Connection* self) +{ + int rc; + const char* tail; + sqlite3_stmt* statement; + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_prepare(self->db, self->begin_statement, -1, &statement, &tail); + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { + _seterror(self->db); + goto error; + } + + rc = _sqlite_step_with_busyhandler(statement, self); + if (rc == SQLITE_DONE) { + self->inTransaction = 1; + } else { + _seterror(self->db); + } + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_finalize(statement); + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK && !PyErr_Occurred()) { + _seterror(self->db); + } + +error: + if (PyErr_Occurred()) { + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} + +PyObject* connection_commit(Connection* self, PyObject* args) +{ + int rc; + const char* tail; + sqlite3_stmt* statement; + + if (!check_thread(self) || !check_connection(self)) { + return NULL; + } + + if (self->inTransaction) { + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_prepare(self->db, "COMMIT", -1, &statement, &tail); + Py_END_ALLOW_THREADS + if (rc != SQLITE_OK) { + _seterror(self->db); + goto error; + } + + rc = _sqlite_step_with_busyhandler(statement, self); + if (rc == SQLITE_DONE) { + self->inTransaction = 0; + } else { + _seterror(self->db); + } + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_finalize(statement); + Py_END_ALLOW_THREADS + if (rc != SQLITE_OK && !PyErr_Occurred()) { + _seterror(self->db); + } + + } + +error: + if (PyErr_Occurred()) { + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} + +PyObject* connection_rollback(Connection* self, PyObject* args) +{ + int rc; + const char* tail; + sqlite3_stmt* statement; + + if (!check_thread(self) || !check_connection(self)) { + return NULL; + } + + if (self->inTransaction) { + reset_all_statements(self); + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_prepare(self->db, "ROLLBACK", -1, &statement, &tail); + Py_END_ALLOW_THREADS + if (rc != SQLITE_OK) { + _seterror(self->db); + goto error; + } + + rc = _sqlite_step_with_busyhandler(statement, self); + if (rc == SQLITE_DONE) { + self->inTransaction = 0; + } else { + _seterror(self->db); + } + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_finalize(statement); + Py_END_ALLOW_THREADS + if (rc != SQLITE_OK && !PyErr_Occurred()) { + _seterror(self->db); + } + + } + +error: + if (PyErr_Occurred()) { + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} + +void _set_result(sqlite3_context* context, PyObject* py_val) +{ + long longval; + const char* buffer; + Py_ssize_t buflen; + PyObject* stringval; + + if ((!py_val) || PyErr_Occurred()) { + sqlite3_result_null(context); + } else if (py_val == Py_None) { + sqlite3_result_null(context); + } else if (PyInt_Check(py_val)) { + longval = PyInt_AsLong(py_val); + sqlite3_result_int64(context, (PY_LONG_LONG)longval); + } else if (PyFloat_Check(py_val)) { + sqlite3_result_double(context, PyFloat_AsDouble(py_val)); + } else if (PyBuffer_Check(py_val)) { + if (PyObject_AsCharBuffer(py_val, &buffer, &buflen) != 0) { + PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); + } else { + sqlite3_result_blob(context, buffer, buflen, SQLITE_TRANSIENT); + } + } else if (PyString_Check(py_val)) { + sqlite3_result_text(context, PyString_AsString(py_val), -1, SQLITE_TRANSIENT); + } else if (PyUnicode_Check(py_val)) { + stringval = PyUnicode_AsUTF8String(py_val); + if (stringval) { + sqlite3_result_text(context, PyString_AsString(stringval), -1, SQLITE_TRANSIENT); + Py_DECREF(stringval); + } + } else { + /* TODO: raise error */ + } +} + +PyObject* _build_py_params(sqlite3_context *context, int argc, sqlite3_value** argv) +{ + PyObject* args; + int i; + sqlite3_value* cur_value; + PyObject* cur_py_value; + const char* val_str; + PY_LONG_LONG val_int; + Py_ssize_t buflen; + void* raw_buffer; + + args = PyTuple_New(argc); + if (!args) { + return NULL; + } + + for (i = 0; i < argc; i++) { + cur_value = argv[i]; + switch (sqlite3_value_type(argv[i])) { + case SQLITE_INTEGER: + val_int = sqlite3_value_int64(cur_value); + cur_py_value = PyInt_FromLong((long)val_int); + break; + case SQLITE_FLOAT: + cur_py_value = PyFloat_FromDouble(sqlite3_value_double(cur_value)); + break; + case SQLITE_TEXT: + val_str = (const char*)sqlite3_value_text(cur_value); + cur_py_value = PyUnicode_DecodeUTF8(val_str, strlen(val_str), NULL); + /* TODO: have a way to show errors here */ + if (!cur_py_value) { + PyErr_Clear(); + Py_INCREF(Py_None); + cur_py_value = Py_None; + } + break; + case SQLITE_BLOB: + buflen = sqlite3_value_bytes(cur_value); + cur_py_value = PyBuffer_New(buflen); + if (!cur_py_value) { + break; + } + if (PyObject_AsWriteBuffer(cur_py_value, &raw_buffer, &buflen)) { + Py_DECREF(cur_py_value); + cur_py_value = NULL; + break; + } + memcpy(raw_buffer, sqlite3_value_blob(cur_value), buflen); + break; + case SQLITE_NULL: + default: + Py_INCREF(Py_None); + cur_py_value = Py_None; + } + + if (!cur_py_value) { + Py_DECREF(args); + return NULL; + } + + PyTuple_SetItem(args, i, cur_py_value); + + } + + return args; +} + +void _func_callback(sqlite3_context* context, int argc, sqlite3_value** argv) +{ + PyObject* args; + PyObject* py_func; + PyObject* py_retval = NULL; + + PyGILState_STATE threadstate; + + threadstate = PyGILState_Ensure(); + + py_func = (PyObject*)sqlite3_user_data(context); + + args = _build_py_params(context, argc, argv); + if (args) { + py_retval = PyObject_CallObject(py_func, args); + Py_DECREF(args); + } + + if (py_retval) { + _set_result(context, py_retval); + Py_DECREF(py_retval); + } else { + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + _sqlite3_result_error(context, "user-defined function raised exception", -1); + } + + PyGILState_Release(threadstate); +} + +static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** params) +{ + PyObject* args; + PyObject* function_result = NULL; + PyObject* aggregate_class; + PyObject** aggregate_instance; + PyObject* stepmethod = NULL; + + PyGILState_STATE threadstate; + + threadstate = PyGILState_Ensure(); + + aggregate_class = (PyObject*)sqlite3_user_data(context); + + aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*)); + + if (*aggregate_instance == 0) { + *aggregate_instance = PyObject_CallFunction(aggregate_class, ""); + + if (PyErr_Occurred()) { + *aggregate_instance = 0; + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + _sqlite3_result_error(context, "user-defined aggregate's '__init__' method raised error", -1); + goto error; + } + } + + stepmethod = PyObject_GetAttrString(*aggregate_instance, "step"); + if (!stepmethod) { + goto error; + } + + args = _build_py_params(context, argc, params); + if (!args) { + goto error; + } + + function_result = PyObject_CallObject(stepmethod, args); + Py_DECREF(args); + + if (!function_result) { + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + _sqlite3_result_error(context, "user-defined aggregate's 'step' method raised error", -1); + } + +error: + Py_XDECREF(stepmethod); + Py_XDECREF(function_result); + + PyGILState_Release(threadstate); +} + +void _final_callback(sqlite3_context* context) +{ + PyObject* function_result = NULL; + PyObject** aggregate_instance; + PyObject* aggregate_class; + + PyGILState_STATE threadstate; + + threadstate = PyGILState_Ensure(); + + aggregate_class = (PyObject*)sqlite3_user_data(context); + + aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*)); + if (!*aggregate_instance) { + /* this branch is executed if there was an exception in the aggregate's + * __init__ */ + + goto error; + } + + function_result = PyObject_CallMethod(*aggregate_instance, "finalize", ""); + if (!function_result) { + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + _sqlite3_result_error(context, "user-defined aggregate's 'finalize' method raised error", -1); + } else { + _set_result(context, function_result); + } + +error: + Py_XDECREF(*aggregate_instance); + Py_XDECREF(function_result); + + PyGILState_Release(threadstate); +} + +void _drop_unused_statement_references(Connection* self) +{ + PyObject* new_list; + PyObject* weakref; + int i; + + /* we only need to do this once in a while */ + if (self->created_statements++ < 200) { + return; + } + + self->created_statements = 0; + + new_list = PyList_New(0); + if (!new_list) { + return; + } + + for (i = 0; i < PyList_Size(self->statements); i++) { + weakref = PyList_GetItem(self->statements, i); + if (PyWeakref_GetObject(weakref) != Py_None) { + if (PyList_Append(new_list, weakref) != 0) { + Py_DECREF(new_list); + return; + } + } + } + + Py_DECREF(self->statements); + self->statements = new_list; +} + +PyObject* connection_create_function(Connection* self, PyObject* args, PyObject* kwargs) +{ + static char *kwlist[] = {"name", "narg", "func", NULL, NULL}; + + PyObject* func; + char* name; + int narg; + int rc; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO", kwlist, + &name, &narg, &func)) + { + return NULL; + } + + rc = sqlite3_create_function(self->db, name, narg, SQLITE_UTF8, (void*)func, _func_callback, NULL, NULL); + + if (rc != SQLITE_OK) { + /* Workaround for SQLite bug: no error code or string is available here */ + PyErr_SetString(OperationalError, "Error creating function"); + return NULL; + } else { + PyDict_SetItem(self->function_pinboard, func, Py_None); + + Py_INCREF(Py_None); + return Py_None; + } +} + +PyObject* connection_create_aggregate(Connection* self, PyObject* args, PyObject* kwargs) +{ + PyObject* aggregate_class; + + int n_arg; + char* name; + static char *kwlist[] = { "name", "n_arg", "aggregate_class", NULL }; + int rc; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO:create_aggregate", + kwlist, &name, &n_arg, &aggregate_class)) { + return NULL; + } + + rc = sqlite3_create_function(self->db, name, n_arg, SQLITE_UTF8, (void*)aggregate_class, 0, &_step_callback, &_final_callback); + if (rc != SQLITE_OK) { + /* Workaround for SQLite bug: no error code or string is available here */ + PyErr_SetString(OperationalError, "Error creating aggregate"); + return NULL; + } else { + PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None); + + Py_INCREF(Py_None); + return Py_None; + } +} + +int _authorizer_callback(void* user_arg, int action, const char* arg1, const char* arg2 , const char* dbname, const char* access_attempt_source) +{ + PyObject *ret; + int rc; + PyGILState_STATE gilstate; + + gilstate = PyGILState_Ensure(); + ret = PyObject_CallFunction((PyObject*)user_arg, "issss", action, arg1, arg2, dbname, access_attempt_source); + + if (!ret) { + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + + rc = SQLITE_DENY; + } else { + if (PyInt_Check(ret)) { + rc = (int)PyInt_AsLong(ret); + } else { + rc = SQLITE_DENY; + } + Py_DECREF(ret); + } + + PyGILState_Release(gilstate); + return rc; +} + +PyObject* connection_set_authorizer(Connection* self, PyObject* args, PyObject* kwargs) +{ + PyObject* authorizer_cb; + + static char *kwlist[] = { "authorizer_callback", NULL }; + int rc; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_authorizer", + kwlist, &authorizer_cb)) { + return NULL; + } + + rc = sqlite3_set_authorizer(self->db, _authorizer_callback, (void*)authorizer_cb); + + if (rc != SQLITE_OK) { + PyErr_SetString(OperationalError, "Error setting authorizer callback"); + return NULL; + } else { + PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None); + + Py_INCREF(Py_None); + return Py_None; + } +} + +int check_thread(Connection* self) +{ + if (self->check_same_thread) { + if (PyThread_get_thread_ident() != self->thread_ident) { + PyErr_Format(ProgrammingError, + "SQLite objects created in a thread can only be used in that same thread." + "The object was created in thread id %ld and this is thread id %ld", + self->thread_ident, PyThread_get_thread_ident()); + return 0; + } + + } + + return 1; +} + +static PyObject* connection_get_isolation_level(Connection* self, void* unused) +{ + Py_INCREF(self->isolation_level); + return self->isolation_level; +} + +static PyObject* connection_get_total_changes(Connection* self, void* unused) +{ + if (!check_connection(self)) { + return NULL; + } else { + return Py_BuildValue("i", sqlite3_total_changes(self->db)); + } +} + +static int connection_set_isolation_level(Connection* self, PyObject* isolation_level) +{ + PyObject* res; + PyObject* begin_statement; + + Py_XDECREF(self->isolation_level); + + if (self->begin_statement) { + PyMem_Free(self->begin_statement); + self->begin_statement = NULL; + } + + if (isolation_level == Py_None) { + Py_INCREF(Py_None); + self->isolation_level = Py_None; + + res = connection_commit(self, NULL); + if (!res) { + return -1; + } + Py_DECREF(res); + + self->inTransaction = 0; + } else { + Py_INCREF(isolation_level); + self->isolation_level = isolation_level; + + begin_statement = PyString_FromString("BEGIN "); + if (!begin_statement) { + return -1; + } + PyString_Concat(&begin_statement, isolation_level); + if (!begin_statement) { + return -1; + } + + self->begin_statement = PyMem_Malloc(PyString_Size(begin_statement) + 2); + if (!self->begin_statement) { + return -1; + } + + strcpy(self->begin_statement, PyString_AsString(begin_statement)); + Py_DECREF(begin_statement); + } + + return 0; +} + +PyObject* connection_call(Connection* self, PyObject* args, PyObject* kwargs) +{ + PyObject* sql; + Statement* statement; + PyObject* weakref; + int rc; + + if (!PyArg_ParseTuple(args, "O", &sql)) { + return NULL; + } + + _drop_unused_statement_references(self); + + statement = PyObject_New(Statement, &StatementType); + if (!statement) { + return NULL; + } + + rc = statement_create(statement, self, sql); + + if (rc != SQLITE_OK) { + if (rc == PYSQLITE_TOO_MUCH_SQL) { + PyErr_SetString(Warning, "You can only execute one statement at a time."); + } else if (rc == PYSQLITE_SQL_WRONG_TYPE) { + PyErr_SetString(Warning, "SQL is of wrong type. Must be string or unicode."); + } else { + _seterror(self->db); + } + + Py_DECREF(statement); + statement = 0; + } else { + weakref = PyWeakref_NewRef((PyObject*)statement, NULL); + if (!weakref) { + Py_DECREF(statement); + statement = 0; + goto error; + } + + if (PyList_Append(self->statements, weakref) != 0) { + Py_DECREF(weakref); + statement = 0; + goto error; + } + + Py_DECREF(weakref); + } + +error: + return (PyObject*)statement; +} + +PyObject* connection_execute(Connection* self, PyObject* args, PyObject* kwargs) +{ + PyObject* cursor = 0; + PyObject* result = 0; + PyObject* method = 0; + + cursor = PyObject_CallMethod((PyObject*)self, "cursor", ""); + if (!cursor) { + goto error; + } + + method = PyObject_GetAttrString(cursor, "execute"); + if (!method) { + Py_DECREF(cursor); + cursor = 0; + goto error; + } + + result = PyObject_CallObject(method, args); + if (!result) { + Py_DECREF(cursor); + cursor = 0; + } + +error: + Py_XDECREF(result); + Py_XDECREF(method); + + return cursor; +} + +PyObject* connection_executemany(Connection* self, PyObject* args, PyObject* kwargs) +{ + PyObject* cursor = 0; + PyObject* result = 0; + PyObject* method = 0; + + cursor = PyObject_CallMethod((PyObject*)self, "cursor", ""); + if (!cursor) { + goto error; + } + + method = PyObject_GetAttrString(cursor, "executemany"); + if (!method) { + Py_DECREF(cursor); + cursor = 0; + goto error; + } + + result = PyObject_CallObject(method, args); + if (!result) { + Py_DECREF(cursor); + cursor = 0; + } + +error: + Py_XDECREF(result); + Py_XDECREF(method); + + return cursor; +} + +PyObject* connection_executescript(Connection* self, PyObject* args, PyObject* kwargs) +{ + PyObject* cursor = 0; + PyObject* result = 0; + PyObject* method = 0; + + cursor = PyObject_CallMethod((PyObject*)self, "cursor", ""); + if (!cursor) { + goto error; + } + + method = PyObject_GetAttrString(cursor, "executescript"); + if (!method) { + Py_DECREF(cursor); + cursor = 0; + goto error; + } + + result = PyObject_CallObject(method, args); + if (!result) { + Py_DECREF(cursor); + cursor = 0; + } + +error: + Py_XDECREF(result); + Py_XDECREF(method); + + return cursor; +} + +/* ------------------------- COLLATION CODE ------------------------ */ + +static int +collation_callback( + void* context, + int text1_length, const void* text1_data, + int text2_length, const void* text2_data) +{ + PyObject* callback = (PyObject*)context; + PyObject* string1 = 0; + PyObject* string2 = 0; + PyGILState_STATE gilstate; + + PyObject* retval = NULL; + int result = 0; + + gilstate = PyGILState_Ensure(); + + if (PyErr_Occurred()) { + goto finally; + } + + string1 = PyString_FromStringAndSize((const char*)text1_data, text1_length); + string2 = PyString_FromStringAndSize((const char*)text2_data, text2_length); + + if (!string1 || !string2) { + goto finally; /* failed to allocate strings */ + } + + retval = PyObject_CallFunctionObjArgs(callback, string1, string2, NULL); + + if (!retval) { + /* execution failed */ + goto finally; + } + + result = PyInt_AsLong(retval); + if (PyErr_Occurred()) { + result = 0; + } + +finally: + Py_XDECREF(string1); + Py_XDECREF(string2); + Py_XDECREF(retval); + + PyGILState_Release(gilstate); + + return result; +} + +static PyObject * +connection_interrupt(Connection* self, PyObject* args) +{ + PyObject* retval = NULL; + + if (!check_connection(self)) { + goto finally; + } + + sqlite3_interrupt(self->db); + + Py_INCREF(Py_None); + retval = Py_None; + +finally: + return retval; +} + +static PyObject * +connection_create_collation(Connection* self, PyObject* args) +{ + PyObject* callable; + PyObject* uppercase_name = 0; + PyObject* name; + PyObject* retval; + char* chk; + int rc; + + if (!check_thread(self) || !check_connection(self)) { + goto finally; + } + + if (!PyArg_ParseTuple(args, "O!O:create_collation(name, callback)", &PyString_Type, &name, &callable)) { + goto finally; + } + + uppercase_name = PyObject_CallMethod(name, "upper", ""); + if (!uppercase_name) { + goto finally; + } + + chk = PyString_AsString(uppercase_name); + while (*chk) { + if ((*chk >= '0' && *chk <= '9') + || (*chk >= 'A' && *chk <= 'Z') + || (*chk == '_')) + { + chk++; + } else { + PyErr_SetString(ProgrammingError, "invalid character in collation name"); + goto finally; + } + } + + if (callable != Py_None && !PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + goto finally; + } + + if (callable != Py_None) { + PyDict_SetItem(self->collations, uppercase_name, callable); + } else { + PyDict_DelItem(self->collations, uppercase_name); + } + + rc = sqlite3_create_collation(self->db, + PyString_AsString(uppercase_name), + SQLITE_UTF8, + (callable != Py_None) ? callable : NULL, + (callable != Py_None) ? collation_callback : NULL); + if (rc != SQLITE_OK) { + PyDict_DelItem(self->collations, uppercase_name); + _seterror(self->db); + goto finally; + } + +finally: + Py_XDECREF(uppercase_name); + + if (PyErr_Occurred()) { + retval = NULL; + } else { + Py_INCREF(Py_None); + retval = Py_None; + } + + return retval; +} + +static char connection_doc[] = +PyDoc_STR("SQLite database connection object."); + +static PyGetSetDef connection_getset[] = { + {"isolation_level", (getter)connection_get_isolation_level, (setter)connection_set_isolation_level}, + {"total_changes", (getter)connection_get_total_changes, (setter)0}, + {NULL} +}; + +static PyMethodDef connection_methods[] = { + {"cursor", (PyCFunction)connection_cursor, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("Return a cursor for the connection.")}, + {"close", (PyCFunction)connection_close, METH_NOARGS, + PyDoc_STR("Closes the connection.")}, + {"commit", (PyCFunction)connection_commit, METH_NOARGS, + PyDoc_STR("Commit the current transaction.")}, + {"rollback", (PyCFunction)connection_rollback, METH_NOARGS, + PyDoc_STR("Roll back the current transaction.")}, + {"create_function", (PyCFunction)connection_create_function, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("Creates a new function. Non-standard.")}, + {"create_aggregate", (PyCFunction)connection_create_aggregate, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("Creates a new aggregate. Non-standard.")}, + {"set_authorizer", (PyCFunction)connection_set_authorizer, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("Sets authorizer callback. Non-standard.")}, + {"execute", (PyCFunction)connection_execute, METH_VARARGS, + PyDoc_STR("Executes a SQL statement. Non-standard.")}, + {"executemany", (PyCFunction)connection_executemany, METH_VARARGS, + PyDoc_STR("Repeatedly executes a SQL statement. Non-standard.")}, + {"executescript", (PyCFunction)connection_executescript, METH_VARARGS, + PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")}, + {"create_collation", (PyCFunction)connection_create_collation, METH_VARARGS, + PyDoc_STR("Creates a collation function. Non-standard.")}, + {"interrupt", (PyCFunction)connection_interrupt, METH_NOARGS, + PyDoc_STR("Abort any pending database operation. Non-standard.")}, + {NULL, NULL} +}; + +static struct PyMemberDef connection_members[] = +{ + {"Warning", T_OBJECT, offsetof(Connection, Warning), RO}, + {"Error", T_OBJECT, offsetof(Connection, Error), RO}, + {"InterfaceError", T_OBJECT, offsetof(Connection, InterfaceError), RO}, + {"DatabaseError", T_OBJECT, offsetof(Connection, DatabaseError), RO}, + {"DataError", T_OBJECT, offsetof(Connection, DataError), RO}, + {"OperationalError", T_OBJECT, offsetof(Connection, OperationalError), RO}, + {"IntegrityError", T_OBJECT, offsetof(Connection, IntegrityError), RO}, + {"InternalError", T_OBJECT, offsetof(Connection, InternalError), RO}, + {"ProgrammingError", T_OBJECT, offsetof(Connection, ProgrammingError), RO}, + {"NotSupportedError", T_OBJECT, offsetof(Connection, NotSupportedError), RO}, + {"row_factory", T_OBJECT, offsetof(Connection, row_factory)}, + {"text_factory", T_OBJECT, offsetof(Connection, text_factory)}, + {NULL} +}; + +PyTypeObject ConnectionType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + MODULE_NAME ".Connection", /* tp_name */ + sizeof(Connection), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)connection_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)connection_call, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + connection_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + connection_methods, /* tp_methods */ + connection_members, /* tp_members */ + connection_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)connection_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +extern int connection_setup_types(void) +{ + ConnectionType.tp_new = PyType_GenericNew; + return PyType_Ready(&ConnectionType); +} diff --git a/sys/src/cmd/python/Modules/_sqlite/connection.h b/sys/src/cmd/python/Modules/_sqlite/connection.h new file mode 100644 index 000000000..8f4d36e1a --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/connection.h @@ -0,0 +1,129 @@ +/* connection.h - definitions for the connection type + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_CONNECTION_H +#define PYSQLITE_CONNECTION_H +#include "Python.h" +#include "pythread.h" +#include "structmember.h" + +#include "cache.h" +#include "module.h" + +#include "sqlite3.h" + +typedef struct +{ + PyObject_HEAD + sqlite3* db; + + /* 1 if we are currently within a transaction, i. e. if a BEGIN has been + * issued */ + int inTransaction; + + /* the type detection mode. Only 0, PARSE_DECLTYPES, PARSE_COLNAMES or a + * bitwise combination thereof makes sense */ + int detect_types; + + /* the timeout value in seconds for database locks */ + double timeout; + + /* for internal use in the timeout handler: when did the timeout handler + * first get called with count=0? */ + double timeout_started; + + /* None for autocommit, otherwise a PyString with the isolation level */ + PyObject* isolation_level; + + /* NULL for autocommit, otherwise a string with the BEGIN statment; will be + * freed in connection destructor */ + char* begin_statement; + + /* 1 if a check should be performed for each API call if the connection is + * used from the same thread it was created in */ + int check_same_thread; + + /* thread identification of the thread the connection was created in */ + long thread_ident; + + Cache* statement_cache; + + /* A list of weak references to statements used within this connection */ + PyObject* statements; + + /* a counter for how many statements were created in the connection. May be + * reset to 0 at certain intervals */ + int created_statements; + + PyObject* row_factory; + + /* Determines how bytestrings from SQLite are converted to Python objects: + * - PyUnicode_Type: Python Unicode objects are constructed from UTF-8 bytestrings + * - OptimizedUnicode: Like before, but for ASCII data, only PyStrings are created. + * - PyString_Type: PyStrings are created as-is. + * - Any custom callable: Any object returned from the callable called with the bytestring + * as single parameter. + */ + PyObject* text_factory; + + /* remember references to functions/classes used in + * create_function/create/aggregate, use these as dictionary keys, so we + * can keep the total system refcount constant by clearing that dictionary + * in connection_dealloc */ + PyObject* function_pinboard; + + /* a dictionary of registered collation name => collation callable mappings */ + PyObject* collations; + + /* Exception objects */ + PyObject* Warning; + PyObject* Error; + PyObject* InterfaceError; + PyObject* DatabaseError; + PyObject* DataError; + PyObject* OperationalError; + PyObject* IntegrityError; + PyObject* InternalError; + PyObject* ProgrammingError; + PyObject* NotSupportedError; +} Connection; + +extern PyTypeObject ConnectionType; + +PyObject* connection_alloc(PyTypeObject* type, int aware); +void connection_dealloc(Connection* self); +PyObject* connection_cursor(Connection* self, PyObject* args, PyObject* kwargs); +PyObject* connection_close(Connection* self, PyObject* args); +PyObject* _connection_begin(Connection* self); +PyObject* connection_begin(Connection* self, PyObject* args); +PyObject* connection_commit(Connection* self, PyObject* args); +PyObject* connection_rollback(Connection* self, PyObject* args); +PyObject* connection_new(PyTypeObject* type, PyObject* args, PyObject* kw); +int connection_init(Connection* self, PyObject* args, PyObject* kwargs); + +int check_thread(Connection* self); +int check_connection(Connection* con); + +int connection_setup_types(void); + +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/cursor.c b/sys/src/cmd/python/Modules/_sqlite/cursor.c new file mode 100644 index 000000000..91d8f74ee --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/cursor.c @@ -0,0 +1,1057 @@ +/* cursor.c - the cursor type + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "cursor.h" +#include "module.h" +#include "util.h" +#include "sqlitecompat.h" + +/* used to decide wether to call PyInt_FromLong or PyLong_FromLongLong */ +#ifndef INT32_MIN +#define INT32_MIN (-2147483647 - 1) +#endif +#ifndef INT32_MAX +#define INT32_MAX 2147483647 +#endif + +PyObject* cursor_iternext(Cursor *self); + +static StatementKind detect_statement_type(char* statement) +{ + char buf[20]; + char* src; + char* dst; + + src = statement; + /* skip over whitepace */ + while (*src == '\r' || *src == '\n' || *src == ' ' || *src == '\t') { + src++; + } + + if (*src == 0) + return STATEMENT_INVALID; + + dst = buf; + *dst = 0; + while (isalpha(*src) && dst - buf < sizeof(buf) - 2) { + *dst++ = tolower(*src++); + } + + *dst = 0; + + if (!strcmp(buf, "select")) { + return STATEMENT_SELECT; + } else if (!strcmp(buf, "insert")) { + return STATEMENT_INSERT; + } else if (!strcmp(buf, "update")) { + return STATEMENT_UPDATE; + } else if (!strcmp(buf, "delete")) { + return STATEMENT_DELETE; + } else if (!strcmp(buf, "replace")) { + return STATEMENT_REPLACE; + } else { + return STATEMENT_OTHER; + } +} + +int cursor_init(Cursor* self, PyObject* args, PyObject* kwargs) +{ + Connection* connection; + + if (!PyArg_ParseTuple(args, "O!", &ConnectionType, &connection)) + { + return -1; + } + + Py_INCREF(connection); + self->connection = connection; + self->statement = NULL; + self->next_row = NULL; + + self->row_cast_map = PyList_New(0); + if (!self->row_cast_map) { + return -1; + } + + Py_INCREF(Py_None); + self->description = Py_None; + + Py_INCREF(Py_None); + self->lastrowid= Py_None; + + self->arraysize = 1; + + self->rowcount = PyInt_FromLong(-1L); + if (!self->rowcount) { + return -1; + } + + Py_INCREF(Py_None); + self->row_factory = Py_None; + + if (!check_thread(self->connection)) { + return -1; + } + + return 0; +} + +void cursor_dealloc(Cursor* self) +{ + int rc; + + /* Reset the statement if the user has not closed the cursor */ + if (self->statement) { + rc = statement_reset(self->statement); + Py_DECREF(self->statement); + } + + Py_XDECREF(self->connection); + Py_XDECREF(self->row_cast_map); + Py_XDECREF(self->description); + Py_XDECREF(self->lastrowid); + Py_XDECREF(self->rowcount); + Py_XDECREF(self->row_factory); + Py_XDECREF(self->next_row); + + self->ob_type->tp_free((PyObject*)self); +} + +PyObject* _get_converter(PyObject* key) +{ + PyObject* upcase_key; + PyObject* retval; + + upcase_key = PyObject_CallMethod(key, "upper", ""); + if (!upcase_key) { + return NULL; + } + + retval = PyDict_GetItem(converters, upcase_key); + Py_DECREF(upcase_key); + + return retval; +} + +int build_row_cast_map(Cursor* self) +{ + int i; + const char* type_start = (const char*)-1; + const char* pos; + + const char* colname; + const char* decltype; + PyObject* py_decltype; + PyObject* converter; + PyObject* key; + + if (!self->connection->detect_types) { + return 0; + } + + Py_XDECREF(self->row_cast_map); + self->row_cast_map = PyList_New(0); + + for (i = 0; i < sqlite3_column_count(self->statement->st); i++) { + converter = NULL; + + if (self->connection->detect_types | PARSE_COLNAMES) { + colname = sqlite3_column_name(self->statement->st, i); + if (colname) { + for (pos = colname; *pos != 0; pos++) { + if (*pos == '[') { + type_start = pos + 1; + } else if (*pos == ']' && type_start != (const char*)-1) { + key = PyString_FromStringAndSize(type_start, pos - type_start); + if (!key) { + /* creating a string failed, but it is too complicated + * to propagate the error here, we just assume there is + * no converter and proceed */ + break; + } + + converter = _get_converter(key); + Py_DECREF(key); + break; + } + } + } + } + + if (!converter && self->connection->detect_types | PARSE_DECLTYPES) { + decltype = sqlite3_column_decltype(self->statement->st, i); + if (decltype) { + for (pos = decltype;;pos++) { + if (*pos == ' ' || *pos == 0) { + py_decltype = PyString_FromStringAndSize(decltype, pos - decltype); + if (!py_decltype) { + return -1; + } + break; + } + } + + converter = _get_converter(py_decltype); + Py_DECREF(py_decltype); + } + } + + if (!converter) { + converter = Py_None; + } + + if (PyList_Append(self->row_cast_map, converter) != 0) { + if (converter != Py_None) { + Py_DECREF(converter); + } + Py_XDECREF(self->row_cast_map); + self->row_cast_map = NULL; + + return -1; + } + } + + return 0; +} + +PyObject* _build_column_name(const char* colname) +{ + const char* pos; + + if (!colname) { + Py_INCREF(Py_None); + return Py_None; + } + + for (pos = colname;; pos++) { + if (*pos == 0 || *pos == '[') { + if ((*pos == '[') && (pos > colname) && (*(pos-1) == ' ')) { + pos--; + } + return PyString_FromStringAndSize(colname, pos - colname); + } + } +} + +PyObject* unicode_from_string(const char* val_str, int optimize) +{ + const char* check; + int is_ascii = 0; + + if (optimize) { + is_ascii = 1; + + check = val_str; + while (*check) { + if (*check & 0x80) { + is_ascii = 0; + break; + } + + check++; + } + } + + if (is_ascii) { + return PyString_FromString(val_str); + } else { + return PyUnicode_DecodeUTF8(val_str, strlen(val_str), NULL); + } +} + +/* + * Returns a row from the currently active SQLite statement + * + * Precondidition: + * - sqlite3_step() has been called before and it returned SQLITE_ROW. + */ +PyObject* _fetch_one_row(Cursor* self) +{ + int i, numcols; + PyObject* row; + PyObject* item = NULL; + int coltype; + PY_LONG_LONG intval; + PyObject* converter; + PyObject* converted; + Py_ssize_t nbytes; + PyObject* buffer; + void* raw_buffer; + const char* val_str; + char buf[200]; + const char* colname; + + Py_BEGIN_ALLOW_THREADS + numcols = sqlite3_data_count(self->statement->st); + Py_END_ALLOW_THREADS + + row = PyTuple_New(numcols); + if (!row) { + return NULL; + } + + for (i = 0; i < numcols; i++) { + if (self->connection->detect_types) { + converter = PyList_GetItem(self->row_cast_map, i); + if (!converter) { + converter = Py_None; + } + } else { + converter = Py_None; + } + + if (converter != Py_None) { + nbytes = sqlite3_column_bytes(self->statement->st, i); + val_str = (const char*)sqlite3_column_blob(self->statement->st, i); + if (!val_str) { + Py_INCREF(Py_None); + converted = Py_None; + } else { + item = PyString_FromStringAndSize(val_str, nbytes); + if (!item) { + return NULL; + } + converted = PyObject_CallFunction(converter, "O", item); + Py_DECREF(item); + if (!converted) { + break; + } + } + } else { + Py_BEGIN_ALLOW_THREADS + coltype = sqlite3_column_type(self->statement->st, i); + Py_END_ALLOW_THREADS + if (coltype == SQLITE_NULL) { + Py_INCREF(Py_None); + converted = Py_None; + } else if (coltype == SQLITE_INTEGER) { + intval = sqlite3_column_int64(self->statement->st, i); + if (intval < INT32_MIN || intval > INT32_MAX) { + converted = PyLong_FromLongLong(intval); + } else { + converted = PyInt_FromLong((long)intval); + } + } else if (coltype == SQLITE_FLOAT) { + converted = PyFloat_FromDouble(sqlite3_column_double(self->statement->st, i)); + } else if (coltype == SQLITE_TEXT) { + val_str = (const char*)sqlite3_column_text(self->statement->st, i); + if ((self->connection->text_factory == (PyObject*)&PyUnicode_Type) + || (self->connection->text_factory == OptimizedUnicode)) { + + converted = unicode_from_string(val_str, + self->connection->text_factory == OptimizedUnicode ? 1 : 0); + + if (!converted) { + colname = sqlite3_column_name(self->statement->st, i); + if (!colname) { + colname = "<unknown column name>"; + } + PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'", + colname , val_str); + PyErr_SetString(OperationalError, buf); + } + } else if (self->connection->text_factory == (PyObject*)&PyString_Type) { + converted = PyString_FromString(val_str); + } else { + converted = PyObject_CallFunction(self->connection->text_factory, "s", val_str); + } + } else { + /* coltype == SQLITE_BLOB */ + nbytes = sqlite3_column_bytes(self->statement->st, i); + buffer = PyBuffer_New(nbytes); + if (!buffer) { + break; + } + if (PyObject_AsWriteBuffer(buffer, &raw_buffer, &nbytes)) { + break; + } + memcpy(raw_buffer, sqlite3_column_blob(self->statement->st, i), nbytes); + converted = buffer; + } + } + + if (converted) { + PyTuple_SetItem(row, i, converted); + } else { + Py_INCREF(Py_None); + PyTuple_SetItem(row, i, Py_None); + } + } + + if (PyErr_Occurred()) { + Py_DECREF(row); + row = NULL; + } + + return row; +} + +PyObject* _query_execute(Cursor* self, int multiple, PyObject* args) +{ + PyObject* operation; + PyObject* operation_bytestr = NULL; + char* operation_cstr; + PyObject* parameters_list = NULL; + PyObject* parameters_iter = NULL; + PyObject* parameters = NULL; + int i; + int rc; + PyObject* func_args; + PyObject* result; + int numcols; + PY_LONG_LONG lastrowid; + int statement_type; + PyObject* descriptor; + PyObject* second_argument = NULL; + long rowcount = 0; + + if (!check_thread(self->connection) || !check_connection(self->connection)) { + return NULL; + } + + Py_XDECREF(self->next_row); + self->next_row = NULL; + + if (multiple) { + /* executemany() */ + if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) { + return NULL; + } + + if (!PyString_Check(operation) && !PyUnicode_Check(operation)) { + PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode"); + return NULL; + } + + if (PyIter_Check(second_argument)) { + /* iterator */ + Py_INCREF(second_argument); + parameters_iter = second_argument; + } else { + /* sequence */ + parameters_iter = PyObject_GetIter(second_argument); + if (!parameters_iter) { + return NULL; + } + } + } else { + /* execute() */ + if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) { + return NULL; + } + + if (!PyString_Check(operation) && !PyUnicode_Check(operation)) { + PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode"); + return NULL; + } + + parameters_list = PyList_New(0); + if (!parameters_list) { + return NULL; + } + + if (second_argument == NULL) { + second_argument = PyTuple_New(0); + if (!second_argument) { + goto error; + } + } else { + Py_INCREF(second_argument); + } + if (PyList_Append(parameters_list, second_argument) != 0) { + Py_DECREF(second_argument); + goto error; + } + Py_DECREF(second_argument); + + parameters_iter = PyObject_GetIter(parameters_list); + if (!parameters_iter) { + goto error; + } + } + + if (self->statement != NULL) { + /* There is an active statement */ + rc = statement_reset(self->statement); + } + + if (PyString_Check(operation)) { + operation_cstr = PyString_AsString(operation); + } else { + operation_bytestr = PyUnicode_AsUTF8String(operation); + if (!operation_bytestr) { + goto error; + } + + operation_cstr = PyString_AsString(operation_bytestr); + } + + /* reset description and rowcount */ + Py_DECREF(self->description); + Py_INCREF(Py_None); + self->description = Py_None; + + Py_DECREF(self->rowcount); + self->rowcount = PyInt_FromLong(-1L); + if (!self->rowcount) { + goto error; + } + + statement_type = detect_statement_type(operation_cstr); + if (self->connection->begin_statement) { + switch (statement_type) { + case STATEMENT_UPDATE: + case STATEMENT_DELETE: + case STATEMENT_INSERT: + case STATEMENT_REPLACE: + if (!self->connection->inTransaction) { + result = _connection_begin(self->connection); + if (!result) { + goto error; + } + Py_DECREF(result); + } + break; + case STATEMENT_OTHER: + /* it's a DDL statement or something similar + - we better COMMIT first so it works for all cases */ + if (self->connection->inTransaction) { + result = connection_commit(self->connection, NULL); + if (!result) { + goto error; + } + Py_DECREF(result); + } + break; + case STATEMENT_SELECT: + if (multiple) { + PyErr_SetString(ProgrammingError, + "You cannot execute SELECT statements in executemany()."); + goto error; + } + break; + } + } + + func_args = PyTuple_New(1); + if (!func_args) { + goto error; + } + Py_INCREF(operation); + if (PyTuple_SetItem(func_args, 0, operation) != 0) { + goto error; + } + + if (self->statement) { + (void)statement_reset(self->statement); + Py_DECREF(self->statement); + } + + self->statement = (Statement*)cache_get(self->connection->statement_cache, func_args); + Py_DECREF(func_args); + + if (!self->statement) { + goto error; + } + + if (self->statement->in_use) { + Py_DECREF(self->statement); + self->statement = PyObject_New(Statement, &StatementType); + if (!self->statement) { + goto error; + } + rc = statement_create(self->statement, self->connection, operation); + if (rc != SQLITE_OK) { + self->statement = 0; + goto error; + } + } + + statement_reset(self->statement); + statement_mark_dirty(self->statement); + + while (1) { + parameters = PyIter_Next(parameters_iter); + if (!parameters) { + break; + } + + statement_mark_dirty(self->statement); + + statement_bind_parameters(self->statement, parameters); + if (PyErr_Occurred()) { + goto error; + } + + if (build_row_cast_map(self) != 0) { + PyErr_SetString(OperationalError, "Error while building row_cast_map"); + goto error; + } + + rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection); + if (rc != SQLITE_DONE && rc != SQLITE_ROW) { + rc = statement_reset(self->statement); + if (rc == SQLITE_SCHEMA) { + rc = statement_recompile(self->statement, parameters); + if (rc == SQLITE_OK) { + rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection); + } else { + _seterror(self->connection->db); + goto error; + } + } else { + if (PyErr_Occurred()) { + /* there was an error that occurred in a user-defined callback */ + if (_enable_callback_tracebacks) { + PyErr_Print(); + } else { + PyErr_Clear(); + } + } + _seterror(self->connection->db); + goto error; + } + } + + if (rc == SQLITE_ROW || (rc == SQLITE_DONE && statement_type == STATEMENT_SELECT)) { + Py_BEGIN_ALLOW_THREADS + numcols = sqlite3_column_count(self->statement->st); + Py_END_ALLOW_THREADS + + if (self->description == Py_None) { + Py_DECREF(self->description); + self->description = PyTuple_New(numcols); + if (!self->description) { + goto error; + } + for (i = 0; i < numcols; i++) { + descriptor = PyTuple_New(7); + if (!descriptor) { + goto error; + } + PyTuple_SetItem(descriptor, 0, _build_column_name(sqlite3_column_name(self->statement->st, i))); + Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 1, Py_None); + Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 2, Py_None); + Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 3, Py_None); + Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 4, Py_None); + Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 5, Py_None); + Py_INCREF(Py_None); PyTuple_SetItem(descriptor, 6, Py_None); + PyTuple_SetItem(self->description, i, descriptor); + } + } + } + + if (rc == SQLITE_ROW) { + if (multiple) { + PyErr_SetString(ProgrammingError, "executemany() can only execute DML statements."); + goto error; + } + + self->next_row = _fetch_one_row(self); + } else if (rc == SQLITE_DONE && !multiple) { + statement_reset(self->statement); + Py_DECREF(self->statement); + self->statement = 0; + } + + switch (statement_type) { + case STATEMENT_UPDATE: + case STATEMENT_DELETE: + case STATEMENT_INSERT: + case STATEMENT_REPLACE: + Py_BEGIN_ALLOW_THREADS + rowcount += (long)sqlite3_changes(self->connection->db); + Py_END_ALLOW_THREADS + Py_DECREF(self->rowcount); + self->rowcount = PyInt_FromLong(rowcount); + } + + Py_DECREF(self->lastrowid); + if (statement_type == STATEMENT_INSERT) { + Py_BEGIN_ALLOW_THREADS + lastrowid = sqlite3_last_insert_rowid(self->connection->db); + Py_END_ALLOW_THREADS + self->lastrowid = PyInt_FromLong((long)lastrowid); + } else { + Py_INCREF(Py_None); + self->lastrowid = Py_None; + } + + if (multiple) { + rc = statement_reset(self->statement); + } + Py_XDECREF(parameters); + } + +error: + Py_XDECREF(operation_bytestr); + Py_XDECREF(parameters); + Py_XDECREF(parameters_iter); + Py_XDECREF(parameters_list); + + if (PyErr_Occurred()) { + return NULL; + } else { + Py_INCREF(self); + return (PyObject*)self; + } +} + +PyObject* cursor_execute(Cursor* self, PyObject* args) +{ + return _query_execute(self, 0, args); +} + +PyObject* cursor_executemany(Cursor* self, PyObject* args) +{ + return _query_execute(self, 1, args); +} + +PyObject* cursor_executescript(Cursor* self, PyObject* args) +{ + PyObject* script_obj; + PyObject* script_str = NULL; + const char* script_cstr; + sqlite3_stmt* statement; + int rc; + PyObject* result; + int statement_completed = 0; + + if (!PyArg_ParseTuple(args, "O", &script_obj)) { + return NULL; + } + + if (!check_thread(self->connection) || !check_connection(self->connection)) { + return NULL; + } + + if (PyString_Check(script_obj)) { + script_cstr = PyString_AsString(script_obj); + } else if (PyUnicode_Check(script_obj)) { + script_str = PyUnicode_AsUTF8String(script_obj); + if (!script_str) { + return NULL; + } + + script_cstr = PyString_AsString(script_str); + } else { + PyErr_SetString(PyExc_ValueError, "script argument must be unicode or string."); + return NULL; + } + + /* commit first */ + result = connection_commit(self->connection, NULL); + if (!result) { + goto error; + } + Py_DECREF(result); + + while (1) { + if (!sqlite3_complete(script_cstr)) { + break; + } + statement_completed = 1; + + rc = sqlite3_prepare(self->connection->db, + script_cstr, + -1, + &statement, + &script_cstr); + if (rc != SQLITE_OK) { + _seterror(self->connection->db); + goto error; + } + + /* execute statement, and ignore results of SELECT statements */ + rc = SQLITE_ROW; + while (rc == SQLITE_ROW) { + rc = _sqlite_step_with_busyhandler(statement, self->connection); + } + + if (rc != SQLITE_DONE) { + (void)sqlite3_finalize(statement); + _seterror(self->connection->db); + goto error; + } + + rc = sqlite3_finalize(statement); + if (rc != SQLITE_OK) { + _seterror(self->connection->db); + goto error; + } + } + +error: + Py_XDECREF(script_str); + + if (!statement_completed) { + PyErr_SetString(ProgrammingError, "you did not provide a complete SQL statement"); + } + + if (PyErr_Occurred()) { + return NULL; + } else { + Py_INCREF(self); + return (PyObject*)self; + } +} + +PyObject* cursor_getiter(Cursor *self) +{ + Py_INCREF(self); + return (PyObject*)self; +} + +PyObject* cursor_iternext(Cursor *self) +{ + PyObject* next_row_tuple; + PyObject* next_row; + int rc; + + if (!check_thread(self->connection) || !check_connection(self->connection)) { + return NULL; + } + + if (!self->next_row) { + if (self->statement) { + (void)statement_reset(self->statement); + Py_DECREF(self->statement); + self->statement = NULL; + } + return NULL; + } + + next_row_tuple = self->next_row; + self->next_row = NULL; + + if (self->row_factory != Py_None) { + next_row = PyObject_CallFunction(self->row_factory, "OO", self, next_row_tuple); + Py_DECREF(next_row_tuple); + } else { + next_row = next_row_tuple; + } + + rc = _sqlite_step_with_busyhandler(self->statement->st, self->connection); + if (rc != SQLITE_DONE && rc != SQLITE_ROW) { + Py_DECREF(next_row); + _seterror(self->connection->db); + return NULL; + } + + if (rc == SQLITE_ROW) { + self->next_row = _fetch_one_row(self); + } + + return next_row; +} + +PyObject* cursor_fetchone(Cursor* self, PyObject* args) +{ + PyObject* row; + + row = cursor_iternext(self); + if (!row && !PyErr_Occurred()) { + Py_INCREF(Py_None); + return Py_None; + } + + return row; +} + +PyObject* cursor_fetchmany(Cursor* self, PyObject* args) +{ + PyObject* row; + PyObject* list; + int maxrows = self->arraysize; + int counter = 0; + + if (!PyArg_ParseTuple(args, "|i", &maxrows)) { + return NULL; + } + + list = PyList_New(0); + if (!list) { + return NULL; + } + + /* just make sure we enter the loop */ + row = Py_None; + + while (row) { + row = cursor_iternext(self); + if (row) { + PyList_Append(list, row); + Py_DECREF(row); + } else { + break; + } + + if (++counter == maxrows) { + break; + } + } + + if (PyErr_Occurred()) { + Py_DECREF(list); + return NULL; + } else { + return list; + } +} + +PyObject* cursor_fetchall(Cursor* self, PyObject* args) +{ + PyObject* row; + PyObject* list; + + list = PyList_New(0); + if (!list) { + return NULL; + } + + /* just make sure we enter the loop */ + row = (PyObject*)Py_None; + + while (row) { + row = cursor_iternext(self); + if (row) { + PyList_Append(list, row); + Py_DECREF(row); + } + } + + if (PyErr_Occurred()) { + Py_DECREF(list); + return NULL; + } else { + return list; + } +} + +PyObject* pysqlite_noop(Connection* self, PyObject* args) +{ + /* don't care, return None */ + Py_INCREF(Py_None); + return Py_None; +} + +PyObject* cursor_close(Cursor* self, PyObject* args) +{ + if (!check_thread(self->connection) || !check_connection(self->connection)) { + return NULL; + } + + if (self->statement) { + (void)statement_reset(self->statement); + Py_DECREF(self->statement); + self->statement = 0; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef cursor_methods[] = { + {"execute", (PyCFunction)cursor_execute, METH_VARARGS, + PyDoc_STR("Executes a SQL statement.")}, + {"executemany", (PyCFunction)cursor_executemany, METH_VARARGS, + PyDoc_STR("Repeatedly executes a SQL statement.")}, + {"executescript", (PyCFunction)cursor_executescript, METH_VARARGS, + PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")}, + {"fetchone", (PyCFunction)cursor_fetchone, METH_NOARGS, + PyDoc_STR("Fetches several rows from the resultset.")}, + {"fetchmany", (PyCFunction)cursor_fetchmany, METH_VARARGS, + PyDoc_STR("Fetches all rows from the resultset.")}, + {"fetchall", (PyCFunction)cursor_fetchall, METH_NOARGS, + PyDoc_STR("Fetches one row from the resultset.")}, + {"close", (PyCFunction)cursor_close, METH_NOARGS, + PyDoc_STR("Closes the cursor.")}, + {"setinputsizes", (PyCFunction)pysqlite_noop, METH_VARARGS, + PyDoc_STR("Required by DB-API. Does nothing in pysqlite.")}, + {"setoutputsize", (PyCFunction)pysqlite_noop, METH_VARARGS, + PyDoc_STR("Required by DB-API. Does nothing in pysqlite.")}, + {NULL, NULL} +}; + +static struct PyMemberDef cursor_members[] = +{ + {"connection", T_OBJECT, offsetof(Cursor, connection), RO}, + {"description", T_OBJECT, offsetof(Cursor, description), RO}, + {"arraysize", T_INT, offsetof(Cursor, arraysize), 0}, + {"lastrowid", T_OBJECT, offsetof(Cursor, lastrowid), RO}, + {"rowcount", T_OBJECT, offsetof(Cursor, rowcount), RO}, + {"row_factory", T_OBJECT, offsetof(Cursor, row_factory), 0}, + {NULL} +}; + +static char cursor_doc[] = +PyDoc_STR("SQLite database cursor class."); + +PyTypeObject CursorType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + MODULE_NAME ".Cursor", /* tp_name */ + sizeof(Cursor), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)cursor_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_ITER|Py_TPFLAGS_BASETYPE, /* tp_flags */ + cursor_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)cursor_getiter, /* tp_iter */ + (iternextfunc)cursor_iternext, /* tp_iternext */ + cursor_methods, /* tp_methods */ + cursor_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)cursor_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +extern int cursor_setup_types(void) +{ + CursorType.tp_new = PyType_GenericNew; + return PyType_Ready(&CursorType); +} diff --git a/sys/src/cmd/python/Modules/_sqlite/cursor.h b/sys/src/cmd/python/Modules/_sqlite/cursor.h new file mode 100644 index 000000000..831ff812a --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/cursor.h @@ -0,0 +1,71 @@ +/* cursor.h - definitions for the cursor type + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_CURSOR_H +#define PYSQLITE_CURSOR_H +#include "Python.h" + +#include "statement.h" +#include "connection.h" +#include "module.h" + +typedef struct +{ + PyObject_HEAD + Connection* connection; + PyObject* description; + PyObject* row_cast_map; + int arraysize; + PyObject* lastrowid; + PyObject* rowcount; + PyObject* row_factory; + Statement* statement; + + /* the next row to be returned, NULL if no next row available */ + PyObject* next_row; +} Cursor; + +typedef enum { + STATEMENT_INVALID, STATEMENT_INSERT, STATEMENT_DELETE, + STATEMENT_UPDATE, STATEMENT_REPLACE, STATEMENT_SELECT, + STATEMENT_OTHER +} StatementKind; + +extern PyTypeObject CursorType; + +int cursor_init(Cursor* self, PyObject* args, PyObject* kwargs); +void cursor_dealloc(Cursor* self); +PyObject* cursor_execute(Cursor* self, PyObject* args); +PyObject* cursor_executemany(Cursor* self, PyObject* args); +PyObject* cursor_getiter(Cursor *self); +PyObject* cursor_iternext(Cursor *self); +PyObject* cursor_fetchone(Cursor* self, PyObject* args); +PyObject* cursor_fetchmany(Cursor* self, PyObject* args); +PyObject* cursor_fetchall(Cursor* self, PyObject* args); +PyObject* pysqlite_noop(Connection* self, PyObject* args); +PyObject* cursor_close(Cursor* self, PyObject* args); + +int cursor_setup_types(void); + +#define UNKNOWN (-1) +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/microprotocols.c b/sys/src/cmd/python/Modules/_sqlite/microprotocols.c new file mode 100644 index 000000000..4956ac073 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/microprotocols.c @@ -0,0 +1,142 @@ +/* microprotocols.c - minimalist and non-validating protocols implementation + * + * Copyright (C) 2003-2004 Federico Di Gregorio <fog@debian.org> + * + * This file is part of psycopg and was adapted for pysqlite. Federico Di + * Gregorio gave the permission to use it within pysqlite under the following + * license: + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include <Python.h> +#include <structmember.h> + +#include "cursor.h" +#include "microprotocols.h" +#include "prepare_protocol.h" + + +/** the adapters registry **/ + +PyObject *psyco_adapters; + +/* microprotocols_init - initialize the adapters dictionary */ + +int +microprotocols_init(PyObject *dict) +{ + /* create adapters dictionary and put it in module namespace */ + if ((psyco_adapters = PyDict_New()) == NULL) { + return -1; + } + + return PyDict_SetItemString(dict, "adapters", psyco_adapters); +} + + +/* microprotocols_add - add a reverse type-caster to the dictionary */ + +int +microprotocols_add(PyTypeObject *type, PyObject *proto, PyObject *cast) +{ + PyObject* key; + int rc; + + if (proto == NULL) proto = (PyObject*)&SQLitePrepareProtocolType; + + key = Py_BuildValue("(OO)", (PyObject*)type, proto); + if (!key) { + return -1; + } + + rc = PyDict_SetItem(psyco_adapters, key, cast); + Py_DECREF(key); + + return rc; +} + +/* microprotocols_adapt - adapt an object to the built-in protocol */ + +PyObject * +microprotocols_adapt(PyObject *obj, PyObject *proto, PyObject *alt) +{ + PyObject *adapter, *key; + + /* we don't check for exact type conformance as specified in PEP 246 + because the SQLitePrepareProtocolType type is abstract and there is no + way to get a quotable object to be its instance */ + + /* look for an adapter in the registry */ + key = Py_BuildValue("(OO)", (PyObject*)obj->ob_type, proto); + if (!key) { + return NULL; + } + adapter = PyDict_GetItem(psyco_adapters, key); + Py_DECREF(key); + if (adapter) { + PyObject *adapted = PyObject_CallFunctionObjArgs(adapter, obj, NULL); + return adapted; + } + + /* try to have the protocol adapt this object*/ + if (PyObject_HasAttrString(proto, "__adapt__")) { + PyObject *adapted = PyObject_CallMethod(proto, "__adapt__", "O", obj); + if (adapted) { + if (adapted != Py_None) { + return adapted; + } else { + Py_DECREF(adapted); + } + } + + if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + } + + /* and finally try to have the object adapt itself */ + if (PyObject_HasAttrString(obj, "__conform__")) { + PyObject *adapted = PyObject_CallMethod(obj, "__conform__","O", proto); + if (adapted) { + if (adapted != Py_None) { + return adapted; + } else { + Py_DECREF(adapted); + } + } + + if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_TypeError)) { + return NULL; + } + } + + /* else set the right exception and return NULL */ + PyErr_SetString(ProgrammingError, "can't adapt"); + return NULL; +} + +/** module-level functions **/ + +PyObject * +psyco_microprotocols_adapt(Cursor *self, PyObject *args) +{ + PyObject *obj, *alt = NULL; + PyObject *proto = (PyObject*)&SQLitePrepareProtocolType; + + if (!PyArg_ParseTuple(args, "O|OO", &obj, &proto, &alt)) return NULL; + return microprotocols_adapt(obj, proto, alt); +} diff --git a/sys/src/cmd/python/Modules/_sqlite/microprotocols.h b/sys/src/cmd/python/Modules/_sqlite/microprotocols.h new file mode 100644 index 000000000..f601bb3d3 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/microprotocols.h @@ -0,0 +1,59 @@ +/* microprotocols.c - definitions for minimalist and non-validating protocols + * + * Copyright (C) 2003-2004 Federico Di Gregorio <fog@debian.org> + * + * This file is part of psycopg and was adapted for pysqlite. Federico Di + * Gregorio gave the permission to use it within pysqlite under the following + * license: + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PSYCOPG_MICROPROTOCOLS_H +#define PSYCOPG_MICROPROTOCOLS_H 1 + +#include <Python.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** adapters registry **/ + +extern PyObject *psyco_adapters; + +/** the names of the three mandatory methods **/ + +#define MICROPROTOCOLS_GETQUOTED_NAME "getquoted" +#define MICROPROTOCOLS_GETSTRING_NAME "getstring" +#define MICROPROTOCOLS_GETBINARY_NAME "getbinary" + +/** exported functions **/ + +/* used by module.c to init the microprotocols system */ +extern int microprotocols_init(PyObject *dict); +extern int microprotocols_add( + PyTypeObject *type, PyObject *proto, PyObject *cast); +extern PyObject *microprotocols_adapt( + PyObject *obj, PyObject *proto, PyObject *alt); + +extern PyObject * + psyco_microprotocols_adapt(Cursor* self, PyObject *args); +#define psyco_microprotocols_adapt_doc \ + "adapt(obj, protocol, alternate) -> adapt obj to given protocol. Non-standard." + +#endif /* !defined(PSYCOPG_MICROPROTOCOLS_H) */ diff --git a/sys/src/cmd/python/Modules/_sqlite/module.c b/sys/src/cmd/python/Modules/_sqlite/module.c new file mode 100644 index 000000000..606454ca1 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/module.c @@ -0,0 +1,409 @@ + /* module.c - the module itself + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "connection.h" +#include "statement.h" +#include "cursor.h" +#include "cache.h" +#include "prepare_protocol.h" +#include "microprotocols.h" +#include "row.h" + +#if SQLITE_VERSION_NUMBER >= 3003003 +#define HAVE_SHARED_CACHE +#endif + +/* static objects at module-level */ + +PyObject* Error, *Warning, *InterfaceError, *DatabaseError, *InternalError, + *OperationalError, *ProgrammingError, *IntegrityError, *DataError, + *NotSupportedError, *OptimizedUnicode; + +PyObject* converters; +int _enable_callback_tracebacks; + +static PyObject* module_connect(PyObject* self, PyObject* args, PyObject* + kwargs) +{ + /* Python seems to have no way of extracting a single keyword-arg at + * C-level, so this code is redundant with the one in connection_init in + * connection.c and must always be copied from there ... */ + + static char *kwlist[] = {"database", "timeout", "detect_types", "isolation_level", "check_same_thread", "factory", "cached_statements", NULL, NULL}; + char* database; + int detect_types = 0; + PyObject* isolation_level; + PyObject* factory = NULL; + int check_same_thread = 1; + int cached_statements; + double timeout = 5.0; + + PyObject* result; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|diOiOi", kwlist, + &database, &timeout, &detect_types, &isolation_level, &check_same_thread, &factory, &cached_statements)) + { + return NULL; + } + + if (factory == NULL) { + factory = (PyObject*)&ConnectionType; + } + + result = PyObject_Call(factory, args, kwargs); + + return result; +} + +static PyObject* module_complete(PyObject* self, PyObject* args, PyObject* + kwargs) +{ + static char *kwlist[] = {"statement", NULL, NULL}; + char* statement; + + PyObject* result; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &statement)) + { + return NULL; + } + + if (sqlite3_complete(statement)) { + result = Py_True; + } else { + result = Py_False; + } + + Py_INCREF(result); + + return result; +} + +#ifdef HAVE_SHARED_CACHE +static PyObject* module_enable_shared_cache(PyObject* self, PyObject* args, PyObject* + kwargs) +{ + static char *kwlist[] = {"do_enable", NULL, NULL}; + int do_enable; + int rc; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &do_enable)) + { + return NULL; + } + + rc = sqlite3_enable_shared_cache(do_enable); + + if (rc != SQLITE_OK) { + PyErr_SetString(OperationalError, "Changing the shared_cache flag failed"); + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} +#endif /* HAVE_SHARED_CACHE */ + +static PyObject* module_register_adapter(PyObject* self, PyObject* args, PyObject* kwargs) +{ + PyTypeObject* type; + PyObject* caster; + + if (!PyArg_ParseTuple(args, "OO", &type, &caster)) { + return NULL; + } + + microprotocols_add(type, (PyObject*)&SQLitePrepareProtocolType, caster); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* module_register_converter(PyObject* self, PyObject* args, PyObject* kwargs) +{ + char* orig_name; + char* name = NULL; + char* c; + PyObject* callable; + PyObject* retval = NULL; + + if (!PyArg_ParseTuple(args, "sO", &orig_name, &callable)) { + return NULL; + } + + /* convert the name to lowercase */ + name = PyMem_Malloc(strlen(orig_name) + 2); + if (!name) { + goto error; + } + strcpy(name, orig_name); + for (c = name; *c != (char)0; c++) { + *c = (*c) & 0xDF; + } + + if (PyDict_SetItemString(converters, name, callable) != 0) { + goto error; + } + + Py_INCREF(Py_None); + retval = Py_None; +error: + if (name) { + PyMem_Free(name); + } + return retval; +} + +static PyObject* enable_callback_tracebacks(PyObject* self, PyObject* args, PyObject* kwargs) +{ + if (!PyArg_ParseTuple(args, "i", &_enable_callback_tracebacks)) { + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +void converters_init(PyObject* dict) +{ + converters = PyDict_New(); + if (!converters) { + return; + } + + PyDict_SetItemString(dict, "converters", converters); +} + +static PyMethodDef module_methods[] = { + {"connect", (PyCFunction)module_connect, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Creates a connection.")}, + {"complete_statement", (PyCFunction)module_complete, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Checks if a string contains a complete SQL statement. Non-standard.")}, +#ifdef HAVE_SHARED_CACHE + {"enable_shared_cache", (PyCFunction)module_enable_shared_cache, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Enable or disable shared cache mode for the calling thread. Experimental/Non-standard.")}, +#endif + {"register_adapter", (PyCFunction)module_register_adapter, METH_VARARGS, PyDoc_STR("Registers an adapter with pysqlite's adapter registry. Non-standard.")}, + {"register_converter", (PyCFunction)module_register_converter, METH_VARARGS, PyDoc_STR("Registers a converter with pysqlite. Non-standard.")}, + {"adapt", (PyCFunction)psyco_microprotocols_adapt, METH_VARARGS, psyco_microprotocols_adapt_doc}, + {"enable_callback_tracebacks", (PyCFunction)enable_callback_tracebacks, METH_VARARGS, PyDoc_STR("Enable or disable callback functions throwing errors to stderr.")}, + {NULL, NULL} +}; + +struct _IntConstantPair { + char* constant_name; + int constant_value; +}; + +typedef struct _IntConstantPair IntConstantPair; + +static IntConstantPair _int_constants[] = { + {"PARSE_DECLTYPES", PARSE_DECLTYPES}, + {"PARSE_COLNAMES", PARSE_COLNAMES}, + + {"SQLITE_OK", SQLITE_OK}, + {"SQLITE_DENY", SQLITE_DENY}, + {"SQLITE_IGNORE", SQLITE_IGNORE}, + {"SQLITE_CREATE_INDEX", SQLITE_CREATE_INDEX}, + {"SQLITE_CREATE_TABLE", SQLITE_CREATE_TABLE}, + {"SQLITE_CREATE_TEMP_INDEX", SQLITE_CREATE_TEMP_INDEX}, + {"SQLITE_CREATE_TEMP_TABLE", SQLITE_CREATE_TEMP_TABLE}, + {"SQLITE_CREATE_TEMP_TRIGGER", SQLITE_CREATE_TEMP_TRIGGER}, + {"SQLITE_CREATE_TEMP_VIEW", SQLITE_CREATE_TEMP_VIEW}, + {"SQLITE_CREATE_TRIGGER", SQLITE_CREATE_TRIGGER}, + {"SQLITE_CREATE_VIEW", SQLITE_CREATE_VIEW}, + {"SQLITE_DELETE", SQLITE_DELETE}, + {"SQLITE_DROP_INDEX", SQLITE_DROP_INDEX}, + {"SQLITE_DROP_TABLE", SQLITE_DROP_TABLE}, + {"SQLITE_DROP_TEMP_INDEX", SQLITE_DROP_TEMP_INDEX}, + {"SQLITE_DROP_TEMP_TABLE", SQLITE_DROP_TEMP_TABLE}, + {"SQLITE_DROP_TEMP_TRIGGER", SQLITE_DROP_TEMP_TRIGGER}, + {"SQLITE_DROP_TEMP_VIEW", SQLITE_DROP_TEMP_VIEW}, + {"SQLITE_DROP_TRIGGER", SQLITE_DROP_TRIGGER}, + {"SQLITE_DROP_VIEW", SQLITE_DROP_VIEW}, + {"SQLITE_INSERT", SQLITE_INSERT}, + {"SQLITE_PRAGMA", SQLITE_PRAGMA}, + {"SQLITE_READ", SQLITE_READ}, + {"SQLITE_SELECT", SQLITE_SELECT}, + {"SQLITE_TRANSACTION", SQLITE_TRANSACTION}, + {"SQLITE_UPDATE", SQLITE_UPDATE}, + {"SQLITE_ATTACH", SQLITE_ATTACH}, + {"SQLITE_DETACH", SQLITE_DETACH}, +#if SQLITE_VERSION_NUMBER >= 3002001 + {"SQLITE_ALTER_TABLE", SQLITE_ALTER_TABLE}, + {"SQLITE_REINDEX", SQLITE_REINDEX}, +#endif +#if SQLITE_VERSION_NUMBER >= 3003000 + {"SQLITE_ANALYZE", SQLITE_ANALYZE}, +#endif + {(char*)NULL, 0} +}; + +PyMODINIT_FUNC init_sqlite3(void) +{ + PyObject *module, *dict; + PyObject *tmp_obj; + int i; + + module = Py_InitModule("_sqlite3", module_methods); + + if (!module || + (row_setup_types() < 0) || + (cursor_setup_types() < 0) || + (connection_setup_types() < 0) || + (cache_setup_types() < 0) || + (statement_setup_types() < 0) || + (prepare_protocol_setup_types() < 0) + ) { + return; + } + + Py_INCREF(&ConnectionType); + PyModule_AddObject(module, "Connection", (PyObject*) &ConnectionType); + Py_INCREF(&CursorType); + PyModule_AddObject(module, "Cursor", (PyObject*) &CursorType); + Py_INCREF(&CacheType); + PyModule_AddObject(module, "Statement", (PyObject*)&StatementType); + Py_INCREF(&StatementType); + PyModule_AddObject(module, "Cache", (PyObject*) &CacheType); + Py_INCREF(&SQLitePrepareProtocolType); + PyModule_AddObject(module, "PrepareProtocol", (PyObject*) &SQLitePrepareProtocolType); + Py_INCREF(&RowType); + PyModule_AddObject(module, "Row", (PyObject*) &RowType); + + if (!(dict = PyModule_GetDict(module))) { + goto error; + } + + /*** Create DB-API Exception hierarchy */ + + if (!(Error = PyErr_NewException(MODULE_NAME ".Error", PyExc_StandardError, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "Error", Error); + + if (!(Warning = PyErr_NewException(MODULE_NAME ".Warning", PyExc_StandardError, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "Warning", Warning); + + /* Error subclasses */ + + if (!(InterfaceError = PyErr_NewException(MODULE_NAME ".InterfaceError", Error, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "InterfaceError", InterfaceError); + + if (!(DatabaseError = PyErr_NewException(MODULE_NAME ".DatabaseError", Error, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "DatabaseError", DatabaseError); + + /* DatabaseError subclasses */ + + if (!(InternalError = PyErr_NewException(MODULE_NAME ".InternalError", DatabaseError, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "InternalError", InternalError); + + if (!(OperationalError = PyErr_NewException(MODULE_NAME ".OperationalError", DatabaseError, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "OperationalError", OperationalError); + + if (!(ProgrammingError = PyErr_NewException(MODULE_NAME ".ProgrammingError", DatabaseError, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "ProgrammingError", ProgrammingError); + + if (!(IntegrityError = PyErr_NewException(MODULE_NAME ".IntegrityError", DatabaseError,NULL))) { + goto error; + } + PyDict_SetItemString(dict, "IntegrityError", IntegrityError); + + if (!(DataError = PyErr_NewException(MODULE_NAME ".DataError", DatabaseError, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "DataError", DataError); + + if (!(NotSupportedError = PyErr_NewException(MODULE_NAME ".NotSupportedError", DatabaseError, NULL))) { + goto error; + } + PyDict_SetItemString(dict, "NotSupportedError", NotSupportedError); + + /* We just need "something" unique for OptimizedUnicode. It does not really + * need to be a string subclass. Just anything that can act as a special + * marker for us. So I pulled PyCell_Type out of my magic hat. + */ + Py_INCREF((PyObject*)&PyCell_Type); + OptimizedUnicode = (PyObject*)&PyCell_Type; + PyDict_SetItemString(dict, "OptimizedUnicode", OptimizedUnicode); + + /* Set integer constants */ + for (i = 0; _int_constants[i].constant_name != 0; i++) { + tmp_obj = PyInt_FromLong(_int_constants[i].constant_value); + if (!tmp_obj) { + goto error; + } + PyDict_SetItemString(dict, _int_constants[i].constant_name, tmp_obj); + Py_DECREF(tmp_obj); + } + + if (!(tmp_obj = PyString_FromString(PYSQLITE_VERSION))) { + goto error; + } + PyDict_SetItemString(dict, "version", tmp_obj); + Py_DECREF(tmp_obj); + + if (!(tmp_obj = PyString_FromString(sqlite3_libversion()))) { + goto error; + } + PyDict_SetItemString(dict, "sqlite_version", tmp_obj); + Py_DECREF(tmp_obj); + + /* initialize microprotocols layer */ + microprotocols_init(dict); + + /* initialize the default converters */ + converters_init(dict); + + _enable_callback_tracebacks = 0; + + /* Original comment form _bsddb.c in the Python core. This is also still + * needed nowadays for Python 2.3/2.4. + * + * PyEval_InitThreads is called here due to a quirk in python 1.5 + * - 2.2.1 (at least) according to Russell Williamson <merel@wt.net>: + * The global interepreter lock is not initialized until the first + * thread is created using thread.start_new_thread() or fork() is + * called. that would cause the ALLOW_THREADS here to segfault due + * to a null pointer reference if no threads or child processes + * have been created. This works around that and is a no-op if + * threads have already been initialized. + * (see pybsddb-users mailing list post on 2002-08-07) + */ + PyEval_InitThreads(); + +error: + if (PyErr_Occurred()) + { + PyErr_SetString(PyExc_ImportError, MODULE_NAME ": init failed"); + } +} diff --git a/sys/src/cmd/python/Modules/_sqlite/module.h b/sys/src/cmd/python/Modules/_sqlite/module.h new file mode 100644 index 000000000..e514bd151 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/module.h @@ -0,0 +1,57 @@ +/* module.h - definitions for the module + * + * Copyright (C) 2004-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_MODULE_H +#define PYSQLITE_MODULE_H +#include "Python.h" + +#define PYSQLITE_VERSION "2.3.2" + +extern PyObject* Error; +extern PyObject* Warning; +extern PyObject* InterfaceError; +extern PyObject* DatabaseError; +extern PyObject* InternalError; +extern PyObject* OperationalError; +extern PyObject* ProgrammingError; +extern PyObject* IntegrityError; +extern PyObject* DataError; +extern PyObject* NotSupportedError; + +extern PyObject* OptimizedUnicode; + +/* the functions time.time() and time.sleep() */ +extern PyObject* time_time; +extern PyObject* time_sleep; + +/* A dictionary, mapping colum types (INTEGER, VARCHAR, etc.) to converter + * functions, that convert the SQL value to the appropriate Python value. + * The key is uppercase. + */ +extern PyObject* converters; + +extern int _enable_callback_tracebacks; + +#define PARSE_DECLTYPES 1 +#define PARSE_COLNAMES 2 +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/prepare_protocol.c b/sys/src/cmd/python/Modules/_sqlite/prepare_protocol.c new file mode 100644 index 000000000..26b663be1 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/prepare_protocol.c @@ -0,0 +1,84 @@ +/* prepare_protocol.c - the protocol for preparing values for SQLite + * + * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "prepare_protocol.h" + +int prepare_protocol_init(SQLitePrepareProtocol* self, PyObject* args, PyObject* kwargs) +{ + return 0; +} + +void prepare_protocol_dealloc(SQLitePrepareProtocol* self) +{ + self->ob_type->tp_free((PyObject*)self); +} + +PyTypeObject SQLitePrepareProtocolType= { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + MODULE_NAME ".PrepareProtocol", /* tp_name */ + sizeof(SQLitePrepareProtocol), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)prepare_protocol_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)prepare_protocol_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +extern int prepare_protocol_setup_types(void) +{ + SQLitePrepareProtocolType.tp_new = PyType_GenericNew; + SQLitePrepareProtocolType.ob_type= &PyType_Type; + return PyType_Ready(&SQLitePrepareProtocolType); +} diff --git a/sys/src/cmd/python/Modules/_sqlite/prepare_protocol.h b/sys/src/cmd/python/Modules/_sqlite/prepare_protocol.h new file mode 100644 index 000000000..2fc4f61cd --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/prepare_protocol.h @@ -0,0 +1,41 @@ +/* prepare_protocol.h - the protocol for preparing values for SQLite + * + * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_PREPARE_PROTOCOL_H +#define PYSQLITE_PREPARE_PROTOCOL_H +#include "Python.h" + +typedef struct +{ + PyObject_HEAD +} SQLitePrepareProtocol; + +extern PyTypeObject SQLitePrepareProtocolType; + +int prepare_protocol_init(SQLitePrepareProtocol* self, PyObject* args, PyObject* kwargs); +void prepare_protocol_dealloc(SQLitePrepareProtocol* self); + +int prepare_protocol_setup_types(void); + +#define UNKNOWN (-1) +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/row.c b/sys/src/cmd/python/Modules/_sqlite/row.c new file mode 100644 index 000000000..80b613554 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/row.c @@ -0,0 +1,202 @@ +/* row.c - an enhanced tuple for database rows + * + * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "row.h" +#include "cursor.h" +#include "sqlitecompat.h" + +void row_dealloc(Row* self) +{ + Py_XDECREF(self->data); + Py_XDECREF(self->description); + + self->ob_type->tp_free((PyObject*)self); +} + +int row_init(Row* self, PyObject* args, PyObject* kwargs) +{ + PyObject* data; + Cursor* cursor; + + self->data = 0; + self->description = 0; + + if (!PyArg_ParseTuple(args, "OO", &cursor, &data)) { + return -1; + } + + if (!PyObject_IsInstance((PyObject*)cursor, (PyObject*)&CursorType)) { + PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument"); + return -1; + } + + if (!PyTuple_Check(data)) { + PyErr_SetString(PyExc_TypeError, "tuple required for second argument"); + return -1; + } + + Py_INCREF(data); + self->data = data; + + Py_INCREF(cursor->description); + self->description = cursor->description; + + return 0; +} + +PyObject* row_subscript(Row* self, PyObject* idx) +{ + long _idx; + char* key; + int nitems, i; + char* compare_key; + + char* p1; + char* p2; + + PyObject* item; + + if (PyInt_Check(idx)) { + _idx = PyInt_AsLong(idx); + item = PyTuple_GetItem(self->data, _idx); + Py_XINCREF(item); + return item; + } else if (PyLong_Check(idx)) { + _idx = PyLong_AsLong(idx); + item = PyTuple_GetItem(self->data, _idx); + Py_XINCREF(item); + return item; + } else if (PyString_Check(idx)) { + key = PyString_AsString(idx); + + nitems = PyTuple_Size(self->description); + + for (i = 0; i < nitems; i++) { + compare_key = PyString_AsString(PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)); + if (!compare_key) { + return NULL; + } + + p1 = key; + p2 = compare_key; + + while (1) { + if ((*p1 == (char)0) || (*p2 == (char)0)) { + break; + } + + if ((*p1 | 0x20) != (*p2 | 0x20)) { + break; + } + + p1++; + p2++; + } + + if ((*p1 == (char)0) && (*p2 == (char)0)) { + /* found item */ + item = PyTuple_GetItem(self->data, i); + Py_INCREF(item); + return item; + } + + } + + PyErr_SetString(PyExc_IndexError, "No item with that key"); + return NULL; + } else if (PySlice_Check(idx)) { + PyErr_SetString(PyExc_ValueError, "slices not implemented, yet"); + return NULL; + } else { + PyErr_SetString(PyExc_IndexError, "Index must be int or string"); + return NULL; + } +} + +Py_ssize_t row_length(Row* self, PyObject* args, PyObject* kwargs) +{ + return PyTuple_GET_SIZE(self->data); +} + +static int row_print(Row* self, FILE *fp, int flags) +{ + return (&PyTuple_Type)->tp_print(self->data, fp, flags); +} + + +PyMappingMethods row_as_mapping = { + /* mp_length */ (lenfunc)row_length, + /* mp_subscript */ (binaryfunc)row_subscript, + /* mp_ass_subscript */ (objobjargproc)0, +}; + + +PyTypeObject RowType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + MODULE_NAME ".Row", /* tp_name */ + sizeof(Row), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)row_dealloc, /* tp_dealloc */ + (printfunc)row_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)row_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +extern int row_setup_types(void) +{ + RowType.tp_new = PyType_GenericNew; + RowType.tp_as_mapping = &row_as_mapping; + return PyType_Ready(&RowType); +} diff --git a/sys/src/cmd/python/Modules/_sqlite/row.h b/sys/src/cmd/python/Modules/_sqlite/row.h new file mode 100644 index 000000000..c6e083c9c --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/row.h @@ -0,0 +1,39 @@ +/* row.h - an enhanced tuple for database rows + * + * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_ROW_H +#define PYSQLITE_ROW_H +#include "Python.h" + +typedef struct _Row +{ + PyObject_HEAD + PyObject* data; + PyObject* description; +} Row; + +extern PyTypeObject RowType; + +int row_setup_types(void); + +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/sqlitecompat.h b/sys/src/cmd/python/Modules/_sqlite/sqlitecompat.h new file mode 100644 index 000000000..c3798257b --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/sqlitecompat.h @@ -0,0 +1,34 @@ +/* sqlitecompat.h - compatibility macros + * + * Copyright (C) 2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_COMPAT_H +#define PYSQLITE_COMPAT_H + +/* define Py_ssize_t for pre-2.5 versions of Python */ + +#if PY_VERSION_HEX < 0x02050000 +typedef int Py_ssize_t; +typedef int (*lenfunc)(PyObject*); +#endif + +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/statement.c b/sys/src/cmd/python/Modules/_sqlite/statement.c new file mode 100644 index 000000000..55923e785 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/statement.c @@ -0,0 +1,432 @@ +/* statement.c - the statement type + * + * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "statement.h" +#include "cursor.h" +#include "connection.h" +#include "microprotocols.h" +#include "prepare_protocol.h" +#include "sqlitecompat.h" + +/* prototypes */ +int check_remaining_sql(const char* tail); + +typedef enum { + LINECOMMENT_1, + IN_LINECOMMENT, + COMMENTSTART_1, + IN_COMMENT, + COMMENTEND_1, + NORMAL +} parse_remaining_sql_state; + +int statement_create(Statement* self, Connection* connection, PyObject* sql) +{ + const char* tail; + int rc; + PyObject* sql_str; + char* sql_cstr; + + self->st = NULL; + self->in_use = 0; + + if (PyString_Check(sql)) { + sql_str = sql; + Py_INCREF(sql_str); + } else if (PyUnicode_Check(sql)) { + sql_str = PyUnicode_AsUTF8String(sql); + if (!sql_str) { + rc = PYSQLITE_SQL_WRONG_TYPE; + return rc; + } + } else { + rc = PYSQLITE_SQL_WRONG_TYPE; + return rc; + } + + self->in_weakreflist = NULL; + self->sql = sql_str; + + sql_cstr = PyString_AsString(sql_str); + + rc = sqlite3_prepare(connection->db, + sql_cstr, + -1, + &self->st, + &tail); + + self->db = connection->db; + + if (rc == SQLITE_OK && check_remaining_sql(tail)) { + (void)sqlite3_finalize(self->st); + self->st = NULL; + rc = PYSQLITE_TOO_MUCH_SQL; + } + + return rc; +} + +int statement_bind_parameter(Statement* self, int pos, PyObject* parameter) +{ + int rc = SQLITE_OK; + long longval; +#ifdef HAVE_LONG_LONG + PY_LONG_LONG longlongval; +#endif + const char* buffer; + char* string; + Py_ssize_t buflen; + PyObject* stringval; + + if (parameter == Py_None) { + rc = sqlite3_bind_null(self->st, pos); + } else if (PyInt_Check(parameter)) { + longval = PyInt_AsLong(parameter); + rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longval); +#ifdef HAVE_LONG_LONG + } else if (PyLong_Check(parameter)) { + longlongval = PyLong_AsLongLong(parameter); + /* in the overflow error case, longlongval is -1, and an exception is set */ + rc = sqlite3_bind_int64(self->st, pos, (sqlite_int64)longlongval); +#endif + } else if (PyFloat_Check(parameter)) { + rc = sqlite3_bind_double(self->st, pos, PyFloat_AsDouble(parameter)); + } else if (PyBuffer_Check(parameter)) { + if (PyObject_AsCharBuffer(parameter, &buffer, &buflen) == 0) { + rc = sqlite3_bind_blob(self->st, pos, buffer, buflen, SQLITE_TRANSIENT); + } else { + PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); + rc = -1; + } + } else if PyString_Check(parameter) { + string = PyString_AsString(parameter); + rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT); + } else if PyUnicode_Check(parameter) { + stringval = PyUnicode_AsUTF8String(parameter); + string = PyString_AsString(stringval); + rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT); + Py_DECREF(stringval); + } else { + rc = -1; + } + + return rc; +} + +void statement_bind_parameters(Statement* self, PyObject* parameters) +{ + PyObject* current_param; + PyObject* adapted; + const char* binding_name; + int i; + int rc; + int num_params_needed; + int num_params; + + Py_BEGIN_ALLOW_THREADS + num_params_needed = sqlite3_bind_parameter_count(self->st); + Py_END_ALLOW_THREADS + + if (PyDict_Check(parameters)) { + /* parameters passed as dictionary */ + for (i = 1; i <= num_params_needed; i++) { + Py_BEGIN_ALLOW_THREADS + binding_name = sqlite3_bind_parameter_name(self->st, i); + Py_END_ALLOW_THREADS + if (!binding_name) { + PyErr_Format(ProgrammingError, "Binding %d has no name, but you supplied a dictionary (which has only names).", i); + return; + } + + binding_name++; /* skip first char (the colon) */ + current_param = PyDict_GetItemString(parameters, binding_name); + if (!current_param) { + PyErr_Format(ProgrammingError, "You did not supply a value for binding %d.", i); + return; + } + + Py_INCREF(current_param); + adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL); + if (adapted) { + Py_DECREF(current_param); + } else { + PyErr_Clear(); + adapted = current_param; + } + + rc = statement_bind_parameter(self, i, adapted); + Py_DECREF(adapted); + + if (rc != SQLITE_OK) { + PyErr_Format(InterfaceError, "Error binding parameter :%s - probably unsupported type.", binding_name); + return; + } + } + } else { + /* parameters passed as sequence */ + num_params = PySequence_Length(parameters); + if (num_params != num_params_needed) { + PyErr_Format(ProgrammingError, "Incorrect number of bindings supplied. The current statement uses %d, and there are %d supplied.", + num_params_needed, num_params); + return; + } + for (i = 0; i < num_params; i++) { + current_param = PySequence_GetItem(parameters, i); + if (!current_param) { + return; + } + adapted = microprotocols_adapt(current_param, (PyObject*)&SQLitePrepareProtocolType, NULL); + + if (adapted) { + Py_DECREF(current_param); + } else { + PyErr_Clear(); + adapted = current_param; + } + + rc = statement_bind_parameter(self, i + 1, adapted); + Py_DECREF(adapted); + + if (rc != SQLITE_OK) { + PyErr_Format(InterfaceError, "Error binding parameter %d - probably unsupported type.", i); + return; + } + } + } +} + +int statement_recompile(Statement* self, PyObject* params) +{ + const char* tail; + int rc; + char* sql_cstr; + sqlite3_stmt* new_st; + + sql_cstr = PyString_AsString(self->sql); + + rc = sqlite3_prepare(self->db, + sql_cstr, + -1, + &new_st, + &tail); + + if (rc == SQLITE_OK) { + /* The efficient sqlite3_transfer_bindings is only available in SQLite + * version 3.2.2 or later. For older SQLite releases, that might not + * even define SQLITE_VERSION_NUMBER, we do it the manual way. + */ + #ifdef SQLITE_VERSION_NUMBER + #if SQLITE_VERSION_NUMBER >= 3002002 + (void)sqlite3_transfer_bindings(self->st, new_st); + #endif + #else + statement_bind_parameters(self, params); + #endif + + (void)sqlite3_finalize(self->st); + self->st = new_st; + } + + return rc; +} + +int statement_finalize(Statement* self) +{ + int rc; + + rc = SQLITE_OK; + if (self->st) { + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_finalize(self->st); + Py_END_ALLOW_THREADS + self->st = NULL; + } + + self->in_use = 0; + + return rc; +} + +int statement_reset(Statement* self) +{ + int rc; + + rc = SQLITE_OK; + + if (self->in_use && self->st) { + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_reset(self->st); + Py_END_ALLOW_THREADS + + if (rc == SQLITE_OK) { + self->in_use = 0; + } + } + + return rc; +} + +void statement_mark_dirty(Statement* self) +{ + self->in_use = 1; +} + +void statement_dealloc(Statement* self) +{ + int rc; + + if (self->st) { + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_finalize(self->st); + Py_END_ALLOW_THREADS + } + + self->st = NULL; + + Py_XDECREF(self->sql); + + if (self->in_weakreflist != NULL) { + PyObject_ClearWeakRefs((PyObject*)self); + } + + self->ob_type->tp_free((PyObject*)self); +} + +/* + * Checks if there is anything left in an SQL string after SQLite compiled it. + * This is used to check if somebody tried to execute more than one SQL command + * with one execute()/executemany() command, which the DB-API and we don't + * allow. + * + * Returns 1 if there is more left than should be. 0 if ok. + */ +int check_remaining_sql(const char* tail) +{ + const char* pos = tail; + + parse_remaining_sql_state state = NORMAL; + + for (;;) { + switch (*pos) { + case 0: + return 0; + case '-': + if (state == NORMAL) { + state = LINECOMMENT_1; + } else if (state == LINECOMMENT_1) { + state = IN_LINECOMMENT; + } + break; + case ' ': + case '\t': + break; + case '\n': + case 13: + if (state == IN_LINECOMMENT) { + state = NORMAL; + } + break; + case '/': + if (state == NORMAL) { + state = COMMENTSTART_1; + } else if (state == COMMENTEND_1) { + state = NORMAL; + } else if (state == COMMENTSTART_1) { + return 1; + } + break; + case '*': + if (state == NORMAL) { + return 1; + } else if (state == LINECOMMENT_1) { + return 1; + } else if (state == COMMENTSTART_1) { + state = IN_COMMENT; + } else if (state == IN_COMMENT) { + state = COMMENTEND_1; + } + break; + default: + if (state == COMMENTEND_1) { + state = IN_COMMENT; + } else if (state == IN_LINECOMMENT) { + } else if (state == IN_COMMENT) { + } else { + return 1; + } + } + + pos++; + } + + return 0; +} + +PyTypeObject StatementType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + MODULE_NAME ".Statement", /* tp_name */ + sizeof(Statement), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)statement_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(Statement, in_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0 /* tp_free */ +}; + +extern int statement_setup_types(void) +{ + StatementType.tp_new = PyType_GenericNew; + return PyType_Ready(&StatementType); +} diff --git a/sys/src/cmd/python/Modules/_sqlite/statement.h b/sys/src/cmd/python/Modules/_sqlite/statement.h new file mode 100644 index 000000000..57ee36fa6 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/statement.h @@ -0,0 +1,59 @@ +/* statement.h - definitions for the statement type + * + * Copyright (C) 2005 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_STATEMENT_H +#define PYSQLITE_STATEMENT_H +#include "Python.h" + +#include "connection.h" +#include "sqlite3.h" + +#define PYSQLITE_TOO_MUCH_SQL (-100) +#define PYSQLITE_SQL_WRONG_TYPE (-101) + +typedef struct +{ + PyObject_HEAD + sqlite3* db; + sqlite3_stmt* st; + PyObject* sql; + int in_use; + PyObject* in_weakreflist; /* List of weak references */ +} Statement; + +extern PyTypeObject StatementType; + +int statement_create(Statement* self, Connection* connection, PyObject* sql); +void statement_dealloc(Statement* self); + +int statement_bind_parameter(Statement* self, int pos, PyObject* parameter); +void statement_bind_parameters(Statement* self, PyObject* parameters); + +int statement_recompile(Statement* self, PyObject* parameters); +int statement_finalize(Statement* self); +int statement_reset(Statement* self); +void statement_mark_dirty(Statement* self); + +int statement_setup_types(void); + +#endif diff --git a/sys/src/cmd/python/Modules/_sqlite/util.c b/sys/src/cmd/python/Modules/_sqlite/util.c new file mode 100644 index 000000000..f5a7233a9 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/util.c @@ -0,0 +1,96 @@ +/* util.c - various utility functions + * + * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include "module.h" +#include "connection.h" + +int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, Connection* connection +) +{ + int rc; + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_step(statement); + Py_END_ALLOW_THREADS + + return rc; +} + +/** + * Checks the SQLite error code and sets the appropriate DB-API exception. + * Returns the error code (0 means no error occurred). + */ +int _seterror(sqlite3* db) +{ + int errorcode; + + errorcode = sqlite3_errcode(db); + + switch (errorcode) + { + case SQLITE_OK: + PyErr_Clear(); + break; + case SQLITE_INTERNAL: + case SQLITE_NOTFOUND: + PyErr_SetString(InternalError, sqlite3_errmsg(db)); + break; + case SQLITE_NOMEM: + (void)PyErr_NoMemory(); + break; + case SQLITE_ERROR: + case SQLITE_PERM: + case SQLITE_ABORT: + case SQLITE_BUSY: + case SQLITE_LOCKED: + case SQLITE_READONLY: + case SQLITE_INTERRUPT: + case SQLITE_IOERR: + case SQLITE_FULL: + case SQLITE_CANTOPEN: + case SQLITE_PROTOCOL: + case SQLITE_EMPTY: + case SQLITE_SCHEMA: + PyErr_SetString(OperationalError, sqlite3_errmsg(db)); + break; + case SQLITE_CORRUPT: + PyErr_SetString(DatabaseError, sqlite3_errmsg(db)); + break; + case SQLITE_TOOBIG: + PyErr_SetString(DataError, sqlite3_errmsg(db)); + break; + case SQLITE_CONSTRAINT: + case SQLITE_MISMATCH: + PyErr_SetString(IntegrityError, sqlite3_errmsg(db)); + break; + case SQLITE_MISUSE: + PyErr_SetString(ProgrammingError, sqlite3_errmsg(db)); + break; + default: + PyErr_SetString(DatabaseError, sqlite3_errmsg(db)); + break; + } + + return errorcode; +} + diff --git a/sys/src/cmd/python/Modules/_sqlite/util.h b/sys/src/cmd/python/Modules/_sqlite/util.h new file mode 100644 index 000000000..7ce3d403c --- /dev/null +++ b/sys/src/cmd/python/Modules/_sqlite/util.h @@ -0,0 +1,38 @@ +/* util.h - various utility functions + * + * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de> + * + * This file is part of pysqlite. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef PYSQLITE_UTIL_H +#define PYSQLITE_UTIL_H +#include "Python.h" +#include "pythread.h" +#include "sqlite3.h" +#include "connection.h" + +int _sqlite_step_with_busyhandler(sqlite3_stmt* statement, Connection* connection); + +/** + * Checks the SQLite error code and sets the appropriate DB-API exception. + * Returns the error code (0 means no error occurred). + */ +int _seterror(sqlite3* db); +#endif diff --git a/sys/src/cmd/python/Modules/_sre.c b/sys/src/cmd/python/Modules/_sre.c new file mode 100644 index 000000000..c1eb71cf2 --- /dev/null +++ b/sys/src/cmd/python/Modules/_sre.c @@ -0,0 +1,3429 @@ +/* + * Secret Labs' Regular Expression Engine + * + * regular expression matching engine + * + * partial history: + * 1999-10-24 fl created (based on existing template matcher code) + * 2000-03-06 fl first alpha, sort of + * 2000-08-01 fl fixes for 1.6b1 + * 2000-08-07 fl use PyOS_CheckStack() if available + * 2000-09-20 fl added expand method + * 2001-03-20 fl lots of fixes for 2.1b2 + * 2001-04-15 fl export copyright as Python attribute, not global + * 2001-04-28 fl added __copy__ methods (work in progress) + * 2001-05-14 fl fixes for 1.5.2 compatibility + * 2001-07-01 fl added BIGCHARSET support (from Martin von Loewis) + * 2001-10-18 fl fixed group reset issue (from Matthew Mueller) + * 2001-10-20 fl added split primitive; reenable unicode for 1.6/2.0/2.1 + * 2001-10-21 fl added sub/subn primitive + * 2001-10-24 fl added finditer primitive (for 2.2 only) + * 2001-12-07 fl fixed memory leak in sub/subn (Guido van Rossum) + * 2002-11-09 fl fixed empty sub/subn return type + * 2003-04-18 mvl fully support 4-byte codes + * 2003-10-17 gn implemented non recursive scheme + * + * Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved. + * + * This version of the SRE library can be redistributed under CNRI's + * Python 1.6 license. For any other use, please contact Secret Labs + * AB (info@pythonware.com). + * + * Portions of this engine have been developed in cooperation with + * CNRI. Hewlett-Packard provided funding for 1.6 integration and + * other compatibility work. + */ + +#ifndef SRE_RECURSIVE + +static char copyright[] = + " SRE 2.2.2 Copyright (c) 1997-2002 by Secret Labs AB "; + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" +#include "structmember.h" /* offsetof */ + +#include "sre.h" + +#include <ctype.h> + +/* name of this module, minus the leading underscore */ +#if !defined(SRE_MODULE) +#define SRE_MODULE "sre" +#endif + +#define SRE_PY_MODULE "re" + +/* defining this one enables tracing */ +#undef VERBOSE + +#if PY_VERSION_HEX >= 0x01060000 +#if PY_VERSION_HEX < 0x02020000 || defined(Py_USING_UNICODE) +/* defining this enables unicode support (default under 1.6a1 and later) */ +#define HAVE_UNICODE +#endif +#endif + +/* -------------------------------------------------------------------- */ +/* optional features */ + +/* enables fast searching */ +#define USE_FAST_SEARCH + +/* enables aggressive inlining (always on for Visual C) */ +#undef USE_INLINE + +/* enables copy/deepcopy handling (work in progress) */ +#undef USE_BUILTIN_COPY + +#if PY_VERSION_HEX < 0x01060000 +#define PyObject_DEL(op) PyMem_DEL((op)) +#endif + +/* -------------------------------------------------------------------- */ + +#if defined(_MSC_VER) +#pragma optimize("agtw", on) /* doesn't seem to make much difference... */ +#pragma warning(disable: 4710) /* who cares if functions are not inlined ;-) */ +/* fastest possible local call under MSVC */ +#define LOCAL(type) static __inline type __fastcall +#elif defined(USE_INLINE) +#define LOCAL(type) static inline type +#else +#define LOCAL(type) static type +#endif + +/* error codes */ +#define SRE_ERROR_ILLEGAL -1 /* illegal opcode */ +#define SRE_ERROR_STATE -2 /* illegal state */ +#define SRE_ERROR_RECURSION_LIMIT -3 /* runaway recursion */ +#define SRE_ERROR_MEMORY -9 /* out of memory */ + +#if defined(VERBOSE) +#define TRACE(v) printf v +#else +#define TRACE(v) +#endif + +/* -------------------------------------------------------------------- */ +/* search engine state */ + +/* default character predicates (run sre_chars.py to regenerate tables) */ + +#define SRE_DIGIT_MASK 1 +#define SRE_SPACE_MASK 2 +#define SRE_LINEBREAK_MASK 4 +#define SRE_ALNUM_MASK 8 +#define SRE_WORD_MASK 16 + +/* FIXME: this assumes ASCII. create tables in init_sre() instead */ + +static char sre_char_info[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 2, +2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 0, 0, 0, 0, 0, 0, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, +0, 0, 16, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 0, 0, 0 }; + +static char sre_char_lower[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, +10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, +27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, +44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, +61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, +108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, +122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, +106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, +120, 121, 122, 123, 124, 125, 126, 127 }; + +#define SRE_IS_DIGIT(ch)\ + ((ch) < 128 ? (sre_char_info[(ch)] & SRE_DIGIT_MASK) : 0) +#define SRE_IS_SPACE(ch)\ + ((ch) < 128 ? (sre_char_info[(ch)] & SRE_SPACE_MASK) : 0) +#define SRE_IS_LINEBREAK(ch)\ + ((ch) < 128 ? (sre_char_info[(ch)] & SRE_LINEBREAK_MASK) : 0) +#define SRE_IS_ALNUM(ch)\ + ((ch) < 128 ? (sre_char_info[(ch)] & SRE_ALNUM_MASK) : 0) +#define SRE_IS_WORD(ch)\ + ((ch) < 128 ? (sre_char_info[(ch)] & SRE_WORD_MASK) : 0) + +static unsigned int sre_lower(unsigned int ch) +{ + return ((ch) < 128 ? (unsigned int)sre_char_lower[ch] : ch); +} + +/* locale-specific character predicates */ +/* !(c & ~N) == (c < N+1) for any unsigned c, this avoids + * warnings when c's type supports only numbers < N+1 */ +#define SRE_LOC_IS_DIGIT(ch) (!((ch) & ~255) ? isdigit((ch)) : 0) +#define SRE_LOC_IS_SPACE(ch) (!((ch) & ~255) ? isspace((ch)) : 0) +#define SRE_LOC_IS_LINEBREAK(ch) ((ch) == '\n') +#define SRE_LOC_IS_ALNUM(ch) (!((ch) & ~255) ? isalnum((ch)) : 0) +#define SRE_LOC_IS_WORD(ch) (SRE_LOC_IS_ALNUM((ch)) || (ch) == '_') + +static unsigned int sre_lower_locale(unsigned int ch) +{ + return ((ch) < 256 ? (unsigned int)tolower((ch)) : ch); +} + +/* unicode-specific character predicates */ + +#if defined(HAVE_UNICODE) + +#define SRE_UNI_IS_DIGIT(ch) Py_UNICODE_ISDIGIT((Py_UNICODE)(ch)) +#define SRE_UNI_IS_SPACE(ch) Py_UNICODE_ISSPACE((Py_UNICODE)(ch)) +#define SRE_UNI_IS_LINEBREAK(ch) Py_UNICODE_ISLINEBREAK((Py_UNICODE)(ch)) +#define SRE_UNI_IS_ALNUM(ch) Py_UNICODE_ISALNUM((Py_UNICODE)(ch)) +#define SRE_UNI_IS_WORD(ch) (SRE_UNI_IS_ALNUM((ch)) || (ch) == '_') + +static unsigned int sre_lower_unicode(unsigned int ch) +{ + return (unsigned int) Py_UNICODE_TOLOWER((Py_UNICODE)(ch)); +} + +#endif + +LOCAL(int) +sre_category(SRE_CODE category, unsigned int ch) +{ + switch (category) { + + case SRE_CATEGORY_DIGIT: + return SRE_IS_DIGIT(ch); + case SRE_CATEGORY_NOT_DIGIT: + return !SRE_IS_DIGIT(ch); + case SRE_CATEGORY_SPACE: + return SRE_IS_SPACE(ch); + case SRE_CATEGORY_NOT_SPACE: + return !SRE_IS_SPACE(ch); + case SRE_CATEGORY_WORD: + return SRE_IS_WORD(ch); + case SRE_CATEGORY_NOT_WORD: + return !SRE_IS_WORD(ch); + case SRE_CATEGORY_LINEBREAK: + return SRE_IS_LINEBREAK(ch); + case SRE_CATEGORY_NOT_LINEBREAK: + return !SRE_IS_LINEBREAK(ch); + + case SRE_CATEGORY_LOC_WORD: + return SRE_LOC_IS_WORD(ch); + case SRE_CATEGORY_LOC_NOT_WORD: + return !SRE_LOC_IS_WORD(ch); + +#if defined(HAVE_UNICODE) + case SRE_CATEGORY_UNI_DIGIT: + return SRE_UNI_IS_DIGIT(ch); + case SRE_CATEGORY_UNI_NOT_DIGIT: + return !SRE_UNI_IS_DIGIT(ch); + case SRE_CATEGORY_UNI_SPACE: + return SRE_UNI_IS_SPACE(ch); + case SRE_CATEGORY_UNI_NOT_SPACE: + return !SRE_UNI_IS_SPACE(ch); + case SRE_CATEGORY_UNI_WORD: + return SRE_UNI_IS_WORD(ch); + case SRE_CATEGORY_UNI_NOT_WORD: + return !SRE_UNI_IS_WORD(ch); + case SRE_CATEGORY_UNI_LINEBREAK: + return SRE_UNI_IS_LINEBREAK(ch); + case SRE_CATEGORY_UNI_NOT_LINEBREAK: + return !SRE_UNI_IS_LINEBREAK(ch); +#else + case SRE_CATEGORY_UNI_DIGIT: + return SRE_IS_DIGIT(ch); + case SRE_CATEGORY_UNI_NOT_DIGIT: + return !SRE_IS_DIGIT(ch); + case SRE_CATEGORY_UNI_SPACE: + return SRE_IS_SPACE(ch); + case SRE_CATEGORY_UNI_NOT_SPACE: + return !SRE_IS_SPACE(ch); + case SRE_CATEGORY_UNI_WORD: + return SRE_LOC_IS_WORD(ch); + case SRE_CATEGORY_UNI_NOT_WORD: + return !SRE_LOC_IS_WORD(ch); + case SRE_CATEGORY_UNI_LINEBREAK: + return SRE_IS_LINEBREAK(ch); + case SRE_CATEGORY_UNI_NOT_LINEBREAK: + return !SRE_IS_LINEBREAK(ch); +#endif + } + return 0; +} + +/* helpers */ + +static void +data_stack_dealloc(SRE_STATE* state) +{ + if (state->data_stack) { + PyMem_FREE(state->data_stack); + state->data_stack = NULL; + } + state->data_stack_size = state->data_stack_base = 0; +} + +static int +data_stack_grow(SRE_STATE* state, Py_ssize_t size) +{ + Py_ssize_t minsize, cursize; + minsize = state->data_stack_base+size; + cursize = state->data_stack_size; + if (cursize < minsize) { + void* stack; + cursize = minsize+minsize/4+1024; + TRACE(("allocate/grow stack %d\n", cursize)); + stack = PyMem_REALLOC(state->data_stack, cursize); + if (!stack) { + data_stack_dealloc(state); + return SRE_ERROR_MEMORY; + } + state->data_stack = (char *)stack; + state->data_stack_size = cursize; + } + return 0; +} + +/* generate 8-bit version */ + +#define SRE_CHAR unsigned char +#define SRE_AT sre_at +#define SRE_COUNT sre_count +#define SRE_CHARSET sre_charset +#define SRE_INFO sre_info +#define SRE_MATCH sre_match +#define SRE_MATCH_CONTEXT sre_match_context +#define SRE_SEARCH sre_search +#define SRE_LITERAL_TEMPLATE sre_literal_template + +#if defined(HAVE_UNICODE) + +#define SRE_RECURSIVE +#include "_sre.c" +#undef SRE_RECURSIVE + +#undef SRE_LITERAL_TEMPLATE +#undef SRE_SEARCH +#undef SRE_MATCH +#undef SRE_MATCH_CONTEXT +#undef SRE_INFO +#undef SRE_CHARSET +#undef SRE_COUNT +#undef SRE_AT +#undef SRE_CHAR + +/* generate 16-bit unicode version */ + +#define SRE_CHAR Py_UNICODE +#define SRE_AT sre_uat +#define SRE_COUNT sre_ucount +#define SRE_CHARSET sre_ucharset +#define SRE_INFO sre_uinfo +#define SRE_MATCH sre_umatch +#define SRE_MATCH_CONTEXT sre_umatch_context +#define SRE_SEARCH sre_usearch +#define SRE_LITERAL_TEMPLATE sre_uliteral_template +#endif + +#endif /* SRE_RECURSIVE */ + +/* -------------------------------------------------------------------- */ +/* String matching engine */ + +/* the following section is compiled twice, with different character + settings */ + +LOCAL(int) +SRE_AT(SRE_STATE* state, SRE_CHAR* ptr, SRE_CODE at) +{ + /* check if pointer is at given position */ + + Py_ssize_t thisp, thatp; + + switch (at) { + + case SRE_AT_BEGINNING: + case SRE_AT_BEGINNING_STRING: + return ((void*) ptr == state->beginning); + + case SRE_AT_BEGINNING_LINE: + return ((void*) ptr == state->beginning || + SRE_IS_LINEBREAK((int) ptr[-1])); + + case SRE_AT_END: + return (((void*) (ptr+1) == state->end && + SRE_IS_LINEBREAK((int) ptr[0])) || + ((void*) ptr == state->end)); + + case SRE_AT_END_LINE: + return ((void*) ptr == state->end || + SRE_IS_LINEBREAK((int) ptr[0])); + + case SRE_AT_END_STRING: + return ((void*) ptr == state->end); + + case SRE_AT_BOUNDARY: + if (state->beginning == state->end) + return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? + SRE_IS_WORD((int) ptr[0]) : 0; + return thisp != thatp; + + case SRE_AT_NON_BOUNDARY: + if (state->beginning == state->end) + return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? + SRE_IS_WORD((int) ptr[0]) : 0; + return thisp == thatp; + + case SRE_AT_LOC_BOUNDARY: + if (state->beginning == state->end) + return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_LOC_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? + SRE_LOC_IS_WORD((int) ptr[0]) : 0; + return thisp != thatp; + + case SRE_AT_LOC_NON_BOUNDARY: + if (state->beginning == state->end) + return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_LOC_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? + SRE_LOC_IS_WORD((int) ptr[0]) : 0; + return thisp == thatp; + +#if defined(HAVE_UNICODE) + case SRE_AT_UNI_BOUNDARY: + if (state->beginning == state->end) + return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_UNI_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? + SRE_UNI_IS_WORD((int) ptr[0]) : 0; + return thisp != thatp; + + case SRE_AT_UNI_NON_BOUNDARY: + if (state->beginning == state->end) + return 0; + thatp = ((void*) ptr > state->beginning) ? + SRE_UNI_IS_WORD((int) ptr[-1]) : 0; + thisp = ((void*) ptr < state->end) ? + SRE_UNI_IS_WORD((int) ptr[0]) : 0; + return thisp == thatp; +#endif + + } + + return 0; +} + +LOCAL(int) +SRE_CHARSET(SRE_CODE* set, SRE_CODE ch) +{ + /* check if character is a member of the given set */ + + int ok = 1; + + for (;;) { + switch (*set++) { + + case SRE_OP_FAILURE: + return !ok; + + case SRE_OP_LITERAL: + /* <LITERAL> <code> */ + if (ch == set[0]) + return ok; + set++; + break; + + case SRE_OP_CATEGORY: + /* <CATEGORY> <code> */ + if (sre_category(set[0], (int) ch)) + return ok; + set += 1; + break; + + case SRE_OP_CHARSET: + if (sizeof(SRE_CODE) == 2) { + /* <CHARSET> <bitmap> (16 bits per code word) */ + if (ch < 256 && (set[ch >> 4] & (1 << (ch & 15)))) + return ok; + set += 16; + } + else { + /* <CHARSET> <bitmap> (32 bits per code word) */ + if (ch < 256 && (set[ch >> 5] & (1 << (ch & 31)))) + return ok; + set += 8; + } + break; + + case SRE_OP_RANGE: + /* <RANGE> <lower> <upper> */ + if (set[0] <= ch && ch <= set[1]) + return ok; + set += 2; + break; + + case SRE_OP_NEGATE: + ok = !ok; + break; + + case SRE_OP_BIGCHARSET: + /* <BIGCHARSET> <blockcount> <256 blockindices> <blocks> */ + { + Py_ssize_t count, block; + count = *(set++); + + if (sizeof(SRE_CODE) == 2) { + block = ((unsigned char*)set)[ch >> 8]; + set += 128; + if (set[block*16 + ((ch & 255)>>4)] & (1 << (ch & 15))) + return ok; + set += count*16; + } + else { + /* !(c & ~N) == (c < N+1) for any unsigned c, this avoids + * warnings when c's type supports only numbers < N+1 */ + if (!(ch & ~65535)) + block = ((unsigned char*)set)[ch >> 8]; + else + block = -1; + set += 64; + if (block >=0 && + (set[block*8 + ((ch & 255)>>5)] & (1 << (ch & 31)))) + return ok; + set += count*8; + } + break; + } + + default: + /* internal error -- there's not much we can do about it + here, so let's just pretend it didn't match... */ + return 0; + } + } +} + +LOCAL(Py_ssize_t) SRE_MATCH(SRE_STATE* state, SRE_CODE* pattern); + +LOCAL(Py_ssize_t) +SRE_COUNT(SRE_STATE* state, SRE_CODE* pattern, Py_ssize_t maxcount) +{ + SRE_CODE chr; + SRE_CHAR* ptr = (SRE_CHAR *)state->ptr; + SRE_CHAR* end = (SRE_CHAR *)state->end; + Py_ssize_t i; + + /* adjust end */ + if (maxcount < end - ptr && maxcount != 65535) + end = ptr + maxcount; + + switch (pattern[0]) { + + case SRE_OP_IN: + /* repeated set */ + TRACE(("|%p|%p|COUNT IN\n", pattern, ptr)); + while (ptr < end && SRE_CHARSET(pattern + 2, *ptr)) + ptr++; + break; + + case SRE_OP_ANY: + /* repeated dot wildcard. */ + TRACE(("|%p|%p|COUNT ANY\n", pattern, ptr)); + while (ptr < end && !SRE_IS_LINEBREAK(*ptr)) + ptr++; + break; + + case SRE_OP_ANY_ALL: + /* repeated dot wildcard. skip to the end of the target + string, and backtrack from there */ + TRACE(("|%p|%p|COUNT ANY_ALL\n", pattern, ptr)); + ptr = end; + break; + + case SRE_OP_LITERAL: + /* repeated literal */ + chr = pattern[1]; + TRACE(("|%p|%p|COUNT LITERAL %d\n", pattern, ptr, chr)); + while (ptr < end && (SRE_CODE) *ptr == chr) + ptr++; + break; + + case SRE_OP_LITERAL_IGNORE: + /* repeated literal */ + chr = pattern[1]; + TRACE(("|%p|%p|COUNT LITERAL_IGNORE %d\n", pattern, ptr, chr)); + while (ptr < end && (SRE_CODE) state->lower(*ptr) == chr) + ptr++; + break; + + case SRE_OP_NOT_LITERAL: + /* repeated non-literal */ + chr = pattern[1]; + TRACE(("|%p|%p|COUNT NOT_LITERAL %d\n", pattern, ptr, chr)); + while (ptr < end && (SRE_CODE) *ptr != chr) + ptr++; + break; + + case SRE_OP_NOT_LITERAL_IGNORE: + /* repeated non-literal */ + chr = pattern[1]; + TRACE(("|%p|%p|COUNT NOT_LITERAL_IGNORE %d\n", pattern, ptr, chr)); + while (ptr < end && (SRE_CODE) state->lower(*ptr) != chr) + ptr++; + break; + + default: + /* repeated single character pattern */ + TRACE(("|%p|%p|COUNT SUBPATTERN\n", pattern, ptr)); + while ((SRE_CHAR*) state->ptr < end) { + i = SRE_MATCH(state, pattern); + if (i < 0) + return i; + if (!i) + break; + } + TRACE(("|%p|%p|COUNT %d\n", pattern, ptr, + (SRE_CHAR*) state->ptr - ptr)); + return (SRE_CHAR*) state->ptr - ptr; + } + + TRACE(("|%p|%p|COUNT %d\n", pattern, ptr, ptr - (SRE_CHAR*) state->ptr)); + return ptr - (SRE_CHAR*) state->ptr; +} + +#if 0 /* not used in this release */ +LOCAL(int) +SRE_INFO(SRE_STATE* state, SRE_CODE* pattern) +{ + /* check if an SRE_OP_INFO block matches at the current position. + returns the number of SRE_CODE objects to skip if successful, 0 + if no match */ + + SRE_CHAR* end = state->end; + SRE_CHAR* ptr = state->ptr; + Py_ssize_t i; + + /* check minimal length */ + if (pattern[3] && (end - ptr) < pattern[3]) + return 0; + + /* check known prefix */ + if (pattern[2] & SRE_INFO_PREFIX && pattern[5] > 1) { + /* <length> <skip> <prefix data> <overlap data> */ + for (i = 0; i < pattern[5]; i++) + if ((SRE_CODE) ptr[i] != pattern[7 + i]) + return 0; + return pattern[0] + 2 * pattern[6]; + } + return pattern[0]; +} +#endif + +/* The macros below should be used to protect recursive SRE_MATCH() + * calls that *failed* and do *not* return immediately (IOW, those + * that will backtrack). Explaining: + * + * - Recursive SRE_MATCH() returned true: that's usually a success + * (besides atypical cases like ASSERT_NOT), therefore there's no + * reason to restore lastmark; + * + * - Recursive SRE_MATCH() returned false but the current SRE_MATCH() + * is returning to the caller: If the current SRE_MATCH() is the + * top function of the recursion, returning false will be a matching + * failure, and it doesn't matter where lastmark is pointing to. + * If it's *not* the top function, it will be a recursive SRE_MATCH() + * failure by itself, and the calling SRE_MATCH() will have to deal + * with the failure by the same rules explained here (it will restore + * lastmark by itself if necessary); + * + * - Recursive SRE_MATCH() returned false, and will continue the + * outside 'for' loop: must be protected when breaking, since the next + * OP could potentially depend on lastmark; + * + * - Recursive SRE_MATCH() returned false, and will be called again + * inside a local for/while loop: must be protected between each + * loop iteration, since the recursive SRE_MATCH() could do anything, + * and could potentially depend on lastmark. + * + * For more information, check the discussion at SF patch #712900. + */ +#define LASTMARK_SAVE() \ + do { \ + ctx->lastmark = state->lastmark; \ + ctx->lastindex = state->lastindex; \ + } while (0) +#define LASTMARK_RESTORE() \ + do { \ + state->lastmark = ctx->lastmark; \ + state->lastindex = ctx->lastindex; \ + } while (0) + +#define RETURN_ERROR(i) do { return i; } while(0) +#define RETURN_FAILURE do { ret = 0; goto exit; } while(0) +#define RETURN_SUCCESS do { ret = 1; goto exit; } while(0) + +#define RETURN_ON_ERROR(i) \ + do { if (i < 0) RETURN_ERROR(i); } while (0) +#define RETURN_ON_SUCCESS(i) \ + do { RETURN_ON_ERROR(i); if (i > 0) RETURN_SUCCESS; } while (0) +#define RETURN_ON_FAILURE(i) \ + do { RETURN_ON_ERROR(i); if (i == 0) RETURN_FAILURE; } while (0) + +#define SFY(x) #x + +#define DATA_STACK_ALLOC(state, type, ptr) \ +do { \ + alloc_pos = state->data_stack_base; \ + TRACE(("allocating %s in %d (%d)\n", \ + SFY(type), alloc_pos, sizeof(type))); \ + if (state->data_stack_size < alloc_pos+sizeof(type)) { \ + int j = data_stack_grow(state, sizeof(type)); \ + if (j < 0) return j; \ + if (ctx_pos != -1) \ + DATA_STACK_LOOKUP_AT(state, SRE_MATCH_CONTEXT, ctx, ctx_pos); \ + } \ + ptr = (type*)(state->data_stack+alloc_pos); \ + state->data_stack_base += sizeof(type); \ +} while (0) + +#define DATA_STACK_LOOKUP_AT(state, type, ptr, pos) \ +do { \ + TRACE(("looking up %s at %d\n", SFY(type), pos)); \ + ptr = (type*)(state->data_stack+pos); \ +} while (0) + +#define DATA_STACK_PUSH(state, data, size) \ +do { \ + TRACE(("copy data in %p to %d (%d)\n", \ + data, state->data_stack_base, size)); \ + if (state->data_stack_size < state->data_stack_base+size) { \ + int j = data_stack_grow(state, size); \ + if (j < 0) return j; \ + if (ctx_pos != -1) \ + DATA_STACK_LOOKUP_AT(state, SRE_MATCH_CONTEXT, ctx, ctx_pos); \ + } \ + memcpy(state->data_stack+state->data_stack_base, data, size); \ + state->data_stack_base += size; \ +} while (0) + +#define DATA_STACK_POP(state, data, size, discard) \ +do { \ + TRACE(("copy data to %p from %d (%d)\n", \ + data, state->data_stack_base-size, size)); \ + memcpy(data, state->data_stack+state->data_stack_base-size, size); \ + if (discard) \ + state->data_stack_base -= size; \ +} while (0) + +#define DATA_STACK_POP_DISCARD(state, size) \ +do { \ + TRACE(("discard data from %d (%d)\n", \ + state->data_stack_base-size, size)); \ + state->data_stack_base -= size; \ +} while(0) + +#define DATA_PUSH(x) \ + DATA_STACK_PUSH(state, (x), sizeof(*(x))) +#define DATA_POP(x) \ + DATA_STACK_POP(state, (x), sizeof(*(x)), 1) +#define DATA_POP_DISCARD(x) \ + DATA_STACK_POP_DISCARD(state, sizeof(*(x))) +#define DATA_ALLOC(t,p) \ + DATA_STACK_ALLOC(state, t, p) +#define DATA_LOOKUP_AT(t,p,pos) \ + DATA_STACK_LOOKUP_AT(state,t,p,pos) + +#define MARK_PUSH(lastmark) \ + do if (lastmark > 0) { \ + i = lastmark; /* ctx->lastmark may change if reallocated */ \ + DATA_STACK_PUSH(state, state->mark, (i+1)*sizeof(void*)); \ + } while (0) +#define MARK_POP(lastmark) \ + do if (lastmark > 0) { \ + DATA_STACK_POP(state, state->mark, (lastmark+1)*sizeof(void*), 1); \ + } while (0) +#define MARK_POP_KEEP(lastmark) \ + do if (lastmark > 0) { \ + DATA_STACK_POP(state, state->mark, (lastmark+1)*sizeof(void*), 0); \ + } while (0) +#define MARK_POP_DISCARD(lastmark) \ + do if (lastmark > 0) { \ + DATA_STACK_POP_DISCARD(state, (lastmark+1)*sizeof(void*)); \ + } while (0) + +#define JUMP_NONE 0 +#define JUMP_MAX_UNTIL_1 1 +#define JUMP_MAX_UNTIL_2 2 +#define JUMP_MAX_UNTIL_3 3 +#define JUMP_MIN_UNTIL_1 4 +#define JUMP_MIN_UNTIL_2 5 +#define JUMP_MIN_UNTIL_3 6 +#define JUMP_REPEAT 7 +#define JUMP_REPEAT_ONE_1 8 +#define JUMP_REPEAT_ONE_2 9 +#define JUMP_MIN_REPEAT_ONE 10 +#define JUMP_BRANCH 11 +#define JUMP_ASSERT 12 +#define JUMP_ASSERT_NOT 13 + +#define DO_JUMP(jumpvalue, jumplabel, nextpattern) \ + DATA_ALLOC(SRE_MATCH_CONTEXT, nextctx); \ + nextctx->last_ctx_pos = ctx_pos; \ + nextctx->jump = jumpvalue; \ + nextctx->pattern = nextpattern; \ + ctx_pos = alloc_pos; \ + ctx = nextctx; \ + goto entrance; \ + jumplabel: \ + while (0) /* gcc doesn't like labels at end of scopes */ \ + +typedef struct { + Py_ssize_t last_ctx_pos; + Py_ssize_t jump; + SRE_CHAR* ptr; + SRE_CODE* pattern; + Py_ssize_t count; + Py_ssize_t lastmark; + Py_ssize_t lastindex; + union { + SRE_CODE chr; + SRE_REPEAT* rep; + } u; +} SRE_MATCH_CONTEXT; + +/* check if string matches the given pattern. returns <0 for + error, 0 for failure, and 1 for success */ +LOCAL(Py_ssize_t) +SRE_MATCH(SRE_STATE* state, SRE_CODE* pattern) +{ + SRE_CHAR* end = (SRE_CHAR *)state->end; + Py_ssize_t alloc_pos, ctx_pos = -1; + Py_ssize_t i, ret = 0; + Py_ssize_t jump; + + SRE_MATCH_CONTEXT* ctx; + SRE_MATCH_CONTEXT* nextctx; + + TRACE(("|%p|%p|ENTER\n", pattern, state->ptr)); + + DATA_ALLOC(SRE_MATCH_CONTEXT, ctx); + ctx->last_ctx_pos = -1; + ctx->jump = JUMP_NONE; + ctx->pattern = pattern; + ctx_pos = alloc_pos; + +entrance: + + ctx->ptr = (SRE_CHAR *)state->ptr; + + if (ctx->pattern[0] == SRE_OP_INFO) { + /* optimization info block */ + /* <INFO> <1=skip> <2=flags> <3=min> ... */ + if (ctx->pattern[3] && (end - ctx->ptr) < ctx->pattern[3]) { + TRACE(("reject (got %d chars, need %d)\n", + (end - ctx->ptr), ctx->pattern[3])); + RETURN_FAILURE; + } + ctx->pattern += ctx->pattern[1] + 1; + } + + for (;;) { + + switch (*ctx->pattern++) { + + case SRE_OP_MARK: + /* set mark */ + /* <MARK> <gid> */ + TRACE(("|%p|%p|MARK %d\n", ctx->pattern, + ctx->ptr, ctx->pattern[0])); + i = ctx->pattern[0]; + if (i & 1) + state->lastindex = i/2 + 1; + if (i > state->lastmark) { + /* state->lastmark is the highest valid index in the + state->mark array. If it is increased by more than 1, + the intervening marks must be set to NULL to signal + that these marks have not been encountered. */ + Py_ssize_t j = state->lastmark + 1; + while (j < i) + state->mark[j++] = NULL; + state->lastmark = i; + } + state->mark[i] = ctx->ptr; + ctx->pattern++; + break; + + case SRE_OP_LITERAL: + /* match literal string */ + /* <LITERAL> <code> */ + TRACE(("|%p|%p|LITERAL %d\n", ctx->pattern, + ctx->ptr, *ctx->pattern)); + if (ctx->ptr >= end || (SRE_CODE) ctx->ptr[0] != ctx->pattern[0]) + RETURN_FAILURE; + ctx->pattern++; + ctx->ptr++; + break; + + case SRE_OP_NOT_LITERAL: + /* match anything that is not literal character */ + /* <NOT_LITERAL> <code> */ + TRACE(("|%p|%p|NOT_LITERAL %d\n", ctx->pattern, + ctx->ptr, *ctx->pattern)); + if (ctx->ptr >= end || (SRE_CODE) ctx->ptr[0] == ctx->pattern[0]) + RETURN_FAILURE; + ctx->pattern++; + ctx->ptr++; + break; + + case SRE_OP_SUCCESS: + /* end of pattern */ + TRACE(("|%p|%p|SUCCESS\n", ctx->pattern, ctx->ptr)); + state->ptr = ctx->ptr; + RETURN_SUCCESS; + + case SRE_OP_AT: + /* match at given position */ + /* <AT> <code> */ + TRACE(("|%p|%p|AT %d\n", ctx->pattern, ctx->ptr, *ctx->pattern)); + if (!SRE_AT(state, ctx->ptr, *ctx->pattern)) + RETURN_FAILURE; + ctx->pattern++; + break; + + case SRE_OP_CATEGORY: + /* match at given category */ + /* <CATEGORY> <code> */ + TRACE(("|%p|%p|CATEGORY %d\n", ctx->pattern, + ctx->ptr, *ctx->pattern)); + if (ctx->ptr >= end || !sre_category(ctx->pattern[0], ctx->ptr[0])) + RETURN_FAILURE; + ctx->pattern++; + ctx->ptr++; + break; + + case SRE_OP_ANY: + /* match anything (except a newline) */ + /* <ANY> */ + TRACE(("|%p|%p|ANY\n", ctx->pattern, ctx->ptr)); + if (ctx->ptr >= end || SRE_IS_LINEBREAK(ctx->ptr[0])) + RETURN_FAILURE; + ctx->ptr++; + break; + + case SRE_OP_ANY_ALL: + /* match anything */ + /* <ANY_ALL> */ + TRACE(("|%p|%p|ANY_ALL\n", ctx->pattern, ctx->ptr)); + if (ctx->ptr >= end) + RETURN_FAILURE; + ctx->ptr++; + break; + + case SRE_OP_IN: + /* match set member (or non_member) */ + /* <IN> <skip> <set> */ + TRACE(("|%p|%p|IN\n", ctx->pattern, ctx->ptr)); + if (ctx->ptr >= end || !SRE_CHARSET(ctx->pattern + 1, *ctx->ptr)) + RETURN_FAILURE; + ctx->pattern += ctx->pattern[0]; + ctx->ptr++; + break; + + case SRE_OP_LITERAL_IGNORE: + TRACE(("|%p|%p|LITERAL_IGNORE %d\n", + ctx->pattern, ctx->ptr, ctx->pattern[0])); + if (ctx->ptr >= end || + state->lower(*ctx->ptr) != state->lower(*ctx->pattern)) + RETURN_FAILURE; + ctx->pattern++; + ctx->ptr++; + break; + + case SRE_OP_NOT_LITERAL_IGNORE: + TRACE(("|%p|%p|NOT_LITERAL_IGNORE %d\n", + ctx->pattern, ctx->ptr, *ctx->pattern)); + if (ctx->ptr >= end || + state->lower(*ctx->ptr) == state->lower(*ctx->pattern)) + RETURN_FAILURE; + ctx->pattern++; + ctx->ptr++; + break; + + case SRE_OP_IN_IGNORE: + TRACE(("|%p|%p|IN_IGNORE\n", ctx->pattern, ctx->ptr)); + if (ctx->ptr >= end + || !SRE_CHARSET(ctx->pattern+1, + (SRE_CODE)state->lower(*ctx->ptr))) + RETURN_FAILURE; + ctx->pattern += ctx->pattern[0]; + ctx->ptr++; + break; + + case SRE_OP_JUMP: + case SRE_OP_INFO: + /* jump forward */ + /* <JUMP> <offset> */ + TRACE(("|%p|%p|JUMP %d\n", ctx->pattern, + ctx->ptr, ctx->pattern[0])); + ctx->pattern += ctx->pattern[0]; + break; + + case SRE_OP_BRANCH: + /* alternation */ + /* <BRANCH> <0=skip> code <JUMP> ... <NULL> */ + TRACE(("|%p|%p|BRANCH\n", ctx->pattern, ctx->ptr)); + LASTMARK_SAVE(); + ctx->u.rep = state->repeat; + if (ctx->u.rep) + MARK_PUSH(ctx->lastmark); + for (; ctx->pattern[0]; ctx->pattern += ctx->pattern[0]) { + if (ctx->pattern[1] == SRE_OP_LITERAL && + (ctx->ptr >= end || + (SRE_CODE) *ctx->ptr != ctx->pattern[2])) + continue; + if (ctx->pattern[1] == SRE_OP_IN && + (ctx->ptr >= end || + !SRE_CHARSET(ctx->pattern + 3, (SRE_CODE) *ctx->ptr))) + continue; + state->ptr = ctx->ptr; + DO_JUMP(JUMP_BRANCH, jump_branch, ctx->pattern+1); + if (ret) { + if (ctx->u.rep) + MARK_POP_DISCARD(ctx->lastmark); + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + if (ctx->u.rep) + MARK_POP_KEEP(ctx->lastmark); + LASTMARK_RESTORE(); + } + if (ctx->u.rep) + MARK_POP_DISCARD(ctx->lastmark); + RETURN_FAILURE; + + case SRE_OP_REPEAT_ONE: + /* match repeated sequence (maximizing regexp) */ + + /* this operator only works if the repeated item is + exactly one character wide, and we're not already + collecting backtracking points. for other cases, + use the MAX_REPEAT operator */ + + /* <REPEAT_ONE> <skip> <1=min> <2=max> item <SUCCESS> tail */ + + TRACE(("|%p|%p|REPEAT_ONE %d %d\n", ctx->pattern, ctx->ptr, + ctx->pattern[1], ctx->pattern[2])); + + if (ctx->ptr + ctx->pattern[1] > end) + RETURN_FAILURE; /* cannot match */ + + state->ptr = ctx->ptr; + + ret = SRE_COUNT(state, ctx->pattern+3, ctx->pattern[2]); + RETURN_ON_ERROR(ret); + DATA_LOOKUP_AT(SRE_MATCH_CONTEXT, ctx, ctx_pos); + ctx->count = ret; + ctx->ptr += ctx->count; + + /* when we arrive here, count contains the number of + matches, and ctx->ptr points to the tail of the target + string. check if the rest of the pattern matches, + and backtrack if not. */ + + if (ctx->count < (Py_ssize_t) ctx->pattern[1]) + RETURN_FAILURE; + + if (ctx->pattern[ctx->pattern[0]] == SRE_OP_SUCCESS) { + /* tail is empty. we're finished */ + state->ptr = ctx->ptr; + RETURN_SUCCESS; + } + + LASTMARK_SAVE(); + + if (ctx->pattern[ctx->pattern[0]] == SRE_OP_LITERAL) { + /* tail starts with a literal. skip positions where + the rest of the pattern cannot possibly match */ + ctx->u.chr = ctx->pattern[ctx->pattern[0]+1]; + for (;;) { + while (ctx->count >= (Py_ssize_t) ctx->pattern[1] && + (ctx->ptr >= end || *ctx->ptr != ctx->u.chr)) { + ctx->ptr--; + ctx->count--; + } + if (ctx->count < (Py_ssize_t) ctx->pattern[1]) + break; + state->ptr = ctx->ptr; + DO_JUMP(JUMP_REPEAT_ONE_1, jump_repeat_one_1, + ctx->pattern+ctx->pattern[0]); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + + LASTMARK_RESTORE(); + + ctx->ptr--; + ctx->count--; + } + + } else { + /* general case */ + while (ctx->count >= (Py_ssize_t) ctx->pattern[1]) { + state->ptr = ctx->ptr; + DO_JUMP(JUMP_REPEAT_ONE_2, jump_repeat_one_2, + ctx->pattern+ctx->pattern[0]); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + ctx->ptr--; + ctx->count--; + LASTMARK_RESTORE(); + } + } + RETURN_FAILURE; + + case SRE_OP_MIN_REPEAT_ONE: + /* match repeated sequence (minimizing regexp) */ + + /* this operator only works if the repeated item is + exactly one character wide, and we're not already + collecting backtracking points. for other cases, + use the MIN_REPEAT operator */ + + /* <MIN_REPEAT_ONE> <skip> <1=min> <2=max> item <SUCCESS> tail */ + + TRACE(("|%p|%p|MIN_REPEAT_ONE %d %d\n", ctx->pattern, ctx->ptr, + ctx->pattern[1], ctx->pattern[2])); + + if (ctx->ptr + ctx->pattern[1] > end) + RETURN_FAILURE; /* cannot match */ + + state->ptr = ctx->ptr; + + if (ctx->pattern[1] == 0) + ctx->count = 0; + else { + /* count using pattern min as the maximum */ + ret = SRE_COUNT(state, ctx->pattern+3, ctx->pattern[1]); + RETURN_ON_ERROR(ret); + DATA_LOOKUP_AT(SRE_MATCH_CONTEXT, ctx, ctx_pos); + if (ret < (Py_ssize_t) ctx->pattern[1]) + /* didn't match minimum number of times */ + RETURN_FAILURE; + /* advance past minimum matches of repeat */ + ctx->count = ret; + ctx->ptr += ctx->count; + } + + if (ctx->pattern[ctx->pattern[0]] == SRE_OP_SUCCESS) { + /* tail is empty. we're finished */ + state->ptr = ctx->ptr; + RETURN_SUCCESS; + + } else { + /* general case */ + LASTMARK_SAVE(); + while ((Py_ssize_t)ctx->pattern[2] == 65535 + || ctx->count <= (Py_ssize_t)ctx->pattern[2]) { + state->ptr = ctx->ptr; + DO_JUMP(JUMP_MIN_REPEAT_ONE,jump_min_repeat_one, + ctx->pattern+ctx->pattern[0]); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + state->ptr = ctx->ptr; + ret = SRE_COUNT(state, ctx->pattern+3, 1); + RETURN_ON_ERROR(ret); + DATA_LOOKUP_AT(SRE_MATCH_CONTEXT, ctx, ctx_pos); + if (ret == 0) + break; + assert(ret == 1); + ctx->ptr++; + ctx->count++; + LASTMARK_RESTORE(); + } + } + RETURN_FAILURE; + + case SRE_OP_REPEAT: + /* create repeat context. all the hard work is done + by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ + /* <REPEAT> <skip> <1=min> <2=max> item <UNTIL> tail */ + TRACE(("|%p|%p|REPEAT %d %d\n", ctx->pattern, ctx->ptr, + ctx->pattern[1], ctx->pattern[2])); + + /* install new repeat context */ + ctx->u.rep = (SRE_REPEAT*) PyObject_MALLOC(sizeof(*ctx->u.rep)); + if (!ctx->u.rep) { + PyErr_NoMemory(); + RETURN_FAILURE; + } + ctx->u.rep->count = -1; + ctx->u.rep->pattern = ctx->pattern; + ctx->u.rep->prev = state->repeat; + ctx->u.rep->last_ptr = NULL; + state->repeat = ctx->u.rep; + + state->ptr = ctx->ptr; + DO_JUMP(JUMP_REPEAT, jump_repeat, ctx->pattern+ctx->pattern[0]); + state->repeat = ctx->u.rep->prev; + PyObject_FREE(ctx->u.rep); + + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + RETURN_FAILURE; + + case SRE_OP_MAX_UNTIL: + /* maximizing repeat */ + /* <REPEAT> <skip> <1=min> <2=max> item <MAX_UNTIL> tail */ + + /* FIXME: we probably need to deal with zero-width + matches in here... */ + + ctx->u.rep = state->repeat; + if (!ctx->u.rep) + RETURN_ERROR(SRE_ERROR_STATE); + + state->ptr = ctx->ptr; + + ctx->count = ctx->u.rep->count+1; + + TRACE(("|%p|%p|MAX_UNTIL %d\n", ctx->pattern, + ctx->ptr, ctx->count)); + + if (ctx->count < ctx->u.rep->pattern[1]) { + /* not enough matches */ + ctx->u.rep->count = ctx->count; + DO_JUMP(JUMP_MAX_UNTIL_1, jump_max_until_1, + ctx->u.rep->pattern+3); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + ctx->u.rep->count = ctx->count-1; + state->ptr = ctx->ptr; + RETURN_FAILURE; + } + + if ((ctx->count < ctx->u.rep->pattern[2] || + ctx->u.rep->pattern[2] == 65535) && + state->ptr != ctx->u.rep->last_ptr) { + /* we may have enough matches, but if we can + match another item, do so */ + ctx->u.rep->count = ctx->count; + LASTMARK_SAVE(); + MARK_PUSH(ctx->lastmark); + /* zero-width match protection */ + DATA_PUSH(&ctx->u.rep->last_ptr); + ctx->u.rep->last_ptr = state->ptr; + DO_JUMP(JUMP_MAX_UNTIL_2, jump_max_until_2, + ctx->u.rep->pattern+3); + DATA_POP(&ctx->u.rep->last_ptr); + if (ret) { + MARK_POP_DISCARD(ctx->lastmark); + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + MARK_POP(ctx->lastmark); + LASTMARK_RESTORE(); + ctx->u.rep->count = ctx->count-1; + state->ptr = ctx->ptr; + } + + /* cannot match more repeated items here. make sure the + tail matches */ + state->repeat = ctx->u.rep->prev; + DO_JUMP(JUMP_MAX_UNTIL_3, jump_max_until_3, ctx->pattern); + RETURN_ON_SUCCESS(ret); + state->repeat = ctx->u.rep; + state->ptr = ctx->ptr; + RETURN_FAILURE; + + case SRE_OP_MIN_UNTIL: + /* minimizing repeat */ + /* <REPEAT> <skip> <1=min> <2=max> item <MIN_UNTIL> tail */ + + ctx->u.rep = state->repeat; + if (!ctx->u.rep) + RETURN_ERROR(SRE_ERROR_STATE); + + state->ptr = ctx->ptr; + + ctx->count = ctx->u.rep->count+1; + + TRACE(("|%p|%p|MIN_UNTIL %d %p\n", ctx->pattern, + ctx->ptr, ctx->count, ctx->u.rep->pattern)); + + if (ctx->count < ctx->u.rep->pattern[1]) { + /* not enough matches */ + ctx->u.rep->count = ctx->count; + DO_JUMP(JUMP_MIN_UNTIL_1, jump_min_until_1, + ctx->u.rep->pattern+3); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + ctx->u.rep->count = ctx->count-1; + state->ptr = ctx->ptr; + RETURN_FAILURE; + } + + LASTMARK_SAVE(); + + /* see if the tail matches */ + state->repeat = ctx->u.rep->prev; + DO_JUMP(JUMP_MIN_UNTIL_2, jump_min_until_2, ctx->pattern); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + + state->repeat = ctx->u.rep; + state->ptr = ctx->ptr; + + LASTMARK_RESTORE(); + + if (ctx->count >= ctx->u.rep->pattern[2] + && ctx->u.rep->pattern[2] != 65535) + RETURN_FAILURE; + + ctx->u.rep->count = ctx->count; + DO_JUMP(JUMP_MIN_UNTIL_3,jump_min_until_3, + ctx->u.rep->pattern+3); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_SUCCESS; + } + ctx->u.rep->count = ctx->count-1; + state->ptr = ctx->ptr; + RETURN_FAILURE; + + case SRE_OP_GROUPREF: + /* match backreference */ + TRACE(("|%p|%p|GROUPREF %d\n", ctx->pattern, + ctx->ptr, ctx->pattern[0])); + i = ctx->pattern[0]; + { + Py_ssize_t groupref = i+i; + if (groupref >= state->lastmark) { + RETURN_FAILURE; + } else { + SRE_CHAR* p = (SRE_CHAR*) state->mark[groupref]; + SRE_CHAR* e = (SRE_CHAR*) state->mark[groupref+1]; + if (!p || !e || e < p) + RETURN_FAILURE; + while (p < e) { + if (ctx->ptr >= end || *ctx->ptr != *p) + RETURN_FAILURE; + p++; ctx->ptr++; + } + } + } + ctx->pattern++; + break; + + case SRE_OP_GROUPREF_IGNORE: + /* match backreference */ + TRACE(("|%p|%p|GROUPREF_IGNORE %d\n", ctx->pattern, + ctx->ptr, ctx->pattern[0])); + i = ctx->pattern[0]; + { + Py_ssize_t groupref = i+i; + if (groupref >= state->lastmark) { + RETURN_FAILURE; + } else { + SRE_CHAR* p = (SRE_CHAR*) state->mark[groupref]; + SRE_CHAR* e = (SRE_CHAR*) state->mark[groupref+1]; + if (!p || !e || e < p) + RETURN_FAILURE; + while (p < e) { + if (ctx->ptr >= end || + state->lower(*ctx->ptr) != state->lower(*p)) + RETURN_FAILURE; + p++; ctx->ptr++; + } + } + } + ctx->pattern++; + break; + + case SRE_OP_GROUPREF_EXISTS: + TRACE(("|%p|%p|GROUPREF_EXISTS %d\n", ctx->pattern, + ctx->ptr, ctx->pattern[0])); + /* <GROUPREF_EXISTS> <group> <skip> codeyes <JUMP> codeno ... */ + i = ctx->pattern[0]; + { + Py_ssize_t groupref = i+i; + if (groupref >= state->lastmark) { + ctx->pattern += ctx->pattern[1]; + break; + } else { + SRE_CHAR* p = (SRE_CHAR*) state->mark[groupref]; + SRE_CHAR* e = (SRE_CHAR*) state->mark[groupref+1]; + if (!p || !e || e < p) { + ctx->pattern += ctx->pattern[1]; + break; + } + } + } + ctx->pattern += 2; + break; + + case SRE_OP_ASSERT: + /* assert subpattern */ + /* <ASSERT> <skip> <back> <pattern> */ + TRACE(("|%p|%p|ASSERT %d\n", ctx->pattern, + ctx->ptr, ctx->pattern[1])); + state->ptr = ctx->ptr - ctx->pattern[1]; + if (state->ptr < state->beginning) + RETURN_FAILURE; + DO_JUMP(JUMP_ASSERT, jump_assert, ctx->pattern+2); + RETURN_ON_FAILURE(ret); + ctx->pattern += ctx->pattern[0]; + break; + + case SRE_OP_ASSERT_NOT: + /* assert not subpattern */ + /* <ASSERT_NOT> <skip> <back> <pattern> */ + TRACE(("|%p|%p|ASSERT_NOT %d\n", ctx->pattern, + ctx->ptr, ctx->pattern[1])); + state->ptr = ctx->ptr - ctx->pattern[1]; + if (state->ptr >= state->beginning) { + DO_JUMP(JUMP_ASSERT_NOT, jump_assert_not, ctx->pattern+2); + if (ret) { + RETURN_ON_ERROR(ret); + RETURN_FAILURE; + } + } + ctx->pattern += ctx->pattern[0]; + break; + + case SRE_OP_FAILURE: + /* immediate failure */ + TRACE(("|%p|%p|FAILURE\n", ctx->pattern, ctx->ptr)); + RETURN_FAILURE; + + default: + TRACE(("|%p|%p|UNKNOWN %d\n", ctx->pattern, ctx->ptr, + ctx->pattern[-1])); + RETURN_ERROR(SRE_ERROR_ILLEGAL); + } + } + +exit: + ctx_pos = ctx->last_ctx_pos; + jump = ctx->jump; + DATA_POP_DISCARD(ctx); + if (ctx_pos == -1) + return ret; + DATA_LOOKUP_AT(SRE_MATCH_CONTEXT, ctx, ctx_pos); + + switch (jump) { + case JUMP_MAX_UNTIL_2: + TRACE(("|%p|%p|JUMP_MAX_UNTIL_2\n", ctx->pattern, ctx->ptr)); + goto jump_max_until_2; + case JUMP_MAX_UNTIL_3: + TRACE(("|%p|%p|JUMP_MAX_UNTIL_3\n", ctx->pattern, ctx->ptr)); + goto jump_max_until_3; + case JUMP_MIN_UNTIL_2: + TRACE(("|%p|%p|JUMP_MIN_UNTIL_2\n", ctx->pattern, ctx->ptr)); + goto jump_min_until_2; + case JUMP_MIN_UNTIL_3: + TRACE(("|%p|%p|JUMP_MIN_UNTIL_3\n", ctx->pattern, ctx->ptr)); + goto jump_min_until_3; + case JUMP_BRANCH: + TRACE(("|%p|%p|JUMP_BRANCH\n", ctx->pattern, ctx->ptr)); + goto jump_branch; + case JUMP_MAX_UNTIL_1: + TRACE(("|%p|%p|JUMP_MAX_UNTIL_1\n", ctx->pattern, ctx->ptr)); + goto jump_max_until_1; + case JUMP_MIN_UNTIL_1: + TRACE(("|%p|%p|JUMP_MIN_UNTIL_1\n", ctx->pattern, ctx->ptr)); + goto jump_min_until_1; + case JUMP_REPEAT: + TRACE(("|%p|%p|JUMP_REPEAT\n", ctx->pattern, ctx->ptr)); + goto jump_repeat; + case JUMP_REPEAT_ONE_1: + TRACE(("|%p|%p|JUMP_REPEAT_ONE_1\n", ctx->pattern, ctx->ptr)); + goto jump_repeat_one_1; + case JUMP_REPEAT_ONE_2: + TRACE(("|%p|%p|JUMP_REPEAT_ONE_2\n", ctx->pattern, ctx->ptr)); + goto jump_repeat_one_2; + case JUMP_MIN_REPEAT_ONE: + TRACE(("|%p|%p|JUMP_MIN_REPEAT_ONE\n", ctx->pattern, ctx->ptr)); + goto jump_min_repeat_one; + case JUMP_ASSERT: + TRACE(("|%p|%p|JUMP_ASSERT\n", ctx->pattern, ctx->ptr)); + goto jump_assert; + case JUMP_ASSERT_NOT: + TRACE(("|%p|%p|JUMP_ASSERT_NOT\n", ctx->pattern, ctx->ptr)); + goto jump_assert_not; + case JUMP_NONE: + TRACE(("|%p|%p|RETURN %d\n", ctx->pattern, ctx->ptr, ret)); + break; + } + + return ret; /* should never get here */ +} + +LOCAL(Py_ssize_t) +SRE_SEARCH(SRE_STATE* state, SRE_CODE* pattern) +{ + SRE_CHAR* ptr = (SRE_CHAR *)state->start; + SRE_CHAR* end = (SRE_CHAR *)state->end; + Py_ssize_t status = 0; + Py_ssize_t prefix_len = 0; + Py_ssize_t prefix_skip = 0; + SRE_CODE* prefix = NULL; + SRE_CODE* charset = NULL; + SRE_CODE* overlap = NULL; + int flags = 0; + + if (pattern[0] == SRE_OP_INFO) { + /* optimization info block */ + /* <INFO> <1=skip> <2=flags> <3=min> <4=max> <5=prefix info> */ + + flags = pattern[2]; + + if (pattern[3] > 1) { + /* adjust end point (but make sure we leave at least one + character in there, so literal search will work) */ + end -= pattern[3]-1; + if (end <= ptr) + end = ptr+1; + } + + if (flags & SRE_INFO_PREFIX) { + /* pattern starts with a known prefix */ + /* <length> <skip> <prefix data> <overlap data> */ + prefix_len = pattern[5]; + prefix_skip = pattern[6]; + prefix = pattern + 7; + overlap = prefix + prefix_len - 1; + } else if (flags & SRE_INFO_CHARSET) + /* pattern starts with a character from a known set */ + /* <charset> */ + charset = pattern + 5; + + pattern += 1 + pattern[1]; + } + + TRACE(("prefix = %p %d %d\n", prefix, prefix_len, prefix_skip)); + TRACE(("charset = %p\n", charset)); + +#if defined(USE_FAST_SEARCH) + if (prefix_len > 1) { + /* pattern starts with a known prefix. use the overlap + table to skip forward as fast as we possibly can */ + Py_ssize_t i = 0; + end = (SRE_CHAR *)state->end; + while (ptr < end) { + for (;;) { + if ((SRE_CODE) ptr[0] != prefix[i]) { + if (!i) + break; + else + i = overlap[i]; + } else { + if (++i == prefix_len) { + /* found a potential match */ + TRACE(("|%p|%p|SEARCH SCAN\n", pattern, ptr)); + state->start = ptr + 1 - prefix_len; + state->ptr = ptr + 1 - prefix_len + prefix_skip; + if (flags & SRE_INFO_LITERAL) + return 1; /* we got all of it */ + status = SRE_MATCH(state, pattern + 2*prefix_skip); + if (status != 0) + return status; + /* close but no cigar -- try again */ + i = overlap[i]; + } + break; + } + } + ptr++; + } + return 0; + } +#endif + + if (pattern[0] == SRE_OP_LITERAL) { + /* pattern starts with a literal character. this is used + for short prefixes, and if fast search is disabled */ + SRE_CODE chr = pattern[1]; + end = (SRE_CHAR *)state->end; + for (;;) { + while (ptr < end && (SRE_CODE) ptr[0] != chr) + ptr++; + if (ptr >= end) + return 0; + TRACE(("|%p|%p|SEARCH LITERAL\n", pattern, ptr)); + state->start = ptr; + state->ptr = ++ptr; + if (flags & SRE_INFO_LITERAL) + return 1; /* we got all of it */ + status = SRE_MATCH(state, pattern + 2); + if (status != 0) + break; + } + } else if (charset) { + /* pattern starts with a character from a known set */ + end = (SRE_CHAR *)state->end; + for (;;) { + while (ptr < end && !SRE_CHARSET(charset, ptr[0])) + ptr++; + if (ptr >= end) + return 0; + TRACE(("|%p|%p|SEARCH CHARSET\n", pattern, ptr)); + state->start = ptr; + state->ptr = ptr; + status = SRE_MATCH(state, pattern); + if (status != 0) + break; + ptr++; + } + } else + /* general case */ + while (ptr <= end) { + TRACE(("|%p|%p|SEARCH\n", pattern, ptr)); + state->start = state->ptr = ptr++; + status = SRE_MATCH(state, pattern); + if (status != 0) + break; + } + + return status; +} + +LOCAL(int) +SRE_LITERAL_TEMPLATE(SRE_CHAR* ptr, Py_ssize_t len) +{ + /* check if given string is a literal template (i.e. no escapes) */ + while (len-- > 0) + if (*ptr++ == '\\') + return 0; + return 1; +} + +#if !defined(SRE_RECURSIVE) + +/* -------------------------------------------------------------------- */ +/* factories and destructors */ + +/* see sre.h for object declarations */ +static PyObject*pattern_new_match(PatternObject*, SRE_STATE*, int); +static PyObject*pattern_scanner(PatternObject*, PyObject*); + +static PyObject * +sre_codesize(PyObject* self, PyObject *unused) +{ + return Py_BuildValue("l", sizeof(SRE_CODE)); +} + +static PyObject * +sre_getlower(PyObject* self, PyObject* args) +{ + int character, flags; + if (!PyArg_ParseTuple(args, "ii", &character, &flags)) + return NULL; + if (flags & SRE_FLAG_LOCALE) + return Py_BuildValue("i", sre_lower_locale(character)); + if (flags & SRE_FLAG_UNICODE) +#if defined(HAVE_UNICODE) + return Py_BuildValue("i", sre_lower_unicode(character)); +#else + return Py_BuildValue("i", sre_lower_locale(character)); +#endif + return Py_BuildValue("i", sre_lower(character)); +} + +LOCAL(void) +state_reset(SRE_STATE* state) +{ + /* FIXME: dynamic! */ + /*memset(state->mark, 0, sizeof(*state->mark) * SRE_MARK_SIZE);*/ + + state->lastmark = -1; + state->lastindex = -1; + + state->repeat = NULL; + + data_stack_dealloc(state); +} + +static void* +getstring(PyObject* string, Py_ssize_t* p_length, int* p_charsize) +{ + /* given a python object, return a data pointer, a length (in + characters), and a character size. return NULL if the object + is not a string (or not compatible) */ + + PyBufferProcs *buffer; + Py_ssize_t size, bytes; + int charsize; + void* ptr; + +#if defined(HAVE_UNICODE) + if (PyUnicode_Check(string)) { + /* unicode strings doesn't always support the buffer interface */ + ptr = (void*) PyUnicode_AS_DATA(string); + bytes = PyUnicode_GET_DATA_SIZE(string); + size = PyUnicode_GET_SIZE(string); + charsize = sizeof(Py_UNICODE); + + } else { +#endif + + /* get pointer to string buffer */ + buffer = string->ob_type->tp_as_buffer; + if (!buffer || !buffer->bf_getreadbuffer || !buffer->bf_getsegcount || + buffer->bf_getsegcount(string, NULL) != 1) { + PyErr_SetString(PyExc_TypeError, "expected string or buffer"); + return NULL; + } + + /* determine buffer size */ + bytes = buffer->bf_getreadbuffer(string, 0, &ptr); + if (bytes < 0) { + PyErr_SetString(PyExc_TypeError, "buffer has negative size"); + return NULL; + } + + /* determine character size */ +#if PY_VERSION_HEX >= 0x01060000 + size = PyObject_Size(string); +#else + size = PyObject_Length(string); +#endif + + if (PyString_Check(string) || bytes == size) + charsize = 1; +#if defined(HAVE_UNICODE) + else if (bytes == (Py_ssize_t) (size * sizeof(Py_UNICODE))) + charsize = sizeof(Py_UNICODE); +#endif + else { + PyErr_SetString(PyExc_TypeError, "buffer size mismatch"); + return NULL; + } + +#if defined(HAVE_UNICODE) + } +#endif + + *p_length = size; + *p_charsize = charsize; + + return ptr; +} + +LOCAL(PyObject*) +state_init(SRE_STATE* state, PatternObject* pattern, PyObject* string, + Py_ssize_t start, Py_ssize_t end) +{ + /* prepare state object */ + + Py_ssize_t length; + int charsize; + void* ptr; + + memset(state, 0, sizeof(SRE_STATE)); + + state->lastmark = -1; + state->lastindex = -1; + + ptr = getstring(string, &length, &charsize); + if (!ptr) + return NULL; + + /* adjust boundaries */ + if (start < 0) + start = 0; + else if (start > length) + start = length; + + if (end < 0) + end = 0; + else if (end > length) + end = length; + + state->charsize = charsize; + + state->beginning = ptr; + + state->start = (void*) ((char*) ptr + start * state->charsize); + state->end = (void*) ((char*) ptr + end * state->charsize); + + Py_INCREF(string); + state->string = string; + state->pos = start; + state->endpos = end; + + if (pattern->flags & SRE_FLAG_LOCALE) + state->lower = sre_lower_locale; + else if (pattern->flags & SRE_FLAG_UNICODE) +#if defined(HAVE_UNICODE) + state->lower = sre_lower_unicode; +#else + state->lower = sre_lower_locale; +#endif + else + state->lower = sre_lower; + + return string; +} + +LOCAL(void) +state_fini(SRE_STATE* state) +{ + Py_XDECREF(state->string); + data_stack_dealloc(state); +} + +/* calculate offset from start of string */ +#define STATE_OFFSET(state, member)\ + (((char*)(member) - (char*)(state)->beginning) / (state)->charsize) + +LOCAL(PyObject*) +state_getslice(SRE_STATE* state, Py_ssize_t index, PyObject* string, int empty) +{ + Py_ssize_t i, j; + + index = (index - 1) * 2; + + if (string == Py_None || index >= state->lastmark || !state->mark[index] || !state->mark[index+1]) { + if (empty) + /* want empty string */ + i = j = 0; + else { + Py_INCREF(Py_None); + return Py_None; + } + } else { + i = STATE_OFFSET(state, state->mark[index]); + j = STATE_OFFSET(state, state->mark[index+1]); + } + + return PySequence_GetSlice(string, i, j); +} + +static void +pattern_error(int status) +{ + switch (status) { + case SRE_ERROR_RECURSION_LIMIT: + PyErr_SetString( + PyExc_RuntimeError, + "maximum recursion limit exceeded" + ); + break; + case SRE_ERROR_MEMORY: + PyErr_NoMemory(); + break; + default: + /* other error codes indicate compiler/engine bugs */ + PyErr_SetString( + PyExc_RuntimeError, + "internal error in regular expression engine" + ); + } +} + +static void +pattern_dealloc(PatternObject* self) +{ + if (self->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) self); + Py_XDECREF(self->pattern); + Py_XDECREF(self->groupindex); + Py_XDECREF(self->indexgroup); + PyObject_DEL(self); +} + +static PyObject* +pattern_match(PatternObject* self, PyObject* args, PyObject* kw) +{ + SRE_STATE state; + int status; + + PyObject* string; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + static char* kwlist[] = { "pattern", "pos", "endpos", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:match", kwlist, + &string, &start, &end)) + return NULL; + + string = state_init(&state, self, string, start, end); + if (!string) + return NULL; + + state.ptr = state.start; + + TRACE(("|%p|%p|MATCH\n", PatternObject_GetCode(self), state.ptr)); + + if (state.charsize == 1) { + status = sre_match(&state, PatternObject_GetCode(self)); + } else { +#if defined(HAVE_UNICODE) + status = sre_umatch(&state, PatternObject_GetCode(self)); +#endif + } + + TRACE(("|%p|%p|END\n", PatternObject_GetCode(self), state.ptr)); + if (PyErr_Occurred()) + return NULL; + + state_fini(&state); + + return pattern_new_match(self, &state, status); +} + +static PyObject* +pattern_search(PatternObject* self, PyObject* args, PyObject* kw) +{ + SRE_STATE state; + int status; + + PyObject* string; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + static char* kwlist[] = { "pattern", "pos", "endpos", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:search", kwlist, + &string, &start, &end)) + return NULL; + + string = state_init(&state, self, string, start, end); + if (!string) + return NULL; + + TRACE(("|%p|%p|SEARCH\n", PatternObject_GetCode(self), state.ptr)); + + if (state.charsize == 1) { + status = sre_search(&state, PatternObject_GetCode(self)); + } else { +#if defined(HAVE_UNICODE) + status = sre_usearch(&state, PatternObject_GetCode(self)); +#endif + } + + TRACE(("|%p|%p|END\n", PatternObject_GetCode(self), state.ptr)); + + state_fini(&state); + + if (PyErr_Occurred()) + return NULL; + + return pattern_new_match(self, &state, status); +} + +static PyObject* +call(char* module, char* function, PyObject* args) +{ + PyObject* name; + PyObject* mod; + PyObject* func; + PyObject* result; + + if (!args) + return NULL; + name = PyString_FromString(module); + if (!name) + return NULL; + mod = PyImport_Import(name); + Py_DECREF(name); + if (!mod) + return NULL; + func = PyObject_GetAttrString(mod, function); + Py_DECREF(mod); + if (!func) + return NULL; + result = PyObject_CallObject(func, args); + Py_DECREF(func); + Py_DECREF(args); + return result; +} + +#ifdef USE_BUILTIN_COPY +static int +deepcopy(PyObject** object, PyObject* memo) +{ + PyObject* copy; + + copy = call( + "copy", "deepcopy", + PyTuple_Pack(2, *object, memo) + ); + if (!copy) + return 0; + + Py_DECREF(*object); + *object = copy; + + return 1; /* success */ +} +#endif + +static PyObject* +join_list(PyObject* list, PyObject* pattern) +{ + /* join list elements */ + + PyObject* joiner; +#if PY_VERSION_HEX >= 0x01060000 + PyObject* function; + PyObject* args; +#endif + PyObject* result; + + switch (PyList_GET_SIZE(list)) { + case 0: + Py_DECREF(list); + return PySequence_GetSlice(pattern, 0, 0); + case 1: + result = PyList_GET_ITEM(list, 0); + Py_INCREF(result); + Py_DECREF(list); + return result; + } + + /* two or more elements: slice out a suitable separator from the + first member, and use that to join the entire list */ + + joiner = PySequence_GetSlice(pattern, 0, 0); + if (!joiner) + return NULL; + +#if PY_VERSION_HEX >= 0x01060000 + function = PyObject_GetAttrString(joiner, "join"); + if (!function) { + Py_DECREF(joiner); + return NULL; + } + args = PyTuple_New(1); + if (!args) { + Py_DECREF(function); + Py_DECREF(joiner); + return NULL; + } + PyTuple_SET_ITEM(args, 0, list); + result = PyObject_CallObject(function, args); + Py_DECREF(args); /* also removes list */ + Py_DECREF(function); +#else + result = call( + "string", "join", + PyTuple_Pack(2, list, joiner) + ); +#endif + Py_DECREF(joiner); + + return result; +} + +static PyObject* +pattern_findall(PatternObject* self, PyObject* args, PyObject* kw) +{ + SRE_STATE state; + PyObject* list; + int status; + Py_ssize_t i, b, e; + + PyObject* string; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + static char* kwlist[] = { "source", "pos", "endpos", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|nn:findall", kwlist, + &string, &start, &end)) + return NULL; + + string = state_init(&state, self, string, start, end); + if (!string) + return NULL; + + list = PyList_New(0); + if (!list) { + state_fini(&state); + return NULL; + } + + while (state.start <= state.end) { + + PyObject* item; + + state_reset(&state); + + state.ptr = state.start; + + if (state.charsize == 1) { + status = sre_search(&state, PatternObject_GetCode(self)); + } else { +#if defined(HAVE_UNICODE) + status = sre_usearch(&state, PatternObject_GetCode(self)); +#endif + } + + if (PyErr_Occurred()) + goto error; + + if (status <= 0) { + if (status == 0) + break; + pattern_error(status); + goto error; + } + + /* don't bother to build a match object */ + switch (self->groups) { + case 0: + b = STATE_OFFSET(&state, state.start); + e = STATE_OFFSET(&state, state.ptr); + item = PySequence_GetSlice(string, b, e); + if (!item) + goto error; + break; + case 1: + item = state_getslice(&state, 1, string, 1); + if (!item) + goto error; + break; + default: + item = PyTuple_New(self->groups); + if (!item) + goto error; + for (i = 0; i < self->groups; i++) { + PyObject* o = state_getslice(&state, i+1, string, 1); + if (!o) { + Py_DECREF(item); + goto error; + } + PyTuple_SET_ITEM(item, i, o); + } + break; + } + + status = PyList_Append(list, item); + Py_DECREF(item); + if (status < 0) + goto error; + + if (state.ptr == state.start) + state.start = (void*) ((char*) state.ptr + state.charsize); + else + state.start = state.ptr; + + } + + state_fini(&state); + return list; + +error: + Py_DECREF(list); + state_fini(&state); + return NULL; + +} + +#if PY_VERSION_HEX >= 0x02020000 +static PyObject* +pattern_finditer(PatternObject* pattern, PyObject* args) +{ + PyObject* scanner; + PyObject* search; + PyObject* iterator; + + scanner = pattern_scanner(pattern, args); + if (!scanner) + return NULL; + + search = PyObject_GetAttrString(scanner, "search"); + Py_DECREF(scanner); + if (!search) + return NULL; + + iterator = PyCallIter_New(search, Py_None); + Py_DECREF(search); + + return iterator; +} +#endif + +static PyObject* +pattern_split(PatternObject* self, PyObject* args, PyObject* kw) +{ + SRE_STATE state; + PyObject* list; + PyObject* item; + int status; + Py_ssize_t n; + Py_ssize_t i; + void* last; + + PyObject* string; + Py_ssize_t maxsplit = 0; + static char* kwlist[] = { "source", "maxsplit", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "O|n:split", kwlist, + &string, &maxsplit)) + return NULL; + + string = state_init(&state, self, string, 0, PY_SSIZE_T_MAX); + if (!string) + return NULL; + + list = PyList_New(0); + if (!list) { + state_fini(&state); + return NULL; + } + + n = 0; + last = state.start; + + while (!maxsplit || n < maxsplit) { + + state_reset(&state); + + state.ptr = state.start; + + if (state.charsize == 1) { + status = sre_search(&state, PatternObject_GetCode(self)); + } else { +#if defined(HAVE_UNICODE) + status = sre_usearch(&state, PatternObject_GetCode(self)); +#endif + } + + if (PyErr_Occurred()) + goto error; + + if (status <= 0) { + if (status == 0) + break; + pattern_error(status); + goto error; + } + + if (state.start == state.ptr) { + if (last == state.end) + break; + /* skip one character */ + state.start = (void*) ((char*) state.ptr + state.charsize); + continue; + } + + /* get segment before this match */ + item = PySequence_GetSlice( + string, STATE_OFFSET(&state, last), + STATE_OFFSET(&state, state.start) + ); + if (!item) + goto error; + status = PyList_Append(list, item); + Py_DECREF(item); + if (status < 0) + goto error; + + /* add groups (if any) */ + for (i = 0; i < self->groups; i++) { + item = state_getslice(&state, i+1, string, 0); + if (!item) + goto error; + status = PyList_Append(list, item); + Py_DECREF(item); + if (status < 0) + goto error; + } + + n = n + 1; + + last = state.start = state.ptr; + + } + + /* get segment following last match (even if empty) */ + item = PySequence_GetSlice( + string, STATE_OFFSET(&state, last), state.endpos + ); + if (!item) + goto error; + status = PyList_Append(list, item); + Py_DECREF(item); + if (status < 0) + goto error; + + state_fini(&state); + return list; + +error: + Py_DECREF(list); + state_fini(&state); + return NULL; + +} + +static PyObject* +pattern_subx(PatternObject* self, PyObject* ptemplate, PyObject* string, + Py_ssize_t count, Py_ssize_t subn) +{ + SRE_STATE state; + PyObject* list; + PyObject* item; + PyObject* filter; + PyObject* args; + PyObject* match; + void* ptr; + int status; + Py_ssize_t n; + Py_ssize_t i, b, e; + int bint; + int filter_is_callable; + + if (PyCallable_Check(ptemplate)) { + /* sub/subn takes either a function or a template */ + filter = ptemplate; + Py_INCREF(filter); + filter_is_callable = 1; + } else { + /* if not callable, check if it's a literal string */ + int literal; + ptr = getstring(ptemplate, &n, &bint); + b = bint; + if (ptr) { + if (b == 1) { + literal = sre_literal_template((unsigned char *)ptr, n); + } else { +#if defined(HAVE_UNICODE) + literal = sre_uliteral_template((Py_UNICODE *)ptr, n); +#endif + } + } else { + PyErr_Clear(); + literal = 0; + } + if (literal) { + filter = ptemplate; + Py_INCREF(filter); + filter_is_callable = 0; + } else { + /* not a literal; hand it over to the template compiler */ + filter = call( + SRE_PY_MODULE, "_subx", + PyTuple_Pack(2, self, ptemplate) + ); + if (!filter) + return NULL; + filter_is_callable = PyCallable_Check(filter); + } + } + + string = state_init(&state, self, string, 0, PY_SSIZE_T_MAX); + if (!string) { + Py_DECREF(filter); + return NULL; + } + + list = PyList_New(0); + if (!list) { + Py_DECREF(filter); + state_fini(&state); + return NULL; + } + + n = i = 0; + + while (!count || n < count) { + + state_reset(&state); + + state.ptr = state.start; + + if (state.charsize == 1) { + status = sre_search(&state, PatternObject_GetCode(self)); + } else { +#if defined(HAVE_UNICODE) + status = sre_usearch(&state, PatternObject_GetCode(self)); +#endif + } + + if (PyErr_Occurred()) + goto error; + + if (status <= 0) { + if (status == 0) + break; + pattern_error(status); + goto error; + } + + b = STATE_OFFSET(&state, state.start); + e = STATE_OFFSET(&state, state.ptr); + + if (i < b) { + /* get segment before this match */ + item = PySequence_GetSlice(string, i, b); + if (!item) + goto error; + status = PyList_Append(list, item); + Py_DECREF(item); + if (status < 0) + goto error; + + } else if (i == b && i == e && n > 0) + /* ignore empty match on latest position */ + goto next; + + if (filter_is_callable) { + /* pass match object through filter */ + match = pattern_new_match(self, &state, 1); + if (!match) + goto error; + args = PyTuple_Pack(1, match); + if (!args) { + Py_DECREF(match); + goto error; + } + item = PyObject_CallObject(filter, args); + Py_DECREF(args); + Py_DECREF(match); + if (!item) + goto error; + } else { + /* filter is literal string */ + item = filter; + Py_INCREF(item); + } + + /* add to list */ + if (item != Py_None) { + status = PyList_Append(list, item); + Py_DECREF(item); + if (status < 0) + goto error; + } + + i = e; + n = n + 1; + +next: + /* move on */ + if (state.ptr == state.start) + state.start = (void*) ((char*) state.ptr + state.charsize); + else + state.start = state.ptr; + + } + + /* get segment following last match */ + if (i < state.endpos) { + item = PySequence_GetSlice(string, i, state.endpos); + if (!item) + goto error; + status = PyList_Append(list, item); + Py_DECREF(item); + if (status < 0) + goto error; + } + + state_fini(&state); + + Py_DECREF(filter); + + /* convert list to single string (also removes list) */ + item = join_list(list, self->pattern); + + if (!item) + return NULL; + + if (subn) + return Py_BuildValue("Ni", item, n); + + return item; + +error: + Py_DECREF(list); + state_fini(&state); + Py_DECREF(filter); + return NULL; + +} + +static PyObject* +pattern_sub(PatternObject* self, PyObject* args, PyObject* kw) +{ + PyObject* ptemplate; + PyObject* string; + Py_ssize_t count = 0; + static char* kwlist[] = { "repl", "string", "count", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|n:sub", kwlist, + &ptemplate, &string, &count)) + return NULL; + + return pattern_subx(self, ptemplate, string, count, 0); +} + +static PyObject* +pattern_subn(PatternObject* self, PyObject* args, PyObject* kw) +{ + PyObject* ptemplate; + PyObject* string; + Py_ssize_t count = 0; + static char* kwlist[] = { "repl", "string", "count", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "OO|n:subn", kwlist, + &ptemplate, &string, &count)) + return NULL; + + return pattern_subx(self, ptemplate, string, count, 1); +} + +static PyObject* +pattern_copy(PatternObject* self, PyObject *unused) +{ +#ifdef USE_BUILTIN_COPY + PatternObject* copy; + int offset; + + copy = PyObject_NEW_VAR(PatternObject, &Pattern_Type, self->codesize); + if (!copy) + return NULL; + + offset = offsetof(PatternObject, groups); + + Py_XINCREF(self->groupindex); + Py_XINCREF(self->indexgroup); + Py_XINCREF(self->pattern); + + memcpy((char*) copy + offset, (char*) self + offset, + sizeof(PatternObject) + self->codesize * sizeof(SRE_CODE) - offset); + copy->weakreflist = NULL; + + return (PyObject*) copy; +#else + PyErr_SetString(PyExc_TypeError, "cannot copy this pattern object"); + return NULL; +#endif +} + +static PyObject* +pattern_deepcopy(PatternObject* self, PyObject* memo) +{ +#ifdef USE_BUILTIN_COPY + PatternObject* copy; + + copy = (PatternObject*) pattern_copy(self); + if (!copy) + return NULL; + + if (!deepcopy(&copy->groupindex, memo) || + !deepcopy(&copy->indexgroup, memo) || + !deepcopy(&copy->pattern, memo)) { + Py_DECREF(copy); + return NULL; + } + +#else + PyErr_SetString(PyExc_TypeError, "cannot deepcopy this pattern object"); + return NULL; +#endif +} + +PyDoc_STRVAR(pattern_match_doc, +"match(string[, pos[, endpos]]) --> match object or None.\n\ + Matches zero or more characters at the beginning of the string"); + +PyDoc_STRVAR(pattern_search_doc, +"search(string[, pos[, endpos]]) --> match object or None.\n\ + Scan through string looking for a match, and return a corresponding\n\ + MatchObject instance. Return None if no position in the string matches."); + +PyDoc_STRVAR(pattern_split_doc, +"split(string[, maxsplit = 0]) --> list.\n\ + Split string by the occurrences of pattern."); + +PyDoc_STRVAR(pattern_findall_doc, +"findall(string[, pos[, endpos]]) --> list.\n\ + Return a list of all non-overlapping matches of pattern in string."); + +PyDoc_STRVAR(pattern_finditer_doc, +"finditer(string[, pos[, endpos]]) --> iterator.\n\ + Return an iterator over all non-overlapping matches for the \n\ + RE pattern in string. For each match, the iterator returns a\n\ + match object."); + +PyDoc_STRVAR(pattern_sub_doc, +"sub(repl, string[, count = 0]) --> newstring\n\ + Return the string obtained by replacing the leftmost non-overlapping\n\ + occurrences of pattern in string by the replacement repl."); + +PyDoc_STRVAR(pattern_subn_doc, +"subn(repl, string[, count = 0]) --> (newstring, number of subs)\n\ + Return the tuple (new_string, number_of_subs_made) found by replacing\n\ + the leftmost non-overlapping occurrences of pattern with the\n\ + replacement repl."); + +PyDoc_STRVAR(pattern_doc, "Compiled regular expression objects"); + +static PyMethodDef pattern_methods[] = { + {"match", (PyCFunction) pattern_match, METH_VARARGS|METH_KEYWORDS, + pattern_match_doc}, + {"search", (PyCFunction) pattern_search, METH_VARARGS|METH_KEYWORDS, + pattern_search_doc}, + {"sub", (PyCFunction) pattern_sub, METH_VARARGS|METH_KEYWORDS, + pattern_sub_doc}, + {"subn", (PyCFunction) pattern_subn, METH_VARARGS|METH_KEYWORDS, + pattern_subn_doc}, + {"split", (PyCFunction) pattern_split, METH_VARARGS|METH_KEYWORDS, + pattern_split_doc}, + {"findall", (PyCFunction) pattern_findall, METH_VARARGS|METH_KEYWORDS, + pattern_findall_doc}, +#if PY_VERSION_HEX >= 0x02020000 + {"finditer", (PyCFunction) pattern_finditer, METH_VARARGS, + pattern_finditer_doc}, +#endif + {"scanner", (PyCFunction) pattern_scanner, METH_VARARGS}, + {"__copy__", (PyCFunction) pattern_copy, METH_NOARGS}, + {"__deepcopy__", (PyCFunction) pattern_deepcopy, METH_O}, + {NULL, NULL} +}; + +static PyObject* +pattern_getattr(PatternObject* self, char* name) +{ + PyObject* res; + + res = Py_FindMethod(pattern_methods, (PyObject*) self, name); + + if (res) + return res; + + PyErr_Clear(); + + /* attributes */ + if (!strcmp(name, "pattern")) { + Py_INCREF(self->pattern); + return self->pattern; + } + + if (!strcmp(name, "flags")) + return Py_BuildValue("i", self->flags); + + if (!strcmp(name, "groups")) + return Py_BuildValue("i", self->groups); + + if (!strcmp(name, "groupindex") && self->groupindex) { + Py_INCREF(self->groupindex); + return self->groupindex; + } + + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +statichere PyTypeObject Pattern_Type = { + PyObject_HEAD_INIT(NULL) + 0, "_" SRE_MODULE ".SRE_Pattern", + sizeof(PatternObject), sizeof(SRE_CODE), + (destructor)pattern_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)pattern_getattr, /*tp_getattr*/ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + pattern_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PatternObject, weakreflist), /* tp_weaklistoffset */ +}; + +static PyObject * +_compile(PyObject* self_, PyObject* args) +{ + /* "compile" pattern descriptor to pattern object */ + + PatternObject* self; + Py_ssize_t i, n; + + PyObject* pattern; + int flags = 0; + PyObject* code; + Py_ssize_t groups = 0; + PyObject* groupindex = NULL; + PyObject* indexgroup = NULL; + if (!PyArg_ParseTuple(args, "OiO!|nOO", &pattern, &flags, + &PyList_Type, &code, &groups, + &groupindex, &indexgroup)) + return NULL; + + n = PyList_GET_SIZE(code); + + self = PyObject_NEW_VAR(PatternObject, &Pattern_Type, n); + if (!self) + return NULL; + + self->codesize = n; + + for (i = 0; i < n; i++) { + PyObject *o = PyList_GET_ITEM(code, i); + unsigned long value = PyInt_Check(o) ? (unsigned long)PyInt_AsLong(o) + : PyLong_AsUnsignedLong(o); + self->code[i] = (SRE_CODE) value; + if ((unsigned long) self->code[i] != value) { + PyErr_SetString(PyExc_OverflowError, + "regular expression code size limit exceeded"); + break; + } + } + + if (PyErr_Occurred()) { + PyObject_DEL(self); + return NULL; + } + + Py_INCREF(pattern); + self->pattern = pattern; + + self->flags = flags; + + self->groups = groups; + + Py_XINCREF(groupindex); + self->groupindex = groupindex; + + Py_XINCREF(indexgroup); + self->indexgroup = indexgroup; + + self->weakreflist = NULL; + + return (PyObject*) self; +} + +/* -------------------------------------------------------------------- */ +/* match methods */ + +static void +match_dealloc(MatchObject* self) +{ + Py_XDECREF(self->regs); + Py_XDECREF(self->string); + Py_DECREF(self->pattern); + PyObject_DEL(self); +} + +static PyObject* +match_getslice_by_index(MatchObject* self, Py_ssize_t index, PyObject* def) +{ + if (index < 0 || index >= self->groups) { + /* raise IndexError if we were given a bad group number */ + PyErr_SetString( + PyExc_IndexError, + "no such group" + ); + return NULL; + } + + index *= 2; + + if (self->string == Py_None || self->mark[index] < 0) { + /* return default value if the string or group is undefined */ + Py_INCREF(def); + return def; + } + + return PySequence_GetSlice( + self->string, self->mark[index], self->mark[index+1] + ); +} + +static Py_ssize_t +match_getindex(MatchObject* self, PyObject* index) +{ + Py_ssize_t i; + + if (PyInt_Check(index)) + return PyInt_AsSsize_t(index); + + i = -1; + + if (self->pattern->groupindex) { + index = PyObject_GetItem(self->pattern->groupindex, index); + if (index) { + if (PyInt_Check(index) || PyLong_Check(index)) + i = PyInt_AsSsize_t(index); + Py_DECREF(index); + } else + PyErr_Clear(); + } + + return i; +} + +static PyObject* +match_getslice(MatchObject* self, PyObject* index, PyObject* def) +{ + return match_getslice_by_index(self, match_getindex(self, index), def); +} + +static PyObject* +match_expand(MatchObject* self, PyObject* ptemplate) +{ + /* delegate to Python code */ + return call( + SRE_PY_MODULE, "_expand", + PyTuple_Pack(3, self->pattern, self, ptemplate) + ); +} + +static PyObject* +match_group(MatchObject* self, PyObject* args) +{ + PyObject* result; + Py_ssize_t i, size; + + size = PyTuple_GET_SIZE(args); + + switch (size) { + case 0: + result = match_getslice(self, Py_False, Py_None); + break; + case 1: + result = match_getslice(self, PyTuple_GET_ITEM(args, 0), Py_None); + break; + default: + /* fetch multiple items */ + result = PyTuple_New(size); + if (!result) + return NULL; + for (i = 0; i < size; i++) { + PyObject* item = match_getslice( + self, PyTuple_GET_ITEM(args, i), Py_None + ); + if (!item) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, item); + } + break; + } + return result; +} + +static PyObject* +match_groups(MatchObject* self, PyObject* args, PyObject* kw) +{ + PyObject* result; + Py_ssize_t index; + + PyObject* def = Py_None; + static char* kwlist[] = { "default", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:groups", kwlist, &def)) + return NULL; + + result = PyTuple_New(self->groups-1); + if (!result) + return NULL; + + for (index = 1; index < self->groups; index++) { + PyObject* item; + item = match_getslice_by_index(self, index, def); + if (!item) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, index-1, item); + } + + return result; +} + +static PyObject* +match_groupdict(MatchObject* self, PyObject* args, PyObject* kw) +{ + PyObject* result; + PyObject* keys; + Py_ssize_t index; + + PyObject* def = Py_None; + static char* kwlist[] = { "default", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:groupdict", kwlist, &def)) + return NULL; + + result = PyDict_New(); + if (!result || !self->pattern->groupindex) + return result; + + keys = PyMapping_Keys(self->pattern->groupindex); + if (!keys) + goto failed; + + for (index = 0; index < PyList_GET_SIZE(keys); index++) { + int status; + PyObject* key; + PyObject* value; + key = PyList_GET_ITEM(keys, index); + if (!key) + goto failed; + value = match_getslice(self, key, def); + if (!value) { + Py_DECREF(key); + goto failed; + } + status = PyDict_SetItem(result, key, value); + Py_DECREF(value); + if (status < 0) + goto failed; + } + + Py_DECREF(keys); + + return result; + +failed: + Py_XDECREF(keys); + Py_DECREF(result); + return NULL; +} + +static PyObject* +match_start(MatchObject* self, PyObject* args) +{ + Py_ssize_t index; + + PyObject* index_ = Py_False; /* zero */ + if (!PyArg_UnpackTuple(args, "start", 0, 1, &index_)) + return NULL; + + index = match_getindex(self, index_); + + if (index < 0 || index >= self->groups) { + PyErr_SetString( + PyExc_IndexError, + "no such group" + ); + return NULL; + } + + /* mark is -1 if group is undefined */ + return Py_BuildValue("i", self->mark[index*2]); +} + +static PyObject* +match_end(MatchObject* self, PyObject* args) +{ + Py_ssize_t index; + + PyObject* index_ = Py_False; /* zero */ + if (!PyArg_UnpackTuple(args, "end", 0, 1, &index_)) + return NULL; + + index = match_getindex(self, index_); + + if (index < 0 || index >= self->groups) { + PyErr_SetString( + PyExc_IndexError, + "no such group" + ); + return NULL; + } + + /* mark is -1 if group is undefined */ + return Py_BuildValue("i", self->mark[index*2+1]); +} + +LOCAL(PyObject*) +_pair(Py_ssize_t i1, Py_ssize_t i2) +{ + PyObject* pair; + PyObject* item; + + pair = PyTuple_New(2); + if (!pair) + return NULL; + + item = PyInt_FromSsize_t(i1); + if (!item) + goto error; + PyTuple_SET_ITEM(pair, 0, item); + + item = PyInt_FromSsize_t(i2); + if (!item) + goto error; + PyTuple_SET_ITEM(pair, 1, item); + + return pair; + + error: + Py_DECREF(pair); + return NULL; +} + +static PyObject* +match_span(MatchObject* self, PyObject* args) +{ + Py_ssize_t index; + + PyObject* index_ = Py_False; /* zero */ + if (!PyArg_UnpackTuple(args, "span", 0, 1, &index_)) + return NULL; + + index = match_getindex(self, index_); + + if (index < 0 || index >= self->groups) { + PyErr_SetString( + PyExc_IndexError, + "no such group" + ); + return NULL; + } + + /* marks are -1 if group is undefined */ + return _pair(self->mark[index*2], self->mark[index*2+1]); +} + +static PyObject* +match_regs(MatchObject* self) +{ + PyObject* regs; + PyObject* item; + Py_ssize_t index; + + regs = PyTuple_New(self->groups); + if (!regs) + return NULL; + + for (index = 0; index < self->groups; index++) { + item = _pair(self->mark[index*2], self->mark[index*2+1]); + if (!item) { + Py_DECREF(regs); + return NULL; + } + PyTuple_SET_ITEM(regs, index, item); + } + + Py_INCREF(regs); + self->regs = regs; + + return regs; +} + +static PyObject* +match_copy(MatchObject* self, PyObject *unused) +{ +#ifdef USE_BUILTIN_COPY + MatchObject* copy; + Py_ssize_t slots, offset; + + slots = 2 * (self->pattern->groups+1); + + copy = PyObject_NEW_VAR(MatchObject, &Match_Type, slots); + if (!copy) + return NULL; + + /* this value a constant, but any compiler should be able to + figure that out all by itself */ + offset = offsetof(MatchObject, string); + + Py_XINCREF(self->pattern); + Py_XINCREF(self->string); + Py_XINCREF(self->regs); + + memcpy((char*) copy + offset, (char*) self + offset, + sizeof(MatchObject) + slots * sizeof(Py_ssize_t) - offset); + + return (PyObject*) copy; +#else + PyErr_SetString(PyExc_TypeError, "cannot copy this match object"); + return NULL; +#endif +} + +static PyObject* +match_deepcopy(MatchObject* self, PyObject* memo) +{ +#ifdef USE_BUILTIN_COPY + MatchObject* copy; + + copy = (MatchObject*) match_copy(self); + if (!copy) + return NULL; + + if (!deepcopy((PyObject**) &copy->pattern, memo) || + !deepcopy(&copy->string, memo) || + !deepcopy(&copy->regs, memo)) { + Py_DECREF(copy); + return NULL; + } + +#else + PyErr_SetString(PyExc_TypeError, "cannot deepcopy this match object"); + return NULL; +#endif +} + +static PyMethodDef match_methods[] = { + {"group", (PyCFunction) match_group, METH_VARARGS}, + {"start", (PyCFunction) match_start, METH_VARARGS}, + {"end", (PyCFunction) match_end, METH_VARARGS}, + {"span", (PyCFunction) match_span, METH_VARARGS}, + {"groups", (PyCFunction) match_groups, METH_VARARGS|METH_KEYWORDS}, + {"groupdict", (PyCFunction) match_groupdict, METH_VARARGS|METH_KEYWORDS}, + {"expand", (PyCFunction) match_expand, METH_O}, + {"__copy__", (PyCFunction) match_copy, METH_NOARGS}, + {"__deepcopy__", (PyCFunction) match_deepcopy, METH_O}, + {NULL, NULL} +}; + +static PyObject* +match_getattr(MatchObject* self, char* name) +{ + PyObject* res; + + res = Py_FindMethod(match_methods, (PyObject*) self, name); + if (res) + return res; + + PyErr_Clear(); + + if (!strcmp(name, "lastindex")) { + if (self->lastindex >= 0) + return Py_BuildValue("i", self->lastindex); + Py_INCREF(Py_None); + return Py_None; + } + + if (!strcmp(name, "lastgroup")) { + if (self->pattern->indexgroup && self->lastindex >= 0) { + PyObject* result = PySequence_GetItem( + self->pattern->indexgroup, self->lastindex + ); + if (result) + return result; + PyErr_Clear(); + } + Py_INCREF(Py_None); + return Py_None; + } + + if (!strcmp(name, "string")) { + if (self->string) { + Py_INCREF(self->string); + return self->string; + } else { + Py_INCREF(Py_None); + return Py_None; + } + } + + if (!strcmp(name, "regs")) { + if (self->regs) { + Py_INCREF(self->regs); + return self->regs; + } else + return match_regs(self); + } + + if (!strcmp(name, "re")) { + Py_INCREF(self->pattern); + return (PyObject*) self->pattern; + } + + if (!strcmp(name, "pos")) + return Py_BuildValue("i", self->pos); + + if (!strcmp(name, "endpos")) + return Py_BuildValue("i", self->endpos); + + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +/* FIXME: implement setattr("string", None) as a special case (to + detach the associated string, if any */ + +statichere PyTypeObject Match_Type = { + PyObject_HEAD_INIT(NULL) + 0, "_" SRE_MODULE ".SRE_Match", + sizeof(MatchObject), sizeof(Py_ssize_t), + (destructor)match_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)match_getattr /*tp_getattr*/ +}; + +static PyObject* +pattern_new_match(PatternObject* pattern, SRE_STATE* state, int status) +{ + /* create match object (from state object) */ + + MatchObject* match; + Py_ssize_t i, j; + char* base; + int n; + + if (status > 0) { + + /* create match object (with room for extra group marks) */ + match = PyObject_NEW_VAR(MatchObject, &Match_Type, + 2*(pattern->groups+1)); + if (!match) + return NULL; + + Py_INCREF(pattern); + match->pattern = pattern; + + Py_INCREF(state->string); + match->string = state->string; + + match->regs = NULL; + match->groups = pattern->groups+1; + + /* fill in group slices */ + + base = (char*) state->beginning; + n = state->charsize; + + match->mark[0] = ((char*) state->start - base) / n; + match->mark[1] = ((char*) state->ptr - base) / n; + + for (i = j = 0; i < pattern->groups; i++, j+=2) + if (j+1 <= state->lastmark && state->mark[j] && state->mark[j+1]) { + match->mark[j+2] = ((char*) state->mark[j] - base) / n; + match->mark[j+3] = ((char*) state->mark[j+1] - base) / n; + } else + match->mark[j+2] = match->mark[j+3] = -1; /* undefined */ + + match->pos = state->pos; + match->endpos = state->endpos; + + match->lastindex = state->lastindex; + + return (PyObject*) match; + + } else if (status == 0) { + + /* no match */ + Py_INCREF(Py_None); + return Py_None; + + } + + /* internal error */ + pattern_error(status); + return NULL; +} + + +/* -------------------------------------------------------------------- */ +/* scanner methods (experimental) */ + +static void +scanner_dealloc(ScannerObject* self) +{ + state_fini(&self->state); + Py_DECREF(self->pattern); + PyObject_DEL(self); +} + +static PyObject* +scanner_match(ScannerObject* self, PyObject *unused) +{ + SRE_STATE* state = &self->state; + PyObject* match; + int status; + + state_reset(state); + + state->ptr = state->start; + + if (state->charsize == 1) { + status = sre_match(state, PatternObject_GetCode(self->pattern)); + } else { +#if defined(HAVE_UNICODE) + status = sre_umatch(state, PatternObject_GetCode(self->pattern)); +#endif + } + if (PyErr_Occurred()) + return NULL; + + match = pattern_new_match((PatternObject*) self->pattern, + state, status); + + if (status == 0 || state->ptr == state->start) + state->start = (void*) ((char*) state->ptr + state->charsize); + else + state->start = state->ptr; + + return match; +} + + +static PyObject* +scanner_search(ScannerObject* self, PyObject *unused) +{ + SRE_STATE* state = &self->state; + PyObject* match; + int status; + + state_reset(state); + + state->ptr = state->start; + + if (state->charsize == 1) { + status = sre_search(state, PatternObject_GetCode(self->pattern)); + } else { +#if defined(HAVE_UNICODE) + status = sre_usearch(state, PatternObject_GetCode(self->pattern)); +#endif + } + if (PyErr_Occurred()) + return NULL; + + match = pattern_new_match((PatternObject*) self->pattern, + state, status); + + if (status == 0 || state->ptr == state->start) + state->start = (void*) ((char*) state->ptr + state->charsize); + else + state->start = state->ptr; + + return match; +} + +static PyMethodDef scanner_methods[] = { + {"match", (PyCFunction) scanner_match, METH_NOARGS}, + {"search", (PyCFunction) scanner_search, METH_NOARGS}, + {NULL, NULL} +}; + +static PyObject* +scanner_getattr(ScannerObject* self, char* name) +{ + PyObject* res; + + res = Py_FindMethod(scanner_methods, (PyObject*) self, name); + if (res) + return res; + + PyErr_Clear(); + + /* attributes */ + if (!strcmp(name, "pattern")) { + Py_INCREF(self->pattern); + return self->pattern; + } + + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +statichere PyTypeObject Scanner_Type = { + PyObject_HEAD_INIT(NULL) + 0, "_" SRE_MODULE ".SRE_Scanner", + sizeof(ScannerObject), 0, + (destructor)scanner_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)scanner_getattr, /*tp_getattr*/ +}; + +static PyObject* +pattern_scanner(PatternObject* pattern, PyObject* args) +{ + /* create search state object */ + + ScannerObject* self; + + PyObject* string; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + if (!PyArg_ParseTuple(args, "O|nn:scanner", &string, &start, &end)) + return NULL; + + /* create scanner object */ + self = PyObject_NEW(ScannerObject, &Scanner_Type); + if (!self) + return NULL; + + string = state_init(&self->state, pattern, string, start, end); + if (!string) { + PyObject_DEL(self); + return NULL; + } + + Py_INCREF(pattern); + self->pattern = (PyObject*) pattern; + + return (PyObject*) self; +} + +static PyMethodDef _functions[] = { + {"compile", _compile, METH_VARARGS}, + {"getcodesize", sre_codesize, METH_NOARGS}, + {"getlower", sre_getlower, METH_VARARGS}, + {NULL, NULL} +}; + +#if PY_VERSION_HEX < 0x02030000 +DL_EXPORT(void) init_sre(void) +#else +PyMODINIT_FUNC init_sre(void) +#endif +{ + PyObject* m; + PyObject* d; + PyObject* x; + + /* Patch object types */ + Pattern_Type.ob_type = Match_Type.ob_type = + Scanner_Type.ob_type = &PyType_Type; + + m = Py_InitModule("_" SRE_MODULE, _functions); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + x = PyInt_FromLong(SRE_MAGIC); + if (x) { + PyDict_SetItemString(d, "MAGIC", x); + Py_DECREF(x); + } + + x = PyInt_FromLong(sizeof(SRE_CODE)); + if (x) { + PyDict_SetItemString(d, "CODESIZE", x); + Py_DECREF(x); + } + + x = PyString_FromString(copyright); + if (x) { + PyDict_SetItemString(d, "copyright", x); + Py_DECREF(x); + } +} + +#endif /* !defined(SRE_RECURSIVE) */ + +/* vim:ts=4:sw=4:et +*/ diff --git a/sys/src/cmd/python/Modules/_ssl.c b/sys/src/cmd/python/Modules/_ssl.c new file mode 100644 index 000000000..3b91b2451 --- /dev/null +++ b/sys/src/cmd/python/Modules/_ssl.c @@ -0,0 +1,726 @@ +/* SSL socket module + + SSL support based on patches by Brian E Gallew and Laszlo Kovacs. + + This module is imported by socket.py. It should *not* be used + directly. + +*/ + +#include "Python.h" +enum py_ssl_error { + /* these mirror ssl.h */ + PY_SSL_ERROR_NONE, + PY_SSL_ERROR_SSL, + PY_SSL_ERROR_WANT_READ, + PY_SSL_ERROR_WANT_WRITE, + PY_SSL_ERROR_WANT_X509_LOOKUP, + PY_SSL_ERROR_SYSCALL, /* look at error stack/return value/errno */ + PY_SSL_ERROR_ZERO_RETURN, + PY_SSL_ERROR_WANT_CONNECT, + /* start of non ssl.h errorcodes */ + PY_SSL_ERROR_EOF, /* special case of SSL_ERROR_SYSCALL */ + PY_SSL_ERROR_INVALID_ERROR_CODE +}; + +/* Include symbols from _socket module */ +#include "socketmodule.h" + +#if defined(HAVE_POLL_H) +#include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +#include <sys/poll.h> +#endif + +/* Include OpenSSL header files */ +#include "openssl/rsa.h" +#include "openssl/crypto.h" +#include "openssl/x509.h" +#include "openssl/pem.h" +#include "openssl/ssl.h" +#include "openssl/err.h" +#include "openssl/rand.h" + +/* SSL error object */ +static PyObject *PySSLErrorObject; + +/* SSL socket object */ + +#define X509_NAME_MAXLEN 256 + +/* RAND_* APIs got added to OpenSSL in 0.9.5 */ +#if OPENSSL_VERSION_NUMBER >= 0x0090500fL +# define HAVE_OPENSSL_RAND 1 +#else +# undef HAVE_OPENSSL_RAND +#endif + +typedef struct { + PyObject_HEAD + PySocketSockObject *Socket; /* Socket on which we're layered */ + SSL_CTX* ctx; + SSL* ssl; + X509* server_cert; + char server[X509_NAME_MAXLEN]; + char issuer[X509_NAME_MAXLEN]; + +} PySSLObject; + +static PyTypeObject PySSL_Type; +static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args); +static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args); +static int check_socket_and_wait_for_timeout(PySocketSockObject *s, + int writing); + +#define PySSLObject_Check(v) ((v)->ob_type == &PySSL_Type) + +typedef enum { + SOCKET_IS_NONBLOCKING, + SOCKET_IS_BLOCKING, + SOCKET_HAS_TIMED_OUT, + SOCKET_HAS_BEEN_CLOSED, + SOCKET_TOO_LARGE_FOR_SELECT, + SOCKET_OPERATION_OK +} timeout_state; + +/* XXX It might be helpful to augment the error message generated + below with the name of the SSL function that generated the error. + I expect it's obvious most of the time. +*/ + +static PyObject * +PySSL_SetError(PySSLObject *obj, int ret) +{ + PyObject *v, *n, *s; + char *errstr; + int err; + enum py_ssl_error p; + + assert(ret <= 0); + + err = SSL_get_error(obj->ssl, ret); + + switch (err) { + case SSL_ERROR_ZERO_RETURN: + errstr = "TLS/SSL connection has been closed"; + p = PY_SSL_ERROR_ZERO_RETURN; + break; + case SSL_ERROR_WANT_READ: + errstr = "The operation did not complete (read)"; + p = PY_SSL_ERROR_WANT_READ; + break; + case SSL_ERROR_WANT_WRITE: + p = PY_SSL_ERROR_WANT_WRITE; + errstr = "The operation did not complete (write)"; + break; + case SSL_ERROR_WANT_X509_LOOKUP: + p = PY_SSL_ERROR_WANT_X509_LOOKUP; + errstr = "The operation did not complete (X509 lookup)"; + break; + case SSL_ERROR_WANT_CONNECT: + p = PY_SSL_ERROR_WANT_CONNECT; + errstr = "The operation did not complete (connect)"; + break; + case SSL_ERROR_SYSCALL: + { + unsigned long e = ERR_get_error(); + if (e == 0) { + if (ret == 0 || !obj->Socket) { + p = PY_SSL_ERROR_EOF; + errstr = "EOF occurred in violation of protocol"; + } else if (ret == -1) { + /* the underlying BIO reported an I/O error */ + return obj->Socket->errorhandler(); + } else { /* possible? */ + p = PY_SSL_ERROR_SYSCALL; + errstr = "Some I/O error occurred"; + } + } else { + p = PY_SSL_ERROR_SYSCALL; + /* XXX Protected by global interpreter lock */ + errstr = ERR_error_string(e, NULL); + } + break; + } + case SSL_ERROR_SSL: + { + unsigned long e = ERR_get_error(); + p = PY_SSL_ERROR_SSL; + if (e != 0) + /* XXX Protected by global interpreter lock */ + errstr = ERR_error_string(e, NULL); + else { /* possible? */ + errstr = "A failure in the SSL library occurred"; + } + break; + } + default: + p = PY_SSL_ERROR_INVALID_ERROR_CODE; + errstr = "Invalid error code"; + } + n = PyInt_FromLong((long) p); + if (n == NULL) + return NULL; + v = PyTuple_New(2); + if (v == NULL) { + Py_DECREF(n); + return NULL; + } + + s = PyString_FromString(errstr); + if (s == NULL) { + Py_DECREF(v); + Py_DECREF(n); + } + PyTuple_SET_ITEM(v, 0, n); + PyTuple_SET_ITEM(v, 1, s); + PyErr_SetObject(PySSLErrorObject, v); + Py_DECREF(v); + return NULL; +} + +static PySSLObject * +newPySSLObject(PySocketSockObject *Sock, char *key_file, char *cert_file) +{ + PySSLObject *self; + char *errstr = NULL; + int ret; + int err; + int sockstate; + + self = PyObject_New(PySSLObject, &PySSL_Type); /* Create new object */ + if (self == NULL) + return NULL; + memset(self->server, '\0', sizeof(char) * X509_NAME_MAXLEN); + memset(self->issuer, '\0', sizeof(char) * X509_NAME_MAXLEN); + self->server_cert = NULL; + self->ssl = NULL; + self->ctx = NULL; + self->Socket = NULL; + + if ((key_file && !cert_file) || (!key_file && cert_file)) { + errstr = "Both the key & certificate files must be specified"; + goto fail; + } + + Py_BEGIN_ALLOW_THREADS + self->ctx = SSL_CTX_new(SSLv23_method()); /* Set up context */ + Py_END_ALLOW_THREADS + if (self->ctx == NULL) { + errstr = "SSL_CTX_new error"; + goto fail; + } + + if (key_file) { + Py_BEGIN_ALLOW_THREADS + ret = SSL_CTX_use_PrivateKey_file(self->ctx, key_file, + SSL_FILETYPE_PEM); + Py_END_ALLOW_THREADS + if (ret < 1) { + errstr = "SSL_CTX_use_PrivateKey_file error"; + goto fail; + } + + Py_BEGIN_ALLOW_THREADS + ret = SSL_CTX_use_certificate_chain_file(self->ctx, + cert_file); + Py_END_ALLOW_THREADS + SSL_CTX_set_options(self->ctx, SSL_OP_ALL); /* ssl compatibility */ + if (ret < 1) { + errstr = "SSL_CTX_use_certificate_chain_file error"; + goto fail; + } + } + + Py_BEGIN_ALLOW_THREADS + SSL_CTX_set_verify(self->ctx, + SSL_VERIFY_NONE, NULL); /* set verify lvl */ + self->ssl = SSL_new(self->ctx); /* New ssl struct */ + Py_END_ALLOW_THREADS + SSL_set_fd(self->ssl, Sock->sock_fd); /* Set the socket for SSL */ + + /* If the socket is in non-blocking mode or timeout mode, set the BIO + * to non-blocking mode (blocking is the default) + */ + if (Sock->sock_timeout >= 0.0) { + /* Set both the read and write BIO's to non-blocking mode */ + BIO_set_nbio(SSL_get_rbio(self->ssl), 1); + BIO_set_nbio(SSL_get_wbio(self->ssl), 1); + } + + Py_BEGIN_ALLOW_THREADS + SSL_set_connect_state(self->ssl); + Py_END_ALLOW_THREADS + + /* Actually negotiate SSL connection */ + /* XXX If SSL_connect() returns 0, it's also a failure. */ + sockstate = 0; + do { + Py_BEGIN_ALLOW_THREADS + ret = SSL_connect(self->ssl); + err = SSL_get_error(self->ssl, ret); + Py_END_ALLOW_THREADS + if(PyErr_CheckSignals()) { + goto fail; + } + if (err == SSL_ERROR_WANT_READ) { + sockstate = check_socket_and_wait_for_timeout(Sock, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { + sockstate = check_socket_and_wait_for_timeout(Sock, 1); + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, "The connect operation timed out"); + goto fail; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); + goto fail; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); + goto fail; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (ret <= 0) { + PySSL_SetError(self, ret); + goto fail; + } + self->ssl->debug = 1; + + Py_BEGIN_ALLOW_THREADS + if ((self->server_cert = SSL_get_peer_certificate(self->ssl))) { + X509_NAME_oneline(X509_get_subject_name(self->server_cert), + self->server, X509_NAME_MAXLEN); + X509_NAME_oneline(X509_get_issuer_name(self->server_cert), + self->issuer, X509_NAME_MAXLEN); + } + Py_END_ALLOW_THREADS + self->Socket = Sock; + Py_INCREF(self->Socket); + return self; + fail: + if (errstr) + PyErr_SetString(PySSLErrorObject, errstr); + Py_DECREF(self); + return NULL; +} + +static PyObject * +PySocket_ssl(PyObject *self, PyObject *args) +{ + PySSLObject *rv; + PySocketSockObject *Sock; + char *key_file = NULL; + char *cert_file = NULL; + + if (!PyArg_ParseTuple(args, "O!|zz:ssl", + PySocketModule.Sock_Type, + (PyObject*)&Sock, + &key_file, &cert_file)) + return NULL; + + rv = newPySSLObject(Sock, key_file, cert_file); + if (rv == NULL) + return NULL; + return (PyObject *)rv; +} + +PyDoc_STRVAR(ssl_doc, +"ssl(socket, [keyfile, certfile]) -> sslobject"); + +/* SSL object methods */ + +static PyObject * +PySSL_server(PySSLObject *self) +{ + return PyString_FromString(self->server); +} + +static PyObject * +PySSL_issuer(PySSLObject *self) +{ + return PyString_FromString(self->issuer); +} + + +static void PySSL_dealloc(PySSLObject *self) +{ + if (self->server_cert) /* Possible not to have one? */ + X509_free (self->server_cert); + if (self->ssl) + SSL_free(self->ssl); + if (self->ctx) + SSL_CTX_free(self->ctx); + Py_XDECREF(self->Socket); + PyObject_Del(self); +} + +/* If the socket has a timeout, do a select()/poll() on the socket. + The argument writing indicates the direction. + Returns one of the possibilities in the timeout_state enum (above). + */ + +static int +check_socket_and_wait_for_timeout(PySocketSockObject *s, int writing) +{ + fd_set fds; + struct timeval tv; + int rc; + + /* Nothing to do unless we're in timeout mode (not non-blocking) */ + if (s->sock_timeout < 0.0) + return SOCKET_IS_BLOCKING; + else if (s->sock_timeout == 0.0) + return SOCKET_IS_NONBLOCKING; + + /* Guard against closed socket */ + if (s->sock_fd < 0) + return SOCKET_HAS_BEEN_CLOSED; + + /* Prefer poll, if available, since you can poll() any fd + * which can't be done with select(). */ +#ifdef HAVE_POLL + { + struct pollfd pollfd; + int timeout; + + pollfd.fd = s->sock_fd; + pollfd.events = writing ? POLLOUT : POLLIN; + + /* s->sock_timeout is in seconds, timeout in ms */ + timeout = (int)(s->sock_timeout * 1000 + 0.5); + Py_BEGIN_ALLOW_THREADS + rc = poll(&pollfd, 1, timeout); + Py_END_ALLOW_THREADS + + goto normal_return; + } +#endif + + /* Guard against socket too large for select*/ +#ifndef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE + if (s->sock_fd >= FD_SETSIZE) + return SOCKET_TOO_LARGE_FOR_SELECT; +#endif + + /* Construct the arguments to select */ + tv.tv_sec = (int)s->sock_timeout; + tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + FD_ZERO(&fds); + FD_SET(s->sock_fd, &fds); + + /* See if the socket is ready */ + Py_BEGIN_ALLOW_THREADS + if (writing) + rc = select(s->sock_fd+1, NULL, &fds, NULL, &tv); + else + rc = select(s->sock_fd+1, &fds, NULL, NULL, &tv); + Py_END_ALLOW_THREADS + +normal_return: + /* Return SOCKET_TIMED_OUT on timeout, SOCKET_OPERATION_OK otherwise + (when we are able to write or when there's something to read) */ + return rc == 0 ? SOCKET_HAS_TIMED_OUT : SOCKET_OPERATION_OK; +} + +static PyObject *PySSL_SSLwrite(PySSLObject *self, PyObject *args) +{ + char *data; + int len; + int count; + int sockstate; + int err; + + if (!PyArg_ParseTuple(args, "s#:write", &data, &count)) + return NULL; + + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, "The write operation timed out"); + return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); + return NULL; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); + return NULL; + } + do { + err = 0; + Py_BEGIN_ALLOW_THREADS + len = SSL_write(self->ssl, data, count); + err = SSL_get_error(self->ssl, len); + Py_END_ALLOW_THREADS + if(PyErr_CheckSignals()) { + return NULL; + } + if (err == SSL_ERROR_WANT_READ) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, "The write operation timed out"); + return NULL; + } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { + PyErr_SetString(PySSLErrorObject, "Underlying socket has been closed."); + return NULL; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (len > 0) + return PyInt_FromLong(len); + else + return PySSL_SetError(self, len); +} + +PyDoc_STRVAR(PySSL_SSLwrite_doc, +"write(s) -> len\n\ +\n\ +Writes the string s into the SSL object. Returns the number\n\ +of bytes written."); + +static PyObject *PySSL_SSLread(PySSLObject *self, PyObject *args) +{ + PyObject *buf; + int count = 0; + int len = 1024; + int sockstate; + int err; + + if (!PyArg_ParseTuple(args, "|i:read", &len)) + return NULL; + + if (!(buf = PyString_FromStringAndSize((char *) 0, len))) + return NULL; + + /* first check if there are bytes ready to be read */ + Py_BEGIN_ALLOW_THREADS + count = SSL_pending(self->ssl); + Py_END_ALLOW_THREADS + + if (!count) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, "The read operation timed out"); + Py_DECREF(buf); + return NULL; + } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { + PyErr_SetString(PySSLErrorObject, "Underlying socket too large for select()."); + return NULL; + } + } + do { + err = 0; + Py_BEGIN_ALLOW_THREADS + count = SSL_read(self->ssl, PyString_AsString(buf), len); + err = SSL_get_error(self->ssl, count); + Py_END_ALLOW_THREADS + if(PyErr_CheckSignals()) { + Py_DECREF(buf); + return NULL; + } + if (err == SSL_ERROR_WANT_READ) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 0); + } else if (err == SSL_ERROR_WANT_WRITE) { + sockstate = check_socket_and_wait_for_timeout(self->Socket, 1); + } else { + sockstate = SOCKET_OPERATION_OK; + } + if (sockstate == SOCKET_HAS_TIMED_OUT) { + PyErr_SetString(PySSLErrorObject, "The read operation timed out"); + Py_DECREF(buf); + return NULL; + } else if (sockstate == SOCKET_IS_NONBLOCKING) { + break; + } + } while (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE); + if (count <= 0) { + Py_DECREF(buf); + return PySSL_SetError(self, count); + } + if (count != len) + _PyString_Resize(&buf, count); + return buf; +} + +PyDoc_STRVAR(PySSL_SSLread_doc, +"read([len]) -> string\n\ +\n\ +Read up to len bytes from the SSL socket."); + +static PyMethodDef PySSLMethods[] = { + {"write", (PyCFunction)PySSL_SSLwrite, METH_VARARGS, + PySSL_SSLwrite_doc}, + {"read", (PyCFunction)PySSL_SSLread, METH_VARARGS, + PySSL_SSLread_doc}, + {"server", (PyCFunction)PySSL_server, METH_NOARGS}, + {"issuer", (PyCFunction)PySSL_issuer, METH_NOARGS}, + {NULL, NULL} +}; + +static PyObject *PySSL_getattr(PySSLObject *self, char *name) +{ + return Py_FindMethod(PySSLMethods, (PyObject *)self, name); +} + +static PyTypeObject PySSL_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "socket.SSL", /*tp_name*/ + sizeof(PySSLObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PySSL_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)PySSL_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +#ifdef HAVE_OPENSSL_RAND + +/* helper routines for seeding the SSL PRNG */ +static PyObject * +PySSL_RAND_add(PyObject *self, PyObject *args) +{ + char *buf; + int len; + double entropy; + + if (!PyArg_ParseTuple(args, "s#d:RAND_add", &buf, &len, &entropy)) + return NULL; + RAND_add(buf, len, entropy); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(PySSL_RAND_add_doc, +"RAND_add(string, entropy)\n\ +\n\ +Mix string into the OpenSSL PRNG state. entropy (a float) is a lower\n\ +bound on the entropy contained in string."); + +static PyObject * +PySSL_RAND_status(PyObject *self) +{ + return PyInt_FromLong(RAND_status()); +} + +PyDoc_STRVAR(PySSL_RAND_status_doc, +"RAND_status() -> 0 or 1\n\ +\n\ +Returns 1 if the OpenSSL PRNG has been seeded with enough data and 0 if not.\n\ +It is necessary to seed the PRNG with RAND_add() on some platforms before\n\ +using the ssl() function."); + +static PyObject * +PySSL_RAND_egd(PyObject *self, PyObject *arg) +{ + int bytes; + + if (!PyString_Check(arg)) + return PyErr_Format(PyExc_TypeError, + "RAND_egd() expected string, found %s", + arg->ob_type->tp_name); + bytes = RAND_egd(PyString_AS_STRING(arg)); + if (bytes == -1) { + PyErr_SetString(PySSLErrorObject, + "EGD connection failed or EGD did not return " + "enough data to seed the PRNG"); + return NULL; + } + return PyInt_FromLong(bytes); +} + +PyDoc_STRVAR(PySSL_RAND_egd_doc, +"RAND_egd(path) -> bytes\n\ +\n\ +Queries the entropy gather daemon (EGD) on socket path. Returns number\n\ +of bytes read. Raises socket.sslerror if connection to EGD fails or\n\ +if it does provide enough data to seed PRNG."); + +#endif + +/* List of functions exported by this module. */ + +static PyMethodDef PySSL_methods[] = { + {"ssl", PySocket_ssl, + METH_VARARGS, ssl_doc}, +#ifdef HAVE_OPENSSL_RAND + {"RAND_add", PySSL_RAND_add, METH_VARARGS, + PySSL_RAND_add_doc}, + {"RAND_egd", PySSL_RAND_egd, METH_O, + PySSL_RAND_egd_doc}, + {"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS, + PySSL_RAND_status_doc}, +#endif + {NULL, NULL} /* Sentinel */ +}; + + +PyDoc_STRVAR(module_doc, +"Implementation module for SSL socket operations. See the socket module\n\ +for documentation."); + +PyMODINIT_FUNC +init_ssl(void) +{ + PyObject *m, *d; + + PySSL_Type.ob_type = &PyType_Type; + + m = Py_InitModule3("_ssl", PySSL_methods, module_doc); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + /* Load _socket module and its C API */ + if (PySocketModule_ImportModuleAndAPI()) + return; + + /* Init OpenSSL */ + SSL_load_error_strings(); + SSLeay_add_ssl_algorithms(); + + /* Add symbols to module dict */ + PySSLErrorObject = PyErr_NewException("socket.sslerror", + PySocketModule.error, + NULL); + if (PySSLErrorObject == NULL) + return; + PyDict_SetItemString(d, "sslerror", PySSLErrorObject); + if (PyDict_SetItemString(d, "SSLType", + (PyObject *)&PySSL_Type) != 0) + return; + PyModule_AddIntConstant(m, "SSL_ERROR_ZERO_RETURN", + PY_SSL_ERROR_ZERO_RETURN); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_READ", + PY_SSL_ERROR_WANT_READ); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_WRITE", + PY_SSL_ERROR_WANT_WRITE); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_X509_LOOKUP", + PY_SSL_ERROR_WANT_X509_LOOKUP); + PyModule_AddIntConstant(m, "SSL_ERROR_SYSCALL", + PY_SSL_ERROR_SYSCALL); + PyModule_AddIntConstant(m, "SSL_ERROR_SSL", + PY_SSL_ERROR_SSL); + PyModule_AddIntConstant(m, "SSL_ERROR_WANT_CONNECT", + PY_SSL_ERROR_WANT_CONNECT); + /* non ssl.h errorcodes */ + PyModule_AddIntConstant(m, "SSL_ERROR_EOF", + PY_SSL_ERROR_EOF); + PyModule_AddIntConstant(m, "SSL_ERROR_INVALID_ERROR_CODE", + PY_SSL_ERROR_INVALID_ERROR_CODE); + +} diff --git a/sys/src/cmd/python/Modules/_struct.c b/sys/src/cmd/python/Modules/_struct.c new file mode 100644 index 000000000..53c64848b --- /dev/null +++ b/sys/src/cmd/python/Modules/_struct.c @@ -0,0 +1,1896 @@ +/* struct module -- pack values into and (out of) strings */ + +/* New version supporting byte order, alignment and size options, + character strings, and unsigned numbers */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" +#include "structseq.h" +#include "structmember.h" +#include <ctype.h> + +static PyTypeObject PyStructType; + +/* compatibility macros */ +#if (PY_VERSION_HEX < 0x02050000) +typedef int Py_ssize_t; +#endif + +/* If PY_STRUCT_OVERFLOW_MASKING is defined, the struct module will wrap all input + numbers for explicit endians such that they fit in the given type, much + like explicit casting in C. A warning will be raised if the number did + not originally fit within the range of the requested type. If it is + not defined, then all range errors and overflow will be struct.error + exceptions. */ + +#define PY_STRUCT_OVERFLOW_MASKING 1 + +#ifdef PY_STRUCT_OVERFLOW_MASKING +static PyObject *pylong_ulong_mask = NULL; +static PyObject *pyint_zero = NULL; +#endif + +/* If PY_STRUCT_FLOAT_COERCE is defined, the struct module will allow float + arguments for integer formats with a warning for backwards + compatibility. */ + +#define PY_STRUCT_FLOAT_COERCE 1 + +#ifdef PY_STRUCT_FLOAT_COERCE +#define FLOAT_COERCE "integer argument expected, got float" +#endif + + +/* The translation function for each format character is table driven */ +typedef struct _formatdef { + char format; + Py_ssize_t size; + Py_ssize_t alignment; + PyObject* (*unpack)(const char *, + const struct _formatdef *); + int (*pack)(char *, PyObject *, + const struct _formatdef *); +} formatdef; + +typedef struct _formatcode { + const struct _formatdef *fmtdef; + Py_ssize_t offset; + Py_ssize_t size; +} formatcode; + +/* Struct object interface */ + +typedef struct { + PyObject_HEAD + Py_ssize_t s_size; + Py_ssize_t s_len; + formatcode *s_codes; + PyObject *s_format; + PyObject *weakreflist; /* List of weak references */ +} PyStructObject; + + +#define PyStruct_Check(op) PyObject_TypeCheck(op, &PyStructType) +#define PyStruct_CheckExact(op) ((op)->ob_type == &PyStructType) + + +/* Exception */ + +static PyObject *StructError; + + +/* Define various structs to figure out the alignments of types */ + + +typedef struct { char c; short x; } st_short; +typedef struct { char c; int x; } st_int; +typedef struct { char c; long x; } st_long; +typedef struct { char c; float x; } st_float; +typedef struct { char c; double x; } st_double; +typedef struct { char c; void *x; } st_void_p; + +#define SHORT_ALIGN (sizeof(st_short) - sizeof(short)) +#define INT_ALIGN (sizeof(st_int) - sizeof(int)) +#define LONG_ALIGN (sizeof(st_long) - sizeof(long)) +#define FLOAT_ALIGN (sizeof(st_float) - sizeof(float)) +#define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double)) +#define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *)) + +/* We can't support q and Q in native mode unless the compiler does; + in std mode, they're 8 bytes on all platforms. */ +#ifdef HAVE_LONG_LONG +typedef struct { char c; PY_LONG_LONG x; } s_long_long; +#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(PY_LONG_LONG)) +#endif + +#define STRINGIFY(x) #x + +#ifdef __powerc +#pragma options align=reset +#endif + +/* Helper to get a PyLongObject by hook or by crook. Caller should decref. */ + +static PyObject * +get_pylong(PyObject *v) +{ + PyNumberMethods *m; + + assert(v != NULL); + if (PyInt_Check(v)) + return PyLong_FromLong(PyInt_AS_LONG(v)); + if (PyLong_Check(v)) { + Py_INCREF(v); + return v; + } + m = v->ob_type->tp_as_number; + if (m != NULL && m->nb_long != NULL) { + v = m->nb_long(v); + if (v == NULL) + return NULL; + if (PyLong_Check(v)) + return v; + Py_DECREF(v); + } + PyErr_SetString(StructError, + "cannot convert argument to long"); + return NULL; +} + +/* Helper routine to get a Python integer and raise the appropriate error + if it isn't one */ + +static int +get_long(PyObject *v, long *p) +{ + long x = PyInt_AsLong(v); + if (x == -1 && PyErr_Occurred()) { +#ifdef PY_STRUCT_FLOAT_COERCE + if (PyFloat_Check(v)) { + PyObject *o; + int res; + PyErr_Clear(); + if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0) + return -1; + o = PyNumber_Int(v); + if (o == NULL) + return -1; + res = get_long(o, p); + Py_DECREF(o); + return res; + } +#endif + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_SetString(StructError, + "required argument is not an integer"); + return -1; + } + *p = x; + return 0; +} + + +/* Same, but handling unsigned long */ + +static int +get_ulong(PyObject *v, unsigned long *p) +{ + if (PyLong_Check(v)) { + unsigned long x = PyLong_AsUnsignedLong(v); + if (x == (unsigned long)(-1) && PyErr_Occurred()) + return -1; + *p = x; + return 0; + } + if (get_long(v, (long *)p) < 0) + return -1; + if (((long)*p) < 0) { + PyErr_SetString(StructError, + "unsigned argument is < 0"); + return -1; + } + return 0; +} + +#ifdef HAVE_LONG_LONG + +/* Same, but handling native long long. */ + +static int +get_longlong(PyObject *v, PY_LONG_LONG *p) +{ + PY_LONG_LONG x; + + v = get_pylong(v); + if (v == NULL) + return -1; + assert(PyLong_Check(v)); + x = PyLong_AsLongLong(v); + Py_DECREF(v); + if (x == (PY_LONG_LONG)-1 && PyErr_Occurred()) + return -1; + *p = x; + return 0; +} + +/* Same, but handling native unsigned long long. */ + +static int +get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p) +{ + unsigned PY_LONG_LONG x; + + v = get_pylong(v); + if (v == NULL) + return -1; + assert(PyLong_Check(v)); + x = PyLong_AsUnsignedLongLong(v); + Py_DECREF(v); + if (x == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred()) + return -1; + *p = x; + return 0; +} + +#endif + +#ifdef PY_STRUCT_OVERFLOW_MASKING + +/* Helper routine to get a Python integer and raise the appropriate error + if it isn't one */ + +#define INT_OVERFLOW "struct integer overflow masking is deprecated" + +static int +get_wrapped_long(PyObject *v, long *p) +{ + if (get_long(v, p) < 0) { + if (PyLong_Check(v) && + PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyObject *wrapped; + long x; + PyErr_Clear(); +#ifdef PY_STRUCT_FLOAT_COERCE + if (PyFloat_Check(v)) { + PyObject *o; + int res; + PyErr_Clear(); + if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0) + return -1; + o = PyNumber_Int(v); + if (o == NULL) + return -1; + res = get_wrapped_long(o, p); + Py_DECREF(o); + return res; + } +#endif + if (PyErr_WarnEx(PyExc_DeprecationWarning, INT_OVERFLOW, 2) < 0) + return -1; + wrapped = PyNumber_And(v, pylong_ulong_mask); + if (wrapped == NULL) + return -1; + x = (long)PyLong_AsUnsignedLong(wrapped); + Py_DECREF(wrapped); + if (x == -1 && PyErr_Occurred()) + return -1; + *p = x; + } else { + return -1; + } + } + return 0; +} + +static int +get_wrapped_ulong(PyObject *v, unsigned long *p) +{ + long x = (long)PyLong_AsUnsignedLong(v); + if (x == -1 && PyErr_Occurred()) { + PyObject *wrapped; + PyErr_Clear(); +#ifdef PY_STRUCT_FLOAT_COERCE + if (PyFloat_Check(v)) { + PyObject *o; + int res; + PyErr_Clear(); + if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0) + return -1; + o = PyNumber_Int(v); + if (o == NULL) + return -1; + res = get_wrapped_ulong(o, p); + Py_DECREF(o); + return res; + } +#endif + wrapped = PyNumber_And(v, pylong_ulong_mask); + if (wrapped == NULL) + return -1; + if (PyErr_WarnEx(PyExc_DeprecationWarning, INT_OVERFLOW, 2) < 0) { + Py_DECREF(wrapped); + return -1; + } + x = (long)PyLong_AsUnsignedLong(wrapped); + Py_DECREF(wrapped); + if (x == -1 && PyErr_Occurred()) + return -1; + } + *p = (unsigned long)x; + return 0; +} + +#define RANGE_ERROR(x, f, flag, mask) \ + do { \ + if (_range_error(f, flag) < 0) \ + return -1; \ + else \ + (x) &= (mask); \ + } while (0) + +#else + +#define get_wrapped_long get_long +#define get_wrapped_ulong get_ulong +#define RANGE_ERROR(x, f, flag, mask) return _range_error(f, flag) + +#endif + +/* Floating point helpers */ + +static PyObject * +unpack_float(const char *p, /* start of 4-byte string */ + int le) /* true for little-endian, false for big-endian */ +{ + double x; + + x = _PyFloat_Unpack4((unsigned char *)p, le); + if (x == -1.0 && PyErr_Occurred()) + return NULL; + return PyFloat_FromDouble(x); +} + +static PyObject * +unpack_double(const char *p, /* start of 8-byte string */ + int le) /* true for little-endian, false for big-endian */ +{ + double x; + + x = _PyFloat_Unpack8((unsigned char *)p, le); + if (x == -1.0 && PyErr_Occurred()) + return NULL; + return PyFloat_FromDouble(x); +} + +/* Helper to format the range error exceptions */ +static int +_range_error(const formatdef *f, int is_unsigned) +{ + /* ulargest is the largest unsigned value with f->size bytes. + * Note that the simpler: + * ((size_t)1 << (f->size * 8)) - 1 + * doesn't work when f->size == sizeof(size_t) because C doesn't + * define what happens when a left shift count is >= the number of + * bits in the integer being shifted; e.g., on some boxes it doesn't + * shift at all when they're equal. + */ + const size_t ulargest = (size_t)-1 >> ((SIZEOF_SIZE_T - f->size)*8); + assert(f->size >= 1 && f->size <= SIZEOF_SIZE_T); + if (is_unsigned) + PyErr_Format(StructError, + "'%c' format requires 0 <= number <= %zu", + f->format, + ulargest); + else { + const Py_ssize_t largest = (Py_ssize_t)(ulargest >> 1); + PyErr_Format(StructError, + "'%c' format requires %zd <= number <= %zd", + f->format, + ~ largest, + largest); + } +#ifdef PY_STRUCT_OVERFLOW_MASKING + { + PyObject *ptype, *pvalue, *ptraceback; + PyObject *msg; + int rval; + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + assert(pvalue != NULL); + msg = PyObject_Str(pvalue); + Py_XDECREF(ptype); + Py_XDECREF(pvalue); + Py_XDECREF(ptraceback); + if (msg == NULL) + return -1; + rval = PyErr_WarnEx(PyExc_DeprecationWarning, + PyString_AS_STRING(msg), 2); + Py_DECREF(msg); + if (rval == 0) + return 0; + } +#endif + return -1; +} + + + +/* A large number of small routines follow, with names of the form + + [bln][up]_TYPE + + [bln] distiguishes among big-endian, little-endian and native. + [pu] distiguishes between pack (to struct) and unpack (from struct). + TYPE is one of char, byte, ubyte, etc. +*/ + +/* Native mode routines. ****************************************************/ +/* NOTE: + In all n[up]_<type> routines handling types larger than 1 byte, there is + *no* guarantee that the p pointer is properly aligned for each type, + therefore memcpy is called. An intermediate variable is used to + compensate for big-endian architectures. + Normally both the intermediate variable and the memcpy call will be + skipped by C optimisation in little-endian architectures (gcc >= 2.91 + does this). */ + +static PyObject * +nu_char(const char *p, const formatdef *f) +{ + return PyString_FromStringAndSize(p, 1); +} + +static PyObject * +nu_byte(const char *p, const formatdef *f) +{ + return PyInt_FromLong((long) *(signed char *)p); +} + +static PyObject * +nu_ubyte(const char *p, const formatdef *f) +{ + return PyInt_FromLong((long) *(unsigned char *)p); +} + +static PyObject * +nu_short(const char *p, const formatdef *f) +{ + short x; + memcpy((char *)&x, p, sizeof x); + return PyInt_FromLong((long)x); +} + +static PyObject * +nu_ushort(const char *p, const formatdef *f) +{ + unsigned short x; + memcpy((char *)&x, p, sizeof x); + return PyInt_FromLong((long)x); +} + +static PyObject * +nu_int(const char *p, const formatdef *f) +{ + int x; + memcpy((char *)&x, p, sizeof x); + return PyInt_FromLong((long)x); +} + +static PyObject * +nu_uint(const char *p, const formatdef *f) +{ + unsigned int x; + memcpy((char *)&x, p, sizeof x); +#if (SIZEOF_LONG > SIZEOF_INT) + return PyInt_FromLong((long)x); +#else + if (x <= ((unsigned int)LONG_MAX)) + return PyInt_FromLong((long)x); + return PyLong_FromUnsignedLong((unsigned long)x); +#endif +} + +static PyObject * +nu_long(const char *p, const formatdef *f) +{ + long x; + memcpy((char *)&x, p, sizeof x); + return PyInt_FromLong(x); +} + +static PyObject * +nu_ulong(const char *p, const formatdef *f) +{ + unsigned long x; + memcpy((char *)&x, p, sizeof x); + if (x <= LONG_MAX) + return PyInt_FromLong((long)x); + return PyLong_FromUnsignedLong(x); +} + +/* Native mode doesn't support q or Q unless the platform C supports + long long (or, on Windows, __int64). */ + +#ifdef HAVE_LONG_LONG + +static PyObject * +nu_longlong(const char *p, const formatdef *f) +{ + PY_LONG_LONG x; + memcpy((char *)&x, p, sizeof x); + if (x >= LONG_MIN && x <= LONG_MAX) + return PyInt_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long)); + return PyLong_FromLongLong(x); +} + +static PyObject * +nu_ulonglong(const char *p, const formatdef *f) +{ + unsigned PY_LONG_LONG x; + memcpy((char *)&x, p, sizeof x); + if (x <= LONG_MAX) + return PyInt_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long)); + return PyLong_FromUnsignedLongLong(x); +} + +#endif + +static PyObject * +nu_float(const char *p, const formatdef *f) +{ + float x; + memcpy((char *)&x, p, sizeof x); + return PyFloat_FromDouble((double)x); +} + +static PyObject * +nu_double(const char *p, const formatdef *f) +{ + double x; + memcpy((char *)&x, p, sizeof x); + return PyFloat_FromDouble(x); +} + +static PyObject * +nu_void_p(const char *p, const formatdef *f) +{ + void *x; + memcpy((char *)&x, p, sizeof x); + return PyLong_FromVoidPtr(x); +} + +static int +np_byte(char *p, PyObject *v, const formatdef *f) +{ + long x; + if (get_long(v, &x) < 0) + return -1; + if (x < -128 || x > 127){ + PyErr_SetString(StructError, + "byte format requires -128 <= number <= 127"); + return -1; + } + *p = (char)x; + return 0; +} + +static int +np_ubyte(char *p, PyObject *v, const formatdef *f) +{ + long x; + if (get_long(v, &x) < 0) + return -1; + if (x < 0 || x > 255){ + PyErr_SetString(StructError, + "ubyte format requires 0 <= number <= 255"); + return -1; + } + *p = (char)x; + return 0; +} + +static int +np_char(char *p, PyObject *v, const formatdef *f) +{ + if (!PyString_Check(v) || PyString_Size(v) != 1) { + PyErr_SetString(StructError, + "char format require string of length 1"); + return -1; + } + *p = *PyString_AsString(v); + return 0; +} + +static int +np_short(char *p, PyObject *v, const formatdef *f) +{ + long x; + short y; + if (get_long(v, &x) < 0) + return -1; + if (x < SHRT_MIN || x > SHRT_MAX){ + PyErr_SetString(StructError, + "short format requires " STRINGIFY(SHRT_MIN) + " <= number <= " STRINGIFY(SHRT_MAX)); + return -1; + } + y = (short)x; + memcpy(p, (char *)&y, sizeof y); + return 0; +} + +static int +np_ushort(char *p, PyObject *v, const formatdef *f) +{ + long x; + unsigned short y; + if (get_long(v, &x) < 0) + return -1; + if (x < 0 || x > USHRT_MAX){ + PyErr_SetString(StructError, + "short format requires 0 <= number <= " STRINGIFY(USHRT_MAX)); + return -1; + } + y = (unsigned short)x; + memcpy(p, (char *)&y, sizeof y); + return 0; +} + +static int +np_int(char *p, PyObject *v, const formatdef *f) +{ + long x; + int y; + if (get_long(v, &x) < 0) + return -1; +#if (SIZEOF_LONG > SIZEOF_INT) + if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX))) + return _range_error(f, 0); +#endif + y = (int)x; + memcpy(p, (char *)&y, sizeof y); + return 0; +} + +static int +np_uint(char *p, PyObject *v, const formatdef *f) +{ + unsigned long x; + unsigned int y; + if (get_ulong(v, &x) < 0) + return _range_error(f, 1); + y = (unsigned int)x; +#if (SIZEOF_LONG > SIZEOF_INT) + if (x > ((unsigned long)UINT_MAX)) + return _range_error(f, 1); +#endif + memcpy(p, (char *)&y, sizeof y); + return 0; +} + +static int +np_long(char *p, PyObject *v, const formatdef *f) +{ + long x; + if (get_long(v, &x) < 0) + return -1; + memcpy(p, (char *)&x, sizeof x); + return 0; +} + +static int +np_ulong(char *p, PyObject *v, const formatdef *f) +{ + unsigned long x; + if (get_ulong(v, &x) < 0) + return _range_error(f, 1); + memcpy(p, (char *)&x, sizeof x); + return 0; +} + +#ifdef HAVE_LONG_LONG + +static int +np_longlong(char *p, PyObject *v, const formatdef *f) +{ + PY_LONG_LONG x; + if (get_longlong(v, &x) < 0) + return -1; + memcpy(p, (char *)&x, sizeof x); + return 0; +} + +static int +np_ulonglong(char *p, PyObject *v, const formatdef *f) +{ + unsigned PY_LONG_LONG x; + if (get_ulonglong(v, &x) < 0) + return -1; + memcpy(p, (char *)&x, sizeof x); + return 0; +} +#endif + +static int +np_float(char *p, PyObject *v, const formatdef *f) +{ + float x = (float)PyFloat_AsDouble(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a float"); + return -1; + } + memcpy(p, (char *)&x, sizeof x); + return 0; +} + +static int +np_double(char *p, PyObject *v, const formatdef *f) +{ + double x = PyFloat_AsDouble(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a float"); + return -1; + } + memcpy(p, (char *)&x, sizeof(double)); + return 0; +} + +static int +np_void_p(char *p, PyObject *v, const formatdef *f) +{ + void *x; + + v = get_pylong(v); + if (v == NULL) + return -1; + assert(PyLong_Check(v)); + x = PyLong_AsVoidPtr(v); + Py_DECREF(v); + if (x == NULL && PyErr_Occurred()) + return -1; + memcpy(p, (char *)&x, sizeof x); + return 0; +} + +static formatdef native_table[] = { + {'x', sizeof(char), 0, NULL}, + {'b', sizeof(char), 0, nu_byte, np_byte}, + {'B', sizeof(char), 0, nu_ubyte, np_ubyte}, + {'c', sizeof(char), 0, nu_char, np_char}, + {'s', sizeof(char), 0, NULL}, + {'p', sizeof(char), 0, NULL}, + {'h', sizeof(short), SHORT_ALIGN, nu_short, np_short}, + {'H', sizeof(short), SHORT_ALIGN, nu_ushort, np_ushort}, + {'i', sizeof(int), INT_ALIGN, nu_int, np_int}, + {'I', sizeof(int), INT_ALIGN, nu_uint, np_uint}, + {'l', sizeof(long), LONG_ALIGN, nu_long, np_long}, + {'L', sizeof(long), LONG_ALIGN, nu_ulong, np_ulong}, +#ifdef HAVE_LONG_LONG + {'q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_longlong, np_longlong}, + {'Q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong}, +#endif + {'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float}, + {'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double}, + {'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p}, + {0} +}; + +/* Big-endian routines. *****************************************************/ + +static PyObject * +bu_int(const char *p, const formatdef *f) +{ + long x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | *bytes++; + } while (--i > 0); + /* Extend the sign bit. */ + if (SIZEOF_LONG > f->size) + x |= -(x & (1L << ((8 * f->size) - 1))); + return PyInt_FromLong(x); +} + +static PyObject * +bu_uint(const char *p, const formatdef *f) +{ + unsigned long x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | *bytes++; + } while (--i > 0); + if (x <= LONG_MAX) + return PyInt_FromLong((long)x); + return PyLong_FromUnsignedLong(x); +} + +static PyObject * +bu_longlong(const char *p, const formatdef *f) +{ +#ifdef HAVE_LONG_LONG + PY_LONG_LONG x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | *bytes++; + } while (--i > 0); + /* Extend the sign bit. */ + if (SIZEOF_LONG_LONG > f->size) + x |= -(x & ( (PY_LONG_LONG)1 << ((8 * f->size) - 1))); + if (x >= LONG_MIN && x <= LONG_MAX) + return PyInt_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long)); + return PyLong_FromLongLong(x); +#else + return _PyLong_FromByteArray((const unsigned char *)p, + 8, + 0, /* little-endian */ + 1 /* signed */); +#endif +} + +static PyObject * +bu_ulonglong(const char *p, const formatdef *f) +{ +#ifdef HAVE_LONG_LONG + unsigned PY_LONG_LONG x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | *bytes++; + } while (--i > 0); + if (x <= LONG_MAX) + return PyInt_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long)); + return PyLong_FromUnsignedLongLong(x); +#else + return _PyLong_FromByteArray((const unsigned char *)p, + 8, + 0, /* little-endian */ + 0 /* signed */); +#endif +} + +static PyObject * +bu_float(const char *p, const formatdef *f) +{ + return unpack_float(p, 0); +} + +static PyObject * +bu_double(const char *p, const formatdef *f) +{ + return unpack_double(p, 0); +} + +static int +bp_int(char *p, PyObject *v, const formatdef *f) +{ + long x; + Py_ssize_t i; + if (get_wrapped_long(v, &x) < 0) + return -1; + i = f->size; + if (i != SIZEOF_LONG) { + if ((i == 2) && (x < -32768 || x > 32767)) + RANGE_ERROR(x, f, 0, 0xffffL); +#if (SIZEOF_LONG != 4) + else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) + RANGE_ERROR(x, f, 0, 0xffffffffL); +#endif +#ifdef PY_STRUCT_OVERFLOW_MASKING + else if ((i == 1) && (x < -128 || x > 127)) + RANGE_ERROR(x, f, 0, 0xffL); +#endif + } + do { + p[--i] = (char)x; + x >>= 8; + } while (i > 0); + return 0; +} + +static int +bp_uint(char *p, PyObject *v, const formatdef *f) +{ + unsigned long x; + Py_ssize_t i; + if (get_wrapped_ulong(v, &x) < 0) + return -1; + i = f->size; + if (i != SIZEOF_LONG) { + unsigned long maxint = 1; + maxint <<= (unsigned long)(i * 8); + if (x >= maxint) + RANGE_ERROR(x, f, 1, maxint - 1); + } + do { + p[--i] = (char)x; + x >>= 8; + } while (i > 0); + return 0; +} + +static int +bp_longlong(char *p, PyObject *v, const formatdef *f) +{ + int res; + v = get_pylong(v); + if (v == NULL) + return -1; + res = _PyLong_AsByteArray((PyLongObject *)v, + (unsigned char *)p, + 8, + 0, /* little_endian */ + 1 /* signed */); + Py_DECREF(v); + return res; +} + +static int +bp_ulonglong(char *p, PyObject *v, const formatdef *f) +{ + int res; + v = get_pylong(v); + if (v == NULL) + return -1; + res = _PyLong_AsByteArray((PyLongObject *)v, + (unsigned char *)p, + 8, + 0, /* little_endian */ + 0 /* signed */); + Py_DECREF(v); + return res; +} + +static int +bp_float(char *p, PyObject *v, const formatdef *f) +{ + double x = PyFloat_AsDouble(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a float"); + return -1; + } + return _PyFloat_Pack4(x, (unsigned char *)p, 0); +} + +static int +bp_double(char *p, PyObject *v, const formatdef *f) +{ + double x = PyFloat_AsDouble(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a float"); + return -1; + } + return _PyFloat_Pack8(x, (unsigned char *)p, 0); +} + +static formatdef bigendian_table[] = { + {'x', 1, 0, NULL}, +#ifdef PY_STRUCT_OVERFLOW_MASKING + /* Native packers do range checking without overflow masking. */ + {'b', 1, 0, nu_byte, bp_int}, + {'B', 1, 0, nu_ubyte, bp_uint}, +#else + {'b', 1, 0, nu_byte, np_byte}, + {'B', 1, 0, nu_ubyte, np_ubyte}, +#endif + {'c', 1, 0, nu_char, np_char}, + {'s', 1, 0, NULL}, + {'p', 1, 0, NULL}, + {'h', 2, 0, bu_int, bp_int}, + {'H', 2, 0, bu_uint, bp_uint}, + {'i', 4, 0, bu_int, bp_int}, + {'I', 4, 0, bu_uint, bp_uint}, + {'l', 4, 0, bu_int, bp_int}, + {'L', 4, 0, bu_uint, bp_uint}, + {'q', 8, 0, bu_longlong, bp_longlong}, + {'Q', 8, 0, bu_ulonglong, bp_ulonglong}, + {'f', 4, 0, bu_float, bp_float}, + {'d', 8, 0, bu_double, bp_double}, + {0} +}; + +/* Little-endian routines. *****************************************************/ + +static PyObject * +lu_int(const char *p, const formatdef *f) +{ + long x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | bytes[--i]; + } while (i > 0); + /* Extend the sign bit. */ + if (SIZEOF_LONG > f->size) + x |= -(x & (1L << ((8 * f->size) - 1))); + return PyInt_FromLong(x); +} + +static PyObject * +lu_uint(const char *p, const formatdef *f) +{ + unsigned long x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | bytes[--i]; + } while (i > 0); + if (x <= LONG_MAX) + return PyInt_FromLong((long)x); + return PyLong_FromUnsignedLong((long)x); +} + +static PyObject * +lu_longlong(const char *p, const formatdef *f) +{ +#ifdef HAVE_LONG_LONG + PY_LONG_LONG x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | bytes[--i]; + } while (i > 0); + /* Extend the sign bit. */ + if (SIZEOF_LONG_LONG > f->size) + x |= -(x & ( (PY_LONG_LONG)1 << ((8 * f->size) - 1))); + if (x >= LONG_MIN && x <= LONG_MAX) + return PyInt_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long)); + return PyLong_FromLongLong(x); +#else + return _PyLong_FromByteArray((const unsigned char *)p, + 8, + 1, /* little-endian */ + 1 /* signed */); +#endif +} + +static PyObject * +lu_ulonglong(const char *p, const formatdef *f) +{ +#ifdef HAVE_LONG_LONG + unsigned PY_LONG_LONG x = 0; + Py_ssize_t i = f->size; + const unsigned char *bytes = (const unsigned char *)p; + do { + x = (x<<8) | bytes[--i]; + } while (i > 0); + if (x <= LONG_MAX) + return PyInt_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long)); + return PyLong_FromUnsignedLongLong(x); +#else + return _PyLong_FromByteArray((const unsigned char *)p, + 8, + 1, /* little-endian */ + 0 /* signed */); +#endif +} + +static PyObject * +lu_float(const char *p, const formatdef *f) +{ + return unpack_float(p, 1); +} + +static PyObject * +lu_double(const char *p, const formatdef *f) +{ + return unpack_double(p, 1); +} + +static int +lp_int(char *p, PyObject *v, const formatdef *f) +{ + long x; + Py_ssize_t i; + if (get_wrapped_long(v, &x) < 0) + return -1; + i = f->size; + if (i != SIZEOF_LONG) { + if ((i == 2) && (x < -32768 || x > 32767)) + RANGE_ERROR(x, f, 0, 0xffffL); +#if (SIZEOF_LONG != 4) + else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) + RANGE_ERROR(x, f, 0, 0xffffffffL); +#endif +#ifdef PY_STRUCT_OVERFLOW_MASKING + else if ((i == 1) && (x < -128 || x > 127)) + RANGE_ERROR(x, f, 0, 0xffL); +#endif + } + do { + *p++ = (char)x; + x >>= 8; + } while (--i > 0); + return 0; +} + +static int +lp_uint(char *p, PyObject *v, const formatdef *f) +{ + unsigned long x; + Py_ssize_t i; + if (get_wrapped_ulong(v, &x) < 0) + return -1; + i = f->size; + if (i != SIZEOF_LONG) { + unsigned long maxint = 1; + maxint <<= (unsigned long)(i * 8); + if (x >= maxint) + RANGE_ERROR(x, f, 1, maxint - 1); + } + do { + *p++ = (char)x; + x >>= 8; + } while (--i > 0); + return 0; +} + +static int +lp_longlong(char *p, PyObject *v, const formatdef *f) +{ + int res; + v = get_pylong(v); + if (v == NULL) + return -1; + res = _PyLong_AsByteArray((PyLongObject*)v, + (unsigned char *)p, + 8, + 1, /* little_endian */ + 1 /* signed */); + Py_DECREF(v); + return res; +} + +static int +lp_ulonglong(char *p, PyObject *v, const formatdef *f) +{ + int res; + v = get_pylong(v); + if (v == NULL) + return -1; + res = _PyLong_AsByteArray((PyLongObject*)v, + (unsigned char *)p, + 8, + 1, /* little_endian */ + 0 /* signed */); + Py_DECREF(v); + return res; +} + +static int +lp_float(char *p, PyObject *v, const formatdef *f) +{ + double x = PyFloat_AsDouble(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a float"); + return -1; + } + return _PyFloat_Pack4(x, (unsigned char *)p, 1); +} + +static int +lp_double(char *p, PyObject *v, const formatdef *f) +{ + double x = PyFloat_AsDouble(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a float"); + return -1; + } + return _PyFloat_Pack8(x, (unsigned char *)p, 1); +} + +static formatdef lilendian_table[] = { + {'x', 1, 0, NULL}, +#ifdef PY_STRUCT_OVERFLOW_MASKING + /* Native packers do range checking without overflow masking. */ + {'b', 1, 0, nu_byte, lp_int}, + {'B', 1, 0, nu_ubyte, lp_uint}, +#else + {'b', 1, 0, nu_byte, np_byte}, + {'B', 1, 0, nu_ubyte, np_ubyte}, +#endif + {'c', 1, 0, nu_char, np_char}, + {'s', 1, 0, NULL}, + {'p', 1, 0, NULL}, + {'h', 2, 0, lu_int, lp_int}, + {'H', 2, 0, lu_uint, lp_uint}, + {'i', 4, 0, lu_int, lp_int}, + {'I', 4, 0, lu_uint, lp_uint}, + {'l', 4, 0, lu_int, lp_int}, + {'L', 4, 0, lu_uint, lp_uint}, + {'q', 8, 0, lu_longlong, lp_longlong}, + {'Q', 8, 0, lu_ulonglong, lp_ulonglong}, + {'f', 4, 0, lu_float, lp_float}, + {'d', 8, 0, lu_double, lp_double}, + {0} +}; + + +static const formatdef * +whichtable(char **pfmt) +{ + const char *fmt = (*pfmt)++; /* May be backed out of later */ + switch (*fmt) { + case '<': + return lilendian_table; + case '>': + case '!': /* Network byte order is big-endian */ + return bigendian_table; + case '=': { /* Host byte order -- different from native in aligment! */ + int n = 1; + char *p = (char *) &n; + if (*p == 1) + return lilendian_table; + else + return bigendian_table; + } + default: + --*pfmt; /* Back out of pointer increment */ + /* Fall through */ + case '@': + return native_table; + } +} + + +/* Get the table entry for a format code */ + +static const formatdef * +getentry(int c, const formatdef *f) +{ + for (; f->format != '\0'; f++) { + if (f->format == c) { + return f; + } + } + PyErr_SetString(StructError, "bad char in struct format"); + return NULL; +} + + +/* Align a size according to a format code */ + +static int +align(Py_ssize_t size, char c, const formatdef *e) +{ + if (e->format == c) { + if (e->alignment) { + size = ((size + e->alignment - 1) + / e->alignment) + * e->alignment; + } + } + return size; +} + + +/* calculate the size of a format string */ + +static int +prepare_s(PyStructObject *self) +{ + const formatdef *f; + const formatdef *e; + formatcode *codes; + + const char *s; + const char *fmt; + char c; + Py_ssize_t size, len, num, itemsize, x; + + fmt = PyString_AS_STRING(self->s_format); + + f = whichtable((char **)&fmt); + + s = fmt; + size = 0; + len = 0; + while ((c = *s++) != '\0') { + if (isspace(Py_CHARMASK(c))) + continue; + if ('0' <= c && c <= '9') { + num = c - '0'; + while ('0' <= (c = *s++) && c <= '9') { + x = num*10 + (c - '0'); + if (x/10 != num) { + PyErr_SetString( + StructError, + "overflow in item count"); + return -1; + } + num = x; + } + if (c == '\0') + break; + } + else + num = 1; + + e = getentry(c, f); + if (e == NULL) + return -1; + + switch (c) { + case 's': /* fall through */ + case 'p': len++; break; + case 'x': break; + default: len += num; break; + } + + itemsize = e->size; + size = align(size, c, e); + x = num * itemsize; + size += x; + if (x/itemsize != num || size < 0) { + PyErr_SetString(StructError, + "total struct size too long"); + return -1; + } + } + + self->s_size = size; + self->s_len = len; + codes = PyMem_MALLOC((len + 1) * sizeof(formatcode)); + if (codes == NULL) { + PyErr_NoMemory(); + return -1; + } + self->s_codes = codes; + + s = fmt; + size = 0; + while ((c = *s++) != '\0') { + if (isspace(Py_CHARMASK(c))) + continue; + if ('0' <= c && c <= '9') { + num = c - '0'; + while ('0' <= (c = *s++) && c <= '9') + num = num*10 + (c - '0'); + if (c == '\0') + break; + } + else + num = 1; + + e = getentry(c, f); + + size = align(size, c, e); + if (c == 's' || c == 'p') { + codes->offset = size; + codes->size = num; + codes->fmtdef = e; + codes++; + size += num; + } else if (c == 'x') { + size += num; + } else { + while (--num >= 0) { + codes->offset = size; + codes->size = e->size; + codes->fmtdef = e; + codes++; + size += e->size; + } + } + } + codes->fmtdef = NULL; + codes->offset = size; + codes->size = 0; + + return 0; +} + +static PyObject * +s_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *self; + + assert(type != NULL && type->tp_alloc != NULL); + + self = type->tp_alloc(type, 0); + if (self != NULL) { + PyStructObject *s = (PyStructObject*)self; + Py_INCREF(Py_None); + s->s_format = Py_None; + s->s_codes = NULL; + s->s_size = -1; + s->s_len = -1; + } + return self; +} + +static int +s_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyStructObject *soself = (PyStructObject *)self; + PyObject *o_format = NULL; + int ret = 0; + static char *kwlist[] = {"format", 0}; + + assert(PyStruct_Check(self)); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:Struct", kwlist, + &o_format)) + return -1; + + Py_INCREF(o_format); + Py_XDECREF(soself->s_format); + soself->s_format = o_format; + + ret = prepare_s(soself); + return ret; +} + +static void +s_dealloc(PyStructObject *s) +{ + if (s->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *)s); + if (s->s_codes != NULL) { + PyMem_FREE(s->s_codes); + } + Py_XDECREF(s->s_format); + s->ob_type->tp_free((PyObject *)s); +} + +static PyObject * +s_unpack_internal(PyStructObject *soself, char *startfrom) { + formatcode *code; + Py_ssize_t i = 0; + PyObject *result = PyTuple_New(soself->s_len); + if (result == NULL) + return NULL; + + for (code = soself->s_codes; code->fmtdef != NULL; code++) { + PyObject *v; + const formatdef *e = code->fmtdef; + const char *res = startfrom + code->offset; + if (e->format == 's') { + v = PyString_FromStringAndSize(res, code->size); + } else if (e->format == 'p') { + Py_ssize_t n = *(unsigned char*)res; + if (n >= code->size) + n = code->size - 1; + v = PyString_FromStringAndSize(res + 1, n); + } else { + v = e->unpack(res, e); + } + if (v == NULL) + goto fail; + PyTuple_SET_ITEM(result, i++, v); + } + + return result; +fail: + Py_DECREF(result); + return NULL; +} + + +PyDoc_STRVAR(s_unpack__doc__, +"S.unpack(str) -> (v1, v2, ...)\n\ +\n\ +Return tuple containing values unpacked according to this Struct's format.\n\ +Requires len(str) == self.size. See struct.__doc__ for more on format\n\ +strings."); + +static PyObject * +s_unpack(PyObject *self, PyObject *inputstr) +{ + char *start; + Py_ssize_t len; + PyObject *args=NULL, *result; + PyStructObject *soself = (PyStructObject *)self; + assert(PyStruct_Check(self)); + assert(soself->s_codes != NULL); + if (inputstr == NULL) + goto fail; + if (PyString_Check(inputstr) && + PyString_GET_SIZE(inputstr) == soself->s_size) { + return s_unpack_internal(soself, PyString_AS_STRING(inputstr)); + } + args = PyTuple_Pack(1, inputstr); + if (args == NULL) + return NULL; + if (!PyArg_ParseTuple(args, "s#:unpack", &start, &len)) + goto fail; + if (soself->s_size != len) + goto fail; + result = s_unpack_internal(soself, start); + Py_DECREF(args); + return result; + +fail: + Py_XDECREF(args); + PyErr_Format(StructError, + "unpack requires a string argument of length %zd", + soself->s_size); + return NULL; +} + +PyDoc_STRVAR(s_unpack_from__doc__, +"S.unpack_from(buffer[, offset]) -> (v1, v2, ...)\n\ +\n\ +Return tuple containing values unpacked according to this Struct's format.\n\ +Unlike unpack, unpack_from can unpack values from any object supporting\n\ +the buffer API, not just str. Requires len(buffer[offset:]) >= self.size.\n\ +See struct.__doc__ for more on format strings."); + +static PyObject * +s_unpack_from(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"buffer", "offset", 0}; +#if (PY_VERSION_HEX < 0x02050000) + static char *fmt = "z#|i:unpack_from"; +#else + static char *fmt = "z#|n:unpack_from"; +#endif + Py_ssize_t buffer_len = 0, offset = 0; + char *buffer = NULL; + PyStructObject *soself = (PyStructObject *)self; + assert(PyStruct_Check(self)); + assert(soself->s_codes != NULL); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, fmt, kwlist, + &buffer, &buffer_len, &offset)) + return NULL; + + if (buffer == NULL) { + PyErr_Format(StructError, + "unpack_from requires a buffer argument"); + return NULL; + } + + if (offset < 0) + offset += buffer_len; + + if (offset < 0 || (buffer_len - offset) < soself->s_size) { + PyErr_Format(StructError, + "unpack_from requires a buffer of at least %zd bytes", + soself->s_size); + return NULL; + } + return s_unpack_internal(soself, buffer + offset); +} + + +/* + * Guts of the pack function. + * + * Takes a struct object, a tuple of arguments, and offset in that tuple of + * argument for where to start processing the arguments for packing, and a + * character buffer for writing the packed string. The caller must insure + * that the buffer may contain the required length for packing the arguments. + * 0 is returned on success, 1 is returned if there is an error. + * + */ +static int +s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf) +{ + formatcode *code; + /* XXX(nnorwitz): why does i need to be a local? can we use + the offset parameter or do we need the wider width? */ + Py_ssize_t i; + + memset(buf, '\0', soself->s_size); + i = offset; + for (code = soself->s_codes; code->fmtdef != NULL; code++) { + Py_ssize_t n; + PyObject *v = PyTuple_GET_ITEM(args, i++); + const formatdef *e = code->fmtdef; + char *res = buf + code->offset; + if (e->format == 's') { + if (!PyString_Check(v)) { + PyErr_SetString(StructError, + "argument for 's' must be a string"); + return -1; + } + n = PyString_GET_SIZE(v); + if (n > code->size) + n = code->size; + if (n > 0) + memcpy(res, PyString_AS_STRING(v), n); + } else if (e->format == 'p') { + if (!PyString_Check(v)) { + PyErr_SetString(StructError, + "argument for 'p' must be a string"); + return -1; + } + n = PyString_GET_SIZE(v); + if (n > (code->size - 1)) + n = code->size - 1; + if (n > 0) + memcpy(res + 1, PyString_AS_STRING(v), n); + if (n > 255) + n = 255; + *res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char); + } else { + if (e->pack(res, v, e) < 0) { + if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError)) + PyErr_SetString(StructError, + "long too large to convert to int"); + return -1; + } + } + } + + /* Success */ + return 0; +} + + +PyDoc_STRVAR(s_pack__doc__, +"S.pack(v1, v2, ...) -> string\n\ +\n\ +Return a string containing values v1, v2, ... packed according to this\n\ +Struct's format. See struct.__doc__ for more on format strings."); + +static PyObject * +s_pack(PyObject *self, PyObject *args) +{ + PyStructObject *soself; + PyObject *result; + + /* Validate arguments. */ + soself = (PyStructObject *)self; + assert(PyStruct_Check(self)); + assert(soself->s_codes != NULL); + if (PyTuple_GET_SIZE(args) != soself->s_len) + { + PyErr_Format(StructError, + "pack requires exactly %zd arguments", soself->s_len); + return NULL; + } + + /* Allocate a new string */ + result = PyString_FromStringAndSize((char *)NULL, soself->s_size); + if (result == NULL) + return NULL; + + /* Call the guts */ + if ( s_pack_internal(soself, args, 0, PyString_AS_STRING(result)) != 0 ) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +PyDoc_STRVAR(s_pack_into__doc__, +"S.pack_into(buffer, offset, v1, v2, ...)\n\ +\n\ +Pack the values v1, v2, ... according to this Struct's format, write \n\ +the packed bytes into the writable buffer buf starting at offset. Note\n\ +that the offset is not an optional argument. See struct.__doc__ for \n\ +more on format strings."); + +static PyObject * +s_pack_into(PyObject *self, PyObject *args) +{ + PyStructObject *soself; + char *buffer; + Py_ssize_t buffer_len, offset; + + /* Validate arguments. +1 is for the first arg as buffer. */ + soself = (PyStructObject *)self; + assert(PyStruct_Check(self)); + assert(soself->s_codes != NULL); + if (PyTuple_GET_SIZE(args) != (soself->s_len + 2)) + { + PyErr_Format(StructError, + "pack_into requires exactly %zd arguments", + (soself->s_len + 2)); + return NULL; + } + + /* Extract a writable memory buffer from the first argument */ + if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0), + (void**)&buffer, &buffer_len) == -1 ) { + return NULL; + } + assert( buffer_len >= 0 ); + + /* Extract the offset from the first argument */ + offset = PyInt_AsSsize_t(PyTuple_GET_ITEM(args, 1)); + + /* Support negative offsets. */ + if (offset < 0) + offset += buffer_len; + + /* Check boundaries */ + if (offset < 0 || (buffer_len - offset) < soself->s_size) { + PyErr_Format(StructError, + "pack_into requires a buffer of at least %zd bytes", + soself->s_size); + return NULL; + } + + /* Call the guts */ + if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) { + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +s_get_format(PyStructObject *self, void *unused) +{ + Py_INCREF(self->s_format); + return self->s_format; +} + +static PyObject * +s_get_size(PyStructObject *self, void *unused) +{ + return PyInt_FromSsize_t(self->s_size); +} + +/* List of functions */ + +static struct PyMethodDef s_methods[] = { + {"pack", s_pack, METH_VARARGS, s_pack__doc__}, + {"pack_into", s_pack_into, METH_VARARGS, s_pack_into__doc__}, + {"unpack", s_unpack, METH_O, s_unpack__doc__}, + {"unpack_from", (PyCFunction)s_unpack_from, METH_KEYWORDS, + s_unpack_from__doc__}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(s__doc__, "Compiled struct object"); + +#define OFF(x) offsetof(PyStructObject, x) + +static PyGetSetDef s_getsetlist[] = { + {"format", (getter)s_get_format, (setter)NULL, "struct format string", NULL}, + {"size", (getter)s_get_size, (setter)NULL, "struct size in bytes", NULL}, + {NULL} /* sentinel */ +}; + +static +PyTypeObject PyStructType = { + PyObject_HEAD_INIT(NULL) + 0, + "Struct", + sizeof(PyStructObject), + 0, + (destructor)s_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS,/* tp_flags */ + s__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyStructObject, weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + s_methods, /* tp_methods */ + NULL, /* tp_members */ + s_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + s_init, /* tp_init */ + PyType_GenericAlloc,/* tp_alloc */ + s_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + +/* Module initialization */ + +PyMODINIT_FUNC +init_struct(void) +{ + PyObject *m = Py_InitModule("_struct", NULL); + if (m == NULL) + return; + + PyStructType.ob_type = &PyType_Type; + if (PyType_Ready(&PyStructType) < 0) + return; + +#ifdef PY_STRUCT_OVERFLOW_MASKING + if (pyint_zero == NULL) { + pyint_zero = PyInt_FromLong(0); + if (pyint_zero == NULL) + return; + } + if (pylong_ulong_mask == NULL) { +#if (SIZEOF_LONG == 4) + pylong_ulong_mask = PyLong_FromString("FFFFFFFF", NULL, 16); +#else + pylong_ulong_mask = PyLong_FromString("FFFFFFFFFFFFFFFF", NULL, 16); +#endif + if (pylong_ulong_mask == NULL) + return; + } + +#else + /* This speed trick can't be used until overflow masking goes away, because + native endian always raises exceptions instead of overflow masking. */ + + /* Check endian and swap in faster functions */ + { + int one = 1; + formatdef *native = native_table; + formatdef *other, *ptr; + if ((int)*(unsigned char*)&one) + other = lilendian_table; + else + other = bigendian_table; + /* Scan through the native table, find a matching + entry in the endian table and swap in the + native implementations whenever possible + (64-bit platforms may not have "standard" sizes) */ + while (native->format != '\0' && other->format != '\0') { + ptr = other; + while (ptr->format != '\0') { + if (ptr->format == native->format) { + /* Match faster when formats are + listed in the same order */ + if (ptr == other) + other++; + /* Only use the trick if the + size matches */ + if (ptr->size != native->size) + break; + /* Skip float and double, could be + "unknown" float format */ + if (ptr->format == 'd' || ptr->format == 'f') + break; + ptr->pack = native->pack; + ptr->unpack = native->unpack; + break; + } + ptr++; + } + native++; + } + } +#endif + + /* Add some symbolic constants to the module */ + if (StructError == NULL) { + StructError = PyErr_NewException("struct.error", NULL, NULL); + if (StructError == NULL) + return; + } + + Py_INCREF(StructError); + PyModule_AddObject(m, "error", StructError); + + Py_INCREF((PyObject*)&PyStructType); + PyModule_AddObject(m, "Struct", (PyObject*)&PyStructType); + + PyModule_AddIntConstant(m, "_PY_STRUCT_RANGE_CHECKING", 1); +#ifdef PY_STRUCT_OVERFLOW_MASKING + PyModule_AddIntConstant(m, "_PY_STRUCT_OVERFLOW_MASKING", 1); +#endif +#ifdef PY_STRUCT_FLOAT_COERCE + PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1); +#endif + +} diff --git a/sys/src/cmd/python/Modules/_testcapimodule.c b/sys/src/cmd/python/Modules/_testcapimodule.c new file mode 100644 index 000000000..b11f0aebf --- /dev/null +++ b/sys/src/cmd/python/Modules/_testcapimodule.c @@ -0,0 +1,898 @@ +/* + * C Extension module to test Python interpreter C APIs. + * + * The 'test_*' functions exported by this module are run as part of the + * standard Python regression test, via Lib/test/test_capi.py. + */ + +#include "Python.h" +#include <float.h> +#include "structmember.h" + +#ifdef WITH_THREAD +#include "pythread.h" +#endif /* WITH_THREAD */ +static PyObject *TestError; /* set to exception object in init */ + +/* Raise TestError with test_name + ": " + msg, and return NULL. */ + +static PyObject * +raiseTestError(const char* test_name, const char* msg) +{ + char buf[2048]; + + if (strlen(test_name) + strlen(msg) > sizeof(buf) - 50) + PyErr_SetString(TestError, "internal error msg too large"); + else { + PyOS_snprintf(buf, sizeof(buf), "%s: %s", test_name, msg); + PyErr_SetString(TestError, buf); + } + return NULL; +} + +/* Test #defines from pyconfig.h (particularly the SIZEOF_* defines). + + The ones derived from autoconf on the UNIX-like OSes can be relied + upon (in the absence of sloppy cross-compiling), but the Windows + platforms have these hardcoded. Better safe than sorry. +*/ +static PyObject* +sizeof_error(const char* fatname, const char* typname, + int expected, int got) +{ + char buf[1024]; + PyOS_snprintf(buf, sizeof(buf), + "%.200s #define == %d but sizeof(%.200s) == %d", + fatname, expected, typname, got); + PyErr_SetString(TestError, buf); + return (PyObject*)NULL; +} + +static PyObject* +test_config(PyObject *self) +{ +#define CHECK_SIZEOF(FATNAME, TYPE) \ + if (FATNAME != sizeof(TYPE)) \ + return sizeof_error(#FATNAME, #TYPE, FATNAME, sizeof(TYPE)) + + CHECK_SIZEOF(SIZEOF_SHORT, short); + CHECK_SIZEOF(SIZEOF_INT, int); + CHECK_SIZEOF(SIZEOF_LONG, long); + CHECK_SIZEOF(SIZEOF_VOID_P, void*); + CHECK_SIZEOF(SIZEOF_TIME_T, time_t); +#ifdef HAVE_LONG_LONG + CHECK_SIZEOF(SIZEOF_LONG_LONG, PY_LONG_LONG); +#endif + +#undef CHECK_SIZEOF + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* +test_list_api(PyObject *self) +{ + PyObject* list; + int i; + + /* SF bug 132008: PyList_Reverse segfaults */ +#define NLIST 30 + list = PyList_New(NLIST); + if (list == (PyObject*)NULL) + return (PyObject*)NULL; + /* list = range(NLIST) */ + for (i = 0; i < NLIST; ++i) { + PyObject* anint = PyInt_FromLong(i); + if (anint == (PyObject*)NULL) { + Py_DECREF(list); + return (PyObject*)NULL; + } + PyList_SET_ITEM(list, i, anint); + } + /* list.reverse(), via PyList_Reverse() */ + i = PyList_Reverse(list); /* should not blow up! */ + if (i != 0) { + Py_DECREF(list); + return (PyObject*)NULL; + } + /* Check that list == range(29, -1, -1) now */ + for (i = 0; i < NLIST; ++i) { + PyObject* anint = PyList_GET_ITEM(list, i); + if (PyInt_AS_LONG(anint) != NLIST-1-i) { + PyErr_SetString(TestError, + "test_list_api: reverse screwed up"); + Py_DECREF(list); + return (PyObject*)NULL; + } + } + Py_DECREF(list); +#undef NLIST + + Py_INCREF(Py_None); + return Py_None; +} + +static int +test_dict_inner(int count) +{ + Py_ssize_t pos = 0, iterations = 0; + int i; + PyObject *dict = PyDict_New(); + PyObject *v, *k; + + if (dict == NULL) + return -1; + + for (i = 0; i < count; i++) { + v = PyInt_FromLong(i); + PyDict_SetItem(dict, v, v); + Py_DECREF(v); + } + + while (PyDict_Next(dict, &pos, &k, &v)) { + PyObject *o; + iterations++; + + i = PyInt_AS_LONG(v) + 1; + o = PyInt_FromLong(i); + if (o == NULL) + return -1; + if (PyDict_SetItem(dict, k, o) < 0) { + Py_DECREF(o); + return -1; + } + Py_DECREF(o); + } + + Py_DECREF(dict); + + if (iterations != count) { + PyErr_SetString( + TestError, + "test_dict_iteration: dict iteration went wrong "); + return -1; + } else { + return 0; + } +} + +static PyObject* +test_dict_iteration(PyObject* self) +{ + int i; + + for (i = 0; i < 200; i++) { + if (test_dict_inner(i) < 0) { + return NULL; + } + } + + Py_INCREF(Py_None); + return Py_None; +} + + +/* Tests of PyLong_{As, From}{Unsigned,}Long(), and (#ifdef HAVE_LONG_LONG) + PyLong_{As, From}{Unsigned,}LongLong(). + + Note that the meat of the test is contained in testcapi_long.h. + This is revolting, but delicate code duplication is worse: "almost + exactly the same" code is needed to test PY_LONG_LONG, but the ubiquitous + dependence on type names makes it impossible to use a parameterized + function. A giant macro would be even worse than this. A C++ template + would be perfect. + + The "report an error" functions are deliberately not part of the #include + file: if the test fails, you can set a breakpoint in the appropriate + error function directly, and crawl back from there in the debugger. +*/ + +#define UNBIND(X) Py_DECREF(X); (X) = NULL + +static PyObject * +raise_test_long_error(const char* msg) +{ + return raiseTestError("test_long_api", msg); +} + +#define TESTNAME test_long_api_inner +#define TYPENAME long +#define F_S_TO_PY PyLong_FromLong +#define F_PY_TO_S PyLong_AsLong +#define F_U_TO_PY PyLong_FromUnsignedLong +#define F_PY_TO_U PyLong_AsUnsignedLong + +#include "testcapi_long.h" + +static PyObject * +test_long_api(PyObject* self) +{ + return TESTNAME(raise_test_long_error); +} + +#undef TESTNAME +#undef TYPENAME +#undef F_S_TO_PY +#undef F_PY_TO_S +#undef F_U_TO_PY +#undef F_PY_TO_U + +#ifdef HAVE_LONG_LONG + +static PyObject * +raise_test_longlong_error(const char* msg) +{ + return raiseTestError("test_longlong_api", msg); +} + +#define TESTNAME test_longlong_api_inner +#define TYPENAME PY_LONG_LONG +#define F_S_TO_PY PyLong_FromLongLong +#define F_PY_TO_S PyLong_AsLongLong +#define F_U_TO_PY PyLong_FromUnsignedLongLong +#define F_PY_TO_U PyLong_AsUnsignedLongLong + +#include "testcapi_long.h" + +static PyObject * +test_longlong_api(PyObject* self, PyObject *args) +{ + return TESTNAME(raise_test_longlong_error); +} + +#undef TESTNAME +#undef TYPENAME +#undef F_S_TO_PY +#undef F_PY_TO_S +#undef F_U_TO_PY +#undef F_PY_TO_U + +/* Test the L code for PyArg_ParseTuple. This should deliver a PY_LONG_LONG + for both long and int arguments. The test may leak a little memory if + it fails. +*/ +static PyObject * +test_L_code(PyObject *self) +{ + PyObject *tuple, *num; + PY_LONG_LONG value; + + tuple = PyTuple_New(1); + if (tuple == NULL) + return NULL; + + num = PyLong_FromLong(42); + if (num == NULL) + return NULL; + + PyTuple_SET_ITEM(tuple, 0, num); + + value = -1; + if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0) + return NULL; + if (value != 42) + return raiseTestError("test_L_code", + "L code returned wrong value for long 42"); + + Py_DECREF(num); + num = PyInt_FromLong(42); + if (num == NULL) + return NULL; + + PyTuple_SET_ITEM(tuple, 0, num); + + value = -1; + if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0) + return NULL; + if (value != 42) + return raiseTestError("test_L_code", + "L code returned wrong value for int 42"); + + Py_DECREF(tuple); + Py_INCREF(Py_None); + return Py_None; +} + +#endif /* ifdef HAVE_LONG_LONG */ + +/* Test tuple argument processing */ +static PyObject * +getargs_tuple(PyObject *self, PyObject *args) +{ + int a, b, c; + if (!PyArg_ParseTuple(args, "i(ii)", &a, &b, &c)) + return NULL; + return Py_BuildValue("iii", a, b, c); +} + +/* Functions to call PyArg_ParseTuple with integer format codes, + and return the result. +*/ +static PyObject * +getargs_b(PyObject *self, PyObject *args) +{ + unsigned char value; + if (!PyArg_ParseTuple(args, "b", &value)) + return NULL; + return PyLong_FromUnsignedLong((unsigned long)value); +} + +static PyObject * +getargs_B(PyObject *self, PyObject *args) +{ + unsigned char value; + if (!PyArg_ParseTuple(args, "B", &value)) + return NULL; + return PyLong_FromUnsignedLong((unsigned long)value); +} + +static PyObject * +getargs_H(PyObject *self, PyObject *args) +{ + unsigned short value; + if (!PyArg_ParseTuple(args, "H", &value)) + return NULL; + return PyLong_FromUnsignedLong((unsigned long)value); +} + +static PyObject * +getargs_I(PyObject *self, PyObject *args) +{ + unsigned int value; + if (!PyArg_ParseTuple(args, "I", &value)) + return NULL; + return PyLong_FromUnsignedLong((unsigned long)value); +} + +static PyObject * +getargs_k(PyObject *self, PyObject *args) +{ + unsigned long value; + if (!PyArg_ParseTuple(args, "k", &value)) + return NULL; + return PyLong_FromUnsignedLong(value); +} + +static PyObject * +getargs_i(PyObject *self, PyObject *args) +{ + int value; + if (!PyArg_ParseTuple(args, "i", &value)) + return NULL; + return PyLong_FromLong((long)value); +} + +static PyObject * +getargs_l(PyObject *self, PyObject *args) +{ + long value; + if (!PyArg_ParseTuple(args, "l", &value)) + return NULL; + return PyLong_FromLong(value); +} + +static PyObject * +getargs_n(PyObject *self, PyObject *args) +{ + Py_ssize_t value; + if (!PyArg_ParseTuple(args, "n", &value)) + return NULL; + return PyInt_FromSsize_t(value); +} + +#ifdef HAVE_LONG_LONG +static PyObject * +getargs_L(PyObject *self, PyObject *args) +{ + PY_LONG_LONG value; + if (!PyArg_ParseTuple(args, "L", &value)) + return NULL; + return PyLong_FromLongLong(value); +} + +static PyObject * +getargs_K(PyObject *self, PyObject *args) +{ + unsigned PY_LONG_LONG value; + if (!PyArg_ParseTuple(args, "K", &value)) + return NULL; + return PyLong_FromUnsignedLongLong(value); +} +#endif + +/* This function not only tests the 'k' getargs code, but also the + PyInt_AsUnsignedLongMask() and PyInt_AsUnsignedLongMask() functions. */ +static PyObject * +test_k_code(PyObject *self) +{ + PyObject *tuple, *num; + unsigned long value; + + tuple = PyTuple_New(1); + if (tuple == NULL) + return NULL; + + /* a number larger than ULONG_MAX even on 64-bit platforms */ + num = PyLong_FromString("FFFFFFFFFFFFFFFFFFFFFFFF", NULL, 16); + if (num == NULL) + return NULL; + + value = PyInt_AsUnsignedLongMask(num); + if (value != ULONG_MAX) + return raiseTestError("test_k_code", + "PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); + + PyTuple_SET_ITEM(tuple, 0, num); + + value = 0; + if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) + return NULL; + if (value != ULONG_MAX) + return raiseTestError("test_k_code", + "k code returned wrong value for long 0xFFF...FFF"); + + Py_DECREF(num); + num = PyLong_FromString("-FFFFFFFF000000000000000042", NULL, 16); + if (num == NULL) + return NULL; + + value = PyInt_AsUnsignedLongMask(num); + if (value != (unsigned long)-0x42) + return raiseTestError("test_k_code", + "PyInt_AsUnsignedLongMask() returned wrong value for long 0xFFF...FFF"); + + PyTuple_SET_ITEM(tuple, 0, num); + + value = 0; + if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0) + return NULL; + if (value != (unsigned long)-0x42) + return raiseTestError("test_k_code", + "k code returned wrong value for long -0xFFF..000042"); + + Py_DECREF(tuple); + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef Py_USING_UNICODE + +/* Test the u and u# codes for PyArg_ParseTuple. May leak memory in case + of an error. +*/ +static PyObject * +test_u_code(PyObject *self) +{ + PyObject *tuple, *obj; + Py_UNICODE *value; + int len; + + tuple = PyTuple_New(1); + if (tuple == NULL) + return NULL; + + obj = PyUnicode_Decode("test", strlen("test"), + "ascii", NULL); + if (obj == NULL) + return NULL; + + PyTuple_SET_ITEM(tuple, 0, obj); + + value = 0; + if (PyArg_ParseTuple(tuple, "u:test_u_code", &value) < 0) + return NULL; + if (value != PyUnicode_AS_UNICODE(obj)) + return raiseTestError("test_u_code", + "u code returned wrong value for u'test'"); + value = 0; + if (PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len) < 0) + return NULL; + if (value != PyUnicode_AS_UNICODE(obj) || + len != PyUnicode_GET_SIZE(obj)) + return raiseTestError("test_u_code", + "u# code returned wrong values for u'test'"); + + Py_DECREF(tuple); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +codec_incrementalencoder(PyObject *self, PyObject *args) +{ + const char *encoding, *errors = NULL; + if (!PyArg_ParseTuple(args, "s|s:test_incrementalencoder", + &encoding, &errors)) + return NULL; + return PyCodec_IncrementalEncoder(encoding, errors); +} + +static PyObject * +codec_incrementaldecoder(PyObject *self, PyObject *args) +{ + const char *encoding, *errors = NULL; + if (!PyArg_ParseTuple(args, "s|s:test_incrementaldecoder", + &encoding, &errors)) + return NULL; + return PyCodec_IncrementalDecoder(encoding, errors); +} + +#endif + +/* Simple test of _PyLong_NumBits and _PyLong_Sign. */ +static PyObject * +test_long_numbits(PyObject *self) +{ + struct triple { + long input; + size_t nbits; + int sign; + } testcases[] = {{0, 0, 0}, + {1L, 1, 1}, + {-1L, 1, -1}, + {2L, 2, 1}, + {-2L, 2, -1}, + {3L, 2, 1}, + {-3L, 2, -1}, + {4L, 3, 1}, + {-4L, 3, -1}, + {0x7fffL, 15, 1}, /* one Python long digit */ + {-0x7fffL, 15, -1}, + {0xffffL, 16, 1}, + {-0xffffL, 16, -1}, + {0xfffffffL, 28, 1}, + {-0xfffffffL, 28, -1}}; + int i; + + for (i = 0; i < sizeof(testcases) / sizeof(struct triple); ++i) { + PyObject *plong = PyLong_FromLong(testcases[i].input); + size_t nbits = _PyLong_NumBits(plong); + int sign = _PyLong_Sign(plong); + + Py_DECREF(plong); + if (nbits != testcases[i].nbits) + return raiseTestError("test_long_numbits", + "wrong result for _PyLong_NumBits"); + if (sign != testcases[i].sign) + return raiseTestError("test_long_numbits", + "wrong result for _PyLong_Sign"); + } + Py_INCREF(Py_None); + return Py_None; +} + +/* Example passing NULLs to PyObject_Str(NULL) and PyObject_Unicode(NULL). */ + +static PyObject * +test_null_strings(PyObject *self) +{ + PyObject *o1 = PyObject_Str(NULL), *o2 = PyObject_Unicode(NULL); + PyObject *tuple = PyTuple_Pack(2, o1, o2); + Py_XDECREF(o1); + Py_XDECREF(o2); + return tuple; +} + +static PyObject * +raise_exception(PyObject *self, PyObject *args) +{ + PyObject *exc; + PyObject *exc_args, *v; + int num_args, i; + + if (!PyArg_ParseTuple(args, "Oi:raise_exception", + &exc, &num_args)) + return NULL; + + exc_args = PyTuple_New(num_args); + if (exc_args == NULL) + return NULL; + for (i = 0; i < num_args; ++i) { + v = PyInt_FromLong(i); + if (v == NULL) { + Py_DECREF(exc_args); + return NULL; + } + PyTuple_SET_ITEM(exc_args, i, v); + } + PyErr_SetObject(exc, exc_args); + Py_DECREF(exc_args); + return NULL; +} + +#ifdef WITH_THREAD + +/* test_thread_state spawns a thread of its own, and that thread releases + * `thread_done` when it's finished. The driver code has to know when the + * thread finishes, because the thread uses a PyObject (the callable) that + * may go away when the driver finishes. The former lack of this explicit + * synchronization caused rare segfaults, so rare that they were seen only + * on a Mac buildbot (although they were possible on any box). + */ +static PyThread_type_lock thread_done = NULL; + +static void +_make_call(void *callable) +{ + PyObject *rc; + PyGILState_STATE s = PyGILState_Ensure(); + rc = PyObject_CallFunction((PyObject *)callable, ""); + Py_XDECREF(rc); + PyGILState_Release(s); +} + +/* Same thing, but releases `thread_done` when it returns. This variant + * should be called only from threads spawned by test_thread_state(). + */ +static void +_make_call_from_thread(void *callable) +{ + _make_call(callable); + PyThread_release_lock(thread_done); +} + +static PyObject * +test_thread_state(PyObject *self, PyObject *args) +{ + PyObject *fn; + + if (!PyArg_ParseTuple(args, "O:test_thread_state", &fn)) + return NULL; + + /* Ensure Python is set up for threading */ + PyEval_InitThreads(); + thread_done = PyThread_allocate_lock(); + if (thread_done == NULL) + return PyErr_NoMemory(); + PyThread_acquire_lock(thread_done, 1); + + /* Start a new thread with our callback. */ + PyThread_start_new_thread(_make_call_from_thread, fn); + /* Make the callback with the thread lock held by this thread */ + _make_call(fn); + /* Do it all again, but this time with the thread-lock released */ + Py_BEGIN_ALLOW_THREADS + _make_call(fn); + PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */ + Py_END_ALLOW_THREADS + + /* And once more with and without a thread + XXX - should use a lock and work out exactly what we are trying + to test <wink> + */ + Py_BEGIN_ALLOW_THREADS + PyThread_start_new_thread(_make_call_from_thread, fn); + _make_call(fn); + PyThread_acquire_lock(thread_done, 1); /* wait for thread to finish */ + Py_END_ALLOW_THREADS + + /* Release lock we acquired above. This is required on HP-UX. */ + PyThread_release_lock(thread_done); + + PyThread_free_lock(thread_done); + Py_RETURN_NONE; +} +#endif + +/* Some tests of PyString_FromFormat(). This needs more tests. */ +static PyObject * +test_string_from_format(PyObject *self, PyObject *args) +{ + PyObject *result; + char *msg; + +#define CHECK_1_FORMAT(FORMAT, TYPE) \ + result = PyString_FromFormat(FORMAT, (TYPE)1); \ + if (result == NULL) \ + return NULL; \ + if (strcmp(PyString_AsString(result), "1")) { \ + msg = FORMAT " failed at 1"; \ + goto Fail; \ + } \ + Py_DECREF(result) + + CHECK_1_FORMAT("%d", int); + CHECK_1_FORMAT("%ld", long); + /* The z width modifier was added in Python 2.5. */ + CHECK_1_FORMAT("%zd", Py_ssize_t); + + /* The u type code was added in Python 2.5. */ + CHECK_1_FORMAT("%u", unsigned int); + CHECK_1_FORMAT("%lu", unsigned long); + CHECK_1_FORMAT("%zu", size_t); + + Py_RETURN_NONE; + + Fail: + Py_XDECREF(result); + return raiseTestError("test_string_from_format", msg); + +#undef CHECK_1_FORMAT +} + +/* This is here to provide a docstring for test_descr. */ +static PyObject * +test_with_docstring(PyObject *self) +{ + Py_RETURN_NONE; +} + +static PyMethodDef TestMethods[] = { + {"raise_exception", raise_exception, METH_VARARGS}, + {"test_config", (PyCFunction)test_config, METH_NOARGS}, + {"test_list_api", (PyCFunction)test_list_api, METH_NOARGS}, + {"test_dict_iteration", (PyCFunction)test_dict_iteration,METH_NOARGS}, + {"test_long_api", (PyCFunction)test_long_api, METH_NOARGS}, + {"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS}, + {"test_k_code", (PyCFunction)test_k_code, METH_NOARGS}, + {"test_null_strings", (PyCFunction)test_null_strings, METH_NOARGS}, + {"test_string_from_format", (PyCFunction)test_string_from_format, METH_NOARGS}, + {"test_with_docstring", (PyCFunction)test_with_docstring, METH_NOARGS, + PyDoc_STR("This is a pretty normal docstring.")}, + + {"getargs_tuple", getargs_tuple, METH_VARARGS}, + {"getargs_b", getargs_b, METH_VARARGS}, + {"getargs_B", getargs_B, METH_VARARGS}, + {"getargs_H", getargs_H, METH_VARARGS}, + {"getargs_I", getargs_I, METH_VARARGS}, + {"getargs_k", getargs_k, METH_VARARGS}, + {"getargs_i", getargs_i, METH_VARARGS}, + {"getargs_l", getargs_l, METH_VARARGS}, + {"getargs_n", getargs_n, METH_VARARGS}, +#ifdef HAVE_LONG_LONG + {"getargs_L", getargs_L, METH_VARARGS}, + {"getargs_K", getargs_K, METH_VARARGS}, + {"test_longlong_api", test_longlong_api, METH_NOARGS}, + {"test_L_code", (PyCFunction)test_L_code, METH_NOARGS}, + {"codec_incrementalencoder", + (PyCFunction)codec_incrementalencoder, METH_VARARGS}, + {"codec_incrementaldecoder", + (PyCFunction)codec_incrementaldecoder, METH_VARARGS}, +#endif +#ifdef Py_USING_UNICODE + {"test_u_code", (PyCFunction)test_u_code, METH_NOARGS}, +#endif +#ifdef WITH_THREAD + {"_test_thread_state", test_thread_state, METH_VARARGS}, +#endif + {NULL, NULL} /* sentinel */ +}; + +#define AddSym(d, n, f, v) {PyObject *o = f(v); PyDict_SetItemString(d, n, o); Py_DECREF(o);} + +typedef struct { + char byte_member; + unsigned char ubyte_member; + short short_member; + unsigned short ushort_member; + int int_member; + unsigned int uint_member; + long long_member; + unsigned long ulong_member; + float float_member; + double double_member; +} all_structmembers; + +typedef struct { + PyObject_HEAD + all_structmembers structmembers; +} test_structmembers; + +static struct PyMemberDef test_members[] = { + {"T_BYTE", T_BYTE, offsetof(test_structmembers, structmembers.byte_member), 0, NULL}, + {"T_UBYTE", T_UBYTE, offsetof(test_structmembers, structmembers.ubyte_member), 0, NULL}, + {"T_SHORT", T_SHORT, offsetof(test_structmembers, structmembers.short_member), 0, NULL}, + {"T_USHORT", T_USHORT, offsetof(test_structmembers, structmembers.ushort_member), 0, NULL}, + {"T_INT", T_INT, offsetof(test_structmembers, structmembers.int_member), 0, NULL}, + {"T_UINT", T_UINT, offsetof(test_structmembers, structmembers.uint_member), 0, NULL}, + {"T_LONG", T_LONG, offsetof(test_structmembers, structmembers.long_member), 0, NULL}, + {"T_ULONG", T_ULONG, offsetof(test_structmembers, structmembers.ulong_member), 0, NULL}, + {"T_FLOAT", T_FLOAT, offsetof(test_structmembers, structmembers.float_member), 0, NULL}, + {"T_DOUBLE", T_DOUBLE, offsetof(test_structmembers, structmembers.double_member), 0, NULL}, + {NULL} +}; + + +static PyObject *test_structmembers_new(PyTypeObject *type, PyObject *args, PyObject *kwargs){ + static char *keywords[]={"T_BYTE", "T_UBYTE", "T_SHORT", "T_USHORT", "T_INT", "T_UINT", + "T_LONG", "T_ULONG", "T_FLOAT", "T_DOUBLE", NULL}; + test_structmembers *ob=PyObject_New(test_structmembers, type); + if (ob==NULL) + return NULL; + memset(&ob->structmembers, 0, sizeof(all_structmembers)); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|bBhHiIlkfd", keywords, + &ob->structmembers.byte_member, &ob->structmembers.ubyte_member, + &ob->structmembers.short_member, &ob->structmembers.ushort_member, + &ob->structmembers.int_member, &ob->structmembers.uint_member, + &ob->structmembers.long_member, &ob->structmembers.ulong_member, + &ob->structmembers.float_member, &ob->structmembers.double_member)){ + Py_DECREF(ob); + return NULL; + } + return (PyObject *)ob; +} + +static void test_structmembers_free(PyObject *ob){ + PyObject_FREE(ob); +} + +static PyTypeObject test_structmembersType = { + PyObject_HEAD_INIT(NULL) + 0, + "test_structmembersType", + sizeof(test_structmembers), /* tp_basicsize */ + 0, /* tp_itemsize */ + test_structmembers_free, /* destructor tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, + PyObject_GenericSetAttr, + 0, /* tp_as_buffer */ + 0, /* tp_flags */ + "Type containing all structmember types", + 0, /* traverseproc tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + test_members, /* tp_members */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + test_structmembers_new, /* tp_new */ +}; + + +PyMODINIT_FUNC +init_testcapi(void) +{ + PyObject *m; + + m = Py_InitModule("_testcapi", TestMethods); + if (m == NULL) + return; + + test_structmembersType.ob_type=&PyType_Type; + Py_INCREF(&test_structmembersType); + PyModule_AddObject(m, "test_structmembersType", (PyObject *)&test_structmembersType); + + PyModule_AddObject(m, "CHAR_MAX", PyInt_FromLong(CHAR_MAX)); + PyModule_AddObject(m, "CHAR_MIN", PyInt_FromLong(CHAR_MIN)); + PyModule_AddObject(m, "UCHAR_MAX", PyInt_FromLong(UCHAR_MAX)); + PyModule_AddObject(m, "SHRT_MAX", PyInt_FromLong(SHRT_MAX)); + PyModule_AddObject(m, "SHRT_MIN", PyInt_FromLong(SHRT_MIN)); + PyModule_AddObject(m, "USHRT_MAX", PyInt_FromLong(USHRT_MAX)); + PyModule_AddObject(m, "INT_MAX", PyLong_FromLong(INT_MAX)); + PyModule_AddObject(m, "INT_MIN", PyLong_FromLong(INT_MIN)); + PyModule_AddObject(m, "UINT_MAX", PyLong_FromUnsignedLong(UINT_MAX)); + PyModule_AddObject(m, "LONG_MAX", PyInt_FromLong(LONG_MAX)); + PyModule_AddObject(m, "LONG_MIN", PyInt_FromLong(LONG_MIN)); + PyModule_AddObject(m, "ULONG_MAX", PyLong_FromUnsignedLong(ULONG_MAX)); + PyModule_AddObject(m, "FLT_MAX", PyFloat_FromDouble(FLT_MAX)); + PyModule_AddObject(m, "FLT_MIN", PyFloat_FromDouble(FLT_MIN)); + PyModule_AddObject(m, "DBL_MAX", PyFloat_FromDouble(DBL_MAX)); + PyModule_AddObject(m, "DBL_MIN", PyFloat_FromDouble(DBL_MIN)); + PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyInt_FromSsize_t(PY_SSIZE_T_MAX)); + PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyInt_FromSsize_t(PY_SSIZE_T_MIN)); + + TestError = PyErr_NewException("_testcapi.error", NULL, NULL); + Py_INCREF(TestError); + PyModule_AddObject(m, "error", TestError); +} diff --git a/sys/src/cmd/python/Modules/_tkinter.c b/sys/src/cmd/python/Modules/_tkinter.c new file mode 100644 index 000000000..0b853b5b4 --- /dev/null +++ b/sys/src/cmd/python/Modules/_tkinter.c @@ -0,0 +1,3165 @@ +/*********************************************************** +Copyright (C) 1994 Steen Lumholt. + + All Rights Reserved + +******************************************************************/ + +/* _tkinter.c -- Interface to libtk.a and libtcl.a. */ + +/* TCL/TK VERSION INFO: + + Only Tcl/Tk 8.2 and later are supported. Older versions are not + supported. (Use Python 2.2 if you cannot upgrade your Tcl/Tk + libraries.) +*/ + +/* XXX Further speed-up ideas, involving Tcl 8.0 features: + + - Register a new Tcl type, "Python callable", which can be called more + efficiently and passed to Tcl_EvalObj() directly (if this is possible). + +*/ + + +#include "Python.h" +#include <ctype.h> + +#ifdef WITH_THREAD +#include "pythread.h" +#endif + +#ifdef MS_WINDOWS +#include <windows.h> +#endif + +/* Allow using this code in Python 2.[12] */ +#ifndef PyDoc_STRVAR +#define PyDoc_STRVAR(name,str) static char name[] = str +#endif + +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC void +#endif + +#ifndef PyBool_Check +#define PyBool_Check(o) 0 +#define PyBool_FromLong PyInt_FromLong +#endif + +/* Starting with Tcl 8.4, many APIs offer const-correctness. Unfortunately, + making _tkinter correct for this API means to break earlier + versions. USE_COMPAT_CONST allows to make _tkinter work with both 8.4 and + earlier versions. Once Tcl releases before 8.4 don't need to be supported + anymore, this should go. */ +#define USE_COMPAT_CONST + +/* If Tcl is compiled for threads, we must also define TCL_THREAD. We define + it always; if Tcl is not threaded, the thread functions in + Tcl are empty. */ +#define TCL_THREADS + +#ifdef TK_FRAMEWORK +#include <Tcl/tcl.h> +#include <Tk/tk.h> +#else +#include <tcl.h> +#include <tk.h> +#endif + +/* For Tcl 8.2 and 8.3, CONST* is not defined (except on Cygwin). */ +#ifndef CONST84_RETURN +#define CONST84_RETURN +#undef CONST +#define CONST +#endif + +#define TKMAJORMINOR (TK_MAJOR_VERSION*1000 + TK_MINOR_VERSION) + +#if TKMAJORMINOR < 8002 +#error "Tk older than 8.2 not supported" +#endif + +/* Unicode conversion assumes that Tcl_UniChar is two bytes. + We cannot test this directly, so we test UTF-8 size instead, + expecting that TCL_UTF_MAX is changed if Tcl ever supports + either UTF-16 or UCS-4. + Redhat 8 sets TCL_UTF_MAX to 6, and uses wchar_t for + Tcl_Unichar. This is also ok as long as Python uses UCS-4, + as well. +*/ +#if TCL_UTF_MAX != 3 && !(defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==6) +#error "unsupported Tcl configuration" +#endif + +#if !(defined(MS_WINDOWS) || defined(__CYGWIN__)) +#define HAVE_CREATEFILEHANDLER +#endif + +#ifdef HAVE_CREATEFILEHANDLER + +/* This bit is to ensure that TCL_UNIX_FD is defined and doesn't interfere + with the proper calculation of FHANDLETYPE == TCL_UNIX_FD below. */ +#ifndef TCL_UNIX_FD +# ifdef TCL_WIN_SOCKET +# define TCL_UNIX_FD (! TCL_WIN_SOCKET) +# else +# define TCL_UNIX_FD 1 +# endif +#endif + +/* Tcl_CreateFileHandler() changed several times; these macros deal with the + messiness. In Tcl 8.0 and later, it is not available on Windows (and on + Unix, only because Jack added it back); when available on Windows, it only + applies to sockets. */ + +#ifdef MS_WINDOWS +#define FHANDLETYPE TCL_WIN_SOCKET +#else +#define FHANDLETYPE TCL_UNIX_FD +#endif + +/* If Tcl can wait for a Unix file descriptor, define the EventHook() routine + which uses this to handle Tcl events while the user is typing commands. */ + +#if FHANDLETYPE == TCL_UNIX_FD +#define WAIT_FOR_STDIN +#endif + +#endif /* HAVE_CREATEFILEHANDLER */ + +#ifdef MS_WINDOWS +#include <conio.h> +#define WAIT_FOR_STDIN +#endif + +#ifdef WITH_THREAD + +/* The threading situation is complicated. Tcl is not thread-safe, except + when configured with --enable-threads. + So we need to use a lock around all uses of Tcl. Previously, the Python + interpreter lock was used for this. However, this causes problems when + other Python threads need to run while Tcl is blocked waiting for events. + + To solve this problem, a separate lock for Tcl is introduced. Holding it + is incompatible with holding Python's interpreter lock. The following four + macros manipulate both locks together. + + ENTER_TCL and LEAVE_TCL are brackets, just like Py_BEGIN_ALLOW_THREADS and + Py_END_ALLOW_THREADS. They should be used whenever a call into Tcl is made + that could call an event handler, or otherwise affect the state of a Tcl + interpreter. These assume that the surrounding code has the Python + interpreter lock; inside the brackets, the Python interpreter lock has been + released and the lock for Tcl has been acquired. + + Sometimes, it is necessary to have both the Python lock and the Tcl lock. + (For example, when transferring data from the Tcl interpreter result to a + Python string object.) This can be done by using different macros to close + the ENTER_TCL block: ENTER_OVERLAP reacquires the Python lock (and restores + the thread state) but doesn't release the Tcl lock; LEAVE_OVERLAP_TCL + releases the Tcl lock. + + By contrast, ENTER_PYTHON and LEAVE_PYTHON are used in Tcl event + handlers when the handler needs to use Python. Such event handlers are + entered while the lock for Tcl is held; the event handler presumably needs + to use Python. ENTER_PYTHON releases the lock for Tcl and acquires + the Python interpreter lock, restoring the appropriate thread state, and + LEAVE_PYTHON releases the Python interpreter lock and re-acquires the lock + for Tcl. It is okay for ENTER_TCL/LEAVE_TCL pairs to be contained inside + the code between ENTER_PYTHON and LEAVE_PYTHON. + + These locks expand to several statements and brackets; they should not be + used in branches of if statements and the like. + + If Tcl is threaded, this approach won't work anymore. The Tcl interpreter is + only valid in the thread that created it, and all Tk activity must happen in this + thread, also. That means that the mainloop must be invoked in the thread that + created the interpreter. Invoking commands from other threads is possible; + _tkinter will queue an event for the interpreter thread, which will then + execute the command and pass back the result. If the main thread is not in the + mainloop, and invoking commands causes an exception; if the main loop is running + but not processing events, the command invocation will block. + + In addition, for a threaded Tcl, a single global tcl_tstate won't be sufficient + anymore, since multiple Tcl interpreters may simultaneously dispatch in different + threads. So we use the Tcl TLS API. + +*/ + +static PyThread_type_lock tcl_lock = 0; + +#ifdef TCL_THREADS +static Tcl_ThreadDataKey state_key; +typedef PyThreadState *ThreadSpecificData; +#define tcl_tstate (*(PyThreadState**)Tcl_GetThreadData(&state_key, sizeof(PyThreadState*))) +#else +static PyThreadState *tcl_tstate = NULL; +#endif + +#define ENTER_TCL \ + { PyThreadState *tstate = PyThreadState_Get(); Py_BEGIN_ALLOW_THREADS \ + if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; + +#define LEAVE_TCL \ + tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); Py_END_ALLOW_THREADS} + +#define ENTER_OVERLAP \ + Py_END_ALLOW_THREADS + +#define LEAVE_OVERLAP_TCL \ + tcl_tstate = NULL; if(tcl_lock)PyThread_release_lock(tcl_lock); } + +#define ENTER_PYTHON \ + { PyThreadState *tstate = tcl_tstate; tcl_tstate = NULL; \ + if(tcl_lock)PyThread_release_lock(tcl_lock); PyEval_RestoreThread((tstate)); } + +#define LEAVE_PYTHON \ + { PyThreadState *tstate = PyEval_SaveThread(); \ + if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); tcl_tstate = tstate; } + +#define CHECK_TCL_APPARTMENT \ + if (((TkappObject *)self)->threaded && \ + ((TkappObject *)self)->thread_id != Tcl_GetCurrentThread()) { \ + PyErr_SetString(PyExc_RuntimeError, "Calling Tcl from different appartment"); \ + return 0; \ + } + +#else + +#define ENTER_TCL +#define LEAVE_TCL +#define ENTER_OVERLAP +#define LEAVE_OVERLAP_TCL +#define ENTER_PYTHON +#define LEAVE_PYTHON +#define CHECK_TCL_APPARTMENT + +#endif + +#ifndef FREECAST +#define FREECAST (char *) +#endif + +/**** Tkapp Object Declaration ****/ + +static PyTypeObject Tkapp_Type; + +typedef struct { + PyObject_HEAD + Tcl_Interp *interp; + int wantobjects; + int threaded; /* True if tcl_platform[threaded] */ + Tcl_ThreadId thread_id; + int dispatching; + /* We cannot include tclInt.h, as this is internal. + So we cache interesting types here. */ + Tcl_ObjType *BooleanType; + Tcl_ObjType *ByteArrayType; + Tcl_ObjType *DoubleType; + Tcl_ObjType *IntType; + Tcl_ObjType *ListType; + Tcl_ObjType *ProcBodyType; + Tcl_ObjType *StringType; +} TkappObject; + +#define Tkapp_Check(v) ((v)->ob_type == &Tkapp_Type) +#define Tkapp_Interp(v) (((TkappObject *) (v))->interp) +#define Tkapp_Result(v) Tcl_GetStringResult(Tkapp_Interp(v)) + +#define DEBUG_REFCNT(v) (printf("DEBUG: id=%p, refcnt=%i\n", \ +(void *) v, ((PyObject *) v)->ob_refcnt)) + + + +/**** Error Handling ****/ + +static PyObject *Tkinter_TclError; +static int quitMainLoop = 0; +static int errorInCmd = 0; +static PyObject *excInCmd; +static PyObject *valInCmd; +static PyObject *trbInCmd; + + + +static PyObject * +Tkinter_Error(PyObject *v) +{ + PyErr_SetString(Tkinter_TclError, Tkapp_Result(v)); + return NULL; +} + + + +/**** Utils ****/ + +static int Tkinter_busywaitinterval = 20; + +#ifdef WITH_THREAD +#ifndef MS_WINDOWS + +/* Millisecond sleep() for Unix platforms. */ + +static void +Sleep(int milli) +{ + /* XXX Too bad if you don't have select(). */ + struct timeval t; + t.tv_sec = milli/1000; + t.tv_usec = (milli%1000) * 1000; + select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); +} +#endif /* MS_WINDOWS */ + +/* Wait up to 1s for the mainloop to come up. */ + +static int +WaitForMainloop(TkappObject* self) +{ + int i; + for (i = 0; i < 10; i++) { + if (self->dispatching) + return 1; + Py_BEGIN_ALLOW_THREADS + Sleep(100); + Py_END_ALLOW_THREADS + } + if (self->dispatching) + return 1; + PyErr_SetString(PyExc_RuntimeError, "main thread is not in main loop"); + return 0; +} +#endif /* WITH_THREAD */ + + +static char * +AsString(PyObject *value, PyObject *tmp) +{ + if (PyString_Check(value)) + return PyString_AsString(value); +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(value)) { + PyObject *v = PyUnicode_AsUTF8String(value); + if (v == NULL) + return NULL; + if (PyList_Append(tmp, v) != 0) { + Py_DECREF(v); + return NULL; + } + Py_DECREF(v); + return PyString_AsString(v); + } +#endif + else { + PyObject *v = PyObject_Str(value); + if (v == NULL) + return NULL; + if (PyList_Append(tmp, v) != 0) { + Py_DECREF(v); + return NULL; + } + Py_DECREF(v); + return PyString_AsString(v); + } +} + + + +#define ARGSZ 64 + +static char * +Merge(PyObject *args) +{ + PyObject *tmp = NULL; + char *argvStore[ARGSZ]; + char **argv = NULL; + int fvStore[ARGSZ]; + int *fv = NULL; + int argc = 0, fvc = 0, i; + char *res = NULL; + + if (!(tmp = PyList_New(0))) + return NULL; + + argv = argvStore; + fv = fvStore; + + if (args == NULL) + argc = 0; + + else if (!PyTuple_Check(args)) { + argc = 1; + fv[0] = 0; + if (!(argv[0] = AsString(args, tmp))) + goto finally; + } + else { + argc = PyTuple_Size(args); + + if (argc > ARGSZ) { + argv = (char **)ckalloc(argc * sizeof(char *)); + fv = (int *)ckalloc(argc * sizeof(int)); + if (argv == NULL || fv == NULL) { + PyErr_NoMemory(); + goto finally; + } + } + + for (i = 0; i < argc; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (PyTuple_Check(v)) { + fv[i] = 1; + if (!(argv[i] = Merge(v))) + goto finally; + fvc++; + } + else if (v == Py_None) { + argc = i; + break; + } + else { + fv[i] = 0; + if (!(argv[i] = AsString(v, tmp))) + goto finally; + fvc++; + } + } + } + res = Tcl_Merge(argc, argv); + if (res == NULL) + PyErr_SetString(Tkinter_TclError, "merge failed"); + + finally: + for (i = 0; i < fvc; i++) + if (fv[i]) { + ckfree(argv[i]); + } + if (argv != argvStore) + ckfree(FREECAST argv); + if (fv != fvStore) + ckfree(FREECAST fv); + + Py_DECREF(tmp); + return res; +} + + + +static PyObject * +Split(char *list) +{ + int argc; + char **argv; + PyObject *v; + + if (list == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + + if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { + /* Not a list. + * Could be a quoted string containing funnies, e.g. {"}. + * Return the string itself. + */ + return PyString_FromString(list); + } + + if (argc == 0) + v = PyString_FromString(""); + else if (argc == 1) + v = PyString_FromString(argv[0]); + else if ((v = PyTuple_New(argc)) != NULL) { + int i; + PyObject *w; + + for (i = 0; i < argc; i++) { + if ((w = Split(argv[i])) == NULL) { + Py_DECREF(v); + v = NULL; + break; + } + PyTuple_SetItem(v, i, w); + } + } + Tcl_Free(FREECAST argv); + return v; +} + +/* In some cases, Tcl will still return strings that are supposed to be + lists. SplitObj walks through a nested tuple, finding string objects that + need to be split. */ + +PyObject * +SplitObj(PyObject *arg) +{ + if (PyTuple_Check(arg)) { + int i, size; + PyObject *elem, *newelem, *result; + + size = PyTuple_Size(arg); + result = NULL; + /* Recursively invoke SplitObj for all tuple items. + If this does not return a new object, no action is + needed. */ + for(i = 0; i < size; i++) { + elem = PyTuple_GetItem(arg, i); + newelem = SplitObj(elem); + if (!newelem) { + Py_XDECREF(result); + return NULL; + } + if (!result) { + int k; + if (newelem == elem) { + Py_DECREF(newelem); + continue; + } + result = PyTuple_New(size); + if (!result) + return NULL; + for(k = 0; k < i; k++) { + elem = PyTuple_GetItem(arg, k); + Py_INCREF(elem); + PyTuple_SetItem(result, k, elem); + } + } + PyTuple_SetItem(result, i, newelem); + } + if (result) + return result; + /* Fall through, returning arg. */ + } + else if (PyString_Check(arg)) { + int argc; + char **argv; + char *list = PyString_AsString(arg); + + if (Tcl_SplitList((Tcl_Interp *)NULL, list, &argc, &argv) != TCL_OK) { + Py_INCREF(arg); + return arg; + } + Tcl_Free(FREECAST argv); + if (argc > 1) + return Split(PyString_AsString(arg)); + /* Fall through, returning arg. */ + } + Py_INCREF(arg); + return arg; +} + + +/**** Tkapp Object ****/ + +#ifndef WITH_APPINIT +int +Tcl_AppInit(Tcl_Interp *interp) +{ + Tk_Window main; + const char * _tkinter_skip_tk_init; + + if (Tcl_Init(interp) == TCL_ERROR) { + PySys_WriteStderr("Tcl_Init error: %s\n", Tcl_GetStringResult(interp)); + return TCL_ERROR; + } + _tkinter_skip_tk_init = Tcl_GetVar(interp, "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY); + if (_tkinter_skip_tk_init == NULL || strcmp(_tkinter_skip_tk_init, "1") != 0) { + main = Tk_MainWindow(interp); + if (Tk_Init(interp) == TCL_ERROR) { + PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp)); + return TCL_ERROR; + } + } + return TCL_OK; +} +#endif /* !WITH_APPINIT */ + + + + +/* Initialize the Tk application; see the `main' function in + * `tkMain.c'. + */ + +static void EnableEventHook(void); /* Forward */ +static void DisableEventHook(void); /* Forward */ + +static TkappObject * +Tkapp_New(char *screenName, char *baseName, char *className, + int interactive, int wantobjects, int wantTk, int sync, char *use) +{ + TkappObject *v; + char *argv0; + + v = PyObject_New(TkappObject, &Tkapp_Type); + if (v == NULL) + return NULL; + + v->interp = Tcl_CreateInterp(); + v->wantobjects = wantobjects; + v->threaded = Tcl_GetVar2Ex(v->interp, "tcl_platform", "threaded", + TCL_GLOBAL_ONLY) != NULL; + v->thread_id = Tcl_GetCurrentThread(); + v->dispatching = 0; + +#ifndef TCL_THREADS + if (v->threaded) { + PyErr_SetString(PyExc_RuntimeError, "Tcl is threaded but _tkinter is not"); + Py_DECREF(v); + return 0; + } +#endif +#ifdef WITH_THREAD + if (v->threaded && tcl_lock) { + /* If Tcl is threaded, we don't need the lock. */ + PyThread_free_lock(tcl_lock); + tcl_lock = NULL; + } +#endif + + v->BooleanType = Tcl_GetObjType("boolean"); + v->ByteArrayType = Tcl_GetObjType("bytearray"); + v->DoubleType = Tcl_GetObjType("double"); + v->IntType = Tcl_GetObjType("int"); + v->ListType = Tcl_GetObjType("list"); + v->ProcBodyType = Tcl_GetObjType("procbody"); + v->StringType = Tcl_GetObjType("string"); + + /* Delete the 'exit' command, which can screw things up */ + Tcl_DeleteCommand(v->interp, "exit"); + + if (screenName != NULL) + Tcl_SetVar2(v->interp, "env", "DISPLAY", + screenName, TCL_GLOBAL_ONLY); + + if (interactive) + Tcl_SetVar(v->interp, "tcl_interactive", "1", TCL_GLOBAL_ONLY); + else + Tcl_SetVar(v->interp, "tcl_interactive", "0", TCL_GLOBAL_ONLY); + + /* This is used to get the application class for Tk 4.1 and up */ + argv0 = (char*)ckalloc(strlen(className) + 1); + if (!argv0) { + PyErr_NoMemory(); + Py_DECREF(v); + return NULL; + } + + strcpy(argv0, className); + if (isupper(Py_CHARMASK(argv0[0]))) + argv0[0] = tolower(Py_CHARMASK(argv0[0])); + Tcl_SetVar(v->interp, "argv0", argv0, TCL_GLOBAL_ONLY); + ckfree(argv0); + + if (! wantTk) { + Tcl_SetVar(v->interp, "_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY); + } + + /* some initial arguments need to be in argv */ + if (sync || use) { + char *args; + int len = 0; + + if (sync) + len += sizeof "-sync"; + if (use) + len += strlen(use) + sizeof "-use "; + + args = (char*)ckalloc(len); + if (!args) { + PyErr_NoMemory(); + Py_DECREF(v); + return NULL; + } + + args[0] = '\0'; + if (sync) + strcat(args, "-sync"); + if (use) { + if (sync) + strcat(args, " "); + strcat(args, "-use "); + strcat(args, use); + } + + Tcl_SetVar(v->interp, "argv", args, TCL_GLOBAL_ONLY); + ckfree(args); + } + + if (Tcl_AppInit(v->interp) != TCL_OK) { + PyObject *result = Tkinter_Error((PyObject *)v); + Py_DECREF((PyObject *)v); + return (TkappObject *)result; + } + + EnableEventHook(); + + return v; +} + + +static void +Tkapp_ThreadSend(TkappObject *self, Tcl_Event *ev, + Tcl_Condition *cond, Tcl_Mutex *mutex) +{ + Py_BEGIN_ALLOW_THREADS; + Tcl_MutexLock(mutex); + Tcl_ThreadQueueEvent(self->thread_id, ev, TCL_QUEUE_TAIL); + Tcl_ThreadAlert(self->thread_id); + Tcl_ConditionWait(cond, mutex, NULL); + Tcl_MutexUnlock(mutex); + Py_END_ALLOW_THREADS +} + + +/** Tcl Eval **/ + +typedef struct { + PyObject_HEAD + Tcl_Obj *value; + PyObject *string; /* This cannot cause cycles. */ +} PyTclObject; + +staticforward PyTypeObject PyTclObject_Type; +#define PyTclObject_Check(v) ((v)->ob_type == &PyTclObject_Type) + +static PyObject * +newPyTclObject(Tcl_Obj *arg) +{ + PyTclObject *self; + self = PyObject_New(PyTclObject, &PyTclObject_Type); + if (self == NULL) + return NULL; + Tcl_IncrRefCount(arg); + self->value = arg; + self->string = NULL; + return (PyObject*)self; +} + +static void +PyTclObject_dealloc(PyTclObject *self) +{ + Tcl_DecrRefCount(self->value); + Py_XDECREF(self->string); + PyObject_Del(self); +} + +static PyObject * +PyTclObject_str(PyTclObject *self) +{ + if (self->string && PyString_Check(self->string)) { + Py_INCREF(self->string); + return self->string; + } + /* XXX Could cache value if it is an ASCII string. */ + return PyString_FromString(Tcl_GetString(self->value)); +} + +static char* +PyTclObject_TclString(PyObject *self) +{ + return Tcl_GetString(((PyTclObject*)self)->value); +} + +/* Like _str, but create Unicode if necessary. */ +PyDoc_STRVAR(PyTclObject_string__doc__, +"the string representation of this object, either as string or Unicode"); + +static PyObject * +PyTclObject_string(PyTclObject *self, void *ignored) +{ + char *s; + int i, len; + if (!self->string) { + s = Tcl_GetStringFromObj(self->value, &len); + for (i = 0; i < len; i++) + if (s[i] & 0x80) + break; +#ifdef Py_USING_UNICODE + if (i == len) + /* It is an ASCII string. */ + self->string = PyString_FromStringAndSize(s, len); + else { + self->string = PyUnicode_DecodeUTF8(s, len, "strict"); + if (!self->string) { + PyErr_Clear(); + self->string = PyString_FromStringAndSize(s, len); + } + } +#else + self->string = PyString_FromStringAndSize(s, len); +#endif + if (!self->string) + return NULL; + } + Py_INCREF(self->string); + return self->string; +} + +#ifdef Py_USING_UNICODE +PyDoc_STRVAR(PyTclObject_unicode__doc__, "convert argument to unicode"); + +static PyObject * +PyTclObject_unicode(PyTclObject *self, void *ignored) +{ + char *s; + int len; + if (self->string && PyUnicode_Check(self->string)) { + Py_INCREF(self->string); + return self->string; + } + /* XXX Could chache result if it is non-ASCII. */ + s = Tcl_GetStringFromObj(self->value, &len); + return PyUnicode_DecodeUTF8(s, len, "strict"); +} +#endif + +static PyObject * +PyTclObject_repr(PyTclObject *self) +{ + char buf[50]; + PyOS_snprintf(buf, 50, "<%s object at %p>", + self->value->typePtr->name, self->value); + return PyString_FromString(buf); +} + +static int +PyTclObject_cmp(PyTclObject *self, PyTclObject *other) +{ + int res; + res = strcmp(Tcl_GetString(self->value), + Tcl_GetString(other->value)); + if (res < 0) return -1; + if (res > 0) return 1; + return 0; +} + +PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type"); + +static PyObject* +get_typename(PyTclObject* obj, void* ignored) +{ + return PyString_FromString(obj->value->typePtr->name); +} + + +static PyGetSetDef PyTclObject_getsetlist[] = { + {"typename", (getter)get_typename, NULL, get_typename__doc__}, + {"string", (getter)PyTclObject_string, NULL, + PyTclObject_string__doc__}, + {0}, +}; + +static PyMethodDef PyTclObject_methods[] = { +#ifdef Py_USING_UNICODE + {"__unicode__", (PyCFunction)PyTclObject_unicode, METH_NOARGS, + PyTclObject_unicode__doc__}, +#endif + {0} +}; + +statichere PyTypeObject PyTclObject_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_tkinter.Tcl_Obj", /*tp_name*/ + sizeof(PyTclObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyTclObject_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + (cmpfunc)PyTclObject_cmp, /*tp_compare*/ + (reprfunc)PyTclObject_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + (reprfunc)PyTclObject_str, /*tp_str*/ + PyObject_GenericGetAttr,/*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + PyTclObject_methods, /*tp_methods*/ + 0, /*tp_members*/ + PyTclObject_getsetlist, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +static Tcl_Obj* +AsObj(PyObject *value) +{ + Tcl_Obj *result; + + if (PyString_Check(value)) + return Tcl_NewStringObj(PyString_AS_STRING(value), + PyString_GET_SIZE(value)); + else if (PyBool_Check(value)) + return Tcl_NewBooleanObj(PyObject_IsTrue(value)); + else if (PyInt_Check(value)) + return Tcl_NewLongObj(PyInt_AS_LONG(value)); + else if (PyFloat_Check(value)) + return Tcl_NewDoubleObj(PyFloat_AS_DOUBLE(value)); + else if (PyTuple_Check(value)) { + Tcl_Obj **argv = (Tcl_Obj**) + ckalloc(PyTuple_Size(value)*sizeof(Tcl_Obj*)); + int i; + if(!argv) + return 0; + for(i=0;i<PyTuple_Size(value);i++) + argv[i] = AsObj(PyTuple_GetItem(value,i)); + result = Tcl_NewListObj(PyTuple_Size(value), argv); + ckfree(FREECAST argv); + return result; + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(value)) { + Py_UNICODE *inbuf = PyUnicode_AS_UNICODE(value); + Py_ssize_t size = PyUnicode_GET_SIZE(value); + /* This #ifdef assumes that Tcl uses UCS-2. + See TCL_UTF_MAX test above. */ +#if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX == 3 + Tcl_UniChar *outbuf; + Py_ssize_t i; + assert(size < size * sizeof(Tcl_UniChar)); + outbuf = (Tcl_UniChar*)ckalloc(size * sizeof(Tcl_UniChar)); + if (!outbuf) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < size; i++) { + if (inbuf[i] >= 0x10000) { + /* Tcl doesn't do UTF-16, yet. */ + PyErr_SetString(PyExc_ValueError, + "unsupported character"); + ckfree(FREECAST outbuf); + return NULL; + } + outbuf[i] = inbuf[i]; + } + result = Tcl_NewUnicodeObj(outbuf, size); + ckfree(FREECAST outbuf); + return result; +#else + return Tcl_NewUnicodeObj(inbuf, size); +#endif + + } +#endif + else if(PyTclObject_Check(value)) { + Tcl_Obj *v = ((PyTclObject*)value)->value; + Tcl_IncrRefCount(v); + return v; + } + else { + PyObject *v = PyObject_Str(value); + if (!v) + return 0; + result = AsObj(v); + Py_DECREF(v); + return result; + } +} + +static PyObject* +FromObj(PyObject* tkapp, Tcl_Obj *value) +{ + PyObject *result = NULL; + TkappObject *app = (TkappObject*)tkapp; + + if (value->typePtr == NULL) { + /* If the result contains any bytes with the top bit set, + it's UTF-8 and we should decode it to Unicode */ +#ifdef Py_USING_UNICODE + int i; + char *s = value->bytes; + int len = value->length; + for (i = 0; i < len; i++) { + if (value->bytes[i] & 0x80) + break; + } + + if (i == value->length) + result = PyString_FromStringAndSize(s, len); + else { + /* Convert UTF-8 to Unicode string */ + result = PyUnicode_DecodeUTF8(s, len, "strict"); + if (result == NULL) { + PyErr_Clear(); + result = PyString_FromStringAndSize(s, len); + } + } +#else + result = PyString_FromStringAndSize(value->bytes, value->length); +#endif + return result; + } + + if (value->typePtr == app->BooleanType) { + result = value->internalRep.longValue ? Py_True : Py_False; + Py_INCREF(result); + return result; + } + + if (value->typePtr == app->ByteArrayType) { + int size; + char *data = (char*)Tcl_GetByteArrayFromObj(value, &size); + return PyString_FromStringAndSize(data, size); + } + + if (value->typePtr == app->DoubleType) { + return PyFloat_FromDouble(value->internalRep.doubleValue); + } + + if (value->typePtr == app->IntType) { + return PyInt_FromLong(value->internalRep.longValue); + } + + if (value->typePtr == app->ListType) { + int size; + int i, status; + PyObject *elem; + Tcl_Obj *tcl_elem; + + status = Tcl_ListObjLength(Tkapp_Interp(tkapp), value, &size); + if (status == TCL_ERROR) + return Tkinter_Error(tkapp); + result = PyTuple_New(size); + if (!result) + return NULL; + for (i = 0; i < size; i++) { + status = Tcl_ListObjIndex(Tkapp_Interp(tkapp), + value, i, &tcl_elem); + if (status == TCL_ERROR) { + Py_DECREF(result); + return Tkinter_Error(tkapp); + } + elem = FromObj(tkapp, tcl_elem); + if (!elem) { + Py_DECREF(result); + return NULL; + } + PyTuple_SetItem(result, i, elem); + } + return result; + } + + if (value->typePtr == app->ProcBodyType) { + /* fall through: return tcl object. */ + } + + if (value->typePtr == app->StringType) { +#ifdef Py_USING_UNICODE +#if defined(Py_UNICODE_WIDE) && TCL_UTF_MAX==3 + PyObject *result; + int size; + Tcl_UniChar *input; + Py_UNICODE *output; + + size = Tcl_GetCharLength(value); + result = PyUnicode_FromUnicode(NULL, size); + if (!result) + return NULL; + input = Tcl_GetUnicode(value); + output = PyUnicode_AS_UNICODE(result); + while (size--) + *output++ = *input++; + return result; +#else + return PyUnicode_FromUnicode(Tcl_GetUnicode(value), + Tcl_GetCharLength(value)); +#endif +#else + int size; + char *c; + c = Tcl_GetStringFromObj(value, &size); + return PyString_FromStringAndSize(c, size); +#endif + } + + return newPyTclObject(value); +} + +/* This mutex synchronizes inter-thread command calls. */ + +TCL_DECLARE_MUTEX(call_mutex) + +typedef struct Tkapp_CallEvent { + Tcl_Event ev; /* Must be first */ + TkappObject *self; + PyObject *args; + int flags; + PyObject **res; + PyObject **exc_type, **exc_value, **exc_tb; + Tcl_Condition done; +} Tkapp_CallEvent; + +void +Tkapp_CallDeallocArgs(Tcl_Obj** objv, Tcl_Obj** objStore, int objc) +{ + int i; + for (i = 0; i < objc; i++) + Tcl_DecrRefCount(objv[i]); + if (objv != objStore) + ckfree(FREECAST objv); +} + +/* Convert Python objects to Tcl objects. This must happen in the + interpreter thread, which may or may not be the calling thread. */ + +static Tcl_Obj** +Tkapp_CallArgs(PyObject *args, Tcl_Obj** objStore, int *pobjc) +{ + Tcl_Obj **objv = objStore; + int objc = 0, i; + if (args == NULL) + /* do nothing */; + + else if (!PyTuple_Check(args)) { + objv[0] = AsObj(args); + if (objv[0] == 0) + goto finally; + objc = 1; + Tcl_IncrRefCount(objv[0]); + } + else { + objc = PyTuple_Size(args); + + if (objc > ARGSZ) { + objv = (Tcl_Obj **)ckalloc(objc * sizeof(char *)); + if (objv == NULL) { + PyErr_NoMemory(); + objc = 0; + goto finally; + } + } + + for (i = 0; i < objc; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (v == Py_None) { + objc = i; + break; + } + objv[i] = AsObj(v); + if (!objv[i]) { + /* Reset objc, so it attempts to clear + objects only up to i. */ + objc = i; + goto finally; + } + Tcl_IncrRefCount(objv[i]); + } + } + *pobjc = objc; + return objv; +finally: + Tkapp_CallDeallocArgs(objv, objStore, objc); + return NULL; +} + +/* Convert the results of a command call into a Python objects. */ + +static PyObject* +Tkapp_CallResult(TkappObject *self) +{ + PyObject *res = NULL; + if(self->wantobjects) { + Tcl_Obj *value = Tcl_GetObjResult(self->interp); + /* Not sure whether the IncrRef is necessary, but something + may overwrite the interpreter result while we are + converting it. */ + Tcl_IncrRefCount(value); + res = FromObj((PyObject*)self, value); + Tcl_DecrRefCount(value); + } else { + const char *s = Tcl_GetStringResult(self->interp); + const char *p = s; + + /* If the result contains any bytes with the top bit set, + it's UTF-8 and we should decode it to Unicode */ +#ifdef Py_USING_UNICODE + while (*p != '\0') { + if (*p & 0x80) + break; + p++; + } + + if (*p == '\0') + res = PyString_FromStringAndSize(s, (int)(p-s)); + else { + /* Convert UTF-8 to Unicode string */ + p = strchr(p, '\0'); + res = PyUnicode_DecodeUTF8(s, (int)(p-s), "strict"); + if (res == NULL) { + PyErr_Clear(); + res = PyString_FromStringAndSize(s, (int)(p-s)); + } + } +#else + p = strchr(p, '\0'); + res = PyString_FromStringAndSize(s, (int)(p-s)); +#endif + } + return res; +} + +/* Tkapp_CallProc is the event procedure that is executed in the context of + the Tcl interpreter thread. Initially, it holds the Tcl lock, and doesn't + hold the Python lock. */ + +static int +Tkapp_CallProc(Tkapp_CallEvent *e, int flags) +{ + Tcl_Obj *objStore[ARGSZ]; + Tcl_Obj **objv; + int objc; + int i; + ENTER_PYTHON + objv = Tkapp_CallArgs(e->args, objStore, &objc); + if (!objv) { + PyErr_Fetch(e->exc_type, e->exc_value, e->exc_tb); + *(e->res) = NULL; + } + LEAVE_PYTHON + if (!objv) + goto done; + i = Tcl_EvalObjv(e->self->interp, objc, objv, e->flags); + ENTER_PYTHON + if (i == TCL_ERROR) { + *(e->res) = NULL; + *(e->exc_type) = NULL; + *(e->exc_tb) = NULL; + *(e->exc_value) = PyObject_CallFunction( + Tkinter_TclError, "s", + Tcl_GetStringResult(e->self->interp)); + } + else { + *(e->res) = Tkapp_CallResult(e->self); + } + LEAVE_PYTHON + done: + /* Wake up calling thread. */ + Tcl_MutexLock(&call_mutex); + Tcl_ConditionNotify(&e->done); + Tcl_MutexUnlock(&call_mutex); + return 1; +} + +/* This is the main entry point for calling a Tcl command. + It supports three cases, with regard to threading: + 1. Tcl is not threaded: Must have the Tcl lock, then can invoke command in + the context of the calling thread. + 2. Tcl is threaded, caller of the command is in the interpreter thread: + Execute the command in the calling thread. Since the Tcl lock will + not be used, we can merge that with case 1. + 3. Tcl is threaded, caller is in a different thread: Must queue an event to + the interpreter thread. Allocation of Tcl objects needs to occur in the + interpreter thread, so we ship the PyObject* args to the target thread, + and perform processing there. */ + +static PyObject * +Tkapp_Call(PyObject *selfptr, PyObject *args) +{ + Tcl_Obj *objStore[ARGSZ]; + Tcl_Obj **objv = NULL; + int objc, i; + PyObject *res = NULL; + TkappObject *self = (TkappObject*)selfptr; + /* Could add TCL_EVAL_GLOBAL if wrapped by GlobalCall... */ + int flags = TCL_EVAL_DIRECT; + +#ifdef WITH_THREAD + if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { + /* We cannot call the command directly. Instead, we must + marshal the parameters to the interpreter thread. */ + Tkapp_CallEvent *ev; + PyObject *exc_type, *exc_value, *exc_tb; + if (!WaitForMainloop(self)) + return NULL; + ev = (Tkapp_CallEvent*)ckalloc(sizeof(Tkapp_CallEvent)); + ev->ev.proc = (Tcl_EventProc*)Tkapp_CallProc; + ev->self = self; + ev->args = args; + ev->res = &res; + ev->exc_type = &exc_type; + ev->exc_value = &exc_value; + ev->exc_tb = &exc_tb; + ev->done = (Tcl_Condition)0; + + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &call_mutex); + + if (res == NULL) { + if (exc_type) + PyErr_Restore(exc_type, exc_value, exc_tb); + else + PyErr_SetObject(Tkinter_TclError, exc_value); + } + } + else +#endif + { + + objv = Tkapp_CallArgs(args, objStore, &objc); + if (!objv) + return NULL; + + ENTER_TCL + + i = Tcl_EvalObjv(self->interp, objc, objv, flags); + + ENTER_OVERLAP + + if (i == TCL_ERROR) + Tkinter_Error(selfptr); + else + res = Tkapp_CallResult(self); + + LEAVE_OVERLAP_TCL + + Tkapp_CallDeallocArgs(objv, objStore, objc); + } + return res; +} + + +static PyObject * +Tkapp_GlobalCall(PyObject *self, PyObject *args) +{ + /* Could do the same here as for Tkapp_Call(), but this is not used + much, so I can't be bothered. Unfortunately Tcl doesn't export a + way for the user to do what all its Global* variants do (save and + reset the scope pointer, call the local version, restore the saved + scope pointer). */ + + char *cmd; + PyObject *res = NULL; + + CHECK_TCL_APPARTMENT; + + cmd = Merge(args); + if (cmd) { + int err; + ENTER_TCL + err = Tcl_GlobalEval(Tkapp_Interp(self), cmd); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + ckfree(cmd); + } + + return res; +} + +static PyObject * +Tkapp_Eval(PyObject *self, PyObject *args) +{ + char *script; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s:eval", &script)) + return NULL; + + CHECK_TCL_APPARTMENT; + + ENTER_TCL + err = Tcl_Eval(Tkapp_Interp(self), script); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_GlobalEval(PyObject *self, PyObject *args) +{ + char *script; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s:globaleval", &script)) + return NULL; + + CHECK_TCL_APPARTMENT; + + ENTER_TCL + err = Tcl_GlobalEval(Tkapp_Interp(self), script); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_EvalFile(PyObject *self, PyObject *args) +{ + char *fileName; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s:evalfile", &fileName)) + return NULL; + + CHECK_TCL_APPARTMENT; + + ENTER_TCL + err = Tcl_EvalFile(Tkapp_Interp(self), fileName); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_Record(PyObject *self, PyObject *args) +{ + char *script; + PyObject *res = NULL; + int err; + + if (!PyArg_ParseTuple(args, "s", &script)) + return NULL; + + CHECK_TCL_APPARTMENT; + + ENTER_TCL + err = Tcl_RecordAndEval(Tkapp_Interp(self), script, TCL_NO_EVAL); + ENTER_OVERLAP + if (err == TCL_ERROR) + res = Tkinter_Error(self); + else + res = PyString_FromString(Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_AddErrorInfo(PyObject *self, PyObject *args) +{ + char *msg; + + if (!PyArg_ParseTuple(args, "s:adderrorinfo", &msg)) + return NULL; + CHECK_TCL_APPARTMENT; + + ENTER_TCL + Tcl_AddErrorInfo(Tkapp_Interp(self), msg); + LEAVE_TCL + + Py_INCREF(Py_None); + return Py_None; +} + + + +/** Tcl Variable **/ + +TCL_DECLARE_MUTEX(var_mutex) + +typedef PyObject* (*EventFunc)(PyObject*, PyObject *args, int flags); +typedef struct VarEvent { + Tcl_Event ev; /* must be first */ + PyObject *self; + PyObject *args; + int flags; + EventFunc func; + PyObject **res; + PyObject **exc_type; + PyObject **exc_val; + Tcl_Condition cond; +} VarEvent; + +static int +varname_converter(PyObject *in, void *_out) +{ + char **out = (char**)_out; + if (PyString_Check(in)) { + *out = PyString_AsString(in); + return 1; + } + if (PyTclObject_Check(in)) { + *out = PyTclObject_TclString(in); + return 1; + } + /* XXX: Should give diagnostics. */ + return 0; +} + +void +var_perform(VarEvent *ev) +{ + *(ev->res) = ev->func(ev->self, ev->args, ev->flags); + if (!*(ev->res)) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + PyErr_NormalizeException(&exc, &val, &tb); + *(ev->exc_type) = exc; + *(ev->exc_val) = val; + Py_DECREF(tb); + } + +} + +static int +var_proc(VarEvent* ev, int flags) +{ + ENTER_PYTHON + var_perform(ev); + Tcl_MutexLock(&var_mutex); + Tcl_ConditionNotify(&ev->cond); + Tcl_MutexUnlock(&var_mutex); + LEAVE_PYTHON + return 1; +} + +static PyObject* +var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) +{ + TkappObject *self = (TkappObject*)selfptr; +#ifdef WITH_THREAD + if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { + TkappObject *self = (TkappObject*)selfptr; + VarEvent *ev; + PyObject *res, *exc_type, *exc_val; + + /* The current thread is not the interpreter thread. Marshal + the call to the interpreter thread, then wait for + completion. */ + if (!WaitForMainloop(self)) + return NULL; + + ev = (VarEvent*)ckalloc(sizeof(VarEvent)); + + ev->self = selfptr; + ev->args = args; + ev->flags = flags; + ev->func = func; + ev->res = &res; + ev->exc_type = &exc_type; + ev->exc_val = &exc_val; + ev->cond = NULL; + ev->ev.proc = (Tcl_EventProc*)var_proc; + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->cond, &var_mutex); + if (!res) { + PyErr_SetObject(exc_type, exc_val); + Py_DECREF(exc_type); + Py_DECREF(exc_val); + return NULL; + } + return res; + } +#endif + /* Tcl is not threaded, or this is the interpreter thread. */ + return func(selfptr, args, flags); +} + +static PyObject * +SetVar(PyObject *self, PyObject *args, int flags) +{ + char *name1, *name2; + PyObject *newValue; + PyObject *res = NULL; + Tcl_Obj *newval, *ok; + + if (PyArg_ParseTuple(args, "O&O:setvar", + varname_converter, &name1, &newValue)) { + /* XXX Acquire tcl lock??? */ + newval = AsObj(newValue); + if (newval == NULL) + return NULL; + ENTER_TCL + ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, NULL, + newval, flags); + ENTER_OVERLAP + if (!ok) + Tkinter_Error(self); + else { + res = Py_None; + Py_INCREF(res); + } + LEAVE_OVERLAP_TCL + } + else { + PyErr_Clear(); + if (PyArg_ParseTuple(args, "ssO:setvar", + &name1, &name2, &newValue)) { + /* XXX must hold tcl lock already??? */ + newval = AsObj(newValue); + ENTER_TCL + ok = Tcl_SetVar2Ex(Tkapp_Interp(self), name1, name2, newval, flags); + ENTER_OVERLAP + if (!ok) + Tkinter_Error(self); + else { + res = Py_None; + Py_INCREF(res); + } + LEAVE_OVERLAP_TCL + } + else { + return NULL; + } + } + return res; +} + +static PyObject * +Tkapp_SetVar(PyObject *self, PyObject *args) +{ + return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG); +} + +static PyObject * +Tkapp_GlobalSetVar(PyObject *self, PyObject *args) +{ + return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); +} + + + +static PyObject * +GetVar(PyObject *self, PyObject *args, int flags) +{ + char *name1, *name2=NULL; + PyObject *res = NULL; + Tcl_Obj *tres; + + if (!PyArg_ParseTuple(args, "O&|s:getvar", + varname_converter, &name1, &name2)) + return NULL; + + ENTER_TCL + tres = Tcl_GetVar2Ex(Tkapp_Interp(self), name1, name2, flags); + ENTER_OVERLAP + if (tres == NULL) { + PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); + } else { + if (((TkappObject*)self)->wantobjects) { + res = FromObj(self, tres); + } + else { + res = PyString_FromString(Tcl_GetString(tres)); + } + } + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_GetVar(PyObject *self, PyObject *args) +{ + return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG); +} + +static PyObject * +Tkapp_GlobalGetVar(PyObject *self, PyObject *args) +{ + return var_invoke(GetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); +} + + + +static PyObject * +UnsetVar(PyObject *self, PyObject *args, int flags) +{ + char *name1, *name2=NULL; + int code; + PyObject *res = NULL; + + if (!PyArg_ParseTuple(args, "s|s:unsetvar", &name1, &name2)) + return NULL; + + ENTER_TCL + code = Tcl_UnsetVar2(Tkapp_Interp(self), name1, name2, flags); + ENTER_OVERLAP + if (code == TCL_ERROR) + res = Tkinter_Error(self); + else { + Py_INCREF(Py_None); + res = Py_None; + } + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_UnsetVar(PyObject *self, PyObject *args) +{ + return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG); +} + +static PyObject * +Tkapp_GlobalUnsetVar(PyObject *self, PyObject *args) +{ + return var_invoke(UnsetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); +} + + + +/** Tcl to Python **/ + +static PyObject * +Tkapp_GetInt(PyObject *self, PyObject *args) +{ + char *s; + int v; + + if (PyTuple_Size(args) == 1) { + PyObject* o = PyTuple_GetItem(args, 0); + if (PyInt_Check(o)) { + Py_INCREF(o); + return o; + } + } + if (!PyArg_ParseTuple(args, "s:getint", &s)) + return NULL; + if (Tcl_GetInt(Tkapp_Interp(self), s, &v) == TCL_ERROR) + return Tkinter_Error(self); + return Py_BuildValue("i", v); +} + +static PyObject * +Tkapp_GetDouble(PyObject *self, PyObject *args) +{ + char *s; + double v; + + if (PyTuple_Size(args) == 1) { + PyObject *o = PyTuple_GetItem(args, 0); + if (PyFloat_Check(o)) { + Py_INCREF(o); + return o; + } + } + if (!PyArg_ParseTuple(args, "s:getdouble", &s)) + return NULL; + if (Tcl_GetDouble(Tkapp_Interp(self), s, &v) == TCL_ERROR) + return Tkinter_Error(self); + return Py_BuildValue("d", v); +} + +static PyObject * +Tkapp_GetBoolean(PyObject *self, PyObject *args) +{ + char *s; + int v; + + if (PyTuple_Size(args) == 1) { + PyObject *o = PyTuple_GetItem(args, 0); + if (PyInt_Check(o)) { + Py_INCREF(o); + return o; + } + } + if (!PyArg_ParseTuple(args, "s:getboolean", &s)) + return NULL; + if (Tcl_GetBoolean(Tkapp_Interp(self), s, &v) == TCL_ERROR) + return Tkinter_Error(self); + return PyBool_FromLong(v); +} + +static PyObject * +Tkapp_ExprString(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + int retval; + + if (!PyArg_ParseTuple(args, "s:exprstring", &s)) + return NULL; + + CHECK_TCL_APPARTMENT; + + ENTER_TCL + retval = Tcl_ExprString(Tkapp_Interp(self), s); + ENTER_OVERLAP + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("s", Tkapp_Result(self)); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_ExprLong(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + int retval; + long v; + + if (!PyArg_ParseTuple(args, "s:exprlong", &s)) + return NULL; + + CHECK_TCL_APPARTMENT; + + ENTER_TCL + retval = Tcl_ExprLong(Tkapp_Interp(self), s, &v); + ENTER_OVERLAP + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("l", v); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_ExprDouble(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + double v; + int retval; + + if (!PyArg_ParseTuple(args, "s:exprdouble", &s)) + return NULL; + CHECK_TCL_APPARTMENT; + PyFPE_START_PROTECT("Tkapp_ExprDouble", return 0) + ENTER_TCL + retval = Tcl_ExprDouble(Tkapp_Interp(self), s, &v); + ENTER_OVERLAP + PyFPE_END_PROTECT(retval) + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("d", v); + LEAVE_OVERLAP_TCL + return res; +} + +static PyObject * +Tkapp_ExprBoolean(PyObject *self, PyObject *args) +{ + char *s; + PyObject *res = NULL; + int retval; + int v; + + if (!PyArg_ParseTuple(args, "s:exprboolean", &s)) + return NULL; + CHECK_TCL_APPARTMENT; + ENTER_TCL + retval = Tcl_ExprBoolean(Tkapp_Interp(self), s, &v); + ENTER_OVERLAP + if (retval == TCL_ERROR) + res = Tkinter_Error(self); + else + res = Py_BuildValue("i", v); + LEAVE_OVERLAP_TCL + return res; +} + + + +static PyObject * +Tkapp_SplitList(PyObject *self, PyObject *args) +{ + char *list; + int argc; + char **argv; + PyObject *v; + int i; + + if (PyTuple_Size(args) == 1) { + v = PyTuple_GetItem(args, 0); + if (PyTuple_Check(v)) { + Py_INCREF(v); + return v; + } + } + if (!PyArg_ParseTuple(args, "et:splitlist", "utf-8", &list)) + return NULL; + + if (Tcl_SplitList(Tkapp_Interp(self), list, + &argc, &argv) == TCL_ERROR) { + PyMem_Free(list); + return Tkinter_Error(self); + } + + if (!(v = PyTuple_New(argc))) + goto finally; + + for (i = 0; i < argc; i++) { + PyObject *s = PyString_FromString(argv[i]); + if (!s || PyTuple_SetItem(v, i, s)) { + Py_DECREF(v); + v = NULL; + goto finally; + } + } + + finally: + ckfree(FREECAST argv); + PyMem_Free(list); + return v; +} + +static PyObject * +Tkapp_Split(PyObject *self, PyObject *args) +{ + PyObject *v; + char *list; + + if (PyTuple_Size(args) == 1) { + PyObject* o = PyTuple_GetItem(args, 0); + if (PyTuple_Check(o)) { + o = SplitObj(o); + return o; + } + } + if (!PyArg_ParseTuple(args, "et:split", "utf-8", &list)) + return NULL; + v = Split(list); + PyMem_Free(list); + return v; +} + +static PyObject * +Tkapp_Merge(PyObject *self, PyObject *args) +{ + char *s = Merge(args); + PyObject *res = NULL; + + if (s) { + res = PyString_FromString(s); + ckfree(s); + } + + return res; +} + + + +/** Tcl Command **/ + +/* Client data struct */ +typedef struct { + PyObject *self; + PyObject *func; +} PythonCmd_ClientData; + +static int +PythonCmd_Error(Tcl_Interp *interp) +{ + errorInCmd = 1; + PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + LEAVE_PYTHON + return TCL_ERROR; +} + +/* This is the Tcl command that acts as a wrapper for Python + * function or method. + */ +static int +PythonCmd(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) +{ + PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; + PyObject *self, *func, *arg, *res, *tmp; + int i, rv; + char *s; + + ENTER_PYTHON + + /* TBD: no error checking here since we know, via the + * Tkapp_CreateCommand() that the client data is a two-tuple + */ + self = data->self; + func = data->func; + + /* Create argument list (argv1, ..., argvN) */ + if (!(arg = PyTuple_New(argc - 1))) + return PythonCmd_Error(interp); + + for (i = 0; i < (argc - 1); i++) { + PyObject *s = PyString_FromString(argv[i + 1]); + if (!s || PyTuple_SetItem(arg, i, s)) { + Py_DECREF(arg); + return PythonCmd_Error(interp); + } + } + res = PyEval_CallObject(func, arg); + Py_DECREF(arg); + + if (res == NULL) + return PythonCmd_Error(interp); + + if (!(tmp = PyList_New(0))) { + Py_DECREF(res); + return PythonCmd_Error(interp); + } + + s = AsString(res, tmp); + if (s == NULL) { + rv = PythonCmd_Error(interp); + } + else { + Tcl_SetResult(Tkapp_Interp(self), s, TCL_VOLATILE); + rv = TCL_OK; + } + + Py_DECREF(res); + Py_DECREF(tmp); + + LEAVE_PYTHON + + return rv; +} + +static void +PythonCmdDelete(ClientData clientData) +{ + PythonCmd_ClientData *data = (PythonCmd_ClientData *)clientData; + + ENTER_PYTHON + Py_XDECREF(data->self); + Py_XDECREF(data->func); + PyMem_DEL(data); + LEAVE_PYTHON +} + + + + +TCL_DECLARE_MUTEX(command_mutex) + +typedef struct CommandEvent{ + Tcl_Event ev; + Tcl_Interp* interp; + char *name; + int create; + int *status; + ClientData *data; + Tcl_Condition done; +} CommandEvent; + +static int +Tkapp_CommandProc(CommandEvent *ev, int flags) +{ + if (ev->create) + *ev->status = Tcl_CreateCommand( + ev->interp, ev->name, PythonCmd, + ev->data, PythonCmdDelete) == NULL; + else + *ev->status = Tcl_DeleteCommand(ev->interp, ev->name); + Tcl_MutexLock(&command_mutex); + Tcl_ConditionNotify(&ev->done); + Tcl_MutexUnlock(&command_mutex); + return 1; +} + +static PyObject * +Tkapp_CreateCommand(PyObject *selfptr, PyObject *args) +{ + TkappObject *self = (TkappObject*)selfptr; + PythonCmd_ClientData *data; + char *cmdName; + PyObject *func; + int err; + + if (!PyArg_ParseTuple(args, "sO:createcommand", &cmdName, &func)) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "command not callable"); + return NULL; + } + +#ifdef WITH_THREAD + if (self->threaded && self->thread_id != Tcl_GetCurrentThread() && + !WaitForMainloop(self)) + return NULL; +#endif + + data = PyMem_NEW(PythonCmd_ClientData, 1); + if (!data) + return PyErr_NoMemory(); + Py_INCREF(self); + Py_INCREF(func); + data->self = selfptr; + data->func = func; + + if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { + CommandEvent *ev = (CommandEvent*)ckalloc(sizeof(CommandEvent)); + ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc; + ev->interp = self->interp; + ev->create = 1; + ev->name = cmdName; + ev->data = (ClientData)data; + ev->status = &err; + ev->done = NULL; + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, &command_mutex); + } + else { + ENTER_TCL + err = Tcl_CreateCommand( + Tkapp_Interp(self), cmdName, PythonCmd, + (ClientData)data, PythonCmdDelete) == NULL; + LEAVE_TCL + } + if (err) { + PyErr_SetString(Tkinter_TclError, "can't create Tcl command"); + PyMem_DEL(data); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + + +static PyObject * +Tkapp_DeleteCommand(PyObject *selfptr, PyObject *args) +{ + TkappObject *self = (TkappObject*)selfptr; + char *cmdName; + int err; + + if (!PyArg_ParseTuple(args, "s:deletecommand", &cmdName)) + return NULL; + if (self->threaded && self->thread_id != Tcl_GetCurrentThread()) { + CommandEvent *ev; + ev = (CommandEvent*)ckalloc(sizeof(CommandEvent)); + ev->ev.proc = (Tcl_EventProc*)Tkapp_CommandProc; + ev->interp = self->interp; + ev->create = 0; + ev->name = cmdName; + ev->status = &err; + ev->done = NULL; + Tkapp_ThreadSend(self, (Tcl_Event*)ev, &ev->done, + &command_mutex); + } + else { + ENTER_TCL + err = Tcl_DeleteCommand(self->interp, cmdName); + LEAVE_TCL + } + if (err == -1) { + PyErr_SetString(Tkinter_TclError, "can't delete Tcl command"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + + + +#ifdef HAVE_CREATEFILEHANDLER +/** File Handler **/ + +typedef struct _fhcdata { + PyObject *func; + PyObject *file; + int id; + struct _fhcdata *next; +} FileHandler_ClientData; + +static FileHandler_ClientData *HeadFHCD; + +static FileHandler_ClientData * +NewFHCD(PyObject *func, PyObject *file, int id) +{ + FileHandler_ClientData *p; + p = PyMem_NEW(FileHandler_ClientData, 1); + if (p != NULL) { + Py_XINCREF(func); + Py_XINCREF(file); + p->func = func; + p->file = file; + p->id = id; + p->next = HeadFHCD; + HeadFHCD = p; + } + return p; +} + +static void +DeleteFHCD(int id) +{ + FileHandler_ClientData *p, **pp; + + pp = &HeadFHCD; + while ((p = *pp) != NULL) { + if (p->id == id) { + *pp = p->next; + Py_XDECREF(p->func); + Py_XDECREF(p->file); + PyMem_DEL(p); + } + else + pp = &p->next; + } +} + +static void +FileHandler(ClientData clientData, int mask) +{ + FileHandler_ClientData *data = (FileHandler_ClientData *)clientData; + PyObject *func, *file, *arg, *res; + + ENTER_PYTHON + func = data->func; + file = data->file; + + arg = Py_BuildValue("(Oi)", file, (long) mask); + res = PyEval_CallObject(func, arg); + Py_DECREF(arg); + + if (res == NULL) { + errorInCmd = 1; + PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + } + Py_XDECREF(res); + LEAVE_PYTHON +} + +static PyObject * +Tkapp_CreateFileHandler(PyObject *self, PyObject *args) + /* args is (file, mask, func) */ +{ + FileHandler_ClientData *data; + PyObject *file, *func; + int mask, tfile; + + if (!PyArg_ParseTuple(args, "OiO:createfilehandler", + &file, &mask, &func)) + return NULL; + +#ifdef WITH_THREAD + if (!self && !tcl_lock) { + /* We don't have the Tcl lock since Tcl is threaded. */ + PyErr_SetString(PyExc_RuntimeError, + "_tkinter.createfilehandler not supported " + "for threaded Tcl"); + return NULL; + } +#endif + + if (self) { + CHECK_TCL_APPARTMENT; + } + + tfile = PyObject_AsFileDescriptor(file); + if (tfile < 0) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "bad argument list"); + return NULL; + } + + data = NewFHCD(func, file, tfile); + if (data == NULL) + return NULL; + + /* Ought to check for null Tcl_File object... */ + ENTER_TCL + Tcl_CreateFileHandler(tfile, mask, FileHandler, (ClientData) data); + LEAVE_TCL + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_DeleteFileHandler(PyObject *self, PyObject *args) +{ + PyObject *file; + int tfile; + + if (!PyArg_ParseTuple(args, "O:deletefilehandler", &file)) + return NULL; + +#ifdef WITH_THREAD + if (!self && !tcl_lock) { + /* We don't have the Tcl lock since Tcl is threaded. */ + PyErr_SetString(PyExc_RuntimeError, + "_tkinter.deletefilehandler not supported " + "for threaded Tcl"); + return NULL; + } +#endif + + if (self) { + CHECK_TCL_APPARTMENT; + } + + tfile = PyObject_AsFileDescriptor(file); + if (tfile < 0) + return NULL; + + DeleteFHCD(tfile); + + /* Ought to check for null Tcl_File object... */ + ENTER_TCL + Tcl_DeleteFileHandler(tfile); + LEAVE_TCL + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_CREATEFILEHANDLER */ + + +/**** Tktt Object (timer token) ****/ + +static PyTypeObject Tktt_Type; + +typedef struct { + PyObject_HEAD + Tcl_TimerToken token; + PyObject *func; +} TkttObject; + +static PyObject * +Tktt_DeleteTimerHandler(PyObject *self, PyObject *args) +{ + TkttObject *v = (TkttObject *)self; + PyObject *func = v->func; + + if (!PyArg_ParseTuple(args, ":deletetimerhandler")) + return NULL; + if (v->token != NULL) { + Tcl_DeleteTimerHandler(v->token); + v->token = NULL; + } + if (func != NULL) { + v->func = NULL; + Py_DECREF(func); + Py_DECREF(v); /* See Tktt_New() */ + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef Tktt_methods[] = +{ + {"deletetimerhandler", Tktt_DeleteTimerHandler, METH_VARARGS}, + {NULL, NULL} +}; + +static TkttObject * +Tktt_New(PyObject *func) +{ + TkttObject *v; + + v = PyObject_New(TkttObject, &Tktt_Type); + if (v == NULL) + return NULL; + + Py_INCREF(func); + v->token = NULL; + v->func = func; + + /* Extra reference, deleted when called or when handler is deleted */ + Py_INCREF(v); + return v; +} + +static void +Tktt_Dealloc(PyObject *self) +{ + TkttObject *v = (TkttObject *)self; + PyObject *func = v->func; + + Py_XDECREF(func); + + PyObject_Del(self); +} + +static PyObject * +Tktt_Repr(PyObject *self) +{ + TkttObject *v = (TkttObject *)self; + char buf[100]; + + PyOS_snprintf(buf, sizeof(buf), "<tktimertoken at %p%s>", v, + v->func == NULL ? ", handler deleted" : ""); + return PyString_FromString(buf); +} + +static PyObject * +Tktt_GetAttr(PyObject *self, char *name) +{ + return Py_FindMethod(Tktt_methods, self, name); +} + +static PyTypeObject Tktt_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size */ + "tktimertoken", /*tp_name */ + sizeof(TkttObject), /*tp_basicsize */ + 0, /*tp_itemsize */ + Tktt_Dealloc, /*tp_dealloc */ + 0, /*tp_print */ + Tktt_GetAttr, /*tp_getattr */ + 0, /*tp_setattr */ + 0, /*tp_compare */ + Tktt_Repr, /*tp_repr */ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash */ +}; + + + +/** Timer Handler **/ + +static void +TimerHandler(ClientData clientData) +{ + TkttObject *v = (TkttObject *)clientData; + PyObject *func = v->func; + PyObject *res; + + if (func == NULL) + return; + + v->func = NULL; + + ENTER_PYTHON + + res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + Py_DECREF(v); /* See Tktt_New() */ + + if (res == NULL) { + errorInCmd = 1; + PyErr_Fetch(&excInCmd, &valInCmd, &trbInCmd); + } + else + Py_DECREF(res); + + LEAVE_PYTHON +} + +static PyObject * +Tkapp_CreateTimerHandler(PyObject *self, PyObject *args) +{ + int milliseconds; + PyObject *func; + TkttObject *v; + + if (!PyArg_ParseTuple(args, "iO:createtimerhandler", + &milliseconds, &func)) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, "bad argument list"); + return NULL; + } + +#ifdef WITH_THREAD + if (!self && !tcl_lock) { + /* We don't have the Tcl lock since Tcl is threaded. */ + PyErr_SetString(PyExc_RuntimeError, + "_tkinter.createtimerhandler not supported " + "for threaded Tcl"); + return NULL; + } +#endif + + if (self) { + CHECK_TCL_APPARTMENT; + } + + v = Tktt_New(func); + if (v) { + v->token = Tcl_CreateTimerHandler(milliseconds, TimerHandler, + (ClientData)v); + } + + return (PyObject *) v; +} + + +/** Event Loop **/ + +static PyObject * +Tkapp_MainLoop(PyObject *selfptr, PyObject *args) +{ + int threshold = 0; + TkappObject *self = (TkappObject*)selfptr; +#ifdef WITH_THREAD + PyThreadState *tstate = PyThreadState_Get(); +#endif + + if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold)) + return NULL; + +#ifdef WITH_THREAD + if (!self && !tcl_lock) { + /* We don't have the Tcl lock since Tcl is threaded. */ + PyErr_SetString(PyExc_RuntimeError, + "_tkinter.mainloop not supported " + "for threaded Tcl"); + return NULL; + } +#endif + + if (self) { + CHECK_TCL_APPARTMENT; + self->dispatching = 1; + } + + quitMainLoop = 0; + while (Tk_GetNumMainWindows() > threshold && + !quitMainLoop && + !errorInCmd) + { + int result; + +#ifdef WITH_THREAD + if (self && self->threaded) { + /* Allow other Python threads to run. */ + ENTER_TCL + result = Tcl_DoOneEvent(0); + LEAVE_TCL + } + else { + Py_BEGIN_ALLOW_THREADS + if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); + tcl_tstate = tstate; + result = Tcl_DoOneEvent(TCL_DONT_WAIT); + tcl_tstate = NULL; + if(tcl_lock)PyThread_release_lock(tcl_lock); + if (result == 0) + Sleep(Tkinter_busywaitinterval); + Py_END_ALLOW_THREADS + } +#else + result = Tcl_DoOneEvent(0); +#endif + + if (PyErr_CheckSignals() != 0) { + if (self) + self->dispatching = 0; + return NULL; + } + if (result < 0) + break; + } + if (self) + self->dispatching = 0; + quitMainLoop = 0; + + if (errorInCmd) { + errorInCmd = 0; + PyErr_Restore(excInCmd, valInCmd, trbInCmd); + excInCmd = valInCmd = trbInCmd = NULL; + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_DoOneEvent(PyObject *self, PyObject *args) +{ + int flags = 0; + int rv; + + if (!PyArg_ParseTuple(args, "|i:dooneevent", &flags)) + return NULL; + + ENTER_TCL + rv = Tcl_DoOneEvent(flags); + LEAVE_TCL + return Py_BuildValue("i", rv); +} + +static PyObject * +Tkapp_Quit(PyObject *self, PyObject *args) +{ + + if (!PyArg_ParseTuple(args, ":quit")) + return NULL; + + quitMainLoop = 1; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_InterpAddr(PyObject *self, PyObject *args) +{ + + if (!PyArg_ParseTuple(args, ":interpaddr")) + return NULL; + + return PyInt_FromLong((long)Tkapp_Interp(self)); +} + +static PyObject * +Tkapp_TkInit(PyObject *self, PyObject *args) +{ + static int has_failed; + Tcl_Interp *interp = Tkapp_Interp(self); + Tk_Window main_window; + const char * _tk_exists = NULL; + int err; + main_window = Tk_MainWindow(interp); + + /* In all current versions of Tk (including 8.4.13), Tk_Init + deadlocks on the second call when the first call failed. + To avoid the deadlock, we just refuse the second call through + a static variable. */ + if (has_failed) { + PyErr_SetString(Tkinter_TclError, + "Calling Tk_Init again after a previous call failed might deadlock"); + return NULL; + } + + /* We want to guard against calling Tk_Init() multiple times */ + CHECK_TCL_APPARTMENT; + ENTER_TCL + err = Tcl_Eval(Tkapp_Interp(self), "info exists tk_version"); + ENTER_OVERLAP + if (err == TCL_ERROR) { + /* This sets an exception, but we cannot return right + away because we need to exit the overlap first. */ + Tkinter_Error(self); + } else { + _tk_exists = Tkapp_Result(self); + } + LEAVE_OVERLAP_TCL + if (err == TCL_ERROR) { + return NULL; + } + if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) { + if (Tk_Init(interp) == TCL_ERROR) { + PyErr_SetString(Tkinter_TclError, Tcl_GetStringResult(Tkapp_Interp(self))); + has_failed = 1; + return NULL; + } + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_WantObjects(PyObject *self, PyObject *args) +{ + + int wantobjects = -1; + if (!PyArg_ParseTuple(args, "|i:wantobjects", &wantobjects)) + return NULL; + if (wantobjects == -1) + return PyBool_FromLong(((TkappObject*)self)->wantobjects); + ((TkappObject*)self)->wantobjects = wantobjects; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Tkapp_WillDispatch(PyObject *self, PyObject *args) +{ + + ((TkappObject*)self)->dispatching = 1; + + Py_INCREF(Py_None); + return Py_None; +} + + +/**** Tkapp Method List ****/ + +static PyMethodDef Tkapp_methods[] = +{ + {"willdispatch", Tkapp_WillDispatch, METH_NOARGS}, + {"wantobjects", Tkapp_WantObjects, METH_VARARGS}, + {"call", Tkapp_Call, METH_OLDARGS}, + {"globalcall", Tkapp_GlobalCall, METH_OLDARGS}, + {"eval", Tkapp_Eval, METH_VARARGS}, + {"globaleval", Tkapp_GlobalEval, METH_VARARGS}, + {"evalfile", Tkapp_EvalFile, METH_VARARGS}, + {"record", Tkapp_Record, METH_VARARGS}, + {"adderrorinfo", Tkapp_AddErrorInfo, METH_VARARGS}, + {"setvar", Tkapp_SetVar, METH_VARARGS}, + {"globalsetvar", Tkapp_GlobalSetVar, METH_VARARGS}, + {"getvar", Tkapp_GetVar, METH_VARARGS}, + {"globalgetvar", Tkapp_GlobalGetVar, METH_VARARGS}, + {"unsetvar", Tkapp_UnsetVar, METH_VARARGS}, + {"globalunsetvar", Tkapp_GlobalUnsetVar, METH_VARARGS}, + {"getint", Tkapp_GetInt, METH_VARARGS}, + {"getdouble", Tkapp_GetDouble, METH_VARARGS}, + {"getboolean", Tkapp_GetBoolean, METH_VARARGS}, + {"exprstring", Tkapp_ExprString, METH_VARARGS}, + {"exprlong", Tkapp_ExprLong, METH_VARARGS}, + {"exprdouble", Tkapp_ExprDouble, METH_VARARGS}, + {"exprboolean", Tkapp_ExprBoolean, METH_VARARGS}, + {"splitlist", Tkapp_SplitList, METH_VARARGS}, + {"split", Tkapp_Split, METH_VARARGS}, + {"merge", Tkapp_Merge, METH_OLDARGS}, + {"createcommand", Tkapp_CreateCommand, METH_VARARGS}, + {"deletecommand", Tkapp_DeleteCommand, METH_VARARGS}, +#ifdef HAVE_CREATEFILEHANDLER + {"createfilehandler", Tkapp_CreateFileHandler, METH_VARARGS}, + {"deletefilehandler", Tkapp_DeleteFileHandler, METH_VARARGS}, +#endif + {"createtimerhandler", Tkapp_CreateTimerHandler, METH_VARARGS}, + {"mainloop", Tkapp_MainLoop, METH_VARARGS}, + {"dooneevent", Tkapp_DoOneEvent, METH_VARARGS}, + {"quit", Tkapp_Quit, METH_VARARGS}, + {"interpaddr", Tkapp_InterpAddr, METH_VARARGS}, + {"loadtk", Tkapp_TkInit, METH_NOARGS}, + {NULL, NULL} +}; + + + +/**** Tkapp Type Methods ****/ + +static void +Tkapp_Dealloc(PyObject *self) +{ + /*CHECK_TCL_APPARTMENT;*/ + ENTER_TCL + Tcl_DeleteInterp(Tkapp_Interp(self)); + LEAVE_TCL + PyObject_Del(self); + DisableEventHook(); +} + +static PyObject * +Tkapp_GetAttr(PyObject *self, char *name) +{ + return Py_FindMethod(Tkapp_methods, self, name); +} + +static PyTypeObject Tkapp_Type = +{ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size */ + "tkapp", /*tp_name */ + sizeof(TkappObject), /*tp_basicsize */ + 0, /*tp_itemsize */ + Tkapp_Dealloc, /*tp_dealloc */ + 0, /*tp_print */ + Tkapp_GetAttr, /*tp_getattr */ + 0, /*tp_setattr */ + 0, /*tp_compare */ + 0, /*tp_repr */ + 0, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0, /*tp_hash */ +}; + + + +/**** Tkinter Module ****/ + +typedef struct { + PyObject* tuple; + int size; /* current size */ + int maxsize; /* allocated size */ +} FlattenContext; + +static int +_bump(FlattenContext* context, int size) +{ + /* expand tuple to hold (at least) size new items. + return true if successful, false if an exception was raised */ + + int maxsize = context->maxsize * 2; + + if (maxsize < context->size + size) + maxsize = context->size + size; + + context->maxsize = maxsize; + + return _PyTuple_Resize(&context->tuple, maxsize) >= 0; +} + +static int +_flatten1(FlattenContext* context, PyObject* item, int depth) +{ + /* add tuple or list to argument tuple (recursively) */ + + int i, size; + + if (depth > 1000) { + PyErr_SetString(PyExc_ValueError, + "nesting too deep in _flatten"); + return 0; + } else if (PyList_Check(item)) { + size = PyList_GET_SIZE(item); + /* preallocate (assume no nesting) */ + if (context->size + size > context->maxsize && + !_bump(context, size)) + return 0; + /* copy items to output tuple */ + for (i = 0; i < size; i++) { + PyObject *o = PyList_GET_ITEM(item, i); + if (PyList_Check(o) || PyTuple_Check(o)) { + if (!_flatten1(context, o, depth + 1)) + return 0; + } else if (o != Py_None) { + if (context->size + 1 > context->maxsize && + !_bump(context, 1)) + return 0; + Py_INCREF(o); + PyTuple_SET_ITEM(context->tuple, + context->size++, o); + } + } + } else if (PyTuple_Check(item)) { + /* same, for tuples */ + size = PyTuple_GET_SIZE(item); + if (context->size + size > context->maxsize && + !_bump(context, size)) + return 0; + for (i = 0; i < size; i++) { + PyObject *o = PyTuple_GET_ITEM(item, i); + if (PyList_Check(o) || PyTuple_Check(o)) { + if (!_flatten1(context, o, depth + 1)) + return 0; + } else if (o != Py_None) { + if (context->size + 1 > context->maxsize && + !_bump(context, 1)) + return 0; + Py_INCREF(o); + PyTuple_SET_ITEM(context->tuple, + context->size++, o); + } + } + } else { + PyErr_SetString(PyExc_TypeError, "argument must be sequence"); + return 0; + } + return 1; +} + +static PyObject * +Tkinter_Flatten(PyObject* self, PyObject* args) +{ + FlattenContext context; + PyObject* item; + + if (!PyArg_ParseTuple(args, "O:_flatten", &item)) + return NULL; + + context.maxsize = PySequence_Size(item); + if (context.maxsize <= 0) + return PyTuple_New(0); + + context.tuple = PyTuple_New(context.maxsize); + if (!context.tuple) + return NULL; + + context.size = 0; + + if (!_flatten1(&context, item,0)) + return NULL; + + if (_PyTuple_Resize(&context.tuple, context.size)) + return NULL; + + return context.tuple; +} + +static PyObject * +Tkinter_Create(PyObject *self, PyObject *args) +{ + char *screenName = NULL; + char *baseName = NULL; + char *className = NULL; + int interactive = 0; + int wantobjects = 0; + int wantTk = 1; /* If false, then Tk_Init() doesn't get called */ + int sync = 0; /* pass -sync to wish */ + char *use = NULL; /* pass -use to wish */ + + baseName = strrchr(Py_GetProgramName(), '/'); + if (baseName != NULL) + baseName++; + else + baseName = Py_GetProgramName(); + className = "Tk"; + + if (!PyArg_ParseTuple(args, "|zssiiiiz:create", + &screenName, &baseName, &className, + &interactive, &wantobjects, &wantTk, + &sync, &use)) + return NULL; + + return (PyObject *) Tkapp_New(screenName, baseName, className, + interactive, wantobjects, wantTk, + sync, use); +} + +static PyObject * +Tkinter_setbusywaitinterval(PyObject *self, PyObject *args) +{ + int new_val; + if (!PyArg_ParseTuple(args, "i:setbusywaitinterval", &new_val)) + return NULL; + if (new_val < 0) { + PyErr_SetString(PyExc_ValueError, + "busywaitinterval must be >= 0"); + return NULL; + } + Tkinter_busywaitinterval = new_val; + Py_INCREF(Py_None); + return Py_None; +} + +static char setbusywaitinterval_doc[] = +"setbusywaitinterval(n) -> None\n\ +\n\ +Set the busy-wait interval in milliseconds between successive\n\ +calls to Tcl_DoOneEvent in a threaded Python interpreter.\n\ +It should be set to a divisor of the maximum time between\n\ +frames in an animation."; + +static PyObject * +Tkinter_getbusywaitinterval(PyObject *self, PyObject *args) +{ + return PyInt_FromLong(Tkinter_busywaitinterval); +} + +static char getbusywaitinterval_doc[] = +"getbusywaitinterval() -> int\n\ +\n\ +Return the current busy-wait interval between successive\n\ +calls to Tcl_DoOneEvent in a threaded Python interpreter."; + +static PyMethodDef moduleMethods[] = +{ + {"_flatten", Tkinter_Flatten, METH_VARARGS}, + {"create", Tkinter_Create, METH_VARARGS}, +#ifdef HAVE_CREATEFILEHANDLER + {"createfilehandler", Tkapp_CreateFileHandler, METH_VARARGS}, + {"deletefilehandler", Tkapp_DeleteFileHandler, METH_VARARGS}, +#endif + {"createtimerhandler", Tkapp_CreateTimerHandler, METH_VARARGS}, + {"mainloop", Tkapp_MainLoop, METH_VARARGS}, + {"dooneevent", Tkapp_DoOneEvent, METH_VARARGS}, + {"quit", Tkapp_Quit, METH_VARARGS}, + {"setbusywaitinterval",Tkinter_setbusywaitinterval, METH_VARARGS, + setbusywaitinterval_doc}, + {"getbusywaitinterval",(PyCFunction)Tkinter_getbusywaitinterval, + METH_NOARGS, getbusywaitinterval_doc}, + {NULL, NULL} +}; + +#ifdef WAIT_FOR_STDIN + +static int stdin_ready = 0; + +#ifndef MS_WINDOWS +static void +MyFileProc(void *clientData, int mask) +{ + stdin_ready = 1; +} +#endif + +#ifdef WITH_THREAD +static PyThreadState *event_tstate = NULL; +#endif + +static int +EventHook(void) +{ +#ifndef MS_WINDOWS + int tfile; +#endif +#ifdef WITH_THREAD + PyEval_RestoreThread(event_tstate); +#endif + stdin_ready = 0; + errorInCmd = 0; +#ifndef MS_WINDOWS + tfile = fileno(stdin); + Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL); +#endif + while (!errorInCmd && !stdin_ready) { + int result; +#ifdef MS_WINDOWS + if (_kbhit()) { + stdin_ready = 1; + break; + } +#endif +#if defined(WITH_THREAD) || defined(MS_WINDOWS) + Py_BEGIN_ALLOW_THREADS + if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); + tcl_tstate = event_tstate; + + result = Tcl_DoOneEvent(TCL_DONT_WAIT); + + tcl_tstate = NULL; + if(tcl_lock)PyThread_release_lock(tcl_lock); + if (result == 0) + Sleep(Tkinter_busywaitinterval); + Py_END_ALLOW_THREADS +#else + result = Tcl_DoOneEvent(0); +#endif + + if (result < 0) + break; + } +#ifndef MS_WINDOWS + Tcl_DeleteFileHandler(tfile); +#endif + if (errorInCmd) { + errorInCmd = 0; + PyErr_Restore(excInCmd, valInCmd, trbInCmd); + excInCmd = valInCmd = trbInCmd = NULL; + PyErr_Print(); + } +#ifdef WITH_THREAD + PyEval_SaveThread(); +#endif + return 0; +} + +#endif + +static void +EnableEventHook(void) +{ +#ifdef WAIT_FOR_STDIN + if (PyOS_InputHook == NULL) { +#ifdef WITH_THREAD + event_tstate = PyThreadState_Get(); +#endif + PyOS_InputHook = EventHook; + } +#endif +} + +static void +DisableEventHook(void) +{ +#ifdef WAIT_FOR_STDIN + if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) { + PyOS_InputHook = NULL; + } +#endif +} + + +/* all errors will be checked in one fell swoop in init_tkinter() */ +static void +ins_long(PyObject *d, char *name, long val) +{ + PyObject *v = PyInt_FromLong(val); + if (v) { + PyDict_SetItemString(d, name, v); + Py_DECREF(v); + } +} +static void +ins_string(PyObject *d, char *name, char *val) +{ + PyObject *v = PyString_FromString(val); + if (v) { + PyDict_SetItemString(d, name, v); + Py_DECREF(v); + } +} + + +PyMODINIT_FUNC +init_tkinter(void) +{ + PyObject *m, *d; + + Tkapp_Type.ob_type = &PyType_Type; + +#ifdef WITH_THREAD + tcl_lock = PyThread_allocate_lock(); +#endif + + m = Py_InitModule("_tkinter", moduleMethods); + if (m == NULL) + return; + + d = PyModule_GetDict(m); + Tkinter_TclError = PyErr_NewException("_tkinter.TclError", NULL, NULL); + PyDict_SetItemString(d, "TclError", Tkinter_TclError); + + ins_long(d, "READABLE", TCL_READABLE); + ins_long(d, "WRITABLE", TCL_WRITABLE); + ins_long(d, "EXCEPTION", TCL_EXCEPTION); + ins_long(d, "WINDOW_EVENTS", TCL_WINDOW_EVENTS); + ins_long(d, "FILE_EVENTS", TCL_FILE_EVENTS); + ins_long(d, "TIMER_EVENTS", TCL_TIMER_EVENTS); + ins_long(d, "IDLE_EVENTS", TCL_IDLE_EVENTS); + ins_long(d, "ALL_EVENTS", TCL_ALL_EVENTS); + ins_long(d, "DONT_WAIT", TCL_DONT_WAIT); + ins_string(d, "TK_VERSION", TK_VERSION); + ins_string(d, "TCL_VERSION", TCL_VERSION); + + PyDict_SetItemString(d, "TkappType", (PyObject *)&Tkapp_Type); + + Tktt_Type.ob_type = &PyType_Type; + PyDict_SetItemString(d, "TkttType", (PyObject *)&Tktt_Type); + + PyTclObject_Type.ob_type = &PyType_Type; + PyDict_SetItemString(d, "Tcl_Obj", (PyObject *)&PyTclObject_Type); + +#ifdef TK_AQUA + /* Tk_MacOSXSetupTkNotifier must be called before Tcl's subsystems + * start waking up. Note that Tcl_FindExecutable will do this, this + * code must be above it! The original warning from + * tkMacOSXAppInit.c is copied below. + * + * NB - You have to swap in the Tk Notifier BEFORE you start up the + * Tcl interpreter for now. It probably should work to do this + * in the other order, but for now it doesn't seem to. + * + */ + Tk_MacOSXSetupTkNotifier(); +#endif + + + /* This helps the dynamic loader; in Unicode aware Tcl versions + it also helps Tcl find its encodings. */ + Tcl_FindExecutable(Py_GetProgramName()); + + if (PyErr_Occurred()) + return; + +#if 0 + /* This was not a good idea; through <Destroy> bindings, + Tcl_Finalize() may invoke Python code but at that point the + interpreter and thread state have already been destroyed! */ + Py_AtExit(Tcl_Finalize); +#endif + +} diff --git a/sys/src/cmd/python/Modules/_typesmodule.c b/sys/src/cmd/python/Modules/_typesmodule.c new file mode 100644 index 000000000..5a6f2b980 --- /dev/null +++ b/sys/src/cmd/python/Modules/_typesmodule.c @@ -0,0 +1,94 @@ +/* This extension module exposes some types that are only available at the + * C level. It should not be used directly, but instead through the Python + * level types modules, which imports this. + */ + +#include "Python.h" +#include "structmember.h" + +typedef struct +{ + PyObject_HEAD + int member; +} Helper; + +static PyMemberDef helper_members[] = { + { "member", T_INT, offsetof(Helper, member), READONLY, + PyDoc_STR("A member descriptor") + }, + { NULL } +}; + +static PyObject * +helper_getter(Helper *self, void *unused) +{ + Py_RETURN_NONE; +} + +static PyGetSetDef helper_getset[] = { + { "getter", (getter)helper_getter, NULL, + PyDoc_STR("A getset descriptor"), + }, + { NULL } +}; + +static PyTypeObject HelperType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "_types.Helper", /* tp_name */ + sizeof(Helper), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + helper_members, /* tp_members */ + helper_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ +}; + +PyMODINIT_FUNC +init_types(void) +{ + PyObject *m; + + m = Py_InitModule3("_types", NULL, "A types module helper"); + if (!m) + return; + + if (PyType_Ready(&HelperType) < 0) + return; + + Py_INCREF(&HelperType); + PyModule_AddObject(m, "Helper", (PyObject *)&HelperType); +} + + diff --git a/sys/src/cmd/python/Modules/_weakref.c b/sys/src/cmd/python/Modules/_weakref.c new file mode 100644 index 000000000..1712f12c0 --- /dev/null +++ b/sys/src/cmd/python/Modules/_weakref.c @@ -0,0 +1,112 @@ +#include "Python.h" + + +#define GET_WEAKREFS_LISTPTR(o) \ + ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o)) + + +PyDoc_STRVAR(weakref_getweakrefcount__doc__, +"getweakrefcount(object) -- return the number of weak references\n" +"to 'object'."); + +static PyObject * +weakref_getweakrefcount(PyObject *self, PyObject *object) +{ + PyObject *result = NULL; + + if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) { + PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); + + result = PyInt_FromSsize_t(_PyWeakref_GetWeakrefCount(*list)); + } + else + result = PyInt_FromLong(0); + + return result; +} + + +PyDoc_STRVAR(weakref_getweakrefs__doc__, +"getweakrefs(object) -- return a list of all weak reference objects\n" +"that point to 'object'."); + +static PyObject * +weakref_getweakrefs(PyObject *self, PyObject *object) +{ + PyObject *result = NULL; + + if (PyType_SUPPORTS_WEAKREFS(object->ob_type)) { + PyWeakReference **list = GET_WEAKREFS_LISTPTR(object); + Py_ssize_t count = _PyWeakref_GetWeakrefCount(*list); + + result = PyList_New(count); + if (result != NULL) { + PyWeakReference *current = *list; + Py_ssize_t i; + for (i = 0; i < count; ++i) { + PyList_SET_ITEM(result, i, (PyObject *) current); + Py_INCREF(current); + current = current->wr_next; + } + } + } + else { + result = PyList_New(0); + } + return result; +} + + +PyDoc_STRVAR(weakref_proxy__doc__, +"proxy(object[, callback]) -- create a proxy object that weakly\n" +"references 'object'. 'callback', if given, is called with a\n" +"reference to the proxy when 'object' is about to be finalized."); + +static PyObject * +weakref_proxy(PyObject *self, PyObject *args) +{ + PyObject *object; + PyObject *callback = NULL; + PyObject *result = NULL; + + if (PyArg_UnpackTuple(args, "proxy", 1, 2, &object, &callback)) { + result = PyWeakref_NewProxy(object, callback); + } + return result; +} + + +static PyMethodDef +weakref_functions[] = { + {"getweakrefcount", weakref_getweakrefcount, METH_O, + weakref_getweakrefcount__doc__}, + {"getweakrefs", weakref_getweakrefs, METH_O, + weakref_getweakrefs__doc__}, + {"proxy", weakref_proxy, METH_VARARGS, + weakref_proxy__doc__}, + {NULL, NULL, 0, NULL} +}; + + +PyMODINIT_FUNC +init_weakref(void) +{ + PyObject *m; + + m = Py_InitModule3("_weakref", weakref_functions, + "Weak-reference support module."); + if (m != NULL) { + Py_INCREF(&_PyWeakref_RefType); + PyModule_AddObject(m, "ref", + (PyObject *) &_PyWeakref_RefType); + Py_INCREF(&_PyWeakref_RefType); + PyModule_AddObject(m, "ReferenceType", + (PyObject *) &_PyWeakref_RefType); + Py_INCREF(&_PyWeakref_ProxyType); + PyModule_AddObject(m, "ProxyType", + (PyObject *) &_PyWeakref_ProxyType); + Py_INCREF(&_PyWeakref_CallableProxyType); + PyModule_AddObject(m, "CallableProxyType", + (PyObject *) &_PyWeakref_CallableProxyType); + } +} diff --git a/sys/src/cmd/python/Modules/addrinfo.h b/sys/src/cmd/python/Modules/addrinfo.h new file mode 100644 index 000000000..6f67a2e95 --- /dev/null +++ b/sys/src/cmd/python/Modules/addrinfo.h @@ -0,0 +1,176 @@ +/* + * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef HAVE_GETADDRINFO + +/* + * Error return codes from getaddrinfo() + */ +#ifdef EAI_ADDRFAMILY +/* If this is defined, there is a conflicting implementation + in the C library, which can't be used for some reason. + Make sure it won't interfere with this emulation. */ + +#undef EAI_ADDRFAMILY +#undef EAI_AGAIN +#undef EAI_BADFLAGS +#undef EAI_FAIL +#undef EAI_FAMILY +#undef EAI_MEMORY +#undef EAI_NODATA +#undef EAI_NONAME +#undef EAI_SERVICE +#undef EAI_SOCKTYPE +#undef EAI_SYSTEM +#undef EAI_BADHINTS +#undef EAI_PROTOCOL +#undef EAI_MAX +#undef getaddrinfo +#define getaddrinfo fake_getaddrinfo +#endif /* EAI_ADDRFAMILY */ + +#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ +#define EAI_AGAIN 2 /* temporary failure in name resolution */ +#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#define EAI_FAMILY 5 /* ai_family not supported */ +#define EAI_MEMORY 6 /* memory allocation failure */ +#define EAI_NODATA 7 /* no address associated with hostname */ +#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ +#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ +#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ +#define EAI_SYSTEM 11 /* system error returned in errno */ +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 +#define EAI_MAX 14 + +/* + * Flag values for getaddrinfo() + */ +#ifdef AI_PASSIVE +#undef AI_PASSIVE +#undef AI_CANONNAME +#undef AI_NUMERICHOST +#undef AI_MASK +#undef AI_ALL +#undef AI_V4MAPPED_CFG +#undef AI_ADDRCONFIG +#undef AI_V4MAPPED +#undef AI_DEFAULT +#endif /* AI_PASSIVE */ + +#define AI_PASSIVE 0x00000001 /* get address to use bind() */ +#define AI_CANONNAME 0x00000002 /* fill ai_canonname */ +#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */ +/* valid flags for addrinfo */ +#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST) + +#define AI_ALL 0x00000100 /* IPv6 and IPv4-mapped (with AI_V4MAPPED) */ +#define AI_V4MAPPED_CFG 0x00000200 /* accept IPv4-mapped if kernel supports */ +#define AI_ADDRCONFIG 0x00000400 /* only if any address is assigned */ +#define AI_V4MAPPED 0x00000800 /* accept IPv4-mapped IPv6 address */ +/* special recommended flags for getipnodebyname */ +#define AI_DEFAULT (AI_V4MAPPED_CFG | AI_ADDRCONFIG) + +#endif /* !HAVE_GETADDRINFO */ + +#ifndef HAVE_GETNAMEINFO + +/* + * Constants for getnameinfo() + */ +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#define NI_MAXSERV 32 +#endif /* !NI_MAXHOST */ + +/* + * Flag values for getnameinfo() + */ +#ifndef NI_NOFQDN +#define NI_NOFQDN 0x00000001 +#define NI_NUMERICHOST 0x00000002 +#define NI_NAMEREQD 0x00000004 +#define NI_NUMERICSERV 0x00000008 +#define NI_DGRAM 0x00000010 +#endif /* !NI_NOFQDN */ + +#endif /* !HAVE_GETNAMEINFO */ + +#ifndef HAVE_ADDRINFO +struct addrinfo { + int ai_flags; /* AI_PASSIVE, AI_CANONNAME */ + int ai_family; /* PF_xxx */ + int ai_socktype; /* SOCK_xxx */ + int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */ + size_t ai_addrlen; /* length of ai_addr */ + char *ai_canonname; /* canonical name for hostname */ + struct sockaddr *ai_addr; /* binary address */ + struct addrinfo *ai_next; /* next structure in linked list */ +}; +#endif /* !HAVE_ADDRINFO */ + +#ifndef HAVE_SOCKADDR_STORAGE +/* + * RFC 2553: protocol-independent placeholder for socket addresses + */ +#define _SS_MAXSIZE 128 +#ifdef HAVE_LONG_LONG +#define _SS_ALIGNSIZE (sizeof(PY_LONG_LONG)) +#else +#define _SS_ALIGNSIZE (sizeof(double)) +#endif /* HAVE_LONG_LONG */ +#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof(u_char) * 2) +#define _SS_PAD2SIZE (_SS_MAXSIZE - sizeof(u_char) * 2 - \ + _SS_PAD1SIZE - _SS_ALIGNSIZE) + +struct sockaddr_storage { +#ifdef HAVE_SOCKADDR_SA_LEN + unsigned char ss_len; /* address length */ + unsigned char ss_family; /* address family */ +#else + unsigned short ss_family; /* address family */ +#endif /* HAVE_SOCKADDR_SA_LEN */ + char __ss_pad1[_SS_PAD1SIZE]; +#ifdef HAVE_LONG_LONG + PY_LONG_LONG __ss_align; /* force desired structure storage alignment */ +#else + double __ss_align; /* force desired structure storage alignment */ +#endif /* HAVE_LONG_LONG */ + char __ss_pad2[_SS_PAD2SIZE]; +}; +#endif /* !HAVE_SOCKADDR_STORAGE */ + +#ifdef __cplusplus +extern "C" { +#endif +extern void freehostent Py_PROTO((struct hostent *)); +#ifdef __cplusplus +} +#endif diff --git a/sys/src/cmd/python/Modules/almodule.c b/sys/src/cmd/python/Modules/almodule.c new file mode 100644 index 000000000..0a45d2e0c --- /dev/null +++ b/sys/src/cmd/python/Modules/almodule.c @@ -0,0 +1,3226 @@ + +#define OLD_INTERFACE /* define for pre-Irix 6 interface */ + +#include "Python.h" +#include "stringobject.h" +#include <audio.h> +#include <stdarg.h> + +#ifndef AL_NO_ELEM +#ifndef OLD_INTERFACE +#define OLD_INTERFACE +#endif /* OLD_INTERFACE */ +#endif /* AL_NO_ELEM */ + +static PyObject *ErrorObject; + +/* ----------------------------------------------------- */ + +/* Declarations for objects of type port */ + +typedef struct { + PyObject_HEAD + /* XXXX Add your own stuff here */ + ALport port; +} alpobject; + +static PyTypeObject Alptype; + + + +/* ---------------------------------------------------------------- */ + +/* Declarations for objects of type config */ + +typedef struct { + PyObject_HEAD + /* XXXX Add your own stuff here */ + ALconfig config; +} alcobject; + +static PyTypeObject Alctype; + + +static void +ErrorHandler(long code, const char *fmt, ...) +{ + va_list args; + char buf[128]; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + PyErr_SetString(ErrorObject, buf); +} + +#ifdef AL_NO_ELEM /* IRIX 6 */ + +static PyObject * +param2python(int resource, int param, ALvalue value, ALparamInfo *pinfo) +{ + ALparamInfo info; + + if (pinfo == NULL) { + pinfo = &info; + if (alGetParamInfo(resource, param, &info) < 0) + return NULL; + } + switch (pinfo->elementType) { + case AL_PTR_ELEM: + /* XXXX don't know how to handle this */ + case AL_NO_ELEM: + Py_INCREF(Py_None); + return Py_None; + case AL_INT32_ELEM: + case AL_RESOURCE_ELEM: + case AL_ENUM_ELEM: + return PyInt_FromLong((long) value.i); + case AL_INT64_ELEM: + return PyLong_FromLongLong(value.ll); + case AL_FIXED_ELEM: + return PyFloat_FromDouble(alFixedToDouble(value.ll)); + case AL_CHAR_ELEM: + if (value.ptr == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString((char *) value.ptr); + default: + PyErr_SetString(ErrorObject, "unknown element type"); + return NULL; + } +} + +static int +python2elem(PyObject *item, void *ptr, int elementType) +{ + switch (elementType) { + case AL_INT32_ELEM: + case AL_RESOURCE_ELEM: + case AL_ENUM_ELEM: + if (!PyInt_Check(item)) { + PyErr_BadArgument(); + return -1; + } + *((int *) ptr) = PyInt_AsLong(item); + break; + case AL_INT64_ELEM: + if (PyInt_Check(item)) + *((long long *) ptr) = PyInt_AsLong(item); + else if (PyLong_Check(item)) + *((long long *) ptr) = PyLong_AsLongLong(item); + else { + PyErr_BadArgument(); + return -1; + } + break; + case AL_FIXED_ELEM: + if (PyInt_Check(item)) + *((long long *) ptr) = alDoubleToFixed((double) PyInt_AsLong(item)); + else if (PyFloat_Check(item)) + *((long long *) ptr) = alDoubleToFixed(PyFloat_AsDouble(item)); + else { + PyErr_BadArgument(); + return -1; + } + break; + default: + PyErr_SetString(ErrorObject, "unknown element type"); + return -1; + } + return 0; +} + +static int +python2param(int resource, ALpv *param, PyObject *value, ALparamInfo *pinfo) +{ + ALparamInfo info; + int i, stepsize; + PyObject *item; + + if (pinfo == NULL) { + pinfo = &info; + if (alGetParamInfo(resource, param->param, &info) < 0) + return -1; + } + switch (pinfo->valueType) { + case AL_STRING_VAL: + if (pinfo->elementType != AL_CHAR_ELEM) { + PyErr_SetString(ErrorObject, "unknown element type"); + return -1; + } + if (!PyString_Check(value)) { + PyErr_BadArgument(); + return -1; + } + param->value.ptr = PyString_AS_STRING(value); + param->sizeIn = PyString_GET_SIZE(value)+1; /*account for NUL*/ + break; + case AL_SET_VAL: + case AL_VECTOR_VAL: + if (!PyList_Check(value) && !PyTuple_Check(value)) { + PyErr_BadArgument(); + return -1; + } + switch (pinfo->elementType) { + case AL_INT32_ELEM: + case AL_RESOURCE_ELEM: + case AL_ENUM_ELEM: + param->sizeIn = PySequence_Size(value); + param->value.ptr = PyMem_NEW(int, param->sizeIn); + stepsize = sizeof(int); + break; + case AL_INT64_ELEM: + case AL_FIXED_ELEM: + param->sizeIn = PySequence_Size(value); + param->value.ptr = PyMem_NEW(long long, param->sizeIn); + stepsize = sizeof(long long); + break; + } + for (i = 0; i < param->sizeIn; i++) { + item = PySequence_GetItem(value, i); + if (python2elem(item, (void *) ((char *) param->value.ptr + i*stepsize), pinfo->elementType) < 0) { + PyMem_DEL(param->value.ptr); + return -1; + } + } + break; + case AL_SCALAR_VAL: + switch (pinfo->elementType) { + case AL_INT32_ELEM: + case AL_RESOURCE_ELEM: + case AL_ENUM_ELEM: + return python2elem(value, (void *) &param->value.i, + pinfo->elementType); + case AL_INT64_ELEM: + case AL_FIXED_ELEM: + return python2elem(value, (void *) &param->value.ll, + pinfo->elementType); + default: + PyErr_SetString(ErrorObject, "unknown element type"); + return -1; + } + } + return 0; +} + +static int +python2params(int resource1, int resource2, PyObject *list, ALpv **pvsp, ALparamInfo **pinfop) +{ + PyObject *item; + ALpv *pvs; + ALparamInfo *pinfo; + int npvs, i; + + npvs = PyList_Size(list); + pvs = PyMem_NEW(ALpv, npvs); + pinfo = PyMem_NEW(ALparamInfo, npvs); + for (i = 0; i < npvs; i++) { + item = PyList_GetItem(list, i); + if (!PyArg_ParseTuple(item, "iO", &pvs[i].param, &item)) + goto error; + if (alGetParamInfo(resource1, pvs[i].param, &pinfo[i]) < 0 && + alGetParamInfo(resource2, pvs[i].param, &pinfo[i]) < 0) + goto error; + if (python2param(resource1, &pvs[i], item, &pinfo[i]) < 0) + goto error; + } + + *pvsp = pvs; + *pinfop = pinfo; + return npvs; + + error: + /* XXXX we should clean up everything */ + if (pvs) + PyMem_DEL(pvs); + if (pinfo) + PyMem_DEL(pinfo); + return -1; +} + +/* -------------------------------------------------------- */ + + +static PyObject * +SetConfig(alcobject *self, PyObject *args, int (*func)(ALconfig, int)) +{ + int par; + + if (!PyArg_ParseTuple(args, "i:SetConfig", &par)) + return NULL; + + if ((*func)(self->config, par) == -1) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +GetConfig(alcobject *self, PyObject *args, int (*func)(ALconfig)) +{ + int par; + + if (!PyArg_ParseTuple(args, ":GetConfig")) + return NULL; + + if ((par = (*func)(self->config)) == -1) + return NULL; + + return PyInt_FromLong((long) par); +} + +PyDoc_STRVAR(alc_SetWidth__doc__, +"alSetWidth: set the wordsize for integer audio data."); + +static PyObject * +alc_SetWidth(alcobject *self, PyObject *args) +{ + return SetConfig(self, args, alSetWidth); +} + + +PyDoc_STRVAR(alc_GetWidth__doc__, +"alGetWidth: get the wordsize for integer audio data."); + +static PyObject * +alc_GetWidth(alcobject *self, PyObject *args) +{ + return GetConfig(self, args, alGetWidth); +} + + +PyDoc_STRVAR(alc_SetSampFmt__doc__, +"alSetSampFmt: set the sample format setting in an audio ALconfig " +"structure."); + +static PyObject * +alc_SetSampFmt(alcobject *self, PyObject *args) +{ + return SetConfig(self, args, alSetSampFmt); +} + + +PyDoc_STRVAR(alc_GetSampFmt__doc__, +"alGetSampFmt: get the sample format setting in an audio ALconfig " +"structure."); + +static PyObject * +alc_GetSampFmt(alcobject *self, PyObject *args) +{ + return GetConfig(self, args, alGetSampFmt); +} + + +PyDoc_STRVAR(alc_SetChannels__doc__, +"alSetChannels: set the channel settings in an audio ALconfig."); + +static PyObject * +alc_SetChannels(alcobject *self, PyObject *args) +{ + return SetConfig(self, args, alSetChannels); +} + + +PyDoc_STRVAR(alc_GetChannels__doc__, +"alGetChannels: get the channel settings in an audio ALconfig."); + +static PyObject * +alc_GetChannels(alcobject *self, PyObject *args) +{ + return GetConfig(self, args, alGetChannels); +} + + +PyDoc_STRVAR(alc_SetFloatMax__doc__, +"alSetFloatMax: set the maximum value of floating point sample data."); + +static PyObject * +alc_SetFloatMax(alcobject *self, PyObject *args) +{ + double maximum_value; + + if (!PyArg_ParseTuple(args, "d:SetFloatMax", &maximum_value)) + return NULL; + if (alSetFloatMax(self->config, maximum_value) < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + + +PyDoc_STRVAR(alc_GetFloatMax__doc__, +"alGetFloatMax: get the maximum value of floating point sample data."); + +static PyObject * +alc_GetFloatMax(alcobject *self, PyObject *args) +{ + double maximum_value; + + if (!PyArg_ParseTuple(args, ":GetFloatMax")) + return NULL; + if ((maximum_value = alGetFloatMax(self->config)) == 0) + return NULL; + return PyFloat_FromDouble(maximum_value); +} + + +PyDoc_STRVAR(alc_SetDevice__doc__, +"alSetDevice: set the device setting in an audio ALconfig structure."); + +static PyObject * +alc_SetDevice(alcobject *self, PyObject *args) +{ + return SetConfig(self, args, alSetDevice); +} + + +PyDoc_STRVAR(alc_GetDevice__doc__, +"alGetDevice: get the device setting in an audio ALconfig structure."); + +static PyObject * +alc_GetDevice(alcobject *self, PyObject *args) +{ + return GetConfig(self, args, alGetDevice); +} + + +PyDoc_STRVAR(alc_SetQueueSize__doc__, +"alSetQueueSize: set audio port buffer size."); + +static PyObject * +alc_SetQueueSize(alcobject *self, PyObject *args) +{ + return SetConfig(self, args, alSetQueueSize); +} + + +PyDoc_STRVAR(alc_GetQueueSize__doc__, +"alGetQueueSize: get audio port buffer size."); + +static PyObject * +alc_GetQueueSize(alcobject *self, PyObject *args) +{ + return GetConfig(self, args, alGetQueueSize); +} + +#endif /* AL_NO_ELEM */ + +static PyObject * +setconfig(alcobject *self, PyObject *args, int (*func)(ALconfig, long)) +{ + long par; + + if (!PyArg_ParseTuple(args, "l:SetConfig", &par)) + return NULL; + + if ((*func)(self->config, par) == -1) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +getconfig(alcobject *self, PyObject *args, long (*func)(ALconfig)) +{ + long par; + + if (!PyArg_ParseTuple(args, ":GetConfig")) + return NULL; + + if ((par = (*func)(self->config)) == -1) + return NULL; + + return PyInt_FromLong((long) par); +} + +static PyObject * +alc_setqueuesize (alcobject *self, PyObject *args) +{ + return setconfig(self, args, ALsetqueuesize); +} + +static PyObject * +alc_getqueuesize (alcobject *self, PyObject *args) +{ + return getconfig(self, args, ALgetqueuesize); +} + +static PyObject * +alc_setwidth (alcobject *self, PyObject *args) +{ + return setconfig(self, args, ALsetwidth); +} + +static PyObject * +alc_getwidth (alcobject *self, PyObject *args) +{ + return getconfig(self, args, ALgetwidth); +} + +static PyObject * +alc_getchannels (alcobject *self, PyObject *args) +{ + return getconfig(self, args, ALgetchannels); +} + +static PyObject * +alc_setchannels (alcobject *self, PyObject *args) +{ + return setconfig(self, args, ALsetchannels); +} + +#ifdef AL_405 + +static PyObject * +alc_getsampfmt (alcobject *self, PyObject *args) +{ + return getconfig(self, args, ALgetsampfmt); +} + +static PyObject * +alc_setsampfmt (alcobject *self, PyObject *args) +{ + return setconfig(self, args, ALsetsampfmt); +} + +static PyObject * +alc_getfloatmax(alcobject *self, PyObject *args) +{ + double arg; + + if (!PyArg_ParseTuple(args, ":GetFloatMax")) + return 0; + if ((arg = ALgetfloatmax(self->config)) == 0) + return NULL; + return PyFloat_FromDouble(arg); +} + +static PyObject * +alc_setfloatmax(alcobject *self, PyObject *args) +{ + double arg; + + if (!PyArg_ParseTuple(args, "d:SetFloatMax", &arg)) + return 0; + if (ALsetfloatmax(self->config, arg) == -1) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} +#endif /* AL_405 */ + +static struct PyMethodDef alc_methods[] = { +#ifdef AL_NO_ELEM /* IRIX 6 */ + {"SetWidth", (PyCFunction)alc_SetWidth, METH_VARARGS, alc_SetWidth__doc__}, + {"GetWidth", (PyCFunction)alc_GetWidth, METH_VARARGS, alc_GetWidth__doc__}, + {"SetSampFmt", (PyCFunction)alc_SetSampFmt, METH_VARARGS, alc_SetSampFmt__doc__}, + {"GetSampFmt", (PyCFunction)alc_GetSampFmt, METH_VARARGS, alc_GetSampFmt__doc__}, + {"SetChannels", (PyCFunction)alc_SetChannels, METH_VARARGS, alc_SetChannels__doc__}, + {"GetChannels", (PyCFunction)alc_GetChannels, METH_VARARGS, alc_GetChannels__doc__}, + {"SetFloatMax", (PyCFunction)alc_SetFloatMax, METH_VARARGS, alc_SetFloatMax__doc__}, + {"GetFloatMax", (PyCFunction)alc_GetFloatMax, METH_VARARGS, alc_GetFloatMax__doc__}, + {"SetDevice", (PyCFunction)alc_SetDevice, METH_VARARGS, alc_SetDevice__doc__}, + {"GetDevice", (PyCFunction)alc_GetDevice, METH_VARARGS, alc_GetDevice__doc__}, + {"SetQueueSize", (PyCFunction)alc_SetQueueSize, METH_VARARGS, alc_SetQueueSize__doc__}, + {"GetQueueSize", (PyCFunction)alc_GetQueueSize, METH_VARARGS, alc_GetQueueSize__doc__}, +#endif /* AL_NO_ELEM */ + {"getqueuesize", (PyCFunction)alc_getqueuesize, METH_VARARGS}, + {"setqueuesize", (PyCFunction)alc_setqueuesize, METH_VARARGS}, + {"getwidth", (PyCFunction)alc_getwidth, METH_VARARGS}, + {"setwidth", (PyCFunction)alc_setwidth, METH_VARARGS}, + {"getchannels", (PyCFunction)alc_getchannels, METH_VARARGS}, + {"setchannels", (PyCFunction)alc_setchannels, METH_VARARGS}, +#ifdef AL_405 + {"getsampfmt", (PyCFunction)alc_getsampfmt, METH_VARARGS}, + {"setsampfmt", (PyCFunction)alc_setsampfmt, METH_VARARGS}, + {"getfloatmax", (PyCFunction)alc_getfloatmax, METH_VARARGS}, + {"setfloatmax", (PyCFunction)alc_setfloatmax, METH_VARARGS}, +#endif /* AL_405 */ + + {NULL, NULL} /* sentinel */ +}; + +/* ---------- */ + + +static PyObject * +newalcobject(ALconfig config) +{ + alcobject *self; + + self = PyObject_New(alcobject, &Alctype); + if (self == NULL) + return NULL; + /* XXXX Add your own initializers here */ + self->config = config; + return (PyObject *) self; +} + + +static void +alc_dealloc(alcobject *self) +{ + /* XXXX Add your own cleanup code here */ +#ifdef AL_NO_ELEM /* IRIX 6 */ + (void) alFreeConfig(self->config); /* ignore errors */ +#else + (void) ALfreeconfig(self->config); /* ignore errors */ +#endif + PyObject_Del(self); +} + +static PyObject * +alc_getattr(alcobject *self, char *name) +{ + /* XXXX Add your own getattr code here */ + return Py_FindMethod(alc_methods, (PyObject *)self, name); +} + +PyDoc_STRVAR(Alctype__doc__, ""); + +static PyTypeObject Alctype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "al.config", /*tp_name*/ + sizeof(alcobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)alc_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)alc_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + + /* Space for future expansion */ + 0L,0L,0L,0L, + Alctype__doc__ /* Documentation string */ +}; + +/* End of code for config objects */ +/* ---------------------------------------------------------------- */ + +#ifdef AL_NO_ELEM /* IRIX 6 */ + +PyDoc_STRVAR(alp_SetConfig__doc__, +"alSetConfig: set the ALconfig of an audio ALport."); + +static PyObject * +alp_SetConfig(alpobject *self, PyObject *args) +{ + alcobject *config; + if (!PyArg_ParseTuple(args, "O!:SetConfig", &Alctype, &config)) + return NULL; + if (alSetConfig(self->port, config->config) < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + + +PyDoc_STRVAR(alp_GetConfig__doc__, +"alGetConfig: get the ALconfig of an audio ALport."); + +static PyObject * +alp_GetConfig(alpobject *self, PyObject *args) +{ + ALconfig config; + if (!PyArg_ParseTuple(args, ":GetConfig")) + return NULL; + if ((config = alGetConfig(self->port)) == NULL) + return NULL; + return newalcobject(config); +} + + +PyDoc_STRVAR(alp_GetResource__doc__, +"alGetResource: get the resource associated with an audio port."); + +static PyObject * +alp_GetResource(alpobject *self, PyObject *args) +{ + int resource; + + if (!PyArg_ParseTuple(args, ":GetResource")) + return NULL; + if ((resource = alGetResource(self->port)) == 0) + return NULL; + return PyInt_FromLong((long) resource); +} + + +PyDoc_STRVAR(alp_GetFD__doc__, +"alGetFD: get the file descriptor for an audio port."); + +static PyObject * +alp_GetFD(alpobject *self, PyObject *args) +{ + int fd; + + if (!PyArg_ParseTuple(args, ":GetFD")) + return NULL; + + if ((fd = alGetFD(self->port)) < 0) + return NULL; + + return PyInt_FromLong((long) fd); +} + + +PyDoc_STRVAR(alp_GetFilled__doc__, +"alGetFilled: return the number of filled sample frames in " +"an audio port."); + +static PyObject * +alp_GetFilled(alpobject *self, PyObject *args) +{ + int filled; + + if (!PyArg_ParseTuple(args, ":GetFilled")) + return NULL; + if ((filled = alGetFilled(self->port)) < 0) + return NULL; + return PyInt_FromLong((long) filled); +} + + +PyDoc_STRVAR(alp_GetFillable__doc__, +"alGetFillable: report the number of unfilled sample frames " +"in an audio port."); + +static PyObject * +alp_GetFillable(alpobject *self, PyObject *args) +{ + int fillable; + + if (!PyArg_ParseTuple(args, ":GetFillable")) + return NULL; + if ((fillable = alGetFillable(self->port)) < 0) + return NULL; + return PyInt_FromLong((long) fillable); +} + + +PyDoc_STRVAR(alp_ReadFrames__doc__, +"alReadFrames: read sample frames from an audio port."); + +static PyObject * +alp_ReadFrames(alpobject *self, PyObject *args) +{ + int framecount; + PyObject *v; + int size; + int ch; + ALconfig c; + + if (!PyArg_ParseTuple(args, "i:ReadFrames", &framecount)) + return NULL; + if (framecount < 0) { + PyErr_SetString(ErrorObject, "negative framecount"); + return NULL; + } + c = alGetConfig(self->port); + switch (alGetSampFmt(c)) { + case AL_SAMPFMT_TWOSCOMP: + switch (alGetWidth(c)) { + case AL_SAMPLE_8: + size = 1; + break; + case AL_SAMPLE_16: + size = 2; + break; + case AL_SAMPLE_24: + size = 4; + break; + default: + PyErr_SetString(ErrorObject, "can't determine width"); + alFreeConfig(c); + return NULL; + } + break; + case AL_SAMPFMT_FLOAT: + size = 4; + break; + case AL_SAMPFMT_DOUBLE: + size = 8; + break; + default: + PyErr_SetString(ErrorObject, "can't determine format"); + alFreeConfig(c); + return NULL; + } + ch = alGetChannels(c); + alFreeConfig(c); + if (ch < 0) { + PyErr_SetString(ErrorObject, "can't determine # of channels"); + return NULL; + } + size *= ch; + v = PyString_FromStringAndSize((char *) NULL, size * framecount); + if (v == NULL) + return NULL; + + Py_BEGIN_ALLOW_THREADS + alReadFrames(self->port, (void *) PyString_AS_STRING(v), framecount); + Py_END_ALLOW_THREADS + + return v; +} + + +PyDoc_STRVAR(alp_DiscardFrames__doc__, +"alDiscardFrames: discard audio from an audio port."); + +static PyObject * +alp_DiscardFrames(alpobject *self, PyObject *args) +{ + int framecount; + + if (!PyArg_ParseTuple(args, "i:DiscardFrames", &framecount)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + framecount = alDiscardFrames(self->port, framecount); + Py_END_ALLOW_THREADS + + if (framecount < 0) + return NULL; + + return PyInt_FromLong((long) framecount); +} + + +PyDoc_STRVAR(alp_ZeroFrames__doc__, +"alZeroFrames: write zero-valued sample frames to an audio port."); + +static PyObject * +alp_ZeroFrames(alpobject *self, PyObject *args) +{ + int framecount; + + if (!PyArg_ParseTuple(args, "i:ZeroFrames", &framecount)) + return NULL; + + if (framecount < 0) { + PyErr_SetString(ErrorObject, "negative framecount"); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + alZeroFrames(self->port, framecount); + Py_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return Py_None; +} + + +PyDoc_STRVAR(alp_SetFillPoint__doc__, +"alSetFillPoint: set low- or high-water mark for an audio port."); + +static PyObject * +alp_SetFillPoint(alpobject *self, PyObject *args) +{ + int fillpoint; + + if (!PyArg_ParseTuple(args, "i:SetFillPoint", &fillpoint)) + return NULL; + + if (alSetFillPoint(self->port, fillpoint) < 0) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + + +PyDoc_STRVAR(alp_GetFillPoint__doc__, +"alGetFillPoint: get low- or high-water mark for an audio port."); + +static PyObject * +alp_GetFillPoint(alpobject *self, PyObject *args) +{ + int fillpoint; + + if (!PyArg_ParseTuple(args, ":GetFillPoint")) + return NULL; + + if ((fillpoint = alGetFillPoint(self->port)) < 0) + return NULL; + + return PyInt_FromLong((long) fillpoint); +} + + +PyDoc_STRVAR(alp_GetFrameNumber__doc__, +"alGetFrameNumber: get the absolute sample frame number " +"associated with a port."); + +static PyObject * +alp_GetFrameNumber(alpobject *self, PyObject *args) +{ + stamp_t fnum; + + if (!PyArg_ParseTuple(args, ":GetFrameNumber")) + return NULL; + + if (alGetFrameNumber(self->port, &fnum) < 0) + return NULL; + + return PyLong_FromLongLong((long long) fnum); +} + + +PyDoc_STRVAR(alp_GetFrameTime__doc__, +"alGetFrameTime: get the time at which a sample frame came " +"in or will go out."); + +static PyObject * +alp_GetFrameTime(alpobject *self, PyObject *args) +{ + stamp_t fnum, time; + PyObject *ret, *v0, *v1; + + if (!PyArg_ParseTuple(args, ":GetFrameTime")) + return NULL; + if (alGetFrameTime(self->port, &fnum, &time) < 0) + return NULL; + v0 = PyLong_FromLongLong((long long) fnum); + v1 = PyLong_FromLongLong((long long) time); + if (PyErr_Occurred()) { + Py_XDECREF(v0); + Py_XDECREF(v1); + return NULL; + } + ret = PyTuple_Pack(2, v0, v1); + Py_DECREF(v0); + Py_DECREF(v1); + return ret; +} + + +PyDoc_STRVAR(alp_WriteFrames__doc__, +"alWriteFrames: write sample frames to an audio port."); + +static PyObject * +alp_WriteFrames(alpobject *self, PyObject *args) +{ + char *samples; + int length; + int size, ch; + ALconfig c; + + if (!PyArg_ParseTuple(args, "s#:WriteFrames", &samples, &length)) + return NULL; + c = alGetConfig(self->port); + switch (alGetSampFmt(c)) { + case AL_SAMPFMT_TWOSCOMP: + switch (alGetWidth(c)) { + case AL_SAMPLE_8: + size = 1; + break; + case AL_SAMPLE_16: + size = 2; + break; + case AL_SAMPLE_24: + size = 4; + break; + default: + PyErr_SetString(ErrorObject, "can't determine width"); + alFreeConfig(c); + return NULL; + } + break; + case AL_SAMPFMT_FLOAT: + size = 4; + break; + case AL_SAMPFMT_DOUBLE: + size = 8; + break; + default: + PyErr_SetString(ErrorObject, "can't determine format"); + alFreeConfig(c); + return NULL; + } + ch = alGetChannels(c); + alFreeConfig(c); + if (ch < 0) { + PyErr_SetString(ErrorObject, "can't determine # of channels"); + return NULL; + } + size *= ch; + if (length % size != 0) { + PyErr_SetString(ErrorObject, + "buffer length not whole number of frames"); + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + alWriteFrames(self->port, (void *) samples, length / size); + Py_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return Py_None; +} + + +PyDoc_STRVAR(alp_ClosePort__doc__, "alClosePort: close an audio port."); + +static PyObject * +alp_ClosePort(alpobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":ClosePort")) + return NULL; + if (alClosePort(self->port) < 0) + return NULL; + self->port = NULL; + Py_INCREF(Py_None); + return Py_None; +} + +#endif /* AL_NO_ELEM */ + +#ifdef OLD_INTERFACE +static PyObject * +alp_closeport(alpobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":ClosePort")) + return NULL; + if (ALcloseport(self->port) < 0) + return NULL; + self->port = NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +alp_getfd(alpobject *self, PyObject *args) +{ + int fd; + + if (!PyArg_ParseTuple(args, ":GetFD")) + return NULL; + if ((fd = ALgetfd(self-> port)) == -1) + return NULL; + return PyInt_FromLong(fd); +} + +static PyObject * +alp_getfilled(alpobject *self, PyObject *args) +{ + long count; + + if (!PyArg_ParseTuple(args, ":GetFilled")) + return NULL; + if ((count = ALgetfilled(self-> port)) == -1) + return NULL; + return PyInt_FromLong(count); +} + +static PyObject * +alp_getfillable(alpobject *self, PyObject *args) +{ + long count; + + if (!PyArg_ParseTuple(args, ":GetFillable")) + return NULL; + if ((count = ALgetfillable(self-> port)) == -1) + return NULL; + return PyInt_FromLong (count); +} + +static PyObject * +alp_readsamps(alpobject *self, PyObject *args) +{ + long count; + PyObject *v; + ALconfig c; + int width; + int ret; + + if (!PyArg_ParseTuple(args, "l:readsamps", &count)) + return NULL; + + if (count <= 0) { + PyErr_SetString(ErrorObject, "al.readsamps : arg <= 0"); + return NULL; + } + + c = ALgetconfig(self->port); +#ifdef AL_405 + width = ALgetsampfmt(c); + if (width == AL_SAMPFMT_FLOAT) + width = sizeof(float); + else if (width == AL_SAMPFMT_DOUBLE) + width = sizeof(double); + else + width = ALgetwidth(c); +#else + width = ALgetwidth(c); +#endif /* AL_405 */ + ALfreeconfig(c); + v = PyString_FromStringAndSize((char *)NULL, width * count); + if (v == NULL) + return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = ALreadsamps(self->port, (void *) PyString_AsString(v), count); + Py_END_ALLOW_THREADS + if (ret == -1) { + Py_DECREF(v); + return NULL; + } + + return (v); +} + +static PyObject * +alp_writesamps(alpobject *self, PyObject *args) +{ + char *buf; + int size, width; + ALconfig c; + int ret; + + if (!PyArg_ParseTuple(args, "s#:writesamps", &buf, &size)) + return NULL; + + c = ALgetconfig(self->port); +#ifdef AL_405 + width = ALgetsampfmt(c); + if (width == AL_SAMPFMT_FLOAT) + width = sizeof(float); + else if (width == AL_SAMPFMT_DOUBLE) + width = sizeof(double); + else + width = ALgetwidth(c); +#else + width = ALgetwidth(c); +#endif /* AL_405 */ + ALfreeconfig(c); + Py_BEGIN_ALLOW_THREADS + ret = ALwritesamps (self->port, (void *) buf, (long) size / width); + Py_END_ALLOW_THREADS + if (ret == -1) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +alp_getfillpoint(alpobject *self, PyObject *args) +{ + long count; + + if (!PyArg_ParseTuple(args, ":GetFillPoint")) + return NULL; + if ((count = ALgetfillpoint(self->port)) == -1) + return NULL; + return PyInt_FromLong(count); +} + +static PyObject * +alp_setfillpoint(alpobject *self, PyObject *args) +{ + long count; + + if (!PyArg_ParseTuple(args, "l:SetFillPoint", &count)) + return NULL; + if (ALsetfillpoint(self->port, count) == -1) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +alp_setconfig(alpobject *self, PyObject *args) +{ + alcobject *config; + + if (!PyArg_ParseTuple(args, "O!:SetConfig", &Alctype, &config)) + return NULL; + if (ALsetconfig(self->port, config->config) == -1) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +alp_getconfig(alpobject *self, PyObject *args) +{ + ALconfig config; + + if (!PyArg_ParseTuple(args, ":GetConfig")) + return NULL; + config = ALgetconfig(self->port); + if (config == NULL) + return NULL; + return newalcobject(config); +} + +#ifdef AL_405 +static PyObject * +alp_getstatus(alpobject *self, PyObject *args) +{ + PyObject *list, *v; + long *PVbuffer; + long length; + int i; + + if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &list)) + return NULL; + length = PyList_Size(list); + PVbuffer = PyMem_NEW(long, length); + if (PVbuffer == NULL) + return PyErr_NoMemory(); + for (i = 0; i < length; i++) { + v = PyList_GetItem(list, i); + if (!PyInt_Check(v)) { + PyMem_DEL(PVbuffer); + PyErr_BadArgument(); + return NULL; + } + PVbuffer[i] = PyInt_AsLong(v); + } + + if (ALgetstatus(self->port, PVbuffer, length) == -1) + return NULL; + + for (i = 0; i < length; i++) + PyList_SetItem(list, i, PyInt_FromLong(PVbuffer[i])); + + PyMem_DEL(PVbuffer); + + Py_INCREF(Py_None); + return Py_None; +} +#endif /* AL_405 */ + +#endif /* OLD_INTERFACE */ + +static struct PyMethodDef alp_methods[] = { +#ifdef AL_NO_ELEM /* IRIX 6 */ + {"SetConfig", (PyCFunction)alp_SetConfig, METH_VARARGS, alp_SetConfig__doc__}, + {"GetConfig", (PyCFunction)alp_GetConfig, METH_VARARGS, alp_GetConfig__doc__}, + {"GetResource", (PyCFunction)alp_GetResource, METH_VARARGS, alp_GetResource__doc__}, + {"GetFD", (PyCFunction)alp_GetFD, METH_VARARGS, alp_GetFD__doc__}, + {"GetFilled", (PyCFunction)alp_GetFilled, METH_VARARGS, alp_GetFilled__doc__}, + {"GetFillable", (PyCFunction)alp_GetFillable, METH_VARARGS, alp_GetFillable__doc__}, + {"ReadFrames", (PyCFunction)alp_ReadFrames, METH_VARARGS, alp_ReadFrames__doc__}, + {"DiscardFrames", (PyCFunction)alp_DiscardFrames, METH_VARARGS, alp_DiscardFrames__doc__}, + {"ZeroFrames", (PyCFunction)alp_ZeroFrames, METH_VARARGS, alp_ZeroFrames__doc__}, + {"SetFillPoint", (PyCFunction)alp_SetFillPoint, METH_VARARGS, alp_SetFillPoint__doc__}, + {"GetFillPoint", (PyCFunction)alp_GetFillPoint, METH_VARARGS, alp_GetFillPoint__doc__}, + {"GetFrameNumber", (PyCFunction)alp_GetFrameNumber, METH_VARARGS, alp_GetFrameNumber__doc__}, + {"GetFrameTime", (PyCFunction)alp_GetFrameTime, METH_VARARGS, alp_GetFrameTime__doc__}, + {"WriteFrames", (PyCFunction)alp_WriteFrames, METH_VARARGS, alp_WriteFrames__doc__}, + {"ClosePort", (PyCFunction)alp_ClosePort, METH_VARARGS, alp_ClosePort__doc__}, +#endif /* AL_NO_ELEM */ +#ifdef OLD_INTERFACE + {"closeport", (PyCFunction)alp_closeport, METH_VARARGS}, + {"getfd", (PyCFunction)alp_getfd, METH_VARARGS}, + {"fileno", (PyCFunction)alp_getfd, METH_VARARGS}, + {"getfilled", (PyCFunction)alp_getfilled, METH_VARARGS}, + {"getfillable", (PyCFunction)alp_getfillable, METH_VARARGS}, + {"readsamps", (PyCFunction)alp_readsamps, METH_VARARGS}, + {"writesamps", (PyCFunction)alp_writesamps, METH_VARARGS}, + {"setfillpoint", (PyCFunction)alp_setfillpoint, METH_VARARGS}, + {"getfillpoint", (PyCFunction)alp_getfillpoint, METH_VARARGS}, + {"setconfig", (PyCFunction)alp_setconfig, METH_VARARGS}, + {"getconfig", (PyCFunction)alp_getconfig, METH_VARARGS}, +#ifdef AL_405 + {"getstatus", (PyCFunction)alp_getstatus, METH_VARARGS}, +#endif /* AL_405 */ +#endif /* OLD_INTERFACE */ + + {NULL, NULL} /* sentinel */ +}; + +/* ---------- */ + + +static PyObject * +newalpobject(ALport port) +{ + alpobject *self; + + self = PyObject_New(alpobject, &Alptype); + if (self == NULL) + return NULL; + /* XXXX Add your own initializers here */ + self->port = port; + return (PyObject *) self; +} + + +static void +alp_dealloc(alpobject *self) +{ + /* XXXX Add your own cleanup code here */ + if (self->port) { +#ifdef AL_NO_ELEM /* IRIX 6 */ + alClosePort(self->port); +#else + ALcloseport(self->port); +#endif + } + PyObject_Del(self); +} + +static PyObject * +alp_getattr(alpobject *self, char *name) +{ + /* XXXX Add your own getattr code here */ + if (self->port == NULL) { + PyErr_SetString(ErrorObject, "port already closed"); + return NULL; + } + return Py_FindMethod(alp_methods, (PyObject *)self, name); +} + +PyDoc_STRVAR(Alptype__doc__, ""); + +static PyTypeObject Alptype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "al.port", /*tp_name*/ + sizeof(alpobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)alp_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)alp_getattr, /*tp_getattr*/ + (setattrfunc)0, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + + /* Space for future expansion */ + 0L,0L,0L,0L, + Alptype__doc__ /* Documentation string */ +}; + +/* End of code for port objects */ +/* -------------------------------------------------------- */ + + +#ifdef AL_NO_ELEM /* IRIX 6 */ + +PyDoc_STRVAR(al_NewConfig__doc__, +"alNewConfig: create and initialize an audio ALconfig structure."); + +static PyObject * +al_NewConfig(PyObject *self, PyObject *args) +{ + ALconfig config; + + if (!PyArg_ParseTuple(args, ":NewConfig")) + return NULL; + if ((config = alNewConfig()) == NULL) + return NULL; + return newalcobject(config); +} + +PyDoc_STRVAR(al_OpenPort__doc__, +"alOpenPort: open an audio port."); + +static PyObject * +al_OpenPort(PyObject *self, PyObject *args) +{ + ALport port; + char *name, *dir; + alcobject *config = NULL; + + if (!PyArg_ParseTuple(args, "ss|O!:OpenPort", &name, &dir, &Alctype, &config)) + return NULL; + if ((port = alOpenPort(name, dir, config ? config->config : NULL)) == NULL) + return NULL; + return newalpobject(port); +} + +PyDoc_STRVAR(al_Connect__doc__, +"alConnect: connect two audio I/O resources."); + +static PyObject * +al_Connect(PyObject *self, PyObject *args) +{ + int source, dest, nprops = 0, id, i; + ALpv *props = NULL; + ALparamInfo *propinfo = NULL; + PyObject *propobj = NULL; + + if (!PyArg_ParseTuple(args, "ii|O!:Connect", &source, &dest, &PyList_Type, &propobj)) + return NULL; + if (propobj != NULL) { + nprops = python2params(source, dest, propobj, &props, &propinfo); + if (nprops < 0) + return NULL; + } + + id = alConnect(source, dest, props, nprops); + + if (props) { + for (i = 0; i < nprops; i++) { + switch (propinfo[i].valueType) { + case AL_SET_VAL: + case AL_VECTOR_VAL: + PyMem_DEL(props[i].value.ptr); + break; + } + } + PyMem_DEL(props); + PyMem_DEL(propinfo); + } + + if (id < 0) + return NULL; + return PyInt_FromLong((long) id); +} + +PyDoc_STRVAR(al_Disconnect__doc__, +"alDisconnect: delete a connection between two audio I/O resources."); + +static PyObject * +al_Disconnect(PyObject *self, PyObject *args) +{ + int res; + + if (!PyArg_ParseTuple(args, "i:Disconnect", &res)) + return NULL; + if (alDisconnect(res) < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(al_GetParams__doc__, +"alGetParams: get the values of audio resource parameters."); + +static PyObject * +al_GetParams(PyObject *self, PyObject *args) +{ + int resource; + PyObject *pvslist, *item = NULL, *v = NULL; + ALpv *pvs; + int i, j, npvs; + ALparamInfo *pinfo; + + if (!PyArg_ParseTuple(args, "iO!:GetParams", &resource, &PyList_Type, &pvslist)) + return NULL; + npvs = PyList_Size(pvslist); + pvs = PyMem_NEW(ALpv, npvs); + pinfo = PyMem_NEW(ALparamInfo, npvs); + for (i = 0; i < npvs; i++) { + item = PyList_GetItem(pvslist, i); + if (!PyInt_Check(item)) { + item = NULL; + PyErr_SetString(ErrorObject, "list of integers expected"); + goto error; + } + pvs[i].param = (int) PyInt_AsLong(item); + item = NULL; /* not needed anymore */ + if (alGetParamInfo(resource, pvs[i].param, &pinfo[i]) < 0) + goto error; + switch (pinfo[i].valueType) { + case AL_NO_VAL: + break; + case AL_MATRIX_VAL: + pinfo[i].maxElems *= pinfo[i].maxElems2; + /* fall through */ + case AL_STRING_VAL: + case AL_SET_VAL: + case AL_VECTOR_VAL: + switch (pinfo[i].elementType) { + case AL_INT32_ELEM: + case AL_RESOURCE_ELEM: + case AL_ENUM_ELEM: + pvs[i].value.ptr = PyMem_NEW(int, pinfo[i].maxElems); + pvs[i].sizeIn = pinfo[i].maxElems; + break; + case AL_INT64_ELEM: + case AL_FIXED_ELEM: + pvs[i].value.ptr = PyMem_NEW(long long, pinfo[i].maxElems); + pvs[i].sizeIn = pinfo[i].maxElems; + break; + case AL_CHAR_ELEM: + pvs[i].value.ptr = PyMem_NEW(char, 32); + pvs[i].sizeIn = 32; + break; + case AL_NO_ELEM: + case AL_PTR_ELEM: + default: + PyErr_SetString(ErrorObject, "internal error"); + goto error; + } + break; + case AL_SCALAR_VAL: + break; + default: + PyErr_SetString(ErrorObject, "internal error"); + goto error; + } + if (pinfo[i].valueType == AL_MATRIX_VAL) { + pinfo[i].maxElems /= pinfo[i].maxElems2; + pvs[i].sizeIn /= pinfo[i].maxElems2; + pvs[i].size2In = pinfo[i].maxElems2; + } + } + if (alGetParams(resource, pvs, npvs) < 0) + goto error; + if (!(v = PyList_New(npvs))) + goto error; + for (i = 0; i < npvs; i++) { + if (pvs[i].sizeOut < 0) { + char buf[32]; + PyOS_snprintf(buf, sizeof(buf), + "problem with param %d", i); + PyErr_SetString(ErrorObject, buf); + goto error; + } + switch (pinfo[i].valueType) { + case AL_NO_VAL: + item = Py_None; + Py_INCREF(item); + break; + case AL_STRING_VAL: + item = PyString_FromString(pvs[i].value.ptr); + PyMem_DEL(pvs[i].value.ptr); + break; + case AL_MATRIX_VAL: + /* XXXX this is not right */ + pvs[i].sizeOut *= pvs[i].size2Out; + /* fall through */ + case AL_SET_VAL: + case AL_VECTOR_VAL: + item = PyList_New(pvs[i].sizeOut); + for (j = 0; j < pvs[i].sizeOut; j++) { + switch (pinfo[i].elementType) { + case AL_INT32_ELEM: + case AL_RESOURCE_ELEM: + case AL_ENUM_ELEM: + PyList_SetItem(item, j, PyInt_FromLong((long) ((int *) pvs[i].value.ptr)[j])); + break; + case AL_INT64_ELEM: + PyList_SetItem(item, j, PyLong_FromLongLong(((long long *) pvs[i].value.ptr)[j])); + break; + case AL_FIXED_ELEM: + PyList_SetItem(item, j, PyFloat_FromDouble(alFixedToDouble(((long long *) pvs[i].value.ptr)[j]))); + break; + default: + PyErr_SetString(ErrorObject, "internal error"); + goto error; + } + } + PyMem_DEL(pvs[i].value.ptr); + break; + case AL_SCALAR_VAL: + item = param2python(resource, pvs[i].param, pvs[i].value, &pinfo[i]); + break; + } + if (PyErr_Occurred() || + PyList_SetItem(v, i, Py_BuildValue("(iO)", pvs[i].param, + item)) < 0 || + PyErr_Occurred()) + goto error; + Py_DECREF(item); + } + PyMem_DEL(pvs); + PyMem_DEL(pinfo); + return v; + + error: + Py_XDECREF(v); + Py_XDECREF(item); + if (pvs) + PyMem_DEL(pvs); + if (pinfo) + PyMem_DEL(pinfo); + return NULL; +} + +PyDoc_STRVAR(al_SetParams__doc__, +"alSetParams: set the values of audio resource parameters."); + +static PyObject * +al_SetParams(PyObject *self, PyObject *args) +{ + int resource; + PyObject *pvslist; + ALpv *pvs; + ALparamInfo *pinfo; + int npvs, i; + + if (!PyArg_ParseTuple(args, "iO!:SetParams", &resource, &PyList_Type, &pvslist)) + return NULL; + npvs = python2params(resource, -1, pvslist, &pvs, &pinfo); + if (npvs < 0) + return NULL; + + if (alSetParams(resource, pvs, npvs) < 0) + goto error; + + /* cleanup */ + for (i = 0; i < npvs; i++) { + switch (pinfo[i].valueType) { + case AL_SET_VAL: + case AL_VECTOR_VAL: + PyMem_DEL(pvs[i].value.ptr); + break; + } + } + PyMem_DEL(pvs); + PyMem_DEL(pinfo); + + Py_INCREF(Py_None); + return Py_None; + + error: + /* XXXX we should clean up everything */ + if (pvs) + PyMem_DEL(pvs); + if (pinfo) + PyMem_DEL(pinfo); + return NULL; +} + +PyDoc_STRVAR(al_QueryValues__doc__, +"alQueryValues: get the set of possible values for a parameter."); + +static PyObject * +al_QueryValues(PyObject *self, PyObject *args) +{ + int resource, param; + ALvalue *return_set = NULL; + int setsize = 32, qualsize = 0, nvals, i; + ALpv *quals = NULL; + ALparamInfo pinfo; + ALparamInfo *qualinfo = NULL; + PyObject *qualobj = NULL; + PyObject *res = NULL, *item; + + if (!PyArg_ParseTuple(args, "ii|O!:QueryValues", &resource, &param, + &PyList_Type, &qualobj)) + return NULL; + if (qualobj != NULL) { + qualsize = python2params(resource, param, qualobj, &quals, &qualinfo); + if (qualsize < 0) + return NULL; + } + setsize = 32; + return_set = PyMem_NEW(ALvalue, setsize); + if (return_set == NULL) { + PyErr_NoMemory(); + goto cleanup; + } + + retry: + nvals = alQueryValues(resource, param, return_set, setsize, quals, qualsize); + if (nvals < 0) + goto cleanup; + if (nvals > setsize) { + setsize = nvals; + PyMem_RESIZE(return_set, ALvalue, setsize); + if (return_set == NULL) { + PyErr_NoMemory(); + goto cleanup; + } + goto retry; + } + + if (alGetParamInfo(resource, param, &pinfo) < 0) + goto cleanup; + + res = PyList_New(nvals); + if (res == NULL) + goto cleanup; + for (i = 0; i < nvals; i++) { + item = param2python(resource, param, return_set[i], &pinfo); + if (item == NULL || + PyList_SetItem(res, i, item) < 0) { + Py_DECREF(res); + res = NULL; + goto cleanup; + } + } + + cleanup: + if (return_set) + PyMem_DEL(return_set); + if (quals) { + for (i = 0; i < qualsize; i++) { + switch (qualinfo[i].valueType) { + case AL_SET_VAL: + case AL_VECTOR_VAL: + PyMem_DEL(quals[i].value.ptr); + break; + } + } + PyMem_DEL(quals); + PyMem_DEL(qualinfo); + } + + return res; +} + +PyDoc_STRVAR(al_GetParamInfo__doc__, +"alGetParamInfo: get information about a parameter on " +"a particular audio resource."); + +static PyObject * +al_GetParamInfo(PyObject *self, PyObject *args) +{ + int res, param; + ALparamInfo pinfo; + PyObject *v, *item; + + if (!PyArg_ParseTuple(args, "ii:GetParamInfo", &res, &param)) + return NULL; + if (alGetParamInfo(res, param, &pinfo) < 0) + return NULL; + v = PyDict_New(); + if (!v) return NULL; + + item = PyInt_FromLong((long) pinfo.resource); + PyDict_SetItemString(v, "resource", item); + Py_DECREF(item); + + item = PyInt_FromLong((long) pinfo.param); + PyDict_SetItemString(v, "param", item); + Py_DECREF(item); + + item = PyInt_FromLong((long) pinfo.valueType); + PyDict_SetItemString(v, "valueType", item); + Py_DECREF(item); + + if (pinfo.valueType != AL_NO_VAL && pinfo.valueType != AL_SCALAR_VAL) { + /* multiple values */ + item = PyInt_FromLong((long) pinfo.maxElems); + PyDict_SetItemString(v, "maxElems", item); + Py_DECREF(item); + + if (pinfo.valueType == AL_MATRIX_VAL) { + /* 2 dimensional */ + item = PyInt_FromLong((long) pinfo.maxElems2); + PyDict_SetItemString(v, "maxElems2", item); + Py_DECREF(item); + } + } + + item = PyInt_FromLong((long) pinfo.elementType); + PyDict_SetItemString(v, "elementType", item); + Py_DECREF(item); + + item = PyString_FromString(pinfo.name); + PyDict_SetItemString(v, "name", item); + Py_DECREF(item); + + item = param2python(res, param, pinfo.initial, &pinfo); + PyDict_SetItemString(v, "initial", item); + Py_DECREF(item); + + if (pinfo.elementType != AL_ENUM_ELEM && + pinfo.elementType != AL_RESOURCE_ELEM && + pinfo.elementType != AL_CHAR_ELEM) { + /* range param */ + item = param2python(res, param, pinfo.min, &pinfo); + PyDict_SetItemString(v, "min", item); + Py_DECREF(item); + + item = param2python(res, param, pinfo.max, &pinfo); + PyDict_SetItemString(v, "max", item); + Py_DECREF(item); + + item = param2python(res, param, pinfo.minDelta, &pinfo); + PyDict_SetItemString(v, "minDelta", item); + Py_DECREF(item); + + item = param2python(res, param, pinfo.maxDelta, &pinfo); + PyDict_SetItemString(v, "maxDelta", item); + Py_DECREF(item); + + item = PyInt_FromLong((long) pinfo.specialVals); + PyDict_SetItemString(v, "specialVals", item); + Py_DECREF(item); + } + + return v; +} + +PyDoc_STRVAR(al_GetResourceByName__doc__, +"alGetResourceByName: find an audio resource by name."); + +static PyObject * +al_GetResourceByName(PyObject *self, PyObject *args) +{ + int res, start_res, type; + char *name; + + if (!PyArg_ParseTuple(args, "isi:GetResourceByName", &start_res, &name, &type)) + return NULL; + if ((res = alGetResourceByName(start_res, name, type)) == 0) + return NULL; + return PyInt_FromLong((long) res); +} + +PyDoc_STRVAR(al_IsSubtype__doc__, +"alIsSubtype: indicate if one resource type is a subtype of another."); + +static PyObject * +al_IsSubtype(PyObject *self, PyObject *args) +{ + int type, subtype; + + if (!PyArg_ParseTuple(args, "ii:IsSubtype", &type, &subtype)) + return NULL; + return PyInt_FromLong((long) alIsSubtype(type, subtype)); +} + +PyDoc_STRVAR(al_SetErrorHandler__doc__, ""); + +static PyObject * +al_SetErrorHandler(PyObject *self, PyObject *args) +{ + + if (!PyArg_ParseTuple(args, ":SetErrorHandler")) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +#endif /* AL_NO_ELEM */ + +#ifdef OLD_INTERFACE + +static PyObject * +al_openport(PyObject *self, PyObject *args) +{ + char *name, *dir; + ALport port; + alcobject *config = NULL; + + if (!PyArg_ParseTuple(args, "ss|O!:OpenPort", &name, &dir, &Alctype, &config)) + return NULL; + if ((port = ALopenport(name, dir, config ? config->config : NULL)) == NULL) + return NULL; + return newalpobject(port); +} + +static PyObject * +al_newconfig(PyObject *self, PyObject *args) +{ + ALconfig config; + + if (!PyArg_ParseTuple(args, ":NewConfig")) + return NULL; + if ((config = ALnewconfig ()) == NULL) + return NULL; + return newalcobject(config); +} + +static PyObject * +al_queryparams(PyObject *self, PyObject *args) +{ + long device; + long length; + long *PVbuffer; + long PVdummy[2]; + PyObject *v = NULL; + int i; + + if (!PyArg_ParseTuple(args, "l:queryparams", &device)) + return NULL; + if ((length = ALqueryparams(device, PVdummy, 2L)) == -1) + return NULL; + if ((PVbuffer = PyMem_NEW(long, length)) == NULL) + return PyErr_NoMemory(); + if (ALqueryparams(device, PVbuffer, length) >= 0 && + (v = PyList_New((int)length)) != NULL) { + for (i = 0; i < length; i++) + PyList_SetItem(v, i, PyInt_FromLong(PVbuffer[i])); + } + PyMem_DEL(PVbuffer); + return v; +} + +static PyObject * +doParams(PyObject *args, int (*func)(long, long *, long), int modified) +{ + long device; + PyObject *list, *v; + long *PVbuffer; + long length; + int i; + + if (!PyArg_ParseTuple(args, "lO!", &device, &PyList_Type, &list)) + return NULL; + length = PyList_Size(list); + PVbuffer = PyMem_NEW(long, length); + if (PVbuffer == NULL) + return PyErr_NoMemory(); + for (i = 0; i < length; i++) { + v = PyList_GetItem(list, i); + if (!PyInt_Check(v)) { + PyMem_DEL(PVbuffer); + PyErr_BadArgument(); + return NULL; + } + PVbuffer[i] = PyInt_AsLong(v); + } + + if ((*func)(device, PVbuffer, length) == -1) { + PyMem_DEL(PVbuffer); + return NULL; + } + + if (modified) { + for (i = 0; i < length; i++) + PyList_SetItem(list, i, PyInt_FromLong(PVbuffer[i])); + } + + PyMem_DEL(PVbuffer); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +al_getparams(PyObject *self, PyObject *args) +{ + return doParams(args, ALgetparams, 1); +} + +static PyObject * +al_setparams(PyObject *self, PyObject *args) +{ + return doParams(args, ALsetparams, 0); +} + +static PyObject * +al_getname(PyObject *self, PyObject *args) +{ + long device, descriptor; + char *name; + + if (!PyArg_ParseTuple(args, "ll:getname", &device, &descriptor)) + return NULL; + if ((name = ALgetname(device, descriptor)) == NULL) + return NULL; + return PyString_FromString(name); +} + +static PyObject * +al_getdefault(PyObject *self, PyObject *args) +{ + long device, descriptor, value; + + if (!PyArg_ParseTuple(args, "ll:getdefault", &device, &descriptor)) + return NULL; + if ((value = ALgetdefault(device, descriptor)) == -1) + return NULL; + return PyLong_FromLong(value); +} + +static PyObject * +al_getminmax(PyObject *self, PyObject *args) +{ + long device, descriptor, min, max; + + if (!PyArg_ParseTuple(args, "ll:getminmax", &device, &descriptor)) + return NULL; + min = -1; + max = -1; + if (ALgetminmax(device, descriptor, &min, &max) == -1) + return NULL; + return Py_BuildValue("ll", min, max); +} + +#endif /* OLD_INTERFACE */ + +/* List of methods defined in the module */ + +static struct PyMethodDef al_methods[] = { +#ifdef AL_NO_ELEM /* IRIX 6 */ + {"NewConfig", (PyCFunction)al_NewConfig, METH_VARARGS, al_NewConfig__doc__}, + {"OpenPort", (PyCFunction)al_OpenPort, METH_VARARGS, al_OpenPort__doc__}, + {"Connect", (PyCFunction)al_Connect, METH_VARARGS, al_Connect__doc__}, + {"Disconnect", (PyCFunction)al_Disconnect, METH_VARARGS, al_Disconnect__doc__}, + {"GetParams", (PyCFunction)al_GetParams, METH_VARARGS, al_GetParams__doc__}, + {"SetParams", (PyCFunction)al_SetParams, METH_VARARGS, al_SetParams__doc__}, + {"QueryValues", (PyCFunction)al_QueryValues, METH_VARARGS, al_QueryValues__doc__}, + {"GetParamInfo", (PyCFunction)al_GetParamInfo, METH_VARARGS, al_GetParamInfo__doc__}, + {"GetResourceByName", (PyCFunction)al_GetResourceByName, METH_VARARGS, al_GetResourceByName__doc__}, + {"IsSubtype", (PyCFunction)al_IsSubtype, METH_VARARGS, al_IsSubtype__doc__}, +#if 0 + /* this one not supported */ + {"SetErrorHandler", (PyCFunction)al_SetErrorHandler, METH_VARARGS, al_SetErrorHandler__doc__}, +#endif +#endif /* AL_NO_ELEM */ +#ifdef OLD_INTERFACE + {"openport", (PyCFunction)al_openport, METH_VARARGS}, + {"newconfig", (PyCFunction)al_newconfig, METH_VARARGS}, + {"queryparams", (PyCFunction)al_queryparams, METH_VARARGS}, + {"getparams", (PyCFunction)al_getparams, METH_VARARGS}, + {"setparams", (PyCFunction)al_setparams, METH_VARARGS}, + {"getname", (PyCFunction)al_getname, METH_VARARGS}, + {"getdefault", (PyCFunction)al_getdefault, METH_VARARGS}, + {"getminmax", (PyCFunction)al_getminmax, METH_VARARGS}, +#endif /* OLD_INTERFACE */ + + {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ +}; + + +/* Initialization function for the module (*must* be called inital) */ + +PyDoc_STRVAR(al_module_documentation, ""); + +void +inital(void) +{ + PyObject *m, *d, *x; + + /* Create the module and add the functions */ + m = Py_InitModule4("al", al_methods, + al_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + ErrorObject = PyErr_NewException("al.error", NULL, NULL); + PyDict_SetItemString(d, "error", ErrorObject); + + /* XXXX Add constants here */ +#ifdef AL_4CHANNEL + x = PyInt_FromLong((long) AL_4CHANNEL); + if (x == NULL || PyDict_SetItemString(d, "FOURCHANNEL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ADAT_IF_TYPE + x = PyInt_FromLong((long) AL_ADAT_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "ADAT_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ADAT_MCLK_TYPE + x = PyInt_FromLong((long) AL_ADAT_MCLK_TYPE); + if (x == NULL || PyDict_SetItemString(d, "ADAT_MCLK_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_AES_IF_TYPE + x = PyInt_FromLong((long) AL_AES_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "AES_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_AES_MCLK_TYPE + x = PyInt_FromLong((long) AL_AES_MCLK_TYPE); + if (x == NULL || PyDict_SetItemString(d, "AES_MCLK_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ANALOG_IF_TYPE + x = PyInt_FromLong((long) AL_ANALOG_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "ANALOG_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ASSOCIATE + x = PyInt_FromLong((long) AL_ASSOCIATE); + if (x == NULL || PyDict_SetItemString(d, "ASSOCIATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_BUFFER_NULL + x = PyInt_FromLong((long) AL_BAD_BUFFER_NULL); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_NULL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_BUFFERLENGTH + x = PyInt_FromLong((long) AL_BAD_BUFFERLENGTH); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFERLENGTH", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_BUFFERLENGTH_NEG + x = PyInt_FromLong((long) AL_BAD_BUFFERLENGTH_NEG); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFERLENGTH_NEG", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_BUFFERLENGTH_ODD + x = PyInt_FromLong((long) AL_BAD_BUFFERLENGTH_ODD); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFERLENGTH_ODD", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_CHANNELS + x = PyInt_FromLong((long) AL_BAD_CHANNELS); + if (x == NULL || PyDict_SetItemString(d, "BAD_CHANNELS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_CONFIG + x = PyInt_FromLong((long) AL_BAD_CONFIG); + if (x == NULL || PyDict_SetItemString(d, "BAD_CONFIG", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_COUNT_NEG + x = PyInt_FromLong((long) AL_BAD_COUNT_NEG); + if (x == NULL || PyDict_SetItemString(d, "BAD_COUNT_NEG", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_DEVICE + x = PyInt_FromLong((long) AL_BAD_DEVICE); + if (x == NULL || PyDict_SetItemString(d, "BAD_DEVICE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_DEVICE_ACCESS + x = PyInt_FromLong((long) AL_BAD_DEVICE_ACCESS); + if (x == NULL || PyDict_SetItemString(d, "BAD_DEVICE_ACCESS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_DIRECTION + x = PyInt_FromLong((long) AL_BAD_DIRECTION); + if (x == NULL || PyDict_SetItemString(d, "BAD_DIRECTION", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_FILLPOINT + x = PyInt_FromLong((long) AL_BAD_FILLPOINT); + if (x == NULL || PyDict_SetItemString(d, "BAD_FILLPOINT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_FLOATMAX + x = PyInt_FromLong((long) AL_BAD_FLOATMAX); + if (x == NULL || PyDict_SetItemString(d, "BAD_FLOATMAX", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_ILLEGAL_STATE + x = PyInt_FromLong((long) AL_BAD_ILLEGAL_STATE); + if (x == NULL || PyDict_SetItemString(d, "BAD_ILLEGAL_STATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_NO_PORTS + x = PyInt_FromLong((long) AL_BAD_NO_PORTS); + if (x == NULL || PyDict_SetItemString(d, "BAD_NO_PORTS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_NOT_FOUND + x = PyInt_FromLong((long) AL_BAD_NOT_FOUND); + if (x == NULL || PyDict_SetItemString(d, "BAD_NOT_FOUND", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_NOT_IMPLEMENTED + x = PyInt_FromLong((long) AL_BAD_NOT_IMPLEMENTED); + if (x == NULL || PyDict_SetItemString(d, "BAD_NOT_IMPLEMENTED", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_OUT_OF_MEM + x = PyInt_FromLong((long) AL_BAD_OUT_OF_MEM); + if (x == NULL || PyDict_SetItemString(d, "BAD_OUT_OF_MEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_PARAM + x = PyInt_FromLong((long) AL_BAD_PARAM); + if (x == NULL || PyDict_SetItemString(d, "BAD_PARAM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_PERMISSIONS + x = PyInt_FromLong((long) AL_BAD_PERMISSIONS); + if (x == NULL || PyDict_SetItemString(d, "BAD_PERMISSIONS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_PORT + x = PyInt_FromLong((long) AL_BAD_PORT); + if (x == NULL || PyDict_SetItemString(d, "BAD_PORT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_PORTSTYLE + x = PyInt_FromLong((long) AL_BAD_PORTSTYLE); + if (x == NULL || PyDict_SetItemString(d, "BAD_PORTSTYLE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_PVBUFFER + x = PyInt_FromLong((long) AL_BAD_PVBUFFER); + if (x == NULL || PyDict_SetItemString(d, "BAD_PVBUFFER", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_QSIZE + x = PyInt_FromLong((long) AL_BAD_QSIZE); + if (x == NULL || PyDict_SetItemString(d, "BAD_QSIZE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_RATE + x = PyInt_FromLong((long) AL_BAD_RATE); + if (x == NULL || PyDict_SetItemString(d, "BAD_RATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_RESOURCE + x = PyInt_FromLong((long) AL_BAD_RESOURCE); + if (x == NULL || PyDict_SetItemString(d, "BAD_RESOURCE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_SAMPFMT + x = PyInt_FromLong((long) AL_BAD_SAMPFMT); + if (x == NULL || PyDict_SetItemString(d, "BAD_SAMPFMT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_TRANSFER_SIZE + x = PyInt_FromLong((long) AL_BAD_TRANSFER_SIZE); + if (x == NULL || PyDict_SetItemString(d, "BAD_TRANSFER_SIZE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_BAD_WIDTH + x = PyInt_FromLong((long) AL_BAD_WIDTH); + if (x == NULL || PyDict_SetItemString(d, "BAD_WIDTH", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CHANNEL_MODE + x = PyInt_FromLong((long) AL_CHANNEL_MODE); + if (x == NULL || PyDict_SetItemString(d, "CHANNEL_MODE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CHANNELS + x = PyInt_FromLong((long) AL_CHANNELS); + if (x == NULL || PyDict_SetItemString(d, "CHANNELS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CHAR_ELEM + x = PyInt_FromLong((long) AL_CHAR_ELEM); + if (x == NULL || PyDict_SetItemString(d, "CHAR_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CLOCK_GEN + x = PyInt_FromLong((long) AL_CLOCK_GEN); + if (x == NULL || PyDict_SetItemString(d, "CLOCK_GEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CLOCKGEN_TYPE + x = PyInt_FromLong((long) AL_CLOCKGEN_TYPE); + if (x == NULL || PyDict_SetItemString(d, "CLOCKGEN_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CONNECT + x = PyInt_FromLong((long) AL_CONNECT); + if (x == NULL || PyDict_SetItemString(d, "CONNECT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CONNECTION_TYPE + x = PyInt_FromLong((long) AL_CONNECTION_TYPE); + if (x == NULL || PyDict_SetItemString(d, "CONNECTION_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CONNECTIONS + x = PyInt_FromLong((long) AL_CONNECTIONS); + if (x == NULL || PyDict_SetItemString(d, "CONNECTIONS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_CRYSTAL_MCLK_TYPE + x = PyInt_FromLong((long) AL_CRYSTAL_MCLK_TYPE); + if (x == NULL || PyDict_SetItemString(d, "CRYSTAL_MCLK_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DEFAULT_DEVICE + x = PyInt_FromLong((long) AL_DEFAULT_DEVICE); + if (x == NULL || PyDict_SetItemString(d, "DEFAULT_DEVICE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DEFAULT_INPUT + x = PyInt_FromLong((long) AL_DEFAULT_INPUT); + if (x == NULL || PyDict_SetItemString(d, "DEFAULT_INPUT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DEFAULT_OUTPUT + x = PyInt_FromLong((long) AL_DEFAULT_OUTPUT); + if (x == NULL || PyDict_SetItemString(d, "DEFAULT_OUTPUT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DEST + x = PyInt_FromLong((long) AL_DEST); + if (x == NULL || PyDict_SetItemString(d, "DEST", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DEVICE_TYPE + x = PyInt_FromLong((long) AL_DEVICE_TYPE); + if (x == NULL || PyDict_SetItemString(d, "DEVICE_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DEVICES + x = PyInt_FromLong((long) AL_DEVICES); + if (x == NULL || PyDict_SetItemString(d, "DEVICES", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DIGITAL_IF_TYPE + x = PyInt_FromLong((long) AL_DIGITAL_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "DIGITAL_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DIGITAL_INPUT_RATE + x = PyInt_FromLong((long) AL_DIGITAL_INPUT_RATE); + if (x == NULL || PyDict_SetItemString(d, "DIGITAL_INPUT_RATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_DISCONNECT + x = PyInt_FromLong((long) AL_DISCONNECT); + if (x == NULL || PyDict_SetItemString(d, "DISCONNECT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ENUM_ELEM + x = PyInt_FromLong((long) AL_ENUM_ELEM); + if (x == NULL || PyDict_SetItemString(d, "ENUM_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ENUM_VALUE + x = PyInt_FromLong((long) AL_ENUM_VALUE); + if (x == NULL || PyDict_SetItemString(d, "ENUM_VALUE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ERROR_INPUT_OVERFLOW + x = PyInt_FromLong((long) AL_ERROR_INPUT_OVERFLOW); + if (x == NULL || PyDict_SetItemString(d, "ERROR_INPUT_OVERFLOW", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ERROR_LENGTH + x = PyInt_FromLong((long) AL_ERROR_LENGTH); + if (x == NULL || PyDict_SetItemString(d, "ERROR_LENGTH", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ERROR_LOCATION_LSP + x = PyInt_FromLong((long) AL_ERROR_LOCATION_LSP); + if (x == NULL || PyDict_SetItemString(d, "ERROR_LOCATION_LSP", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ERROR_LOCATION_MSP + x = PyInt_FromLong((long) AL_ERROR_LOCATION_MSP); + if (x == NULL || PyDict_SetItemString(d, "ERROR_LOCATION_MSP", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ERROR_NUMBER + x = PyInt_FromLong((long) AL_ERROR_NUMBER); + if (x == NULL || PyDict_SetItemString(d, "ERROR_NUMBER", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ERROR_OUTPUT_UNDERFLOW + x = PyInt_FromLong((long) AL_ERROR_OUTPUT_UNDERFLOW); + if (x == NULL || PyDict_SetItemString(d, "ERROR_OUTPUT_UNDERFLOW", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_ERROR_TYPE + x = PyInt_FromLong((long) AL_ERROR_TYPE); + if (x == NULL || PyDict_SetItemString(d, "ERROR_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_FIXED_ELEM + x = PyInt_FromLong((long) AL_FIXED_ELEM); + if (x == NULL || PyDict_SetItemString(d, "FIXED_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_FIXED_MCLK_TYPE + x = PyInt_FromLong((long) AL_FIXED_MCLK_TYPE); + if (x == NULL || PyDict_SetItemString(d, "FIXED_MCLK_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_GAIN + x = PyInt_FromLong((long) AL_GAIN); + if (x == NULL || PyDict_SetItemString(d, "GAIN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_GAIN_REF + x = PyInt_FromLong((long) AL_GAIN_REF); + if (x == NULL || PyDict_SetItemString(d, "GAIN_REF", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_HRB_TYPE + x = PyInt_FromLong((long) AL_HRB_TYPE); + if (x == NULL || PyDict_SetItemString(d, "HRB_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_COUNT + x = PyInt_FromLong((long) AL_INPUT_COUNT); + if (x == NULL || PyDict_SetItemString(d, "INPUT_COUNT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_DEVICE_TYPE + x = PyInt_FromLong((long) AL_INPUT_DEVICE_TYPE); + if (x == NULL || PyDict_SetItemString(d, "INPUT_DEVICE_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_DIGITAL + x = PyInt_FromLong((long) AL_INPUT_DIGITAL); + if (x == NULL || PyDict_SetItemString(d, "INPUT_DIGITAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_HRB_TYPE + x = PyInt_FromLong((long) AL_INPUT_HRB_TYPE); + if (x == NULL || PyDict_SetItemString(d, "INPUT_HRB_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_LINE + x = PyInt_FromLong((long) AL_INPUT_LINE); + if (x == NULL || PyDict_SetItemString(d, "INPUT_LINE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_MIC + x = PyInt_FromLong((long) AL_INPUT_MIC); + if (x == NULL || PyDict_SetItemString(d, "INPUT_MIC", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_PORT_TYPE + x = PyInt_FromLong((long) AL_INPUT_PORT_TYPE); + if (x == NULL || PyDict_SetItemString(d, "INPUT_PORT_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_RATE + x = PyInt_FromLong((long) AL_INPUT_RATE); + if (x == NULL || PyDict_SetItemString(d, "INPUT_RATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INPUT_SOURCE + x = PyInt_FromLong((long) AL_INPUT_SOURCE); + if (x == NULL || PyDict_SetItemString(d, "INPUT_SOURCE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INT32_ELEM + x = PyInt_FromLong((long) AL_INT32_ELEM); + if (x == NULL || PyDict_SetItemString(d, "INT32_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INT64_ELEM + x = PyInt_FromLong((long) AL_INT64_ELEM); + if (x == NULL || PyDict_SetItemString(d, "INT64_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INTERFACE + x = PyInt_FromLong((long) AL_INTERFACE); + if (x == NULL || PyDict_SetItemString(d, "INTERFACE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INTERFACE_TYPE + x = PyInt_FromLong((long) AL_INTERFACE_TYPE); + if (x == NULL || PyDict_SetItemString(d, "INTERFACE_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INVALID_PARAM + x = PyInt_FromLong((long) AL_INVALID_PARAM); + if (x == NULL || PyDict_SetItemString(d, "INVALID_PARAM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_INVALID_VALUE + x = PyInt_FromLong((long) AL_INVALID_VALUE); + if (x == NULL || PyDict_SetItemString(d, "INVALID_VALUE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_JITTER + x = PyInt_FromLong((long) AL_JITTER); + if (x == NULL || PyDict_SetItemString(d, "JITTER", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LABEL + x = PyInt_FromLong((long) AL_LABEL); + if (x == NULL || PyDict_SetItemString(d, "LABEL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LEFT_INPUT_ATTEN + x = PyInt_FromLong((long) AL_LEFT_INPUT_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "LEFT_INPUT_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LEFT_MONITOR_ATTEN + x = PyInt_FromLong((long) AL_LEFT_MONITOR_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "LEFT_MONITOR_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LEFT_SPEAKER_GAIN + x = PyInt_FromLong((long) AL_LEFT_SPEAKER_GAIN); + if (x == NULL || PyDict_SetItemString(d, "LEFT_SPEAKER_GAIN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LEFT1_INPUT_ATTEN + x = PyInt_FromLong((long) AL_LEFT1_INPUT_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "LEFT1_INPUT_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LEFT2_INPUT_ATTEN + x = PyInt_FromLong((long) AL_LEFT2_INPUT_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "LEFT2_INPUT_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LINE_IF_TYPE + x = PyInt_FromLong((long) AL_LINE_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "LINE_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_LOCKED + x = PyInt_FromLong((long) AL_LOCKED); + if (x == NULL || PyDict_SetItemString(d, "LOCKED", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MASTER_CLOCK + x = PyInt_FromLong((long) AL_MASTER_CLOCK); + if (x == NULL || PyDict_SetItemString(d, "MASTER_CLOCK", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MATRIX_VAL + x = PyInt_FromLong((long) AL_MATRIX_VAL); + if (x == NULL || PyDict_SetItemString(d, "MATRIX_VAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MAX_ERROR + x = PyInt_FromLong((long) AL_MAX_ERROR); + if (x == NULL || PyDict_SetItemString(d, "MAX_ERROR", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MAX_EVENT_PARAM + x = PyInt_FromLong((long) AL_MAX_EVENT_PARAM); + if (x == NULL || PyDict_SetItemString(d, "MAX_EVENT_PARAM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MAX_PBUFSIZE + x = PyInt_FromLong((long) AL_MAX_PBUFSIZE); + if (x == NULL || PyDict_SetItemString(d, "MAX_PBUFSIZE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MAX_PORTS + x = PyInt_FromLong((long) AL_MAX_PORTS); + if (x == NULL || PyDict_SetItemString(d, "MAX_PORTS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MAX_RESOURCE_ID + x = PyInt_FromLong((long) AL_MAX_RESOURCE_ID); + if (x == NULL || PyDict_SetItemString(d, "MAX_RESOURCE_ID", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MAX_SETSIZE + x = PyInt_FromLong((long) AL_MAX_SETSIZE); + if (x == NULL || PyDict_SetItemString(d, "MAX_SETSIZE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MAX_STRLEN + x = PyInt_FromLong((long) AL_MAX_STRLEN); + if (x == NULL || PyDict_SetItemString(d, "MAX_STRLEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MCLK_TYPE + x = PyInt_FromLong((long) AL_MCLK_TYPE); + if (x == NULL || PyDict_SetItemString(d, "MCLK_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MIC_IF_TYPE + x = PyInt_FromLong((long) AL_MIC_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "MIC_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MONITOR_CTL + x = PyInt_FromLong((long) AL_MONITOR_CTL); + if (x == NULL || PyDict_SetItemString(d, "MONITOR_CTL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MONITOR_OFF + x = PyInt_FromLong((long) AL_MONITOR_OFF); + if (x == NULL || PyDict_SetItemString(d, "MONITOR_OFF", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MONITOR_ON + x = PyInt_FromLong((long) AL_MONITOR_ON); + if (x == NULL || PyDict_SetItemString(d, "MONITOR_ON", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MONO + x = PyInt_FromLong((long) AL_MONO); + if (x == NULL || PyDict_SetItemString(d, "MONO", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_MUTE + x = PyInt_FromLong((long) AL_MUTE); + if (x == NULL || PyDict_SetItemString(d, "MUTE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NAME + x = PyInt_FromLong((long) AL_NAME); + if (x == NULL || PyDict_SetItemString(d, "NAME", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NEG_INFINITY + x = PyInt_FromLong((long) AL_NEG_INFINITY); + if (x == NULL || PyDict_SetItemString(d, "NEG_INFINITY", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NEG_INFINITY_BIT + x = PyInt_FromLong((long) AL_NEG_INFINITY_BIT); + if (x == NULL || PyDict_SetItemString(d, "NEG_INFINITY_BIT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NO_CHANGE + x = PyInt_FromLong((long) AL_NO_CHANGE); + if (x == NULL || PyDict_SetItemString(d, "NO_CHANGE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NO_CHANGE_BIT + x = PyInt_FromLong((long) AL_NO_CHANGE_BIT); + if (x == NULL || PyDict_SetItemString(d, "NO_CHANGE_BIT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NO_ELEM + x = PyInt_FromLong((long) AL_NO_ELEM); + if (x == NULL || PyDict_SetItemString(d, "NO_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NO_ERRORS + x = PyInt_FromLong((long) AL_NO_ERRORS); + if (x == NULL || PyDict_SetItemString(d, "NO_ERRORS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NO_OP + x = PyInt_FromLong((long) AL_NO_OP); + if (x == NULL || PyDict_SetItemString(d, "NO_OP", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NO_VAL + x = PyInt_FromLong((long) AL_NO_VAL); + if (x == NULL || PyDict_SetItemString(d, "NO_VAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NULL_INTERFACE + x = PyInt_FromLong((long) AL_NULL_INTERFACE); + if (x == NULL || PyDict_SetItemString(d, "NULL_INTERFACE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_NULL_RESOURCE + x = PyInt_FromLong((long) AL_NULL_RESOURCE); + if (x == NULL || PyDict_SetItemString(d, "NULL_RESOURCE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_OPTICAL_IF_TYPE + x = PyInt_FromLong((long) AL_OPTICAL_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "OPTICAL_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_OUTPUT_COUNT + x = PyInt_FromLong((long) AL_OUTPUT_COUNT); + if (x == NULL || PyDict_SetItemString(d, "OUTPUT_COUNT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_OUTPUT_DEVICE_TYPE + x = PyInt_FromLong((long) AL_OUTPUT_DEVICE_TYPE); + if (x == NULL || PyDict_SetItemString(d, "OUTPUT_DEVICE_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_OUTPUT_HRB_TYPE + x = PyInt_FromLong((long) AL_OUTPUT_HRB_TYPE); + if (x == NULL || PyDict_SetItemString(d, "OUTPUT_HRB_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_OUTPUT_PORT_TYPE + x = PyInt_FromLong((long) AL_OUTPUT_PORT_TYPE); + if (x == NULL || PyDict_SetItemString(d, "OUTPUT_PORT_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_OUTPUT_RATE + x = PyInt_FromLong((long) AL_OUTPUT_RATE); + if (x == NULL || PyDict_SetItemString(d, "OUTPUT_RATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PARAM_BIT + x = PyInt_FromLong((long) AL_PARAM_BIT); + if (x == NULL || PyDict_SetItemString(d, "PARAM_BIT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PARAMS + x = PyInt_FromLong((long) AL_PARAMS); + if (x == NULL || PyDict_SetItemString(d, "PARAMS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PORT_COUNT + x = PyInt_FromLong((long) AL_PORT_COUNT); + if (x == NULL || PyDict_SetItemString(d, "PORT_COUNT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PORT_TYPE + x = PyInt_FromLong((long) AL_PORT_TYPE); + if (x == NULL || PyDict_SetItemString(d, "PORT_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PORTS + x = PyInt_FromLong((long) AL_PORTS); + if (x == NULL || PyDict_SetItemString(d, "PORTS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PORTSTYLE_DIRECT + x = PyInt_FromLong((long) AL_PORTSTYLE_DIRECT); + if (x == NULL || PyDict_SetItemString(d, "PORTSTYLE_DIRECT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PORTSTYLE_SERIAL + x = PyInt_FromLong((long) AL_PORTSTYLE_SERIAL); + if (x == NULL || PyDict_SetItemString(d, "PORTSTYLE_SERIAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PRINT_ERRORS + x = PyInt_FromLong((long) AL_PRINT_ERRORS); + if (x == NULL || PyDict_SetItemString(d, "PRINT_ERRORS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_PTR_ELEM + x = PyInt_FromLong((long) AL_PTR_ELEM); + if (x == NULL || PyDict_SetItemString(d, "PTR_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RANGE_VALUE + x = PyInt_FromLong((long) AL_RANGE_VALUE); + if (x == NULL || PyDict_SetItemString(d, "RANGE_VALUE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE + x = PyInt_FromLong((long) AL_RATE); + if (x == NULL || PyDict_SetItemString(d, "RATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_11025 + x = PyInt_FromLong((long) AL_RATE_11025); + if (x == NULL || PyDict_SetItemString(d, "RATE_11025", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_16000 + x = PyInt_FromLong((long) AL_RATE_16000); + if (x == NULL || PyDict_SetItemString(d, "RATE_16000", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_22050 + x = PyInt_FromLong((long) AL_RATE_22050); + if (x == NULL || PyDict_SetItemString(d, "RATE_22050", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_32000 + x = PyInt_FromLong((long) AL_RATE_32000); + if (x == NULL || PyDict_SetItemString(d, "RATE_32000", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_44100 + x = PyInt_FromLong((long) AL_RATE_44100); + if (x == NULL || PyDict_SetItemString(d, "RATE_44100", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_48000 + x = PyInt_FromLong((long) AL_RATE_48000); + if (x == NULL || PyDict_SetItemString(d, "RATE_48000", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_8000 + x = PyInt_FromLong((long) AL_RATE_8000); + if (x == NULL || PyDict_SetItemString(d, "RATE_8000", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_AES_1 + x = PyInt_FromLong((long) AL_RATE_AES_1); + if (x == NULL || PyDict_SetItemString(d, "RATE_AES_1", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_AES_1s + x = PyInt_FromLong((long) AL_RATE_AES_1s); + if (x == NULL || PyDict_SetItemString(d, "RATE_AES_1s", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_AES_2 + x = PyInt_FromLong((long) AL_RATE_AES_2); + if (x == NULL || PyDict_SetItemString(d, "RATE_AES_2", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_AES_3 + x = PyInt_FromLong((long) AL_RATE_AES_3); + if (x == NULL || PyDict_SetItemString(d, "RATE_AES_3", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_AES_4 + x = PyInt_FromLong((long) AL_RATE_AES_4); + if (x == NULL || PyDict_SetItemString(d, "RATE_AES_4", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_AES_6 + x = PyInt_FromLong((long) AL_RATE_AES_6); + if (x == NULL || PyDict_SetItemString(d, "RATE_AES_6", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_FRACTION_D + x = PyInt_FromLong((long) AL_RATE_FRACTION_D); + if (x == NULL || PyDict_SetItemString(d, "RATE_FRACTION_D", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_FRACTION_N + x = PyInt_FromLong((long) AL_RATE_FRACTION_N); + if (x == NULL || PyDict_SetItemString(d, "RATE_FRACTION_N", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_INPUTRATE + x = PyInt_FromLong((long) AL_RATE_INPUTRATE); + if (x == NULL || PyDict_SetItemString(d, "RATE_INPUTRATE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_NO_DIGITAL_INPUT + x = PyInt_FromLong((long) AL_RATE_NO_DIGITAL_INPUT); + if (x == NULL || PyDict_SetItemString(d, "RATE_NO_DIGITAL_INPUT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_UNACQUIRED + x = PyInt_FromLong((long) AL_RATE_UNACQUIRED); + if (x == NULL || PyDict_SetItemString(d, "RATE_UNACQUIRED", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RATE_UNDEFINED + x = PyInt_FromLong((long) AL_RATE_UNDEFINED); + if (x == NULL || PyDict_SetItemString(d, "RATE_UNDEFINED", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_REF_0DBV + x = PyInt_FromLong((long) AL_REF_0DBV); + if (x == NULL || PyDict_SetItemString(d, "REF_0DBV", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_REF_NONE + x = PyInt_FromLong((long) AL_REF_NONE); + if (x == NULL || PyDict_SetItemString(d, "REF_NONE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RESERVED1_TYPE + x = PyInt_FromLong((long) AL_RESERVED1_TYPE); + if (x == NULL || PyDict_SetItemString(d, "RESERVED1_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RESERVED2_TYPE + x = PyInt_FromLong((long) AL_RESERVED2_TYPE); + if (x == NULL || PyDict_SetItemString(d, "RESERVED2_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RESERVED3_TYPE + x = PyInt_FromLong((long) AL_RESERVED3_TYPE); + if (x == NULL || PyDict_SetItemString(d, "RESERVED3_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RESERVED4_TYPE + x = PyInt_FromLong((long) AL_RESERVED4_TYPE); + if (x == NULL || PyDict_SetItemString(d, "RESERVED4_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RESOURCE + x = PyInt_FromLong((long) AL_RESOURCE); + if (x == NULL || PyDict_SetItemString(d, "RESOURCE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RESOURCE_ELEM + x = PyInt_FromLong((long) AL_RESOURCE_ELEM); + if (x == NULL || PyDict_SetItemString(d, "RESOURCE_ELEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RESOURCE_TYPE + x = PyInt_FromLong((long) AL_RESOURCE_TYPE); + if (x == NULL || PyDict_SetItemString(d, "RESOURCE_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RIGHT_INPUT_ATTEN + x = PyInt_FromLong((long) AL_RIGHT_INPUT_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "RIGHT_INPUT_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RIGHT_MONITOR_ATTEN + x = PyInt_FromLong((long) AL_RIGHT_MONITOR_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "RIGHT_MONITOR_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RIGHT_SPEAKER_GAIN + x = PyInt_FromLong((long) AL_RIGHT_SPEAKER_GAIN); + if (x == NULL || PyDict_SetItemString(d, "RIGHT_SPEAKER_GAIN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RIGHT1_INPUT_ATTEN + x = PyInt_FromLong((long) AL_RIGHT1_INPUT_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "RIGHT1_INPUT_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_RIGHT2_INPUT_ATTEN + x = PyInt_FromLong((long) AL_RIGHT2_INPUT_ATTEN); + if (x == NULL || PyDict_SetItemString(d, "RIGHT2_INPUT_ATTEN", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SAMPFMT_DOUBLE + x = PyInt_FromLong((long) AL_SAMPFMT_DOUBLE); + if (x == NULL || PyDict_SetItemString(d, "SAMPFMT_DOUBLE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SAMPFMT_FLOAT + x = PyInt_FromLong((long) AL_SAMPFMT_FLOAT); + if (x == NULL || PyDict_SetItemString(d, "SAMPFMT_FLOAT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SAMPFMT_TWOSCOMP + x = PyInt_FromLong((long) AL_SAMPFMT_TWOSCOMP); + if (x == NULL || PyDict_SetItemString(d, "SAMPFMT_TWOSCOMP", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SAMPLE_16 + x = PyInt_FromLong((long) AL_SAMPLE_16); + if (x == NULL || PyDict_SetItemString(d, "SAMPLE_16", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SAMPLE_24 + x = PyInt_FromLong((long) AL_SAMPLE_24); + if (x == NULL || PyDict_SetItemString(d, "SAMPLE_24", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SAMPLE_8 + x = PyInt_FromLong((long) AL_SAMPLE_8); + if (x == NULL || PyDict_SetItemString(d, "SAMPLE_8", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SCALAR_VAL + x = PyInt_FromLong((long) AL_SCALAR_VAL); + if (x == NULL || PyDict_SetItemString(d, "SCALAR_VAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SET_VAL + x = PyInt_FromLong((long) AL_SET_VAL); + if (x == NULL || PyDict_SetItemString(d, "SET_VAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SHORT_NAME + x = PyInt_FromLong((long) AL_SHORT_NAME); + if (x == NULL || PyDict_SetItemString(d, "SHORT_NAME", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SMPTE272M_IF_TYPE + x = PyInt_FromLong((long) AL_SMPTE272M_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "SMPTE272M_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SOURCE + x = PyInt_FromLong((long) AL_SOURCE); + if (x == NULL || PyDict_SetItemString(d, "SOURCE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SPEAKER_IF_TYPE + x = PyInt_FromLong((long) AL_SPEAKER_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "SPEAKER_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SPEAKER_MUTE_CTL + x = PyInt_FromLong((long) AL_SPEAKER_MUTE_CTL); + if (x == NULL || PyDict_SetItemString(d, "SPEAKER_MUTE_CTL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SPEAKER_MUTE_OFF + x = PyInt_FromLong((long) AL_SPEAKER_MUTE_OFF); + if (x == NULL || PyDict_SetItemString(d, "SPEAKER_MUTE_OFF", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SPEAKER_MUTE_ON + x = PyInt_FromLong((long) AL_SPEAKER_MUTE_ON); + if (x == NULL || PyDict_SetItemString(d, "SPEAKER_MUTE_ON", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SPEAKER_PLUS_LINE_IF_TYPE + x = PyInt_FromLong((long) AL_SPEAKER_PLUS_LINE_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "SPEAKER_PLUS_LINE_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_STEREO + x = PyInt_FromLong((long) AL_STEREO); + if (x == NULL || PyDict_SetItemString(d, "STEREO", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_STRING_VAL + x = PyInt_FromLong((long) AL_STRING_VAL); + if (x == NULL || PyDict_SetItemString(d, "STRING_VAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SUBSYSTEM + x = PyInt_FromLong((long) AL_SUBSYSTEM); + if (x == NULL || PyDict_SetItemString(d, "SUBSYSTEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SUBSYSTEM_TYPE + x = PyInt_FromLong((long) AL_SUBSYSTEM_TYPE); + if (x == NULL || PyDict_SetItemString(d, "SUBSYSTEM_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SYNC_INPUT_TO_AES + x = PyInt_FromLong((long) AL_SYNC_INPUT_TO_AES); + if (x == NULL || PyDict_SetItemString(d, "SYNC_INPUT_TO_AES", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SYNC_OUTPUT_TO_AES + x = PyInt_FromLong((long) AL_SYNC_OUTPUT_TO_AES); + if (x == NULL || PyDict_SetItemString(d, "SYNC_OUTPUT_TO_AES", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SYSTEM + x = PyInt_FromLong((long) AL_SYSTEM); + if (x == NULL || PyDict_SetItemString(d, "SYSTEM", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_SYSTEM_TYPE + x = PyInt_FromLong((long) AL_SYSTEM_TYPE); + if (x == NULL || PyDict_SetItemString(d, "SYSTEM_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_TEST_IF_TYPE + x = PyInt_FromLong((long) AL_TEST_IF_TYPE); + if (x == NULL || PyDict_SetItemString(d, "TEST_IF_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_TYPE + x = PyInt_FromLong((long) AL_TYPE); + if (x == NULL || PyDict_SetItemString(d, "TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_TYPE_BIT + x = PyInt_FromLong((long) AL_TYPE_BIT); + if (x == NULL || PyDict_SetItemString(d, "TYPE_BIT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_UNUSED_COUNT + x = PyInt_FromLong((long) AL_UNUSED_COUNT); + if (x == NULL || PyDict_SetItemString(d, "UNUSED_COUNT", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_UNUSED_PORTS + x = PyInt_FromLong((long) AL_UNUSED_PORTS); + if (x == NULL || PyDict_SetItemString(d, "UNUSED_PORTS", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_VARIABLE_MCLK_TYPE + x = PyInt_FromLong((long) AL_VARIABLE_MCLK_TYPE); + if (x == NULL || PyDict_SetItemString(d, "VARIABLE_MCLK_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_VECTOR_VAL + x = PyInt_FromLong((long) AL_VECTOR_VAL); + if (x == NULL || PyDict_SetItemString(d, "VECTOR_VAL", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_VIDEO_MCLK_TYPE + x = PyInt_FromLong((long) AL_VIDEO_MCLK_TYPE); + if (x == NULL || PyDict_SetItemString(d, "VIDEO_MCLK_TYPE", x) < 0) + goto error; + Py_DECREF(x); +#endif +#ifdef AL_WORDSIZE + x = PyInt_FromLong((long) AL_WORDSIZE); + if (x == NULL || PyDict_SetItemString(d, "WORDSIZE", x) < 0) + goto error; + Py_DECREF(x); +#endif + +#ifdef AL_NO_ELEM /* IRIX 6 */ + (void) alSetErrorHandler(ErrorHandler); +#endif /* AL_NO_ELEM */ +#ifdef OLD_INTERFACE + (void) ALseterrorhandler(ErrorHandler); +#endif /* OLD_INTERFACE */ + + error: + return; +} diff --git a/sys/src/cmd/python/Modules/ar_beos b/sys/src/cmd/python/Modules/ar_beos new file mode 100755 index 000000000..e7efa7540 --- /dev/null +++ b/sys/src/cmd/python/Modules/ar_beos @@ -0,0 +1,73 @@ +#!/bin/sh +# +# Truly fake ar, using a directory to store object files. +# +# Donn Cave, donn@oz.net + +usage='Usage: ar-fake cr libpython.dir obj.o ... + ar-fake d libpython.dir obj.o ... + ar-fake so libpython.dir libpython.so' + +case $# in +0|1|2) + echo "$usage" >&2 + exit 1 + ;; +esac + +command=$1 +library=$2 +shift 2 + +case $command in +cr) + if test -d $library + then : + else + mkdir $library + fi + if cp -p $* $library + then + # To force directory modify date, create or delete a file. + if test -e $library/.tch + then rm $library/.tch + else echo tch > $library/.tch + fi + exit 0 + fi + ;; +d) + if test -d $library + then + cd $library + rm -f $* + fi + ;; +so) + case $BE_HOST_CPU in + ppc) + # In case your libpython.a refers to any exotic libraries, + # mwld needs to know that here. The following hack makes + # a couple of assumptions about Modules/Makefile. If it + # doesn't work, you may as well add the necessary libraries + # here explicitly instead. + extralibs=$( + (cd Modules; make -f Makefile -n link) | + sed -n 's/.*\.so \(.*\) -o python.*/\1/p' + ) + mwld -xms -export pragma -nodup -o $1 $library/* $extralibs + ;; + x86) + ld -shared -soname $(basename $1) -o $1 $library/* + ;; + esac + status=$? + cd $(dirname $1) + ln -sf $PWD lib + exit $status + ;; +*) + echo "$usage" >&2 + exit 1 + ;; +esac diff --git a/sys/src/cmd/python/Modules/arraymodule.c b/sys/src/cmd/python/Modules/arraymodule.c new file mode 100644 index 000000000..3ba5cf88e --- /dev/null +++ b/sys/src/cmd/python/Modules/arraymodule.c @@ -0,0 +1,2141 @@ +/* Array object implementation */ + +/* An array is a uniform list -- all items have the same type. + The item type is restricted to simple C types like int or float */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#ifdef STDC_HEADERS +#include <stddef.h> +#else /* !STDC_HEADERS */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> /* For size_t */ +#endif /* HAVE_SYS_TYPES_H */ +#endif /* !STDC_HEADERS */ + +struct arrayobject; /* Forward */ + +/* All possible arraydescr values are defined in the vector "descriptors" + * below. That's defined later because the appropriate get and set + * functions aren't visible yet. + */ +struct arraydescr { + int typecode; + int itemsize; + PyObject * (*getitem)(struct arrayobject *, Py_ssize_t); + int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *); +}; + +typedef struct arrayobject { + PyObject_VAR_HEAD + char *ob_item; + Py_ssize_t allocated; + struct arraydescr *ob_descr; + PyObject *weakreflist; /* List of weak references */ +} arrayobject; + +static PyTypeObject Arraytype; + +#define array_Check(op) PyObject_TypeCheck(op, &Arraytype) +#define array_CheckExact(op) ((op)->ob_type == &Arraytype) + +static int +array_resize(arrayobject *self, Py_ssize_t newsize) +{ + char *items; + size_t _new_size; + + /* Bypass realloc() when a previous overallocation is large enough + to accommodate the newsize. If the newsize is 16 smaller than the + current size, then proceed with the realloc() to shrink the list. + */ + + if (self->allocated >= newsize && + self->ob_size < newsize + 16 && + self->ob_item != NULL) { + self->ob_size = newsize; + return 0; + } + + /* This over-allocates proportional to the array size, making room + * for additional growth. The over-allocation is mild, but is + * enough to give linear-time amortized behavior over a long + * sequence of appends() in the presence of a poorly-performing + * system realloc(). + * The growth pattern is: 0, 4, 8, 16, 25, 34, 46, 56, 67, 79, ... + * Note, the pattern starts out the same as for lists but then + * grows at a smaller rate so that larger arrays only overallocate + * by about 1/16th -- this is done because arrays are presumed to be more + * memory critical. + */ + + _new_size = (newsize >> 4) + (self->ob_size < 8 ? 3 : 7) + newsize; + items = self->ob_item; + /* XXX The following multiplication and division does not optimize away + like it does for lists since the size is not known at compile time */ + if (_new_size <= ((~(size_t)0) / self->ob_descr->itemsize)) + PyMem_RESIZE(items, char, (_new_size * self->ob_descr->itemsize)); + else + items = NULL; + if (items == NULL) { + PyErr_NoMemory(); + return -1; + } + self->ob_item = items; + self->ob_size = newsize; + self->allocated = _new_size; + return 0; +} + +/**************************************************************************** +Get and Set functions for each type. +A Get function takes an arrayobject* and an integer index, returning the +array value at that index wrapped in an appropriate PyObject*. +A Set function takes an arrayobject, integer index, and PyObject*; sets +the array value at that index to the raw C data extracted from the PyObject*, +and returns 0 if successful, else nonzero on failure (PyObject* not of an +appropriate type or value). +Note that the basic Get and Set functions do NOT check that the index is +in bounds; that's the responsibility of the caller. +****************************************************************************/ + +static PyObject * +c_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyString_FromStringAndSize(&((char *)ap->ob_item)[i], 1); +} + +static int +c_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + char x; + if (!PyArg_Parse(v, "c;array item must be char", &x)) + return -1; + if (i >= 0) + ((char *)ap->ob_item)[i] = x; + return 0; +} + +static PyObject * +b_getitem(arrayobject *ap, Py_ssize_t i) +{ + long x = ((char *)ap->ob_item)[i]; + if (x >= 128) + x -= 256; + return PyInt_FromLong(x); +} + +static int +b_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + short x; + /* PyArg_Parse's 'b' formatter is for an unsigned char, therefore + must use the next size up that is signed ('h') and manually do + the overflow checking */ + if (!PyArg_Parse(v, "h;array item must be integer", &x)) + return -1; + else if (x < -128) { + PyErr_SetString(PyExc_OverflowError, + "signed char is less than minimum"); + return -1; + } + else if (x > 127) { + PyErr_SetString(PyExc_OverflowError, + "signed char is greater than maximum"); + return -1; + } + if (i >= 0) + ((char *)ap->ob_item)[i] = (char)x; + return 0; +} + +static PyObject * +BB_getitem(arrayobject *ap, Py_ssize_t i) +{ + long x = ((unsigned char *)ap->ob_item)[i]; + return PyInt_FromLong(x); +} + +static int +BB_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + unsigned char x; + /* 'B' == unsigned char, maps to PyArg_Parse's 'b' formatter */ + if (!PyArg_Parse(v, "b;array item must be integer", &x)) + return -1; + if (i >= 0) + ((char *)ap->ob_item)[i] = x; + return 0; +} + +#ifdef Py_USING_UNICODE +static PyObject * +u_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyUnicode_FromUnicode(&((Py_UNICODE *) ap->ob_item)[i], 1); +} + +static int +u_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + Py_UNICODE *p; + Py_ssize_t len; + + if (!PyArg_Parse(v, "u#;array item must be unicode character", &p, &len)) + return -1; + if (len != 1) { + PyErr_SetString(PyExc_TypeError, + "array item must be unicode character"); + return -1; + } + if (i >= 0) + ((Py_UNICODE *)ap->ob_item)[i] = p[0]; + return 0; +} +#endif + +static PyObject * +h_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyInt_FromLong((long) ((short *)ap->ob_item)[i]); +} + +static int +h_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + short x; + /* 'h' == signed short, maps to PyArg_Parse's 'h' formatter */ + if (!PyArg_Parse(v, "h;array item must be integer", &x)) + return -1; + if (i >= 0) + ((short *)ap->ob_item)[i] = x; + return 0; +} + +static PyObject * +HH_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyInt_FromLong((long) ((unsigned short *)ap->ob_item)[i]); +} + +static int +HH_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + int x; + /* PyArg_Parse's 'h' formatter is for a signed short, therefore + must use the next size up and manually do the overflow checking */ + if (!PyArg_Parse(v, "i;array item must be integer", &x)) + return -1; + else if (x < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned short is less than minimum"); + return -1; + } + else if (x > USHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned short is greater than maximum"); + return -1; + } + if (i >= 0) + ((short *)ap->ob_item)[i] = (short)x; + return 0; +} + +static PyObject * +i_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyInt_FromLong((long) ((int *)ap->ob_item)[i]); +} + +static int +i_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + int x; + /* 'i' == signed int, maps to PyArg_Parse's 'i' formatter */ + if (!PyArg_Parse(v, "i;array item must be integer", &x)) + return -1; + if (i >= 0) + ((int *)ap->ob_item)[i] = x; + return 0; +} + +static PyObject * +II_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyLong_FromUnsignedLong( + (unsigned long) ((unsigned int *)ap->ob_item)[i]); +} + +static int +II_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + unsigned long x; + if (PyLong_Check(v)) { + x = PyLong_AsUnsignedLong(v); + if (x == (unsigned long) -1 && PyErr_Occurred()) + return -1; + } + else { + long y; + if (!PyArg_Parse(v, "l;array item must be integer", &y)) + return -1; + if (y < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned int is less than minimum"); + return -1; + } + x = (unsigned long)y; + + } + if (x > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned int is greater than maximum"); + return -1; + } + + if (i >= 0) + ((unsigned int *)ap->ob_item)[i] = (unsigned int)x; + return 0; +} + +static PyObject * +l_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyInt_FromLong(((long *)ap->ob_item)[i]); +} + +static int +l_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + long x; + if (!PyArg_Parse(v, "l;array item must be integer", &x)) + return -1; + if (i >= 0) + ((long *)ap->ob_item)[i] = x; + return 0; +} + +static PyObject * +LL_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyLong_FromUnsignedLong(((unsigned long *)ap->ob_item)[i]); +} + +static int +LL_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + unsigned long x; + if (PyLong_Check(v)) { + x = PyLong_AsUnsignedLong(v); + if (x == (unsigned long) -1 && PyErr_Occurred()) + return -1; + } + else { + long y; + if (!PyArg_Parse(v, "l;array item must be integer", &y)) + return -1; + if (y < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned long is less than minimum"); + return -1; + } + x = (unsigned long)y; + + } + if (x > ULONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned long is greater than maximum"); + return -1; + } + + if (i >= 0) + ((unsigned long *)ap->ob_item)[i] = x; + return 0; +} + +static PyObject * +f_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyFloat_FromDouble((double) ((float *)ap->ob_item)[i]); +} + +static int +f_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + float x; + if (!PyArg_Parse(v, "f;array item must be float", &x)) + return -1; + if (i >= 0) + ((float *)ap->ob_item)[i] = x; + return 0; +} + +static PyObject * +d_getitem(arrayobject *ap, Py_ssize_t i) +{ + return PyFloat_FromDouble(((double *)ap->ob_item)[i]); +} + +static int +d_setitem(arrayobject *ap, Py_ssize_t i, PyObject *v) +{ + double x; + if (!PyArg_Parse(v, "d;array item must be float", &x)) + return -1; + if (i >= 0) + ((double *)ap->ob_item)[i] = x; + return 0; +} + +/* Description of types */ +static struct arraydescr descriptors[] = { + {'c', sizeof(char), c_getitem, c_setitem}, + {'b', sizeof(char), b_getitem, b_setitem}, + {'B', sizeof(char), BB_getitem, BB_setitem}, +#ifdef Py_USING_UNICODE + {'u', sizeof(Py_UNICODE), u_getitem, u_setitem}, +#endif + {'h', sizeof(short), h_getitem, h_setitem}, + {'H', sizeof(short), HH_getitem, HH_setitem}, + {'i', sizeof(int), i_getitem, i_setitem}, + {'I', sizeof(int), II_getitem, II_setitem}, + {'l', sizeof(long), l_getitem, l_setitem}, + {'L', sizeof(long), LL_getitem, LL_setitem}, + {'f', sizeof(float), f_getitem, f_setitem}, + {'d', sizeof(double), d_getitem, d_setitem}, + {'\0', 0, 0, 0} /* Sentinel */ +}; + +/**************************************************************************** +Implementations of array object methods. +****************************************************************************/ + +static PyObject * +newarrayobject(PyTypeObject *type, Py_ssize_t size, struct arraydescr *descr) +{ + arrayobject *op; + size_t nbytes; + + if (size < 0) { + PyErr_BadInternalCall(); + return NULL; + } + + nbytes = size * descr->itemsize; + /* Check for overflow */ + if (nbytes / descr->itemsize != (size_t)size) { + return PyErr_NoMemory(); + } + op = (arrayobject *) type->tp_alloc(type, 0); + if (op == NULL) { + return NULL; + } + op->ob_size = size; + if (size <= 0) { + op->ob_item = NULL; + } + else { + op->ob_item = PyMem_NEW(char, nbytes); + if (op->ob_item == NULL) { + PyObject_Del(op); + return PyErr_NoMemory(); + } + } + op->ob_descr = descr; + op->allocated = size; + op->weakreflist = NULL; + return (PyObject *) op; +} + +static PyObject * +getarrayitem(PyObject *op, Py_ssize_t i) +{ + register arrayobject *ap; + assert(array_Check(op)); + ap = (arrayobject *)op; + assert(i>=0 && i<ap->ob_size); + return (*ap->ob_descr->getitem)(ap, i); +} + +static int +ins1(arrayobject *self, Py_ssize_t where, PyObject *v) +{ + char *items; + Py_ssize_t n = self->ob_size; + if (v == NULL) { + PyErr_BadInternalCall(); + return -1; + } + if ((*self->ob_descr->setitem)(self, -1, v) < 0) + return -1; + + if (array_resize(self, n+1) == -1) + return -1; + items = self->ob_item; + if (where < 0) { + where += n; + if (where < 0) + where = 0; + } + if (where > n) + where = n; + /* appends don't need to call memmove() */ + if (where != n) + memmove(items + (where+1)*self->ob_descr->itemsize, + items + where*self->ob_descr->itemsize, + (n-where)*self->ob_descr->itemsize); + return (*self->ob_descr->setitem)(self, where, v); +} + +/* Methods */ + +static void +array_dealloc(arrayobject *op) +{ + if (op->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) op); + if (op->ob_item != NULL) + PyMem_DEL(op->ob_item); + op->ob_type->tp_free((PyObject *)op); +} + +static PyObject * +array_richcompare(PyObject *v, PyObject *w, int op) +{ + arrayobject *va, *wa; + PyObject *vi = NULL; + PyObject *wi = NULL; + Py_ssize_t i, k; + PyObject *res; + + if (!array_Check(v) || !array_Check(w)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + va = (arrayobject *)v; + wa = (arrayobject *)w; + + if (va->ob_size != wa->ob_size && (op == Py_EQ || op == Py_NE)) { + /* Shortcut: if the lengths differ, the arrays differ */ + if (op == Py_EQ) + res = Py_False; + else + res = Py_True; + Py_INCREF(res); + return res; + } + + /* Search for the first index where items are different */ + k = 1; + for (i = 0; i < va->ob_size && i < wa->ob_size; i++) { + vi = getarrayitem(v, i); + wi = getarrayitem(w, i); + if (vi == NULL || wi == NULL) { + Py_XDECREF(vi); + Py_XDECREF(wi); + return NULL; + } + k = PyObject_RichCompareBool(vi, wi, Py_EQ); + if (k == 0) + break; /* Keeping vi and wi alive! */ + Py_DECREF(vi); + Py_DECREF(wi); + if (k < 0) + return NULL; + } + + if (k) { + /* No more items to compare -- compare sizes */ + Py_ssize_t vs = va->ob_size; + Py_ssize_t ws = wa->ob_size; + int cmp; + switch (op) { + case Py_LT: cmp = vs < ws; break; + case Py_LE: cmp = vs <= ws; break; + case Py_EQ: cmp = vs == ws; break; + case Py_NE: cmp = vs != ws; break; + case Py_GT: cmp = vs > ws; break; + case Py_GE: cmp = vs >= ws; break; + default: return NULL; /* cannot happen */ + } + if (cmp) + res = Py_True; + else + res = Py_False; + Py_INCREF(res); + return res; + } + + /* We have an item that differs. First, shortcuts for EQ/NE */ + if (op == Py_EQ) { + Py_INCREF(Py_False); + res = Py_False; + } + else if (op == Py_NE) { + Py_INCREF(Py_True); + res = Py_True; + } + else { + /* Compare the final item again using the proper operator */ + res = PyObject_RichCompare(vi, wi, op); + } + Py_DECREF(vi); + Py_DECREF(wi); + return res; +} + +static Py_ssize_t +array_length(arrayobject *a) +{ + return a->ob_size; +} + +static PyObject * +array_item(arrayobject *a, Py_ssize_t i) +{ + if (i < 0 || i >= a->ob_size) { + PyErr_SetString(PyExc_IndexError, "array index out of range"); + return NULL; + } + return getarrayitem((PyObject *)a, i); +} + +static PyObject * +array_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh) +{ + arrayobject *np; + if (ilow < 0) + ilow = 0; + else if (ilow > a->ob_size) + ilow = a->ob_size; + if (ihigh < 0) + ihigh = 0; + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > a->ob_size) + ihigh = a->ob_size; + np = (arrayobject *) newarrayobject(&Arraytype, ihigh - ilow, a->ob_descr); + if (np == NULL) + return NULL; + memcpy(np->ob_item, a->ob_item + ilow * a->ob_descr->itemsize, + (ihigh-ilow) * a->ob_descr->itemsize); + return (PyObject *)np; +} + +static PyObject * +array_copy(arrayobject *a, PyObject *unused) +{ + return array_slice(a, 0, a->ob_size); +} + +PyDoc_STRVAR(copy_doc, +"copy(array)\n\ +\n\ + Return a copy of the array."); + +static PyObject * +array_concat(arrayobject *a, PyObject *bb) +{ + Py_ssize_t size; + arrayobject *np; + if (!array_Check(bb)) { + PyErr_Format(PyExc_TypeError, + "can only append array (not \"%.200s\") to array", + bb->ob_type->tp_name); + return NULL; + } +#define b ((arrayobject *)bb) + if (a->ob_descr != b->ob_descr) { + PyErr_BadArgument(); + return NULL; + } + size = a->ob_size + b->ob_size; + np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr); + if (np == NULL) { + return NULL; + } + memcpy(np->ob_item, a->ob_item, a->ob_size*a->ob_descr->itemsize); + memcpy(np->ob_item + a->ob_size*a->ob_descr->itemsize, + b->ob_item, b->ob_size*b->ob_descr->itemsize); + return (PyObject *)np; +#undef b +} + +static PyObject * +array_repeat(arrayobject *a, Py_ssize_t n) +{ + Py_ssize_t i; + Py_ssize_t size; + arrayobject *np; + char *p; + Py_ssize_t nbytes; + if (n < 0) + n = 0; + size = a->ob_size * n; + np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr); + if (np == NULL) + return NULL; + p = np->ob_item; + nbytes = a->ob_size * a->ob_descr->itemsize; + for (i = 0; i < n; i++) { + memcpy(p, a->ob_item, nbytes); + p += nbytes; + } + return (PyObject *) np; +} + +static int +array_ass_slice(arrayobject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) +{ + char *item; + Py_ssize_t n; /* Size of replacement array */ + Py_ssize_t d; /* Change in size */ +#define b ((arrayobject *)v) + if (v == NULL) + n = 0; + else if (array_Check(v)) { + n = b->ob_size; + if (a == b) { + /* Special case "a[i:j] = a" -- copy b first */ + int ret; + v = array_slice(b, 0, n); + if (!v) + return -1; + ret = array_ass_slice(a, ilow, ihigh, v); + Py_DECREF(v); + return ret; + } + if (b->ob_descr != a->ob_descr) { + PyErr_BadArgument(); + return -1; + } + } + else { + PyErr_Format(PyExc_TypeError, + "can only assign array (not \"%.200s\") to array slice", + v->ob_type->tp_name); + return -1; + } + if (ilow < 0) + ilow = 0; + else if (ilow > a->ob_size) + ilow = a->ob_size; + if (ihigh < 0) + ihigh = 0; + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > a->ob_size) + ihigh = a->ob_size; + item = a->ob_item; + d = n - (ihigh-ilow); + if (d < 0) { /* Delete -d items */ + memmove(item + (ihigh+d)*a->ob_descr->itemsize, + item + ihigh*a->ob_descr->itemsize, + (a->ob_size-ihigh)*a->ob_descr->itemsize); + a->ob_size += d; + PyMem_RESIZE(item, char, a->ob_size*a->ob_descr->itemsize); + /* Can't fail */ + a->ob_item = item; + a->allocated = a->ob_size; + } + else if (d > 0) { /* Insert d items */ + PyMem_RESIZE(item, char, + (a->ob_size + d)*a->ob_descr->itemsize); + if (item == NULL) { + PyErr_NoMemory(); + return -1; + } + memmove(item + (ihigh+d)*a->ob_descr->itemsize, + item + ihigh*a->ob_descr->itemsize, + (a->ob_size-ihigh)*a->ob_descr->itemsize); + a->ob_item = item; + a->ob_size += d; + a->allocated = a->ob_size; + } + if (n > 0) + memcpy(item + ilow*a->ob_descr->itemsize, b->ob_item, + n*b->ob_descr->itemsize); + return 0; +#undef b +} + +static int +array_ass_item(arrayobject *a, Py_ssize_t i, PyObject *v) +{ + if (i < 0 || i >= a->ob_size) { + PyErr_SetString(PyExc_IndexError, + "array assignment index out of range"); + return -1; + } + if (v == NULL) + return array_ass_slice(a, i, i+1, v); + return (*a->ob_descr->setitem)(a, i, v); +} + +static int +setarrayitem(PyObject *a, Py_ssize_t i, PyObject *v) +{ + assert(array_Check(a)); + return array_ass_item((arrayobject *)a, i, v); +} + +static int +array_iter_extend(arrayobject *self, PyObject *bb) +{ + PyObject *it, *v; + + it = PyObject_GetIter(bb); + if (it == NULL) + return -1; + + while ((v = PyIter_Next(it)) != NULL) { + if (ins1(self, (int) self->ob_size, v) != 0) { + Py_DECREF(v); + Py_DECREF(it); + return -1; + } + Py_DECREF(v); + } + Py_DECREF(it); + if (PyErr_Occurred()) + return -1; + return 0; +} + +static int +array_do_extend(arrayobject *self, PyObject *bb) +{ + Py_ssize_t size; + + if (!array_Check(bb)) + return array_iter_extend(self, bb); +#define b ((arrayobject *)bb) + if (self->ob_descr != b->ob_descr) { + PyErr_SetString(PyExc_TypeError, + "can only extend with array of same kind"); + return -1; + } + size = self->ob_size + b->ob_size; + PyMem_RESIZE(self->ob_item, char, size*self->ob_descr->itemsize); + if (self->ob_item == NULL) { + PyObject_Del(self); + PyErr_NoMemory(); + return -1; + } + memcpy(self->ob_item + self->ob_size*self->ob_descr->itemsize, + b->ob_item, b->ob_size*b->ob_descr->itemsize); + self->ob_size = size; + self->allocated = size; + + return 0; +#undef b +} + +static PyObject * +array_inplace_concat(arrayobject *self, PyObject *bb) +{ + if (!array_Check(bb)) { + PyErr_Format(PyExc_TypeError, + "can only extend array with array (not \"%.200s\")", + bb->ob_type->tp_name); + return NULL; + } + if (array_do_extend(self, bb) == -1) + return NULL; + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +array_inplace_repeat(arrayobject *self, Py_ssize_t n) +{ + char *items, *p; + Py_ssize_t size, i; + + if (self->ob_size > 0) { + if (n < 0) + n = 0; + items = self->ob_item; + size = self->ob_size * self->ob_descr->itemsize; + if (n == 0) { + PyMem_FREE(items); + self->ob_item = NULL; + self->ob_size = 0; + self->allocated = 0; + } + else { + PyMem_Resize(items, char, n * size); + if (items == NULL) + return PyErr_NoMemory(); + p = items; + for (i = 1; i < n; i++) { + p += size; + memcpy(p, items, size); + } + self->ob_item = items; + self->ob_size *= n; + self->allocated = self->ob_size; + } + } + Py_INCREF(self); + return (PyObject *)self; +} + + +static PyObject * +ins(arrayobject *self, Py_ssize_t where, PyObject *v) +{ + if (ins1(self, where, v) != 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +array_count(arrayobject *self, PyObject *v) +{ + Py_ssize_t count = 0; + Py_ssize_t i; + + for (i = 0; i < self->ob_size; i++) { + PyObject *selfi = getarrayitem((PyObject *)self, i); + int cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); + Py_DECREF(selfi); + if (cmp > 0) + count++; + else if (cmp < 0) + return NULL; + } + return PyInt_FromSsize_t(count); +} + +PyDoc_STRVAR(count_doc, +"count(x)\n\ +\n\ +Return number of occurences of x in the array."); + +static PyObject * +array_index(arrayobject *self, PyObject *v) +{ + Py_ssize_t i; + + for (i = 0; i < self->ob_size; i++) { + PyObject *selfi = getarrayitem((PyObject *)self, i); + int cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); + Py_DECREF(selfi); + if (cmp > 0) { + return PyInt_FromLong((long)i); + } + else if (cmp < 0) + return NULL; + } + PyErr_SetString(PyExc_ValueError, "array.index(x): x not in list"); + return NULL; +} + +PyDoc_STRVAR(index_doc, +"index(x)\n\ +\n\ +Return index of first occurence of x in the array."); + +static int +array_contains(arrayobject *self, PyObject *v) +{ + Py_ssize_t i; + int cmp; + + for (i = 0, cmp = 0 ; cmp == 0 && i < self->ob_size; i++) { + PyObject *selfi = getarrayitem((PyObject *)self, i); + cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); + Py_DECREF(selfi); + } + return cmp; +} + +static PyObject * +array_remove(arrayobject *self, PyObject *v) +{ + int i; + + for (i = 0; i < self->ob_size; i++) { + PyObject *selfi = getarrayitem((PyObject *)self,i); + int cmp = PyObject_RichCompareBool(selfi, v, Py_EQ); + Py_DECREF(selfi); + if (cmp > 0) { + if (array_ass_slice(self, i, i+1, + (PyObject *)NULL) != 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; + } + else if (cmp < 0) + return NULL; + } + PyErr_SetString(PyExc_ValueError, "array.remove(x): x not in list"); + return NULL; +} + +PyDoc_STRVAR(remove_doc, +"remove(x)\n\ +\n\ +Remove the first occurence of x in the array."); + +static PyObject * +array_pop(arrayobject *self, PyObject *args) +{ + Py_ssize_t i = -1; + PyObject *v; + if (!PyArg_ParseTuple(args, "|n:pop", &i)) + return NULL; + if (self->ob_size == 0) { + /* Special-case most common failure cause */ + PyErr_SetString(PyExc_IndexError, "pop from empty array"); + return NULL; + } + if (i < 0) + i += self->ob_size; + if (i < 0 || i >= self->ob_size) { + PyErr_SetString(PyExc_IndexError, "pop index out of range"); + return NULL; + } + v = getarrayitem((PyObject *)self,i); + if (array_ass_slice(self, i, i+1, (PyObject *)NULL) != 0) { + Py_DECREF(v); + return NULL; + } + return v; +} + +PyDoc_STRVAR(pop_doc, +"pop([i])\n\ +\n\ +Return the i-th element and delete it from the array. i defaults to -1."); + +static PyObject * +array_extend(arrayobject *self, PyObject *bb) +{ + if (array_do_extend(self, bb) == -1) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(extend_doc, +"extend(array or iterable)\n\ +\n\ + Append items to the end of the array."); + +static PyObject * +array_insert(arrayobject *self, PyObject *args) +{ + Py_ssize_t i; + PyObject *v; + if (!PyArg_ParseTuple(args, "nO:insert", &i, &v)) + return NULL; + return ins(self, i, v); +} + +PyDoc_STRVAR(insert_doc, +"insert(i,x)\n\ +\n\ +Insert a new item x into the array before position i."); + + +static PyObject * +array_buffer_info(arrayobject *self, PyObject *unused) +{ + PyObject* retval = NULL; + retval = PyTuple_New(2); + if (!retval) + return NULL; + + PyTuple_SET_ITEM(retval, 0, PyLong_FromVoidPtr(self->ob_item)); + PyTuple_SET_ITEM(retval, 1, PyInt_FromLong((long)(self->ob_size))); + + return retval; +} + +PyDoc_STRVAR(buffer_info_doc, +"buffer_info() -> (address, length)\n\ +\n\ +Return a tuple (address, length) giving the current memory address and\n\ +the length in items of the buffer used to hold array's contents\n\ +The length should be multiplied by the itemsize attribute to calculate\n\ +the buffer length in bytes."); + + +static PyObject * +array_append(arrayobject *self, PyObject *v) +{ + return ins(self, (int) self->ob_size, v); +} + +PyDoc_STRVAR(append_doc, +"append(x)\n\ +\n\ +Append new value x to the end of the array."); + + +static PyObject * +array_byteswap(arrayobject *self, PyObject *unused) +{ + char *p; + Py_ssize_t i; + + switch (self->ob_descr->itemsize) { + case 1: + break; + case 2: + for (p = self->ob_item, i = self->ob_size; --i >= 0; p += 2) { + char p0 = p[0]; + p[0] = p[1]; + p[1] = p0; + } + break; + case 4: + for (p = self->ob_item, i = self->ob_size; --i >= 0; p += 4) { + char p0 = p[0]; + char p1 = p[1]; + p[0] = p[3]; + p[1] = p[2]; + p[2] = p1; + p[3] = p0; + } + break; + case 8: + for (p = self->ob_item, i = self->ob_size; --i >= 0; p += 8) { + char p0 = p[0]; + char p1 = p[1]; + char p2 = p[2]; + char p3 = p[3]; + p[0] = p[7]; + p[1] = p[6]; + p[2] = p[5]; + p[3] = p[4]; + p[4] = p3; + p[5] = p2; + p[6] = p1; + p[7] = p0; + } + break; + default: + PyErr_SetString(PyExc_RuntimeError, + "don't know how to byteswap this array type"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(byteswap_doc, +"byteswap()\n\ +\n\ +Byteswap all items of the array. If the items in the array are not 1, 2,\n\ +4, or 8 bytes in size, RuntimeError is raised."); + +static PyObject * +array_reduce(arrayobject *array) +{ + PyObject *dict, *result; + + dict = PyObject_GetAttrString((PyObject *)array, "__dict__"); + if (dict == NULL) { + PyErr_Clear(); + dict = Py_None; + Py_INCREF(dict); + } + if (array->ob_size > 0) { + result = Py_BuildValue("O(cs#)O", + array->ob_type, + array->ob_descr->typecode, + array->ob_item, + array->ob_size * array->ob_descr->itemsize, + dict); + } else { + result = Py_BuildValue("O(c)O", + array->ob_type, + array->ob_descr->typecode, + dict); + } + Py_DECREF(dict); + return result; +} + +PyDoc_STRVAR(array_doc, "Return state information for pickling."); + +static PyObject * +array_reverse(arrayobject *self, PyObject *unused) +{ + register Py_ssize_t itemsize = self->ob_descr->itemsize; + register char *p, *q; + /* little buffer to hold items while swapping */ + char tmp[256]; /* 8 is probably enough -- but why skimp */ + assert((size_t)itemsize <= sizeof(tmp)); + + if (self->ob_size > 1) { + for (p = self->ob_item, + q = self->ob_item + (self->ob_size - 1)*itemsize; + p < q; + p += itemsize, q -= itemsize) { + /* memory areas guaranteed disjoint, so memcpy + * is safe (& memmove may be slower). + */ + memcpy(tmp, p, itemsize); + memcpy(p, q, itemsize); + memcpy(q, tmp, itemsize); + } + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(reverse_doc, +"reverse()\n\ +\n\ +Reverse the order of the items in the array."); + +static PyObject * +array_fromfile(arrayobject *self, PyObject *args) +{ + PyObject *f; + Py_ssize_t n; + FILE *fp; + if (!PyArg_ParseTuple(args, "On:fromfile", &f, &n)) + return NULL; + fp = PyFile_AsFile(f); + if (fp == NULL) { + PyErr_SetString(PyExc_TypeError, "arg1 must be open file"); + return NULL; + } + if (n > 0) { + char *item = self->ob_item; + Py_ssize_t itemsize = self->ob_descr->itemsize; + size_t nread; + Py_ssize_t newlength; + size_t newbytes; + /* Be careful here about overflow */ + if ((newlength = self->ob_size + n) <= 0 || + (newbytes = newlength * itemsize) / itemsize != + (size_t)newlength) + goto nomem; + PyMem_RESIZE(item, char, newbytes); + if (item == NULL) { + nomem: + PyErr_NoMemory(); + return NULL; + } + self->ob_item = item; + self->ob_size += n; + self->allocated = self->ob_size; + nread = fread(item + (self->ob_size - n) * itemsize, + itemsize, n, fp); + if (nread < (size_t)n) { + self->ob_size -= (n - nread); + PyMem_RESIZE(item, char, self->ob_size*itemsize); + self->ob_item = item; + self->allocated = self->ob_size; + PyErr_SetString(PyExc_EOFError, + "not enough items in file"); + return NULL; + } + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(fromfile_doc, +"fromfile(f, n)\n\ +\n\ +Read n objects from the file object f and append them to the end of the\n\ +array. Also called as read."); + + +static PyObject * +array_tofile(arrayobject *self, PyObject *f) +{ + FILE *fp; + + fp = PyFile_AsFile(f); + if (fp == NULL) { + PyErr_SetString(PyExc_TypeError, "arg must be open file"); + return NULL; + } + if (self->ob_size > 0) { + if (fwrite(self->ob_item, self->ob_descr->itemsize, + self->ob_size, fp) != (size_t)self->ob_size) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(fp); + return NULL; + } + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(tofile_doc, +"tofile(f)\n\ +\n\ +Write all items (as machine values) to the file object f. Also called as\n\ +write."); + + +static PyObject * +array_fromlist(arrayobject *self, PyObject *list) +{ + Py_ssize_t n; + Py_ssize_t itemsize = self->ob_descr->itemsize; + + if (!PyList_Check(list)) { + PyErr_SetString(PyExc_TypeError, "arg must be list"); + return NULL; + } + n = PyList_Size(list); + if (n > 0) { + char *item = self->ob_item; + Py_ssize_t i; + PyMem_RESIZE(item, char, (self->ob_size + n) * itemsize); + if (item == NULL) { + PyErr_NoMemory(); + return NULL; + } + self->ob_item = item; + self->ob_size += n; + self->allocated = self->ob_size; + for (i = 0; i < n; i++) { + PyObject *v = PyList_GetItem(list, i); + if ((*self->ob_descr->setitem)(self, + self->ob_size - n + i, v) != 0) { + self->ob_size -= n; + PyMem_RESIZE(item, char, + self->ob_size * itemsize); + self->ob_item = item; + self->allocated = self->ob_size; + return NULL; + } + } + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(fromlist_doc, +"fromlist(list)\n\ +\n\ +Append items to array from list."); + + +static PyObject * +array_tolist(arrayobject *self, PyObject *unused) +{ + PyObject *list = PyList_New(self->ob_size); + Py_ssize_t i; + + if (list == NULL) + return NULL; + for (i = 0; i < self->ob_size; i++) { + PyObject *v = getarrayitem((PyObject *)self, i); + if (v == NULL) { + Py_DECREF(list); + return NULL; + } + PyList_SetItem(list, i, v); + } + return list; +} + +PyDoc_STRVAR(tolist_doc, +"tolist() -> list\n\ +\n\ +Convert array to an ordinary list with the same items."); + + +static PyObject * +array_fromstring(arrayobject *self, PyObject *args) +{ + char *str; + Py_ssize_t n; + int itemsize = self->ob_descr->itemsize; + if (!PyArg_ParseTuple(args, "s#:fromstring", &str, &n)) + return NULL; + if (n % itemsize != 0) { + PyErr_SetString(PyExc_ValueError, + "string length not a multiple of item size"); + return NULL; + } + n = n / itemsize; + if (n > 0) { + char *item = self->ob_item; + PyMem_RESIZE(item, char, (self->ob_size + n) * itemsize); + if (item == NULL) { + PyErr_NoMemory(); + return NULL; + } + self->ob_item = item; + self->ob_size += n; + self->allocated = self->ob_size; + memcpy(item + (self->ob_size - n) * itemsize, + str, itemsize*n); + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(fromstring_doc, +"fromstring(string)\n\ +\n\ +Appends items from the string, interpreting it as an array of machine\n\ +values,as if it had been read from a file using the fromfile() method)."); + + +static PyObject * +array_tostring(arrayobject *self, PyObject *unused) +{ + return PyString_FromStringAndSize(self->ob_item, + self->ob_size * self->ob_descr->itemsize); +} + +PyDoc_STRVAR(tostring_doc, +"tostring() -> string\n\ +\n\ +Convert the array to an array of machine values and return the string\n\ +representation."); + + + +#ifdef Py_USING_UNICODE +static PyObject * +array_fromunicode(arrayobject *self, PyObject *args) +{ + Py_UNICODE *ustr; + Py_ssize_t n; + + if (!PyArg_ParseTuple(args, "u#:fromunicode", &ustr, &n)) + return NULL; + if (self->ob_descr->typecode != 'u') { + PyErr_SetString(PyExc_ValueError, + "fromunicode() may only be called on " + "type 'u' arrays"); + return NULL; + } + if (n > 0) { + Py_UNICODE *item = (Py_UNICODE *) self->ob_item; + PyMem_RESIZE(item, Py_UNICODE, self->ob_size + n); + if (item == NULL) { + PyErr_NoMemory(); + return NULL; + } + self->ob_item = (char *) item; + self->ob_size += n; + self->allocated = self->ob_size; + memcpy(item + self->ob_size - n, + ustr, n * sizeof(Py_UNICODE)); + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(fromunicode_doc, +"fromunicode(ustr)\n\ +\n\ +Extends this array with data from the unicode string ustr.\n\ +The array must be a type 'u' array; otherwise a ValueError\n\ +is raised. Use array.fromstring(ustr.decode(...)) to\n\ +append Unicode data to an array of some other type."); + + +static PyObject * +array_tounicode(arrayobject *self, PyObject *unused) +{ + if (self->ob_descr->typecode != 'u') { + PyErr_SetString(PyExc_ValueError, + "tounicode() may only be called on type 'u' arrays"); + return NULL; + } + return PyUnicode_FromUnicode((Py_UNICODE *) self->ob_item, self->ob_size); +} + +PyDoc_STRVAR(tounicode_doc, +"tounicode() -> unicode\n\ +\n\ +Convert the array to a unicode string. The array must be\n\ +a type 'u' array; otherwise a ValueError is raised. Use\n\ +array.tostring().decode() to obtain a unicode string from\n\ +an array of some other type."); + +#endif /* Py_USING_UNICODE */ + + +static PyObject * +array_get_typecode(arrayobject *a, void *closure) +{ + char tc = a->ob_descr->typecode; + return PyString_FromStringAndSize(&tc, 1); +} + +static PyObject * +array_get_itemsize(arrayobject *a, void *closure) +{ + return PyInt_FromLong((long)a->ob_descr->itemsize); +} + +static PyGetSetDef array_getsets [] = { + {"typecode", (getter) array_get_typecode, NULL, + "the typecode character used to create the array"}, + {"itemsize", (getter) array_get_itemsize, NULL, + "the size, in bytes, of one array item"}, + {NULL} +}; + +PyMethodDef array_methods[] = { + {"append", (PyCFunction)array_append, METH_O, + append_doc}, + {"buffer_info", (PyCFunction)array_buffer_info, METH_NOARGS, + buffer_info_doc}, + {"byteswap", (PyCFunction)array_byteswap, METH_NOARGS, + byteswap_doc}, + {"__copy__", (PyCFunction)array_copy, METH_NOARGS, + copy_doc}, + {"count", (PyCFunction)array_count, METH_O, + count_doc}, + {"__deepcopy__",(PyCFunction)array_copy, METH_O, + copy_doc}, + {"extend", (PyCFunction)array_extend, METH_O, + extend_doc}, + {"fromfile", (PyCFunction)array_fromfile, METH_VARARGS, + fromfile_doc}, + {"fromlist", (PyCFunction)array_fromlist, METH_O, + fromlist_doc}, + {"fromstring", (PyCFunction)array_fromstring, METH_VARARGS, + fromstring_doc}, +#ifdef Py_USING_UNICODE + {"fromunicode", (PyCFunction)array_fromunicode, METH_VARARGS, + fromunicode_doc}, +#endif + {"index", (PyCFunction)array_index, METH_O, + index_doc}, + {"insert", (PyCFunction)array_insert, METH_VARARGS, + insert_doc}, + {"pop", (PyCFunction)array_pop, METH_VARARGS, + pop_doc}, + {"read", (PyCFunction)array_fromfile, METH_VARARGS, + fromfile_doc}, + {"__reduce__", (PyCFunction)array_reduce, METH_NOARGS, + array_doc}, + {"remove", (PyCFunction)array_remove, METH_O, + remove_doc}, + {"reverse", (PyCFunction)array_reverse, METH_NOARGS, + reverse_doc}, +/* {"sort", (PyCFunction)array_sort, METH_VARARGS, + sort_doc},*/ + {"tofile", (PyCFunction)array_tofile, METH_O, + tofile_doc}, + {"tolist", (PyCFunction)array_tolist, METH_NOARGS, + tolist_doc}, + {"tostring", (PyCFunction)array_tostring, METH_NOARGS, + tostring_doc}, +#ifdef Py_USING_UNICODE + {"tounicode", (PyCFunction)array_tounicode, METH_NOARGS, + tounicode_doc}, +#endif + {"write", (PyCFunction)array_tofile, METH_O, + tofile_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +array_repr(arrayobject *a) +{ + char buf[256], typecode; + PyObject *s, *t, *v = NULL; + Py_ssize_t len; + + len = a->ob_size; + typecode = a->ob_descr->typecode; + if (len == 0) { + PyOS_snprintf(buf, sizeof(buf), "array('%c')", typecode); + return PyString_FromString(buf); + } + + if (typecode == 'c') + v = array_tostring(a, NULL); +#ifdef Py_USING_UNICODE + else if (typecode == 'u') + v = array_tounicode(a, NULL); +#endif + else + v = array_tolist(a, NULL); + t = PyObject_Repr(v); + Py_XDECREF(v); + + PyOS_snprintf(buf, sizeof(buf), "array('%c', ", typecode); + s = PyString_FromString(buf); + PyString_ConcatAndDel(&s, t); + PyString_ConcatAndDel(&s, PyString_FromString(")")); + return s; +} + +static PyObject* +array_subscr(arrayobject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i==-1 && PyErr_Occurred()) { + return NULL; + } + if (i < 0) + i += self->ob_size; + return array_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, cur, i; + PyObject* result; + arrayobject* ar; + int itemsize = self->ob_descr->itemsize; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->ob_size, + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return newarrayobject(&Arraytype, 0, self->ob_descr); + } + else { + result = newarrayobject(&Arraytype, slicelength, self->ob_descr); + if (!result) return NULL; + + ar = (arrayobject*)result; + + for (cur = start, i = 0; i < slicelength; + cur += step, i++) { + memcpy(ar->ob_item + i*itemsize, + self->ob_item + cur*itemsize, + itemsize); + } + + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "list indices must be integers"); + return NULL; + } +} + +static int +array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i==-1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += self->ob_size; + return array_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + int itemsize = self->ob_descr->itemsize; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->ob_size, + &start, &stop, &step, &slicelength) < 0) { + return -1; + } + + /* treat A[slice(a,b)] = v _exactly_ like A[a:b] = v */ + if (step == 1 && ((PySliceObject*)item)->step == Py_None) + return array_ass_slice(self, start, stop, value); + + if (value == NULL) { + /* delete slice */ + Py_ssize_t cur, i, extra; + + if (slicelength <= 0) + return 0; + + if (step < 0) { + stop = start + 1; + start = stop + step*(slicelength - 1) - 1; + step = -step; + } + + for (cur = start, i = 0; i < slicelength - 1; + cur += step, i++) { + memmove(self->ob_item + (cur - i)*itemsize, + self->ob_item + (cur + 1)*itemsize, + (step - 1) * itemsize); + } + extra = self->ob_size - (cur + 1); + if (extra > 0) { + memmove(self->ob_item + (cur - i)*itemsize, + self->ob_item + (cur + 1)*itemsize, + extra*itemsize); + } + + self->ob_size -= slicelength; + self->ob_item = (char *)PyMem_REALLOC(self->ob_item, + itemsize*self->ob_size); + self->allocated = self->ob_size; + + return 0; + } + else { + /* assign slice */ + Py_ssize_t cur, i; + arrayobject* av; + + if (!array_Check(value)) { + PyErr_Format(PyExc_TypeError, + "must assign array (not \"%.200s\") to slice", + value->ob_type->tp_name); + return -1; + } + + av = (arrayobject*)value; + + if (av->ob_size != slicelength) { + PyErr_Format(PyExc_ValueError, + "attempt to assign array of size %ld to extended slice of size %ld", + /*XXX*/(long)av->ob_size, /*XXX*/(long)slicelength); + return -1; + } + + if (!slicelength) + return 0; + + /* protect against a[::-1] = a */ + if (self == av) { + value = array_slice(av, 0, av->ob_size); + av = (arrayobject*)value; + if (!av) + return -1; + } + else { + Py_INCREF(value); + } + + for (cur = start, i = 0; i < slicelength; + cur += step, i++) { + memcpy(self->ob_item + cur*itemsize, + av->ob_item + i*itemsize, + itemsize); + } + + Py_DECREF(value); + + return 0; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "list indices must be integers"); + return -1; + } +} + +static PyMappingMethods array_as_mapping = { + (lenfunc)array_length, + (binaryfunc)array_subscr, + (objobjargproc)array_ass_subscr +}; + +static const void *emptybuf = ""; + +static Py_ssize_t +array_buffer_getreadbuf(arrayobject *self, Py_ssize_t index, const void **ptr) +{ + if ( index != 0 ) { + PyErr_SetString(PyExc_SystemError, + "Accessing non-existent array segment"); + return -1; + } + *ptr = (void *)self->ob_item; + if (*ptr == NULL) + *ptr = emptybuf; + return self->ob_size*self->ob_descr->itemsize; +} + +static Py_ssize_t +array_buffer_getwritebuf(arrayobject *self, Py_ssize_t index, const void **ptr) +{ + if ( index != 0 ) { + PyErr_SetString(PyExc_SystemError, + "Accessing non-existent array segment"); + return -1; + } + *ptr = (void *)self->ob_item; + if (*ptr == NULL) + *ptr = emptybuf; + return self->ob_size*self->ob_descr->itemsize; +} + +static Py_ssize_t +array_buffer_getsegcount(arrayobject *self, Py_ssize_t *lenp) +{ + if ( lenp ) + *lenp = self->ob_size*self->ob_descr->itemsize; + return 1; +} + +static PySequenceMethods array_as_sequence = { + (lenfunc)array_length, /*sq_length*/ + (binaryfunc)array_concat, /*sq_concat*/ + (ssizeargfunc)array_repeat, /*sq_repeat*/ + (ssizeargfunc)array_item, /*sq_item*/ + (ssizessizeargfunc)array_slice, /*sq_slice*/ + (ssizeobjargproc)array_ass_item, /*sq_ass_item*/ + (ssizessizeobjargproc)array_ass_slice, /*sq_ass_slice*/ + (objobjproc)array_contains, /*sq_contains*/ + (binaryfunc)array_inplace_concat, /*sq_inplace_concat*/ + (ssizeargfunc)array_inplace_repeat /*sq_inplace_repeat*/ +}; + +static PyBufferProcs array_as_buffer = { + (readbufferproc)array_buffer_getreadbuf, + (writebufferproc)array_buffer_getwritebuf, + (segcountproc)array_buffer_getsegcount, + NULL, +}; + +static PyObject * +array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + char c; + PyObject *initial = NULL, *it = NULL; + struct arraydescr *descr; + + if (type == &Arraytype && !_PyArg_NoKeywords("array.array()", kwds)) + return NULL; + + if (!PyArg_ParseTuple(args, "c|O:array", &c, &initial)) + return NULL; + + if (!(initial == NULL || PyList_Check(initial) + || PyString_Check(initial) || PyTuple_Check(initial) + || (c == 'u' && PyUnicode_Check(initial)))) { + it = PyObject_GetIter(initial); + if (it == NULL) + return NULL; + /* We set initial to NULL so that the subsequent code + will create an empty array of the appropriate type + and afterwards we can use array_iter_extend to populate + the array. + */ + initial = NULL; + } + for (descr = descriptors; descr->typecode != '\0'; descr++) { + if (descr->typecode == c) { + PyObject *a; + Py_ssize_t len; + + if (initial == NULL || !(PyList_Check(initial) + || PyTuple_Check(initial))) + len = 0; + else + len = PySequence_Size(initial); + + a = newarrayobject(type, len, descr); + if (a == NULL) + return NULL; + + if (len > 0) { + Py_ssize_t i; + for (i = 0; i < len; i++) { + PyObject *v = + PySequence_GetItem(initial, i); + if (v == NULL) { + Py_DECREF(a); + return NULL; + } + if (setarrayitem(a, i, v) != 0) { + Py_DECREF(v); + Py_DECREF(a); + return NULL; + } + Py_DECREF(v); + } + } else if (initial != NULL && PyString_Check(initial)) { + PyObject *t_initial, *v; + t_initial = PyTuple_Pack(1, initial); + if (t_initial == NULL) { + Py_DECREF(a); + return NULL; + } + v = array_fromstring((arrayobject *)a, + t_initial); + Py_DECREF(t_initial); + if (v == NULL) { + Py_DECREF(a); + return NULL; + } + Py_DECREF(v); +#ifdef Py_USING_UNICODE + } else if (initial != NULL && PyUnicode_Check(initial)) { + Py_ssize_t n = PyUnicode_GET_DATA_SIZE(initial); + if (n > 0) { + arrayobject *self = (arrayobject *)a; + char *item = self->ob_item; + item = (char *)PyMem_Realloc(item, n); + if (item == NULL) { + PyErr_NoMemory(); + Py_DECREF(a); + return NULL; + } + self->ob_item = item; + self->ob_size = n / sizeof(Py_UNICODE); + memcpy(item, PyUnicode_AS_DATA(initial), n); + self->allocated = self->ob_size; + } +#endif + } + if (it != NULL) { + if (array_iter_extend((arrayobject *)a, it) == -1) { + Py_DECREF(it); + Py_DECREF(a); + return NULL; + } + Py_DECREF(it); + } + return a; + } + } + PyErr_SetString(PyExc_ValueError, + "bad typecode (must be c, b, B, u, h, H, i, I, l, L, f or d)"); + return NULL; +} + + +PyDoc_STRVAR(module_doc, +"This module defines an object type which can efficiently represent\n\ +an array of basic values: characters, integers, floating point\n\ +numbers. Arrays are sequence types and behave very much like lists,\n\ +except that the type of objects stored in them is constrained. The\n\ +type is specified at object creation time by using a type code, which\n\ +is a single character. The following type codes are defined:\n\ +\n\ + Type code C Type Minimum size in bytes \n\ + 'c' character 1 \n\ + 'b' signed integer 1 \n\ + 'B' unsigned integer 1 \n\ + 'u' Unicode character 2 \n\ + 'h' signed integer 2 \n\ + 'H' unsigned integer 2 \n\ + 'i' signed integer 2 \n\ + 'I' unsigned integer 2 \n\ + 'l' signed integer 4 \n\ + 'L' unsigned integer 4 \n\ + 'f' floating point 4 \n\ + 'd' floating point 8 \n\ +\n\ +The constructor is:\n\ +\n\ +array(typecode [, initializer]) -- create a new array\n\ +"); + +PyDoc_STRVAR(arraytype_doc, +"array(typecode [, initializer]) -> array\n\ +\n\ +Return a new array whose items are restricted by typecode, and\n\ +initialized from the optional initializer value, which must be a list,\n\ +string. or iterable over elements of the appropriate type.\n\ +\n\ +Arrays represent basic values and behave very much like lists, except\n\ +the type of objects stored in them is constrained.\n\ +\n\ +Methods:\n\ +\n\ +append() -- append a new item to the end of the array\n\ +buffer_info() -- return information giving the current memory info\n\ +byteswap() -- byteswap all the items of the array\n\ +count() -- return number of occurences of an object\n\ +extend() -- extend array by appending multiple elements from an iterable\n\ +fromfile() -- read items from a file object\n\ +fromlist() -- append items from the list\n\ +fromstring() -- append items from the string\n\ +index() -- return index of first occurence of an object\n\ +insert() -- insert a new item into the array at a provided position\n\ +pop() -- remove and return item (default last)\n\ +read() -- DEPRECATED, use fromfile()\n\ +remove() -- remove first occurence of an object\n\ +reverse() -- reverse the order of the items in the array\n\ +tofile() -- write all items to a file object\n\ +tolist() -- return the array converted to an ordinary list\n\ +tostring() -- return the array converted to a string\n\ +write() -- DEPRECATED, use tofile()\n\ +\n\ +Attributes:\n\ +\n\ +typecode -- the typecode character used to create the array\n\ +itemsize -- the length in bytes of one array item\n\ +"); + +static PyObject *array_iter(arrayobject *ao); + +static PyTypeObject Arraytype = { + PyObject_HEAD_INIT(NULL) + 0, + "array.array", + sizeof(arrayobject), + 0, + (destructor)array_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)array_repr, /* tp_repr */ + 0, /* tp_as_number*/ + &array_as_sequence, /* tp_as_sequence*/ + &array_as_mapping, /* tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + &array_as_buffer, /* tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + arraytype_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + array_richcompare, /* tp_richcompare */ + offsetof(arrayobject, weakreflist), /* tp_weaklistoffset */ + (getiterfunc)array_iter, /* tp_iter */ + 0, /* tp_iternext */ + array_methods, /* tp_methods */ + 0, /* tp_members */ + array_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + array_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +/*********************** Array Iterator **************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t index; + arrayobject *ao; + PyObject * (*getitem)(struct arrayobject *, Py_ssize_t); +} arrayiterobject; + +static PyTypeObject PyArrayIter_Type; + +#define PyArrayIter_Check(op) PyObject_TypeCheck(op, &PyArrayIter_Type) + +static PyObject * +array_iter(arrayobject *ao) +{ + arrayiterobject *it; + + if (!array_Check(ao)) { + PyErr_BadInternalCall(); + return NULL; + } + + it = PyObject_GC_New(arrayiterobject, &PyArrayIter_Type); + if (it == NULL) + return NULL; + + Py_INCREF(ao); + it->ao = ao; + it->index = 0; + it->getitem = ao->ob_descr->getitem; + PyObject_GC_Track(it); + return (PyObject *)it; +} + +static PyObject * +arrayiter_next(arrayiterobject *it) +{ + assert(PyArrayIter_Check(it)); + if (it->index < it->ao->ob_size) + return (*it->getitem)(it->ao, it->index++); + return NULL; +} + +static void +arrayiter_dealloc(arrayiterobject *it) +{ + PyObject_GC_UnTrack(it); + Py_XDECREF(it->ao); + PyObject_GC_Del(it); +} + +static int +arrayiter_traverse(arrayiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->ao); + return 0; +} + +static PyTypeObject PyArrayIter_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "arrayiterator", /* tp_name */ + sizeof(arrayiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)arrayiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)arrayiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)arrayiter_next, /* tp_iternext */ + 0, /* tp_methods */ +}; + + +/*********************** Install Module **************************/ + +/* No functions in array module. */ +static PyMethodDef a_methods[] = { + {NULL, NULL, 0, NULL} /* Sentinel */ +}; + + +PyMODINIT_FUNC +initarray(void) +{ + PyObject *m; + + Arraytype.ob_type = &PyType_Type; + PyArrayIter_Type.ob_type = &PyType_Type; + m = Py_InitModule3("array", a_methods, module_doc); + if (m == NULL) + return; + + Py_INCREF((PyObject *)&Arraytype); + PyModule_AddObject(m, "ArrayType", (PyObject *)&Arraytype); + Py_INCREF((PyObject *)&Arraytype); + PyModule_AddObject(m, "array", (PyObject *)&Arraytype); + /* No need to check the error here, the caller will do that */ +} diff --git a/sys/src/cmd/python/Modules/audioop.c b/sys/src/cmd/python/Modules/audioop.c new file mode 100644 index 000000000..8f5d30c80 --- /dev/null +++ b/sys/src/cmd/python/Modules/audioop.c @@ -0,0 +1,1612 @@ + +/* audioopmodule - Module to detect peak values in arrays */ + +#include "Python.h" + +#if SIZEOF_INT == 4 +typedef int Py_Int32; +typedef unsigned int Py_UInt32; +#else +#if SIZEOF_LONG == 4 +typedef long Py_Int32; +typedef unsigned long Py_UInt32; +#else +#error "No 4-byte integral type" +#endif +#endif + +typedef short PyInt16; + +#if defined(__CHAR_UNSIGNED__) +#if defined(signed) +/* This module currently does not work on systems where only unsigned + characters are available. Take it out of Setup. Sorry. */ +#endif +#endif + +/* Code shamelessly stolen from sox, 12.17.7, g711.c +** (c) Craig Reese, Joe Campbell and Jeff Poskanzer 1989 */ + +/* From g711.c: + * + * December 30, 1994: + * Functions linear2alaw, linear2ulaw have been updated to correctly + * convert unquantized 16 bit values. + * Tables for direct u- to A-law and A- to u-law conversions have been + * corrected. + * Borge Lindberg, Center for PersonKommunikation, Aalborg University. + * bli@cpk.auc.dk + * + */ +#define BIAS 0x84 /* define the add-in bias for 16 bit samples */ +#define CLIP 32635 +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +static PyInt16 seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; +static PyInt16 seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + +static PyInt16 +search(PyInt16 val, PyInt16 *table, int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} +#define st_ulaw2linear16(uc) (_st_ulaw2linear16[uc]) +#define st_alaw2linear16(uc) (_st_alaw2linear16[uc]) + +static PyInt16 _st_ulaw2linear16[256] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, + -24956, -23932, -22908, -21884, -20860, -19836, -18812, + -17788, -16764, -15996, -15484, -14972, -14460, -13948, + -13436, -12924, -12412, -11900, -11388, -10876, -10364, + -9852, -9340, -8828, -8316, -7932, -7676, -7420, + -7164, -6908, -6652, -6396, -6140, -5884, -5628, + -5372, -5116, -4860, -4604, -4348, -4092, -3900, + -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, + -1980, -1884, -1820, -1756, -1692, -1628, -1564, + -1500, -1436, -1372, -1308, -1244, -1180, -1116, + -1052, -988, -924, -876, -844, -812, -780, + -748, -716, -684, -652, -620, -588, -556, + -524, -492, -460, -428, -396, -372, -356, + -340, -324, -308, -292, -276, -260, -244, + -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, + -8, 0, 32124, 31100, 30076, 29052, 28028, + 27004, 25980, 24956, 23932, 22908, 21884, 20860, + 19836, 18812, 17788, 16764, 15996, 15484, 14972, + 14460, 13948, 13436, 12924, 12412, 11900, 11388, + 10876, 10364, 9852, 9340, 8828, 8316, 7932, + 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, + 4092, 3900, 3772, 3644, 3516, 3388, 3260, + 3132, 3004, 2876, 2748, 2620, 2492, 2364, + 2236, 2108, 1980, 1884, 1820, 1756, 1692, + 1628, 1564, 1500, 1436, 1372, 1308, 1244, + 1180, 1116, 1052, 988, 924, 876, 844, + 812, 780, 748, 716, 684, 652, 620, + 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, + 260, 244, 228, 212, 196, 180, 164, + 148, 132, 120, 112, 104, 96, 88, + 80, 72, 64, 56, 48, 40, 32, + 24, 16, 8, 0 +}; + +/* + * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 14-bits. + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +static unsigned char +st_14linear2ulaw(PyInt16 pcm_val) /* 2's complement (14-bit range) */ +{ + PyInt16 mask; + PyInt16 seg; + unsigned char uval; + + /* The original sox code does this in the calling function, not here */ + pcm_val = pcm_val >> 2; + + /* u-law inverts all bits */ + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } + +} + +static PyInt16 _st_alaw2linear16[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, + -4736, -7552, -7296, -8064, -7808, -6528, -6272, + -7040, -6784, -2752, -2624, -3008, -2880, -2240, + -2112, -2496, -2368, -3776, -3648, -4032, -3904, + -3264, -3136, -3520, -3392, -22016, -20992, -24064, + -23040, -17920, -16896, -19968, -18944, -30208, -29184, + -32256, -31232, -26112, -25088, -28160, -27136, -11008, + -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, + -13568, -344, -328, -376, -360, -280, -264, + -312, -296, -472, -456, -504, -488, -408, + -392, -440, -424, -88, -72, -120, -104, + -24, -8, -56, -40, -216, -200, -248, + -232, -152, -136, -184, -168, -1376, -1312, + -1504, -1440, -1120, -1056, -1248, -1184, -1888, + -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, + -592, -944, -912, -1008, -976, -816, -784, + -880, -848, 5504, 5248, 6016, 5760, 4480, + 4224, 4992, 4736, 7552, 7296, 8064, 7808, + 6528, 6272, 7040, 6784, 2752, 2624, 3008, + 2880, 2240, 2112, 2496, 2368, 3776, 3648, + 4032, 3904, 3264, 3136, 3520, 3392, 22016, + 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, + 27136, 11008, 10496, 12032, 11520, 8960, 8448, + 9984, 9472, 15104, 14592, 16128, 15616, 13056, + 12544, 14080, 13568, 344, 328, 376, 360, + 280, 264, 312, 296, 472, 456, 504, + 488, 408, 392, 440, 424, 88, 72, + 120, 104, 24, 8, 56, 40, 216, + 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, + 1184, 1888, 1824, 2016, 1952, 1632, 1568, + 1760, 1696, 688, 656, 752, 720, 560, + 528, 624, 592, 944, 912, 1008, 976, + 816, 784, 880, 848 +}; + +/* + * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 13-bits. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +static unsigned char +st_linear2alaw(PyInt16 pcm_val) /* 2's complement (13-bit range) */ +{ + PyInt16 mask; + short seg; + unsigned char aval; + + /* The original sox code does this in the calling function, not here */ + pcm_val = pcm_val >> 3; + + /* A-law using even bit inversion */ + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + aval = (unsigned char) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } +} +/* End of code taken from sox */ + +/* Intel ADPCM step variation table */ +static int indexTable[16] = { + -1, -1, -1, -1, 2, 4, 6, 8, + -1, -1, -1, -1, 2, 4, 6, 8, +}; + +static int stepsizeTable[89] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + +#define CHARP(cp, i) ((signed char *)(cp+i)) +#define SHORTP(cp, i) ((short *)(cp+i)) +#define LONGP(cp, i) ((Py_Int32 *)(cp+i)) + + + +static PyObject *AudioopError; + +static PyObject * +audioop_getsample(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0; + int i; + + if ( !PyArg_ParseTuple(args, "s#ii:getsample", &cp, &len, &size, &i) ) + return 0; + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + if ( i < 0 || i >= len/size ) { + PyErr_SetString(AudioopError, "Index out of range"); + return 0; + } + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i*2); + else if ( size == 4 ) val = (int)*LONGP(cp, i*4); + return PyInt_FromLong(val); +} + +static PyObject * +audioop_max(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0; + int i; + int max = 0; + + if ( !PyArg_ParseTuple(args, "s#i:max", &cp, &len, &size) ) + return 0; + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + for ( i=0; i<len; i+= size) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + if ( val < 0 ) val = (-val); + if ( val > max ) max = val; + } + return PyInt_FromLong(max); +} + +static PyObject * +audioop_minmax(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0; + int i; + int min = 0x7fffffff, max = -0x7fffffff; + + if (!PyArg_ParseTuple(args, "s#i:minmax", &cp, &len, &size)) + return NULL; + if (size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return NULL; + } + for (i = 0; i < len; i += size) { + if (size == 1) val = (int) *CHARP(cp, i); + else if (size == 2) val = (int) *SHORTP(cp, i); + else if (size == 4) val = (int) *LONGP(cp, i); + if (val > max) max = val; + if (val < min) min = val; + } + return Py_BuildValue("(ii)", min, max); +} + +static PyObject * +audioop_avg(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0; + int i; + double avg = 0.0; + + if ( !PyArg_ParseTuple(args, "s#i:avg", &cp, &len, &size) ) + return 0; + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + for ( i=0; i<len; i+= size) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + avg += val; + } + if ( len == 0 ) + val = 0; + else + val = (int)(avg / (double)(len/size)); + return PyInt_FromLong(val); +} + +static PyObject * +audioop_rms(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0; + int i; + double sum_squares = 0.0; + + if ( !PyArg_ParseTuple(args, "s#i:rms", &cp, &len, &size) ) + return 0; + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + for ( i=0; i<len; i+= size) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + sum_squares += (double)val*(double)val; + } + if ( len == 0 ) + val = 0; + else + val = (int)sqrt(sum_squares / (double)(len/size)); + return PyInt_FromLong(val); +} + +static double _sum2(short *a, short *b, int len) +{ + int i; + double sum = 0.0; + + for( i=0; i<len; i++) { + sum = sum + (double)a[i]*(double)b[i]; + } + return sum; +} + +/* +** Findfit tries to locate a sample within another sample. Its main use +** is in echo-cancellation (to find the feedback of the output signal in +** the input signal). +** The method used is as follows: +** +** let R be the reference signal (length n) and A the input signal (length N) +** with N > n, and let all sums be over i from 0 to n-1. +** +** Now, for each j in {0..N-n} we compute a factor fj so that -fj*R matches A +** as good as possible, i.e. sum( (A[j+i]+fj*R[i])^2 ) is minimal. This +** equation gives fj = sum( A[j+i]R[i] ) / sum(R[i]^2). +** +** Next, we compute the relative distance between the original signal and +** the modified signal and minimize that over j: +** vj = sum( (A[j+i]-fj*R[i])^2 ) / sum( A[j+i]^2 ) => +** vj = ( sum(A[j+i]^2)*sum(R[i]^2) - sum(A[j+i]R[i])^2 ) / sum( A[j+i]^2 ) +** +** In the code variables correspond as follows: +** cp1 A +** cp2 R +** len1 N +** len2 n +** aj_m1 A[j-1] +** aj_lm1 A[j+n-1] +** sum_ri_2 sum(R[i]^2) +** sum_aij_2 sum(A[i+j]^2) +** sum_aij_ri sum(A[i+j]R[i]) +** +** sum_ri is calculated once, sum_aij_2 is updated each step and sum_aij_ri +** is completely recalculated each step. +*/ +static PyObject * +audioop_findfit(PyObject *self, PyObject *args) +{ + short *cp1, *cp2; + int len1, len2; + int j, best_j; + double aj_m1, aj_lm1; + double sum_ri_2, sum_aij_2, sum_aij_ri, result, best_result, factor; + + if ( !PyArg_ParseTuple(args, "s#s#:findfit", + &cp1, &len1, &cp2, &len2) ) + return 0; + if ( len1 & 1 || len2 & 1 ) { + PyErr_SetString(AudioopError, "Strings should be even-sized"); + return 0; + } + len1 >>= 1; + len2 >>= 1; + + if ( len1 < len2 ) { + PyErr_SetString(AudioopError, "First sample should be longer"); + return 0; + } + sum_ri_2 = _sum2(cp2, cp2, len2); + sum_aij_2 = _sum2(cp1, cp1, len2); + sum_aij_ri = _sum2(cp1, cp2, len2); + + result = (sum_ri_2*sum_aij_2 - sum_aij_ri*sum_aij_ri) / sum_aij_2; + + best_result = result; + best_j = 0; + j = 0; + + for ( j=1; j<=len1-len2; j++) { + aj_m1 = (double)cp1[j-1]; + aj_lm1 = (double)cp1[j+len2-1]; + + sum_aij_2 = sum_aij_2 + aj_lm1*aj_lm1 - aj_m1*aj_m1; + sum_aij_ri = _sum2(cp1+j, cp2, len2); + + result = (sum_ri_2*sum_aij_2 - sum_aij_ri*sum_aij_ri) + / sum_aij_2; + + if ( result < best_result ) { + best_result = result; + best_j = j; + } + + } + + factor = _sum2(cp1+best_j, cp2, len2) / sum_ri_2; + + return Py_BuildValue("(if)", best_j, factor); +} + +/* +** findfactor finds a factor f so that the energy in A-fB is minimal. +** See the comment for findfit for details. +*/ +static PyObject * +audioop_findfactor(PyObject *self, PyObject *args) +{ + short *cp1, *cp2; + int len1, len2; + double sum_ri_2, sum_aij_ri, result; + + if ( !PyArg_ParseTuple(args, "s#s#:findfactor", + &cp1, &len1, &cp2, &len2) ) + return 0; + if ( len1 & 1 || len2 & 1 ) { + PyErr_SetString(AudioopError, "Strings should be even-sized"); + return 0; + } + if ( len1 != len2 ) { + PyErr_SetString(AudioopError, "Samples should be same size"); + return 0; + } + len2 >>= 1; + sum_ri_2 = _sum2(cp2, cp2, len2); + sum_aij_ri = _sum2(cp1, cp2, len2); + + result = sum_aij_ri / sum_ri_2; + + return PyFloat_FromDouble(result); +} + +/* +** findmax returns the index of the n-sized segment of the input sample +** that contains the most energy. +*/ +static PyObject * +audioop_findmax(PyObject *self, PyObject *args) +{ + short *cp1; + int len1, len2; + int j, best_j; + double aj_m1, aj_lm1; + double result, best_result; + + if ( !PyArg_ParseTuple(args, "s#i:findmax", &cp1, &len1, &len2) ) + return 0; + if ( len1 & 1 ) { + PyErr_SetString(AudioopError, "Strings should be even-sized"); + return 0; + } + len1 >>= 1; + + if ( len1 < len2 ) { + PyErr_SetString(AudioopError, "Input sample should be longer"); + return 0; + } + + result = _sum2(cp1, cp1, len2); + + best_result = result; + best_j = 0; + j = 0; + + for ( j=1; j<=len1-len2; j++) { + aj_m1 = (double)cp1[j-1]; + aj_lm1 = (double)cp1[j+len2-1]; + + result = result + aj_lm1*aj_lm1 - aj_m1*aj_m1; + + if ( result > best_result ) { + best_result = result; + best_j = j; + } + + } + + return PyInt_FromLong(best_j); +} + +static PyObject * +audioop_avgpp(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0, prevval = 0, prevextremevalid = 0, + prevextreme = 0; + int i; + double avg = 0.0; + int diff, prevdiff, extremediff, nextreme = 0; + + if ( !PyArg_ParseTuple(args, "s#i:avgpp", &cp, &len, &size) ) + return 0; + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + /* Compute first delta value ahead. Also automatically makes us + ** skip the first extreme value + */ + if ( size == 1 ) prevval = (int)*CHARP(cp, 0); + else if ( size == 2 ) prevval = (int)*SHORTP(cp, 0); + else if ( size == 4 ) prevval = (int)*LONGP(cp, 0); + if ( size == 1 ) val = (int)*CHARP(cp, size); + else if ( size == 2 ) val = (int)*SHORTP(cp, size); + else if ( size == 4 ) val = (int)*LONGP(cp, size); + prevdiff = val - prevval; + + for ( i=size; i<len; i+= size) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + diff = val - prevval; + if ( diff*prevdiff < 0 ) { + /* Derivative changed sign. Compute difference to last + ** extreme value and remember. + */ + if ( prevextremevalid ) { + extremediff = prevval - prevextreme; + if ( extremediff < 0 ) + extremediff = -extremediff; + avg += extremediff; + nextreme++; + } + prevextremevalid = 1; + prevextreme = prevval; + } + prevval = val; + if ( diff != 0 ) + prevdiff = diff; + } + if ( nextreme == 0 ) + val = 0; + else + val = (int)(avg / (double)nextreme); + return PyInt_FromLong(val); +} + +static PyObject * +audioop_maxpp(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0, prevval = 0, prevextremevalid = 0, + prevextreme = 0; + int i; + int max = 0; + int diff, prevdiff, extremediff; + + if ( !PyArg_ParseTuple(args, "s#i:maxpp", &cp, &len, &size) ) + return 0; + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + /* Compute first delta value ahead. Also automatically makes us + ** skip the first extreme value + */ + if ( size == 1 ) prevval = (int)*CHARP(cp, 0); + else if ( size == 2 ) prevval = (int)*SHORTP(cp, 0); + else if ( size == 4 ) prevval = (int)*LONGP(cp, 0); + if ( size == 1 ) val = (int)*CHARP(cp, size); + else if ( size == 2 ) val = (int)*SHORTP(cp, size); + else if ( size == 4 ) val = (int)*LONGP(cp, size); + prevdiff = val - prevval; + + for ( i=size; i<len; i+= size) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + diff = val - prevval; + if ( diff*prevdiff < 0 ) { + /* Derivative changed sign. Compute difference to + ** last extreme value and remember. + */ + if ( prevextremevalid ) { + extremediff = prevval - prevextreme; + if ( extremediff < 0 ) + extremediff = -extremediff; + if ( extremediff > max ) + max = extremediff; + } + prevextremevalid = 1; + prevextreme = prevval; + } + prevval = val; + if ( diff != 0 ) + prevdiff = diff; + } + return PyInt_FromLong(max); +} + +static PyObject * +audioop_cross(PyObject *self, PyObject *args) +{ + signed char *cp; + int len, size, val = 0; + int i; + int prevval, ncross; + + if ( !PyArg_ParseTuple(args, "s#i:cross", &cp, &len, &size) ) + return 0; + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + ncross = -1; + prevval = 17; /* Anything <> 0,1 */ + for ( i=0; i<len; i+= size) { + if ( size == 1 ) val = ((int)*CHARP(cp, i)) >> 7; + else if ( size == 2 ) val = ((int)*SHORTP(cp, i)) >> 15; + else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 31; + val = val & 1; + if ( val != prevval ) ncross++; + prevval = val; + } + return PyInt_FromLong(ncross); +} + +static PyObject * +audioop_mul(PyObject *self, PyObject *args) +{ + signed char *cp, *ncp; + int len, size, val = 0; + double factor, fval, maxval; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#id:mul", &cp, &len, &size, &factor ) ) + return 0; + + if ( size == 1 ) maxval = (double) 0x7f; + else if ( size == 2 ) maxval = (double) 0x7fff; + else if ( size == 4 ) maxval = (double) 0x7fffffff; + else { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len); + if ( rv == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(rv); + + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + fval = (double)val*factor; + if ( fval > maxval ) fval = maxval; + else if ( fval < -maxval ) fval = -maxval; + val = (int)fval; + if ( size == 1 ) *CHARP(ncp, i) = (signed char)val; + else if ( size == 2 ) *SHORTP(ncp, i) = (short)val; + else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)val; + } + return rv; +} + +static PyObject * +audioop_tomono(PyObject *self, PyObject *args) +{ + signed char *cp, *ncp; + int len, size, val1 = 0, val2 = 0; + double fac1, fac2, fval, maxval; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#idd:tomono", + &cp, &len, &size, &fac1, &fac2 ) ) + return 0; + + if ( size == 1 ) maxval = (double) 0x7f; + else if ( size == 2 ) maxval = (double) 0x7fff; + else if ( size == 4 ) maxval = (double) 0x7fffffff; + else { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len/2); + if ( rv == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(rv); + + + for ( i=0; i < len; i += size*2 ) { + if ( size == 1 ) val1 = (int)*CHARP(cp, i); + else if ( size == 2 ) val1 = (int)*SHORTP(cp, i); + else if ( size == 4 ) val1 = (int)*LONGP(cp, i); + if ( size == 1 ) val2 = (int)*CHARP(cp, i+1); + else if ( size == 2 ) val2 = (int)*SHORTP(cp, i+2); + else if ( size == 4 ) val2 = (int)*LONGP(cp, i+4); + fval = (double)val1*fac1 + (double)val2*fac2; + if ( fval > maxval ) fval = maxval; + else if ( fval < -maxval ) fval = -maxval; + val1 = (int)fval; + if ( size == 1 ) *CHARP(ncp, i/2) = (signed char)val1; + else if ( size == 2 ) *SHORTP(ncp, i/2) = (short)val1; + else if ( size == 4 ) *LONGP(ncp, i/2)= (Py_Int32)val1; + } + return rv; +} + +static PyObject * +audioop_tostereo(PyObject *self, PyObject *args) +{ + signed char *cp, *ncp; + int len, size, val1, val2, val = 0; + double fac1, fac2, fval, maxval; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#idd:tostereo", + &cp, &len, &size, &fac1, &fac2 ) ) + return 0; + + if ( size == 1 ) maxval = (double) 0x7f; + else if ( size == 2 ) maxval = (double) 0x7fff; + else if ( size == 4 ) maxval = (double) 0x7fffffff; + else { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len*2); + if ( rv == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(rv); + + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + + fval = (double)val*fac1; + if ( fval > maxval ) fval = maxval; + else if ( fval < -maxval ) fval = -maxval; + val1 = (int)fval; + + fval = (double)val*fac2; + if ( fval > maxval ) fval = maxval; + else if ( fval < -maxval ) fval = -maxval; + val2 = (int)fval; + + if ( size == 1 ) *CHARP(ncp, i*2) = (signed char)val1; + else if ( size == 2 ) *SHORTP(ncp, i*2) = (short)val1; + else if ( size == 4 ) *LONGP(ncp, i*2) = (Py_Int32)val1; + + if ( size == 1 ) *CHARP(ncp, i*2+1) = (signed char)val2; + else if ( size == 2 ) *SHORTP(ncp, i*2+2) = (short)val2; + else if ( size == 4 ) *LONGP(ncp, i*2+4) = (Py_Int32)val2; + } + return rv; +} + +static PyObject * +audioop_add(PyObject *self, PyObject *args) +{ + signed char *cp1, *cp2, *ncp; + int len1, len2, size, val1 = 0, val2 = 0, maxval, newval; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#s#i:add", + &cp1, &len1, &cp2, &len2, &size ) ) + return 0; + + if ( len1 != len2 ) { + PyErr_SetString(AudioopError, "Lengths should be the same"); + return 0; + } + + if ( size == 1 ) maxval = 0x7f; + else if ( size == 2 ) maxval = 0x7fff; + else if ( size == 4 ) maxval = 0x7fffffff; + else { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len1); + if ( rv == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(rv); + + for ( i=0; i < len1; i += size ) { + if ( size == 1 ) val1 = (int)*CHARP(cp1, i); + else if ( size == 2 ) val1 = (int)*SHORTP(cp1, i); + else if ( size == 4 ) val1 = (int)*LONGP(cp1, i); + + if ( size == 1 ) val2 = (int)*CHARP(cp2, i); + else if ( size == 2 ) val2 = (int)*SHORTP(cp2, i); + else if ( size == 4 ) val2 = (int)*LONGP(cp2, i); + + newval = val1 + val2; + /* truncate in case of overflow */ + if (newval > maxval) newval = maxval; + else if (newval < -maxval) newval = -maxval; + else if (size == 4 && (newval^val1) < 0 && (newval^val2) < 0) + newval = val1 > 0 ? maxval : - maxval; + + if ( size == 1 ) *CHARP(ncp, i) = (signed char)newval; + else if ( size == 2 ) *SHORTP(ncp, i) = (short)newval; + else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)newval; + } + return rv; +} + +static PyObject * +audioop_bias(PyObject *self, PyObject *args) +{ + signed char *cp, *ncp; + int len, size, val = 0; + PyObject *rv; + int i; + int bias; + + if ( !PyArg_ParseTuple(args, "s#ii:bias", + &cp, &len, &size , &bias) ) + return 0; + + if ( size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len); + if ( rv == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(rv); + + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = (int)*CHARP(cp, i); + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = (int)*LONGP(cp, i); + + if ( size == 1 ) *CHARP(ncp, i) = (signed char)(val+bias); + else if ( size == 2 ) *SHORTP(ncp, i) = (short)(val+bias); + else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(val+bias); + } + return rv; +} + +static PyObject * +audioop_reverse(PyObject *self, PyObject *args) +{ + signed char *cp; + unsigned char *ncp; + int len, size, val = 0; + PyObject *rv; + int i, j; + + if ( !PyArg_ParseTuple(args, "s#i:reverse", + &cp, &len, &size) ) + return 0; + + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16; + + j = len - i - size; + + if ( size == 1 ) *CHARP(ncp, j) = (signed char)(val >> 8); + else if ( size == 2 ) *SHORTP(ncp, j) = (short)(val); + else if ( size == 4 ) *LONGP(ncp, j) = (Py_Int32)(val<<16); + } + return rv; +} + +static PyObject * +audioop_lin2lin(PyObject *self, PyObject *args) +{ + signed char *cp; + unsigned char *ncp; + int len, size, size2, val = 0; + PyObject *rv; + int i, j; + + if ( !PyArg_ParseTuple(args, "s#ii:lin2lin", + &cp, &len, &size, &size2) ) + return 0; + + if ( (size != 1 && size != 2 && size != 4) || + (size2 != 1 && size2 != 2 && size2 != 4)) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, (len/size)*size2); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0, j=0; i < len; i += size, j += size2 ) { + if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16; + + if ( size2 == 1 ) *CHARP(ncp, j) = (signed char)(val >> 8); + else if ( size2 == 2 ) *SHORTP(ncp, j) = (short)(val); + else if ( size2 == 4 ) *LONGP(ncp, j) = (Py_Int32)(val<<16); + } + return rv; +} + +static int +gcd(int a, int b) +{ + while (b > 0) { + int tmp = a % b; + a = b; + b = tmp; + } + return a; +} + +static PyObject * +audioop_ratecv(PyObject *self, PyObject *args) +{ + char *cp, *ncp; + int len, size, nchannels, inrate, outrate, weightA, weightB; + int chan, d, *prev_i, *cur_i, cur_o; + PyObject *state, *samps, *str, *rv = NULL; + int bytes_per_frame; + + weightA = 1; + weightB = 0; + if (!PyArg_ParseTuple(args, "s#iiiiO|ii:ratecv", &cp, &len, &size, + &nchannels, &inrate, &outrate, &state, + &weightA, &weightB)) + return NULL; + if (size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return NULL; + } + if (nchannels < 1) { + PyErr_SetString(AudioopError, "# of channels should be >= 1"); + return NULL; + } + bytes_per_frame = size * nchannels; + if (bytes_per_frame / nchannels != size) { + /* This overflow test is rigorously correct because + both multiplicands are >= 1. Use the argument names + from the docs for the error msg. */ + PyErr_SetString(PyExc_OverflowError, + "width * nchannels too big for a C int"); + return NULL; + } + if (weightA < 1 || weightB < 0) { + PyErr_SetString(AudioopError, + "weightA should be >= 1, weightB should be >= 0"); + return NULL; + } + if (len % bytes_per_frame != 0) { + PyErr_SetString(AudioopError, "not a whole number of frames"); + return NULL; + } + if (inrate <= 0 || outrate <= 0) { + PyErr_SetString(AudioopError, "sampling rate not > 0"); + return NULL; + } + /* divide inrate and outrate by their greatest common divisor */ + d = gcd(inrate, outrate); + inrate /= d; + outrate /= d; + + prev_i = (int *) malloc(nchannels * sizeof(int)); + cur_i = (int *) malloc(nchannels * sizeof(int)); + if (prev_i == NULL || cur_i == NULL) { + (void) PyErr_NoMemory(); + goto exit; + } + + len /= bytes_per_frame; /* # of frames */ + + if (state == Py_None) { + d = -outrate; + for (chan = 0; chan < nchannels; chan++) + prev_i[chan] = cur_i[chan] = 0; + } + else { + if (!PyArg_ParseTuple(state, + "iO!;audioop.ratecv: illegal state argument", + &d, &PyTuple_Type, &samps)) + goto exit; + if (PyTuple_Size(samps) != nchannels) { + PyErr_SetString(AudioopError, + "illegal state argument"); + goto exit; + } + for (chan = 0; chan < nchannels; chan++) { + if (!PyArg_ParseTuple(PyTuple_GetItem(samps, chan), + "ii:ratecv", &prev_i[chan], + &cur_i[chan])) + goto exit; + } + } + + /* str <- Space for the output buffer. */ + { + /* There are len input frames, so we need (mathematically) + ceiling(len*outrate/inrate) output frames, and each frame + requires bytes_per_frame bytes. Computing this + without spurious overflow is the challenge; we can + settle for a reasonable upper bound, though. */ + int ceiling; /* the number of output frames */ + int nbytes; /* the number of output bytes needed */ + int q = len / inrate; + /* Now len = q * inrate + r exactly (with r = len % inrate), + and this is less than q * inrate + inrate = (q+1)*inrate. + So a reasonable upper bound on len*outrate/inrate is + ((q+1)*inrate)*outrate/inrate = + (q+1)*outrate. + */ + ceiling = (q+1) * outrate; + nbytes = ceiling * bytes_per_frame; + /* See whether anything overflowed; if not, get the space. */ + if (q+1 < 0 || + ceiling / outrate != q+1 || + nbytes / bytes_per_frame != ceiling) + str = NULL; + else + str = PyString_FromStringAndSize(NULL, nbytes); + + if (str == NULL) { + PyErr_SetString(PyExc_MemoryError, + "not enough memory for output buffer"); + goto exit; + } + } + ncp = PyString_AsString(str); + + for (;;) { + while (d < 0) { + if (len == 0) { + samps = PyTuple_New(nchannels); + if (samps == NULL) + goto exit; + for (chan = 0; chan < nchannels; chan++) + PyTuple_SetItem(samps, chan, + Py_BuildValue("(ii)", + prev_i[chan], + cur_i[chan])); + if (PyErr_Occurred()) + goto exit; + /* We have checked before that the length + * of the string fits into int. */ + len = (int)(ncp - PyString_AsString(str)); + if (len == 0) { + /*don't want to resize to zero length*/ + rv = PyString_FromStringAndSize("", 0); + Py_DECREF(str); + str = rv; + } else if (_PyString_Resize(&str, len) < 0) + goto exit; + rv = Py_BuildValue("(O(iO))", str, d, samps); + Py_DECREF(samps); + Py_DECREF(str); + goto exit; /* return rv */ + } + for (chan = 0; chan < nchannels; chan++) { + prev_i[chan] = cur_i[chan]; + if (size == 1) + cur_i[chan] = ((int)*CHARP(cp, 0)) << 8; + else if (size == 2) + cur_i[chan] = (int)*SHORTP(cp, 0); + else if (size == 4) + cur_i[chan] = ((int)*LONGP(cp, 0)) >> 16; + cp += size; + /* implements a simple digital filter */ + cur_i[chan] = + (weightA * cur_i[chan] + + weightB * prev_i[chan]) / + (weightA + weightB); + } + len--; + d += outrate; + } + while (d >= 0) { + for (chan = 0; chan < nchannels; chan++) { + cur_o = (prev_i[chan] * d + + cur_i[chan] * (outrate - d)) / + outrate; + if (size == 1) + *CHARP(ncp, 0) = (signed char)(cur_o >> 8); + else if (size == 2) + *SHORTP(ncp, 0) = (short)(cur_o); + else if (size == 4) + *LONGP(ncp, 0) = (Py_Int32)(cur_o<<16); + ncp += size; + } + d -= inrate; + } + } + exit: + if (prev_i != NULL) + free(prev_i); + if (cur_i != NULL) + free(cur_i); + return rv; +} + +static PyObject * +audioop_lin2ulaw(PyObject *self, PyObject *args) +{ + signed char *cp; + unsigned char *ncp; + int len, size, val = 0; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#i:lin2ulaw", + &cp, &len, &size) ) + return 0 ; + + if ( size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len/size); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16; + + *ncp++ = st_14linear2ulaw(val); + } + return rv; +} + +static PyObject * +audioop_ulaw2lin(PyObject *self, PyObject *args) +{ + unsigned char *cp; + unsigned char cval; + signed char *ncp; + int len, size, val; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#i:ulaw2lin", + &cp, &len, &size) ) + return 0; + + if ( size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len*size); + if ( rv == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(rv); + + for ( i=0; i < len*size; i += size ) { + cval = *cp++; + val = st_ulaw2linear16(cval); + + if ( size == 1 ) *CHARP(ncp, i) = (signed char)(val >> 8); + else if ( size == 2 ) *SHORTP(ncp, i) = (short)(val); + else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(val<<16); + } + return rv; +} + +static PyObject * +audioop_lin2alaw(PyObject *self, PyObject *args) +{ + signed char *cp; + unsigned char *ncp; + int len, size, val = 0; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#i:lin2alaw", + &cp, &len, &size) ) + return 0; + + if ( size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len/size); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16; + + *ncp++ = st_linear2alaw(val); + } + return rv; +} + +static PyObject * +audioop_alaw2lin(PyObject *self, PyObject *args) +{ + unsigned char *cp; + unsigned char cval; + signed char *ncp; + int len, size, val; + PyObject *rv; + int i; + + if ( !PyArg_ParseTuple(args, "s#i:alaw2lin", + &cp, &len, &size) ) + return 0; + + if ( size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len*size); + if ( rv == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(rv); + + for ( i=0; i < len*size; i += size ) { + cval = *cp++; + val = st_alaw2linear16(cval); + + if ( size == 1 ) *CHARP(ncp, i) = (signed char)(val >> 8); + else if ( size == 2 ) *SHORTP(ncp, i) = (short)(val); + else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(val<<16); + } + return rv; +} + +static PyObject * +audioop_lin2adpcm(PyObject *self, PyObject *args) +{ + signed char *cp; + signed char *ncp; + int len, size, val = 0, step, valpred, delta, + index, sign, vpdiff, diff; + PyObject *rv, *state, *str; + int i, outputbuffer = 0, bufferstep; + + if ( !PyArg_ParseTuple(args, "s#iO:lin2adpcm", + &cp, &len, &size, &state) ) + return 0; + + + if ( size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + str = PyString_FromStringAndSize(NULL, len/(size*2)); + if ( str == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(str); + + /* Decode state, should have (value, step) */ + if ( state == Py_None ) { + /* First time, it seems. Set defaults */ + valpred = 0; + step = 7; + index = 0; + } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) ) + return 0; + + step = stepsizeTable[index]; + bufferstep = 1; + + for ( i=0; i < len; i += size ) { + if ( size == 1 ) val = ((int)*CHARP(cp, i)) << 8; + else if ( size == 2 ) val = (int)*SHORTP(cp, i); + else if ( size == 4 ) val = ((int)*LONGP(cp, i)) >> 16; + + /* Step 1 - compute difference with previous value */ + diff = val - valpred; + sign = (diff < 0) ? 8 : 0; + if ( sign ) diff = (-diff); + + /* Step 2 - Divide and clamp */ + /* Note: + ** This code *approximately* computes: + ** delta = diff*4/step; + ** vpdiff = (delta+0.5)*step/4; + ** but in shift step bits are dropped. The net result of this + ** is that even if you have fast mul/div hardware you cannot + ** put it to good use since the fixup would be too expensive. + */ + delta = 0; + vpdiff = (step >> 3); + + if ( diff >= step ) { + delta = 4; + diff -= step; + vpdiff += step; + } + step >>= 1; + if ( diff >= step ) { + delta |= 2; + diff -= step; + vpdiff += step; + } + step >>= 1; + if ( diff >= step ) { + delta |= 1; + vpdiff += step; + } + + /* Step 3 - Update previous value */ + if ( sign ) + valpred -= vpdiff; + else + valpred += vpdiff; + + /* Step 4 - Clamp previous value to 16 bits */ + if ( valpred > 32767 ) + valpred = 32767; + else if ( valpred < -32768 ) + valpred = -32768; + + /* Step 5 - Assemble value, update index and step values */ + delta |= sign; + + index += indexTable[delta]; + if ( index < 0 ) index = 0; + if ( index > 88 ) index = 88; + step = stepsizeTable[index]; + + /* Step 6 - Output value */ + if ( bufferstep ) { + outputbuffer = (delta << 4) & 0xf0; + } else { + *ncp++ = (delta & 0x0f) | outputbuffer; + } + bufferstep = !bufferstep; + } + rv = Py_BuildValue("(O(ii))", str, valpred, index); + Py_DECREF(str); + return rv; +} + +static PyObject * +audioop_adpcm2lin(PyObject *self, PyObject *args) +{ + signed char *cp; + signed char *ncp; + int len, size, valpred, step, delta, index, sign, vpdiff; + PyObject *rv, *str, *state; + int i, inputbuffer = 0, bufferstep; + + if ( !PyArg_ParseTuple(args, "s#iO:adpcm2lin", + &cp, &len, &size, &state) ) + return 0; + + if ( size != 1 && size != 2 && size != 4) { + PyErr_SetString(AudioopError, "Size should be 1, 2 or 4"); + return 0; + } + + /* Decode state, should have (value, step) */ + if ( state == Py_None ) { + /* First time, it seems. Set defaults */ + valpred = 0; + step = 7; + index = 0; + } else if ( !PyArg_ParseTuple(state, "ii", &valpred, &index) ) + return 0; + + str = PyString_FromStringAndSize(NULL, len*size*2); + if ( str == 0 ) + return 0; + ncp = (signed char *)PyString_AsString(str); + + step = stepsizeTable[index]; + bufferstep = 0; + + for ( i=0; i < len*size*2; i += size ) { + /* Step 1 - get the delta value and compute next index */ + if ( bufferstep ) { + delta = inputbuffer & 0xf; + } else { + inputbuffer = *cp++; + delta = (inputbuffer >> 4) & 0xf; + } + + bufferstep = !bufferstep; + + /* Step 2 - Find new index value (for later) */ + index += indexTable[delta]; + if ( index < 0 ) index = 0; + if ( index > 88 ) index = 88; + + /* Step 3 - Separate sign and magnitude */ + sign = delta & 8; + delta = delta & 7; + + /* Step 4 - Compute difference and new predicted value */ + /* + ** Computes 'vpdiff = (delta+0.5)*step/4', but see comment + ** in adpcm_coder. + */ + vpdiff = step >> 3; + if ( delta & 4 ) vpdiff += step; + if ( delta & 2 ) vpdiff += step>>1; + if ( delta & 1 ) vpdiff += step>>2; + + if ( sign ) + valpred -= vpdiff; + else + valpred += vpdiff; + + /* Step 5 - clamp output value */ + if ( valpred > 32767 ) + valpred = 32767; + else if ( valpred < -32768 ) + valpred = -32768; + + /* Step 6 - Update step value */ + step = stepsizeTable[index]; + + /* Step 6 - Output value */ + if ( size == 1 ) *CHARP(ncp, i) = (signed char)(valpred >> 8); + else if ( size == 2 ) *SHORTP(ncp, i) = (short)(valpred); + else if ( size == 4 ) *LONGP(ncp, i) = (Py_Int32)(valpred<<16); + } + + rv = Py_BuildValue("(O(ii))", str, valpred, index); + Py_DECREF(str); + return rv; +} + +static PyMethodDef audioop_methods[] = { + { "max", audioop_max, METH_VARARGS }, + { "minmax", audioop_minmax, METH_VARARGS }, + { "avg", audioop_avg, METH_VARARGS }, + { "maxpp", audioop_maxpp, METH_VARARGS }, + { "avgpp", audioop_avgpp, METH_VARARGS }, + { "rms", audioop_rms, METH_VARARGS }, + { "findfit", audioop_findfit, METH_VARARGS }, + { "findmax", audioop_findmax, METH_VARARGS }, + { "findfactor", audioop_findfactor, METH_VARARGS }, + { "cross", audioop_cross, METH_VARARGS }, + { "mul", audioop_mul, METH_VARARGS }, + { "add", audioop_add, METH_VARARGS }, + { "bias", audioop_bias, METH_VARARGS }, + { "ulaw2lin", audioop_ulaw2lin, METH_VARARGS }, + { "lin2ulaw", audioop_lin2ulaw, METH_VARARGS }, + { "alaw2lin", audioop_alaw2lin, METH_VARARGS }, + { "lin2alaw", audioop_lin2alaw, METH_VARARGS }, + { "lin2lin", audioop_lin2lin, METH_VARARGS }, + { "adpcm2lin", audioop_adpcm2lin, METH_VARARGS }, + { "lin2adpcm", audioop_lin2adpcm, METH_VARARGS }, + { "tomono", audioop_tomono, METH_VARARGS }, + { "tostereo", audioop_tostereo, METH_VARARGS }, + { "getsample", audioop_getsample, METH_VARARGS }, + { "reverse", audioop_reverse, METH_VARARGS }, + { "ratecv", audioop_ratecv, METH_VARARGS }, + { 0, 0 } +}; + +PyMODINIT_FUNC +initaudioop(void) +{ + PyObject *m, *d; + m = Py_InitModule("audioop", audioop_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + if (d == NULL) + return; + AudioopError = PyErr_NewException("audioop.error", NULL, NULL); + if (AudioopError != NULL) + PyDict_SetItemString(d,"error",AudioopError); +} diff --git a/sys/src/cmd/python/Modules/binascii.c b/sys/src/cmd/python/Modules/binascii.c new file mode 100644 index 000000000..4dee45198 --- /dev/null +++ b/sys/src/cmd/python/Modules/binascii.c @@ -0,0 +1,1350 @@ +/* +** Routines to represent binary data in ASCII and vice-versa +** +** This module currently supports the following encodings: +** uuencode: +** each line encodes 45 bytes (except possibly the last) +** First char encodes (binary) length, rest data +** each char encodes 6 bits, as follows: +** binary: 01234567 abcdefgh ijklmnop +** ascii: 012345 67abcd efghij klmnop +** ASCII encoding method is "excess-space": 000000 is encoded as ' ', etc. +** short binary data is zero-extended (so the bits are always in the +** right place), this does *not* reflect in the length. +** base64: +** Line breaks are insignificant, but lines are at most 76 chars +** each char encodes 6 bits, in similar order as uucode/hqx. Encoding +** is done via a table. +** Short binary data is filled (in ASCII) with '='. +** hqx: +** File starts with introductory text, real data starts and ends +** with colons. +** Data consists of three similar parts: info, datafork, resourcefork. +** Each part is protected (at the end) with a 16-bit crc +** The binary data is run-length encoded, and then ascii-fied: +** binary: 01234567 abcdefgh ijklmnop +** ascii: 012345 67abcd efghij klmnop +** ASCII encoding is table-driven, see the code. +** Short binary data results in the runt ascii-byte being output with +** the bits in the right place. +** +** While I was reading dozens of programs that encode or decode the formats +** here (documentation? hihi:-) I have formulated Jansen's Observation: +** +** Programs that encode binary data in ASCII are written in +** such a style that they are as unreadable as possible. Devices used +** include unnecessary global variables, burying important tables +** in unrelated sourcefiles, putting functions in include files, +** using seemingly-descriptive variable names for different purposes, +** calls to empty subroutines and a host of others. +** +** I have attempted to break with this tradition, but I guess that that +** does make the performance sub-optimal. Oh well, too bad... +** +** Jack Jansen, CWI, July 1995. +** +** Added support for quoted-printable encoding, based on rfc 1521 et al +** quoted-printable encoding specifies that non printable characters (anything +** below 32 and above 126) be encoded as =XX where XX is the hexadecimal value +** of the character. It also specifies some other behavior to enable 8bit data +** in a mail message with little difficulty (maximum line sizes, protecting +** some cases of whitespace, etc). +** +** Brandon Long, September 2001. +*/ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" + +static PyObject *Error; +static PyObject *Incomplete; + +/* +** hqx lookup table, ascii->binary. +*/ + +#define RUNCHAR 0x90 + +#define DONE 0x7F +#define SKIP 0x7E +#define FAIL 0x7D + +static unsigned char table_a2b_hqx[256] = { +/* ^@ ^A ^B ^C ^D ^E ^F ^G */ +/* 0*/ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, +/* \b \t \n ^K ^L \r ^N ^O */ +/* 1*/ FAIL, FAIL, SKIP, FAIL, FAIL, SKIP, FAIL, FAIL, +/* ^P ^Q ^R ^S ^T ^U ^V ^W */ +/* 2*/ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, +/* ^X ^Y ^Z ^[ ^\ ^] ^^ ^_ */ +/* 3*/ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, +/* ! " # $ % & ' */ +/* 4*/ FAIL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, +/* ( ) * + , - . / */ +/* 5*/ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, FAIL, FAIL, +/* 0 1 2 3 4 5 6 7 */ +/* 6*/ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, FAIL, +/* 8 9 : ; < = > ? */ +/* 7*/ 0x14, 0x15, DONE, FAIL, FAIL, FAIL, FAIL, FAIL, +/* @ A B C D E F G */ +/* 8*/ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, +/* H I J K L M N O */ +/* 9*/ 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, FAIL, +/* P Q R S T U V W */ +/*10*/ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, FAIL, +/* X Y Z [ \ ] ^ _ */ +/*11*/ 0x2C, 0x2D, 0x2E, 0x2F, FAIL, FAIL, FAIL, FAIL, +/* ` a b c d e f g */ +/*12*/ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, FAIL, +/* h i j k l m n o */ +/*13*/ 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, FAIL, FAIL, +/* p q r s t u v w */ +/*14*/ 0x3D, 0x3E, 0x3F, FAIL, FAIL, FAIL, FAIL, FAIL, +/* x y z { | } ~ ^? */ +/*15*/ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, +/*16*/ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, + FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, +}; + +static unsigned char table_b2a_hqx[] = +"!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"; + +static char table_a2b_base64[] = { + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, /* Note PAD->0 */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +}; + +#define BASE64_PAD '=' + +/* Max binary chunk size; limited only by available memory */ +#define BASE64_MAXBIN (INT_MAX/2 - sizeof(PyStringObject) - 3) + +static unsigned char table_b2a_base64[] = +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + + +static unsigned short crctab_hqx[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, +}; + +PyDoc_STRVAR(doc_a2b_uu, "(ascii) -> bin. Decode a line of uuencoded data"); + +static PyObject * +binascii_a2b_uu(PyObject *self, PyObject *args) +{ + unsigned char *ascii_data, *bin_data; + int leftbits = 0; + unsigned char this_ch; + unsigned int leftchar = 0; + PyObject *rv; + Py_ssize_t ascii_len, bin_len; + + if ( !PyArg_ParseTuple(args, "t#:a2b_uu", &ascii_data, &ascii_len) ) + return NULL; + + /* First byte: binary data length (in bytes) */ + bin_len = (*ascii_data++ - ' ') & 077; + ascii_len--; + + /* Allocate the buffer */ + if ( (rv=PyString_FromStringAndSize(NULL, bin_len)) == NULL ) + return NULL; + bin_data = (unsigned char *)PyString_AsString(rv); + + for( ; bin_len > 0 ; ascii_len--, ascii_data++ ) { + /* XXX is it really best to add NULs if there's no more data */ + this_ch = (ascii_len > 0) ? *ascii_data : 0; + if ( this_ch == '\n' || this_ch == '\r' || ascii_len <= 0) { + /* + ** Whitespace. Assume some spaces got eaten at + ** end-of-line. (We check this later) + */ + this_ch = 0; + } else { + /* Check the character for legality + ** The 64 in stead of the expected 63 is because + ** there are a few uuencodes out there that use + ** '`' as zero instead of space. + */ + if ( this_ch < ' ' || this_ch > (' ' + 64)) { + PyErr_SetString(Error, "Illegal char"); + Py_DECREF(rv); + return NULL; + } + this_ch = (this_ch - ' ') & 077; + } + /* + ** Shift it in on the low end, and see if there's + ** a byte ready for output. + */ + leftchar = (leftchar << 6) | (this_ch); + leftbits += 6; + if ( leftbits >= 8 ) { + leftbits -= 8; + *bin_data++ = (leftchar >> leftbits) & 0xff; + leftchar &= ((1 << leftbits) - 1); + bin_len--; + } + } + /* + ** Finally, check that if there's anything left on the line + ** that it's whitespace only. + */ + while( ascii_len-- > 0 ) { + this_ch = *ascii_data++; + /* Extra '`' may be written as padding in some cases */ + if ( this_ch != ' ' && this_ch != ' '+64 && + this_ch != '\n' && this_ch != '\r' ) { + PyErr_SetString(Error, "Trailing garbage"); + Py_DECREF(rv); + return NULL; + } + } + return rv; +} + +PyDoc_STRVAR(doc_b2a_uu, "(bin) -> ascii. Uuencode line of data"); + +static PyObject * +binascii_b2a_uu(PyObject *self, PyObject *args) +{ + unsigned char *ascii_data, *bin_data; + int leftbits = 0; + unsigned char this_ch; + unsigned int leftchar = 0; + PyObject *rv; + Py_ssize_t bin_len; + + if ( !PyArg_ParseTuple(args, "s#:b2a_uu", &bin_data, &bin_len) ) + return NULL; + if ( bin_len > 45 ) { + /* The 45 is a limit that appears in all uuencode's */ + PyErr_SetString(Error, "At most 45 bytes at once"); + return NULL; + } + + /* We're lazy and allocate to much (fixed up later) */ + if ( (rv=PyString_FromStringAndSize(NULL, bin_len*2+2)) == NULL ) + return NULL; + ascii_data = (unsigned char *)PyString_AsString(rv); + + /* Store the length */ + *ascii_data++ = ' ' + (bin_len & 077); + + for( ; bin_len > 0 || leftbits != 0 ; bin_len--, bin_data++ ) { + /* Shift the data (or padding) into our buffer */ + if ( bin_len > 0 ) /* Data */ + leftchar = (leftchar << 8) | *bin_data; + else /* Padding */ + leftchar <<= 8; + leftbits += 8; + + /* See if there are 6-bit groups ready */ + while ( leftbits >= 6 ) { + this_ch = (leftchar >> (leftbits-6)) & 0x3f; + leftbits -= 6; + *ascii_data++ = this_ch + ' '; + } + } + *ascii_data++ = '\n'; /* Append a courtesy newline */ + + _PyString_Resize(&rv, (ascii_data - + (unsigned char *)PyString_AsString(rv))); + return rv; +} + + +static int +binascii_find_valid(unsigned char *s, Py_ssize_t slen, int num) +{ + /* Finds & returns the (num+1)th + ** valid character for base64, or -1 if none. + */ + + int ret = -1; + unsigned char c, b64val; + + while ((slen > 0) && (ret == -1)) { + c = *s; + b64val = table_a2b_base64[c & 0x7f]; + if ( ((c <= 0x7f) && (b64val != (unsigned char)-1)) ) { + if (num == 0) + ret = *s; + num--; + } + + s++; + slen--; + } + return ret; +} + +PyDoc_STRVAR(doc_a2b_base64, "(ascii) -> bin. Decode a line of base64 data"); + +static PyObject * +binascii_a2b_base64(PyObject *self, PyObject *args) +{ + unsigned char *ascii_data, *bin_data; + int leftbits = 0; + unsigned char this_ch; + unsigned int leftchar = 0; + PyObject *rv; + Py_ssize_t ascii_len, bin_len; + int quad_pos = 0; + + if ( !PyArg_ParseTuple(args, "t#:a2b_base64", &ascii_data, &ascii_len) ) + return NULL; + + bin_len = ((ascii_len+3)/4)*3; /* Upper bound, corrected later */ + + /* Allocate the buffer */ + if ( (rv=PyString_FromStringAndSize(NULL, bin_len)) == NULL ) + return NULL; + bin_data = (unsigned char *)PyString_AsString(rv); + bin_len = 0; + + for( ; ascii_len > 0; ascii_len--, ascii_data++) { + this_ch = *ascii_data; + + if (this_ch > 0x7f || + this_ch == '\r' || this_ch == '\n' || this_ch == ' ') + continue; + + /* Check for pad sequences and ignore + ** the invalid ones. + */ + if (this_ch == BASE64_PAD) { + if ( (quad_pos < 2) || + ((quad_pos == 2) && + (binascii_find_valid(ascii_data, ascii_len, 1) + != BASE64_PAD)) ) + { + continue; + } + else { + /* A pad sequence means no more input. + ** We've already interpreted the data + ** from the quad at this point. + */ + leftbits = 0; + break; + } + } + + this_ch = table_a2b_base64[*ascii_data]; + if ( this_ch == (unsigned char) -1 ) + continue; + + /* + ** Shift it in on the low end, and see if there's + ** a byte ready for output. + */ + quad_pos = (quad_pos + 1) & 0x03; + leftchar = (leftchar << 6) | (this_ch); + leftbits += 6; + + if ( leftbits >= 8 ) { + leftbits -= 8; + *bin_data++ = (leftchar >> leftbits) & 0xff; + bin_len++; + leftchar &= ((1 << leftbits) - 1); + } + } + + if (leftbits != 0) { + PyErr_SetString(Error, "Incorrect padding"); + Py_DECREF(rv); + return NULL; + } + + /* And set string size correctly. If the result string is empty + ** (because the input was all invalid) return the shared empty + ** string instead; _PyString_Resize() won't do this for us. + */ + if (bin_len > 0) + _PyString_Resize(&rv, bin_len); + else { + Py_DECREF(rv); + rv = PyString_FromString(""); + } + return rv; +} + +PyDoc_STRVAR(doc_b2a_base64, "(bin) -> ascii. Base64-code line of data"); + +static PyObject * +binascii_b2a_base64(PyObject *self, PyObject *args) +{ + unsigned char *ascii_data, *bin_data; + int leftbits = 0; + unsigned char this_ch; + unsigned int leftchar = 0; + PyObject *rv; + Py_ssize_t bin_len; + + if ( !PyArg_ParseTuple(args, "s#:b2a_base64", &bin_data, &bin_len) ) + return NULL; + if ( bin_len > BASE64_MAXBIN ) { + PyErr_SetString(Error, "Too much data for base64 line"); + return NULL; + } + + /* We're lazy and allocate too much (fixed up later). + "+3" leaves room for up to two pad characters and a trailing + newline. Note that 'b' gets encoded as 'Yg==\n' (1 in, 5 out). */ + if ( (rv=PyString_FromStringAndSize(NULL, bin_len*2 + 3)) == NULL ) + return NULL; + ascii_data = (unsigned char *)PyString_AsString(rv); + + for( ; bin_len > 0 ; bin_len--, bin_data++ ) { + /* Shift the data into our buffer */ + leftchar = (leftchar << 8) | *bin_data; + leftbits += 8; + + /* See if there are 6-bit groups ready */ + while ( leftbits >= 6 ) { + this_ch = (leftchar >> (leftbits-6)) & 0x3f; + leftbits -= 6; + *ascii_data++ = table_b2a_base64[this_ch]; + } + } + if ( leftbits == 2 ) { + *ascii_data++ = table_b2a_base64[(leftchar&3) << 4]; + *ascii_data++ = BASE64_PAD; + *ascii_data++ = BASE64_PAD; + } else if ( leftbits == 4 ) { + *ascii_data++ = table_b2a_base64[(leftchar&0xf) << 2]; + *ascii_data++ = BASE64_PAD; + } + *ascii_data++ = '\n'; /* Append a courtesy newline */ + + _PyString_Resize(&rv, (ascii_data - + (unsigned char *)PyString_AsString(rv))); + return rv; +} + +PyDoc_STRVAR(doc_a2b_hqx, "ascii -> bin, done. Decode .hqx coding"); + +static PyObject * +binascii_a2b_hqx(PyObject *self, PyObject *args) +{ + unsigned char *ascii_data, *bin_data; + int leftbits = 0; + unsigned char this_ch; + unsigned int leftchar = 0; + PyObject *rv; + Py_ssize_t len; + int done = 0; + + if ( !PyArg_ParseTuple(args, "t#:a2b_hqx", &ascii_data, &len) ) + return NULL; + + /* Allocate a string that is too big (fixed later) + Add two to the initial length to prevent interning which + would preclude subsequent resizing. */ + if ( (rv=PyString_FromStringAndSize(NULL, len+2)) == NULL ) + return NULL; + bin_data = (unsigned char *)PyString_AsString(rv); + + for( ; len > 0 ; len--, ascii_data++ ) { + /* Get the byte and look it up */ + this_ch = table_a2b_hqx[*ascii_data]; + if ( this_ch == SKIP ) + continue; + if ( this_ch == FAIL ) { + PyErr_SetString(Error, "Illegal char"); + Py_DECREF(rv); + return NULL; + } + if ( this_ch == DONE ) { + /* The terminating colon */ + done = 1; + break; + } + + /* Shift it into the buffer and see if any bytes are ready */ + leftchar = (leftchar << 6) | (this_ch); + leftbits += 6; + if ( leftbits >= 8 ) { + leftbits -= 8; + *bin_data++ = (leftchar >> leftbits) & 0xff; + leftchar &= ((1 << leftbits) - 1); + } + } + + if ( leftbits && !done ) { + PyErr_SetString(Incomplete, + "String has incomplete number of bytes"); + Py_DECREF(rv); + return NULL; + } + _PyString_Resize( + &rv, (bin_data - (unsigned char *)PyString_AsString(rv))); + if (rv) { + PyObject *rrv = Py_BuildValue("Oi", rv, done); + Py_DECREF(rv); + return rrv; + } + + return NULL; +} + +PyDoc_STRVAR(doc_rlecode_hqx, "Binhex RLE-code binary data"); + +static PyObject * +binascii_rlecode_hqx(PyObject *self, PyObject *args) +{ + unsigned char *in_data, *out_data; + PyObject *rv; + unsigned char ch; + Py_ssize_t in, inend, len; + + if ( !PyArg_ParseTuple(args, "s#:rlecode_hqx", &in_data, &len) ) + return NULL; + + /* Worst case: output is twice as big as input (fixed later) */ + if ( (rv=PyString_FromStringAndSize(NULL, len*2+2)) == NULL ) + return NULL; + out_data = (unsigned char *)PyString_AsString(rv); + + for( in=0; in<len; in++) { + ch = in_data[in]; + if ( ch == RUNCHAR ) { + /* RUNCHAR. Escape it. */ + *out_data++ = RUNCHAR; + *out_data++ = 0; + } else { + /* Check how many following are the same */ + for(inend=in+1; + inend<len && in_data[inend] == ch && + inend < in+255; + inend++) ; + if ( inend - in > 3 ) { + /* More than 3 in a row. Output RLE. */ + *out_data++ = ch; + *out_data++ = RUNCHAR; + *out_data++ = inend-in; + in = inend-1; + } else { + /* Less than 3. Output the byte itself */ + *out_data++ = ch; + } + } + } + _PyString_Resize(&rv, (out_data - + (unsigned char *)PyString_AsString(rv))); + return rv; +} + +PyDoc_STRVAR(doc_b2a_hqx, "Encode .hqx data"); + +static PyObject * +binascii_b2a_hqx(PyObject *self, PyObject *args) +{ + unsigned char *ascii_data, *bin_data; + int leftbits = 0; + unsigned char this_ch; + unsigned int leftchar = 0; + PyObject *rv; + Py_ssize_t len; + + if ( !PyArg_ParseTuple(args, "s#:b2a_hqx", &bin_data, &len) ) + return NULL; + + /* Allocate a buffer that is at least large enough */ + if ( (rv=PyString_FromStringAndSize(NULL, len*2+2)) == NULL ) + return NULL; + ascii_data = (unsigned char *)PyString_AsString(rv); + + for( ; len > 0 ; len--, bin_data++ ) { + /* Shift into our buffer, and output any 6bits ready */ + leftchar = (leftchar << 8) | *bin_data; + leftbits += 8; + while ( leftbits >= 6 ) { + this_ch = (leftchar >> (leftbits-6)) & 0x3f; + leftbits -= 6; + *ascii_data++ = table_b2a_hqx[this_ch]; + } + } + /* Output a possible runt byte */ + if ( leftbits ) { + leftchar <<= (6-leftbits); + *ascii_data++ = table_b2a_hqx[leftchar & 0x3f]; + } + _PyString_Resize(&rv, (ascii_data - + (unsigned char *)PyString_AsString(rv))); + return rv; +} + +PyDoc_STRVAR(doc_rledecode_hqx, "Decode hexbin RLE-coded string"); + +static PyObject * +binascii_rledecode_hqx(PyObject *self, PyObject *args) +{ + unsigned char *in_data, *out_data; + unsigned char in_byte, in_repeat; + PyObject *rv; + Py_ssize_t in_len, out_len, out_len_left; + + if ( !PyArg_ParseTuple(args, "s#:rledecode_hqx", &in_data, &in_len) ) + return NULL; + + /* Empty string is a special case */ + if ( in_len == 0 ) + return PyString_FromString(""); + + /* Allocate a buffer of reasonable size. Resized when needed */ + out_len = in_len*2; + if ( (rv=PyString_FromStringAndSize(NULL, out_len)) == NULL ) + return NULL; + out_len_left = out_len; + out_data = (unsigned char *)PyString_AsString(rv); + + /* + ** We need two macros here to get/put bytes and handle + ** end-of-buffer for input and output strings. + */ +#define INBYTE(b) \ + do { \ + if ( --in_len < 0 ) { \ + PyErr_SetString(Incomplete, ""); \ + Py_DECREF(rv); \ + return NULL; \ + } \ + b = *in_data++; \ + } while(0) + +#define OUTBYTE(b) \ + do { \ + if ( --out_len_left < 0 ) { \ + _PyString_Resize(&rv, 2*out_len); \ + if ( rv == NULL ) return NULL; \ + out_data = (unsigned char *)PyString_AsString(rv) \ + + out_len; \ + out_len_left = out_len-1; \ + out_len = out_len * 2; \ + } \ + *out_data++ = b; \ + } while(0) + + /* + ** Handle first byte separately (since we have to get angry + ** in case of an orphaned RLE code). + */ + INBYTE(in_byte); + + if (in_byte == RUNCHAR) { + INBYTE(in_repeat); + if (in_repeat != 0) { + /* Note Error, not Incomplete (which is at the end + ** of the string only). This is a programmer error. + */ + PyErr_SetString(Error, "Orphaned RLE code at start"); + Py_DECREF(rv); + return NULL; + } + OUTBYTE(RUNCHAR); + } else { + OUTBYTE(in_byte); + } + + while( in_len > 0 ) { + INBYTE(in_byte); + + if (in_byte == RUNCHAR) { + INBYTE(in_repeat); + if ( in_repeat == 0 ) { + /* Just an escaped RUNCHAR value */ + OUTBYTE(RUNCHAR); + } else { + /* Pick up value and output a sequence of it */ + in_byte = out_data[-1]; + while ( --in_repeat > 0 ) + OUTBYTE(in_byte); + } + } else { + /* Normal byte */ + OUTBYTE(in_byte); + } + } + _PyString_Resize(&rv, (out_data - + (unsigned char *)PyString_AsString(rv))); + return rv; +} + +PyDoc_STRVAR(doc_crc_hqx, +"(data, oldcrc) -> newcrc. Compute hqx CRC incrementally"); + +static PyObject * +binascii_crc_hqx(PyObject *self, PyObject *args) +{ + unsigned char *bin_data; + unsigned int crc; + Py_ssize_t len; + + if ( !PyArg_ParseTuple(args, "s#i:crc_hqx", &bin_data, &len, &crc) ) + return NULL; + + while(len--) { + crc=((crc<<8)&0xff00)^crctab_hqx[((crc>>8)&0xff)^*bin_data++]; + } + + return Py_BuildValue("i", crc); +} + +PyDoc_STRVAR(doc_crc32, +"(data, oldcrc = 0) -> newcrc. Compute CRC-32 incrementally"); + +/* Crc - 32 BIT ANSI X3.66 CRC checksum files + Also known as: ISO 3307 +**********************************************************************| +* *| +* Demonstration program to compute the 32-bit CRC used as the frame *| +* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| +* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| +* protocol). The 32-bit FCS was added via the Federal Register, *| +* 1 June 1982, p.23798. I presume but don't know for certain that *| +* this polynomial is or will be included in CCITT V.41, which *| +* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| +* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| +* errors by a factor of 10^-5 over 16-bit FCS. *| +* *| +**********************************************************************| + + Copyright (C) 1986 Gary S. Brown. You may use this program, or + code or tables extracted from it, as desired without restriction. + + First, the polynomial itself and its table of feedback terms. The + polynomial is + X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + Note that we take it "backwards" and put the highest-order term in + the lowest-order bit. The X^32 term is "implied"; the LSB is the + X^31 term, etc. The X^0 term (usually shown as "+1") results in + the MSB being 1. + + Note that the usual hardware shift register implementation, which + is what we're using (we're merely optimizing it by doing eight-bit + chunks at a time) shifts bits into the lowest-order term. In our + implementation, that means shifting towards the right. Why do we + do it this way? Because the calculated CRC must be transmitted in + order from highest-order term to lowest-order term. UARTs transmit + characters in order from LSB to MSB. By storing the CRC this way, + we hand it to the UART in the order low-byte to high-byte; the UART + sends each low-bit to hight-bit; and the result is transmission bit + by bit from highest- to lowest-order term without requiring any bit + shuffling on our part. Reception works similarly. + + The feedback terms table consists of 256, 32-bit entries. Notes: + + 1. The table can be generated at runtime if desired; code to do so + is shown later. It might not be obvious, but the feedback + terms simply represent the results of eight shift/xor opera- + tions for all combinations of data and CRC register values. + + 2. The CRC accumulation logic is the same for all CRC polynomials, + be they sixteen or thirty-two bits wide. You simply choose the + appropriate table. Alternatively, because the table can be + generated at runtime, you can start by generating the table for + the polynomial in question and use exactly the same "updcrc", + if your application needn't simultaneously handle two CRC + polynomials. (Note, however, that XMODEM is strange.) + + 3. For 16-bit CRCs, the table entries need be only 16 bits wide; + of course, 32-bit entries work OK if the high 16 bits are zero. + + 4. The values must be right-shifted by eight bits by the "updcrc" + logic; the shift must be unsigned (bring in zeroes). On some + hardware you could probably optimize the shift in assembler by + using byte-swap instructions. +********************************************************************/ + +static unsigned long crc_32_tab[256] = { +0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, +0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, +0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, +0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, +0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, +0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, +0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, +0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, +0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, +0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, +0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, +0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, +0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, +0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, +0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, +0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, +0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, +0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, +0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, +0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, +0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, +0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, +0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, +0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, +0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, +0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, +0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, +0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, +0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, +0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, +0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, +0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, +0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, +0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, +0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, +0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, +0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, +0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, +0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, +0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, +0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, +0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, +0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, +0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, +0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, +0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, +0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, +0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, +0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, +0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, +0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, +0x2d02ef8dUL +}; + +static PyObject * +binascii_crc32(PyObject *self, PyObject *args) +{ /* By Jim Ahlstrom; All rights transferred to CNRI */ + unsigned char *bin_data; + unsigned long crc = 0UL; /* initial value of CRC */ + Py_ssize_t len; + long result; + + if ( !PyArg_ParseTuple(args, "s#|l:crc32", &bin_data, &len, &crc) ) + return NULL; + + crc = ~ crc; +#if SIZEOF_LONG > 4 + /* only want the trailing 32 bits */ + crc &= 0xFFFFFFFFUL; +#endif + while (len--) + crc = crc_32_tab[(crc ^ *bin_data++) & 0xffUL] ^ (crc >> 8); + /* Note: (crc >> 8) MUST zero fill on left */ + + result = (long)(crc ^ 0xFFFFFFFFUL); +#if SIZEOF_LONG > 4 + /* Extend the sign bit. This is one way to ensure the result is the + * same across platforms. The other way would be to return an + * unbounded unsigned long, but the evidence suggests that lots of + * code outside this treats the result as if it were a signed 4-byte + * integer. + */ + result |= -(result & (1L << 31)); +#endif + return PyInt_FromLong(result); +} + + +static PyObject * +binascii_hexlify(PyObject *self, PyObject *args) +{ + char* argbuf; + Py_ssize_t arglen; + PyObject *retval; + char* retbuf; + Py_ssize_t i, j; + + if (!PyArg_ParseTuple(args, "s#:b2a_hex", &argbuf, &arglen)) + return NULL; + + retval = PyString_FromStringAndSize(NULL, arglen*2); + if (!retval) + return NULL; + retbuf = PyString_AsString(retval); + if (!retbuf) + goto finally; + + /* make hex version of string, taken from shamodule.c */ + for (i=j=0; i < arglen; i++) { + char c; + c = (argbuf[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + c = argbuf[i] & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + retbuf[j++] = c; + } + return retval; + + finally: + Py_DECREF(retval); + return NULL; +} + +PyDoc_STRVAR(doc_hexlify, +"b2a_hex(data) -> s; Hexadecimal representation of binary data.\n\ +\n\ +This function is also available as \"hexlify()\"."); + + +static int +to_int(int c) +{ + if (isdigit(c)) + return c - '0'; + else { + if (isupper(c)) + c = tolower(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + } + return -1; +} + + +static PyObject * +binascii_unhexlify(PyObject *self, PyObject *args) +{ + char* argbuf; + Py_ssize_t arglen; + PyObject *retval; + char* retbuf; + Py_ssize_t i, j; + + if (!PyArg_ParseTuple(args, "s#:a2b_hex", &argbuf, &arglen)) + return NULL; + + /* XXX What should we do about strings with an odd length? Should + * we add an implicit leading zero, or a trailing zero? For now, + * raise an exception. + */ + if (arglen % 2) { + PyErr_SetString(PyExc_TypeError, "Odd-length string"); + return NULL; + } + + retval = PyString_FromStringAndSize(NULL, (arglen/2)); + if (!retval) + return NULL; + retbuf = PyString_AsString(retval); + if (!retbuf) + goto finally; + + for (i=j=0; i < arglen; i += 2) { + int top = to_int(Py_CHARMASK(argbuf[i])); + int bot = to_int(Py_CHARMASK(argbuf[i+1])); + if (top == -1 || bot == -1) { + PyErr_SetString(PyExc_TypeError, + "Non-hexadecimal digit found"); + goto finally; + } + retbuf[j++] = (top << 4) + bot; + } + return retval; + + finally: + Py_DECREF(retval); + return NULL; +} + +PyDoc_STRVAR(doc_unhexlify, +"a2b_hex(hexstr) -> s; Binary data of hexadecimal representation.\n\ +\n\ +hexstr must contain an even number of hex digits (upper or lower case).\n\ +This function is also available as \"unhexlify()\""); + +static int table_hex[128] = { + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 +}; + +#define hexval(c) table_hex[(unsigned int)(c)] + +#define MAXLINESIZE 76 + +PyDoc_STRVAR(doc_a2b_qp, "Decode a string of qp-encoded data"); + +static PyObject* +binascii_a2b_qp(PyObject *self, PyObject *args, PyObject *kwargs) +{ + Py_ssize_t in, out; + char ch; + unsigned char *data, *odata; + Py_ssize_t datalen = 0; + PyObject *rv; + static char *kwlist[] = {"data", "header", NULL}; + int header = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|i", kwlist, &data, + &datalen, &header)) + return NULL; + + /* We allocate the output same size as input, this is overkill. + * The previous implementation used calloc() so we'll zero out the + * memory here too, since PyMem_Malloc() does not guarantee that. + */ + odata = (unsigned char *) PyMem_Malloc(datalen); + if (odata == NULL) { + PyErr_NoMemory(); + return NULL; + } + memset(odata, 0, datalen); + + in = out = 0; + while (in < datalen) { + if (data[in] == '=') { + in++; + if (in >= datalen) break; + /* Soft line breaks */ + if ((data[in] == '\n') || (data[in] == '\r')) { + if (data[in] != '\n') { + while (in < datalen && data[in] != '\n') in++; + } + if (in < datalen) in++; + } + else if (data[in] == '=') { + /* broken case from broken python qp */ + odata[out++] = '='; + in++; + } + else if (((data[in] >= 'A' && data[in] <= 'F') || + (data[in] >= 'a' && data[in] <= 'f') || + (data[in] >= '0' && data[in] <= '9')) && + ((data[in+1] >= 'A' && data[in+1] <= 'F') || + (data[in+1] >= 'a' && data[in+1] <= 'f') || + (data[in+1] >= '0' && data[in+1] <= '9'))) { + /* hexval */ + ch = hexval(data[in]) << 4; + in++; + ch |= hexval(data[in]); + in++; + odata[out++] = ch; + } + else { + odata[out++] = '='; + } + } + else if (header && data[in] == '_') { + odata[out++] = ' '; + in++; + } + else { + odata[out] = data[in]; + in++; + out++; + } + } + if ((rv = PyString_FromStringAndSize((char *)odata, out)) == NULL) { + PyMem_Free(odata); + return NULL; + } + PyMem_Free(odata); + return rv; +} + +static int +to_hex (unsigned char ch, unsigned char *s) +{ + unsigned int uvalue = ch; + + s[1] = "0123456789ABCDEF"[uvalue % 16]; + uvalue = (uvalue / 16); + s[0] = "0123456789ABCDEF"[uvalue % 16]; + return 0; +} + +PyDoc_STRVAR(doc_b2a_qp, +"b2a_qp(data, quotetabs=0, istext=1, header=0) -> s; \n\ + Encode a string using quoted-printable encoding. \n\ +\n\ +On encoding, when istext is set, newlines are not encoded, and white \n\ +space at end of lines is. When istext is not set, \\r and \\n (CR/LF) are \n\ +both encoded. When quotetabs is set, space and tabs are encoded."); + +/* XXX: This is ridiculously complicated to be backward compatible + * (mostly) with the quopri module. It doesn't re-create the quopri + * module bug where text ending in CRLF has the CR encoded */ +static PyObject* +binascii_b2a_qp (PyObject *self, PyObject *args, PyObject *kwargs) +{ + Py_ssize_t in, out; + unsigned char *data, *odata; + Py_ssize_t datalen = 0, odatalen = 0; + PyObject *rv; + unsigned int linelen = 0; + static char *kwlist[] = {"data", "quotetabs", "istext", + "header", NULL}; + int istext = 1; + int quotetabs = 0; + int header = 0; + unsigned char ch; + int crlf = 0; + unsigned char *p; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|iii", kwlist, &data, + &datalen, &quotetabs, &istext, &header)) + return NULL; + + /* See if this string is using CRLF line ends */ + /* XXX: this function has the side effect of converting all of + * the end of lines to be the same depending on this detection + * here */ + p = (unsigned char *) strchr((char *)data, '\n'); + if ((p != NULL) && (p > data) && (*(p-1) == '\r')) + crlf = 1; + + /* First, scan to see how many characters need to be encoded */ + in = 0; + while (in < datalen) { + if ((data[in] > 126) || + (data[in] == '=') || + (header && data[in] == '_') || + ((data[in] == '.') && (linelen == 1)) || + (!istext && ((data[in] == '\r') || (data[in] == '\n'))) || + ((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) || + ((data[in] < 33) && + (data[in] != '\r') && (data[in] != '\n') && + (quotetabs && ((data[in] != '\t') || (data[in] != ' '))))) + { + if ((linelen + 3) >= MAXLINESIZE) { + linelen = 0; + if (crlf) + odatalen += 3; + else + odatalen += 2; + } + linelen += 3; + odatalen += 3; + in++; + } + else { + if (istext && + ((data[in] == '\n') || + ((in+1 < datalen) && (data[in] == '\r') && + (data[in+1] == '\n')))) + { + linelen = 0; + /* Protect against whitespace on end of line */ + if (in && ((data[in-1] == ' ') || (data[in-1] == '\t'))) + odatalen += 2; + if (crlf) + odatalen += 2; + else + odatalen += 1; + if (data[in] == '\r') + in += 2; + else + in++; + } + else { + if ((in + 1 != datalen) && + (data[in+1] != '\n') && + (linelen + 1) >= MAXLINESIZE) { + linelen = 0; + if (crlf) + odatalen += 3; + else + odatalen += 2; + } + linelen++; + odatalen++; + in++; + } + } + } + + /* We allocate the output same size as input, this is overkill. + * The previous implementation used calloc() so we'll zero out the + * memory here too, since PyMem_Malloc() does not guarantee that. + */ + odata = (unsigned char *) PyMem_Malloc(odatalen); + if (odata == NULL) { + PyErr_NoMemory(); + return NULL; + } + memset(odata, 0, odatalen); + + in = out = linelen = 0; + while (in < datalen) { + if ((data[in] > 126) || + (data[in] == '=') || + (header && data[in] == '_') || + ((data[in] == '.') && (linelen == 1)) || + (!istext && ((data[in] == '\r') || (data[in] == '\n'))) || + ((data[in] == '\t' || data[in] == ' ') && (in + 1 == datalen)) || + ((data[in] < 33) && + (data[in] != '\r') && (data[in] != '\n') && + (quotetabs && ((data[in] != '\t') || (data[in] != ' '))))) + { + if ((linelen + 3 )>= MAXLINESIZE) { + odata[out++] = '='; + if (crlf) odata[out++] = '\r'; + odata[out++] = '\n'; + linelen = 0; + } + odata[out++] = '='; + to_hex(data[in], &odata[out]); + out += 2; + in++; + linelen += 3; + } + else { + if (istext && + ((data[in] == '\n') || + ((in+1 < datalen) && (data[in] == '\r') && + (data[in+1] == '\n')))) + { + linelen = 0; + /* Protect against whitespace on end of line */ + if (out && ((odata[out-1] == ' ') || (odata[out-1] == '\t'))) { + ch = odata[out-1]; + odata[out-1] = '='; + to_hex(ch, &odata[out]); + out += 2; + } + + if (crlf) odata[out++] = '\r'; + odata[out++] = '\n'; + if (data[in] == '\r') + in += 2; + else + in++; + } + else { + if ((in + 1 != datalen) && + (data[in+1] != '\n') && + (linelen + 1) >= MAXLINESIZE) { + odata[out++] = '='; + if (crlf) odata[out++] = '\r'; + odata[out++] = '\n'; + linelen = 0; + } + linelen++; + if (header && data[in] == ' ') { + odata[out++] = '_'; + in++; + } + else { + odata[out++] = data[in++]; + } + } + } + } + if ((rv = PyString_FromStringAndSize((char *)odata, out)) == NULL) { + PyMem_Free(odata); + return NULL; + } + PyMem_Free(odata); + return rv; +} + +/* List of functions defined in the module */ + +static struct PyMethodDef binascii_module_methods[] = { + {"a2b_uu", binascii_a2b_uu, METH_VARARGS, doc_a2b_uu}, + {"b2a_uu", binascii_b2a_uu, METH_VARARGS, doc_b2a_uu}, + {"a2b_base64", binascii_a2b_base64, METH_VARARGS, doc_a2b_base64}, + {"b2a_base64", binascii_b2a_base64, METH_VARARGS, doc_b2a_base64}, + {"a2b_hqx", binascii_a2b_hqx, METH_VARARGS, doc_a2b_hqx}, + {"b2a_hqx", binascii_b2a_hqx, METH_VARARGS, doc_b2a_hqx}, + {"b2a_hex", binascii_hexlify, METH_VARARGS, doc_hexlify}, + {"a2b_hex", binascii_unhexlify, METH_VARARGS, doc_unhexlify}, + {"hexlify", binascii_hexlify, METH_VARARGS, doc_hexlify}, + {"unhexlify", binascii_unhexlify, METH_VARARGS, doc_unhexlify}, + {"rlecode_hqx", binascii_rlecode_hqx, METH_VARARGS, doc_rlecode_hqx}, + {"rledecode_hqx", binascii_rledecode_hqx, METH_VARARGS, + doc_rledecode_hqx}, + {"crc_hqx", binascii_crc_hqx, METH_VARARGS, doc_crc_hqx}, + {"crc32", binascii_crc32, METH_VARARGS, doc_crc32}, + {"a2b_qp", (PyCFunction)binascii_a2b_qp, METH_VARARGS | METH_KEYWORDS, + doc_a2b_qp}, + {"b2a_qp", (PyCFunction)binascii_b2a_qp, METH_VARARGS | METH_KEYWORDS, + doc_b2a_qp}, + {NULL, NULL} /* sentinel */ +}; + + +/* Initialization function for the module (*must* be called initbinascii) */ +PyDoc_STRVAR(doc_binascii, "Conversion between binary data and ASCII"); + +PyMODINIT_FUNC +initbinascii(void) +{ + PyObject *m, *d, *x; + + /* Create the module and add the functions */ + m = Py_InitModule("binascii", binascii_module_methods); + if (m == NULL) + return; + + d = PyModule_GetDict(m); + x = PyString_FromString(doc_binascii); + PyDict_SetItemString(d, "__doc__", x); + Py_XDECREF(x); + + Error = PyErr_NewException("binascii.Error", NULL, NULL); + PyDict_SetItemString(d, "Error", Error); + Incomplete = PyErr_NewException("binascii.Incomplete", NULL, NULL); + PyDict_SetItemString(d, "Incomplete", Incomplete); +} diff --git a/sys/src/cmd/python/Modules/bsddbmodule.c b/sys/src/cmd/python/Modules/bsddbmodule.c new file mode 100644 index 000000000..61c656437 --- /dev/null +++ b/sys/src/cmd/python/Modules/bsddbmodule.c @@ -0,0 +1,858 @@ +/* Berkeley DB interface. + Author: Michael McLay + Hacked: Guido van Rossum + Btree and Recno additions plus sequence methods: David Ely + Hacked by Gustavo Niemeyer <niemeyer@conectiva.com> fixing recno + support. + + XXX To do: + - provide a way to access the various hash functions + - support more open flags + + The windows port of the Berkeley DB code is hard to find on the web: + www.nightmare.com/software.html +*/ + +#include "Python.h" +#ifdef WITH_THREAD +#include "pythread.h" +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#ifdef HAVE_DB_185_H +#include <db_185.h> +#else +#include <db.h> +#endif +/* Please don't include internal header files of the Berkeley db package + (it messes up the info required in the Setup file) */ + +typedef struct { + PyObject_HEAD + DB *di_bsddb; + int di_size; /* -1 means recompute */ + int di_type; +#ifdef WITH_THREAD + PyThread_type_lock di_lock; +#endif +} bsddbobject; + +static PyTypeObject Bsddbtype; + +#define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype) +#define check_bsddbobject_open(v, r) if ((v)->di_bsddb == NULL) \ + { PyErr_SetString(BsddbError, \ + "BSDDB object has already been closed"); \ + return r; } + +static PyObject *BsddbError; + +static PyObject * +newdbhashobject(char *file, int flags, int mode, + int bsize, int ffactor, int nelem, int cachesize, + int hash, int lorder) +{ + bsddbobject *dp; + HASHINFO info; + + if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL) + return NULL; + + info.bsize = bsize; + info.ffactor = ffactor; + info.nelem = nelem; + info.cachesize = cachesize; + info.hash = NULL; /* XXX should derive from hash argument */ + info.lorder = lorder; + +#ifdef O_BINARY + flags |= O_BINARY; +#endif + Py_BEGIN_ALLOW_THREADS + dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info); + Py_END_ALLOW_THREADS + if (dp->di_bsddb == NULL) { + PyErr_SetFromErrno(BsddbError); +#ifdef WITH_THREAD + dp->di_lock = NULL; +#endif + Py_DECREF(dp); + return NULL; + } + + dp->di_size = -1; + dp->di_type = DB_HASH; + +#ifdef WITH_THREAD + dp->di_lock = PyThread_allocate_lock(); + if (dp->di_lock == NULL) { + PyErr_SetString(BsddbError, "can't allocate lock"); + Py_DECREF(dp); + return NULL; + } +#endif + + return (PyObject *)dp; +} + +static PyObject * +newdbbtobject(char *file, int flags, int mode, + int btflags, int cachesize, int maxkeypage, + int minkeypage, int psize, int lorder) +{ + bsddbobject *dp; + BTREEINFO info; + + if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL) + return NULL; + + info.flags = btflags; + info.cachesize = cachesize; + info.maxkeypage = maxkeypage; + info.minkeypage = minkeypage; + info.psize = psize; + info.lorder = lorder; + info.compare = 0; /* Use default comparison functions, for now..*/ + info.prefix = 0; + +#ifdef O_BINARY + flags |= O_BINARY; +#endif + Py_BEGIN_ALLOW_THREADS + dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info); + Py_END_ALLOW_THREADS + if (dp->di_bsddb == NULL) { + PyErr_SetFromErrno(BsddbError); +#ifdef WITH_THREAD + dp->di_lock = NULL; +#endif + Py_DECREF(dp); + return NULL; + } + + dp->di_size = -1; + dp->di_type = DB_BTREE; + +#ifdef WITH_THREAD + dp->di_lock = PyThread_allocate_lock(); + if (dp->di_lock == NULL) { + PyErr_SetString(BsddbError, "can't allocate lock"); + Py_DECREF(dp); + return NULL; + } +#endif + + return (PyObject *)dp; +} + +static PyObject * +newdbrnobject(char *file, int flags, int mode, + int rnflags, int cachesize, int psize, int lorder, + size_t reclen, u_char bval, char *bfname) +{ + bsddbobject *dp; + RECNOINFO info; + int fd; + + if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL) + return NULL; + + info.flags = rnflags; + info.cachesize = cachesize; + info.psize = psize; + info.lorder = lorder; + info.reclen = reclen; + info.bval = bval; + info.bfname = bfname; + +#ifdef O_BINARY + flags |= O_BINARY; +#endif + /* This is a hack to avoid a dbopen() bug that happens when + * it fails. */ + fd = open(file, flags); + if (fd == -1) { + dp->di_bsddb = NULL; + } + else { + close(fd); + Py_BEGIN_ALLOW_THREADS + dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info); + Py_END_ALLOW_THREADS + } + if (dp->di_bsddb == NULL) { + PyErr_SetFromErrno(BsddbError); +#ifdef WITH_THREAD + dp->di_lock = NULL; +#endif + Py_DECREF(dp); + return NULL; + } + + dp->di_size = -1; + dp->di_type = DB_RECNO; + +#ifdef WITH_THREAD + dp->di_lock = PyThread_allocate_lock(); + if (dp->di_lock == NULL) { + PyErr_SetString(BsddbError, "can't allocate lock"); + Py_DECREF(dp); + return NULL; + } +#endif + + return (PyObject *)dp; +} + +static void +bsddb_dealloc(bsddbobject *dp) +{ +#ifdef WITH_THREAD + if (dp->di_lock) { + PyThread_acquire_lock(dp->di_lock, 0); + PyThread_release_lock(dp->di_lock); + PyThread_free_lock(dp->di_lock); + dp->di_lock = NULL; + } +#endif + if (dp->di_bsddb != NULL) { + int status; + Py_BEGIN_ALLOW_THREADS + status = (dp->di_bsddb->close)(dp->di_bsddb); + Py_END_ALLOW_THREADS + if (status != 0) + fprintf(stderr, + "Python bsddb: close errno %d in dealloc\n", + errno); + } + PyObject_Del(dp); +} + +#ifdef WITH_THREAD +#define BSDDB_BGN_SAVE(_dp) \ + Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1); +#define BSDDB_END_SAVE(_dp) \ + PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS +#else +#define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS +#define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS +#endif + +static Py_ssize_t +bsddb_length(bsddbobject *dp) +{ + check_bsddbobject_open(dp, -1); + if (dp->di_size < 0) { + DBT krec, drec; + int status; + int size = 0; + BSDDB_BGN_SAVE(dp) + for (status = (dp->di_bsddb->seq)(dp->di_bsddb, + &krec, &drec,R_FIRST); + status == 0; + status = (dp->di_bsddb->seq)(dp->di_bsddb, + &krec, &drec, R_NEXT)) + size++; + BSDDB_END_SAVE(dp) + if (status < 0) { + PyErr_SetFromErrno(BsddbError); + return -1; + } + dp->di_size = size; + } + return dp->di_size; +} + +static PyObject * +bsddb_subscript(bsddbobject *dp, PyObject *key) +{ + int status; + DBT krec, drec; + char *data,buf[4096]; + int size; + PyObject *result; + recno_t recno; + + if (dp->di_type == DB_RECNO) { + if (!PyArg_Parse(key, "i", &recno)) { + PyErr_SetString(PyExc_TypeError, + "key type must be integer"); + return NULL; + } + krec.data = &recno; + krec.size = sizeof(recno); + } + else { + if (!PyArg_Parse(key, "s#", &data, &size)) { + PyErr_SetString(PyExc_TypeError, + "key type must be string"); + return NULL; + } + krec.data = data; + krec.size = size; + } + check_bsddbobject_open(dp, NULL); + + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0); + if (status == 0) { + if (drec.size > sizeof(buf)) data = malloc(drec.size); + else data = buf; + if (data!=NULL) memcpy(data,drec.data,drec.size); + } + BSDDB_END_SAVE(dp) + if (data==NULL) return PyErr_NoMemory(); + if (status != 0) { + if (status < 0) + PyErr_SetFromErrno(BsddbError); + else + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + + result = PyString_FromStringAndSize(data, (int)drec.size); + if (data != buf) free(data); + return result; +} + +static int +bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value) +{ + int status; + DBT krec, drec; + char *data; + int size; + recno_t recno; + + if (dp->di_type == DB_RECNO) { + if (!PyArg_Parse(key, "i", &recno)) { + PyErr_SetString(PyExc_TypeError, + "bsddb key type must be integer"); + return -1; + } + krec.data = &recno; + krec.size = sizeof(recno); + } + else { + if (!PyArg_Parse(key, "s#", &data, &size)) { + PyErr_SetString(PyExc_TypeError, + "bsddb key type must be string"); + return -1; + } + krec.data = data; + krec.size = size; + } + check_bsddbobject_open(dp, -1); + dp->di_size = -1; + if (value == NULL) { + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0); + BSDDB_END_SAVE(dp) + } + else { + if (!PyArg_Parse(value, "s#", &data, &size)) { + PyErr_SetString(PyExc_TypeError, + "bsddb value type must be string"); + return -1; + } + drec.data = data; + drec.size = size; + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0); + BSDDB_END_SAVE(dp) + } + if (status != 0) { + if (status < 0) + PyErr_SetFromErrno(BsddbError); + else + PyErr_SetObject(PyExc_KeyError, key); + return -1; + } + return 0; +} + +static PyMappingMethods bsddb_as_mapping = { + (lenfunc)bsddb_length, /*mp_length*/ + (binaryfunc)bsddb_subscript, /*mp_subscript*/ + (objobjargproc)bsddb_ass_sub, /*mp_ass_subscript*/ +}; + +static PyObject * +bsddb_close(bsddbobject *dp) +{ + if (dp->di_bsddb != NULL) { + int status; + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->close)(dp->di_bsddb); + BSDDB_END_SAVE(dp) + if (status != 0) { + dp->di_bsddb = NULL; + PyErr_SetFromErrno(BsddbError); + return NULL; + } + } + dp->di_bsddb = NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +bsddb_keys(bsddbobject *dp) +{ + PyObject *list, *item=NULL; + DBT krec, drec; + char *data=NULL,buf[4096]; + int status; + int err; + + check_bsddbobject_open(dp, NULL); + list = PyList_New(0); + if (list == NULL) + return NULL; + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST); + if (status == 0) { + if (krec.size > sizeof(buf)) data = malloc(krec.size); + else data = buf; + if (data != NULL) memcpy(data,krec.data,krec.size); + } + BSDDB_END_SAVE(dp) + if (status == 0 && data==NULL) return PyErr_NoMemory(); + while (status == 0) { + if (dp->di_type == DB_RECNO) + item = PyInt_FromLong(*((int*)data)); + else + item = PyString_FromStringAndSize(data, + (int)krec.size); + if (data != buf) free(data); + if (item == NULL) { + Py_DECREF(list); + return NULL; + } + err = PyList_Append(list, item); + Py_DECREF(item); + if (err != 0) { + Py_DECREF(list); + return NULL; + } + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->seq) + (dp->di_bsddb, &krec, &drec, R_NEXT); + if (status == 0) { + if (krec.size > sizeof(buf)) + data = malloc(krec.size); + else data = buf; + if (data != NULL) + memcpy(data,krec.data,krec.size); + } + BSDDB_END_SAVE(dp) + if (data == NULL) return PyErr_NoMemory(); + } + if (status < 0) { + PyErr_SetFromErrno(BsddbError); + Py_DECREF(list); + return NULL; + } + if (dp->di_size < 0) + dp->di_size = PyList_Size(list); /* We just did the work */ + return list; +} + +static PyObject * +bsddb_has_key(bsddbobject *dp, PyObject *args) +{ + DBT krec, drec; + int status; + char *data; + int size; + recno_t recno; + + if (dp->di_type == DB_RECNO) { + if (!PyArg_ParseTuple(args, "i;key type must be integer", + &recno)) { + return NULL; + } + krec.data = &recno; + krec.size = sizeof(recno); + } + else { + if (!PyArg_ParseTuple(args, "s#;key type must be string", + &data, &size)) { + return NULL; + } + krec.data = data; + krec.size = size; + } + check_bsddbobject_open(dp, NULL); + + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0); + BSDDB_END_SAVE(dp) + if (status < 0) { + PyErr_SetFromErrno(BsddbError); + return NULL; + } + + return PyInt_FromLong(status == 0); +} + +static PyObject * +bsddb_set_location(bsddbobject *dp, PyObject *key) +{ + int status; + DBT krec, drec; + char *data,buf[4096]; + int size; + PyObject *result; + recno_t recno; + + if (dp->di_type == DB_RECNO) { + if (!PyArg_ParseTuple(key, "i;key type must be integer", + &recno)) { + return NULL; + } + krec.data = &recno; + krec.size = sizeof(recno); + } + else { + if (!PyArg_ParseTuple(key, "s#;key type must be string", + &data, &size)) { + return NULL; + } + krec.data = data; + krec.size = size; + } + check_bsddbobject_open(dp, NULL); + + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR); + if (status == 0) { + if (drec.size > sizeof(buf)) data = malloc(drec.size); + else data = buf; + if (data!=NULL) memcpy(data,drec.data,drec.size); + } + BSDDB_END_SAVE(dp) + if (data==NULL) return PyErr_NoMemory(); + if (status != 0) { + if (status < 0) + PyErr_SetFromErrno(BsddbError); + else + PyErr_SetObject(PyExc_KeyError, key); + return NULL; + } + + if (dp->di_type == DB_RECNO) + result = Py_BuildValue("is#", *((int*)krec.data), + data, drec.size); + else + result = Py_BuildValue("s#s#", krec.data, krec.size, + data, drec.size); + if (data != buf) free(data); + return result; +} + +static PyObject * +bsddb_seq(bsddbobject *dp, int sequence_request) +{ + int status; + DBT krec, drec; + char *kdata=NULL,kbuf[4096]; + char *ddata=NULL,dbuf[4096]; + PyObject *result; + + check_bsddbobject_open(dp, NULL); + krec.data = 0; + krec.size = 0; + + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, + &drec, sequence_request); + if (status == 0) { + if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size); + else kdata = kbuf; + if (kdata != NULL) memcpy(kdata,krec.data,krec.size); + if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size); + else ddata = dbuf; + if (ddata != NULL) memcpy(ddata,drec.data,drec.size); + } + BSDDB_END_SAVE(dp) + if (status == 0) { + if ((kdata == NULL) || (ddata == NULL)) + return PyErr_NoMemory(); + } + else { + /* (status != 0) */ + if (status < 0) + PyErr_SetFromErrno(BsddbError); + else + PyErr_SetString(PyExc_KeyError, "no key/data pairs"); + return NULL; + } + + if (dp->di_type == DB_RECNO) + result = Py_BuildValue("is#", *((int*)kdata), + ddata, drec.size); + else + result = Py_BuildValue("s#s#", kdata, krec.size, + ddata, drec.size); + if (kdata != kbuf) free(kdata); + if (ddata != dbuf) free(ddata); + return result; +} + +static PyObject * +bsddb_next(bsddbobject *dp) +{ + return bsddb_seq(dp, R_NEXT); +} +static PyObject * +bsddb_previous(bsddbobject *dp) +{ + return bsddb_seq(dp, R_PREV); +} +static PyObject * +bsddb_first(bsddbobject *dp) +{ + return bsddb_seq(dp, R_FIRST); +} +static PyObject * +bsddb_last(bsddbobject *dp) +{ + return bsddb_seq(dp, R_LAST); +} +static PyObject * +bsddb_sync(bsddbobject *dp) +{ + int status; + + check_bsddbobject_open(dp, NULL); + BSDDB_BGN_SAVE(dp) + status = (dp->di_bsddb->sync)(dp->di_bsddb, 0); + BSDDB_END_SAVE(dp) + if (status != 0) { + PyErr_SetFromErrno(BsddbError); + return NULL; + } + return PyInt_FromLong(status = 0); +} +static PyMethodDef bsddb_methods[] = { + {"close", (PyCFunction)bsddb_close, METH_NOARGS}, + {"keys", (PyCFunction)bsddb_keys, METH_NOARGS}, + {"has_key", (PyCFunction)bsddb_has_key, METH_VARARGS}, + {"set_location", (PyCFunction)bsddb_set_location, METH_VARARGS}, + {"next", (PyCFunction)bsddb_next, METH_NOARGS}, + {"previous", (PyCFunction)bsddb_previous, METH_NOARGS}, + {"first", (PyCFunction)bsddb_first, METH_NOARGS}, + {"last", (PyCFunction)bsddb_last, METH_NOARGS}, + {"sync", (PyCFunction)bsddb_sync, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +bsddb_getattr(PyObject *dp, char *name) +{ + return Py_FindMethod(bsddb_methods, dp, name); +} + +static PyTypeObject Bsddbtype = { + PyObject_HEAD_INIT(NULL) + 0, + "bsddb.bsddb", + sizeof(bsddbobject), + 0, + (destructor)bsddb_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)bsddb_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &bsddb_as_mapping, /*tp_as_mapping*/ +}; + +static PyObject * +bsdhashopen(PyObject *self, PyObject *args) +{ + char *file; + char *flag = NULL; + int flags = O_RDONLY; + int mode = 0666; + int bsize = 0; + int ffactor = 0; + int nelem = 0; + int cachesize = 0; + int hash = 0; /* XXX currently ignored */ + int lorder = 0; + + if (!PyArg_ParseTuple(args, "z|siiiiiii:hashopen", + &file, &flag, &mode, + &bsize, &ffactor, &nelem, &cachesize, + &hash, &lorder)) + return NULL; + if (flag != NULL) { + /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */ + if (flag[0] == 'r') + flags = O_RDONLY; + else if (flag[0] == 'w') + flags = O_RDWR; + else if (flag[0] == 'c') + flags = O_RDWR|O_CREAT; + else if (flag[0] == 'n') + flags = O_RDWR|O_CREAT|O_TRUNC; + else { + PyErr_SetString(BsddbError, + "Flag should begin with 'r', 'w', 'c' or 'n'"); + return NULL; + } + if (flag[1] == 'l') { +#if defined(O_EXLOCK) && defined(O_SHLOCK) + if (flag[0] == 'r') + flags |= O_SHLOCK; + else + flags |= O_EXLOCK; +#else + PyErr_SetString(BsddbError, + "locking not supported on this platform"); + return NULL; +#endif + } + } + return newdbhashobject(file, flags, mode, + bsize, ffactor, nelem, cachesize, hash, lorder); +} + +static PyObject * +bsdbtopen(PyObject *self, PyObject *args) +{ + char *file; + char *flag = NULL; + int flags = O_RDONLY; + int mode = 0666; + int cachesize = 0; + int maxkeypage = 0; + int minkeypage = 0; + int btflags = 0; + unsigned int psize = 0; + int lorder = 0; + + if (!PyArg_ParseTuple(args, "z|siiiiiii:btopen", + &file, &flag, &mode, + &btflags, &cachesize, &maxkeypage, &minkeypage, + &psize, &lorder)) + return NULL; + if (flag != NULL) { + /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */ + if (flag[0] == 'r') + flags = O_RDONLY; + else if (flag[0] == 'w') + flags = O_RDWR; + else if (flag[0] == 'c') + flags = O_RDWR|O_CREAT; + else if (flag[0] == 'n') + flags = O_RDWR|O_CREAT|O_TRUNC; + else { + PyErr_SetString(BsddbError, + "Flag should begin with 'r', 'w', 'c' or 'n'"); + return NULL; + } + if (flag[1] == 'l') { +#if defined(O_EXLOCK) && defined(O_SHLOCK) + if (flag[0] == 'r') + flags |= O_SHLOCK; + else + flags |= O_EXLOCK; +#else + PyErr_SetString(BsddbError, + "locking not supported on this platform"); + return NULL; +#endif + } + } + return newdbbtobject(file, flags, mode, + btflags, cachesize, maxkeypage, minkeypage, + psize, lorder); +} + +static PyObject * +bsdrnopen(PyObject *self, PyObject *args) +{ + char *file; + char *flag = NULL; + int flags = O_RDONLY; + int mode = 0666; + int cachesize = 0; + int rnflags = 0; + unsigned int psize = 0; + int lorder = 0; + size_t reclen = 0; + char *bval = ""; + char *bfname = NULL; + + if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen", + &file, &flag, &mode, + &rnflags, &cachesize, &psize, &lorder, + &reclen, &bval, &bfname)) + return NULL; + + if (flag != NULL) { + /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */ + if (flag[0] == 'r') + flags = O_RDONLY; + else if (flag[0] == 'w') + flags = O_RDWR; + else if (flag[0] == 'c') + flags = O_RDWR|O_CREAT; + else if (flag[0] == 'n') + flags = O_RDWR|O_CREAT|O_TRUNC; + else { + PyErr_SetString(BsddbError, + "Flag should begin with 'r', 'w', 'c' or 'n'"); + return NULL; + } + if (flag[1] == 'l') { +#if defined(O_EXLOCK) && defined(O_SHLOCK) + if (flag[0] == 'r') + flags |= O_SHLOCK; + else + flags |= O_EXLOCK; +#else + PyErr_SetString(BsddbError, + "locking not supported on this platform"); + return NULL; +#endif + } + else if (flag[1] != '\0') { + PyErr_SetString(BsddbError, + "Flag char 2 should be 'l' or absent"); + return NULL; + } + } + return newdbrnobject(file, flags, mode, rnflags, cachesize, + psize, lorder, reclen, bval[0], bfname); +} + +static PyMethodDef bsddbmodule_methods[] = { + {"hashopen", (PyCFunction)bsdhashopen, METH_VARARGS}, + {"btopen", (PyCFunction)bsdbtopen, METH_VARARGS}, + {"rnopen", (PyCFunction)bsdrnopen, METH_VARARGS}, + /* strictly for use by dbhhash!!! */ + {"open", (PyCFunction)bsdhashopen, METH_VARARGS}, + {0, 0}, +}; + +PyMODINIT_FUNC +initbsddb185(void) { + PyObject *m, *d; + + Bsddbtype.ob_type = &PyType_Type; + m = Py_InitModule("bsddb185", bsddbmodule_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + BsddbError = PyErr_NewException("bsddb.error", NULL, NULL); + if (BsddbError != NULL) + PyDict_SetItemString(d, "error", BsddbError); +} diff --git a/sys/src/cmd/python/Modules/bz2module.c b/sys/src/cmd/python/Modules/bz2module.c new file mode 100644 index 000000000..9d92cf6bb --- /dev/null +++ b/sys/src/cmd/python/Modules/bz2module.c @@ -0,0 +1,2230 @@ +/* + +python-bz2 - python bz2 library interface + +Copyright (c) 2002 Gustavo Niemeyer <niemeyer@conectiva.com> +Copyright (c) 2002 Python Software Foundation; All Rights Reserved + +*/ + +#include "Python.h" +#include <stdio.h> +#include <bzlib.h> +#include "structmember.h" + +#ifdef WITH_THREAD +#include "pythread.h" +#endif + +static char __author__[] = +"The bz2 python module was written by:\n\ +\n\ + Gustavo Niemeyer <niemeyer@conectiva.com>\n\ +"; + +/* Our very own off_t-like type, 64-bit if possible */ +/* copied from Objects/fileobject.c */ +#if !defined(HAVE_LARGEFILE_SUPPORT) +typedef off_t Py_off_t; +#elif SIZEOF_OFF_T >= 8 +typedef off_t Py_off_t; +#elif SIZEOF_FPOS_T >= 8 +typedef fpos_t Py_off_t; +#else +#error "Large file support, but neither off_t nor fpos_t is large enough." +#endif + +#define BUF(v) PyString_AS_STRING((PyStringObject *)v) + +#define MODE_CLOSED 0 +#define MODE_READ 1 +#define MODE_READ_EOF 2 +#define MODE_WRITE 3 + +#define BZ2FileObject_Check(v) ((v)->ob_type == &BZ2File_Type) + + +#ifdef BZ_CONFIG_ERROR + +#if SIZEOF_LONG >= 8 +#define BZS_TOTAL_OUT(bzs) \ + (((long)bzs->total_out_hi32 << 32) + bzs->total_out_lo32) +#elif SIZEOF_LONG_LONG >= 8 +#define BZS_TOTAL_OUT(bzs) \ + (((PY_LONG_LONG)bzs->total_out_hi32 << 32) + bzs->total_out_lo32) +#else +#define BZS_TOTAL_OUT(bzs) \ + bzs->total_out_lo32 +#endif + +#else /* ! BZ_CONFIG_ERROR */ + +#define BZ2_bzRead bzRead +#define BZ2_bzReadOpen bzReadOpen +#define BZ2_bzReadClose bzReadClose +#define BZ2_bzWrite bzWrite +#define BZ2_bzWriteOpen bzWriteOpen +#define BZ2_bzWriteClose bzWriteClose +#define BZ2_bzCompress bzCompress +#define BZ2_bzCompressInit bzCompressInit +#define BZ2_bzCompressEnd bzCompressEnd +#define BZ2_bzDecompress bzDecompress +#define BZ2_bzDecompressInit bzDecompressInit +#define BZ2_bzDecompressEnd bzDecompressEnd + +#define BZS_TOTAL_OUT(bzs) bzs->total_out + +#endif /* ! BZ_CONFIG_ERROR */ + + +#ifdef WITH_THREAD +#define ACQUIRE_LOCK(obj) PyThread_acquire_lock(obj->lock, 1) +#define RELEASE_LOCK(obj) PyThread_release_lock(obj->lock) +#else +#define ACQUIRE_LOCK(obj) +#define RELEASE_LOCK(obj) +#endif + +/* Bits in f_newlinetypes */ +#define NEWLINE_UNKNOWN 0 /* No newline seen, yet */ +#define NEWLINE_CR 1 /* \r newline seen */ +#define NEWLINE_LF 2 /* \n newline seen */ +#define NEWLINE_CRLF 4 /* \r\n newline seen */ + +/* ===================================================================== */ +/* Structure definitions. */ + +typedef struct { + PyObject_HEAD + PyObject *file; + + char* f_buf; /* Allocated readahead buffer */ + char* f_bufend; /* Points after last occupied position */ + char* f_bufptr; /* Current buffer position */ + + int f_softspace; /* Flag used by 'print' command */ + + int f_univ_newline; /* Handle any newline convention */ + int f_newlinetypes; /* Types of newlines seen */ + int f_skipnextlf; /* Skip next \n */ + + BZFILE *fp; + int mode; + Py_off_t pos; + Py_off_t size; +#ifdef WITH_THREAD + PyThread_type_lock lock; +#endif +} BZ2FileObject; + +typedef struct { + PyObject_HEAD + bz_stream bzs; + int running; +#ifdef WITH_THREAD + PyThread_type_lock lock; +#endif +} BZ2CompObject; + +typedef struct { + PyObject_HEAD + bz_stream bzs; + int running; + PyObject *unused_data; +#ifdef WITH_THREAD + PyThread_type_lock lock; +#endif +} BZ2DecompObject; + +/* ===================================================================== */ +/* Utility functions. */ + +static int +Util_CatchBZ2Error(int bzerror) +{ + int ret = 0; + switch(bzerror) { + case BZ_OK: + case BZ_STREAM_END: + break; + +#ifdef BZ_CONFIG_ERROR + case BZ_CONFIG_ERROR: + PyErr_SetString(PyExc_SystemError, + "the bz2 library was not compiled " + "correctly"); + ret = 1; + break; +#endif + + case BZ_PARAM_ERROR: + PyErr_SetString(PyExc_ValueError, + "the bz2 library has received wrong " + "parameters"); + ret = 1; + break; + + case BZ_MEM_ERROR: + PyErr_NoMemory(); + ret = 1; + break; + + case BZ_DATA_ERROR: + case BZ_DATA_ERROR_MAGIC: + PyErr_SetString(PyExc_IOError, "invalid data stream"); + ret = 1; + break; + + case BZ_IO_ERROR: + PyErr_SetString(PyExc_IOError, "unknown IO error"); + ret = 1; + break; + + case BZ_UNEXPECTED_EOF: + PyErr_SetString(PyExc_EOFError, + "compressed file ended before the " + "logical end-of-stream was detected"); + ret = 1; + break; + + case BZ_SEQUENCE_ERROR: + PyErr_SetString(PyExc_RuntimeError, + "wrong sequence of bz2 library " + "commands used"); + ret = 1; + break; + } + return ret; +} + +#if BUFSIZ < 8192 +#define SMALLCHUNK 8192 +#else +#define SMALLCHUNK BUFSIZ +#endif + +#if SIZEOF_INT < 4 +#define BIGCHUNK (512 * 32) +#else +#define BIGCHUNK (512 * 1024) +#endif + +/* This is a hacked version of Python's fileobject.c:new_buffersize(). */ +static size_t +Util_NewBufferSize(size_t currentsize) +{ + if (currentsize > SMALLCHUNK) { + /* Keep doubling until we reach BIGCHUNK; + then keep adding BIGCHUNK. */ + if (currentsize <= BIGCHUNK) + return currentsize + currentsize; + else + return currentsize + BIGCHUNK; + } + return currentsize + SMALLCHUNK; +} + +/* This is a hacked version of Python's fileobject.c:get_line(). */ +static PyObject * +Util_GetLine(BZ2FileObject *f, int n) +{ + char c; + char *buf, *end; + size_t total_v_size; /* total # of slots in buffer */ + size_t used_v_size; /* # used slots in buffer */ + size_t increment; /* amount to increment the buffer */ + PyObject *v; + int bzerror; + int newlinetypes = f->f_newlinetypes; + int skipnextlf = f->f_skipnextlf; + int univ_newline = f->f_univ_newline; + + total_v_size = n > 0 ? n : 100; + v = PyString_FromStringAndSize((char *)NULL, total_v_size); + if (v == NULL) + return NULL; + + buf = BUF(v); + end = buf + total_v_size; + + for (;;) { + Py_BEGIN_ALLOW_THREADS + if (univ_newline) { + while (1) { + BZ2_bzRead(&bzerror, f->fp, &c, 1); + f->pos++; + if (bzerror != BZ_OK || buf == end) + break; + if (skipnextlf) { + skipnextlf = 0; + if (c == '\n') { + /* Seeing a \n here with + * skipnextlf true means we + * saw a \r before. + */ + newlinetypes |= NEWLINE_CRLF; + BZ2_bzRead(&bzerror, f->fp, + &c, 1); + if (bzerror != BZ_OK) + break; + } else { + newlinetypes |= NEWLINE_CR; + } + } + if (c == '\r') { + skipnextlf = 1; + c = '\n'; + } else if ( c == '\n') + newlinetypes |= NEWLINE_LF; + *buf++ = c; + if (c == '\n') break; + } + if (bzerror == BZ_STREAM_END && skipnextlf) + newlinetypes |= NEWLINE_CR; + } else /* If not universal newlines use the normal loop */ + do { + BZ2_bzRead(&bzerror, f->fp, &c, 1); + f->pos++; + *buf++ = c; + } while (bzerror == BZ_OK && c != '\n' && buf != end); + Py_END_ALLOW_THREADS + f->f_newlinetypes = newlinetypes; + f->f_skipnextlf = skipnextlf; + if (bzerror == BZ_STREAM_END) { + f->size = f->pos; + f->mode = MODE_READ_EOF; + break; + } else if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + Py_DECREF(v); + return NULL; + } + if (c == '\n') + break; + /* Must be because buf == end */ + if (n > 0) + break; + used_v_size = total_v_size; + increment = total_v_size >> 2; /* mild exponential growth */ + total_v_size += increment; + if (total_v_size > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "line is longer than a Python string can hold"); + Py_DECREF(v); + return NULL; + } + if (_PyString_Resize(&v, total_v_size) < 0) + return NULL; + buf = BUF(v) + used_v_size; + end = BUF(v) + total_v_size; + } + + used_v_size = buf - BUF(v); + if (used_v_size != total_v_size) + _PyString_Resize(&v, used_v_size); + return v; +} + +/* This is a hacked version of Python's + * fileobject.c:Py_UniversalNewlineFread(). */ +size_t +Util_UnivNewlineRead(int *bzerror, BZFILE *stream, + char* buf, size_t n, BZ2FileObject *f) +{ + char *dst = buf; + int newlinetypes, skipnextlf; + + assert(buf != NULL); + assert(stream != NULL); + + if (!f->f_univ_newline) + return BZ2_bzRead(bzerror, stream, buf, n); + + newlinetypes = f->f_newlinetypes; + skipnextlf = f->f_skipnextlf; + + /* Invariant: n is the number of bytes remaining to be filled + * in the buffer. + */ + while (n) { + size_t nread; + int shortread; + char *src = dst; + + nread = BZ2_bzRead(bzerror, stream, dst, n); + assert(nread <= n); + n -= nread; /* assuming 1 byte out for each in; will adjust */ + shortread = n != 0; /* true iff EOF or error */ + while (nread--) { + char c = *src++; + if (c == '\r') { + /* Save as LF and set flag to skip next LF. */ + *dst++ = '\n'; + skipnextlf = 1; + } + else if (skipnextlf && c == '\n') { + /* Skip LF, and remember we saw CR LF. */ + skipnextlf = 0; + newlinetypes |= NEWLINE_CRLF; + ++n; + } + else { + /* Normal char to be stored in buffer. Also + * update the newlinetypes flag if either this + * is an LF or the previous char was a CR. + */ + if (c == '\n') + newlinetypes |= NEWLINE_LF; + else if (skipnextlf) + newlinetypes |= NEWLINE_CR; + *dst++ = c; + skipnextlf = 0; + } + } + if (shortread) { + /* If this is EOF, update type flags. */ + if (skipnextlf && *bzerror == BZ_STREAM_END) + newlinetypes |= NEWLINE_CR; + break; + } + } + f->f_newlinetypes = newlinetypes; + f->f_skipnextlf = skipnextlf; + return dst - buf; +} + +/* This is a hacked version of Python's fileobject.c:drop_readahead(). */ +static void +Util_DropReadAhead(BZ2FileObject *f) +{ + if (f->f_buf != NULL) { + PyMem_Free(f->f_buf); + f->f_buf = NULL; + } +} + +/* This is a hacked version of Python's fileobject.c:readahead(). */ +static int +Util_ReadAhead(BZ2FileObject *f, int bufsize) +{ + int chunksize; + int bzerror; + + if (f->f_buf != NULL) { + if((f->f_bufend - f->f_bufptr) >= 1) + return 0; + else + Util_DropReadAhead(f); + } + if (f->mode == MODE_READ_EOF) { + f->f_bufptr = f->f_buf; + f->f_bufend = f->f_buf; + return 0; + } + if ((f->f_buf = PyMem_Malloc(bufsize)) == NULL) { + return -1; + } + Py_BEGIN_ALLOW_THREADS + chunksize = Util_UnivNewlineRead(&bzerror, f->fp, f->f_buf, + bufsize, f); + Py_END_ALLOW_THREADS + f->pos += chunksize; + if (bzerror == BZ_STREAM_END) { + f->size = f->pos; + f->mode = MODE_READ_EOF; + } else if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + Util_DropReadAhead(f); + return -1; + } + f->f_bufptr = f->f_buf; + f->f_bufend = f->f_buf + chunksize; + return 0; +} + +/* This is a hacked version of Python's + * fileobject.c:readahead_get_line_skip(). */ +static PyStringObject * +Util_ReadAheadGetLineSkip(BZ2FileObject *f, int skip, int bufsize) +{ + PyStringObject* s; + char *bufptr; + char *buf; + int len; + + if (f->f_buf == NULL) + if (Util_ReadAhead(f, bufsize) < 0) + return NULL; + + len = f->f_bufend - f->f_bufptr; + if (len == 0) + return (PyStringObject *) + PyString_FromStringAndSize(NULL, skip); + bufptr = memchr(f->f_bufptr, '\n', len); + if (bufptr != NULL) { + bufptr++; /* Count the '\n' */ + len = bufptr - f->f_bufptr; + s = (PyStringObject *) + PyString_FromStringAndSize(NULL, skip+len); + if (s == NULL) + return NULL; + memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len); + f->f_bufptr = bufptr; + if (bufptr == f->f_bufend) + Util_DropReadAhead(f); + } else { + bufptr = f->f_bufptr; + buf = f->f_buf; + f->f_buf = NULL; /* Force new readahead buffer */ + s = Util_ReadAheadGetLineSkip(f, skip+len, + bufsize + (bufsize>>2)); + if (s == NULL) { + PyMem_Free(buf); + return NULL; + } + memcpy(PyString_AS_STRING(s)+skip, bufptr, len); + PyMem_Free(buf); + } + return s; +} + +/* ===================================================================== */ +/* Methods of BZ2File. */ + +PyDoc_STRVAR(BZ2File_read__doc__, +"read([size]) -> string\n\ +\n\ +Read at most size uncompressed bytes, returned as a string. If the size\n\ +argument is negative or omitted, read until EOF is reached.\n\ +"); + +/* This is a hacked version of Python's fileobject.c:file_read(). */ +static PyObject * +BZ2File_read(BZ2FileObject *self, PyObject *args) +{ + long bytesrequested = -1; + size_t bytesread, buffersize, chunksize; + int bzerror; + PyObject *ret = NULL; + + if (!PyArg_ParseTuple(args, "|l:read", &bytesrequested)) + return NULL; + + ACQUIRE_LOCK(self); + switch (self->mode) { + case MODE_READ: + break; + case MODE_READ_EOF: + ret = PyString_FromString(""); + goto cleanup; + case MODE_CLOSED: + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto cleanup; + default: + PyErr_SetString(PyExc_IOError, + "file is not ready for reading"); + goto cleanup; + } + + if (bytesrequested < 0) + buffersize = Util_NewBufferSize((size_t)0); + else + buffersize = bytesrequested; + if (buffersize > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "requested number of bytes is " + "more than a Python string can hold"); + goto cleanup; + } + ret = PyString_FromStringAndSize((char *)NULL, buffersize); + if (ret == NULL) + goto cleanup; + bytesread = 0; + + for (;;) { + Py_BEGIN_ALLOW_THREADS + chunksize = Util_UnivNewlineRead(&bzerror, self->fp, + BUF(ret)+bytesread, + buffersize-bytesread, + self); + self->pos += chunksize; + Py_END_ALLOW_THREADS + bytesread += chunksize; + if (bzerror == BZ_STREAM_END) { + self->size = self->pos; + self->mode = MODE_READ_EOF; + break; + } else if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + Py_DECREF(ret); + ret = NULL; + goto cleanup; + } + if (bytesrequested < 0) { + buffersize = Util_NewBufferSize(buffersize); + if (_PyString_Resize(&ret, buffersize) < 0) + goto cleanup; + } else { + break; + } + } + if (bytesread != buffersize) + _PyString_Resize(&ret, bytesread); + +cleanup: + RELEASE_LOCK(self); + return ret; +} + +PyDoc_STRVAR(BZ2File_readline__doc__, +"readline([size]) -> string\n\ +\n\ +Return the next line from the file, as a string, retaining newline.\n\ +A non-negative size argument will limit the maximum number of bytes to\n\ +return (an incomplete line may be returned then). Return an empty\n\ +string at EOF.\n\ +"); + +static PyObject * +BZ2File_readline(BZ2FileObject *self, PyObject *args) +{ + PyObject *ret = NULL; + int sizehint = -1; + + if (!PyArg_ParseTuple(args, "|i:readline", &sizehint)) + return NULL; + + ACQUIRE_LOCK(self); + switch (self->mode) { + case MODE_READ: + break; + case MODE_READ_EOF: + ret = PyString_FromString(""); + goto cleanup; + case MODE_CLOSED: + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto cleanup; + default: + PyErr_SetString(PyExc_IOError, + "file is not ready for reading"); + goto cleanup; + } + + if (sizehint == 0) + ret = PyString_FromString(""); + else + ret = Util_GetLine(self, (sizehint < 0) ? 0 : sizehint); + +cleanup: + RELEASE_LOCK(self); + return ret; +} + +PyDoc_STRVAR(BZ2File_readlines__doc__, +"readlines([size]) -> list\n\ +\n\ +Call readline() repeatedly and return a list of lines read.\n\ +The optional size argument, if given, is an approximate bound on the\n\ +total number of bytes in the lines returned.\n\ +"); + +/* This is a hacked version of Python's fileobject.c:file_readlines(). */ +static PyObject * +BZ2File_readlines(BZ2FileObject *self, PyObject *args) +{ + long sizehint = 0; + PyObject *list = NULL; + PyObject *line; + char small_buffer[SMALLCHUNK]; + char *buffer = small_buffer; + size_t buffersize = SMALLCHUNK; + PyObject *big_buffer = NULL; + size_t nfilled = 0; + size_t nread; + size_t totalread = 0; + char *p, *q, *end; + int err; + int shortread = 0; + int bzerror; + + if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint)) + return NULL; + + ACQUIRE_LOCK(self); + switch (self->mode) { + case MODE_READ: + break; + case MODE_READ_EOF: + list = PyList_New(0); + goto cleanup; + case MODE_CLOSED: + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto cleanup; + default: + PyErr_SetString(PyExc_IOError, + "file is not ready for reading"); + goto cleanup; + } + + if ((list = PyList_New(0)) == NULL) + goto cleanup; + + for (;;) { + Py_BEGIN_ALLOW_THREADS + nread = Util_UnivNewlineRead(&bzerror, self->fp, + buffer+nfilled, + buffersize-nfilled, self); + self->pos += nread; + Py_END_ALLOW_THREADS + if (bzerror == BZ_STREAM_END) { + self->size = self->pos; + self->mode = MODE_READ_EOF; + if (nread == 0) { + sizehint = 0; + break; + } + shortread = 1; + } else if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + error: + Py_DECREF(list); + list = NULL; + goto cleanup; + } + totalread += nread; + p = memchr(buffer+nfilled, '\n', nread); + if (!shortread && p == NULL) { + /* Need a larger buffer to fit this line */ + nfilled += nread; + buffersize *= 2; + if (buffersize > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "line is longer than a Python string can hold"); + goto error; + } + if (big_buffer == NULL) { + /* Create the big buffer */ + big_buffer = PyString_FromStringAndSize( + NULL, buffersize); + if (big_buffer == NULL) + goto error; + buffer = PyString_AS_STRING(big_buffer); + memcpy(buffer, small_buffer, nfilled); + } + else { + /* Grow the big buffer */ + _PyString_Resize(&big_buffer, buffersize); + buffer = PyString_AS_STRING(big_buffer); + } + continue; + } + end = buffer+nfilled+nread; + q = buffer; + while (p != NULL) { + /* Process complete lines */ + p++; + line = PyString_FromStringAndSize(q, p-q); + if (line == NULL) + goto error; + err = PyList_Append(list, line); + Py_DECREF(line); + if (err != 0) + goto error; + q = p; + p = memchr(q, '\n', end-q); + } + /* Move the remaining incomplete line to the start */ + nfilled = end-q; + memmove(buffer, q, nfilled); + if (sizehint > 0) + if (totalread >= (size_t)sizehint) + break; + if (shortread) { + sizehint = 0; + break; + } + } + if (nfilled != 0) { + /* Partial last line */ + line = PyString_FromStringAndSize(buffer, nfilled); + if (line == NULL) + goto error; + if (sizehint > 0) { + /* Need to complete the last line */ + PyObject *rest = Util_GetLine(self, 0); + if (rest == NULL) { + Py_DECREF(line); + goto error; + } + PyString_Concat(&line, rest); + Py_DECREF(rest); + if (line == NULL) + goto error; + } + err = PyList_Append(list, line); + Py_DECREF(line); + if (err != 0) + goto error; + } + + cleanup: + RELEASE_LOCK(self); + if (big_buffer) { + Py_DECREF(big_buffer); + } + return list; +} + +PyDoc_STRVAR(BZ2File_xreadlines__doc__, +"xreadlines() -> self\n\ +\n\ +For backward compatibility. BZ2File objects now include the performance\n\ +optimizations previously implemented in the xreadlines module.\n\ +"); + +PyDoc_STRVAR(BZ2File_write__doc__, +"write(data) -> None\n\ +\n\ +Write the 'data' string to file. Note that due to buffering, close() may\n\ +be needed before the file on disk reflects the data written.\n\ +"); + +/* This is a hacked version of Python's fileobject.c:file_write(). */ +static PyObject * +BZ2File_write(BZ2FileObject *self, PyObject *args) +{ + PyObject *ret = NULL; + char *buf; + int len; + int bzerror; + + if (!PyArg_ParseTuple(args, "s#:write", &buf, &len)) + return NULL; + + ACQUIRE_LOCK(self); + switch (self->mode) { + case MODE_WRITE: + break; + + case MODE_CLOSED: + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto cleanup; + + default: + PyErr_SetString(PyExc_IOError, + "file is not ready for writing"); + goto cleanup; + } + + self->f_softspace = 0; + + Py_BEGIN_ALLOW_THREADS + BZ2_bzWrite (&bzerror, self->fp, buf, len); + self->pos += len; + Py_END_ALLOW_THREADS + + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto cleanup; + } + + Py_INCREF(Py_None); + ret = Py_None; + +cleanup: + RELEASE_LOCK(self); + return ret; +} + +PyDoc_STRVAR(BZ2File_writelines__doc__, +"writelines(sequence_of_strings) -> None\n\ +\n\ +Write the sequence of strings to the file. Note that newlines are not\n\ +added. The sequence can be any iterable object producing strings. This is\n\ +equivalent to calling write() for each string.\n\ +"); + +/* This is a hacked version of Python's fileobject.c:file_writelines(). */ +static PyObject * +BZ2File_writelines(BZ2FileObject *self, PyObject *seq) +{ +#define CHUNKSIZE 1000 + PyObject *list = NULL; + PyObject *iter = NULL; + PyObject *ret = NULL; + PyObject *line; + int i, j, index, len, islist; + int bzerror; + + ACQUIRE_LOCK(self); + switch (self->mode) { + case MODE_WRITE: + break; + + case MODE_CLOSED: + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto error; + + default: + PyErr_SetString(PyExc_IOError, + "file is not ready for writing"); + goto error; + } + + islist = PyList_Check(seq); + if (!islist) { + iter = PyObject_GetIter(seq); + if (iter == NULL) { + PyErr_SetString(PyExc_TypeError, + "writelines() requires an iterable argument"); + goto error; + } + list = PyList_New(CHUNKSIZE); + if (list == NULL) + goto error; + } + + /* Strategy: slurp CHUNKSIZE lines into a private list, + checking that they are all strings, then write that list + without holding the interpreter lock, then come back for more. */ + for (index = 0; ; index += CHUNKSIZE) { + if (islist) { + Py_XDECREF(list); + list = PyList_GetSlice(seq, index, index+CHUNKSIZE); + if (list == NULL) + goto error; + j = PyList_GET_SIZE(list); + } + else { + for (j = 0; j < CHUNKSIZE; j++) { + line = PyIter_Next(iter); + if (line == NULL) { + if (PyErr_Occurred()) + goto error; + break; + } + PyList_SetItem(list, j, line); + } + } + if (j == 0) + break; + + /* Check that all entries are indeed strings. If not, + apply the same rules as for file.write() and + convert the rets to strings. This is slow, but + seems to be the only way since all conversion APIs + could potentially execute Python code. */ + for (i = 0; i < j; i++) { + PyObject *v = PyList_GET_ITEM(list, i); + if (!PyString_Check(v)) { + const char *buffer; + Py_ssize_t len; + if (PyObject_AsCharBuffer(v, &buffer, &len)) { + PyErr_SetString(PyExc_TypeError, + "writelines() " + "argument must be " + "a sequence of " + "strings"); + goto error; + } + line = PyString_FromStringAndSize(buffer, + len); + if (line == NULL) + goto error; + Py_DECREF(v); + PyList_SET_ITEM(list, i, line); + } + } + + self->f_softspace = 0; + + /* Since we are releasing the global lock, the + following code may *not* execute Python code. */ + Py_BEGIN_ALLOW_THREADS + for (i = 0; i < j; i++) { + line = PyList_GET_ITEM(list, i); + len = PyString_GET_SIZE(line); + BZ2_bzWrite (&bzerror, self->fp, + PyString_AS_STRING(line), len); + if (bzerror != BZ_OK) { + Py_BLOCK_THREADS + Util_CatchBZ2Error(bzerror); + goto error; + } + } + Py_END_ALLOW_THREADS + + if (j < CHUNKSIZE) + break; + } + + Py_INCREF(Py_None); + ret = Py_None; + + error: + RELEASE_LOCK(self); + Py_XDECREF(list); + Py_XDECREF(iter); + return ret; +#undef CHUNKSIZE +} + +PyDoc_STRVAR(BZ2File_seek__doc__, +"seek(offset [, whence]) -> None\n\ +\n\ +Move to new file position. Argument offset is a byte count. Optional\n\ +argument whence defaults to 0 (offset from start of file, offset\n\ +should be >= 0); other values are 1 (move relative to current position,\n\ +positive or negative), and 2 (move relative to end of file, usually\n\ +negative, although many platforms allow seeking beyond the end of a file).\n\ +\n\ +Note that seeking of bz2 files is emulated, and depending on the parameters\n\ +the operation may be extremely slow.\n\ +"); + +static PyObject * +BZ2File_seek(BZ2FileObject *self, PyObject *args) +{ + int where = 0; + PyObject *offobj; + Py_off_t offset; + char small_buffer[SMALLCHUNK]; + char *buffer = small_buffer; + size_t buffersize = SMALLCHUNK; + Py_off_t bytesread = 0; + size_t readsize; + int chunksize; + int bzerror; + PyObject *ret = NULL; + + if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &where)) + return NULL; +#if !defined(HAVE_LARGEFILE_SUPPORT) + offset = PyInt_AsLong(offobj); +#else + offset = PyLong_Check(offobj) ? + PyLong_AsLongLong(offobj) : PyInt_AsLong(offobj); +#endif + if (PyErr_Occurred()) + return NULL; + + ACQUIRE_LOCK(self); + Util_DropReadAhead(self); + switch (self->mode) { + case MODE_READ: + case MODE_READ_EOF: + break; + + case MODE_CLOSED: + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto cleanup; + + default: + PyErr_SetString(PyExc_IOError, + "seek works only while reading"); + goto cleanup; + } + + if (where == 2) { + if (self->size == -1) { + assert(self->mode != MODE_READ_EOF); + for (;;) { + Py_BEGIN_ALLOW_THREADS + chunksize = Util_UnivNewlineRead( + &bzerror, self->fp, + buffer, buffersize, + self); + self->pos += chunksize; + Py_END_ALLOW_THREADS + + bytesread += chunksize; + if (bzerror == BZ_STREAM_END) { + break; + } else if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto cleanup; + } + } + self->mode = MODE_READ_EOF; + self->size = self->pos; + bytesread = 0; + } + offset = self->size + offset; + } else if (where == 1) { + offset = self->pos + offset; + } + + /* Before getting here, offset must be the absolute position the file + * pointer should be set to. */ + + if (offset >= self->pos) { + /* we can move forward */ + offset -= self->pos; + } else { + /* we cannot move back, so rewind the stream */ + BZ2_bzReadClose(&bzerror, self->fp); + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto cleanup; + } + ret = PyObject_CallMethod(self->file, "seek", "(i)", 0); + if (!ret) + goto cleanup; + Py_DECREF(ret); + ret = NULL; + self->pos = 0; + self->fp = BZ2_bzReadOpen(&bzerror, PyFile_AsFile(self->file), + 0, 0, NULL, 0); + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto cleanup; + } + self->mode = MODE_READ; + } + + if (offset <= 0 || self->mode == MODE_READ_EOF) + goto exit; + + /* Before getting here, offset must be set to the number of bytes + * to walk forward. */ + for (;;) { + if (offset-bytesread > buffersize) + readsize = buffersize; + else + /* offset might be wider that readsize, but the result + * of the subtraction is bound by buffersize (see the + * condition above). buffersize is 8192. */ + readsize = (size_t)(offset-bytesread); + Py_BEGIN_ALLOW_THREADS + chunksize = Util_UnivNewlineRead(&bzerror, self->fp, + buffer, readsize, self); + self->pos += chunksize; + Py_END_ALLOW_THREADS + bytesread += chunksize; + if (bzerror == BZ_STREAM_END) { + self->size = self->pos; + self->mode = MODE_READ_EOF; + break; + } else if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto cleanup; + } + if (bytesread == offset) + break; + } + +exit: + Py_INCREF(Py_None); + ret = Py_None; + +cleanup: + RELEASE_LOCK(self); + return ret; +} + +PyDoc_STRVAR(BZ2File_tell__doc__, +"tell() -> int\n\ +\n\ +Return the current file position, an integer (may be a long integer).\n\ +"); + +static PyObject * +BZ2File_tell(BZ2FileObject *self, PyObject *args) +{ + PyObject *ret = NULL; + + if (self->mode == MODE_CLOSED) { + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto cleanup; + } + +#if !defined(HAVE_LARGEFILE_SUPPORT) + ret = PyInt_FromLong(self->pos); +#else + ret = PyLong_FromLongLong(self->pos); +#endif + +cleanup: + return ret; +} + +PyDoc_STRVAR(BZ2File_close__doc__, +"close() -> None or (perhaps) an integer\n\ +\n\ +Close the file. Sets data attribute .closed to true. A closed file\n\ +cannot be used for further I/O operations. close() may be called more\n\ +than once without error.\n\ +"); + +static PyObject * +BZ2File_close(BZ2FileObject *self) +{ + PyObject *ret = NULL; + int bzerror = BZ_OK; + + ACQUIRE_LOCK(self); + switch (self->mode) { + case MODE_READ: + case MODE_READ_EOF: + BZ2_bzReadClose(&bzerror, self->fp); + break; + case MODE_WRITE: + BZ2_bzWriteClose(&bzerror, self->fp, + 0, NULL, NULL); + break; + } + self->mode = MODE_CLOSED; + ret = PyObject_CallMethod(self->file, "close", NULL); + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + Py_XDECREF(ret); + ret = NULL; + } + + RELEASE_LOCK(self); + return ret; +} + +static PyObject *BZ2File_getiter(BZ2FileObject *self); + +static PyMethodDef BZ2File_methods[] = { + {"read", (PyCFunction)BZ2File_read, METH_VARARGS, BZ2File_read__doc__}, + {"readline", (PyCFunction)BZ2File_readline, METH_VARARGS, BZ2File_readline__doc__}, + {"readlines", (PyCFunction)BZ2File_readlines, METH_VARARGS, BZ2File_readlines__doc__}, + {"xreadlines", (PyCFunction)BZ2File_getiter, METH_VARARGS, BZ2File_xreadlines__doc__}, + {"write", (PyCFunction)BZ2File_write, METH_VARARGS, BZ2File_write__doc__}, + {"writelines", (PyCFunction)BZ2File_writelines, METH_O, BZ2File_writelines__doc__}, + {"seek", (PyCFunction)BZ2File_seek, METH_VARARGS, BZ2File_seek__doc__}, + {"tell", (PyCFunction)BZ2File_tell, METH_NOARGS, BZ2File_tell__doc__}, + {"close", (PyCFunction)BZ2File_close, METH_NOARGS, BZ2File_close__doc__}, + {NULL, NULL} /* sentinel */ +}; + + +/* ===================================================================== */ +/* Getters and setters of BZ2File. */ + +/* This is a hacked version of Python's fileobject.c:get_newlines(). */ +static PyObject * +BZ2File_get_newlines(BZ2FileObject *self, void *closure) +{ + switch (self->f_newlinetypes) { + case NEWLINE_UNKNOWN: + Py_INCREF(Py_None); + return Py_None; + case NEWLINE_CR: + return PyString_FromString("\r"); + case NEWLINE_LF: + return PyString_FromString("\n"); + case NEWLINE_CR|NEWLINE_LF: + return Py_BuildValue("(ss)", "\r", "\n"); + case NEWLINE_CRLF: + return PyString_FromString("\r\n"); + case NEWLINE_CR|NEWLINE_CRLF: + return Py_BuildValue("(ss)", "\r", "\r\n"); + case NEWLINE_LF|NEWLINE_CRLF: + return Py_BuildValue("(ss)", "\n", "\r\n"); + case NEWLINE_CR|NEWLINE_LF|NEWLINE_CRLF: + return Py_BuildValue("(sss)", "\r", "\n", "\r\n"); + default: + PyErr_Format(PyExc_SystemError, + "Unknown newlines value 0x%x\n", + self->f_newlinetypes); + return NULL; + } +} + +static PyObject * +BZ2File_get_closed(BZ2FileObject *self, void *closure) +{ + return PyInt_FromLong(self->mode == MODE_CLOSED); +} + +static PyObject * +BZ2File_get_mode(BZ2FileObject *self, void *closure) +{ + return PyObject_GetAttrString(self->file, "mode"); +} + +static PyObject * +BZ2File_get_name(BZ2FileObject *self, void *closure) +{ + return PyObject_GetAttrString(self->file, "name"); +} + +static PyGetSetDef BZ2File_getset[] = { + {"closed", (getter)BZ2File_get_closed, NULL, + "True if the file is closed"}, + {"newlines", (getter)BZ2File_get_newlines, NULL, + "end-of-line convention used in this file"}, + {"mode", (getter)BZ2File_get_mode, NULL, + "file mode ('r', 'w', or 'U')"}, + {"name", (getter)BZ2File_get_name, NULL, + "file name"}, + {NULL} /* Sentinel */ +}; + + +/* ===================================================================== */ +/* Members of BZ2File_Type. */ + +#undef OFF +#define OFF(x) offsetof(BZ2FileObject, x) + +static PyMemberDef BZ2File_members[] = { + {"softspace", T_INT, OFF(f_softspace), 0, + "flag indicating that a space needs to be printed; used by print"}, + {NULL} /* Sentinel */ +}; + +/* ===================================================================== */ +/* Slot definitions for BZ2File_Type. */ + +static int +BZ2File_init(BZ2FileObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = {"filename", "mode", "buffering", + "compresslevel", 0}; + PyObject *name; + char *mode = "r"; + int buffering = -1; + int compresslevel = 9; + int bzerror; + int mode_char = 0; + + self->size = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|sii:BZ2File", + kwlist, &name, &mode, &buffering, + &compresslevel)) + return -1; + + if (compresslevel < 1 || compresslevel > 9) { + PyErr_SetString(PyExc_ValueError, + "compresslevel must be between 1 and 9"); + return -1; + } + + for (;;) { + int error = 0; + switch (*mode) { + case 'r': + case 'w': + if (mode_char) + error = 1; + mode_char = *mode; + break; + + case 'b': + break; + + case 'U': +#ifdef __VMS + self->f_univ_newline = 0; +#else + self->f_univ_newline = 1; +#endif + break; + + default: + error = 1; + break; + } + if (error) { + PyErr_Format(PyExc_ValueError, + "invalid mode char %c", *mode); + return -1; + } + mode++; + if (*mode == '\0') + break; + } + + if (mode_char == 0) { + mode_char = 'r'; + } + + mode = (mode_char == 'r') ? "rb" : "wb"; + + self->file = PyObject_CallFunction((PyObject*)&PyFile_Type, "(Osi)", + name, mode, buffering); + if (self->file == NULL) + return -1; + + /* From now on, we have stuff to dealloc, so jump to error label + * instead of returning */ + +#ifdef WITH_THREAD + self->lock = PyThread_allocate_lock(); + if (!self->lock) { + PyErr_SetString(PyExc_MemoryError, "unable to allocate lock"); + goto error; + } +#endif + + if (mode_char == 'r') + self->fp = BZ2_bzReadOpen(&bzerror, + PyFile_AsFile(self->file), + 0, 0, NULL, 0); + else + self->fp = BZ2_bzWriteOpen(&bzerror, + PyFile_AsFile(self->file), + compresslevel, 0, 0); + + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto error; + } + + self->mode = (mode_char == 'r') ? MODE_READ : MODE_WRITE; + + return 0; + +error: + Py_CLEAR(self->file); +#ifdef WITH_THREAD + if (self->lock) { + PyThread_free_lock(self->lock); + self->lock = NULL; + } +#endif + return -1; +} + +static void +BZ2File_dealloc(BZ2FileObject *self) +{ + int bzerror; +#ifdef WITH_THREAD + if (self->lock) + PyThread_free_lock(self->lock); +#endif + switch (self->mode) { + case MODE_READ: + case MODE_READ_EOF: + BZ2_bzReadClose(&bzerror, self->fp); + break; + case MODE_WRITE: + BZ2_bzWriteClose(&bzerror, self->fp, + 0, NULL, NULL); + break; + } + Util_DropReadAhead(self); + Py_XDECREF(self->file); + self->ob_type->tp_free((PyObject *)self); +} + +/* This is a hacked version of Python's fileobject.c:file_getiter(). */ +static PyObject * +BZ2File_getiter(BZ2FileObject *self) +{ + if (self->mode == MODE_CLOSED) { + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + return NULL; + } + Py_INCREF((PyObject*)self); + return (PyObject *)self; +} + +/* This is a hacked version of Python's fileobject.c:file_iternext(). */ +#define READAHEAD_BUFSIZE 8192 +static PyObject * +BZ2File_iternext(BZ2FileObject *self) +{ + PyStringObject* ret; + ACQUIRE_LOCK(self); + if (self->mode == MODE_CLOSED) { + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + return NULL; + } + ret = Util_ReadAheadGetLineSkip(self, 0, READAHEAD_BUFSIZE); + RELEASE_LOCK(self); + if (ret == NULL || PyString_GET_SIZE(ret) == 0) { + Py_XDECREF(ret); + return NULL; + } + return (PyObject *)ret; +} + +/* ===================================================================== */ +/* BZ2File_Type definition. */ + +PyDoc_VAR(BZ2File__doc__) = +PyDoc_STR( +"BZ2File(name [, mode='r', buffering=0, compresslevel=9]) -> file object\n\ +\n\ +Open a bz2 file. The mode can be 'r' or 'w', for reading (default) or\n\ +writing. When opened for writing, the file will be created if it doesn't\n\ +exist, and truncated otherwise. If the buffering argument is given, 0 means\n\ +unbuffered, and larger numbers specify the buffer size. If compresslevel\n\ +is given, must be a number between 1 and 9.\n\ +") +PyDoc_STR( +"\n\ +Add a 'U' to mode to open the file for input with universal newline\n\ +support. Any line ending in the input file will be seen as a '\\n' in\n\ +Python. Also, a file so opened gains the attribute 'newlines'; the value\n\ +for this attribute is one of None (no newline read yet), '\\r', '\\n',\n\ +'\\r\\n' or a tuple containing all the newline types seen. Universal\n\ +newlines are available only when reading.\n\ +") +; + +static PyTypeObject BZ2File_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "bz2.BZ2File", /*tp_name*/ + sizeof(BZ2FileObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)BZ2File_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr,/*tp_getattro*/ + PyObject_GenericSetAttr,/*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + BZ2File__doc__, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + (getiterfunc)BZ2File_getiter, /*tp_iter*/ + (iternextfunc)BZ2File_iternext, /*tp_iternext*/ + BZ2File_methods, /*tp_methods*/ + BZ2File_members, /*tp_members*/ + BZ2File_getset, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + (initproc)BZ2File_init, /*tp_init*/ + PyType_GenericAlloc, /*tp_alloc*/ + PyType_GenericNew, /*tp_new*/ + _PyObject_Del, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + +/* ===================================================================== */ +/* Methods of BZ2Comp. */ + +PyDoc_STRVAR(BZ2Comp_compress__doc__, +"compress(data) -> string\n\ +\n\ +Provide more data to the compressor object. It will return chunks of\n\ +compressed data whenever possible. When you've finished providing data\n\ +to compress, call the flush() method to finish the compression process,\n\ +and return what is left in the internal buffers.\n\ +"); + +static PyObject * +BZ2Comp_compress(BZ2CompObject *self, PyObject *args) +{ + char *data; + int datasize; + int bufsize = SMALLCHUNK; + PY_LONG_LONG totalout; + PyObject *ret = NULL; + bz_stream *bzs = &self->bzs; + int bzerror; + + if (!PyArg_ParseTuple(args, "s#:compress", &data, &datasize)) + return NULL; + + if (datasize == 0) + return PyString_FromString(""); + + ACQUIRE_LOCK(self); + if (!self->running) { + PyErr_SetString(PyExc_ValueError, + "this object was already flushed"); + goto error; + } + + ret = PyString_FromStringAndSize(NULL, bufsize); + if (!ret) + goto error; + + bzs->next_in = data; + bzs->avail_in = datasize; + bzs->next_out = BUF(ret); + bzs->avail_out = bufsize; + + totalout = BZS_TOTAL_OUT(bzs); + + for (;;) { + Py_BEGIN_ALLOW_THREADS + bzerror = BZ2_bzCompress(bzs, BZ_RUN); + Py_END_ALLOW_THREADS + if (bzerror != BZ_RUN_OK) { + Util_CatchBZ2Error(bzerror); + goto error; + } + if (bzs->avail_in == 0) + break; /* no more input data */ + if (bzs->avail_out == 0) { + bufsize = Util_NewBufferSize(bufsize); + if (_PyString_Resize(&ret, bufsize) < 0) { + BZ2_bzCompressEnd(bzs); + goto error; + } + bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs) + - totalout); + bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); + } + } + + _PyString_Resize(&ret, (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)); + + RELEASE_LOCK(self); + return ret; + +error: + RELEASE_LOCK(self); + Py_XDECREF(ret); + return NULL; +} + +PyDoc_STRVAR(BZ2Comp_flush__doc__, +"flush() -> string\n\ +\n\ +Finish the compression process and return what is left in internal buffers.\n\ +You must not use the compressor object after calling this method.\n\ +"); + +static PyObject * +BZ2Comp_flush(BZ2CompObject *self) +{ + int bufsize = SMALLCHUNK; + PyObject *ret = NULL; + bz_stream *bzs = &self->bzs; + PY_LONG_LONG totalout; + int bzerror; + + ACQUIRE_LOCK(self); + if (!self->running) { + PyErr_SetString(PyExc_ValueError, "object was already " + "flushed"); + goto error; + } + self->running = 0; + + ret = PyString_FromStringAndSize(NULL, bufsize); + if (!ret) + goto error; + + bzs->next_out = BUF(ret); + bzs->avail_out = bufsize; + + totalout = BZS_TOTAL_OUT(bzs); + + for (;;) { + Py_BEGIN_ALLOW_THREADS + bzerror = BZ2_bzCompress(bzs, BZ_FINISH); + Py_END_ALLOW_THREADS + if (bzerror == BZ_STREAM_END) { + break; + } else if (bzerror != BZ_FINISH_OK) { + Util_CatchBZ2Error(bzerror); + goto error; + } + if (bzs->avail_out == 0) { + bufsize = Util_NewBufferSize(bufsize); + if (_PyString_Resize(&ret, bufsize) < 0) + goto error; + bzs->next_out = BUF(ret); + bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs) + - totalout); + bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); + } + } + + if (bzs->avail_out != 0) + _PyString_Resize(&ret, (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)); + + RELEASE_LOCK(self); + return ret; + +error: + RELEASE_LOCK(self); + Py_XDECREF(ret); + return NULL; +} + +static PyMethodDef BZ2Comp_methods[] = { + {"compress", (PyCFunction)BZ2Comp_compress, METH_VARARGS, + BZ2Comp_compress__doc__}, + {"flush", (PyCFunction)BZ2Comp_flush, METH_NOARGS, + BZ2Comp_flush__doc__}, + {NULL, NULL} /* sentinel */ +}; + + +/* ===================================================================== */ +/* Slot definitions for BZ2Comp_Type. */ + +static int +BZ2Comp_init(BZ2CompObject *self, PyObject *args, PyObject *kwargs) +{ + int compresslevel = 9; + int bzerror; + static char *kwlist[] = {"compresslevel", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|i:BZ2Compressor", + kwlist, &compresslevel)) + return -1; + + if (compresslevel < 1 || compresslevel > 9) { + PyErr_SetString(PyExc_ValueError, + "compresslevel must be between 1 and 9"); + goto error; + } + +#ifdef WITH_THREAD + self->lock = PyThread_allocate_lock(); + if (!self->lock) { + PyErr_SetString(PyExc_MemoryError, "unable to allocate lock"); + goto error; + } +#endif + + memset(&self->bzs, 0, sizeof(bz_stream)); + bzerror = BZ2_bzCompressInit(&self->bzs, compresslevel, 0, 0); + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto error; + } + + self->running = 1; + + return 0; +error: +#ifdef WITH_THREAD + if (self->lock) { + PyThread_free_lock(self->lock); + self->lock = NULL; + } +#endif + return -1; +} + +static void +BZ2Comp_dealloc(BZ2CompObject *self) +{ +#ifdef WITH_THREAD + if (self->lock) + PyThread_free_lock(self->lock); +#endif + BZ2_bzCompressEnd(&self->bzs); + self->ob_type->tp_free((PyObject *)self); +} + + +/* ===================================================================== */ +/* BZ2Comp_Type definition. */ + +PyDoc_STRVAR(BZ2Comp__doc__, +"BZ2Compressor([compresslevel=9]) -> compressor object\n\ +\n\ +Create a new compressor object. This object may be used to compress\n\ +data sequentially. If you want to compress data in one shot, use the\n\ +compress() function instead. The compresslevel parameter, if given,\n\ +must be a number between 1 and 9.\n\ +"); + +static PyTypeObject BZ2Comp_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "bz2.BZ2Compressor", /*tp_name*/ + sizeof(BZ2CompObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)BZ2Comp_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr,/*tp_getattro*/ + PyObject_GenericSetAttr,/*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + BZ2Comp__doc__, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + BZ2Comp_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + (initproc)BZ2Comp_init, /*tp_init*/ + PyType_GenericAlloc, /*tp_alloc*/ + PyType_GenericNew, /*tp_new*/ + _PyObject_Del, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + +/* ===================================================================== */ +/* Members of BZ2Decomp. */ + +#undef OFF +#define OFF(x) offsetof(BZ2DecompObject, x) + +static PyMemberDef BZ2Decomp_members[] = { + {"unused_data", T_OBJECT, OFF(unused_data), RO}, + {NULL} /* Sentinel */ +}; + + +/* ===================================================================== */ +/* Methods of BZ2Decomp. */ + +PyDoc_STRVAR(BZ2Decomp_decompress__doc__, +"decompress(data) -> string\n\ +\n\ +Provide more data to the decompressor object. It will return chunks\n\ +of decompressed data whenever possible. If you try to decompress data\n\ +after the end of stream is found, EOFError will be raised. If any data\n\ +was found after the end of stream, it'll be ignored and saved in\n\ +unused_data attribute.\n\ +"); + +static PyObject * +BZ2Decomp_decompress(BZ2DecompObject *self, PyObject *args) +{ + char *data; + int datasize; + int bufsize = SMALLCHUNK; + PY_LONG_LONG totalout; + PyObject *ret = NULL; + bz_stream *bzs = &self->bzs; + int bzerror; + + if (!PyArg_ParseTuple(args, "s#:decompress", &data, &datasize)) + return NULL; + + ACQUIRE_LOCK(self); + if (!self->running) { + PyErr_SetString(PyExc_EOFError, "end of stream was " + "already found"); + goto error; + } + + ret = PyString_FromStringAndSize(NULL, bufsize); + if (!ret) + goto error; + + bzs->next_in = data; + bzs->avail_in = datasize; + bzs->next_out = BUF(ret); + bzs->avail_out = bufsize; + + totalout = BZS_TOTAL_OUT(bzs); + + for (;;) { + Py_BEGIN_ALLOW_THREADS + bzerror = BZ2_bzDecompress(bzs); + Py_END_ALLOW_THREADS + if (bzerror == BZ_STREAM_END) { + if (bzs->avail_in != 0) { + Py_DECREF(self->unused_data); + self->unused_data = + PyString_FromStringAndSize(bzs->next_in, + bzs->avail_in); + } + self->running = 0; + break; + } + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto error; + } + if (bzs->avail_in == 0) + break; /* no more input data */ + if (bzs->avail_out == 0) { + bufsize = Util_NewBufferSize(bufsize); + if (_PyString_Resize(&ret, bufsize) < 0) { + BZ2_bzDecompressEnd(bzs); + goto error; + } + bzs->next_out = BUF(ret); + bzs->next_out = BUF(ret) + (BZS_TOTAL_OUT(bzs) + - totalout); + bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); + } + } + + if (bzs->avail_out != 0) + _PyString_Resize(&ret, (Py_ssize_t)(BZS_TOTAL_OUT(bzs) - totalout)); + + RELEASE_LOCK(self); + return ret; + +error: + RELEASE_LOCK(self); + Py_XDECREF(ret); + return NULL; +} + +static PyMethodDef BZ2Decomp_methods[] = { + {"decompress", (PyCFunction)BZ2Decomp_decompress, METH_VARARGS, BZ2Decomp_decompress__doc__}, + {NULL, NULL} /* sentinel */ +}; + + +/* ===================================================================== */ +/* Slot definitions for BZ2Decomp_Type. */ + +static int +BZ2Decomp_init(BZ2DecompObject *self, PyObject *args, PyObject *kwargs) +{ + int bzerror; + + if (!PyArg_ParseTuple(args, ":BZ2Decompressor")) + return -1; + +#ifdef WITH_THREAD + self->lock = PyThread_allocate_lock(); + if (!self->lock) { + PyErr_SetString(PyExc_MemoryError, "unable to allocate lock"); + goto error; + } +#endif + + self->unused_data = PyString_FromString(""); + if (!self->unused_data) + goto error; + + memset(&self->bzs, 0, sizeof(bz_stream)); + bzerror = BZ2_bzDecompressInit(&self->bzs, 0, 0); + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + goto error; + } + + self->running = 1; + + return 0; + +error: +#ifdef WITH_THREAD + if (self->lock) { + PyThread_free_lock(self->lock); + self->lock = NULL; + } +#endif + Py_CLEAR(self->unused_data); + return -1; +} + +static void +BZ2Decomp_dealloc(BZ2DecompObject *self) +{ +#ifdef WITH_THREAD + if (self->lock) + PyThread_free_lock(self->lock); +#endif + Py_XDECREF(self->unused_data); + BZ2_bzDecompressEnd(&self->bzs); + self->ob_type->tp_free((PyObject *)self); +} + + +/* ===================================================================== */ +/* BZ2Decomp_Type definition. */ + +PyDoc_STRVAR(BZ2Decomp__doc__, +"BZ2Decompressor() -> decompressor object\n\ +\n\ +Create a new decompressor object. This object may be used to decompress\n\ +data sequentially. If you want to decompress data in one shot, use the\n\ +decompress() function instead.\n\ +"); + +static PyTypeObject BZ2Decomp_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "bz2.BZ2Decompressor", /*tp_name*/ + sizeof(BZ2DecompObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)BZ2Decomp_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr,/*tp_getattro*/ + PyObject_GenericSetAttr,/*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/ + BZ2Decomp__doc__, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + BZ2Decomp_methods, /*tp_methods*/ + BZ2Decomp_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + (initproc)BZ2Decomp_init, /*tp_init*/ + PyType_GenericAlloc, /*tp_alloc*/ + PyType_GenericNew, /*tp_new*/ + _PyObject_Del, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + +/* ===================================================================== */ +/* Module functions. */ + +PyDoc_STRVAR(bz2_compress__doc__, +"compress(data [, compresslevel=9]) -> string\n\ +\n\ +Compress data in one shot. If you want to compress data sequentially,\n\ +use an instance of BZ2Compressor instead. The compresslevel parameter, if\n\ +given, must be a number between 1 and 9.\n\ +"); + +static PyObject * +bz2_compress(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int compresslevel=9; + char *data; + int datasize; + int bufsize; + PyObject *ret = NULL; + bz_stream _bzs; + bz_stream *bzs = &_bzs; + int bzerror; + static char *kwlist[] = {"data", "compresslevel", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|i", + kwlist, &data, &datasize, + &compresslevel)) + return NULL; + + if (compresslevel < 1 || compresslevel > 9) { + PyErr_SetString(PyExc_ValueError, + "compresslevel must be between 1 and 9"); + return NULL; + } + + /* Conforming to bz2 manual, this is large enough to fit compressed + * data in one shot. We will check it later anyway. */ + bufsize = datasize + (datasize/100+1) + 600; + + ret = PyString_FromStringAndSize(NULL, bufsize); + if (!ret) + return NULL; + + memset(bzs, 0, sizeof(bz_stream)); + + bzs->next_in = data; + bzs->avail_in = datasize; + bzs->next_out = BUF(ret); + bzs->avail_out = bufsize; + + bzerror = BZ2_bzCompressInit(bzs, compresslevel, 0, 0); + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + Py_DECREF(ret); + return NULL; + } + + for (;;) { + Py_BEGIN_ALLOW_THREADS + bzerror = BZ2_bzCompress(bzs, BZ_FINISH); + Py_END_ALLOW_THREADS + if (bzerror == BZ_STREAM_END) { + break; + } else if (bzerror != BZ_FINISH_OK) { + BZ2_bzCompressEnd(bzs); + Util_CatchBZ2Error(bzerror); + Py_DECREF(ret); + return NULL; + } + if (bzs->avail_out == 0) { + bufsize = Util_NewBufferSize(bufsize); + if (_PyString_Resize(&ret, bufsize) < 0) { + BZ2_bzCompressEnd(bzs); + Py_DECREF(ret); + return NULL; + } + bzs->next_out = BUF(ret) + BZS_TOTAL_OUT(bzs); + bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); + } + } + + if (bzs->avail_out != 0) + _PyString_Resize(&ret, (Py_ssize_t)BZS_TOTAL_OUT(bzs)); + BZ2_bzCompressEnd(bzs); + + return ret; +} + +PyDoc_STRVAR(bz2_decompress__doc__, +"decompress(data) -> decompressed data\n\ +\n\ +Decompress data in one shot. If you want to decompress data sequentially,\n\ +use an instance of BZ2Decompressor instead.\n\ +"); + +static PyObject * +bz2_decompress(PyObject *self, PyObject *args) +{ + char *data; + int datasize; + int bufsize = SMALLCHUNK; + PyObject *ret; + bz_stream _bzs; + bz_stream *bzs = &_bzs; + int bzerror; + + if (!PyArg_ParseTuple(args, "s#:decompress", &data, &datasize)) + return NULL; + + if (datasize == 0) + return PyString_FromString(""); + + ret = PyString_FromStringAndSize(NULL, bufsize); + if (!ret) + return NULL; + + memset(bzs, 0, sizeof(bz_stream)); + + bzs->next_in = data; + bzs->avail_in = datasize; + bzs->next_out = BUF(ret); + bzs->avail_out = bufsize; + + bzerror = BZ2_bzDecompressInit(bzs, 0, 0); + if (bzerror != BZ_OK) { + Util_CatchBZ2Error(bzerror); + Py_DECREF(ret); + return NULL; + } + + for (;;) { + Py_BEGIN_ALLOW_THREADS + bzerror = BZ2_bzDecompress(bzs); + Py_END_ALLOW_THREADS + if (bzerror == BZ_STREAM_END) { + break; + } else if (bzerror != BZ_OK) { + BZ2_bzDecompressEnd(bzs); + Util_CatchBZ2Error(bzerror); + Py_DECREF(ret); + return NULL; + } + if (bzs->avail_in == 0) { + BZ2_bzDecompressEnd(bzs); + PyErr_SetString(PyExc_ValueError, + "couldn't find end of stream"); + Py_DECREF(ret); + return NULL; + } + if (bzs->avail_out == 0) { + bufsize = Util_NewBufferSize(bufsize); + if (_PyString_Resize(&ret, bufsize) < 0) { + BZ2_bzDecompressEnd(bzs); + Py_DECREF(ret); + return NULL; + } + bzs->next_out = BUF(ret) + BZS_TOTAL_OUT(bzs); + bzs->avail_out = bufsize - (bzs->next_out - BUF(ret)); + } + } + + if (bzs->avail_out != 0) + _PyString_Resize(&ret, (Py_ssize_t)BZS_TOTAL_OUT(bzs)); + BZ2_bzDecompressEnd(bzs); + + return ret; +} + +static PyMethodDef bz2_methods[] = { + {"compress", (PyCFunction) bz2_compress, METH_VARARGS|METH_KEYWORDS, + bz2_compress__doc__}, + {"decompress", (PyCFunction) bz2_decompress, METH_VARARGS, + bz2_decompress__doc__}, + {NULL, NULL} /* sentinel */ +}; + +/* ===================================================================== */ +/* Initialization function. */ + +PyDoc_STRVAR(bz2__doc__, +"The python bz2 module provides a comprehensive interface for\n\ +the bz2 compression library. It implements a complete file\n\ +interface, one shot (de)compression functions, and types for\n\ +sequential (de)compression.\n\ +"); + +PyMODINIT_FUNC +initbz2(void) +{ + PyObject *m; + + BZ2File_Type.ob_type = &PyType_Type; + BZ2Comp_Type.ob_type = &PyType_Type; + BZ2Decomp_Type.ob_type = &PyType_Type; + + m = Py_InitModule3("bz2", bz2_methods, bz2__doc__); + if (m == NULL) + return; + + PyModule_AddObject(m, "__author__", PyString_FromString(__author__)); + + Py_INCREF(&BZ2File_Type); + PyModule_AddObject(m, "BZ2File", (PyObject *)&BZ2File_Type); + + Py_INCREF(&BZ2Comp_Type); + PyModule_AddObject(m, "BZ2Compressor", (PyObject *)&BZ2Comp_Type); + + Py_INCREF(&BZ2Decomp_Type); + PyModule_AddObject(m, "BZ2Decompressor", (PyObject *)&BZ2Decomp_Type); +} diff --git a/sys/src/cmd/python/Modules/cPickle.c b/sys/src/cmd/python/Modules/cPickle.c new file mode 100644 index 000000000..4f7d1f198 --- /dev/null +++ b/sys/src/cmd/python/Modules/cPickle.c @@ -0,0 +1,5757 @@ +#include "Python.h" +#include "cStringIO.h" +#include "structmember.h" + +PyDoc_STRVAR(cPickle_module_documentation, +"C implementation and optimization of the Python pickle module."); + +#ifndef Py_eval_input +#include <graminit.h> +#define Py_eval_input eval_input +#endif /* Py_eval_input */ + +#define DEL_LIST_SLICE(list, from, to) (PyList_SetSlice(list, from, to, NULL)) + +#define WRITE_BUF_SIZE 256 + +/* Bump this when new opcodes are added to the pickle protocol. */ +#define HIGHEST_PROTOCOL 2 + +/* + * Pickle opcodes. These must be kept in synch with pickle.py. Extensive + * docs are in pickletools.py. + */ +#define MARK '(' +#define STOP '.' +#define POP '0' +#define POP_MARK '1' +#define DUP '2' +#define FLOAT 'F' +#define BINFLOAT 'G' +#define INT 'I' +#define BININT 'J' +#define BININT1 'K' +#define LONG 'L' +#define BININT2 'M' +#define NONE 'N' +#define PERSID 'P' +#define BINPERSID 'Q' +#define REDUCE 'R' +#define STRING 'S' +#define BINSTRING 'T' +#define SHORT_BINSTRING 'U' +#define UNICODE 'V' +#define BINUNICODE 'X' +#define APPEND 'a' +#define BUILD 'b' +#define GLOBAL 'c' +#define DICT 'd' +#define EMPTY_DICT '}' +#define APPENDS 'e' +#define GET 'g' +#define BINGET 'h' +#define INST 'i' +#define LONG_BINGET 'j' +#define LIST 'l' +#define EMPTY_LIST ']' +#define OBJ 'o' +#define PUT 'p' +#define BINPUT 'q' +#define LONG_BINPUT 'r' +#define SETITEM 's' +#define TUPLE 't' +#define EMPTY_TUPLE ')' +#define SETITEMS 'u' + +/* Protocol 2. */ +#define PROTO '\x80' /* identify pickle protocol */ +#define NEWOBJ '\x81' /* build object by applying cls.__new__ to argtuple */ +#define EXT1 '\x82' /* push object from extension registry; 1-byte index */ +#define EXT2 '\x83' /* ditto, but 2-byte index */ +#define EXT4 '\x84' /* ditto, but 4-byte index */ +#define TUPLE1 '\x85' /* build 1-tuple from stack top */ +#define TUPLE2 '\x86' /* build 2-tuple from two topmost stack items */ +#define TUPLE3 '\x87' /* build 3-tuple from three topmost stack items */ +#define NEWTRUE '\x88' /* push True */ +#define NEWFALSE '\x89' /* push False */ +#define LONG1 '\x8a' /* push long from < 256 bytes */ +#define LONG4 '\x8b' /* push really big long */ + +/* There aren't opcodes -- they're ways to pickle bools before protocol 2, + * so that unpicklers written before bools were introduced unpickle them + * as ints, but unpicklers after can recognize that bools were intended. + * Note that protocol 2 added direct ways to pickle bools. + */ +#undef TRUE +#define TRUE "I01\n" +#undef FALSE +#define FALSE "I00\n" + +/* Keep in synch with pickle.Pickler._BATCHSIZE. This is how many elements + * batch_list/dict() pumps out before doing APPENDS/SETITEMS. Nothing will + * break if this gets out of synch with pickle.py, but it's unclear that + * would help anything either. + */ +#define BATCHSIZE 1000 + +static char MARKv = MARK; + +static PyObject *PickleError; +static PyObject *PicklingError; +static PyObject *UnpickleableError; +static PyObject *UnpicklingError; +static PyObject *BadPickleGet; + +/* As the name says, an empty tuple. */ +static PyObject *empty_tuple; + +/* copy_reg.dispatch_table, {type_object: pickling_function} */ +static PyObject *dispatch_table; + +/* For EXT[124] opcodes. */ +/* copy_reg._extension_registry, {(module_name, function_name): code} */ +static PyObject *extension_registry; +/* copy_reg._inverted_registry, {code: (module_name, function_name)} */ +static PyObject *inverted_registry; +/* copy_reg._extension_cache, {code: object} */ +static PyObject *extension_cache; + +/* For looking up name pairs in copy_reg._extension_registry. */ +static PyObject *two_tuple; + +static PyObject *__class___str, *__getinitargs___str, *__dict___str, + *__getstate___str, *__setstate___str, *__name___str, *__reduce___str, + *__reduce_ex___str, + *write_str, *append_str, + *read_str, *readline_str, *__main___str, + *copy_reg_str, *dispatch_table_str; + +/************************************************************************* + Internal Data type for pickle data. */ + +typedef struct { + PyObject_HEAD + int length; /* number of initial slots in data currently used */ + int size; /* number of slots in data allocated */ + PyObject **data; +} Pdata; + +static void +Pdata_dealloc(Pdata *self) +{ + int i; + PyObject **p; + + for (i = self->length, p = self->data; --i >= 0; p++) { + Py_DECREF(*p); + } + if (self->data) + free(self->data); + PyObject_Del(self); +} + +static PyTypeObject PdataType = { + PyObject_HEAD_INIT(NULL) 0, "cPickle.Pdata", sizeof(Pdata), 0, + (destructor)Pdata_dealloc, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0L,0L,0L,0L, "" +}; + +#define Pdata_Check(O) ((O)->ob_type == &PdataType) + +static PyObject * +Pdata_New(void) +{ + Pdata *self; + + if (!(self = PyObject_New(Pdata, &PdataType))) + return NULL; + self->size = 8; + self->length = 0; + self->data = malloc(self->size * sizeof(PyObject*)); + if (self->data) + return (PyObject*)self; + Py_DECREF(self); + return PyErr_NoMemory(); +} + +static int +stackUnderflow(void) +{ + PyErr_SetString(UnpicklingError, "unpickling stack underflow"); + return -1; +} + +/* Retain only the initial clearto items. If clearto >= the current + * number of items, this is a (non-erroneous) NOP. + */ +static int +Pdata_clear(Pdata *self, int clearto) +{ + int i; + PyObject **p; + + if (clearto < 0) return stackUnderflow(); + if (clearto >= self->length) return 0; + + for (i = self->length, p = self->data + clearto; + --i >= clearto; + p++) { + Py_CLEAR(*p); + } + self->length = clearto; + + return 0; +} + +static int +Pdata_grow(Pdata *self) +{ + int bigger; + size_t nbytes; + PyObject **tmp; + + bigger = self->size << 1; + if (bigger <= 0) /* was 0, or new value overflows */ + goto nomemory; + if ((int)(size_t)bigger != bigger) + goto nomemory; + nbytes = (size_t)bigger * sizeof(PyObject *); + if (nbytes / sizeof(PyObject *) != (size_t)bigger) + goto nomemory; + tmp = realloc(self->data, nbytes); + if (tmp == NULL) + goto nomemory; + self->data = tmp; + self->size = bigger; + return 0; + + nomemory: + PyErr_NoMemory(); + return -1; +} + +/* D is a Pdata*. Pop the topmost element and store it into V, which + * must be an lvalue holding PyObject*. On stack underflow, UnpicklingError + * is raised and V is set to NULL. D and V may be evaluated several times. + */ +#define PDATA_POP(D, V) { \ + if ((D)->length) \ + (V) = (D)->data[--((D)->length)]; \ + else { \ + PyErr_SetString(UnpicklingError, "bad pickle data"); \ + (V) = NULL; \ + } \ +} + +/* PDATA_PUSH and PDATA_APPEND both push rvalue PyObject* O on to Pdata* + * D. If the Pdata stack can't be grown to hold the new value, both + * raise MemoryError and execute "return ER". The difference is in ownership + * of O after: _PUSH transfers ownership of O from the caller to the stack + * (no incref of O is done, and in case of error O is decrefed), while + * _APPEND pushes a new reference. + */ + +/* Push O on stack D, giving ownership of O to the stack. */ +#define PDATA_PUSH(D, O, ER) { \ + if (((Pdata*)(D))->length == ((Pdata*)(D))->size && \ + Pdata_grow((Pdata*)(D)) < 0) { \ + Py_DECREF(O); \ + return ER; \ + } \ + ((Pdata*)(D))->data[((Pdata*)(D))->length++] = (O); \ +} + +/* Push O on stack D, pushing a new reference. */ +#define PDATA_APPEND(D, O, ER) { \ + if (((Pdata*)(D))->length == ((Pdata*)(D))->size && \ + Pdata_grow((Pdata*)(D)) < 0) \ + return ER; \ + Py_INCREF(O); \ + ((Pdata*)(D))->data[((Pdata*)(D))->length++] = (O); \ +} + + +static PyObject * +Pdata_popTuple(Pdata *self, int start) +{ + PyObject *r; + int i, j, l; + + l = self->length-start; + r = PyTuple_New(l); + if (r == NULL) + return NULL; + for (i = start, j = 0 ; j < l; i++, j++) + PyTuple_SET_ITEM(r, j, self->data[i]); + + self->length = start; + return r; +} + +static PyObject * +Pdata_popList(Pdata *self, int start) +{ + PyObject *r; + int i, j, l; + + l=self->length-start; + if (!( r=PyList_New(l))) return NULL; + for (i=start, j=0 ; j < l; i++, j++) + PyList_SET_ITEM(r, j, self->data[i]); + + self->length=start; + return r; +} + +/*************************************************************************/ + +#define ARG_TUP(self, o) { \ + if (self->arg || (self->arg=PyTuple_New(1))) { \ + Py_XDECREF(PyTuple_GET_ITEM(self->arg,0)); \ + PyTuple_SET_ITEM(self->arg,0,o); \ + } \ + else { \ + Py_DECREF(o); \ + } \ +} + +#define FREE_ARG_TUP(self) { \ + if (self->arg->ob_refcnt > 1) { \ + Py_DECREF(self->arg); \ + self->arg=NULL; \ + } \ + } + +typedef struct Picklerobject { + PyObject_HEAD + FILE *fp; + PyObject *write; + PyObject *file; + PyObject *memo; + PyObject *arg; + PyObject *pers_func; + PyObject *inst_pers_func; + + /* pickle protocol number, >= 0 */ + int proto; + + /* bool, true if proto > 0 */ + int bin; + + int fast; /* Fast mode doesn't save in memo, don't use if circ ref */ + int nesting; + int (*write_func)(struct Picklerobject *, const char *, Py_ssize_t); + char *write_buf; + int buf_size; + PyObject *dispatch_table; + int fast_container; /* count nested container dumps */ + PyObject *fast_memo; +} Picklerobject; + +#ifndef PY_CPICKLE_FAST_LIMIT +#define PY_CPICKLE_FAST_LIMIT 50 +#endif + +static PyTypeObject Picklertype; + +typedef struct Unpicklerobject { + PyObject_HEAD + FILE *fp; + PyObject *file; + PyObject *readline; + PyObject *read; + PyObject *memo; + PyObject *arg; + Pdata *stack; + PyObject *mark; + PyObject *pers_func; + PyObject *last_string; + int *marks; + int num_marks; + int marks_size; + Py_ssize_t (*read_func)(struct Unpicklerobject *, char **, Py_ssize_t); + Py_ssize_t (*readline_func)(struct Unpicklerobject *, char **); + int buf_size; + char *buf; + PyObject *find_class; +} Unpicklerobject; + +static PyTypeObject Unpicklertype; + +/* Forward decls that need the above structs */ +static int save(Picklerobject *, PyObject *, int); +static int put2(Picklerobject *, PyObject *); + +static +PyObject * +cPickle_ErrFormat(PyObject *ErrType, char *stringformat, char *format, ...) +{ + va_list va; + PyObject *args=0, *retval=0; + va_start(va, format); + + if (format) args = Py_VaBuildValue(format, va); + va_end(va); + if (format && ! args) return NULL; + if (stringformat && !(retval=PyString_FromString(stringformat))) + return NULL; + + if (retval) { + if (args) { + PyObject *v; + v=PyString_Format(retval, args); + Py_DECREF(retval); + Py_DECREF(args); + if (! v) return NULL; + retval=v; + } + } + else + if (args) retval=args; + else { + PyErr_SetObject(ErrType,Py_None); + return NULL; + } + PyErr_SetObject(ErrType,retval); + Py_DECREF(retval); + return NULL; +} + +static int +write_file(Picklerobject *self, const char *s, Py_ssize_t n) +{ + size_t nbyteswritten; + + if (s == NULL) { + return 0; + } + + if (n > INT_MAX) { + /* String too large */ + return -1; + } + + Py_BEGIN_ALLOW_THREADS + nbyteswritten = fwrite(s, sizeof(char), n, self->fp); + Py_END_ALLOW_THREADS + if (nbyteswritten != (size_t)n) { + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + + return (int)n; +} + +static int +write_cStringIO(Picklerobject *self, const char *s, Py_ssize_t n) +{ + if (s == NULL) { + return 0; + } + + if (PycStringIO->cwrite((PyObject *)self->file, s, n) != n) { + return -1; + } + + return (int)n; +} + +static int +write_none(Picklerobject *self, const char *s, Py_ssize_t n) +{ + if (s == NULL) return 0; + if (n > INT_MAX) return -1; + return (int)n; +} + +static int +write_other(Picklerobject *self, const char *s, Py_ssize_t _n) +{ + PyObject *py_str = 0, *junk = 0; + int n; + + if (_n > INT_MAX) + return -1; + n = (int)_n; + if (s == NULL) { + if (!( self->buf_size )) return 0; + py_str = PyString_FromStringAndSize(self->write_buf, + self->buf_size); + if (!py_str) + return -1; + } + else { + if (self->buf_size && (n + self->buf_size) > WRITE_BUF_SIZE) { + if (write_other(self, NULL, 0) < 0) + return -1; + } + + if (n > WRITE_BUF_SIZE) { + if (!( py_str = + PyString_FromStringAndSize(s, n))) + return -1; + } + else { + memcpy(self->write_buf + self->buf_size, s, n); + self->buf_size += n; + return n; + } + } + + if (self->write) { + /* object with write method */ + ARG_TUP(self, py_str); + if (self->arg) { + junk = PyObject_Call(self->write, self->arg, NULL); + FREE_ARG_TUP(self); + } + if (junk) Py_DECREF(junk); + else return -1; + } + else + PDATA_PUSH(self->file, py_str, -1); + + self->buf_size = 0; + return n; +} + + +static Py_ssize_t +read_file(Unpicklerobject *self, char **s, Py_ssize_t n) +{ + size_t nbytesread; + + if (self->buf_size == 0) { + int size; + + size = ((n < 32) ? 32 : n); + if (!( self->buf = (char *)malloc(size))) { + PyErr_NoMemory(); + return -1; + } + + self->buf_size = size; + } + else if (n > self->buf_size) { + self->buf = (char *)realloc(self->buf, n); + if (!self->buf) { + PyErr_NoMemory(); + return -1; + } + self->buf_size = n; + } + + Py_BEGIN_ALLOW_THREADS + nbytesread = fread(self->buf, sizeof(char), n, self->fp); + Py_END_ALLOW_THREADS + if (nbytesread != (size_t)n) { + if (feof(self->fp)) { + PyErr_SetNone(PyExc_EOFError); + return -1; + } + + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + + *s = self->buf; + + return n; +} + + +static Py_ssize_t +readline_file(Unpicklerobject *self, char **s) +{ + int i; + + if (self->buf_size == 0) { + if (!( self->buf = (char *)malloc(40))) { + PyErr_NoMemory(); + return -1; + } + self->buf_size = 40; + } + + i = 0; + while (1) { + int bigger; + for (; i < (self->buf_size - 1); i++) { + if (feof(self->fp) || + (self->buf[i] = getc(self->fp)) == '\n') { + self->buf[i + 1] = '\0'; + *s = self->buf; + return i + 1; + } + } + bigger = self->buf_size << 1; + if (bigger <= 0) { /* overflow */ + PyErr_NoMemory(); + return -1; + } + self->buf = (char *)realloc(self->buf, bigger); + if (!self->buf) { + PyErr_NoMemory(); + return -1; + } + self->buf_size = bigger; + } +} + + +static Py_ssize_t +read_cStringIO(Unpicklerobject *self, char **s, Py_ssize_t n) +{ + char *ptr; + + if (PycStringIO->cread((PyObject *)self->file, &ptr, n) != n) { + PyErr_SetNone(PyExc_EOFError); + return -1; + } + + *s = ptr; + + return n; +} + + +static Py_ssize_t +readline_cStringIO(Unpicklerobject *self, char **s) +{ + Py_ssize_t n; + char *ptr; + + if ((n = PycStringIO->creadline((PyObject *)self->file, &ptr)) < 0) { + return -1; + } + + *s = ptr; + + return n; +} + + +static Py_ssize_t +read_other(Unpicklerobject *self, char **s, Py_ssize_t n) +{ + PyObject *bytes, *str=0; + + if (!( bytes = PyInt_FromSsize_t(n))) return -1; + + ARG_TUP(self, bytes); + if (self->arg) { + str = PyObject_Call(self->read, self->arg, NULL); + FREE_ARG_TUP(self); + } + if (! str) return -1; + + Py_XDECREF(self->last_string); + self->last_string = str; + + if (! (*s = PyString_AsString(str))) return -1; + return n; +} + + +static Py_ssize_t +readline_other(Unpicklerobject *self, char **s) +{ + PyObject *str; + Py_ssize_t str_size; + + if (!( str = PyObject_CallObject(self->readline, empty_tuple))) { + return -1; + } + + if ((str_size = PyString_Size(str)) < 0) + return -1; + + Py_XDECREF(self->last_string); + self->last_string = str; + + if (! (*s = PyString_AsString(str))) + return -1; + + return str_size; +} + +/* Copy the first n bytes from s into newly malloc'ed memory, plus a + * trailing 0 byte. Return a pointer to that, or NULL if out of memory. + * The caller is responsible for free()'ing the return value. + */ +static char * +pystrndup(const char *s, int n) +{ + char *r = (char *)malloc(n+1); + if (r == NULL) + return (char*)PyErr_NoMemory(); + memcpy(r, s, n); + r[n] = 0; + return r; +} + + +static int +get(Picklerobject *self, PyObject *id) +{ + PyObject *value, *mv; + long c_value; + char s[30]; + size_t len; + + if (!( mv = PyDict_GetItem(self->memo, id))) { + PyErr_SetObject(PyExc_KeyError, id); + return -1; + } + + if (!( value = PyTuple_GetItem(mv, 0))) + return -1; + + if (!( PyInt_Check(value))) { + PyErr_SetString(PicklingError, "no int where int expected in memo"); + return -1; + } + c_value = PyInt_AS_LONG((PyIntObject*)value); + + if (!self->bin) { + s[0] = GET; + PyOS_snprintf(s + 1, sizeof(s) - 1, "%ld\n", c_value); + len = strlen(s); + } + else if (Pdata_Check(self->file)) { + if (write_other(self, NULL, 0) < 0) return -1; + PDATA_APPEND(self->file, mv, -1); + return 0; + } + else { + if (c_value < 256) { + s[0] = BINGET; + s[1] = (int)(c_value & 0xff); + len = 2; + } + else { + s[0] = LONG_BINGET; + s[1] = (int)(c_value & 0xff); + s[2] = (int)((c_value >> 8) & 0xff); + s[3] = (int)((c_value >> 16) & 0xff); + s[4] = (int)((c_value >> 24) & 0xff); + len = 5; + } + } + + if (self->write_func(self, s, len) < 0) + return -1; + + return 0; +} + + +static int +put(Picklerobject *self, PyObject *ob) +{ + if (ob->ob_refcnt < 2 || self->fast) + return 0; + + return put2(self, ob); +} + + +static int +put2(Picklerobject *self, PyObject *ob) +{ + char c_str[30]; + int p; + size_t len; + int res = -1; + PyObject *py_ob_id = 0, *memo_len = 0, *t = 0; + + if (self->fast) + return 0; + + if ((p = PyDict_Size(self->memo)) < 0) + goto finally; + + /* Make sure memo keys are positive! */ + /* XXX Why? + * XXX And does "positive" really mean non-negative? + * XXX pickle.py starts with PUT index 0, not 1. This makes for + * XXX gratuitous differences between the pickling modules. + */ + p++; + + if (!( py_ob_id = PyLong_FromVoidPtr(ob))) + goto finally; + + if (!( memo_len = PyInt_FromLong(p))) + goto finally; + + if (!( t = PyTuple_New(2))) + goto finally; + + PyTuple_SET_ITEM(t, 0, memo_len); + Py_INCREF(memo_len); + PyTuple_SET_ITEM(t, 1, ob); + Py_INCREF(ob); + + if (PyDict_SetItem(self->memo, py_ob_id, t) < 0) + goto finally; + + if (!self->bin) { + c_str[0] = PUT; + PyOS_snprintf(c_str + 1, sizeof(c_str) - 1, "%d\n", p); + len = strlen(c_str); + } + else if (Pdata_Check(self->file)) { + if (write_other(self, NULL, 0) < 0) return -1; + PDATA_APPEND(self->file, memo_len, -1); + res=0; /* Job well done ;) */ + goto finally; + } + else { + if (p >= 256) { + c_str[0] = LONG_BINPUT; + c_str[1] = (int)(p & 0xff); + c_str[2] = (int)((p >> 8) & 0xff); + c_str[3] = (int)((p >> 16) & 0xff); + c_str[4] = (int)((p >> 24) & 0xff); + len = 5; + } + else { + c_str[0] = BINPUT; + c_str[1] = p; + len = 2; + } + } + + if (self->write_func(self, c_str, len) < 0) + goto finally; + + res = 0; + + finally: + Py_XDECREF(py_ob_id); + Py_XDECREF(memo_len); + Py_XDECREF(t); + + return res; +} + +static PyObject * +whichmodule(PyObject *global, PyObject *global_name) +{ + Py_ssize_t i, j; + PyObject *module = 0, *modules_dict = 0, + *global_name_attr = 0, *name = 0; + + module = PyObject_GetAttrString(global, "__module__"); + if (module) + return module; + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + return NULL; + + if (!( modules_dict = PySys_GetObject("modules"))) + return NULL; + + i = 0; + while ((j = PyDict_Next(modules_dict, &i, &name, &module))) { + + if (PyObject_Compare(name, __main___str)==0) continue; + + global_name_attr = PyObject_GetAttr(module, global_name); + if (!global_name_attr) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + return NULL; + continue; + } + + if (global_name_attr != global) { + Py_DECREF(global_name_attr); + continue; + } + + Py_DECREF(global_name_attr); + + break; + } + + /* The following implements the rule in pickle.py added in 1.5 + that used __main__ if no module is found. I don't actually + like this rule. jlf + */ + if (!j) { + j=1; + name=__main___str; + } + + Py_INCREF(name); + return name; +} + + +static int +fast_save_enter(Picklerobject *self, PyObject *obj) +{ + /* if fast_container < 0, we're doing an error exit. */ + if (++self->fast_container >= PY_CPICKLE_FAST_LIMIT) { + PyObject *key = NULL; + if (self->fast_memo == NULL) { + self->fast_memo = PyDict_New(); + if (self->fast_memo == NULL) { + self->fast_container = -1; + return 0; + } + } + key = PyLong_FromVoidPtr(obj); + if (key == NULL) + return 0; + if (PyDict_GetItem(self->fast_memo, key)) { + Py_DECREF(key); + PyErr_Format(PyExc_ValueError, + "fast mode: can't pickle cyclic objects " + "including object type %s at %p", + obj->ob_type->tp_name, obj); + self->fast_container = -1; + return 0; + } + if (PyDict_SetItem(self->fast_memo, key, Py_None) < 0) { + Py_DECREF(key); + self->fast_container = -1; + return 0; + } + Py_DECREF(key); + } + return 1; +} + +int +fast_save_leave(Picklerobject *self, PyObject *obj) +{ + if (self->fast_container-- >= PY_CPICKLE_FAST_LIMIT) { + PyObject *key = PyLong_FromVoidPtr(obj); + if (key == NULL) + return 0; + if (PyDict_DelItem(self->fast_memo, key) < 0) { + Py_DECREF(key); + return 0; + } + Py_DECREF(key); + } + return 1; +} + +static int +save_none(Picklerobject *self, PyObject *args) +{ + static char none = NONE; + if (self->write_func(self, &none, 1) < 0) + return -1; + + return 0; +} + +static int +save_bool(Picklerobject *self, PyObject *args) +{ + static const char *buf[2] = {FALSE, TRUE}; + static char len[2] = {sizeof(FALSE)-1, sizeof(TRUE)-1}; + long l = PyInt_AS_LONG((PyIntObject *)args); + + if (self->proto >= 2) { + char opcode = l ? NEWTRUE : NEWFALSE; + if (self->write_func(self, &opcode, 1) < 0) + return -1; + } + else if (self->write_func(self, buf[l], len[l]) < 0) + return -1; + return 0; +} + +static int +save_int(Picklerobject *self, PyObject *args) +{ + char c_str[32]; + long l = PyInt_AS_LONG((PyIntObject *)args); + int len = 0; + + if (!self->bin +#if SIZEOF_LONG > 4 + || l > 0x7fffffffL + || l < -0x80000000L +#endif + ) { + /* Text-mode pickle, or long too big to fit in the 4-byte + * signed BININT format: store as a string. + */ + c_str[0] = INT; + PyOS_snprintf(c_str + 1, sizeof(c_str) - 1, "%ld\n", l); + if (self->write_func(self, c_str, strlen(c_str)) < 0) + return -1; + } + else { + /* Binary pickle and l fits in a signed 4-byte int. */ + c_str[1] = (int)( l & 0xff); + c_str[2] = (int)((l >> 8) & 0xff); + c_str[3] = (int)((l >> 16) & 0xff); + c_str[4] = (int)((l >> 24) & 0xff); + + if ((c_str[4] == 0) && (c_str[3] == 0)) { + if (c_str[2] == 0) { + c_str[0] = BININT1; + len = 2; + } + else { + c_str[0] = BININT2; + len = 3; + } + } + else { + c_str[0] = BININT; + len = 5; + } + + if (self->write_func(self, c_str, len) < 0) + return -1; + } + + return 0; +} + + +static int +save_long(Picklerobject *self, PyObject *args) +{ + Py_ssize_t size; + int res = -1; + PyObject *repr = NULL; + + static char l = LONG; + + if (self->proto >= 2) { + /* Linear-time pickling. */ + size_t nbits; + size_t nbytes; + unsigned char *pdata; + char c_str[5]; + int i; + int sign = _PyLong_Sign(args); + + if (sign == 0) { + /* It's 0 -- an empty bytestring. */ + c_str[0] = LONG1; + c_str[1] = 0; + i = self->write_func(self, c_str, 2); + if (i < 0) goto finally; + res = 0; + goto finally; + } + nbits = _PyLong_NumBits(args); + if (nbits == (size_t)-1 && PyErr_Occurred()) + goto finally; + /* How many bytes do we need? There are nbits >> 3 full + * bytes of data, and nbits & 7 leftover bits. If there + * are any leftover bits, then we clearly need another + * byte. Wnat's not so obvious is that we *probably* + * need another byte even if there aren't any leftovers: + * the most-significant bit of the most-significant byte + * acts like a sign bit, and it's usually got a sense + * opposite of the one we need. The exception is longs + * of the form -(2**(8*j-1)) for j > 0. Such a long is + * its own 256's-complement, so has the right sign bit + * even without the extra byte. That's a pain to check + * for in advance, though, so we always grab an extra + * byte at the start, and cut it back later if possible. + */ + nbytes = (nbits >> 3) + 1; + if (nbytes > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "long too large " + "to pickle"); + goto finally; + } + repr = PyString_FromStringAndSize(NULL, (int)nbytes); + if (repr == NULL) goto finally; + pdata = (unsigned char *)PyString_AS_STRING(repr); + i = _PyLong_AsByteArray((PyLongObject *)args, + pdata, nbytes, + 1 /* little endian */, 1 /* signed */); + if (i < 0) goto finally; + /* If the long is negative, this may be a byte more than + * needed. This is so iff the MSB is all redundant sign + * bits. + */ + if (sign < 0 && nbytes > 1 && pdata[nbytes - 1] == 0xff && + (pdata[nbytes - 2] & 0x80) != 0) + --nbytes; + + if (nbytes < 256) { + c_str[0] = LONG1; + c_str[1] = (char)nbytes; + size = 2; + } + else { + c_str[0] = LONG4; + size = (int)nbytes; + for (i = 1; i < 5; i++) { + c_str[i] = (char)(size & 0xff); + size >>= 8; + } + size = 5; + } + i = self->write_func(self, c_str, size); + if (i < 0) goto finally; + i = self->write_func(self, (char *)pdata, (int)nbytes); + if (i < 0) goto finally; + res = 0; + goto finally; + } + + /* proto < 2: write the repr and newline. This is quadratic-time + * (in the number of digits), in both directions. + */ + if (!( repr = PyObject_Repr(args))) + goto finally; + + if ((size = PyString_Size(repr)) < 0) + goto finally; + + if (self->write_func(self, &l, 1) < 0) + goto finally; + + if (self->write_func(self, + PyString_AS_STRING((PyStringObject *)repr), + size) < 0) + goto finally; + + if (self->write_func(self, "\n", 1) < 0) + goto finally; + + res = 0; + + finally: + Py_XDECREF(repr); + return res; +} + + +static int +save_float(Picklerobject *self, PyObject *args) +{ + double x = PyFloat_AS_DOUBLE((PyFloatObject *)args); + + if (self->bin) { + char str[9]; + str[0] = BINFLOAT; + if (_PyFloat_Pack8(x, (unsigned char *)&str[1], 0) < 0) + return -1; + if (self->write_func(self, str, 9) < 0) + return -1; + } + else { + char c_str[250]; + c_str[0] = FLOAT; + PyOS_ascii_formatd(c_str + 1, sizeof(c_str) - 2, "%.17g", x); + /* Extend the formatted string with a newline character */ + strcat(c_str, "\n"); + + if (self->write_func(self, c_str, strlen(c_str)) < 0) + return -1; + } + + return 0; +} + + +static int +save_string(Picklerobject *self, PyObject *args, int doput) +{ + int size, len; + PyObject *repr=0; + + if ((size = PyString_Size(args)) < 0) + return -1; + + if (!self->bin) { + char *repr_str; + + static char string = STRING; + + if (!( repr = PyObject_Repr(args))) + return -1; + + if ((len = PyString_Size(repr)) < 0) + goto err; + repr_str = PyString_AS_STRING((PyStringObject *)repr); + + if (self->write_func(self, &string, 1) < 0) + goto err; + + if (self->write_func(self, repr_str, len) < 0) + goto err; + + if (self->write_func(self, "\n", 1) < 0) + goto err; + + Py_XDECREF(repr); + } + else { + int i; + char c_str[5]; + + if ((size = PyString_Size(args)) < 0) + return -1; + + if (size < 256) { + c_str[0] = SHORT_BINSTRING; + c_str[1] = size; + len = 2; + } + else if (size <= INT_MAX) { + c_str[0] = BINSTRING; + for (i = 1; i < 5; i++) + c_str[i] = (int)(size >> ((i - 1) * 8)); + len = 5; + } + else + return -1; /* string too large */ + + if (self->write_func(self, c_str, len) < 0) + return -1; + + if (size > 128 && Pdata_Check(self->file)) { + if (write_other(self, NULL, 0) < 0) return -1; + PDATA_APPEND(self->file, args, -1); + } + else { + if (self->write_func(self, + PyString_AS_STRING( + (PyStringObject *)args), + size) < 0) + return -1; + } + } + + if (doput) + if (put(self, args) < 0) + return -1; + + return 0; + + err: + Py_XDECREF(repr); + return -1; +} + + +#ifdef Py_USING_UNICODE +/* A copy of PyUnicode_EncodeRawUnicodeEscape() that also translates + backslash and newline characters to \uXXXX escapes. */ +static PyObject * +modified_EncodeRawUnicodeEscape(const Py_UNICODE *s, int size) +{ + PyObject *repr; + char *p; + char *q; + + static const char *hexdigit = "0123456789ABCDEF"; + + repr = PyString_FromStringAndSize(NULL, 6 * size); + if (repr == NULL) + return NULL; + if (size == 0) + return repr; + + p = q = PyString_AS_STRING(repr); + while (size-- > 0) { + Py_UNICODE ch = *s++; + /* Map 16-bit characters to '\uxxxx' */ + if (ch >= 256 || ch == '\\' || ch == '\n') { + *p++ = '\\'; + *p++ = 'u'; + *p++ = hexdigit[(ch >> 12) & 0xf]; + *p++ = hexdigit[(ch >> 8) & 0xf]; + *p++ = hexdigit[(ch >> 4) & 0xf]; + *p++ = hexdigit[ch & 15]; + } + /* Copy everything else as-is */ + else + *p++ = (char) ch; + } + *p = '\0'; + _PyString_Resize(&repr, p - q); + return repr; +} + + +static int +save_unicode(Picklerobject *self, PyObject *args, int doput) +{ + Py_ssize_t size, len; + PyObject *repr=0; + + if (!PyUnicode_Check(args)) + return -1; + + if (!self->bin) { + char *repr_str; + static char string = UNICODE; + + repr = modified_EncodeRawUnicodeEscape( + PyUnicode_AS_UNICODE(args), PyUnicode_GET_SIZE(args)); + if (!repr) + return -1; + + if ((len = PyString_Size(repr)) < 0) + goto err; + repr_str = PyString_AS_STRING((PyStringObject *)repr); + + if (self->write_func(self, &string, 1) < 0) + goto err; + + if (self->write_func(self, repr_str, len) < 0) + goto err; + + if (self->write_func(self, "\n", 1) < 0) + goto err; + + Py_XDECREF(repr); + } + else { + int i; + char c_str[5]; + + if (!( repr = PyUnicode_AsUTF8String(args))) + return -1; + + if ((size = PyString_Size(repr)) < 0) + goto err; + if (size > INT_MAX) + return -1; /* string too large */ + + c_str[0] = BINUNICODE; + for (i = 1; i < 5; i++) + c_str[i] = (int)(size >> ((i - 1) * 8)); + len = 5; + + if (self->write_func(self, c_str, len) < 0) + goto err; + + if (size > 128 && Pdata_Check(self->file)) { + if (write_other(self, NULL, 0) < 0) + goto err; + PDATA_APPEND(self->file, repr, -1); + } + else { + if (self->write_func(self, PyString_AS_STRING(repr), + size) < 0) + goto err; + } + + Py_DECREF(repr); + } + + if (doput) + if (put(self, args) < 0) + return -1; + + return 0; + + err: + Py_XDECREF(repr); + return -1; +} +#endif + +/* A helper for save_tuple. Push the len elements in tuple t on the stack. */ +static int +store_tuple_elements(Picklerobject *self, PyObject *t, int len) +{ + int i; + int res = -1; /* guilty until proved innocent */ + + assert(PyTuple_Size(t) == len); + + for (i = 0; i < len; i++) { + PyObject *element = PyTuple_GET_ITEM(t, i); + + if (element == NULL) + goto finally; + if (save(self, element, 0) < 0) + goto finally; + } + res = 0; + + finally: + return res; +} + +/* Tuples are ubiquitous in the pickle protocols, so many techniques are + * used across protocols to minimize the space needed to pickle them. + * Tuples are also the only builtin immutable type that can be recursive + * (a tuple can be reached from itself), and that requires some subtle + * magic so that it works in all cases. IOW, this is a long routine. + */ +static int +save_tuple(Picklerobject *self, PyObject *args) +{ + PyObject *py_tuple_id = NULL; + int len, i; + int res = -1; + + static char tuple = TUPLE; + static char pop = POP; + static char pop_mark = POP_MARK; + static char len2opcode[] = {EMPTY_TUPLE, TUPLE1, TUPLE2, TUPLE3}; + + if ((len = PyTuple_Size(args)) < 0) + goto finally; + + if (len == 0) { + char c_str[2]; + + if (self->proto) { + c_str[0] = EMPTY_TUPLE; + len = 1; + } + else { + c_str[0] = MARK; + c_str[1] = TUPLE; + len = 2; + } + if (self->write_func(self, c_str, len) >= 0) + res = 0; + /* Don't memoize an empty tuple. */ + goto finally; + } + + /* A non-empty tuple. */ + + /* id(tuple) isn't in the memo now. If it shows up there after + * saving the tuple elements, the tuple must be recursive, in + * which case we'll pop everything we put on the stack, and fetch + * its value from the memo. + */ + py_tuple_id = PyLong_FromVoidPtr(args); + if (py_tuple_id == NULL) + goto finally; + + if (len <= 3 && self->proto >= 2) { + /* Use TUPLE{1,2,3} opcodes. */ + if (store_tuple_elements(self, args, len) < 0) + goto finally; + if (PyDict_GetItem(self->memo, py_tuple_id)) { + /* pop the len elements */ + for (i = 0; i < len; ++i) + if (self->write_func(self, &pop, 1) < 0) + goto finally; + /* fetch from memo */ + if (get(self, py_tuple_id) < 0) + goto finally; + res = 0; + goto finally; + } + /* Not recursive. */ + if (self->write_func(self, len2opcode + len, 1) < 0) + goto finally; + goto memoize; + } + + /* proto < 2 and len > 0, or proto >= 2 and len > 3. + * Generate MARK elt1 elt2 ... TUPLE + */ + if (self->write_func(self, &MARKv, 1) < 0) + goto finally; + + if (store_tuple_elements(self, args, len) < 0) + goto finally; + + if (PyDict_GetItem(self->memo, py_tuple_id)) { + /* pop the stack stuff we pushed */ + if (self->bin) { + if (self->write_func(self, &pop_mark, 1) < 0) + goto finally; + } + else { + /* Note that we pop one more than len, to remove + * the MARK too. + */ + for (i = 0; i <= len; i++) + if (self->write_func(self, &pop, 1) < 0) + goto finally; + } + /* fetch from memo */ + if (get(self, py_tuple_id) >= 0) + res = 0; + goto finally; + } + + /* Not recursive. */ + if (self->write_func(self, &tuple, 1) < 0) + goto finally; + + memoize: + if (put(self, args) >= 0) + res = 0; + + finally: + Py_XDECREF(py_tuple_id); + return res; +} + +/* iter is an iterator giving items, and we batch up chunks of + * MARK item item ... item APPENDS + * opcode sequences. Calling code should have arranged to first create an + * empty list, or list-like object, for the APPENDS to operate on. + * Returns 0 on success, <0 on error. + */ +static int +batch_list(Picklerobject *self, PyObject *iter) +{ + PyObject *obj; + PyObject *slice[BATCHSIZE]; + int i, n; + + static char append = APPEND; + static char appends = APPENDS; + + assert(iter != NULL); + + if (self->proto == 0) { + /* APPENDS isn't available; do one at a time. */ + for (;;) { + obj = PyIter_Next(iter); + if (obj == NULL) { + if (PyErr_Occurred()) + return -1; + break; + } + i = save(self, obj, 0); + Py_DECREF(obj); + if (i < 0) + return -1; + if (self->write_func(self, &append, 1) < 0) + return -1; + } + return 0; + } + + /* proto > 0: write in batches of BATCHSIZE. */ + do { + /* Get next group of (no more than) BATCHSIZE elements. */ + for (n = 0; n < BATCHSIZE; ++n) { + obj = PyIter_Next(iter); + if (obj == NULL) { + if (PyErr_Occurred()) + goto BatchFailed; + break; + } + slice[n] = obj; + } + + if (n > 1) { + /* Pump out MARK, slice[0:n], APPENDS. */ + if (self->write_func(self, &MARKv, 1) < 0) + goto BatchFailed; + for (i = 0; i < n; ++i) { + if (save(self, slice[i], 0) < 0) + goto BatchFailed; + } + if (self->write_func(self, &appends, 1) < 0) + goto BatchFailed; + } + else if (n == 1) { + if (save(self, slice[0], 0) < 0) + goto BatchFailed; + if (self->write_func(self, &append, 1) < 0) + goto BatchFailed; + } + + for (i = 0; i < n; ++i) { + Py_DECREF(slice[i]); + } + } while (n == BATCHSIZE); + return 0; + +BatchFailed: + while (--n >= 0) { + Py_DECREF(slice[n]); + } + return -1; +} + +static int +save_list(Picklerobject *self, PyObject *args) +{ + int res = -1; + char s[3]; + int len; + PyObject *iter; + + if (self->fast && !fast_save_enter(self, args)) + goto finally; + + /* Create an empty list. */ + if (self->bin) { + s[0] = EMPTY_LIST; + len = 1; + } + else { + s[0] = MARK; + s[1] = LIST; + len = 2; + } + + if (self->write_func(self, s, len) < 0) + goto finally; + + /* Get list length, and bow out early if empty. */ + if ((len = PyList_Size(args)) < 0) + goto finally; + + /* Memoize. */ + if (len == 0) { + if (put(self, args) >= 0) + res = 0; + goto finally; + } + if (put2(self, args) < 0) + goto finally; + + /* Materialize the list elements. */ + iter = PyObject_GetIter(args); + if (iter == NULL) + goto finally; + res = batch_list(self, iter); + Py_DECREF(iter); + + finally: + if (self->fast && !fast_save_leave(self, args)) + res = -1; + + return res; +} + + +/* iter is an iterator giving (key, value) pairs, and we batch up chunks of + * MARK key value ... key value SETITEMS + * opcode sequences. Calling code should have arranged to first create an + * empty dict, or dict-like object, for the SETITEMS to operate on. + * Returns 0 on success, <0 on error. + * + * This is very much like batch_list(). The difference between saving + * elements directly, and picking apart two-tuples, is so long-winded at + * the C level, though, that attempts to combine these routines were too + * ugly to bear. + */ +static int +batch_dict(Picklerobject *self, PyObject *iter) +{ + PyObject *p; + PyObject *slice[BATCHSIZE]; + int i, n; + + static char setitem = SETITEM; + static char setitems = SETITEMS; + + assert(iter != NULL); + + if (self->proto == 0) { + /* SETITEMS isn't available; do one at a time. */ + for (;;) { + p = PyIter_Next(iter); + if (p == NULL) { + if (PyErr_Occurred()) + return -1; + break; + } + if (!PyTuple_Check(p) || PyTuple_Size(p) != 2) { + PyErr_SetString(PyExc_TypeError, "dict items " + "iterator must return 2-tuples"); + return -1; + } + i = save(self, PyTuple_GET_ITEM(p, 0), 0); + if (i >= 0) + i = save(self, PyTuple_GET_ITEM(p, 1), 0); + Py_DECREF(p); + if (i < 0) + return -1; + if (self->write_func(self, &setitem, 1) < 0) + return -1; + } + return 0; + } + + /* proto > 0: write in batches of BATCHSIZE. */ + do { + /* Get next group of (no more than) BATCHSIZE elements. */ + for (n = 0; n < BATCHSIZE; ++n) { + p = PyIter_Next(iter); + if (p == NULL) { + if (PyErr_Occurred()) + goto BatchFailed; + break; + } + if (!PyTuple_Check(p) || PyTuple_Size(p) != 2) { + PyErr_SetString(PyExc_TypeError, "dict items " + "iterator must return 2-tuples"); + goto BatchFailed; + } + slice[n] = p; + } + + if (n > 1) { + /* Pump out MARK, slice[0:n], SETITEMS. */ + if (self->write_func(self, &MARKv, 1) < 0) + goto BatchFailed; + for (i = 0; i < n; ++i) { + p = slice[i]; + if (save(self, PyTuple_GET_ITEM(p, 0), 0) < 0) + goto BatchFailed; + if (save(self, PyTuple_GET_ITEM(p, 1), 0) < 0) + goto BatchFailed; + } + if (self->write_func(self, &setitems, 1) < 0) + goto BatchFailed; + } + else if (n == 1) { + p = slice[0]; + if (save(self, PyTuple_GET_ITEM(p, 0), 0) < 0) + goto BatchFailed; + if (save(self, PyTuple_GET_ITEM(p, 1), 0) < 0) + goto BatchFailed; + if (self->write_func(self, &setitem, 1) < 0) + goto BatchFailed; + } + + for (i = 0; i < n; ++i) { + Py_DECREF(slice[i]); + } + } while (n == BATCHSIZE); + return 0; + +BatchFailed: + while (--n >= 0) { + Py_DECREF(slice[n]); + } + return -1; +} + +static int +save_dict(Picklerobject *self, PyObject *args) +{ + int res = -1; + char s[3]; + int len; + PyObject *iter; + + if (self->fast && !fast_save_enter(self, args)) + goto finally; + + /* Create an empty dict. */ + if (self->bin) { + s[0] = EMPTY_DICT; + len = 1; + } + else { + s[0] = MARK; + s[1] = DICT; + len = 2; + } + + if (self->write_func(self, s, len) < 0) + goto finally; + + /* Get dict size, and bow out early if empty. */ + if ((len = PyDict_Size(args)) < 0) + goto finally; + + if (len == 0) { + if (put(self, args) >= 0) + res = 0; + goto finally; + } + if (put2(self, args) < 0) + goto finally; + + /* Materialize the dict items. */ + iter = PyObject_CallMethod(args, "iteritems", "()"); + if (iter == NULL) + goto finally; + res = batch_dict(self, iter); + Py_DECREF(iter); + + finally: + if (self->fast && !fast_save_leave(self, args)) + res = -1; + + return res; +} + + +static int +save_inst(Picklerobject *self, PyObject *args) +{ + PyObject *class = 0, *module = 0, *name = 0, *state = 0, + *getinitargs_func = 0, *getstate_func = 0, *class_args = 0; + char *module_str, *name_str; + int module_size, name_size, res = -1; + + static char inst = INST, obj = OBJ, build = BUILD; + + if (self->fast && !fast_save_enter(self, args)) + goto finally; + + if (self->write_func(self, &MARKv, 1) < 0) + goto finally; + + if (!( class = PyObject_GetAttr(args, __class___str))) + goto finally; + + if (self->bin) { + if (save(self, class, 0) < 0) + goto finally; + } + + if ((getinitargs_func = PyObject_GetAttr(args, __getinitargs___str))) { + PyObject *element = 0; + int i, len; + + if (!( class_args = + PyObject_Call(getinitargs_func, empty_tuple, NULL))) + goto finally; + + if ((len = PyObject_Size(class_args)) < 0) + goto finally; + + for (i = 0; i < len; i++) { + if (!( element = PySequence_GetItem(class_args, i))) + goto finally; + + if (save(self, element, 0) < 0) { + Py_DECREF(element); + goto finally; + } + + Py_DECREF(element); + } + } + else { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + goto finally; + } + + if (!self->bin) { + if (!( name = ((PyClassObject *)class)->cl_name )) { + PyErr_SetString(PicklingError, "class has no name"); + goto finally; + } + + if (!( module = whichmodule(class, name))) + goto finally; + + + if ((module_size = PyString_Size(module)) < 0 || + (name_size = PyString_Size(name)) < 0) + goto finally; + + module_str = PyString_AS_STRING((PyStringObject *)module); + name_str = PyString_AS_STRING((PyStringObject *)name); + + if (self->write_func(self, &inst, 1) < 0) + goto finally; + + if (self->write_func(self, module_str, module_size) < 0) + goto finally; + + if (self->write_func(self, "\n", 1) < 0) + goto finally; + + if (self->write_func(self, name_str, name_size) < 0) + goto finally; + + if (self->write_func(self, "\n", 1) < 0) + goto finally; + } + else if (self->write_func(self, &obj, 1) < 0) { + goto finally; + } + + if ((getstate_func = PyObject_GetAttr(args, __getstate___str))) { + state = PyObject_Call(getstate_func, empty_tuple, NULL); + if (!state) + goto finally; + } + else { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + goto finally; + + if (!( state = PyObject_GetAttr(args, __dict___str))) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + goto finally; + res = 0; + goto finally; + } + } + + if (!PyDict_Check(state)) { + if (put2(self, args) < 0) + goto finally; + } + else { + if (put(self, args) < 0) + goto finally; + } + + if (save(self, state, 0) < 0) + goto finally; + + if (self->write_func(self, &build, 1) < 0) + goto finally; + + res = 0; + + finally: + if (self->fast && !fast_save_leave(self, args)) + res = -1; + + Py_XDECREF(module); + Py_XDECREF(class); + Py_XDECREF(state); + Py_XDECREF(getinitargs_func); + Py_XDECREF(getstate_func); + Py_XDECREF(class_args); + + return res; +} + + +static int +save_global(Picklerobject *self, PyObject *args, PyObject *name) +{ + PyObject *global_name = 0, *module = 0, *mod = 0, *klass = 0; + char *name_str, *module_str; + int module_size, name_size, res = -1; + + static char global = GLOBAL; + + if (name) { + global_name = name; + Py_INCREF(global_name); + } + else { + if (!( global_name = PyObject_GetAttr(args, __name___str))) + goto finally; + } + + if (!( module = whichmodule(args, global_name))) + goto finally; + + if ((module_size = PyString_Size(module)) < 0 || + (name_size = PyString_Size(global_name)) < 0) + goto finally; + + module_str = PyString_AS_STRING((PyStringObject *)module); + name_str = PyString_AS_STRING((PyStringObject *)global_name); + + /* XXX This can be doing a relative import. Clearly it shouldn't, + but I don't know how to stop it. :-( */ + mod = PyImport_ImportModule(module_str); + if (mod == NULL) { + cPickle_ErrFormat(PicklingError, + "Can't pickle %s: import of module %s " + "failed", + "OS", args, module); + goto finally; + } + klass = PyObject_GetAttrString(mod, name_str); + if (klass == NULL) { + cPickle_ErrFormat(PicklingError, + "Can't pickle %s: attribute lookup %s.%s " + "failed", + "OSS", args, module, global_name); + goto finally; + } + if (klass != args) { + Py_DECREF(klass); + cPickle_ErrFormat(PicklingError, + "Can't pickle %s: it's not the same object " + "as %s.%s", + "OSS", args, module, global_name); + goto finally; + } + Py_DECREF(klass); + + if (self->proto >= 2) { + /* See whether this is in the extension registry, and if + * so generate an EXT opcode. + */ + PyObject *py_code; /* extension code as Python object */ + long code; /* extension code as C value */ + char c_str[5]; + int n; + + PyTuple_SET_ITEM(two_tuple, 0, module); + PyTuple_SET_ITEM(two_tuple, 1, global_name); + py_code = PyDict_GetItem(extension_registry, two_tuple); + if (py_code == NULL) + goto gen_global; /* not registered */ + + /* Verify py_code has the right type and value. */ + if (!PyInt_Check(py_code)) { + cPickle_ErrFormat(PicklingError, "Can't pickle %s: " + "extension code %s isn't an integer", + "OO", args, py_code); + goto finally; + } + code = PyInt_AS_LONG(py_code); + if (code <= 0 || code > 0x7fffffffL) { + cPickle_ErrFormat(PicklingError, "Can't pickle %s: " + "extension code %ld is out of range", + "Ol", args, code); + goto finally; + } + + /* Generate an EXT opcode. */ + if (code <= 0xff) { + c_str[0] = EXT1; + c_str[1] = (char)code; + n = 2; + } + else if (code <= 0xffff) { + c_str[0] = EXT2; + c_str[1] = (char)(code & 0xff); + c_str[2] = (char)((code >> 8) & 0xff); + n = 3; + } + else { + c_str[0] = EXT4; + c_str[1] = (char)(code & 0xff); + c_str[2] = (char)((code >> 8) & 0xff); + c_str[3] = (char)((code >> 16) & 0xff); + c_str[4] = (char)((code >> 24) & 0xff); + n = 5; + } + + if (self->write_func(self, c_str, n) >= 0) + res = 0; + goto finally; /* and don't memoize */ + } + + gen_global: + if (self->write_func(self, &global, 1) < 0) + goto finally; + + if (self->write_func(self, module_str, module_size) < 0) + goto finally; + + if (self->write_func(self, "\n", 1) < 0) + goto finally; + + if (self->write_func(self, name_str, name_size) < 0) + goto finally; + + if (self->write_func(self, "\n", 1) < 0) + goto finally; + + if (put(self, args) < 0) + goto finally; + + res = 0; + + finally: + Py_XDECREF(module); + Py_XDECREF(global_name); + Py_XDECREF(mod); + + return res; +} + +static int +save_pers(Picklerobject *self, PyObject *args, PyObject *f) +{ + PyObject *pid = 0; + int size, res = -1; + + static char persid = PERSID, binpersid = BINPERSID; + + Py_INCREF(args); + ARG_TUP(self, args); + if (self->arg) { + pid = PyObject_Call(f, self->arg, NULL); + FREE_ARG_TUP(self); + } + if (! pid) return -1; + + if (pid != Py_None) { + if (!self->bin) { + if (!PyString_Check(pid)) { + PyErr_SetString(PicklingError, + "persistent id must be string"); + goto finally; + } + + if (self->write_func(self, &persid, 1) < 0) + goto finally; + + if ((size = PyString_Size(pid)) < 0) + goto finally; + + if (self->write_func(self, + PyString_AS_STRING( + (PyStringObject *)pid), + size) < 0) + goto finally; + + if (self->write_func(self, "\n", 1) < 0) + goto finally; + + res = 1; + goto finally; + } + else if (save(self, pid, 1) >= 0) { + if (self->write_func(self, &binpersid, 1) < 0) + res = -1; + else + res = 1; + } + + goto finally; + } + + res = 0; + + finally: + Py_XDECREF(pid); + + return res; +} + +/* We're saving ob, and args is the 2-thru-5 tuple returned by the + * appropriate __reduce__ method for ob. + */ +static int +save_reduce(Picklerobject *self, PyObject *args, PyObject *ob) +{ + PyObject *callable; + PyObject *argtup; + PyObject *state = NULL; + PyObject *listitems = NULL; + PyObject *dictitems = NULL; + + int use_newobj = self->proto >= 2; + + static char reduce = REDUCE; + static char build = BUILD; + static char newobj = NEWOBJ; + + if (! PyArg_UnpackTuple(args, "save_reduce", 2, 5, + &callable, + &argtup, + &state, + &listitems, + &dictitems)) + return -1; + + if (!PyTuple_Check(argtup)) { + PyErr_SetString(PicklingError, + "args from reduce() should be a tuple"); + return -1; + } + + if (state == Py_None) + state = NULL; + if (listitems == Py_None) + listitems = NULL; + if (dictitems == Py_None) + dictitems = NULL; + + /* Protocol 2 special case: if callable's name is __newobj__, use + * NEWOBJ. This consumes a lot of code. + */ + if (use_newobj) { + PyObject *temp = PyObject_GetAttr(callable, __name___str); + + if (temp == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + return -1; + use_newobj = 0; + } + else { + use_newobj = PyString_Check(temp) && + strcmp(PyString_AS_STRING(temp), + "__newobj__") == 0; + Py_DECREF(temp); + } + } + if (use_newobj) { + PyObject *cls; + PyObject *newargtup; + int n, i; + + /* Sanity checks. */ + n = PyTuple_Size(argtup); + if (n < 1) { + PyErr_SetString(PicklingError, "__newobj__ arglist " + "is empty"); + return -1; + } + + cls = PyTuple_GET_ITEM(argtup, 0); + if (! PyObject_HasAttrString(cls, "__new__")) { + PyErr_SetString(PicklingError, "args[0] from " + "__newobj__ args has no __new__"); + return -1; + } + + /* XXX How could ob be NULL? */ + if (ob != NULL) { + PyObject *ob_dot_class; + + ob_dot_class = PyObject_GetAttr(ob, __class___str); + if (ob_dot_class == NULL) { + if (PyErr_ExceptionMatches( + PyExc_AttributeError)) + PyErr_Clear(); + else + return -1; + } + i = ob_dot_class != cls; /* true iff a problem */ + Py_XDECREF(ob_dot_class); + if (i) { + PyErr_SetString(PicklingError, "args[0] from " + "__newobj__ args has the wrong class"); + return -1; + } + } + + /* Save the class and its __new__ arguments. */ + if (save(self, cls, 0) < 0) + return -1; + + newargtup = PyTuple_New(n-1); /* argtup[1:] */ + if (newargtup == NULL) + return -1; + for (i = 1; i < n; ++i) { + PyObject *temp = PyTuple_GET_ITEM(argtup, i); + Py_INCREF(temp); + PyTuple_SET_ITEM(newargtup, i-1, temp); + } + i = save(self, newargtup, 0) < 0; + Py_DECREF(newargtup); + if (i < 0) + return -1; + + /* Add NEWOBJ opcode. */ + if (self->write_func(self, &newobj, 1) < 0) + return -1; + } + else { + /* Not using NEWOBJ. */ + if (save(self, callable, 0) < 0 || + save(self, argtup, 0) < 0 || + self->write_func(self, &reduce, 1) < 0) + return -1; + } + + /* Memoize. */ + /* XXX How can ob be NULL? */ + if (ob != NULL) { + if (state && !PyDict_Check(state)) { + if (put2(self, ob) < 0) + return -1; + } + else if (put(self, ob) < 0) + return -1; + } + + + if (listitems && batch_list(self, listitems) < 0) + return -1; + + if (dictitems && batch_dict(self, dictitems) < 0) + return -1; + + if (state) { + if (save(self, state, 0) < 0 || + self->write_func(self, &build, 1) < 0) + return -1; + } + + return 0; +} + +static int +save(Picklerobject *self, PyObject *args, int pers_save) +{ + PyTypeObject *type; + PyObject *py_ob_id = 0, *__reduce__ = 0, *t = 0; + PyObject *arg_tup; + int res = -1; + int tmp, size; + + if (self->nesting++ > Py_GetRecursionLimit()){ + PyErr_SetString(PyExc_RuntimeError, + "maximum recursion depth exceeded"); + goto finally; + } + + if (!pers_save && self->pers_func) { + if ((tmp = save_pers(self, args, self->pers_func)) != 0) { + res = tmp; + goto finally; + } + } + + if (args == Py_None) { + res = save_none(self, args); + goto finally; + } + + type = args->ob_type; + + switch (type->tp_name[0]) { + case 'b': + if (args == Py_False || args == Py_True) { + res = save_bool(self, args); + goto finally; + } + break; + case 'i': + if (type == &PyInt_Type) { + res = save_int(self, args); + goto finally; + } + break; + + case 'l': + if (type == &PyLong_Type) { + res = save_long(self, args); + goto finally; + } + break; + + case 'f': + if (type == &PyFloat_Type) { + res = save_float(self, args); + goto finally; + } + break; + + case 't': + if (type == &PyTuple_Type && PyTuple_Size(args) == 0) { + res = save_tuple(self, args); + goto finally; + } + break; + + case 's': + if ((type == &PyString_Type) && (PyString_GET_SIZE(args) < 2)) { + res = save_string(self, args, 0); + goto finally; + } + +#ifdef Py_USING_UNICODE + case 'u': + if ((type == &PyUnicode_Type) && (PyString_GET_SIZE(args) < 2)) { + res = save_unicode(self, args, 0); + goto finally; + } +#endif + } + + if (args->ob_refcnt > 1) { + if (!( py_ob_id = PyLong_FromVoidPtr(args))) + goto finally; + + if (PyDict_GetItem(self->memo, py_ob_id)) { + if (get(self, py_ob_id) < 0) + goto finally; + + res = 0; + goto finally; + } + } + + switch (type->tp_name[0]) { + case 's': + if (type == &PyString_Type) { + res = save_string(self, args, 1); + goto finally; + } + break; + +#ifdef Py_USING_UNICODE + case 'u': + if (type == &PyUnicode_Type) { + res = save_unicode(self, args, 1); + goto finally; + } + break; +#endif + + case 't': + if (type == &PyTuple_Type) { + res = save_tuple(self, args); + goto finally; + } + if (type == &PyType_Type) { + res = save_global(self, args, NULL); + goto finally; + } + break; + + case 'l': + if (type == &PyList_Type) { + res = save_list(self, args); + goto finally; + } + break; + + case 'd': + if (type == &PyDict_Type) { + res = save_dict(self, args); + goto finally; + } + break; + + case 'i': + if (type == &PyInstance_Type) { + res = save_inst(self, args); + goto finally; + } + break; + + case 'c': + if (type == &PyClass_Type) { + res = save_global(self, args, NULL); + goto finally; + } + break; + + case 'f': + if (type == &PyFunction_Type) { + res = save_global(self, args, NULL); + if (res && PyErr_ExceptionMatches(PickleError)) { + /* fall back to reduce */ + PyErr_Clear(); + break; + } + goto finally; + } + break; + + case 'b': + if (type == &PyCFunction_Type) { + res = save_global(self, args, NULL); + goto finally; + } + } + + if (!pers_save && self->inst_pers_func) { + if ((tmp = save_pers(self, args, self->inst_pers_func)) != 0) { + res = tmp; + goto finally; + } + } + + if (PyType_IsSubtype(type, &PyType_Type)) { + res = save_global(self, args, NULL); + goto finally; + } + + /* Get a reduction callable, and call it. This may come from + * copy_reg.dispatch_table, the object's __reduce_ex__ method, + * or the object's __reduce__ method. + */ + __reduce__ = PyDict_GetItem(dispatch_table, (PyObject *)type); + if (__reduce__ != NULL) { + Py_INCREF(__reduce__); + Py_INCREF(args); + ARG_TUP(self, args); + if (self->arg) { + t = PyObject_Call(__reduce__, self->arg, NULL); + FREE_ARG_TUP(self); + } + } + else { + /* Check for a __reduce_ex__ method. */ + __reduce__ = PyObject_GetAttr(args, __reduce_ex___str); + if (__reduce__ != NULL) { + t = PyInt_FromLong(self->proto); + if (t != NULL) { + ARG_TUP(self, t); + t = NULL; + if (self->arg) { + t = PyObject_Call(__reduce__, + self->arg, NULL); + FREE_ARG_TUP(self); + } + } + } + else { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + goto finally; + /* Check for a __reduce__ method. */ + __reduce__ = PyObject_GetAttr(args, __reduce___str); + if (__reduce__ != NULL) { + t = PyObject_Call(__reduce__, + empty_tuple, NULL); + } + else { + PyErr_SetObject(UnpickleableError, args); + goto finally; + } + } + } + + if (t == NULL) + goto finally; + + if (PyString_Check(t)) { + res = save_global(self, args, t); + goto finally; + } + + if (! PyTuple_Check(t)) { + cPickle_ErrFormat(PicklingError, "Value returned by " + "%s must be string or tuple", + "O", __reduce__); + goto finally; + } + + size = PyTuple_Size(t); + if (size < 2 || size > 5) { + cPickle_ErrFormat(PicklingError, "tuple returned by " + "%s must contain 2 through 5 elements", + "O", __reduce__); + goto finally; + } + + arg_tup = PyTuple_GET_ITEM(t, 1); + if (!(PyTuple_Check(arg_tup) || arg_tup == Py_None)) { + cPickle_ErrFormat(PicklingError, "Second element of " + "tuple returned by %s must be a tuple", + "O", __reduce__); + goto finally; + } + + res = save_reduce(self, t, args); + + finally: + self->nesting--; + Py_XDECREF(py_ob_id); + Py_XDECREF(__reduce__); + Py_XDECREF(t); + + return res; +} + + +static int +dump(Picklerobject *self, PyObject *args) +{ + static char stop = STOP; + + if (self->proto >= 2) { + char bytes[2]; + + bytes[0] = PROTO; + assert(self->proto >= 0 && self->proto < 256); + bytes[1] = (char)self->proto; + if (self->write_func(self, bytes, 2) < 0) + return -1; + } + + if (save(self, args, 0) < 0) + return -1; + + if (self->write_func(self, &stop, 1) < 0) + return -1; + + if (self->write_func(self, NULL, 0) < 0) + return -1; + + return 0; +} + +static PyObject * +Pickle_clear_memo(Picklerobject *self, PyObject *args) +{ + if (self->memo) + PyDict_Clear(self->memo); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +Pickle_getvalue(Picklerobject *self, PyObject *args) +{ + int l, i, rsize, ssize, clear=1, lm; + long ik; + PyObject *k, *r; + char *s, *p, *have_get; + Pdata *data; + + /* Can be called by Python code or C code */ + if (args && !PyArg_ParseTuple(args, "|i:getvalue", &clear)) + return NULL; + + /* Check to make sure we are based on a list */ + if (! Pdata_Check(self->file)) { + PyErr_SetString(PicklingError, + "Attempt to getvalue() a non-list-based pickler"); + return NULL; + } + + /* flush write buffer */ + if (write_other(self, NULL, 0) < 0) return NULL; + + data=(Pdata*)self->file; + l=data->length; + + /* set up an array to hold get/put status */ + lm = PyDict_Size(self->memo); + if (lm < 0) return NULL; + lm++; + have_get = malloc(lm); + if (have_get == NULL) return PyErr_NoMemory(); + memset(have_get, 0, lm); + + /* Scan for gets. */ + for (rsize = 0, i = l; --i >= 0; ) { + k = data->data[i]; + + if (PyString_Check(k)) + rsize += PyString_GET_SIZE(k); + + else if (PyInt_Check(k)) { /* put */ + ik = PyInt_AS_LONG((PyIntObject*)k); + if (ik >= lm || ik == 0) { + PyErr_SetString(PicklingError, + "Invalid get data"); + goto err; + } + if (have_get[ik]) /* with matching get */ + rsize += ik < 256 ? 2 : 5; + } + + else if (! (PyTuple_Check(k) && + PyTuple_GET_SIZE(k) == 2 && + PyInt_Check((k = PyTuple_GET_ITEM(k, 0)))) + ) { + PyErr_SetString(PicklingError, + "Unexpected data in internal list"); + goto err; + } + + else { /* put */ + ik = PyInt_AS_LONG((PyIntObject *)k); + if (ik >= lm || ik == 0) { + PyErr_SetString(PicklingError, + "Invalid get data"); + return NULL; + } + have_get[ik] = 1; + rsize += ik < 256 ? 2 : 5; + } + } + + /* Now generate the result */ + r = PyString_FromStringAndSize(NULL, rsize); + if (r == NULL) goto err; + s = PyString_AS_STRING((PyStringObject *)r); + + for (i = 0; i < l; i++) { + k = data->data[i]; + + if (PyString_Check(k)) { + ssize = PyString_GET_SIZE(k); + if (ssize) { + p=PyString_AS_STRING((PyStringObject *)k); + while (--ssize >= 0) + *s++ = *p++; + } + } + + else if (PyTuple_Check(k)) { /* get */ + ik = PyInt_AS_LONG((PyIntObject *) + PyTuple_GET_ITEM(k, 0)); + if (ik < 256) { + *s++ = BINGET; + *s++ = (int)(ik & 0xff); + } + else { + *s++ = LONG_BINGET; + *s++ = (int)(ik & 0xff); + *s++ = (int)((ik >> 8) & 0xff); + *s++ = (int)((ik >> 16) & 0xff); + *s++ = (int)((ik >> 24) & 0xff); + } + } + + else { /* put */ + ik = PyInt_AS_LONG((PyIntObject*)k); + + if (have_get[ik]) { /* with matching get */ + if (ik < 256) { + *s++ = BINPUT; + *s++ = (int)(ik & 0xff); + } + else { + *s++ = LONG_BINPUT; + *s++ = (int)(ik & 0xff); + *s++ = (int)((ik >> 8) & 0xff); + *s++ = (int)((ik >> 16) & 0xff); + *s++ = (int)((ik >> 24) & 0xff); + } + } + } + } + + if (clear) { + PyDict_Clear(self->memo); + Pdata_clear(data, 0); + } + + free(have_get); + return r; + err: + free(have_get); + return NULL; +} + +static PyObject * +Pickler_dump(Picklerobject *self, PyObject *args) +{ + PyObject *ob; + int get=0; + + if (!( PyArg_ParseTuple(args, "O|i:dump", &ob, &get))) + return NULL; + + if (dump(self, ob) < 0) + return NULL; + + if (get) return Pickle_getvalue(self, NULL); + + /* XXX Why does dump() return self? */ + Py_INCREF(self); + return (PyObject*)self; +} + + +static struct PyMethodDef Pickler_methods[] = +{ + {"dump", (PyCFunction)Pickler_dump, METH_VARARGS, + PyDoc_STR("dump(object) -- " + "Write an object in pickle format to the object's pickle stream")}, + {"clear_memo", (PyCFunction)Pickle_clear_memo, METH_NOARGS, + PyDoc_STR("clear_memo() -- Clear the picklers memo")}, + {"getvalue", (PyCFunction)Pickle_getvalue, METH_VARARGS, + PyDoc_STR("getvalue() -- Finish picking a list-based pickle")}, + {NULL, NULL} /* sentinel */ +}; + + +static Picklerobject * +newPicklerobject(PyObject *file, int proto) +{ + Picklerobject *self; + + if (proto < 0) + proto = HIGHEST_PROTOCOL; + if (proto > HIGHEST_PROTOCOL) { + PyErr_Format(PyExc_ValueError, "pickle protocol %d asked for; " + "the highest available protocol is %d", + proto, HIGHEST_PROTOCOL); + return NULL; + } + + self = PyObject_GC_New(Picklerobject, &Picklertype); + if (self == NULL) + return NULL; + self->proto = proto; + self->bin = proto > 0; + self->fp = NULL; + self->write = NULL; + self->memo = NULL; + self->arg = NULL; + self->pers_func = NULL; + self->inst_pers_func = NULL; + self->write_buf = NULL; + self->fast = 0; + self->nesting = 0; + self->fast_container = 0; + self->fast_memo = NULL; + self->buf_size = 0; + self->dispatch_table = NULL; + + self->file = NULL; + if (file) + Py_INCREF(file); + else { + file = Pdata_New(); + if (file == NULL) + goto err; + } + self->file = file; + + if (!( self->memo = PyDict_New())) + goto err; + + if (PyFile_Check(file)) { + self->fp = PyFile_AsFile(file); + if (self->fp == NULL) { + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto err; + } + self->write_func = write_file; + } + else if (PycStringIO_OutputCheck(file)) { + self->write_func = write_cStringIO; + } + else if (file == Py_None) { + self->write_func = write_none; + } + else { + self->write_func = write_other; + + if (! Pdata_Check(file)) { + self->write = PyObject_GetAttr(file, write_str); + if (!self->write) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "argument must have 'write' " + "attribute"); + goto err; + } + } + + self->write_buf = (char *)PyMem_Malloc(WRITE_BUF_SIZE); + if (self->write_buf == NULL) { + PyErr_NoMemory(); + goto err; + } + } + + if (PyEval_GetRestricted()) { + /* Restricted execution, get private tables */ + PyObject *m = PyImport_Import(copy_reg_str); + + if (m == NULL) + goto err; + self->dispatch_table = PyObject_GetAttr(m, dispatch_table_str); + Py_DECREF(m); + if (self->dispatch_table == NULL) + goto err; + } + else { + self->dispatch_table = dispatch_table; + Py_INCREF(dispatch_table); + } + PyObject_GC_Track(self); + + return self; + + err: + Py_DECREF(self); + return NULL; +} + + +static PyObject * +get_Pickler(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"file", "protocol", NULL}; + PyObject *file = NULL; + int proto = 0; + + /* XXX + * The documented signature is Pickler(file, protocol=0), but this + * accepts Pickler() and Pickler(integer) too. The meaning then + * is clear as mud, undocumented, and not supported by pickle.py. + * I'm told Zope uses this, but I haven't traced into this code + * far enough to figure out what it means. + */ + if (!PyArg_ParseTuple(args, "|i:Pickler", &proto)) { + PyErr_Clear(); + proto = 0; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|i:Pickler", + kwlist, &file, &proto)) + return NULL; + } + return (PyObject *)newPicklerobject(file, proto); +} + + +static void +Pickler_dealloc(Picklerobject *self) +{ + PyObject_GC_UnTrack(self); + Py_XDECREF(self->write); + Py_XDECREF(self->memo); + Py_XDECREF(self->fast_memo); + Py_XDECREF(self->arg); + Py_XDECREF(self->file); + Py_XDECREF(self->pers_func); + Py_XDECREF(self->inst_pers_func); + Py_XDECREF(self->dispatch_table); + PyMem_Free(self->write_buf); + self->ob_type->tp_free((PyObject *)self); +} + +static int +Pickler_traverse(Picklerobject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->write); + Py_VISIT(self->memo); + Py_VISIT(self->fast_memo); + Py_VISIT(self->arg); + Py_VISIT(self->file); + Py_VISIT(self->pers_func); + Py_VISIT(self->inst_pers_func); + Py_VISIT(self->dispatch_table); + return 0; +} + +static int +Pickler_clear(Picklerobject *self) +{ + Py_CLEAR(self->write); + Py_CLEAR(self->memo); + Py_CLEAR(self->fast_memo); + Py_CLEAR(self->arg); + Py_CLEAR(self->file); + Py_CLEAR(self->pers_func); + Py_CLEAR(self->inst_pers_func); + Py_CLEAR(self->dispatch_table); + return 0; +} + +static PyObject * +Pickler_get_pers_func(Picklerobject *p) +{ + if (p->pers_func == NULL) + PyErr_SetString(PyExc_AttributeError, "persistent_id"); + else + Py_INCREF(p->pers_func); + return p->pers_func; +} + +static int +Pickler_set_pers_func(Picklerobject *p, PyObject *v) +{ + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "attribute deletion is not supported"); + return -1; + } + Py_XDECREF(p->pers_func); + Py_INCREF(v); + p->pers_func = v; + return 0; +} + +static int +Pickler_set_inst_pers_func(Picklerobject *p, PyObject *v) +{ + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "attribute deletion is not supported"); + return -1; + } + Py_XDECREF(p->inst_pers_func); + Py_INCREF(v); + p->inst_pers_func = v; + return 0; +} + +static PyObject * +Pickler_get_memo(Picklerobject *p) +{ + if (p->memo == NULL) + PyErr_SetString(PyExc_AttributeError, "memo"); + else + Py_INCREF(p->memo); + return p->memo; +} + +static int +Pickler_set_memo(Picklerobject *p, PyObject *v) +{ + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "attribute deletion is not supported"); + return -1; + } + if (!PyDict_Check(v)) { + PyErr_SetString(PyExc_TypeError, "memo must be a dictionary"); + return -1; + } + Py_XDECREF(p->memo); + Py_INCREF(v); + p->memo = v; + return 0; +} + +static PyObject * +Pickler_get_error(Picklerobject *p) +{ + /* why is this an attribute on the Pickler? */ + Py_INCREF(PicklingError); + return PicklingError; +} + +static PyMemberDef Pickler_members[] = { + {"binary", T_INT, offsetof(Picklerobject, bin)}, + {"fast", T_INT, offsetof(Picklerobject, fast)}, + {NULL} +}; + +static PyGetSetDef Pickler_getsets[] = { + {"persistent_id", (getter)Pickler_get_pers_func, + (setter)Pickler_set_pers_func}, + {"inst_persistent_id", NULL, (setter)Pickler_set_inst_pers_func}, + {"memo", (getter)Pickler_get_memo, (setter)Pickler_set_memo}, + {"PicklingError", (getter)Pickler_get_error, NULL}, + {NULL} +}; + +PyDoc_STRVAR(Picklertype__doc__, +"Objects that know how to pickle objects\n"); + +static PyTypeObject Picklertype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "cPickle.Pickler", /*tp_name*/ + sizeof(Picklerobject), /*tp_basicsize*/ + 0, + (destructor)Pickler_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + Picklertype__doc__, /* tp_doc */ + (traverseproc)Pickler_traverse, /* tp_traverse */ + (inquiry)Pickler_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Pickler_methods, /* tp_methods */ + Pickler_members, /* tp_members */ + Pickler_getsets, /* tp_getset */ +}; + +static PyObject * +find_class(PyObject *py_module_name, PyObject *py_global_name, PyObject *fc) +{ + PyObject *global = 0, *module; + + if (fc) { + if (fc==Py_None) { + PyErr_SetString(UnpicklingError, "Global and instance " + "pickles are not supported."); + return NULL; + } + return PyObject_CallFunctionObjArgs(fc, py_module_name, + py_global_name, NULL); + } + + module = PySys_GetObject("modules"); + if (module == NULL) + return NULL; + + module = PyDict_GetItem(module, py_module_name); + if (module == NULL) { + module = PyImport_Import(py_module_name); + if (!module) + return NULL; + global = PyObject_GetAttr(module, py_global_name); + Py_DECREF(module); + } + else + global = PyObject_GetAttr(module, py_global_name); + return global; +} + +static int +marker(Unpicklerobject *self) +{ + if (self->num_marks < 1) { + PyErr_SetString(UnpicklingError, "could not find MARK"); + return -1; + } + + return self->marks[--self->num_marks]; +} + + +static int +load_none(Unpicklerobject *self) +{ + PDATA_APPEND(self->stack, Py_None, -1); + return 0; +} + +static int +bad_readline(void) +{ + PyErr_SetString(UnpicklingError, "pickle data was truncated"); + return -1; +} + +static int +load_int(Unpicklerobject *self) +{ + PyObject *py_int = 0; + char *endptr, *s; + int len, res = -1; + long l; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + if (!( s=pystrndup(s,len))) return -1; + + errno = 0; + l = strtol(s, &endptr, 0); + + if (errno || (*endptr != '\n') || (endptr[1] != '\0')) { + /* Hm, maybe we've got something long. Let's try reading + it as a Python long object. */ + errno = 0; + py_int = PyLong_FromString(s, NULL, 0); + if (py_int == NULL) { + PyErr_SetString(PyExc_ValueError, + "could not convert string to int"); + goto finally; + } + } + else { + if (len == 3 && (l == 0 || l == 1)) { + if (!( py_int = PyBool_FromLong(l))) goto finally; + } + else { + if (!( py_int = PyInt_FromLong(l))) goto finally; + } + } + + free(s); + PDATA_PUSH(self->stack, py_int, -1); + return 0; + + finally: + free(s); + + return res; +} + +static int +load_bool(Unpicklerobject *self, PyObject *boolean) +{ + assert(boolean == Py_True || boolean == Py_False); + PDATA_APPEND(self->stack, boolean, -1); + return 0; +} + +/* s contains x bytes of a little-endian integer. Return its value as a + * C int. Obscure: when x is 1 or 2, this is an unsigned little-endian + * int, but when x is 4 it's a signed one. This is an historical source + * of x-platform bugs. + */ +static long +calc_binint(char *s, int x) +{ + unsigned char c; + int i; + long l; + + for (i = 0, l = 0L; i < x; i++) { + c = (unsigned char)s[i]; + l |= (long)c << (i * 8); + } +#if SIZEOF_LONG > 4 + /* Unlike BININT1 and BININT2, BININT (more accurately BININT4) + * is signed, so on a box with longs bigger than 4 bytes we need + * to extend a BININT's sign bit to the full width. + */ + if (x == 4 && l & (1L << 31)) + l |= (~0L) << 32; +#endif + return l; +} + + +static int +load_binintx(Unpicklerobject *self, char *s, int x) +{ + PyObject *py_int = 0; + long l; + + l = calc_binint(s, x); + + if (!( py_int = PyInt_FromLong(l))) + return -1; + + PDATA_PUSH(self->stack, py_int, -1); + return 0; +} + + +static int +load_binint(Unpicklerobject *self) +{ + char *s; + + if (self->read_func(self, &s, 4) < 0) + return -1; + + return load_binintx(self, s, 4); +} + + +static int +load_binint1(Unpicklerobject *self) +{ + char *s; + + if (self->read_func(self, &s, 1) < 0) + return -1; + + return load_binintx(self, s, 1); +} + + +static int +load_binint2(Unpicklerobject *self) +{ + char *s; + + if (self->read_func(self, &s, 2) < 0) + return -1; + + return load_binintx(self, s, 2); +} + +static int +load_long(Unpicklerobject *self) +{ + PyObject *l = 0; + char *end, *s; + int len, res = -1; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + if (!( s=pystrndup(s,len))) return -1; + + if (!( l = PyLong_FromString(s, &end, 0))) + goto finally; + + free(s); + PDATA_PUSH(self->stack, l, -1); + return 0; + + finally: + free(s); + + return res; +} + +/* 'size' bytes contain the # of bytes of little-endian 256's-complement + * data following. + */ +static int +load_counted_long(Unpicklerobject *self, int size) +{ + Py_ssize_t i; + char *nbytes; + unsigned char *pdata; + PyObject *along; + + assert(size == 1 || size == 4); + i = self->read_func(self, &nbytes, size); + if (i < 0) return -1; + + size = calc_binint(nbytes, size); + if (size < 0) { + /* Corrupt or hostile pickle -- we never write one like + * this. + */ + PyErr_SetString(UnpicklingError, "LONG pickle has negative " + "byte count"); + return -1; + } + + if (size == 0) + along = PyLong_FromLong(0L); + else { + /* Read the raw little-endian bytes & convert. */ + i = self->read_func(self, (char **)&pdata, size); + if (i < 0) return -1; + along = _PyLong_FromByteArray(pdata, (size_t)size, + 1 /* little endian */, 1 /* signed */); + } + if (along == NULL) + return -1; + PDATA_PUSH(self->stack, along, -1); + return 0; +} + +static int +load_float(Unpicklerobject *self) +{ + PyObject *py_float = 0; + char *endptr, *s; + int len, res = -1; + double d; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + if (!( s=pystrndup(s,len))) return -1; + + errno = 0; + d = PyOS_ascii_strtod(s, &endptr); + + if (errno || (endptr[0] != '\n') || (endptr[1] != '\0')) { + PyErr_SetString(PyExc_ValueError, + "could not convert string to float"); + goto finally; + } + + if (!( py_float = PyFloat_FromDouble(d))) + goto finally; + + free(s); + PDATA_PUSH(self->stack, py_float, -1); + return 0; + + finally: + free(s); + + return res; +} + +static int +load_binfloat(Unpicklerobject *self) +{ + PyObject *py_float; + double x; + char *p; + + if (self->read_func(self, &p, 8) < 0) + return -1; + + x = _PyFloat_Unpack8((unsigned char *)p, 0); + if (x == -1.0 && PyErr_Occurred()) + return -1; + + py_float = PyFloat_FromDouble(x); + if (py_float == NULL) + return -1; + + PDATA_PUSH(self->stack, py_float, -1); + return 0; +} + +static int +load_string(Unpicklerobject *self) +{ + PyObject *str = 0; + int len, res = -1; + char *s, *p; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + if (!( s=pystrndup(s,len))) return -1; + + + /* Strip outermost quotes */ + while (s[len-1] <= ' ') + len--; + if(s[0]=='"' && s[len-1]=='"'){ + s[len-1] = '\0'; + p = s + 1 ; + len -= 2; + } else if(s[0]=='\'' && s[len-1]=='\''){ + s[len-1] = '\0'; + p = s + 1 ; + len -= 2; + } else + goto insecure; + /********************************************/ + + str = PyString_DecodeEscape(p, len, NULL, 0, NULL); + free(s); + if (str) { + PDATA_PUSH(self->stack, str, -1); + res = 0; + } + return res; + + insecure: + free(s); + PyErr_SetString(PyExc_ValueError,"insecure string pickle"); + return -1; +} + + +static int +load_binstring(Unpicklerobject *self) +{ + PyObject *py_string = 0; + long l; + char *s; + + if (self->read_func(self, &s, 4) < 0) return -1; + + l = calc_binint(s, 4); + + if (self->read_func(self, &s, l) < 0) + return -1; + + if (!( py_string = PyString_FromStringAndSize(s, l))) + return -1; + + PDATA_PUSH(self->stack, py_string, -1); + return 0; +} + + +static int +load_short_binstring(Unpicklerobject *self) +{ + PyObject *py_string = 0; + unsigned char l; + char *s; + + if (self->read_func(self, &s, 1) < 0) + return -1; + + l = (unsigned char)s[0]; + + if (self->read_func(self, &s, l) < 0) return -1; + + if (!( py_string = PyString_FromStringAndSize(s, l))) return -1; + + PDATA_PUSH(self->stack, py_string, -1); + return 0; +} + + +#ifdef Py_USING_UNICODE +static int +load_unicode(Unpicklerobject *self) +{ + PyObject *str = 0; + int len, res = -1; + char *s; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 1) return bad_readline(); + + if (!( str = PyUnicode_DecodeRawUnicodeEscape(s, len - 1, NULL))) + goto finally; + + PDATA_PUSH(self->stack, str, -1); + return 0; + + finally: + return res; +} +#endif + + +#ifdef Py_USING_UNICODE +static int +load_binunicode(Unpicklerobject *self) +{ + PyObject *unicode; + long l; + char *s; + + if (self->read_func(self, &s, 4) < 0) return -1; + + l = calc_binint(s, 4); + + if (self->read_func(self, &s, l) < 0) + return -1; + + if (!( unicode = PyUnicode_DecodeUTF8(s, l, NULL))) + return -1; + + PDATA_PUSH(self->stack, unicode, -1); + return 0; +} +#endif + + +static int +load_tuple(Unpicklerobject *self) +{ + PyObject *tup; + int i; + + if ((i = marker(self)) < 0) return -1; + if (!( tup=Pdata_popTuple(self->stack, i))) return -1; + PDATA_PUSH(self->stack, tup, -1); + return 0; +} + +static int +load_counted_tuple(Unpicklerobject *self, int len) +{ + PyObject *tup = PyTuple_New(len); + + if (tup == NULL) + return -1; + + while (--len >= 0) { + PyObject *element; + + PDATA_POP(self->stack, element); + if (element == NULL) + return -1; + PyTuple_SET_ITEM(tup, len, element); + } + PDATA_PUSH(self->stack, tup, -1); + return 0; +} + +static int +load_empty_list(Unpicklerobject *self) +{ + PyObject *list; + + if (!( list=PyList_New(0))) return -1; + PDATA_PUSH(self->stack, list, -1); + return 0; +} + +static int +load_empty_dict(Unpicklerobject *self) +{ + PyObject *dict; + + if (!( dict=PyDict_New())) return -1; + PDATA_PUSH(self->stack, dict, -1); + return 0; +} + + +static int +load_list(Unpicklerobject *self) +{ + PyObject *list = 0; + int i; + + if ((i = marker(self)) < 0) return -1; + if (!( list=Pdata_popList(self->stack, i))) return -1; + PDATA_PUSH(self->stack, list, -1); + return 0; +} + +static int +load_dict(Unpicklerobject *self) +{ + PyObject *dict, *key, *value; + int i, j, k; + + if ((i = marker(self)) < 0) return -1; + j=self->stack->length; + + if (!( dict = PyDict_New())) return -1; + + for (k = i+1; k < j; k += 2) { + key =self->stack->data[k-1]; + value=self->stack->data[k ]; + if (PyDict_SetItem(dict, key, value) < 0) { + Py_DECREF(dict); + return -1; + } + } + Pdata_clear(self->stack, i); + PDATA_PUSH(self->stack, dict, -1); + return 0; +} + +static PyObject * +Instance_New(PyObject *cls, PyObject *args) +{ + PyObject *r = 0; + + if (PyClass_Check(cls)) { + int l; + + if ((l=PyObject_Size(args)) < 0) goto err; + if (!( l )) { + PyObject *__getinitargs__; + + __getinitargs__ = PyObject_GetAttr(cls, + __getinitargs___str); + if (!__getinitargs__) { + /* We have a class with no __getinitargs__, + so bypass usual construction */ + PyObject *inst; + + PyErr_Clear(); + if (!( inst=PyInstance_NewRaw(cls, NULL))) + goto err; + return inst; + } + Py_DECREF(__getinitargs__); + } + + if ((r=PyInstance_New(cls, args, NULL))) return r; + else goto err; + } + + if ((r=PyObject_CallObject(cls, args))) return r; + + err: + { + PyObject *tp, *v, *tb, *tmp_value; + + PyErr_Fetch(&tp, &v, &tb); + tmp_value = v; + /* NULL occurs when there was a KeyboardInterrupt */ + if (tmp_value == NULL) + tmp_value = Py_None; + if ((r = PyTuple_Pack(3, tmp_value, cls, args))) { + Py_XDECREF(v); + v=r; + } + PyErr_Restore(tp,v,tb); + } + return NULL; +} + + +static int +load_obj(Unpicklerobject *self) +{ + PyObject *class, *tup, *obj=0; + int i; + + if ((i = marker(self)) < 0) return -1; + if (!( tup=Pdata_popTuple(self->stack, i+1))) return -1; + PDATA_POP(self->stack, class); + if (class) { + obj = Instance_New(class, tup); + Py_DECREF(class); + } + Py_DECREF(tup); + + if (! obj) return -1; + PDATA_PUSH(self->stack, obj, -1); + return 0; +} + + +static int +load_inst(Unpicklerobject *self) +{ + PyObject *tup, *class=0, *obj=0, *module_name, *class_name; + int i, len; + char *s; + + if ((i = marker(self)) < 0) return -1; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + module_name = PyString_FromStringAndSize(s, len - 1); + if (!module_name) return -1; + + if ((len = self->readline_func(self, &s)) >= 0) { + if (len < 2) return bad_readline(); + if ((class_name = PyString_FromStringAndSize(s, len - 1))) { + class = find_class(module_name, class_name, + self->find_class); + Py_DECREF(class_name); + } + } + Py_DECREF(module_name); + + if (! class) return -1; + + if ((tup=Pdata_popTuple(self->stack, i))) { + obj = Instance_New(class, tup); + Py_DECREF(tup); + } + Py_DECREF(class); + + if (! obj) return -1; + + PDATA_PUSH(self->stack, obj, -1); + return 0; +} + +static int +load_newobj(Unpicklerobject *self) +{ + PyObject *args = NULL; + PyObject *clsraw = NULL; + PyTypeObject *cls; /* clsraw cast to its true type */ + PyObject *obj; + + /* Stack is ... cls argtuple, and we want to call + * cls.__new__(cls, *argtuple). + */ + PDATA_POP(self->stack, args); + if (args == NULL) goto Fail; + if (! PyTuple_Check(args)) { + PyErr_SetString(UnpicklingError, "NEWOBJ expected an arg " + "tuple."); + goto Fail; + } + + PDATA_POP(self->stack, clsraw); + cls = (PyTypeObject *)clsraw; + if (cls == NULL) goto Fail; + if (! PyType_Check(cls)) { + PyErr_SetString(UnpicklingError, "NEWOBJ class argument " + "isn't a type object"); + goto Fail; + } + if (cls->tp_new == NULL) { + PyErr_SetString(UnpicklingError, "NEWOBJ class argument " + "has NULL tp_new"); + goto Fail; + } + + /* Call __new__. */ + obj = cls->tp_new(cls, args, NULL); + if (obj == NULL) goto Fail; + + Py_DECREF(args); + Py_DECREF(clsraw); + PDATA_PUSH(self->stack, obj, -1); + return 0; + + Fail: + Py_XDECREF(args); + Py_XDECREF(clsraw); + return -1; +} + +static int +load_global(Unpicklerobject *self) +{ + PyObject *class = 0, *module_name = 0, *class_name = 0; + int len; + char *s; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + module_name = PyString_FromStringAndSize(s, len - 1); + if (!module_name) return -1; + + if ((len = self->readline_func(self, &s)) >= 0) { + if (len < 2) { + Py_DECREF(module_name); + return bad_readline(); + } + if ((class_name = PyString_FromStringAndSize(s, len - 1))) { + class = find_class(module_name, class_name, + self->find_class); + Py_DECREF(class_name); + } + } + Py_DECREF(module_name); + + if (! class) return -1; + PDATA_PUSH(self->stack, class, -1); + return 0; +} + + +static int +load_persid(Unpicklerobject *self) +{ + PyObject *pid = 0; + int len; + char *s; + + if (self->pers_func) { + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + + pid = PyString_FromStringAndSize(s, len - 1); + if (!pid) return -1; + + if (PyList_Check(self->pers_func)) { + if (PyList_Append(self->pers_func, pid) < 0) { + Py_DECREF(pid); + return -1; + } + } + else { + ARG_TUP(self, pid); + if (self->arg) { + pid = PyObject_Call(self->pers_func, self->arg, + NULL); + FREE_ARG_TUP(self); + } + } + + if (! pid) return -1; + + PDATA_PUSH(self->stack, pid, -1); + return 0; + } + else { + PyErr_SetString(UnpicklingError, + "A load persistent id instruction was encountered,\n" + "but no persistent_load function was specified."); + return -1; + } +} + +static int +load_binpersid(Unpicklerobject *self) +{ + PyObject *pid = 0; + + if (self->pers_func) { + PDATA_POP(self->stack, pid); + if (! pid) return -1; + + if (PyList_Check(self->pers_func)) { + if (PyList_Append(self->pers_func, pid) < 0) { + Py_DECREF(pid); + return -1; + } + } + else { + ARG_TUP(self, pid); + if (self->arg) { + pid = PyObject_Call(self->pers_func, self->arg, + NULL); + FREE_ARG_TUP(self); + } + if (! pid) return -1; + } + + PDATA_PUSH(self->stack, pid, -1); + return 0; + } + else { + PyErr_SetString(UnpicklingError, + "A load persistent id instruction was encountered,\n" + "but no persistent_load function was specified."); + return -1; + } +} + + +static int +load_pop(Unpicklerobject *self) +{ + int len; + + if (!( (len=self->stack->length) > 0 )) return stackUnderflow(); + + /* Note that we split the (pickle.py) stack into two stacks, + an object stack and a mark stack. We have to be clever and + pop the right one. We do this by looking at the top of the + mark stack. + */ + + if ((self->num_marks > 0) && + (self->marks[self->num_marks - 1] == len)) + self->num_marks--; + else { + len--; + Py_DECREF(self->stack->data[len]); + self->stack->length=len; + } + + return 0; +} + + +static int +load_pop_mark(Unpicklerobject *self) +{ + int i; + + if ((i = marker(self)) < 0) + return -1; + + Pdata_clear(self->stack, i); + + return 0; +} + + +static int +load_dup(Unpicklerobject *self) +{ + PyObject *last; + int len; + + if ((len = self->stack->length) <= 0) return stackUnderflow(); + last=self->stack->data[len-1]; + Py_INCREF(last); + PDATA_PUSH(self->stack, last, -1); + return 0; +} + + +static int +load_get(Unpicklerobject *self) +{ + PyObject *py_str = 0, *value = 0; + int len; + char *s; + int rc; + + if ((len = self->readline_func(self, &s)) < 0) return -1; + if (len < 2) return bad_readline(); + + if (!( py_str = PyString_FromStringAndSize(s, len - 1))) return -1; + + value = PyDict_GetItem(self->memo, py_str); + if (! value) { + PyErr_SetObject(BadPickleGet, py_str); + rc = -1; + } + else { + PDATA_APPEND(self->stack, value, -1); + rc = 0; + } + + Py_DECREF(py_str); + return rc; +} + + +static int +load_binget(Unpicklerobject *self) +{ + PyObject *py_key = 0, *value = 0; + unsigned char key; + char *s; + int rc; + + if (self->read_func(self, &s, 1) < 0) return -1; + + key = (unsigned char)s[0]; + if (!( py_key = PyInt_FromLong((long)key))) return -1; + + value = PyDict_GetItem(self->memo, py_key); + if (! value) { + PyErr_SetObject(BadPickleGet, py_key); + rc = -1; + } + else { + PDATA_APPEND(self->stack, value, -1); + rc = 0; + } + + Py_DECREF(py_key); + return rc; +} + + +static int +load_long_binget(Unpicklerobject *self) +{ + PyObject *py_key = 0, *value = 0; + unsigned char c; + char *s; + long key; + int rc; + + if (self->read_func(self, &s, 4) < 0) return -1; + + c = (unsigned char)s[0]; + key = (long)c; + c = (unsigned char)s[1]; + key |= (long)c << 8; + c = (unsigned char)s[2]; + key |= (long)c << 16; + c = (unsigned char)s[3]; + key |= (long)c << 24; + + if (!( py_key = PyInt_FromLong((long)key))) return -1; + + value = PyDict_GetItem(self->memo, py_key); + if (! value) { + PyErr_SetObject(BadPickleGet, py_key); + rc = -1; + } + else { + PDATA_APPEND(self->stack, value, -1); + rc = 0; + } + + Py_DECREF(py_key); + return rc; +} + +/* Push an object from the extension registry (EXT[124]). nbytes is + * the number of bytes following the opcode, holding the index (code) value. + */ +static int +load_extension(Unpicklerobject *self, int nbytes) +{ + char *codebytes; /* the nbytes bytes after the opcode */ + long code; /* calc_binint returns long */ + PyObject *py_code; /* code as a Python int */ + PyObject *obj; /* the object to push */ + PyObject *pair; /* (module_name, class_name) */ + PyObject *module_name, *class_name; + + assert(nbytes == 1 || nbytes == 2 || nbytes == 4); + if (self->read_func(self, &codebytes, nbytes) < 0) return -1; + code = calc_binint(codebytes, nbytes); + if (code <= 0) { /* note that 0 is forbidden */ + /* Corrupt or hostile pickle. */ + PyErr_SetString(UnpicklingError, "EXT specifies code <= 0"); + return -1; + } + + /* Look for the code in the cache. */ + py_code = PyInt_FromLong(code); + if (py_code == NULL) return -1; + obj = PyDict_GetItem(extension_cache, py_code); + if (obj != NULL) { + /* Bingo. */ + Py_DECREF(py_code); + PDATA_APPEND(self->stack, obj, -1); + return 0; + } + + /* Look up the (module_name, class_name) pair. */ + pair = PyDict_GetItem(inverted_registry, py_code); + if (pair == NULL) { + Py_DECREF(py_code); + PyErr_Format(PyExc_ValueError, "unregistered extension " + "code %ld", code); + return -1; + } + /* Since the extension registry is manipulable via Python code, + * confirm that pair is really a 2-tuple of strings. + */ + if (!PyTuple_Check(pair) || PyTuple_Size(pair) != 2 || + !PyString_Check(module_name = PyTuple_GET_ITEM(pair, 0)) || + !PyString_Check(class_name = PyTuple_GET_ITEM(pair, 1))) { + Py_DECREF(py_code); + PyErr_Format(PyExc_ValueError, "_inverted_registry[%ld] " + "isn't a 2-tuple of strings", code); + return -1; + } + /* Load the object. */ + obj = find_class(module_name, class_name, self->find_class); + if (obj == NULL) { + Py_DECREF(py_code); + return -1; + } + /* Cache code -> obj. */ + code = PyDict_SetItem(extension_cache, py_code, obj); + Py_DECREF(py_code); + if (code < 0) { + Py_DECREF(obj); + return -1; + } + PDATA_PUSH(self->stack, obj, -1); + return 0; +} + +static int +load_put(Unpicklerobject *self) +{ + PyObject *py_str = 0, *value = 0; + int len, l; + char *s; + + if ((l = self->readline_func(self, &s)) < 0) return -1; + if (l < 2) return bad_readline(); + if (!( len=self->stack->length )) return stackUnderflow(); + if (!( py_str = PyString_FromStringAndSize(s, l - 1))) return -1; + value=self->stack->data[len-1]; + l=PyDict_SetItem(self->memo, py_str, value); + Py_DECREF(py_str); + return l; +} + + +static int +load_binput(Unpicklerobject *self) +{ + PyObject *py_key = 0, *value = 0; + unsigned char key; + char *s; + int len; + + if (self->read_func(self, &s, 1) < 0) return -1; + if (!( (len=self->stack->length) > 0 )) return stackUnderflow(); + + key = (unsigned char)s[0]; + + if (!( py_key = PyInt_FromLong((long)key))) return -1; + value=self->stack->data[len-1]; + len=PyDict_SetItem(self->memo, py_key, value); + Py_DECREF(py_key); + return len; +} + + +static int +load_long_binput(Unpicklerobject *self) +{ + PyObject *py_key = 0, *value = 0; + long key; + unsigned char c; + char *s; + int len; + + if (self->read_func(self, &s, 4) < 0) return -1; + if (!( len=self->stack->length )) return stackUnderflow(); + + c = (unsigned char)s[0]; + key = (long)c; + c = (unsigned char)s[1]; + key |= (long)c << 8; + c = (unsigned char)s[2]; + key |= (long)c << 16; + c = (unsigned char)s[3]; + key |= (long)c << 24; + + if (!( py_key = PyInt_FromLong(key))) return -1; + value=self->stack->data[len-1]; + len=PyDict_SetItem(self->memo, py_key, value); + Py_DECREF(py_key); + return len; +} + + +static int +do_append(Unpicklerobject *self, int x) +{ + PyObject *value = 0, *list = 0, *append_method = 0; + int len, i; + + len=self->stack->length; + if (!( len >= x && x > 0 )) return stackUnderflow(); + /* nothing to do */ + if (len==x) return 0; + + list=self->stack->data[x-1]; + + if (PyList_Check(list)) { + PyObject *slice; + int list_len; + + slice=Pdata_popList(self->stack, x); + if (! slice) return -1; + list_len = PyList_GET_SIZE(list); + i=PyList_SetSlice(list, list_len, list_len, slice); + Py_DECREF(slice); + return i; + } + else { + + if (!( append_method = PyObject_GetAttr(list, append_str))) + return -1; + + for (i = x; i < len; i++) { + PyObject *junk; + + value=self->stack->data[i]; + junk=0; + ARG_TUP(self, value); + if (self->arg) { + junk = PyObject_Call(append_method, self->arg, + NULL); + FREE_ARG_TUP(self); + } + if (! junk) { + Pdata_clear(self->stack, i+1); + self->stack->length=x; + Py_DECREF(append_method); + return -1; + } + Py_DECREF(junk); + } + self->stack->length=x; + Py_DECREF(append_method); + } + + return 0; +} + + +static int +load_append(Unpicklerobject *self) +{ + return do_append(self, self->stack->length - 1); +} + + +static int +load_appends(Unpicklerobject *self) +{ + return do_append(self, marker(self)); +} + + +static int +do_setitems(Unpicklerobject *self, int x) +{ + PyObject *value = 0, *key = 0, *dict = 0; + int len, i, r=0; + + if (!( (len=self->stack->length) >= x + && x > 0 )) return stackUnderflow(); + + dict=self->stack->data[x-1]; + + for (i = x+1; i < len; i += 2) { + key =self->stack->data[i-1]; + value=self->stack->data[i ]; + if (PyObject_SetItem(dict, key, value) < 0) { + r=-1; + break; + } + } + + Pdata_clear(self->stack, x); + + return r; +} + + +static int +load_setitem(Unpicklerobject *self) +{ + return do_setitems(self, self->stack->length - 2); +} + +static int +load_setitems(Unpicklerobject *self) +{ + return do_setitems(self, marker(self)); +} + + +static int +load_build(Unpicklerobject *self) +{ + PyObject *state, *inst, *slotstate; + PyObject *__setstate__; + PyObject *d_key, *d_value; + Py_ssize_t i; + int res = -1; + + /* Stack is ... instance, state. We want to leave instance at + * the stack top, possibly mutated via instance.__setstate__(state). + */ + if (self->stack->length < 2) + return stackUnderflow(); + PDATA_POP(self->stack, state); + if (state == NULL) + return -1; + inst = self->stack->data[self->stack->length - 1]; + + __setstate__ = PyObject_GetAttr(inst, __setstate___str); + if (__setstate__ != NULL) { + PyObject *junk = NULL; + + /* The explicit __setstate__ is responsible for everything. */ + ARG_TUP(self, state); + if (self->arg) { + junk = PyObject_Call(__setstate__, self->arg, NULL); + FREE_ARG_TUP(self); + } + Py_DECREF(__setstate__); + if (junk == NULL) + return -1; + Py_DECREF(junk); + return 0; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + + /* A default __setstate__. First see whether state embeds a + * slot state dict too (a proto 2 addition). + */ + if (PyTuple_Check(state) && PyTuple_Size(state) == 2) { + PyObject *temp = state; + state = PyTuple_GET_ITEM(temp, 0); + slotstate = PyTuple_GET_ITEM(temp, 1); + Py_INCREF(state); + Py_INCREF(slotstate); + Py_DECREF(temp); + } + else + slotstate = NULL; + + /* Set inst.__dict__ from the state dict (if any). */ + if (state != Py_None) { + PyObject *dict; + if (! PyDict_Check(state)) { + PyErr_SetString(UnpicklingError, "state is not a " + "dictionary"); + goto finally; + } + dict = PyObject_GetAttr(inst, __dict___str); + if (dict == NULL) + goto finally; + + i = 0; + while (PyDict_Next(state, &i, &d_key, &d_value)) { + if (PyObject_SetItem(dict, d_key, d_value) < 0) + goto finally; + } + Py_DECREF(dict); + } + + /* Also set instance attributes from the slotstate dict (if any). */ + if (slotstate != NULL) { + if (! PyDict_Check(slotstate)) { + PyErr_SetString(UnpicklingError, "slot state is not " + "a dictionary"); + goto finally; + } + i = 0; + while (PyDict_Next(slotstate, &i, &d_key, &d_value)) { + if (PyObject_SetAttr(inst, d_key, d_value) < 0) + goto finally; + } + } + res = 0; + + finally: + Py_DECREF(state); + Py_XDECREF(slotstate); + return res; +} + + +static int +load_mark(Unpicklerobject *self) +{ + int s; + + /* Note that we split the (pickle.py) stack into two stacks, an + object stack and a mark stack. Here we push a mark onto the + mark stack. + */ + + if ((self->num_marks + 1) >= self->marks_size) { + s=self->marks_size+20; + if (s <= self->num_marks) s=self->num_marks + 1; + if (self->marks == NULL) + self->marks=(int *)malloc(s * sizeof(int)); + else + self->marks=(int *)realloc(self->marks, + s * sizeof(int)); + if (! self->marks) { + PyErr_NoMemory(); + return -1; + } + self->marks_size = s; + } + + self->marks[self->num_marks++] = self->stack->length; + + return 0; +} + +static int +load_reduce(Unpicklerobject *self) +{ + PyObject *callable = 0, *arg_tup = 0, *ob = 0; + + PDATA_POP(self->stack, arg_tup); + if (! arg_tup) return -1; + PDATA_POP(self->stack, callable); + if (callable) { + ob = Instance_New(callable, arg_tup); + Py_DECREF(callable); + } + Py_DECREF(arg_tup); + + if (! ob) return -1; + + PDATA_PUSH(self->stack, ob, -1); + return 0; +} + +/* Just raises an error if we don't know the protocol specified. PROTO + * is the first opcode for protocols >= 2. + */ +static int +load_proto(Unpicklerobject *self) +{ + int i; + char *protobyte; + + i = self->read_func(self, &protobyte, 1); + if (i < 0) + return -1; + + i = calc_binint(protobyte, 1); + /* No point checking for < 0, since calc_binint returns an unsigned + * int when chewing on 1 byte. + */ + assert(i >= 0); + if (i <= HIGHEST_PROTOCOL) + return 0; + + PyErr_Format(PyExc_ValueError, "unsupported pickle protocol: %d", i); + return -1; +} + +static PyObject * +load(Unpicklerobject *self) +{ + PyObject *err = 0, *val = 0; + char *s; + + self->num_marks = 0; + if (self->stack->length) Pdata_clear(self->stack, 0); + + while (1) { + if (self->read_func(self, &s, 1) < 0) + break; + + switch (s[0]) { + case NONE: + if (load_none(self) < 0) + break; + continue; + + case BININT: + if (load_binint(self) < 0) + break; + continue; + + case BININT1: + if (load_binint1(self) < 0) + break; + continue; + + case BININT2: + if (load_binint2(self) < 0) + break; + continue; + + case INT: + if (load_int(self) < 0) + break; + continue; + + case LONG: + if (load_long(self) < 0) + break; + continue; + + case LONG1: + if (load_counted_long(self, 1) < 0) + break; + continue; + + case LONG4: + if (load_counted_long(self, 4) < 0) + break; + continue; + + case FLOAT: + if (load_float(self) < 0) + break; + continue; + + case BINFLOAT: + if (load_binfloat(self) < 0) + break; + continue; + + case BINSTRING: + if (load_binstring(self) < 0) + break; + continue; + + case SHORT_BINSTRING: + if (load_short_binstring(self) < 0) + break; + continue; + + case STRING: + if (load_string(self) < 0) + break; + continue; + +#ifdef Py_USING_UNICODE + case UNICODE: + if (load_unicode(self) < 0) + break; + continue; + + case BINUNICODE: + if (load_binunicode(self) < 0) + break; + continue; +#endif + + case EMPTY_TUPLE: + if (load_counted_tuple(self, 0) < 0) + break; + continue; + + case TUPLE1: + if (load_counted_tuple(self, 1) < 0) + break; + continue; + + case TUPLE2: + if (load_counted_tuple(self, 2) < 0) + break; + continue; + + case TUPLE3: + if (load_counted_tuple(self, 3) < 0) + break; + continue; + + case TUPLE: + if (load_tuple(self) < 0) + break; + continue; + + case EMPTY_LIST: + if (load_empty_list(self) < 0) + break; + continue; + + case LIST: + if (load_list(self) < 0) + break; + continue; + + case EMPTY_DICT: + if (load_empty_dict(self) < 0) + break; + continue; + + case DICT: + if (load_dict(self) < 0) + break; + continue; + + case OBJ: + if (load_obj(self) < 0) + break; + continue; + + case INST: + if (load_inst(self) < 0) + break; + continue; + + case NEWOBJ: + if (load_newobj(self) < 0) + break; + continue; + + case GLOBAL: + if (load_global(self) < 0) + break; + continue; + + case APPEND: + if (load_append(self) < 0) + break; + continue; + + case APPENDS: + if (load_appends(self) < 0) + break; + continue; + + case BUILD: + if (load_build(self) < 0) + break; + continue; + + case DUP: + if (load_dup(self) < 0) + break; + continue; + + case BINGET: + if (load_binget(self) < 0) + break; + continue; + + case LONG_BINGET: + if (load_long_binget(self) < 0) + break; + continue; + + case GET: + if (load_get(self) < 0) + break; + continue; + + case EXT1: + if (load_extension(self, 1) < 0) + break; + continue; + + case EXT2: + if (load_extension(self, 2) < 0) + break; + continue; + + case EXT4: + if (load_extension(self, 4) < 0) + break; + continue; + case MARK: + if (load_mark(self) < 0) + break; + continue; + + case BINPUT: + if (load_binput(self) < 0) + break; + continue; + + case LONG_BINPUT: + if (load_long_binput(self) < 0) + break; + continue; + + case PUT: + if (load_put(self) < 0) + break; + continue; + + case POP: + if (load_pop(self) < 0) + break; + continue; + + case POP_MARK: + if (load_pop_mark(self) < 0) + break; + continue; + + case SETITEM: + if (load_setitem(self) < 0) + break; + continue; + + case SETITEMS: + if (load_setitems(self) < 0) + break; + continue; + + case STOP: + break; + + case PERSID: + if (load_persid(self) < 0) + break; + continue; + + case BINPERSID: + if (load_binpersid(self) < 0) + break; + continue; + + case REDUCE: + if (load_reduce(self) < 0) + break; + continue; + + case PROTO: + if (load_proto(self) < 0) + break; + continue; + + case NEWTRUE: + if (load_bool(self, Py_True) < 0) + break; + continue; + + case NEWFALSE: + if (load_bool(self, Py_False) < 0) + break; + continue; + + case '\0': + /* end of file */ + PyErr_SetNone(PyExc_EOFError); + break; + + default: + cPickle_ErrFormat(UnpicklingError, + "invalid load key, '%s'.", + "c", s[0]); + return NULL; + } + + break; + } + + if ((err = PyErr_Occurred())) { + if (err == PyExc_EOFError) { + PyErr_SetNone(PyExc_EOFError); + } + return NULL; + } + + PDATA_POP(self->stack, val); + return val; +} + + +/* No-load functions to support noload, which is used to + find persistent references. */ + +static int +noload_obj(Unpicklerobject *self) +{ + int i; + + if ((i = marker(self)) < 0) return -1; + return Pdata_clear(self->stack, i+1); +} + + +static int +noload_inst(Unpicklerobject *self) +{ + int i; + char *s; + + if ((i = marker(self)) < 0) return -1; + Pdata_clear(self->stack, i); + if (self->readline_func(self, &s) < 0) return -1; + if (self->readline_func(self, &s) < 0) return -1; + PDATA_APPEND(self->stack, Py_None, -1); + return 0; +} + +static int +noload_newobj(Unpicklerobject *self) +{ + PyObject *obj; + + PDATA_POP(self->stack, obj); /* pop argtuple */ + if (obj == NULL) return -1; + Py_DECREF(obj); + + PDATA_POP(self->stack, obj); /* pop cls */ + if (obj == NULL) return -1; + Py_DECREF(obj); + + PDATA_APPEND(self->stack, Py_None, -1); + return 0; +} + +static int +noload_global(Unpicklerobject *self) +{ + char *s; + + if (self->readline_func(self, &s) < 0) return -1; + if (self->readline_func(self, &s) < 0) return -1; + PDATA_APPEND(self->stack, Py_None,-1); + return 0; +} + +static int +noload_reduce(Unpicklerobject *self) +{ + + if (self->stack->length < 2) return stackUnderflow(); + Pdata_clear(self->stack, self->stack->length-2); + PDATA_APPEND(self->stack, Py_None,-1); + return 0; +} + +static int +noload_build(Unpicklerobject *self) { + + if (self->stack->length < 1) return stackUnderflow(); + Pdata_clear(self->stack, self->stack->length-1); + return 0; +} + +static int +noload_extension(Unpicklerobject *self, int nbytes) +{ + char *codebytes; + + assert(nbytes == 1 || nbytes == 2 || nbytes == 4); + if (self->read_func(self, &codebytes, nbytes) < 0) return -1; + PDATA_APPEND(self->stack, Py_None, -1); + return 0; +} + + +static PyObject * +noload(Unpicklerobject *self) +{ + PyObject *err = 0, *val = 0; + char *s; + + self->num_marks = 0; + Pdata_clear(self->stack, 0); + + while (1) { + if (self->read_func(self, &s, 1) < 0) + break; + + switch (s[0]) { + case NONE: + if (load_none(self) < 0) + break; + continue; + + case BININT: + if (load_binint(self) < 0) + break; + continue; + + case BININT1: + if (load_binint1(self) < 0) + break; + continue; + + case BININT2: + if (load_binint2(self) < 0) + break; + continue; + + case INT: + if (load_int(self) < 0) + break; + continue; + + case LONG: + if (load_long(self) < 0) + break; + continue; + + case LONG1: + if (load_counted_long(self, 1) < 0) + break; + continue; + + case LONG4: + if (load_counted_long(self, 4) < 0) + break; + continue; + + case FLOAT: + if (load_float(self) < 0) + break; + continue; + + case BINFLOAT: + if (load_binfloat(self) < 0) + break; + continue; + + case BINSTRING: + if (load_binstring(self) < 0) + break; + continue; + + case SHORT_BINSTRING: + if (load_short_binstring(self) < 0) + break; + continue; + + case STRING: + if (load_string(self) < 0) + break; + continue; + +#ifdef Py_USING_UNICODE + case UNICODE: + if (load_unicode(self) < 0) + break; + continue; + + case BINUNICODE: + if (load_binunicode(self) < 0) + break; + continue; +#endif + + case EMPTY_TUPLE: + if (load_counted_tuple(self, 0) < 0) + break; + continue; + + case TUPLE1: + if (load_counted_tuple(self, 1) < 0) + break; + continue; + + case TUPLE2: + if (load_counted_tuple(self, 2) < 0) + break; + continue; + + case TUPLE3: + if (load_counted_tuple(self, 3) < 0) + break; + continue; + + case TUPLE: + if (load_tuple(self) < 0) + break; + continue; + + case EMPTY_LIST: + if (load_empty_list(self) < 0) + break; + continue; + + case LIST: + if (load_list(self) < 0) + break; + continue; + + case EMPTY_DICT: + if (load_empty_dict(self) < 0) + break; + continue; + + case DICT: + if (load_dict(self) < 0) + break; + continue; + + case OBJ: + if (noload_obj(self) < 0) + break; + continue; + + case INST: + if (noload_inst(self) < 0) + break; + continue; + + case NEWOBJ: + if (noload_newobj(self) < 0) + break; + continue; + + case GLOBAL: + if (noload_global(self) < 0) + break; + continue; + + case APPEND: + if (load_append(self) < 0) + break; + continue; + + case APPENDS: + if (load_appends(self) < 0) + break; + continue; + + case BUILD: + if (noload_build(self) < 0) + break; + continue; + + case DUP: + if (load_dup(self) < 0) + break; + continue; + + case BINGET: + if (load_binget(self) < 0) + break; + continue; + + case LONG_BINGET: + if (load_long_binget(self) < 0) + break; + continue; + + case GET: + if (load_get(self) < 0) + break; + continue; + + case EXT1: + if (noload_extension(self, 1) < 0) + break; + continue; + + case EXT2: + if (noload_extension(self, 2) < 0) + break; + continue; + + case EXT4: + if (noload_extension(self, 4) < 0) + break; + continue; + + case MARK: + if (load_mark(self) < 0) + break; + continue; + + case BINPUT: + if (load_binput(self) < 0) + break; + continue; + + case LONG_BINPUT: + if (load_long_binput(self) < 0) + break; + continue; + + case PUT: + if (load_put(self) < 0) + break; + continue; + + case POP: + if (load_pop(self) < 0) + break; + continue; + + case POP_MARK: + if (load_pop_mark(self) < 0) + break; + continue; + + case SETITEM: + if (load_setitem(self) < 0) + break; + continue; + + case SETITEMS: + if (load_setitems(self) < 0) + break; + continue; + + case STOP: + break; + + case PERSID: + if (load_persid(self) < 0) + break; + continue; + + case BINPERSID: + if (load_binpersid(self) < 0) + break; + continue; + + case REDUCE: + if (noload_reduce(self) < 0) + break; + continue; + + case PROTO: + if (load_proto(self) < 0) + break; + continue; + + case NEWTRUE: + if (load_bool(self, Py_True) < 0) + break; + continue; + + case NEWFALSE: + if (load_bool(self, Py_False) < 0) + break; + continue; + default: + cPickle_ErrFormat(UnpicklingError, + "invalid load key, '%s'.", + "c", s[0]); + return NULL; + } + + break; + } + + if ((err = PyErr_Occurred())) { + if (err == PyExc_EOFError) { + PyErr_SetNone(PyExc_EOFError); + } + return NULL; + } + + PDATA_POP(self->stack, val); + return val; +} + + +static PyObject * +Unpickler_load(Unpicklerobject *self, PyObject *unused) +{ + return load(self); +} + +static PyObject * +Unpickler_noload(Unpicklerobject *self, PyObject *unused) +{ + return noload(self); +} + + +static struct PyMethodDef Unpickler_methods[] = { + {"load", (PyCFunction)Unpickler_load, METH_NOARGS, + PyDoc_STR("load() -- Load a pickle") + }, + {"noload", (PyCFunction)Unpickler_noload, METH_NOARGS, + PyDoc_STR( + "noload() -- not load a pickle, but go through most of the motions\n" + "\n" + "This function can be used to read past a pickle without instantiating\n" + "any objects or importing any modules. It can also be used to find all\n" + "persistent references without instantiating any objects or importing\n" + "any modules.\n") + }, + {NULL, NULL} /* sentinel */ +}; + + +static Unpicklerobject * +newUnpicklerobject(PyObject *f) +{ + Unpicklerobject *self; + + if (!( self = PyObject_GC_New(Unpicklerobject, &Unpicklertype))) + return NULL; + + self->file = NULL; + self->arg = NULL; + self->stack = (Pdata*)Pdata_New(); + self->pers_func = NULL; + self->last_string = NULL; + self->marks = NULL; + self->num_marks = 0; + self->marks_size = 0; + self->buf_size = 0; + self->read = NULL; + self->readline = NULL; + self->find_class = NULL; + + if (!( self->memo = PyDict_New())) + goto err; + + if (!self->stack) + goto err; + + Py_INCREF(f); + self->file = f; + + /* Set read, readline based on type of f */ + if (PyFile_Check(f)) { + self->fp = PyFile_AsFile(f); + if (self->fp == NULL) { + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + goto err; + } + self->read_func = read_file; + self->readline_func = readline_file; + } + else if (PycStringIO_InputCheck(f)) { + self->fp = NULL; + self->read_func = read_cStringIO; + self->readline_func = readline_cStringIO; + } + else { + + self->fp = NULL; + self->read_func = read_other; + self->readline_func = readline_other; + + if (!( (self->readline = PyObject_GetAttr(f, readline_str)) && + (self->read = PyObject_GetAttr(f, read_str)))) { + PyErr_Clear(); + PyErr_SetString( PyExc_TypeError, + "argument must have 'read' and " + "'readline' attributes" ); + goto err; + } + } + PyObject_GC_Track(self); + + return self; + + err: + Py_DECREF((PyObject *)self); + return NULL; +} + + +static PyObject * +get_Unpickler(PyObject *self, PyObject *file) +{ + return (PyObject *)newUnpicklerobject(file); +} + + +static void +Unpickler_dealloc(Unpicklerobject *self) +{ + PyObject_GC_UnTrack((PyObject *)self); + Py_XDECREF(self->readline); + Py_XDECREF(self->read); + Py_XDECREF(self->file); + Py_XDECREF(self->memo); + Py_XDECREF(self->stack); + Py_XDECREF(self->pers_func); + Py_XDECREF(self->arg); + Py_XDECREF(self->last_string); + Py_XDECREF(self->find_class); + + if (self->marks) { + free(self->marks); + } + + if (self->buf_size) { + free(self->buf); + } + + self->ob_type->tp_free((PyObject *)self); +} + +static int +Unpickler_traverse(Unpicklerobject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->readline); + Py_VISIT(self->read); + Py_VISIT(self->file); + Py_VISIT(self->memo); + Py_VISIT(self->stack); + Py_VISIT(self->pers_func); + Py_VISIT(self->arg); + Py_VISIT(self->last_string); + Py_VISIT(self->find_class); + return 0; +} + +static int +Unpickler_clear(Unpicklerobject *self) +{ + Py_CLEAR(self->readline); + Py_CLEAR(self->read); + Py_CLEAR(self->file); + Py_CLEAR(self->memo); + Py_CLEAR(self->stack); + Py_CLEAR(self->pers_func); + Py_CLEAR(self->arg); + Py_CLEAR(self->last_string); + Py_CLEAR(self->find_class); + return 0; +} + +static PyObject * +Unpickler_getattr(Unpicklerobject *self, char *name) +{ + if (!strcmp(name, "persistent_load")) { + if (!self->pers_func) { + PyErr_SetString(PyExc_AttributeError, name); + return NULL; + } + + Py_INCREF(self->pers_func); + return self->pers_func; + } + + if (!strcmp(name, "find_global")) { + if (!self->find_class) { + PyErr_SetString(PyExc_AttributeError, name); + return NULL; + } + + Py_INCREF(self->find_class); + return self->find_class; + } + + if (!strcmp(name, "memo")) { + if (!self->memo) { + PyErr_SetString(PyExc_AttributeError, name); + return NULL; + } + + Py_INCREF(self->memo); + return self->memo; + } + + if (!strcmp(name, "UnpicklingError")) { + Py_INCREF(UnpicklingError); + return UnpicklingError; + } + + return Py_FindMethod(Unpickler_methods, (PyObject *)self, name); +} + + +static int +Unpickler_setattr(Unpicklerobject *self, char *name, PyObject *value) +{ + + if (!strcmp(name, "persistent_load")) { + Py_XDECREF(self->pers_func); + self->pers_func = value; + Py_XINCREF(value); + return 0; + } + + if (!strcmp(name, "find_global")) { + Py_XDECREF(self->find_class); + self->find_class = value; + Py_XINCREF(value); + return 0; + } + + if (! value) { + PyErr_SetString(PyExc_TypeError, + "attribute deletion is not supported"); + return -1; + } + + if (strcmp(name, "memo") == 0) { + if (!PyDict_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "memo must be a dictionary"); + return -1; + } + Py_XDECREF(self->memo); + self->memo = value; + Py_INCREF(value); + return 0; + } + + PyErr_SetString(PyExc_AttributeError, name); + return -1; +} + +/* --------------------------------------------------------------------------- + * Module-level functions. + */ + +/* dump(obj, file, protocol=0). */ +static PyObject * +cpm_dump(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"obj", "file", "protocol", NULL}; + PyObject *ob, *file, *res = NULL; + Picklerobject *pickler = 0; + int proto = 0; + + if (!( PyArg_ParseTupleAndKeywords(args, kwds, "OO|i", kwlist, + &ob, &file, &proto))) + goto finally; + + if (!( pickler = newPicklerobject(file, proto))) + goto finally; + + if (dump(pickler, ob) < 0) + goto finally; + + Py_INCREF(Py_None); + res = Py_None; + + finally: + Py_XDECREF(pickler); + + return res; +} + + +/* dumps(obj, protocol=0). */ +static PyObject * +cpm_dumps(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"obj", "protocol", NULL}; + PyObject *ob, *file = 0, *res = NULL; + Picklerobject *pickler = 0; + int proto = 0; + + if (!( PyArg_ParseTupleAndKeywords(args, kwds, "O|i:dumps", kwlist, + &ob, &proto))) + goto finally; + + if (!( file = PycStringIO->NewOutput(128))) + goto finally; + + if (!( pickler = newPicklerobject(file, proto))) + goto finally; + + if (dump(pickler, ob) < 0) + goto finally; + + res = PycStringIO->cgetvalue(file); + + finally: + Py_XDECREF(pickler); + Py_XDECREF(file); + + return res; +} + + +/* load(fileobj). */ +static PyObject * +cpm_load(PyObject *self, PyObject *ob) +{ + Unpicklerobject *unpickler = 0; + PyObject *res = NULL; + + if (!( unpickler = newUnpicklerobject(ob))) + goto finally; + + res = load(unpickler); + + finally: + Py_XDECREF(unpickler); + + return res; +} + + +/* loads(string) */ +static PyObject * +cpm_loads(PyObject *self, PyObject *args) +{ + PyObject *ob, *file = 0, *res = NULL; + Unpicklerobject *unpickler = 0; + + if (!( PyArg_ParseTuple(args, "S:loads", &ob))) + goto finally; + + if (!( file = PycStringIO->NewInput(ob))) + goto finally; + + if (!( unpickler = newUnpicklerobject(file))) + goto finally; + + res = load(unpickler); + + finally: + Py_XDECREF(file); + Py_XDECREF(unpickler); + + return res; +} + + +PyDoc_STRVAR(Unpicklertype__doc__, +"Objects that know how to unpickle"); + +static PyTypeObject Unpicklertype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "cPickle.Unpickler", /*tp_name*/ + sizeof(Unpicklerobject), /*tp_basicsize*/ + 0, + (destructor)Unpickler_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc)Unpickler_getattr, /* tp_getattr */ + (setattrfunc)Unpickler_setattr, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + Unpicklertype__doc__, /* tp_doc */ + (traverseproc)Unpickler_traverse, /* tp_traverse */ + (inquiry)Unpickler_clear, /* tp_clear */ +}; + +static struct PyMethodDef cPickle_methods[] = { + {"dump", (PyCFunction)cpm_dump, METH_VARARGS | METH_KEYWORDS, + PyDoc_STR("dump(obj, file, protocol=0) -- " + "Write an object in pickle format to the given file.\n" + "\n" + "See the Pickler docstring for the meaning of optional argument proto.") + }, + + {"dumps", (PyCFunction)cpm_dumps, METH_VARARGS | METH_KEYWORDS, + PyDoc_STR("dumps(obj, protocol=0) -- " + "Return a string containing an object in pickle format.\n" + "\n" + "See the Pickler docstring for the meaning of optional argument proto.") + }, + + {"load", (PyCFunction)cpm_load, METH_O, + PyDoc_STR("load(file) -- Load a pickle from the given file")}, + + {"loads", (PyCFunction)cpm_loads, METH_VARARGS, + PyDoc_STR("loads(string) -- Load a pickle from the given string")}, + + {"Pickler", (PyCFunction)get_Pickler, METH_VARARGS | METH_KEYWORDS, + PyDoc_STR("Pickler(file, protocol=0) -- Create a pickler.\n" + "\n" + "This takes a file-like object for writing a pickle data stream.\n" + "The optional proto argument tells the pickler to use the given\n" + "protocol; supported protocols are 0, 1, 2. The default\n" + "protocol is 0, to be backwards compatible. (Protocol 0 is the\n" + "only protocol that can be written to a file opened in text\n" + "mode and read back successfully. When using a protocol higher\n" + "than 0, make sure the file is opened in binary mode, both when\n" + "pickling and unpickling.)\n" + "\n" + "Protocol 1 is more efficient than protocol 0; protocol 2 is\n" + "more efficient than protocol 1.\n" + "\n" + "Specifying a negative protocol version selects the highest\n" + "protocol version supported. The higher the protocol used, the\n" + "more recent the version of Python needed to read the pickle\n" + "produced.\n" + "\n" + "The file parameter must have a write() method that accepts a single\n" + "string argument. It can thus be an open file object, a StringIO\n" + "object, or any other custom object that meets this interface.\n") + }, + + {"Unpickler", (PyCFunction)get_Unpickler, METH_O, + PyDoc_STR("Unpickler(file) -- Create an unpickler.")}, + + { NULL, NULL } +}; + +static int +init_stuff(PyObject *module_dict) +{ + PyObject *copy_reg, *t, *r; + +#define INIT_STR(S) if (!( S ## _str=PyString_InternFromString(#S))) return -1; + + if (PyType_Ready(&Unpicklertype) < 0) + return -1; + if (PyType_Ready(&Picklertype) < 0) + return -1; + + INIT_STR(__class__); + INIT_STR(__getinitargs__); + INIT_STR(__dict__); + INIT_STR(__getstate__); + INIT_STR(__setstate__); + INIT_STR(__name__); + INIT_STR(__main__); + INIT_STR(__reduce__); + INIT_STR(__reduce_ex__); + INIT_STR(write); + INIT_STR(append); + INIT_STR(read); + INIT_STR(readline); + INIT_STR(copy_reg); + INIT_STR(dispatch_table); + + if (!( copy_reg = PyImport_ImportModule("copy_reg"))) + return -1; + + /* This is special because we want to use a different + one in restricted mode. */ + dispatch_table = PyObject_GetAttr(copy_reg, dispatch_table_str); + if (!dispatch_table) return -1; + + extension_registry = PyObject_GetAttrString(copy_reg, + "_extension_registry"); + if (!extension_registry) return -1; + + inverted_registry = PyObject_GetAttrString(copy_reg, + "_inverted_registry"); + if (!inverted_registry) return -1; + + extension_cache = PyObject_GetAttrString(copy_reg, + "_extension_cache"); + if (!extension_cache) return -1; + + Py_DECREF(copy_reg); + + if (!(empty_tuple = PyTuple_New(0))) + return -1; + + two_tuple = PyTuple_New(2); + if (two_tuple == NULL) + return -1; + /* We use this temp container with no regard to refcounts, or to + * keeping containees alive. Exempt from GC, because we don't + * want anything looking at two_tuple() by magic. + */ + PyObject_GC_UnTrack(two_tuple); + + /* Ugh */ + if (!( t=PyImport_ImportModule("__builtin__"))) return -1; + if (PyDict_SetItemString(module_dict, "__builtins__", t) < 0) + return -1; + + if (!( t=PyDict_New())) return -1; + if (!( r=PyRun_String( + "def __str__(self):\n" + " return self.args and ('%s' % self.args[0]) or '(what)'\n", + Py_file_input, + module_dict, t) )) return -1; + Py_DECREF(r); + + PickleError = PyErr_NewException("cPickle.PickleError", NULL, t); + if (!PickleError) + return -1; + + Py_DECREF(t); + + PicklingError = PyErr_NewException("cPickle.PicklingError", + PickleError, NULL); + if (!PicklingError) + return -1; + + if (!( t=PyDict_New())) return -1; + if (!( r=PyRun_String( + "def __str__(self):\n" + " a=self.args\n" + " a=a and type(a[0]) or '(what)'\n" + " return 'Cannot pickle %s objects' % a\n" + , Py_file_input, + module_dict, t) )) return -1; + Py_DECREF(r); + + if (!( UnpickleableError = PyErr_NewException( + "cPickle.UnpickleableError", PicklingError, t))) + return -1; + + Py_DECREF(t); + + if (!( UnpicklingError = PyErr_NewException("cPickle.UnpicklingError", + PickleError, NULL))) + return -1; + + if (!( BadPickleGet = PyErr_NewException("cPickle.BadPickleGet", + UnpicklingError, NULL))) + return -1; + + if (PyDict_SetItemString(module_dict, "PickleError", + PickleError) < 0) + return -1; + + if (PyDict_SetItemString(module_dict, "PicklingError", + PicklingError) < 0) + return -1; + + if (PyDict_SetItemString(module_dict, "UnpicklingError", + UnpicklingError) < 0) + return -1; + + if (PyDict_SetItemString(module_dict, "UnpickleableError", + UnpickleableError) < 0) + return -1; + + if (PyDict_SetItemString(module_dict, "BadPickleGet", + BadPickleGet) < 0) + return -1; + + PycString_IMPORT; + + return 0; +} + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC +initcPickle(void) +{ + PyObject *m, *d, *di, *v, *k; + Py_ssize_t i; + char *rev = "1.71"; /* XXX when does this change? */ + PyObject *format_version; + PyObject *compatible_formats; + + Picklertype.ob_type = &PyType_Type; + Unpicklertype.ob_type = &PyType_Type; + PdataType.ob_type = &PyType_Type; + + /* Initialize some pieces. We need to do this before module creation, + * so we're forced to use a temporary dictionary. :( + */ + di = PyDict_New(); + if (!di) return; + if (init_stuff(di) < 0) return; + + /* Create the module and add the functions */ + m = Py_InitModule4("cPickle", cPickle_methods, + cPickle_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + v = PyString_FromString(rev); + PyDict_SetItemString(d, "__version__", v); + Py_XDECREF(v); + + /* Copy data from di. Waaa. */ + for (i=0; PyDict_Next(di, &i, &k, &v); ) { + if (PyObject_SetItem(d, k, v) < 0) { + Py_DECREF(di); + return; + } + } + Py_DECREF(di); + + i = PyModule_AddIntConstant(m, "HIGHEST_PROTOCOL", HIGHEST_PROTOCOL); + if (i < 0) + return; + + /* These are purely informational; no code uses them. */ + /* File format version we write. */ + format_version = PyString_FromString("2.0"); + /* Format versions we can read. */ + compatible_formats = Py_BuildValue("[sssss]", + "1.0", /* Original protocol 0 */ + "1.1", /* Protocol 0 + INST */ + "1.2", /* Original protocol 1 */ + "1.3", /* Protocol 1 + BINFLOAT */ + "2.0"); /* Original protocol 2 */ + PyDict_SetItemString(d, "format_version", format_version); + PyDict_SetItemString(d, "compatible_formats", compatible_formats); + Py_XDECREF(format_version); + Py_XDECREF(compatible_formats); +} diff --git a/sys/src/cmd/python/Modules/cStringIO.c b/sys/src/cmd/python/Modules/cStringIO.c new file mode 100644 index 000000000..100891ba4 --- /dev/null +++ b/sys/src/cmd/python/Modules/cStringIO.c @@ -0,0 +1,745 @@ + +#include "Python.h" +#include "import.h" +#include "cStringIO.h" +#include "structmember.h" + +PyDoc_STRVAR(cStringIO_module_documentation, +"A simple fast partial StringIO replacement.\n" +"\n" +"This module provides a simple useful replacement for\n" +"the StringIO module that is written in C. It does not provide the\n" +"full generality of StringIO, but it provides enough for most\n" +"applications and is especially useful in conjunction with the\n" +"pickle module.\n" +"\n" +"Usage:\n" +"\n" +" from cStringIO import StringIO\n" +"\n" +" an_output_stream=StringIO()\n" +" an_output_stream.write(some_stuff)\n" +" ...\n" +" value=an_output_stream.getvalue()\n" +"\n" +" an_input_stream=StringIO(a_string)\n" +" spam=an_input_stream.readline()\n" +" spam=an_input_stream.read(5)\n" +" an_input_stream.seek(0) # OK, start over\n" +" spam=an_input_stream.read() # and read it all\n" +" \n" +"If someone else wants to provide a more complete implementation,\n" +"go for it. :-) \n" +"\n" +"cStringIO.c,v 1.29 1999/06/15 14:10:27 jim Exp\n"); + +/* Declaration for file-like objects that manage data as strings + + The IOobject type should be though of as a common base type for + Iobjects, which provide input (read-only) StringIO objects and + Oobjects, which provide read-write objects. Most of the methods + depend only on common data. +*/ + +typedef struct { + PyObject_HEAD + char *buf; + Py_ssize_t pos, string_size; +} IOobject; + +#define IOOOBJECT(O) ((IOobject*)(O)) + +/* Declarations for objects of type StringO */ + +typedef struct { /* Subtype of IOobject */ + PyObject_HEAD + char *buf; + Py_ssize_t pos, string_size; + + Py_ssize_t buf_size; + int softspace; +} Oobject; + +/* Declarations for objects of type StringI */ + +typedef struct { /* Subtype of IOobject */ + PyObject_HEAD + char *buf; + Py_ssize_t pos, string_size; + /* We store a reference to the object here in order to keep + the buffer alive during the lifetime of the Iobject. */ + PyObject *pbuf; +} Iobject; + +/* IOobject (common) methods */ + +PyDoc_STRVAR(IO_flush__doc__, "flush(): does nothing."); + +static int +IO__opencheck(IOobject *self) { + if (!self->buf) { + PyErr_SetString(PyExc_ValueError, + "I/O operation on closed file"); + return 0; + } + return 1; +} + +static PyObject * +IO_get_closed(IOobject *self, void *closure) +{ + PyObject *result = Py_False; + + if (self->buf == NULL) + result = Py_True; + Py_INCREF(result); + return result; +} + +static PyGetSetDef file_getsetlist[] = { + {"closed", (getter)IO_get_closed, NULL, "True if the file is closed"}, + {0}, +}; + +static PyObject * +IO_flush(IOobject *self, PyObject *unused) { + + if (!IO__opencheck(self)) return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(IO_getval__doc__, +"getvalue([use_pos]) -- Get the string value." +"\n" +"If use_pos is specified and is a true value, then the string returned\n" +"will include only the text up to the current file position.\n"); + +static PyObject * +IO_cgetval(PyObject *self) { + if (!IO__opencheck(IOOOBJECT(self))) return NULL; + return PyString_FromStringAndSize(((IOobject*)self)->buf, + ((IOobject*)self)->pos); +} + +static PyObject * +IO_getval(IOobject *self, PyObject *args) { + PyObject *use_pos=Py_None; + Py_ssize_t s; + + if (!IO__opencheck(self)) return NULL; + if (!PyArg_UnpackTuple(args,"getval", 0, 1,&use_pos)) return NULL; + + if (PyObject_IsTrue(use_pos)) { + s=self->pos; + if (s > self->string_size) s=self->string_size; + } + else + s=self->string_size; + return PyString_FromStringAndSize(self->buf, s); +} + +PyDoc_STRVAR(IO_isatty__doc__, "isatty(): always returns 0"); + +static PyObject * +IO_isatty(IOobject *self, PyObject *unused) { + if (!IO__opencheck(self)) return NULL; + Py_INCREF(Py_False); + return Py_False; +} + +PyDoc_STRVAR(IO_read__doc__, +"read([s]) -- Read s characters, or the rest of the string"); + +static int +IO_cread(PyObject *self, char **output, Py_ssize_t n) { + Py_ssize_t l; + + if (!IO__opencheck(IOOOBJECT(self))) return -1; + l = ((IOobject*)self)->string_size - ((IOobject*)self)->pos; + if (n < 0 || n > l) { + n = l; + if (n < 0) n=0; + } + + *output=((IOobject*)self)->buf + ((IOobject*)self)->pos; + ((IOobject*)self)->pos += n; + return n; +} + +static PyObject * +IO_read(IOobject *self, PyObject *args) { + Py_ssize_t n = -1; + char *output = NULL; + + if (!PyArg_ParseTuple(args, "|n:read", &n)) return NULL; + + if ( (n=IO_cread((PyObject*)self,&output,n)) < 0) return NULL; + + return PyString_FromStringAndSize(output, n); +} + +PyDoc_STRVAR(IO_readline__doc__, "readline() -- Read one line"); + +static int +IO_creadline(PyObject *self, char **output) { + char *n, *s; + Py_ssize_t l; + + if (!IO__opencheck(IOOOBJECT(self))) return -1; + + for (n = ((IOobject*)self)->buf + ((IOobject*)self)->pos, + s = ((IOobject*)self)->buf + ((IOobject*)self)->string_size; + n < s && *n != '\n'; n++); + if (n < s) n++; + + *output=((IOobject*)self)->buf + ((IOobject*)self)->pos; + l = n - ((IOobject*)self)->buf - ((IOobject*)self)->pos; + assert(((IOobject*)self)->pos + l < INT_MAX); + ((IOobject*)self)->pos += (int)l; + return (int)l; +} + +static PyObject * +IO_readline(IOobject *self, PyObject *args) { + int n, m=-1; + char *output; + + if (args) + if (!PyArg_ParseTuple(args, "|i:readline", &m)) return NULL; + + if( (n=IO_creadline((PyObject*)self,&output)) < 0) return NULL; + if (m >= 0 && m < n) { + m = n - m; + n -= m; + self->pos -= m; + } + return PyString_FromStringAndSize(output, n); +} + +PyDoc_STRVAR(IO_readlines__doc__, "readlines() -- Read all lines"); + +static PyObject * +IO_readlines(IOobject *self, PyObject *args) { + int n; + char *output; + PyObject *result, *line; + int hint = 0, length = 0; + + if (!PyArg_ParseTuple(args, "|i:readlines", &hint)) return NULL; + + result = PyList_New(0); + if (!result) + return NULL; + + while (1){ + if ( (n = IO_creadline((PyObject*)self,&output)) < 0) + goto err; + if (n == 0) + break; + line = PyString_FromStringAndSize (output, n); + if (!line) + goto err; + if (PyList_Append (result, line) == -1) { + Py_DECREF (line); + goto err; + } + Py_DECREF (line); + length += n; + if (hint > 0 && length >= hint) + break; + } + return result; + err: + Py_DECREF(result); + return NULL; +} + +PyDoc_STRVAR(IO_reset__doc__, +"reset() -- Reset the file position to the beginning"); + +static PyObject * +IO_reset(IOobject *self, PyObject *unused) { + + if (!IO__opencheck(self)) return NULL; + + self->pos = 0; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(IO_tell__doc__, "tell() -- get the current position."); + +static PyObject * +IO_tell(IOobject *self, PyObject *unused) { + + if (!IO__opencheck(self)) return NULL; + + return PyInt_FromSsize_t(self->pos); +} + +PyDoc_STRVAR(IO_truncate__doc__, +"truncate(): truncate the file at the current position."); + +static PyObject * +IO_truncate(IOobject *self, PyObject *args) { + Py_ssize_t pos = -1; + + if (!IO__opencheck(self)) return NULL; + if (!PyArg_ParseTuple(args, "|n:truncate", &pos)) return NULL; + if (pos < 0) pos = self->pos; + + if (self->string_size > pos) self->string_size = pos; + self->pos = self->string_size; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +IO_iternext(Iobject *self) +{ + PyObject *next; + next = IO_readline((IOobject *)self, NULL); + if (!next) + return NULL; + if (!PyString_GET_SIZE(next)) { + Py_DECREF(next); + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } + return next; +} + + + + +/* Read-write object methods */ + +PyDoc_STRVAR(O_seek__doc__, +"seek(position) -- set the current position\n" +"seek(position, mode) -- mode 0: absolute; 1: relative; 2: relative to EOF"); + +static PyObject * +O_seek(Oobject *self, PyObject *args) { + Py_ssize_t position; + int mode = 0; + + if (!IO__opencheck(IOOOBJECT(self))) return NULL; + if (!PyArg_ParseTuple(args, "n|i:seek", &position, &mode)) + return NULL; + + if (mode == 2) { + position += self->string_size; + } + else if (mode == 1) { + position += self->pos; + } + + if (position > self->buf_size) { + self->buf_size*=2; + if (self->buf_size <= position) self->buf_size=position+1; + self->buf = (char*) realloc(self->buf,self->buf_size); + if (!self->buf) { + self->buf_size=self->pos=0; + return PyErr_NoMemory(); + } + } + else if (position < 0) position=0; + + self->pos=position; + + while (--position >= self->string_size) self->buf[position]=0; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(O_write__doc__, +"write(s) -- Write a string to the file" +"\n\nNote (hack:) writing None resets the buffer"); + + +static int +O_cwrite(PyObject *self, const char *c, Py_ssize_t l) { + Py_ssize_t newl; + Oobject *oself; + + if (!IO__opencheck(IOOOBJECT(self))) return -1; + oself = (Oobject *)self; + + newl = oself->pos+l; + if (newl >= oself->buf_size) { + oself->buf_size *= 2; + if (oself->buf_size <= newl) { + assert(newl + 1 < INT_MAX); + oself->buf_size = (int)(newl+1); + } + oself->buf = (char*)realloc(oself->buf, oself->buf_size); + if (!oself->buf) { + PyErr_SetString(PyExc_MemoryError,"out of memory"); + oself->buf_size = oself->pos = 0; + return -1; + } + } + + memcpy(oself->buf+oself->pos,c,l); + + assert(oself->pos + l < INT_MAX); + oself->pos += (int)l; + + if (oself->string_size < oself->pos) { + oself->string_size = oself->pos; + } + + return (int)l; +} + +static PyObject * +O_write(Oobject *self, PyObject *args) { + char *c; + int l; + + if (!PyArg_ParseTuple(args, "t#:write", &c, &l)) return NULL; + + if (O_cwrite((PyObject*)self,c,l) < 0) return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(O_close__doc__, "close(): explicitly release resources held."); + +static PyObject * +O_close(Oobject *self, PyObject *unused) { + if (self->buf != NULL) free(self->buf); + self->buf = NULL; + + self->pos = self->string_size = self->buf_size = 0; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(O_writelines__doc__, +"writelines(sequence_of_strings) -> None. Write the strings to the file.\n" +"\n" +"Note that newlines are not added. The sequence can be any iterable object\n" +"producing strings. This is equivalent to calling write() for each string."); +static PyObject * +O_writelines(Oobject *self, PyObject *args) { + PyObject *it, *s; + + it = PyObject_GetIter(args); + if (it == NULL) + return NULL; + while ((s = PyIter_Next(it)) != NULL) { + Py_ssize_t n; + char *c; + if (PyString_AsStringAndSize(s, &c, &n) == -1) { + Py_DECREF(it); + Py_DECREF(s); + return NULL; + } + if (O_cwrite((PyObject *)self, c, n) == -1) { + Py_DECREF(it); + Py_DECREF(s); + return NULL; + } + Py_DECREF(s); + } + + Py_DECREF(it); + + /* See if PyIter_Next failed */ + if (PyErr_Occurred()) + return NULL; + + Py_RETURN_NONE; +} +static struct PyMethodDef O_methods[] = { + /* Common methods: */ + {"flush", (PyCFunction)IO_flush, METH_NOARGS, IO_flush__doc__}, + {"getvalue", (PyCFunction)IO_getval, METH_VARARGS, IO_getval__doc__}, + {"isatty", (PyCFunction)IO_isatty, METH_NOARGS, IO_isatty__doc__}, + {"read", (PyCFunction)IO_read, METH_VARARGS, IO_read__doc__}, + {"readline", (PyCFunction)IO_readline, METH_VARARGS, IO_readline__doc__}, + {"readlines", (PyCFunction)IO_readlines,METH_VARARGS, IO_readlines__doc__}, + {"reset", (PyCFunction)IO_reset, METH_NOARGS, IO_reset__doc__}, + {"tell", (PyCFunction)IO_tell, METH_NOARGS, IO_tell__doc__}, + {"truncate", (PyCFunction)IO_truncate, METH_VARARGS, IO_truncate__doc__}, + + /* Read-write StringIO specific methods: */ + {"close", (PyCFunction)O_close, METH_NOARGS, O_close__doc__}, + {"seek", (PyCFunction)O_seek, METH_VARARGS, O_seek__doc__}, + {"write", (PyCFunction)O_write, METH_VARARGS, O_write__doc__}, + {"writelines", (PyCFunction)O_writelines, METH_O, O_writelines__doc__}, + {NULL, NULL} /* sentinel */ +}; + +static PyMemberDef O_memberlist[] = { + {"softspace", T_INT, offsetof(Oobject, softspace), 0, + "flag indicating that a space needs to be printed; used by print"}, + /* getattr(f, "closed") is implemented without this table */ + {NULL} /* Sentinel */ +}; + +static void +O_dealloc(Oobject *self) { + if (self->buf != NULL) + free(self->buf); + PyObject_Del(self); +} + +PyDoc_STRVAR(Otype__doc__, "Simple type for output to strings."); + +static PyTypeObject Otype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "cStringIO.StringO", /*tp_name*/ + sizeof(Oobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)O_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr */ + 0, /*tp_setattr */ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0 , /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro */ + 0, /*tp_setattro */ + 0, /*tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + Otype__doc__, /*tp_doc */ + 0, /*tp_traverse */ + 0, /*tp_clear */ + 0, /*tp_richcompare */ + 0, /*tp_weaklistoffset */ + PyObject_SelfIter, /*tp_iter */ + (iternextfunc)IO_iternext, /*tp_iternext */ + O_methods, /*tp_methods */ + O_memberlist, /*tp_members */ + file_getsetlist, /*tp_getset */ +}; + +static PyObject * +newOobject(int size) { + Oobject *self; + + self = PyObject_New(Oobject, &Otype); + if (self == NULL) + return NULL; + self->pos=0; + self->string_size = 0; + self->softspace = 0; + + self->buf = (char *)malloc(size); + if (!self->buf) { + PyErr_SetString(PyExc_MemoryError,"out of memory"); + self->buf_size = 0; + Py_DECREF(self); + return NULL; + } + + self->buf_size=size; + return (PyObject*)self; +} + +/* End of code for StringO objects */ +/* -------------------------------------------------------- */ + +static PyObject * +I_close(Iobject *self, PyObject *unused) { + Py_XDECREF(self->pbuf); + self->pbuf = NULL; + self->buf = NULL; + + self->pos = self->string_size = 0; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +I_seek(Iobject *self, PyObject *args) { + Py_ssize_t position; + int mode = 0; + + if (!IO__opencheck(IOOOBJECT(self))) return NULL; + if (!PyArg_ParseTuple(args, "n|i:seek", &position, &mode)) + return NULL; + + if (mode == 2) position += self->string_size; + else if (mode == 1) position += self->pos; + + if (position < 0) position=0; + + self->pos=position; + + Py_INCREF(Py_None); + return Py_None; +} + +static struct PyMethodDef I_methods[] = { + /* Common methods: */ + {"flush", (PyCFunction)IO_flush, METH_NOARGS, IO_flush__doc__}, + {"getvalue", (PyCFunction)IO_getval, METH_VARARGS, IO_getval__doc__}, + {"isatty", (PyCFunction)IO_isatty, METH_NOARGS, IO_isatty__doc__}, + {"read", (PyCFunction)IO_read, METH_VARARGS, IO_read__doc__}, + {"readline", (PyCFunction)IO_readline, METH_VARARGS, IO_readline__doc__}, + {"readlines", (PyCFunction)IO_readlines,METH_VARARGS, IO_readlines__doc__}, + {"reset", (PyCFunction)IO_reset, METH_NOARGS, IO_reset__doc__}, + {"tell", (PyCFunction)IO_tell, METH_NOARGS, IO_tell__doc__}, + {"truncate", (PyCFunction)IO_truncate, METH_VARARGS, IO_truncate__doc__}, + + /* Read-only StringIO specific methods: */ + {"close", (PyCFunction)I_close, METH_NOARGS, O_close__doc__}, + {"seek", (PyCFunction)I_seek, METH_VARARGS, O_seek__doc__}, + {NULL, NULL} +}; + +static void +I_dealloc(Iobject *self) { + Py_XDECREF(self->pbuf); + PyObject_Del(self); +} + + +PyDoc_STRVAR(Itype__doc__, +"Simple type for treating strings as input file streams"); + +static PyTypeObject Itype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "cStringIO.StringI", /*tp_name*/ + sizeof(Iobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)I_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /* tp_getattr */ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + Itype__doc__, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)IO_iternext, /* tp_iternext */ + I_methods, /* tp_methods */ + 0, /* tp_members */ + file_getsetlist, /* tp_getset */ +}; + +static PyObject * +newIobject(PyObject *s) { + Iobject *self; + char *buf; + Py_ssize_t size; + + if (PyObject_AsCharBuffer(s, (const char **)&buf, &size) != 0) + return NULL; + + self = PyObject_New(Iobject, &Itype); + if (!self) return NULL; + Py_INCREF(s); + self->buf=buf; + self->string_size=size; + self->pbuf=s; + self->pos=0; + + return (PyObject*)self; +} + +/* End of code for StringI objects */ +/* -------------------------------------------------------- */ + + +PyDoc_STRVAR(IO_StringIO__doc__, +"StringIO([s]) -- Return a StringIO-like stream for reading or writing"); + +static PyObject * +IO_StringIO(PyObject *self, PyObject *args) { + PyObject *s=0; + + if (!PyArg_UnpackTuple(args, "StringIO", 0, 1, &s)) return NULL; + + if (s) return newIobject(s); + return newOobject(128); +} + +/* List of methods defined in the module */ + +static struct PyMethodDef IO_methods[] = { + {"StringIO", (PyCFunction)IO_StringIO, + METH_VARARGS, IO_StringIO__doc__}, + {NULL, NULL} /* sentinel */ +}; + + +/* Initialization function for the module (*must* be called initcStringIO) */ + +static struct PycStringIO_CAPI CAPI = { + IO_cread, + IO_creadline, + O_cwrite, + IO_cgetval, + newOobject, + newIobject, + &Itype, + &Otype, +}; + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC +initcStringIO(void) { + PyObject *m, *d, *v; + + + /* Create the module and add the functions */ + m = Py_InitModule4("cStringIO", IO_methods, + cStringIO_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); + if (m == NULL) return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + + /* Export C API */ + Itype.ob_type=&PyType_Type; + Otype.ob_type=&PyType_Type; + if (PyType_Ready(&Otype) < 0) return; + if (PyType_Ready(&Itype) < 0) return; + PyDict_SetItemString(d,"cStringIO_CAPI", + v = PyCObject_FromVoidPtr(&CAPI,NULL)); + Py_XDECREF(v); + + /* Export Types */ + PyDict_SetItemString(d,"InputType", (PyObject*)&Itype); + PyDict_SetItemString(d,"OutputType", (PyObject*)&Otype); + + /* Maybe make certain warnings go away */ + if (0) PycString_IMPORT; +} diff --git a/sys/src/cmd/python/Modules/cdmodule.c b/sys/src/cmd/python/Modules/cdmodule.c new file mode 100644 index 000000000..f8efd395a --- /dev/null +++ b/sys/src/cmd/python/Modules/cdmodule.c @@ -0,0 +1,796 @@ +/* CD module -- interface to Mark Callow's and Roger Chickering's */ + /* CD Audio Library (CD). */ + +#include <sys/types.h> +#include <cdaudio.h> +#include "Python.h" + +#define NCALLBACKS 8 + +typedef struct { + PyObject_HEAD + CDPLAYER *ob_cdplayer; +} cdplayerobject; + +static PyObject *CdError; /* exception cd.error */ + +static PyObject * +CD_allowremoval(cdplayerobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":allowremoval")) + return NULL; + + CDallowremoval(self->ob_cdplayer); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_preventremoval(cdplayerobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":preventremoval")) + return NULL; + + CDpreventremoval(self->ob_cdplayer); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_bestreadsize(cdplayerobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":bestreadsize")) + return NULL; + + return PyInt_FromLong((long) CDbestreadsize(self->ob_cdplayer)); +} + +static PyObject * +CD_close(cdplayerobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":close")) + return NULL; + + if (!CDclose(self->ob_cdplayer)) { + PyErr_SetFromErrno(CdError); /* XXX - ??? */ + return NULL; + } + self->ob_cdplayer = NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_eject(cdplayerobject *self, PyObject *args) +{ + CDSTATUS status; + + if (!PyArg_ParseTuple(args, ":eject")) + return NULL; + + if (!CDeject(self->ob_cdplayer)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "eject failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_getstatus(cdplayerobject *self, PyObject *args) +{ + CDSTATUS status; + + if (!PyArg_ParseTuple(args, ":getstatus")) + return NULL; + + if (!CDgetstatus(self->ob_cdplayer, &status)) { + PyErr_SetFromErrno(CdError); /* XXX - ??? */ + return NULL; + } + + return Py_BuildValue("(ii(iii)(iii)(iii)iiii)", status.state, + status.track, status.min, status.sec, status.frame, + status.abs_min, status.abs_sec, status.abs_frame, + status.total_min, status.total_sec, status.total_frame, + status.first, status.last, status.scsi_audio, + status.cur_block); +} + +static PyObject * +CD_gettrackinfo(cdplayerobject *self, PyObject *args) +{ + int track; + CDTRACKINFO info; + CDSTATUS status; + + if (!PyArg_ParseTuple(args, "i:gettrackinfo", &track)) + return NULL; + + if (!CDgettrackinfo(self->ob_cdplayer, track, &info)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "gettrackinfo failed"); + return NULL; + } + + return Py_BuildValue("((iii)(iii))", + info.start_min, info.start_sec, info.start_frame, + info.total_min, info.total_sec, info.total_frame); +} + +static PyObject * +CD_msftoblock(cdplayerobject *self, PyObject *args) +{ + int min, sec, frame; + + if (!PyArg_ParseTuple(args, "iii:msftoblock", &min, &sec, &frame)) + return NULL; + + return PyInt_FromLong((long) CDmsftoblock(self->ob_cdplayer, + min, sec, frame)); +} + +static PyObject * +CD_play(cdplayerobject *self, PyObject *args) +{ + int start, play; + CDSTATUS status; + + if (!PyArg_ParseTuple(args, "ii:play", &start, &play)) + return NULL; + + if (!CDplay(self->ob_cdplayer, start, play)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "play failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_playabs(cdplayerobject *self, PyObject *args) +{ + int min, sec, frame, play; + CDSTATUS status; + + if (!PyArg_ParseTuple(args, "iiii:playabs", &min, &sec, &frame, &play)) + return NULL; + + if (!CDplayabs(self->ob_cdplayer, min, sec, frame, play)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "playabs failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_playtrack(cdplayerobject *self, PyObject *args) +{ + int start, play; + CDSTATUS status; + + if (!PyArg_ParseTuple(args, "ii:playtrack", &start, &play)) + return NULL; + + if (!CDplaytrack(self->ob_cdplayer, start, play)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "playtrack failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_playtrackabs(cdplayerobject *self, PyObject *args) +{ + int track, min, sec, frame, play; + CDSTATUS status; + + if (!PyArg_ParseTuple(args, "iiiii:playtrackabs", &track, &min, &sec, + &frame, &play)) + return NULL; + + if (!CDplaytrackabs(self->ob_cdplayer, track, min, sec, frame, play)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "playtrackabs failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_readda(cdplayerobject *self, PyObject *args) +{ + int numframes, n; + PyObject *result; + + if (!PyArg_ParseTuple(args, "i:readda", &numframes)) + return NULL; + + result = PyString_FromStringAndSize(NULL, numframes * sizeof(CDFRAME)); + if (result == NULL) + return NULL; + + n = CDreadda(self->ob_cdplayer, + (CDFRAME *) PyString_AsString(result), numframes); + if (n == -1) { + Py_DECREF(result); + PyErr_SetFromErrno(CdError); + return NULL; + } + if (n < numframes) + _PyString_Resize(&result, n * sizeof(CDFRAME)); + + return result; +} + +static PyObject * +CD_seek(cdplayerobject *self, PyObject *args) +{ + int min, sec, frame; + long PyTryBlock; + + if (!PyArg_ParseTuple(args, "iii:seek", &min, &sec, &frame)) + return NULL; + + PyTryBlock = CDseek(self->ob_cdplayer, min, sec, frame); + if (PyTryBlock == -1) { + PyErr_SetFromErrno(CdError); + return NULL; + } + + return PyInt_FromLong(PyTryBlock); +} + +static PyObject * +CD_seektrack(cdplayerobject *self, PyObject *args) +{ + int track; + long PyTryBlock; + + if (!PyArg_ParseTuple(args, "i:seektrack", &track)) + return NULL; + + PyTryBlock = CDseektrack(self->ob_cdplayer, track); + if (PyTryBlock == -1) { + PyErr_SetFromErrno(CdError); + return NULL; + } + + return PyInt_FromLong(PyTryBlock); +} + +static PyObject * +CD_seekblock(cdplayerobject *self, PyObject *args) +{ + unsigned long PyTryBlock; + + if (!PyArg_ParseTuple(args, "l:seekblock", &PyTryBlock)) + return NULL; + + PyTryBlock = CDseekblock(self->ob_cdplayer, PyTryBlock); + if (PyTryBlock == (unsigned long) -1) { + PyErr_SetFromErrno(CdError); + return NULL; + } + + return PyInt_FromLong(PyTryBlock); +} + +static PyObject * +CD_stop(cdplayerobject *self, PyObject *args) +{ + CDSTATUS status; + + if (!PyArg_ParseTuple(args, ":stop")) + return NULL; + + if (!CDstop(self->ob_cdplayer)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "stop failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_togglepause(cdplayerobject *self, PyObject *args) +{ + CDSTATUS status; + + if (!PyArg_ParseTuple(args, ":togglepause")) + return NULL; + + if (!CDtogglepause(self->ob_cdplayer)) { + if (CDgetstatus(self->ob_cdplayer, &status) && + status.state == CD_NODISC) + PyErr_SetString(CdError, "no disc in player"); + else + PyErr_SetString(CdError, "togglepause failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef cdplayer_methods[] = { + {"allowremoval", (PyCFunction)CD_allowremoval, METH_VARARGS}, + {"bestreadsize", (PyCFunction)CD_bestreadsize, METH_VARARGS}, + {"close", (PyCFunction)CD_close, METH_VARARGS}, + {"eject", (PyCFunction)CD_eject, METH_VARARGS}, + {"getstatus", (PyCFunction)CD_getstatus, METH_VARARGS}, + {"gettrackinfo", (PyCFunction)CD_gettrackinfo, METH_VARARGS}, + {"msftoblock", (PyCFunction)CD_msftoblock, METH_VARARGS}, + {"play", (PyCFunction)CD_play, METH_VARARGS}, + {"playabs", (PyCFunction)CD_playabs, METH_VARARGS}, + {"playtrack", (PyCFunction)CD_playtrack, METH_VARARGS}, + {"playtrackabs", (PyCFunction)CD_playtrackabs, METH_VARARGS}, + {"preventremoval", (PyCFunction)CD_preventremoval, METH_VARARGS}, + {"readda", (PyCFunction)CD_readda, METH_VARARGS}, + {"seek", (PyCFunction)CD_seek, METH_VARARGS}, + {"seekblock", (PyCFunction)CD_seekblock, METH_VARARGS}, + {"seektrack", (PyCFunction)CD_seektrack, METH_VARARGS}, + {"stop", (PyCFunction)CD_stop, METH_VARARGS}, + {"togglepause", (PyCFunction)CD_togglepause, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static void +cdplayer_dealloc(cdplayerobject *self) +{ + if (self->ob_cdplayer != NULL) + CDclose(self->ob_cdplayer); + PyObject_Del(self); +} + +static PyObject * +cdplayer_getattr(cdplayerobject *self, char *name) +{ + if (self->ob_cdplayer == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no player active"); + return NULL; + } + return Py_FindMethod(cdplayer_methods, (PyObject *)self, name); +} + +PyTypeObject CdPlayertype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "cd.cdplayer", /*tp_name*/ + sizeof(cdplayerobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)cdplayer_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)cdplayer_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyObject * +newcdplayerobject(CDPLAYER *cdp) +{ + cdplayerobject *p; + + p = PyObject_New(cdplayerobject, &CdPlayertype); + if (p == NULL) + return NULL; + p->ob_cdplayer = cdp; + return (PyObject *) p; +} + +static PyObject * +CD_open(PyObject *self, PyObject *args) +{ + char *dev, *direction; + CDPLAYER *cdp; + + /* + * Variable number of args. + * First defaults to "None", second defaults to "r". + */ + dev = NULL; + direction = "r"; + if (!PyArg_ParseTuple(args, "|zs:open", &dev, &direction)) + return NULL; + + cdp = CDopen(dev, direction); + if (cdp == NULL) { + PyErr_SetFromErrno(CdError); + return NULL; + } + + return newcdplayerobject(cdp); +} + +typedef struct { + PyObject_HEAD + CDPARSER *ob_cdparser; + struct { + PyObject *ob_cdcallback; + PyObject *ob_cdcallbackarg; + } ob_cdcallbacks[NCALLBACKS]; +} cdparserobject; + +static void +CD_callback(void *arg, CDDATATYPES type, void *data) +{ + PyObject *result, *args, *v = NULL; + char *p; + int i; + cdparserobject *self; + + self = (cdparserobject *) arg; + args = PyTuple_New(3); + if (args == NULL) + return; + Py_INCREF(self->ob_cdcallbacks[type].ob_cdcallbackarg); + PyTuple_SetItem(args, 0, self->ob_cdcallbacks[type].ob_cdcallbackarg); + PyTuple_SetItem(args, 1, PyInt_FromLong((long) type)); + switch (type) { + case cd_audio: + v = PyString_FromStringAndSize(data, CDDA_DATASIZE); + break; + case cd_pnum: + case cd_index: + v = PyInt_FromLong(((CDPROGNUM *) data)->value); + break; + case cd_ptime: + case cd_atime: +#define ptr ((struct cdtimecode *) data) + v = Py_BuildValue("(iii)", + ptr->mhi * 10 + ptr->mlo, + ptr->shi * 10 + ptr->slo, + ptr->fhi * 10 + ptr->flo); +#undef ptr + break; + case cd_catalog: + v = PyString_FromStringAndSize(NULL, 13); + p = PyString_AsString(v); + for (i = 0; i < 13; i++) + *p++ = ((char *) data)[i] + '0'; + break; + case cd_ident: +#define ptr ((struct cdident *) data) + v = PyString_FromStringAndSize(NULL, 12); + p = PyString_AsString(v); + CDsbtoa(p, ptr->country, 2); + p += 2; + CDsbtoa(p, ptr->owner, 3); + p += 3; + *p++ = ptr->year[0] + '0'; + *p++ = ptr->year[1] + '0'; + *p++ = ptr->serial[0] + '0'; + *p++ = ptr->serial[1] + '0'; + *p++ = ptr->serial[2] + '0'; + *p++ = ptr->serial[3] + '0'; + *p++ = ptr->serial[4] + '0'; +#undef ptr + break; + case cd_control: + v = PyInt_FromLong((long) *((unchar *) data)); + break; + } + PyTuple_SetItem(args, 2, v); + if (PyErr_Occurred()) { + Py_DECREF(args); + return; + } + + result = PyEval_CallObject(self->ob_cdcallbacks[type].ob_cdcallback, + args); + Py_DECREF(args); + Py_XDECREF(result); +} + +static PyObject * +CD_deleteparser(cdparserobject *self, PyObject *args) +{ + int i; + + if (!PyArg_ParseTuple(args, ":deleteparser")) + return NULL; + + CDdeleteparser(self->ob_cdparser); + self->ob_cdparser = NULL; + + /* no sense in keeping the callbacks, so remove them */ + for (i = 0; i < NCALLBACKS; i++) { + Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback); + self->ob_cdcallbacks[i].ob_cdcallback = NULL; + Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg); + self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_parseframe(cdparserobject *self, PyObject *args) +{ + char *cdfp; + int length; + CDFRAME *p; + + if (!PyArg_ParseTuple(args, "s#:parseframe", &cdfp, &length)) + return NULL; + + if (length % sizeof(CDFRAME) != 0) { + PyErr_SetString(PyExc_TypeError, "bad length"); + return NULL; + } + + p = (CDFRAME *) cdfp; + while (length > 0) { + CDparseframe(self->ob_cdparser, p); + length -= sizeof(CDFRAME); + p++; + if (PyErr_Occurred()) + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_removecallback(cdparserobject *self, PyObject *args) +{ + int type; + + if (!PyArg_ParseTuple(args, "i:removecallback", &type)) + return NULL; + + if (type < 0 || type >= NCALLBACKS) { + PyErr_SetString(PyExc_TypeError, "bad type"); + return NULL; + } + + CDremovecallback(self->ob_cdparser, (CDDATATYPES) type); + + Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback); + self->ob_cdcallbacks[type].ob_cdcallback = NULL; + + Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg); + self->ob_cdcallbacks[type].ob_cdcallbackarg = NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_resetparser(cdparserobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":resetparser")) + return NULL; + + CDresetparser(self->ob_cdparser); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +CD_addcallback(cdparserobject *self, PyObject *args) +{ + int type; + PyObject *func, *funcarg; + + /* XXX - more work here */ + if (!PyArg_ParseTuple(args, "iOO:addcallback", &type, &func, &funcarg)) + return NULL; + + if (type < 0 || type >= NCALLBACKS) { + PyErr_SetString(PyExc_TypeError, "argument out of range"); + return NULL; + } + +#ifdef CDsetcallback + CDaddcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback, + (void *) self); +#else + CDsetcallback(self->ob_cdparser, (CDDATATYPES) type, CD_callback, + (void *) self); +#endif + Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallback); + Py_INCREF(func); + self->ob_cdcallbacks[type].ob_cdcallback = func; + Py_XDECREF(self->ob_cdcallbacks[type].ob_cdcallbackarg); + Py_INCREF(funcarg); + self->ob_cdcallbacks[type].ob_cdcallbackarg = funcarg; + +/* + if (type == cd_audio) { + sigfpe_[_UNDERFL].repls = _ZERO; + handle_sigfpes(_ON, _EN_UNDERFL, NULL, + _ABORT_ON_ERROR, NULL); + } +*/ + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef cdparser_methods[] = { + {"addcallback", (PyCFunction)CD_addcallback, METH_VARARGS}, + {"deleteparser", (PyCFunction)CD_deleteparser, METH_VARARGS}, + {"parseframe", (PyCFunction)CD_parseframe, METH_VARARGS}, + {"removecallback", (PyCFunction)CD_removecallback, METH_VARARGS}, + {"resetparser", (PyCFunction)CD_resetparser, METH_VARARGS}, + /* backward compatibility */ + {"setcallback", (PyCFunction)CD_addcallback, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static void +cdparser_dealloc(cdparserobject *self) +{ + int i; + + for (i = 0; i < NCALLBACKS; i++) { + Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallback); + self->ob_cdcallbacks[i].ob_cdcallback = NULL; + Py_XDECREF(self->ob_cdcallbacks[i].ob_cdcallbackarg); + self->ob_cdcallbacks[i].ob_cdcallbackarg = NULL; + } + CDdeleteparser(self->ob_cdparser); + PyObject_Del(self); +} + +static PyObject * +cdparser_getattr(cdparserobject *self, char *name) +{ + if (self->ob_cdparser == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no parser active"); + return NULL; + } + + return Py_FindMethod(cdparser_methods, (PyObject *)self, name); +} + +PyTypeObject CdParsertype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "cd.cdparser", /*tp_name*/ + sizeof(cdparserobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)cdparser_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)cdparser_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyObject * +newcdparserobject(CDPARSER *cdp) +{ + cdparserobject *p; + int i; + + p = PyObject_New(cdparserobject, &CdParsertype); + if (p == NULL) + return NULL; + p->ob_cdparser = cdp; + for (i = 0; i < NCALLBACKS; i++) { + p->ob_cdcallbacks[i].ob_cdcallback = NULL; + p->ob_cdcallbacks[i].ob_cdcallbackarg = NULL; + } + return (PyObject *) p; +} + +static PyObject * +CD_createparser(PyObject *self, PyObject *args) +{ + CDPARSER *cdp; + + if (!PyArg_ParseTuple(args, ":createparser")) + return NULL; + cdp = CDcreateparser(); + if (cdp == NULL) { + PyErr_SetString(CdError, "createparser failed"); + return NULL; + } + + return newcdparserobject(cdp); +} + +static PyObject * +CD_msftoframe(PyObject *self, PyObject *args) +{ + int min, sec, frame; + + if (!PyArg_ParseTuple(args, "iii:msftoframe", &min, &sec, &frame)) + return NULL; + + return PyInt_FromLong((long) CDmsftoframe(min, sec, frame)); +} + +static PyMethodDef CD_methods[] = { + {"open", (PyCFunction)CD_open, METH_VARARGS}, + {"createparser", (PyCFunction)CD_createparser, METH_VARARGS}, + {"msftoframe", (PyCFunction)CD_msftoframe, METH_VARARGS}, + {NULL, NULL} /* Sentinel */ +}; + +void +initcd(void) +{ + PyObject *m, *d; + + m = Py_InitModule("cd", CD_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + CdError = PyErr_NewException("cd.error", NULL, NULL); + PyDict_SetItemString(d, "error", CdError); + + /* Identifiers for the different types of callbacks from the parser */ + PyDict_SetItemString(d, "audio", PyInt_FromLong((long) cd_audio)); + PyDict_SetItemString(d, "pnum", PyInt_FromLong((long) cd_pnum)); + PyDict_SetItemString(d, "index", PyInt_FromLong((long) cd_index)); + PyDict_SetItemString(d, "ptime", PyInt_FromLong((long) cd_ptime)); + PyDict_SetItemString(d, "atime", PyInt_FromLong((long) cd_atime)); + PyDict_SetItemString(d, "catalog", PyInt_FromLong((long) cd_catalog)); + PyDict_SetItemString(d, "ident", PyInt_FromLong((long) cd_ident)); + PyDict_SetItemString(d, "control", PyInt_FromLong((long) cd_control)); + + /* Block size information for digital audio data */ + PyDict_SetItemString(d, "DATASIZE", + PyInt_FromLong((long) CDDA_DATASIZE)); + PyDict_SetItemString(d, "BLOCKSIZE", + PyInt_FromLong((long) CDDA_BLOCKSIZE)); + + /* Possible states for the cd player */ + PyDict_SetItemString(d, "ERROR", PyInt_FromLong((long) CD_ERROR)); + PyDict_SetItemString(d, "NODISC", PyInt_FromLong((long) CD_NODISC)); + PyDict_SetItemString(d, "READY", PyInt_FromLong((long) CD_READY)); + PyDict_SetItemString(d, "PLAYING", PyInt_FromLong((long) CD_PLAYING)); + PyDict_SetItemString(d, "PAUSED", PyInt_FromLong((long) CD_PAUSED)); + PyDict_SetItemString(d, "STILL", PyInt_FromLong((long) CD_STILL)); +#ifdef CD_CDROM /* only newer versions of the library */ + PyDict_SetItemString(d, "CDROM", PyInt_FromLong((long) CD_CDROM)); +#endif +} diff --git a/sys/src/cmd/python/Modules/cgen.py b/sys/src/cmd/python/Modules/cgen.py new file mode 100644 index 000000000..f07d9843b --- /dev/null +++ b/sys/src/cmd/python/Modules/cgen.py @@ -0,0 +1,520 @@ +######################################################################## +# Copyright (c) 2000, BeOpen.com. +# Copyright (c) 1995-2000, Corporation for National Research Initiatives. +# Copyright (c) 1990-1995, Stichting Mathematisch Centrum. +# All rights reserved. +# +# See the file "Misc/COPYRIGHT" for information on usage and +# redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. +######################################################################## + +# Python script to parse cstubs file for gl and generate C stubs. +# usage: python cgen.py <cstubs >glmodule.c +# +# NOTE: You must first make a python binary without the "GL" option +# before you can run this, when building Python for the first time. +# See comments in the Makefile. +# +# XXX BUG return arrays generate wrong code +# XXX need to change error returns into gotos to free mallocked arrays + + +import string +import sys + + +# Function to print to stderr +# +def err(*args): + savestdout = sys.stdout + try: + sys.stdout = sys.stderr + for i in args: + print i, + print + finally: + sys.stdout = savestdout + + +# The set of digits that form a number +# +digits = '0123456789' + + +# Function to extract a string of digits from the front of the string. +# Returns the leading string of digits and the remaining string. +# If no number is found, returns '' and the original string. +# +def getnum(s): + n = '' + while s and s[0] in digits: + n = n + s[0] + s = s[1:] + return n, s + + +# Function to check if a string is a number +# +def isnum(s): + if not s: return False + for c in s: + if not c in digits: return False + return True + + +# Allowed function return types +# +return_types = ['void', 'short', 'long'] + + +# Allowed function argument types +# +arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double'] + + +# Need to classify arguments as follows +# simple input variable +# simple output variable +# input array +# output array +# input giving size of some array +# +# Array dimensions can be specified as follows +# constant +# argN +# constant * argN +# retval +# constant * retval +# +# The dimensions given as constants * something are really +# arrays of points where points are 2- 3- or 4-tuples +# +# We have to consider three lists: +# python input arguments +# C stub arguments (in & out) +# python output arguments (really return values) +# +# There is a mapping from python input arguments to the input arguments +# of the C stub, and a further mapping from C stub arguments to the +# python return values + + +# Exception raised by checkarg() and generate() +# +arg_error = 'bad arg' + + +# Function to check one argument. +# Arguments: the type and the arg "name" (really mode plus subscript). +# Raises arg_error if something's wrong. +# Return type, mode, factor, rest of subscript; factor and rest may be empty. +# +def checkarg(type, arg): + # + # Turn "char *x" into "string x". + # + if type == 'char' and arg[0] == '*': + type = 'string' + arg = arg[1:] + # + # Check that the type is supported. + # + if type not in arg_types: + raise arg_error, ('bad type', type) + if type[:2] == 'u_': + type = 'unsigned ' + type[2:] + # + # Split it in the mode (first character) and the rest. + # + mode, rest = arg[:1], arg[1:] + # + # The mode must be 's' for send (= input) or 'r' for return argument. + # + if mode not in ('r', 's'): + raise arg_error, ('bad arg mode', mode) + # + # Is it a simple argument: if so, we are done. + # + if not rest: + return type, mode, '', '' + # + # Not a simple argument; must be an array. + # The 'rest' must be a subscript enclosed in [ and ]. + # The subscript must be one of the following forms, + # otherwise we don't handle it (where N is a number): + # N + # argN + # retval + # N*argN + # N*retval + # + if rest[:1] <> '[' or rest[-1:] <> ']': + raise arg_error, ('subscript expected', rest) + sub = rest[1:-1] + # + # Is there a leading number? + # + num, sub = getnum(sub) + if num: + # There is a leading number + if not sub: + # The subscript is just a number + return type, mode, num, '' + if sub[:1] == '*': + # There is a factor prefix + sub = sub[1:] + else: + raise arg_error, ('\'*\' expected', sub) + if sub == 'retval': + # size is retval -- must be a reply argument + if mode <> 'r': + raise arg_error, ('non-r mode with [retval]', mode) + elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])): + raise arg_error, ('bad subscript', sub) + # + return type, mode, num, sub + + +# List of functions for which we have generated stubs +# +functions = [] + + +# Generate the stub for the given function, using the database of argument +# information build by successive calls to checkarg() +# +def generate(type, func, database): + # + # Check that we can handle this case: + # no variable size reply arrays yet + # + n_in_args = 0 + n_out_args = 0 + # + for a_type, a_mode, a_factor, a_sub in database: + if a_mode == 's': + n_in_args = n_in_args + 1 + elif a_mode == 'r': + n_out_args = n_out_args + 1 + else: + # Can't happen + raise arg_error, ('bad a_mode', a_mode) + if (a_mode == 'r' and a_sub) or a_sub == 'retval': + err('Function', func, 'too complicated:', + a_type, a_mode, a_factor, a_sub) + print '/* XXX Too complicated to generate code for */' + return + # + functions.append(func) + # + # Stub header + # + print + print 'static PyObject *' + print 'gl_' + func + '(self, args)' + print '\tPyObject *self;' + print '\tPyObject *args;' + print '{' + # + # Declare return value if any + # + if type <> 'void': + print '\t' + type, 'retval;' + # + # Declare arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + print '\t' + a_type, + brac = ket = '' + if a_sub and not isnum(a_sub): + if a_factor: + brac = '(' + ket = ')' + print brac + '*', + print 'arg' + repr(i+1) + ket, + if a_sub and isnum(a_sub): + print '[', a_sub, ']', + if a_factor: + print '[', a_factor, ']', + print ';' + # + # Find input arguments derived from array sizes + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]): + # Sending a variable-length array + n = eval(a_sub[3:]) + if 1 <= n <= len(database): + b_type, b_mode, b_factor, b_sub = database[n-1] + if b_mode == 's': + database[n-1] = b_type, 'i', a_factor, repr(i) + n_in_args = n_in_args - 1 + # + # Assign argument positions in the Python argument list + # + in_pos = [] + i_in = 0 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode == 's': + in_pos.append(i_in) + i_in = i_in + 1 + else: + in_pos.append(-1) + # + # Get input arguments + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_type[:9] == 'unsigned ': + xtype = a_type[9:] + else: + xtype = a_type + if a_mode == 'i': + # + # Implicit argument; + # a_factor is divisor if present, + # a_sub indicates which arg (`database index`) + # + j = eval(a_sub) + print '\tif', + print '(!geti' + xtype + 'arraysize(args,', + print repr(n_in_args) + ',', + print repr(in_pos[j]) + ',', + if xtype <> a_type: + print '('+xtype+' *)', + print '&arg' + repr(i+1) + '))' + print '\t\treturn NULL;' + if a_factor: + print '\targ' + repr(i+1), + print '= arg' + repr(i+1), + print '/', a_factor + ';' + elif a_mode == 's': + if a_sub and not isnum(a_sub): + # Allocate memory for varsize array + print '\tif ((arg' + repr(i+1), '=', + if a_factor: + print '('+a_type+'(*)['+a_factor+'])', + print 'PyMem_NEW(' + a_type, ',', + if a_factor: + print a_factor, '*', + print a_sub, ')) == NULL)' + print '\t\treturn PyErr_NoMemory();' + print '\tif', + if a_factor or a_sub: # Get a fixed-size array array + print '(!geti' + xtype + 'array(args,', + print repr(n_in_args) + ',', + print repr(in_pos[i]) + ',', + if a_factor: print a_factor, + if a_factor and a_sub: print '*', + if a_sub: print a_sub, + print ',', + if (a_sub and a_factor) or xtype <> a_type: + print '('+xtype+' *)', + print 'arg' + repr(i+1) + '))' + else: # Get a simple variable + print '(!geti' + xtype + 'arg(args,', + print repr(n_in_args) + ',', + print repr(in_pos[i]) + ',', + if xtype <> a_type: + print '('+xtype+' *)', + print '&arg' + repr(i+1) + '))' + print '\t\treturn NULL;' + # + # Begin of function call + # + if type <> 'void': + print '\tretval =', func + '(', + else: + print '\t' + func + '(', + # + # Argument list + # + for i in range(len(database)): + if i > 0: print ',', + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode == 'r' and not a_factor: + print '&', + print 'arg' + repr(i+1), + # + # End of function call + # + print ');' + # + # Free varsize arrays + # + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode == 's' and a_sub and not isnum(a_sub): + print '\tPyMem_DEL(arg' + repr(i+1) + ');' + # + # Return + # + if n_out_args: + # + # Multiple return values -- construct a tuple + # + if type <> 'void': + n_out_args = n_out_args + 1 + if n_out_args == 1: + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode == 'r': + break + else: + raise arg_error, 'expected r arg not found' + print '\treturn', + print mkobject(a_type, 'arg' + repr(i+1)) + ';' + else: + print '\t{ PyObject *v = PyTuple_New(', + print n_out_args, ');' + print '\t if (v == NULL) return NULL;' + i_out = 0 + if type <> 'void': + print '\t PyTuple_SetItem(v,', + print repr(i_out) + ',', + print mkobject(type, 'retval') + ');' + i_out = i_out + 1 + for i in range(len(database)): + a_type, a_mode, a_factor, a_sub = database[i] + if a_mode == 'r': + print '\t PyTuple_SetItem(v,', + print repr(i_out) + ',', + s = mkobject(a_type, 'arg' + repr(i+1)) + print s + ');' + i_out = i_out + 1 + print '\t return v;' + print '\t}' + else: + # + # Simple function return + # Return None or return value + # + if type == 'void': + print '\tPy_INCREF(Py_None);' + print '\treturn Py_None;' + else: + print '\treturn', mkobject(type, 'retval') + ';' + # + # Stub body closing brace + # + print '}' + + +# Subroutine to return a function call to mknew<type>object(<arg>) +# +def mkobject(type, arg): + if type[:9] == 'unsigned ': + type = type[9:] + return 'mknew' + type + 'object((' + type + ') ' + arg + ')' + return 'mknew' + type + 'object(' + arg + ')' + + +defined_archs = [] + +# usage: cgen [ -Dmach ... ] [ file ] +for arg in sys.argv[1:]: + if arg[:2] == '-D': + defined_archs.append(arg[2:]) + else: + # Open optional file argument + sys.stdin = open(arg, 'r') + + +# Input line number +lno = 0 + + +# Input is divided in two parts, separated by a line containing '%%'. +# <part1> -- literally copied to stdout +# <part2> -- stub definitions + +# Variable indicating the current input part. +# +part = 1 + +# Main loop over the input +# +while 1: + try: + line = raw_input() + except EOFError: + break + # + lno = lno+1 + words = string.split(line) + # + if part == 1: + # + # In part 1, copy everything literally + # except look for a line of just '%%' + # + if words == ['%%']: + part = part + 1 + else: + # + # Look for names of manually written + # stubs: a single percent followed by the name + # of the function in Python. + # The stub name is derived by prefixing 'gl_'. + # + if words and words[0][0] == '%': + func = words[0][1:] + if (not func) and words[1:]: + func = words[1] + if func: + functions.append(func) + else: + print line + continue + if not words: + continue # skip empty line + elif words[0] == 'if': + # if XXX rest + # if !XXX rest + if words[1][0] == '!': + if words[1][1:] in defined_archs: + continue + elif words[1] not in defined_archs: + continue + words = words[2:] + if words[0] == '#include': + print line + elif words[0][:1] == '#': + pass # ignore comment + elif words[0] not in return_types: + err('Line', lno, ': bad return type :', words[0]) + elif len(words) < 2: + err('Line', lno, ': no funcname :', line) + else: + if len(words) % 2 <> 0: + err('Line', lno, ': odd argument list :', words[2:]) + else: + database = [] + try: + for i in range(2, len(words), 2): + x = checkarg(words[i], words[i+1]) + database.append(x) + print + print '/*', + for w in words: print w, + print '*/' + generate(words[0], words[1], database) + except arg_error, msg: + err('Line', lno, ':', msg) + + +print +print 'static struct PyMethodDef gl_methods[] = {' +for func in functions: + print '\t{"' + func + '", gl_' + func + '},' +print '\t{NULL, NULL} /* Sentinel */' +print '};' +print +print 'void' +print 'initgl()' +print '{' +print '\t(void) Py_InitModule("gl", gl_methods);' +print '}' diff --git a/sys/src/cmd/python/Modules/cgensupport.c b/sys/src/cmd/python/Modules/cgensupport.c new file mode 100644 index 000000000..7e7d0ff9f --- /dev/null +++ b/sys/src/cmd/python/Modules/cgensupport.c @@ -0,0 +1,310 @@ + +/* Functions used by cgen output */ + +#include "Python.h" +#include "cgensupport.h" + + +/* Functions to extract arguments. + These needs to know the total number of arguments supplied, + since the argument list is a tuple only of there is more than + one argument. */ + +int +PyArg_GetObject(register PyObject *args, int nargs, int i, PyObject **p_arg) +{ + if (nargs != 1) { + if (args == NULL || !PyTuple_Check(args) || + nargs != PyTuple_Size(args) || + i < 0 || i >= nargs) { + return PyErr_BadArgument(); + } + else { + args = PyTuple_GetItem(args, i); + } + } + if (args == NULL) { + return PyErr_BadArgument(); + } + *p_arg = args; + return 1; +} + +int +PyArg_GetLong(register PyObject *args, int nargs, int i, long *p_arg) +{ + if (nargs != 1) { + if (args == NULL || !PyTuple_Check(args) || + nargs != PyTuple_Size(args) || + i < 0 || i >= nargs) { + return PyErr_BadArgument(); + } + args = PyTuple_GetItem(args, i); + } + if (args == NULL || !PyInt_Check(args)) { + return PyErr_BadArgument(); + } + *p_arg = PyInt_AsLong(args); + return 1; +} + +int +PyArg_GetShort(register PyObject *args, int nargs, int i, short *p_arg) +{ + long x; + if (!PyArg_GetLong(args, nargs, i, &x)) + return 0; + *p_arg = (short) x; + return 1; +} + +static int +extractdouble(register PyObject *v, double *p_arg) +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (PyFloat_Check(v)) { + *p_arg = PyFloat_AS_DOUBLE((PyFloatObject *)v); + return 1; + } + else if (PyInt_Check(v)) { + *p_arg = PyInt_AS_LONG((PyIntObject *)v); + return 1; + } + else if (PyLong_Check(v)) { + *p_arg = PyLong_AsDouble(v); + return 1; + } + return PyErr_BadArgument(); +} + +static int +extractfloat(register PyObject *v, float *p_arg) +{ + if (v == NULL) { + /* Fall through to error return at end of function */ + } + else if (PyFloat_Check(v)) { + *p_arg = (float) PyFloat_AS_DOUBLE((PyFloatObject *)v); + return 1; + } + else if (PyInt_Check(v)) { + *p_arg = (float) PyInt_AS_LONG((PyIntObject *)v); + return 1; + } + else if (PyLong_Check(v)) { + *p_arg = (float) PyLong_AsDouble(v); + return 1; + } + return PyErr_BadArgument(); +} + +int +PyArg_GetFloat(register PyObject *args, int nargs, int i, float *p_arg) +{ + PyObject *v; + float x; + if (!PyArg_GetObject(args, nargs, i, &v)) + return 0; + if (!extractfloat(v, &x)) + return 0; + *p_arg = x; + return 1; +} + +int +PyArg_GetString(PyObject *args, int nargs, int i, string *p_arg) +{ + PyObject *v; + if (!PyArg_GetObject(args, nargs, i, &v)) + return 0; + if (!PyString_Check(v)) { + return PyErr_BadArgument(); + } + *p_arg = PyString_AsString(v); + return 1; +} + +int +PyArg_GetChar(PyObject *args, int nargs, int i, char *p_arg) +{ + string x; + if (!PyArg_GetString(args, nargs, i, &x)) + return 0; + if (x[0] == '\0' || x[1] != '\0') { + /* Not exactly one char */ + return PyErr_BadArgument(); + } + *p_arg = x[0]; + return 1; +} + +int +PyArg_GetLongArraySize(PyObject *args, int nargs, int i, long *p_arg) +{ + PyObject *v; + if (!PyArg_GetObject(args, nargs, i, &v)) + return 0; + if (PyTuple_Check(v)) { + *p_arg = PyTuple_Size(v); + return 1; + } + if (PyList_Check(v)) { + *p_arg = PyList_Size(v); + return 1; + } + return PyErr_BadArgument(); +} + +int +PyArg_GetShortArraySize(PyObject *args, int nargs, int i, short *p_arg) +{ + long x; + if (!PyArg_GetLongArraySize(args, nargs, i, &x)) + return 0; + *p_arg = (short) x; + return 1; +} + +/* XXX The following four are too similar. Should share more code. */ + +int +PyArg_GetLongArray(PyObject *args, int nargs, int i, int n, long *p_arg) +{ + PyObject *v, *w; + if (!PyArg_GetObject(args, nargs, i, &v)) + return 0; + if (PyTuple_Check(v)) { + if (PyTuple_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyTuple_GetItem(v, i); + if (!PyInt_Check(w)) { + return PyErr_BadArgument(); + } + p_arg[i] = PyInt_AsLong(w); + } + return 1; + } + else if (PyList_Check(v)) { + if (PyList_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyList_GetItem(v, i); + if (!PyInt_Check(w)) { + return PyErr_BadArgument(); + } + p_arg[i] = PyInt_AsLong(w); + } + return 1; + } + else { + return PyErr_BadArgument(); + } +} + +int +PyArg_GetShortArray(PyObject *args, int nargs, int i, int n, short *p_arg) +{ + PyObject *v, *w; + if (!PyArg_GetObject(args, nargs, i, &v)) + return 0; + if (PyTuple_Check(v)) { + if (PyTuple_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyTuple_GetItem(v, i); + if (!PyInt_Check(w)) { + return PyErr_BadArgument(); + } + p_arg[i] = (short) PyInt_AsLong(w); + } + return 1; + } + else if (PyList_Check(v)) { + if (PyList_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyList_GetItem(v, i); + if (!PyInt_Check(w)) { + return PyErr_BadArgument(); + } + p_arg[i] = (short) PyInt_AsLong(w); + } + return 1; + } + else { + return PyErr_BadArgument(); + } +} + +int +PyArg_GetDoubleArray(PyObject *args, int nargs, int i, int n, double *p_arg) +{ + PyObject *v, *w; + if (!PyArg_GetObject(args, nargs, i, &v)) + return 0; + if (PyTuple_Check(v)) { + if (PyTuple_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyTuple_GetItem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (PyList_Check(v)) { + if (PyList_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyList_GetItem(v, i); + if (!extractdouble(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return PyErr_BadArgument(); + } +} + +int +PyArg_GetFloatArray(PyObject *args, int nargs, int i, int n, float *p_arg) +{ + PyObject *v, *w; + if (!PyArg_GetObject(args, nargs, i, &v)) + return 0; + if (PyTuple_Check(v)) { + if (PyTuple_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyTuple_GetItem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else if (PyList_Check(v)) { + if (PyList_Size(v) != n) { + return PyErr_BadArgument(); + } + for (i = 0; i < n; i++) { + w = PyList_GetItem(v, i); + if (!extractfloat(w, &p_arg[i])) + return 0; + } + return 1; + } + else { + return PyErr_BadArgument(); + } +} diff --git a/sys/src/cmd/python/Modules/cgensupport.h b/sys/src/cmd/python/Modules/cgensupport.h new file mode 100644 index 000000000..bc901f6e8 --- /dev/null +++ b/sys/src/cmd/python/Modules/cgensupport.h @@ -0,0 +1,64 @@ +#ifndef Py_CGENSUPPORT_H +#define Py_CGENSUPPORT_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Definitions used by cgen output */ + +/* XXX This file is obsolete. It is *only* used by glmodule.c. */ + +typedef char *string; + +#define mknewlongobject(x) PyInt_FromLong(x) +#define mknewshortobject(x) PyInt_FromLong((long)x) +#define mknewfloatobject(x) PyFloat_FromDouble(x) +#define mknewcharobject(ch) Py_BuildValue("c", ch) + +#define getichararg PyArg_GetChar +#define getidoublearray PyArg_GetDoubleArray +#define getifloatarg PyArg_GetFloat +#define getifloatarray PyArg_GetFloatArray +#define getilongarg PyArg_GetLong +#define getilongarray PyArg_GetLongArray +#define getilongarraysize PyArg_GetLongArraySize +#define getiobjectarg PyArg_GetObject +#define getishortarg PyArg_GetShort +#define getishortarray PyArg_GetShortArray +#define getishortarraysize PyArg_GetShortArraySize +#define getistringarg PyArg_GetString + +extern int PyArg_GetObject(PyObject *args, int nargs, + int i, PyObject **p_a); +extern int PyArg_GetLong(PyObject *args, int nargs, + int i, long *p_a); +extern int PyArg_GetShort(PyObject *args, int nargs, + int i, short *p_a); +extern int PyArg_GetFloat(PyObject *args, int nargs, + int i, float *p_a); +extern int PyArg_GetString(PyObject *args, int nargs, + int i, string *p_a); +extern int PyArg_GetChar(PyObject *args, int nargs, + int i, char *p_a); +extern int PyArg_GetLongArray(PyObject *args, int nargs, + int i, int n, long *p_a); +extern int PyArg_GetShortArray(PyObject *args, int nargs, + int i, int n, short *p_a); +extern int PyArg_GetDoubleArray(PyObject *args, int nargs, + int i, int n, double *p_a); +extern int PyArg_GetFloatArray(PyObject *args, int nargs, + int i, int n, float *p_a); +extern int PyArg_GetLongArraySize(PyObject *args, int nargs, + int i, long *p_a); +extern int PyArg_GetShortArraySize(PyObject *args, int nargs, + int i, short *p_a); +extern int PyArg_GetDoubleArraySize(PyObject *args, int nargs, + int i, double *p_a); +extern int PyArg_GetFloatArraySize(PyObject *args, int nargs, + int i, float *p_a); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_CGENSUPPORT_H */ diff --git a/sys/src/cmd/python/Modules/cjkcodecs/README b/sys/src/cmd/python/Modules/cjkcodecs/README new file mode 100644 index 000000000..b2370bc29 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/README @@ -0,0 +1,79 @@ +To generate or modify mapping headers +------------------------------------- +Mapping headers are imported from CJKCodecs as pre-generated form. +If you need to tweak or add something on it, please look at tools/ +subdirectory of CJKCodecs' distribution. + + + +Notes on implmentation characteristics of each codecs +----------------------------------------------------- + +1) Big5 codec + + The big5 codec maps the following characters as cp950 does rather + than conforming Unicode.org's that maps to 0xFFFD. + + BIG5 Unicode Description + + 0xA15A 0x2574 SPACING UNDERSCORE + 0xA1C3 0xFFE3 SPACING HEAVY OVERSCORE + 0xA1C5 0x02CD SPACING HEAVY UNDERSCORE + 0xA1FE 0xFF0F LT DIAG UP RIGHT TO LOW LEFT + 0xA240 0xFF3C LT DIAG UP LEFT TO LOW RIGHT + 0xA2CC 0x5341 HANGZHOU NUMERAL TEN + 0xA2CE 0x5345 HANGZHOU NUMERAL THIRTY + + Because unicode 0x5341, 0x5345, 0xFF0F, 0xFF3C is mapped to another + big5 codes already, a roundtrip compatibility is not guaranteed for + them. + + +2) cp932 codec + + To conform to Windows's real mapping, cp932 codec maps the following + codepoints in addition of the official cp932 mapping. + + CP932 Unicode Description + + 0x80 0x80 UNDEFINED + 0xA0 0xF8F0 UNDEFINED + 0xFD 0xF8F1 UNDEFINED + 0xFE 0xF8F2 UNDEFINED + 0xFF 0xF8F3 UNDEFINED + + +3) euc-jisx0213 codec + + The euc-jisx0213 codec maps JIS X 0213 Plane 1 code 0x2140 into + unicode U+FF3C instead of U+005C as on unicode.org's mapping. + Because euc-jisx0213 has REVERSE SOLIDUS on 0x5c already and A140 + is shown as a full width character, mapping to U+FF3C can make + more sense. + + The euc-jisx0213 codec is enabled to decode JIS X 0212 codes on + codeset 2. Because JIS X 0212 and JIS X 0213 Plane 2 don't have + overlapped by each other, it doesn't bother standard conformations + (and JIS X 0213 Plane 2 is intended to use so.) On encoding + sessions, the codec will try to encode kanji characters in this + order: + + JIS X 0213 Plane 1 -> JIS X 0213 Plane 2 -> JIS X 0212 + + +4) euc-jp codec + + The euc-jp codec is a compatibility instance on these points: + - U+FF3C FULLWIDTH REVERSE SOLIDUS is mapped to EUC-JP A1C0 (vice versa) + - U+00A5 YEN SIGN is mapped to EUC-JP 0x5c. (one way) + - U+203E OVERLINE is mapped to EUC-JP 0x7e. (one way) + + +5) shift-jis codec + + The shift-jis codec is mapping 0x20-0x7e area to U+20-U+7E directly + instead of using JIS X 0201 for compatibility. The differences are: + - U+005C REVERSE SOLIDUS is mapped to SHIFT-JIS 0x5c. + - U+007E TILDE is mapped to SHIFT-JIS 0x7e. + - U+FF3C FULL-WIDTH REVERSE SOLIDUS is mapped to SHIFT-JIS 815f. + diff --git a/sys/src/cmd/python/Modules/cjkcodecs/_codecs_cn.c b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_cn.c new file mode 100644 index 000000000..c811a67ed --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_cn.c @@ -0,0 +1,443 @@ +/* + * _codecs_cn.c: Codecs collection for Mainland Chinese encodings + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#include "cjkcodecs.h" +#include "mappings_cn.h" + +/** + * hz is predefined as 100 on AIX. So we undefine it to avoid + * conflict against hz codec's. + */ +#ifdef _AIX +#undef hz +#endif + +/* GBK and GB2312 map differently in few codepoints that are listed below: + * + * gb2312 gbk + * A1A4 U+30FB KATAKANA MIDDLE DOT U+00B7 MIDDLE DOT + * A1AA U+2015 HORIZONTAL BAR U+2014 EM DASH + * A844 undefined U+2015 HORIZONTAL BAR + */ + +#define GBK_DECODE(dc1, dc2, assi) \ + if ((dc1) == 0xa1 && (dc2) == 0xaa) (assi) = 0x2014; \ + else if ((dc1) == 0xa8 && (dc2) == 0x44) (assi) = 0x2015; \ + else if ((dc1) == 0xa1 && (dc2) == 0xa4) (assi) = 0x00b7; \ + else TRYMAP_DEC(gb2312, assi, dc1 ^ 0x80, dc2 ^ 0x80); \ + else TRYMAP_DEC(gbkext, assi, dc1, dc2); + +#define GBK_ENCODE(code, assi) \ + if ((code) == 0x2014) (assi) = 0xa1aa; \ + else if ((code) == 0x2015) (assi) = 0xa844; \ + else if ((code) == 0x00b7) (assi) = 0xa1a4; \ + else if ((code) != 0x30fb && TRYMAP_ENC_COND(gbcommon, assi, code)); + +/* + * GB2312 codec + */ + +ENCODER(gb2312) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(gbcommon, code, c); + else return 1; + + if (code & 0x8000) /* MSB set: GBK */ + return 1; + + OUT1((code >> 8) | 0x80) + OUT2((code & 0xFF) | 0x80) + NEXT(1, 2) + } + + return 0; +} + +DECODER(gb2312) +{ + while (inleft > 0) { + unsigned char c = **inbuf; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + TRYMAP_DEC(gb2312, **outbuf, c ^ 0x80, IN2 ^ 0x80) { + NEXT(2, 1) + } + else return 2; + } + + return 0; +} + + +/* + * GBK codec + */ + +ENCODER(gbk) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + + GBK_ENCODE(c, code) + else return 1; + + OUT1((code >> 8) | 0x80) + if (code & 0x8000) + OUT2((code & 0xFF)) /* MSB set: GBK */ + else + OUT2((code & 0xFF) | 0x80) /* MSB unset: GB2312 */ + NEXT(1, 2) + } + + return 0; +} + +DECODER(gbk) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + GBK_DECODE(c, IN2, **outbuf) + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * GB18030 codec + */ + +ENCODER(gb18030) +{ + while (inleft > 0) { + ucs4_t c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1(c) + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + if (c > 0x10FFFF) +#if Py_UNICODE_SIZE == 2 + return 2; /* surrogates pair */ +#else + return 1; +#endif + else if (c >= 0x10000) { + ucs4_t tc = c - 0x10000; + + REQUIRE_OUTBUF(4) + + OUT4((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT3((unsigned char)(tc % 126) + 0x81) + tc /= 126; + OUT2((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT1((unsigned char)(tc + 0x90)) + +#if Py_UNICODE_SIZE == 2 + NEXT(2, 4) /* surrogates pair */ +#else + NEXT(1, 4) +#endif + continue; + } + + REQUIRE_OUTBUF(2) + + GBK_ENCODE(c, code) + else { + const struct _gb18030_to_unibmp_ranges *utrrange; + + REQUIRE_OUTBUF(4) + + for (utrrange = gb18030_to_unibmp_ranges; + utrrange->first != 0; + utrrange++) + if (utrrange->first <= c && + c <= utrrange->last) { + Py_UNICODE tc; + + tc = c - utrrange->first + + utrrange->base; + + OUT4((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT3((unsigned char)(tc % 126) + 0x81) + tc /= 126; + OUT2((unsigned char)(tc % 10) + 0x30) + tc /= 10; + OUT1((unsigned char)tc + 0x81) + + NEXT(1, 4) + break; + } + + if (utrrange->first == 0) + return 1; + continue; + } + + OUT1((code >> 8) | 0x80) + if (code & 0x8000) + OUT2((code & 0xFF)) /* MSB set: GBK or GB18030ext */ + else + OUT2((code & 0xFF) | 0x80) /* MSB unset: GB2312 */ + + NEXT(1, 2) + } + + return 0; +} + +DECODER(gb18030) +{ + while (inleft > 0) { + unsigned char c = IN1, c2; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + c2 = IN2; + if (c2 >= 0x30 && c2 <= 0x39) { /* 4 bytes seq */ + const struct _gb18030_to_unibmp_ranges *utr; + unsigned char c3, c4; + ucs4_t lseq; + + REQUIRE_INBUF(4) + c3 = IN3; + c4 = IN4; + if (c < 0x81 || c3 < 0x81 || c4 < 0x30 || c4 > 0x39) + return 4; + c -= 0x81; c2 -= 0x30; + c3 -= 0x81; c4 -= 0x30; + + if (c < 4) { /* U+0080 - U+FFFF */ + lseq = ((ucs4_t)c * 10 + c2) * 1260 + + (ucs4_t)c3 * 10 + c4; + if (lseq < 39420) { + for (utr = gb18030_to_unibmp_ranges; + lseq >= (utr + 1)->base; + utr++) ; + OUT1(utr->first - utr->base + lseq) + NEXT(4, 1) + continue; + } + } + else if (c >= 15) { /* U+10000 - U+10FFFF */ + lseq = 0x10000 + (((ucs4_t)c-15) * 10 + c2) + * 1260 + (ucs4_t)c3 * 10 + c4; + if (lseq <= 0x10FFFF) { + WRITEUCS4(lseq); + NEXT_IN(4) + continue; + } + } + return 4; + } + + GBK_DECODE(c, c2, **outbuf) + else TRYMAP_DEC(gb18030ext, **outbuf, c, c2); + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * HZ codec + */ + +ENCODER_INIT(hz) +{ + state->i = 0; + return 0; +} + +ENCODER_RESET(hz) +{ + if (state->i != 0) { + WRITE2('~', '}') + state->i = 0; + NEXT_OUT(2) + } + return 0; +} + +ENCODER(hz) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + if (state->i == 0) { + WRITE1((unsigned char)c) + NEXT(1, 1) + } + else { + WRITE3('~', '}', (unsigned char)c) + NEXT(1, 3) + state->i = 0; + } + continue; + } + + UCS4INVALID(c) + + TRYMAP_ENC(gbcommon, code, c); + else return 1; + + if (code & 0x8000) /* MSB set: GBK */ + return 1; + + if (state->i == 0) { + WRITE4('~', '{', code >> 8, code & 0xff) + NEXT(1, 4) + state->i = 1; + } + else { + WRITE2(code >> 8, code & 0xff) + NEXT(1, 2) + } + } + + return 0; +} + +DECODER_INIT(hz) +{ + state->i = 0; + return 0; +} + +DECODER_RESET(hz) +{ + state->i = 0; + return 0; +} + +DECODER(hz) +{ + while (inleft > 0) { + unsigned char c = IN1; + + if (c == '~') { + unsigned char c2 = IN2; + + REQUIRE_INBUF(2) + if (c2 == '~') { + WRITE1('~') + NEXT(2, 1) + continue; + } + else if (c2 == '{' && state->i == 0) + state->i = 1; /* set GB */ + else if (c2 == '}' && state->i == 1) + state->i = 0; /* set ASCII */ + else if (c2 == '\n') + ; /* line-continuation */ + else + return 2; + NEXT(2, 0); + continue; + } + + if (c & 0x80) + return 1; + + if (state->i == 0) { /* ASCII mode */ + WRITE1(c) + NEXT(1, 1) + } + else { /* GB mode */ + REQUIRE_INBUF(2) + REQUIRE_OUTBUF(1) + TRYMAP_DEC(gb2312, **outbuf, c, IN2) { + NEXT(2, 1) + } + else + return 2; + } + } + + return 0; +} + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(gb2312) + MAPPING_DECONLY(gbkext) + MAPPING_ENCONLY(gbcommon) + MAPPING_ENCDEC(gb18030ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(gb2312) + CODEC_STATELESS(gbk) + CODEC_STATELESS(gb18030) + CODEC_STATEFUL(hz) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(cn) diff --git a/sys/src/cmd/python/Modules/cjkcodecs/_codecs_hk.c b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_hk.c new file mode 100644 index 000000000..221eced3c --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_hk.c @@ -0,0 +1,143 @@ +/* + * _codecs_hk.c: Codecs collection for encodings from Hong Kong + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#define USING_IMPORTED_MAPS + +#include "cjkcodecs.h" +#include "mappings_hk.h" + +/* + * BIG5HKSCS codec + */ + +static const encode_map *big5_encmap = NULL; +static const decode_map *big5_decmap = NULL; + +CODEC_INIT(big5hkscs) +{ + static int initialized = 0; + + if (!initialized && IMPORT_MAP(tw, big5, &big5_encmap, &big5_decmap)) + return -1; + initialized = 1; + return 0; +} + +ENCODER(big5hkscs) +{ + while (inleft > 0) { + ucs4_t c = **inbuf; + DBCHAR code; + Py_ssize_t insize; + + if (c < 0x80) { + REQUIRE_OUTBUF(1) + **outbuf = (unsigned char)c; + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + insize = GET_INSIZE(c); + + REQUIRE_OUTBUF(2) + + if (c < 0x10000) { + TRYMAP_ENC(big5hkscs_bmp, code, c); + else TRYMAP_ENC(big5, code, c); + else return 1; + } + else if (c < 0x20000) + return insize; + else if (c < 0x30000) { + TRYMAP_ENC(big5hkscs_nonbmp, code, c & 0xffff); + else return insize; + } + else + return insize; + + OUT1(code >> 8) + OUT2(code & 0xFF) + NEXT(insize, 2) + } + + return 0; +} + +#define BH2S(c1, c2) (((c1) - 0x88) * (0xfe - 0x40 + 1) + ((c2) - 0x40)) + +DECODER(big5hkscs) +{ + while (inleft > 0) { + unsigned char c = IN1; + ucs4_t decoded; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + if (0xc6 <= c && c <= 0xc8 && (c >= 0xc7 || IN2 >= 0xa1)) + goto hkscsdec; + + TRYMAP_DEC(big5, **outbuf, c, IN2) { + NEXT(2, 1) + } + else +hkscsdec: TRYMAP_DEC(big5hkscs, decoded, c, IN2) { + int s = BH2S(c, IN2); + const unsigned char *hintbase; + + assert(0x88 <= c && c <= 0xfe); + assert(0x40 <= IN2 && IN2 <= 0xfe); + + if (BH2S(0x88, 0x40) <= s && s <= BH2S(0xa0, 0xfe)) { + hintbase = big5hkscs_phint_0; + s -= BH2S(0x88, 0x40); + } + else if (BH2S(0xc6,0xa1) <= s && s <= BH2S(0xc8,0xfe)){ + hintbase = big5hkscs_phint_11939; + s -= BH2S(0xc6, 0xa1); + } + else if (BH2S(0xf9,0xd6) <= s && s <= BH2S(0xfe,0xfe)){ + hintbase = big5hkscs_phint_21733; + s -= BH2S(0xf9, 0xd6); + } + else + return MBERR_INTERNAL; + + if (hintbase[s >> 3] & (1 << (s & 7))) { + WRITEUCS4(decoded | 0x20000) + NEXT_IN(2) + } + else { + OUT1(decoded) + NEXT(2, 1) + } + } + else return 2; + } + + return 0; +} + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(big5hkscs) + MAPPING_ENCONLY(big5hkscs_bmp) + MAPPING_ENCONLY(big5hkscs_nonbmp) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS_WINIT(big5hkscs) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(hk) diff --git a/sys/src/cmd/python/Modules/cjkcodecs/_codecs_iso2022.c b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_iso2022.c new file mode 100644 index 000000000..55196a9ea --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_iso2022.c @@ -0,0 +1,1131 @@ +/* + * _codecs_iso2022.c: Codecs collection for ISO-2022 encodings. + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#define USING_IMPORTED_MAPS +#define USING_BINARY_PAIR_SEARCH +#define EXTERN_JISX0213_PAIR +#define EMULATE_JISX0213_2000_ENCODE_INVALID MAP_UNMAPPABLE +#define EMULATE_JISX0213_2000_DECODE_INVALID MAP_UNMAPPABLE + +#include "cjkcodecs.h" +#include "alg_jisx0201.h" +#include "emu_jisx0213_2000.h" +#include "mappings_jisx0213_pair.h" + +/* STATE + + state->c[0-3] + + 00000000 + ||^^^^^| + |+-----+---- G0-3 Character Set + +----------- Is G0-3 double byte? + + state->c[4] + + 00000000 + || + |+---- Locked-Shift? + +----- ESC Throughout +*/ + +#define ESC 0x1B +#define SO 0x0E +#define SI 0x0F +#define LF 0x0A + +#define MAX_ESCSEQLEN 16 + +#define CHARSET_ISO8859_1 'A' +#define CHARSET_ASCII 'B' +#define CHARSET_ISO8859_7 'F' +#define CHARSET_JISX0201_K 'I' +#define CHARSET_JISX0201_R 'J' + +#define CHARSET_GB2312 ('A'|CHARSET_DBCS) +#define CHARSET_JISX0208 ('B'|CHARSET_DBCS) +#define CHARSET_KSX1001 ('C'|CHARSET_DBCS) +#define CHARSET_JISX0212 ('D'|CHARSET_DBCS) +#define CHARSET_GB2312_8565 ('E'|CHARSET_DBCS) +#define CHARSET_CNS11643_1 ('G'|CHARSET_DBCS) +#define CHARSET_CNS11643_2 ('H'|CHARSET_DBCS) +#define CHARSET_JISX0213_2000_1 ('O'|CHARSET_DBCS) +#define CHARSET_JISX0213_2 ('P'|CHARSET_DBCS) +#define CHARSET_JISX0213_2004_1 ('Q'|CHARSET_DBCS) +#define CHARSET_JISX0208_O ('@'|CHARSET_DBCS) + +#define CHARSET_DBCS 0x80 +#define ESCMARK(mark) ((mark) & 0x7f) + +#define IS_ESCEND(c) (((c) >= 'A' && (c) <= 'Z') || (c) == '@') +#define IS_ISO2022ESC(c2) \ + ((c2) == '(' || (c2) == ')' || (c2) == '$' || \ + (c2) == '.' || (c2) == '&') + /* this is not a complete list of ISO-2022 escape sequence headers. + * but, it's enough to implement CJK instances of iso-2022. */ + +#define MAP_UNMAPPABLE 0xFFFF +#define MAP_MULTIPLE_AVAIL 0xFFFE /* for JIS X 0213 */ + +#define F_SHIFTED 0x01 +#define F_ESCTHROUGHOUT 0x02 + +#define STATE_SETG(dn, v) ((state)->c[dn]) = (v); +#define STATE_GETG(dn) ((state)->c[dn]) + +#define STATE_G0 STATE_GETG(0) +#define STATE_G1 STATE_GETG(1) +#define STATE_G2 STATE_GETG(2) +#define STATE_G3 STATE_GETG(3) +#define STATE_SETG0(v) STATE_SETG(0, v) +#define STATE_SETG1(v) STATE_SETG(1, v) +#define STATE_SETG2(v) STATE_SETG(2, v) +#define STATE_SETG3(v) STATE_SETG(3, v) + +#define STATE_SETFLAG(f) ((state)->c[4]) |= (f); +#define STATE_GETFLAG(f) ((state)->c[4] & (f)) +#define STATE_CLEARFLAG(f) ((state)->c[4]) &= ~(f); +#define STATE_CLEARFLAGS() ((state)->c[4]) = 0; + +#define ISO2022_CONFIG ((const struct iso2022_config *)config) +#define CONFIG_ISSET(flag) (ISO2022_CONFIG->flags & (flag)) +#define CONFIG_DESIGNATIONS (ISO2022_CONFIG->designations) + +/* iso2022_config.flags */ +#define NO_SHIFT 0x01 +#define USE_G2 0x02 +#define USE_JISX0208_EXT 0x04 + +/*-*- internal data structures -*-*/ + +typedef int (*iso2022_init_func)(void); +typedef ucs4_t (*iso2022_decode_func)(const unsigned char *data); +typedef DBCHAR (*iso2022_encode_func)(const ucs4_t *data, Py_ssize_t *length); + +struct iso2022_designation { + unsigned char mark; + unsigned char plane; + unsigned char width; + iso2022_init_func initializer; + iso2022_decode_func decoder; + iso2022_encode_func encoder; +}; + +struct iso2022_config { + int flags; + const struct iso2022_designation *designations; /* non-ascii desigs */ +}; + +/*-*- iso-2022 codec implementation -*-*/ + +CODEC_INIT(iso2022) +{ + const struct iso2022_designation *desig = CONFIG_DESIGNATIONS; + for (desig = CONFIG_DESIGNATIONS; desig->mark; desig++) + if (desig->initializer != NULL && desig->initializer() != 0) + return -1; + return 0; +} + +ENCODER_INIT(iso2022) +{ + STATE_CLEARFLAGS() + STATE_SETG0(CHARSET_ASCII) + STATE_SETG1(CHARSET_ASCII) + return 0; +} + +ENCODER_RESET(iso2022) +{ + if (STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SI) + NEXT_OUT(1) + STATE_CLEARFLAG(F_SHIFTED) + } + if (STATE_G0 != CHARSET_ASCII) { + WRITE3(ESC, '(', 'B') + NEXT_OUT(3) + STATE_SETG0(CHARSET_ASCII) + } + return 0; +} + +ENCODER(iso2022) +{ + while (inleft > 0) { + const struct iso2022_designation *dsg; + DBCHAR encoded; + ucs4_t c = **inbuf; + Py_ssize_t insize; + + if (c < 0x80) { + if (STATE_G0 != CHARSET_ASCII) { + WRITE3(ESC, '(', 'B') + STATE_SETG0(CHARSET_ASCII) + NEXT_OUT(3) + } + if (STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SI) + STATE_CLEARFLAG(F_SHIFTED) + NEXT_OUT(1) + } + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + insize = GET_INSIZE(c); + + encoded = MAP_UNMAPPABLE; + for (dsg = CONFIG_DESIGNATIONS; dsg->mark; dsg++) { + Py_ssize_t length = 1; + encoded = dsg->encoder(&c, &length); + if (encoded == MAP_MULTIPLE_AVAIL) { + /* this implementation won't work for pair + * of non-bmp characters. */ + if (inleft < 2) { + if (!(flags & MBENC_FLUSH)) + return MBERR_TOOFEW; + length = -1; + } + else + length = 2; +#if Py_UNICODE_SIZE == 2 + if (length == 2) { + ucs4_t u4in[2]; + u4in[0] = (ucs4_t)IN1; + u4in[1] = (ucs4_t)IN2; + encoded = dsg->encoder(u4in, &length); + } else + encoded = dsg->encoder(&c, &length); +#else + encoded = dsg->encoder(*inbuf, &length); +#endif + if (encoded != MAP_UNMAPPABLE) { + insize = length; + break; + } + } + else if (encoded != MAP_UNMAPPABLE) + break; + } + + if (!dsg->mark) + return 1; + assert(dsg->width == 1 || dsg->width == 2); + + switch (dsg->plane) { + case 0: /* G0 */ + if (STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SI) + STATE_CLEARFLAG(F_SHIFTED) + NEXT_OUT(1) + } + if (STATE_G0 != dsg->mark) { + if (dsg->width == 1) { + WRITE3(ESC, '(', ESCMARK(dsg->mark)) + STATE_SETG0(dsg->mark) + NEXT_OUT(3) + } + else if (dsg->mark == CHARSET_JISX0208) { + WRITE3(ESC, '$', ESCMARK(dsg->mark)) + STATE_SETG0(dsg->mark) + NEXT_OUT(3) + } + else { + WRITE4(ESC, '$', '(', + ESCMARK(dsg->mark)) + STATE_SETG0(dsg->mark) + NEXT_OUT(4) + } + } + break; + case 1: /* G1 */ + if (STATE_G1 != dsg->mark) { + if (dsg->width == 1) { + WRITE3(ESC, ')', ESCMARK(dsg->mark)) + STATE_SETG1(dsg->mark) + NEXT_OUT(3) + } + else { + WRITE4(ESC, '$', ')', + ESCMARK(dsg->mark)) + STATE_SETG1(dsg->mark) + NEXT_OUT(4) + } + } + if (!STATE_GETFLAG(F_SHIFTED)) { + WRITE1(SO) + STATE_SETFLAG(F_SHIFTED) + NEXT_OUT(1) + } + break; + default: /* G2 and G3 is not supported: no encoding in + * CJKCodecs are using them yet */ + return MBERR_INTERNAL; + } + + if (dsg->width == 1) { + WRITE1((unsigned char)encoded) + NEXT_OUT(1) + } + else { + WRITE2(encoded >> 8, encoded & 0xff) + NEXT_OUT(2) + } + NEXT_IN(insize) + } + + return 0; +} + +DECODER_INIT(iso2022) +{ + STATE_CLEARFLAGS() + STATE_SETG0(CHARSET_ASCII) + STATE_SETG1(CHARSET_ASCII) + STATE_SETG2(CHARSET_ASCII) + return 0; +} + +DECODER_RESET(iso2022) +{ + STATE_SETG0(CHARSET_ASCII) + STATE_CLEARFLAG(F_SHIFTED) + return 0; +} + +static Py_ssize_t +iso2022processesc(const void *config, MultibyteCodec_State *state, + const unsigned char **inbuf, Py_ssize_t *inleft) +{ + unsigned char charset, designation; + Py_ssize_t i, esclen; + + for (i = 1;i < MAX_ESCSEQLEN;i++) { + if (i >= *inleft) + return MBERR_TOOFEW; + if (IS_ESCEND((*inbuf)[i])) { + esclen = i + 1; + break; + } + else if (CONFIG_ISSET(USE_JISX0208_EXT) && i+1 < *inleft && + (*inbuf)[i] == '&' && (*inbuf)[i+1] == '@') + i += 2; + } + + if (i >= MAX_ESCSEQLEN) + return 1; /* unterminated escape sequence */ + + switch (esclen) { + case 3: + if (IN2 == '$') { + charset = IN3 | CHARSET_DBCS; + designation = 0; + } + else { + charset = IN3; + if (IN2 == '(') designation = 0; + else if (IN2 == ')') designation = 1; + else if (CONFIG_ISSET(USE_G2) && IN2 == '.') + designation = 2; + else return 3; + } + break; + case 4: + if (IN2 != '$') + return 4; + + charset = IN4 | CHARSET_DBCS; + if (IN3 == '(') designation = 0; + else if (IN3 == ')') designation = 1; + else return 4; + break; + case 6: /* designation with prefix */ + if (CONFIG_ISSET(USE_JISX0208_EXT) && + (*inbuf)[3] == ESC && (*inbuf)[4] == '$' && + (*inbuf)[5] == 'B') { + charset = 'B' | CHARSET_DBCS; + designation = 0; + } + else + return 6; + break; + default: + return esclen; + } + + /* raise error when the charset is not designated for this encoding */ + if (charset != CHARSET_ASCII) { + const struct iso2022_designation *dsg; + + for (dsg = CONFIG_DESIGNATIONS; dsg->mark; dsg++) + if (dsg->mark == charset) + break; + if (!dsg->mark) + return esclen; + } + + STATE_SETG(designation, charset) + *inleft -= esclen; + (*inbuf) += esclen; + return 0; +} + +#define ISO8859_7_DECODE(c, assi) \ + if ((c) < 0xa0) (assi) = (c); \ + else if ((c) < 0xc0 && (0x288f3bc9L & (1L << ((c)-0xa0)))) \ + (assi) = (c); \ + else if ((c) >= 0xb4 && (c) <= 0xfe && ((c) >= 0xd4 || \ + (0xbffffd77L & (1L << ((c)-0xb4))))) \ + (assi) = 0x02d0 + (c); \ + else if ((c) == 0xa1) (assi) = 0x2018; \ + else if ((c) == 0xa2) (assi) = 0x2019; \ + else if ((c) == 0xaf) (assi) = 0x2015; + +static Py_ssize_t +iso2022processg2(const void *config, MultibyteCodec_State *state, + const unsigned char **inbuf, Py_ssize_t *inleft, + Py_UNICODE **outbuf, Py_ssize_t *outleft) +{ + /* not written to use encoder, decoder functions because only few + * encodings use G2 designations in CJKCodecs */ + if (STATE_G2 == CHARSET_ISO8859_1) { + if (IN3 < 0x80) + OUT1(IN3 + 0x80) + else + return 3; + } + else if (STATE_G2 == CHARSET_ISO8859_7) { + ISO8859_7_DECODE(IN3 ^ 0x80, **outbuf) + else return 3; + } + else if (STATE_G2 == CHARSET_ASCII) { + if (IN3 & 0x80) return 3; + else **outbuf = IN3; + } + else + return MBERR_INTERNAL; + + (*inbuf) += 3; + *inleft -= 3; + (*outbuf) += 1; + *outleft -= 1; + return 0; +} + +DECODER(iso2022) +{ + const struct iso2022_designation *dsgcache = NULL; + + while (inleft > 0) { + unsigned char c = IN1; + Py_ssize_t err; + + if (STATE_GETFLAG(F_ESCTHROUGHOUT)) { + /* ESC throughout mode: + * for non-iso2022 escape sequences */ + WRITE1(c) /* assume as ISO-8859-1 */ + NEXT(1, 1) + if (IS_ESCEND(c)) { + STATE_CLEARFLAG(F_ESCTHROUGHOUT) + } + continue; + } + + switch (c) { + case ESC: + REQUIRE_INBUF(2) + if (IS_ISO2022ESC(IN2)) { + err = iso2022processesc(config, state, + inbuf, &inleft); + if (err != 0) + return err; + } + else if (CONFIG_ISSET(USE_G2) && IN2 == 'N') {/* SS2 */ + REQUIRE_INBUF(3) + err = iso2022processg2(config, state, + inbuf, &inleft, outbuf, &outleft); + if (err != 0) + return err; + } + else { + WRITE1(ESC) + STATE_SETFLAG(F_ESCTHROUGHOUT) + NEXT(1, 1) + } + break; + case SI: + if (CONFIG_ISSET(NO_SHIFT)) + goto bypass; + STATE_CLEARFLAG(F_SHIFTED) + NEXT_IN(1) + break; + case SO: + if (CONFIG_ISSET(NO_SHIFT)) + goto bypass; + STATE_SETFLAG(F_SHIFTED) + NEXT_IN(1) + break; + case LF: + STATE_CLEARFLAG(F_SHIFTED) + WRITE1(LF) + NEXT(1, 1) + break; + default: + if (c < 0x20) /* C0 */ + goto bypass; + else if (c >= 0x80) + return 1; + else { + const struct iso2022_designation *dsg; + unsigned char charset; + ucs4_t decoded; + + if (STATE_GETFLAG(F_SHIFTED)) + charset = STATE_G1; + else + charset = STATE_G0; + + if (charset == CHARSET_ASCII) { +bypass: WRITE1(c) + NEXT(1, 1) + break; + } + + if (dsgcache != NULL && + dsgcache->mark == charset) + dsg = dsgcache; + else { + for (dsg = CONFIG_DESIGNATIONS; + dsg->mark != charset +#ifdef Py_DEBUG + && dsg->mark != '\0' +#endif + ;dsg++) + /* noop */; + assert(dsg->mark != '\0'); + dsgcache = dsg; + } + + REQUIRE_INBUF(dsg->width) + decoded = dsg->decoder(*inbuf); + if (decoded == MAP_UNMAPPABLE) + return dsg->width; + + if (decoded < 0x10000) { + WRITE1(decoded) + NEXT_OUT(1) + } + else if (decoded < 0x30000) { + WRITEUCS4(decoded) + } + else { /* JIS X 0213 pairs */ + WRITE2(decoded >> 16, decoded & 0xffff) + NEXT_OUT(2) + } + NEXT_IN(dsg->width) + } + break; + } + } + return 0; +} + +/*-*- mapping table holders -*-*/ + +#define ENCMAP(enc) static const encode_map *enc##_encmap = NULL; +#define DECMAP(enc) static const decode_map *enc##_decmap = NULL; + +/* kr */ +ENCMAP(cp949) +DECMAP(ksx1001) + +/* jp */ +ENCMAP(jisxcommon) +DECMAP(jisx0208) +DECMAP(jisx0212) +ENCMAP(jisx0213_bmp) +DECMAP(jisx0213_1_bmp) +DECMAP(jisx0213_2_bmp) +ENCMAP(jisx0213_emp) +DECMAP(jisx0213_1_emp) +DECMAP(jisx0213_2_emp) + +/* cn */ +ENCMAP(gbcommon) +DECMAP(gb2312) + +/* tw */ + +/*-*- mapping access functions -*-*/ + +static int +ksx1001_init(void) +{ + static int initialized = 0; + + if (!initialized && ( + IMPORT_MAP(kr, cp949, &cp949_encmap, NULL) || + IMPORT_MAP(kr, ksx1001, NULL, &ksx1001_decmap))) + return -1; + initialized = 1; + return 0; +} + +static ucs4_t +ksx1001_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(ksx1001, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +ksx1001_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + TRYMAP_ENC(cp949, coded, *data) + if (!(coded & 0x8000)) + return coded; + } + return MAP_UNMAPPABLE; +} + +static int +jisx0208_init(void) +{ + static int initialized = 0; + + if (!initialized && ( + IMPORT_MAP(jp, jisxcommon, &jisxcommon_encmap, NULL) || + IMPORT_MAP(jp, jisx0208, NULL, &jisx0208_decmap))) + return -1; + initialized = 1; + return 0; +} + +static ucs4_t +jisx0208_decoder(const unsigned char *data) +{ + ucs4_t u; + if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */ + return 0xff3c; + else TRYMAP_DEC(jisx0208, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +jisx0208_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + if (*data == 0xff3c) /* F/W REVERSE SOLIDUS */ + return 0x2140; + else TRYMAP_ENC(jisxcommon, coded, *data) { + if (!(coded & 0x8000)) + return coded; + } + } + return MAP_UNMAPPABLE; +} + +static int +jisx0212_init(void) +{ + static int initialized = 0; + + if (!initialized && ( + IMPORT_MAP(jp, jisxcommon, &jisxcommon_encmap, NULL) || + IMPORT_MAP(jp, jisx0212, NULL, &jisx0212_decmap))) + return -1; + initialized = 1; + return 0; +} + +static ucs4_t +jisx0212_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(jisx0212, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +jisx0212_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + TRYMAP_ENC(jisxcommon, coded, *data) { + if (coded & 0x8000) + return coded & 0x7fff; + } + } + return MAP_UNMAPPABLE; +} + +static int +jisx0213_init(void) +{ + static int initialized = 0; + + if (!initialized && ( + jisx0208_init() || + IMPORT_MAP(jp, jisx0213_bmp, + &jisx0213_bmp_encmap, NULL) || + IMPORT_MAP(jp, jisx0213_1_bmp, + NULL, &jisx0213_1_bmp_decmap) || + IMPORT_MAP(jp, jisx0213_2_bmp, + NULL, &jisx0213_2_bmp_decmap) || + IMPORT_MAP(jp, jisx0213_emp, + &jisx0213_emp_encmap, NULL) || + IMPORT_MAP(jp, jisx0213_1_emp, + NULL, &jisx0213_1_emp_decmap) || + IMPORT_MAP(jp, jisx0213_2_emp, + NULL, &jisx0213_2_emp_decmap) || + IMPORT_MAP(jp, jisx0213_pair, &jisx0213_pair_encmap, + &jisx0213_pair_decmap))) + return -1; + initialized = 1; + return 0; +} + +#define config ((void *)2000) +static ucs4_t +jisx0213_2000_1_decoder(const unsigned char *data) +{ + ucs4_t u; + EMULATE_JISX0213_2000_DECODE_PLANE1(u, data[0], data[1]) + else if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */ + return 0xff3c; + else TRYMAP_DEC(jisx0208, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_emp, u, data[0], data[1]) + u |= 0x20000; + else TRYMAP_DEC(jisx0213_pair, u, data[0], data[1]); + else + return MAP_UNMAPPABLE; + return u; +} + +static ucs4_t +jisx0213_2000_2_decoder(const unsigned char *data) +{ + ucs4_t u; + EMULATE_JISX0213_2000_DECODE_PLANE2(u, data[0], data[1]) + TRYMAP_DEC(jisx0213_2_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_2_emp, u, data[0], data[1]) + u |= 0x20000; + else + return MAP_UNMAPPABLE; + return u; +} +#undef config + +static ucs4_t +jisx0213_2004_1_decoder(const unsigned char *data) +{ + ucs4_t u; + if (data[0] == 0x21 && data[1] == 0x40) /* F/W REVERSE SOLIDUS */ + return 0xff3c; + else TRYMAP_DEC(jisx0208, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_1_emp, u, data[0], data[1]) + u |= 0x20000; + else TRYMAP_DEC(jisx0213_pair, u, data[0], data[1]); + else + return MAP_UNMAPPABLE; + return u; +} + +static ucs4_t +jisx0213_2004_2_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(jisx0213_2_bmp, u, data[0], data[1]); + else TRYMAP_DEC(jisx0213_2_emp, u, data[0], data[1]) + u |= 0x20000; + else + return MAP_UNMAPPABLE; + return u; +} + +static DBCHAR +jisx0213_encoder(const ucs4_t *data, Py_ssize_t *length, void *config) +{ + DBCHAR coded; + + switch (*length) { + case 1: /* first character */ + if (*data >= 0x10000) { + if ((*data) >> 16 == 0x20000 >> 16) { + EMULATE_JISX0213_2000_ENCODE_EMP(coded, *data) + else TRYMAP_ENC(jisx0213_emp, coded, + (*data) & 0xffff) + return coded; + } + return MAP_UNMAPPABLE; + } + + EMULATE_JISX0213_2000_ENCODE_BMP(coded, *data) + else TRYMAP_ENC(jisx0213_bmp, coded, *data) { + if (coded == MULTIC) + return MAP_MULTIPLE_AVAIL; + } + else TRYMAP_ENC(jisxcommon, coded, *data) { + if (coded & 0x8000) + return MAP_UNMAPPABLE; + } + else + return MAP_UNMAPPABLE; + return coded; + case 2: /* second character of unicode pair */ + coded = find_pairencmap((ucs2_t)data[0], (ucs2_t)data[1], + jisx0213_pair_encmap, JISX0213_ENCPAIRS); + if (coded == DBCINV) { + *length = 1; + coded = find_pairencmap((ucs2_t)data[0], 0, + jisx0213_pair_encmap, JISX0213_ENCPAIRS); + if (coded == DBCINV) + return MAP_UNMAPPABLE; + } + else + return coded; + case -1: /* flush unterminated */ + *length = 1; + coded = find_pairencmap((ucs2_t)data[0], 0, + jisx0213_pair_encmap, JISX0213_ENCPAIRS); + if (coded == DBCINV) + return MAP_UNMAPPABLE; + else + return coded; + default: + return MAP_UNMAPPABLE; + } +} + +static DBCHAR +jisx0213_2000_1_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, (void *)2000); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return MAP_UNMAPPABLE; + else + return coded; +} + +static DBCHAR +jisx0213_2000_1_encoder_paironly(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + Py_ssize_t ilength = *length; + + coded = jisx0213_encoder(data, length, (void *)2000); + switch (ilength) { + case 1: + if (coded == MAP_MULTIPLE_AVAIL) + return MAP_MULTIPLE_AVAIL; + else + return MAP_UNMAPPABLE; + case 2: + if (*length != 2) + return MAP_UNMAPPABLE; + else + return coded; + default: + return MAP_UNMAPPABLE; + } +} + +static DBCHAR +jisx0213_2000_2_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, (void *)2000); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return coded & 0x7fff; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +jisx0213_2004_1_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, NULL); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return MAP_UNMAPPABLE; + else + return coded; +} + +static DBCHAR +jisx0213_2004_1_encoder_paironly(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + Py_ssize_t ilength = *length; + + coded = jisx0213_encoder(data, length, NULL); + switch (ilength) { + case 1: + if (coded == MAP_MULTIPLE_AVAIL) + return MAP_MULTIPLE_AVAIL; + else + return MAP_UNMAPPABLE; + case 2: + if (*length != 2) + return MAP_UNMAPPABLE; + else + return coded; + default: + return MAP_UNMAPPABLE; + } +} + +static DBCHAR +jisx0213_2004_2_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded = jisx0213_encoder(data, length, NULL); + if (coded == MAP_UNMAPPABLE || coded == MAP_MULTIPLE_AVAIL) + return coded; + else if (coded & 0x8000) + return coded & 0x7fff; + else + return MAP_UNMAPPABLE; +} + +static ucs4_t +jisx0201_r_decoder(const unsigned char *data) +{ + ucs4_t u; + JISX0201_R_DECODE(*data, u) + else return MAP_UNMAPPABLE; + return u; +} + +static DBCHAR +jisx0201_r_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + JISX0201_R_ENCODE(*data, coded) + else return MAP_UNMAPPABLE; + return coded; +} + +static ucs4_t +jisx0201_k_decoder(const unsigned char *data) +{ + ucs4_t u; + JISX0201_K_DECODE(*data ^ 0x80, u) + else return MAP_UNMAPPABLE; + return u; +} + +static DBCHAR +jisx0201_k_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + JISX0201_K_ENCODE(*data, coded) + else return MAP_UNMAPPABLE; + return coded - 0x80; +} + +static int +gb2312_init(void) +{ + static int initialized = 0; + + if (!initialized && ( + IMPORT_MAP(cn, gbcommon, &gbcommon_encmap, NULL) || + IMPORT_MAP(cn, gb2312, NULL, &gb2312_decmap))) + return -1; + initialized = 1; + return 0; +} + +static ucs4_t +gb2312_decoder(const unsigned char *data) +{ + ucs4_t u; + TRYMAP_DEC(gb2312, u, data[0], data[1]) + return u; + else + return MAP_UNMAPPABLE; +} + +static DBCHAR +gb2312_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + DBCHAR coded; + assert(*length == 1); + if (*data < 0x10000) { + TRYMAP_ENC(gbcommon, coded, *data) { + if (!(coded & 0x8000)) + return coded; + } + } + return MAP_UNMAPPABLE; +} + + +static ucs4_t +dummy_decoder(const unsigned char *data) +{ + return MAP_UNMAPPABLE; +} + +static DBCHAR +dummy_encoder(const ucs4_t *data, Py_ssize_t *length) +{ + return MAP_UNMAPPABLE; +} + +/*-*- registry tables -*-*/ + +#define REGISTRY_KSX1001_G0 { CHARSET_KSX1001, 0, 2, \ + ksx1001_init, \ + ksx1001_decoder, ksx1001_encoder } +#define REGISTRY_KSX1001_G1 { CHARSET_KSX1001, 1, 2, \ + ksx1001_init, \ + ksx1001_decoder, ksx1001_encoder } +#define REGISTRY_JISX0201_R { CHARSET_JISX0201_R, 0, 1, \ + NULL, \ + jisx0201_r_decoder, jisx0201_r_encoder } +#define REGISTRY_JISX0201_K { CHARSET_JISX0201_K, 0, 1, \ + NULL, \ + jisx0201_k_decoder, jisx0201_k_encoder } +#define REGISTRY_JISX0208 { CHARSET_JISX0208, 0, 2, \ + jisx0208_init, \ + jisx0208_decoder, jisx0208_encoder } +#define REGISTRY_JISX0208_O { CHARSET_JISX0208_O, 0, 2, \ + jisx0208_init, \ + jisx0208_decoder, jisx0208_encoder } +#define REGISTRY_JISX0212 { CHARSET_JISX0212, 0, 2, \ + jisx0212_init, \ + jisx0212_decoder, jisx0212_encoder } +#define REGISTRY_JISX0213_2000_1 { CHARSET_JISX0213_2000_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2000_1_decoder, \ + jisx0213_2000_1_encoder } +#define REGISTRY_JISX0213_2000_1_PAIRONLY { CHARSET_JISX0213_2000_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2000_1_decoder, \ + jisx0213_2000_1_encoder_paironly } +#define REGISTRY_JISX0213_2000_2 { CHARSET_JISX0213_2, 0, 2, \ + jisx0213_init, \ + jisx0213_2000_2_decoder, \ + jisx0213_2000_2_encoder } +#define REGISTRY_JISX0213_2004_1 { CHARSET_JISX0213_2004_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2004_1_decoder, \ + jisx0213_2004_1_encoder } +#define REGISTRY_JISX0213_2004_1_PAIRONLY { CHARSET_JISX0213_2004_1, 0, 2, \ + jisx0213_init, \ + jisx0213_2004_1_decoder, \ + jisx0213_2004_1_encoder_paironly } +#define REGISTRY_JISX0213_2004_2 { CHARSET_JISX0213_2, 0, 2, \ + jisx0213_init, \ + jisx0213_2004_2_decoder, \ + jisx0213_2004_2_encoder } +#define REGISTRY_GB2312 { CHARSET_GB2312, 0, 2, \ + gb2312_init, \ + gb2312_decoder, gb2312_encoder } +#define REGISTRY_CNS11643_1 { CHARSET_CNS11643_1, 1, 2, \ + cns11643_init, \ + cns11643_1_decoder, cns11643_1_encoder } +#define REGISTRY_CNS11643_2 { CHARSET_CNS11643_2, 2, 2, \ + cns11643_init, \ + cns11643_2_decoder, cns11643_2_encoder } +#define REGISTRY_ISO8859_1 { CHARSET_ISO8859_1, 2, 1, \ + NULL, dummy_decoder, dummy_encoder } +#define REGISTRY_ISO8859_7 { CHARSET_ISO8859_7, 2, 1, \ + NULL, dummy_decoder, dummy_encoder } +#define REGISTRY_SENTINEL { 0, } +#define CONFIGDEF(var, attrs) \ + static const struct iso2022_config iso2022_##var##_config = { \ + attrs, iso2022_##var##_designations \ + }; + +static const struct iso2022_designation iso2022_kr_designations[] = { + REGISTRY_KSX1001_G1, REGISTRY_SENTINEL +}; +CONFIGDEF(kr, 0) + +static const struct iso2022_designation iso2022_jp_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0201_R, REGISTRY_JISX0208_O, + REGISTRY_SENTINEL +}; +CONFIGDEF(jp, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_1_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_JISX0201_R, + REGISTRY_JISX0208_O, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_1, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_2_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_KSX1001_G0, + REGISTRY_GB2312, REGISTRY_JISX0201_R, REGISTRY_JISX0208_O, + REGISTRY_ISO8859_1, REGISTRY_ISO8859_7, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_2, NO_SHIFT | USE_G2 | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_2004_designations[] = { + REGISTRY_JISX0213_2004_1_PAIRONLY, REGISTRY_JISX0208, + REGISTRY_JISX0213_2004_1, REGISTRY_JISX0213_2004_2, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_2004, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_3_designations[] = { + REGISTRY_JISX0213_2000_1_PAIRONLY, REGISTRY_JISX0208, + REGISTRY_JISX0213_2000_1, REGISTRY_JISX0213_2000_2, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_3, NO_SHIFT | USE_JISX0208_EXT) + +static const struct iso2022_designation iso2022_jp_ext_designations[] = { + REGISTRY_JISX0208, REGISTRY_JISX0212, REGISTRY_JISX0201_R, + REGISTRY_JISX0201_K, REGISTRY_JISX0208_O, REGISTRY_SENTINEL +}; +CONFIGDEF(jp_ext, NO_SHIFT | USE_JISX0208_EXT) + + +BEGIN_MAPPINGS_LIST + /* no mapping table here */ +END_MAPPINGS_LIST + +#define ISO2022_CODEC(variation) { \ + "iso2022_" #variation, \ + &iso2022_##variation##_config, \ + iso2022_codec_init, \ + _STATEFUL_METHODS(iso2022) \ +}, + +BEGIN_CODECS_LIST + ISO2022_CODEC(kr) + ISO2022_CODEC(jp) + ISO2022_CODEC(jp_1) + ISO2022_CODEC(jp_2) + ISO2022_CODEC(jp_2004) + ISO2022_CODEC(jp_3) + ISO2022_CODEC(jp_ext) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(iso2022) diff --git a/sys/src/cmd/python/Modules/cjkcodecs/_codecs_jp.c b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_jp.c new file mode 100644 index 000000000..f49a10b10 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_jp.c @@ -0,0 +1,731 @@ +/* + * _codecs_jp.c: Codecs collection for Japanese encodings + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#define USING_BINARY_PAIR_SEARCH +#define EMPBASE 0x20000 + +#include "cjkcodecs.h" +#include "mappings_jp.h" +#include "mappings_jisx0213_pair.h" +#include "alg_jisx0201.h" +#include "emu_jisx0213_2000.h" + +/* + * CP932 codec + */ + +ENCODER(cp932) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + unsigned char c1, c2; + + if (c <= 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + else if (c >= 0xff61 && c <= 0xff9f) { + WRITE1(c - 0xfec0) + NEXT(1, 1) + continue; + } + else if (c >= 0xf8f0 && c <= 0xf8f3) { + /* Windows compatibility */ + REQUIRE_OUTBUF(1) + if (c == 0xf8f0) + OUT1(0xa0) + else + OUT1(c - 0xfef1 + 0xfd) + NEXT(1, 1) + continue; + } + + UCS4INVALID(c) + REQUIRE_OUTBUF(2) + + TRYMAP_ENC(cp932ext, code, c) { + OUT1(code >> 8) + OUT2(code & 0xff) + } + else TRYMAP_ENC(jisxcommon, code, c) { + if (code & 0x8000) /* MSB set: JIS X 0212 */ + return 1; + + /* JIS X 0208 */ + c1 = code >> 8; + c2 = code & 0xff; + c2 = (((c1 - 0x21) & 1) ? 0x5e : 0) + (c2 - 0x21); + c1 = (c1 - 0x21) >> 1; + OUT1(c1 < 0x1f ? c1 + 0x81 : c1 + 0xc1) + OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41) + } + else if (c >= 0xe000 && c < 0xe758) { + /* User-defined area */ + c1 = (Py_UNICODE)(c - 0xe000) / 188; + c2 = (Py_UNICODE)(c - 0xe000) % 188; + OUT1(c1 + 0xf0) + OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41) + } + else + return 1; + + NEXT(1, 2) + } + + return 0; +} + +DECODER(cp932) +{ + while (inleft > 0) { + unsigned char c = IN1, c2; + + REQUIRE_OUTBUF(1) + if (c <= 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + else if (c >= 0xa0 && c <= 0xdf) { + if (c == 0xa0) + OUT1(0xf8f0) /* half-width katakana */ + else + OUT1(0xfec0 + c) + NEXT(1, 1) + continue; + } + else if (c >= 0xfd/* && c <= 0xff*/) { + /* Windows compatibility */ + OUT1(0xf8f1 - 0xfd + c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + c2 = IN2; + + TRYMAP_DEC(cp932ext, **outbuf, c, c2); + else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){ + if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) + return 2; + + c = (c < 0xe0 ? c - 0x81 : c - 0xc1); + c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); + c = (2 * c + (c2 < 0x5e ? 0 : 1) + 0x21); + c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; + + TRYMAP_DEC(jisx0208, **outbuf, c, c2); + else return 2; + } + else if (c >= 0xf0 && c <= 0xf9) { + if ((c2 >= 0x40 && c2 <= 0x7e) || + (c2 >= 0x80 && c2 <= 0xfc)) + OUT1(0xe000 + 188 * (c - 0xf0) + + (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41)) + else + return 2; + } + else + return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * EUC-JIS-2004 codec + */ + +ENCODER(euc_jis_2004) +{ + while (inleft > 0) { + ucs4_t c = IN1; + DBCHAR code; + Py_ssize_t insize; + + if (c < 0x80) { + WRITE1(c) + NEXT(1, 1) + continue; + } + + DECODE_SURROGATE(c) + insize = GET_INSIZE(c); + + if (c <= 0xFFFF) { + EMULATE_JISX0213_2000_ENCODE_BMP(code, c) + else TRYMAP_ENC(jisx0213_bmp, code, c) { + if (code == MULTIC) { + if (inleft < 2) { + if (flags & MBENC_FLUSH) { + code = find_pairencmap( + (ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } + else + return MBERR_TOOFEW; + } + else { + code = find_pairencmap( + (ucs2_t)c, (*inbuf)[1], + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) { + code = find_pairencmap( + (ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } else + insize = 2; + } + } + } + else TRYMAP_ENC(jisxcommon, code, c); + else if (c >= 0xff61 && c <= 0xff9f) { + /* JIS X 0201 half-width katakana */ + WRITE2(0x8e, c - 0xfec0) + NEXT(1, 2) + continue; + } + else if (c == 0xff3c) + /* F/W REVERSE SOLIDUS (see NOTES) */ + code = 0x2140; + else if (c == 0xff5e) + /* F/W TILDE (see NOTES) */ + code = 0x2232; + else + return 1; + } + else if (c >> 16 == EMPBASE >> 16) { + EMULATE_JISX0213_2000_ENCODE_EMP(code, c) + else TRYMAP_ENC(jisx0213_emp, code, c & 0xffff); + else return insize; + } + else + return insize; + + if (code & 0x8000) { + /* Codeset 2 */ + WRITE3(0x8f, code >> 8, (code & 0xFF) | 0x80) + NEXT(insize, 3) + } else { + /* Codeset 1 */ + WRITE2((code >> 8) | 0x80, (code & 0xFF) | 0x80) + NEXT(insize, 2) + } + } + + return 0; +} + +DECODER(euc_jis_2004) +{ + while (inleft > 0) { + unsigned char c = IN1; + ucs4_t code; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + if (c == 0x8e) { + /* JIS X 0201 half-width katakana */ + unsigned char c2; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 >= 0xa1 && c2 <= 0xdf) { + OUT1(0xfec0 + c2) + NEXT(2, 1) + } + else + return 2; + } + else if (c == 0x8f) { + unsigned char c2, c3; + + REQUIRE_INBUF(3) + c2 = IN2 ^ 0x80; + c3 = IN3 ^ 0x80; + + /* JIS X 0213 Plane 2 or JIS X 0212 (see NOTES) */ + EMULATE_JISX0213_2000_DECODE_PLANE2(**outbuf, c2, c3) + else TRYMAP_DEC(jisx0213_2_bmp, **outbuf, c2, c3) ; + else TRYMAP_DEC(jisx0213_2_emp, code, c2, c3) { + WRITEUCS4(EMPBASE | code) + NEXT_IN(3) + continue; + } + else TRYMAP_DEC(jisx0212, **outbuf, c2, c3) ; + else return 3; + NEXT(3, 1) + } + else { + unsigned char c2; + + REQUIRE_INBUF(2) + c ^= 0x80; + c2 = IN2 ^ 0x80; + + /* JIS X 0213 Plane 1 */ + EMULATE_JISX0213_2000_DECODE_PLANE1(**outbuf, c, c2) + else if (c == 0x21 && c2 == 0x40) **outbuf = 0xff3c; + else if (c == 0x22 && c2 == 0x32) **outbuf = 0xff5e; + else TRYMAP_DEC(jisx0208, **outbuf, c, c2); + else TRYMAP_DEC(jisx0213_1_bmp, **outbuf, c, c2); + else TRYMAP_DEC(jisx0213_1_emp, code, c, c2) { + WRITEUCS4(EMPBASE | code) + NEXT_IN(2) + continue; + } + else TRYMAP_DEC(jisx0213_pair, code, c, c2) { + WRITE2(code >> 16, code & 0xffff) + NEXT(2, 2) + continue; + } + else return 2; + NEXT(2, 1) + } + } + + return 0; +} + + +/* + * EUC-JP codec + */ + +ENCODER(euc_jp) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + + UCS4INVALID(c) + + TRYMAP_ENC(jisxcommon, code, c); + else if (c >= 0xff61 && c <= 0xff9f) { + /* JIS X 0201 half-width katakana */ + WRITE2(0x8e, c - 0xfec0) + NEXT(1, 2) + continue; + } +#ifndef STRICT_BUILD + else if (c == 0xff3c) /* FULL-WIDTH REVERSE SOLIDUS */ + code = 0x2140; + else if (c == 0xa5) { /* YEN SIGN */ + WRITE1(0x5c); + NEXT(1, 1) + continue; + } else if (c == 0x203e) { /* OVERLINE */ + WRITE1(0x7e); + NEXT(1, 1) + continue; + } +#endif + else + return 1; + + if (code & 0x8000) { + /* JIS X 0212 */ + WRITE3(0x8f, code >> 8, (code & 0xFF) | 0x80) + NEXT(1, 3) + } else { + /* JIS X 0208 */ + WRITE2((code >> 8) | 0x80, (code & 0xFF) | 0x80) + NEXT(1, 2) + } + } + + return 0; +} + +DECODER(euc_jp) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + if (c == 0x8e) { + /* JIS X 0201 half-width katakana */ + unsigned char c2; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 >= 0xa1 && c2 <= 0xdf) { + OUT1(0xfec0 + c2) + NEXT(2, 1) + } + else + return 2; + } + else if (c == 0x8f) { + unsigned char c2, c3; + + REQUIRE_INBUF(3) + c2 = IN2; + c3 = IN3; + /* JIS X 0212 */ + TRYMAP_DEC(jisx0212, **outbuf, c2 ^ 0x80, c3 ^ 0x80) { + NEXT(3, 1) + } + else + return 3; + } + else { + unsigned char c2; + + REQUIRE_INBUF(2) + c2 = IN2; + /* JIS X 0208 */ +#ifndef STRICT_BUILD + if (c == 0xa1 && c2 == 0xc0) + /* FULL-WIDTH REVERSE SOLIDUS */ + **outbuf = 0xff3c; + else +#endif + TRYMAP_DEC(jisx0208, **outbuf, + c ^ 0x80, c2 ^ 0x80) ; + else return 2; + NEXT(2, 1) + } + } + + return 0; +} + + +/* + * SHIFT_JIS codec + */ + +ENCODER(shift_jis) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + unsigned char c1, c2; + +#ifdef STRICT_BUILD + JISX0201_R_ENCODE(c, code) +#else + if (c < 0x80) code = c; + else if (c == 0x00a5) code = 0x5c; /* YEN SIGN */ + else if (c == 0x203e) code = 0x7e; /* OVERLINE */ +#endif + else JISX0201_K_ENCODE(c, code) + else UCS4INVALID(c) + else code = NOCHAR; + + if (code < 0x80 || (code >= 0xa1 && code <= 0xdf)) { + REQUIRE_OUTBUF(1) + + OUT1((unsigned char)code) + NEXT(1, 1) + continue; + } + + REQUIRE_OUTBUF(2) + + if (code == NOCHAR) { + TRYMAP_ENC(jisxcommon, code, c); +#ifndef STRICT_BUILD + else if (c == 0xff3c) + code = 0x2140; /* FULL-WIDTH REVERSE SOLIDUS */ +#endif + else + return 1; + + if (code & 0x8000) /* MSB set: JIS X 0212 */ + return 1; + } + + c1 = code >> 8; + c2 = code & 0xff; + c2 = (((c1 - 0x21) & 1) ? 0x5e : 0) + (c2 - 0x21); + c1 = (c1 - 0x21) >> 1; + OUT1(c1 < 0x1f ? c1 + 0x81 : c1 + 0xc1) + OUT2(c2 < 0x3f ? c2 + 0x40 : c2 + 0x41) + NEXT(1, 2) + } + + return 0; +} + +DECODER(shift_jis) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + +#ifdef STRICT_BUILD + JISX0201_R_DECODE(c, **outbuf) +#else + if (c < 0x80) **outbuf = c; +#endif + else JISX0201_K_DECODE(c, **outbuf) + else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xea)){ + unsigned char c1, c2; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) + return 2; + + c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); + c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); + c1 = (2 * c1 + (c2 < 0x5e ? 0 : 1) + 0x21); + c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; + +#ifndef STRICT_BUILD + if (c1 == 0x21 && c2 == 0x40) { + /* FULL-WIDTH REVERSE SOLIDUS */ + OUT1(0xff3c) + NEXT(2, 1) + continue; + } +#endif + TRYMAP_DEC(jisx0208, **outbuf, c1, c2) { + NEXT(2, 1) + continue; + } + else + return 2; + } + else + return 2; + + NEXT(1, 1) /* JIS X 0201 */ + } + + return 0; +} + + +/* + * SHIFT_JIS-2004 codec + */ + +ENCODER(shift_jis_2004) +{ + while (inleft > 0) { + ucs4_t c = IN1; + DBCHAR code = NOCHAR; + int c1, c2; + Py_ssize_t insize; + + JISX0201_ENCODE(c, code) + else DECODE_SURROGATE(c) + + if (code < 0x80 || (code >= 0xa1 && code <= 0xdf)) { + WRITE1((unsigned char)code) + NEXT(1, 1) + continue; + } + + REQUIRE_OUTBUF(2) + insize = GET_INSIZE(c); + + if (code == NOCHAR) { + if (c <= 0xffff) { + EMULATE_JISX0213_2000_ENCODE_BMP(code, c) + else TRYMAP_ENC(jisx0213_bmp, code, c) { + if (code == MULTIC) { + if (inleft < 2) { + if (flags & MBENC_FLUSH) { + code = find_pairencmap + ((ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } + else + return MBERR_TOOFEW; + } + else { + code = find_pairencmap( + (ucs2_t)c, IN2, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) { + code = find_pairencmap( + (ucs2_t)c, 0, + jisx0213_pair_encmap, + JISX0213_ENCPAIRS); + if (code == DBCINV) + return 1; + } + else + insize = 2; + } + } + } + else TRYMAP_ENC(jisxcommon, code, c) { + /* abandon JIS X 0212 codes */ + if (code & 0x8000) + return 1; + } + else return 1; + } + else if (c >> 16 == EMPBASE >> 16) { + EMULATE_JISX0213_2000_ENCODE_EMP(code, c) + else TRYMAP_ENC(jisx0213_emp, code, c&0xffff); + else return insize; + } + else + return insize; + } + + c1 = code >> 8; + c2 = (code & 0xff) - 0x21; + + if (c1 & 0x80) { /* Plane 2 */ + if (c1 >= 0xee) c1 -= 0x87; + else if (c1 >= 0xac || c1 == 0xa8) c1 -= 0x49; + else c1 -= 0x43; + } + else /* Plane 1 */ + c1 -= 0x21; + + if (c1 & 1) c2 += 0x5e; + c1 >>= 1; + OUT1(c1 + (c1 < 0x1f ? 0x81 : 0xc1)) + OUT2(c2 + (c2 < 0x3f ? 0x40 : 0x41)) + + NEXT(insize, 2) + } + + return 0; +} + +DECODER(shift_jis_2004) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + JISX0201_DECODE(c, **outbuf) + else if ((c >= 0x81 && c <= 0x9f) || (c >= 0xe0 && c <= 0xfc)){ + unsigned char c1, c2; + ucs4_t code; + + REQUIRE_INBUF(2) + c2 = IN2; + if (c2 < 0x40 || (c2 > 0x7e && c2 < 0x80) || c2 > 0xfc) + return 2; + + c1 = (c < 0xe0 ? c - 0x81 : c - 0xc1); + c2 = (c2 < 0x80 ? c2 - 0x40 : c2 - 0x41); + c1 = (2 * c1 + (c2 < 0x5e ? 0 : 1)); + c2 = (c2 < 0x5e ? c2 : c2 - 0x5e) + 0x21; + + if (c1 < 0x5e) { /* Plane 1 */ + c1 += 0x21; + EMULATE_JISX0213_2000_DECODE_PLANE1(**outbuf, + c1, c2) + else TRYMAP_DEC(jisx0208, **outbuf, c1, c2) { + NEXT_OUT(1) + } + else TRYMAP_DEC(jisx0213_1_bmp, **outbuf, + c1, c2) { + NEXT_OUT(1) + } + else TRYMAP_DEC(jisx0213_1_emp, code, c1, c2) { + WRITEUCS4(EMPBASE | code) + } + else TRYMAP_DEC(jisx0213_pair, code, c1, c2) { + WRITE2(code >> 16, code & 0xffff) + NEXT_OUT(2) + } + else + return 2; + NEXT_IN(2) + } + else { /* Plane 2 */ + if (c1 >= 0x67) c1 += 0x07; + else if (c1 >= 0x63 || c1 == 0x5f) c1 -= 0x37; + else c1 -= 0x3d; + + EMULATE_JISX0213_2000_DECODE_PLANE2(**outbuf, + c1, c2) + else TRYMAP_DEC(jisx0213_2_bmp, **outbuf, + c1, c2) ; + else TRYMAP_DEC(jisx0213_2_emp, code, c1, c2) { + WRITEUCS4(EMPBASE | code) + NEXT_IN(2) + continue; + } + else + return 2; + NEXT(2, 1) + } + continue; + } + else + return 2; + + NEXT(1, 1) /* JIS X 0201 */ + } + + return 0; +} + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(jisx0208) + MAPPING_DECONLY(jisx0212) + MAPPING_ENCONLY(jisxcommon) + MAPPING_DECONLY(jisx0213_1_bmp) + MAPPING_DECONLY(jisx0213_2_bmp) + MAPPING_ENCONLY(jisx0213_bmp) + MAPPING_DECONLY(jisx0213_1_emp) + MAPPING_DECONLY(jisx0213_2_emp) + MAPPING_ENCONLY(jisx0213_emp) + MAPPING_ENCDEC(jisx0213_pair) + MAPPING_ENCDEC(cp932ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(shift_jis) + CODEC_STATELESS(cp932) + CODEC_STATELESS(euc_jp) + CODEC_STATELESS(shift_jis_2004) + CODEC_STATELESS(euc_jis_2004) + { "euc_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(euc_jis_2004) }, + { "shift_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(shift_jis_2004) }, +END_CODECS_LIST + +I_AM_A_MODULE_FOR(jp) diff --git a/sys/src/cmd/python/Modules/cjkcodecs/_codecs_kr.c b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_kr.c new file mode 100644 index 000000000..2a95bbe9b --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_kr.c @@ -0,0 +1,355 @@ +/* + * _codecs_kr.c: Codecs collection for Korean encodings + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#include "cjkcodecs.h" +#include "mappings_kr.h" + +/* + * EUC-KR codec + */ + +ENCODER(euc_kr) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(cp949, code, c); + else return 1; + + if (code & 0x8000) /* MSB set: CP949 */ + return 1; + + OUT1((code >> 8) | 0x80) + OUT2((code & 0xFF) | 0x80) + NEXT(1, 2) + } + + return 0; +} + +DECODER(euc_kr) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80) { + NEXT(2, 1) + } else return 2; + } + + return 0; +} + + +/* + * CP949 codec + */ + +ENCODER(cp949) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(cp949, code, c); + else return 1; + + OUT1((code >> 8) | 0x80) + if (code & 0x8000) + OUT2(code & 0xFF) /* MSB set: CP949 */ + else + OUT2((code & 0xFF) | 0x80) /* MSB unset: ks x 1001 */ + NEXT(1, 2) + } + + return 0; +} + +DECODER(cp949) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + TRYMAP_DEC(ksx1001, **outbuf, c ^ 0x80, IN2 ^ 0x80); + else TRYMAP_DEC(cp949ext, **outbuf, c, IN2); + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + +/* + * JOHAB codec + */ + +static const unsigned char u2johabidx_choseong[32] = { + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, +}; +static const unsigned char u2johabidx_jungseong[32] = { + 0x03, 0x04, 0x05, 0x06, 0x07, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x1a, 0x1b, 0x1c, 0x1d, +}; +static const unsigned char u2johabidx_jongseong[32] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, +}; +static const DBCHAR u2johabjamo[] = { + 0x8841, 0x8c41, 0x8444, 0x9041, 0x8446, 0x8447, 0x9441, + 0x9841, 0x9c41, 0x844a, 0x844b, 0x844c, 0x844d, 0x844e, 0x844f, + 0x8450, 0xa041, 0xa441, 0xa841, 0x8454, 0xac41, 0xb041, 0xb441, + 0xb841, 0xbc41, 0xc041, 0xc441, 0xc841, 0xcc41, 0xd041, 0x8461, + 0x8481, 0x84a1, 0x84c1, 0x84e1, 0x8541, 0x8561, 0x8581, 0x85a1, + 0x85c1, 0x85e1, 0x8641, 0x8661, 0x8681, 0x86a1, 0x86c1, 0x86e1, + 0x8741, 0x8761, 0x8781, 0x87a1, +}; + +ENCODER(johab) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + + if (c >= 0xac00 && c <= 0xd7a3) { + c -= 0xac00; + code = 0x8000 | + (u2johabidx_choseong[c / 588] << 10) | + (u2johabidx_jungseong[(c / 28) % 21] << 5) | + u2johabidx_jongseong[c % 28]; + } + else if (c >= 0x3131 && c <= 0x3163) + code = u2johabjamo[c - 0x3131]; + else TRYMAP_ENC(cp949, code, c) { + unsigned char c1, c2, t2; + unsigned short t1; + + assert((code & 0x8000) == 0); + c1 = code >> 8; + c2 = code & 0xff; + if (((c1 >= 0x21 && c1 <= 0x2c) || + (c1 >= 0x4a && c1 <= 0x7d)) && + (c2 >= 0x21 && c2 <= 0x7e)) { + t1 = (c1 < 0x4a ? (c1 - 0x21 + 0x1b2) : + (c1 - 0x21 + 0x197)); + t2 = ((t1 & 1) ? 0x5e : 0) + (c2 - 0x21); + OUT1(t1 >> 1) + OUT2(t2 < 0x4e ? t2 + 0x31 : t2 + 0x43) + NEXT(1, 2) + continue; + } + else + return 1; + } + else + return 1; + + OUT1(code >> 8) + OUT2(code & 0xff) + NEXT(1, 2) + } + + return 0; +} + +#define FILL 0xfd +#define NONE 0xff + +static const unsigned char johabidx_choseong[32] = { + NONE, FILL, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x10, 0x11, 0x12, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, +}; +static const unsigned char johabidx_jungseong[32] = { + NONE, NONE, FILL, 0x00, 0x01, 0x02, 0x03, 0x04, + NONE, NONE, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + NONE, NONE, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + NONE, NONE, 0x11, 0x12, 0x13, 0x14, NONE, NONE, +}; +static const unsigned char johabidx_jongseong[32] = { + NONE, FILL, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, NONE, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, NONE, NONE, +}; + +static const unsigned char johabjamo_choseong[32] = { + NONE, FILL, 0x31, 0x32, 0x34, 0x37, 0x38, 0x39, + 0x41, 0x42, 0x43, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, +}; +static const unsigned char johabjamo_jungseong[32] = { + NONE, NONE, FILL, 0x4f, 0x50, 0x51, 0x52, 0x53, + NONE, NONE, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + NONE, NONE, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + NONE, NONE, 0x60, 0x61, 0x62, 0x63, NONE, NONE, +}; +static const unsigned char johabjamo_jongseong[32] = { + NONE, FILL, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, NONE, 0x42, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, NONE, NONE, +}; + +DECODER(johab) +{ + while (inleft > 0) { + unsigned char c = IN1, c2; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + c2 = IN2; + + if (c < 0xd8) { + /* johab hangul */ + unsigned char c_cho, c_jung, c_jong; + unsigned char i_cho, i_jung, i_jong; + + c_cho = (c >> 2) & 0x1f; + c_jung = ((c << 3) | c2 >> 5) & 0x1f; + c_jong = c2 & 0x1f; + + i_cho = johabidx_choseong[c_cho]; + i_jung = johabidx_jungseong[c_jung]; + i_jong = johabidx_jongseong[c_jong]; + + if (i_cho == NONE || i_jung == NONE || i_jong == NONE) + return 2; + + /* we don't use U+1100 hangul jamo yet. */ + if (i_cho == FILL) { + if (i_jung == FILL) { + if (i_jong == FILL) + OUT1(0x3000) + else + OUT1(0x3100 | + johabjamo_jongseong[c_jong]) + } + else { + if (i_jong == FILL) + OUT1(0x3100 | + johabjamo_jungseong[c_jung]) + else + return 2; + } + } else { + if (i_jung == FILL) { + if (i_jong == FILL) + OUT1(0x3100 | + johabjamo_choseong[c_cho]) + else + return 2; + } + else + OUT1(0xac00 + + i_cho * 588 + + i_jung * 28 + + (i_jong == FILL ? 0 : i_jong)) + } + NEXT(2, 1) + } else { + /* KS X 1001 except hangul jamos and syllables */ + if (c == 0xdf || c > 0xf9 || + c2 < 0x31 || (c2 >= 0x80 && c2 < 0x91) || + (c2 & 0x7f) == 0x7f || + (c == 0xda && (c2 >= 0xa1 && c2 <= 0xd3))) + return 2; + else { + unsigned char t1, t2; + + t1 = (c < 0xe0 ? 2 * (c - 0xd9) : + 2 * c - 0x197); + t2 = (c2 < 0x91 ? c2 - 0x31 : c2 - 0x43); + t1 = t1 + (t2 < 0x5e ? 0 : 1) + 0x21; + t2 = (t2 < 0x5e ? t2 : t2 - 0x5e) + 0x21; + + TRYMAP_DEC(ksx1001, **outbuf, t1, t2); + else return 2; + NEXT(2, 1) + } + } + } + + return 0; +} +#undef NONE +#undef FILL + + +BEGIN_MAPPINGS_LIST + MAPPING_DECONLY(ksx1001) + MAPPING_ENCONLY(cp949) + MAPPING_DECONLY(cp949ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(euc_kr) + CODEC_STATELESS(cp949) + CODEC_STATELESS(johab) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(kr) diff --git a/sys/src/cmd/python/Modules/cjkcodecs/_codecs_tw.c b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_tw.c new file mode 100644 index 000000000..8ccbca1df --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/_codecs_tw.c @@ -0,0 +1,132 @@ +/* + * _codecs_tw.c: Codecs collection for Taiwan's encodings + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#include "cjkcodecs.h" +#include "mappings_tw.h" + +/* + * BIG5 codec + */ + +ENCODER(big5) +{ + while (inleft > 0) { + Py_UNICODE c = **inbuf; + DBCHAR code; + + if (c < 0x80) { + REQUIRE_OUTBUF(1) + **outbuf = (unsigned char)c; + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + + TRYMAP_ENC(big5, code, c); + else return 1; + + OUT1(code >> 8) + OUT2(code & 0xFF) + NEXT(1, 2) + } + + return 0; +} + +DECODER(big5) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + TRYMAP_DEC(big5, **outbuf, c, IN2) { + NEXT(2, 1) + } + else return 2; + } + + return 0; +} + + +/* + * CP950 codec + */ + +ENCODER(cp950) +{ + while (inleft > 0) { + Py_UNICODE c = IN1; + DBCHAR code; + + if (c < 0x80) { + WRITE1((unsigned char)c) + NEXT(1, 1) + continue; + } + UCS4INVALID(c) + + REQUIRE_OUTBUF(2) + TRYMAP_ENC(cp950ext, code, c); + else TRYMAP_ENC(big5, code, c); + else return 1; + + OUT1(code >> 8) + OUT2(code & 0xFF) + NEXT(1, 2) + } + + return 0; +} + +DECODER(cp950) +{ + while (inleft > 0) { + unsigned char c = IN1; + + REQUIRE_OUTBUF(1) + + if (c < 0x80) { + OUT1(c) + NEXT(1, 1) + continue; + } + + REQUIRE_INBUF(2) + + TRYMAP_DEC(cp950ext, **outbuf, c, IN2); + else TRYMAP_DEC(big5, **outbuf, c, IN2); + else return 2; + + NEXT(2, 1) + } + + return 0; +} + + + +BEGIN_MAPPINGS_LIST + MAPPING_ENCDEC(big5) + MAPPING_ENCDEC(cp950ext) +END_MAPPINGS_LIST + +BEGIN_CODECS_LIST + CODEC_STATELESS(big5) + CODEC_STATELESS(cp950) +END_CODECS_LIST + +I_AM_A_MODULE_FOR(tw) diff --git a/sys/src/cmd/python/Modules/cjkcodecs/alg_jisx0201.h b/sys/src/cmd/python/Modules/cjkcodecs/alg_jisx0201.h new file mode 100644 index 000000000..1fca06bce --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/alg_jisx0201.h @@ -0,0 +1,24 @@ +#define JISX0201_R_ENCODE(c, assi) \ + if ((c) < 0x80 && (c) != 0x5c && (c) != 0x7e) \ + (assi) = (c); \ + else if ((c) == 0x00a5) (assi) = 0x5c; \ + else if ((c) == 0x203e) (assi) = 0x7e; +#define JISX0201_K_ENCODE(c, assi) \ + if ((c) >= 0xff61 && (c) <= 0xff9f) \ + (assi) = (c) - 0xfec0; +#define JISX0201_ENCODE(c, assi) \ + JISX0201_R_ENCODE(c, assi) \ + else JISX0201_K_ENCODE(c, assi) + +#define JISX0201_R_DECODE(c, assi) \ + if ((c) < 0x5c) (assi) = (c); \ + else if ((c) == 0x5c) (assi) = 0x00a5; \ + else if ((c) < 0x7e) (assi) = (c); \ + else if ((c) == 0x7e) (assi) = 0x203e; \ + else if ((c) == 0x7f) (assi) = 0x7f; +#define JISX0201_K_DECODE(c, assi) \ + if ((c) >= 0xa1 && (c) <= 0xdf) \ + (assi) = 0xfec0 + (c); +#define JISX0201_DECODE(c, assi) \ + JISX0201_R_DECODE(c, assi) \ + else JISX0201_K_DECODE(c, assi) diff --git a/sys/src/cmd/python/Modules/cjkcodecs/cjkcodecs.h b/sys/src/cmd/python/Modules/cjkcodecs/cjkcodecs.h new file mode 100644 index 000000000..71c54f093 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/cjkcodecs.h @@ -0,0 +1,398 @@ +/* + * cjkcodecs.h: common header for cjkcodecs + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#ifndef _CJKCODECS_H_ +#define _CJKCODECS_H_ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "multibytecodec.h" + + +/* a unicode "undefined" codepoint */ +#define UNIINV 0xFFFE + +/* internal-use DBCS codepoints which aren't used by any charsets */ +#define NOCHAR 0xFFFF +#define MULTIC 0xFFFE +#define DBCINV 0xFFFD + +/* shorter macros to save source size of mapping tables */ +#define U UNIINV +#define N NOCHAR +#define M MULTIC +#define D DBCINV + +struct dbcs_index { + const ucs2_t *map; + unsigned char bottom, top; +}; +typedef struct dbcs_index decode_map; + +struct widedbcs_index { + const ucs4_t *map; + unsigned char bottom, top; +}; +typedef struct widedbcs_index widedecode_map; + +struct unim_index { + const DBCHAR *map; + unsigned char bottom, top; +}; +typedef struct unim_index encode_map; + +struct unim_index_bytebased { + const unsigned char *map; + unsigned char bottom, top; +}; + +struct dbcs_map { + const char *charset; + const struct unim_index *encmap; + const struct dbcs_index *decmap; +}; + +struct pair_encodemap { + ucs4_t uniseq; + DBCHAR code; +}; + +static const MultibyteCodec *codec_list; +static const struct dbcs_map *mapping_list; + +#define CODEC_INIT(encoding) \ + static int encoding##_codec_init(const void *config) + +#define ENCODER_INIT(encoding) \ + static int encoding##_encode_init( \ + MultibyteCodec_State *state, const void *config) +#define ENCODER(encoding) \ + static Py_ssize_t encoding##_encode( \ + MultibyteCodec_State *state, const void *config, \ + const Py_UNICODE **inbuf, Py_ssize_t inleft, \ + unsigned char **outbuf, Py_ssize_t outleft, int flags) +#define ENCODER_RESET(encoding) \ + static Py_ssize_t encoding##_encode_reset( \ + MultibyteCodec_State *state, const void *config, \ + unsigned char **outbuf, Py_ssize_t outleft) + +#define DECODER_INIT(encoding) \ + static int encoding##_decode_init( \ + MultibyteCodec_State *state, const void *config) +#define DECODER(encoding) \ + static Py_ssize_t encoding##_decode( \ + MultibyteCodec_State *state, const void *config, \ + const unsigned char **inbuf, Py_ssize_t inleft, \ + Py_UNICODE **outbuf, Py_ssize_t outleft) +#define DECODER_RESET(encoding) \ + static Py_ssize_t encoding##_decode_reset( \ + MultibyteCodec_State *state, const void *config) + +#if Py_UNICODE_SIZE == 4 +#define UCS4INVALID(code) \ + if ((code) > 0xFFFF) \ + return 1; +#else +#define UCS4INVALID(code) \ + if (0) ; +#endif + +#define NEXT_IN(i) \ + (*inbuf) += (i); \ + (inleft) -= (i); +#define NEXT_OUT(o) \ + (*outbuf) += (o); \ + (outleft) -= (o); +#define NEXT(i, o) \ + NEXT_IN(i) NEXT_OUT(o) + +#define REQUIRE_INBUF(n) \ + if (inleft < (n)) \ + return MBERR_TOOFEW; +#define REQUIRE_OUTBUF(n) \ + if (outleft < (n)) \ + return MBERR_TOOSMALL; + +#define IN1 ((*inbuf)[0]) +#define IN2 ((*inbuf)[1]) +#define IN3 ((*inbuf)[2]) +#define IN4 ((*inbuf)[3]) + +#define OUT1(c) ((*outbuf)[0]) = (c); +#define OUT2(c) ((*outbuf)[1]) = (c); +#define OUT3(c) ((*outbuf)[2]) = (c); +#define OUT4(c) ((*outbuf)[3]) = (c); + +#define WRITE1(c1) \ + REQUIRE_OUTBUF(1) \ + (*outbuf)[0] = (c1); +#define WRITE2(c1, c2) \ + REQUIRE_OUTBUF(2) \ + (*outbuf)[0] = (c1); \ + (*outbuf)[1] = (c2); +#define WRITE3(c1, c2, c3) \ + REQUIRE_OUTBUF(3) \ + (*outbuf)[0] = (c1); \ + (*outbuf)[1] = (c2); \ + (*outbuf)[2] = (c3); +#define WRITE4(c1, c2, c3, c4) \ + REQUIRE_OUTBUF(4) \ + (*outbuf)[0] = (c1); \ + (*outbuf)[1] = (c2); \ + (*outbuf)[2] = (c3); \ + (*outbuf)[3] = (c4); + +#if Py_UNICODE_SIZE == 2 +# define WRITEUCS4(c) \ + REQUIRE_OUTBUF(2) \ + (*outbuf)[0] = 0xd800 + (((c) - 0x10000) >> 10); \ + (*outbuf)[1] = 0xdc00 + (((c) - 0x10000) & 0x3ff); \ + NEXT_OUT(2) +#else +# define WRITEUCS4(c) \ + REQUIRE_OUTBUF(1) \ + **outbuf = (Py_UNICODE)(c); \ + NEXT_OUT(1) +#endif + +#define _TRYMAP_ENC(m, assi, val) \ + ((m)->map != NULL && (val) >= (m)->bottom && \ + (val)<= (m)->top && ((assi) = (m)->map[(val) - \ + (m)->bottom]) != NOCHAR) +#define TRYMAP_ENC_COND(charset, assi, uni) \ + _TRYMAP_ENC(&charset##_encmap[(uni) >> 8], assi, (uni) & 0xff) +#define TRYMAP_ENC(charset, assi, uni) \ + if TRYMAP_ENC_COND(charset, assi, uni) + +#define _TRYMAP_DEC(m, assi, val) \ + ((m)->map != NULL && (val) >= (m)->bottom && \ + (val)<= (m)->top && ((assi) = (m)->map[(val) - \ + (m)->bottom]) != UNIINV) +#define TRYMAP_DEC(charset, assi, c1, c2) \ + if _TRYMAP_DEC(&charset##_decmap[c1], assi, c2) + +#define _TRYMAP_ENC_MPLANE(m, assplane, asshi, asslo, val) \ + ((m)->map != NULL && (val) >= (m)->bottom && \ + (val)<= (m)->top && \ + ((assplane) = (m)->map[((val) - (m)->bottom)*3]) != 0 && \ + (((asshi) = (m)->map[((val) - (m)->bottom)*3 + 1]), 1) && \ + (((asslo) = (m)->map[((val) - (m)->bottom)*3 + 2]), 1)) +#define TRYMAP_ENC_MPLANE(charset, assplane, asshi, asslo, uni) \ + if _TRYMAP_ENC_MPLANE(&charset##_encmap[(uni) >> 8], \ + assplane, asshi, asslo, (uni) & 0xff) +#define TRYMAP_DEC_MPLANE(charset, assi, plane, c1, c2) \ + if _TRYMAP_DEC(&charset##_decmap[plane][c1], assi, c2) + +#if Py_UNICODE_SIZE == 2 +#define DECODE_SURROGATE(c) \ + if (c >> 10 == 0xd800 >> 10) { /* high surrogate */ \ + REQUIRE_INBUF(2) \ + if (IN2 >> 10 == 0xdc00 >> 10) { /* low surrogate */ \ + c = 0x10000 + ((ucs4_t)(c - 0xd800) << 10) + \ + ((ucs4_t)(IN2) - 0xdc00); \ + } \ + } +#define GET_INSIZE(c) ((c) > 0xffff ? 2 : 1) +#else +#define DECODE_SURROGATE(c) {;} +#define GET_INSIZE(c) 1 +#endif + +#define BEGIN_MAPPINGS_LIST static const struct dbcs_map _mapping_list[] = { +#define MAPPING_ENCONLY(enc) {#enc, (void*)enc##_encmap, NULL}, +#define MAPPING_DECONLY(enc) {#enc, NULL, (void*)enc##_decmap}, +#define MAPPING_ENCDEC(enc) {#enc, (void*)enc##_encmap, (void*)enc##_decmap}, +#define END_MAPPINGS_LIST \ + {"", NULL, NULL} }; \ + static const struct dbcs_map *mapping_list = \ + (const struct dbcs_map *)_mapping_list; + +#define BEGIN_CODECS_LIST static const MultibyteCodec _codec_list[] = { +#define _STATEFUL_METHODS(enc) \ + enc##_encode, \ + enc##_encode_init, \ + enc##_encode_reset, \ + enc##_decode, \ + enc##_decode_init, \ + enc##_decode_reset, +#define _STATELESS_METHODS(enc) \ + enc##_encode, NULL, NULL, \ + enc##_decode, NULL, NULL, +#define CODEC_STATEFUL(enc) { \ + #enc, NULL, NULL, \ + _STATEFUL_METHODS(enc) \ +}, +#define CODEC_STATELESS(enc) { \ + #enc, NULL, NULL, \ + _STATELESS_METHODS(enc) \ +}, +#define CODEC_STATELESS_WINIT(enc) { \ + #enc, NULL, \ + enc##_codec_init, \ + _STATELESS_METHODS(enc) \ +}, +#define END_CODECS_LIST \ + {"", NULL,} }; \ + static const MultibyteCodec *codec_list = \ + (const MultibyteCodec *)_codec_list; + +static PyObject * +getmultibytecodec(void) +{ + static PyObject *cofunc = NULL; + + if (cofunc == NULL) { + PyObject *mod = PyImport_ImportModule("_multibytecodec"); + if (mod == NULL) + return NULL; + cofunc = PyObject_GetAttrString(mod, "__create_codec"); + Py_DECREF(mod); + } + return cofunc; +} + +static PyObject * +getcodec(PyObject *self, PyObject *encoding) +{ + PyObject *codecobj, *r, *cofunc; + const MultibyteCodec *codec; + const char *enc; + + if (!PyString_Check(encoding)) { + PyErr_SetString(PyExc_TypeError, + "encoding name must be a string."); + return NULL; + } + + cofunc = getmultibytecodec(); + if (cofunc == NULL) + return NULL; + + enc = PyString_AS_STRING(encoding); + for (codec = codec_list; codec->encoding[0]; codec++) + if (strcmp(codec->encoding, enc) == 0) + break; + + if (codec->encoding[0] == '\0') { + PyErr_SetString(PyExc_LookupError, + "no such codec is supported."); + return NULL; + } + + codecobj = PyCObject_FromVoidPtr((void *)codec, NULL); + if (codecobj == NULL) + return NULL; + + r = PyObject_CallFunctionObjArgs(cofunc, codecobj, NULL); + Py_DECREF(codecobj); + + return r; +} + +static struct PyMethodDef __methods[] = { + {"getcodec", (PyCFunction)getcodec, METH_O, ""}, + {NULL, NULL}, +}; + +static int +register_maps(PyObject *module) +{ + const struct dbcs_map *h; + + for (h = mapping_list; h->charset[0] != '\0'; h++) { + char mhname[256] = "__map_"; + int r; + strcpy(mhname + sizeof("__map_") - 1, h->charset); + r = PyModule_AddObject(module, mhname, + PyCObject_FromVoidPtr((void *)h, NULL)); + if (r == -1) + return -1; + } + return 0; +} + +#ifdef USING_BINARY_PAIR_SEARCH +static DBCHAR +find_pairencmap(ucs2_t body, ucs2_t modifier, + const struct pair_encodemap *haystack, int haystacksize) +{ + int pos, min, max; + ucs4_t value = body << 16 | modifier; + + min = 0; + max = haystacksize; + + for (pos = haystacksize >> 1; min != max; pos = (min + max) >> 1) + if (value < haystack[pos].uniseq) { + if (max == pos) break; + else max = pos; + } + else if (value > haystack[pos].uniseq) { + if (min == pos) break; + else min = pos; + } + else + break; + + if (value == haystack[pos].uniseq) + return haystack[pos].code; + else + return DBCINV; +} +#endif + +#ifdef USING_IMPORTED_MAPS +#define IMPORT_MAP(locale, charset, encmap, decmap) \ + importmap("_codecs_" #locale, "__map_" #charset, \ + (const void**)encmap, (const void**)decmap) + +static int +importmap(const char *modname, const char *symbol, + const void **encmap, const void **decmap) +{ + PyObject *o, *mod; + + mod = PyImport_ImportModule((char *)modname); + if (mod == NULL) + return -1; + + o = PyObject_GetAttrString(mod, (char*)symbol); + if (o == NULL) + goto errorexit; + else if (!PyCObject_Check(o)) { + PyErr_SetString(PyExc_ValueError, + "map data must be a CObject."); + goto errorexit; + } + else { + struct dbcs_map *map; + map = PyCObject_AsVoidPtr(o); + if (encmap != NULL) + *encmap = map->encmap; + if (decmap != NULL) + *decmap = map->decmap; + Py_DECREF(o); + } + + Py_DECREF(mod); + return 0; + +errorexit: + Py_DECREF(mod); + return -1; +} +#endif + +#define I_AM_A_MODULE_FOR(loc) \ + void \ + init_codecs_##loc(void) \ + { \ + PyObject *m = Py_InitModule("_codecs_" #loc, __methods);\ + if (m != NULL) \ + (void)register_maps(m); \ + } + +#endif diff --git a/sys/src/cmd/python/Modules/cjkcodecs/emu_jisx0213_2000.h b/sys/src/cmd/python/Modules/cjkcodecs/emu_jisx0213_2000.h new file mode 100644 index 000000000..250c67304 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/emu_jisx0213_2000.h @@ -0,0 +1,43 @@ +/* These routines may be quite inefficient, but it's used only to emulate old + * standards. */ + +#ifndef EMULATE_JISX0213_2000_ENCODE_INVALID +#define EMULATE_JISX0213_2000_ENCODE_INVALID 1 +#endif + +#define EMULATE_JISX0213_2000_ENCODE_BMP(assi, c) \ + if (config == (void *)2000 && ( \ + (c) == 0x9B1C || (c) == 0x4FF1 || \ + (c) == 0x525D || (c) == 0x541E || \ + (c) == 0x5653 || (c) == 0x59F8 || \ + (c) == 0x5C5B || (c) == 0x5E77 || \ + (c) == 0x7626 || (c) == 0x7E6B)) \ + return EMULATE_JISX0213_2000_ENCODE_INVALID; \ + else if (config == (void *)2000 && (c) == 0x9B1D) \ + (assi) = 0x8000 | 0x7d3b; \ + +#define EMULATE_JISX0213_2000_ENCODE_EMP(assi, c) \ + if (config == (void *)2000 && (c) == 0x20B9F) \ + return EMULATE_JISX0213_2000_ENCODE_INVALID; + +#ifndef EMULATE_JISX0213_2000_DECODE_INVALID +#define EMULATE_JISX0213_2000_DECODE_INVALID 2 +#endif + +#define EMULATE_JISX0213_2000_DECODE_PLANE1(assi, c1, c2) \ + if (config == (void *)2000 && \ + (((c1) == 0x2E && (c2) == 0x21) || \ + ((c1) == 0x2F && (c2) == 0x7E) || \ + ((c1) == 0x4F && (c2) == 0x54) || \ + ((c1) == 0x4F && (c2) == 0x7E) || \ + ((c1) == 0x74 && (c2) == 0x27) || \ + ((c1) == 0x7E && (c2) == 0x7A) || \ + ((c1) == 0x7E && (c2) == 0x7B) || \ + ((c1) == 0x7E && (c2) == 0x7C) || \ + ((c1) == 0x7E && (c2) == 0x7D) || \ + ((c1) == 0x7E && (c2) == 0x7E))) \ + return EMULATE_JISX0213_2000_DECODE_INVALID; + +#define EMULATE_JISX0213_2000_DECODE_PLANE2(assi, c1, c2) \ + if (config == (void *)2000 && (c1) == 0x7D && (c2) == 0x3B) \ + (assi) = 0x9B1D; diff --git a/sys/src/cmd/python/Modules/cjkcodecs/mappings_cn.h b/sys/src/cmd/python/Modules/cjkcodecs/mappings_cn.h new file mode 100644 index 000000000..a6dcebfe4 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/mappings_cn.h @@ -0,0 +1,4103 @@ +static const ucs2_t __gb2312_decmap[7482] = { +12288,12289,12290,12539,713,711,168,12291,12293,8213,65374,8214,8230,8216, +8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303, +12310,12311,12304,12305,177,215,247,8758,8743,8744,8721,8719,8746,8745,8712, +8759,8730,8869,8741,8736,8978,8857,8747,8750,8801,8780,8776,8765,8733,8800, +8814,8815,8804,8805,8734,8757,8756,9794,9792,176,8242,8243,8451,65284,164, +65504,65505,8240,167,8470,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651, +9650,8251,8594,8592,8593,8595,12307,9352,9353,9354,9355,9356,9357,9358,9359, +9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9332,9333,9334, +9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349, +9350,9351,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,U,U,12832,12833, +12834,12835,12836,12837,12838,12839,12840,12841,U,U,8544,8545,8546,8547,8548, +8549,8550,8551,8552,8553,8554,8555,65281,65282,65283,65509,65285,65286,65287, +65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300, +65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313, +65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326, +65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339, +65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352, +65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365, +65366,65367,65368,65369,65370,65371,65372,65373,65507,12353,12354,12355,12356, +12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369, +12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382, +12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395, +12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408, +12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421, +12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434, +12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460, +12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473, +12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486, +12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499, +12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512, +12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525, +12526,12527,12528,12529,12530,12531,12532,12533,12534,913,914,915,916,917,918, +919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,U,U,U, +U,U,U,U,U,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961, +963,964,965,966,967,968,969,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048, +1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063, +1064,1065,1066,1067,1068,1069,1070,1071,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,1072, +1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086, +1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101, +1102,1103,257,225,462,224,275,233,283,232,299,237,464,236,333,243,466,242,363, +250,468,249,470,472,474,476,252,234,U,U,U,U,U,U,U,U,U,U,12549,12550,12551, +12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564, +12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577, +12578,12579,12580,12581,12582,12583,12584,12585,9472,9473,9474,9475,9476,9477, +9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492, +9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507, +9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522, +9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537, +9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,21834,38463,22467,25384, +21710,21769,21696,30353,30284,34108,30702,33406,30861,29233,38552,38797,27688, +23433,20474,25353,26263,23736,33018,26696,32942,26114,30414,20985,25942,29100, +32753,34948,20658,22885,25034,28595,33453,25420,25170,21485,21543,31494,20843, +30116,24052,25300,36299,38774,25226,32793,22365,38712,32610,29240,30333,26575, +30334,25670,20336,36133,25308,31255,26001,29677,25644,25203,33324,39041,26495, +29256,25198,25292,20276,29923,21322,21150,32458,37030,24110,26758,27036,33152, +32465,26834,30917,34444,38225,20621,35876,33502,32990,21253,35090,21093,34180, +38649,20445,22561,39281,23453,25265,25253,26292,35961,40077,29190,26479,30865, +24754,21329,21271,36744,32972,36125,38049,20493,29384,22791,24811,28953,34987, +22868,33519,26412,31528,23849,32503,29997,27893,36454,36856,36924,40763,27604, +37145,31508,24444,30887,34006,34109,27605,27609,27606,24065,24199,30201,38381, +25949,24330,24517,36767,22721,33218,36991,38491,38829,36793,32534,36140,25153, +20415,21464,21342,36776,36777,36779,36941,26631,24426,33176,34920,40150,24971, +21035,30250,24428,25996,28626,28392,23486,25672,20853,20912,26564,19993,31177, +39292,28851,30149,24182,29627,33760,25773,25320,38069,27874,21338,21187,25615, +38082,31636,20271,24091,33334,33046,33162,28196,27850,39539,25429,21340,21754, +34917,22496,19981,24067,27493,31807,37096,24598,25830,29468,35009,26448,25165, +36130,30572,36393,37319,24425,33756,34081,39184,21442,34453,27531,24813,24808, +28799,33485,33329,20179,27815,34255,25805,31961,27133,26361,33609,21397,31574, +20391,20876,27979,23618,36461,25554,21449,33580,33590,26597,30900,25661,23519, +23700,24046,35815,25286,26612,35962,25600,25530,34633,39307,35863,32544,38130, +20135,38416,39076,26124,29462,22330,23581,24120,38271,20607,32928,21378,25950, +30021,21809,20513,36229,25220,38046,26397,22066,28526,24034,21557,28818,36710, +25199,25764,25507,24443,28552,37108,33251,36784,23576,26216,24561,27785,38472, +36225,34924,25745,31216,22478,27225,25104,21576,20056,31243,24809,28548,35802, +25215,36894,39563,31204,21507,30196,25345,21273,27744,36831,24347,39536,32827, +40831,20360,23610,36196,32709,26021,28861,20805,20914,34411,23815,23456,25277, +37228,30068,36364,31264,24833,31609,20167,32504,30597,19985,33261,21021,20986, +27249,21416,36487,38148,38607,28353,38500,26970,30784,20648,30679,25616,35302, +22788,25571,24029,31359,26941,20256,33337,21912,20018,30126,31383,24162,24202, +38383,21019,21561,28810,25462,38180,22402,26149,26943,37255,21767,28147,32431, +34850,25139,32496,30133,33576,30913,38604,36766,24904,29943,35789,27492,21050, +36176,27425,32874,33905,22257,21254,20174,19995,20945,31895,37259,31751,20419, +36479,31713,31388,25703,23828,20652,33030,30209,31929,28140,32736,26449,23384, +23544,30923,25774,25619,25514,25387,38169,25645,36798,31572,30249,25171,22823, +21574,27513,20643,25140,24102,27526,20195,36151,34955,24453,36910,24608,32829, +25285,20025,21333,37112,25528,32966,26086,27694,20294,24814,28129,35806,24377, +34507,24403,25377,20826,33633,26723,20992,25443,36424,20498,23707,31095,23548, +21040,31291,24764,36947,30423,24503,24471,30340,36460,28783,30331,31561,30634, +20979,37011,22564,20302,28404,36842,25932,31515,29380,28068,32735,23265,25269, +24213,22320,33922,31532,24093,24351,36882,32532,39072,25474,28359,30872,28857, +20856,38747,22443,30005,20291,30008,24215,24806,22880,28096,27583,30857,21500, +38613,20939,20993,25481,21514,38035,35843,36300,29241,30879,34678,36845,35853, +21472,19969,30447,21486,38025,39030,40718,38189,23450,35746,20002,19996,20908, +33891,25026,21160,26635,20375,24683,20923,27934,20828,25238,26007,38497,35910, +36887,30168,37117,30563,27602,29322,29420,35835,22581,30585,36172,26460,38208, +32922,24230,28193,22930,31471,30701,38203,27573,26029,32526,22534,20817,38431, +23545,22697,21544,36466,25958,39039,22244,38045,30462,36929,25479,21702,22810, +22842,22427,36530,26421,36346,33333,21057,24816,22549,34558,23784,40517,20420, +39069,35769,23077,24694,21380,25212,36943,37122,39295,24681,32780,20799,32819, +23572,39285,27953,20108,36144,21457,32602,31567,20240,20047,38400,27861,29648, +34281,24070,30058,32763,27146,30718,38034,32321,20961,28902,21453,36820,33539, +36137,29359,39277,27867,22346,33459,26041,32938,25151,38450,22952,20223,35775, +32442,25918,33778,38750,21857,39134,32933,21290,35837,21536,32954,24223,27832, +36153,33452,37210,21545,27675,20998,32439,22367,28954,27774,31881,22859,20221, +24575,24868,31914,20016,23553,26539,34562,23792,38155,39118,30127,28925,36898, +20911,32541,35773,22857,20964,20315,21542,22827,25975,32932,23413,25206,25282, +36752,24133,27679,31526,20239,20440,26381,28014,28074,31119,34993,24343,29995, +25242,36741,20463,37340,26023,33071,33105,24220,33104,36212,21103,35206,36171, +22797,20613,20184,38428,29238,33145,36127,23500,35747,38468,22919,32538,21648, +22134,22030,35813,25913,27010,38041,30422,28297,24178,29976,26438,26577,31487, +32925,36214,24863,31174,25954,36195,20872,21018,38050,32568,32923,32434,23703, +28207,26464,31705,30347,39640,33167,32660,31957,25630,38224,31295,21578,21733, +27468,25601,25096,40509,33011,30105,21106,38761,33883,26684,34532,38401,38548, +38124,20010,21508,32473,26681,36319,32789,26356,24218,32697,22466,32831,26775, +24037,25915,21151,24685,40858,20379,36524,20844,23467,24339,24041,27742,25329, +36129,20849,38057,21246,27807,33503,29399,22434,26500,36141,22815,36764,33735, +21653,31629,20272,27837,23396,22993,40723,21476,34506,39592,35895,32929,25925, +39038,22266,38599,21038,29916,21072,23521,25346,35074,20054,25296,24618,26874, +20851,23448,20896,35266,31649,39302,32592,24815,28748,36143,20809,24191,36891, +29808,35268,22317,30789,24402,40863,38394,36712,39740,35809,30328,26690,26588, +36330,36149,21053,36746,28378,26829,38149,37101,22269,26524,35065,36807,21704, +39608,23401,28023,27686,20133,23475,39559,37219,25000,37039,38889,21547,28085, +23506,20989,21898,32597,32752,25788,25421,26097,25022,24717,28938,27735,27721, +22831,26477,33322,22741,22158,35946,27627,37085,22909,32791,21495,28009,21621, +21917,33655,33743,26680,31166,21644,20309,21512,30418,35977,38402,27827,28088, +36203,35088,40548,36154,22079,40657,30165,24456,29408,24680,21756,20136,27178, +34913,24658,36720,21700,28888,34425,40511,27946,23439,24344,32418,21897,20399, +29492,21564,21402,20505,21518,21628,20046,24573,29786,22774,33899,32993,34676, +29392,31946,28246,24359,34382,21804,25252,20114,27818,25143,33457,21719,21326, +29502,28369,30011,21010,21270,35805,27088,24458,24576,28142,22351,27426,29615, +26707,36824,32531,25442,24739,21796,30186,35938,28949,28067,23462,24187,33618, +24908,40644,30970,34647,31783,30343,20976,24822,29004,26179,24140,24653,35854, +28784,25381,36745,24509,24674,34516,22238,27585,24724,24935,21321,24800,26214, +36159,31229,20250,28905,27719,35763,35826,32472,33636,26127,23130,39746,27985, +28151,35905,27963,20249,28779,33719,25110,24785,38669,36135,31096,20987,22334, +22522,26426,30072,31293,31215,31637,32908,39269,36857,28608,35749,40481,23020, +32489,32521,21513,26497,26840,36753,31821,38598,21450,24613,30142,27762,21363, +23241,32423,25380,20960,33034,24049,34015,25216,20864,23395,20238,31085,21058, +24760,27982,23492,23490,35745,35760,26082,24524,38469,22931,32487,32426,22025, +26551,22841,20339,23478,21152,33626,39050,36158,30002,38078,20551,31292,20215, +26550,39550,23233,27516,30417,22362,23574,31546,38388,29006,20860,32937,33392, +22904,32516,33575,26816,26604,30897,30839,25315,25441,31616,20461,21098,20943, +33616,27099,37492,36341,36145,35265,38190,31661,20214,20581,33328,21073,39279, +28176,28293,28071,24314,20725,23004,23558,27974,27743,30086,33931,26728,22870, +35762,21280,37233,38477,34121,26898,30977,28966,33014,20132,37066,27975,39556, +23047,22204,25605,38128,30699,20389,33050,29409,35282,39290,32564,32478,21119, +25945,37237,36735,36739,21483,31382,25581,25509,30342,31224,34903,38454,25130, +21163,33410,26708,26480,25463,30571,31469,27905,32467,35299,22992,25106,34249, +33445,30028,20511,20171,30117,35819,23626,24062,31563,26020,37329,20170,27941, +35167,32039,38182,20165,35880,36827,38771,26187,31105,36817,28908,28024,23613, +21170,33606,20834,33550,30555,26230,40120,20140,24778,31934,31923,32463,20117, +35686,26223,39048,38745,22659,25964,38236,24452,30153,38742,31455,31454,20928, +28847,31384,25578,31350,32416,29590,38893,20037,28792,20061,37202,21417,25937, +26087,33276,33285,21646,23601,30106,38816,25304,29401,30141,23621,39545,33738, +23616,21632,30697,20030,27822,32858,25298,25454,24040,20855,36317,36382,38191, +20465,21477,24807,28844,21095,25424,40515,23071,20518,30519,21367,32482,25733, +25899,25225,25496,20500,29237,35273,20915,35776,32477,22343,33740,38055,20891, +21531,23803,20426,31459,27994,37089,39567,21888,21654,21345,21679,24320,25577, +26999,20975,24936,21002,22570,21208,22350,30733,30475,24247,24951,31968,25179, +25239,20130,28821,32771,25335,28900,38752,22391,33499,26607,26869,30933,39063, +31185,22771,21683,21487,28212,20811,21051,23458,35838,32943,21827,22438,24691, +22353,21549,31354,24656,23380,25511,25248,21475,25187,23495,26543,21741,31391, +33510,37239,24211,35044,22840,22446,25358,36328,33007,22359,31607,20393,24555, +23485,27454,21281,31568,29378,26694,30719,30518,26103,20917,20111,30420,23743, +31397,33909,22862,39745,20608,39304,24871,28291,22372,26118,25414,22256,25324, +25193,24275,38420,22403,25289,21895,34593,33098,36771,21862,33713,26469,36182, +34013,23146,26639,25318,31726,38417,20848,28572,35888,25597,35272,25042,32518, +28866,28389,29701,27028,29436,24266,37070,26391,28010,25438,21171,29282,32769, +20332,23013,37226,28889,28061,21202,20048,38647,38253,34174,30922,32047,20769, +22418,25794,32907,31867,27882,26865,26974,20919,21400,26792,29313,40654,31729, +29432,31163,28435,29702,26446,37324,40100,31036,33673,33620,21519,26647,20029, +21385,21169,30782,21382,21033,20616,20363,20432,30178,31435,31890,27813,38582, +21147,29827,21737,20457,32852,33714,36830,38256,24265,24604,28063,24088,25947, +33080,38142,24651,28860,32451,31918,20937,26753,31921,33391,20004,36742,37327, +26238,20142,35845,25769,32842,20698,30103,29134,23525,36797,28518,20102,25730, +38243,24278,26009,21015,35010,28872,21155,29454,29747,26519,30967,38678,20020, +37051,40158,28107,20955,36161,21533,25294,29618,33777,38646,40836,38083,20278, +32666,20940,28789,38517,23725,39046,21478,20196,28316,29705,27060,30827,39311, +30041,21016,30244,27969,26611,20845,40857,32843,21657,31548,31423,38534,22404, +25314,38471,27004,23044,25602,31699,28431,38475,33446,21346,39045,24208,28809, +25523,21348,34383,40065,40595,30860,38706,36335,36162,40575,28510,31108,24405, +38470,25134,39540,21525,38109,20387,26053,23653,23649,32533,34385,27695,24459, +29575,28388,32511,23782,25371,23402,28390,21365,20081,25504,30053,25249,36718, +20262,20177,27814,32438,35770,33821,34746,32599,36923,38179,31657,39585,35064, +33853,27931,39558,32476,22920,40635,29595,30721,34434,39532,39554,22043,21527, +22475,20080,40614,21334,36808,33033,30610,39314,34542,28385,34067,26364,24930, +28459,35881,33426,33579,30450,27667,24537,33725,29483,33541,38170,27611,30683, +38086,21359,33538,20882,24125,35980,36152,20040,29611,26522,26757,37238,38665, +29028,27809,30473,23186,38209,27599,32654,26151,23504,22969,23194,38376,38391, +20204,33804,33945,27308,30431,38192,29467,26790,23391,30511,37274,38753,31964, +36855,35868,24357,31859,31192,35269,27852,34588,23494,24130,26825,30496,32501, +20885,20813,21193,23081,32517,38754,33495,25551,30596,34256,31186,28218,24217, +22937,34065,28781,27665,25279,30399,25935,24751,38397,26126,34719,40483,38125, +21517,21629,35884,25720,25721,34321,27169,33180,30952,25705,39764,25273,26411, +33707,22696,40664,27819,28448,23518,38476,35851,29279,26576,25287,29281,20137, +22982,27597,22675,26286,24149,21215,24917,26408,30446,30566,29287,31302,25343, +21738,21584,38048,37027,23068,32435,27670,20035,22902,32784,22856,21335,30007, +38590,22218,25376,33041,24700,38393,28118,21602,39297,20869,23273,33021,22958, +38675,20522,27877,23612,25311,20320,21311,33147,36870,28346,34091,25288,24180, +30910,25781,25467,24565,23064,37247,40479,23615,25423,32834,23421,21870,38218, +38221,28037,24744,26592,29406,20957,23425,25319,27870,29275,25197,38062,32445, +33043,27987,20892,24324,22900,21162,24594,22899,26262,34384,30111,25386,25062, +31983,35834,21734,27431,40485,27572,34261,21589,20598,27812,21866,36276,29228, +24085,24597,29750,25293,25490,29260,24472,28227,27966,25856,28504,30424,30928, +30460,30036,21028,21467,20051,24222,26049,32810,32982,25243,21638,21032,28846, +34957,36305,27873,21624,32986,22521,35060,36180,38506,37197,20329,27803,21943, +30406,30768,25256,28921,28558,24429,34028,26842,30844,31735,33192,26379,40527, +25447,30896,22383,30738,38713,25209,25259,21128,29749,27607,21860,33086,30130, +30382,21305,30174,20731,23617,35692,31687,20559,29255,39575,39128,28418,29922, +31080,25735,30629,25340,39057,36139,21697,32856,20050,22378,33529,33805,24179, +20973,29942,35780,23631,22369,27900,39047,23110,30772,39748,36843,31893,21078, +25169,38138,20166,33670,33889,33769,33970,22484,26420,22275,26222,28006,35889, +26333,28689,26399,27450,26646,25114,22971,19971,20932,28422,26578,27791,20854, +26827,22855,27495,30054,23822,33040,40784,26071,31048,31041,39569,36215,23682, +20062,20225,21551,22865,30732,22120,27668,36804,24323,27773,27875,35755,25488, +24688,27965,29301,25190,38030,38085,21315,36801,31614,20191,35878,20094,40660, +38065,38067,21069,28508,36963,27973,35892,22545,23884,27424,27465,26538,21595, +33108,32652,22681,34103,24378,25250,27207,38201,25970,24708,26725,30631,20052, +20392,24039,38808,25772,32728,23789,20431,31373,20999,33540,19988,24623,31363, +38054,20405,20146,31206,29748,21220,33465,25810,31165,23517,27777,38738,36731, +27682,20542,21375,28165,25806,26228,27696,24773,39031,35831,24198,29756,31351, +31179,19992,37041,29699,27714,22234,37195,27845,36235,21306,34502,26354,36527, +23624,39537,28192,21462,23094,40843,36259,21435,22280,39079,26435,37275,27849, +20840,30154,25331,29356,21048,21149,32570,28820,30264,21364,40522,27063,30830, +38592,35033,32676,28982,29123,20873,26579,29924,22756,25880,22199,35753,39286, +25200,32469,24825,28909,22764,20161,20154,24525,38887,20219,35748,20995,22922, +32427,25172,20173,26085,25102,33592,33993,33635,34701,29076,28342,23481,32466, +20887,25545,26580,32905,33593,34837,20754,23418,22914,36785,20083,27741,20837, +35109,36719,38446,34122,29790,38160,38384,28070,33509,24369,25746,27922,33832, +33134,40131,22622,36187,19977,21441,20254,25955,26705,21971,20007,25620,39578, +25195,23234,29791,33394,28073,26862,20711,33678,30722,26432,21049,27801,32433, +20667,21861,29022,31579,26194,29642,33515,26441,23665,21024,29053,34923,38378, +38485,25797,36193,33203,21892,27733,25159,32558,22674,20260,21830,36175,26188, +19978,23578,35059,26786,25422,31245,28903,33421,21242,38902,23569,21736,37045, +32461,22882,36170,34503,33292,33293,36198,25668,23556,24913,28041,31038,35774, +30775,30003,21627,20280,36523,28145,23072,32453,31070,27784,23457,23158,29978, +32958,24910,28183,22768,29983,29989,29298,21319,32499,30465,30427,21097,32988, +22307,24072,22833,29422,26045,28287,35799,23608,34417,21313,30707,25342,26102, +20160,39135,34432,23454,35782,21490,30690,20351,23630,39542,22987,24335,31034, +22763,19990,26623,20107,25325,35475,36893,21183,26159,21980,22124,36866,20181, +20365,37322,39280,27663,24066,24643,23460,35270,35797,25910,25163,39318,23432, +23551,25480,21806,21463,30246,20861,34092,26530,26803,27530,25234,36755,21460, +33298,28113,30095,20070,36174,23408,29087,34223,26257,26329,32626,34560,40653, +40736,23646,26415,36848,26641,26463,25101,31446,22661,24246,25968,28465,24661, +21047,32781,25684,34928,29993,24069,26643,25332,38684,21452,29245,35841,27700, +30561,31246,21550,30636,39034,33308,35828,30805,26388,28865,26031,25749,22070, +24605,31169,21496,19997,27515,32902,23546,21987,22235,20282,20284,39282,24051, +26494,32824,24578,39042,36865,23435,35772,35829,25628,33368,25822,22013,33487, +37221,20439,32032,36895,31903,20723,22609,28335,23487,35785,32899,37240,33948, +31639,34429,38539,38543,32485,39635,30862,23681,31319,36930,38567,31071,23385, +25439,31499,34001,26797,21766,32553,29712,32034,38145,25152,22604,20182,23427, +22905,22612,29549,25374,36427,36367,32974,33492,25260,21488,27888,37214,22826, +24577,27760,22349,25674,36138,30251,28393,22363,27264,30192,28525,35885,35848, +22374,27631,34962,30899,25506,21497,28845,27748,22616,25642,22530,26848,33179, +21776,31958,20504,36538,28108,36255,28907,25487,28059,28372,32486,33796,26691, +36867,28120,38518,35752,22871,29305,34276,33150,30140,35466,26799,21076,36386, +38161,25552,39064,36420,21884,20307,26367,22159,24789,28053,21059,23625,22825, +28155,22635,30000,29980,24684,33300,33094,25361,26465,36834,30522,36339,36148, +38081,24086,21381,21548,28867,27712,24311,20572,20141,24237,25402,33351,36890, +26704,37230,30643,21516,38108,24420,31461,26742,25413,31570,32479,30171,20599, +25237,22836,36879,20984,31171,31361,22270,24466,36884,28034,23648,22303,21520, +20820,28237,22242,25512,39059,33151,34581,35114,36864,21534,23663,33216,25302, +25176,33073,40501,38464,39534,39548,26925,22949,25299,21822,25366,21703,34521, +27964,23043,29926,34972,27498,22806,35916,24367,28286,29609,39037,20024,28919, +23436,30871,25405,26202,30358,24779,23451,23113,19975,33109,27754,29579,20129, +26505,32593,24448,26106,26395,24536,22916,23041,24013,24494,21361,38886,36829, +26693,22260,21807,24799,20026,28493,32500,33479,33806,22996,20255,20266,23614, +32428,26410,34074,21619,30031,32963,21890,39759,20301,28205,35859,23561,24944, +21355,30239,28201,34442,25991,38395,32441,21563,31283,32010,38382,21985,32705, +29934,25373,34583,28065,31389,25105,26017,21351,25569,27779,24043,21596,38056, +20044,27745,35820,23627,26080,33436,26791,21566,21556,27595,27494,20116,25410, +21320,33310,20237,20398,22366,25098,38654,26212,29289,21247,21153,24735,35823, +26132,29081,26512,35199,30802,30717,26224,22075,21560,38177,29306,31232,24687, +24076,24713,33181,22805,24796,29060,28911,28330,27728,29312,27268,34989,24109, +20064,23219,21916,38115,27927,31995,38553,25103,32454,30606,34430,21283,38686, +36758,26247,23777,20384,29421,19979,21414,22799,21523,25472,38184,20808,20185, +40092,32420,21688,36132,34900,33335,38386,28046,24358,23244,26174,38505,29616, +29486,21439,33146,39301,32673,23466,38519,38480,32447,30456,21410,38262,39321, +31665,35140,28248,20065,32724,31077,35814,24819,21709,20139,39033,24055,27233, +20687,21521,35937,33831,30813,38660,21066,21742,22179,38144,28040,23477,28102, +26195,23567,23389,26657,32918,21880,31505,25928,26964,20123,27463,34638,38795, +21327,25375,25658,37034,26012,32961,35856,20889,26800,21368,34809,25032,27844, +27899,35874,23633,34218,33455,38156,27427,36763,26032,24571,24515,20449,34885, +26143,33125,29481,24826,20852,21009,22411,24418,37026,34892,37266,24184,26447, +24615,22995,20804,20982,33016,21256,27769,38596,29066,20241,20462,32670,26429, +21957,38152,31168,34966,32483,22687,25100,38656,34394,22040,39035,24464,35768, +33988,37207,21465,26093,24207,30044,24676,32110,23167,32490,32493,36713,21927, +23459,24748,26059,29572,36873,30307,30505,32474,38772,34203,23398,31348,38634, +34880,21195,29071,24490,26092,35810,23547,39535,24033,27529,27739,35757,35759, +36874,36805,21387,25276,40486,40493,21568,20011,33469,29273,34460,23830,34905, +28079,38597,21713,20122,35766,28937,21693,38409,28895,28153,30416,20005,30740, +34578,23721,24310,35328,39068,38414,28814,27839,22852,25513,30524,34893,28436, +33395,22576,29141,21388,30746,38593,21761,24422,28976,23476,35866,39564,27523, +22830,40495,31207,26472,25196,20335,30113,32650,27915,38451,27687,20208,30162, +20859,26679,28478,36992,33136,22934,29814,25671,23591,36965,31377,35875,23002, +21676,33280,33647,35201,32768,26928,22094,32822,29239,37326,20918,20063,39029, +25494,19994,21494,26355,33099,22812,28082,19968,22777,21307,25558,38129,20381, +20234,34915,39056,22839,36951,31227,20202,33008,30097,27778,23452,23016,24413, +26885,34433,20506,24050,20057,30691,20197,33402,25233,26131,37009,23673,20159, +24441,33222,36920,32900,30123,20134,35028,24847,27589,24518,20041,30410,28322, +35811,35758,35850,35793,24322,32764,32716,32462,33589,33643,22240,27575,38899, +38452,23035,21535,38134,28139,23493,39278,23609,24341,38544,21360,33521,27185, +23156,40560,24212,32552,33721,33828,33829,33639,34631,36814,36194,30408,24433, +39062,30828,26144,21727,25317,20323,33219,30152,24248,38605,36362,34553,21647, +27891,28044,27704,24703,21191,29992,24189,20248,24736,24551,23588,30001,37038, +38080,29369,27833,28216,37193,26377,21451,21491,20305,37321,35825,21448,24188, +36802,28132,20110,30402,27014,34398,24858,33286,20313,20446,36926,40060,24841, +28189,28180,38533,20104,23089,38632,19982,23679,31161,23431,35821,32701,29577, +22495,33419,37057,21505,36935,21947,23786,24481,24840,27442,29425,32946,35465, +28020,23507,35029,39044,35947,39533,40499,28170,20900,20803,22435,34945,21407, +25588,36757,22253,21592,22278,29503,28304,32536,36828,33489,24895,24616,38498, +26352,32422,36234,36291,38053,23731,31908,26376,24742,38405,32792,20113,37095, +21248,38504,20801,36816,34164,37213,26197,38901,23381,21277,30776,26434,26685, +21705,28798,23472,36733,20877,22312,21681,25874,26242,36190,36163,33039,33900, +36973,31967,20991,34299,26531,26089,28577,34468,36481,22122,36896,30338,28790, +29157,36131,25321,21017,27901,36156,24590,22686,24974,26366,36192,25166,21939, +28195,26413,36711,38113,38392,30504,26629,27048,21643,20045,28856,35784,25688, +25995,23429,31364,20538,23528,30651,27617,35449,31896,27838,30415,26025,36759, +23853,23637,34360,26632,21344,25112,31449,28251,32509,27167,31456,24432,28467, +24352,25484,28072,26454,19976,24080,36134,20183,32960,30260,38556,25307,26157, +25214,27836,36213,29031,32617,20806,32903,21484,36974,25240,21746,34544,36761, +32773,38167,34071,36825,27993,29645,26015,30495,29956,30759,33275,36126,38024, +20390,26517,30137,35786,38663,25391,38215,38453,33976,25379,30529,24449,29424, +20105,24596,25972,25327,27491,25919,24103,30151,37073,35777,33437,26525,25903, +21553,34584,30693,32930,33026,27713,20043,32455,32844,30452,26893,27542,25191, +20540,20356,22336,25351,27490,36286,21482,26088,32440,24535,25370,25527,33267, +33268,32622,24092,23769,21046,26234,31209,31258,36136,28825,30164,28382,27835, +31378,20013,30405,24544,38047,34935,32456,31181,32959,37325,20210,20247,33311, +21608,24030,27954,35788,31909,36724,32920,24090,21650,30385,23449,26172,39588, +29664,26666,34523,26417,29482,35832,35803,36880,31481,28891,29038,25284,30633, +22065,20027,33879,26609,21161,34496,36142,38136,31569,20303,27880,31069,39547, +25235,29226,25341,19987,30742,36716,25776,36186,31686,26729,24196,35013,22918, +25758,22766,29366,26894,38181,36861,36184,22368,32512,35846,20934,25417,25305, +21331,26700,29730,33537,37196,21828,30528,28796,27978,20857,21672,36164,23039, +28363,28100,23388,32043,20180,31869,28371,23376,33258,28173,23383,39683,26837, +36394,23447,32508,24635,32437,37049,36208,22863,25549,31199,36275,21330,26063, +31062,35781,38459,32452,38075,32386,22068,37257,26368,32618,23562,36981,26152, +24038,20304,26590,20570,20316,22352,24231,20109,19980,20800,19984,24319,21317, +19989,20120,19998,39730,23404,22121,20008,31162,20031,21269,20039,22829,29243, +21358,27664,22239,32996,39319,27603,30590,40727,20022,20127,40720,20060,20073, +20115,33416,23387,21868,22031,20164,21389,21405,21411,21413,21422,38757,36189, +21274,21493,21286,21294,21310,36188,21350,21347,20994,21000,21006,21037,21043, +21055,21056,21068,21086,21089,21084,33967,21117,21122,21121,21136,21139,20866, +32596,20155,20163,20169,20162,20200,20193,20203,20190,20251,20211,20258,20324, +20213,20261,20263,20233,20267,20318,20327,25912,20314,20317,20319,20311,20274, +20285,20342,20340,20369,20361,20355,20367,20350,20347,20394,20348,20396,20372, +20454,20456,20458,20421,20442,20451,20444,20433,20447,20472,20521,20556,20467, +20524,20495,20526,20525,20478,20508,20492,20517,20520,20606,20547,20565,20552, +20558,20588,20603,20645,20647,20649,20666,20694,20742,20717,20716,20710,20718, +20743,20747,20189,27709,20312,20325,20430,40864,27718,31860,20846,24061,40649, +39320,20865,22804,21241,21261,35335,21264,20971,22809,20821,20128,20822,20147, +34926,34980,20149,33044,35026,31104,23348,34819,32696,20907,20913,20925,20924, +20935,20886,20898,20901,35744,35750,35751,35754,35764,35765,35767,35778,35779, +35787,35791,35790,35794,35795,35796,35798,35800,35801,35804,35807,35808,35812, +35816,35817,35822,35824,35827,35830,35833,35836,35839,35840,35842,35844,35847, +35852,35855,35857,35858,35860,35861,35862,35865,35867,35864,35869,35871,35872, +35873,35877,35879,35882,35883,35886,35887,35890,35891,35893,35894,21353,21370, +38429,38434,38433,38449,38442,38461,38460,38466,38473,38484,38495,38503,38508, +38514,38516,38536,38541,38551,38576,37015,37019,37021,37017,37036,37025,37044, +37043,37046,37050,37048,37040,37071,37061,37054,37072,37060,37063,37075,37094, +37090,37084,37079,37083,37099,37103,37118,37124,37154,37150,37155,37169,37167, +37177,37187,37190,21005,22850,21154,21164,21165,21182,21759,21200,21206,21232, +21471,29166,30669,24308,20981,20988,39727,21430,24321,30042,24047,22348,22441, +22433,22654,22716,22725,22737,22313,22316,22314,22323,22329,22318,22319,22364, +22331,22338,22377,22405,22379,22406,22396,22395,22376,22381,22390,22387,22445, +22436,22412,22450,22479,22439,22452,22419,22432,22485,22488,22490,22489,22482, +22456,22516,22511,22520,22500,22493,22539,22541,22525,22509,22528,22558,22553, +22596,22560,22629,22636,22657,22665,22682,22656,39336,40729,25087,33401,33405, +33407,33423,33418,33448,33412,33422,33425,33431,33433,33451,33464,33470,33456, +33480,33482,33507,33432,33463,33454,33483,33484,33473,33449,33460,33441,33450, +33439,33476,33486,33444,33505,33545,33527,33508,33551,33543,33500,33524,33490, +33496,33548,33531,33491,33553,33562,33542,33556,33557,33504,33493,33564,33617, +33627,33628,33544,33682,33596,33588,33585,33691,33630,33583,33615,33607,33603, +33631,33600,33559,33632,33581,33594,33587,33638,33637,33640,33563,33641,33644, +33642,33645,33646,33712,33656,33715,33716,33696,33706,33683,33692,33669,33660, +33718,33705,33661,33720,33659,33688,33694,33704,33722,33724,33729,33793,33765, +33752,22535,33816,33803,33757,33789,33750,33820,33848,33809,33798,33748,33759, +33807,33795,33784,33785,33770,33733,33728,33830,33776,33761,33884,33873,33882, +33881,33907,33927,33928,33914,33929,33912,33852,33862,33897,33910,33932,33934, +33841,33901,33985,33997,34000,34022,33981,34003,33994,33983,33978,34016,33953, +33977,33972,33943,34021,34019,34060,29965,34104,34032,34105,34079,34106,34134, +34107,34047,34044,34137,34120,34152,34148,34142,34170,30626,34115,34162,34171, +34212,34216,34183,34191,34169,34222,34204,34181,34233,34231,34224,34259,34241, +34268,34303,34343,34309,34345,34326,34364,24318,24328,22844,22849,32823,22869, +22874,22872,21263,23586,23589,23596,23604,25164,25194,25247,25275,25290,25306, +25303,25326,25378,25334,25401,25419,25411,25517,25590,25457,25466,25486,25524, +25453,25516,25482,25449,25518,25532,25586,25592,25568,25599,25540,25566,25550, +25682,25542,25534,25669,25665,25611,25627,25632,25612,25638,25633,25694,25732, +25709,25750,25722,25783,25784,25753,25786,25792,25808,25815,25828,25826,25865, +25893,25902,24331,24530,29977,24337,21343,21489,21501,21481,21480,21499,21522, +21526,21510,21579,21586,21587,21588,21590,21571,21537,21591,21593,21539,21554, +21634,21652,21623,21617,21604,21658,21659,21636,21622,21606,21661,21712,21677, +21698,21684,21714,21671,21670,21715,21716,21618,21667,21717,21691,21695,21708, +21721,21722,21724,21673,21674,21668,21725,21711,21726,21787,21735,21792,21757, +21780,21747,21794,21795,21775,21777,21799,21802,21863,21903,21941,21833,21869, +21825,21845,21823,21840,21820,21815,21846,21877,21878,21879,21811,21808,21852, +21899,21970,21891,21937,21945,21896,21889,21919,21886,21974,21905,21883,21983, +21949,21950,21908,21913,21994,22007,21961,22047,21969,21995,21996,21972,21990, +21981,21956,21999,21989,22002,22003,21964,21965,21992,22005,21988,36756,22046, +22024,22028,22017,22052,22051,22014,22016,22055,22061,22104,22073,22103,22060, +22093,22114,22105,22108,22092,22100,22150,22116,22129,22123,22139,22140,22149, +22163,22191,22228,22231,22237,22241,22261,22251,22265,22271,22276,22282,22281, +22300,24079,24089,24084,24081,24113,24123,24124,24119,24132,24148,24155,24158, +24161,23692,23674,23693,23696,23702,23688,23704,23705,23697,23706,23708,23733, +23714,23741,23724,23723,23729,23715,23745,23735,23748,23762,23780,23755,23781, +23810,23811,23847,23846,23854,23844,23838,23814,23835,23896,23870,23860,23869, +23916,23899,23919,23901,23915,23883,23882,23913,23924,23938,23961,23965,35955, +23991,24005,24435,24439,24450,24455,24457,24460,24469,24473,24476,24488,24493, +24501,24508,34914,24417,29357,29360,29364,29367,29368,29379,29377,29390,29389, +29394,29416,29423,29417,29426,29428,29431,29441,29427,29443,29434,29435,29463, +29459,29473,29450,29470,29469,29461,29474,29497,29477,29484,29496,29489,29520, +29517,29527,29536,29548,29551,29566,33307,22821,39143,22820,22786,39267,39271, +39272,39273,39274,39275,39276,39284,39287,39293,39296,39300,39303,39306,39309, +39312,39313,39315,39316,39317,24192,24209,24203,24214,24229,24224,24249,24245, +24254,24243,36179,24274,24273,24283,24296,24298,33210,24516,24521,24534,24527, +24579,24558,24580,24545,24548,24574,24581,24582,24554,24557,24568,24601,24629, +24614,24603,24591,24589,24617,24619,24586,24639,24609,24696,24697,24699,24698, +24642,24682,24701,24726,24730,24749,24733,24707,24722,24716,24731,24812,24763, +24753,24797,24792,24774,24794,24756,24864,24870,24853,24867,24820,24832,24846, +24875,24906,24949,25004,24980,24999,25015,25044,25077,24541,38579,38377,38379, +38385,38387,38389,38390,38396,38398,38403,38404,38406,38408,38410,38411,38412, +38413,38415,38418,38421,38422,38423,38425,38426,20012,29247,25109,27701,27732, +27740,27722,27811,27781,27792,27796,27788,27752,27753,27764,27766,27782,27817, +27856,27860,27821,27895,27896,27889,27863,27826,27872,27862,27898,27883,27886, +27825,27859,27887,27902,27961,27943,27916,27971,27976,27911,27908,27929,27918, +27947,27981,27950,27957,27930,27983,27986,27988,27955,28049,28015,28062,28064, +27998,28051,28052,27996,28000,28028,28003,28186,28103,28101,28126,28174,28095, +28128,28177,28134,28125,28121,28182,28075,28172,28078,28203,28270,28238,28267, +28338,28255,28294,28243,28244,28210,28197,28228,28383,28337,28312,28384,28461, +28386,28325,28327,28349,28347,28343,28375,28340,28367,28303,28354,28319,28514, +28486,28487,28452,28437,28409,28463,28470,28491,28532,28458,28425,28457,28553, +28557,28556,28536,28530,28540,28538,28625,28617,28583,28601,28598,28610,28641, +28654,28638,28640,28655,28698,28707,28699,28729,28725,28751,28766,23424,23428, +23445,23443,23461,23480,29999,39582,25652,23524,23534,35120,23536,36423,35591, +36790,36819,36821,36837,36846,36836,36841,36838,36851,36840,36869,36868,36875, +36902,36881,36877,36886,36897,36917,36918,36909,36911,36932,36945,36946,36944, +36968,36952,36962,36955,26297,36980,36989,36994,37000,36995,37003,24400,24407, +24406,24408,23611,21675,23632,23641,23409,23651,23654,32700,24362,24361,24365, +33396,24380,39739,23662,22913,22915,22925,22953,22954,22947,22935,22986,22955, +22942,22948,22994,22962,22959,22999,22974,23045,23046,23005,23048,23011,23000, +23033,23052,23049,23090,23092,23057,23075,23059,23104,23143,23114,23125,23100, +23138,23157,33004,23210,23195,23159,23162,23230,23275,23218,23250,23252,23224, +23264,23267,23281,23254,23270,23256,23260,23305,23319,23318,23346,23351,23360, +23573,23580,23386,23397,23411,23377,23379,23394,39541,39543,39544,39546,39551, +39549,39552,39553,39557,39560,39562,39568,39570,39571,39574,39576,39579,39580, +39581,39583,39584,39586,39587,39589,39591,32415,32417,32419,32421,32424,32425, +32429,32432,32446,32448,32449,32450,32457,32459,32460,32464,32468,32471,32475, +32480,32481,32488,32491,32494,32495,32497,32498,32525,32502,32506,32507,32510, +32513,32514,32515,32519,32520,32523,32524,32527,32529,32530,32535,32537,32540, +32539,32543,32545,32546,32547,32548,32549,32550,32551,32554,32555,32556,32557, +32559,32560,32561,32562,32563,32565,24186,30079,24027,30014,37013,29582,29585, +29614,29602,29599,29647,29634,29649,29623,29619,29632,29641,29640,29669,29657, +39036,29706,29673,29671,29662,29626,29682,29711,29738,29787,29734,29733,29736, +29744,29742,29740,29723,29722,29761,29788,29783,29781,29785,29815,29805,29822, +29852,29838,29824,29825,29831,29835,29854,29864,29865,29840,29863,29906,29882, +38890,38891,38892,26444,26451,26462,26440,26473,26533,26503,26474,26483,26520, +26535,26485,26536,26526,26541,26507,26487,26492,26608,26633,26584,26634,26601, +26544,26636,26585,26549,26586,26547,26589,26624,26563,26552,26594,26638,26561, +26621,26674,26675,26720,26721,26702,26722,26692,26724,26755,26653,26709,26726, +26689,26727,26688,26686,26698,26697,26665,26805,26767,26740,26743,26771,26731, +26818,26990,26876,26911,26912,26873,26916,26864,26891,26881,26967,26851,26896, +26993,26937,26976,26946,26973,27012,26987,27008,27032,27000,26932,27084,27015, +27016,27086,27017,26982,26979,27001,27035,27047,27067,27051,27053,27092,27057, +27073,27082,27103,27029,27104,27021,27135,27183,27117,27159,27160,27237,27122, +27204,27198,27296,27216,27227,27189,27278,27257,27197,27176,27224,27260,27281, +27280,27305,27287,27307,29495,29522,27521,27522,27527,27524,27538,27539,27533, +27546,27547,27553,27562,36715,36717,36721,36722,36723,36725,36726,36728,36727, +36729,36730,36732,36734,36737,36738,36740,36743,36747,36749,36750,36751,36760, +36762,36558,25099,25111,25115,25119,25122,25121,25125,25124,25132,33255,29935, +29940,29951,29967,29969,29971,25908,26094,26095,26096,26122,26137,26482,26115, +26133,26112,28805,26359,26141,26164,26161,26166,26165,32774,26207,26196,26177, +26191,26198,26209,26199,26231,26244,26252,26279,26269,26302,26331,26332,26342, +26345,36146,36147,36150,36155,36157,36160,36165,36166,36168,36169,36167,36173, +36181,36185,35271,35274,35275,35276,35278,35279,35280,35281,29294,29343,29277, +29286,29295,29310,29311,29316,29323,29325,29327,29330,25352,25394,25520,25663, +25816,32772,27626,27635,27645,27637,27641,27653,27655,27654,27661,27669,27672, +27673,27674,27681,27689,27684,27690,27698,25909,25941,25963,29261,29266,29270, +29232,34402,21014,32927,32924,32915,32956,26378,32957,32945,32939,32941,32948, +32951,32999,33000,33001,33002,32987,32962,32964,32985,32973,32983,26384,32989, +33003,33009,33012,33005,33037,33038,33010,33020,26389,33042,35930,33078,33054, +33068,33048,33074,33096,33100,33107,33140,33113,33114,33137,33120,33129,33148, +33149,33133,33127,22605,23221,33160,33154,33169,28373,33187,33194,33228,26406, +33226,33211,33217,33190,27428,27447,27449,27459,27462,27481,39121,39122,39123, +39125,39129,39130,27571,24384,27586,35315,26000,40785,26003,26044,26054,26052, +26051,26060,26062,26066,26070,28800,28828,28822,28829,28859,28864,28855,28843, +28849,28904,28874,28944,28947,28950,28975,28977,29043,29020,29032,28997,29042, +29002,29048,29050,29080,29107,29109,29096,29088,29152,29140,29159,29177,29213, +29224,28780,28952,29030,29113,25150,25149,25155,25160,25161,31035,31040,31046, +31049,31067,31068,31059,31066,31074,31063,31072,31087,31079,31098,31109,31114, +31130,31143,31155,24529,24528,24636,24669,24666,24679,24641,24665,24675,24747, +24838,24845,24925,25001,24989,25035,25041,25094,32896,32895,27795,27894,28156, +30710,30712,30720,30729,30743,30744,30737,26027,30765,30748,30749,30777,30778, +30779,30751,30780,30757,30764,30755,30761,30798,30829,30806,30807,30758,30800, +30791,30796,30826,30875,30867,30874,30855,30876,30881,30883,30898,30905,30885, +30932,30937,30921,30956,30962,30981,30964,30995,31012,31006,31028,40859,40697, +40699,40700,30449,30468,30477,30457,30471,30472,30490,30498,30489,30509,30502, +30517,30520,30544,30545,30535,30531,30554,30568,30562,30565,30591,30605,30589, +30592,30604,30609,30623,30624,30640,30645,30653,30010,30016,30030,30027,30024, +30043,30066,30073,30083,32600,32609,32607,35400,32616,32628,32625,32633,32641, +32638,30413,30437,34866,38021,38022,38023,38027,38026,38028,38029,38031,38032, +38036,38039,38037,38042,38043,38044,38051,38052,38059,38058,38061,38060,38063, +38064,38066,38068,38070,38071,38072,38073,38074,38076,38077,38079,38084,38088, +38089,38090,38091,38092,38093,38094,38096,38097,38098,38101,38102,38103,38105, +38104,38107,38110,38111,38112,38114,38116,38117,38119,38120,38122,38121,38123, +38126,38127,38131,38132,38133,38135,38137,38140,38141,38143,38147,38146,38150, +38151,38153,38154,38157,38158,38159,38162,38163,38164,38165,38166,38168,38171, +38173,38174,38175,38178,38186,38187,38185,38188,38193,38194,38196,38198,38199, +38200,38204,38206,38207,38210,38197,38212,38213,38214,38217,38220,38222,38223, +38226,38227,38228,38230,38231,38232,38233,38235,38238,38239,38237,38241,38242, +38244,38245,38246,38247,38248,38249,38250,38251,38252,38255,38257,38258,38259, +38202,30695,30700,38601,31189,31213,31203,31211,31238,23879,31235,31234,31262, +31252,31289,31287,31313,40655,39333,31344,30344,30350,30355,30361,30372,29918, +29920,29996,40480,40482,40488,40489,40490,40491,40492,40498,40497,40502,40504, +40503,40505,40506,40510,40513,40514,40516,40518,40519,40520,40521,40523,40524, +40526,40529,40533,40535,40538,40539,40540,40542,40547,40550,40551,40552,40553, +40554,40555,40556,40561,40557,40563,30098,30100,30102,30112,30109,30124,30115, +30131,30132,30136,30148,30129,30128,30147,30146,30166,30157,30179,30184,30182, +30180,30187,30183,30211,30193,30204,30207,30224,30208,30213,30220,30231,30218, +30245,30232,30229,30233,30235,30268,30242,30240,30272,30253,30256,30271,30261, +30275,30270,30259,30285,30302,30292,30300,30294,30315,30319,32714,31462,31352, +31353,31360,31366,31368,31381,31398,31392,31404,31400,31405,31411,34916,34921, +34930,34941,34943,34946,34978,35014,34999,35004,35017,35042,35022,35043,35045, +35057,35098,35068,35048,35070,35056,35105,35097,35091,35099,35082,35124,35115, +35126,35137,35174,35195,30091,32997,30386,30388,30684,32786,32788,32790,32796, +32800,32802,32805,32806,32807,32809,32808,32817,32779,32821,32835,32838,32845, +32850,32873,32881,35203,39032,39040,39043,39049,39052,39053,39055,39060,39066, +39067,39070,39071,39073,39074,39077,39078,34381,34388,34412,34414,34431,34426, +34428,34427,34472,34445,34443,34476,34461,34471,34467,34474,34451,34473,34486, +34500,34485,34510,34480,34490,34481,34479,34505,34511,34484,34537,34545,34546, +34541,34547,34512,34579,34526,34548,34527,34520,34513,34563,34567,34552,34568, +34570,34573,34569,34595,34619,34590,34597,34606,34586,34622,34632,34612,34609, +34601,34615,34623,34690,34594,34685,34686,34683,34656,34672,34636,34670,34699, +34643,34659,34684,34660,34649,34661,34707,34735,34728,34770,34758,34696,34693, +34733,34711,34691,34731,34789,34732,34741,34739,34763,34771,34749,34769,34752, +34762,34779,34794,34784,34798,34838,34835,34814,34826,34843,34849,34873,34876, +32566,32578,32580,32581,33296,31482,31485,31496,31491,31492,31509,31498,31531, +31503,31559,31544,31530,31513,31534,31537,31520,31525,31524,31539,31550,31518, +31576,31578,31557,31605,31564,31581,31584,31598,31611,31586,31602,31601,31632, +31654,31655,31672,31660,31645,31656,31621,31658,31644,31650,31659,31668,31697, +31681,31692,31709,31706,31717,31718,31722,31756,31742,31740,31759,31766,31755, +31775,31786,31782,31800,31809,31808,33278,33281,33282,33284,33260,34884,33313, +33314,33315,33325,33327,33320,33323,33336,33339,33331,33332,33342,33348,33353, +33355,33359,33370,33375,33384,34942,34949,34952,35032,35039,35166,32669,32671, +32679,32687,32688,32690,31868,25929,31889,31901,31900,31902,31906,31922,31932, +31933,31937,31943,31948,31949,31944,31941,31959,31976,33390,26280,32703,32718, +32725,32741,32737,32742,32745,32750,32755,31992,32119,32166,32174,32327,32411, +40632,40628,36211,36228,36244,36241,36273,36199,36205,35911,35913,37194,37200, +37198,37199,37220,37218,37217,37232,37225,37231,37245,37246,37234,37236,37241, +37260,37253,37264,37261,37265,37282,37283,37290,37293,37294,37295,37301,37300, +37306,35925,40574,36280,36331,36357,36441,36457,36277,36287,36284,36282,36292, +36310,36311,36314,36318,36302,36303,36315,36294,36332,36343,36344,36323,36345, +36347,36324,36361,36349,36372,36381,36383,36396,36398,36387,36399,36410,36416, +36409,36405,36413,36401,36425,36417,36418,36433,36434,36426,36464,36470,36476, +36463,36468,36485,36495,36500,36496,36508,36510,35960,35970,35978,35973,35992, +35988,26011,35286,35294,35290,35292,35301,35307,35311,35390,35622,38739,38633, +38643,38639,38662,38657,38664,38671,38670,38698,38701,38704,38718,40832,40835, +40837,40838,40839,40840,40841,40842,40844,40702,40715,40717,38585,38588,38589, +38606,38610,30655,38624,37518,37550,37576,37694,37738,37834,37775,37950,37995, +40063,40066,40069,40070,40071,40072,31267,40075,40078,40080,40081,40082,40084, +40085,40090,40091,40094,40095,40096,40097,40098,40099,40101,40102,40103,40104, +40105,40107,40109,40110,40112,40113,40114,40115,40116,40117,40118,40119,40122, +40123,40124,40125,40132,40133,40134,40135,40138,40139,40140,40141,40142,40143, +40144,40147,40148,40149,40151,40152,40153,40156,40157,40159,40162,38780,38789, +38801,38802,38804,38831,38827,38819,38834,38836,39601,39600,39607,40536,39606, +39610,39612,39617,39616,39621,39618,39627,39628,39633,39749,39747,39751,39753, +39752,39757,39761,39144,39181,39214,39253,39252,39647,39649,39654,39663,39659, +39675,39661,39673,39688,39695,39699,39711,39715,40637,40638,32315,40578,40583, +40584,40587,40594,37846,40605,40607,40667,40668,40669,40672,40671,40674,40681, +40679,40677,40682,40687,40738,40748,40751,40761,40759,40765,40766,40772, +}; + +static const struct dbcs_index gb2312_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb2312_decmap+0,33,126},{__gb2312_decmap+94, +49,124},{__gb2312_decmap+170,33,126},{__gb2312_decmap+264,33,115},{ +__gb2312_decmap+347,33,118},{__gb2312_decmap+433,33,88},{__gb2312_decmap+489, +33,113},{__gb2312_decmap+570,33,105},{__gb2312_decmap+643,36,111},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb2312_decmap+719,33,126},{ +__gb2312_decmap+813,33,126},{__gb2312_decmap+907,33,126},{__gb2312_decmap+1001 +,33,126},{__gb2312_decmap+1095,33,126},{__gb2312_decmap+1189,33,126},{ +__gb2312_decmap+1283,33,126},{__gb2312_decmap+1377,33,126},{__gb2312_decmap+ +1471,33,126},{__gb2312_decmap+1565,33,126},{__gb2312_decmap+1659,33,126},{ +__gb2312_decmap+1753,33,126},{__gb2312_decmap+1847,33,126},{__gb2312_decmap+ +1941,33,126},{__gb2312_decmap+2035,33,126},{__gb2312_decmap+2129,33,126},{ +__gb2312_decmap+2223,33,126},{__gb2312_decmap+2317,33,126},{__gb2312_decmap+ +2411,33,126},{__gb2312_decmap+2505,33,126},{__gb2312_decmap+2599,33,126},{ +__gb2312_decmap+2693,33,126},{__gb2312_decmap+2787,33,126},{__gb2312_decmap+ +2881,33,126},{__gb2312_decmap+2975,33,126},{__gb2312_decmap+3069,33,126},{ +__gb2312_decmap+3163,33,126},{__gb2312_decmap+3257,33,126},{__gb2312_decmap+ +3351,33,126},{__gb2312_decmap+3445,33,126},{__gb2312_decmap+3539,33,126},{ +__gb2312_decmap+3633,33,126},{__gb2312_decmap+3727,33,126},{__gb2312_decmap+ +3821,33,126},{__gb2312_decmap+3915,33,126},{__gb2312_decmap+4009,33,126},{ +__gb2312_decmap+4103,33,126},{__gb2312_decmap+4197,33,126},{__gb2312_decmap+ +4291,33,126},{__gb2312_decmap+4385,33,121},{__gb2312_decmap+4474,33,126},{ +__gb2312_decmap+4568,33,126},{__gb2312_decmap+4662,33,126},{__gb2312_decmap+ +4756,33,126},{__gb2312_decmap+4850,33,126},{__gb2312_decmap+4944,33,126},{ +__gb2312_decmap+5038,33,126},{__gb2312_decmap+5132,33,126},{__gb2312_decmap+ +5226,33,126},{__gb2312_decmap+5320,33,126},{__gb2312_decmap+5414,33,126},{ +__gb2312_decmap+5508,33,126},{__gb2312_decmap+5602,33,126},{__gb2312_decmap+ +5696,33,126},{__gb2312_decmap+5790,33,126},{__gb2312_decmap+5884,33,126},{ +__gb2312_decmap+5978,33,126},{__gb2312_decmap+6072,33,126},{__gb2312_decmap+ +6166,33,126},{__gb2312_decmap+6260,33,126},{__gb2312_decmap+6354,33,126},{ +__gb2312_decmap+6448,33,126},{__gb2312_decmap+6542,33,126},{__gb2312_decmap+ +6636,33,126},{__gb2312_decmap+6730,33,126},{__gb2312_decmap+6824,33,126},{ +__gb2312_decmap+6918,33,126},{__gb2312_decmap+7012,33,126},{__gb2312_decmap+ +7106,33,126},{__gb2312_decmap+7200,33,126},{__gb2312_decmap+7294,33,126},{ +__gb2312_decmap+7388,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __gbkext_decmap[14531] = { +19970,19972,19973,19974,19983,19986,19991,19999,20000,20001,20003,20006,20009, +20014,20015,20017,20019,20021,20023,20028,20032,20033,20034,20036,20038,20042, +20049,20053,20055,20058,20059,20066,20067,20068,20069,20071,20072,20074,20075, +20076,20077,20078,20079,20082,20084,20085,20086,20087,20088,20089,20090,20091, +20092,20093,20095,20096,20097,20098,20099,20100,20101,20103,20106,U,20112, +20118,20119,20121,20124,20125,20126,20131,20138,20143,20144,20145,20148,20150, +20151,20152,20153,20156,20157,20158,20168,20172,20175,20176,20178,20186,20187, +20188,20192,20194,20198,20199,20201,20205,20206,20207,20209,20212,20216,20217, +20218,20220,20222,20224,20226,20227,20228,20229,20230,20231,20232,20235,20236, +20242,20243,20244,20245,20246,20252,20253,20257,20259,20264,20265,20268,20269, +20270,20273,20275,20277,20279,20281,20283,20286,20287,20288,20289,20290,20292, +20293,20295,20296,20297,20298,20299,20300,20306,20308,20310,20321,20322,20326, +20328,20330,20331,20333,20334,20337,20338,20341,20343,20344,20345,20346,20349, +20352,20353,20354,20357,20358,20359,20362,20364,20366,20368,20370,20371,20373, +20374,20376,20377,20378,20380,20382,20383,20385,20386,20388,20395,20397,20400, +20401,20402,20403,20404,20406,20407,20408,20409,20410,20411,20412,20413,20414, +20416,20417,20418,20422,20423,20424,20425,20427,20428,20429,20434,20435,20436, +20437,20438,20441,20443,20448,20450,20452,20453,20455,20459,20460,20464,20466, +20468,20469,20470,20471,20473,20475,20476,20477,20479,20480,20481,20482,20483, +20484,20485,20486,20487,20488,20489,20490,U,20491,20494,20496,20497,20499, +20501,20502,20503,20507,20509,20510,20512,20514,20515,20516,20519,20523,20527, +20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20539,20541,20543, +20544,20545,20546,20548,20549,20550,20553,20554,20555,20557,20560,20561,20562, +20563,20564,20566,20567,20568,20569,20571,20573,20574,20575,20576,20577,20578, +20579,20580,20582,20583,20584,20585,20586,20587,20589,20590,20591,20592,20593, +20594,20595,20596,20597,20600,20601,20602,20604,20605,20609,20610,20611,20612, +20614,20615,20617,20618,20619,20620,20622,20623,20624,20625,20626,20627,20628, +20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641, +20642,20644,20646,20650,20651,20653,20654,20655,20656,20657,20659,20660,20661, +20662,20663,20664,20665,20668,20669,20670,20671,20672,20673,20674,20675,20676, +20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,20688,20689,20690, +20691,20692,20693,20695,20696,20697,20699,20700,20701,20702,20703,20704,20705, +20706,20707,20708,20709,20712,20713,20714,20715,20719,20720,20721,20722,20724, +20726,20727,20728,20729,20730,20732,20733,20734,20735,20736,20737,20738,20739, +20740,20741,20744,U,20745,20746,20748,20749,20750,20751,20752,20753,20755, +20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,20768, +20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782, +20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,20795, +20796,20797,20798,20802,20807,20810,20812,20814,20815,20816,20818,20819,20823, +20824,20825,20827,20829,20830,20831,20832,20833,20835,20836,20838,20839,20841, +20842,20847,20850,20858,20862,20863,20867,20868,20870,20871,20874,20875,20878, +20879,20880,20881,20883,20884,20888,20890,20893,20894,20895,20897,20899,20902, +20903,20904,20905,20906,20909,20910,20916,20920,20921,20922,20926,20927,20929, +20930,20931,20933,20936,20938,20941,20942,20944,20946,20947,20948,20949,20950, +20951,20952,20953,20954,20956,20958,20959,20962,20963,20965,20966,20967,20968, +20969,20970,20972,20974,20977,20978,20980,20983,20990,20996,20997,21001,21003, +21004,21007,21008,21011,21012,21013,21020,21022,21023,21025,21026,21027,21029, +21030,21031,21034,21036,21039,21041,21042,21044,21045,21052,21054,21060,21061, +21062,21063,21064,21065,21067,21070,21071,21074,21075,21077,21079,21080,U, +21081,21082,21083,21085,21087,21088,21090,21091,21092,21094,21096,21099,21100, +21101,21102,21104,21105,21107,21108,21109,21110,21111,21112,21113,21114,21115, +21116,21118,21120,21123,21124,21125,21126,21127,21129,21130,21131,21132,21133, +21134,21135,21137,21138,21140,21141,21142,21143,21144,21145,21146,21148,21156, +21157,21158,21159,21166,21167,21168,21172,21173,21174,21175,21176,21177,21178, +21179,21180,21181,21184,21185,21186,21188,21189,21190,21192,21194,21196,21197, +21198,21199,21201,21203,21204,21205,21207,21209,21210,21211,21212,21213,21214, +21216,21217,21218,21219,21221,21222,21223,21224,21225,21226,21227,21228,21229, +21230,21231,21233,21234,21235,21236,21237,21238,21239,21240,21243,21244,21245, +21249,21250,21251,21252,21255,21257,21258,21259,21260,21262,21265,21266,21267, +21268,21272,21275,21276,21278,21279,21282,21284,21285,21287,21288,21289,21291, +21292,21293,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21308, +21309,21312,21314,21316,21318,21323,21324,21325,21328,21332,21336,21337,21339, +21341,21349,21352,21354,21356,21357,21362,21366,21369,21371,21372,21373,21374, +21376,21377,21379,21383,21384,21386,21390,21391,U,21392,21393,21394,21395, +21396,21398,21399,21401,21403,21404,21406,21408,21409,21412,21415,21418,21419, +21420,21421,21423,21424,21425,21426,21427,21428,21429,21431,21432,21433,21434, +21436,21437,21438,21440,21443,21444,21445,21446,21447,21454,21455,21456,21458, +21459,21461,21466,21468,21469,21470,21473,21474,21479,21492,21498,21502,21503, +21504,21506,21509,21511,21515,21524,21528,21529,21530,21532,21538,21540,21541, +21546,21552,21555,21558,21559,21562,21565,21567,21569,21570,21572,21573,21575, +21577,21580,21581,21582,21583,21585,21594,21597,21598,21599,21600,21601,21603, +21605,21607,21609,21610,21611,21612,21613,21614,21615,21616,21620,21625,21626, +21630,21631,21633,21635,21637,21639,21640,21641,21642,21645,21649,21651,21655, +21656,21660,21662,21663,21664,21665,21666,21669,21678,21680,21682,21685,21686, +21687,21689,21690,21692,21694,21699,21701,21706,21707,21718,21720,21723,21728, +21729,21730,21731,21732,21739,21740,21743,21744,21745,21748,21749,21750,21751, +21752,21753,21755,21758,21760,21762,21763,21764,21765,21768,21770,21771,21772, +21773,21774,21778,21779,21781,21782,21783,21784,21785,21786,21788,21789,21790, +21791,21793,21797,21798,U,21800,21801,21803,21805,21810,21812,21813,21814, +21816,21817,21818,21819,21821,21824,21826,21829,21831,21832,21835,21836,21837, +21838,21839,21841,21842,21843,21844,21847,21848,21849,21850,21851,21853,21854, +21855,21856,21858,21859,21864,21865,21867,21871,21872,21873,21874,21875,21876, +21881,21882,21885,21887,21893,21894,21900,21901,21902,21904,21906,21907,21909, +21910,21911,21914,21915,21918,21920,21921,21922,21923,21924,21925,21926,21928, +21929,21930,21931,21932,21933,21934,21935,21936,21938,21940,21942,21944,21946, +21948,21951,21952,21953,21954,21955,21958,21959,21960,21962,21963,21966,21967, +21968,21973,21975,21976,21977,21978,21979,21982,21984,21986,21991,21993,21997, +21998,22000,22001,22004,22006,22008,22009,22010,22011,22012,22015,22018,22019, +22020,22021,22022,22023,22026,22027,22029,22032,22033,22034,22035,22036,22037, +22038,22039,22041,22042,22044,22045,22048,22049,22050,22053,22054,22056,22057, +22058,22059,22062,22063,22064,22067,22069,22071,22072,22074,22076,22077,22078, +22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22095, +22096,22097,22098,22099,22101,22102,22106,22107,22109,22110,22111,22112,22113, +U,22115,22117,22118,22119,22125,22126,22127,22128,22130,22131,22132,22133, +22135,22136,22137,22138,22141,22142,22143,22144,22145,22146,22147,22148,22151, +22152,22153,22154,22155,22156,22157,22160,22161,22162,22164,22165,22166,22167, +22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,22178,22180,22181, +22182,22183,22184,22185,22186,22187,22188,22189,22190,22192,22193,22194,22195, +22196,22197,22198,22200,22201,22202,22203,22205,22206,22207,22208,22209,22210, +22211,22212,22213,22214,22215,22216,22217,22219,22220,22221,22222,22223,22224, +22225,22226,22227,22229,22230,22232,22233,22236,22243,22245,22246,22247,22248, +22249,22250,22252,22254,22255,22258,22259,22262,22263,22264,22267,22268,22272, +22273,22274,22277,22279,22283,22284,22285,22286,22287,22288,22289,22290,22291, +22292,22293,22294,22295,22296,22297,22298,22299,22301,22302,22304,22305,22306, +22308,22309,22310,22311,22315,22321,22322,22324,22325,22326,22327,22328,22332, +22333,22335,22337,22339,22340,22341,22342,22344,22345,22347,22354,22355,22356, +22357,22358,22360,22361,22370,22371,22373,22375,22380,22382,22384,22385,22386, +22388,22389,22392,22393,22394,22397,22398,22399,22400,U,22401,22407,22408, +22409,22410,22413,22414,22415,22416,22417,22420,22421,22422,22423,22424,22425, +22426,22428,22429,22430,22431,22437,22440,22442,22444,22447,22448,22449,22451, +22453,22454,22455,22457,22458,22459,22460,22461,22462,22463,22464,22465,22468, +22469,22470,22471,22472,22473,22474,22476,22477,22480,22481,22483,22486,22487, +22491,22492,22494,22497,22498,22499,22501,22502,22503,22504,22505,22506,22507, +22508,22510,22512,22513,22514,22515,22517,22518,22519,22523,22524,22526,22527, +22529,22531,22532,22533,22536,22537,22538,22540,22542,22543,22544,22546,22547, +22548,22550,22551,22552,22554,22555,22556,22557,22559,22562,22563,22565,22566, +22567,22568,22569,22571,22572,22573,22574,22575,22577,22578,22579,22580,22582, +22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,22595, +22597,22598,22599,22600,22601,22602,22603,22606,22607,22608,22610,22611,22613, +22614,22615,22617,22618,22619,22620,22621,22623,22624,22625,22626,22627,22628, +22630,22631,22632,22633,22634,22637,22638,22639,22640,22641,22642,22643,22644, +22645,22646,22647,22648,22649,22650,22651,22652,22653,22655,22658,22660,22662, +22663,22664,22666,22667,22668,U,22669,22670,22671,22672,22673,22676,22677, +22678,22679,22680,22683,22684,22685,22688,22689,22690,22691,22692,22693,22694, +22695,22698,22699,22700,22701,22702,22703,22704,22705,22706,22707,22708,22709, +22710,22711,22712,22713,22714,22715,22717,22718,22719,22720,22722,22723,22724, +22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22738,22739, +22740,22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753, +22754,22755,22757,22758,22759,22760,22761,22762,22765,22767,22769,22770,22772, +22773,22775,22776,22778,22779,22780,22781,22782,22783,22784,22785,22787,22789, +22790,22792,22793,22794,22795,22796,22798,22800,22801,22802,22803,22807,22808, +22811,22813,22814,22816,22817,22818,22819,22822,22824,22828,22832,22834,22835, +22837,22838,22843,22845,22846,22847,22848,22851,22853,22854,22858,22860,22861, +22864,22866,22867,22873,22875,22876,22877,22878,22879,22881,22883,22884,22886, +22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,22898,22901, +22903,22906,22907,22908,22910,22911,22912,22917,22921,22923,22924,22926,22927, +22928,22929,22932,22933,22936,22938,22939,22940,22941,22943,22944,22945,22946, +22950,U,22951,22956,22957,22960,22961,22963,22964,22965,22966,22967,22968, +22970,22972,22973,22975,22976,22977,22978,22979,22980,22981,22983,22984,22985, +22988,22989,22990,22991,22997,22998,23001,23003,23006,23007,23008,23009,23010, +23012,23014,23015,23017,23018,23019,23021,23022,23023,23024,23025,23026,23027, +23028,23029,23030,23031,23032,23034,23036,23037,23038,23040,23042,23050,23051, +23053,23054,23055,23056,23058,23060,23061,23062,23063,23065,23066,23067,23069, +23070,23073,23074,23076,23078,23079,23080,23082,23083,23084,23085,23086,23087, +23088,23091,23093,23095,23096,23097,23098,23099,23101,23102,23103,23105,23106, +23107,23108,23109,23111,23112,23115,23116,23117,23118,23119,23120,23121,23122, +23123,23124,23126,23127,23128,23129,23131,23132,23133,23134,23135,23136,23137, +23139,23140,23141,23142,23144,23145,23147,23148,23149,23150,23151,23152,23153, +23154,23155,23160,23161,23163,23164,23165,23166,23168,23169,23170,23171,23172, +23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185, +23187,23188,23189,23190,23191,23192,23193,23196,23197,23198,23199,23200,23201, +23202,23203,23204,23205,23206,23207,23208,23209,23211,23212,U,23213,23214, +23215,23216,23217,23220,23222,23223,23225,23226,23227,23228,23229,23231,23232, +23235,23236,23237,23238,23239,23240,23242,23243,23245,23246,23247,23248,23249, +23251,23253,23255,23257,23258,23259,23261,23262,23263,23266,23268,23269,23271, +23272,23274,23276,23277,23278,23279,23280,23282,23283,23284,23285,23286,23287, +23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,23300, +23301,23302,23303,23304,23306,23307,23308,23309,23310,23311,23312,23313,23314, +23315,23316,23317,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329, +23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,23342, +23343,23344,23345,23347,23349,23350,23352,23353,23354,23355,23356,23357,23358, +23359,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,23372, +23373,23374,23375,23378,23382,23390,23392,23393,23399,23400,23403,23405,23406, +23407,23410,23412,23414,23415,23416,23417,23419,23420,23422,23423,23426,23430, +23434,23437,23438,23440,23441,23442,23444,23446,23455,23463,23464,23465,23468, +23469,23470,23471,23473,23474,23479,23482,23483,23484,23488,23489,23491,23496, +23497,23498,23499,23501,23502,23503,U,23505,23508,23509,23510,23511,23512, +23513,23514,23515,23516,23520,23522,23523,23526,23527,23529,23530,23531,23532, +23533,23535,23537,23538,23539,23540,23541,23542,23543,23549,23550,23552,23554, +23555,23557,23559,23560,23563,23564,23565,23566,23568,23570,23571,23575,23577, +23579,23582,23583,23584,23585,23587,23590,23592,23593,23594,23595,23597,23598, +23599,23600,23602,23603,23605,23606,23607,23619,23620,23622,23623,23628,23629, +23634,23635,23636,23638,23639,23640,23642,23643,23644,23645,23647,23650,23652, +23655,23656,23657,23658,23659,23660,23661,23664,23666,23667,23668,23669,23670, +23671,23672,23675,23676,23677,23678,23680,23683,23684,23685,23686,23687,23689, +23690,23691,23694,23695,23698,23699,23701,23709,23710,23711,23712,23713,23716, +23717,23718,23719,23720,23722,23726,23727,23728,23730,23732,23734,23737,23738, +23739,23740,23742,23744,23746,23747,23749,23750,23751,23752,23753,23754,23756, +23757,23758,23759,23760,23761,23763,23764,23765,23766,23767,23768,23770,23771, +23772,23773,23774,23775,23776,23778,23779,23783,23785,23787,23788,23790,23791, +23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23804,23805,23806, +23807,23808,U,23809,23812,23813,23816,23817,23818,23819,23820,23821,23823, +23824,23825,23826,23827,23829,23831,23832,23833,23834,23836,23837,23839,23840, +23841,23842,23843,23845,23848,23850,23851,23852,23855,23856,23857,23858,23859, +23861,23862,23863,23864,23865,23866,23867,23868,23871,23872,23873,23874,23875, +23876,23877,23878,23880,23881,23885,23886,23887,23888,23889,23890,23891,23892, +23893,23894,23895,23897,23898,23900,23902,23903,23904,23905,23906,23907,23908, +23909,23910,23911,23912,23914,23917,23918,23920,23921,23922,23923,23925,23926, +23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23939,23940, +23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953, +23954,23955,23956,23957,23958,23959,23960,23962,23963,23964,23966,23967,23968, +23969,23970,23971,23972,23973,23974,23975,23976,23977,23978,23979,23980,23981, +23982,23983,23984,23985,23986,23987,23988,23989,23990,23992,23993,23994,23995, +23996,23997,23998,23999,24000,24001,24002,24003,24004,24006,24007,24008,24009, +24010,24011,24012,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023, +24024,24025,24026,24028,24031,24032,24035,24036,24042,24044,24045,U,24048, +24053,24054,24056,24057,24058,24059,24060,24063,24064,24068,24071,24073,24074, +24075,24077,24078,24082,24083,24087,24094,24095,24096,24097,24098,24099,24100, +24101,24104,24105,24106,24107,24108,24111,24112,24114,24115,24116,24117,24118, +24121,24122,24126,24127,24128,24129,24131,24134,24135,24136,24137,24138,24139, +24141,24142,24143,24144,24145,24146,24147,24150,24151,24152,24153,24154,24156, +24157,24159,24160,24163,24164,24165,24166,24167,24168,24169,24170,24171,24172, +24173,24174,24175,24176,24177,24181,24183,24185,24190,24193,24194,24195,24197, +24200,24201,24204,24205,24206,24210,24216,24219,24221,24225,24226,24227,24228, +24232,24233,24234,24235,24236,24238,24239,24240,24241,24242,24244,24250,24251, +24252,24253,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24267, +24268,24269,24270,24271,24272,24276,24277,24279,24280,24281,24282,24284,24285, +24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,24297,24299,24300, +24301,24302,24303,24304,24305,24306,24307,24309,24312,24313,24315,24316,24317, +24325,24326,24327,24329,24332,24333,24334,24336,24338,24340,24342,24345,24346, +24348,24349,24350,24353,24354,24355,24356,U,24360,24363,24364,24366,24368, +24370,24371,24372,24373,24374,24375,24376,24379,24381,24382,24383,24385,24386, +24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,24398,24399, +24401,24404,24409,24410,24411,24412,24414,24415,24416,24419,24421,24423,24424, +24427,24430,24431,24434,24436,24437,24438,24440,24442,24445,24446,24447,24451, +24454,24461,24462,24463,24465,24467,24468,24470,24474,24475,24477,24478,24479, +24480,24482,24483,24484,24485,24486,24487,24489,24491,24492,24495,24496,24497, +24498,24499,24500,24502,24504,24505,24506,24507,24510,24511,24512,24513,24514, +24519,24520,24522,24523,24526,24531,24532,24533,24538,24539,24540,24542,24543, +24546,24547,24549,24550,24552,24553,24556,24559,24560,24562,24563,24564,24566, +24567,24569,24570,24572,24583,24584,24585,24587,24588,24592,24593,24595,24599, +24600,24602,24606,24607,24610,24611,24612,24620,24621,24622,24624,24625,24626, +24627,24628,24630,24631,24632,24633,24634,24637,24638,24640,24644,24645,24646, +24647,24648,24649,24650,24652,24654,24655,24657,24659,24660,24662,24663,24664, +24667,24668,24670,24671,24672,24673,24677,24678,24686,24689,24690,24692,24693, +24695,24702,24704,U,24705,24706,24709,24710,24711,24712,24714,24715,24718, +24719,24720,24721,24723,24725,24727,24728,24729,24732,24734,24737,24738,24740, +24741,24743,24745,24746,24750,24752,24755,24757,24758,24759,24761,24762,24765, +24766,24767,24768,24769,24770,24771,24772,24775,24776,24777,24780,24781,24782, +24783,24784,24786,24787,24788,24790,24791,24793,24795,24798,24801,24802,24803, +24804,24805,24810,24817,24818,24821,24823,24824,24827,24828,24829,24830,24831, +24834,24835,24836,24837,24839,24842,24843,24844,24848,24849,24850,24851,24852, +24854,24855,24856,24857,24859,24860,24861,24862,24865,24866,24869,24872,24873, +24874,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,24887, +24888,24889,24890,24891,24892,24893,24894,24896,24897,24898,24899,24900,24901, +24902,24903,24905,24907,24909,24911,24912,24914,24915,24916,24918,24919,24920, +24921,24922,24923,24924,24926,24927,24928,24929,24931,24932,24933,24934,24937, +24938,24939,24940,24941,24942,24943,24945,24946,24947,24948,24950,24952,24953, +24954,24955,24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966, +24967,24968,24969,24970,24972,24973,24975,24976,24977,24978,24979,24981,U, +24982,24983,24984,24985,24986,24987,24988,24990,24991,24992,24993,24994,24995, +24996,24997,24998,25002,25003,25005,25006,25007,25008,25009,25010,25011,25012, +25013,25014,25016,25017,25018,25019,25020,25021,25023,25024,25025,25027,25028, +25029,25030,25031,25033,25036,25037,25038,25039,25040,25043,25045,25046,25047, +25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,25058,25059,25060, +25061,25063,25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074, +25075,25076,25078,25079,25080,25081,25082,25083,25084,25085,25086,25088,25089, +25090,25091,25092,25093,25095,25097,25107,25108,25113,25116,25117,25118,25120, +25123,25126,25127,25128,25129,25131,25133,25135,25136,25137,25138,25141,25142, +25144,25145,25146,25147,25148,25154,25156,25157,25158,25162,25167,25168,25173, +25174,25175,25177,25178,25180,25181,25182,25183,25184,25185,25186,25188,25189, +25192,25201,25202,25204,25205,25207,25208,25210,25211,25213,25217,25218,25219, +25221,25222,25223,25224,25227,25228,25229,25230,25231,25232,25236,25241,25244, +25245,25246,25251,25254,25255,25257,25258,25261,25262,25263,25264,25266,25267, +25268,25270,25271,25272,25274,25278,25280,25281,U,25283,25291,25295,25297, +25301,25309,25310,25312,25313,25316,25322,25323,25328,25330,25333,25336,25337, +25338,25339,25344,25347,25348,25349,25350,25354,25355,25356,25357,25359,25360, +25362,25363,25364,25365,25367,25368,25369,25372,25382,25383,25385,25388,25389, +25390,25392,25393,25395,25396,25397,25398,25399,25400,25403,25404,25406,25407, +25408,25409,25412,25415,25416,25418,25425,25426,25427,25428,25430,25431,25432, +25433,25434,25435,25436,25437,25440,25444,25445,25446,25448,25450,25451,25452, +25455,25456,25458,25459,25460,25461,25464,25465,25468,25469,25470,25471,25473, +25475,25476,25477,25478,25483,25485,25489,25491,25492,25493,25495,25497,25498, +25499,25500,25501,25502,25503,25505,25508,25510,25515,25519,25521,25522,25525, +25526,25529,25531,25533,25535,25536,25537,25538,25539,25541,25543,25544,25546, +25547,25548,25553,25555,25556,25557,25559,25560,25561,25562,25563,25564,25565, +25567,25570,25572,25573,25574,25575,25576,25579,25580,25582,25583,25584,25585, +25587,25589,25591,25593,25594,25595,25596,25598,25603,25604,25606,25607,25608, +25609,25610,25613,25614,25617,25618,25621,25622,25623,25624,25625,25626,25629, +25631,25634,25635,25636,U,25637,25639,25640,25641,25643,25646,25647,25648, +25649,25650,25651,25653,25654,25655,25656,25657,25659,25660,25662,25664,25666, +25667,25673,25675,25676,25677,25678,25679,25680,25681,25683,25685,25686,25687, +25689,25690,25691,25692,25693,25695,25696,25697,25698,25699,25700,25701,25702, +25704,25706,25707,25708,25710,25711,25712,25713,25714,25715,25716,25717,25718, +25719,25723,25724,25725,25726,25727,25728,25729,25731,25734,25736,25737,25738, +25739,25740,25741,25742,25743,25744,25747,25748,25751,25752,25754,25755,25756, +25757,25759,25760,25761,25762,25763,25765,25766,25767,25768,25770,25771,25775, +25777,25778,25779,25780,25782,25785,25787,25789,25790,25791,25793,25795,25796, +25798,25799,25800,25801,25802,25803,25804,25807,25809,25811,25812,25813,25814, +25817,25818,25819,25820,25821,25823,25824,25825,25827,25829,25831,25832,25833, +25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846, +25847,25848,25849,25850,25851,25852,25853,25854,25855,25857,25858,25859,25860, +25861,25862,25863,25864,25866,25867,25868,25869,25870,25871,25872,25873,25875, +25876,25877,25878,25879,25881,25882,25883,25884,25885,25886,25887,25888,25889, +U,25890,25891,25892,25894,25895,25896,25897,25898,25900,25901,25904,25905, +25906,25907,25911,25914,25916,25917,25920,25921,25922,25923,25924,25926,25927, +25930,25931,25933,25934,25936,25938,25939,25940,25943,25944,25946,25948,25951, +25952,25953,25956,25957,25959,25960,25961,25962,25965,25966,25967,25969,25971, +25973,25974,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986, +25987,25988,25989,25990,25992,25993,25994,25997,25998,25999,26002,26004,26005, +26006,26008,26010,26013,26014,26016,26018,26019,26022,26024,26026,26028,26030, +26033,26034,26035,26036,26037,26038,26039,26040,26042,26043,26046,26047,26048, +26050,26055,26056,26057,26058,26061,26064,26065,26067,26068,26069,26072,26073, +26074,26075,26076,26077,26078,26079,26081,26083,26084,26090,26091,26098,26099, +26100,26101,26104,26105,26107,26108,26109,26110,26111,26113,26116,26117,26119, +26120,26121,26123,26125,26128,26129,26130,26134,26135,26136,26138,26139,26140, +26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26162, +26163,26167,26168,26169,26170,26171,26173,26175,26176,26178,26180,26181,26182, +26183,26184,26185,26186,26189,26190,26192,26193,26200,U,26201,26203,26204, +26205,26206,26208,26210,26211,26213,26215,26217,26218,26219,26220,26221,26225, +26226,26227,26229,26232,26233,26235,26236,26237,26239,26240,26241,26243,26245, +26246,26248,26249,26250,26251,26253,26254,26255,26256,26258,26259,26260,26261, +26264,26265,26266,26267,26268,26270,26271,26272,26273,26274,26275,26276,26277, +26278,26281,26282,26283,26284,26285,26287,26288,26289,26290,26291,26293,26294, +26295,26296,26298,26299,26300,26301,26303,26304,26305,26306,26307,26308,26309, +26310,26311,26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322, +26323,26324,26325,26326,26327,26328,26330,26334,26335,26336,26337,26338,26339, +26340,26341,26343,26344,26346,26347,26348,26349,26350,26351,26353,26357,26358, +26360,26362,26363,26365,26369,26370,26371,26372,26373,26374,26375,26380,26382, +26383,26385,26386,26387,26390,26392,26393,26394,26396,26398,26400,26401,26402, +26403,26404,26405,26407,26409,26414,26416,26418,26419,26422,26423,26424,26425, +26427,26428,26430,26431,26433,26436,26437,26439,26442,26443,26445,26450,26452, +26453,26455,26456,26457,26458,26459,26461,26466,26467,26468,26470,26471,26475, +26476,26478,26481,26484,26486,U,26488,26489,26490,26491,26493,26496,26498, +26499,26501,26502,26504,26506,26508,26509,26510,26511,26513,26514,26515,26516, +26518,26521,26523,26527,26528,26529,26532,26534,26537,26540,26542,26545,26546, +26548,26553,26554,26555,26556,26557,26558,26559,26560,26562,26565,26566,26567, +26568,26569,26570,26571,26572,26573,26574,26581,26582,26583,26587,26591,26593, +26595,26596,26598,26599,26600,26602,26603,26605,26606,26610,26613,26614,26615, +26616,26617,26618,26619,26620,26622,26625,26626,26627,26628,26630,26637,26640, +26642,26644,26645,26648,26649,26650,26651,26652,26654,26655,26656,26658,26659, +26660,26661,26662,26663,26664,26667,26668,26669,26670,26671,26672,26673,26676, +26677,26678,26682,26683,26687,26695,26699,26701,26703,26706,26710,26711,26712, +26713,26714,26715,26716,26717,26718,26719,26730,26732,26733,26734,26735,26736, +26737,26738,26739,26741,26744,26745,26746,26747,26748,26749,26750,26751,26752, +26754,26756,26759,26760,26761,26762,26763,26764,26765,26766,26768,26769,26770, +26772,26773,26774,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785, +26787,26788,26789,26793,26794,26795,26796,26798,26801,26802,26804,26806,26807, +26808,U,26809,26810,26811,26812,26813,26814,26815,26817,26819,26820,26821, +26822,26823,26824,26826,26828,26830,26831,26832,26833,26835,26836,26838,26839, +26841,26843,26844,26845,26846,26847,26849,26850,26852,26853,26854,26855,26856, +26857,26858,26859,26860,26861,26863,26866,26867,26868,26870,26871,26872,26875, +26877,26878,26879,26880,26882,26883,26884,26886,26887,26888,26889,26890,26892, +26895,26897,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909, +26910,26913,26914,26915,26917,26918,26919,26920,26921,26922,26923,26924,26926, +26927,26929,26930,26931,26933,26934,26935,26936,26938,26939,26940,26942,26944, +26945,26947,26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958, +26959,26960,26961,26962,26963,26965,26966,26968,26969,26971,26972,26975,26977, +26978,26980,26981,26983,26984,26985,26986,26988,26989,26991,26992,26994,26995, +26996,26997,26998,27002,27003,27005,27006,27007,27009,27011,27013,27018,27019, +27020,27022,27023,27024,27025,27026,27027,27030,27031,27033,27034,27037,27038, +27039,27040,27041,27042,27043,27044,27045,27046,27049,27050,27052,27054,27055, +27056,27058,27059,27061,27062,27064,27065,27066,27068,27069,U,27070,27071, +27072,27074,27075,27076,27077,27078,27079,27080,27081,27083,27085,27087,27089, +27090,27091,27093,27094,27095,27096,27097,27098,27100,27101,27102,27105,27106, +27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27118,27119,27120, +27121,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27134,27136, +27137,27138,27139,27140,27141,27142,27143,27144,27145,27147,27148,27149,27150, +27151,27152,27153,27154,27155,27156,27157,27158,27161,27162,27163,27164,27165, +27166,27168,27170,27171,27172,27173,27174,27175,27177,27179,27180,27181,27182, +27184,27186,27187,27188,27190,27191,27192,27193,27194,27195,27196,27199,27200, +27201,27202,27203,27205,27206,27208,27209,27210,27211,27212,27213,27214,27215, +27217,27218,27219,27220,27221,27222,27223,27226,27228,27229,27230,27231,27232, +27234,27235,27236,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247, +27248,27250,27251,27252,27253,27254,27255,27256,27258,27259,27261,27262,27263, +27265,27266,27267,27269,27270,27271,27272,27273,27274,27275,27276,27277,27279, +27282,27283,27284,27285,27286,27288,27289,27290,27291,27292,27293,27294,27295, +27297,27298,27299,27300,27301,27302,U,27303,27304,27306,27309,27310,27311, +27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324, +27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337, +27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,27350, +27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363, +27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,27374,27375,27376, +27377,27378,27379,27380,27381,27382,27383,27384,27385,27386,27387,27388,27389, +27390,27391,27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402, +27403,27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415, +27416,27417,27418,27419,27420,27421,27422,27423,27429,27430,27432,27433,27434, +27435,27436,27437,27438,27439,27440,27441,27443,27444,27445,27446,27448,27451, +27452,27453,27455,27456,27457,27458,27460,27461,27464,27466,27467,27469,27470, +27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27482,27483,27484, +27485,27486,27487,27488,27489,27496,27497,27499,27500,27501,27502,27503,27504, +27505,27506,27507,27508,27509,27510,27511,27512,27514,27517,27518,27519,27520, +27525,27528,U,27532,27534,27535,27536,27537,27540,27541,27543,27544,27545, +27548,27549,27550,27551,27552,27554,27555,27556,27557,27558,27559,27560,27561, +27563,27564,27565,27566,27567,27568,27569,27570,27574,27576,27577,27578,27579, +27580,27581,27582,27584,27587,27588,27590,27591,27592,27593,27594,27596,27598, +27600,27601,27608,27610,27612,27613,27614,27615,27616,27618,27619,27620,27621, +27622,27623,27624,27625,27628,27629,27630,27632,27633,27634,27636,27638,27639, +27640,27642,27643,27644,27646,27647,27648,27649,27650,27651,27652,27656,27657, +27658,27659,27660,27662,27666,27671,27676,27677,27678,27680,27683,27685,27691, +27692,27693,27697,27699,27702,27703,27705,27706,27707,27708,27710,27711,27715, +27716,27717,27720,27723,27724,27725,27726,27727,27729,27730,27731,27734,27736, +27737,27738,27746,27747,27749,27750,27751,27755,27756,27757,27758,27759,27761, +27763,27765,27767,27768,27770,27771,27772,27775,27776,27780,27783,27786,27787, +27789,27790,27793,27794,27797,27798,27799,27800,27802,27804,27805,27806,27808, +27810,27816,27820,27823,27824,27828,27829,27830,27831,27834,27840,27841,27842, +27843,27846,27847,27848,27851,27853,27854,27855,27857,27858,27864,U,27865, +27866,27868,27869,27871,27876,27878,27879,27881,27884,27885,27890,27892,27897, +27903,27904,27906,27907,27909,27910,27912,27913,27914,27917,27919,27920,27921, +27923,27924,27925,27926,27928,27932,27933,27935,27936,27937,27938,27939,27940, +27942,27944,27945,27948,27949,27951,27952,27956,27958,27959,27960,27962,27967, +27968,27970,27972,27977,27980,27984,27989,27990,27991,27992,27995,27997,27999, +28001,28002,28004,28005,28007,28008,28011,28012,28013,28016,28017,28018,28019, +28021,28022,28025,28026,28027,28029,28030,28031,28032,28033,28035,28036,28038, +28039,28042,28043,28045,28047,28048,28050,28054,28055,28056,28057,28058,28060, +28066,28069,28076,28077,28080,28081,28083,28084,28086,28087,28089,28090,28091, +28092,28093,28094,28097,28098,28099,28104,28105,28106,28109,28110,28111,28112, +28114,28115,28116,28117,28119,28122,28123,28124,28127,28130,28131,28133,28135, +28136,28137,28138,28141,28143,28144,28146,28148,28149,28150,28152,28154,28157, +28158,28159,28160,28161,28162,28163,28164,28166,28167,28168,28169,28171,28175, +28178,28179,28181,28184,28185,28187,28188,28190,28191,28194,28198,28199,28200, +28202,28204,28206,28208,28209,28211,28213,U,28214,28215,28217,28219,28220, +28221,28222,28223,28224,28225,28226,28229,28230,28231,28232,28233,28234,28235, +28236,28239,28240,28241,28242,28245,28247,28249,28250,28252,28253,28254,28256, +28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28268,28269,28271, +28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284, +28285,28288,28289,28290,28292,28295,28296,28298,28299,28300,28301,28302,28305, +28306,28307,28308,28309,28310,28311,28313,28314,28315,28317,28318,28320,28321, +28323,28324,28326,28328,28329,28331,28332,28333,28334,28336,28339,28341,28344, +28345,28348,28350,28351,28352,28355,28356,28357,28358,28360,28361,28362,28364, +28365,28366,28368,28370,28374,28376,28377,28379,28380,28381,28387,28391,28394, +28395,28396,28397,28398,28399,28400,28401,28402,28403,28405,28406,28407,28408, +28410,28411,28412,28413,28414,28415,28416,28417,28419,28420,28421,28423,28424, +28426,28427,28428,28429,28430,28432,28433,28434,28438,28439,28440,28441,28442, +28443,28444,28445,28446,28447,28449,28450,28451,28453,28454,28455,28456,28460, +28462,28464,28466,28468,28469,28471,28472,28473,28474,28475,28476,28477,28479, +28480,28481,28482,U,28483,28484,28485,28488,28489,28490,28492,28494,28495, +28496,28497,28498,28499,28500,28501,28502,28503,28505,28506,28507,28509,28511, +28512,28513,28515,28516,28517,28519,28520,28521,28522,28523,28524,28527,28528, +28529,28531,28533,28534,28535,28537,28539,28541,28542,28543,28544,28545,28546, +28547,28549,28550,28551,28554,28555,28559,28560,28561,28562,28563,28564,28565, +28566,28567,28568,28569,28570,28571,28573,28574,28575,28576,28578,28579,28580, +28581,28582,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594, +28596,28597,28599,28600,28602,28603,28604,28605,28606,28607,28609,28611,28612, +28613,28614,28615,28616,28618,28619,28620,28621,28622,28623,28624,28627,28628, +28629,28630,28631,28632,28633,28634,28635,28636,28637,28639,28642,28643,28644, +28645,28646,28647,28648,28649,28650,28651,28652,28653,28656,28657,28658,28659, +28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,28670,28671,28672, +28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685, +28686,28687,28688,28690,28691,28692,28693,28694,28695,28696,28697,28700,28701, +28702,28703,28704,28705,28706,28708,28709,28710,28711,28712,28713,28714,U, +28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28726,28727,28728, +28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742, +28743,28744,28745,28746,28747,28749,28750,28752,28753,28754,28755,28756,28757, +28758,28759,28760,28761,28762,28763,28764,28765,28767,28768,28769,28770,28771, +28772,28773,28774,28775,28776,28777,28778,28782,28785,28786,28787,28788,28791, +28793,28794,28795,28797,28801,28802,28803,28804,28806,28807,28808,28811,28812, +28813,28815,28816,28817,28819,28823,28824,28826,28827,28830,28831,28832,28833, +28834,28835,28836,28837,28838,28839,28840,28841,28842,28848,28850,28852,28853, +28854,28858,28862,28863,28868,28869,28870,28871,28873,28875,28876,28877,28878, +28879,28880,28881,28882,28883,28884,28885,28886,28887,28890,28892,28893,28894, +28896,28897,28898,28899,28901,28906,28910,28912,28913,28914,28915,28916,28917, +28918,28920,28922,28923,28924,28926,28927,28928,28929,28930,28931,28932,28933, +28934,28935,28936,28939,28940,28941,28942,28943,28945,28946,28948,28951,28955, +28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28967,28968,28969, +28970,28971,28972,28973,28974,28978,28979,28980,U,28981,28983,28984,28985, +28986,28987,28988,28989,28990,28991,28992,28993,28994,28995,28996,28998,28999, +29000,29001,29003,29005,29007,29008,29009,29010,29011,29012,29013,29014,29015, +29016,29017,29018,29019,29021,29023,29024,29025,29026,29027,29029,29033,29034, +29035,29036,29037,29039,29040,29041,29044,29045,29046,29047,29049,29051,29052, +29054,29055,29056,29057,29058,29059,29061,29062,29063,29064,29065,29067,29068, +29069,29070,29072,29073,29074,29075,29077,29078,29079,29082,29083,29084,29085, +29086,29089,29090,29091,29092,29093,29094,29095,29097,29098,29099,29101,29102, +29103,29104,29105,29106,29108,29110,29111,29112,29114,29115,29116,29117,29118, +29119,29120,29121,29122,29124,29125,29126,29127,29128,29129,29130,29131,29132, +29133,29135,29136,29137,29138,29139,29142,29143,29144,29145,29146,29147,29148, +29149,29150,29151,29153,29154,29155,29156,29158,29160,29161,29162,29163,29164, +29165,29167,29168,29169,29170,29171,29172,29173,29174,29175,29176,29178,29179, +29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29191,29192,29193, +29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206, +29207,29208,29209,29210,U,29211,29212,29214,29215,29216,29217,29218,29219, +29220,29221,29222,29223,29225,29227,29229,29230,29231,29234,29235,29236,29242, +29244,29246,29248,29249,29250,29251,29252,29253,29254,29257,29258,29259,29262, +29263,29264,29265,29267,29268,29269,29271,29272,29274,29276,29278,29280,29283, +29284,29285,29288,29290,29291,29292,29293,29296,29297,29299,29300,29302,29303, +29304,29307,29308,29309,29314,29315,29317,29318,29319,29320,29321,29324,29326, +29328,29329,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341, +29342,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,29354,29355, +29358,29361,29362,29363,29365,29370,29371,29372,29373,29374,29375,29376,29381, +29382,29383,29385,29386,29387,29388,29391,29393,29395,29396,29397,29398,29400, +29402,29403,183,U,U,U,U,U,8212,8560,8561,8562,8563,8564,8565,8566,8567,8568, +8569,65077,65078,65081,65082,65087,65088,65085,65086,65089,65090,65091,65092, +U,U,65083,65084,65079,65080,65073,U,65075,65076,714,715,729,8211,8213,8229, +8245,8453,8457,8598,8599,8600,8601,8725,8735,8739,8786,8806,8807,8895,9552, +9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567, +9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582, +9583,9584,9585,9586,9587,9601,9602,9603,9604,9605,9606,9607,U,9608,9609,9610, +9611,9612,9613,9614,9615,9619,9620,9621,9660,9661,9698,9699,9700,9701,9737, +8853,12306,12317,12318,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,593,U,324,328,U,609,12321,12322,12323,12324,12325,12326, +12327,12328,12329,12963,13198,13199,13212,13213,13214,13217,13252,13262,13265, +13266,13269,65072,65506,65508,U,8481,12849,U,8208,U,U,U,12540,12443,12444, +12541,12542,12294,12445,12446,65097,65098,65099,65100,65101,65102,65103,65104, +65105,65106,65108,65109,65110,65111,65113,65114,65115,65116,65117,65118,65119, +65120,65121,U,65122,65123,65124,65125,65126,65128,65129,65130,65131,U,U,U,U,U, +U,U,U,U,U,U,U,U,12295,29404,29405,29407,29410,29411,29412,29413,29414,29415, +29418,29419,29429,29430,29433,29437,29438,29439,29440,29442,29444,29445,29446, +29447,29448,29449,29451,29452,29453,29455,29456,29457,29458,29460,29464,29465, +29466,29471,29472,29475,29476,29478,29479,29480,29485,29487,29488,29490,29491, +29493,29494,29498,29499,29500,29501,29504,29505,29506,29507,29508,29509,29510, +29511,29512,U,29513,29514,29515,29516,29518,29519,29521,29523,29524,29525, +29526,29528,29529,29530,29531,29532,29533,29534,29535,29537,29538,29539,29540, +29541,29542,29543,29544,29545,29546,29547,29550,29552,29553,29554,29555,29556, +29557,29558,29559,29560,29561,29562,29563,29564,29565,29567,29568,29569,29570, +29571,29573,29574,29576,29578,29580,29581,29583,29584,29586,29587,29588,29589, +29591,29592,29593,29594,29596,29597,29598,29600,29601,29603,29604,29605,29606, +29607,29608,29610,29612,29613,29617,29620,29621,29622,29624,29625,29628,29629, +29630,29631,29633,29635,29636,29637,29638,29639,U,29643,29644,29646,29650, +29651,29652,29653,29654,29655,29656,29658,29659,29660,29661,29663,29665,29666, +29667,29668,29670,29672,29674,29675,29676,29678,29679,29680,29681,29683,29684, +29685,29686,29687,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697, +29698,29700,29703,29704,29707,29708,29709,29710,29713,29714,29715,29716,29717, +29718,29719,29720,29721,29724,29725,29726,29727,29728,29729,29731,29732,29735, +29737,29739,29741,29743,29745,29746,29751,29752,29753,29754,29755,29757,29758, +29759,29760,29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772, +29773,U,29774,29775,29776,29777,29778,29779,29780,29782,29784,29789,29792, +29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29806, +29807,29809,29810,29811,29812,29813,29816,29817,29818,29819,29820,29821,29823, +29826,29828,29829,29830,29832,29833,29834,29836,29837,29839,29841,29842,29843, +29844,29845,29846,29847,29848,29849,29850,29851,29853,29855,29856,29857,29858, +29859,29860,29861,29862,29866,29867,29868,29869,29870,29871,29872,29873,29874, +29875,29876,29877,29878,29879,29880,29881,29883,29884,29885,29886,29887,29888, +29889,29890,29891,29892,29893,29894,29895,U,29896,29897,29898,29899,29900, +29901,29902,29903,29904,29905,29907,29908,29909,29910,29911,29912,29913,29914, +29915,29917,29919,29921,29925,29927,29928,29929,29930,29931,29932,29933,29936, +29937,29938,29939,29941,29944,29945,29946,29947,29948,29949,29950,29952,29953, +29954,29955,29957,29958,29959,29960,29961,29962,29963,29964,29966,29968,29970, +29972,29973,29974,29975,29979,29981,29982,29984,29985,29986,29987,29988,29990, +29991,29994,29998,30004,30006,30009,30012,30013,30015,30017,30018,30019,30020, +30022,30023,30025,30026,30029,30032,30033,30034,30035,30037,30038,30039,30040, +U,30045,30046,30047,30048,30049,30050,30051,30052,30055,30056,30057,30059, +30060,30061,30062,30063,30064,30065,30067,30069,30070,30071,30074,30075,30076, +30077,30078,30080,30081,30082,30084,30085,30087,30088,30089,30090,30092,30093, +30094,30096,30099,30101,30104,30107,30108,30110,30114,30118,30119,30120,30121, +30122,30125,30134,30135,30138,30139,30143,30144,30145,30150,30155,30156,30158, +30159,30160,30161,30163,30167,30169,30170,30172,30173,30175,30176,30177,30181, +30185,30188,30189,30190,30191,30194,30195,30197,30198,30199,30200,30202,30203, +30205,30206,30210,30212,30214,30215,U,30216,30217,30219,30221,30222,30223, +30225,30226,30227,30228,30230,30234,30236,30237,30238,30241,30243,30247,30248, +30252,30254,30255,30257,30258,30262,30263,30265,30266,30267,30269,30273,30274, +30276,30277,30278,30279,30280,30281,30282,30283,30286,30287,30288,30289,30290, +30291,30293,30295,30296,30297,30298,30299,30301,30303,30304,30305,30306,30308, +30309,30310,30311,30312,30313,30314,30316,30317,30318,30320,30321,30322,30323, +30324,30325,30326,30327,30329,30330,30332,30335,30336,30337,30339,30341,30345, +30346,30348,30349,30351,30352,30354,30356,30357,30359,30360,30362,30363,U, +30364,30365,30366,30367,30368,30369,30370,30371,30373,30374,30375,30376,30377, +30378,30379,30380,30381,30383,30384,30387,30389,30390,30391,30392,30393,30394, +30395,30396,30397,30398,30400,30401,30403,30404,30407,30409,30411,30412,30419, +30421,30425,30426,30428,30429,30430,30432,30433,30434,30435,30436,30438,30439, +30440,30441,30442,30443,30444,30445,30448,30451,30453,30454,30455,30458,30459, +30461,30463,30464,30466,30467,30469,30470,30474,30476,30478,30479,30480,30481, +30482,30483,30484,30485,30486,30487,30488,30491,30492,30493,30494,30497,30499, +30500,30501,30503,30506,30507,U,30508,30510,30512,30513,30514,30515,30516, +30521,30523,30525,30526,30527,30530,30532,30533,30534,30536,30537,30538,30539, +30540,30541,30542,30543,30546,30547,30548,30549,30550,30551,30552,30553,30556, +30557,30558,30559,30560,30564,30567,30569,30570,30573,30574,30575,30576,30577, +30578,30579,30580,30581,30582,30583,30584,30586,30587,30588,30593,30594,30595, +30598,30599,30600,30601,30602,30603,30607,30608,30611,30612,30613,30614,30615, +30616,30617,30618,30619,30620,30621,30622,30625,30627,30628,30630,30632,30635, +30637,30638,30639,30641,30642,30644,30646,30647,30648,30649,30650,U,30652, +30654,30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667, +30668,30670,30671,30672,30673,30674,30675,30676,30677,30678,30680,30681,30682, +30685,30686,30687,30688,30689,30692,30694,30696,30698,30703,30704,30705,30706, +30708,30709,30711,30713,30714,30715,30716,30723,30724,30725,30726,30727,30728, +30730,30731,30734,30735,30736,30739,30741,30745,30747,30750,30752,30753,30754, +30756,30760,30762,30763,30766,30767,30769,30770,30771,30773,30774,30781,30783, +30785,30786,30787,30788,30790,30792,30793,30794,30795,30797,30799,30801,30803, +30804,30808,30809,30810,U,30811,30812,30814,30815,30816,30817,30818,30819, +30820,30821,30822,30823,30824,30825,30831,30832,30833,30834,30835,30836,30837, +30838,30840,30841,30842,30843,30845,30846,30847,30848,30849,30850,30851,30852, +30853,30854,30856,30858,30859,30863,30864,30866,30868,30869,30870,30873,30877, +30878,30880,30882,30884,30886,30888,30889,30890,30891,30892,30893,30894,30895, +30901,30902,30903,30904,30906,30907,30908,30909,30911,30912,30914,30915,30916, +30918,30919,30920,30924,30925,30926,30927,30929,30930,30931,30934,30935,30936, +30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,U,30948,30949, +30950,30951,30953,30954,30955,30957,30958,30959,30960,30961,30963,30965,30966, +30968,30969,30971,30972,30973,30974,30975,30976,30978,30979,30980,30982,30983, +30984,30985,30986,30987,30988,30989,30990,30991,30992,30993,30994,30996,30997, +30998,30999,31000,31001,31002,31003,31004,31005,31007,31008,31009,31010,31011, +31013,31014,31015,31016,31017,31018,31019,31020,31021,31022,31023,31024,31025, +31026,31027,31029,31030,31031,31032,31033,31037,31039,31042,31043,31044,31045, +31047,31050,31051,31052,31053,31054,31055,31056,31057,31058,31060,31061,31064, +31065,31073,31075,U,31076,31078,31081,31082,31083,31084,31086,31088,31089, +31090,31091,31092,31093,31094,31097,31099,31100,31101,31102,31103,31106,31107, +31110,31111,31112,31113,31115,31116,31117,31118,31120,31121,31122,31123,31124, +31125,31126,31127,31128,31129,31131,31132,31133,31134,31135,31136,31137,31138, +31139,31140,31141,31142,31144,31145,31146,31147,31148,31149,31150,31151,31152, +31153,31154,31156,31157,31158,31159,31160,31164,31167,31170,31172,31173,31175, +31176,31178,31180,31182,31183,31184,31187,31188,31190,31191,31193,31194,31195, +31196,31197,31198,31200,31201,31202,31205,31208,31210,U,31212,31214,31217, +31218,31219,31220,31221,31222,31223,31225,31226,31228,31230,31231,31233,31236, +31237,31239,31240,31241,31242,31244,31247,31248,31249,31250,31251,31253,31254, +31256,31257,31259,31260,31261,31263,31265,31266,31268,31269,31270,31271,31272, +31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,31284,31285,31286, +31288,31290,31294,31296,31297,31298,31299,31300,31301,31303,31304,31305,31306, +31307,31308,31309,31310,31311,31312,31314,31315,31316,31317,31318,31320,31321, +31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,31334, +31335,31336,U,31337,31338,31339,31340,31341,31342,31343,31345,31346,31347, +31349,31355,31356,31357,31358,31362,31365,31367,31369,31370,31371,31372,31374, +31375,31376,31379,31380,31385,31386,31387,31390,31393,31394,31395,31396,31399, +31401,31402,31403,31406,31407,31408,31409,31410,31412,31413,31414,31415,31416, +31417,31418,31419,31420,31421,31422,31424,31425,31426,31427,31428,31429,31430, +31431,31432,31433,31434,31436,31437,31438,31439,31440,31441,31442,31443,31444, +31445,31447,31448,31450,31451,31452,31453,31457,31458,31460,31463,31464,31465, +31466,31467,31468,31470,31472,31473,31474,31475,U,31476,31477,31478,31479, +31480,31483,31484,31486,31488,31489,31490,31493,31495,31497,31500,31501,31502, +31504,31506,31507,31510,31511,31512,31514,31516,31517,31519,31521,31522,31523, +31527,31529,31533,31535,31536,31538,31540,31541,31542,31543,31545,31547,31549, +31551,31552,31553,31554,31555,31556,31558,31560,31562,31565,31566,31571,31573, +31575,31577,31580,31582,31583,31585,31587,31588,31589,31590,31591,31592,31593, +31594,31595,31596,31597,31599,31600,31603,31604,31606,31608,31610,31612,31613, +31615,31617,31618,31619,31620,31622,31623,31624,31625,31626,31627,31628,31630, +31631,U,31633,31634,31635,31638,31640,31641,31642,31643,31646,31647,31648, +31651,31652,31653,31662,31663,31664,31666,31667,31669,31670,31671,31673,31674, +31675,31676,31677,31678,31679,31680,31682,31683,31684,31685,31688,31689,31690, +31691,31693,31694,31695,31696,31698,31700,31701,31702,31703,31704,31707,31708, +31710,31711,31712,31714,31715,31716,31719,31720,31721,31723,31724,31725,31727, +31728,31730,31731,31732,31733,31734,31736,31737,31738,31739,31741,31743,31744, +31745,31746,31747,31748,31749,31750,31752,31753,31754,31757,31758,31760,31761, +31762,31763,31764,31765,31767,31768,31769,U,31770,31771,31772,31773,31774, +31776,31777,31778,31779,31780,31781,31784,31785,31787,31788,31789,31790,31791, +31792,31793,31794,31795,31796,31797,31798,31799,31801,31802,31803,31804,31805, +31806,31810,31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31822, +31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,31835, +31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848, +31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,31861,31862,31863, +31864,31865,31866,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879, +U,31880,31882,31883,31884,31885,31886,31887,31888,31891,31892,31894,31897, +31898,31899,31904,31905,31907,31910,31911,31912,31913,31915,31916,31917,31919, +31920,31924,31925,31926,31927,31928,31930,31931,31935,31936,31938,31939,31940, +31942,31945,31947,31950,31951,31952,31953,31954,31955,31956,31960,31962,31963, +31965,31966,31969,31970,31971,31972,31973,31974,31975,31977,31978,31979,31980, +31981,31982,31984,31985,31986,31987,31988,31989,31990,31991,31993,31994,31996, +31997,31998,31999,32000,32001,32002,32003,32004,32005,32006,32007,32008,32009, +32011,32012,32013,32014,32015,32016,U,32017,32018,32019,32020,32021,32022, +32023,32024,32025,32026,32027,32028,32029,32030,32031,32033,32035,32036,32037, +32038,32040,32041,32042,32044,32045,32046,32048,32049,32050,32051,32052,32053, +32054,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,32066, +32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,32078,32079, +32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,32090,32091,32092, +32093,32094,32095,32096,32097,32098,32099,32100,32101,32102,32103,32104,32105, +32106,32107,32108,32109,32111,32112,32113,32114,32115,32116,32117,32118,U, +32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,32132, +32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145, +32146,32147,32148,32149,32150,32151,32152,32153,32154,32155,32156,32157,32158, +32159,32160,32161,32162,32163,32164,32165,32167,32168,32169,32170,32171,32172, +32173,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,32186, +32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,32198,32199, +32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212, +32213,32214,32215,32216,32217,U,32218,32219,32220,32221,32222,32223,32224, +32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,32235,32236,32237, +32238,32239,32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250, +32251,32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263, +32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,32276, +32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289, +32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302, +32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,U,32314, +32316,32317,32318,32319,32320,32322,32323,32324,32325,32326,32328,32329,32330, +32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,32342,32343, +32344,32345,32346,32347,32348,32349,32350,32351,32352,32353,32354,32355,32356, +32357,32358,32359,32360,32361,32362,32363,32364,32365,32366,32367,32368,32369, +32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382, +32383,32384,32385,32387,32388,32389,32390,32391,32392,32393,32394,32395,32396, +32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409, +32410,32412,32413,32414,U,32430,32436,32443,32444,32470,32484,32492,32505, +32522,32528,32542,32567,32569,32571,32572,32573,32574,32575,32576,32577,32579, +32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32594,32595,32598, +32601,32603,32604,32605,32606,32608,32611,32612,32613,32614,32615,32619,32620, +32621,32623,32624,32627,32629,32630,32631,32632,32634,32635,32636,32637,32639, +32640,32642,32643,32644,32645,32646,32647,32648,32649,32651,32653,32655,32656, +32657,32658,32659,32661,32662,32663,32664,32665,32667,32668,32672,32674,32675, +32677,32678,32680,32681,32682,32683,32684,32685,32686,32689,U,32691,32692, +32693,32694,32695,32698,32699,32702,32704,32706,32707,32708,32710,32711,32712, +32713,32715,32717,32719,32720,32721,32722,32723,32726,32727,32729,32730,32731, +32732,32733,32734,32738,32739,32740,32743,32744,32746,32747,32748,32749,32751, +32754,32756,32757,32758,32759,32760,32761,32762,32765,32766,32767,32770,32775, +32776,32777,32778,32782,32783,32785,32787,32794,32795,32797,32798,32799,32801, +32803,32804,32811,32812,32813,32814,32815,32816,32818,32820,32825,32826,32828, +32830,32832,32833,32836,32837,32839,32840,32841,32846,32847,32848,32849,32851, +32853,32854,32855,U,32857,32859,32860,32861,32862,32863,32864,32865,32866, +32867,32868,32869,32870,32871,32872,32875,32876,32877,32878,32879,32880,32882, +32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,32894,32897, +32898,32901,32904,32906,32909,32910,32911,32912,32913,32914,32916,32917,32919, +32921,32926,32931,32934,32935,32936,32940,32944,32947,32949,32950,32952,32953, +32955,32965,32967,32968,32969,32970,32971,32975,32976,32977,32978,32979,32980, +32981,32984,32991,32992,32994,32995,32998,33006,33013,33015,33017,33019,33022, +33023,33024,33025,33027,33028,33029,33031,33032,33035,U,33036,33045,33047, +33049,33051,33052,33053,33055,33056,33057,33058,33059,33060,33061,33062,33063, +33064,33065,33066,33067,33069,33070,33072,33075,33076,33077,33079,33081,33082, +33083,33084,33085,33087,33088,33089,33090,33091,33092,33093,33095,33097,33101, +33102,33103,33106,33110,33111,33112,33115,33116,33117,33118,33119,33121,33122, +33123,33124,33126,33128,33130,33131,33132,33135,33138,33139,33141,33142,33143, +33144,33153,33155,33156,33157,33158,33159,33161,33163,33164,33165,33166,33168, +33170,33171,33172,33173,33174,33175,33177,33178,33182,33183,33184,33185,33186, +33188,33189,U,33191,33193,33195,33196,33197,33198,33199,33200,33201,33202, +33204,33205,33206,33207,33208,33209,33212,33213,33214,33215,33220,33221,33223, +33224,33225,33227,33229,33230,33231,33232,33233,33234,33235,33236,33237,33238, +33239,33240,33241,33242,33243,33244,33245,33246,33247,33248,33249,33250,33252, +33253,33254,33256,33257,33259,33262,33263,33264,33265,33266,33269,33270,33271, +33272,33273,33274,33277,33279,33283,33287,33288,33289,33290,33291,33294,33295, +33297,33299,33301,33302,33303,33304,33305,33306,33309,33312,33316,33317,33318, +33319,33321,33326,33330,33338,33340,33341,33343,U,33344,33345,33346,33347, +33349,33350,33352,33354,33356,33357,33358,33360,33361,33362,33363,33364,33365, +33366,33367,33369,33371,33372,33373,33374,33376,33377,33378,33379,33380,33381, +33382,33383,33385,33386,33387,33388,33389,33393,33397,33398,33399,33400,33403, +33404,33408,33409,33411,33413,33414,33415,33417,33420,33424,33427,33428,33429, +33430,33434,33435,33438,33440,33442,33443,33447,33458,33461,33462,33466,33467, +33468,33471,33472,33474,33475,33477,33478,33481,33488,33494,33497,33498,33501, +33506,33511,33512,33513,33514,33516,33517,33518,33520,33522,33523,33525,33526, +33528,U,33530,33532,33533,33534,33535,33536,33546,33547,33549,33552,33554, +33555,33558,33560,33561,33565,33566,33567,33568,33569,33570,33571,33572,33573, +33574,33577,33578,33582,33584,33586,33591,33595,33597,33598,33599,33601,33602, +33604,33605,33608,33610,33611,33612,33613,33614,33619,33621,33622,33623,33624, +33625,33629,33634,33648,33649,33650,33651,33652,33653,33654,33657,33658,33662, +33663,33664,33665,33666,33667,33668,33671,33672,33674,33675,33676,33677,33679, +33680,33681,33684,33685,33686,33687,33689,33690,33693,33695,33697,33698,33699, +33700,33701,33702,33703,33708,33709,33710,U,33711,33717,33723,33726,33727, +33730,33731,33732,33734,33736,33737,33739,33741,33742,33744,33745,33746,33747, +33749,33751,33753,33754,33755,33758,33762,33763,33764,33766,33767,33768,33771, +33772,33773,33774,33775,33779,33780,33781,33782,33783,33786,33787,33788,33790, +33791,33792,33794,33797,33799,33800,33801,33802,33808,33810,33811,33812,33813, +33814,33815,33817,33818,33819,33822,33823,33824,33825,33826,33827,33833,33834, +33835,33836,33837,33838,33839,33840,33842,33843,33844,33845,33846,33847,33849, +33850,33851,33854,33855,33856,33857,33858,33859,33860,33861,33863,33864,33865, +U,33866,33867,33868,33869,33870,33871,33872,33874,33875,33876,33877,33878, +33880,33885,33886,33887,33888,33890,33892,33893,33894,33895,33896,33898,33902, +33903,33904,33906,33908,33911,33913,33915,33916,33917,33918,33919,33920,33921, +33923,33924,33925,33926,33930,33933,33935,33936,33937,33938,33939,33940,33941, +33942,33944,33946,33947,33949,33950,33951,33952,33954,33955,33956,33957,33958, +33959,33960,33961,33962,33963,33964,33965,33966,33968,33969,33971,33973,33974, +33975,33979,33980,33982,33984,33986,33987,33989,33990,33991,33992,33995,33996, +33998,33999,34002,34004,34005,34007,U,34008,34009,34010,34011,34012,34014, +34017,34018,34020,34023,34024,34025,34026,34027,34029,34030,34031,34033,34034, +34035,34036,34037,34038,34039,34040,34041,34042,34043,34045,34046,34048,34049, +34050,34051,34052,34053,34054,34055,34056,34057,34058,34059,34061,34062,34063, +34064,34066,34068,34069,34070,34072,34073,34075,34076,34077,34078,34080,34082, +34083,34084,34085,34086,34087,34088,34089,34090,34093,34094,34095,34096,34097, +34098,34099,34100,34101,34102,34110,34111,34112,34113,34114,34116,34117,34118, +34119,34123,34124,34125,34126,34127,34128,34129,34130,34131,34132,34133,U, +34135,34136,34138,34139,34140,34141,34143,34144,34145,34146,34147,34149,34150, +34151,34153,34154,34155,34156,34157,34158,34159,34160,34161,34163,34165,34166, +34167,34168,34172,34173,34175,34176,34177,34178,34179,34182,34184,34185,34186, +34187,34188,34189,34190,34192,34193,34194,34195,34196,34197,34198,34199,34200, +34201,34202,34205,34206,34207,34208,34209,34210,34211,34213,34214,34215,34217, +34219,34220,34221,34225,34226,34227,34228,34229,34230,34232,34234,34235,34236, +34237,34238,34239,34240,34242,34243,34244,34245,34246,34247,34248,34250,34251, +34252,34253,34254,34257,34258,U,34260,34262,34263,34264,34265,34266,34267, +34269,34270,34271,34272,34273,34274,34275,34277,34278,34279,34280,34282,34283, +34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296, +34297,34298,34300,34301,34302,34304,34305,34306,34307,34308,34310,34311,34312, +34313,34314,34315,34316,34317,34318,34319,34320,34322,34323,34324,34325,34327, +34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340, +34341,34342,34344,34346,34347,34348,34349,34350,34351,34352,34353,34354,34355, +34356,34357,34358,34359,34361,34362,34363,34365,34366,34367,34368,U,34369, +34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34386,34387, +34389,34390,34391,34392,34393,34395,34396,34397,34399,34400,34401,34403,34404, +34405,34406,34407,34408,34409,34410,34413,34415,34416,34418,34419,34420,34421, +34422,34423,34424,34435,34436,34437,34438,34439,34440,34441,34446,34447,34448, +34449,34450,34452,34454,34455,34456,34457,34458,34459,34462,34463,34464,34465, +34466,34469,34470,34475,34477,34478,34482,34483,34487,34488,34489,34491,34492, +34493,34494,34495,34497,34498,34499,34501,34504,34508,34509,34514,34515,34517, +34518,34519,34522,34524,U,34525,34528,34529,34530,34531,34533,34534,34535, +34536,34538,34539,34540,34543,34549,34550,34551,34554,34555,34556,34557,34559, +34561,34564,34565,34566,34571,34572,34574,34575,34576,34577,34580,34582,34585, +34587,34589,34591,34592,34596,34598,34599,34600,34602,34603,34604,34605,34607, +34608,34610,34611,34613,34614,34616,34617,34618,34620,34621,34624,34625,34626, +34627,34628,34629,34630,34634,34635,34637,34639,34640,34641,34642,34644,34645, +34646,34648,34650,34651,34652,34653,34654,34655,34657,34658,34662,34663,34664, +34665,34666,34667,34668,34669,34671,34673,34674,34675,34677,U,34679,34680, +34681,34682,34687,34688,34689,34692,34694,34695,34697,34698,34700,34702,34703, +34704,34705,34706,34708,34709,34710,34712,34713,34714,34715,34716,34717,34718, +34720,34721,34722,34723,34724,34725,34726,34727,34729,34730,34734,34736,34737, +34738,34740,34742,34743,34744,34745,34747,34748,34750,34751,34753,34754,34755, +34756,34757,34759,34760,34761,34764,34765,34766,34767,34768,34772,34773,34774, +34775,34776,34777,34778,34780,34781,34782,34783,34785,34786,34787,34788,34790, +34791,34792,34793,34795,34796,34797,34799,34800,34801,34802,34803,34804,34805, +34806,34807,34808,U,34810,34811,34812,34813,34815,34816,34817,34818,34820, +34821,34822,34823,34824,34825,34827,34828,34829,34830,34831,34832,34833,34834, +34836,34839,34840,34841,34842,34844,34845,34846,34847,34848,34851,34852,34853, +34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34867, +34868,34869,34870,34871,34872,34874,34875,34877,34878,34879,34881,34882,34883, +34886,34887,34888,34889,34890,34891,34894,34895,34896,34897,34898,34899,34901, +34902,34904,34906,34907,34908,34909,34910,34911,34912,34918,34919,34922,34925, +34927,34929,34931,34932,34933,34934,34936,34937,34938,U,34939,34940,34944, +34947,34950,34951,34953,34954,34956,34958,34959,34960,34961,34963,34964,34965, +34967,34968,34969,34970,34971,34973,34974,34975,34976,34977,34979,34981,34982, +34983,34984,34985,34986,34988,34990,34991,34992,34994,34995,34996,34997,34998, +35000,35001,35002,35003,35005,35006,35007,35008,35011,35012,35015,35016,35018, +35019,35020,35021,35023,35024,35025,35027,35030,35031,35034,35035,35036,35037, +35038,35040,35041,35046,35047,35049,35050,35051,35052,35053,35054,35055,35058, +35061,35062,35063,35066,35067,35069,35071,35072,35073,35075,35076,35077,35078, +35079,35080,U,35081,35083,35084,35085,35086,35087,35089,35092,35093,35094, +35095,35096,35100,35101,35102,35103,35104,35106,35107,35108,35110,35111,35112, +35113,35116,35117,35118,35119,35121,35122,35123,35125,35127,35128,35129,35130, +35131,35132,35133,35134,35135,35136,35138,35139,35141,35142,35143,35144,35145, +35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158, +35159,35160,35161,35162,35163,35164,35165,35168,35169,35170,35171,35172,35173, +35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187, +35188,35189,35190,35191,35192,35193,35194,35196,U,35197,35198,35200,35202, +35204,35205,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217, +35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230, +35231,35232,35233,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243, +35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256, +35257,35258,35259,35260,35261,35262,35263,35264,35267,35277,35283,35284,35285, +35287,35288,35289,35291,35293,35295,35296,35297,35298,35300,35303,35304,35305, +35306,35308,35309,35310,35312,35313,35314,35316,35317,35318,35319,35320,35321, +35322,U,35323,35324,35325,35326,35327,35329,35330,35331,35332,35333,35334, +35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348, +35349,35350,35351,35352,35353,35354,35355,35356,35357,35358,35359,35360,35361, +35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374, +35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387, +35388,35389,35391,35392,35393,35394,35395,35396,35397,35398,35399,35401,35402, +35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415, +35416,35417,35418,35419,35420,35421,35422,U,35423,35424,35425,35426,35427, +35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440, +35441,35442,35443,35444,35445,35446,35447,35448,35450,35451,35452,35453,35454, +35455,35456,35457,35458,35459,35460,35461,35462,35463,35464,35467,35468,35469, +35470,35471,35472,35473,35474,35476,35477,35478,35479,35480,35481,35482,35483, +35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35494,35495,35496, +35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509, +35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522, +U,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534, +35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547, +35548,35549,35550,35551,35552,35553,35554,35555,35556,35557,35558,35559,35560, +35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573, +35574,35575,35576,35577,35578,35579,35580,35581,35582,35583,35584,35585,35586, +35587,35588,35589,35590,35592,35593,35594,35595,35596,35597,35598,35599,35600, +35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613, +35614,35615,35616,35617,35618,35619,U,35620,35621,35623,35624,35625,35626, +35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639, +35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652, +35653,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665, +35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678, +35679,35680,35681,35682,35683,35684,35685,35687,35688,35689,35690,35691,35693, +35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706, +35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,U, +35719,35720,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731, +35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35756, +35761,35771,35783,35792,35818,35849,35870,35896,35897,35898,35899,35900,35901, +35902,35903,35904,35906,35907,35908,35909,35912,35914,35915,35917,35918,35919, +35920,35921,35922,35923,35924,35926,35927,35928,35929,35931,35932,35933,35934, +35935,35936,35939,35940,35941,35942,35943,35944,35945,35948,35949,35950,35951, +35952,35953,35954,35956,35957,35958,35959,35963,35964,35965,35966,35967,35968, +35969,35971,35972,35974,35975,U,35976,35979,35981,35982,35983,35984,35985, +35986,35987,35989,35990,35991,35993,35994,35995,35996,35997,35998,35999,36000, +36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013, +36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,36026, +36027,36028,36029,36030,36031,36032,36033,36034,36035,36036,36037,36038,36039, +36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36052, +36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065, +36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,U,36077, +36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090, +36091,36092,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103, +36104,36105,36106,36107,36108,36109,36110,36111,36112,36113,36114,36115,36116, +36117,36118,36119,36120,36121,36122,36123,36124,36128,36177,36178,36183,36191, +36197,36200,36201,36202,36204,36206,36207,36209,36210,36216,36217,36218,36219, +36220,36221,36222,36223,36224,36226,36227,36230,36231,36232,36233,36236,36237, +36238,36239,36240,36242,36243,36245,36246,36247,36248,36249,36250,36251,36252, +36253,36254,36256,36257,U,36258,36260,36261,36262,36263,36264,36265,36266, +36267,36268,36269,36270,36271,36272,36274,36278,36279,36281,36283,36285,36288, +36289,36290,36293,36295,36296,36297,36298,36301,36304,36306,36307,36308,36309, +36312,36313,36316,36320,36321,36322,36325,36326,36327,36329,36333,36334,36336, +36337,36338,36340,36342,36348,36350,36351,36352,36353,36354,36355,36356,36358, +36359,36360,36363,36365,36366,36368,36369,36370,36371,36373,36374,36375,36376, +36377,36378,36379,36380,36384,36385,36388,36389,36390,36391,36392,36395,36397, +36400,36402,36403,36404,36406,36407,36408,36411,36412,36414,U,36415,36419, +36421,36422,36428,36429,36430,36431,36432,36435,36436,36437,36438,36439,36440, +36442,36443,36444,36445,36446,36447,36448,36449,36450,36451,36452,36453,36455, +36456,36458,36459,36462,36465,36467,36469,36471,36472,36473,36474,36475,36477, +36478,36480,36482,36483,36484,36486,36488,36489,36490,36491,36492,36493,36494, +36497,36498,36499,36501,36502,36503,36504,36505,36506,36507,36509,36511,36512, +36513,36514,36515,36516,36517,36518,36519,36520,36521,36522,36525,36526,36528, +36529,36531,36532,36533,36534,36535,36536,36537,36539,36540,36541,36542,36543, +36544,36545,36546,U,36547,36548,36549,36550,36551,36552,36553,36554,36555, +36556,36557,36559,36560,36561,36562,36563,36564,36565,36566,36567,36568,36569, +36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,36581,36582, +36583,36584,36585,36586,36587,36588,36589,36590,36591,36592,36593,36594,36595, +36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608, +36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36621, +36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634, +36635,36636,36637,36638,36639,36640,36641,36642,36643,U,36644,36645,36646, +36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659, +36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36670,36671,36672, +36673,36674,36675,36676,36677,36678,36679,36680,36681,36682,36683,36684,36685, +36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697,36698, +36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36714,36736, +36748,36754,36765,36768,36769,36770,36772,36773,36774,36775,36778,36780,36781, +36782,36783,36786,36787,36788,36789,36791,36792,36794,36795,36796,36799,36800, +36803,36806,U,36809,36810,36811,36812,36813,36815,36818,36822,36823,36826, +36832,36833,36835,36839,36844,36847,36849,36850,36852,36853,36854,36858,36859, +36860,36862,36863,36871,36872,36876,36878,36883,36885,36888,36889,36892,36899, +36900,36901,36903,36904,36905,36906,36907,36908,36912,36913,36914,36915,36916, +36919,36921,36922,36925,36927,36928,36931,36933,36934,36936,36937,36938,36939, +36940,36942,36948,36949,36950,36953,36954,36956,36957,36958,36959,36960,36961, +36964,36966,36967,36969,36970,36971,36972,36975,36976,36977,36978,36979,36982, +36983,36984,36985,36986,36987,36988,36990,36993,U,36996,36997,36998,36999, +37001,37002,37004,37005,37006,37007,37008,37010,37012,37014,37016,37018,37020, +37022,37023,37024,37028,37029,37031,37032,37033,37035,37037,37042,37047,37052, +37053,37055,37056,37058,37059,37062,37064,37065,37067,37068,37069,37074,37076, +37077,37078,37080,37081,37082,37086,37087,37088,37091,37092,37093,37097,37098, +37100,37102,37104,37105,37106,37107,37109,37110,37111,37113,37114,37115,37116, +37119,37120,37121,37123,37125,37126,37127,37128,37129,37130,37131,37132,37133, +37134,37135,37136,37137,37138,37139,37140,37141,37142,37143,37144,37146,37147, +37148,U,37149,37151,37152,37153,37156,37157,37158,37159,37160,37161,37162, +37163,37164,37165,37166,37168,37170,37171,37172,37173,37174,37175,37176,37178, +37179,37180,37181,37182,37183,37184,37185,37186,37188,37189,37191,37192,37201, +37203,37204,37205,37206,37208,37209,37211,37212,37215,37216,37222,37223,37224, +37227,37229,37235,37242,37243,37244,37248,37249,37250,37251,37252,37254,37256, +37258,37262,37263,37267,37268,37269,37270,37271,37272,37273,37276,37277,37278, +37279,37280,37281,37284,37285,37286,37287,37288,37289,37291,37292,37296,37297, +37298,37299,37302,37303,37304,37305,37307,U,37308,37309,37310,37311,37312, +37313,37314,37315,37316,37317,37318,37320,37323,37328,37330,37331,37332,37333, +37334,37335,37336,37337,37338,37339,37341,37342,37343,37344,37345,37346,37347, +37348,37349,37350,37351,37352,37353,37354,37355,37356,37357,37358,37359,37360, +37361,37362,37363,37364,37365,37366,37367,37368,37369,37370,37371,37372,37373, +37374,37375,37376,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386, +37387,37388,37389,37390,37391,37392,37393,37394,37395,37396,37397,37398,37399, +37400,37401,37402,37403,37404,37405,37406,37407,37408,37409,37410,37411,37412, +U,37413,37414,37415,37416,37417,37418,37419,37420,37421,37422,37423,37424, +37425,37426,37427,37428,37429,37430,37431,37432,37433,37434,37435,37436,37437, +37438,37439,37440,37441,37442,37443,37444,37445,37446,37447,37448,37449,37450, +37451,37452,37453,37454,37455,37456,37457,37458,37459,37460,37461,37462,37463, +37464,37465,37466,37467,37468,37469,37470,37471,37472,37473,37474,37475,37476, +37477,37478,37479,37480,37481,37482,37483,37484,37485,37486,37487,37488,37489, +37490,37491,37493,37494,37495,37496,37497,37498,37499,37500,37501,37502,37503, +37504,37505,37506,37507,37508,37509,U,37510,37511,37512,37513,37514,37515, +37516,37517,37519,37520,37521,37522,37523,37524,37525,37526,37527,37528,37529, +37530,37531,37532,37533,37534,37535,37536,37537,37538,37539,37540,37541,37542, +37543,37544,37545,37546,37547,37548,37549,37551,37552,37553,37554,37555,37556, +37557,37558,37559,37560,37561,37562,37563,37564,37565,37566,37567,37568,37569, +37570,37571,37572,37573,37574,37575,37577,37578,37579,37580,37581,37582,37583, +37584,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596, +37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,U, +37609,37610,37611,37612,37613,37614,37615,37616,37617,37618,37619,37620,37621, +37622,37623,37624,37625,37626,37627,37628,37629,37630,37631,37632,37633,37634, +37635,37636,37637,37638,37639,37640,37641,37642,37643,37644,37645,37646,37647, +37648,37649,37650,37651,37652,37653,37654,37655,37656,37657,37658,37659,37660, +37661,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673, +37674,37675,37676,37677,37678,37679,37680,37681,37682,37683,37684,37685,37686, +37687,37688,37689,37690,37691,37692,37693,37695,37696,37697,37698,37699,37700, +37701,37702,37703,37704,37705,U,37706,37707,37708,37709,37710,37711,37712, +37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,37725, +37726,37727,37728,37729,37730,37731,37732,37733,37734,37735,37736,37737,37739, +37740,37741,37742,37743,37744,37745,37746,37747,37748,37749,37750,37751,37752, +37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,37763,37764,37765, +37766,37767,37768,37769,37770,37771,37772,37773,37774,37776,37777,37778,37779, +37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792, +37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,U,37804, +37805,37806,37807,37808,37809,37810,37811,37812,37813,37814,37815,37816,37817, +37818,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830, +37831,37832,37833,37835,37836,37837,37838,37839,37840,37841,37842,37843,37844, +37845,37847,37848,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858, +37859,37860,37861,37862,37863,37864,37865,37866,37867,37868,37869,37870,37871, +37872,37873,37874,37875,37876,37877,37878,37879,37880,37881,37882,37883,37884, +37885,37886,37887,37888,37889,37890,37891,37892,37893,37894,37895,37896,37897, +37898,37899,37900,37901,U,37902,37903,37904,37905,37906,37907,37908,37909, +37910,37911,37912,37913,37914,37915,37916,37917,37918,37919,37920,37921,37922, +37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,37933,37934,37935, +37936,37937,37938,37939,37940,37941,37942,37943,37944,37945,37946,37947,37948, +37949,37951,37952,37953,37954,37955,37956,37957,37958,37959,37960,37961,37962, +37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975, +37976,37977,37978,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988, +37989,37990,37991,37992,37993,37994,37996,37997,37998,37999,U,38000,38001, +38002,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014, +38015,38016,38017,38018,38019,38020,38033,38038,38040,38087,38095,38099,38100, +38106,38118,38139,38172,38176,38183,38195,38205,38211,38216,38219,38229,38234, +38240,38254,38260,38261,38263,38264,38265,38266,38267,38268,38269,38270,38272, +38273,38274,38275,38276,38277,38278,38279,38280,38281,38282,38283,38284,38285, +38286,38287,38288,38289,38290,38291,38292,38293,38294,38295,38296,38297,38298, +38299,38300,38301,38302,38303,38304,38305,38306,38307,38308,38309,38310,38311, +38312,38313,38314,U,38315,38316,38317,38318,38319,38320,38321,38322,38323, +38324,38325,38326,38327,38328,38329,38330,38331,38332,38333,38334,38335,38336, +38337,38338,38339,38340,38341,38342,38343,38344,38345,38346,38347,38348,38349, +38350,38351,38352,38353,38354,38355,38356,38357,38358,38359,38360,38361,38362, +38363,38364,38365,38366,38367,38368,38369,38370,38371,38372,38373,38374,38375, +38380,38399,38407,38419,38424,38427,38430,38432,38435,38436,38437,38438,38439, +38440,38441,38443,38444,38445,38447,38448,38455,38456,38457,38458,38462,38465, +38467,38474,38478,38479,38481,38482,38483,38486,38487,U,38488,38489,38490, +38492,38493,38494,38496,38499,38501,38502,38507,38509,38510,38511,38512,38513, +38515,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531, +38532,38535,38537,38538,38540,38542,38545,38546,38547,38549,38550,38554,38555, +38557,38558,38559,38560,38561,38562,38563,38564,38565,38566,38568,38569,38570, +38571,38572,38573,38574,38575,38577,38578,38580,38581,38583,38584,38586,38587, +38591,38594,38595,38600,38602,38603,38608,38609,38611,38612,38614,38615,38616, +38617,38618,38619,38620,38621,38622,38623,38625,38626,38627,38628,38629,38630, +38631,38635,U,38636,38637,38638,38640,38641,38642,38644,38645,38648,38650, +38651,38652,38653,38655,38658,38659,38661,38666,38667,38668,38672,38673,38674, +38676,38677,38679,38680,38681,38682,38683,38685,38687,38688,38689,38690,38691, +38692,38693,38694,38695,38696,38697,38699,38700,38702,38703,38705,38707,38708, +38709,38710,38711,38714,38715,38716,38717,38719,38720,38721,38722,38723,38724, +38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737, +38740,38741,38743,38744,38746,38748,38749,38751,38755,38756,38758,38759,38760, +38762,38763,38764,38765,38766,38767,38768,38769,U,38770,38773,38775,38776, +38777,38778,38779,38781,38782,38783,38784,38785,38786,38787,38788,38790,38791, +38792,38793,38794,38796,38798,38799,38800,38803,38805,38806,38807,38809,38810, +38811,38812,38813,38814,38815,38817,38818,38820,38821,38822,38823,38824,38825, +38826,38828,38830,38832,38833,38835,38837,38838,38839,38840,38841,38842,38843, +38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856, +38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869, +38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882, +38883,U,38884,38885,38888,38894,38895,38896,38897,38898,38900,38903,38904, +38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917, +38918,38919,38920,38921,38922,38923,38924,38925,38926,38927,38928,38929,38930, +38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943, +38944,38945,38946,38947,38948,38949,38950,38951,38952,38953,38954,38955,38956, +38957,38958,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969, +38970,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982, +38983,38984,38985,38986,38987,38988,38989,U,38990,38991,38992,38993,38994, +38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007, +39008,39009,39010,39011,39012,39013,39014,39015,39016,39017,39018,39019,39020, +39021,39022,39023,39024,39025,39026,39027,39028,39051,39054,39058,39061,39065, +39075,39080,39081,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091, +39092,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104, +39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,39115,39116,39117, +39119,39120,39124,39126,39127,39131,39132,39133,39136,39137,39138,39139,39140, +U,39141,39142,39145,39146,39147,39148,39149,39150,39151,39152,39153,39154, +39155,39156,39157,39158,39159,39160,39161,39162,39163,39164,39165,39166,39167, +39168,39169,39170,39171,39172,39173,39174,39175,39176,39177,39178,39179,39180, +39182,39183,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39195, +39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39208, +39209,39210,39211,39212,39213,39215,39216,39217,39218,39219,39220,39221,39222, +39223,39224,39225,39226,39227,39228,39229,39230,39231,39232,39233,39234,39235, +39236,39237,39238,39239,39240,39241,U,39242,39243,39244,39245,39246,39247, +39248,39249,39250,39251,39254,39255,39256,39257,39258,39259,39260,39261,39262, +39263,39264,39265,39266,39268,39270,39283,39288,39289,39291,39294,39298,39299, +39305,39308,39310,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331, +39332,39334,39335,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346, +39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357,39358,39359, +39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372, +39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,U, +39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397, +39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409,39410, +39411,39412,39413,39414,39415,39416,39417,39418,39419,39420,39421,39422,39423, +39424,39425,39426,39427,39428,39429,39430,39431,39432,39433,39434,39435,39436, +39437,39438,39439,39440,39441,39442,39443,39444,39445,39446,39447,39448,39449, +39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462, +39463,39464,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475, +39476,39477,39478,39479,39480,U,39481,39482,39483,39484,39485,39486,39487, +39488,39489,39490,39491,39492,39493,39494,39495,39496,39497,39498,39499,39500, +39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513, +39514,39515,39516,39517,39518,39519,39520,39521,39522,39523,39524,39525,39526, +39527,39528,39529,39530,39531,39538,39555,39561,39565,39566,39572,39573,39577, +39590,39593,39594,39595,39596,39597,39598,39599,39602,39603,39604,39605,39609, +39611,39613,39614,39615,39619,39620,39622,39623,39624,39625,39626,39629,39630, +39631,39632,39634,39636,39637,39638,39639,39641,39642,39643,39644,U,39645, +39646,39648,39650,39651,39652,39653,39655,39656,39657,39658,39660,39662,39664, +39665,39666,39667,39668,39669,39670,39671,39672,39674,39676,39677,39678,39679, +39680,39681,39682,39684,39685,39686,39687,39689,39690,39691,39692,39693,39694, +39696,39697,39698,39700,39701,39702,39703,39704,39705,39706,39707,39708,39709, +39710,39712,39713,39714,39716,39717,39718,39719,39720,39721,39722,39723,39724, +39725,39726,39728,39729,39731,39732,39733,39734,39735,39736,39737,39738,39741, +39742,39743,39744,39750,39754,39755,39756,39758,39760,39762,39763,39765,39766, +39767,39768,39769,39770,U,39771,39772,39773,39774,39775,39776,39777,39778, +39779,39780,39781,39782,39783,39784,39785,39786,39787,39788,39789,39790,39791, +39792,39793,39794,39795,39796,39797,39798,39799,39800,39801,39802,39803,39804, +39805,39806,39807,39808,39809,39810,39811,39812,39813,39814,39815,39816,39817, +39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829,39830, +39831,39832,39833,39834,39835,39836,39837,39838,39839,39840,39841,39842,39843, +39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39854,39855,39856, +39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,U,39867,39868, +39869,39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881, +39882,39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894, +39895,39896,39897,39898,39899,39900,39901,39902,39903,39904,39905,39906,39907, +39908,39909,39910,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920, +39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933, +39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946, +39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959, +39960,39961,39962,U,39963,39964,39965,39966,39967,39968,39969,39970,39971, +39972,39973,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984, +39985,39986,39987,39988,39989,39990,39991,39992,39993,39994,39995,39996,39997, +39998,39999,40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010, +40011,40012,40013,40014,40015,40016,40017,40018,40019,40020,40021,40022,40023, +40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40035,40036, +40037,40038,40039,40040,40041,40042,40043,40044,40045,40046,40047,40048,40049, +40050,40051,40052,40053,40054,40055,40056,40057,40058,U,40059,40061,40062, +40064,40067,40068,40073,40074,40076,40079,40083,40086,40087,40088,40089,40093, +40106,40108,40111,40121,40126,40127,40128,40129,40130,40136,40137,40145,40146, +40154,40155,40160,40161,40163,40164,40165,40166,40167,40168,40169,40170,40171, +40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184, +40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197, +40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210, +40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223, +40224,40225,U,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235, +40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248, +40249,40250,40251,40252,40253,40254,40255,40256,40257,40258,40259,40260,40261, +40262,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274, +40275,40276,40277,40278,40279,40280,40281,40282,40283,40284,40285,40286,40287, +40288,40289,40290,40291,40292,40293,40294,40295,40296,40297,40298,40299,40300, +40301,40302,40303,40304,40305,40306,40307,40308,40309,40310,40311,40312,40313, +40314,40315,40316,40317,40318,40319,40320,40321,U,40322,40323,40324,40325, +40326,40327,40328,40329,40330,40331,40332,40333,40334,40335,40336,40337,40338, +40339,40340,40341,40342,40343,40344,40345,40346,40347,40348,40349,40350,40351, +40352,40353,40354,40355,40356,40357,40358,40359,40360,40361,40362,40363,40364, +40365,40366,40367,40368,40369,40370,40371,40372,40373,40374,40375,40376,40377, +40378,40379,40380,40381,40382,40383,40384,40385,40386,40387,40388,40389,40390, +40391,40392,40393,40394,40395,40396,40397,40398,40399,40400,40401,40402,40403, +40404,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416, +40417,U,40418,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428, +40429,40430,40431,40432,40433,40434,40435,40436,40437,40438,40439,40440,40441, +40442,40443,40444,40445,40446,40447,40448,40449,40450,40451,40452,40453,40454, +40455,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467, +40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40484,40487, +40494,40496,40500,40507,40508,40512,40525,40528,40530,40531,40532,40534,40537, +40541,40543,40544,40545,40546,40549,40558,40559,40562,40564,40565,40566,40567, +40568,40569,40570,40571,40572,40573,40576,U,40577,40579,40580,40581,40582, +40585,40586,40588,40589,40590,40591,40592,40593,40596,40597,40598,40599,40600, +40601,40602,40603,40604,40606,40608,40609,40610,40611,40612,40613,40615,40616, +40617,40618,40619,40620,40621,40622,40623,40624,40625,40626,40627,40629,40630, +40631,40633,40634,40636,40639,40640,40641,40642,40643,40645,40646,40647,40648, +40650,40651,40652,40656,40658,40659,40661,40662,40663,40665,40666,40670,40673, +40675,40676,40678,40680,40683,40684,40685,40686,40688,40689,40690,40691,40692, +40693,40694,40695,40696,40698,40701,40703,40704,40705,40706,40707,40708,40709, +U,40710,40711,40712,40713,40714,40716,40719,40721,40722,40724,40725,40726, +40728,40730,40731,40732,40733,40734,40735,40737,40739,40740,40741,40742,40743, +40744,40745,40746,40747,40749,40750,40752,40753,40754,40755,40756,40757,40758, +40760,40762,40764,40767,40768,40769,40770,40771,40773,40774,40775,40776,40777, +40778,40779,40780,40781,40782,40783,40786,40787,40788,40789,40790,40791,40792, +40793,40794,40795,40796,40797,40798,40799,40800,40801,40802,40803,40804,40805, +40806,40807,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818, +40819,40820,40821,40822,40823,40824,U,40825,40826,40827,40828,40829,40830, +40833,40834,40845,40846,40847,40848,40849,40850,40851,40852,40853,40854,40855, +40856,40860,40861,40862,40865,40866,40867,40868,40869,63788,63865,63893,63975, +63985,64012,64013,64014,64015,64017,64019,64020,64024,64031,64032,64033,64035, +64036,64039,64040,64041, +}; + +static const struct dbcs_index gbkext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{__gbkext_decmap+0,64,254},{__gbkext_decmap+191,64, +254},{__gbkext_decmap+382,64,254},{__gbkext_decmap+573,64,254},{ +__gbkext_decmap+764,64,254},{__gbkext_decmap+955,64,254},{__gbkext_decmap+1146 +,64,254},{__gbkext_decmap+1337,64,254},{__gbkext_decmap+1528,64,254},{ +__gbkext_decmap+1719,64,254},{__gbkext_decmap+1910,64,254},{__gbkext_decmap+ +2101,64,254},{__gbkext_decmap+2292,64,254},{__gbkext_decmap+2483,64,254},{ +__gbkext_decmap+2674,64,254},{__gbkext_decmap+2865,64,254},{__gbkext_decmap+ +3056,64,254},{__gbkext_decmap+3247,64,254},{__gbkext_decmap+3438,64,254},{ +__gbkext_decmap+3629,64,254},{__gbkext_decmap+3820,64,254},{__gbkext_decmap+ +4011,64,254},{__gbkext_decmap+4202,64,254},{__gbkext_decmap+4393,64,254},{ +__gbkext_decmap+4584,64,254},{__gbkext_decmap+4775,64,254},{__gbkext_decmap+ +4966,64,254},{__gbkext_decmap+5157,64,254},{__gbkext_decmap+5348,64,254},{ +__gbkext_decmap+5539,64,254},{__gbkext_decmap+5730,64,254},{__gbkext_decmap+ +5921,64,254},{__gbkext_decmap+6112,164,170},{__gbkext_decmap+6119,161,170},{0, +0,0},{0,0,0},{0,0,0},{__gbkext_decmap+6129,224,245},{0,0,0},{__gbkext_decmap+ +6151,64,192},{__gbkext_decmap+6280,64,150},{__gbkext_decmap+6367,64,160},{ +__gbkext_decmap+6464,64,160},{__gbkext_decmap+6561,64,160},{__gbkext_decmap+ +6658,64,160},{__gbkext_decmap+6755,64,160},{__gbkext_decmap+6852,64,160},{ +__gbkext_decmap+6949,64,160},{__gbkext_decmap+7046,64,160},{__gbkext_decmap+ +7143,64,160},{__gbkext_decmap+7240,64,160},{__gbkext_decmap+7337,64,160},{ +__gbkext_decmap+7434,64,160},{__gbkext_decmap+7531,64,160},{__gbkext_decmap+ +7628,64,160},{__gbkext_decmap+7725,64,160},{__gbkext_decmap+7822,64,160},{ +__gbkext_decmap+7919,64,160},{__gbkext_decmap+8016,64,160},{__gbkext_decmap+ +8113,64,160},{__gbkext_decmap+8210,64,160},{__gbkext_decmap+8307,64,160},{ +__gbkext_decmap+8404,64,160},{__gbkext_decmap+8501,64,160},{__gbkext_decmap+ +8598,64,160},{__gbkext_decmap+8695,64,160},{__gbkext_decmap+8792,64,160},{ +__gbkext_decmap+8889,64,160},{__gbkext_decmap+8986,64,160},{__gbkext_decmap+ +9083,64,160},{__gbkext_decmap+9180,64,160},{__gbkext_decmap+9277,64,160},{ +__gbkext_decmap+9374,64,160},{__gbkext_decmap+9471,64,160},{__gbkext_decmap+ +9568,64,160},{__gbkext_decmap+9665,64,160},{__gbkext_decmap+9762,64,160},{ +__gbkext_decmap+9859,64,160},{__gbkext_decmap+9956,64,160},{__gbkext_decmap+ +10053,64,160},{__gbkext_decmap+10150,64,160},{__gbkext_decmap+10247,64,160},{ +__gbkext_decmap+10344,64,160},{__gbkext_decmap+10441,64,160},{__gbkext_decmap+ +10538,64,160},{__gbkext_decmap+10635,64,160},{__gbkext_decmap+10732,64,160},{ +__gbkext_decmap+10829,64,160},{__gbkext_decmap+10926,64,160},{__gbkext_decmap+ +11023,64,160},{__gbkext_decmap+11120,64,160},{__gbkext_decmap+11217,64,160},{ +__gbkext_decmap+11314,64,160},{__gbkext_decmap+11411,64,160},{__gbkext_decmap+ +11508,64,160},{__gbkext_decmap+11605,64,160},{__gbkext_decmap+11702,64,160},{ +__gbkext_decmap+11799,64,160},{__gbkext_decmap+11896,64,160},{__gbkext_decmap+ +11993,64,160},{__gbkext_decmap+12090,64,160},{__gbkext_decmap+12187,64,160},{ +__gbkext_decmap+12284,64,160},{__gbkext_decmap+12381,64,160},{__gbkext_decmap+ +12478,64,160},{__gbkext_decmap+12575,64,160},{__gbkext_decmap+12672,64,160},{ +__gbkext_decmap+12769,64,160},{__gbkext_decmap+12866,64,160},{__gbkext_decmap+ +12963,64,160},{__gbkext_decmap+13060,64,160},{__gbkext_decmap+13157,64,160},{ +__gbkext_decmap+13254,64,160},{__gbkext_decmap+13351,64,160},{__gbkext_decmap+ +13448,64,160},{__gbkext_decmap+13545,64,160},{__gbkext_decmap+13642,64,160},{ +__gbkext_decmap+13739,64,160},{__gbkext_decmap+13836,64,160},{__gbkext_decmap+ +13933,64,160},{__gbkext_decmap+14030,64,160},{__gbkext_decmap+14127,64,160},{ +__gbkext_decmap+14224,64,160},{__gbkext_decmap+14321,64,160},{__gbkext_decmap+ +14418,64,160},{__gbkext_decmap+14515,64,79},{0,0,0}, +}; + +static const DBCHAR __gbcommon_encmap[23231] = { +8552,N,N,8556,8487,N,N,N,N,N,N,N,8547,8512,N,N,N,N,N,41380,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8513,N,N,N,N,N,N,N,N,10276,10274, +N,N,N,N,N,N,10280,10278,10298,N,10284,10282,N,N,N,N,10288,10286,N,N,N,8514,N, +10292,10290,N,10297,10273,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10277,N,N,N,N,N,N, +N,10279,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,43197,N,N,N,43198,N,N,N,N,10285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,10289,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10275, +N,10283,N,10287,N,10291,N,10293,N,10294,N,10295,N,10296,43195,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,43200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8486,N,8485, +43072,43073,N,N,N,N,N,N,N,N,N,N,N,N,N,43074,9761,9762,9763,9764,9765,9766, +9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,N,9778,9779,9780,9781, +9782,9783,9784,N,N,N,N,N,N,N,9793,9794,9795,9796,9797,9798,9799,9800,9801, +9802,9803,9804,9805,9806,9807,9808,9809,N,9810,9811,9812,9813,9814,9815,9816, +10023,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10017,10018,10019,10020,10021,10022,10024, +10025,10026,10027,10028,10029,10030,10031,10032,10033,10034,10035,10036,10037, +10038,10039,10040,10041,10042,10043,10044,10045,10046,10047,10048,10049,10065, +10066,10067,10068,10069,10070,10072,10073,10074,10075,10076,10077,10078,10079, +10080,10081,10082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092, +10093,10094,10095,10096,10097,N,10071,43356,N,N,43075,41386,8490,8492,N,8494, +8495,N,N,8496,8497,N,N,N,N,N,N,N,43077,8493,N,N,N,N,N,N,N,N,N,8555,N,8548, +8549,N,43078,N,N,N,N,N,8569,8550,N,43079,N,N,N,43080,N,N,N,N,N,N,N,N,N,N,N,N, +8557,N,N,N,N,N,N,N,N,N,N,43353,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,8828,N,N,N,N,41633, +41634,41635,41636,41637,41638,41639,41640,41641,41642,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,8571,8572,8570,8573,N,N,43081,43082,43083,43084,8522,N,N, +N,N,N,N,8519,N,8518,N,N,N,43085,N,N,N,N,8524,N,N,8536,8542,43086,8527,N,N, +43087,N,8526,N,8516,8517,8521,8520,8530,N,N,8531,N,N,N,N,N,8544,8543,8515, +8523,N,N,N,N,N,8535,N,N,N,N,N,N,N,N,N,N,8534,N,N,N,8533,N,N,N,N,N,43088,N,N,N, +N,N,N,N,N,N,N,N,N,N,8537,8532,N,N,8540,8541,43089,43090,N,N,N,N,N,N,8538,8539, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43154,N,N,N,8529,N,N,N,N,N,N,N,N,N,N,N,8525,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,43091,8528,8793,8794,8795,8796,8797,8798,8799,8800,8801,8802, +N,N,N,N,N,N,N,N,N,N,8773,8774,8775,8776,8777,8778,8779,8780,8781,8782,8783, +8784,8785,8786,8787,8788,8789,8790,8791,8792,8753,8754,8755,8756,8757,8758, +8759,8760,8761,8762,8763,8764,8765,8766,8767,8768,8769,8770,8771,8772,10532, +10533,10534,10535,10536,10537,10538,10539,10540,10541,10542,10543,10544,10545, +10546,10547,10548,10549,10550,10551,10552,10553,10554,10555,10556,10557,10558, +10559,10560,10561,10562,10563,10564,10565,10566,10567,10568,10569,10570,10571, +10572,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584, +10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597, +10598,10599,10600,10601,10602,10603,10604,10605,10606,10607,N,N,N,N,43092, +43093,43094,43095,43096,43097,43098,43099,43100,43101,43102,43103,43104,43105, +43106,43107,43108,43109,43110,43111,43112,43113,43114,43115,43116,43117,43118, +43119,43120,43121,43122,43123,43124,43125,43126,43127,N,N,N,N,N,N,N,N,N,N,N,N, +N,43128,43129,43130,43131,43132,43133,43134,43136,43137,43138,43139,43140, +43141,43142,43143,N,N,N,43144,43145,43146,N,N,N,N,N,N,N,N,N,N,8566,8565,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,8568,8567,N,N,N,N,N,N,N,N,43147,43148,N,N,N,N,N,N,N, +N,8564,8563,N,N,N,8560,N,N,8562,8561,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43149,43150,43151,43152,8559,8558,N,N,43153,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +8546,N,8545,8481,8482,8483,8488,N,8489,43365,43414,8500,8501,8502,8503,8504, +8505,8506,8507,8510,8511,43155,8574,8498,8499,8508,8509,N,N,N,N,N,43156,43157, +N,N,43328,43329,43330,43331,43332,43333,43334,43335,43336,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258, +9259,9260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273, +9274,9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288, +9289,9290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303, +9304,9305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318, +9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,N,N,N,N,N,N, +N,43361,43362,43366,43367,N,N,9505,9506,9507,9508,9509,9510,9511,9512,9513, +9514,9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528, +9529,9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543, +9544,9545,9546,9547,9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558, +9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573, +9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588, +9589,9590,N,N,N,N,8484,43360,43363,43364,10309,10310,10311,10312,10313,10314, +10315,10316,10317,10318,10319,10320,10321,10322,10323,10324,10325,10326,10327, +10328,10329,10330,10331,10332,10333,10334,10335,10336,10337,10338,10339,10340, +10341,10342,10343,10344,10345,8805,8806,8807,8808,8809,8810,8811,8812,8813, +8814,N,N,N,N,N,N,N,43354,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,43337,43338,43339,N,N,N,N,N,N,N,N,N,N,N,N,43340,43341,43342, +N,N,43343,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43344,N,N,N,N,N,N,N,N,N,43345,N,N,43346,43347,N,N,43348,21051,13857,33088, +18015,33089,33090,33091,19826,21833,18557,18767,20290,22562,12859,21355,33092, +22564,13171,33093,22312,18258,22567,19008,33094,18288,12667,21045,13396,13867, +19263,22569,33095,33096,33097,13866,33098,16701,20815,33099,18725,22573,33100, +14454,20798,25436,22096,33101,33102,14177,33103,13358,33104,16729,33105,22588, +33106,19816,13604,20010,22135,33107,16502,15961,22575,33108,33109,33110,17483, +33111,15939,33112,22577,17204,21093,33113,22062,20058,21799,14965,14118,16470, +33114,17977,17746,18247,33115,14676,33116,13131,21074,33117,33118,22591,15941, +18034,21042,20272,20327,33119,33120,33121,33122,19049,33123,33124,22592,33125, +33126,33127,33128,33129,33130,17010,16978,33131,18537,33132,33133,33134,33135, +33136,33137,33138,33139,33140,33141,18220,33142,33143,33144,33145,33146,33147, +33148,16715,33149,21352,21881,33150,19010,13950,22561,21338,16247,33152,21574, +15141,22593,20069,15918,33153,33154,22568,33155,20807,20521,33156,33157,33158, +22589,22895,19830,16186,33159,15675,14885,21088,12922,14944,17462,33160,20333, +15913,19748,16705,33161,33162,33163,18263,22897,33164,22900,33165,33166,33167, +33168,18507,22633,33169,33170,33171,21082,18994,18506,22636,22634,22598,15734, +17997,13168,33172,22635,15729,15721,33173,18516,13395,33174,33175,16984,33176, +12886,22352,19019,19323,21836,14390,20297,33177,33178,33179,22874,22640,18218, +33180,22638,33181,13434,16750,21076,33182,33183,22637,33184,21063,22639,17223, +33185,33186,33187,20854,33188,22105,22642,33189,22645,15486,15451,33190,33191, +33192,18510,33193,14173,33194,14146,33195,18035,33196,33197,33198,33199,33200, +33201,33202,22648,21057,33203,33204,20073,15423,14204,14117,20573,33205,33206, +33207,33208,33209,22106,21317,15215,15201,22641,33210,33211,18721,20016,13355, +33212,22643,33213,18763,22646,16983,22647,33214,33215,20017,22649,33216,33217, +33218,12846,14656,33219,22819,33220,12393,33221,16742,33222,18796,33223,19269, +33224,19270,22820,33225,33226,33227,33228,33229,13672,33230,33231,13611,33232, +33233,33234,33235,33236,33237,20027,13645,22305,22388,21331,33238,19557,33239, +14926,33240,22818,22876,21344,22653,14192,22391,22654,22650,22817,17507,33241, +33242,21302,22644,22877,33243,22651,33244,17765,33245,33246,16464,33247,33248, +20848,12379,33249,33250,15441,22822,33251,22821,33252,33253,33254,33255,22828, +22830,33256,22827,19001,33257,33258,33259,22825,22070,33260,33261,33262,13150, +22824,33263,16509,33264,19020,33265,22826,33266,22823,33267,33268,22832,33269, +33270,13873,33271,33272,33273,14633,33274,21056,33275,33276,20288,33277,33278, +16962,33344,15684,21868,12896,18248,16235,22829,33345,22831,33346,20074,14958, +33347,33348,33349,33350,33351,18262,33352,33353,33354,33355,33356,33357,33358, +33359,33360,12643,33361,33362,33363,13401,13933,22836,33364,33365,33366,33367, +16161,33368,33369,33370,22878,18254,16510,22840,33371,33372,33373,33374,33375, +19287,14205,33376,22837,33377,22839,12579,21345,22841,33378,20549,33379,22838, +33380,33381,22833,33382,22834,16681,22835,33383,33384,15475,20574,14377,33385, +15971,33386,22845,33387,33388,33389,33390,22842,33391,12339,33392,33393,33394, +22850,33395,33396,33397,33398,33399,33400,33401,33402,33403,33404,33405,33406, +33408,22852,12598,33409,22847,33410,33411,13625,33412,15987,33413,33414,33415, +19528,14962,21072,33416,22851,33417,33418,15720,33419,13099,33420,33421,33422, +22853,15979,33423,22854,22843,17503,33424,22846,22849,22848,33425,33426,33427, +33428,33429,33430,33431,33432,33433,33434,33435,21806,33436,22069,33437,18275, +33438,33439,33440,33441,22856,33442,33443,33444,15449,22858,33445,33446,33447, +22844,33448,22859,17963,33449,33450,33451,33452,33453,22857,33454,33455,33456, +33457,22390,33458,19747,33459,33460,33461,33462,33463,33464,33465,33466,15649, +33467,33468,33469,33470,33471,33472,22860,33473,33474,33475,33476,33477,33478, +33479,33480,33481,17724,19765,33482,33483,33484,22861,33485,33486,22855,13093, +16254,33487,33488,33489,33490,14389,33491,33492,16508,33493,33494,33495,33496, +12408,33497,33498,33499,33500,33501,33502,33503,33504,33505,33506,33507,33508, +33509,33510,33511,33512,33513,33514,33515,33516,33517,13430,33518,22862,33519, +22863,13346,22864,33520,33521,13407,33522,33523,33524,33525,33526,12353,33527, +33528,33529,33530,33531,33532,33533,22865,18741,33534,33600,33601,33602,33603, +33604,33605,33606,33607,33608,33609,33610,33611,33612,33613,33614,33615,33616, +33617,20337,33618,33619,33620,33621,33622,33623,22866,33624,33625,33626,16709, +33627,33628,33629,33630,33631,33632,33633,33634,33635,33636,33637,22870,18734, +33638,33639,33640,33641,22869,22868,22871,33642,33643,33644,33645,19291,33646, +15657,33647,33648,33649,33650,33651,17959,33652,33653,33654,33655,33656,33657, +33658,33659,33660,33661,22867,22872,33662,33664,33665,22873,33666,33667,33668, +33669,33670,33671,18533,33672,33673,33674,33675,33676,33677,33678,33679,33680, +33681,33682,33683,33684,33685,16476,33686,33687,33688,33689,33690,33691,33692, +33693,33694,33695,33696,33697,33698,33699,33700,33701,33702,33703,33704,33705, +33706,33707,33708,33709,33710,33711,33712,33713,33714,13945,22563,21578,33715, +21546,20566,13156,21847,33716,20296,14690,33717,16203,33718,17250,33719,33720, +33721,13906,33722,33723,19779,22894,22896,33724,33725,33726,13619,33727,13877, +33728,33729,33730,33731,33732,15908,33733,33734,18539,33735,33736,18475,33737, +33738,12363,14635,16761,22882,33739,16444,14642,33740,14680,20555,12664,18020, +15967,13668,22344,33741,20856,15462,19038,33742,33743,15421,22886,22631,33744, +33745,17498,33746,33747,14420,18493,33748,33749,12897,21593,33750,33751,33752, +33753,17200,33754,33755,17249,23074,18527,33756,20532,33757,15996,17705,33758, +33759,33760,14682,33761,23075,33762,21545,23076,33763,33764,33765,33766,33767, +22907,13868,33768,33769,14187,12665,22908,13157,15990,33770,16246,21041,16484, +33771,33772,33773,13875,22910,22909,33774,33775,15931,33776,33777,33778,18016, +33779,22332,23073,33780,16697,33781,13682,16744,33782,33783,15477,33784,13397, +33785,33786,33787,33788,33789,33790,33856,33857,33858,16733,33859,17533,33860, +33861,15416,14130,33862,33863,14191,33864,33865,33866,33867,33868,33869,22892, +33870,17982,33871,16173,15179,33872,33873,13642,33874,23369,20567,33875,19769, +12348,13174,15223,23370,14895,33876,21604,13622,13683,22614,18512,33877,33878, +14166,18256,22615,33879,16175,33880,33881,23355,22616,33882,33883,20556,15150, +33884,33885,33886,27454,16720,16757,21618,14421,13364,33887,13173,33888,33889, +18750,33890,33891,33892,17744,33893,33894,33895,17753,16507,33896,12656,33897, +22617,14670,33898,13629,33899,33900,22618,33901,33902,22086,19234,18479,18738, +13388,16204,33903,14708,33904,22619,22620,13927,15425,19562,33905,33906,33907, +33908,33909,33910,20343,33911,22621,18224,33912,33913,14672,15651,33914,33915, +19550,33916,17994,33917,33918,33920,33921,33922,22624,33923,22622,33924,33925, +22623,33926,33927,33928,12414,33929,15975,33930,18979,15476,33931,33932,33933, +33934,14385,33935,33936,14446,33937,33938,33939,33940,33941,33942,33943,33944, +33945,33946,22626,33947,15691,33948,22628,22627,33949,33950,33951,33952,33953, +17788,33954,33955,33956,33957,33958,33959,33960,22629,33961,33962,22630,33963, +33964,33965,33966,33967,33968,33969,16678,33970,18480,12396,14630,15443,20081, +23357,16723,33971,33972,33973,33974,13871,22138,17708,15705,23358,23359,33975, +33976,33977,16504,15906,16461,33978,33979,33980,33981,33982,33983,33984,33985, +33986,33987,23360,19014,33988,33989,33990,12842,33991,33992,33993,21314,33994, +17251,33995,20779,33996,33997,33998,33999,23362,34000,16469,34001,34002,34003, +23363,34004,16177,34005,34006,34007,34008,34009,34010,17468,34011,34012,34013, +34014,18266,34015,34016,34017,34018,34019,34020,34021,34022,34023,34024,34025, +23364,34026,34027,34028,34029,34030,34031,34032,34033,22888,18775,34034,34035, +34036,14644,20080,21576,34037,34038,34039,34040,12412,13394,34041,20569,34042, +34043,34044,34045,22889,34046,24139,22891,34112,34113,34114,34115,22576,15151, +12593,34116,13143,22606,34117,34118,21585,34119,34120,15667,16239,34121,20283, +34122,34123,22608,34124,34125,34126,14155,34127,34128,34129,22609,34130,34131, +34132,34133,34134,34135,34136,34137,34138,34139,17957,18296,21053,34140,34141, +22610,17508,34142,18990,34143,18215,34144,22566,34145,18813,20071,15196,12395, +34146,34147,34148,15146,20525,34149,12592,22372,22335,34150,13605,17012,17487, +34151,34152,12841,34153,12855,34154,12645,24370,21820,16168,16940,22613,16945, +34155,22612,20052,34156,23136,34157,20032,34158,34159,22580,17198,21281,20003, +34160,15412,18484,16977,34161,15981,20534,34162,23137,34163,34164,34165,34166, +18276,34167,34168,13095,34169,13938,19580,16506,34170,34171,16503,34172,20793, +20833,22599,34173,34174,34176,34177,34178,34179,34180,12894,34181,34182,16485, +34183,14961,34184,34185,22600,34186,21549,34187,34188,20321,22601,34189,22602, +20291,34190,13176,15943,34191,34192,34193,34194,22603,34195,34196,34197,34198, +34199,34200,34201,23372,34202,34203,34204,34205,18469,34206,34207,34208,20312, +34209,18558,12878,34210,34211,34212,34213,34214,21334,12902,15408,21329,19243, +14132,34215,34216,34217,14114,34218,34219,19045,34220,18465,19036,12644,20592, +34221,17745,34222,34223,34224,23365,13694,34225,34226,16218,14661,15972,16749, +34227,24374,24373,22075,15696,21849,12360,13859,16201,19496,24371,18999,21330, +34228,22607,21046,14917,19262,19518,34229,24375,13680,24372,34230,34231,34232, +21365,34233,13140,14455,34234,24378,34235,14927,15402,13685,34236,19756,17275, +14963,16500,19778,20338,24376,20293,34237,16960,24377,17008,34238,34239,34240, +15997,34241,16735,19788,21111,14157,24385,34242,24388,34243,34244,14193,12361, +13910,14164,34245,14892,19581,16212,19249,18036,34246,22056,24389,34247,20066, +13107,34248,34249,20092,13365,34250,20039,14960,34251,20065,34252,20797,34253, +34254,24384,34255,34256,13428,34257,13130,34258,14438,24379,34259,34260,34261, +34262,17477,34263,24380,24381,24382,17723,24383,24386,21553,24387,34264,18234, +20056,34265,34266,34267,34268,34269,17496,34270,24394,34271,24399,34272,22108, +34273,34274,34275,34276,34277,34278,34279,34280,24393,24410,20022,34281,14919, +24398,24392,17758,34282,34283,18795,14964,17276,34284,34285,15959,34286,24390, +34287,24397,34288,17752,34289,34290,34291,34292,21798,14925,34293,15948,21309, +14400,34294,22116,34295,24391,14654,16167,34296,34297,16764,24395,24396,34298, +24400,34299,34300,34301,34302,34368,24411,24421,34369,24407,24406,22345,24419, +24420,25963,21031,24402,34370,16169,34371,21595,34372,16200,24404,34373,34374, +34375,20300,34376,34377,24413,34378,20810,34379,24414,12327,17975,24403,34380, +14949,34381,13919,19803,14718,21589,34382,34383,24415,20332,12325,24423,24401, +20806,24405,24408,24409,24412,34384,15145,34385,24416,24417,34386,24418,24422, +24424,21300,34387,34388,34389,34390,34391,14439,17718,24426,18778,16680,17476, +34392,34393,16222,20344,34394,34395,34396,21852,24430,34397,34398,34399,34400, +34401,34402,12856,34403,14943,24428,34404,23361,34405,20836,34406,34407,34408, +34409,19316,13373,34410,12326,34411,34412,34413,34414,34415,24433,19526,24434, +34416,34417,24429,34418,34419,34420,34421,34422,34423,24425,34424,34425,34426, +34427,24427,34428,24431,24432,15165,34429,34430,24435,34432,34433,24436,34434, +15139,34435,19035,20008,24615,13098,34436,24614,34437,34438,34439,24609,34440, +34441,34442,34443,24446,34444,19801,24444,34445,24442,34446,16208,22340,34447, +18764,34448,34449,24440,12321,34450,34451,34452,34453,34454,24445,34455,34456, +34457,34458,24443,24610,34459,34460,34461,34462,34463,24616,34464,34465,34466, +34467,14152,34468,34469,17953,18742,16434,24437,34470,34471,17726,34472,22596, +24441,17526,34473,34474,34475,34476,34477,34478,24611,24612,24613,20517,34479, +34480,24628,19556,34481,24625,34482,16166,24623,20025,24619,18758,34483,34484, +16430,24622,14957,14896,24617,34485,34486,34487,24438,34488,24627,34489,34490, +24632,34491,34492,34493,13357,24633,34494,34495,20274,14920,34496,24624,34497, +34498,34499,34500,34501,34502,34503,20602,34504,34505,34506,34507,34508,34509, +34510,34511,34512,24620,34513,21627,34514,24439,34515,17767,34516,24621,34517, +21367,34518,24630,24631,34519,34520,34521,34522,34523,24644,20577,34524,34525, +34526,24636,34527,34528,24649,24650,34529,34530,34531,24638,24618,18724,24641, +34532,24626,34533,34534,34535,34536,34537,19016,24643,34538,24629,34539,20043, +34540,19267,24653,24646,24642,34541,24651,34542,24634,24639,24640,34543,34544, +24645,34545,34546,24647,24648,34547,24652,34548,24635,34549,34550,34551,34552, +34553,19284,24661,34554,24662,24658,34555,34556,34557,34558,34624,34625,24656, +15438,34626,34627,24657,34628,14402,22597,34629,34630,34631,34632,34633,34634, +34635,34636,20586,34637,34638,17007,34639,34640,24655,24637,34641,34642,34643, +24660,24659,34644,34645,24663,34646,34647,34648,34649,24668,24664,34650,34651, +34652,22134,13104,34653,22380,34654,19259,34655,34656,24666,34657,20091,34658, +34659,34660,14937,34661,34662,34663,34664,34665,34666,34667,34668,34669,34670, +34671,34672,24673,24669,21037,34673,34674,34675,34676,34677,24674,34678,34679, +24667,24665,24671,34680,34681,24672,34682,34683,34684,34685,34686,24670,34688, +24676,34689,34690,34691,18039,22572,21611,24678,19017,34692,34693,34694,34695, +24677,34696,34697,34698,34699,14401,34700,34701,34702,34703,24679,24680,34704, +34705,34706,34707,34708,34709,34710,34711,24681,24675,34712,34713,34714,34715, +34716,34717,34718,14911,19559,34719,34720,34721,24682,34722,34723,34724,34725, +34726,34727,34728,34729,34730,34731,34732,34733,34734,34735,34736,20345,34737, +34738,34739,34740,34741,34742,34743,34744,34745,34746,34747,24683,34748,34749, +34750,34751,34752,34753,34754,18498,34755,34756,34757,34758,15680,34759,34760, +34761,34762,34763,34764,34765,34766,34767,34768,34769,34770,34771,17490,34772, +34773,34774,34775,34776,34777,34778,34779,34780,24684,34781,34782,24685,34783, +34784,18292,19268,34785,24686,15192,22582,21106,24687,19781,34786,13914,34787, +34788,34789,34790,34791,34792,24689,34793,21552,34794,34795,16423,13393,34796, +34797,20007,24688,34798,34799,34800,24690,14668,34801,34802,14714,19772,24691, +34803,34804,34805,18004,24692,34806,21554,34807,18470,24694,24693,34808,34809, +34810,34811,34812,34813,34814,34880,34881,34882,34883,34884,34885,34886,34887, +34888,34889,24695,34890,34891,19777,34892,34893,34894,18981,34895,34896,34897, +34898,21594,23383,23385,34899,23384,14695,23388,23389,13656,34900,34901,23386, +34902,34903,34904,34905,34906,23387,13089,23391,34907,34908,15224,34909,22071, +34910,23392,34911,34912,34913,34914,15993,34915,34916,14139,34917,23376,19502, +16178,15157,22392,16211,34918,34919,34920,34921,34922,16233,34923,34924,15457, +19507,23390,12371,20075,14168,22329,17986,34925,34926,16420,34927,19513,34928, +23399,23393,17978,23395,34929,23400,34930,17783,34931,34932,34933,23402,34934, +34935,23401,16192,34936,34937,34938,23398,23397,34939,34940,34941,34942,34944, +13369,16428,16930,23394,23396,34945,34946,34947,34948,20557,23405,34949,34950, +34951,34952,34953,16477,23410,34954,34955,34956,34957,34958,34959,34960,13922, +34961,34962,34963,34964,23411,23378,14648,21547,23404,34965,16209,23408,34966, +23377,34967,13670,34968,23403,16229,34969,34970,34971,23406,34972,23409,34973, +34974,34975,23417,34976,34977,34978,34979,34980,34981,34982,34983,34984,14625, +12323,34985,34986,34987,34988,34989,34990,34991,17009,34992,34993,13127,23407, +34994,34995,23416,34996,18002,23412,34997,34998,23413,23415,23414,34999,35000, +23422,35001,21362,12858,35002,35003,35004,23421,35005,35006,35007,35008,35009, +35010,35011,35012,23588,35013,23419,35014,35015,35016,35017,23418,35018,35019, +35020,23420,17760,15225,35021,35022,23587,35023,35024,23589,35025,19523,35026, +35027,35028,13905,23872,35029,35030,35031,23585,35032,23586,35033,35034,35035, +18229,35036,35037,35038,13929,35039,35040,35041,23591,35042,35043,35044,35045, +23590,35046,23593,12580,35047,35048,13644,35049,35050,35051,35052,35053,16176, +35054,35055,35056,35057,35058,20831,35059,35060,35061,35062,13890,35063,35064, +35065,35066,35067,35068,35069,35070,35136,35137,35138,35139,35140,35141,23592, +35142,35143,35144,35145,35146,35147,35148,19322,27507,35149,35150,35151,19292, +35152,35153,19326,35154,35155,35156,19521,35157,35158,35159,35160,35161,18555, +35162,35163,35164,35165,35166,35167,23594,35168,35169,35170,35171,35172,19566, +23595,35173,35174,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184, +35185,35186,35187,35188,35189,23379,35190,23599,23596,35191,15923,35192,19067, +35193,35194,35195,23597,35196,35197,35198,35200,35201,35202,35203,35204,18762, +17465,35205,35206,35207,35208,35209,18237,23598,35210,35211,35212,21622,20582, +35213,35214,35215,35216,35217,35218,35219,35220,17451,13909,35221,35222,35223, +35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,35234,35235,35236, +35237,35238,23380,35239,35240,35241,35242,12634,35243,35244,35245,23381,35246, +35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,23382,35257,35258, +35259,14910,35260,35261,35262,35263,35264,35265,35266,35267,35268,35269,35270, +35271,35272,35273,18496,35274,35275,35276,35277,35278,35279,19007,18505,35280, +22323,35281,18809,35282,35283,16199,35284,35285,14968,35286,35287,21052,35288, +35289,35290,35291,35292,35293,35294,35295,25146,35296,13350,35297,35298,12600, +35299,35300,35301,35302,35303,14388,35304,20292,35305,35306,35307,35308,22887, +20262,19810,35309,35310,22893,13920,35311,21049,35312,35313,14651,35314,35315, +35316,35317,25145,25143,35318,13427,35319,19564,19499,14194,35320,22578,20843, +14907,35321,18983,35322,35323,19767,35324,35325,21060,16228,15440,13921,35326, +24133,35392,35393,35394,35395,24134,23356,35396,20825,35397,35398,18022,17486, +14190,35399,14172,35400,35401,16252,22368,35402,18037,35403,35404,12604,24136, +15665,19543,24138,35405,24137,35406,35407,35408,35409,35410,13676,35411,18781, +35412,35413,12354,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423, +35424,35425,35426,17710,17707,35427,17484,35428,15465,19325,35429,35430,35431, +14915,35432,35433,35434,25977,18535,25978,19837,35435,22321,14398,17000,35436, +18513,35437,35438,25979,35439,35440,35441,35442,13898,15435,35443,35444,20861, +26145,35445,17262,35446,35447,35448,35449,26148,35450,35451,35452,35453,25982, +26149,19799,35454,35456,14145,25980,25981,26147,35457,35458,17501,26152,35459, +35460,26151,35461,35462,35463,35464,35465,35466,17219,35467,18014,35468,35469, +26154,35470,35471,35472,35473,35474,35475,35476,17463,35477,35478,35479,26146, +19004,35480,35481,35482,35483,15715,14659,26150,20565,20015,35484,35485,26153, +26160,35486,21030,35487,15658,26157,35488,35489,35490,35491,35492,26159,35493, +16465,35494,35495,21068,35496,35497,35498,15399,35499,35500,35501,35502,35503, +35504,35505,35506,35507,35508,35509,35510,26161,35511,21110,35512,35513,35514, +22347,35515,19838,35516,19806,16934,26155,26156,15679,26158,26163,35517,35518, +26162,35519,35520,35521,35522,26166,35523,26168,35524,35525,35526,35527,17519, +35528,35529,35530,17480,35531,35532,15978,18799,35533,35534,26167,35535,13936, +35536,35537,35538,17252,35539,35540,35541,35542,35543,35544,35545,21353,26164, +35546,26165,35547,18466,35548,35549,35550,35551,35552,26173,35553,35554,35555, +26169,35556,35557,35558,35559,35560,17989,35561,35562,19825,26171,35563,35564, +35565,35566,35567,35568,35569,35570,35571,35572,26172,35573,35574,35575,35576, +15209,35577,35578,35579,35580,35581,35582,35648,26174,35649,35650,35651,35652, +26170,35653,35654,16439,35655,35656,35657,35658,35659,35660,35661,35662,35663, +21284,26175,18804,26179,35664,35665,26180,35666,35667,35668,35669,20598,35670, +35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683, +35684,35685,35686,35687,17213,35688,35689,35690,35691,35692,35693,35694,17220, +26178,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706, +35707,35708,26177,35709,35710,35712,35713,35714,35715,35716,26183,20273,35717, +27508,35718,35719,26186,35720,35721,35722,35723,35724,26181,35725,35726,15454, +18729,35727,35728,35729,35730,35731,35732,15413,35733,35734,20307,35735,35736, +35737,35738,35739,26184,35740,26185,35741,26190,35742,26192,35743,35744,35745, +26193,35746,35747,35748,26187,13653,35749,26188,35750,35751,26191,35752,35753, +17499,35754,26182,35755,35756,35757,35758,35759,26189,35760,35761,35762,35763, +35764,35765,35766,35767,35768,35769,35770,35771,35772,35773,35774,35775,35776, +35777,35778,35779,35780,35781,35782,26194,35783,35784,35785,35786,35787,35788, +35789,35790,35791,35792,35793,35794,26196,26195,35795,35796,35797,35798,35799, +35800,35801,35802,35803,35804,35805,35806,35807,35808,35809,35810,35811,35812, +35813,35814,35815,35816,35817,35818,35819,35820,26197,35821,22904,35822,35823, +26198,35824,35825,35826,35827,35828,35829,35830,35831,26199,35832,35833,35834, +35835,35836,35837,35838,35904,35905,35906,35907,35908,35909,35910,35911,22355, +26205,35912,26206,16215,21584,35913,22358,13414,19311,26202,22595,22350,20514, +35914,17231,35915,35916,26207,15422,14658,26203,20775,35917,35918,14882,16975, +35919,22571,35920,35921,35922,19051,25966,35923,26204,35924,14197,35925,35926, +35927,35928,18534,35929,35930,17525,35931,35932,25906,17534,35933,19324,25907, +21804,35934,21358,19032,12338,35935,19278,19818,35936,35937,14954,35938,35939, +35940,25909,35941,25908,35942,22362,14681,22118,13864,19824,21067,12582,18997, +35943,13160,18803,16205,20603,19026,25910,15170,35944,35945,35946,20316,14636, +35947,35948,35949,35950,21591,35951,35952,14886,20839,20348,15442,35953,25911, +18525,35954,35955,35956,16237,12662,19294,35957,35958,15429,35959,15428,21114, +17244,16220,35960,35961,35962,35963,14395,35964,35965,35966,17218,35968,14894, +21538,35969,35970,35971,35972,35973,35974,35975,35976,35977,18270,17455,12908, +35978,14673,35979,35980,25915,16712,35981,35982,21807,35983,35984,35985,35986, +35987,25916,35988,25918,35989,35990,35991,35992,35993,35994,35995,13415,13908, +19266,20784,13628,35996,35997,19033,35998,14178,35999,36000,18788,36001,15659, +36002,36003,20030,22384,36004,36005,36006,36007,20513,36008,18777,36009,36010, +13947,26200,15458,36011,13118,36012,18768,36013,26201,13090,36014,36015,36016, +36017,24140,36018,21320,24141,36019,21026,36020,36021,36022,36023,24142,36024, +36025,36026,36027,15949,36028,36029,24143,36030,36031,36032,18988,21116,13151, +25962,17505,15905,20018,17522,15958,17960,12899,36033,36034,15955,36035,36036, +18300,19563,15724,20061,36037,36038,19002,17985,25964,20540,36039,36040,36041, +21817,36042,36043,36044,25965,36045,36046,36047,36048,19060,36049,19776,16965, +36050,25967,36051,16964,25968,36052,36053,36054,36055,36056,36057,36058,25976, +19789,36059,18749,36060,36061,36062,36063,36064,36065,36066,21081,24872,36067, +36068,36069,36070,21356,36071,19306,18033,36072,36073,36074,36075,36076,24876, +36077,36078,36079,24871,24873,36080,36081,24874,24879,36082,36083,12909,36084, +24875,14426,24877,24878,24880,13626,24881,36085,36086,36087,36088,36089,24883, +24888,36090,36091,36092,36093,36094,20818,36160,24886,24885,16747,36161,36162, +36163,24887,36164,21568,36165,24882,36166,24890,12342,36167,36168,36169,36170, +24884,36171,16249,36172,24889,36173,36174,24891,36175,36176,36177,36178,36179, +36180,24894,36181,36182,36183,36184,36185,36186,24892,36187,36188,36189,36190, +36191,36192,22085,36193,36194,36195,36196,36197,36198,36199,20287,36200,36201, +24893,24895,16973,36202,13931,36203,21368,36204,36205,18253,36206,36207,14181, +36208,36209,36210,36211,36212,36213,36214,36215,36216,36217,15998,36218,36219, +36220,36221,36222,36224,24896,24897,36225,36226,24903,13159,36227,36228,36229, +36230,36231,36232,18025,36233,36234,36235,36236,36237,13406,36238,20802,36239, +36240,36241,36242,24904,36243,36244,24902,36245,36246,36247,36248,36249,24901, +36250,24899,24898,36251,12608,36252,36253,36254,21816,24900,36255,36256,36257, +36258,36259,24907,36260,36261,36262,36263,36264,36265,36266,36267,24908,24906, +36268,36269,36270,36271,36272,36273,36274,36275,28538,36276,36277,24915,24914, +18230,36278,36279,36280,36281,36282,36283,36284,36285,36286,36287,36288,24905, +36289,36290,24910,36291,24912,36292,36293,36294,36295,36296,36297,36298,36299, +36300,36301,36302,24916,36303,24913,24909,36304,36305,24911,36306,36307,36308, +36309,24917,36310,36311,36312,36313,36314,36315,36316,36317,36318,36319,36320, +36321,36322,24918,36323,36324,36325,36326,36327,36328,36329,36330,36331,36332, +36333,36334,36335,36336,36337,36338,36339,36340,36341,36342,36343,36344,24919, +36345,36346,36347,24920,36348,36349,36350,36416,36417,36418,36419,36420,36421, +36422,36423,36424,36425,36426,36427,36428,36429,36430,36431,36432,36433,36434, +36435,36436,36437,24922,36438,36439,36440,36441,36442,36443,36444,36445,36446, +36447,36448,36449,36450,24923,36451,36452,36453,36454,36455,36456,36457,20001, +36458,36459,36460,36461,36462,36463,36464,36465,36466,36467,36468,36469,36470, +26461,36471,13352,22109,36472,36473,20786,13106,36474,36475,14628,22387,18249, +15966,14638,36476,20055,36477,36478,12910,23375,36480,15418,21073,19272,12365, +36481,36482,20335,36483,36484,36485,36486,36487,22883,15725,36488,36489,12626, +19024,12860,36490,19239,14123,36491,18982,36492,36493,36494,20259,36495,36496, +24696,21834,24699,36497,36498,24698,17729,19579,36499,16689,24697,22115,12847, +22084,13659,36500,36501,36502,36503,36504,36505,36506,36507,13432,22049,36508, +36509,36510,36511,36512,20271,12399,36513,36514,24700,36515,36516,36517,36518, +36519,24865,13091,36520,36521,24701,24702,17201,36522,36523,36524,36525,17245, +36526,24866,14201,36527,36528,36529,36530,36531,36532,15183,36533,36534,36535, +36536,36537,36538,36539,24867,17467,36540,36541,36542,36543,36544,24868,36545, +36546,24869,36547,36548,24870,13361,36549,36550,36551,36552,36553,36554,36555, +36556,36557,36558,36559,36560,36561,36562,36563,14409,17981,17514,36564,12834, +36565,20562,36566,26459,15171,21335,21316,36567,14691,25167,36568,36569,36570, +22319,36571,18284,12627,36572,36573,13362,25169,36574,36575,36576,20594,16942, +25168,36577,16226,21286,13655,25170,13674,36578,17261,14461,36579,14382,36580, +17747,14159,25172,36581,36582,36583,36584,25171,13896,22393,36585,36586,36587, +36588,36589,19749,36590,36591,36592,36593,36594,25176,36595,25174,19068,16181, +21305,25173,36596,36597,36598,36599,25175,36600,36601,36602,36603,36604,36605, +36606,36672,36673,36674,16686,16456,36675,36676,36677,36678,36679,36680,25179, +25178,16426,36681,36682,16718,36683,36684,36685,36686,25180,36687,36688,36689, +36690,36691,36692,36693,36694,36695,36696,36697,36698,25181,36699,25182,36700, +36701,36702,36703,36704,36705,36706,36707,36708,23368,36709,20819,19746,36710, +36711,15656,36712,36713,36714,24131,22565,16170,23373,21100,18042,17706,36715, +36716,36717,24132,36718,12631,24366,36719,36720,36721,19005,36722,24369,36723, +14637,36724,21117,36725,14373,14955,36726,36727,13146,36728,36729,36730,13660, +21829,36731,36732,36733,36734,17238,20306,15137,36736,25971,25970,36737,36738, +25972,36739,19812,36740,18549,36741,36742,36743,36744,36745,36746,36747,13615, +18239,36748,25974,36749,36750,36751,27696,36752,36753,36754,36755,36756,36757, +36758,36759,36760,36761,36762,36763,36764,36765,36766,25958,36767,14697,13617, +36768,16956,25960,25959,25961,36769,36770,36771,36772,21069,36773,36774,36775, +24938,20558,36776,19758,36777,20837,36778,36779,12874,12651,36780,12658,17773, +36781,36782,21827,21296,36783,24924,36784,36785,36786,24925,36787,21083,36788, +13113,12619,36789,36790,36791,19833,21879,24926,36792,15926,13437,36793,24927, +14940,24928,15154,16969,24929,36794,36795,36796,20588,36797,19773,36798,36799, +24930,36800,13635,17735,24931,36801,36802,24932,36803,36804,36805,36806,21369, +36807,36808,36809,36810,36811,36812,24933,36813,20781,36814,36815,24934,20002, +36816,36817,36818,36819,36820,36821,24935,36822,13634,36823,36824,36825,36826, +24936,15189,36827,36828,36829,36830,36831,20548,25184,12632,21092,36832,36833, +25185,36834,36835,15433,18508,36836,25187,27774,27773,24367,36837,36838,36839, +25186,22078,19836,17190,36840,36841,36842,25411,36843,36844,22098,25191,36845, +36846,25192,36847,36848,21319,36849,36850,25196,16236,36851,25197,25189,36852, +36853,13120,36854,36855,36856,17518,36857,36858,25198,36859,36860,20547,36861, +14966,25193,14174,15155,19500,19275,25188,25190,25194,25195,36862,36928,36929, +25207,36930,36931,25204,21621,25203,36932,36933,17709,36934,21882,17730,12864, +36935,36936,25199,36937,25202,16687,19260,36938,36939,13601,25209,36940,36941, +36942,15409,25201,20564,21561,25205,14678,25206,36943,36944,36945,18259,36946, +36947,36948,36949,36950,25200,36951,36952,36953,36954,36955,22364,27937,36956, +36957,25208,36958,27941,25214,19025,36959,36960,36961,36962,36963,36964,36965, +16693,36966,15184,36967,36968,16214,36969,14947,36970,36971,19233,36972,36973, +36974,27942,27939,36975,36976,27938,36977,36978,36979,36980,15190,27943,20596, +36981,36982,27940,14942,13943,25377,13874,19569,14631,36983,20258,18209,36984, +36985,16210,36986,36987,13937,36988,25210,25211,25213,25212,17493,25378,36989, +21313,36990,36992,36993,25383,18244,36994,36995,36996,36997,20260,36998,36999, +25385,14903,37000,37001,37002,37003,25384,37004,15194,37005,25379,37006,37007, +37008,25380,25386,37009,25382,37010,20082,21318,37011,37012,15164,37013,37014, +21571,37015,17530,37016,37017,27944,20604,25381,37018,17269,37019,25389,12591, +37020,25394,37021,37022,37023,15426,37024,37025,25388,13631,37026,37027,37028, +37029,37030,37031,37032,37033,18281,25392,37034,37035,37036,15914,19823,37037, +37038,37039,37040,37041,15219,37042,37043,37044,19560,37045,37046,25391,37047, +25393,37048,20263,25390,37049,20009,15197,37050,37051,37052,37053,37054,13675, +15973,12882,13133,37055,12601,25387,12881,13612,14687,13928,37056,37057,20331, +25399,37058,15180,37059,37060,18503,20554,37061,37062,37063,37064,37065,25400, +13166,37066,37067,37068,37069,27945,37070,21370,21348,37071,37072,37073,27946, +25401,21090,37074,37075,37076,37077,37078,25397,37079,37080,37081,37082,21342, +37083,37084,37085,37086,14416,25395,37087,37088,25398,14175,37089,25396,16418, +37090,37091,37092,25402,37093,37094,37095,37096,37097,37098,37099,37100,37101, +37102,37103,37104,37105,37106,37107,37108,37109,37110,37111,21560,37112,37113, +37114,37115,37116,37117,37118,37184,13384,37185,25403,37186,15173,37187,18807, +37188,37189,18789,37190,37191,37192,17469,37193,37194,37195,37196,37197,37198, +37199,27947,37200,37201,37202,37203,17021,37204,37205,37206,37207,15195,16174, +37208,37209,37210,37211,37212,37213,37214,20031,37215,37216,37217,37218,25404, +37219,16182,37220,37221,37222,37223,37224,37225,37226,37227,37228,37229,37230, +37231,37232,37233,37234,37235,37236,37237,37238,12655,37239,37240,21623,37241, +37242,37243,37244,37245,25406,37246,37248,37249,37250,37251,37252,37253,37254, +27949,37255,37256,37257,37258,37259,37260,37261,37262,37263,25407,14889,27948, +37264,37265,25405,37266,37267,37268,37269,37270,37271,37272,37273,37274,37275, +25408,37276,37277,37278,37279,37280,37281,14902,37282,37283,37284,13870,37285, +37286,37287,37288,37289,20536,37290,12355,27950,37291,37292,37293,37294,37295, +27951,16449,37296,25409,37297,37298,37299,37300,37301,37302,37303,37304,37305, +37306,37307,37308,37309,37310,37311,37312,37313,17715,37314,37315,37316,37317, +37318,37319,37320,37321,37322,37323,37324,37325,37326,37327,25410,37328,37329, +37330,37331,37332,37333,37334,37335,37336,23602,37337,37338,37339,37340,37341, +37342,27952,37343,14442,37344,20076,27175,20583,19065,18518,20279,13129,20050, +15716,37345,37346,25438,15218,27176,21821,37347,18013,27177,37348,37349,37350, +27178,37351,27180,27179,37352,27182,27181,37353,37354,37355,37356,15704,37357, +27183,37358,16958,37359,37360,37361,37362,13377,13431,37363,37364,15143,37365, +37366,37367,37368,37369,27750,27749,14143,19321,12642,37370,27751,37371,37372, +37373,18760,27752,27753,37374,19030,24144,12869,21626,37440,37441,17995,12359, +13426,18515,37442,37443,37444,19792,37445,37446,16184,37447,37448,37449,37450, +37451,37452,37453,16219,37454,37455,18212,22068,37456,16425,24145,18728,20847, +17700,12391,13110,18501,37457,37458,12386,37459,37460,14198,37461,37462,17786, +37463,37464,13939,37465,21842,13136,15420,37466,37467,37468,13101,37469,37470, +37471,37472,15985,12369,37473,37474,37475,37476,37477,37478,21078,19043,22309, +37479,19766,13878,16185,21851,37480,14375,17751,37481,37482,37483,24146,16217, +16981,18240,37484,15140,12584,37485,37486,17770,37487,37488,17787,19495,37489, +37490,37491,37492,12583,37493,37494,37495,13654,37496,37497,37498,17448,37499, +24147,20794,13161,37500,17266,37501,37502,14199,37504,22132,13603,12912,17460, +17513,16429,24148,37505,12392,17732,16736,37506,14677,37507,15964,19800,12366, +37508,19791,24150,15952,22334,24149,21840,12381,37509,37510,17506,37511,37512, +16931,15472,37513,21301,16441,17697,12838,21617,37514,37515,16424,19011,24151, +21884,37516,14640,37517,18477,19241,37518,24153,16189,37519,37520,37521,37522, +17972,22311,18992,17475,37523,13142,14674,37524,37525,37526,37527,22072,27260, +12340,37528,37529,37530,37531,16230,37532,37533,19572,37534,37535,37536,37537, +19802,37538,37539,37540,22079,16974,37541,20046,19490,20526,17491,13618,24152, +21877,15415,15187,37542,37543,12324,37544,17714,13420,37545,37546,37547,21873, +37548,37549,27261,37550,37551,37552,37553,37554,37555,24154,19750,37556,37557, +19820,37558,37559,37560,37561,20070,24156,37562,19761,16422,37563,37564,22333, +37565,24155,12358,14900,18771,17523,15976,37566,37567,37568,37569,12854,37570, +37571,37572,37573,37574,37575,37576,37577,16460,19312,37578,15473,15163,13623, +37579,37580,37581,17781,37582,24166,37583,37584,37585,24163,15965,37586,37587, +24159,37588,37589,37590,37591,13367,15709,37592,37593,24160,17517,37594,37595, +37596,37597,20294,37598,13664,37599,37600,37601,37602,13918,19034,13684,24165, +37603,21830,37604,24161,19533,18046,37605,17733,37606,37607,37608,21044,37609, +15986,37610,37611,37612,37613,37614,37615,37616,16979,37617,19517,13112,37618, +15699,37619,16216,19782,20826,13419,37620,24164,24157,24167,37621,27262,37622, +37623,16944,24162,37624,37625,22080,13607,37626,12916,37627,24168,37628,24178, +37629,37630,37696,37697,37698,24173,37699,24177,37700,37701,18528,37702,37703, +37704,22369,24175,17256,19553,37705,12901,37706,37707,37708,21054,37709,37710, +37711,37712,37713,37714,37715,24174,37716,24171,20053,37717,13351,37718,37719, +37720,37721,37722,16171,15934,37723,37724,15698,37725,37726,37727,37728,24169, +37729,21550,37730,24158,37731,24170,37732,37733,37734,37735,16447,37736,24172, +12915,14441,16935,37737,37738,15681,37739,37740,37741,37742,37743,24181,24184, +37744,37745,12843,13348,37746,37747,13418,18726,37748,37749,37750,37751,37752, +37753,24182,19281,37754,14435,37755,24183,24186,37756,37757,37758,37760,24185, +37761,37762,37763,19522,37764,12385,13422,37765,37766,37767,37768,37769,37770, +25914,37771,37772,37773,37774,37775,20527,37776,37777,12907,37778,27425,37779, +24180,37780,37781,18787,24179,12378,21025,12663,37782,19503,37783,37784,37785, +37786,37787,37788,37789,24176,37790,19236,37791,37792,37793,21802,37794,37795, +37796,37797,37798,24187,37799,37800,37801,37802,37803,37804,37805,37806,13405, +37807,17446,37808,37809,37810,24189,37811,37812,37813,37814,37815,37816,37817, +37818,37819,37820,17278,17441,24353,37821,37822,37823,37824,37825,37826,37827, +16716,37828,24188,15983,37829,17970,37830,37831,37832,37833,37834,37835,37836, +37837,37838,13125,18550,37839,37840,19258,24190,37841,37842,24356,37843,37844, +37845,37846,22322,37847,37848,37849,37850,37851,13111,37852,37853,37854,37855, +16707,37856,37857,18251,12837,13417,37858,22315,37859,37860,37861,37862,17516, +37863,24354,24355,37864,24357,37865,14899,37866,37867,37868,24358,37869,16478, +37870,37871,18755,37872,37873,37874,37875,37876,37877,37878,12889,18278,37879, +24359,37880,18268,37881,37882,37883,37884,24360,27426,37885,37886,37952,37953, +37954,19283,37955,37956,37957,24362,37958,24361,37959,12865,37960,37961,37962, +37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975, +37976,37977,37978,37979,37980,37981,37982,37983,37984,17738,37985,37986,37987, +37988,37989,37990,37991,37992,24363,37993,37994,37995,37996,37997,37998,37999, +38000,21596,38001,38002,38003,38004,38005,18497,38006,38007,38008,38009,38010, +38011,38012,38013,38014,38016,38017,38018,24364,38019,38020,38021,38022,38023, +15984,38024,38025,24365,22055,38026,38027,38028,38029,27191,27446,19029,38030, +22652,14404,38031,14629,38032,38033,14149,21886,38034,38035,38036,38037,38038, +14666,38039,38040,20519,29773,38041,38042,13648,38043,38044,17268,38045,15944, +38046,38047,38048,27447,12349,38049,38050,15692,38051,16690,38052,12630,13096, +38053,38054,38055,14418,18722,38056,38057,13912,38058,38059,38060,38061,27448, +15924,38062,38063,38064,19069,38065,18243,38066,21883,38067,38068,14195,38069, +38070,38071,38072,38073,38074,38075,38076,38077,38078,38079,38080,38081,38082, +38083,20036,38084,38085,38086,21803,12659,38087,38088,38089,27699,12383,38090, +27701,38091,38092,38093,13879,38094,16719,38095,30074,20529,38096,38097,21861, +38098,20051,38099,38100,15727,13154,38101,14379,38102,21814,38103,27965,38104, +13903,38105,19257,20546,38106,38107,38108,38109,38110,38111,38112,38113,14141, +38114,38115,27702,18985,38116,38117,38118,17748,38119,27705,27704,16963,27703, +38120,38121,38122,38123,20605,27706,38124,27707,22373,38125,38126,27708,38127, +38128,38129,27709,18028,38130,38131,38132,38133,38134,38135,38136,38137,20062, +38138,15432,38139,38140,18517,13609,15945,22076,21607,38141,38142,20782,20593, +27192,27193,27194,14901,38208,38209,38210,38211,18993,16245,38212,38213,19834, +38214,38215,38216,38217,38218,27200,38219,12346,27198,38220,38221,16421,38222, +38223,38224,27195,38225,12925,38226,17271,15208,38227,38228,38229,21079,20084, +27199,38230,38231,38232,27196,38233,38234,38235,27203,38236,20551,21299,38237, +38238,38239,38240,13370,38241,17217,22386,38242,38243,38244,38245,21841,38246, +19015,38247,27205,38248,38249,27204,27207,27206,38250,38251,38252,38253,38254, +22119,38255,20308,38256,38257,27211,38258,15182,38259,38260,38261,38262,38263, +38264,38265,15738,18766,38266,38267,27212,38268,38269,18745,20350,27210,21582, +27213,27215,38270,38272,19821,38273,38274,38275,38276,27209,38277,27214,38278, +38279,20078,38280,15198,38281,13119,38282,38283,38284,38285,38286,18005,15920, +20090,38287,38288,38289,18279,38290,15911,27216,38291,38292,22087,38293,38294, +38295,16704,38296,38297,38298,21597,38299,27217,38300,38301,20286,38302,38303, +38304,38305,27218,38306,38307,38308,38309,19054,38310,38311,38312,38313,17711, +12341,38314,38315,38316,38317,38318,27220,38319,38320,38321,38322,38323,38324, +38325,38326,38327,27219,29791,38328,38329,38330,38331,38332,17466,38333,38334, +38335,38336,38337,12585,38338,38339,38340,38341,25951,38342,38343,38344,38345, +27221,38346,38347,38348,38349,38350,38351,38352,38353,38354,38355,38356,38357, +38358,38359,38360,38361,38362,38363,38364,38365,38366,38367,38368,38369,38370, +38371,19055,38372,27222,27223,18008,38373,38374,38375,38376,38377,38378,38379, +38380,27224,38381,38382,27225,38383,38384,38385,38386,38387,38388,21563,38389, +18298,21047,14460,38390,38391,27202,38392,12892,38393,38394,17020,38395,21624, +19558,22382,38396,38397,38398,38464,38465,38466,38467,21570,21328,27459,17779, +38468,14206,38469,38470,27476,38471,38472,38473,19255,27486,38474,16458,38475, +38476,38477,19835,38478,13103,38479,18010,38480,38481,38482,38483,38484,38485, +27516,38486,17470,38487,20020,17449,12606,21629,38488,19061,38489,22124,38490, +38491,18003,13924,38492,38493,38494,38495,15226,38496,38497,20576,38498,38499, +18737,38500,21587,18472,38501,38502,14411,38503,26686,18748,38504,38505,26683, +38506,16494,20563,12868,13413,38507,26684,38508,38509,21832,38510,38511,38512, +38513,38514,13893,38515,26685,19064,14428,19573,38516,38517,38518,16436,38519, +38520,20846,26687,26690,38521,38522,14908,38523,12589,15708,38524,27197,26691, +38525,26694,38526,26699,38528,38529,38530,38531,26700,38532,19273,12389,38533, +15403,38534,38535,14649,38536,38537,26689,38538,19831,38539,26698,38540,38541, +38542,38543,20086,38544,38545,38546,38547,21869,38548,16726,26692,38549,17206, +38550,14715,22054,26696,38551,38552,38553,19040,21606,38554,26688,38555,26693, +26695,38556,18233,14179,38557,26697,38558,16221,26706,38559,38560,26711,38561, +26709,15452,15439,26715,38562,38563,38564,38565,38566,38567,38568,38569,26718, +38570,26714,12666,38571,38572,38573,38574,38575,38576,38577,38578,38579,38580, +12376,17459,14412,18018,18494,18529,38581,38582,38583,26703,26708,26710,38584, +14705,26712,22389,38585,17531,38586,26716,38587,38588,12905,38589,38590,38591, +26705,38592,38593,15469,38594,38595,16194,26701,22137,38596,16760,12913,38597, +38598,38599,38600,38601,38602,38603,38604,26719,38605,19009,26713,38606,38607, +38608,38609,21796,38610,12650,21819,26702,26704,13872,26707,38611,26717,16440, +38612,19063,38613,19240,38614,38615,18012,16501,38616,38617,38618,38619,38620, +26729,38621,38622,38623,20515,38624,38625,38626,38627,38628,38629,38630,26738, +22122,38631,38632,38633,38634,38635,38636,38637,26720,26721,38638,38639,38640, +20857,14923,14457,38641,38642,14449,21588,26735,38643,26734,26732,14704,19538, +26726,20006,16242,38644,12344,26737,26736,38645,22336,38646,26724,38647,19753, +18723,38648,15160,15707,26730,38649,38650,38651,38652,38653,38654,38720,38721, +38722,38723,26722,26723,26725,13621,26727,18245,26731,26733,15664,22318,38724, +26744,38725,38726,38727,38728,38729,38730,38731,38732,26741,38733,19760,26742, +38734,38735,38736,38737,38738,38739,38740,38741,38742,16698,38743,26728,38744, +17207,12400,38745,38746,38747,38748,38749,38750,38751,38752,26740,38753,38754, +38755,26743,38756,38757,38758,14627,38759,38760,38761,38762,38763,38764,38765, +38766,38767,38768,18770,38769,38770,38771,17230,20064,16486,38772,38773,38774, +38775,19315,38776,19549,20533,38777,38778,19041,38779,26739,38780,38781,38782, +38784,38785,38786,38787,38788,38789,38790,15468,38791,26745,38792,38793,38794, +38795,38796,38797,17246,38798,18021,38799,14711,38800,38801,38802,38803,12404, +38804,38805,22360,38806,38807,15404,38808,17775,38809,38810,38811,38812,38813, +19524,38814,38815,26918,38816,38817,38818,38819,38820,38821,38822,38823,38824, +38825,18733,38826,26914,16482,38827,38828,38829,16195,38830,38831,38832,26750, +14679,38833,26747,38834,38835,38836,38837,26916,38838,38839,38840,21070,38841, +38842,38843,38844,38845,26915,38846,22066,22325,38847,26919,38848,15671,38849, +38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,26748,26749, +38861,38862,38863,26913,38864,38865,38866,38867,38868,38869,38870,38871,19798, +38872,38873,21036,38874,38875,38876,26930,38877,38878,38879,38880,26921,38881, +38882,38883,13354,38884,13371,38885,38886,26923,38887,38888,38889,38890,38891, +38892,38893,38894,38895,38896,38897,38898,38899,38900,38901,38902,38903,20520, +38904,38905,26917,38906,38907,13182,38908,38909,26924,16483,38910,26922,38976, +38977,26937,38978,38979,26936,38980,38981,38982,38983,26926,38984,38985,26746, +38986,38987,26920,38988,38989,38990,38991,38992,16172,26929,26938,38993,38994, +16933,38995,38996,38997,26927,38998,14405,38999,26925,39000,21340,26932,26933, +26935,39001,39002,39003,26951,39004,39005,39006,39007,39008,39009,16454,26949, +39010,39011,26928,39012,39013,26939,12401,39014,39015,39016,39017,39018,39019, +39020,39021,39022,39023,26940,21797,39024,39025,26942,39026,26943,39027,39028, +39029,26945,39030,39031,16753,39032,39033,18486,39034,39035,39036,26941,39037, +39038,39040,39041,39042,26946,39043,39044,39045,39046,39047,39048,39049,39050, +26947,39051,26931,39052,26934,39053,15153,39054,39055,39056,26944,39057,39058, +39059,39060,39061,39062,15479,39063,39064,39065,26948,26950,39066,39067,39068, +39069,39070,39071,39072,39073,39074,39075,39076,39077,26954,39078,39079,39080, +39081,26958,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091,12891, +39092,26952,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,14126, +39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,26955, +26956,39115,39116,39117,39118,39119,39120,21825,39121,17443,39122,39123,39124, +39125,39126,39127,26968,39128,14945,39129,39130,39131,39132,26953,39133,21283, +39134,39135,39136,26964,39137,39138,39139,39140,39141,39142,39143,26967,26960, +39144,39145,39146,39147,39148,26959,39149,39150,18241,39151,39152,39153,39154, +39155,39156,39157,39158,26962,39159,39160,39161,39162,39163,39164,39165,26969, +13128,39166,26963,39232,39233,39234,39235,39236,20336,39237,39238,39239,26957, +39240,39241,39242,39243,39244,39245,39246,39247,39248,39249,39250,13175,39251, +39252,39253,39254,39255,39256,39257,26966,39258,39259,26970,39260,39261,39262, +19508,39263,39264,39265,20269,39266,39267,39268,39269,39270,39271,39272,39273, +39274,26965,39275,26972,26971,39276,39277,39278,39279,39280,26974,39281,39282, +39283,39284,39285,39286,39287,39288,26961,39289,39290,39291,39292,39293,39294, +39296,39297,26973,39298,26975,17226,39299,39300,39301,39302,39303,39304,39305, +39306,39307,39308,39309,39310,39311,39312,39313,39314,39315,39316,39317,39318, +39319,39320,39321,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331, +39332,39333,39334,39335,39336,39337,39338,39339,39340,39341,39342,39343,39344, +39345,39346,39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357, +39358,39359,39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370, +39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383, +39384,39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396, +39397,39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409, +39410,39411,39412,39413,18231,13390,15158,20544,27683,39414,39415,17719,39416, +39417,39418,39419,39420,39421,39422,39488,39489,39490,21371,39491,39492,39493, +39494,27684,39495,27685,18011,39496,39497,39498,16238,39499,39500,39501,39502, +27686,39503,39504,27687,20522,39505,18232,39506,39507,14440,39508,39509,39510, +39511,39512,39513,39514,39515,39516,39517,39518,39519,27688,39520,39521,39522, +39523,39524,39525,39526,39527,22073,21885,13387,12861,20068,18023,39528,39529, +19809,39530,39531,39532,39533,39534,39535,39536,39537,39538,39539,39540,39541, +39542,39543,13429,39544,19264,15455,39545,39546,39547,39548,26978,26979,20842, +26981,39549,13433,26980,39550,20787,19042,12880,39552,26984,39553,39554,39555, +39556,26982,26983,39557,39558,22067,39559,39560,39561,26985,26986,39562,39563, +39564,39565,39566,26987,39567,39568,39569,39570,39571,39572,39573,39574,26988, +39575,39576,39577,39578,39579,39580,39581,39582,27695,17721,13902,39583,21107, +39584,39585,39586,39587,39588,39589,39590,13678,39591,15193,27697,39592,39593, +21091,39594,39595,39596,39597,39598,20067,39599,17464,39600,17215,39601,39602, +13886,22585,12616,12623,12625,17790,39603,12624,39604,17195,39605,39606,39607, +39608,39609,21809,39610,39611,39612,39613,39614,39615,39616,39617,27428,14913, +39618,39619,39620,19514,39621,39622,39623,27429,39624,27431,39625,39626,39627, +27432,39628,39629,39630,27430,39631,39632,39633,39634,39635,39636,39637,27433, +27435,27434,39638,39639,39640,39641,39642,27436,39643,19023,22581,17265,39644, +17189,18040,27437,17482,39645,27438,27439,27440,14165,39646,39647,39648,14202, +39649,27441,18274,39650,27443,39651,14884,20853,12337,27442,27444,39652,39653, +39654,13610,16968,18280,39655,27445,39656,19246,25439,39657,39658,21312,39659, +39660,39661,39662,22875,39663,39664,19745,22061,18291,39665,39666,39667,22880, +15203,39668,14906,25442,39669,39670,39671,39672,39673,20267,39674,39675,39676, +25440,18759,39677,14905,39678,39744,39745,20788,25441,18538,14639,15661,13144, +20059,39746,39747,19520,39748,39749,39750,25448,25449,19828,39751,39752,39753, +39754,39755,19501,39756,15411,39757,25450,39758,25451,39759,39760,20570,39761, +39762,39763,18043,14170,39764,39765,18271,21066,20054,39766,25444,25452,39767, +18802,13121,39768,39769,25447,39770,39771,18019,25445,39772,39773,27955,25446, +39774,39775,39776,39777,18739,39778,17766,39779,39780,39781,14645,39782,17211, +39783,25443,17725,16676,16985,12887,39784,25453,15142,17453,39785,25456,15962, +39786,39787,25467,25461,14931,39788,39789,39790,39791,14160,21325,39792,22094, +21843,14657,21812,20824,39793,39794,39795,39796,20537,18294,39797,39798,39799, +18474,12852,39800,17242,39801,39802,39803,25454,39804,39805,25468,25455,14120, +25463,25460,39806,39808,39809,14138,39810,39811,17698,39812,25462,17757,12840, +18044,39813,17504,39814,39815,22306,39816,16481,25465,39817,39818,25466,25469, +19497,25459,39819,21310,39820,12611,27956,25457,25458,39821,25464,20538,17987, +21619,25470,39822,39823,15712,39824,39825,25639,39826,39827,25638,39828,39829, +39830,20851,25635,39831,25641,39832,39833,39834,18551,39835,39836,39837,39838, +20276,39839,25640,25646,16997,39840,39841,13876,39842,39843,39844,39845,39846, +39847,15730,39848,25634,39849,39850,14953,25642,39851,39852,25644,39853,39854, +13949,22110,25650,39855,25645,39856,39857,39858,25633,39859,15214,19805,18210, +17737,39860,39861,16759,39862,25636,39863,18227,15660,15677,25637,39864,22343, +12898,39865,25643,15427,25647,39866,15211,25648,17704,25649,39867,39868,39869, +39870,21859,16163,39871,25658,39872,25655,39873,25659,39874,39875,25661,39876, +39877,18006,39878,39879,14918,16459,39880,39881,39882,14369,25652,39883,39884, +39885,39886,21537,39887,39888,14883,15742,39889,39890,39891,25660,39892,39893, +39894,39895,39896,19775,39897,39898,17529,39899,39900,20347,18790,39901,39902, +21311,39903,20305,39904,39905,25651,39906,25656,25657,19561,39907,39908,39909, +39910,39911,19534,39912,16468,25653,16688,25654,20048,39913,15169,13651,39914, +18547,15655,21831,18732,14370,25674,39915,39916,25676,20804,39917,39918,21050, +39919,39920,14893,39921,39922,14932,39923,39924,39925,39926,39927,39928,25667, +13677,39929,39930,39931,22349,25664,20349,25663,39932,39933,39934,16732,19530, +40000,40001,40002,40003,19047,40004,40005,40006,40007,17495,40008,19540,25672, +40009,40010,40011,25671,25665,40012,25668,13613,40013,40014,21337,40015,25670, +40016,40017,40018,40019,21113,13411,40020,15156,40021,40022,18798,40023,13374, +40024,40025,40026,15212,40027,20813,40028,19565,27957,40029,40030,40031,40032, +40033,40034,40035,40036,18277,40037,40038,40039,40040,21544,40041,25675,22357, +25666,40042,15653,25669,40043,40044,21350,40045,25673,18808,40046,40047,25662, +40048,40049,21349,40050,40051,18302,13897,40052,21628,12851,25687,40053,40054, +40055,20034,40056,25677,40057,20028,40058,14427,40059,40060,25686,40061,16202, +40062,40064,40065,21326,40066,17260,40067,40068,40069,40070,40071,40072,40073, +40074,17736,25688,40075,40076,40077,40078,40079,40080,40081,40082,19780,25679, +40083,40084,40085,40086,25684,25685,40087,14974,40088,20326,40089,40090,21823, +40091,40092,40093,25682,40094,40095,40096,40097,40098,40099,40100,40101,40102, +40103,40104,25680,40105,40106,25678,40107,40108,40109,40110,40111,40112,40113, +40114,40115,40116,40117,40118,40119,40120,40121,19813,18986,40122,40123,40124, +16419,40125,15654,25683,40126,40127,14408,40128,40129,40130,40131,40132,25703, +21556,40133,40134,40135,40136,40137,40138,40139,25691,40140,40141,40142,16751, +40143,40144,25705,40145,40146,21095,40147,40148,25695,40149,25696,40150,40151, +20266,40152,40153,40154,40155,19293,40156,25690,25681,40157,25701,40158,18524, +25699,40159,40160,17511,25698,40161,25697,40162,40163,40164,13180,25704,40165, +40166,40167,40168,13665,40169,40170,40171,22348,40172,40173,40174,25702,40175, +15148,40176,22354,19535,27512,40177,25700,40178,40179,14710,40180,40181,40182, +22093,25689,25692,17018,25694,40183,16971,16452,16976,40184,12661,19506,40185, +40186,40187,40188,40189,40190,40256,40257,40258,40259,13646,40260,40261,40262, +40263,25711,40264,40265,40266,40267,40268,40269,40270,40271,17967,40272,40273, +40274,18017,40275,40276,25717,40277,40278,40279,40280,40281,16937,40282,40283, +40284,16492,20829,25710,40285,40286,40287,40288,40289,40290,40291,40292,40293, +40294,17454,40295,40296,40297,25709,40298,40299,40300,40301,25718,25716,17022, +40302,25693,40303,25712,40304,19070,40305,21828,40306,40307,25713,40308,40309, +40310,40311,40312,40313,40314,20858,40315,40316,40317,40318,40320,40321,40322, +25707,25708,40323,40324,40325,25714,40326,20011,40327,40328,40329,40330,40331, +40332,40333,40334,40335,40336,17739,40337,40338,40339,18225,40340,16954,40341, +40342,40343,25706,40344,40345,40346,16714,40347,40348,40349,40350,40351,40352, +19510,13105,40353,40354,40355,25723,40356,25715,40357,40358,40359,25722,40360, +25725,40361,25724,40362,40363,40364,40365,40366,40367,40368,13134,40369,40370, +40371,13114,25719,40372,40373,25721,25720,17772,40374,40375,40376,40377,40378, +40379,40380,40381,40382,40383,40384,40385,40386,16445,40387,40388,40389,40390, +21608,40391,40392,40393,40394,40395,25890,40396,40397,40398,40399,40400,40401, +40402,40403,40404,40405,40406,12356,40407,40408,25892,40409,40410,25891,40411, +40412,40413,40414,40415,40416,15396,40417,25893,40418,40419,40420,40421,40422, +40423,25889,40424,40425,40426,40427,40428,40429,40430,25726,12660,40431,40432, +40433,40434,40435,40436,40437,40438,40439,40440,40441,25896,40442,25897,25894, +40443,40444,40445,40446,40512,40513,40514,40515,40516,40517,40518,40519,25895, +25898,40520,40521,40522,40523,40524,40525,40526,40527,40528,40529,40530,40531, +40532,40533,40534,40535,40536,40537,40538,40539,40540,40541,40542,40543,40544, +40545,40546,40547,40548,40549,40550,40551,40552,18009,40553,40554,40555,40556, +40557,40558,40559,40560,25899,25901,40561,40562,40563,40564,40565,40566,40567, +25900,40568,40569,40570,40571,40572,40573,40574,40576,40577,40578,40579,40580, +40581,40582,40583,40584,40585,25903,40586,40587,40588,25902,40589,40590,40591, +40592,40593,40594,40595,40596,40597,40598,40599,40600,40601,40602,40603,40604, +40605,40606,14688,40607,40608,25904,40609,40610,40611,40612,40613,40614,40615, +40616,40617,40618,40619,40620,40621,40622,25905,40623,40624,40625,40626,40627, +40628,40629,40630,40631,40632,40633,40634,15216,27745,17264,40635,13638,15186, +40636,40637,40638,40639,16745,21614,40640,15940,40641,40642,40643,22342,40644, +21590,12883,27710,40645,40646,40647,40648,27201,40649,40650,40651,16943,13366, +40652,40653,40654,20823,40655,40656,40657,13108,40658,18482,16187,27712,40659, +40660,22091,40661,40662,27711,27713,40663,40664,40665,40666,40667,40668,40669, +40670,40671,40672,40673,40674,40675,27717,15974,19519,17754,15932,40676,27718, +40677,12670,40678,40679,40680,27716,21800,13667,40681,27714,16694,13155,40682, +40683,27715,19256,16451,19582,40684,40685,40686,40687,16722,40688,27720,40689, +40690,40691,40692,40693,40694,40695,40696,40697,40698,40699,40700,40701,14950, +16467,40702,22130,40768,40769,40770,20812,40771,40772,40773,40774,16190,40775, +14131,18773,27719,15202,40776,19532,15741,18504,40777,20265,40778,40779,40780, +40781,40782,40783,40784,19817,40785,17771,40786,40787,40788,14185,40789,40790, +40791,40792,40793,40794,40795,40796,40797,40798,40799,20809,14904,40800,40801, +40802,40803,40804,27721,40805,40806,27722,40807,15168,27723,40808,27746,12602, +14169,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,15673, +40820,40821,40822,40823,40824,40825,40826,40827,27724,20838,27725,40828,40829, +40830,40832,18491,40833,40834,40835,40836,40837,40838,40839,40840,40841,40842, +40843,40844,40845,40846,27729,40847,40848,40849,40850,27731,40851,15181,40852, +15461,40853,40854,40855,40856,40857,40858,40859,40860,40861,40862,40863,40864, +40865,27727,40866,18743,40867,40868,40869,40870,40871,17210,40872,27747,21845, +27728,40873,40874,40875,40876,40877,22131,40878,40879,40880,27730,27726,40881, +40882,40883,40884,27732,40885,27733,40886,40887,18751,40888,40889,40890,40891, +40892,40893,20264,40894,40895,40896,40897,40898,20572,40899,40900,40901,40902, +20780,40903,40904,40905,40906,18523,40907,40908,40909,27734,20085,40910,40911, +40912,40913,40914,19052,27738,40915,40916,40917,40918,40919,40920,40921,27737, +40922,40923,40924,12350,40925,40926,40927,40928,40929,40930,27735,40931,27736, +40932,40933,40934,27748,40935,40936,40937,40938,40939,40940,40941,40942,40943, +18492,40944,40945,40946,40947,40948,40949,40950,40951,40952,40953,16711,40954, +40955,40956,40957,40958,27740,20832,41024,41025,41026,41027,41028,41029,41030, +41031,41032,41033,27739,41034,41035,41036,41037,21615,41038,27741,41039,41040, +41041,41042,41043,41044,23366,41045,41046,41047,41048,41049,41050,41051,41052, +41053,41054,27742,41055,41056,41057,41058,41059,41060,41061,41062,41063,41064, +41065,41066,12588,41067,41068,41069,41070,41071,41072,41073,41074,41075,41076, +41077,41078,41079,41080,41081,41082,41083,41084,41085,41086,41088,41089,27743, +41090,41091,41092,41093,41094,41095,41096,41097,41098,41099,27744,41100,22310, +41101,17728,41102,41103,41104,27452,12334,41105,41106,41107,15988,14392,21039, +12374,13689,41108,22579,41109,19244,41110,25437,41111,41112,41113,41114,41115, +41116,41117,17964,12390,41118,41119,41120,17734,27449,41121,41122,41123,41124, +27450,41125,41126,41127,27451,41128,41129,20800,41130,17699,41131,27250,41132, +17458,41133,17461,16462,41134,41135,41136,27251,17473,41137,20079,41138,41139, +41140,41141,27248,27252,41142,41143,18812,41144,41145,18211,41146,41147,41148, +19544,20094,41149,41150,41151,27253,27254,20268,16487,41152,41153,27255,41154, +41155,41156,41157,41158,13887,27256,41159,27257,41160,27258,41161,41162,27259, +41163,41164,41165,41166,41167,41168,41169,41170,41171,41172,41173,41174,27249, +41175,41176,41177,41178,41179,41180,41181,41182,41183,41184,41185,41186,18478, +24939,41187,14136,24940,41188,41189,41190,24941,41191,22324,24942,24943,21324, +41192,41193,41194,41195,41196,41197,41198,24945,16241,24944,13650,41199,41200, +41201,12599,41202,41203,41204,41205,24947,24946,41206,14972,41207,24948,41208, +41209,41210,41211,14647,41212,15953,41213,41214,43584,43585,17532,43586,14941, +15686,43587,43588,43589,43590,43591,43592,24949,24951,43593,43594,13888,20289, +18984,24950,21880,21372,24952,24956,24953,43595,43596,24954,16490,43597,24958, +25121,16455,43598,43599,43600,43601,24955,43602,24957,43603,43604,43605,43606, +43607,43608,25125,43609,43610,43611,16724,43612,43613,43614,43615,25123,43616, +25128,12926,25122,43617,43618,43619,17229,12866,25127,25126,43620,43621,25124, +25129,43622,43623,25131,43624,43625,43626,20553,22125,17192,25132,43627,20311, +43628,43629,25134,43630,43631,14959,43632,43633,26976,25133,25130,43634,43635, +43636,43637,15147,21555,43638,43639,43640,43641,43642,43643,43644,43645,43646, +43648,43649,43650,43651,25136,43652,43653,25135,43654,26977,43655,43656,43657, +43658,25137,43659,43660,43661,43662,43663,43664,43665,43666,25138,43667,43668, +43669,43670,43671,43672,43673,43674,43675,43676,43677,25139,19489,43678,25140, +43679,43680,43840,43841,43842,43843,43844,43845,43846,43847,43848,43849,43850, +43851,25141,43852,43853,43854,43855,43856,20606,43857,43858,16970,43859,21361, +43860,19829,43861,43862,26464,43863,43864,26465,43865,43866,43867,43868,15937, +43869,43870,43871,43872,17002,43873,43874,43875,26468,43876,43877,26467,43878, +43879,43880,43881,43882,43883,19814,43884,17205,43885,43886,26466,15159,20310, +43887,16737,26473,43888,43889,43890,26472,43891,43892,26484,12835,43893,43894, +43895,43896,26474,43897,26470,43898,43899,43900,43901,43902,26476,26475,18746, +43904,43905,21860,43906,26469,14121,26471,43907,43908,43909,43910,43911,43912, +43913,26478,43914,43915,43916,43917,26483,43918,22121,43919,43920,43921,43922, +26477,43923,26482,43924,26481,43925,43926,43927,12384,43928,43929,43930,43931, +26485,43932,43933,43934,43935,43936,44096,44097,44098,44099,44100,44101,44102, +44103,44104,44105,44106,18290,44107,16453,16493,44108,44109,16752,26480,44110, +44111,44112,44113,26486,19318,44114,44115,44116,44117,44118,44119,44120,44121, +44122,26658,26657,44123,44124,44125,44126,44127,44128,22337,44129,44130,26490, +26489,44131,26491,44132,26487,44133,26494,44134,26493,44135,26492,44136,44137, +16725,18265,17789,17731,44138,44139,44140,44141,44142,18285,44143,44144,44145, +44146,26659,44147,44148,44149,44150,44151,44152,44153,44154,44155,44156,44157, +44158,44160,44161,44162,44163,44164,44165,44166,26662,44167,26661,44168,26663, +14967,26488,26660,44169,18544,18730,44170,44171,44172,44173,44174,44175,44176, +44177,44178,44179,44180,44181,44182,26665,44183,44184,14693,44185,44186,44187, +44188,44189,20862,26664,44190,44191,44192,44352,44353,44354,26666,44355,26669, +26670,44356,16679,44357,44358,44359,26671,44360,44361,44362,26672,44363,44364, +26668,44365,26676,44366,44367,44368,44369,44370,44371,44372,44373,44374,44375, +44376,26667,44377,26673,44378,44379,44380,44381,44382,44383,44384,44385,26677, +26674,26675,44386,44387,44388,44389,44390,44391,44392,44393,44394,44395,44396, +44397,44398,44399,44400,44401,26679,44402,44403,44404,44405,44406,44407,44408, +44409,44410,44411,44412,44413,44414,44416,44417,44418,44419,44420,44421,44422, +44423,44424,44425,26678,44426,44427,44428,44429,44430,44431,44432,44433,44434, +14671,44435,28716,44436,28717,44437,17968,12394,18495,44438,19807,44439,44440, +44441,44442,44443,44444,44445,20045,27185,44446,44447,44448,44608,27186,44609, +17983,13385,44610,44611,44612,44613,44614,44615,44616,27187,44617,44618,44619, +44620,21863,44621,44622,44623,44624,44625,44626,44627,44628,23929,44629,27188, +44630,27189,44631,27190,44632,44633,44634,44635,14410,24368,18805,44636,19568, +44637,44638,18810,44639,44640,44641,44642,44643,18811,44644,44645,21315,19238, +44646,14374,28718,12610,44647,25912,19567,21321,15447,18794,44648,13671,44649, +17488,13673,44650,28206,15149,44651,44652,26462,44653,28207,44654,44655,44656, +44657,13097,44658,44659,28210,44660,44661,28209,15719,44662,28208,20023,44663, +44664,44665,44666,17743,44667,44668,44669,44670,16756,23374,28211,20595,44672, +44673,44674,44675,44676,44677,44678,44679,16980,18024,44680,44681,44682,14124, +44683,44684,44685,44686,44687,44688,44689,28212,44690,13163,44691,44692,44693, +15227,28213,44694,44695,44696,44697,44698,26460,44699,44700,44701,28214,44702, +44703,15662,44704,44864,44865,44866,29026,44867,44868,44869,19048,44870,21065, +28762,44871,28763,44872,28764,16710,44873,14445,15950,44874,44875,28766,44876, +17713,28765,20849,44877,28768,12364,15722,44878,44879,44880,44881,44882,21087, +28767,44883,13359,14184,28774,28773,17955,28769,28770,13379,44884,44885,28771, +21870,44886,44887,19547,15954,15410,44888,44889,44890,28776,28775,28772,12833, +44891,22050,21304,15927,18476,44892,44893,28778,44894,44895,44896,44897,20855, +44898,22092,14939,28777,44899,13883,44900,44901,19764,44902,44903,17958,44904, +44905,44906,16673,28779,28782,44907,28781,28784,28780,44908,15166,28783,44909, +44910,44911,44912,19509,28786,44913,44914,13141,44915,44916,44917,44918,12628, +44919,44920,28787,44921,44922,28788,28790,13409,44923,28785,44924,28791,44925, +44926,44928,44929,28794,44930,28792,44931,44932,44933,28789,44934,44935,44936, +44937,28797,44938,28793,28796,28798,44939,28961,44940,44941,44942,20033,28964, +44943,28963,44944,16758,28795,19037,44945,44946,13425,12657,19505,44947,28966, +44948,44949,28967,44950,44951,28972,21838,28969,44952,44953,18483,44954,44955, +44956,28962,44957,28971,28968,28965,44958,44959,28970,44960,45120,45121,45122, +45123,45124,45125,45126,12329,28973,45127,45128,45129,45130,45131,45132,28975, +45133,28977,45134,45135,45136,45137,45138,28976,45139,28974,45140,45141,45142, +45143,20770,45144,45145,45146,45147,45148,45149,45150,28978,45151,45152,45153, +28979,45154,45155,45156,45157,45158,45159,45160,45161,14703,45162,45163,13639, +45164,12375,12377,45165,45166,45167,21613,45168,13636,45169,15700,15178,28711, +45170,45171,14430,45172,45173,28712,45174,45175,12328,45176,28713,45177,45178, +19822,45179,45180,28714,45181,45182,45184,45185,45186,45187,45188,45189,45190, +45191,28715,45192,45193,45194,45195,45196,45197,45198,45199,45200,17956,45201, +45202,22117,29028,45203,29029,45204,45205,45206,45207,45208,45209,45210,45211, +45212,45213,17267,45214,45215,21339,45216,45376,22097,17768,45377,21295,45378, +21094,45379,45380,28225,12347,21813,20814,15456,14928,45381,16248,45382,14407, +13633,17740,45383,45384,18978,45385,45386,45387,17227,45388,45389,45390,45391, +45392,28226,45393,45394,45395,45396,45397,45398,45399,45400,17471,13858,45401, +28012,17188,45402,22065,45403,45404,45405,20320,28015,45406,45407,17742,45408, +13916,45409,45410,18977,45411,45412,28013,45413,45414,28016,28017,17212,45415, +16180,45416,28014,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426, +45427,28020,28018,45428,45429,45430,45431,21862,17247,45432,28019,45433,45434, +45435,28022,45436,21795,20771,45437,45438,45440,28021,45441,17232,45442,45443, +45444,45445,45446,28023,16244,15980,28024,45447,19575,45448,20827,45449,45450, +45451,22341,21878,45452,28028,45453,45454,45455,28027,45456,45457,45458,45459, +45460,45461,45462,45463,28025,28026,45464,45465,45466,45467,45468,45469,45470, +45471,28029,15910,45472,45632,45633,45634,45635,19247,28193,13885,45636,28194, +17472,45637,28030,45638,45639,15710,12871,45640,45641,45642,45643,45644,45645, +45646,45647,45648,45649,45650,45651,13891,45652,45653,45654,28197,22586,28195, +28198,45655,45656,45657,17257,13170,45658,45659,45660,45661,45662,45663,28199, +28196,20281,45664,45665,28200,17015,45666,45667,45668,45669,45670,45671,45672, +45673,45674,45675,45676,45677,28201,28202,45678,24107,45679,45680,17971,45681, +18246,45682,22133,13641,45683,19250,45684,45685,45686,28203,45687,45688,19755, +45689,28204,45690,45691,45692,45693,45694,21808,45696,28205,45697,30276,45698, +45699,45700,45701,45702,45703,45704,45705,45706,45707,45708,45709,45710,23367, +45711,45712,45713,45714,45715,45716,45717,45718,45719,13347,45720,45721,45722, +17196,29030,45723,45724,45725,45726,45727,19000,21075,45728,22058,45888,28530, +45889,15960,45890,15683,28531,13900,12331,45891,45892,45893,45894,18991,45895, +45896,27958,45897,27959,45898,45899,45900,45901,20089,14127,16243,27960,17003, +18736,45902,45903,45904,45905,45906,45907,27961,45908,45909,18038,16179,45910, +45911,45912,27964,17784,45913,20816,45914,22313,27962,27963,45915,20834,45916, +27967,27968,45917,27972,45918,45919,45920,27976,45921,27974,27982,21864,45922, +27977,45923,45924,27975,27966,45925,45926,17769,45927,45928,45929,17990,45930, +45931,18793,21586,27969,27970,27971,27973,45932,16505,45933,13345,45934,45935, +45936,45937,14696,45938,27984,45939,45940,45941,45942,27985,45943,27978,45944, +27983,45945,20088,45946,45947,19254,27980,27981,45948,45949,45950,45952,45953, +20341,45954,45955,45956,45957,45958,45959,45960,45961,45962,45963,45964,45965, +27986,16754,21298,27979,18487,45966,45967,45968,45969,45970,45971,45972,45973, +15471,45974,45975,45976,45977,17776,45978,45979,45980,45981,45982,45983,45984, +46144,46145,46146,27990,46147,13679,46148,46149,16949,12333,19305,46150,46151, +12590,46152,27988,46153,46154,46155,19819,13666,46156,27989,27987,27991,46157, +46158,13690,46159,27992,46160,27993,46161,27996,46162,12620,46163,46164,46165, +46166,46167,46168,46169,46170,17782,15470,27994,19516,12906,46171,46172,46173, +46174,27995,46175,46176,46177,46178,17515,46179,46180,13381,46181,46182,46183, +12405,46184,46185,46186,27999,16474,13416,46187,46188,46189,46190,17741,46191, +46192,46193,27997,16196,46194,46195,46196,27998,46197,46198,46199,46200,46201, +46202,46203,46204,46205,46206,46208,46209,46210,46211,17445,46212,46213,46214, +28000,46215,46216,46217,46218,46219,28001,46220,28003,46221,46222,16727,46223, +46224,15175,46225,46226,46227,46228,46229,46230,15672,46231,46232,46233,28002, +46234,46235,46236,46237,46238,46239,46240,46400,46401,46402,46403,46404,46405, +28004,46406,46407,46408,46409,46410,46411,46412,46413,46414,46415,28006,46416, +46417,46418,46419,46420,28005,46421,46422,46423,46424,46425,46426,46427,46428, +46429,46430,46431,46432,46433,46434,46435,28007,46436,46437,46438,46439,46440, +19006,27754,16497,46441,18791,46442,27755,18030,46443,46444,46445,46446,27756, +46447,18029,27757,46448,46449,46450,46451,46452,46453,46454,46455,46456,27760, +46457,46458,22374,27763,46459,46460,27761,27758,27759,22307,18801,19310,27764, +46461,27762,46462,46464,20329,46465,27766,17969,46466,46467,46468,46469,15424, +46470,27765,46471,46472,46473,46474,46475,46476,46477,13627,15222,46478,27767, +46479,46480,46481,46482,46483,22903,15739,46484,46485,16955,27768,46486,46487, +46488,46489,27769,46490,46491,46492,46493,14371,46494,46495,46496,46656,46657, +46658,46659,46660,46661,46662,27770,46663,46664,46665,46666,46667,46668,46669, +46670,46671,46672,46673,46674,27771,46675,46676,46677,46678,46679,46680,46681, +46682,46683,46684,46685,27772,46686,46687,46688,46689,46690,21357,22574,16491, +46691,18269,14924,46692,20579,19261,46693,19770,46694,46695,14417,46696,46697, +12668,46698,18287,46699,22102,46700,46701,46702,16198,17259,46703,46704,28533, +46705,46706,17240,46707,46708,46709,46710,46711,46712,22370,46713,46714,46715, +28535,13139,46716,18264,20845,46717,22088,46718,28536,46720,28534,46721,15229, +13126,46722,46723,46724,46725,46726,46727,46728,15701,46729,46730,21062,46731, +15200,46732,46733,20257,46734,28540,28539,46735,46736,28537,46737,46738,46739, +46740,13132,46741,18772,19248,46742,46743,46744,46745,46746,28542,46747,46748, +12382,46749,46750,22089,46751,46752,46912,28541,46913,13165,46914,46915,30293, +46916,46917,46918,46919,46920,46921,46922,46923,46924,46925,46926,46927,46928, +46929,46930,20040,46931,46932,46933,28706,46934,28705,46935,13630,15450,15228, +46936,14437,46937,46938,46939,46940,46941,46942,17474,46943,46944,46945,46946, +46947,46948,46949,46950,46951,46952,28707,46953,46954,46955,46956,46957,19307, +46958,46959,46960,46961,46962,46963,46964,46965,46966,46967,46968,46969,46970, +46971,46972,46973,46974,46976,46977,46978,46979,46980,46981,46982,28710,46983, +46984,46985,20776,46986,15935,18286,28982,28983,16213,46987,46988,46989,46990, +13353,28984,19771,46991,18260,21805,46992,28985,46993,28986,46994,46995,46996, +46997,18255,46998,46999,47000,21028,22095,47001,47002,28987,15697,13360,15933, +47003,47004,47005,13404,20049,47006,16223,28989,47007,47008,47168,47169,16250, +28988,47170,28991,47171,47172,47173,28990,28992,47174,47175,47176,47177,47178, +28993,47179,47180,47181,47182,47183,47184,47185,47186,47187,47188,47189,16766, +47190,47191,47192,47193,47194,47195,47196,47197,47198,47199,47200,16674,47201, +47202,47203,47204,47205,47206,47207,47208,47209,47210,19066,47211,47212,21822, +47213,47214,47215,47216,15930,15929,21826,47217,47218,16162,47219,19759,28981, +47220,47221,47222,47223,47224,47225,15711,47226,13899,47227,47228,47229,47230, +47232,47233,47234,47235,47236,22129,29507,47237,47238,29508,47239,14413,47240, +47241,47242,29510,29511,47243,12362,47244,29509,47245,29513,19313,47246,47247, +47248,29515,47249,20518,47250,47251,12618,29512,47252,47253,47254,29519,47255, +13649,47256,47257,29527,47258,29522,47259,47260,47261,29524,29523,14203,47262, +12607,47263,29518,29514,13658,47264,29520,47424,47425,29521,47426,29525,47427, +47428,47429,47430,29517,47431,15459,47432,16765,47433,29526,47434,47435,47436, +47437,47438,47439,29530,47440,29516,47441,13640,47442,15726,29532,47443,47444, +14116,16240,22142,19762,47445,13424,47446,12895,47447,29528,47448,29529,18744, +47449,29533,47450,47451,29534,47452,29537,47453,47454,47455,47456,47457,47458, +47459,47460,47461,47462,47463,29535,47464,47465,29539,29538,47466,47467,29531, +47468,16234,47469,13167,47470,29536,47471,47472,18217,47473,15474,47474,47475, +47476,47477,29547,47478,47479,47480,47481,47482,47483,47484,14655,47485,47486, +29540,47488,47489,47490,12845,15230,47491,19299,47492,47493,47494,47495,29549, +29545,47496,47497,47498,14684,29550,47499,47500,47501,29541,29542,29546,16993, +29548,29551,29544,15485,47502,47503,47504,20324,47505,47506,29552,47507,47508, +47509,29543,47510,47511,47512,47513,47514,47515,47516,47517,29554,47518,47519, +47520,47680,22317,17962,47681,47682,47683,47684,29555,47685,47686,47687,47688, +29553,47689,16936,47690,47691,47692,47693,47694,14429,29557,47695,47696,29556, +47697,47698,47699,13403,47700,47701,47702,29558,29559,47703,47704,47705,29560, +47706,47707,47708,16442,47709,47710,16489,47711,47712,47713,47714,47715,17777, +47716,47717,47718,47719,29563,47720,29562,47721,47722,47723,47724,47725,47726, +47727,47728,13400,47729,47730,47731,29566,29561,47732,47733,29564,47734,47735, +47736,47737,47738,47739,29565,47740,47741,47742,47744,47745,47746,47747,47748, +29729,47749,47750,47751,47752,47753,47754,29731,15177,47755,47756,29730,47757, +47758,47759,47760,47761,47762,47763,47764,47765,47766,47767,47768,47769,29732, +47770,47771,47772,47773,47774,47775,12862,29734,29733,47776,47936,47937,47938, +47939,47940,47941,47942,47943,47944,47945,15406,47946,47947,47948,47949,47950, +47951,47952,47953,47954,47955,47956,47957,47958,47959,47960,47961,47962,47963, +47964,47965,47966,47967,47968,47969,47970,47971,47972,47973,47974,47975,47976, +47977,47978,47979,47980,47981,47982,17239,22881,47983,47984,47985,47986,47987, +47988,16480,29772,22353,47989,47990,47991,47992,47993,47994,47995,47996,47997, +47998,48000,14171,48001,48002,48003,48004,48005,48006,48007,29774,16675,48008, +48009,17993,48010,13398,21811,48011,48012,48013,29776,29775,29777,19290,48014, +48015,29778,48016,21569,22112,48017,48018,48019,48020,14176,48021,48022,48023, +16696,48024,48025,16699,29779,15916,48026,48027,48028,48029,48030,13410,48031, +48032,29780,29781,15915,48192,48193,29782,48194,48195,48196,29787,48197,29783, +29786,48198,14973,48199,29784,29785,48200,48201,48202,48203,48204,48205,48206, +14434,19527,29788,48207,12890,48208,48209,17235,48210,48211,21603,16183,48212, +48213,48214,48215,48216,48217,48218,29789,48219,48220,48221,48222,48223,48224, +17716,48225,48226,48227,48228,48229,48230,48231,48232,29801,48233,48234,20277, +48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247, +48248,20041,48249,48250,48251,48252,48253,48254,48256,48257,48258,48259,48260, +48261,48262,48263,48264,48265,48266,48267,48268,48269,48270,19288,48271,19319, +48272,48273,48274,48275,15732,48276,48277,48278,22351,48279,48280,48281,16475, +48282,48283,48284,48285,48286,48287,48288,48448,48449,48450,48451,48452,48453, +48454,48455,48456,48457,48458,48459,48460,48461,48462,48463,48464,48465,48466, +48467,48468,48469,48470,48471,48472,48473,48474,48475,48476,48477,48478,48479, +48480,48481,48482,48483,48484,48485,48486,48487,48488,48489,48490,48491,48492, +48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,20597,48503,48504, +48505,48506,48507,48508,48509,48510,29802,48512,48513,48514,48515,48516,48517, +48518,48519,48520,48521,48522,48523,48524,48525,48526,48527,48528,48529,48530, +48531,48532,48533,48534,48535,48536,48537,48538,48539,48540,48541,48542,48543, +48544,48704,48705,48706,48707,48708,48709,48710,48711,48712,48713,48714,48715, +48716,29803,48717,48718,48719,48720,48721,48722,48723,29804,48724,48725,48726, +48727,48728,48729,48730,48731,48732,48733,48734,48735,48736,48737,48738,48739, +48740,48741,48742,48743,48744,48745,48746,48747,48748,48749,48750,48751,48752, +48753,48754,48755,48756,48757,48758,48759,48760,48761,48762,48763,48764,48765, +48766,48768,48769,48770,48771,48772,48773,48774,48775,48776,48777,48778,48779, +48780,48781,48782,48783,48784,48785,48786,48787,48788,48789,48790,48791,48792, +48793,48794,48795,48796,48797,48798,48799,48800,48960,48961,48962,48963,48964, +48965,48966,48967,48968,48969,48970,48971,48972,48973,48974,48975,48976,48977, +48978,48979,48980,48981,48982,48983,48984,48985,48986,48987,48988,48989,48990, +48991,48992,48993,48994,48995,48996,48997,48998,48999,49000,49001,49002,49003, +49004,49005,49006,49007,49008,49009,49010,49011,49012,49013,49014,49015,49016, +49017,49018,49019,49020,49021,49022,49024,30563,49025,49026,49027,49028,49029, +14129,49030,49031,49032,49033,49034,29805,49035,49036,49037,49038,49039,49040, +49041,49042,49043,49044,49045,49046,49047,49048,49049,49050,49051,49052,49053, +49054,49055,49056,49216,49217,49218,49219,49220,49221,49222,49223,49224,49225, +49226,49227,49228,49229,49230,49231,49232,49233,49234,49235,49236,49237,49238, +49239,49240,49241,49242,49243,49244,49245,49246,49247,49248,49249,49250,49251, +22379,49252,49253,49254,49255,49256,49257,49258,49259,49260,49261,49262,49263, +49264,49265,49266,49267,49268,49269,49270,49271,49272,49273,49274,49275,29806, +49276,49277,49278,26233,15936,26234,14956,26235,20299,26236,21564,15414,26237, +26238,15437,18514,20019,26401,49280,13375,26402,18740,14425,17481,49281,22365, +16986,14167,22077,20038,14148,49282,49283,17702,26403,20319,26404,26405,26406, +16695,22377,18800,20280,22063,22101,26407,12397,26408,26409,18780,21103,15917, +26410,12403,18526,15713,26411,18502,49284,26412,15206,14456,20772,26413,16999, +15992,15690,19763,26414,26415,15982,20581,49285,19303,19536,15436,26416,15400, +20599,26417,49286,20600,26418,26419,13378,26420,26421,18814,20012,17248,26423, +12609,13169,49287,26424,26425,22363,21824,26426,16972,22330,26427,26428,26429, +15466,17253,16450,26430,26431,15401,49288,26432,26433,26422,13904,26434,49289, +26435,26436,15162,13662,16966,12640,26437,21557,26438,14399,26440,26439,14188, +49290,26441,12920,26442,26443,26444,26445,26446,26447,26448,21287,19317,26449, +26450,26451,26452,18761,26453,26454,26455,26456,26457,15689,26458,29502,49291, +14423,49292,18481,49293,49294,49295,49296,49297,49298,49299,29503,49300,29504, +29505,49301,49302,49303,49304,49305,49306,49307,49308,49309,49310,14686,19832, +49311,49312,22632,14897,49472,16990,28215,49473,14115,49474,49475,49476,49477, +28217,49478,28216,12373,49479,49480,49481,49482,49483,28219,21846,22383,49484, +49485,49486,22083,49487,49488,28221,19056,49489,28220,49490,49491,49492,49493, +28222,49494,49495,49496,49497,28224,49498,49499,28223,49500,49501,49502,49503, +49504,49505,49506,49507,20850,49508,18236,49509,17216,49510,49511,49512,49513, +49514,14433,49515,49516,49517,49518,49519,16743,49520,49521,29766,20575,29767, +49522,20315,49523,49524,18490,49525,49526,29768,49527,49528,49529,49530,49531, +49532,49533,29769,29770,49534,29771,49536,49537,49538,49539,49540,22906,14462, +49541,49542,25969,21360,49543,29792,49544,20044,49545,49546,49547,13153,49548, +49549,49550,49551,28980,49552,21102,49553,29793,49554,49555,49556,49557,49558, +20328,29794,49559,49560,18252,49561,49562,49563,49564,49565,49566,13652,13412, +29796,49567,49568,49728,29795,29797,49729,49730,29798,49731,49732,49733,49734, +29799,49735,14898,12351,49736,29800,49737,49738,49739,49740,49741,49742,49743, +14125,21101,49744,49745,49746,21035,16463,49747,16188,27427,21855,27208,49748, +49749,49750,49751,29043,13944,19235,49752,49753,17485,49754,29031,49755,29032, +14459,29033,14916,21573,12370,49756,49757,29034,49758,49759,49760,29035,49761, +29036,49762,49763,29037,29038,29039,29041,29040,17749,49764,49765,49766,49767, +49768,49769,29042,49770,13946,49771,29044,21038,24135,19274,49772,49773,13148, +49774,13602,49775,14626,49776,49777,17524,29045,49778,49779,29046,49780,49781, +49782,16708,16763,22064,29047,49783,49784,49785,49786,29048,49787,16682,49788, +49789,49790,17976,49792,15963,49793,49794,49795,49796,49797,49798,49799,49800, +49801,49802,49803,49804,49805,49806,29049,13391,49807,49808,49809,49810,49811, +49812,29050,49813,49814,49815,49816,49817,49818,49819,49820,49821,49822,49823, +49824,49984,27954,27953,49985,49986,19296,21086,49987,19265,21848,49988,18530, +49989,16479,15393,49990,49991,49992,49993,49994,49995,27457,49996,49997,20516, +49998,22114,49999,13895,14424,27456,14414,50000,27455,13094,14665,22059,50001, +14196,14154,50002,50003,50004,15463,14142,27462,50005,27463,12345,16207,50006, +27461,21373,50007,27464,50008,50009,27465,50010,50011,14158,50012,27458,27460, +18806,22103,21837,20530,27471,20024,27472,50013,13608,50014,50015,50016,50017, +50018,12595,27474,19493,50019,50020,50021,50022,50023,50024,50025,17750,27475, +50026,27473,17759,27470,18980,27477,12411,50027,50028,14970,50029,50030,22583, +29027,50031,27466,27467,27468,27469,27478,26176,27481,50032,16232,21064,27479, +27484,14444,27480,50033,15674,50034,20568,50035,12343,50036,27485,17500,50037, +50038,50039,50040,22060,50041,50042,50043,13408,50044,50045,17014,15417,50046, +50048,27482,27483,21600,18026,17492,27487,17703,22901,50049,12849,50050,27492, +50051,15685,50052,50053,50054,27490,50055,50056,50057,50058,50059,50060,50061, +50062,50063,50064,50065,50066,50067,27491,50068,50069,14380,50070,19793,27493, +50071,50072,50073,27489,50074,16691,50075,50076,50077,50078,50079,17954,50080, +50240,50241,50242,50243,50244,50245,19571,50246,27494,50247,16432,21048,27495, +50248,50249,50250,14383,14381,50251,27496,18235,19827,50252,50253,50254,27498, +27499,50255,50256,50257,50258,50259,27501,50260,50261,50262,50263,20552,50264, +27506,50265,27502,50266,50267,50268,27505,18553,50269,20860,27500,50270,50271, +27497,50272,50273,50274,50275,14393,20313,17509,27503,27504,19546,19784,12402, +50276,27510,50277,50278,50279,50280,50281,27509,50282,12850,50283,50284,50285, +50286,14432,50287,27511,50288,50289,50290,50291,50292,50293,12652,50294,50295, +19525,17444,20261,50296,50297,50298,50299,50300,27513,50301,50302,27682,50304, +17778,50305,27514,50306,50307,50308,50309,50310,50311,50312,50313,18757,50314, +50315,50316,50317,50318,50319,25183,27518,50320,50321,50322,50323,19790,27681, +12635,21303,50324,50325,21084,50326,50327,50328,27517,50329,27515,50330,50331, +50332,50333,50334,50335,50336,50496,50497,50498,50499,50500,50501,50502,50503, +50504,50505,50506,50507,50508,50509,50510,13116,50511,50512,50513,27184,50514, +50515,22356,50516,29739,13172,50517,50518,50519,50520,50521,22081,22082,50522, +50523,50524,50525,50526,50527,21865,15946,50528,29735,50529,21032,29736,29737, +50530,29738,15947,21343,50531,50532,50533,50534,50535,18784,18785,50536,50537, +29506,50538,19046,50539,19570,50540,50541,50542,50543,50544,50545,25142,19252, +50546,20072,22107,50547,29741,29742,29743,50548,50549,50550,50551,29746,50552, +14909,29747,12387,29744,50553,29745,15650,12885,50554,29750,29751,13926,12848, +20303,29748,13356,50555,29749,50556,50557,29752,50558,50560,50561,50562,50563, +29753,50564,50565,19751,50566,29754,50567,29755,50568,50569,50570,29756,50571, +50572,50573,50574,50575,50576,50577,50578,19282,50579,29757,50580,50581,50582, +50583,29758,50584,50585,50586,50587,50588,50589,50590,50591,29759,50592,50752, +50753,50754,50755,29790,16700,15464,50756,18731,20830,25973,50757,50758,50759, +50760,23603,21077,50761,50762,23604,12332,23605,50763,50764,15706,50765,23609, +50766,50767,50768,22594,50769,23607,21363,50770,18774,23610,23606,50771,23611, +17186,50772,50773,50774,50775,23612,23621,23613,50776,50777,20063,22053,50778, +23631,50779,23629,50780,50781,23634,15718,16939,50782,23608,23627,23630,23614, +14162,12357,23623,20542,23617,15144,50783,14140,23628,50784,50785,23622,23615, +18267,50786,50787,50788,20799,23616,50789,50790,23626,50791,50792,23632,50793, +50794,20013,23618,50795,23619,23624,23625,12884,23633,19285,50796,21559,23643, +23647,19494,23654,50797,17255,23644,50798,50799,16193,23641,50800,12410,14646, +23653,23635,50801,23620,23638,18548,16224,50802,50803,50804,50805,18747,50806, +50807,50808,12605,50809,21282,50810,50811,23642,50812,50813,23637,50814,17979, +50816,23646,50817,50818,50819,50820,50821,22338,17199,14134,18257,17193,23650, +23640,23659,23636,50822,50823,23645,50824,15909,23639,50825,23648,50826,50827, +23651,23652,50828,23672,50829,50830,23649,23842,23655,50831,50832,50833,50834, +50835,50836,50837,50838,50839,50840,15467,13380,50841,50842,17187,12903,23674, +50843,23666,50844,23663,50845,23676,23662,21104,12904,50846,18519,18531,23675, +50847,23661,50848,51008,51009,23671,51010,51011,23669,51012,51013,15907,23668, +51014,12893,51015,51016,51017,51018,51019,23667,15478,23656,15172,51020,16499, +51021,51022,51023,51024,51025,15444,23657,23658,51026,23665,23670,23673,13620, +51027,18521,15207,23678,23677,21291,23841,23843,23845,21105,23844,23846,23847, +21033,51028,51029,51030,51031,51032,51033,51034,14921,23849,51035,51036,23862, +23857,23860,51037,51038,51039,51040,51041,51042,51043,23856,17998,51044,51045, +16498,51046,51047,51048,51049,18735,51050,51051,51052,23660,23854,51053,51054, +51055,51056,23863,51057,51058,23664,23855,51059,23864,51060,23852,51061,51062, +51063,51064,51065,51066,51067,23865,23859,23853,17450,51068,51069,51070,51072, +23848,16435,16683,23850,23851,51073,23858,15217,23861,21288,23866,51074,23867, +17191,51075,51076,23890,23868,51077,51078,51079,23889,51080,14653,51081,51082, +15957,51083,15994,51084,51085,14922,51086,51087,51088,51089,23882,51090,23877, +51091,23871,51092,51093,51094,12875,23875,51095,23883,12836,23893,51096,51097, +51098,23870,51099,51100,51101,18000,23888,51102,51103,51104,51264,51265,23892, +16738,14150,51266,51267,51268,51269,51270,23886,23887,51271,51272,51273,23876, +51274,51275,51276,23869,51277,23885,19537,51278,23881,51279,51280,51281,51282, +23874,17224,17980,20014,23884,51283,23880,51284,51285,51286,51287,51288,51289, +23873,51290,51291,51292,23878,16988,51293,51294,51295,51296,51297,51298,21289, +21290,23891,20340,18552,51299,51300,51301,51302,51303,51304,51305,51306,23910, +51307,51308,51309,51310,51311,51312,23879,51313,51314,51315,23904,16996,51316, +51317,51318,51319,51320,51321,51322,51323,23905,51324,51325,51326,51328,51329, +51330,51331,51332,51333,51334,23895,51335,51336,51337,51338,51339,22136,51340, +23897,23896,14448,23894,51341,51342,51343,51344,17999,51345,13869,51346,51347, +51348,51349,51350,23906,51351,14969,21601,23911,51352,51353,51354,13392,51355, +23898,51356,16251,23907,51357,23903,51358,23901,51359,51360,51520,51521,51522, +51523,51524,13657,51525,51526,51527,51528,23899,23900,23902,51529,15663,23908, +51530,23909,51531,51532,51533,51534,51535,51536,51537,51538,23925,51539,17225, +51540,51541,19298,51542,51543,51544,51545,23922,51546,51547,51548,51549,51550, +51551,51552,51553,51554,51555,51556,51557,51558,22625,51559,51560,18001,51561, +23924,51562,51563,51564,21876,23923,23920,51565,51566,23916,51567,23919,51568, +23912,51569,51570,20590,51571,51572,51573,51574,18520,23918,51575,51576,23913, +51577,51578,23914,19314,51579,23917,51580,51581,12621,51582,51584,51585,51586, +51587,51588,16438,51589,15419,23921,51590,51591,23927,51592,23926,23915,51593, +51594,51595,51596,51597,17774,51598,51599,51600,23931,51601,51602,51603,51604, +51605,51606,51607,51608,51609,51610,51611,24100,51612,51613,24099,51614,51615, +51616,51776,51777,51778,51779,51780,51781,51782,51783,51784,23928,51785,51786, +51787,51788,17263,51789,17019,51790,51791,51792,21857,51793,51794,20021,51795, +51796,51797,51798,23933,51799,12876,51800,51801,51802,51803,51804,51805,51806, +51807,51808,17512,19039,51809,51810,51811,51812,51813,51814,51815,51816,51817, +51818,18238,23930,23932,23934,24098,12330,12622,51819,51820,51821,51822,51823, +24108,51824,51825,51826,51827,24102,15670,18543,51828,51829,51830,51831,51832, +51833,51834,51835,51836,51837,51838,24097,51840,51841,24101,51842,51843,51844, +51845,24105,51846,51847,51848,51849,51850,24104,51851,51852,51853,24103,51854, +51855,51856,51857,51858,51859,51860,51861,51862,24109,51863,21580,51864,51865, +51866,51867,24115,24106,24110,51868,51869,16473,51870,51871,51872,52032,52033, +12577,24118,52034,24113,52035,52036,52037,52038,52039,52040,52041,24114,52042, +52043,52044,52045,52046,52047,52048,52049,52050,52051,52052,20774,24117,52053, +52054,52055,52056,52057,52058,52059,24111,52060,52061,52062,24112,52063,20541, +52064,52065,52066,24116,19053,24121,52067,52068,52069,52070,52071,52072,24120, +52073,24119,52074,52075,52076,52077,52078,52079,52080,24123,52081,52082,52083, +52084,52085,52086,52087,15717,52088,52089,52090,52091,52092,12888,17258,52093, +52094,24122,52096,17722,52097,52098,52099,52100,52101,52102,24124,52103,52104, +52105,52106,52107,52108,52109,19545,52110,52111,52112,52113,14122,52114,52115, +52116,52117,52118,52119,52120,52121,52122,52123,52124,52125,52126,52127,52128, +52288,52289,21605,52290,52291,52292,24125,52293,52294,52295,52296,52297,24127, +52298,52299,52300,52301,52302,52303,52304,52305,52306,52307,52308,17442,52309, +52310,52311,52312,24129,52313,52314,52315,52316,52317,52318,52319,52320,52321, +52322,52323,52324,52325,52326,52327,52328,24126,52329,24128,52330,52331,52332, +52333,52334,52335,52336,52337,52338,52339,52340,52341,52342,52343,21818,52344, +52345,52346,24130,52347,52348,52349,52350,52352,52353,52354,52355,52356,52357, +52358,52359,52360,52361,52362,52363,29230,15138,16946,17712,16967,52364,52365, +29231,52366,52367,52368,52369,52370,20585,52371,52372,52373,21341,52374,52375, +52376,27453,52377,52378,52379,52380,52381,52382,52383,52384,13158,29232,52544, +29233,52545,52546,18989,52547,52548,52549,52550,52551,52552,52553,14951,29235, +29237,29236,19300,20282,29234,18996,21071,17004,52554,52555,52556,52557,52558, +52559,52560,20035,29240,12406,29239,52561,52562,52563,52564,52565,29246,52566, +12879,52567,52568,52569,52570,52571,52572,20801,29242,52573,52574,52575,52576, +52577,29244,21609,52578,52579,29243,29238,29247,29245,52580,29241,52581,52582, +29255,29252,29254,52583,52584,29258,29250,29248,52585,52586,52587,29253,52588, +52589,52590,52591,52592,22139,52593,52594,52595,29249,52596,18297,18783,52597, +29256,14662,13616,52598,52599,29251,29257,29264,29270,52600,52601,15191,52602, +52603,52604,29269,19804,52605,22123,52606,52608,29266,29268,52609,52610,52611, +52612,14450,52613,52614,52615,52616,29259,52617,52618,52619,29262,17017,52620, +21853,29260,29261,29263,29267,52621,52622,52623,29273,21308,52624,52625,52626, +52627,13930,52628,19057,52629,14180,29271,52630,52631,52632,29272,29274,29277, +29275,52633,52634,29276,52635,52636,52637,52638,20817,29265,52639,19785,52640, +20047,22057,52800,29283,52801,17243,52802,29280,52803,52804,16431,29292,29278, +52805,29281,52806,52807,52808,29288,52809,52810,52811,52812,29282,52813,52814, +29287,52815,52816,29286,52817,52818,29289,52819,52820,52821,29279,52822,52823, +29284,29290,52824,52825,52826,52827,52828,52829,52830,21292,29285,12917,52831, +52832,29298,52833,20523,52834,52835,52836,52837,29301,52838,52839,52840,15176, +52841,29305,52842,52843,52844,52845,52846,52847,29296,52848,52849,29302,29304, +29306,52850,52851,52852,52853,52854,52855,52856,52857,29299,52858,29297,52859, +52860,52861,14971,52862,13691,52864,52865,52866,52867,29295,29303,29293,29294, +52868,52869,52870,29291,29478,52871,29475,52872,52873,29474,52874,52875,29300, +52876,18522,52877,52878,52879,52880,52881,29307,52882,52883,52884,29477,52885, +52886,52887,52888,52889,52890,52891,17272,52892,52893,52894,52895,52896,53056, +53057,53058,29309,53059,53060,29479,29481,29476,53061,29308,53062,53063,53064, +29483,53065,29482,53066,53067,53068,53069,16989,53070,53071,29486,53072,53073, +29488,53074,53075,53076,53077,53078,29473,53079,53080,53081,29489,29484,53082, +53083,53084,53085,53086,29487,29310,29485,53087,53088,53089,53090,53091,53092, +53093,29490,53094,53095,53096,53097,29492,53098,53099,53100,53101,29480,53102, +53103,53104,53105,29491,53106,53107,53108,29493,53109,53110,53111,53112,53113, +53114,53115,53116,53117,53118,20535,53120,53121,53122,53123,29496,53124,53125, +53126,53127,22905,53128,53129,53130,53131,53132,53133,29497,53134,53135,53136, +53137,53138,53139,53140,53141,29495,53142,18532,29494,53143,53144,53145,53146, +29498,53147,53148,53149,53150,53151,29499,13376,53152,53312,53313,53314,53315, +53316,53317,53318,53319,53320,53321,53322,53323,53324,53325,28227,53326,53327, +53328,53329,53330,53331,29500,53332,53333,29501,53334,53335,53336,20778,53337, +53338,53339,29740,20550,53340,53341,53342,53343,53344,53345,20560,20828,53346, +53347,53348,53349,53350,53351,20302,53352,53353,15702,53354,20803,53355,53356, +53357,53358,53359,53360,53361,14946,24937,21058,28994,12857,53362,53363,12653, +28995,53364,18752,13124,53365,22898,53366,19237,53367,28996,53368,53369,53370, +53371,22100,53372,53373,53374,53376,53377,28997,29760,28998,53378,21548,28999, +53379,12352,29761,53380,53381,29762,53382,53383,13436,53384,17755,53385,53386, +53387,53388,19515,53389,53390,53391,20580,53392,53393,53394,53395,53396,19808, +53397,53398,53399,53400,53401,29000,53402,22899,53403,53404,53405,53406,53407, +53408,12603,53568,20270,53569,53570,53571,14372,53572,53573,53574,53575,53576, +29002,53577,53578,53579,53580,29003,53581,53582,53583,53584,12867,16721,53585, +53586,22320,29001,53587,53588,29004,53589,53590,53591,53592,29006,53593,53594, +53595,22902,53596,21089,21539,53597,53598,29763,18489,53599,53600,53601,53602, +53603,29764,53604,53605,29005,29007,16227,29008,53606,53607,29012,53608,53609, +53610,53611,53612,53613,53614,29014,29009,53615,18769,17761,53616,53617,53618, +16995,14716,53619,53620,29011,53621,29013,53622,53623,53624,14675,53625,53626, +53627,53628,53629,53630,53632,29019,53633,53634,53635,53636,53637,14934,53638, +12413,29017,53639,53640,53641,53642,53643,29016,29010,29018,53644,53645,53646, +53647,53648,29015,53649,53650,53651,18540,53652,53653,53654,53655,19786,29021, +53656,53657,53658,53659,25917,53660,53661,53662,29020,53663,29022,53664,53824, +53825,53826,53827,53828,53829,53830,53831,53832,29023,53833,53834,20325,53835, +53836,53837,53838,53839,53840,53841,53842,53843,53844,53845,53846,53847,53848, +53849,53850,53851,53852,53853,53854,53855,53856,53857,53858,53859,29765,15731, +53860,53861,53862,53863,53864,53865,29024,53866,53867,53868,53869,53870,53871, +53872,53873,53874,53875,53876,53877,53878,53879,53880,53881,53882,53883,53884, +53885,29025,53886,53888,53889,20087,53890,21034,53891,29051,53892,53893,14386, +53894,53895,53896,53897,53898,53899,53900,53901,53902,53903,53904,53905,53906, +53907,53908,53909,53910,53911,53912,53913,53914,53915,53916,53917,53918,53919, +53920,54080,54081,54082,54083,54084,54085,54086,54087,54088,54089,54090,54091, +54092,54093,54094,54095,54096,54097,54098,54099,54100,54101,54102,54103,54104, +54105,54106,54107,54108,54109,54110,15483,14683,54111,14694,17241,19027,27240, +16448,15989,27241,27242,27243,54112,27244,27245,27246,27247,15687,54113,54114, +54115,30075,54116,54117,54118,30077,54119,30078,54120,30076,54121,54122,54123, +54124,15714,54125,30241,13349,54126,54127,54128,54129,30242,54130,54131,54132, +30243,54133,54134,54135,27698,54136,54137,54138,54139,54140,54141,54142,54144, +54145,54146,54147,54148,20820,54149,54150,54151,54152,54153,54154,22890,54155, +54156,54157,54158,54159,54160,54161,54162,54163,54164,54165,54166,54167,54168, +54169,54170,54171,54172,54173,54174,54175,54176,54336,54337,54338,54339,54340, +54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351,54352,54353, +54354,54355,54356,54357,54358,54359,54360,54361,54362,54363,54364,54365,54366, +54367,30244,54368,54369,54370,54371,54372,54373,54374,54375,54376,28218,54377, +54378,54379,54380,54381,54382,54383,54384,54385,54386,54387,54388,54389,54390, +54391,54392,54393,54394,54395,54396,54397,54398,54400,54401,54402,54403,54404, +54405,54406,54407,54408,54409,54410,54411,54412,54413,54414,54415,54416,54417, +54418,54419,54420,54421,54422,54423,54424,54425,21810,54426,54427,54428,54429, +54430,54431,54432,54592,54593,54594,54595,54596,54597,54598,54599,21374,19548, +54600,54601,54602,54603,54604,54605,54606,54607,19012,54608,54609,54610,54611, +54612,54613,54614,54615,54616,54617,54618,54619,54620,54621,54622,54623,54624, +54625,54626,54627,54628,54629,54630,54631,54632,54633,54634,54635,54636,54637, +54638,54639,54640,54641,54642,54643,54644,54645,54646,54647,54648,54649,54650, +54651,54652,54653,54654,54656,54657,54658,54659,54660,54661,54662,54663,54664, +54665,54666,54667,54668,54669,54670,54671,54672,54673,54674,54675,54676,54677, +54678,54679,54680,54681,54682,54683,54684,54685,54686,54687,54688,54848,54849, +54850,54851,54852,54853,54854,54855,54856,54857,54858,54859,54860,54861,54862, +54863,54864,54865,54866,54867,54868,54869,54870,54871,54872,54873,54874,54875, +54876,54877,54878,54879,54880,54881,54882,25920,54883,54884,54885,54886,54887, +54888,54889,54890,54891,54892,54893,54894,54895,54896,54897,54898,54899,54900, +54901,54902,54903,54904,54905,54906,54907,54908,54909,54910,54912,54913,30245, +54914,54915,54916,54917,54918,54919,54920,54921,54922,54923,54924,54925,54926, +54927,54928,54929,54930,54931,54932,54933,54934,54935,54936,54937,54938,54939, +54940,54941,54942,54943,54944,55104,55105,55106,55107,55108,55109,55110,55111, +55112,55113,55114,55115,55116,55117,55118,55119,55120,55121,55122,55123,55124, +55125,55126,55127,55128,55129,55130,55131,55132,55133,55134,55135,15919,55136, +55137,55138,55139,55140,17961,55141,55142,55143,55144,55145,55146,55147,55148, +55149,55150,55151,55152,55153,55154,55155,55156,55157,55158,55159,55160,55161, +55162,55163,55164,55165,55166,55168,55169,55170,55171,55172,55173,55174,55175, +55176,55177,55178,55179,55180,55181,55182,55183,55184,55185,55186,55187,55188, +55189,55190,55191,55192,23077,15430,13865,14396,18511,15397,23078,23079,19542, +18499,23080,18045,55193,20789,21097,20790,15431,55194,15666,15204,23081,23082, +20808,23083,20589,13935,16987,55195,19279,14189,18792,14147,15991,22052,23084, +23085,17984,22375,18998,55196,21801,19295,21871,23086,22111,13386,23088,23087, +55197,21099,23089,23090,23091,19028,23092,18987,23093,23094,13135,22127,23095, +15152,13614,23096,23097,14702,20783,21096,23098,14403,20330,12911,23099,23100, +55198,15723,20060,21359,23101,20083,23102,21333,15205,23103,19253,19280,23104, +18283,22126,23105,17717,13889,23106,14156,16206,23107,23108,19245,23109,13687, +23110,16706,22331,23111,19512,55199,21098,17457,23112,13693,15185,23113,20531, +23114,23115,20029,23116,23117,23118,12919,23121,23119,20840,23120,17237,23122, +55200,23123,23124,23125,20539,21029,12409,23126,18219,23127,15735,17185,23128, +23129,17277,19511,23130,23131,16446,18007,23132,23133,18228,23134,23135,14664, +55360,55361,55362,55363,55364,55365,55366,55367,55368,15213,55369,55370,55371, +55372,13881,29816,55373,29817,55374,55375,19811,55376,55377,55378,55379,55380, +55381,55382,55383,30009,55384,55385,55386,55387,27488,55388,55389,55390,55391, +55392,55393,20339,15167,55394,55395,55396,55397,55398,55399,55400,14912,21541, +55401,55402,55403,55404,55405,55406,55407,24921,55408,55409,55410,55411,30068, +12586,12914,55412,55413,55414,55415,55416,55417,55418,30069,55419,55420,30071, +55421,55422,55424,14929,30070,55425,17202,55426,55427,55428,55429,55430,55431, +55432,30073,55433,55434,55435,30072,55436,55437,55438,55439,55440,55441,55442, +55443,55444,55445,55446,55447,55448,55449,55450,55451,55452,55453,55454,55455, +55456,55616,55617,55618,55619,55620,55621,55622,55623,55624,55625,55626,55627, +55628,55629,55630,55631,55632,55633,55634,55635,55636,55637,55638,55639,55640, +55641,55642,55643,55644,55645,55646,55647,55648,55649,55650,55651,55652,55653, +55654,55655,55656,55657,55658,55659,55660,55661,55662,55663,55664,55665,55666, +55667,55668,55669,55670,55671,55672,55673,55674,55675,55676,55677,55678,55680, +55681,55682,55683,55684,55685,55686,55687,55688,55689,55690,55691,55692,55693, +55694,55695,55696,55697,55698,55699,55700,55701,55702,55703,55704,55705,55706, +55707,55708,55709,55710,55711,55712,55872,55873,55874,55875,55876,55877,55878, +55879,55880,55881,55882,55883,55884,55885,55886,12596,21866,14394,55887,14641, +12870,21616,20301,12380,21835,15221,22090,14135,19504,17974,12641,14650,22140, +14689,14113,15482,27226,27227,19577,14707,27228,13435,17203,14161,14936,27229, +21620,27230,15446,15199,27231,16734,16952,21599,22346,27232,27233,27236,27234, +27235,18782,14387,13892,27237,19050,18765,13389,55888,55889,25177,17762,27238, +16437,55890,22328,27239,22316,18556,22611,22605,21598,55891,21625,18756,21294, +14419,13152,55892,18786,29814,55893,55894,55895,14933,55896,29815,55897,55898, +22367,55899,55900,29809,14384,21844,14415,18032,55901,55902,55903,55904,55905, +55906,55907,55908,55909,13123,55910,55911,29810,13100,55912,55913,55914,55915, +21565,18295,55916,55917,55918,55919,55920,29812,55921,55922,29811,55923,55924, +55925,55926,55927,55928,55929,55930,55931,55932,19531,55933,55934,55936,18468, +55937,55938,55939,55940,55941,55942,55943,55944,55945,55946,55947,55948,55949, +29813,55950,22371,17727,30016,55951,55952,30011,55953,30019,55954,30018,55955, +22074,30017,55956,55957,55958,21566,30020,55959,30028,55960,55961,55962,55963, +12367,13688,55964,30025,30026,55965,17756,55966,55967,55968,56128,30021,30022, +56129,56130,30023,30027,56131,15968,30024,14458,56132,56133,56134,30032,30035, +56135,56136,56137,16231,56138,14706,30012,30029,56139,56140,16951,56141,56142, +56143,19576,56144,15481,56145,30030,30031,30033,13925,30034,56146,30037,56147, +56148,56149,56150,56151,56152,56153,30013,56154,56155,56156,30036,21307,56157, +13164,56158,56159,19492,56160,56161,56162,56163,30038,56164,56165,56166,56167, +56168,56169,56170,56171,30039,15969,30040,56172,56173,19551,30043,56174,56175, +56176,56177,56178,12872,22361,56179,30041,56180,30042,30044,56181,30050,56182, +56183,56184,30048,56185,56186,56187,30047,30045,56188,56189,30049,56190,56192, +30046,30052,30053,56193,19555,56194,56195,25919,13624,30051,30056,19491,56196, +56197,56198,56199,56200,30054,30055,56201,56202,56203,56204,56205,56206,30014, +56207,56208,56209,56210,56211,56212,56213,56214,56215,56216,56217,56218,12612, +56219,56220,30015,56221,56222,13637,12900,56223,30060,30057,56224,13911,56384, +30061,56385,30058,56386,56387,56388,56389,56390,30059,56391,56392,13402,56393, +21610,56394,56395,56396,30062,56397,13177,56398,56399,56400,56401,56402,56403, +56404,30063,30065,56405,56406,56407,30064,56408,56409,56410,56411,56412,56413, +56414,30066,56415,30067,56416,56417,56418,56419,56420,56421,56422,56423,56424, +56425,56426,56427,18797,14634,56428,56429,18299,56430,56431,13923,56432,56433, +56434,56435,56436,56437,56438,19529,56439,56440,56441,56442,56443,56444,56445, +56446,56448,56449,56450,56451,56452,56453,56454,56455,56456,56457,56458,27174, +56459,56460,56461,56462,56463,56464,56465,56466,56467,56468,56469,56470,56471, +56472,56473,56474,56475,56476,56477,56478,56479,56480,56640,56641,56642,56643, +56644,56645,56646,56647,56648,56649,56650,56651,56652,56653,56654,56655,56656, +56657,56658,56659,56660,56661,56662,56663,56664,56665,56666,56667,56668,56669, +56670,56671,56672,56673,56674,56675,56676,56677,56678,56679,56680,56681,56682, +56683,56684,56685,56686,56687,56688,56689,56690,56691,56692,56693,56694,56695, +56696,56697,56698,56699,56700,56701,56702,56704,56705,56706,56707,56708,56709, +56710,56711,56712,56713,56714,56715,56716,56717,56718,56719,56720,56721,56722, +56723,56724,56725,56726,56727,56728,56729,56730,56731,56732,56733,56734,56735, +56736,56896,56897,56898,56899,56900,56901,56902,56903,56904,56905,56906,56907, +56908,56909,56910,56911,56912,56913,56914,56915,56916,56917,56918,56919,56920, +56921,56922,56923,56924,56925,56926,56927,56928,13109,21630,14700,20601,56929, +26989,22314,26990,16982,18541,14948,26991,26992,26993,22113,26994,26995,26997, +26996,26998,26999,18273,27000,21592,27001,15694,56930,27002,27003,15695,27004, +14376,16702,27005,12594,15188,14709,27006,56931,27169,27170,27171,14200,15405, +56932,19044,24654,21551,20285,21815,27172,21854,27173,20545,14652,56933,13383, +12633,56934,56935,56936,16433,56937,56938,56939,56940,12646,12647,56941,12648, +56942,56943,56944,56945,13117,18536,56946,56947,56948,56949,25921,56950,56951, +12639,56952,56953,56954,16713,13423,56955,56956,18216,21336,56957,18041,20792, +56958,14717,17013,56960,56961,56962,56963,56964,21293,56965,21579,15740,56966, +25922,14133,25923,56967,56968,15161,21858,56969,15736,21558,20005,16684,13145, +56970,56971,19574,56972,25926,25924,25928,56973,25930,25927,13647,17992,56974, +13692,25925,56975,19062,56976,56977,25929,56978,56979,56980,17236,12613,15395, +56981,56982,56983,22327,56984,56985,19787,19277,19018,19539,25932,25931,17510, +56986,56987,20769,20791,25933,56988,25936,56989,19768,22128,25935,13661,56990, +19774,56991,25937,13882,56992,57152,19752,14692,57153,19013,13137,19289,21612, +25938,14186,57154,57155,57156,25934,57157,57158,57159,57160,57161,57162,25941, +13438,25942,57163,57164,57165,57166,57167,25939,25940,57168,21085,57169,57170, +16991,12614,57171,21346,57172,57173,13917,19308,57174,25943,57175,57176,21366, +57177,57178,57179,57180,57181,12649,57182,13940,25946,25944,25945,13632,57183, +57184,57185,21061,25948,57186,57187,25950,57188,57189,57190,57191,57192,57193, +25949,18226,57194,21027,57195,57196,25947,57197,57198,57199,57200,21602,21850, +57201,57202,57203,57204,57205,25952,22385,57206,57207,57208,57209,57210,57211, +57212,25953,57213,12636,20859,57214,25954,25956,57216,57217,57218,57219,25955, +57220,57221,25957,57222,57223,57224,57225,57226,21080,57227,13643,57228,26463, +57229,23157,57230,23160,57231,23158,57232,23159,57233,57234,57235,23162,20559, +17479,57236,57237,12398,57238,57239,57240,20528,57241,23161,57242,21322,14890, +23330,18289,57243,23164,23163,18779,23165,57244,23329,22366,23166,16730,57245, +57246,23333,57247,57248,21364,57408,57409,23335,23332,57410,23336,57411,57412, +15676,57413,57414,57415,16457,23331,23334,22051,57416,23337,57417,57418,57419, +23341,57420,57421,57422,23342,23340,14914,57423,57424,57425,16164,23339,57426, +57427,57428,23338,21575,12863,57429,57430,23343,57431,14713,57432,23344,57433, +57434,57435,57436,13115,57437,57438,57439,13606,57440,57441,57442,57443,13884, +23345,57444,57445,57446,13941,57447,23346,57448,57449,57450,57451,57452,57453, +57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466, +57467,12617,57468,57469,57470,57472,23348,57473,57474,57475,23347,23349,57476, +57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,23351,57487,23350, +57488,57489,57490,57491,57492,57493,57494,23352,57495,57496,57497,57498,57499, +57500,57501,57502,57503,23353,57504,57664,23354,57665,57666,21327,29818,18293, +22339,17764,29820,29821,29819,57667,15942,57668,57669,57670,57671,20591,57672, +57673,14163,57674,57675,21581,19498,57676,57677,29986,29985,14888,29822,19286, +57678,57679,57680,29988,16466,57681,13162,57682,19754,29989,29987,15668,29992, +57683,29993,15693,17208,16225,19297,29994,57684,57685,57686,29990,29991,17520, +57687,57688,57689,57690,57691,29996,57692,13372,57693,22381,57694,13399,29995, +29998,57695,57696,29997,29999,20561,57697,57698,57699,57700,57701,57702,57703, +17233,18473,57704,57705,57706,57707,57708,57709,30000,30001,57710,57711,57712, +57713,57714,57715,30002,57716,57717,30003,30004,30005,57718,57719,57720,57721, +30007,30006,57722,57723,57724,57725,30008,57726,57728,57729,57730,57731,57732, +57733,57734,57735,57736,57737,57738,12873,57739,21332,19021,57740,16495,22104, +21040,16703,57741,15728,57742,57743,57744,57745,57746,57747,57748,57749,57750, +57751,14378,57752,57753,57754,57755,57756,57757,57758,57759,57760,57920,57921, +57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933,57934, +57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947, +57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960, +57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973, +57974,57975,57976,57977,57978,57979,57980,57981,57982,57984,57985,57986,57987, +57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,58000, +58001,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013, +58014,58015,58016,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185, +58186,58187,58188,58189,58190,58191,58192,58193,58194,58195,58196,58197,58198, +58199,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211, +58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,15480,58222,58223, +58224,58225,58226,58227,58228,58229,58230,58231,58232,58233,58234,58235,58236, +58237,58238,58240,58241,58242,58243,58244,58245,58246,58247,30278,58248,58249, +58250,58251,58252,58253,58254,58255,58256,58257,58258,58259,58260,58261,58262, +58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58432,58433,58434, +58435,58436,58437,30279,58438,58439,58440,58441,58442,58443,58444,58445,58446, +58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58457,58458,58459, +58460,58461,58462,30280,58463,58464,58465,58466,58467,58468,58469,58470,58471, +58472,58473,58474,58475,58476,58477,58478,58479,58480,58481,58482,58483,58484, +58485,58486,58487,58488,58489,58490,58491,58492,58493,58494,58496,58497,58498, +58499,58500,58501,58502,58503,58504,58505,58506,58507,58508,58509,58510,58511, +58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524, +58525,58526,58527,58528,58688,58689,58690,58691,58692,58693,58694,58695,58696, +58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709, +58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720,58721,58722, +58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735, +58736,58737,58738,58739,30281,58740,58741,58742,58743,58744,58745,58746,58747, +58748,58749,58750,58752,58753,58754,58755,58756,58757,58758,58759,58760,58761, +58762,58763,58764,58765,58766,58767,58768,58769,58770,58771,58772,58773,58774, +58775,58776,58777,58778,58779,58780,58781,58782,58783,30282,58784,58944,58945, +58946,58947,58948,58949,58950,58951,58952,58953,58954,58955,58956,58957,58958, +58959,58960,58961,58962,58963,58964,58965,58966,58967,58968,58969,58970,58971, +58972,58973,58974,58975,58976,58977,58978,30284,58979,58980,58981,58982,58983, +58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58995,58996, +58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59008,59009,59010, +59011,59012,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023, +59024,59025,59026,59027,59028,59029,59030,59031,59032,59033,59034,59035,59036, +59037,30283,59038,59039,59040,59200,59201,59202,59203,59204,59205,59206,59207, +30569,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,59219, +59220,59221,59222,59223,59224,59225,59226,59227,59228,59229,59230,59231,59232, +59233,59234,59235,59236,59237,59238,59239,59240,59241,59242,59243,59244,59245, +59246,59247,59248,59249,59250,59251,59252,59253,59254,59255,59256,59257,59258, +59259,59260,59261,59262,59264,59265,59266,59267,59268,59269,59270,59271,59272, +59273,59274,59275,59276,59277,59278,59279,59280,59281,59282,59283,59284,59285, +59286,59287,59288,59289,59290,59291,59292,59293,59294,59295,59296,59456,59457, +59458,59459,59460,59461,59462,59463,59464,59465,59466,59467,59468,59469,59470, +30285,59471,59472,59473,59474,59475,59476,59477,59478,59479,59480,59481,59482, +59483,59484,59485,59486,59487,59488,59489,59490,59491,59492,59493,59494,59495, +59496,59497,59498,59499,59500,59501,59502,59503,59504,59505,59506,59507,59508, +59509,59510,59511,59512,59513,59514,30286,59515,59516,59517,59518,59520,59521, +59522,59523,59524,59525,59526,59527,59528,59529,59530,59531,59532,59533,59534, +59535,59536,59537,59538,59539,59540,28228,28229,28230,21867,13860,28232,28231, +28233,28234,18213,28235,28236,59541,14128,13686,28237,28239,59542,28238,59543, +14406,28240,28241,28242,13915,13102,22099,17478,12597,14422,28243,28244,21567, +18261,15995,20057,14643,28246,28245,28248,28247,17701,28249,28250,18222,28251, +18223,28252,12839,28253,28254,28255,28256,28257,22378,28258,28259,15448,28260, +21323,19578,12844,16741,28261,18214,17197,59544,28262,28263,28264,28265,28266, +28267,28268,59545,28269,28270,28271,59546,59547,28272,28273,28274,28276,28275, +59548,28277,19757,16961,28278,28279,28280,21793,28281,20275,28282,28283,59549, +28284,28285,28449,28286,28450,14453,17274,28451,28452,15682,21055,12921,28453, +28454,28455,21112,28456,22141,28457,17996,59550,28458,28459,16692,28460,20346, +19320,28462,28461,13178,14712,28463,28464,20578,28465,28466,14182,20543,28467, +28468,28469,18545,19552,28470,28471,28472,28473,28474,21856,28475,13421,17194, +28476,59551,28477,28478,28479,59552,20093,28480,16992,13368,22326,15733,59712, +20295,28483,28481,28482,28484,13863,15484,15970,17228,28485,28486,59713,28487, +28495,28488,28489,28490,18242,28529,13901,28491,59714,28492,28493,13894,17214, +28494,59715,28496,28497,28498,21874,59716,28499,17527,59717,28500,17528,28501, +28502,14436,12407,28503,28504,28505,59718,28506,28507,28508,28509,59719,28510, +15925,28513,28511,28512,59720,28514,28515,16717,28516,28517,28518,28519,28520, +28521,28522,28523,28524,16472,59721,28525,16685,28526,28527,28528,59722,59723, +20322,59724,59725,59726,59727,59728,59729,59730,59731,13092,59732,59733,59734, +59735,59736,59737,59738,59739,59740,59741,59742,59743,59744,59745,59746,59747, +59748,59749,59750,59751,59752,59753,59754,59755,59756,59757,59758,59759,59760, +59761,59762,59763,59764,59765,59766,59767,59768,59769,59770,59771,59772,59773, +59774,59776,59777,59778,59779,59780,59781,59782,59783,59784,59785,59786,59787, +59788,59789,59790,59791,59792,59793,59794,59795,59796,59797,59798,59799,59800, +59801,59802,59803,59804,59805,59806,59807,59808,59968,59969,59970,59971,59972, +59973,59974,59975,59976,59977,59978,59979,59980,59981,59982,59983,59984,59985, +59986,59987,59988,59989,59990,59991,59992,59993,59994,59995,17221,25413,18753, +25414,59996,12629,20042,13363,18546,25415,20304,25416,15460,25417,25418,17222, +21794,17494,14699,20037,25419,17270,25420,59997,14119,14451,14930,25421,25422, +21572,25423,59998,25424,20811,25425,25426,25427,25428,20822,25429,12923,16443, +25430,59999,16427,25431,25432,25433,60000,25434,25435,60001,14391,23138,60002, +13907,60003,23140,23139,60004,60005,60006,60007,60008,60009,60010,23142,60011, +60012,60013,18542,60014,60015,23141,14144,20852,21109,21875,15703,60016,60017, +60018,60019,22376,23144,23143,60020,12322,19795,60021,23145,60022,14397,15434, +16957,16932,13122,23146,60023,16938,17456,15669,60024,60025,20318,60026,60027, +60028,23147,18754,60029,60030,60032,60033,60034,12637,60035,60036,60037,23148, +60038,13880,21562,60039,13181,60040,60041,23149,21577,20309,17763,60042,23150, +60043,60044,60045,60046,60047,23151,60048,23152,16746,19541,20317,60049,60050, +60051,60052,60053,60054,60055,60056,60057,60058,60059,60060,60061,21351,16929, +60062,23153,60063,60064,19301,60224,23154,60225,19302,21118,60226,60227,60228, +14452,60229,60230,23155,12335,20278,60231,60232,21839,60233,60234,60235,60236, +60237,60238,60239,60240,60241,60242,19309,60243,60244,60245,60246,60247,60248, +60249,60250,23156,60251,60252,25412,60253,60254,16677,60255,60256,30271,60257, +60258,30272,30273,17489,60259,18488,20835,60260,60261,20571,20805,15407,14669, +60262,28532,60263,60264,13382,21306,30274,13179,60265,60266,30275,60267,60268, +13681,60269,60270,60271,60272,60273,60274,60275,60276,60277,60278,30277,60279, +60280,60281,60282,60283,60284,60285,21354,30247,20777,60286,60288,60289,60290, +30249,60291,60292,60293,30248,60294,60295,16739,16471,60296,12578,60297,60298, +60299,60300,20077,60301,20584,30251,60302,60303,20342,60304,30250,21872,30252, +17209,60305,60306,60307,15220,30254,30253,60308,60309,60310,17502,60311,60312, +16728,60313,60314,60315,60316,60317,19242,60318,20284,60319,60320,60480,60481, +60482,60483,60484,60485,60486,60487,60488,30255,60489,60490,30256,60491,60492, +30257,60493,16950,60494,60495,60496,60497,60498,12372,17785,60499,60500,60501, +60502,30258,60503,60504,60505,60506,60507,60508,60509,60510,60511,60512,60513, +60514,60515,60516,60517,60518,60519,60520,60521,18272,30246,60522,60523,15928, +60524,60525,15922,60526,13669,60527,60528,14151,60529,16191,17234,17254,60530, +60531,22604,60532,60533,60534,14447,60535,60536,60537,60538,60539,60540,60541, +60542,60544,15737,20773,60545,12368,60546,60547,60548,60549,60550,30512,60551, +60552,60553,60554,60555,60556,60557,60558,30513,60559,60560,60561,60562,60563, +20524,60564,12336,60565,60566,60567,30514,30515,60568,30516,60569,60570,60571, +18250,60572,60573,60574,60575,60576,60736,60737,15951,60738,60739,30519,60740, +60741,60742,60743,60744,60745,60746,30518,60747,12638,60748,30517,60749,60750, +30520,60751,30521,60752,60753,60754,60755,60756,60757,60758,60759,60760,60761, +60762,60763,60764,60765,60766,60767,60768,60769,60770,60771,60772,60773,60774, +60775,60776,60777,60778,60779,60780,60781,60782,60783,60784,60785,60786,60787, +60788,60789,60790,60791,60792,60793,60794,60795,60796,60797,60798,60800,60801, +20004,18509,60802,14891,26680,26681,26682,15938,60803,60804,60805,60806,60807, +21108,60808,21583,18776,60809,60810,60811,60812,60813,60814,60815,60816,60817, +60818,60819,60820,60821,60822,60823,60824,60825,60826,60827,60828,60829,60830, +60831,60832,60992,60993,60994,60995,60996,60997,60998,60999,61000,61001,61002, +61003,61004,61005,61006,61007,61008,61009,61010,61011,61012,61013,61014,61015, +61016,61017,61018,61019,61020,61021,61022,61023,61024,61025,61026,61027,61028, +61029,61030,61031,61032,61033,61034,61035,61036,61037,61038,61039,61040,61041, +61042,61043,61044,61045,61046,61047,61048,61049,61050,61051,61052,61053,61054, +61056,61057,61058,61059,61060,61061,61062,61063,61064,61065,61066,61067,61068, +61069,61070,61071,61072,61073,61074,61075,61076,61077,61078,61079,61080,61081, +61082,61083,61084,61085,61086,61087,61088,61248,61249,61250,61251,61252,61253, +21043,13861,18282,29052,20334,19251,20587,26479,19815,14667,13913,29053,12388, +19276,29054,21540,16941,16748,17988,15921,29217,15445,61254,29218,29219,61255, +29220,21059,17973,61256,19783,29221,61257,21297,16197,19554,61258,29222,29223, +20821,13934,29224,29225,13663,29226,29227,61259,12924,29228,29229,18471,61260, +61261,61262,61263,61264,61265,61266,61267,61268,61269,61270,61271,61272,61273, +61274,61275,61276,61277,61278,61279,61280,61281,61282,61283,61284,61285,61286, +61287,61288,61289,61290,61291,61292,61293,61294,61295,61296,61297,14183,61298, +61299,27689,27690,27691,61300,27692,61301,61302,17966,27693,27694,61303,61304, +61305,14153,18995,61306,61307,61308,61309,61310,61312,61313,25144,30543,61314, +61315,61316,61317,61318,61319,61320,61321,61322,61323,61324,61325,61326,61327, +61328,61329,61330,61331,61332,61333,61334,61335,61336,61337,61338,61339,61340, +61341,61342,61343,61344,61504,61505,61506,61507,61508,30544,61509,61510,12877, +61511,61512,61513,61514,61515,61516,61517,61518,61519,61520,61521,61522,61523, +61524,61525,61526,61527,61528,61529,61530,61531,61532,61533,61534,61535,61536, +61537,61538,61539,30545,61540,61541,61542,61543,61544,61545,61546,61547,61548, +61549,61550,61551,61552,61553,61554,61555,61556,61557,61558,61559,61560,61561, +61562,61563,61564,61565,61566,61568,61569,61570,61571,61572,61573,61574,61575, +61576,61577,30547,30546,61578,61579,61580,61581,61582,61583,61584,61585,61586, +61587,61588,61589,61590,25147,61591,15394,61592,25148,25149,25150,25151,25152, +25153,14137,21115,15652,19022,12581,19271,61593,25154,13948,18500,25155,61594, +61595,15688,61596,12669,25156,61597,13942,25157,17497,61598,61599,25158,20314, +14685,25159,16417,61600,25160,12918,61760,25161,61761,16755,25162,25163,17016, +25164,25165,25166,19031,22584,22885,20323,61762,61763,61764,61765,61766,61767, +61768,61769,61770,61771,61772,28709,61773,61774,23600,61775,61776,61777,61778, +61779,61780,61781,61782,61783,61784,61785,61786,61787,61788,61789,61790,61791, +61792,61793,61794,61795,61796,61797,61798,61799,61800,61801,61802,61803,61804, +61805,61806,61807,61808,61809,61810,61811,61812,61813,61814,61815,61816,61817, +61818,61819,61820,61821,61822,61824,61825,61826,61827,61828,61829,61830,61831, +61832,61833,61834,61835,61836,61837,61838,61839,61840,61841,61842,61843,61844, +61845,61846,61847,61848,61849,61850,61851,61852,61853,61854,61855,61856,62016, +62017,62018,62019,62020,62021,62022,62023,62024,62025,62026,62027,62028,62029, +62030,62031,62032,62033,62034,62035,62036,62037,62038,62039,62040,62041,62042, +62043,62044,62045,62046,62047,62048,62049,62050,62051,62052,62053,62054,62055, +62056,62057,62058,62059,62060,62061,62062,62063,62064,62065,62066,62067,62068, +62069,62070,62071,62072,62073,62074,62075,62076,62077,62078,62080,62081,62082, +62083,62084,62085,62086,62087,62088,62089,62090,62091,62092,62093,62094,62095, +62096,62097,62098,62099,62100,62101,62102,62103,62104,62105,62106,62107,62108, +62109,62110,62111,62112,62272,62273,62274,62275,62276,62277,62278,62279,62280, +62281,62282,62283,62284,62285,62286,62287,62288,62289,17005,21542,19796,20785, +13147,18301,62290,12853,16959,26208,19003,26209,26210,15956,26211,22308,19797, +26213,15453,26212,26214,26215,17006,62291,15678,26216,16998,14887,26217,62292, +26218,13138,20841,62293,62294,16165,26219,18031,26220,26221,62295,62296,26222, +17965,26223,62297,18727,26224,26225,26226,25913,26227,26228,16994,26229,26230, +22120,26231,62298,26232,14663,62299,62300,62301,62302,62303,62304,62305,30523, +30522,62306,62307,62308,62309,30526,30524,14881,62310,30527,62311,30528,62312, +62313,62314,30530,30529,30532,62315,62316,30531,62317,62318,62319,62320,62321, +30533,30534,62322,62323,62324,62325,30535,62326,19304,62327,62328,62329,62330, +14431,62331,62332,62333,62334,62336,62337,30548,62338,30549,62339,62340,62341, +62342,30550,62343,62344,62345,62346,30552,62347,30554,62348,30551,62349,62350, +62351,62352,62353,62354,62355,62356,62357,30555,62358,30553,62359,62360,62361, +62362,62363,62364,62365,22359,62366,62367,62368,62528,30556,62529,62530,62531, +62532,62533,62534,30557,62535,62536,62537,30558,62538,62539,62540,62541,62542, +62543,62544,62545,62546,62547,62548,30559,62549,62550,62551,30560,62552,62553, +62554,62555,62556,62557,62558,62559,62560,62561,62562,23371,62563,62564,22570, +62565,62566,62567,62568,62569,62570,62571,62572,25975,14701,62573,62574,62575, +62576,16253,15210,30537,17991,30536,62577,30538,30540,30539,62578,62579,62580, +30541,62581,20026,62582,30542,62583,62584,17447,62585,62586,62587,62588,62589, +62590,62592,62593,62594,62595,62596,62597,62598,62599,62600,62601,62602,62603, +62604,62605,62606,62607,62608,62609,62610,62611,62612,62613,62614,62615,62616, +62617,62618,62619,62620,62621,62622,62623,62624,62784,62785,62786,62787,62788, +62789,62790,62791,62792,62793,62794,62795,62796,62797,62798,62799,62800,62801, +62802,62803,62804,62805,62806,62807,62808,62809,62810,62811,62812,62813,62814, +62815,62816,62817,62818,62819,62820,62821,62822,62823,62824,62825,62826,62827, +62828,62829,62830,62831,62832,62833,62834,62835,62836,62837,62838,62839,62840, +62841,62842,62843,62844,62845,62846,62848,62849,62850,62851,62852,62853,62854, +62855,62856,62857,62858,62859,62860,62861,62862,62863,62864,62865,62866,62867, +62868,62869,62870,62871,62872,62873,62874,62875,62876,62877,62878,62879,62880, +63040,63041,63042,63043,63044,63045,63046,63047,63048,63049,63050,63051,63052, +63053,63054,63055,63056,63057,63058,63059,63060,63061,63062,63063,63064,63065, +63066,63067,63068,63069,63070,63071,63072,63073,63074,63075,63076,63077,63078, +63079,63080,63081,63082,63083,63084,63085,63086,63087,63088,63089,63090,63091, +63092,63093,63094,63095,63096,63097,63098,63099,63100,63101,63102,63104,63105, +63106,63107,63108,63109,63110,63111,63112,63113,63114,63115,63116,63117,63118, +63119,63120,63121,63122,63123,63124,63125,63126,63127,63128,63129,63130,63131, +63132,63133,63134,63135,63136,63296,63297,63298,63299,63300,63301,63302,63303, +63304,63305,63306,63307,63308,63309,63310,63311,63312,63313,63314,63315,63316, +63317,63318,63319,63320,63321,63322,63323,63324,63325,63326,63327,63328,63329, +63330,63331,63332,63333,63334,63335,63336,63337,63338,63339,63340,63341,63342, +63343,63344,63345,63346,63347,63348,63349,63350,63351,63352,63353,63354,63355, +63356,63357,63358,63360,21347,63361,63362,30287,63363,16947,30288,63364,63365, +30289,30290,30291,30292,63366,63367,30294,63368,12587,30295,63369,30296,30297, +30298,63370,30299,30300,63371,63372,63373,63374,30301,30302,20298,63375,30303, +30304,30305,30306,30307,30308,16496,30309,30310,30311,30312,30313,63376,30314, +63377,30315,30316,63378,30317,30318,30319,30320,30321,30322,30323,30324,15912, +63379,30325,30326,30327,30328,63380,63381,63382,63383,63384,18554,30329,30330, +30331,30332,63385,63386,30333,30334,30497,30498,30499,30500,30501,63387,63388, +30502,30503,30504,12654,30505,30506,30507,63389,63390,30508,30509,16731,30510, +63391,63392,30511,63552,63553,63554,63555,63556,63557,63558,63559,63560,63561, +63562,63563,63564,63565,63566,63567,63568,63569,63570,63571,63572,63573,63574, +63575,63576,63577,63578,63579,63580,63581,63582,63583,63584,63585,63586,63587, +63588,63589,63590,63591,63592,63593,63594,63595,63596,63597,63598,63599,63600, +63601,63602,63603,63604,63605,63606,63607,63608,63609,63610,63611,63612,63613, +63614,63616,63617,63618,63619,63620,63621,63622,63623,63624,63625,63626,63627, +63628,63629,63630,63631,63632,63633,63634,63635,63636,63637,63638,63639,63640, +63641,63642,63643,63644,63645,63646,63647,63648,63808,63809,63810,63811,63812, +63813,63814,63815,63816,63817,63818,63819,63820,63821,63822,63823,63824,63825, +63826,63827,63828,63829,63830,63831,63832,63833,63834,63835,63836,63837,63838, +63839,63840,63841,63842,63843,63844,63845,63846,63847,63848,63849,63850,63851, +63852,63853,63854,63855,63856,63857,63858,63859,63860,63861,63862,63863,63864, +63865,63866,63867,63868,63869,63870,63872,63873,63874,63875,63876,63877,63878, +63879,63880,63881,63882,63883,63884,63885,63886,63887,63888,63889,63890,63891, +63892,63893,63894,63895,63896,63897,63898,63899,63900,63901,63902,63903,63904, +64064,64065,64066,64067,64068,64069,64070,64071,64072,64073,64074,64075,64076, +64077,64078,64079,64080,64081,64082,64083,64084,64085,64086,64087,64088,64089, +64090,64091,64092,64093,64094,64095,64096,64097,64098,64099,64100,64101,64102, +64103,64104,64105,64106,64107,64108,64109,64110,64111,64112,64113,64114,64115, +64116,64117,64118,64119,64120,64121,64122,64123,64124,64125,64126,64128,64129, +64130,64131,64132,64133,64134,64135,64136,64137,64138,64139,64140,64141,64142, +64143,64144,64145,64146,64147,64148,64149,64150,64151,64152,64153,64154,64155, +64156,64157,64158,64159,64160,64320,64321,64322,64323,64324,64325,64326,64327, +64328,64329,64330,64331,64332,64333,64334,64335,64336,64337,64338,64339,64340, +64341,64342,64343,64344,64345,64346,64347,17521,28719,15398,28720,17273,64348, +17720,20795,64349,28721,28722,28723,28724,28725,20796,64350,20844,64351,28727, +28726,21543,64352,19794,28728,28730,28729,28731,28732,64353,64354,14443,28733, +14952,64355,28734,28735,15977,28736,13932,28737,28738,28739,28740,18485,28741, +28742,64356,28743,17780,64357,28744,64358,64359,64360,28745,64361,28746,30525, +64362,28747,28748,28749,64363,28750,64364,64365,64366,64367,28751,14935,64368, +28752,28753,28754,28755,28756,28757,28758,28760,64369,64370,21285,28759,64371, +28761,64372,64373,64374,64375,64376,64377,64378,64379,64380,64381,30010,16953, +64382,64384,30564,64385,64386,64387,64388,30565,30566,64389,64390,30567,64391, +64392,64393,64394,64395,64396,30568,16948,64397,64398,64399,64400,64401,64402, +64403,64404,64405,30570,64406,30571,64407,64408,64409,64410,64411,64412,17011, +64413,64414,64415,64416,64576,64577,64578,64579,64580,64581,64582,64583,64584, +29808,64585,64586,64587,29807,64588,64589,17001,64590,30561,30562,64591,64592, +64593,64594,64595,15174,64596,64597,64598,64599,22884,64600,64601,64602,19058, +16488,28708,64603,14938,64604,64605,18221,64606,64607,64608,17452,64609,64610, +30572,30573,30574,64611,30576,30575,64612,30577,64613,64614,30580,64615,30579, +64616,30578,30581,64617,64618,64619,64620,30582,64621,64622,64623,64624,64625, +64626,64627,64628,64629,28009,64630,28010,28011,64631,30268,64632,64633,64634, +64635,64636,64637,64638,64640,64641,64642,64643,64644,30269,64645,30270,13862, +64646,22590,64647,64648,14660,64649,64650,64651,22587,64652,23601,64653,64654, +64655,64656,64657,64658,19059,64659,30583,64660,64661,64662,64663,64664,64665, +64666,64667,64668,30584,64669,64670,30585,64671,64672,64832,64833,64834,64835, +64836,30587,64837,30586,64838,12615,64839,30588,30589,64840,64841,64842,64843, +64844,30590,64845,64846,64847,64848,64849,64850,64851,64852,64853,64854,64855, +18027,27700,64856,64857,64858,64859,64860,64861,64862,64863,64864,64865,64866, +64867,64868,64869,64870,64871,64872,64873,64874,64875,64876,64877,64878,64879, +64880,64881,64882,64883,64884,64885,64886,64887,64888,64889,64890,64891,64892, +64893,64894,64896,64897,64898,64899,64900,64901,13149,30259,64902,64903,30260, +16740,30261,30262,30263,30264,30265,30266,18467,30267,64904,64905,64906,64907, +64908,64909,64910,64911,64912,64913,64914,64915,16762,14632,28008,64916,64917, +64918,14698,22879,64919,64920,64921,64922,64923,64924,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64925,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64926,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64927,N,N,N,N,N,N,N,N,N,64928, +65088,65089,65090,65091,N,65092,N,65093,65094,N,N,N,65095,N,N,N,N,N,N,65096, +65097,65098,N,65099,65100,N,N,65101,65102,65103,43349,42738,N,42740,42741, +42720,42721,42736,42737,42722,42723,42734,42735,42726,42727,42724,42725,42728, +42729,42730,42731,N,N,N,N,43368,43369,43370,43371,43372,43373,43374,43375, +43376,43377,N,43378,43379,43380,43381,N,43382,43383,43384,43385,43386,43387, +43388,43389,43390,43392,43393,43394,43395,43396,N,43397,43398,43399,43400, +8993,8994,8995,8551,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007, +9008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,9022, +9023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037, +9038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052, +9053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,9065,9066,9067, +9068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082, +9083,9084,9085,8491,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8553,8554,43350,9086,43351,8996, +}; + +static const struct unim_index gbcommon_encmap[256] = { +{__gbcommon_encmap+0,164,252},{__gbcommon_encmap+89,1,220},{__gbcommon_encmap+ +309,81,217},{__gbcommon_encmap+446,145,201},{__gbcommon_encmap+503,1,81},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gbcommon_encmap+584, +16,59},{__gbcommon_encmap+628,3,153},{__gbcommon_encmap+779,8,191},{ +__gbcommon_encmap+963,18,18},{__gbcommon_encmap+964,96,155},{__gbcommon_encmap ++1024,0,229},{__gbcommon_encmap+1254,5,66},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gbcommon_encmap+1316,0,254},{ +__gbcommon_encmap+1571,5,41},{__gbcommon_encmap+1608,32,163},{ +__gbcommon_encmap+1740,142,213},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{__gbcommon_encmap+1812,0,255},{__gbcommon_encmap+2068,0,255},{ +__gbcommon_encmap+2324,0,255},{__gbcommon_encmap+2580,0,255},{ +__gbcommon_encmap+2836,0,255},{__gbcommon_encmap+3092,0,255},{ +__gbcommon_encmap+3348,0,255},{__gbcommon_encmap+3604,0,255},{ +__gbcommon_encmap+3860,0,255},{__gbcommon_encmap+4116,0,255},{ +__gbcommon_encmap+4372,0,255},{__gbcommon_encmap+4628,0,255},{ +__gbcommon_encmap+4884,0,255},{__gbcommon_encmap+5140,0,255},{ +__gbcommon_encmap+5396,0,255},{__gbcommon_encmap+5652,0,255},{ +__gbcommon_encmap+5908,0,255},{__gbcommon_encmap+6164,0,255},{ +__gbcommon_encmap+6420,0,255},{__gbcommon_encmap+6676,0,255},{ +__gbcommon_encmap+6932,0,255},{__gbcommon_encmap+7188,0,255},{ +__gbcommon_encmap+7444,0,255},{__gbcommon_encmap+7700,0,255},{ +__gbcommon_encmap+7956,0,255},{__gbcommon_encmap+8212,0,255},{ +__gbcommon_encmap+8468,0,255},{__gbcommon_encmap+8724,0,255},{ +__gbcommon_encmap+8980,0,255},{__gbcommon_encmap+9236,0,255},{ +__gbcommon_encmap+9492,0,255},{__gbcommon_encmap+9748,0,255},{ +__gbcommon_encmap+10004,0,255},{__gbcommon_encmap+10260,0,255},{ +__gbcommon_encmap+10516,0,255},{__gbcommon_encmap+10772,0,255},{ +__gbcommon_encmap+11028,0,255},{__gbcommon_encmap+11284,0,255},{ +__gbcommon_encmap+11540,0,255},{__gbcommon_encmap+11796,0,255},{ +__gbcommon_encmap+12052,0,255},{__gbcommon_encmap+12308,0,255},{ +__gbcommon_encmap+12564,0,255},{__gbcommon_encmap+12820,0,255},{ +__gbcommon_encmap+13076,0,255},{__gbcommon_encmap+13332,0,255},{ +__gbcommon_encmap+13588,0,255},{__gbcommon_encmap+13844,0,255},{ +__gbcommon_encmap+14100,0,255},{__gbcommon_encmap+14356,0,255},{ +__gbcommon_encmap+14612,0,255},{__gbcommon_encmap+14868,0,255},{ +__gbcommon_encmap+15124,0,255},{__gbcommon_encmap+15380,0,255},{ +__gbcommon_encmap+15636,0,255},{__gbcommon_encmap+15892,0,255},{ +__gbcommon_encmap+16148,0,255},{__gbcommon_encmap+16404,0,255},{ +__gbcommon_encmap+16660,0,255},{__gbcommon_encmap+16916,0,255},{ +__gbcommon_encmap+17172,0,255},{__gbcommon_encmap+17428,0,255},{ +__gbcommon_encmap+17684,0,255},{__gbcommon_encmap+17940,0,255},{ +__gbcommon_encmap+18196,0,255},{__gbcommon_encmap+18452,0,255},{ +__gbcommon_encmap+18708,0,255},{__gbcommon_encmap+18964,0,255},{ +__gbcommon_encmap+19220,0,255},{__gbcommon_encmap+19476,0,255},{ +__gbcommon_encmap+19732,0,255},{__gbcommon_encmap+19988,0,255},{ +__gbcommon_encmap+20244,0,255},{__gbcommon_encmap+20500,0,255},{ +__gbcommon_encmap+20756,0,255},{__gbcommon_encmap+21012,0,255},{ +__gbcommon_encmap+21268,0,255},{__gbcommon_encmap+21524,0,255},{ +__gbcommon_encmap+21780,0,255},{__gbcommon_encmap+22036,0,255},{ +__gbcommon_encmap+22292,0,255},{__gbcommon_encmap+22548,0,165},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{__gbcommon_encmap+22714,44,241},{__gbcommon_encmap+22912,12,41},{0,0,0},{0, +0,0},{0,0,0},{__gbcommon_encmap+22942,48,107},{__gbcommon_encmap+23002,1,229}, +}; + +static const ucs2_t __gb18030ext_decmap[2729] = { +58566,58567,58568,58569,58570,58571,58572,58573,58574,58575,58576,58577,58578, +58579,58580,58581,58582,58583,58584,58585,58586,58587,58588,58589,58590,58591, +58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604, +58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,58617, +58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,U,58629, +58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642, +58643,58644,58645,58646,58647,58648,58649,58650,58651,58652,58653,58654,58655, +58656,58657,58658,58659,58660,58661,58662,58663,58664,58665,58666,58667,58668, +58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681, +58682,58683,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694, +58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707, +58708,58709,58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720, +58721,58722,58723,58724,U,58725,58726,58727,58728,58729,58730,58731,58732, +58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745, +58746,58747,58748,58749,58750,58751,58752,58753,58754,58755,58756,58757,U,U,U, +U,U,U,U,U,U,U,59238,59239,59240,59241,59242,59243,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,8364, +59245,U,U,U,U,U,U,U,U,U,U,59246,59247,U,U,U,U,U,U,U,U,U,U,U,U,59248,59249, +58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770, +58771,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783, +58784,58785,58786,58787,58788,58789,58790,58791,58792,58793,58794,58795,58796, +58797,58798,58799,58800,58801,58802,58803,58804,58805,58806,58807,58808,58809, +58810,58811,58812,58813,58814,58815,58816,58817,58818,58819,58820,U,58821, +58822,58823,58824,58825,58826,58827,58828,58829,58830,58831,58832,58833,58834, +58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847, +58848,58849,58850,58851,58852,58853,58854,58855,58856,58857,58858,58859,58860, +58861,58862,58863,58864,58865,58866,58867,58868,58869,58870,58871,58872,58873, +58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886, +58887,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899, +58900,58901,58902,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912, +58913,58914,58915,58916,U,58917,58918,58919,58920,58921,58922,58923,58924, +58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937, +58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,59250,59251,59252,59253,59254,59255,59256,59257,59258,59259,59260,58950, +58951,58952,58953,58954,58955,58956,58957,58958,58959,58960,58961,58962,58963, +58964,58965,58966,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976, +58977,58978,58979,58980,58981,58982,58983,58984,58985,58986,58987,58988,58989, +58990,58991,58992,58993,58994,58995,58996,58997,58998,58999,59000,59001,59002, +59003,59004,59005,59006,59007,59008,59009,59010,59011,59012,U,59013,59014, +59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027, +59028,59029,59030,59031,59032,59033,59034,59035,59036,59037,59038,59039,59040, +59041,59042,59043,59044,59045,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59261,59262,59263,59264,59265, +59266,59267,59268,59046,59047,59048,59049,59050,59051,59052,59053,59054,59055, +59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,59068, +59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,59079,59080,59081, +59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,59093,59094, +59095,59096,59097,59098,59099,59100,59101,59102,59103,59104,59105,59106,59107, +59108,U,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119, +59120,59121,59122,59123,59124,59125,59126,59127,59128,59129,59130,59131,59132, +59133,59134,59135,59136,59137,59138,59139,59140,59141,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,59269,59270,59271,59272,59273,59274,59275,59276,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59277,59278,59279,59280,59281,59282, +59283,U,U,U,U,U,U,U,U,U,U,U,U,59284,59285,U,U,U,U,U,59286,U,U,59287,59288, +59289,59290,59291,59292,59293,59294,59295,59142,59143,59144,59145,59146,59147, +59148,59149,59150,59151,59152,59153,59154,59155,59156,59157,59158,59159,59160, +59161,59162,59163,59164,59165,59166,59167,59168,59169,59170,59171,59172,59173, +59174,59175,59176,59177,59178,59179,59180,59181,59182,59183,59184,59185,59186, +59187,59188,59189,59190,59191,59192,59193,59194,59195,59196,59197,59198,59199, +59200,59201,59202,59203,59204,U,59205,59206,59207,59208,59209,59210,59211, +59212,59213,59214,59215,59216,59217,59218,59219,59220,59221,59222,59223,59224, +59225,59226,59227,59228,59229,59230,59231,59232,59233,59234,59235,59236,59237, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59296,59297, +59298,59299,59300,59301,59302,59303,59304,59305,59306,59307,59308,59309,59310, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59311,59312, +59313,59314,59315,59316,59317,59318,59319,59320,59321,59322,59323,59324,59325, +59326,59327,59328,59329,59330,59331,59332,59333,59334,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59335,U,U,505,U,59337,59338,59339,59340,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,59341,59342, +59343,59344,59345,59346,59347,59348,59349,59350,59351,59352,59353,59354,59355, +59356,59357,59358,59359,59360,59361,59362,U,U,59363,U,59364,59365,59366,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +12350,12272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283, +U,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391, +59392,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404, +59405,59406,59407,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353, +57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366, +57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379, +57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57391,57392, +57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405, +57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418, +57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431, +57432,57433,57434,57435,57436,57437,57438,57439,57440,57441,57442,57443,57444, +57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457, +57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57470, +57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483, +57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496, +57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509, +57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522, +57523,57524,57525,57526,57527,57528,57529,57530,57531,57532,57533,57534,57535, +57536,57537,57538,57539,57540,57541,57542,57543,57544,57545,57546,57547,57548, +57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561, +57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574, +57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587, +57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600, +57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613, +57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,57626, +57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639, +57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652, +57653,57654,57655,57656,57657,57658,57659,57660,57661,57662,57663,57664,57665, +57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678, +57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691, +57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704, +57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717, +57718,57719,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730, +57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743, +57744,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756, +57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769, +57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782, +57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795, +57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808, +57809,57810,57811,57812,57813,57814,57815,57816,57817,57818,57819,57820,57821, +57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834, +57835,57836,57837,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847, +57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860, +57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873, +57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886, +57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899, +57900,57901,57902,57903,57904,57905,57906,57907,59408,59409,59410,59411,59412, +57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920, +57921,57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933, +57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946, +57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959, +57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972, +57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985, +57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998, +57999,58000,58001,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011, +58012,58013,58014,58015,58016,58017,58018,58019,58020,58021,58022,58023,58024, +58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037, +58038,58039,58040,58041,58042,58043,58044,58045,58046,58047,58048,58049,58050, +58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063, +58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076, +58077,58078,58079,58080,58081,58082,58083,58084,58085,58086,58087,58088,58089, +58090,58091,58092,58093,58094,58095,58096,58097,58098,58099,58100,58101,58102, +58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58114,58115, +58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128, +58129,58130,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141, +58142,58143,58144,58145,58146,58147,58148,58149,58150,58151,58152,58153,58154, +58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167, +58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180, +58181,58182,58183,58184,58185,58186,58187,58188,58189,58190,58191,58192,58193, +58194,58195,58196,58197,58198,58199,58200,58201,58202,58203,58204,58205,58206, +58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219, +58220,58221,58222,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232, +58233,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245, +58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258, +58259,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271, +58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,58284, +58285,58286,58287,58288,58289,58290,58291,58292,58293,58294,58295,58296,58297, +58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310, +58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323, +58324,58325,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336, +58337,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349, +58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362, +58363,58364,58365,58366,58367,58368,58369,58370,58371,58372,58373,58374,58375, +58376,58377,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388, +58389,58390,58391,58392,58393,58394,58395,58396,58397,58398,58399,58400,58401, +58402,58403,58404,58405,58406,58407,58408,58409,58410,58411,58412,58413,58414, +58415,58416,58417,58418,58419,58420,58421,58422,58423,58424,58425,58426,58427, +58428,58429,58430,58431,58432,58433,58434,58435,58436,58437,58438,58439,58440, +58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453, +58454,58455,58456,58457,58458,58459,58460,58461,58462,58463,58464,58465,58466, +58467,58468,58469,58470,58471,11905,59414,59415,59416,11908,13427,13383,11912, +11915,59422,13726,13850,13838,11916,11927,14702,14616,59430,14799,14815,14963, +14800,59435,59436,15182,15470,15584,11943,59441,59442,11946,16470,16735,11950, +17207,11955,11958,11959,59451,17329,17324,11963,17373,17622,18017,17996,59459, +U,18211,18217,18300,18317,11978,18759,18810,18813,18818,18819,18821,18822, +18847,18843,18871,18870,59476,59477,19619,19615,19616,19617,19575,19618,19731, +19732,19733,19734,19735,19736,19737,19886,59492,58472,58473,58474,58475,58476, +58477,58478,58479,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489, +58490,58491,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58502, +58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515, +58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528, +58529,58530,58531,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541, +58542,58543,58544,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554, +58555,58556,58557,58558,58559,58560,58561,58562,58563,58564,58565, +}; + +static const struct dbcs_index gb18030ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_decmap+0,64, +160},{__gb18030ext_decmap+97,64,254},{__gb18030ext_decmap+288,64,160},{ +__gb18030ext_decmap+385,64,254},{__gb18030ext_decmap+576,64,254},{ +__gb18030ext_decmap+767,64,254},{__gb18030ext_decmap+958,64,254},{ +__gb18030ext_decmap+1149,150,254},{__gb18030ext_decmap+1254,88,254},{ +__gb18030ext_decmap+1421,161,254},{__gb18030ext_decmap+1515,161,254},{ +__gb18030ext_decmap+1609,161,254},{__gb18030ext_decmap+1703,161,254},{ +__gb18030ext_decmap+1797,161,254},{__gb18030ext_decmap+1891,161,254},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__gb18030ext_decmap+1985,250,254},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_decmap ++1990,161,254},{__gb18030ext_decmap+2084,161,254},{__gb18030ext_decmap+2178, +161,254},{__gb18030ext_decmap+2272,161,254},{__gb18030ext_decmap+2366,161,254 +},{__gb18030ext_decmap+2460,161,254},{__gb18030ext_decmap+2554,80,254},{0,0,0 +}, +}; + +static const DBCHAR __gb18030ext_encmap[3227] = { +43199,41699,65104,N,N,65108,N,N,N,65111,N,N,65112,65117,N,N,N,N,N,N,N,N,N,N, +65118,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65131,N,N,65134,N,N,N,65137,N,N,N,N,65139, +N,N,65140,65141,N,N,N,65145,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65156,43402,43403, +43404,43405,43406,43407,43408,43409,43410,43411,43412,43413,43401,65110,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,65109,65114,65116,N,N,N,N,N,N,N,N,N,N,N,65115,65120,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65119,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65122,65125,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65123, +65124,65128,65129,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65130,65135,65136,65138,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65144,N,N,N,N,65143,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65146,65147,65149, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65148,65152,N,N,N,N,N,65153,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +65154,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65155,65157,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65158, +N,N,65159,N,N,N,N,65160,65161,N,65162,65163,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,65165,N,N,N,65164,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65167, +65166,65174,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65171,65172,65173,65175,65170,65176,65177,65178,65179,65180,65181, +65182,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65183, +43681,43682,43683,43684,43685,43686,43687,43688,43689,43690,43691,43692,43693, +43694,43695,43696,43697,43698,43699,43700,43701,43702,43703,43704,43705,43706, +43707,43708,43709,43710,43711,43712,43713,43714,43715,43716,43717,43718,43719, +43720,43721,43722,43723,43724,43725,43726,43727,43728,43729,43730,43731,43732, +43733,43734,43735,43736,43737,43738,43739,43740,43741,43742,43743,43744,43745, +43746,43747,43748,43749,43750,43751,43752,43753,43754,43755,43756,43757,43758, +43759,43760,43761,43762,43763,43764,43765,43766,43767,43768,43769,43770,43771, +43772,43773,43774,43937,43938,43939,43940,43941,43942,43943,43944,43945,43946, +43947,43948,43949,43950,43951,43952,43953,43954,43955,43956,43957,43958,43959, +43960,43961,43962,43963,43964,43965,43966,43967,43968,43969,43970,43971,43972, +43973,43974,43975,43976,43977,43978,43979,43980,43981,43982,43983,43984,43985, +43986,43987,43988,43989,43990,43991,43992,43993,43994,43995,43996,43997,43998, +43999,44000,44001,44002,44003,44004,44005,44006,44007,44008,44009,44010,44011, +44012,44013,44014,44015,44016,44017,44018,44019,44020,44021,44022,44023,44024, +44025,44026,44027,44028,44029,44030,44193,44194,44195,44196,44197,44198,44199, +44200,44201,44202,44203,44204,44205,44206,44207,44208,44209,44210,44211,44212, +44213,44214,44215,44216,44217,44218,44219,44220,44221,44222,44223,44224,44225, +44226,44227,44228,44229,44230,44231,44232,44233,44234,44235,44236,44237,44238, +44239,44240,44241,44242,44243,44244,44245,44246,44247,44248,44249,44250,44251, +44252,44253,44254,44255,44256,44257,44258,44259,44260,44261,44262,44263,44264, +44265,44266,44267,44268,44269,44270,44271,44272,44273,44274,44275,44276,44277, +44278,44279,44280,44281,44282,44283,44284,44285,44286,44449,44450,44451,44452, +44453,44454,44455,44456,44457,44458,44459,44460,44461,44462,44463,44464,44465, +44466,44467,44468,44469,44470,44471,44472,44473,44474,44475,44476,44477,44478, +44479,44480,44481,44482,44483,44484,44485,44486,44487,44488,44489,44490,44491, +44492,44493,44494,44495,44496,44497,44498,44499,44500,44501,44502,44503,44504, +44505,44506,44507,44508,44509,44510,44511,44512,44513,44514,44515,44516,44517, +44518,44519,44520,44521,44522,44523,44524,44525,44526,44527,44528,44529,44530, +44531,44532,44533,44534,44535,44536,44537,44538,44539,44540,44541,44542,44705, +44706,44707,44708,44709,44710,44711,44712,44713,44714,44715,44716,44717,44718, +44719,44720,44721,44722,44723,44724,44725,44726,44727,44728,44729,44730,44731, +44732,44733,44734,44735,44736,44737,44738,44739,44740,44741,44742,44743,44744, +44745,44746,44747,44748,44749,44750,44751,44752,44753,44754,44755,44756,44757, +44758,44759,44760,44761,44762,44763,44764,44765,44766,44767,44768,44769,44770, +44771,44772,44773,44774,44775,44776,44777,44778,44779,44780,44781,44782,44783, +44784,44785,44786,44787,44788,44789,44790,44791,44792,44793,44794,44795,44796, +44797,44798,44961,44962,44963,44964,44965,44966,44967,44968,44969,44970,44971, +44972,44973,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44984, +44985,44986,44987,44988,44989,44990,44991,44992,44993,44994,44995,44996,44997, +44998,44999,45000,45001,45002,45003,45004,45005,45006,45007,45008,45009,45010, +45011,45012,45013,45014,45015,45016,45017,45018,45019,45020,45021,45022,45023, +45024,45025,45026,45027,45028,45029,45030,45031,45032,45033,45034,45035,45036, +45037,45038,45039,45040,45041,45042,45043,45044,45045,45046,45047,45048,45049, +45050,45051,45052,45053,45054,63649,63650,63651,63652,63653,63654,63655,63656, +63657,63658,63659,63660,63661,63662,63663,63664,63665,63666,63667,63668,63669, +63670,63671,63672,63673,63674,63675,63676,63677,63678,63679,63680,63681,63682, +63683,63684,63685,63686,63687,63688,63689,63690,63691,63692,63693,63694,63695, +63696,63697,63698,63699,63700,63701,63702,63703,63704,63705,63706,63707,63708, +63709,63710,63711,63712,63713,63714,63715,63716,63717,63718,63719,63720,63721, +63722,63723,63724,63725,63726,63727,63728,63729,63730,63731,63732,63733,63734, +63735,63736,63737,63738,63739,63740,63741,63742,63905,63906,63907,63908,63909, +63910,63911,63912,63913,63914,63915,63916,63917,63918,63919,63920,63921,63922, +63923,63924,63925,63926,63927,63928,63929,63930,63931,63932,63933,63934,63935, +63936,63937,63938,63939,63940,63941,63942,63943,63944,63945,63946,63947,63948, +63949,63950,63951,63952,63953,63954,63955,63956,63957,63958,63959,63960,63961, +63962,63963,63964,63965,63966,63967,63968,63969,63970,63971,63972,63973,63974, +63975,63976,63977,63978,63979,63980,63981,63982,63983,63984,63985,63986,63987, +63988,63989,63990,63991,63992,63993,63994,63995,63996,63997,63998,64161,64162, +64163,64164,64165,64166,64167,64168,64169,64170,64171,64172,64173,64174,64175, +64176,64177,64178,64179,64180,64181,64182,64183,64184,64185,64186,64187,64188, +64189,64190,64191,64192,64193,64194,64195,64196,64197,64198,64199,64200,64201, +64202,64203,64204,64205,64206,64207,64208,64209,64210,64211,64212,64213,64214, +64215,64216,64217,64218,64219,64220,64221,64222,64223,64224,64225,64226,64227, +64228,64229,64230,64231,64232,64233,64234,64235,64236,64237,64238,64239,64240, +64241,64242,64243,64244,64245,64246,64247,64248,64249,64250,64251,64252,64253, +64254,64417,64418,64419,64420,64421,64422,64423,64424,64425,64426,64427,64428, +64429,64430,64431,64432,64433,64434,64435,64436,64437,64438,64439,64440,64441, +64442,64443,64444,64445,64446,64447,64448,64449,64450,64451,64452,64453,64454, +64455,64456,64457,64458,64459,64460,64461,64462,64463,64464,64465,64466,64467, +64468,64469,64470,64471,64472,64473,64474,64475,64476,64477,64478,64479,64480, +64481,64482,64483,64484,64485,64486,64487,64488,64489,64490,64491,64492,64493, +64494,64495,64496,64497,64498,64499,64500,64501,64502,64503,64504,64505,64506, +64507,64508,64509,64510,64673,64674,64675,64676,64677,64678,64679,64680,64681, +64682,64683,64684,64685,64686,64687,64688,64689,64690,64691,64692,64693,64694, +64695,64696,64697,64698,64699,64700,64701,64702,64703,64704,64705,64706,64707, +64708,64709,64710,64711,64712,64713,64714,64715,64716,64717,64718,64719,64720, +64721,64722,64723,64724,64725,64726,64727,64728,64729,64730,64731,64732,64733, +64734,64735,64736,64737,64738,64739,64740,64741,64742,64743,64744,64745,64746, +64747,64748,64749,64750,64751,64752,64753,64754,64755,64756,64757,64758,64759, +64760,64761,64762,64763,64764,64765,64766,64929,64930,64931,64932,64933,64934, +64935,64936,64937,64938,64939,64940,64941,64942,64943,64944,64945,64946,64947, +64948,64949,64950,64951,64952,64953,64954,64955,64956,64957,64958,64959,64960, +64961,64962,64963,64964,64965,64966,64967,64968,64969,64970,64971,64972,64973, +64974,64975,64976,64977,64978,64979,64980,64981,64982,64983,64984,64985,64986, +64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64998,64999, +65000,65001,65002,65003,65004,65005,65006,65007,65008,65009,65010,65011,65012, +65013,65014,65015,65016,65017,65018,65019,65020,65021,65022,65185,65186,65187, +65188,65189,65190,65191,65192,65193,65194,65195,65196,65197,65198,65199,65200, +65201,65202,65203,65204,65205,65206,65207,65208,65209,65210,65211,65212,65213, +65214,65215,65216,65217,65218,65219,65220,65221,65222,65223,65224,65225,65226, +65227,65228,65229,65230,65231,65232,65233,65234,65235,65236,65237,65238,65239, +65240,65241,65242,65243,65244,65245,65246,65247,65248,65249,65250,65251,65252, +65253,65254,65255,65256,65257,65258,65259,65260,65261,65262,65263,65264,65265, +65266,65267,65268,65269,65270,65271,65272,65273,65274,65275,65276,65277,65278, +41280,41281,41282,41283,41284,41285,41286,41287,41288,41289,41290,41291,41292, +41293,41294,41295,41296,41297,41298,41299,41300,41301,41302,41303,41304,41305, +41306,41307,41308,41309,41310,41311,41312,41313,41314,41315,41316,41317,41318, +41319,41320,41321,41322,41323,41324,41325,41326,41327,41328,41329,41330,41331, +41332,41333,41334,41335,41336,41337,41338,41339,41340,41341,41342,41344,41345, +41346,41347,41348,41349,41350,41351,41352,41353,41354,41355,41356,41357,41358, +41359,41360,41361,41362,41363,41364,41365,41366,41367,41368,41369,41370,41371, +41372,41373,41374,41375,41376,41536,41537,41538,41539,41540,41541,41542,41543, +41544,41545,41546,41547,41548,41549,41550,41551,41552,41553,41554,41555,41556, +41557,41558,41559,41560,41561,41562,41563,41564,41565,41566,41567,41568,41569, +41570,41571,41572,41573,41574,41575,41576,41577,41578,41579,41580,41581,41582, +41583,41584,41585,41586,41587,41588,41589,41590,41591,41592,41593,41594,41595, +41596,41597,41598,41600,41601,41602,41603,41604,41605,41606,41607,41608,41609, +41610,41611,41612,41613,41614,41615,41616,41617,41618,41619,41620,41621,41622, +41623,41624,41625,41626,41627,41628,41629,41630,41631,41632,41792,41793,41794, +41795,41796,41797,41798,41799,41800,41801,41802,41803,41804,41805,41806,41807, +41808,41809,41810,41811,41812,41813,41814,41815,41816,41817,41818,41819,41820, +41821,41822,41823,41824,41825,41826,41827,41828,41829,41830,41831,41832,41833, +41834,41835,41836,41837,41838,41839,41840,41841,41842,41843,41844,41845,41846, +41847,41848,41849,41850,41851,41852,41853,41854,41856,41857,41858,41859,41860, +41861,41862,41863,41864,41865,41866,41867,41868,41869,41870,41871,41872,41873, +41874,41875,41876,41877,41878,41879,41880,41881,41882,41883,41884,41885,41886, +41887,41888,42048,42049,42050,42051,42052,42053,42054,42055,42056,42057,42058, +42059,42060,42061,42062,42063,42064,42065,42066,42067,42068,42069,42070,42071, +42072,42073,42074,42075,42076,42077,42078,42079,42080,42081,42082,42083,42084, +42085,42086,42087,42088,42089,42090,42091,42092,42093,42094,42095,42096,42097, +42098,42099,42100,42101,42102,42103,42104,42105,42106,42107,42108,42109,42110, +42112,42113,42114,42115,42116,42117,42118,42119,42120,42121,42122,42123,42124, +42125,42126,42127,42128,42129,42130,42131,42132,42133,42134,42135,42136,42137, +42138,42139,42140,42141,42142,42143,42144,42304,42305,42306,42307,42308,42309, +42310,42311,42312,42313,42314,42315,42316,42317,42318,42319,42320,42321,42322, +42323,42324,42325,42326,42327,42328,42329,42330,42331,42332,42333,42334,42335, +42336,42337,42338,42339,42340,42341,42342,42343,42344,42345,42346,42347,42348, +42349,42350,42351,42352,42353,42354,42355,42356,42357,42358,42359,42360,42361, +42362,42363,42364,42365,42366,42368,42369,42370,42371,42372,42373,42374,42375, +42376,42377,42378,42379,42380,42381,42382,42383,42384,42385,42386,42387,42388, +42389,42390,42391,42392,42393,42394,42395,42396,42397,42398,42399,42400,42560, +42561,42562,42563,42564,42565,42566,42567,42568,42569,42570,42571,42572,42573, +42574,42575,42576,42577,42578,42579,42580,42581,42582,42583,42584,42585,42586, +42587,42588,42589,42590,42591,42592,42593,42594,42595,42596,42597,42598,42599, +42600,42601,42602,42603,42604,42605,42606,42607,42608,42609,42610,42611,42612, +42613,42614,42615,42616,42617,42618,42619,42620,42621,42622,42624,42625,42626, +42627,42628,42629,42630,42631,42632,42633,42634,42635,42636,42637,42638,42639, +42640,42641,42642,42643,42644,42645,42646,42647,42648,42649,42650,42651,42652, +42653,42654,42655,42656,42816,42817,42818,42819,42820,42821,42822,42823,42824, +42825,42826,42827,42828,42829,42830,42831,42832,42833,42834,42835,42836,42837, +42838,42839,42840,42841,42842,42843,42844,42845,42846,42847,42848,42849,42850, +42851,42852,42853,42854,42855,42856,42857,42858,42859,42860,42861,42862,42863, +42864,42865,42866,42867,42868,42869,42870,42871,42872,42873,42874,42875,42876, +42877,42878,42880,42881,42882,42883,42884,42885,42886,42887,42888,42889,42890, +42891,42892,42893,42894,42895,42896,42897,42898,42899,42900,42901,42902,42903, +42904,42905,42906,42907,42908,42909,42910,42911,42912,41643,41644,41645,41646, +41647,41648,N,41700,41711,41712,41725,41726,42228,42229,42230,42231,42232, +42233,42234,42235,42236,42237,42238,42487,42488,42489,42490,42491,42492,42493, +42494,42681,42682,42683,42684,42685,42686,42687,42688,42713,42714,42715,42716, +42717,42718,42719,42732,42733,42739,42742,42743,42744,42745,42746,42747,42748, +42749,42750,42946,42947,42948,42949,42950,42951,42952,42953,42954,42955,42956, +42957,42958,42959,42960,42994,42995,42996,42997,42998,42999,43000,43001,43002, +43003,43004,43005,43006,43158,43159,43160,43161,43162,43163,43164,43165,43166, +43167,43168,43196,N,43201,43202,43203,43204,43242,43243,43244,43245,43246, +43247,43248,43249,43250,43251,43252,43253,43254,43255,43256,43257,43258,43259, +43260,43261,43262,43352,43355,43357,43358,43359,N,N,N,N,N,N,N,N,N,N,N,N,N, +43415,43416,43417,43418,43419,43420,43421,43422,43423,43424,43425,43426,43427, +43504,43505,43506,43507,43508,43509,43510,43511,43512,43513,43514,43515,43516, +43517,43518,55290,55291,55292,55293,55294,N,65105,65106,65107,N,N,N,N,N,65113, +N,N,N,N,N,N,N,65121,N,N,N,N,65126,65127,N,N,N,N,65132,65133,N,N,N,N,N,N,N,N, +65142,N,N,N,N,N,N,N,65150,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65168,65169,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,65184, +}; + +static const struct unim_index gb18030ext_encmap[256] = { +{0,0,0},{__gb18030ext_encmap+0,249,249},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_encmap+1,172,172 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_encmap+2,129,202},{ +__gb18030ext_encmap+76,240,251},{__gb18030ext_encmap+88,62,62},{0,0,0},{0,0,0 +},{0,0,0},{__gb18030ext_encmap+89,71,115},{__gb18030ext_encmap+134,158,158},{ +__gb18030ext_encmap+135,14,26},{0,0,0},{0,0,0},{__gb18030ext_encmap+148,24,223 +},{__gb18030ext_encmap+348,115,115},{__gb18030ext_encmap+349,78,78},{ +__gb18030ext_encmap+350,110,224},{0,0,0},{0,0,0},{0,0,0},{__gb18030ext_encmap+ +465,86,86},{__gb18030ext_encmap+466,95,95},{0,0,0},{__gb18030ext_encmap+467, +55,221},{__gb18030ext_encmap+634,214,214},{0,0,0},{__gb18030ext_encmap+635,76, +97},{__gb18030ext_encmap+657,35,141},{0,0,0},{__gb18030ext_encmap+764,71,183}, +{0,0,0},{0,0,0},{__gb18030ext_encmap+877,119,163},{__gb18030ext_encmap+922,19, +174},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{__gb18030ext_encmap+1078,0,255},{__gb18030ext_encmap+1334,0,255 +},{__gb18030ext_encmap+1590,0,255},{__gb18030ext_encmap+1846,0,255},{ +__gb18030ext_encmap+2102,0,255},{__gb18030ext_encmap+2358,0,255},{ +__gb18030ext_encmap+2614,0,255},{__gb18030ext_encmap+2870,0,255},{ +__gb18030ext_encmap+3126,0,100},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + + +static const struct _gb18030_to_unibmp_ranges { + Py_UNICODE first, last; + DBCHAR base; +} gb18030_to_unibmp_ranges[] = { +{128,163,0},{165,166,36},{169,175,38},{178,182,45},{184,214,50},{216,223,81},{ +226,231,89},{235,235,95},{238,241,96},{244,246,100},{248,248,103},{251,251,104 +},{253,256,105},{258,274,109},{276,282,126},{284,298,133},{300,323,148},{325, +327,172},{329,332,175},{334,362,179},{364,461,208},{463,463,306},{465,465,307 +},{467,467,308},{469,469,309},{471,471,310},{473,473,311},{475,475,312},{477, +504,313},{506,592,341},{594,608,428},{610,710,443},{712,712,544},{716,728,545 +},{730,912,558},{930,930,741},{938,944,742},{962,962,749},{970,1024,750},{1026 +,1039,805},{1104,1104,819},{1106,8207,820},{8209,8210,7922},{8215,8215,7924},{ +8218,8219,7925},{8222,8228,7927},{8231,8239,7934},{8241,8241,7943},{8244,8244, +7944},{8246,8250,7945},{8252,8363,7950},{8365,8450,8062},{8452,8452,8148},{ +8454,8456,8149},{8458,8469,8152},{8471,8480,8164},{8482,8543,8174},{8556,8559, +8236},{8570,8591,8240},{8596,8597,8262},{8602,8711,8264},{8713,8718,8374},{ +8720,8720,8380},{8722,8724,8381},{8726,8729,8384},{8731,8732,8388},{8737,8738, +8390},{8740,8740,8392},{8742,8742,8393},{8748,8749,8394},{8751,8755,8396},{ +8760,8764,8401},{8766,8775,8406},{8777,8779,8416},{8781,8785,8419},{8787,8799, +8424},{8802,8803,8437},{8808,8813,8439},{8816,8852,8445},{8854,8856,8482},{ +8858,8868,8485},{8870,8894,8496},{8896,8977,8521},{8979,9311,8603},{9322,9331, +8936},{9372,9471,8946},{9548,9551,9046},{9588,9600,9050},{9616,9618,9063},{ +9622,9631,9066},{9634,9649,9076},{9652,9659,9092},{9662,9669,9100},{9672,9674, +9108},{9676,9677,9111},{9680,9697,9113},{9702,9732,9131},{9735,9736,9162},{ +9738,9791,9164},{9793,9793,9218},{9795,11904,9219},{11906,11907,11329},{11909, +11911,11331},{11913,11914,11334},{11917,11926,11336},{11928,11942,11346},{ +11944,11945,11361},{11947,11949,11363},{11951,11954,11366},{11956,11957,11370 +},{11960,11962,11372},{11964,11977,11375},{11979,12271,11389},{12284,12287, +11682},{12292,12292,11686},{12312,12316,11687},{12319,12320,11692},{12330, +12349,11694},{12351,12352,11714},{12436,12442,11716},{12447,12448,11723},{ +12535,12539,11725},{12543,12548,11730},{12586,12831,11736},{12842,12848,11982 +},{12850,12962,11989},{12964,13197,12102},{13200,13211,12336},{13215,13216, +12348},{13218,13251,12350},{13253,13261,12384},{13263,13264,12393},{13267, +13268,12395},{13270,13382,12397},{13384,13426,12510},{13428,13725,12553},{ +13727,13837,12851},{13839,13849,12962},{13851,14615,12973},{14617,14701,13738 +},{14703,14798,13823},{14801,14814,13919},{14816,14962,13933},{14964,15181, +14080},{15183,15469,14298},{15471,15583,14585},{15585,16469,14698},{16471, +16734,15583},{16736,17206,15847},{17208,17323,16318},{17325,17328,16434},{ +17330,17372,16438},{17374,17621,16481},{17623,17995,16729},{17997,18016,17102 +},{18018,18210,17122},{18212,18216,17315},{18218,18299,17320},{18301,18316, +17402},{18318,18758,17418},{18760,18809,17859},{18811,18812,17909},{18814, +18817,17911},{18820,18820,17915},{18823,18842,17916},{18844,18846,17936},{ +18848,18869,17939},{18872,19574,17961},{19576,19614,18664},{19620,19730,18703 +},{19738,19885,18814},{19887,19967,18962},{40870,55295,19043},{59244,59244, +33469},{59336,59336,33470},{59367,59379,33471},{59413,59413,33484},{59417, +59421,33485},{59423,59429,33490},{59431,59434,33497},{59437,59440,33501},{ +59443,59450,33505},{59452,59458,33513},{59460,59475,33520},{59478,59491,33536 +},{59493,63787,33550},{63789,63864,37845},{63866,63892,37921},{63894,63974, +37948},{63976,63984,38029},{63986,64011,38038},{64016,64016,38064},{64018, +64018,38065},{64021,64023,38066},{64025,64030,38069},{64034,64034,38075},{ +64037,64038,38076},{64042,65071,38078},{65074,65074,39108},{65093,65096,39109 +},{65107,65107,39113},{65112,65112,39114},{65127,65127,39115},{65132,65280, +39116},{65375,65503,39265},{65510,65535,39394},{0,0,39420}}; diff --git a/sys/src/cmd/python/Modules/cjkcodecs/mappings_hk.h b/sys/src/cmd/python/Modules/cjkcodecs/mappings_hk.h new file mode 100644 index 000000000..a526e90d5 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/mappings_hk.h @@ -0,0 +1,2340 @@ +static const ucs2_t __big5hkscs_decmap[6095] = { +62211,62212,62213,62214,62215,268,62217,209,205,62220,62221,203,8168,62224, +202,62226,62227,62228,62229,270,62231,62232,256,193,461,192,274,201,282,200, +332,211,465,210,62245,7870,62247,7872,202,257,225,462,224,593,275,233,283,232, +299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,476,252,62276,7871,62278, +7873,234,609,62282,62283,41897,4421,U,25866,U,U,20029,28381,40270,37343,U,U, +30517,25745,20250,20264,20392,20822,20852,20892,20964,21153,21160,21307,21326, +21457,21464,22242,22768,22788,22791,22834,22836,23398,23454,23455,23706,24198, +24635,25993,26622,26628,26725,27982,28860,30005,32420,32428,32442,32455,32463, +32479,32518,32567,33402,33487,33647,35270,35774,35810,36710,36711,36718,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29713,31996, +32205,26950,31433,21031,U,U,U,U,37260,30904,37214,32956,U,36107,33014,2535,U, +U,32927,40647,19661,40393,40460,19518,40438,28686,40458,41267,13761,U,28314, +33342,29977,U,18705,39532,39567,40857,31111,33900,7626,1488,10982,20004,20097, +20096,20103,20159,20203,20279,13388,20413,15944,20483,20616,13437,13459,13477, +20870,22789,20955,20988,20997,20105,21113,21136,21287,13767,21417,13649,21424, +13651,21442,21539,13677,13682,13953,21651,21667,21684,21689,21712,21743,21784, +21795,21800,13720,21823,13733,13759,21975,13765,32132,21797,U,3138,3349,20779, +21904,11462,14828,833,36422,19896,38117,16467,32958,30586,11320,14900,18389, +33117,27122,19946,25821,3452,4020,3285,4340,25741,36478,3734,3083,3940,11433, +33366,17619,U,3398,39501,33001,18420,20135,11458,39602,14951,38388,16365, +13574,21191,38868,30920,11588,40302,38933,U,17369,24741,25780,21731,11596, +11210,4215,14843,4207,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,26330,26390,31136,25834,20562,3139,36456,8609,35660,1841,U,18443, +425,16378,22643,11661,U,17864,1276,24727,3916,3478,21881,16571,17338,U,19124, +10854,4253,33194,39157,3484,25465,14846,10101,36288,22177,25724,15939,U,42497, +3593,10959,11465,U,4296,14786,14738,14854,33435,13688,24137,8391,22098,3889, +11442,38688,13500,27709,20027,U,U,30068,11915,8712,42587,36045,3706,3124, +26652,32659,4303,10243,10553,13819,20963,3724,3981,3754,16275,3888,3399,4431, +3660,U,3755,2985,3400,4288,4413,16377,9878,25650,4013,13300,30265,11214,3454, +3455,11345,11349,14872,3736,4295,3886,42546,27472,36050,36249,36042,38314, +21708,33476,21945,U,40643,39974,39606,30558,11758,28992,33133,33004,23580, +25970,33076,14231,21343,32957,37302,3834,3599,3703,3835,13789,19947,13833, +3286,22191,10165,4297,3600,3704,4216,4424,33287,5205,3705,20048,11684,23124, +4125,4126,4341,4342,22428,3601,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,30356,33485,4021,3707,20862,14083,4022,4480,21208,41661, +18906,6202,16759,33404,22681,21096,13850,22333,31666,23400,18432,19244,40743, +18919,39967,39821,23412,12605,22011,13810,22153,20008,22786,7105,63608,38737, +134,20059,20155,13630,23587,24401,24516,14586,25164,25909,27514,27701,27706, +28780,29227,20012,29357,18665,32594,31035,31993,32595,25194,13505,U,25419, +32770,32896,26130,26961,21341,34916,35265,30898,35744,36125,38021,38264,38271, +38376,36367,38886,39029,39118,39134,39267,38928,40060,40479,40644,27503,63751, +20023,135,38429,25143,38050,20539,28158,40051,62842,15817,34959,16718,28791, +23797,19232,20941,13657,23856,24866,35378,36775,37366,29073,26393,29626,12929, +41223,15499,6528,19216,30948,29698,20910,34575,16393,27235,41658,16931,34319, +U,31274,39239,35562,38741,28749,21284,8318,37876,30425,35299,62884,30685, +20131,20464,20668,20015,20247,62891,21556,32139,22674,22736,7606,24210,24217, +24514,10002,25995,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,13305,26905,27203,15459,27903,U,29184,17669,29580,16091,18963,23317, +29881,35715,23716,22165,31379,31724,31939,32364,33528,34199,62924,34960,62926, +36537,62928,36815,34143,39392,37409,62933,36281,5183,16497,17058,23066,U,U,U, +39016,26475,17014,22333,U,34262,18811,33471,28941,19585,28020,23931,27413, +28606,62956,62957,23446,62959,U,32347,23870,23880,23894,15868,14351,23972, +23993,14368,14392,24130,24253,24357,24451,14600,14612,14655,14669,24791,24893, +23781,14729,25015,25017,25039,14776,25132,25232,25317,25368,14840,22193,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,14851,25570, +25595,25607,25690,14923,25792,23829,22049,40863,14999,25990,15037,26111,26195, +15090,26258,15138,26390,15170,26532,26624,15192,26698,26756,15218,15217,15227, +26889,26947,29276,26980,27039,27013,15292,27094,15325,27237,27252,27249,27266, +15340,27289,15346,27307,27317,27348,27382,27521,27585,27626,27765,27818,15563, +27906,27910,27942,28033,15599,28068,28081,28181,28184,28201,28294,35264,28347, +28386,28378,40831,28392,28393,28452,28468,15686,16193,28545,28606,15722,15733, +29111,23705,15754,28716,15761,28752,28756,28783,28799,28809,805,17345,13809, +3800,16087,22462,28371,28990,22496,13902,27042,35817,23412,31305,22753,38105, +31333,31357,22956,31419,31408,31426,31427,29137,25741,16842,31450,31453,31466, +16879,21682,23553,31499,31573,31529,21262,23806,31650,31599,33692,23476,27775, +31696,33825,31634,U,23840,15789,23653,33938,31738,U,31797,23745,31812,31875, +18562,31910,26237,17784,31945,31943,31974,31860,31987,31989,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32359,17693,28228,32093, +28374,29837,32137,32171,28981,32179,U,16471,24617,32228,15635,32245,6137, +32229,33645,U,24865,24922,32366,32402,17195,37996,32295,32576,32577,32583, +31030,25296,39393,32663,25425,32675,5729,104,17756,14182,17667,33594,32762, +25737,U,32776,32797,U,32815,41095,27843,32827,32828,32865,10004,18825,26150, +15843,26344,26405,32935,35400,33031,33050,22704,9974,27775,25752,20408,25831, +5258,33304,6238,27219,19045,19093,17530,33321,2829,27218,15742,20473,5373, +34018,33634,27402,18855,13616,6003,15864,33450,26907,63892,16859,34123,33488, +33562,3606,6068,14017,12669,13658,33403,33506,33560,16011,28067,27397,27543, +13774,15807,33565,21996,33669,17675,28069,33708,U,33747,13438,28372,27223, +34138,13462,28226,12015,33880,23524,33905,15827,17636,27303,33866,15541,31064, +U,27542,28279,28227,34014,U,33681,17568,33939,34020,23697,16960,23744,17731, +34100,23282,28313,17703,34163,17686,26559,34326,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34341,34363,34241,28808,34306,5506, +28877,63922,17770,34344,13896,6306,21495,29594,34430,34673,41208,34798,11303, +34737,34778,34831,22113,34412,26710,17935,34885,34886,30176,15801,30180,34910, +34972,18011,34996,34997,25537,35013,30583,30479,35207,35210,U,U,35239,35260, +35365,35303,31012,31421,35484,30611,37374,35472,31321,31465,31546,16271,18195, +31544,29052,35596,35615,21552,21861,35647,35660,35661,35497,19066,35728,35739, +35503,5855,17941,34895,35995,32084,32143,63956,14117,32083,36054,32152,32189, +36114,36099,6416,36059,28764,36113,19657,16080,36265,32770,4116,18826,15228, +33212,28940,31463,36525,36534,36547,37588,36633,36653,33637,33810,36773,37635, +41631,2640,36787,18730,35294,34109,15803,24312,12898,36857,40980,34492,34049, +8997,14720,28375,36919,34108,31422,36961,34156,34315,37032,34579,37060,34534, +37038,U,37223,15088,37289,37316,31916,35123,7817,37390,27807,37441,37474, +21945,U,35526,15515,35596,21979,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,3377,37676,37739,35553,35819,28815,23235,35554,35557, +18789,37444,35820,35897,35839,37747,37979,36540,38277,38310,37926,38304,28662, +17081,9850,34520,4732,15918,18911,27676,38523,38550,16748,38563,28373,25050, +38582,30965,35552,38589,21452,18849,27832,628,25616,37039,37093,19153,6421, +13066,38705,34370,38710,18959,17725,17797,19177,28789,23361,38683,U,37333, +38743,23370,37355,38751,37925,20688,12471,12476,38793,38815,38833,38846,38848, +38866,38880,21612,38894,29724,37939,U,38901,37917,31098,19153,38964,38963, +38987,39014,15118,29045,15697,1584,16732,22278,39114,39095,39112,39111,19199, +27943,5843,21936,39137,39142,39148,37752,39225,18985,19314,38999,39173,39413, +39436,39483,39440,39512,22309,14020,37041,39893,39648,39650,39685,39668,19470, +39700,39725,34304,20532,39732,27048,14531,12413,39760,39744,40254,23109,6243, +39822,16971,39938,39935,39948,40552,40404,40887,41362,41387,41185,41251,41439, +40318,40323,41268,40462,26760,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,40388,8539,41363,41504,6459,41523,40249,41145,41652,40592, +40597,40606,40610,19764,40618,40623,17252,40641,15200,14821,15645,20274,14270, +35883,40706,40712,19350,37924,28066,40727,U,40761,22175,22154,40773,39352, +37003,38898,33919,40802,40809,31452,40846,29206,19390,18805,18875,29047,18936, +17224,19025,29598,35802,6394,31135,35198,36406,37737,37875,35396,37612,37761, +37835,35180,17593,29207,16107,30578,31299,28880,17523,17400,29054,6127,28835, +6334,13721,16071,6277,21551,6136,14114,5883,6201,14049,6004,6353,24395,14115, +5824,22363,18981,5118,4776,5062,5302,34051,13990,U,33877,18836,29029,15921, +21852,16123,28754,17652,14062,39325,28454,26617,14131,15381,15847,22636,6434, +26640,16471,14143,16609,16523,16655,27681,21707,22174,26289,22162,4063,2984, +3597,37830,35603,37788,20216,20779,14361,17462,20156,1125,895,20299,20362, +22097,23144,427,971,14745,778,1044,13365,20265,704,36531,629,35546,524,20120, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,20685, +20749,20386,20227,18958,16010,20290,20526,20588,20609,20428,20453,20568,20732, +U,U,U,U,28278,13717,15929,16063,28018,6276,16009,20904,20931,1504,17629,1187, +1170,1169,36218,35484,1806,21081,21156,2163,21217,U,18042,29068,17292,3104, +18860,4324,27089,3613,U,16094,29849,29716,29782,29592,19342,19132,16525,21456, +13700,29199,16585,21940,837,21709,3014,22301,37469,38644,37734,22493,22413, +22399,13886,22731,23193,35398,5882,5999,5904,23084,22968,37519,23166,23247, +23058,22854,6643,6241,17045,14069,27909,29763,23073,24195,23169,35799,1043, +37856,29836,4867,28933,18802,37896,35323,37821,14240,23582,23710,24158,24136, +6550,6524,15086,24269,23375,6403,6404,14081,6304,14045,5886,14035,33066,35399, +7610,13426,35240,24332,24334,6439,6059,23147,5947,23364,34324,30205,34912, +24702,10336,9771,24539,16056,9647,9662,37000,28531,25024,62,70,9755,24985, +24984,24693,11419,11527,18132,37197,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,25713,18021,11114,14889,11042,13392,39146,11896, +25399,42075,25782,25393,25553,18915,11623,25252,11425,25659,25963,26994,15348, +12430,12973,18825,12971,21773,13024,6361,37951,26318,12937,12723,15072,16784, +21892,35618,21903,5884,21851,21541,30958,12547,6186,12852,13412,12815,12674, +17097,26254,27940,26219,19347,26160,30832,7659,26211,13010,13025,26142,22642, +14545,14394,14268,15257,14242,13310,29904,15254,26511,17962,26806,26654,15300, +27326,14435,14293,17543,27187,27218,27337,27397,6418,25873,26776,27212,15319, +27258,27479,16320,15514,37792,37618,35818,35531,37513,32798,35292,37991,28069, +28427,18924,U,16255,15759,28164,16444,23101,28170,22599,27940,30786,28987, +17178,17014,28913,29264,29319,29332,18319,18213,20857,19108,1515,29818,16120, +13919,19018,18711,24545,16134,16049,19167,35875,16181,24743,16115,29900,29756, +37767,29751,17567,28138,17745,30083,16227,19673,19718,16216,30037,30323,42438, +15129,29800,35532,18859,18830,15099,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,15821,19022,16127,18885,18675,37370,22322,37698, +35555,6244,20703,21025,20967,30584,12850,30478,30479,30587,18071,14209,14942, +18672,29752,29851,16063,19130,19143,16584,19094,25006,37639,21889,30750,30861, +30856,30930,29648,31065,30529,22243,16654,U,33942,31141,27181,16122,31290, +31220,16750,5862,16690,37429,31217,3404,18828,665,15802,5998,13719,21867, +13680,13994,468,3085,31458,23129,9973,23215,23196,23053,603,30960,23082,23494, +31486,16889,31837,31853,16913,23475,24252,24230,31949,18937,6064,31886,31868, +31918,27314,32220,32263,32211,32590,25185,24924,31560,32151,24194,17002,27509, +2326,26582,78,13775,22468,25618,25592,18786,32733,31527,2092,23273,23875, +31500,24078,39398,34373,39523,27164,13375,14818,18935,26029,39455,26016,33920, +28967,27857,17642,33079,17410,32966,33033,33090,26548,39107,27202,33378,33381, +27217,33875,28071,34320,29211,23174,16767,6208,23339,6305,23268,6360,34464, +63932,15759,34861,29730,23042,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,34926,20293,34951,35007,35046,35173,35149,22147,35156, +30597,30596,35829,35801,35740,35321,16045,33955,18165,18127,14322,35389,35356, +37960,24397,37419,17028,26068,28969,28868,6213,40301,35999,36073,32220,22938, +30659,23024,17262,14036,36394,36519,19465,36656,36682,17140,27736,28603,8993, +18587,28537,28299,6106,39913,14005,18735,37051,U,21873,18694,37307,37892, +35403,16482,35580,37927,35869,35899,34021,35371,38297,38311,38295,38294,36148, +29765,16066,18687,19010,17386,16103,12837,38543,36583,36454,36453,16076,18925, +19064,16366,29714,29803,16124,38721,37040,26695,18973,37011,22495,U,37736, +35209,35878,35631,25534,37562,23313,35689,18748,29689,16923,38811,38769,39224, +3878,24001,35781,19122,38943,38106,37622,38359,37349,17600,35664,19047,35684, +39132,35397,16128,37418,18725,33812,39227,39245,31494,15869,39323,19311,39338, +39516,35685,22728,27279,39457,23294,39471,39153,19344,39240,39356,19389,19351, +37757,22642,4866,22562,18872,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,5352,30788,10015,15800,26821,15741,37976,14631,24912, +10113,10603,24839,40015,40019,40059,39989,39952,39807,39887,40493,39839,41461, +41214,40225,19630,16644,40472,19632,40204,41396,41197,41203,39215,40357,33981, +28178,28639,27522,34300,17715,28068,28292,28144,33824,34286,28160,14295,24676, +31202,13724,13888,18733,18910,15714,37851,37566,37704,703,30905,37495,37965, +20452,13376,36964,21853,30781,30804,30902,30795,5975,12745,18753,13978,20338, +28634,28633,U,28702,21524,16821,22459,22771,22410,40214,22487,28980,13487, +16812,29163,27712,20375,U,6069,35401,24844,23246,23051,17084,17544,14124, +19323,35324,37819,37816,6358,3869,33906,27840,5139,17146,11302,17345,22932, +15799,26433,32168,24923,24740,18873,18827,35322,37605,29666,16105,29876,35683, +6303,16097,19123,27352,29683,29691,16086,19006,19092,6105,19046,935,5156, +18917,29768,18710,28837,18806,37508,29670,37727,1278,37681,35534,35350,37766, +35815,21973,18741,35458,29035,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,18755,3327,22180,1562,3051,3256,21762,31172,6138,32254, +5826,19024,6226,17710,37889,14090,35520,18861,22960,6335,6275,29828,23201, +14050,15707,14000,37471,23161,35457,6242,37748,15565,2740,19094,14730,20724, +15721,15692,5020,29045,17147,33304,28175,37092,17643,27991,32335,28775,27823, +15574,16365,15917,28162,28428,15727,1013,30033,14012,13512,18048,16090,18545, +22980,37486,18750,36673,35868,27584,22546,22472,14038,5202,28926,17250,19057, +12259,4784,9149,26809,26983,5016,13541,31732,14047,35459,14294,13306,19615, +27162,13997,27831,33854,17631,17614,27942,27985,27778,28638,28439,28937,33597, +5946,33773,27776,28755,6107,22921,23170,6067,23137,23153,6405,16892,14125, +23023,5948,14023,29070,37776,26266,17061,23150,23083,17043,27179,16121,30518, +17499,17098,28957,16985,35297,20400,27944,23746,17614,32333,17341,27148,16982, +4868,28838,28979,17385,15781,27871,63525,19023,32357,23019,23855,15859,24412, +19037,6111,32164,33830,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,21637,15098,13056,532,22398,2261,1561,16357,8094,41654,28675, +37211,23920,29583,31955,35417,37920,20424,32743,29389,29456,31476,29496,29497, +22262,29505,29512,16041,31512,36972,29173,18674,29665,33270,16074,30476,16081, +27810,22269,29721,29726,29727,16098,16112,16116,16122,29907,16142,16211,30018, +30061,30066,30093,16252,30152,30172,16320,30285,16343,30324,16348,30330,20316, +29064,22051,35200,22633,16413,30531,16441,26465,16453,13787,30616,16490,16495, +23646,30654,30667,22770,30744,28857,30748,16552,30777,30791,30801,30822,33864, +21813,31027,26627,31026,16643,16649,31121,31129,36795,31238,36796,16743,31377, +16818,31420,33401,16836,31439,31451,16847,20001,31586,31596,31611,31762,31771, +16992,17018,31867,31900,17036,31928,17044,31981,36755,28864,3279,32207,32212, +32208,32253,32686,32692,29343,17303,32800,32805,31545,32814,32817,32852,15820, +22452,28832,32951,33001,17389,33036,29482,33038,33042,30048,33044,17409,15161, +33110,33113,33114,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,17427,22586,33148,33156,17445,33171,17453,33189,22511,33217,33252, +33364,17551,33446,33398,33482,33496,33535,17584,33623,38505,27018,33797,28917, +33892,24803,33928,17668,33982,34017,34040,34064,34104,34130,17723,34159,34160, +34272,17783,34418,34450,34482,34543,38469,34699,17926,17943,34990,35071,35108, +35143,35217,31079,35369,35384,35476,35508,35921,36052,36082,36124,18328,22623, +36291,18413,20206,36410,21976,22356,36465,22005,36528,18487,36558,36578,36580, +36589,36594,36791,36801,36810,36812,36915,39364,18605,39136,37395,18718,37416, +37464,37483,37553,37550,37567,37603,37611,37619,37620,37629,37699,37764,37805, +18757,18769,40639,37911,21249,37917,37933,37950,18794,37972,38009,38189,38306, +18855,38388,38451,18917,26528,18980,38720,18997,38834,38850,22100,19172,24808, +39097,19225,39153,22596,39182,39193,20916,39196,39223,39234,39261,39266,19312, +39365,19357,39484,39695,31363,39785,39809,39901,39921,39924,19565,39968,14191, +7106,40265,39994,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,40702,22096,40339,40381,40384,40444,38134,36790,40571,40620,40625, +40637,40646,38108,40674,40689,40696,31432,40772,148,695,928,26906,38083,22956, +1239,22592,38081,14265,1493,1557,1654,5818,22359,29043,2754,2765,3007,21610, +63547,3019,21662,3067,3131,3155,3173,3196,24807,3213,22138,3253,3293,3309, +3439,3506,3528,26965,39983,34725,3588,3598,3799,3984,3885,3699,23584,4028, +24075,4188,4175,4214,26398,4219,4232,4246,13895,4287,4307,4399,4411,21348, +33965,4835,4981,4918,35713,5495,5657,6083,6087,20088,28859,6189,6506,6701, +6725,7210,7280,7340,7880,25283,7893,7957,29080,26709,8261,27113,14024,8828, +9175,9210,10026,10353,10575,33533,10599,10643,10965,35237,10984,36768,11022, +38840,11071,38983,39613,11340,U,11400,11447,23528,11528,11538,11703,11669, +11842,12148,12236,12339,12390,13087,13278,24497,26184,26303,31353,13671,13811, +U,18874,U,13850,14102,U,838,22709,26382,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26904,15015,30295,24546,15889,16057,30206,8346, +18640,19128,16665,35482,17134,17165,16443,17204,17302,19013,1482,20946,1553, +22943,7848,15294,15615,17412,17622,22408,18036,14747,18223,34280,39369,14178, +8643,35678,35662,U,18450,18683,18965,29193,19136,3192,22885,20133,20358,1913, +36570,20524,21135,22335,29041,21145,21529,16202,19111,21948,21574,21614,27474, +U,13427,21823,30258,21854,18200,21858,21862,22471,18751,22621,20582,13563, +13260,U,22787,18300,35144,23214,23433,23558,7568,22433,29009,U,24834,31762, +36950,25010,20378,35682,25602,25674,23899,27639,U,25732,6428,35562,18934, +25736,16367,25874,19392,26047,26293,10011,37989,22497,24981,23079,63693,U, +22201,17697,26364,20074,18740,38486,28047,27837,13848,35191,26521,26734,25617, +26718,U,26823,31554,37056,2577,26918,U,26937,31301,U,27130,39462,27181,13919, +25705,33,31107,27188,27483,23852,13593,U,27549,18128,27812,30011,34917,28078, +22710,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +14108,9613,28747,29133,15444,29312,29317,37505,8570,29323,37680,29414,18896, +27705,38047,29776,3832,34855,35061,10534,33907,6065,28344,18986,6176,14756, +14009,U,U,17727,26294,40109,39076,35139,30668,30808,22230,16607,5642,14753, +14127,33000,5061,29101,33638,31197,37288,U,19639,28847,35243,31229,31242, +31499,32102,16762,31555,31102,32777,28597,41695,27139,33560,21410,28167,37823, +26678,38749,33135,32803,27061,5101,12847,32840,23941,35888,32899,22293,38947, +35145,23979,18824,26046,27093,21458,19109,16257,15377,26422,32912,33012,33070, +8097,33103,33161,33199,33306,33542,33583,33674,13770,33896,34474,18682,25574, +35158,30728,37461,35256,17394,35303,17375,35304,35654,35796,23032,35849,U, +36805,37100,U,37136,37180,15863,37214,19146,36816,29327,22155,38119,38377, +38320,38328,38706,39121,39241,39274,39363,39464,39694,40282,40347,32415,40696, +40739,19620,38215,41619,29090,41727,19857,36882,42443,19868,3228,36798,21953, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,36794, +9392,36793,19091,17673,32383,28502,27313,20202,13540,35628,30877,14138,36480, +6133,32804,35692,35737,31294,26287,15851,30293,15543,22069,22870,20122,24193, +25176,22207,3693,36366,23405,16008,19614,25566,U,6134,6267,25904,22061,23626, +21530,21265,15814,40344,19581,22050,22046,32585,24280,22901,15680,34672,19996, +4074,3401,14010,33047,40286,36120,30267,40005,30286,30649,37701,21554,33096, +33527,22053,33074,33816,32957,21994,31074,22083,21526,3741,13774,22021,22001, +26353,33506,13869,30004,22000,21946,21655,21874,3137,3222,24272,20808,3702, +11362,3746,40619,32090,21982,4213,25245,38765,21652,36045,29174,37238,25596, +25529,25598,21865,11075,40050,11955,20890,13535,3495,20903,21581,21790,21779, +30310,36397,26762,30129,32950,34820,34694,35015,33206,33820,4289,17644,29444, +18182,23440,33547,26771,22139,9972,32047,16803,32115,28368,29366,37232,4569, +37384,15612,42665,3756,3833,29286,7330,18254,20418,32761,4075,16634,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40029,25887,11680, +18675,18400,40316,4076,3594,U,30115,4077,U,24648,4487,29091,32398,40272,19994, +19972,13687,23309,27826,21351,13996,14812,21373,13989,17944,22682,19310,33325, +21579,22442,23189,2425,U,14930,9317,29556,40620,19721,39917,15614,40752,19547, +20393,38302,40926,33884,15798,29362,26547,14112,25390,32037,16119,15916,14890, +36872,21196,15988,13946,17897,1166,30272,23280,3766,30842,18358,22695,16575, +22140,39819,23924,30292,42036,40581,19681,U,14331,24857,12506,17394,U,22109, +4777,22439,18787,40454,21044,28846,13741,U,40316,31830,39737,22494,5996,23635, +25811,38096,25397,29028,34477,3368,27938,19170,3441,U,20990,7951,23950,38659, +7633,40577,36940,31519,39682,23761,31651,25192,25397,39679,31695,39722,31870, +U,31810,31878,39957,31740,39689,U,39963,18750,40794,21875,23491,20477,40600, +20466,21088,15878,21201,22375,20566,22967,24082,38856,40363,36700,21609,38836, +39232,38842,21292,24880,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,26924,21466,39946,40194,19515,38465,27008,20646,30022,5997, +39386,21107,U,37209,38529,37212,U,37201,36503,25471,27939,27338,22033,37262, +30074,25221,1020,29519,31856,23585,15613,U,18713,30422,39837,20010,3284,33726, +34882,U,23626,27072,U,22394,21023,24053,20174,27697,498,20281,21660,21722, +21146,36226,13822,U,13811,U,27474,37244,40869,39831,38958,39092,39610,40616, +40580,29050,31508,U,27642,34840,32632,U,22048,42570,36471,40787,U,36308,36431, +40476,36353,25218,33661,36392,36469,31443,19063,31294,30936,27882,35431,30215, +35418,40742,27854,34774,30147,41650,30803,63552,36108,29410,29553,35629,29442, +29937,36075,19131,34351,24506,34976,17591,U,6203,28165,U,35454,9499,U,24829, +30311,39639,40260,37742,39823,34805,U,U,36087,29484,38689,39856,13782,29362, +19463,31825,39242,24921,24921,19460,40598,24957,U,22367,24943,25254,25145,U, +14940,25058,21418,13301,25444,26626,13778,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23895,35778,36826,36409,U,20697,7494,30982, +21298,38456,3899,16485,U,30718,U,31938,24346,31962,31277,32870,32867,32077, +29957,29938,35220,33306,26380,32866,29830,32859,29936,33027,30500,35209,26572, +30035,28369,34729,34766,33224,34700,35401,36013,35651,30507,29944,34010,13877, +27058,36262,U,35241,U,28089,34753,16401,29927,15835,29046,24740,24988,15569,U, +24695,U,32625,35629,U,24809,19326,21024,15384,15559,24279,30294,21809,6468, +4862,39171,28124,28845,23745,25005,35343,13943,238,26694,20238,17762,23327, +25420,40784,40614,25195,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321, +9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,8560,8561,8562,8563,8564, +8565,8566,8567,8568,8569,20022,20031,20101,20128,20866,20886,20907,21241, +21304,21353,21430,22794,23424,24027,12083,24191,U,24400,24417,25908,U,30098,U, +36789,U,168,710,12541,12542,12445,12446,U,U,12293,12294,12295,12540,65339, +65341,10045,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363, +12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376, +12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389, +12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402, +12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415, +12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428, +12429,12430,12431,12432,12433,12434,12435,12449,12450,12451,12452,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12453,12454,12455, +12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468, +12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481, +12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494, +12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507, +12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520, +12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533, +12534,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052, +1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067, +1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081, +1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096, +1097,1098,1099,1100,1101,1102,1103,8679,8632,8633,63461,204,20058,138,20994, +63466,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +63467,20872,63469,30215,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,65506,65508,65287,65282,12849,8470,8481,12443,12444, +11904,11908,11910,11911,11912,11914,11916,11917,11925,11932,11933,11941,11943, +11946,11948,11950,11958,11964,11966,11974,11978,11980,11981,11983,11990,11991, +11998,12003,U,U,U,643,592,603,596,629,339,248,331,650,618,30849,37561,35023, +22715,24658,31911,23290,9556,9574,9559,9568,9580,9571,9562,9577,9565,9554, +9572,9557,9566,9578,9569,9560,9575,9563,9555,9573,9558,9567,9579,9570,9561, +9576,9564,9553,9552,9581,9582,9584,9583,65517,1351,37595,1503,16325,34124, +17077,29679,20917,13897,18754,35300,37700,6619,33518,15560,30780,26436,25311, +18739,35242,672,27571,4869,20395,9453,20488,27945,31364,13824,19121,9491,U, +894,24484,896,839,28379,1055,U,20737,13434,20750,39020,14147,33814,18852,1159, +20832,13236,20842,3071,8444,741,9520,1422,12851,6531,23426,34685,1459,15513, +20914,20920,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,40244,20937,20943,20945,15580,20947,19110,20915,20962,21314,20973,33741, +26942,14125,24443,21003,21030,21052,21173,21079,21140,21177,21189,31765,34114, +21216,34317,27411,U,35550,21833,28377,16256,2388,16364,21299,U,3042,27851, +5926,26651,29653,24650,16042,14540,5864,29149,17570,21357,21364,34475,21374,U, +5526,5651,30694,21395,35483,21408,21419,21422,29607,22386,16217,29596,21441, +21445,27721,20041,22526,21465,15019,2959,21472,16363,11683,21494,3191,21523, +28793,21803,26199,27995,21613,27475,3444,21853,21647,21668,18342,5901,3805, +15796,3405,35260,9880,21831,19693,21551,29719,21894,21929,U,6359,16442,17746, +17461,26291,4276,22071,26317,12938,26276,26285,22093,22095,30961,22257,38791, +21502,22272,22255,22253,35686,13859,4687,22342,16805,27758,28811,22338,14001, +27774,22502,5142,22531,5204,17251,22566,19445,22620,22698,13665,22752,22748, +4668,22779,23551,22339,41296,17016,37843,13729,22815,26790,14019,28249,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,5694,23076, +21843,5778,34053,22985,3406,27777,27946,6108,23001,6139,6066,28070,28017,6184, +5845,23033,28229,23211,23139,14054,18857,U,14088,23190,29797,23251,28577,9556, +15749,6417,14130,5816,24195,21200,23414,25992,23420,31246,16388,18525,516, +23509,24928,6708,22988,1445,23539,23453,19728,23557,6980,23571,29646,23572, +7333,27432,23625,18653,23685,23785,23791,23947,7673,7735,23824,23832,23878, +7844,23738,24023,33532,14381,18689,8265,8563,33415,14390,15298,24110,27274,U, +24186,17596,3283,21414,20151,U,21416,6001,24073,24308,33922,24313,24315,14496, +24316,26686,37915,24333,449,63636,15070,18606,4922,24378,26760,9168,U,9329, +24419,38845,28270,24434,37696,35382,24487,23990,15711,21072,8042,28920,9832, +37334,670,35369,24625,26245,6263,14691,15815,13881,22416,10164,31089,15936, +24734,U,24755,18818,18831,31315,29860,20705,23200,24932,33828,24898,63654, +28370,24961,20980,1622,24967,23466,16311,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,10335,25043,35741,39261,25040,14642,10624, +10433,24611,24924,25886,25483,280,25285,6000,25301,11789,25452,18911,14871, +25656,25592,5006,6140,U,28554,11830,38932,16524,22301,25825,25829,38011,14950, +25658,14935,25933,28438,18984,18979,25989,25965,25951,12414,26037,18752,19255, +26065,16600,6185,26080,26083,24543,13312,26136,12791,12792,26180,12708,12709, +26187,3701,26215,20966,26227,U,7741,12849,34292,12744,21267,30661,10487,39332, +26370,17308,18977,15147,27130,14274,U,26471,26466,16845,37101,26583,17641, +26658,28240,37436,26625,13286,28064,26717,13423,27105,27147,35551,26995,26819, +13773,26881,26880,15666,14849,13884,15232,26540,26977,35402,17148,26934,27032, +15265,969,33635,20624,27129,13913,8490,27205,14083,27293,15347,26545,27336, +37276,15373,27421,2339,24798,27445,27508,10189,28341,15067,949,6488,14144, +21537,15194,27617,16124,27612,27703,9355,18673,27473,27738,33318,27769,15804, +17605,15805,16804,18700,18688,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,15561,14053,15595,3378,39811,12793,9361,32655,26679,27941, +28065,28139,28054,27996,28284,28420,18815,16517,28274,34099,28532,20935,U,U, +33838,35617,U,15919,29779,16258,31180,28239,23185,12363,28664,14093,28573, +15920,28410,5271,16445,17749,37872,28484,28508,15694,28532,37232,15675,28575, +16708,28627,16529,16725,16441,16368,16308,16703,20959,16726,16727,16704,25053, +28747,28798,28839,28801,28876,28885,28886,28895,16644,15848,29108,29078,17015, +28971,28997,23176,29002,U,23708,17253,29007,37730,17089,28972,17498,18983, +18978,29114,35816,28861,29198,37954,29205,22801,37955,29220,37697,22021,29230, +29248,18804,26813,29269,29271,15957,12356,26637,28477,29314,U,29483,18467, +34859,18669,34820,29480,29486,29647,29610,3130,27182,29641,29769,16866,5863, +18980,26147,14021,18871,18829,18939,29687,29717,26883,18982,29753,1475,16087, +U,10413,29792,36530,29767,29668,29814,33721,29804,14128,29812,37873,27180, +29826,18771,19084,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,16735,19065,35727,23366,35843,6302,29896,6536,29966,U,29982,36569, +6731,23511,36524,37765,30029,30026,30055,30062,20354,16132,19731,30094,29789, +30110,30132,30210,30252,30289,30287,30319,30326,25589,30352,33263,14328,26897, +26894,30369,30373,30391,30412,28575,33890,20637,20861,7708,30494,30502,30528, +25775,21024,30552,12972,30639,35172,35176,5825,30708,U,4982,18962,26826,30895, +30919,30931,38565,31022,21984,30935,31028,30897,30220,36792,34948,35627,24707, +9756,31110,35072,26882,31104,22615,31133,31545,31036,31145,28202,28966,16040, +31174,37133,31188, +}; + +static const struct dbcs_index big5hkscs_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{__big5hkscs_decmap+0,64,170},{__big5hkscs_decmap+107,64,254},{ +__big5hkscs_decmap+298,64,254},{__big5hkscs_decmap+489,64,253},{ +__big5hkscs_decmap+679,64,220},{__big5hkscs_decmap+836,96,254},{ +__big5hkscs_decmap+995,64,254},{__big5hkscs_decmap+1186,64,253},{ +__big5hkscs_decmap+1376,64,254},{__big5hkscs_decmap+1567,64,254},{ +__big5hkscs_decmap+1758,64,254},{__big5hkscs_decmap+1949,64,254},{ +__big5hkscs_decmap+2140,64,254},{__big5hkscs_decmap+2331,64,254},{ +__big5hkscs_decmap+2522,64,254},{__big5hkscs_decmap+2713,64,254},{ +__big5hkscs_decmap+2904,64,254},{__big5hkscs_decmap+3095,64,254},{ +__big5hkscs_decmap+3286,64,254},{__big5hkscs_decmap+3477,64,254},{ +__big5hkscs_decmap+3668,64,254},{__big5hkscs_decmap+3859,64,254},{ +__big5hkscs_decmap+4050,64,254},{__big5hkscs_decmap+4241,64,254},{ +__big5hkscs_decmap+4432,64,254},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__big5hkscs_decmap+4623,161,254},{__big5hkscs_decmap+4717, +64,254},{__big5hkscs_decmap+4908,64,254},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5hkscs_decmap+5099,214,254},{ +__big5hkscs_decmap+5140,64,254},{__big5hkscs_decmap+5331,64,254},{ +__big5hkscs_decmap+5522,64,254},{__big5hkscs_decmap+5713,64,254},{ +__big5hkscs_decmap+5904,64,254},{0,0,0}, +}; + +static const unsigned char big5hkscs_phint_0[] = { +160,89,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,128,1,8,0,0,0,0,0,0,0,0,0,0, +0,0,2,44,0,30,0,0,0,0,0,64,174,86,238,249,221,228,33,23,0,0,0,128,219,73,31, +76,130,55,237,228,223,189,247,245,239,31,100,136,94,253,223,11,0,0,0,192,247, +143,0,131,5,0,8,201,8,4,129,64,68,5,11,9,35,1,32,2,0,0,0,32,145,24,0,96,0,168, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,128,0,64,86,50,65,32,198, +80,72,2,0,0,0,0,160,192,168,1,164,85,48,58,209,106,46,159,176,241,65,136,5,57, +80,4,0,0,0,0,172,163,20,192,1,2,13,45,134,136,107,34,110,192,204,245,218,10, +24,122,0,0,0,0,50,115,0,15,68,252,3,33,49,32,25,232,96,160,65,19,82,42,250,9, +0,0,0,0,190,1,129,16,16,96,183,137,193,218,237,250,242,59,200,167,11,77,155, +11,0,0,0,0,24,0,220,116,19,94,192,168,0,60,240,208,68,224,172,60,75,230,29,15, +0,0,0,128,189,88,120,55,191,187,216,218,8,134,192,108,148,192,176,125,14,136, +145,3,0,0,0,64,99,139,197,22,24,68,124,152,75,112,3,92,219,185,208,26,40,149, +106,1,0,0,0,0,232,7,36,34,32,136,4,106,32,215,29,50,15,162,149,11,4,67,65,1,0, +0,0,104,48,64,19,207,57,183,16,8,7,4,180,33,217,183,15,11,127,69,91,0,0,0,0, +236,116,236,196,4,41,49,2,48,250,252,27,175,78,38,164,183,110,50,24,0,0,0,0, +220,22,67,34,1,0,0,128,0,0,0,4,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0, +0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,28,241,220,190,126,252,186,123,238,249,55,249, +93,165,255,31,215,2,0,0,0,128,63,255,213,117,117,187,120,231,62,245,177,173, +189,75,150,188,46,181,85,2,0,0,0,192,109,51,55,176,233,204,159,42,126,83,204, +255,77,234,218,198,255,55,165,0,0,0,0,160,192,252,222,50,83,161,28,0,0,33,176, +71,0,74,32,32,233,215,235,0,0,0,0,160,183,1,64,49,101,247,12,36,64,48,45,144, +123,18,0,0,2,0,0,0,0,0,0,0,8,80,144,69,0,4,0,0,32,64,4,161,128,96,2,0,32,0,8, +0,0,0,0,148,8,2,32,40,0,0,1,8,254,251,73, +}; + +static const unsigned char big5hkscs_phint_11939[] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,128,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +}; + +static const unsigned char big5hkscs_phint_21733[] = { +0,0,0,0,0,26,172,248,250,90,192,250,51,0,0,0,0,0,129,0,160,156,130,144,9,1, +180,192,176,3,86,2,160,66,45,136,1,0,0,0,0,146,119,139,96,5,201,33,6,70,56,96, +72,192,180,36,222,132,224,192,36,0,0,0,0,205,80,197,52,192,40,162,173,124,153, +24,88,18,34,196,66,162,83,142,30,0,0,0,128,52,135,11,21,209,64,250,61,0,4,210, +5,72,8,22,230,28,165,0,8,0,0,0,192,45,22,20,128,24,58,212,25,136,28,138,4, +}; + +static const DBCHAR __big5hkscs_bmp_encmap[26537] = { +50904,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34905,34903,N,N,N,N,N,N, +34909,34907,34918,N,N,N,N,N,N,N,34913,34911,N,N,N,N,N,N,N,N,N,N,N,N,34922, +34920,N,N,N,N,N,N,34927,34925,34983,N,34931,34929,N,N,N,N,34935,34933,N,N,N,N, +51451,34939,34937,N,34978,34902,34919,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34906, +34924,N,N,N,N,N,N,34908,34926,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34928,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,51452,34910,34932,N,N,N,N,N, +51450,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34936,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,34904,34921,N,34930,34912,34934,N,34938,N,34940,N,34941,N, +34942,N,34977,51446,34923,N,N,51448,N,N,N,N,N,N,51447,N,N,N,N,N,34984,N,N,N,N, +N,N,N,N,51454,N,N,N,N,N,N,N,N,N,N,51449,N,N,N,N,N,N,N,N,N,N,N,N,N,51445,N,N,N, +N,N,N,51453,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50905,51193,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,51187,51188,51189,51190,51191,51192,51194,51195,51196,51197, +51198,51264,51265,51266,51267,51268,51269,51270,51271,51272,51273,51274,51275, +51276,51277,51278,51279,51280,51281,51282,51283,51284,51285,51286,51287,51288, +51289,51290,51292,51293,51294,51295,51296,51297,51298,51299,51300,51301,51302, +51303,51304,51305,51306,51307,51308,51309,51310,51311,51312,51313,51314,51315, +51316,51317,N,51291,34915,34980,34917,34982,51410,N,N,N,N,N,N,N,N,N,N,51411,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +50869,50870,50871,50872,50873,50874,50875,50876,50877,50878,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,51319,51320,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,51318,50849,50850,50851, +50852,50853,50854,50855,50856,50857,50858,N,N,N,N,N,N,N,N,N,N,50859,50860, +50861,50862,50863,50864,50865,50866,50867,50868,63993,63992,63974,63983,63965, +63976,63985,63967,63980,63989,63971,63982,63991,63973,63977,63986,63968,63979, +63988,63970,63975,63984,63966,63981,63990,63972,63978,63987,63969,63994,63995, +63997,63996,50918,51414,N,N,N,51415,N,51416,51417,51418,N,51419,N,51420,51421, +N,N,N,N,N,N,N,51422,N,N,N,N,N,N,51423,51424,N,N,N,N,N,N,N,51425,N,51426,N,N, +51427,N,51428,N,51429,N,N,N,N,N,N,N,51430,N,N,N,N,N,51431,N,51432,N,N,N,N,N,N, +N,51433,N,N,N,51434,N,51435,51436,N,51437,N,N,N,N,N,N,51438,51439,N,N,N,N,N,N, +51440,N,N,N,N,51441,50893,50912,50913,50914,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,50919,50920,50921,50922,50923,50924,50925,50926,50927,50928,50929,50930, +50931,50932,50933,50934,50935,50936,50937,50938,50939,50940,50941,50942,51008, +51009,51010,51011,51012,51013,51014,51015,51016,51017,51018,51019,51020,51021, +51022,51023,51024,51025,51026,51027,51028,51029,51030,51031,51032,51033,51034, +51035,51036,51037,51038,51039,51040,51041,51042,51043,51044,51045,51046,51047, +51048,51049,51050,51051,51052,51053,51054,51055,51056,51057,51058,51059,51060, +51061,51062,51063,51064,51065,51066,N,N,N,N,N,N,N,51412,51413,50908,50909,N,N, +51067,51068,51069,51070,51105,51106,51107,51108,51109,51110,51111,51112,51113, +51114,51115,51116,51117,51118,51119,51120,51121,51122,51123,51124,51125,51126, +51127,51128,51129,51130,51131,51132,51133,51134,51135,51136,51137,51138,51139, +51140,51141,51142,51143,51144,51145,51146,51147,51148,51149,51150,51151,51152, +51153,51154,51155,51156,51157,51158,51159,51160,51161,51162,51163,51164,51165, +51166,51167,51168,51169,51170,51171,51172,51173,51174,51175,51176,51177,51178, +51179,51180,51181,51182,51183,51184,51185,51186,N,N,N,N,N,50915,50906,50907, +51409,37495,N,N,N,N,N,N,N,N,N,N,38623,N,N,N,N,N,N,N,N,N,N,N,35285,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37837,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39903,N,N, +N,N,N,N,64104,N,N,35290,36697,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35291,N, +N,36701,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35292,N,N,N,N,N,N,N,N,N,38647,N,N,N,N,N,N, +N,N,N,N,N,N,35546,N,N,N,N,35804,N,N,N,N,N,N,38875,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40531,N,N,N,N,40362,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39914,35438,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35784,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35304,N,35306,N,N,N,N,N,35915,N,N,N,N,N,N,N,64368,N,N,N,N,N,N,N,N,N, +N,N,35309,N,N,38109,N,35310,N,N,N,N,40628,35539,N,N,N,N,N,N,N,N,N,N,N,37595,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38107,35321,N,N,N,N,N,N,N,N,64378,N,N,N, +35323,N,N,N,N,N,N,N,40700,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35324,N,35263,N,N, +N,35326,N,35302,N,N,40262,N,N,N,40430,N,N,N,41086,N,N,N,41064,N,N,N,N,39145,N, +35688,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36349,35774,40921,N,N,N,N,N,N,N, +35563,N,N,40919,35690,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40028,N,35761,N,N,N,N,N,N,N, +N,64350,N,N,N,N,N,N,N,N,N,40435,N,N,N,N,N,N,N,41168,N,N,N,64614,N,N,N,N,37609, +N,N,N,N,N,N,N,N,39660,36779,64072,N,N,N,N,36421,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40047,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40670,N,N,N,N,N,N, +35311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38633,N,N,N,N,N,N,N,N,N, +N,40635,N,N,N,N,38110,N,40632,N,N,N,38842,64357,N,N,N,38358,N,N,N,40123,N,N, +38874,N,N,N,N,36677,N,64381,37208,65124,N,38998,39757,N,N,N,N,N,N,N,N,N,N, +37723,38343,N,38887,N,N,N,N,N,N,37721,N,N,N,37365,38840,N,N,64930,64438,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37626,37719,N,35750,N,N,N,N,64441,N,38832,N,N,64964,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40097,N,N,N,N,N,37362,37369,N,36849,N,N,N,N,N,N,38725, +38995,N,N,65144,N,64449,37457,N,N,N,N,N,N,40365,N,N,N,N,N,64876,N,N,64107,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39874,N,N,N,N,N,N,N,N, +N,N,N,N,39547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,35680,N,N,N,N,N,N,N,N,37707,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39613,N,N,N,N,37303,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38324,N,N,N,N,N,65221, +N,N,40688,36196,N,N,N,N,N,N,N,N,N,37481,N,N,N,N,N,N,36199,N,N,N,N,N,N,N,N,N,N, +N,N,64490,N,N,N,N,N,N,N,N,64495,N,36200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37867,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,64578,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,37222,N,N,N,N,N,N,N,N,64205,N,N,N,N,37853,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35788,36205,N,N,N,N,N, +N,N,N,N,N,N,36206,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38568,N,N,N,N,N,N,N,N,N, +N,64678,N,N,N,N,N,N,N,N,N,N,N,N,36207,N,N,N,N,N,N,N,N,N,N,N,N,N,36208,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64612,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,36960,N,N,N,N,N,N,N,N,36212,38851,N,N,N,N,N,N,N,35536,N,N,N, +N,N,N,37492,N,39870,N,N,N,N,N,40136,N,N,40122,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36216,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40633,N,N,N,N,N,38234,N,N,37300,N,N,N,N,N,N,35400,N,N,N,N,N,N,N,N,N,N,N, +36221,N,N,35453,N,N,35522,64842,N,36257,N,N,35537,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64692,35655,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37796,40666,N,N,N,N,N,N,N,N,N, +35409,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36262,N,N,N,N,N,N,40645,N,N, +N,N,64708,N,N,N,N,41080,N,38069,N,N,N,N,N,N,N,64706,35435,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36267,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64232,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36269,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64585,N,37825,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36975,N,36272,N,N,N,N,N,N,N,N, +38014,37114,N,N,N,N,N,N,N,N,N,N,38009,N,N,N,N,N,N,N,N,36274,N,N,N,N,N,N,N,N, +64750,N,N,N,N,N,N,N,N,N,N,N,N,N,39291,N,N,N,N,N,N,N,N,36276,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36279,N,N,N,N,N,N,N,37299,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,36283,36282,N,N,N,N,N,N,N,N,36284,36932,N,N,N,64844,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37860,N,N,37856,N,N,N,N,N,N,N,64851,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36291,N,39864,N,N,N,64496,N,37865,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37878,N,N,N,N,N,36293,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36298, +N,N,N,N,N,36300,64861,37813,64865,N,N,N,40184,N,N,N,37458,N,N,41192,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40101,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35926,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36310,N,38848,N,N,N,41182,N,N,N,N, +38866,N,N,N,N,N,64165,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64931,N,N,N,36315,36527,N,N, +N,N,N,N,N,N,N,37301,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64841,N,N,N,N,N,N, +N,N,64977,N,N,N,N,N,N,N,N,N,N,36331,N,N,N,N,N,38854,N,64974,N,N,37116,N,N,N,N, +N,N,N,N,N,N,N,N,N,64601,N,N,38614,N,N,N,N,N,N,38853,36335,N,N,N,N,38871,N,N,N, +N,N,36336,N,N,N,N,N,N,N,38566,N,N,N,N,N,N,N,64447,N,N,N,N,36339,N,N,N,N,37961, +N,36341,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39026,N,N,N,N,N,N,N,36459,N,N,N, +N,N,N,64253,N,N,N,N,N,N,N,N,N,N,36688,N,N,N,N,N,N,40396,64613,N,35908,N,N, +39278,38049,N,N,N,N,N,36707,N,N,N,N,N,N,N,41178,N,N,N,N,N,N,N,N,N,N,N,37459, +65001,N,N,40373,N,N,N,N,N,N,N,39033,N,N,N,40285,N,N,N,N,36195,38505,40816,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64618,N,N,35527,N,N,N,N,35287,N,N,N,N,N,N,N,N, +N,N,N,N,65101,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40669,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65275,39100,64204,N,N,38320,N,N,N,37988,N,N,N,N, +N,N,37743,N,N,N,N,N,N,38073,N,N,38380,N,N,N,N,37358,N,N,39107,N,38390,N,N,N, +36861,39109,N,N,N,N,38758,65134,N,N,38877,36010,N,N,37586,N,N,38753,39115,N,N, +N,N,38384,N,38749,N,37347,N,N,N,N,39116,N,N,37993,39117,N,N,N,N,N,39118,N, +38396,N,N,38051,38498,N,N,N,65206,N,37987,N,N,N,N,N,N,N,39120,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39121,N,N,N,N,38005,64224,N,N,N,N,N, +N,N,N,N,38002,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39126,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35568,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39129,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39131,N,N,N,N,39133,N,N,N,N,N,N,N,N,39080,N,N,N,N,N,N,N, +35437,N,N,N,N,N,N,N,N,N,N,N,35579,35502,64457,N,N,N,N,35933,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,39140,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39142,N,N,N,N,N,N,N,N,N,N,N,39144,N,N,N,N,N,N,N,N,N,N,N,N,N,35405,N,N,N, +37463,N,N,N,N,N,N,N,N,N,N,38367,N,N,41132,N,N,N,N,39147,N,N,N,N,39148,N,36035, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39156,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35512, +N,N,N,40679,N,N,N,N,N,N,N,N,38076,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64721,N,N,N,N, +N,N,40134,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40574,39166, +65000,N,N,N,N,39232,N,N,N,N,38089,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,38099,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39238,N,N,N,N,37056, +N,38097,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38259,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37826,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39240, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39243,N,N,N,N,N,36437,N,N,N,N,39246,N,N,N,N, +N,N,N,N,N,N,N,36606,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36441,N,N,N,N,N,N,N, +N,N,38124,38127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35936,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36724,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39253,N,N,N,N,N,N,N,N,N,38212,N,N,N,N,N,N,N,N,N,N,N, +36043,N,N,N,39254,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39257,N,N,N,N,N,N,N,39259, +N,N,N,N,N,N,N,N,N,N,N,N,N,36036,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64069,N,N, +N,37047,N,N,38723,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38349,N,N,N,N,N,N,38857, +64848,36537,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38342,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39271,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35513,N,N,N,N,N,N,36348,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35446,N, +N,N,N,N,40273,N,N,N,N,N,N,N,N,N,N,N,N,N,39283,N,N,N,N,40271,39290,38244,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39329,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39333,N,N,N, +N,N,N,N,39335,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36589,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39341,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37998,36720,N,64208,N,N,N,N,N,N,N,N,N,N,N,N,N,39347,N,N,N,N,N,N, +41043,N,N,N,N,N,N,N,N,38492,N,N,N,N,64890,N,N,N,N,N,N,N,N,38910,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37565,N,38909,N,N,N,N,36708,N,N,N,N,64759,38242,38861,40548,N,N, +N,N,N,N,N,37452,36553,39356,N,N,N,N,40357,N,36692,N,N,N,N,N,N,N,N,N,N,36732,N, +N,N,N,N,N,36514,N,N,N,N,N,N,N,N,N,36730,N,N,N,N,N,N,38830,N,N,N,N,38600,N,N,N, +N,N,N,N,39363,N,37078,N,40126,N,N,N,36726,N,N,N,N,N,N,N,N,N,N,N,N,N,38000, +64331,N,N,64970,N,N,N,N,N,N,36551,N,N,N,N,N,41209,N,N,N,N,N,N,N,36777,N,N,N,N, +N,N,N,N,N,N,N,N,39367,N,N,N,N,N,N,N,N,N,N,N,N,N,37079,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40671,39374,N,N,N,N,N,N,N,N,36794,N,N,N,N,N,36843,N,39375,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36802,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37577,N,N,N,N,N,38876,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38323,40057,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38322, +36827,N,N,N,N,39907,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40570,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39918,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39390,N,N,N,N,N,N,N,N,N,N,N,N, +N,64250,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40677,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35410,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39393,N,N,N,N,N,N,35431,35765,N,N,N,N,N,N,N,N,N,N,35500,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39401,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64458,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38878,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38353,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39413,64586,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39849,N,N,N,N,N,N,N,N,N,N,N,N,64476,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65110,N, +N,N,N,N,40612,N,N,N,N,N,N,40265,38363,N,N,N,N,N,N,N,N,N,N,35269,N,N,N,N,N,N,N, +N,N,N,N,N,39416,N,N,N,N,N,N,38500,N,N,N,N,36949,N,N,38612,N,N,N,N,N,N,N,38780, +N,N,N,N,N,N,38477,N,38881,N,N,N,N,N,N,39496,N,N,N,N,N,N,N,N,N,N,N,39497,N, +65149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37034,N,N,N,N,39504,N,N,N,N,N,N,N, +37703,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36568,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37065,N,N,N,N,N,39509,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37052,N,N,N,N,N,39512,N,35768,37077,N,N,N,N,N,N,N,N,N,N,N,N,N,38465,N,N,N,N,N, +N,39514,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39516,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,38850,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35515,N,N, +N,39850,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37109,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,39520,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37189,35928,N,N,N,N,N,N,N,N,39523,N,N,N,N,N,N,35913,N,N,N,N,N,N,N,N,N,N,N, +35766,N,N,N,N,N,N,N,N,N,N,64719,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38507,39534,N, +37199,N,N,N,N,N,N,N,N,38726,N,N,41190,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37591,N, +38517,N,N,37844,N,N,37307,38521,N,N,N,N,N,39536,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38520,37325,N,40010,41071,N,N,41066,N,N,N,N,N, +N,37215,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40869,N,N,35258,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40653,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39545,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40398,N,N,N,36050,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40307,N,N,N,N,N,N,N,N,N,38585,N,38588,N,N,N,N,N,N,40145,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35255,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40686,N,N,N,N,N,N,N,N,N,N,N,64323,40649,N,N,N,N,N,N,64467,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37294,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40312,N,N,N,N,N,N,N,N,N,N,40315,40627,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40626,N,40406,N,N,N,N,39247,N,N,35278,N,N,N,35776,N,40900,N,35796, +N,N,35954,N,N,N,N,N,N,50879,35833,N,N,N,N,N,35142,N,50880,N,N,N,N,N,N,N,N,N, +64229,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,51323,35782,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40023,N,N,N,N,N,N,N,N,N,N,N,N,N,39675,N,N,N,N,N,N,N,35280,35279,N,N,N,50881,N, +35281,N,35298,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37502,N,40378,N,N,N,N,N,50882,N,N, +35951,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64504,N,N,N,35783,37483,N,N,35282, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40911,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40361,35283,N,N,39394,N,N,N,N,N,N,N,N,N,37479,37540,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,35955,N,N,35150,N,N,N,N,N,N,N,N,N,N,N,N,N,35151,37496,N, +N,N,N,N,N,N,N,37302,N,N,N,N,35284,N,40914,N,N,N,N,N,N,N,N,37543,N,N,38306,N,N, +N,N,N,37486,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,38634,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37487,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37539,N,N,N,N,N,35152,N,N,64087,N,N,N,N, +39014,N,N,N,N,N,N,N,N,N,N,N,N,35286,N,N,N,N,N,N,N,N,N,N,39090,N,N,N,37547,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38622,37548,N,N,N,N,N,N,N,N,N,N, +35952,N,40814,N,N,N,N,N,N,36594,N,N,N,40812,35288,N,N,N,N,64089,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37544,N,N,N,N,N, +37219,N,N,N,N,N,N,35904,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40819,N,37549,N,N,N,N,N,N,N,N,N,N,N,N,N,39913,N,N,N,N,N,37545,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37546,N,N,N,N,N,N,35289,N,N,N,N,N,N,N,64854,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40872,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,35953,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37537,N,N,37091,N,N,N,N,N,N,N,N,41126, +N,N,N,N,N,38059,N,64626,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38852,N,N,N,N,N,N, +N,37550,64103,N,N,N,N,N,N,N,N,N,N,N,37538,64105,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,37480,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35153,N,N,N,N,N,N,N,N,N,64111,N,N,N,N,N, +N,N,N,N,64113,N,N,N,N,N,N,N,N,N,35154,N,N,N,N,37978,N,N,N,N,N,N,N,N,50883,N,N, +N,35293,N,51362,N,N,N,N,N,N,N,N,N,N,N,N,N,50884,N,N,N,40530,N,35155,N,N,N,N,N, +N,N,N,N,N,40533,37562,N,N,50885,N,N,35931,N,N,N,64125,64168,39528,64071,N,N, +64126,N,N,N,N,N,N,N,N,N,N,37563,N,N,N,64950,N,64162,N,N,N,N,N,64163,N,64164, +39860,64166,N,N,N,N,N,N,N,35295,N,N,N,64987,N,N,64169,N,35156,N,N,N,N,N,N,N,N, +64171,N,N,N,N,N,N,64634,N,N,N,N,N,N,N,35296,N,40783,51325,N,N,35297,N,N,N,N,N, +64176,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40909,41191,N,N,N,N,N,64177,35238, +N,N,N,N,N,N,N,N,N,N,N,N,40698,N,N,N,N,N,N,N,64178,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64180,N,37572,N,N,N,N,N,N,40815,N,N,N,N,N,N,N,35760,N, +N,N,N,N,N,N,N,N,N,40876,N,N,N,N,N,35299,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39891,35300,N,N,N,64181,N,N,N,N,N,40917,N,N,N,N,N,N,35157,N,N,37573,N,N,N, +35158,N,N,N,N,N,N,N,N,N,N,N,N,64179,N,N,N,64182,N,N,N,N,N,N,N,N,N,N,N,64183,N, +N,N,N,N,N,40668,N,N,N,64452,40817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64186,37575,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50886,39500,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35944,N,N,35301,N,N,N,N,40829,N,N, +N,N,N,41129,64196,N,N,N,N,50887,N,N,35159,N,N,N,N,N,N,64170,N,N,N,N,N,N,N,N,N, +N,N,35160,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35811,N,35681,N,N,N,N,39665,N,N,40631,N, +50888,N,N,N,64209,N,N,N,N,N,N,64210,N,N,N,N,N,N,N,N,40634,64212,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64217,N,N,N,N,N,N,N,N,N,N,N,N,64219,N,40160,N,N,N, +64503,N,64506,35303,41082,64220,N,N,64221,N,35305,N,N,N,N,N,50889,N,N,N,N,N,N, +N,N,N,N,64226,35307,N,N,64227,N,N,N,N,N,N,37064,N,N,N,37594,35161,40181,N,N,N, +N,N,35162,64231,40866,N,N,N,N,N,64234,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64237,36781,N,N,N,N,N,N,64345,64239,38639,N,40428,N,N,N,40394,N,N,N,N,N,N, +64877,N,35308,N,N,N,N,N,N,N,N,N,N,N,64324,N,N,40418,N,35957,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40640,N,40534,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40825,39623,N,N,64244,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39073,N,N,N,N,N,N,N,N,N,64248,N,N,N,35312,40519,N,N,40439,N,N,N,N,40915, +N,39626,N,N,N,N,35313,64249,N,N,N,N,N,N,N,N,N,N,N,N,N,36442,N,35314,N,N,N,N, +35315,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37469,35665,37600,N,N,35316,N,N,N,N,N, +N,N,N,N,40916,N,N,N,N,N,N,N,N,35449,N,N,N,N,N,N,N,N,N,N,N,35317,38823,N,N,N,N, +N,N,N,N,N,N,37818,N,N,N,N,N,40536,N,N,N,N,35318,N,N,N,N,N,40535,N,N,N,N,35319, +N,35393,N,N,35320,N,N,64241,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35322,N,N,N, +N,N,N,N,64322,N,64191,N,N,N,N,N,N,N,N,N,64419,N,N,N,N,N,N,N,N,N,64247,N,N,N,N, +N,N,N,N,N,N,N,40526,N,38108,N,N,N,N,N,38362,40440,40810,N,N,N,N,N,35511,N,N,N, +N,N,N,N,N,N,N,N,N,64326,N,N,N,N,N,N,N,N,N,35398,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64327,N,N,N,N,N,N,37192,N,N,N,37598,N,N,N,N,35667,40438,N, +39898,N,N,N,N,40318,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35325,39396,N,N, +N,N,N,40515,N,N,N,N,N,N,N,N,N,N,N,40425,N,36690,N,N,N,40437,40432,N,N,N,39399, +N,N,N,N,N,35773,40431,N,N,N,N,N,N,N,N,N,N,N,40887,N,N,N,N,N,N,N,N,N,N,N,N, +40400,N,40939,36265,40399,39137,N,40421,N,N,N,N,N,N,N,40392,N,N,N,N,N,N,N,N,N, +64335,N,N,N,N,N,N,N,N,N,N,N,40427,N,N,N,N,N,N,N,N,N,64340,N,64341,39586,N, +35542,N,39519,N,N,N,N,N,N,N,N,40693,N,N,N,36791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39634,40554,40680,N,N,N,N,N,N,N,N,N,N,N,N,35775,37314,40290, +N,N,N,N,N,N,37472,N,N,N,N,N,N,N,N,N,N,N,37470,37313,N,35525,N,N,38819,N,N,N,N, +N,N,N,N,N,N,35692,N,36222,N,N,N,N,N,N,N,40020,N,N,N,N,N,40381,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40133,N,N,N,N,N,N,N,N,N,N,N,35163,N,N,N,N,N,N,N,N, +N,N,64348,N,64347,N,64343,N,N,N,N,N,N,N,N,N,N,N,39111,64346,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40174,N,N,N,N,N,N,N,37602,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,38055,N,N,N,N,N,N,N,N,N,N,36044,N,39892,N,N,64356,64374,N,N,64352,N, +N,N,N,N,N,N,N,N,N,N,N,N,39397,N,N,39618,N,N,N,37371,N,N,N,41075,N,N,N,N,N,N,N, +40818,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40908,N,N,N,39077,37608,N,N,N,N,N,N, +N,N,39868,N,38643,N,N,37607,N,N,64615,N,N,N,N,N,N,N,N,N,N,N,35709,N,N,N,N, +39924,N,N,N,N,N,40695,N,N,40641,N,N,N,N,N,N,N,N,N,39279,N,N,N,N,N,N,38641,N,N, +36417,N,N,N,N,N,38218,N,N,N,38886,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38645,N,N,N,N,N, +37606,40770,N,N,N,N,N,N,N,64359,N,N,N,N,N,N,N,N,39337,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64230,64361,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38885,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,38525,N,N,N,64364,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39330,N,N,N,N,N, +39611,N,N,N,39525,N,N,37966,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64366,N,N, +39391,N,N,N,N,N,N,N,N,N,39139,N,N,37460,N,N,N,N,N,38523,35503,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35959,N,N,N,N,N,N,35759,40637,N,N, +N,N,N,N,N,N,N,N,N,N,40678,N,N,64367,N,N,N,N,N,36577,N,N,N,N,39805,40062,N,N,N, +N,63961,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37610,N,N,N,N,35960,N,N,N,N,N,N,N,N,N,N, +N,64370,N,N,N,64369,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35164,N,39152,38642,N,N,N,N, +N,N,N,64372,35777,N,35165,35294,N,35166,N,N,50890,N,N,N,N,N,N,65090,N,N,N,N,N, +N,N,N,N,N,N,N,N,64379,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35167,N,35168,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39885,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40403,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38988,N,N,N,N,N,N,N,N,N,N,38738,N,N,N,N,N,38339,N,N,N,N,39862,N, +N,N,N,N,N,N,N,N,N,N,N,39609,N,N,N,38835,N,N,N,N,N,N,40820,37617,N,N,N,N,N,N,N, +N,N,N,N,38879,N,N,N,N,64422,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64427,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,39031,N,N,N,38996,38341,N,N,N,N,N,N,N,40277,64434,38270,N, +N,N,N,N,N,N,N,38722,N,38118,N,N,N,N,37621,N,N,N,N,N,N,N,36037,N,N,N,N,N,N, +37629,N,N,64418,N,N,40017,N,N,38121,39004,37616,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,37964,N,N,N,N,N,N,N,37227,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35704,N,N,N,N,38114,N, +N,N,N,N,N,N,38991,N,64437,N,N,N,N,37489,N,N,37733,N,N,39003,N,N,38992,N,N,N,N, +N,N,N,38844,N,N,N,N,37619,N,N,37696,38989,N,N,N,38258,N,65007,N,N,N,N,N,N,N,N, +64961,N,N,N,N,64442,N,N,37611,N,N,N,N,N,N,64627,38839,N,N,N,N,N,N,N,N,N,64436, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37031,N,N,N,N,N,N,N,N,N,N,38721, +37620,N,N,N,64444,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38263,N,N,N,N,N,N,N,N,N,N,N, +40674,N,36728,N,N,N,N,N,N,N,63964,N,N,N,38514,40629,N,N,N,38475,N,N,N,36012,N, +N,N,N,N,N,N,N,N,41210,N,N,N,N,N,N,N,N,N,N,N,38261,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37082,N,N,37735,N,65188,N,N,N,37087,N,N,N,N,37716,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35169,N,35764,N,N,N,N,40384,N,N,N,N,N,N,36424,N, +64453,N,N,N,N,N,64455,N,N,N,50891,N,64121,N,N,N,N,N,N,N,N,N,N,N,N,N,40551,N,N, +N,N,N,36057,N,N,N,N,N,N,64466,35170,35171,N,N,N,N,N,N,N,N,N,N,64637,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40811,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64460,N,65198,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64465,N,N, +N,N,N,N,N,N,N,N,N,64373,64468,N,N,N,N,N,N,N,N,N,N,N,N,N,64470,64472,N,N,N,N,N, +N,N,35677,N,37708,N,39650,N,N,35785,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64475,40905,N,N,N,N,N,N,N,N,40772,N,N,N,N,N,N, +N,N,N,N,39149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64477,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36338,35172,N,65010,N, +37709,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64487,N,N,N,N,N,N, +41202,39016,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40792,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36211,N,N,N,64478,N,N,N,N,N,64479,N,N,N,N,N,35912,64483,N,N,N,N,36264,N, +N,64484,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40053,N,N,39032,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36192,N,N,N,N,N,N,N,64485,N,36193,N,N,N,N,N,N,N,N,N,N,N,N,N,36194, +41121,N,N,N,40000,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39085,N,N,N,40682,N, +N,N,N,N,N,36052,N,N,N,N,N,N,N,N,N,40171,N,N,N,N,N,64480,N,N,40785,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36197,N,N,N,N,N,N,40177,N,N,N,N,N,N,N,N,N,N, +64600,N,N,36198,N,N,N,N,N,N,N,38484,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64488,N,N,N,50892,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40910, +64508,N,39652,N,N,N,N,N,N,40821,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64497,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36201,N,N,N,N,N,37711,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37710,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64500,N,N,N,N,50894,N,N,N,64451,N,N,35173,N,N,N,N,N,N,N,N, +N,N,N,35962,N,N,N,N,N,N,35963,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36202,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37715,N,N,40443,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64509,N,N,N, +36953,64576,N,64577,64579,37729,64582,37730,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36203,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64588,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,38328,N,N,50896,35786,N,N,N,N,N,N,N,N,N,N,39034,N,N,N,N, +50897,N,64593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64596,N,N,N,N,N,N,N,N,64175,N,N,N,N, +N,N,N,36204,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64097,N,N,64599,N,N,N,N,N,N,N,N,N,39792,N,N,N,N,N,N,N,N,41041,N,N,N,N,N,N,N, +35964,N,35787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37742,N,N,N,64725, +64681,N,N,N,N,N,N,N,N,N,N,N,N,N,64609,N,N,N,N,N,N,N,N,N,35174,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64203,N,N,N,N,N,N,N,63962,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37754,N,41184,N,N,N,N,N,N,37739,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64619,N,N,N,N,N,41180,N,N,37992,N, +N,N,N,N,N,N,N,N,N,N,64621,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,36209,N,N,N,N,N,N,64868,N,N,N,N,39354,N,N,N,39632,39521, +41189,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41051,38572,N,N,N,N,38720,N,N,N,N, +N,N,N,N,N,N,N,N,40689,N,N,N,N,N,N,N,N,35917,N,N,N,N,N,N,N,N,N,N,N,N,N,40830,N, +N,N,N,N,N,N,N,N,N,N,N,36210,N,N,N,N,64630,N,N,N,N,N,N,N,N,N,N,N,N,N,38569,N,N, +N,N,N,N,N,N,41070,N,N,64682,N,N,N,64461,N,N,N,64628,N,N,N,N,N,N,N,N,N,N,41076, +N,N,N,N,N,N,N,N,N,N,N,N,N,41073,N,N,N,64633,N,N,N,N,N,64636,N,N,N,N,N,N,N,N,N, +N,N,N,N,40016,N,N,37753,37752,N,N,41181,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,36213,N,36214,N,N,N,N,N,N,37748,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36215,64677,N,N,64674,N,N,N,N,N,N,37059,N,N,N,N,N,N,N,41081,36217,N,N,N,N,N,N, +N,N,N,N,35836,N,41078,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35789,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40794,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40948,N,N,40890,N,N,N,N,N,N,N,N,N,N,36218,N,N,N,N,N,N,N,N,N, +N,N,N,40517,N,N,N,N,N,N,37808,N,41077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39750,N,64686,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64688,N,N,N,N,N,N, +N,N,N,64081,N,N,N,N,N,36219,36220,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40662,N,N,37804,N,N,N,40795,N,37801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41084,N,N,N,N,N,N,N,64690,N,N,N, +N,N,N,N,N,N,N,N,N,35521,N,N,N,N,N,40884,N,N,N,N,N,N,N,N,N,N,N,64684,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40524,N,N,N,N,N,N,N,36805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37805,N,N,N,N,N,N,N, +N,N,N,N,N,40387,N,N,N,36258,N,N,N,40266,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64694,N,N,36259,40523,N,40525,36260,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35581,N,N,N,N,N,64693,N,64707,37810, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36261,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37793,N,N,N,N,N,N,N,N,N,N,35526,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,35419,N,N,N,35149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,65236,N,N,N,N,35448,N,37803,N,N,N,N,N,N,N,N,N,36263,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40773,N,N,N,N,N,N,N,N,N,35414,N,N,N,64703,N,N,N, +64704,N,36582,N,N,35492,35139,N,N,N,N,N,N,37875,N,N,N,N,N,N,N,N,N,N,N,N,64683, +40610,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40391,N,N,N,50898,35790,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64709,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64715,N, +N,N,N,N,N,N,N,N,N,N,37811,N,64714,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64713,36268,N,64454,35175,N,35966,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64717,N,N,N,N,N,N,N,N,40179,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64720,N,N,38331,N,N,N,N,N,N,N,N,N,N,N,64723,N,N, +64724,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36270,64727,N,N,N, +N,N,37851,N,N,N,N,65123,N,N,N,N,N,N,N,N,N,N,N,N,37845,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64730,N,N,N,39793,N,N,64733,N,N,N,N,N,N,N,36271,N,N,N,64242,N,N, +N,N,N,N,N,N,N,N,N,37848,N,N,N,64735,N,N,N,37843,N,N,N,N,N,N,N,64737,N,N,N,N,N, +N,N,N,N,36470,N,N,N,N,N,N,N,64610,N,N,N,N,N,N,N,N,37841,N,N,N,36273,N,N,N,N,N, +N,N,39001,N,N,N,N,N,N,N,N,N,64338,N,N,N,N,N,N,N,N,64339,N,N,N,N,N,64333,N,N, +40127,N,N,N,N,N,N,N,N,39794,N,N,N,N,N,N,N,N,N,N,N,N,N,64336,37822,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40433,64747,N,N,N,N,N, +N,N,N,N,41147,N,39806,N,N,N,N,N,N,N,36275,N,N,35922,N,N,N,N,39656,N,N,N,N,N,N, +36572,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40185,N,N,N,N,N,N,N,N,N,N,N,N,N,64080,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39143,64755,N,N,N,N, +64754,N,N,N,36042,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,37861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39513,N,N,N,36277,N,N,N,N,N,N, +N,64845,N,N,N,N,64862,N,N,N,N,N,N,N,N,N,N,N,N,N,36733,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,38215,64758,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37456,N,N,N,N,35176,36278,64763,41085,39164,35177,N,N,N,N, +N,N,N,N,65103,N,N,37462,N,N,N,N,N,N,N,N,N,N,64201,N,N,37864,N,N,N,64760,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40163,64937,N,N,N,N,N,N,64580,N,N,N,N,N,N,N,N, +38464,N,N,36280,N,N,N,N,N,N,N,N,N,N,39754,36793,N,N,N,N,N,N,64766,N,N,N,N,N,N, +N,35178,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36281,N,N, +N,37246,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37876,N,N,N,N,N,N,N,N,N,N,N,N,N,64380,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37863,N,N,38895,N,N,N,65098,N,N,N,N,N,64837,N, +38565,N,N,N,N,65248,64840,64839,65266,65130,N,N,N,N,N,36285,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39841,36002,39607,36604,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40865,N,N,N, +N,N,N,N,N,N,64849,N,N,N,N,N,N,N,64173,N,N,N,N,36286,N,N,35236,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39641,N,N,N,N,N,N,N,N,N,N,N,64846,N,N,36288,N,N,38896,N,N,N,N,N,N, +N,N,N,N,37812,64836,N,N,N,N,N,N,N,N,N,N,N,N,40871,N,N,N,N,36290,N,N,N,N,39350, +N,N,N,N,N,N,N,N,N,N,N,N,N,64850,N,N,N,N,N,N,36289,N,N,36422,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,41169,N,N,N,N,N,N,N,N,N,N,N,N,N,40906,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37583,N,N,N,40180,36292,N,N,N,N,N,N,N,N,N,N,64833,N,N,N,N,N,N,N,39756,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64855,64751,40158,N,N,N,N,N,N,N,64834,39020,N,N,N,N, +N,N,N,N,N,N,N,N,N,38905,N,38232,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39006,65147,38093, +N,N,N,N,N,37870,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36003,N,64858,N,N,N,N,N,N,37877, +N,N,N,N,N,37871,36586,N,N,N,36699,N,N,N,N,N,N,N,N,N,N,N,35934,N,36294,N,N,N,N, +N,N,N,N,N,N,N,36296,N,N,36295,N,N,N,N,N,37879,N,N,N,N,N,N,N,36297,N,N,N,N,N,N, +N,64498,N,N,N,N,38512,N,N,N,N,N,N,N,N,N,36299,N,N,N,64860,N,N,N,N,N,N,N,N,N, +36709,N,N,N,36301,N,N,N,N,N,40360,38137,N,N,36302,N,N,N,N,N,N,N,N,37866,N,N,N, +N,N,N,N,N,N,64863,37872,40886,N,N,N,N,N,N,N,N,N,36303,N,N,N,38755,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36304,37873,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64866,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40923,N,N,N,N, +37880,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35831,N,N,N,N,64870,N,N,N, +N,N,35791,N,N,N,N,N,N,36305,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36306,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64881,N,N,N,N,64879, +N,N,N,N,N,N,N,N,36307,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40935,37053,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40912,N,N,N,35792,N,64882,N,40110,35793,N,N,35547,N, +N,N,N,N,N,N,N,N,N,N,64228,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38350,N,64886,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64354,N,N,N,N,N,N,36308,N,N,N,64888,N,N,N,N,N, +36579,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36982,N,N, +39110,N,N,N,N,N,N,N,36309,N,N,N,N,38865,N,N,40630,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,64199,N,N,41026,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39027,N,N, +N,N,N,N,N,N,N,N,40956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36005,36311,N,N, +37627,36312,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37967,N, +36313,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,35179,N,N,N,N,N,N,N,N,38862,N,N,N,64243,64942,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64431,37559,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36314,N,N,N,N,N,N,N,N,N, +N,N,N,N,40026,N,N,N,N,N,N,64941,N,N,N,N,N,N,N,N,N,N,N,N,N,36316,37956,N,N,N,N, +N,N,N,N,N,N,N,36317,N,N,N,N,N,N,N,41174,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,35905,38869,N,37962,N,N,N,N,N,37965,N,N,N,N,38859,N,N,N,N, +N,36318,N,N,36319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36320,65273,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64960,64761,N,N,N,N,N, +N,N,N,64382,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37555,N,N, +N,N,N,64943,N,N,N,N,N,N,N,N,N,36321,N,N,N,N,38355,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35265,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64872,N,N,40119,N,N, +36323,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64192,36325, +64100,N,35143,N,N,N,N,36324,N,N,N,N,N,36327,36328,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64967,64944,N,N,N,N,N,N,37957,38870,N,N,N,N,N,N,N,N,N,64710,38980,N,N,N,N, +N,N,N,N,N,N,N,N,36329,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36330,N,N,N,N,N,N,N,N, +65104,N,N,N,N,N,N,64972,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40359,N,N,N,N,N, +64973,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64975,N,N,N,N,38354,N,N,N, +N,N,N,N,36333,N,N,N,N,N,N,N,N,64698,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64965, +N,64978,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40156,N,N,N,N,N,38351,N,N, +36334,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64980,N,N,N,N,N,38636,38635,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37046,N,64963,39083,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38638,N,N,N,N,N,N,N,N,N,N,N,N,N, +36340,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64992,N, +35943,N,N,36342,N,N,N,36343,N,N,N,N,N,N,N,36858,N,N,N,N,N,N,N,N,N,N,38864,N,N, +N,N,35794,N,N,36344,N,N,N,N,N,37081,N,35911,N,64240,N,N,N,N,64993,36345,N, +64995,N,N,N,N,N,N,N,36346,N,64355,N,N,N,37030,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39280,N,N,37355,N,38768,39023,64994,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39154,N, +39676,35180,65021,N,N,39262,N,N,N,38333,N,N,N,N,N,N,N,64996,N,N,N,37350,N,N,N, +N,64997,64998,N,N,N,N,N,N,N,N,64999,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37972,N, +N,N,39352,N,N,N,N,N,N,N,N,38889,37702,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39011,N,N,N,N,N,N,N,N,N,N,N,38332,N,65005,65015,N,N,N,N,N,N,39024,38646, +36521,N,N,N,N,N,37969,N,N,36419,N,35674,N,N,N,N,65006,N,N,N,N,65008,N,N,N,N, +65012,N,39925,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38782,N,N,N,N, +N,39893,N,39619,N,38856,41179,37328,N,N,40932,N,36829,N,37353,N,N,N,N,N,N,N,N, +N,39136,N,N,N,37578,N,38999,N,N,35921,N,N,N,N,65003,N,39753,N,N,N,N,N,N,N,N,N, +40310,40623,N,N,N,N,N,N,N,N,N,40140,N,N,N,N,N,N,65002,N,N,36337,N,N,65019,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36435,N,N,N,N,N,N,N,N,N,N,N,64207,N,N, +N,N,N,N,N,N,N,N,N,N,N,38649,N,N,N,N,N,N,N,N,N,39103,40521,36007,N,N,N,N,N,N,N, +N,39882,N,N,N,N,65022,37596,N,N,N,N,N,65089,37324,37346,N,N,N,N,N,N,N,N,N,N,N, +N,65092,N,N,N,N,N,N,35795,N,N,65095,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65096,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37973,N,N,N,N,65099,N,65100,N,N,N,N,36287,N,N,N,N, +N,N,N,N,N,40568,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65105,N, +N,N,N,37974,N,N,N,N,N,N,N,40289,N,N,N,N,37975,N,N,N,N,N,N,N,N,N,N,39270,N,N,N, +N,N,N,N,N,N,N,N,N,N,35797,N,N,N,N,41065,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,39092,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41033,41036,N, +40549,N,N,N,N,N,N,N,N,N,N,N,39093,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,65112,N,39285,65107,41061,N,65113,N,N,N,N,N,N,N,N,N,39095,39096,N,N,N,N,N,N, +N,39098,N,N,N,N,N,N,39099,N,N,N,N,N,N,40892,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41034,N,N,40647,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,36009,N,N,39086,N,N,N,N,N,N,N,N,37590,N,N,N,64225,N,37332,N,N, +N,N,N,N,N,N,64222,N,N,65115,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35923,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,65118,N,N,N,N,64471,65114,38085,N,N,N,N,64202,N,N,N,N,N,N,N,N,N, +N,N,39105,38748,N,65140,N,38771,N,N,N,N,N,N,N,N,64070,N,N,N,38756,N,N,N,65128, +N,38478,N,38757,35930,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35233,38394,N,37588,65129,N, +64325,N,39112,N,N,37103,N,39113,39114,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37997,38071,65132,N,N,37995,N,N,N,N,N,N,37628,N,38379,N,65139,38766, +65119,N,N,N,N,N,N,N,N,N,64957,N,N,37589,N,N,N,N,N,N,65209,N,N,65137,N,N,N,N, +64443,N,N,38010,N,N,38395,65143,N,N,N,N,N,N,N,65145,N,65141,N,N,N,37981,N,N,N, +N,N,N,N,65148,N,N,N,N,N,N,N,N,N,37700,36518,N,N,N,N,N,N,N,N,N,N,N,37587,N, +38072,N,N,N,N,N,N,N,N,64625,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38750,N,N,N,N,36013, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,65191,N,N,N,37994,N,N,N,37859,N,N,39119,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,41177,N,N,N,N,N,N,N,N,41151,41037,41144,N,N,N,N,N, +41166,41143,N,N,N,N,N,N,N,N,65193,N,N,N,N,N,N,N,N,N,N,35267,N,N,N,N,65195,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40436,35181,N,N,N,N,N,40059,N,N,N,N,N,N, +39122,N,N,N,40873,N,N,N,65202,N,N,65201,N,N,N,38873,N,41156,N,38006,N,N,N,N,N, +N,N,N,N,N,39288,N,N,N,N,N,N,65203,N,N,N,N,N,39123,65204,N,N,N,39124,N,N,N,N,N, +N,N,40889,N,N,N,N,N,N,N,N,38001,N,N,N,N,N,N,N,N,N,39125,65208,N,N,N,50900,N,N, +N,N,N,N,N,N,N,N,N,65210,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40540,N,N,65211,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,41028,N,N,N,N,39127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39128,65212,N,N,N,N,40958,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,65213,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40413,N,N,N,N, +40673,N,N,N,N,N,N,N,N,N,N,N,N,39130,40415,65215,N,65214,N,N,40683,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40537,41052,N,N,N,N,N,N,N,65216,N,N,N,38007,39132,N, +65217,N,N,N,39134,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65219,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,65224,N,N,N,65225,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65226, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65227,N,N,N,N,N,N,N,N,N,40898,N,N, +35947,39108,N,38064,38065,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65233,N,N,N,N,N,41153,N, +65234,N,N,N,N,41165,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65235,N,N,39141,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65238,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37348,N,N,N,N,36807,38062,N,35407,38066,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36820,N,N,N,N,39146,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65240,N,N,N,N,N,N,N,N,N,40416,N,N,N,N,39150,N,N,N,N,38340,N,64744,N, +N,N,N,N,39151,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35950,N,N,N,N,N,N,N,N,64216,N, +N,N,N,N,N,N,N,N,N,N,N,N,65244,N,N,N,N,N,N,N,N,N,41134,40268,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39153,N,N,N,39155,N,38081,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39157,N,N,64079,38626,N,N,N,N,37968,N,38562,N,N,39158,N,N,N,38629, +N,N,N,N,N,39159,N,41030,38627,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39160,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40676,N,N,N,N,N,N,63958,N,N,N,N,N,N,38083,N,N,N, +N,38082,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +65249,N,65257,N,N,N,N,38628,N,35244,38619,N,N,N,N,N,N,N,N,N,N,N,N,N,65250,N,N, +N,N,N,N,N,N,N,N,38084,65251,N,N,N,65255,40955,N,N,N,N,N,N,N,N,N,N,N,35929,N,N, +N,N,N,N,N,N,N,37833,N,38120,64342,N,N,N,37061,41128,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65253,N,N,N,39165,39163, +65256,N,36543,N,N,N,N,35800,65271,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36712,38086,N,N,N,N,N,N,N,N,40426,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64617, +N,N,N,N,N,N,N,N,N,N,N,N,40154,N,65267,N,N,40050,N,N,65264,35273,N,N,N,N,N,N,N, +N,N,39233,N,N,N,N,N,N,N,39234,N,N,N,65269,N,37335,N,N,N,N,N,38092,N,N,N,65272, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38824,N,65276,N,N,N,N,N, +64959,N,N,N,N,N,N,N,65278,N,N,N,N,N,N,N,N,N,N,N,N,N,38609,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,38101,N,N,38096,39236,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,35939,N,N,41139,N,N,N,N,N,N,N,N,N,N,N,N,38095,N,N,N, +40954,N,N,N,N,37349,N,40042,N,N,N,36425,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,36428,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36429,N,N, +N,N,N,39539,N,N,N,N,N,N,N,N,N,N,N,N,N,39239,N,36017,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36432,N,N,N,N,N,N,N,N,N,N,36431,39241,N,N,N,N,N, +36433,36434,N,N,N,N,39602,35237,N,N,N,N,N,39244,N,N,N,40952,N,N,N,N,N,N,36438, +39245,37322,36439,N,N,N,N,38113,N,N,N,N,36935,N,36824,36440,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,38123,36444,38227,N,N,N,N,N,N,N,40933,N,N,N,N,N,N,N,N,N,N, +40790,N,N,N,N,N,N,N,38223,N,36446,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39274,N,N,N,N, +N,N,N,N,40036,40153,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36445,N,N,N,N,N,N,N,N,N, +N,N,N,39248,N,N,N,N,N,N,N,N,N,39249,N,N,36450,N,N,N,N,N,N,N,N,N,N,N,39250,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36456,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36449,40793,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35763,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40797,36454,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36018,N,N,N,N,N,N,N,N,N,N,N,N,N,36462,N,40804,39251,N,N,64184,N,N, +N,N,N,39252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36464,N,N,N,N,N, +N,N,N,N,N,N,N,40801,N,36466,N,N,N,N,N,N,N,N,N,N,N,N,41067,N,N,N,N,40768,N,N,N, +N,N,N,38125,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38126,N,N,40893,N,N,N,36475,N,N,N,N, +N,N,39255,38135,N,40799,N,N,N,N,36467,N,N,40802,N,N,N,N,N,N,N,38134,N,N,N,N,N, +N,N,N,N,N,N,N,N,39256,N,N,N,N,N,N,N,N,N,36469,63963,N,N,N,N,36978,N,38136,N,N, +N,N,N,N,N,N,N,39258,N,N,N,N,N,N,N,N,N,41136,36019,N,N,N,36473,N,36472,N,N,N, +38131,N,N,N,N,N,39087,N,N,N,N,N,N,41138,N,N,N,N,N,N,N,N,N,N,N,36474,N,N,N,N,N, +N,39260,N,N,N,N,N,36476,N,36477,N,N,N,35801,N,N,35234,40663,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41142,N,N,N,N,N,N, +N,N,N,N,N,N,40514,N,N,36516,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36519,N,35958,N,N,N,N,N,N,N,N,N,N,N,38210, +N,N,N,N,N,N,N,N,N,N,N,N,39037,N,N,N,38741,N,N,36520,N,N,N,N,N,N,N,36522,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35235,N,39264,39266,N,N,38140, +39265,N,N,N,N,N,N,N,38138,N,N,N,N,N,N,N,36526,36530,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,36528,N,N,N,N,N,N,N,39267,38826,38139,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,36539,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36060,N,N,N,N,N,N,N,N, +N,39030,N,36513,N,N,N,N,36020,N,36535,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40358,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40624,N,N,N,36536,N,N,N,N,N,N,N,N,N,N,N,N,40304,N,N, +N,N,35182,N,N,N,N,N,N,N,35183,N,N,N,N,N,N,N,N,N,N,N,N,N,35184,N,N,N,N,N,N,N,N, +N,N,N,N,35185,N,N,N,N,N,N,N,35186,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35187,35188,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35189,N,N,N,N,N,N,N,N,36540,36541,N,N,N,N,N,36542,N,40401,N,N, +N,N,38141,N,N,N,35799,35802,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,41186,N,N,N,N,N,N,40937,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64936,N,N,N,35559,N,N,N,36546,N,N,N,N,N,N,N,N,N,N,N,36548,N,N,N,N,N,N,N,N,N,N, +39268,N,N,N,N,N,39269,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,38222,N,N,N,N,N,N,N,N,N,39091,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36555,35807,N,N,N,N,N,36558,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,36559,N,N,39272,N,N,N,N,39273,N,N,N,N,N,N,N,N,39275,36561,N,39276,N,N,N,N,N, +N,N,N,N,36564,36565,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39277,N,N,N, +N,N,N,41150,N,N,N,N,N,36566,41148,41141,N,N,41140,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,35808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35253,N,N,N,N,N,N,N,36573,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40541,39281,N, +N,N,N,35246,40424,N,N,N,N,N,N,N,N,38245,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39282,N,N,35676,N,N,N,N,N,N,N,N,N,35249,41152,N, +N,N,36575,N,38246,N,N,39284,N,39286,N,N,N,39287,N,39289,N,N,40410,N,N,36576,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37724,N,N,N,N,N,N,N,40422,N,35679,N,N,38243,N,N,N, +N,N,N,N,N,N,N,38247,N,N,N,N,N,40419,N,N,N,N,N,N,N,N,N,N,N,N,N,39292,N,N,39293, +39294,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35675,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39331,N,N,N,N,N,N,N,39332,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39334,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39336,N,N,N,N,35518,N,N,N,N,N,N,N,N,N,N,N,40545,N,N,N,N,N,N,N, +N,N,N,39338,N,N,N,N,N,N,41160,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39339,N,N,N,N,N,N,N,N,N,N,65220,N,N,N,N,N,N,39106,36584,N,41146,N,N,N,N, +N,N,N,N,N,N,N,64887,N,N,36590,N,N,N,40639,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35266,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39340,N,N,N,N,N,N,N,N,N,N,N,N, +N,38251,N,N,38252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39343,N,N,39242,35190,36680, +N,N,N,N,N,N,N,N,N,N,N,64494,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39342,N,N,N,36603,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36048,N,N, +N,N,35666,N,N,N,N,N,39344,N,N,N,N,35191,36673,N,N,N,N,N,N,N,39345,N,N,N,N,N,N, +N,N,N,36681,N,N,N,N,N,N,N,N,N,N,N,64077,N,N,N,N,N,N,N,N,40420,36021,N,N,N, +64489,39764,N,39346,40552,N,N,N,N,N,N,N,N,N,N,N,N,36682,N,36674,N,N,36689,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38982,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39348,N,N,N,N,N,N,N,N,N,N,36597,64853,N,N, +40141,N,N,N,N,N,N,N,N,35192,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36691,N, +N,N,N,N,N,N,N,N,N,N,36719,N,N,N,N,N,N,N,N,N,N,36451,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,36694,N,N,N,N,N,N,N,N,N,N,N,N,65142,N,N,N,N,40902,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64172,N,N,N,N,N,36696,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38984,39351,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38501,N,64108,N,40423,N,N,N,40546,N,N, +N,38604,36455,N,N,64629,N,39038,N,N,N,N,N,N,N,64953,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,38908,N,N,N,N,N,N,N,N,N,39161,N,36710,N,N,N,N,N,N,N,N,38254,N,37445,N,N, +36704,N,N,N,40657,N,N,N,N,N,65229,N,39353,N,N,N,N,N,N,N,N,N,N,N,N,36706,38732, +N,N,N,N,N,N,N,N,N,N,N,N,37319,38239,N,N,N,N,N,N,N,39355,N,N,N,N,N,N,N,N,N, +36461,36721,N,N,38091,N,N,N,N,N,N,N,N,N,N,N,N,38321,N,N,N,N,N,N,N,N,N,39666,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38595,39357,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,41167,N,N,N,36717,N,N,39358,36596,N,36722,38372,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39359,37442,N,64421,N,N,N,N,N,N,N,N,N,N,39360,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64948,36727,N,N,N, +39361,N,N,N,N,N,N,N,N,N,64185,N,N,N,N,N,N,N,N,36672,64068,N,N,N,N,N,39362,N,N, +N,N,N,N,N,36700,N,N,N,N,36029,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39364,39365,N,N, +36731,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36022,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36771,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36046,N,N,N,N,N,N,N,N, +N,39366,N,N,N,N,N,N,N,N,N,N,N,N,N,38605,N,N,N,N,N,N,N,N,N,N,N,N,N,38599,36773, +N,N,N,N,N,N,N,N,N,N,64187,N,35937,38256,N,N,N,37736,N,36734,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,36778,N,N,N,N,N,N,41040,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37075,N,N,38230,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,36792,N,N,N,N,N,39368,N,N,N,N,N,N,N,N,N,N,N,36783,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39369,N,N,N,N,N,N,N,N,N,N,N,N,N,38265,N,N,N,N,N,N,N,N, +N,N,N,N,40777,N,N,N,N,39370,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39371, +40405,36784,N,N,N,N,N,N,N,N,N,N,N,64122,N,N,N,N,N,N,N,N,40543,N,N,N,N,39373, +41161,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39643,N,N,N,41158,N,N,N, +N,N,N,N,36788,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41175,N,N,N,N,N,N,N,N,N,N,N,N, +41159,N,N,N,N,N,N,N,41027,N,N,N,36789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36786,N,N,N,N,N,N,41057,40542,N,N,N,N,N,N,N,N,N,N,36790,N,N,N,N,N,N,N,N,40936, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40114,N,N,N,N,N,38268,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40903,N,N,36795,36796,N,N,N,N,N,N,N,N,36844,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36800,N,37738,N,N,N,35812,40060,N,N,N,N,N,N,N,N,38305,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,65260,N,N,38307,N,N,N,N,N,N,N,35909,36024,N,N,N,N,N,N, +N,N,N,N,N,36801,N,N,N,41042,N,N,N,N,N,N,N,N,N,N,N,N,N,39376,N,N,N,N,N,36803, +36804,N,N,N,N,N,N,N,N,N,38308,N,N,N,N,N,36806,N,40544,N,N,N,N,N,N,N,63960,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38309,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40115,N,N,N,N,N,N,N,N,N,39377,65265,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,39378,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40130,N,N,N,39379,N,N,N,N,N,38311,N,N,N,N,N,N,38313,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,38310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40029,N,N,N,N,N, +N,N,N,39138,N,N,N,N,N,N,36809,N,41154,36810,N,N,N,N,N,N,39380,N,N,41145,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39768,N,36813,N,41172,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36814,N,N,N,N,35813,N,N,N,N,35193,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,36816,38326,N,N,N,N,N,N,N,N,N,N,N,N,39382,N,38373,N, +N,N,N,N,N,N,N,N,N,N,N,39383,N,N,N,N,38325,N,N,N,N,N,N,N,N,N,N,N,41162,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40957,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,41048,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36822,N,N,N, +39384,N,N,N,N,N,N,N,36819,N,N,N,N,N,N,N,N,N,N,N,N,36837,N,N,N,N,N,36841,N,N,N, +N,39385,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37500,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40005,36830,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36831,N,N,N,N,N,N,N,N,N,N,N,N,N,41035,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,36834,N,N,N,41164,N,N,N,N,N,N,N,N,36835,36836,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39876,N,N,N,39932,N,N,N,N,N,N,38476,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,39670,N,36014,N,N,N,N,N,N,N,N,N,N,N,N,36839,N,N,N,N,N,N,N,N,N,N,36840, +N,N,N,N,35815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35194, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35195, +39386,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36845,N,N,N,38336,N,N,N,N,N,N,N,N,N,N,N,N,N,41163,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40520,N,N,N,N,N,N,39387,N,36851,N,N,N,N, +36857,N,N,N,N,N,N,N,N,N,N,N,N,N,38337,N,41038,N,N,N,N,N,N,39388,N,N,N,N,41060, +36855,N,N,N,N,N,N,N,35248,41032,N,N,N,N,36859,36854,N,N,N,N,N,40412,N,N,N, +39389,35816,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37569,N,N,N,N,N,N,N,40918,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41170,N,N,36928,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35524,N,N,39392,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40944,40947,N,N,N,N,N,N,N,N,N,N,N,N,40383,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40950,N,38344,N,N,40538,N,N,N,N,N,N,N,N,N,N,N,N,39395, +N,N,N,N,N,N,N,N,N,N,N,35402,N,N,N,N,N,N,N,N,40945,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,35495,N,N,N,N,N,N,N,N,39398,N,N,N,40951,N,40941,N,N,N,N,N, +N,35420,N,40366,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38345,N,N,N,N,N,36936,N,N,39400,N,N,N,N,N,36937,N,N,36026,N,N, +37041,N,N,N,N,N,N,36938,N,N,N,N,N,N,N,N,N,N,39402,N,N,N,N,N,N,N,N,N,N,N,39889, +N,N,N,N,N,N,N,39403,N,39404,N,N,N,N,N,N,N,N,39405,N,N,N,N,39406,36940,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36941,N,N,38347,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38882,N,N,N,N,N,N,N,N,38348,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40824,N,N,N,N,N, +N,N,N,N,35196,35197,N,N,N,N,N,N,35198,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39261,N,N,N,N,N,N,N,N,N,N,N,N,39770,N,N,N,N, +36944,N,35919,N,N,N,N,N,N,N,N,N,N,N,36948,N,50902,39592,39407,65259,40355, +40353,39235,39237,N,40317,N,N,39408,N,N,N,N,N,N,N,N,39409,N,39410,N,N,36028, +40288,N,N,N,N,N,N,N,N,N,41123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36955,40667,N,N,N,N,N,N,N,N,N,40313,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39411,N,N,N,36962,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40789,N,N,N,N,N,N,N,N,N,39929,N,N,N,N,N,N,N,N,N,N,36965,N,N, +38624,N,N,N,N,N,N,N,39102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36968,N,N,N, +N,N,36972,N,N,N,N,N,N,N,N,N,N,N,N,38360,N,N,N,N,N,N,N,N,36970,40882,N,N,N,N,N, +N,N,40878,N,N,40880,N,35245,N,N,N,N,N,N,N,N,36974,N,N,N,N,N,N,N,N,40561,N,N,N, +N,N,40522,N,N,N,N,N,40924,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35243,N,40888,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36976,N,N,N,N,N,N,N,N,N,N,N,N, +35683,N,N,N,N,38364,N,N,N,N,N,N,N,N,36977,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64606,N,N,N,N,N,N,N,N,35145,N,N,N,N,N,38491,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35920,N,N,N,38054,N,N,N,36821,40563,N,N,N,N,N,36981,N,N,N,N,39415,N,N,N,N,N,N, +N,N,N,N,N,N,N,36031,N,N,N,N,N,N,39417,N,38499,38329,N,N,N,N,N,N,N,N,N,38100,N, +N,N,N,N,N,64762,N,N,N,N,36983,N,N,37035,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40269, +N,N,39418,N,N,N,N,37603,N,38843,N,N,36984,N,N,N,N,N,N,N,N,39419,N,N,38880,N,N, +N,N,N,N,N,N,38620,N,N,N,N,N,N,N,N,N,40104,N,N,38770,N,N,N,N,37952,N,N,N,N,N, +37618,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39421,N,N, +39420,N,N,N,N,N,N,N,63959,38474,N,N,N,38616,39422,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36939,N,N,N,N,N,N,64065,N,N,N,N,N,N,N,39488,N,38747,N,N,N,N,N, +39489,37341,N,N,N,N,N,37884,39490,39491,N,38489,N,N,N,N,N,N,39492,36945,N,N,N, +38079,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37026,N,N,N,40107,38774,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64597,65093,38056,39493, +64075,40417,N,N,38617,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38772,N,N, +65013,N,N,N,37605,N,38469,37338,N,37027,N,N,41055,N,N,N,N,37039,38847,N,N,N, +37196,N,N,N,N,38522,N,N,N,37342,N,N,39494,65200,38777,37996,N,N,N,N,N,N,N,N, +39000,N,N,N,N,N,N,N,N,N,N,N,37478,N,N,N,37883,N,N,N,N,N,N,N,N,N,N,N,N,39495,N, +N,N,N,N,N,N,N,N,N,38729,N,N,38728,N,37706,N,40162,N,N,N,N,N,N,37476,N,N,N,N, +37343,N,N,N,N,N,N,N,64377,N,N,N,N,N,N,N,38615,N,N,N,N,37699,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64971,65146,N,37339,35946,38831,N,N,38365,N,N,N,37704,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39499,N,N,N,64581,N,39501,N,N,N,N,N,N,37308,37090,37044,38369, +N,N,N,N,N,39502,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39503,N,N,N,65088,65091,N,N,N, +N,N,N,N,N,N,38621,N,N,N,N,N,N,39505,N,N,N,38567,N,N,37040,N,N,N,N,N,N,N,N,N, +40014,N,37955,N,N,N,N,36538,N,N,N,N,N,N,N,N,N,N,N,N,39506,N,64705,N,N,N,N,N,N, +N,N,N,35817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40111,N,N,35837, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39612,N,39608,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39598,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39591,39507,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40308,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35818,N,N,N,N,N,N,35819,N,N,N,N,N,37042,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,38377,38376,N,38374,N,N,N,N,N,N,37045,N,39508,N,N,N, +37043,38375,N,N,35664,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35820,N,N,N, +N,N,N,N,N,N,N,N,39510,35835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39511,N, +N,N,N,41130,N,N,N,N,N,N,N,N,40870,N,N,N,39372,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40025,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39349,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37054,N,N,N,N,N,40879,N,N,N,N,N,N,N,N,N,N,N,N,N,38386,N,N,N,N,N,N,37055,N, +N,N,N,N,N,N,N,N,N,N,N,37057,N,65252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37060,N,N, +N,N,N,N,37063,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37604,40786,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37083,N,N,N,N,N,41062,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37074,N,N,N,N,37076,N,N,N,N,N,N,N,N,N,39515,38397,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,35780,N,N,N,35942,N,37086,N,N,N,N,N,40164,N,37089,N,N,N,N,N,N,N,N,N,N,N,N,N, +40518,N,N,N,38481,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64344,N,37094,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38480,N,N,N,37095,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37096,39517,N,40826,N,N,N,39772,N,40828,N,N,64594,37097,N,37098,N,39518,N, +N,N,N,N,40822,N,N,N,N,N,N,N,N,N,37099,N,N,N,N,N,N,N,N,N,N,N,N,N,37100,N,N,N,N, +N,35822,N,N,N,N,N,N,N,37102,N,N,N,37318,N,N,37106,64700,35444,N,N,N,N,N,N,N,N, +N,38487,N,N,N,40175,N,N,N,N,N,N,N,N,N,N,40927,N,N,N,N,37111,37110,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39774,N,N,N,37112,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37113,N,36041,N,N,N,64106,N,N,N,N,N,N,N,N,35823,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40928,N,N,37186,N,39522,N,N,N,N,N,N,N,N,N, +38249,N,N,N,37188,37187,N,37185,N,N,N,35824,N,N,N,N,N,N,N,N,N,N,N,N,N,38496,N, +35825,N,39414,37193,N,N,N,N,37194,N,N,N,N,N,37195,N,N,N,N,39524,N,N,N,35519, +39526,N,N,N,N,N,N,N,N,N,N,39527,N,N,39529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39530,38482,37197,N,38502,N,N,N,N,40827,N,39531,N,N,N,N,N,N,N, +41068,N,N,38503,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39532,N,N,N,N,39533,35826,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,38506,N,N,N,N,N,N,N,N,64746,N,N,N,N,N,38508,N,N,N,N, +N,N,N,N,N,N,N,N,N,37316,N,N,N,38519,N,N,N,N,N,N,N,39412,39535,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40875,N,N,N,N,N,36030,36545,N,N,N,N,38229,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37202,37203,N,N,N,37205,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38237,N, +38513,N,N,N,N,40045,N,N,N,N,N,N,N,N,38515,N,N,N,N,N,N,N,N,N,N,N,37204,39537,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37206,N,N,N,38509,N,N,N,N, +N,N,38231,N,N,N,N,N,N,N,N,35270,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,35271,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,35434,N,N,N,35671,N,N,N,40929,N,N,39775,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41053,N,N,N,N,N,N,N,N,37211,N,37212,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37214,N,N,N,N,N,N,N,N,N,N,40796,40791,N,N,N,N,N,N,40805, +N,N,N,N,N,39538,N,N,N,N,37216,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40798, +N,N,37217,N,N,N,N,N,N,37220,N,N,N,N,40769,N,N,N,N,N,N,37225,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,37224,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39540,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38578,N,39541,N,64933,N,N,N,N,N,N,N,40681, +N,35770,37229,41056,N,N,N,N,N,N,N,40926,N,N,N,N,N,40899,N,38581,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,41063,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,38579,N,N,N,N,N,N,N,N,N,N,N,N,N,39542,N,N,N,N,N,N,N,N,N,N,N,38357,N,N,N, +40650,N,N,N,39543,N,N,39544,N,N,N,N,N,N,N,N,N,N,37232,37231,N,N,N,N,N,N,N, +40867,N,37233,N,N,N,38577,N,N,N,N,40803,N,N,N,N,N,40807,N,N,N,35769,39546,N,N, +N,N,N,35670,N,N,N,N,N,N,N,N,39642,N,N,N,N,N,38576,N,N,N,N,39550,N,N,N,N,N,N,N, +N,N,N,40414,N,N,N,N,N,N,N,N,N,38573,N,N,N,38574,N,N,N,N,N,N,N,N,N,40609,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40528,N,N,N,N,N,N,N,N,38575,35828,40868,N,N, +N,N,N,N,N,N,N,38589,N,N,N,N,N,N,N,N,N,38644,N,N,N,N,N,N,N,N,N,N,38584,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64161,N,N,N,N,37287,N,N,N,N,N,N,N,N,N,N,41054,N,N, +N,N,39549,N,N,N,N,35144,N,40625,N,N,N,N,N,N,N,N,N,N,N,N,N,40411,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38335,35443,N,N,N,N,N,N,N,N,N,N,N,N,N,40702,N,37242,N,N,N,N, +37243,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39587,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38594,N,N,N,N,N,40823,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39588,N,N,39589,N,N,N, +37281,N,N,N,N,35256,N,N,N,N,N,N,N,N,N,N,37235,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39590,35261,N,35257,N,37245,N,N, +N,N,N,N,N,N,N,38587,N,N,N,40946,N,N,35829,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39593,N,N, +N,N,N,40788,N,N,40931,40685,N,N,N,N,N,N,N,N,N,N,37290,N,N,N,N,37291,41072,N, +40813,N,N,N,N,N,37292,N,N,N,37293,N,N,N,41213,N,40930,N,37295,40513,39594,N,N, +37296,N,39595,N,N,N,N,N,N,N,N,N,N,N,39596,N,39498,N,37298,N,N,35830,N,39597, +35254,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39599,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,39600,N,N,N,N,N,N,39601,N,N,N,N,N,39585,37305,N,N,N,N,N,37306,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,37310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41025,35767,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37312,N,N,N,N,N,N,N,N,N,N,39603,37315,N,N,N,N,N,N, +N,N,N,N,41212,N,N,40942,N,N,N,N,N,N,40809,N,N,N,N,N,N,N,37320,N,N,N,N,N,N, +37321,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36326,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37323,N,N,N,N,N,N,N,N,N,N,35272,N,N,N,N,N,36266,N,N,N,N,N,40925,34880, +34881,34882,34883,34884,N,34886,N,N,34889,34890,N,N,34893,N,34895,34896,34897, +34898,N,34900,34901,N,N,N,N,N,N,N,N,N,N,N,N,34914,N,34916,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34979,N,34981,N,N,N,34985,34986,35907,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35949,N,N,N,N,N,N,35956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36023,N,36025,N,36027,N,N,N,N,36032,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36055,36056,N,36058,51321,N,N,N,N,51326,51361,N,51363,35832,51408, +N,N,N,N,51407,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50916,N,50917,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,51405,N, +51406,N,N,N,N,N,N,N,N,63998, +}; + +static const struct unim_index big5hkscs_bmp_encmap[256] = { +{__big5hkscs_bmp_encmap+0,168,252},{__big5hkscs_bmp_encmap+85,0,220},{ +__big5hkscs_bmp_encmap+306,80,198},{0,0,0},{__big5hkscs_bmp_encmap+425,1,81},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5hkscs_bmp_encmap+506,190, +193},{0,0,0},{0,0,0},{__big5hkscs_bmp_encmap+510,22,231},{0,0,0},{0,0,0},{ +__big5hkscs_bmp_encmap+720,96,125},{__big5hkscs_bmp_encmap+750,80,112},{0,0,0 +},{__big5hkscs_bmp_encmap+783,61,61},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{__big5hkscs_bmp_encmap+784,128,227},{__big5hkscs_bmp_encmap+884,51,51 +},{__big5hkscs_bmp_encmap+885,5,254},{0,0,0},{__big5hkscs_bmp_encmap+1135,49, +49},{0,0,0},{__big5hkscs_bmp_encmap+1136,53,251},{__big5hkscs_bmp_encmap+1335, +6,254},{__big5hkscs_bmp_encmap+1584,9,245},{__big5hkscs_bmp_encmap+1821,1,251 +},{__big5hkscs_bmp_encmap+2072,15,250},{__big5hkscs_bmp_encmap+2308,8,254},{ +__big5hkscs_bmp_encmap+2555,1,251},{__big5hkscs_bmp_encmap+2806,14,244},{ +__big5hkscs_bmp_encmap+3037,13,239},{__big5hkscs_bmp_encmap+3264,19,253},{ +__big5hkscs_bmp_encmap+3499,6,255},{__big5hkscs_bmp_encmap+3749,0,250},{ +__big5hkscs_bmp_encmap+4000,4,250},{__big5hkscs_bmp_encmap+4247,3,249},{ +__big5hkscs_bmp_encmap+4494,17,252},{__big5hkscs_bmp_encmap+4730,43,242},{ +__big5hkscs_bmp_encmap+4930,1,244},{__big5hkscs_bmp_encmap+5174,3,233},{ +__big5hkscs_bmp_encmap+5405,6,245},{__big5hkscs_bmp_encmap+5645,19,244},{ +__big5hkscs_bmp_encmap+5871,0,250},{__big5hkscs_bmp_encmap+6122,6,231},{ +__big5hkscs_bmp_encmap+6348,15,255},{__big5hkscs_bmp_encmap+6589,16,192},{ +__big5hkscs_bmp_encmap+6766,4,237},{__big5hkscs_bmp_encmap+7000,9,156},{ +__big5hkscs_bmp_encmap+7148,4,248},{__big5hkscs_bmp_encmap+7393,3,253},{ +__big5hkscs_bmp_encmap+7644,3,252},{__big5hkscs_bmp_encmap+7894,1,254},{ +__big5hkscs_bmp_encmap+8148,2,249},{__big5hkscs_bmp_encmap+8396,1,254},{ +__big5hkscs_bmp_encmap+8650,19,239},{__big5hkscs_bmp_encmap+8871,2,251},{ +__big5hkscs_bmp_encmap+9121,5,253},{__big5hkscs_bmp_encmap+9370,0,254},{ +__big5hkscs_bmp_encmap+9625,3,251},{__big5hkscs_bmp_encmap+9874,2,249},{ +__big5hkscs_bmp_encmap+10122,2,254},{__big5hkscs_bmp_encmap+10375,13,255},{ +__big5hkscs_bmp_encmap+10618,5,245},{__big5hkscs_bmp_encmap+10859,16,245},{ +__big5hkscs_bmp_encmap+11089,9,252},{__big5hkscs_bmp_encmap+11333,12,223},{ +__big5hkscs_bmp_encmap+11545,35,253},{__big5hkscs_bmp_encmap+11764,7,226},{ +__big5hkscs_bmp_encmap+11984,44,229},{__big5hkscs_bmp_encmap+12170,24,254},{ +__big5hkscs_bmp_encmap+12401,7,234},{__big5hkscs_bmp_encmap+12629,10,255},{ +__big5hkscs_bmp_encmap+12875,24,241},{__big5hkscs_bmp_encmap+13093,2,254},{ +__big5hkscs_bmp_encmap+13346,0,202},{__big5hkscs_bmp_encmap+13549,0,250},{ +__big5hkscs_bmp_encmap+13800,3,246},{__big5hkscs_bmp_encmap+14044,5,250},{ +__big5hkscs_bmp_encmap+14290,28,255},{__big5hkscs_bmp_encmap+14518,2,254},{ +__big5hkscs_bmp_encmap+14771,2,250},{__big5hkscs_bmp_encmap+15020,4,248},{ +__big5hkscs_bmp_encmap+15265,3,254},{__big5hkscs_bmp_encmap+15517,5,246},{ +__big5hkscs_bmp_encmap+15759,0,226},{__big5hkscs_bmp_encmap+15986,2,251},{ +__big5hkscs_bmp_encmap+16236,2,248},{__big5hkscs_bmp_encmap+16483,5,220},{ +__big5hkscs_bmp_encmap+16699,2,217},{__big5hkscs_bmp_encmap+16915,12,254},{ +__big5hkscs_bmp_encmap+17158,8,245},{__big5hkscs_bmp_encmap+17396,6,244},{ +__big5hkscs_bmp_encmap+17635,6,254},{__big5hkscs_bmp_encmap+17884,11,252},{ +__big5hkscs_bmp_encmap+18126,18,252},{__big5hkscs_bmp_encmap+18361,37,254},{ +__big5hkscs_bmp_encmap+18579,7,223},{__big5hkscs_bmp_encmap+18796,6,250},{ +__big5hkscs_bmp_encmap+19041,2,246},{__big5hkscs_bmp_encmap+19286,3,246},{ +__big5hkscs_bmp_encmap+19530,24,255},{__big5hkscs_bmp_encmap+19762,11,237},{ +__big5hkscs_bmp_encmap+19989,5,248},{__big5hkscs_bmp_encmap+20233,3,252},{ +__big5hkscs_bmp_encmap+20483,2,239},{__big5hkscs_bmp_encmap+20721,112,245},{ +__big5hkscs_bmp_encmap+20855,4,255},{__big5hkscs_bmp_encmap+21107,0,231},{ +__big5hkscs_bmp_encmap+21339,28,234},{__big5hkscs_bmp_encmap+21546,12,226},{ +__big5hkscs_bmp_encmap+21761,81,247},{__big5hkscs_bmp_encmap+21928,3,212},{ +__big5hkscs_bmp_encmap+22138,1,242},{__big5hkscs_bmp_encmap+22380,25,249},{ +__big5hkscs_bmp_encmap+22605,8,196},{__big5hkscs_bmp_encmap+22794,81,254},{ +__big5hkscs_bmp_encmap+22968,8,253},{__big5hkscs_bmp_encmap+23214,3,244},{ +__big5hkscs_bmp_encmap+23456,1,246},{__big5hkscs_bmp_encmap+23702,45,244},{ +__big5hkscs_bmp_encmap+23902,29,244},{__big5hkscs_bmp_encmap+24118,3,245},{ +__big5hkscs_bmp_encmap+24361,20,245},{__big5hkscs_bmp_encmap+24587,14,245},{ +__big5hkscs_bmp_encmap+24819,12,255},{__big5hkscs_bmp_encmap+25063,2,255},{ +__big5hkscs_bmp_encmap+25317,2,124},{__big5hkscs_bmp_encmap+25440,2,252},{ +__big5hkscs_bmp_encmap+25691,10,254},{__big5hkscs_bmp_encmap+25936,2,165},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5hkscs_bmp_encmap+26100,3,75}, +{0,0,0},{__big5hkscs_bmp_encmap+26173,122,239},{0,0,0},{__big5hkscs_bmp_encmap ++26291,229,237},{0,0,0},{__big5hkscs_bmp_encmap+26300,7,7},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{__big5hkscs_bmp_encmap+26301,2,237}, +}; + +static const DBCHAR __big5hkscs_nonbmp_encmap[28325] = { +40049,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37749,N,N,N,N,N, +N,N,37750,N,N,N,N,N,N,N,38216,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,36550,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35781,35834, +N,N,51324,N,N,N,N,N,N,N,N,N,39604,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34894,34891, +51322,34888,N,N,N,34887,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,41206,34885,N,34899,N,N,N,N,N,N,N,N,N,64685,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,35501,N,37490,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64583,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38111,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40913,64459,N,N,N,N,N,N,N,37501,N,N,N,N,N,N,N, +39076,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38119,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37067,37499,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38104,N,N,N,N,64607,N,64084,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39605,N,N,N,N,N,N,N,38618,37497,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64116, +37493,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36347,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35401,N,N,N,37599,39804,64099,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,64096,37485,64098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39606,N,N,N,N,N,N,38763,N,N,N,N,N,N,N,N,N,N,N,N,N, +64874,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64852,N,37491,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38872,N,N,N,N,N, +N,40891,37698,37494,N,N,N,N,N,N,N,N,N,N,64101,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37484,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,64110,N,N,N,N,N,N,40672,N,N,37568,37567,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,37566,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39610,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35507,N,38773,64064,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64118,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,64464,N,N,N,N,N,N,N,N,N,N,N,N,N,64123,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65133,N,N,N,N,N,N,39859,N,N,N,N,N,35276,N,N,N,N,39614,N,N,N,N,N,N, +N,N,N,64066,37564,N,N,N,N,N,N,N,N,N,N,37980,39861,N,N,N,39615,N,N,N,39079, +38820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37117,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64635,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39616,37571,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35498,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39888,38224,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37574,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39078,38214,N,N,N,N,N,N,N,N,N,N,N,N,64867,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64194,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40643,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35250,40038,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36947,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38849,N,N,N,N,N,N,N,N,N,N,N,N,N,39620,N,N,N,N,N,N,N,N,N,N,39621,36591,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,64233,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37474, +35575,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39622,N,N,N,N,N,N,37601,N,N,N, +N,39625,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64198,N,N,N,N,N,N,N,N, +38821,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39627,N,N,N,64114,35422,N,38112,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,37580,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35557,N, +N,N,N,N,65116,39628,N,N,N,N,N,40441,35395,35494,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39629,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39630,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64238,39884,N,N,N,39631,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39633,N,N,N,N,N,N,N, +N,40442,N,N,N,N,N,40316,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39635, +N,N,38822,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39263,N,N,N,64502,40901, +35417,35691,N,N,N,N,N,N,39636,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39637,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,38818,35396,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40778,N, +N,N,N,N,N,N,N,37025,64932,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35428,35570, +35576,40408,N,N,38102,64254,64423,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,39638,N,40781,N,N,64246,N,N,N,N,N,N,N,35415,N,35651,35652, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35510,N,N,N,N,N,35520,N,N,N,N,N,N, +N,N,N,N,40532,N,N,N,N,N,N,N,N,N,N,39639,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39640,39644,N,N,N,N,35530,40616,N,N,37475,39645,35685,35695,35710,N,N,N,N, +36675,N,N,N,N,N,N,37584,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35572,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40382,N,N,N,N,N,39649,N,64734,40445,35686,35696, +35701,35556,35748,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35565,N,N,N,N,N,N,N,N,N, +35421,N,35656,N,N,N,N,40429,N,N,N,N,40512,N,N,N,N,N,N,N,35567,35574,40566,N,N, +N,N,N,N,N,N,N,40675,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,39646,36350,N,N,N,N,64252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40113,40567,35684,35687,38731,N,N,N,N,N,N,N,N,38483,N,N,N,N,N,N,39648, +35658,N,35569,35543,N,N,N,N,N,N,N,N,N,41131,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35509,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35423,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35566,N,N,39647,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35582,N,N,N,N,N,N,35416, +35747,35751,N,N,N,N,N,39651,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37473,N,N,N,N,N,N,N,N,N,N,40407,40573,40615,40619,36930,N,N, +N,N,N,N,N,N,35705,35706,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39654,N,N,N,N,N,N,N,N,N,N,N,N,39653, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35454,N,N,N,N,N,40516,39655,35452,35697,N, +N,39657,N,N,N,N,N,N,N,N,N,N,N,N,39658,N,N,N,N,N,N,N,N,N,N,N,N,N,39659,N,N,N,N, +N,N,35517,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64334,N,N,N,N,N,N,N,N,N, +N,39661,35577,40547,N,N,N,N,N,35657,35534,35694,N,N,N,N,N,35560,N,N,N,39662,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37582,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35418,35707, +35708,39663,N,N,N,N,N,N,N,N,N,N,N,39664,N,35578,N,N,N,N,N,N,N,35137,N,N,35698, +N,N,N,N,N,N,35571,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35752,N,N,N,N,N,N,40622,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40562,64371, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64351,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37050,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37374,40694, +N,N,N,N,N,N,38893,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39667,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,41198,38524,37701,39022,64086,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39669,N,N, +N,64587,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39668,65246,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64695,N,N,N,N,N,N,N,N,N,38897,N,N,N,38855,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40139, +37440,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40168,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37373,38734,N,N,64360,N,N,N,N,N,N,N, +N,N,N,N,N,N,38764,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36034,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38888,N,64362,35700,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,36583,N,N,N,N,N,N,N,N,N,N,N,N,64968,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37441,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38561,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,36595,39671,N,N,N,N,N,N,N,N,N,N,36774,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64214,40135,N,N,N,N,N,N,N,N,64215,N,N,N,N,N,39672,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64417,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36549,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64420,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64450,N,39617,N,N,N,N,N,37370,65243,38827,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37191,N,64433,N,N,N,N,N,N,N,N,N,36842,N,N,N,N,N,N,38098,65121,64206,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37613,37363,37830,N,37722,64251,N,N,37615,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38983,37734,38997,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38630,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40771,40874,38106,37614,64687,64507,N, +36601,37366,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37732,N,N,N,N,38133,40118,64429, +38990,36676,38653,N,N,N,N,N,N,N,N,N,N,N,N,N,39673,N,N,N,39674,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38761,38356,38987,64426,N,N,39036,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37354,N,N,N,N,N,40367,40389,N,37361,36529,38825,64428,64696,40121,N,N,N,N, +N,N,N,64432,64722,37835,N,N,39677,N,N,N,N,N,N,N,N,N,N,N,37364,35756,41045,N,N, +N,N,38260,N,N,N,N,38334,N,N,N,N,N,N,N,N,N,N,N,N,38829,N,N,N,N,N,N,N,N,N,N,N, +36585,N,N,37624,38846,37228,38058,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64611,N, +N,N,40390,N,N,N,N,N,N,N,38837,37560,37359,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65190,38752,37720,38262,36780,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,37356,38836,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37367,N,N,N,N, +38730,64329,38264,37820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,37334,37717,37718,38993,N,N,N,N,N,N,N,N,N,N,36856,64448,37874,N,N, +37072,N,N,N,N,N,N,40004,N,N,N,N,N,37461,N,N,N,N,37731,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37285,N,N,N,N,N,N,N,N,41197,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64875,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39678,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37713,N,N,N,35927,N,N,64120,N,N,N,N,65192,N,N,N,N,N,N,N,N,N,N,N,N,N,37712, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64076,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37623,39744,N,N,N,N,N,N,64462,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39745,N,N,N,N,N,65197,64469,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35778,39548,39746,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39747,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40569,N,N,64473,N,N,N,N,N,N,39748,41127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39923,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35961,N,N,N,37726,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,35275,N,N,N,N,N,N,40787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37847,N,N,N,N,N,N,N,N,N,N,N,N,N,64481,65232,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,64482,N,N,N,N,N,64739,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36980,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64486,N,N,N,39863,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,39749,N,N,N,N,N,N,N,N,N,N,N,N,39751,40784,N,N,N,N,N,39752, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64603,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39081,N,N,40189,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34892,39755,N,N,N,64492,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,35945,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39848,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35541,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64115,64857,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37282,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64493,N,N,N,N,N,N,40105,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35496,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39875, +35553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39758,38352,N,N,N,36959,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,38894,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64590,N,N,N,N,N,N, +39759,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39760,40646,N,N,N,N,N,N,N,N,N,N,N,64592,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64883,N,N,N,N,N,64935,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40354,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64088,64094,N, +N,N,N,N,N,N,41049,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64117,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64446,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,37744,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37745,37751,65263,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37741,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64605,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37048,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,35580,N,64321,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40555,38115,36578,35965,N,36567, +N,N,N,N,N,N,40013,N,N,N,38563,N,N,N,N,N,N,N,N,N,N,39761,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35523,N,N,N,N,N,N,N,N,N,N,N, +38570,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64616,35693,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64871,35561,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64673,37740,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39762,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65136,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64680,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64745,40116,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,35562,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39763,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39765,N,N,N,38571,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64679,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39766,35516,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35531,N,N,N,N, +N,39767,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35277,N,39769,39771,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37797,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39773,N,N,N,40527,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37795,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35451,N,N,N,35650, +38736,36787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35408,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39776,N,N,N,N,35653,N,N,N,35654,N,N,N,N,N,N,N,N,N,N,N,N,40446,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39778,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37755,N,N,N,N,N,37809,N,N,N,N,N,N,N,35424,N,N, +N,N,N,N,N,N,35544,N,N,N,N,39779,N,N,N,N,N,N,N,N,N,N,35433,N,N,N,35399,N,N, +35532,37756,39781,N,N,N,N,N,N,N,N,N,39782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35442,N,N,N,N,N, +N,N,35450,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37807,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35504,N,N,N,N, +N,N,N,39784,N,N,N,N,N,N,N,N,N,N,40611,N,N,64236,35703,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,39783,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35673,64689,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64699,N,N,N,N,N, +N,N,N,N,N,N,39785,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37800,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35552,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36703,39786,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,39787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38892,39788,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65102,N,N,N,N,N,N,64962,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,39789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37223,64716,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37814,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37092,N,N,N,N,37093,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40690,37834,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,35772,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36678,N,N,N,N,37839,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64731,64732,N,N,N,N,N,N,N,N,N,N,N,N,N,37824,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64742,38631,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64728,64729,64934,37838,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,38385,N,N,N,N,N,N,N,N,N,40169,N,64740,38063,64119, +37836,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,36954,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,35924,N,N,N,N,N,N,N,37823,64337,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37817,65239,37815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37849,N,N,N,N,N,N,N,N,N,N,N,N,N,37819, +37850,39075,N,N,N,N,N,N,N,N,N,37073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39790,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64112,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39915,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39791,N,N,N,N,N,N,N,64764,N,N,N,N,N,N,N,N,N,N,N,N,N,35648,41083,N,N,N, +36001,38903,N,N,N,37858,64726,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38233,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37798,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64832,N,N,37727,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38898,40054,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,36600,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36679,N,N,N,N,N,N,N,N,N,N,N,N,39796,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37556, +N,N,N,37357,N,N,38610,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64838,36687,38217,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39797,64092,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64843,N,N,N,38611,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,64856,N,N,N,N,N,37983,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,41205,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,37443,N,N,N,N,N,N,38906,N,N,N,N,N,N,N,N,N,N,N,N, +40409,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38900,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37453,64859,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,39802,N,N,N,N,N,N,N,N,N,40661,N,N,N,N,N,N,N,N,N,N,N,N,64174,N,40137,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37464,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,36552,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,38068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37857,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37855,N,N,N,N,N,64752, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37868,38902,38607,37854,35535,39842,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64873,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37714,N,N,N,N,N,N, +N,N,N,N,N,39074,64878,36004,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64124,37882,36988,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36711,N,40375,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,41193,64078,64929,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40564,40895,40651,39865, +40404,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38841,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36593,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38267,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40658,38739,38564,36798,38105,36952,64889,64891,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36570,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36602,39845,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40665,38868,37051,64956,64966,37448,N,N,N,N,N,N,N,37557,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40385, +37561,37542,36683,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39846,N,N,N,N,N,37558,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,36416,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40664,37982,39007,38094,37450,64880,37991,N,N,N,N,N,N,N,N,N,N,N, +36332,N,N,N,N,N,N,N,N,39896,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37960,64193,40183,64958, +N,N,N,N,N,N,N,N,N,N,N,N,36826,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64985,N,N,64638,N,N,N,N,N,N,N,N,37881,N,N,N,N,64067,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64235, +64195,38867,38393,40008,64984,41176,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64983,64330,39855,37963,64969,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36524,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64946,N,N,N,N,N,37466, +64701,37593,N,N,N,64981,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37597,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37465,38586,N,N,N,N,N,N,N,N,N,N,37467,N,N,N,N,N, +N,N,N,N,39851,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,64986,64990,N,N,N,64979,N,N,N,N,N,N,N,N,N,35910,N,N,N,N,N,N,64982, +64988,64989,N,N,N,N,37118,N,N,65185,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,35757,N,N,40152,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40557,64892,64353,N,N,N,N,N,N,38648,N,N,N,N,N,N,N,N, +38640,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64756,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,65120,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38994,38479,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37230,N,N,N,N,N,N,N,N,N,N,39021,N,N,39012,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37971,65004,64376,N,N,N,N,N,N, +N,N,N,N,N,38330,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39005,N,37625,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39002,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65014,N, +N,N,N,N,N,N,37840,39010,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39853,N,N,N,N,N,N,N,N,N,N,N,38735,39854,N,N,N,N,N,N,N,N,N,N,N, +N,37970,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39856,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37330,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,38890,64363,37297,65011,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37579,N,N,N,N,N,N,N,N,N,39857,N,N,N,N,N,64748,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39019,N,N,N,38737,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +39025,38383,N,N,N,N,N,N,N,40691,N,N,N,N,N,37352,39866,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64332, +37482,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +65016,39009,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37351,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,37869,38724,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37345,N,N,64501,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39017,N,N,N,N,35426,N,N,39867,36008,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40021,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36471,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35506, +40636,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37862,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37794,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37757,40550,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37977,N,N,N,N,N,N,N,N,N,39871,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37976,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40613,39879,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65108,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,36468,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35798,N,N,N,N,N,N, +38070,64884,39104,38053,N,N,N,N,N,N,N,39880,N,N,N,38381,64894,64491,N,N,N,N,N, +N,N,N,N,N,64893,N,N,N,N,N,N,N,N,N,38767,37985,N,40897,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38359,N,N,N,64082,40024,N,N,N,N,N,N,N,N,N,40808,39911,64718, +38632,64073,38817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38221,40696,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65097,37326,38769,N,N,N,N,36047,N, +N,N,64945,N,N,64622,N,N,N,N,N,40178,37816,36931,38745,38103,65126,38013,64623, +N,N,N,N,37446,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64109,N,N,36599,N,64439,N,38012, +37581,38834,N,N,N,N,N,N,N,N,N,65125,38526,38744,39799,37327,N,N,N,N,N,N,N,N,N, +38052,N,N,N,N,N,N,N,N,N,N,40109,N,N,N,N,N,N,N,N,N,35755,N,N,N,38613,64691,N,N, +N,37806,N,38765,N,N,N,N,N,N,37958,38391,N,N,N,N,N,N,N,N,40006,38235,37329, +38132,N,65127,37541,N,N,N,65247,36011,N,39881,N,N,N,N,N,N,N,N,N,N,N,64749, +65018,64712,65122,37372,65131,65017,64711,37198,40120,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38759,N,N,N,38382,N,N,39858,N,N,N,N,37984,N,N,N,38050,39029, +38828,37331,N,N,N,N,N,N,N,N,N,N,N,39035,N,N,N,N,N,N,N,36587,38762,38494,N,N,N, +N,N,N,N,N,N,38891,N,N,N,N,N,40953,38392,65186,36838,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,65150,N,N,N,N,N,N,40356,38760,36588,38077,N,N,N,N,N,N,N,N,N,N,N,N,N, +37979,40182,64167,39897,N,N,N,N,N,N,N,N,N,64093,38486,38754,N,N,N,N,N,N,38074, +41039,37592,N,N,N,39883,N,N,N,N,N,N,38075,N,N,40287,N,N,N,N,N,N,37071,N,N,N,N, +N,N,N,N,N,N,N,N,N,37989,N,N,40780,N,N,N,N,N,N,37080,40638,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64365,38346,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40386,38904,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,36860,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38003,38004,N,N, +N,N,N,N,N,N,N,N,N,N,65207,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35403,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35413, +35689,35548,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35702,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39886,N, +35432,41208,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,39135,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65205,N,N,N,39887,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38651,N,N,39931, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40654,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36581,N,N,N,N,N, +N,N,N,N,40571,39890,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35493,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,65230,35397,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40444,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65231,35749,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35914,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,35564,N,N,64736,38061,65237,38060,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64602,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39894,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35439,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35753,36447,N,N,40395,N,64743,39895,N,N, +N,N,N,N,N,N,N,N,N,37832,N,N,N,N,N,N,N,N,N,37360,36832,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,39899,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37101,N,39900,41196,N,N,N,39162,N,N,N,N,N,N,N,N,N,39904,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37831,37449,38625,39906,N, +N,N,39908,N,N,36833,39909,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38080,N,N,37827,N,N,N,N,N,N,N,N,N,N,37829,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36985,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,38779,N,N,N,N,N,36990,N,N,N,N,65254,65094,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,40376,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37488,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,38312,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36016,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38088,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,39097,37184,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,64702,N,N,N,N,N,N,N,37207,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35762,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64223,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39910,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,38467,36420,40015,65268,N,N,N,N,N,39912,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,37852,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38511,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36426,39917,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,37622,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40377,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36430,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64463,40642,N,N,N,N,N, +N,38117,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39920,38116,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,38225,35771,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39921,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38128,36452,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38122,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36705,N,N,N,39780,36443,N,N,N,N,39922,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40894,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40393,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36460,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36723,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36015,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36725, +36465,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36448,36458,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,35916,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38226,38228,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35540,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40379,38211, +37630,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +38130,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38129,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,41194,40402,41137,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37368,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37986,39844,36525,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40621,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38608,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,65262,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35508,N, +N,N,N,N,N,N,N,N,N,N,N,38743,35447,39927,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,36533,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41069,36534,38742, +38208,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,41203,38078,N,N,N,39930,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64991,40380,N,N,N,N,N,N,N,N,38142,N,N, +N,N,N,N,N,N,35803,41214,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36544, +40775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35806,41211,N,N,N,N,36547,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38473,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,65218,N,N,38220,39933,N,N,N,N,N,N,N,N,N,N,N,N,N,37068,40032, +38219,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39934,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40048,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,40003,N,N,N,40007,36556,N,N,N,36436,N,N,N,N,N,N,N,N,N,N,36580,40009,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35678,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38238,N,N,N,N,N,N,N,N,N,N,N,N, +38236,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40011,35809,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,36569,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40372,N,37471,N,N,N, +40012,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35489,N,N,N,N,N,N,N,N,N,N,N,N,N,36571,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40022,35490,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,38740,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40030,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,40660,38248,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41155,35558,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,41207,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40033,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64589,N,40539,N,N,N,N,N,N,N,N,40553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40035,65223,N, +N,65222,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40039,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40041,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35810,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,37221,N,N,N,N,N,N,N,N,N,N,N,N,40167,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,35412,N,N,N,N,N,N,N,40044,40046,65117,N,N,N,N,N,40051,N,N,N,N,N,N,N,N, +N,N,N,N,N,38250,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38253,36592,36685,N,N,N,N,36598,N, +N,N,N,N,N,N,N,64188,N,36053,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64474,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35660, +64885,39901,64245,N,N,N,N,N,N,N,40052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,38213,N,N,N,N,N,N,N,N,N,N,N,N,38598,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,36714,36686,N,N,N,N,N,40056,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64085,N,N,N,N,N,N,N,N,N,N,N,N,38884,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40001,37468, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38650,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64358,36453,38985,64424,38978,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40058,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,38907,37066,N,N,N,N,40027,N,N,38733,N,N,36563,N,N,N,N,N,N,N,N,N, +N,N,N,N,38241,40779,40885,37842,64938,38976,37190,39015,64090,64425,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38977,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36051,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64765,64939,37309,36684,38601,36693,64430,38255,N,N,N,N,N,N,40061,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41200,N,N,N,N,N,N,N,N,N,N,N,N,N,37999,64940,N,N,N,N,38603,38606,N,N,N,N,41046, +N,40161,N,N,N,N,N,N,N,N,N,N,38596,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36702,36716,36515,64435,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64595,N,N,N,64947,N,N,N,N,36715,N,N,N,N,N,N,N,N,N,N,N,N,38602,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,36729,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40559,41157,64632, +36418,36698,37058,36517,36961,37455,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37747,64949,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65228,N,64445,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36054,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38979,38597,35260,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40099,N,N,N,N,N,N,37451,38986,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36772,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41201, +40699,40146,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36775,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,64604,38981,N,N,36934,36049,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,65274,38240,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40776,37447,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37115,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40100,38257,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40102,N,N,N,N,40103,N,N,N,N,N,40106,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40659,N,N,N,40560,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,40108,36782,38269,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40112,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38838, +N,41149,35551,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,40618,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36797,N,N,N,36799,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37737,39847, +51364,N,N,N,N,65258,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,39905,N,N,N,N,N,N,35649,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,40374,41195,39843,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35745,36808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,35148,39008,N,N,N,N,N,N,N,N,N,N,38087,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,35672,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,38315,38314,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40131,40132,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,37846,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40364,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35814,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35441,36817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,39381,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37108,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35491,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40142,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40148,40149,N,N,N,64456,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40371,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64624,N,N,N,N,N,36823,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39795,N,N,N,N,N,N,N,N,N,N,64091,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,36818,36964,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39094, +38504,N,N,N,N,40150,N,N,N,N,N,N,N,N,N,N,N,N,39101,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36828,65270,36825,N,N,N,N,N,N,N,N,N,N,N,N,N, +38209,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38899,39928,40556,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36850,36846,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40151,N,N,N,N,N,N,N,N,N,N,N,N,40558,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,35392,N,N,N,N,N,N,N,N,N,N,36847,N,N,N,N,N,N,N,N,36852,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36853,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38338,39018,N,38863,40572,36929,N,N,N, +N,N,N,40155,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37953,N,N,N,N,40166,40368, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40170,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40173,N,N,N,N,N,N,N,N,N,N,N,N,40186,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,35682,35406,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,40138,35430,N,N,N,N,N,N,N,N,N,N,40187,40188,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40190,N,N,N,N,N,N,N,N,N,N,N, +N,N,35411,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40165,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40256,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40257,N,N,N,N,N,N,N,N,N,N,N,N,36933,35699,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,38858,N,40258,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35425,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,35758,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35538,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35746,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40434,40259,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40159,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40260,N,N,N,N,N,N,N,N,N,N,36554,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36942,N,N,N,N,N,N,N,36531,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40949,N,N,N,N,N,N,N,N,N,N,N,N,40261,36943,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40263,N,N,N,35274,N,N,N,N,N,N,40117,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64510,36958,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36963,36951,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36966,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39872,N,N,N,N,N,N,N,N,N,N,N,64741,37218,N,N,N,N,N,N,N,N,N,N,36967,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36769,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,36770,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,40264,64211,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36957,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,37049,N,N,N,N,N,N,N,N,N,N,N,N,N,36971,35932,N,N,N, +36969,65111,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65109,36979,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,39919,40176,N,N, +N,N,N,N,N,N,N,N,N,N,40267,N,N,N,N,N,N,N,N,N,N,N,N,N,65241,N,N,N,65242,N,N,N, +37344,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37336,N,N,N,N,N,N,N,N,N,N,38470,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37728,N,64083,40147,N,N, +N,N,N,N,N,N,N,N,N,N,40270,N,N,N,64320,N,N,N,36322,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,37954,N,36950,N,N,39013,N,35948,64074,N,N,40272, +40274,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38319,38746,37705,38727,41204,N,N,N,N,N, +N,38776,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36815,N,N,N,64608,N,N,N,N,N,N,N,N,35918,N, +N,N,64598,N,N,N,N,N,N,N,N,N,N,N,N,N,37340,38497,37612,37725,36574,38654,64847, +38366,N,N,N,N,N,N,N,N,N,N,N,N,N,39088,41024,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38845,38781,38901,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,39852,64218,37570,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38833,N,N,N,N,N,36987,N,N,N,N,37886,38011, +N,38775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64190,64835,37062,37028,37032,38057,N, +37033,N,N,N,N,35941,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38368,36989,N,N,N,N,N,N, +37477,N,N,N,N,N,N,N,N,N,N,N,N,N,64954,37828,N,N,N,N,N,N,N,N,65261,40363,41187, +N,38472,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40275,N,N,N,N,N,35497,N, +39877,N,38493,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38751,38495,38510,64349,N,N, +N,N,N,40369,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,65187,N,N,N,N,N,N,N,N,N,40370,N,N,38318,64675,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41122,N,N,38485,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,40276,N,N,37697,N,38317,37333,N,N,N,N,N,N,N,N,N,N,N,N,38778,65020, +36423,37885,37029,37036,N,N,N,N,N,N,N,N,38316,N,N,N,N,N,N,N,N,N,37038,65189,N, +N,N,N,N,40278,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38883,38370,N,N,N,N,N,37990, +N,N,38471,N,N,N,N,37304,N,N,N,N,40172,N,N,N,N,N,N,N,N,37037,N,38371,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35663,N,N,35555,N,N,N,N,35661,38378,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35662,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36033,35821,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37337,N,N,41124,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38389,38388, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,40883,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65199,N,N,N,N, +N,65138,37498,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65196,N,N,N,N,N,N,N,N,N,N,N,N,N,38387,40280,37746,N,N,37317,N,N,N,N, +N,N,N,38466,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37069,38398, +37209,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40037,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38860,37070,N,N,N,N,N,N,40281,64757,65277,N,N, +40283,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,40284,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37758,N,N,N,N,N,N,N,N,N,N, +N,N,N,39084,N,N,40286,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64976,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64864,N, +N,N,N,N,N,N,N,N,N,N,40143,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37085,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37088,37107,N,N,39089,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37104,N,N,N,N, +N,N,N,N,N,N,N,37821,N,N,N,N,N,N,N,N,38327,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40774,N,N,N,N,N,N,N,N,36427,38488,N,N,N,N,N,N,N,N,N,N,35404,N,40291,40655,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40293,N,N,N,N,N,N,N,40294,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38490,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40292,N,N,N,N,N,N,N,N,N,N,35436,35545,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40295, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35440,35827,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,37200,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,40129,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,40296,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +37799,N,N,N,N,N,N,38516,41199,N,37201,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35940,38518,40297,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64676, +N,N,N,N,N,N,N,N,N,N,N,N,40298,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37454,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40299,N,N,N,N,N,39873, +40300,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +35429,37213,N,N,N,N,N,N,N,N,40301,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37210,35906,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,40128,37226,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +40302,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40614, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40397,N,N,40303,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,35259,40697,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,38580,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37234,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40648,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,35669,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40305,40306,N,N,N,N, +N,N,N,N,N,N,N,N,40652,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37236,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40656,36956,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,36562,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,37288,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,37239,N,N,N,N,N,N,N,N,N,N,N,38591,N,N,N,N,N,38592,N,N,N,N, +36785,N,N,N,N,N,38583,35925,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,37240,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35262,37244,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64375,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,37237,37283,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37238,N,N,N, +N,N,N,N,N,38590,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,37241,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,38582, +37284,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37286,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40309,N,N,N,N,N,N,N,N,N,N,N,36946,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41029,N,37289,N,39082,N,N,N,35935,N,N,35754,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40157,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,40311,35136,40684,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,37802,38008,N,N,N,N,40314,35529,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,35659,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,40940,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,35554,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,40565,39028,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,39624,N,N,N,N,41031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,35779,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64584,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64631,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,40018,36605,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36776,N,N,N,N,N,N,N,N,N,38266,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +36848, +}; + +static const struct unim_index big5hkscs_nonbmp_encmap[256] = { +{__big5hkscs_nonbmp_encmap+0,33,238},{__big5hkscs_nonbmp_encmap+206,12,242},{ +__big5hkscs_nonbmp_encmap+437,4,229},{__big5hkscs_nonbmp_encmap+663,10,252},{ +__big5hkscs_nonbmp_encmap+906,19,254},{__big5hkscs_nonbmp_encmap+1142,71,235}, +{__big5hkscs_nonbmp_encmap+1307,17,118},{__big5hkscs_nonbmp_encmap+1409,14,121 +},{__big5hkscs_nonbmp_encmap+1517,44,213},{__big5hkscs_nonbmp_encmap+1687,22, +231},{__big5hkscs_nonbmp_encmap+1897,17,205},{__big5hkscs_nonbmp_encmap+2086, +13,255},{__big5hkscs_nonbmp_encmap+2329,11,255},{__big5hkscs_nonbmp_encmap+ +2574,21,200},{__big5hkscs_nonbmp_encmap+2754,4,251},{__big5hkscs_nonbmp_encmap ++3002,29,237},{__big5hkscs_nonbmp_encmap+3211,20,246},{ +__big5hkscs_nonbmp_encmap+3438,47,217},{__big5hkscs_nonbmp_encmap+3609,60,254 +},{__big5hkscs_nonbmp_encmap+3804,2,254},{__big5hkscs_nonbmp_encmap+4057,19, +253},{__big5hkscs_nonbmp_encmap+4292,119,150},{__big5hkscs_nonbmp_encmap+4324, +10,254},{__big5hkscs_nonbmp_encmap+4569,13,252},{__big5hkscs_nonbmp_encmap+ +4809,32,250},{__big5hkscs_nonbmp_encmap+5028,3,243},{__big5hkscs_nonbmp_encmap ++5269,45,75},{__big5hkscs_nonbmp_encmap+5300,68,194},{ +__big5hkscs_nonbmp_encmap+5427,42,172},{__big5hkscs_nonbmp_encmap+5558,70,249 +},{__big5hkscs_nonbmp_encmap+5738,28,213},{__big5hkscs_nonbmp_encmap+5924,15, +232},{__big5hkscs_nonbmp_encmap+6142,69,252},{__big5hkscs_nonbmp_encmap+6326, +42,195},{__big5hkscs_nonbmp_encmap+6480,8,124},{__big5hkscs_nonbmp_encmap+6597 +,33,250},{__big5hkscs_nonbmp_encmap+6815,101,237},{__big5hkscs_nonbmp_encmap+ +6952,19,190},{__big5hkscs_nonbmp_encmap+7124,27,246},{ +__big5hkscs_nonbmp_encmap+7344,18,205},{__big5hkscs_nonbmp_encmap+7532,3,247}, +{__big5hkscs_nonbmp_encmap+7777,38,147},{__big5hkscs_nonbmp_encmap+7887,102, +232},{__big5hkscs_nonbmp_encmap+8018,14,206},{__big5hkscs_nonbmp_encmap+8211, +38,201},{__big5hkscs_nonbmp_encmap+8375,7,238},{__big5hkscs_nonbmp_encmap+8607 +,13,239},{__big5hkscs_nonbmp_encmap+8834,116,227},{__big5hkscs_nonbmp_encmap+ +8946,51,218},{__big5hkscs_nonbmp_encmap+9114,3,249},{__big5hkscs_nonbmp_encmap ++9361,15,225},{__big5hkscs_nonbmp_encmap+9572,0,254},{ +__big5hkscs_nonbmp_encmap+9827,0,229},{__big5hkscs_nonbmp_encmap+10057,25,243 +},{__big5hkscs_nonbmp_encmap+10276,0,238},{__big5hkscs_nonbmp_encmap+10515,3, +215},{__big5hkscs_nonbmp_encmap+10728,58,58},{__big5hkscs_nonbmp_encmap+10729, +194,194},{__big5hkscs_nonbmp_encmap+10730,167,250},{__big5hkscs_nonbmp_encmap+ +10814,90,90},{__big5hkscs_nonbmp_encmap+10815,99,255},{ +__big5hkscs_nonbmp_encmap+10972,64,248},{__big5hkscs_nonbmp_encmap+11157,17, +252},{__big5hkscs_nonbmp_encmap+11393,53,240},{__big5hkscs_nonbmp_encmap+11581 +,17,225},{__big5hkscs_nonbmp_encmap+11790,4,252},{__big5hkscs_nonbmp_encmap+ +12039,27,250},{__big5hkscs_nonbmp_encmap+12263,13,248},{ +__big5hkscs_nonbmp_encmap+12499,4,214},{__big5hkscs_nonbmp_encmap+12710,5,200 +},{__big5hkscs_nonbmp_encmap+12906,24,212},{__big5hkscs_nonbmp_encmap+13095,6, +224},{__big5hkscs_nonbmp_encmap+13314,18,255},{__big5hkscs_nonbmp_encmap+13552 +,0,251},{__big5hkscs_nonbmp_encmap+13804,14,233},{__big5hkscs_nonbmp_encmap+ +14024,110,245},{__big5hkscs_nonbmp_encmap+14160,9,217},{ +__big5hkscs_nonbmp_encmap+14369,6,235},{__big5hkscs_nonbmp_encmap+14599,59,167 +},{__big5hkscs_nonbmp_encmap+14708,14,194},{__big5hkscs_nonbmp_encmap+14889, +44,157},{__big5hkscs_nonbmp_encmap+15003,43,231},{__big5hkscs_nonbmp_encmap+ +15192,32,216},{__big5hkscs_nonbmp_encmap+15377,14,19},{ +__big5hkscs_nonbmp_encmap+15383,25,110},{__big5hkscs_nonbmp_encmap+15469,49, +224},{__big5hkscs_nonbmp_encmap+15645,5,246},{__big5hkscs_nonbmp_encmap+15887, +6,225},{__big5hkscs_nonbmp_encmap+16107,87,225},{__big5hkscs_nonbmp_encmap+ +16246,3,204},{__big5hkscs_nonbmp_encmap+16448,149,233},{ +__big5hkscs_nonbmp_encmap+16533,116,232},{__big5hkscs_nonbmp_encmap+16650,1, +254},{__big5hkscs_nonbmp_encmap+16904,32,67},{__big5hkscs_nonbmp_encmap+16940, +14,216},{__big5hkscs_nonbmp_encmap+17143,26,226},{__big5hkscs_nonbmp_encmap+ +17344,41,165},{__big5hkscs_nonbmp_encmap+17469,2,221},{ +__big5hkscs_nonbmp_encmap+17689,88,208},{__big5hkscs_nonbmp_encmap+17810,53, +248},{__big5hkscs_nonbmp_encmap+18006,2,152},{__big5hkscs_nonbmp_encmap+18157, +18,191},{__big5hkscs_nonbmp_encmap+18331,18,252},{__big5hkscs_nonbmp_encmap+ +18566,22,204},{__big5hkscs_nonbmp_encmap+18749,28,199},{ +__big5hkscs_nonbmp_encmap+18921,14,250},{__big5hkscs_nonbmp_encmap+19158,45,82 +},{__big5hkscs_nonbmp_encmap+19196,5,247},{__big5hkscs_nonbmp_encmap+19439,33, +209},{__big5hkscs_nonbmp_encmap+19616,34,240},{__big5hkscs_nonbmp_encmap+19823 +,0,215},{__big5hkscs_nonbmp_encmap+20039,38,223},{__big5hkscs_nonbmp_encmap+ +20225,14,248},{__big5hkscs_nonbmp_encmap+20460,9,205},{ +__big5hkscs_nonbmp_encmap+20657,27,230},{__big5hkscs_nonbmp_encmap+20861,154, +154},{__big5hkscs_nonbmp_encmap+20862,34,134},{__big5hkscs_nonbmp_encmap+20963 +,116,254},{__big5hkscs_nonbmp_encmap+21102,7,148},{__big5hkscs_nonbmp_encmap+ +21244,15,204},{__big5hkscs_nonbmp_encmap+21434,88,200},{ +__big5hkscs_nonbmp_encmap+21547,36,253},{__big5hkscs_nonbmp_encmap+21765,10, +244},{__big5hkscs_nonbmp_encmap+22000,6,244},{__big5hkscs_nonbmp_encmap+22239, +18,18},{__big5hkscs_nonbmp_encmap+22240,47,220},{__big5hkscs_nonbmp_encmap+ +22414,77,79},{__big5hkscs_nonbmp_encmap+22417,249,249},{ +__big5hkscs_nonbmp_encmap+22418,2,244},{__big5hkscs_nonbmp_encmap+22661,46,188 +},{__big5hkscs_nonbmp_encmap+22804,7,226},{__big5hkscs_nonbmp_encmap+23024,6, +138},{__big5hkscs_nonbmp_encmap+23157,18,130},{__big5hkscs_nonbmp_encmap+23270 +,1,244},{__big5hkscs_nonbmp_encmap+23514,0,230},{__big5hkscs_nonbmp_encmap+ +23745,15,19},{__big5hkscs_nonbmp_encmap+23750,4,43},{__big5hkscs_nonbmp_encmap ++23790,51,252},{__big5hkscs_nonbmp_encmap+23992,15,252},{ +__big5hkscs_nonbmp_encmap+24230,12,255},{__big5hkscs_nonbmp_encmap+24474,3,210 +},{__big5hkscs_nonbmp_encmap+24682,52,185},{__big5hkscs_nonbmp_encmap+24816, +15,231},{__big5hkscs_nonbmp_encmap+25033,197,197},{__big5hkscs_nonbmp_encmap+ +25034,136,237},{__big5hkscs_nonbmp_encmap+25136,13,235},{0,0,0},{0,0,0},{ +__big5hkscs_nonbmp_encmap+25359,29,231},{__big5hkscs_nonbmp_encmap+25562,158, +244},{0,0,0},{__big5hkscs_nonbmp_encmap+25649,32,212},{ +__big5hkscs_nonbmp_encmap+25830,16,241},{__big5hkscs_nonbmp_encmap+26056,3,201 +},{__big5hkscs_nonbmp_encmap+26255,40,77},{__big5hkscs_nonbmp_encmap+26293,5, +213},{__big5hkscs_nonbmp_encmap+26502,115,173},{__big5hkscs_nonbmp_encmap+ +26561,62,246},{__big5hkscs_nonbmp_encmap+26746,6,248},{ +__big5hkscs_nonbmp_encmap+26989,35,222},{__big5hkscs_nonbmp_encmap+27177,20, +254},{__big5hkscs_nonbmp_encmap+27412,7,245},{__big5hkscs_nonbmp_encmap+27651, +32,255},{__big5hkscs_nonbmp_encmap+27875,169,169},{__big5hkscs_nonbmp_encmap+ +27876,52,91},{__big5hkscs_nonbmp_encmap+27916,198,203},{ +__big5hkscs_nonbmp_encmap+27922,1,169},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__big5hkscs_nonbmp_encmap+28091,37,205},{__big5hkscs_nonbmp_encmap+28260,148, +212},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; diff --git a/sys/src/cmd/python/Modules/cjkcodecs/mappings_jisx0213_pair.h b/sys/src/cmd/python/Modules/cjkcodecs/mappings_jisx0213_pair.h new file mode 100644 index 000000000..eda8e9e81 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/mappings_jisx0213_pair.h @@ -0,0 +1,59 @@ +#define JISX0213_ENCPAIRS 46 +#ifdef EXTERN_JISX0213_PAIR +static const struct widedbcs_index *jisx0213_pair_decmap; +static const struct pair_encodemap *jisx0213_pair_encmap; +#else +static const ucs4_t __jisx0213_pair_decmap[49] = { +810234010,810365082,810496154,810627226,810758298,816525466,816656538, +816787610,816918682,817049754,817574042,818163866,818426010,838283418, +15074048,U,U,U,39060224,39060225,42730240,42730241,39387904,39387905,39453440, +39453441,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,48825061,48562921, +}; + +static const struct widedbcs_index jisx0213_pair_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_pair_decmap ++0,119,123},{__jisx0213_pair_decmap+5,119,126},{__jisx0213_pair_decmap+13,120, +120},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_pair_decmap+14,68,102},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const struct pair_encodemap jisx0213_pair_encmap[JISX0213_ENCPAIRS] = { +{0x00e60000,0x295c},{0x00e60300,0x2b44},{0x02540000,0x2b38},{0x02540300,0x2b48 +},{0x02540301,0x2b49},{0x02590000,0x2b30},{0x02590300,0x2b4c},{0x02590301, +0x2b4d},{0x025a0000,0x2b43},{0x025a0300,0x2b4e},{0x025a0301,0x2b4f},{ +0x028c0000,0x2b37},{0x028c0300,0x2b4a},{0x028c0301,0x2b4b},{0x02e50000,0x2b60 +},{0x02e502e9,0x2b66},{0x02e90000,0x2b64},{0x02e902e5,0x2b65},{0x304b0000, +0x242b},{0x304b309a,0x2477},{0x304d0000,0x242d},{0x304d309a,0x2478},{ +0x304f0000,0x242f},{0x304f309a,0x2479},{0x30510000,0x2431},{0x3051309a,0x247a +},{0x30530000,0x2433},{0x3053309a,0x247b},{0x30ab0000,0x252b},{0x30ab309a, +0x2577},{0x30ad0000,0x252d},{0x30ad309a,0x2578},{0x30af0000,0x252f},{ +0x30af309a,0x2579},{0x30b10000,0x2531},{0x30b1309a,0x257a},{0x30b30000,0x2533 +},{0x30b3309a,0x257b},{0x30bb0000,0x253b},{0x30bb309a,0x257c},{0x30c40000, +0x2544},{0x30c4309a,0x257d},{0x30c80000,0x2548},{0x30c8309a,0x257e},{ +0x31f70000,0x2675},{0x31f7309a,0x2678}, +}; +#endif diff --git a/sys/src/cmd/python/Modules/cjkcodecs/mappings_jp.h b/sys/src/cmd/python/Modules/cjkcodecs/mappings_jp.h new file mode 100644 index 000000000..c6dae3daa --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/mappings_jp.h @@ -0,0 +1,4765 @@ +static const ucs2_t __jisx0208_decmap[6956] = { +12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,180, +65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,12293,12294, +12295,12540,8213,8208,65295,92,12316,8214,65372,8230,8229,8216,8217,8220,8221, +65288,65289,12308,12309,65339,65341,65371,65373,12296,12297,12298,12299,12300, +12301,12302,12303,12304,12305,65291,8722,177,215,247,65309,8800,65308,65310, +8806,8807,8734,8756,9794,9792,176,8242,8243,8451,65509,65284,162,163,65285, +65283,65286,65290,65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651, +9650,9661,9660,8251,12306,8594,8592,8593,8595,12307,U,U,U,U,U,U,U,U,U,U,U, +8712,8715,8838,8839,8834,8835,8746,8745,U,U,U,U,U,U,U,U,8743,8744,172,8658, +8660,8704,8707,U,U,U,U,U,U,U,U,U,U,U,8736,8869,8978,8706,8711,8801,8786,8810, +8811,8730,8765,8733,8757,8747,8748,U,U,U,U,U,U,U,8491,8240,9839,9837,9834, +8224,8225,182,U,U,U,U,9711,65296,65297,65298,65299,65300,65301,65302,65303, +65304,65305,U,U,U,U,U,U,U,65313,65314,65315,65316,65317,65318,65319,65320, +65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333, +65334,65335,65336,65337,65338,U,U,U,U,U,U,65345,65346,65347,65348,65349,65350, +65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363, +65364,65365,65366,65367,65368,65369,65370,12353,12354,12355,12356,12357,12358, +12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371, +12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384, +12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397, +12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410, +12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423, +12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,12449, +12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462, +12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475, +12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488, +12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501, +12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514, +12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527, +12528,12529,12530,12531,12532,12533,12534,913,914,915,916,917,918,919,920,921, +922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,U,U,U,U,U,U,U,U, +945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964, +965,966,967,968,969,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049, +1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064, +1065,1066,1067,1068,1069,1070,1071,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,1072,1073, +1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087, +1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102, +1103,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487, +9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520, +9509,9528,9538,20124,21782,23043,38463,21696,24859,25384,23030,36898,33909, +33564,31312,24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201, +23451,22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353, +26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,22996, +23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,32173,32239, +32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,32946,37057,30959, +19968,22769,28322,36920,31282,33576,33419,39983,20801,21360,21693,21729,22240, +23035,24341,39154,28139,32996,34093,38498,38512,38560,38907,21515,21491,23431, +28879,32701,36802,38632,21359,40284,31418,19985,30867,33276,28198,22040,21764, +27421,34074,39995,23013,21417,28006,29916,38287,22082,20113,36939,38642,33615, +39180,21473,21942,23344,24433,26144,26355,26628,27704,27891,27945,29787,30408, +31310,38964,33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234, +38322,27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839, +28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,40219, +22633,26044,27738,29989,20985,22830,22885,24448,24540,25276,26106,27178,27431, +27572,29579,32705,35158,40236,40206,40644,23713,27798,33659,20740,23627,25014, +33222,26742,29281,20057,20474,21368,24681,28201,31311,38899,19979,21270,20206, +20309,20285,20385,20339,21152,21487,22025,22799,23233,23478,23521,31185,26247, +26524,26550,27468,27827,28779,29634,31117,31166,31292,31623,33457,33499,33540, +33655,33775,33747,34662,35506,22057,36008,36838,36942,38686,34442,20420,23784, +25105,29273,30011,33253,33469,34558,36032,38597,39187,39381,20171,20250,35299, +22238,22602,22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,39745, +26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,35997,20977, +21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,34903,35442,37799, +39608,28012,39336,34521,22435,26623,34510,37390,21123,22151,21508,24275,25313, +25785,26684,26680,27579,29554,30906,31339,35226,35282,36203,36611,37101,38307, +38548,38761,23398,23731,27005,38989,38990,25499,31520,27179,27263,26806,39949, +28511,21106,21917,24688,25324,27963,28167,28369,33883,35088,36676,19988,39993, +21494,26907,27194,38788,26666,20828,31427,33970,37340,37772,22107,40232,26658, +33541,33841,31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223, +24059,21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022, +25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,29976, +30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,35251,35532, +36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,20024,21547,23736, +24012,29609,30284,30524,23721,32747,36107,38593,38929,38996,39000,20225,20238, +21361,21916,22120,22522,22855,23305,23492,23696,24076,24190,24524,25582,26426, +26071,26082,26399,26827,26820,27231,24112,27589,27671,27773,30079,31048,23395, +31232,32000,24509,35215,35352,36020,36215,36556,36637,39138,39438,39740,20096, +20605,20736,22931,23452,25135,25216,25836,27450,29344,30097,31047,32681,34811, +35516,35696,25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485, +40653,21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470, +24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,32026, +31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,34394,35377, +36317,37624,28417,31142,39770,20136,20139,20140,20379,20384,20689,20807,31478, +20849,20982,21332,21281,21375,21483,21932,22659,23777,24375,24394,24623,24656, +24685,25375,25945,27211,27841,29378,29421,30703,33016,33029,33288,34126,37111, +37857,38911,39255,39514,20208,20957,23597,26241,26989,23616,26354,26997,29577, +26704,31873,20677,21220,22343,24062,37670,26020,27427,27453,29748,31105,31165, +31563,32202,33465,33740,34943,35167,35641,36817,37329,21535,37504,20061,20534, +21477,21306,29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398, +21936,31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,25496,31391, +27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,37740,21234,21531, +34219,35347,32676,36557,37089,21350,34952,31041,20418,20670,21009,20804,21843, +22317,29674,22411,22865,24418,24452,24693,24950,24935,25001,25522,25658,25964, +26223,26690,28179,30054,31293,31995,32076,32153,32331,32619,33550,33610,34509, +35336,35427,35686,36605,38938,40335,33464,36814,39912,21127,25119,25731,28608, +38553,26689,20625,27424,27770,28500,31348,32080,34880,35363,26376,20214,20537, +20518,20581,20860,21048,21091,21927,22287,22533,23244,24314,25010,25080,25331, +25458,26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609, +36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,24358, +28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,21476,21628, +22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,29392,31946,34996, +32929,32993,33776,34382,35463,36328,37431,38599,39015,40723,20116,20114,20237, +21320,21577,21566,23087,24460,24481,24735,26791,27278,29786,30849,35486,35492, +35703,37264,20062,39881,20132,20348,20399,20505,20502,20809,20844,21151,21177, +21246,21402,21475,21521,21518,21897,22353,22434,22909,23380,23389,23439,24037, +24039,24055,24184,24195,24218,24247,24344,24658,24908,25239,25304,25511,25915, +26114,26179,26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002, +30343,30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108, +33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,37628, +38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,25335,28640, +35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,40658,29508,28425, +33136,29969,24573,24794,39592,29403,36796,27492,38915,20170,22256,22372,22718, +23130,24680,25031,26127,26118,26681,26801,28151,30165,32058,33390,39746,20123, +20304,21449,21766,23919,24038,24046,26619,27801,29811,30722,35408,37782,35039, +22352,24231,25387,20661,20652,20877,26368,21705,22622,22971,23472,24425,25165, +25505,26685,27507,28168,28797,37319,29312,30741,30758,31085,25998,32048,33756, +35009,36617,38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018, +32948,21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613, +31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,23519,25334,25774, +25830,26413,27578,34217,38609,30352,39894,25420,37638,39851,30399,26194,19977, +20632,21442,23665,24808,25746,25955,26719,29158,29642,29987,31639,32386,34453, +35715,36059,37240,39184,26028,26283,27531,20181,20180,20282,20351,21050,21496, +21490,21987,22235,22763,22987,22985,23039,23376,23629,24066,24107,24535,24605, +25351,25903,23388,26031,26045,26088,26525,27490,27515,27663,29509,31049,31169, +31992,32025,32043,32930,33026,33267,35222,35422,35433,35430,35468,35566,36039, +36060,38604,39164,27503,20107,20284,20365,20816,23383,23546,24904,25345,26178, +27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,36766, +27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,22519,22833, +23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,20594,26612,33437, +23649,34122,32286,33294,20889,23556,25448,36198,26012,29038,31038,32023,32773, +35613,36554,36974,34503,37034,20511,21242,23610,26451,28796,29237,37196,37320, +37675,33509,23490,24369,24825,20027,21462,23432,25163,26417,27530,29417,29664, +31278,33131,36259,37202,39318,20754,21463,21610,23551,25480,27193,32172,38656, +22234,21454,21608,23447,23601,24030,20462,24833,25342,27954,31168,31179,32066, +32333,32722,33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228, +38598,37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294, +37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,34899, +36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,26991,27529, +28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,21021,25152,26257, +26329,28186,24246,32210,32626,26360,34223,34295,35576,21161,21465,22899,24207, +24464,24661,37604,38500,20663,20767,21213,21280,21319,21484,21736,21830,21809, +22039,22888,22974,23100,23477,23558,23567,23569,23578,24196,24202,24288,24432, +25215,25220,25307,25484,25463,26119,26124,26157,26230,26494,26786,27167,27189, +27836,28040,28169,28248,28988,28966,29031,30151,30465,30813,30977,31077,31216, +31456,31505,31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412, +35443,35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055, +20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,29366, +30067,31331,33976,35698,37304,37664,22065,22516,39166,25325,26893,27542,29165, +32340,32887,33394,35302,39135,34645,36785,23611,20280,20449,20405,21767,23072, +23517,23529,24515,24910,25391,26032,26187,26862,27035,28024,28145,30003,30137, +30495,31070,31206,32051,33251,33455,34218,35242,35386,36523,36763,36914,37341, +38663,20154,20161,20995,22645,22764,23563,29978,23613,33102,35338,36805,38499, +38765,31525,35535,38920,37218,22259,21416,36887,21561,22402,24101,25512,27700, +28810,30561,31883,32736,34928,36930,37204,37648,37656,38543,29790,39620,23815, +23913,25968,26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,28548, +25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,24615,25104, +25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,30427,31934,32854, +22768,35069,35199,35488,35475,35531,36893,37266,38738,38745,25993,31246,33030, +38587,24109,24796,25114,26021,26132,26512,30707,31309,31821,32318,33034,36012, +36196,36321,36447,30889,20999,25305,25509,25666,25240,35373,31363,31680,35500, +38634,32118,33292,34633,20185,20808,21315,21344,23459,23554,23574,24029,25126, +25159,25776,26643,26676,27849,27973,27927,26579,28508,29006,29053,26059,31359, +31661,32218,32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983, +37549,37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950, +22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,31199, +31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,21474,20489, +21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,25475,25407,25531, +25805,26089,26361,24035,27085,27133,28437,29157,20105,30185,30456,31379,31967, +32207,32156,32865,33609,33624,33900,33980,34299,35013,36208,36865,36973,37783, +38684,39442,20687,22679,24974,33235,34101,36104,36896,20419,20596,21063,21363, +24687,25417,26463,28204,36275,36895,20439,23646,36042,26063,32154,21330,34966, +20854,25539,23384,23403,23562,25613,26449,36956,20182,22810,22826,27760,35409, +21822,22549,22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534, +23550,32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151, +33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,37261, +38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,28655,29730, +35351,37944,28609,35582,33592,20967,34552,21482,21481,20294,36948,36784,22890, +33073,24061,31466,36799,26842,35895,29432,40008,27197,35504,20025,21336,22022, +22374,25285,25506,26086,27470,28129,28251,28845,30701,31471,31658,32187,32829, +32966,34507,35477,37723,22243,22727,24382,26029,26262,27264,27573,30007,35527, +20516,30693,22320,24347,24677,26234,27744,30196,31258,32622,33268,34584,36933, +39347,31689,30044,31481,31569,33988,36880,31209,31378,33590,23265,30528,20013, +20210,23449,24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376, +27159,28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,24086,24115, +24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,29266,30010,30522, +32884,33081,33144,34678,35519,35548,36229,36339,37530,38263,38914,40165,21189, +25431,30452,26389,27784,29645,36035,37806,38515,27941,22684,26894,27084,36861, +37786,30171,36890,22618,26626,25524,27131,20291,28460,26584,36795,34086,32180, +37716,26943,28528,22378,22775,23340,32044,29226,21514,37347,40372,20141,20302, +20572,20597,21059,35998,21576,22564,23450,24093,24213,24237,24311,24351,24716, +25269,25402,25552,26799,27712,30855,31118,31243,32224,33351,35330,35558,36420, +36883,37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969, +37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,24215, +28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,38651,20814, +21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,33759,36077,36884, +37117,37709,30757,30778,21162,24230,22303,22900,24594,20498,20826,20908,20941, +20992,21776,22612,22616,22871,23445,23798,23947,24764,25237,25645,26481,26691, +26812,26847,30423,28120,28271,28059,28783,29128,24403,30168,31095,31561,31572, +31570,31958,32113,21040,33891,34153,34276,35342,35588,35910,36367,36867,36879, +37913,38518,38957,39472,38360,20685,21205,21516,22530,23566,24999,25758,27934, +30643,31461,33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305, +30563,31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182, +33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,21585, +26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,37707,26978, +39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,24336,36841,21250, +36049,32905,34425,24319,26085,20083,20837,22914,23615,38894,20219,22922,24525, +35469,28641,31152,31074,23527,33905,29483,29105,24180,24565,25467,25754,29123, +31896,20035,24316,20043,22492,22178,24745,28611,32013,33021,33075,33215,36786, +35223,34468,24052,25226,25773,35207,26487,27874,27966,29750,30772,23110,32629, +33453,39340,20467,24259,25309,25490,25943,26479,30403,29260,32972,32954,36649, +37197,20493,22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889, +34687,31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893, +33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,20989,31665,30834, +31672,32903,31560,27368,24161,32908,30033,30048,20843,37474,28300,30330,37271, +39658,20240,32624,25244,31567,38309,40169,22138,22617,34532,38588,20276,21028, +21322,21453,21467,24070,25644,26001,26495,27710,27726,29256,29359,29677,30036, +32321,33324,34281,36009,31684,37318,29033,38930,39151,25405,26217,30058,30436, +30928,34115,34542,21290,21329,21542,22915,24199,24444,24754,25161,25209,25259, +26000,27604,27852,30130,30382,30865,31192,32203,32631,32933,34987,35513,36027, +36991,38750,39131,27147,31800,20633,23614,24494,26503,27608,29749,30473,32654, +40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,30050, +31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,27703,28418, +29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,37672,37618,33948, +34541,39981,21697,24428,25996,27996,28693,36007,36051,38971,25935,29942,19981, +20184,22496,22827,23142,23500,20904,24067,24220,24598,25206,25975,26023,26222, +28014,29238,31526,33104,33178,33433,35676,36000,36070,36212,38428,38468,20398, +25771,27494,33310,33889,34154,37096,23553,26963,39080,33914,34135,20239,21103, +24489,24133,26381,31119,33145,35079,35206,28149,24343,25173,27832,20175,29289, +39826,20998,21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640, +25991,32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281, +38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,22793, +29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,20445,33303, +37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,24917,25098,26286, +27597,31807,33769,20515,20472,21253,21574,22577,22857,23453,23792,23791,23849, +24214,25265,25447,25918,26041,26379,27861,27873,28921,30770,32299,32990,33459, +33804,34028,34562,35090,35370,35914,37030,37586,39165,40179,40300,20047,20129, +20621,21078,22346,22952,24125,24536,24537,25151,26292,26395,26576,26834,20882, +32033,32938,33192,35584,35980,36031,37502,38450,21536,38956,21271,20693,21340, +22696,25778,26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868, +26412,32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598, +21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,25273, +26411,27819,36804,20397,32365,40639,19975,24930,28288,28459,34067,21619,26410, +39749,24051,31637,23724,23494,34588,28234,34001,31252,33032,22937,31885,27665, +30496,21209,22818,28961,29279,30683,38695,40289,26891,23167,23064,20901,21517, +21629,26126,30431,36855,37528,40180,23018,29277,28357,20813,26825,32191,32236, +38754,40634,25720,27169,33538,22916,23391,27611,29467,30450,32178,32791,33945, +20786,26408,40665,30446,26466,21247,39173,23588,25147,31870,36016,21839,24758, +32011,38272,21249,20063,20918,22812,29242,32822,37326,24357,30690,21380,24441, +32004,34220,35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,35565, +36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,26377,26586, +28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,37109,38596,34701, +22805,20104,20313,19982,35465,36671,38928,20653,24188,22934,23481,24248,25562, +25594,25793,26332,26954,27096,27915,28342,29076,29992,31407,32650,32768,33865, +33993,35201,35617,36362,36965,38525,39178,24958,25233,27442,27779,28020,32716, +32764,28096,32645,34746,35064,26469,33713,38972,38647,27931,32097,33853,37226, +20081,21365,23888,27396,28651,34253,34349,35239,21033,21519,23653,26446,26792, +29702,29827,30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504, +30053,21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942, +26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,30274, +30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,20523,21400, +26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,22593,28057,32047, +39006,20196,20278,20363,20919,21169,23994,24604,29618,31036,33491,37428,38583, +38646,38666,40599,40802,26278,27508,21015,21155,28872,35010,24265,24651,24976, +28451,29001,31806,32244,32879,34030,36899,37676,21570,39791,27347,28809,36034, +36335,38706,21172,23105,24266,24324,26391,27004,27028,28010,28431,29282,29436, +31725,32769,32894,34635,37070,20845,40595,31108,32907,37682,35542,20525,21644, +35441,27498,36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152, +26880,28286,30871,33109,24332,19984,19989,20010,20017,20022,20028,20031,20034, +20054,20056,20098,20101,35947,20106,33298,24333,20110,20126,20127,20128,20130, +20144,20147,20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215, +20233,20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329, +20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,20442, +20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,20513,20521, +20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,20552,20570,20566, +20588,20600,20608,20634,20613,20660,20658,20681,20682,20659,20674,20694,20702, +20709,20717,20707,20718,20729,20725,20745,20737,20738,20758,20757,20756,20762, +20769,20794,20791,20796,20795,20799,20800,20818,20812,20820,20834,31480,20841, +20842,20846,20864,20866,22232,20876,20873,20879,20881,20883,20885,20886,20900, +20902,20898,20905,20906,20907,20915,20913,20914,20912,20917,20925,20933,20937, +20955,20960,34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031, +21034,21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097, +21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,36775,21164,21165, +21180,21173,21185,21197,21207,21214,21219,21222,39149,21216,21235,21237,21240, +21241,21254,21256,30008,21261,21264,21263,21269,21274,21283,21295,21297,21299, +21304,21312,21318,21317,19991,21321,21325,20950,21342,21353,21358,22808,21371, +21367,21378,21398,21408,21414,21413,21422,21424,21430,21443,31762,38617,21471, +26364,29166,21486,21480,21485,21498,21505,21565,21568,21548,21549,21564,21550, +21558,21545,21533,21582,21647,21621,21646,21599,21617,21623,21616,21650,21627, +21632,21622,21636,21648,21638,21703,21666,21688,21669,21676,21700,21704,21672, +21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,21741, +21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,21816,21811, +21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,21934,21884,21891, +21929,21895,21928,21978,21957,21983,21956,21980,21988,21972,22036,22007,22038, +22014,22013,22043,22009,22094,22096,29151,22068,22070,22066,22072,22123,22116, +22063,22124,22122,22150,22144,22154,22176,22164,22159,22181,22190,22198,22196, +22210,22204,22209,22211,22208,22216,22222,22225,22227,22231,22254,22265,22272, +22271,22276,22281,22280,22283,22285,22291,22296,22294,21959,22300,22310,22327, +22328,22350,22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432, +22451,22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539, +22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,22713, +22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,22745,22744, +22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,22786,22794,22800, +22811,26790,22821,22828,22829,22834,22840,22846,31442,22869,22864,22862,22874, +22872,22882,22880,22887,22892,22889,22904,22913,22941,20318,20395,22947,22962, +22982,23016,23004,22925,23001,23002,23077,23071,23057,23068,23049,23066,23104, +23148,23113,23093,23094,23138,23146,23194,23228,23230,23243,23234,23229,23267, +23255,23270,23273,23254,23290,23291,23308,23307,23318,23346,23248,23338,23350, +23358,23363,23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413, +23416,25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524, +23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,23571, +23584,23586,23592,23608,23609,23617,23622,23630,23635,23632,23631,23409,23660, +23662,20066,23670,23673,23692,23697,23700,22939,23723,23739,23734,23740,23735, +23749,23742,23751,23769,23785,23805,23802,23789,23948,23786,23819,23829,23831, +23900,23839,23835,23825,23828,23842,23834,23833,23832,23884,23890,23886,23883, +23916,23923,23926,23943,23940,23938,23970,23965,23980,23982,23997,23952,23991, +23996,24009,24013,24019,24018,24022,24027,24043,24050,24053,24075,24090,24089, +24081,24091,24118,24119,24132,24131,24128,24142,24151,24148,24159,24162,24164, +24135,24181,24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,24278, +24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,24304,24308, +24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,24365,24376,24385, +24392,24396,24398,24367,24401,24406,24407,24409,24417,24429,24435,24439,24451, +24450,24447,24458,24456,24465,24455,24478,24473,24472,24480,24488,24493,24508, +24534,24571,24548,24568,24561,24541,24755,24575,24609,24672,24601,24592,24617, +24590,24625,24603,24597,24619,24614,24591,24634,24666,24641,24682,24695,24671, +24650,24646,24653,24675,24643,24676,24642,24684,24683,24665,24705,24717,24807, +24707,24730,24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787, +24756,24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820, +24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,24895, +24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,24939,24948, +24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,25004,24980,24986, +24970,24977,25003,25006,25036,25034,25033,25079,25032,25027,25030,25018,25035, +32633,25037,25062,25059,25078,25082,25076,25087,25085,25084,25086,25088,25096, +25097,25101,25100,25108,25115,25118,25121,25130,25134,25136,25138,25139,25153, +25166,25182,25187,25179,25184,25192,25212,25218,25225,25214,25234,25235,25238, +25300,25219,25236,25303,25297,25275,25295,25343,25286,25812,25288,25308,25292, +25290,25282,25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333, +25424,25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481, +25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,25540, +25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,25711,25718, +25678,25898,25749,25747,25765,25769,25736,25788,25818,25810,25797,25799,25787, +25816,25794,25841,25831,33289,25824,25825,25260,25827,25839,25900,25846,25844, +25842,25850,25856,25853,25880,25884,25861,25892,25891,25899,25908,25909,25911, +25910,25912,30027,25928,25942,25941,25933,25944,25950,25949,25970,25976,25986, +25987,35722,26011,26015,26027,26039,26051,26054,26049,26052,26060,26066,26075, +26073,26080,26081,26097,26482,26122,26115,26107,26483,26165,26166,26164,26140, +26191,26180,26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243, +26248,26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,26308,26296, +26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,26390,26398,26406, +26407,38712,26414,26431,26422,26433,26424,26423,26438,26462,26464,26457,26467, +26468,26505,26480,26537,26492,26474,26508,26507,26534,26529,26501,26551,26607, +26548,26604,26547,26601,26552,26596,26590,26589,26594,26606,26553,26574,26566, +26599,27292,26654,26694,26665,26688,26701,26674,26702,26803,26667,26713,26723, +26743,26751,26783,26767,26797,26772,26781,26779,26755,27310,26809,26740,26805, +26784,26810,26895,26765,26750,26881,26826,26888,26840,26914,26918,26849,26892, +26829,26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863, +26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,27006, +26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,27058,27054, +27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,27075,27047,27182, +27025,27040,27036,27029,27060,27102,27112,27138,27163,27135,27402,27129,27122, +27111,27141,27057,27166,27117,27156,27115,27146,27154,27329,27171,27155,27204, +27148,27250,27190,27256,27207,27234,27225,27238,27208,27192,27170,27280,27277, +27296,27268,27298,27299,27287,34327,27323,27331,27330,27320,27315,27308,27358, +27345,27359,27306,27354,27370,27387,27397,34326,27386,27410,27414,39729,27423, +27448,27447,30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487, +27489,27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562, +27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,27627, +27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,27746,27754, +27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,27844,27889,27859, +27837,27863,27845,27869,27822,27825,27838,27834,27867,27887,27865,27882,27935, +34893,27958,27947,27965,27960,27929,27957,27955,27922,27916,28003,28051,28004, +27994,28025,27993,28046,28053,28644,28037,28153,28181,28170,28085,28103,28134, +28088,28102,28140,28126,28108,28136,28114,28101,28154,28121,28132,28117,28138, +28142,28205,28270,28206,28185,28274,28255,28222,28195,28267,28203,28278,28237, +28191,28227,28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343, +28371,28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433, +28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,28478,28435,28407, +28550,28538,28536,28545,28544,28527,28507,28659,28525,28546,28540,28504,28558, +28561,28610,28518,28595,28579,28577,28580,28601,28614,28586,28639,28629,28652, +28628,28632,28657,28654,28635,28681,28683,28666,28689,28673,28687,28670,28699, +28698,28532,28701,28696,28703,28720,28734,28722,28753,28771,28825,28818,28847, +28913,28844,28856,28851,28846,28895,28875,28893,28889,28937,28925,28956,28953, +29029,29013,29064,29030,29026,29004,29014,29036,29071,29179,29060,29077,29096, +29100,29143,29113,29118,29138,29129,29140,29134,29152,29164,29159,29173,29180, +29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,29247, +29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,29346,29351, +29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,29433,29431,20495, +29463,29450,29468,29462,29469,29492,29487,29481,29477,29502,29518,29519,40664, +29527,29546,29544,29552,29560,29557,29563,29562,29640,29619,29646,29627,29632, +29669,29678,29662,29858,29701,29807,29733,29688,29746,29754,29781,29759,29791, +29785,29761,29788,29801,29808,29795,29802,29814,29822,29835,29854,29863,29898, +29903,29908,29681,29920,29923,29927,29929,29934,29938,29936,29937,29944,29943, +29956,29955,29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020, +30029,30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070, +30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,30131, +30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,30174,30206, +30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,30239,30247,30240, +30241,30242,30244,30260,30256,30267,30279,30280,30278,30300,30296,30305,30306, +30312,30313,30314,30311,30316,30320,30322,30326,30328,30332,30336,30339,30344, +30347,30350,30358,30355,30361,30362,30384,30388,30392,30393,30394,30402,30413, +30422,30418,30430,30433,30437,30439,30442,34351,30459,30472,30471,30468,30505, +30500,30494,30501,30502,30491,30519,30520,30535,30554,30568,30571,30555,30565, +30591,30590,30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652, +30653,30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014, +30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,30895, +30929,30918,30923,30932,30910,30908,30917,30922,30956,30951,30938,30973,30964, +30983,30994,30993,31001,31020,31019,31040,31072,31063,31071,31066,31061,31059, +31098,31103,31114,31133,31143,40779,31146,31150,31155,31161,31162,31177,31189, +31207,31212,31201,31203,31240,31245,31256,31257,31264,31263,31104,31281,31291, +31294,31287,31299,31319,31305,31329,31330,31337,40861,31344,31353,31357,31368, +31383,31381,31384,31382,31401,31432,31408,31414,31429,31428,31423,36995,31431, +31434,31437,31439,31445,31443,31449,31450,31453,31457,31458,31462,31469,31472, +31490,31503,31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,31610, +31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,31596,31598, +31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,31641,31691,31681, +31692,31695,31668,31686,31709,31721,31761,31764,31718,31717,31840,31744,31751, +31763,31731,31735,31767,31757,31734,31779,31783,31786,31775,31799,31787,31805, +31820,31811,31828,31823,31808,31824,31832,31839,31844,31830,31845,31852,31861, +31875,31888,31908,31917,31906,31915,31905,31912,31923,31922,31921,31918,31929, +31933,31936,31941,31938,31960,31954,31964,31970,39739,31983,31986,31988,31990, +31994,32006,32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070, +32115,32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125, +32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,32184, +32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,32291,32289, +32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,32313,32323,32311, +32306,32314,32359,32349,32342,32350,32345,32346,32377,32362,32361,32380,32379, +32387,32213,32381,36782,32383,32392,32393,32396,32402,32400,32403,32404,32406, +32398,32411,32412,32568,32570,32581,32588,32589,32590,32592,32593,32597,32596, +32600,32607,32608,32616,32617,32615,32632,32642,32646,32643,32648,32647,32652, +32660,32670,32669,32666,32675,32687,32690,32697,32686,32694,32696,35697,32709, +32710,32714,32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779, +32786,32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858, +32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,32901, +32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,32986,32982, +33033,33007,33009,33051,33065,33059,33071,33099,38539,33094,33086,33107,33105, +33020,33137,33134,33125,33126,33140,33155,33160,33162,33152,33154,33184,33173, +33188,33187,33119,33171,33193,33200,33205,33214,33208,33213,33216,33218,33210, +33225,33229,33233,33241,33240,33224,33242,33247,33248,33255,33274,33275,33278, +33281,33282,33285,33287,33290,33293,33296,33302,33321,33323,33336,33331,33344, +33369,33368,33373,33370,33375,33380,33378,33384,33386,33387,33326,33393,33399, +33400,33406,33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524, +33523,33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,33589,33588, +33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,33560,33669,33690, +33706,33695,33698,33686,33571,33678,33671,33674,33660,33717,33651,33653,33696, +33673,33704,33780,33811,33771,33742,33789,33795,33752,33803,33729,33783,33799, +33760,33778,33805,33826,33824,33725,33848,34054,33787,33901,33834,33852,34138, +33924,33911,33899,33965,33902,33922,33897,33862,33836,33903,33913,33845,33994, +33890,33977,33983,33951,34009,33997,33979,34010,34000,33985,33990,34006,33953, +34081,34047,34036,34071,34072,34092,34079,34069,34068,34044,34112,34147,34136, +34120,34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196, +34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,34261, +34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,34330,34352, +34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,34474,34443,34444, +34486,34479,34500,34502,34480,34505,34851,34475,34516,34526,34537,34540,34527, +34523,34543,34578,34566,34568,34560,34563,34555,34577,34569,34573,34553,34570, +34612,34623,34615,34619,34597,34601,34586,34656,34655,34680,34636,34638,34676, +34647,34664,34670,34649,34643,34659,34666,34821,34722,34719,34690,34735,34763, +34749,34752,34768,38614,34731,34756,34739,34759,34758,34747,34799,34802,34784, +34831,34829,34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865, +34870,34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942, +34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,34980, +34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,35068,35060, +35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,35115,35137,35140, +35131,35126,35128,35148,35101,35168,35166,35174,35172,35181,35178,35183,35188, +35191,35198,35203,35208,35210,35219,35224,35233,35241,35238,35244,35247,35250, +35258,35261,35263,35264,35290,35292,35293,35303,35316,35320,35331,35350,35344, +35340,35355,35357,35365,35382,35393,35419,35410,35398,35400,35452,35437,35436, +35426,35461,35458,35460,35496,35489,35473,35493,35494,35482,35491,35524,35533, +35522,35546,35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547, +35596,35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646, +35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,35679,35692,35695, +35700,35709,35712,35724,35726,35730,35731,35734,35737,35738,35898,35905,35903, +35912,35916,35918,35920,35925,35938,35948,35960,35962,35970,35977,35973,35978, +35981,35982,35988,35964,35992,25117,36013,36010,36029,36018,36019,36014,36022, +36040,36033,36068,36067,36058,36093,36090,36091,36100,36101,36106,36103,36111, +36109,36112,40782,36115,36045,36116,36118,36199,36205,36209,36211,36225,36249, +36290,36286,36282,36303,36314,36310,36300,36315,36299,36330,36331,36319,36323, +36348,36360,36361,36351,36381,36382,36368,36383,36418,36405,36400,36404,36426, +36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,36466, +36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,36522,36513, +36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,36604,36603,36587, +36606,36618,36613,36629,36626,36633,36627,36636,36639,36635,36620,36646,36659, +36667,36665,36677,36674,36670,36684,36681,36678,36686,36695,36700,36706,36707, +36708,36764,36767,36771,36781,36783,36791,36826,36837,36834,36842,36847,36999, +36852,36869,36857,36858,36881,36885,36897,36877,36894,36886,36875,36903,36918, +36917,36921,36856,36943,36944,36945,36946,36878,36937,36926,36950,36952,36958, +36968,36975,36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032, +37039,37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194, +37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,37295, +37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,37345,37339, +37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,37463,37445,37449, +37476,37448,37525,37439,37451,37456,37532,37526,37523,37531,37466,37583,37561, +37559,37609,37647,37626,37700,37678,37657,37666,37658,37667,37690,37685,37691, +37724,37728,37756,37742,37718,37808,37804,37805,37780,37817,37846,37847,37864, +37861,37848,37827,37853,37840,37832,37860,37914,37908,37907,37891,37895,37904, +37942,37931,37941,37921,37946,37953,37970,37956,37979,37984,37986,37982,37994, +37417,38000,38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282, +38292,38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346, +28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,38440, +38446,38447,38466,38476,38479,38475,38519,38492,38494,38493,38495,38502,38514, +38508,38541,38552,38549,38551,38570,38567,38577,38578,38576,38580,38582,38584, +38585,38606,38603,38601,38605,35149,38620,38669,38613,38649,38660,38662,38664, +38675,38670,38673,38671,38678,38681,38692,38698,38704,38713,38717,38718,38724, +38726,38728,38722,38729,38748,38752,38756,38758,38760,21202,38763,38769,38777, +38789,38780,38785,38778,38790,38795,38799,38800,38812,38824,38822,38819,38835, +38836,38851,38854,38856,38859,38876,38893,40783,38898,31455,38902,38901,38927, +38924,38968,38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,39025, +39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,39171,39177, +39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,39229,39230,39234, +39241,39237,39248,39243,39249,39250,39244,39253,39319,39320,39333,39341,39342, +39356,39391,39387,39389,39384,39377,39405,39406,39409,39410,39419,39416,39425, +39439,39429,39394,39449,39467,39479,39493,39490,39488,39491,39486,39509,39501, +39515,39511,39519,39522,39525,39524,39529,39531,39530,39597,39600,39612,39616, +39631,39633,39635,39636,39646,39647,39650,39651,39654,39663,39659,39662,39668, +39665,39671,39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721, +39722,39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827, +39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,39887, +39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,39957,39956, +39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,39973,39972,39969, +39984,40007,39986,40006,39998,40026,40032,40039,40054,40056,40167,40172,40176, +40201,40200,40171,40195,40198,40234,40230,40367,40227,40223,40260,40213,40210, +40257,40255,40254,40262,40264,40285,40286,40292,40273,40272,40281,40306,40329, +40327,40363,40303,40314,40346,40356,40361,40370,40388,40385,40379,40376,40378, +40390,40399,40386,40409,40403,40440,40422,40429,40431,40445,40474,40475,40478, +40565,40569,40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617, +40632,40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672, +40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,30391, +40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,40806,40807, +40812,40810,40823,40818,40822,40853,40860,40864,22575,27079,36953,29796,20956, +29081, +}; + +static const struct dbcs_index jisx0208_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0208_decmap+0,33,126},{__jisx0208_decmap ++94,33,126},{__jisx0208_decmap+188,48,122},{__jisx0208_decmap+263,33,115},{ +__jisx0208_decmap+346,33,118},{__jisx0208_decmap+432,33,88},{__jisx0208_decmap ++488,33,113},{__jisx0208_decmap+569,33,64},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{__jisx0208_decmap+601,33,126},{__jisx0208_decmap+695,33, +126},{__jisx0208_decmap+789,33,126},{__jisx0208_decmap+883,33,126},{ +__jisx0208_decmap+977,33,126},{__jisx0208_decmap+1071,33,126},{ +__jisx0208_decmap+1165,33,126},{__jisx0208_decmap+1259,33,126},{ +__jisx0208_decmap+1353,33,126},{__jisx0208_decmap+1447,33,126},{ +__jisx0208_decmap+1541,33,126},{__jisx0208_decmap+1635,33,126},{ +__jisx0208_decmap+1729,33,126},{__jisx0208_decmap+1823,33,126},{ +__jisx0208_decmap+1917,33,126},{__jisx0208_decmap+2011,33,126},{ +__jisx0208_decmap+2105,33,126},{__jisx0208_decmap+2199,33,126},{ +__jisx0208_decmap+2293,33,126},{__jisx0208_decmap+2387,33,126},{ +__jisx0208_decmap+2481,33,126},{__jisx0208_decmap+2575,33,126},{ +__jisx0208_decmap+2669,33,126},{__jisx0208_decmap+2763,33,126},{ +__jisx0208_decmap+2857,33,126},{__jisx0208_decmap+2951,33,126},{ +__jisx0208_decmap+3045,33,126},{__jisx0208_decmap+3139,33,126},{ +__jisx0208_decmap+3233,33,126},{__jisx0208_decmap+3327,33,126},{ +__jisx0208_decmap+3421,33,126},{__jisx0208_decmap+3515,33,83},{ +__jisx0208_decmap+3566,33,126},{__jisx0208_decmap+3660,33,126},{ +__jisx0208_decmap+3754,33,126},{__jisx0208_decmap+3848,33,126},{ +__jisx0208_decmap+3942,33,126},{__jisx0208_decmap+4036,33,126},{ +__jisx0208_decmap+4130,33,126},{__jisx0208_decmap+4224,33,126},{ +__jisx0208_decmap+4318,33,126},{__jisx0208_decmap+4412,33,126},{ +__jisx0208_decmap+4506,33,126},{__jisx0208_decmap+4600,33,126},{ +__jisx0208_decmap+4694,33,126},{__jisx0208_decmap+4788,33,126},{ +__jisx0208_decmap+4882,33,126},{__jisx0208_decmap+4976,33,126},{ +__jisx0208_decmap+5070,33,126},{__jisx0208_decmap+5164,33,126},{ +__jisx0208_decmap+5258,33,126},{__jisx0208_decmap+5352,33,126},{ +__jisx0208_decmap+5446,33,126},{__jisx0208_decmap+5540,33,126},{ +__jisx0208_decmap+5634,33,126},{__jisx0208_decmap+5728,33,126},{ +__jisx0208_decmap+5822,33,126},{__jisx0208_decmap+5916,33,126},{ +__jisx0208_decmap+6010,33,126},{__jisx0208_decmap+6104,33,126},{ +__jisx0208_decmap+6198,33,126},{__jisx0208_decmap+6292,33,126},{ +__jisx0208_decmap+6386,33,126},{__jisx0208_decmap+6480,33,126},{ +__jisx0208_decmap+6574,33,126},{__jisx0208_decmap+6668,33,126},{ +__jisx0208_decmap+6762,33,126},{__jisx0208_decmap+6856,33,126},{ +__jisx0208_decmap+6950,33,38},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __jisx0212_decmap[6179] = { +728,711,184,729,733,175,731,730,126,900,901,U,U,U,U,U,U,U,U,161,166,191,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,186,170, +169,174,8482,164,8470,902,904,905,906,938,U,908,U,910,939,U,911,U,U,U,U,940, +941,942,943,970,912,972,962,973,971,944,974,1026,1027,1028,1029,1030,1031, +1032,1033,1034,1035,1036,1038,1039,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115, +1116,1118,1119,198,272,U,294,U,306,U,321,319,U,330,216,338,U,358,222,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,230,273,240,295,305,307,312,322,320,329,331,248,339, +223,359,254,193,192,196,194,258,461,256,260,197,195,262,264,268,199,266,270, +201,200,203,202,282,278,274,280,U,284,286,290,288,292,205,204,207,206,463,304, +298,302,296,308,310,313,317,315,323,327,325,209,211,210,214,212,465,336,332, +213,340,344,342,346,348,352,350,356,354,218,217,220,219,364,467,368,362,370, +366,360,471,475,473,469,372,221,376,374,377,381,379,225,224,228,226,259,462, +257,261,229,227,263,265,269,231,267,271,233,232,235,234,283,279,275,281,501, +285,287,U,289,293,237,236,239,238,464,U,299,303,297,309,311,314,318,316,324, +328,326,241,243,242,246,244,466,337,333,245,341,345,343,347,349,353,351,357, +355,250,249,252,251,365,468,369,363,371,367,361,472,476,474,470,373,253,255, +375,378,382,380,19970,19972,19973,19980,19986,19999,20003,20004,20008,20011, +20014,20015,20016,20021,20032,20033,20036,20039,20049,20058,20060,20067,20072, +20073,20084,20085,20089,20095,20109,20118,20119,20125,20143,20153,20163,20176, +20186,20187,20192,20193,20194,20200,20207,20209,20211,20213,20221,20222,20223, +20224,20226,20227,20232,20235,20236,20242,20245,20246,20247,20249,20270,20273, +20320,20275,20277,20279,20281,20283,20286,20288,20290,20296,20297,20299,20300, +20306,20308,20310,20312,20319,20323,20330,20332,20334,20337,20343,20344,20345, +20346,20349,20350,20353,20354,20356,20357,20361,20362,20364,20366,20368,20370, +20371,20372,20375,20377,20378,20382,20383,20402,20407,20409,20411,20412,20413, +20414,20416,20417,20421,20422,20424,20425,20427,20428,20429,20431,20434,20444, +20448,20450,20464,20466,20476,20477,20479,20480,20481,20484,20487,20490,20492, +20494,20496,20499,20503,20504,20507,20508,20509,20510,20514,20519,20526,20528, +20530,20531,20533,20544,20545,20546,20549,20550,20554,20556,20558,20561,20562, +20563,20567,20569,20575,20576,20578,20579,20582,20583,20586,20589,20592,20593, +20539,20609,20611,20612,20614,20618,20622,20623,20624,20626,20627,20628,20630, +20635,20636,20638,20639,20640,20641,20642,20650,20655,20656,20665,20666,20669, +20672,20675,20676,20679,20684,20686,20688,20691,20692,20696,20700,20701,20703, +20706,20708,20710,20712,20713,20719,20721,20726,20730,20734,20739,20742,20743, +20744,20747,20748,20749,20750,20722,20752,20759,20761,20763,20764,20765,20766, +20771,20775,20776,20780,20781,20783,20785,20787,20788,20789,20792,20793,20802, +20810,20815,20819,20821,20823,20824,20831,20836,20838,20862,20867,20868,20875, +20878,20888,20893,20897,20899,20909,20920,20922,20924,20926,20927,20930,20936, +20943,20945,20946,20947,20949,20952,20958,20962,20965,20974,20978,20979,20980, +20983,20993,20994,20997,21010,21011,21013,21014,21016,21026,21032,21041,21042, +21045,21052,21061,21065,21077,21079,21080,21082,21084,21087,21088,21089,21094, +21102,21111,21112,21113,21120,21122,21125,21130,21132,21139,21141,21142,21143, +21144,21146,21148,21156,21157,21158,21159,21167,21168,21174,21175,21176,21178, +21179,21181,21184,21188,21190,21192,21196,21199,21201,21204,21206,21211,21212, +21217,21221,21224,21225,21226,21228,21232,21233,21236,21238,21239,21248,21251, +21258,21259,21260,21265,21267,21272,21275,21276,21278,21279,21285,21287,21288, +21289,21291,21292,21293,21296,21298,21301,21308,21309,21310,21314,21324,21323, +21337,21339,21345,21347,21349,21356,21357,21362,21369,21374,21379,21383,21384, +21390,21395,21396,21401,21405,21409,21412,21418,21419,21423,21426,21428,21429, +21431,21432,21434,21437,21440,21445,21455,21458,21459,21461,21466,21469,21470, +21472,21478,21479,21493,21506,21523,21530,21537,21543,21544,21546,21551,21553, +21556,21557,21571,21572,21575,21581,21583,21598,21602,21604,21606,21607,21609, +21611,21613,21614,21620,21631,21633,21635,21637,21640,21641,21645,21649,21653, +21654,21660,21663,21665,21670,21671,21673,21674,21677,21678,21681,21687,21689, +21690,21691,21695,21702,21706,21709,21710,21728,21738,21740,21743,21750,21756, +21758,21759,21760,21761,21765,21768,21769,21772,21773,21774,21781,21802,21803, +21810,21813,21814,21819,21820,21821,21825,21831,21833,21834,21837,21840,21841, +21848,21850,21851,21854,21856,21857,21860,21862,21887,21889,21890,21894,21896, +21902,21903,21905,21906,21907,21908,21911,21923,21924,21933,21938,21951,21953, +21955,21958,21961,21963,21964,21966,21969,21970,21971,21975,21976,21979,21982, +21986,21993,22006,22015,22021,22024,22026,22029,22030,22031,22032,22033,22034, +22041,22060,22064,22067,22069,22071,22073,22075,22076,22077,22079,22080,22081, +22083,22084,22086,22089,22091,22093,22095,22100,22110,22112,22113,22114,22115, +22118,22121,22125,22127,22129,22130,22133,22148,22149,22152,22155,22156,22165, +22169,22170,22173,22174,22175,22182,22183,22184,22185,22187,22188,22189,22193, +22195,22199,22206,22213,22217,22218,22219,22223,22224,22220,22221,22233,22236, +22237,22239,22241,22244,22245,22246,22247,22248,22257,22251,22253,22262,22263, +22273,22274,22279,22282,22284,22289,22293,22298,22299,22301,22304,22306,22307, +22308,22309,22313,22314,22316,22318,22319,22323,22324,22333,22334,22335,22341, +22342,22348,22349,22354,22370,22373,22375,22376,22379,22381,22382,22383,22384, +22385,22387,22388,22389,22391,22393,22394,22395,22396,22398,22401,22403,22412, +22420,22423,22425,22426,22428,22429,22430,22431,22433,22421,22439,22440,22441, +22444,22456,22461,22471,22472,22476,22479,22485,22493,22494,22500,22502,22503, +22505,22509,22512,22517,22518,22520,22525,22526,22527,22531,22532,22536,22537, +22497,22540,22541,22555,22558,22559,22560,22566,22567,22573,22578,22585,22591, +22601,22604,22605,22607,22608,22613,22623,22625,22628,22631,22632,22648,22652, +22655,22656,22657,22663,22664,22665,22666,22668,22669,22671,22672,22676,22678, +22685,22688,22689,22690,22694,22697,22705,22706,22724,22716,22722,22728,22733, +22734,22736,22738,22740,22742,22746,22749,22753,22754,22761,22771,22789,22790, +22795,22796,22802,22803,22804,34369,22813,22817,22819,22820,22824,22831,22832, +22835,22837,22838,22847,22851,22854,22866,22867,22873,22875,22877,22878,22879, +22881,22883,22891,22893,22895,22898,22901,22902,22905,22907,22908,22923,22924, +22926,22930,22933,22935,22943,22948,22951,22957,22958,22959,22960,22963,22967, +22970,22972,22977,22979,22980,22984,22986,22989,22994,23005,23006,23007,23011, +23012,23015,23022,23023,23025,23026,23028,23031,23040,23044,23052,23053,23054, +23058,23059,23070,23075,23076,23079,23080,23082,23085,23088,23108,23109,23111, +23112,23116,23120,23125,23134,23139,23141,23143,23149,23159,23162,23163,23166, +23179,23184,23187,23190,23193,23196,23198,23199,23200,23202,23207,23212,23217, +23218,23219,23221,23224,23226,23227,23231,23236,23238,23240,23247,23258,23260, +23264,23269,23274,23278,23285,23286,23293,23296,23297,23304,23319,23348,23321, +23323,23325,23329,23333,23341,23352,23361,23371,23372,23378,23382,23390,23400, +23406,23407,23420,23421,23422,23423,23425,23428,23430,23434,23438,23440,23441, +23443,23444,23446,23464,23465,23468,23469,23471,23473,23474,23479,23482,23484, +23488,23489,23501,23503,23510,23511,23512,23513,23514,23520,23535,23537,23540, +23549,23564,23575,23582,23583,23587,23590,23593,23595,23596,23598,23600,23602, +23605,23606,23641,23642,23644,23650,23651,23655,23656,23657,23661,23664,23668, +23669,23674,23675,23676,23677,23687,23688,23690,23695,23698,23709,23711,23712, +23714,23715,23718,23722,23730,23732,23733,23738,23753,23755,23762,23773,23767, +23790,23793,23794,23796,23809,23814,23821,23826,23851,23843,23844,23846,23847, +23857,23860,23865,23869,23871,23874,23875,23878,23880,23893,23889,23897,23882, +23903,23904,23905,23906,23908,23914,23917,23920,23929,23930,23934,23935,23937, +23939,23944,23946,23954,23955,23956,23957,23961,23963,23967,23968,23975,23979, +23984,23988,23992,23993,24003,24007,24011,24016,24014,24024,24025,24032,24036, +24041,24056,24057,24064,24071,24077,24082,24084,24085,24088,24095,24096,24110, +24104,24114,24117,24126,24139,24144,24137,24145,24150,24152,24155,24156,24158, +24168,24170,24171,24172,24173,24174,24176,24192,24203,24206,24226,24228,24229, +24232,24234,24236,24241,24243,24253,24254,24255,24262,24268,24267,24270,24273, +24274,24276,24277,24284,24286,24293,24299,24322,24326,24327,24328,24334,24345, +24348,24349,24353,24354,24355,24356,24360,24363,24364,24366,24368,24372,24374, +24379,24381,24383,24384,24388,24389,24391,24397,24400,24404,24408,24411,24416, +24419,24420,24423,24431,24434,24436,24437,24440,24442,24445,24446,24457,24461, +24463,24470,24476,24477,24482,24487,24491,24484,24492,24495,24496,24497,24504, +24516,24519,24520,24521,24523,24528,24529,24530,24531,24532,24542,24545,24546, +24552,24553,24554,24556,24557,24558,24559,24562,24563,24566,24570,24572,24583, +24586,24589,24595,24596,24599,24600,24602,24607,24612,24621,24627,24629,24640, +24647,24648,24649,24652,24657,24660,24662,24663,24669,24673,24679,24689,24702, +24703,24706,24710,24712,24714,24718,24721,24723,24725,24728,24733,24734,24738, +24740,24741,24744,24752,24753,24759,24763,24766,24770,24772,24776,24777,24778, +24779,24782,24783,24788,24789,24793,24795,24797,24798,24802,24805,24818,24821, +24824,24828,24829,24834,24839,24842,24844,24848,24849,24850,24851,24852,24854, +24855,24857,24860,24862,24866,24874,24875,24880,24881,24885,24886,24887,24889, +24897,24901,24902,24905,24926,24928,24940,24946,24952,24955,24956,24959,24960, +24961,24963,24964,24971,24973,24978,24979,24983,24984,24988,24989,24991,24992, +24997,25000,25002,25005,25016,25017,25020,25024,25025,25026,25038,25039,25045, +25052,25053,25054,25055,25057,25058,25063,25065,25061,25068,25069,25071,25089, +25091,25092,25095,25107,25109,25116,25120,25122,25123,25127,25129,25131,25145, +25149,25154,25155,25156,25158,25164,25168,25169,25170,25172,25174,25178,25180, +25188,25197,25199,25203,25210,25213,25229,25230,25231,25232,25254,25256,25267, +25270,25271,25274,25278,25279,25284,25294,25301,25302,25306,25322,25330,25332, +25340,25341,25347,25348,25354,25355,25357,25360,25363,25366,25368,25385,25386, +25389,25397,25398,25401,25404,25409,25410,25411,25412,25414,25418,25419,25422, +25426,25427,25428,25432,25435,25445,25446,25452,25453,25457,25460,25461,25464, +25468,25469,25471,25474,25476,25479,25482,25488,25492,25493,25497,25498,25502, +25508,25510,25517,25518,25519,25533,25537,25541,25544,25550,25553,25555,25556, +25557,25564,25568,25573,25578,25580,25586,25587,25589,25592,25593,25609,25610, +25616,25618,25620,25624,25630,25632,25634,25636,25637,25641,25642,25647,25648, +25653,25661,25663,25675,25679,25681,25682,25683,25684,25690,25691,25692,25693, +25695,25696,25697,25699,25709,25715,25716,25723,25725,25733,25735,25743,25744, +25745,25752,25753,25755,25757,25759,25761,25763,25766,25768,25772,25779,25789, +25790,25791,25796,25801,25802,25803,25804,25806,25808,25809,25813,25815,25828, +25829,25833,25834,25837,25840,25845,25847,25851,25855,25857,25860,25864,25865, +25866,25871,25875,25876,25878,25881,25883,25886,25887,25890,25894,25897,25902, +25905,25914,25916,25917,25923,25927,25929,25936,25938,25940,25951,25952,25959, +25963,25978,25981,25985,25989,25994,26002,26005,26008,26013,26016,26019,26022, +26030,26034,26035,26036,26047,26050,26056,26057,26062,26064,26068,26070,26072, +26079,26096,26098,26100,26101,26105,26110,26111,26112,26116,26120,26121,26125, +26129,26130,26133,26134,26141,26142,26145,26146,26147,26148,26150,26153,26154, +26155,26156,26158,26160,26161,26163,26169,26167,26176,26181,26182,26186,26188, +26193,26190,26199,26200,26201,26203,26204,26208,26209,26363,26218,26219,26220, +26238,26227,26229,26239,26231,26232,26233,26235,26240,26236,26251,26252,26253, +26256,26258,26265,26266,26267,26268,26271,26272,26276,26285,26289,26290,26293, +26299,26303,26304,26306,26307,26312,26316,26318,26319,26324,26331,26335,26344, +26347,26348,26350,26362,26373,26375,26382,26387,26393,26396,26400,26402,26419, +26430,26437,26439,26440,26444,26452,26453,26461,26470,26476,26478,26484,26486, +26491,26497,26500,26510,26511,26513,26515,26518,26520,26521,26523,26544,26545, +26546,26549,26555,26556,26557,26617,26560,26562,26563,26565,26568,26569,26578, +26583,26585,26588,26593,26598,26608,26610,26614,26615,26706,26644,26649,26653, +26655,26664,26663,26668,26669,26671,26672,26673,26675,26683,26687,26692,26693, +26698,26700,26709,26711,26712,26715,26731,26734,26735,26736,26737,26738,26741, +26745,26746,26747,26748,26754,26756,26758,26760,26774,26776,26778,26780,26785, +26787,26789,26793,26794,26798,26802,26811,26821,26824,26828,26831,26832,26833, +26835,26838,26841,26844,26845,26853,26856,26858,26859,26860,26861,26864,26865, +26869,26870,26875,26876,26877,26886,26889,26890,26896,26897,26899,26902,26903, +26929,26931,26933,26936,26939,26946,26949,26953,26958,26967,26971,26979,26980, +26981,26982,26984,26985,26988,26992,26993,26994,27002,27003,27007,27008,27021, +27026,27030,27032,27041,27045,27046,27048,27051,27053,27055,27063,27064,27066, +27068,27077,27080,27089,27094,27095,27106,27109,27118,27119,27121,27123,27125, +27134,27136,27137,27139,27151,27153,27157,27162,27165,27168,27172,27176,27184, +27186,27188,27191,27195,27198,27199,27205,27206,27209,27210,27214,27216,27217, +27218,27221,27222,27227,27236,27239,27242,27249,27251,27262,27265,27267,27270, +27271,27273,27275,27281,27291,27293,27294,27295,27301,27307,27311,27312,27313, +27316,27325,27326,27327,27334,27337,27336,27340,27344,27348,27349,27350,27356, +27357,27364,27367,27372,27376,27377,27378,27388,27389,27394,27395,27398,27399, +27401,27407,27408,27409,27415,27419,27422,27428,27432,27435,27436,27439,27445, +27446,27451,27455,27462,27466,27469,27474,27478,27480,27485,27488,27495,27499, +27502,27504,27509,27517,27518,27522,27525,27543,27547,27551,27552,27554,27555, +27560,27561,27564,27565,27566,27568,27576,27577,27581,27582,27587,27588,27593, +27596,27606,27610,27617,27619,27622,27623,27630,27633,27639,27641,27647,27650, +27652,27653,27657,27661,27662,27664,27666,27673,27679,27686,27687,27688,27692, +27694,27699,27701,27702,27706,27707,27711,27722,27723,27725,27727,27730,27732, +27737,27739,27740,27755,27757,27759,27764,27766,27768,27769,27771,27781,27782, +27783,27785,27796,27797,27799,27800,27804,27807,27824,27826,27828,27842,27846, +27853,27855,27856,27857,27858,27860,27862,27866,27868,27872,27879,27881,27883, +27884,27886,27890,27892,27908,27911,27914,27918,27919,27921,27923,27930,27942, +27943,27944,27751,27950,27951,27953,27961,27964,27967,27991,27998,27999,28001, +28005,28007,28015,28016,28028,28034,28039,28049,28050,28052,28054,28055,28056, +28074,28076,28084,28087,28089,28093,28095,28100,28104,28106,28110,28111,28118, +28123,28125,28127,28128,28130,28133,28137,28143,28144,28148,28150,28156,28160, +28164,28190,28194,28199,28210,28214,28217,28219,28220,28228,28229,28232,28233, +28235,28239,28241,28242,28243,28244,28247,28252,28253,28254,28258,28259,28264, +28275,28283,28285,28301,28307,28313,28320,28327,28333,28334,28337,28339,28347, +28351,28352,28353,28355,28359,28360,28362,28365,28366,28367,28395,28397,28398, +28409,28411,28413,28420,28424,28426,28428,28429,28438,28440,28442,28443,28454, +28457,28458,28463,28464,28467,28470,28475,28476,28461,28495,28497,28498,28499, +28503,28505,28506,28509,28510,28513,28514,28520,28524,28541,28542,28547,28551, +28552,28555,28556,28557,28560,28562,28563,28564,28566,28570,28575,28576,28581, +28582,28583,28584,28590,28591,28592,28597,28598,28604,28613,28615,28616,28618, +28634,28638,28648,28649,28656,28661,28665,28668,28669,28672,28677,28678,28679, +28685,28695,28704,28707,28719,28724,28727,28729,28732,28739,28740,28744,28745, +28746,28747,28756,28757,28765,28766,28750,28772,28773,28780,28782,28789,28790, +28798,28801,28805,28806,28820,28821,28822,28823,28824,28827,28836,28843,28848, +28849,28852,28855,28874,28881,28883,28884,28885,28886,28888,28892,28900,28922, +28931,28932,28933,28934,28935,28939,28940,28943,28958,28960,28971,28973,28975, +28976,28977,28984,28993,28997,28998,28999,29002,29003,29008,29010,29015,29018, +29020,29022,29024,29032,29049,29056,29061,29063,29068,29074,29082,29083,29088, +29090,29103,29104,29106,29107,29114,29119,29120,29121,29124,29131,29132,29139, +29142,29145,29146,29148,29176,29182,29184,29191,29192,29193,29203,29207,29210, +29213,29215,29220,29227,29231,29236,29240,29241,29249,29250,29251,29253,29262, +29263,29264,29267,29269,29270,29274,29276,29278,29280,29283,29288,29291,29294, +29295,29297,29303,29304,29307,29308,29311,29316,29321,29325,29326,29331,29339, +29352,29357,29358,29361,29364,29374,29377,29383,29385,29388,29397,29398,29400, +29407,29413,29427,29428,29434,29435,29438,29442,29444,29445,29447,29451,29453, +29458,29459,29464,29465,29470,29474,29476,29479,29480,29484,29489,29490,29493, +29498,29499,29501,29507,29517,29520,29522,29526,29528,29533,29534,29535,29536, +29542,29543,29545,29547,29548,29550,29551,29553,29559,29561,29564,29568,29569, +29571,29573,29574,29582,29584,29587,29589,29591,29592,29596,29598,29599,29600, +29602,29605,29606,29610,29611,29613,29621,29623,29625,29628,29629,29631,29637, +29638,29641,29643,29644,29647,29650,29651,29654,29657,29661,29665,29667,29670, +29671,29673,29684,29685,29687,29689,29690,29691,29693,29695,29696,29697,29700, +29703,29706,29713,29722,29723,29732,29734,29736,29737,29738,29739,29740,29741, +29742,29743,29744,29745,29753,29760,29763,29764,29766,29767,29771,29773,29777, +29778,29783,29789,29794,29798,29799,29800,29803,29805,29806,29809,29810,29824, +29825,29829,29830,29831,29833,29839,29840,29841,29842,29848,29849,29850,29852, +29855,29856,29857,29859,29862,29864,29865,29866,29867,29870,29871,29873,29874, +29877,29881,29883,29887,29896,29897,29900,29904,29907,29912,29914,29915,29918, +29919,29924,29928,29930,29931,29935,29940,29946,29947,29948,29951,29958,29970, +29974,29975,29984,29985,29988,29991,29993,29994,29999,30006,30009,30013,30014, +30015,30016,30019,30023,30024,30030,30032,30034,30039,30046,30047,30049,30063, +30065,30073,30074,30075,30076,30077,30078,30081,30085,30096,30098,30099,30101, +30105,30108,30114,30116,30132,30138,30143,30144,30145,30148,30150,30156,30158, +30159,30167,30172,30175,30176,30177,30180,30183,30188,30190,30191,30193,30201, +30208,30210,30211,30212,30215,30216,30218,30220,30223,30226,30227,30229,30230, +30233,30235,30236,30237,30238,30243,30245,30246,30249,30253,30258,30259,30261, +30264,30265,30266,30268,30282,30272,30273,30275,30276,30277,30281,30283,30293, +30297,30303,30308,30309,30317,30318,30319,30321,30324,30337,30341,30348,30349, +30357,30363,30364,30365,30367,30368,30370,30371,30372,30373,30374,30375,30376, +30378,30381,30397,30401,30405,30409,30411,30412,30414,30420,30425,30432,30438, +30440,30444,30448,30449,30454,30457,30460,30464,30470,30474,30478,30482,30484, +30485,30487,30489,30490,30492,30498,30504,30509,30510,30511,30516,30517,30518, +30521,30525,30526,30530,30533,30534,30538,30541,30542,30543,30546,30550,30551, +30556,30558,30559,30560,30562,30564,30567,30570,30572,30576,30578,30579,30580, +30586,30589,30592,30596,30604,30605,30612,30613,30614,30618,30623,30626,30631, +30634,30638,30639,30641,30645,30654,30659,30665,30673,30674,30677,30681,30686, +30687,30688,30692,30694,30698,30700,30704,30705,30708,30712,30715,30725,30726, +30729,30733,30734,30737,30749,30753,30754,30755,30765,30766,30768,30773,30775, +30787,30788,30791,30792,30796,30798,30802,30812,30814,30816,30817,30819,30820, +30824,30826,30830,30842,30846,30858,30863,30868,30872,30881,30877,30878,30879, +30884,30888,30892,30893,30896,30897,30898,30899,30907,30909,30911,30919,30920, +30921,30924,30926,30930,30931,30933,30934,30948,30939,30943,30944,30945,30950, +30954,30962,30963,30976,30966,30967,30970,30971,30975,30982,30988,30992,31002, +31004,31006,31007,31008,31013,31015,31017,31021,31025,31028,31029,31035,31037, +31039,31044,31045,31046,31050,31051,31055,31057,31060,31064,31067,31068,31079, +31081,31083,31090,31097,31099,31100,31102,31115,31116,31121,31123,31124,31125, +31126,31128,31131,31132,31137,31144,31145,31147,31151,31153,31156,31160,31163, +31170,31172,31175,31176,31178,31183,31188,31190,31194,31197,31198,31200,31202, +31205,31210,31211,31213,31217,31224,31228,31234,31235,31239,31241,31242,31244, +31249,31253,31259,31262,31265,31271,31275,31277,31279,31280,31284,31285,31288, +31289,31290,31300,31301,31303,31304,31308,31317,31318,31321,31324,31325,31327, +31328,31333,31335,31338,31341,31349,31352,31358,31360,31362,31365,31366,31370, +31371,31376,31377,31380,31390,31392,31395,31404,31411,31413,31417,31419,31420, +31430,31433,31436,31438,31441,31451,31464,31465,31467,31468,31473,31476,31483, +31485,31486,31495,31508,31519,31523,31527,31529,31530,31531,31533,31534,31535, +31536,31537,31540,31549,31551,31552,31553,31559,31566,31573,31584,31588,31590, +31593,31594,31597,31599,31602,31603,31607,31620,31625,31630,31632,31633,31638, +31643,31646,31648,31653,31660,31663,31664,31666,31669,31670,31674,31675,31676, +31677,31682,31685,31688,31690,31700,31702,31703,31705,31706,31707,31720,31722, +31730,31732,31733,31736,31737,31738,31740,31742,31745,31746,31747,31748,31750, +31753,31755,31756,31758,31759,31769,31771,31776,31781,31782,31784,31788,31793, +31795,31796,31798,31801,31802,31814,31818,31829,31825,31826,31827,31833,31834, +31835,31836,31837,31838,31841,31843,31847,31849,31853,31854,31856,31858,31865, +31868,31869,31878,31879,31887,31892,31902,31904,31910,31920,31926,31927,31930, +31931,31932,31935,31940,31943,31944,31945,31949,31951,31955,31956,31957,31959, +31961,31962,31965,31974,31977,31979,31989,32003,32007,32008,32009,32015,32017, +32018,32019,32022,32029,32030,32035,32038,32042,32045,32049,32060,32061,32062, +32064,32065,32071,32072,32077,32081,32083,32087,32089,32090,32092,32093,32101, +32103,32106,32112,32120,32122,32123,32127,32129,32130,32131,32133,32134,32136, +32139,32140,32141,32145,32150,32151,32157,32158,32166,32167,32170,32179,32182, +32183,32185,32194,32195,32196,32197,32198,32204,32205,32206,32215,32217,32256, +32226,32229,32230,32234,32235,32237,32241,32245,32246,32249,32250,32264,32272, +32273,32277,32279,32284,32285,32288,32295,32296,32300,32301,32303,32307,32310, +32319,32324,32325,32327,32334,32336,32338,32344,32351,32353,32354,32357,32363, +32366,32367,32371,32376,32382,32385,32390,32391,32394,32397,32401,32405,32408, +32410,32413,32414,32572,32571,32573,32574,32575,32579,32580,32583,32591,32594, +32595,32603,32604,32605,32609,32611,32612,32613,32614,32621,32625,32637,32638, +32639,32640,32651,32653,32655,32656,32657,32662,32663,32668,32673,32674,32678, +32682,32685,32692,32700,32703,32704,32707,32712,32718,32719,32731,32735,32739, +32741,32744,32748,32750,32751,32754,32762,32765,32766,32767,32775,32776,32778, +32781,32782,32783,32785,32787,32788,32790,32797,32798,32799,32800,32804,32806, +32812,32814,32816,32820,32821,32823,32825,32826,32828,32830,32832,32836,32864, +32868,32870,32877,32881,32885,32897,32904,32910,32924,32926,32934,32935,32939, +32952,32953,32968,32973,32975,32978,32980,32981,32983,32984,32992,33005,33006, +33008,33010,33011,33014,33017,33018,33022,33027,33035,33046,33047,33048,33052, +33054,33056,33060,33063,33068,33072,33077,33082,33084,33093,33095,33098,33100, +33106,33111,33120,33121,33127,33128,33129,33133,33135,33143,33153,33168,33156, +33157,33158,33163,33166,33174,33176,33179,33182,33186,33198,33202,33204,33211, +33227,33219,33221,33226,33230,33231,33237,33239,33243,33245,33246,33249,33252, +33259,33260,33264,33265,33266,33269,33270,33272,33273,33277,33279,33280,33283, +33295,33299,33300,33305,33306,33309,33313,33314,33320,33330,33332,33338,33347, +33348,33349,33350,33355,33358,33359,33361,33366,33372,33376,33379,33383,33389, +33396,33403,33405,33407,33408,33409,33411,33412,33415,33417,33418,33422,33425, +33428,33430,33432,33434,33435,33440,33441,33443,33444,33447,33448,33449,33450, +33454,33456,33458,33460,33463,33466,33468,33470,33471,33478,33488,33493,33498, +33504,33506,33508,33512,33514,33517,33519,33526,33527,33533,33534,33536,33537, +33543,33544,33546,33547,33620,33563,33565,33566,33567,33569,33570,33580,33581, +33582,33584,33587,33591,33594,33596,33597,33602,33603,33604,33607,33613,33614, +33617,33621,33622,33623,33648,33656,33661,33663,33664,33666,33668,33670,33677, +33682,33684,33685,33688,33689,33691,33692,33693,33702,33703,33705,33708,33726, +33727,33728,33735,33737,33743,33744,33745,33748,33757,33619,33768,33770,33782, +33784,33785,33788,33793,33798,33802,33807,33809,33813,33817,33709,33839,33849, +33861,33863,33864,33866,33869,33871,33873,33874,33878,33880,33881,33882,33884, +33888,33892,33893,33895,33898,33904,33907,33908,33910,33912,33916,33917,33921, +33925,33938,33939,33941,33950,33958,33960,33961,33962,33967,33969,33972,33978, +33981,33982,33984,33986,33991,33992,33996,33999,34003,34012,34023,34026,34031, +34032,34033,34034,34039,34098,34042,34043,34045,34050,34051,34055,34060,34062, +34064,34076,34078,34082,34083,34084,34085,34087,34090,34091,34095,34099,34100, +34102,34111,34118,34127,34128,34129,34130,34131,34134,34137,34140,34141,34142, +34143,34144,34145,34146,34148,34155,34159,34169,34170,34171,34173,34175,34177, +34181,34182,34185,34187,34188,34191,34195,34200,34205,34207,34208,34210,34213, +34215,34228,34230,34231,34232,34236,34237,34238,34239,34242,34247,34250,34251, +34254,34221,34264,34266,34271,34272,34278,34280,34285,34291,34294,34300,34303, +34304,34308,34309,34317,34318,34320,34321,34322,34328,34329,34331,34334,34337, +34343,34345,34358,34360,34362,34364,34365,34368,34370,34374,34386,34387,34390, +34391,34392,34393,34397,34400,34401,34402,34403,34404,34409,34412,34415,34421, +34422,34423,34426,34445,34449,34454,34456,34458,34460,34465,34470,34471,34472, +34477,34481,34483,34484,34485,34487,34488,34489,34495,34496,34497,34499,34501, +34513,34514,34517,34519,34522,34524,34528,34531,34533,34535,34440,34554,34556, +34557,34564,34565,34567,34571,34574,34575,34576,34579,34580,34585,34590,34591, +34593,34595,34600,34606,34607,34609,34610,34617,34618,34620,34621,34622,34624, +34627,34629,34637,34648,34653,34657,34660,34661,34671,34673,34674,34683,34691, +34692,34693,34694,34695,34696,34697,34699,34700,34704,34707,34709,34711,34712, +34713,34718,34720,34723,34727,34732,34733,34734,34737,34741,34750,34751,34753, +34760,34761,34762,34766,34773,34774,34777,34778,34780,34783,34786,34787,34788, +34794,34795,34797,34801,34803,34808,34810,34815,34817,34819,34822,34825,34826, +34827,34832,34841,34834,34835,34836,34840,34842,34843,34844,34846,34847,34856, +34861,34862,34864,34866,34869,34874,34876,34881,34883,34885,34888,34889,34890, +34891,34894,34897,34901,34902,34904,34906,34908,34911,34912,34916,34921,34929, +34937,34939,34944,34968,34970,34971,34972,34975,34976,34984,34986,35002,35005, +35006,35008,35018,35019,35020,35021,35022,35025,35026,35027,35035,35038,35047, +35055,35056,35057,35061,35063,35073,35078,35085,35086,35087,35093,35094,35096, +35097,35098,35100,35104,35110,35111,35112,35120,35121,35122,35125,35129,35130, +35134,35136,35138,35141,35142,35145,35151,35154,35159,35162,35163,35164,35169, +35170,35171,35179,35182,35184,35187,35189,35194,35195,35196,35197,35209,35213, +35216,35220,35221,35227,35228,35231,35232,35237,35248,35252,35253,35254,35255, +35260,35284,35285,35286,35287,35288,35301,35305,35307,35309,35313,35315,35318, +35321,35325,35327,35332,35333,35335,35343,35345,35346,35348,35349,35358,35360, +35362,35364,35366,35371,35372,35375,35381,35383,35389,35390,35392,35395,35397, +35399,35401,35405,35406,35411,35414,35415,35416,35420,35421,35425,35429,35431, +35445,35446,35447,35449,35450,35451,35454,35455,35456,35459,35462,35467,35471, +35472,35474,35478,35479,35481,35487,35495,35497,35502,35503,35507,35510,35511, +35515,35518,35523,35526,35528,35529,35530,35537,35539,35540,35541,35543,35549, +35551,35564,35568,35572,35573,35574,35580,35583,35589,35590,35595,35601,35612, +35614,35615,35594,35629,35632,35639,35644,35650,35651,35652,35653,35654,35656, +35666,35667,35668,35673,35661,35678,35683,35693,35702,35704,35705,35708,35710, +35713,35716,35717,35723,35725,35727,35732,35733,35740,35742,35743,35896,35897, +35901,35902,35909,35911,35913,35915,35919,35921,35923,35924,35927,35928,35931, +35933,35929,35939,35940,35942,35944,35945,35949,35955,35957,35958,35963,35966, +35974,35975,35979,35984,35986,35987,35993,35995,35996,36004,36025,36026,36037, +36038,36041,36043,36047,36054,36053,36057,36061,36065,36072,36076,36079,36080, +36082,36085,36087,36088,36094,36095,36097,36099,36105,36114,36119,36123,36197, +36201,36204,36206,36223,36226,36228,36232,36237,36240,36241,36245,36254,36255, +36256,36262,36267,36268,36271,36274,36277,36279,36281,36283,36288,36293,36294, +36295,36296,36298,36302,36305,36308,36309,36311,36313,36324,36325,36327,36332, +36336,36284,36337,36338,36340,36349,36353,36356,36357,36358,36363,36369,36372, +36374,36384,36385,36386,36387,36390,36391,36401,36403,36406,36407,36408,36409, +36413,36416,36417,36427,36429,36430,36431,36436,36443,36444,36445,36446,36449, +36450,36457,36460,36461,36463,36464,36465,36473,36474,36475,36482,36483,36489, +36496,36498,36501,36506,36507,36509,36510,36514,36519,36521,36525,36526,36531, +36533,36538,36539,36544,36545,36547,36548,36551,36559,36561,36564,36572,36584, +36590,36592,36593,36599,36601,36602,36589,36608,36610,36615,36616,36623,36624, +36630,36631,36632,36638,36640,36641,36643,36645,36647,36648,36652,36653,36654, +36660,36661,36662,36663,36666,36672,36673,36675,36679,36687,36689,36690,36691, +36692,36693,36696,36701,36702,36709,36765,36768,36769,36772,36773,36774,36789, +36790,36792,36798,36800,36801,36806,36810,36811,36813,36816,36818,36819,36821, +36832,36835,36836,36840,36846,36849,36853,36854,36859,36862,36866,36868,36872, +36876,36888,36891,36904,36905,36911,36906,36908,36909,36915,36916,36919,36927, +36931,36932,36940,36955,36957,36962,36966,36967,36972,36976,36980,36985,36997, +37000,37003,37004,37006,37008,37013,37015,37016,37017,37019,37024,37025,37026, +37029,37040,37042,37043,37044,37046,37053,37068,37054,37059,37060,37061,37063, +37064,37077,37079,37080,37081,37084,37085,37087,37093,37074,37110,37099,37103, +37104,37108,37118,37119,37120,37124,37125,37126,37128,37133,37136,37140,37142, +37143,37144,37146,37148,37150,37152,37157,37154,37155,37159,37161,37166,37167, +37169,37172,37174,37175,37177,37178,37180,37181,37187,37191,37192,37199,37203, +37207,37209,37210,37211,37217,37220,37223,37229,37236,37241,37242,37243,37249, +37251,37253,37254,37258,37262,37265,37267,37268,37269,37272,37278,37281,37286, +37288,37292,37293,37294,37296,37297,37298,37299,37302,37307,37308,37309,37311, +37314,37315,37317,37331,37332,37335,37337,37338,37342,37348,37349,37353,37354, +37356,37357,37358,37359,37360,37361,37367,37369,37371,37373,37376,37377,37380, +37381,37382,37383,37385,37386,37388,37392,37394,37395,37398,37400,37404,37405, +37411,37412,37413,37414,37416,37422,37423,37424,37427,37429,37430,37432,37433, +37434,37436,37438,37440,37442,37443,37446,37447,37450,37453,37454,37455,37457, +37464,37465,37468,37469,37472,37473,37477,37479,37480,37481,37486,37487,37488, +37493,37494,37495,37496,37497,37499,37500,37501,37503,37512,37513,37514,37517, +37518,37522,37527,37529,37535,37536,37540,37541,37543,37544,37547,37551,37554, +37558,37560,37562,37563,37564,37565,37567,37568,37569,37570,37571,37573,37574, +37575,37576,37579,37580,37581,37582,37584,37587,37589,37591,37592,37593,37596, +37597,37599,37600,37601,37603,37605,37607,37608,37612,37614,37616,37625,37627, +37631,37632,37634,37640,37645,37649,37652,37653,37660,37661,37662,37663,37665, +37668,37669,37671,37673,37674,37683,37684,37686,37687,37703,37704,37705,37712, +37713,37714,37717,37719,37720,37722,37726,37732,37733,37735,37737,37738,37741, +37743,37744,37745,37747,37748,37750,37754,37757,37759,37760,37761,37762,37768, +37770,37771,37773,37775,37778,37781,37784,37787,37790,37793,37795,37796,37798, +37800,37803,37812,37813,37814,37818,37801,37825,37828,37829,37830,37831,37833, +37834,37835,37836,37837,37843,37849,37852,37854,37855,37858,37862,37863,37881, +37879,37880,37882,37883,37885,37889,37890,37892,37896,37897,37901,37902,37903, +37909,37910,37911,37919,37934,37935,37937,37938,37939,37940,37947,37951,37949, +37955,37957,37960,37962,37964,37973,37977,37980,37983,37985,37987,37992,37995, +37997,37998,37999,38001,38002,38020,38019,38264,38265,38270,38276,38280,38284, +38285,38286,38301,38302,38303,38305,38310,38313,38315,38316,38324,38326,38330, +38333,38335,38342,38344,38345,38347,38352,38353,38354,38355,38361,38362,38365, +38366,38367,38368,38372,38374,38429,38430,38434,38436,38437,38438,38444,38449, +38451,38455,38456,38457,38458,38460,38461,38465,38482,38484,38486,38487,38488, +38497,38510,38516,38523,38524,38526,38527,38529,38530,38531,38532,38537,38545, +38550,38554,38557,38559,38564,38565,38566,38569,38574,38575,38579,38586,38602, +38610,23986,38616,38618,38621,38622,38623,38633,38639,38641,38650,38658,38659, +38661,38665,38682,38683,38685,38689,38690,38691,38696,38705,38707,38721,38723, +38730,38734,38735,38741,38743,38744,38746,38747,38755,38759,38762,38766,38771, +38774,38775,38776,38779,38781,38783,38784,38793,38805,38806,38807,38809,38810, +38814,38815,38818,38828,38830,38833,38834,38837,38838,38840,38841,38842,38844, +38846,38847,38849,38852,38853,38855,38857,38858,38860,38861,38862,38864,38865, +38868,38871,38872,38873,38877,38878,38880,38875,38881,38884,38895,38897,38900, +38903,38904,38906,38919,38922,38937,38925,38926,38932,38934,38940,38942,38944, +38947,38950,38955,38958,38959,38960,38962,38963,38965,38949,38974,38980,38983, +38986,38993,38994,38995,38998,38999,39001,39002,39010,39011,39013,39014,39018, +39020,39083,39085,39086,39088,39092,39095,39096,39098,39099,39103,39106,39109, +39112,39116,39137,39139,39141,39142,39143,39146,39155,39158,39170,39175,39176, +39185,39189,39190,39191,39194,39195,39196,39199,39202,39206,39207,39211,39217, +39218,39219,39220,39221,39225,39226,39227,39228,39232,39233,39238,39239,39240, +39245,39246,39252,39256,39257,39259,39260,39262,39263,39264,39323,39325,39327, +39334,39344,39345,39346,39349,39353,39354,39357,39359,39363,39369,39379,39380, +39385,39386,39388,39390,39399,39402,39403,39404,39408,39412,39413,39417,39421, +39422,39426,39427,39428,39435,39436,39440,39441,39446,39454,39456,39458,39459, +39460,39463,39469,39470,39475,39477,39478,39480,39495,39489,39492,39498,39499, +39500,39502,39505,39508,39510,39517,39594,39596,39598,39599,39602,39604,39605, +39606,39609,39611,39614,39615,39617,39619,39622,39624,39630,39632,39634,39637, +39638,39639,39643,39644,39648,39652,39653,39655,39657,39660,39666,39667,39669, +39673,39674,39677,39679,39680,39681,39682,39683,39684,39685,39688,39689,39691, +39692,39693,39694,39696,39698,39702,39705,39707,39708,39712,39718,39723,39725, +39731,39732,39733,39735,39737,39738,39741,39752,39755,39756,39765,39766,39767, +39771,39774,39777,39779,39781,39782,39784,39786,39787,39788,39789,39790,39795, +39797,39799,39800,39801,39807,39808,39812,39813,39814,39815,39817,39818,39819, +39821,39823,39824,39828,39834,39837,39838,39846,39847,39849,39852,39856,39857, +39858,39863,39864,39867,39868,39870,39871,39873,39879,39880,39886,39888,39895, +39896,39901,39903,39909,39911,39914,39915,39919,39923,39927,39928,39929,39930, +39933,39935,39936,39938,39947,39951,39953,39958,39960,39961,39962,39964,39966, +39970,39971,39974,39975,39976,39977,39978,39985,39989,39990,39991,39997,40001, +40003,40004,40005,40009,40010,40014,40015,40016,40019,40020,40022,40024,40027, +40029,40030,40031,40035,40041,40042,40028,40043,40040,40046,40048,40050,40053, +40055,40059,40166,40178,40183,40185,40203,40194,40209,40215,40216,40220,40221, +40222,40239,40240,40242,40243,40244,40250,40252,40261,40253,40258,40259,40263, +40266,40275,40276,40287,40291,40290,40293,40297,40298,40299,40304,40310,40311, +40315,40316,40318,40323,40324,40326,40330,40333,40334,40338,40339,40341,40342, +40343,40344,40353,40362,40364,40366,40369,40373,40377,40380,40383,40387,40391, +40393,40394,40404,40405,40406,40407,40410,40414,40415,40416,40421,40423,40425, +40427,40430,40432,40435,40436,40446,40458,40450,40455,40462,40464,40465,40466, +40469,40470,40473,40476,40477,40570,40571,40572,40576,40578,40579,40580,40581, +40583,40590,40591,40598,40600,40603,40606,40612,40616,40620,40622,40623,40624, +40627,40628,40629,40646,40648,40651,40661,40671,40676,40679,40684,40685,40686, +40688,40689,40690,40693,40696,40703,40706,40707,40713,40719,40720,40721,40722, +40724,40726,40727,40729,40730,40731,40735,40738,40742,40746,40747,40751,40753, +40754,40756,40759,40761,40762,40764,40765,40767,40769,40771,40772,40773,40774, +40775,40787,40789,40790,40791,40792,40794,40797,40798,40808,40809,40813,40814, +40815,40816,40817,40819,40821,40826,40829,40847,40848,40849,40850,40852,40854, +40855,40862,40865,40866,40867,40869, +}; + +static const struct dbcs_index jisx0212_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0212_decmap+0,47,113},{0,0,0},{ +0,0,0},{0,0,0},{__jisx0212_decmap+67,97,124},{__jisx0212_decmap+95,66,126},{0, +0,0},{__jisx0212_decmap+156,33,80},{__jisx0212_decmap+204,33,119},{ +__jisx0212_decmap+291,33,119},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0212_decmap+378,33,126},{__jisx0212_decmap+472,33,126},{ +__jisx0212_decmap+566,33,126},{__jisx0212_decmap+660,33,126},{ +__jisx0212_decmap+754,33,126},{__jisx0212_decmap+848,33,126},{ +__jisx0212_decmap+942,33,126},{__jisx0212_decmap+1036,33,126},{ +__jisx0212_decmap+1130,33,126},{__jisx0212_decmap+1224,33,126},{ +__jisx0212_decmap+1318,33,126},{__jisx0212_decmap+1412,33,126},{ +__jisx0212_decmap+1506,33,126},{__jisx0212_decmap+1600,33,126},{ +__jisx0212_decmap+1694,33,126},{__jisx0212_decmap+1788,33,126},{ +__jisx0212_decmap+1882,33,126},{__jisx0212_decmap+1976,33,126},{ +__jisx0212_decmap+2070,33,126},{__jisx0212_decmap+2164,33,126},{ +__jisx0212_decmap+2258,33,126},{__jisx0212_decmap+2352,33,126},{ +__jisx0212_decmap+2446,33,126},{__jisx0212_decmap+2540,33,126},{ +__jisx0212_decmap+2634,33,126},{__jisx0212_decmap+2728,33,126},{ +__jisx0212_decmap+2822,33,126},{__jisx0212_decmap+2916,33,126},{ +__jisx0212_decmap+3010,33,126},{__jisx0212_decmap+3104,33,126},{ +__jisx0212_decmap+3198,33,126},{__jisx0212_decmap+3292,33,126},{ +__jisx0212_decmap+3386,33,126},{__jisx0212_decmap+3480,33,126},{ +__jisx0212_decmap+3574,33,126},{__jisx0212_decmap+3668,33,126},{ +__jisx0212_decmap+3762,33,126},{__jisx0212_decmap+3856,33,126},{ +__jisx0212_decmap+3950,33,126},{__jisx0212_decmap+4044,33,126},{ +__jisx0212_decmap+4138,33,126},{__jisx0212_decmap+4232,33,126},{ +__jisx0212_decmap+4326,33,126},{__jisx0212_decmap+4420,33,126},{ +__jisx0212_decmap+4514,33,126},{__jisx0212_decmap+4608,33,126},{ +__jisx0212_decmap+4702,33,126},{__jisx0212_decmap+4796,33,126},{ +__jisx0212_decmap+4890,33,126},{__jisx0212_decmap+4984,33,126},{ +__jisx0212_decmap+5078,33,126},{__jisx0212_decmap+5172,33,126},{ +__jisx0212_decmap+5266,33,126},{__jisx0212_decmap+5360,33,126},{ +__jisx0212_decmap+5454,33,126},{__jisx0212_decmap+5548,33,126},{ +__jisx0212_decmap+5642,33,126},{__jisx0212_decmap+5736,33,126},{ +__jisx0212_decmap+5830,33,126},{__jisx0212_decmap+5924,33,126},{ +__jisx0212_decmap+6018,33,126},{__jisx0212_decmap+6112,33,99},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __jisxcommon_encmap[22016] = { +8512,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41527, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41538, +8561,8562,41584,N,41539,8568,8495,41581,41580,N,8780,N,41582,41524,8555,8542, +N,N,8493,N,8825,N,41521,N,41579,N,N,N,N,41540,43554,43553,43556,43562,43555, +43561,43297,43566,43570,43569,43572,43571,43584,43583,43586,43585,N,43600, +43602,43601,43604,43608,43603,8543,43308,43619,43618,43621,43620,43634,43312, +43342,43810,43809,43812,43818,43811,43817,43329,43822,43826,43825,43828,43827, +43840,43839,43842,43841,43331,43856,43858,43857,43860,43864,43859,8544,43340, +43875,43874,43877,43876,43890,43344,43891,43559,43815,43557,43813,43560,43816, +43563,43819,43564,43820,43567,43823,43565,43821,43568,43824,43298,43330,43575, +43831,N,N,43574,43830,43576,43832,43573,43829,43578,43834,43579,43835,43581, +43837,43580,N,43582,43838,43300,43332,43591,43847,43589,43845,N,N,43590,43846, +43588,43333,43302,43334,43592,43848,43593,43849,43335,43594,43850,43596,43852, +43595,43851,43305,43337,43304,43336,43597,43853,43599,43855,43598,43854,43338, +43307,43339,43607,43863,N,N,43606,43862,43309,43341,43609,43865,43611,43867, +43610,43866,43612,43868,43613,43869,43615,43871,43614,43870,43617,43873,43616, +43872,43311,43343,43628,43884,43625,43881,43622,43878,43627,43883,43624,43880, +43626,43882,43633,43889,43636,43892,43635,43637,43893,43639,43895,43638,43894, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43558,43814,43587,43843,43605,43861,43623,43879,43632,43888,43629,43885,43631, +43887,43630,43886,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43833,41520, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41519,41522,41526,41525,N,41523,41528,41529, +42593,N,42594,42595,42596,N,42599,N,42601,42604,42614,9761,9762,9763,9764, +9765,9766,9767,9768,9769,9770,9771,9772,9773,9774,9775,9776,9777,N,9778,9779, +9780,9781,9782,9783,9784,42597,42602,42609,42610,42611,42612,42619,9793,9794, +9795,9796,9797,9798,9799,9800,9801,9802,9803,9804,9805,9806,9807,9808,9809, +42616,9810,9811,9812,9813,9814,9815,9816,42613,42618,42615,42617,42620,10023, +42818,42819,42820,42821,42822,42823,42824,42825,42826,42827,42828,N,42829, +42830,10017,10018,10019,10020,10021,10022,10024,10025,10026,10027,10028,10029, +10030,10031,10032,10033,10034,10035,10036,10037,10038,10039,10040,10041,10042, +10043,10044,10045,10046,10047,10048,10049,10065,10066,10067,10068,10069,10070, +10072,10073,10074,10075,10076,10077,10078,10079,10080,10081,10082,10083,10084, +10085,10086,10087,10088,10089,10090,10091,10092,10093,10094,10095,10096,10097, +N,10071,42866,42867,42868,42869,42870,42871,42872,42873,42874,42875,42876,N, +42877,42878,8510,N,N,N,N,8509,8514,N,8518,8519,N,N,8520,8521,N,N,8823,8824,N, +N,N,8517,8516,N,N,N,N,N,N,N,N,N,8819,N,8556,8557,N,N,N,N,N,N,N,8744,8558,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41585,N,N,N,N,N,N,N,N,N,N,N,41583,N,N,N,N,N,N, +N,N,8818,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8747,8748,8746,8749,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8781,N,8782,8783,N,8799,8784,N,N,N, +8800,8762,N,N,8763,N,N,N,N,N,N,8541,N,N,N,N,N,N,N,8805,N,N,8807,8551,N,8796,N, +N,N,N,N,N,8778,8779,8769,8768,8809,8810,N,N,N,N,N,N,N,8552,8808,N,N,N,N,N,N,N, +8806,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8802,N,N,N,N,N,N,N,N,N,N,N,N,N, +8546,8801,N,N,N,N,8549,8550,N,N,8803,8804,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,8766,8767,N,N,8764,8765,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,8797,8798,10273,10284,10274,10285,N,N,N,N,N,N,N,N,10275,N,N,10286, +10276,N,N,10287,10278,N,N,10289,10277,N,N,10288,10279,10300,N,N,10295,N,N, +10290,10281,10302,N,N,10297,N,N,10292,10280,N,N,10296,10301,N,N,10291,10282,N, +N,10298,10303,N,N,10293,10283,N,N,10299,N,N,10304,N,N,N,N,N,N,N,N,10294,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,8739,8738,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8741,8740,N,N,N,N,N,N,N,N, +8743,8742,N,N,N,N,N,N,N,N,8737,8574,N,N,N,8571,N,N,8573,8572,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8830,8570,8569,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,8554,N,8553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8822,N,N,8821,N,8820,8481,8482,8483,8503,N, +8505,8506,8507,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8745,8750, +8524,8525,N,N,N,N,N,N,8513,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259, +9260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274, +9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289, +9290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304, +9305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319, +9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,N,N,N,N,N,N,N, +8491,8492,8501,8502,N,N,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514, +9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529, +9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544, +9545,9546,9547,9548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559, +9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574, +9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589, +9590,N,N,N,N,8486,8508,8499,8500,12396,17274,45089,15415,45090,45091,N,19324, +15974,15152,15973,12860,45092,18772,19775,N,20514,12591,45093,N,13166,20515, +16420,21058,13654,19002,N,N,N,N,15975,45094,N,20030,N,45095,45096,N,19010,N, +45097,N,20516,45098,N,17254,45099,45100,45101,20517,13946,N,N,45102,20518,N, +13405,17200,N,15463,20519,N,N,20520,45103,45104,20521,18229,45105,13655,N, +45106,N,N,N,18231,N,18019,14403,19251,N,45107,N,N,N,26953,20522,15976,20523, +12853,45108,N,45109,13925,14448,19561,N,N,22054,45110,N,N,N,N,45111,45112,N,N, +N,N,N,N,N,19824,N,18045,45113,45114,N,N,N,45115,N,N,N,N,13349,45116,13621,N, +20524,N,N,20525,20027,N,19773,16744,20527,15222,18035,45117,20530,N,N,12606, +14431,N,14430,12390,45118,45119,20299,20298,N,14899,12321,45120,20531,20532, +20533,19252,20534,N,14450,12391,19314,N,13692,N,N,13693,13694,17506,20028, +45121,20535,N,N,20536,N,N,20537,N,N,45122,16205,N,N,N,N,N,15674,16206,20542, +45123,20540,N,20541,13656,N,N,14883,12912,N,20539,20538,18985,45124,N,N,N, +15174,15173,16958,20543,18773,16487,45125,45126,N,8504,20544,20546,45127, +45128,45129,16997,20065,12362,N,N,45130,N,N,N,N,20545,12862,45131,13892,45132, +17255,45133,N,45134,14191,20547,N,N,N,18212,N,45135,45136,45137,45138,13419, +45139,45140,N,N,N,N,45141,20548,12363,45142,45143,14432,13420,18810,18482, +13657,45144,N,N,45145,45146,45147,N,45148,12913,N,20583,17729,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,45149,18284,20550,45150,N,45152,18492,45153,20066,45154,16173, +45155,15175,45156,15223,12864,45157,N,45158,N,45159,17489,N,N,17186,20554, +45160,45161,N,45162,45163,12364,17507,15675,14900,19748,45164,16974,45165, +12863,45166,20553,45167,19774,20549,20551,14958,20552,21796,45168,45151,N,N, +45169,N,N,N,N,N,20560,45170,N,45171,N,45172,20563,20561,45173,N,12866,N,19003, +20555,45174,45175,45176,45177,20559,14451,45178,45179,15176,N,45180,45181, +13350,45182,45345,20564,N,20556,45346,45347,20067,45348,15224,45349,20557, +45350,20562,45351,45352,45353,N,20565,45354,20558,45355,45356,13857,N,12365, +45357,45358,13858,12865,N,N,N,N,N,N,N,N,N,21797,N,19321,18798,14452,N,N,45359, +N,N,16175,20023,45360,N,45361,N,45362,45363,45364,45365,19032,45366,45367, +14136,16933,12900,45368,45369,N,45370,45371,15699,45372,45373,45374,20569, +45375,20574,20572,45376,N,20567,N,N,16943,20570,N,20573,20571,45377,19037,N, +20568,45378,16174,45379,19315,20575,20576,N,N,N,N,N,N,N,N,15652,20589,45380,N, +45381,18256,N,18742,20584,N,19056,N,12854,N,45382,45383,20588,45384,45385, +45386,N,N,45387,20582,20591,45388,N,16722,45389,14404,45390,18268,45391,24647, +45392,20590,17757,45393,20579,N,14454,45394,45395,14453,20577,45396,45397, +45398,45399,15450,N,20585,45400,19055,17229,20581,14193,45401,20578,20586, +20580,20049,20587,20289,45402,N,45403,N,45404,45405,N,45406,13926,N,N,14192,N, +45430,N,N,N,N,45407,45408,45409,20592,N,45410,45411,20593,20597,12366,45412,N, +45413,N,45414,19024,20596,45415,45416,45417,N,20595,20599,45418,N,45419,20598, +N,17508,N,N,45420,45421,N,45422,45423,N,14194,45424,45425,N,N,45426,N,20600, +45427,N,N,45428,45429,15429,N,16934,17509,13942,N,20601,N,N,N,N,13622,N,N, +20602,45431,N,45432,45433,20604,45434,N,N,N,45435,N,N,19253,45436,45437,45438, +14182,45601,45602,45603,N,45604,N,15153,18551,20603,45605,45606,N,45607,45608, +45609,45610,45611,N,N,N,N,N,N,N,45612,N,14917,19779,N,45613,45614,N,20606, +20771,20605,14916,N,15741,N,45615,45616,N,N,45617,14137,N,45618,N,20772,45619, +45620,13903,N,45621,N,20769,20770,N,45622,17967,45623,16764,45624,13859,N, +45625,45626,19277,20773,N,45627,N,20029,N,45628,45629,20774,45630,N,N,45631, +20777,45632,20775,45633,16718,45634,45635,N,N,N,20776,20778,45636,N,45637, +45649,N,N,20780,45638,N,N,20779,45639,19016,N,N,45640,13623,20782,20783,45641, +12847,N,45642,45643,45644,20781,N,45645,45646,45647,45648,N,45650,N,15476,N, +20786,20785,20784,45651,20566,45652,20787,45653,45654,45655,45656,15742,N, +20788,N,45657,N,N,N,45658,45659,N,19749,N,45660,45661,N,45662,N,45663,19545, +45664,45665,45666,N,20790,45667,45668,20789,20792,20791,N,N,20793,20794,12404, +45669,14389,14139,15676,17275,13860,16488,14455,45670,14702,20796,19528,17734, +45671,15225,N,20795,45672,20797,45673,N,45674,45675,N,17758,N,13173,N,N,45676, +N,N,20798,N,45677,18046,45678,N,16692,20800,20801,18476,14456,20283,20802,N,N, +13862,N,N,N,19004,16950,13937,17717,N,N,N,14195,N,45679,N,20803,N,20804,45680, +45681,18018,12639,N,N,20807,14973,45682,20806,14918,45683,20808,26222,20809, +19265,20810,N,20811,20812,15977,45684,15436,N,N,N,45685,N,N,13351,45686,20815, +45687,20813,19517,20814,N,18778,20816,20817,20818,17759,45688,N,N,20822,20820, +20821,20819,14947,20823,19562,20068,45689,N,45690,N,45691,20824,45692,45693,N, +N,45694,N,16424,20825,15706,N,45857,20826,N,17276,20031,17760,N,45858,N,45859, +45860,45861,N,45862,21061,N,45863,N,N,20827,29733,13893,45864,N,20828,19294, +45865,N,N,45866,15720,17020,N,20830,18020,N,N,20831,45867,N,20832,13102,45868, +45869,45870,20833,13863,45871,17996,12666,15696,N,N,18465,20834,17761,45872, +45873,16207,20835,45874,18988,16474,13346,N,13353,20836,N,N,20838,N,N,14138, +45875,45876,20837,45877,45878,20083,45879,N,N,N,N,15721,N,N,N,N,45880,N,18493, +19020,N,20839,45881,19832,20840,N,N,N,20841,N,17790,45882,45883,20842,N,45884, +16425,14974,14196,20843,15177,14703,45885,N,N,N,N,N,N,17510,20845,45886,N, +16935,N,45887,14959,20846,20847,16688,N,20844,N,N,N,N,20849,45888,19254,45889, +45890,N,45891,14692,45892,N,20848,45893,45894,45895,N,14197,14942,18285,45896, +N,N,20852,20850,N,N,N,45897,18811,15978,20859,13156,20853,20851,16719,N,45898, +45899,45900,N,N,N,20855,N,20854,45901,N,45902,13124,N,45903,N,14176,20860, +20013,45904,N,45905,20856,N,N,N,20861,20858,45906,20857,45907,45908,45909, +45910,N,45911,20047,45912,N,N,14457,12867,N,N,20084,45913,45914,45915,45916,N, +15733,17752,14693,21026,21027,N,45917,45918,20069,N,N,20267,21029,45919,45920, +45921,14458,45922,45923,21028,45924,13103,N,45925,21030,N,19286,45926,17468, +45927,19750,45928,19033,N,N,45929,21031,N,45930,N,45931,28757,N,45932,17968, +45933,21032,13354,19507,N,45934,45935,15905,21033,19047,21037,45936,16426, +21034,13904,45937,21035,13355,45938,45939,45940,N,45941,N,N,N,45942,45943, +14126,21038,45944,21039,45945,45946,21040,21041,15451,N,N,N,14459,19550,45947, +19560,18039,45948,N,19057,21042,N,21043,N,45949,45950,46113,21045,N,21047, +21046,46114,N,46115,N,21048,12861,19276,46116,14972,21049,46117,46118,16729, +46119,46120,15906,13865,N,21050,N,46121,N,46122,46123,46124,18523,46125,46126, +46127,N,21051,46128,21052,46129,21053,N,46130,N,N,21054,18724,13928,12389, +46131,46132,46133,17983,21055,15677,46134,16489,N,21057,21056,15907,14433, +21059,18494,46136,46135,21060,N,N,N,18524,16948,17006,13864,N,N,18030,17201, +46137,18286,46138,19278,N,21062,N,16490,46139,N,46140,N,46141,14133,N,N,21063, +N,N,46142,46143,21064,12588,12405,13421,46144,16936,13649,19825,N,21067,12855, +46145,N,21066,N,N,46146,13866,N,N,21068,46147,19569,N,N,46148,46149,N,N,N,N,N, +46150,N,N,N,N,46151,46152,N,21069,N,20050,46153,14460,N,N,46154,N,14390,21070, +46155,N,N,46156,21072,21071,N,16223,12601,46157,46158,N,12638,21073,46159, +21074,N,46160,14391,46161,46162,21075,46163,46164,N,46165,13678,N,46166,N,N, +46167,N,15154,21076,N,46168,N,N,19316,14901,13658,19751,16720,18495,15485, +46169,N,N,46170,46171,15687,46172,15464,15477,N,15734,46173,18496,N,46174, +46175,21079,46176,12611,16721,14461,14405,13927,46177,46178,21083,17185,17022, +13867,15908,21084,21082,12868,16998,15416,15179,12582,N,46179,13168,14694, +15178,N,21085,21086,46180,13641,13126,N,N,N,14695,13640,17503,12581,17969, +19518,14625,19833,17735,14462,N,46181,N,N,N,N,N,N,46182,14127,N,21095,N,13923, +19274,46183,N,N,N,N,18525,46184,46185,21094,46186,13406,21089,21090,21092, +46187,N,46188,N,N,46189,46190,21093,N,13659,16225,N,18989,21091,21087,14435,N, +21088,N,20260,46191,46192,N,19058,46193,17512,14434,14704,N,N,46194,21096, +46195,N,18013,N,N,N,N,N,N,N,N,N,N,N,N,46196,21100,N,N,46197,N,46198,N,46199, +46200,15486,46201,15478,46202,N,46203,46204,N,21103,21101,N,19491,46205,21098, +21107,21102,N,N,N,21105,14406,19519,N,46206,21106,46369,N,46370,21108,46371, +21110,N,46372,46373,N,14960,20290,46374,21099,21097,21109,46375,21104,N,N, +46376,46377,N,N,N,N,N,46378,N,N,46379,N,46380,21112,N,21283,21114,46381,46382, +21118,46383,46384,21281,21115,46385,46386,21310,N,46387,14953,13105,N,N,N, +46388,21113,46389,46390,46391,21285,12406,21284,46392,12325,18762,21282,N, +21116,N,46393,21111,21117,14920,46394,N,N,46395,46396,N,N,N,N,N,N,N,N,N,21286, +N,N,N,N,N,N,N,46397,12407,21295,N,N,21287,21288,N,15909,19305,46398,N,46399, +21293,21292,46400,N,N,17711,N,N,N,46401,N,N,N,21294,N,46402,21291,46403,46404, +46405,46406,N,N,12596,46407,14902,16176,46408,46409,N,N,46410,46411,46412, +21289,17762,N,N,N,21290,46413,12322,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +46414,46415,N,N,21300,19747,N,15911,46416,21306,N,46417,46418,N,21305,21296,N, +46419,46420,46421,16963,N,21297,46422,N,N,17007,21302,15910,46423,N,46424, +46425,N,21299,46426,N,19556,46427,46428,N,14140,N,N,21303,21304,46429,N,46430, +46431,21301,21307,46432,N,46433,46434,N,21298,46435,N,46436,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,21313,21318,N,21314,46437,21309,46438,46439,21319,16689, +N,46440,21321,46441,14626,21311,17277,N,N,46442,46443,N,46444,46445,46446, +46447,N,N,46448,21315,21308,13357,N,13422,13157,21316,21312,N,N,N,46449,46450, +N,N,14198,21322,21320,16723,13642,13868,46451,21317,N,13940,N,46452,N,N,N, +12612,N,N,N,N,N,N,N,N,46453,N,46454,N,46455,21326,21324,46456,21543,N,46457,N, +46458,46459,N,46460,N,N,46461,46462,46625,21329,N,N,46626,46627,N,21323,46628, +21327,N,46629,21325,N,N,46630,15180,21328,N,N,N,N,46631,N,N,N,N,N,N,N,N,N,N,N, +N,46632,21331,N,21336,N,N,N,21334,21333,46633,46634,17202,N,46635,12869,46636, +N,N,46637,46638,46639,46640,46641,46642,N,21330,N,21332,15912,12595,46643,N, +21335,N,N,N,N,N,N,N,N,N,N,N,N,N,12894,N,N,46644,N,N,21346,46645,15996,21342, +46646,21340,46647,21341,46648,21343,46649,N,46650,46651,46652,N,46653,46654, +46655,12605,46656,46657,N,46658,N,N,46659,N,46660,16697,46661,21337,46662, +21338,N,N,N,46663,N,N,N,N,N,N,13178,N,N,46664,N,46665,46666,46667,46668,21345, +N,46669,N,13423,46670,21348,21344,21347,46671,N,46672,N,46673,46674,N,18990, +46675,N,N,18005,N,18488,N,N,N,N,N,21350,N,N,N,46676,46677,21349,13125,46678,N, +21351,46679,46680,N,N,21354,N,N,N,N,21353,46681,N,N,N,46682,46683,N,N,46684, +46685,46686,21352,N,18233,N,N,21355,46687,46688,46689,46690,N,46691,46692, +46693,21356,N,N,46694,N,46695,21358,N,21357,46696,N,N,N,N,21360,N,46697,N, +21363,21361,21359,21362,N,46698,N,N,21364,46699,46700,46701,46704,46705,21365, +46702,46703,21366,N,21367,N,N,N,21368,20805,46706,15484,15181,46707,46708, +12915,46709,12408,46710,N,17220,46711,46712,46713,46714,46715,N,N,46717,N, +46718,21369,N,14884,46716,12367,16222,N,N,46881,46882,N,21370,14407,N,N,14705, +N,21372,21371,46883,46884,19040,21373,N,N,46885,21537,21374,46886,21538,46887, +21539,N,14199,N,46888,12640,21540,N,46889,21542,N,21541,N,46890,46891,21544, +46892,N,17754,46893,N,46894,46895,46896,46897,21545,12341,14943,46898,46899,N, +46900,14141,46901,46902,17231,N,N,46903,46904,N,N,21546,21547,N,N,21549,N, +46905,46906,46907,21550,N,14948,N,N,46908,46909,13905,N,N,19255,N,46910,46911, +21548,21551,14913,14627,46912,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21555,46913,N,14885, +46914,17203,46915,46916,21552,17498,46917,N,46918,46919,46920,46921,46922,N, +46923,46924,46925,N,46926,N,46927,46928,46929,46930,N,46931,21556,N,46932, +16226,46933,N,N,N,N,21554,21557,N,14143,46934,N,N,N,N,N,N,21558,46935,46944,N, +46936,N,46937,46938,N,46939,46940,46941,46942,21559,46943,14628,13120,21561,N, +N,46945,46946,46947,21562,N,46948,N,N,N,21563,N,N,21560,N,N,N,N,46949,N,N,N,N, +46950,N,N,21553,N,N,21564,N,N,21565,46951,46952,N,N,19300,46953,N,15979,46954, +N,N,21567,21568,21566,46955,21570,N,N,N,N,N,18232,46956,46957,12392,18774, +46974,N,21571,46958,N,46959,46960,N,46961,N,N,N,46962,N,N,46963,N,N,N,15997, +46964,46965,15417,46966,18269,13424,N,14955,46967,46968,46969,19289,N,17970, +46970,46971,14200,16975,N,46972,46973,21569,21572,47137,47138,N,N,N,N,N,N,N, +16964,N,N,N,21573,N,47139,N,21574,47140,47141,47142,21576,N,N,17513,N,47143, +47144,N,N,13358,N,N,47145,N,29729,12641,19059,47146,N,15980,17736,N,N,N,47147, +14950,N,N,21582,N,47148,19005,20061,N,N,N,N,N,N,N,47149,12916,21578,47150, +47151,N,47152,47153,16698,21581,N,17763,47154,N,17737,17764,18489,17485,N,N,N, +14921,47155,N,47156,21577,N,47157,N,N,47158,47159,12662,N,17718,N,N,N,N,21579, +N,21575,N,N,16208,N,N,47160,21583,N,N,47161,N,15694,47162,47163,47164,N,13869, +N,21584,N,47165,47166,47167,47168,N,47169,47170,N,47171,47172,N,N,19048,47173, +N,47174,16765,N,N,N,N,17478,47175,N,21586,47176,47177,47178,N,N,N,47179,N, +19279,47180,N,21587,N,N,21592,N,N,47181,47182,18991,N,N,N,N,21591,21585,21588, +21590,47184,N,14886,N,N,19017,47185,N,47183,21593,N,17221,47186,N,12917,N, +15981,47187,47188,N,47189,21595,47190,21594,47191,14696,47192,21596,21598, +21597,47193,N,21600,47194,21589,21602,N,47195,47196,N,21601,21599,N,N,N,47197, +N,15182,16209,N,16724,21603,16444,12397,18276,47198,N,N,N,17499,N,21605,21604, +21606,21607,21608,21609,N,N,47199,47200,N,N,19025,21610,47201,47202,N,N,12870, +21611,N,47203,47204,47205,19772,13104,N,21065,15688,16959,21612,19563,47207,N, +N,N,47208,19508,47209,47210,21614,N,16999,47211,17719,16960,18775,21615,21616, +12667,47212,47213,15418,21617,47214,N,47215,47216,12368,21618,N,N,N,N,N,21619, +47217,N,N,N,47218,12642,N,47219,13425,18016,19060,N,N,N,N,21623,16725,21622, +14144,47220,47221,19291,21621,N,17765,21625,47222,21624,47223,N,47224,47225, +47226,21627,47227,21626,47228,N,12668,N,21628,15913,21630,17189,47229,21629, +47230,18995,47393,N,N,47394,15735,17755,47395,47396,N,21793,47397,N,47398, +47399,14629,N,N,N,21794,18209,18526,19537,N,N,N,N,N,18213,47400,47401,21803, +47402,N,N,N,47403,13624,N,47404,19781,47405,N,19503,N,22060,N,21795,N,47406,N, +N,N,21798,47407,16965,N,47408,19256,N,N,N,17738,47409,47410,47411,47412,N, +21799,47413,N,N,N,47414,N,19301,47415,14922,47416,N,15914,N,N,47417,N,47418, +47419,N,21800,N,47420,15184,47421,15183,N,47422,N,N,12345,14408,47423,16427, +12369,N,N,N,N,21804,21805,N,21802,47424,47425,47426,N,N,N,47427,47428,12600, +13359,47429,21801,N,19525,18737,N,N,47430,47431,N,47432,47433,N,47434,N,12328, +47435,N,N,N,12409,N,N,N,15185,47436,12370,N,12323,47437,N,N,N,N,21810,N,N, +47438,47439,47440,N,N,21808,47441,47442,N,N,N,N,19516,N,21811,N,21809,N,47443, +21807,16177,N,N,47444,47445,21806,N,47446,47447,19034,47448,N,N,47449,N,14436, +47450,N,N,N,N,21815,21816,N,N,N,N,N,15915,N,N,N,21812,20268,N,N,47451,47452, +18252,47453,47454,21814,N,N,47455,N,N,N,47456,N,N,N,N,47457,N,N,N,N,14887,N,N, +N,47458,N,N,N,21817,47459,N,47460,18776,47461,N,N,21818,N,21813,47462,N,N,N,N, +N,N,N,N,N,47463,N,N,47464,47465,N,N,47466,19515,N,N,N,N,N,N,N,N,N,N,N,47467,N, +N,N,N,47468,N,18270,47469,N,N,47470,N,N,47471,21819,18738,47472,N,47473,47474, +47475,N,47476,N,N,N,N,47477,N,N,N,N,47478,N,N,N,N,47479,47480,47481,N,47482,N, +N,47483,N,47484,47485,21820,21824,21821,47486,N,12871,21823,N,47649,N,47650,N, +47651,15419,N,21822,14201,N,N,47652,21836,N,N,N,N,N,21829,21826,N,N,47653,N, +47654,N,N,N,47655,17252,N,21825,N,47656,21827,N,N,21828,47657,N,N,N,47658,N,N, +N,N,N,N,47659,47660,N,N,N,21830,21831,N,47661,47662,47663,N,N,N,N,N,N,47664, +13426,N,21833,21832,N,N,N,N,N,N,N,N,N,21834,47665,N,47667,N,47668,N,47669,N,N, +N,47670,15982,N,N,47671,N,N,N,N,21837,N,17500,47672,N,N,12613,N,21835,N,47666, +N,21838,N,47673,N,N,N,N,N,21839,N,21842,47674,N,21840,N,21841,N,N,N,N,N,47675, +47676,N,N,N,15186,21843,47677,N,14630,21844,47678,15226,16952,N,21845,21846, +15194,14631,47679,19538,N,N,N,13608,14409,21847,13144,N,47680,21848,N,16953,N, +N,47681,47682,21849,22051,N,21850,N,21851,N,N,21852,N,21854,N,47683,47684, +47685,47686,21855,47687,N,21856,47688,17008,47689,12583,15465,12354,47690, +16727,13360,15413,47691,14632,47692,47693,N,47694,47695,17766,47696,15649, +13361,17256,17514,12344,13625,19061,N,15426,N,N,13650,16491,15420,19752,21857, +N,47697,47698,N,N,47699,47700,13660,47701,14923,47702,47703,13106,12643,15916, +12872,47704,21858,19782,47705,N,47706,N,N,15689,47707,47708,15460,21859,13427, +18002,19497,21860,N,21861,N,N,18777,47709,N,47710,21863,N,13352,13943,21862,N, +47711,47712,47713,47714,47715,13362,N,16178,21867,15137,47716,12873,21866,N, +21864,21868,21865,18219,23629,16179,N,21869,N,N,20032,47717,21870,47718,N, +21872,47719,17278,21871,N,16419,N,15227,N,N,47720,16976,15479,18805,16492,N, +15437,21873,15917,21874,21875,12371,16954,16210,47721,21876,17971,15918,N, +15919,N,21877,N,N,16493,47722,N,N,15920,N,N,N,47723,47724,21878,N,21879,47725, +19552,N,47726,N,21880,47727,N,47728,47729,13894,47730,N,47731,15650,47732,N,N, +47733,47734,N,21881,21882,15452,16172,18036,16212,18552,18210,13897,21883,N,N, +N,13679,21884,N,13950,N,17999,12848,N,15187,21885,22050,22049,13949,N,21886,N, +17720,N,N,N,47735,47736,N,47737,N,16944,N,17739,15432,47738,47739,16728,19834, +N,47740,47741,47742,N,N,22052,47905,22053,18006,47906,15155,N,N,47907,47908, +22055,N,N,22056,47909,47910,47911,47912,N,N,N,N,N,N,N,N,N,47913,47914,N,47915, +N,22057,N,N,47916,13428,22058,47917,N,22059,N,N,N,N,N,N,N,N,47918,N,47919, +47920,12844,47921,47922,N,N,47923,N,16699,13412,47924,22061,19496,N,N,N,N, +16978,47925,13145,47926,47927,22063,22065,13407,N,47928,22062,22064,N,22067,N, +N,N,N,N,N,22066,N,22068,N,47929,N,47930,N,N,N,N,N,N,47931,N,N,N,N,47933,N, +22069,N,N,N,47932,N,N,17981,13870,N,N,N,N,N,N,12901,22070,22075,N,N,22073, +47934,19063,19062,47935,47936,N,47937,N,17767,N,N,N,22072,15700,N,22071,47938, +N,N,N,N,47939,16242,N,N,N,22076,N,47940,14954,N,N,22082,47941,N,22083,22077, +13107,22078,22087,22086,22085,22081,N,N,N,22080,N,N,22084,47943,47944,N,47945, +47946,N,19064,N,47942,N,N,N,N,N,47947,N,N,47948,N,N,N,N,47949,N,N,N,47950,N, +47951,N,N,47952,47953,N,N,47954,N,47955,N,47959,22091,22088,N,22090,N,19826, +47957,22089,N,N,47956,N,N,N,47958,N,N,22079,N,N,47960,47961,47962,47963,N, +47964,N,N,N,N,16243,47965,N,22092,47966,N,14903,47967,N,N,22093,N,N,22094,N,N, +47968,47969,N,N,N,47970,47971,N,47972,22097,47973,22096,N,N,22095,47974,N, +47975,17768,22074,N,N,N,22103,N,47976,47977,47978,47979,N,N,N,47980,N,47981,N, +22099,N,47982,47983,N,22098,N,N,N,N,47984,N,N,N,47985,22100,N,22101,N,47986,N, +58996,N,47987,N,N,22104,47988,47989,20070,N,22105,22102,N,N,N,N,N,47990,N,N,N, +47991,N,22106,N,47992,13408,22107,47994,N,47993,N,22109,22108,N,N,22110,N, +47995,47996,N,22111,N,16494,15651,N,47997,15716,N,16739,47998,14633,14904, +14634,13680,48161,N,22112,N,N,14905,N,N,14410,22113,19494,18243,22114,N,14635, +48162,48163,N,13356,N,17191,13906,48164,N,15188,18779,N,N,18497,48165,N,N,N, +22115,13429,48166,N,N,N,22118,48167,N,48168,48169,17441,N,48170,22117,22116, +22119,N,17515,N,48171,48172,N,N,N,N,16227,N,N,48174,N,N,15189,N,16458,48173, +16979,13602,N,48175,17442,N,48176,22120,22121,15983,N,N,N,N,19257,48177,N, +22124,N,N,22123,22122,18813,N,22131,N,48180,N,48178,19290,N,22125,N,48179, +48181,N,N,22127,19307,48182,22126,48183,N,N,48184,48185,N,48186,22128,N,18472, +22129,19006,22130,N,N,N,48187,N,48188,48189,48190,48191,48192,N,48193,N,13363, +19007,18223,22132,22133,N,14636,13364,22134,14392,19780,19753,13430,22136, +48194,17443,N,14637,15921,N,N,18527,N,N,15922,48195,N,N,48196,15736,N,N,N,N,N, +17516,19065,17721,N,N,14638,N,18780,N,N,N,22137,N,48197,N,48198,48199,17753, +14914,48200,N,48201,14411,48202,17517,N,N,N,48203,N,48204,N,12355,15726,14639, +19783,N,N,N,N,48205,48206,48207,N,22138,22139,18257,N,N,48208,N,22140,20087, +20269,48210,48209,N,48211,22142,22141,48212,48213,13127,48214,48215,22305,N,N, +N,22308,22309,48216,22307,48217,18752,15923,22311,22310,22306,N,48218,N,N, +22312,22313,N,48219,22314,N,N,N,22317,22315,N,22316,22318,N,12644,17518,22319, +N,14202,12918,18230,N,22320,18043,19035,48220,22321,20270,N,48221,48222,48223, +22322,19008,22325,20513,20529,48224,15408,18037,22326,N,13661,17444,12410, +22327,18982,14640,48225,N,17232,48226,48227,N,17519,N,48228,48229,48230,48231, +19567,14393,14412,48232,22328,N,48233,48234,22329,48235,22335,48236,15461,N,N, +48237,17445,48238,13871,22330,N,N,48239,18731,48240,17222,48241,48242,22331,N, +N,48243,48244,N,48245,22332,N,13872,N,22333,48246,22334,N,48247,22336,N,17782, +48248,N,22337,22338,48249,22339,N,48250,22324,22323,N,N,48251,22340,14145, +48252,48253,N,18727,48254,N,14924,18743,17446,18763,22341,N,48417,15924,12614, +48418,22342,48419,48420,N,22343,48421,19570,48422,N,18528,48423,48424,22346, +12669,16428,22345,22344,14146,16980,N,22350,22348,48425,22347,20007,14437, +48426,N,48427,15737,22349,17740,15678,N,N,48428,17984,22353,22352,N,N,48429, +48430,22351,N,22354,14438,48431,N,48434,N,N,48432,22355,18812,15707,48433, +48435,22356,18553,48436,48437,48438,N,17985,17447,N,N,N,48439,17712,N,N,22357, +13611,N,N,N,N,N,16180,48440,18732,N,48441,48442,48443,N,48444,13431,18214,N,N, +48445,48446,48447,48448,48449,N,22358,15190,19258,19259,N,N,12670,22363,48450, +N,17257,48451,48452,N,22360,N,N,N,48453,48454,48455,12919,48456,48457,48458, +48459,22573,22362,48460,48461,N,18224,48462,N,22361,N,48463,22359,48464,14714, +N,22365,48465,N,N,48466,N,N,48467,22371,22377,22369,N,17756,48468,48469,22374, +18781,48470,48471,22368,48472,22373,20071,15191,N,48473,16981,22366,N,N,48474, +13662,22376,16429,12645,22370,12920,22375,N,48475,N,13873,N,22372,N,48476,N, +48477,N,N,N,N,22378,N,N,N,N,N,48478,22380,22390,22388,N,N,22385,48479,48480, +48481,22384,20088,48482,22386,N,N,13874,48483,14641,N,48484,15738,48485,48486, +N,22393,22379,N,N,48487,N,22383,22367,48488,12922,22387,22389,17233,N,48489, +14888,12856,22381,22392,22391,13875,N,16937,13158,48490,N,N,N,14147,N,22382,N, +N,N,N,N,N,48491,48492,N,22394,48493,22397,22561,N,48494,N,48495,15421,48496, +22567,17520,22395,48497,N,N,48498,22565,48499,12921,48500,22563,22564,48501,N, +22398,22562,N,48502,48503,14439,19754,N,48504,13365,48505,48506,12633,22566, +48507,18234,12333,N,N,N,N,N,48508,48509,18529,22364,22572,22576,19557,48510, +22569,N,N,48673,17769,22574,48674,N,N,N,48675,N,48676,15984,22575,18007,48677, +48678,48679,48680,N,N,48681,48682,N,20295,N,22571,48683,48684,N,N,22577,48685, +14715,48686,16459,48687,48688,12372,22570,22568,48689,16730,N,48690,N,22396, +15156,N,N,N,N,N,N,N,16966,22589,48691,16731,22584,48692,22581,22582,48693, +15462,22585,22588,48694,48695,22583,15653,48696,22586,N,N,22580,48697,19580, +19579,48698,N,48699,22590,22591,12373,48700,48701,48702,48703,48704,22579, +48705,48706,N,48707,13938,12326,48708,N,48709,13366,N,22587,48710,N,N,N,N, +22595,22594,N,48711,48712,22599,N,N,N,48713,48714,N,N,22600,48715,48716,48717, +N,48718,N,N,22598,22601,22593,22597,N,48719,22602,N,22603,48720,48721,22592, +15228,48722,22596,16982,14642,22578,16181,N,N,N,N,22616,N,19049,N,N,22606, +22607,22608,N,N,22615,48723,22614,48724,N,19325,13367,N,22612,N,14149,13108,N, +N,22609,48725,N,20024,22611,12374,22613,48726,22604,22610,22617,14148,22605, +48727,N,N,48728,48729,N,19805,48730,48731,48732,19755,48733,48734,N,N,22620,N, +N,22624,48735,N,48736,16766,N,20089,22625,48737,48738,22622,N,22619,48739, +48740,22618,22623,N,48741,48742,N,48743,48744,N,N,N,18992,48745,N,17972,48746, +14150,48747,22626,22621,48748,22627,N,N,N,14203,N,N,N,12849,N,48749,48750, +22635,N,48751,N,13368,N,48752,48753,48754,22633,N,N,22634,14889,22632,22630, +22629,22636,22628,22638,48755,48756,12923,N,N,N,N,48757,N,N,N,N,N,N,48758, +48759,48760,48761,N,48762,48763,22640,N,48766,22639,48764,N,48765,N,N,48929, +48930,N,48931,N,N,17448,N,22643,N,22641,22631,14204,N,22642,N,22646,22645, +22647,22644,22648,48932,N,48933,48934,N,N,48935,22649,22650,19050,N,22652, +22651,15679,N,16430,12902,12924,48936,22653,48937,12351,N,N,N,16460,22654, +48938,27715,22817,14177,48939,22818,48940,48941,N,N,16495,48942,N,48943,22819, +48944,N,N,22820,13626,22821,N,22822,22823,16983,N,N,N,14413,48945,N,19553,N, +48946,N,19260,15722,22824,48947,48948,48949,N,48950,16496,28221,18530,N,15466, +48951,14925,22825,N,48952,48953,48954,16967,48955,18983,48956,N,17009,N,48957, +22828,48958,N,22826,N,22829,N,N,22827,48959,N,N,N,22830,N,N,N,N,48960,18993, +48961,N,12343,N,48962,N,N,18782,N,N,18531,48963,N,22831,48964,22834,15925, +13627,N,22832,22839,15926,N,N,N,N,22833,18244,N,N,48965,48966,48967,48968, +19806,22835,22836,22840,17770,22837,14643,16478,N,N,22854,18484,N,17010,N,N,N, +N,N,N,N,48969,N,48970,N,N,18532,23085,N,N,N,N,19066,N,48971,N,17521,48972, +48973,N,19317,48974,22843,12833,17258,48975,48976,N,N,22852,N,48977,17204, +22846,22853,22848,22855,22851,N,22850,18287,48978,22844,12925,22842,13681, +17011,22838,48979,48980,22841,14644,16475,48981,15927,22849,18258,N,N,13682, +13128,N,N,N,N,N,N,N,N,48982,N,13159,16161,22857,22862,N,22858,48983,14205, +48984,22863,15138,14697,N,N,N,N,48985,48986,15654,22845,15229,22860,48987, +48988,N,N,15192,22861,12356,48989,48990,22856,48991,N,N,48992,17449,N,48993,N, +N,48994,N,48995,13683,N,N,N,N,N,13876,N,N,N,N,N,N,N,22859,12327,48996,48997, +14915,N,48998,N,16182,N,N,N,N,N,48999,49000,N,N,49001,17522,N,49002,18516, +22865,16734,N,49003,49004,49005,49006,N,49007,N,N,16938,49008,49009,15147, +22866,49010,22868,22864,N,49011,49012,49013,19041,N,17469,49014,N,N,49015, +16732,N,N,N,N,N,N,N,N,49016,49017,19067,15438,22880,N,22879,49018,49019,16248, +N,N,49020,14206,N,49021,49022,22873,15929,49185,N,18024,18225,49186,49187,N, +49188,22871,N,49189,16733,49190,N,N,49191,15480,22876,49192,N,15928,N,22870, +22875,49193,N,18259,N,49194,49195,22869,N,14113,49196,49197,13149,N,N,49198, +22877,20011,14926,17205,22874,49199,16476,49200,14645,16228,12646,16700,22872, +13637,49201,49202,49203,N,N,14151,N,17487,22878,N,N,N,N,N,16735,N,49204,22881, +N,22883,49205,N,16951,22889,49206,22884,N,49207,22886,N,N,N,N,49208,18753, +17523,49209,22887,49210,49211,49212,19756,N,N,N,19784,13369,49213,N,N,N,49214, +12334,N,22885,N,49215,N,N,N,22882,49216,N,49217,N,13432,N,N,N,49218,49219, +12647,49220,22888,N,49221,49222,19785,22892,N,N,49223,49224,N,N,16955,N,22899, +49225,N,49226,22893,49227,N,22890,22897,49228,N,N,N,22867,N,49229,N,49230,N, +49231,N,49232,49233,22894,N,22898,49234,49235,N,18498,17771,N,49236,49237,N,N, +N,22891,49238,22895,N,N,N,14152,N,N,49239,14961,49240,N,N,16477,N,N,N,N,N,N,N, +N,49241,N,N,22903,49242,N,49243,49244,49245,49246,N,N,N,17702,N,49247,49248, +49249,49250,N,49251,49252,49253,N,49254,N,N,N,22900,N,19296,N,N,N,49255,N, +22901,N,N,N,49256,49257,N,22902,N,19534,N,16418,49258,N,49259,N,N,N,N,N,14178, +N,49260,N,49261,22909,N,N,N,N,N,N,49262,49263,49264,15157,22906,N,22905,N,N, +49265,49266,18226,49267,N,49268,17973,49269,N,49270,N,49271,17713,22907,49272, +N,49273,22908,N,18799,49274,18245,15139,N,16497,N,19280,49275,N,N,N,N,N,13129, +N,23077,22910,49276,49277,49278,N,19786,23079,N,49441,23075,N,23076,N,49442, +49443,49444,49445,16736,49446,N,49447,49448,23074,N,22847,49449,N,49450,23078, +N,23073,N,N,N,N,N,23083,23084,17703,23086,49451,49452,15140,23081,N,49453, +49454,N,13628,49455,N,23087,49456,23080,23091,N,23090,49457,23089,49458,N,N, +23092,49459,N,23094,15985,49460,23093,49461,N,N,49462,23097,N,N,49463,49464, +49465,N,N,N,N,49466,N,N,N,49467,49468,N,49469,N,23095,49470,N,49471,23096, +22896,49472,49473,N,N,49474,23099,23098,N,49475,N,N,49476,22904,23100,23088,N, +49477,15193,N,49478,N,N,23101,23102,23104,23103,23105,12926,49479,14646,49480, +49481,19068,16431,N,N,N,49482,N,14414,N,49483,23107,49484,N,N,N,23110,N,18770, +49485,13663,49486,N,49487,23109,23108,18260,23111,13877,N,N,N,23113,23112, +49488,49489,N,13370,15158,N,N,18008,49490,N,N,N,49491,14153,N,N,N,16244,N, +23114,N,16432,17704,N,18783,23115,N,49492,N,N,49493,N,N,N,49494,23116,23117,N, +49495,N,19000,21853,16454,49496,N,18764,N,14936,N,18533,18499,49497,N,N,49498, +N,17741,49499,20033,N,23119,15440,49500,N,23120,49501,12342,N,49502,13908, +16461,49503,18784,N,N,N,23121,15170,17223,49504,15195,16183,N,49505,49506, +49507,N,N,23122,N,19069,N,N,12663,15196,N,49508,N,23125,49509,23123,23126, +20025,23124,N,49510,49511,N,16507,23127,N,49512,16946,49513,N,23128,N,49514,N, +49515,13434,49516,23130,N,23129,N,N,N,49517,23131,23132,13435,N,N,18044,17206, +13676,15197,16737,N,N,15708,12336,N,N,49518,23133,49519,N,49520,49521,N,N,N, +49522,12834,23137,N,N,49523,49524,49525,N,14647,23136,49526,N,14891,15930, +49527,49528,23135,N,15931,49529,19520,14890,N,49530,49531,12375,16462,49532, +49533,N,N,N,N,N,23142,49534,49697,16433,12615,49698,49699,49700,49701,15701, +49702,19302,14962,49703,49704,49705,49706,15932,49707,16423,49708,49709,N, +49710,23141,23139,23140,49712,N,49711,N,N,17259,N,N,23334,49713,23146,15230, +14648,23144,49714,49715,N,N,23145,49716,16184,49717,N,49719,23143,N,49718, +15151,N,N,N,N,49720,49721,49722,N,49723,49724,23148,23147,23152,49725,49726, +23153,N,23149,N,13090,23150,23151,18517,49728,49729,49730,N,18785,14154,23154, +N,N,49732,16434,49733,15933,49735,49736,49737,17234,49738,49740,N,49731,49734, +49739,13895,N,23155,23159,N,N,12875,23156,23158,N,49741,49742,49743,23157,N, +49744,15723,49745,N,N,N,17224,12357,23160,49746,49747,49748,49749,23161,N, +49750,49751,N,17450,N,49752,N,20081,N,N,N,N,15171,N,49753,19051,N,N,49754, +49755,N,19261,49756,N,N,23330,23163,N,49757,23166,N,23165,49758,49759,23162, +49760,49761,23329,N,N,18014,49762,23164,N,N,49763,N,49764,49765,N,N,N,N,49766, +N,23331,N,N,15724,23332,49767,19787,18296,N,49768,23333,N,N,N,N,N,23335,N, +49769,23336,N,49770,49771,N,49772,N,23337,N,13898,12616,14649,23338,N,23339, +15729,16738,49773,49727,21080,16702,16701,16984,14919,N,N,20594,N,49774,N, +49775,14190,19757,N,19070,N,18814,49776,23340,N,N,N,49777,14963,17471,23341, +20271,N,49778,N,19262,49779,17451,23342,13436,49780,N,49781,N,N,N,23343,23344, +19546,N,19492,19318,19292,15141,23346,N,N,15467,N,49782,19281,N,23348,23351, +23350,N,13433,N,N,13664,49783,23347,N,23349,N,N,N,49784,23352,49785,49786, +16249,N,N,49787,N,19835,12361,14944,16956,N,15453,49788,49789,15987,N,N,23355, +N,N,17742,49790,23353,16939,23354,15986,19549,23356,23357,19816,49953,N,N,N, +23362,N,49954,14650,49955,18261,23359,17772,23134,23138,49956,13647,49957, +18247,N,N,N,49958,23361,N,15934,18500,N,49959,N,N,49960,23367,N,18554,N,23358, +N,23364,23363,N,49961,49962,16463,49963,N,49964,N,19309,49965,20051,49966, +49967,19303,49968,12876,15198,N,N,20296,23366,16245,N,N,N,23365,N,N,23360,N,N, +N,N,N,14415,49969,49970,49971,23372,23370,49972,12877,23368,23374,23380,N, +49973,49974,49975,N,N,49977,16968,49978,49979,19009,49980,23382,N,49981,49982, +18722,N,N,N,23381,18288,19263,13371,49983,16503,15680,N,N,49984,17491,49985, +19758,N,49986,23377,23376,N,N,49987,23378,N,23375,N,49988,23383,N,23373,N,N, +23371,N,23379,23369,49989,17260,49990,19576,15430,14964,49991,49992,N,49976,N, +14906,N,N,19311,13121,17486,17994,12617,N,N,N,N,N,N,N,N,N,N,N,N,N,N,16498, +49994,N,16436,14122,N,49995,N,N,N,49996,23385,49997,N,14651,13180,N,N,N,N, +49999,49998,23387,13172,23393,50000,50001,N,50002,50003,50004,23390,50005, +16499,N,N,N,13131,14892,N,50006,13130,14927,N,50007,23388,14181,14155,17773, +50008,50009,23386,N,12358,N,50010,N,50011,23389,23391,N,13901,14124,49993, +13372,13643,50012,N,50013,50014,23394,N,50015,14969,19313,N,15159,N,N,N,23395, +N,N,N,18736,N,N,N,50016,N,N,50017,50018,50019,50020,50021,N,23407,50022,12851, +23396,N,50023,50024,50025,50026,N,23413,23397,N,20034,50027,23404,50028,18271, +50029,N,50030,N,N,N,N,23412,N,23399,N,N,N,12340,23401,N,50031,14652,50032,N, +50033,23403,50034,23402,N,23398,23409,50035,15935,50036,N,50037,21613,14440, +19836,50038,50039,N,N,23400,50040,17524,13091,14893,50041,23392,N,23408,13153, +N,N,23406,23410,50042,17774,N,N,N,N,N,N,N,13438,50043,23602,N,50044,19529, +23415,13437,50045,23422,N,50046,50209,50210,19264,50211,23585,23587,50212, +23591,23417,50213,17194,N,50214,50215,N,17775,23595,23420,N,23592,N,50216,N, +23586,50217,N,50218,50219,50220,50221,16185,23596,50222,50223,16435,N,N,50224, +50225,N,N,23594,13373,50226,50227,50228,20304,23414,N,N,23590,12376,50229,N, +23416,50230,50231,19514,23421,16162,17479,23411,50232,50233,23589,50234,N,N, +50235,50236,N,16250,23599,13169,14369,N,N,N,N,23601,23418,23600,N,23593,23419, +N,23597,N,23598,N,N,N,N,N,23615,50237,N,50238,17998,50239,23588,N,50240,23611, +N,50241,N,23613,N,17496,N,N,50242,N,N,50243,N,N,N,50244,19788,N,N,N,50245,N,N, +N,N,18806,23608,16970,N,50246,N,23614,16703,50247,23605,23618,23617,N,18031, +23616,18026,50248,50249,50250,50251,N,50252,50253,23620,23607,50254,13896, +23610,15709,50255,50256,50257,18272,23612,13899,N,23604,23606,23603,50258, +50259,20272,13146,23609,50260,50261,23619,13109,N,N,N,N,N,N,N,14951,N,N,50262, +12637,N,N,23636,50263,N,20273,23639,50264,N,50265,N,N,16186,23638,N,N,N,23637, +50266,N,N,N,50267,50268,23634,50269,N,N,50270,N,50271,23622,50272,N,23651, +23621,N,23640,N,N,50273,50274,N,50275,23632,50276,N,23627,23624,N,23625,N, +23633,N,50277,N,29730,50278,N,23630,14653,17480,16740,23628,N,23623,50279,N, +23626,N,N,50280,50281,19789,19306,N,N,N,23631,23641,N,N,N,50282,N,N,50283,N, +23649,23642,N,N,23655,N,23653,50284,50285,N,50286,23648,50287,N,50288,N,N,N, +23647,N,17488,N,16741,50289,23645,50290,50291,23643,50292,N,23650,N,N,N,N, +23656,18549,23662,N,N,50293,N,50294,23657,23660,23654,50295,N,17268,N,18744, +50296,23644,N,50297,23652,15936,50298,19535,23672,23659,50299,N,N,N,50300, +14370,12835,13151,N,N,23635,N,50301,N,50302,N,50465,15937,23664,50466,23671, +15481,13170,50467,N,17198,50468,50469,N,N,N,N,23661,50470,50471,23666,23670, +50472,50473,13878,N,N,50474,N,50475,50476,50477,N,N,50478,50479,N,13644,23668, +N,50480,N,N,N,13601,N,17995,23667,N,50481,N,23669,50482,N,N,50483,N,N,N,N,N,N, +50484,23663,50485,N,N,N,N,23665,N,N,N,N,N,50486,13152,17225,50487,N,50488, +23676,N,50489,50490,N,50491,N,50492,N,23674,14441,N,23673,50493,N,N,N,N,N, +23841,N,N,N,50494,23384,50495,50496,50497,23675,N,23677,23678,N,50498,N,N,N,N, +23852,50499,23848,N,23405,50500,50501,50502,N,23847,50503,N,N,N,23846,N,N, +23843,N,50504,50505,50506,N,23658,23845,23844,N,N,50507,N,50509,50508,N,N, +50510,N,N,N,50511,23850,N,20262,50512,50513,50514,N,N,N,23853,13947,50515, +50516,23849,23851,N,N,N,N,50517,N,N,50518,18471,N,23854,N,50519,N,N,N,50520, +50521,50522,N,N,N,N,N,N,N,23858,23855,50523,50524,50525,50526,19827,23856, +50527,50528,N,50529,23646,N,N,N,N,50530,50531,50532,23859,N,N,N,23860,50533,N, +N,N,50534,N,12597,50535,23862,14183,15393,N,13909,50536,N,N,12836,50537,N,N, +50538,50539,N,N,50540,N,N,19807,N,N,50541,50542,23864,23863,23866,13629,50543, +N,13910,13374,50544,N,N,N,23869,N,N,50545,23868,N,23870,50546,N,12878,50547, +17207,N,23871,N,50548,13375,23873,N,50549,N,50550,23872,N,23874,N,50551,N, +23875,50552,23876,15199,16437,14881,N,18800,50553,N,19042,20292,50554,N,N, +50555,15221,50556,N,N,14928,20082,50557,N,N,23877,23878,N,15200,N,50558,50721, +23879,23880,N,50722,23882,23881,50723,19288,N,N,15710,15468,15172,N,23883,N,N, +N,N,N,N,N,23885,16163,50724,23884,N,N,50725,N,N,23886,50726,50727,N,50728, +50729,23887,N,N,N,50730,50731,23888,23889,50732,50733,50734,23890,50735,23892, +23891,23893,12837,17226,N,23894,50736,50737,15142,13132,23895,50738,50739, +17730,21580,N,N,50740,50741,13603,23896,N,N,50742,N,23897,50743,19052,19304,N, +N,N,17991,23898,18534,N,50744,N,18555,N,50745,19539,N,N,N,23899,N,50746,N, +50747,N,N,50748,50749,N,N,N,23901,23900,N,50750,23903,N,50751,N,23902,N,N,N, +50752,N,50753,N,N,N,N,N,50754,50755,N,50756,50757,N,N,23905,50758,N,N,N,50759, +50760,15201,50761,19505,50762,23906,23907,N,N,13604,N,50763,N,23908,N,N,N, +50764,N,N,N,23910,23909,N,50765,50766,50767,N,N,N,50768,N,50769,N,N,N,N,50770, +16229,50771,50772,18745,12618,N,50773,50774,N,N,18501,50775,17525,15681,13665, +N,N,N,N,N,N,N,50776,50777,N,50778,18502,50779,15406,N,50780,N,50781,23912,N, +13376,N,50782,12664,50783,50784,18034,23911,14654,17235,N,23913,N,N,N,N,50998, +23921,N,23914,50785,N,50786,N,50787,16961,N,13666,23922,50788,N,50789,N,50790, +50791,14184,50792,N,13605,23920,N,N,23918,23915,19808,N,50793,50794,50795, +17472,50796,N,N,18009,23916,N,N,23924,N,23923,14115,50797,50798,12845,50799, +50800,14907,23917,23919,50801,N,N,50802,N,19287,17012,N,N,N,N,N,N,N,N,19319,N, +N,23932,N,50803,23933,50804,12879,50805,N,N,N,18984,19581,24097,15395,15938, +23928,23934,12648,N,13879,50806,N,23925,23930,50807,N,N,16500,18289,N,18535, +50808,N,50809,50810,50811,50812,23927,50813,19233,50814,23929,N,24100,50977, +24098,50978,23931,N,N,50979,19234,18248,13667,N,17701,N,50980,17261,50981, +24101,50982,50983,N,50984,24099,16985,23926,50985,12619,50986,50987,N,N,50988, +N,N,50989,19790,24112,N,50990,50991,N,50992,24111,50993,N,N,N,16502,N,24108, +50994,19820,N,N,17974,24102,N,N,N,N,N,17477,50995,50996,50997,12620,14655, +24105,N,N,50999,51000,N,51001,15655,24110,N,24109,24104,N,24107,51002,N,13160, +51003,24106,18249,51004,N,20014,N,N,15988,16501,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,51005,N,24118,24116,N,18765,N,51006,51007,N,51008,N,24113,24115,51009, +12602,51010,N,14656,20274,N,13117,N,18786,51011,51012,N,N,N,19809,N,N,13092, +16187,24117,N,N,51013,N,N,N,N,N,51014,N,N,24122,N,51015,15939,N,N,N,19760,N, +24119,N,N,51016,51017,24114,51018,24120,51019,51020,51021,20062,N,17779,17986, +N,N,N,N,N,N,N,N,N,N,N,N,N,51022,N,51023,N,N,13110,N,N,12629,N,51024,24126,N, +51025,24129,51026,N,N,20035,51027,N,51028,19812,N,N,N,51029,24136,24130,24127, +51030,N,51031,20052,24133,N,51032,51033,N,15690,24135,N,N,24140,51034,N,17777, +24138,N,51035,N,51036,24132,51037,51038,17208,51039,N,24139,51040,24128,N, +24134,51041,24141,12412,24131,N,24142,51042,51043,16188,N,15711,51044,18981, +51045,14894,N,24123,24137,17722,51046,51047,N,N,N,51048,16438,N,13161,14929, +15940,24125,15682,N,N,N,N,N,N,N,14156,N,24124,N,N,N,24146,15725,14394,N,24161, +51049,24155,13684,17743,51050,24150,24159,12335,12594,51051,N,12857,N,24152, +16940,24143,24145,14657,N,N,51052,N,N,N,51053,N,24162,51054,24157,51055,51056, +N,24149,N,N,N,N,24156,51057,51058,N,N,51059,51060,19499,51061,N,24154,24158, +51062,N,51063,51064,51065,51066,N,14416,51067,15941,N,N,17209,51068,51069, +51070,24148,N,N,51233,51234,N,N,N,19759,51235,N,N,24151,N,N,24144,17778,N,N, +24147,51236,N,N,24153,N,N,N,N,51237,N,51238,20305,15422,19326,N,24163,N,N,N,N, +N,N,N,N,N,18478,51239,N,24175,14395,N,N,51240,N,N,15712,N,24165,51241,N,N, +20015,14658,N,24178,51242,N,12398,N,N,24176,N,51243,N,N,24164,N,N,51244,51245, +24170,N,51246,24172,51247,N,N,19791,24167,N,N,17710,51248,N,24169,N,51249, +51250,51251,24177,51252,24171,19527,N,51253,51254,24166,51255,15394,24190, +51256,51257,51258,N,13162,N,24168,24173,24174,N,N,N,N,N,N,N,17004,16986,N,N,N, +N,N,N,N,N,N,N,N,N,51259,24182,51260,51261,24188,N,N,24186,N,17705,N,N,24355, +24183,51262,N,51263,N,51264,24184,24160,13689,18746,N,51265,N,15423,N,51266, +14711,51267,N,51268,51269,N,20275,N,24180,N,24354,12649,16742,51270,N,51271,N, +51272,51273,N,N,N,N,18297,N,13377,20090,N,N,51274,N,N,51275,51276,19489,17490, +51283,N,51277,51278,24187,24189,51279,N,N,51280,N,16690,N,N,51281,51282,N, +24353,24185,N,24179,N,N,N,13379,N,N,N,N,N,N,N,N,N,51284,N,51285,51286,51287, +14185,N,N,51288,24367,51289,51290,24362,16504,51291,51292,13155,N,51293,51294, +N,15713,N,24371,N,51295,N,N,N,51296,24364,17452,24361,17497,N,N,N,24396,N,N,N, +24358,N,24357,N,24366,51297,51298,N,24360,24359,24365,51299,16417,N,24356, +51300,51301,N,N,51302,51303,51304,24368,N,51305,24369,51306,51307,51308,N, +51309,13378,N,N,51310,N,N,N,N,51311,51312,24374,N,24373,24375,51313,51314, +51315,51316,N,24378,N,N,N,51317,51318,51319,17731,N,24372,N,51320,51321,N,N, +24376,N,N,51322,N,N,N,14179,17017,24370,18235,N,51323,24377,51324,51325,N, +51326,N,N,N,N,N,N,N,N,N,24382,24380,N,N,24383,N,51489,24386,N,N,51490,24379, +14698,18216,N,N,24121,N,N,N,51491,51492,N,19828,24381,N,24385,17013,51493, +24384,N,24363,N,51494,28521,N,N,51495,24389,N,51496,51497,24393,51498,24391,N, +N,N,51499,51500,51501,N,24387,N,24388,N,51502,N,24392,N,24390,N,N,N,18766,N, +51503,24398,N,24395,24394,N,24397,18004,24399,51504,N,N,51505,N,N,17269,17005, +N,N,N,N,16421,N,N,51506,24400,N,24402,N,51507,N,N,51508,N,51509,N,N,51510,N, +24401,N,N,N,N,51511,51512,N,N,N,51513,51514,51515,51516,24181,N,51521,N,N, +24403,N,N,51517,51518,N,N,18023,N,N,N,N,51519,51520,N,N,N,N,24404,51522,51523, +N,N,N,N,N,12880,51524,N,51525,17780,13093,N,N,N,N,51526,51527,N,13668,N,N,N, +15454,14930,51528,N,N,51529,N,N,N,51530,51531,N,N,20263,16230,N,N,N,12650,N,N, +N,24406,N,51532,51533,51534,51535,51536,24405,N,51537,N,N,N,N,N,N,N,N,51538,N, +N,N,N,N,N,51539,24409,17210,24412,24407,51540,51541,N,24411,51542,N,N,51543, +24410,17728,12377,N,N,N,N,N,N,N,N,N,N,N,N,N,20085,N,51544,24414,N,N,N,12584,N, +51545,N,51546,51547,51548,51549,N,51550,24416,N,N,51551,24415,N,24413,N,N,N,N, +51552,N,N,N,N,N,N,N,N,N,N,N,N,24408,N,N,N,N,N,N,N,19235,51553,N,N,24418,51554, +51555,51556,51557,51558,N,24417,N,51559,51560,N,N,51561,N,N,N,N,12651,N,N,N,N, +24420,18994,N,24419,N,51562,N,51563,19509,N,N,N,N,15943,N,N,N,N,51564,N,51565, +N,51566,51567,51568,N,N,N,N,16691,N,51569,N,N,N,15942,N,N,N,N,51570,N,N,N, +51571,51572,51573,N,20091,51574,51575,24426,N,16505,N,51576,N,51577,N,N,24422, +24427,51578,N,12652,51579,N,51580,N,51581,N,51582,N,24425,N,18273,24421,24424, +15944,51745,18513,N,N,24428,N,15441,N,N,N,N,N,N,N,N,N,N,51746,N,N,N,16506,N,N, +51747,N,N,N,24431,51748,N,51749,24423,N,14119,N,51750,N,N,24429,N,N,51751,N, +19792,24432,N,N,N,29734,51752,51753,N,N,N,15695,51754,N,51755,N,N,N,N,N,24433, +N,N,N,24434,N,N,51756,51757,18222,51758,51759,N,N,N,N,N,24436,51760,N,N,N, +24437,51761,51762,51763,N,18227,51764,N,N,N,17781,24439,N,51765,51766,N,24441, +N,20053,N,24438,51767,24440,12653,51768,24435,N,51769,51770,N,51771,N,N,21339, +24442,N,N,N,N,16743,15160,24444,N,N,N,N,24443,16164,21081,N,N,N,N,N,N,24445,N, +N,51772,24609,N,24430,24446,N,51773,24610,51774,N,N,N,N,N,18298,51775,51776, +51777,N,N,N,24611,N,N,24612,N,N,51778,N,N,N,51779,N,N,51780,24613,N,51781,N, +51782,N,N,N,N,51783,N,N,N,24614,N,17502,51784,24616,24615,N,51785,24617,N, +24618,N,51786,15455,18787,N,51787,51788,19564,24619,24620,16726,15396,24621, +24622,51789,51790,51791,N,51792,24623,19026,18503,N,N,24624,18263,N,51793, +51794,51795,N,17453,51796,N,51797,51798,N,24625,12903,51799,13677,51800,19526, +51801,19510,51802,12852,20276,51803,N,N,N,19282,51804,18986,N,51805,N,N,51806, +51807,N,51808,16439,N,24626,N,N,51809,51810,17987,N,51811,51812,14371,24627, +51813,14932,24629,24628,N,51814,N,N,24630,N,51815,N,N,N,51816,51817,N,N,N, +24631,51818,N,N,24632,N,N,N,N,51819,N,N,N,N,13630,N,24633,N,N,N,N,24634,51820, +N,N,N,14372,51821,51822,18504,N,51823,24636,N,51824,N,15989,N,N,24635,N,N,N,N, +51825,N,N,51826,13880,24637,24639,N,24638,51827,N,51828,N,N,51829,N,24640,N, +14417,N,24641,N,N,51830,51831,13929,51832,16704,N,14717,N,N,N,51833,24643, +24644,24642,N,N,51834,N,N,N,15469,N,N,17992,13881,N,N,N,N,N,51835,51836,N,N, +24646,17196,24645,51837,51838,20277,18274,52001,52002,N,52003,52004,N,52005,N, +N,24649,52006,N,52007,N,N,N,N,52008,52009,N,N,24651,24648,52010,52011,N,19540, +24650,24652,52012,20036,N,N,52013,N,52014,24656,N,52015,52016,24655,17270, +18221,52017,N,14373,24654,N,52018,52019,N,24653,52020,19761,19762,N,N,52021, +52022,N,52023,24657,12654,N,N,N,52024,14710,15202,N,N,N,N,N,N,N,52025,24658, +24659,52026,N,52027,N,N,N,52028,24661,52029,N,N,N,N,52030,52031,52032,52033,N, +N,15683,N,N,52034,52035,24663,52036,24662,52037,52038,N,52039,52040,24664, +52041,13133,N,N,24666,N,52042,24665,52043,24668,24667,52044,N,N,N,52045,52046, +N,52047,14396,52048,52049,20008,N,13900,N,12838,N,N,52050,N,52051,N,N,52052,N, +52053,13930,52054,52055,N,N,N,52056,N,52057,52058,52059,N,52060,N,N,52061, +52062,N,N,13409,52063,52064,N,52065,N,N,N,N,20072,24670,N,52066,N,52067,N, +52068,N,24672,52069,52070,N,52071,24673,N,12881,N,N,52072,52073,N,24669,52074, +15161,52075,52076,17473,24671,52077,N,N,52078,52079,N,N,52080,N,N,52081,N,N,N, +52082,24676,N,15470,52083,N,52084,N,24674,52085,52086,N,52087,14142,N,N,18505, +24675,N,N,24702,N,N,52088,52089,N,52090,24681,52091,52092,52093,N,52094,14397, +52257,52258,52259,N,13669,52260,24678,19837,52261,N,20016,52262,N,N,N,N,N,N, +52263,N,N,N,N,N,N,N,N,52264,52265,N,N,N,N,N,N,17014,N,52266,24680,52267,N, +52268,52269,52270,52271,52272,52273,52274,52275,52276,52277,24682,20054,13911, +18556,18250,N,N,52278,24683,N,N,N,N,24685,52279,24688,N,52280,52281,N,52282, +52283,N,N,N,52284,N,52285,N,N,N,52286,52287,N,N,24684,N,52288,N,24687,14442, +12621,24689,52289,16240,24686,20060,N,52290,24692,29732,N,52291,52292,52293, +24690,24693,52294,N,52295,52296,24679,24691,52297,52298,14908,N,N,24694,N,N,N, +N,N,N,N,24695,N,52299,52300,N,19838,N,52301,52302,52303,N,52304,N,24696,N,N,N, +52305,52306,52307,52308,N,N,N,N,N,52309,52310,52311,N,52312,N,24697,52313, +52314,52315,24677,52316,N,N,52317,24698,52318,52319,52320,52321,N,N,52322, +52323,13380,52324,52325,N,N,52326,N,N,N,52327,N,52328,N,15397,N,52329,N,N,N,N, +N,N,N,N,52330,52331,24699,N,52332,N,N,24700,52333,N,N,52334,24701,N,N,N,52335, +N,52336,52337,12603,N,52338,52339,24865,N,18747,24866,52340,N,13348,24867, +52341,24868,52342,52343,N,N,24869,52344,24871,24872,24870,N,52345,N,18771, +24874,24873,N,52346,52347,52348,N,N,52349,24876,24875,24877,52350,N,N,N,N,N, +24878,24880,24879,N,N,14713,52513,24882,N,24881,52514,52515,13381,N,16211,N, +17724,N,24883,16440,52516,52517,N,15162,52518,12665,24884,52519,19793,52520, +52521,19043,24885,N,N,52522,17732,19763,14659,16189,N,N,52523,17227,21044, +52524,17454,12904,24886,52525,52526,52527,52528,N,N,52529,24887,N,24892,52530, +52531,24890,24889,23106,13094,24888,52532,12378,52533,18474,52534,N,18506,N,N, +52535,N,20017,24893,24891,17244,16422,52536,52537,18475,52538,18733,N,24895, +20012,14157,24896,N,24894,18518,24897,N,24898,N,52539,12379,52540,N,15990, +24903,N,24900,18029,24899,52541,52542,52543,52544,52545,52546,13606,N,52547, +24906,N,N,52548,24901,24902,N,24905,24904,18725,N,N,16706,16705,52549,13631, +52550,52551,24907,52552,N,N,N,52553,24908,N,52554,24909,N,N,N,N,52555,24911, +52556,24910,N,N,N,N,N,12630,N,N,N,N,N,24919,18536,24913,52557,24915,N,N,24917, +16190,52558,N,24918,24916,15424,52559,52560,52561,24912,24914,52562,18754, +52563,15945,N,N,24921,N,52564,24920,52565,52566,N,N,24922,N,15398,14895,N, +52567,17783,24923,N,17483,52568,N,24925,52569,52570,52571,20001,24924,52572,N, +N,52573,N,16745,N,N,52574,N,52575,52576,24930,52577,24932,24933,17236,N,N,N,N, +52578,24931,N,24928,N,24926,24927,52579,24929,52580,52581,52582,N,N,52583, +52584,24936,52585,24934,52586,24935,N,52587,N,N,52588,52589,N,52590,52591,N,N, +52592,N,52593,52594,52595,52596,24937,24939,24940,24941,52597,24942,52598, +52599,24938,N,52600,N,N,N,52601,N,N,24944,N,52602,52603,24943,52604,N,N,52605, +52606,52769,24945,52770,N,N,N,52772,52773,20037,52774,52775,52776,24948,24946, +24947,52777,52771,52778,13410,N,N,N,N,N,19582,N,N,52779,19018,N,24950,52780,N, +N,24949,N,N,52781,N,24951,24952,N,52782,52783,N,24956,24953,24954,24955,N, +24957,52784,52785,52786,24958,52787,25121,N,52788,N,25122,N,25123,N,18479, +17744,25124,18290,18740,N,25125,52789,N,25126,17706,52790,13095,14660,25127,N, +N,25128,52791,52792,25129,N,15145,N,N,25131,N,52793,25130,N,N,25132,25133, +52794,52795,52796,N,52797,52798,N,52799,52800,52801,52802,52803,52804,52805,N, +52806,N,N,52807,18537,N,25134,N,N,N,25135,N,N,29545,25136,25137,25138,N,N, +52808,N,15150,N,52809,25139,18262,N,52810,19295,N,12622,52811,12631,52812, +52813,25140,52814,N,N,N,25142,N,52815,N,25141,17776,N,52816,N,16441,23865,N, +25143,19521,52817,25144,N,13382,18519,25145,52818,25146,52819,N,25147,N,52820, +N,19548,N,52821,52822,19541,N,17470,N,52823,N,16746,52824,N,25149,52825,N, +15714,52826,15946,N,N,25152,N,52827,25151,25150,18557,52828,13383,14377,N, +52829,N,N,N,52830,N,52831,52832,N,52833,N,52834,52835,25158,52836,N,25155, +16191,19506,N,52837,N,25154,25156,25157,N,52838,25153,N,N,N,52839,52840,52841, +N,N,N,N,52842,52843,52844,25159,25160,52845,17455,N,13411,52846,52847,N,17253, +N,52848,N,N,52849,52850,25161,N,N,52851,N,N,52852,52853,52854,N,N,52855,N,N,N, +52856,52857,N,N,25162,25165,52858,N,52859,52860,52861,16231,52862,17988,53025, +25166,19283,53026,25163,N,53027,25164,53028,N,N,N,53029,N,53030,53031,53032,N, +N,N,N,25169,53033,N,N,53034,25168,25167,53035,N,N,N,53036,N,N,N,N,N,N,25171, +53037,53038,25170,N,N,25172,N,N,53039,53040,53041,N,N,N,53042,N,N,N,25174, +53043,25173,N,53044,N,N,19021,N,53045,N,N,53046,N,15702,20038,53047,53048, +25175,53049,N,17975,N,53050,25176,N,N,25177,N,25181,25179,25180,53051,25178,N, +N,N,53052,N,N,N,25182,N,53053,N,N,N,25183,N,N,N,53054,53055,N,N,53056,N,25184, +N,53057,25185,19511,25186,N,53058,53059,53060,N,19568,25187,53061,17230,53062, +18282,N,13931,53063,N,53064,17211,25188,13882,53065,53066,N,16464,53067,N,N,N, +53068,N,N,53069,25189,14909,N,N,53070,53071,N,N,53072,N,N,25190,53073,53074,N, +N,53075,25191,N,14374,14933,N,N,N,N,N,N,N,53076,N,N,25193,53077,53078,53079,N, +17750,14934,13646,N,N,N,N,N,53080,53081,N,53082,N,19236,N,18251,53083,N,53084, +N,N,17751,N,N,N,N,14684,N,N,N,53085,53086,25195,N,53087,53088,N,N,N,53089,N, +53090,N,N,N,53091,N,N,N,N,N,N,N,N,N,53092,15947,53093,N,53094,53095,N,53096, +53097,N,N,N,53098,N,53099,20018,14661,N,53100,14375,N,N,18467,N,25197,N,N,N,N, +N,53101,N,25199,N,53102,N,N,14443,N,N,N,N,25198,17526,N,N,53103,N,25201,13111, +25196,53104,N,18538,N,12592,53105,14956,N,20306,53106,N,25200,N,N,53108,53109, +53110,N,53107,N,25202,53111,N,N,19019,53112,16473,25204,N,53113,53114,N,25205, +53115,53116,53117,53118,N,25203,N,N,N,N,13134,53281,25211,53282,25210,53283,N, +15399,N,N,N,25212,25207,53284,53285,53286,25213,25208,53287,N,53288,N,18520, +25206,53289,53290,25209,53291,53292,N,N,N,25378,53294,N,N,N,53295,53296,53297, +N,N,53293,N,53298,25377,19297,N,53299,N,25214,N,N,12395,N,N,53300,53301,25380, +N,53303,53304,N,N,53305,53306,N,25379,N,53307,53302,15948,N,N,N,N,53308,25381, +N,N,N,N,53309,N,16707,N,53310,25383,25382,N,N,N,N,N,N,25384,53311,N,53312,N, +53313,53314,53315,N,N,N,N,53316,25192,53317,N,53318,25194,25386,25385,53319,N, +N,N,53320,N,N,53321,53322,N,N,N,N,15400,53323,20073,53324,15442,53325,25387, +14135,N,N,53326,53327,53328,13632,13607,15203,53329,53330,N,N,N,53331,19764, +53332,N,25393,53333,25392,16708,25389,53334,N,25391,53335,53336,15691,16192, +25390,25388,N,18218,N,N,15949,N,53337,18748,53338,N,53339,N,14935,N,N,N,N, +53340,N,N,N,N,17784,N,53341,25394,53342,53343,N,53344,25395,25417,13912,N,N, +20285,16693,N,N,N,N,25396,53345,53346,12882,17527,18977,N,53347,N,53348,53349, +53350,53351,N,53352,N,N,53353,53354,25397,N,N,N,53355,N,N,N,N,13690,25398, +53356,53357,25400,53358,N,N,25401,53359,18217,53360,N,25402,53361,N,N,N,53362, +25403,25404,53363,N,13913,12883,17989,15656,15204,53364,N,53365,N,N,53366, +53367,25405,53368,15657,N,N,N,53369,N,12874,18755,N,53370,25406,53371,N,18539, +N,53372,N,N,53373,53374,16709,53537,25409,53538,25410,18281,53539,16193,25407, +N,17249,53540,53541,25408,53542,N,N,15950,53543,N,N,N,N,N,N,53544,N,N,12380, +53545,13609,N,53546,53547,N,N,N,53548,25411,53549,53550,17528,53551,25412, +16455,N,N,53552,N,N,19501,53553,N,18723,25413,25414,17237,53554,20039,N,53555, +25416,25415,53556,N,N,N,N,N,53557,N,N,N,53558,N,53559,15471,53560,53561,25418, +12400,N,53562,53563,N,25421,53564,53565,53566,25419,12884,14158,25420,14662, +14706,N,19046,25422,53567,53568,19284,53569,53570,25424,N,N,53571,16465,12623, +12858,12332,N,N,N,N,53572,53573,25423,N,53574,N,N,53575,53576,N,53577,53578, +25425,25426,15991,N,53579,N,53580,N,25427,53581,13135,N,53582,N,N,25429,N,N,N, +14186,53583,13670,N,53584,25430,13941,N,N,25431,53585,16508,53586,17997,53587, +16480,14965,53588,53589,N,25432,N,53590,53591,N,N,N,N,53592,53593,17250,16747, +53594,25434,25436,25433,25435,N,N,N,N,N,53595,14114,53596,N,N,53597,N,N,N,N,N, +25437,14118,N,53598,N,13671,19794,25439,N,N,53599,N,53600,25440,N,N,53601, +12590,53602,53603,N,N,25443,N,N,N,13174,25442,25441,53604,25445,25438,53605, +25446,20009,53606,25447,53607,25448,N,53608,21620,25450,N,25449,N,N,N,25451, +25452,53609,20021,25453,N,28783,15951,25454,25455,15703,N,17976,25456,N,53610, +53611,17192,53612,53613,25457,N,17212,25458,53614,N,N,53615,N,13861,N,20799, +17245,15411,53616,N,53617,53618,13384,25459,N,25634,N,25462,53619,13672,N, +25461,25636,N,N,N,25460,N,15952,N,N,53620,N,N,N,25464,25465,N,17707,N,N,25466, +53621,13150,N,N,53622,N,16218,18788,53623,25468,53624,53625,53626,17000,53627, +53628,53629,53630,53793,N,25463,53794,25467,25469,N,N,14971,N,N,N,53795,N, +53796,53797,53798,N,N,N,25638,18734,53799,18470,17785,N,13914,25637,25635, +53800,18485,25470,17246,17787,N,17786,53801,14966,N,N,N,N,N,N,25656,N,N,53802, +N,N,N,53803,25640,53804,25642,N,53805,53806,N,25645,53807,25646,53808,25643, +25644,53809,53810,25641,25639,N,53811,N,N,25633,N,N,N,N,N,N,N,N,N,53812,N, +19023,12885,N,53813,N,25653,N,25650,53814,25655,53815,53816,25654,N,18291, +19495,53817,15163,25648,25657,25652,53818,25651,25647,53819,25649,53820,13385, +N,N,N,53821,N,N,N,N,17213,N,53822,16509,N,53823,53824,18466,53825,N,25662, +53826,53827,N,18468,N,53828,53829,53830,53831,N,N,16481,25659,53832,N,18511, +53833,25663,19027,53834,17243,53835,25658,25660,N,N,25661,N,N,N,N,53836,N, +53837,53838,N,53839,53840,53841,N,25664,N,N,15428,N,N,N,17990,25669,25668,N, +53842,25665,53843,N,N,20278,N,N,N,N,53844,25674,53845,53846,25678,25675,53847, +53848,53849,N,53850,N,53851,25671,53852,53853,53854,53855,N,53856,25672,N, +53857,N,53858,53859,25677,53860,53861,N,25666,21077,25673,25667,N,N,25676,N, +53862,N,53863,N,N,N,25682,53864,13386,N,25679,N,53865,53866,25680,53867,N, +25681,25684,53868,N,N,N,N,53869,N,53870,53871,N,53872,25683,18550,53873,53874, +N,N,25685,20092,19053,25690,N,N,25687,N,N,53875,N,N,N,53876,N,25686,16466,N, +25689,25691,53878,53879,53880,25688,53877,25695,N,25692,53881,53882,53883, +53884,53885,53886,25693,25670,54049,N,54050,25694,25696,N,54051,N,54052,N,N, +25697,54053,54054,N,54055,N,54056,19014,N,25698,N,N,N,54057,N,N,54058,54059, +19554,N,N,13902,14121,25699,N,N,54060,54061,N,18996,N,16232,N,19504,N,54062, +25700,N,20019,N,54063,18292,N,16710,18228,N,N,15693,N,N,54064,12352,54065, +25705,25703,N,25701,13345,54066,15953,25706,N,N,25704,N,25702,25710,N,54067, +25709,25708,25707,N,N,54068,54069,N,25711,54070,54071,54072,25712,16442,54073, +25713,N,25715,N,54074,25714,N,54075,54076,54077,14418,N,N,54078,16696,54079,N, +N,25717,54080,54081,54082,17788,54083,25716,54084,54085,N,25718,54086,18997, +16748,14663,N,25719,N,N,N,54087,20040,N,54088,N,54089,N,N,N,25721,N,N,25722,N, +25723,54090,25724,N,15205,N,25725,14159,N,N,13674,13610,N,25889,54091,19571, +14664,25726,54092,54093,54094,25892,19558,N,18236,N,54095,18739,54096,54097, +54098,15715,25891,54099,15443,14665,15206,13673,18998,25890,54100,54101,N, +16711,19266,14967,54102,N,N,54103,N,N,N,54104,15207,17501,54105,25895,20063, +14937,54106,25896,16194,N,25898,N,N,N,15954,14896,N,54107,54108,54109,25897, +54110,54111,15658,14398,16712,25893,25899,54112,54113,N,N,25894,14160,54114, +25902,25906,14187,54115,N,54116,N,N,25901,54117,N,54118,54119,25910,54120, +54121,14666,N,N,19821,12348,25907,N,54122,13675,54123,25904,N,54124,N,N,N, +25905,N,54125,17789,25903,25900,N,13096,16484,N,54126,14376,54127,54128,N, +25912,N,54129,N,54130,54131,54132,N,54133,54134,N,54135,25909,N,54136,54137, +54138,N,25911,N,54139,N,25908,N,N,54140,54141,N,14161,16947,25913,16750,54142, +54305,25926,N,N,25922,25916,N,N,54306,54307,N,N,54308,25920,15482,12381,25915, +25923,25927,14667,19542,54309,17494,25917,54310,54311,25925,54312,25914,17214, +N,25919,12349,19530,N,N,54313,54314,54315,54316,54317,25918,N,N,13915,18540, +54318,54319,54320,16749,N,20048,15727,N,N,25966,N,54321,25928,54322,16510,N, +25924,25929,25931,N,17529,25934,54324,N,25930,54325,54326,N,19028,13387,54327, +54328,19531,54329,N,12382,N,54330,25933,N,20093,54331,54332,N,N,54333,54334, +25932,54323,12655,N,N,18028,25935,N,N,54335,25942,25936,25943,N,N,N,N,54336, +54337,25939,N,N,54338,N,54339,N,N,N,18299,54340,54341,15434,25941,54342,25938, +25944,25937,N,N,15684,54343,54344,N,N,19237,54345,54346,15692,54347,N,25940, +25952,54348,N,25948,54349,25951,N,25949,25953,25947,N,25921,16467,54350,N, +18507,N,25950,54351,54352,25945,54353,N,N,16673,14162,N,15659,54354,N,54355,N, +54356,N,16165,16694,25956,N,54357,25958,25959,N,N,25955,25957,54358,N,54359, +54360,N,N,54361,25946,25954,N,25962,25961,54362,N,19322,54363,54364,14123,N,N, +54365,N,N,N,N,54366,25960,N,25964,25963,25967,54367,25969,N,54368,15164,25965, +N,N,54369,54370,25970,25971,54371,N,25972,54372,25978,17723,25974,54373,25973, +25975,25976,54374,25977,N,54375,N,54376,25979,25980,54377,54378,13388,N,25981, +N,25982,54380,54379,54381,54382,54383,N,N,N,54384,54385,26145,N,54386,N,N,N,N, +26146,26147,26148,54387,26149,26150,54388,54389,26152,26151,N,N,26153,N,N, +54390,54391,54392,N,26154,26155,54393,N,54394,54395,54396,54397,26158,26156, +26157,14945,14163,N,54398,17238,N,18483,54561,15728,N,N,18253,N,18541,26159, +22637,N,N,N,54562,54563,54564,54565,N,26160,26162,N,19813,26161,26164,26163,N, +19795,54566,26165,54567,18558,54568,54569,54570,N,N,26166,N,54571,54572,N,N, +26169,N,54573,26168,26167,N,N,54574,54575,26170,14130,N,54576,N,16674,13633, +54577,N,N,54578,26174,26171,N,N,26172,N,54579,N,26175,N,26176,26173,N,N,54580, +12585,N,54581,54582,12839,N,54583,N,26178,26179,N,54584,N,26180,N,19810,N, +54585,54586,N,N,15660,N,26182,26181,N,N,N,N,N,54587,N,N,N,54588,16233,26183,N, +54589,N,54590,26184,N,54591,26185,N,13413,54592,N,54593,54594,13389,N,54595, +26186,N,N,N,N,N,26187,54596,19293,19811,54597,54598,54599,19796,20279,N,14669, +26190,15444,26189,54600,54601,N,54602,26191,15401,54603,54604,54605,16977, +54606,26192,54607,54608,14668,54609,19543,26193,26194,N,N,26195,54610,54611, +54612,54613,26196,N,N,54614,N,54615,N,26197,N,N,N,54616,N,54617,N,54618,N,N, +15402,54619,54620,19565,54621,N,54622,54623,26199,54624,17215,54625,26198, +54626,N,N,N,54627,N,26201,N,N,N,26200,N,N,N,N,N,N,N,26202,N,N,N,16443,N,26203, +N,26204,N,N,N,19001,26205,54628,16751,26206,N,54629,N,54630,N,26207,N,N,N,N, +54631,N,20094,26210,54632,26209,26208,17456,54633,26211,16166,N,26212,N,N,N, +26213,20280,26214,N,54634,N,N,26215,26217,26216,18469,54635,18041,N,20286, +18473,N,54636,N,N,N,N,26219,N,N,15955,N,18730,N,26220,26218,54637,13390,54638, +N,N,14420,15208,N,N,18542,54639,54640,N,14378,19267,54641,26223,26221,N,14670, +N,14671,12393,N,14952,N,N,N,54642,54643,18265,N,N,N,N,N,N,N,N,12383,26228,N, +17216,N,54644,N,N,N,18264,54645,16987,54646,N,N,54647,N,54648,54649,26230, +54650,54651,26226,26229,26224,N,26227,19238,N,54652,14421,N,N,12413,26225,N,N, +N,N,N,N,N,54653,54654,26232,54817,26233,54818,54819,17977,N,54820,N,13883, +54821,54822,N,26406,18237,54823,15209,54824,N,13884,16456,20294,19502,26231, +16468,54825,N,N,N,N,N,N,N,N,N,N,54826,54827,54828,N,13651,26234,54829,N,54830, +N,54831,N,N,26236,54832,N,N,54833,N,26235,N,N,54834,N,N,26237,54835,17190,N, +18238,N,54836,N,N,N,17457,54837,N,54838,N,26403,N,N,N,N,N,N,54839,26402,54840, +N,N,54841,26238,54842,N,16213,N,18789,26405,54843,26404,14672,20307,N,54844,N, +N,N,N,N,N,N,26421,54845,54846,N,N,N,26409,26410,54847,54848,54849,N,15472,N, +54850,26408,54851,14712,26407,N,N,26411,N,N,54852,17458,18978,16675,N,N,N,N, +16988,26415,54853,26416,26412,54855,54856,54857,N,26413,N,26414,54858,N,N, +54859,14673,54854,N,N,26422,N,26418,54860,N,54861,N,18790,54862,19308,18728, +54863,N,26417,N,54864,26420,26419,N,N,N,19268,26423,N,N,N,N,54865,N,26424,N, +54866,16695,54867,26425,N,N,26427,N,26431,54868,N,26428,26426,18239,26429,N, +26430,54870,N,54871,12850,N,26437,26432,54872,54869,N,26433,54873,54874,N, +26434,N,16929,N,54875,N,54876,26436,26435,26438,54877,N,54878,54879,26439, +26440,54880,N,16195,54881,12905,N,26441,20055,N,15403,54882,54883,15661,N,N, +54884,54885,54886,15210,17239,54887,54888,N,54889,54890,26442,26443,12593, +54891,26444,54892,54893,26445,26446,54894,N,26447,N,26448,13885,23082,26449,N, +16485,26450,15435,54895,26451,N,20528,54896,54897,N,26452,19038,13404,54898, +54899,16676,15704,54900,18801,15662,N,54901,54902,N,N,N,N,N,54903,26453,14674, +26454,18508,N,26468,N,N,N,54904,26456,54905,16969,18293,14399,26455,16677, +54906,N,N,N,N,N,26457,N,N,54907,54908,54909,54910,17530,N,N,N,55073,N,N,55074, +55075,N,55076,N,N,N,N,55077,N,26459,26458,26461,N,55078,26460,N,26462,55079,N, +26464,55080,26463,N,13391,55081,26465,N,26466,26467,N,55082,14897,20041,N, +26469,16167,N,55083,N,12656,26470,26471,N,N,55084,N,55085,26472,55086,55087, +55088,N,55089,55090,N,N,55091,N,55092,55093,12402,N,26473,55094,N,N,55095, +26474,N,55096,N,55097,N,55098,18791,55099,55100,N,15431,N,26476,55101,55102,N, +55103,55104,13097,12338,55105,55106,55107,55108,26475,26478,18254,55109,16196, +55110,12886,55111,19239,55112,N,N,55113,14173,13916,55114,26477,55115,12906, +55116,55117,N,N,N,N,N,13347,55118,N,N,N,N,N,N,N,N,N,55119,12657,26482,20074, +16989,55120,N,18756,N,26494,55121,12887,26492,N,26490,26481,55122,26479,55123, +26480,55124,15459,13932,17271,55125,N,55126,18001,N,55127,N,55128,N,12625,N, +26484,26483,N,55129,55130,N,26489,26485,26488,N,55131,55132,55133,55134,19536, +26487,12888,13181,26491,55135,55136,26493,55137,55138,N,N,14164,N,N,N,N,N,N,N, +26659,26668,26669,N,N,55140,12331,55141,55142,55143,N,55144,55145,26676,N,N,N, +N,12401,N,N,26667,55146,55147,55148,26666,55149,26661,26660,55150,26658,26657, +17251,55151,17019,26663,55152,N,55153,55154,N,N,26662,N,55155,55156,55157, +26665,N,55158,N,16752,14165,N,N,55159,55160,12609,26664,55161,14675,55358, +55139,55162,55163,55164,16753,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +55165,N,N,26682,N,26683,N,12889,55166,N,N,12846,26680,55329,N,55330,55331,N, +55332,N,55333,26670,55334,26678,N,26685,26679,N,N,55335,26677,N,N,N,55336, +26486,55337,55338,26675,N,55339,55340,26671,55341,55342,55343,13392,26673, +26684,N,26674,N,N,N,55344,55345,26686,55346,26672,18300,55347,55372,N,N,N, +19817,N,N,N,26681,N,N,N,N,N,N,N,26703,55348,55349,55350,26695,N,N,N,16251,N, +55351,N,55352,13638,N,13917,N,26690,55353,55354,55355,N,12891,55356,N,15956,N, +26693,N,N,N,14938,55357,N,17745,26698,N,N,N,N,N,N,N,55359,19054,55360,26689,N, +N,N,12890,14422,18729,26699,N,26687,N,55361,26696,55362,55363,N,26706,55364, +26691,55365,N,26692,17978,N,55366,26697,N,N,55367,26694,19240,26700,12384, +55368,N,55369,N,26688,N,55370,N,N,N,55371,N,N,N,N,N,N,26702,N,26701,N,N,N,N,N, +N,18283,26708,N,26719,N,N,55373,N,13182,N,N,N,26722,N,N,26704,55374,N,N,26709, +19822,N,N,N,N,N,N,N,55375,26718,55376,55377,19797,55378,N,N,55379,20010,55380, +N,55381,55382,N,N,N,55383,17272,55384,55385,55386,13163,55387,N,N,N,55388, +18802,26724,17953,55389,55390,12337,55391,N,26717,55392,26713,16754,26707, +26715,26720,55393,18220,N,55394,55395,12330,55396,26712,55397,26721,18808,N, +55398,55399,N,N,N,55400,26716,N,26711,55401,N,N,N,N,N,15957,N,N,N,N,15663,N, +55402,55403,15404,55404,N,N,N,19544,N,N,18759,N,55405,26727,N,26736,N,N,N,N, +55406,N,55407,55408,55409,N,N,26714,N,55410,N,55411,13175,N,55412,N,N,N,15992, +26725,55413,26730,16755,55414,55415,26726,55416,26733,55417,N,17247,N,26734, +55418,55419,19798,26723,13112,55420,26729,N,55421,26732,19500,N,55422,N,N, +26735,N,N,26728,26731,N,55585,N,N,N,N,N,N,N,N,N,N,55586,N,N,55587,N,19241,N, +20257,55588,55589,55590,55591,N,26739,N,N,55592,N,N,55594,55595,26746,55596,N, +26738,15427,N,55597,55598,N,N,26705,55599,N,N,N,N,55600,N,55601,N,55602,19022, +N,19490,26745,26744,N,26740,26741,N,12598,N,55603,N,55604,26743,N,26737,55605, +55606,55607,55608,17493,55609,N,N,55610,55611,26742,12414,N,55612,N,N,55593, +55613,55614,16930,55615,N,N,N,N,N,N,19011,N,55616,26747,26913,N,18521,N,N, +55617,N,26750,15958,15433,26915,N,N,13886,55618,55619,55620,55621,55622,N, +26916,55623,18809,26749,55624,26710,N,55625,55626,55627,55628,55629,55630, +55631,26748,55632,N,N,N,20303,17954,18803,55633,N,26923,N,55634,N,N,N,N,N,N,N, +26929,N,55635,55636,55637,N,55638,26930,55639,26917,55640,N,N,18294,55641, +55642,26927,26919,55643,26921,55644,55645,N,N,55646,26931,26920,N,55647,26924, +N,N,12658,55648,18021,N,26925,26928,55649,N,55650,55651,N,55652,N,26918,55653, +16678,55654,26922,15143,16197,14128,19572,55668,19577,15730,N,N,N,N,55655,N, +55656,55657,55658,26935,26933,N,55659,55660,55661,55662,N,20302,55663,N,N,N,N, +55664,N,26932,55665,55666,N,19829,55667,26934,26936,N,N,N,N,26937,N,N,55669,N, +55670,N,26940,26938,N,55671,55672,N,N,N,17955,26939,55673,N,55674,18509,26926, +N,N,55675,N,N,N,N,N,55676,N,N,55677,15731,N,26941,26946,16756,55678,N,26945, +55841,55842,N,26914,N,55843,55844,26947,16713,N,N,26942,26944,N,55845,55846,N, +55847,55848,55849,26943,N,N,23857,23842,55850,55851,26949,55852,N,N,55853,N,N, +55854,26948,N,N,N,N,55855,N,55856,N,N,N,19830,N,25148,26950,N,N,N,N,N,55857,N, +55858,N,55859,N,55860,55861,N,26951,55862,47206,55863,N,N,N,55864,N,N,N,N,N,N, +26952,14423,N,13652,N,55865,55866,26954,20829,55867,55868,55869,55870,13685,N, +20026,55871,13939,26955,55872,55873,55874,55875,55876,N,N,26956,N,55877,N, +17262,55878,N,N,55879,N,26957,N,N,N,55880,55881,55882,N,18042,55883,12346,N,N, +N,N,N,N,N,N,N,N,N,N,55917,N,12899,26962,26963,55884,N,N,N,55885,N,26958,N, +15165,55886,N,55887,N,55888,N,55889,N,N,N,N,55890,N,26959,18242,N,55891,55892, +55893,26960,26961,26971,N,55894,N,26965,26968,55895,N,55896,55897,55898,26964, +55899,55900,55901,N,N,N,N,N,55902,55903,55904,N,55905,26966,55906,26967,15448, +N,26969,N,17217,N,14166,13122,N,N,55907,55908,N,26972,55909,N,55910,N,13119, +55911,26977,55912,N,26973,26976,55913,N,N,55914,18490,55915,N,55916,N,26974,N, +N,26975,18760,18522,26978,N,N,N,N,N,N,N,N,17021,26988,55918,26984,55919,55920, +12907,26982,N,19242,26983,55921,55922,26980,55923,26981,26986,26989,55924,N, +26987,55925,55926,55927,26985,26979,55928,55929,N,N,N,17240,55930,26996,N, +19498,N,55931,55932,N,55933,N,55934,N,26994,N,N,56097,26995,N,N,N,N,56098, +56099,N,56100,56101,N,26990,N,N,26992,N,56102,56103,26993,56104,56105,56106, +26991,56107,N,N,56108,N,56109,N,N,N,16486,N,20281,27000,56110,27001,N,N,N,N, +27169,N,16170,N,27003,56111,27006,N,N,N,56112,N,26998,26997,56113,N,27170, +56114,56115,12892,N,27004,N,27171,N,N,N,27005,56116,N,56117,56118,N,27002,N, +17459,N,26999,N,N,56119,N,N,N,18280,N,N,27175,56120,56121,56122,56123,56124, +56125,56126,N,56127,56128,19771,N,N,56129,N,N,56130,N,56131,N,56132,56133, +56134,N,N,N,N,56135,27174,56136,N,27173,56137,N,N,N,56138,N,N,N,27182,56139, +56140,56141,27176,N,56142,N,27184,N,56143,N,N,N,N,19814,27187,N,27178,56144, +56145,27179,56146,N,N,27183,N,27186,27185,56147,56148,56149,27177,N,N,56150,N, +27180,N,27197,N,N,56151,56152,N,N,56153,56154,N,56155,N,N,56156,27190,N,56157, +56158,56159,N,N,N,N,N,56160,56161,N,56162,N,27188,N,56163,27189,56164,N,N, +27194,27195,56165,13098,56166,13634,N,N,27193,56167,56168,N,56169,N,27172, +56170,N,N,56171,56172,56173,N,27192,27196,27191,56174,27198,56176,56177,56178, +27200,27199,N,56179,56175,56180,56181,56182,N,56183,56184,N,27202,27201,26970, +N,N,N,27206,56185,N,N,N,N,56186,56187,N,56188,27203,56189,N,N,56190,27204,N,N, +27205,56353,27207,56354,N,N,N,14188,56355,27209,56356,27208,56357,15664,N, +56358,56359,56360,56361,14676,24103,56362,N,N,56363,27210,15697,N,56364,56365, +13113,56366,27211,56367,12626,56368,15959,27212,56369,56370,14677,27213,12385, +56371,N,N,N,18749,56372,N,27214,N,N,N,N,16234,56373,27221,N,N,27218,N,17263,N, +56374,N,56375,N,27219,27216,13918,56376,27215,27222,N,N,N,N,N,14134,N,N,16990, +N,27228,N,N,N,N,27224,N,N,N,16949,27223,56377,27226,56378,56379,56380,N,27217, +56381,56382,N,27227,N,27229,N,N,N,56383,N,56384,18543,N,N,27225,N,27230,27232, +N,N,14419,27220,N,12353,N,N,56385,N,N,56386,56387,27231,56388,14939,20086, +27233,27234,16757,N,N,N,N,56389,56390,56391,56392,56393,20002,N,56394,56395, +56396,27235,19765,N,N,27236,27237,N,56397,19044,27238,56398,14912,N,20003,N,N, +N,N,N,56399,27243,N,N,N,N,N,N,56400,56401,56402,27244,15960,27242,56403,N, +56404,19815,27239,N,N,27241,16445,16254,56405,27240,N,27245,N,56406,18979,N,N, +27247,N,27246,56407,56408,56409,13164,N,19243,27248,N,56410,56411,N,56412, +56413,56414,N,56415,27260,27250,N,56416,N,N,N,N,27251,56417,56418,56419,N, +27252,27253,N,N,N,N,56420,56421,56422,N,N,56423,27257,N,27258,56424,56425, +27256,N,N,56426,N,56427,27254,56428,27249,27255,56429,56430,N,N,56431,N,N, +27259,28727,N,56432,N,N,56433,N,N,N,12840,56434,N,N,56435,56436,56437,N,27262, +13919,27261,56438,56439,56440,27426,N,27425,N,N,N,27428,56441,N,27427,56442, +27429,56443,N,15665,56444,27430,56445,N,27431,N,N,56446,56609,56610,56611, +27432,16446,N,19799,N,27433,N,N,18980,18246,27434,56612,27435,14379,N,56613,N, +13612,56614,N,N,27436,56615,56616,15211,18241,27437,N,13136,56617,56618,N,N, +56619,56620,27438,N,N,N,56621,27440,19831,N,27439,16198,N,27441,N,N,27442, +56622,N,27443,13393,56623,56624,56625,56626,N,N,27444,N,56627,27445,N,27446, +27447,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,13137,N,56628,56629,56630,56631,56632, +N,27448,N,27449,27450,N,N,N,N,N,12914,N,56633,16168,27451,N,56634,N,56635,N, +56636,N,N,N,56637,N,56638,27452,N,56639,N,27453,56640,N,N,N,56641,N,56642, +14400,N,17531,27454,56643,56644,N,56645,14167,N,16214,N,27457,N,17956,56646, +27456,56647,56648,14129,56649,56650,27455,17015,13613,N,N,27458,N,27459,56651, +15961,56652,N,56653,14189,56654,27460,56655,N,N,N,19244,56656,56657,16479,N, +56658,N,13686,N,19573,16714,56659,27461,56660,N,N,16199,17264,15962,56661, +56662,N,56663,27462,N,56664,N,56665,27465,56666,27466,56667,N,N,N,56668,56669, +N,14910,16962,27464,56670,15963,18750,56671,56672,56673,N,N,27463,56674,56675, +15212,N,12627,56676,27470,14168,N,56677,15214,56678,N,15213,N,20301,27469, +27468,16679,N,13645,20291,13114,15964,N,56679,56680,56681,N,56682,56683,56684, +27467,N,56685,56686,56687,N,27472,56688,27473,27471,56689,14424,N,19776,N, +56690,15215,18215,N,56691,56692,27476,56693,16448,N,17218,56694,56695,19766, +56696,27479,N,N,N,14444,56697,16447,27475,N,27480,14445,27477,27478,56698, +27474,56699,N,N,16482,17993,56700,56701,17199,N,12893,56702,N,N,56865,56866,N, +18544,N,56867,13635,N,56868,17460,N,N,27483,56869,27481,N,56870,17228,56871, +56872,56873,16449,13394,27482,N,16219,N,56874,20042,56875,56876,56877,20288, +56878,N,N,27484,27495,17461,56879,27494,56880,27491,27499,27492,N,27488,N, +17532,27487,N,N,N,27485,56881,19745,15216,N,56882,27489,N,27486,56883,56884, +56885,27493,15732,N,14401,N,56886,N,17018,56887,19269,12634,12386,N,17957, +56888,56889,27497,N,N,56895,56890,27496,N,18022,N,27501,56891,N,N,27490,N, +27500,27502,N,14380,27498,14678,56892,15445,56893,56894,27503,19800,N,N,N,N, +27506,N,27509,N,N,27507,18741,56896,N,N,56897,N,N,27504,N,N,N,56898,N,13920,N, +N,56899,N,27508,N,N,27510,56900,56901,56902,56903,56904,N,56905,27514,N,N, +27511,56910,27513,27512,N,N,56906,56907,56908,N,27515,N,15409,56909,27517, +27516,18792,N,56911,27681,N,N,N,56912,N,N,14169,N,N,N,N,27518,27682,56913,N, +27683,13636,26177,15993,N,27684,N,56914,14446,56915,56916,N,N,56917,27685, +56918,N,27686,56919,N,15166,56920,56921,N,N,N,N,23118,56922,27687,56923,27688, +56924,15666,N,27689,27690,56925,56926,27691,N,N,27692,27693,N,56927,N,56928, +56929,17195,56930,56931,27694,N,N,56932,56933,27696,N,27695,N,N,N,56934,17958, +56935,27697,56936,19245,56937,27698,N,27699,56938,27700,56939,N,56940,56941, +27701,N,56942,56943,56946,18010,56944,N,56945,N,N,N,15965,27702,56947,56948,N, +56949,N,56950,56951,14699,20526,27703,56952,N,N,N,N,N,56953,N,56954,56955,N, +27704,18751,27705,56956,27713,N,56957,N,N,N,27706,N,N,27708,56958,57121,N, +27707,27709,57122,19270,27710,27711,N,57123,N,57124,57125,27712,N,N,N,27714, +57126,N,57127,57128,13101,17511,N,18793,14946,14679,N,57129,N,N,18767,12895, +18510,27717,13395,16469,27716,27721,17273,19555,N,27719,27720,13614,N,27722, +18275,16991,57130,57131,18545,17725,27718,N,19271,12908,27724,20264,17474, +20293,57132,57133,15217,27723,57134,16945,57135,N,27740,16680,57136,N,18040,N, +18768,N,57138,57137,N,N,57139,27727,15167,15218,57140,15966,N,18277,57141, +14381,27726,27725,N,18794,N,57142,N,15425,N,57143,17746,N,57144,57145,N,57146, +N,N,57147,N,57148,57149,N,27729,27730,14680,27728,57150,57151,57152,N,57153, +27731,27732,N,27734,16931,57154,27733,13414,N,27736,N,27735,27737,N,57155, +27739,27741,N,27742,57156,N,N,N,57157,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,16470,57158,15439,27743,N,57159,N,13138,57160,27744, +57161,N,16758,27745,N,27746,18795,N,N,13615,N,N,N,N,N,N,N,57162,N,27747,57163, +N,57164,17462,N,N,57165,N,12635,N,N,57166,N,N,57167,57168,N,N,N,57169,N,N,N, +27748,N,N,N,N,57170,57171,57172,N,N,15473,N,N,57173,N,16246,N,N,57174,57175,N, +N,57176,N,N,57177,16941,N,57178,N,57179,N,57180,27751,57181,57199,N,27750,N, +57182,N,27749,N,N,57183,57184,57185,57186,N,57187,27757,27755,N,57188,27752,N, +57189,N,N,57190,57191,27754,57192,N,57193,27753,27756,N,13687,N,27760,N,16471, +N,27761,57194,57195,N,57196,14425,N,27758,27759,57197,N,N,20265,57198,57200, +57201,17463,57202,16681,N,N,N,N,N,N,27762,57203,N,27765,57204,N,N,57205,57206, +57207,N,27763,27764,19801,57208,N,N,N,17959,27768,57209,N,N,57210,N,57211,N,N, +N,N,N,N,27766,27767,27769,57212,57213,57214,57377,N,N,57378,57379,N,N,27945,N, +N,N,N,N,27772,57380,N,57381,27773,27771,57382,57383,57384,57385,N,N,N,57386,N, +N,57387,57388,27770,N,17533,N,N,27937,27941,27938,27774,57389,27939,57390, +57391,57392,27940,N,N,N,57393,27947,N,N,N,27942,N,57394,57395,57396,57397, +16472,27944,57398,57399,27946,27943,N,N,N,N,57400,N,N,57401,57402,N,57403, +57404,57405,27949,N,15667,N,27948,N,N,57406,57407,57408,27950,N,N,N,N,27951, +57409,57410,27954,27953,N,27952,N,57411,27956,27955,N,19574,N,N,57412,27958, +57413,27957,27959,57414,N,N,N,27960,57415,57416,N,57417,57418,N,N,27962,57419, +N,N,N,N,57420,N,57421,27961,16200,27963,57422,57423,13933,27964,27966,N,57424, +N,57425,N,N,N,N,57426,57427,N,N,27967,N,57428,57429,N,57430,57431,27968,27965, +57432,27969,N,15446,27970,13616,14131,N,57433,N,57434,14382,N,57435,N,N,N,N,N, +N,27971,57436,N,N,18032,N,N,17726,27972,N,N,N,N,57437,N,N,27975,N,57444,57438, +N,57439,57440,N,N,N,N,N,57441,15412,57442,57443,27974,27973,14170,27976,57445, +N,57446,13139,N,27978,N,57447,57448,14940,27977,N,27986,N,N,57449,57450,N, +27980,27982,19045,27979,57451,57452,57453,27981,N,27985,27983,13617,57454, +27984,57455,57456,N,57457,N,57458,27987,57459,57460,18266,20056,N,57461,57462, +57463,15668,N,N,N,27988,57464,57465,57466,57467,19746,27990,57468,27989,N,N, +27993,19777,57469,57470,27992,57633,13165,27991,27996,57634,N,27995,N,N,27994, +17714,27997,57635,N,57636,57637,57638,57639,57640,N,27998,57641,N,N,N,27999, +57642,57643,14700,N,14117,28000,28001,28002,57644,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +16201,28003,57645,15405,28004,57646,57647,N,28005,57648,57649,57650,21025, +20862,N,N,N,N,28006,25968,28007,17188,16171,18240,N,N,57651,57652,28008,57653, +N,19029,17492,14718,N,57654,17193,57655,57656,12586,N,19320,16215,57657,N,N,N, +57658,57659,N,57660,14174,N,57661,13921,57662,57663,19030,57664,N,N,N,N,28009, +N,N,N,N,N,57665,N,28011,57666,57667,28010,12896,N,57668,18038,28012,18295,N, +17715,57669,28013,15698,57670,N,N,28015,57671,57672,19522,28030,28017,28018, +57673,N,17481,57674,16992,16759,57675,17960,57676,28016,13653,N,57677,N,N, +28025,57678,28022,28197,17961,17248,28019,N,17534,17747,28020,28024,16224, +57679,18279,17484,57680,N,16450,28023,16942,16932,28021,12329,20258,N,N,N, +28026,57681,57682,57684,N,57685,57686,16993,57683,N,15669,16202,57687,57688, +28028,28027,57689,12399,28029,N,N,18735,N,28199,57690,N,18011,16235,57691, +57692,17241,N,13944,N,28198,19767,12607,57693,19031,12897,28193,28194,28195, +28196,17979,17187,12387,28200,N,28201,29731,N,57694,16957,57695,28202,N,12659, +16716,57696,14383,N,19802,57697,57698,28203,17708,N,N,57699,16760,15447,28204, +57700,N,28207,N,57701,15717,28205,16683,16682,57702,12388,N,20043,28209,N, +18546,28211,28210,28208,25444,13396,57703,N,28014,57704,28213,28212,57705, +57706,N,57707,28214,57708,19768,N,N,N,57709,N,57710,57711,57712,N,57713,N,N,N, +N,57714,57715,57716,18017,N,57717,19246,N,28215,N,15449,N,N,N,N,28216,57718, +28217,57719,57720,57721,28218,57722,N,17697,N,N,N,N,57723,57725,N,N,12394,N, +57726,57889,57890,N,57891,57892,N,14681,N,57724,N,20282,N,N,N,57901,N,N,57893, +N,57894,57895,57896,N,28222,57897,57898,N,57899,N,14132,28219,N,28220,57900,N, +N,18804,N,N,57903,N,13140,N,57904,57905,N,N,N,57906,19769,57902,13887,N,N,N,N, +N,17748,57907,57908,57909,N,28223,N,57910,57911,57912,N,57913,N,N,N,N,57914,N, +N,57915,N,28224,N,57916,N,57917,57918,57919,28225,57920,N,57921,N,57922,N, +57923,N,57925,57926,N,57924,N,57927,N,57928,N,N,N,17698,57929,57930,28227, +57931,28226,N,57932,N,57933,57934,N,57935,57936,N,57937,57938,N,N,N,N,N,57939, +N,N,N,57940,57941,18003,28228,15670,15456,18267,17265,57942,N,N,15474,57943, +16236,N,28229,57944,28230,57945,57946,57947,N,N,N,N,N,57948,16221,28231,57949, +28232,N,57950,N,28233,19823,N,15671,57951,N,N,N,N,28235,28234,57952,14682,N, +14707,15168,57953,57954,57955,N,N,N,N,N,57956,28238,57957,N,57958,57959,15718, +N,28237,57960,28236,N,17001,57961,N,14447,57962,16451,57963,57964,57965,N, +18480,57966,N,N,N,15673,N,57967,N,N,57968,28239,N,15967,N,57969,N,57970,N, +28242,28240,57971,57972,57973,28241,57974,57975,57976,57977,28244,28243,57978, +N,15994,N,28245,57979,57980,57981,N,57982,28246,28247,58145,58146,N,58147, +18512,14931,15457,28248,N,28249,20004,15685,19566,20044,28250,13922,N,58148, +58149,N,28251,58150,17699,58151,58152,28254,13176,16203,58153,28252,N,28253,N, +17504,58154,58155,19285,13948,N,58156,58157,N,58158,58159,58160,58161,58162, +58163,N,N,N,28256,28257,58164,N,58165,N,58166,28255,58167,N,28259,58168,58169, +N,N,58170,58171,58172,58173,N,58174,58175,N,58176,18015,13123,N,58177,28263, +58178,58179,28260,28262,58180,N,58181,N,N,N,58182,58183,28258,N,N,N,N,58184, +58185,58186,58187,N,58188,28495,N,N,28261,N,58189,58190,58191,N,N,58192,20075, +58193,58194,14426,58195,58196,58197,N,58198,N,58199,28271,58200,N,58201,58202, +17716,28266,58203,58204,28269,28267,58205,28272,N,58206,58207,58208,28273, +58209,N,N,N,N,N,28265,58210,58211,28278,12660,58212,58213,28264,N,58214,58215, +18477,N,28268,58216,15968,58217,58218,58219,N,N,N,N,58220,58221,58222,14683,N, +N,N,58223,58224,58225,58226,58227,N,58228,58229,58230,19272,58231,13924,N,N, +15686,N,17980,N,N,58232,58233,58234,N,N,58235,58236,N,N,16685,58237,28276,N, +28270,28275,58238,19523,58401,17464,28277,28274,N,N,58402,58403,N,N,N,58404, +58405,N,58406,58407,N,N,58408,N,16684,N,58409,N,N,58410,N,N,N,58411,28281, +58412,28280,58413,58414,58415,58416,N,58417,58418,58419,58420,58421,N,58422, +58423,58424,58425,N,N,58426,58427,58428,58429,28279,58430,N,19247,58431,N, +58432,N,58433,58434,58435,N,N,58436,58437,N,58438,58439,58440,N,58441,15739, +58442,N,58443,58444,28282,19039,N,58445,12628,58446,N,58447,N,18758,17266,N,N, +N,N,13688,58448,28284,58449,14685,N,N,58450,58451,N,58452,N,N,N,15148,N,58453, +N,N,N,N,58454,N,28283,16237,58455,N,N,58456,58457,N,N,16238,28449,28451,N, +58458,58459,58460,58461,15995,58462,28450,28452,58463,58464,13907,58465,18757, +58466,58467,15458,20259,N,28286,14968,N,N,20287,58468,58469,28454,58470,58471, +N,N,28453,28455,N,N,N,N,N,N,N,N,28285,N,N,58472,58473,58474,N,18025,N,17749,N, +N,58475,58476,58477,N,17495,58478,28460,58479,58480,N,58481,17219,28456,N, +58482,N,28457,N,N,N,58483,58484,N,58485,N,58486,58487,N,14125,58488,28459, +58489,58490,58491,N,58492,58493,14384,58494,N,N,N,58657,N,28458,58658,15969, +58659,58660,58661,58662,N,N,N,N,N,58663,N,58664,58665,13177,58666,N,58667,N,N, +58668,N,28464,58669,14911,16761,58670,N,17482,58671,N,N,58672,N,N,58673,N, +58674,58675,N,58676,13115,58677,58683,N,58678,28462,28463,17475,N,28461,N,N,N, +58679,58680,58681,N,N,28465,58682,N,N,N,N,N,N,58684,N,28471,58685,58686,58687, +58688,28474,58689,58690,58691,58692,58693,N,N,28473,17709,N,58694,N,N,28466, +28467,28470,58695,N,N,58696,28472,58697,58698,N,13888,58699,N,28475,28469, +58700,58701,28468,N,N,N,N,N,N,N,N,N,N,N,N,N,N,58703,58704,58702,58705,58706,N, +58707,58708,58709,28479,58710,N,N,28480,58711,58712,N,N,N,58713,58714,58715, +28481,N,N,28478,28477,58716,58717,58718,15970,17962,28476,N,N,N,N,58719,N, +28485,N,N,N,N,N,N,N,N,N,28483,N,N,58720,58721,N,58722,58723,58724,58725,28484, +28482,N,17016,N,28486,58726,N,58728,N,58727,N,28487,N,58729,28489,58730,N,N, +58731,N,58732,N,58733,N,N,N,N,13397,28488,19578,N,58734,N,N,N,58735,28500, +28490,58736,N,28493,58737,28491,58738,28492,58739,N,N,N,N,58740,N,28494,58741, +N,58742,58743,58744,28496,58745,58746,N,N,28497,N,28498,N,N,N,N,28501,28499, +28502,28504,N,28503,N,58748,58747,17465,58749,58750,N,N,N,N,58913,N,19559,N, +28505,16686,58914,N,N,28506,58915,19012,28507,13099,58916,58917,58918,12604,N, +13399,N,13398,28508,N,28509,N,28510,28511,N,N,N,58919,58920,58921,28512,58922, +13400,13141,14686,18486,58923,28514,28513,58924,N,58925,58926,28515,N,N,N,N, +12636,N,58927,N,58928,N,N,28518,58929,28517,28516,58930,28519,58931,N,N,N, +28522,N,N,58932,12359,58933,58934,28520,58935,28524,28523,N,N,58936,58937, +58938,58939,28526,28525,28527,N,17966,58940,58941,N,28528,58942,58943,58944, +58945,28529,28531,N,58946,28530,58947,18796,58948,58949,N,N,28532,58950,N, +58951,58952,58953,N,28533,N,14949,N,58954,N,28534,28535,N,58955,19273,58956,N, +N,N,58957,58958,58959,58960,16715,58961,58962,N,12324,16971,58963,28536,N, +18797,N,N,N,N,N,N,28539,28537,14687,N,28538,14402,N,58964,N,58965,N,58966, +58967,58968,N,N,19013,28541,28705,28542,28706,N,58969,12577,16216,15740,13401, +28707,N,N,N,18278,N,28709,N,58970,N,12578,N,28708,17476,58971,20045,17963, +28540,20006,N,14385,58972,58973,19803,58974,58975,N,58976,58977,58978,58979, +13945,20020,N,14120,58980,16994,26401,N,28710,13100,16239,N,58981,N,N,13142, +28712,58982,28713,28711,14180,58983,14941,15971,58984,N,58985,12579,N,N,20057, +58986,58987,58988,28715,28206,58989,28714,N,N,N,58990,58991,28718,28716,28717, +58992,28719,N,28720,20076,28721,28722,58993,16457,18491,N,N,N,16253,13415,N,N, +19770,12909,15672,14427,N,28725,58994,28724,15219,28726,28723,N,N,15144,58995, +N,N,28730,27181,N,58997,21078,58998,16247,28728,58999,59000,59001,N,N,20005, +18033,N,N,N,N,12587,59002,16483,15414,N,N,N,59003,18999,59004,12608,N,N,N, +20077,19819,N,28731,59005,17733,15483,N,59006,59169,28732,59170,28733,16204, +28734,59171,20078,N,N,28729,28736,28738,N,28737,N,28735,N,N,28739,N,N,28740, +59172,59173,16762,59174,12898,N,N,59175,59176,59177,28741,N,N,19512,59178,N, +28742,N,N,N,N,N,28743,59179,20266,59180,N,N,N,N,23345,28744,N,N,N,28745,28746, +N,N,59181,28750,59182,28747,N,28748,N,28749,28751,59183,N,N,N,59184,59185,N,N, +16452,N,N,59186,19575,59187,59188,16453,59189,59190,28752,N,18547,N,28753, +29523,19532,59191,28754,N,28755,59192,28756,13143,59193,28758,N,16217,59194,N, +N,28759,N,59195,14116,N,59196,59197,59198,28760,28764,59199,28762,59200,N, +59201,59202,28763,N,N,13171,28761,28765,N,N,59203,N,28766,N,12360,N,28767, +28768,N,N,N,N,59204,59205,59206,15972,59207,59208,N,28769,N,59209,59210,13639, +N,59211,28772,N,N,28771,N,28770,N,N,27505,59212,19036,59213,N,N,59214,59215, +28773,28774,59216,59217,N,59218,59219,59220,N,59221,N,59222,59223,N,59224,N, +28775,59225,59226,28776,59227,28777,59228,59229,28778,59230,59231,59232,N, +59233,59234,N,13402,59235,N,N,59236,59237,59238,N,59242,28779,59239,59240,N, +59241,59243,N,N,59244,N,N,N,N,N,N,N,N,28780,18211,59245,N,59246,28782,12859, +59247,28785,28784,59248,59249,N,59250,12580,N,N,N,13889,19015,17466,14882,N, +14688,15719,59251,16220,N,59252,N,28787,59254,59255,28786,19778,13416,18514, +18012,59256,N,59257,16252,20046,59253,14171,N,59258,N,59259,N,59260,28790,N, +59261,28789,59432,59262,N,N,N,N,59425,19275,17964,59426,59427,59428,N,59429, +59430,12624,59431,N,28791,28788,N,N,18769,19818,28792,59433,N,N,N,N,N,59434,N, +28793,59435,N,N,59436,28795,17002,13147,13148,28794,N,59437,59438,59439,13417, +14386,59440,59441,13418,59442,59443,17727,N,N,20064,N,N,N,59444,59445,N,59446, +59447,14428,N,N,59448,28796,59449,N,N,28797,28798,28961,N,28963,28962,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,18807,N,28964,59450,N,59451,59452,28965,59453,28966,N,N,59454, +N,28967,59455,59456,N,59457,59458,N,N,N,59459,N,N,59460,28969,28968,59461, +28970,N,59462,N,N,N,59463,N,N,N,N,N,N,N,N,N,N,N,N,N,N,18548,26188,N,N,16169,N, +59464,13618,59465,N,59466,59467,59468,N,28971,59469,28972,N,21036,23867,18515, +N,N,12411,59470,12347,N,59471,N,N,N,N,N,15220,19248,15998,59472,28973,N,19551, +N,59473,59474,28974,19804,N,12610,N,N,N,15169,59475,28975,12910,28976,59476, +59477,59478,28977,N,59479,59480,59481,28979,28980,59482,28982,28978,59483,N, +28981,N,59484,59485,13403,N,N,59486,28983,N,28984,N,N,59487,59488,59489,59490, +59491,N,N,N,59492,59493,59494,59495,28985,28986,N,59496,59497,28987,N,N,28989, +59498,59499,59500,28988,N,28991,28994,59501,59502,N,28990,28992,28993,N,59503, +28995,N,13890,59504,59505,N,59506,59507,N,59508,59509,59510,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,15475,28996,28997,14689,N,59511,N,59512,N,59513,N,N,N,N,N,28998, +59514,N,13118,N,N,N,18255,28999,29000,N,59515,59516,59517,17242,18027,59518,N, +N,N,59681,59682,N,29001,59683,N,59684,N,18301,N,59685,16972,12632,13934,N, +13935,59686,N,N,N,N,N,N,17267,29006,13936,59687,59688,12911,N,N,29005,59689, +59690,29003,59691,29004,59692,29002,N,N,29016,N,N,N,N,59693,N,N,59694,59695, +59696,29007,29008,N,59697,29009,29010,N,59698,59699,N,N,29012,59700,N,29011,N, +59701,59702,15705,29013,59703,59704,59705,29015,N,N,N,N,N,59706,59707,N,13619, +29014,59708,59709,16763,14387,N,N,59710,N,N,29017,N,N,N,N,59711,N,59712,N, +59713,59714,59715,N,N,59716,16973,N,N,29018,N,59717,59718,N,17965,N,N,59719,N, +59720,59721,29019,59722,N,N,N,N,N,29024,N,29022,59724,29021,29023,59725,29020, +N,59723,N,N,59726,59727,59728,29026,59729,N,N,59730,N,N,59731,29025,59732, +29028,N,N,13891,29027,N,59733,N,29029,N,N,29030,N,29032,29031,N,N,N,29033, +29035,29034,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,14716,N,59734,N,59735, +29036,59736,59737,29037,N,59738,N,59739,59740,59741,N,13116,59742,N,59743, +29038,N,59744,59745,29039,59746,N,59747,16241,N,59748,N,59749,N,N,N,N,N,59750, +29040,59751,29041,59752,29042,29043,59753,59754,59755,14690,N,N,59756,59757,N, +29044,29045,59758,N,29046,29047,59759,59760,29048,59761,N,59762,18481,29050, +59763,18726,29051,29049,N,29053,59764,59765,29052,59766,N,29054,N,59767,59768, +29217,N,59769,N,59770,59771,59772,59773,59774,59937,59938,29218,N,59939,59940, +N,59941,59942,59943,59944,N,59945,N,59946,N,N,N,59947,N,29219,59948,29220, +59949,59950,N,N,29221,59951,N,29222,29223,N,29224,59952,29225,29226,29227, +29228,59953,N,59954,29229,29230,N,23861,29231,59955,59956,59957,N,59958,N, +59959,59960,25720,13620,59961,N,N,N,13089,14898,29233,29232,19493,N,N,59962,N, +N,59963,59964,29235,29236,29234,N,29237,N,N,19298,59965,59966,59967,29238,N, +13691,59968,N,N,59969,N,N,59970,N,59971,N,59972,59973,N,59974,N,59975,59976, +59977,59978,59979,20261,N,N,N,59980,29239,59981,N,59982,59983,59984,N,N,N,N,N, +59985,59986,N,N,29241,59987,59988,59989,59990,N,59991,59992,59993,N,59994, +12350,59995,59996,29242,18987,29240,59997,N,29243,29244,N,N,59998,N,N,59999, +60000,29245,29246,N,N,N,N,N,60001,60002,29247,60003,19310,15149,60004,14970, +16687,N,60005,60006,60007,N,29248,N,N,60008,60009,29251,N,60010,60011,N,60012, +60013,29249,60014,N,N,N,N,29252,60015,60016,14449,29250,N,N,N,60017,29253, +60018,29254,29255,N,29259,N,15146,60019,60020,N,N,16996,N,60021,N,60022,N, +29260,29257,29256,29258,60023,N,60024,14175,N,60025,60026,N,N,N,60027,29264, +29263,29262,60028,N,12339,N,60029,60030,60193,60194,N,N,60195,N,60196,60197,N, +60198,N,29274,N,29270,N,29271,29267,29273,60199,29269,13154,N,60200,20300, +60201,29272,29268,29266,29265,60202,N,60203,60204,60205,29276,60206,N,60207,N, +N,29279,60208,60209,29278,29277,60210,60211,60212,60213,60214,N,N,18761,29275, +12403,29280,60215,29282,N,N,60216,60217,60218,N,13167,29261,12599,N,60219, +29284,N,N,60220,N,60221,60222,60223,29283,29281,17197,60224,60225,N,N,N,60226, +60227,60228,N,19312,60229,60230,N,60231,20058,60232,N,29285,60233,60240,60234, +60235,60236,29286,N,N,60237,N,N,N,29287,60242,60238,60239,60241,N,N,60243,N, +60244,N,60245,N,N,60246,29288,60247,29289,N,N,60248,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,17467,60249,29290,N,18487,N,29295,29291,N,N,N, +29292,N,60250,19249,19524,N,18000,60251,N,60252,60254,29296,N,N,29297,17982, +29294,29293,N,60253,N,N,12842,N,N,60255,29305,N,N,29304,N,60256,60257,N,N, +12661,60258,60259,60260,29302,N,N,N,29301,N,N,29299,N,13179,N,29298,15410, +12841,N,N,60261,60262,N,60263,60264,60265,N,N,N,N,N,60266,14691,60267,60269, +29308,29307,N,29306,60270,60271,29303,60268,29309,60272,29310,N,60273,N,N,N,N, +N,29477,29476,N,60274,60275,N,N,N,N,29478,N,N,12589,29473,29474,60276,14708, +19513,60278,60277,29475,60279,N,N,N,60280,60281,60282,19250,N,N,29483,60283,N, +29479,N,N,N,60284,60285,N,N,29484,60286,60449,N,60450,N,N,N,N,60451,60452,N, +60453,29481,N,29480,60454,N,N,60455,60456,14172,N,N,60457,60458,N,60459,60460, +60461,60462,N,29485,N,N,N,N,N,N,60463,N,N,29486,N,N,N,N,29487,60464,29482, +60465,N,60466,29300,N,60467,29488,N,17505,60468,N,N,29492,60469,29493,29491, +60470,N,N,60471,N,29490,29496,60472,29489,N,29494,60473,N,60474,60475,N,N,N,N, +29495,N,N,N,29498,60476,60477,60478,60479,N,29497,60480,N,N,N,60481,60482, +60483,N,N,N,N,60484,29500,60485,N,60486,N,60487,N,29501,60488,29502,60489,N, +20297,60490,60491,N,N,N,29499,17003,14957,N,N,29503,60492,60494,N,N,N,N,60495, +N,N,60493,N,N,N,60496,N,60497,60498,60499,N,N,60500,60501,N,N,60502,29504, +29505,60503,60504,29506,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29507,N,N,14388,29508,60505,60506, +60507,29509,N,15407,60508,29510,60509,60510,60511,60512,N,60513,29511,N,N, +29512,29513,N,60514,60515,N,29516,29514,20284,N,29515,60516,20079,60517,N,N, +60518,N,29517,60519,20059,N,N,N,N,60520,29518,18302,N,60521,29519,29521,N, +60522,29522,60523,60524,60525,N,N,60526,60527,60528,N,N,29520,14701,19533, +19299,22135,N,23904,19323,N,N,N,N,12843,N,60529,N,60530,N,N,60531,29524,13648, +29525,29526,29527,N,14709,N,29528,60532,N,N,24660,19547,N,16995,29529,29531, +29530,60533,29532,N,N,N,60534,29533,N,60535,29534,N,N,N,60536,60537,60538, +29535,60539,60540,60541,N,29536,60542,29537,29538,60705,29539,N,29540,29541, +29542,N,60706,60707,60708,N,N,N,29543,29544,60709,N,N,N,N,17700,60710,60711, +60712,60713,14429,60714,29546,60715,60716,N,60717,60718,60719,N,N,N,60720, +16717,29547,60721,N,N,N,60722,N,N,N,60723,60724,29548,N,N,60725,N,60726,60727, +N,60728,N,N,60729,N,60730,60731,18721,60732,60733,29549,60734,N,60735,N,60736, +60737,60738,60739,60740,N,N,29550,25399,N,N,27738,28781,N,N,29551,60741,29552, +60742,60743,60744,60745,N,60746,N,N,60747,60748,29554,29555,29556,20080,29553, +N,N,29557,29558,60749,60750,29560,N,29559,60751,60752,60753,60754,60755,29562, +60756,N,60757,29563,29561,N,N,60758,N,N,60759,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +20022,N,60760,60761,60762,60763,N,60764,29564,60765,60766,N,N,N,N,29565,25428, +60767,N,29566,60768,60769,60770,N,60771,8490,N,8564,8560,8563,8565,N,8522, +8523,8566,8540,8484,N,8485,8511,9008,9009,9010,9011,9012,9013,9014,9015,9016, +9017,8487,8488,8547,8545,8548,8489,8567,9025,9026,9027,9028,9029,9030,9031, +9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045,9046, +9047,9048,9049,9050,8526,N,8527,8496,8498,8494,9057,9058,9059,9060,9061,9062, +9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,9073,9074,9075,9076,9077, +9078,9079,9080,9081,9082,8528,8515,8529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8497, +N,8559, +}; + +static const struct unim_index jisxcommon_encmap[256] = { +{__jisxcommon_encmap+0,92,255},{__jisxcommon_encmap+164,0,245},{ +__jisxcommon_encmap+410,199,221},{__jisxcommon_encmap+433,132,206},{ +__jisxcommon_encmap+508,1,95},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{__jisxcommon_encmap+603,16,59},{__jisxcommon_encmap+647,3,212},{ +__jisxcommon_encmap+857,0,165},{__jisxcommon_encmap+1023,18,18},{0,0,0},{ +__jisxcommon_encmap+1024,0,239},{__jisxcommon_encmap+1264,5,111},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisxcommon_encmap+1371,0,254},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisxcommon_encmap+1626,0,255},{ +__jisxcommon_encmap+1882,0,255},{__jisxcommon_encmap+2138,0,254},{ +__jisxcommon_encmap+2393,0,254},{__jisxcommon_encmap+2648,0,255},{ +__jisxcommon_encmap+2904,0,250},{__jisxcommon_encmap+3155,1,255},{ +__jisxcommon_encmap+3410,0,255},{__jisxcommon_encmap+3666,5,255},{ +__jisxcommon_encmap+3917,0,255},{__jisxcommon_encmap+4173,0,253},{ +__jisxcommon_encmap+4427,2,255},{__jisxcommon_encmap+4681,0,253},{ +__jisxcommon_encmap+4935,0,255},{__jisxcommon_encmap+5191,1,253},{ +__jisxcommon_encmap+5444,1,254},{__jisxcommon_encmap+5698,0,255},{ +__jisxcommon_encmap+5954,1,255},{__jisxcommon_encmap+6209,7,253},{ +__jisxcommon_encmap+6456,0,255},{__jisxcommon_encmap+6712,0,255},{ +__jisxcommon_encmap+6968,1,250},{__jisxcommon_encmap+7218,6,255},{ +__jisxcommon_encmap+7468,0,255},{__jisxcommon_encmap+7724,0,255},{ +__jisxcommon_encmap+7980,0,255},{__jisxcommon_encmap+8236,2,253},{ +__jisxcommon_encmap+8488,0,255},{__jisxcommon_encmap+8744,0,253},{ +__jisxcommon_encmap+8998,2,255},{__jisxcommon_encmap+9252,2,244},{ +__jisxcommon_encmap+9495,4,252},{__jisxcommon_encmap+9744,0,255},{ +__jisxcommon_encmap+10000,1,254},{__jisxcommon_encmap+10254,0,253},{ +__jisxcommon_encmap+10508,3,255},{__jisxcommon_encmap+10761,0,254},{ +__jisxcommon_encmap+11016,2,255},{__jisxcommon_encmap+11270,0,255},{ +__jisxcommon_encmap+11526,3,255},{__jisxcommon_encmap+11779,0,254},{ +__jisxcommon_encmap+12034,0,252},{__jisxcommon_encmap+12287,2,255},{ +__jisxcommon_encmap+12541,0,252},{__jisxcommon_encmap+12794,0,255},{ +__jisxcommon_encmap+13050,2,254},{__jisxcommon_encmap+13303,0,254},{ +__jisxcommon_encmap+13558,0,251},{__jisxcommon_encmap+13810,0,158},{ +__jisxcommon_encmap+13969,54,255},{__jisxcommon_encmap+14171,0,254},{ +__jisxcommon_encmap+14426,2,255},{__jisxcommon_encmap+14680,0,254},{ +__jisxcommon_encmap+14935,0,253},{__jisxcommon_encmap+15189,1,255},{ +__jisxcommon_encmap+15444,0,255},{__jisxcommon_encmap+15700,0,254},{ +__jisxcommon_encmap+15955,0,255},{__jisxcommon_encmap+16211,1,254},{ +__jisxcommon_encmap+16465,1,255},{__jisxcommon_encmap+16720,0,255},{ +__jisxcommon_encmap+16976,0,159},{__jisxcommon_encmap+17136,55,255},{ +__jisxcommon_encmap+17337,1,255},{__jisxcommon_encmap+17592,1,254},{ +__jisxcommon_encmap+17846,0,254},{__jisxcommon_encmap+18101,0,255},{ +__jisxcommon_encmap+18357,0,255},{__jisxcommon_encmap+18613,0,255},{ +__jisxcommon_encmap+18869,0,253},{__jisxcommon_encmap+19123,1,132},{ +__jisxcommon_encmap+19255,119,230},{__jisxcommon_encmap+19367,28,251},{ +__jisxcommon_encmap+19591,0,255},{__jisxcommon_encmap+19847,1,254},{ +__jisxcommon_encmap+20101,2,255},{__jisxcommon_encmap+20355,1,255},{ +__jisxcommon_encmap+20610,0,255},{__jisxcommon_encmap+20866,0,249},{ +__jisxcommon_encmap+21116,2,254},{__jisxcommon_encmap+21369,2,255},{ +__jisxcommon_encmap+21623,2,165},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__jisxcommon_encmap+21787,1,229}, +}; + +static const ucs2_t __cp932ext_decmap[969] = { +65340,65374,8741,65372,8230,8229,8216,8217,8220,8221,65288,65289,12308,12309, +65339,65341,65371,65373,12296,12297,12298,12299,12300,12301,12302,12303,12304, +12305,65291,65293,177,215,U,247,65309,8800,65308,65310,8806,8807,8734,8756, +9794,9792,176,8242,8243,8451,65509,65284,65504,65505,65285,65283,65286,65290, +65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660, +8251,12306,8594,8592,8593,8595,12307,U,U,U,U,U,U,U,U,U,U,U,8712,8715,8838, +8839,8834,8835,8746,8745,U,U,U,U,U,U,U,U,8743,8744,65506,9312,9313,9314,9315, +9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330, +9331,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,U,13129,13076,13090, +13133,13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115, +13212,13213,13214,13198,13199,13252,13217,U,U,U,U,U,U,U,U,13179,U,12317,12319, +8470,13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181, +13180,8786,8801,8747,8750,8721,8730,8869,8736,8735,8895,8757,8745,8746,32394, +35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193, +20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479, +20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013, +21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660, +21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,U,64016,22686, +22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532, +23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353, +24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887, +24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121, +26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362, +26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032, +27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759, +27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199, +28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020, +28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654, +29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063, +30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024, +64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072, +32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782, +33864,33972,34131,34137,U,34155,64031,34224,64032,64033,34823,35061,35346, +35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214, +64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357, +37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433, +37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669, +37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880, +37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735, +38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797, +39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,U,U,8560,8561, +8562,8563,8564,8565,8566,8567,8568,8569,65506,65508,65287,65282,8560,8561, +8562,8563,8564,8565,8566,8567,8568,8569,8544,8545,8546,8547,8548,8549,8550, +8551,8552,8553,65506,65508,65287,65282,12849,8470,8481,8757,32394,35100,37704, +37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224, +20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550, +20592,20546,20628,20724,20696,20810,U,20836,20893,20926,20972,21013,21148, +21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642, +21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795, +22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718, +23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423, +24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984, +25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142, +26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785, +26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184, +27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908, +28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351, +28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999, +64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650, +29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364, +30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025, +U,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092, +32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864, +33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449, +35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559, +64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348, +37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543, +37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627, +64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957, +37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741, +38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823, +39857,39867,39936,40304,40299,64045,40473,40657, +}; + +static const struct dbcs_index cp932ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{__cp932ext_decmap+0,95,202},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__cp932ext_decmap+108,64,156},{0,0,0},{0,0,0},{0,0,0},{0,0, +0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{__cp932ext_decmap+201,64,252},{__cp932ext_decmap+390,64,252},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__cp932ext_decmap+579,64,252},{__cp932ext_decmap+768,64,252},{ +__cp932ext_decmap+957,64,75},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __cp932ext_encmap[9686] = { +34690,N,N,N,N,N,N,N,N,N,N,34692,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +34644,34645,34646,34647,34648,34649,34650,34651,34652,34653,N,N,N,N,N,N,61167, +61168,61169,61170,61171,61172,61173,61174,61175,61176,34708,N,N,N,N,N,N,N,N,N, +N,N,N,N,34712,N,N,N,N,N,33121,N,N,N,N,N,N,N,N,34707,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,34713,34624,34625,34626,34627,34628,34629,34630, +34631,34632,34633,34634,34635,34636,34637,34638,34639,34640,34641,34642,34643, +34688,N,34689,34698,34699,N,N,N,N,N,N,34700,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,34693,34694,34695,34696,34697,34661,N,N,N,N,N,N,N,N,N, +34665,N,N,N,N,N,N,34656,N,N,N,34659,N,N,N,N,N,N,N,N,N,34657,34667,N,N,34666, +34660,N,N,N,34668,N,N,N,N,N,N,N,N,N,N,34662,N,N,N,N,34670,N,N,N,N,N,N,N,N,N,N, +N,N,N,34655,34669,N,N,34658,N,N,N,34663,N,N,N,N,N,34664,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,34686,34703,34702,34701,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,34674,34675,N,N,N,N,N,N,N,N,N,N,N,N,34671,34672,34673, +N,N,34677,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +34676,N,N,N,N,N,N,N,N,34691,60748,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,60749,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60750, +60751,N,N,60752,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60753,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,60754,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60756,N,N,N,N,N,N,N, +60755,N,60758,N,N,N,N,N,60757,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60741,N,N,N,60759,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,60762,60763,N,N,N,60761,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,60760,N,60766,N,N,N,60764,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60765,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60767,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60769,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60768,60770,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60771,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60772,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,60773,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60774,60775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,60776,N,N,N,N,N,N,N,N,N,60777,N,N,N,N,N,N,N,N,61019,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,60778,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60779, +60780,N,N,N,N,N,N,60781,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60783,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60784,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60785,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60786,60789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60788,N,N,N,N,N,N,N,N,N,N,N,N, +60790,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60791,60792,60793,N,N,N,N,N,N,N,N,N,N,N,60794,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60795,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60797,60796,60801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,60802,60803,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60804,N,N,N,N,N,N,N,60805,N,60806,N,N,N,N,N,60807,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,60808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60809,60810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60811,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60814,60815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60816,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60817,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60818,60819,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60822,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,60820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60823,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60824,60825,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60826,60827,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,60828,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60747,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60829,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60830,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60831,60832,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60833,N,N, +N,N,60834,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60836,N,N,N,N,N,N,N,N,60835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60838, +60839,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60837,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60841,N, +N,N,N,N,N,60840,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60842,60843,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60844,60845,60846,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60847,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60848,60849,60850,N,N,N,N,N, +N,N,N,60853,N,N,N,N,N,N,N,N,N,N,N,60851,N,N,N,N,N,N,N,N,60855,N,N,N,N,N,60856, +N,N,N,N,N,N,N,N,N,60854,N,N,60743,N,N,N,N,N,N,N,N,N,60852,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60858,N,60859,N,N,N,N,N,N,N,N,N,N,N,60857,N, +N,N,N,N,N,N,N,N,N,N,N,N,60861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60862,N,N,N,N,N,N,60863,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60864,N,N,N,N,N,N,N,N,N,N,N,N,60865,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,60866,60746,60867,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60870,N,N,N,N,60872, +60873,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60874,N,N,N,N,N,N, +N,N,N,N,N,N,N,60871,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,60744,N,N,N,N,N,N,60875,60877,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60879,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60880,60881,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60883,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60882,N,N,N,N,N,N,N,60884,N,N,N,N,N,N,N, +N,N,N,60885,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60886,N,60887,60888, +60889,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60890,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,60892,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60891,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,60893,60894,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60896,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60895,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,60897,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60898,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60899,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60901,N,N,N,N,N,60900,N, +N,N,60902,60905,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60903,N,N,60906,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60904,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,60907,60908,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60909,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,60910,60911,N,60912,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,60913,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60914,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60915,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,60742,60917,N,N,N,N,N,N,N,N,N,N,60916,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,60919,60920,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60918,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60922,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60923,60924,N,N,N,N,N,N,N,N,N,N,N,N,60992,60993,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60995,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60996,N,N,N,N,N,N,N,N,N,N,N,60997, +N,N,N,N,N,N,N,N,61000,N,N,N,60998,N,N,N,N,N,N,N,N,N,N,N,N,60999,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,61002,61001,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61003,N,N,61005,61004,N,N,N,61006,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61007, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61008,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61009,61010,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60812, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61011,61012,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61015,61013,N,61014,N,N,N,N,N,N,N,61016,61018, +61020,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61021,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61022,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61023,61024,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61028,N,N,N,N,N,N,61030,61031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61032,N,N,N,61034,61035,61037,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61038, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61040,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61039,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61041,61042,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60736,61043,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61044,61046,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61047,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61048,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61049,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61050,61051,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61052,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60740,61053,N,N,N,N, +N,61054,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61056,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61058,61061,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61062,60737,61063,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61064,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61065,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61066,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,61068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61070, +61071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61072,61073,N,N,N,61074,61075,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,61076,61078,61081,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61082,61084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61085,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61087,N,N,61086,N,N,N,61088,N,N,N, +N,N,61091,61092,N,N,N,N,N,N,N,61089,61090,61093,N,N,N,61095,N,N,N,N,N,61094,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61102,61096,N,61098,N,N,N,61097,N,N,N,N,N,N,N,N,N,N,N,N,N,61099,N,N,61101,N,N, +N,N,N,N,N,61100,N,N,N,N,N,N,N,N,N,N,N,N,N,61103,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61105,61106,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60739,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61104,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61110,N,N,61114,N,61112,N,61108,N,61109, +N,N,N,N,N,N,61113,N,N,N,N,N,N,61107,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60745,N, +61117,N,N,N,61120,61122,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61121,61119,N,N,61116,N,N,N,61115,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,60738,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61124,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61125,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61126,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61127,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61128,61129,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61130,N,N,61131, +61132,61135,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61136,61137,N,N,N,N,N,N,N,61138, +N,N,N,N,N,N,N,61139,N,N,N,N,N,N,N,N,N,61140,N,61141,N,61142,N,N,N,61143,61144, +N,N,N,N,N,N,N,N,N,N,N,N,N,61145,61148,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61150,61151,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61152,N,N,61153,61155,N,N,61154,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,61156,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61157,N,N,N,N,N,N,N,N,N,61158,61159,61161,N,N,N,N,61160,61163,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61164,60868,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61133,60787,60798,60800,60821,60860,60876,60878, +60921,60994,61017,61025,61026,61027,61029,61033,61036,61045,61057,61059,61060, +61069,61077,61079,61080,61083,61111,61118,61134,61146,61147,61149,61162,61180, +N,N,N,N,61179,N,N,N,N,N,33148,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,33119,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,33120,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,33169, +33170,33226,N,61178, +}; + +static const struct unim_index cp932ext_encmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp932ext_encmap+0,22,121},{__cp932ext_encmap ++100,17,191},{0,0,0},{__cp932ext_encmap+275,96,115},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__cp932ext_encmap+295,29,31},{0,0,0},{__cp932ext_encmap+298,49,168},{ +__cp932ext_encmap+418,3,205},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{__cp932ext_encmap+621,40,252},{__cp932ext_encmap+834,0,255},{ +__cp932ext_encmap+1090,30,244},{__cp932ext_encmap+1305,74,236},{ +__cp932ext_encmap+1468,21,219},{__cp932ext_encmap+1667,0,221},{ +__cp932ext_encmap+1889,138,255},{__cp932ext_encmap+2007,134,134},{0,0,0},{ +__cp932ext_encmap+2008,89,200},{__cp932ext_encmap+2120,158,178},{ +__cp932ext_encmap+2141,11,186},{0,0,0},{__cp932ext_encmap+2317,86,236},{ +__cp932ext_encmap+2468,30,245},{__cp932ext_encmap+2684,39,208},{0,0,0},{ +__cp932ext_encmap+2854,33,222},{__cp932ext_encmap+3044,93,242},{ +__cp932ext_encmap+3194,17,152},{__cp932ext_encmap+3330,19,166},{ +__cp932ext_encmap+3478,245,245},{__cp932ext_encmap+3479,96,206},{ +__cp932ext_encmap+3590,78,78},{__cp932ext_encmap+3591,0,251},{ +__cp932ext_encmap+3843,14,192},{__cp932ext_encmap+4022,1,207},{ +__cp932ext_encmap+4229,104,226},{__cp932ext_encmap+4352,48,228},{ +__cp932ext_encmap+4533,214,214},{__cp932ext_encmap+4534,63,218},{ +__cp932ext_encmap+4690,4,252},{__cp932ext_encmap+4939,39,191},{ +__cp932ext_encmap+5092,136,245},{__cp932ext_encmap+5202,5,187},{ +__cp932ext_encmap+5385,4,254},{__cp932ext_encmap+5636,177,190},{ +__cp932ext_encmap+5650,36,245},{__cp932ext_encmap+5860,7,159},{ +__cp932ext_encmap+6013,1,111},{__cp932ext_encmap+6124,130,166},{ +__cp932ext_encmap+6161,70,70},{__cp932ext_encmap+6162,33,122},{ +__cp932ext_encmap+6252,48,155},{__cp932ext_encmap+6360,209,235},{ +__cp932ext_encmap+6387,158,158},{0,0,0},{__cp932ext_encmap+6388,72,214},{ +__cp932ext_encmap+6531,82,138},{__cp932ext_encmap+6588,71,161},{0,0,0},{0,0,0 +},{0,0,0},{__cp932ext_encmap+6679,1,246},{__cp932ext_encmap+6925,72,220},{ +__cp932ext_encmap+7074,83,176},{0,0,0},{0,0,0},{__cp932ext_encmap+7168,7,245}, +{__cp932ext_encmap+7407,28,28},{__cp932ext_encmap+7408,18,246},{ +__cp932ext_encmap+7637,83,127},{__cp932ext_encmap+7682,240,244},{ +__cp932ext_encmap+7687,18,118},{__cp932ext_encmap+7788,207,207},{0,0,0},{ +__cp932ext_encmap+7789,103,222},{__cp932ext_encmap+7909,21,238},{ +__cp932ext_encmap+8127,6,255},{__cp932ext_encmap+8377,2,248},{ +__cp932ext_encmap+8624,49,72},{__cp932ext_encmap+8648,146,146},{ +__cp932ext_encmap+8649,157,175},{__cp932ext_encmap+8668,51,85},{ +__cp932ext_encmap+8703,87,101},{__cp932ext_encmap+8718,39,158},{ +__cp932ext_encmap+8838,78,220},{__cp932ext_encmap+8981,114,187},{ +__cp932ext_encmap+9055,0,0},{__cp932ext_encmap+9056,107,112},{ +__cp932ext_encmap+9062,25,209},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp932ext_encmap+9247 +,41,220},{__cp932ext_encmap+9427,14,45},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__cp932ext_encmap+9459,2,228}, +}; + +static const ucs2_t __jisx0213_1_bmp_decmap[2197] = { +65287,65282,65293,126,12339,12340,12341,12347,12348,12543,12447,U,U,U,U,U,U,U, +U,8836,8837,8842,8843,8713,8709,8965,8966,U,U,U,U,U,U,U,8853,8854,8855,8741, +8742,10629,10630,12312,12313,12310,12311,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,8802, +8771,8773,8776,8822,8823,8596,U,U,U,U,U,U,U,U,9838,9835,9836,9833,9655,9654, +9665,9664,8599,8600,8598,8601,8644,8680,8678,8679,8681,10548,10549,U,U,U,U,U, +U,U,U,U,U,10687,9673,12349,65094,65093,9702,8226,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,8723,8501,8463,13259,8467,8487,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12448,8211,10746,10747,12363,U,12365,U,12367,U, +12369,U,12371,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12436,12437, +12438,12459,U,12461,U,12463,U,12465,U,12467,U,U,U,U,U,U,U,12475,U,U,U,U,U,U,U, +U,12484,U,U,U,12488,9828,9824,9826,9830,9825,9829,9831,9827,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,962,9461,9462,9463,9464,9465,9466,9467,9468, +9469,9470,9750,9751,12320,9742,9728,9729,9730,9731,9832,9649,12784,12785, +12786,12787,12788,12789,12790,12791,12792,12793,U,12794,12795,12796,12797, +12798,12799,9150,9151,9152,9153,9154,9155,9156,9157,9158,9159,9160,9161,9162, +9163,9164,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +12535,12536,12537,12538,8922,8923,8531,8532,8533,10003,8984,9251,9166,12881, +12882,12883,12884,12885,12886,12887,12888,12889,12890,12891,12892,12893,12894, +12895,12977,12978,12979,12980,12981,12982,12983,12984,12985,12986,12987,12988, +12989,12990,12991,U,U,U,U,U,U,U,U,9680,9681,9682,9683,8252,8263,8264,8265,461, +462,464,7742,7743,504,505,465,466,468,470,472,474,476,8364,160,161,164,166, +169,170,171,173,174,175,178,179,183,184,185,186,187,188,189,190,191,192,193, +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212, +213,214,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232, +233,234,235,236,237,238,239,240,241,242,243,244,245,246,248,249,250,251,252, +253,254,255,256,298,362,274,332,257,299,363,275,333,260,728,321,317,346,352, +350,356,377,381,379,261,731,322,318,347,711,353,351,357,378,733,382,380,340, +258,313,262,268,280,282,270,323,327,336,344,366,368,354,341,259,314,263,269, +281,283,271,273,324,328,337,345,367,369,355,729,264,284,292,308,348,364,265, +285,293,309,349,365,625,651,638,643,658,620,622,633,648,598,627,637,642,656, +635,621,607,626,669,654,609,331,624,641,295,661,660,614,664,450,595,599,644, +608,403,339,338,616,649,600,629,601,604,606,592,623,650,612,652,596,593,594, +653,613,674,673,597,657,634,615,602,U,509,8048,8049,U,U,U,U,U,U,U,U,8050,8051, +865,712,716,720,721,774,8255,779,769,772,768,783,780,770,741,742,743,744,745, +U,U,805,812,825,796,799,800,776,829,809,815,734,804,816,828,820,797,798,792, +793,810,826,827,771,794,10102,10103,10104,10105,10106,10107,10108,10109,10110, +10111,9451,9452,9453,9454,9455,9456,9457,9458,9459,9460,8560,8561,8562,8563, +8564,8565,8566,8567,8568,8569,8570,8571,9424,9425,9426,9427,9428,9429,9430, +9431,9432,9433,9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445, +9446,9447,9448,9449,13008,13009,13010,13011,13012,13013,13014,13015,13016, +13017,13018,13019,13020,13021,13022,13023,13024,13025,13026,13027,13050,13033, +13029,13037,13036,U,U,U,U,U,U,U,U,U,8273,8258,9312,9313,9314,9315,9316,9317, +9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,8544, +8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,13129,13076,13090,13133, +13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115,13212, +13213,13214,13198,13199,13252,13217,8555,U,U,U,U,U,U,U,13179,12317,12319,8470, +13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181,13180, +U,U,U,8750,U,U,U,U,8735,8895,U,U,U,10070,9758,20465,U,13314,20008,20015,20016, +20109,20193,20221,20223,20227,20235,20320,20296,20297,20310,20319,20330,20332, +20350,20362,20372,20375,64048,20425,20448,20481,20482,20494,20504,20519,20526, +20544,20539,20545,20628,20684,20722,20688,20710,64049,20742,20739,20747,20766, +20789,20810,64050,20821,20823,13493,20893,20931,20938,20958,20962,20974,20993, +13531,21011,21013,21065,21079,21089,21139,21192,64051,21196,21200,21206,21211, +64052,21232,21243,21248,21255,21276,64053,21345,21347,21373,21395,21405,21426, +21522,21543,21581,21660,21611,21620,21631,21640,21654,21665,21673,21702,21759, +21774,21803,21813,21840,21854,21889,21894,21902,64054,21933,21966,64055,22024, +22030,22075,22089,22134,22118,64056,22127,22129,22130,22169,22174,22185,22188, +22195,22217,22218,22282,U,22305,22319,22323,22324,22384,22391,22396,22428, +64015,U,22456,22471,22472,22479,22500,22509,22517,22518,22527,22537,64016, +22625,22628,64057,22652,22665,22686,64058,22697,U,22738,22734,22740,22746, +22752,22761,22796,34369,22877,22893,22923,22930,22948,22979,22994,23005,23059, +23075,23143,23149,23159,23166,23172,23198,23207,23236,U,23321,23333,21085, +23361,23382,23421,23443,23512,23532,23570,23582,23587,23595,14221,23650,64059, +64060,U,23674,23695,23711,23715,23722,23738,23755,23760,23762,23796,U,14306, +23821,23847,64017,23878,23879,23891,23882,23917,23937,23968,23972,23975,23992, +24011,21534,22099,24034,24084,24088,24152,24158,24254,63784,24267,24313,24320, +24322,24327,24349,24355,24372,24374,24381,24384,24389,24404,24408,24420,24423, +24445,24457,24476,24487,24495,24501,24503,24521,24542,24545,24553,24589,24596, +24600,24627,24629,24647,64061,24733,24734,24779,24788,24789,24797,24824,24860, +24875,24880,24887,64062,24973,64063,25020,25017,64064,25122,25150,25155,25174, +25178,25199,25221,25284,25302,25340,25354,25368,25401,25411,25445,25468,25573, +25581,25589,25616,25620,25634,25721,25681,25696,25709,25806,25790,25791,25796, +25802,25808,25847,25851,25890,25897,64065,25959,26013,64066,26112,26121,26133, +26142,26170,26146,26148,26155,26160,26161,26163,26363,26184,26188,U,26201, +26202,26209,26213,26227,26231,26232,26253,64067,26272,26290,26299,26310,26312, +15138,26331,26344,26362,26387,63785,26419,26470,26439,26440,26491,26497,26515, +26520,26523,26555,26617,26560,26583,26620,26625,26706,26653,26668,26673,26715, +26738,26741,64068,26787,26789,26802,26824,26832,26856,26861,26864,26865,26876, +26890,26953,U,26933,26946,26967,26979,26980,26984,27008,64020,27045,27053, +27087,15286,15299,27106,27113,27114,27125,27126,27151,27157,U,27195,27198, +27205,27216,27222,27227,27243,27251,U,27273,27284,27293,27294,27301,27364, +27367,15375,63773,27419,27422,27436,27445,27462,27478,27488,27493,27495,27511, +27522,27561,27565,63856,27599,27606,27607,27647,27653,27664,27699,27737,27740, +27818,27764,27766,27781,27782,27800,27804,27899,27846,27860,27872,27883,27886, +U,27908,27918,27950,27953,27961,27967,27992,28005,64069,28034,28039,28041, +28052,28074,28076,28095,28100,28118,28122,28123,28125,28156,64070,28212,28228, +28252,28254,28331,28337,28353,28359,28366,28432,28442,64071,28458,28463,28467, +28497,28505,28510,28513,28514,28542,28552,28556,28557,28564,28576,28583,28598, +28604,28615,28618,28665,28656,28661,28677,28678,28712,28746,28765,28766,28750, +28772,28789,28805,28836,28843,28855,28884,28888,28900,28943,28971,28958,28960, +28974,28976,28998,28999,29009,64072,29010,29020,29024,29032,64021,29061,29063, +29074,29121,29114,29124,29182,29184,29205,29269,29270,15935,29325,29339,29374, +29376,29435,U,29479,29480,64022,29520,29542,29564,29589,29599,29600,29602, +29606,29611,29641,29647,29654,29657,29667,29673,29703,29706,29722,29723,64074, +29734,29736,29738,29739,29740,29742,29743,29744,29764,29766,29767,29771,29783, +29794,29803,29805,29830,29831,29833,29848,29852,29855,29859,29840,29862,29864, +29865,29877,29887,29896,29897,29914,29951,29953,29975,29999,30063,30073,30098, +16242,30158,30180,30208,30210,30216,30229,30230,30233,30238,30253,30261,30275, +30283,30308,30309,30317,30319,30321,30337,30363,30365,30366,30374,30378,30390, +30405,30412,30414,30420,30438,30449,30460,30474,30489,30516,30518,30534,30541, +30542,30556,30559,30562,30586,30592,30612,30634,30688,30765,30787,30798,30799, +30801,30824,30830,64075,30896,U,30893,30948,30962,30976,30967,31004,31022, +31025,31028,64076,64077,31045,31046,64078,64079,64080,31068,64081,64025,64026, +31097,64082,64083,64027,31128,31153,31160,31176,31178,U,31188,31198,31211, +31213,31235,64084,31289,31325,31341,64085,31365,31392,U,31411,31419,31438, +31467,31485,31506,31533,31547,31559,31566,31584,31597,31599,31602,31646,64086, +31703,31705,31745,31793,31774,31776,31795,31798,16996,U,31833,31853,31865, +31887,31892,31904,31932,31957,31961,31965,32007,32008,32019,32029,32035,32049, +32065,32072,32083,32092,32122,32131,32139,32160,32166,32194,32204,32214,32227, +64087,32296,32264,32273,32277,64089,32327,32338,32353,32394,32397,32583,64090, +32657,32663,32703,32718,32731,32735,32748,32750,32762,64091,32788,32806,32821, +32823,32828,32970,32983,32992,33011,33048,33098,33120,33127,33128,33133,33211, +33226,33231,33239,64092,17491,17499,33376,33396,U,33422,33441,33443,33444, +33449,33454,33463,33470,33471,33478,33493,33533,33534,33536,33537,33634,33570, +33581,33594,33603,33607,33617,33621,33661,33670,33682,33688,33703,33705,33727, +33728,33735,33743,33745,33761,33770,33793,33798,33802,64095,33864,33887,33904, +33907,33925,33950,33967,33972,33978,33984,33986,U,34098,34078,34083,34095, +34137,34148,64031,34221,34170,34188,34191,34210,34224,34251,34254,34285,34322, +34303,34308,34309,34320,U,34328,34345,34360,34391,34395,63798,34402,17821, +34412,34421,34456,34488,34554,34556,34557,34571,34673,34695,34696,34732,34733, +34741,17898,34774,34796,34822,34826,34832,34836,34847,34968,34986,35018,35022, +U,35061,35100,64096,35096,35097,35098,35111,35120,35122,35129,35136,35220, +64097,35284,35301,35318,35346,35349,35362,35383,35399,35406,35421,35425,35445, +35449,35495,35536,35551,35572,35574,64034,64098,64099,35654,35668,35673,35689, +35741,35913,35944,64100,36065,36084,36088,36094,64101,36114,36123,36271,36302, +36305,36311,36384,36387,36413,36464,36475,U,36544,18500,36602,36638,36653, +36662,36692,U,36774,36789,36836,36840,36846,36872,36909,64103,37000,37013, +37015,37017,37019,37026,37043,37054,37060,37061,37063,37079,37085,37086,37103, +37108,64038,37140,37141,37142,37154,37155,37159,37167,37169,37172,37181,37192, +37211,37251,37278,37292,37297,37308,37335,37371,37348,37349,37357,37361,37383, +37392,37432,37433,37434,37436,37440,37443,37455,37496,37512,37570,37579,37580, +37587,37600,37631,37636,37663,37665,37669,37704,37705,37706,37732,37733,37738, +37744,37787,37795,37818,37830,37854,37855,37892,37885,37939,37962,37987,37995, +38001,38002,38286,38303,38310,38313,38316,38326,38333,38347,38352,38355,18864, +38362,38366,38488,38532,63964,38557,38564,38565,38610,38622,64104,38633,38639, +38707,38715,38733,38734,38735,38746,38766,38771,38805,38830,38842,38849,38857, +38878,38875,38900,64105,38922,38942,38955,38960,64106,38994,38995,38998,38999, +39001,39002,63952,39013,39020,39098,39112,39143,39256,39326,39426,39427,39460, +39469,39470,39480,39498,39502,39506,39606,39617,39619,39630,39638,39673,39682, +39688,39712,19479,39725,39774,39801,39782,39794,39797,39812,39818,39823,39838, +39847,39873,39886,39909,39928,39933,39936,39971,40001,40015,40016,40019,40035, +40037,40055,40221,40222,40259,40263,40274,40291,40304,40316,40330,40342,40384, +40364,40380,40407,U,40423,40455,40469,40572,40606,40612,40620,40623,40628, +40629,40643,40657,40720,40761,40791,40848,40852,40855,40866,23032,23643,24183, +30246,32363, +}; + +static const struct dbcs_index jisx0213_1_bmp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_1_bmp_decmap+0,47,125},{ +__jisx0213_1_bmp_decmap+79,33,126},{__jisx0213_1_bmp_decmap+173,43,118},{ +__jisx0213_1_bmp_decmap+249,43,72},{__jisx0213_1_bmp_decmap+279,57,126},{ +__jisx0213_1_bmp_decmap+349,66,126},{__jisx0213_1_bmp_decmap+410,65,124},{ +__jisx0213_1_bmp_decmap+470,33,126},{__jisx0213_1_bmp_decmap+564,33,126},{ +__jisx0213_1_bmp_decmap+658,33,126},{__jisx0213_1_bmp_decmap+752,33,126},{ +__jisx0213_1_bmp_decmap+846,33,126},{__jisx0213_1_bmp_decmap+940,33,126},{ +__jisx0213_1_bmp_decmap+1034,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_1_bmp_decmap+ +1128,85,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_1_bmp_decmap+1170,39,126},{__jisx0213_1_bmp_decmap+1258,33,126},{ +__jisx0213_1_bmp_decmap+1352,33,126},{__jisx0213_1_bmp_decmap+1446,33,126},{ +__jisx0213_1_bmp_decmap+1540,33,125},{__jisx0213_1_bmp_decmap+1633,33,126},{ +__jisx0213_1_bmp_decmap+1727,33,126},{__jisx0213_1_bmp_decmap+1821,33,126},{ +__jisx0213_1_bmp_decmap+1915,33,126},{__jisx0213_1_bmp_decmap+2009,33,126},{ +__jisx0213_1_bmp_decmap+2103,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __jisx0213_2_bmp_decmap[2425] = { +19970,19983,19986,20009,20011,20014,20032,20039,20040,U,20049,13318,U,20058, +20073,20125,13356,13358,20153,20155,U,20156,20163,20168,20176,20203,20186, +20209,20213,20224,20246,20324,20279,20286,20308,20312,U,20343,20344,20346, +20349,20354,20357,20370,20378,20454,20402,20414,20421,20427,20431,20434,13418, +20466,20480,20496,20499,20508,20510,20514,13416,20546,20550,20558,20563,20567, +20579,20582,20586,20592,20643,20616,20626,20627,20629,20630,20636,20650,U, +20657,20666,20667,20676,20679,20723,U,20686,U,20692,20697,20705,20713,13458, +20744,U,20759,20763,U,20832,U,20851,20867,20875,13500,20888,20899,20909,13511, +20924,U,U,20979,20980,20994,21010,21014,U,21077,21084,21100,21111,21124,21122, +U,21144,U,21156,21158,21167,21178,21179,21194,13599,21201,U,21239,21258,21259, +21284,21301,21310,21314,U,U,21351,21356,21370,21412,21428,U,21431,21440,U, +13661,13662,21461,21466,13667,21492,21493,21589,21540,21544,13678,21571,21602, +21606,21612,21642,21645,21653,21664,21670,21677,21678,21687,21690,21695,21699, +U,21740,21743,21745,21747,21760,21761,21769,21820,21825,13734,21831,21834, +13736,21856,21857,21860,U,21885,21890,21896,21905,13765,21970,U,U,21951,21961, +21964,21969,21981,13786,21986,U,21993,22056,U,22023,22032,22064,22071,13812, +22077,22079,22080,22087,22110,22112,22125,13829,22152,22156,22165,22170,22173, +22184,22189,22194,22213,22221,22239,22248,22262,22263,U,22293,22307,U,22313,U, +22341,22342,22348,22349,U,22376,22383,22387,22388,22389,22395,U,U,22444,22426, +22429,22430,22440,22487,U,22476,U,U,22494,22502,22512,13898,22520,22523,22525, +22532,22558,22560,22567,22578,22585,U,22601,22604,22631,22666,22667,22669, +22671,22672,22676,22685,22698,22705,U,22723,22733,22754,22771,22772,22789, +22790,22795,22797,22804,22820,U,13969,22845,13977,22854,13974,U,22875,22879,U, +22901,22902,22908,22943,22958,22972,22984,22989,23006,23011,23012,23015,23022, +U,U,14031,23052,23053,23063,23079,23085,23125,23141,23162,23179,23196,23199, +23200,23202,23217,23219,23221,23226,23231,23258,23260,23264,23269,23280,23278, +23285,23296,23304,23319,23348,23341,23372,23378,23400,23407,23420,23423,23425, +23428,23446,23468,14177,23488,14178,23502,23510,14188,14187,23537,23549,14197, +23555,23593,23600,U,23647,23651,23655,23656,23657,23664,U,U,23676,U,U,23688, +23690,14273,U,U,23712,23714,23718,23719,U,23725,23733,U,23753,U,U,23814,23824, +23851,23837,23840,23844,23846,23857,23865,23874,14312,23905,23914,14324,23920, +U,14333,23944,14336,23954,23956,23959,23961,23984,23986,23988,U,23993,24017, +24023,24024,24032,U,24036,24041,14383,24064,14390,24082,24085,14400,24095, +24110,24126,24137,14428,24150,14433,24171,24172,24173,24174,U,24229,24234, +24236,24249,24255,24262,24274,24281,U,24317,24328,24334,24348,U,24350,24391, +24419,24434,24446,24463,24482,24484,24504,24516,14586,24519,24523,24530,24531, +24532,24546,24558,24559,24563,24572,14615,24599,24610,24612,14618,24652,24703, +24714,24725,24744,U,24752,24753,24766,24776,24793,24795,24814,24818,24821, +24848,24850,24851,24857,24862,24890,14703,24897,24902,24928,24956,U,24978, +24979,24983,24984,24997,25000,25005,U,25045,25053,25055,25077,U,25109,25123, +25129,25158,25164,25169,25170,25185,25188,25211,25197,25203,25241,25254,25301, +U,25341,25347,25357,25360,U,U,25394,25397,25403,25404,25409,25412,25422,U, +25433,U,U,25452,25476,25497,U,25492,25533,25591,25556,25557,25564,25568,25579, +25580,25586,25609,25630,25637,25641,25647,25690,25691,25693,25715,25725,25735, +25745,25757,25759,25803,25804,25813,25815,U,25828,25829,25855,25860,14958, +25871,25876,25878,14963,25886,25906,25924,25940,25963,25978,25985,25988,25989, +25994,26034,26037,26040,26047,26050,26057,26068,15062,26098,26105,26108,26116, +26120,26145,26154,26181,26193,26190,15082,U,26199,26203,26211,U,U,26218,26219, +26220,26221,26235,26240,26256,26258,26265,15118,26285,26289,26293,15130,26303, +15132,26348,15063,26369,26373,26386,U,26393,U,U,26444,26445,26452,26461,U,U,U, +26484,26486,U,26514,U,33635,26640,26544,26546,26563,26568,26578,26585,26587, +26608,26615,U,U,U,26648,26655,26669,U,26675,26683,26686,26692,26693,26697, +26700,26709,26711,15223,26731,26734,26746,26748,26754,26768,26774,15213,26776, +26777,26778,26780,26794,26795,26804,26811,26875,U,U,64019,26819,26821,26828, +26831,26838,26841,26852,26853,26860,26871,26883,26887,15239,15240,U,26939, +15245,26950,26985,26988,26994,27002,27007,27026,15268,27030,27032,27046,27056, +27063,27066,27068,27072,27089,27094,U,U,27184,U,U,27107,27118,27119,27123, +15309,27124,27134,27153,27162,27165,U,27186,27187,27188,27199,27206,27209, +27258,27214,27218,27236,U,27262,27267,27275,15344,27281,27295,27297,U,27307, +27325,27334,27348,27344,27356,27357,U,U,27372,27377,27378,27379,27389,U,27403, +27407,27408,27409,U,27415,15398,27439,27466,27480,27500,27509,27514,27521, +27547,27566,U,27581,27582,27591,27592,27593,27610,27622,27623,27630,27633, +27650,27658,27662,27701,27702,27706,U,27711,27725,27739,27757,27780,27785, +15555,27796,27797,27799,27821,27842,27856,15570,27862,27866,27868,27881,27884, +27885,U,27904,27914,27940,27942,27943,27751,27951,27964,27995,27998,28000, +28016,28032,28033,28042,28045,28049,28056,U,28183,U,U,U,28075,28078,28084, +28098,27956,28104,28110,28111,28112,28127,28137,28150,28214,28190,28194,28199, +15633,28210,28220,28232,28233,28235,28236,28239,28241,28243,28244,28247,28259, +15646,28307,28327,28340,28351,28355,28362,28377,28469,28395,28409,28411,28426, +28428,28440,28453,28470,28476,U,28498,28503,28506,28512,28520,28568,28541, +28560,28566,28606,28575,28581,28591,15716,28597,28616,28617,28634,28638,28649, +U,28668,28672,28679,28682,28707,U,28729,28730,28732,28739,28743,28747,15770, +28756,28773,28777,28780,28782,28790,28798,28801,28806,28821,28823,28859,U, +28831,28849,U,28908,28874,28881,28883,28892,28931,28932,28934,28935,28936, +28940,15808,28975,28977,29008,29002,29011,29022,15828,29078,29056,29083,29088, +29090,29102,29103,29107,U,29131,29139,29145,29148,29191,15877,64073,29227, +29236,29240,29241,20012,29250,29267,29271,29283,U,29294,29295,29304,29311, +29326,U,29357,29358,29360,29361,29377,15968,29388,15974,15976,29427,29434, +29447,29458,29464,29465,16003,29497,29484,29489,29491,29501,29522,16020,29547, +29548,U,29550,29551,29553,29559,29569,29573,29578,29588,29592,29596,29598, +29605,29608,29621,29623,29625,29628,29631,29637,29643,29665,29671,29689,29715, +29690,29697,29732,29745,29753,29779,29760,29763,29773,29778,29789,29809,29825, +29829,29832,U,29842,29847,29849,29856,29857,29861,29866,29867,29881,29883, +29882,29910,29912,29918,29935,29931,U,29946,U,29984,29988,29994,16215,U,30013, +30014,30016,30024,30030,30032,30034,30060,30066,30065,30074,30077,30078,30081, +U,30092,16245,30114,16247,30128,30135,30143,30144,30150,30159,30163,30173, +30175,30176,30183,30188,30190,30193,30201,30211,30232,30215,30223,16302,U, +30227,30235,30236,U,30245,30248,30268,30259,U,16329,30273,U,30281,30293,16343, +30318,30357,30364,30369,30368,30375,30376,30383,U,30409,U,30440,30444,U,30487, +30490,30509,30517,16441,U,U,30552,30560,30570,U,30578,30588,30589,U,16472, +30618,30623,30626,30628,30633,30686,30687,30692,30694,30698,30700,16531,30704, +30708,30715,U,30725,30726,30729,30733,30745,30753,30764,30791,30820,30826,U, +30858,30868,30884,30877,30878,30879,30907,30920,30924,30926,30933,30944,30945, +30950,30969,30970,30971,30974,U,30992,31003,31024,31013,31035,31050,31064, +31067,16645,31079,31090,31124,31125,31126,31131,31137,31145,31156,31163,31170, +31175,31180,31181,31190,16712,U,U,16719,31242,31249,31253,31259,31262,16739, +31277,31288,31303,31308,31318,31321,31324,31327,31328,31335,31338,31349,31352, +31362,31370,31376,31395,31404,U,16820,31417,31420,31422,16831,31436,31441, +31463,31464,31476,U,U,31495,U,31549,31527,31530,31534,31535,31537,16870,16883, +31615,31553,16878,31573,31609,31588,31590,31593,31603,U,16903,31632,31633, +31643,16910,31663,31669,31676,31685,31690,U,U,31700,31702,31706,31722,31728, +31747,31755,31758,31759,31782,31813,31818,31825,31831,31838,31841,31849,31854, +31855,31856,U,U,U,31910,U,31926,31927,31935,U,31940,U,31944,31949,U,31959,U, +31974,31979,U,31989,32003,32009,17094,32018,32030,U,U,32061,32062,32064,32071, +U,U,17110,32089,32090,32106,32112,17117,32127,U,32134,32136,32140,32151,U, +32157,32167,32170,32182,32183,32192,32215,32217,32230,32241,32249,17154,U, +64088,32272,32279,32285,32288,32295,32300,32325,32371,32373,32382,32390,32391, +17195,32401,32408,32410,17219,32572,32571,32574,32579,32580,32591,13505,U, +32594,U,32609,32611,32612,32621,32637,32638,U,32656,20859,U,32662,32668,32685, +U,32707,32719,32739,32741,32751,32754,32770,32778,32776,32782,32785,32790, +32804,32812,32816,32835,32870,32881,32885,32891,32921,32924,32932,32935,32952, +U,32965,32981,32984,32998,U,33037,33013,33019,17390,33077,33046,33054,17392, +33060,33063,33068,U,33085,17416,33129,17431,33153,17436,33156,33157,17442, +33176,33202,33217,33219,33238,33243,U,33252,U,33260,U,33277,33279,U,33284,U, +33305,33313,33314,U,33330,33332,33340,33350,33353,33349,U,33355,17526,33359, +17530,33367,U,33372,33379,U,64093,64094,33401,17553,33405,33407,33411,33418, +33427,33447,33448,33458,33460,33466,33468,33506,33512,33527,33543,33544,33548, +33620,33563,33565,33584,33596,33604,33623,17598,33663,17620,17587,33677,33684, +33685,33691,33693,33737,33744,33748,33757,33765,33785,33807,33809,33813,U, +33815,33849,33866,33871,33873,33874,33881,33882,33884,U,33893,33910,33912, +33916,33921,17677,34012,33943,33958,33982,17672,33998,33999,34003,U,34023, +34026,34031,34032,34033,34042,34045,34060,34075,34084,34085,34091,34100,34127, +34159,17701,17731,34110,34129,34131,34142,34145,34146,U,34171,34173,34175, +34177,34182,34195,34205,34207,34231,34236,34247,34250,34264,34265,34271,34273, +34278,34294,34304,34321,34334,34337,34340,34343,U,34361,34364,U,34368,64032, +34387,34390,34415,34423,34426,34439,34441,34445,34449,34460,34461,34472,64033, +34481,34483,34497,34499,34513,34517,34519,34531,34534,17848,34565,34567,34574, +34576,34579,34585,34591,34593,34595,34609,34618,34622,34624,34627,34641,34648, +34660,34661,34674,34684,U,U,34727,34697,34699,34707,34720,U,17893,34750,U, +34753,34766,34805,34783,U,34787,34789,34790,34794,34795,34797,34817,34819, +34827,34835,34856,34862,34866,34876,17935,34890,34904,34911,34916,U,U,34921,U, +34927,34976,35004,35005,35006,35008,35026,U,35025,35027,35035,35056,35057, +17985,35073,U,35127,U,35138,35141,35145,U,18021,35170,35200,35209,35216,35231, +35248,35255,35286,35288,35307,18081,35313,35315,35325,35327,18095,35345,35348, +U,35361,35381,35390,35397,35405,35416,35502,35472,35511,35518,35543,35580,U, +35594,35589,35597,35612,35615,35629,35651,18188,35665,35678,35702,35711,35713, +35723,35732,35733,35740,35742,35897,U,35901,U,U,35909,35911,35919,35924,35927, +35945,35949,35955,U,35987,35986,35993,18276,35995,36004,36054,36053,36057,U, +36080,36081,U,36105,36110,36204,36228,36245,36262,U,36294,36296,36313,36332, +36364,18429,36349,36358,U,36372,36374,36385,36386,36391,U,18454,36406,36409, +36427,36436,36450,36460,36461,36463,36504,36510,36526,36531,36533,36534,36539, +U,36561,36564,18510,36601,U,36608,36616,36631,36651,36672,36682,36696,U,36772, +36788,64102,36790,U,36801,36806,64036,36810,36813,36819,36821,36832,36849, +36853,36859,36866,36876,36919,U,36931,36932,36957,36997,37004,37008,38429, +37025,18613,37040,37046,37059,37064,U,37084,37087,U,37110,37106,37120,37099, +37118,37119,37124,37126,37144,37148,37150,37175,37177,37178,37190,37191,37207, +37209,37217,37220,37236,37241,37253,37262,37288,37294,37299,37302,37315,37316, +37338,U,U,37356,37358,37377,37386,37398,37399,U,37427,37442,37447,37450,37454, +37457,37462,37465,37472,37473,37477,37479,37480,U,U,37500,37501,37503,37513, +37517,37527,37529,37535,37543,37547,U,U,37554,37567,37568,37574,37582,37584, +37591,37593,37605,37607,37649,37623,37625,37627,37634,37645,37653,37661,37662, +37671,37673,U,U,37703,37713,37719,37722,37739,37745,37747,37793,U,U,37768, +37771,37775,37790,37877,U,U,37873,37825,37831,37852,37858,37863,37897,37903, +37910,37911,37883,37938,37940,37947,37957,U,U,37997,37999,38264,38265,38278, +38284,38285,U,38315,38324,U,38344,U,U,38444,38451,38452,U,38460,38465,38497,U, +38530,U,38554,U,18919,38569,38575,38579,38586,38589,18938,U,38616,38618,38621, +18948,38676,38691,18985,38710,38721,38727,38741,38743,38747,38762,U,U,38806, +38810,38814,38818,38833,38834,38846,38860,38865,38868,38872,38873,38881,38897, +38916,38925,38926,38932,38934,19132,U,38947,38962,38963,38949,38983,39014, +39083,39085,39088,U,39095,39096,39099,39100,39103,39106,39111,39115,39136,U, +39137,39139,39141,39146,39152,39153,39155,39176,19259,U,39190,39191,U,39194, +39195,39196,U,39217,39218,39219,39226,39227,39228,39232,39233,39238,39245, +39246,39260,39263,39264,39331,39334,39353,39357,39359,39363,39369,39380,39385, +39390,U,39408,39417,39420,39434,39441,39446,39450,39456,39473,39478,39492, +39500,39512,19394,39599,19402,39607,19410,39609,U,39622,39632,39634,39637, +19432,39644,39648,39653,39657,39683,39692,39696,39698,39702,39708,39723,39731, +39741,19488,39755,39779,39781,39787,39788,39795,39798,39799,39846,39852,39857, +U,U,39858,39864,39870,39879,39923,39896,39901,39911,39914,39915,39919,39918,U, +39930,U,39927,U,39958,39960,39961,39962,39965,39970,39975,39977,39978,U,39985, +39990,39991,40005,40028,U,40009,40010,U,40020,40024,40027,40029,40031,40041, +40042,40043,40045,40046,40048,40050,40053,40058,40166,40178,40203,40194,U, +40209,40215,40216,U,19652,U,40242,19665,40258,40266,40287,40290,U,40297,40299, +U,40307,40310,40311,40318,40324,40333,40345,40353,40383,40373,40377,40381, +40387,40391,40393,40406,40410,40415,40416,40419,40436,19719,40458,40450,40461, +40473,40476,40477,40571,U,40576,40581,40603,40616,U,40637,U,40671,40679,40686, +40703,40706,19831,40707,40727,40729,40751,40759,40762,40765,40769,40773,40774, +40787,40789,40792,U,40797,U,40809,U,40813,40816,40821, +}; + +static const struct dbcs_index jisx0213_2_bmp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_bmp_decmap+0,34,126},{0,0,0},{ +__jisx0213_2_bmp_decmap+93,33,126},{__jisx0213_2_bmp_decmap+187,33,126},{ +__jisx0213_2_bmp_decmap+281,33,125},{0,0,0},{0,0,0},{__jisx0213_2_bmp_decmap+ +374,33,126},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_bmp_decmap+468,33,126},{ +__jisx0213_2_bmp_decmap+562,33,126},{__jisx0213_2_bmp_decmap+656,33,126},{ +__jisx0213_2_bmp_decmap+750,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_2_bmp_decmap+844,33,126},{__jisx0213_2_bmp_decmap+938,33,126},{ +__jisx0213_2_bmp_decmap+1032,33,126},{__jisx0213_2_bmp_decmap+1126,33,126},{ +__jisx0213_2_bmp_decmap+1220,34,126},{__jisx0213_2_bmp_decmap+1313,33,126},{ +__jisx0213_2_bmp_decmap+1407,33,126},{__jisx0213_2_bmp_decmap+1501,33,126},{ +__jisx0213_2_bmp_decmap+1595,33,125},{__jisx0213_2_bmp_decmap+1688,35,126},{ +__jisx0213_2_bmp_decmap+1780,33,126},{__jisx0213_2_bmp_decmap+1874,33,125},{ +__jisx0213_2_bmp_decmap+1967,34,125},{__jisx0213_2_bmp_decmap+2059,34,126},{ +__jisx0213_2_bmp_decmap+2152,33,126},{__jisx0213_2_bmp_decmap+2246,33,126},{ +__jisx0213_2_bmp_decmap+2340,33,117},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __jisx0213_bmp_encmap[27287] = { +8754,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10530, +10531,N,N,10532,N,10533,N,N,10534,10535,10536,N,10537,10538,10539,N,N,10540, +10541,N,N,N,10542,10543,10544,10545,10546,10547,10548,10549,10550,10551,10552, +10553,10554,10555,10556,10557,10558,10559,10560,10561,10562,10563,10564,10565, +10566,10567,10568,10569,10570,10571,10572,10573,N,10574,10575,10576,10577, +10578,10579,10580,10581,10582,10583,10584,10585,10586,10587,M,10589,10590, +10591,10592,10593,10594,10595,10596,10597,10598,10599,10600,10601,10602,10603, +10604,N,10605,10606,10607,10608,10609,10610,10611,10612,10613,10618,10810, +10825,10785,10796,10812,10827,10841,10847,N,N,10813,10828,10816,10831,N,10832, +10616,10621,N,N,N,N,10814,10829,10815,10830,10842,10848,N,N,N,N,N,N,10843, +10849,N,10877,N,N,10614,10619,N,N,N,N,N,N,N,N,10844,10850,N,N,N,10811,10826,N, +N,10788,10799,N,N,10787,10798,10817,10833,N,N,10818,10834,N,N,10874,10617, +10622,N,N,10819,10835,11051,11050,10809,10824,N,N,10820,10836,10789,10800, +10845,10851,10791,10803,10790,10802,10823,10839,10792,10804,N,N,N,N,10615, +10620,10846,10852,10821,10837,10822,10838,N,N,N,N,N,N,N,10793,10805,10795, +10808,10794,10807,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11049,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +11044,N,N,N,N,N,N,N,N,N,N,10351,10352,N,10353,10358,10359,N,10360,N,10361,N, +10362,N,10363,N,10364,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +10356,10357,N,N,N,11077,11059,11065,11066,11045,M,11071,10862,11046,11054,M,M, +N,11057,N,11058,10869,11048,10873,N,N,11062,11068,11042,11074,11052,N,N,N, +10858,10868,10859,11060,10875,10853,10870,10863,N,11055,N,N,N,10860,11073, +10867,N,10864,10855,N,N,10876,10865,10856,11047,N,N,N,10861,11053,11061,10854, +M,11067,10872,N,10866,11072,10857,N,11041,10878,N,N,11043,N,N,N,N,10871,N,N,N, +11070,11069,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,10801,11091,N,N,N,11092,N,N,N,11093,11094,N,N,N,N,N,N,10786,10840,N, +10797,N,10806,11121,N,N,N,N,N,N,M,11105,11106,11107,M,11100,11098,11103,11133, +11099,N,11095,N,11117,N,N,11097,11102,N,N,11101,N,N,N,N,N,N,N,N,11128,11129, +11134,N,11114,11126,11127,11115,11116,N,N,N,11122,11111,N,N,N,11119,11130,N, +11112,N,N,11120,11123,N,N,N,11125,N,N,N,N,11113,11131,11132,11124,11118,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11090,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,9817,10354,10355,11078,11079,11088,11089,9084,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,9024,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,10347,N,N,11096,N,N,11390,N,N,N,N,10348,10349,10350,N,N,N,N,N,N,N,11389,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,10529,9053,N,N,N,9055,N,N,11618,N,N,N,N,N,N,N,N,N,N,11620, +N,N,N,N,N,9056,N,N,N,N,N,N,N,N,N,N,N,N,N,9052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,10104,10105,10106,N,N,N,N,N,N,N,N,N,N,11573,11574, +11575,11576,11577,11578,11579,11580,11581,11582,11583,11607,N,N,N,N,11317, +11318,11319,11320,11321,11322,11323,11324,11325,11326,11327,11328,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8817,N,8999,8997,8998,9000,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9001,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9003,9004, +9002,9005,8775,N,N,N,8774,N,N,N,N,N,N,N,N,N,9051,N,N,N,N,N,N,N,N,N,N,N,11640, +N,N,N,N,N,8788,8789,N,N,N,N,N,N,N,11635,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,8812,N,8813,N,N,8814,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8811, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8815,8816,N,N,N,N,N,N,N,N,N,N,N,N,8770, +8771,N,N,N,N,8772,8773,N,N,N,N,N,N,N,N,N,8785,8786,8787,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11641,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10102,10103,8776,8777,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,10108,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10050,10051,10052,10053,10054,10055, +10056,10057,10058,10059,10060,10061,10062,10063,10064,N,10110,10109,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11553,11554,11555,11556,11557,11558,11559, +11560,11561,11562,11563,11564,11565,11566,11567,11568,11569,11570,11571,11572, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,11329,11330,11331,11332,11333,11334,11335,11336, +11337,11338,11339,11340,11341,11342,11343,11344,11345,11346,11347,11348,11349, +11350,11351,11352,11353,11354,N,11307,11308,11309,11310,11311,11312,11313, +11314,11315,11316,9818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9837,N,N, +N,N,8994,8993,N,N,N,N,N,N,N,N,8996,8995,N,N,N,N,N,N,N,9019,N,N,N,N,N,N,10343, +10344,10345,10346,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9023,9832,9833,9834, +9835,N,N,N,N,N,N,N,N,N,N,9831,N,N,N,N,N,N,N,9828,9829,N,N,N,N,N,N,11646,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9786,9789,9787,9792,9785,9790, +9788,9791,9836,8829,N,8827,8828,N,8826,10107,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,11645,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,11297,11298,11299,11300,11301,11302,11303,11304,11305,11306,9006, +9007,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,8790,8791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,9018,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,9085,9086,8794,8795,8792,8793,N,N,N,11616,N,11617,9830,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8755,8756,8757,N,N,N,N,N,8758,8759,9020,N,N,N, +N,N,N,N,N,N,N,N,N,N,M,N,M,N,M,N,M,N,M,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,9332,9333,9334,N,N,N,N,N,N,N,N,8761,9083,N,N,N,N,N,N,N,N,N,N,M,N,M, +N,M,N,M,N,M,N,N,N,N,N,N,N,M,N,N,N,N,N,N,N,N,M,N,N,N,M,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10098, +10099,10100,10101,N,N,N,N,8760,9838,9839,9840,9841,9842,9843,9844,M,9846,9847, +9849,9850,9851,9852,9853,9854,11626,11627,N,N,N,N,N,N,11628,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,10305,10306,10307,10308,10309,10310,10311,10312, +10313,10314,10315,10316,10317,10318,10319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,11621,11622,11623,11624,11625,N,N,N,N,N,N,N,N,10320, +10321,10322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333, +10334,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11355,11356,11357,11358,11359,11360, +11361,11362,11363,11364,11365,11366,11367,11368,11369,11370,11371,11372,11373, +11374,N,11377,N,N,N,11376,N,N,11379,11378,N,N,N,N,N,N,N,N,N,N,N,N,11375,11590, +N,N,N,N,N,N,N,N,N,11594,N,N,N,N,N,N,11585,N,N,N,11588,N,N,N,N,N,N,N,N,N,11586, +11596,N,N,11595,11589,N,N,N,11597,N,N,N,N,N,N,N,N,N,N,11591,N,N,N,N,11599,N,N, +N,N,N,N,N,N,N,N,N,N,N,11584,11598,N,N,11587,N,N,N,11592,N,N,N,N,N,11593,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11615,11631, +11630,11629,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11603,11604,N,N,N,N,N,N,N,N,N,N,N,N, +11600,11601,11602,N,N,11606,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,11605,N,N,N,N,N,N,9054,N,11619,11811,N,N,N,41261,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41266,N,41267, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41310,N,41302,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41342,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11859,N,N,N,N,N,N,41771,N,N,N,N, +62568,N,N,N,N,N,41775,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11867,41800,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41821,41822,N,N,N,N,41825,N,N,N,N,N,N,N, +N,N,N,41831,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42019,N,42022,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,42040,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42050,42058,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42105,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42303,N,N,N,N,42307,N,N,42305,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,42327,43043,43045,N,N,N,N,N,N,N,N,43049,43048,N,N,N,N,N, +N,N,N,43052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20319,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,43070,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,20335,N,N,N,N,N,43094,N,N,N,N,N,N,N,N,N,N,N,43097,N,N,N,N,N,N,N,N,43100, +43102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,43119,N,N,N,N,N,N,43121,N,N,N,N,N,N,N,N,N,43124,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43129,N,N,N,N,43131,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44091,44102,N,N,44106, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44128,44379,N,N,N,N,44383,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44401,44598,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44412,44590,N,N,N,N,N,N,N,N,N, +N,N,44594,N,44596,N,N,N,N,N,30025,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,44653,N,N,N,N,N,N,N,N,N,44645,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,44840,44841,N,N,N,N,44844,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44852,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30078,N,N,N,N,N,N,N,N,N,N,N,N,30241,N, +N,N,N,N,N,N,N,N,44872,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44893,30266,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44919,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +60987,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60994,61041,N,N,N,N,N,N,N,N,N,N,N,N,61054,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61248,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,61268,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61296,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61303,61480,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30566,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,61503,N,N,N,N,N,61505,N,61506,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,61513,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61520,61748,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30797,N,N,61766,N,61768,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,61788,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,61799,N,N,N,N,N,N,N,N,N,N,N,N,N,61804,61986,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61997,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62009,62052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62068,N,N,N, +N,N,N,62071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62077,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62259,N,N,N,N,N,N, +N,N,N,N,62263,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,62279,N,N,N,N,N,N,N,62283,N,N,N,N,62280,62291,N,N,N,N,N,N,62295,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,31085,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62507,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62518,N,N,N,N,N,N,62523,62542,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62557,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,62561,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62782,N,62786,62792,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,62794,N,N,N,N,62796,N,N,N,N,N,62799,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31321,N,N,N,N,N,N,N,31322,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62828,N,N,N,62830,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62839,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63029,N,N,N,N,N,N,N,N, +N,N,63026,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63028,63065,N,N,N,N,63060, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63085,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63086,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31569,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63340,N,N,N,N,31584, +63524,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,63546,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,63555,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63566,N, +N,N,N,N,N,N,N,N,N,N,N,N,63571,63595,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63785,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63807,63817,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31819,N,N,N,N,N,N,N,N,N,63836,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64039,32088,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64362,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64368,64373,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,64376,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64567,64597,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64806,N,N,N,N,N,N,N,64808,N,N,N, +N,N,N,N,64810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64817,32318,N,N,N,N,N, +N,N,N,64831,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,65066,N,N,N,N,N,N,N,N,N,N,N,N,65069,65099,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65120,41250,N,N,N,N,N, +N,N,N,N,N,N,N,41251,N,N,41252,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11812, +41253,N,41254,61486,N,41255,11813,11814,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41256,N, +N,N,N,N,N,41257,41258,N,N,N,N,N,N,N,N,41260,N,N,N,N,N,N,N,N,41263,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,41264,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,11815,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41265,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41268,N,41269,41271,N,N,N,N,N,N,41272,N,N,N,N, +41273,N,N,N,N,N,N,N,41274,N,N,N,N,N,N,N,N,N,41276,N,N,N,N,N,N,11816,N,N,N,N,N, +N,N,N,N,41275,N,N,N,N,N,41277,N,N,N,41278,N,N,N,N,N,N,N,11817,N,11818,41279,N, +N,11819,N,N,N,N,N,N,N,11820,N,N,N,N,N,N,N,N,N,N,41280,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41282,N,N,N,N,N,N,41283,N,N,N,N,N,N,N, +N,N,11822,11823,N,N,N,N,N,N,N,N,N,N,41284,N,11824,N,41285,N,N,N,N,N,N,11825, +11821,N,N,N,41281,N,N,N,N,N,11826,N,11827,N,N,N,N,N,N,N,N,N,N,41287,41288,N, +41289,N,N,41290,11828,N,N,N,41291,N,N,41292,N,N,N,N,11829,N,N,N,N,N,N,N,41293, +N,11830,N,N,11831,N,N,41294,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41296,N,N,N,N,N,N,N,N,N,N,N,41297,N,N,N,N,N,N,41298,N,N,N,11833,N,41299,N,N,N, +41300,N,N,41301,N,N,N,N,N,N,N,N,N,N,N,N,N,11834,N,N,N,N,N,41295,N,N,N,N,N,N,N, +N,N,N,11809,41303,41304,11835,11836,N,N,N,N,N,N,N,N,N,N,N,11837,N,41305,N,N, +41306,N,N,N,N,11838,N,N,N,41307,N,41308,N,N,N,41309,N,N,N,N,11839,N,N,N,N,N,N, +11840,N,N,N,N,N,N,N,N,N,N,N,N,11842,N,N,N,N,11841,11843,41311,N,N,N,41312,N,N, +N,N,N,N,N,41313,N,N,N,N,41314,N,N,N,41315,N,N,N,N,N,N,N,N,N,N,N,41316,N,N, +41317,N,N,N,41318,N,N,N,N,N,41319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,41321,N,N,N,N,N,N,N,N,N,41322,41323,11844,41324,41325,N,N,N,N,N,41326,N,N,N, +N,N,N,41320,N,N,N,N,N,N,41327,N,N,N,N,N,N,41329,N,N,N,N,N,N,N,N,41330,41331,N, +N,N,N,N,N,N,N,41332,N,N,41333,N,N,N,N,11845,N,41336,N,11847,N,N,N,41338,N,N,N, +N,41339,N,N,N,N,N,N,N,41340,N,N,N,N,11848,N,N,41341,N,N,N,N,N,N,N,N,11846, +41334,11851,N,N,11850,N,41761,N,N,11852,N,N,N,N,N,N,N,N,N,N,N,41763,N,N,N, +41764,N,N,11853,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11854,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,11855,N,N,N,N,N,N,N,N,N,N,11857,N,11858,N,N,N,N,N, +N,N,N,41766,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41768,N,N,N,N,N,N,N,62580,N,N, +N,N,N,N,N,41769,N,N,N,N,N,N,N,41770,N,N,N,N,N,N,N,N,N,N,N,N,41772,N,N,N,N, +11860,N,N,N,N,N,41773,N,N,N,N,N,N,N,N,N,41774,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41776,N,N,N,N,N,N,11861,N,N,N,N,N,N,11862,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,11863,N,N,N,11864,N,N,N,N,N,N,N,N,N,N,N,11865,N,N,N,N,41779,41780,11866, +41781,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41782,11868,N,11869,41783,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,11870,N,N,N,N,N,N,N,N,N,N,N,41785,N,11871,N,N,N,N,41786,12158,N,N,N, +11872,N,N,N,N,N,N,N,N,N,N,41787,N,N,N,N,N,N,N,N,N,N,41788,N,N,N,N,N,N,N,N,N,N, +41790,N,41789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11873,N,N,N,N,41792,N,N,N,N,N,N,N,N, +N,N,N,41794,N,41795,N,N,N,N,N,N,N,N,41796,N,N,N,N,N,N,N,N,N,N,41797,41798,N,N, +N,N,N,N,N,N,N,N,N,N,11874,N,41799,N,11876,N,N,N,11877,41801,N,N,N,N,11878,N,N, +N,N,11879,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11881,N,N,N,N,N,N,41803,N,N, +N,11882,11883,N,N,N,N,N,N,11884,N,N,41804,41805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,11885,N,N,N,N,N,N,N,41806,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41807,N,N,N,N,N,N, +N,N,41808,N,N,N,41809,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,11887,N,11888,N,N,N,41812,N,N,N,N,41813,N,N,N,N,N,N,N,N,N,N,N,N,N,41814,N, +N,11889,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11890,N,N,N,N,N,N,N,N,N, +11891,N,N,N,N,N,N,41815,N,N,N,N,N,N,N,N,N,N,N,N,N,11892,N,41816,N,N,41818,N,N, +N,N,N,N,N,N,41819,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41823,N,N,N,N,41824, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41826,41827,11893,N,N,N,N,N, +N,N,N,N,N,N,20350,N,N,N,N,N,41829,N,N,11894,41830,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,41832,N,N,N,N,N,N,N,N,N,11895,N,N,N,N,N,N,N,41828,N,N, +N,N,N,N,N,N,N,N,N,N,41833,N,N,N,41834,N,N,N,N,11897,41835,N,N,N,N,N,N,N,11898, +N,N,N,N,N,N,N,N,N,N,11899,N,N,N,N,N,N,N,N,11900,N,41836,N,N,41837,N,N,N,N,N,N, +N,41838,11901,N,N,N,N,N,11896,N,N,N,41839,11902,N,N,N,N,41840,N,N,12065,N,N,N, +41841,41842,N,N,N,N,N,N,N,N,41843,N,N,41844,N,N,N,N,41845,N,N,N,41846,N,N, +12066,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,41848,N,N,41849,N,41850,N,41851,N,N,N,N,N,N,N,N,N,N,N,12067,41852,41853,N,N, +N,N,N,N,N,41854,N,N,N,N,12068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,12069,N,N,N,N,N,N,N,N,N,12070,N,N,N,N,N,N,42017,N,N,N,N,42018,N,N,N,N, +N,42020,N,N,42021,N,N,N,N,N,12071,N,N,N,N,N,N,N,N,N,N,N,N,N,12072,N,42023, +42024,N,N,42025,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42027,N,N,N, +12073,42028,N,N,N,12074,N,42029,N,N,N,N,N,12075,N,N,42030,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,12077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +42035,N,N,N,N,N,N,N,N,N,42036,N,N,42037,N,12078,N,N,42038,42032,N,N,N,N,N,N,N, +N,N,N,42039,N,N,N,N,42041,N,N,N,N,N,N,42043,42046,12080,N,N,N,N,N,12081,N, +42047,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42044,N,N,N,N,N,N,N,42048, +N,N,N,N,N,N,42049,N,N,N,12082,N,42051,N,42052,42053,N,N,N,N,N,N,42054,N,12083, +N,N,N,N,N,N,N,N,N,29735,N,N,N,N,N,N,N,N,N,N,42055,N,42056,N,N,N,N,N,12085,N,N, +N,N,N,N,42057,N,12087,N,12088,12089,N,N,N,12084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,42059,N,N,N,42060,N,N,N,N,N,N,N,N,42061,N,N,N,12090,42062,N,N,42063,12091, +N,N,N,N,N,N,N,N,N,42064,12092,N,N,12093,42065,N,N,N,N,42066,12094,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,42067,N,N,N,12095,12096,N,N,42068,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,42069,N,N,N,N,N,N,N,N,42070,N,N,N,N,N,N,N,N,N,N,N,N,N,42071,42072, +12097,N,N,N,N,N,N,N,N,N,N,42074,N,N,N,N,N,N,N,N,N,N,N,12099,N,42075,N,N,N,N,N, +42077,N,N,N,N,N,12100,N,N,N,12101,12102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42079, +42080,N,N,N,N,N,42081,42082,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,42084,N,N,N,N,N,N,42085,12103,N,N,42086,42087,42088,N,12104,N,N,N,42089, +12105,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42093,N,12106, +42094,42095,N,N,N,N,N,N,N,N,N,42096,N,N,N,42092,N,N,N,N,N,N,N,N,N,N,N,12109,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,12110,12111,N,N,N,42099,N,N,12112,N,N,N,N,N,N,N, +42097,N,N,N,N,N,N,42102,N,N,N,N,N,12113,N,42103,N,N,N,N,N,N,12114,N,N,42104,N, +N,N,N,12115,12116,N,42106,N,N,42107,N,42108,N,12117,42109,N,N,N,N,12118,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42110,N,42273,N,N,N,N,N,N,42274,N,N,N,N,N,N, +N,N,N,N,42275,N,N,N,N,N,N,42276,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42278,N,N,42279, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,12120,N,N,12121,N,N,42280,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,12123,N,N,N,N,N,N,N,N,N,N,N,N,12124,42281,42282,N, +42283,N,42284,42285,N,N,N,42286,N,N,N,N,N,N,N,N,42287,12125,N,N,N,N,N,N,N,N,N, +N,12127,42288,N,N,N,N,N,N,42289,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42291,N,N,N, +N,N,N,N,N,N,42292,12130,N,N,N,12129,N,12131,N,N,N,N,N,12132,N,N,N,N,N,12133,N, +42293,N,N,N,N,N,N,12134,N,N,N,N,N,N,N,N,N,42294,42295,42296,42297,N,N,N,N, +42298,12135,42299,N,N,N,N,N,N,42300,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42301,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42304,N,N,N,N,N,N,N,N,42306,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42309,N,12137,N,42310,N,N,N,N,N,N,N,N,N,N,N,N, +N,12138,N,N,N,N,N,N,N,42312,42313,N,N,N,N,N,42314,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +12139,N,N,N,N,N,N,12140,N,N,N,N,N,N,N,N,N,N,N,N,42315,N,N,N,N,12141,N,N,N,N,N, +N,N,N,N,42316,N,N,N,N,N,N,N,N,N,N,N,N,N,42317,N,N,N,N,N,N,12142,N,N,N,N,42318, +N,N,N,N,42319,N,N,N,N,12143,N,N,N,N,N,N,N,N,N,N,12144,42320,N,N,N,N,42321, +42322,N,N,42323,N,N,N,N,N,N,42324,N,N,N,N,N,N,N,N,N,32378,42328,42329,N,N,N,N, +N,12145,N,N,N,42330,N,N,N,N,N,N,N,N,N,N,N,12146,N,N,N,42331,N,N,N,N,N,42332,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +42333,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42334,N,12147,N,N,N,N,N,12148,N,N,N,N,N,N, +N,N,N,12149,N,N,42335,N,N,N,12150,N,N,N,N,N,12151,N,N,N,N,N,N,42336,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,42337,N,12152,42338,42339,N,42340,N,N,N,N,12153,N,N,N,N, +N,N,N,N,N,42341,N,42342,N,42343,N,N,N,N,42344,N,N,N,N,42345,N,N,N,N,12154,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42346,N,42347,N,N,N,42348,N,N,N,N,42349, +N,N,N,N,N,N,N,N,42351,N,42350,N,N,N,N,42352,42353,N,N,N,N,N,N,N,42354,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,42355,N,12156,N,N,N,N,N,N,N,N,N,N,N,12157,N,N,N,N,N,N,N, +42357,N,N,N,N,N,N,42356,N,N,N,N,N,N,N,N,N,N,N,N,20309,N,N,N,N,N,N,N,N,N,N, +42358,N,N,N,N,N,42359,N,N,N,20310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42360,N,N, +N,N,N,N,42361,N,N,N,N,N,N,N,N,N,N,N,N,42362,20311,N,42363,N,42364,N,N,42365,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,20312,N,N,43041,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,43042,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43044,N,N,N,N,N,N,N,N,N,N,N, +N,N,43046,N,N,N,N,N,N,N,43047,N,20313,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +20314,N,N,N,N,43050,N,N,N,N,N,N,N,N,N,N,N,43051,43053,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,20315,N,N,N,N,N,N,N,N,N,N,N,20316,N,N,N,N,20317,N,N,N,N,N,43054,N,20318,N, +N,N,N,43055,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,32379,N,N,N,43057,N,N,20320,43058,N,N,N,43059,43060,43061,N, +N,N,N,N,N,43062,N,N,N,N,N,N,N,N,N,20324,N,43065,N,N,N,N,N,N,N,N,N,N,N,43068,N, +43069,N,N,N,N,20325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20326,43073,N,43074,20327,N, +N,43075,43076,N,N,20328,N,N,43078,N,N,N,N,N,N,N,43079,N,N,N,N,20329,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,43081,N,20330,N,N,N,N,20331,N,20332,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20333,43084,N,N,N,N,N,N,20336,N,N, +43085,N,N,N,N,N,N,N,N,N,N,N,N,43087,N,N,43088,N,N,N,43089,N,43090,20337,N,N,N, +43086,N,N,N,N,N,43091,N,N,N,N,N,N,N,43092,N,N,N,N,N,N,N,N,43093,N,N,N,20339, +20340,N,N,20342,N,N,N,N,N,N,N,N,20341,N,N,N,N,N,N,N,N,N,N,N,N,N,43095,N,N,N,N, +N,N,N,N,43096,N,N,20343,N,N,43098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20344,N,N,N, +N,N,N,43101,N,N,N,N,N,N,N,N,N,43103,N,43104,N,N,43105,N,43106,N,N,N,N,N,N, +20345,N,N,N,20346,N,N,20347,N,N,N,N,N,N,N,N,43107,N,43108,N,43109,N,N,N,20348, +43111,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20349,N,N,N,N,N,43112,N,N,N,N,N,43113, +43114,N,N,N,N,N,N,N,43115,N,29736,N,43117,N,N,N,N,43118,43120,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,43122,N,29737,43123,N,N,29738,N,N,N,N,N,N,43125,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,43126,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43127,N,N,N,N,N,N,N,N,N,N, +43128,N,N,N,N,N,N,N,N,N,N,N,N,43130,N,29739,N,N,N,N,N,29740,N,N,N,N,N,N,N,N,N, +N,N,N,43132,43133,43134,44065,N,N,N,N,N,N,N,N,32380,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44067,N,N,N,N, +44068,N,44069,N,N,N,N,N,N,N,N,N,N,N,N,44070,N,N,N,N,29741,44071,N,N,N,N,N,N, +44072,N,N,N,N,29743,N,N,N,N,N,N,44073,N,N,N,N,N,N,44074,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29744,N,N,N,44076,29745,N,29746,N,N,N, +N,29747,44077,N,N,N,N,N,44078,N,N,N,N,N,N,N,N,N,N,N,N,N,44079,29748,44081,N,N, +N,N,29749,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29750,N,29751,N,N,N,N,N,N,29752,N,N, +29753,N,N,N,N,29754,N,44082,N,N,N,N,N,N,N,N,N,N,N,N,29755,N,N,N,29756,N,N,N,N, +N,N,N,N,N,N,44083,29757,N,N,29758,N,N,N,N,N,N,N,N,N,N,44084,N,N,N,N,N,N,N,N,N, +N,29759,44085,N,N,N,N,N,N,N,N,N,N,29760,N,N,N,N,N,44086,N,N,N,N,N,N,N,N,N,N,N, +N,29761,N,N,N,N,N,44087,N,44088,N,N,29762,N,N,N,N,N,N,N,29763,N,N,N,N,N,29764, +N,29765,44089,N,N,N,N,N,N,N,N,N,N,N,44090,N,N,44092,N,29766,N,44093,N,N,N,N,N, +N,44094,44095,44096,N,N,N,N,N,N,N,N,N,29767,N,N,29768,44097,N,N,N,N,N,N,29769, +N,N,N,N,44098,44099,N,N,N,44100,N,N,N,N,N,N,N,N,44101,29770,N,N,N,N,N,N,29771, +N,N,44103,29772,N,N,N,N,N,N,N,N,N,44104,N,44105,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +29773,N,29774,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29775,N,N,N,N,44107,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44108,N,N,N,N,N,N,N,N,N,N,44109,N,N,N,N,N,N,N,N,N,N,44110,N,N,N,N, +N,N,N,29777,29778,N,N,N,N,N,N,N,N,N,44111,N,N,N,N,N,N,N,44113,44114,N,N,N,N,N, +N,N,N,N,N,N,N,44115,N,N,N,N,N,N,N,N,N,44116,N,N,29779,N,N,N,N,N,N,N,N,29780, +29781,N,N,N,44117,N,44118,N,29782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44119,N,N,N, +44120,N,N,44121,N,N,29783,44122,N,44123,44124,N,N,N,N,N,44125,N,N,29784,N, +44126,N,N,N,N,N,N,N,N,N,N,N,N,29785,N,N,N,N,29786,N,N,N,N,N,N,29787,N,N,44127, +N,N,N,N,N,N,44129,N,N,N,N,44130,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,44131,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44132,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,29789,N,N,N,N,44134,44135,N,N,N,44136,44137,N,N,N,N,N, +N,N,N,N,N,N,N,44138,N,N,44139,N,N,N,N,44140,N,N,N,N,N,N,N,N,N,N,N,29792,N,N, +29791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44142,N,N,N,N,N,N,N, +44143,N,44144,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44145,44147,N,N,N,N,N, +N,N,N,N,N,N,N,29794,44148,N,N,N,N,N,44149,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,29795,N,N,N,N,29796,N,N,44150,N,N,N,N,N,44151,N,N,N,N,44152,44153,N,N,N, +29797,N,N,N,29798,N,N,N,N,N,N,44154,N,N,44155,N,N,N,N,N,N,N,N,44157,N,29799,N, +N,N,44158,N,N,N,N,N,N,N,44156,N,N,N,N,N,N,N,N,N,29800,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,44321,N,N,N,N,N,N,N,N,N,N,N,N,44322,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44323, +29802,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,29803,44325,44326,N,N,N,N,N,N,29804,N,N,44327,N,N,44328,N,N,N,N,N,N,N,29805, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44331,N,N,44332,N,N,N,29806, +N,44333,44334,N,N,N,N,44335,N,29807,44336,N,N,N,N,N,N,N,N,N,44337,N,N,N,N,N,N, +N,N,N,N,44339,N,N,N,N,N,N,N,N,N,N,N,29808,N,N,N,N,N,N,44342,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,29809,N,N,N,N,N,N,N,44343,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44346,N,N, +N,N,44344,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,44347,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44349,44350,N,N,N,N,N,N, +44351,N,N,N,44352,N,N,N,N,29810,N,N,N,N,N,44353,44354,29811,N,N,N,N,44355,N,N, +29812,N,44348,44356,N,N,N,N,N,N,29813,N,N,N,29814,N,N,N,N,N,N,N,N,N,44357,N,N, +N,29815,N,N,44358,N,N,N,44359,N,N,N,N,N,44360,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29817,N,N,N,N,N,N,N,N,44361,44362,N,44363,N, +N,29818,N,N,N,N,N,N,N,N,N,N,N,N,29819,N,N,N,N,N,44364,N,N,N,N,N,29816,N,N,N, +44365,N,N,N,N,N,N,N,N,N,44366,N,N,N,N,N,N,N,N,N,44367,N,N,N,N,N,N,N,N,N,N,N, +44368,N,44369,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +29821,29822,N,N,N,N,29985,N,N,N,N,N,29986,44370,44371,N,29820,N,29987,N,N,N,N, +44372,N,44373,N,N,N,N,N,N,N,N,N,N,N,N,44375,44376,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,29988,N,N,N,29989,N,N,N,44377,44378,N,N,N,N,N,N,N,N,N,N,44380,N,N,N,N, +44381,N,44382,N,N,N,N,N,N,N,44384,N,N,N,29990,N,N,N,N,N,N,29991,N,N,N,N,N,N,N, +N,44385,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44386,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44387,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29993,N,N,N,44388,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,44389,N,N,N,N,N,N,44390,N,N,44391,44392,N,N,N,N,44393,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,29994,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44394,N,N, +44395,N,N,44396,N,N,N,N,N,N,44397,N,N,44398,N,N,N,N,N,N,44399,N,N,N,N,N,N,N,N, +N,N,44400,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44402,N,N, +N,N,N,N,44403,N,N,44404,29996,N,N,N,44405,N,N,N,44406,29997,N,N,N,N,N,N,N,N,N, +N,N,29998,N,N,N,N,N,N,N,N,29999,N,N,44407,30001,N,30002,N,N,N,N,N,44408,30003, +N,N,N,N,30004,30005,N,30006,N,N,N,N,N,N,30000,N,N,N,N,N,N,N,N,N,N,44409,N,N, +30008,N,N,N,30009,N,44411,N,N,44410,N,N,N,N,N,44414,N,30011,30012,44577,N,N,N, +N,N,30013,N,44578,N,30014,N,N,N,N,44581,44582,44583,44584,N,N,N,N,N,30015,N,N, +N,30016,30017,N,N,44585,N,N,N,N,44586,N,N,N,N,N,N,N,N,N,N,N,N,30018,N,N,44587, +N,44588,N,N,N,N,N,N,44589,N,N,N,N,N,N,30020,N,N,N,N,N,N,N,N,N,N,N,N,44591,N,N, +N,44592,30021,N,N,44593,N,N,N,N,N,30022,N,N,N,44595,N,N,N,N,N,N,30023,N,30024, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30026,N,N,N,N,N,N,N,N,N,N,N,N,30027,N,N,N, +44597,N,N,N,N,N,N,N,N,N,N,N,N,N,30028,30007,44599,N,N,N,44600,N,N,N,N,N,N,N,N, +N,N,N,N,44601,30029,N,N,N,N,N,44603,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,30031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30033,30034,N,N,N,44606, +44607,N,N,N,N,N,N,44608,N,N,N,N,N,N,N,N,44609,N,N,N,N,N,N,N,N,30032,N,N,N,N,N, +N,N,N,N,N,N,N,N,44613,N,44614,N,N,N,N,30035,N,N,N,N,N,30036,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,44616,30037,N,N,N,N,30038,N,N,30039,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44620,N,44621,N,N,N,N,N,N,N,N,30040,N,N,N,N,30042,N,N,44622,N,N,N, +N,44623,N,N,N,N,N,N,N,N,N,44624,N,N,N,N,30043,N,44625,N,44626,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,44627,N,N,N,N,N,N,44628,N,30041,N,N,30044,30045,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,44619,N,N,N,N,N,N,N,44632,N,N,N,N,30047,N,44633,N,N,N,N, +N,N,N,N,N,N,N,N,30048,44634,N,N,N,30049,N,44636,N,N,N,N,N,N,N,44637,N,N,44638, +N,N,N,N,N,44639,44640,N,N,N,44641,N,N,44642,N,N,N,N,N,30046,N,N,44643,N,44644, +N,N,N,30050,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44646,N,N,44647,N,N,N,30051,N,N, +30052,N,N,N,N,44648,N,44649,N,N,N,N,N,44650,N,N,N,N,N,N,N,N,N,N,N,N,N,44651,N, +N,N,N,N,44652,N,44654,44655,44656,N,44657,N,N,N,N,N,N,30054,N,30055,N,N,N,N, +44658,44659,N,N,N,N,N,N,30056,N,44660,N,N,N,N,N,N,44661,N,N,N,N,N,N,N,44666,N, +44667,N,N,30057,N,N,N,44668,N,N,44669,30058,N,N,N,N,N,44670,N,N,44833,N,N,N,N, +N,N,N,N,N,N,44834,44835,N,N,30059,N,N,N,44836,30060,N,N,30061,30062,N,N,N,N,N, +44837,N,N,N,44662,30063,44838,N,N,N,44839,N,N,30064,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30067,N,N,N,N,N, +44843,N,N,N,N,N,N,30068,N,N,N,44845,N,N,30065,N,N,N,N,N,N,N,N,N,N,N,N,N,30069, +N,N,N,N,N,N,N,N,N,N,N,30070,30071,N,N,N,30072,44846,N,N,44847,N,N,N,N,N,44848, +N,N,N,N,N,N,N,44849,N,N,N,N,44850,30073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44851,N,N,N,44853,N,44854,N,N,N,N,N,N,N,N,N,N,N,N,30075,44855,N,N,N,N,N,N, +30076,N,N,44856,N,N,N,N,N,N,44857,N,N,44858,N,44859,N,N,N,44860,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,30077,N,44861,N,N,N,N,44862,N,N,N,N,N,N,N,N,N,N,N,30242,44868,N, +N,N,N,N,30243,30244,N,N,N,44869,44870,N,N,N,44871,44873,30245,30246,N,N,N,N,N, +N,N,44874,30247,N,44875,N,N,N,30248,N,N,N,N,44876,N,N,44877,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,44865,N,44879,44880,44881,N,N,N,N,N,N,30250,N,N,30251,44882, +N,N,N,N,N,30252,44883,N,N,44884,N,N,N,N,44886,N,30253,N,44887,N,N,N,30254,N,N, +N,N,30255,N,N,N,N,N,N,N,N,44888,N,N,N,N,N,N,30256,N,N,N,N,N,N,N,30257,N,N,N,N, +N,N,44885,N,N,N,44890,N,N,N,N,44891,N,N,N,N,N,30259,N,44892,N,N,N,N,N,44894,N, +N,30260,N,N,N,N,N,N,N,N,30261,30262,44895,N,44896,N,N,N,30263,N,N,N,N,N,44898, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44899,N,N,N,N,N,N,N,N,44900,N,N,N,N,N,N,N,N, +N,44902,N,N,N,44901,N,N,N,N,N,N,N,44903,44904,N,N,N,N,N,N,30264,N,N,30265,N,N, +N,N,44907,N,N,N,N,44908,44909,44910,N,N,N,N,N,N,N,N,N,44911,44913,N,N,N,44914, +44915,44916,N,N,N,N,N,44918,N,N,N,30268,N,N,30269,N,N,N,N,N,N,N,N,N,N,N,N,N, +30270,N,N,44920,N,N,N,N,N,30271,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30272,N,N,N, +44921,N,N,N,N,N,N,N,N,N,N,N,30273,N,44922,N,N,N,N,N,N,N,30274,N,N,N,N,30275,N, +30276,N,N,N,N,44923,N,N,N,N,N,N,N,N,44924,N,30277,N,N,44925,N,N,N,N,N,N,44926, +30278,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60961,N,N,N,N,N,N,N,N,N, +N,N,N,N,30279,N,N,N,30280,60962,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60964,60965,N,N,N, +N,N,N,N,N,60966,60967,60968,N,N,N,N,N,30282,N,N,N,N,N,N,30283,30284,N,N,60969, +N,N,N,N,N,N,N,N,N,N,N,60970,60971,N,N,N,N,N,N,60972,N,N,60973,N,N,N,N,N,N,N,N, +N,N,N,N,N,30285,60974,N,N,30286,N,N,N,N,60975,N,N,N,60976,N,30287,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30288,N,60977,60978,N, +N,N,60979,N,N,N,N,60981,N,N,N,N,N,N,N,N,N,N,N,N,N,60982,N,N,N,N,N,N,N,N,N,N,N, +30289,N,60983,30290,N,N,N,N,N,N,N,N,N,N,61007,N,N,N,N,N,60984,N,N,N,N,N,N, +30292,N,30293,N,N,N,N,N,N,N,N,N,N,N,N,N,60985,30294,30295,N,N,60986,N,N,N,N,N, +N,N,N,N,N,60988,60989,N,60990,30296,N,N,N,30297,N,N,N,N,N,N,N,N,N,N,N,N,N, +30291,N,N,60991,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,60992,N,N,N,30299,N,N, +N,N,N,N,N,N,N,60993,N,N,N,30300,N,60995,N,N,N,60996,N,60997,N,N,N,30301,N,N,N, +N,N,N,N,N,60998,N,30302,60999,61000,30303,N,N,N,N,N,N,N,N,N,N,N,N,30298,61002, +N,N,N,30305,N,N,N,N,N,61003,N,N,N,30306,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61004,N,61005,61006,N,N,N,N,N,N,30307,61008,N,30308,N,N,61029,N,N,N,N, +30309,N,N,61009,N,N,30310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30311,N,N,61010,N,N,61011,N,61012,N,N,N,N,30312,N,N,N,N,N,N,N,N,N,N,61013,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,61014,61015,30314,N,N,N,N,30315,N,30316,61016,N,N, +61017,N,N,N,61018,N,N,30317,N,N,N,61019,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30318,61025,30319,N,61026,N,N,N,N,N,61027,N,N,N,N,N,N,N,N,N,N,30320,N,N,61028, +N,30321,N,N,N,61030,N,N,N,N,N,61031,61032,61033,N,N,N,N,N,30322,N,N,N,30323, +30324,N,30325,N,61034,N,N,N,N,N,N,N,N,N,61035,N,N,N,N,N,N,N,N,N,N,N,N,61036,N, +N,N,N,N,30326,61021,N,N,N,N,N,N,61038,N,N,N,61039,N,N,N,N,61040,N,N,N,N,N,N,N, +N,N,N,61042,N,30328,N,61037,N,N,N,N,N,61043,N,N,N,N,N,N,N,30329,N,N,N,61044, +61045,N,61046,61047,N,N,61048,N,61049,N,61050,61051,N,N,61052,N,N,N,N,30330,N, +30331,N,N,N,N,61053,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61217,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61218,N,N,N,30332,N,N,N,N,N,30333,N,N,61219,N,N,N,N,N,N,N,N,N,N,61220,N, +30334,N,61221,N,N,N,30497,N,N,61222,N,N,N,30498,N,N,N,N,N,N,N,N,N,N,61223,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61225,N,N,N,N,N,N,N,N,N,N,N,N,N,61226,N,61227, +61228,N,61229,N,N,N,30499,N,N,N,N,N,N,N,61230,N,30500,N,N,N,N,N,N,N,N,N,N, +61231,N,N,N,N,30502,N,N,N,N,30503,N,N,N,30504,N,61224,61232,N,N,N,N,N,61233,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30505,61235,N,N,N,N,61236,N,30506,61237, +N,N,N,30507,N,61238,30508,30509,N,N,N,N,N,61239,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61241,30510,N,N,N,N,N,N,N,N,N,30511,N,N,N,30512,30513,N,N,61242,N,N, +N,30514,N,61243,N,61240,N,N,N,N,N,N,61245,30515,N,N,N,N,61246,N,30516,N,N,N,N, +N,N,N,61247,N,N,N,N,N,61249,30517,N,N,N,N,N,30518,N,61244,N,N,N,N,N,N,N,N, +30519,61250,61251,30520,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61252,N,N,N,61253,N,N,N, +N,N,N,N,N,N,N,61254,N,N,N,N,N,N,30522,N,N,N,N,30523,N,N,N,30521,N,N,61256, +61257,N,N,N,N,30524,30525,61258,N,N,61259,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,61260,N,N,N,N,30526,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61262,61263,N, +61264,N,N,N,N,N,N,61265,N,N,N,61266,N,N,30527,61267,N,N,30530,N,N,N,N,N,61269, +N,N,N,N,N,N,N,N,30528,30529,N,N,N,N,N,30531,61270,N,N,N,61271,N,N,61272,N, +61273,N,N,N,N,N,N,30532,61274,N,N,N,N,N,N,N,61275,N,N,61276,N,N,N,30533,61277, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,61278,N,61279,N,N,N,N,N,N,N,61282,N,N,N,N,30534,N, +N,N,N,N,N,30535,N,N,N,N,N,61283,N,N,N,N,N,30536,N,N,N,61280,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,61286,N,N,N,N,N,N,61287,N,61288,30537,N,N,N,30538,N,N,N,61289,N,N,N, +N,N,N,N,30539,N,N,N,N,N,N,N,61285,61290,61291,N,61292,61293,61294,N,N,N,61295, +N,N,30540,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30542,N,30543,N,N,N,N,N,N,N,N,N,N,30541, +N,N,30544,61297,30545,61298,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30546, +30547,N,N,61300,N,N,N,N,N,61299,30548,30550,61301,N,N,N,N,N,N,N,N,30551,N, +61302,N,30552,N,N,N,N,N,N,N,30553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61305,N,N,N,N,30555,N,30556,N,N,N,N,N,N,N,N,N,N,30557,N,N,N,61304,N,N,N,N, +61306,N,N,N,N,61307,N,61308,N,N,N,N,N,N,N,N,N,N,N,61309,61310,N,N,N,61473,N,N, +N,N,N,N,30559,N,N,N,N,N,N,30558,N,N,30560,N,N,N,N,N,N,61475,N,N,N,N,N,N,N, +61476,N,N,N,N,N,61477,N,N,61478,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,30561,30562,N,N,N,N,N,N,61479,N,N,N,N,N,N,N,N,N,N,N,N,N, +30563,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61482,N,N,N,N,N,N,N,N,61483,N, +N,N,61484,61485,N,N,N,N,N,N,N,N,61487,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61488,N, +30564,30565,61489,N,N,N,N,N,N,N,N,N,N,N,61490,N,N,N,N,N,N,N,N,N,N,61492,61493, +N,N,N,N,N,N,N,N,61494,N,N,N,N,N,N,61495,N,N,N,N,N,N,N,N,N,N,N,N,N,30567,61496, +N,N,N,N,N,N,N,N,N,N,N,N,30568,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61498,61499,N, +61500,61501,N,N,N,N,N,N,N,N,N,N,N,N,30569,N,30570,61502,N,N,N,N,N,N,N,N,N,N, +61504,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61507,N,N,N,N,N,N,61508,30571,61509,N,N,N,N,N,N,N,N,N,N,61510,N,N,N,N,N, +61511,61512,N,N,N,N,N,N,N,N,N,N,N,N,N,30573,30574,N,N,N,61515,N,N,N,N,61516,N, +61517,N,N,N,N,N,61514,N,N,N,61518,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30576,N, +61519,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30577,N,N,N,N,61521,61522,N,61524, +61525,N,61526,N,N,N,N,N,61527,N,N,N,N,30578,N,N,N,N,61528,N,N,N,61529,N,N,N,N, +61530,N,N,N,N,N,N,N,N,N,61531,30579,N,N,61532,N,N,N,61533,N,61534,30580,30581, +N,30582,N,N,61535,30583,N,61536,N,N,30584,N,N,N,N,N,N,N,N,N,61537,N,61538,N, +61539,N,N,61540,N,N,61541,N,N,N,N,N,61542,N,N,N,30585,N,61543,N,N,N,30586,N,N, +N,N,N,N,30587,N,N,30588,N,N,N,N,N,N,N,61544,N,30589,N,N,N,61545,N,30590,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,61546,61548,61549,N,N,N,N,N,30753,N,N,30754,N,N,N,N,N, +N,N,N,61547,N,N,N,N,N,N,30755,30756,N,N,N,N,N,N,N,N,61550,N,30758,N,30759,N, +30760,30761,30762,N,30763,30764,30765,61551,N,N,N,N,N,N,N,61552,N,N,N,N,N,N, +61554,N,N,61555,30766,N,30767,30768,N,N,N,30769,N,61556,N,N,N,N,61557,61553,N, +N,N,30770,N,N,N,N,N,61558,N,N,N,N,30771,N,N,N,N,N,N,N,N,30772,N,30773,N,N,N, +61559,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61560,N,N,N,61561,30774,30775,61562,30776, +N,N,N,N,N,N,30781,N,61564,N,N,N,N,61565,30777,61566,N,N,30778,N,N,30779,61729, +61730,N,30780,N,61731,30782,N,30783,30784,61732,61733,N,N,N,N,N,N,N,N,N,30785, +N,N,N,61734,61736,61735,N,N,N,30786,N,N,N,N,N,N,N,N,30787,30788,N,N,N,N,N,N,N, +N,N,N,N,N,61737,N,61738,N,30789,N,N,N,61739,N,N,N,N,N,N,N,N,N,N,N,N,61741,N,N, +N,61740,N,N,N,N,N,N,N,N,N,N,61743,N,N,N,N,30790,30791,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,30792,N,N,N,N,N,N,N,N,61745,N,N,N,61746,N,N,N,N,N,61747,N,N, +N,N,30793,N,N,N,N,N,N,N,N,N,N,N,N,N,61750,61751,N,61752,N,N,N,N,N,N,N,61753,N, +N,N,N,N,61754,N,61755,N,61756,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61757,N,N,30794,N,61759,61758,N,N,N,N,N,N,30795,61760,N,N,61761,61762,N,N, +61763,N,N,N,N,N,N,N,N,N,N,61765,N,N,N,N,N,30796,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61767,N,N,N,N,N,N,N,N,N,N,N,N,N,61769,N,N,N,N,N,N,61770,N,N,N,N,N,N,N,61771, +61772,N,N,N,N,N,61773,N,N,N,N,N,N,N,30798,61774,N,N,N,61775,N,N,N,N,N,N,N,N,N, +61776,N,61777,61778,N,N,N,30799,N,N,61779,N,N,N,N,61780,N,61781,N,N,61782,N,N, +N,N,N,N,N,61783,30800,N,30801,61784,N,N,N,61786,30802,N,N,N,N,N,N,61787,N,N,N, +61790,N,30803,30804,N,61785,30805,N,61791,61792,N,30806,N,N,N,N,N,N,61794, +32381,N,61795,N,N,N,N,30807,N,N,N,N,N,61797,N,30808,N,N,N,N,N,N,61796,N,N,N,N, +61800,N,30809,N,N,N,N,N,61802,N,30810,N,N,N,N,N,N,N,N,N,61803,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,30811,30812,N,N,N,N,N,N,N,30813,61805,30814,N,30815,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,30816,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61806,N,N,N,N,N, +30817,61807,30818,30819,N,61809,61808,N,N,N,N,30820,61810,61811,N,30821,N,N,N, +N,61812,N,N,N,N,N,N,30822,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30823,N,N,N,61814,N,N, +30824,N,30825,N,N,N,N,N,30826,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30827,N,61816, +N,N,N,61817,N,N,N,N,30828,N,N,N,N,N,N,N,N,N,N,30829,30830,N,N,N,N,N,N,N,N,N,N, +N,N,61819,N,30831,61820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61821,N,N,N,N,N,N, +30832,61822,30833,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30834,N,N,N,N,N,N,30835,30836, +N,N,N,N,N,N,N,N,N,61989,N,N,N,30837,N,N,30838,61990,N,30839,N,N,N,N,N,N,N, +61991,N,N,N,N,N,N,N,61993,N,N,N,N,N,N,N,30840,N,61994,61995,N,N,30841,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30842,N,N,N,N,N,61998,N,N,N,N,61999,N,N,62000,N, +62001,N,N,N,N,62002,30843,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62003,62004,30844,N,N,N, +62005,N,62006,N,N,N,62007,N,62008,N,N,N,62010,N,N,N,62011,N,N,N,N,N,N,62012, +62014,62015,N,N,62016,N,N,N,62017,N,N,N,N,N,N,N,N,N,N,N,62018,N,N,N,N,N,N,N, +62019,N,N,N,N,N,N,N,N,N,N,62020,30845,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,31009,N,N,N,62021,N,N,N,N,N,N,31010,31011,N,31012,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,62022,N,N,N,31013,N,62023,N,N,N,31014,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,62025,N,N,N,N,N,N,N,N,N,62026,N,N,N,N,N,N,N,N,62028, +62029,62030,N,N,N,N,62027,N,N,N,N,N,N,N,N,31018,N,N,31016,N,N,N,N,N,N,N,N,N,N, +62031,N,N,N,N,N,N,N,N,N,N,N,N,62032,N,N,N,62033,N,62034,N,N,N,N,N,N,62035,N,N, +N,N,N,N,N,N,N,N,62036,62037,N,N,31019,N,62038,N,N,N,N,N,N,N,N,N,N,N,31020,N,N, +N,N,31022,N,62039,62040,62041,N,N,62042,31021,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62044,N,N,N,N,N,N,N,N,N,N,62045,31023,N,N,N,N,N,N,N,N,62047,N,N,N,N,N,N,N,N, +31024,N,62046,31025,N,N,31026,N,N,N,N,N,N,62048,N,N,N,N,N,N,N,N,N,31029,31030, +N,N,N,62049,N,N,N,N,N,N,N,N,N,N,N,N,N,62050,N,N,62051,31034,N,N,N,N,N,N,N,N,N, +N,62053,N,N,N,N,N,N,N,N,N,N,62054,N,N,N,N,N,N,31038,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,62055,62056,62057,N,31042,N,N,62058,N,N,N,N,N,62059, +N,N,N,N,N,N,N,62060,N,N,N,N,N,N,N,31043,N,N,62061,N,N,N,31044,N,N,62062,N,N,N, +N,N,N,62063,N,N,N,N,62064,31045,N,31046,N,62065,62066,N,N,N,N,N,N,31048,N, +62067,N,N,N,N,N,N,N,31049,N,N,N,N,N,N,N,N,N,N,N,N,31050,N,31051,31052,N,N,N,N, +N,N,62072,N,N,N,N,N,N,62073,N,N,N,62074,N,N,N,N,N,62075,N,N,62076,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,62078,N,N,N,N,N,N,N,N,N,N,62241,31054,N,N,N,N,N,N,N,N,N,N,N,N, +N,62242,N,N,N,N,62243,N,N,N,N,N,N,N,N,N,62244,N,N,62245,N,N,62246,31055,N, +62247,62248,N,N,N,N,N,N,62249,N,N,62250,N,N,31056,N,N,N,N,N,N,N,62251,N,N, +62252,N,N,N,N,N,N,N,N,N,62253,N,N,31058,N,N,N,N,62254,N,N,N,N,N,62255,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,31059,N,N,62256,N,N,N,N,N,N,N,N,62257,N,N,N,N,N,N,31061, +N,N,N,N,N,62260,N,31062,62261,N,62262,N,N,N,N,N,N,N,N,N,N,N,N,N,62264,N,31063, +N,N,62265,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62266,62267,N,N,31064,N,N, +N,N,N,N,N,N,62268,N,N,N,N,N,N,N,N,31065,62271,N,N,N,N,N,N,N,N,N,N,31066,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62274,N,N,62275,N,N,31067,62276,62277,N, +62278,N,N,N,N,N,N,N,N,N,31068,N,62273,N,N,N,62282,N,N,N,N,N,31069,N,N,N,N,N,N, +31070,N,N,N,N,N,N,62284,N,N,N,N,N,N,N,N,N,N,31071,N,N,N,62286,N,62287,N,N, +62288,N,N,N,31072,N,31073,N,N,31074,62289,N,N,N,N,N,62285,N,N,N,N,N,62281,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,62292,62293,N,N,N,N,N,N,N,N,N,62294,N,N,31075,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,62296,N,N,N,N,N,62297,N,N,N,N,N,N,62298,N,N,N,N,N, +N,N,N,62299,N,N,N,N,62300,N,N,N,N,N,N,N,N,N,62303,N,62304,31077,N,31078,62305, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62306,N,N,N,N,N,62307,31079,N,62308,N,N,N,N,N,N, +N,62309,N,N,62310,62311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31081,N,31082,N,N,N,N,N, +62312,N,N,N,N,N,N,N,N,N,N,31080,N,31083,N,N,31084,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62313,N,N,N,N,62314,N,N,N,N,N,N,62315,N,N,N,N,N,62316,N,31087,N,N,N,N,62317,N, +N,62318,N,N,N,N,N,N,N,62319,N,N,N,31088,62320,62321,62322,N,N,N,N,N,N,N,N, +31089,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31090,N,N,N,N,31091,N,N,N,N,N, +N,N,N,N,N,N,31092,N,N,N,N,N,62326,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62328,62329,N, +N,N,N,31093,N,N,62330,N,N,N,N,62332,N,N,N,62334,N,N,N,N,62497,N,N,N,N,N,N,N, +31094,N,62499,N,31095,N,N,N,31096,N,N,N,N,N,N,N,N,62501,N,N,N,N,62502,N,N,N,N, +N,N,N,N,N,62504,62505,N,N,N,31097,31098,62506,N,N,N,N,N,N,N,N,62508,31099,N,N, +N,N,N,N,N,N,N,31100,62509,N,N,N,N,31101,N,N,N,N,N,N,N,N,N,N,N,N,N,31102,N,N,N, +N,N,N,N,N,N,N,N,62512,62513,N,62514,31265,N,N,N,N,N,62515,31266,N,N,N,N,N,N,N, +N,N,N,31267,N,N,N,N,N,62519,62520,N,31268,N,N,N,N,N,N,N,N,N,N,N,N,N,62521,N,N, +N,N,N,62522,N,N,N,N,N,N,N,N,N,31269,N,N,N,N,62524,N,N,N,31270,N,N,62526,N, +62527,N,N,31271,62528,N,N,N,N,N,N,N,N,N,N,62529,N,N,N,N,N,62531,N,N,31272,N,N, +N,N,N,31273,62532,N,N,62533,N,N,N,N,N,N,N,N,N,N,N,62534,62535,N,N,N,N,N,N,N,N, +62536,N,31274,N,N,N,N,N,N,N,N,N,31275,N,N,N,N,N,N,N,N,N,31276,62537,N,62538,N, +N,N,N,N,N,N,N,N,31277,N,N,62539,N,N,N,N,N,N,N,N,N,N,62540,N,N,N,N,N,N,N,62541, +31280,N,N,N,N,N,N,N,62545,31281,N,N,N,31282,N,62546,N,N,N,N,N,62547,N,N,62548, +N,N,N,N,N,N,62549,31279,N,N,N,62550,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,62551,N,31284,N,N,N,N,N,N,N,N,N,N,31285,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31286,N,N,N,N,N,N,N,N,N,32382,N,N,N,N,N,N,N,62552,N,62553,N,N,N,N,N,N,N,N, +62554,N,N,N,N,N,N,N,62555,62556,N,N,31287,N,N,31288,N,N,N,62558,N,N,N,N,N,N, +62559,N,62560,62563,62562,N,62564,N,N,N,N,62565,62566,N,N,31289,N,N,N,N,N,N,N, +62567,N,N,62570,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62572,N,62573,62574,N,N,N,N,N,N,N, +N,62575,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62576,62577,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,62579,31291,N,N,N,N,62582,31292,N,N,N,N,62583,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,62584,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31293,N,N,N,62586,N,N,N,N,N,N,N, +N,N,N,31294,62587,N,N,N,N,N,N,N,N,N,N,N,31295,N,N,N,31296,N,N,N,62588,N,62589, +N,N,N,N,N,N,31297,N,31298,62590,N,N,62753,N,N,N,N,N,N,N,31299,62754,N,N,N,N,N, +62756,N,62755,N,N,N,62757,N,N,62758,N,N,31301,N,62759,N,N,N,N,N,N,N,N,N,N,N,N, +N,62760,N,31302,N,N,N,N,N,62761,N,N,N,62762,N,N,N,N,31303,N,31304,N,N,N,N, +31305,N,N,N,N,N,N,62763,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62764,N,N,N,N,N,N,N,N,N,N,62765,N,N,N,62766,N,N,N,N,N,62767,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62768,N,N,62769,N,N,N,N, +N,N,N,62770,N,N,62771,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62772,N,N,N,N,N,N,N,N,N, +N,N,N,62774,N,N,N,N,31306,N,N,N,N,N,N,N,N,N,N,62775,N,31307,62776,N,N,N,N,N,N, +N,31308,N,N,N,N,N,62777,N,N,N,N,N,N,N,N,N,N,N,N,31309,N,62780,N,N,N,N,N,62781, +62779,N,N,N,N,N,N,N,N,62784,N,31310,N,N,N,N,N,62785,N,N,N,N,N,62787,N,N,62788, +N,N,N,N,62789,N,N,N,N,N,N,N,N,62783,N,N,N,N,N,N,N,62791,N,N,N,N,N,N,N,N,N,N,N, +N,31311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31312,N,N,N,N,N,N,31313, +31314,62793,N,N,N,31315,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62795,N,N,62797, +62798,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62800,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,62801,N,N,N,N,N,N,N,N,31316,N,N,N,N,N,62802,N,62803,N,N,N, +N,N,N,31317,N,N,N,N,31318,N,N,N,N,N,N,62804,31319,N,N,N,62805,N,N,N,N,N,N,N,N, +62807,N,N,N,N,N,N,N,62809,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62811,N,62812,62814, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62816,N,N,N,N,N,N,N,62817,62818,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,62820,N,62821,N,N,N,N,N,N,N,62822,N,N,N,N,N,N,N,N, +62825,62823,N,N,62824,N,62827,N,N,N,62829,N,N,N,N,N,N,N,62831,N,N,N,N,62833,N, +N,N,31323,N,N,62834,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31324,N,N,N,N,62838,N,N,N, +62840,N,62841,N,N,N,62842,N,N,N,N,N,N,62843,N,N,N,31326,N,N,N,N,62844,N,N,N,N, +N,N,N,N,N,N,N,N,N,31327,N,31328,31329,N,N,62845,62846,31330,N,N,N,N,31331,N,N, +N,63009,N,63010,N,N,31332,N,N,63011,N,63012,N,31333,31334,N,N,N,N,N,N,31335,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,31336,N,N,N,N,N,N,N,N,N,N,N,N,63013,N,N,N,N,N,63014, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63015,N,N,N,N,N,31337,31338,31339,31340,N,N,N,N,N, +63016,63017,N,N,N,63018,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63020,N,63021,N,N,N,N, +31342,N,N,N,N,N,N,N,N,N,N,31343,N,N,63022,N,N,N,N,N,N,N,N,N,31344,N,63023,N,N, +N,N,N,N,31345,63024,N,N,31346,N,N,N,N,N,N,N,N,N,31347,N,N,63019,31348,N,63025, +N,N,N,N,N,N,N,N,N,N,31341,44618,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,31349,N,63027,N,N,N,N,N,N,31350,N,N,N,N,N,N,63030,N,N,N,N,31351,N,63031, +63032,N,N,31352,N,N,63033,N,63034,N,N,N,N,N,N,N,N,N,31353,N,31354,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31355,31356,N,N,N,N,N,N,31357,N,63035,N,N,N,N,N, +31358,63036,31521,N,N,63037,N,N,N,N,N,N,N,N,63038,N,N,N,31522,N,N,N,63039,N,N, +N,N,31523,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63040,31524,N,N,N,N,31525,N,N,N,31526,N, +N,N,N,63041,N,63042,N,N,N,63043,N,63045,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63046,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31528,N,63047,N, +N,N,N,63048,N,63049,63050,N,N,N,N,N,N,63051,63052,N,63053,N,N,31529,N,N,N,N,N, +63055,N,N,N,N,N,N,N,N,N,N,31530,N,N,31531,N,N,63056,N,63057,N,N,N,63058,N,N,N, +N,63059,N,N,N,31532,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63062,N,N,N,N,N,N,31533, +N,N,N,N,N,N,N,63063,N,N,N,N,N,N,N,N,31534,N,N,N,N,31535,N,N,N,N,N,31536,N,N,N, +63064,N,31537,N,31538,N,N,N,N,N,N,N,N,N,N,N,63066,63067,N,N,N,63068,N,N,N,N,N, +N,N,N,63061,N,N,N,N,N,N,N,N,N,N,63070,N,N,63071,N,N,N,N,63072,63073,63074,N,N, +N,N,N,N,N,N,63075,N,N,63076,63077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63078,N,N,31541, +N,N,N,N,31542,63079,63080,N,N,N,N,N,63081,N,N,N,31543,N,N,31540,N,63082,N,N,N, +N,N,N,N,N,N,63087,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63083,N,63088,N,63089,N,N,N, +N,N,31544,N,N,N,N,63090,N,N,63091,63092,N,31545,N,N,N,N,N,N,N,N,N,N,63084,N,N, +N,N,N,N,N,N,N,N,31548,63094,N,63095,N,63096,N,63097,N,N,N,N,63098,N,N,N,N,N, +31549,N,N,31550,N,N,N,63099,N,N,N,N,N,N,N,N,N,63100,N,63101,N,N,31551,N,N,N,N, +N,N,N,N,N,N,31547,N,N,31552,N,N,N,N,N,N,63267,N,N,N,N,63268,N,N,N,N,N,N,N,N,N, +N,63269,N,N,63270,31553,N,N,31554,N,N,N,N,N,N,N,N,N,63271,63272,N,N,N,N,N, +63273,N,63274,N,N,N,N,63275,N,N,N,N,N,N,31555,N,N,N,N,N,N,N,N,63276,N,N,N,N,N, +N,N,N,31557,63277,N,N,N,31558,31559,N,N,N,N,N,N,N,N,N,N,31560,63278,31556,N,N, +N,N,N,31562,N,N,N,N,N,63279,N,N,63280,N,N,63281,N,N,63282,N,31563,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,31564,63284,N,N,63285,N,N,N,63287,12136,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,63289,N,N,63290,31565,N,N,N,31566,N,N,N,N,N,N,31568,N,N,N,N,N,N,N, +N,N,31570,N,N,63291,N,N,N,N,N,31571,N,63292,N,N,63293,N,N,N,N,N,N,N,N,N,N,N,N, +63294,N,63295,N,N,N,63296,N,N,N,63297,N,N,N,N,N,N,31572,N,N,N,63298,63299,N,N, +N,N,N,N,N,N,N,N,63300,N,N,N,N,N,N,N,N,63302,N,63303,N,N,N,N,31573,N,N,N,N,N,N, +N,N,63304,N,63305,N,N,N,N,N,N,N,N,N,N,N,N,N,63306,N,N,N,63307,N,63308,N,N,N,N, +N,N,N,N,N,N,N,63309,N,N,63310,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31574,N, +31575,31576,63312,N,63313,N,N,N,31577,N,N,63314,N,63315,N,N,63316,N,N,N,N,N, +63317,N,N,N,N,N,63318,N,63319,N,63320,N,N,N,N,N,N,N,N,N,N,N,N,N,63321,N,N,N,N, +N,N,N,N,63322,N,N,N,63323,N,63324,N,N,63325,N,N,N,N,N,N,N,N,N,N,N,N,N,63326,N, +N,N,N,N,N,63327,N,N,N,N,N,N,N,N,N,N,N,63328,63329,N,N,N,N,N,N,N,N,N,N,N,31578, +63330,N,N,N,N,N,N,N,N,N,63331,N,N,N,N,N,N,N,N,N,N,31579,31580,63335,N,63336,N, +N,N,N,N,N,N,63337,N,N,N,N,N,N,N,N,N,N,N,N,63338,N,N,N,N,N,N,63334,N,N,N,N, +31581,31582,N,N,N,N,N,N,N,31583,N,N,N,N,N,N,N,N,63341,N,N,63343,N,N,N,N,N,N,N, +N,N,N,N,N,63344,N,N,N,N,N,N,N,31585,N,N,N,N,N,N,N,N,63346,N,N,N,63348,N,63349, +63350,N,N,N,63351,63352,31586,63353,N,N,N,N,N,N,N,63345,63354,N,63355,N,N, +31587,N,N,N,31588,63356,N,N,N,N,31589,N,N,63357,31590,N,N,N,N,N,N,N,N,N,N, +31591,N,N,N,N,N,N,N,N,63358,N,N,N,N,N,63521,N,N,N,63522,N,N,N,N,N,N,N,N,N, +63523,N,N,N,N,N,N,N,N,N,N,N,N,N,63525,N,N,N,N,N,N,N,N,N,N,N,N,N,63526,N,N,N,N, +N,N,63527,N,N,N,N,63528,N,N,N,N,63531,N,N,N,N,N,63533,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31592,N,N,N,N,N,N,N, +63534,N,N,N,N,N,N,N,N,N,31593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63535,63536, +63537,N,63538,N,N,N,N,N,N,N,N,N,31594,N,N,N,31595,N,N,63541,63539,63542,N,N,N, +N,N,N,N,63543,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63544,63545,N,N,N,31597, +63547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31600,31601,31602,N,31598,N, +N,N,N,N,N,N,N,N,N,31603,N,N,N,N,N,N,N,N,31604,N,31605,N,N,N,N,63549,N,31606,N, +N,N,N,N,N,31607,N,63551,N,N,63552,N,N,N,63553,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,63556,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,63557,N,N,N,N,N,N,N,N,63558,N,N,N,N,N,N,63559,N,N,N,31608,N,N,N,N,N,N,N,N,N, +N,63560,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63561,N,N,N,N,N,N,63562,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31610,N,63563,N,63564,N,N,N,N,N,N,N, +N,N,N,N,N,31611,N,N,N,N,N,63565,N,N,N,N,N,63567,N,63568,N,N,31612,N,N,N,N,N,N, +63569,N,63570,63572,31613,N,63573,31614,N,N,N,N,N,N,N,N,N,N,N,63575,31777,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63576,N,31778,N,N,N,N,N,N,63577,N,N,N,N,N,N, +63578,N,31779,N,N,N,N,N,63579,31780,N,N,N,N,N,N,N,N,N,63580,N,N,N,N,31781,N,N, +N,31782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31783,N,N,N,31784,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63582,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,31785,N,N,N,N,N,N,63581,N,N,N,N,N,N,N,N,63583,N,N,N,N,N,N,63584,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,31786,N,N,N,N,N,N,63585,N,N,N,N,N,N,N,31787,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,31788,N,31789,N,N,N,N,N,63586,63589,N,N,N,N,63588, +N,N,63590,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63591,N,N,63592,N,N,N,N,N,N,N,N,N,N,N,N, +N,63593,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63594,N,N,31793,N,N,N,N,N,N, +N,N,N,N,63596,N,N,31794,N,N,N,N,31795,N,N,N,N,63597,N,N,N,N,N,N,N,N,N,N,31796, +N,N,N,N,N,N,N,N,N,N,N,N,63598,N,N,N,N,N,N,N,N,63599,N,63600,N,N,N,N,N,N,N,N,N, +63601,N,N,N,N,N,N,N,N,63602,63603,N,N,N,N,N,N,63604,31797,63605,63606,N,N,N, +63608,N,N,N,N,N,N,N,63611,N,63612,N,31798,N,N,N,N,N,63613,N,N,N,N,63614,N,N, +63777,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31799,63778,N,N,N,63779,N,N,N,N,N,63780, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63783,63782,N,N,N, +N,N,63784,N,63786,N,N,N,N,N,N,N,N,63787,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63789,63788,N,N, +63790,N,N,N,N,N,N,N,31801,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63792,63793,N,N,31802,N, +N,N,31803,N,N,N,N,N,31804,63795,N,N,N,N,63796,N,N,N,31806,N,N,N,N,N,N,N,N, +31807,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,63797,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63798,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,63799,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63800,N,N,N,N,N,N, +N,N,31808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63802,N,63803,N,N,N,N,N, +31809,N,N,31810,N,N,N,N,N,31811,N,63804,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63808,63809,N,N,N,N,N,63806,N,N,N,N,N,N, +N,63811,N,63812,N,N,N,N,N,N,N,N,N,31812,63813,63814,31813,N,N,N,63815,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,63818,N,N,63819,N,N,N,31814,N,N,N,N,N,N,N,N,N,N,N,N,N, +63820,N,N,N,N,N,N,N,N,63821,N,N,N,N,N,N,N,N,N,N,N,N,N,63822,N,N,N,N,N,N,N,N,N, +63823,63824,N,63825,31815,N,N,N,N,N,N,N,N,N,N,31816,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63826,N,N,N,N,N,63827,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,63828,N,N,N,N,63829,N,63830,63831,N,N,N,N,63832,N,N,N,N,31818,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,63834,N,N,63835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63837,31820,63839,N,N,N,N,N,N,N,63840,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,63841,N,N,N,N,N,N,31821,N,N,N,N,N,N,N,N,N,N,N,N,63842,N, +31822,N,N,N,N,N,N,N,N,31823,N,N,N,N,N,N,N,N,N,63843,N,N,N,N,N,N,N,N,N,63844,N, +N,N,N,N,N,N,N,N,31824,N,N,N,63845,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63847,N,31826,N,N,N,N,N,N,N,N,N,N,N,N,N,63848, +31827,63850,N,N,N,N,N,N,N,N,N,N,63852,N,N,N,N,63853,N,N,N,63855,N,N,63856,N,N, +N,N,N,63857,N,63858,N,N,N,N,N,N,N,N,N,N,63859,N,N,N,31828,N,N,N,31829,N,N,N,N, +N,31830,N,N,63860,N,N,N,63861,N,N,N,N,N,63862,63863,N,N,N,N,N,31831,N,N,N, +63864,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31832,N, +N,N,N,N,N,N,N,N,63865,N,N,N,N,N,N,N,N,N,N,N,63867,63868,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,63869,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64034,N,N,31834,N,N,N,64035,N,N,N,64036,N,N,N, +N,31835,N,31836,N,31837,N,31838,N,N,N,N,N,64038,31839,N,N,N,N,N,N,N,N,N,N,N,N, +N,64040,N,N,31840,N,N,64041,N,N,N,N,N,N,N,31841,N,N,N,N,64042,31842,31843,N, +31844,64043,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31845,N,N,N,N,64045,31846,31847,64046, +N,N,N,N,N,N,N,N,N,N,N,64051,N,N,N,31848,N,N,64049,N,31849,N,64048,N,N,N,N,N,N, +N,64052,64053,64050,N,N,N,64054,N,64055,N,N,N,N,N,N,N,N,N,N,N,N,N,31851,31852, +31853,N,64056,N,N,N,64057,N,64058,N,N,N,31854,31855,N,N,N,31856,N,N,N,N,N,N,N, +31857,N,31858,N,N,31859,N,N,64059,N,64060,64061,N,N,31860,N,N,N,N,N,N,N,N, +64062,64063,31861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64064,N,64065,N,31862,N,N,N,N,N, +64066,N,N,64067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64068,N,N,N,N,64069,N,N,N,N,N,N, +N,N,N,31863,N,64070,N,N,N,N,N,N,N,N,64071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31864, +N,N,N,N,N,N,N,N,N,64072,N,N,N,31865,N,64073,N,N,31866,N,64074,N,N,64075,N,N,N, +N,N,31867,N,N,N,N,N,N,64076,64077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31868,N, +N,64078,N,N,N,N,N,N,N,N,N,31870,32033,N,N,N,N,N,N,64081,32034,64082,N,N,32035, +N,N,N,N,N,N,N,N,N,31869,64083,N,N,N,N,N,32036,N,N,64084,N,N,N,N,N,32037,N,N,N, +N,N,64085,64086,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64088,N, +N,N,N,32038,32039,32040,N,32041,N,N,N,32042,N,64089,32043,N,N,N,64090,N,N, +64091,N,N,N,64092,32044,N,64093,N,N,N,N,64094,N,N,64095,N,N,N,N,N,N,64096, +64097,N,N,N,64098,N,64099,64100,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32045,N,N,N, +64103,64104,N,64105,N,N,N,N,N,N,N,N,32046,64106,N,N,N,64107,N,N,N,N,N,N,N,N,N, +64108,N,64109,N,N,N,N,N,64110,N,N,N,N,N,N,N,64111,N,N,N,64112,N,N,N,N,N,N, +64115,N,N,N,N,N,N,N,N,N,N,N,N,64116,64117,N,32047,N,N,N,64118,N,N,N,N,32048, +32049,N,64119,N,64120,N,N,32050,N,N,N,64121,N,64122,N,N,N,N,N,N,32051,N,N,N,N, +64123,N,64124,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64290,N,64291,N,64292,N,N,N,32052, +64293,N,32053,N,N,N,N,N,N,N,N,64294,N,N,N,64125,N,N,N,64295,N,N,N,N,N,N,N, +64296,64297,32054,N,32055,N,N,N,32056,N,64298,N,64299,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64302,32057,32058,32059,N,N,N,N,N,N,64303,N, +N,N,N,N,64304,N,N,64305,N,N,N,N,N,N,N,N,N,32060,32061,N,N,N,N,32062,64306,N,N, +N,N,32063,64307,N,64308,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64312,N,N, +64313,N,N,N,64314,N,N,N,N,N,N,N,N,N,N,N,32064,N,N,64315,N,N,64309,N,32065,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32066,N,N,N,N,N,N,64320,N,N,N,N,32067, +64321,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64322,N,32068,32069,N,N,64323,N, +N,N,N,64324,N,N,N,N,N,N,N,N,N,64319,N,N,N,64316,N,N,N,N,N,64329,N,32071,32070, +N,N,N,N,64325,N,N,N,N,N,64326,N,N,N,N,N,N,64327,64328,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64330,32072,64331,N,N,N,N,N,N,64332,N,N,N,N,N,N,N, +N,N,64333,N,N,N,N,32073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32074, +N,N,N,N,N,N,N,32075,N,64336,N,64337,N,32076,32077,64338,64339,N,N,N,N,N,N,N,N, +N,N,N,N,64340,N,N,N,N,N,64341,64342,32078,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32079,N,N,N,N,N,N,32080,N,N,32081,N,64344,32082,N,N,N,N,N,N,N,64345,N,32083,N, +N,N,N,N,N,32084,N,N,N,N,N,N,N,N,N,N,64347,N,N,32085,N,N,N,N,32086,N,N,32087,N, +N,N,N,N,N,32089,N,N,N,32090,64037,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64350,N,N,N,N,N, +N,64351,64352,N,N,N,N,N,N,N,64354,N,N,N,N,64355,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,32091,N,N,N,N,N,N,N,N,64356,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,64358,N,32092,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,64360,N,N,32094,N,N,N,N,N,N,32095,32096,N,N,N,64363,N,N,N,N,N,64364,N,N, +N,64365,N,N,N,N,N,N,64366,N,N,64367,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32097,N,N,N,N,N,64370,N,64371,N,N,64372,32098,N,N,N,N,N,N,N,N,N,N,32100,N,N,N, +N,N,32101,64374,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64375,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,32102,N,N,64377,N,N,N,N,32103,N,N,N,N,N,64378,N,N,N,N,N,64379,N,N,N,N,N, +32104,32105,32106,N,N,N,N,N,64380,N,64381,N,N,32107,64382,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64545,N,N,N,32108,N,N,N,N,32109,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,32110,64548,N,N,N,64549,N,N,N,64550,N,N,N,64551,N, +N,N,N,N,N,N,N,N,N,N,32111,N,N,64552,64553,N,N,N,N,N,N,N,32112,N,N,N,64554,N,N, +32113,N,N,N,N,N,N,N,32114,N,N,64555,N,N,N,N,64556,N,N,64557,N,N,N,64558,64559, +N,32116,N,N,32115,N,N,64560,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64561,N,N,32117, +64562,N,N,N,N,N,32119,N,N,64563,64564,N,N,N,N,N,64565,N,64566,N,N,N,N,N,N,N, +32120,N,N,N,N,64569,N,64572,N,N,N,N,N,32121,N,N,N,N,32122,N,64570,64571,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64573,N,N,N,N,N,N,N,N,N,N,32124,32125,N,N, +32126,32289,N,32290,32291,N,N,N,N,N,N,N,N,N,N,32293,64574,N,N,N,N,N,32294,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64575,N,64576,N,N,64577,N,N,N,N,N,N, +64579,64580,N,32295,64581,64582,N,N,64583,N,N,64584,N,N,N,N,64585,32296,N,N, +64586,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64587,64589,N,64590,N,64591,N, +32297,N,N,64592,N,N,N,N,N,64593,64594,N,64595,64596,N,N,N,N,N,N,N,N,N,N,N,N,N, +64599,64600,N,N,64602,64603,64604,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64606,64607,64608,N,N,N,N,N,N,64609,64610,64611,N,N,N,64612,64613,N,N,N,N, +64614,N,N,N,N,N,N,64615,64616,N,N,N,N,N,N,N,N,N,32298,N,N,N,64617,N,N,64618, +64619,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32299,N,N,N,N,64620,N,N, +64621,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64622,N,N,N,64623,N,64624,N,N,N, +64625,N,N,N,N,N,64626,N,N,N,N,N,N,N,N,N,N,64627,N,N,N,N,64628,N,N,N,N,64629,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64631,N,N,N,N,N,N,N,N,64632,N,N,64633,32300, +32301,N,N,N,N,N,N,64634,N,N,N,N,N,N,64635,N,N,N,N,64636,N,N,N,64637,N,N,N,N,N, +64638,N,N,N,32302,N,N,N,N,N,N,N,N,32303,32304,N,N,64801,N,N,N,N,64802,N,32305, +N,N,N,N,N,N,N,N,N,N,N,64803,N,N,N,N,N,32306,N,64804,N,32307,N,N,N,32308,N,N,N, +N,N,64805,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,64807,N,N,N,N,N,N,32309,64809,N,64811,N,N,N,N,N,N,N, +32310,N,32311,N,N,64813,N,N,N,N,N,N,N,32312,N,64814,N,64815,N,N,64816,32313,N, +N,N,N,N,64818,N,N,N,64819,N,N,N,N,64820,N,N,N,64821,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,32314,32315,64822,N,N,N,N,32316,N,N,N,64823,N,N,N,64824,N,64825,N,N,N, +64826,N,N,N,N,N,64827,N,N,N,32317,N,N,N,N,N,N,N,N,N,N,64828,N,32319,N,N,N,N,N, +64829,N,N,N,N,N,N,N,N,N,64830,N,N,N,N,N,N,N,N,N,N,N,N,N,64832,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,32320,N,N,N,N,64833,N,64834,32322,N,N,N,N,64835,64836,N,N, +N,N,N,32323,64837,N,32324,64838,64839,N,32321,N,N,N,N,N,N,N,N,N,N,32325,N,N,N, +N,N,32326,N,N,N,N,32327,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32328,N,N,N,N,N,N,N,64840, +32329,N,N,N,N,64841,N,N,N,N,64842,64845,N,N,N,N,N,64846,N,N,N,N,N,64847,N,N, +32330,N,N,N,N,N,64848,N,N,N,N,N,N,32331,N,N,N,N,N,N,N,N,N,64850,N,N,N,N,64851, +N,N,N,N,N,N,N,32332,N,64852,N,N,64853,64854,N,N,64856,64855,N,N,N,64849,N,N,N, +64860,32333,N,64858,N,N,32334,32335,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64862,N,64863,64864,64865,N,N,64866,N,N,N,N,64867,32336,N,N,N,64868,N,64869, +64870,N,N,N,N,N,N,64872,N,N,N,N,64873,64874,N,N,N,N,N,N,N,N,N,32337,N,N,N, +64875,N,N,N,64878,64879,N,N,N,N,32338,32339,N,N,32340,64881,N,N,N,64882,N,N, +64883,64876,64884,N,64885,N,N,N,32341,N,32342,N,N,N,64886,64887,64888,N,64889, +64890,N,64891,N,64892,N,N,64893,N,32343,N,N,64894,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65057,N,N,N,N,N,N,N,N,N,N,N,65058,65060,N,N,N,N, +N,N,N,N,65059,N,N,N,N,N,65062,N,N,N,N,N,65063,65064,N,N,N,N,32344,32345,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65068,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65070, +32346,N,N,N,32347,N,N,65071,N,N,N,N,N,N,N,32348,N,N,N,N,N,N,N,N,N,N,N,N,65072, +N,N,65073,32349,N,N,N,N,N,65075,N,65076,N,N,N,N,32350,N,N,65078,N,N,65079, +65080,N,N,N,N,32351,N,65081,N,N,N,N,N,65082,N,N,N,N,N,32352,N,N,65083,N,N,N,N, +N,N,N,N,32353,N,N,65084,N,N,N,N,N,N,N,65085,N,N,N,N,N,N,N,N,N,N,32355,N,N,N,N, +N,N,N,N,65087,N,N,N,65088,N,N,32356,65089,N,65086,32354,N,N,65090,N,N,N,65091, +N,65092,N,N,N,N,N,N,N,N,N,N,N,N,65093,32357,N,N,65094,N,N,N,N,65095,65096,N,N, +65097,N,N,N,32359,N,N,N,N,N,N,N,N,N,N,N,N,65098,65101,N,N,N,N,32360,N,N,65100, +N,N,65102,N,N,N,N,N,N,N,32361,N,N,N,65103,N,N,65104,65105,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,65106,32362,N,N,N,65108,N,N,N,N,65109,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,65110,N,N,32363,N,N,N,N,N,32364,N,N,N,65111,N,N,N,32365,N,N,32366, +N,N,N,N,32367,32368,N,N,N,N,N,N,N,65113,N,N,N,N,N,32369,N,N,N,N,N,N,N,N,N,N,N, +N,N,32370,N,N,N,N,N,N,N,N,N,N,N,N,N,65115,N,N,N,N,N,N,N,65116,N,N,N,N,N,N, +65117,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65118,65119,65121,N,N,N,N,N,N,N,N,N,N,N, +N,32371,N,N,N,N,N,N,65122,N,65123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +65124,N,N,N,N,N,N,N,65125,N,32372,65126,N,N,65127,N,N,N,65128,N,N,N,65129, +65130,N,N,N,N,N,N,N,N,N,N,N,N,65131,N,65132,N,32373,65133,N,N,N,N,65135,N,N,N, +N,N,N,N,N,N,N,N,65137,N,N,N,65139,N,N,65140,N,N,N,N,65141,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32374,N,N,N,32375,N,N,32376,N,N,N,N,N,N,N,N,N, +N,32377,30267,N,N,N,N,N,N,N,N,N,N,29742,30030,N,N,N,N,N,N,N,N,N,N,N,N,31567,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32292,N,N,N,N,N,N,N,N,N,N,N,32093,12107,12119,20338,N,44665,30074,30554,30575, +N,N,31036,31037,31041,N,N,N,31546,63288,63301,31790,N,63854,N,31850,N,N,N,N,N, +N,N,N,N,11832,11849,11856,11875,11880,11886,12076,12079,12086,12122,12126, +20321,20322,29776,29788,29790,29793,29992,29995,30019,30053,30313,30327,30501, +30549,61481,30757,31015,31027,31028,31031,31032,31033,31035,31039,31040,31053, +31057,31076,31278,62544,31283,31290,31300,31320,62836,62837,31527,31599,31609, +31791,31792,31800,31805,63849,31833,32099,32118,32123,9022,9021,8752,N,N,N,N, +8751,N,N,N,N,N,8753, +}; + +static const struct unim_index jisx0213_bmp_encmap[256] = { +{__jisx0213_bmp_encmap+0,126,255},{__jisx0213_bmp_encmap+130,0,253},{ +__jisx0213_bmp_encmap+384,80,233},{__jisx0213_bmp_encmap+538,0,194},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_bmp_encmap+733,62,63 +},{__jisx0213_bmp_encmap+735,112,115},{__jisx0213_bmp_encmap+739,19,172},{ +__jisx0213_bmp_encmap+893,15,233},{__jisx0213_bmp_encmap+1112,5,219},{ +__jisx0213_bmp_encmap+1327,5,206},{__jisx0213_bmp_encmap+1529,35,254},{ +__jisx0213_bmp_encmap+1749,177,230},{__jisx0213_bmp_encmap+1803,0,110},{ +__jisx0213_bmp_encmap+1914,19,127},{0,0,0},{__jisx0213_bmp_encmap+2023,52,251 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_bmp_encmap+2223, +22,255},{__jisx0213_bmp_encmap+2457,240,255},{__jisx0213_bmp_encmap+2473,49, +250},{__jisx0213_bmp_encmap+2675,3,205},{__jisx0213_bmp_encmap+2878,2,219},{ +__jisx0213_bmp_encmap+3096,31,244},{__jisx0213_bmp_encmap+3310,5,207},{ +__jisx0213_bmp_encmap+3513,97,253},{__jisx0213_bmp_encmap+3670,0,250},{ +__jisx0213_bmp_encmap+3921,23,111},{__jisx0213_bmp_encmap+4010,110,234},{ +__jisx0213_bmp_encmap+4135,14,240},{__jisx0213_bmp_encmap+4362,15,210},{ +__jisx0213_bmp_encmap+4558,17,212},{__jisx0213_bmp_encmap+4754,5,148},{ +__jisx0213_bmp_encmap+4898,87,215},{__jisx0213_bmp_encmap+5027,57,147},{ +__jisx0213_bmp_encmap+5118,5,243},{__jisx0213_bmp_encmap+5357,7,221},{ +__jisx0213_bmp_encmap+5572,2,240},{__jisx0213_bmp_encmap+5811,8,212},{ +__jisx0213_bmp_encmap+6016,8,234},{__jisx0213_bmp_encmap+6243,15,175},{ +__jisx0213_bmp_encmap+6404,12,253},{__jisx0213_bmp_encmap+6646,22,181},{ +__jisx0213_bmp_encmap+6806,176,250},{__jisx0213_bmp_encmap+6881,4,188},{ +__jisx0213_bmp_encmap+7066,59,232},{__jisx0213_bmp_encmap+7240,23,209},{ +__jisx0213_bmp_encmap+7427,7,119},{__jisx0213_bmp_encmap+7540,2,255},{ +__jisx0213_bmp_encmap+7794,0,242},{__jisx0213_bmp_encmap+8037,0,243},{ +__jisx0213_bmp_encmap+8281,3,244},{__jisx0213_bmp_encmap+8523,1,251},{ +__jisx0213_bmp_encmap+8774,0,245},{__jisx0213_bmp_encmap+9020,18,255},{ +__jisx0213_bmp_encmap+9258,0,233},{__jisx0213_bmp_encmap+9492,7,247},{ +__jisx0213_bmp_encmap+9733,10,255},{__jisx0213_bmp_encmap+9979,4,244},{ +__jisx0213_bmp_encmap+10220,5,248},{__jisx0213_bmp_encmap+10464,12,245},{ +__jisx0213_bmp_encmap+10698,0,253},{__jisx0213_bmp_encmap+10952,3,244},{ +__jisx0213_bmp_encmap+11194,6,233},{__jisx0213_bmp_encmap+11422,0,253},{ +__jisx0213_bmp_encmap+11676,0,252},{__jisx0213_bmp_encmap+11929,13,248},{ +__jisx0213_bmp_encmap+12165,16,245},{__jisx0213_bmp_encmap+12395,21,253},{ +__jisx0213_bmp_encmap+12628,3,247},{__jisx0213_bmp_encmap+12873,9,255},{ +__jisx0213_bmp_encmap+13120,4,252},{__jisx0213_bmp_encmap+13369,0,251},{ +__jisx0213_bmp_encmap+13621,1,252},{__jisx0213_bmp_encmap+13873,1,252},{ +__jisx0213_bmp_encmap+14125,3,254},{__jisx0213_bmp_encmap+14377,15,253},{ +__jisx0213_bmp_encmap+14616,11,255},{__jisx0213_bmp_encmap+14861,2,251},{ +__jisx0213_bmp_encmap+15111,0,252},{__jisx0213_bmp_encmap+15364,23,251},{ +__jisx0213_bmp_encmap+15593,10,252},{__jisx0213_bmp_encmap+15836,0,236},{ +__jisx0213_bmp_encmap+16073,3,254},{__jisx0213_bmp_encmap+16325,0,251},{ +__jisx0213_bmp_encmap+16577,7,250},{__jisx0213_bmp_encmap+16821,1,255},{ +__jisx0213_bmp_encmap+17076,1,249},{__jisx0213_bmp_encmap+17325,0,252},{ +__jisx0213_bmp_encmap+17578,10,251},{__jisx0213_bmp_encmap+17820,5,254},{ +__jisx0213_bmp_encmap+18070,0,237},{__jisx0213_bmp_encmap+18308,3,253},{ +__jisx0213_bmp_encmap+18559,7,240},{__jisx0213_bmp_encmap+18793,1,245},{ +__jisx0213_bmp_encmap+19038,3,249},{__jisx0213_bmp_encmap+19285,8,154},{ +__jisx0213_bmp_encmap+19432,59,250},{__jisx0213_bmp_encmap+19624,2,251},{ +__jisx0213_bmp_encmap+19874,13,255},{__jisx0213_bmp_encmap+20117,4,254},{ +__jisx0213_bmp_encmap+20368,0,249},{__jisx0213_bmp_encmap+20618,1,253},{ +__jisx0213_bmp_encmap+20871,12,255},{__jisx0213_bmp_encmap+21115,0,253},{ +__jisx0213_bmp_encmap+21369,5,245},{__jisx0213_bmp_encmap+21610,1,245},{ +__jisx0213_bmp_encmap+21855,1,255},{__jisx0213_bmp_encmap+22110,17,252},{ +__jisx0213_bmp_encmap+22346,5,158},{__jisx0213_bmp_encmap+22500,57,254},{ +__jisx0213_bmp_encmap+22698,9,253},{__jisx0213_bmp_encmap+22943,6,250},{ +__jisx0213_bmp_encmap+23188,0,251},{__jisx0213_bmp_encmap+23440,2,255},{ +__jisx0213_bmp_encmap+23694,0,251},{__jisx0213_bmp_encmap+23946,1,255},{ +__jisx0213_bmp_encmap+24201,2,253},{__jisx0213_bmp_encmap+24453,4,114},{ +__jisx0213_bmp_encmap+24564,120,222},{__jisx0213_bmp_encmap+24667,29,239},{ +__jisx0213_bmp_encmap+24878,20,244},{__jisx0213_bmp_encmap+25103,4,243},{ +__jisx0213_bmp_encmap+25343,8,252},{__jisx0213_bmp_encmap+25588,2,249},{ +__jisx0213_bmp_encmap+25836,2,253},{__jisx0213_bmp_encmap+26088,0,242},{ +__jisx0213_bmp_encmap+26331,2,244},{__jisx0213_bmp_encmap+26574,2,255},{ +__jisx0213_bmp_encmap+26828,2,162},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_bmp_encmap+26989 +,29,220},{__jisx0213_bmp_encmap+27181,15,106},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_bmp_encmap+27273,69,70},{__jisx0213_bmp_encmap+27275,2,13}, +}; + +static const ucs2_t __jisx0213_1_emp_decmap[340] = { +11,4669,U,U,U,U,U,U,U,U,U,4891,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,5230,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,6333,2975,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,5812,U,U,U,U,U,U,U,U,U,U,7732,12740,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +13764,14143,U,U,U,U,U,U,U,U,14179,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,15614,18417,21646,21774,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22385,U,U,U,U,U,U,U,U,U,U,U, +U,22980,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23969,27391,28224,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28916,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30340,33399,U,U,U,U,U,U,U,33741,41360, +}; + +static const struct dbcs_index jisx0213_1_emp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_1_emp_decmap+0,34,34},{__jisx0213_1_emp_decmap+1,66,123},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{__jisx0213_1_emp_decmap+59,84,110},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_1_emp_decmap+86,58,114},{ +__jisx0213_1_emp_decmap+143,41,96},{__jisx0213_1_emp_decmap+199,108,108},{ +__jisx0213_1_emp_decmap+200,126,126},{__jisx0213_1_emp_decmap+201,41,110},{ +__jisx0213_1_emp_decmap+271,93,93},{__jisx0213_1_emp_decmap+272,51,108},{ +__jisx0213_1_emp_decmap+330,73,81},{0,0,0},{__jisx0213_1_emp_decmap+339,102, +102},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const ucs2_t __jisx0213_2_emp_decmap[2053] = { +137,U,U,U,U,U,U,U,U,U,162,U,U,164,U,U,U,U,U,U,U,418,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,531,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,811,U,U,U,U,U,U,897,U,881,1017,U,U,1098,U,1289,U,U,U,U,U,U,U,U,U, +1494,1576,U,U,U,U,U,1871,U,U,U,U,U,U,2055,U,2106,U,U,U,U,U,U,U,U,2233,U,U,U,U, +U,U,U,2428,2461,U,U,U,U,U,2771,U,U,2845,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,3397,3553,U,U,U,U,U,U,3733,3693,U,U,U,U,U,U,U,3684,U,U,3935,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,4609,U,U,4693,U,4731,U,U,U, +U,4724,U,U,U,U,U,U,4836,4823,U,U,U,U,U,U,4861,U,4918,4932,5060,U,U,U,U,U,U,U, +U,U,U,U,U,5229,U,U,U,U,U,U,U,U,U,U,U,5591,U,U,U,U,U,27689,U,U,5703,U,U,U,U,U, +U,U,U,U,U,U,U,U,5894,5954,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,6595,7254,U,U,U,U,U,U,7469,7493,U,7544,7522,U,U,U, +7585,7580,U,U,U,U,7570,U,U,7607,U,7648,7731,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +7966,U,U,U,U,U,U,U,U,U,U,8054,U,U,U,U,U,8186,8571,U,U,U,U,U,U,U,U,8990,U,U,U, +U,9133,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,9971,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,10331,U,U,U,U,U,U,U,10411,U,U,U,U,10639, +10936,U,U,U,U,11087,11088,U,U,U,U,U,U,U,11078,U,11293,11174,U,U,U,11300,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,11745,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12739,12789,12726,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,13170,U,13267,13266,U,U,U,U,13264,13284, +13269,U,U,13274,U,13279,U,U,U,U,U,U,U,U,U,U,U,13386,13393,13387,U,U,U,13413,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,13540,13658,13716,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,13881,13895,U,13880,13882,U,U,U,U,U,U,U,U,U,U, +14108,U,U,U,U,U,U,U,U,U,U,14092,U,U,U,U,U,U,U,14180,U,U,U,U,U,U,U,14335,14311, +U,U,U,U,U,14372,U,U,U,U,14397,15000,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,15487,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,15616,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +15680,U,15866,15865,15827,16254,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,16534, +U,U,U,U,U,16643,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,16838,U,U,16894,17340,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,17961,U,U,U,U,U,18085,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,18582,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,19021,19286,U,19311,U,U,U,U,19478,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,19732,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,19982,U,U, +U,20023,U,U,U,U,20074,U,U,20107,U,U,U,U,U,U,U,U,U,U,U,20554,U,20565,U,U,20770, +20905,U,20965,20941,U,U,U,21022,U,U,U,21068,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +21550,U,U,U,U,U,U,U,U,U,U,21721,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21927,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22441,22452,22996,U,U,U,U,U,U,U, +U,U,U,23268,23267,U,23281,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23474,U,U,U,U,U,U, +U,U,U,U,23627,23652,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24110,24150,24165, +U,24162,U,U,U,24280,U,24258,24296,U,24355,U,U,24412,U,U,U,U,U,U,24544,24532,U, +U,U,U,24588,24571,U,U,U,U,U,U,U,24599,U,U,U,U,24672,U,U,U,U,U,U,U,U,U,U,U,U, +24813,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25200,U,25222,U,U,U,U, +U,U,25420,U,U,15630,U,U,U,25602,26238,U,U,U,U,26288,U,U,U,U,U,U,U,U,U,U,U, +26397,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26845,U,26858,U,26961,U,U,26991,U,27101,U, +U,U,27166,U,U,U,U,U,U,27224,U,U,U,U,U,27276,U,U,27319,27763,U,U,U,U,U,U,U,U,U, +27869,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28261,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,28564,U,U,U,U,U,U,U,U,28664,28662,28663,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,28941,U,U,28985,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29659,29658,U,U,U,U,U,29694,U,U,29712,U,U,U,U, +29769,30229,30228,U,30257,U,U,U,U,U,U,U,30355,U,U,U,U,U,U,U,30478,U,30499,U,U, +U,30546,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31109,U,U,U,U,U,U,U,U,U,U,U,U, +31364,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31667,U,31678,31687,31928,U,U,U,U, +U,U,U,U,U,32160,U,U,32272,U,U,U,U,U,U,32695,U,U,U,U,U,U,U,U,32906,U,U,U,U,U, +32955,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33410,U,U,U,U,33523,U,U,U,U,U,U,U,33804, +U,U,U,U,33877,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34155,U,U,U,34248,34249,U,U,U,U,U,U, +U,U,U,U,34519,U,U,34554,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,35145,35142,U,U,U,U,U,U,35179,U,U,U,U,U,U,U,U,U,U,U,U,U,35207,35208,U, +U,U,U,U,U,U,U,U,U,35258,35259,U,U,U,U,U,U,U,U,U,U,U,35358,35369,U,U,U,U,U,U,U, +U,U,U,35441,35395,U,U,U,U,U,U,U,U,35481,35533,U,U,U,U,U,35556,35549,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,35777,35823,U,U,U,U,U,U,U,36112,U,U,36209,U,36347,36383,U, +U,U,36406,U,U,U,36489,U,36587,U,36658,U,U,U,U,U,U,U,36856,37536,37553,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38032,U,U,U,U,U,U,U,U,U,38351,U,U,U,U,U,U,U,U, +U,38527,U,U,U,U,U,U,U,U,U,38640,U,U,38681,U,U,U,38736,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,39110,39538,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,40411,40509,U,U,U,U,U,U,U,U,U,U,U,U,40469,U,40586,U,40521,U, +U,U,U,U,U,U,U,U,40644,U,U,U,U,U,40681,U,U,40667,40910,U,U,U,41007,U,40986,U,U, +U,U,U,U,41209,U,U,41090,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,8728,U,U,U,U,41868,U,42039,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,42481,U, +42498,U,42522,U,U,U,42674, +}; + +static const struct dbcs_index jisx0213_2_emp_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_emp_decmap+0,33,121},{0,0,0},{ +__jisx0213_2_emp_decmap+89,34,119},{__jisx0213_2_emp_decmap+175,42,117},{ +__jisx0213_2_emp_decmap+251,37,126},{0,0,0},{0,0,0},{__jisx0213_2_emp_decmap+ +341,48,108},{0,0,0},{0,0,0},{0,0,0},{__jisx0213_2_emp_decmap+402,34,114},{ +__jisx0213_2_emp_decmap+483,36,125},{__jisx0213_2_emp_decmap+573,35,120},{ +__jisx0213_2_emp_decmap+659,42,117},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +__jisx0213_2_emp_decmap+735,35,96},{__jisx0213_2_emp_decmap+797,50,100},{ +__jisx0213_2_emp_decmap+848,34,123},{__jisx0213_2_emp_decmap+938,46,122},{ +__jisx0213_2_emp_decmap+1015,33,118},{__jisx0213_2_emp_decmap+1101,50,125},{ +__jisx0213_2_emp_decmap+1177,34,121},{__jisx0213_2_emp_decmap+1265,53,115},{ +__jisx0213_2_emp_decmap+1328,68,126},{__jisx0213_2_emp_decmap+1387,33,115},{ +__jisx0213_2_emp_decmap+1470,41,122},{__jisx0213_2_emp_decmap+1552,37,126},{ +__jisx0213_2_emp_decmap+1642,33,126},{__jisx0213_2_emp_decmap+1736,33,113},{ +__jisx0213_2_emp_decmap+1817,34,118},{__jisx0213_2_emp_decmap+1902,44,112},{ +__jisx0213_2_emp_decmap+1971,37,118},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __jisx0213_emp_encmap[8787] = { +11810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,41249,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41259,N,41262,41270,41286,41328,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,41337,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41335,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41762,41765,41767, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,41777,41778,41784,41791,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41793,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,41802,41810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,41811,41817,41820,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20308,41847,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42026,42042,N,N,N, +N,N,N,N,N,42034,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,42033,42045,42073,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +12098,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42076,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42083,N,N,N,N,N,N,42078,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,42091,N,N,N,N,N,N,N,N,N,N,N,N,42090,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,42098,12108,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,42100,N,N,N,N,N,N,N,N,N,N,N,N,N,42101,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42277,42290, +12128,42302,42311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +20323,42325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,42326,12155,42366,43056, +43063,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43064,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43067,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,43066,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43077,N,N,N,N,N, +N,N,N,N,43072,N,N,N,N,43071,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43080,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43082,43083,20334,43099,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43110,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +43116,44066,65107,44075,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44080,44112,44133,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,44141,44146,44324,44338,N,N,N,N,N,N,N,N,44329,44330,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,44341,44340,N,N,N,N,N,N,44345,44374,44580,N,N,N,N,N,N,N,N,N,N,N,N, +44413,30010,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44579,44602,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44610, +N,44605,44604,N,44612,N,N,N,N,44615,N,N,N,N,44617,N,N,N,N,44611,44629,44631,N, +N,N,N,N,44630,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44635,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +44663,44664,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44842,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30066, +44866,44863,44867,N,N,N,N,N,N,N,N,N,N,N,N,44864,44889,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,44878,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,30249,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30258,44897,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44906,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44905,44912,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44917, +60963,60980,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30304,61001,N,N,N,N,N,N,N,N,N,N,N,N,N,62581,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,61020,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,61024,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,61023,61022,61234,61255,61261,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61284, +61474,61491,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,61497,30572,61523,61563,61742,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,61744,61749,61764,61789,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61793,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +61798,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61801, +61813,N,N,N,N,N,N,N,N,N,N,61815,61818,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61985, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61988,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61987,61992,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,61996, +62013,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30846,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62024,31017,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62043,31047,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,62069,N,N,N,N,N,N,N,N,N,N,62070,31060,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +62258,62270,62269,N,N,N,N,N,N,N,N,N,N,N,N,62272,62290,62301,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62302,31086,62323,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62324,N,N,N,N,N,N,N,N,N,N,N, +62327,N,N,62325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62333,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62331,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62498,62500,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,62503,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,62511,N,N,N,N,N,N,N,N,N,N,N,62510,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62517,62516,N,N,N,N,N,N,N,N,N,N,62525,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62530,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62543,62569,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,62571,62578,62585,62773,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62778,62790,62806,N,N, +N,N,N,N,N,N,N,N,N,N,62808,62810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,62813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,62815,62819,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,62826,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,62832,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,62835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,31325,42308,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,63044,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63054, +31539,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63069,63093,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63265,63266,63102,31561, +63283,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,63286,63333,63332,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,63339,63342,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63347, +63530,63529,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63532,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,31596,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63540,63548,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,63550,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63554,63574,63587,63607,N,N,N,N,N,N,N,N,N,N, +63609,N,N,N,N,N,N,N,N,63610,63781,63791,63794,63801,63810,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63816,31817,N,N,N,N,N,N,N,N,N,N,63833,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,63838,31825,63846,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,63851,63866,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +63870,64033,64044,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,64047,64080,N,N,64079,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64087,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64101,64102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64113,64114,64126,N,N,N,N,N,N,N,N,N,N,64289,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64301,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64300,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64310, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64311,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64318,N,N,N,N,N,N, +64317,64334,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,64335,64343,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64346, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64348,64349,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,64353,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64357,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64359,64361,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,64369,64546,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64547,64568,64578, +64588,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64598,64601,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64605,64630,64812,64843,64857,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64844, +N,N,N,N,N,N,N,N,N,N,N,64861,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +64859,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,64871,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,64880,N,N,N,N,N,N,N,N,N,N,N,N,N,64877,65061,65067,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,65065,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65077,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65074,32358,65112,65114,65134, +65136,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65138,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,65142, +}; + +static const struct unim_index jisx0213_emp_encmap[256] = { +{__jisx0213_emp_encmap+0,11,164},{__jisx0213_emp_encmap+154,162,162},{ +__jisx0213_emp_encmap+155,19,19},{__jisx0213_emp_encmap+156,43,249},{ +__jisx0213_emp_encmap+363,74,74},{__jisx0213_emp_encmap+364,9,214},{ +__jisx0213_emp_encmap+570,40,40},{__jisx0213_emp_encmap+571,79,79},{ +__jisx0213_emp_encmap+572,7,185},{__jisx0213_emp_encmap+751,124,157},{ +__jisx0213_emp_encmap+785,211,211},{__jisx0213_emp_encmap+786,29,159},{0,0,0}, +{__jisx0213_emp_encmap+917,69,225},{__jisx0213_emp_encmap+1074,100,149},{ +__jisx0213_emp_encmap+1124,95,95},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+1125, +1,253},{__jisx0213_emp_encmap+1378,27,196},{__jisx0213_emp_encmap+1548,109,110 +},{__jisx0213_emp_encmap+1550,215,215},{__jisx0213_emp_encmap+1551,71,180},{ +__jisx0213_emp_encmap+1661,6,66},{__jisx0213_emp_encmap+1722,189,189},{ +__jisx0213_emp_encmap+1723,195,195},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+ +1724,86,86},{__jisx0213_emp_encmap+1725,45,224},{__jisx0213_emp_encmap+1905, +51,52},{__jisx0213_emp_encmap+1907,30,250},{0,0,0},{__jisx0213_emp_encmap+2128 +,123,123},{__jisx0213_emp_encmap+2129,24,24},{__jisx0213_emp_encmap+2130,30, +173},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+2274,243,243},{0,0,0},{ +__jisx0213_emp_encmap+2275,91,171},{__jisx0213_emp_encmap+2356,143,143},{ +__jisx0213_emp_encmap+2357,184,184},{__jisx0213_emp_encmap+2358,70,166},{ +__jisx0213_emp_encmap+2455,29,36},{__jisx0213_emp_encmap+2463,225,225},{0,0,0 +},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+2464,182,245},{0,0,0},{ +__jisx0213_emp_encmap+2528,114,228},{__jisx0213_emp_encmap+2643,74,228},{ +__jisx0213_emp_encmap+2798,90,196},{__jisx0213_emp_encmap+2905,56,71},{ +__jisx0213_emp_encmap+2921,12,255},{__jisx0213_emp_encmap+3165,36,61},{0,0,0}, +{__jisx0213_emp_encmap+3191,152,152},{0,0,0},{__jisx0213_emp_encmap+3192,127, +254},{__jisx0213_emp_encmap+3320,0,250},{0,0,0},{__jisx0213_emp_encmap+3571, +126,126},{__jisx0213_emp_encmap+3572,150,150},{__jisx0213_emp_encmap+3573,3, +254},{0,0,0},{__jisx0213_emp_encmap+3825,188,188},{0,0,0},{0,0,0},{ +__jisx0213_emp_encmap+3826,41,165},{__jisx0213_emp_encmap+3951,241,241},{ +__jisx0213_emp_encmap+3952,150,150},{0,0,0},{__jisx0213_emp_encmap+3953,77,77 +},{__jisx0213_emp_encmap+3954,86,111},{__jisx0213_emp_encmap+3980,22,22},{ +__jisx0213_emp_encmap+3981,20,20},{__jisx0213_emp_encmap+3982,14,139},{0,0,0}, +{__jisx0213_emp_encmap+4108,74,85},{__jisx0213_emp_encmap+4120,34,229},{ +__jisx0213_emp_encmap+4316,30,76},{0,0,0},{__jisx0213_emp_encmap+4363,46,217}, +{__jisx0213_emp_encmap+4535,14,167},{0,0,0},{__jisx0213_emp_encmap+4689,113, +180},{0,0,0},{__jisx0213_emp_encmap+4757,196,212},{__jisx0213_emp_encmap+4774, +227,241},{__jisx0213_emp_encmap+4789,178,178},{__jisx0213_emp_encmap+4790,75, +100},{__jisx0213_emp_encmap+4816,161,161},{__jisx0213_emp_encmap+4817,46,232}, +{__jisx0213_emp_encmap+5004,35,251},{__jisx0213_emp_encmap+5221,12,237},{0,0,0 +},{__jisx0213_emp_encmap+5447,112,134},{__jisx0213_emp_encmap+5470,76,76},{ +__jisx0213_emp_encmap+5471,2,2},{0,0,0},{__jisx0213_emp_encmap+5472,126,176},{ +__jisx0213_emp_encmap+5523,29,29},{__jisx0213_emp_encmap+5524,221,234},{ +__jisx0213_emp_encmap+5538,81,221},{__jisx0213_emp_encmap+5679,30,255},{0,0,0 +},{__jisx0213_emp_encmap+5905,41,221},{0,0,0},{__jisx0213_emp_encmap+6086,64, +101},{__jisx0213_emp_encmap+6124,148,248},{__jisx0213_emp_encmap+6225,244,244 +},{__jisx0213_emp_encmap+6226,13,57},{0,0,0},{__jisx0213_emp_encmap+6271,218, +254},{__jisx0213_emp_encmap+6308,16,73},{0,0,0},{__jisx0213_emp_encmap+6366, +20,147},{__jisx0213_emp_encmap+6494,14,82},{0,0,0},{__jisx0213_emp_encmap+6563 +,133,133},{__jisx0213_emp_encmap+6564,132,132},{__jisx0213_emp_encmap+6565, +179,199},{__jisx0213_emp_encmap+6586,184,184},{__jisx0213_emp_encmap+6587,160, +160},{__jisx0213_emp_encmap+6588,16,16},{__jisx0213_emp_encmap+6589,183,183},{ +__jisx0213_emp_encmap+6590,138,187},{0,0,0},{__jisx0213_emp_encmap+6640,119, +243},{__jisx0213_emp_encmap+6765,205,205},{__jisx0213_emp_encmap+6766,12,85},{ +__jisx0213_emp_encmap+6840,107,201},{__jisx0213_emp_encmap+6935,215,250},{0,0, +0},{0,0,0},{__jisx0213_emp_encmap+6971,70,187},{__jisx0213_emp_encmap+7089,30, +228},{__jisx0213_emp_encmap+7288,193,239},{0,0,0},{__jisx0213_emp_encmap+7335, +16,251},{__jisx0213_emp_encmap+7571,31,235},{__jisx0213_emp_encmap+7776,50,248 +},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+7975,160,177},{0,0,0},{ +__jisx0213_emp_encmap+7993,144,144},{__jisx0213_emp_encmap+7994,207,207},{ +__jisx0213_emp_encmap+7995,127,240},{__jisx0213_emp_encmap+8109,25,80},{ +__jisx0213_emp_encmap+8165,198,198},{0,0,0},{__jisx0213_emp_encmap+8166,114, +114},{0,0,0},{0,0,0},{__jisx0213_emp_encmap+8167,219,219},{ +__jisx0213_emp_encmap+8168,21,233},{__jisx0213_emp_encmap+8381,206,206},{ +__jisx0213_emp_encmap+8382,26,249},{__jisx0213_emp_encmap+8606,144,144},{0,0,0 +},{__jisx0213_emp_encmap+8607,140,140},{__jisx0213_emp_encmap+8608,55,55},{ +__jisx0213_emp_encmap+8609,241,241},{__jisx0213_emp_encmap+8610,2,178},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0}, +}; + diff --git a/sys/src/cmd/python/Modules/cjkcodecs/mappings_kr.h b/sys/src/cmd/python/Modules/cjkcodecs/mappings_kr.h new file mode 100644 index 000000000..7e6fdd270 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/mappings_kr.h @@ -0,0 +1,3251 @@ +static const ucs2_t __ksx1001_decmap[8264] = { +12288,12289,12290,183,8229,8230,168,12291,173,8213,8741,65340,8764,8216,8217, +8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12304, +12305,177,215,247,8800,8804,8805,8734,8756,176,8242,8243,8451,8491,65504, +65505,65509,9794,9792,8736,8869,8978,8706,8711,8801,8786,167,8251,9734,9733, +9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8594,8592,8593,8595, +8596,12307,8810,8811,8730,8765,8733,8757,8747,8748,8712,8715,8838,8839,8834, +8835,8746,8745,8743,8744,65506,8658,8660,8704,8707,180,65374,711,728,733,730, +729,184,731,161,191,720,8750,8721,8719,164,8457,8240,9665,9664,9655,9654,9828, +9824,9825,9829,9831,9827,8857,9672,9635,9680,9681,9618,9636,9637,9640,9639, +9638,9641,9832,9743,9742,9756,9758,182,8224,8225,8597,8599,8601,8598,8600, +9837,9833,9834,9836,12927,12828,8470,13255,8482,13250,13272,8481,8364,174, +65281,65282,65283,65284,65285,65286,65287,65288,65289,65290,65291,65292,65293, +65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306, +65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319, +65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332, +65333,65334,65335,65336,65337,65338,65339,65510,65341,65342,65343,65344,65345, +65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358, +65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371, +65372,65373,65507,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602, +12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615, +12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628, +12629,12630,12631,12632,12633,12634,12635,12636,12637,12638,12639,12640,12641, +12642,12643,12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654, +12655,12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667, +12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,12680, +12681,12682,12683,12684,12685,12686,8560,8561,8562,8563,8564,8565,8566,8567, +8568,8569,U,U,U,U,U,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,U,U,U,U, +U,U,U,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931, +932,933,934,935,936,937,U,U,U,U,U,U,U,U,945,946,947,948,949,950,951,952,953, +954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,9472,9474,9484, +9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507, +9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,9490, +9489,9498,9497,9494,9493,9486,9485,9502,9503,9505,9506,9510,9511,9513,9514, +9517,9518,9521,9522,9525,9526,9529,9530,9533,9534,9536,9537,9539,9540,9541, +9542,9543,9544,9545,9546,13205,13206,13207,8467,13208,13252,13219,13220,13221, +13222,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13258,13197, +13198,13199,13263,13192,13193,13256,13223,13224,13232,13233,13234,13235,13236, +13237,13238,13239,13240,13241,13184,13185,13186,13187,13188,13242,13243,13244, +13245,13246,13247,13200,13201,13202,13203,13204,8486,13248,13249,13194,13195, +13196,13270,13253,13229,13230,13231,13275,13225,13226,13227,13228,13277,13264, +13267,13251,13257,13276,13254,198,208,170,294,U,306,U,319,321,216,338,186,222, +358,330,U,12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906, +12907,12908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919, +12920,12921,12922,12923,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433, +9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448, +9449,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325, +9326,189,8531,8532,188,190,8539,8540,8541,8542,230,273,240,295,305,307,312, +320,322,248,339,223,254,359,331,329,12800,12801,12802,12803,12804,12805,12806, +12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819, +12820,12821,12822,12823,12824,12825,12826,12827,9372,9373,9374,9375,9376,9377, +9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392, +9393,9394,9395,9396,9397,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341, +9342,9343,9344,9345,9346,185,178,179,8308,8319,8321,8322,8323,8324,12353, +12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366, +12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379, +12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392, +12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405, +12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418, +12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431, +12432,12433,12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457, +12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470, +12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483, +12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496, +12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509, +12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522, +12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,1040, +1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054, +1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069, +1070,1071,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,1072,1073,1074,1075,1076,1077,1105, +1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092, +1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,44032,44033,44036, +44039,44040,44041,44042,44048,44049,44050,44051,44052,44053,44054,44055,44057, +44058,44059,44060,44061,44064,44068,44076,44077,44079,44080,44081,44088,44089, +44092,44096,44107,44109,44116,44120,44124,44144,44145,44148,44151,44152,44154, +44160,44161,44163,44164,44165,44166,44169,44170,44171,44172,44176,44180,44188, +44189,44191,44192,44193,44200,44201,44202,44204,44207,44208,44216,44217,44219, +44220,44221,44225,44228,44232,44236,44245,44247,44256,44257,44260,44263,44264, +44266,44268,44271,44272,44273,44275,44277,44278,44284,44285,44288,44292,44294, +44300,44301,44303,44305,44312,44316,44320,44329,44332,44333,44340,44341,44344, +44348,44356,44357,44359,44361,44368,44372,44376,44385,44387,44396,44397,44400, +44403,44404,44405,44406,44411,44412,44413,44415,44417,44418,44424,44425,44428, +44432,44444,44445,44452,44471,44480,44481,44484,44488,44496,44497,44499,44508, +44512,44516,44536,44537,44540,44543,44544,44545,44552,44553,44555,44557,44564, +44592,44593,44596,44599,44600,44602,44608,44609,44611,44613,44614,44618,44620, +44621,44622,44624,44628,44630,44636,44637,44639,44640,44641,44645,44648,44649, +44652,44656,44664,44665,44667,44668,44669,44676,44677,44684,44732,44733,44734, +44736,44740,44748,44749,44751,44752,44753,44760,44761,44764,44776,44779,44781, +44788,44792,44796,44807,44808,44813,44816,44844,44845,44848,44850,44852,44860, +44861,44863,44865,44866,44867,44872,44873,44880,44892,44893,44900,44901,44921, +44928,44932,44936,44944,44945,44949,44956,44984,44985,44988,44992,44999,45000, +45001,45003,45005,45006,45012,45020,45032,45033,45040,45041,45044,45048,45056, +45057,45060,45068,45072,45076,45084,45085,45096,45124,45125,45128,45130,45132, +45134,45139,45140,45141,45143,45145,45149,45180,45181,45184,45188,45196,45197, +45199,45201,45208,45209,45210,45212,45215,45216,45217,45218,45224,45225,45227, +45228,45229,45230,45231,45233,45235,45236,45237,45240,45244,45252,45253,45255, +45256,45257,45264,45265,45268,45272,45280,45285,45320,45321,45323,45324,45328, +45330,45331,45336,45337,45339,45340,45341,45347,45348,45349,45352,45356,45364, +45365,45367,45368,45369,45376,45377,45380,45384,45392,45393,45396,45397,45400, +45404,45408,45432,45433,45436,45440,45442,45448,45449,45451,45453,45458,45459, +45460,45464,45468,45480,45516,45520,45524,45532,45533,45535,45544,45545,45548, +45552,45561,45563,45565,45572,45573,45576,45579,45580,45588,45589,45591,45593, +45600,45620,45628,45656,45660,45664,45672,45673,45684,45685,45692,45700,45701, +45705,45712,45713,45716,45720,45721,45722,45728,45729,45731,45733,45734,45738, +45740,45744,45748,45768,45769,45772,45776,45778,45784,45785,45787,45789,45794, +45796,45797,45798,45800,45803,45804,45805,45806,45807,45811,45812,45813,45815, +45816,45817,45818,45819,45823,45824,45825,45828,45832,45840,45841,45843,45844, +45845,45852,45908,45909,45910,45912,45915,45916,45918,45919,45924,45925,45927, +45929,45931,45934,45936,45937,45940,45944,45952,45953,45955,45956,45957,45964, +45968,45972,45984,45985,45992,45996,46020,46021,46024,46027,46028,46030,46032, +46036,46037,46039,46041,46043,46045,46048,46052,46056,46076,46096,46104,46108, +46112,46120,46121,46123,46132,46160,46161,46164,46168,46176,46177,46179,46181, +46188,46208,46216,46237,46244,46248,46252,46261,46263,46265,46272,46276,46280, +46288,46293,46300,46301,46304,46307,46308,46310,46316,46317,46319,46321,46328, +46356,46357,46360,46363,46364,46372,46373,46375,46376,46377,46378,46384,46385, +46388,46392,46400,46401,46403,46404,46405,46411,46412,46413,46416,46420,46428, +46429,46431,46432,46433,46496,46497,46500,46504,46506,46507,46512,46513,46515, +46516,46517,46523,46524,46525,46528,46532,46540,46541,46543,46544,46545,46552, +46572,46608,46609,46612,46616,46629,46636,46644,46664,46692,46696,46748,46749, +46752,46756,46763,46764,46769,46804,46832,46836,46840,46848,46849,46853,46888, +46889,46892,46895,46896,46904,46905,46907,46916,46920,46924,46932,46933,46944, +46948,46952,46960,46961,46963,46965,46972,46973,46976,46980,46988,46989,46991, +46992,46993,46994,46998,46999,47000,47001,47004,47008,47016,47017,47019,47020, +47021,47028,47029,47032,47047,47049,47084,47085,47088,47092,47100,47101,47103, +47104,47105,47111,47112,47113,47116,47120,47128,47129,47131,47133,47140,47141, +47144,47148,47156,47157,47159,47160,47161,47168,47172,47185,47187,47196,47197, +47200,47204,47212,47213,47215,47217,47224,47228,47245,47272,47280,47284,47288, +47296,47297,47299,47301,47308,47312,47316,47325,47327,47329,47336,47337,47340, +47344,47352,47353,47355,47357,47364,47384,47392,47420,47421,47424,47428,47436, +47439,47441,47448,47449,47452,47456,47464,47465,47467,47469,47476,47477,47480, +47484,47492,47493,47495,47497,47498,47501,47502,47532,47533,47536,47540,47548, +47549,47551,47553,47560,47561,47564,47566,47567,47568,47569,47570,47576,47577, +47579,47581,47582,47585,47587,47588,47589,47592,47596,47604,47605,47607,47608, +47609,47610,47616,47617,47624,47637,47672,47673,47676,47680,47682,47688,47689, +47691,47693,47694,47699,47700,47701,47704,47708,47716,47717,47719,47720,47721, +47728,47729,47732,47736,47747,47748,47749,47751,47756,47784,47785,47787,47788, +47792,47794,47800,47801,47803,47805,47812,47816,47832,47833,47868,47872,47876, +47885,47887,47889,47896,47900,47904,47913,47915,47924,47925,47926,47928,47931, +47932,47933,47934,47940,47941,47943,47945,47949,47951,47952,47956,47960,47969, +47971,47980,48008,48012,48016,48036,48040,48044,48052,48055,48064,48068,48072, +48080,48083,48120,48121,48124,48127,48128,48130,48136,48137,48139,48140,48141, +48143,48145,48148,48149,48150,48151,48152,48155,48156,48157,48158,48159,48164, +48165,48167,48169,48173,48176,48177,48180,48184,48192,48193,48195,48196,48197, +48201,48204,48205,48208,48221,48260,48261,48264,48267,48268,48270,48276,48277, +48279,48281,48282,48288,48289,48292,48295,48296,48304,48305,48307,48308,48309, +48316,48317,48320,48324,48333,48335,48336,48337,48341,48344,48348,48372,48373, +48374,48376,48380,48388,48389,48391,48393,48400,48404,48420,48428,48448,48456, +48457,48460,48464,48472,48473,48484,48488,48512,48513,48516,48519,48520,48521, +48522,48528,48529,48531,48533,48537,48538,48540,48548,48560,48568,48596,48597, +48600,48604,48617,48624,48628,48632,48640,48643,48645,48652,48653,48656,48660, +48668,48669,48671,48708,48709,48712,48716,48718,48724,48725,48727,48729,48730, +48731,48736,48737,48740,48744,48746,48752,48753,48755,48756,48757,48763,48764, +48765,48768,48772,48780,48781,48783,48784,48785,48792,48793,48808,48848,48849, +48852,48855,48856,48864,48867,48868,48869,48876,48897,48904,48905,48920,48921, +48923,48924,48925,48960,48961,48964,48968,48976,48977,48981,49044,49072,49093, +49100,49101,49104,49108,49116,49119,49121,49212,49233,49240,49244,49248,49256, +49257,49296,49297,49300,49304,49312,49313,49315,49317,49324,49325,49327,49328, +49331,49332,49333,49334,49340,49341,49343,49344,49345,49349,49352,49353,49356, +49360,49368,49369,49371,49372,49373,49380,49381,49384,49388,49396,49397,49399, +49401,49408,49412,49416,49424,49429,49436,49437,49438,49439,49440,49443,49444, +49446,49447,49452,49453,49455,49456,49457,49462,49464,49465,49468,49472,49480, +49481,49483,49484,49485,49492,49493,49496,49500,49508,49509,49511,49512,49513, +49520,49524,49528,49541,49548,49549,49550,49552,49556,49558,49564,49565,49567, +49569,49573,49576,49577,49580,49584,49597,49604,49608,49612,49620,49623,49624, +49632,49636,49640,49648,49649,49651,49660,49661,49664,49668,49676,49677,49679, +49681,49688,49689,49692,49695,49696,49704,49705,49707,49709,49711,49713,49714, +49716,49736,49744,49745,49748,49752,49760,49765,49772,49773,49776,49780,49788, +49789,49791,49793,49800,49801,49808,49816,49819,49821,49828,49829,49832,49836, +49837,49844,49845,49847,49849,49884,49885,49888,49891,49892,49899,49900,49901, +49903,49905,49910,49912,49913,49915,49916,49920,49928,49929,49932,49933,49939, +49940,49941,49944,49948,49956,49957,49960,49961,49989,50024,50025,50028,50032, +50034,50040,50041,50044,50045,50052,50056,50060,50112,50136,50137,50140,50143, +50144,50146,50152,50153,50157,50164,50165,50168,50184,50192,50212,50220,50224, +50228,50236,50237,50248,50276,50277,50280,50284,50292,50293,50297,50304,50324, +50332,50360,50364,50409,50416,50417,50420,50424,50426,50431,50432,50433,50444, +50448,50452,50460,50472,50473,50476,50480,50488,50489,50491,50493,50500,50501, +50504,50505,50506,50508,50509,50510,50515,50516,50517,50519,50520,50521,50525, +50526,50528,50529,50532,50536,50544,50545,50547,50548,50549,50556,50557,50560, +50564,50567,50572,50573,50575,50577,50581,50583,50584,50588,50592,50601,50612, +50613,50616,50617,50619,50620,50621,50622,50628,50629,50630,50631,50632,50633, +50634,50636,50638,50640,50641,50644,50648,50656,50657,50659,50661,50668,50669, +50670,50672,50676,50678,50679,50684,50685,50686,50687,50688,50689,50693,50694, +50695,50696,50700,50704,50712,50713,50715,50716,50724,50725,50728,50732,50733, +50734,50736,50739,50740,50741,50743,50745,50747,50752,50753,50756,50760,50768, +50769,50771,50772,50773,50780,50781,50784,50796,50799,50801,50808,50809,50812, +50816,50824,50825,50827,50829,50836,50837,50840,50844,50852,50853,50855,50857, +50864,50865,50868,50872,50873,50874,50880,50881,50883,50885,50892,50893,50896, +50900,50908,50909,50912,50913,50920,50921,50924,50928,50936,50937,50941,50948, +50949,50952,50956,50964,50965,50967,50969,50976,50977,50980,50984,50992,50993, +50995,50997,50999,51004,51005,51008,51012,51018,51020,51021,51023,51025,51026, +51027,51028,51029,51030,51031,51032,51036,51040,51048,51051,51060,51061,51064, +51068,51069,51070,51075,51076,51077,51079,51080,51081,51082,51086,51088,51089, +51092,51094,51095,51096,51098,51104,51105,51107,51108,51109,51110,51116,51117, +51120,51124,51132,51133,51135,51136,51137,51144,51145,51148,51150,51152,51160, +51165,51172,51176,51180,51200,51201,51204,51208,51210,51216,51217,51219,51221, +51222,51228,51229,51232,51236,51244,51245,51247,51249,51256,51260,51264,51272, +51273,51276,51277,51284,51312,51313,51316,51320,51322,51328,51329,51331,51333, +51334,51335,51339,51340,51341,51348,51357,51359,51361,51368,51388,51389,51396, +51400,51404,51412,51413,51415,51417,51424,51425,51428,51445,51452,51453,51456, +51460,51461,51462,51468,51469,51471,51473,51480,51500,51508,51536,51537,51540, +51544,51552,51553,51555,51564,51568,51572,51580,51592,51593,51596,51600,51608, +51609,51611,51613,51648,51649,51652,51655,51656,51658,51664,51665,51667,51669, +51670,51673,51674,51676,51677,51680,51682,51684,51687,51692,51693,51695,51696, +51697,51704,51705,51708,51712,51720,51721,51723,51724,51725,51732,51736,51753, +51788,51789,51792,51796,51804,51805,51807,51808,51809,51816,51837,51844,51864, +51900,51901,51904,51908,51916,51917,51919,51921,51923,51928,51929,51936,51948, +51956,51976,51984,51988,51992,52000,52001,52033,52040,52041,52044,52048,52056, +52057,52061,52068,52088,52089,52124,52152,52180,52196,52199,52201,52236,52237, +52240,52244,52252,52253,52257,52258,52263,52264,52265,52268,52270,52272,52280, +52281,52283,52284,52285,52286,52292,52293,52296,52300,52308,52309,52311,52312, +52313,52320,52324,52326,52328,52336,52341,52376,52377,52380,52384,52392,52393, +52395,52396,52397,52404,52405,52408,52412,52420,52421,52423,52425,52432,52436, +52452,52460,52464,52481,52488,52489,52492,52496,52504,52505,52507,52509,52516, +52520,52524,52537,52572,52576,52580,52588,52589,52591,52593,52600,52616,52628, +52629,52632,52636,52644,52645,52647,52649,52656,52676,52684,52688,52712,52716, +52720,52728,52729,52731,52733,52740,52744,52748,52756,52761,52768,52769,52772, +52776,52784,52785,52787,52789,52824,52825,52828,52831,52832,52833,52840,52841, +52843,52845,52852,52853,52856,52860,52868,52869,52871,52873,52880,52881,52884, +52888,52896,52897,52899,52900,52901,52908,52909,52929,52964,52965,52968,52971, +52972,52980,52981,52983,52984,52985,52992,52993,52996,53000,53008,53009,53011, +53013,53020,53024,53028,53036,53037,53039,53040,53041,53048,53076,53077,53080, +53084,53092,53093,53095,53097,53104,53105,53108,53112,53120,53125,53132,53153, +53160,53168,53188,53216,53217,53220,53224,53232,53233,53235,53237,53244,53248, +53252,53265,53272,53293,53300,53301,53304,53308,53316,53317,53319,53321,53328, +53332,53336,53344,53356,53357,53360,53364,53372,53373,53377,53412,53413,53416, +53420,53428,53429,53431,53433,53440,53441,53444,53448,53449,53456,53457,53459, +53460,53461,53468,53469,53472,53476,53484,53485,53487,53488,53489,53496,53517, +53552,53553,53556,53560,53562,53568,53569,53571,53572,53573,53580,53581,53584, +53588,53596,53597,53599,53601,53608,53612,53628,53636,53640,53664,53665,53668, +53672,53680,53681,53683,53685,53690,53692,53696,53720,53748,53752,53767,53769, +53776,53804,53805,53808,53812,53820,53821,53823,53825,53832,53852,53860,53888, +53889,53892,53896,53904,53905,53909,53916,53920,53924,53932,53937,53944,53945, +53948,53951,53952,53954,53960,53961,53963,53972,53976,53980,53988,53989,54000, +54001,54004,54008,54016,54017,54019,54021,54028,54029,54030,54032,54036,54038, +54044,54045,54047,54048,54049,54053,54056,54057,54060,54064,54072,54073,54075, +54076,54077,54084,54085,54140,54141,54144,54148,54156,54157,54159,54160,54161, +54168,54169,54172,54176,54184,54185,54187,54189,54196,54200,54204,54212,54213, +54216,54217,54224,54232,54241,54243,54252,54253,54256,54260,54268,54269,54271, +54273,54280,54301,54336,54340,54364,54368,54372,54381,54383,54392,54393,54396, +54399,54400,54402,54408,54409,54411,54413,54420,54441,54476,54480,54484,54492, +54495,54504,54508,54512,54520,54523,54525,54532,54536,54540,54548,54549,54551, +54588,54589,54592,54596,54604,54605,54607,54609,54616,54617,54620,54624,54629, +54632,54633,54635,54637,54644,54645,54648,54652,54660,54661,54663,54664,54665, +54672,54693,54728,54729,54732,54736,54738,54744,54745,54747,54749,54756,54757, +54760,54764,54772,54773,54775,54777,54784,54785,54788,54792,54800,54801,54803, +54804,54805,54812,54816,54820,54829,54840,54841,54844,54848,54853,54856,54857, +54859,54861,54865,54868,54869,54872,54876,54887,54889,54896,54897,54900,54915, +54917,54924,54925,54928,54932,54941,54943,54945,54952,54956,54960,54969,54971, +54980,54981,54984,54988,54993,54996,54999,55001,55008,55012,55016,55024,55029, +55036,55037,55040,55044,55057,55064,55065,55068,55072,55080,55081,55083,55085, +55092,55093,55096,55100,55108,55111,55113,55120,55121,55124,55126,55127,55128, +55129,55136,55137,55139,55141,55145,55148,55152,55156,55164,55165,55169,55176, +55177,55180,55184,55192,55193,55195,55197,20285,20339,20551,20729,21152,21487, +21621,21733,22025,23233,23478,26247,26550,26551,26607,27468,29634,30146,31292, +33499,33540,34903,34952,35382,36040,36303,36603,36838,39381,21051,21364,21508, +24682,24932,27580,29647,33050,35258,35282,38307,20355,21002,22718,22904,23014, +24178,24185,25031,25536,26438,26604,26751,28567,30286,30475,30965,31240,31487, +31777,32925,33390,33393,35563,38291,20075,21917,26359,28212,30883,31469,33883, +35088,34638,38824,21208,22350,22570,23884,24863,25022,25121,25954,26577,27204, +28187,29976,30131,30435,30640,32058,37039,37969,37970,40853,21283,23724,30002, +32987,37440,38296,21083,22536,23004,23713,23831,24247,24378,24394,24951,27743, +30074,30086,31968,32115,32177,32652,33108,33313,34193,35137,35611,37628,38477, +40007,20171,20215,20491,20977,22607,24887,24894,24936,25913,27114,28433,30117, +30342,30422,31623,33445,33995,63744,37799,38283,21888,23458,22353,63745,31923, +32697,37301,20520,21435,23621,24040,25298,25454,25818,25831,28192,28844,31067, +36317,36382,63746,36989,37445,37624,20094,20214,20581,24062,24314,24838,26967, +33137,34388,36423,37749,39467,20062,20625,26480,26688,20745,21133,21138,27298, +30652,37392,40660,21163,24623,36850,20552,25001,25581,25802,26684,27268,28608, +33160,35233,38548,22533,29309,29356,29956,32121,32365,32937,35211,35700,36963, +40273,25225,27770,28500,32080,32570,35363,20860,24906,31645,35609,37463,37772, +20140,20435,20510,20670,20742,21185,21197,21375,22384,22659,24218,24465,24950, +25004,25806,25964,26223,26299,26356,26775,28039,28805,28913,29855,29861,29898, +30169,30828,30956,31455,31478,32069,32147,32789,32831,33051,33686,35686,36629, +36885,37857,38915,38968,39514,39912,20418,21843,22586,22865,23395,23622,24760, +25106,26690,26800,26856,28330,30028,30328,30926,31293,31995,32363,32380,35336, +35489,35903,38542,40388,21476,21481,21578,21617,22266,22993,23396,23611,24235, +25335,25911,25925,25970,26272,26543,27073,27837,30204,30352,30590,31295,32660, +32771,32929,33167,33510,33533,33776,34241,34865,34996,35493,63747,36764,37678, +38599,39015,39640,40723,21741,26011,26354,26767,31296,35895,40288,22256,22372, +23825,26118,26801,26829,28414,29736,34974,39908,27752,63748,39592,20379,20844, +20849,21151,23380,24037,24656,24685,25329,25511,25915,29657,31354,34467,36002, +38799,20018,23521,25096,26524,29916,31185,33747,35463,35506,36328,36942,37707, +38982,24275,27112,34303,37101,63749,20896,23448,23532,24931,26874,27454,28748, +29743,29912,31649,32592,33733,35264,36011,38364,39208,21038,24669,25324,36866, +20362,20809,21281,22745,24291,26336,27960,28826,29378,29654,31568,33009,37979, +21350,25499,32619,20054,20608,22602,22750,24618,24871,25296,27088,39745,23439, +32024,32945,36703,20132,20689,21676,21932,23308,23968,24039,25898,25934,26657, +27211,29409,30350,30703,32094,32761,33184,34126,34527,36611,36686,37066,39171, +39509,39851,19992,20037,20061,20167,20465,20855,21246,21312,21475,21477,21646, +22036,22389,22434,23495,23943,24272,25084,25304,25937,26552,26601,27083,27472, +27590,27628,27714,28317,28792,29399,29590,29699,30655,30697,31350,32127,32777, +33276,33285,33290,33503,34914,35635,36092,36544,36881,37041,37476,37558,39378, +39493,40169,40407,40860,22283,23616,33738,38816,38827,40628,21531,31384,32676, +35033,36557,37089,22528,23624,25496,31391,23470,24339,31353,31406,33422,36524, +20518,21048,21240,21367,22280,25331,25458,27402,28099,30519,21413,29527,34152, +36470,38357,26426,27331,28528,35437,36556,39243,63750,26231,27512,36020,39740, +63751,21483,22317,22862,25542,27131,29674,30789,31418,31429,31998,33909,35215, +36211,36917,38312,21243,22343,30023,31584,33740,37406,63752,27224,20811,21067, +21127,25119,26840,26997,38553,20677,21156,21220,25027,26020,26681,27135,29822, +31563,33465,33771,35250,35641,36817,39241,63753,20170,22935,25810,26129,27278, +29748,31105,31165,33449,34942,34943,35167,63754,37670,20235,21450,24613,25201, +27762,32026,32102,20120,20834,30684,32943,20225,20238,20854,20864,21980,22120, +22331,22522,22524,22804,22855,22931,23492,23696,23822,24049,24190,24524,25216, +26071,26083,26398,26399,26462,26827,26820,27231,27450,27683,27773,27778,28103, +29592,29734,29738,29826,29859,30072,30079,30849,30959,31041,31047,31048,31098, +31637,32000,32186,32648,32774,32813,32908,35352,35663,35912,36215,37665,37668, +39138,39249,39438,39439,39525,40594,32202,20342,21513,25326,26708,37329,21931, +20794,63755,63756,23068,25062,63757,25295,25343,63758,63759,63760,63761,63762, +63763,37027,63764,63765,63766,63767,63768,35582,63769,63770,63771,63772,26262, +63773,29014,63774,63775,38627,63776,25423,25466,21335,63777,26511,26976,28275, +63778,30007,63779,63780,63781,32013,63782,63783,34930,22218,23064,63784,63785, +63786,63787,63788,20035,63789,20839,22856,26608,32784,63790,22899,24180,25754, +31178,24565,24684,25288,25467,23527,23511,21162,63791,22900,24361,24594,63792, +63793,63794,29785,63795,63796,63797,63798,63799,63800,39377,63801,63802,63803, +63804,63805,63806,63807,63808,63809,63810,63811,28611,63812,63813,33215,36786, +24817,63814,63815,33126,63816,63817,23615,63818,63819,63820,63821,63822,63823, +63824,63825,23273,35365,26491,32016,63826,63827,63828,63829,63830,63831,33021, +63832,63833,23612,27877,21311,28346,22810,33590,20025,20150,20294,21934,22296, +22727,24406,26039,26086,27264,27573,28237,30701,31471,31774,32222,34507,34962, +37170,37723,25787,28606,29562,30136,36948,21846,22349,25018,25812,26311,28129, +28251,28525,28601,30192,32835,33213,34113,35203,35527,35674,37663,27795,30035, +31572,36367,36957,21776,22530,22616,24162,25095,25758,26848,30070,31958,34739, +40680,20195,22408,22382,22823,23565,23729,24118,24453,25140,25825,29619,33274, +34955,36024,38538,40667,23429,24503,24755,20498,20992,21040,22294,22581,22615, +23566,23648,23798,23947,24230,24466,24764,25361,25481,25623,26691,26873,27330, +28120,28193,28372,28644,29182,30428,30585,31153,31291,33796,35241,36077,36339, +36424,36867,36884,36947,37117,37709,38518,38876,27602,28678,29272,29346,29544, +30563,31167,31716,32411,35712,22697,24775,25958,26109,26302,27788,28958,29129, +35930,38931,20077,31361,20189,20908,20941,21205,21516,24999,26481,26704,26847, +27934,28540,30140,30643,31461,33012,33891,37509,20828,26007,26460,26515,30168, +31431,33651,63834,35910,36887,38957,23663,33216,33434,36929,36975,37389,24471, +23965,27225,29128,30331,31561,34276,35588,37159,39472,21895,25078,63835,30313, +32645,34367,34746,35064,37007,63836,27931,28889,29662,32097,33853,63837,37226, +39409,63838,20098,21365,27396,27410,28734,29211,34349,40478,21068,36771,23888, +25829,25900,27414,28651,31811,32412,34253,35172,35261,25289,33240,34847,24266, +26391,28010,29436,29701,29807,34690,37086,20358,23821,24480,33802,20919,25504, +30053,20142,20486,20841,20937,26753,27153,31918,31921,31975,33391,35538,36635, +37327,20406,20791,21237,21570,24300,24942,25150,26053,27354,28670,31018,34268, +34851,38317,39522,39530,40599,40654,21147,26310,27511,28701,31019,36706,38722, +24976,25088,25891,28451,29001,29833,32244,32879,34030,36646,36899,37706,20925, +21015,21155,27916,28872,35010,24265,25986,27566,28610,31806,29557,20196,20278, +22265,63839,23738,23994,24604,29618,31533,32666,32718,32838,36894,37428,38646, +38728,38936,40801,20363,28583,31150,37300,38583,21214,63840,25736,25796,27347, +28510,28696,29200,30439,32769,34310,34396,36335,36613,38706,39791,40442,40565, +30860,31103,32160,33737,37636,40575,40595,35542,22751,24324,26407,28711,29903, +31840,32894,20769,28712,29282,30922,36034,36058,36084,38647,20102,20698,23534, +24278,26009,29134,30274,30637,32842,34044,36988,39719,40845,22744,23105,23650, +27155,28122,28431,30267,32047,32311,34078,35128,37860,38475,21129,26066,26611, +27060,27969,28316,28687,29705,29792,30041,30244,30827,35628,39006,20845,25134, +38520,20374,20523,23833,28138,32184,36650,24459,24900,26647,63841,38534,21202, +32907,20956,20940,26974,31260,32190,33777,38517,20442,21033,21400,21519,21774, +23653,24743,26446,26792,28012,29313,29432,29702,29827,63842,30178,31852,32633, +32696,33673,35023,35041,37324,37328,38626,39881,21533,28542,29136,29848,34298, +36522,38563,40023,40607,26519,28107,29747,33256,38678,30764,31435,31520,31890, +25705,29802,30194,30908,30952,39340,39764,40635,23518,24149,28448,33180,33707, +37000,19975,21325,23081,24018,24398,24930,25405,26217,26364,28415,28459,28771, +30622,33836,34067,34875,36627,39237,39995,21788,25273,26411,27819,33545,35178, +38778,20129,22916,24536,24537,26395,32178,32596,33426,33579,33725,36638,37017, +22475,22969,23186,23504,26151,26522,26757,27599,29028,32629,36023,36067,36993, +39749,33032,35978,38476,39488,40613,23391,27667,29467,30450,30431,33804,20906, +35219,20813,20885,21193,26825,27796,30468,30496,32191,32236,38754,40629,28357, +34065,20901,21517,21629,26126,26269,26919,28319,30399,30609,33559,33986,34719, +37225,37528,40180,34946,20398,20882,21215,22982,24125,24917,25720,25721,26286, +26576,27169,27597,27611,29279,29281,29761,30520,30683,32791,33468,33541,35584, +35624,35980,26408,27792,29287,30446,30566,31302,40361,27519,27794,22818,26406, +33945,21359,22675,22937,24287,25551,26164,26483,28218,29483,31447,33495,37672, +21209,24043,25006,25035,25098,25287,25771,26080,26969,27494,27595,28961,29687, +30045,32326,33310,33538,34154,35491,36031,38695,40289,22696,40664,20497,21006, +21563,21839,25991,27766,32010,32011,32862,34442,38272,38639,21247,27797,29289, +21619,23194,23614,23883,24396,24494,26410,26806,26979,28220,28228,30473,31859, +32654,34183,35598,36855,38753,40692,23735,24758,24845,25003,25935,26107,26108, +27665,27887,29599,29641,32225,38292,23494,34588,35600,21085,21338,25293,25615, +25778,26420,27192,27850,29632,29854,31636,31893,32283,33162,33334,34180,36843, +38649,39361,20276,21322,21453,21467,25292,25644,25856,26001,27075,27886,28504, +29677,30036,30242,30436,30460,30928,30971,31020,32070,33324,34784,36820,38930, +39151,21187,25300,25765,28196,28497,30332,36299,37297,37474,39662,39747,20515, +20621,22346,22952,23592,24135,24439,25151,25918,26041,26049,26121,26507,27036, +28354,30917,32033,32938,33152,33323,33459,33953,34444,35370,35607,37030,38450, +40848,20493,20467,63843,22521,24472,25308,25490,26479,28227,28953,30403,32972, +32986,35060,35061,35097,36064,36649,37197,38506,20271,20336,24091,26575,26658, +30333,30334,39748,24161,27146,29033,29140,30058,63844,32321,34115,34281,39132, +20240,31567,32624,38309,20961,24070,26805,27710,27726,27867,29359,31684,33539, +27861,29754,20731,21128,22721,25816,27287,29863,30294,30887,34327,38370,38713, +63845,21342,24321,35722,36776,36783,37002,21029,30629,40009,40712,19993,20482, +20853,23643,24183,26142,26170,26564,26821,28851,29953,30149,31177,31453,36647, +39200,39432,20445,22561,22577,23542,26222,27493,27921,28282,28541,29668,29995, +33769,35036,35091,35676,36628,20239,20693,21264,21340,23443,24489,26381,31119, +33145,33583,34068,35079,35206,36665,36667,39333,39954,26412,20086,20472,22857, +23553,23791,23792,25447,26834,28925,29090,29739,32299,34028,34562,36898,37586, +40179,19981,20184,20463,20613,21078,21103,21542,21648,22496,22827,23142,23386, +23413,23500,24220,63846,25206,25975,26023,28014,28325,29238,31526,31807,32566, +33104,33105,33178,33344,33433,33705,35331,36000,36070,36091,36212,36282,37096, +37340,38428,38468,39385,40167,21271,20998,21545,22132,22707,22868,22894,24575, +24996,25198,26128,27774,28954,30406,31881,31966,32027,33452,36033,38640,63847, +20315,24343,24447,25282,23849,26379,26842,30844,32323,40300,19989,20633,21269, +21290,21329,22915,23138,24199,24754,24970,25161,25209,26000,26503,27047,27604, +27606,27607,27608,27832,63848,29749,30202,30738,30865,31189,31192,31875,32203, +32737,32933,33086,33218,33778,34586,35048,35513,35692,36027,37145,38750,39131, +40763,22188,23338,24428,25996,27315,27567,27996,28657,28693,29277,29613,36007, +36051,38971,24977,27703,32856,39425,20045,20107,20123,20181,20282,20284,20351, +20447,20735,21490,21496,21766,21987,22235,22763,22882,23057,23531,23546,23556, +24051,24107,24473,24605,25448,26012,26031,26614,26619,26797,27515,27801,27863, +28195,28681,29509,30722,31038,31040,31072,31169,31721,32023,32114,32902,33293, +33678,34001,34503,35039,35408,35422,35613,36060,36198,36781,37034,39164,39391, +40605,21066,63849,26388,63850,20632,21034,23665,25955,27733,29642,29987,30109, +31639,33948,37240,38704,20087,25746,27578,29022,34217,19977,63851,26441,26862, +28183,33439,34072,34923,25591,28545,37394,39087,19978,20663,20687,20767,21830, +21930,22039,23360,23577,23776,24120,24202,24224,24258,24819,26705,27233,28248, +29245,29248,29376,30456,31077,31665,32724,35059,35316,35443,35937,36062,38684, +22622,29885,36093,21959,63852,31329,32034,33394,29298,29983,29989,63853,31513, +22661,22779,23996,24207,24246,24464,24661,25234,25471,25933,26257,26329,26360, +26646,26866,29312,29790,31598,32110,32214,32626,32997,33298,34223,35199,35475, +36893,37604,40653,40736,22805,22893,24109,24796,26132,26227,26512,27728,28101, +28511,30707,30889,33990,37323,37675,20185,20682,20808,21892,23307,23459,25159, +25982,26059,28210,29053,29697,29764,29831,29887,30316,31146,32218,32341,32680, +33146,33203,33337,34330,34796,35445,36323,36984,37521,37925,39245,39854,21352, +23633,26964,27844,27945,28203,33292,34203,35131,35373,35498,38634,40807,21089, +26297,27570,32406,34814,36109,38275,38493,25885,28041,29166,63854,22478,22995, +23468,24615,24826,25104,26143,26207,29481,29689,30427,30465,31596,32854,32882, +33125,35488,37266,19990,21218,27506,27927,31237,31545,32048,63855,36016,21484, +22063,22609,23477,23567,23569,24034,25152,25475,25620,26157,26803,27836,28040, +28335,28703,28836,29138,29990,30095,30094,30233,31505,31712,31787,32032,32057, +34092,34157,34311,35380,36877,36961,37045,37559,38902,39479,20439,23660,26463, +28049,31903,32396,35606,36118,36895,23403,24061,25613,33984,36956,39137,29575, +23435,24730,26494,28126,35359,35494,36865,38924,21047,63856,28753,30862,37782, +34928,37335,20462,21463,22013,22234,22402,22781,23234,23432,23723,23744,24101, +24833,25101,25163,25480,25628,25910,25976,27193,27530,27700,27929,28465,29159, +29417,29560,29703,29874,30246,30561,31168,31319,31466,31929,32143,32172,32353, +32670,33065,33585,33936,34010,34282,34966,35504,35728,36664,36930,36995,37228, +37526,37561,38539,38567,38568,38614,38656,38920,39318,39635,39706,21460,22654, +22809,23408,23487,28113,28506,29087,29729,29881,32901,33789,24033,24455,24490, +24642,26092,26642,26991,27219,27529,27957,28147,29667,30462,30636,31565,32020, +33059,33308,33600,34036,34147,35426,35524,37255,37662,38918,39348,25100,34899, +36848,37477,23815,23847,23913,29791,33181,34664,28629,25342,32722,35126,35186, +19998,20056,20711,21213,21319,25215,26119,32361,34821,38494,20365,21273,22070, +22987,23204,23608,23630,23629,24066,24337,24643,26045,26159,26178,26558,26612, +29468,30690,31034,32709,33940,33997,35222,35430,35433,35553,35925,35962,22516, +23508,24335,24687,25325,26893,27542,28252,29060,31698,34645,35672,36606,39135, +39166,20280,20353,20449,21627,23072,23480,24892,26032,26216,29180,30003,31070, +32051,33102,33251,33688,34218,34254,34563,35338,36523,36763,63857,36805,22833, +23460,23526,24713,23529,23563,24515,27777,63858,28145,28683,29978,33455,35574, +20160,21313,63859,38617,27663,20126,20420,20818,21854,23077,23784,25105,29273, +33469,33706,34558,34905,35357,38463,38597,39187,40201,40285,22538,23731,23997, +24132,24801,24853,25569,27138,28197,37122,37716,38990,39952,40823,23433,23736, +25353,26191,26696,30524,38593,38797,38996,39839,26017,35585,36555,38332,21813, +23721,24022,24245,26263,30284,33780,38343,22739,25276,29390,40232,20208,22830, +24591,26171,27523,31207,40230,21395,21696,22467,23830,24859,26326,28079,30861, +33406,38552,38724,21380,25212,25494,28082,32266,33099,38989,27387,32588,40367, +40474,20063,20539,20918,22812,24825,25590,26928,29242,32822,63860,37326,24369, +63861,63862,32004,33509,33903,33979,34277,36493,63863,20335,63864,63865,22756, +23363,24665,25562,25880,25965,26264,63866,26954,27171,27915,28673,29036,30162, +30221,31155,31344,63867,32650,63868,35140,63869,35731,37312,38525,63870,39178, +22276,24481,26044,28417,30208,31142,35486,39341,39770,40812,20740,25014,25233, +27277,33222,20547,22576,24422,28937,35328,35578,23420,34326,20474,20796,22196, +22852,25513,28153,23978,26989,20870,20104,20313,63871,63872,63873,22914,63874, +63875,27487,27741,63876,29877,30998,63877,33287,33349,33593,36671,36701,63878, +39192,63879,63880,63881,20134,63882,22495,24441,26131,63883,63884,30123,32377, +35695,63885,36870,39515,22181,22567,23032,23071,23476,63886,24310,63887,63888, +25424,25403,63889,26941,27783,27839,28046,28051,28149,28436,63890,28895,28982, +29017,63891,29123,29141,63892,30799,30831,63893,31605,32227,63894,32303,63895, +34893,36575,63896,63897,63898,37467,63899,40182,63900,63901,63902,24709,28037, +63903,29105,63904,63905,38321,21421,63906,63907,63908,26579,63909,28814,28976, +29744,33398,33490,63910,38331,39653,40573,26308,63911,29121,33865,63912,63913, +22603,63914,63915,23992,24433,63916,26144,26254,27001,27054,27704,27891,28214, +28481,28634,28699,28719,29008,29151,29552,63917,29787,63918,29908,30408,31310, +32403,63919,63920,33521,35424,36814,63921,37704,63922,38681,63923,63924,20034, +20522,63925,21000,21473,26355,27757,28618,29450,30591,31330,33454,34269,34306, +63926,35028,35427,35709,35947,63927,37555,63928,38675,38928,20116,20237,20425, +20658,21320,21566,21555,21978,22626,22714,22887,23067,23524,24735,63929,25034, +25942,26111,26212,26791,27738,28595,28879,29100,29522,31613,34568,35492,39986, +40711,23627,27779,29508,29577,37434,28331,29797,30239,31337,32277,34314,20800, +22725,25793,29934,29973,30320,32705,37013,38605,39252,28198,29926,31401,31402, +33253,34521,34680,35355,23113,23436,23451,26785,26880,28003,29609,29715,29740, +30871,32233,32747,33048,33109,33694,35916,38446,38929,26352,24448,26106,26505, +27754,29579,20525,23043,27498,30702,22806,23916,24013,29477,30031,63930,63931, +20709,20985,22575,22829,22934,23002,23525,63932,63933,23970,25303,25622,25747, +25854,63934,26332,63935,27208,63936,29183,29796,63937,31368,31407,32327,32350, +32768,33136,63938,34799,35201,35616,36953,63939,36992,39250,24958,27442,28020, +32287,35109,36785,20433,20653,20887,21191,22471,22665,23481,24248,24898,27029, +28044,28263,28342,29076,29794,29992,29996,32883,33592,33993,36362,37780,37854, +63940,20110,20305,20598,20778,21448,21451,21491,23431,23507,23588,24858,24962, +26100,29275,29591,29760,30402,31056,31121,31161,32006,32701,33419,34261,34398, +36802,36935,37109,37354,38533,38632,38633,21206,24423,26093,26161,26671,29020, +31286,37057,38922,20113,63941,27218,27550,28560,29065,32792,33464,34131,36939, +38549,38642,38907,34074,39729,20112,29066,38596,20803,21407,21729,22291,22290, +22435,23195,23236,23491,24616,24895,25588,27781,27961,28274,28304,29232,29503, +29783,33489,34945,36677,36960,63942,38498,39000,40219,26376,36234,37470,20301, +20553,20702,21361,22285,22996,23041,23561,24944,26256,28205,29234,29771,32239, +32963,33806,33894,34111,34655,34907,35096,35586,36949,38859,39759,20083,20369, +20754,20842,63943,21807,21929,23418,23461,24188,24189,24254,24736,24799,24840, +24841,25540,25912,26377,63944,26580,26586,63945,26977,26978,27833,27943,63946, +28216,63947,28641,29494,29495,63948,29788,30001,63949,30290,63950,63951,32173, +33278,33848,35029,35480,35547,35565,36400,36418,36938,36926,36986,37193,37321, +37742,63952,63953,22537,63954,27603,32905,32946,63955,63956,20801,22891,23609, +63957,63958,28516,29607,32996,36103,63959,37399,38287,63960,63961,63962,63963, +32895,25102,28700,32104,34701,63964,22432,24681,24903,27575,35518,37504,38577, +20057,21535,28139,34093,38512,38899,39150,25558,27875,37009,20957,25033,33210, +40441,20381,20506,20736,23452,24847,25087,25836,26885,27589,30097,30691,32681, +33380,34191,34811,34915,35516,35696,37291,20108,20197,20234,63965,63966,22839, +23016,63967,24050,24347,24411,24609,63968,63969,63970,63971,29246,29669,63972, +30064,30157,63973,31227,63974,32780,32819,32900,33505,33617,63975,63976,36029, +36019,36999,63977,63978,39156,39180,63979,63980,28727,30410,32714,32716,32764, +35610,20154,20161,20995,21360,63981,21693,22240,23035,23493,24341,24525,28270, +63982,63983,32106,33589,63984,34451,35469,63985,38765,38775,63986,63987,19968, +20314,20350,22777,26085,28322,36920,37808,39353,20219,22764,22922,23001,24641, +63988,63989,31252,63990,33615,36035,20837,21316,63991,63992,63993,20173,21097, +23381,33471,20180,21050,21672,22985,23039,23376,23383,23388,24675,24904,28363, +28825,29038,29574,29943,30133,30913,32043,32773,33258,33576,34071,34249,35566, +36039,38604,20316,21242,22204,26027,26152,28796,28856,29237,32189,33421,37196, +38592,40306,23409,26855,27544,28538,30430,23697,26283,28507,31668,31786,34870, +38620,19976,20183,21280,22580,22715,22767,22892,23559,24115,24196,24373,25484, +26290,26454,27167,27299,27404,28479,29254,63994,29520,29835,31456,31911,33144, +33247,33255,33674,33900,34083,34196,34255,35037,36115,37292,38263,38556,20877, +21705,22312,23472,25165,26448,26685,26771,28221,28371,28797,32289,35009,36001, +36617,40779,40782,29229,31631,35533,37658,20295,20302,20786,21632,22992,24213, +25269,26485,26990,27159,27822,28186,29401,29482,30141,31672,32053,33511,33785, +33879,34295,35419,36015,36487,36889,37048,38606,40799,21219,21514,23265,23490, +25688,25973,28404,29380,63995,30340,31309,31515,31821,32318,32735,33659,35627, +36042,36196,36321,36447,36842,36857,36969,37841,20291,20346,20659,20840,20856, +21069,21098,22625,22652,22880,23560,23637,24283,24731,25136,26643,27583,27656, +28593,29006,29728,30000,30008,30033,30322,31564,31627,31661,31686,32399,35438, +36670,36681,37439,37523,37666,37931,38651,39002,39019,39198,20999,25130,25240, +27993,30308,31434,31680,32118,21344,23742,24215,28472,28857,31896,38673,39822, +40670,25509,25722,34678,19969,20117,20141,20572,20597,21576,22979,23450,24128, +24237,24311,24449,24773,25402,25919,25972,26060,26230,26232,26622,26984,27273, +27491,27712,28096,28136,28191,28254,28702,28833,29582,29693,30010,30555,30855, +31118,31243,31357,31934,32142,33351,35330,35562,35998,37165,37194,37336,37478, +37580,37664,38662,38742,38748,38914,40718,21046,21137,21884,22564,24093,24351, +24716,25552,26799,28639,31085,31532,33229,34234,35069,35576,36420,37261,38500, +38555,38717,38988,40778,20430,20806,20939,21161,22066,24340,24427,25514,25805, +26089,26177,26362,26361,26397,26781,26839,27133,28437,28526,29031,29157,29226, +29866,30522,31062,31066,31199,31264,31381,31895,31967,32068,32368,32903,34299, +34468,35412,35519,36249,36481,36896,36973,37347,38459,38613,40165,26063,31751, +36275,37827,23384,23562,21330,25305,29469,20519,23447,24478,24752,24939,26837, +28121,29742,31278,32066,32156,32305,33131,36394,36405,37758,37912,20304,22352, +24038,24231,25387,32618,20027,20303,20367,20570,23005,32964,21610,21608,22014, +22863,23449,24030,24282,26205,26417,26609,26666,27880,27954,28234,28557,28855, +29664,30087,31820,32002,32044,32162,33311,34523,35387,35461,36208,36490,36659, +36913,37198,37202,37956,39376,31481,31909,20426,20737,20934,22472,23535,23803, +26201,27197,27994,28310,28652,28940,30063,31459,34850,36897,36981,38603,39423, +33537,20013,20210,34886,37325,21373,27355,26987,27713,33914,22686,24974,26366, +25327,28893,29969,30151,32338,33976,35657,36104,20043,21482,21675,22320,22336, +24535,25345,25351,25711,25903,26088,26234,26525,26547,27490,27744,27802,28460, +30693,30757,31049,31063,32025,32930,33026,33267,33437,33463,34584,35468,63996, +36100,36286,36978,30452,31257,31287,32340,32887,21767,21972,22645,25391,25634, +26185,26187,26733,27035,27524,27941,28337,29645,29800,29857,30043,30137,30433, +30494,30603,31206,32265,32285,33275,34095,34967,35386,36049,36587,36784,36914, +37805,38499,38515,38663,20356,21489,23018,23241,24089,26702,29894,30142,31209, +31378,33187,34541,36074,36300,36845,26015,26389,63997,22519,28503,32221,36655, +37878,38598,24501,25074,28548,19988,20376,20511,21449,21983,23919,24046,27425, +27492,30923,31642,63998,36425,36554,36974,25417,25662,30528,31364,37679,38015, +40810,25776,28591,29158,29864,29914,31428,31762,32386,31922,32408,35738,36106, +38013,39184,39244,21049,23519,25830,26413,32046,20717,21443,22649,24920,24921, +25082,26028,31449,35730,35734,20489,20513,21109,21809,23100,24288,24432,24884, +25950,26124,26166,26274,27085,28356,28466,29462,30241,31379,33081,33369,33750, +33980,20661,22512,23488,23528,24425,25505,30758,32181,33756,34081,37319,37365, +20874,26613,31574,36012,20932,22971,24765,34389,20508,63999,21076,23610,24957, +25114,25299,25842,26021,28364,30240,33034,36448,38495,38587,20191,21315,21912, +22825,24029,25797,27849,28154,29588,31359,33307,34214,36068,36368,36983,37351, +38369,38433,38854,20984,21746,21894,24505,25764,28552,32180,36639,36685,37941, +20681,23574,27838,28155,29979,30651,31805,31844,35449,35522,22558,22974,24086, +25463,29266,30090,30571,35548,36028,36626,24307,26228,28152,32893,33729,35531, +38737,39894,64000,21059,26367,28053,28399,32224,35558,36910,36958,39636,21021, +21119,21736,24980,25220,25307,26786,26898,26970,27189,28818,28966,30813,30977, +30990,31186,31245,32918,33400,33493,33609,34121,35970,36229,37218,37259,37294, +20419,22225,29165,30679,34560,35320,23544,24534,26449,37032,21474,22618,23541, +24740,24961,25696,32317,32880,34085,37507,25774,20652,23828,26368,22684,25277, +25512,26894,27000,27166,28267,30394,31179,33467,33833,35535,36264,36861,37138, +37195,37276,37648,37656,37786,38619,39478,39949,19985,30044,31069,31482,31569, +31689,32302,33988,36441,36468,36600,36880,26149,26943,29763,20986,26414,40668, +20805,24544,27798,34802,34909,34935,24756,33205,33795,36101,21462,21561,22068, +23094,23601,28810,32736,32858,33030,33261,36259,37257,39519,40434,20596,20164, +21408,24827,28204,23652,20360,20516,21988,23769,24159,24677,26772,27835,28100, +29118,30164,30196,30305,31258,31305,32199,32251,32622,33268,34473,36636,38601, +39347,40786,21063,21189,39149,35242,19971,26578,28422,20405,23522,26517,27784, +28024,29723,30759,37341,37756,34756,31204,31281,24555,20182,21668,21822,22702, +22949,24816,25171,25302,26422,26965,33333,38464,39345,39389,20524,21331,21828, +22396,64001,25176,64002,25826,26219,26589,28609,28655,29730,29752,35351,37944, +21585,22022,22374,24392,24986,27470,28760,28845,32187,35477,22890,33067,25506, +30472,32829,36010,22612,25645,27067,23445,24081,28271,64003,34153,20812,21488, +22826,24608,24907,27526,27760,27888,31518,32974,33492,36294,37040,39089,64004, +25799,28580,25745,25860,20814,21520,22303,35342,24927,26742,64005,30171,31570, +32113,36890,22534,27084,33151,35114,36864,38969,20600,22871,22956,25237,36879, +39722,24925,29305,38358,22369,23110,24052,25226,25773,25850,26487,27874,27966, +29228,29750,30772,32631,33453,36315,38935,21028,22338,26495,29256,29923,36009, +36774,37393,38442,20843,21485,25420,20329,21764,24726,25943,27803,28031,29260, +29437,31255,35207,35997,24429,28558,28921,33192,24846,20415,20559,25153,29255, +31687,32232,32745,36941,38829,39449,36022,22378,24179,26544,33805,35413,21536, +23318,24163,24290,24330,25987,32954,34109,38281,38491,20296,21253,21261,21263, +21638,21754,22275,24067,24598,25243,25265,25429,64006,27873,28006,30129,30770, +32990,33071,33502,33889,33970,34957,35090,36875,37610,39165,39825,24133,26292, +26333,28689,29190,64007,20469,21117,24426,24915,26451,27161,28418,29922,31080, +34920,35961,39111,39108,39491,21697,31263,26963,35575,35914,39080,39342,24444, +25259,30130,30382,34987,36991,38466,21305,24380,24517,27852,29644,30050,30091, +31558,33534,39325,20047,36924,19979,20309,21414,22799,24264,26160,27827,29781, +33655,34662,36032,36944,38686,39957,22737,23416,34384,35604,40372,23506,24680, +24717,26097,27735,28450,28579,28698,32597,32752,38289,38290,38480,38867,21106, +36676,20989,21547,21688,21859,21898,27323,28085,32216,33382,37532,38519,40569, +21512,21704,30418,34532,38308,38356,38492,20130,20233,23022,23270,24055,24658, +25239,26477,26689,27782,28207,32568,32923,33322,64008,64009,38917,20133,20565, +21683,22419,22874,23401,23475,25032,26999,28023,28707,34809,35299,35442,35559, +36994,39405,39608,21182,26680,20502,24184,26447,33607,34892,20139,21521,22190, +29670,37141,38911,39177,39255,39321,22099,22687,34395,35377,25010,27382,29563, +36562,27463,38570,39511,22869,29184,36203,38761,20436,23796,24358,25080,26203, +27883,28843,29572,29625,29694,30505,30541,32067,32098,32291,33335,34898,64010, +36066,37449,39023,23377,31348,34880,38913,23244,20448,21332,22846,23805,25406, +28025,29433,33029,33031,33698,37583,38960,20136,20804,21009,22411,24418,27842, +28366,28677,28752,28847,29074,29673,29801,33610,34722,34913,36872,37026,37795, +39336,20846,24407,24800,24935,26291,34137,36426,37295,38795,20046,20114,21628, +22741,22778,22909,23733,24359,25142,25160,26122,26215,27627,28009,28111,28246, +28408,28564,28640,28649,28765,29392,29733,29786,29920,30355,31068,31946,32286, +32993,33446,33899,33983,34382,34399,34676,35703,35946,37804,38912,39013,24785, +25110,37239,23130,26127,28151,28222,29759,39746,24573,24794,31503,21700,24344, +27742,27859,27946,28888,32005,34425,35340,40251,21270,21644,23301,27194,28779, +30069,31117,31166,33457,33775,35441,35649,36008,38772,64011,25844,25899,30906, +30907,31339,20024,21914,22864,23462,24187,24739,25563,27489,26213,26707,28185, +29029,29872,32008,36996,39529,39973,27963,28369,29502,35905,38346,20976,24140, +24488,24653,24822,24880,24908,26179,26180,27045,27841,28255,28361,28514,29004, +29852,30343,31681,31783,33618,34647,36945,38541,40643,21295,22238,24315,24458, +24674,24724,25079,26214,26371,27292,28142,28590,28784,29546,32362,33214,33588, +34516,35496,36036,21123,29554,23446,27243,37892,21742,22150,23389,25928,25989, +26313,26783,28045,28102,29243,32948,37237,39501,20399,20505,21402,21518,21564, +21897,21957,24127,24460,26429,29030,29661,36869,21211,21235,22628,22734,28932, +29071,29179,34224,35347,26248,34216,21927,26244,29002,33841,21321,21913,27585, +24409,24509,25582,26249,28999,35569,36637,40638,20241,25658,28875,30054,34407, +24676,35662,40440,20807,20982,21256,27958,33016,40657,26133,27427,28824,30165, +21507,23673,32007,35350,27424,27453,27462,21560,24688,27965,32725,33288,20694, +20958,21916,22123,22221,23020,23305,24076,24985,24984,25137,26206,26342,29081, +29113,29114,29351,31143,31232,32690,35440, +}; + +static const struct dbcs_index ksx1001_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__ksx1001_decmap+0,33,126},{__ksx1001_decmap+ +94,33,103},{__ksx1001_decmap+165,33,126},{__ksx1001_decmap+259,33,126},{ +__ksx1001_decmap+353,33,120},{__ksx1001_decmap+441,33,100},{__ksx1001_decmap+ +509,33,111},{__ksx1001_decmap+588,33,126},{__ksx1001_decmap+682,33,126},{ +__ksx1001_decmap+776,33,115},{__ksx1001_decmap+859,33,118},{__ksx1001_decmap+ +945,33,113},{0,0,0},{0,0,0},{0,0,0},{__ksx1001_decmap+1026,33,126},{ +__ksx1001_decmap+1120,33,126},{__ksx1001_decmap+1214,33,126},{__ksx1001_decmap ++1308,33,126},{__ksx1001_decmap+1402,33,126},{__ksx1001_decmap+1496,33,126},{ +__ksx1001_decmap+1590,33,126},{__ksx1001_decmap+1684,33,126},{__ksx1001_decmap ++1778,33,126},{__ksx1001_decmap+1872,33,126},{__ksx1001_decmap+1966,33,126},{ +__ksx1001_decmap+2060,33,126},{__ksx1001_decmap+2154,33,126},{__ksx1001_decmap ++2248,33,126},{__ksx1001_decmap+2342,33,126},{__ksx1001_decmap+2436,33,126},{ +__ksx1001_decmap+2530,33,126},{__ksx1001_decmap+2624,33,126},{__ksx1001_decmap ++2718,33,126},{__ksx1001_decmap+2812,33,126},{__ksx1001_decmap+2906,33,126},{ +__ksx1001_decmap+3000,33,126},{__ksx1001_decmap+3094,33,126},{__ksx1001_decmap ++3188,33,126},{__ksx1001_decmap+3282,33,126},{0,0,0},{__ksx1001_decmap+3376, +33,126},{__ksx1001_decmap+3470,33,126},{__ksx1001_decmap+3564,33,126},{ +__ksx1001_decmap+3658,33,126},{__ksx1001_decmap+3752,33,126},{__ksx1001_decmap ++3846,33,126},{__ksx1001_decmap+3940,33,126},{__ksx1001_decmap+4034,33,126},{ +__ksx1001_decmap+4128,33,126},{__ksx1001_decmap+4222,33,126},{__ksx1001_decmap ++4316,33,126},{__ksx1001_decmap+4410,33,126},{__ksx1001_decmap+4504,33,126},{ +__ksx1001_decmap+4598,33,126},{__ksx1001_decmap+4692,33,126},{__ksx1001_decmap ++4786,33,126},{__ksx1001_decmap+4880,33,126},{__ksx1001_decmap+4974,33,126},{ +__ksx1001_decmap+5068,33,126},{__ksx1001_decmap+5162,33,126},{__ksx1001_decmap ++5256,33,126},{__ksx1001_decmap+5350,33,126},{__ksx1001_decmap+5444,33,126},{ +__ksx1001_decmap+5538,33,126},{__ksx1001_decmap+5632,33,126},{__ksx1001_decmap ++5726,33,126},{__ksx1001_decmap+5820,33,126},{__ksx1001_decmap+5914,33,126},{ +__ksx1001_decmap+6008,33,126},{__ksx1001_decmap+6102,33,126},{__ksx1001_decmap ++6196,33,126},{__ksx1001_decmap+6290,33,126},{__ksx1001_decmap+6384,33,126},{ +__ksx1001_decmap+6478,33,126},{__ksx1001_decmap+6572,33,126},{__ksx1001_decmap ++6666,33,126},{__ksx1001_decmap+6760,33,126},{__ksx1001_decmap+6854,33,126},{ +__ksx1001_decmap+6948,33,126},{__ksx1001_decmap+7042,33,126},{__ksx1001_decmap ++7136,33,126},{__ksx1001_decmap+7230,33,126},{__ksx1001_decmap+7324,33,126},{ +__ksx1001_decmap+7418,33,126},{__ksx1001_decmap+7512,33,126},{__ksx1001_decmap ++7606,33,126},{__ksx1001_decmap+7700,33,126},{__ksx1001_decmap+7794,33,126},{ +__ksx1001_decmap+7888,33,126},{__ksx1001_decmap+7982,33,126},{__ksx1001_decmap ++8076,33,126},{__ksx1001_decmap+8170,33,126},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +}, +}; + +static const ucs2_t __cp949ext_decmap[9650] = { +44034,44035,44037,44038,44043,44044,44045,44046,44047,44056,44062,44063,44065, +44066,44067,44069,44070,44071,44072,44073,44074,44075,44078,44082,44083,44084, +U,U,U,U,U,U,44085,44086,44087,44090,44091,44093,44094,44095,44097,44098,44099, +44100,44101,44102,44103,44104,44105,44106,44108,44110,44111,44112,44113,44114, +44115,44117,U,U,U,U,U,U,44118,44119,44121,44122,44123,44125,44126,44127,44128, +44129,44130,44131,44132,44133,44134,44135,44136,44137,44138,44139,44140,44141, +44142,44143,44146,44147,44149,44150,44153,44155,44156,44157,44158,44159,44162, +44167,44168,44173,44174,44175,44177,44178,44179,44181,44182,44183,44184,44185, +44186,44187,44190,44194,44195,44196,44197,44198,44199,44203,44205,44206,44209, +44210,44211,44212,44213,44214,44215,44218,44222,44223,44224,44226,44227,44229, +44230,44231,44233,44234,44235,44237,44238,44239,44240,44241,44242,44243,44244, +44246,44248,44249,44250,44251,44252,44253,44254,44255,44258,44259,44261,44262, +44265,44267,44269,44270,44274,44276,44279,44280,44281,44282,44283,44286,44287, +44289,44290,44291,44293,44295,44296,44297,44298,44299,44302,44304,44306,44307, +44308,44309,44310,44311,44313,44314,44315,44317,44318,44319,44321,44322,44323, +44324,44325,44326,44327,44328,44330,44331,44334,44335,44336,44337,44338,44339, +U,U,U,U,U,U,44342,44343,44345,44346,44347,44349,44350,44351,44352,44353,44354, +44355,44358,44360,44362,44363,44364,44365,44366,44367,44369,44370,44371,44373, +44374,44375,U,U,U,U,U,U,44377,44378,44379,44380,44381,44382,44383,44384,44386, +44388,44389,44390,44391,44392,44393,44394,44395,44398,44399,44401,44402,44407, +44408,44409,44410,44414,44416,44419,44420,44421,44422,44423,44426,44427,44429, +44430,44431,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442,44443, +44446,44447,44448,44449,44450,44451,44453,44454,44455,44456,44457,44458,44459, +44460,44461,44462,44463,44464,44465,44466,44467,44468,44469,44470,44472,44473, +44474,44475,44476,44477,44478,44479,44482,44483,44485,44486,44487,44489,44490, +44491,44492,44493,44494,44495,44498,44500,44501,44502,44503,44504,44505,44506, +44507,44509,44510,44511,44513,44514,44515,44517,44518,44519,44520,44521,44522, +44523,44524,44525,44526,44527,44528,44529,44530,44531,44532,44533,44534,44535, +44538,44539,44541,44542,44546,44547,44548,44549,44550,44551,44554,44556,44558, +44559,44560,44561,44562,44563,44565,44566,44567,44568,44569,44570,44571,44572, +U,U,U,U,U,U,44573,44574,44575,44576,44577,44578,44579,44580,44581,44582,44583, +44584,44585,44586,44587,44588,44589,44590,44591,44594,44595,44597,44598,44601, +44603,44604,U,U,U,U,U,U,44605,44606,44607,44610,44612,44615,44616,44617,44619, +44623,44625,44626,44627,44629,44631,44632,44633,44634,44635,44638,44642,44643, +44644,44646,44647,44650,44651,44653,44654,44655,44657,44658,44659,44660,44661, +44662,44663,44666,44670,44671,44672,44673,44674,44675,44678,44679,44680,44681, +44682,44683,44685,44686,44687,44688,44689,44690,44691,44692,44693,44694,44695, +44696,44697,44698,44699,44700,44701,44702,44703,44704,44705,44706,44707,44708, +44709,44710,44711,44712,44713,44714,44715,44716,44717,44718,44719,44720,44721, +44722,44723,44724,44725,44726,44727,44728,44729,44730,44731,44735,44737,44738, +44739,44741,44742,44743,44744,44745,44746,44747,44750,44754,44755,44756,44757, +44758,44759,44762,44763,44765,44766,44767,44768,44769,44770,44771,44772,44773, +44774,44775,44777,44778,44780,44782,44783,44784,44785,44786,44787,44789,44790, +44791,44793,44794,44795,44797,44798,44799,44800,44801,44802,44803,44804,44805, +U,U,U,U,U,U,44806,44809,44810,44811,44812,44814,44815,44817,44818,44819,44820, +44821,44822,44823,44824,44825,44826,44827,44828,44829,44830,44831,44832,44833, +44834,44835,U,U,U,U,U,U,44836,44837,44838,44839,44840,44841,44842,44843,44846, +44847,44849,44851,44853,44854,44855,44856,44857,44858,44859,44862,44864,44868, +44869,44870,44871,44874,44875,44876,44877,44878,44879,44881,44882,44883,44884, +44885,44886,44887,44888,44889,44890,44891,44894,44895,44896,44897,44898,44899, +44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,44912,44913,44914, +44915,44916,44917,44918,44919,44920,44922,44923,44924,44925,44926,44927,44929, +44930,44931,44933,44934,44935,44937,44938,44939,44940,44941,44942,44943,44946, +44947,44948,44950,44951,44952,44953,44954,44955,44957,44958,44959,44960,44961, +44962,44963,44964,44965,44966,44967,44968,44969,44970,44971,44972,44973,44974, +44975,44976,44977,44978,44979,44980,44981,44982,44983,44986,44987,44989,44990, +44991,44993,44994,44995,44996,44997,44998,45002,45004,45007,45008,45009,45010, +45011,45013,45014,45015,45016,45017,45018,45019,45021,45022,45023,45024,45025, +U,U,U,U,U,U,45026,45027,45028,45029,45030,45031,45034,45035,45036,45037,45038, +45039,45042,45043,45045,45046,45047,45049,45050,45051,45052,45053,45054,45055, +45058,45059,U,U,U,U,U,U,45061,45062,45063,45064,45065,45066,45067,45069,45070, +45071,45073,45074,45075,45077,45078,45079,45080,45081,45082,45083,45086,45087, +45088,45089,45090,45091,45092,45093,45094,45095,45097,45098,45099,45100,45101, +45102,45103,45104,45105,45106,45107,45108,45109,45110,45111,45112,45113,45114, +45115,45116,45117,45118,45119,45120,45121,45122,45123,45126,45127,45129,45131, +45133,45135,45136,45137,45138,45142,45144,45146,45147,45148,45150,45151,45152, +45153,45154,45155,45156,45157,45158,45159,45160,45161,45162,45163,45164,45165, +45166,45167,45168,45169,45170,45171,45172,45173,45174,45175,45176,45177,45178, +45179,45182,45183,45185,45186,45187,45189,45190,45191,45192,45193,45194,45195, +45198,45200,45202,45203,45204,45205,45206,45207,45211,45213,45214,45219,45220, +45221,45222,45223,45226,45232,45234,45238,45239,45241,45242,45243,45245,45246, +45247,45248,45249,45250,45251,45254,45258,45259,45260,45261,45262,45263,45266, +U,U,U,U,U,U,45267,45269,45270,45271,45273,45274,45275,45276,45277,45278,45279, +45281,45282,45283,45284,45286,45287,45288,45289,45290,45291,45292,45293,45294, +45295,45296,U,U,U,U,U,U,45297,45298,45299,45300,45301,45302,45303,45304,45305, +45306,45307,45308,45309,45310,45311,45312,45313,45314,45315,45316,45317,45318, +45319,45322,45325,45326,45327,45329,45332,45333,45334,45335,45338,45342,45343, +45344,45345,45346,45350,45351,45353,45354,45355,45357,45358,45359,45360,45361, +45362,45363,45366,45370,45371,45372,45373,45374,45375,45378,45379,45381,45382, +45383,45385,45386,45387,45388,45389,45390,45391,45394,45395,45398,45399,45401, +45402,45403,45405,45406,45407,45409,45410,45411,45412,45413,45414,45415,45416, +45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429, +45430,45431,45434,45435,45437,45438,45439,45441,45443,45444,45445,45446,45447, +45450,45452,45454,45455,45456,45457,45461,45462,45463,45465,45466,45467,45469, +45470,45471,45472,45473,45474,45475,45476,45477,45478,45479,45481,45482,45483, +45484,45485,45486,45487,45488,45489,45490,45491,45492,45493,45494,45495,45496, +U,U,U,U,U,U,45497,45498,45499,45500,45501,45502,45503,45504,45505,45506,45507, +45508,45509,45510,45511,45512,45513,45514,45515,45517,45518,45519,45521,45522, +45523,45525,U,U,U,U,U,U,45526,45527,45528,45529,45530,45531,45534,45536,45537, +45538,45539,45540,45541,45542,45543,45546,45547,45549,45550,45551,45553,45554, +45555,45556,45557,45558,45559,45560,45562,45564,45566,45567,45568,45569,45570, +45571,45574,45575,45577,45578,45581,45582,45583,45584,45585,45586,45587,45590, +45592,45594,45595,45596,45597,45598,45599,45601,45602,45603,45604,45605,45606, +45607,45608,45609,45610,45611,45612,45613,45614,45615,45616,45617,45618,45619, +45621,45622,45623,45624,45625,45626,45627,45629,45630,45631,45632,45633,45634, +45635,45636,45637,45638,45639,45640,45641,45642,45643,45644,45645,45646,45647, +45648,45649,45650,45651,45652,45653,45654,45655,45657,45658,45659,45661,45662, +45663,45665,45666,45667,45668,45669,45670,45671,45674,45675,45676,45677,45678, +45679,45680,45681,45682,45683,45686,45687,45688,45689,45690,45691,45693,45694, +45695,45696,45697,45698,45699,45702,45703,45704,45706,45707,45708,45709,45710, +U,U,U,U,U,U,45711,45714,45715,45717,45718,45719,45723,45724,45725,45726,45727, +45730,45732,45735,45736,45737,45739,45741,45742,45743,45745,45746,45747,45749, +45750,45751,U,U,U,U,U,U,45752,45753,45754,45755,45756,45757,45758,45759,45760, +45761,45762,45763,45764,45765,45766,45767,45770,45771,45773,45774,45775,45777, +45779,45780,45781,45782,45783,45786,45788,45790,45791,45792,45793,45795,45799, +45801,45802,45808,45809,45810,45814,45820,45821,45822,45826,45827,45829,45830, +45831,45833,45834,45835,45836,45837,45838,45839,45842,45846,45847,45848,45849, +45850,45851,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863, +45864,45865,45866,45867,45868,45869,45870,45871,45872,45873,45874,45875,45876, +45877,45878,45879,45880,45881,45882,45883,45884,45885,45886,45887,45888,45889, +45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902, +45903,45904,45905,45906,45907,45911,45913,45914,45917,45920,45921,45922,45923, +45926,45928,45930,45932,45933,45935,45938,45939,45941,45942,45943,45945,45946, +45947,45948,45949,45950,45951,45954,45958,45959,45960,45961,45962,45963,45965, +U,U,U,U,U,U,45966,45967,45969,45970,45971,45973,45974,45975,45976,45977,45978, +45979,45980,45981,45982,45983,45986,45987,45988,45989,45990,45991,45993,45994, +45995,45997,U,U,U,U,U,U,45998,45999,46000,46001,46002,46003,46004,46005,46006, +46007,46008,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019, +46022,46023,46025,46026,46029,46031,46033,46034,46035,46038,46040,46042,46044, +46046,46047,46049,46050,46051,46053,46054,46055,46057,46058,46059,46060,46061, +46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074, +46075,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088, +46089,46090,46091,46092,46093,46094,46095,46097,46098,46099,46100,46101,46102, +46103,46105,46106,46107,46109,46110,46111,46113,46114,46115,46116,46117,46118, +46119,46122,46124,46125,46126,46127,46128,46129,46130,46131,46133,46134,46135, +46136,46137,46138,46139,46140,46141,46142,46143,46144,46145,46146,46147,46148, +46149,46150,46151,46152,46153,46154,46155,46156,46157,46158,46159,46162,46163, +46165,46166,46167,46169,46170,46171,46172,46173,46174,46175,46178,46180,46182, +U,U,U,U,U,U,46183,46184,46185,46186,46187,46189,46190,46191,46192,46193,46194, +46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207, +46209,46210,U,U,U,U,U,U,46211,46212,46213,46214,46215,46217,46218,46219,46220, +46221,46222,46223,46224,46225,46226,46227,46228,46229,46230,46231,46232,46233, +46234,46235,46236,46238,46239,46240,46241,46242,46243,46245,46246,46247,46249, +46250,46251,46253,46254,46255,46256,46257,46258,46259,46260,46262,46264,46266, +46267,46268,46269,46270,46271,46273,46274,46275,46277,46278,46279,46281,46282, +46283,46284,46285,46286,46287,46289,46290,46291,46292,46294,46295,46296,46297, +46298,46299,46302,46303,46305,46306,46309,46311,46312,46313,46314,46315,46318, +46320,46322,46323,46324,46325,46326,46327,46329,46330,46331,46332,46333,46334, +46335,46336,46337,46338,46339,46340,46341,46342,46343,46344,46345,46346,46347, +46348,46349,46350,46351,46352,46353,46354,46355,46358,46359,46361,46362,46365, +46366,46367,46368,46369,46370,46371,46374,46379,46380,46381,46382,46383,46386, +46387,46389,46390,46391,46393,46394,46395,46396,46397,46398,46399,46402,46406, +U,U,U,U,U,U,46407,46408,46409,46410,46414,46415,46417,46418,46419,46421,46422, +46423,46424,46425,46426,46427,46430,46434,46435,46436,46437,46438,46439,46440, +46441,46442,U,U,U,U,U,U,46443,46444,46445,46446,46447,46448,46449,46450,46451, +46452,46453,46454,46455,46456,46457,46458,46459,46460,46461,46462,46463,46464, +46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,46475,46476,46477, +46478,46479,46480,46481,46482,46483,46484,46485,46486,46487,46488,46489,46490, +46491,46492,46493,46494,46495,46498,46499,46501,46502,46503,46505,46508,46509, +46510,46511,46514,46518,46519,46520,46521,46522,46526,46527,46529,46530,46531, +46533,46534,46535,46536,46537,46538,46539,46542,46546,46547,46548,46549,46550, +46551,46553,46554,46555,46556,46557,46558,46559,46560,46561,46562,46563,46564, +46565,46566,46567,46568,46569,46570,46571,46573,46574,46575,46576,46577,46578, +46579,46580,46581,46582,46583,46584,46585,46586,46587,46588,46589,46590,46591, +46592,46593,46594,46595,46596,46597,46598,46599,46600,46601,46602,46603,46604, +46605,46606,46607,46610,46611,46613,46614,46615,46617,46618,46619,46620,46621, +U,U,U,U,U,U,46622,46623,46624,46625,46626,46627,46628,46630,46631,46632,46633, +46634,46635,46637,46638,46639,46640,46641,46642,46643,46645,46646,46647,46648, +46649,46650,U,U,U,U,U,U,46651,46652,46653,46654,46655,46656,46657,46658,46659, +46660,46661,46662,46663,46665,46666,46667,46668,46669,46670,46671,46672,46673, +46674,46675,46676,46677,46678,46679,46680,46681,46682,46683,46684,46685,46686, +46687,46688,46689,46690,46691,46693,46694,46695,46697,46698,46699,46700,46701, +46702,46703,46704,46705,46706,46707,46708,46709,46710,46711,46712,46713,46714, +46715,46716,46717,46718,46719,46720,46721,46722,46723,46724,46725,46726,46727, +46728,46729,46730,46731,46732,46733,46734,46735,46736,46737,46738,46739,46740, +46741,46742,46743,46744,46745,46746,46747,46750,46751,46753,46754,46755,46757, +46758,46759,46760,46761,46762,46765,46766,46767,46768,46770,46771,46772,46773, +46774,46775,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786, +46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799, +46800,46801,46802,46803,46805,46806,46807,46808,46809,46810,46811,46812,46813, +U,U,U,U,U,U,46814,46815,46816,46817,46818,46819,46820,46821,46822,46823,46824, +46825,46826,46827,46828,46829,46830,46831,46833,46834,46835,46837,46838,46839, +46841,46842,U,U,U,U,U,U,46843,46844,46845,46846,46847,46850,46851,46852,46854, +46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867, +46868,46869,46870,46871,46872,46873,46874,46875,46876,46877,46878,46879,46880, +46881,46882,46883,46884,46885,46886,46887,46890,46891,46893,46894,46897,46898, +46899,46900,46901,46902,46903,46906,46908,46909,46910,46911,46912,46913,46914, +46915,46917,46918,46919,46921,46922,46923,46925,46926,46927,46928,46929,46930, +46931,46934,46935,46936,46937,46938,46939,46940,46941,46942,46943,46945,46946, +46947,46949,46950,46951,46953,46954,46955,46956,46957,46958,46959,46962,46964, +46966,46967,46968,46969,46970,46971,46974,46975,46977,46978,46979,46981,46982, +46983,46984,46985,46986,46987,46990,46995,46996,46997,47002,47003,47005,47006, +47007,47009,47010,47011,47012,47013,47014,47015,47018,47022,47023,47024,47025, +47026,47027,47030,47031,47033,47034,47035,47036,47037,47038,47039,47040,47041, +U,U,U,U,U,U,47042,47043,47044,47045,47046,47048,47050,47051,47052,47053,47054, +47055,47056,47057,47058,47059,47060,47061,47062,47063,47064,47065,47066,47067, +47068,47069,U,U,U,U,U,U,47070,47071,47072,47073,47074,47075,47076,47077,47078, +47079,47080,47081,47082,47083,47086,47087,47089,47090,47091,47093,47094,47095, +47096,47097,47098,47099,47102,47106,47107,47108,47109,47110,47114,47115,47117, +47118,47119,47121,47122,47123,47124,47125,47126,47127,47130,47132,47134,47135, +47136,47137,47138,47139,47142,47143,47145,47146,47147,47149,47150,47151,47152, +47153,47154,47155,47158,47162,47163,47164,47165,47166,47167,47169,47170,47171, +47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47186, +47188,47189,47190,47191,47192,47193,47194,47195,47198,47199,47201,47202,47203, +47205,47206,47207,47208,47209,47210,47211,47214,47216,47218,47219,47220,47221, +47222,47223,47225,47226,47227,47229,47230,47231,47232,47233,47234,47235,47236, +47237,47238,47239,47240,47241,47242,47243,47244,47246,47247,47248,47249,47250, +47251,47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263, +U,U,U,U,U,U,47264,47265,47266,47267,47268,47269,47270,47271,47273,47274,47275, +47276,47277,47278,47279,47281,47282,47283,47285,47286,47287,47289,47290,47291, +47292,47293,U,U,U,U,U,U,47294,47295,47298,47300,47302,47303,47304,47305,47306, +47307,47309,47310,47311,47313,47314,47315,47317,47318,47319,47320,47321,47322, +47323,47324,47326,47328,47330,47331,47332,47333,47334,47335,47338,47339,47341, +47342,47343,47345,47346,47347,47348,47349,47350,47351,47354,47356,47358,47359, +47360,47361,47362,47363,47365,47366,47367,47368,47369,47370,47371,47372,47373, +47374,47375,47376,47377,47378,47379,47380,47381,47382,47383,47385,47386,47387, +47388,47389,47390,47391,47393,47394,47395,47396,47397,47398,47399,47400,47401, +47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,47412,47413,47414, +47415,47416,47417,47418,47419,47422,47423,47425,47426,47427,47429,47430,47431, +47432,47433,47434,47435,47437,47438,47440,47442,47443,47444,47445,47446,47447, +47450,47451,47453,47454,47455,47457,47458,47459,47460,47461,47462,47463,47466, +47468,47470,47471,47472,47473,47474,47475,47478,47479,47481,47482,47483,47485, +U,U,U,U,U,U,47486,47487,47488,47489,47490,47491,47494,47496,47499,47500,47503, +47504,47505,47506,47507,47508,47509,47510,47511,47512,47513,47514,47515,47516, +47517,47518,U,U,U,U,U,U,47519,47520,47521,47522,47523,47524,47525,47526,47527, +47528,47529,47530,47531,47534,47535,47537,47538,47539,47541,47542,47543,47544, +47545,47546,47547,47550,47552,47554,47555,47556,47557,47558,47559,47562,47563, +47565,47571,47572,47573,47574,47575,47578,47580,47583,47584,47586,47590,47591, +47593,47594,47595,47597,47598,47599,47600,47601,47602,47603,47606,47611,47612, +47613,47614,47615,47618,47619,47620,47621,47622,47623,47625,47626,47627,47628, +47629,47630,47631,47632,47633,47634,47635,47636,47638,47639,47640,47641,47642, +47643,47644,47645,47646,47647,47648,47649,47650,47651,47652,47653,47654,47655, +47656,47657,47658,47659,47660,47661,47662,47663,47664,47665,47666,47667,47668, +47669,47670,47671,47674,47675,47677,47678,47679,47681,47683,47684,47685,47686, +47687,47690,47692,47695,47696,47697,47698,47702,47703,47705,47706,47707,47709, +47710,47711,47712,47713,47714,47715,47718,47722,47723,47724,47725,47726,47727, +U,U,U,U,U,U,47730,47731,47733,47734,47735,47737,47738,47739,47740,47741,47742, +47743,47744,47745,47746,47750,47752,47753,47754,47755,47757,47758,47759,47760, +47761,47762,U,U,U,U,U,U,47763,47764,47765,47766,47767,47768,47769,47770,47771, +47772,47773,47774,47775,47776,47777,47778,47779,47780,47781,47782,47783,47786, +47789,47790,47791,47793,47795,47796,47797,47798,47799,47802,47804,47806,47807, +47808,47809,47810,47811,47813,47814,47815,47817,47818,47819,47820,47821,47822, +47823,47824,47825,47826,47827,47828,47829,47830,47831,47834,47835,47836,47837, +47838,47839,47840,47841,47842,47843,47844,47845,47846,47847,47848,47849,47850, +47851,47852,47853,47854,47855,47856,47857,47858,47859,47860,47861,47862,47863, +47864,47865,47866,47867,47869,47870,47871,47873,47874,47875,47877,47878,47879, +47880,47881,47882,47883,47884,47886,47888,47890,47891,47892,47893,47894,47895, +47897,47898,47899,47901,47902,47903,47905,47906,47907,47908,47909,47910,47911, +47912,47914,47916,47917,47918,47919,47920,47921,47922,47923,47927,47929,47930, +47935,47936,47937,47938,47939,47942,47944,47946,47947,47948,47950,47953,47954, +U,U,U,U,U,U,47955,47957,47958,47959,47961,47962,47963,47964,47965,47966,47967, +47968,47970,47972,47973,47974,47975,47976,47977,47978,47979,47981,47982,47983, +47984,47985,U,U,U,U,U,U,47986,47987,47988,47989,47990,47991,47992,47993,47994, +47995,47996,47997,47998,47999,48000,48001,48002,48003,48004,48005,48006,48007, +48009,48010,48011,48013,48014,48015,48017,48018,48019,48020,48021,48022,48023, +48024,48025,48026,48027,48028,48029,48030,48031,48032,48033,48034,48035,48037, +48038,48039,48041,48042,48043,48045,48046,48047,48048,48049,48050,48051,48053, +48054,48056,48057,48058,48059,48060,48061,48062,48063,48065,48066,48067,48069, +48070,48071,48073,48074,48075,48076,48077,48078,48079,48081,48082,48084,48085, +48086,48087,48088,48089,48090,48091,48092,48093,48094,48095,48096,48097,48098, +48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111, +48112,48113,48114,48115,48116,48117,48118,48119,48122,48123,48125,48126,48129, +48131,48132,48133,48134,48135,48138,48142,48144,48146,48147,48153,48154,48160, +48161,48162,48163,48166,48168,48170,48171,48172,48174,48175,48178,48179,48181, +U,U,U,U,U,U,48182,48183,48185,48186,48187,48188,48189,48190,48191,48194,48198, +48199,48200,48202,48203,48206,48207,48209,48210,48211,48212,48213,48214,48215, +48216,48217,U,U,U,U,U,U,48218,48219,48220,48222,48223,48224,48225,48226,48227, +48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240, +48241,48242,48243,48244,48245,48246,48247,48248,48249,48250,48251,48252,48253, +48254,48255,48256,48257,48258,48259,48262,48263,48265,48266,48269,48271,48272, +48273,48274,48275,48278,48280,48283,48284,48285,48286,48287,48290,48291,48293, +48294,48297,48298,48299,48300,48301,48302,48303,48306,48310,48311,48312,48313, +48314,48315,48318,48319,48321,48322,48323,48325,48326,48327,48328,48329,48330, +48331,48332,48334,48338,48339,48340,48342,48343,48345,48346,48347,48349,48350, +48351,48352,48353,48354,48355,48356,48357,48358,48359,48360,48361,48362,48363, +48364,48365,48366,48367,48368,48369,48370,48371,48375,48377,48378,48379,48381, +48382,48383,48384,48385,48386,48387,48390,48392,48394,48395,48396,48397,48398, +48399,48401,48402,48403,48405,48406,48407,48408,48409,48410,48411,48412,48413, +U,U,U,U,U,U,48414,48415,48416,48417,48418,48419,48421,48422,48423,48424,48425, +48426,48427,48429,48430,48431,48432,48433,48434,48435,48436,48437,48438,48439, +48440,48441,U,U,U,U,U,U,48442,48443,48444,48445,48446,48447,48449,48450,48451, +48452,48453,48454,48455,48458,48459,48461,48462,48463,48465,48466,48467,48468, +48469,48470,48471,48474,48475,48476,48477,48478,48479,48480,48481,48482,48483, +48485,48486,48487,48489,48490,48491,48492,48493,48494,48495,48496,48497,48498, +48499,48500,48501,48502,48503,48504,48505,48506,48507,48508,48509,48510,48511, +48514,48515,48517,48518,48523,48524,48525,48526,48527,48530,48532,48534,48535, +48536,48539,48541,48542,48543,48544,48545,48546,48547,48549,48550,48551,48552, +48553,48554,48555,48556,48557,48558,48559,48561,48562,48563,48564,48565,48566, +48567,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580, +48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,48591,48592,48593, +48594,48595,48598,48599,48601,48602,48603,48605,48606,48607,48608,48609,48610, +48611,48612,48613,48614,48615,48616,48618,48619,48620,48621,48622,48623,48625, +U,U,U,U,U,U,48626,48627,48629,48630,48631,48633,48634,48635,48636,48637,48638, +48639,48641,48642,48644,48646,48647,48648,48649,48650,48651,48654,48655,48657, +48658,48659,U,U,U,U,U,U,48661,48662,48663,48664,48665,48666,48667,48670,48672, +48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,48684,48685, +48686,48687,48688,48689,48690,48691,48692,48693,48694,48695,48696,48697,48698, +48699,48700,48701,48702,48703,48704,48705,48706,48707,48710,48711,48713,48714, +48715,48717,48719,48720,48721,48722,48723,48726,48728,48732,48733,48734,48735, +48738,48739,48741,48742,48743,48745,48747,48748,48749,48750,48751,48754,48758, +48759,48760,48761,48762,48766,48767,48769,48770,48771,48773,48774,48775,48776, +48777,48778,48779,48782,48786,48787,48788,48789,48790,48791,48794,48795,48796, +48797,48798,48799,48800,48801,48802,48803,48804,48805,48806,48807,48809,48810, +48811,48812,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,48823, +48824,48825,48826,48827,48828,48829,48830,48831,48832,48833,48834,48835,48836, +48837,48838,48839,48840,48841,48842,48843,48844,48845,48846,48847,48850,48851, +U,U,U,U,U,U,48853,48854,48857,48858,48859,48860,48861,48862,48863,48865,48866, +48870,48871,48872,48873,48874,48875,48877,48878,48879,48880,48881,48882,48883, +48884,48885,U,U,U,U,U,U,48886,48887,48888,48889,48890,48891,48892,48893,48894, +48895,48896,48898,48899,48900,48901,48902,48903,48906,48907,48908,48909,48910, +48911,48912,48913,48914,48915,48916,48917,48918,48919,48922,48926,48927,48928, +48929,48930,48931,48932,48933,48934,48935,48936,48937,48938,48939,48940,48941, +48942,48943,48944,48945,48946,48947,48948,48949,48950,48951,48952,48953,48954, +48955,48956,48957,48958,48959,48962,48963,48965,48966,48967,48969,48970,48971, +48972,48973,48974,48975,48978,48979,48980,48982,48983,48984,48985,48986,48987, +48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,48998,48999,49000, +49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,49012,49013, +49014,49015,49016,49017,49018,49019,49020,49021,49022,49023,49024,49025,49026, +49027,49028,49029,49030,49031,49032,49033,49034,49035,49036,49037,49038,49039, +49040,49041,49042,49043,49045,49046,49047,49048,49049,49050,49051,49052,49053, +U,U,U,U,U,U,49054,49055,49056,49057,49058,49059,49060,49061,49062,49063,49064, +49065,49066,49067,49068,49069,49070,49071,49073,49074,49075,49076,49077,49078, +49079,49080,U,U,U,U,U,U,49081,49082,49083,49084,49085,49086,49087,49088,49089, +49090,49091,49092,49094,49095,49096,49097,49098,49099,49102,49103,49105,49106, +49107,49109,49110,49111,49112,49113,49114,49115,49117,49118,49120,49122,49123, +49124,49125,49126,49127,49128,49129,49130,49131,49132,49133,49134,49135,49136, +49137,49138,49139,49140,49141,49142,49143,49144,49145,49146,49147,49148,49149, +49150,49151,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49162, +49163,49164,49165,49166,49167,49168,49169,49170,49171,49172,49173,49174,49175, +49176,49177,49178,49179,49180,49181,49182,49183,49184,49185,49186,49187,49188, +49189,49190,49191,49192,49193,49194,49195,49196,49197,49198,49199,49200,49201, +49202,49203,49204,49205,49206,49207,49208,49209,49210,49211,49213,49214,49215, +49216,49217,49218,49219,49220,49221,49222,49223,49224,49225,49226,49227,49228, +49229,49230,49231,49232,49234,49235,49236,49237,49238,49239,49241,49242,49243, +U,U,U,U,U,U,49245,49246,49247,49249,49250,49251,49252,49253,49254,49255,49258, +49259,49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271, +49272,49273,U,U,U,U,U,U,49274,49275,49276,49277,49278,49279,49280,49281,49282, +49283,49284,49285,49286,49287,49288,49289,49290,49291,49292,49293,49294,49295, +49298,49299,49301,49302,49303,49305,49306,49307,49308,49309,49310,49311,49314, +49316,49318,49319,49320,49321,49322,49323,49326,49329,49330,49335,49336,49337, +49338,49339,49342,49346,49347,49348,49350,49351,49354,49355,49357,49358,49359, +49361,49362,49363,49364,49365,49366,49367,49370,49374,49375,49376,49377,49378, +49379,49382,49383,49385,49386,49387,49389,49390,49391,49392,49393,49394,49395, +49398,49400,49402,49403,49404,49405,49406,49407,49409,49410,49411,49413,49414, +49415,49417,49418,49419,49420,49421,49422,49423,49425,49426,49427,49428,49430, +49431,49432,49433,49434,49435,49441,49442,49445,49448,49449,49450,49451,49454, +49458,49459,49460,49461,49463,49466,49467,49469,49470,49471,49473,49474,49475, +49476,49477,49478,49479,49482,49486,49487,49488,49489,49490,49491,49494,49495, +U,U,U,U,U,U,49497,49498,49499,49501,49502,49503,49504,49505,49506,49507,49510, +49514,49515,49516,49517,49518,49519,49521,49522,49523,49525,49526,49527,49529, +49530,49531,U,U,U,U,U,U,49532,49533,49534,49535,49536,49537,49538,49539,49540, +49542,49543,49544,49545,49546,49547,49551,49553,49554,49555,49557,49559,49560, +49561,49562,49563,49566,49568,49570,49571,49572,49574,49575,49578,49579,49581, +49582,49583,49585,49586,49587,49588,49589,49590,49591,49592,49593,49594,49595, +49596,49598,49599,49600,49601,49602,49603,49605,49606,49607,49609,49610,49611, +49613,49614,49615,49616,49617,49618,49619,49621,49622,49625,49626,49627,49628, +49629,49630,49631,49633,49634,49635,49637,49638,49639,49641,49642,49643,49644, +49645,49646,49647,49650,49652,49653,49654,49655,49656,49657,49658,49659,49662, +49663,49665,49666,49667,49669,49670,49671,49672,49673,49674,49675,49678,49680, +49682,49683,49684,49685,49686,49687,49690,49691,49693,49694,49697,49698,49699, +49700,49701,49702,49703,49706,49708,49710,49712,49715,49717,49718,49719,49720, +49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733, +U,U,U,U,U,U,49734,49735,49737,49738,49739,49740,49741,49742,49743,49746,49747, +49749,49750,49751,49753,49754,49755,49756,49757,49758,49759,49761,49762,49763, +49764,49766,U,U,U,U,U,U,49767,49768,49769,49770,49771,49774,49775,49777,49778, +49779,49781,49782,49783,49784,49785,49786,49787,49790,49792,49794,49795,49796, +49797,49798,49799,49802,49803,49804,49805,49806,49807,49809,49810,49811,49812, +49813,49814,49815,49817,49818,49820,49822,49823,49824,49825,49826,49827,49830, +49831,49833,49834,49835,49838,49839,49840,49841,49842,49843,49846,49848,49850, +49851,49852,49853,49854,49855,49856,49857,49858,49859,49860,49861,49862,49863, +49864,49865,49866,49867,49868,49869,49870,49871,49872,49873,49874,49875,49876, +49877,49878,49879,49880,49881,49882,49883,49886,49887,49889,49890,49893,49894, +49895,49896,49897,49898,49902,49904,49906,49907,49908,49909,49911,49914,49917, +49918,49919,49921,49922,49923,49924,49925,49926,49927,49930,49931,49934,49935, +49936,49937,49938,49942,49943,49945,49946,49947,49949,49950,49951,49952,49953, +49954,49955,49958,49959,49962,49963,49964,49965,49966,49967,49968,49969,49970, +U,U,U,U,U,U,49971,49972,49973,49974,49975,49976,49977,49978,49979,49980,49981, +49982,49983,49984,49985,49986,49987,49988,49990,49991,49992,49993,49994,49995, +49996,49997,U,U,U,U,U,U,49998,49999,50000,50001,50002,50003,50004,50005,50006, +50007,50008,50009,50010,50011,50012,50013,50014,50015,50016,50017,50018,50019, +50020,50021,50022,50023,50026,50027,50029,50030,50031,50033,50035,50036,50037, +50038,50039,50042,50043,50046,50047,50048,50049,50050,50051,50053,50054,50055, +50057,50058,50059,50061,50062,50063,50064,50065,50066,50067,50068,50069,50070, +50071,50072,50073,50074,50075,50076,50077,50078,50079,50080,50081,50082,50083, +50084,50085,50086,50087,50088,50089,50090,50091,50092,50093,50094,50095,50096, +50097,50098,50099,50100,50101,50102,50103,50104,50105,50106,50107,50108,50109, +50110,50111,50113,50114,50115,50116,50117,50118,50119,50120,50121,50122,50123, +50124,50125,50126,50127,50128,50129,50130,50131,50132,50133,50134,50135,50138, +50139,50141,50142,50145,50147,50148,50149,50150,50151,50154,50155,50156,50158, +50159,50160,50161,50162,50163,50166,50167,50169,50170,50171,50172,50173,50174, +U,U,U,U,U,U,50175,50176,50177,50178,50179,50180,50181,50182,50183,50185,50186, +50187,50188,50189,50190,50191,50193,50194,50195,50196,50197,50198,50199,50200, +50201,50202,U,U,U,U,U,U,50203,50204,50205,50206,50207,50208,50209,50210,50211, +50213,50214,50215,50216,50217,50218,50219,50221,50222,50223,50225,50226,50227, +50229,50230,50231,50232,50233,50234,50235,50238,50239,50240,50241,50242,50243, +50244,50245,50246,50247,50249,50250,50251,50252,50253,50254,50255,50256,50257, +50258,50259,50260,50261,50262,50263,50264,50265,50266,50267,50268,50269,50270, +50271,50272,50273,50274,50275,50278,50279,50281,50282,50283,50285,50286,50287, +50288,50289,50290,50291,50294,50295,50296,50298,50299,50300,50301,50302,50303, +50305,50306,50307,50308,50309,50310,50311,50312,50313,50314,50315,50316,50317, +50318,50319,50320,50321,50322,50323,50325,50326,50327,50328,50329,50330,50331, +50333,50334,50335,50336,50337,50338,50339,50340,50341,50342,50343,50344,50345, +50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,50356,50357,50358, +50359,50361,50362,50363,50365,50366,50367,50368,50369,50370,50371,50372,50373, +U,U,U,U,U,U,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384, +50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397, +50398,50399,U,U,U,U,U,U,50400,50401,50402,50403,50404,50405,50406,50407,50408, +50410,50411,50412,50413,50414,50415,50418,50419,50421,50422,50423,50425,50427, +50428,50429,50430,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443, +50445,50446,50447,50449,50450,50451,50453,50454,50455,50456,50457,50458,50459, +50461,50462,50463,50464,50465,50466,50467,50468,50469,50470,50471,50474,50475, +50477,50478,50479,50481,50482,50483,50484,50485,50486,50487,50490,50492,50494, +50495,50496,50497,50498,50499,50502,50503,50507,50511,50512,50513,50514,50518, +50522,50523,50524,50527,50530,50531,50533,50534,50535,50537,50538,50539,50540, +50541,50542,50543,50546,50550,50551,50552,50553,50554,50555,50558,50559,50561, +50562,50563,50565,50566,50568,50569,50570,50571,50574,50576,50578,50579,50580, +50582,50585,50586,50587,50589,50590,50591,50593,50594,50595,50596,50597,50598, +50599,50600,50602,50603,50604,50605,50606,50607,50608,50609,50610,50611,50614, +U,U,U,U,U,U,50615,50618,50623,50624,50625,50626,50627,50635,50637,50639,50642, +50643,50645,50646,50647,50649,50650,50651,50652,50653,50654,50655,50658,50660, +50662,50663,U,U,U,U,U,U,50664,50665,50666,50667,50671,50673,50674,50675,50677, +50680,50681,50682,50683,50690,50691,50692,50697,50698,50699,50701,50702,50703, +50705,50706,50707,50708,50709,50710,50711,50714,50717,50718,50719,50720,50721, +50722,50723,50726,50727,50729,50730,50731,50735,50737,50738,50742,50744,50746, +50748,50749,50750,50751,50754,50755,50757,50758,50759,50761,50762,50763,50764, +50765,50766,50767,50770,50774,50775,50776,50777,50778,50779,50782,50783,50785, +50786,50787,50788,50789,50790,50791,50792,50793,50794,50795,50797,50798,50800, +50802,50803,50804,50805,50806,50807,50810,50811,50813,50814,50815,50817,50818, +50819,50820,50821,50822,50823,50826,50828,50830,50831,50832,50833,50834,50835, +50838,50839,50841,50842,50843,50845,50846,50847,50848,50849,50850,50851,50854, +50856,50858,50859,50860,50861,50862,50863,50866,50867,50869,50870,50871,50875, +50876,50877,50878,50879,50882,50884,50886,50887,50888,50889,50890,50891,50894, +U,U,U,U,U,U,50895,50897,50898,50899,50901,50902,50903,50904,50905,50906,50907, +50910,50911,50914,50915,50916,50917,50918,50919,50922,50923,50925,50926,50927, +50929,50930,U,U,U,U,U,U,50931,50932,50933,50934,50935,50938,50939,50940,50942, +50943,50944,50945,50946,50947,50950,50951,50953,50954,50955,50957,50958,50959, +50960,50961,50962,50963,50966,50968,50970,50971,50972,50973,50974,50975,50978, +50979,50981,50982,50983,50985,50986,50987,50988,50989,50990,50991,50994,50996, +50998,51000,51001,51002,51003,51006,51007,51009,51010,51011,51013,51014,51015, +51016,51017,51019,51022,51024,51033,51034,51035,51037,51038,51039,51041,51042, +51043,51044,51045,51046,51047,51049,51050,51052,51053,51054,51055,51056,51057, +51058,51059,51062,51063,51065,51066,51067,51071,51072,51073,51074,51078,51083, +51084,51085,51087,51090,51091,51093,51097,51099,51100,51101,51102,51103,51106, +51111,51112,51113,51114,51115,51118,51119,51121,51122,51123,51125,51126,51127, +51128,51129,51130,51131,51134,51138,51139,51140,51141,51142,51143,51146,51147, +51149,51151,51153,51154,51155,51156,51157,51158,51159,51161,51162,51163,51164, +U,U,U,U,U,U,51166,51167,51168,51169,51170,51171,51173,51174,51175,51177,51178, +51179,51181,51182,51183,51184,51185,51186,51187,51188,51189,51190,51191,51192, +51193,51194,U,U,U,U,U,U,51195,51196,51197,51198,51199,51202,51203,51205,51206, +51207,51209,51211,51212,51213,51214,51215,51218,51220,51223,51224,51225,51226, +51227,51230,51231,51233,51234,51235,51237,51238,51239,51240,51241,51242,51243, +51246,51248,51250,51251,51252,51253,51254,51255,51257,51258,51259,51261,51262, +51263,51265,51266,51267,51268,51269,51270,51271,51274,51275,51278,51279,51280, +51281,51282,51283,51285,51286,51287,51288,51289,51290,51291,51292,51293,51294, +51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305,51306,51307, +51308,51309,51310,51311,51314,51315,51317,51318,51319,51321,51323,51324,51325, +51326,51327,51330,51332,51336,51337,51338,51342,51343,51344,51345,51346,51347, +51349,51350,51351,51352,51353,51354,51355,51356,51358,51360,51362,51363,51364, +51365,51366,51367,51369,51370,51371,51372,51373,51374,51375,51376,51377,51378, +51379,51380,51381,51382,51383,51384,51385,51386,51387,51390,51391,51392,51393, +U,U,U,U,U,U,51394,51395,51397,51398,51399,51401,51402,51403,51405,51406,51407, +51408,51409,51410,51411,51414,51416,51418,51419,51420,51421,51422,51423,51426, +51427,51429,U,U,U,U,U,U,51430,51431,51432,51433,51434,51435,51436,51437,51438, +51439,51440,51441,51442,51443,51444,51446,51447,51448,51449,51450,51451,51454, +51455,51457,51458,51459,51463,51464,51465,51466,51467,51470,51472,51474,51475, +51476,51477,51478,51479,51481,51482,51483,51484,51485,51486,51487,51488,51489, +51490,51491,51492,51493,51494,51495,51496,51497,51498,51499,U,U,U,U,U,U,51501, +51502,51503,51504,51505,51506,51507,51509,51510,51511,51512,51513,51514,51515, +51516,51517,51518,51519,51520,51521,51522,51523,51524,51525,51526,51527,U,U,U, +U,U,U,51528,51529,51530,51531,51532,51533,51534,51535,51538,51539,51541,51542, +51543,51545,51546,51547,51548,51549,51550,51551,51554,51556,51557,51558,51559, +51560,51561,51562,51563,51565,51566,51567,51569,51570,51571,51573,51574,51575, +51576,51577,51578,51579,51581,51582,51583,51584,51585,51586,51587,51588,51589, +51590,51591,51594,51595,51597,51598,51599,U,U,U,U,U,U,51601,51602,51603,51604, +51605,51606,51607,51610,51612,51614,51615,51616,51617,51618,51619,51620,51621, +51622,51623,51624,51625,51626,51627,51628,51629,51630,U,U,U,U,U,U,51631,51632, +51633,51634,51635,51636,51637,51638,51639,51640,51641,51642,51643,51644,51645, +51646,51647,51650,51651,51653,51654,51657,51659,51660,51661,51662,51663,51666, +51668,51671,51672,51675,51678,51679,51681,51683,51685,51686,51688,51689,51690, +51691,51694,51698,51699,51700,51701,51702,51703,51706,51707,51709,51710,51711, +51713,51714,51715,51716,U,U,U,U,U,U,51717,51718,51719,51722,51726,51727,51728, +51729,51730,51731,51733,51734,51735,51737,51738,51739,51740,51741,51742,51743, +51744,51745,51746,51747,51748,51749,U,U,U,U,U,U,51750,51751,51752,51754,51755, +51756,51757,51758,51759,51760,51761,51762,51763,51764,51765,51766,51767,51768, +51769,51770,51771,51772,51773,51774,51775,51776,51777,51778,51779,51780,51781, +51782,51783,51784,51785,51786,51787,51790,51791,51793,51794,51795,51797,51798, +51799,51800,51801,51802,51803,51806,51810,51811,51812,51813,51814,51815,51817, +51818,U,U,U,U,U,U,51819,51820,51821,51822,51823,51824,51825,51826,51827,51828, +51829,51830,51831,51832,51833,51834,51835,51836,51838,51839,51840,51841,51842, +51843,51845,51846,U,U,U,U,U,U,51847,51848,51849,51850,51851,51852,51853,51854, +51855,51856,51857,51858,51859,51860,51861,51862,51863,51865,51866,51867,51868, +51869,51870,51871,51872,51873,51874,51875,51876,51877,51878,51879,51880,51881, +51882,51883,51884,51885,51886,51887,51888,51889,51890,51891,51892,51893,51894, +51895,51896,51897,51898,51899,51902,51903,51905,51906,51907,51909,U,U,U,U,U,U, +51910,51911,51912,51913,51914,51915,51918,51920,51922,51924,51925,51926,51927, +51930,51931,51932,51933,51934,51935,51937,51938,51939,51940,51941,51942,51943, +U,U,U,U,U,U,51944,51945,51946,51947,51949,51950,51951,51952,51953,51954,51955, +51957,51958,51959,51960,51961,51962,51963,51964,51965,51966,51967,51968,51969, +51970,51971,51972,51973,51974,51975,51977,51978,51979,51980,51981,51982,51983, +51985,51986,51987,51989,51990,51991,51993,51994,51995,51996,51997,51998,51999, +52002,52003,52004,52005,52006,52007,52008,52009,U,U,U,U,U,U,52010,52011,52012, +52013,52014,52015,52016,52017,52018,52019,52020,52021,52022,52023,52024,52025, +52026,52027,52028,52029,52030,52031,52032,52034,52035,52036,U,U,U,U,U,U,52037, +52038,52039,52042,52043,52045,52046,52047,52049,52050,52051,52052,52053,52054, +52055,52058,52059,52060,52062,52063,52064,52065,52066,52067,52069,52070,52071, +52072,52073,52074,52075,52076,52077,52078,52079,52080,52081,52082,52083,52084, +52085,52086,52087,52090,52091,52092,52093,52094,52095,52096,52097,52098,52099, +52100,52101,52102,52103,52104,U,U,U,U,U,U,52105,52106,52107,52108,52109,52110, +52111,52112,52113,52114,52115,52116,52117,52118,52119,52120,52121,52122,52123, +52125,52126,52127,52128,52129,52130,52131,U,U,U,U,U,U,52132,52133,52134,52135, +52136,52137,52138,52139,52140,52141,52142,52143,52144,52145,52146,52147,52148, +52149,52150,52151,52153,52154,52155,52156,52157,52158,52159,52160,52161,52162, +52163,52164,52165,52166,52167,52168,52169,52170,52171,52172,52173,52174,52175, +52176,52177,52178,52179,52181,52182,52183,52184,52185,52186,52187,52188,52189, +52190,52191,U,U,U,U,U,U,52192,52193,52194,52195,52197,52198,52200,52202,52203, +52204,52205,52206,52207,52208,52209,52210,52211,52212,52213,52214,52215,52216, +52217,52218,52219,52220,U,U,U,U,U,U,52221,52222,52223,52224,52225,52226,52227, +52228,52229,52230,52231,52232,52233,52234,52235,52238,52239,52241,52242,52243, +52245,52246,52247,52248,52249,52250,52251,52254,52255,52256,52259,52260,52261, +52262,52266,52267,52269,52271,52273,52274,52275,52276,52277,52278,52279,52282, +52287,52288,52289,52290,52291,52294,52295,52297,52298,52299,52301,52302,U,U,U, +U,U,U,52303,52304,52305,52306,52307,52310,52314,52315,52316,52317,52318,52319, +52321,52322,52323,52325,52327,52329,52330,52331,52332,52333,52334,52335,52337, +52338,U,U,U,U,U,U,52339,52340,52342,52343,52344,52345,52346,52347,52348,52349, +52350,52351,52352,52353,52354,52355,52356,52357,52358,52359,52360,52361,52362, +52363,52364,52365,52366,52367,52368,52369,52370,52371,52372,52373,52374,52375, +52378,52379,52381,52382,52383,52385,52386,52387,52388,52389,52390,52391,52394, +52398,52399,52400,52401,52402,52403,52406,52407,52409,U,U,U,U,U,U,52410,52411, +52413,52414,52415,52416,52417,52418,52419,52422,52424,52426,52427,52428,52429, +52430,52431,52433,52434,52435,52437,52438,52439,52440,52441,52442,U,U,U,U,U,U, +52443,52444,52445,52446,52447,52448,52449,52450,52451,52453,52454,52455,52456, +52457,52458,52459,52461,52462,52463,52465,52466,52467,52468,52469,52470,52471, +52472,52473,52474,52475,52476,52477,52478,52479,52480,52482,52483,52484,52485, +52486,52487,52490,52491,52493,52494,52495,52497,52498,52499,52500,52501,52502, +52503,52506,52508,52510,52511,52512,U,U,U,U,U,U,52513,52514,52515,52517,52518, +52519,52521,52522,52523,52525,52526,52527,52528,52529,52530,52531,52532,52533, +52534,52535,52536,52538,52539,52540,52541,52542,U,U,U,U,U,U,52543,52544,52545, +52546,52547,52548,52549,52550,52551,52552,52553,52554,52555,52556,52557,52558, +52559,52560,52561,52562,52563,52564,52565,52566,52567,52568,52569,52570,52571, +52573,52574,52575,52577,52578,52579,52581,52582,52583,52584,52585,52586,52587, +52590,52592,52594,52595,52596,52597,52598,52599,52601,52602,52603,52604,52605, +52606,52607,52608,U,U,U,U,U,U,52609,52610,52611,52612,52613,52614,52615,52617, +52618,52619,52620,52621,52622,52623,52624,52625,52626,52627,52630,52631,52633, +52634,52635,52637,52638,52639,U,U,U,U,U,U,52640,52641,52642,52643,52646,52648, +52650,52651,52652,52653,52654,52655,52657,52658,52659,52660,52661,52662,52663, +52664,52665,52666,52667,52668,52669,52670,52671,52672,52673,52674,52675,52677, +52678,52679,52680,52681,52682,52683,52685,52686,52687,52689,52690,52691,52692, +52693,52694,52695,52696,52697,52698,52699,52700,52701,52702,52703,52704,52705, +U,U,U,U,U,U,52706,52707,52708,52709,52710,52711,52713,52714,52715,52717,52718, +52719,52721,52722,52723,52724,52725,52726,52727,52730,52732,52734,52735,52736, +52737,52738,U,U,U,U,U,U,52739,52741,52742,52743,52745,52746,52747,52749,52750, +52751,52752,52753,52754,52755,52757,52758,52759,52760,52762,52763,52764,52765, +52766,52767,52770,52771,52773,52774,52775,52777,52778,52779,52780,52781,52782, +52783,52786,52788,52790,52791,52792,52793,52794,52795,52796,52797,52798,52799, +52800,52801,52802,52803,52804,52805,52806,52807,52808,52809,U,U,U,U,U,U,52810, +52811,52812,52813,52814,52815,52816,52817,52818,52819,52820,52821,52822,52823, +52826,52827,52829,52830,52834,52835,52836,52837,52838,52839,52842,52844,U,U,U, +U,U,U,52846,52847,52848,52849,52850,52851,52854,52855,52857,52858,52859,52861, +52862,52863,52864,52865,52866,52867,52870,52872,52874,52875,52876,52877,52878, +52879,52882,52883,52885,52886,52887,52889,52890,52891,52892,52893,52894,52895, +52898,52902,52903,52904,52905,52906,52907,52910,52911,52912,52913,52914,52915, +52916,52917,52918,52919,52920,52921,52922,U,U,U,U,U,U,52923,52924,52925,52926, +52927,52928,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940, +52941,52942,52943,52944,52945,52946,52947,52948,52949,U,U,U,U,U,U,52950,52951, +52952,52953,52954,52955,52956,52957,52958,52959,52960,52961,52962,52963,52966, +52967,52969,52970,52973,52974,52975,52976,52977,52978,52979,52982,52986,52987, +52988,52989,52990,52991,52994,52995,52997,52998,52999,53001,53002,53003,53004, +53005,53006,53007,53010,53012,53014,53015,53016,53017,53018,53019,53021,53022, +53023,53025,53026,53027,U,U,U,U,U,U,53029,53030,53031,53032,53033,53034,53035, +53038,53042,53043,53044,53045,53046,53047,53049,53050,53051,53052,53053,53054, +53055,53056,53057,53058,53059,53060,U,U,U,U,U,U,53061,53062,53063,53064,53065, +53066,53067,53068,53069,53070,53071,53072,53073,53074,53075,53078,53079,53081, +53082,53083,53085,53086,53087,53088,53089,53090,53091,53094,53096,53098,53099, +53100,53101,53102,53103,53106,53107,53109,53110,53111,53113,53114,53115,53116, +53117,53118,53119,53121,53122,53123,53124,53126,53127,53128,53129,53130,53131, +53133,U,U,U,U,U,U,53134,53135,53136,53137,53138,53139,53140,53141,53142,53143, +53144,53145,53146,53147,53148,53149,53150,53151,53152,53154,53155,53156,53157, +53158,53159,53161,U,U,U,U,U,U,53162,53163,53164,53165,53166,53167,53169,53170, +53171,53172,53173,53174,53175,53176,53177,53178,53179,53180,53181,53182,53183, +53184,53185,53186,53187,53189,53190,53191,53192,53193,53194,53195,53196,53197, +53198,53199,53200,53201,53202,53203,53204,53205,53206,53207,53208,53209,53210, +53211,53212,53213,53214,53215,53218,53219,53221,53222,53223,53225,U,U,U,U,U,U, +53226,53227,53228,53229,53230,53231,53234,53236,53238,53239,53240,53241,53242, +53243,53245,53246,53247,53249,53250,53251,53253,53254,53255,53256,53257,53258, +U,U,U,U,U,U,53259,53260,53261,53262,53263,53264,53266,53267,53268,53269,53270, +53271,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,53284, +53285,53286,53287,53288,53289,53290,53291,53292,53294,53295,53296,53297,53298, +53299,53302,53303,53305,53306,53307,53309,53310,53311,53312,53313,53314,53315, +53318,53320,53322,53323,53324,53325,53326,53327,U,U,U,U,U,U,53329,53330,53331, +53333,53334,53335,53337,53338,53339,53340,53341,53342,53343,53345,53346,53347, +53348,53349,53350,53351,53352,53353,53354,53355,53358,53359,U,U,U,U,U,U,53361, +53362,53363,53365,53366,53367,53368,53369,53370,53371,53374,53375,53376,53378, +53379,53380,53381,53382,53383,53384,53385,53386,53387,53388,53389,53390,53391, +53392,53393,53394,53395,53396,53397,53398,53399,53400,53401,53402,53403,53404, +53405,53406,53407,53408,53409,53410,53411,53414,53415,53417,53418,53419,53421, +53422,53423,53424,53425,53426,U,U,U,U,U,U,53427,53430,53432,53434,53435,53436, +53437,53438,53439,53442,53443,53445,53446,53447,53450,53451,53452,53453,53454, +53455,53458,53462,53463,53464,53465,53466,U,U,U,U,U,U,53467,53470,53471,53473, +53474,53475,53477,53478,53479,53480,53481,53482,53483,53486,53490,53491,53492, +53493,53494,53495,53497,53498,53499,53500,53501,53502,53503,53504,53505,53506, +53507,53508,53509,53510,53511,53512,53513,53514,53515,53516,53518,53519,53520, +53521,53522,53523,53524,53525,53526,53527,53528,53529,53530,53531,53532,53533, +53534,53535,U,U,U,U,U,U,53536,53537,53538,53539,53540,53541,53542,53543,53544, +53545,53546,53547,53548,53549,53550,53551,53554,53555,53557,53558,53559,53561, +53563,53564,53565,53566,U,U,U,U,U,U,53567,53570,53574,53575,53576,53577,53578, +53579,53582,53583,53585,53586,53587,53589,53590,53591,53592,53593,53594,53595, +53598,53600,53602,53603,53604,53605,53606,53607,53609,53610,53611,53613,53614, +53615,53616,53617,53618,53619,53620,53621,53622,53623,53624,53625,53626,53627, +53629,53630,53631,53632,53633,53634,53635,53637,53638,53639,53641,53642,U,U,U, +U,U,U,53643,53644,53645,53646,53647,53648,53649,53650,53651,53652,53653,53654, +53655,53656,53657,53658,53659,53660,53661,53662,53663,53666,53667,53669,53670, +53671,U,U,U,U,U,U,53673,53674,53675,53676,53677,53678,53679,53682,53684,53686, +53687,53688,53689,53691,53693,53694,53695,53697,53698,53699,53700,53701,53702, +53703,53704,53705,53706,53707,53708,53709,53710,53711,53712,53713,53714,53715, +53716,53717,53718,53719,53721,53722,53723,53724,53725,53726,53727,53728,53729, +53730,53731,53732,53733,53734,53735,53736,53737,53738,U,U,U,U,U,U,53739,53740, +53741,53742,53743,53744,53745,53746,53747,53749,53750,53751,53753,53754,53755, +53756,53757,53758,53759,53760,53761,53762,53763,53764,53765,53766,U,U,U,U,U,U, +53768,53770,53771,53772,53773,53774,53775,53777,53778,53779,53780,53781,53782, +53783,53784,53785,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795, +53796,53797,53798,53799,53800,53801,53802,53803,53806,53807,53809,53810,53811, +53813,53814,53815,53816,53817,53818,53819,53822,53824,53826,53827,53828,53829, +53830,53831,53833,53834,53835,53836,U,U,U,U,U,U,53837,53838,53839,53840,53841, +53842,53843,53844,53845,53846,53847,53848,53849,53850,53851,53853,53854,53855, +53856,53857,53858,53859,53861,53862,53863,53864,U,U,U,U,U,U,53865,53866,53867, +53868,53869,53870,53871,53872,53873,53874,53875,53876,53877,53878,53879,53880, +53881,53882,53883,53884,53885,53886,53887,53890,53891,53893,53894,53895,53897, +53898,53899,53900,53901,53902,53903,53906,53907,53908,53910,53911,53912,53913, +53914,53915,53917,53918,53919,53921,53922,53923,53925,53926,53927,53928,53929, +53930,53931,53933,U,U,U,U,U,U,53934,53935,53936,53938,53939,53940,53941,53942, +53943,53946,53947,53949,53950,53953,53955,53956,53957,53958,53959,53962,53964, +53965,53966,53967,53968,53969,U,U,U,U,U,U,53970,53971,53973,53974,53975,53977, +53978,53979,53981,53982,53983,53984,53985,53986,53987,53990,53991,53992,53993, +53994,53995,53996,53997,53998,53999,54002,54003,54005,54006,54007,54009,54010, +54011,54012,54013,54014,54015,54018,54020,54022,54023,54024,54025,54026,54027, +54031,54033,54034,54035,54037,54039,54040,54041,54042,54043,54046,54050,54051, +U,U,U,U,U,U,54052,54054,54055,54058,54059,54061,54062,54063,54065,54066,54067, +54068,54069,54070,54071,54074,54078,54079,54080,54081,54082,54083,54086,54087, +54088,54089,U,U,U,U,U,U,54090,54091,54092,54093,54094,54095,54096,54097,54098, +54099,54100,54101,54102,54103,54104,54105,54106,54107,54108,54109,54110,54111, +54112,54113,54114,54115,54116,54117,54118,54119,54120,54121,54122,54123,54124, +54125,54126,54127,54128,54129,54130,54131,54132,54133,54134,54135,54136,54137, +54138,54139,54142,54143,54145,54146,54147,54149,54150,54151,U,U,U,U,U,U,54152, +54153,54154,54155,54158,54162,54163,54164,54165,54166,54167,54170,54171,54173, +54174,54175,54177,54178,54179,54180,54181,54182,54183,54186,54188,54190,U,U,U, +U,U,U,54191,54192,54193,54194,54195,54197,54198,54199,54201,54202,54203,54205, +54206,54207,54208,54209,54210,54211,54214,54215,54218,54219,54220,54221,54222, +54223,54225,54226,54227,54228,54229,54230,54231,54233,54234,54235,54236,54237, +54238,54239,54240,54242,54244,54245,54246,54247,54248,54249,54250,54251,54254, +54255,54257,54258,54259,54261,54262,54263,U,U,U,U,U,U,54264,54265,54266,54267, +54270,54272,54274,54275,54276,54277,54278,54279,54281,54282,54283,54284,54285, +54286,54287,54288,54289,54290,54291,54292,54293,54294,U,U,U,U,U,U,54295,54296, +54297,54298,54299,54300,54302,54303,54304,54305,54306,54307,54308,54309,54310, +54311,54312,54313,54314,54315,54316,54317,54318,54319,54320,54321,54322,54323, +54324,54325,54326,54327,54328,54329,54330,54331,54332,54333,54334,54335,54337, +54338,54339,54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351, +54352,54353,54354,54355,U,U,U,U,U,U,54356,54357,54358,54359,54360,54361,54362, +54363,54365,54366,54367,54369,54370,54371,54373,54374,54375,54376,54377,54378, +54379,54380,54382,54384,54385,54386,U,U,U,U,U,U,54387,54388,54389,54390,54391, +54394,54395,54397,54398,54401,54403,54404,54405,54406,54407,54410,54412,54414, +54415,54416,54417,54418,54419,54421,54422,54423,54424,54425,54426,54427,54428, +54429,54430,54431,54432,54433,54434,54435,54436,54437,54438,54439,54440,54442, +54443,54444,54445,54446,54447,54448,54449,54450,54451,54452,54453,54454,54455, +54456,U,U,U,U,U,U,54457,54458,54459,54460,54461,54462,54463,54464,54465,54466, +54467,54468,54469,54470,54471,54472,54473,54474,54475,54477,54478,54479,54481, +54482,54483,54485,U,U,U,U,U,U,54486,54487,54488,54489,54490,54491,54493,54494, +54496,54497,54498,54499,54500,54501,54502,54503,54505,54506,54507,54509,54510, +54511,54513,54514,54515,54516,54517,54518,54519,54521,54522,54524,54526,54527, +54528,54529,54530,54531,54533,54534,54535,54537,54538,54539,54541,54542,54543, +54544,54545,54546,54547,54550,54552,54553,54554,54555,54556,54557,U,U,U,U,U,U, +54558,54559,54560,54561,54562,54563,54564,54565,54566,54567,54568,54569,54570, +54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,54583, +U,U,U,U,U,U,54584,54585,54586,54587,54590,54591,54593,54594,54595,54597,54598, +54599,54600,54601,54602,54603,54606,54608,54610,54611,54612,54613,54614,54615, +54618,54619,54621,54622,54623,54625,54626,54627,54628,54630,54631,54634,54636, +54638,54639,54640,54641,54642,54643,54646,54647,54649,54650,54651,54653,54654, +54655,54656,54657,54658,54659,54662,54666,54667,U,U,U,U,U,U,54668,54669,54670, +54671,54673,54674,54675,54676,54677,54678,54679,54680,54681,54682,54683,54684, +54685,54686,54687,54688,54689,54690,54691,54692,54694,54695,U,U,U,U,U,U,54696, +54697,54698,54699,54700,54701,54702,54703,54704,54705,54706,54707,54708,54709, +54710,54711,54712,54713,54714,54715,54716,54717,54718,54719,54720,54721,54722, +54723,54724,54725,54726,54727,54730,54731,54733,54734,54735,54737,54739,54740, +54741,54742,54743,54746,54748,54750,54751,54752,54753,54754,54755,54758,54759, +54761,54762,54763,54765,54766,U,U,U,U,U,U,54767,54768,54769,54770,54771,54774, +54776,54778,54779,54780,54781,54782,54783,54786,54787,54789,54790,54791,54793, +54794,54795,54796,54797,54798,54799,54802,U,U,U,U,U,U,54806,54807,54808,54809, +54810,54811,54813,54814,54815,54817,54818,54819,54821,54822,54823,54824,54825, +54826,54827,54828,54830,54831,54832,54833,54834,54835,54836,54837,54838,54839, +54842,54843,54845,54846,54847,54849,54850,54851,54852,54854,54855,54858,54860, +54862,54863,54864,54866,54867,54870,54871,54873,54874,54875,54877,54878,54879, +54880,54881,U,U,U,U,U,U,54882,54883,54884,54885,54886,54888,54890,54891,54892, +54893,54894,54895,54898,54899,54901,54902,54903,54904,54905,54906,54907,54908, +54909,54910,54911,54912,U,U,U,U,U,U,54913,54914,54916,54918,54919,54920,54921, +54922,54923,54926,54927,54929,54930,54931,54933,54934,54935,54936,54937,54938, +54939,54940,54942,54944,54946,54947,54948,54949,54950,54951,54953,54954,54955, +54957,54958,54959,54961,54962,54963,54964,54965,54966,54967,54968,54970,54972, +54973,54974,54975,54976,54977,54978,54979,54982,54983,54985,54986,54987,U,U,U, +U,U,U,54989,54990,54991,54992,54994,54995,54997,54998,55000,55002,55003,55004, +55005,55006,55007,55009,55010,55011,55013,55014,55015,55017,55018,55019,55020, +55021,U,U,U,U,U,U,55022,55023,55025,55026,55027,55028,55030,55031,55032,55033, +55034,55035,55038,55039,55041,55042,55043,55045,55046,55047,55048,55049,55050, +55051,55052,55053,55054,55055,55056,55058,55059,55060,55061,55062,55063,55066, +55067,55069,55070,55071,55073,55074,55075,55076,55077,55078,55079,55082,55084, +55086,55087,55088,55089,55090,55091,55094,55095,55097,U,U,U,U,U,U,55098,55099, +55101,55102,55103,55104,55105,55106,55107,55109,55110,55112,55114,55115,55116, +55117,55118,55119,55122,55123,55125,55130,55131,55132,55133,55134,U,U,U,U,U,U, +55135,55138,55140,55142,55143,55144,55146,55147,55149,55150,55151,55153,55154, +55155,55157,55158,55159,55160,55161,55162,55163,55166,55167,55168,55170,55171, +55172,55173,55174,55175,55178,55179,55181,55182,55183,55185,55186,55187,55188, +55189,55190,55191,55194,55196,55198,55199,55200,55201,55202,55203, +}; + +static const struct dbcs_index cp949ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{__cp949ext_decmap+0,65,254},{__cp949ext_decmap+190, +65,254},{__cp949ext_decmap+380,65,254},{__cp949ext_decmap+570,65,254},{ +__cp949ext_decmap+760,65,254},{__cp949ext_decmap+950,65,254},{ +__cp949ext_decmap+1140,65,254},{__cp949ext_decmap+1330,65,254},{ +__cp949ext_decmap+1520,65,254},{__cp949ext_decmap+1710,65,254},{ +__cp949ext_decmap+1900,65,254},{__cp949ext_decmap+2090,65,254},{ +__cp949ext_decmap+2280,65,254},{__cp949ext_decmap+2470,65,254},{ +__cp949ext_decmap+2660,65,254},{__cp949ext_decmap+2850,65,254},{ +__cp949ext_decmap+3040,65,254},{__cp949ext_decmap+3230,65,254},{ +__cp949ext_decmap+3420,65,254},{__cp949ext_decmap+3610,65,254},{ +__cp949ext_decmap+3800,65,254},{__cp949ext_decmap+3990,65,254},{ +__cp949ext_decmap+4180,65,254},{__cp949ext_decmap+4370,65,254},{ +__cp949ext_decmap+4560,65,254},{__cp949ext_decmap+4750,65,254},{ +__cp949ext_decmap+4940,65,254},{__cp949ext_decmap+5130,65,254},{ +__cp949ext_decmap+5320,65,254},{__cp949ext_decmap+5510,65,254},{ +__cp949ext_decmap+5700,65,254},{__cp949ext_decmap+5890,65,254},{ +__cp949ext_decmap+6080,65,160},{__cp949ext_decmap+6176,65,160},{ +__cp949ext_decmap+6272,65,160},{__cp949ext_decmap+6368,65,160},{ +__cp949ext_decmap+6464,65,160},{__cp949ext_decmap+6560,65,160},{ +__cp949ext_decmap+6656,65,160},{__cp949ext_decmap+6752,65,160},{ +__cp949ext_decmap+6848,65,160},{__cp949ext_decmap+6944,65,160},{ +__cp949ext_decmap+7040,65,160},{__cp949ext_decmap+7136,65,160},{ +__cp949ext_decmap+7232,65,160},{__cp949ext_decmap+7328,65,160},{ +__cp949ext_decmap+7424,65,160},{__cp949ext_decmap+7520,65,160},{ +__cp949ext_decmap+7616,65,160},{__cp949ext_decmap+7712,65,160},{ +__cp949ext_decmap+7808,65,160},{__cp949ext_decmap+7904,65,160},{ +__cp949ext_decmap+8000,65,160},{__cp949ext_decmap+8096,65,160},{ +__cp949ext_decmap+8192,65,160},{__cp949ext_decmap+8288,65,160},{ +__cp949ext_decmap+8384,65,160},{__cp949ext_decmap+8480,65,160},{ +__cp949ext_decmap+8576,65,160},{__cp949ext_decmap+8672,65,160},{ +__cp949ext_decmap+8768,65,160},{__cp949ext_decmap+8864,65,160},{ +__cp949ext_decmap+8960,65,160},{__cp949ext_decmap+9056,65,160},{ +__cp949ext_decmap+9152,65,160},{__cp949ext_decmap+9248,65,160},{ +__cp949ext_decmap+9344,65,160},{__cp949ext_decmap+9440,65,160},{ +__cp949ext_decmap+9536,65,160},{__cp949ext_decmap+9632,65,82},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __cp949_encmap[33133] = { +8750,N,N,8756,N,N,8535,8487,N,10275,N,N,8489,8807,N,8518,8510,10615,10616, +8741,N,8786,8484,8748,10614,10284,N,10361,10358,10362,8751,N,N,N,N,N,N,10273, +N,N,N,N,N,N,N,N,N,10274,N,N,N,N,N,N,8511,10282,N,N,N,N,N,10285,10540,N,N,N,N, +N,N,10529,N,N,N,N,N,N,N,N,N,10531,N,N,N,N,N,N,8512,10538,N,N,N,N,N,10541, +10530,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10276,10532,N,N,N,N,N,N,N,N,N, +10533,10278,10534,N,N,N,N,10535,N,N,N,N,N,N,10280,10536,10281,10537,N,N,N,N,N, +N,10544,10287,10543,N,N,N,N,N,N,10283,10539,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,10286,10542,8743,N,N,N,N,N,N,N,N,8752,N,N,N,N,N,N,N,8744,8747,8746,8749,N, +8745,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,9548,9549,9550, +9551,9552,9553,N,9554,9555,9556,9557,9558,9559,9560,N,N,N,N,N,N,N,9569,9570, +9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,N, +9586,9587,9588,9589,9590,9591,9592,11303,N,N,N,N,N,N,N,N,N,N,N,N,N,N,11297, +11298,11299,11300,11301,11302,11304,11305,11306,11307,11308,11309,11310,11311, +11312,11313,11314,11315,11316,11317,11318,11319,11320,11321,11322,11323,11324, +11325,11326,11327,11328,11329,11345,11346,11347,11348,11349,11350,11352,11353, +11354,11355,11356,11357,11358,11359,11360,11361,11362,11363,11364,11365,11366, +11367,11368,11369,11370,11371,11372,11373,11374,11375,11376,11377,N,11351, +8490,N,N,8494,8495,N,N,8496,8497,N,N,8787,8788,N,N,N,8485,8486,N,N,N,N,N,N,N, +N,N,8758,N,8519,8520,N,N,N,N,N,N,N,8536,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +10617,N,N,N,N,N,N,N,N,N,N,10618,N,10619,10620,10621,10622,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8806,8521,N,N,N,N,N, +8757,N,N,N,N,N,N,N,N,N,10020,N,N,8800,N,N,N,N,N,N,N,N,N,N,8805,8802,N,N,N, +10073,N,N,N,N,8522,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,10359,10360,N,N,N,N,N,N,10363,10364,10365,10366,N,9520, +9521,9522,9523,9524,9525,9526,9527,9528,9529,N,N,N,N,N,N,9505,9506,9507,9508, +9509,9510,9511,9512,9513,9514,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +8551,8552,8550,8553,8554,8789,8792,8790,8793,8791,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,8737,N,8738,8739,N,8531,8740,N,N,N,8532,8564,N,N,8565,N,N,N,8755,N,8754, +N,N,N,N,N,N,N,N,8558,N,N,8560,8516,N,8528,N,N,N,N,8491,N,8572,8573,8571,8570, +8562,8563,N,8753,N,N,N,N,N,8517,8561,N,N,N,N,N,N,8493,8559,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,8534,N,N,N,N,N,N,N,N,N,N,N,N,N,8513,8533,N,N,8514,8515, +N,N,N,N,8556,8557,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8568,8569,N,N, +8566,8567,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8769,N,N,N,N,N,N,N,N,N,N,N,8529, +8530,10343,10344,10345,10346,10347,10348,10349,10350,10351,10352,10353,10354, +10355,10356,10357,N,N,N,N,N,10599,10600,10601,10602,10603,10604,10605,10606, +10607,10608,10609,10610,10611,10612,10613,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,10573,10574,10575,10576,10577,10578,10579,10580,10581,10582, +10583,10584,10585,10586,10587,10588,10589,10590,10591,10592,10593,10594,10595, +10596,10597,10598,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10317, +10318,10319,10320,10321,10322,10323,10324,10325,10326,10327,10328,10329,10330, +10331,10332,10333,10334,10335,10336,10337,10338,10339,10340,10341,10342,9761, +9772,9762,9773,N,N,N,N,N,N,N,N,9763,9800,9799,9774,9764,9794,9793,9775,9766, +9798,9797,9777,9765,9796,9795,9776,9767,9788,9801,9802,9783,9803,9804,9778, +9769,9790,9805,9806,9785,9807,9808,9780,9768,9809,9810,9784,9789,9811,9812, +9779,9770,9813,9814,9786,9791,9815,9816,9781,9771,9817,9818,9787,9819,9820, +9792,9821,9822,9823,9824,9825,9826,9827,9828,9782,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8774,N,N,N,N,N,N,N,N,N,N,N,N,N,8545,8544,N, +8771,8775,8776,8779,8778,8777,8780,N,N,N,N,N,N,N,N,8547,8546,N,N,8762,8761,N, +N,N,N,8549,8548,N,N,8760,8759,N,N,N,N,8543,8542,8770,N,N,8539,N,N,8541,8540, +8772,8773,8538,8537,N,N,N,N,N,N,N,8783,8782,N,N,N,N,N,N,N,N,N,N,N,N,8784,N, +8785,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8527,N, +8526,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,8764,8765,N, +8768,8763,8766,N,8767,8781,8795,8796,N,8797,8794,8481,8482,8483,8488,N,N,N,N, +8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,N,8555,8498,8499,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +10785,10786,10787,10788,10789,10790,10791,10792,10793,10794,10795,10796,10797, +10798,10799,10800,10801,10802,10803,10804,10805,10806,10807,10808,10809,10810, +10811,10812,10813,10814,10815,10816,10817,10818,10819,10820,10821,10822,10823, +10824,10825,10826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836, +10837,10838,10839,10840,10841,10842,10843,10844,10845,10846,10847,10848,10849, +10850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860,10861,10862, +10863,10864,10865,10866,10867,N,N,N,N,N,N,N,N,N,N,N,N,N,11041,11042,11043, +11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056, +11057,11058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069, +11070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,11082, +11083,11084,11085,11086,11087,11088,11089,11090,11091,11092,11093,11094,11095, +11096,11097,11098,11099,11100,11101,11102,11103,11104,11105,11106,11107,11108, +11109,11110,11111,11112,11113,11114,11115,11116,11117,11118,11119,11120,11121, +11122,11123,11124,11125,11126,9249,9250,9251,9252,9253,9254,9255,9256,9257, +9258,9259,9260,9261,9262,9263,9264,9265,9266,9267,9268,9269,9270,9271,9272, +9273,9274,9275,9276,9277,9278,9279,9280,9281,9282,9283,9284,9285,9286,9287, +9288,9289,9290,9291,9292,9293,9294,9295,9296,9297,9298,9299,9300,9301,9302, +9303,9304,9305,9306,9307,9308,9309,9310,9311,9312,9313,9314,9315,9316,9317, +9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,9332, +9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,10545,10546,10547,10548, +10549,10550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561, +10562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,8799,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,10289,10290,10291,10292, +10293,10294,10295,10296,10297,10298,10299,10300,10301,10302,10303,10304,10305, +10306,10307,10308,10309,10310,10311,10312,10313,10314,10315,10316,N,N,N,8798, +10057,10058,10059,10060,10061,N,N,N,10042,10043,10076,10077,10078,10038,10039, +10040,10068,10069,10070,10071,10072,10017,10018,10019,10021,10027,10028,10029, +10030,10031,10032,10033,10034,10035,10036,10023,10024,10025,10026,10045,10046, +10085,10086,10087,10088,10081,10082,10083,10047,10048,10049,10050,10051,10052, +10053,10054,10055,10056,10062,10063,10064,10065,10066,10067,10074,10075,8803, +10092,10022,10080,10095,8801,10044,10093,10037,N,N,N,N,10041,10090,N,N,10091, +N,N,10079,N,8804,N,N,10084,10094,10089,27753,28491,N,30290,N,N,N,22578,27995, +24370,24382,31035,N,23668,N,N,N,30052,N,N,29478,23904,24870,N,20088,23600,N,N, +N,N,25386,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29033,N,N,N,N,19834,N,N,N,N,N,31791, +21281,N,28971,N,N,N,N,N,N,26449,21036,N,20089,N,N,N,N,N,29053,N,24127,31546, +31033,N,N,N,N,N,N,20050,N,25387,27488,N,N,N,20090,19319,25893,N,N,N,N,N,N,N,N, +N,N,N,19041,N,21580,N,N,N,N,N,27233,N,N,23651,24365,N,N,N,N,N,N,19307,N,N,N, +21807,N,N,N,22133,N,25976,N,N,24128,27683,N,26957,N,27175,26998,31547,N,26473, +28492,N,N,20582,N,N,24129,N,N,25644,N,N,22604,31089,N,20063,31268,26162,N, +31355,N,N,31293,19528,28493,21845,N,N,N,N,N,N,N,21282,N,N,N,27729,N,N,N,N,N, +25639,27730,N,N,30257,N,N,20091,N,N,20561,19263,N,27940,N,N,N,N,N,N,27944, +24130,30306,27996,23669,24633,N,N,N,21582,N,29749,N,N,N,21339,22069,27684,N,N, +N,N,N,N,N,N,N,N,25702,N,29034,N,N,N,19308,19264,N,N,N,27762,20586,N,N,N,N,N,N, +N,31090,27685,20575,N,26474,20587,23633,23401,32076,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23383,N,N,N,N,23137,N,22070,N,25439,N,24131,N, +24132,18977,N,N,N,N,N,28268,N,N,21283,28215,30799,N,N,N,N,27208,28216,28972, +28965,26958,N,N,N,31036,N,N,N,25977,27754,23894,27970,N,N,N,N,N,N,N,N,N,N,N,N, +30757,N,N,N,N,N,25914,23384,N,N,18978,N,N,20813,N,N,N,28269,N,N,N,27755,24133, +N,25440,N,19017,29289,N,21838,N,30262,N,20034,22087,N,25396,N,28973,N,27234,N, +N,N,N,22338,N,29479,N,N,19818,N,27502,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22834, +32037,N,N,N,N,N,30293,21858,N,N,N,N,N,N,N,N,30773,N,N,19573,30005,25645,N,N,N, +N,26475,29013,N,N,N,28731,N,N,26933,N,19529,31317,N,N,24916,N,N,22358,N,N, +23617,N,24134,31343,25441,N,N,N,N,N,N,N,N,N,N,N,N,24947,23670,N,20092,N,23364, +N,30833,N,N,23652,N,25967,23601,N,N,N,21846,N,N,29530,N,19265,N,23363,N,N,N, +22906,21358,N,N,N,31288,N,N,32038,27503,N,29734,N,19530,29480,N,29531,N,23335, +30263,N,20326,28786,19290,N,26450,22339,30320,26718,N,N,N,N,N,N,N,N,N,N,N,N,N, +25894,N,N,N,N,N,N,N,25959,N,N,N,18979,19495,27209,N,N,N,N,N,30774,N,N,N,N,N, +31269,N,N,N,N,28974,N,28494,N,N,N,N,N,N,N,N,19309,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30256,28495,26959,N,30558,N,N,N,N,N,N,N,20051,N,N,N,N,23671,N,N,N,N,N,N,N, +23336,N,N,N,19320,N,N,N,N,N,N,24353,23905,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +30026,26934,N,N,N,N,26476,28270,N,29552,N,24383,N,N,N,N,N,N,19531,N,N,N,N,N,N, +20545,N,N,N,29778,24634,N,N,N,N,24384,N,20064,N,N,N,23634,32106,N,N,N,22134,N, +N,N,27210,N,N,N,N,N,N,26729,N,25388,N,N,N,N,N,29520,N,N,N,N,N,N,N,N,N,N,N, +18980,N,23416,N,N,N,24135,27504,29014,N,N,25954,N,19532,N,N,19323,N,N,N,N,N,N, +N,N,27235,N,N,N,N,N,N,N,N,N,N,N,N,24385,N,22125,N,N,N,N,N,N,N,N,26960,N,N,N,N, +N,N,N,28217,N,N,N,N,21859,N,N,20819,N,25968,N,N,N,26676,27459,N,27178,31356, +30070,28732,32084,24635,20035,N,20538,30522,22643,30541,N,N,N,25646,N,N,N,N,N, +N,N,N,N,21599,N,N,N,N,N,20583,N,N,27773,N,21038,28271,21847,27236,30754,19819, +22335,31537,N,N,19820,N,N,N,23602,20588,20093,28272,N,N,N,19522,N,N,N,20589,N, +N,N,N,N,25975,N,N,N,29564,N,N,28194,N,N,N,N,22835,N,N,22644,N,26935,N,N,N,N,N, +N,N,N,20014,N,N,N,N,22818,N,N,N,N,22641,N,21583,N,N,N,N,N,N,N,N,N,25895,21842, +N,N,N,N,N,22057,N,N,N,N,N,N,29730,N,29015,N,N,21848,N,28733,22352,21584,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,22351,27498,32107,N,N,23405,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +31813,19266,N,N,N,N,32085,N,29768,26730,30067,N,N,31070,21359,N,N,27731,N,N, +23874,28471,26452,N,19018,N,N,N,22907,N,N,31357,N,N,N,N,N,22058,N,N,N,N,N, +29816,N,N,N,N,N,N,30583,23596,N,N,N,22359,24354,N,N,N,20030,N,21360,N,N,N,N,N, +28708,24940,20327,29515,27945,19006,N,N,N,N,N,N,N,29807,N,N,N,30286,N,N,24187, +20539,21815,28273,N,N,N,N,N,N,29736,N,23672,N,N,N,N,19239,N,23118,N,N,N,24678, +N,N,N,N,N,N,N,27941,28274,N,N,N,N,23673,N,N,31068,N,N,29532,N,N,N,N,N,N,N, +30834,N,29817,N,N,N,31857,N,N,N,20540,23417,22321,N,N,N,19324,N,N,N,28709, +19325,N,N,N,N,N,N,N,N,21876,N,N,N,19821,18981,N,N,22059,20546,N,N,N,N,28734, +21053,19492,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31286,N,N,19533,N,23162,N, +30287,N,26936,N,22645,N,N,N,19534,N,N,N,N,22349,N,N,21585,26989,N,19051,22882, +N,32050,N,25389,22092,22836,N,N,24871,28243,20547,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +32051,N,21860,N,N,20328,N,27971,20530,N,N,20094,23080,30800,N,N,32086,N,N,N,N, +30801,N,30802,23635,N,N,N,N,23906,31609,23873,N,25397,N,N,N,N,N,N,27997,20036, +N,19233,N,N,N,N,N,N,23907,N,N,N,N,31837,N,N,N,N,N,N,N,N,N,31023,N,N,N,N,N, +21115,20257,25640,N,29750,27774,N,N,25390,26477,32065,23138,N,N,22579,N,N,N, +23908,28783,30321,31344,N,N,20853,N,N,23119,N,23636,N,23590,N,28479,N,N,N,N,N, +20047,N,24665,N,N,N,N,N,N,22870,27732,27211,N,N,19007,21808,N,20329,N,N,N,N,N, +29037,N,19535,N,N,N,N,25720,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25709,N,N,N,N,22360,N, +32039,N,N,N,N,27179,30258,N,N,N,N,20336,31037,N,N,N,N,N,N,26228,N,N,N,N,N,N,N, +N,N,N,N,N,N,19291,N,N,N,N,N,N,N,29521,N,N,N,N,26961,29481,20576,26962,N,23139, +N,N,N,N,N,N,25170,N,30242,24948,N,N,N,23140,N,N,N,N,N,26453,30015,20258,19759, +20259,N,N,N,19760,29054,20515,24879,30755,N,18982,30523,29290,24136,26963,N,N, +N,N,24137,32094,19008,N,N,N,31082,20814,28244,N,21586,22819,32040,22361,30542, +31294,N,N,N,N,N,N,N,N,N,20310,N,22384,N,27489,30789,N,N,N,N,N,23674,N,N,23875, +N,31071,N,N,N,N,N,N,N,26479,N,N,N,N,32101,30243,N,22908,32041,N,26478,N,N,N, +21861,N,N,N,N,N,28496,N,19761,N,N,N,N,N,N,30498,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,28978,N,28977,N,N,N,N,N,N,19762,N,23083,N,18983,N,N,N,N,N,25442, +31548,22820,N,N,28218,N,N,N,N,N,30803,N,N,N,N,N,31610,N,20260,N,23675,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30307,N,N,N,27946,N,N,29217,20065,N,N,N,N,N,N, +31270,N,N,N,N,31072,N,N,N,N,27734,N,N,25710,31009,N,N,31599,N,N,N,31083,28195, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27180,N,N,N,18984,N,N,29818,N,N, +N,N,19798,31862,N,N,N,29769,N,N,N,N,N,N,N,30804,30758,N,24138,29254,N,N,N,N,N, +N,22362,N,21328,N,N,N,N,N,N,N,N,N,N,N,22597,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,27238,N,29533,N,N,N,25690,N,N,N,N,N,N,N,N,30308,N,N,N,N,N,30322,N,24386,N,N, +N,N,N,N,N,N,22909,N,N,N,19574,N,N,21306,N,N,N,N,N,N,N,25647,N,N,N,N,31073,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28710,N,N,N,19283,N,N,N,24636,N, +29770,21626,N,32042,31074,N,N,N,N,N,N,N,N,N,N,N,N,N,29751,32066,31792,N,32108, +19042,N,N,N,N,N,N,N,N,N,32061,N,27239,24387,20818,20066,N,21284,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,32043,N,24416,N,N,N,N,N,N,N,N,N,N,N,N,29255,N,N, +N,N,N,26480,N,20590,N,N,29482,N,N,N,24139,30264,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,24949,28979,30499,N,N,18985,N,N,N,N,N,N,N,N,N,N,20261,N,N, +24388,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24880,N,N,28735,N,30244,N, +25398,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31302,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20591,N,N,32109,N,N,N,N,N,N,N,N,23876,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,31863,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,26175,N,N,N,N,N,N,24109,N,31295,N,N,N,N,N,25969,N,N,N,N,N,N,N, +27972,N,N,N,N,N,N,N,N,N,N,N,N,N,21029,N,N,32110,N,N,N,30006,N,N,N,N,N,N,N,N, +24950,24140,N,N,31838,N,27735,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19805,N,N,N,N,N,N, +N,N,22071,19763,30805,25944,N,N,N,20330,N,N,20304,N,27212,N,N,N,N,27182,27181, +N,N,21361,N,21285,N,N,N,N,N,N,30543,N,N,N,N,N,N,N,N,28196,N,N,N,N,20516,N,N, +29218,N,N,N,N,N,N,N,N,N,N,20592,N,N,N,N,29219,N,30584,N,N,N,N,20531,N,N,23337, +N,N,21307,19052,N,28966,19285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30567,N,N,19806,N, +30500,N,N,N,30784,N,N,N,21341,N,19536,N,N,N,N,20262,N,N,N,N,N,N,30323,N,N,N,N, +N,24951,N,N,N,N,N,21340,N,N,31358,N,N,N,N,N,N,N,31271,N,N,N,N,N,N,N,N,N,N,N,N, +27481,N,20263,27183,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,25711,N,N,N,26937,29016,N,N,22616,N,N,24690,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,26164,23676,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29553,N,N,N,25424,N,N,29307,N, +23366,20593,N,20594,20316,N,21329,N,N,19505,30552,N,19240,27452,25662,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29788,N,N,23618,N,N,28711,N,N,26176,N,N,19053,N, +N,N,N,26731,25960,23619,N,N,27998,21362,N,N,N,N,19575,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,20052,26411,N,N,N,19267,N,24881,N,N,30514,N,N,21363,21330,N,30016,N,N,N, +24413,N,N,28275,26481,N,32052,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29256,N,N,N, +29522,N,N,28276,N,25171,N,N,N,N,19537,N,24426,N,N,N,26938,N,N,N,N,N,N,N,N,N, +22871,N,N,N,N,N,N,N,N,30029,N,29042,31303,N,N,N,N,N,N,N,N,22904,21570,N,N,N,N, +30309,N,N,N,N,23877,N,N,N,N,N,N,26482,27999,N,N,19019,N,N,23418,N,N,N,26677,N, +21286,N,N,N,N,N,N,32053,N,N,31049,N,25698,N,31549,N,N,22308,20037,N,N,N,N, +20053,22118,N,N,N,N,25917,N,N,N,N,N,N,24141,27763,N,N,28000,N,N,N,N,N,N,N,N,N, +27756,31550,24427,N,24952,31038,N,N,N,N,20595,24618,26722,N,N,25172,21117,N, +25896,N,N,N,N,N,22867,N,N,N,N,21342,N,29752,30524,23677,N,26732,25703,N,N, +25463,N,N,N,N,N,27688,N,N,N,N,N,N,31345,N,N,N,N,N,25970,N,N,20596,21039,23653, +N,N,N,N,20517,28980,31793,19576,N,N,23878,31313,N,30559,N,N,31272,N,N,N,N,N, +28277,N,24142,N,N,N,N,26483,N,N,30508,27460,28001,24619,23879,N,N,N,N,21043, +21055,N,N,N,19020,N,N,N,N,31551,N,N,N,N,25981,23909,22605,N,N,N,N,N,27764,N,N, +N,N,N,N,N,N,20597,N,N,26733,20562,N,22872,N,N,N,N,N,N,N,N,N,N,N,30310,N,N, +23338,N,N,N,30560,N,N,N,N,N,N,N,N,N,N,N,N,22617,N,29731,N,N,29789,N,N,N,N, +28497,N,N,22837,N,N,27947,N,25399,N,N,N,N,28219,19764,N,24691,27213,N,N,N,N, +27765,26734,N,19241,28975,N,N,N,N,N,N,N,N,19021,N,27689,N,29291,N,32111,N, +31091,N,N,N,N,N,N,N,N,N,26177,N,N,27736,N,N,N,27948,27214,N,26719,N,N,N,N,N,N, +N,N,N,N,N,N,N,24143,N,N,N,N,N,N,21030,N,N,26484,20822,N,N,26178,25443,N,N,N,N, +25648,N,N,N,22580,N,N,N,N,N,N,N,N,N,N,N,N,30245,N,N,N,N,N,29534,N,N,N,N,22309, +N,N,N,N,30568,N,N,26694,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31590,N,N,N,N,N,N,N, +23910,N,N,N,23678,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,22618,N,N,N,N,N,N,N,23084,27184,N,N,N,N,N,N,N,N, +25400,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,18986,24953,N, +27185,N,N,N,N,29292,N,N,31342,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28245,N, +N,N,N,31092,N,N,21100,31611,N,N,N,32112,N,24637,20067,N,N,N,N,N,N,N,N,N,30790, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24110,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,24389,N,N,25918,N,N,N,N,N,N,N,N,N,N,N,N,27949,31338,N,N,19822,27942,N, +27950,28781,N,23841,N,27951,31864,N,22635,N,N,N,19577,19765,N,N,N,N,31273,N, +24925,N,N,N,N,25173,27983,N,N,N,23842,N,N,31050,N,27240,N,25965,N,N,N,N,N,N,N, +N,21355,N,26964,24954,25676,N,24932,26695,N,N,20059,N,N,N,23637,N,30517,31859, +28787,20015,28981,28498,26696,27505,N,N,N,N,N,19284,24638,25464,27241,31794,N, +N,N,N,N,24692,N,20320,N,28197,N,N,31274,26179,24882,18987,N,25444,26939,N,N,N, +N,N,25174,29554,N,28246,27186,20598,27737,23115,20264,N,N,N,N,23843,N,N,N, +22619,N,31054,26965,25425,N,N,21052,N,N,N,N,N,N,22572,29516,N,19835,30294,N, +26485,26735,25465,21051,29555,25467,N,24144,20016,N,22135,29017,N,N,N,N,N, +30017,23620,N,30011,N,24145,23654,N,N,24146,N,N,28002,28278,27215,28782,25468, +N,21343,21364,24883,N,24884,N,N,N,N,29779,N,N,24390,N,N,N,N,N,N,N,N,N,N,26966, +N,N,N,23339,N,N,N,N,N,N,N,N,30246,N,N,N,N,N,N,25401,27461,29737,19766,21113,N, +23085,21091,20305,N,N,N,N,19292,19578,N,20317,N,N,26665,N,25403,25402,N,N, +24666,N,N,N,28279,N,N,N,N,N,23603,N,N,N,N,21365,N,22310,N,30261,22363,N,N,N,N, +N,N,24917,N,N,21610,N,24355,N,N,N,N,N,N,N,32095,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,20599,27988,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19242,N,N,N,N,N,N,N, +25691,N,24955,19234,N,N,N,N,21344,N,25663,N,31552,N,23102,25677,N,22073,N,N,N, +28480,N,24956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30265,N,N,N,N,N, +N,24391,N,N,N,N,N,N,N,25649,N,N,N,N,N,N,23655,23656,N,N,N,31318,N,21366,N,N,N, +N,29018,N,31346,25213,N,N,N,N,N,21839,20600,N,N,19807,N,N,30027,N,25712,19243, +N,22340,N,N,N,N,N,N,N,N,N,N,N,N,N,25214,N,23898,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23086,19054,N,N,N,21817,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25377,N,N,26723,N,N,29483,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,20265,N,N,N,21367,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +21617,N,N,20068,N,26738,N,N,N,N,N,N,N,25973,N,N,N,N,N,N,N,N,N,N,N,N,N,26414,N, +22074,N,24428,25664,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26724,N,N,N,N,22581,N,N,N, +25692,N,N,N,N,N,N,29753,28982,N,N,25182,24885,N,N,19823,28967,20069,19293,N,N, +22883,N,N,29484,N,N,20601,27691,24147,30569,N,N,31093,N,N,N,N,N,24926,19310, +25404,30806,N,N,23406,N,N,N,N,N,32113,N,N,N,N,30518,N,N,N,N,29790,N,N,29293,N, +23385,N,28712,N,N,N,N,N,N,N,24957,N,N,N,N,N,24148,N,24620,N,N,N,N,N,28003,N,N, +21345,N,24392,N,N,N,N,22838,N,32044,28499,N,N,N,25665,30827,N,23340,N,N,N,N, +31814,N,N,N,N,N,N,N,N,22573,N,N,N,N,N,N,N,N,N,30266,N,23391,21331,30791,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,19022,30785,21044,N,N,23604,31289,19023,N,31795,27242, +27243,20602,N,N,N,N,N,28004,N,N,23911,N,N,24393,N,N,N,N,24429,N,N,N,N,N,28220, +N,28481,N,N,19538,N,23844,N,N,N,24394,N,N,N,N,N,21368,28968,N,N,N,19767,N, +28500,N,N,N,N,N,N,N,25693,24430,19244,26940,N,N,N,N,N,27244,N,N,N,24395,N,N,N, +N,N,31039,22063,21830,N,N,N,N,N,20266,N,N,20009,N,N,22136,N,N,N,28983,28280,N, +N,N,22873,29535,N,30792,20038,N,N,N,N,N,N,N,N,21862,N,N,N,N,N,N,29798,N,N, +26181,28501,N,N,19311,31839,23591,N,N,22119,N,N,N,N,N,30793,N,N,N,N,25426,N, +25405,N,20321,28736,27738,N,23895,31600,N,N,27692,N,N,N,28713,N,N,N,N,N,N, +31319,31553,N,21056,N,N,N,N,N,N,N,25904,N,N,N,28005,N,N,N,N,19245,N,31024,N,N, +N,N,N,N,N,N,N,N,N,30501,N,19246,N,23087,N,22582,N,N,N,N,N,N,N,21287,31538,N, +32068,N,27693,N,N,N,N,N,N,31521,N,N,N,25961,26990,N,29556,30835,28737,24111, +30768,N,N,29536,26415,N,N,N,N,N,23341,N,26165,N,N,31016,N,N,23896,26713,28502, +N,N,N,21346,N,25183,N,N,31840,22344,32045,N,N,N,24431,19539,21369,N,N,N,N, +21616,23367,24149,N,N,N,N,28788,N,21840,25945,N,N,N,N,N,N,31815,23638,25184,N, +N,N,23088,N,N,N,N,N,N,29475,N,21356,N,29771,N,N,N,32069,N,N,N,N,N,25469,N, +31025,N,N,N,N,N,N,20603,27739,N,N,N,N,N,N,N,N,30012,29220,22606,22607,N,N,N,N, +N,N,30071,N,N,N,N,N,N,N,N,N,N,30305,N,N,N,N,N,N,N,N,N,21047,N,N,N,N,N,N,N, +31596,N,23880,25704,N,N,21057,N,N,N,30807,N,N,N,N,N,22075,24150,N,N,30525, +27694,N,N,N,20577,N,24693,27187,N,20054,N,N,N,N,19493,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,27766,25185,25406,N,N,N,N,N,N,N,N,N,31816,N,N,19824,N,31094,N,N, +24432,N,N,N,25919,N,N,N,20031,N,N,N,N,31841,27952,32081,30267,N,N,31055,27482, +19009,N,21048,19825,N,25427,32102,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +26221,N,N,N,25466,N,N,28714,31056,N,N,N,N,N,N,31842,N,30759,N,N,N,24933,28281, +N,N,N,26486,27245,N,N,31796,30018,N,N,22364,N,N,N,N,N,N,N,N,28789,N,23912, +21357,30076,N,23103,N,19579,N,N,N,21370,29732,N,N,N,N,N,N,N,28503,N,21571,N,N, +N,N,N,N,N,N,N,31587,N,N,N,N,N,N,N,N,31597,N,24621,N,N,27246,31539,25666,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,30311,21085,N,24396,N,N,31817,N,N,25897,24694,30259, +24958,N,N,N,N,19312,N,27247,27248,N,N,N,23104,30772,27506,N,N,N,N,N,25667,N,N, +N,N,26967,25713,N,N,N,19055,N,N,N,N,N,N,N,20055,N,N,N,N,N,N,N,N,31818,N,N,N, +29537,N,N,19268,N,N,N,N,25445,N,19269,27188,N,N,26941,N,22345,N,N,27483,27953, +N,19523,30526,31819,N,N,N,N,N,N,30836,N,22839,N,N,29523,29524,N,N,N,30564,N, +30545,N,N,22583,20017,19010,N,N,31540,19270,N,N,28790,N,N,21863,N,27216,N,N,N, +N,N,19540,19247,N,N,N,N,N,29738,26927,N,N,30019,26968,N,N,N,N,N,N,N,23913,N,N, +N,29043,N,21883,24123,N,N,29819,N,N,N,32115,32114,30502,N,N,N,N,N,N,N,N,N, +23881,N,N,21587,N,19496,N,23105,19541,N,22884,N,N,N,31306,N,N,N,25955,N,N,N, +21308,N,N,N,19056,N,N,N,N,20548,N,N,N,19024,31275,27499,26488,22885,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20823,N,N,N,N,N,N,N,N,N,N,N,29476,N, +N,N,21627,31843,31320,N,29525,N,20267,N,N,27507,21884,N,N,N,N,N,N,21332,19836, +N,22886,N,25209,25121,27476,N,24695,25650,19580,N,N,N,31588,N,N,N,29739,N,N,N, +N,20541,N,19057,N,N,N,N,N,N,N,N,28472,N,N,N,22336,N,28282,32116,N,N,21347,N, +31554,N,N,N,N,N,N,N,21864,23342,24886,30775,N,N,N,N,N,24639,31555,23914,N, +25122,N,28198,N,N,N,N,N,30312,N,N,N,N,30325,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,23882,N,N,20578,N,N,N,N,23846,N,N,23915,N,N,25721,N,N,25391,20604,N,N, +N,29820,N,N,N,N,19516,30570,N,N,N,N,N,N,25956,24433,N,N,30561,N,31095,28473,N, +N,30808,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31017,N,N,N,N,N,30809,N,N,N,28221,N,N,N, +22598,N,N,25699,30030,N,N,N,N,23897,N,N,N,N,22887,21049,21827,N,N,23141,23120, +N,20825,20056,N,19294,29740,23163,N,30313,26739,20268,28784,N,29821,23368,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,20032,25428,20815,29045,N,19826,N,20331,N,N,N,19768, +N,N,N,N,N,N,25382,20826,29221,N,N,N,N,N,29222,N,25678,N,N,N,N,N,N,N,21371,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28969,N,N,N,29257,N,N,N,N,N,N,N, +N,N,N,28504,26185,N,22584,31347,N,N,N,N,N,N,N,N,N,N,29493,N,N,30756,N,N,20851, +26184,N,N,N,N,30810,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23657,24151,N,N,N,N,N, +19295,N,N,N,20332,N,N,N,N,29791,N,N,20852,21050,N,N,N,24434,N,N,N,24887,N,N,N, +N,25123,21372,N,N,28006,N,N,N,N,N,23369,N,N,N,25722,N,20318,N,N,20048,N,N,N,N, +21843,29557,30510,N,N,28488,N,19827,30031,25971,28738,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,19025,N,N,N,27249,N,20518,N,N,N,N,N,N,N,N,22874,28715,N,N,N, +N,N,27495,N,N,N,25920,31797,N,N,N,N,N,25668,N,N,N,N,N,N,N,N,N,N,N,19497,32070, +N,N,N,N,N,27189,N,25898,24378,24927,N,23121,N,N,N,N,24888,N,26740,21373,N,N,N, +N,25124,N,N,N,N,N,29258,N,N,N,N,N,N,N,N,N,23142,30515,N,N,N,N,N,N,N,N,N,N,N,N, +32077,N,N,N,29494,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28247,N,N, +N,N,N,N,N,30020,N,N,N,N,N,N,N,N,22564,N,N,N,N,N,29223,N,N,N,N,N,N,N,N,22840, +22841,28489,N,N,N,N,N,N,N,N,N,N,N,N,N,22094,N,N,N,N,N,N,N,N,30539,24366,26741, +N,N,N,N,N,N,21045,N,N,N,21333,N,N,N,N,N,29772,23164,N,N,N,N,N,22888,N,30571, +30025,N,29500,N,23122,N,N,N,N,N,N,N,N,21301,N,N,N,N,N,26678,N,N,22095,29754,N, +30537,N,N,19498,N,N,28739,19542,N,N,N,20563,N,21309,N,N,N,23419,N,19296,N,N,N, +N,N,N,21348,30327,N,N,21818,29517,19297,N,N,N,N,27508,N,N,N,N,N,29741,N,31786, +N,N,N,N,N,30572,N,N,N,26742,23143,N,N,N,30540,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,25921,N,N,N,N,24686,N,N,N,N,N,21885,N,N,N,N,N,N,20070,31787,21819,N,N, +29224,N,N,N,N,N,N,25125,19769,27250,19271,N,19828,N,N,23343,28505,N,N,N,N,N, +19770,N,N,31865,N,N,N,N,24435,20071,23106,N,20269,N,N,N,N,26489,30760,N,N,N,N, +N,N,29538,N,N,N,19058,24356,N,N,21572,N,N,N,N,N,19543,25922,N,N,N,N,19771,N, +28506,28248,N,23847,25126,N,N,N,N,N,24640,N,N,N,22064,30794,N,31866,N,22910,N, +N,N,N,24112,N,N,N,23916,23144,N,N,N,N,N,21600,N,22137,N,19799,24152,N,N,29304, +N,25686,N,N,20549,29742,N,23848,N,N,N,27973,29526,N,N,24153,25446,N,N,N,N,N,N, +21288,N,23344,N,N,25946,25407,N,N,N,23345,N,N,N,21865,N,N,N,N,N,24641,28507,N, +N,28777,N,N,22322,N,N,N,N,20605,N,N,N,N,N,N,N,N,22889,N,N,20606,N,27757,21289, +N,29225,28740,N,N,25186,26991,N,N,N,31057,N,N,26969,N,N,N,N,N,26714,23107, +23108,21573,N,26490,19808,25392,N,23346,31556,N,29539,N,22821,31591,23883, +20564,N,26166,24622,32090,N,N,N,N,N,N,N,N,23605,24696,26417,N,N,N,N,30064,N, +22620,27974,N,N,N,N,24889,N,25408,31040,26992,N,N,22875,N,29540,N,N,N,23606, +25705,N,N,N,N,N,28741,25409,31820,31821,N,N,N,N,29259,N,29260,N,N,N,25679,N,N, +N,N,N,N,N,N,N,29019,N,31321,N,28984,32117,24697,N,N,N,N,26491,31799,31844, +31557,25447,22585,N,30328,N,N,23621,19544,N,N,N,24623,29799,N,28508,20348, +28509,N,29226,N,N,N,N,N,N,N,N,N,32062,N,N,18988,32059,32071,N,N,N,N,26418,N, +27217,24436,N,N,N,N,20844,25694,25923,N,N,N,N,22822,N,N,19772,N,29541,N,N,N,N, +N,N,N,N,27989,N,N,22842,N,N,N,28007,31541,30828,N,N,N,N,24679,N,19545,N,N, +21574,N,N,N,N,N,26405,N,21877,21310,N,31867,N,N,N,N,N,N,N,N,N,N,N,N,25714,N,N, +24437,N,N,26744,30829,N,N,20039,N,N,N,N,N,32118,N,N,N,N,N,N,N,N,N,26712,N, +19800,26454,19546,N,N,19043,24438,28743,28742,N,22586,N,29044,29808,30028,N,N, +31845,N,N,N,N,27205,27251,N,23899,N,23639,N,N,N,N,N,N,24189,29305,N,21831,N,N, +N,22608,N,28744,20769,20770,N,N,N,N,N,N,22868,22120,22858,N,23089,22599,23650, +29518,30068,N,N,28985,N,N,23123,N,30314,N,N,N,20341,N,N,32046,N,N,N,N,N,N,N,N, +19026,N,N,24372,N,N,N,N,22365,31290,28199,30013,N,30837,N,N,28008,N,N,N,N,N, +21601,N,20771,24918,N,N,N,N,N,N,N,N,N,N,N,N,N,31096,N,23370,19321,21588,N, +22876,N,28222,N,30573,N,N,N,21102,N,N,24934,30585,N,N,N,N,N,N,N,23917,N,26715, +N,23347,N,N,N,20855,24624,N,N,21602,N,30295,N,22393,N,N,22621,N,19837,29227,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19773,30786,N,N,29228,N,N,18989,18990,20270,N, +N,N,N,N,25410,N,N,N,N,N,23607,N,N,N,N,N,N,N,N,N,N,23386,22843,19059,30291, +26232,27253,N,N,N,N,N,27254,N,N,30329,N,N,N,N,N,N,N,N,N,N,N,20271,N,N,19027,N, +N,18991,21040,28986,N,22323,25411,29565,24154,N,N,N,N,24155,N,N,28510,25187, +28283,N,N,24439,22346,N,N,N,N,N,N,N,N,N,20072,23387,N,N,N,N,N,N,N,28987,N,N,N, +N,26993,N,N,N,N,N,N,N,N,31287,20550,N,N,19499,28200,N,N,19322,31097,19581, +21374,N,N,N,N,25680,N,N,N,N,N,29294,N,21589,24397,N,31800,20816,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29261,N,N,N,N,N,N,N,N,30546,N,N,N,N,N,N,N,N, +19028,N,21849,N,N,N,22622,N,N,N,N,N,N,N,N,N,19801,N,N,N,28201,30268,N,N,19547, +N,N,N,N,N,28745,N,31868,N,26697,29822,N,N,N,N,26492,22366,N,N,N,N,24156,N, +28716,19582,19809,N,24890,N,23407,23090,N,N,N,N,N,N,N,N,N,N,N,N,N,20773,23608, +N,N,N,22646,N,20772,N,19810,N,N,N,N,23658,N,N,28791,N,28746,20542,N,23900,N,N, +N,N,21590,21334,N,N,N,N,N,N,27984,19745,N,N,N,N,N,24373,N,N,N,24440,N,N,N,N,N, +N,21537,20018,26698,N,N,N,N,27509,N,N,N,N,N,N,N,25429,30032,N,N,N,29985,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22823,N,N,N,N,N,N,N,N,25899,N,N,N,N,N,N,N,N, +N,N,N,N,26187,N,30065,N,N,N,N,N,N,N,N,N,N,25925,N,N,N,N,N,N,N,N,31011,24667, +30315,N,19313,N,22890,29986,N,N,N,22353,N,20856,27256,27257,23091,N,N,N,N, +28511,N,N,29039,N,25974,28223,25188,N,N,N,N,N,20543,N,31276,30033,26419,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26942,N,N,N,N,N,29262,23348,N, +N,N,N,N,N,N,N,31822,N,23918,N,N,N,N,N,N,26420,N,N,N,N,N,22324,N,N,N,N,N,N, +30516,N,N,N,N,N,19774,N,23145,N,N,N,N,N,N,N,20272,30553,29542,N,N,20057,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20010,N,19272,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,20519,N,28747,N,20551,25669,N,N,N,N,N,N,N,23392,N,N,N,N,N,N,21850,N, +22311,N,N,N,28224,N,30838,N,N,N,N,30034,28009,N,22844,N,25926,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,29987,N,N,23124,25127,31612,N,N,29020,N,N,N,N,N,N,19060,N,N, +N,26746,N,N,20073,N,N,N,N,N,N,27000,25189,N,N,N,N,20537,21618,N,N,N,N,N,20774, +N,24398,N,N,N,N,N,N,N,N,N,31860,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21290, +N,N,N,19500,N,N,N,N,28512,N,N,N,25957,20565,N,N,N,N,N,N,N,N,23420,N,N,N,N, +31846,N,N,N,N,N,19326,28010,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24113,N,N,N,N,N,N,N, +31075,N,N,N,N,N,N,21538,20342,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22096,N,N,N,N,N,N, +21866,29038,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31307,N,N,N,N, +25889,21809,N,N,N,N,N,20333,N,28011,N,N,N,N,N,21810,N,N,N,21820,N,N,N,N,N,N,N, +N,N,32098,29485,N,32091,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26928,N,N,N,N,N,N,N,20775, +N,N,32099,20019,N,N,N,N,N,N,N,32100,31310,N,N,N,N,18992,N,30503,N,20273,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,26146,N,31798,29229,28513,29486,23622,22891,N,N,N,26720, +N,N,N,N,N,N,N,24872,N,N,N,N,21878,20349,N,N,24157,N,N,N,22865,N,N,N,25706, +29263,N,30527,N,N,25190,25128,N,N,N,N,N,N,N,N,N,N,N,25430,N,27985,N,N,N,N,N, +27001,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22065,24114,N,N,24680,N,N,21291,N,27484,N, +N,24367,N,19011,N,N,28284,N,32067,N,N,N,27510,20274,N,N,N,N,22892,N,22845,N, +22623,N,N,21560,27454,23919,N,23920,23921,23922,N,N,22846,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,31558,20275,28285,N,N,N,N,N,N,25643,N,23109,N,22636,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,20776,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25129,N,N,24124,26421,N,N, +N,N,N,23408,N,28514,29040,20276,N,N,N,N,N,N,N,N,N,N,N,23409,N,24625,N,N,N,N, +24357,N,31058,N,N,26493,N,N,26147,31601,19248,29230,N,N,N,N,N,N,N,19815,N, +26716,N,N,26455,N,N,30528,N,20579,N,N,N,23073,N,N,N,19517,N,N,20777,23884,N,N, +25470,20778,26666,N,27190,31098,26188,30296,N,N,N,21575,N,N,N,22859,N,22866, +21323,22647,23081,30072,N,N,24158,29231,30761,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +22600,N,N,28225,N,N,N,N,31041,N,N,N,N,23923,27258,N,30269,24891,19775,29780, +26189,N,31823,31522,N,24668,N,N,N,N,29755,23125,N,31026,N,N,N,N,N,N,31602,N, +23414,N,24159,N,N,N,23410,N,N,N,N,N,30812,30574,27496,N,21114,N,N,28988,N,N, +31322,N,N,23146,23110,30529,N,N,26422,25927,22060,N,N,N,N,23623,N,N,N,N,N, +24873,N,25130,N,21798,N,N,21591,N,N,N,N,N,N,29264,N,27259,N,24669,31603,N,N,N, +N,N,N,N,28989,N,N,25191,32087,N,20040,27191,N,31808,N,32103,30575,N,N,22325,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28474,29021,N,24115,N,N,N,N,N,N, +26699,N,N,30813,N,N,31559,21832,N,22367,N,23849,N,N,N,N,N,26929,N,N,31277, +30297,31348,N,N,N,N,N,30762,N,N,N,N,N,26222,N,19548,24892,24687,N,N,26943, +31869,26190,N,N,24919,N,26191,N,29809,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,25715,N,N,25723,N,N,31076,N,N,N,N,N,N,N,N,N,N,28515,N,N,20334,30270, +24626,31870,20779,N,N,N,22394,N,N,N,31560,N,25175,N,N,N,N,N,N,21539,28792, +22312,N,N,N,24935,N,N,21311,N,N,N,N,N,N,28516,N,22341,27490,N,N,31847,N,N, +25634,N,25192,N,26192,N,31592,29800,25972,29756,29781,24374,N,31801,28226, +19061,N,N,N,28517,19298,21540,N,24160,23165,25670,26686,N,N,N,N,24670,30260, +27218,N,31099,N,N,24642,N,19044,N,26423,N,27261,N,22877,N,23092,28202,31593,N, +N,N,N,23371,23093,N,N,N,N,N,28990,N,N,21292,N,N,N,N,N,N,N,N,31561,N,24399,N,N, +21312,25431,N,28518,31824,N,N,N,N,N,N,N,26944,N,N,N,30035,N,N,27740,30519,N,N, +27192,20857,N,N,N,N,N,N,23624,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27193, +N,N,N,N,N,29022,N,N,N,N,N,22326,20277,N,22824,N,N,27758,N,N,23850,N,N,N,N, +19746,26670,N,N,N,24893,N,29265,N,N,N,N,26945,N,N,N,21116,N,N,N,N,N,N,N,23349, +N,29543,22654,N,N,N,31825,N,27954,29743,N,31523,N,N,31809,N,28203,21541,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29810,N,N,N,N,28249,N,N,N,31562, +N,N,N,N,N,19811,22587,25947,30839,N,N,N,30292,N,N,N,N,N,N,N,N,22313,N,19273,N, +N,26193,28748,N,N,N,N,N,N,N,N,N,N,22574,N,31059,21886,N,N,N,N,N,N,N,22588, +29232,N,N,N,N,25131,29544,N,N,N,N,N,28482,N,N,N,N,N,N,28012,N,26424,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,23166,N,N,19518,N,N,29308,23147,N,25176,27990,N,N,22097, +24627,N,N,31826,N,27464,N,N,N,N,N,N,N,N,21313,28749,N,20343,N,N,N,N,N,N,N,N,N, +27986,N,21592,23625,22385,N,N,24379,N,N,29477,N,N,N,29773,N,N,N,N,28991,30769, +N,27002,N,N,N,31563,N,N,19029,N,N,N,N,N,N,N,N,N,N,N,31060,30538,N,N,22088,N,N, +N,N,N,N,31848,29501,N,28286,N,26494,N,N,N,N,N,21314,N,N,N,N,21302,N,19501, +30330,22066,21080,N,N,N,N,N,N,26456,N,N,N,N,N,N,N,N,N,N,25381,N,N,N,N,26425,N, +N,N,N,28717,31564,27425,N,N,21542,N,N,N,N,31565,N,21821,29023,N,N,30331,N, +24116,N,N,N,N,N,N,N,N,N,N,N,N,21867,25928,N,N,N,31524,21561,N,N,24161,N,25635, +N,N,N,22327,N,30830,N,N,N,24117,N,N,22098,N,31061,26426,27477,21879,28519, +24894,N,N,N,31278,N,N,N,22121,22126,N,N,N,N,N,N,26427,N,N,N,N,N,N,N,27723,N,N, +N,N,N,N,21811,N,N,N,N,N,N,N,N,N,N,N,N,N,20020,N,N,N,31525,24942,N,N,N,N,N,N, +30504,N,N,N,N,31566,N,N,N,N,N,22589,N,N,N,N,N,N,N,31613,N,N,N,N,31849,N,N,N,N, +N,N,N,20278,N,N,N,27975,28204,N,N,N,N,N,N,N,19549,N,N,N,N,30247,N,N,N,26234,N, +N,N,29988,N,N,N,N,N,32092,27955,20041,N,N,N,N,N,N,28520,N,N,24895,N,N,N,N,N,N, +31323,19299,30505,N,31526,N,N,N,23609,N,N,N,28992,27976,28483,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,22061,N,N,32078,N,N,N,26657,N,N,N,N,N,N,N,N,31604,21799,N,N,N, +29046,N,26195,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19550,N,N,N,N,N,N,N,30770,N,N, +N,23659,32054,N,N,N,N,25962,N,N,29024,N,N,N,N,N,N,N,N,N,N,N,N,23372,23885,N,N, +N,21576,N,N,22893,N,N,N,N,29989,N,N,N,N,N,N,N,N,N,26235,N,N,N,N,N,26196,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,32072,N,22049,32063,N,31827,N,28449,N,26428,N,N,N,N, +N,20846,N,N,26197,N,N,26994,N,24368,N,N,N,N,N,22624,31802,32047,28750,N,23393, +N,N,25929,N,27956,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24643,N,N,N,N,N,N,25432,N,N,N,N, +27003,27176,N,N,N,N,32055,N,N,31527,N,26946,N,N,N,N,32119,N,N,N,N,N,25177,N,N, +23660,N,N,N,N,N,N,N,N,N,26658,N,N,N,N,26224,N,N,N,N,N,N,N,32120,32121,N,N,N, +30271,N,N,26407,N,26199,N,N,N,N,21619,21577,N,N,N,N,22138,N,22386,N,24896,N, +23394,26200,N,N,N,N,N,N,N,N,N,26429,N,N,N,N,N,28751,29502,25132,N,N,N,N,N, +30007,24688,N,N,N,N,N,N,N,N,N,N,N,N,32056,25448,N,21543,26748,31314,N,N,N,N,N, +30831,N,N,N,N,N,N,N,N,N,22099,N,N,N,N,N,N,N,N,N,N,21812,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,28752,N,30576,28211,N,N,27194,N,27219,N,N,27977,23851,N,N,N,25900,32033, +N,24400,27699,N,24401,N,N,N,N,N,28013,30776,30586,N,N,N,30763,N,N,N,N,N,29792, +N,N,N,N,N,21562,25651,N,26970,N,24118,N,22847,N,22848,22127,N,N,N,N,22860,N, +23082,N,N,N,N,N,N,N,N,24421,N,N,N,N,N,N,30565,N,N,N,19506,N,N,24441,22368,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21563,N,N,N,N, +32122,N,N,N,N,19507,N,N,23411,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24402,N,20042,N, +28250,N,N,N,N,N,N,N,N,N,25700,N,31567,N,N,N,N,N,N,20279,N,28227,N,N,N,N,N,N,N, +20074,N,N,N,N,N,N,N,25133,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22369,31349,N,N,21833, +30764,26457,N,N,N,N,N,N,N,N,N,N,N,29545,N,N,N,N,22637,25412,28785,N,N,N,N,N,N, +N,26725,N,N,N,24698,28228,22878,N,N,N,N,N,N,N,N,N,N,27426,27427,N,N,N,N,N,N, +31810,27195,N,N,N,N,26667,24162,N,N,N,N,N,N,N,N,N,N,28015,N,26659,N,N,N,N, +20337,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21564,N,31850,N,N,N,N,N,26430,N,31858,N, +N,22068,N,N,25134,N,21303,31308,N,N,N,N,N,N,N,N,31324,N,27957,24931,N,26668,N, +26717,N,N,28521,N,N,N,N,N,29757,N,20280,26971,20780,N,N,N,N,N,N,23111,N,N,N,N, +N,N,N,27465,N,26700,N,N,N,24119,N,N,N,N,22076,21349,N,N,N,N,N,31325,N,N,N,N,N, +N,23126,N,18993,N,N,N,N,N,N,23112,24358,N,31027,29266,N,19012,N,N,N,N,N,N, +20043,N,N,19829,N,N,N,32048,21800,N,28993,N,N,25193,23626,27700,31296,N,N, +31528,20520,N,N,23148,N,N,N,N,N,N,N,N,N,22894,N,24699,N,N,N,28522,31326,24644, +N,20281,N,21834,22370,25135,N,22328,N,N,N,N,N,N,N,N,N,26701,N,N,N,N,N,N,N, +30298,N,N,N,N,28450,25178,30332,N,N,31568,20781,N,19812,N,20782,23661,26702,N, +28793,20021,26236,N,N,22395,20566,23925,30577,N,30333,N,23415,N,N,N,N,31594, +26972,22849,N,30066,24645,N,N,N,N,N,N,27220,N,N,N,N,N,N,N,N,N,31042,N,27196,N, +21061,31569,26432,27429,N,24442,25378,22329,N,26947,N,26749,26671,N,N,29267, +31529,22565,N,N,N,N,21835,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20552,N,N,N,20783,22371, +N,N,N,24646,N,22050,N,28016,N,N,N,N,N,N,N,N,N,N,N,N,22387,N,N,N,31828,N,23127, +19551,N,29268,N,20784,N,19552,N,23421,29503,N,28753,N,N,N,N,N,31803,N,25136,N, +N,26149,N,N,N,25179,N,N,N,24414,N,24647,N,N,N,N,N,N,29295,N,N,N,19553,N,N,N,N, +22122,N,N,N,N,26434,N,N,N,20022,N,29504,N,19838,N,N,N,31570,N,30840,30587,N,N, +26687,N,N,N,N,N,N,N,26679,N,N,N,N,N,N,N,N,27958,23610,N,N,19508,N,N,N,N,N,N,N, +N,N,N,N,N,29047,N,N,N,26680,N,N,19062,N,25636,29782,N,N,N,24422,N,N,N,24359,N, +24423,24897,N,26948,N,N,23627,26949,N,N,N,28451,27430,19235,25449,N,N,N,20859, +28452,N,28523,N,N,N,N,N,N,N,N,N,N,N,N,20532,N,N,N,N,19747,N,N,26726,N,28453,N, +21324,23149,N,N,N,N,22330,N,29269,30053,22895,N,N,N,N,31028,N,N,21844,32079,N, +N,N,23395,N,N,N,N,29025,27702,N,N,N,N,31614,21335,N,20785,N,19249,N,N,N,N, +20786,N,N,N,N,N,N,19250,28994,N,N,29793,31029,N,N,24899,24898,N,27511,N,N,N,N, +N,N,N,N,N,N,N,24360,N,N,N,N,N,N,N,19274,N,N,N,N,N,26169,N,N,N,N,N,30814,31018, +19063,N,27959,N,N,21304,29270,N,N,21593,28229,29296,N,N,N,18994,N,N,23611,N, +29048,N,N,N,N,N,27703,N,N,N,N,25930,N,30272,32093,N,N,21603,19554,N,30548,N,N, +N,N,N,N,22373,N,N,N,N,N,N,N,N,N,N,N,N,N,21315,N,22566,N,30273,N,N,N,N,N,23926, +N,19776,25948,N,N,N,N,N,N,N,N,N,N,N,N,25931,N,N,N,N,N,N,N,N,N,N,N,24900,N,N,N, +N,N,26672,29744,29546,23150,N,22331,N,25137,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,22314,N,N,N,N,N,N,22139,N,N,N,N,N,N,N,N,N,25695,N,19030,N,N,N,27432,N,N, +N,23422,N,N,N,N,N,N,N,N,N,N,30274,N,N,28475,N,N,N,N,21629,N,N,24648,N,N,N, +26681,N,28454,N,N,N,N,N,19748,N,N,21620,23329,23388,23389,N,N,N,N,N,28252,N, +19275,31829,N,N,N,N,N,N,20075,N,19777,N,N,31571,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,31019,N,N,N,N,N,N,N,N,N,N,N,30036,N,N,N,N,22825,N,N, +26973,23373,N,N,23886,N,26435,N,27724,N,N,N,N,N,N,N,31084,N,N,N,19276,N,N,N,N, +24700,21544,N,27987,22639,N,29271,N,19064,23151,N,N,22100,N,N,N,N,N,N,22861,N, +N,N,22638,N,29249,N,N,N,24403,N,N,N,23152,N,25194,24701,N,N,22648,N,N,N,30511, +23094,N,19031,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29272,N,22649,N,N,N,N,N,N,N, +N,31327,N,N,N,N,N,N,N,N,N,N,N,N,N,20335,22850,N,28754,N,25681,N,N,N,29495,N,N, +N,N,N,N,N,N,N,N,N,N,31328,N,N,N,N,N,N,N,N,N,N,N,N,N,28524,N,N,N,N,N,25138,N, +21565,N,N,22862,N,N,N,N,29794,N,N,N,N,N,N,N,N,N,N,N,N,N,21545,N,N,N,N,19778, +26458,N,N,N,N,N,N,N,N,N,N,N,29273,N,N,N,N,N,22826,N,N,N,N,N,N,N,N,N,N,N,N, +22590,N,N,N,N,N,N,23597,N,N,N,N,N,N,25195,22140,N,N,19065,N,N,21594,N,N,N,N,N, +N,N,29783,19489,N,N,20282,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30008, +N,N,N,22851,20584,N,N,N,N,N,25413,27512,N,29233,N,N,N,20283,N,N,N,21293,26721, +20076,N,N,N,24628,24163,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23927,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,29234,29558,30299,N,N,N,N,22398,N,N,N,N,N,30815,N,30578,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,20521,N,N,N,N,N,N,N,N,N,26202,N,N,N,N,N,N,N,N,N,N, +N,N,N,29990,N,N,N,N,N,N,N,N,N,N,N,N,N,22332,19555,N,N,26203,N,N,N,N,N,N,N,N,N, +N,N,N,23901,N,N,N,N,20787,N,N,N,N,N,28525,N,N,N,N,22110,25716,24943,N,N,23928, +N,N,N,N,N,26703,N,N,N,N,N,N,N,N,N,N,N,19045,N,N,N,23585,N,24629,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,31788,31789,22567,N,N,N,N,27960,N,N,N,23350,N,N,N,N,22128, +29487,N,N,19749,N,23153,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22568,N, +N,N,19556,N,N,20788,N,N,N,N,N,19032,N,N,N,N,N,23154,29991,N,N,N,N,N,N,N,N,N,N, +N,N,29992,N,N,N,N,N,N,N,26150,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21868, +21880,23155,N,N,N,N,N,N,N,N,N,N,N,N,N,25414,N,N,N,24164,N,24165,20789,N,N,N,N, +N,20790,20791,29235,N,N,N,N,N,N,26974,N,N,N,N,N,28755,29236,N,N,28756,19300, +31572,30054,25450,N,24166,N,N,N,N,24404,N,N,30841,N,N,N,N,28718,N,N,N,N,N,N,N, +N,N,N,N,N,20792,N,N,N,N,22111,N,20567,N,N,N,N,N,N,N,N,N,N,N,31777,28526,23640, +N,26975,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25949,32123,N,N,24649,N,N,N, +22089,N,N,21546,N,25932,N,N,N,N,N,26976,N,N,N,20568,31778,21566,25139,24167,N, +N,N,N,N,N,N,23612,21046,30037,N,N,N,N,N,20001,29993,N,N,23929,N,N,23930,N,N,N, +N,N,N,28757,N,N,N,N,30303,N,29274,25707,N,29297,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,27705,32124,N,N,N,N,24874,N,N,19033,N,N,28527,N,29994,N,N,N,N,N,N,27769,N, +N,30765,N,29250,30275,N,22354,N,N,31010,28758,N,N,N,N,N,N,N,N,N,N,N,N,N,28794, +N,N,30304,N,N,N,N,26995,29251,N,N,N,21547,18995,19750,N,19779,19802,N,N,N,N,N, +22863,N,N,30276,N,N,N,28253,26436,N,N,N,N,N,N,N,N,25140,N,N,N,N,N,N,N,N,N, +24418,26459,N,N,N,N,N,N,26673,N,31790,N,N,N,N,25933,N,N,N,31339,N,20284,N,N, +20322,19830,N,N,28528,N,29758,N,21581,N,N,29496,N,N,N,26913,N,N,N,N,N,N,N,N,N, +29298,29547,N,28759,N,N,20311,N,N,N,N,N,N,20319,N,N,N,N,N,N,N,N,N,26688,26689, +N,N,N,20323,26914,N,N,N,N,N,N,N,N,N,N,20522,N,N,N,N,N,N,N,N,N,29505,20523,N, +21604,N,N,28476,22561,N,N,N,N,N,N,N,N,N,N,N,22879,N,29527,N,N,N,23613,N,19557, +28017,N,N,29026,N,21595,N,N,N,N,25141,N,N,19046,N,21294,N,N,N,N,N,N,19558,N,N, +29011,30055,N,N,N,N,19034,31598,N,24901,N,N,N,N,N,N,N,24425,N,28254,N,N,30530, +N,22562,N,N,N,N,N,23852,N,N,N,N,N,28719,22077,N,N,N,N,N,N,N,N,N,N,N,24875,N,N, +N,N,N,N,N,N,N,N,N,N,31030,N,N,21621,N,20553,28455,25196,N,23402,20044,30056, +30549,N,21325,N,29566,N,N,N,N,N,N,N,N,N,20533,N,N,N,N,N,N,N,N,N,N,N,24702,N, +24443,N,N,N,N,N,N,26205,N,N,N,N,N,N,N,26660,N,N,N,N,N,N,N,N,N,19277,N,N,N, +28456,N,N,N,28212,N,N,N,N,23128,20793,N,24361,N,N,29488,N,N,19524,N,N,N,20023, +N,N,N,N,N,N,N,N,N,N,N,28457,N,N,N,24405,N,N,27991,N,N,N,28230,N,N,N,N,N,N,N, +28477,31830,N,N,23412,N,28458,30777,N,30057,N,N,N,N,N,N,N,N,25433,N,N,N,N,N,N, +N,N,N,N,N,N,N,24902,N,N,N,21567,N,N,N,N,24168,28778,N,N,N,N,N,N,N,N,N,N,29506, +N,N,N,N,N,N,N,N,N,N,N,21295,N,N,19035,N,N,N,N,N,31831,N,N,27992,24903,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,29784,22067,23853,N,N,N,21822,N,N,N,N,N,N,N,N,28995, +28255,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22123,N,N,N,29785,N,N,N,N,N,N,N, +22374,N,N,N,N,N,N,23095,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23931,N,N,N,N,N,23887,N, +N,N,N,N,N,N,N,22563,N,N,23129,N,28760,28484,N,N,N,N,N,N,24920,N,N,N,N,N,29012, +N,28018,N,N,N,N,N,N,21851,N,N,21852,29508,19287,N,N,N,N,N,25142,N,N,N,N,28529, +N,N,N,N,N,N,N,N,N,N,N,31573,N,N,N,N,N,N,N,N,N,N,N,21336,N,N,N,N,N,N,N,23888, +28761,19251,N,N,N,N,N,N,21853,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19751,N,N, +20524,20794,N,28996,N,25907,31605,26977,32096,31804,N,23074,23075,N,21025,N,N, +21103,N,N,N,25197,N,N,24169,20060,29237,20580,23889,N,N,N,N,24904,23351,24419, +N,N,N,N,N,N,N,N,27961,28997,N,29519,22315,24876,N,N,25451,N,28231,N,N,N,24905, +19066,N,N,N,N,N,N,N,28795,31329,28762,19559,23156,N,N,N,N,N,N,N,N,N,19519,N,N, +N,N,N,N,N,N,N,N,N,N,N,20077,N,N,21801,31330,N,N,N,20581,N,27478,N,27743,N,N,N, +24444,N,N,30550,24170,19252,N,N,28478,N,N,19509,N,N,N,N,N,20285,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,28530,25143,N,N,N,19560,N,N,N,N,N,N,N,N,28796,N,N,N,22112,N, +28998,N,N,N,N,N,N,N,N,N,25144,27435,N,N,N,19253,22609,N,29774,29559,N,N,22342, +N,20795,30506,N,27978,22355,22650,N,N,N,N,N,N,N,30277,N,N,20812,23932,N,N,N,N, +N,N,N,N,N,N,24445,N,31077,N,24650,N,N,29309,21296,N,29811,23113,N,26206,N,N,N, +N,30778,26704,N,N,22651,N,N,27221,N,N,N,N,22051,N,N,N,N,N,N,30278,29275,25724, +N,N,N,N,N,N,N,N,N,N,26674,N,N,N,N,N,23130,N,29276,31574,26930,N,28205,N,31331, +N,N,N,N,N,N,N,23662,N,N,30058,26208,N,28797,N,N,N,N,N,22316,N,N,N,N,N,30021, +28256,N,N,23397,N,23902,N,N,22896,26915,N,N,N,N,N,N,N,N,N,N,29049,N,29252, +24651,N,N,N,N,N,N,N,N,26916,N,N,25145,N,N,N,N,N,N,N,25393,31851,19752,N,19510, +N,N,28763,N,N,N,N,N,N,N,N,26170,N,N,19753,N,N,N,N,N,29507,N,N,N,N,N,N,N,N,N, +24921,N,N,28459,N,N,N,26437,N,N,24681,N,29509,N,N,21568,21823,23854,N,31100,N, +19520,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25890,N,N,N,20024,N,N,N,22610,31062,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28970,20049,N,N,30279,N,23403,N,24446,N, +N,22625,N,30579,N,22375,N,N,N,N,N,N,N,N,N,N,N,21630,N,N,20796,N,25935,N,19254, +N,23096,N,N,N,N,N,19780,N,N,N,N,N,22078,N,N,N,25146,N,N,N,N,N,20312,N,N,N, +24652,27513,N,N,N,N,N,N,N,N,32125,N,N,N,N,N,22376,19288,N,N,N,26978,N,N,N, +26682,N,N,N,25415,N,N,N,N,27725,N,27726,N,22079,N,N,N,25383,N,24406,32104,N,N, +N,N,N,N,N,N,N,28257,30248,23933,N,N,N,N,N,N,N,30779,N,26705,N,N,N,N,31063,N,N, +N,N,N,N,N,N,20078,N,N,27727,26917,22101,N,19781,N,27962,20797,N,N,20286,N,N, +27707,N,N,N,21041,N,N,N,N,19561,N,22852,27004,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,20798,N,N,N,N,N,27708,N,N,25901,N,N,N,N,N,N,30512,N,19562,N,N,N,21316, +N,N,22080,N,N,N,22141,N,N,N,N,N,N,N,N,N,N,N,24865,N,24125,N,30249,N,N,N,23076, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22052,30022,N,24866,26950,N,N,N,29253,N,N,N,N, +N,29801,22124,27475,N,N,N,N,27709,25180,24171,28764,N,27455,N,22350,20799,N,N, +N,N,N,N,N,N,N,29995,N,N,N,N,31101,N,19036,N,N,N,19782,29238,N,N,23934,N,N,N, +19511,23352,N,N,N,N,20585,N,20061,27456,N,32034,N,N,N,N,N,30795,N,N,N,N,N,N,N, +N,27222,28976,N,N,N,N,N,N,N,23374,N,30531,N,N,N,N,N,N,N,N,N,N,N,23375,19236,N, +N,30816,N,N,31575,N,N,27466,24609,N,N,N,N,N,N,N,N,N,N,N,20045,N,N,21596,N,N,N, +32088,N,N,N,N,21110,29239,N,N,31350,30250,31351,22630,N,29745,N,N,N,N,N,N,N,N, +N,N,N,N,N,26706,N,19013,19563,N,N,N,N,N,N,N,25198,N,N,N,N,N,25147,N,30509,N,N, +N,30817,N,N,N,N,N,N,N,N,N,29548,N,N,N,N,24097,N,N,N,N,N,N,N,N,N,N,N,N,25725,N, +N,25452,N,23855,23856,N,N,19255,26707,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24867, +21088,N,N,N,N,28798,N,N,N,N,26918,19314,N,N,N,N,N,N,28019,23641,24653,N,N,N,N, +30554,23353,N,N,N,N,N,N,N,19502,N,23131,N,N,N,N,19783,N,N,N,N,N,N,N,N,N,N, +23857,N,22575,25379,N,N,20079,N,N,29299,N,N,N,N,30771,N,N,N,N,N,N,N,N,N,N, +24654,N,30077,N,N,N,N,27500,N,N,21317,31852,21083,21611,N,24098,N,N,N,25958,N, +N,N,N,N,N,28720,N,N,N,N,N,N,N,N,N,N,21828,N,N,N,N,N,N,28020,N,N,N,25453,N, +26690,N,28021,22396,N,27963,N,N,30251,N,N,N,N,N,29240,30280,N,N,N,N,N,21350, +29277,20287,N,27436,20288,N,26152,32105,N,20289,N,24671,24172,N,N,N,N,24610,N, +N,N,N,N,N,N,N,29759,25199,N,22897,28999,N,19256,N,N,N,N,N,N,N,N,31102,23354, +23157,N,N,N,N,N,N,N,N,30316,23132,31332,N,24655,N,N,N,N,N,N,23858,N,N,N,N, +26153,N,28531,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29549,N,N,N,N,N,N,N,N,N,N, +27514,N,31078,N,N,N,N,N,N,N,19037,21854,N,19038,24420,N,N,N,26237,N,29996,N,N, +N,N,N,25717,N,N,N,N,N,N,N,N,N,N,N,N,26979,N,27979,20324,N,N,N,22611,N,N,N,N,N, +N,23859,21612,N,N,29241,N,24375,N,N,N,N,N,19278,31576,N,N,20569,N,N,23890, +30580,26460,25637,N,31779,N,23355,N,N,N,29242,27005,20554,N,30038,22853,25652, +N,27943,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27197,26238,N,30532,29997,N,22880,N, +N,N,18996,N,N,30818,20290,N,27710,N,N,N,25908,19784,28232,N,N,N,N,N,N,N,N,N, +26440,N,N,N,N,N,N,N,N,N,N,N,19785,31031,29032,22898,23413,18997,22854,N,N,N, +22601,N,N,N,N,N,N,N,N,N,N,N,N,N,22827,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27964,N, +N,22612,N,N,N,23642,N,25148,N,N,31853,27744,21118,N,26951,26154,N,N,N,N,N,N, +25200,N,N,N,N,N,N,31291,N,29998,31530,N,N,N,N,27771,N,27711,31832,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21605,N,N,N,31043,N,N,N, +28258,N,N,N,N,N,N,N,N,N,N,N,N,N,22377,28022,N,N,N,24173,N,N,N,N,N,N,N,19564,N, +25454,N,N,N,N,N,26708,N,N,N,31352,N,N,N,N,N,N,23860,25653,22576,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,22613,N,N,N,29802,N,N,N,20025,N,N,N,22113,20306,N,20534,N, +N,N,N,N,N,20002,N,N,29550,N,N,N,N,N,29560,N,N,N,N,N,N,N,N,N,N,N,N,23628,N, +20555,N,N,N,31780,19786,22356,24099,N,25696,N,N,N,N,28233,N,N,N,25181,30078, +21548,N,N,N,N,N,21841,N,22640,30787,27223,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,30039,N,N,22591,N,N,N,N,32064,N,N,N,N,N,N,27437,N,N,N,N,21802, +N,N,N,N,N,N,N,N,N,N,N,26408,N,N,N,N,N,N,N,N,N,N,N,N,N,28234,N,N,N,19047,N,N,N, +N,N,30819,N,21597,N,N,27224,N,N,N,N,31577,28023,N,N,25909,N,N,N,N,N,20525,N,N, +N,N,29041,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25149,N,N,N,25416,N,N,N,N, +22869,N,N,24362,N,N,N,N,23356,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30820,N,N,N,N,N, +29050,N,N,25910,29551,N,N,31578,24928,N,22828,N,30059,N,24630,N,N,26952,N, +19279,N,25417,N,N,N,24174,N,N,N,N,N,N,N,N,25150,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,23663,N,22053,N,N,N,N,N,25201,N,N,N,N,N,N,N,22142,22817,N,22592,23643,N,N, +27965,24376,N,27173,N,N,N,22317,N,N,29561,N,28024,N,30023,N,N,N,N,N,N,24906, +27491,N,29278,N,N,N,N,N,N,N,N,N,N,N,N,N,30796,N,27225,N,21318,N,23398,N,N,N,N, +N,29999,N,N,N,N,20080,N,N,N,N,27006,N,N,N,N,N,31542,N,N,N,N,N,N,N,N,N,25202,N, +N,N,N,20338,30521,22899,N,N,24907,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +23133,N,N,23097,N,N,N,N,N,N,N,27515,N,19257,N,N,28025,N,N,N,N,N,N,24672,N,N,N, +N,N,N,N,N,N,N,29760,N,32060,24369,25455,N,N,N,N,24611,32057,N,N,N,N,N,N,N,N,N, +28721,N,N,N,N,N,N,19787,N,N,N,N,N,N,N,27966,N,N,N,21824,25456,28026,N,N,N,N,N, +26980,N,N,N,N,N,N,21869,26461,N,N,N,N,N,N,21622,25911,N,N,N,23399,25151,N,N,N, +N,N,N,N,N,N,N,N,N,28235,N,N,22388,28765,N,N,N,20011,26462,N,N,N,22102,24908,N, +N,26675,N,N,N,N,N,N,N,N,N,N,N,25966,23586,N,N,24656,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,21813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21793,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,31579,N,31051,N,N,N,19315,29733,N,N,N,N,N,31304,22103,N,26981,31580,N,N, +N,N,N,N,N,32080,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31606,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,23077,N,23357,N,N,N,N,N,N,27746,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19831, +28766,N,N,N,N,30281,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +24175,N,N,N,21297,N,N,N,N,N,N,N,N,31854,N,N,N,N,26691,N,29000,N,N,N,20081,N,N, +N,N,31085,N,N,N,N,N,N,N,N,29300,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25654,30009,N, +23664,25457,N,N,N,N,26661,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29243,N,24100,N,23116, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,19049,N,N,N,N,N,N,25434,N,31833,N,N,N,N,N,N,N,27226,N,N,N, +N,N,N,31044,N,25380,N,N,N,N,N,N,N,N,N,N,N,31581,N,28490,N,26692,N,N,N,N,N,N,N, +N,N,21836,N,N,N,N,N,N,N,N,N,N,27479,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22829,N, +N,31531,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21337,N,N,N,N,N,N,21794,N,N,N,N,N,N,N, +N,N,30302,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,23158,N,N,N,N, +N,N,N,N,N,N,N,24657,N,N,26920,N,N,30073,N,N,N,N,N,N,31279,N,27516,N,N,24682, +25394,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,21829,N,N,29027,21870, +N,N,N,N,N,N,N,N,N,N,N,N,N,19788,N,N,N,N,27993,N,N,N,N,22593,N,N,N,N,31340,N,N, +N,N,N,29035,N,N,N,N,N,31292,26210,N,N,N,N,31333,25210,N,N,N,18998,N,25655,N, +27227,N,30074,N,N,N,31532,20291,27517,N,N,N,N,30842,N,N,24377,N,N,N,N,24945,N, +21028,N,N,N,N,30075,N,N,N,N,N,N,20570,20571,N,27198,22833,N,N,N,N,N,18999,N,N, +21351,N,30821,N,N,N,N,21298,N,N,N,25152,29279,N,N,N,N,N,N,19813,N,N,N,N,N,N,N, +N,N,N,N,N,31020,N,N,N,N,N,N,N,N,19789,N,N,N,N,N,N,N,N,N,N,N,N,28206,22062,N,N, +N,N,N,N,N,N,N,N,N,N,22378,N,N,N,N,26464,27438,N,N,N,20313,N,N,23629,28027,N, +24176,N,22379,N,N,N,N,N,N,24101,N,N,N,N,N,N,N,N,N,N,24407,23376,23377,N,N, +21795,N,N,N,N,28722,23644,N,N,N,N,N,N,N,N,19048,N,30822,23630,N,N,N,N,27228, +23378,N,N,N,N,N,N,N,N,N,N,N,26931,N,N,N,N,30555,N,N,N,N,N,N,N,N,N,N,N,25384,N, +22318,N,N,24673,N,N,N,N,N,19258,N,N,25937,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,20572,N,N,N,N,21825,N,N,N,N,N,22602,N,N,N,N,N,N,N,25385,N,N,N, +N,N,N,N,N,N,N,N,N,24612,N,26921,N,21319,N,N,23645,30766,N,N,N,19512,N,N,N, +20526,N,N,N,22642,N,N,25418,N,N,N,N,N,N,N,N,N,N,19503,N,N,N,N,N,N,N,21549, +30289,N,N,N,N,N,N,N,20556,N,N,N,N,N,N,N,19014,N,N,21826,N,N,20026,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,19015,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31280,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,24408,N,N,N,30010,25963,N,28532,23861,N,N,N,N,19754,N, +25458,N,31607,N,30544,N,N,N,N,32058,N,N,32097,30334,20800,N,N,26693,N,25656,N, +24936,N,N,N,19521,N,21101,N,N,N,N,23358,N,N,24674,N,N,N,31305,N,N,24909,N, +19000,N,N,N,29280,29001,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24177,N,N,N, +28767,30788,N,N,N,N,N,28236,N,N,24178,N,26441,N,25203,26465,N,N,25419,N,N, +25420,N,N,N,20344,28460,N,32126,31781,31281,24409,N,24658,N,N,N,29786,N,N,N,N, +N,N,N,N,N,N,N,29002,N,20003,N,N,N,N,29244,27747,N,N,N,N,N,24613,N,30507,N,N, +27439,N,N,N,N,N,25950,N,24868,19755,N,22900,26662,19790,24937,N,31855,N,24675, +N,N,N,N,N,25153,N,20004,N,N,N,N,N,N,24102,N,N,27518,N,27485,28768,N,N,29787,N, +25204,N,N,21320,N,N,N,29803,N,28213,N,30040,N,N,21855,N,N,N,22117,N,N,N,N, +27440,29795,N,N,N,N,25421,N,N,N,N,29812,31282,N,N,28533,19039,N,27441,27967,N, +N,32073,N,N,N,N,25638,31012,28723,N,25964,N,N,N,20839,22855,25687,27229,N, +21623,N,N,N,N,N,N,N,N,N,23098,N,23117,N,N,N,31052,N,24922,23359,N,19525,27728, +19259,N,24179,N,N,26922,N,N,N,N,N,N,N,22856,N,N,28259,22333,N,N,N,N,N,N,20292, +N,N,N,N,N,20557,N,N,N,N,N,N,N,31782,N,N,N,N,N,N,N,29051,N,N,N,N,32082,20801,N, +N,N,N,N,N,N,N,25435,N,21321,N,23631,N,N,N,N,N,N,N,N,N,19565,N,N,N,N,N,24103,N, +N,26171,27681,N,N,N,19513,N,N,31582,N,N,N,N,N,26466,N,N,21569,N,N,N,N,N,N,N,N, +N,23592,N,N,N,N,N,25154,N,29528,25939,N,N,29529,N,N,N,29510,19803,N,N,N,N,N,N, +N,19756,N,31811,N,N,N,N,21607,N,20802,N,31013,N,26709,N,N,N,N,N,N,N,N,25422,N, +N,N,N,21578,N,N,N,N,N,N,24410,N,N,N,N,N,N,N,N,31583,26467,N,N,N,N,N,N,N,N,N,N, +N,N,N,30843,25423,N,N,N,N,N,N,N,30000,N,N,N,N,N,N,N,22631,N,22857,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,30767,28534,N,23862,28207,19832,N,N,N,N,24120,31783,30588, +30513,20027,29729,N,N,28237,24878,N,N,27715,20350,N,30783,22626,21352,N,N, +24104,29796,27714,N,22901,31045,23891,22129,27772,31856,N,N,27968,19001,N, +28260,N,N,N,N,N,N,29281,N,24121,N,N,N,N,N,N,22130,N,24180,N,24411,N,23379,N, +31335,22627,29761,N,23863,N,N,N,29301,N,N,21550,N,N,N,N,N,N,22131,N,N,N,N,N,N, +23864,20293,24415,29246,30241,N,27467,29052,N,29511,N,N,24683,N,N,N,N,N,28028, +N,N,24923,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,28261,N,24181,N,N,N,N,31315,N,N,N,N,29003,N,N,20527,23865,N,N,20803,N, +N,N,N,N,N,N,N,N,N,N,N,N,30001,N,N,N,N,27206,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28769, +N,N,N,N,N,N,N,N,N,30252,N,N,N,N,30041,N,N,N,N,N,N,N,N,N,N,28779,N,N,N,N,N,N, +23866,N,N,N,29247,N,N,N,N,N,N,N,30533,N,N,N,N,23330,29302,N,N,19002,N,N,N,N,N, +N,N,N,N,N,N,30581,N,19301,N,N,N,28262,N,24659,N,N,N,N,20005,N,N,N,N,N,N,22104, +N,N,N,21551,26953,N,N,N,N,21326,29762,N,N,N,N,N,N,N,N,N,N,N,N,N,19302,N,N,N,N, +N,N,N,N,N,N,N,28961,N,N,N,N,N,27442,N,N,N,N,28962,N,N,N,N,N,N,N,N,N,N,N,N, +27443,N,28724,N,N,19316,21552,29490,31543,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30060,N, +N,N,N,N,28263,29746,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30061,N,20339,N,N,N, +N,N,N,N,N,N,N,28770,N,N,N,N,N,28238,N,N,29004,N,N,25912,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22389,25459,20325,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,20294,N,N,N,N,N,N,N,N,N,29491,25688,20345,20314,N,N,N,N,31309,N,N, +N,N,N,N,N,N,N,N,N,N,26211,N,N,N,N,N,N,N,N,N,N,N,29282,N,N,N,N,N,N,N,N,N,N,N,N, +30062,N,N,19003,N,N,25436,20082,N,22105,N,N,N,28208,N,N,N,N,N,N,N,N,29797, +22594,23632,19566,N,N,N,N,N,21856,30282,32074,22614,29775,N,N,N,N,N,N,22054, +23614,N,23380,22343,N,N,N,N,29310,N,N,N,29005,N,N,N,N,25155,23646,N,23647,N,N, +28461,26155,N,N,N,N,31069,27199,N,N,N,28462,N,N,N,29776,20083,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,26156,N,20062,N,N,21881,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25460, +19792,N,N,N,N,N,N,21816,N,N,30589,N,23593,N,N,N,N,24182,N,23594,29283,26932, +21084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26982,N,N,25462,N,N,N,N,N,N,N,N,26442,N,N, +20558,N,N,23159,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19004,N,N,N,28264,23134,N, +29303,N,N,25211,N,19494,N,N,N,N,23099,N,28265,N,N,N,30042,30556,24938,20033, +21553,N,32049,26173,N,31533,N,N,30823,N,24910,N,30562,30063,20295,N,N,21554, +19567,N,21608,N,28239,30551,N,N,24614,22081,24924,28771,29028,23665,22055,N,N, +N,N,N,N,N,N,N,N,29813,N,N,29006,29284,N,N,20528,N,N,27759,N,N,N,31034,N,27445, +N,N,21613,25156,N,N,N,N,26983,N,N,27444,27169,N,30780,20006,N,31046,31834,N, +21555,21305,27230,N,N,N,26923,N,N,24929,21327,29814,N,27200,24911,N,19514,N,N, +N,N,N,28266,N,N,N,28772,29492,21614,N,N,29248,N,N,29029,N,29763,24660,N,27446, +N,22305,19304,N,31021,26925,22628,31283,25157,31805,N,N,27716,22577,N,23595,N, +N,N,N,21796,N,27497,N,N,N,26683,N,N,N,22615,N,N,N,N,N,N,N,N,31534,20833,N,N, +23360,N,30014,N,24183,N,N,N,N,19067,30534,20296,N,N,N,24912,N,N,28240,N,N,N,N, +N,N,N,N,26996,N,N,N,N,N,N,N,N,20084,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +21837,N,N,20315,N,N,N,N,N,N,23867,N,N,N,N,20012,N,N,N,N,N,N,N,26984,N,N,N,N,N, +N,N,21556,25671,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,30043,N,N,31297,N,N,N,24105,N,N, +N,N,N,N,N,N,N,N,N,N,N,21624,N,N,N,N,N,28535,N,N,N,N,21299,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,27447,28536,30044,27980,23381,29007,N,N,N,29008,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,30002,N,N,N,N,N,N,22830,21804,N,25158,N,N,N,N,N,N,N,N, +32035,N,31589,24363,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25205,N,30253,N,30003,N,28725, +N,N,N,N,24869,N,N,N,N,N,N,N,N,N,30045,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27682,28029, +N,30004,31544,N,23331,N,N,22090,19289,N,N,N,N,N,N,N,N,N,N,25940,N,N,N,N,N,N, +29562,N,27448,N,24631,22380,29036,25903,21857,22381,20817,N,N,N,N,N,24946, +28537,N,N,N,23868,30300,N,N,N,N,N,28773,N,N,N,29764,N,N,26985,N,N,N,N,N,N,N,N, +N,N,29563,21615,N,N,19490,30590,24380,N,N,N,N,27469,N,N,N,N,N,N,20535,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22082,N,N,N,N,N,26669,N,N,N,N,28463,19237,N, +N,N,N,19305,N,N,N,31336,N,N,N,N,N,N,N,N,N,N,N,N,N,19526,N,N,N,26215,N,N,27207, +N,N,N,23332,N,20297,25212,28538,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,27486,N,N,30024,N,21598,N,N,N,N,N,N,N,N,N,N,N,24661,N,28464,N,N,25159,N, +22831,N,N,N,31079,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26469,N,N,20298, +24913,N,25160,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28539,N,N,31353,N,N,23666,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,24615,N,N,N,N,N,30824,N,N,N,N,N,N,N,N,N,N,N,N, +N,19306,N,N,N,19260,22114,N,N,N,N,N,N,N,N,N,N,N,30046,N,N,N,N,N,N,N,30047,N, +28214,N,N,N,25206,21322,28540,20804,28465,N,20805,N,20574,N,22881,N,N,24632,N, +N,19793,29497,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,26444,N,22056, +20007,N,21557,N,N,N,N,N,N,25672,N,N,N,N,N,N,21300,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,27449,N,N,N,N,N,N,19317,N,N,N,N,N,N,30301,N,28963,N,N,N,N,N,N,N,N,N,N, +N,N,N,19527,N,N,N,N,N,N,N,26954,N,24944,N,N,N,30048,N,N,N,N,N,N,N,N,31535,N,N, +N,19281,N,N,N,N,31584,29285,N,N,27760,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +28780,N,N,N,N,N,N,N,N,N,N,N,N,N,28267,N,N,N,N,N,N,N,N,N,N,N,N,26955,N,N,19568, +N,N,22319,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29473,31861,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,28964,N,N,N,N,N,N,N,N,N,N,N,N,24662,N,N,N,N,N,28466,N,N,N,N,N, +N,N,N,N,29777,N,N,30497,N,N,N,N,N,N,N,N,N,N,N,29009,N,N,N,N,N,N,N,N,N,N,N,N, +19068,19069,N,N,N,N,N,N,N,N,20046,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,29512,N,29498,28030,N,N,N,N,N,N,N,N,23078,N,N,24684,N,N, +N,N,N,30797,N,19282,N,N,N,27470,N,31064,31065,19040,23114,N,N,N,19238,N,N,N,N, +N,N,N,N,N,N,19016,31086,23404,N,N,20529,N,N,N,N,21871,N,N,N,26227,N,N,N,N,N,N, +N,N,N,26402,25689,N,N,N,N,N,N,N,N,N,N,25697,N,N,31812,N,N,N,N,N,N,N,N,N,31087, +20340,30566,N,N,N,N,N,20028,N,N,N,N,29765,23587,23869,N,N,N,N,29766,N,N,N,N,N, +N,N,N,30753,N,N,N,26710,N,N,N,23361,N,N,N,N,N,N,N,N,28774,N,N,N,25657,30317,N, +31022,N,23870,N,N,N,N,N,N,22320,22632,19261,N,N,31066,N,N,N,N,N,N,N,N,N,N, +30798,31088,24685,25395,29747,N,N,27202,29286,28726,N,N,N,N,N,23382,N,N,N,N,N, +27492,N,N,29287,N,22357,21558,31080,22337,N,N,N,N,25941,N,N,N,N,N,N,N,26986, +22348,N,N,N,21353,25161,N,31835,19757,N,N,N,N,N,19504,27170,N,N,25718,20544,N, +28727,28193,N,N,N,N,N,N,22390,N,N,N,25162,25163,N,31311,N,N,N,N,N,N,27487,N,N, +N,N,N,22091,N,N,N,29748,N,N,N,N,27981,25682,N,N,27177,25658,29474,19794,N, +30283,N,29030,27969,26684,28241,N,N,N,N,N,N,28775,25164,N,N,25642,N,30049, +27994,N,N,N,N,N,22382,20849,N,N,N,N,26987,26988,24676,N,N,N,N,23079,23892,N, +27171,N,N,N,22083,22132,N,23135,N,28467,25165,N,N,N,N,N,28541,29288,N,N,N,N,N, +N,N,N,N,28485,N,26471,N,N,22397,N,N,26446,N,N,24412,N,31047,N,N,N,N,N,N,N,N, +22902,N,N,N,N,N,N,N,N,24364,N,22106,N,N,N,N,N,N,23588,N,N,N,28728,N,N,N,N, +21882,N,25719,N,N,N,22084,N,N,N,N,N,N,N,N,29804,N,N,N,N,28542,N,N,N,N,N,28705, +N,24106,N,N,23100,22652,N,N,N,N,N,N,31316,N,N,N,27749,N,N,N,N,N,N,31784,N,N, +27750,N,N,22603,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31545,N,25683,N,19833,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,20307,N,N,N,N,N,N,N,19050,N,N,20308,N,30781,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29767,N,N,N,N,27231,N,N,N,N,N,N,N,31067, +N,N,N,N,N,N,N,N,21559,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27493,N,N, +24914,N,N,N,N,27172,N,N,N,31298,31585,31341,28706,19569,N,31267,25207,N,25166, +N,26997,N,24939,N,N,N,26472,26711,23160,21579,N,N,N,30582,22085,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,21609,N,N,31354,N,N,N,N,N,N,N,19570,30557,N,24122,N, +N,N,N,N,N,N,N,N,N,20008,N,N,N,N,N,28729,25726,25673,N,N,N,N,N,25684,N,N,N, +27203,N,28468,N,N,N,22334,N,N,N,N,N,N,31586,N,19795,N,N,N,28469,N,N,N,31337,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31014,N,N,N,N,N,N,24381,N,30535,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,30845,N,N,30844,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +24107,23400,N,N,25437,N,24930,20806,N,N,N,N,N,N,N,N,N,N,30288,27494,23161,N,N, +N,N,27719,N,N,N,N,N,N,N,24184,30825,25438,20085,N,N,N,N,N,31299,25943,N,27720, +N,N,N,29513,N,N,25659,N,N,N,N,26158,N,N,N,N,N,28470,N,23615,N,N,N,N,N,N,N, +20029,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22595,N,N,N, +20559,N,20346,29514,24663,N,N,N,20807,26926,N,26685,N,N,31300,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25167,N,N,31301,N,N,N,31032,N,N,N,N,N,N,N,23648, +N,N,31536,N,N,N,22569,25951,31015,N,N,30318,N,30284,25208,N,N,N,N,27761,N,N,N, +N,N,N,N,23136,N,N,N,N,N,N,N,N,N,N,N,N,N,N,29010,21068,20299,N,N,19005,N,N,N, +23871,N,N,N,30319,N,24185,N,N,N,N,N,N,N,N,N,N,N,N,N,31284,N,N,N,21805,N,N,N,N, +N,N,N,N,N,N,N,N,N,29031,24126,N,N,N,N,N,N,23616,N,N,N,N,N,20808,20809,N,N,N,N, +N,N,N,N,N,30782,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19318,N,N,N,N,21625,N,N,N,N, +N,30050,24915,N,N,N,N,N,N,N,N,22633,N,N,30846,N,20300,N,N,N,N,N,N,N,32036,N,N, +N,N,N,N,N,20086,N,31312,N,N,19571,26174,N,N,N,30254,N,N,21872,N,N,20810,N,N,N, +31806,21873,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19817,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,31285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,25168, +29815,N,N,N,19796,N,N,N,N,N,N,N,N,N,N,N,N,26403,N,N,N,N,N,N,N,N,23333,25169,N, +N,N,N,N,N,N,N,N,N,N,N,22306,N,N,30563,N,N,N,N,N,N,27174,N,N,N,N,N,N,N,N,N,N, +20513,N,N,N,N,20058,31595,23334,23390,22629,N,N,N,N,N,N,N,N,N,27232,N,N,N,N, +22570,N,N,N,N,N,25952,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22107,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28486,N,N,30826,N,N,N,N,N,N, +N,N,N,N,N,N,N,25685,N,N,N,N,N,N,N,N,N,N,N,20087,N,N,24664,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22383,N,N,N,N,N,N,N,N,N,N,N,N,29805,N,N,N,N,N, +N,N,N,N,N,N,N,N,19814,N,N,N,19572,30051,N,N,25674,N,23649,N,N,31048,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,31807,N,N,N,N,N,N,N,N,N,N,N,N,26663,N,N,N,N,N,N,N,N,22596, +N,N,N,N,N,N,N,N,N,N,N,19262,N,23598,N,N,N,N,N,N,N,N,N,N,N,N,N,22391,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28776,N,23872,N,20301,N,N,N,N,N,N,N,N,N, +23667,22832,N,26217,25660,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,27204,N,N,N,N,N,N, +N,N,N,N,25708,N,25701,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,31608,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,19515,N,N,N,N,N,N,N,N,N,N,N,25661,N,N,19804,22903, +N,N,N,N,N,N,N,N,N,N,23903,N,N,N,N,N,27982,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22864, +N,N,N,N,N,25891,N,N,N,N,31053,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,19758,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,20302,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,30255,N,N,N,N,N,32083,27501,22108,25892,N,N,N,21814,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22109, +N,N,N,31081,N,N,N,26404,N,22115,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,20811, +22116,N,N,N,21874,N,N,N,N,N,24186,N,22392,N,N,N,N,N,22634,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,20309,22653,N,N,N,N,N,22571,N,N,32075,N,N,N,N,31836,N,N,N,N,N,N,N,N,N, +24616,21875,N,N,32089,N,N,19491,N,N,N,22905,N,N,21354,30069,N,28487,N,N,N,N,N, +N,N,N,N,21338,N,N,N,N,N,N,N,N,N,N,N,23101,26664,23599,N,N,N,N,N,28707,N,N,N,N, +19797,N,N,N,N,N,N,N,N,N,N,N,N,24617,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,24108,N,N,N,N,N,N,N,N,N,N,N,N,N,N,28730,28209,N,N,28210,N,N,N,30285, +N,N,N,N,N,N,N,N,N,N,N,N,28242,N,22086,N,N,N,N,N,24677,N,N,29499,N,25953,N,N,N, +N,N,N,N,N,N,N,25675,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,22307,N,N,23362, +N,N,N,N,19070,N,N,N,N,N,N,20303,12321,12322,33089,33090,12323,33091,33092, +12324,12325,12326,12327,33093,33094,33095,33096,33097,12328,12329,12330,12331, +12332,12333,12334,12335,33098,12336,12337,12338,12339,12340,33099,33100,12341, +33101,33102,33103,12342,33104,33105,33106,33107,33108,33109,33110,12343,12344, +33111,12345,12346,12347,33112,33113,33114,33121,33122,33123,12348,12349,33124, +33125,12350,33126,33127,33128,12351,33129,33130,33131,33132,33133,33134,33135, +33136,33137,33138,12352,33139,12353,33140,33141,33142,33143,33144,33145,12354, +33146,33153,33154,12355,33155,33156,33157,12356,33158,33159,33160,33161,33162, +33163,33164,33165,33166,33167,33168,33169,33170,33171,33172,33173,33174,33175, +33176,12357,12358,33177,33178,12359,33179,33180,12360,12361,33181,12362,33182, +33183,33184,33185,33186,12363,12364,33187,12365,12366,12367,12368,33188,33189, +12369,12370,12371,12372,33190,33191,33192,12373,33193,33194,33195,12374,33196, +33197,33198,33199,33200,33201,33202,12375,12376,33203,12377,12378,12379,33204, +33205,33206,33207,33208,33209,12380,12381,12382,33210,12383,33211,33212,12384, +12385,33213,33214,33215,33216,33217,33218,33219,12386,12387,33220,12388,12389, +12390,33221,33222,33223,12391,33224,33225,12392,33226,33227,33228,12393,33229, +33230,33231,12394,33232,33233,33234,33235,33236,33237,33238,33239,12395,33240, +12396,33241,33242,33243,33244,33245,33246,33247,33248,12397,12398,33249,33250, +12399,33251,33252,12400,12401,33253,12402,33254,12403,33255,33256,12404,12405, +12406,33257,12407,33258,12408,12409,33259,33260,33261,33262,33263,12410,12411, +33264,33265,12412,33266,33267,33268,12413,33269,12414,33270,33271,33272,33273, +33274,12577,12578,33275,12579,33276,12580,33277,33278,33345,33346,33347,33348, +12581,33349,33350,33351,12582,33352,33353,33354,12583,33355,33356,33357,33358, +33359,33360,33361,33362,12584,33363,33364,12585,12586,33365,33366,33367,33368, +33369,33370,12587,12588,33377,33378,12589,33379,33380,33381,12590,33382,33383, +33384,33385,33386,33387,33388,12591,12592,33389,12593,33390,12594,33391,33392, +33393,33394,33395,33396,12595,33397,33398,33399,12596,33400,33401,33402,12597, +33409,33410,33411,33412,33413,33414,33415,33416,12598,33417,12599,33418,33419, +33420,33421,33422,33423,33424,33425,12600,12601,33426,33427,12602,33428,33429, +12603,12604,12605,12606,33430,33431,33432,33433,12607,12608,12609,33434,12610, +33435,12611,12612,33436,33437,33438,33439,33440,12613,12614,33441,33442,12615, +33443,33444,33445,12616,33446,33447,33448,33449,33450,33451,33452,33453,33454, +33455,33456,12617,12618,33457,33458,33459,33460,33461,33462,12619,33463,33464, +33465,33466,33467,33468,33469,33470,33471,33472,33473,33474,33475,33476,33477, +33478,33479,33480,12620,33481,33482,33483,33484,33485,33486,33487,33488,12621, +12622,33489,33490,12623,33491,33492,33493,12624,33494,33495,33496,33497,33498, +33499,33500,12625,12626,33501,12627,33502,33503,33504,33505,33506,33507,33508, +33509,12628,33510,33511,33512,12629,33513,33514,33515,12630,33516,33517,33518, +33519,33520,33521,33522,33523,33524,33525,33526,33527,33528,33529,33530,33531, +33532,33533,33534,12631,12632,33601,33602,12633,33603,33604,12634,12635,12636, +33605,33606,33607,33608,33609,33610,12637,12638,33611,12639,33612,12640,33613, +33614,33615,33616,33617,33618,12641,33619,33620,33621,33622,33623,33624,33625, +33626,33633,33634,33635,33636,33637,33638,33639,33640,33641,33642,33643,33644, +33645,33646,33647,33648,33649,33650,33651,12642,12643,33652,33653,12644,33654, +33655,12645,12646,33656,12647,33657,33658,33665,33666,33667,12648,12649,33668, +12650,33669,12651,12652,33670,33671,33672,12653,33673,12654,12655,12656,33674, +12657,33675,33676,33677,12658,33678,12659,33679,33680,33681,33682,33683,12660, +12661,33684,12662,12663,12664,33685,33686,33687,12665,33688,33689,12666,12667, +33690,33691,12668,33692,33693,33694,12669,33695,33696,33697,33698,33699,33700, +33701,12670,12833,33702,12834,12835,12836,33703,33704,33705,33706,33707,33708, +12837,12838,33709,33710,33711,33712,33713,33714,12839,33715,33716,33717,33718, +33719,33720,33721,33722,33723,33724,33725,33726,33727,33728,33729,33730,33731, +33732,33733,33734,33735,33736,33737,33738,33739,33740,33741,33742,33743,33744, +33745,33746,33747,33748,33749,33750,33751,33752,33753,33754,33755,33756,33757, +33758,33759,33760,33761,12840,12841,12842,33762,12843,33763,33764,33765,12844, +33766,33767,33768,33769,33770,33771,33772,12845,12846,33773,12847,12848,12849, +33774,33775,33776,33777,33778,33779,12850,12851,33780,33781,12852,33782,33783, +33784,33785,33786,33787,33788,33789,33790,33857,33858,12853,33859,33860,12854, +33861,12855,33862,33863,33864,33865,33866,33867,12856,33868,33869,33870,12857, +33871,33872,33873,12858,33874,33875,33876,33877,33878,33879,33880,33881,33882, +33889,12859,12860,33890,33891,33892,33893,12861,33894,33895,12862,33896,33897, +33898,33899,33900,33901,33902,33903,33904,33905,33906,33907,33908,33909,33910, +33911,33912,33913,33914,33921,33922,33923,33924,33925,33926,33927,33928,12863, +12864,33929,33930,12865,33931,12866,33932,12867,33933,33934,33935,33936,33937, +33938,33939,12868,12869,33940,12870,33941,12871,12872,12873,33942,33943,33944, +33945,12874,12875,33946,33947,33948,33949,33950,33951,12876,33952,33953,33954, +33955,33956,33957,33958,33959,33960,33961,33962,12877,12878,33963,33964,33965, +33966,33967,33968,12879,12880,33969,33970,33971,33972,33973,33974,33975,33976, +33977,33978,33979,33980,33981,33982,33983,33984,33985,33986,33987,12881,33988, +33989,33990,33991,33992,33993,12882,33994,33995,33996,12883,33997,33998,33999, +12884,34000,34001,34002,34003,34004,34005,34006,12885,12886,34007,34008,34009, +12887,34010,34011,34012,34013,34014,34015,12888,34016,34017,34018,34019,34020, +34021,34022,34023,34024,34025,34026,34027,34028,34029,34030,34031,34032,34033, +34034,34035,34036,34037,34038,34039,34040,34041,34042,12889,12890,34043,34044, +12891,34045,34046,34113,12892,34114,34115,34116,34117,34118,34119,12893,12894, +12895,34120,12896,34121,12897,12898,34122,34123,34124,34125,34126,12899,34127, +34128,34129,34130,34131,34132,34133,12900,34134,34135,34136,34137,34138,34145, +34146,34147,34148,34149,34150,12901,12902,34151,34152,34153,34154,34155,34156, +12903,12904,34157,34158,12905,34159,34160,34161,12906,34162,34163,34164,34165, +34166,34167,34168,12907,12908,34169,34170,12909,34177,34178,34179,34180,34181, +34182,34183,12910,34184,34185,34186,12911,34187,34188,34189,12912,34190,34191, +34192,34193,34194,34195,34196,12913,12914,34197,34198,34199,34200,34201,34202, +34203,34204,34205,34206,12915,34207,34208,34209,34210,34211,34212,34213,34214, +34215,34216,34217,34218,34219,34220,34221,34222,34223,34224,34225,34226,34227, +34228,34229,34230,34231,34232,34233,12916,12917,34234,34235,12918,34236,12919, +34237,12920,34238,12921,34239,34240,34241,34242,12922,12923,12924,34243,12925, +34244,12926,34245,34246,34247,13089,34248,34249,34250,34251,34252,34253,34254, +34255,34256,34257,34258,34259,34260,34261,34262,34263,34264,34265,34266,34267, +34268,34269,34270,34271,34272,34273,34274,34275,34276,34277,13090,13091,34278, +34279,13092,34280,34281,34282,13093,34283,34284,34285,34286,34287,34288,34289, +13094,13095,34290,13096,34291,13097,34292,34293,34294,34295,34296,34297,13098, +13099,13100,34298,13101,34299,34300,13102,13103,13104,13105,34301,34302,34369, +34370,34371,13106,13107,34372,13108,13109,13110,13111,13112,34373,13113,34374, +13114,13115,13116,34375,34376,13117,34377,34378,34379,13118,34380,34381,34382, +34383,34384,34385,34386,13119,13120,34387,13121,13122,13123,34388,34389,34390, +34391,34392,34393,13124,13125,34394,34401,13126,34402,34403,34404,13127,34405, +34406,34407,34408,34409,34410,34411,13128,34412,34413,34414,34415,13129,34416, +34417,34418,34419,34420,34421,34422,34423,34424,34425,34426,34433,34434,34435, +34436,34437,34438,34439,34440,34441,34442,34443,34444,34445,34446,34447,34448, +34449,34450,34451,34452,34453,34454,34455,13130,13131,34456,13132,13133,34457, +34458,34459,13134,34460,13135,13136,34461,34462,34463,34464,13137,13138,34465, +13139,13140,13141,34466,34467,34468,34469,34470,13142,13143,13144,34471,34472, +13145,34473,34474,34475,13146,34476,34477,34478,34479,34480,34481,34482,13147, +13148,34483,13149,13150,13151,34484,34485,34486,34487,34488,34489,13152,13153, +34490,34491,13154,34492,34493,34494,13155,34495,34496,34497,34498,34499,34500, +34501,13156,13157,34502,34503,13158,13159,34504,34505,13160,34506,34507,34508, +13161,34509,34510,34511,13162,34512,34513,34514,34515,34516,34517,34518,34519, +34520,34521,34522,34523,34524,34525,34526,34527,34528,34529,34530,34531,34532, +34533,34534,13163,13164,34535,34536,13165,34537,34538,34539,13166,34540,13167, +34541,34542,34543,34544,34545,13168,13169,34546,13170,34547,13171,34548,34549, +34550,34551,13172,13173,13174,34552,34553,34554,13175,34555,34556,34557,13176, +34558,34625,34626,34627,34628,34629,34630,34631,34632,34633,34634,13177,34635, +34636,34637,34638,34639,34640,34641,34642,34643,34644,34645,34646,34647,34648, +34649,34650,34657,34658,34659,34660,34661,34662,34663,34664,34665,34666,34667, +34668,34669,34670,34671,34672,34673,34674,34675,13178,34676,34677,34678,13179, +34679,34680,34681,13180,34682,34689,34690,34691,34692,34693,34694,13181,13182, +34695,13345,34696,34697,34698,34699,34700,34701,34702,34703,13346,13347,34704, +34705,13348,34706,34707,34708,13349,34709,34710,34711,34712,34713,34714,34715, +34716,13350,34717,13351,34718,13352,34719,34720,34721,34722,34723,34724,13353, +13354,34725,34726,13355,34727,34728,13356,13357,34729,34730,34731,34732,34733, +34734,34735,13358,13359,34736,13360,34737,13361,34738,34739,34740,34741,34742, +34743,13362,34744,34745,34746,34747,34748,34749,34750,34751,34752,34753,34754, +34755,34756,34757,34758,34759,34760,34761,34762,13363,34763,34764,34765,34766, +34767,34768,34769,13364,34770,34771,34772,34773,34774,34775,34776,34777,34778, +34779,34780,34781,34782,34783,34784,34785,34786,34787,34788,34789,34790,34791, +34792,34793,34794,34795,34796,13365,34797,34798,34799,13366,34800,34801,34802, +13367,34803,34804,34805,34806,34807,34808,34809,13368,13369,34810,34811,34812, +34813,34814,34881,34882,34883,34884,34885,13370,13371,34886,34887,34888,34889, +34890,34891,13372,34892,34893,34894,34895,34896,34897,34898,13373,13374,34899, +34900,34901,13375,34902,34903,34904,34905,34906,34913,13376,13377,34914,34915, +13378,34916,34917,34918,13379,13380,13381,34919,34920,34921,34922,34923,13382, +13383,34924,13384,34925,13385,13386,34926,34927,34928,13387,34929,13388,34930, +34931,34932,13389,34933,34934,34935,13390,34936,34937,34938,34945,34946,34947, +34948,34949,34950,34951,34952,34953,34954,34955,34956,34957,34958,34959,34960, +13391,13392,34961,34962,13393,34963,34964,34965,13394,34966,13395,34967,34968, +34969,34970,34971,13396,13397,34972,13398,34973,13399,34974,34975,34976,34977, +13400,34978,13401,13402,13403,34979,13404,34980,34981,13405,13406,13407,13408, +13409,34982,34983,34984,13410,13411,13412,34985,13413,13414,13415,13416,13417, +34986,34987,34988,13418,13419,13420,34989,34990,13421,34991,34992,34993,13422, +34994,34995,34996,34997,34998,34999,35000,13423,13424,35001,13425,13426,13427, +35002,35003,35004,35005,35006,35007,13428,35008,35009,35010,35011,35012,35013, +35014,35015,35016,35017,35018,35019,35020,35021,35022,35023,35024,35025,35026, +35027,35028,35029,35030,35031,35032,35033,35034,35035,35036,35037,35038,35039, +35040,35041,35042,35043,35044,35045,35046,35047,35048,35049,35050,35051,35052, +35053,35054,35055,35056,35057,35058,35059,35060,35061,35062,13429,13430,13431, +35063,13432,35064,35065,13433,13434,35066,13435,13436,35067,35068,35069,35070, +13437,13438,35137,13601,35138,13602,35139,13603,35140,35141,13604,35142,13605, +13606,35143,35144,13607,35145,35146,35147,13608,35148,35149,35150,35151,35152, +35153,35154,13609,13610,35155,13611,13612,13613,35156,35157,35158,35159,35160, +35161,13614,35162,35169,35170,13615,35171,35172,35173,13616,35174,35175,35176, +35177,35178,35179,35180,35181,35182,35183,35184,13617,13618,35185,35186,35187, +35188,35189,35190,13619,35191,35192,35193,13620,35194,35201,35202,35203,35204, +35205,35206,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217, +35218,35219,35220,35221,35222,13621,13622,35223,35224,13623,35225,35226,13624, +13625,35227,13626,35228,13627,35229,35230,35231,13628,13629,35232,13630,35233, +13631,35234,13632,35235,13633,35236,35237,13634,35238,35239,35240,13635,35241, +35242,35243,13636,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253, +35254,35255,35256,35257,35258,35259,35260,35261,35262,13637,35263,35264,35265, +35266,35267,35268,35269,35270,35271,35272,35273,35274,35275,35276,35277,35278, +35279,35280,35281,13638,35282,35283,35284,35285,35286,35287,35288,13639,35289, +35290,35291,13640,35292,35293,35294,13641,35295,35296,35297,35298,35299,35300, +35301,13642,13643,35302,13644,35303,35304,35305,35306,35307,35308,35309,35310, +13645,35311,35312,35313,35314,35315,35316,35317,35318,35319,35320,35321,35322, +35323,35324,35325,35326,35393,35394,35395,35396,35397,35398,35399,35400,35401, +35402,35403,13646,13647,35404,35405,13648,35406,35407,35408,13649,35409,35410, +35411,35412,35413,35414,35415,13650,13651,35416,13652,35417,13653,35418,35425, +35426,35427,35428,35429,13654,35430,35431,35432,35433,35434,35435,35436,35437, +35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,13655,35449, +35450,35457,35458,35459,35460,35461,13656,35462,35463,35464,35465,35466,35467, +35468,35469,35470,35471,35472,35473,35474,35475,35476,35477,35478,35479,35480, +35481,13657,35482,35483,35484,35485,35486,35487,13658,35488,35489,35490,13659, +35491,35492,35493,13660,35494,35495,35496,35497,35498,35499,35500,35501,13661, +35502,13662,35503,13663,35504,35505,35506,35507,35508,35509,13664,35510,35511, +35512,13665,35513,35514,35515,13666,35516,35517,35518,35519,35520,35521,35522, +13667,35523,35524,35525,35526,13668,35527,35528,35529,35530,35531,35532,13669, +13670,35533,35534,13671,35535,35536,13672,13673,35537,13674,35538,35539,35540, +35541,35542,13675,13676,35543,13677,35544,13678,35545,35546,35547,35548,35549, +35550,13679,35551,35552,35553,35554,35555,35556,35557,35558,35559,35560,35561, +35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574, +35575,35576,35577,13680,13681,35578,35579,13682,35580,35581,13683,13684,35582, +35649,35650,35651,35652,35653,35654,13685,13686,35655,13687,13688,13689,13690, +35656,35657,35658,35659,35660,13691,13692,35661,35662,13693,35663,35664,35665, +13694,35666,35667,35668,35669,35670,35671,35672,13857,13858,35673,13859,13860, +13861,35674,35681,35682,35683,35684,13862,13863,13864,35685,35686,13865,35687, +35688,35689,13866,35690,35691,35692,35693,35694,35695,35696,13867,13868,35697, +13869,13870,13871,35698,35699,35700,35701,35702,35703,35704,35705,35706,35713, +35714,35715,35716,35717,35718,35719,35720,35721,35722,35723,35724,35725,35726, +35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739, +35740,35741,35742,35743,35744,35745,35746,35747,35748,35749,35750,35751,35752, +35753,35754,35755,35756,35757,35758,35759,35760,35761,35762,35763,35764,35765, +13872,13873,35766,35767,13874,35768,35769,35770,13875,35771,13876,13877,35772, +35773,35774,35775,13878,13879,35776,13880,13881,13882,35777,35778,35779,35780, +35781,13883,13884,13885,35782,35783,13886,35784,35785,35786,13887,35787,35788, +35789,35790,35791,35792,35793,13888,13889,35794,13890,13891,13892,35795,35796, +35797,35798,35799,35800,13893,35801,35802,35803,35804,35805,35806,35807,35808, +35809,35810,35811,35812,35813,35814,35815,35816,35817,35818,35819,13894,35820, +35821,35822,35823,35824,35825,35826,35827,35828,35829,35830,35831,35832,35833, +35834,35835,35836,35837,35838,35905,35906,35907,35908,35909,35910,35911,35912, +35913,35914,35915,35916,35917,35918,35919,35920,13895,13896,35921,35922,13897, +35923,35924,35925,13898,35926,35927,35928,35929,35930,35937,35938,35939,35940, +35941,35942,35943,13899,35944,35945,35946,35947,35948,35949,13900,35950,35951, +35952,35953,35954,35955,35956,13901,35957,35958,35959,35960,35961,35962,35969, +35970,35971,35972,35973,35974,35975,35976,35977,35978,35979,35980,35981,13902, +35982,35983,35984,35985,35986,35987,35988,35989,35990,35991,35992,35993,35994, +35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007, +36008,13903,36009,36010,36011,13904,36012,36013,36014,36015,36016,36017,36018, +36019,36020,36021,36022,36023,36024,36025,36026,36027,36028,36029,36030,36031, +36032,36033,36034,36035,36036,36037,36038,36039,36040,36041,36042,36043,36044, +36045,36046,36047,36048,36049,36050,36051,36052,36053,36054,36055,36056,36057, +36058,36059,36060,36061,36062,13905,13906,36063,36064,13907,36065,36066,36067, +13908,36068,36069,36070,36071,36072,36073,13909,13910,36074,36075,36076,36077, +13911,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089, +36090,36091,36092,36093,36094,36161,36162,36163,36164,36165,36166,36167,36168, +36169,36170,36171,36172,36173,36174,36175,36176,36177,13912,36178,36179,36180, +36181,36182,36183,36184,36185,36186,36193,36194,36195,36196,36197,36198,36199, +36200,36201,36202,36203,36204,36205,36206,36207,36208,36209,36210,13913,36211, +36212,36213,13914,36214,36215,36216,13915,36217,36218,36225,36226,36227,36228, +36229,13916,13917,36230,36231,36232,13918,36233,36234,36235,36236,36237,36238, +36239,36240,36241,36242,36243,36244,36245,36246,36247,36248,36249,36250,36251, +36252,36253,36254,36255,36256,36257,36258,36259,36260,36261,36262,36263,36264, +36265,36266,13919,13920,36267,36268,13921,36269,36270,13922,13923,36271,36272, +36273,36274,36275,36276,36277,13924,13925,36278,13926,36279,36280,36281,36282, +36283,36284,36285,36286,13927,36287,36288,36289,13928,36290,36291,36292,13929, +36293,36294,36295,36296,36297,36298,36299,13930,13931,36300,36301,36302,36303, +36304,36305,36306,36307,36308,36309,13932,36310,36311,36312,13933,36313,36314, +36315,13934,36316,36317,36318,36319,36320,36321,36322,13935,13936,36323,13937, +36324,13938,36325,36326,36327,36328,36329,36330,13939,13940,36331,36332,13941, +36333,36334,36335,13942,36336,36337,36338,36339,36340,36341,36342,13943,13944, +36343,13945,13946,13947,13948,36344,36345,36346,13949,13950,14113,14114,36347, +36348,14115,36349,36350,36417,14116,36418,36419,36420,36421,36422,36423,36424, +14117,14118,36425,14119,14120,14121,36426,36427,36428,36429,36430,36431,14122, +14123,36432,36433,14124,36434,36435,36436,36437,36438,36439,36440,36441,36442, +36449,36450,36451,36452,36453,14125,36454,14126,36455,36456,36457,36458,36459, +36460,36461,36462,36463,36464,36465,36466,36467,36468,36469,36470,36471,36472, +36473,36474,36481,36482,36483,36484,36485,36486,36487,36488,36489,36490,36491, +36492,36493,36494,14127,14128,36495,36496,14129,36497,36498,36499,14130,36500, +36501,36502,36503,36504,36505,36506,14131,14132,36507,14133,14134,14135,36508, +36509,36510,36511,36512,14136,14137,14138,36513,36514,14139,36515,36516,36517, +14140,36518,36519,36520,36521,36522,36523,36524,14141,14142,36525,14143,36526, +14144,36527,36528,36529,36530,36531,36532,14145,14146,36533,36534,14147,36535, +36536,36537,14148,36538,36539,36540,36541,36542,36543,36544,14149,14150,36545, +14151,14152,14153,36546,36547,36548,36549,36550,36551,14154,36552,36553,36554, +14155,36555,36556,36557,36558,36559,36560,36561,36562,36563,36564,36565,36566, +14156,36567,14157,36568,36569,36570,36571,36572,36573,36574,36575,14158,14159, +36576,36577,14160,36578,36579,36580,14161,36581,36582,36583,36584,36585,36586, +36587,14162,14163,36588,14164,36589,14165,36590,36591,36592,36593,36594,36595, +14166,36596,36597,36598,14167,36599,36600,36601,36602,36603,36604,36605,36606, +36673,36674,36675,36676,36677,36678,36679,36680,14168,36681,36682,36683,36684, +36685,36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697, +36698,36705,36706,36707,36708,36709,36710,36711,36712,14169,36713,36714,36715, +36716,36717,36718,36719,14170,36720,36721,36722,14171,36723,36724,36725,14172, +36726,36727,36728,36729,36730,36737,36738,14173,14174,36739,14175,36740,14176, +36741,36742,36743,36744,36745,36746,14177,36747,36748,36749,14178,36750,36751, +36752,14179,36753,36754,36755,36756,36757,36758,36759,36760,14180,36761,14181, +36762,14182,36763,36764,36765,36766,36767,36768,14183,14184,36769,36770,14185, +36771,36772,36773,14186,36774,36775,36776,36777,36778,36779,36780,14187,14188, +36781,14189,36782,14190,36783,36784,36785,36786,36787,36788,14191,36789,36790, +36791,36792,36793,36794,36795,36796,36797,36798,36799,36800,36801,36802,36803, +36804,36805,36806,36807,14192,36808,36809,36810,36811,36812,36813,36814,14193, +36815,36816,36817,36818,36819,36820,36821,36822,36823,36824,36825,36826,36827, +36828,36829,36830,36831,36832,36833,36834,36835,36836,36837,36838,36839,36840, +36841,14194,14195,36842,36843,14196,36844,36845,36846,14197,36847,36848,36849, +36850,36851,36852,36853,14198,36854,36855,14199,36856,14200,36857,36858,36859, +36860,36861,36862,14201,14202,36929,36930,14203,36931,36932,36933,14204,36934, +36935,36936,36937,36938,36939,36940,14205,14206,36941,14369,36942,14370,36943, +36944,36945,36946,36947,36948,14371,14372,36949,36950,14373,36951,36952,36953, +14374,36954,36961,36962,36963,36964,36965,36966,14375,14376,36967,14377,36968, +14378,14379,36969,36970,14380,14381,36971,36972,36973,36974,36975,36976,36977, +36978,36979,36980,36981,36982,36983,36984,36985,36986,36993,36994,36995,36996, +36997,36998,36999,37000,37001,37002,37003,37004,37005,14382,14383,37006,37007, +14384,37008,37009,37010,14385,37011,37012,37013,37014,37015,37016,37017,14386, +14387,37018,14388,37019,14389,37020,37021,37022,37023,37024,37025,14390,14391, +37026,37027,14392,37028,14393,14394,14395,14396,14397,37029,37030,37031,37032, +37033,14398,14399,37034,14400,37035,14401,14402,37036,37037,14403,37038,14404, +14405,14406,37039,37040,14407,37041,37042,37043,14408,37044,37045,37046,37047, +37048,37049,37050,14409,14410,37051,14411,14412,14413,14414,37052,37053,37054, +37055,37056,14415,14416,37057,37058,37059,37060,37061,37062,14417,37063,37064, +37065,37066,37067,37068,37069,37070,37071,37072,37073,37074,14418,37075,37076, +37077,37078,37079,37080,37081,37082,37083,37084,37085,37086,37087,37088,37089, +37090,37091,37092,37093,37094,37095,37096,37097,37098,37099,37100,37101,37102, +37103,37104,37105,37106,37107,37108,14419,14420,37109,37110,14421,37111,37112, +37113,14422,37114,14423,37115,37116,37117,37118,37185,14424,14425,37186,14426, +37187,14427,14428,37188,37189,37190,37191,14429,14430,14431,37192,37193,14432, +37194,37195,37196,14433,37197,37198,37199,37200,37201,37202,37203,14434,14435, +37204,14436,14437,14438,37205,37206,37207,37208,37209,37210,14439,14440,37217, +37218,14441,37219,37220,37221,14442,37222,37223,37224,37225,37226,37227,37228, +37229,37230,37231,14443,14444,14445,37232,14446,37233,37234,37235,37236,14447, +37237,37238,37239,37240,37241,37242,37249,37250,37251,37252,37253,37254,37255, +37256,37257,37258,37259,37260,37261,37262,37263,37264,37265,37266,37267,37268, +37269,14448,14449,37270,14450,14451,37271,37272,37273,14452,37274,14453,37275, +37276,37277,37278,37279,14454,14455,37280,14456,37281,14457,37282,37283,37284, +37285,37286,37287,14458,37288,37289,37290,14459,37291,37292,37293,37294,37295, +37296,37297,37298,37299,37300,37301,37302,37303,37304,37305,14460,14461,37306, +37307,37308,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37319, +37320,37321,37322,37323,37324,37325,37326,37327,37328,37329,37330,37331,37332, +37333,37334,37335,37336,37337,37338,37339,14462,37340,37341,37342,14625,37343, +37344,37345,14626,37346,37347,37348,37349,37350,37351,37352,37353,14627,37354, +14628,37355,14629,37356,37357,37358,37359,37360,37361,14630,37362,37363,37364, +14631,37365,37366,37367,14632,37368,37369,37370,37371,37372,37373,37374,37441, +14633,37442,14634,37443,37444,37445,37446,37447,37448,37449,37450,14635,14636, +14637,37451,14638,37452,37453,14639,14640,14641,14642,37454,37455,37456,37457, +37458,14643,14644,37459,14645,37460,14646,37461,37462,37463,14647,37464,14648, +14649,37465,37466,37473,14650,37474,37475,37476,14651,37477,37478,37479,37480, +37481,37482,37483,37484,14652,37485,14653,37486,37487,37488,37489,37490,37491, +37492,37493,14654,37494,37495,37496,37497,37498,37505,37506,37507,37508,37509, +37510,37511,37512,37513,37514,37515,37516,37517,37518,37519,37520,37521,37522, +37523,37524,37525,37526,14655,37527,37528,37529,14656,37530,37531,37532,14657, +37533,37534,37535,37536,37537,37538,37539,37540,37541,37542,37543,37544,37545, +37546,37547,37548,37549,37550,37551,14658,37552,37553,37554,14659,37555,37556, +37557,14660,37558,37559,37560,37561,37562,37563,37564,14661,37565,37566,14662, +37567,37568,37569,37570,37571,37572,37573,37574,14663,37575,37576,37577,14664, +37578,37579,37580,14665,37581,37582,37583,37584,37585,37586,37587,14666,37588, +37589,14667,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600, +37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,37612,37613, +37614,37615,37616,37617,37618,37619,37620,37621,37622,37623,37624,37625,14668, +14669,37626,37627,14670,37628,37629,14671,14672,37630,14673,37697,37698,37699, +37700,37701,14674,14675,37702,14676,14677,14678,37703,14679,37704,14680,37705, +37706,14681,14682,14683,14684,14685,37707,37708,14686,14687,14688,14689,14690, +37709,37710,37711,37712,14691,14692,37713,14693,37714,14694,37715,37716,37717, +14695,37718,37719,14696,14697,37720,37721,14698,37722,37729,37730,14699,37731, +37732,37733,37734,37735,37736,37737,14700,14701,37738,14702,14703,14704,37739, +37740,37741,14705,37742,37743,14706,14707,37744,37745,14708,37746,37747,37748, +37749,37750,37751,37752,37753,37754,37761,37762,37763,14709,37764,37765,37766, +37767,37768,37769,37770,37771,37772,37773,37774,37775,37776,37777,37778,37779, +37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792, +37793,37794,37795,37796,37797,37798,37799,37800,37801,14710,14711,37802,37803, +14712,37804,37805,14713,14714,37806,14715,37807,37808,37809,37810,37811,14716, +14717,37812,14718,37813,14881,14882,37814,37815,37816,37817,37818,14883,14884, +37819,37820,14885,37821,37822,14886,14887,37823,37824,37825,37826,37827,37828, +37829,14888,14889,37830,14890,14891,14892,37831,37832,37833,37834,37835,37836, +14893,14894,37837,37838,14895,37839,37840,37841,14896,37842,37843,37844,37845, +37846,37847,37848,37849,14897,37850,14898,14899,14900,37851,37852,37853,14901, +37854,37855,14902,37856,37857,37858,14903,37859,37860,37861,37862,37863,37864, +37865,37866,37867,37868,37869,37870,37871,37872,37873,37874,37875,37876,37877, +37878,37879,37880,37881,14904,14905,14906,37882,14907,37883,37884,37885,14908, +37886,37953,37954,37955,37956,37957,37958,14909,14910,37959,14911,37960,14912, +37961,37962,37963,37964,37965,37966,14913,37967,37968,37969,14914,37970,37971, +37972,37973,37974,37975,37976,37977,37978,37985,37986,37987,37988,37989,37990, +14915,37991,37992,37993,37994,37995,37996,37997,14916,37998,37999,38000,38001, +38002,38003,38004,38005,38006,38007,38008,38009,38010,38017,38018,38019,38020, +38021,38022,14917,38023,38024,38025,38026,38027,38028,38029,14918,14919,38030, +38031,14920,38032,38033,38034,14921,38035,38036,38037,38038,38039,38040,38041, +14922,14923,38042,38043,38044,38045,38046,38047,38048,38049,38050,38051,14924, +38052,38053,38054,14925,38055,38056,38057,38058,38059,38060,38061,38062,38063, +38064,38065,38066,38067,38068,38069,38070,38071,38072,38073,38074,38075,38076, +38077,14926,14927,38078,38079,14928,38080,38081,14929,14930,14931,14932,38082, +38083,38084,38085,38086,14933,14934,38087,14935,38088,14936,38089,38090,38091, +14937,14938,38092,14939,38093,38094,38095,38096,38097,38098,38099,14940,38100, +38101,38102,38103,38104,38105,38106,38107,38108,38109,38110,14941,38111,38112, +38113,38114,38115,38116,38117,14942,38118,38119,38120,38121,38122,38123,38124, +38125,38126,38127,38128,38129,38130,38131,38132,38133,38134,38135,38136,38137, +38138,38139,38140,38141,38142,38209,38210,14943,14944,38211,38212,14945,38213, +38214,38215,14946,38216,38217,38218,38219,38220,38221,38222,38223,38224,38225, +38226,38227,14947,38228,38229,38230,38231,38232,38233,14948,38234,38241,38242, +14949,38243,38244,38245,14950,38246,38247,38248,38249,38250,38251,38252,14951, +38253,38254,14952,38255,14953,38256,38257,38258,38259,38260,38261,14954,14955, +38262,38263,14956,38264,38265,38266,14957,38273,38274,38275,38276,38277,38278, +38279,14958,14959,38280,14960,38281,38282,38283,38284,38285,38286,38287,38288, +38289,38290,38291,38292,38293,38294,38295,38296,38297,38298,38299,38300,38301, +38302,38303,38304,38305,38306,38307,38308,38309,38310,38311,38312,38313,38314, +38315,38316,14961,14962,38317,38318,14963,38319,38320,38321,14964,38322,14965, +38323,38324,38325,38326,38327,14966,14967,38328,14968,38329,14969,14970,14971, +38330,38331,38332,38333,14972,14973,38334,38335,14974,38336,38337,38338,15137, +38339,15138,38340,38341,38342,38343,38344,15139,15140,38345,15141,15142,15143, +38346,38347,38348,38349,38350,15144,15145,15146,38351,38352,15147,38353,38354, +38355,15148,38356,38357,38358,38359,38360,38361,38362,15149,15150,38363,15151, +15152,15153,38364,38365,38366,38367,38368,38369,15154,15155,38370,38371,38372, +38373,38374,38375,38376,38377,38378,38379,38380,38381,38382,38383,15156,38384, +38385,38386,38387,38388,38389,38390,38391,38392,38393,38394,38395,38396,38397, +38398,38465,38466,38467,38468,38469,38470,38471,38472,38473,38474,38475,38476, +38477,38478,38479,38480,38481,38482,38483,38484,38485,38486,38487,38488,15157, +15158,38489,38490,15159,38497,38498,15160,15161,38499,38500,38501,38502,38503, +38504,38505,15162,38506,38507,15163,15164,15165,38508,38509,38510,38511,38512, +38513,15166,38514,38515,38516,38517,38518,38519,38520,38521,38522,38529,38530, +38531,38532,38533,38534,38535,38536,38537,38538,38539,15167,38540,38541,38542, +38543,38544,38545,15168,15169,38546,38547,38548,38549,38550,38551,38552,38553, +38554,38555,38556,38557,38558,38559,15170,15171,38560,15172,15173,15174,38561, +38562,38563,38564,38565,38566,38567,38568,38569,38570,38571,38572,38573,38574, +38575,38576,38577,38578,38579,38580,38581,38582,38583,38584,38585,38586,38587, +38588,38589,38590,38591,38592,38593,38594,15175,15176,38595,38596,15177,38597, +38598,38599,15178,38600,38601,38602,38603,38604,38605,38606,15179,15180,38607, +38608,38609,15181,38610,38611,38612,38613,38614,38615,38616,38617,38618,38619, +38620,38621,38622,38623,38624,38625,38626,38627,38628,38629,38630,38631,38632, +38633,38634,38635,38636,38637,38638,38639,38640,38641,38642,38643,38644,38645, +38646,38647,38648,38649,38650,38651,38652,38653,38654,38721,38722,38723,38724, +38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737, +15182,38738,38739,38740,38741,38742,38743,38744,38745,38746,38753,38754,38755, +38756,38757,38758,38759,38760,38761,38762,38763,38764,38765,38766,38767,38768, +38769,38770,15183,38771,38772,38773,38774,38775,38776,38777,38778,38785,38786, +38787,38788,38789,38790,38791,38792,38793,38794,38795,38796,15184,38797,38798, +38799,38800,38801,38802,15185,15186,38803,38804,15187,38805,38806,38807,15188, +38808,38809,38810,38811,38812,38813,38814,15189,38815,38816,15190,38817,15191, +38818,38819,38820,38821,38822,38823,38824,38825,38826,38827,38828,38829,38830, +38831,38832,38833,38834,38835,38836,38837,38838,38839,38840,38841,38842,38843, +38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856, +38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869, +38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882, +38883,38884,38885,38886,38887,38888,38889,38890,38891,38892,38893,38894,38895, +38896,38897,38898,38899,38900,38901,38902,38903,38904,38905,38906,38907,15192, +38908,38909,38910,38977,38978,38979,38980,38981,38982,38983,38984,38985,38986, +38987,38988,38989,38990,38991,38992,38993,15193,38994,38995,38996,38997,38998, +38999,15194,39000,39001,39002,15195,39009,39010,39011,15196,39012,39013,39014, +39015,39016,39017,39018,15197,15198,39019,39020,39021,39022,39023,39024,39025, +39026,39027,39028,39029,39030,39031,39032,39033,39034,39041,39042,39043,39044, +39045,39046,39047,39048,39049,39050,39051,39052,39053,39054,39055,39056,39057, +39058,39059,39060,39061,39062,15199,15200,39063,39064,15201,39065,39066,39067, +15202,39068,39069,39070,39071,39072,39073,39074,15203,15204,39075,15205,39076, +15206,39077,39078,39079,39080,39081,39082,15207,15208,39083,15209,15210,39084, +39085,15211,15212,15213,15214,39086,39087,39088,39089,39090,15215,15216,39091, +15217,15218,15219,39092,39093,39094,15220,39095,39096,15221,15222,39097,39098, +15223,39099,39100,39101,15224,39102,39103,39104,39105,39106,39107,39108,15225, +15226,39109,15227,15228,15229,39110,39111,39112,39113,39114,39115,15230,15393, +39116,39117,15394,39118,39119,39120,15395,39121,39122,39123,39124,39125,39126, +39127,15396,15397,39128,15398,39129,15399,39130,39131,39132,39133,39134,39135, +15400,39136,39137,39138,15401,39139,39140,39141,15402,39142,39143,39144,39145, +39146,39147,39148,15403,39149,39150,39151,39152,15404,39153,39154,39155,39156, +39157,39158,15405,15406,15407,15408,15409,39159,39160,15410,15411,39161,15412, +15413,39162,39163,39164,39165,15414,15415,39166,15416,15417,15418,39233,39234, +39235,39236,15419,39237,15420,15421,39238,39239,15422,39240,39241,39242,15423, +39243,39244,39245,39246,39247,39248,39249,15424,15425,39250,15426,15427,15428, +39251,39252,39253,39254,39255,39256,15429,15430,39257,39258,15431,39265,39266, +39267,15432,39268,39269,39270,39271,39272,39273,39274,15433,15434,39275,15435, +15436,15437,39276,39277,39278,39279,39280,39281,15438,39282,39283,39284,15439, +39285,39286,39287,15440,39288,39289,39290,39297,39298,39299,39300,39301,39302, +39303,39304,39305,15441,39306,39307,39308,39309,39310,39311,15442,15443,15444, +39312,15445,39313,39314,39315,15446,39316,15447,39317,39318,39319,39320,39321, +15448,15449,39322,15450,39323,15451,39324,39325,39326,15452,39327,39328,15453, +15454,39329,39330,15455,39331,39332,39333,15456,39334,39335,39336,39337,39338, +39339,39340,39341,39342,39343,39344,39345,15457,39346,39347,39348,39349,39350, +39351,15458,39352,39353,39354,15459,39355,39356,39357,15460,39358,39359,39360, +39361,39362,39363,39364,15461,39365,39366,15462,15463,39367,39368,39369,39370, +39371,39372,39373,15464,39374,39375,39376,15465,39377,39378,39379,15466,39380, +39381,39382,39383,39384,39385,39386,15467,15468,39387,15469,39388,39389,39390, +39391,39392,39393,39394,39395,15470,15471,39396,39397,15472,39398,39399,39400, +15473,39401,39402,39403,39404,39405,39406,39407,15474,15475,39408,15476,39409, +15477,39410,39411,39412,39413,39414,39415,15478,15479,39416,39417,15480,39418, +39419,15481,15482,39420,39421,39422,39489,39490,39491,39492,15483,15484,39493, +15485,39494,15486,39495,15649,39496,15650,15651,39497,15652,39498,39499,39500, +39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513, +39514,39521,39522,15653,39523,39524,39525,39526,39527,39528,39529,15654,15655, +39530,39531,15656,39532,39533,39534,15657,39535,39536,39537,39538,39539,39540, +39541,15658,39542,39543,39544,39545,15659,39546,39553,39554,39555,39556,39557, +15660,15661,39558,39559,15662,39560,39561,39562,15663,39563,39564,39565,39566, +39567,39568,39569,15664,15665,39570,15666,39571,15667,39572,39573,39574,39575, +39576,39577,15668,15669,39578,39579,39580,39581,39582,39583,15670,39584,39585, +39586,39587,39588,39589,39590,15671,39591,39592,15672,39593,15673,39594,39595, +39596,39597,39598,39599,15674,15675,39600,39601,15676,39602,39603,39604,15677, +15678,39605,39606,39607,39608,39609,39610,15679,15680,39611,15681,39612,15682, +39613,39614,39615,39616,39617,39618,39619,39620,39621,39622,39623,39624,39625, +39626,39627,39628,39629,39630,39631,39632,39633,39634,39635,39636,39637,39638, +39639,39640,39641,39642,39643,39644,39645,39646,15683,15684,39647,39648,15685, +39649,39650,15686,15687,39651,39652,39653,39654,39655,39656,15688,15689,15690, +39657,15691,39658,15692,39659,39660,39661,39662,15693,39663,15694,15695,39664, +15696,15697,39665,39666,39667,15698,39668,39669,39670,39671,39672,39673,39674, +15699,15700,39675,39676,15701,15702,39677,39678,39745,39746,39747,15703,15704, +15705,39748,39749,15706,39750,39751,39752,15707,39753,39754,39755,39756,39757, +39758,39759,15708,15709,39760,39761,15710,15711,39762,39763,39764,39765,39766, +39767,39768,39769,39770,39777,39778,39779,39780,39781,39782,39783,39784,39785, +39786,39787,39788,39789,39790,39791,39792,39793,39794,15712,39795,39796,39797, +39798,39799,39800,39801,39802,39809,39810,39811,39812,39813,39814,39815,39816, +39817,39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829, +39830,39831,39832,39833,39834,15713,15714,39835,39836,15715,39837,39838,39839, +15716,39840,15717,39841,39842,39843,39844,39845,15718,15719,39846,39847,15720, +15721,39848,39849,39850,39851,39852,39853,15722,39854,39855,39856,15723,39857, +39858,39859,15724,39860,39861,39862,39863,39864,39865,39866,39867,39868,39869, +39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881,39882, +39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894,39895, +39896,39897,39898,39899,39900,39901,39902,39903,39904,39905,39906,39907,39908, +39909,39910,15725,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920, +39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933, +15726,15727,39934,40001,15728,40002,40003,15729,15730,40004,15731,40005,40006, +40007,40008,40009,15732,15733,40010,40011,40012,15734,40013,40014,40015,40016, +40017,40018,15735,15736,40019,40020,15737,40021,40022,40023,40024,40025,40026, +40033,40034,40035,40036,40037,40038,40039,40040,40041,15738,40042,40043,40044, +40045,40046,40047,40048,15739,40049,40050,40051,40052,40053,40054,40055,40056, +40057,40058,40065,40066,40067,40068,40069,40070,40071,40072,40073,15740,40074, +40075,40076,40077,40078,40079,40080,15741,40081,40082,40083,15742,40084,40085, +40086,15905,40087,40088,40089,40090,40091,40092,40093,15906,15907,40094,40095, +40096,40097,40098,40099,40100,40101,40102,40103,15908,40104,40105,40106,40107, +40108,40109,40110,40111,40112,40113,40114,40115,40116,40117,40118,40119,40120, +40121,40122,40123,40124,40125,40126,40127,40128,40129,40130,15909,15910,40131, +40132,15911,40133,40134,40135,15912,40136,40137,40138,40139,40140,40141,40142, +15913,15914,40143,40144,40145,15915,40146,40147,40148,40149,40150,40151,15916, +40152,40153,40154,40155,40156,40157,40158,40159,40160,40161,40162,40163,40164, +40165,40166,40167,40168,40169,40170,15917,40171,40172,40173,40174,40175,40176, +40177,15918,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188, +40189,40190,40257,40258,40259,40260,40261,40262,40263,40264,40265,40266,40267, +40268,40269,40270,15919,40271,40272,40273,15920,40274,40275,40276,40277,40278, +40279,40280,40281,40282,40289,40290,40291,40292,40293,40294,40295,40296,40297, +40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,40309,40310, +40311,40312,40313,40314,40321,40322,40323,40324,40325,40326,40327,40328,40329, +15921,40330,40331,40332,40333,40334,40335,15922,15923,40336,40337,15924,40338, +40339,40340,15925,40341,15926,40342,40343,40344,40345,15927,15928,15929,40346, +40347,40348,40349,40350,40351,40352,40353,40354,40355,15930,40356,40357,40358, +15931,40359,40360,40361,15932,40362,40363,40364,40365,40366,40367,40368,15933, +40369,40370,40371,40372,40373,40374,40375,40376,40377,40378,40379,15934,15935, +40380,40381,15936,40382,40383,40384,15937,40385,40386,40387,40388,40389,40390, +40391,15938,15939,40392,15940,40393,15941,40394,40395,40396,40397,40398,40399, +15942,15943,40400,40401,15944,15945,15946,40402,15947,15948,15949,40403,40404, +40405,40406,15950,15951,15952,40407,15953,15954,15955,40408,40409,40410,15956, +15957,40411,15958,15959,40412,40413,15960,40414,40415,40416,15961,40417,40418, +40419,40420,40421,40422,40423,15962,15963,40424,15964,15965,15966,40425,40426, +40427,40428,40429,40430,15967,15968,40431,40432,15969,40433,40434,40435,15970, +40436,40437,15971,40438,40439,40440,40441,15972,15973,40442,15974,40443,15975, +40444,40445,40446,15976,40513,15977,15978,40514,40515,40516,15979,40517,40518, +40519,15980,40520,40521,40522,40523,40524,40525,40526,40527,15981,40528,40529, +40530,40531,40532,40533,40534,40535,40536,40537,15982,15983,40538,40545,15984, +15985,40546,15986,15987,15988,15989,40547,40548,40549,40550,40551,15990,15991, +15992,15993,15994,15995,15996,40552,15997,40553,15998,40554,16161,16162,40555, +40556,16163,40557,40558,40559,16164,40560,40561,40562,40563,40564,40565,40566, +16165,16166,40567,16167,40568,16168,40569,40570,40577,40578,40579,40580,16169, +16170,16171,40581,16172,40582,40583,40584,16173,40585,16174,16175,40586,40587, +40588,40589,16176,16177,16178,16179,16180,16181,40590,40591,40592,16182,16183, +16184,16185,40593,40594,40595,16186,40596,40597,40598,16187,40599,40600,40601, +40602,40603,40604,40605,16188,16189,40606,16190,16191,40607,40608,40609,40610, +40611,40612,40613,16192,16193,40614,40615,16194,40616,40617,40618,16195,16196, +16197,40619,16198,40620,40621,16199,16200,16201,40622,16202,40623,16203,40624, +16204,40625,40626,40627,40628,16205,16206,40629,40630,16207,40631,40632,40633, +16208,40634,40635,40636,40637,40638,40639,40640,16209,16210,40641,16211,16212, +16213,40642,40643,40644,40645,40646,40647,16214,16215,40648,40649,16216,40650, +40651,40652,40653,40654,40655,40656,40657,40658,40659,40660,16217,40661,40662, +16218,40663,16219,40664,40665,40666,40667,40668,40669,16220,16221,40670,40671, +16222,40672,40673,40674,16223,40675,40676,40677,40678,40679,40680,40681,16224, +16225,40682,16226,40683,16227,40684,40685,40686,40687,40688,40689,16228,16229, +40690,40691,16230,40692,40693,40694,16231,40695,40696,40697,40698,40699,40700, +40701,16232,16233,40702,16234,40769,16235,40770,40771,40772,40773,40774,40775, +16236,16237,40776,40777,16238,40778,40779,40780,16239,16240,16241,40781,40782, +40783,40784,40785,16242,16243,40786,16244,40787,16245,40788,40789,40790,40791, +40792,40793,16246,16247,40794,40801,16248,40802,40803,40804,16249,40805,40806, +40807,40808,40809,40810,40811,16250,16251,40812,40813,16252,16253,40814,40815, +40816,40817,40818,40819,16254,16417,40820,40821,16418,40822,40823,40824,16419, +40825,40826,40833,40834,40835,40836,40837,16420,16421,40838,40839,40840,16422, +40841,40842,40843,40844,40845,40846,16423,16424,40847,40848,16425,40849,40850, +40851,16426,40852,40853,40854,40855,40856,40857,40858,16427,16428,40859,16429, +40860,16430,40861,40862,40863,40864,40865,40866,16431,16432,40867,40868,16433, +40869,40870,40871,16434,40872,40873,40874,40875,40876,40877,40878,16435,16436, +40879,16437,40880,16438,40881,16439,40882,40883,40884,40885,16440,16441,40886, +40887,16442,40888,40889,40890,16443,40891,40892,40893,40894,40895,16444,40896, +16445,16446,40897,16447,40898,16448,16449,16450,16451,16452,16453,16454,16455, +40899,40900,40901,16456,40902,40903,40904,16457,40905,40906,40907,40908,40909, +40910,40911,16458,40912,40913,16459,40914,40915,40916,40917,40918,40919,40920, +40921,16460,16461,40922,40923,16462,40924,40925,40926,16463,16464,16465,40927, +40928,40929,40930,16466,16467,16468,40931,16469,16470,16471,16472,40932,40933, +40934,16473,40935,16474,16475,40936,40937,16476,40938,16477,16478,16479,40939, +16480,40940,40941,40942,40943,40944,16481,16482,40945,16483,16484,16485,16486, +40946,40947,40948,40949,40950,16487,16488,40951,40952,16489,40953,40954,40955, +16490,40956,40957,40958,41025,41026,41027,41028,16491,16492,41029,16493,16494, +16495,41030,41031,41032,41033,41034,41035,16496,16497,41036,41037,16498,41038, +16499,41039,16500,41040,41041,41042,41043,41044,41045,41046,16501,41047,41048, +41049,41050,16502,41057,41058,41059,41060,41061,41062,16503,41063,41064,41065, +16504,41066,41067,41068,16505,41069,41070,41071,41072,41073,41074,41075,41076, +41077,41078,41079,41080,41081,41082,41089,41090,41091,41092,41093,16506,16507, +41094,41095,16508,41096,41097,41098,16509,41099,16510,41100,41101,41102,41103, +41104,16673,16674,41105,16675,41106,16676,16677,41107,41108,41109,41110,41111, +16678,16679,41112,41113,16680,41114,41115,41116,16681,41117,41118,41119,41120, +41121,41122,41123,16682,16683,41124,16684,41125,16685,41126,41127,41128,41129, +41130,41131,16686,41132,41133,41134,16687,41135,41136,41137,16688,41138,41139, +41140,41141,41142,41143,41144,16689,16690,41145,41146,16691,16692,41147,41148, +41149,41150,41151,41152,16693,41153,41154,41155,41156,41157,41158,41159,41160, +41161,41162,41163,41164,41165,41166,41167,41168,41169,41170,41171,41172,41173, +41174,41175,41176,41177,41178,41179,16694,16695,41180,41181,16696,41182,41183, +41184,16697,41185,16698,41186,41187,41188,41189,41190,16699,16700,41191,16701, +41192,16702,16703,16704,41193,41194,41195,16705,16706,16707,41196,41197,41198, +41199,41200,41201,16708,41202,41203,41204,41205,41206,41207,41208,41209,16709, +41210,16710,41211,16711,41212,41213,41214,41281,41282,41283,16712,41284,41285, +41286,41287,41288,41289,41290,41291,41292,41293,41294,41295,41296,41297,41298, +41299,41300,41301,41302,16713,16714,41303,41304,41305,41306,41313,41314,16715, +41315,41316,41317,16716,41318,41319,41320,16717,41321,41322,41323,41324,41325, +41326,41327,16718,16719,41328,16720,41329,16721,41330,41331,41332,41333,41334, +41335,16722,16723,41336,41337,16724,41338,41345,41346,41347,41348,41349,41350, +41351,41352,41353,41354,41355,41356,41357,41358,41359,16725,41360,41361,41362, +41363,41364,41365,16726,16727,41366,41367,16728,41368,41369,41370,16729,16730, +16731,41371,41372,41373,41374,41375,16732,16733,41376,16734,41537,16735,41538, +41539,41540,41541,41542,41543,16736,41544,41545,41546,41547,41548,41549,41550, +41551,41552,41553,41554,41555,41556,41557,41558,41559,41560,41561,41562,16737, +41569,41570,41571,41572,41573,41574,41575,16738,41576,41577,41578,41579,41580, +41581,41582,41583,41584,41585,41586,41587,41588,41589,41590,41591,41592,41593, +41594,41601,41602,41603,41604,41605,41606,41607,41608,16739,16740,41609,41610, +16741,41611,41612,41613,16742,41614,41615,41616,41617,41618,41619,41620,16743, +16744,41621,16745,41622,41623,41624,41625,41626,41627,41628,41629,16746,41630, +41631,41632,16747,41793,41794,41795,16748,41796,41797,41798,41799,41800,41801, +41802,16749,41803,41804,41805,41806,41807,41808,41809,41810,41811,41812,41813, +16750,16751,41814,41815,16752,41816,41817,41818,16753,41825,41826,41827,41828, +41829,41830,41831,16754,16755,41832,16756,41833,16757,41834,41835,41836,41837, +41838,41839,41840,41841,41842,41843,41844,41845,41846,41847,41848,41849,41850, +41857,41858,41859,41860,41861,41862,41863,41864,41865,41866,41867,41868,41869, +41870,41871,41872,41873,16758,16759,41874,41875,16760,41876,41877,16761,16762, +41878,16763,41879,41880,41881,41882,41883,16764,16765,41884,16766,41885,16929, +16930,41886,41887,16931,16932,41888,16933,16934,42049,42050,16935,42051,16936, +42052,16937,42053,42054,16938,42055,42056,42057,42058,16939,16940,42059,16941, +16942,16943,42060,42061,42062,42063,42064,42065,16944,16945,42066,42067,16946, +42068,42069,42070,16947,42071,42072,42073,42074,42081,42082,42083,16948,16949, +42084,16950,16951,16952,42085,42086,42087,42088,42089,42090,16953,42091,42092, +42093,16954,42094,42095,42096,42097,42098,42099,42100,42101,42102,42103,42104, +42105,42106,42113,42114,42115,16955,42116,42117,42118,42119,42120,42121,42122, +42123,42124,42125,42126,42127,42128,42129,42130,42131,42132,42133,42134,42135, +42136,42137,42138,42139,42140,42141,42142,42143,42144,42305,42306,42307,42308, +42309,16956,16957,42310,42311,16958,42312,42313,42314,16959,42315,42316,42317, +42318,42319,42320,42321,16960,16961,42322,16962,16963,16964,42323,42324,42325, +42326,42327,42328,16965,42329,42330,42337,42338,42339,42340,42341,42342,42343, +42344,42345,42346,42347,42348,42349,42350,42351,42352,42353,42354,16966,42355, +42356,42357,42358,42359,42360,16967,42361,42362,42369,42370,42371,42372,42373, +42374,42375,42376,42377,42378,42379,42380,42381,42382,42383,42384,42385,16968, +42386,42387,42388,42389,42390,42391,42392,42393,42394,42395,42396,42397,42398, +42399,42400,42561,42562,42563,42564,42565,42566,42567,42568,42569,42570,42571, +42572,42573,42574,42575,42576,42577,42578,42579,42580,16969,16970,42581,42582, +16971,42583,42584,42585,16972,42586,42593,42594,42595,42596,42597,42598,16973, +16974,42599,16975,42600,16976,42601,16977,42602,42603,42604,42605,16978,16979, +42606,42607,42608,42609,42610,42611,16980,42612,42613,42614,42615,42616,42617, +42618,42625,42626,42627,42628,16981,42629,42630,42631,42632,42633,42634,42635, +16982,42636,42637,42638,42639,42640,42641,42642,42643,42644,42645,42646,42647, +42648,42649,42650,42651,42652,42653,42654,16983,42655,42656,42817,42818,42819, +42820,42821,16984,42822,42823,42824,16985,42825,42826,42827,16986,42828,42829, +42830,42831,42832,42833,42834,16987,16988,42835,42836,42837,42838,42839,42840, +42841,42842,42849,42850,42851,42852,42853,42854,42855,42856,42857,42858,42859, +42860,42861,42862,42863,42864,42865,42866,42867,42868,42869,42870,42871,16989, +42872,42873,42874,42881,42882,42883,16990,16991,42884,42885,16992,42886,42887, +42888,16993,42889,42890,42891,42892,42893,42894,42895,16994,16995,42896,42897, +42898,16996,42899,42900,42901,42902,42903,42904,16997,42905,42906,42907,42908, +42909,42910,42911,42912,43073,43074,43075,43076,43077,43078,43079,43080,43081, +43082,43083,16998,16999,43084,43085,43086,43087,43088,43089,43090,43091,43092, +43093,43094,43095,43096,43097,43098,43105,43106,43107,43108,43109,43110,43111, +43112,43113,43114,43115,43116,43117,43118,43119,43120,43121,43122,43123,17000, +43124,43125,43126,43127,43128,43129,43130,43137,43138,43139,43140,43141,43142, +43143,43144,43145,43146,43147,43148,43149,43150,43151,43152,43153,43154,43155, +43156,17001,43157,43158,43159,43160,43161,43162,43163,43164,43165,43166,43167, +43168,43329,43330,43331,43332,43333,43334,43335,43336,43337,43338,43339,43340, +43341,43342,43343,17002,43344,43345,43346,43347,43348,43349,43350,43351,43352, +43353,43354,43361,43362,43363,43364,17003,43365,43366,17004,43367,17005,43368, +43369,43370,43371,43372,43373,43374,43375,43376,43377,43378,43379,43380,43381, +43382,43383,43384,43385,43386,43393,43394,43395,43396,43397,43398,43399,43400, +43401,43402,43403,43404,43405,43406,43407,17006,17007,43408,43409,17008,43410, +43411,43412,17009,43413,43414,43415,43416,43417,43418,43419,17010,17011,43420, +43421,43422,17012,17013,43423,43424,43585,43586,17014,17015,17016,43587,43588, +17017,43589,17018,43590,17019,43591,43592,43593,43594,43595,43596,43597,17020, +17021,43598,17022,17185,17186,17187,43599,43600,43601,43602,43603,17188,17189, +43604,43605,17190,43606,43607,43608,17191,43609,43610,43617,43618,43619,43620, +43621,17192,17193,43622,17194,17195,17196,43623,43624,43625,43626,43627,43628, +17197,43629,43630,43631,17198,43632,17199,43633,17200,43634,43635,43636,43637, +43638,43639,43640,17201,43641,43642,43649,43650,17202,43651,43652,43653,43654, +43655,43656,43657,43658,43659,43660,43661,43662,43663,43664,43665,43666,43667, +43668,43669,43670,43671,43672,43673,43674,43675,43676,43677,43678,43679,43680, +43841,43842,43843,43844,17203,17204,43845,43846,17205,43847,43848,43849,17206, +43850,43851,43852,43853,43854,43855,43856,17207,17208,43857,17209,17210,17211, +43858,43859,43860,43861,43862,43863,17212,17213,43864,43865,17214,43866,43873, +43874,17215,43875,43876,43877,43878,43879,43880,43881,17216,17217,43882,17218, +43883,17219,43884,43885,43886,43887,43888,43889,17220,43890,43891,43892,17221, +43893,43894,43895,43896,43897,43898,43905,43906,43907,43908,43909,43910,43911, +43912,43913,17222,43914,43915,43916,43917,43918,43919,43920,17223,43921,43922, +43923,17224,43924,43925,43926,43927,43928,43929,43930,43931,43932,43933,43934, +43935,43936,44097,44098,44099,17225,44100,44101,44102,44103,44104,44105,17226, +17227,44106,44107,17228,44108,44109,44110,17229,44111,44112,44113,44114,44115, +44116,44117,17230,17231,44118,17232,44119,17233,44120,44121,44122,44129,44130, +44131,17234,44132,44133,44134,17235,44135,44136,44137,17236,44138,44139,44140, +44141,44142,44143,44144,44145,44146,44147,44148,44149,17237,44150,44151,44152, +44153,44154,44161,44162,44163,44164,44165,44166,44167,44168,44169,44170,44171, +44172,44173,44174,44175,44176,44177,44178,44179,44180,44181,44182,44183,44184, +44185,44186,44187,44188,44189,17238,44190,44191,44192,17239,44353,44354,44355, +17240,44356,44357,44358,44359,44360,44361,44362,17241,17242,44363,17243,44364, +17244,44365,44366,44367,44368,44369,44370,17245,44371,44372,44373,44374,44375, +44376,44377,44378,44385,44386,44387,44388,44389,44390,44391,17246,44392,44393, +44394,44395,44396,44397,44398,44399,44400,44401,44402,17247,17248,44403,44404, +17249,44405,44406,44407,17250,44408,44409,44410,44417,44418,44419,44420,17251, +17252,44421,17253,44422,17254,44423,44424,44425,44426,44427,44428,17255,44429, +44430,44431,44432,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442, +44443,44444,44445,44446,44447,17256,44448,44609,44610,44611,44612,44613,44614, +17257,44615,44616,44617,17258,44618,44619,44620,44621,44622,44623,44624,44625, +44626,44627,44628,44629,44630,44631,44632,44633,44634,44641,44642,44643,44644, +44645,44646,17259,44647,44648,44649,17260,44650,44651,44652,17261,44653,44654, +44655,44656,44657,44658,44659,17262,17263,44660,17264,44661,17265,44662,44663, +44664,44665,44666,44673,17266,44674,44675,44676,17267,44677,44678,44679,17268, +44680,44681,44682,44683,44684,44685,44686,17269,44687,44688,44689,44690,17270, +44691,44692,44693,44694,44695,44696,17271,17272,44697,44698,17273,44699,44700, +44701,17274,44702,44703,44704,44865,44866,44867,44868,17275,17276,44869,17277, +44870,17278,44871,44872,44873,44874,44875,44876,44877,44878,44879,44880,44881, +44882,44883,44884,44885,44886,44887,44888,44889,44890,44897,44898,44899,44900, +44901,44902,44903,44904,44905,44906,44907,44908,44909,44910,17441,17442,44911, +44912,17443,44913,44914,17444,17445,17446,44915,44916,44917,44918,44919,44920, +17447,17448,44921,17449,44922,17450,44929,44930,44931,44932,44933,44934,17451, +17452,44935,44936,17453,44937,44938,44939,17454,44940,44941,44942,44943,44944, +44945,44946,17455,17456,44947,17457,44948,17458,44949,44950,44951,44952,44953, +44954,17459,17460,44955,44956,17461,44957,44958,44959,17462,44960,45121,45122, +45123,45124,45125,45126,17463,17464,45127,17465,17466,17467,45128,45129,45130, +45131,45132,45133,17468,17469,45134,45135,45136,45137,45138,45139,45140,45141, +45142,45143,45144,45145,45146,45153,45154,45155,45156,45157,45158,17470,45159, +45160,45161,45162,45163,45164,45165,45166,45167,45168,45169,45170,45171,45172, +45173,45174,45175,45176,45177,45178,45185,45186,45187,45188,45189,45190,45191, +45192,45193,45194,45195,45196,45197,45198,17471,17472,45199,45200,17473,45201, +45202,17474,17475,45203,45204,45205,45206,45207,45208,45209,17476,17477,45210, +17478,17479,17480,45211,45212,45213,45214,45215,45216,17481,17482,45377,45378, +17483,45379,45380,45381,17484,45382,45383,45384,45385,45386,45387,45388,17485, +17486,45389,17487,45390,17488,45391,45392,45393,45394,45395,45396,17489,45397, +45398,45399,17490,45400,45401,45402,17491,45409,45410,45411,45412,45413,45414, +45415,17492,17493,45416,17494,17495,17496,45417,45418,45419,45420,45421,45422, +17497,45423,45424,45425,45426,45427,45428,45429,45430,45431,45432,45433,45434, +45441,45442,45443,45444,45445,45446,45447,45448,45449,45450,45451,45452,45453, +45454,45455,17498,17499,45456,45457,17500,45458,45459,45460,17501,45461,45462, +45463,45464,45465,45466,45467,17502,17503,45468,17504,45469,17505,45470,45471, +45472,45633,45634,45635,17506,17507,45636,45637,17508,45638,45639,45640,17509, +45641,45642,45643,45644,45645,45646,45647,17510,45648,45649,45650,45651,17511, +45652,45653,45654,45655,45656,45657,17512,45658,45665,45666,45667,45668,45669, +45670,45671,45672,45673,45674,45675,45676,45677,45678,45679,45680,45681,45682, +45683,17513,45684,45685,45686,45687,45688,45689,17514,45690,45697,45698,45699, +45700,45701,45702,17515,45703,45704,45705,45706,45707,45708,45709,45710,45711, +45712,45713,45714,45715,45716,45717,45718,45719,45720,45721,17516,45722,45723, +45724,45725,45726,45727,45728,45889,45890,45891,45892,45893,45894,45895,45896, +45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45908,17517, +17518,45909,45910,17519,45911,45912,45913,17520,45914,45921,45922,45923,45924, +45925,45926,17521,17522,45927,17523,45928,17524,45929,45930,45931,45932,45933, +45934,17525,45935,45936,45937,17526,45938,45939,45940,17527,45941,45942,45943, +45944,45945,45946,45953,45954,45955,45956,45957,45958,17528,45959,45960,45961, +45962,45963,45964,17529,45965,45966,45967,45968,45969,45970,45971,45972,45973, +45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45984,17530,46145, +46146,46147,46148,46149,46150,17531,17532,46151,46152,17533,46153,46154,46155, +17534,46156,46157,46158,46159,46160,46161,46162,17697,17698,46163,17699,46164, +17700,46165,46166,46167,46168,46169,46170,17701,46177,46178,46179,17702,46180, +46181,46182,17703,46183,46184,46185,46186,46187,46188,46189,17704,46190,46191, +46192,46193,46194,46195,46196,46197,46198,46199,46200,17705,17706,46201,46202, +17707,46209,46210,46211,17708,46212,46213,46214,46215,46216,46217,46218,17709, +17710,46219,46220,46221,17711,46222,46223,46224,46225,46226,46227,46228,46229, +46230,46231,46232,46233,46234,46235,46236,46237,46238,46239,46240,46401,46402, +46403,46404,46405,46406,46407,46408,46409,46410,46411,46412,46413,46414,46415, +17712,17713,46416,46417,17714,46418,46419,46420,17715,46421,46422,46423,46424, +46425,46426,46433,17716,17717,46434,17718,46435,17719,46436,46437,46438,46439, +46440,46441,17720,17721,46442,46443,17722,46444,46445,46446,17723,17724,46447, +46448,46449,46450,46451,46452,17725,17726,46453,17727,17728,17729,46454,46455, +46456,46457,46458,46465,17730,17731,46466,46467,17732,46468,46469,46470,17733, +46471,46472,46473,46474,46475,46476,46477,17734,17735,46478,17736,17737,17738, +46479,46480,46481,46482,46483,46484,17739,46485,46486,46487,46488,46489,46490, +46491,46492,46493,46494,46495,46496,46657,46658,46659,46660,46661,46662,46663, +46664,17740,46665,46666,46667,46668,46669,46670,46671,46672,46673,46674,46675, +46676,46677,46678,46679,46680,46681,46682,46689,46690,46691,46692,46693,46694, +46695,46696,46697,46698,46699,46700,46701,46702,46703,46704,17741,17742,46705, +46706,17743,46707,46708,46709,17744,46710,17745,46711,46712,46713,46714,46721, +17746,17747,46722,17748,17749,17750,46723,46724,46725,46726,46727,46728,17751, +17752,46729,46730,17753,46731,46732,46733,17754,46734,46735,46736,46737,46738, +46739,46740,17755,17756,46741,17757,46742,17758,46743,46744,46745,46746,46747, +46748,17759,46749,46750,46751,17760,46752,46913,46914,46915,46916,46917,46918, +46919,46920,46921,46922,46923,46924,46925,46926,17761,46927,46928,46929,46930, +46931,46932,46933,17762,46934,46935,46936,17763,46937,46938,46945,46946,46947, +46948,46949,46950,46951,46952,46953,46954,46955,46956,46957,46958,46959,46960, +46961,46962,46963,46964,46965,17764,17765,46966,46967,17766,46968,46969,46970, +17767,46977,46978,46979,46980,46981,46982,46983,17768,17769,46984,17770,46985, +17771,46986,46987,46988,46989,17772,46990,17773,46991,46992,46993,17774,46994, +46995,46996,46997,46998,46999,47000,47001,47002,47003,47004,47005,47006,47007, +47008,47169,47170,47171,47172,47173,47174,47175,47176,17775,47177,47178,47179, +47180,47181,47182,47183,47184,47185,47186,47187,47188,47189,47190,47191,47192, +47193,47194,47201,47202,47203,47204,47205,47206,47207,47208,47209,17776,47210, +47211,47212,17777,47213,47214,47215,47216,47217,47218,47219,47220,47221,47222, +47223,47224,47225,47226,17778,47233,17779,47234,47235,47236,47237,47238,47239, +17780,47240,47241,47242,47243,47244,47245,47246,47247,47248,47249,47250,47251, +47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263,47264, +47425,47426,17781,17782,47427,47428,17783,47429,47430,47431,17784,47432,47433, +47434,47435,47436,47437,47438,17785,17786,47439,17787,47440,17788,47441,47442, +47443,47444,47445,47446,17789,47447,47448,47449,47450,47457,47458,47459,47460, +47461,47462,47463,47464,47465,47466,47467,47468,47469,47470,47471,17790,47472, +47473,47474,47475,47476,47477,47478,17953,47479,47480,47481,47482,47489,47490, +47491,47492,47493,47494,47495,47496,47497,47498,47499,47500,47501,47502,47503, +47504,47505,47506,47507,47508,47509,47510,47511,17954,17955,47512,47513,17956, +47514,47515,47516,17957,47517,47518,47519,47520,47681,47682,47683,17958,17959, +47684,47685,47686,17960,47687,47688,47689,47690,47691,47692,17961,47693,47694, +47695,17962,47696,47697,47698,17963,47699,47700,47701,47702,47703,47704,47705, +17964,47706,47713,47714,47715,17965,47716,47717,47718,47719,47720,47721,17966, +17967,47722,47723,17968,47724,47725,17969,17970,47726,17971,47727,47728,47729, +47730,47731,17972,17973,47732,17974,47733,47734,47735,47736,47737,47738,47745, +47746,17975,47747,47748,47749,17976,47750,47751,47752,17977,47753,47754,47755, +47756,47757,47758,47759,17978,17979,47760,47761,47762,47763,47764,47765,47766, +47767,47768,47769,17980,17981,47770,47771,17982,47772,47773,47774,17983,47775, +47776,47937,47938,47939,47940,47941,17984,17985,47942,17986,47943,17987,47944, +47945,47946,47947,47948,47949,17988,17989,17990,47950,17991,47951,47952,47953, +17992,47954,17993,47955,47956,47957,47958,47959,17994,17995,47960,17996,17997, +17998,47961,47962,47969,17999,47970,47971,18000,18001,47972,47973,18002,47974, +47975,47976,18003,47977,47978,47979,47980,47981,47982,47983,18004,18005,47984, +18006,18007,18008,47985,47986,47987,47988,47989,47990,18009,18010,47991,47992, +47993,47994,48001,48002,48003,48004,48005,48006,48007,48008,48009,48010,48011, +48012,48013,48014,48015,48016,48017,48018,48019,48020,48021,48022,48023,48024, +48025,48026,48027,48028,48029,48030,48031,48032,48193,48194,48195,48196,48197, +48198,48199,48200,48201,48202,48203,48204,48205,48206,48207,48208,48209,48210, +18011,18012,48211,48212,18013,48213,48214,48215,18014,48216,48217,48218,48225, +48226,48227,48228,18015,18016,48229,18017,18018,18019,48230,48231,48232,48233, +48234,48235,18020,18021,48236,48237,18022,48238,48239,48240,18023,48241,48242, +48243,48244,48245,48246,48247,18024,18025,48248,18026,48249,18027,48250,48257, +48258,48259,48260,48261,18028,48262,48263,48264,18029,48265,48266,48267,18030, +48268,48269,48270,48271,48272,48273,48274,18031,18032,48275,48276,18033,18034, +48277,48278,48279,48280,48281,48282,18035,48283,48284,48285,48286,48287,48288, +48449,18036,48450,48451,48452,48453,48454,48455,48456,48457,18037,48458,18038, +48459,48460,48461,48462,48463,48464,48465,48466,18039,18040,48467,48468,18041, +48469,48470,48471,18042,48472,48473,48474,48481,48482,48483,48484,18043,18044, +48485,18045,48486,18046,48487,48488,48489,48490,48491,48492,18209,48493,48494, +48495,48496,48497,48498,48499,48500,48501,48502,48503,48504,48505,48506,48513, +48514,48515,48516,48517,48518,18210,48519,48520,48521,48522,48523,48524,48525, +48526,48527,48528,48529,48530,48531,48532,48533,48534,48535,48536,48537,48538, +48539,48540,48541,48542,48543,48544,48705,48706,48707,48708,48709,48710,48711, +48712,18211,48713,48714,48715,18212,48716,48717,48718,48719,48720,48721,48722, +48723,48724,48725,48726,48727,48728,48729,48730,48737,48738,48739,48740,48741, +48742,48743,48744,18213,48745,48746,48747,18214,48748,48749,48750,18215,48751, +48752,48753,48754,48755,48756,48757,48758,18216,48759,18217,48760,48761,48762, +48769,48770,48771,48772,48773,18218,18219,48774,48775,18220,48776,48777,18221, +18222,48778,18223,48779,48780,48781,48782,48783,18224,18225,48784,18226,48785, +18227,48786,48787,48788,48789,48790,48791,18228,48792,48793,48794,48795,48796, +48797,48798,48799,48800,48961,48962,48963,48964,48965,48966,48967,48968,48969, +48970,48971,18229,48972,48973,48974,48975,48976,48977,48978,48979,48980,48981, +48982,48983,48984,48985,48986,48993,48994,48995,48996,48997,48998,48999,49000, +49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,18230,49012, +49013,49014,18231,49015,49016,49017,18232,49018,49025,49026,49027,49028,49029, +49030,18233,49031,49032,18234,49033,49034,49035,49036,49037,49038,49039,49040, +18235,49041,49042,49043,18236,49044,49045,49046,18237,49047,49048,49049,49050, +49051,49052,49053,18238,49054,49055,18239,49056,18240,49217,49218,49219,49220, +49221,49222,18241,49223,49224,49225,18242,49226,49227,49228,18243,49229,49230, +49231,49232,49233,49234,49235,18244,18245,49236,18246,49237,49238,49239,49240, +49241,49242,49249,49250,49251,49252,49253,49254,49255,49256,49257,49258,49259, +49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271,49272, +49273,49274,49281,49282,49283,49284,18247,18248,49285,49286,18249,49287,49288, +49289,18250,49290,49291,49292,49293,49294,49295,49296,18251,18252,49297,18253, +49298,18254,49299,49300,49301,49302,49303,49304,18255,18256,49305,49306,18257, +49307,49308,49309,18258,49310,49311,49312,49473,18259,49474,49475,18260,18261, +49476,18262,49477,18263,49478,49479,49480,49481,49482,49483,18264,18265,49484, +49485,18266,49486,49487,49488,18267,49489,49490,49491,49492,49493,49494,49495, +18268,18269,49496,18270,18271,18272,49497,49498,49505,49506,49507,49508,18273, +49509,49510,49511,49512,49513,49514,49515,49516,49517,49518,49519,49520,49521, +49522,49523,49524,49525,49526,49527,49528,18274,49529,49530,49537,49538,49539, +49540,49541,49542,49543,49544,49545,49546,49547,49548,49549,49550,49551,49552, +49553,49554,49555,49556,49557,49558,49559,49560,49561,49562,49563,49564,49565, +49566,49567,49568,18275,18276,49729,49730,18277,49731,49732,49733,18278,49734, +18279,49735,49736,49737,49738,49739,18280,18281,49740,18282,49741,18283,49742, +49743,49744,49745,49746,49747,18284,18285,49748,49749,18286,49750,49751,49752, +18287,49753,49754,49761,49762,49763,49764,49765,18288,18289,49766,18290,49767, +18291,49768,49769,49770,49771,49772,49773,18292,18293,49774,49775,18294,49776, +49777,49778,18295,49779,49780,49781,49782,49783,49784,49785,18296,18297,49786, +18298,18299,18300,49793,49794,49795,49796,49797,49798,18301,49799,49800,49801, +18302,49802,49803,49804,18465,49805,49806,49807,49808,49809,49810,49811,49812, +18466,49813,49814,49815,49816,49817,49818,49819,49820,49821,49822,18467,18468, +49823,49824,18469,49985,49986,49987,18470,49988,49989,49990,49991,18471,49992, +49993,18472,18473,49994,18474,49995,18475,49996,49997,49998,18476,49999,50000, +18477,18478,50001,50002,18479,50003,50004,50005,18480,50006,50007,50008,50009, +50010,50017,50018,50019,50020,50021,18481,50022,18482,50023,50024,50025,50026, +50027,50028,18483,18484,50029,50030,18485,50031,50032,50033,50034,50035,50036, +50037,50038,50039,50040,50041,50042,50049,50050,18486,50051,18487,50052,50053, +50054,50055,50056,50057,18488,18489,50058,50059,18490,50060,50061,50062,18491, +50063,50064,50065,50066,50067,50068,50069,50070,18492,50071,18493,50072,18494, +50073,50074,50075,50076,50077,50078,18495,50079,50080,50241,18496,50242,50243, +50244,18497,50245,50246,50247,50248,50249,50250,50251,50252,18498,50253,18499, +50254,50255,50256,50257,50258,50259,50260,50261,18500,18501,50262,50263,18502, +50264,50265,50266,18503,50273,50274,50275,50276,18504,50277,50278,18505,50279, +50280,18506,50281,18507,50282,50283,50284,50285,50286,50287,18508,50288,50289, +50290,18509,50291,50292,50293,18510,50294,50295,50296,50297,50298,50305,50306, +18511,50307,50308,50309,50310,18512,50311,50312,50313,50314,50315,50316,18513, +18514,50317,50318,18515,50319,50320,50321,18516,50322,50323,50324,50325,50326, +50327,50328,50329,50330,50331,50332,50333,18517,50334,50335,50336,50497,50498, +50499,18518,18519,50500,50501,18520,50502,50503,50504,18521,50505,50506,50507, +50508,50509,50510,50511,18522,18523,50512,18524,50513,18525,50514,50515,50516, +50517,50518,50519,18526,18527,50520,50521,18528,50522,50529,50530,18529,50531, +50532,50533,50534,50535,50536,50537,18530,50538,50539,18531,50540,18532,50541, +50542,50543,50544,50545,50546,18533,18534,50547,50548,18535,50549,18536,18537, +18538,18539,50550,50551,50552,50553,50554,50561,18540,18541,50562,18542,50563, +18543,50564,50565,50566,18544,50567,50568,18545,50569,50570,50571,18546,50572, +50573,50574,18547,50575,50576,50577,50578,50579,50580,50581,18548,18549,50582, +50583,50584,18550,50585,50586,50587,50588,50589,50590,18551,18552,50591,50592, +18553,50753,50754,50755,18554,50756,50757,50758,50759,50760,50761,50762,18555, +18556,50763,18557,50764,18558,50765,50766,50767,50768,50769,50770,19280,19286, +19303,19791,19816,20013,20347,20514,20536,20560,20573,20820,20821,20824,20827, +20828,20829,20830,20831,20832,20834,20835,20836,20837,20838,20840,20841,20842, +20843,20845,20847,20848,20850,20854,20858,20860,20861,20862,21026,21027,21031, +21032,21033,21034,21035,21037,21042,21054,21058,21059,21060,21062,21063,21064, +21065,21066,21067,21069,21070,21071,21072,21073,21074,21075,21076,21077,21078, +21079,21081,21082,21086,21087,21089,21090,21092,21093,21094,21095,21096,21097, +21098,21099,21104,21105,21106,21107,21108,21109,21111,21112,21606,21628,21797, +21803,21806,22072,22093,22347,22372,23365,23396,23589,23845,23893,23924,24188, +24190,24371,24417,24424,24689,24877,24941,25461,25633,25641,25902,25905,25906, +25913,25915,25916,25924,25934,25936,25938,25942,25978,25979,25980,25982,26145, +26148,26151,26157,26159,26160,26161,26163,26167,26168,26172,26180,26182,26183, +26186,26194,26198,26201,26204,26207,26209,26212,26213,26214,26216,26218,26219, +26220,26223,26225,26226,26229,26230,26231,26233,26401,26406,26409,26410,26412, +26413,26416,26431,26433,26438,26439,26443,26445,26447,26448,26451,26463,26468, +26470,26487,26727,26728,26736,26737,26743,26745,26747,26750,26919,26924,26956, +26999,27201,27237,27252,27255,27260,27262,27428,27431,27433,27434,27450,27451, +27453,27457,27458,27462,27463,27468,27471,27472,27473,27474,27480,27686,27687, +27690,27695,27696,27697,27698,27701,27704,27706,27712,27713,27717,27718,27721, +27722,27733,27741,27742,27745,27748,27751,27752,27767,27768,27770,27937,27938, +27939,28014,28251,29245,29306,29489,29735,29806,30324,30326,30520,30536,30547, +30811,30832,31265,31266,31334,31785,8993,8994,8995,8996,8997,8998,8999,9000, +9001,9002,9003,9004,9005,9006,9007,9008,9009,9010,9011,9012,9013,9014,9015, +9016,9017,9018,9019,9020,9021,9022,9023,9024,9025,9026,9027,9028,9029,9030, +9031,9032,9033,9034,9035,9036,9037,9038,9039,9040,9041,9042,9043,9044,9045, +9046,9047,9048,9049,9050,9051,8492,9053,9054,9055,9056,9057,9058,9059,9060, +9061,9062,9063,9064,9065,9066,9067,9068,9069,9070,9071,9072,9073,9074,9075, +9076,9077,9078,9079,9080,9081,9082,9083,9084,9085,8742,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,8523,8524,8574,9086,N,8525,9052, +}; + +static const struct unim_index cp949_encmap[256] = { +{__cp949_encmap+0,161,254},{__cp949_encmap+94,17,103},{__cp949_encmap+181,199, +221},{__cp949_encmap+204,145,201},{__cp949_encmap+261,1,81},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+342,21,172},{ +__cp949_encmap+494,3,212},{__cp949_encmap+704,0,165},{__cp949_encmap+870,18,18 +},{__cp949_encmap+871,96,233},{__cp949_encmap+1009,0,209},{__cp949_encmap+1219 +,5,109},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{__cp949_encmap+1324,0,246},{__cp949_encmap+1571,49,142},{__cp949_encmap+ +1665,0,127},{__cp949_encmap+1793,128,221},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__cp949_encmap+1887,0,251},{__cp949_encmap+2139,1,250},{ +__cp949_encmap+2389,2,255},{__cp949_encmap+2643,0,253},{__cp949_encmap+2897,0, +255},{__cp949_encmap+3153,5,248},{__cp949_encmap+3397,3,250},{__cp949_encmap+ +3645,4,254},{__cp949_encmap+3896,6,250},{__cp949_encmap+4141,3,252},{ +__cp949_encmap+4391,0,253},{__cp949_encmap+4645,15,255},{__cp949_encmap+4886, +1,233},{__cp949_encmap+5119,5,250},{__cp949_encmap+5365,1,253},{__cp949_encmap ++5618,7,254},{__cp949_encmap+5866,2,251},{__cp949_encmap+6116,1,255},{ +__cp949_encmap+6371,15,251},{__cp949_encmap+6608,1,255},{__cp949_encmap+6863, +0,255},{__cp949_encmap+7119,1,247},{__cp949_encmap+7366,13,254},{ +__cp949_encmap+7608,0,255},{__cp949_encmap+7864,6,255},{__cp949_encmap+8114,0, +254},{__cp949_encmap+8369,18,250},{__cp949_encmap+8602,0,255},{__cp949_encmap+ +8858,2,251},{__cp949_encmap+9108,4,236},{__cp949_encmap+9341,8,243},{ +__cp949_encmap+9577,11,251},{__cp949_encmap+9818,23,255},{__cp949_encmap+10051 +,1,254},{__cp949_encmap+10305,1,253},{__cp949_encmap+10558,4,255},{ +__cp949_encmap+10810,0,253},{__cp949_encmap+11064,10,254},{__cp949_encmap+ +11309,1,247},{__cp949_encmap+11556,1,252},{__cp949_encmap+11808,0,254},{ +__cp949_encmap+12063,1,243},{__cp949_encmap+12306,2,251},{__cp949_encmap+12556 +,1,251},{__cp949_encmap+12807,0,255},{__cp949_encmap+13063,15,233},{ +__cp949_encmap+13282,7,254},{__cp949_encmap+13530,0,251},{__cp949_encmap+13782 +,9,156},{__cp949_encmap+13930,54,252},{__cp949_encmap+14129,0,253},{ +__cp949_encmap+14383,2,254},{__cp949_encmap+14636,5,254},{__cp949_encmap+14886 +,1,253},{__cp949_encmap+15139,3,252},{__cp949_encmap+15389,17,255},{ +__cp949_encmap+15628,2,254},{__cp949_encmap+15881,0,254},{__cp949_encmap+16136 +,5,253},{__cp949_encmap+16385,7,248},{__cp949_encmap+16627,0,254},{ +__cp949_encmap+16882,0,154},{__cp949_encmap+17037,55,253},{__cp949_encmap+ +17236,4,243},{__cp949_encmap+17476,10,254},{__cp949_encmap+17721,3,253},{ +__cp949_encmap+17972,0,253},{__cp949_encmap+18226,2,245},{__cp949_encmap+18470 +,13,252},{__cp949_encmap+18710,4,246},{__cp949_encmap+18953,4,127},{ +__cp949_encmap+19077,119,226},{__cp949_encmap+19185,28,251},{__cp949_encmap+ +19409,0,255},{__cp949_encmap+19665,0,254},{__cp949_encmap+19920,3,255},{ +__cp949_encmap+20173,1,238},{__cp949_encmap+20411,26,232},{__cp949_encmap+ +20618,13,246},{__cp949_encmap+20852,9,250},{__cp949_encmap+21094,26,244},{ +__cp949_encmap+21313,7,156},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+21463,0,255},{ +__cp949_encmap+21719,0,255},{__cp949_encmap+21975,0,255},{__cp949_encmap+22231 +,0,255},{__cp949_encmap+22487,0,255},{__cp949_encmap+22743,0,255},{ +__cp949_encmap+22999,0,255},{__cp949_encmap+23255,0,255},{__cp949_encmap+23511 +,0,255},{__cp949_encmap+23767,0,255},{__cp949_encmap+24023,0,255},{ +__cp949_encmap+24279,0,255},{__cp949_encmap+24535,0,255},{__cp949_encmap+24791 +,0,255},{__cp949_encmap+25047,0,255},{__cp949_encmap+25303,0,255},{ +__cp949_encmap+25559,0,255},{__cp949_encmap+25815,0,255},{__cp949_encmap+26071 +,0,255},{__cp949_encmap+26327,0,255},{__cp949_encmap+26583,0,255},{ +__cp949_encmap+26839,0,255},{__cp949_encmap+27095,0,255},{__cp949_encmap+27351 +,0,255},{__cp949_encmap+27607,0,255},{__cp949_encmap+27863,0,255},{ +__cp949_encmap+28119,0,255},{__cp949_encmap+28375,0,255},{__cp949_encmap+28631 +,0,255},{__cp949_encmap+28887,0,255},{__cp949_encmap+29143,0,255},{ +__cp949_encmap+29399,0,255},{__cp949_encmap+29655,0,255},{__cp949_encmap+29911 +,0,255},{__cp949_encmap+30167,0,255},{__cp949_encmap+30423,0,255},{ +__cp949_encmap+30679,0,255},{__cp949_encmap+30935,0,255},{__cp949_encmap+31191 +,0,255},{__cp949_encmap+31447,0,255},{__cp949_encmap+31703,0,255},{ +__cp949_encmap+31959,0,255},{__cp949_encmap+32215,0,255},{__cp949_encmap+32471 +,0,163},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+32635,0,255},{ +__cp949_encmap+32891,0,11},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp949_encmap+ +32903,1,230}, +}; diff --git a/sys/src/cmd/python/Modules/cjkcodecs/mappings_tw.h b/sys/src/cmd/python/Modules/cjkcodecs/mappings_tw.h new file mode 100644 index 000000000..ec3f9f746 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/mappings_tw.h @@ -0,0 +1,2633 @@ +static const ucs2_t __big5_decmap[16702] = { +12288,65292,12289,12290,65294,8226,65307,65306,65311,65281,65072,8230,8229, +65104,65380,65106,183,65108,65109,65110,65111,65372,8211,65073,8212,65075, +9588,65076,65103,65288,65289,65077,65078,65371,65373,65079,65080,12308,12309, +65081,65082,12304,12305,65083,65084,12298,12299,65085,65086,12296,12297,65087, +65088,12300,12301,65089,65090,12302,12303,65091,65092,65113,65114,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,65115,65116,65117, +65118,8216,8217,8220,8221,12317,12318,8245,8242,65283,65286,65290,8251,167, +12291,9675,9679,9651,9650,9678,9734,9733,9671,9670,9633,9632,9661,9660,12963, +8453,8254,65507,65343,717,65097,65098,65101,65102,65099,65100,65119,65120, +65121,65291,65293,215,247,177,8730,65308,65310,65309,8806,8807,8800,8734,8786, +8801,65122,65123,65124,65125,65126,8764,8745,8746,8869,8736,8735,8895,13266, +13265,8747,8750,8757,8756,9792,9794,9793,9737,8593,8595,8592,8594,8598,8599, +8601,8600,8741,8739,65295,65340,65295,65340,65284,165,12306,162,163,65285, +65312,8451,8457,65129,65130,65131,13269,13212,13213,13214,13262,13217,13198, +13199,13252,176,20825,20827,20830,20829,20833,20835,21991,29929,31950,9601, +9602,9603,9604,9605,9606,9607,9608,9615,9614,9613,9612,9611,9610,9609,9532, +9524,9516,9508,9500,9620,9472,9474,9621,9484,9488,9492,9496,9581,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,9582,9584,9583,9552, +9566,9578,9569,9698,9699,9701,9700,9585,9586,9587,65296,65297,65298,65299, +65300,65301,65302,65303,65304,65305,8544,8545,8546,8547,8548,8549,8550,8551, +8552,8553,12321,12322,12323,12324,12325,12326,12327,12328,12329,21313,21316, +21317,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324, +65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337, +65338,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356, +65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369, +65370,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931, +932,933,934,935,936,937,945,946,947,948,949,950,951,952,953,954,955,956,957, +958,959,960,961,963,964,965,966,967,968,969,12549,12550,12551,12552,12553, +12554,12555,12556,12557,12558,12559,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,12560,12561,12562,12563,12564,12565,12566,12567, +12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580, +12581,12582,12583,12584,12585,729,713,714,711,715,19968,20057,19969,19971, +20035,20061,20102,20108,20154,20799,20837,20843,20960,20992,20993,21147,21269, +21313,21340,21448,19977,19979,19976,19978,20011,20024,20961,20037,20040,20063, +20062,20110,20129,20800,20995,21242,21315,21449,21475,22303,22763,22805,22823, +22899,23376,23377,23379,23544,23567,23586,23608,23665,24029,24037,24049,24050, +24051,24062,24178,24318,24331,24339,25165,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,19985,19984,19981,20013,20016,20025,20043, +23609,20104,20113,20117,20114,20116,20130,20161,20160,20163,20166,20167,20173, +20170,20171,20164,20803,20801,20839,20845,20846,20844,20887,20982,20998,20999, +21000,21243,21246,21247,21270,21305,21320,21319,21317,21342,21380,21451,21450, +21453,22764,22825,22827,22826,22829,23380,23569,23588,23610,23663,24052,24187, +24319,24340,24341,24515,25096,25142,25163,25166,25903,25991,26007,26020,26041, +26085,26352,26376,26408,27424,27490,27513,27595,27604,27611,27663,27700,28779, +29226,29238,29243,29255,29273,29275,29356,29579,19993,19990,19989,19988,19992, +20027,20045,20047,20046,20197,20184,20180,20181,20182,20183,20195,20196,20185, +20190,20805,20804,20873,20874,20908,20985,20986,20984,21002,21152,21151,21253, +21254,21271,21277,20191,21322,21321,21345,21344,21359,21358,21435,21487,21476, +21491,21484,21486,21481,21480,21500,21496,21493,21483,21478,21482,21490,21489, +21488,21477,21485,21499,22235,22234,22806,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22830,22833,22900,22902,23381,23427,23612, +24040,24039,24038,24066,24067,24179,24188,24321,24344,24343,24517,25098,25171, +25172,25170,25169,26021,26086,26414,26412,26410,26411,26413,27491,27597,27665, +27664,27704,27713,27712,27710,29359,29572,29577,29916,29926,29976,29983,29992, +29993,30000,30001,30002,30003,30091,30333,30382,30399,30446,30683,30690,30707, +31034,31166,31348,31435,19998,19999,20050,20051,20073,20121,20132,20134,20133, +20223,20233,20249,20234,20245,20237,20240,20241,20239,20210,20214,20219,20208, +20211,20221,20225,20235,20809,20807,20806,20808,20840,20849,20877,20912,21015, +21009,21010,21006,21014,21155,21256,21281,21280,21360,21361,21513,21519,21516, +21514,21520,21505,21515,21508,21521,21517,21512,21507,21518,21510,21522,22240, +22238,22237,22323,22320,22312,22317,22316,22319,22313,22809,22810,22839,22840, +22916,22904,22915,22909,22905,22914,22913,23383,23384,23431,23432,23429,23433, +23546,23574,23673,24030,24070,24182,24180,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24335,24347,24537,24534,25102,25100,25101, +25104,25187,25179,25176,25910,26089,26088,26092,26093,26354,26355,26377,26429, +26420,26417,26421,27425,27492,27515,27670,27741,27735,27737,27743,27744,27728, +27733,27745,27739,27725,27726,28784,29279,29277,30334,31481,31859,31992,32566, +32650,32701,32769,32771,32780,32786,32819,32895,32905,32907,32908,33251,33258, +33267,33276,33292,33307,33311,33390,33394,33406,34411,34880,34892,34915,35199, +38433,20018,20136,20301,20303,20295,20311,20318,20276,20315,20309,20272,20304, +20305,20285,20282,20280,20291,20308,20284,20294,20323,20316,20320,20271,20302, +20278,20313,20317,20296,20314,20812,20811,20813,20853,20918,20919,21029,21028, +21033,21034,21032,21163,21161,21162,21164,21283,21363,21365,21533,21549,21534, +21566,21542,21582,21543,21574,21571,21555,21576,21570,21531,21545,21578,21561, +21563,21560,21550,21557,21558,21536,21564,21568,21553,21547,21535,21548,22250, +22256,22244,22251,22346,22353,22336,22349,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22343,22350,22334,22352,22351,22331,22767, +22846,22941,22930,22952,22942,22947,22937,22934,22925,22948,22931,22922,22949, +23389,23388,23386,23387,23436,23435,23439,23596,23616,23617,23615,23614,23696, +23697,23700,23692,24043,24076,24207,24199,24202,24311,24324,24351,24420,24418, +24439,24441,24536,24524,24535,24525,24561,24555,24568,24554,25106,25105,25220, +25239,25238,25216,25206,25225,25197,25226,25212,25214,25209,25203,25234,25199, +25240,25198,25237,25235,25233,25222,25913,25915,25912,26097,26356,26463,26446, +26447,26448,26449,26460,26454,26462,26441,26438,26464,26451,26455,27493,27599, +27714,27742,27801,27777,27784,27785,27781,27803,27754,27770,27792,27760,27788, +27752,27798,27794,27773,27779,27762,27774,27764,27782,27766,27789,27796,27800, +27778,28790,28796,28797,28792,29282,29281,29280,29380,29378,29590,29996,29995, +30007,30008,30338,30447,30691,31169,31168,31167,31350,31995,32597,32918,32915, +32925,32920,32923,32922,32946,33391,33426,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33419,33421,35211,35282,35328,35895,35910, +35925,35997,36196,36208,36275,36523,36554,36763,36784,36802,36806,36805,36804, +24033,37009,37026,37034,37030,37027,37193,37318,37324,38450,38446,38449,38442, +38444,20006,20054,20083,20107,20123,20126,20139,20140,20335,20381,20365,20339, +20351,20332,20379,20363,20358,20355,20336,20341,20360,20329,20347,20374,20350, +20367,20369,20346,20820,20818,20821,20841,20855,20854,20856,20925,20989,21051, +21048,21047,21050,21040,21038,21046,21057,21182,21179,21330,21332,21331,21329, +21350,21367,21368,21369,21462,21460,21463,21619,21621,21654,21624,21653,21632, +21627,21623,21636,21650,21638,21628,21648,21617,21622,21644,21658,21602,21608, +21643,21629,21646,22266,22403,22391,22378,22377,22369,22374,22372,22396,22812, +22857,22855,22856,22852,22868,22974,22971,22996,22969,22958,22993,22982,22992, +22989,22987,22995,22986,22959,22963,22994,22981,23391,23396,23395,23447,23450, +23448,23452,23449,23451,23578,23624,23621,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23622,23735,23713,23736,23721,23723,23729, +23731,24088,24090,24086,24085,24091,24081,24184,24218,24215,24220,24213,24214, +24310,24358,24359,24361,24448,24449,24447,24444,24541,24544,24573,24565,24575, +24591,24596,24623,24629,24598,24618,24597,24609,24615,24617,24619,24603,25110, +25109,25151,25150,25152,25215,25289,25292,25284,25279,25282,25273,25298,25307, +25259,25299,25300,25291,25288,25256,25277,25276,25296,25305,25287,25293,25269, +25306,25265,25304,25302,25303,25286,25260,25294,25918,26023,26044,26106,26132, +26131,26124,26118,26114,26126,26112,26127,26133,26122,26119,26381,26379,26477, +26507,26517,26481,26524,26483,26487,26503,26525,26519,26479,26480,26495,26505, +26494,26512,26485,26522,26515,26492,26474,26482,27427,27494,27495,27519,27667, +27675,27875,27880,27891,27825,27852,27877,27827,27837,27838,27836,27874,27819, +27861,27859,27832,27844,27833,27841,27822,27863,27845,27889,27839,27835,27873, +27867,27850,27820,27887,27868,27862,27872,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28821,28814,28818,28810,28825,29228,29229, +29240,29256,29287,29289,29376,29390,29401,29399,29392,29609,29608,29599,29611, +29605,30013,30109,30105,30106,30340,30402,30450,30452,30693,30717,31038,31040, +31041,31177,31176,31354,31353,31482,31998,32596,32652,32651,32773,32954,32933, +32930,32945,32929,32939,32937,32948,32938,32943,33253,33278,33293,33459,33437, +33433,33453,33469,33439,33465,33457,33452,33445,33455,33464,33443,33456,33470, +33463,34382,34417,21021,34920,36555,36814,36820,36817,37045,37048,37041,37046, +37319,37329,38263,38272,38428,38464,38463,38459,38468,38466,38585,38632,38738, +38750,20127,20141,20142,20449,20405,20399,20415,20448,20433,20431,20445,20419, +20406,20440,20447,20426,20439,20398,20432,20420,20418,20442,20430,20446,20407, +20823,20882,20881,20896,21070,21059,21066,21069,21068,21067,21063,21191,21193, +21187,21185,21261,21335,21371,21402,21467,21676,21696,21672,21710,21705,21688, +21670,21683,21703,21698,21693,21674,21697,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21700,21704,21679,21675,21681,21691,21673, +21671,21695,22271,22402,22411,22432,22435,22434,22478,22446,22419,22869,22865, +22863,22862,22864,23004,23000,23039,23011,23016,23043,23013,23018,23002,23014, +23041,23035,23401,23459,23462,23460,23458,23461,23553,23630,23631,23629,23627, +23769,23762,24055,24093,24101,24095,24189,24224,24230,24314,24328,24365,24421, +24456,24453,24458,24459,24455,24460,24457,24594,24605,24608,24613,24590,24616, +24653,24688,24680,24674,24646,24643,24684,24683,24682,24676,25153,25308,25366, +25353,25340,25325,25345,25326,25341,25351,25329,25335,25327,25324,25342,25332, +25361,25346,25919,25925,26027,26045,26082,26149,26157,26144,26151,26159,26143, +26152,26161,26148,26359,26623,26579,26609,26580,26576,26604,26550,26543,26613, +26601,26607,26564,26577,26548,26586,26597,26552,26575,26590,26611,26544,26585, +26594,26589,26578,27498,27523,27526,27573,27602,27607,27679,27849,27915,27954, +27946,27969,27941,27916,27953,27934,27927,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,27963,27965,27966,27958,27931,27893,27961, +27943,27960,27945,27950,27957,27918,27947,28843,28858,28851,28844,28847,28845, +28856,28846,28836,29232,29298,29295,29300,29417,29408,29409,29623,29642,29627, +29618,29645,29632,29619,29978,29997,30031,30028,30030,30027,30123,30116,30117, +30114,30115,30328,30342,30343,30344,30408,30406,30403,30405,30465,30457,30456, +30473,30475,30462,30460,30471,30684,30722,30740,30732,30733,31046,31049,31048, +31047,31161,31162,31185,31186,31179,31359,31361,31487,31485,31869,32002,32005, +32000,32009,32007,32004,32006,32568,32654,32703,32772,32784,32781,32785,32822, +32982,32997,32986,32963,32964,32972,32993,32987,32974,32990,32996,32989,33268, +33314,33511,33539,33541,33507,33499,33510,33540,33509,33538,33545,33490,33495, +33521,33537,33500,33492,33489,33502,33491,33503,33519,33542,34384,34425,34427, +34426,34893,34923,35201,35284,35336,35330,35331,35998,36000,36212,36211,36276, +36557,36556,36848,36838,36834,36842,36837,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,36845,36843,36836,36840,37066,37070,37057, +37059,37195,37194,37325,38274,38480,38475,38476,38477,38754,38761,38859,38893, +38899,38913,39080,39131,39135,39318,39321,20056,20147,20492,20493,20515,20463, +20518,20517,20472,20521,20502,20486,20540,20511,20506,20498,20497,20474,20480, +20500,20520,20465,20513,20491,20505,20504,20467,20462,20525,20522,20478,20523, +20489,20860,20900,20901,20898,20941,20940,20934,20939,21078,21084,21076,21083, +21085,21290,21375,21407,21405,21471,21736,21776,21761,21815,21756,21733,21746, +21766,21754,21780,21737,21741,21729,21769,21742,21738,21734,21799,21767,21757, +21775,22275,22276,22466,22484,22475,22467,22537,22799,22871,22872,22874,23057, +23064,23068,23071,23067,23059,23020,23072,23075,23081,23077,23052,23049,23403, +23640,23472,23475,23478,23476,23470,23477,23481,23480,23556,23633,23637,23632, +23789,23805,23803,23786,23784,23792,23798,23809,23796,24046,24109,24107,24235, +24237,24231,24369,24466,24465,24464,24665,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24675,24677,24656,24661,24685,24681,24687, +24708,24735,24730,24717,24724,24716,24709,24726,25159,25331,25352,25343,25422, +25406,25391,25429,25410,25414,25423,25417,25402,25424,25405,25386,25387,25384, +25421,25420,25928,25929,26009,26049,26053,26178,26185,26191,26179,26194,26188, +26181,26177,26360,26388,26389,26391,26657,26680,26696,26694,26707,26681,26690, +26708,26665,26803,26647,26700,26705,26685,26612,26704,26688,26684,26691,26666, +26693,26643,26648,26689,27530,27529,27575,27683,27687,27688,27686,27684,27888, +28010,28053,28040,28039,28006,28024,28023,27993,28051,28012,28041,28014,27994, +28020,28009,28044,28042,28025,28037,28005,28052,28874,28888,28900,28889,28872, +28879,29241,29305,29436,29433,29437,29432,29431,29574,29677,29705,29678,29664, +29674,29662,30036,30045,30044,30042,30041,30142,30149,30151,30130,30131,30141, +30140,30137,30146,30136,30347,30384,30410,30413,30414,30505,30495,30496,30504, +30697,30768,30759,30776,30749,30772,30775,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30757,30765,30752,30751,30770,31061,31056, +31072,31071,31062,31070,31069,31063,31066,31204,31203,31207,31199,31206,31209, +31192,31364,31368,31449,31494,31505,31881,32033,32023,32011,32010,32032,32034, +32020,32016,32021,32026,32028,32013,32025,32027,32570,32607,32660,32709,32705, +32774,32792,32789,32793,32791,32829,32831,33009,33026,33008,33029,33005,33012, +33030,33016,33011,33032,33021,33034,33020,33007,33261,33260,33280,33296,33322, +33323,33320,33324,33467,33579,33618,33620,33610,33592,33616,33609,33589,33588, +33615,33586,33593,33590,33559,33600,33585,33576,33603,34388,34442,34474,34451, +34468,34473,34444,34467,34460,34928,34935,34945,34946,34941,34937,35352,35344, +35342,35340,35349,35338,35351,35347,35350,35343,35345,35912,35962,35961,36001, +36002,36215,36524,36562,36564,36559,36785,36865,36870,36855,36864,36858,36852, +36867,36861,36869,36856,37013,37089,37085,37090,37202,37197,37196,37336,37341, +37335,37340,37337,38275,38498,38499,38497,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38491,38493,38500,38488,38494,38587,39138, +39340,39592,39640,39717,39730,39740,20094,20602,20605,20572,20551,20547,20556, +20570,20553,20581,20598,20558,20565,20597,20596,20599,20559,20495,20591,20589, +20828,20885,20976,21098,21103,21202,21209,21208,21205,21264,21263,21273,21311, +21312,21310,21443,26364,21830,21866,21862,21828,21854,21857,21827,21834,21809, +21846,21839,21845,21807,21860,21816,21806,21852,21804,21859,21811,21825,21847, +22280,22283,22281,22495,22533,22538,22534,22496,22500,22522,22530,22581,22519, +22521,22816,22882,23094,23105,23113,23142,23146,23104,23100,23138,23130,23110, +23114,23408,23495,23493,23492,23490,23487,23494,23561,23560,23559,23648,23644, +23645,23815,23814,23822,23835,23830,23842,23825,23849,23828,23833,23844,23847, +23831,24034,24120,24118,24115,24119,24247,24248,24246,24245,24254,24373,24375, +24407,24428,24425,24427,24471,24473,24478,24472,24481,24480,24476,24703,24739, +24713,24736,24744,24779,24756,24806,24765,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24773,24763,24757,24796,24764,24792,24789, +24774,24799,24760,24794,24775,25114,25115,25160,25504,25511,25458,25494,25506, +25509,25463,25447,25496,25514,25457,25513,25481,25475,25499,25451,25512,25476, +25480,25497,25505,25516,25490,25487,25472,25467,25449,25448,25466,25949,25942, +25937,25945,25943,21855,25935,25944,25941,25940,26012,26011,26028,26063,26059, +26060,26062,26205,26202,26212,26216,26214,26206,26361,21207,26395,26753,26799, +26786,26771,26805,26751,26742,26801,26791,26775,26800,26755,26820,26797,26758, +26757,26772,26781,26792,26783,26785,26754,27442,27578,27627,27628,27691,28046, +28092,28147,28121,28082,28129,28108,28132,28155,28154,28165,28103,28107,28079, +28113,28078,28126,28153,28088,28151,28149,28101,28114,28186,28085,28122,28139, +28120,28138,28145,28142,28136,28102,28100,28074,28140,28095,28134,28921,28937, +28938,28925,28911,29245,29309,29313,29468,29467,29462,29459,29465,29575,29701, +29706,29699,29702,29694,29709,29920,29942,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29943,29980,29986,30053,30054,30050,30064, +30095,30164,30165,30133,30154,30157,30350,30420,30418,30427,30519,30526,30524, +30518,30520,30522,30827,30787,30798,31077,31080,31085,31227,31378,31381,31520, +31528,31515,31532,31526,31513,31518,31534,31890,31895,31893,32070,32067,32113, +32046,32057,32060,32064,32048,32051,32068,32047,32066,32050,32049,32573,32670, +32666,32716,32718,32722,32796,32842,32838,33071,33046,33059,33067,33065,33072, +33060,33282,33333,33335,33334,33337,33678,33694,33688,33656,33698,33686,33725, +33707,33682,33674,33683,33673,33696,33655,33659,33660,33670,33703,34389,24426, +34503,34496,34486,34500,34485,34502,34507,34481,34479,34505,34899,34974,34952, +34987,34962,34966,34957,34955,35219,35215,35370,35357,35363,35365,35377,35373, +35359,35355,35362,35913,35930,36009,36012,36011,36008,36010,36007,36199,36198, +36286,36282,36571,36575,36889,36877,36890,36887,36899,36895,36893,36880,36885, +36894,36896,36879,36898,36886,36891,36884,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,37096,37101,37117,37207,37326,37365,37350, +37347,37351,37357,37353,38281,38506,38517,38515,38520,38512,38516,38518,38519, +38508,38592,38634,38633,31456,31455,38914,38915,39770,40165,40565,40575,40613, +40635,20642,20621,20613,20633,20625,20608,20630,20632,20634,26368,20977,21106, +21108,21109,21097,21214,21213,21211,21338,21413,21883,21888,21927,21884,21898, +21917,21912,21890,21916,21930,21908,21895,21899,21891,21939,21934,21919,21822, +21938,21914,21947,21932,21937,21886,21897,21931,21913,22285,22575,22570,22580, +22564,22576,22577,22561,22557,22560,22777,22778,22880,23159,23194,23167,23186, +23195,23207,23411,23409,23506,23500,23507,23504,23562,23563,23601,23884,23888, +23860,23879,24061,24133,24125,24128,24131,24190,24266,24257,24258,24260,24380, +24429,24489,24490,24488,24785,24801,24754,24758,24800,24860,24867,24826,24853, +24816,24827,24820,24936,24817,24846,24822,24841,24832,24850,25119,25161,25507, +25484,25551,25536,25577,25545,25542,25549,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25554,25571,25552,25569,25558,25581,25582, +25462,25588,25578,25563,25682,25562,25593,25950,25958,25954,25955,26001,26000, +26031,26222,26224,26228,26230,26223,26257,26234,26238,26231,26366,26367,26399, +26397,26874,26837,26848,26840,26839,26885,26847,26869,26862,26855,26873,26834, +26866,26851,26827,26829,26893,26898,26894,26825,26842,26990,26875,27454,27450, +27453,27544,27542,27580,27631,27694,27695,27692,28207,28216,28244,28193,28210, +28263,28234,28192,28197,28195,28187,28251,28248,28196,28246,28270,28205,28198, +28271,28212,28237,28218,28204,28227,28189,28222,28363,28297,28185,28238,28259, +28228,28274,28265,28255,28953,28954,28966,28976,28961,28982,29038,28956,29260, +29316,29312,29494,29477,29492,29481,29754,29738,29747,29730,29733,29749,29750, +29748,29743,29723,29734,29736,29989,29990,30059,30058,30178,30171,30179,30169, +30168,30174,30176,30331,30332,30358,30355,30388,30428,30543,30701,30813,30828, +30831,31245,31240,31243,31237,31232,31384,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31383,31382,31461,31459,31561,31574,31558, +31568,31570,31572,31565,31563,31567,31569,31903,31909,32094,32080,32104,32085, +32043,32110,32114,32097,32102,32098,32112,32115,21892,32724,32725,32779,32850, +32901,33109,33108,33099,33105,33102,33081,33094,33086,33100,33107,33140,33298, +33308,33769,33795,33784,33805,33760,33733,33803,33729,33775,33777,33780,33879, +33802,33776,33804,33740,33789,33778,33738,33848,33806,33796,33756,33799,33748, +33759,34395,34527,34521,34541,34516,34523,34532,34512,34526,34903,35009,35010, +34993,35203,35222,35387,35424,35413,35422,35388,35393,35412,35419,35408,35398, +35380,35386,35382,35414,35937,35970,36015,36028,36019,36029,36033,36027,36032, +36020,36023,36022,36031,36024,36234,36229,36225,36302,36317,36299,36314,36305, +36300,36315,36294,36603,36600,36604,36764,36910,36917,36913,36920,36914,36918, +37122,37109,37129,37118,37219,37221,37327,37396,37397,37411,37385,37406,37389, +37392,37383,37393,38292,38287,38283,38289,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38291,38290,38286,38538,38542,38539,38525, +38533,38534,38541,38514,38532,38593,38597,38596,38598,38599,38639,38642,38860, +38917,38918,38920,39143,39146,39151,39145,39154,39149,39342,39341,40643,40653, +40657,20098,20653,20661,20658,20659,20677,20670,20652,20663,20667,20655,20679, +21119,21111,21117,21215,21222,21220,21218,21219,21295,21983,21992,21971,21990, +21966,21980,21959,21969,21987,21988,21999,21978,21985,21957,21958,21989,21961, +22290,22291,22622,22609,22616,22615,22618,22612,22635,22604,22637,22602,22626, +22610,22603,22887,23233,23241,23244,23230,23229,23228,23219,23234,23218,23913, +23919,24140,24185,24265,24264,24338,24409,24492,24494,24858,24847,24904,24863, +24819,24859,24825,24833,24840,24910,24908,24900,24909,24894,24884,24871,24845, +24838,24887,25121,25122,25619,25662,25630,25642,25645,25661,25644,25615,25628, +25620,25613,25654,25622,25623,25606,25964,26015,26032,26263,26249,26247,26248, +26262,26244,26264,26253,26371,27028,26989,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26970,26999,26976,26964,26997,26928,27010, +26954,26984,26987,26974,26963,27001,27014,26973,26979,26971,27463,27506,27584, +27583,27603,27645,28322,28335,28371,28342,28354,28304,28317,28359,28357,28325, +28312,28348,28346,28331,28369,28310,28316,28356,28372,28330,28327,28340,29006, +29017,29033,29028,29001,29031,29020,29036,29030,29004,29029,29022,28998,29032, +29014,29242,29266,29495,29509,29503,29502,29807,29786,29781,29791,29790,29761, +29759,29785,29787,29788,30070,30072,30208,30192,30209,30194,30193,30202,30207, +30196,30195,30430,30431,30555,30571,30566,30558,30563,30585,30570,30572,30556, +30565,30568,30562,30702,30862,30896,30871,30872,30860,30857,30844,30865,30867, +30847,31098,31103,31105,33836,31165,31260,31258,31264,31252,31263,31262,31391, +31392,31607,31680,31584,31598,31591,31921,31923,31925,32147,32121,32145,32129, +32143,32091,32622,32617,32618,32626,32681,32680,32676,32854,32856,32902,32900, +33137,33136,33144,33125,33134,33139,33131,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33145,33146,33126,33285,33351,33922,33911, +33853,33841,33909,33894,33899,33865,33900,33883,33852,33845,33889,33891,33897, +33901,33862,34398,34396,34399,34553,34579,34568,34567,34560,34558,34555,34562, +34563,34566,34570,34905,35039,35028,35033,35036,35032,35037,35041,35018,35029, +35026,35228,35299,35435,35442,35443,35430,35433,35440,35463,35452,35427,35488, +35441,35461,35437,35426,35438,35436,35449,35451,35390,35432,35938,35978,35977, +36042,36039,36040,36036,36018,36035,36034,36037,36321,36319,36328,36335,36339, +36346,36330,36324,36326,36530,36611,36617,36606,36618,36767,36786,36939,36938, +36947,36930,36948,36924,36949,36944,36935,36943,36942,36941,36945,36926,36929, +37138,37143,37228,37226,37225,37321,37431,37463,37432,37437,37440,37438,37467, +37451,37476,37457,37428,37449,37453,37445,37433,37439,37466,38296,38552,38548, +38549,38605,38603,38601,38602,38647,38651,38649,38646,38742,38772,38774,38928, +38929,38931,38922,38930,38924,39164,39156,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39165,39166,39347,39345,39348,39649,40169, +40578,40718,40723,40736,20711,20718,20709,20694,20717,20698,20693,20687,20689, +20721,20686,20713,20834,20979,21123,21122,21297,21421,22014,22016,22043,22039, +22013,22036,22022,22025,22029,22030,22007,22038,22047,22024,22032,22006,22296, +22294,22645,22654,22659,22675,22666,22649,22661,22653,22781,22821,22818,22820, +22890,22889,23265,23270,23273,23255,23254,23256,23267,23413,23518,23527,23521, +23525,23526,23528,23522,23524,23519,23565,23650,23940,23943,24155,24163,24149, +24151,24148,24275,24278,24330,24390,24432,24505,24903,24895,24907,24951,24930, +24931,24927,24922,24920,24949,25130,25735,25688,25684,25764,25720,25695,25722, +25681,25703,25652,25709,25723,25970,26017,26071,26070,26274,26280,26269,27036, +27048,27029,27073,27054,27091,27083,27035,27063,27067,27051,27060,27088,27085, +27053,27084,27046,27075,27043,27465,27468,27699,28467,28436,28414,28435,28404, +28457,28478,28448,28460,28431,28418,28450,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28415,28399,28422,28465,28472,28466,28451, +28437,28459,28463,28552,28458,28396,28417,28402,28364,28407,29076,29081,29053, +29066,29060,29074,29246,29330,29334,29508,29520,29796,29795,29802,29808,29805, +29956,30097,30247,30221,30219,30217,30227,30433,30435,30596,30589,30591,30561, +30913,30879,30887,30899,30889,30883,31118,31119,31117,31278,31281,31402,31401, +31469,31471,31649,31637,31627,31605,31639,31645,31636,31631,31672,31623,31620, +31929,31933,31934,32187,32176,32156,32189,32190,32160,32202,32180,32178,32177, +32186,32162,32191,32181,32184,32173,32210,32199,32172,32624,32736,32737,32735, +32862,32858,32903,33104,33152,33167,33160,33162,33151,33154,33255,33274,33287, +33300,33310,33355,33993,33983,33990,33988,33945,33950,33970,33948,33995,33976, +33984,34003,33936,33980,34001,33994,34623,34588,34619,34594,34597,34612,34584, +34645,34615,34601,35059,35074,35060,35065,35064,35069,35048,35098,35055,35494, +35468,35486,35491,35469,35489,35475,35492,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,35498,35493,35496,35480,35473,35482,35495, +35946,35981,35980,36051,36049,36050,36203,36249,36245,36348,36628,36626,36629, +36627,36771,36960,36952,36956,36963,36953,36958,36962,36957,36955,37145,37144, +37150,37237,37240,37239,37236,37496,37504,37509,37528,37526,37499,37523,37532, +37544,37500,37521,38305,38312,38313,38307,38309,38308,38553,38556,38555,38604, +38610,38656,38780,38789,38902,38935,38936,39087,39089,39171,39173,39180,39177, +39361,39599,39600,39654,39745,39746,40180,40182,40179,40636,40763,40778,20740, +20736,20731,20725,20729,20738,20744,20745,20741,20956,21127,21128,21129,21133, +21130,21232,21426,22062,22075,22073,22066,22079,22068,22057,22099,22094,22103, +22132,22070,22063,22064,22656,22687,22686,22707,22684,22702,22697,22694,22893, +23305,23291,23307,23285,23308,23304,23534,23532,23529,23531,23652,23653,23965, +23956,24162,24159,24161,24290,24282,24287,24285,24291,24288,24392,24433,24503, +24501,24950,24935,24942,24925,24917,24962,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24956,24944,24939,24958,24999,24976,25003, +24974,25004,24986,24996,24980,25006,25134,25705,25711,25721,25758,25778,25736, +25744,25776,25765,25747,25749,25769,25746,25774,25773,25771,25754,25772,25753, +25762,25779,25973,25975,25976,26286,26283,26292,26289,27171,27167,27112,27137, +27166,27161,27133,27169,27155,27146,27123,27138,27141,27117,27153,27472,27470, +27556,27589,27590,28479,28540,28548,28497,28518,28500,28550,28525,28507,28536, +28526,28558,28538,28528,28516,28567,28504,28373,28527,28512,28511,29087,29100, +29105,29096,29270,29339,29518,29527,29801,29835,29827,29822,29824,30079,30240, +30249,30239,30244,30246,30241,30242,30362,30394,30436,30606,30599,30604,30609, +30603,30923,30917,30906,30922,30910,30933,30908,30928,31295,31292,31296,31293, +31287,31291,31407,31406,31661,31665,31684,31668,31686,31687,31681,31648,31692, +31946,32224,32244,32239,32251,32216,32236,32221,32232,32227,32218,32222,32233, +32158,32217,32242,32249,32629,32631,32687,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32745,32806,33179,33180,33181,33184,33178, +33176,34071,34109,34074,34030,34092,34093,34067,34065,34083,34081,34068,34028, +34085,34047,34054,34690,34676,34678,34656,34662,34680,34664,34649,34647,34636, +34643,34907,34909,35088,35079,35090,35091,35093,35082,35516,35538,35527,35524, +35477,35531,35576,35506,35529,35522,35519,35504,35542,35533,35510,35513,35547, +35916,35918,35948,36064,36062,36070,36068,36076,36077,36066,36067,36060,36074, +36065,36205,36255,36259,36395,36368,36381,36386,36367,36393,36383,36385,36382, +36538,36637,36635,36639,36649,36646,36650,36636,36638,36645,36969,36974,36968, +36973,36983,37168,37165,37159,37169,37255,37257,37259,37251,37573,37563,37559, +37610,37548,37604,37569,37555,37564,37586,37575,37616,37554,38317,38321,38660, +38662,38663,38665,38752,38797,38795,38799,38945,38955,38940,39091,39178,39187, +39186,39192,39389,39376,39391,39387,39377,39381,39378,39385,39607,39662,39663, +39719,39749,39748,39799,39791,40198,40201,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40195,40617,40638,40654,22696,40786,20754, +20760,20756,20752,20757,20864,20906,20957,21137,21139,21235,22105,22123,22137, +22121,22116,22136,22122,22120,22117,22129,22127,22124,22114,22134,22721,22718, +22727,22725,22894,23325,23348,23416,23536,23566,24394,25010,24977,25001,24970, +25037,25014,25022,25034,25032,25136,25797,25793,25803,25787,25788,25818,25796, +25799,25794,25805,25791,25810,25812,25790,25972,26310,26313,26297,26308,26311, +26296,27197,27192,27194,27225,27243,27224,27193,27204,27234,27233,27211,27207, +27189,27231,27208,27481,27511,27653,28610,28593,28577,28611,28580,28609,28583, +28595,28608,28601,28598,28582,28576,28596,29118,29129,29136,29138,29128,29141, +29113,29134,29145,29148,29123,29124,29544,29852,29859,29848,29855,29854,29922, +29964,29965,30260,30264,30266,30439,30437,30624,30622,30623,30629,30952,30938, +30956,30951,31142,31309,31310,31302,31308,31307,31418,31705,31761,31689,31716, +31707,31713,31721,31718,31957,31958,32266,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32273,32264,32283,32291,32286,32285,32265, +32272,32633,32690,32752,32753,32750,32808,33203,33193,33192,33275,33288,33368, +33369,34122,34137,34120,34152,34153,34115,34121,34157,34154,34142,34691,34719, +34718,34722,34701,34913,35114,35122,35109,35115,35105,35242,35238,35558,35578, +35563,35569,35584,35548,35559,35566,35582,35585,35586,35575,35565,35571,35574, +35580,35947,35949,35987,36084,36420,36401,36404,36418,36409,36405,36667,36655, +36664,36659,36776,36774,36981,36980,36984,36978,36988,36986,37172,37266,37664, +37686,37624,37683,37679,37666,37628,37675,37636,37658,37648,37670,37665,37653, +37678,37657,38331,38567,38568,38570,38613,38670,38673,38678,38669,38675,38671, +38747,38748,38758,38808,38960,38968,38971,38967,38957,38969,38948,39184,39208, +39198,39195,39201,39194,39405,39394,39409,39608,39612,39675,39661,39720,39825, +40213,40227,40230,40232,40210,40219,40664,40660,40845,40860,20778,20767,20769, +20786,21237,22158,22144,22160,22149,22151,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22159,22741,22739,22737,22734,23344,23338, +23332,23418,23607,23656,23996,23994,23997,23992,24171,24396,24509,25033,25026, +25031,25062,25035,25138,25140,25806,25802,25816,25824,25840,25830,25836,25841, +25826,25837,25986,25987,26329,26326,27264,27284,27268,27298,27292,27355,27299, +27262,27287,27280,27296,27484,27566,27610,27656,28632,28657,28639,28640,28635, +28644,28651,28655,28544,28652,28641,28649,28629,28654,28656,29159,29151,29166, +29158,29157,29165,29164,29172,29152,29237,29254,29552,29554,29865,29872,29862, +29864,30278,30274,30284,30442,30643,30634,30640,30636,30631,30637,30703,30967, +30970,30964,30959,30977,31143,31146,31319,31423,31751,31757,31742,31735,31756, +31712,31968,31964,31966,31970,31967,31961,31965,32302,32318,32326,32311,32306, +32323,32299,32317,32305,32325,32321,32308,32313,32328,32309,32319,32303,32580, +32755,32764,32881,32882,32880,32879,32883,33222,33219,33210,33218,33216,33215, +33213,33225,33214,33256,33289,33393,34218,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34180,34174,34204,34193,34196,34223,34203, +34183,34216,34186,34407,34752,34769,34739,34770,34758,34731,34747,34746,34760, +34763,35131,35126,35140,35128,35133,35244,35598,35607,35609,35611,35594,35616, +35613,35588,35600,35905,35903,35955,36090,36093,36092,36088,36091,36264,36425, +36427,36424,36426,36676,36670,36674,36677,36671,36991,36989,36996,36993,36994, +36992,37177,37283,37278,37276,37709,37762,37672,37749,37706,37733,37707,37656, +37758,37740,37723,37744,37722,37716,38346,38347,38348,38344,38342,38577,38584, +38614,38684,38686,38816,38867,38982,39094,39221,39425,39423,39854,39851,39850, +39853,40251,40255,40587,40655,40670,40668,40669,40667,40766,40779,21474,22165, +22190,22745,22744,23352,24413,25059,25139,25844,25842,25854,25862,25850,25851, +25847,26039,26332,26406,27315,27308,27331,27323,27320,27330,27310,27311,27487, +27512,27567,28681,28683,28670,28678,28666,28689,28687,29179,29180,29182,29176, +29559,29557,29863,29887,29973,30294,30296,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30290,30653,30655,30651,30652,30990,31150, +31329,31330,31328,31428,31429,31787,31783,31786,31774,31779,31777,31975,32340, +32341,32350,32346,32353,32338,32345,32584,32761,32763,32887,32886,33229,33231, +33290,34255,34217,34253,34256,34249,34224,34234,34233,34214,34799,34796,34802, +34784,35206,35250,35316,35624,35641,35628,35627,35920,36101,36441,36451,36454, +36452,36447,36437,36544,36681,36685,36999,36995,37000,37291,37292,37328,37780, +37770,37782,37794,37811,37806,37804,37808,37784,37786,37783,38356,38358,38352, +38357,38626,38620,38617,38619,38622,38692,38819,38822,38829,38905,38989,38991, +38988,38990,38995,39098,39230,39231,39229,39214,39333,39438,39617,39683,39686, +39759,39758,39757,39882,39881,39933,39880,39872,40273,40285,40288,40672,40725, +40748,20787,22181,22750,22751,22754,23541,40848,24300,25074,25079,25078,25077, +25856,25871,26336,26333,27365,27357,27354,27347,28699,28703,28712,28698,28701, +28693,28696,29190,29197,29272,29346,29560,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29562,29885,29898,29923,30087,30086,30303, +30305,30663,31001,31153,31339,31337,31806,31807,31800,31805,31799,31808,32363, +32365,32377,32361,32362,32645,32371,32694,32697,32696,33240,34281,34269,34282, +34261,34276,34277,34295,34811,34821,34829,34809,34814,35168,35167,35158,35166, +35649,35676,35672,35657,35674,35662,35663,35654,35673,36104,36106,36476,36466, +36487,36470,36460,36474,36468,36692,36686,36781,37002,37003,37297,37294,37857, +37841,37855,37827,37832,37852,37853,37846,37858,37837,37848,37860,37847,37864, +38364,38580,38627,38698,38695,38753,38876,38907,39006,39000,39003,39100,39237, +39241,39446,39449,39693,39912,39911,39894,39899,40329,40289,40306,40298,40300, +40594,40599,40595,40628,21240,22184,22199,22198,22196,22204,22756,23360,23363, +23421,23542,24009,25080,25082,25880,25876,25881,26342,26407,27372,28734,28720, +28722,29200,29563,29903,30306,30309,31014,31018,31020,31019,31431,31478,31820, +31811,31821,31983,31984,36782,32381,32380,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32386,32588,32768,33242,33382,34299,34297, +34321,34298,34310,34315,34311,34314,34836,34837,35172,35258,35320,35696,35692, +35686,35695,35679,35691,36111,36109,36489,36481,36485,36482,37300,37323,37912, +37891,37885,38369,38704,39108,39250,39249,39336,39467,39472,39479,39477,39955, +39949,40569,40629,40680,40751,40799,40803,40801,20791,20792,22209,22208,22210, +22804,23660,24013,25084,25086,25885,25884,26005,26345,27387,27396,27386,27570, +28748,29211,29351,29910,29908,30313,30675,31824,32399,32396,32700,34327,34349, +34330,34851,34850,34849,34847,35178,35180,35261,35700,35703,35709,36115,36490, +36493,36491,36703,36783,37306,37934,37939,37941,37946,37944,37938,37931,38370, +38712,38713,38706,38911,39015,39013,39255,39493,39491,39488,39486,39631,39764, +39761,39981,39973,40367,40372,40386,40376,40605,40687,40729,40796,40806,40807, +20796,20795,22216,22218,22217,23423,24020,24018,24398,25087,25892,27402,27489, +28753,28760,29568,29924,30090,30318,30316,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31155,31840,31839,32894,32893,33247,35186, +35183,35324,35712,36118,36119,36497,36499,36705,37192,37956,37969,37970,38717, +38718,38851,38849,39019,39253,39509,39501,39634,39706,40009,39985,39998,39995, +40403,40407,40756,40812,40810,40852,22220,24022,25088,25891,25899,25898,26348, +27408,29914,31434,31844,31843,31845,32403,32406,32404,33250,34360,34367,34865, +35722,37008,37007,37987,37984,37988,38760,39023,39260,39514,39515,39511,39635, +39636,39633,40020,40023,40022,40421,40607,40692,22225,22761,25900,28766,30321, +30322,30679,32592,32648,34870,34873,34914,35731,35730,35734,33399,36123,37312, +37994,38722,38728,38724,38854,39024,39519,39714,39768,40031,40441,40442,40572, +40573,40711,40823,40818,24307,27414,28771,31852,31854,34875,35264,36513,37313, +38002,38000,39025,39262,39638,39715,40652,28772,30682,35738,38007,38857,39522, +39525,32412,35740,36522,37317,38013,38014,38012,40055,40056,40695,35924,38015, +40474,29224,39530,39729,40475,40478,31858,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12542,12445,12446,12293,12353,12354,12355, +12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368, +12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381, +12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394, +12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407, +12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420, +12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433, +12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459, +12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472, +12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485, +12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498, +12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511, +12512,12513,12514,12515,12516,12517,12518,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,12519,12520,12521,12522,12523,12524,12525, +12526,12527,12528,12529,12530,12531,12532,12533,12534,1044,1045,1025,1046, +1047,1048,1049,1050,1051,1052,1059,1060,1061,1062,1063,1064,1065,1066,1067, +1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081, +1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096, +1097,1098,1099,1100,1101,1102,1103,9312,9313,9314,9315,9316,9317,9318,9319, +9320,9321,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,20034,20060,20981, +21274,21378,19975,19980,20039,20109,22231,64012,23662,24435,19983,20871,19982, +20014,20115,20162,20169,20168,20888,21244,21356,21433,22304,22787,22828,23568, +24063,26081,27571,27596,27668,29247,20017,20028,20200,20188,20201,20193,20189, +20186,21004,21276,21324,22306,22307,22807,22831,23425,23428,23570,23611,23668, +23667,24068,24192,24194,24521,25097,25168,27669,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,27702,27715,27711,27707,29358,29360, +29578,31160,32906,38430,20238,20248,20268,20213,20244,20209,20224,20215,20232, +20253,20226,20229,20258,20243,20228,20212,20242,20913,21011,21001,21008,21158, +21282,21279,21325,21386,21511,22241,22239,22318,22314,22324,22844,22912,22908, +22917,22907,22910,22903,22911,23382,23573,23589,23676,23674,23675,23678,24031, +24181,24196,24322,24346,24436,24533,24532,24527,25180,25182,25188,25185,25190, +25186,25177,25184,25178,25189,26095,26094,26430,26425,26424,26427,26426,26431, +26428,26419,27672,27718,27730,27740,27727,27722,27732,27723,27724,28785,29278, +29364,29365,29582,29994,30335,31349,32593,33400,33404,33408,33405,33407,34381, +35198,37017,37015,37016,37019,37012,38434,38436,38432,38435,20310,20283,20322, +20297,20307,20324,20286,20327,20306,20319,20289,20312,20269,20275,20287,20321, +20879,20921,21020,21022,21025,21165,21166,21257,21347,21362,21390,21391,21552, +21559,21546,21588,21573,21529,21532,21541,21528,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21565,21583,21569,21544,21540,21575, +22254,22247,22245,22337,22341,22348,22345,22347,22354,22790,22848,22950,22936, +22944,22935,22926,22946,22928,22927,22951,22945,23438,23442,23592,23594,23693, +23695,23688,23691,23689,23698,23690,23686,23699,23701,24032,24074,24078,24203, +24201,24204,24200,24205,24325,24349,24440,24438,24530,24529,24528,24557,24552, +24558,24563,24545,24548,24547,24570,24559,24567,24571,24576,24564,25146,25219, +25228,25230,25231,25236,25223,25201,25211,25210,25200,25217,25224,25207,25213, +25202,25204,25911,26096,26100,26099,26098,26101,26437,26439,26457,26453,26444, +26440,26461,26445,26458,26443,27600,27673,27674,27768,27751,27755,27780,27787, +27791,27761,27759,27753,27802,27757,27783,27797,27804,27750,27763,27749,27771, +27790,28788,28794,29283,29375,29373,29379,29382,29377,29370,29381,29589,29591, +29587,29588,29586,30010,30009,30100,30101,30337,31037,32820,32917,32921,32912, +32914,32924,33424,33423,33413,33422,33425,33427,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33418,33411,33412,35960,36809,36799, +37023,37025,37029,37022,37031,37024,38448,38440,38447,38445,20019,20376,20348, +20357,20349,20352,20359,20342,20340,20361,20356,20343,20300,20375,20330,20378, +20345,20353,20344,20368,20380,20372,20382,20370,20354,20373,20331,20334,20894, +20924,20926,21045,21042,21043,21062,21041,21180,21258,21259,21308,21394,21396, +21639,21631,21633,21649,21634,21640,21611,21626,21630,21605,21612,21620,21606, +21645,21615,21601,21600,21656,21603,21607,21604,22263,22265,22383,22386,22381, +22379,22385,22384,22390,22400,22389,22395,22387,22388,22370,22376,22397,22796, +22853,22965,22970,22991,22990,22962,22988,22977,22966,22972,22979,22998,22961, +22973,22976,22984,22964,22983,23394,23397,23443,23445,23620,23623,23726,23716, +23712,23733,23727,23720,23724,23711,23715,23725,23714,23722,23719,23709,23717, +23734,23728,23718,24087,24084,24089,24360,24354,24355,24356,24404,24450,24446, +24445,24542,24549,24621,24614,24601,24626,24587,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24628,24586,24599,24627,24602,24606, +24620,24610,24589,24592,24622,24595,24593,24588,24585,24604,25108,25149,25261, +25268,25297,25278,25258,25270,25290,25262,25267,25263,25275,25257,25264,25272, +25917,26024,26043,26121,26108,26116,26130,26120,26107,26115,26123,26125,26117, +26109,26129,26128,26358,26378,26501,26476,26510,26514,26486,26491,26520,26502, +26500,26484,26509,26508,26490,26527,26513,26521,26499,26493,26497,26488,26489, +26516,27429,27520,27518,27614,27677,27795,27884,27883,27886,27865,27830,27860, +27821,27879,27831,27856,27842,27834,27843,27846,27885,27890,27858,27869,27828, +27786,27805,27776,27870,27840,27952,27853,27847,27824,27897,27855,27881,27857, +28820,28824,28805,28819,28806,28804,28817,28822,28802,28826,28803,29290,29398, +29387,29400,29385,29404,29394,29396,29402,29388,29393,29604,29601,29613,29606, +29602,29600,29612,29597,29917,29928,30015,30016,30014,30092,30104,30383,30451, +30449,30448,30453,30712,30716,30713,30715,30714,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30711,31042,31039,31173,31352,31355, +31483,31861,31997,32821,32911,32942,32931,32952,32949,32941,33312,33440,33472, +33451,33434,33432,33435,33461,33447,33454,33468,33438,33466,33460,33448,33441, +33449,33474,33444,33475,33462,33442,34416,34415,34413,34414,35926,36818,36811, +36819,36813,36822,36821,36823,37042,37044,37039,37043,37040,38457,38461,38460, +38458,38467,20429,20421,20435,20402,20425,20427,20417,20436,20444,20441,20411, +20403,20443,20423,20438,20410,20416,20409,20460,21060,21065,21184,21186,21309, +21372,21399,21398,21401,21400,21690,21665,21677,21669,21711,21699,33549,21687, +21678,21718,21686,21701,21702,21664,21616,21692,21666,21694,21618,21726,21680, +22453,22430,22431,22436,22412,22423,22429,22427,22420,22424,22415,22425,22437, +22426,22421,22772,22797,22867,23009,23006,23022,23040,23025,23005,23034,23037, +23036,23030,23012,23026,23031,23003,23017,23027,23029,23008,23038,23028,23021, +23464,23628,23760,23768,23756,23767,23755,23771,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23774,23770,23753,23751,23754,23766, +23763,23764,23759,23752,23750,23758,23775,23800,24057,24097,24098,24099,24096, +24100,24240,24228,24226,24219,24227,24229,24327,24366,24406,24454,24631,24633, +24660,24690,24670,24645,24659,24647,24649,24667,24652,24640,24642,24671,24612, +24644,24664,24678,24686,25154,25155,25295,25357,25355,25333,25358,25347,25323, +25337,25359,25356,25336,25334,25344,25363,25364,25338,25365,25339,25328,25921, +25923,26026,26047,26166,26145,26162,26165,26140,26150,26146,26163,26155,26170, +26141,26164,26169,26158,26383,26384,26561,26610,26568,26554,26588,26555,26616, +26584,26560,26551,26565,26603,26596,26591,26549,26573,26547,26615,26614,26606, +26595,26562,26553,26574,26599,26608,26546,26620,26566,26605,26572,26542,26598, +26587,26618,26569,26570,26563,26602,26571,27432,27522,27524,27574,27606,27608, +27616,27680,27681,27944,27956,27949,27935,27964,27967,27922,27914,27866,27955, +27908,27929,27962,27930,27921,27904,27933,27970,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,27905,27928,27959,27907,27919,27968, +27911,27936,27948,27912,27938,27913,27920,28855,28831,28862,28849,28848,28833, +28852,28853,28841,29249,29257,29258,29292,29296,29299,29294,29386,29412,29416, +29419,29407,29418,29414,29411,29573,29644,29634,29640,29637,29625,29622,29621, +29620,29675,29631,29639,29630,29635,29638,29624,29643,29932,29934,29998,30023, +30024,30119,30122,30329,30404,30472,30467,30468,30469,30474,30455,30459,30458, +30695,30696,30726,30737,30738,30725,30736,30735,30734,30729,30723,30739,31050, +31052,31051,31045,31044,31189,31181,31183,31190,31182,31360,31358,31441,31488, +31489,31866,31864,31865,31871,31872,31873,32003,32008,32001,32600,32657,32653, +32702,32775,32782,32783,32788,32823,32984,32967,32992,32977,32968,32962,32976, +32965,32995,32985,32988,32970,32981,32969,32975,32983,32998,32973,33279,33313, +33428,33497,33534,33529,33543,33512,33536,33493,33594,33515,33494,33524,33516, +33505,33522,33525,33548,33531,33526,33520,33514,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33508,33504,33530,33523,33517,34423, +34420,34428,34419,34881,34894,34919,34922,34921,35283,35332,35335,36210,36835, +36833,36846,36832,37105,37053,37055,37077,37061,37054,37063,37067,37064,37332, +37331,38484,38479,38481,38483,38474,38478,20510,20485,20487,20499,20514,20528, +20507,20469,20468,20531,20535,20524,20470,20471,20503,20508,20512,20519,20533, +20527,20529,20494,20826,20884,20883,20938,20932,20933,20936,20942,21089,21082, +21074,21086,21087,21077,21090,21197,21262,21406,21798,21730,21783,21778,21735, +21747,21732,21786,21759,21764,21768,21739,21777,21765,21745,21770,21755,21751, +21752,21728,21774,21763,21771,22273,22274,22476,22578,22485,22482,22458,22470, +22461,22460,22456,22454,22463,22471,22480,22457,22465,22798,22858,23065,23062, +23085,23086,23061,23055,23063,23050,23070,23091,23404,23463,23469,23468,23555, +23638,23636,23788,23807,23790,23793,23799,23808,23801,24105,24104,24232,24238, +24234,24236,24371,24368,24423,24669,24666,24679,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24641,24738,24712,24704,24722,24705, +24733,24707,24725,24731,24727,24711,24732,24718,25113,25158,25330,25360,25430, +25388,25412,25413,25398,25411,25572,25401,25419,25418,25404,25385,25409,25396, +25432,25428,25433,25389,25415,25395,25434,25425,25400,25431,25408,25416,25930, +25926,26054,26051,26052,26050,26186,26207,26183,26193,26386,26387,26655,26650, +26697,26674,26675,26683,26699,26703,26646,26673,26652,26677,26667,26669,26671, +26702,26692,26676,26653,26642,26644,26662,26664,26670,26701,26682,26661,26656, +27436,27439,27437,27441,27444,27501,32898,27528,27622,27620,27624,27619,27618, +27623,27685,28026,28003,28004,28022,27917,28001,28050,27992,28002,28013,28015, +28049,28045,28143,28031,28038,27998,28007,28000,28055,28016,28028,27999,28034, +28056,27951,28008,28043,28030,28032,28036,27926,28035,28027,28029,28021,28048, +28892,28883,28881,28893,28875,32569,28898,28887,28882,28894,28896,28884,28877, +28869,28870,28871,28890,28878,28897,29250,29304,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29303,29302,29440,29434,29428,29438, +29430,29427,29435,29441,29651,29657,29669,29654,29628,29671,29667,29673,29660, +29650,29659,29652,29661,29658,29655,29656,29672,29918,29919,29940,29941,29985, +30043,30047,30128,30145,30139,30148,30144,30143,30134,30138,30346,30409,30493, +30491,30480,30483,30482,30499,30481,30485,30489,30490,30498,30503,30755,30764, +30754,30773,30767,30760,30766,30763,30753,30761,30771,30762,30769,31060,31067, +31055,31068,31059,31058,31057,31211,31212,31200,31214,31213,31210,31196,31198, +31197,31366,31369,31365,31371,31372,31370,31367,31448,31504,31492,31507,31493, +31503,31496,31498,31502,31497,31506,31876,31889,31882,31884,31880,31885,31877, +32030,32029,32017,32014,32024,32022,32019,32031,32018,32015,32012,32604,32609, +32606,32608,32605,32603,32662,32658,32707,32706,32704,32790,32830,32825,33018, +33010,33017,33013,33025,33019,33024,33281,33327,33317,33587,33581,33604,33561, +33617,33573,33622,33599,33601,33574,33564,33570,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33602,33614,33563,33578,33544,33596, +33613,33558,33572,33568,33591,33583,33577,33607,33605,33612,33619,33566,33580, +33611,33575,33608,34387,34386,34466,34472,34454,34445,34449,34462,34439,34455, +34438,34443,34458,34437,34469,34457,34465,34471,34453,34456,34446,34461,34448, +34452,34883,34884,34925,34933,34934,34930,34944,34929,34943,34927,34947,34942, +34932,34940,35346,35911,35927,35963,36004,36003,36214,36216,36277,36279,36278, +36561,36563,36862,36853,36866,36863,36859,36868,36860,36854,37078,37088,37081, +37082,37091,37087,37093,37080,37083,37079,37084,37092,37200,37198,37199,37333, +37346,37338,38492,38495,38588,39139,39647,39727,20095,20592,20586,20577,20574, +20576,20563,20555,20573,20594,20552,20557,20545,20571,20554,20578,20501,20549, +20575,20585,20587,20579,20580,20550,20544,20590,20595,20567,20561,20944,21099, +21101,21100,21102,21206,21203,21293,21404,21877,21878,21820,21837,21840,21812, +21802,21841,21858,21814,21813,21808,21842,21829,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,21772,21810,21861,21838,21817,21832, +21805,21819,21824,21835,22282,22279,22523,22548,22498,22518,22492,22516,22528, +22509,22525,22536,22520,22539,22515,22479,22535,22510,22499,22514,22501,22508, +22497,22542,22524,22544,22503,22529,22540,22513,22505,22512,22541,22532,22876, +23136,23128,23125,23143,23134,23096,23093,23149,23120,23135,23141,23148,23123, +23140,23127,23107,23133,23122,23108,23131,23112,23182,23102,23117,23097,23116, +23152,23145,23111,23121,23126,23106,23132,23410,23406,23489,23488,23641,23838, +23819,23837,23834,23840,23820,23848,23821,23846,23845,23823,23856,23826,23843, +23839,23854,24126,24116,24241,24244,24249,24242,24243,24374,24376,24475,24470, +24479,24714,24720,24710,24766,24752,24762,24787,24788,24783,24804,24793,24797, +24776,24753,24795,24759,24778,24767,24771,24781,24768,25394,25445,25482,25474, +25469,25533,25502,25517,25501,25495,25515,25486,25455,25479,25488,25454,25519, +25461,25500,25453,25518,25468,25508,25403,25503,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25464,25477,25473,25489,25485,25456, +25939,26061,26213,26209,26203,26201,26204,26210,26392,26745,26759,26768,26780, +26733,26734,26798,26795,26966,26735,26787,26796,26793,26741,26740,26802,26767, +26743,26770,26748,26731,26738,26794,26752,26737,26750,26779,26774,26763,26784, +26761,26788,26744,26747,26769,26764,26762,26749,27446,27443,27447,27448,27537, +27535,27533,27534,27532,27690,28096,28075,28084,28083,28276,28076,28137,28130, +28087,28150,28116,28160,28104,28128,28127,28118,28094,28133,28124,28125,28123, +28148,28106,28093,28141,28144,28090,28117,28098,28111,28105,28112,28146,28115, +28157,28119,28109,28131,28091,28922,28941,28919,28951,28916,28940,28912,28932, +28915,28944,28924,28927,28934,28947,28928,28920,28918,28939,28930,28942,29310, +29307,29308,29311,29469,29463,29447,29457,29464,29450,29448,29439,29455,29470, +29576,29686,29688,29685,29700,29697,29693,29703,29696,29690,29692,29695,29708, +29707,29684,29704,30052,30051,30158,30162,30159,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30155,30156,30161,30160,30351,30345, +30419,30521,30511,30509,30513,30514,30516,30515,30525,30501,30523,30517,30792, +30802,30793,30797,30794,30796,30758,30789,30800,31076,31079,31081,31082,31075, +31083,31073,31163,31226,31224,31222,31223,31375,31380,31376,31541,31559,31540, +31525,31536,31522,31524,31539,31512,31530,31517,31537,31531,31533,31535,31538, +31544,31514,31523,31892,31896,31894,31907,32053,32061,32056,32054,32058,32069, +32044,32041,32065,32071,32062,32063,32074,32059,32040,32611,32661,32668,32669, +32667,32714,32715,32717,32720,32721,32711,32719,32713,32799,32798,32795,32839, +32835,32840,33048,33061,33049,33051,33069,33055,33068,33054,33057,33045,33063, +33053,33058,33297,33336,33331,33338,33332,33330,33396,33680,33699,33704,33677, +33658,33651,33700,33652,33679,33665,33685,33689,33653,33684,33705,33661,33667, +33676,33693,33691,33706,33675,33662,33701,33711,33672,33687,33712,33663,33702, +33671,33710,33654,33690,34393,34390,34495,34487,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34498,34497,34501,34490,34480,34504, +34489,34483,34488,34508,34484,34491,34492,34499,34493,34494,34898,34953,34965, +34984,34978,34986,34970,34961,34977,34975,34968,34983,34969,34971,34967,34980, +34988,34956,34963,34958,35202,35286,35289,35285,35376,35367,35372,35358,35897, +35899,35932,35933,35965,36005,36221,36219,36217,36284,36290,36281,36287,36289, +36568,36574,36573,36572,36567,36576,36577,36900,36875,36881,36892,36876,36897, +37103,37098,37104,37108,37106,37107,37076,37099,37100,37097,37206,37208,37210, +37203,37205,37356,37364,37361,37363,37368,37348,37369,37354,37355,37367,37352, +37358,38266,38278,38280,38524,38509,38507,38513,38511,38591,38762,38916,39141, +39319,20635,20629,20628,20638,20619,20643,20611,20620,20622,20637,20584,20636, +20626,20610,20615,20831,20948,21266,21265,21412,21415,21905,21928,21925,21933, +21879,22085,21922,21907,21896,21903,21941,21889,21923,21906,21924,21885,21900, +21926,21887,21909,21921,21902,22284,22569,22583,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,22553,22558,22567,22563,22568,22517, +22600,22565,22556,22555,22579,22591,22582,22574,22585,22584,22573,22572,22587, +22881,23215,23188,23199,23162,23202,23198,23160,23206,23164,23205,23212,23189, +23214,23095,23172,23178,23191,23171,23179,23209,23163,23165,23180,23196,23183, +23187,23197,23530,23501,23499,23508,23505,23498,23502,23564,23600,23863,23875, +23915,23873,23883,23871,23861,23889,23886,23893,23859,23866,23890,23869,23857, +23897,23874,23865,23881,23864,23868,23858,23862,23872,23877,24132,24129,24408, +24486,24485,24491,24777,24761,24780,24802,24782,24772,24852,24818,24842,24854, +24837,24821,24851,24824,24828,24830,24769,24835,24856,24861,24848,24831,24836, +24843,25162,25492,25521,25520,25550,25573,25576,25583,25539,25757,25587,25546, +25568,25590,25557,25586,25589,25697,25567,25534,25565,25564,25540,25560,25555, +25538,25543,25548,25547,25544,25584,25559,25561,25906,25959,25962,25956,25948, +25960,25957,25996,26013,26014,26030,26064,26066,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,26236,26220,26235,26240,26225,26233, +26218,26226,26369,26892,26835,26884,26844,26922,26860,26858,26865,26895,26838, +26871,26859,26852,26870,26899,26896,26867,26849,26887,26828,26888,26992,26804, +26897,26863,26822,26900,26872,26832,26877,26876,26856,26891,26890,26903,26830, +26824,26845,26846,26854,26868,26833,26886,26836,26857,26901,26917,26823,27449, +27451,27455,27452,27540,27543,27545,27541,27581,27632,27634,27635,27696,28156, +28230,28231,28191,28233,28296,28220,28221,28229,28258,28203,28223,28225,28253, +28275,28188,28211,28235,28224,28241,28219,28163,28206,28254,28264,28252,28257, +28209,28200,28256,28273,28267,28217,28194,28208,28243,28261,28199,28280,28260, +28279,28245,28281,28242,28262,28213,28214,28250,28960,28958,28975,28923,28974, +28977,28963,28965,28962,28978,28959,28968,28986,28955,29259,29274,29320,29321, +29318,29317,29323,29458,29451,29488,29474,29489,29491,29479,29490,29485,29478, +29475,29493,29452,29742,29740,29744,29739,29718,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29722,29729,29741,29745,29732,29731, +29725,29737,29728,29746,29947,29999,30063,30060,30183,30170,30177,30182,30173, +30175,30180,30167,30357,30354,30426,30534,30535,30532,30541,30533,30538,30542, +30539,30540,30686,30700,30816,30820,30821,30812,30829,30833,30826,30830,30832, +30825,30824,30814,30818,31092,31091,31090,31088,31234,31242,31235,31244,31236, +31385,31462,31460,31562,31547,31556,31560,31564,31566,31552,31576,31557,31906, +31902,31912,31905,32088,32111,32099,32083,32086,32103,32106,32079,32109,32092, +32107,32082,32084,32105,32081,32095,32078,32574,32575,32613,32614,32674,32672, +32673,32727,32849,32847,32848,33022,32980,33091,33098,33106,33103,33095,33085, +33101,33082,33254,33262,33271,33272,33273,33284,33340,33341,33343,33397,33595, +33743,33785,33827,33728,33768,33810,33767,33764,33788,33782,33808,33734,33736, +33771,33763,33727,33793,33757,33765,33752,33791,33761,33739,33742,33750,33781, +33737,33801,33807,33758,33809,33798,33730,33779,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33749,33786,33735,33745,33770,33811, +33731,33772,33774,33732,33787,33751,33762,33819,33755,33790,34520,34530,34534, +34515,34531,34522,34538,34525,34539,34524,34540,34537,34519,34536,34513,34888, +34902,34901,35002,35031,35001,35000,35008,35006,34998,35004,34999,35005,34994, +35073,35017,35221,35224,35223,35293,35290,35291,35406,35405,35385,35417,35392, +35415,35416,35396,35397,35410,35400,35409,35402,35404,35407,35935,35969,35968, +36026,36030,36016,36025,36021,36228,36224,36233,36312,36307,36301,36295,36310, +36316,36303,36309,36313,36296,36311,36293,36591,36599,36602,36601,36582,36590, +36581,36597,36583,36584,36598,36587,36593,36588,36596,36585,36909,36916,36911, +37126,37164,37124,37119,37116,37128,37113,37115,37121,37120,37127,37125,37123, +37217,37220,37215,37218,37216,37377,37386,37413,37379,37402,37414,37391,37388, +37376,37394,37375,37373,37382,37380,37415,37378,37404,37412,37401,37399,37381, +37398,38267,38285,38284,38288,38535,38526,38536,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38537,38531,38528,38594,38600,38595, +38641,38640,38764,38768,38766,38919,39081,39147,40166,40697,20099,20100,20150, +20669,20671,20678,20654,20676,20682,20660,20680,20674,20656,20673,20666,20657, +20683,20681,20662,20664,20951,21114,21112,21115,21116,21955,21979,21964,21968, +21963,21962,21981,21952,21972,21956,21993,21951,21970,21901,21967,21973,21986, +21974,21960,22002,21965,21977,21954,22292,22611,22632,22628,22607,22605,22601, +22639,22613,22606,22621,22617,22629,22619,22589,22627,22641,22780,23239,23236, +23243,23226,23224,23217,23221,23216,23231,23240,23227,23238,23223,23232,23242, +23220,23222,23245,23225,23184,23510,23512,23513,23583,23603,23921,23907,23882, +23909,23922,23916,23902,23912,23911,23906,24048,24143,24142,24138,24141,24139, +24261,24268,24262,24267,24263,24384,24495,24493,24823,24905,24906,24875,24901, +24886,24882,24878,24902,24879,24911,24873,24896,25120,37224,25123,25125,25124, +25541,25585,25579,25616,25618,25609,25632,25636,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25651,25667,25631,25621,25624,25657, +25655,25634,25635,25612,25638,25648,25640,25665,25653,25647,25610,25626,25664, +25637,25639,25611,25575,25627,25646,25633,25614,25967,26002,26067,26246,26252, +26261,26256,26251,26250,26265,26260,26232,26400,26982,26975,26936,26958,26978, +26993,26943,26949,26986,26937,26946,26967,26969,27002,26952,26953,26933,26988, +26931,26941,26981,26864,27000,26932,26985,26944,26991,26948,26998,26968,26945, +26996,26956,26939,26955,26935,26972,26959,26961,26930,26962,26927,27003,26940, +27462,27461,27459,27458,27464,27457,27547,64013,27643,27644,27641,27639,27640, +28315,28374,28360,28303,28352,28319,28307,28308,28320,28337,28345,28358,28370, +28349,28353,28318,28361,28343,28336,28365,28326,28367,28338,28350,28355,28380, +28376,28313,28306,28302,28301,28324,28321,28351,28339,28368,28362,28311,28334, +28323,28999,29012,29010,29027,29024,28993,29021,29026,29042,29048,29034,29025, +28994,29016,28995,29003,29040,29023,29008,29011,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28996,29005,29018,29263,29325,29324, +29329,29328,29326,29500,29506,29499,29498,29504,29514,29513,29764,29770,29771, +29778,29777,29783,29760,29775,29776,29774,29762,29766,29773,29780,29921,29951, +29950,29949,29981,30073,30071,27011,30191,30223,30211,30199,30206,30204,30201, +30200,30224,30203,30198,30189,30197,30205,30361,30389,30429,30549,30559,30560, +30546,30550,30554,30569,30567,30548,30553,30573,30688,30855,30874,30868,30863, +30852,30869,30853,30854,30881,30851,30841,30873,30848,30870,30843,31100,31106, +31101,31097,31249,31256,31257,31250,31255,31253,31266,31251,31259,31248,31395, +31394,31390,31467,31590,31588,31597,31604,31593,31602,31589,31603,31601,31600, +31585,31608,31606,31587,31922,31924,31919,32136,32134,32128,32141,32127,32133, +32122,32142,32123,32131,32124,32140,32148,32132,32125,32146,32621,32619,32615, +32616,32620,32678,32677,32679,32731,32732,32801,33124,33120,33143,33116,33129, +33115,33122,33138,26401,33118,33142,33127,33135,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33092,33121,33309,33353,33348,33344, +33346,33349,34033,33855,33878,33910,33913,33935,33933,33893,33873,33856,33926, +33895,33840,33869,33917,33882,33881,33908,33907,33885,34055,33886,33847,33850, +33844,33914,33859,33912,33842,33861,33833,33753,33867,33839,33858,33837,33887, +33904,33849,33870,33868,33874,33903,33989,33934,33851,33863,33846,33843,33896, +33918,33860,33835,33888,33876,33902,33872,34571,34564,34551,34572,34554,34518, +34549,34637,34552,34574,34569,34561,34550,34573,34565,35030,35019,35021,35022, +35038,35035,35034,35020,35024,35205,35227,35295,35301,35300,35297,35296,35298, +35292,35302,35446,35462,35455,35425,35391,35447,35458,35460,35445,35459,35457, +35444,35450,35900,35915,35914,35941,35940,35942,35974,35972,35973,36044,36200, +36201,36241,36236,36238,36239,36237,36243,36244,36240,36242,36336,36320,36332, +36337,36334,36304,36329,36323,36322,36327,36338,36331,36340,36614,36607,36609, +36608,36613,36615,36616,36610,36619,36946,36927,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,36932,36937,36925,37136,37133,37135, +37137,37142,37140,37131,37134,37230,37231,37448,37458,37424,37434,37478,37427, +37477,37470,37507,37422,37450,37446,37485,37484,37455,37472,37479,37487,37430, +37473,37488,37425,37460,37475,37456,37490,37454,37459,37452,37462,37426,38303, +38300,38302,38299,38546,38547,38545,38551,38606,38650,38653,38648,38645,38771, +38775,38776,38770,38927,38925,38926,39084,39158,39161,39343,39346,39344,39349, +39597,39595,39771,40170,40173,40167,40576,40701,20710,20692,20695,20712,20723, +20699,20714,20701,20708,20691,20716,20720,20719,20707,20704,20952,21120,21121, +21225,21227,21296,21420,22055,22037,22028,22034,22012,22031,22044,22017,22035, +22018,22010,22045,22020,22015,22009,22665,22652,22672,22680,22662,22657,22655, +22644,22667,22650,22663,22673,22670,22646,22658,22664,22651,22676,22671,22782, +22891,23260,23278,23269,23253,23274,23258,23277,23275,23283,23266,23264,23259, +23276,23262,23261,23257,23272,23263,23415,23520,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,23523,23651,23938,23936,23933,23942, +23930,23937,23927,23946,23945,23944,23934,23932,23949,23929,23935,24152,24153, +24147,24280,24273,24279,24270,24284,24277,24281,24274,24276,24388,24387,24431, +24502,24876,24872,24897,24926,24945,24947,24914,24915,24946,24940,24960,24948, +24916,24954,24923,24933,24891,24938,24929,24918,25129,25127,25131,25643,25677, +25691,25693,25716,25718,25714,25715,25725,25717,25702,25766,25678,25730,25694, +25692,25675,25683,25696,25680,25727,25663,25708,25707,25689,25701,25719,25971, +26016,26273,26272,26271,26373,26372,26402,27057,27062,27081,27040,27086,27030, +27056,27052,27068,27025,27033,27022,27047,27021,27049,27070,27055,27071,27076, +27069,27044,27092,27065,27082,27034,27087,27059,27027,27050,27041,27038,27097, +27031,27024,27074,27061,27045,27078,27466,27469,27467,27550,27551,27552,27587, +27588,27646,28366,28405,28401,28419,28453,28408,28471,28411,28462,28425,28494, +28441,28442,28455,28440,28475,28434,28397,28426,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,28470,28531,28409,28398,28461,28480, +28464,28476,28469,28395,28423,28430,28483,28421,28413,28406,28473,28444,28412, +28474,28447,28429,28446,28424,28449,29063,29072,29065,29056,29061,29058,29071, +29051,29062,29057,29079,29252,29267,29335,29333,29331,29507,29517,29521,29516, +29794,29811,29809,29813,29810,29799,29806,29952,29954,29955,30077,30096,30230, +30216,30220,30229,30225,30218,30228,30392,30593,30588,30597,30594,30574,30592, +30575,30590,30595,30898,30890,30900,30893,30888,30846,30891,30878,30885,30880, +30892,30882,30884,31128,31114,31115,31126,31125,31124,31123,31127,31112,31122, +31120,31275,31306,31280,31279,31272,31270,31400,31403,31404,31470,31624,31644, +31626,31633,31632,31638,31629,31628,31643,31630,31621,31640,21124,31641,31652, +31618,31931,31935,31932,31930,32167,32183,32194,32163,32170,32193,32192,32197, +32157,32206,32196,32198,32203,32204,32175,32185,32150,32188,32159,32166,32174, +32169,32161,32201,32627,32738,32739,32741,32734,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,32804,32861,32860,33161,33158,33155, +33159,33165,33164,33163,33301,33943,33956,33953,33951,33978,33998,33986,33964, +33966,33963,33977,33972,33985,33997,33962,33946,33969,34000,33949,33959,33979, +33954,33940,33991,33996,33947,33961,33967,33960,34006,33944,33974,33999,33952, +34007,34004,34002,34011,33968,33937,34401,34611,34595,34600,34667,34624,34606, +34590,34593,34585,34587,34627,34604,34625,34622,34630,34592,34610,34602,34605, +34620,34578,34618,34609,34613,34626,34598,34599,34616,34596,34586,34608,34577, +35063,35047,35057,35058,35066,35070,35054,35068,35062,35067,35056,35052,35051, +35229,35233,35231,35230,35305,35307,35304,35499,35481,35467,35474,35471,35478, +35901,35944,35945,36053,36047,36055,36246,36361,36354,36351,36365,36349,36362, +36355,36359,36358,36357,36350,36352,36356,36624,36625,36622,36621,37155,37148, +37152,37154,37151,37149,37146,37156,37153,37147,37242,37234,37241,37235,37541, +37540,37494,37531,37498,37536,37524,37546,37517,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,37542,37530,37547,37497,37527,37503, +37539,37614,37518,37506,37525,37538,37501,37512,37537,37514,37510,37516,37529, +37543,37502,37511,37545,37533,37515,37421,38558,38561,38655,38744,38781,38778, +38782,38787,38784,38786,38779,38788,38785,38783,38862,38861,38934,39085,39086, +39170,39168,39175,39325,39324,39363,39353,39355,39354,39362,39357,39367,39601, +39651,39655,39742,39743,39776,39777,39775,40177,40178,40181,40615,20735,20739, +20784,20728,20742,20743,20726,20734,20747,20748,20733,20746,21131,21132,21233, +21231,22088,22082,22092,22069,22081,22090,22089,22086,22104,22106,22080,22067, +22077,22060,22078,22072,22058,22074,22298,22699,22685,22705,22688,22691,22703, +22700,22693,22689,22783,23295,23284,23293,23287,23286,23299,23288,23298,23289, +23297,23303,23301,23311,23655,23961,23959,23967,23954,23970,23955,23957,23968, +23964,23969,23962,23966,24169,24157,24160,24156,32243,24283,24286,24289,24393, +24498,24971,24963,24953,25009,25008,24994,24969,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,24987,24979,25007,25005,24991,24978, +25002,24993,24973,24934,25011,25133,25710,25712,25750,25760,25733,25751,25756, +25743,25739,25738,25740,25763,25759,25704,25777,25752,25974,25978,25977,25979, +26034,26035,26293,26288,26281,26290,26295,26282,26287,27136,27142,27159,27109, +27128,27157,27121,27108,27168,27135,27116,27106,27163,27165,27134,27175,27122, +27118,27156,27127,27111,27200,27144,27110,27131,27149,27132,27115,27145,27140, +27160,27173,27151,27126,27174,27143,27124,27158,27473,27557,27555,27554,27558, +27649,27648,27647,27650,28481,28454,28542,28551,28614,28562,28557,28553,28556, +28514,28495,28549,28506,28566,28534,28524,28546,28501,28530,28498,28496,28503, +28564,28563,28509,28416,28513,28523,28541,28519,28560,28499,28555,28521,28543, +28565,28515,28535,28522,28539,29106,29103,29083,29104,29088,29082,29097,29109, +29085,29093,29086,29092,29089,29098,29084,29095,29107,29336,29338,29528,29522, +29534,29535,29536,29533,29531,29537,29530,29529,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,29538,29831,29833,29834,29830,29825, +29821,29829,29832,29820,29817,29960,29959,30078,30245,30238,30233,30237,30236, +30243,30234,30248,30235,30364,30365,30366,30363,30605,30607,30601,30600,30925, +30907,30927,30924,30929,30926,30932,30920,30915,30916,30921,31130,31137,31136, +31132,31138,31131,27510,31289,31410,31412,31411,31671,31691,31678,31660,31694, +31663,31673,31690,31669,31941,31944,31948,31947,32247,32219,32234,32231,32215, +32225,32259,32250,32230,32246,32241,32240,32238,32223,32630,32684,32688,32685, +32749,32747,32746,32748,32742,32744,32868,32871,33187,33183,33182,33173,33186, +33177,33175,33302,33359,33363,33362,33360,33358,33361,34084,34107,34063,34048, +34089,34062,34057,34061,34079,34058,34087,34076,34043,34091,34042,34056,34060, +34036,34090,34034,34069,34039,34027,34035,34044,34066,34026,34025,34070,34046, +34088,34077,34094,34050,34045,34078,34038,34097,34086,34023,34024,34032,34031, +34041,34072,34080,34096,34059,34073,34095,34402,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,34646,34659,34660,34679,34785,34675, +34648,34644,34651,34642,34657,34650,34641,34654,34669,34666,34640,34638,34655, +34653,34671,34668,34682,34670,34652,34661,34639,34683,34677,34658,34663,34665, +34906,35077,35084,35092,35083,35095,35096,35097,35078,35094,35089,35086,35081, +35234,35236,35235,35309,35312,35308,35535,35526,35512,35539,35537,35540,35541, +35515,35543,35518,35520,35525,35544,35523,35514,35517,35545,35902,35917,35983, +36069,36063,36057,36072,36058,36061,36071,36256,36252,36257,36251,36384,36387, +36389,36388,36398,36373,36379,36374,36369,36377,36390,36391,36372,36370,36376, +36371,36380,36375,36378,36652,36644,36632,36634,36640,36643,36630,36631,36979, +36976,36975,36967,36971,37167,37163,37161,37162,37170,37158,37166,37253,37254, +37258,37249,37250,37252,37248,37584,37571,37572,37568,37593,37558,37583,37617, +37599,37592,37609,37591,37597,37580,37615,37570,37608,37578,37576,37582,37606, +37581,37589,37577,37600,37598,37607,37585,37587,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,37557,37601,37574,37556,38268,38316, +38315,38318,38320,38564,38562,38611,38661,38664,38658,38746,38794,38798,38792, +38864,38863,38942,38941,38950,38953,38952,38944,38939,38951,39090,39176,39162, +39185,39188,39190,39191,39189,39388,39373,39375,39379,39380,39374,39369,39382, +39384,39371,39383,39372,39603,39660,39659,39667,39666,39665,39750,39747,39783, +39796,39793,39782,39798,39797,39792,39784,39780,39788,40188,40186,40189,40191, +40183,40199,40192,40185,40187,40200,40197,40196,40579,40659,40719,40720,20764, +20755,20759,20762,20753,20958,21300,21473,22128,22112,22126,22131,22118,22115, +22125,22130,22110,22135,22300,22299,22728,22717,22729,22719,22714,22722,22716, +22726,23319,23321,23323,23329,23316,23315,23312,23318,23336,23322,23328,23326, +23535,23980,23985,23977,23975,23989,23984,23982,23978,23976,23986,23981,23983, +23988,24167,24168,24166,24175,24297,24295,24294,24296,24293,24395,24508,24989, +25000,24982,25029,25012,25030,25025,25036,25018,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,25023,25016,24972,25815,25814,25808, +25807,25801,25789,25737,25795,25819,25843,25817,25907,25983,25980,26018,26312, +26302,26304,26314,26315,26319,26301,26299,26298,26316,26403,27188,27238,27209, +27239,27186,27240,27198,27229,27245,27254,27227,27217,27176,27226,27195,27199, +27201,27242,27236,27216,27215,27220,27247,27241,27232,27196,27230,27222,27221, +27213,27214,27206,27477,27476,27478,27559,27562,27563,27592,27591,27652,27651, +27654,28589,28619,28579,28615,28604,28622,28616,28510,28612,28605,28574,28618, +28584,28676,28581,28590,28602,28588,28586,28623,28607,28600,28578,28617,28587, +28621,28591,28594,28592,29125,29122,29119,29112,29142,29120,29121,29131,29140, +29130,29127,29135,29117,29144,29116,29126,29146,29147,29341,29342,29545,29542, +29543,29548,29541,29547,29546,29823,29850,29856,29844,29842,29845,29857,29963, +30080,30255,30253,30257,30269,30259,30268,30261,30258,30256,30395,30438,30618, +30621,30625,30620,30619,30626,30627,30613,30617,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30615,30941,30953,30949,30954,30942, +30947,30939,30945,30946,30957,30943,30944,31140,31300,31304,31303,31414,31416, +31413,31409,31415,31710,31715,31719,31709,31701,31717,31706,31720,31737,31700, +31722,31714,31708,31723,31704,31711,31954,31956,31959,31952,31953,32274,32289, +32279,32268,32287,32288,32275,32270,32284,32277,32282,32290,32267,32271,32278, +32269,32276,32293,32292,32579,32635,32636,32634,32689,32751,32810,32809,32876, +33201,33190,33198,33209,33205,33195,33200,33196,33204,33202,33207,33191,33266, +33365,33366,33367,34134,34117,34155,34125,34131,34145,34136,34112,34118,34148, +34113,34146,34116,34129,34119,34147,34110,34139,34161,34126,34158,34165,34133, +34151,34144,34188,34150,34141,34132,34149,34156,34403,34405,34404,34715,34703, +34711,34707,34706,34696,34689,34710,34712,34681,34695,34723,34693,34704,34705, +34717,34692,34708,34716,34714,34697,35102,35110,35120,35117,35118,35111,35121, +35106,35113,35107,35119,35116,35103,35313,35552,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,35554,35570,35572,35573,35549,35604, +35556,35551,35568,35528,35550,35553,35560,35583,35567,35579,35985,35986,35984, +36085,36078,36081,36080,36083,36204,36206,36261,36263,36403,36414,36408,36416, +36421,36406,36412,36413,36417,36400,36415,36541,36662,36654,36661,36658,36665, +36663,36660,36982,36985,36987,36998,37114,37171,37173,37174,37267,37264,37265, +37261,37263,37671,37662,37640,37663,37638,37647,37754,37688,37692,37659,37667, +37650,37633,37702,37677,37646,37645,37579,37661,37626,37669,37651,37625,37623, +37684,37634,37668,37631,37673,37689,37685,37674,37652,37644,37643,37630,37641, +37632,37627,37654,38332,38349,38334,38329,38330,38326,38335,38325,38333,38569, +38612,38667,38674,38672,38809,38807,38804,38896,38904,38965,38959,38962,39204, +39199,39207,39209,39326,39406,39404,39397,39396,39408,39395,39402,39401,39399, +39609,39615,39604,39611,39670,39674,39673,39671,39731,39808,39813,39815,39804, +39806,39803,39810,39827,39826,39824,39802,39829,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39805,39816,40229,40215,40224,40222, +40212,40233,40221,40216,40226,40208,40217,40223,40584,40582,40583,40622,40621, +40661,40662,40698,40722,40765,20774,20773,20770,20772,20768,20777,21236,22163, +22156,22157,22150,22148,22147,22142,22146,22143,22145,22742,22740,22735,22738, +23341,23333,23346,23331,23340,23335,23334,23343,23342,23419,23537,23538,23991, +24172,24170,24510,24507,25027,25013,25020,25063,25056,25061,25060,25064,25054, +25839,25833,25827,25835,25828,25832,25985,25984,26038,26074,26322,27277,27286, +27265,27301,27273,27295,27291,27297,27294,27271,27283,27278,27285,27267,27304, +27300,27281,27263,27302,27290,27269,27276,27282,27483,27565,27657,28620,28585, +28660,28628,28643,28636,28653,28647,28646,28638,28658,28637,28642,28648,29153, +29169,29160,29170,29156,29168,29154,29555,29550,29551,29847,29874,29867,29840, +29866,29869,29873,29861,29871,29968,29969,29970,29967,30084,30275,30280,30281, +30279,30372,30441,30645,30635,30642,30647,30646,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,30644,30641,30632,30704,30963,30973, +30978,30971,30972,30962,30981,30969,30974,30980,31147,31144,31324,31323,31318, +31320,31316,31322,31422,31424,31425,31749,31759,31730,31744,31743,31739,31758, +31732,31755,31731,31746,31753,31747,31745,31736,31741,31750,31728,31729,31760, +31754,31976,32301,32316,32322,32307,38984,32312,32298,32329,32320,32327,32297, +32332,32304,32315,32310,32324,32314,32581,32639,32638,32637,32756,32754,32812, +33211,33220,33228,33226,33221,33223,33212,33257,33371,33370,33372,34179,34176, +34191,34215,34197,34208,34187,34211,34171,34212,34202,34206,34167,34172,34185, +34209,34170,34168,34135,34190,34198,34182,34189,34201,34205,34177,34210,34178, +34184,34181,34169,34166,34200,34192,34207,34408,34750,34730,34733,34757,34736, +34732,34745,34741,34748,34734,34761,34755,34754,34764,34743,34735,34756,34762, +34740,34742,34751,34744,34749,34782,34738,35125,35123,35132,35134,35137,35154, +35127,35138,35245,35247,35246,35314,35315,35614,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,35608,35606,35601,35589,35595,35618, +35599,35602,35605,35591,35597,35592,35590,35612,35603,35610,35919,35952,35954, +35953,35951,35989,35988,36089,36207,36430,36429,36435,36432,36428,36423,36675, +36672,36997,36990,37176,37274,37282,37275,37273,37279,37281,37277,37280,37793, +37763,37807,37732,37718,37703,37756,37720,37724,37750,37705,37712,37713,37728, +37741,37775,37708,37738,37753,37719,37717,37714,37711,37745,37751,37755,37729, +37726,37731,37735,37760,37710,37721,38343,38336,38345,38339,38341,38327,38574, +38576,38572,38688,38687,38680,38685,38681,38810,38817,38812,38814,38813,38869, +38868,38897,38977,38980,38986,38985,38981,38979,39205,39211,39212,39210,39219, +39218,39215,39213,39217,39216,39320,39331,39329,39426,39418,39412,39415,39417, +39416,39414,39419,39421,39422,39420,39427,39614,39678,39677,39681,39676,39752, +39834,39848,39838,39835,39846,39841,39845,39844,39814,39842,39840,39855,40243, +40257,40295,40246,40238,40239,40241,40248,40240,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40261,40258,40259,40254,40247,40256, +40253,32757,40237,40586,40585,40589,40624,40648,40666,40699,40703,40740,40739, +40738,40788,40864,20785,20781,20782,22168,22172,22167,22170,22173,22169,22896, +23356,23657,23658,24000,24173,24174,25048,25055,25069,25070,25073,25066,25072, +25067,25046,25065,25855,25860,25853,25848,25857,25859,25852,26004,26075,26330, +26331,26328,27333,27321,27325,27361,27334,27322,27318,27319,27335,27316,27309, +27486,27593,27659,28679,28684,28685,28673,28677,28692,28686,28671,28672,28667, +28710,28668,28663,28682,29185,29183,29177,29187,29181,29558,29880,29888,29877, +29889,29886,29878,29883,29890,29972,29971,30300,30308,30297,30288,30291,30295, +30298,30374,30397,30444,30658,30650,30975,30988,30995,30996,30985,30992,30994, +30993,31149,31148,31327,31772,31785,31769,31776,31775,31789,31773,31782,31784, +31778,31781,31792,32348,32336,32342,32355,32344,32354,32351,32337,32352,32343, +32339,32693,32691,32759,32760,32885,33233,33234,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,33232,33375,33374,34228,34246,34240, +34243,34242,34227,34229,34237,34247,34244,34239,34251,34254,34248,34245,34225, +34230,34258,34340,34232,34231,34238,34409,34791,34790,34786,34779,34795,34794, +34789,34783,34803,34788,34772,34780,34771,34797,34776,34787,34724,34775,34777, +34817,34804,34792,34781,35155,35147,35151,35148,35142,35152,35153,35145,35626, +35623,35619,35635,35632,35637,35655,35631,35644,35646,35633,35621,35639,35622, +35638,35630,35620,35643,35645,35642,35906,35957,35993,35992,35991,36094,36100, +36098,36096,36444,36450,36448,36439,36438,36446,36453,36455,36443,36442,36449, +36445,36457,36436,36678,36679,36680,36683,37160,37178,37179,37182,37288,37285, +37287,37295,37290,37813,37772,37778,37815,37787,37789,37769,37799,37774,37802, +37790,37798,37781,37768,37785,37791,37773,37809,37777,37810,37796,37800,37812, +37795,37797,38354,38355,38353,38579,38615,38618,24002,38623,38616,38621,38691, +38690,38693,38828,38830,38824,38827,38820,38826,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38818,38821,38871,38873,38870,38872, +38906,38992,38993,38994,39096,39233,39228,39226,39439,39435,39433,39437,39428, +39441,39434,39429,39431,39430,39616,39644,39688,39684,39685,39721,39733,39754, +39756,39755,39879,39878,39875,39871,39873,39861,39864,39891,39862,39876,39865, +39869,40284,40275,40271,40266,40283,40267,40281,40278,40268,40279,40274,40276, +40287,40280,40282,40590,40588,40671,40705,40704,40726,40741,40747,40746,40745, +40744,40780,40789,20788,20789,21142,21239,21428,22187,22189,22182,22183,22186, +22188,22746,22749,22747,22802,23357,23358,23359,24003,24176,24511,25083,25863, +25872,25869,25865,25868,25870,25988,26078,26077,26334,27367,27360,27340,27345, +27353,27339,27359,27356,27344,27371,27343,27341,27358,27488,27568,27660,28697, +28711,28704,28694,28715,28705,28706,28707,28713,28695,28708,28700,28714,29196, +29194,29191,29186,29189,29349,29350,29348,29347,29345,29899,29893,29879,29891, +29974,30304,30665,30666,30660,30705,31005,31003,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31009,31004,30999,31006,31152,31335, +31336,31795,31804,31801,31788,31803,31980,31978,32374,32373,32376,32368,32375, +32367,32378,32370,32372,32360,32587,32586,32643,32646,32695,32765,32766,32888, +33239,33237,33380,33377,33379,34283,34289,34285,34265,34273,34280,34266,34263, +34284,34290,34296,34264,34271,34275,34268,34257,34288,34278,34287,34270,34274, +34816,34810,34819,34806,34807,34825,34828,34827,34822,34812,34824,34815,34826, +34818,35170,35162,35163,35159,35169,35164,35160,35165,35161,35208,35255,35254, +35318,35664,35656,35658,35648,35667,35670,35668,35659,35669,35665,35650,35666, +35671,35907,35959,35958,35994,36102,36103,36105,36268,36266,36269,36267,36461, +36472,36467,36458,36463,36475,36546,36690,36689,36687,36688,36691,36788,37184, +37183,37296,37293,37854,37831,37839,37826,37850,37840,37881,37868,37836,37849, +37801,37862,37834,37844,37870,37859,37845,37828,37838,37824,37842,37863,38269, +38362,38363,38625,38697,38699,38700,38696,38694,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,38835,38839,38838,38877,38878,38879, +39004,39001,39005,38999,39103,39101,39099,39102,39240,39239,39235,39334,39335, +39450,39445,39461,39453,39460,39451,39458,39456,39463,39459,39454,39452,39444, +39618,39691,39690,39694,39692,39735,39914,39915,39904,39902,39908,39910,39906, +39920,39892,39895,39916,39900,39897,39909,39893,39905,39898,40311,40321,40330, +40324,40328,40305,40320,40312,40326,40331,40332,40317,40299,40308,40309,40304, +40297,40325,40307,40315,40322,40303,40313,40319,40327,40296,40596,40593,40640, +40700,40749,40768,40769,40781,40790,40791,40792,21303,22194,22197,22195,22755, +23365,24006,24007,24302,24303,24512,24513,25081,25879,25878,25877,25875,26079, +26344,26339,26340,27379,27376,27370,27368,27385,27377,27374,27375,28732,28725, +28719,28727,28724,28721,28738,28728,28735,28730,28729,28736,28731,28723,28737, +29203,29204,29352,29565,29564,29882,30379,30378,30398,30445,30668,30670,30671, +30669,30706,31013,31011,31015,31016,31012,31017,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,31154,31342,31340,31341,31479,31817, +31816,31818,31815,31813,31982,32379,32382,32385,32384,32698,32767,32889,33243, +33241,33291,33384,33385,34338,34303,34305,34302,34331,34304,34294,34308,34313, +34309,34316,34301,34841,34832,34833,34839,34835,34838,35171,35174,35257,35319, +35680,35690,35677,35688,35683,35685,35687,35693,36270,36486,36488,36484,36697, +36694,36695,36693,36696,36698,37005,37187,37185,37303,37301,37298,37299,37899, +37907,37883,37920,37903,37908,37886,37909,37904,37928,37913,37901,37877,37888, +37879,37895,37902,37910,37906,37882,37897,37880,37898,37887,37884,37900,37878, +37905,37894,38366,38368,38367,38702,38703,38841,38843,38909,38910,39008,39010, +39011,39007,39105,39106,39248,39246,39257,39244,39243,39251,39474,39476,39473, +39468,39466,39478,39465,39470,39480,39469,39623,39626,39622,39696,39698,39697, +39947,39944,39927,39941,39954,39928,40000,39943,39950,39942,39959,39956,39945, +40351,40345,40356,40349,40338,40344,40336,40347,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40352,40340,40348,40362,40343,40353, +40346,40354,40360,40350,40355,40383,40361,40342,40358,40359,40601,40603,40602, +40677,40676,40679,40678,40752,40750,40795,40800,40798,40797,40793,40849,20794, +20793,21144,21143,22211,22205,22206,23368,23367,24011,24015,24305,25085,25883, +27394,27388,27395,27384,27392,28739,28740,28746,28744,28745,28741,28742,29213, +29210,29209,29566,29975,30314,30672,31021,31025,31023,31828,31827,31986,32394, +32391,32392,32395,32390,32397,32589,32699,32816,33245,34328,34346,34342,34335, +34339,34332,34329,34343,34350,34337,34336,34345,34334,34341,34857,34845,34843, +34848,34852,34844,34859,34890,35181,35177,35182,35179,35322,35705,35704,35653, +35706,35707,36112,36116,36271,36494,36492,36702,36699,36701,37190,37188,37189, +37305,37951,37947,37942,37929,37949,37948,37936,37945,37930,37943,37932,37952, +37937,38373,38372,38371,38709,38714,38847,38881,39012,39113,39110,39104,39256, +39254,39481,39485,39494,39492,39490,39489,39482,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39487,39629,39701,39703,39704,39702, +39738,39762,39979,39965,39964,39980,39971,39976,39977,39972,39969,40375,40374, +40380,40385,40391,40394,40399,40382,40389,40387,40379,40373,40398,40377,40378, +40364,40392,40369,40365,40396,40371,40397,40370,40570,40604,40683,40686,40685, +40731,40728,40730,40753,40782,40805,40804,40850,20153,22214,22213,22219,22897, +23371,23372,24021,24017,24306,25889,25888,25894,25890,27403,27400,27401,27661, +28757,28758,28759,28754,29214,29215,29353,29567,29912,29909,29913,29911,30317, +30381,31029,31156,31344,31345,31831,31836,31833,31835,31834,31988,31985,32401, +32591,32647,33246,33387,34356,34357,34355,34348,34354,34358,34860,34856,34854, +34858,34853,35185,35263,35262,35323,35710,35716,35714,35718,35717,35711,36117, +36501,36500,36506,36498,36496,36502,36503,36704,36706,37191,37964,37968,37962, +37963,37967,37959,37957,37960,37961,37958,38719,38883,39018,39017,39115,39252, +39259,39502,39507,39508,39500,39503,39496,39498,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,39497,39506,39504,39632,39705,39723, +39739,39766,39765,40006,40008,39999,40004,39993,39987,40001,39996,39991,39988, +39986,39997,39990,40411,40402,40414,40410,40395,40400,40412,40401,40415,40425, +40409,40408,40406,40437,40405,40413,40630,40688,40757,40755,40754,40770,40811, +40853,40866,20797,21145,22760,22759,22898,23373,24024,34863,24399,25089,25091, +25092,25897,25893,26006,26347,27409,27410,27407,27594,28763,28762,29218,29570, +29569,29571,30320,30676,31847,31846,32405,33388,34362,34368,34361,34364,34353, +34363,34366,34864,34866,34862,34867,35190,35188,35187,35326,35724,35726,35723, +35720,35909,36121,36504,36708,36707,37308,37986,37973,37981,37975,37982,38852, +38853,38912,39510,39513,39710,39711,39712,40018,40024,40016,40010,40013,40011, +40021,40025,40012,40014,40443,40439,40431,40419,40427,40440,40420,40438,40417, +40430,40422,40434,40432,40418,40428,40436,40435,40424,40429,40642,40656,40690, +40691,40710,40732,40760,40759,40758,40771,40783,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40817,40816,40814,40815,22227,22221, +23374,23661,25901,26349,26350,27411,28767,28769,28765,28768,29219,29915,29925, +30677,31032,31159,31158,31850,32407,32649,33389,34371,34872,34871,34869,34891, +35732,35733,36510,36511,36512,36509,37310,37309,37314,37995,37992,37993,38629, +38726,38723,38727,38855,38885,39518,39637,39769,40035,40039,40038,40034,40030, +40032,40450,40446,40455,40451,40454,40453,40448,40449,40457,40447,40445,40452, +40608,40734,40774,40820,40821,40822,22228,25902,26040,27416,27417,27415,27418, +28770,29222,29354,30680,30681,31033,31849,31851,31990,32410,32408,32411,32409, +33248,33249,34374,34375,34376,35193,35194,35196,35195,35327,35736,35737,36517, +36516,36515,37998,37997,37999,38001,38003,38729,39026,39263,40040,40046,40045, +40459,40461,40464,40463,40466,40465,40609,40693,40713,40775,40824,40827,40826, +40825,22302,28774,31855,34876,36274,36518,37315,38004,38008,38006,38005,39520, +40052,40051,40049,40053,40468,40467,40694,40714,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,40868,28776,28773,31991,34410,34878, +34877,34879,35742,35996,36521,36553,38731,39027,39028,39116,39265,39339,39524, +39526,39527,39716,40469,40471,40776,25095,27422,29223,34380,36520,38018,38016, +38017,39529,39528,39726,40473,29225,34379,35743,38019,40057,40631,30325,39531, +40058,40477,28777,28778,40612,40830,40777,40856, +}; + +static const struct dbcs_index big5_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5_decmap+0,64,254},{ +__big5_decmap+191,64,254},{__big5_decmap+382,64,191},{__big5_decmap+510,64,254 +},{__big5_decmap+701,64,254},{__big5_decmap+892,64,254},{__big5_decmap+1083, +64,254},{__big5_decmap+1274,64,254},{__big5_decmap+1465,64,254},{__big5_decmap ++1656,64,254},{__big5_decmap+1847,64,254},{__big5_decmap+2038,64,254},{ +__big5_decmap+2229,64,254},{__big5_decmap+2420,64,254},{__big5_decmap+2611,64, +254},{__big5_decmap+2802,64,254},{__big5_decmap+2993,64,254},{__big5_decmap+ +3184,64,254},{__big5_decmap+3375,64,254},{__big5_decmap+3566,64,254},{ +__big5_decmap+3757,64,254},{__big5_decmap+3948,64,254},{__big5_decmap+4139,64, +254},{__big5_decmap+4330,64,254},{__big5_decmap+4521,64,254},{__big5_decmap+ +4712,64,254},{__big5_decmap+4903,64,254},{__big5_decmap+5094,64,254},{ +__big5_decmap+5285,64,254},{__big5_decmap+5476,64,254},{__big5_decmap+5667,64, +254},{__big5_decmap+5858,64,254},{__big5_decmap+6049,64,254},{__big5_decmap+ +6240,64,254},{__big5_decmap+6431,64,254},{__big5_decmap+6622,64,254},{ +__big5_decmap+6813,64,254},{__big5_decmap+7004,64,254},{__big5_decmap+7195,64, +252},{0,0,0},{__big5_decmap+7384,64,254},{__big5_decmap+7575,64,254},{ +__big5_decmap+7766,64,254},{__big5_decmap+7957,64,254},{__big5_decmap+8148,64, +254},{__big5_decmap+8339,64,254},{__big5_decmap+8530,64,254},{__big5_decmap+ +8721,64,254},{__big5_decmap+8912,64,254},{__big5_decmap+9103,64,254},{ +__big5_decmap+9294,64,254},{__big5_decmap+9485,64,254},{__big5_decmap+9676,64, +254},{__big5_decmap+9867,64,254},{__big5_decmap+10058,64,254},{__big5_decmap+ +10249,64,254},{__big5_decmap+10440,64,254},{__big5_decmap+10631,64,254},{ +__big5_decmap+10822,64,254},{__big5_decmap+11013,64,254},{__big5_decmap+11204, +64,254},{__big5_decmap+11395,64,254},{__big5_decmap+11586,64,254},{ +__big5_decmap+11777,64,254},{__big5_decmap+11968,64,254},{__big5_decmap+12159, +64,254},{__big5_decmap+12350,64,254},{__big5_decmap+12541,64,254},{ +__big5_decmap+12732,64,254},{__big5_decmap+12923,64,254},{__big5_decmap+13114, +64,254},{__big5_decmap+13305,64,254},{__big5_decmap+13496,64,254},{ +__big5_decmap+13687,64,254},{__big5_decmap+13878,64,254},{__big5_decmap+14069, +64,254},{__big5_decmap+14260,64,254},{__big5_decmap+14451,64,254},{ +__big5_decmap+14642,64,254},{__big5_decmap+14833,64,254},{__big5_decmap+15024, +64,254},{__big5_decmap+15215,64,254},{__big5_decmap+15406,64,254},{ +__big5_decmap+15597,64,254},{__big5_decmap+15788,64,254},{__big5_decmap+15979, +64,254},{__big5_decmap+16170,64,254},{__big5_decmap+16361,64,254},{ +__big5_decmap+16552,64,213},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __big5_encmap[21764] = { +41542,41543,N,41540,N,41393,N,N,N,N,N,N,N,N,41560,41427,N,N,N,N,N,41296,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41425,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41426,41918,N,41916,41917,41919, +N,41413,N,N,N,N,N,N,N,N,N,N,N,41915,41796,41797,41798,41799,41800,41801,41802, +41803,41804,41805,41806,41807,41808,41809,41810,41811,41812,N,41813,41814, +41815,41816,41817,41818,41819,N,N,N,N,N,N,N,41820,41821,41822,41823,41824, +41825,41826,41827,41828,41829,41830,41831,41832,41833,41834,41835,41836,N, +41837,41838,41839,41840,41841,41842,41843,51123,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,51121,51122,51124,51125,51126,51127,51128,51129,51130,N,N,N,N,N,N,51131, +51132,51133,51134,51135,51136,51137,51138,51139,51140,51141,51142,51143,51144, +51145,51146,51147,51148,51149,51151,51152,51153,51154,51155,51156,51157,51158, +51159,51160,51161,51162,51163,51164,51165,51166,51167,51168,51169,51170,51171, +51172,51173,51174,51175,51176,N,51150,41302,41304,N,N,N,41381,41382,N,N,41383, +41384,N,N,N,N,41285,N,N,41292,41291,N,N,N,N,N,N,N,N,N,N,N,41388,N,N,41387,N,N, +N,N,N,41392,N,N,41410,41546,N,41409,N,N,N,41547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41657,41658, +41659,41660,41661,41662,41663,41664,41665,41666,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41462,41460,41463,41461,N,N, +41464,41465,41467,41466,41428,N,N,N,41435,41448,41447,N,N,41469,N,41468,N,N,N, +41444,41445,41452,N,N,41453,N,N,N,N,N,41455,41454,N,N,N,N,N,N,41443,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41436,N,N,N,N,N,N,N,N,N,N,N,N,N,41434,41437,N, +N,N,N,41432,41433,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41446,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41449,51177,51178,51179,51180,51181, +51182,51183,51184,51185,51186,N,N,N,N,N,N,N,N,N,N,51187,51188,51189,51190, +51191,51192,51193,51194,51195,51196,41591,N,41592,N,N,N,N,N,N,N,N,N,41594,N,N, +N,41595,N,N,N,41596,N,N,N,41597,N,N,N,41589,N,N,N,N,N,N,N,41588,N,N,N,N,N,N,N, +41587,N,N,N,N,N,N,N,41586,N,N,N,N,N,N,N,41585,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,41636,N,N,N,N,N,N,N,N,N,N,N,N,N,41637,N,N,41639,N,N,N,N,N,N,N,N,41638,N, +N,41598,41633,41635,41634,41644,41645,41646,41306,N,N,N,N,N,N,N,N,N,N,N,N, +41570,41571,41572,41573,41574,41575,41576,41577,41584,41583,41582,41581,41580, +41579,41578,N,N,N,N,41590,41593,N,N,N,N,N,N,N,N,N,N,41405,41404,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,41398,41397,N,N,N,N,N,N,N,N,41407,41406,N,N,N,N,N,N,N,N, +41403,41402,N,N,N,41395,N,N,41399,41396,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41640,41641,41643,41642,41401,41400,N,N,41459,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41456,41458,41457,41280,41282,41283,41394,N,50852,N,N,41329,41330,41325,41326, +41333,41334,41337,41338,41321,41322,41541,N,41317,41318,N,N,N,N,N,N,N,41385, +41386,N,N,41667,41668,41669,41670,41671,41672,41673,41674,41675,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,50853,50854,50855,50856,50857,50858,50859, +50860,50861,50862,50863,50864,50865,50866,50867,50868,50869,50870,50871,50872, +50873,50874,50875,50876,50877,50878,50879,50880,50881,50882,50883,50884,50885, +50886,50887,50888,50889,50890,50891,50892,50893,50894,50895,50896,50897,50898, +50899,50900,50901,50902,50903,50904,50905,50906,50907,50908,50909,50910,50911, +50912,50913,50914,50915,50916,50917,50918,50919,50920,50921,50922,50923,50924, +50925,50926,50927,50928,50929,50930,50931,50932,50933,50934,50935,N,N,N,N,N,N, +N,N,N,50850,50851,N,N,50936,50937,50938,50939,50940,50941,50942,51008,51009, +51010,51011,51012,51013,51014,51015,51016,51017,51018,51019,51020,51021,51022, +51023,51024,51025,51026,51027,51028,51029,51030,51031,51032,51033,51034,51035, +51036,51037,51038,51039,51040,51041,51042,51043,51044,51045,51046,51047,51048, +51049,51050,51051,51052,51053,51054,51055,51056,51057,51058,51059,51060,51061, +51062,51063,51064,51065,51066,51067,51068,51069,51070,51105,51106,51107,51108, +51109,51110,51111,51112,51113,51114,51115,51116,51117,51118,51119,51120,N,N,N, +N,N,N,N,50849,41844,41845,41846,41847,41848,41849,41850,41851,41852,41853, +41854,41889,41890,41891,41892,41893,41894,41895,41896,41897,41898,41899,41900, +41901,41902,41903,41904,41905,41906,41907,41908,41909,41910,41911,41912,41913, +41914,41408,41557,41558,N,N,N,N,N,N,N,N,N,N,N,N,41552,41553,41554,N,N,41556,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41559,N,N,N, +N,N,N,N,N,N,41555,N,N,41451,41450,N,N,41551,42048,42050,N,42051,N,N,N,51525, +42070,42068,42071,42069,51526,42147,51535,51533,42146,42145,N,N,42306,42305, +42304,N,42307,42238,N,N,N,N,42464,42465,N,N,N,N,N,N,43203,N,N,N,N,42072,N, +42148,51536,N,42149,51555,42730,52145,N,N,N,N,42073,42150,N,42308,51556,N,N,N, +N,N,51520,42052,N,42075,N,51527,42076,N,N,42151,N,42309,42311,42310,N,N,42466, +42467,N,N,43204,N,44476,42049,N,N,51521,42053,42078,42077,N,N,N,N,N,N,N,N,N, +42468,N,N,N,N,N,N,N,N,N,43205,N,N,N,N,N,N,N,N,N,N,45230,54347,N,N,46787,56497, +56498,N,42054,N,42153,N,N,43206,42055,51528,42079,N,N,42154,42156,51537,42157, +42155,N,N,N,42469,N,43207,N,N,43208,43845,N,42080,42158,N,42470,42472,42471,N, +42731,N,N,43209,43210,43846,43847,N,N,N,N,44477,N,N,56499,N,N,63190,42056,N,N, +N,N,N,42160,42159,51538,42161,42167,N,42162,42163,51540,51539,42165,42166,N, +42164,N,N,N,N,N,N,42314,42315,42316,42317,42313,42320,51562,N,51558,51561, +42321,42337,N,51560,N,42318,42319,42312,N,N,51557,51559,N,N,N,N,N,N,42485, +51632,42482,42486,51642,51630,42483,51634,N,N,N,42484,N,42487,N,42473,51633, +42488,51637,N,51641,51638,N,N,51635,42474,42476,42489,N,42478,51627,42481, +42479,42480,51643,51640,51631,42477,N,N,51628,42475,N,N,N,51636,N,N,N,N,51639, +N,N,N,N,N,N,N,N,N,51629,51814,N,42818,42740,N,N,51815,42737,N,42820,N,42745,N, +42744,51803,42748,42743,51808,51816,N,51812,N,42746,N,N,42749,42734,42823, +51805,N,N,52157,42732,42819,42733,42741,42742,51810,51806,42747,42739,51802, +42735,51813,42821,42824,42738,42816,42822,42736,51811,42817,51817,51804,42750, +51807,N,N,51809,N,43224,52159,52171,43216,N,52172,43211,43221,N,N,43214,52153, +43222,52152,52156,52163,52161,43230,43225,52147,52149,43227,43215,52150,52162, +52169,43220,52155,52148,43219,52151,43223,52154,N,43218,N,43213,N,43228,52164, +43229,52168,N,52166,52170,43226,52158,52146,N,52160,43217,52165,43212,52167,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,43862,43850,N,N,52704,52712,N,43849,43857,43869,N, +52718,52716,52711,N,N,N,43851,52717,52707,43865,43856,43864,52702,N,52714,N, +52705,43860,52706,N,52701,43867,43854,43863,43853,N,52703,52708,N,52715,43861, +43858,52710,43866,52713,52709,43855,43868,43859,43852,43848,N,N,N,N,N,N,N,N,N, +N,52719,N,44503,44481,N,44497,N,44502,53456,53455,53460,53461,44484,N,44493,N, +N,N,44506,44494,N,N,N,N,53449,44487,53450,N,44508,N,44499,44478,44479,53469, +45247,N,44492,44491,53451,44495,54363,44486,53462,44501,44500,44490,53454, +53463,N,53448,44489,53464,44498,53452,44480,N,44483,44482,53465,44496,44485, +44505,44507,53459,44504,N,53467,53453,53468,N,53457,N,53466,N,53458,N,N,N,N, +44488,N,N,N,54371,54359,N,45235,N,54364,54370,45234,54357,45238,54361,54354, +45236,54358,45241,45246,N,54375,N,54353,N,45242,N,54374,N,N,45237,54360,45233, +54355,54351,54365,54352,54350,54362,54368,54369,45239,N,N,55387,54366,54349, +54367,N,45249,54372,45248,54348,N,54356,54373,45244,45243,45240,45245,N,N, +45231,N,N,45232,N,N,46024,N,55390,55383,N,46021,N,55391,N,N,N,55381,55384, +46020,55385,N,N,46023,55389,N,55379,55378,46025,N,46026,46022,46027,55377, +55388,55386,55380,N,N,N,46019,55382,N,N,N,N,N,N,N,N,46794,46788,56503,46797, +56509,56512,46790,46791,56506,46789,56515,46795,56516,N,56511,46796,N,56500, +46793,56501,N,56510,56508,N,56504,46792,56502,46798,56507,56514,56505,56513,N, +N,47542,47539,N,47540,N,57593,57585,47538,47535,57586,N,N,47537,57589,N,57591, +N,N,57598,N,N,57597,57592,47534,57584,47532,57587,47543,57590,N,57594,47536, +47533,57596,57595,47541,N,57588,N,48120,58604,N,58601,48121,N,48119,N,58608, +58605,58598,48118,N,48122,58599,48117,48125,58602,58603,48123,48124,58609, +58606,58607,N,N,N,48810,59640,48807,59637,48809,48811,N,59638,48808,N,59639,N, +59636,N,N,49270,60605,49271,60603,N,60604,60602,60601,N,N,60606,49269,N,N, +61368,61369,N,58600,61367,49272,50015,61931,61932,N,50391,50392,62913,62912, +50540,50539,63440,N,42057,42081,42169,N,42168,42323,42322,42492,42491,42493, +42490,N,42826,42825,42827,N,N,N,N,43232,N,43231,43233,N,43870,N,41561,53470, +41562,45250,41564,41563,55392,N,41565,47544,41566,N,42058,N,42170,42494,43234, +N,42059,42173,42171,42172,N,N,42560,N,N,N,42828,43236,43235,43237,N,N,N,44509, +N,N,N,48812,N,N,N,N,N,N,51534,N,42324,42325,N,N,42561,N,51818,N,43872,43871, +53472,53471,45251,N,42174,51541,N,N,N,N,N,52173,N,43873,N,44512,N,44510,44511, +N,N,N,N,48813,N,42326,N,N,N,42562,51644,N,N,N,N,42829,42830,N,51819,N,N,52174, +43238,52175,N,N,N,N,N,53474,53475,44515,N,53476,N,53473,44516,44514,44513, +53477,N,54376,N,N,N,55393,N,N,56517,57664,N,N,N,48126,48814,59641,N,42060, +42074,N,N,N,N,N,N,N,N,N,N,N,N,N,N,45252,46029,N,47545,N,51522,42175,N,42329, +42327,42328,N,N,43239,42061,42062,N,42082,N,N,42176,42177,42178,51646,42330,N, +51563,N,42566,N,51647,42564,42565,51645,N,N,42567,42563,N,N,N,N,51820,43756, +51821,N,N,51822,N,N,42832,42831,N,N,42835,42833,42834,N,N,N,43245,N,43244, +52180,52177,52178,N,52176,43246,43242,43241,N,43243,43240,N,N,N,N,N,43247,N, +43875,52720,N,52179,43880,N,52721,43876,43879,43878,43877,43874,N,N,N,53480,N, +44519,53483,44517,N,N,N,53479,44520,44518,44521,53481,53482,N,53478,53484,N,N, +N,N,N,N,46033,45253,54377,54379,54378,54380,45254,N,N,46030,N,46031,46032,N, +46800,56519,N,56518,56520,56521,46801,N,46799,57665,57666,47547,47546,58202,N, +N,48192,48193,48194,48196,58610,58611,48195,N,N,N,48815,N,48816,N,N,61933, +62915,62914,63441,N,42063,N,N,N,42332,42331,N,N,42568,N,N,51648,N,N,42837, +42838,42836,42839,51823,51824,N,N,N,N,N,N,N,N,N,N,N,N,43249,52181,N,43248,N, +52722,43884,52723,43883,N,N,N,43881,N,43882,N,N,N,53485,N,N,N,N,45255,54382,N, +45258,54381,45541,45257,45256,N,46036,N,46035,46034,46802,N,N,46805,46806, +46804,N,46803,N,N,57667,N,57668,N,N,N,58613,48197,58612,N,48817,60607,49273,N, +61934,50261,N,42083,42179,51542,N,42180,42181,42333,42334,N,42569,51825,52182, +52183,N,43885,53486,45260,45259,55395,55394,N,N,42064,42182,42335,N,45261, +51523,N,51564,42336,N,51650,42571,42570,51649,42840,N,N,N,N,N,N,44522,N,N, +54383,N,46807,57669,47548,N,N,59642,N,N,62461,N,42183,N,N,52184,52724,45264, +45262,45263,42065,N,42084,41677,42186,N,42185,42184,42339,42338,N,51565,51651, +N,N,N,43253,43250,43252,43251,N,N,43886,N,N,46037,N,42066,N,42187,N,42341, +42340,N,51826,N,N,43254,N,N,N,N,N,51543,N,42343,42342,42572,42573,51827,42841, +N,42842,N,43255,43256,43257,N,43887,52725,N,N,44523,N,N,51524,N,42188,N,N,N,N, +N,51652,N,N,N,51828,51829,N,N,52185,N,52186,N,52727,52726,52729,52728,43888,N, +54384,44525,53487,44524,N,N,N,N,55396,46038,N,55397,N,N,N,N,57670,47549,N,N,N, +N,48198,N,61935,N,N,N,N,51544,N,42344,N,N,N,N,N,N,N,45265,N,N,N,N,42067,42085, +42190,42189,N,42191,N,N,N,N,N,N,43259,N,43258,43260,N,N,N,43889,N,N,N,44526,N, +59643,49743,42086,42346,42361,42356,N,42351,42350,42357,42355,42348,42362, +42349,42345,42360,42359,42358,42347,N,42354,N,N,42353,N,N,42363,42352,42579,N, +42585,42581,N,42587,51653,42584,42574,42577,42580,42576,42583,42586,42575, +42578,42582,42588,N,N,N,N,N,51838,51835,N,42855,51836,42843,42845,42869,42864, +N,N,N,51877,51837,42847,42849,51876,42856,51832,42868,42870,42844,42861,N, +51830,42867,N,42852,N,42862,42863,51831,42860,42858,N,42859,42865,51873,42846, +N,42866,51875,42854,42851,N,51834,42850,51878,42853,N,42857,N,N,N,42848,51874, +N,N,N,N,51833,N,N,N,N,N,N,N,N,N,N,N,52203,52202,43343,52205,52207,52196,52199, +52206,43344,N,N,52193,52197,N,N,52201,52809,43339,52813,43261,52198,43262, +43340,43333,43329,N,52194,43332,43337,43346,52195,52188,43331,52189,52191,N, +43334,N,43336,52187,52192,N,N,43345,43341,52200,43347,N,43338,52190,43335,N,N, +43330,43328,N,52204,N,43342,N,N,N,N,N,52808,52731,52811,N,N,52733,43896,43944, +43892,43943,43901,43940,43890,52732,52803,43939,52815,43941,N,43897,N,N,52805, +52802,43895,N,52730,43942,52810,43900,52812,43945,43891,43902,43899,52800, +43937,52806,52807,43898,43938,43894,N,N,N,N,43893,52734,N,N,N,N,N,N,52804,N,N, +N,N,N,N,N,52814,N,53572,44539,53489,N,53494,44532,44608,53492,44527,44537, +44542,53499,N,44538,44541,N,N,53502,44533,53493,N,N,N,53570,53571,N,44535, +53569,44531,44611,N,53496,44529,N,53574,53497,53501,44534,44610,53498,44540, +53568,53575,54433,N,53573,44612,44528,53500,53491,N,44536,N,N,53490,N,N,53495, +N,N,N,N,N,N,N,N,N,N,N,53488,44609,N,N,54391,N,45284,54439,45282,45279,54396, +45275,54434,45286,54390,54395,54394,44530,45281,54437,N,54440,54387,N,46056,N, +54441,45287,N,45273,45270,54398,45267,N,54438,N,45274,54442,N,54388,54436, +45277,54389,54392,54397,N,N,45278,45276,45288,N,N,N,N,45283,N,45271,45522,N, +45272,54393,45285,45280,54435,45269,N,N,N,45268,N,N,N,N,N,N,N,N,N,N,54385, +54386,55402,N,N,N,46039,46042,55413,46062,55416,46040,55409,46046,46052,46525, +N,N,46050,55406,46063,46043,46051,55414,56535,55419,55407,N,55398,55411,55405, +46049,55417,N,N,46045,46065,46058,N,46047,46044,N,46055,N,55418,55404,55410, +55412,55400,55415,46041,55399,N,46048,46064,46060,55401,46054,N,N,46061,46057, +46053,N,55408,N,N,N,N,N,46059,N,N,N,56533,56529,N,56544,56522,56531,46821, +46822,46814,56540,46824,56527,56526,56524,56542,46812,56536,56525,46815,56534, +46810,56530,56537,56539,N,N,56543,46819,56523,46813,56528,N,46808,N,46820, +56538,46816,46817,46823,46811,41567,46809,56532,N,N,N,N,N,46818,N,N,56541,N,N, +N,47565,47560,N,57685,57681,N,57675,47554,47550,57684,47551,57678,57680,N, +57683,N,47556,N,47563,47557,N,N,57673,47558,47559,57676,47564,N,57674,57679, +47555,57672,47561,47553,N,N,N,47552,57677,57682,N,47562,N,N,N,N,N,N,N,57671,N, +48205,58695,N,58692,N,48199,48211,48212,N,48202,58690,48204,58617,48210,N, +58694,48201,58696,48200,N,58691,58693,48203,58689,58618,58615,N,N,55403,58621, +N,58614,58620,58619,N,58616,N,48207,N,N,N,N,48206,N,N,N,48208,58622,48818, +58688,N,N,N,59717,N,59645,N,48830,59714,48822,48826,59713,N,48825,48821,48824, +48819,48829,59715,59646,48828,59644,48827,59716,59712,48209,N,48831,59718, +48823,48820,N,N,N,N,60614,60616,49275,60617,60615,60613,60612,49277,60611, +49278,N,N,N,N,60609,60610,49274,49313,49276,N,N,60608,N,49744,N,61372,61370, +61375,61373,N,61371,61374,N,N,N,N,N,N,N,50016,61938,61939,50262,N,61940,61936, +61941,61937,49745,N,N,N,62462,62529,50265,62528,50264,50263,N,N,N,N,50266, +62917,62918,N,50394,50393,50395,62916,N,63192,63191,N,50541,50543,50542,63193, +50632,63654,N,N,N,50673,N,63653,63726,N,N,51529,N,N,42365,42364,N,42591,42590, +51655,42589,51654,N,N,42873,51881,N,51880,N,N,42871,42874,N,N,51879,N,42872,N, +N,N,N,N,N,52208,N,52209,43348,N,N,N,N,43946,53576,53577,44613,44614,N,N,54444, +45289,45291,54443,45290,55420,46066,N,N,N,N,46825,46826,56545,N,47567,N,47566, +N,58697,59720,59719,N,63851,42087,51545,N,51566,51567,N,N,N,N,42594,42598, +51657,N,42596,42595,51656,42597,42593,N,N,42592,51658,N,N,N,N,N,N,42918,N,N, +42915,N,42877,51882,N,N,N,51883,N,42913,N,51885,42875,51886,51884,42878,42914, +42917,42916,42876,51887,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43353,52222,N,43355,N, +43354,N,52288,43352,43351,52213,N,52212,N,52210,52215,52214,52211,52220,52221, +52218,52216,43350,N,N,N,52219,43356,52289,N,N,52217,N,43947,43349,N,N,N,N,N,N, +N,43948,52820,N,N,52826,N,N,N,43954,52824,52830,N,52821,52825,52827,52829, +52823,N,52822,52817,52818,43949,N,43951,43950,52819,52828,N,N,N,N,N,N,N,N, +43953,N,N,N,N,N,N,52816,53587,N,53586,53591,53582,N,53585,53584,N,53588,N, +53592,44615,44618,N,N,53583,53589,N,N,N,44617,53578,N,43952,54458,53590,N, +53581,N,44616,53580,N,N,N,N,N,N,54449,N,N,45292,45296,54465,54447,54461,45297, +54463,N,54469,N,54473,N,N,54464,54452,54460,N,54474,54472,54462,54457,54450, +55462,54448,45301,54455,45302,45298,54445,54467,54453,54451,54470,45299,N, +54476,45293,45295,54459,54454,44619,45294,54456,54471,54475,54466,N,54468,N,N, +N,54446,N,N,N,N,55457,N,55466,55465,46074,55458,N,46075,46073,N,55460,46070, +55464,N,55459,55461,55421,46068,N,55474,55473,55470,46067,46071,46072,53579, +55467,46069,45300,55469,55422,55472,55471,N,55475,N,56559,N,55468,N,N,N,N,N,N, +N,N,55463,56551,46836,46839,46834,56550,56554,56549,N,46828,46838,56546,46832, +56553,N,46830,46829,56556,46831,56558,N,56555,46827,N,N,N,46837,56560,56548, +56557,N,N,56547,N,N,46833,N,46835,N,56552,N,56561,N,N,57693,47568,57699,N,N, +47573,57695,57702,57687,47575,47569,57692,48213,57691,57700,47570,N,47574, +57690,57696,57701,57686,47572,57694,N,N,57698,57704,57688,57697,N,47571,57703, +N,N,N,57689,N,N,N,48217,58699,48215,48214,58701,58706,N,58702,N,58705,48220,N, +48805,48219,N,58698,58704,N,48218,58703,N,58700,N,48216,N,N,N,N,N,N,59725,N, +59727,59722,48833,59724,N,48832,59726,N,N,48835,59728,48834,59721,59723,N,N,N, +N,49317,60620,N,49316,60621,49315,60619,49314,60618,N,49747,49746,61942,61944, +N,61943,50017,50018,N,N,50019,62530,50267,N,N,63443,63442,50674,N,42088,42192, +N,N,42919,N,N,N,N,52831,N,N,N,N,46076,46077,N,56562,47576,57705,58707,51546,N, +N,51888,N,N,N,N,N,52290,52832,53593,44620,N,N,61945,N,50396,42089,42366,51568, +N,42599,42600,N,43357,N,N,N,45303,N,47578,N,47579,47577,N,42090,N,42193,42195, +42194,51547,42196,42401,51569,N,42402,N,N,N,N,N,42601,42602,N,N,N,51659,N, +42920,N,51889,N,N,N,43361,52291,N,43359,43360,43358,53594,N,N,N,43958,43957, +43959,43956,N,52833,43362,43955,N,44621,44622,N,44623,N,54477,N,N,N,46078, +55476,45304,N,N,N,N,46840,N,47581,47580,57706,N,48221,48836,N,61376,63194, +63444,42091,42403,N,42404,51665,42604,42607,N,51663,51661,42606,51664,51666, +51660,42609,42608,42605,42603,51662,N,N,N,N,42931,N,N,42928,51894,51897,51896, +N,42922,42930,N,N,42927,51893,51891,42926,N,N,N,42921,42924,N,51892,51899, +51895,42925,42929,42932,51890,51898,42923,N,N,N,N,N,43367,43375,N,52303,52296, +43376,52307,52292,52299,N,N,43366,52293,43364,52300,52304,43363,N,52305,52298, +N,52301,N,43378,43369,52308,52306,N,43374,43372,52297,43371,52295,52294,43370, +43368,43377,43373,43365,N,52302,N,43961,N,43968,52847,43960,52839,52835,N, +52851,52834,N,43963,52844,43966,43969,N,43964,52848,43967,N,44630,52854,52836, +N,N,52838,52845,52849,52853,52850,52843,52846,N,N,52840,43971,52842,52841, +52852,43962,52837,43970,N,43965,N,N,N,N,N,44636,53602,N,44635,N,N,53600,N, +44624,N,44629,N,53599,53596,53601,44625,53595,N,44628,44626,N,53603,44627, +44631,N,N,44632,N,44634,N,N,N,44633,N,N,N,53597,53598,N,N,N,N,53604,N,54484, +45305,55490,54483,54502,N,N,45376,N,54500,N,45310,45306,54509,54493,54496,N, +45379,54506,54498,45307,45380,N,54503,54501,N,N,54486,54507,54495,54490,N, +54480,54508,54492,54479,N,45378,54497,54510,54494,54482,54487,54478,N,45377,N, +54491,54488,45308,54481,N,54505,45309,N,54489,54485,N,N,54504,N,N,N,N,N,N, +46144,55483,N,55480,55497,55485,55498,N,46146,N,N,N,55494,55491,N,N,N,N,N, +55492,55495,55499,N,54499,55501,56647,N,46147,55502,55478,55488,N,55493,N,N, +46145,46148,55500,55503,55482,55479,N,N,55481,N,N,55486,55484,46149,N,55496,N, +N,55487,N,55489,55477,56570,56568,46914,46912,56643,56569,56644,56640,56567, +56646,56566,56573,46846,46845,46844,56571,56641,46841,46913,N,56564,N,56574, +56563,56572,46842,56642,56565,46843,56645,N,N,N,N,N,N,N,57710,47586,47585, +47587,57722,57712,57718,57707,57721,57720,57724,57717,47582,57716,47588,N, +57709,47583,N,57723,47584,57711,57714,57719,57713,57708,N,N,N,N,57715,58709, +48225,58712,58711,58714,58716,N,48223,N,58710,N,58708,58717,58715,58713,N, +58719,N,58718,48227,48222,N,48224,48226,N,N,58720,59735,N,N,59734,59733,N, +59736,59729,N,59730,59738,59731,N,48837,59740,N,59739,59732,N,60625,49320, +60623,60628,60627,59737,N,49319,N,60626,60622,60630,60629,49318,N,60624,N, +48838,N,N,N,49748,N,N,N,61377,61946,61947,61948,50268,N,N,50269,N,62531,N, +62920,62919,N,N,63195,63196,63445,63655,N,42092,42093,N,42094,42197,42405, +51667,42610,42611,N,42935,42936,42934,42933,N,43379,N,N,52309,43381,43380, +52310,N,N,N,43972,N,44637,53605,N,54512,N,45381,46151,54511,46150,N,47589,N, +57725,48839,N,49321,60631,N,50270,N,50544,N,51570,N,42406,51571,42614,N,42612, +42613,42615,N,42938,42937,N,51900,42939,N,N,51901,52311,N,52312,N,43382,43384, +43386,43383,43387,43385,N,N,N,N,N,43976,43973,43975,43977,43974,53606,52855,N, +N,N,53608,53607,44643,N,44639,N,N,44640,44642,44644,44641,N,44646,44645,N,N,N, +N,N,45386,54514,54513,45385,N,45384,45383,45387,45382,N,N,55509,55506,46153, +55505,55510,N,46155,55508,46152,46154,55507,N,56648,N,56649,56650,N,N,N,N, +47590,47598,57726,47592,47596,57761,47597,47593,47594,47591,47595,48230,55504, +48231,48229,N,48228,59741,48840,60632,60633,N,N,50020,50271,N,42095,N,42616, +43978,N,53609,44647,N,N,45390,45389,45388,46156,46157,55511,47599,48841,42096, +51548,42198,51572,N,N,51668,42617,N,N,N,43388,N,N,N,N,56651,N,N,42097,N,42199, +51669,N,N,51902,N,51903,N,42940,N,N,N,55512,46158,N,56652,N,N,N,49322,42098, +42152,42200,51573,42407,N,42944,42943,42941,42942,N,N,52313,43390,43425,52314, +43389,N,N,43982,52856,43981,43979,43980,44650,44648,N,N,53611,44649,53610,N, +44638,54515,N,N,45392,45393,N,N,45391,N,47600,57762,48232,48233,N,58721,49323, +61378,61379,N,50397,63656,51531,42201,N,42099,N,51575,51574,N,N,N,N,42618, +51671,51672,51670,N,51673,N,N,N,N,N,N,N,51911,N,51906,51908,51910,51907,42948, +51904,N,51905,42945,42946,51909,51912,42947,51913,N,N,N,N,N,N,N,52328,N,52322, +52317,43427,52325,52323,52316,52329,52332,52327,52320,43429,52326,43430,52321, +52324,52315,52319,52331,43431,N,43432,N,52318,52330,43426,43428,N,N,N,N,N,N,N, +N,N,N,N,N,N,52907,52900,52906,52899,52901,52861,52859,N,52908,52905,52857,N, +43984,52903,52904,N,52902,52860,52858,43983,52898,52862,N,N,52897,52909,N,N,N, +N,N,N,N,N,44655,N,44654,N,53612,44651,53614,N,44656,53615,N,N,44659,N,44657, +53616,52910,53618,N,44653,N,44652,N,53613,53617,44658,N,N,N,N,45395,45394,N,N, +N,54517,54521,54523,45396,54526,N,45400,54593,N,45402,N,45398,45406,N,45403, +54519,45397,N,54518,54516,54595,54520,N,45399,54594,45404,54525,54524,45405, +54522,45401,N,N,N,N,54596,N,54592,55527,55534,55523,46161,55519,55535,55513, +55532,55530,55524,N,55533,55526,N,55518,55536,55516,55529,55514,N,55537,N, +46162,N,55531,56655,55517,46159,N,55521,N,46160,55520,55525,N,N,55522,N,N,N, +55528,N,N,N,N,56659,N,N,N,56662,56654,N,56656,N,56661,56660,46915,N,55515, +56658,N,N,46916,N,56653,56657,N,N,N,N,57769,N,57776,57767,N,57774,57765,57773, +57777,57764,57768,57763,N,47601,N,57766,47602,57772,57771,57770,N,N,57775,N,N, +N,N,58725,58727,48235,58728,N,58723,N,58722,58732,N,58730,48234,58733,58724, +58729,58731,58726,N,N,N,N,59745,59750,59744,59749,N,59742,59752,59748,59753, +59747,59743,59751,N,59754,59746,N,60634,49327,N,49325,N,49324,49326,N,N,61380, +N,61810,61949,N,N,62532,62533,N,50272,N,62921,N,50398,N,62922,N,63198,50546,N, +50545,63197,50633,N,63446,N,N,N,N,42100,42619,51674,51914,43189,45407,N,N, +42101,42410,42409,42408,N,N,42949,N,N,44660,N,56663,42102,42103,42104,42202,N, +N,43985,N,52911,N,N,N,46163,42105,51549,42411,42412,51576,N,42620,N,N,N,51915, +N,42950,N,51916,N,N,43438,N,N,52334,43436,43435,52333,43433,52335,43434,43437, +N,43986,N,43988,52915,52912,52913,52914,52916,43987,N,N,53620,53619,N,44662,N, +44661,N,N,N,N,N,45410,54598,N,45409,45411,45408,N,N,N,N,46165,54597,N,46166, +55539,N,46167,55538,46164,N,N,N,N,56666,56668,46917,56667,56665,56664,N,N,N, +57780,47607,47605,N,47606,57778,57779,N,47603,58737,58735,N,48237,58736,48238, +48236,47604,N,N,59757,59755,59756,58734,60636,49328,60635,61381,61382,59758, +61950,N,42106,42413,42622,51675,42621,N,43439,46918,N,42203,42414,43989,46168, +N,51577,N,51578,N,51676,N,N,42952,51920,51918,42953,51917,51919,51921,N,42951, +N,N,N,N,N,43443,43444,43441,N,N,43440,52920,43442,N,N,N,43990,N,52919,52921, +52918,52922,43991,44665,53621,N,53623,44663,53624,44664,53622,N,52917,54599, +54602,54603,54600,45415,45414,45412,45413,54601,N,N,N,N,45416,N,N,46170,46171, +N,46172,56669,56671,56673,46920,46919,46169,56672,56670,N,57784,N,N,57782, +57788,47608,57789,57786,47609,57783,57781,57787,48240,58739,57785,48242,58740, +48241,48244,58741,48239,48243,N,59763,59761,59760,59762,59759,N,N,50022,N, +62534,62535,N,62923,63199,50773,N,N,43445,42954,N,N,43992,N,N,N,42107,42204, +42415,51677,N,42955,51922,N,52923,43993,N,47610,42108,N,N,N,42657,N,N,46921, +42109,42205,42206,N,42417,42416,N,51678,42658,N,51923,N,42956,N,N,52337,52338, +52339,N,43446,43447,52336,43448,N,N,N,43994,52924,N,53626,44666,N,53625,N, +45417,54604,45418,54605,N,N,N,46173,N,N,N,56674,N,N,57791,57790,N,47611,N, +48245,58742,48842,59764,49329,N,50547,63448,N,N,N,N,52340,N,52925,45419,55540, +46922,N,N,N,49749,N,N,N,N,42958,N,42957,43995,N,53627,N,45421,45891,45422, +45420,46174,N,57792,47612,48246,N,51532,51679,N,51925,42959,51924,42960,N,N, +43452,52343,52342,43451,43449,43450,52341,N,N,43997,52926,44000,43996,44002, +43998,43999,44001,N,N,N,44669,44668,44667,N,N,N,54607,45423,45426,45424,N, +54606,45429,N,45425,54608,45428,45427,N,N,N,55542,55541,N,46177,46175,46176, +55543,46923,56676,46924,56675,N,N,58743,N,N,48248,57793,48247,N,47613,N,60638, +59765,49330,60637,62016,62536,62537,N,42207,N,42418,N,N,N,51579,N,N,42962, +42964,N,51682,51928,51927,51926,N,51681,51680,42660,42963,42961,42659,N,N,N, +43453,52344,N,43454,51933,N,51935,51934,52345,N,N,51930,N,42968,42966,N,51929, +51931,51937,N,42965,N,51932,51941,43456,N,51938,42967,N,51936,51939,N,43455,N, +43457,51940,N,N,N,N,N,N,N,N,52399,52386,52350,52398,52393,44007,43458,52394, +52397,44003,52396,43459,43464,43462,52387,N,52348,52389,43469,52400,44004, +52390,N,44005,43465,52392,N,52941,44006,52347,43466,44008,43467,43463,43468, +52391,52346,52395,43460,N,N,52349,52388,52385,43461,N,52927,N,52928,N,N,N,N,N, +N,52938,53665,52939,44014,52942,52932,44013,52934,N,52935,N,N,52937,44009,N,N, +44707,N,N,52933,52929,44708,N,N,52943,44670,53629,52936,N,53628,52931,52940,N, +N,44012,44705,44018,44706,52944,53630,44011,44710,44017,44016,44015,44709, +52945,44711,44010,N,52930,N,N,N,N,N,N,N,N,N,N,N,N,45430,53668,53670,N,53672, +44712,44718,54611,53676,53667,45432,54609,N,44717,44715,53678,N,54610,N,53669, +N,44716,53673,44719,53675,N,N,44714,53674,53677,53671,N,44713,45433,N,53666, +45431,N,N,N,N,45434,N,N,N,N,N,N,N,54613,54622,46180,N,45436,45475,46181,54624, +45482,55545,54614,45474,45477,45438,54612,54626,54629,55625,N,54627,55549, +45473,45480,45484,54621,55544,54625,45435,55546,54628,55548,54617,N,46178,N, +54615,54616,45479,N,N,45478,54619,45483,54623,45476,54620,N,45481,46182,46179, +55547,N,54618,N,45437,N,N,N,N,N,N,N,N,N,46187,46191,55616,46929,46189,55620, +46193,56677,55622,46931,46185,46188,55623,N,55624,55630,46195,46932,N,55626, +55631,55619,46942,N,46933,46194,55617,55632,N,46941,46192,46926,55629,N,46196, +55621,55550,46186,55618,N,55627,N,46925,46930,46183,55628,N,46928,N,N,N,46184, +N,N,N,46940,57795,56688,N,56680,57794,N,56684,56686,N,N,56683,N,46939,N,56682, +46943,N,N,N,57810,N,N,46938,47680,56689,57796,N,N,46936,56681,56685,47614, +46927,56678,56679,47681,46935,46937,46934,56687,N,N,57800,57801,57806,48253, +57813,N,47687,N,47686,57808,N,48252,57797,47685,N,57812,47683,47684,N,57809, +58794,48250,46190,N,57811,48291,57803,N,48251,N,48290,57798,57802,57799,57805, +47688,48249,47682,N,58746,57807,N,48289,N,48292,N,57804,N,48254,58745,N,N,N,N, +N,58750,48846,58744,59811,58793,48296,N,48294,48844,58790,58786,48300,N,59768, +N,N,N,48298,58785,N,59766,N,58789,N,58792,58749,N,48299,N,N,48293,59767,48845, +58791,48295,48297,58788,48301,58787,58748,58747,48843,58795,59770,60640,48848, +N,59810,N,59774,N,60641,N,48849,59809,N,59772,49332,60639,N,59769,59771,49333, +48851,49331,48850,49335,59773,48847,N,N,N,N,N,N,N,N,61391,N,61383,N,N,N,N,N, +60647,61384,60643,N,N,49750,60645,60644,49334,60642,60646,61392,61388,61390,N, +61385,61386,N,61389,61387,50023,N,N,50026,50025,50024,50273,62538,50274,62017, +50399,62924,50400,50548,50634,63449,N,63450,63451,N,N,63930,42208,51580,42419, +N,42662,42663,42661,N,42664,42970,42969,N,52401,43471,43470,N,N,53679,45485, +45486,N,N,N,46197,56690,46944,46945,56692,56694,56693,N,57815,N,57814,47689, +57816,N,58796,48302,N,48852,N,49336,49751,49337,N,42209,N,N,N,51942,N,N,52402, +43473,43472,43474,44019,52946,52947,N,N,53680,44720,45487,46198,55633,42210,N, +42110,42211,N,51581,42423,42422,42420,42421,N,N,N,42667,51689,51691,42666, +51683,N,51684,N,51690,51686,51688,42665,51685,51692,51687,N,N,N,N,N,N,42977, +42986,42984,51952,51949,51957,42982,51958,N,42975,51955,N,42981,51951,51950, +42979,51956,42980,43475,42974,51953,N,51943,42971,N,42990,51948,51954,42976, +42978,N,51944,N,51945,51946,N,42989,42983,42988,51947,42987,42973,42972,42985, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43489,52414,52407,43484,43503,52403,52410,52412, +52415,43498,N,52411,52404,43496,52408,N,52416,43481,N,52413,43491,43490,52406, +43479,N,N,43480,N,43478,N,43502,43494,43488,43476,52409,43487,43477,43495, +43504,52948,43492,52405,43482,43485,43486,N,43500,43501,43499,43493,43497, +43483,44020,N,N,N,N,N,N,N,N,N,N,N,N,N,N,52954,44097,44024,44026,44096,52966, +44029,53681,44721,44099,52951,52959,44030,52958,52955,52963,52965,44023,44027, +44098,44723,52960,44025,44101,52953,N,N,N,44028,44722,44022,N,52950,52957, +52949,52952,52956,53682,44100,N,52961,52962,52964,44021,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,44737,53694,44735,44736,53684,53700,N,44726,N,N,54630,53702,53696, +N,53687,N,53705,53690,44732,54653,53693,44734,44725,N,53707,53695,44728,53688, +53685,53686,44729,53701,53708,44731,53692,53691,44739,44738,44724,44730,44733, +53704,N,N,53698,44727,53683,53706,53697,53699,53703,N,N,N,N,N,N,N,N,N,N,54631, +N,45495,45515,45514,N,45503,N,54649,54645,54642,54694,45498,45490,N,N,54647, +46248,45494,54689,N,45516,45513,54651,54634,N,N,45512,54691,54633,45501,45505, +54690,N,54643,45506,45500,54632,N,46200,54693,54641,45511,54644,54692,45510,N, +55634,N,45491,54639,45496,45507,N,45502,54648,54638,54636,54654,45488,45508, +45492,46199,54652,45493,N,45489,45504,45499,45497,54640,45509,54637,54650, +54646,55636,55635,N,N,N,N,N,N,N,N,N,N,N,54635,55652,N,46202,N,55658,55641, +55655,56695,46205,55659,55662,46204,55644,55661,55660,46206,55637,46201,46243, +N,46241,55657,N,55647,46245,55664,55656,55665,46253,46251,55654,55653,N,55651, +55645,46244,N,46242,53689,55638,N,56759,55639,46203,46250,56697,N,46246,46247, +55640,55663,56696,55648,55643,46249,55649,55646,N,N,46254,46960,N,N,56700, +56753,56758,56746,46956,56763,46953,56698,N,56699,46946,46955,56740,46958, +46959,56741,N,56754,56760,46954,N,46948,56739,56701,56762,56744,56745,56702, +56756,56747,56757,56749,N,46949,57817,46952,46950,56761,56752,56748,N,N,56737, +47699,56751,46957,56743,N,56742,N,N,N,46951,46947,57838,56755,56750,N,56738,N, +N,N,N,N,N,N,57833,N,57818,57829,N,57836,47697,46252,57834,47692,N,N,N,47691, +57841,N,57819,57832,57820,57831,47695,57835,55650,N,N,N,57842,57827,47698, +58810,48303,N,57840,57839,47700,58797,48304,58798,N,57823,57824,57821,57826, +57822,57843,47694,48305,47696,47701,N,57825,N,57837,N,N,57830,N,N,58801,N, +47690,48308,59818,58806,58805,58807,N,N,58804,48309,N,48315,48312,N,48313, +58799,58802,58812,48321,48319,N,58803,55642,48306,58809,58800,N,48322,58808, +47693,48311,57828,N,N,48314,N,48318,48320,48317,48316,N,48310,58811,48307, +48323,N,N,N,N,N,N,N,48856,48857,59817,48866,48863,N,48854,48861,59819,48859, +48853,N,48860,N,59816,49339,48855,N,48862,49338,59815,59814,N,48864,N,48865,N, +59813,59812,49340,59822,48858,59820,N,N,N,N,49341,N,49346,60650,60652,N,49343, +N,60653,60649,N,60651,49344,49347,N,60648,49342,49345,49753,59821,49752,N,N, +49758,61396,N,49756,49757,61399,61395,49754,61393,50027,61397,N,61398,61394,N, +49755,62018,N,62021,N,N,62022,62020,62023,50028,62019,N,N,62542,50276,62541, +62540,62539,50275,50277,N,62925,50402,50401,N,N,63201,63200,63203,50635,50549, +63453,63202,N,N,63452,50637,50636,50675,63657,63727,42212,N,N,55666,59823,N,N, +42668,51959,42993,42991,N,42992,N,52417,43505,44102,N,52967,N,52968,N,44103, +53710,N,44740,44741,53709,N,N,N,N,45523,N,45519,N,54695,45526,45525,45518, +45521,45524,45520,N,N,55670,45517,46255,N,N,N,46257,46258,55669,55672,46256, +55667,55671,N,55668,N,46961,N,N,56764,N,N,47702,57844,48867,48324,58813,48325, +48326,58815,58814,58816,59825,N,N,59824,60655,60654,49348,49349,62024,N,N, +42213,N,N,N,N,55673,N,N,N,46260,46259,56765,N,61400,50403,63454,42214,N,44742, +N,45528,45527,55674,55675,46962,57845,47703,59826,N,42215,42424,N,43506,52418, +N,52969,44104,45529,N,55676,46261,46963,N,58817,58818,N,N,60656,49759,63728, +42216,N,52419,43507,44105,N,52970,N,44743,53714,53712,53713,44744,53711,N,N,N, +N,45531,45532,54696,45533,45530,55677,N,55678,56766,N,N,47705,47704,N,N,60657, +61401,N,62026,62025,62543,N,51550,44106,N,N,42217,42425,N,42670,42669,N,N, +42671,42672,51694,51693,51960,42994,51963,51962,51961,51964,N,N,N,N,43508, +52425,52421,52430,43515,N,43513,52426,52422,52429,43512,43584,52424,52420, +43518,52427,43511,52428,43514,43516,52432,52431,52423,43510,43509,43517,N,N,N, +N,N,N,52975,52981,N,44112,44109,52972,52977,N,44115,44107,52976,44110,44113,N, +N,52979,N,44108,52984,44111,N,44114,52973,52978,52982,52974,52971,N,N,52983, +52980,N,N,N,N,N,N,44752,44745,44748,N,44751,N,53717,N,44746,53715,N,44750,N,N, +44747,N,53718,44749,N,N,N,N,N,N,54700,45535,54699,54701,45534,45539,53716,N, +54698,54702,N,45536,54697,45538,N,45537,N,55719,N,55714,N,46262,46266,46263, +55717,55720,N,46264,N,46265,46270,56775,55718,46268,55715,55713,N,46269,N, +55716,N,N,N,46969,N,56767,46966,46967,46965,56772,56771,56768,46971,N,N,56770, +46267,N,N,56774,56769,46968,46964,46970,56773,N,N,N,47708,N,57848,57847,57846, +47706,N,N,N,N,N,47707,58821,58824,48328,N,N,48327,58825,58820,48330,58822,N, +48329,58819,N,58823,48873,48870,59835,59834,N,59833,59828,N,59829,N,N,N,48871, +N,48868,48872,59827,48869,59830,59831,59836,N,N,59832,N,N,60658,N,N,N,49351,N, +61404,49350,61402,61403,49760,50030,62027,N,50029,N,N,62545,62546,N,50278,N, +62544,50404,N,63455,50638,63658,63659,N,42218,N,42673,42674,42995,N,52433, +44116,44753,45540,N,N,45266,N,46271,46272,46028,55721,N,46972,57850,57849,N,N, +42219,42675,52434,43586,N,43585,N,52985,52986,N,53719,53720,44754,44755,N, +44756,54703,N,N,45542,N,46274,N,46273,56776,57210,57851,59837,N,N,49761,50279, +42220,N,42428,42429,42427,42430,42426,N,N,42678,N,51702,42677,42679,N,N,51697, +51696,51699,51698,51701,42676,51695,51700,N,N,N,N,N,51965,43005,51966,52035, +43004,N,52039,52034,52037,42997,42998,42999,43000,N,43072,N,52033,43002,43073, +N,52032,52038,N,43001,52036,43003,42996,43006,N,N,N,N,N,N,N,N,N,43607,N,52436, +43587,N,43597,43598,43590,43608,43592,52444,43603,52439,43593,52454,52455, +52447,52440,43606,52452,43601,43599,N,52453,N,52451,52443,52435,52442,43594,N, +43600,N,43588,52446,52445,52437,N,43602,52449,52438,43605,52456,43589,N,43596, +52441,52450,43604,N,43591,43595,N,52448,N,N,N,N,N,N,N,N,N,N,N,N,N,N,53083, +44124,44137,N,53078,53068,44130,53066,44123,53061,44133,53074,52990,53057,N,N, +N,N,53060,52987,53073,53089,44128,53062,53080,N,52989,53087,53088,53091,53082, +53067,53075,44134,44121,44129,44141,44118,44120,N,N,N,53059,44138,44131,53085, +53056,44140,44135,53065,N,N,44139,53072,53064,44132,53084,53076,N,44126,53090, +53063,44122,53081,53071,44127,53077,44119,52988,44136,44771,44125,53070,53069, +53058,N,53086,N,53079,N,N,44117,53740,44778,53741,N,53729,44767,44779,N,53722, +N,53731,53739,N,53721,53748,44757,N,N,N,53747,53742,N,53743,44765,44776,53733, +N,53734,53744,53735,N,53730,53724,53725,53738,53732,N,N,44758,44762,53746, +53726,44774,44770,N,N,44773,44780,44763,44775,53737,44777,44760,N,44759,53723, +N,53727,44768,53745,53736,53728,44772,44769,N,44761,44764,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,54724,N,54708,54709,54713,N,54728,54725,N,54718,54717, +45549,54721,54736,54704,N,54737,54723,54741,54729,45548,54727,45543,45564, +45554,N,45558,45557,54705,N,54734,54740,54732,54739,N,N,54720,54706,54738, +54722,45546,45559,N,54731,45552,N,N,N,54730,54707,45560,N,45562,54733,45563, +45545,54714,54735,N,N,45551,45561,54716,54726,54711,54715,45556,54710,45544, +45553,45550,54719,44766,55744,45547,N,N,N,N,N,N,N,N,N,N,N,N,N,N,45555,N,55747, +55769,55758,46294,N,46289,55741,46290,55757,N,55750,55763,46286,55723,55765, +46276,55731,46279,46278,N,46295,N,55725,55759,55760,46281,46277,55739,N,46288, +55734,N,55761,46284,55753,55766,55728,55733,55727,N,46283,55746,56798,55729, +46287,55738,55762,46282,55735,55732,55749,46285,46275,46297,55752,55751,55724, +46280,55764,55740,55742,N,55755,55754,55722,46291,46293,55730,55737,55745, +46292,55736,55748,55767,N,55756,N,N,N,N,N,N,N,N,N,N,N,N,N,55768,N,N,N,N,55726, +N,N,N,N,56818,47014,N,56816,56795,56800,56793,N,56812,56779,56786,N,56810, +56820,56796,N,56783,56802,56807,56787,N,56804,56784,N,N,56791,56792,47016, +56811,56809,N,56780,56814,N,56815,56817,47020,47012,N,54712,56788,56806,56789, +47009,47025,56813,47023,47019,56778,47011,N,56781,47024,N,56797,56777,N,47017, +56801,56785,47018,56794,46974,46296,56803,55743,56782,N,N,56808,47013,56805, +47010,56799,47021,56790,56819,N,N,N,N,N,N,47015,57030,N,N,47022,N,N,N,N,N,N, +57930,57928,N,57950,57926,N,57944,46973,47711,57922,57949,N,57927,57941,47716, +47709,N,57947,N,57920,57946,N,47727,57937,57953,47725,57929,47710,57931,57945, +47719,57924,47723,47713,57933,57923,57852,N,57943,47720,57952,57853,47717,N, +57939,N,47718,57925,57936,57932,57934,N,47712,57951,47726,57935,N,57954,N,N, +57854,57940,47715,47724,47722,57921,57942,47721,N,N,47714,57938,N,N,N,N,57948, +N,N,N,N,N,N,N,N,58837,N,58833,58829,58849,58846,48333,N,N,58853,58836,48344, +58843,N,N,58832,58842,48341,58862,N,58859,58845,58830,N,N,58850,58852,48337, +58840,58835,58826,48334,48342,N,58855,48343,58827,58861,58848,58854,48340,N,N, +58851,N,58858,N,48345,N,48339,58844,58831,58863,58828,58856,48336,N,58838,N, +58839,48335,48332,58834,48338,N,48331,N,58857,58860,58841,59850,N,N,N,N,N,N,N, +N,N,59842,N,59838,48886,N,N,48875,48880,48876,59852,59863,48874,59844,59853, +58847,59854,N,N,48881,N,59869,48885,48888,59840,N,48884,N,59867,59868,59858, +59857,59849,N,N,59859,59866,59865,N,48879,48877,59851,59848,N,59845,59864, +48887,59862,48883,48882,N,59856,N,59839,59841,59843,59861,59855,48878,N,59846, +N,59860,N,N,N,N,N,N,59847,N,N,N,N,N,N,N,49359,60741,49352,60661,N,60737,49354, +60744,N,60668,N,60663,N,N,60745,60659,60670,N,49361,60740,60746,60669,49353, +60736,60660,49360,N,N,60743,60665,49356,N,60667,60664,49362,60666,49355,49358, +60739,60662,60742,N,60738,N,N,N,49763,61415,49768,49769,N,N,N,49762,61414,N, +61411,61412,49766,61406,61410,49765,N,61407,N,N,N,N,49767,49764,N,61405,61409, +61413,N,N,N,62033,62030,62039,N,62038,62036,62031,N,50034,N,N,N,N,N,62032, +50033,49357,62035,50032,62040,62034,62029,61408,N,N,N,50031,N,62028,62550,N, +62549,62037,50280,N,62553,62554,62548,62552,N,62547,N,N,N,N,62929,62551,50407, +50405,62927,62930,N,62926,62928,50406,N,N,N,63205,63206,50550,63204,N,N,N, +63458,50639,63456,63457,63660,N,N,50774,63731,63729,63730,63732,N,N,N,63931,N, +42221,42680,N,43609,N,52457,N,N,53092,N,N,N,53749,53751,N,53750,N,53752,45565, +54743,53753,N,54742,54744,54745,55770,46299,55771,55773,46300,46298,55772,N, +56826,56824,56823,N,56822,56821,47026,56825,47728,57955,57957,47729,57956, +48347,N,48346,58864,N,N,59871,59870,59872,N,N,48889,N,60747,49363,N,61416, +49770,62041,50551,42222,42431,42681,43074,43610,43611,N,N,44142,N,N,53754,N,N, +N,N,47027,N,N,N,59089,48890,49771,42223,N,42682,N,N,52459,43612,52458,N,53093, +44143,53094,N,44144,N,53756,44782,44781,N,54750,54748,54749,54747,N,54746,N,N, +55774,55777,46302,55775,46301,55776,N,56827,N,N,57958,57959,57960,N,58867, +58866,48348,58865,58868,59873,N,N,59874,59875,N,60748,49364,49772,62042,N, +50408,51551,N,44145,53095,44783,N,N,45566,N,46303,55778,N,47029,47028,N,N, +57961,57962,48349,48350,59877,59876,61417,63459,42224,51552,42432,N,43075, +52040,N,44146,47030,42225,N,53096,44147,53097,N,49365,42226,N,N,52460,N,53098, +N,53826,53825,53758,N,53757,53827,53824,N,N,45632,45633,N,N,46304,55779,N, +55780,55781,N,N,N,56897,56898,56896,N,56829,56830,47031,57963,58871,58870, +58869,58872,59879,59878,48891,59880,N,49366,60749,N,61418,62043,63207,N,42227, +42434,42433,N,43613,51553,51582,42683,N,51703,52041,52042,43614,N,52461,N, +44148,53099,53100,N,44784,44788,53828,44787,44785,44786,N,54751,45634,46307,N, +46305,46306,55782,N,N,47730,42228,N,51617,N,42435,N,N,51620,N,N,42438,51619, +42437,42436,43076,51618,N,N,51704,N,N,N,51708,51710,51776,42693,42694,51707, +42689,N,51705,N,51709,42690,N,42685,N,42686,N,42692,51706,42684,43077,42687, +42688,42691,N,N,N,52059,52057,52044,43089,52051,43084,52045,N,52053,N,52050, +43087,52049,43094,52058,43096,N,43098,N,52043,N,43085,52060,N,43092,43095,N, +52549,43079,43102,43093,52046,43082,43097,52054,43080,43081,52547,52047,43088, +43099,52061,52048,43086,N,43091,52462,43100,52055,43090,N,43101,43078,52052, +43083,52056,52548,N,N,N,N,N,N,N,N,N,N,N,N,N,43626,43642,52469,43633,N,52555, +43618,N,43621,52546,N,52467,52471,43629,43631,52474,43638,43624,43622,43623, +43637,52551,43632,52473,52475,43630,43635,52476,52554,N,44149,43641,N,43619, +52553,N,52557,52472,52559,52544,43628,52468,43627,43645,43634,N,52466,53109, +43640,43644,52545,52550,N,43646,43639,43625,43615,N,43620,N,52470,43616,52558, +N,52464,52463,52477,52465,43643,44789,43636,52478,43617,N,44198,N,N,N,52556, +53116,53153,N,53156,53111,N,N,53159,53162,53164,53108,44150,44155,53833,44205, +53157,53165,53115,53107,N,N,N,53860,44158,53154,53112,53114,44197,N,53117, +44157,53104,53160,N,53163,N,N,44154,N,44200,53101,44202,44152,44206,53161, +53103,44203,53854,52552,44156,44151,53110,53102,44204,44196,53155,44201,44199, +53113,44193,53105,44194,44195,53106,53158,44153,53118,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,53836,44797,44867,N,N,N,53845,53851,53847,53834,53837,53830, +53831,44874,44794,53846,53855,44869,44790,N,44864,53838,44866,53839,53849,N,N, +N,44868,53864,53832,44796,44795,44872,53829,53862,53850,53863,53857,53843, +53858,N,53852,53861,53859,44873,53844,44793,44792,44865,44871,53856,44870, +53841,45635,N,53865,53840,53835,44798,44875,44791,N,53848,53853,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,45669,54753,54757,N,45650,45648,N,N,45639,54755,54754, +45659,N,54760,45653,N,54778,54855,45636,54775,54768,45671,54752,N,54780,N, +45668,45656,45667,45646,54764,54782,54774,45647,45641,54853,N,54781,54848, +45649,45657,54850,54762,54779,54767,54852,45662,45638,45660,54772,54770,54771, +45651,54766,54765,45640,54759,54854,45642,54769,45672,N,45666,54758,45663, +45661,45670,54776,45665,53842,54777,45664,54849,45637,54773,45655,54761,45654, +N,45652,45644,45643,55783,54851,54763,N,N,55804,N,45645,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,46401,45658,46318,55798,46332,N,55786,46315,46311,55881,46317, +46321,46316,46325,55885,55876,N,N,55793,46330,46324,55805,46308,55882,55875, +46312,55799,46327,55893,55894,N,46309,55880,46329,55803,55789,55790,46333, +55794,55801,55795,N,46331,46404,55791,55784,55785,N,55787,46314,55800,N,46328, +46402,N,N,55802,55891,55883,46310,55889,46322,N,46320,N,55895,46319,55873, +55796,55806,46407,55877,55874,55792,46403,55887,55884,55892,46313,55872,46406, +N,55879,N,N,46323,46326,N,55878,46405,55797,54756,N,N,55888,55886,55890,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,55788,46400,N,N,N,56929,56928,56902,47037,N,56927,56905, +56906,N,47047,56936,47042,56926,N,56899,47048,47038,56914,56904,56907,56931, +47032,56938,56930,47041,56919,47052,N,N,47051,47045,N,N,56937,47033,56917, +56908,56921,56933,47053,N,47035,56916,N,56909,47044,N,47043,56912,56922,56932, +56903,56913,47036,56923,47049,47040,56910,47039,56901,56915,56935,46334,47792, +56918,57964,56920,56934,47046,56911,47034,47050,48368,56900,N,56925,N,N,N, +56924,N,N,N,N,N,N,N,N,N,N,N,N,N,N,58026,47789,57981,58020,47778,N,57966,47791, +N,47735,57965,58032,47793,57969,58019,N,57971,58035,58031,47733,47777,58963, +47790,47741,57967,N,58030,47779,58027,58040,57973,57982,N,N,58038,58028,47740, +N,N,57980,47734,47732,47784,N,N,57978,57975,57976,N,58034,N,58039,58037,47738, +58041,47742,47783,N,57968,58874,57977,N,47736,47788,47785,47739,58021,57972, +47786,58023,47780,47782,47731,N,58025,58017,57970,47781,58033,58036,57979, +58024,N,47737,48351,58022,58873,N,58029,N,N,N,N,N,N,N,N,N,N,57974,58948,58958, +48354,58957,58969,48356,58955,N,58959,48367,N,58950,48359,N,58962,59888,48371, +48370,58964,58947,58974,48365,N,48355,58967,N,58971,58976,58965,58953,48358, +48361,48369,48364,N,58956,58018,N,N,58952,58975,48360,N,48363,58977,48352, +58966,58875,58972,49375,N,58954,N,48353,58949,48357,58876,47787,58945,N,58970, +58946,58944,48362,N,58968,N,58878,58961,58960,58973,58951,48366,N,N,N,N,N,N, +59891,N,48969,48894,59968,59883,48961,59895,48968,48963,59893,60751,59899, +59970,59898,59881,59896,59972,59974,48893,59973,48964,48970,N,48967,N,59902, +48966,59897,N,59885,59890,N,59901,48965,48962,48892,48960,59889,N,58877,59884, +59887,59969,59892,59882,60750,59971,59886,59900,N,N,N,N,60753,49379,N,N,49367, +N,N,49371,60755,60761,60759,49369,49370,49377,60762,60754,49372,N,60758,60757, +60763,49378,N,49373,49376,60756,49380,49374,49381,49368,60760,N,60752,N,N, +61431,N,N,49777,61428,61430,N,49775,61426,61427,61422,N,N,59894,61423,49776, +61419,N,49773,61432,49774,61420,61421,61425,49779,N,49778,N,N,61424,50040, +62047,62053,50041,62044,50038,50035,62055,50039,N,50036,62046,62049,62050, +62051,62054,N,61429,62045,50037,62052,62056,62048,N,N,N,62557,50282,62560, +50283,62568,62559,62556,N,62558,62562,62565,62564,62567,62555,N,50281,62563, +62566,62569,62561,62931,62932,62936,62937,N,62934,62935,62933,N,50409,N,N,N,N, +50552,63211,N,N,63208,63209,63210,50553,N,63461,63460,N,63663,50676,63661, +63664,63662,63733,50775,50789,63907,63852,N,63906,63952,63953,42229,N,N,N,N, +42695,51777,N,N,52062,N,43103,N,43106,N,52063,N,43104,43105,N,N,N,N,52568, +52570,52565,52562,52564,N,N,N,43684,N,N,N,43682,N,N,52566,43683,52563,52560, +43681,52567,N,52561,43685,52569,N,N,N,N,53167,N,53171,N,N,44215,N,N,N,N,53174, +N,44207,44210,44212,44214,44211,53170,53169,N,44209,53172,53173,N,53166,44213, +N,44208,N,N,N,53168,N,N,N,N,N,N,53879,53880,53881,44880,N,44876,53870,N,53878, +53883,44881,N,53868,53874,53867,53877,N,N,53873,44877,44879,53882,N,53866, +53869,53875,N,53876,53884,53872,N,44878,N,N,N,N,N,N,N,N,N,N,45677,54862,N,N, +54864,54860,N,54872,54858,54871,45673,54856,55899,54866,45676,N,54867,54870,N, +54874,N,54863,N,54868,N,N,45674,45675,54873,54861,54857,54875,N,54865,N,N, +54869,N,N,N,54859,N,46408,46409,55909,46415,N,55897,55906,55896,46412,55904, +55902,N,55903,46410,N,55907,N,N,N,N,N,55900,55898,46411,55901,55905,N,N,N, +46413,N,N,N,55908,N,N,N,N,N,N,56944,56951,56953,56993,N,47066,56939,N,47058,N, +56954,47063,56994,47054,N,56957,N,56941,56958,56940,N,47068,N,56952,47055, +56995,N,47060,56945,47065,56956,56943,56950,56946,56942,47057,47064,47062, +47059,47067,47056,56949,N,47061,N,46414,N,56955,N,56947,N,N,N,N,N,56948,N,N, +58049,N,47796,N,N,58045,58051,58047,N,47798,58046,58050,58042,N,58044,47797,N, +N,N,N,58048,58043,N,47799,N,47794,N,N,58052,N,47795,58983,58980,58992,58986, +58988,48372,58982,58990,N,N,58989,58987,N,58993,48375,58984,58991,N,48373,N,N, +58979,58981,48374,58978,58994,N,58985,N,N,59978,48977,N,N,59989,59987,48971, +59977,59980,59981,59976,48981,48982,59975,59990,59985,48975,48972,59984,59982, +N,N,48978,59986,48973,N,48974,N,59983,48976,59979,N,59988,48979,59991,59992, +48980,N,N,49383,49390,60764,60770,N,60768,49386,49385,49382,60766,N,N,N,49388, +49387,49384,N,60769,60765,60767,N,49389,N,N,N,49783,61435,N,49780,49781,61437, +49782,61434,61433,62060,61436,N,62061,50042,62059,N,N,62058,N,62057,50043,N,N, +50284,N,N,62570,62571,N,N,N,N,62940,62939,50410,N,62938,63212,63213,N,N,63462, +63665,N,N,63734,63932,50809,63942,42230,N,43686,43687,N,N,44216,N,N,N,N,49391, +42231,N,43688,44882,47069,42232,N,45678,47800,51554,N,53175,53885,N,58053,N, +49392,42233,43689,53176,53177,55910,46416,N,N,56996,N,N,47070,58054,N,N,48376, +N,50044,42234,55911,42235,N,42697,51778,42696,43109,43108,43107,52064,N,N,N, +43690,N,43691,52571,N,53178,N,53181,44218,53179,N,44217,53180,44219,N,53922, +53921,53886,44883,N,54877,54878,45679,54876,54879,46418,45680,N,N,46417,55915, +55914,N,55912,55913,N,55916,56998,56997,57001,N,57000,56999,47801,58057,N, +58056,47802,58055,58995,N,58996,48377,N,59993,59994,N,N,62066,50045,62065, +62064,62062,62063,50411,62572,63214,63735,N,42236,N,51621,42439,51622,N,N,N, +51779,51780,N,N,N,N,52070,N,N,52066,N,52065,43692,52069,43111,52067,43110, +52071,52068,N,N,52575,53182,52573,52580,N,43693,N,43696,52581,52577,N,52578,N, +52572,43695,52574,43694,52579,N,52576,N,N,53186,44221,44222,N,53189,53183,N, +53188,N,53184,44220,53187,53185,N,N,N,N,N,N,N,53928,53925,N,53927,44888,44887, +44885,53924,53929,44884,44886,53926,54887,53923,53930,N,N,N,N,N,54882,54886,N, +54885,55918,55929,N,N,54888,N,54883,55917,45684,N,N,45683,54881,54884,45685,N, +45682,45681,54880,54889,N,N,N,55920,55927,N,46420,55926,55923,N,46422,N,N,N, +55925,N,N,55919,55921,55924,55922,46421,55928,46419,47071,N,N,57005,57004, +57002,N,47074,47073,57006,N,57003,58058,47803,47072,N,N,N,57008,57007,N,58061, +58059,48378,N,47804,58060,58998,N,N,N,N,48379,58997,59006,59005,59003,N,59002, +58999,59000,59001,59004,59041,N,N,59999,59996,59997,48983,59995,60001,60000, +59998,N,60772,60773,49393,N,49394,60771,N,49785,61438,49784,50046,N,50081, +50285,62574,62573,62941,63215,50554,63464,63463,63465,42440,53190,44889,45686, +54890,42441,51623,42237,N,N,51781,N,N,N,52076,52074,52075,52072,43112,52073,N, +N,N,N,N,52589,N,43699,52587,52583,52586,N,52582,43701,52585,N,43698,43697,N, +43700,52588,52584,N,N,N,N,44226,44229,53198,53197,53196,44223,53205,53195,N, +44225,53935,N,53202,53200,44228,N,53192,53203,N,53194,53204,53201,53193,N, +44224,53206,53191,44227,N,N,N,N,53940,53931,53942,N,53934,53945,53946,53932, +53944,53941,53939,53943,44895,N,44893,N,N,53937,N,53933,N,53936,53947,53938, +44894,53199,N,44890,44892,N,N,N,N,N,54904,54893,54891,N,54892,N,54899,N,54900, +54896,45691,54901,54898,54895,N,45689,54894,45687,45690,54897,54905,44891, +45688,54903,54902,45692,N,N,N,N,N,N,N,N,55934,N,N,N,55969,46432,N,55975,N,N, +55977,55970,46426,55974,55973,46427,46433,N,46434,55976,46424,55933,55931, +55971,55930,46431,55932,55972,55978,46425,46430,46428,46429,N,N,N,46423,N,N,N, +N,47081,57015,47080,57019,N,57009,N,57020,N,N,N,57010,57011,N,57021,57018, +57016,57017,57013,57012,N,57022,47077,N,57014,N,47082,47076,47083,47084,N, +47079,47078,N,N,58062,47806,47805,N,N,58067,N,48380,47807,N,N,47809,58068, +47075,47808,58064,58066,58063,N,58065,N,N,N,59051,N,N,59050,59047,48448,60002, +48449,59046,N,48382,N,59048,59045,59042,59049,59043,59044,48381,N,N,N,N,60777, +N,60006,N,60005,60007,N,60774,48986,N,60003,N,48984,N,48988,48987,60004,60008, +N,48985,N,60781,49397,49786,49398,49395,60778,60776,N,60779,N,60782,49396, +60780,60775,N,N,61506,61509,62069,61504,N,62575,61510,N,50082,61508,49787, +61505,61507,61511,62070,N,62068,N,N,N,N,50083,62067,N,N,N,50286,N,N,N,N,50413, +63217,50412,63219,63216,63218,50640,63666,42442,52590,53948,53949,45693,57023, +48989,50084,50555,63667,42443,N,52591,41568,N,N,53207,N,53208,N,N,N,N,N,53950, +53951,45694,45729,N,N,N,55979,N,57026,57025,57024,58069,N,58070,58071,47810,N, +N,59053,59052,N,N,60009,48990,48991,N,60786,60783,60784,60785,61513,61512, +49788,62071,62942,42444,N,44230,N,45730,57027,N,42445,N,53952,45731,N,N,46435, +46436,N,42446,42447,51782,43114,43113,44231,53209,55980,42448,42449,42450, +42451,N,N,N,43115,43116,52078,52077,N,N,43702,52594,52592,52593,N,N,N,N,N,N, +53210,53211,N,N,44235,44233,N,44234,44232,N,N,N,N,44896,N,N,N,N,44900,44899, +53953,44898,44897,N,53954,N,N,45734,54907,54906,45732,45733,N,N,N,46438,46437, +55982,N,N,55981,45735,N,N,N,N,N,47085,57029,47086,57028,N,N,N,58072,59054, +48450,60010,N,N,N,60787,N,50086,50085,N,N,50556,42452,52595,N,N,45736,58073, +47811,N,N,52079,52080,N,N,52596,43704,43705,N,N,43703,N,N,N,N,44239,44240, +44237,44238,N,53212,N,N,53213,44236,N,N,N,N,53955,N,44904,44905,N,45739,53961, +N,44910,44908,53962,53957,44907,44906,44901,53960,53959,53956,44909,N,53958, +44902,N,44903,N,N,45740,54945,54946,45741,54908,54910,54948,54947,54909,N, +45737,45738,N,55990,46443,46442,55984,46440,N,55987,46444,55988,46445,55985, +46439,46441,55989,N,55986,55983,N,N,N,N,N,57042,N,57031,47088,47091,47090, +47095,47094,57043,57041,57034,57038,57037,47092,57040,57036,57044,57035,47093, +47087,47089,N,57033,N,N,N,N,58075,47815,58079,47814,58076,47813,N,57032,57039, +58078,N,47816,58080,58077,58074,N,N,59057,59061,59063,59059,59058,59056,48453, +48451,48456,48457,59060,48454,59055,48455,47812,59062,48452,N,N,N,60012,N, +60011,60019,60013,60018,60015,48992,60017,N,N,48993,N,48994,N,60016,60014,N,N, +N,N,49400,60788,N,N,49399,60791,60789,60790,N,N,49401,N,N,N,61517,N,49825, +61518,N,N,49789,61519,49790,61516,61520,N,61514,N,N,50087,62072,50088,50287,N, +61515,50288,N,N,N,50414,62943,N,50558,63220,50557,N,63466,50677,50678,N,N, +63948,N,N,44241,53214,N,46446,46447,42453,42698,51783,N,52081,43117,N,43706,N, +44242,44243,44244,54950,53963,44911,N,N,45742,54949,N,N,55992,46449,N,55991, +46448,N,N,57045,48458,59067,59064,59065,59066,N,N,N,N,N,60792,N,61521,N,N,N, +62577,62576,N,63221,42454,52597,44912,N,N,N,46450,57046,N,N,58081,N,48459, +60020,N,61522,62578,42455,N,N,43707,44247,53215,44248,44246,N,44245,53964, +44913,N,N,44914,44915,N,N,N,45744,54951,45743,N,N,N,N,N,55993,45745,46451, +57047,47096,47097,N,47817,N,47818,48460,48996,60021,48995,N,60793,49402,N, +61523,62579,42456,43118,52600,52599,43708,52598,43709,52601,N,53221,44251, +44250,53223,53222,44255,N,44254,44249,N,53217,53218,53219,N,44256,53216,44252, +53220,44253,N,N,N,N,53967,53971,53969,53968,N,53972,N,N,N,53973,53974,53966,N, +53965,N,44917,44918,N,53975,53970,N,54960,N,53976,44919,44916,N,N,N,54954,N, +54953,N,54955,54956,54958,54957,54962,45749,45746,45750,54952,45751,54961, +45748,54959,45747,N,N,N,N,N,55996,55998,55994,55995,N,N,55999,56001,56002, +55997,56000,46452,N,N,57051,N,57056,57048,57052,N,N,57057,57053,47098,47171,N, +47101,57049,57050,47822,47174,47102,N,47172,47100,57055,47173,57054,47169, +47099,47170,57058,58086,58088,N,N,N,N,N,N,N,N,N,47168,N,N,58083,47820,58089, +47821,58087,58082,58085,58090,47819,58084,N,48462,59071,59070,N,48465,48463, +59068,48461,59069,N,48464,N,N,N,60029,N,60065,N,60030,60022,60026,60025,60023, +48998,48999,48997,60024,60027,60028,N,49000,N,49472,60835,N,49404,60795,49406, +49473,N,N,49405,60834,60796,49403,60833,60794,60798,60797,N,N,61525,49828, +49829,49826,N,49827,N,N,61524,N,62075,N,N,50089,N,62073,62074,N,62580,62583, +62581,62582,62944,N,N,50415,63467,63668,N,50679,63736,63737,50790,42457,44257, +N,56003,N,57059,N,42458,43119,N,43710,N,53224,53225,44920,N,N,56004,46453, +47175,49474,60836,62076,62584,42459,N,N,N,52641,52602,52604,52606,52605,52603, +43711,44258,53234,N,53229,53226,N,N,53233,N,N,44260,44261,53232,53231,53230, +53227,53228,53235,44259,N,N,N,N,N,N,N,N,44924,N,44964,44963,53985,53979,53977, +N,44961,54969,44922,53982,53986,53988,53984,53978,44962,53983,53981,44921, +53989,44965,53987,44925,53980,N,44926,44923,N,N,N,N,N,N,N,N,N,N,45753,N,54970, +N,N,54963,54965,54967,N,54968,54966,45754,N,54971,N,54964,N,N,N,N,N,N,N,N,N, +56008,46454,56016,N,56005,N,56017,N,56006,56007,N,N,56015,56014,56011,45752, +46455,56009,56012,46456,56013,56010,N,N,N,N,N,N,N,57070,N,57074,47182,N,58096, +47185,57072,N,N,57069,57064,57066,57067,57060,N,47181,N,N,47180,N,47176,57063, +N,47183,N,47184,57062,57065,57073,47178,47179,57071,57061,N,N,N,58098,47824, +58100,57068,58102,47828,58103,58099,N,47825,58095,47827,58092,58097,58101, +58094,N,N,47177,N,58091,47826,58093,N,N,N,N,N,48468,59073,48472,N,48470,N,N, +47823,N,59080,59081,48467,N,N,59079,59082,48469,48466,59075,59072,59077,59074, +48473,59076,N,N,59078,48471,N,N,N,N,49002,60072,N,60066,60070,60076,60077, +60073,60074,60071,N,60068,N,49004,49001,60067,60069,N,49003,60075,N,49478,N,N, +60842,60837,49477,N,N,49475,N,60844,49476,60840,60841,60838,60845,61526,49479, +60839,N,60846,60843,N,N,N,61530,N,N,61527,N,49830,N,61531,61533,61532,61528, +61529,N,N,62115,N,50090,N,62078,62114,62077,62116,N,N,62113,N,62586,62589, +62585,50289,62587,62588,62590,50290,50292,50291,62945,N,62947,N,62946,N,N,N, +63222,N,N,63669,63738,42460,N,N,52082,43712,52643,43713,43714,52642,N,53240, +53239,44262,44265,44264,44263,53236,53238,53237,N,N,53992,44967,53996,53995, +53994,53990,44966,44970,44973,N,N,44974,53991,53993,44972,44971,44969,44968, +54978,N,54976,54972,45755,N,54973,45756,54974,54975,54977,N,45757,N,N,56021,N, +56020,56019,56018,N,N,N,N,57078,47186,N,57075,57077,N,47187,N,47188,57076,N,N, +N,N,N,58177,N,58105,58106,N,47831,47829,47830,58179,N,58178,58110,58109,58108, +58107,58176,58104,N,59083,59088,59086,N,N,N,59085,59084,59087,N,60078,N,49005, +49480,60848,N,49481,60847,61535,61534,49831,N,62117,50091,62625,50593,63223,N, +63671,63670,51624,44266,44267,54979,N,47190,42461,43122,43121,43120,N,N,N, +52644,N,N,43716,43715,N,44270,N,53242,53245,53243,N,44268,44269,N,N,53241, +53244,N,44981,N,N,N,54003,54005,54004,44978,53999,N,N,44976,44975,N,44979, +44977,N,44980,54002,53997,53998,54001,54000,N,N,N,N,N,N,N,54982,54983,54981,N, +54980,45758,46461,N,56022,56024,56026,46460,N,N,46458,N,56023,46459,56025, +46457,N,N,57153,57079,57082,57086,47194,57084,N,57083,57080,57081,47192,57152, +47191,N,47196,47195,47193,N,57085,N,N,N,58185,N,58184,N,N,58180,N,N,47832, +58183,58182,47833,N,N,N,N,N,48478,N,59090,N,48479,48475,48477,N,48474,48476,N, +N,N,60079,N,49008,60081,60080,N,58181,49010,49009,49006,49007,N,N,N,N,N,60853, +N,60851,49482,60852,N,60854,60850,60849,N,N,61536,49834,49832,49833,N,N,N,N, +62118,62119,50093,N,50092,62627,62628,62626,N,63224,63225,N,N,42462,51784, +43123,N,52645,43718,43717,52646,N,N,53312,44271,53246,44272,N,N,44982,54008, +54006,54012,44983,54007,54011,54009,54010,N,N,54984,54986,N,45759,N,54985, +45760,46498,46497,46462,56027,N,N,N,N,57156,47197,47198,N,57155,57154,N,N,N,N, +58186,47835,47834,58187,58188,N,48481,48480,N,60085,59091,59093,59092,60084, +60082,60086,60083,N,49011,N,N,N,60855,49483,60856,60857,N,N,49835,49836,N, +50293,N,N,50641,42463,N,N,N,N,N,53313,N,N,N,N,N,N,54013,44984,N,N,N,N,N,46010, +46009,N,N,46500,56029,46499,56028,N,N,N,N,57157,N,47836,58189,47837,N,N,N,N,N, +N,50294,62629,N,42699,43719,52647,N,44274,N,44273,53314,53315,N,N,54080,54082, +44985,N,54084,54087,54085,N,N,N,54086,54083,54014,44986,54088,54081,N,N,N,N, +54995,45766,55004,45763,N,54997,45767,N,45761,N,54992,55005,54993,54990,45765, +N,45762,N,54996,54999,45764,55000,45768,55001,54991,54998,55002,54994,54989, +54987,N,N,55003,N,N,56031,N,N,N,N,56036,N,N,N,56032,56038,46503,54988,56033, +46501,56030,46508,56034,46507,56035,46509,46504,46510,46505,N,46506,N,46502,N, +56037,N,N,N,N,N,N,N,47201,57168,N,57171,57159,57164,57158,47203,N,57162,N,N,N, +57160,47202,N,57167,57166,57163,57165,57161,47841,57170,47199,57169,N,N,N,N,N, +N,N,N,N,58205,N,47848,58200,N,47847,58190,N,58192,47840,58197,58196,58199, +47845,58194,58193,N,N,47844,47839,58195,47842,58201,58203,N,58198,58191,47843, +N,N,48489,47838,N,N,58204,N,N,N,N,N,N,N,59097,48482,N,59099,N,48483,N,N,48485, +59102,N,59094,47846,59100,N,N,N,N,59096,N,47200,48488,N,N,48484,N,48486,48487, +N,49014,59101,59095,48490,N,59098,N,N,N,N,N,60096,60091,N,N,60101,49012,60093, +49016,60099,60090,60087,60102,49489,49017,60098,60088,49015,60092,49019,60089, +60094,49018,60097,60100,N,N,N,N,60875,60876,60860,60867,60865,N,N,49487,60872, +60095,N,60863,N,60873,49486,60862,60861,60871,60868,60870,N,60858,60874,49484, +N,60869,60878,60866,49488,49485,60864,60859,60877,49013,N,N,N,N,N,N,N,61539,N, +N,61537,61543,49840,61541,61540,49842,61546,49841,N,61547,61544,49838,61545, +61538,49839,49837,62123,61542,N,N,61548,N,N,62120,N,N,N,50098,50096,62122,N, +62124,62121,50097,50094,50095,50099,N,N,50296,N,62634,N,62633,62631,62630, +62632,N,50295,50297,N,N,50416,N,N,62949,62948,N,N,63226,N,63228,63230,63229, +63227,N,N,50595,50594,N,N,50643,50642,50644,63469,63468,N,63739,63672,63740, +50776,N,50777,63853,N,N,50814,42700,N,52648,N,N,53317,53318,53316,N,N,44275,N, +53319,53320,53321,N,N,54089,54095,N,N,54093,44987,54091,N,54092,54094,N,N,N, +54090,45769,N,55006,45771,55008,45770,55007,N,N,N,N,N,56040,46511,N,56042, +56039,55009,N,46512,N,N,56041,N,N,N,N,N,N,57174,N,47204,57172,47205,57173, +47206,N,N,N,47849,58209,58206,58208,47850,47851,58207,N,N,N,N,N,59103,N,N, +59104,N,48491,59106,59105,N,41569,N,60106,60107,60103,N,60104,49020,49021, +60105,N,49495,N,N,49491,49496,49492,49494,49490,N,49493,N,N,N,N,49843,60879,N, +62126,N,62125,N,62635,50298,50299,63297,62950,N,63296,N,63741,63908,42701,N,N, +43124,N,52649,43720,44278,53324,44276,53322,44281,44277,44282,44280,53323, +44279,44991,44990,54106,44999,54099,54105,44995,54098,54104,54102,44994,44996, +54101,44989,54100,45000,44997,45001,44998,54097,54096,54103,44992,44988,44993, +N,N,N,N,N,55024,55017,N,46517,55016,N,45775,45782,45779,45785,45784,45780,N, +55010,55013,N,55012,45776,55014,55023,45777,55011,55020,55021,45778,55018, +45783,45773,45781,55015,45772,55019,N,N,55022,N,N,N,56059,56050,46514,56057, +56054,56046,56055,46516,56047,N,56043,N,N,47212,56052,N,46513,56058,N,46520, +46522,56045,N,N,46521,56048,46515,56056,56049,56053,N,56051,46518,56044,46523, +45774,46519,46524,N,N,N,N,N,47208,57181,57183,57185,57189,N,57179,57177,47210, +N,57184,57188,57180,57176,N,57175,N,N,N,57186,57178,57182,47211,N,47209,57190, +47207,57187,N,58226,N,N,N,N,N,47854,58218,48504,58228,47857,58232,47863,58213, +N,N,58229,58210,N,58231,58214,N,47870,47867,58230,58224,47853,47861,47860,N, +47859,47865,N,58211,47866,58225,47862,47852,58227,47855,47856,47864,58216, +58215,58212,N,58220,58217,58221,47869,N,58233,47858,58222,58223,N,58219,N,N,N, +47868,N,N,N,N,59111,48496,48505,48501,59108,N,48498,48502,59120,48492,59112,N, +48500,N,N,59115,59110,48499,48503,59109,N,48497,N,59119,48494,59118,59117, +48506,58738,48493,N,59116,59107,N,48507,59114,48495,59113,N,N,N,N,49058,49063, +49022,60120,60111,60123,60115,60121,49064,49057,60108,60114,60124,60117,60122, +60110,N,N,60118,49059,60116,49062,49061,60112,60113,60109,60119,49060,60126, +60125,N,N,N,60890,60886,49503,N,60880,49497,49513,60892,49505,49501,60883, +49508,49511,60894,49500,60885,49509,60896,60893,60881,49504,49498,49512,60888, +49507,60882,49502,60895,49506,49499,60889,49510,60887,N,N,60891,N,N,N,61550, +61556,49849,61559,49844,49845,61551,61558,61553,49850,49847,N,61549,N,49846, +61555,61557,49848,61554,61552,N,N,N,N,62136,50103,50104,50100,N,50101,N,62132, +62130,N,62134,50106,62135,62128,62127,62131,62129,50102,62133,62636,50302, +50301,62637,N,62639,62638,50337,N,N,N,62955,62952,62953,N,62951,62954,50418, +62956,N,50417,N,63298,N,50645,50647,63470,50646,63673,63808,63810,63742,63809, +50796,42702,N,44283,53871,45002,N,N,45786,56060,56061,N,N,N,60127,49514,60897, +N,N,49851,N,62138,62137,50338,62957,N,63299,50680,51785,N,N,43721,43125,N,N, +53325,N,N,54112,54107,54111,54109,45003,54110,54108,N,55025,N,56062,56128, +57193,57194,47214,47215,57192,57195,57191,47213,N,47936,N,47216,58234,N,48508, +59121,48509,N,49065,60130,60128,60129,60900,60899,60898,N,N,N,62139,N,50105, +62140,63300,50681,63674,42703,43723,43722,53327,44284,N,N,53326,54114,N,45004, +55026,54113,N,N,N,45788,55029,55027,55028,45787,N,56130,56131,56129,N,47219, +57197,57196,57198,47218,47217,N,N,59122,59124,N,48510,59123,60131,49066,61561, +N,61560,50107,62141,50109,50108,62640,62958,50419,42704,53328,44285,54117, +45006,54116,54115,N,45005,N,55035,N,55037,55030,55031,45789,55032,45790,55036, +55033,55034,45791,N,46526,46527,N,56132,N,N,N,57199,57200,N,58238,47939,47937, +47938,58235,58236,N,58237,59129,N,59130,48545,59127,59126,59128,59125,49069, +60132,49067,49068,60902,49515,60901,61352,N,61562,61563,49852,N,49853,49516, +62142,62143,62641,50339,42705,N,42706,44286,43724,45007,53329,N,N,N,46528, +42707,44353,53330,53331,44352,44354,42708,N,53332,45009,54118,45011,45008, +45010,N,55105,45792,N,55104,55038,N,57201,N,N,58273,N,48546,N,49070,60134, +60133,N,60903,N,N,N,62959,N,N,42709,52083,52650,44355,53333,N,54120,N,N,N, +45012,54119,45013,N,N,N,55107,N,N,45794,55106,55108,N,45793,N,N,N,N,56134, +56135,56133,46529,N,N,N,47220,N,47221,N,47941,N,58275,58274,47940,N,N,N,N,N, +59131,N,N,59132,N,N,N,N,60135,N,N,49520,49519,49517,49518,49521,N,61564,49855, +49854,62144,62642,N,N,N,50597,50596,42710,N,N,53755,N,47223,46530,47222,47942, +N,42711,51625,42712,42713,N,N,52651,52086,N,52087,43127,N,52084,43126,N,43129, +52085,43131,43130,52088,43128,N,N,N,43729,43727,52653,N,43726,N,N,N,43731, +43733,43730,N,52656,52652,43734,N,43728,43132,N,43732,52655,N,N,52654,N,43725, +N,N,N,N,N,N,N,53339,44359,44360,53341,N,53335,53338,53347,53345,N,44361,53351, +44364,53348,53340,53337,N,N,56137,53346,44356,53349,53334,53343,44358,44363, +53344,44367,44365,N,53336,44362,N,53342,44366,44357,53350,N,N,N,N,N,N,45018,N, +45027,45016,45014,54122,45022,45019,54124,N,N,45021,54123,54121,54126,45026, +45024,56136,54127,54125,45015,N,N,45017,45020,N,45023,N,45025,N,N,N,N,N,N,N,N, +N,N,55118,45796,N,55109,55111,N,55112,N,55120,55116,55114,N,55117,55121,45797, +45801,55110,N,55119,N,45799,N,45798,55115,55113,N,45795,45800,N,N,N,N,N,N,N,N, +46536,56145,N,N,56143,46538,N,N,N,N,56138,57249,N,46537,56142,N,N,56139,46533, +46539,56144,46535,56141,47943,46534,56140,46540,46532,46531,N,N,N,N,N,57207, +57205,N,57211,N,57203,57250,57208,N,57202,47227,47267,57213,N,57206,N,47230,N, +N,47228,57214,47225,47224,57209,47229,46541,N,57212,57204,47226,47265,47266,N, +N,N,N,47948,47944,N,47949,58278,N,N,58277,58279,47946,58276,47947,58282,58281, +58280,N,47945,N,N,N,N,N,59201,N,59204,48552,59203,48551,48547,48548,48549, +59200,59134,48550,N,59202,59133,N,N,60137,60147,49073,49072,N,60141,60143,N, +60138,N,60142,60136,60145,49071,60144,60140,N,60146,N,60139,49524,60904,60910, +49528,49530,49527,49526,N,49525,49523,60905,60908,49522,60909,N,49529,60907,N, +60906,49856,N,49857,61601,61565,61566,N,N,62146,N,62145,50110,62644,50340, +62643,N,62960,63301,50598,63811,63812,50648,42714,N,43735,56146,47950,49531, +60911,42715,N,45029,45028,56147,N,N,N,60148,42716,44368,N,N,56148,56149,56150, +47951,49074,42717,N,43736,53352,45030,54128,45802,N,56151,47268,N,47952,49075, +49532,49858,62645,42718,43737,N,N,45031,55122,46542,N,47953,58283,59205,N,N,N, +N,42719,46543,57251,47954,42720,52657,53353,44369,N,N,54130,N,N,45034,N,45032, +45033,45035,N,N,54129,N,N,55127,55124,55126,45803,45805,45804,55123,45806, +55125,N,56152,56153,N,56154,57254,N,57255,N,57253,57256,N,47269,N,57252,N, +47955,N,N,59210,59206,59209,59211,59208,59207,N,60149,60150,60151,49076,49077, +60913,60912,60914,N,61603,61602,N,62148,N,62149,62147,N,50341,N,62646,62647,N, +63302,63471,63675,42721,43133,N,49533,42722,N,55128,56155,N,50753,51786,N,N,N, +51787,51789,42723,51790,51788,N,N,52130,52131,52091,N,N,N,N,52129,43169,N, +43170,52092,52090,52089,52093,43134,52094,53354,N,N,N,52662,43740,52661,52663, +N,43739,52668,43743,52658,52672,52678,43750,52675,43747,N,52665,52671,52673,N, +52660,43746,43741,52666,43748,43751,43745,N,43738,52670,52664,52677,43753, +43749,43744,52669,45036,52667,43742,43752,N,52659,N,52674,52676,N,N,N,N,N,N,N, +N,N,N,N,N,N,44386,44380,44388,44385,53361,53364,44381,N,53355,N,44374,44384,N, +44387,44389,53410,53367,N,44373,53409,44377,44375,44370,53359,N,53374,53363, +53366,53413,N,44390,53373,44382,53368,53412,53365,53369,53372,N,N,53357,53411, +53371,N,N,53356,53360,44383,44378,44371,44376,44372,44391,53358,54181,44379,N, +N,53370,52801,N,N,N,N,N,N,N,N,54184,45050,N,54134,N,54179,54141,N,54194,N, +54186,N,54142,N,54185,54136,54140,54197,45053,54189,54180,45037,54195,54132,N, +54188,N,45052,45047,54131,45045,45044,45049,54187,45041,45048,53362,56156, +54182,N,N,54138,45051,54139,54177,45054,54133,54191,N,54190,54198,45043,45040, +54196,54192,54183,54178,45046,45042,54135,45038,54193,45039,N,54137,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,55134,55136,55141,55161,45820, +45810,N,55133,45821,45822,55144,55151,55157,N,55138,N,55145,N,N,45888,55159, +55154,45818,45816,55150,55146,55132,45807,55137,55129,N,45815,45817,55142, +55139,45812,55155,45809,55140,55162,55148,N,55147,45808,N,45819,N,45811,55130, +55135,55152,55158,45889,55131,55143,55149,45814,N,N,55160,55153,55156,N,N,N,N, +N,N,N,N,N,N,N,N,45813,N,56172,56160,46551,56189,56231,56234,46549,56168,56227, +56169,56183,46562,56179,46559,N,56180,56157,N,56228,N,N,46568,56225,56181, +56236,56176,57288,N,56239,46566,56174,56186,46569,46548,56178,56237,56171, +56164,56175,N,56163,56161,46544,56229,56170,56232,N,56233,46552,46557,46553, +46561,56190,46554,56182,56166,N,46546,56158,56226,56235,56165,46560,56240, +56177,56173,N,46545,46565,N,56188,46567,N,56184,46556,46550,46558,46547,46564, +56185,56167,56187,56162,56230,N,N,N,N,N,N,N,56238,N,N,N,N,N,N,N,56159,N,N,N,N, +N,57287,N,57309,47189,57292,N,57290,57269,47273,57285,57305,57281,47281,57304, +57279,46563,57295,57280,57302,47280,47272,N,57258,57266,N,57291,57283,57308, +57286,47286,57303,N,47277,N,57289,57297,57270,57296,N,57313,57265,57298,N, +57311,N,57259,46555,N,57273,57272,47279,N,57276,57278,57293,57310,47282,N, +47283,N,57264,47275,57268,57306,47284,N,47276,47278,47285,57312,57299,57294,N, +N,57275,57274,47274,57260,47271,57284,57261,57282,N,N,57271,57307,N,N,N,47270, +N,N,N,57267,N,N,N,N,N,N,57263,57301,57262,47968,58323,N,N,58306,N,N,58284, +58314,47960,58299,58309,47963,58302,47961,58287,58317,58286,58305,N,58285,N,N, +58303,58312,58310,58298,58293,58291,N,58292,58311,58322,58300,47962,N,58295,N, +58315,N,47965,58294,58288,58304,47969,N,N,47957,47966,58296,58290,N,47959, +57300,47958,58307,N,47956,47971,47964,58308,58297,58289,58316,58301,47970, +58320,47967,58319,N,58313,58318,N,N,N,58321,N,N,N,N,N,N,N,N,N,N,N,59251,59252, +59239,59238,59234,48564,N,48556,59254,59253,57257,59231,59235,59229,N,59248, +59233,N,59255,59226,59224,59236,59246,59241,48566,59215,N,59245,N,N,N,48567, +57277,59227,59218,59221,59259,59228,59219,59217,59214,N,48560,59237,48559, +48563,59232,59240,48553,59256,59260,48555,N,59223,59243,59247,59220,59257, +48562,N,48561,59212,48565,59250,59222,59242,59216,59230,59225,48557,48558, +59244,59261,59258,59249,N,N,N,N,N,N,N,N,N,59213,N,48554,60233,N,60224,60227,N, +49083,60229,60153,60225,60231,49080,49084,49078,N,N,60155,60236,N,N,60230,N, +60156,60245,60239,60152,60998,60158,49079,N,60234,N,60244,49087,N,60241,60157, +60228,60232,60226,60246,60243,60240,49081,49082,49086,60154,60247,49085,60237, +N,N,60235,N,N,N,60238,61011,60992,60997,61010,60996,60923,60993,N,49570,N, +60916,61005,61007,60915,49569,61009,61001,49576,61008,60994,49578,60921,60242, +61002,60999,60917,61013,49572,N,N,49573,60919,61000,N,61012,61003,60925,49575, +49571,61004,60926,61014,60920,60995,61006,60922,60924,N,49867,60918,49577, +49860,49534,N,N,N,N,49574,49864,61619,N,61609,61604,61610,61620,61624,61623, +49866,49865,N,N,61611,61625,61614,61606,N,61608,61607,61613,61618,61605,61612, +61617,49863,N,61615,N,49861,61616,49859,49862,62165,61621,N,N,50114,N,62157, +62161,62153,62156,N,62164,50112,62169,62162,N,62154,62170,62163,50115,50116, +62167,N,62155,50111,50113,62150,62158,62152,N,62168,62166,62151,62159,N,N,N, +62654,50117,62160,50343,50345,50342,N,62659,62651,62649,62653,62650,N,N,62655, +62657,50346,50348,N,62656,50349,50347,62658,N,N,N,N,50344,N,N,N,N,N,50420, +62961,62967,50422,62652,62966,N,62973,62964,62971,62970,62648,62965,61622, +62974,62963,62968,N,62972,62962,N,63306,50421,62969,N,N,63476,63307,63305, +63303,63304,63308,N,50649,63474,63472,63477,63475,N,63478,50650,63473,N,N, +63676,N,N,63813,63814,63815,N,N,63943,63933,51791,43754,N,44392,N,54200,54199, +45120,45890,55164,N,N,55163,N,46570,47288,N,47287,47289,N,58324,59262,60248, +60250,60249,N,49579,61015,61626,63909,42724,N,52681,52682,52680,52679,43755,N, +53417,53415,N,N,53414,N,44393,44395,44394,53416,N,N,N,N,N,N,N,N,54212,54209, +54207,N,N,45121,54210,45126,54204,54219,N,54221,54205,N,45123,54222,54217, +54203,54208,54218,54214,54211,N,45128,54220,54206,N,N,54215,54201,45127,45124, +54213,N,54216,54202,45125,45122,N,N,N,N,45900,55205,45899,N,55208,55211,45896, +45894,55166,55209,55207,55204,55212,55213,55215,55216,55165,45893,55202,55201, +55214,45895,55203,45897,45892,55206,45901,N,45898,55210,N,N,N,46577,56255,N, +56244,46574,N,57319,56253,56241,46572,56246,46575,56250,56248,46578,46571,N,N, +56242,56245,46576,N,56243,N,56254,56252,56247,56249,56251,46573,N,N,N,N,N,N,N, +57320,57326,57316,57322,47290,57318,47296,N,N,47295,47294,57325,47297,47298, +57315,57328,47299,47293,47292,57324,47300,57314,57317,57327,57323,N,N,58356, +58345,47291,N,N,N,N,47978,58333,58354,58334,47973,N,58331,N,58340,58332,47975, +58326,58353,47976,58350,58351,58327,47981,58342,N,58336,58343,58330,N,58355, +58347,58341,58325,47977,58348,N,47980,58352,N,58346,47974,58344,N,58338,47972, +58329,58337,58349,58335,N,N,58339,N,N,N,N,N,48577,57321,59314,59323,59313, +59309,59306,48578,59304,47979,59297,48576,59303,48575,59308,59305,59321,59316, +59310,59315,48571,59307,59326,59298,59299,59322,48572,59327,48574,59328,59312, +58328,59318,59311,59320,59317,N,N,N,59302,48569,59325,48570,59300,48573,60260, +59319,59324,N,N,N,N,N,60257,48568,49088,60267,60263,N,60261,60256,60271,N,N,N, +49092,N,60252,60264,60265,60255,60254,60268,N,60258,60253,60259,N,60270,60251, +60269,60266,49090,49089,N,N,49091,60262,61643,N,N,N,N,N,61017,49585,61021, +61018,61025,61031,61020,N,61040,49582,61034,61023,61035,61030,61037,61022, +49587,49586,61024,61038,61016,61036,49580,N,61028,61027,61032,61019,49584,N, +49588,61026,61033,49589,61029,N,N,N,N,49581,49583,61639,61637,N,N,61644,61641, +61645,N,61630,61638,61649,61039,61634,49871,59301,61629,61642,61636,61633, +61628,61627,61648,N,61632,61631,49869,61640,N,49868,N,N,49870,61635,61647,N, +62174,62175,N,50121,62172,50118,62180,N,50122,62182,62171,61646,62184,62173,N, +50119,62179,N,62181,62176,62183,62178,62177,50120,N,N,62661,62662,N,62664, +50350,50351,62665,62663,N,62660,N,63042,63045,63041,N,50426,63043,50425,50424, +50423,63044,63313,63311,N,63310,63040,63312,63046,63309,N,63481,63447,63479, +50651,63480,63482,N,63679,50682,63678,63677,50683,N,50778,63854,63911,63910, +63912,42725,53418,N,54223,54224,N,N,N,56256,N,63047,63680,42726,44396,53419,N, +N,N,55217,45902,N,56258,56257,46579,N,47301,59329,48579,N,48580,N,N,N,49093, +50684,42727,N,N,N,53420,43757,53422,53421,44397,N,54225,N,54232,45129,54230, +54228,N,54235,54226,54227,45130,N,45134,N,N,54236,45133,54234,54231,54229, +45131,45132,54233,N,N,N,N,45904,55218,N,45909,55234,45908,55236,N,N,55224, +45906,55235,N,55219,45907,55231,55227,55229,55223,55230,N,N,45903,55226,N, +55225,55221,N,55232,N,N,55228,55220,N,55222,45905,55233,N,N,N,N,46582,56269,N, +N,N,56265,56267,56262,56261,56259,N,56266,56268,56264,N,56263,46580,46581,N,N, +N,N,N,N,56271,47309,57330,57336,57331,57332,N,57337,N,47311,N,47303,47310, +57329,56260,47306,47304,57335,57334,47305,47307,57333,47302,N,47308,N,N,N,N,N, +58358,47988,N,N,58434,58433,N,58363,47990,58432,58359,58360,47982,47984,N, +58365,58357,47986,47985,58361,58366,58364,47987,58362,56270,47983,N,N,59330, +59337,48582,N,59341,48586,59333,59331,N,59340,N,48581,59339,48583,48584,59332, +48585,59338,59334,59335,59336,47989,N,N,N,60272,60284,N,49098,60279,60281,N, +49096,60273,60277,N,60280,49094,49097,60283,60275,60276,60282,60274,60278, +49095,61042,N,61041,49591,61047,49593,N,N,49590,61043,49594,61044,N,N,61045, +61048,N,49592,N,61654,N,N,61657,N,61651,61653,N,N,61652,61655,61656,61046, +61650,N,N,50125,62188,62191,62193,62186,62187,62190,62192,50126,50124,50123, +62189,62185,62666,50352,N,62667,N,N,63049,50427,63051,50428,63048,63050,50600, +N,63314,50599,63485,63484,N,63483,N,N,63816,63817,63819,63818,N,51792,42728,N, +44398,55237,46583,N,57338,49872,N,62194,N,N,43171,N,N,N,45911,N,N,N,45910,N, +56272,46584,56274,56273,N,N,57339,47312,58435,58438,58437,N,58436,59342,59344, +59343,N,49100,N,N,N,49099,N,49595,61049,61051,61050,N,N,49873,N,N,N,62196, +62195,N,62668,50353,N,N,50429,63316,63315,50779,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,43172,53423,44399,55240,55238,N,N,55239,56276,56277,57411,56275,N,57340, +57409,57408,57410,47313,57342,57341,57412,N,58441,58439,N,58440,59347,59345,N, +N,59346,60285,61052,61053,49874,N,62197,62669,50354,N,63052,63317,50601,N, +63486,63820,43173,N,44401,44402,53424,N,N,53425,44400,N,45140,N,45138,N,45137, +45144,45136,45145,54237,45142,N,45139,45143,45141,45135,N,N,45919,N,45913, +55244,45918,N,N,45920,45914,N,45915,N,55242,N,N,45912,N,55243,45917,N,N,55241, +45916,N,N,46660,N,46662,N,N,56280,46661,46585,46589,N,47332,57417,56282,46590, +N,N,56285,56286,46659,N,56288,N,56290,N,56291,56279,56278,56292,46658,56289, +56287,N,46656,46587,46663,56283,56284,56281,N,46657,N,N,46588,N,46586,57416, +47327,47322,N,N,47317,N,47333,47318,N,47314,47329,47326,47328,N,47319,47324, +47315,47316,57424,57421,57413,57418,N,47330,57425,47331,47321,N,N,57415,N, +57423,57419,57422,57420,47325,57414,47320,N,N,N,58444,47992,47995,N,58446,N, +48037,58445,47997,N,48591,58447,N,48036,58443,48038,N,N,N,47993,N,47323,47996, +N,47994,47998,48034,47991,48039,48035,N,48033,58442,N,N,N,N,48598,N,48594,N,N, +N,48601,N,59350,48602,59362,59355,48587,59363,59357,48597,59358,N,48596,59361, +48590,59359,59349,48589,60330,48595,N,48592,N,48600,N,59348,N,59352,48588, +59351,59353,59354,48599,59356,59360,59364,N,48603,49106,60325,60331,60328, +60286,60332,60321,N,60327,N,49101,49107,60333,N,N,49103,N,49113,49108,60335, +60329,49104,60322,49114,60323,60324,49115,49112,48593,N,49102,60336,49116,N, +49109,60334,49105,49110,49111,N,49603,61092,61101,61098,61100,N,49600,61093,N, +61099,49596,61095,49604,61091,61096,61103,60326,61097,61090,49597,61089,49598, +61104,49599,61102,49602,61054,N,49601,N,61094,61660,61674,61669,61671,61659, +49875,N,61658,49878,49877,N,61673,61665,61662,61668,N,61661,N,61663,61672, +61670,N,49876,61677,61675,61666,61676,61667,N,62201,50127,62273,N,N,63055, +50134,61664,62199,50130,62200,62205,N,N,50132,50133,62198,62272,62274,62202, +62204,62206,62203,62275,50129,50135,50131,N,50128,62672,N,50359,62670,N,N, +62674,N,62675,50357,62676,62673,N,62671,50360,50356,62677,N,50358,50355,N,N,N, +50430,N,N,50496,63054,63053,63056,63057,N,50497,63318,63323,50602,N,63320,N, +63319,63322,63321,N,63555,N,50652,63554,63552,N,63553,N,N,N,50686,50685,63681, +63682,50752,N,63821,63822,50791,N,50797,N,63913,63944,43174,N,55245,N,55246, +57426,58448,59365,49606,N,49605,61678,62276,N,63556,43175,54238,45146,45921, +57428,57427,48604,59366,48605,61105,49879,N,N,N,50806,43176,52683,54239,N,N, +45922,N,55247,55248,N,56293,N,46664,47334,N,57430,57429,57431,N,58449,58450, +48040,49117,48606,49118,N,61109,61106,61108,61107,49607,N,61679,62278,62277, +52132,45148,45147,54240,N,55249,N,N,56295,56294,46665,N,57433,57434,57432,N,N, +47336,47335,N,48042,48041,N,59367,60339,60337,60338,49119,61111,61110,N,61682, +61681,61680,62279,N,63914,43177,44403,N,44404,45149,45150,54242,54241,55250,N, +45928,45926,45923,45927,45925,45924,N,N,46666,56298,N,47341,46668,46673,56300, +46675,46674,46677,56299,56296,46671,46667,46669,56297,46676,46672,46670,47343, +47342,47340,47344,N,47338,47339,N,47337,N,57435,N,N,58452,N,48044,48045,48043, +N,58451,N,58453,N,59370,59372,N,48615,59373,48608,59369,48607,48617,48613, +48614,48610,59368,48609,59374,59371,N,48616,N,48611,48612,60341,N,60343,60342, +N,60344,49120,60340,N,N,49611,61112,49608,49612,49610,49609,61683,61686,N, +61685,N,61684,49880,62280,62281,50136,62282,50137,N,N,50362,N,50361,63058,N,N, +50498,63059,63324,50603,50604,N,63557,N,50754,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43178,N,45930,45929,57436,57437,N,48046, +60345,48618,60346,61113,43179,N,53426,44406,44405,N,54243,45151,54244,55253,N, +55252,N,55251,N,N,56302,46680,N,N,56301,46679,N,N,N,56303,46678,N,57439,57442, +57440,57441,57445,57438,57446,57443,57444,48048,58454,N,N,48047,N,59378,59376, +N,N,48619,59375,59377,N,48620,N,60347,N,60348,49613,N,62284,62286,62283,62285, +62678,63060,N,N,63855,43180,44407,54245,54247,54246,N,55256,45932,N,55254,N, +45931,55257,N,55258,55255,N,N,56315,46688,56307,56313,N,N,46683,46686,56306, +46681,56310,57452,46685,N,56305,N,56311,56308,56314,56304,56312,46684,46687, +56309,46682,N,47346,57448,47345,57455,57454,47352,N,47353,57456,47347,57453, +47351,57458,57449,N,57451,47348,57447,57450,57457,47349,57459,N,N,N,N,N,47350, +N,48049,58459,58465,58457,58466,N,58456,58461,58467,58464,58463,58462,N,58455, +58460,N,N,58458,N,48625,48622,59387,59457,59459,59456,59384,59386,59461,59458, +59388,59462,59385,59460,48623,48629,48627,59379,48628,48624,59380,59382,59381, +59389,59390,N,48626,N,48621,N,N,59383,N,60358,49122,N,60349,49123,49126,60354, +N,60351,49125,N,N,60355,60356,60350,60359,60352,60357,49124,N,49121,60353,N, +61119,49616,49614,49617,49615,61118,61115,61114,N,61117,N,N,61116,61765,49886, +61691,61690,N,49881,61761,61760,61687,61763,61692,49885,61689,61762,61688, +49882,49884,61693,49883,61694,N,61764,62290,N,50142,62287,N,62291,N,N,50139, +62289,50144,N,50141,N,62288,N,50143,62292,50138,N,N,N,N,50364,50366,N,62681, +50365,62679,50140,62680,50363,50499,50501,63062,50500,63061,N,63329,50605, +63328,50606,63326,63325,63330,63331,63558,N,63327,N,N,63686,63683,63684,63685, +50780,N,63825,63824,63823,63856,N,63934,63915,50798,43181,45152,N,N,N,N,N, +47354,N,N,N,N,N,N,N,48630,N,N,60360,N,N,49887,N,62293,N,N,N,N,N,N,63916,43182, +43758,44409,44408,N,45155,N,54248,45153,54249,45154,N,N,55263,55259,N,N,45933, +55262,55261,55260,45934,55264,55265,N,N,N,56387,56385,56389,56390,56396,N, +56392,56394,N,56386,56316,N,56393,N,N,56395,56388,56391,56317,46690,56384, +56318,46689,46691,N,47357,57461,57463,57462,57467,47355,N,57464,57460,57465, +57466,47356,47358,57468,N,58471,58470,N,58468,58469,48051,48053,48050,48052, +59469,59470,59465,N,59466,48632,48637,48631,48638,48633,59467,N,N,59468,59464, +48704,48635,N,N,48634,48636,N,59463,N,60362,49128,N,N,60364,49130,60367,60363, +60361,60366,49129,60365,N,49127,N,N,49619,49622,61121,N,49620,61120,49618, +49621,61766,61767,61768,49888,N,61769,N,49889,50146,62296,62297,62295,62294, +62298,50145,62685,62683,62684,62686,62682,62687,63064,N,63065,63063,50502, +63332,50607,63333,63560,63559,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,43183,46692,N,N, +47424,N,N,N,48054,N,N,49132,N,49131,N,N,N,N,50147,50300,50503,43184,45156, +47425,N,62299,N,N,N,N,N,N,N,N,N,N,52134,N,N,43185,N,43188,43187,43186,N,N, +52133,N,52685,N,52687,43759,N,N,43761,52684,52686,43760,52689,52688,52690,N,N, +N,N,N,N,N,N,53430,53428,44412,53427,44451,44414,44411,N,44452,N,44413,44450,N, +44449,53429,N,44410,N,N,N,45162,54251,54257,45159,45166,N,45161,54254,54256, +45164,54250,54253,45160,45157,54252,45163,54255,45165,45158,N,N,N,N,55267, +55270,45936,N,45946,45942,55268,N,N,45950,45943,45948,45938,N,45935,45937, +45949,55269,45941,45944,45940,45945,55271,45947,45939,55266,N,N,N,N,N,N,N,N, +56397,46693,56399,N,46695,46697,N,56398,46694,46698,N,46696,N,N,N,47431,57507, +47439,57470,N,47440,47429,N,57505,N,N,47434,N,57506,47427,47426,N,47437,47436, +47435,47433,47438,57469,47428,47430,47432,N,N,48056,48059,N,48063,48057,48062, +48060,N,48055,N,48061,48058,N,N,N,59474,48707,48705,N,59475,N,48708,48706, +59473,59472,N,49136,59471,49134,49133,60368,48709,49135,60369,49138,60370, +49137,49624,61123,49623,49628,49626,49627,49891,49625,61122,60371,49890,49892, +N,50148,50149,N,62688,N,50654,50653,43190,N,N,51797,45167,N,51794,51795,51793, +N,51796,N,N,52138,52135,52140,52136,43191,43194,N,52137,43193,52139,N,N,43192, +N,N,N,N,52693,52695,43764,52691,52694,52692,43762,43765,N,43763,N,N,N,N,53432, +53436,53433,N,44455,N,44456,N,53435,N,53437,53439,N,44453,53438,N,N,44454,N,N, +N,N,N,55278,53434,54258,54267,54265,54260,54261,54266,54268,45169,N,54263, +54259,45168,45170,54262,54269,54264,N,N,45985,55281,55273,55279,55280,45986,N, +55272,55274,53431,55276,55277,55275,46700,N,N,N,56406,60372,56407,56404,45987, +46702,56403,56409,56408,46699,56412,56402,56411,56400,56410,56405,46701,N, +57514,N,57509,57515,57510,57508,57511,47441,N,57513,N,57512,47442,48065,48064, +58478,58481,58473,58477,48066,58476,58474,58480,58475,58472,58479,N,59481, +48712,61770,59478,59479,59477,56401,48711,59482,59476,48710,48713,59480,60373, +49139,60374,60375,N,61124,49629,61771,61772,N,N,61773,62301,62300,62690,N, +62689,63067,63068,63066,63334,50608,43195,44458,44457,45173,45172,54336,54337, +54270,N,45171,55285,N,55286,55282,45988,55283,N,55284,N,N,N,N,56415,56417, +56413,56416,46703,56414,46704,N,N,56691,47445,47444,N,47443,N,57516,57517,N,N, +58483,58485,48070,48067,N,48069,48068,58484,58482,N,N,N,N,N,59489,59486,59487, +48717,59488,59483,59484,48714,N,48715,59485,48716,N,60379,N,60380,60377,60378, +49140,60376,N,N,N,N,N,61128,61125,61127,49632,61131,49631,61129,61132,61130, +61126,49630,N,61775,N,61776,61774,N,61778,49893,49894,62303,50151,61777,62302, +50150,62693,62694,50367,62692,N,62691,N,63069,50504,N,63561,63688,63687,N, +50755,50781,63689,63857,N,50799,43196,43766,N,47446,N,50368,43197,44459,45989, +46705,49895,43767,N,53441,53440,54338,N,45176,45174,45178,54340,N,45177,45175, +N,N,N,N,54339,45992,55292,N,45991,45993,55362,45995,55294,55360,55287,45994, +55363,N,N,55289,N,55290,55288,45990,N,55361,55291,55293,N,N,N,56429,N,56428, +56426,56418,56433,56421,56431,56438,56430,46713,N,46709,56419,N,56425,46711,N, +56424,46712,46714,56427,N,46706,46707,56439,56437,N,56436,56422,N,56434,N, +46710,N,N,N,N,46708,56435,56420,56423,56432,N,N,N,N,N,58554,57527,N,57520, +57539,57548,57523,47457,N,57536,47447,47449,47461,57521,N,N,47450,47452,47462, +47451,N,N,N,N,47460,57529,N,57518,47458,57528,47454,57546,47459,57544,57532, +57542,47456,57519,57545,57540,N,57547,47448,N,N,47463,47453,N,N,57525,N,57533, +57537,N,57541,47455,57524,57522,57534,N,N,N,N,57531,57530,N,57535,57538,N, +57543,N,N,N,58488,N,48071,58532,58490,48076,48080,58541,58549,58534,48072,N, +58538,57526,N,48073,58545,58550,58542,N,58544,58553,58546,58494,58537,N,N, +48081,N,48077,58492,58539,48075,58533,48074,58547,58530,58489,48078,58552,N,N, +58491,58543,58540,58535,58487,58486,58529,58548,48079,58551,58493,58531,48722, +N,N,N,N,N,48730,48725,59556,59553,59495,48720,N,N,N,48719,48726,N,N,N,59493, +48724,59505,59491,59492,48718,59555,48728,59508,59513,59507,60398,59503,59511, +59509,59496,59490,59517,48727,59518,N,59512,N,59501,59499,59494,N,N,N,59502, +59515,59498,59514,59554,N,N,48723,N,59510,59516,59506,59500,48721,N,N,N,58536, +59504,48729,59497,N,N,N,N,N,60404,49143,60403,60400,60484,49147,N,60481,60408, +60483,60393,60406,N,49149,N,60385,N,60383,60482,N,60480,60414,60397,60396, +60386,49216,N,60392,60402,60413,49219,60485,N,49640,49221,49150,60390,N,60399, +60382,60384,49141,49218,49146,60391,60407,60401,49217,60381,49635,60409,60412, +49148,N,60395,49220,49145,N,N,N,49144,60405,60411,49142,N,60388,60410,N,N, +60389,N,N,N,N,N,N,N,N,N,60394,61138,N,61143,49637,49639,61149,49633,61164, +61155,61144,61145,61154,N,49646,61153,61137,61152,61140,61165,49645,49643, +61141,N,61160,N,61146,61159,N,61161,61136,49638,N,61162,N,N,61150,N,49642, +61147,N,N,49644,61156,N,N,N,49636,61142,61157,N,61151,60387,61158,61139,N, +49641,N,61163,N,49634,61134,N,N,N,N,61792,61785,49897,N,61780,61795,61787, +61148,N,61797,61781,N,49896,61791,49898,49906,49904,61793,49905,61783,N,61784, +61789,61794,N,61133,49899,61802,61799,61803,61790,61786,61800,62314,61788,N, +49902,N,49901,61135,49903,61796,61798,49900,61801,61779,N,61782,N,N,N,N,N,N,N, +N,62323,N,62307,50155,62321,N,N,62305,50156,N,62316,N,62312,50161,62322,62306, +62309,50153,62324,N,62317,62320,50159,50164,50162,62313,62308,N,50157,50158, +62304,50154,N,50152,50160,62319,50163,N,62315,62325,50165,N,N,N,62311,N,62318, +N,N,N,N,N,N,62707,62786,62709,62716,62310,62714,62697,62784,50371,62701,62718, +62708,N,N,50370,N,N,62788,62710,N,62715,62717,62695,62785,62706,62711,62699, +62703,62787,62713,62696,62700,62702,62712,N,50369,62705,N,N,N,N,N,N,62698,N,N, +N,N,N,N,N,62704,63073,63078,50511,63080,N,50505,N,63076,63082,50510,50506,N, +50507,63072,63079,50509,63077,50508,63071,63075,63074,N,63070,63081,N,N,N, +50609,63341,63344,63340,63342,63343,63337,63338,63335,N,N,63339,63336,50610, +50611,N,N,63563,N,63565,N,N,N,N,N,63564,63566,N,50656,N,63562,50655,50657,N,N, +N,63691,63692,50756,63690,N,63827,63826,63828,50783,63829,50782,63830,63858, +63861,63860,50792,63859,N,N,N,50802,50800,50801,50807,63936,63937,63935,63945, +43768,N,N,55364,56440,59557,62326,N,N,43769,N,44460,45179,N,N,55365,N,55366, +45996,N,46717,56442,56441,46755,46716,56443,46718,46754,46753,46715,N,N,N, +47464,N,N,57552,57550,N,57551,57549,N,48082,N,48085,48087,48086,N,N,48083, +48084,N,59559,59558,48731,59560,N,59561,48732,N,N,N,60493,60491,61171,N,60489, +60490,49222,60486,60494,60488,60492,61167,N,N,61169,N,61170,49651,61166,49650, +61168,49647,49648,49649,60487,N,N,49909,61806,61804,61805,49907,49910,49908,N, +N,N,62327,62328,50166,N,62789,62791,62790,50372,50512,63085,63084,63083,43770, +N,51626,N,51800,42729,51798,51801,51799,N,N,N,52142,N,43201,N,43202,52144, +43199,52143,52141,43200,43198,N,N,N,N,N,N,52696,52699,43773,52698,52697,N, +43772,43771,N,43840,52700,43774,N,N,N,N,N,53446,44462,44463,44464,53447,53443, +44461,53444,N,53445,53442,N,N,N,45220,N,N,45217,54341,45218,45221,54342,N, +45182,45180,45181,45219,N,N,N,N,N,45997,55369,46005,55368,N,55371,46001,55370, +46763,45999,46002,45998,46003,46004,46000,N,N,N,55367,46759,56445,N,56483,N,N, +56482,46764,46760,46761,56444,56446,56481,46756,46758,N,46762,46757,N,N,57555, +57553,57554,47466,47467,N,57556,47465,48088,N,48090,48089,N,58555,N,N,58556, +59563,N,59562,N,N,49223,49224,60495,49225,N,61174,N,61172,N,61173,49652,N, +61807,50167,N,N,N,49653,43841,N,45222,54343,N,N,55372,46006,46765,56484,56486, +46767,46766,46768,46769,56485,47470,47471,47469,48091,47468,57557,N,N,N,48092, +59564,60496,49226,49654,61808,61812,49913,61809,49914,49912,61813,49915,61811, +N,62329,49911,50168,N,63693,N,N,43842,46008,46007,N,N,N,N,46770,56488,56487, +46771,N,N,57561,47475,47472,57560,47474,57558,47473,N,57559,N,58557,48093,N, +59567,N,48733,59565,48734,48735,59566,48736,N,60497,N,49230,49227,49232,60499, +49228,60498,49231,N,N,49229,N,61177,61179,N,N,49655,61178,49656,61176,61175,N, +61815,61814,49916,61816,62334,50170,62333,62330,50169,62331,62332,N,62792, +62793,50373,N,50515,N,N,63086,N,N,50513,50514,63087,N,N,50612,50613,63345,N,N, +50757,63695,50759,N,63694,63696,50758,63831,N,63917,N,N,N,N,N,N,43843,N,N,N, +47476,N,58558,N,59568,49233,49234,N,43844,N,48737,50171,44465,N,N,N,49235,N, +50658,44466,55373,N,56489,N,56491,N,56490,N,57565,57562,47477,N,47478,57563, +57564,N,58560,58565,48094,58559,58561,58568,58563,58567,58564,58562,58566, +48095,N,N,59571,N,59569,48739,N,48738,59570,48740,N,N,N,N,60502,N,N,60501, +49236,60500,61180,N,61182,61249,61248,N,49657,61181,61857,49917,61821,61858, +49918,N,61819,N,61822,61820,61817,49984,61818,N,N,N,N,62369,N,N,62371,62370,N, +62794,N,62795,N,N,N,63088,N,50615,N,50614,63567,63568,50760,63697,N,50793,N, +44467,46772,58570,58569,59573,59572,N,N,49658,61251,61250,61861,61859,61862, +61860,N,N,50172,62372,62373,62374,N,63089,N,63346,N,63698,N,N,N,N,N,N,N,44468, +N,N,60503,61252,N,44469,N,N,48096,N,60504,49985,61863,50173,N,62796,62797, +50516,63569,44470,46011,46012,55374,46773,46774,56492,46775,N,47482,N,47484, +57567,57568,57566,47479,47480,47483,47481,N,N,58571,48097,48098,N,N,59580, +48743,59575,59574,N,59579,48741,N,N,49243,N,59576,59581,59578,59577,N,48742,N, +49241,N,60506,49237,N,60507,N,N,60505,N,49240,49238,49242,N,49239,N,N,N,N,N, +61253,N,61258,61254,61257,49659,N,60884,61256,61255,N,49988,49986,49989,49987, +61864,61865,61866,49990,N,N,N,62378,50240,62376,N,50241,62375,62377,50174, +62801,62798,N,62799,62800,63090,50518,N,50517,N,63348,63347,50616,N,N,N,50659, +50761,50784,63832,63918,63919,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44471,56493,N,N,57569, +58572,58573,48099,N,48100,59582,48744,N,N,49660,N,61867,N,49991,62381,50242, +62380,62382,62379,63093,62802,62803,N,50374,N,63092,N,N,63091,N,63349,63920,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,44472,N,N,N,44473,N,N,45223,54344,N,55375,N,46776,N, +46779,46777,56494,N,46781,N,46778,N,N,46780,N,47486,N,57570,N,N,57571,59584,N, +47485,47521,47522,58575,N,58574,48101,N,48102,N,58576,59583,48104,48745,N, +48103,N,N,N,49244,59585,48747,48746,59586,59589,59587,59588,48748,N,49249, +49247,N,N,49246,60509,N,49248,N,N,60508,61259,N,60510,49245,60511,61262,61260, +61261,61266,49995,61265,61268,61267,61264,61263,N,49661,N,N,N,N,61870,N,61869, +49994,49992,49993,N,61868,N,62385,N,50243,N,62384,62383,50244,N,62808,62807,N, +62805,N,62804,50376,50375,62809,63350,50617,63095,50519,63094,62806,N,63351, +50660,N,50785,63833,N,63921,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,44474,55376,61269,44475, +N,N,58578,58577,60512,N,N,61271,N,61270,N,49996,62386,62387,50377,N,N,63922, +45224,46783,46782,57572,57574,47524,57573,47523,47525,57575,N,N,N,58580,58582, +58581,N,58584,N,N,N,48105,58583,58579,N,N,N,58585,N,59596,N,59599,59601,59591, +59595,59592,48750,48753,48755,59593,59594,48754,59597,59600,59598,48756,N, +48752,59590,48749,N,48751,N,N,49251,60518,60516,60515,N,60521,N,60520,60519,N, +60514,49250,60513,N,60517,49252,N,N,61274,N,61278,61275,61277,61276,61273, +61279,61282,61280,61281,49728,49662,61272,61283,61875,61878,61880,61879,N, +61873,61877,61872,N,61874,49997,61871,N,61876,N,N,62400,62389,50245,N,N,50246, +62388,62393,62399,62391,62398,N,62395,N,62394,62397,62392,62390,N,62396,N, +62816,62814,50378,62813,62819,62817,N,50379,62812,62810,N,62811,50381,62815, +50380,62818,63096,63102,N,N,63097,50523,63137,50522,63101,63100,50521,63099, +50520,63098,N,63357,63393,63358,N,63355,50619,63352,63356,63395,N,63394,63353, +63354,50618,63570,50663,N,63571,50661,50662,N,N,63699,50762,63862,N,50794,N, +63923,50795,63924,63925,63939,63938,50810,63949,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,45225,N,N,57577,N,57576,N,48106,48107,58586,N,59602,60524,N,N, +48757,49253,60522,N,60525,49254,N,61284,60523,61881,49998,62401,N,N,N,62822, +62820,N,N,62821,N,N,63138,N,50524,63396,50666,50620,50664,50665,63700,50786,N, +45226,N,N,N,61882,N,N,54345,N,47526,N,58587,N,N,48108,58588,N,N,N,59604,59603, +49256,48758,48759,N,59607,59606,59605,N,N,60526,60529,N,60528,60527,49255, +61288,61286,61285,61287,N,49999,61884,61885,50000,N,61883,N,62403,62402,62405, +50247,62404,N,62823,62825,62824,N,N,63139,63142,63140,63141,63397,50621,N,N,N, +63572,63573,63574,N,50763,50787,63926,45227,N,48760,49257,61886,N,63398,N,N, +63940,54346,N,50811,45228,60530,N,61887,N,62406,N,N,63143,63399,45229,N,58589, +58590,N,48109,48110,59609,48762,48761,59608,N,61289,N,61888,61890,61889,50003, +50002,50001,N,50526,63144,N,50525,63401,63400,N,50764,63701,46013,57578,N,N,N, +58593,58591,58592,N,N,59618,N,59613,59610,59617,N,N,N,59619,N,N,48764,59616, +59612,N,N,59611,59615,59614,48763,N,N,60541,60536,60534,60577,60535,N,60531,N, +60537,N,N,60532,61298,60533,60578,N,N,N,N,N,N,N,60540,49258,60539,60538,N, +60542,N,N,N,N,61290,61293,N,N,61292,N,61300,61295,61299,N,61297,61296,61294,N, +61291,N,49731,49730,N,49732,49729,61301,N,N,N,N,N,61896,61899,N,61897,61901,N, +N,N,61902,N,61894,50008,61895,N,61893,61900,N,61892,61891,50007,50005,50004,N, +N,N,N,N,N,N,N,61898,62415,62421,50250,62416,N,62419,62423,50251,62418,N,62410, +N,62409,62422,62413,N,62411,62420,62412,50249,50248,N,62407,62408,62417,N,N,N, +62414,N,N,N,N,N,N,62828,62831,N,N,N,N,50006,62829,62835,62833,62827,62838,N, +62826,N,50383,62834,N,N,N,62830,50382,62837,N,N,62836,N,N,N,N,63147,63146,N,N, +N,63153,N,63149,63152,50528,N,N,63150,63151,N,63145,63148,50527,N,N,N,50623, +63412,63407,63411,N,63414,63410,N,63406,N,50625,63409,63413,50624,63404,62832, +63408,N,N,63405,N,63402,N,63403,50622,63578,63580,63583,63579,63584,N,63577,N, +63575,N,50667,63581,50669,50668,63576,63582,N,N,N,N,63706,50765,63707,N,63705, +63702,N,N,63704,63703,63834,N,N,N,N,63836,63835,N,N,63865,N,63864,63863,63866, +N,50803,50804,63946,63950,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,46014,56495,57581,N,47527,57579,N,N,57580,N,N,N,58594,58595,48113,48111, +58596,48112,59624,N,59627,59621,59628,59620,59622,N,59623,59626,N,N,48801, +59631,59630,48765,59625,59629,48766,N,N,N,N,N,N,60588,N,49263,N,60583,49259,N, +60580,60586,60589,N,49264,N,60585,60582,60590,60581,N,60587,49260,N,60579, +49261,N,49262,60584,N,N,N,61353,61306,61307,61310,61308,N,61302,N,N,61305, +61349,61309,N,N,49733,N,61351,61348,49734,61350,61303,61346,61347,N,61345,N,N, +N,N,61906,61908,61911,N,N,61905,N,50009,61913,61904,61914,N,61910,61912,61916, +61909,61917,61907,61903,50010,N,61915,50011,50253,N,N,N,N,N,61304,62449,62440, +50255,62436,50256,N,N,62445,62439,62429,50254,62442,62437,62438,N,62424,62431, +62446,N,62443,N,62435,N,62447,62430,62425,62444,N,62427,62441,62432,62448, +62428,50252,62426,62433,62434,N,N,N,62845,N,62843,N,62882,N,62894,62885,62844, +62840,62887,62846,62883,62842,62890,62839,62881,62886,62888,62891,62841,N, +62895,62896,62889,62893,62884,N,63169,63172,N,50529,N,63171,63176,63174,50530, +63165,63155,63154,50532,63167,63168,63164,63156,N,63161,62892,N,63157,50531, +63163,N,63162,N,63158,63170,N,63159,63419,63173,63175,63166,63160,63420,63422, +63416,50626,N,63429,63427,50627,63426,63425,63418,63415,63421,63430,63417, +63423,N,63593,63598,63588,63591,50670,63595,N,63602,63424,N,63589,63599,63603, +63594,63587,63597,N,63596,63601,63600,63428,63592,63586,63590,50766,50767, +63585,N,63718,63709,63717,63714,63715,63708,63711,63719,63713,63712,63710,N, +63716,N,63837,N,63838,N,63840,63839,63842,63841,63868,63867,63927,N,63928,N, +63941,50808,50812,N,63951,50813,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,46015,N,N,N,50384,63177,N, +50768,50769,N,46016,57582,N,47528,59632,N,N,60592,60593,60591,61355,61354, +49735,61919,61356,61918,N,N,62451,50257,50259,62450,N,N,50258,N,62897,62899, +62898,63178,50533,N,50671,63720,63843,N,N,63954,46017,N,58597,N,48802,N,N,N, +60595,60594,N,61357,N,N,N,50260,50385,63431,63947,N,N,N,46018,48114,N,48803,N, +62452,N,63604,46784,N,N,N,N,61358,N,N,N,50788,46785,48804,49736,63605,46786,N, +59633,49266,60596,60597,N,49265,N,61359,49740,49738,49739,49737,61920,50012,N, +N,N,62901,62900,62903,62902,50386,N,N,63179,N,63181,63180,50534,63432,N,63606, +63607,50672,63844,63869,50805,N,56496,60598,61360,62453,57583,N,61361,61922, +61921,N,N,N,N,63608,50770,N,63845,63870,N,N,N,47529,59634,59635,N,60599,47530, +N,50013,61923,N,63183,50535,63184,63182,63609,N,63721,N,47531,N,61364,61363, +61362,61924,N,N,61928,61927,61926,61925,50014,62454,62905,50387,62904,63185, +63435,63434,50628,63433,63612,63611,63610,N,N,48115,N,60600,49741,N,62455, +62456,63436,63613,N,N,63722,63846,63929,63956,48116,49742,61929,62457,63186, +63614,N,N,48806,N,61365,61930,62458,62459,62460,62910,N,62906,50536,62909, +62908,50388,62907,50390,N,50389,63188,63187,50537,50538,N,N,50630,63437,50629, +N,63651,63652,63650,63649,50772,N,63723,63724,63725,50771,63847,63850,63849, +63848,N,N,63955,N,N,N,N,N,N,N,N,N,N,N,N,N,N,49267,N,N,50021,62911,63189,N, +50631,63438,N,N,63957,N,N,N,49268,N,N,N,61366,N,63439,N,63905,51530,56828, +41290,41303,N,41305,41307,41311,41312,41315,41316,41319,41320,41323,41324, +41327,41328,41331,41332,41335,41336,41339,41340,N,N,N,N,41414,41415,41418, +41419,41416,41417,41308,41293,N,41295,N,41297,41298,41299,41300,N,41341,41342, +41377,41378,41379,41380,41420,41421,41422,41438,41439,41440,41441,41442,N,N, +41548,41549,41550,41289,N,41389,41539,41544,41390,N,41309,41310,41391,41423, +41281,41424,41284,41537,41647,41648,41649,41650,41651,41652,41653,41654,41655, +41656,41287,41286,41429,41431,41430,41288,41545,41679,41680,41681,41682,41683, +41684,41685,41686,41687,41688,41689,41690,41691,41692,41693,41694,41695,41696, +41697,41698,41699,41700,41701,41702,41703,41704,N,41538,N,N,41412,N,41705, +41706,41707,41708,41709,41710,41711,41712,41713,41714,41715,41716,41717,41718, +41719,41720,41721,41722,41723,41724,41725,41726,41792,41793,41794,41795,41313, +41301,41314,N,N,N,N,N,N,41294,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41411, +}; + +static const struct unim_index big5_encmap[256] = { +{__big5_encmap+0,162,247},{0,0,0},{__big5_encmap+86,199,217},{__big5_encmap+ +105,145,201},{__big5_encmap+162,1,81},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{__big5_encmap+243,19,62},{__big5_encmap+287,3,153},{ +__big5_encmap+438,26,191},{0,0,0},{__big5_encmap+604,96,125},{__big5_encmap+ +634,0,229},{__big5_encmap+864,5,66},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5_encmap+926,0,254},{__big5_encmap+1181, +5,41},{__big5_encmap+1218,163,163},{__big5_encmap+1219,142,213},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__big5_encmap+1291,0,255},{ +__big5_encmap+1547,0,254},{__big5_encmap+1802,0,255},{__big5_encmap+2058,0,253 +},{__big5_encmap+2312,0,255},{__big5_encmap+2568,5,252},{__big5_encmap+2816,1, +255},{__big5_encmap+3071,1,255},{__big5_encmap+3326,0,255},{__big5_encmap+3582 +,1,253},{__big5_encmap+3835,0,255},{__big5_encmap+4091,3,255},{__big5_encmap+ +4344,0,255},{__big5_encmap+4600,1,250},{__big5_encmap+4850,1,255},{ +__big5_encmap+5105,0,255},{__big5_encmap+5361,2,255},{__big5_encmap+5615,1,255 +},{__big5_encmap+5870,0,255},{__big5_encmap+6126,0,255},{__big5_encmap+6382,0, +255},{__big5_encmap+6638,0,249},{__big5_encmap+6888,6,255},{__big5_encmap+7138 +,0,253},{__big5_encmap+7392,0,255},{__big5_encmap+7648,0,255},{__big5_encmap+ +7904,18,253},{__big5_encmap+8140,4,255},{__big5_encmap+8392,0,252},{ +__big5_encmap+8645,0,255},{__big5_encmap+8901,0,249},{__big5_encmap+9151,0,253 +},{__big5_encmap+9405,0,255},{__big5_encmap+9661,0,255},{__big5_encmap+9917,0, +255},{__big5_encmap+10173,0,255},{__big5_encmap+10429,1,255},{__big5_encmap+ +10684,0,255},{__big5_encmap+10940,0,255},{__big5_encmap+11196,0,255},{ +__big5_encmap+11452,0,254},{__big5_encmap+11707,1,253},{__big5_encmap+11960,2, +255},{__big5_encmap+12214,1,251},{__big5_encmap+12465,0,255},{__big5_encmap+ +12721,0,255},{__big5_encmap+12977,0,254},{__big5_encmap+13232,0,251},{ +__big5_encmap+13484,3,156},{__big5_encmap+13638,54,255},{__big5_encmap+13840, +0,254},{__big5_encmap+14095,0,255},{__big5_encmap+14351,0,254},{__big5_encmap+ +14606,0,255},{__big5_encmap+14862,1,255},{__big5_encmap+15117,0,255},{ +__big5_encmap+15373,0,254},{__big5_encmap+15628,0,255},{__big5_encmap+15884,0, +254},{__big5_encmap+16139,1,255},{__big5_encmap+16394,0,255},{__big5_encmap+ +16650,0,159},{__big5_encmap+16810,55,254},{__big5_encmap+17010,0,255},{ +__big5_encmap+17266,0,255},{__big5_encmap+17522,0,255},{__big5_encmap+17778,0, +255},{__big5_encmap+18034,0,255},{__big5_encmap+18290,0,255},{__big5_encmap+ +18546,0,255},{__big5_encmap+18802,0,131},{__big5_encmap+18934,119,229},{ +__big5_encmap+19045,28,255},{__big5_encmap+19273,0,255},{__big5_encmap+19529, +0,254},{__big5_encmap+19784,0,255},{__big5_encmap+20040,1,254},{__big5_encmap+ +20294,1,253},{__big5_encmap+20547,5,255},{__big5_encmap+20798,0,255},{ +__big5_encmap+21054,0,255},{__big5_encmap+21310,0,164},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{__big5_encmap+21475,12,13},{0,0,0},{0,0,0},{0,0,0},{__big5_encmap+21477,48, +107},{__big5_encmap+21537,1,227}, +}; + +static const ucs2_t __cp950ext_decmap[224] = { +8231,U,U,U,U,U,U,U,U,65105,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,U,U,U,U,U,175,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U, +U,U,U,U,U,U,U,65374,U,U,U,U,U,U,U,U,U,U,U,U,U,U,8853,8857,8725,65128,U,65509, +U,65504,65505,8364,30849,37561,35023,22715,24658,31911,23290,9556,9574,9559, +9568,9580,9571,9562,9577,9565,9554,9572,9557,9566,9578,9569,9560,9575,9563, +9555,9573,9558,9567,9579,9570,9561,9576,9564,9553,9552,9581,9582,9584,9583, +9619, +}; + +static const struct dbcs_index cp950ext_decmap[256] = { +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_decmap+0,69,243 +},{__cp950ext_decmap+175,65,71},{__cp950ext_decmap+182,225,225},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_decmap+183,214,254 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +}; + +static const DBCHAR __cp950ext_encmap[581] = { +41410,41285,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41953,41537,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +41458,N,N,N,41459,63992,63974,63983,63965,63976,63985,63967,63980,63989,63971, +63982,63991,63973,N,63986,63968,N,63988,63970,63975,63984,63966,63981,63990, +63972,N,63987,63969,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,63998,63961,63964,63962,63958,63963,63960,63959,41294,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41538,41470,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41536,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,41443,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N, +N,N,N,41542,41543,N,N,N,41540, +}; + +static const struct unim_index cp950ext_encmap[256] = { +{__cp950ext_encmap+0,175,175},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0}, +{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+1,39,172},{0, +0,0},{__cp950ext_encmap+135,21,153},{0,0,0},{0,0,0},{__cp950ext_encmap+268,81, +147},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{__cp950ext_encmap+335,187,187},{0,0,0},{__cp950ext_encmap+ +336,250,250},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+337, +82,82},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+338,129,129},{0,0,0},{ +0,0,0},{0,0,0},{__cp950ext_encmap+339,167,167},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+ +340,207,207},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{__cp950ext_encmap+341,185,185},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{ +0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0 +},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0, +0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{0,0,0},{__cp950ext_encmap+342,81,104},{ +__cp950ext_encmap+366,15,229}, +}; diff --git a/sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.c b/sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.c new file mode 100644 index 000000000..7c6b98935 --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.c @@ -0,0 +1,1793 @@ +/* + * multibytecodec.c: Common Multibyte Codec Implementation + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" +#include "multibytecodec.h" + +typedef struct { + const Py_UNICODE *inbuf, *inbuf_top, *inbuf_end; + unsigned char *outbuf, *outbuf_end; + PyObject *excobj, *outobj; +} MultibyteEncodeBuffer; + +typedef struct { + const unsigned char *inbuf, *inbuf_top, *inbuf_end; + Py_UNICODE *outbuf, *outbuf_end; + PyObject *excobj, *outobj; +} MultibyteDecodeBuffer; + +PyDoc_STRVAR(MultibyteCodec_Encode__doc__, +"I.encode(unicode[, errors]) -> (string, length consumed)\n\ +\n\ +Return an encoded string version of `unicode'. errors may be given to\n\ +set a different error handling scheme. Default is 'strict' meaning that\n\ +encoding errors raise a UnicodeEncodeError. Other possible values are\n\ +'ignore', 'replace' and 'xmlcharrefreplace' as well as any other name\n\ +registered with codecs.register_error that can handle UnicodeEncodeErrors."); + +PyDoc_STRVAR(MultibyteCodec_Decode__doc__, +"I.decode(string[, errors]) -> (unicodeobject, length consumed)\n\ +\n\ +Decodes `string' using I, an MultibyteCodec instance. errors may be given\n\ +to set a different error handling scheme. Default is 'strict' meaning\n\ +that encoding errors raise a UnicodeDecodeError. Other possible values\n\ +are 'ignore' and 'replace' as well as any other name registerd with\n\ +codecs.register_error that is able to handle UnicodeDecodeErrors."); + +static char *codeckwarglist[] = {"input", "errors", NULL}; +static char *incnewkwarglist[] = {"errors", NULL}; +static char *incrementalkwarglist[] = {"input", "final", NULL}; +static char *streamkwarglist[] = {"stream", "errors", NULL}; + +static PyObject *multibytecodec_encode(MultibyteCodec *, + MultibyteCodec_State *, const Py_UNICODE **, Py_ssize_t, + PyObject *, int); + +#define MBENC_RESET MBENC_MAX<<1 /* reset after an encoding session */ + +static PyObject * +make_tuple(PyObject *object, Py_ssize_t len) +{ + PyObject *v, *w; + + if (object == NULL) + return NULL; + + v = PyTuple_New(2); + if (v == NULL) { + Py_DECREF(object); + return NULL; + } + PyTuple_SET_ITEM(v, 0, object); + + w = PyInt_FromSsize_t(len); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyTuple_SET_ITEM(v, 1, w); + + return v; +} + +static PyObject * +internal_error_callback(const char *errors) +{ + if (errors == NULL || strcmp(errors, "strict") == 0) + return ERROR_STRICT; + else if (strcmp(errors, "ignore") == 0) + return ERROR_IGNORE; + else if (strcmp(errors, "replace") == 0) + return ERROR_REPLACE; + else + return PyString_FromString(errors); +} + +static PyObject * +call_error_callback(PyObject *errors, PyObject *exc) +{ + PyObject *args, *cb, *r; + + assert(PyString_Check(errors)); + cb = PyCodec_LookupError(PyString_AS_STRING(errors)); + if (cb == NULL) + return NULL; + + args = PyTuple_New(1); + if (args == NULL) { + Py_DECREF(cb); + return NULL; + } + + PyTuple_SET_ITEM(args, 0, exc); + Py_INCREF(exc); + + r = PyObject_CallObject(cb, args); + Py_DECREF(args); + Py_DECREF(cb); + return r; +} + +static PyObject * +codecctx_errors_get(MultibyteStatefulCodecContext *self) +{ + const char *errors; + + if (self->errors == ERROR_STRICT) + errors = "strict"; + else if (self->errors == ERROR_IGNORE) + errors = "ignore"; + else if (self->errors == ERROR_REPLACE) + errors = "replace"; + else { + Py_INCREF(self->errors); + return self->errors; + } + + return PyString_FromString(errors); +} + +static int +codecctx_errors_set(MultibyteStatefulCodecContext *self, PyObject *value, + void *closure) +{ + PyObject *cb; + + if (!PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, "errors must be a string"); + return -1; + } + + cb = internal_error_callback(PyString_AS_STRING(value)); + if (cb == NULL) + return -1; + + ERROR_DECREF(self->errors); + self->errors = cb; + return 0; +} + +/* This getset handlers list is used by all the stateful codec objects */ +static PyGetSetDef codecctx_getsets[] = { + {"errors", (getter)codecctx_errors_get, + (setter)codecctx_errors_set, + PyDoc_STR("how to treat errors")}, + {NULL,} +}; + +static int +expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize) +{ + Py_ssize_t orgpos, orgsize; + + orgpos = (Py_ssize_t)((char *)buf->outbuf - + PyString_AS_STRING(buf->outobj)); + orgsize = PyString_GET_SIZE(buf->outobj); + if (_PyString_Resize(&buf->outobj, orgsize + ( + esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize)) == -1) + return -1; + + buf->outbuf = (unsigned char *)PyString_AS_STRING(buf->outobj) +orgpos; + buf->outbuf_end = (unsigned char *)PyString_AS_STRING(buf->outobj) + + PyString_GET_SIZE(buf->outobj); + + return 0; +} +#define REQUIRE_ENCODEBUFFER(buf, s) { \ + if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ + if (expand_encodebuffer(buf, s) == -1) \ + goto errorexit; \ +} + +static int +expand_decodebuffer(MultibyteDecodeBuffer *buf, Py_ssize_t esize) +{ + Py_ssize_t orgpos, orgsize; + + orgpos = (Py_ssize_t)(buf->outbuf - PyUnicode_AS_UNICODE(buf->outobj)); + orgsize = PyUnicode_GET_SIZE(buf->outobj); + if (PyUnicode_Resize(&buf->outobj, orgsize + ( + esize < (orgsize >> 1) ? (orgsize >> 1) | 1 : esize)) == -1) + return -1; + + buf->outbuf = PyUnicode_AS_UNICODE(buf->outobj) + orgpos; + buf->outbuf_end = PyUnicode_AS_UNICODE(buf->outobj) + + PyUnicode_GET_SIZE(buf->outobj); + + return 0; +} +#define REQUIRE_DECODEBUFFER(buf, s) { \ + if ((s) < 1 || (buf)->outbuf + (s) > (buf)->outbuf_end) \ + if (expand_decodebuffer(buf, s) == -1) \ + goto errorexit; \ +} + + +/** + * MultibyteCodec object + */ + +static int +multibytecodec_encerror(MultibyteCodec *codec, + MultibyteCodec_State *state, + MultibyteEncodeBuffer *buf, + PyObject *errors, Py_ssize_t e) +{ + PyObject *retobj = NULL, *retstr = NULL, *tobj; + Py_ssize_t retstrsize, newpos; + Py_ssize_t esize, start, end; + const char *reason; + + if (e > 0) { + reason = "illegal multibyte sequence"; + esize = e; + } + else { + switch (e) { + case MBERR_TOOSMALL: + REQUIRE_ENCODEBUFFER(buf, -1); + return 0; /* retry it */ + case MBERR_TOOFEW: + reason = "incomplete multibyte sequence"; + esize = (Py_ssize_t)(buf->inbuf_end - buf->inbuf); + break; + case MBERR_INTERNAL: + PyErr_SetString(PyExc_RuntimeError, + "internal codec error"); + return -1; + default: + PyErr_SetString(PyExc_RuntimeError, + "unknown runtime error"); + return -1; + } + } + + if (errors == ERROR_REPLACE) { + const Py_UNICODE replchar = '?', *inbuf = &replchar; + Py_ssize_t r; + + for (;;) { + Py_ssize_t outleft; + + outleft = (Py_ssize_t)(buf->outbuf_end - buf->outbuf); + r = codec->encode(state, codec->config, &inbuf, 1, + &buf->outbuf, outleft, 0); + if (r == MBERR_TOOSMALL) { + REQUIRE_ENCODEBUFFER(buf, -1); + continue; + } + else + break; + } + + if (r != 0) { + REQUIRE_ENCODEBUFFER(buf, 1); + *buf->outbuf++ = '?'; + } + } + if (errors == ERROR_IGNORE || errors == ERROR_REPLACE) { + buf->inbuf += esize; + return 0; + } + + start = (Py_ssize_t)(buf->inbuf - buf->inbuf_top); + end = start + esize; + + /* use cached exception object if available */ + if (buf->excobj == NULL) { + buf->excobj = PyUnicodeEncodeError_Create(codec->encoding, + buf->inbuf_top, + buf->inbuf_end - buf->inbuf_top, + start, end, reason); + if (buf->excobj == NULL) + goto errorexit; + } + else + if (PyUnicodeEncodeError_SetStart(buf->excobj, start) != 0 || + PyUnicodeEncodeError_SetEnd(buf->excobj, end) != 0 || + PyUnicodeEncodeError_SetReason(buf->excobj, reason) != 0) + goto errorexit; + + if (errors == ERROR_STRICT) { + PyCodec_StrictErrors(buf->excobj); + goto errorexit; + } + + retobj = call_error_callback(errors, buf->excobj); + if (retobj == NULL) + goto errorexit; + + if (!PyTuple_Check(retobj) || PyTuple_GET_SIZE(retobj) != 2 || + !PyUnicode_Check((tobj = PyTuple_GET_ITEM(retobj, 0))) || + !(PyInt_Check(PyTuple_GET_ITEM(retobj, 1)) || + PyLong_Check(PyTuple_GET_ITEM(retobj, 1)))) { + PyErr_SetString(PyExc_TypeError, + "encoding error handler must return " + "(unicode, int) tuple"); + goto errorexit; + } + + { + const Py_UNICODE *uraw = PyUnicode_AS_UNICODE(tobj); + + retstr = multibytecodec_encode(codec, state, &uraw, + PyUnicode_GET_SIZE(tobj), ERROR_STRICT, + MBENC_FLUSH); + if (retstr == NULL) + goto errorexit; + } + + retstrsize = PyString_GET_SIZE(retstr); + REQUIRE_ENCODEBUFFER(buf, retstrsize); + + memcpy(buf->outbuf, PyString_AS_STRING(retstr), retstrsize); + buf->outbuf += retstrsize; + + newpos = PyInt_AsSsize_t(PyTuple_GET_ITEM(retobj, 1)); + if (newpos < 0 && !PyErr_Occurred()) + newpos += (Py_ssize_t)(buf->inbuf_end - buf->inbuf_top); + if (newpos < 0 || buf->inbuf_top + newpos > buf->inbuf_end) { + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, + "position %zd from error handler out of bounds", + newpos); + goto errorexit; + } + buf->inbuf = buf->inbuf_top + newpos; + + Py_DECREF(retobj); + Py_DECREF(retstr); + return 0; + +errorexit: + Py_XDECREF(retobj); + Py_XDECREF(retstr); + return -1; +} + +static int +multibytecodec_decerror(MultibyteCodec *codec, + MultibyteCodec_State *state, + MultibyteDecodeBuffer *buf, + PyObject *errors, Py_ssize_t e) +{ + PyObject *retobj = NULL, *retuni = NULL; + Py_ssize_t retunisize, newpos; + const char *reason; + Py_ssize_t esize, start, end; + + if (e > 0) { + reason = "illegal multibyte sequence"; + esize = e; + } + else { + switch (e) { + case MBERR_TOOSMALL: + REQUIRE_DECODEBUFFER(buf, -1); + return 0; /* retry it */ + case MBERR_TOOFEW: + reason = "incomplete multibyte sequence"; + esize = (Py_ssize_t)(buf->inbuf_end - buf->inbuf); + break; + case MBERR_INTERNAL: + PyErr_SetString(PyExc_RuntimeError, + "internal codec error"); + return -1; + default: + PyErr_SetString(PyExc_RuntimeError, + "unknown runtime error"); + return -1; + } + } + + if (errors == ERROR_REPLACE) { + REQUIRE_DECODEBUFFER(buf, 1); + *buf->outbuf++ = Py_UNICODE_REPLACEMENT_CHARACTER; + } + if (errors == ERROR_IGNORE || errors == ERROR_REPLACE) { + buf->inbuf += esize; + return 0; + } + + start = (Py_ssize_t)(buf->inbuf - buf->inbuf_top); + end = start + esize; + + /* use cached exception object if available */ + if (buf->excobj == NULL) { + buf->excobj = PyUnicodeDecodeError_Create(codec->encoding, + (const char *)buf->inbuf_top, + (Py_ssize_t)(buf->inbuf_end - buf->inbuf_top), + start, end, reason); + if (buf->excobj == NULL) + goto errorexit; + } + else + if (PyUnicodeDecodeError_SetStart(buf->excobj, start) || + PyUnicodeDecodeError_SetEnd(buf->excobj, end) || + PyUnicodeDecodeError_SetReason(buf->excobj, reason)) + goto errorexit; + + if (errors == ERROR_STRICT) { + PyCodec_StrictErrors(buf->excobj); + goto errorexit; + } + + retobj = call_error_callback(errors, buf->excobj); + if (retobj == NULL) + goto errorexit; + + if (!PyTuple_Check(retobj) || PyTuple_GET_SIZE(retobj) != 2 || + !PyUnicode_Check((retuni = PyTuple_GET_ITEM(retobj, 0))) || + !(PyInt_Check(PyTuple_GET_ITEM(retobj, 1)) || + PyLong_Check(PyTuple_GET_ITEM(retobj, 1)))) { + PyErr_SetString(PyExc_TypeError, + "decoding error handler must return " + "(unicode, int) tuple"); + goto errorexit; + } + + retunisize = PyUnicode_GET_SIZE(retuni); + if (retunisize > 0) { + REQUIRE_DECODEBUFFER(buf, retunisize); + memcpy((char *)buf->outbuf, PyUnicode_AS_DATA(retuni), + retunisize * Py_UNICODE_SIZE); + buf->outbuf += retunisize; + } + + newpos = PyInt_AsSsize_t(PyTuple_GET_ITEM(retobj, 1)); + if (newpos < 0 && !PyErr_Occurred()) + newpos += (Py_ssize_t)(buf->inbuf_end - buf->inbuf_top); + if (newpos < 0 || buf->inbuf_top + newpos > buf->inbuf_end) { + PyErr_Clear(); + PyErr_Format(PyExc_IndexError, + "position %zd from error handler out of bounds", + newpos); + goto errorexit; + } + buf->inbuf = buf->inbuf_top + newpos; + Py_DECREF(retobj); + return 0; + +errorexit: + Py_XDECREF(retobj); + return -1; +} + +static PyObject * +multibytecodec_encode(MultibyteCodec *codec, + MultibyteCodec_State *state, + const Py_UNICODE **data, Py_ssize_t datalen, + PyObject *errors, int flags) +{ + MultibyteEncodeBuffer buf; + Py_ssize_t finalsize, r = 0; + + if (datalen == 0) + return PyString_FromString(""); + + buf.excobj = NULL; + buf.inbuf = buf.inbuf_top = *data; + buf.inbuf_end = buf.inbuf_top + datalen; + buf.outobj = PyString_FromStringAndSize(NULL, datalen * 2 + 16); + if (buf.outobj == NULL) + goto errorexit; + buf.outbuf = (unsigned char *)PyString_AS_STRING(buf.outobj); + buf.outbuf_end = buf.outbuf + PyString_GET_SIZE(buf.outobj); + + while (buf.inbuf < buf.inbuf_end) { + Py_ssize_t inleft, outleft; + + /* we don't reuse inleft and outleft here. + * error callbacks can relocate the cursor anywhere on buffer*/ + inleft = (Py_ssize_t)(buf.inbuf_end - buf.inbuf); + outleft = (Py_ssize_t)(buf.outbuf_end - buf.outbuf); + r = codec->encode(state, codec->config, &buf.inbuf, inleft, + &buf.outbuf, outleft, flags); + *data = buf.inbuf; + if ((r == 0) || (r == MBERR_TOOFEW && !(flags & MBENC_FLUSH))) + break; + else if (multibytecodec_encerror(codec, state, &buf, errors,r)) + goto errorexit; + else if (r == MBERR_TOOFEW) + break; + } + + if (codec->encreset != NULL) + for (;;) { + Py_ssize_t outleft; + + outleft = (Py_ssize_t)(buf.outbuf_end - buf.outbuf); + r = codec->encreset(state, codec->config, &buf.outbuf, + outleft); + if (r == 0) + break; + else if (multibytecodec_encerror(codec, state, + &buf, errors, r)) + goto errorexit; + } + + finalsize = (Py_ssize_t)((char *)buf.outbuf - + PyString_AS_STRING(buf.outobj)); + + if (finalsize != PyString_GET_SIZE(buf.outobj)) + if (_PyString_Resize(&buf.outobj, finalsize) == -1) + goto errorexit; + + Py_XDECREF(buf.excobj); + return buf.outobj; + +errorexit: + Py_XDECREF(buf.excobj); + Py_XDECREF(buf.outobj); + return NULL; +} + +static PyObject * +MultibyteCodec_Encode(MultibyteCodecObject *self, + PyObject *args, PyObject *kwargs) +{ + MultibyteCodec_State state; + Py_UNICODE *data; + PyObject *errorcb, *r, *arg, *ucvt; + const char *errors = NULL; + Py_ssize_t datalen; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|z:encode", + codeckwarglist, &arg, &errors)) + return NULL; + + if (PyUnicode_Check(arg)) + ucvt = NULL; + else { + arg = ucvt = PyObject_Unicode(arg); + if (arg == NULL) + return NULL; + else if (!PyUnicode_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "couldn't convert the object to unicode."); + Py_DECREF(ucvt); + return NULL; + } + } + + data = PyUnicode_AS_UNICODE(arg); + datalen = PyUnicode_GET_SIZE(arg); + + errorcb = internal_error_callback(errors); + if (errorcb == NULL) { + Py_XDECREF(ucvt); + return NULL; + } + + if (self->codec->encinit != NULL && + self->codec->encinit(&state, self->codec->config) != 0) + goto errorexit; + r = multibytecodec_encode(self->codec, &state, + (const Py_UNICODE **)&data, datalen, errorcb, + MBENC_FLUSH | MBENC_RESET); + if (r == NULL) + goto errorexit; + + ERROR_DECREF(errorcb); + Py_XDECREF(ucvt); + return make_tuple(r, datalen); + +errorexit: + ERROR_DECREF(errorcb); + Py_XDECREF(ucvt); + return NULL; +} + +static PyObject * +MultibyteCodec_Decode(MultibyteCodecObject *self, + PyObject *args, PyObject *kwargs) +{ + MultibyteCodec_State state; + MultibyteDecodeBuffer buf; + PyObject *errorcb; + const char *data, *errors = NULL; + Py_ssize_t datalen, finalsize; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#|z:decode", + codeckwarglist, &data, &datalen, &errors)) + return NULL; + + errorcb = internal_error_callback(errors); + if (errorcb == NULL) + return NULL; + + if (datalen == 0) { + ERROR_DECREF(errorcb); + return make_tuple(PyUnicode_FromUnicode(NULL, 0), 0); + } + + buf.excobj = NULL; + buf.inbuf = buf.inbuf_top = (unsigned char *)data; + buf.inbuf_end = buf.inbuf_top + datalen; + buf.outobj = PyUnicode_FromUnicode(NULL, datalen); + if (buf.outobj == NULL) + goto errorexit; + buf.outbuf = PyUnicode_AS_UNICODE(buf.outobj); + buf.outbuf_end = buf.outbuf + PyUnicode_GET_SIZE(buf.outobj); + + if (self->codec->decinit != NULL && + self->codec->decinit(&state, self->codec->config) != 0) + goto errorexit; + + while (buf.inbuf < buf.inbuf_end) { + Py_ssize_t inleft, outleft, r; + + inleft = (Py_ssize_t)(buf.inbuf_end - buf.inbuf); + outleft = (Py_ssize_t)(buf.outbuf_end - buf.outbuf); + + r = self->codec->decode(&state, self->codec->config, + &buf.inbuf, inleft, &buf.outbuf, outleft); + if (r == 0) + break; + else if (multibytecodec_decerror(self->codec, &state, + &buf, errorcb, r)) + goto errorexit; + } + + finalsize = (Py_ssize_t)(buf.outbuf - + PyUnicode_AS_UNICODE(buf.outobj)); + + if (finalsize != PyUnicode_GET_SIZE(buf.outobj)) + if (PyUnicode_Resize(&buf.outobj, finalsize) == -1) + goto errorexit; + + Py_XDECREF(buf.excobj); + ERROR_DECREF(errorcb); + return make_tuple(buf.outobj, datalen); + +errorexit: + ERROR_DECREF(errorcb); + Py_XDECREF(buf.excobj); + Py_XDECREF(buf.outobj); + + return NULL; +} + +static struct PyMethodDef multibytecodec_methods[] = { + {"encode", (PyCFunction)MultibyteCodec_Encode, + METH_VARARGS | METH_KEYWORDS, + MultibyteCodec_Encode__doc__}, + {"decode", (PyCFunction)MultibyteCodec_Decode, + METH_VARARGS | METH_KEYWORDS, + MultibyteCodec_Decode__doc__}, + {NULL, NULL}, +}; + +static void +multibytecodec_dealloc(MultibyteCodecObject *self) +{ + PyObject_Del(self); +} + +static PyTypeObject MultibyteCodec_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "MultibyteCodec", /* tp_name */ + sizeof(MultibyteCodecObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)multibytecodec_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iterext */ + multibytecodec_methods, /* tp_methods */ +}; + + +/** + * Utility functions for stateful codec mechanism + */ + +#define STATEFUL_DCTX(o) ((MultibyteStatefulDecoderContext *)(o)) +#define STATEFUL_ECTX(o) ((MultibyteStatefulEncoderContext *)(o)) + +static PyObject * +encoder_encode_stateful(MultibyteStatefulEncoderContext *ctx, + PyObject *unistr, int final) +{ + PyObject *ucvt, *r = NULL; + Py_UNICODE *inbuf, *inbuf_end, *inbuf_tmp = NULL; + Py_ssize_t datalen, origpending; + + if (PyUnicode_Check(unistr)) + ucvt = NULL; + else { + unistr = ucvt = PyObject_Unicode(unistr); + if (unistr == NULL) + return NULL; + else if (!PyUnicode_Check(unistr)) { + PyErr_SetString(PyExc_TypeError, + "couldn't convert the object to unicode."); + Py_DECREF(ucvt); + return NULL; + } + } + + datalen = PyUnicode_GET_SIZE(unistr); + origpending = ctx->pendingsize; + + if (origpending > 0) { + inbuf_tmp = PyMem_New(Py_UNICODE, datalen + ctx->pendingsize); + if (inbuf_tmp == NULL) + goto errorexit; + memcpy(inbuf_tmp, ctx->pending, + Py_UNICODE_SIZE * ctx->pendingsize); + memcpy(inbuf_tmp + ctx->pendingsize, + PyUnicode_AS_UNICODE(unistr), + Py_UNICODE_SIZE * datalen); + datalen += ctx->pendingsize; + ctx->pendingsize = 0; + inbuf = inbuf_tmp; + } + else + inbuf = (Py_UNICODE *)PyUnicode_AS_UNICODE(unistr); + + inbuf_end = inbuf + datalen; + + r = multibytecodec_encode(ctx->codec, &ctx->state, + (const Py_UNICODE **)&inbuf, + datalen, ctx->errors, final ? MBENC_FLUSH : 0); + if (r == NULL) { + /* recover the original pending buffer */ + if (origpending > 0) + memcpy(ctx->pending, inbuf_tmp, + Py_UNICODE_SIZE * origpending); + ctx->pendingsize = origpending; + goto errorexit; + } + + if (inbuf < inbuf_end) { + ctx->pendingsize = (Py_ssize_t)(inbuf_end - inbuf); + if (ctx->pendingsize > MAXENCPENDING) { + /* normal codecs can't reach here */ + ctx->pendingsize = 0; + PyErr_SetString(PyExc_UnicodeError, + "pending buffer overflow"); + goto errorexit; + } + memcpy(ctx->pending, inbuf, + ctx->pendingsize * Py_UNICODE_SIZE); + } + + if (inbuf_tmp != NULL) + PyMem_Del(inbuf_tmp); + Py_XDECREF(ucvt); + return r; + +errorexit: + if (inbuf_tmp != NULL) + PyMem_Del(inbuf_tmp); + Py_XDECREF(r); + Py_XDECREF(ucvt); + return NULL; +} + +static int +decoder_append_pending(MultibyteStatefulDecoderContext *ctx, + MultibyteDecodeBuffer *buf) +{ + Py_ssize_t npendings; + + npendings = (Py_ssize_t)(buf->inbuf_end - buf->inbuf); + if (npendings + ctx->pendingsize > MAXDECPENDING) { + PyErr_SetString(PyExc_UnicodeError, "pending buffer overflow"); + return -1; + } + memcpy(ctx->pending + ctx->pendingsize, buf->inbuf, npendings); + ctx->pendingsize += npendings; + return 0; +} + +static int +decoder_prepare_buffer(MultibyteDecodeBuffer *buf, const char *data, + Py_ssize_t size) +{ + buf->inbuf = buf->inbuf_top = (const unsigned char *)data; + buf->inbuf_end = buf->inbuf_top + size; + if (buf->outobj == NULL) { /* only if outobj is not allocated yet */ + buf->outobj = PyUnicode_FromUnicode(NULL, size); + if (buf->outobj == NULL) + return -1; + buf->outbuf = PyUnicode_AS_UNICODE(buf->outobj); + buf->outbuf_end = buf->outbuf + + PyUnicode_GET_SIZE(buf->outobj); + } + + return 0; +} + +static int +decoder_feed_buffer(MultibyteStatefulDecoderContext *ctx, + MultibyteDecodeBuffer *buf) +{ + while (buf->inbuf < buf->inbuf_end) { + Py_ssize_t inleft, outleft; + Py_ssize_t r; + + inleft = (Py_ssize_t)(buf->inbuf_end - buf->inbuf); + outleft = (Py_ssize_t)(buf->outbuf_end - buf->outbuf); + + r = ctx->codec->decode(&ctx->state, ctx->codec->config, + &buf->inbuf, inleft, &buf->outbuf, outleft); + if (r == 0 || r == MBERR_TOOFEW) + break; + else if (multibytecodec_decerror(ctx->codec, &ctx->state, + buf, ctx->errors, r)) + return -1; + } + return 0; +} + + +/** + * MultibyteIncrementalEncoder object + */ + +static PyObject * +mbiencoder_encode(MultibyteIncrementalEncoderObject *self, + PyObject *args, PyObject *kwargs) +{ + PyObject *data; + int final = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:encode", + incrementalkwarglist, &data, &final)) + return NULL; + + return encoder_encode_stateful(STATEFUL_ECTX(self), data, final); +} + +static PyObject * +mbiencoder_reset(MultibyteIncrementalEncoderObject *self) +{ + if (self->codec->decreset != NULL && + self->codec->decreset(&self->state, self->codec->config) != 0) + return NULL; + self->pendingsize = 0; + + Py_RETURN_NONE; +} + +static struct PyMethodDef mbiencoder_methods[] = { + {"encode", (PyCFunction)mbiencoder_encode, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"reset", (PyCFunction)mbiencoder_reset, + METH_NOARGS, NULL}, + {NULL, NULL}, +}; + +static PyObject * +mbiencoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + MultibyteIncrementalEncoderObject *self; + PyObject *codec = NULL; + char *errors = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s:IncrementalEncoder", + incnewkwarglist, &errors)) + return NULL; + + self = (MultibyteIncrementalEncoderObject *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + codec = PyObject_GetAttrString((PyObject *)type, "codec"); + if (codec == NULL) + goto errorexit; + if (!MultibyteCodec_Check(codec)) { + PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); + goto errorexit; + } + + self->codec = ((MultibyteCodecObject *)codec)->codec; + self->pendingsize = 0; + self->errors = internal_error_callback(errors); + if (self->errors == NULL) + goto errorexit; + if (self->codec->encinit != NULL && + self->codec->encinit(&self->state, self->codec->config) != 0) + goto errorexit; + + Py_DECREF(codec); + return (PyObject *)self; + +errorexit: + Py_XDECREF(self); + Py_XDECREF(codec); + return NULL; +} + +static int +mbiencoder_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +static int +mbiencoder_traverse(MultibyteIncrementalEncoderObject *self, + visitproc visit, void *arg) +{ + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + return 0; +} + +static void +mbiencoder_dealloc(MultibyteIncrementalEncoderObject *self) +{ + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); + self->ob_type->tp_free(self); +} + +static PyTypeObject MultibyteIncrementalEncoder_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "MultibyteIncrementalEncoder", /* tp_name */ + sizeof(MultibyteIncrementalEncoderObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)mbiencoder_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)mbiencoder_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iterext */ + mbiencoder_methods, /* tp_methods */ + 0, /* tp_members */ + codecctx_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + mbiencoder_init, /* tp_init */ + 0, /* tp_alloc */ + mbiencoder_new, /* tp_new */ +}; + + +/** + * MultibyteIncrementalDecoder object + */ + +static PyObject * +mbidecoder_decode(MultibyteIncrementalDecoderObject *self, + PyObject *args, PyObject *kwargs) +{ + MultibyteDecodeBuffer buf; + char *data, *wdata; + Py_ssize_t wsize, finalsize = 0, size, origpending; + int final = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "t#|i:decode", + incrementalkwarglist, &data, &size, &final)) + return NULL; + + buf.outobj = buf.excobj = NULL; + origpending = self->pendingsize; + + if (self->pendingsize == 0) { + wsize = size; + wdata = data; + } + else { + wsize = size + self->pendingsize; + wdata = PyMem_Malloc(wsize); + if (wdata == NULL) + goto errorexit; + memcpy(wdata, self->pending, self->pendingsize); + memcpy(wdata + self->pendingsize, data, size); + self->pendingsize = 0; + } + + if (decoder_prepare_buffer(&buf, wdata, wsize) != 0) + goto errorexit; + + if (decoder_feed_buffer(STATEFUL_DCTX(self), &buf)) + goto errorexit; + + if (final && buf.inbuf < buf.inbuf_end) { + if (multibytecodec_decerror(self->codec, &self->state, + &buf, self->errors, MBERR_TOOFEW)) { + /* recover the original pending buffer */ + memcpy(self->pending, wdata, origpending); + self->pendingsize = origpending; + goto errorexit; + } + } + + if (buf.inbuf < buf.inbuf_end) { /* pending sequence still exists */ + if (decoder_append_pending(STATEFUL_DCTX(self), &buf) != 0) + goto errorexit; + } + + finalsize = (Py_ssize_t)(buf.outbuf - PyUnicode_AS_UNICODE(buf.outobj)); + if (finalsize != PyUnicode_GET_SIZE(buf.outobj)) + if (PyUnicode_Resize(&buf.outobj, finalsize) == -1) + goto errorexit; + + if (wdata != data) + PyMem_Del(wdata); + Py_XDECREF(buf.excobj); + return buf.outobj; + +errorexit: + if (wdata != NULL && wdata != data) + PyMem_Del(wdata); + Py_XDECREF(buf.excobj); + Py_XDECREF(buf.outobj); + return NULL; +} + +static PyObject * +mbidecoder_reset(MultibyteIncrementalDecoderObject *self) +{ + if (self->codec->decreset != NULL && + self->codec->decreset(&self->state, self->codec->config) != 0) + return NULL; + self->pendingsize = 0; + + Py_RETURN_NONE; +} + +static struct PyMethodDef mbidecoder_methods[] = { + {"decode", (PyCFunction)mbidecoder_decode, + METH_VARARGS | METH_KEYWORDS, NULL}, + {"reset", (PyCFunction)mbidecoder_reset, + METH_NOARGS, NULL}, + {NULL, NULL}, +}; + +static PyObject * +mbidecoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + MultibyteIncrementalDecoderObject *self; + PyObject *codec = NULL; + char *errors = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s:IncrementalDecoder", + incnewkwarglist, &errors)) + return NULL; + + self = (MultibyteIncrementalDecoderObject *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + codec = PyObject_GetAttrString((PyObject *)type, "codec"); + if (codec == NULL) + goto errorexit; + if (!MultibyteCodec_Check(codec)) { + PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); + goto errorexit; + } + + self->codec = ((MultibyteCodecObject *)codec)->codec; + self->pendingsize = 0; + self->errors = internal_error_callback(errors); + if (self->errors == NULL) + goto errorexit; + if (self->codec->decinit != NULL && + self->codec->decinit(&self->state, self->codec->config) != 0) + goto errorexit; + + Py_DECREF(codec); + return (PyObject *)self; + +errorexit: + Py_XDECREF(self); + Py_XDECREF(codec); + return NULL; +} + +static int +mbidecoder_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +static int +mbidecoder_traverse(MultibyteIncrementalDecoderObject *self, + visitproc visit, void *arg) +{ + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + return 0; +} + +static void +mbidecoder_dealloc(MultibyteIncrementalDecoderObject *self) +{ + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); + self->ob_type->tp_free(self); +} + +static PyTypeObject MultibyteIncrementalDecoder_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "MultibyteIncrementalDecoder", /* tp_name */ + sizeof(MultibyteIncrementalDecoderObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)mbidecoder_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)mbidecoder_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iterext */ + mbidecoder_methods, /* tp_methods */ + 0, /* tp_members */ + codecctx_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + mbidecoder_init, /* tp_init */ + 0, /* tp_alloc */ + mbidecoder_new, /* tp_new */ +}; + + +/** + * MultibyteStreamReader object + */ + +static PyObject * +mbstreamreader_iread(MultibyteStreamReaderObject *self, + const char *method, Py_ssize_t sizehint) +{ + MultibyteDecodeBuffer buf; + PyObject *cres; + Py_ssize_t rsize, finalsize = 0; + + if (sizehint == 0) + return PyUnicode_FromUnicode(NULL, 0); + + buf.outobj = buf.excobj = NULL; + cres = NULL; + + for (;;) { + if (sizehint < 0) + cres = PyObject_CallMethod(self->stream, + (char *)method, NULL); + else + cres = PyObject_CallMethod(self->stream, + (char *)method, "i", sizehint); + if (cres == NULL) + goto errorexit; + + if (!PyString_Check(cres)) { + PyErr_SetString(PyExc_TypeError, + "stream function returned a " + "non-string object"); + goto errorexit; + } + + if (self->pendingsize > 0) { + PyObject *ctr; + char *ctrdata; + + rsize = PyString_GET_SIZE(cres) + self->pendingsize; + ctr = PyString_FromStringAndSize(NULL, rsize); + if (ctr == NULL) + goto errorexit; + ctrdata = PyString_AS_STRING(ctr); + memcpy(ctrdata, self->pending, self->pendingsize); + memcpy(ctrdata + self->pendingsize, + PyString_AS_STRING(cres), + PyString_GET_SIZE(cres)); + Py_DECREF(cres); + cres = ctr; + self->pendingsize = 0; + } + + rsize = PyString_GET_SIZE(cres); + if (decoder_prepare_buffer(&buf, PyString_AS_STRING(cres), + rsize) != 0) + goto errorexit; + + if (rsize > 0 && decoder_feed_buffer( + (MultibyteStatefulDecoderContext *)self, &buf)) + goto errorexit; + + if (rsize == 0 || sizehint < 0) { /* end of file */ + if (buf.inbuf < buf.inbuf_end && + multibytecodec_decerror(self->codec, &self->state, + &buf, self->errors, MBERR_TOOFEW)) + goto errorexit; + } + + if (buf.inbuf < buf.inbuf_end) { /* pending sequence exists */ + if (decoder_append_pending(STATEFUL_DCTX(self), + &buf) != 0) + goto errorexit; + } + + finalsize = (Py_ssize_t)(buf.outbuf - + PyUnicode_AS_UNICODE(buf.outobj)); + Py_DECREF(cres); + cres = NULL; + + if (sizehint < 0 || finalsize != 0 || rsize == 0) + break; + + sizehint = 1; /* read 1 more byte and retry */ + } + + if (finalsize != PyUnicode_GET_SIZE(buf.outobj)) + if (PyUnicode_Resize(&buf.outobj, finalsize) == -1) + goto errorexit; + + Py_XDECREF(cres); + Py_XDECREF(buf.excobj); + return buf.outobj; + +errorexit: + Py_XDECREF(cres); + Py_XDECREF(buf.excobj); + Py_XDECREF(buf.outobj); + return NULL; +} + +static PyObject * +mbstreamreader_read(MultibyteStreamReaderObject *self, PyObject *args) +{ + PyObject *sizeobj = NULL; + Py_ssize_t size; + + if (!PyArg_UnpackTuple(args, "read", 0, 1, &sizeobj)) + return NULL; + + if (sizeobj == Py_None || sizeobj == NULL) + size = -1; + else if (PyInt_Check(sizeobj)) + size = PyInt_AsSsize_t(sizeobj); + else { + PyErr_SetString(PyExc_TypeError, "arg 1 must be an integer"); + return NULL; + } + + return mbstreamreader_iread(self, "read", size); +} + +static PyObject * +mbstreamreader_readline(MultibyteStreamReaderObject *self, PyObject *args) +{ + PyObject *sizeobj = NULL; + Py_ssize_t size; + + if (!PyArg_UnpackTuple(args, "readline", 0, 1, &sizeobj)) + return NULL; + + if (sizeobj == Py_None || sizeobj == NULL) + size = -1; + else if (PyInt_Check(sizeobj)) + size = PyInt_AsSsize_t(sizeobj); + else { + PyErr_SetString(PyExc_TypeError, "arg 1 must be an integer"); + return NULL; + } + + return mbstreamreader_iread(self, "readline", size); +} + +static PyObject * +mbstreamreader_readlines(MultibyteStreamReaderObject *self, PyObject *args) +{ + PyObject *sizehintobj = NULL, *r, *sr; + Py_ssize_t sizehint; + + if (!PyArg_UnpackTuple(args, "readlines", 0, 1, &sizehintobj)) + return NULL; + + if (sizehintobj == Py_None || sizehintobj == NULL) + sizehint = -1; + else if (PyInt_Check(sizehintobj)) + sizehint = PyInt_AsSsize_t(sizehintobj); + else { + PyErr_SetString(PyExc_TypeError, "arg 1 must be an integer"); + return NULL; + } + + r = mbstreamreader_iread(self, "read", sizehint); + if (r == NULL) + return NULL; + + sr = PyUnicode_Splitlines(r, 1); + Py_DECREF(r); + return sr; +} + +static PyObject * +mbstreamreader_reset(MultibyteStreamReaderObject *self) +{ + if (self->codec->decreset != NULL && + self->codec->decreset(&self->state, self->codec->config) != 0) + return NULL; + self->pendingsize = 0; + + Py_RETURN_NONE; +} + +static struct PyMethodDef mbstreamreader_methods[] = { + {"read", (PyCFunction)mbstreamreader_read, + METH_VARARGS, NULL}, + {"readline", (PyCFunction)mbstreamreader_readline, + METH_VARARGS, NULL}, + {"readlines", (PyCFunction)mbstreamreader_readlines, + METH_VARARGS, NULL}, + {"reset", (PyCFunction)mbstreamreader_reset, + METH_NOARGS, NULL}, + {NULL, NULL}, +}; + +static PyMemberDef mbstreamreader_members[] = { + {"stream", T_OBJECT, + offsetof(MultibyteStreamReaderObject, stream), + READONLY, NULL}, + {NULL,} +}; + +static PyObject * +mbstreamreader_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + MultibyteStreamReaderObject *self; + PyObject *stream, *codec = NULL; + char *errors = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s:StreamReader", + streamkwarglist, &stream, &errors)) + return NULL; + + self = (MultibyteStreamReaderObject *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + codec = PyObject_GetAttrString((PyObject *)type, "codec"); + if (codec == NULL) + goto errorexit; + if (!MultibyteCodec_Check(codec)) { + PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); + goto errorexit; + } + + self->codec = ((MultibyteCodecObject *)codec)->codec; + self->stream = stream; + Py_INCREF(stream); + self->pendingsize = 0; + self->errors = internal_error_callback(errors); + if (self->errors == NULL) + goto errorexit; + if (self->codec->decinit != NULL && + self->codec->decinit(&self->state, self->codec->config) != 0) + goto errorexit; + + Py_DECREF(codec); + return (PyObject *)self; + +errorexit: + Py_XDECREF(self); + Py_XDECREF(codec); + return NULL; +} + +static int +mbstreamreader_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +static int +mbstreamreader_traverse(MultibyteStreamReaderObject *self, + visitproc visit, void *arg) +{ + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + Py_VISIT(self->stream); + return 0; +} + +static void +mbstreamreader_dealloc(MultibyteStreamReaderObject *self) +{ + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); + Py_DECREF(self->stream); + self->ob_type->tp_free(self); +} + +static PyTypeObject MultibyteStreamReader_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "MultibyteStreamReader", /* tp_name */ + sizeof(MultibyteStreamReaderObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)mbstreamreader_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)mbstreamreader_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iterext */ + mbstreamreader_methods, /* tp_methods */ + mbstreamreader_members, /* tp_members */ + codecctx_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + mbstreamreader_init, /* tp_init */ + 0, /* tp_alloc */ + mbstreamreader_new, /* tp_new */ +}; + + +/** + * MultibyteStreamWriter object + */ + +static int +mbstreamwriter_iwrite(MultibyteStreamWriterObject *self, + PyObject *unistr) +{ + PyObject *str, *wr; + + str = encoder_encode_stateful(STATEFUL_ECTX(self), unistr, 0); + if (str == NULL) + return -1; + + wr = PyObject_CallMethod(self->stream, "write", "O", str); + Py_DECREF(str); + if (wr == NULL) + return -1; + + Py_DECREF(wr); + return 0; +} + +static PyObject * +mbstreamwriter_write(MultibyteStreamWriterObject *self, PyObject *strobj) +{ + if (mbstreamwriter_iwrite(self, strobj)) + return NULL; + else + Py_RETURN_NONE; +} + +static PyObject * +mbstreamwriter_writelines(MultibyteStreamWriterObject *self, PyObject *lines) +{ + PyObject *strobj; + int i, r; + + if (!PySequence_Check(lines)) { + PyErr_SetString(PyExc_TypeError, + "arg must be a sequence object"); + return NULL; + } + + for (i = 0; i < PySequence_Length(lines); i++) { + /* length can be changed even within this loop */ + strobj = PySequence_GetItem(lines, i); + if (strobj == NULL) + return NULL; + + r = mbstreamwriter_iwrite(self, strobj); + Py_DECREF(strobj); + if (r == -1) + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * +mbstreamwriter_reset(MultibyteStreamWriterObject *self) +{ + const Py_UNICODE *pending; + PyObject *pwrt; + + pending = self->pending; + pwrt = multibytecodec_encode(self->codec, &self->state, + &pending, self->pendingsize, self->errors, + MBENC_FLUSH | MBENC_RESET); + /* some pending buffer can be truncated when UnicodeEncodeError is + * raised on 'strict' mode. but, 'reset' method is designed to + * reset the pending buffer or states so failed string sequence + * ought to be missed */ + self->pendingsize = 0; + if (pwrt == NULL) + return NULL; + + if (PyString_Size(pwrt) > 0) { + PyObject *wr; + wr = PyObject_CallMethod(self->stream, "write", "O", pwrt); + if (wr == NULL) { + Py_DECREF(pwrt); + return NULL; + } + } + Py_DECREF(pwrt); + + Py_RETURN_NONE; +} + +static PyObject * +mbstreamwriter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + MultibyteStreamWriterObject *self; + PyObject *stream, *codec = NULL; + char *errors = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s:StreamWriter", + streamkwarglist, &stream, &errors)) + return NULL; + + self = (MultibyteStreamWriterObject *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + codec = PyObject_GetAttrString((PyObject *)type, "codec"); + if (codec == NULL) + goto errorexit; + if (!MultibyteCodec_Check(codec)) { + PyErr_SetString(PyExc_TypeError, "codec is unexpected type"); + goto errorexit; + } + + self->codec = ((MultibyteCodecObject *)codec)->codec; + self->stream = stream; + Py_INCREF(stream); + self->pendingsize = 0; + self->errors = internal_error_callback(errors); + if (self->errors == NULL) + goto errorexit; + if (self->codec->encinit != NULL && + self->codec->encinit(&self->state, self->codec->config) != 0) + goto errorexit; + + Py_DECREF(codec); + return (PyObject *)self; + +errorexit: + Py_XDECREF(self); + Py_XDECREF(codec); + return NULL; +} + +static int +mbstreamwriter_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +static int +mbstreamwriter_traverse(MultibyteStreamWriterObject *self, + visitproc visit, void *arg) +{ + if (ERROR_ISCUSTOM(self->errors)) + Py_VISIT(self->errors); + Py_VISIT(self->stream); + return 0; +} + +static void +mbstreamwriter_dealloc(MultibyteStreamWriterObject *self) +{ + PyObject_GC_UnTrack(self); + ERROR_DECREF(self->errors); + Py_DECREF(self->stream); + self->ob_type->tp_free(self); +} + +static struct PyMethodDef mbstreamwriter_methods[] = { + {"write", (PyCFunction)mbstreamwriter_write, + METH_O, NULL}, + {"writelines", (PyCFunction)mbstreamwriter_writelines, + METH_O, NULL}, + {"reset", (PyCFunction)mbstreamwriter_reset, + METH_NOARGS, NULL}, + {NULL, NULL}, +}; + +static PyMemberDef mbstreamwriter_members[] = { + {"stream", T_OBJECT, + offsetof(MultibyteStreamWriterObject, stream), + READONLY, NULL}, + {NULL,} +}; + +static PyTypeObject MultibyteStreamWriter_Type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "MultibyteStreamWriter", /* tp_name */ + sizeof(MultibyteStreamWriterObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)mbstreamwriter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)mbstreamwriter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iterext */ + mbstreamwriter_methods, /* tp_methods */ + mbstreamwriter_members, /* tp_members */ + codecctx_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + mbstreamwriter_init, /* tp_init */ + 0, /* tp_alloc */ + mbstreamwriter_new, /* tp_new */ +}; + + +/** + * Exposed factory function + */ + +static PyObject * +__create_codec(PyObject *ignore, PyObject *arg) +{ + MultibyteCodecObject *self; + MultibyteCodec *codec; + + if (!PyCObject_Check(arg)) { + PyErr_SetString(PyExc_ValueError, "argument type invalid"); + return NULL; + } + + codec = PyCObject_AsVoidPtr(arg); + if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0) + return NULL; + + self = PyObject_New(MultibyteCodecObject, &MultibyteCodec_Type); + if (self == NULL) + return NULL; + self->codec = codec; + + return (PyObject *)self; +} + +static struct PyMethodDef __methods[] = { + {"__create_codec", (PyCFunction)__create_codec, METH_O}, + {NULL, NULL}, +}; + +PyMODINIT_FUNC +init_multibytecodec(void) +{ + int i; + PyObject *m; + PyTypeObject *typelist[] = { + &MultibyteIncrementalEncoder_Type, + &MultibyteIncrementalDecoder_Type, + &MultibyteStreamReader_Type, + &MultibyteStreamWriter_Type, + NULL + }; + + if (PyType_Ready(&MultibyteCodec_Type) < 0) + return; + + m = Py_InitModule("_multibytecodec", __methods); + if (m == NULL) + return; + + for (i = 0; typelist[i] != NULL; i++) { + if (PyType_Ready(typelist[i]) < 0) + return; + Py_INCREF(typelist[i]); + PyModule_AddObject(m, typelist[i]->tp_name, + (PyObject *)typelist[i]); + } + + if (PyErr_Occurred()) + Py_FatalError("can't initialize the _multibytecodec module"); +} diff --git a/sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.h b/sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.h new file mode 100644 index 000000000..22ea5d4ab --- /dev/null +++ b/sys/src/cmd/python/Modules/cjkcodecs/multibytecodec.h @@ -0,0 +1,138 @@ +/* + * multibytecodec.h: Common Multibyte Codec Implementation + * + * Written by Hye-Shik Chang <perky@FreeBSD.org> + */ + +#ifndef _PYTHON_MULTIBYTECODEC_H_ +#define _PYTHON_MULTIBYTECODEC_H_ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef uint32_t +typedef uint32_t ucs4_t; +#else +typedef unsigned int ucs4_t; +#endif + +#ifdef uint16_t +typedef uint16_t ucs2_t, DBCHAR; +#else +typedef unsigned short ucs2_t, DBCHAR; +#endif + +typedef union { + void *p; + int i; + unsigned char c[8]; + ucs2_t u2[4]; + ucs4_t u4[2]; +} MultibyteCodec_State; + +typedef int (*mbcodec_init)(const void *config); +typedef Py_ssize_t (*mbencode_func)(MultibyteCodec_State *state, + const void *config, + const Py_UNICODE **inbuf, Py_ssize_t inleft, + unsigned char **outbuf, Py_ssize_t outleft, + int flags); +typedef int (*mbencodeinit_func)(MultibyteCodec_State *state, + const void *config); +typedef Py_ssize_t (*mbencodereset_func)(MultibyteCodec_State *state, + const void *config, + unsigned char **outbuf, Py_ssize_t outleft); +typedef Py_ssize_t (*mbdecode_func)(MultibyteCodec_State *state, + const void *config, + const unsigned char **inbuf, Py_ssize_t inleft, + Py_UNICODE **outbuf, Py_ssize_t outleft); +typedef int (*mbdecodeinit_func)(MultibyteCodec_State *state, + const void *config); +typedef Py_ssize_t (*mbdecodereset_func)(MultibyteCodec_State *state, + const void *config); + +typedef struct { + const char *encoding; + const void *config; + mbcodec_init codecinit; + mbencode_func encode; + mbencodeinit_func encinit; + mbencodereset_func encreset; + mbdecode_func decode; + mbdecodeinit_func decinit; + mbdecodereset_func decreset; +} MultibyteCodec; + +typedef struct { + PyObject_HEAD + MultibyteCodec *codec; +} MultibyteCodecObject; + +#define MultibyteCodec_Check(op) ((op)->ob_type == &MultibyteCodec_Type) + +#define _MultibyteStatefulCodec_HEAD \ + PyObject_HEAD \ + MultibyteCodec *codec; \ + MultibyteCodec_State state; \ + PyObject *errors; +typedef struct { + _MultibyteStatefulCodec_HEAD +} MultibyteStatefulCodecContext; + +#define MAXENCPENDING 2 +#define _MultibyteStatefulEncoder_HEAD \ + _MultibyteStatefulCodec_HEAD \ + Py_UNICODE pending[MAXENCPENDING]; \ + Py_ssize_t pendingsize; +typedef struct { + _MultibyteStatefulEncoder_HEAD +} MultibyteStatefulEncoderContext; + +#define MAXDECPENDING 8 +#define _MultibyteStatefulDecoder_HEAD \ + _MultibyteStatefulCodec_HEAD \ + unsigned char pending[MAXDECPENDING]; \ + Py_ssize_t pendingsize; +typedef struct { + _MultibyteStatefulDecoder_HEAD +} MultibyteStatefulDecoderContext; + +typedef struct { + _MultibyteStatefulEncoder_HEAD +} MultibyteIncrementalEncoderObject; + +typedef struct { + _MultibyteStatefulDecoder_HEAD +} MultibyteIncrementalDecoderObject; + +typedef struct { + _MultibyteStatefulDecoder_HEAD + PyObject *stream; +} MultibyteStreamReaderObject; + +typedef struct { + _MultibyteStatefulEncoder_HEAD + PyObject *stream; +} MultibyteStreamWriterObject; + +/* positive values for illegal sequences */ +#define MBERR_TOOSMALL (-1) /* insufficient output buffer space */ +#define MBERR_TOOFEW (-2) /* incomplete input buffer */ +#define MBERR_INTERNAL (-3) /* internal runtime error */ + +#define ERROR_STRICT (PyObject *)(1) +#define ERROR_IGNORE (PyObject *)(2) +#define ERROR_REPLACE (PyObject *)(3) +#define ERROR_ISCUSTOM(p) ((p) < ERROR_STRICT || ERROR_REPLACE < (p)) +#define ERROR_DECREF(p) do { \ + if (p != NULL && ERROR_ISCUSTOM(p)) { \ + Py_DECREF(p); \ + } \ +} while (0); + +#define MBENC_FLUSH 0x0001 /* encode all characters encodable */ +#define MBENC_MAX MBENC_FLUSH + +#ifdef __cplusplus +} +#endif +#endif diff --git a/sys/src/cmd/python/Modules/clmodule.c b/sys/src/cmd/python/Modules/clmodule.c new file mode 100644 index 000000000..a535e031f --- /dev/null +++ b/sys/src/cmd/python/Modules/clmodule.c @@ -0,0 +1,2559 @@ + + +/* Cl objects */ + +#define CLDEBUG + +#include <stdarg.h> +#include <cl.h> +#if defined(CL_JPEG_SOFTWARE) && !defined(CL_JPEG_COSMO) +#include <dmedia/cl_cosmo.h> +#endif +#include "Python.h" + +typedef struct { + PyObject_HEAD + int ob_isCompressor; /* Compressor or Decompressor */ + CL_Handle ob_compressorHdl; + int *ob_paramtypes; + int ob_nparams; +} clobject; + +static PyObject *ClError; /* exception cl.error */ + +static int error_handler_called = 0; + +/* + * We want to use the function prototypes that are available in the C + * compiler on the SGI. Because of that, we need to declare the first + * argument of the compressor and decompressor methods as "object *", + * even though they are really "clobject *". Therefore we cast the + * argument to the proper type using this macro. + */ +#define SELF ((clobject *) self) + +/******************************************************************** + Utility routines. +********************************************************************/ +static void +cl_ErrorHandler(CL_Handle handle, int code, const char *fmt, ...) +{ + va_list ap; + char errbuf[BUFSIZ]; /* hopefully big enough */ + char *p; + + if (PyErr_Occurred()) /* don't change existing error */ + return; + error_handler_called = 1; + va_start(ap, fmt); + vsprintf(errbuf, fmt, ap); + va_end(ap); + p = &errbuf[strlen(errbuf) - 1]; /* swat the line feed */ + if (*p == '\n') + *p = 0; + PyErr_SetString(ClError, errbuf); +} + +/* + * This assumes that params are always in the range 0 to some maximum. + */ +static int +param_type_is_float(clobject *self, int param) +{ + int bufferlength; + + if (self->ob_paramtypes == NULL) { + error_handler_called = 0; + bufferlength = clQueryParams(self->ob_compressorHdl, 0, 0); + if (error_handler_called) + return -1; + + self->ob_paramtypes = PyMem_NEW(int, bufferlength); + if (self->ob_paramtypes == NULL) + return -1; + self->ob_nparams = bufferlength / 2; + + (void) clQueryParams(self->ob_compressorHdl, + self->ob_paramtypes, bufferlength); + if (error_handler_called) { + PyMem_DEL(self->ob_paramtypes); + self->ob_paramtypes = NULL; + return -1; + } + } + + if (param < 0 || param >= self->ob_nparams) + return -1; + + if (self->ob_paramtypes[param*2 + 1] == CL_FLOATING_ENUM_VALUE || + self->ob_paramtypes[param*2 + 1] == CL_FLOATING_RANGE_VALUE) + return 1; + else + return 0; +} + +/******************************************************************** + Single image compression/decompression. +********************************************************************/ +static PyObject * +cl_CompressImage(PyObject *self, PyObject *args) +{ + int compressionScheme, width, height, originalFormat; + float compressionRatio; + int frameBufferSize, compressedBufferSize; + char *frameBuffer; + PyObject *compressedBuffer; + + if (!PyArg_ParseTuple(args, "iiiifs#", &compressionScheme, + &width, &height, + &originalFormat, &compressionRatio, &frameBuffer, + &frameBufferSize)) + return NULL; + + retry: + compressedBuffer = PyString_FromStringAndSize(NULL, frameBufferSize); + if (compressedBuffer == NULL) + return NULL; + + compressedBufferSize = frameBufferSize; + error_handler_called = 0; + if (clCompressImage(compressionScheme, width, height, originalFormat, + compressionRatio, (void *) frameBuffer, + &compressedBufferSize, + (void *) PyString_AsString(compressedBuffer)) + == FAILURE || error_handler_called) { + Py_DECREF(compressedBuffer); + if (!error_handler_called) + PyErr_SetString(ClError, "clCompressImage failed"); + return NULL; + } + + if (compressedBufferSize > frameBufferSize) { + frameBufferSize = compressedBufferSize; + Py_DECREF(compressedBuffer); + goto retry; + } + + if (compressedBufferSize < frameBufferSize) + _PyString_Resize(&compressedBuffer, compressedBufferSize); + + return compressedBuffer; +} + +static PyObject * +cl_DecompressImage(PyObject *self, PyObject *args) +{ + int compressionScheme, width, height, originalFormat; + char *compressedBuffer; + int compressedBufferSize, frameBufferSize; + PyObject *frameBuffer; + + if (!PyArg_ParseTuple(args, "iiiis#", &compressionScheme, &width, &height, + &originalFormat, &compressedBuffer, + &compressedBufferSize)) + return NULL; + + frameBufferSize = width * height * CL_BytesPerPixel(originalFormat); + + frameBuffer = PyString_FromStringAndSize(NULL, frameBufferSize); + if (frameBuffer == NULL) + return NULL; + + error_handler_called = 0; + if (clDecompressImage(compressionScheme, width, height, originalFormat, + compressedBufferSize, compressedBuffer, + (void *) PyString_AsString(frameBuffer)) + == FAILURE || error_handler_called) { + Py_DECREF(frameBuffer); + if (!error_handler_called) + PyErr_SetString(ClError, "clDecompressImage failed"); + return NULL; + } + + return frameBuffer; +} + +/******************************************************************** + Sequential compression/decompression. +********************************************************************/ +#define CheckCompressor(self) if ((self)->ob_compressorHdl == NULL) { \ + PyErr_SetString(PyExc_RuntimeError, "(de)compressor not active"); \ + return NULL; \ +} + +static PyObject * +doClose(clobject *self, int (*close_func)(CL_Handle)) +{ + CheckCompressor(self); + + error_handler_called = 0; + if ((*close_func)(self->ob_compressorHdl) == FAILURE || + error_handler_called) { + if (!error_handler_called) + PyErr_SetString(ClError, "close failed"); + return NULL; + } + + self->ob_compressorHdl = NULL; + + if (self->ob_paramtypes) + PyMem_DEL(self->ob_paramtypes); + self->ob_paramtypes = NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +clm_CloseCompressor(PyObject *self) +{ + return doClose(SELF, clCloseCompressor); +} + +static PyObject * +clm_CloseDecompressor(PyObject *self) +{ + return doClose(SELF, clCloseDecompressor); +} + +static PyObject * +clm_Compress(PyObject *self, PyObject *args) +{ + int numberOfFrames; + int frameBufferSize, compressedBufferSize, size; + char *frameBuffer; + PyObject *data; + + CheckCompressor(SELF); + + if (!PyArg_Parse(args, "(is#)", &numberOfFrames, + &frameBuffer, &frameBufferSize)) + return NULL; + + error_handler_called = 0; + size = clGetParam(SELF->ob_compressorHdl, CL_COMPRESSED_BUFFER_SIZE); + compressedBufferSize = size; + if (error_handler_called) + return NULL; + + data = PyString_FromStringAndSize(NULL, size); + if (data == NULL) + return NULL; + + error_handler_called = 0; + if (clCompress(SELF->ob_compressorHdl, numberOfFrames, + (void *) frameBuffer, &compressedBufferSize, + (void *) PyString_AsString(data)) == FAILURE || + error_handler_called) { + Py_DECREF(data); + if (!error_handler_called) + PyErr_SetString(ClError, "compress failed"); + return NULL; + } + + if (compressedBufferSize < size) + if (_PyString_Resize(&data, compressedBufferSize)) + return NULL; + + if (compressedBufferSize > size) { + /* we didn't get all "compressed" data */ + Py_DECREF(data); + PyErr_SetString(ClError, + "compressed data is more than fitted"); + return NULL; + } + + return data; +} + +static PyObject * +clm_Decompress(PyObject *self, PyObject *args) +{ + PyObject *data; + int numberOfFrames; + char *compressedData; + int compressedDataSize, dataSize; + + CheckCompressor(SELF); + + if (!PyArg_Parse(args, "(is#)", &numberOfFrames, &compressedData, + &compressedDataSize)) + return NULL; + + error_handler_called = 0; + dataSize = clGetParam(SELF->ob_compressorHdl, CL_FRAME_BUFFER_SIZE); + if (error_handler_called) + return NULL; + + data = PyString_FromStringAndSize(NULL, dataSize); + if (data == NULL) + return NULL; + + error_handler_called = 0; + if (clDecompress(SELF->ob_compressorHdl, numberOfFrames, + compressedDataSize, (void *) compressedData, + (void *) PyString_AsString(data)) == FAILURE || + error_handler_called) { + Py_DECREF(data); + if (!error_handler_called) + PyErr_SetString(ClError, "decompress failed"); + return NULL; + } + + return data; +} + +static PyObject * +doParams(clobject *self, PyObject *args, int (*func)(CL_Handle, int *, int), + int modified) +{ + PyObject *list, *v; + int *PVbuffer; + int length; + int i; + float number; + + CheckCompressor(self); + + if (!PyArg_Parse(args, "O", &list)) + return NULL; + if (!PyList_Check(list)) { + PyErr_BadArgument(); + return NULL; + } + length = PyList_Size(list); + PVbuffer = PyMem_NEW(int, length); + if (PVbuffer == NULL) + return PyErr_NoMemory(); + for (i = 0; i < length; i++) { + v = PyList_GetItem(list, i); + if (PyFloat_Check(v)) { + number = PyFloat_AsDouble(v); + PVbuffer[i] = CL_TypeIsInt(number); + } else if (PyInt_Check(v)) { + PVbuffer[i] = PyInt_AsLong(v); + if ((i & 1) && + param_type_is_float(self, PVbuffer[i-1]) > 0) { + number = PVbuffer[i]; + PVbuffer[i] = CL_TypeIsInt(number); + } + } else { + PyMem_DEL(PVbuffer); + PyErr_BadArgument(); + return NULL; + } + } + + error_handler_called = 0; + (*func)(self->ob_compressorHdl, PVbuffer, length); + if (error_handler_called) { + PyMem_DEL(PVbuffer); + return NULL; + } + + if (modified) { + for (i = 0; i < length; i++) { + if ((i & 1) && + param_type_is_float(self, PVbuffer[i-1]) > 0) { + number = CL_TypeIsFloat(PVbuffer[i]); + v = PyFloat_FromDouble(number); + } else + v = PyInt_FromLong(PVbuffer[i]); + PyList_SetItem(list, i, v); + } + } + + PyMem_DEL(PVbuffer); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +clm_GetParams(PyObject *self, PyObject *args) +{ + return doParams(SELF, args, clGetParams, 1); +} + +static PyObject * +clm_SetParams(PyObject *self, PyObject *args) +{ + return doParams(SELF, args, clSetParams, 0); +} + +static PyObject * +do_get(clobject *self, PyObject *args, int (*func)(CL_Handle, int)) +{ + int paramID, value; + float fvalue; + + CheckCompressor(self); + + if (!PyArg_Parse(args, "i", &paramID)) + return NULL; + + error_handler_called = 0; + value = (*func)(self->ob_compressorHdl, paramID); + if (error_handler_called) + return NULL; + + if (param_type_is_float(self, paramID) > 0) { + fvalue = CL_TypeIsFloat(value); + return PyFloat_FromDouble(fvalue); + } + + return PyInt_FromLong(value); +} + +static PyObject * +clm_GetParam(PyObject *self, PyObject *args) +{ + return do_get(SELF, args, clGetParam); +} + +static PyObject * +clm_GetDefault(PyObject *self, PyObject *args) +{ + return do_get(SELF, args, clGetDefault); +} + +static PyObject * +clm_SetParam(PyObject *self, PyObject *args) +{ + int paramID, value; + float fvalue; + + CheckCompressor(SELF); + + if (!PyArg_Parse(args, "(ii)", &paramID, &value)) { + PyErr_Clear(); + if (!PyArg_Parse(args, "(if)", &paramID, &fvalue)) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "bad argument list (format '(ii)' or '(if)')"); + return NULL; + } + value = CL_TypeIsInt(fvalue); + } else { + if (param_type_is_float(SELF, paramID) > 0) { + fvalue = value; + value = CL_TypeIsInt(fvalue); + } + } + + error_handler_called = 0; + value = clSetParam(SELF->ob_compressorHdl, paramID, value); + if (error_handler_called) + return NULL; + + if (param_type_is_float(SELF, paramID) > 0) + return PyFloat_FromDouble(CL_TypeIsFloat(value)); + else + return PyInt_FromLong(value); +} + +static PyObject * +clm_GetParamID(PyObject *self, PyObject *args) +{ + char *name; + int value; + + CheckCompressor(SELF); + + if (!PyArg_Parse(args, "s", &name)) + return NULL; + + error_handler_called = 0; + value = clGetParamID(SELF->ob_compressorHdl, name); + if (value == FAILURE || error_handler_called) { + if (!error_handler_called) + PyErr_SetString(ClError, "getparamid failed"); + return NULL; + } + + return PyInt_FromLong(value); +} + +static PyObject * +clm_QueryParams(PyObject *self) +{ + int bufferlength; + int *PVbuffer; + PyObject *list; + int i; + + CheckCompressor(SELF); + + error_handler_called = 0; + bufferlength = clQueryParams(SELF->ob_compressorHdl, 0, 0); + if (error_handler_called) + return NULL; + + PVbuffer = PyMem_NEW(int, bufferlength); + if (PVbuffer == NULL) + return PyErr_NoMemory(); + + bufferlength = clQueryParams(SELF->ob_compressorHdl, PVbuffer, + bufferlength); + if (error_handler_called) { + PyMem_DEL(PVbuffer); + return NULL; + } + + list = PyList_New(bufferlength); + if (list == NULL) { + PyMem_DEL(PVbuffer); + return NULL; + } + + for (i = 0; i < bufferlength; i++) { + if (i & 1) + PyList_SetItem(list, i, PyInt_FromLong(PVbuffer[i])); + else if (PVbuffer[i] == 0) { + Py_INCREF(Py_None); + PyList_SetItem(list, i, Py_None); + } else + PyList_SetItem(list, i, + PyString_FromString((char *) PVbuffer[i])); + } + + PyMem_DEL(PVbuffer); + + return list; +} + +static PyObject * +clm_GetMinMax(PyObject *self, PyObject *args) +{ + int param, min, max; + float fmin, fmax; + + CheckCompressor(SELF); + + if (!PyArg_Parse(args, "i", &param)) + return NULL; + + clGetMinMax(SELF->ob_compressorHdl, param, &min, &max); + + if (param_type_is_float(SELF, param) > 0) { + fmin = CL_TypeIsFloat(min); + fmax = CL_TypeIsFloat(max); + return Py_BuildValue("(ff)", fmin, fmax); + } + + return Py_BuildValue("(ii)", min, max); +} + +static PyObject * +clm_GetName(PyObject *self, PyObject *args) +{ + int param; + char *name; + + CheckCompressor(SELF); + + if (!PyArg_Parse(args, "i", &param)) + return NULL; + + error_handler_called = 0; + name = clGetName(SELF->ob_compressorHdl, param); + if (name == NULL || error_handler_called) { + if (!error_handler_called) + PyErr_SetString(ClError, "getname failed"); + return NULL; + } + + return PyString_FromString(name); +} + +static PyObject * +clm_QuerySchemeFromHandle(PyObject *self) +{ + CheckCompressor(SELF); + return PyInt_FromLong(clQuerySchemeFromHandle(SELF->ob_compressorHdl)); +} + +static PyObject * +clm_ReadHeader(PyObject *self, PyObject *args) +{ + char *header; + int headerSize; + + CheckCompressor(SELF); + + if (!PyArg_Parse(args, "s#", &header, &headerSize)) + return NULL; + + return PyInt_FromLong(clReadHeader(SELF->ob_compressorHdl, + headerSize, header)); +} + +static PyMethodDef compressor_methods[] = { + {"close", clm_CloseCompressor, METH_NOARGS}, /* alias */ + {"CloseCompressor", clm_CloseCompressor, METH_NOARGS}, + {"Compress", clm_Compress, METH_OLDARGS}, + {"GetDefault", clm_GetDefault, METH_OLDARGS}, + {"GetMinMax", clm_GetMinMax, METH_OLDARGS}, + {"GetName", clm_GetName, METH_OLDARGS}, + {"GetParam", clm_GetParam, METH_OLDARGS}, + {"GetParamID", clm_GetParamID, METH_OLDARGS}, + {"GetParams", clm_GetParams, METH_OLDARGS}, + {"QueryParams", clm_QueryParams, METH_NOARGS}, + {"QuerySchemeFromHandle",clm_QuerySchemeFromHandle, METH_NOARGS}, + {"SetParam", clm_SetParam, METH_OLDARGS}, + {"SetParams", clm_SetParams, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyMethodDef decompressor_methods[] = { + {"close", clm_CloseDecompressor, METH_NOARGS}, /* alias */ + {"CloseDecompressor", clm_CloseDecompressor, METH_NOARGS}, + {"Decompress", clm_Decompress, METH_OLDARGS}, + {"GetDefault", clm_GetDefault, METH_OLDARGS}, + {"GetMinMax", clm_GetMinMax, METH_OLDARGS}, + {"GetName", clm_GetName, METH_OLDARGS}, + {"GetParam", clm_GetParam, METH_OLDARGS}, + {"GetParamID", clm_GetParamID, METH_OLDARGS}, + {"GetParams", clm_GetParams, METH_OLDARGS}, + {"ReadHeader", clm_ReadHeader, METH_OLDARGS}, + {"QueryParams", clm_QueryParams, METH_NOARGS}, + {"QuerySchemeFromHandle",clm_QuerySchemeFromHandle, METH_NOARGS}, + {"SetParam", clm_SetParam, METH_OLDARGS}, + {"SetParams", clm_SetParams, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +static void +cl_dealloc(PyObject *self) +{ + if (SELF->ob_compressorHdl) { + if (SELF->ob_isCompressor) + clCloseCompressor(SELF->ob_compressorHdl); + else + clCloseDecompressor(SELF->ob_compressorHdl); + } + PyObject_Del(self); +} + +static PyObject * +cl_getattr(PyObject *self, char *name) +{ + if (SELF->ob_isCompressor) + return Py_FindMethod(compressor_methods, self, name); + else + return Py_FindMethod(decompressor_methods, self, name); +} + +static PyTypeObject Cltype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "cl.cl", /*tp_name*/ + sizeof(clobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)cl_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)cl_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +static PyObject * +doOpen(PyObject *self, PyObject *args, int (*open_func)(int, CL_Handle *), + int iscompressor) +{ + int scheme; + clobject *new; + + if (!PyArg_ParseTuple(args, "i", &scheme)) + return NULL; + + new = PyObject_New(clobject, &Cltype); + if (new == NULL) + return NULL; + + new->ob_compressorHdl = NULL; + new->ob_isCompressor = iscompressor; + new->ob_paramtypes = NULL; + + error_handler_called = 0; + if ((*open_func)(scheme, &new->ob_compressorHdl) == FAILURE || + error_handler_called) { + Py_DECREF(new); + if (!error_handler_called) + PyErr_SetString(ClError, "Open(De)Compressor failed"); + return NULL; + } + return (PyObject *)new; +} + +static PyObject * +cl_OpenCompressor(PyObject *self, PyObject *args) +{ + return doOpen(self, args, clOpenCompressor, 1); +} + +static PyObject * +cl_OpenDecompressor(PyObject *self, PyObject *args) +{ + return doOpen(self, args, clOpenDecompressor, 0); +} + +static PyObject * +cl_QueryScheme(PyObject *self, PyObject *args) +{ + char *header; + int headerlen; + int scheme; + + if (!PyArg_ParseTuple(args, "s#", &header, &headerlen)) + return NULL; + + scheme = clQueryScheme(header); + if (scheme < 0) { + PyErr_SetString(ClError, "unknown compression scheme"); + return NULL; + } + + return PyInt_FromLong(scheme); +} + +static PyObject * +cl_QueryMaxHeaderSize(PyObject *self, PyObject *args) +{ + int scheme; + + if (!PyArg_ParseTuple(args, "i", &scheme)) + return NULL; + + return PyInt_FromLong(clQueryMaxHeaderSize(scheme)); +} + +static PyObject * +cl_QueryAlgorithms(PyObject *self, PyObject *args) +{ + int algorithmMediaType; + int bufferlength; + int *PVbuffer; + PyObject *list; + int i; + + if (!PyArg_ParseTuple(args, "i", &algorithmMediaType)) + return NULL; + + error_handler_called = 0; + bufferlength = clQueryAlgorithms(algorithmMediaType, 0, 0); + if (error_handler_called) + return NULL; + + PVbuffer = PyMem_NEW(int, bufferlength); + if (PVbuffer == NULL) + return PyErr_NoMemory(); + + bufferlength = clQueryAlgorithms(algorithmMediaType, PVbuffer, + bufferlength); + if (error_handler_called) { + PyMem_DEL(PVbuffer); + return NULL; + } + + list = PyList_New(bufferlength); + if (list == NULL) { + PyMem_DEL(PVbuffer); + return NULL; + } + + for (i = 0; i < bufferlength; i++) { + if (i & 1) + PyList_SetItem(list, i, PyInt_FromLong(PVbuffer[i])); + else if (PVbuffer[i] == 0) { + Py_INCREF(Py_None); + PyList_SetItem(list, i, Py_None); + } else + PyList_SetItem(list, i, + PyString_FromString((char *) PVbuffer[i])); + } + + PyMem_DEL(PVbuffer); + + return list; +} + +static PyObject * +cl_QuerySchemeFromName(PyObject *self, PyObject *args) +{ + int algorithmMediaType; + char *name; + int scheme; + + if (!PyArg_ParseTuple(args, "is", &algorithmMediaType, &name)) + return NULL; + + error_handler_called = 0; + scheme = clQuerySchemeFromName(algorithmMediaType, name); + if (error_handler_called) { + PyErr_SetString(ClError, "unknown compression scheme"); + return NULL; + } + + return PyInt_FromLong(scheme); +} + +static PyObject * +cl_GetAlgorithmName(PyObject *self, PyObject *args) +{ + int scheme; + char *name; + + if (!PyArg_ParseTuple(args, "i", &scheme)) + return NULL; + + name = clGetAlgorithmName(scheme); + if (name == 0) { + PyErr_SetString(ClError, "unknown compression scheme"); + return NULL; + } + + return PyString_FromString(name); +} + +static PyObject * +do_set(PyObject *self, PyObject *args, int (*func)(int, int, int)) +{ + int scheme, paramID, value; + float fvalue; + int is_float = 0; + + if (!PyArg_ParseTuple(args, "iii", &scheme, &paramID, &value)) { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "iif", &scheme, &paramID, &fvalue)) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "bad argument list (format '(iii)' or '(iif)')"); + return NULL; + } + value = CL_TypeIsInt(fvalue); + is_float = 1; + } else { + /* check some parameters which we know to be floats */ + switch (scheme) { + case CL_COMPRESSION_RATIO: + case CL_SPEED: + fvalue = value; + value = CL_TypeIsInt(fvalue); + is_float = 1; + break; + } + } + + error_handler_called = 0; + value = (*func)(scheme, paramID, value); + if (error_handler_called) + return NULL; + + if (is_float) + return PyFloat_FromDouble(CL_TypeIsFloat(value)); + else + return PyInt_FromLong(value); +} + +static PyObject * +cl_SetDefault(PyObject *self, PyObject *args) +{ + return do_set(self, args, clSetDefault); +} + +static PyObject * +cl_SetMin(PyObject *self, PyObject *args) +{ + return do_set(self, args, clSetMin); +} + +static PyObject * +cl_SetMax(PyObject *self, PyObject *args) +{ + return do_set(self, args, clSetMax); +} + +#define func(name, handler) \ +static PyObject *cl_##name(PyObject *self, PyObject *args) \ +{ \ + int x; \ + if (!PyArg_ParseTuple(args, "i", &x)) return NULL; \ + return Py##handler(CL_##name(x)); \ +} + +#define func2(name, handler) \ +static PyObject *cl_##name(PyObject *self, PyObject *args) \ +{ \ + int a1, a2; \ + if (!PyArg_ParseTuple(args, "ii", &a1, &a2)) return NULL; \ + return Py##handler(CL_##name(a1, a2)); \ +} + +func(BytesPerSample, Int_FromLong) +func(BytesPerPixel, Int_FromLong) +func(AudioFormatName, String_FromString) +func(VideoFormatName, String_FromString) +func(AlgorithmNumber, Int_FromLong) +func(AlgorithmType, Int_FromLong) +func2(Algorithm, Int_FromLong) +func(ParamNumber, Int_FromLong) +func(ParamType, Int_FromLong) +func2(ParamID, Int_FromLong) + +#ifdef CLDEBUG + static PyObject * +cvt_type(PyObject *self, PyObject *args) +{ + int number; + float fnumber; + + if (PyArg_Parse(args, "i", &number)) + return PyFloat_FromDouble(CL_TypeIsFloat(number)); + else { + PyErr_Clear(); + if (PyArg_Parse(args, "f", &fnumber)) + return PyInt_FromLong(CL_TypeIsInt(fnumber)); + return NULL; + } +} +#endif + +static PyMethodDef cl_methods[] = { + {"CompressImage", cl_CompressImage, METH_VARARGS}, + {"DecompressImage", cl_DecompressImage, METH_VARARGS}, + {"GetAlgorithmName", cl_GetAlgorithmName, METH_VARARGS}, + {"OpenCompressor", cl_OpenCompressor, METH_VARARGS}, + {"OpenDecompressor", cl_OpenDecompressor, METH_VARARGS}, + {"QueryAlgorithms", cl_QueryAlgorithms, METH_VARARGS}, + {"QueryMaxHeaderSize", cl_QueryMaxHeaderSize, METH_VARARGS}, + {"QueryScheme", cl_QueryScheme, METH_VARARGS}, + {"QuerySchemeFromName", cl_QuerySchemeFromName, METH_VARARGS}, + {"SetDefault", cl_SetDefault, METH_VARARGS}, + {"SetMax", cl_SetMax, METH_VARARGS}, + {"SetMin", cl_SetMin, METH_VARARGS}, + {"BytesPerSample", cl_BytesPerSample, METH_VARARGS}, + {"BytesPerPixel", cl_BytesPerPixel, METH_VARARGS}, + {"AudioFormatName", cl_AudioFormatName, METH_VARARGS}, + {"VideoFormatName", cl_VideoFormatName, METH_VARARGS}, + {"AlgorithmNumber", cl_AlgorithmNumber, METH_VARARGS}, + {"AlgorithmType", cl_AlgorithmType, METH_VARARGS}, + {"Algorithm", cl_Algorithm, METH_VARARGS}, + {"ParamNumber", cl_ParamNumber, METH_VARARGS}, + {"ParamType", cl_ParamType, METH_VARARGS}, + {"ParamID", cl_ParamID, METH_VARARGS}, +#ifdef CLDEBUG + {"cvt_type", cvt_type, METH_VARARGS}, +#endif + {NULL, NULL} /* Sentinel */ +}; + +#ifdef CL_JPEG_SOFTWARE +#define IRIX_5_3_LIBRARY +#endif + +void +initcl(void) +{ + PyObject *m, *d, *x; + + m = Py_InitModule("cl", cl_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + ClError = PyErr_NewException("cl.error", NULL, NULL); + (void) PyDict_SetItemString(d, "error", ClError); + +#ifdef CL_ADDED_ALGORITHM_ERROR + x = PyInt_FromLong(CL_ADDED_ALGORITHM_ERROR); + if (x == NULL || PyDict_SetItemString(d, "ADDED_ALGORITHM_ERROR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ALAW + x = PyInt_FromLong(CL_ALAW); + if (x == NULL || PyDict_SetItemString(d, "ALAW", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ALGORITHM_ID + x = PyInt_FromLong(CL_ALGORITHM_ID); + if (x == NULL || PyDict_SetItemString(d, "ALGORITHM_ID", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ALGORITHM_TABLE_FULL + x = PyInt_FromLong(CL_ALGORITHM_TABLE_FULL); + if (x == NULL || PyDict_SetItemString(d, "ALGORITHM_TABLE_FULL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ALGORITHM_VERSION + x = PyInt_FromLong(CL_ALGORITHM_VERSION); + if (x == NULL || PyDict_SetItemString(d, "ALGORITHM_VERSION", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ALG_AUDIO + x = PyInt_FromLong(CL_ALG_AUDIO); + if (x == NULL || PyDict_SetItemString(d, "ALG_AUDIO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ALG_VIDEO + x = PyInt_FromLong(CL_ALG_VIDEO); + if (x == NULL || PyDict_SetItemString(d, "ALG_VIDEO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AUDIO + x = PyInt_FromLong(CL_AUDIO); + if (x == NULL || PyDict_SetItemString(d, "AUDIO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_BITRATE_POLICY + x = PyInt_FromLong(CL_AWARE_BITRATE_POLICY); + if (x == NULL || PyDict_SetItemString(d, "AWARE_BITRATE_POLICY", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_BITRATE_TARGET + x = PyInt_FromLong(CL_AWARE_BITRATE_TARGET); + if (x == NULL || PyDict_SetItemString(d, "AWARE_BITRATE_TARGET", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_CHANNEL_POLICY + x = PyInt_FromLong(CL_AWARE_CHANNEL_POLICY); + if (x == NULL || PyDict_SetItemString(d, "AWARE_CHANNEL_POLICY", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_CONST_QUAL + x = PyInt_FromLong(CL_AWARE_CONST_QUAL); + if (x == NULL || PyDict_SetItemString(d, "AWARE_CONST_QUAL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_ERROR + x = PyInt_FromLong(CL_AWARE_ERROR); + if (x == NULL || PyDict_SetItemString(d, "AWARE_ERROR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_FIXED_RATE + x = PyInt_FromLong(CL_AWARE_FIXED_RATE); + if (x == NULL || PyDict_SetItemString(d, "AWARE_FIXED_RATE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_INDEPENDENT + x = PyInt_FromLong(CL_AWARE_INDEPENDENT); + if (x == NULL || PyDict_SetItemString(d, "AWARE_INDEPENDENT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_JOINT_STEREO + x = PyInt_FromLong(CL_AWARE_JOINT_STEREO); + if (x == NULL || PyDict_SetItemString(d, "AWARE_JOINT_STEREO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_LAYER + x = PyInt_FromLong(CL_AWARE_LAYER); + if (x == NULL || PyDict_SetItemString(d, "AWARE_LAYER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_LOSSLESS + x = PyInt_FromLong(CL_AWARE_LOSSLESS); + if (x == NULL || PyDict_SetItemString(d, "AWARE_LOSSLESS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_MPEG_AUDIO + x = PyInt_FromLong(CL_AWARE_MPEG_AUDIO); + if (x == NULL || PyDict_SetItemString(d, "AWARE_MPEG_AUDIO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_MPEG_LAYER_I + x = PyInt_FromLong(CL_AWARE_MPEG_LAYER_I); + if (x == NULL || PyDict_SetItemString(d, "AWARE_MPEG_LAYER_I", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_MPEG_LAYER_II + x = PyInt_FromLong(CL_AWARE_MPEG_LAYER_II); + if (x == NULL || PyDict_SetItemString(d, "AWARE_MPEG_LAYER_II", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_MULTIRATE + x = PyInt_FromLong(CL_AWARE_MULTIRATE); + if (x == NULL || PyDict_SetItemString(d, "AWARE_MULTIRATE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_NOISE_MARGIN + x = PyInt_FromLong(CL_AWARE_NOISE_MARGIN); + if (x == NULL || PyDict_SetItemString(d, "AWARE_NOISE_MARGIN", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_AWARE_STEREO + x = PyInt_FromLong(CL_AWARE_STEREO); + if (x == NULL || PyDict_SetItemString(d, "AWARE_STEREO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_ALGORITHM_NAME + x = PyInt_FromLong(CL_BAD_ALGORITHM_NAME); + if (x == NULL || PyDict_SetItemString(d, "BAD_ALGORITHM_NAME", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_ALGORITHM_TYPE + x = PyInt_FromLong(CL_BAD_ALGORITHM_TYPE); + if (x == NULL || PyDict_SetItemString(d, "BAD_ALGORITHM_TYPE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BLOCK_SIZE + x = PyInt_FromLong(CL_BAD_BLOCK_SIZE); + if (x == NULL || PyDict_SetItemString(d, "BAD_BLOCK_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BOARD + x = PyInt_FromLong(CL_BAD_BOARD); + if (x == NULL || PyDict_SetItemString(d, "BAD_BOARD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFERING + x = PyInt_FromLong(CL_BAD_BUFFERING); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFERING", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFERLENGTH_NEG + x = PyInt_FromLong(CL_BAD_BUFFERLENGTH_NEG); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFERLENGTH_NEG", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFERLENGTH_ODD + x = PyInt_FromLong(CL_BAD_BUFFERLENGTH_ODD); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFERLENGTH_ODD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFER_EXISTS + x = PyInt_FromLong(CL_BAD_BUFFER_EXISTS); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_EXISTS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFER_HANDLE + x = PyInt_FromLong(CL_BAD_BUFFER_HANDLE); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_HANDLE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFER_POINTER + x = PyInt_FromLong(CL_BAD_BUFFER_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFER_QUERY_SIZE + x = PyInt_FromLong(CL_BAD_BUFFER_QUERY_SIZE); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_QUERY_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFER_SIZE + x = PyInt_FromLong(CL_BAD_BUFFER_SIZE); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFER_SIZE_POINTER + x = PyInt_FromLong(CL_BAD_BUFFER_SIZE_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_SIZE_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_BUFFER_TYPE + x = PyInt_FromLong(CL_BAD_BUFFER_TYPE); + if (x == NULL || PyDict_SetItemString(d, "BAD_BUFFER_TYPE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_COMPRESSION_SCHEME + x = PyInt_FromLong(CL_BAD_COMPRESSION_SCHEME); + if (x == NULL || PyDict_SetItemString(d, "BAD_COMPRESSION_SCHEME", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_COMPRESSOR_HANDLE + x = PyInt_FromLong(CL_BAD_COMPRESSOR_HANDLE); + if (x == NULL || PyDict_SetItemString(d, "BAD_COMPRESSOR_HANDLE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_COMPRESSOR_HANDLE_POINTER + x = PyInt_FromLong(CL_BAD_COMPRESSOR_HANDLE_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_COMPRESSOR_HANDLE_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_FRAME_SIZE + x = PyInt_FromLong(CL_BAD_FRAME_SIZE); + if (x == NULL || PyDict_SetItemString(d, "BAD_FRAME_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_FUNCTIONALITY + x = PyInt_FromLong(CL_BAD_FUNCTIONALITY); + if (x == NULL || PyDict_SetItemString(d, "BAD_FUNCTIONALITY", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_FUNCTION_POINTER + x = PyInt_FromLong(CL_BAD_FUNCTION_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_FUNCTION_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_HEADER_SIZE + x = PyInt_FromLong(CL_BAD_HEADER_SIZE); + if (x == NULL || PyDict_SetItemString(d, "BAD_HEADER_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_INITIAL_VALUE + x = PyInt_FromLong(CL_BAD_INITIAL_VALUE); + if (x == NULL || PyDict_SetItemString(d, "BAD_INITIAL_VALUE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_INTERNAL_FORMAT + x = PyInt_FromLong(CL_BAD_INTERNAL_FORMAT); + if (x == NULL || PyDict_SetItemString(d, "BAD_INTERNAL_FORMAT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_LICENSE + x = PyInt_FromLong(CL_BAD_LICENSE); + if (x == NULL || PyDict_SetItemString(d, "BAD_LICENSE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_MIN_GT_MAX + x = PyInt_FromLong(CL_BAD_MIN_GT_MAX); + if (x == NULL || PyDict_SetItemString(d, "BAD_MIN_GT_MAX", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_NO_BUFFERSPACE + x = PyInt_FromLong(CL_BAD_NO_BUFFERSPACE); + if (x == NULL || PyDict_SetItemString(d, "BAD_NO_BUFFERSPACE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_NUMBER_OF_BLOCKS + x = PyInt_FromLong(CL_BAD_NUMBER_OF_BLOCKS); + if (x == NULL || PyDict_SetItemString(d, "BAD_NUMBER_OF_BLOCKS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_PARAM + x = PyInt_FromLong(CL_BAD_PARAM); + if (x == NULL || PyDict_SetItemString(d, "BAD_PARAM", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_PARAM_ID_POINTER + x = PyInt_FromLong(CL_BAD_PARAM_ID_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_PARAM_ID_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_PARAM_TYPE + x = PyInt_FromLong(CL_BAD_PARAM_TYPE); + if (x == NULL || PyDict_SetItemString(d, "BAD_PARAM_TYPE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_POINTER + x = PyInt_FromLong(CL_BAD_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_PVBUFFER + x = PyInt_FromLong(CL_BAD_PVBUFFER); + if (x == NULL || PyDict_SetItemString(d, "BAD_PVBUFFER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_SCHEME_POINTER + x = PyInt_FromLong(CL_BAD_SCHEME_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_SCHEME_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_STREAM_HEADER + x = PyInt_FromLong(CL_BAD_STREAM_HEADER); + if (x == NULL || PyDict_SetItemString(d, "BAD_STREAM_HEADER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_STRING_POINTER + x = PyInt_FromLong(CL_BAD_STRING_POINTER); + if (x == NULL || PyDict_SetItemString(d, "BAD_STRING_POINTER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BAD_TEXT_STRING_PTR + x = PyInt_FromLong(CL_BAD_TEXT_STRING_PTR); + if (x == NULL || PyDict_SetItemString(d, "BAD_TEXT_STRING_PTR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BEST_FIT + x = PyInt_FromLong(CL_BEST_FIT); + if (x == NULL || PyDict_SetItemString(d, "BEST_FIT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BIDIRECTIONAL + x = PyInt_FromLong(CL_BIDIRECTIONAL); + if (x == NULL || PyDict_SetItemString(d, "BIDIRECTIONAL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BITRATE + x = PyInt_FromLong(CL_BITRATE); + if (x == NULL || PyDict_SetItemString(d, "BITRATE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BITRATE_POLICY + x = PyInt_FromLong(CL_BITRATE_POLICY); + if (x == NULL || PyDict_SetItemString(d, "BITRATE_POLICY", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BITRATE_TARGET + x = PyInt_FromLong(CL_BITRATE_TARGET); + if (x == NULL || PyDict_SetItemString(d, "BITRATE_TARGET", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BITS_PER_COMPONENT + x = PyInt_FromLong(CL_BITS_PER_COMPONENT); + if (x == NULL || PyDict_SetItemString(d, "BITS_PER_COMPONENT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BLENDING + x = PyInt_FromLong(CL_BLENDING); + if (x == NULL || PyDict_SetItemString(d, "BLENDING", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BLOCK_SIZE + x = PyInt_FromLong(CL_BLOCK_SIZE); + if (x == NULL || PyDict_SetItemString(d, "BLOCK_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BOTTOM_UP + x = PyInt_FromLong(CL_BOTTOM_UP); + if (x == NULL || PyDict_SetItemString(d, "BOTTOM_UP", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BUFFER_NOT_CREATED + x = PyInt_FromLong(CL_BUFFER_NOT_CREATED); + if (x == NULL || PyDict_SetItemString(d, "BUFFER_NOT_CREATED", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BUF_COMPRESSED + x = PyInt_FromLong(CL_BUF_COMPRESSED); + if (x == NULL || PyDict_SetItemString(d, "BUF_COMPRESSED", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BUF_DATA + x = PyInt_FromLong(CL_BUF_DATA); + if (x == NULL || PyDict_SetItemString(d, "BUF_DATA", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_BUF_FRAME + x = PyInt_FromLong(CL_BUF_FRAME); + if (x == NULL || PyDict_SetItemString(d, "BUF_FRAME", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_CHANNEL_POLICY + x = PyInt_FromLong(CL_CHANNEL_POLICY); + if (x == NULL || PyDict_SetItemString(d, "CHANNEL_POLICY", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_CHROMA_THRESHOLD + x = PyInt_FromLong(CL_CHROMA_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "CHROMA_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_CODEC + x = PyInt_FromLong(CL_CODEC); + if (x == NULL || PyDict_SetItemString(d, "CODEC", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COMPONENTS + x = PyInt_FromLong(CL_COMPONENTS); + if (x == NULL || PyDict_SetItemString(d, "COMPONENTS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COMPRESSED_BUFFER_SIZE + x = PyInt_FromLong(CL_COMPRESSED_BUFFER_SIZE); + if (x == NULL || PyDict_SetItemString(d, "COMPRESSED_BUFFER_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COMPRESSION_RATIO + x = PyInt_FromLong(CL_COMPRESSION_RATIO); + if (x == NULL || PyDict_SetItemString(d, "COMPRESSION_RATIO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COMPRESSOR + x = PyInt_FromLong(CL_COMPRESSOR); + if (x == NULL || PyDict_SetItemString(d, "COMPRESSOR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_CONTINUOUS_BLOCK + x = PyInt_FromLong(CL_CONTINUOUS_BLOCK); + if (x == NULL || PyDict_SetItemString(d, "CONTINUOUS_BLOCK", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_CONTINUOUS_NONBLOCK + x = PyInt_FromLong(CL_CONTINUOUS_NONBLOCK); + if (x == NULL || PyDict_SetItemString(d, "CONTINUOUS_NONBLOCK", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COSMO_CODEC_CONTROL + x = PyInt_FromLong(CL_COSMO_CODEC_CONTROL); + if (x == NULL || PyDict_SetItemString(d, "COSMO_CODEC_CONTROL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COSMO_NUM_PARAMS + x = PyInt_FromLong(CL_COSMO_NUM_PARAMS); + if (x == NULL || PyDict_SetItemString(d, "COSMO_NUM_PARAMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COSMO_VALUE_BASE + x = PyInt_FromLong(CL_COSMO_VALUE_BASE); + if (x == NULL || PyDict_SetItemString(d, "COSMO_VALUE_BASE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COSMO_VIDEO_MANUAL_CONTROL + x = PyInt_FromLong(CL_COSMO_VIDEO_MANUAL_CONTROL); + if (x == NULL || PyDict_SetItemString(d, "COSMO_VIDEO_MANUAL_CONTROL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_COSMO_VIDEO_TRANSFER_MODE + x = PyInt_FromLong(CL_COSMO_VIDEO_TRANSFER_MODE); + if (x == NULL || PyDict_SetItemString(d, "COSMO_VIDEO_TRANSFER_MODE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_DATA + x = PyInt_FromLong(CL_DATA); + if (x == NULL || PyDict_SetItemString(d, "DATA", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_DECOMPRESSOR + x = PyInt_FromLong(CL_DECOMPRESSOR); + if (x == NULL || PyDict_SetItemString(d, "DECOMPRESSOR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_DSO_ERROR + x = PyInt_FromLong(CL_DSO_ERROR); + if (x == NULL || PyDict_SetItemString(d, "DSO_ERROR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_EDGE_THRESHOLD + x = PyInt_FromLong(CL_EDGE_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "EDGE_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ENABLE_IMAGEINFO + x = PyInt_FromLong(CL_ENABLE_IMAGEINFO); + if (x == NULL || PyDict_SetItemString(d, "ENABLE_IMAGEINFO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_END_OF_SEQUENCE + x = PyInt_FromLong(CL_END_OF_SEQUENCE); + if (x == NULL || PyDict_SetItemString(d, "END_OF_SEQUENCE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ENUM_VALUE + x = PyInt_FromLong(CL_ENUM_VALUE); + if (x == NULL || PyDict_SetItemString(d, "ENUM_VALUE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_EXACT_COMPRESSION_RATIO + x = PyInt_FromLong(CL_EXACT_COMPRESSION_RATIO); + if (x == NULL || PyDict_SetItemString(d, "EXACT_COMPRESSION_RATIO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_EXTERNAL_DEVICE + x = PyInt_FromLong((long) CL_EXTERNAL_DEVICE); + if (x == NULL || PyDict_SetItemString(d, "EXTERNAL_DEVICE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FLOATING_ENUM_VALUE + x = PyInt_FromLong(CL_FLOATING_ENUM_VALUE); + if (x == NULL || PyDict_SetItemString(d, "FLOATING_ENUM_VALUE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FLOATING_RANGE_VALUE + x = PyInt_FromLong(CL_FLOATING_RANGE_VALUE); + if (x == NULL || PyDict_SetItemString(d, "FLOATING_RANGE_VALUE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT + x = PyInt_FromLong(CL_FORMAT); + if (x == NULL || PyDict_SetItemString(d, "FORMAT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_ABGR + x = PyInt_FromLong(CL_FORMAT_ABGR); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_ABGR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_BGR + x = PyInt_FromLong(CL_FORMAT_BGR); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_BGR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_BGR233 + x = PyInt_FromLong(CL_FORMAT_BGR233); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_BGR233", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_GRAYSCALE + x = PyInt_FromLong(CL_FORMAT_GRAYSCALE); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_GRAYSCALE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_MONO + x = PyInt_FromLong(CL_FORMAT_MONO); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_MONO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_RBG323 + x = PyInt_FromLong(CL_FORMAT_RBG323); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_RBG323", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_STEREO_INTERLEAVED + x = PyInt_FromLong(CL_FORMAT_STEREO_INTERLEAVED); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_STEREO_INTERLEAVED", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_XBGR + x = PyInt_FromLong(CL_FORMAT_XBGR); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_XBGR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_YCbCr + x = PyInt_FromLong(CL_FORMAT_YCbCr); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_YCbCr", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_YCbCr422 + x = PyInt_FromLong(CL_FORMAT_YCbCr422); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_YCbCr422", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FORMAT_YCbCr422DC + x = PyInt_FromLong(CL_FORMAT_YCbCr422DC); + if (x == NULL || PyDict_SetItemString(d, "FORMAT_YCbCr422DC", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAME + x = PyInt_FromLong(CL_FRAME); + if (x == NULL || PyDict_SetItemString(d, "FRAME", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAMES_PER_CHUNK + x = PyInt_FromLong(CL_FRAMES_PER_CHUNK); + if (x == NULL || PyDict_SetItemString(d, "FRAMES_PER_CHUNK", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAME_BUFFER_SIZE + x = PyInt_FromLong(CL_FRAME_BUFFER_SIZE); + if (x == NULL || PyDict_SetItemString(d, "FRAME_BUFFER_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAME_BUFFER_SIZE_ZERO + x = PyInt_FromLong(CL_FRAME_BUFFER_SIZE_ZERO); + if (x == NULL || PyDict_SetItemString(d, "FRAME_BUFFER_SIZE_ZERO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAME_INDEX + x = PyInt_FromLong(CL_FRAME_INDEX); + if (x == NULL || PyDict_SetItemString(d, "FRAME_INDEX", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAME_RATE + x = PyInt_FromLong(CL_FRAME_RATE); + if (x == NULL || PyDict_SetItemString(d, "FRAME_RATE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAME_SIZE + x = PyInt_FromLong(CL_FRAME_SIZE); + if (x == NULL || PyDict_SetItemString(d, "FRAME_SIZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_FRAME_TYPE + x = PyInt_FromLong(CL_FRAME_TYPE); + if (x == NULL || PyDict_SetItemString(d, "FRAME_TYPE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_G711_ALAW + x = PyInt_FromLong(CL_G711_ALAW); + if (x == NULL || PyDict_SetItemString(d, "G711_ALAW", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_G711_ALAW_SOFTWARE + x = PyInt_FromLong(CL_G711_ALAW_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "G711_ALAW_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_G711_ULAW + x = PyInt_FromLong(CL_G711_ULAW); + if (x == NULL || PyDict_SetItemString(d, "G711_ULAW", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_G711_ULAW_SOFTWARE + x = PyInt_FromLong(CL_G711_ULAW_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "G711_ULAW_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_GRAYSCALE + x = PyInt_FromLong(CL_GRAYSCALE); + if (x == NULL || PyDict_SetItemString(d, "GRAYSCALE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_HDCC + x = PyInt_FromLong(CL_HDCC); + if (x == NULL || PyDict_SetItemString(d, "HDCC", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_HDCC_SAMPLES_PER_TILE + x = PyInt_FromLong(CL_HDCC_SAMPLES_PER_TILE); + if (x == NULL || PyDict_SetItemString(d, "HDCC_SAMPLES_PER_TILE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_HDCC_SOFTWARE + x = PyInt_FromLong(CL_HDCC_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "HDCC_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_HDCC_TILE_THRESHOLD + x = PyInt_FromLong(CL_HDCC_TILE_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "HDCC_TILE_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_HEADER_START_CODE + x = PyInt_FromLong(CL_HEADER_START_CODE); + if (x == NULL || PyDict_SetItemString(d, "HEADER_START_CODE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMAGEINFO_FIELDMASK + x = PyInt_FromLong(CL_IMAGEINFO_FIELDMASK); + if (x == NULL || PyDict_SetItemString(d, "IMAGEINFO_FIELDMASK", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMAGE_CROP_BOTTOM + x = PyInt_FromLong(CL_IMAGE_CROP_BOTTOM); + if (x == NULL || PyDict_SetItemString(d, "IMAGE_CROP_BOTTOM", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMAGE_CROP_LEFT + x = PyInt_FromLong(CL_IMAGE_CROP_LEFT); + if (x == NULL || PyDict_SetItemString(d, "IMAGE_CROP_LEFT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMAGE_CROP_RIGHT + x = PyInt_FromLong(CL_IMAGE_CROP_RIGHT); + if (x == NULL || PyDict_SetItemString(d, "IMAGE_CROP_RIGHT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMAGE_CROP_TOP + x = PyInt_FromLong(CL_IMAGE_CROP_TOP); + if (x == NULL || PyDict_SetItemString(d, "IMAGE_CROP_TOP", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMAGE_HEIGHT + x = PyInt_FromLong(CL_IMAGE_HEIGHT); + if (x == NULL || PyDict_SetItemString(d, "IMAGE_HEIGHT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMAGE_WIDTH + x = PyInt_FromLong(CL_IMAGE_WIDTH); + if (x == NULL || PyDict_SetItemString(d, "IMAGE_WIDTH", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMPACT_CODEC_CONTROL + x = PyInt_FromLong(CL_IMPACT_CODEC_CONTROL); + if (x == NULL || PyDict_SetItemString(d, "IMPACT_CODEC_CONTROL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMPACT_FRAME_INTERLEAVE + x = PyInt_FromLong(CL_IMPACT_FRAME_INTERLEAVE); + if (x == NULL || PyDict_SetItemString(d, "IMPACT_FRAME_INTERLEAVE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_IMPACT_NUM_PARAMS + x = PyInt_FromLong(CL_IMPACT_NUM_PARAMS); + if (x == NULL || PyDict_SetItemString(d, "IMPACT_NUM_PARAMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_INTERNAL_FORMAT + x = PyInt_FromLong(CL_INTERNAL_FORMAT); + if (x == NULL || PyDict_SetItemString(d, "INTERNAL_FORMAT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_INTERNAL_IMAGE_HEIGHT + x = PyInt_FromLong(CL_INTERNAL_IMAGE_HEIGHT); + if (x == NULL || PyDict_SetItemString(d, "INTERNAL_IMAGE_HEIGHT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_INTERNAL_IMAGE_WIDTH + x = PyInt_FromLong(CL_INTERNAL_IMAGE_WIDTH); + if (x == NULL || PyDict_SetItemString(d, "INTERNAL_IMAGE_WIDTH", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_INTRA + x = PyInt_FromLong(CL_INTRA); + if (x == NULL || PyDict_SetItemString(d, "INTRA", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG + x = PyInt_FromLong(CL_JPEG); + if (x == NULL || PyDict_SetItemString(d, "JPEG", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_COSMO + x = PyInt_FromLong(CL_JPEG_COSMO); + if (x == NULL || PyDict_SetItemString(d, "JPEG_COSMO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_ERROR + x = PyInt_FromLong(CL_JPEG_ERROR); + if (x == NULL || PyDict_SetItemString(d, "JPEG_ERROR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_IMPACT + x = PyInt_FromLong(CL_JPEG_IMPACT); + if (x == NULL || PyDict_SetItemString(d, "JPEG_IMPACT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_NUM_PARAMS + x = PyInt_FromLong(CL_JPEG_NUM_PARAMS); + if (x == NULL || PyDict_SetItemString(d, "JPEG_NUM_PARAMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_QUALITY_FACTOR + x = PyInt_FromLong(CL_JPEG_QUALITY_FACTOR); + if (x == NULL || PyDict_SetItemString(d, "JPEG_QUALITY_FACTOR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_QUANTIZATION_TABLES + x = PyInt_FromLong(CL_JPEG_QUANTIZATION_TABLES); + if (x == NULL || PyDict_SetItemString(d, "JPEG_QUANTIZATION_TABLES", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_SOFTWARE + x = PyInt_FromLong(CL_JPEG_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "JPEG_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_JPEG_STREAM_HEADERS + x = PyInt_FromLong(CL_JPEG_STREAM_HEADERS); + if (x == NULL || PyDict_SetItemString(d, "JPEG_STREAM_HEADERS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_KEYFRAME + x = PyInt_FromLong(CL_KEYFRAME); + if (x == NULL || PyDict_SetItemString(d, "KEYFRAME", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_KEYFRAME_DISTANCE + x = PyInt_FromLong(CL_KEYFRAME_DISTANCE); + if (x == NULL || PyDict_SetItemString(d, "KEYFRAME_DISTANCE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_LAST_FRAME_INDEX + x = PyInt_FromLong(CL_LAST_FRAME_INDEX); + if (x == NULL || PyDict_SetItemString(d, "LAST_FRAME_INDEX", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_LAYER + x = PyInt_FromLong(CL_LAYER); + if (x == NULL || PyDict_SetItemString(d, "LAYER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_LUMA_THRESHOLD + x = PyInt_FromLong(CL_LUMA_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "LUMA_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MAX_NUMBER_OF_AUDIO_ALGORITHMS + x = PyInt_FromLong(CL_MAX_NUMBER_OF_AUDIO_ALGORITHMS); + if (x == NULL || PyDict_SetItemString(d, "MAX_NUMBER_OF_AUDIO_ALGORITHMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MAX_NUMBER_OF_FORMATS + x = PyInt_FromLong(CL_MAX_NUMBER_OF_FORMATS); + if (x == NULL || PyDict_SetItemString(d, "MAX_NUMBER_OF_FORMATS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MAX_NUMBER_OF_ORIGINAL_FORMATS + x = PyInt_FromLong(CL_MAX_NUMBER_OF_ORIGINAL_FORMATS); + if (x == NULL || PyDict_SetItemString(d, "MAX_NUMBER_OF_ORIGINAL_FORMATS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MAX_NUMBER_OF_PARAMS + x = PyInt_FromLong(CL_MAX_NUMBER_OF_PARAMS); + if (x == NULL || PyDict_SetItemString(d, "MAX_NUMBER_OF_PARAMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MAX_NUMBER_OF_VIDEO_ALGORITHMS + x = PyInt_FromLong(CL_MAX_NUMBER_OF_VIDEO_ALGORITHMS); + if (x == NULL || PyDict_SetItemString(d, "MAX_NUMBER_OF_VIDEO_ALGORITHMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MONO + x = PyInt_FromLong(CL_MONO); + if (x == NULL || PyDict_SetItemString(d, "MONO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_AWARE + x = PyInt_FromLong(CL_MPEG1_AUDIO_AWARE); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_AWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_LAYER + x = PyInt_FromLong(CL_MPEG1_AUDIO_LAYER); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_LAYER", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_LAYER_I + x = PyInt_FromLong(CL_MPEG1_AUDIO_LAYER_I); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_LAYER_I", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_LAYER_II + x = PyInt_FromLong(CL_MPEG1_AUDIO_LAYER_II); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_LAYER_II", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_MODE + x = PyInt_FromLong(CL_MPEG1_AUDIO_MODE); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_MODE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_MODE_DUAL + x = PyInt_FromLong(CL_MPEG1_AUDIO_MODE_DUAL); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_MODE_DUAL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_MODE_JOINT + x = PyInt_FromLong(CL_MPEG1_AUDIO_MODE_JOINT); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_MODE_JOINT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_MODE_SINGLE + x = PyInt_FromLong(CL_MPEG1_AUDIO_MODE_SINGLE); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_MODE_SINGLE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_MODE_STEREO + x = PyInt_FromLong(CL_MPEG1_AUDIO_MODE_STEREO); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_MODE_STEREO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_AUDIO_SOFTWARE + x = PyInt_FromLong(CL_MPEG1_AUDIO_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_AUDIO_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_END_OF_STREAM + x = PyInt_FromLong(CL_MPEG1_END_OF_STREAM); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_END_OF_STREAM", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_ERROR + x = PyInt_FromLong(CL_MPEG1_ERROR); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_ERROR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_NUM_PARAMS + x = PyInt_FromLong(CL_MPEG1_NUM_PARAMS); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_NUM_PARAMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_M + x = PyInt_FromLong(CL_MPEG1_VIDEO_M); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_M", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_B_X + x = PyInt_FromLong(CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_B_X); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_B_X", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_B_Y + x = PyInt_FromLong(CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_B_Y); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_B_Y", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_P_X + x = PyInt_FromLong(CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_P_X); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_P_X", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_P_Y + x = PyInt_FromLong(CL_MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_P_Y); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_MAX_MOTION_VECTOR_LENGTH_P_Y", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_N + x = PyInt_FromLong(CL_MPEG1_VIDEO_N); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_N", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_SOFTNESS + x = PyInt_FromLong(CL_MPEG1_VIDEO_SOFTNESS); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_SOFTNESS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_SOFTNESS_MAXIMUM + x = PyInt_FromLong(CL_MPEG1_VIDEO_SOFTNESS_MAXIMUM); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_SOFTNESS_MAXIMUM", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_SOFTNESS_MEDIUM + x = PyInt_FromLong(CL_MPEG1_VIDEO_SOFTNESS_MEDIUM); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_SOFTNESS_MEDIUM", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_SOFTNESS_NONE + x = PyInt_FromLong(CL_MPEG1_VIDEO_SOFTNESS_NONE); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_SOFTNESS_NONE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG1_VIDEO_SOFTWARE + x = PyInt_FromLong(CL_MPEG1_VIDEO_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "MPEG1_VIDEO_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MPEG_VIDEO + x = PyInt_FromLong(CL_MPEG_VIDEO); + if (x == NULL || PyDict_SetItemString(d, "MPEG_VIDEO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MULTIRATE_AWARE + x = PyInt_FromLong(CL_MULTIRATE_AWARE); + if (x == NULL || PyDict_SetItemString(d, "MULTIRATE_AWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC1 + x = PyInt_FromLong(CL_MVC1); + if (x == NULL || PyDict_SetItemString(d, "MVC1", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC1_SOFTWARE + x = PyInt_FromLong(CL_MVC1_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "MVC1_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2 + x = PyInt_FromLong(CL_MVC2); + if (x == NULL || PyDict_SetItemString(d, "MVC2", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_BLENDING + x = PyInt_FromLong(CL_MVC2_BLENDING); + if (x == NULL || PyDict_SetItemString(d, "MVC2_BLENDING", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_BLENDING_OFF + x = PyInt_FromLong(CL_MVC2_BLENDING_OFF); + if (x == NULL || PyDict_SetItemString(d, "MVC2_BLENDING_OFF", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_BLENDING_ON + x = PyInt_FromLong(CL_MVC2_BLENDING_ON); + if (x == NULL || PyDict_SetItemString(d, "MVC2_BLENDING_ON", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_CHROMA_THRESHOLD + x = PyInt_FromLong(CL_MVC2_CHROMA_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "MVC2_CHROMA_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_EDGE_THRESHOLD + x = PyInt_FromLong(CL_MVC2_EDGE_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "MVC2_EDGE_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_ERROR + x = PyInt_FromLong(CL_MVC2_ERROR); + if (x == NULL || PyDict_SetItemString(d, "MVC2_ERROR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_LUMA_THRESHOLD + x = PyInt_FromLong(CL_MVC2_LUMA_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "MVC2_LUMA_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC2_SOFTWARE + x = PyInt_FromLong(CL_MVC2_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "MVC2_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC3_QUALITY_LEVEL + x = PyInt_FromLong(CL_MVC3_QUALITY_LEVEL); + if (x == NULL || PyDict_SetItemString(d, "MVC3_QUALITY_LEVEL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_MVC3_SOFTWARE + x = PyInt_FromLong(CL_MVC3_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "MVC3_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NEXT_NOT_AVAILABLE + x = PyInt_FromLong(CL_NEXT_NOT_AVAILABLE); + if (x == NULL || PyDict_SetItemString(d, "NEXT_NOT_AVAILABLE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NOISE_MARGIN + x = PyInt_FromLong(CL_NOISE_MARGIN); + if (x == NULL || PyDict_SetItemString(d, "NOISE_MARGIN", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NONE + x = PyInt_FromLong(CL_NONE); + if (x == NULL || PyDict_SetItemString(d, "NONE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NUMBER_OF_FORMATS + x = PyInt_FromLong(CL_NUMBER_OF_FORMATS); + if (x == NULL || PyDict_SetItemString(d, "NUMBER_OF_FORMATS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NUMBER_OF_FRAMES + x = PyInt_FromLong(CL_NUMBER_OF_FRAMES); + if (x == NULL || PyDict_SetItemString(d, "NUMBER_OF_FRAMES", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NUMBER_OF_PARAMS + x = PyInt_FromLong(CL_NUMBER_OF_PARAMS); + if (x == NULL || PyDict_SetItemString(d, "NUMBER_OF_PARAMS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NUMBER_OF_PARAMS_FREEZE + x = PyInt_FromLong(CL_NUMBER_OF_PARAMS_FREEZE); + if (x == NULL || PyDict_SetItemString(d, "NUMBER_OF_PARAMS_FREEZE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_NUMBER_OF_VIDEO_FORMATS + x = PyInt_FromLong(CL_NUMBER_OF_VIDEO_FORMATS); + if (x == NULL || PyDict_SetItemString(d, "NUMBER_OF_VIDEO_FORMATS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ORIENTATION + x = PyInt_FromLong(CL_ORIENTATION); + if (x == NULL || PyDict_SetItemString(d, "ORIENTATION", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ORIGINAL_FORMAT + x = PyInt_FromLong(CL_ORIGINAL_FORMAT); + if (x == NULL || PyDict_SetItemString(d, "ORIGINAL_FORMAT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_PARAM_OUT_OF_RANGE + x = PyInt_FromLong(CL_PARAM_OUT_OF_RANGE); + if (x == NULL || PyDict_SetItemString(d, "PARAM_OUT_OF_RANGE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_PIXEL_ASPECT + x = PyInt_FromLong(CL_PIXEL_ASPECT); + if (x == NULL || PyDict_SetItemString(d, "PIXEL_ASPECT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_PREDICTED + x = PyInt_FromLong(CL_PREDICTED); + if (x == NULL || PyDict_SetItemString(d, "PREDICTED", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_PREROLL + x = PyInt_FromLong(CL_PREROLL); + if (x == NULL || PyDict_SetItemString(d, "PREROLL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_QUALITY_FACTOR + x = PyInt_FromLong(CL_QUALITY_FACTOR); + if (x == NULL || PyDict_SetItemString(d, "QUALITY_FACTOR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_QUALITY_LEVEL + x = PyInt_FromLong(CL_QUALITY_LEVEL); + if (x == NULL || PyDict_SetItemString(d, "QUALITY_LEVEL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_QUALITY_SPATIAL + x = PyInt_FromLong(CL_QUALITY_SPATIAL); + if (x == NULL || PyDict_SetItemString(d, "QUALITY_SPATIAL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_QUALITY_TEMPORAL + x = PyInt_FromLong(CL_QUALITY_TEMPORAL); + if (x == NULL || PyDict_SetItemString(d, "QUALITY_TEMPORAL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_QUANTIZATION_TABLES + x = PyInt_FromLong(CL_QUANTIZATION_TABLES); + if (x == NULL || PyDict_SetItemString(d, "QUANTIZATION_TABLES", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RANGE_VALUE + x = PyInt_FromLong(CL_RANGE_VALUE); + if (x == NULL || PyDict_SetItemString(d, "RANGE_VALUE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RGB + x = PyInt_FromLong(CL_RGB); + if (x == NULL || PyDict_SetItemString(d, "RGB", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RGB332 + x = PyInt_FromLong(CL_RGB332); + if (x == NULL || PyDict_SetItemString(d, "RGB332", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RGB8 + x = PyInt_FromLong(CL_RGB8); + if (x == NULL || PyDict_SetItemString(d, "RGB8", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RGBA + x = PyInt_FromLong(CL_RGBA); + if (x == NULL || PyDict_SetItemString(d, "RGBA", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RGBX + x = PyInt_FromLong(CL_RGBX); + if (x == NULL || PyDict_SetItemString(d, "RGBX", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RLE + x = PyInt_FromLong(CL_RLE); + if (x == NULL || PyDict_SetItemString(d, "RLE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RLE24 + x = PyInt_FromLong(CL_RLE24); + if (x == NULL || PyDict_SetItemString(d, "RLE24", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RLE24_SOFTWARE + x = PyInt_FromLong(CL_RLE24_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "RLE24_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RLE_SOFTWARE + x = PyInt_FromLong(CL_RLE_SOFTWARE); + if (x == NULL || PyDict_SetItemString(d, "RLE_SOFTWARE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RTR + x = PyInt_FromLong(CL_RTR); + if (x == NULL || PyDict_SetItemString(d, "RTR", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RTR1 + x = PyInt_FromLong(CL_RTR1); + if (x == NULL || PyDict_SetItemString(d, "RTR1", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_RTR_QUALITY_LEVEL + x = PyInt_FromLong(CL_RTR_QUALITY_LEVEL); + if (x == NULL || PyDict_SetItemString(d, "RTR_QUALITY_LEVEL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_SAMPLES_PER_TILE + x = PyInt_FromLong(CL_SAMPLES_PER_TILE); + if (x == NULL || PyDict_SetItemString(d, "SAMPLES_PER_TILE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_SCHEME_BUSY + x = PyInt_FromLong(CL_SCHEME_BUSY); + if (x == NULL || PyDict_SetItemString(d, "SCHEME_BUSY", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_SCHEME_NOT_AVAILABLE + x = PyInt_FromLong(CL_SCHEME_NOT_AVAILABLE); + if (x == NULL || PyDict_SetItemString(d, "SCHEME_NOT_AVAILABLE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_SPEED + x = PyInt_FromLong(CL_SPEED); + if (x == NULL || PyDict_SetItemString(d, "SPEED", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_STEREO_INTERLEAVED + x = PyInt_FromLong(CL_STEREO_INTERLEAVED); + if (x == NULL || PyDict_SetItemString(d, "STEREO_INTERLEAVED", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_STREAM_HEADERS + x = PyInt_FromLong(CL_STREAM_HEADERS); + if (x == NULL || PyDict_SetItemString(d, "STREAM_HEADERS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_TILE_THRESHOLD + x = PyInt_FromLong(CL_TILE_THRESHOLD); + if (x == NULL || PyDict_SetItemString(d, "TILE_THRESHOLD", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_TOP_DOWN + x = PyInt_FromLong(CL_TOP_DOWN); + if (x == NULL || PyDict_SetItemString(d, "TOP_DOWN", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_ULAW + x = PyInt_FromLong(CL_ULAW); + if (x == NULL || PyDict_SetItemString(d, "ULAW", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_UNCOMPRESSED + x = PyInt_FromLong(CL_UNCOMPRESSED); + if (x == NULL || PyDict_SetItemString(d, "UNCOMPRESSED", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_UNCOMPRESSED_AUDIO + x = PyInt_FromLong(CL_UNCOMPRESSED_AUDIO); + if (x == NULL || PyDict_SetItemString(d, "UNCOMPRESSED_AUDIO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_UNCOMPRESSED_VIDEO + x = PyInt_FromLong(CL_UNCOMPRESSED_VIDEO); + if (x == NULL || PyDict_SetItemString(d, "UNCOMPRESSED_VIDEO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_UNKNOWN_SCHEME + x = PyInt_FromLong(CL_UNKNOWN_SCHEME); + if (x == NULL || PyDict_SetItemString(d, "UNKNOWN_SCHEME", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_VIDEO + x = PyInt_FromLong(CL_VIDEO); + if (x == NULL || PyDict_SetItemString(d, "VIDEO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_Y + x = PyInt_FromLong(CL_Y); + if (x == NULL || PyDict_SetItemString(d, "Y", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YCbCr + x = PyInt_FromLong(CL_YCbCr); + if (x == NULL || PyDict_SetItemString(d, "YCbCr", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YCbCr422 + x = PyInt_FromLong(CL_YCbCr422); + if (x == NULL || PyDict_SetItemString(d, "YCbCr422", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YCbCr422DC + x = PyInt_FromLong(CL_YCbCr422DC); + if (x == NULL || PyDict_SetItemString(d, "YCbCr422DC", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YCbCr422HC + x = PyInt_FromLong(CL_YCbCr422HC); + if (x == NULL || PyDict_SetItemString(d, "YCbCr422HC", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YUV + x = PyInt_FromLong(CL_YUV); + if (x == NULL || PyDict_SetItemString(d, "YUV", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YUV422 + x = PyInt_FromLong(CL_YUV422); + if (x == NULL || PyDict_SetItemString(d, "YUV422", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YUV422DC + x = PyInt_FromLong(CL_YUV422DC); + if (x == NULL || PyDict_SetItemString(d, "YUV422DC", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef CL_YUV422HC + x = PyInt_FromLong(CL_YUV422HC); + if (x == NULL || PyDict_SetItemString(d, "YUV422HC", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_STEREO + x = PyInt_FromLong(AWCMP_STEREO); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_STEREO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_JOINT_STEREO + x = PyInt_FromLong(AWCMP_JOINT_STEREO); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_JOINT_STEREO", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_INDEPENDENT + x = PyInt_FromLong(AWCMP_INDEPENDENT); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_INDEPENDENT", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_FIXED_RATE + x = PyInt_FromLong(AWCMP_FIXED_RATE); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_FIXED_RATE", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_CONST_QUAL + x = PyInt_FromLong(AWCMP_CONST_QUAL); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_CONST_QUAL", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_LOSSLESS + x = PyInt_FromLong(AWCMP_LOSSLESS); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_LOSSLESS", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_MPEG_LAYER_I + x = PyInt_FromLong(AWCMP_MPEG_LAYER_I); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_MPEG_LAYER_I", x) < 0) + return; + Py_DECREF(x); +#endif +#ifdef AWCMP_MPEG_LAYER_II + x = PyInt_FromLong(AWCMP_MPEG_LAYER_II); + if (x == NULL || PyDict_SetItemString(d, "AWCMP_MPEG_LAYER_II", x) < 0) + return; + Py_DECREF(x); +#endif + + (void) clSetErrorHandler(cl_ErrorHandler); +} diff --git a/sys/src/cmd/python/Modules/cmathmodule.c b/sys/src/cmd/python/Modules/cmathmodule.c new file mode 100644 index 000000000..ec48ce8d7 --- /dev/null +++ b/sys/src/cmd/python/Modules/cmathmodule.c @@ -0,0 +1,426 @@ +/* Complex math module */ + +/* much code borrowed from mathmodule.c */ + +#include "Python.h" + +#ifndef M_PI +#define M_PI (3.141592653589793239) +#endif + +/* First, the C functions that do the real work */ + +/* constants */ +static Py_complex c_one = {1., 0.}; +static Py_complex c_half = {0.5, 0.}; +static Py_complex c_i = {0., 1.}; +static Py_complex c_halfi = {0., 0.5}; + +/* forward declarations */ +static Py_complex c_log(Py_complex); +static Py_complex c_prodi(Py_complex); +static Py_complex c_sqrt(Py_complex); +static PyObject * math_error(void); + + +static Py_complex +c_acos(Py_complex x) +{ + return c_neg(c_prodi(c_log(c_sum(x,c_prod(c_i, + c_sqrt(c_diff(c_one,c_prod(x,x)))))))); +} + +PyDoc_STRVAR(c_acos_doc, +"acos(x)\n" +"\n" +"Return the arc cosine of x."); + + +static Py_complex +c_acosh(Py_complex x) +{ + Py_complex z; + z = c_sqrt(c_half); + z = c_log(c_prod(z, c_sum(c_sqrt(c_sum(x,c_one)), + c_sqrt(c_diff(x,c_one))))); + return c_sum(z, z); +} + +PyDoc_STRVAR(c_acosh_doc, +"acosh(x)\n" +"\n" +"Return the hyperbolic arccosine of x."); + + +static Py_complex +c_asin(Py_complex x) +{ + /* -i * log[(sqrt(1-x**2) + i*x] */ + const Py_complex squared = c_prod(x, x); + const Py_complex sqrt_1_minus_x_sq = c_sqrt(c_diff(c_one, squared)); + return c_neg(c_prodi(c_log( + c_sum(sqrt_1_minus_x_sq, c_prodi(x)) + ) ) ); +} + +PyDoc_STRVAR(c_asin_doc, +"asin(x)\n" +"\n" +"Return the arc sine of x."); + + +static Py_complex +c_asinh(Py_complex x) +{ + Py_complex z; + z = c_sqrt(c_half); + z = c_log(c_prod(z, c_sum(c_sqrt(c_sum(x, c_i)), + c_sqrt(c_diff(x, c_i))))); + return c_sum(z, z); +} + +PyDoc_STRVAR(c_asinh_doc, +"asinh(x)\n" +"\n" +"Return the hyperbolic arc sine of x."); + + +static Py_complex +c_atan(Py_complex x) +{ + return c_prod(c_halfi,c_log(c_quot(c_sum(c_i,x),c_diff(c_i,x)))); +} + +PyDoc_STRVAR(c_atan_doc, +"atan(x)\n" +"\n" +"Return the arc tangent of x."); + + +static Py_complex +c_atanh(Py_complex x) +{ + return c_prod(c_half,c_log(c_quot(c_sum(c_one,x),c_diff(c_one,x)))); +} + +PyDoc_STRVAR(c_atanh_doc, +"atanh(x)\n" +"\n" +"Return the hyperbolic arc tangent of x."); + + +static Py_complex +c_cos(Py_complex x) +{ + Py_complex r; + r.real = cos(x.real)*cosh(x.imag); + r.imag = -sin(x.real)*sinh(x.imag); + return r; +} + +PyDoc_STRVAR(c_cos_doc, +"cos(x)\n" +"n" +"Return the cosine of x."); + + +static Py_complex +c_cosh(Py_complex x) +{ + Py_complex r; + r.real = cos(x.imag)*cosh(x.real); + r.imag = sin(x.imag)*sinh(x.real); + return r; +} + +PyDoc_STRVAR(c_cosh_doc, +"cosh(x)\n" +"n" +"Return the hyperbolic cosine of x."); + + +static Py_complex +c_exp(Py_complex x) +{ + Py_complex r; + double l = exp(x.real); + r.real = l*cos(x.imag); + r.imag = l*sin(x.imag); + return r; +} + +PyDoc_STRVAR(c_exp_doc, +"exp(x)\n" +"\n" +"Return the exponential value e**x."); + + +static Py_complex +c_log(Py_complex x) +{ + Py_complex r; + double l = hypot(x.real,x.imag); + r.imag = atan2(x.imag, x.real); + r.real = log(l); + return r; +} + + +static Py_complex +c_log10(Py_complex x) +{ + Py_complex r; + double l = hypot(x.real,x.imag); + r.imag = atan2(x.imag, x.real)/log(10.); + r.real = log10(l); + return r; +} + +PyDoc_STRVAR(c_log10_doc, +"log10(x)\n" +"\n" +"Return the base-10 logarithm of x."); + + +/* internal function not available from Python */ +static Py_complex +c_prodi(Py_complex x) +{ + Py_complex r; + r.real = -x.imag; + r.imag = x.real; + return r; +} + + +static Py_complex +c_sin(Py_complex x) +{ + Py_complex r; + r.real = sin(x.real) * cosh(x.imag); + r.imag = cos(x.real) * sinh(x.imag); + return r; +} + +PyDoc_STRVAR(c_sin_doc, +"sin(x)\n" +"\n" +"Return the sine of x."); + + +static Py_complex +c_sinh(Py_complex x) +{ + Py_complex r; + r.real = cos(x.imag) * sinh(x.real); + r.imag = sin(x.imag) * cosh(x.real); + return r; +} + +PyDoc_STRVAR(c_sinh_doc, +"sinh(x)\n" +"\n" +"Return the hyperbolic sine of x."); + + +static Py_complex +c_sqrt(Py_complex x) +{ + Py_complex r; + double s,d; + if (x.real == 0. && x.imag == 0.) + r = x; + else { + s = sqrt(0.5*(fabs(x.real) + hypot(x.real,x.imag))); + d = 0.5*x.imag/s; + if (x.real > 0.) { + r.real = s; + r.imag = d; + } + else if (x.imag >= 0.) { + r.real = d; + r.imag = s; + } + else { + r.real = -d; + r.imag = -s; + } + } + return r; +} + +PyDoc_STRVAR(c_sqrt_doc, +"sqrt(x)\n" +"\n" +"Return the square root of x."); + + +static Py_complex +c_tan(Py_complex x) +{ + Py_complex r; + double sr,cr,shi,chi; + double rs,is,rc,ic; + double d; + sr = sin(x.real); + cr = cos(x.real); + shi = sinh(x.imag); + chi = cosh(x.imag); + rs = sr * chi; + is = cr * shi; + rc = cr * chi; + ic = -sr * shi; + d = rc*rc + ic * ic; + r.real = (rs*rc + is*ic) / d; + r.imag = (is*rc - rs*ic) / d; + return r; +} + +PyDoc_STRVAR(c_tan_doc, +"tan(x)\n" +"\n" +"Return the tangent of x."); + + +static Py_complex +c_tanh(Py_complex x) +{ + Py_complex r; + double si,ci,shr,chr; + double rs,is,rc,ic; + double d; + si = sin(x.imag); + ci = cos(x.imag); + shr = sinh(x.real); + chr = cosh(x.real); + rs = ci * shr; + is = si * chr; + rc = ci * chr; + ic = si * shr; + d = rc*rc + ic*ic; + r.real = (rs*rc + is*ic) / d; + r.imag = (is*rc - rs*ic) / d; + return r; +} + +PyDoc_STRVAR(c_tanh_doc, +"tanh(x)\n" +"\n" +"Return the hyperbolic tangent of x."); + +static PyObject * +cmath_log(PyObject *self, PyObject *args) +{ + Py_complex x; + Py_complex y; + + if (!PyArg_ParseTuple(args, "D|D", &x, &y)) + return NULL; + + errno = 0; + PyFPE_START_PROTECT("complex function", return 0) + x = c_log(x); + if (PyTuple_GET_SIZE(args) == 2) + x = c_quot(x, c_log(y)); + PyFPE_END_PROTECT(x) + if (errno != 0) + return math_error(); + Py_ADJUST_ERANGE2(x.real, x.imag); + return PyComplex_FromCComplex(x); +} + +PyDoc_STRVAR(cmath_log_doc, +"log(x[, base]) -> the logarithm of x to the given base.\n\ +If the base not specified, returns the natural logarithm (base e) of x."); + + +/* And now the glue to make them available from Python: */ + +static PyObject * +math_error(void) +{ + if (errno == EDOM) + PyErr_SetString(PyExc_ValueError, "math domain error"); + else if (errno == ERANGE) + PyErr_SetString(PyExc_OverflowError, "math range error"); + else /* Unexpected math error */ + PyErr_SetFromErrno(PyExc_ValueError); + return NULL; +} + +static PyObject * +math_1(PyObject *args, Py_complex (*func)(Py_complex)) +{ + Py_complex x; + if (!PyArg_ParseTuple(args, "D", &x)) + return NULL; + errno = 0; + PyFPE_START_PROTECT("complex function", return 0) + x = (*func)(x); + PyFPE_END_PROTECT(x) + Py_ADJUST_ERANGE2(x.real, x.imag); + if (errno != 0) + return math_error(); + else + return PyComplex_FromCComplex(x); +} + +#define FUNC1(stubname, func) \ + static PyObject * stubname(PyObject *self, PyObject *args) { \ + return math_1(args, func); \ + } + +FUNC1(cmath_acos, c_acos) +FUNC1(cmath_acosh, c_acosh) +FUNC1(cmath_asin, c_asin) +FUNC1(cmath_asinh, c_asinh) +FUNC1(cmath_atan, c_atan) +FUNC1(cmath_atanh, c_atanh) +FUNC1(cmath_cos, c_cos) +FUNC1(cmath_cosh, c_cosh) +FUNC1(cmath_exp, c_exp) +FUNC1(cmath_log10, c_log10) +FUNC1(cmath_sin, c_sin) +FUNC1(cmath_sinh, c_sinh) +FUNC1(cmath_sqrt, c_sqrt) +FUNC1(cmath_tan, c_tan) +FUNC1(cmath_tanh, c_tanh) + + +PyDoc_STRVAR(module_doc, +"This module is always available. It provides access to mathematical\n" +"functions for complex numbers."); + +static PyMethodDef cmath_methods[] = { + {"acos", cmath_acos, METH_VARARGS, c_acos_doc}, + {"acosh", cmath_acosh, METH_VARARGS, c_acosh_doc}, + {"asin", cmath_asin, METH_VARARGS, c_asin_doc}, + {"asinh", cmath_asinh, METH_VARARGS, c_asinh_doc}, + {"atan", cmath_atan, METH_VARARGS, c_atan_doc}, + {"atanh", cmath_atanh, METH_VARARGS, c_atanh_doc}, + {"cos", cmath_cos, METH_VARARGS, c_cos_doc}, + {"cosh", cmath_cosh, METH_VARARGS, c_cosh_doc}, + {"exp", cmath_exp, METH_VARARGS, c_exp_doc}, + {"log", cmath_log, METH_VARARGS, cmath_log_doc}, + {"log10", cmath_log10, METH_VARARGS, c_log10_doc}, + {"sin", cmath_sin, METH_VARARGS, c_sin_doc}, + {"sinh", cmath_sinh, METH_VARARGS, c_sinh_doc}, + {"sqrt", cmath_sqrt, METH_VARARGS, c_sqrt_doc}, + {"tan", cmath_tan, METH_VARARGS, c_tan_doc}, + {"tanh", cmath_tanh, METH_VARARGS, c_tanh_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +initcmath(void) +{ + PyObject *m; + + m = Py_InitModule3("cmath", cmath_methods, module_doc); + if (m == NULL) + return; + + PyModule_AddObject(m, "pi", + PyFloat_FromDouble(atan(1.0) * 4.0)); + PyModule_AddObject(m, "e", PyFloat_FromDouble(exp(1.0))); +} diff --git a/sys/src/cmd/python/Modules/collectionsmodule.c b/sys/src/cmd/python/Modules/collectionsmodule.c new file mode 100644 index 000000000..9d128fc95 --- /dev/null +++ b/sys/src/cmd/python/Modules/collectionsmodule.c @@ -0,0 +1,1370 @@ +#include "Python.h" +#include "structmember.h" + +/* collections module implementation of a deque() datatype + Written and maintained by Raymond D. Hettinger <python@rcn.com> + Copyright (c) 2004 Python Software Foundation. + All rights reserved. +*/ + +/* The block length may be set to any number over 1. Larger numbers + * reduce the number of calls to the memory allocator but take more + * memory. Ideally, BLOCKLEN should be set with an eye to the + * length of a cache line. + */ + +#define BLOCKLEN 62 +#define CENTER ((BLOCKLEN - 1) / 2) + +/* A `dequeobject` is composed of a doubly-linked list of `block` nodes. + * This list is not circular (the leftmost block has leftlink==NULL, + * and the rightmost block has rightlink==NULL). A deque d's first + * element is at d.leftblock[leftindex] and its last element is at + * d.rightblock[rightindex]; note that, unlike as for Python slice + * indices, these indices are inclusive on both ends. By being inclusive + * on both ends, algorithms for left and right operations become + * symmetrical which simplifies the design. + * + * The list of blocks is never empty, so d.leftblock and d.rightblock + * are never equal to NULL. + * + * The indices, d.leftindex and d.rightindex are always in the range + * 0 <= index < BLOCKLEN. + * Their exact relationship is: + * (d.leftindex + d.len - 1) % BLOCKLEN == d.rightindex. + * + * Empty deques have d.len == 0; d.leftblock==d.rightblock; + * d.leftindex == CENTER+1; and d.rightindex == CENTER. + * Checking for d.len == 0 is the intended way to see whether d is empty. + * + * Whenever d.leftblock == d.rightblock, + * d.leftindex + d.len - 1 == d.rightindex. + * + * However, when d.leftblock != d.rightblock, d.leftindex and d.rightindex + * become indices into distinct blocks and either may be larger than the + * other. + */ + +typedef struct BLOCK { + struct BLOCK *leftlink; + struct BLOCK *rightlink; + PyObject *data[BLOCKLEN]; +} block; + +static block * +newblock(block *leftlink, block *rightlink, int len) { + block *b; + /* To prevent len from overflowing INT_MAX on 64-bit machines, we + * refuse to allocate new blocks if the current len is dangerously + * close. There is some extra margin to prevent spurious arithmetic + * overflows at various places. The following check ensures that + * the blocks allocated to the deque, in the worst case, can only + * have INT_MAX-2 entries in total. + */ + if (len >= INT_MAX - 2*BLOCKLEN) { + PyErr_SetString(PyExc_OverflowError, + "cannot add more blocks to the deque"); + return NULL; + } + b = PyMem_Malloc(sizeof(block)); + if (b == NULL) { + PyErr_NoMemory(); + return NULL; + } + b->leftlink = leftlink; + b->rightlink = rightlink; + return b; +} + +typedef struct { + PyObject_HEAD + block *leftblock; + block *rightblock; + int leftindex; /* in range(BLOCKLEN) */ + int rightindex; /* in range(BLOCKLEN) */ + int len; + long state; /* incremented whenever the indices move */ + PyObject *weakreflist; /* List of weak references */ +} dequeobject; + +static PyTypeObject deque_type; + +static PyObject * +deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + dequeobject *deque; + block *b; + + if (type == &deque_type && !_PyArg_NoKeywords("deque()", kwds)) + return NULL; + + /* create dequeobject structure */ + deque = (dequeobject *)type->tp_alloc(type, 0); + if (deque == NULL) + return NULL; + + b = newblock(NULL, NULL, 0); + if (b == NULL) { + Py_DECREF(deque); + return NULL; + } + + assert(BLOCKLEN >= 2); + deque->leftblock = b; + deque->rightblock = b; + deque->leftindex = CENTER + 1; + deque->rightindex = CENTER; + deque->len = 0; + deque->state = 0; + deque->weakreflist = NULL; + + return (PyObject *)deque; +} + +static PyObject * +deque_append(dequeobject *deque, PyObject *item) +{ + deque->state++; + if (deque->rightindex == BLOCKLEN-1) { + block *b = newblock(deque->rightblock, NULL, deque->len); + if (b == NULL) + return NULL; + assert(deque->rightblock->rightlink == NULL); + deque->rightblock->rightlink = b; + deque->rightblock = b; + deque->rightindex = -1; + } + Py_INCREF(item); + deque->len++; + deque->rightindex++; + deque->rightblock->data[deque->rightindex] = item; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(append_doc, "Add an element to the right side of the deque."); + +static PyObject * +deque_appendleft(dequeobject *deque, PyObject *item) +{ + deque->state++; + if (deque->leftindex == 0) { + block *b = newblock(NULL, deque->leftblock, deque->len); + if (b == NULL) + return NULL; + assert(deque->leftblock->leftlink == NULL); + deque->leftblock->leftlink = b; + deque->leftblock = b; + deque->leftindex = BLOCKLEN; + } + Py_INCREF(item); + deque->len++; + deque->leftindex--; + deque->leftblock->data[deque->leftindex] = item; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(appendleft_doc, "Add an element to the left side of the deque."); + +static PyObject * +deque_pop(dequeobject *deque, PyObject *unused) +{ + PyObject *item; + block *prevblock; + + if (deque->len == 0) { + PyErr_SetString(PyExc_IndexError, "pop from an empty deque"); + return NULL; + } + item = deque->rightblock->data[deque->rightindex]; + deque->rightindex--; + deque->len--; + deque->state++; + + if (deque->rightindex == -1) { + if (deque->len == 0) { + assert(deque->leftblock == deque->rightblock); + assert(deque->leftindex == deque->rightindex+1); + /* re-center instead of freeing a block */ + deque->leftindex = CENTER + 1; + deque->rightindex = CENTER; + } else { + prevblock = deque->rightblock->leftlink; + assert(deque->leftblock != deque->rightblock); + PyMem_Free(deque->rightblock); + prevblock->rightlink = NULL; + deque->rightblock = prevblock; + deque->rightindex = BLOCKLEN - 1; + } + } + return item; +} + +PyDoc_STRVAR(pop_doc, "Remove and return the rightmost element."); + +static PyObject * +deque_popleft(dequeobject *deque, PyObject *unused) +{ + PyObject *item; + block *prevblock; + + if (deque->len == 0) { + PyErr_SetString(PyExc_IndexError, "pop from an empty deque"); + return NULL; + } + assert(deque->leftblock != NULL); + item = deque->leftblock->data[deque->leftindex]; + deque->leftindex++; + deque->len--; + deque->state++; + + if (deque->leftindex == BLOCKLEN) { + if (deque->len == 0) { + assert(deque->leftblock == deque->rightblock); + assert(deque->leftindex == deque->rightindex+1); + /* re-center instead of freeing a block */ + deque->leftindex = CENTER + 1; + deque->rightindex = CENTER; + } else { + assert(deque->leftblock != deque->rightblock); + prevblock = deque->leftblock->rightlink; + PyMem_Free(deque->leftblock); + assert(prevblock != NULL); + prevblock->leftlink = NULL; + deque->leftblock = prevblock; + deque->leftindex = 0; + } + } + return item; +} + +PyDoc_STRVAR(popleft_doc, "Remove and return the leftmost element."); + +static PyObject * +deque_extend(dequeobject *deque, PyObject *iterable) +{ + PyObject *it, *item; + + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + + while ((item = PyIter_Next(it)) != NULL) { + deque->state++; + if (deque->rightindex == BLOCKLEN-1) { + block *b = newblock(deque->rightblock, NULL, + deque->len); + if (b == NULL) { + Py_DECREF(item); + Py_DECREF(it); + return NULL; + } + assert(deque->rightblock->rightlink == NULL); + deque->rightblock->rightlink = b; + deque->rightblock = b; + deque->rightindex = -1; + } + deque->len++; + deque->rightindex++; + deque->rightblock->data[deque->rightindex] = item; + } + Py_DECREF(it); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(extend_doc, +"Extend the right side of the deque with elements from the iterable"); + +static PyObject * +deque_extendleft(dequeobject *deque, PyObject *iterable) +{ + PyObject *it, *item; + + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + + while ((item = PyIter_Next(it)) != NULL) { + deque->state++; + if (deque->leftindex == 0) { + block *b = newblock(NULL, deque->leftblock, + deque->len); + if (b == NULL) { + Py_DECREF(item); + Py_DECREF(it); + return NULL; + } + assert(deque->leftblock->leftlink == NULL); + deque->leftblock->leftlink = b; + deque->leftblock = b; + deque->leftindex = BLOCKLEN; + } + deque->len++; + deque->leftindex--; + deque->leftblock->data[deque->leftindex] = item; + } + Py_DECREF(it); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(extendleft_doc, +"Extend the left side of the deque with elements from the iterable"); + +static int +_deque_rotate(dequeobject *deque, Py_ssize_t n) +{ + int i, len=deque->len, halflen=(len+1)>>1; + PyObject *item, *rv; + + if (len == 0) + return 0; + if (n > halflen || n < -halflen) { + n %= len; + if (n > halflen) + n -= len; + else if (n < -halflen) + n += len; + } + + for (i=0 ; i<n ; i++) { + item = deque_pop(deque, NULL); + assert (item != NULL); + rv = deque_appendleft(deque, item); + Py_DECREF(item); + if (rv == NULL) + return -1; + Py_DECREF(rv); + } + for (i=0 ; i>n ; i--) { + item = deque_popleft(deque, NULL); + assert (item != NULL); + rv = deque_append(deque, item); + Py_DECREF(item); + if (rv == NULL) + return -1; + Py_DECREF(rv); + } + return 0; +} + +static PyObject * +deque_rotate(dequeobject *deque, PyObject *args) +{ + int n=1; + + if (!PyArg_ParseTuple(args, "|i:rotate", &n)) + return NULL; + if (_deque_rotate(deque, n) == 0) + Py_RETURN_NONE; + return NULL; +} + +PyDoc_STRVAR(rotate_doc, +"Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); + +static Py_ssize_t +deque_len(dequeobject *deque) +{ + return deque->len; +} + +static PyObject * +deque_remove(dequeobject *deque, PyObject *value) +{ + Py_ssize_t i, n=deque->len; + + for (i=0 ; i<n ; i++) { + PyObject *item = deque->leftblock->data[deque->leftindex]; + int cmp = PyObject_RichCompareBool(item, value, Py_EQ); + + if (deque->len != n) { + PyErr_SetString(PyExc_IndexError, + "deque mutated during remove()."); + return NULL; + } + if (cmp > 0) { + PyObject *tgt = deque_popleft(deque, NULL); + assert (tgt != NULL); + Py_DECREF(tgt); + if (_deque_rotate(deque, i) == -1) + return NULL; + Py_RETURN_NONE; + } + else if (cmp < 0) { + _deque_rotate(deque, i); + return NULL; + } + _deque_rotate(deque, -1); + } + PyErr_SetString(PyExc_ValueError, "deque.remove(x): x not in deque"); + return NULL; +} + +PyDoc_STRVAR(remove_doc, +"D.remove(value) -- remove first occurrence of value."); + +static int +deque_clear(dequeobject *deque) +{ + PyObject *item; + + while (deque->len) { + item = deque_pop(deque, NULL); + assert (item != NULL); + Py_DECREF(item); + } + assert(deque->leftblock == deque->rightblock && + deque->leftindex - 1 == deque->rightindex && + deque->len == 0); + return 0; +} + +static PyObject * +deque_item(dequeobject *deque, int i) +{ + block *b; + PyObject *item; + int n, index=i; + + if (i < 0 || i >= deque->len) { + PyErr_SetString(PyExc_IndexError, + "deque index out of range"); + return NULL; + } + + if (i == 0) { + i = deque->leftindex; + b = deque->leftblock; + } else if (i == deque->len - 1) { + i = deque->rightindex; + b = deque->rightblock; + } else { + i += deque->leftindex; + n = i / BLOCKLEN; + i %= BLOCKLEN; + if (index < (deque->len >> 1)) { + b = deque->leftblock; + while (n--) + b = b->rightlink; + } else { + n = (deque->leftindex + deque->len - 1) / BLOCKLEN - n; + b = deque->rightblock; + while (n--) + b = b->leftlink; + } + } + item = b->data[i]; + Py_INCREF(item); + return item; +} + +/* delitem() implemented in terms of rotate for simplicity and reasonable + performance near the end points. If for some reason this method becomes + popular, it is not hard to re-implement this using direct data movement + (similar to code in list slice assignment) and achieve a two or threefold + performance boost. +*/ + +static int +deque_del_item(dequeobject *deque, Py_ssize_t i) +{ + PyObject *item; + + assert (i >= 0 && i < deque->len); + if (_deque_rotate(deque, -i) == -1) + return -1; + + item = deque_popleft(deque, NULL); + assert (item != NULL); + Py_DECREF(item); + + return _deque_rotate(deque, i); +} + +static int +deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v) +{ + PyObject *old_value; + block *b; + Py_ssize_t n, len=deque->len, halflen=(len+1)>>1, index=i; + + if (i < 0 || i >= len) { + PyErr_SetString(PyExc_IndexError, + "deque index out of range"); + return -1; + } + if (v == NULL) + return deque_del_item(deque, i); + + i += deque->leftindex; + n = i / BLOCKLEN; + i %= BLOCKLEN; + if (index <= halflen) { + b = deque->leftblock; + while (n--) + b = b->rightlink; + } else { + n = (deque->leftindex + len - 1) / BLOCKLEN - n; + b = deque->rightblock; + while (n--) + b = b->leftlink; + } + Py_INCREF(v); + old_value = b->data[i]; + b->data[i] = v; + Py_DECREF(old_value); + return 0; +} + +static PyObject * +deque_clearmethod(dequeobject *deque) +{ + int rv; + + rv = deque_clear(deque); + assert (rv != -1); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(clear_doc, "Remove all elements from the deque."); + +static void +deque_dealloc(dequeobject *deque) +{ + PyObject_GC_UnTrack(deque); + if (deque->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) deque); + if (deque->leftblock != NULL) { + deque_clear(deque); + assert(deque->leftblock != NULL); + PyMem_Free(deque->leftblock); + } + deque->leftblock = NULL; + deque->rightblock = NULL; + deque->ob_type->tp_free(deque); +} + +static int +deque_traverse(dequeobject *deque, visitproc visit, void *arg) +{ + block *b; + PyObject *item; + int index; + int indexlo = deque->leftindex; + + for (b = deque->leftblock; b != NULL; b = b->rightlink) { + const int indexhi = b == deque->rightblock ? + deque->rightindex : + BLOCKLEN - 1; + + for (index = indexlo; index <= indexhi; ++index) { + item = b->data[index]; + Py_VISIT(item); + } + indexlo = 0; + } + return 0; +} + +static long +deque_nohash(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "deque objects are unhashable"); + return -1; +} + +static PyObject * +deque_copy(PyObject *deque) +{ + return PyObject_CallFunctionObjArgs((PyObject *)(deque->ob_type), + deque, NULL); +} + +PyDoc_STRVAR(copy_doc, "Return a shallow copy of a deque."); + +static PyObject * +deque_reduce(dequeobject *deque) +{ + PyObject *dict, *result, *it; + + dict = PyObject_GetAttrString((PyObject *)deque, "__dict__"); + if (dict == NULL) { + PyErr_Clear(); + dict = Py_None; + Py_INCREF(dict); + } + it = PyObject_GetIter((PyObject *)deque); + if (it == NULL) { + Py_DECREF(dict); + return NULL; + } + result = Py_BuildValue("O()ON", deque->ob_type, dict, it); + Py_DECREF(dict); + return result; +} + +PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); + +static PyObject * +deque_repr(PyObject *deque) +{ + PyObject *aslist, *result, *fmt; + int i; + + i = Py_ReprEnter(deque); + if (i != 0) { + if (i < 0) + return NULL; + return PyString_FromString("[...]"); + } + + aslist = PySequence_List(deque); + if (aslist == NULL) { + Py_ReprLeave(deque); + return NULL; + } + + fmt = PyString_FromString("deque(%r)"); + if (fmt == NULL) { + Py_DECREF(aslist); + Py_ReprLeave(deque); + return NULL; + } + result = PyString_Format(fmt, aslist); + Py_DECREF(fmt); + Py_DECREF(aslist); + Py_ReprLeave(deque); + return result; +} + +static int +deque_tp_print(PyObject *deque, FILE *fp, int flags) +{ + PyObject *it, *item; + char *emit = ""; /* No separator emitted on first pass */ + char *separator = ", "; + int i; + + i = Py_ReprEnter(deque); + if (i != 0) { + if (i < 0) + return i; + fputs("[...]", fp); + return 0; + } + + it = PyObject_GetIter(deque); + if (it == NULL) + return -1; + + fputs("deque([", fp); + while ((item = PyIter_Next(it)) != NULL) { + fputs(emit, fp); + emit = separator; + if (PyObject_Print(item, fp, 0) != 0) { + Py_DECREF(item); + Py_DECREF(it); + Py_ReprLeave(deque); + return -1; + } + Py_DECREF(item); + } + Py_ReprLeave(deque); + Py_DECREF(it); + if (PyErr_Occurred()) + return -1; + fputs("])", fp); + return 0; +} + +static PyObject * +deque_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *it1=NULL, *it2=NULL, *x, *y; + int b, vs, ws, cmp=-1; + + if (!PyObject_TypeCheck(v, &deque_type) || + !PyObject_TypeCheck(w, &deque_type)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + /* Shortcuts */ + vs = ((dequeobject *)v)->len; + ws = ((dequeobject *)w)->len; + if (op == Py_EQ) { + if (v == w) + Py_RETURN_TRUE; + if (vs != ws) + Py_RETURN_FALSE; + } + if (op == Py_NE) { + if (v == w) + Py_RETURN_FALSE; + if (vs != ws) + Py_RETURN_TRUE; + } + + /* Search for the first index where items are different */ + it1 = PyObject_GetIter(v); + if (it1 == NULL) + goto done; + it2 = PyObject_GetIter(w); + if (it2 == NULL) + goto done; + for (;;) { + x = PyIter_Next(it1); + if (x == NULL && PyErr_Occurred()) + goto done; + y = PyIter_Next(it2); + if (x == NULL || y == NULL) + break; + b = PyObject_RichCompareBool(x, y, Py_EQ); + if (b == 0) { + cmp = PyObject_RichCompareBool(x, y, op); + Py_DECREF(x); + Py_DECREF(y); + goto done; + } + Py_DECREF(x); + Py_DECREF(y); + if (b == -1) + goto done; + } + /* We reached the end of one deque or both */ + Py_XDECREF(x); + Py_XDECREF(y); + if (PyErr_Occurred()) + goto done; + switch (op) { + case Py_LT: cmp = y != NULL; break; /* if w was longer */ + case Py_LE: cmp = x == NULL; break; /* if v was not longer */ + case Py_EQ: cmp = x == y; break; /* if we reached the end of both */ + case Py_NE: cmp = x != y; break; /* if one deque continues */ + case Py_GT: cmp = x != NULL; break; /* if v was longer */ + case Py_GE: cmp = y == NULL; break; /* if w was not longer */ + } + +done: + Py_XDECREF(it1); + Py_XDECREF(it2); + if (cmp == 1) + Py_RETURN_TRUE; + if (cmp == 0) + Py_RETURN_FALSE; + return NULL; +} + +static int +deque_init(dequeobject *deque, PyObject *args, PyObject *kwds) +{ + PyObject *iterable = NULL; + + if (!PyArg_UnpackTuple(args, "deque", 0, 1, &iterable)) + return -1; + + if (iterable != NULL) { + PyObject *rv = deque_extend(deque, iterable); + if (rv == NULL) + return -1; + Py_DECREF(rv); + } + return 0; +} + +static PySequenceMethods deque_as_sequence = { + (lenfunc)deque_len, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)deque_item, /* sq_item */ + 0, /* sq_slice */ + (ssizeobjargproc)deque_ass_item, /* sq_ass_item */ +}; + +/* deque object ********************************************************/ + +static PyObject *deque_iter(dequeobject *deque); +static PyObject *deque_reviter(dequeobject *deque); +PyDoc_STRVAR(reversed_doc, + "D.__reversed__() -- return a reverse iterator over the deque"); + +static PyMethodDef deque_methods[] = { + {"append", (PyCFunction)deque_append, + METH_O, append_doc}, + {"appendleft", (PyCFunction)deque_appendleft, + METH_O, appendleft_doc}, + {"clear", (PyCFunction)deque_clearmethod, + METH_NOARGS, clear_doc}, + {"__copy__", (PyCFunction)deque_copy, + METH_NOARGS, copy_doc}, + {"extend", (PyCFunction)deque_extend, + METH_O, extend_doc}, + {"extendleft", (PyCFunction)deque_extendleft, + METH_O, extendleft_doc}, + {"pop", (PyCFunction)deque_pop, + METH_NOARGS, pop_doc}, + {"popleft", (PyCFunction)deque_popleft, + METH_NOARGS, popleft_doc}, + {"__reduce__", (PyCFunction)deque_reduce, + METH_NOARGS, reduce_doc}, + {"remove", (PyCFunction)deque_remove, + METH_O, remove_doc}, + {"__reversed__", (PyCFunction)deque_reviter, + METH_NOARGS, reversed_doc}, + {"rotate", (PyCFunction)deque_rotate, + METH_VARARGS, rotate_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(deque_doc, +"deque(iterable) --> deque object\n\ +\n\ +Build an ordered collection accessible from endpoints only."); + +static PyTypeObject deque_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "collections.deque", /* tp_name */ + sizeof(dequeobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)deque_dealloc, /* tp_dealloc */ + deque_tp_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + deque_repr, /* tp_repr */ + 0, /* tp_as_number */ + &deque_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + deque_nohash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + deque_doc, /* tp_doc */ + (traverseproc)deque_traverse, /* tp_traverse */ + (inquiry)deque_clear, /* tp_clear */ + (richcmpfunc)deque_richcompare, /* tp_richcompare */ + offsetof(dequeobject, weakreflist), /* tp_weaklistoffset*/ + (getiterfunc)deque_iter, /* tp_iter */ + 0, /* tp_iternext */ + deque_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)deque_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + deque_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +/*********************** Deque Iterator **************************/ + +typedef struct { + PyObject_HEAD + int index; + block *b; + dequeobject *deque; + long state; /* state when the iterator is created */ + int counter; /* number of items remaining for iteration */ +} dequeiterobject; + +PyTypeObject dequeiter_type; + +static PyObject * +deque_iter(dequeobject *deque) +{ + dequeiterobject *it; + + it = PyObject_New(dequeiterobject, &dequeiter_type); + if (it == NULL) + return NULL; + it->b = deque->leftblock; + it->index = deque->leftindex; + Py_INCREF(deque); + it->deque = deque; + it->state = deque->state; + it->counter = deque->len; + return (PyObject *)it; +} + +static void +dequeiter_dealloc(dequeiterobject *dio) +{ + Py_XDECREF(dio->deque); + dio->ob_type->tp_free(dio); +} + +static PyObject * +dequeiter_next(dequeiterobject *it) +{ + PyObject *item; + + if (it->deque->state != it->state) { + it->counter = 0; + PyErr_SetString(PyExc_RuntimeError, + "deque mutated during iteration"); + return NULL; + } + if (it->counter == 0) + return NULL; + assert (!(it->b == it->deque->rightblock && + it->index > it->deque->rightindex)); + + item = it->b->data[it->index]; + it->index++; + it->counter--; + if (it->index == BLOCKLEN && it->counter > 0) { + assert (it->b->rightlink != NULL); + it->b = it->b->rightlink; + it->index = 0; + } + Py_INCREF(item); + return item; +} + +static PyObject * +dequeiter_len(dequeiterobject *it) +{ + return PyInt_FromLong(it->counter); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef dequeiter_methods[] = { + {"__length_hint__", (PyCFunction)dequeiter_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyTypeObject dequeiter_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "deque_iterator", /* tp_name */ + sizeof(dequeiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)dequeiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)dequeiter_next, /* tp_iternext */ + dequeiter_methods, /* tp_methods */ + 0, +}; + +/*********************** Deque Reverse Iterator **************************/ + +PyTypeObject dequereviter_type; + +static PyObject * +deque_reviter(dequeobject *deque) +{ + dequeiterobject *it; + + it = PyObject_New(dequeiterobject, &dequereviter_type); + if (it == NULL) + return NULL; + it->b = deque->rightblock; + it->index = deque->rightindex; + Py_INCREF(deque); + it->deque = deque; + it->state = deque->state; + it->counter = deque->len; + return (PyObject *)it; +} + +static PyObject * +dequereviter_next(dequeiterobject *it) +{ + PyObject *item; + if (it->counter == 0) + return NULL; + + if (it->deque->state != it->state) { + it->counter = 0; + PyErr_SetString(PyExc_RuntimeError, + "deque mutated during iteration"); + return NULL; + } + assert (!(it->b == it->deque->leftblock && + it->index < it->deque->leftindex)); + + item = it->b->data[it->index]; + it->index--; + it->counter--; + if (it->index == -1 && it->counter > 0) { + assert (it->b->leftlink != NULL); + it->b = it->b->leftlink; + it->index = BLOCKLEN - 1; + } + Py_INCREF(item); + return item; +} + +PyTypeObject dequereviter_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "deque_reverse_iterator", /* tp_name */ + sizeof(dequeiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)dequeiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)dequereviter_next, /* tp_iternext */ + dequeiter_methods, /* tp_methods */ + 0, +}; + +/* defaultdict type *********************************************************/ + +typedef struct { + PyDictObject dict; + PyObject *default_factory; +} defdictobject; + +static PyTypeObject defdict_type; /* Forward */ + +PyDoc_STRVAR(defdict_missing_doc, +"__missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n\ + if self.default_factory is None: raise KeyError((key,))\n\ + self[key] = value = self.default_factory()\n\ + return value\n\ +"); + +static PyObject * +defdict_missing(defdictobject *dd, PyObject *key) +{ + PyObject *factory = dd->default_factory; + PyObject *value; + if (factory == NULL || factory == Py_None) { + /* XXX Call dict.__missing__(key) */ + PyObject *tup; + tup = PyTuple_Pack(1, key); + if (!tup) return NULL; + PyErr_SetObject(PyExc_KeyError, tup); + Py_DECREF(tup); + return NULL; + } + value = PyEval_CallObject(factory, NULL); + if (value == NULL) + return value; + if (PyObject_SetItem((PyObject *)dd, key, value) < 0) { + Py_DECREF(value); + return NULL; + } + return value; +} + +PyDoc_STRVAR(defdict_copy_doc, "D.copy() -> a shallow copy of D."); + +static PyObject * +defdict_copy(defdictobject *dd) +{ + /* This calls the object's class. That only works for subclasses + whose class constructor has the same signature. Subclasses that + define a different constructor signature must override copy(). + */ + return PyObject_CallFunctionObjArgs((PyObject *)dd->dict.ob_type, + dd->default_factory, dd, NULL); +} + +static PyObject * +defdict_reduce(defdictobject *dd) +{ + /* __reduce__ must return a 5-tuple as follows: + + - factory function + - tuple of args for the factory function + - additional state (here None) + - sequence iterator (here None) + - dictionary iterator (yielding successive (key, value) pairs + + This API is used by pickle.py and copy.py. + + For this to be useful with pickle.py, the default_factory + must be picklable; e.g., None, a built-in, or a global + function in a module or package. + + Both shallow and deep copying are supported, but for deep + copying, the default_factory must be deep-copyable; e.g. None, + or a built-in (functions are not copyable at this time). + + This only works for subclasses as long as their constructor + signature is compatible; the first argument must be the + optional default_factory, defaulting to None. + */ + PyObject *args; + PyObject *items; + PyObject *result; + if (dd->default_factory == NULL || dd->default_factory == Py_None) + args = PyTuple_New(0); + else + args = PyTuple_Pack(1, dd->default_factory); + if (args == NULL) + return NULL; + items = PyObject_CallMethod((PyObject *)dd, "iteritems", "()"); + if (items == NULL) { + Py_DECREF(args); + return NULL; + } + result = PyTuple_Pack(5, dd->dict.ob_type, args, + Py_None, Py_None, items); + Py_DECREF(items); + Py_DECREF(args); + return result; +} + +static PyMethodDef defdict_methods[] = { + {"__missing__", (PyCFunction)defdict_missing, METH_O, + defdict_missing_doc}, + {"copy", (PyCFunction)defdict_copy, METH_NOARGS, + defdict_copy_doc}, + {"__copy__", (PyCFunction)defdict_copy, METH_NOARGS, + defdict_copy_doc}, + {"__reduce__", (PyCFunction)defdict_reduce, METH_NOARGS, + reduce_doc}, + {NULL} +}; + +static PyMemberDef defdict_members[] = { + {"default_factory", T_OBJECT, + offsetof(defdictobject, default_factory), 0, + PyDoc_STR("Factory for default value called by __missing__().")}, + {NULL} +}; + +static void +defdict_dealloc(defdictobject *dd) +{ + Py_CLEAR(dd->default_factory); + PyDict_Type.tp_dealloc((PyObject *)dd); +} + +static int +defdict_print(defdictobject *dd, FILE *fp, int flags) +{ + int sts; + fprintf(fp, "defaultdict("); + if (dd->default_factory == NULL) + fprintf(fp, "None"); + else { + PyObject_Print(dd->default_factory, fp, 0); + } + fprintf(fp, ", "); + sts = PyDict_Type.tp_print((PyObject *)dd, fp, 0); + fprintf(fp, ")"); + return sts; +} + +static PyObject * +defdict_repr(defdictobject *dd) +{ + PyObject *defrepr; + PyObject *baserepr; + PyObject *result; + baserepr = PyDict_Type.tp_repr((PyObject *)dd); + if (baserepr == NULL) + return NULL; + if (dd->default_factory == NULL) + defrepr = PyString_FromString("None"); + else + defrepr = PyObject_Repr(dd->default_factory); + if (defrepr == NULL) { + Py_DECREF(baserepr); + return NULL; + } + result = PyString_FromFormat("defaultdict(%s, %s)", + PyString_AS_STRING(defrepr), + PyString_AS_STRING(baserepr)); + Py_DECREF(defrepr); + Py_DECREF(baserepr); + return result; +} + +static int +defdict_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(((defdictobject *)self)->default_factory); + return PyDict_Type.tp_traverse(self, visit, arg); +} + +static int +defdict_tp_clear(defdictobject *dd) +{ + Py_CLEAR(dd->default_factory); + return PyDict_Type.tp_clear((PyObject *)dd); +} + +static int +defdict_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + defdictobject *dd = (defdictobject *)self; + PyObject *olddefault = dd->default_factory; + PyObject *newdefault = NULL; + PyObject *newargs; + int result; + if (args == NULL || !PyTuple_Check(args)) + newargs = PyTuple_New(0); + else { + Py_ssize_t n = PyTuple_GET_SIZE(args); + if (n > 0) { + newdefault = PyTuple_GET_ITEM(args, 0); + if (!PyCallable_Check(newdefault)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be callable"); + return -1; + } + } + newargs = PySequence_GetSlice(args, 1, n); + } + if (newargs == NULL) + return -1; + Py_XINCREF(newdefault); + dd->default_factory = newdefault; + result = PyDict_Type.tp_init(self, newargs, kwds); + Py_DECREF(newargs); + Py_XDECREF(olddefault); + return result; +} + +PyDoc_STRVAR(defdict_doc, +"defaultdict(default_factory) --> dict with default factory\n\ +\n\ +The default factory is called without arguments to produce\n\ +a new value when a key is not present, in __getitem__ only.\n\ +A defaultdict compares equal to a dict with the same items.\n\ +"); + +/* See comment in xxsubtype.c */ +#define DEFERRED_ADDRESS(ADDR) 0 + +static PyTypeObject defdict_type = { + PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) + 0, /* ob_size */ + "collections.defaultdict", /* tp_name */ + sizeof(defdictobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)defdict_dealloc, /* tp_dealloc */ + (printfunc)defdict_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)defdict_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + defdict_doc, /* tp_doc */ + defdict_traverse, /* tp_traverse */ + (inquiry)defdict_tp_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset*/ + 0, /* tp_iter */ + 0, /* tp_iternext */ + defdict_methods, /* tp_methods */ + defdict_members, /* tp_members */ + 0, /* tp_getset */ + DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + defdict_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +/* module level code ********************************************************/ + +PyDoc_STRVAR(module_doc, +"High performance data structures.\n\ +- deque: ordered collection accessible from endpoints only\n\ +- defaultdict: dict subclass with a default value factory\n\ +"); + +PyMODINIT_FUNC +initcollections(void) +{ + PyObject *m; + + m = Py_InitModule3("collections", NULL, module_doc); + if (m == NULL) + return; + + if (PyType_Ready(&deque_type) < 0) + return; + Py_INCREF(&deque_type); + PyModule_AddObject(m, "deque", (PyObject *)&deque_type); + + defdict_type.tp_base = &PyDict_Type; + if (PyType_Ready(&defdict_type) < 0) + return; + Py_INCREF(&defdict_type); + PyModule_AddObject(m, "defaultdict", (PyObject *)&defdict_type); + + if (PyType_Ready(&dequeiter_type) < 0) + return; + + if (PyType_Ready(&dequereviter_type) < 0) + return; + + return; +} diff --git a/sys/src/cmd/python/Modules/config b/sys/src/cmd/python/Modules/config new file mode 100644 index 000000000..ef3eb55bc --- /dev/null +++ b/sys/src/cmd/python/Modules/config @@ -0,0 +1,54 @@ +_codecs +_csv +#_curses +#_curses_panel +_elementtree +_functools +_hashlib +_locale +_lsprof +_md5 +_random +_sha +_sha256 +_sre +_ssl +_struct +_symtable +_testcapi +_weakref +array +audioop +binascii +bz2 +cPickle +cStringIO +cmath +collections +datetime +errno +fcntl +fpetest +grp +imageop +itertools +math +operator +parser +posix +pure +pwd +pyexpat +rgbimg +select +signal +_socket +strop +thread +time +unicodedata +xx +xxsubtype +zipimport +zlib +#_sqlite3 diff --git a/sys/src/cmd/python/Modules/config.c.in b/sys/src/cmd/python/Modules/config.c.in new file mode 100644 index 000000000..8c25eea2e --- /dev/null +++ b/sys/src/cmd/python/Modules/config.c.in @@ -0,0 +1,66 @@ +/* -*- C -*- *********************************************** +Copyright (c) 2000, BeOpen.com. +Copyright (c) 1995-2000, Corporation for National Research Initiatives. +Copyright (c) 1990-1995, Stichting Mathematisch Centrum. +All rights reserved. + +See the file "Misc/COPYRIGHT" for information on usage and +redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. +******************************************************************/ + +/* Module configuration */ + +/* !!! !!! !!! This file is edited by the makesetup script !!! !!! !!! */ + +/* This file contains the table of built-in modules. + See init_builtin() in import.c. */ + +#include "Python.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* -- ADDMODULE MARKER 1 -- */ + +extern void PyMarshal_Init(void); +extern void initimp(void); +extern void initgc(void); +extern void init_ast(void); +extern void init_types(void); + +struct _inittab _PyImport_Inittab[] = { + +/* -- ADDMODULE MARKER 2 -- */ + + /* This module lives in marshal.c */ + {"marshal", PyMarshal_Init}, + + /* This lives in import.c */ + {"imp", initimp}, + + /* This lives in Python/Python-ast.c */ + {"_ast", init_ast}, + + /* This lives in Python/_types.c */ + {"_types", init_types}, + + /* These entries are here for sys.builtin_module_names */ + {"__main__", NULL}, + {"__builtin__", NULL}, + {"sys", NULL}, + {"exceptions", NULL}, + + /* This lives in gcmodule.c */ + {"gc", initgc}, + + /* Sentinel */ + {0, 0} +}; + + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Modules/cryptmodule.c b/sys/src/cmd/python/Modules/cryptmodule.c new file mode 100644 index 000000000..6377f8430 --- /dev/null +++ b/sys/src/cmd/python/Modules/cryptmodule.c @@ -0,0 +1,49 @@ +/* cryptmodule.c - by Steve Majewski + */ + +#include "Python.h" + +#include <sys/types.h> + +#ifdef __VMS +#include <openssl/des.h> +#endif + +/* Module crypt */ + + +static PyObject *crypt_crypt(PyObject *self, PyObject *args) +{ + char *word, *salt; +#ifndef __VMS + extern char * crypt(const char *, const char *); +#endif + + if (!PyArg_ParseTuple(args, "ss:crypt", &word, &salt)) { + return NULL; + } + /* On some platforms (AtheOS) crypt returns NULL for an invalid + salt. Return None in that case. XXX Maybe raise an exception? */ + return Py_BuildValue("s", crypt(word, salt)); + +} + +PyDoc_STRVAR(crypt_crypt__doc__, +"crypt(word, salt) -> string\n\ +word will usually be a user's password. salt is a 2-character string\n\ +which will be used to select one of 4096 variations of DES. The characters\n\ +in salt must be either \".\", \"/\", or an alphanumeric character. Returns\n\ +the hashed password as a string, which will be composed of characters from\n\ +the same alphabet as the salt."); + + +static PyMethodDef crypt_methods[] = { + {"crypt", crypt_crypt, METH_VARARGS, crypt_crypt__doc__}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +initcrypt(void) +{ + Py_InitModule("crypt", crypt_methods); +} diff --git a/sys/src/cmd/python/Modules/cstubs b/sys/src/cmd/python/Modules/cstubs new file mode 100644 index 000000000..53bd4ab31 --- /dev/null +++ b/sys/src/cmd/python/Modules/cstubs @@ -0,0 +1,1364 @@ + +/* +Input used to generate the Python module "glmodule.c". +The stub generator is a Python script called "cgen.py". + +Each definition must be contained on one line: + +<returntype> <name> <type> <arg> <type> <arg> + +<returntype> can be: void, short, long (XXX maybe others?) + +<type> can be: char, string, short, float, long, or double + string indicates a null terminated string; + if <type> is char and <arg> begins with a *, the * is stripped + and <type> is changed into string + +<arg> has the form <mode> or <mode>[<subscript>] + where <mode> can be + s: arg is sent + r: arg is received (arg is a pointer) + and <subscript> can be (N and I are numbers): + N + argI + retval + N*argI + N*I + N*retval + In the case where the subscript consists of two parts + separated by *, the first part is the width of the matrix, and + the second part is the length of the matrix. This order is + opposite from the order used in C to declare a two-dimensional + matrix. +*/ + +/* + * An attempt has been made to make this module switch threads on qread + * calls. It is far from safe, though. + */ + +#include <gl.h> +#include <device.h> + +#ifdef __sgi +extern int devport(); +extern int textwritemask(); +extern int pagewritemask(); +extern int gewrite(); +extern int gettp(); +#endif + +#include "Python.h" +#include "cgensupport.h" + +/* +Some stubs are too complicated for the stub generator. +We can include manually written versions of them here. +A line starting with '%' gives the name of the function so the stub +generator can include it in the table of functions. +*/ + +% qread + +static PyObject * +gl_qread(self, args) + PyObject *self; + PyObject *args; +{ + long retval; + short arg1 ; + Py_BEGIN_ALLOW_THREADS + retval = qread( & arg1 ); + Py_END_ALLOW_THREADS + { PyObject *v = PyTuple_New( 2 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewlongobject(retval)); + PyTuple_SetItem(v, 1, mknewshortobject(arg1)); + return v; + } +} + + +/* +varray -- an array of v.. calls. +The argument is an array (maybe list or tuple) of points. +Each point must be a tuple or list of coordinates (x, y, z). +The points may be 2- or 3-dimensional but must all have the +same dimension. Float and int values may be mixed however. +The points are always converted to 3D double precision points +by assuming z=0.0 if necessary (as indicated in the man page), +and for each point v3d() is called. +*/ + +% varray + +static PyObject * +gl_varray(self, args) + PyObject *self; + PyObject *args; +{ + PyObject *v, *w=NULL; + int i, n, width; + double vec[3]; + PyObject * (*getitem)(PyObject *, int); + + if (!PyArg_GetObject(args, 1, 0, &v)) + return NULL; + + if (PyList_Check(v)) { + n = PyList_Size(v); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(v)) { + n = PyTuple_Size(v); + getitem = PyTuple_GetItem; + } + else { + PyErr_BadArgument(); + return NULL; + } + + if (n == 0) { + Py_INCREF(Py_None); + return Py_None; + } + if (n > 0) + w = (*getitem)(v, 0); + + width = 0; + if (w == NULL) { + } + else if (PyList_Check(w)) { + width = PyList_Size(w); + } + else if (PyTuple_Check(w)) { + width = PyTuple_Size(w); + } + + switch (width) { + case 2: + vec[2] = 0.0; + /* Fall through */ + case 3: + break; + default: + PyErr_BadArgument(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!PyArg_GetDoubleArray(w, 1, 0, width, vec)) + return NULL; + v3d(vec); + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* +vnarray, nvarray -- an array of n3f and v3f calls. +The argument is an array (list or tuple) of pairs of points and normals. +Each pair is a tuple (NOT a list) of a point and a normal for that point. +Each point or normal must be a tuple (NOT a list) of coordinates (x, y, z). +Three coordinates must be given. Float and int values may be mixed. +For each pair, n3f() is called for the normal, and then v3f() is called +for the vector. + +vnarray and nvarray differ only in the order of the vector and normal in +the pair: vnarray expects (v, n) while nvarray expects (n, v). +*/ + +static PyObject *gen_nvarray(); /* Forward */ + +% nvarray + +static PyObject * +gl_nvarray(self, args) + PyObject *self; + PyObject *args; +{ + return gen_nvarray(args, 0); +} + +% vnarray + +static PyObject * +gl_vnarray(self, args) + PyObject *self; + PyObject *args; +{ + return gen_nvarray(args, 1); +} + +/* Generic, internal version of {nv,nv}array: inorm indicates the + argument order, 0: normal first, 1: vector first. */ + +static PyObject * +gen_nvarray(args, inorm) + PyObject *args; + int inorm; +{ + PyObject *v, *w, *wnorm, *wvec; + int i, n; + float norm[3], vec[3]; + PyObject * (*getitem)(PyObject *, int); + + if (!PyArg_GetObject(args, 1, 0, &v)) + return NULL; + + if (PyList_Check(v)) { + n = PyList_Size(v); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(v)) { + n = PyTuple_Size(v); + getitem = PyTuple_GetItem; + } + else { + PyErr_BadArgument(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!PyTuple_Check(w) || PyTuple_Size(w) != 2) { + PyErr_BadArgument(); + return NULL; + } + wnorm = PyTuple_GetItem(w, inorm); + wvec = PyTuple_GetItem(w, 1 - inorm); + if (!PyArg_GetFloatArray(wnorm, 1, 0, 3, norm) || + !PyArg_GetFloatArray(wvec, 1, 0, 3, vec)) + return NULL; + n3f(norm); + v3f(vec); + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* nurbssurface(s_knots[], t_knots[], ctl[][], s_order, t_order, type). + The dimensions of ctl[] are computed as follows: + [len(s_knots) - s_order], [len(t_knots) - t_order] +*/ + +% nurbssurface + +static PyObject * +gl_nurbssurface(self, args) + PyObject *self; + PyObject *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + double *arg5 ; + long arg6 ; + long arg7 ; + long arg8 ; + long ncoords; + long s_byte_stride, t_byte_stride; + long s_nctl, t_nctl; + long s, t; + PyObject *v, *w, *pt; + double *pnext; + if (!PyArg_GetLongArraySize(args, 6, 0, &arg1)) + return NULL; + if ((arg2 = PyMem_NEW(double, arg1 )) == NULL) { + return PyErr_NoMemory(); + } + if (!PyArg_GetDoubleArray(args, 6, 0, arg1 , arg2)) + return NULL; + if (!PyArg_GetLongArraySize(args, 6, 1, &arg3)) + return NULL; + if ((arg4 = PyMem_NEW(double, arg3 )) == NULL) { + return PyErr_NoMemory(); + } + if (!PyArg_GetDoubleArray(args, 6, 1, arg3 , arg4)) + return NULL; + if (!PyArg_GetLong(args, 6, 3, &arg6)) + return NULL; + if (!PyArg_GetLong(args, 6, 4, &arg7)) + return NULL; + if (!PyArg_GetLong(args, 6, 5, &arg8)) + return NULL; + if (arg8 == N_XYZ) + ncoords = 3; + else if (arg8 == N_XYZW) + ncoords = 4; + else { + PyErr_BadArgument(); + return NULL; + } + s_nctl = arg1 - arg6; + t_nctl = arg3 - arg7; + if (!PyArg_GetObject(args, 6, 2, &v)) + return NULL; + if (!PyList_Check(v) || PyList_Size(v) != s_nctl) { + PyErr_BadArgument(); + return NULL; + } + if ((arg5 = PyMem_NEW(double, s_nctl*t_nctl*ncoords )) == NULL) { + return PyErr_NoMemory(); + } + pnext = arg5; + for (s = 0; s < s_nctl; s++) { + w = PyList_GetItem(v, s); + if (w == NULL || !PyList_Check(w) || + PyList_Size(w) != t_nctl) { + PyErr_BadArgument(); + return NULL; + } + for (t = 0; t < t_nctl; t++) { + pt = PyList_GetItem(w, t); + if (!PyArg_GetDoubleArray(pt, 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + } + s_byte_stride = sizeof(double) * ncoords; + t_byte_stride = s_byte_stride * s_nctl; + nurbssurface( arg1 , arg2 , arg3 , arg4 , + s_byte_stride , t_byte_stride , arg5 , arg6 , arg7 , arg8 ); + PyMem_DEL(arg2); + PyMem_DEL(arg4); + PyMem_DEL(arg5); + Py_INCREF(Py_None); + return Py_None; +} + +/* nurbscurve(knots, ctlpoints, order, type). + The length of ctlpoints is len(knots)-order. */ + +%nurbscurve + +static PyObject * +gl_nurbscurve(self, args) + PyObject *self; + PyObject *args; +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + long arg5 ; + long arg6 ; + int ncoords, npoints; + int i; + PyObject *v; + double *pnext; + if (!PyArg_GetLongArraySize(args, 4, 0, &arg1)) + return NULL; + if ((arg2 = PyMem_NEW(double, arg1 )) == NULL) { + return PyErr_NoMemory(); + } + if (!PyArg_GetDoubleArray(args, 4, 0, arg1 , arg2)) + return NULL; + if (!PyArg_GetLong(args, 4, 2, &arg5)) + return NULL; + if (!PyArg_GetLong(args, 4, 3, &arg6)) + return NULL; + if (arg6 == N_ST) + ncoords = 2; + else if (arg6 == N_STW) + ncoords = 3; + else { + PyErr_BadArgument(); + return NULL; + } + npoints = arg1 - arg5; + if (!PyArg_GetObject(args, 4, 1, &v)) + return NULL; + if (!PyList_Check(v) || PyList_Size(v) != npoints) { + PyErr_BadArgument(); + return NULL; + } + if ((arg4 = PyMem_NEW(double, npoints*ncoords )) == NULL) { + return PyErr_NoMemory(); + } + pnext = arg4; + for (i = 0; i < npoints; i++) { + if (!PyArg_GetDoubleArray(PyList_GetItem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + arg3 = (sizeof(double)) * ncoords; + nurbscurve( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + PyMem_DEL(arg2); + PyMem_DEL(arg4); + Py_INCREF(Py_None); + return Py_None; +} + +/* pwlcurve(points, type). + Points is a list of points. Type must be N_ST. */ + +%pwlcurve + +static PyObject * +gl_pwlcurve(self, args) + PyObject *self; + PyObject *args; +{ + PyObject *v; + long type; + double *data, *pnext; + long npoints, ncoords; + int i; + if (!PyArg_GetObject(args, 2, 0, &v)) + return NULL; + if (!PyArg_GetLong(args, 2, 1, &type)) + return NULL; + if (!PyList_Check(v)) { + PyErr_BadArgument(); + return NULL; + } + npoints = PyList_Size(v); + if (type == N_ST) + ncoords = 2; + else { + PyErr_BadArgument(); + return NULL; + } + if ((data = PyMem_NEW(double, npoints*ncoords)) == NULL) { + return PyErr_NoMemory(); + } + pnext = data; + for (i = 0; i < npoints; i++) { + if (!PyArg_GetDoubleArray(PyList_GetItem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + pwlcurve(npoints, data, sizeof(double)*ncoords, type); + PyMem_DEL(data); + Py_INCREF(Py_None); + return Py_None; +} + + +/* Picking and Selecting */ + +static short *pickbuffer = NULL; +static long pickbuffersize; + +static PyObject * +pick_select(args, func) + PyObject *args; + void (*func)(); +{ + if (!PyArg_GetLong(args, 1, 0, &pickbuffersize)) + return NULL; + if (pickbuffer != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "pick/gselect: already picking/selecting"); + return NULL; + } + if ((pickbuffer = PyMem_NEW(short, pickbuffersize)) == NULL) { + return PyErr_NoMemory(); + } + (*func)(pickbuffer, pickbuffersize); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +endpick_select(args, func) + PyObject *args; + long (*func)(); +{ + PyObject *v, *w; + int i, nhits, n; + if (!PyArg_NoArgs(args)) + return NULL; + if (pickbuffer == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "endpick/endselect: not in pick/select mode"); + return NULL; + } + nhits = (*func)(pickbuffer); + if (nhits < 0) { + nhits = -nhits; /* How to report buffer overflow otherwise? */ + } + /* Scan the buffer to see how many integers */ + n = 0; + for (; nhits > 0; nhits--) { + n += 1 + pickbuffer[n]; + } + v = PyList_New(n); + if (v == NULL) + return NULL; + /* XXX Could do it nicer and interpret the data structure here, + returning a list of lists. But this can be done in Python... */ + for (i = 0; i < n; i++) { + w = PyInt_FromLong((long)pickbuffer[i]); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(v, i, w); + } + PyMem_DEL(pickbuffer); + pickbuffer = NULL; + return v; +} + +extern void pick(), gselect(); +extern long endpick(), endselect(); + +%pick +static PyObject *gl_pick(self, args) PyObject *self, *args; { + return pick_select(args, pick); +} + +%endpick +static PyObject *gl_endpick(self, args) PyObject *self, *args; { + return endpick_select(args, endpick); +} + +%gselect +static PyObject *gl_gselect(self, args) PyObject *self, *args; { + return pick_select(args, gselect); +} + +%endselect +static PyObject *gl_endselect(self, args) PyObject *self, *args; { + return endpick_select(args, endselect); +} + + +/* XXX The generator botches this one. Here's a quick hack to fix it. */ + +/* XXX The generator botches this one. Here's a quick hack to fix it. */ + +% getmatrix float r[16] + +static PyObject * +gl_getmatrix(self, args) + PyObject *self; + PyObject *args; +{ + Matrix arg1; + PyObject *v, *w; + int i, j; + getmatrix( arg1 ); + v = PyList_New(16); + if (v == NULL) { + return PyErr_NoMemory(); + } + for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) { + w = mknewfloatobject(arg1[i][j]); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(v, i*4+j, w); + } + return v; +} + +/* Here's an alternate version that returns a 4x4 matrix instead of + a vector. Unfortunately it is incompatible with loadmatrix and + multmatrix... */ + +% altgetmatrix float r[4][4] + +static PyObject * +gl_altgetmatrix(self, args) + PyObject *self; + PyObject *args; +{ + Matrix arg1; + PyObject *v, *w; + int i, j; + getmatrix( arg1 ); + v = PyList_New(4); + if (v == NULL) { + return NULL; + } + for (i = 0; i < 4; i++) { + w = PyList_New(4); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(v, i, w); + } + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + w = mknewfloatobject(arg1[i][j]); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(PyList_GetItem(v, i), j, w); + } + } + return v; +} + +% lrectwrite + +static PyObject * +gl_lrectwrite(self, args) + PyObject *self; + PyObject *args; +{ + short x1 ; + short y1 ; + short x2 ; + short y2 ; + string parray ; + PyObject *s; +#if 0 + int pixcount; +#endif + if (!PyArg_GetShort(args, 5, 0, &x1)) + return NULL; + if (!PyArg_GetShort(args, 5, 1, &y1)) + return NULL; + if (!PyArg_GetShort(args, 5, 2, &x2)) + return NULL; + if (!PyArg_GetShort(args, 5, 3, &y2)) + return NULL; + if (!PyArg_GetString(args, 5, 4, &parray)) + return NULL; + if (!PyArg_GetObject(args, 5, 4, &s)) + return NULL; +#if 0 +/* Don't check this, it breaks experiments with pixmode(PM_SIZE, ...) */ + pixcount = (long)(x2+1-x1) * (long)(y2+1-y1); + if (!PyString_Check(s) || PyString_Size(s) != pixcount*sizeof(long)) { + PyErr_SetString(PyExc_RuntimeError, + "string arg to lrectwrite has wrong size"); + return NULL; + } +#endif + lrectwrite( x1 , y1 , x2 , y2 , (unsigned long *) parray ); + Py_INCREF(Py_None); + return Py_None; +} + +% lrectread + +static PyObject * +gl_lrectread(self, args) + PyObject *self; + PyObject *args; +{ + short x1 ; + short y1 ; + short x2 ; + short y2 ; + PyObject *parray; + int pixcount; + if (!PyArg_GetShort(args, 4, 0, &x1)) + return NULL; + if (!PyArg_GetShort(args, 4, 1, &y1)) + return NULL; + if (!PyArg_GetShort(args, 4, 2, &x2)) + return NULL; + if (!PyArg_GetShort(args, 4, 3, &y2)) + return NULL; + pixcount = (long)(x2+1-x1) * (long)(y2+1-y1); + parray = PyString_FromStringAndSize((char *)NULL, pixcount*sizeof(long)); + if (parray == NULL) + return NULL; /* No memory */ + lrectread(x1, y1, x2, y2, (unsigned long *) PyString_AsString(parray)); + return parray; +} + +% readdisplay + +static PyObject * +gl_readdisplay(self, args) + PyObject *self; + PyObject *args; +{ + short x1, y1, x2, y2; + unsigned long *parray, hints; + long size, size_ret; + PyObject *rv; + + if ( !PyArg_Parse(args, "hhhhl", &x1, &y1, &x2, &y2, &hints) ) + return 0; + size = (long)(x2+1-x1) * (long)(y2+1-y1); + rv = PyString_FromStringAndSize((char *)NULL, size*sizeof(long)); + if ( rv == NULL ) + return NULL; + parray = (unsigned long *)PyString_AsString(rv); + size_ret = readdisplay(x1, y1, x2, y2, parray, hints); + if ( size_ret != size ) { + printf("gl_readdisplay: got %ld pixels, expected %ld\n", + size_ret, size); + PyErr_SetString(PyExc_RuntimeError, "readdisplay returned unexpected length"); + return NULL; + } + return rv; +} + +/* Desperately needed, here are tools to compress and decompress + the data manipulated by lrectread/lrectwrite. + + gl.packrect(width, height, packfactor, bigdata) --> smalldata + makes 'bigdata' 4*(packfactor**2) times smaller by: + - turning it into B/W (a factor 4) + - replacing squares of size pacfactor by one + representative + + gl.unpackrect(width, height, packfactor, smalldata) --> bigdata + is the inverse; the numeric arguments must be *the same*. + + Both work best if width and height are multiples of packfactor + (in fact unpackrect will leave garbage bytes). +*/ + +% packrect + +static PyObject * +gl_packrect(self, args) + PyObject *self; + PyObject *args; +{ + long width, height, packfactor; + char *s; + PyObject *unpacked, *packed; + int pixcount, packedcount, x, y, r, g, b; + unsigned long pixel; + unsigned char *p; + unsigned long *parray; + if (!PyArg_GetLong(args, 4, 0, &width)) + return NULL; + if (!PyArg_GetLong(args, 4, 1, &height)) + return NULL; + if (!PyArg_GetLong(args, 4, 2, &packfactor)) + return NULL; + if (!PyArg_GetString(args, 4, 3, &s)) /* For type checking only */ + return NULL; + if (!PyArg_GetObject(args, 4, 3, &unpacked)) + return NULL; + if (width <= 0 || height <= 0 || packfactor <= 0) { + PyErr_SetString(PyExc_RuntimeError, "packrect args must be > 0"); + return NULL; + } + pixcount = width*height; + packedcount = ((width+packfactor-1)/packfactor) * + ((height+packfactor-1)/packfactor); + if (PyString_Size(unpacked) != pixcount*sizeof(long)) { + PyErr_SetString(PyExc_RuntimeError, + "string arg to packrect has wrong size"); + return NULL; + } + packed = PyString_FromStringAndSize((char *)NULL, packedcount); + if (packed == NULL) + return NULL; + parray = (unsigned long *) PyString_AsString(unpacked); + p = (unsigned char *) PyString_AsString(packed); + for (y = 0; y < height; y += packfactor, parray += packfactor*width) { + for (x = 0; x < width; x += packfactor) { + pixel = parray[x]; + r = pixel & 0xff; + g = (pixel >> 8) & 0xff; + b = (pixel >> 16) & 0xff; + *p++ = (30*r+59*g+11*b) / 100; + } + } + return packed; +} + +% unpackrect + +static unsigned long unpacktab[256]; +static int unpacktab_inited = 0; + +static PyObject * +gl_unpackrect(self, args) + PyObject *self; + PyObject *args; +{ + long width, height, packfactor; + char *s; + PyObject *unpacked, *packed; + int pixcount, packedcount; + register unsigned char *p; + register unsigned long *parray; + if (!unpacktab_inited) { + register int white; + for (white = 256; --white >= 0; ) + unpacktab[white] = white * 0x010101L; + unpacktab_inited++; + } + if (!PyArg_GetLong(args, 4, 0, &width)) + return NULL; + if (!PyArg_GetLong(args, 4, 1, &height)) + return NULL; + if (!PyArg_GetLong(args, 4, 2, &packfactor)) + return NULL; + if (!PyArg_GetString(args, 4, 3, &s)) /* For type checking only */ + return NULL; + if (!PyArg_GetObject(args, 4, 3, &packed)) + return NULL; + if (width <= 0 || height <= 0 || packfactor <= 0) { + PyErr_SetString(PyExc_RuntimeError, "packrect args must be > 0"); + return NULL; + } + pixcount = width*height; + packedcount = ((width+packfactor-1)/packfactor) * + ((height+packfactor-1)/packfactor); + if (PyString_Size(packed) != packedcount) { + PyErr_SetString(PyExc_RuntimeError, + "string arg to unpackrect has wrong size"); + return NULL; + } + unpacked = PyString_FromStringAndSize((char *)NULL, pixcount*sizeof(long)); + if (unpacked == NULL) + return NULL; + parray = (unsigned long *) PyString_AsString(unpacked); + p = (unsigned char *) PyString_AsString(packed); + if (packfactor == 1 && width*height > 0) { + /* Just expand bytes to longs */ + register int x = width * height; + do { + *parray++ = unpacktab[*p++]; + } while (--x >= 0); + } + else { + register int y; + for (y = 0; y < height-packfactor+1; + y += packfactor, parray += packfactor*width) { + register int x; + for (x = 0; x < width-packfactor+1; x += packfactor) { + register unsigned long pixel = unpacktab[*p++]; + register int i; + for (i = packfactor*width; (i-=width) >= 0;) { + register int j; + for (j = packfactor; --j >= 0; ) + parray[i+x+j] = pixel; + } + } + } + } + return unpacked; +} + +% gversion +static PyObject * +gl_gversion(self, args) + PyObject *self; + PyObject *args; +{ + char buf[20]; + gversion(buf); + return PyString_FromString(buf); +} + + +/* void clear - Manual because of clash with termcap */ +%clear +static PyObject * +gl_clear(self, args) + PyObject *self; + PyObject *args; +{ + __GLclear( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* End of manually written stubs */ + +%% + +long getshade +if !solaris void devport short s long s +void rdr2i long s long s +void rectfs short s short s short s short s +void rects short s short s short s short s +void rmv2i long s long s +void noport +void popviewport +void clearhitcode +void closeobj +void cursoff +void curson +void doublebuffer +void finish +void gconfig +void ginit +void greset +void multimap +void onemap +void popattributes +void popmatrix +void pushattributes +void pushmatrix +void pushviewport +void qreset +void RGBmode +void singlebuffer +void swapbuffers +void gsync +void gflush +void tpon +void tpoff +void clkon +void clkoff +void ringbell +#void callfunc +void gbegin +void textinit +void initnames +void pclos +void popname +if !solaris void spclos +void zclear +void screenspace +void reshapeviewport +void winpush +void winpop +void foreground +void endfullscrn +if !solaris void endpupmode +void fullscrn +if !solaris void pupmode +void winconstraints +void pagecolor short s +void textcolor short s +void color short s +void curveit short s +void font short s +void linewidth short s +void setlinestyle short s +void setmap short s +void swapinterval short s +void writemask short s +if !solaris void textwritemask short s +void qdevice short s +void unqdevice short s +void curvebasis short s +void curveprecision short s +void loadname short s +void passthrough short s +void pushname short s +void setmonitor short s +if !solaris void setshade short s +void setpattern short s +if !solaris void pagewritemask short s +# +void callobj long s +void delobj long s +void editobj long s +void makeobj long s +void maketag long s +void chunksize long s +void compactify long s +void deltag long s +void lsrepeat long s +void objinsert long s +void objreplace long s +void winclose long s +void blanktime long s +void freepup long s +# This is not in the library!? +###void pupcolor long s +# +void backbuffer long s +void frontbuffer long s +if !solaris void lsbackup long s +void resetls long s +void lampon long s +void lampoff long s +void setbell long s +void blankscreen long s +void depthcue long s +void zbuffer long s +void backface long s +# +void cmov2i long s long s +void draw2i long s long s +void move2i long s long s +void pnt2i long s long s +void patchbasis long s long s +void patchprecision long s long s +void pdr2i long s long s +void pmv2i long s long s +void rpdr2i long s long s +void rpmv2i long s long s +void xfpt2i long s long s +void objdelete long s long s +void patchcurves long s long s +void minsize long s long s +void maxsize long s long s +void keepaspect long s long s +void prefsize long s long s +void stepunit long s long s +void fudge long s long s +void winmove long s long s +# +void attachcursor short s short s +void deflinestyle short s short s +void noise short s short s +void picksize short s short s +void qenter short s short s +void setdepth short s short s +void cmov2s short s short s +void draw2s short s short s +void move2s short s short s +void pdr2s short s short s +void pmv2s short s short s +void pnt2s short s short s +void rdr2s short s short s +void rmv2s short s short s +void rpdr2s short s short s +void rpmv2s short s short s +void xfpt2s short s short s +# +void cmov2 float s float s +void draw2 float s float s +void move2 float s float s +void pnt2 float s float s +void pdr2 float s float s +void pmv2 float s float s +void rdr2 float s float s +void rmv2 float s float s +void rpdr2 float s float s +void rpmv2 float s float s +void xfpt2 float s float s +# +void loadmatrix float s[4*4] +# Really [4][4] +void multmatrix float s[4*4] +# Really [4][4] +void crv float s[3*4] +# Really [4][3] +void rcrv float s[4*4] +# Really [4][4] +# +# Methods that have strings. +# +void addtopup long s char *s long s +void charstr char *s +void getport char *s +long strwidth char *s +long winopen char *s +void wintitle char *s +# +# Methods that have 1 long (# of elements) and an array +# +void polf long s float s[3*arg1] +void polf2 long s float s[2*arg1] +void poly long s float s[3*arg1] +void poly2 long s float s[2*arg1] +void crvn long s float s[3*arg1] +void rcrvn long s float s[4*arg1] +# +void polf2i long s long s[2*arg1] +void polfi long s long s[3*arg1] +void poly2i long s long s[2*arg1] +void polyi long s long s[3*arg1] +# +void polf2s long s short s[2*arg1] +void polfs long s short s[3*arg1] +void polys long s short s[3*arg1] +void poly2s long s short s[2*arg1] +# +void defcursor short s u_short s[128] +# Is this useful? +void writepixels short s u_short s[arg1] +# Should be unsigned short... +void defbasis long s float s[4*4] +if !solaris void gewrite short s short s[arg1] +# +void rotate short s char s +# This is not in the library!? +###void setbutton short s char s +void rot float s char s +# +void circfi long s long s long s +void circi long s long s long s +void cmovi long s long s long s +void drawi long s long s long s +void movei long s long s long s +void pnti long s long s long s +void newtag long s long s long s +void pdri long s long s long s +void pmvi long s long s long s +void rdri long s long s long s +void rmvi long s long s long s +void rpdri long s long s long s +void rpmvi long s long s long s +void xfpti long s long s long s +# +void circ float s float s float s +void circf float s float s float s +void cmov float s float s float s +void draw float s float s float s +void move float s float s float s +void pnt float s float s float s +void scale float s float s float s +void translate float s float s float s +void pdr float s float s float s +void pmv float s float s float s +void rdr float s float s float s +void rmv float s float s float s +void rpdr float s float s float s +void rpmv float s float s float s +void xfpt float s float s float s +# +void RGBcolor short s short s short s +void RGBwritemask short s short s short s +void setcursor short s short s short s +void tie short s short s short s +void circfs short s short s short s +void circs short s short s short s +void cmovs short s short s short s +void draws short s short s short s +void moves short s short s short s +void pdrs short s short s short s +void pmvs short s short s short s +void pnts short s short s short s +void rdrs short s short s short s +void rmvs short s short s short s +void rpdrs short s short s short s +void rpmvs short s short s short s +void xfpts short s short s short s +void curorigin short s short s short s +void cyclemap short s short s short s +# +void patch float s[4*4] float s[4*4] float s[4*4] +void splf long s float s[3*arg1] u_short s[arg1] +void splf2 long s float s[2*arg1] u_short s[arg1] +void splfi long s long s[3*arg1] u_short s[arg1] +void splf2i long s long s[2*arg1] u_short s[arg1] +void splfs long s short s[3*arg1] u_short s[arg1] +void splf2s long s short s[2*arg1] u_short s[arg1] +###void defpattern short s short s u_short s[arg2*arg2/16] +# +void rpatch float s[4*4] float s[4*4] float s[4*4] float s[4*4] +# +# routines that send 4 floats +# +void ortho2 float s float s float s float s +void rect float s float s float s float s +void rectf float s float s float s float s +void xfpt4 float s float s float s float s +# +void textport short s short s short s short s +void mapcolor short s short s short s short s +void scrmask short s short s short s short s +void setvaluator short s short s short s short s +void viewport short s short s short s short s +void shaderange short s short s short s short s +void xfpt4s short s short s short s short s +void rectfi long s long s long s long s +void recti long s long s long s long s +void xfpt4i long s long s long s long s +void prefposition long s long s long s long s +# +void arc float s float s float s short s short s +void arcf float s float s float s short s short s +void arcfi long s long s long s short s short s +void arci long s long s long s short s short s +# +void bbox2 short s short s float s float s float s float s +void bbox2i short s short s long s long s long s long s +void bbox2s short s short s short s short s short s short s +void blink short s short s short s short s short s +void ortho float s float s float s float s float s float s +void window float s float s float s float s float s float s +void lookat float s float s float s float s float s float s short s +# +void perspective short s float s float s float s +void polarview float s short s short s short s +# XXX getichararray not supported +#void writeRGB short s char s[arg1] char s[arg1] char s[arg1] +# +void arcfs short s short s short s short s short s +void arcs short s short s short s short s short s +void rectcopy short s short s short s short s short s short s +if !solaris void RGBcursor short s short s short s short s short s short s short s +# +long getbutton short s +long getcmmode +long getlsbackup +long getresetls +long getdcm +long getzbuffer +long ismex +long isobj long s +long isqueued short s +long istag long s +# +long genobj +long gentag +long getbuffer +long getcolor +long getdisplaymode +long getfont +long getheight +long gethitcode +long getlstyle +long getlwidth +long getmap +long getplanes +long getwritemask +long qtest +long getlsrepeat +long getmonitor +long getopenobj +long getpattern +long winget +long winattach +long getothermonitor +long newpup +# +long getvaluator short s +void winset long s +long dopup long s +void getdepth short r short r +void getcpos short r short r +void getsize long r long r +void getorigin long r long r +void getviewport short r short r short r short r +if !solaris void gettp short r short r short r short r +void getgpos float r float r float r float r +void winposition long s long s long s long s +void gRGBcolor short r short r short r +void gRGBmask short r short r short r +void getscrmask short r short r short r short r +###void gRGBcursor short r short r short r short r short r short r short r short r +void getmcolor short s short r short r short r +void mapw long s short s short s float r float r float r float r float r float r +void mapw2 long s short s short s float r float r +###void defrasterfont short s short s short s Fontchar s[arg3] short s short s[4*arg5] +###long qread short r +void getcursor short r u_short r u_short r long r +# +# For these we receive arrays of stuff +# +###void getdev long s short s[arg1] short r[arg1] +#XXX not generated correctly yet +#void getmatrix float r[16] +###long readpixels short s short r[retval] +###long readRGB short s char r[retval] char r[retval] char r[retval] +###long blkqread short s short r[arg1] +# +# New 4D routines +# +void cmode +void concave long s +void curstype long s +void drawmode long s +void gammaramp short s[256] short s[256] short s[256] +long getbackface +long getdescender +long getdrawmode +long getmmode +long getsm +long getvideo long s +void imakebackground +void lmbind short s short s +void lmdef long s long s long s float s[arg3] +void mmode long s +void normal float s[3] +void overlay long s +void RGBrange short s short s short s short s short s short s short s short s +if !solaris void setvideo long s long s +void shademodel long s +void underlay long s +# +# New Personal Iris/GT Routines +# +void bgnclosedline +void bgnline +void bgnpoint +void bgnpolygon +void bgnsurface +void bgntmesh +void bgntrim +void endclosedline +void endline +void endpoint +void endpolygon +void endsurface +void endtmesh +void endtrim +void blendfunction long s long s +void c3f float s[3] +void c3i long s[3] +void c3s short s[3] +void c4f float s[4] +void c4i long s[4] +void c4s short s[4] +void colorf float s +void cpack long s +void czclear long s long s +void dglclose long s +long dglopen char *s long s +long getgdesc long s +void getnurbsproperty long s float r +void glcompat long s long s +void iconsize long s long s +void icontitle char *s +void lRGBrange short s short s short s short s short s short s long s long s +void linesmooth long s +void lmcolor long s +void logicop long s +###long lrectread short s short s short s short s long r[retval] +###void lrectwrite short s short s short s short s long s[(arg2-arg1+1)*(arg4-arg3+1)] +### Now manual, with string last arg +###long rectread short s short s short s short s short r[retval] +###void rectwrite short s short s short s short s short s[(arg2-arg1+1)*(arg4-arg3+1)] +void lsetdepth long s long s +void lshaderange short s short s long s long s +void n3f float s[3] +void noborder +void pntsmooth long s +void readsource long s +void rectzoom float s float s +void sbox float s float s float s float s +void sboxi long s long s long s long s +void sboxs short s short s short s short s +void sboxf float s float s float s float s +void sboxfi long s long s long s long s +void sboxfs short s short s short s short s +void setnurbsproperty long s float s +void setpup long s long s long s +void smoothline long s +void subpixel long s +void swaptmesh +long swinopen long s +void v2f float s[2] +void v2i long s[2] +void v2s short s[2] +void v3f float s[3] +void v3i long s[3] +void v3s short s[3] +void v4f float s[4] +void v4i long s[4] +void v4s short s[4] +void videocmd long s +long windepth long s +void wmpack long s +void zdraw long s +void zfunction long s +void zsource long s +void zwritemask long s +# +# uses doubles +# +void v2d double s[2] +void v3d double s[3] +void v4d double s[4] +# +# Why isn't this here? +# +void pixmode long s long s +# +# New in IRIX 4.0 +# +long qgetfd +void dither long s diff --git a/sys/src/cmd/python/Modules/datetimemodule.c b/sys/src/cmd/python/Modules/datetimemodule.c new file mode 100644 index 000000000..8207ffd0c --- /dev/null +++ b/sys/src/cmd/python/Modules/datetimemodule.c @@ -0,0 +1,4988 @@ +/* C implementation for the date/time type documented at + * http://www.zope.org/Members/fdrake/DateTimeWiki/FrontPage + */ + +#include "Python.h" +#include "modsupport.h" +#include "structmember.h" + +#include <time.h> + +#include "timefuncs.h" + +/* Differentiate between building the core module and building extension + * modules. + */ +#define Py_BUILD_CORE +#include "datetime.h" +#undef Py_BUILD_CORE + +/* We require that C int be at least 32 bits, and use int virtually + * everywhere. In just a few cases we use a temp long, where a Python + * API returns a C long. In such cases, we have to ensure that the + * final result fits in a C int (this can be an issue on 64-bit boxes). + */ +#if SIZEOF_INT < 4 +# error "datetime.c requires that C int have at least 32 bits" +#endif + +#define MINYEAR 1 +#define MAXYEAR 9999 + +/* Nine decimal digits is easy to communicate, and leaves enough room + * so that two delta days can be added w/o fear of overflowing a signed + * 32-bit int, and with plenty of room left over to absorb any possible + * carries from adding seconds. + */ +#define MAX_DELTA_DAYS 999999999 + +/* Rename the long macros in datetime.h to more reasonable short names. */ +#define GET_YEAR PyDateTime_GET_YEAR +#define GET_MONTH PyDateTime_GET_MONTH +#define GET_DAY PyDateTime_GET_DAY +#define DATE_GET_HOUR PyDateTime_DATE_GET_HOUR +#define DATE_GET_MINUTE PyDateTime_DATE_GET_MINUTE +#define DATE_GET_SECOND PyDateTime_DATE_GET_SECOND +#define DATE_GET_MICROSECOND PyDateTime_DATE_GET_MICROSECOND + +/* Date accessors for date and datetime. */ +#define SET_YEAR(o, v) (((o)->data[0] = ((v) & 0xff00) >> 8), \ + ((o)->data[1] = ((v) & 0x00ff))) +#define SET_MONTH(o, v) (PyDateTime_GET_MONTH(o) = (v)) +#define SET_DAY(o, v) (PyDateTime_GET_DAY(o) = (v)) + +/* Date/Time accessors for datetime. */ +#define DATE_SET_HOUR(o, v) (PyDateTime_DATE_GET_HOUR(o) = (v)) +#define DATE_SET_MINUTE(o, v) (PyDateTime_DATE_GET_MINUTE(o) = (v)) +#define DATE_SET_SECOND(o, v) (PyDateTime_DATE_GET_SECOND(o) = (v)) +#define DATE_SET_MICROSECOND(o, v) \ + (((o)->data[7] = ((v) & 0xff0000) >> 16), \ + ((o)->data[8] = ((v) & 0x00ff00) >> 8), \ + ((o)->data[9] = ((v) & 0x0000ff))) + +/* Time accessors for time. */ +#define TIME_GET_HOUR PyDateTime_TIME_GET_HOUR +#define TIME_GET_MINUTE PyDateTime_TIME_GET_MINUTE +#define TIME_GET_SECOND PyDateTime_TIME_GET_SECOND +#define TIME_GET_MICROSECOND PyDateTime_TIME_GET_MICROSECOND +#define TIME_SET_HOUR(o, v) (PyDateTime_TIME_GET_HOUR(o) = (v)) +#define TIME_SET_MINUTE(o, v) (PyDateTime_TIME_GET_MINUTE(o) = (v)) +#define TIME_SET_SECOND(o, v) (PyDateTime_TIME_GET_SECOND(o) = (v)) +#define TIME_SET_MICROSECOND(o, v) \ + (((o)->data[3] = ((v) & 0xff0000) >> 16), \ + ((o)->data[4] = ((v) & 0x00ff00) >> 8), \ + ((o)->data[5] = ((v) & 0x0000ff))) + +/* Delta accessors for timedelta. */ +#define GET_TD_DAYS(o) (((PyDateTime_Delta *)(o))->days) +#define GET_TD_SECONDS(o) (((PyDateTime_Delta *)(o))->seconds) +#define GET_TD_MICROSECONDS(o) (((PyDateTime_Delta *)(o))->microseconds) + +#define SET_TD_DAYS(o, v) ((o)->days = (v)) +#define SET_TD_SECONDS(o, v) ((o)->seconds = (v)) +#define SET_TD_MICROSECONDS(o, v) ((o)->microseconds = (v)) + +/* p is a pointer to a time or a datetime object; HASTZINFO(p) returns + * p->hastzinfo. + */ +#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo) + +/* M is a char or int claiming to be a valid month. The macro is equivalent + * to the two-sided Python test + * 1 <= M <= 12 + */ +#define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12) + +/* Forward declarations. */ +static PyTypeObject PyDateTime_DateType; +static PyTypeObject PyDateTime_DateTimeType; +static PyTypeObject PyDateTime_DeltaType; +static PyTypeObject PyDateTime_TimeType; +static PyTypeObject PyDateTime_TZInfoType; + +/* --------------------------------------------------------------------------- + * Math utilities. + */ + +/* k = i+j overflows iff k differs in sign from both inputs, + * iff k^i has sign bit set and k^j has sign bit set, + * iff (k^i)&(k^j) has sign bit set. + */ +#define SIGNED_ADD_OVERFLOWED(RESULT, I, J) \ + ((((RESULT) ^ (I)) & ((RESULT) ^ (J))) < 0) + +/* Compute Python divmod(x, y), returning the quotient and storing the + * remainder into *r. The quotient is the floor of x/y, and that's + * the real point of this. C will probably truncate instead (C99 + * requires truncation; C89 left it implementation-defined). + * Simplification: we *require* that y > 0 here. That's appropriate + * for all the uses made of it. This simplifies the code and makes + * the overflow case impossible (divmod(LONG_MIN, -1) is the only + * overflow case). + */ +static int +divmod(int x, int y, int *r) +{ + int quo; + + assert(y > 0); + quo = x / y; + *r = x - quo * y; + if (*r < 0) { + --quo; + *r += y; + } + assert(0 <= *r && *r < y); + return quo; +} + +/* Round a double to the nearest long. |x| must be small enough to fit + * in a C long; this is not checked. + */ +static long +round_to_long(double x) +{ + if (x >= 0.0) + x = floor(x + 0.5); + else + x = ceil(x - 0.5); + return (long)x; +} + +/* --------------------------------------------------------------------------- + * General calendrical helper functions + */ + +/* For each month ordinal in 1..12, the number of days in that month, + * and the number of days before that month in the same year. These + * are correct for non-leap years only. + */ +static int _days_in_month[] = { + 0, /* unused; this vector uses 1-based indexing */ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static int _days_before_month[] = { + 0, /* unused; this vector uses 1-based indexing */ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +/* year -> 1 if leap year, else 0. */ +static int +is_leap(int year) +{ + /* Cast year to unsigned. The result is the same either way, but + * C can generate faster code for unsigned mod than for signed + * mod (especially for % 4 -- a good compiler should just grab + * the last 2 bits when the LHS is unsigned). + */ + const unsigned int ayear = (unsigned int)year; + return ayear % 4 == 0 && (ayear % 100 != 0 || ayear % 400 == 0); +} + +/* year, month -> number of days in that month in that year */ +static int +days_in_month(int year, int month) +{ + assert(month >= 1); + assert(month <= 12); + if (month == 2 && is_leap(year)) + return 29; + else + return _days_in_month[month]; +} + +/* year, month -> number of days in year preceeding first day of month */ +static int +days_before_month(int year, int month) +{ + int days; + + assert(month >= 1); + assert(month <= 12); + days = _days_before_month[month]; + if (month > 2 && is_leap(year)) + ++days; + return days; +} + +/* year -> number of days before January 1st of year. Remember that we + * start with year 1, so days_before_year(1) == 0. + */ +static int +days_before_year(int year) +{ + int y = year - 1; + /* This is incorrect if year <= 0; we really want the floor + * here. But so long as MINYEAR is 1, the smallest year this + * can see is 0 (this can happen in some normalization endcases), + * so we'll just special-case that. + */ + assert (year >= 0); + if (y >= 0) + return y*365 + y/4 - y/100 + y/400; + else { + assert(y == -1); + return -366; + } +} + +/* Number of days in 4, 100, and 400 year cycles. That these have + * the correct values is asserted in the module init function. + */ +#define DI4Y 1461 /* days_before_year(5); days in 4 years */ +#define DI100Y 36524 /* days_before_year(101); days in 100 years */ +#define DI400Y 146097 /* days_before_year(401); days in 400 years */ + +/* ordinal -> year, month, day, considering 01-Jan-0001 as day 1. */ +static void +ord_to_ymd(int ordinal, int *year, int *month, int *day) +{ + int n, n1, n4, n100, n400, leapyear, preceding; + + /* ordinal is a 1-based index, starting at 1-Jan-1. The pattern of + * leap years repeats exactly every 400 years. The basic strategy is + * to find the closest 400-year boundary at or before ordinal, then + * work with the offset from that boundary to ordinal. Life is much + * clearer if we subtract 1 from ordinal first -- then the values + * of ordinal at 400-year boundaries are exactly those divisible + * by DI400Y: + * + * D M Y n n-1 + * -- --- ---- ---------- ---------------- + * 31 Dec -400 -DI400Y -DI400Y -1 + * 1 Jan -399 -DI400Y +1 -DI400Y 400-year boundary + * ... + * 30 Dec 000 -1 -2 + * 31 Dec 000 0 -1 + * 1 Jan 001 1 0 400-year boundary + * 2 Jan 001 2 1 + * 3 Jan 001 3 2 + * ... + * 31 Dec 400 DI400Y DI400Y -1 + * 1 Jan 401 DI400Y +1 DI400Y 400-year boundary + */ + assert(ordinal >= 1); + --ordinal; + n400 = ordinal / DI400Y; + n = ordinal % DI400Y; + *year = n400 * 400 + 1; + + /* Now n is the (non-negative) offset, in days, from January 1 of + * year, to the desired date. Now compute how many 100-year cycles + * precede n. + * Note that it's possible for n100 to equal 4! In that case 4 full + * 100-year cycles precede the desired day, which implies the + * desired day is December 31 at the end of a 400-year cycle. + */ + n100 = n / DI100Y; + n = n % DI100Y; + + /* Now compute how many 4-year cycles precede it. */ + n4 = n / DI4Y; + n = n % DI4Y; + + /* And now how many single years. Again n1 can be 4, and again + * meaning that the desired day is December 31 at the end of the + * 4-year cycle. + */ + n1 = n / 365; + n = n % 365; + + *year += n100 * 100 + n4 * 4 + n1; + if (n1 == 4 || n100 == 4) { + assert(n == 0); + *year -= 1; + *month = 12; + *day = 31; + return; + } + + /* Now the year is correct, and n is the offset from January 1. We + * find the month via an estimate that's either exact or one too + * large. + */ + leapyear = n1 == 3 && (n4 != 24 || n100 == 3); + assert(leapyear == is_leap(*year)); + *month = (n + 50) >> 5; + preceding = (_days_before_month[*month] + (*month > 2 && leapyear)); + if (preceding > n) { + /* estimate is too large */ + *month -= 1; + preceding -= days_in_month(*year, *month); + } + n -= preceding; + assert(0 <= n); + assert(n < days_in_month(*year, *month)); + + *day = n + 1; +} + +/* year, month, day -> ordinal, considering 01-Jan-0001 as day 1. */ +static int +ymd_to_ord(int year, int month, int day) +{ + return days_before_year(year) + days_before_month(year, month) + day; +} + +/* Day of week, where Monday==0, ..., Sunday==6. 1/1/1 was a Monday. */ +static int +weekday(int year, int month, int day) +{ + return (ymd_to_ord(year, month, day) + 6) % 7; +} + +/* Ordinal of the Monday starting week 1 of the ISO year. Week 1 is the + * first calendar week containing a Thursday. + */ +static int +iso_week1_monday(int year) +{ + int first_day = ymd_to_ord(year, 1, 1); /* ord of 1/1 */ + /* 0 if 1/1 is a Monday, 1 if a Tue, etc. */ + int first_weekday = (first_day + 6) % 7; + /* ordinal of closest Monday at or before 1/1 */ + int week1_monday = first_day - first_weekday; + + if (first_weekday > 3) /* if 1/1 was Fri, Sat, Sun */ + week1_monday += 7; + return week1_monday; +} + +/* --------------------------------------------------------------------------- + * Range checkers. + */ + +/* Check that -MAX_DELTA_DAYS <= days <= MAX_DELTA_DAYS. If so, return 0. + * If not, raise OverflowError and return -1. + */ +static int +check_delta_day_range(int days) +{ + if (-MAX_DELTA_DAYS <= days && days <= MAX_DELTA_DAYS) + return 0; + PyErr_Format(PyExc_OverflowError, + "days=%d; must have magnitude <= %d", + days, MAX_DELTA_DAYS); + return -1; +} + +/* Check that date arguments are in range. Return 0 if they are. If they + * aren't, raise ValueError and return -1. + */ +static int +check_date_args(int year, int month, int day) +{ + + if (year < MINYEAR || year > MAXYEAR) { + PyErr_SetString(PyExc_ValueError, + "year is out of range"); + return -1; + } + if (month < 1 || month > 12) { + PyErr_SetString(PyExc_ValueError, + "month must be in 1..12"); + return -1; + } + if (day < 1 || day > days_in_month(year, month)) { + PyErr_SetString(PyExc_ValueError, + "day is out of range for month"); + return -1; + } + return 0; +} + +/* Check that time arguments are in range. Return 0 if they are. If they + * aren't, raise ValueError and return -1. + */ +static int +check_time_args(int h, int m, int s, int us) +{ + if (h < 0 || h > 23) { + PyErr_SetString(PyExc_ValueError, + "hour must be in 0..23"); + return -1; + } + if (m < 0 || m > 59) { + PyErr_SetString(PyExc_ValueError, + "minute must be in 0..59"); + return -1; + } + if (s < 0 || s > 59) { + PyErr_SetString(PyExc_ValueError, + "second must be in 0..59"); + return -1; + } + if (us < 0 || us > 999999) { + PyErr_SetString(PyExc_ValueError, + "microsecond must be in 0..999999"); + return -1; + } + return 0; +} + +/* --------------------------------------------------------------------------- + * Normalization utilities. + */ + +/* One step of a mixed-radix conversion. A "hi" unit is equivalent to + * factor "lo" units. factor must be > 0. If *lo is less than 0, or + * at least factor, enough of *lo is converted into "hi" units so that + * 0 <= *lo < factor. The input values must be such that int overflow + * is impossible. + */ +static void +normalize_pair(int *hi, int *lo, int factor) +{ + assert(factor > 0); + assert(lo != hi); + if (*lo < 0 || *lo >= factor) { + const int num_hi = divmod(*lo, factor, lo); + const int new_hi = *hi + num_hi; + assert(! SIGNED_ADD_OVERFLOWED(new_hi, *hi, num_hi)); + *hi = new_hi; + } + assert(0 <= *lo && *lo < factor); +} + +/* Fiddle days (d), seconds (s), and microseconds (us) so that + * 0 <= *s < 24*3600 + * 0 <= *us < 1000000 + * The input values must be such that the internals don't overflow. + * The way this routine is used, we don't get close. + */ +static void +normalize_d_s_us(int *d, int *s, int *us) +{ + if (*us < 0 || *us >= 1000000) { + normalize_pair(s, us, 1000000); + /* |s| can't be bigger than about + * |original s| + |original us|/1000000 now. + */ + + } + if (*s < 0 || *s >= 24*3600) { + normalize_pair(d, s, 24*3600); + /* |d| can't be bigger than about + * |original d| + + * (|original s| + |original us|/1000000) / (24*3600) now. + */ + } + assert(0 <= *s && *s < 24*3600); + assert(0 <= *us && *us < 1000000); +} + +/* Fiddle years (y), months (m), and days (d) so that + * 1 <= *m <= 12 + * 1 <= *d <= days_in_month(*y, *m) + * The input values must be such that the internals don't overflow. + * The way this routine is used, we don't get close. + */ +static void +normalize_y_m_d(int *y, int *m, int *d) +{ + int dim; /* # of days in month */ + + /* This gets muddy: the proper range for day can't be determined + * without knowing the correct month and year, but if day is, e.g., + * plus or minus a million, the current month and year values make + * no sense (and may also be out of bounds themselves). + * Saying 12 months == 1 year should be non-controversial. + */ + if (*m < 1 || *m > 12) { + --*m; + normalize_pair(y, m, 12); + ++*m; + /* |y| can't be bigger than about + * |original y| + |original m|/12 now. + */ + } + assert(1 <= *m && *m <= 12); + + /* Now only day can be out of bounds (year may also be out of bounds + * for a datetime object, but we don't care about that here). + * If day is out of bounds, what to do is arguable, but at least the + * method here is principled and explainable. + */ + dim = days_in_month(*y, *m); + if (*d < 1 || *d > dim) { + /* Move day-1 days from the first of the month. First try to + * get off cheap if we're only one day out of range + * (adjustments for timezone alone can't be worse than that). + */ + if (*d == 0) { + --*m; + if (*m > 0) + *d = days_in_month(*y, *m); + else { + --*y; + *m = 12; + *d = 31; + } + } + else if (*d == dim + 1) { + /* move forward a day */ + ++*m; + *d = 1; + if (*m > 12) { + *m = 1; + ++*y; + } + } + else { + int ordinal = ymd_to_ord(*y, *m, 1) + + *d - 1; + ord_to_ymd(ordinal, y, m, d); + } + } + assert(*m > 0); + assert(*d > 0); +} + +/* Fiddle out-of-bounds months and days so that the result makes some kind + * of sense. The parameters are both inputs and outputs. Returns < 0 on + * failure, where failure means the adjusted year is out of bounds. + */ +static int +normalize_date(int *year, int *month, int *day) +{ + int result; + + normalize_y_m_d(year, month, day); + if (MINYEAR <= *year && *year <= MAXYEAR) + result = 0; + else { + PyErr_SetString(PyExc_OverflowError, + "date value out of range"); + result = -1; + } + return result; +} + +/* Force all the datetime fields into range. The parameters are both + * inputs and outputs. Returns < 0 on error. + */ +static int +normalize_datetime(int *year, int *month, int *day, + int *hour, int *minute, int *second, + int *microsecond) +{ + normalize_pair(second, microsecond, 1000000); + normalize_pair(minute, second, 60); + normalize_pair(hour, minute, 60); + normalize_pair(day, hour, 24); + return normalize_date(year, month, day); +} + +/* --------------------------------------------------------------------------- + * Basic object allocation: tp_alloc implementations. These allocate + * Python objects of the right size and type, and do the Python object- + * initialization bit. If there's not enough memory, they return NULL after + * setting MemoryError. All data members remain uninitialized trash. + * + * We abuse the tp_alloc "nitems" argument to communicate whether a tzinfo + * member is needed. This is ugly, imprecise, and possibly insecure. + * tp_basicsize for the time and datetime types is set to the size of the + * struct that has room for the tzinfo member, so subclasses in Python will + * allocate enough space for a tzinfo member whether or not one is actually + * needed. That's the "ugly and imprecise" parts. The "possibly insecure" + * part is that PyType_GenericAlloc() (which subclasses in Python end up + * using) just happens today to effectively ignore the nitems argument + * when tp_itemsize is 0, which it is for these type objects. If that + * changes, perhaps the callers of tp_alloc slots in this file should + * be changed to force a 0 nitems argument unless the type being allocated + * is a base type implemented in this file (so that tp_alloc is time_alloc + * or datetime_alloc below, which know about the nitems abuse). + */ + +static PyObject * +time_alloc(PyTypeObject *type, Py_ssize_t aware) +{ + PyObject *self; + + self = (PyObject *) + PyObject_MALLOC(aware ? + sizeof(PyDateTime_Time) : + sizeof(_PyDateTime_BaseTime)); + if (self == NULL) + return (PyObject *)PyErr_NoMemory(); + PyObject_INIT(self, type); + return self; +} + +static PyObject * +datetime_alloc(PyTypeObject *type, Py_ssize_t aware) +{ + PyObject *self; + + self = (PyObject *) + PyObject_MALLOC(aware ? + sizeof(PyDateTime_DateTime) : + sizeof(_PyDateTime_BaseDateTime)); + if (self == NULL) + return (PyObject *)PyErr_NoMemory(); + PyObject_INIT(self, type); + return self; +} + +/* --------------------------------------------------------------------------- + * Helpers for setting object fields. These work on pointers to the + * appropriate base class. + */ + +/* For date and datetime. */ +static void +set_date_fields(PyDateTime_Date *self, int y, int m, int d) +{ + self->hashcode = -1; + SET_YEAR(self, y); + SET_MONTH(self, m); + SET_DAY(self, d); +} + +/* --------------------------------------------------------------------------- + * Create various objects, mostly without range checking. + */ + +/* Create a date instance with no range checking. */ +static PyObject * +new_date_ex(int year, int month, int day, PyTypeObject *type) +{ + PyDateTime_Date *self; + + self = (PyDateTime_Date *) (type->tp_alloc(type, 0)); + if (self != NULL) + set_date_fields(self, year, month, day); + return (PyObject *) self; +} + +#define new_date(year, month, day) \ + new_date_ex(year, month, day, &PyDateTime_DateType) + +/* Create a datetime instance with no range checking. */ +static PyObject * +new_datetime_ex(int year, int month, int day, int hour, int minute, + int second, int usecond, PyObject *tzinfo, PyTypeObject *type) +{ + PyDateTime_DateTime *self; + char aware = tzinfo != Py_None; + + self = (PyDateTime_DateTime *) (type->tp_alloc(type, aware)); + if (self != NULL) { + self->hastzinfo = aware; + set_date_fields((PyDateTime_Date *)self, year, month, day); + DATE_SET_HOUR(self, hour); + DATE_SET_MINUTE(self, minute); + DATE_SET_SECOND(self, second); + DATE_SET_MICROSECOND(self, usecond); + if (aware) { + Py_INCREF(tzinfo); + self->tzinfo = tzinfo; + } + } + return (PyObject *)self; +} + +#define new_datetime(y, m, d, hh, mm, ss, us, tzinfo) \ + new_datetime_ex(y, m, d, hh, mm, ss, us, tzinfo, \ + &PyDateTime_DateTimeType) + +/* Create a time instance with no range checking. */ +static PyObject * +new_time_ex(int hour, int minute, int second, int usecond, + PyObject *tzinfo, PyTypeObject *type) +{ + PyDateTime_Time *self; + char aware = tzinfo != Py_None; + + self = (PyDateTime_Time *) (type->tp_alloc(type, aware)); + if (self != NULL) { + self->hastzinfo = aware; + self->hashcode = -1; + TIME_SET_HOUR(self, hour); + TIME_SET_MINUTE(self, minute); + TIME_SET_SECOND(self, second); + TIME_SET_MICROSECOND(self, usecond); + if (aware) { + Py_INCREF(tzinfo); + self->tzinfo = tzinfo; + } + } + return (PyObject *)self; +} + +#define new_time(hh, mm, ss, us, tzinfo) \ + new_time_ex(hh, mm, ss, us, tzinfo, &PyDateTime_TimeType) + +/* Create a timedelta instance. Normalize the members iff normalize is + * true. Passing false is a speed optimization, if you know for sure + * that seconds and microseconds are already in their proper ranges. In any + * case, raises OverflowError and returns NULL if the normalized days is out + * of range). + */ +static PyObject * +new_delta_ex(int days, int seconds, int microseconds, int normalize, + PyTypeObject *type) +{ + PyDateTime_Delta *self; + + if (normalize) + normalize_d_s_us(&days, &seconds, &microseconds); + assert(0 <= seconds && seconds < 24*3600); + assert(0 <= microseconds && microseconds < 1000000); + + if (check_delta_day_range(days) < 0) + return NULL; + + self = (PyDateTime_Delta *) (type->tp_alloc(type, 0)); + if (self != NULL) { + self->hashcode = -1; + SET_TD_DAYS(self, days); + SET_TD_SECONDS(self, seconds); + SET_TD_MICROSECONDS(self, microseconds); + } + return (PyObject *) self; +} + +#define new_delta(d, s, us, normalize) \ + new_delta_ex(d, s, us, normalize, &PyDateTime_DeltaType) + +/* --------------------------------------------------------------------------- + * tzinfo helpers. + */ + +/* Ensure that p is None or of a tzinfo subclass. Return 0 if OK; if not + * raise TypeError and return -1. + */ +static int +check_tzinfo_subclass(PyObject *p) +{ + if (p == Py_None || PyTZInfo_Check(p)) + return 0; + PyErr_Format(PyExc_TypeError, + "tzinfo argument must be None or of a tzinfo subclass, " + "not type '%s'", + p->ob_type->tp_name); + return -1; +} + +/* Return tzinfo.methname(tzinfoarg), without any checking of results. + * If tzinfo is None, returns None. + */ +static PyObject * +call_tzinfo_method(PyObject *tzinfo, char *methname, PyObject *tzinfoarg) +{ + PyObject *result; + + assert(tzinfo && methname && tzinfoarg); + assert(check_tzinfo_subclass(tzinfo) >= 0); + if (tzinfo == Py_None) { + result = Py_None; + Py_INCREF(result); + } + else + result = PyObject_CallMethod(tzinfo, methname, "O", tzinfoarg); + return result; +} + +/* If self has a tzinfo member, return a BORROWED reference to it. Else + * return NULL, which is NOT AN ERROR. There are no error returns here, + * and the caller must not decref the result. + */ +static PyObject * +get_tzinfo_member(PyObject *self) +{ + PyObject *tzinfo = NULL; + + if (PyDateTime_Check(self) && HASTZINFO(self)) + tzinfo = ((PyDateTime_DateTime *)self)->tzinfo; + else if (PyTime_Check(self) && HASTZINFO(self)) + tzinfo = ((PyDateTime_Time *)self)->tzinfo; + + return tzinfo; +} + +/* Call getattr(tzinfo, name)(tzinfoarg), and extract an int from the + * result. tzinfo must be an instance of the tzinfo class. If the method + * returns None, this returns 0 and sets *none to 1. If the method doesn't + * return None or timedelta, TypeError is raised and this returns -1. If it + * returnsa timedelta and the value is out of range or isn't a whole number + * of minutes, ValueError is raised and this returns -1. + * Else *none is set to 0 and the integer method result is returned. + */ +static int +call_utc_tzinfo_method(PyObject *tzinfo, char *name, PyObject *tzinfoarg, + int *none) +{ + PyObject *u; + int result = -1; + + assert(tzinfo != NULL); + assert(PyTZInfo_Check(tzinfo)); + assert(tzinfoarg != NULL); + + *none = 0; + u = call_tzinfo_method(tzinfo, name, tzinfoarg); + if (u == NULL) + return -1; + + else if (u == Py_None) { + result = 0; + *none = 1; + } + else if (PyDelta_Check(u)) { + const int days = GET_TD_DAYS(u); + if (days < -1 || days > 0) + result = 24*60; /* trigger ValueError below */ + else { + /* next line can't overflow because we know days + * is -1 or 0 now + */ + int ss = days * 24 * 3600 + GET_TD_SECONDS(u); + result = divmod(ss, 60, &ss); + if (ss || GET_TD_MICROSECONDS(u)) { + PyErr_Format(PyExc_ValueError, + "tzinfo.%s() must return a " + "whole number of minutes", + name); + result = -1; + } + } + } + else { + PyErr_Format(PyExc_TypeError, + "tzinfo.%s() must return None or " + "timedelta, not '%s'", + name, u->ob_type->tp_name); + } + + Py_DECREF(u); + if (result < -1439 || result > 1439) { + PyErr_Format(PyExc_ValueError, + "tzinfo.%s() returned %d; must be in " + "-1439 .. 1439", + name, result); + result = -1; + } + return result; +} + +/* Call tzinfo.utcoffset(tzinfoarg), and extract an integer from the + * result. tzinfo must be an instance of the tzinfo class. If utcoffset() + * returns None, call_utcoffset returns 0 and sets *none to 1. If uctoffset() + * doesn't return None or timedelta, TypeError is raised and this returns -1. + * If utcoffset() returns an invalid timedelta (out of range, or not a whole + * # of minutes), ValueError is raised and this returns -1. Else *none is + * set to 0 and the offset is returned (as int # of minutes east of UTC). + */ +static int +call_utcoffset(PyObject *tzinfo, PyObject *tzinfoarg, int *none) +{ + return call_utc_tzinfo_method(tzinfo, "utcoffset", tzinfoarg, none); +} + +/* Call tzinfo.name(tzinfoarg), and return the offset as a timedelta or None. + */ +static PyObject * +offset_as_timedelta(PyObject *tzinfo, char *name, PyObject *tzinfoarg) { + PyObject *result; + + assert(tzinfo && name && tzinfoarg); + if (tzinfo == Py_None) { + result = Py_None; + Py_INCREF(result); + } + else { + int none; + int offset = call_utc_tzinfo_method(tzinfo, name, tzinfoarg, + &none); + if (offset < 0 && PyErr_Occurred()) + return NULL; + if (none) { + result = Py_None; + Py_INCREF(result); + } + else + result = new_delta(0, offset * 60, 0, 1); + } + return result; +} + +/* Call tzinfo.dst(tzinfoarg), and extract an integer from the + * result. tzinfo must be an instance of the tzinfo class. If dst() + * returns None, call_dst returns 0 and sets *none to 1. If dst() + & doesn't return None or timedelta, TypeError is raised and this + * returns -1. If dst() returns an invalid timedelta for a UTC offset, + * ValueError is raised and this returns -1. Else *none is set to 0 and + * the offset is returned (as an int # of minutes east of UTC). + */ +static int +call_dst(PyObject *tzinfo, PyObject *tzinfoarg, int *none) +{ + return call_utc_tzinfo_method(tzinfo, "dst", tzinfoarg, none); +} + +/* Call tzinfo.tzname(tzinfoarg), and return the result. tzinfo must be + * an instance of the tzinfo class or None. If tzinfo isn't None, and + * tzname() doesn't return None or a string, TypeError is raised and this + * returns NULL. + */ +static PyObject * +call_tzname(PyObject *tzinfo, PyObject *tzinfoarg) +{ + PyObject *result; + + assert(tzinfo != NULL); + assert(check_tzinfo_subclass(tzinfo) >= 0); + assert(tzinfoarg != NULL); + + if (tzinfo == Py_None) { + result = Py_None; + Py_INCREF(result); + } + else + result = PyObject_CallMethod(tzinfo, "tzname", "O", tzinfoarg); + + if (result != NULL && result != Py_None && ! PyString_Check(result)) { + PyErr_Format(PyExc_TypeError, "tzinfo.tzname() must " + "return None or a string, not '%s'", + result->ob_type->tp_name); + Py_DECREF(result); + result = NULL; + } + return result; +} + +typedef enum { + /* an exception has been set; the caller should pass it on */ + OFFSET_ERROR, + + /* type isn't date, datetime, or time subclass */ + OFFSET_UNKNOWN, + + /* date, + * datetime with !hastzinfo + * datetime with None tzinfo, + * datetime where utcoffset() returns None + * time with !hastzinfo + * time with None tzinfo, + * time where utcoffset() returns None + */ + OFFSET_NAIVE, + + /* time or datetime where utcoffset() doesn't return None */ + OFFSET_AWARE +} naivety; + +/* Classify an object as to whether it's naive or offset-aware. See + * the "naivety" typedef for details. If the type is aware, *offset is set + * to minutes east of UTC (as returned by the tzinfo.utcoffset() method). + * If the type is offset-naive (or unknown, or error), *offset is set to 0. + * tzinfoarg is the argument to pass to the tzinfo.utcoffset() method. + */ +static naivety +classify_utcoffset(PyObject *op, PyObject *tzinfoarg, int *offset) +{ + int none; + PyObject *tzinfo; + + assert(tzinfoarg != NULL); + *offset = 0; + tzinfo = get_tzinfo_member(op); /* NULL means no tzinfo, not error */ + if (tzinfo == Py_None) + return OFFSET_NAIVE; + if (tzinfo == NULL) { + /* note that a datetime passes the PyDate_Check test */ + return (PyTime_Check(op) || PyDate_Check(op)) ? + OFFSET_NAIVE : OFFSET_UNKNOWN; + } + *offset = call_utcoffset(tzinfo, tzinfoarg, &none); + if (*offset == -1 && PyErr_Occurred()) + return OFFSET_ERROR; + return none ? OFFSET_NAIVE : OFFSET_AWARE; +} + +/* Classify two objects as to whether they're naive or offset-aware. + * This isn't quite the same as calling classify_utcoffset() twice: for + * binary operations (comparison and subtraction), we generally want to + * ignore the tzinfo members if they're identical. This is by design, + * so that results match "naive" expectations when mixing objects from a + * single timezone. So in that case, this sets both offsets to 0 and + * both naiveties to OFFSET_NAIVE. + * The function returns 0 if everything's OK, and -1 on error. + */ +static int +classify_two_utcoffsets(PyObject *o1, int *offset1, naivety *n1, + PyObject *tzinfoarg1, + PyObject *o2, int *offset2, naivety *n2, + PyObject *tzinfoarg2) +{ + if (get_tzinfo_member(o1) == get_tzinfo_member(o2)) { + *offset1 = *offset2 = 0; + *n1 = *n2 = OFFSET_NAIVE; + } + else { + *n1 = classify_utcoffset(o1, tzinfoarg1, offset1); + if (*n1 == OFFSET_ERROR) + return -1; + *n2 = classify_utcoffset(o2, tzinfoarg2, offset2); + if (*n2 == OFFSET_ERROR) + return -1; + } + return 0; +} + +/* repr is like "someclass(arg1, arg2)". If tzinfo isn't None, + * stuff + * ", tzinfo=" + repr(tzinfo) + * before the closing ")". + */ +static PyObject * +append_keyword_tzinfo(PyObject *repr, PyObject *tzinfo) +{ + PyObject *temp; + + assert(PyString_Check(repr)); + assert(tzinfo); + if (tzinfo == Py_None) + return repr; + /* Get rid of the trailing ')'. */ + assert(PyString_AsString(repr)[PyString_Size(repr)-1] == ')'); + temp = PyString_FromStringAndSize(PyString_AsString(repr), + PyString_Size(repr) - 1); + Py_DECREF(repr); + if (temp == NULL) + return NULL; + repr = temp; + + /* Append ", tzinfo=". */ + PyString_ConcatAndDel(&repr, PyString_FromString(", tzinfo=")); + + /* Append repr(tzinfo). */ + PyString_ConcatAndDel(&repr, PyObject_Repr(tzinfo)); + + /* Add a closing paren. */ + PyString_ConcatAndDel(&repr, PyString_FromString(")")); + return repr; +} + +/* --------------------------------------------------------------------------- + * String format helpers. + */ + +static PyObject * +format_ctime(PyDateTime_Date *date, int hours, int minutes, int seconds) +{ + static const char *DayNames[] = { + "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" + }; + static const char *MonthNames[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + char buffer[128]; + int wday = weekday(GET_YEAR(date), GET_MONTH(date), GET_DAY(date)); + + PyOS_snprintf(buffer, sizeof(buffer), "%s %s %2d %02d:%02d:%02d %04d", + DayNames[wday], MonthNames[GET_MONTH(date) - 1], + GET_DAY(date), hours, minutes, seconds, + GET_YEAR(date)); + return PyString_FromString(buffer); +} + +/* Add an hours & minutes UTC offset string to buf. buf has no more than + * buflen bytes remaining. The UTC offset is gotten by calling + * tzinfo.uctoffset(tzinfoarg). If that returns None, \0 is stored into + * *buf, and that's all. Else the returned value is checked for sanity (an + * integer in range), and if that's OK it's converted to an hours & minutes + * string of the form + * sign HH sep MM + * Returns 0 if everything is OK. If the return value from utcoffset() is + * bogus, an appropriate exception is set and -1 is returned. + */ +static int +format_utcoffset(char *buf, size_t buflen, const char *sep, + PyObject *tzinfo, PyObject *tzinfoarg) +{ + int offset; + int hours; + int minutes; + char sign; + int none; + + offset = call_utcoffset(tzinfo, tzinfoarg, &none); + if (offset == -1 && PyErr_Occurred()) + return -1; + if (none) { + *buf = '\0'; + return 0; + } + sign = '+'; + if (offset < 0) { + sign = '-'; + offset = - offset; + } + hours = divmod(offset, 60, &minutes); + PyOS_snprintf(buf, buflen, "%c%02d%s%02d", sign, hours, sep, minutes); + return 0; +} + +/* I sure don't want to reproduce the strftime code from the time module, + * so this imports the module and calls it. All the hair is due to + * giving special meanings to the %z and %Z format codes via a preprocessing + * step on the format string. + * tzinfoarg is the argument to pass to the object's tzinfo method, if + * needed. + */ +static PyObject * +wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple, + PyObject *tzinfoarg) +{ + PyObject *result = NULL; /* guilty until proved innocent */ + + PyObject *zreplacement = NULL; /* py string, replacement for %z */ + PyObject *Zreplacement = NULL; /* py string, replacement for %Z */ + + char *pin; /* pointer to next char in input format */ + char ch; /* next char in input format */ + + PyObject *newfmt = NULL; /* py string, the output format */ + char *pnew; /* pointer to available byte in output format */ + int totalnew; /* number bytes total in output format buffer, + exclusive of trailing \0 */ + int usednew; /* number bytes used so far in output format buffer */ + + char *ptoappend; /* pointer to string to append to output buffer */ + int ntoappend; /* # of bytes to append to output buffer */ + + assert(object && format && timetuple); + assert(PyString_Check(format)); + + /* Give up if the year is before 1900. + * Python strftime() plays games with the year, and different + * games depending on whether envar PYTHON2K is set. This makes + * years before 1900 a nightmare, even if the platform strftime + * supports them (and not all do). + * We could get a lot farther here by avoiding Python's strftime + * wrapper and calling the C strftime() directly, but that isn't + * an option in the Python implementation of this module. + */ + { + long year; + PyObject *pyyear = PySequence_GetItem(timetuple, 0); + if (pyyear == NULL) return NULL; + assert(PyInt_Check(pyyear)); + year = PyInt_AsLong(pyyear); + Py_DECREF(pyyear); + if (year < 1900) { + PyErr_Format(PyExc_ValueError, "year=%ld is before " + "1900; the datetime strftime() " + "methods require year >= 1900", + year); + return NULL; + } + } + + /* Scan the input format, looking for %z and %Z escapes, building + * a new format. Since computing the replacements for those codes + * is expensive, don't unless they're actually used. + */ + totalnew = PyString_Size(format) + 1; /* realistic if no %z/%Z */ + newfmt = PyString_FromStringAndSize(NULL, totalnew); + if (newfmt == NULL) goto Done; + pnew = PyString_AsString(newfmt); + usednew = 0; + + pin = PyString_AsString(format); + while ((ch = *pin++) != '\0') { + if (ch != '%') { + ptoappend = pin - 1; + ntoappend = 1; + } + else if ((ch = *pin++) == '\0') { + /* There's a lone trailing %; doesn't make sense. */ + PyErr_SetString(PyExc_ValueError, "strftime format " + "ends with raw %"); + goto Done; + } + /* A % has been seen and ch is the character after it. */ + else if (ch == 'z') { + if (zreplacement == NULL) { + /* format utcoffset */ + char buf[100]; + PyObject *tzinfo = get_tzinfo_member(object); + zreplacement = PyString_FromString(""); + if (zreplacement == NULL) goto Done; + if (tzinfo != Py_None && tzinfo != NULL) { + assert(tzinfoarg != NULL); + if (format_utcoffset(buf, + sizeof(buf), + "", + tzinfo, + tzinfoarg) < 0) + goto Done; + Py_DECREF(zreplacement); + zreplacement = PyString_FromString(buf); + if (zreplacement == NULL) goto Done; + } + } + assert(zreplacement != NULL); + ptoappend = PyString_AS_STRING(zreplacement); + ntoappend = PyString_GET_SIZE(zreplacement); + } + else if (ch == 'Z') { + /* format tzname */ + if (Zreplacement == NULL) { + PyObject *tzinfo = get_tzinfo_member(object); + Zreplacement = PyString_FromString(""); + if (Zreplacement == NULL) goto Done; + if (tzinfo != Py_None && tzinfo != NULL) { + PyObject *temp; + assert(tzinfoarg != NULL); + temp = call_tzname(tzinfo, tzinfoarg); + if (temp == NULL) goto Done; + if (temp != Py_None) { + assert(PyString_Check(temp)); + /* Since the tzname is getting + * stuffed into the format, we + * have to double any % signs + * so that strftime doesn't + * treat them as format codes. + */ + Py_DECREF(Zreplacement); + Zreplacement = PyObject_CallMethod( + temp, "replace", + "ss", "%", "%%"); + Py_DECREF(temp); + if (Zreplacement == NULL) + goto Done; + if (!PyString_Check(Zreplacement)) { + PyErr_SetString(PyExc_TypeError, "tzname.replace() did not return a string"); + goto Done; + } + } + else + Py_DECREF(temp); + } + } + assert(Zreplacement != NULL); + ptoappend = PyString_AS_STRING(Zreplacement); + ntoappend = PyString_GET_SIZE(Zreplacement); + } + else { + /* percent followed by neither z nor Z */ + ptoappend = pin - 2; + ntoappend = 2; + } + + /* Append the ntoappend chars starting at ptoappend to + * the new format. + */ + assert(ptoappend != NULL); + assert(ntoappend >= 0); + if (ntoappend == 0) + continue; + while (usednew + ntoappend > totalnew) { + int bigger = totalnew << 1; + if ((bigger >> 1) != totalnew) { /* overflow */ + PyErr_NoMemory(); + goto Done; + } + if (_PyString_Resize(&newfmt, bigger) < 0) + goto Done; + totalnew = bigger; + pnew = PyString_AsString(newfmt) + usednew; + } + memcpy(pnew, ptoappend, ntoappend); + pnew += ntoappend; + usednew += ntoappend; + assert(usednew <= totalnew); + } /* end while() */ + + if (_PyString_Resize(&newfmt, usednew) < 0) + goto Done; + { + PyObject *time = PyImport_ImportModule("time"); + if (time == NULL) + goto Done; + result = PyObject_CallMethod(time, "strftime", "OO", + newfmt, timetuple); + Py_DECREF(time); + } + Done: + Py_XDECREF(zreplacement); + Py_XDECREF(Zreplacement); + Py_XDECREF(newfmt); + return result; +} + +static char * +isoformat_date(PyDateTime_Date *dt, char buffer[], int bufflen) +{ + int x; + x = PyOS_snprintf(buffer, bufflen, + "%04d-%02d-%02d", + GET_YEAR(dt), GET_MONTH(dt), GET_DAY(dt)); + return buffer + x; +} + +static void +isoformat_time(PyDateTime_DateTime *dt, char buffer[], int bufflen) +{ + int us = DATE_GET_MICROSECOND(dt); + + PyOS_snprintf(buffer, bufflen, + "%02d:%02d:%02d", /* 8 characters */ + DATE_GET_HOUR(dt), + DATE_GET_MINUTE(dt), + DATE_GET_SECOND(dt)); + if (us) + PyOS_snprintf(buffer + 8, bufflen - 8, ".%06d", us); +} + +/* --------------------------------------------------------------------------- + * Wrap functions from the time module. These aren't directly available + * from C. Perhaps they should be. + */ + +/* Call time.time() and return its result (a Python float). */ +static PyObject * +time_time(void) +{ + PyObject *result = NULL; + PyObject *time = PyImport_ImportModule("time"); + + if (time != NULL) { + result = PyObject_CallMethod(time, "time", "()"); + Py_DECREF(time); + } + return result; +} + +/* Build a time.struct_time. The weekday and day number are automatically + * computed from the y,m,d args. + */ +static PyObject * +build_struct_time(int y, int m, int d, int hh, int mm, int ss, int dstflag) +{ + PyObject *time; + PyObject *result = NULL; + + time = PyImport_ImportModule("time"); + if (time != NULL) { + result = PyObject_CallMethod(time, "struct_time", + "((iiiiiiiii))", + y, m, d, + hh, mm, ss, + weekday(y, m, d), + days_before_month(y, m) + d, + dstflag); + Py_DECREF(time); + } + return result; +} + +/* --------------------------------------------------------------------------- + * Miscellaneous helpers. + */ + +/* For obscure reasons, we need to use tp_richcompare instead of tp_compare. + * The comparisons here all most naturally compute a cmp()-like result. + * This little helper turns that into a bool result for rich comparisons. + */ +static PyObject * +diff_to_bool(int diff, int op) +{ + PyObject *result; + int istrue; + + switch (op) { + case Py_EQ: istrue = diff == 0; break; + case Py_NE: istrue = diff != 0; break; + case Py_LE: istrue = diff <= 0; break; + case Py_GE: istrue = diff >= 0; break; + case Py_LT: istrue = diff < 0; break; + case Py_GT: istrue = diff > 0; break; + default: + assert(! "op unknown"); + istrue = 0; /* To shut up compiler */ + } + result = istrue ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +/* Raises a "can't compare" TypeError and returns NULL. */ +static PyObject * +cmperror(PyObject *a, PyObject *b) +{ + PyErr_Format(PyExc_TypeError, + "can't compare %s to %s", + a->ob_type->tp_name, b->ob_type->tp_name); + return NULL; +} + +/* --------------------------------------------------------------------------- + * Cached Python objects; these are set by the module init function. + */ + +/* Conversion factors. */ +static PyObject *us_per_us = NULL; /* 1 */ +static PyObject *us_per_ms = NULL; /* 1000 */ +static PyObject *us_per_second = NULL; /* 1000000 */ +static PyObject *us_per_minute = NULL; /* 1e6 * 60 as Python int */ +static PyObject *us_per_hour = NULL; /* 1e6 * 3600 as Python long */ +static PyObject *us_per_day = NULL; /* 1e6 * 3600 * 24 as Python long */ +static PyObject *us_per_week = NULL; /* 1e6*3600*24*7 as Python long */ +static PyObject *seconds_per_day = NULL; /* 3600*24 as Python int */ + +/* --------------------------------------------------------------------------- + * Class implementations. + */ + +/* + * PyDateTime_Delta implementation. + */ + +/* Convert a timedelta to a number of us, + * (24*3600*self.days + self.seconds)*1000000 + self.microseconds + * as a Python int or long. + * Doing mixed-radix arithmetic by hand instead is excruciating in C, + * due to ubiquitous overflow possibilities. + */ +static PyObject * +delta_to_microseconds(PyDateTime_Delta *self) +{ + PyObject *x1 = NULL; + PyObject *x2 = NULL; + PyObject *x3 = NULL; + PyObject *result = NULL; + + x1 = PyInt_FromLong(GET_TD_DAYS(self)); + if (x1 == NULL) + goto Done; + x2 = PyNumber_Multiply(x1, seconds_per_day); /* days in seconds */ + if (x2 == NULL) + goto Done; + Py_DECREF(x1); + x1 = NULL; + + /* x2 has days in seconds */ + x1 = PyInt_FromLong(GET_TD_SECONDS(self)); /* seconds */ + if (x1 == NULL) + goto Done; + x3 = PyNumber_Add(x1, x2); /* days and seconds in seconds */ + if (x3 == NULL) + goto Done; + Py_DECREF(x1); + Py_DECREF(x2); + x1 = x2 = NULL; + + /* x3 has days+seconds in seconds */ + x1 = PyNumber_Multiply(x3, us_per_second); /* us */ + if (x1 == NULL) + goto Done; + Py_DECREF(x3); + x3 = NULL; + + /* x1 has days+seconds in us */ + x2 = PyInt_FromLong(GET_TD_MICROSECONDS(self)); + if (x2 == NULL) + goto Done; + result = PyNumber_Add(x1, x2); + +Done: + Py_XDECREF(x1); + Py_XDECREF(x2); + Py_XDECREF(x3); + return result; +} + +/* Convert a number of us (as a Python int or long) to a timedelta. + */ +static PyObject * +microseconds_to_delta_ex(PyObject *pyus, PyTypeObject *type) +{ + int us; + int s; + int d; + long temp; + + PyObject *tuple = NULL; + PyObject *num = NULL; + PyObject *result = NULL; + + tuple = PyNumber_Divmod(pyus, us_per_second); + if (tuple == NULL) + goto Done; + + num = PyTuple_GetItem(tuple, 1); /* us */ + if (num == NULL) + goto Done; + temp = PyLong_AsLong(num); + num = NULL; + if (temp == -1 && PyErr_Occurred()) + goto Done; + assert(0 <= temp && temp < 1000000); + us = (int)temp; + if (us < 0) { + /* The divisor was positive, so this must be an error. */ + assert(PyErr_Occurred()); + goto Done; + } + + num = PyTuple_GetItem(tuple, 0); /* leftover seconds */ + if (num == NULL) + goto Done; + Py_INCREF(num); + Py_DECREF(tuple); + + tuple = PyNumber_Divmod(num, seconds_per_day); + if (tuple == NULL) + goto Done; + Py_DECREF(num); + + num = PyTuple_GetItem(tuple, 1); /* seconds */ + if (num == NULL) + goto Done; + temp = PyLong_AsLong(num); + num = NULL; + if (temp == -1 && PyErr_Occurred()) + goto Done; + assert(0 <= temp && temp < 24*3600); + s = (int)temp; + + if (s < 0) { + /* The divisor was positive, so this must be an error. */ + assert(PyErr_Occurred()); + goto Done; + } + + num = PyTuple_GetItem(tuple, 0); /* leftover days */ + if (num == NULL) + goto Done; + Py_INCREF(num); + temp = PyLong_AsLong(num); + if (temp == -1 && PyErr_Occurred()) + goto Done; + d = (int)temp; + if ((long)d != temp) { + PyErr_SetString(PyExc_OverflowError, "normalized days too " + "large to fit in a C int"); + goto Done; + } + result = new_delta_ex(d, s, us, 0, type); + +Done: + Py_XDECREF(tuple); + Py_XDECREF(num); + return result; +} + +#define microseconds_to_delta(pymicros) \ + microseconds_to_delta_ex(pymicros, &PyDateTime_DeltaType) + +static PyObject * +multiply_int_timedelta(PyObject *intobj, PyDateTime_Delta *delta) +{ + PyObject *pyus_in; + PyObject *pyus_out; + PyObject *result; + + pyus_in = delta_to_microseconds(delta); + if (pyus_in == NULL) + return NULL; + + pyus_out = PyNumber_Multiply(pyus_in, intobj); + Py_DECREF(pyus_in); + if (pyus_out == NULL) + return NULL; + + result = microseconds_to_delta(pyus_out); + Py_DECREF(pyus_out); + return result; +} + +static PyObject * +divide_timedelta_int(PyDateTime_Delta *delta, PyObject *intobj) +{ + PyObject *pyus_in; + PyObject *pyus_out; + PyObject *result; + + pyus_in = delta_to_microseconds(delta); + if (pyus_in == NULL) + return NULL; + + pyus_out = PyNumber_FloorDivide(pyus_in, intobj); + Py_DECREF(pyus_in); + if (pyus_out == NULL) + return NULL; + + result = microseconds_to_delta(pyus_out); + Py_DECREF(pyus_out); + return result; +} + +static PyObject * +delta_add(PyObject *left, PyObject *right) +{ + PyObject *result = Py_NotImplemented; + + if (PyDelta_Check(left) && PyDelta_Check(right)) { + /* delta + delta */ + /* The C-level additions can't overflow because of the + * invariant bounds. + */ + int days = GET_TD_DAYS(left) + GET_TD_DAYS(right); + int seconds = GET_TD_SECONDS(left) + GET_TD_SECONDS(right); + int microseconds = GET_TD_MICROSECONDS(left) + + GET_TD_MICROSECONDS(right); + result = new_delta(days, seconds, microseconds, 1); + } + + if (result == Py_NotImplemented) + Py_INCREF(result); + return result; +} + +static PyObject * +delta_negative(PyDateTime_Delta *self) +{ + return new_delta(-GET_TD_DAYS(self), + -GET_TD_SECONDS(self), + -GET_TD_MICROSECONDS(self), + 1); +} + +static PyObject * +delta_positive(PyDateTime_Delta *self) +{ + /* Could optimize this (by returning self) if this isn't a + * subclass -- but who uses unary + ? Approximately nobody. + */ + return new_delta(GET_TD_DAYS(self), + GET_TD_SECONDS(self), + GET_TD_MICROSECONDS(self), + 0); +} + +static PyObject * +delta_abs(PyDateTime_Delta *self) +{ + PyObject *result; + + assert(GET_TD_MICROSECONDS(self) >= 0); + assert(GET_TD_SECONDS(self) >= 0); + + if (GET_TD_DAYS(self) < 0) + result = delta_negative(self); + else + result = delta_positive(self); + + return result; +} + +static PyObject * +delta_subtract(PyObject *left, PyObject *right) +{ + PyObject *result = Py_NotImplemented; + + if (PyDelta_Check(left) && PyDelta_Check(right)) { + /* delta - delta */ + PyObject *minus_right = PyNumber_Negative(right); + if (minus_right) { + result = delta_add(left, minus_right); + Py_DECREF(minus_right); + } + else + result = NULL; + } + + if (result == Py_NotImplemented) + Py_INCREF(result); + return result; +} + +/* This is more natural as a tp_compare, but doesn't work then: for whatever + * reason, Python's try_3way_compare ignores tp_compare unless + * PyInstance_Check returns true, but these aren't old-style classes. + */ +static PyObject * +delta_richcompare(PyDateTime_Delta *self, PyObject *other, int op) +{ + int diff = 42; /* nonsense */ + + if (PyDelta_Check(other)) { + diff = GET_TD_DAYS(self) - GET_TD_DAYS(other); + if (diff == 0) { + diff = GET_TD_SECONDS(self) - GET_TD_SECONDS(other); + if (diff == 0) + diff = GET_TD_MICROSECONDS(self) - + GET_TD_MICROSECONDS(other); + } + } + else if (op == Py_EQ || op == Py_NE) + diff = 1; /* any non-zero value will do */ + + else /* stop this from falling back to address comparison */ + return cmperror((PyObject *)self, other); + + return diff_to_bool(diff, op); +} + +static PyObject *delta_getstate(PyDateTime_Delta *self); + +static long +delta_hash(PyDateTime_Delta *self) +{ + if (self->hashcode == -1) { + PyObject *temp = delta_getstate(self); + if (temp != NULL) { + self->hashcode = PyObject_Hash(temp); + Py_DECREF(temp); + } + } + return self->hashcode; +} + +static PyObject * +delta_multiply(PyObject *left, PyObject *right) +{ + PyObject *result = Py_NotImplemented; + + if (PyDelta_Check(left)) { + /* delta * ??? */ + if (PyInt_Check(right) || PyLong_Check(right)) + result = multiply_int_timedelta(right, + (PyDateTime_Delta *) left); + } + else if (PyInt_Check(left) || PyLong_Check(left)) + result = multiply_int_timedelta(left, + (PyDateTime_Delta *) right); + + if (result == Py_NotImplemented) + Py_INCREF(result); + return result; +} + +static PyObject * +delta_divide(PyObject *left, PyObject *right) +{ + PyObject *result = Py_NotImplemented; + + if (PyDelta_Check(left)) { + /* delta * ??? */ + if (PyInt_Check(right) || PyLong_Check(right)) + result = divide_timedelta_int( + (PyDateTime_Delta *)left, + right); + } + + if (result == Py_NotImplemented) + Py_INCREF(result); + return result; +} + +/* Fold in the value of the tag ("seconds", "weeks", etc) component of a + * timedelta constructor. sofar is the # of microseconds accounted for + * so far, and there are factor microseconds per current unit, the number + * of which is given by num. num * factor is added to sofar in a + * numerically careful way, and that's the result. Any fractional + * microseconds left over (this can happen if num is a float type) are + * added into *leftover. + * Note that there are many ways this can give an error (NULL) return. + */ +static PyObject * +accum(const char* tag, PyObject *sofar, PyObject *num, PyObject *factor, + double *leftover) +{ + PyObject *prod; + PyObject *sum; + + assert(num != NULL); + + if (PyInt_Check(num) || PyLong_Check(num)) { + prod = PyNumber_Multiply(num, factor); + if (prod == NULL) + return NULL; + sum = PyNumber_Add(sofar, prod); + Py_DECREF(prod); + return sum; + } + + if (PyFloat_Check(num)) { + double dnum; + double fracpart; + double intpart; + PyObject *x; + PyObject *y; + + /* The Plan: decompose num into an integer part and a + * fractional part, num = intpart + fracpart. + * Then num * factor == + * intpart * factor + fracpart * factor + * and the LHS can be computed exactly in long arithmetic. + * The RHS is again broken into an int part and frac part. + * and the frac part is added into *leftover. + */ + dnum = PyFloat_AsDouble(num); + if (dnum == -1.0 && PyErr_Occurred()) + return NULL; + fracpart = modf(dnum, &intpart); + x = PyLong_FromDouble(intpart); + if (x == NULL) + return NULL; + + prod = PyNumber_Multiply(x, factor); + Py_DECREF(x); + if (prod == NULL) + return NULL; + + sum = PyNumber_Add(sofar, prod); + Py_DECREF(prod); + if (sum == NULL) + return NULL; + + if (fracpart == 0.0) + return sum; + /* So far we've lost no information. Dealing with the + * fractional part requires float arithmetic, and may + * lose a little info. + */ + assert(PyInt_Check(factor) || PyLong_Check(factor)); + if (PyInt_Check(factor)) + dnum = (double)PyInt_AsLong(factor); + else + dnum = PyLong_AsDouble(factor); + + dnum *= fracpart; + fracpart = modf(dnum, &intpart); + x = PyLong_FromDouble(intpart); + if (x == NULL) { + Py_DECREF(sum); + return NULL; + } + + y = PyNumber_Add(sum, x); + Py_DECREF(sum); + Py_DECREF(x); + *leftover += fracpart; + return y; + } + + PyErr_Format(PyExc_TypeError, + "unsupported type for timedelta %s component: %s", + tag, num->ob_type->tp_name); + return NULL; +} + +static PyObject * +delta_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *self = NULL; + + /* Argument objects. */ + PyObject *day = NULL; + PyObject *second = NULL; + PyObject *us = NULL; + PyObject *ms = NULL; + PyObject *minute = NULL; + PyObject *hour = NULL; + PyObject *week = NULL; + + PyObject *x = NULL; /* running sum of microseconds */ + PyObject *y = NULL; /* temp sum of microseconds */ + double leftover_us = 0.0; + + static char *keywords[] = { + "days", "seconds", "microseconds", "milliseconds", + "minutes", "hours", "weeks", NULL + }; + + if (PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOO:__new__", + keywords, + &day, &second, &us, + &ms, &minute, &hour, &week) == 0) + goto Done; + + x = PyInt_FromLong(0); + if (x == NULL) + goto Done; + +#define CLEANUP \ + Py_DECREF(x); \ + x = y; \ + if (x == NULL) \ + goto Done + + if (us) { + y = accum("microseconds", x, us, us_per_us, &leftover_us); + CLEANUP; + } + if (ms) { + y = accum("milliseconds", x, ms, us_per_ms, &leftover_us); + CLEANUP; + } + if (second) { + y = accum("seconds", x, second, us_per_second, &leftover_us); + CLEANUP; + } + if (minute) { + y = accum("minutes", x, minute, us_per_minute, &leftover_us); + CLEANUP; + } + if (hour) { + y = accum("hours", x, hour, us_per_hour, &leftover_us); + CLEANUP; + } + if (day) { + y = accum("days", x, day, us_per_day, &leftover_us); + CLEANUP; + } + if (week) { + y = accum("weeks", x, week, us_per_week, &leftover_us); + CLEANUP; + } + if (leftover_us) { + /* Round to nearest whole # of us, and add into x. */ + PyObject *temp = PyLong_FromLong(round_to_long(leftover_us)); + if (temp == NULL) { + Py_DECREF(x); + goto Done; + } + y = PyNumber_Add(x, temp); + Py_DECREF(temp); + CLEANUP; + } + + self = microseconds_to_delta_ex(x, type); + Py_DECREF(x); +Done: + return self; + +#undef CLEANUP +} + +static int +delta_nonzero(PyDateTime_Delta *self) +{ + return (GET_TD_DAYS(self) != 0 + || GET_TD_SECONDS(self) != 0 + || GET_TD_MICROSECONDS(self) != 0); +} + +static PyObject * +delta_repr(PyDateTime_Delta *self) +{ + if (GET_TD_MICROSECONDS(self) != 0) + return PyString_FromFormat("%s(%d, %d, %d)", + self->ob_type->tp_name, + GET_TD_DAYS(self), + GET_TD_SECONDS(self), + GET_TD_MICROSECONDS(self)); + if (GET_TD_SECONDS(self) != 0) + return PyString_FromFormat("%s(%d, %d)", + self->ob_type->tp_name, + GET_TD_DAYS(self), + GET_TD_SECONDS(self)); + + return PyString_FromFormat("%s(%d)", + self->ob_type->tp_name, + GET_TD_DAYS(self)); +} + +static PyObject * +delta_str(PyDateTime_Delta *self) +{ + int days = GET_TD_DAYS(self); + int seconds = GET_TD_SECONDS(self); + int us = GET_TD_MICROSECONDS(self); + int hours; + int minutes; + char buf[100]; + char *pbuf = buf; + size_t buflen = sizeof(buf); + int n; + + minutes = divmod(seconds, 60, &seconds); + hours = divmod(minutes, 60, &minutes); + + if (days) { + n = PyOS_snprintf(pbuf, buflen, "%d day%s, ", days, + (days == 1 || days == -1) ? "" : "s"); + if (n < 0 || (size_t)n >= buflen) + goto Fail; + pbuf += n; + buflen -= (size_t)n; + } + + n = PyOS_snprintf(pbuf, buflen, "%d:%02d:%02d", + hours, minutes, seconds); + if (n < 0 || (size_t)n >= buflen) + goto Fail; + pbuf += n; + buflen -= (size_t)n; + + if (us) { + n = PyOS_snprintf(pbuf, buflen, ".%06d", us); + if (n < 0 || (size_t)n >= buflen) + goto Fail; + pbuf += n; + } + + return PyString_FromStringAndSize(buf, pbuf - buf); + + Fail: + PyErr_SetString(PyExc_SystemError, "goofy result from PyOS_snprintf"); + return NULL; +} + +/* Pickle support, a simple use of __reduce__. */ + +/* __getstate__ isn't exposed */ +static PyObject * +delta_getstate(PyDateTime_Delta *self) +{ + return Py_BuildValue("iii", GET_TD_DAYS(self), + GET_TD_SECONDS(self), + GET_TD_MICROSECONDS(self)); +} + +static PyObject * +delta_reduce(PyDateTime_Delta* self) +{ + return Py_BuildValue("ON", self->ob_type, delta_getstate(self)); +} + +#define OFFSET(field) offsetof(PyDateTime_Delta, field) + +static PyMemberDef delta_members[] = { + + {"days", T_INT, OFFSET(days), READONLY, + PyDoc_STR("Number of days.")}, + + {"seconds", T_INT, OFFSET(seconds), READONLY, + PyDoc_STR("Number of seconds (>= 0 and less than 1 day).")}, + + {"microseconds", T_INT, OFFSET(microseconds), READONLY, + PyDoc_STR("Number of microseconds (>= 0 and less than 1 second).")}, + {NULL} +}; + +static PyMethodDef delta_methods[] = { + {"__reduce__", (PyCFunction)delta_reduce, METH_NOARGS, + PyDoc_STR("__reduce__() -> (cls, state)")}, + + {NULL, NULL}, +}; + +static char delta_doc[] = +PyDoc_STR("Difference between two datetime values."); + +static PyNumberMethods delta_as_number = { + delta_add, /* nb_add */ + delta_subtract, /* nb_subtract */ + delta_multiply, /* nb_multiply */ + delta_divide, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + (unaryfunc)delta_negative, /* nb_negative */ + (unaryfunc)delta_positive, /* nb_positive */ + (unaryfunc)delta_abs, /* nb_absolute */ + (inquiry)delta_nonzero, /* nb_nonzero */ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + 0, /*nb_coerce*/ + 0, /*nb_int*/ + 0, /*nb_long*/ + 0, /*nb_float*/ + 0, /*nb_oct*/ + 0, /*nb_hex*/ + 0, /*nb_inplace_add*/ + 0, /*nb_inplace_subtract*/ + 0, /*nb_inplace_multiply*/ + 0, /*nb_inplace_divide*/ + 0, /*nb_inplace_remainder*/ + 0, /*nb_inplace_power*/ + 0, /*nb_inplace_lshift*/ + 0, /*nb_inplace_rshift*/ + 0, /*nb_inplace_and*/ + 0, /*nb_inplace_xor*/ + 0, /*nb_inplace_or*/ + delta_divide, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ +}; + +static PyTypeObject PyDateTime_DeltaType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "datetime.timedelta", /* tp_name */ + sizeof(PyDateTime_Delta), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)delta_repr, /* tp_repr */ + &delta_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)delta_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)delta_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + delta_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)delta_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + delta_methods, /* tp_methods */ + delta_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + delta_new, /* tp_new */ + 0, /* tp_free */ +}; + +/* + * PyDateTime_Date implementation. + */ + +/* Accessor properties. */ + +static PyObject * +date_year(PyDateTime_Date *self, void *unused) +{ + return PyInt_FromLong(GET_YEAR(self)); +} + +static PyObject * +date_month(PyDateTime_Date *self, void *unused) +{ + return PyInt_FromLong(GET_MONTH(self)); +} + +static PyObject * +date_day(PyDateTime_Date *self, void *unused) +{ + return PyInt_FromLong(GET_DAY(self)); +} + +static PyGetSetDef date_getset[] = { + {"year", (getter)date_year}, + {"month", (getter)date_month}, + {"day", (getter)date_day}, + {NULL} +}; + +/* Constructors. */ + +static char *date_kws[] = {"year", "month", "day", NULL}; + +static PyObject * +date_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *self = NULL; + PyObject *state; + int year; + int month; + int day; + + /* Check for invocation from pickle with __getstate__ state */ + if (PyTuple_GET_SIZE(args) == 1 && + PyString_Check(state = PyTuple_GET_ITEM(args, 0)) && + PyString_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE && + MONTH_IS_SANE(PyString_AS_STRING(state)[2])) + { + PyDateTime_Date *me; + + me = (PyDateTime_Date *) (type->tp_alloc(type, 0)); + if (me != NULL) { + char *pdata = PyString_AS_STRING(state); + memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE); + me->hashcode = -1; + } + return (PyObject *)me; + } + + if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws, + &year, &month, &day)) { + if (check_date_args(year, month, day) < 0) + return NULL; + self = new_date_ex(year, month, day, type); + } + return self; +} + +/* Return new date from localtime(t). */ +static PyObject * +date_local_from_time_t(PyObject *cls, double ts) +{ + struct tm *tm; + time_t t; + PyObject *result = NULL; + + t = _PyTime_DoubleToTimet(ts); + if (t == (time_t)-1 && PyErr_Occurred()) + return NULL; + tm = localtime(&t); + if (tm) + result = PyObject_CallFunction(cls, "iii", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday); + else + PyErr_SetString(PyExc_ValueError, + "timestamp out of range for " + "platform localtime() function"); + return result; +} + +/* Return new date from current time. + * We say this is equivalent to fromtimestamp(time.time()), and the + * only way to be sure of that is to *call* time.time(). That's not + * generally the same as calling C's time. + */ +static PyObject * +date_today(PyObject *cls, PyObject *dummy) +{ + PyObject *time; + PyObject *result; + + time = time_time(); + if (time == NULL) + return NULL; + + /* Note well: today() is a class method, so this may not call + * date.fromtimestamp. For example, it may call + * datetime.fromtimestamp. That's why we need all the accuracy + * time.time() delivers; if someone were gonzo about optimization, + * date.today() could get away with plain C time(). + */ + result = PyObject_CallMethod(cls, "fromtimestamp", "O", time); + Py_DECREF(time); + return result; +} + +/* Return new date from given timestamp (Python timestamp -- a double). */ +static PyObject * +date_fromtimestamp(PyObject *cls, PyObject *args) +{ + double timestamp; + PyObject *result = NULL; + + if (PyArg_ParseTuple(args, "d:fromtimestamp", &timestamp)) + result = date_local_from_time_t(cls, timestamp); + return result; +} + +/* Return new date from proleptic Gregorian ordinal. Raises ValueError if + * the ordinal is out of range. + */ +static PyObject * +date_fromordinal(PyObject *cls, PyObject *args) +{ + PyObject *result = NULL; + int ordinal; + + if (PyArg_ParseTuple(args, "i:fromordinal", &ordinal)) { + int year; + int month; + int day; + + if (ordinal < 1) + PyErr_SetString(PyExc_ValueError, "ordinal must be " + ">= 1"); + else { + ord_to_ymd(ordinal, &year, &month, &day); + result = PyObject_CallFunction(cls, "iii", + year, month, day); + } + } + return result; +} + +/* + * Date arithmetic. + */ + +/* date + timedelta -> date. If arg negate is true, subtract the timedelta + * instead. + */ +static PyObject * +add_date_timedelta(PyDateTime_Date *date, PyDateTime_Delta *delta, int negate) +{ + PyObject *result = NULL; + int year = GET_YEAR(date); + int month = GET_MONTH(date); + int deltadays = GET_TD_DAYS(delta); + /* C-level overflow is impossible because |deltadays| < 1e9. */ + int day = GET_DAY(date) + (negate ? -deltadays : deltadays); + + if (normalize_date(&year, &month, &day) >= 0) + result = new_date(year, month, day); + return result; +} + +static PyObject * +date_add(PyObject *left, PyObject *right) +{ + if (PyDateTime_Check(left) || PyDateTime_Check(right)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (PyDate_Check(left)) { + /* date + ??? */ + if (PyDelta_Check(right)) + /* date + delta */ + return add_date_timedelta((PyDateTime_Date *) left, + (PyDateTime_Delta *) right, + 0); + } + else { + /* ??? + date + * 'right' must be one of us, or we wouldn't have been called + */ + if (PyDelta_Check(left)) + /* delta + date */ + return add_date_timedelta((PyDateTime_Date *) right, + (PyDateTime_Delta *) left, + 0); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyObject * +date_subtract(PyObject *left, PyObject *right) +{ + if (PyDateTime_Check(left) || PyDateTime_Check(right)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (PyDate_Check(left)) { + if (PyDate_Check(right)) { + /* date - date */ + int left_ord = ymd_to_ord(GET_YEAR(left), + GET_MONTH(left), + GET_DAY(left)); + int right_ord = ymd_to_ord(GET_YEAR(right), + GET_MONTH(right), + GET_DAY(right)); + return new_delta(left_ord - right_ord, 0, 0, 0); + } + if (PyDelta_Check(right)) { + /* date - delta */ + return add_date_timedelta((PyDateTime_Date *) left, + (PyDateTime_Delta *) right, + 1); + } + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + + +/* Various ways to turn a date into a string. */ + +static PyObject * +date_repr(PyDateTime_Date *self) +{ + char buffer[1028]; + const char *type_name; + + type_name = self->ob_type->tp_name; + PyOS_snprintf(buffer, sizeof(buffer), "%s(%d, %d, %d)", + type_name, + GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); + + return PyString_FromString(buffer); +} + +static PyObject * +date_isoformat(PyDateTime_Date *self) +{ + char buffer[128]; + + isoformat_date(self, buffer, sizeof(buffer)); + return PyString_FromString(buffer); +} + +/* str() calls the appropriate isoformat() method. */ +static PyObject * +date_str(PyDateTime_Date *self) +{ + return PyObject_CallMethod((PyObject *)self, "isoformat", "()"); +} + + +static PyObject * +date_ctime(PyDateTime_Date *self) +{ + return format_ctime(self, 0, 0, 0); +} + +static PyObject * +date_strftime(PyDateTime_Date *self, PyObject *args, PyObject *kw) +{ + /* This method can be inherited, and needs to call the + * timetuple() method appropriate to self's class. + */ + PyObject *result; + PyObject *format; + PyObject *tuple; + static char *keywords[] = {"format", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kw, "O!:strftime", keywords, + &PyString_Type, &format)) + return NULL; + + tuple = PyObject_CallMethod((PyObject *)self, "timetuple", "()"); + if (tuple == NULL) + return NULL; + result = wrap_strftime((PyObject *)self, format, tuple, + (PyObject *)self); + Py_DECREF(tuple); + return result; +} + +/* ISO methods. */ + +static PyObject * +date_isoweekday(PyDateTime_Date *self) +{ + int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); + + return PyInt_FromLong(dow + 1); +} + +static PyObject * +date_isocalendar(PyDateTime_Date *self) +{ + int year = GET_YEAR(self); + int week1_monday = iso_week1_monday(year); + int today = ymd_to_ord(year, GET_MONTH(self), GET_DAY(self)); + int week; + int day; + + week = divmod(today - week1_monday, 7, &day); + if (week < 0) { + --year; + week1_monday = iso_week1_monday(year); + week = divmod(today - week1_monday, 7, &day); + } + else if (week >= 52 && today >= iso_week1_monday(year + 1)) { + ++year; + week = 0; + } + return Py_BuildValue("iii", year, week + 1, day + 1); +} + +/* Miscellaneous methods. */ + +/* This is more natural as a tp_compare, but doesn't work then: for whatever + * reason, Python's try_3way_compare ignores tp_compare unless + * PyInstance_Check returns true, but these aren't old-style classes. + */ +static PyObject * +date_richcompare(PyDateTime_Date *self, PyObject *other, int op) +{ + int diff = 42; /* nonsense */ + + if (PyDate_Check(other)) + diff = memcmp(self->data, ((PyDateTime_Date *)other)->data, + _PyDateTime_DATE_DATASIZE); + + else if (PyObject_HasAttrString(other, "timetuple")) { + /* A hook for other kinds of date objects. */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + else if (op == Py_EQ || op == Py_NE) + diff = 1; /* any non-zero value will do */ + + else /* stop this from falling back to address comparison */ + return cmperror((PyObject *)self, other); + + return diff_to_bool(diff, op); +} + +static PyObject * +date_timetuple(PyDateTime_Date *self) +{ + return build_struct_time(GET_YEAR(self), + GET_MONTH(self), + GET_DAY(self), + 0, 0, 0, -1); +} + +static PyObject * +date_replace(PyDateTime_Date *self, PyObject *args, PyObject *kw) +{ + PyObject *clone; + PyObject *tuple; + int year = GET_YEAR(self); + int month = GET_MONTH(self); + int day = GET_DAY(self); + + if (! PyArg_ParseTupleAndKeywords(args, kw, "|iii:replace", date_kws, + &year, &month, &day)) + return NULL; + tuple = Py_BuildValue("iii", year, month, day); + if (tuple == NULL) + return NULL; + clone = date_new(self->ob_type, tuple, NULL); + Py_DECREF(tuple); + return clone; +} + +static PyObject *date_getstate(PyDateTime_Date *self); + +static long +date_hash(PyDateTime_Date *self) +{ + if (self->hashcode == -1) { + PyObject *temp = date_getstate(self); + if (temp != NULL) { + self->hashcode = PyObject_Hash(temp); + Py_DECREF(temp); + } + } + return self->hashcode; +} + +static PyObject * +date_toordinal(PyDateTime_Date *self) +{ + return PyInt_FromLong(ymd_to_ord(GET_YEAR(self), GET_MONTH(self), + GET_DAY(self))); +} + +static PyObject * +date_weekday(PyDateTime_Date *self) +{ + int dow = weekday(GET_YEAR(self), GET_MONTH(self), GET_DAY(self)); + + return PyInt_FromLong(dow); +} + +/* Pickle support, a simple use of __reduce__. */ + +/* __getstate__ isn't exposed */ +static PyObject * +date_getstate(PyDateTime_Date *self) +{ + return Py_BuildValue( + "(N)", + PyString_FromStringAndSize((char *)self->data, + _PyDateTime_DATE_DATASIZE)); +} + +static PyObject * +date_reduce(PyDateTime_Date *self, PyObject *arg) +{ + return Py_BuildValue("(ON)", self->ob_type, date_getstate(self)); +} + +static PyMethodDef date_methods[] = { + + /* Class methods: */ + + {"fromtimestamp", (PyCFunction)date_fromtimestamp, METH_VARARGS | + METH_CLASS, + PyDoc_STR("timestamp -> local date from a POSIX timestamp (like " + "time.time()).")}, + + {"fromordinal", (PyCFunction)date_fromordinal, METH_VARARGS | + METH_CLASS, + PyDoc_STR("int -> date corresponding to a proleptic Gregorian " + "ordinal.")}, + + {"today", (PyCFunction)date_today, METH_NOARGS | METH_CLASS, + PyDoc_STR("Current date or datetime: same as " + "self.__class__.fromtimestamp(time.time()).")}, + + /* Instance methods: */ + + {"ctime", (PyCFunction)date_ctime, METH_NOARGS, + PyDoc_STR("Return ctime() style string.")}, + + {"strftime", (PyCFunction)date_strftime, METH_KEYWORDS, + PyDoc_STR("format -> strftime() style string.")}, + + {"timetuple", (PyCFunction)date_timetuple, METH_NOARGS, + PyDoc_STR("Return time tuple, compatible with time.localtime().")}, + + {"isocalendar", (PyCFunction)date_isocalendar, METH_NOARGS, + PyDoc_STR("Return a 3-tuple containing ISO year, week number, and " + "weekday.")}, + + {"isoformat", (PyCFunction)date_isoformat, METH_NOARGS, + PyDoc_STR("Return string in ISO 8601 format, YYYY-MM-DD.")}, + + {"isoweekday", (PyCFunction)date_isoweekday, METH_NOARGS, + PyDoc_STR("Return the day of the week represented by the date.\n" + "Monday == 1 ... Sunday == 7")}, + + {"toordinal", (PyCFunction)date_toordinal, METH_NOARGS, + PyDoc_STR("Return proleptic Gregorian ordinal. January 1 of year " + "1 is day 1.")}, + + {"weekday", (PyCFunction)date_weekday, METH_NOARGS, + PyDoc_STR("Return the day of the week represented by the date.\n" + "Monday == 0 ... Sunday == 6")}, + + {"replace", (PyCFunction)date_replace, METH_KEYWORDS, + PyDoc_STR("Return date with new specified fields.")}, + + {"__reduce__", (PyCFunction)date_reduce, METH_NOARGS, + PyDoc_STR("__reduce__() -> (cls, state)")}, + + {NULL, NULL} +}; + +static char date_doc[] = +PyDoc_STR("date(year, month, day) --> date object"); + +static PyNumberMethods date_as_number = { + date_add, /* nb_add */ + date_subtract, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + 0, /* nb_nonzero */ +}; + +static PyTypeObject PyDateTime_DateType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "datetime.date", /* tp_name */ + sizeof(PyDateTime_Date), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)date_repr, /* tp_repr */ + &date_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)date_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)date_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + date_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)date_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + date_methods, /* tp_methods */ + 0, /* tp_members */ + date_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + date_new, /* tp_new */ + 0, /* tp_free */ +}; + +/* + * PyDateTime_TZInfo implementation. + */ + +/* This is a pure abstract base class, so doesn't do anything beyond + * raising NotImplemented exceptions. Real tzinfo classes need + * to derive from this. This is mostly for clarity, and for efficiency in + * datetime and time constructors (their tzinfo arguments need to + * be subclasses of this tzinfo class, which is easy and quick to check). + * + * Note: For reasons having to do with pickling of subclasses, we have + * to allow tzinfo objects to be instantiated. This wasn't an issue + * in the Python implementation (__init__() could raise NotImplementedError + * there without ill effect), but doing so in the C implementation hit a + * brick wall. + */ + +static PyObject * +tzinfo_nogo(const char* methodname) +{ + PyErr_Format(PyExc_NotImplementedError, + "a tzinfo subclass must implement %s()", + methodname); + return NULL; +} + +/* Methods. A subclass must implement these. */ + +static PyObject * +tzinfo_tzname(PyDateTime_TZInfo *self, PyObject *dt) +{ + return tzinfo_nogo("tzname"); +} + +static PyObject * +tzinfo_utcoffset(PyDateTime_TZInfo *self, PyObject *dt) +{ + return tzinfo_nogo("utcoffset"); +} + +static PyObject * +tzinfo_dst(PyDateTime_TZInfo *self, PyObject *dt) +{ + return tzinfo_nogo("dst"); +} + +static PyObject * +tzinfo_fromutc(PyDateTime_TZInfo *self, PyDateTime_DateTime *dt) +{ + int y, m, d, hh, mm, ss, us; + + PyObject *result; + int off, dst; + int none; + int delta; + + if (! PyDateTime_Check(dt)) { + PyErr_SetString(PyExc_TypeError, + "fromutc: argument must be a datetime"); + return NULL; + } + if (! HASTZINFO(dt) || dt->tzinfo != (PyObject *)self) { + PyErr_SetString(PyExc_ValueError, "fromutc: dt.tzinfo " + "is not self"); + return NULL; + } + + off = call_utcoffset(dt->tzinfo, (PyObject *)dt, &none); + if (off == -1 && PyErr_Occurred()) + return NULL; + if (none) { + PyErr_SetString(PyExc_ValueError, "fromutc: non-None " + "utcoffset() result required"); + return NULL; + } + + dst = call_dst(dt->tzinfo, (PyObject *)dt, &none); + if (dst == -1 && PyErr_Occurred()) + return NULL; + if (none) { + PyErr_SetString(PyExc_ValueError, "fromutc: non-None " + "dst() result required"); + return NULL; + } + + y = GET_YEAR(dt); + m = GET_MONTH(dt); + d = GET_DAY(dt); + hh = DATE_GET_HOUR(dt); + mm = DATE_GET_MINUTE(dt); + ss = DATE_GET_SECOND(dt); + us = DATE_GET_MICROSECOND(dt); + + delta = off - dst; + mm += delta; + if ((mm < 0 || mm >= 60) && + normalize_datetime(&y, &m, &d, &hh, &mm, &ss, &us) < 0) + return NULL; + result = new_datetime(y, m, d, hh, mm, ss, us, dt->tzinfo); + if (result == NULL) + return result; + + dst = call_dst(dt->tzinfo, result, &none); + if (dst == -1 && PyErr_Occurred()) + goto Fail; + if (none) + goto Inconsistent; + if (dst == 0) + return result; + + mm += dst; + if ((mm < 0 || mm >= 60) && + normalize_datetime(&y, &m, &d, &hh, &mm, &ss, &us) < 0) + goto Fail; + Py_DECREF(result); + result = new_datetime(y, m, d, hh, mm, ss, us, dt->tzinfo); + return result; + +Inconsistent: + PyErr_SetString(PyExc_ValueError, "fromutc: tz.dst() gave" + "inconsistent results; cannot convert"); + + /* fall thru to failure */ +Fail: + Py_DECREF(result); + return NULL; +} + +/* + * Pickle support. This is solely so that tzinfo subclasses can use + * pickling -- tzinfo itself is supposed to be uninstantiable. + */ + +static PyObject * +tzinfo_reduce(PyObject *self) +{ + PyObject *args, *state, *tmp; + PyObject *getinitargs, *getstate; + + tmp = PyTuple_New(0); + if (tmp == NULL) + return NULL; + + getinitargs = PyObject_GetAttrString(self, "__getinitargs__"); + if (getinitargs != NULL) { + args = PyObject_CallObject(getinitargs, tmp); + Py_DECREF(getinitargs); + if (args == NULL) { + Py_DECREF(tmp); + return NULL; + } + } + else { + PyErr_Clear(); + args = tmp; + Py_INCREF(args); + } + + getstate = PyObject_GetAttrString(self, "__getstate__"); + if (getstate != NULL) { + state = PyObject_CallObject(getstate, tmp); + Py_DECREF(getstate); + if (state == NULL) { + Py_DECREF(args); + Py_DECREF(tmp); + return NULL; + } + } + else { + PyObject **dictptr; + PyErr_Clear(); + state = Py_None; + dictptr = _PyObject_GetDictPtr(self); + if (dictptr && *dictptr && PyDict_Size(*dictptr)) + state = *dictptr; + Py_INCREF(state); + } + + Py_DECREF(tmp); + + if (state == Py_None) { + Py_DECREF(state); + return Py_BuildValue("(ON)", self->ob_type, args); + } + else + return Py_BuildValue("(ONN)", self->ob_type, args, state); +} + +static PyMethodDef tzinfo_methods[] = { + + {"tzname", (PyCFunction)tzinfo_tzname, METH_O, + PyDoc_STR("datetime -> string name of time zone.")}, + + {"utcoffset", (PyCFunction)tzinfo_utcoffset, METH_O, + PyDoc_STR("datetime -> minutes east of UTC (negative for " + "west of UTC).")}, + + {"dst", (PyCFunction)tzinfo_dst, METH_O, + PyDoc_STR("datetime -> DST offset in minutes east of UTC.")}, + + {"fromutc", (PyCFunction)tzinfo_fromutc, METH_O, + PyDoc_STR("datetime in UTC -> datetime in local time.")}, + + {"__reduce__", (PyCFunction)tzinfo_reduce, METH_NOARGS, + PyDoc_STR("-> (cls, state)")}, + + {NULL, NULL} +}; + +static char tzinfo_doc[] = +PyDoc_STR("Abstract base class for time zone info objects."); + +statichere PyTypeObject PyDateTime_TZInfoType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "datetime.tzinfo", /* tp_name */ + sizeof(PyDateTime_TZInfo), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + tzinfo_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + tzinfo_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + 0, /* tp_free */ +}; + +/* + * PyDateTime_Time implementation. + */ + +/* Accessor properties. + */ + +static PyObject * +time_hour(PyDateTime_Time *self, void *unused) +{ + return PyInt_FromLong(TIME_GET_HOUR(self)); +} + +static PyObject * +time_minute(PyDateTime_Time *self, void *unused) +{ + return PyInt_FromLong(TIME_GET_MINUTE(self)); +} + +/* The name time_second conflicted with some platform header file. */ +static PyObject * +py_time_second(PyDateTime_Time *self, void *unused) +{ + return PyInt_FromLong(TIME_GET_SECOND(self)); +} + +static PyObject * +time_microsecond(PyDateTime_Time *self, void *unused) +{ + return PyInt_FromLong(TIME_GET_MICROSECOND(self)); +} + +static PyObject * +time_tzinfo(PyDateTime_Time *self, void *unused) +{ + PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None; + Py_INCREF(result); + return result; +} + +static PyGetSetDef time_getset[] = { + {"hour", (getter)time_hour}, + {"minute", (getter)time_minute}, + {"second", (getter)py_time_second}, + {"microsecond", (getter)time_microsecond}, + {"tzinfo", (getter)time_tzinfo}, + {NULL} +}; + +/* + * Constructors. + */ + +static char *time_kws[] = {"hour", "minute", "second", "microsecond", + "tzinfo", NULL}; + +static PyObject * +time_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *self = NULL; + PyObject *state; + int hour = 0; + int minute = 0; + int second = 0; + int usecond = 0; + PyObject *tzinfo = Py_None; + + /* Check for invocation from pickle with __getstate__ state */ + if (PyTuple_GET_SIZE(args) >= 1 && + PyTuple_GET_SIZE(args) <= 2 && + PyString_Check(state = PyTuple_GET_ITEM(args, 0)) && + PyString_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE && + ((unsigned char) (PyString_AS_STRING(state)[0])) < 24) + { + PyDateTime_Time *me; + char aware; + + if (PyTuple_GET_SIZE(args) == 2) { + tzinfo = PyTuple_GET_ITEM(args, 1); + if (check_tzinfo_subclass(tzinfo) < 0) { + PyErr_SetString(PyExc_TypeError, "bad " + "tzinfo state arg"); + return NULL; + } + } + aware = (char)(tzinfo != Py_None); + me = (PyDateTime_Time *) (type->tp_alloc(type, aware)); + if (me != NULL) { + char *pdata = PyString_AS_STRING(state); + + memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE); + me->hashcode = -1; + me->hastzinfo = aware; + if (aware) { + Py_INCREF(tzinfo); + me->tzinfo = tzinfo; + } + } + return (PyObject *)me; + } + + if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO", time_kws, + &hour, &minute, &second, &usecond, + &tzinfo)) { + if (check_time_args(hour, minute, second, usecond) < 0) + return NULL; + if (check_tzinfo_subclass(tzinfo) < 0) + return NULL; + self = new_time_ex(hour, minute, second, usecond, tzinfo, + type); + } + return self; +} + +/* + * Destructor. + */ + +static void +time_dealloc(PyDateTime_Time *self) +{ + if (HASTZINFO(self)) { + Py_XDECREF(self->tzinfo); + } + self->ob_type->tp_free((PyObject *)self); +} + +/* + * Indirect access to tzinfo methods. + */ + +/* These are all METH_NOARGS, so don't need to check the arglist. */ +static PyObject * +time_utcoffset(PyDateTime_Time *self, PyObject *unused) { + return offset_as_timedelta(HASTZINFO(self) ? self->tzinfo : Py_None, + "utcoffset", Py_None); +} + +static PyObject * +time_dst(PyDateTime_Time *self, PyObject *unused) { + return offset_as_timedelta(HASTZINFO(self) ? self->tzinfo : Py_None, + "dst", Py_None); +} + +static PyObject * +time_tzname(PyDateTime_Time *self, PyObject *unused) { + return call_tzname(HASTZINFO(self) ? self->tzinfo : Py_None, + Py_None); +} + +/* + * Various ways to turn a time into a string. + */ + +static PyObject * +time_repr(PyDateTime_Time *self) +{ + char buffer[100]; + const char *type_name = self->ob_type->tp_name; + int h = TIME_GET_HOUR(self); + int m = TIME_GET_MINUTE(self); + int s = TIME_GET_SECOND(self); + int us = TIME_GET_MICROSECOND(self); + PyObject *result = NULL; + + if (us) + PyOS_snprintf(buffer, sizeof(buffer), + "%s(%d, %d, %d, %d)", type_name, h, m, s, us); + else if (s) + PyOS_snprintf(buffer, sizeof(buffer), + "%s(%d, %d, %d)", type_name, h, m, s); + else + PyOS_snprintf(buffer, sizeof(buffer), + "%s(%d, %d)", type_name, h, m); + result = PyString_FromString(buffer); + if (result != NULL && HASTZINFO(self)) + result = append_keyword_tzinfo(result, self->tzinfo); + return result; +} + +static PyObject * +time_str(PyDateTime_Time *self) +{ + return PyObject_CallMethod((PyObject *)self, "isoformat", "()"); +} + +/* Even though this silently ignores all arguments, it cannot + be fixed to reject them in release25-maint */ +static PyObject * +time_isoformat(PyDateTime_Time *self, PyObject *unused_args, + PyObject *unused_keywords) +{ + char buf[100]; + PyObject *result; + /* Reuse the time format code from the datetime type. */ + PyDateTime_DateTime datetime; + PyDateTime_DateTime *pdatetime = &datetime; + + /* Copy over just the time bytes. */ + memcpy(pdatetime->data + _PyDateTime_DATE_DATASIZE, + self->data, + _PyDateTime_TIME_DATASIZE); + + isoformat_time(pdatetime, buf, sizeof(buf)); + result = PyString_FromString(buf); + if (result == NULL || ! HASTZINFO(self) || self->tzinfo == Py_None) + return result; + + /* We need to append the UTC offset. */ + if (format_utcoffset(buf, sizeof(buf), ":", self->tzinfo, + Py_None) < 0) { + Py_DECREF(result); + return NULL; + } + PyString_ConcatAndDel(&result, PyString_FromString(buf)); + return result; +} + +static PyObject * +time_strftime(PyDateTime_Time *self, PyObject *args, PyObject *kw) +{ + PyObject *result; + PyObject *format; + PyObject *tuple; + static char *keywords[] = {"format", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kw, "O!:strftime", keywords, + &PyString_Type, &format)) + return NULL; + + /* Python's strftime does insane things with the year part of the + * timetuple. The year is forced to (the otherwise nonsensical) + * 1900 to worm around that. + */ + tuple = Py_BuildValue("iiiiiiiii", + 1900, 1, 1, /* year, month, day */ + TIME_GET_HOUR(self), + TIME_GET_MINUTE(self), + TIME_GET_SECOND(self), + 0, 1, -1); /* weekday, daynum, dst */ + if (tuple == NULL) + return NULL; + assert(PyTuple_Size(tuple) == 9); + result = wrap_strftime((PyObject *)self, format, tuple, Py_None); + Py_DECREF(tuple); + return result; +} + +/* + * Miscellaneous methods. + */ + +/* This is more natural as a tp_compare, but doesn't work then: for whatever + * reason, Python's try_3way_compare ignores tp_compare unless + * PyInstance_Check returns true, but these aren't old-style classes. + */ +static PyObject * +time_richcompare(PyDateTime_Time *self, PyObject *other, int op) +{ + int diff; + naivety n1, n2; + int offset1, offset2; + + if (! PyTime_Check(other)) { + if (op == Py_EQ || op == Py_NE) { + PyObject *result = op == Py_EQ ? Py_False : Py_True; + Py_INCREF(result); + return result; + } + /* Stop this from falling back to address comparison. */ + return cmperror((PyObject *)self, other); + } + if (classify_two_utcoffsets((PyObject *)self, &offset1, &n1, Py_None, + other, &offset2, &n2, Py_None) < 0) + return NULL; + assert(n1 != OFFSET_UNKNOWN && n2 != OFFSET_UNKNOWN); + /* If they're both naive, or both aware and have the same offsets, + * we get off cheap. Note that if they're both naive, offset1 == + * offset2 == 0 at this point. + */ + if (n1 == n2 && offset1 == offset2) { + diff = memcmp(self->data, ((PyDateTime_Time *)other)->data, + _PyDateTime_TIME_DATASIZE); + return diff_to_bool(diff, op); + } + + if (n1 == OFFSET_AWARE && n2 == OFFSET_AWARE) { + assert(offset1 != offset2); /* else last "if" handled it */ + /* Convert everything except microseconds to seconds. These + * can't overflow (no more than the # of seconds in 2 days). + */ + offset1 = TIME_GET_HOUR(self) * 3600 + + (TIME_GET_MINUTE(self) - offset1) * 60 + + TIME_GET_SECOND(self); + offset2 = TIME_GET_HOUR(other) * 3600 + + (TIME_GET_MINUTE(other) - offset2) * 60 + + TIME_GET_SECOND(other); + diff = offset1 - offset2; + if (diff == 0) + diff = TIME_GET_MICROSECOND(self) - + TIME_GET_MICROSECOND(other); + return diff_to_bool(diff, op); + } + + assert(n1 != n2); + PyErr_SetString(PyExc_TypeError, + "can't compare offset-naive and " + "offset-aware times"); + return NULL; +} + +static long +time_hash(PyDateTime_Time *self) +{ + if (self->hashcode == -1) { + naivety n; + int offset; + PyObject *temp; + + n = classify_utcoffset((PyObject *)self, Py_None, &offset); + assert(n != OFFSET_UNKNOWN); + if (n == OFFSET_ERROR) + return -1; + + /* Reduce this to a hash of another object. */ + if (offset == 0) + temp = PyString_FromStringAndSize((char *)self->data, + _PyDateTime_TIME_DATASIZE); + else { + int hour; + int minute; + + assert(n == OFFSET_AWARE); + assert(HASTZINFO(self)); + hour = divmod(TIME_GET_HOUR(self) * 60 + + TIME_GET_MINUTE(self) - offset, + 60, + &minute); + if (0 <= hour && hour < 24) + temp = new_time(hour, minute, + TIME_GET_SECOND(self), + TIME_GET_MICROSECOND(self), + Py_None); + else + temp = Py_BuildValue("iiii", + hour, minute, + TIME_GET_SECOND(self), + TIME_GET_MICROSECOND(self)); + } + if (temp != NULL) { + self->hashcode = PyObject_Hash(temp); + Py_DECREF(temp); + } + } + return self->hashcode; +} + +static PyObject * +time_replace(PyDateTime_Time *self, PyObject *args, PyObject *kw) +{ + PyObject *clone; + PyObject *tuple; + int hh = TIME_GET_HOUR(self); + int mm = TIME_GET_MINUTE(self); + int ss = TIME_GET_SECOND(self); + int us = TIME_GET_MICROSECOND(self); + PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; + + if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO:replace", + time_kws, + &hh, &mm, &ss, &us, &tzinfo)) + return NULL; + tuple = Py_BuildValue("iiiiO", hh, mm, ss, us, tzinfo); + if (tuple == NULL) + return NULL; + clone = time_new(self->ob_type, tuple, NULL); + Py_DECREF(tuple); + return clone; +} + +static int +time_nonzero(PyDateTime_Time *self) +{ + int offset; + int none; + + if (TIME_GET_SECOND(self) || TIME_GET_MICROSECOND(self)) { + /* Since utcoffset is in whole minutes, nothing can + * alter the conclusion that this is nonzero. + */ + return 1; + } + offset = 0; + if (HASTZINFO(self) && self->tzinfo != Py_None) { + offset = call_utcoffset(self->tzinfo, Py_None, &none); + if (offset == -1 && PyErr_Occurred()) + return -1; + } + return (TIME_GET_MINUTE(self) - offset + TIME_GET_HOUR(self)*60) != 0; +} + +/* Pickle support, a simple use of __reduce__. */ + +/* Let basestate be the non-tzinfo data string. + * If tzinfo is None, this returns (basestate,), else (basestate, tzinfo). + * So it's a tuple in any (non-error) case. + * __getstate__ isn't exposed. + */ +static PyObject * +time_getstate(PyDateTime_Time *self) +{ + PyObject *basestate; + PyObject *result = NULL; + + basestate = PyString_FromStringAndSize((char *)self->data, + _PyDateTime_TIME_DATASIZE); + if (basestate != NULL) { + if (! HASTZINFO(self) || self->tzinfo == Py_None) + result = PyTuple_Pack(1, basestate); + else + result = PyTuple_Pack(2, basestate, self->tzinfo); + Py_DECREF(basestate); + } + return result; +} + +static PyObject * +time_reduce(PyDateTime_Time *self, PyObject *arg) +{ + return Py_BuildValue("(ON)", self->ob_type, time_getstate(self)); +} + +static PyMethodDef time_methods[] = { + + {"isoformat", (PyCFunction)time_isoformat, METH_KEYWORDS, + PyDoc_STR("Return string in ISO 8601 format, HH:MM:SS[.mmmmmm]" + "[+HH:MM].")}, + + {"strftime", (PyCFunction)time_strftime, METH_KEYWORDS, + PyDoc_STR("format -> strftime() style string.")}, + + {"utcoffset", (PyCFunction)time_utcoffset, METH_NOARGS, + PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, + + {"tzname", (PyCFunction)time_tzname, METH_NOARGS, + PyDoc_STR("Return self.tzinfo.tzname(self).")}, + + {"dst", (PyCFunction)time_dst, METH_NOARGS, + PyDoc_STR("Return self.tzinfo.dst(self).")}, + + {"replace", (PyCFunction)time_replace, METH_KEYWORDS, + PyDoc_STR("Return time with new specified fields.")}, + + {"__reduce__", (PyCFunction)time_reduce, METH_NOARGS, + PyDoc_STR("__reduce__() -> (cls, state)")}, + + {NULL, NULL} +}; + +static char time_doc[] = +PyDoc_STR("time([hour[, minute[, second[, microsecond[, tzinfo]]]]]) --> a time object\n\ +\n\ +All arguments are optional. tzinfo may be None, or an instance of\n\ +a tzinfo subclass. The remaining arguments may be ints or longs.\n"); + +static PyNumberMethods time_as_number = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + (inquiry)time_nonzero, /* nb_nonzero */ +}; + +statichere PyTypeObject PyDateTime_TimeType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "datetime.time", /* tp_name */ + sizeof(PyDateTime_Time), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)time_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)time_repr, /* tp_repr */ + &time_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)time_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)time_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + time_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)time_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + time_methods, /* tp_methods */ + 0, /* tp_members */ + time_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + time_alloc, /* tp_alloc */ + time_new, /* tp_new */ + 0, /* tp_free */ +}; + +/* + * PyDateTime_DateTime implementation. + */ + +/* Accessor properties. Properties for day, month, and year are inherited + * from date. + */ + +static PyObject * +datetime_hour(PyDateTime_DateTime *self, void *unused) +{ + return PyInt_FromLong(DATE_GET_HOUR(self)); +} + +static PyObject * +datetime_minute(PyDateTime_DateTime *self, void *unused) +{ + return PyInt_FromLong(DATE_GET_MINUTE(self)); +} + +static PyObject * +datetime_second(PyDateTime_DateTime *self, void *unused) +{ + return PyInt_FromLong(DATE_GET_SECOND(self)); +} + +static PyObject * +datetime_microsecond(PyDateTime_DateTime *self, void *unused) +{ + return PyInt_FromLong(DATE_GET_MICROSECOND(self)); +} + +static PyObject * +datetime_tzinfo(PyDateTime_DateTime *self, void *unused) +{ + PyObject *result = HASTZINFO(self) ? self->tzinfo : Py_None; + Py_INCREF(result); + return result; +} + +static PyGetSetDef datetime_getset[] = { + {"hour", (getter)datetime_hour}, + {"minute", (getter)datetime_minute}, + {"second", (getter)datetime_second}, + {"microsecond", (getter)datetime_microsecond}, + {"tzinfo", (getter)datetime_tzinfo}, + {NULL} +}; + +/* + * Constructors. + */ + +static char *datetime_kws[] = { + "year", "month", "day", "hour", "minute", "second", + "microsecond", "tzinfo", NULL +}; + +static PyObject * +datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *self = NULL; + PyObject *state; + int year; + int month; + int day; + int hour = 0; + int minute = 0; + int second = 0; + int usecond = 0; + PyObject *tzinfo = Py_None; + + /* Check for invocation from pickle with __getstate__ state */ + if (PyTuple_GET_SIZE(args) >= 1 && + PyTuple_GET_SIZE(args) <= 2 && + PyString_Check(state = PyTuple_GET_ITEM(args, 0)) && + PyString_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE && + MONTH_IS_SANE(PyString_AS_STRING(state)[2])) + { + PyDateTime_DateTime *me; + char aware; + + if (PyTuple_GET_SIZE(args) == 2) { + tzinfo = PyTuple_GET_ITEM(args, 1); + if (check_tzinfo_subclass(tzinfo) < 0) { + PyErr_SetString(PyExc_TypeError, "bad " + "tzinfo state arg"); + return NULL; + } + } + aware = (char)(tzinfo != Py_None); + me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware)); + if (me != NULL) { + char *pdata = PyString_AS_STRING(state); + + memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE); + me->hashcode = -1; + me->hastzinfo = aware; + if (aware) { + Py_INCREF(tzinfo); + me->tzinfo = tzinfo; + } + } + return (PyObject *)me; + } + + if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO", datetime_kws, + &year, &month, &day, &hour, &minute, + &second, &usecond, &tzinfo)) { + if (check_date_args(year, month, day) < 0) + return NULL; + if (check_time_args(hour, minute, second, usecond) < 0) + return NULL; + if (check_tzinfo_subclass(tzinfo) < 0) + return NULL; + self = new_datetime_ex(year, month, day, + hour, minute, second, usecond, + tzinfo, type); + } + return self; +} + +/* TM_FUNC is the shared type of localtime() and gmtime(). */ +typedef struct tm *(*TM_FUNC)(const time_t *timer); + +/* Internal helper. + * Build datetime from a time_t and a distinct count of microseconds. + * Pass localtime or gmtime for f, to control the interpretation of timet. + */ +static PyObject * +datetime_from_timet_and_us(PyObject *cls, TM_FUNC f, time_t timet, int us, + PyObject *tzinfo) +{ + struct tm *tm; + PyObject *result = NULL; + + tm = f(&timet); + if (tm) { + /* The platform localtime/gmtime may insert leap seconds, + * indicated by tm->tm_sec > 59. We don't care about them, + * except to the extent that passing them on to the datetime + * constructor would raise ValueError for a reason that + * made no sense to the user. + */ + if (tm->tm_sec > 59) + tm->tm_sec = 59; + result = PyObject_CallFunction(cls, "iiiiiiiO", + tm->tm_year + 1900, + tm->tm_mon + 1, + tm->tm_mday, + tm->tm_hour, + tm->tm_min, + tm->tm_sec, + us, + tzinfo); + } + else + PyErr_SetString(PyExc_ValueError, + "timestamp out of range for " + "platform localtime()/gmtime() function"); + return result; +} + +/* Internal helper. + * Build datetime from a Python timestamp. Pass localtime or gmtime for f, + * to control the interpretation of the timestamp. Since a double doesn't + * have enough bits to cover a datetime's full range of precision, it's + * better to call datetime_from_timet_and_us provided you have a way + * to get that much precision (e.g., C time() isn't good enough). + */ +static PyObject * +datetime_from_timestamp(PyObject *cls, TM_FUNC f, double timestamp, + PyObject *tzinfo) +{ + time_t timet; + double fraction; + int us; + + timet = _PyTime_DoubleToTimet(timestamp); + if (timet == (time_t)-1 && PyErr_Occurred()) + return NULL; + fraction = timestamp - (double)timet; + us = (int)round_to_long(fraction * 1e6); + if (us < 0) { + /* Truncation towards zero is not what we wanted + for negative numbers (Python's mod semantics) */ + timet -= 1; + us += 1000000; + } + /* If timestamp is less than one microsecond smaller than a + * full second, round up. Otherwise, ValueErrors are raised + * for some floats. */ + if (us == 1000000) { + timet += 1; + us = 0; + } + return datetime_from_timet_and_us(cls, f, timet, us, tzinfo); +} + +/* Internal helper. + * Build most accurate possible datetime for current time. Pass localtime or + * gmtime for f as appropriate. + */ +static PyObject * +datetime_best_possible(PyObject *cls, TM_FUNC f, PyObject *tzinfo) +{ +#ifdef HAVE_GETTIMEOFDAY + struct timeval t; + +#ifdef GETTIMEOFDAY_NO_TZ + gettimeofday(&t); +#else + gettimeofday(&t, (struct timezone *)NULL); +#endif + return datetime_from_timet_and_us(cls, f, t.tv_sec, (int)t.tv_usec, + tzinfo); + +#else /* ! HAVE_GETTIMEOFDAY */ + /* No flavor of gettimeofday exists on this platform. Python's + * time.time() does a lot of other platform tricks to get the + * best time it can on the platform, and we're not going to do + * better than that (if we could, the better code would belong + * in time.time()!) We're limited by the precision of a double, + * though. + */ + PyObject *time; + double dtime; + + time = time_time(); + if (time == NULL) + return NULL; + dtime = PyFloat_AsDouble(time); + Py_DECREF(time); + if (dtime == -1.0 && PyErr_Occurred()) + return NULL; + return datetime_from_timestamp(cls, f, dtime, tzinfo); +#endif /* ! HAVE_GETTIMEOFDAY */ +} + +/* Return best possible local time -- this isn't constrained by the + * precision of a timestamp. + */ +static PyObject * +datetime_now(PyObject *cls, PyObject *args, PyObject *kw) +{ + PyObject *self; + PyObject *tzinfo = Py_None; + static char *keywords[] = {"tz", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kw, "|O:now", keywords, + &tzinfo)) + return NULL; + if (check_tzinfo_subclass(tzinfo) < 0) + return NULL; + + self = datetime_best_possible(cls, + tzinfo == Py_None ? localtime : gmtime, + tzinfo); + if (self != NULL && tzinfo != Py_None) { + /* Convert UTC to tzinfo's zone. */ + PyObject *temp = self; + self = PyObject_CallMethod(tzinfo, "fromutc", "O", self); + Py_DECREF(temp); + } + return self; +} + +/* Return best possible UTC time -- this isn't constrained by the + * precision of a timestamp. + */ +static PyObject * +datetime_utcnow(PyObject *cls, PyObject *dummy) +{ + return datetime_best_possible(cls, gmtime, Py_None); +} + +/* Return new local datetime from timestamp (Python timestamp -- a double). */ +static PyObject * +datetime_fromtimestamp(PyObject *cls, PyObject *args, PyObject *kw) +{ + PyObject *self; + double timestamp; + PyObject *tzinfo = Py_None; + static char *keywords[] = {"timestamp", "tz", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kw, "d|O:fromtimestamp", + keywords, &timestamp, &tzinfo)) + return NULL; + if (check_tzinfo_subclass(tzinfo) < 0) + return NULL; + + self = datetime_from_timestamp(cls, + tzinfo == Py_None ? localtime : gmtime, + timestamp, + tzinfo); + if (self != NULL && tzinfo != Py_None) { + /* Convert UTC to tzinfo's zone. */ + PyObject *temp = self; + self = PyObject_CallMethod(tzinfo, "fromutc", "O", self); + Py_DECREF(temp); + } + return self; +} + +/* Return new UTC datetime from timestamp (Python timestamp -- a double). */ +static PyObject * +datetime_utcfromtimestamp(PyObject *cls, PyObject *args) +{ + double timestamp; + PyObject *result = NULL; + + if (PyArg_ParseTuple(args, "d:utcfromtimestamp", &timestamp)) + result = datetime_from_timestamp(cls, gmtime, timestamp, + Py_None); + return result; +} + +/* Return new datetime from time.strptime(). */ +static PyObject * +datetime_strptime(PyObject *cls, PyObject *args) +{ + PyObject *result = NULL, *obj, *module; + const char *string, *format; + + if (!PyArg_ParseTuple(args, "ss:strptime", &string, &format)) + return NULL; + + if ((module = PyImport_ImportModule("time")) == NULL) + return NULL; + obj = PyObject_CallMethod(module, "strptime", "ss", string, format); + Py_DECREF(module); + + if (obj != NULL) { + int i, good_timetuple = 1; + long int ia[6]; + if (PySequence_Check(obj) && PySequence_Size(obj) >= 6) + for (i=0; i < 6; i++) { + PyObject *p = PySequence_GetItem(obj, i); + if (p == NULL) { + Py_DECREF(obj); + return NULL; + } + if (PyInt_Check(p)) + ia[i] = PyInt_AsLong(p); + else + good_timetuple = 0; + Py_DECREF(p); + } + else + good_timetuple = 0; + if (good_timetuple) + result = PyObject_CallFunction(cls, "iiiiii", + ia[0], ia[1], ia[2], ia[3], ia[4], ia[5]); + else + PyErr_SetString(PyExc_ValueError, + "unexpected value from time.strptime"); + Py_DECREF(obj); + } + return result; +} + +/* Return new datetime from date/datetime and time arguments. */ +static PyObject * +datetime_combine(PyObject *cls, PyObject *args, PyObject *kw) +{ + static char *keywords[] = {"date", "time", NULL}; + PyObject *date; + PyObject *time; + PyObject *result = NULL; + + if (PyArg_ParseTupleAndKeywords(args, kw, "O!O!:combine", keywords, + &PyDateTime_DateType, &date, + &PyDateTime_TimeType, &time)) { + PyObject *tzinfo = Py_None; + + if (HASTZINFO(time)) + tzinfo = ((PyDateTime_Time *)time)->tzinfo; + result = PyObject_CallFunction(cls, "iiiiiiiO", + GET_YEAR(date), + GET_MONTH(date), + GET_DAY(date), + TIME_GET_HOUR(time), + TIME_GET_MINUTE(time), + TIME_GET_SECOND(time), + TIME_GET_MICROSECOND(time), + tzinfo); + } + return result; +} + +/* + * Destructor. + */ + +static void +datetime_dealloc(PyDateTime_DateTime *self) +{ + if (HASTZINFO(self)) { + Py_XDECREF(self->tzinfo); + } + self->ob_type->tp_free((PyObject *)self); +} + +/* + * Indirect access to tzinfo methods. + */ + +/* These are all METH_NOARGS, so don't need to check the arglist. */ +static PyObject * +datetime_utcoffset(PyDateTime_DateTime *self, PyObject *unused) { + return offset_as_timedelta(HASTZINFO(self) ? self->tzinfo : Py_None, + "utcoffset", (PyObject *)self); +} + +static PyObject * +datetime_dst(PyDateTime_DateTime *self, PyObject *unused) { + return offset_as_timedelta(HASTZINFO(self) ? self->tzinfo : Py_None, + "dst", (PyObject *)self); +} + +static PyObject * +datetime_tzname(PyDateTime_DateTime *self, PyObject *unused) { + return call_tzname(HASTZINFO(self) ? self->tzinfo : Py_None, + (PyObject *)self); +} + +/* + * datetime arithmetic. + */ + +/* factor must be 1 (to add) or -1 (to subtract). The result inherits + * the tzinfo state of date. + */ +static PyObject * +add_datetime_timedelta(PyDateTime_DateTime *date, PyDateTime_Delta *delta, + int factor) +{ + /* Note that the C-level additions can't overflow, because of + * invariant bounds on the member values. + */ + int year = GET_YEAR(date); + int month = GET_MONTH(date); + int day = GET_DAY(date) + GET_TD_DAYS(delta) * factor; + int hour = DATE_GET_HOUR(date); + int minute = DATE_GET_MINUTE(date); + int second = DATE_GET_SECOND(date) + GET_TD_SECONDS(delta) * factor; + int microsecond = DATE_GET_MICROSECOND(date) + + GET_TD_MICROSECONDS(delta) * factor; + + assert(factor == 1 || factor == -1); + if (normalize_datetime(&year, &month, &day, + &hour, &minute, &second, &microsecond) < 0) + return NULL; + else + return new_datetime(year, month, day, + hour, minute, second, microsecond, + HASTZINFO(date) ? date->tzinfo : Py_None); +} + +static PyObject * +datetime_add(PyObject *left, PyObject *right) +{ + if (PyDateTime_Check(left)) { + /* datetime + ??? */ + if (PyDelta_Check(right)) + /* datetime + delta */ + return add_datetime_timedelta( + (PyDateTime_DateTime *)left, + (PyDateTime_Delta *)right, + 1); + } + else if (PyDelta_Check(left)) { + /* delta + datetime */ + return add_datetime_timedelta((PyDateTime_DateTime *) right, + (PyDateTime_Delta *) left, + 1); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyObject * +datetime_subtract(PyObject *left, PyObject *right) +{ + PyObject *result = Py_NotImplemented; + + if (PyDateTime_Check(left)) { + /* datetime - ??? */ + if (PyDateTime_Check(right)) { + /* datetime - datetime */ + naivety n1, n2; + int offset1, offset2; + int delta_d, delta_s, delta_us; + + if (classify_two_utcoffsets(left, &offset1, &n1, left, + right, &offset2, &n2, + right) < 0) + return NULL; + assert(n1 != OFFSET_UNKNOWN && n2 != OFFSET_UNKNOWN); + if (n1 != n2) { + PyErr_SetString(PyExc_TypeError, + "can't subtract offset-naive and " + "offset-aware datetimes"); + return NULL; + } + delta_d = ymd_to_ord(GET_YEAR(left), + GET_MONTH(left), + GET_DAY(left)) - + ymd_to_ord(GET_YEAR(right), + GET_MONTH(right), + GET_DAY(right)); + /* These can't overflow, since the values are + * normalized. At most this gives the number of + * seconds in one day. + */ + delta_s = (DATE_GET_HOUR(left) - + DATE_GET_HOUR(right)) * 3600 + + (DATE_GET_MINUTE(left) - + DATE_GET_MINUTE(right)) * 60 + + (DATE_GET_SECOND(left) - + DATE_GET_SECOND(right)); + delta_us = DATE_GET_MICROSECOND(left) - + DATE_GET_MICROSECOND(right); + /* (left - offset1) - (right - offset2) = + * (left - right) + (offset2 - offset1) + */ + delta_s += (offset2 - offset1) * 60; + result = new_delta(delta_d, delta_s, delta_us, 1); + } + else if (PyDelta_Check(right)) { + /* datetime - delta */ + result = add_datetime_timedelta( + (PyDateTime_DateTime *)left, + (PyDateTime_Delta *)right, + -1); + } + } + + if (result == Py_NotImplemented) + Py_INCREF(result); + return result; +} + +/* Various ways to turn a datetime into a string. */ + +static PyObject * +datetime_repr(PyDateTime_DateTime *self) +{ + char buffer[1000]; + const char *type_name = self->ob_type->tp_name; + PyObject *baserepr; + + if (DATE_GET_MICROSECOND(self)) { + PyOS_snprintf(buffer, sizeof(buffer), + "%s(%d, %d, %d, %d, %d, %d, %d)", + type_name, + GET_YEAR(self), GET_MONTH(self), GET_DAY(self), + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), + DATE_GET_SECOND(self), + DATE_GET_MICROSECOND(self)); + } + else if (DATE_GET_SECOND(self)) { + PyOS_snprintf(buffer, sizeof(buffer), + "%s(%d, %d, %d, %d, %d, %d)", + type_name, + GET_YEAR(self), GET_MONTH(self), GET_DAY(self), + DATE_GET_HOUR(self), DATE_GET_MINUTE(self), + DATE_GET_SECOND(self)); + } + else { + PyOS_snprintf(buffer, sizeof(buffer), + "%s(%d, %d, %d, %d, %d)", + type_name, + GET_YEAR(self), GET_MONTH(self), GET_DAY(self), + DATE_GET_HOUR(self), DATE_GET_MINUTE(self)); + } + baserepr = PyString_FromString(buffer); + if (baserepr == NULL || ! HASTZINFO(self)) + return baserepr; + return append_keyword_tzinfo(baserepr, self->tzinfo); +} + +static PyObject * +datetime_str(PyDateTime_DateTime *self) +{ + return PyObject_CallMethod((PyObject *)self, "isoformat", "(s)", " "); +} + +static PyObject * +datetime_isoformat(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +{ + char sep = 'T'; + static char *keywords[] = {"sep", NULL}; + char buffer[100]; + char *cp; + PyObject *result; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|c:isoformat", keywords, + &sep)) + return NULL; + cp = isoformat_date((PyDateTime_Date *)self, buffer, sizeof(buffer)); + assert(cp != NULL); + *cp++ = sep; + isoformat_time(self, cp, sizeof(buffer) - (cp - buffer)); + result = PyString_FromString(buffer); + if (result == NULL || ! HASTZINFO(self)) + return result; + + /* We need to append the UTC offset. */ + if (format_utcoffset(buffer, sizeof(buffer), ":", self->tzinfo, + (PyObject *)self) < 0) { + Py_DECREF(result); + return NULL; + } + PyString_ConcatAndDel(&result, PyString_FromString(buffer)); + return result; +} + +static PyObject * +datetime_ctime(PyDateTime_DateTime *self) +{ + return format_ctime((PyDateTime_Date *)self, + DATE_GET_HOUR(self), + DATE_GET_MINUTE(self), + DATE_GET_SECOND(self)); +} + +/* Miscellaneous methods. */ + +/* This is more natural as a tp_compare, but doesn't work then: for whatever + * reason, Python's try_3way_compare ignores tp_compare unless + * PyInstance_Check returns true, but these aren't old-style classes. + */ +static PyObject * +datetime_richcompare(PyDateTime_DateTime *self, PyObject *other, int op) +{ + int diff; + naivety n1, n2; + int offset1, offset2; + + if (! PyDateTime_Check(other)) { + /* If other has a "timetuple" attr, that's an advertised + * hook for other classes to ask to get comparison control. + * However, date instances have a timetuple attr, and we + * don't want to allow that comparison. Because datetime + * is a subclass of date, when mixing date and datetime + * in a comparison, Python gives datetime the first shot + * (it's the more specific subtype). So we can stop that + * combination here reliably. + */ + if (PyObject_HasAttrString(other, "timetuple") && + ! PyDate_Check(other)) { + /* A hook for other kinds of datetime objects. */ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (op == Py_EQ || op == Py_NE) { + PyObject *result = op == Py_EQ ? Py_False : Py_True; + Py_INCREF(result); + return result; + } + /* Stop this from falling back to address comparison. */ + return cmperror((PyObject *)self, other); + } + + if (classify_two_utcoffsets((PyObject *)self, &offset1, &n1, + (PyObject *)self, + other, &offset2, &n2, + other) < 0) + return NULL; + assert(n1 != OFFSET_UNKNOWN && n2 != OFFSET_UNKNOWN); + /* If they're both naive, or both aware and have the same offsets, + * we get off cheap. Note that if they're both naive, offset1 == + * offset2 == 0 at this point. + */ + if (n1 == n2 && offset1 == offset2) { + diff = memcmp(self->data, ((PyDateTime_DateTime *)other)->data, + _PyDateTime_DATETIME_DATASIZE); + return diff_to_bool(diff, op); + } + + if (n1 == OFFSET_AWARE && n2 == OFFSET_AWARE) { + PyDateTime_Delta *delta; + + assert(offset1 != offset2); /* else last "if" handled it */ + delta = (PyDateTime_Delta *)datetime_subtract((PyObject *)self, + other); + if (delta == NULL) + return NULL; + diff = GET_TD_DAYS(delta); + if (diff == 0) + diff = GET_TD_SECONDS(delta) | + GET_TD_MICROSECONDS(delta); + Py_DECREF(delta); + return diff_to_bool(diff, op); + } + + assert(n1 != n2); + PyErr_SetString(PyExc_TypeError, + "can't compare offset-naive and " + "offset-aware datetimes"); + return NULL; +} + +static long +datetime_hash(PyDateTime_DateTime *self) +{ + if (self->hashcode == -1) { + naivety n; + int offset; + PyObject *temp; + + n = classify_utcoffset((PyObject *)self, (PyObject *)self, + &offset); + assert(n != OFFSET_UNKNOWN); + if (n == OFFSET_ERROR) + return -1; + + /* Reduce this to a hash of another object. */ + if (n == OFFSET_NAIVE) + temp = PyString_FromStringAndSize( + (char *)self->data, + _PyDateTime_DATETIME_DATASIZE); + else { + int days; + int seconds; + + assert(n == OFFSET_AWARE); + assert(HASTZINFO(self)); + days = ymd_to_ord(GET_YEAR(self), + GET_MONTH(self), + GET_DAY(self)); + seconds = DATE_GET_HOUR(self) * 3600 + + (DATE_GET_MINUTE(self) - offset) * 60 + + DATE_GET_SECOND(self); + temp = new_delta(days, + seconds, + DATE_GET_MICROSECOND(self), + 1); + } + if (temp != NULL) { + self->hashcode = PyObject_Hash(temp); + Py_DECREF(temp); + } + } + return self->hashcode; +} + +static PyObject * +datetime_replace(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +{ + PyObject *clone; + PyObject *tuple; + int y = GET_YEAR(self); + int m = GET_MONTH(self); + int d = GET_DAY(self); + int hh = DATE_GET_HOUR(self); + int mm = DATE_GET_MINUTE(self); + int ss = DATE_GET_SECOND(self); + int us = DATE_GET_MICROSECOND(self); + PyObject *tzinfo = HASTZINFO(self) ? self->tzinfo : Py_None; + + if (! PyArg_ParseTupleAndKeywords(args, kw, "|iiiiiiiO:replace", + datetime_kws, + &y, &m, &d, &hh, &mm, &ss, &us, + &tzinfo)) + return NULL; + tuple = Py_BuildValue("iiiiiiiO", y, m, d, hh, mm, ss, us, tzinfo); + if (tuple == NULL) + return NULL; + clone = datetime_new(self->ob_type, tuple, NULL); + Py_DECREF(tuple); + return clone; +} + +static PyObject * +datetime_astimezone(PyDateTime_DateTime *self, PyObject *args, PyObject *kw) +{ + int y, m, d, hh, mm, ss, us; + PyObject *result; + int offset, none; + + PyObject *tzinfo; + static char *keywords[] = {"tz", NULL}; + + if (! PyArg_ParseTupleAndKeywords(args, kw, "O!:astimezone", keywords, + &PyDateTime_TZInfoType, &tzinfo)) + return NULL; + + if (!HASTZINFO(self) || self->tzinfo == Py_None) + goto NeedAware; + + /* Conversion to self's own time zone is a NOP. */ + if (self->tzinfo == tzinfo) { + Py_INCREF(self); + return (PyObject *)self; + } + + /* Convert self to UTC. */ + offset = call_utcoffset(self->tzinfo, (PyObject *)self, &none); + if (offset == -1 && PyErr_Occurred()) + return NULL; + if (none) + goto NeedAware; + + y = GET_YEAR(self); + m = GET_MONTH(self); + d = GET_DAY(self); + hh = DATE_GET_HOUR(self); + mm = DATE_GET_MINUTE(self); + ss = DATE_GET_SECOND(self); + us = DATE_GET_MICROSECOND(self); + + mm -= offset; + if ((mm < 0 || mm >= 60) && + normalize_datetime(&y, &m, &d, &hh, &mm, &ss, &us) < 0) + return NULL; + + /* Attach new tzinfo and let fromutc() do the rest. */ + result = new_datetime(y, m, d, hh, mm, ss, us, tzinfo); + if (result != NULL) { + PyObject *temp = result; + + result = PyObject_CallMethod(tzinfo, "fromutc", "O", temp); + Py_DECREF(temp); + } + return result; + +NeedAware: + PyErr_SetString(PyExc_ValueError, "astimezone() cannot be applied to " + "a naive datetime"); + return NULL; +} + +static PyObject * +datetime_timetuple(PyDateTime_DateTime *self) +{ + int dstflag = -1; + + if (HASTZINFO(self) && self->tzinfo != Py_None) { + int none; + + dstflag = call_dst(self->tzinfo, (PyObject *)self, &none); + if (dstflag == -1 && PyErr_Occurred()) + return NULL; + + if (none) + dstflag = -1; + else if (dstflag != 0) + dstflag = 1; + + } + return build_struct_time(GET_YEAR(self), + GET_MONTH(self), + GET_DAY(self), + DATE_GET_HOUR(self), + DATE_GET_MINUTE(self), + DATE_GET_SECOND(self), + dstflag); +} + +static PyObject * +datetime_getdate(PyDateTime_DateTime *self) +{ + return new_date(GET_YEAR(self), + GET_MONTH(self), + GET_DAY(self)); +} + +static PyObject * +datetime_gettime(PyDateTime_DateTime *self) +{ + return new_time(DATE_GET_HOUR(self), + DATE_GET_MINUTE(self), + DATE_GET_SECOND(self), + DATE_GET_MICROSECOND(self), + Py_None); +} + +static PyObject * +datetime_gettimetz(PyDateTime_DateTime *self) +{ + return new_time(DATE_GET_HOUR(self), + DATE_GET_MINUTE(self), + DATE_GET_SECOND(self), + DATE_GET_MICROSECOND(self), + HASTZINFO(self) ? self->tzinfo : Py_None); +} + +static PyObject * +datetime_utctimetuple(PyDateTime_DateTime *self) +{ + int y = GET_YEAR(self); + int m = GET_MONTH(self); + int d = GET_DAY(self); + int hh = DATE_GET_HOUR(self); + int mm = DATE_GET_MINUTE(self); + int ss = DATE_GET_SECOND(self); + int us = 0; /* microseconds are ignored in a timetuple */ + int offset = 0; + + if (HASTZINFO(self) && self->tzinfo != Py_None) { + int none; + + offset = call_utcoffset(self->tzinfo, (PyObject *)self, &none); + if (offset == -1 && PyErr_Occurred()) + return NULL; + } + /* Even if offset is 0, don't call timetuple() -- tm_isdst should be + * 0 in a UTC timetuple regardless of what dst() says. + */ + if (offset) { + /* Subtract offset minutes & normalize. */ + int stat; + + mm -= offset; + stat = normalize_datetime(&y, &m, &d, &hh, &mm, &ss, &us); + if (stat < 0) { + /* At the edges, it's possible we overflowed + * beyond MINYEAR or MAXYEAR. + */ + if (PyErr_ExceptionMatches(PyExc_OverflowError)) + PyErr_Clear(); + else + return NULL; + } + } + return build_struct_time(y, m, d, hh, mm, ss, 0); +} + +/* Pickle support, a simple use of __reduce__. */ + +/* Let basestate be the non-tzinfo data string. + * If tzinfo is None, this returns (basestate,), else (basestate, tzinfo). + * So it's a tuple in any (non-error) case. + * __getstate__ isn't exposed. + */ +static PyObject * +datetime_getstate(PyDateTime_DateTime *self) +{ + PyObject *basestate; + PyObject *result = NULL; + + basestate = PyString_FromStringAndSize((char *)self->data, + _PyDateTime_DATETIME_DATASIZE); + if (basestate != NULL) { + if (! HASTZINFO(self) || self->tzinfo == Py_None) + result = PyTuple_Pack(1, basestate); + else + result = PyTuple_Pack(2, basestate, self->tzinfo); + Py_DECREF(basestate); + } + return result; +} + +static PyObject * +datetime_reduce(PyDateTime_DateTime *self, PyObject *arg) +{ + return Py_BuildValue("(ON)", self->ob_type, datetime_getstate(self)); +} + +static PyMethodDef datetime_methods[] = { + + /* Class methods: */ + + {"now", (PyCFunction)datetime_now, + METH_KEYWORDS | METH_CLASS, + PyDoc_STR("[tz] -> new datetime with tz's local day and time.")}, + + {"utcnow", (PyCFunction)datetime_utcnow, + METH_NOARGS | METH_CLASS, + PyDoc_STR("Return a new datetime representing UTC day and time.")}, + + {"fromtimestamp", (PyCFunction)datetime_fromtimestamp, + METH_KEYWORDS | METH_CLASS, + PyDoc_STR("timestamp[, tz] -> tz's local time from POSIX timestamp.")}, + + {"utcfromtimestamp", (PyCFunction)datetime_utcfromtimestamp, + METH_VARARGS | METH_CLASS, + PyDoc_STR("timestamp -> UTC datetime from a POSIX timestamp " + "(like time.time()).")}, + + {"strptime", (PyCFunction)datetime_strptime, + METH_VARARGS | METH_CLASS, + PyDoc_STR("string, format -> new datetime parsed from a string " + "(like time.strptime()).")}, + + {"combine", (PyCFunction)datetime_combine, + METH_VARARGS | METH_KEYWORDS | METH_CLASS, + PyDoc_STR("date, time -> datetime with same date and time fields")}, + + /* Instance methods: */ + + {"date", (PyCFunction)datetime_getdate, METH_NOARGS, + PyDoc_STR("Return date object with same year, month and day.")}, + + {"time", (PyCFunction)datetime_gettime, METH_NOARGS, + PyDoc_STR("Return time object with same time but with tzinfo=None.")}, + + {"timetz", (PyCFunction)datetime_gettimetz, METH_NOARGS, + PyDoc_STR("Return time object with same time and tzinfo.")}, + + {"ctime", (PyCFunction)datetime_ctime, METH_NOARGS, + PyDoc_STR("Return ctime() style string.")}, + + {"timetuple", (PyCFunction)datetime_timetuple, METH_NOARGS, + PyDoc_STR("Return time tuple, compatible with time.localtime().")}, + + {"utctimetuple", (PyCFunction)datetime_utctimetuple, METH_NOARGS, + PyDoc_STR("Return UTC time tuple, compatible with time.localtime().")}, + + {"isoformat", (PyCFunction)datetime_isoformat, METH_KEYWORDS, + PyDoc_STR("[sep] -> string in ISO 8601 format, " + "YYYY-MM-DDTHH:MM:SS[.mmmmmm][+HH:MM].\n\n" + "sep is used to separate the year from the time, and " + "defaults to 'T'.")}, + + {"utcoffset", (PyCFunction)datetime_utcoffset, METH_NOARGS, + PyDoc_STR("Return self.tzinfo.utcoffset(self).")}, + + {"tzname", (PyCFunction)datetime_tzname, METH_NOARGS, + PyDoc_STR("Return self.tzinfo.tzname(self).")}, + + {"dst", (PyCFunction)datetime_dst, METH_NOARGS, + PyDoc_STR("Return self.tzinfo.dst(self).")}, + + {"replace", (PyCFunction)datetime_replace, METH_KEYWORDS, + PyDoc_STR("Return datetime with new specified fields.")}, + + {"astimezone", (PyCFunction)datetime_astimezone, METH_KEYWORDS, + PyDoc_STR("tz -> convert to local time in new timezone tz\n")}, + + {"__reduce__", (PyCFunction)datetime_reduce, METH_NOARGS, + PyDoc_STR("__reduce__() -> (cls, state)")}, + + {NULL, NULL} +}; + +static char datetime_doc[] = +PyDoc_STR("datetime(year, month, day[, hour[, minute[, second[, microsecond[,tzinfo]]]]])\n\ +\n\ +The year, month and day arguments are required. tzinfo may be None, or an\n\ +instance of a tzinfo subclass. The remaining arguments may be ints or longs.\n"); + +static PyNumberMethods datetime_as_number = { + datetime_add, /* nb_add */ + datetime_subtract, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + 0, /* nb_nonzero */ +}; + +statichere PyTypeObject PyDateTime_DateTimeType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "datetime.datetime", /* tp_name */ + sizeof(PyDateTime_DateTime), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)datetime_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)datetime_repr, /* tp_repr */ + &datetime_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)datetime_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)datetime_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + datetime_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)datetime_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + datetime_methods, /* tp_methods */ + 0, /* tp_members */ + datetime_getset, /* tp_getset */ + &PyDateTime_DateType, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + datetime_alloc, /* tp_alloc */ + datetime_new, /* tp_new */ + 0, /* tp_free */ +}; + +/* --------------------------------------------------------------------------- + * Module methods and initialization. + */ + +static PyMethodDef module_methods[] = { + {NULL, NULL} +}; + +/* C API. Clients get at this via PyDateTime_IMPORT, defined in + * datetime.h. + */ +static PyDateTime_CAPI CAPI = { + &PyDateTime_DateType, + &PyDateTime_DateTimeType, + &PyDateTime_TimeType, + &PyDateTime_DeltaType, + &PyDateTime_TZInfoType, + new_date_ex, + new_datetime_ex, + new_time_ex, + new_delta_ex, + datetime_fromtimestamp, + date_fromtimestamp +}; + + +PyMODINIT_FUNC +initdatetime(void) +{ + PyObject *m; /* a module object */ + PyObject *d; /* its dict */ + PyObject *x; + + m = Py_InitModule3("datetime", module_methods, + "Fast implementation of the datetime type."); + if (m == NULL) + return; + + if (PyType_Ready(&PyDateTime_DateType) < 0) + return; + if (PyType_Ready(&PyDateTime_DateTimeType) < 0) + return; + if (PyType_Ready(&PyDateTime_DeltaType) < 0) + return; + if (PyType_Ready(&PyDateTime_TimeType) < 0) + return; + if (PyType_Ready(&PyDateTime_TZInfoType) < 0) + return; + + /* timedelta values */ + d = PyDateTime_DeltaType.tp_dict; + + x = new_delta(0, 0, 1, 0); + if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0) + return; + Py_DECREF(x); + + x = new_delta(-MAX_DELTA_DAYS, 0, 0, 0); + if (x == NULL || PyDict_SetItemString(d, "min", x) < 0) + return; + Py_DECREF(x); + + x = new_delta(MAX_DELTA_DAYS, 24*3600-1, 1000000-1, 0); + if (x == NULL || PyDict_SetItemString(d, "max", x) < 0) + return; + Py_DECREF(x); + + /* date values */ + d = PyDateTime_DateType.tp_dict; + + x = new_date(1, 1, 1); + if (x == NULL || PyDict_SetItemString(d, "min", x) < 0) + return; + Py_DECREF(x); + + x = new_date(MAXYEAR, 12, 31); + if (x == NULL || PyDict_SetItemString(d, "max", x) < 0) + return; + Py_DECREF(x); + + x = new_delta(1, 0, 0, 0); + if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0) + return; + Py_DECREF(x); + + /* time values */ + d = PyDateTime_TimeType.tp_dict; + + x = new_time(0, 0, 0, 0, Py_None); + if (x == NULL || PyDict_SetItemString(d, "min", x) < 0) + return; + Py_DECREF(x); + + x = new_time(23, 59, 59, 999999, Py_None); + if (x == NULL || PyDict_SetItemString(d, "max", x) < 0) + return; + Py_DECREF(x); + + x = new_delta(0, 0, 1, 0); + if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0) + return; + Py_DECREF(x); + + /* datetime values */ + d = PyDateTime_DateTimeType.tp_dict; + + x = new_datetime(1, 1, 1, 0, 0, 0, 0, Py_None); + if (x == NULL || PyDict_SetItemString(d, "min", x) < 0) + return; + Py_DECREF(x); + + x = new_datetime(MAXYEAR, 12, 31, 23, 59, 59, 999999, Py_None); + if (x == NULL || PyDict_SetItemString(d, "max", x) < 0) + return; + Py_DECREF(x); + + x = new_delta(0, 0, 1, 0); + if (x == NULL || PyDict_SetItemString(d, "resolution", x) < 0) + return; + Py_DECREF(x); + + /* module initialization */ + PyModule_AddIntConstant(m, "MINYEAR", MINYEAR); + PyModule_AddIntConstant(m, "MAXYEAR", MAXYEAR); + + Py_INCREF(&PyDateTime_DateType); + PyModule_AddObject(m, "date", (PyObject *) &PyDateTime_DateType); + + Py_INCREF(&PyDateTime_DateTimeType); + PyModule_AddObject(m, "datetime", + (PyObject *)&PyDateTime_DateTimeType); + + Py_INCREF(&PyDateTime_TimeType); + PyModule_AddObject(m, "time", (PyObject *) &PyDateTime_TimeType); + + Py_INCREF(&PyDateTime_DeltaType); + PyModule_AddObject(m, "timedelta", (PyObject *) &PyDateTime_DeltaType); + + Py_INCREF(&PyDateTime_TZInfoType); + PyModule_AddObject(m, "tzinfo", (PyObject *) &PyDateTime_TZInfoType); + + x = PyCObject_FromVoidPtrAndDesc(&CAPI, (void*) DATETIME_API_MAGIC, + NULL); + if (x == NULL) + return; + PyModule_AddObject(m, "datetime_CAPI", x); + + /* A 4-year cycle has an extra leap day over what we'd get from + * pasting together 4 single years. + */ + assert(DI4Y == 4 * 365 + 1); + assert(DI4Y == days_before_year(4+1)); + + /* Similarly, a 400-year cycle has an extra leap day over what we'd + * get from pasting together 4 100-year cycles. + */ + assert(DI400Y == 4 * DI100Y + 1); + assert(DI400Y == days_before_year(400+1)); + + /* OTOH, a 100-year cycle has one fewer leap day than we'd get from + * pasting together 25 4-year cycles. + */ + assert(DI100Y == 25 * DI4Y - 1); + assert(DI100Y == days_before_year(100+1)); + + us_per_us = PyInt_FromLong(1); + us_per_ms = PyInt_FromLong(1000); + us_per_second = PyInt_FromLong(1000000); + us_per_minute = PyInt_FromLong(60000000); + seconds_per_day = PyInt_FromLong(24 * 3600); + if (us_per_us == NULL || us_per_ms == NULL || us_per_second == NULL || + us_per_minute == NULL || seconds_per_day == NULL) + return; + + /* The rest are too big for 32-bit ints, but even + * us_per_week fits in 40 bits, so doubles should be exact. + */ + us_per_hour = PyLong_FromDouble(3600000000.0); + us_per_day = PyLong_FromDouble(86400000000.0); + us_per_week = PyLong_FromDouble(604800000000.0); + if (us_per_hour == NULL || us_per_day == NULL || us_per_week == NULL) + return; +} + +/* --------------------------------------------------------------------------- +Some time zone algebra. For a datetime x, let + x.n = x stripped of its timezone -- its naive time. + x.o = x.utcoffset(), and assuming that doesn't raise an exception or + return None + x.d = x.dst(), and assuming that doesn't raise an exception or + return None + x.s = x's standard offset, x.o - x.d + +Now some derived rules, where k is a duration (timedelta). + +1. x.o = x.s + x.d + This follows from the definition of x.s. + +2. If x and y have the same tzinfo member, x.s = y.s. + This is actually a requirement, an assumption we need to make about + sane tzinfo classes. + +3. The naive UTC time corresponding to x is x.n - x.o. + This is again a requirement for a sane tzinfo class. + +4. (x+k).s = x.s + This follows from #2, and that datimetimetz+timedelta preserves tzinfo. + +5. (x+k).n = x.n + k + Again follows from how arithmetic is defined. + +Now we can explain tz.fromutc(x). Let's assume it's an interesting case +(meaning that the various tzinfo methods exist, and don't blow up or return +None when called). + +The function wants to return a datetime y with timezone tz, equivalent to x. +x is already in UTC. + +By #3, we want + + y.n - y.o = x.n [1] + +The algorithm starts by attaching tz to x.n, and calling that y. So +x.n = y.n at the start. Then it wants to add a duration k to y, so that [1] +becomes true; in effect, we want to solve [2] for k: + + (y+k).n - (y+k).o = x.n [2] + +By #1, this is the same as + + (y+k).n - ((y+k).s + (y+k).d) = x.n [3] + +By #5, (y+k).n = y.n + k, which equals x.n + k because x.n=y.n at the start. +Substituting that into [3], + + x.n + k - (y+k).s - (y+k).d = x.n; the x.n terms cancel, leaving + k - (y+k).s - (y+k).d = 0; rearranging, + k = (y+k).s - (y+k).d; by #4, (y+k).s == y.s, so + k = y.s - (y+k).d + +On the RHS, (y+k).d can't be computed directly, but y.s can be, and we +approximate k by ignoring the (y+k).d term at first. Note that k can't be +very large, since all offset-returning methods return a duration of magnitude +less than 24 hours. For that reason, if y is firmly in std time, (y+k).d must +be 0, so ignoring it has no consequence then. + +In any case, the new value is + + z = y + y.s [4] + +It's helpful to step back at look at [4] from a higher level: it's simply +mapping from UTC to tz's standard time. + +At this point, if + + z.n - z.o = x.n [5] + +we have an equivalent time, and are almost done. The insecurity here is +at the start of daylight time. Picture US Eastern for concreteness. The wall +time jumps from 1:59 to 3:00, and wall hours of the form 2:MM don't make good +sense then. The docs ask that an Eastern tzinfo class consider such a time to +be EDT (because it's "after 2"), which is a redundant spelling of 1:MM EST +on the day DST starts. We want to return the 1:MM EST spelling because that's +the only spelling that makes sense on the local wall clock. + +In fact, if [5] holds at this point, we do have the standard-time spelling, +but that takes a bit of proof. We first prove a stronger result. What's the +difference between the LHS and RHS of [5]? Let + + diff = x.n - (z.n - z.o) [6] + +Now + z.n = by [4] + (y + y.s).n = by #5 + y.n + y.s = since y.n = x.n + x.n + y.s = since z and y are have the same tzinfo member, + y.s = z.s by #2 + x.n + z.s + +Plugging that back into [6] gives + + diff = + x.n - ((x.n + z.s) - z.o) = expanding + x.n - x.n - z.s + z.o = cancelling + - z.s + z.o = by #2 + z.d + +So diff = z.d. + +If [5] is true now, diff = 0, so z.d = 0 too, and we have the standard-time +spelling we wanted in the endcase described above. We're done. Contrarily, +if z.d = 0, then we have a UTC equivalent, and are also done. + +If [5] is not true now, diff = z.d != 0, and z.d is the offset we need to +add to z (in effect, z is in tz's standard time, and we need to shift the +local clock into tz's daylight time). + +Let + + z' = z + z.d = z + diff [7] + +and we can again ask whether + + z'.n - z'.o = x.n [8] + +If so, we're done. If not, the tzinfo class is insane, according to the +assumptions we've made. This also requires a bit of proof. As before, let's +compute the difference between the LHS and RHS of [8] (and skipping some of +the justifications for the kinds of substitutions we've done several times +already): + + diff' = x.n - (z'.n - z'.o) = replacing z'.n via [7] + x.n - (z.n + diff - z'.o) = replacing diff via [6] + x.n - (z.n + x.n - (z.n - z.o) - z'.o) = + x.n - z.n - x.n + z.n - z.o + z'.o = cancel x.n + - z.n + z.n - z.o + z'.o = cancel z.n + - z.o + z'.o = #1 twice + -z.s - z.d + z'.s + z'.d = z and z' have same tzinfo + z'.d - z.d + +So z' is UTC-equivalent to x iff z'.d = z.d at this point. If they are equal, +we've found the UTC-equivalent so are done. In fact, we stop with [7] and +return z', not bothering to compute z'.d. + +How could z.d and z'd differ? z' = z + z.d [7], so merely moving z' by +a dst() offset, and starting *from* a time already in DST (we know z.d != 0), +would have to change the result dst() returns: we start in DST, and moving +a little further into it takes us out of DST. + +There isn't a sane case where this can happen. The closest it gets is at +the end of DST, where there's an hour in UTC with no spelling in a hybrid +tzinfo class. In US Eastern, that's 5:MM UTC = 0:MM EST = 1:MM EDT. During +that hour, on an Eastern clock 1:MM is taken as being in standard time (6:MM +UTC) because the docs insist on that, but 0:MM is taken as being in daylight +time (4:MM UTC). There is no local time mapping to 5:MM UTC. The local +clock jumps from 1:59 back to 1:00 again, and repeats the 1:MM hour in +standard time. Since that's what the local clock *does*, we want to map both +UTC hours 5:MM and 6:MM to 1:MM Eastern. The result is ambiguous +in local time, but so it goes -- it's the way the local clock works. + +When x = 5:MM UTC is the input to this algorithm, x.o=0, y.o=-5 and y.d=0, +so z=0:MM. z.d=60 (minutes) then, so [5] doesn't hold and we keep going. +z' = z + z.d = 1:MM then, and z'.d=0, and z'.d - z.d = -60 != 0 so [8] +(correctly) concludes that z' is not UTC-equivalent to x. + +Because we know z.d said z was in daylight time (else [5] would have held and +we would have stopped then), and we know z.d != z'.d (else [8] would have held +and we would have stopped then), and there are only 2 possible values dst() can +return in Eastern, it follows that z'.d must be 0 (which it is in the example, +but the reasoning doesn't depend on the example -- it depends on there being +two possible dst() outcomes, one zero and the other non-zero). Therefore +z' must be in standard time, and is the spelling we want in this case. + +Note again that z' is not UTC-equivalent as far as the hybrid tzinfo class is +concerned (because it takes z' as being in standard time rather than the +daylight time we intend here), but returning it gives the real-life "local +clock repeats an hour" behavior when mapping the "unspellable" UTC hour into +tz. + +When the input is 6:MM, z=1:MM and z.d=0, and we stop at once, again with +the 1:MM standard time spelling we want. + +So how can this break? One of the assumptions must be violated. Two +possibilities: + +1) [2] effectively says that y.s is invariant across all y belong to a given + time zone. This isn't true if, for political reasons or continental drift, + a region decides to change its base offset from UTC. + +2) There may be versions of "double daylight" time where the tail end of + the analysis gives up a step too early. I haven't thought about that + enough to say. + +In any case, it's clear that the default fromutc() is strong enough to handle +"almost all" time zones: so long as the standard offset is invariant, it +doesn't matter if daylight time transition points change from year to year, or +if daylight time is skipped in some years; it doesn't matter how large or +small dst() may get within its bounds; and it doesn't even matter if some +perverse time zone returns a negative dst()). So a breaking case must be +pretty bizarre, and a tzinfo subclass can override fromutc() if it is. +--------------------------------------------------------------------------- */ diff --git a/sys/src/cmd/python/Modules/dbmmodule.c b/sys/src/cmd/python/Modules/dbmmodule.c new file mode 100644 index 000000000..9086c8477 --- /dev/null +++ b/sys/src/cmd/python/Modules/dbmmodule.c @@ -0,0 +1,370 @@ + +/* DBM module using dictionary interface */ + + +#include "Python.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +/* Some Linux systems install gdbm/ndbm.h, but not ndbm.h. This supports + * whichever configure was able to locate. + */ +#if defined(HAVE_NDBM_H) +#include <ndbm.h> +#if defined(PYOS_OS2) && !defined(PYCC_GCC) +static char *which_dbm = "ndbm"; +#else +static char *which_dbm = "GNU gdbm"; /* EMX port of GDBM */ +#endif +#elif defined(HAVE_GDBM_NDBM_H) +#include <gdbm/ndbm.h> +static char *which_dbm = "GNU gdbm"; +#elif defined(HAVE_BERKDB_H) +#include <db.h> +static char *which_dbm = "Berkeley DB"; +#else +#error "No ndbm.h available!" +#endif + +typedef struct { + PyObject_HEAD + int di_size; /* -1 means recompute */ + DBM *di_dbm; +} dbmobject; + +static PyTypeObject Dbmtype; + +#define is_dbmobject(v) ((v)->ob_type == &Dbmtype) +#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \ + { PyErr_SetString(DbmError, "DBM object has already been closed"); \ + return NULL; } + +static PyObject *DbmError; + +static PyObject * +newdbmobject(char *file, int flags, int mode) +{ + dbmobject *dp; + + dp = PyObject_New(dbmobject, &Dbmtype); + if (dp == NULL) + return NULL; + dp->di_size = -1; + if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) { + PyErr_SetFromErrno(DbmError); + Py_DECREF(dp); + return NULL; + } + return (PyObject *)dp; +} + +/* Methods */ + +static void +dbm_dealloc(register dbmobject *dp) +{ + if ( dp->di_dbm ) + dbm_close(dp->di_dbm); + PyObject_Del(dp); +} + +static Py_ssize_t +dbm_length(dbmobject *dp) +{ + if (dp->di_dbm == NULL) { + PyErr_SetString(DbmError, "DBM object has already been closed"); + return -1; + } + if ( dp->di_size < 0 ) { + datum key; + int size; + + size = 0; + for ( key=dbm_firstkey(dp->di_dbm); key.dptr; + key = dbm_nextkey(dp->di_dbm)) + size++; + dp->di_size = size; + } + return dp->di_size; +} + +static PyObject * +dbm_subscript(dbmobject *dp, register PyObject *key) +{ + datum drec, krec; + int tmp_size; + + if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size) ) + return NULL; + + krec.dsize = tmp_size; + check_dbmobject_open(dp); + drec = dbm_fetch(dp->di_dbm, krec); + if ( drec.dptr == 0 ) { + PyErr_SetString(PyExc_KeyError, + PyString_AS_STRING((PyStringObject *)key)); + return NULL; + } + if ( dbm_error(dp->di_dbm) ) { + dbm_clearerr(dp->di_dbm); + PyErr_SetString(DbmError, ""); + return NULL; + } + return PyString_FromStringAndSize(drec.dptr, drec.dsize); +} + +static int +dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w) +{ + datum krec, drec; + int tmp_size; + + if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) { + PyErr_SetString(PyExc_TypeError, + "dbm mappings have string indices only"); + return -1; + } + krec.dsize = tmp_size; + if (dp->di_dbm == NULL) { + PyErr_SetString(DbmError, "DBM object has already been closed"); + return -1; + } + dp->di_size = -1; + if (w == NULL) { + if ( dbm_delete(dp->di_dbm, krec) < 0 ) { + dbm_clearerr(dp->di_dbm); + PyErr_SetString(PyExc_KeyError, + PyString_AS_STRING((PyStringObject *)v)); + return -1; + } + } else { + if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) { + PyErr_SetString(PyExc_TypeError, + "dbm mappings have string elements only"); + return -1; + } + drec.dsize = tmp_size; + if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) { + dbm_clearerr(dp->di_dbm); + PyErr_SetString(DbmError, + "cannot add item to database"); + return -1; + } + } + if ( dbm_error(dp->di_dbm) ) { + dbm_clearerr(dp->di_dbm); + PyErr_SetString(DbmError, ""); + return -1; + } + return 0; +} + +static PyMappingMethods dbm_as_mapping = { + (lenfunc)dbm_length, /*mp_length*/ + (binaryfunc)dbm_subscript, /*mp_subscript*/ + (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/ +}; + +static PyObject * +dbm__close(register dbmobject *dp, PyObject *unused) +{ + if (dp->di_dbm) + dbm_close(dp->di_dbm); + dp->di_dbm = NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +dbm_keys(register dbmobject *dp, PyObject *unused) +{ + register PyObject *v, *item; + datum key; + int err; + + check_dbmobject_open(dp); + v = PyList_New(0); + if (v == NULL) + return NULL; + for (key = dbm_firstkey(dp->di_dbm); key.dptr; + key = dbm_nextkey(dp->di_dbm)) { + item = PyString_FromStringAndSize(key.dptr, key.dsize); + if (item == NULL) { + Py_DECREF(v); + return NULL; + } + err = PyList_Append(v, item); + Py_DECREF(item); + if (err != 0) { + Py_DECREF(v); + return NULL; + } + } + return v; +} + +static PyObject * +dbm_has_key(register dbmobject *dp, PyObject *args) +{ + datum key, val; + int tmp_size; + + if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &tmp_size)) + return NULL; + key.dsize = tmp_size; + check_dbmobject_open(dp); + val = dbm_fetch(dp->di_dbm, key); + return PyInt_FromLong(val.dptr != NULL); +} + +static PyObject * +dbm_get(register dbmobject *dp, PyObject *args) +{ + datum key, val; + PyObject *defvalue = Py_None; + int tmp_size; + + if (!PyArg_ParseTuple(args, "s#|O:get", + &key.dptr, &tmp_size, &defvalue)) + return NULL; + key.dsize = tmp_size; + check_dbmobject_open(dp); + val = dbm_fetch(dp->di_dbm, key); + if (val.dptr != NULL) + return PyString_FromStringAndSize(val.dptr, val.dsize); + else { + Py_INCREF(defvalue); + return defvalue; + } +} + +static PyObject * +dbm_setdefault(register dbmobject *dp, PyObject *args) +{ + datum key, val; + PyObject *defvalue = NULL; + int tmp_size; + + if (!PyArg_ParseTuple(args, "s#|S:setdefault", + &key.dptr, &tmp_size, &defvalue)) + return NULL; + key.dsize = tmp_size; + check_dbmobject_open(dp); + val = dbm_fetch(dp->di_dbm, key); + if (val.dptr != NULL) + return PyString_FromStringAndSize(val.dptr, val.dsize); + if (defvalue == NULL) { + defvalue = PyString_FromStringAndSize(NULL, 0); + if (defvalue == NULL) + return NULL; + } + else + Py_INCREF(defvalue); + val.dptr = PyString_AS_STRING(defvalue); + val.dsize = PyString_GET_SIZE(defvalue); + if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) { + dbm_clearerr(dp->di_dbm); + PyErr_SetString(DbmError, "cannot add item to database"); + return NULL; + } + return defvalue; +} + +static PyMethodDef dbm_methods[] = { + {"close", (PyCFunction)dbm__close, METH_NOARGS, + "close()\nClose the database."}, + {"keys", (PyCFunction)dbm_keys, METH_NOARGS, + "keys() -> list\nReturn a list of all keys in the database."}, + {"has_key", (PyCFunction)dbm_has_key, METH_VARARGS, + "has_key(key} -> boolean\nReturn true iff key is in the database."}, + {"get", (PyCFunction)dbm_get, METH_VARARGS, + "get(key[, default]) -> value\n" + "Return the value for key if present, otherwise default."}, + {"setdefault", (PyCFunction)dbm_setdefault, METH_VARARGS, + "setdefault(key[, default]) -> value\n" + "Return the value for key if present, otherwise default. If key\n" + "is not in the database, it is inserted with default as the value."}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +dbm_getattr(dbmobject *dp, char *name) +{ + return Py_FindMethod(dbm_methods, (PyObject *)dp, name); +} + +static PyTypeObject Dbmtype = { + PyObject_HEAD_INIT(NULL) + 0, + "dbm.dbm", + sizeof(dbmobject), + 0, + (destructor)dbm_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)dbm_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &dbm_as_mapping, /*tp_as_mapping*/ +}; + +/* ----------------------------------------------------------------- */ + +static PyObject * +dbmopen(PyObject *self, PyObject *args) +{ + char *name; + char *flags = "r"; + int iflags; + int mode = 0666; + + if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) ) + return NULL; + if ( strcmp(flags, "r") == 0 ) + iflags = O_RDONLY; + else if ( strcmp(flags, "w") == 0 ) + iflags = O_RDWR; + else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */ + iflags = O_RDWR|O_CREAT; + else if ( strcmp(flags, "c") == 0 ) + iflags = O_RDWR|O_CREAT; + else if ( strcmp(flags, "n") == 0 ) + iflags = O_RDWR|O_CREAT|O_TRUNC; + else { + PyErr_SetString(DbmError, + "arg 2 to open should be 'r', 'w', 'c', or 'n'"); + return NULL; + } + return newdbmobject(name, iflags, mode); +} + +static PyMethodDef dbmmodule_methods[] = { + { "open", (PyCFunction)dbmopen, METH_VARARGS, + "open(path[, flag[, mode]]) -> mapping\n" + "Return a database object."}, + { 0, 0 }, +}; + +PyMODINIT_FUNC +initdbm(void) { + PyObject *m, *d, *s; + + Dbmtype.ob_type = &PyType_Type; + m = Py_InitModule("dbm", dbmmodule_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + if (DbmError == NULL) + DbmError = PyErr_NewException("dbm.error", NULL, NULL); + s = PyString_FromString(which_dbm); + if (s != NULL) { + PyDict_SetItemString(d, "library", s); + Py_DECREF(s); + } + if (DbmError != NULL) + PyDict_SetItemString(d, "error", DbmError); +} diff --git a/sys/src/cmd/python/Modules/dlmodule.c b/sys/src/cmd/python/Modules/dlmodule.c new file mode 100644 index 000000000..5622ed9e7 --- /dev/null +++ b/sys/src/cmd/python/Modules/dlmodule.c @@ -0,0 +1,278 @@ + +/* dl module */ + +#include "Python.h" + +#include <dlfcn.h> + +#ifdef __VMS +#include <unistd.h> +#endif + +#ifndef RTLD_LAZY +#define RTLD_LAZY 1 +#endif + +typedef void *PyUnivPtr; +typedef struct { + PyObject_HEAD + PyUnivPtr *dl_handle; +} dlobject; + +static PyTypeObject Dltype; + +static PyObject *Dlerror; + +static PyObject * +newdlobject(PyUnivPtr *handle) +{ + dlobject *xp; + xp = PyObject_New(dlobject, &Dltype); + if (xp == NULL) + return NULL; + xp->dl_handle = handle; + return (PyObject *)xp; +} + +static void +dl_dealloc(dlobject *xp) +{ + if (xp->dl_handle != NULL) + dlclose(xp->dl_handle); + PyObject_Del(xp); +} + +static PyObject * +dl_close(dlobject *xp) +{ + if (xp->dl_handle != NULL) { + dlclose(xp->dl_handle); + xp->dl_handle = NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +dl_sym(dlobject *xp, PyObject *args) +{ + char *name; + PyUnivPtr *func; + if (PyString_Check(args)) { + name = PyString_AS_STRING(args); + } else { + PyErr_Format(PyExc_TypeError, "expected string, found %.200s", + args->ob_type->tp_name); + return NULL; + } + func = dlsym(xp->dl_handle, name); + if (func == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyInt_FromLong((long)func); +} + +static PyObject * +dl_call(dlobject *xp, PyObject *args) +{ + PyObject *name; + long (*func)(long, long, long, long, long, + long, long, long, long, long); + long alist[10]; + long res; + Py_ssize_t i; + Py_ssize_t n = PyTuple_Size(args); + if (n < 1) { + PyErr_SetString(PyExc_TypeError, "at least a name is needed"); + return NULL; + } + name = PyTuple_GetItem(args, 0); + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "function name must be a string"); + return NULL; + } + func = (long (*)(long, long, long, long, long, + long, long, long, long, long)) + dlsym(xp->dl_handle, PyString_AsString(name)); + if (func == NULL) { + PyErr_SetString(PyExc_ValueError, dlerror()); + return NULL; + } + if (n-1 > 10) { + PyErr_SetString(PyExc_TypeError, + "too many arguments (max 10)"); + return NULL; + } + for (i = 1; i < n; i++) { + PyObject *v = PyTuple_GetItem(args, i); + if (PyInt_Check(v)) + alist[i-1] = PyInt_AsLong(v); + else if (PyString_Check(v)) + alist[i-1] = (long)PyString_AsString(v); + else if (v == Py_None) + alist[i-1] = (long) ((char *)NULL); + else { + PyErr_SetString(PyExc_TypeError, + "arguments must be int, string or None"); + return NULL; + } + } + for (; i <= 10; i++) + alist[i-1] = 0; + res = (*func)(alist[0], alist[1], alist[2], alist[3], alist[4], + alist[5], alist[6], alist[7], alist[8], alist[9]); + return PyInt_FromLong(res); +} + +static PyMethodDef dlobject_methods[] = { + {"call", (PyCFunction)dl_call, METH_VARARGS}, + {"sym", (PyCFunction)dl_sym, METH_O}, + {"close", (PyCFunction)dl_close, METH_NOARGS}, + {NULL, NULL} /* Sentinel */ +}; + +static PyObject * +dl_getattr(dlobject *xp, char *name) +{ + return Py_FindMethod(dlobject_methods, (PyObject *)xp, name); +} + + +static PyTypeObject Dltype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "dl.dl", /*tp_name*/ + sizeof(dlobject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)dl_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)dl_getattr,/*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +static PyObject * +dl_open(PyObject *self, PyObject *args) +{ + char *name; + int mode; + PyUnivPtr *handle; + if (sizeof(int) != sizeof(long) || + sizeof(long) != sizeof(char *)) { + PyErr_SetString(PyExc_SystemError, + "module dl requires sizeof(int) == sizeof(long) == sizeof(char*)"); + return NULL; + } + + if (PyArg_ParseTuple(args, "z:open", &name)) + mode = RTLD_LAZY; + else { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "zi:open", &name, &mode)) + return NULL; +#ifndef RTLD_NOW + if (mode != RTLD_LAZY) { + PyErr_SetString(PyExc_ValueError, "mode must be 1"); + return NULL; + } +#endif + } + handle = dlopen(name, mode); + if (handle == NULL) { + PyErr_SetString(Dlerror, dlerror()); + return NULL; + } +#ifdef __VMS + /* Under OpenVMS dlopen doesn't do any check, just save the name + * for later use, so we have to check if the file is readable, + * the name can be a logical or a file from SYS$SHARE. + */ + if (access(name, R_OK)) { + char fname[strlen(name) + 20]; + strcpy(fname, "SYS$SHARE:"); + strcat(fname, name); + strcat(fname, ".EXE"); + if (access(fname, R_OK)) { + dlclose(handle); + PyErr_SetString(Dlerror, + "File not found or protection violation"); + return NULL; + } + } +#endif + return newdlobject(handle); +} + +static PyMethodDef dl_methods[] = { + {"open", dl_open, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* From socketmodule.c + * Convenience routine to export an integer value. + * + * Errors are silently ignored, for better or for worse... + */ +static void +insint(PyObject *d, char *name, int value) +{ + PyObject *v = PyInt_FromLong((long) value); + if (!v || PyDict_SetItemString(d, name, v)) + PyErr_Clear(); + + Py_XDECREF(v); +} + +PyMODINIT_FUNC +initdl(void) +{ + PyObject *m, *d, *x; + + /* Initialize object type */ + Dltype.ob_type = &PyType_Type; + + /* Create the module and add the functions */ + m = Py_InitModule("dl", dl_methods); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + Dlerror = x = PyErr_NewException("dl.error", NULL, NULL); + PyDict_SetItemString(d, "error", x); + x = PyInt_FromLong((long)RTLD_LAZY); + PyDict_SetItemString(d, "RTLD_LAZY", x); +#define INSINT(X) insint(d,#X,X) +#ifdef RTLD_NOW + INSINT(RTLD_NOW); +#endif +#ifdef RTLD_NOLOAD + INSINT(RTLD_NOLOAD); +#endif +#ifdef RTLD_GLOBAL + INSINT(RTLD_GLOBAL); +#endif +#ifdef RTLD_LOCAL + INSINT(RTLD_LOCAL); +#endif +#ifdef RTLD_PARENT + INSINT(RTLD_PARENT); +#endif +#ifdef RTLD_GROUP + INSINT(RTLD_GROUP); +#endif +#ifdef RTLD_WORLD + INSINT(RTLD_WORLD); +#endif +#ifdef RTLD_NODELETE + INSINT(RTLD_NODELETE); +#endif +} diff --git a/sys/src/cmd/python/Modules/errnomodule.c b/sys/src/cmd/python/Modules/errnomodule.c new file mode 100644 index 000000000..696d396b0 --- /dev/null +++ b/sys/src/cmd/python/Modules/errnomodule.c @@ -0,0 +1,788 @@ + +/* Errno module */ + +#include "Python.h" + +/* Windows socket errors (WSA*) */ +#ifdef MS_WINDOWS +#include <winsock.h> +#endif + +/* + * Pull in the system error definitions + */ + +static PyMethodDef errno_methods[] = { + {NULL, NULL} +}; + +/* Helper function doing the dictionary inserting */ + +static void +_inscode(PyObject *d, PyObject *de, char *name, int code) +{ + PyObject *u = PyString_FromString(name); + PyObject *v = PyInt_FromLong((long) code); + + /* Don't bother checking for errors; they'll be caught at the end + * of the module initialization function by the caller of + * initerrno(). + */ + if (u && v) { + /* insert in modules dict */ + PyDict_SetItem(d, u, v); + /* insert in errorcode dict */ + PyDict_SetItem(de, v, u); + } + Py_XDECREF(u); + Py_XDECREF(v); +} + +PyDoc_STRVAR(errno__doc__, +"This module makes available standard errno system symbols.\n\ +\n\ +The value of each symbol is the corresponding integer value,\n\ +e.g., on most systems, errno.ENOENT equals the integer 2.\n\ +\n\ +The dictionary errno.errorcode maps numeric codes to symbol names,\n\ +e.g., errno.errorcode[2] could be the string 'ENOENT'.\n\ +\n\ +Symbols that are not relevant to the underlying system are not defined.\n\ +\n\ +To map error codes to error messages, use the function os.strerror(),\n\ +e.g. os.strerror(2) could return 'No such file or directory'."); + +PyMODINIT_FUNC +initerrno(void) +{ + PyObject *m, *d, *de; + m = Py_InitModule3("errno", errno_methods, errno__doc__); + if (m == NULL) + return; + d = PyModule_GetDict(m); + de = PyDict_New(); + if (!d || !de || PyDict_SetItemString(d, "errorcode", de) < 0) + return; + +/* Macro so I don't have to edit each and every line below... */ +#define inscode(d, ds, de, name, code, comment) _inscode(d, de, name, code) + + /* + * The names and comments are borrowed from linux/include/errno.h, + * which should be pretty all-inclusive + */ + +#ifdef ENODEV + inscode(d, ds, de, "ENODEV", ENODEV, "No such device"); +#endif +#ifdef ENOCSI + inscode(d, ds, de, "ENOCSI", ENOCSI, "No CSI structure available"); +#endif +#ifdef EHOSTUNREACH + inscode(d, ds, de, "EHOSTUNREACH", EHOSTUNREACH, "No route to host"); +#else +#ifdef WSAEHOSTUNREACH + inscode(d, ds, de, "EHOSTUNREACH", WSAEHOSTUNREACH, "No route to host"); +#endif +#endif +#ifdef ENOMSG + inscode(d, ds, de, "ENOMSG", ENOMSG, "No message of desired type"); +#endif +#ifdef EUCLEAN + inscode(d, ds, de, "EUCLEAN", EUCLEAN, "Structure needs cleaning"); +#endif +#ifdef EL2NSYNC + inscode(d, ds, de, "EL2NSYNC", EL2NSYNC, "Level 2 not synchronized"); +#endif +#ifdef EL2HLT + inscode(d, ds, de, "EL2HLT", EL2HLT, "Level 2 halted"); +#endif +#ifdef ENODATA + inscode(d, ds, de, "ENODATA", ENODATA, "No data available"); +#endif +#ifdef ENOTBLK + inscode(d, ds, de, "ENOTBLK", ENOTBLK, "Block device required"); +#endif +#ifdef ENOSYS + inscode(d, ds, de, "ENOSYS", ENOSYS, "Function not implemented"); +#endif +#ifdef EPIPE + inscode(d, ds, de, "EPIPE", EPIPE, "Broken pipe"); +#endif +#ifdef EINVAL + inscode(d, ds, de, "EINVAL", EINVAL, "Invalid argument"); +#else +#ifdef WSAEINVAL + inscode(d, ds, de, "EINVAL", WSAEINVAL, "Invalid argument"); +#endif +#endif +#ifdef EOVERFLOW + inscode(d, ds, de, "EOVERFLOW", EOVERFLOW, "Value too large for defined data type"); +#endif +#ifdef EADV + inscode(d, ds, de, "EADV", EADV, "Advertise error"); +#endif +#ifdef EINTR + inscode(d, ds, de, "EINTR", EINTR, "Interrupted system call"); +#else +#ifdef WSAEINTR + inscode(d, ds, de, "EINTR", WSAEINTR, "Interrupted system call"); +#endif +#endif +#ifdef EUSERS + inscode(d, ds, de, "EUSERS", EUSERS, "Too many users"); +#else +#ifdef WSAEUSERS + inscode(d, ds, de, "EUSERS", WSAEUSERS, "Too many users"); +#endif +#endif +#ifdef ENOTEMPTY + inscode(d, ds, de, "ENOTEMPTY", ENOTEMPTY, "Directory not empty"); +#else +#ifdef WSAENOTEMPTY + inscode(d, ds, de, "ENOTEMPTY", WSAENOTEMPTY, "Directory not empty"); +#endif +#endif +#ifdef ENOBUFS + inscode(d, ds, de, "ENOBUFS", ENOBUFS, "No buffer space available"); +#else +#ifdef WSAENOBUFS + inscode(d, ds, de, "ENOBUFS", WSAENOBUFS, "No buffer space available"); +#endif +#endif +#ifdef EPROTO + inscode(d, ds, de, "EPROTO", EPROTO, "Protocol error"); +#endif +#ifdef EREMOTE + inscode(d, ds, de, "EREMOTE", EREMOTE, "Object is remote"); +#else +#ifdef WSAEREMOTE + inscode(d, ds, de, "EREMOTE", WSAEREMOTE, "Object is remote"); +#endif +#endif +#ifdef ENAVAIL + inscode(d, ds, de, "ENAVAIL", ENAVAIL, "No XENIX semaphores available"); +#endif +#ifdef ECHILD + inscode(d, ds, de, "ECHILD", ECHILD, "No child processes"); +#endif +#ifdef ELOOP + inscode(d, ds, de, "ELOOP", ELOOP, "Too many symbolic links encountered"); +#else +#ifdef WSAELOOP + inscode(d, ds, de, "ELOOP", WSAELOOP, "Too many symbolic links encountered"); +#endif +#endif +#ifdef EXDEV + inscode(d, ds, de, "EXDEV", EXDEV, "Cross-device link"); +#endif +#ifdef E2BIG + inscode(d, ds, de, "E2BIG", E2BIG, "Arg list too long"); +#endif +#ifdef ESRCH + inscode(d, ds, de, "ESRCH", ESRCH, "No such process"); +#endif +#ifdef EMSGSIZE + inscode(d, ds, de, "EMSGSIZE", EMSGSIZE, "Message too long"); +#else +#ifdef WSAEMSGSIZE + inscode(d, ds, de, "EMSGSIZE", WSAEMSGSIZE, "Message too long"); +#endif +#endif +#ifdef EAFNOSUPPORT + inscode(d, ds, de, "EAFNOSUPPORT", EAFNOSUPPORT, "Address family not supported by protocol"); +#else +#ifdef WSAEAFNOSUPPORT + inscode(d, ds, de, "EAFNOSUPPORT", WSAEAFNOSUPPORT, "Address family not supported by protocol"); +#endif +#endif +#ifdef EBADR + inscode(d, ds, de, "EBADR", EBADR, "Invalid request descriptor"); +#endif +#ifdef EHOSTDOWN + inscode(d, ds, de, "EHOSTDOWN", EHOSTDOWN, "Host is down"); +#else +#ifdef WSAEHOSTDOWN + inscode(d, ds, de, "EHOSTDOWN", WSAEHOSTDOWN, "Host is down"); +#endif +#endif +#ifdef EPFNOSUPPORT + inscode(d, ds, de, "EPFNOSUPPORT", EPFNOSUPPORT, "Protocol family not supported"); +#else +#ifdef WSAEPFNOSUPPORT + inscode(d, ds, de, "EPFNOSUPPORT", WSAEPFNOSUPPORT, "Protocol family not supported"); +#endif +#endif +#ifdef ENOPROTOOPT + inscode(d, ds, de, "ENOPROTOOPT", ENOPROTOOPT, "Protocol not available"); +#else +#ifdef WSAENOPROTOOPT + inscode(d, ds, de, "ENOPROTOOPT", WSAENOPROTOOPT, "Protocol not available"); +#endif +#endif +#ifdef EBUSY + inscode(d, ds, de, "EBUSY", EBUSY, "Device or resource busy"); +#endif +#ifdef EWOULDBLOCK + inscode(d, ds, de, "EWOULDBLOCK", EWOULDBLOCK, "Operation would block"); +#else +#ifdef WSAEWOULDBLOCK + inscode(d, ds, de, "EWOULDBLOCK", WSAEWOULDBLOCK, "Operation would block"); +#endif +#endif +#ifdef EBADFD + inscode(d, ds, de, "EBADFD", EBADFD, "File descriptor in bad state"); +#endif +#ifdef EDOTDOT + inscode(d, ds, de, "EDOTDOT", EDOTDOT, "RFS specific error"); +#endif +#ifdef EISCONN + inscode(d, ds, de, "EISCONN", EISCONN, "Transport endpoint is already connected"); +#else +#ifdef WSAEISCONN + inscode(d, ds, de, "EISCONN", WSAEISCONN, "Transport endpoint is already connected"); +#endif +#endif +#ifdef ENOANO + inscode(d, ds, de, "ENOANO", ENOANO, "No anode"); +#endif +#ifdef ESHUTDOWN + inscode(d, ds, de, "ESHUTDOWN", ESHUTDOWN, "Cannot send after transport endpoint shutdown"); +#else +#ifdef WSAESHUTDOWN + inscode(d, ds, de, "ESHUTDOWN", WSAESHUTDOWN, "Cannot send after transport endpoint shutdown"); +#endif +#endif +#ifdef ECHRNG + inscode(d, ds, de, "ECHRNG", ECHRNG, "Channel number out of range"); +#endif +#ifdef ELIBBAD + inscode(d, ds, de, "ELIBBAD", ELIBBAD, "Accessing a corrupted shared library"); +#endif +#ifdef ENONET + inscode(d, ds, de, "ENONET", ENONET, "Machine is not on the network"); +#endif +#ifdef EBADE + inscode(d, ds, de, "EBADE", EBADE, "Invalid exchange"); +#endif +#ifdef EBADF + inscode(d, ds, de, "EBADF", EBADF, "Bad file number"); +#else +#ifdef WSAEBADF + inscode(d, ds, de, "EBADF", WSAEBADF, "Bad file number"); +#endif +#endif +#ifdef EMULTIHOP + inscode(d, ds, de, "EMULTIHOP", EMULTIHOP, "Multihop attempted"); +#endif +#ifdef EIO + inscode(d, ds, de, "EIO", EIO, "I/O error"); +#endif +#ifdef EUNATCH + inscode(d, ds, de, "EUNATCH", EUNATCH, "Protocol driver not attached"); +#endif +#ifdef EPROTOTYPE + inscode(d, ds, de, "EPROTOTYPE", EPROTOTYPE, "Protocol wrong type for socket"); +#else +#ifdef WSAEPROTOTYPE + inscode(d, ds, de, "EPROTOTYPE", WSAEPROTOTYPE, "Protocol wrong type for socket"); +#endif +#endif +#ifdef ENOSPC + inscode(d, ds, de, "ENOSPC", ENOSPC, "No space left on device"); +#endif +#ifdef ENOEXEC + inscode(d, ds, de, "ENOEXEC", ENOEXEC, "Exec format error"); +#endif +#ifdef EALREADY + inscode(d, ds, de, "EALREADY", EALREADY, "Operation already in progress"); +#else +#ifdef WSAEALREADY + inscode(d, ds, de, "EALREADY", WSAEALREADY, "Operation already in progress"); +#endif +#endif +#ifdef ENETDOWN + inscode(d, ds, de, "ENETDOWN", ENETDOWN, "Network is down"); +#else +#ifdef WSAENETDOWN + inscode(d, ds, de, "ENETDOWN", WSAENETDOWN, "Network is down"); +#endif +#endif +#ifdef ENOTNAM + inscode(d, ds, de, "ENOTNAM", ENOTNAM, "Not a XENIX named type file"); +#endif +#ifdef EACCES + inscode(d, ds, de, "EACCES", EACCES, "Permission denied"); +#else +#ifdef WSAEACCES + inscode(d, ds, de, "EACCES", WSAEACCES, "Permission denied"); +#endif +#endif +#ifdef ELNRNG + inscode(d, ds, de, "ELNRNG", ELNRNG, "Link number out of range"); +#endif +#ifdef EILSEQ + inscode(d, ds, de, "EILSEQ", EILSEQ, "Illegal byte sequence"); +#endif +#ifdef ENOTDIR + inscode(d, ds, de, "ENOTDIR", ENOTDIR, "Not a directory"); +#endif +#ifdef ENOTUNIQ + inscode(d, ds, de, "ENOTUNIQ", ENOTUNIQ, "Name not unique on network"); +#endif +#ifdef EPERM + inscode(d, ds, de, "EPERM", EPERM, "Operation not permitted"); +#endif +#ifdef EDOM + inscode(d, ds, de, "EDOM", EDOM, "Math argument out of domain of func"); +#endif +#ifdef EXFULL + inscode(d, ds, de, "EXFULL", EXFULL, "Exchange full"); +#endif +#ifdef ECONNREFUSED + inscode(d, ds, de, "ECONNREFUSED", ECONNREFUSED, "Connection refused"); +#else +#ifdef WSAECONNREFUSED + inscode(d, ds, de, "ECONNREFUSED", WSAECONNREFUSED, "Connection refused"); +#endif +#endif +#ifdef EISDIR + inscode(d, ds, de, "EISDIR", EISDIR, "Is a directory"); +#endif +#ifdef EPROTONOSUPPORT + inscode(d, ds, de, "EPROTONOSUPPORT", EPROTONOSUPPORT, "Protocol not supported"); +#else +#ifdef WSAEPROTONOSUPPORT + inscode(d, ds, de, "EPROTONOSUPPORT", WSAEPROTONOSUPPORT, "Protocol not supported"); +#endif +#endif +#ifdef EROFS + inscode(d, ds, de, "EROFS", EROFS, "Read-only file system"); +#endif +#ifdef EADDRNOTAVAIL + inscode(d, ds, de, "EADDRNOTAVAIL", EADDRNOTAVAIL, "Cannot assign requested address"); +#else +#ifdef WSAEADDRNOTAVAIL + inscode(d, ds, de, "EADDRNOTAVAIL", WSAEADDRNOTAVAIL, "Cannot assign requested address"); +#endif +#endif +#ifdef EIDRM + inscode(d, ds, de, "EIDRM", EIDRM, "Identifier removed"); +#endif +#ifdef ECOMM + inscode(d, ds, de, "ECOMM", ECOMM, "Communication error on send"); +#endif +#ifdef ESRMNT + inscode(d, ds, de, "ESRMNT", ESRMNT, "Srmount error"); +#endif +#ifdef EREMOTEIO + inscode(d, ds, de, "EREMOTEIO", EREMOTEIO, "Remote I/O error"); +#endif +#ifdef EL3RST + inscode(d, ds, de, "EL3RST", EL3RST, "Level 3 reset"); +#endif +#ifdef EBADMSG + inscode(d, ds, de, "EBADMSG", EBADMSG, "Not a data message"); +#endif +#ifdef ENFILE + inscode(d, ds, de, "ENFILE", ENFILE, "File table overflow"); +#endif +#ifdef ELIBMAX + inscode(d, ds, de, "ELIBMAX", ELIBMAX, "Attempting to link in too many shared libraries"); +#endif +#ifdef ESPIPE + inscode(d, ds, de, "ESPIPE", ESPIPE, "Illegal seek"); +#endif +#ifdef ENOLINK + inscode(d, ds, de, "ENOLINK", ENOLINK, "Link has been severed"); +#endif +#ifdef ENETRESET + inscode(d, ds, de, "ENETRESET", ENETRESET, "Network dropped connection because of reset"); +#else +#ifdef WSAENETRESET + inscode(d, ds, de, "ENETRESET", WSAENETRESET, "Network dropped connection because of reset"); +#endif +#endif +#ifdef ETIMEDOUT + inscode(d, ds, de, "ETIMEDOUT", ETIMEDOUT, "Connection timed out"); +#else +#ifdef WSAETIMEDOUT + inscode(d, ds, de, "ETIMEDOUT", WSAETIMEDOUT, "Connection timed out"); +#endif +#endif +#ifdef ENOENT + inscode(d, ds, de, "ENOENT", ENOENT, "No such file or directory"); +#endif +#ifdef EEXIST + inscode(d, ds, de, "EEXIST", EEXIST, "File exists"); +#endif +#ifdef EDQUOT + inscode(d, ds, de, "EDQUOT", EDQUOT, "Quota exceeded"); +#else +#ifdef WSAEDQUOT + inscode(d, ds, de, "EDQUOT", WSAEDQUOT, "Quota exceeded"); +#endif +#endif +#ifdef ENOSTR + inscode(d, ds, de, "ENOSTR", ENOSTR, "Device not a stream"); +#endif +#ifdef EBADSLT + inscode(d, ds, de, "EBADSLT", EBADSLT, "Invalid slot"); +#endif +#ifdef EBADRQC + inscode(d, ds, de, "EBADRQC", EBADRQC, "Invalid request code"); +#endif +#ifdef ELIBACC + inscode(d, ds, de, "ELIBACC", ELIBACC, "Can not access a needed shared library"); +#endif +#ifdef EFAULT + inscode(d, ds, de, "EFAULT", EFAULT, "Bad address"); +#else +#ifdef WSAEFAULT + inscode(d, ds, de, "EFAULT", WSAEFAULT, "Bad address"); +#endif +#endif +#ifdef EFBIG + inscode(d, ds, de, "EFBIG", EFBIG, "File too large"); +#endif +#ifdef EDEADLK + inscode(d, ds, de, "EDEADLK", EDEADLK, "Resource deadlock would occur"); +#endif +#ifdef ENOTCONN + inscode(d, ds, de, "ENOTCONN", ENOTCONN, "Transport endpoint is not connected"); +#else +#ifdef WSAENOTCONN + inscode(d, ds, de, "ENOTCONN", WSAENOTCONN, "Transport endpoint is not connected"); +#endif +#endif +#ifdef EDESTADDRREQ + inscode(d, ds, de, "EDESTADDRREQ", EDESTADDRREQ, "Destination address required"); +#else +#ifdef WSAEDESTADDRREQ + inscode(d, ds, de, "EDESTADDRREQ", WSAEDESTADDRREQ, "Destination address required"); +#endif +#endif +#ifdef ELIBSCN + inscode(d, ds, de, "ELIBSCN", ELIBSCN, ".lib section in a.out corrupted"); +#endif +#ifdef ENOLCK + inscode(d, ds, de, "ENOLCK", ENOLCK, "No record locks available"); +#endif +#ifdef EISNAM + inscode(d, ds, de, "EISNAM", EISNAM, "Is a named type file"); +#endif +#ifdef ECONNABORTED + inscode(d, ds, de, "ECONNABORTED", ECONNABORTED, "Software caused connection abort"); +#else +#ifdef WSAECONNABORTED + inscode(d, ds, de, "ECONNABORTED", WSAECONNABORTED, "Software caused connection abort"); +#endif +#endif +#ifdef ENETUNREACH + inscode(d, ds, de, "ENETUNREACH", ENETUNREACH, "Network is unreachable"); +#else +#ifdef WSAENETUNREACH + inscode(d, ds, de, "ENETUNREACH", WSAENETUNREACH, "Network is unreachable"); +#endif +#endif +#ifdef ESTALE + inscode(d, ds, de, "ESTALE", ESTALE, "Stale NFS file handle"); +#else +#ifdef WSAESTALE + inscode(d, ds, de, "ESTALE", WSAESTALE, "Stale NFS file handle"); +#endif +#endif +#ifdef ENOSR + inscode(d, ds, de, "ENOSR", ENOSR, "Out of streams resources"); +#endif +#ifdef ENOMEM + inscode(d, ds, de, "ENOMEM", ENOMEM, "Out of memory"); +#endif +#ifdef ENOTSOCK + inscode(d, ds, de, "ENOTSOCK", ENOTSOCK, "Socket operation on non-socket"); +#else +#ifdef WSAENOTSOCK + inscode(d, ds, de, "ENOTSOCK", WSAENOTSOCK, "Socket operation on non-socket"); +#endif +#endif +#ifdef ESTRPIPE + inscode(d, ds, de, "ESTRPIPE", ESTRPIPE, "Streams pipe error"); +#endif +#ifdef EMLINK + inscode(d, ds, de, "EMLINK", EMLINK, "Too many links"); +#endif +#ifdef ERANGE + inscode(d, ds, de, "ERANGE", ERANGE, "Math result not representable"); +#endif +#ifdef ELIBEXEC + inscode(d, ds, de, "ELIBEXEC", ELIBEXEC, "Cannot exec a shared library directly"); +#endif +#ifdef EL3HLT + inscode(d, ds, de, "EL3HLT", EL3HLT, "Level 3 halted"); +#endif +#ifdef ECONNRESET + inscode(d, ds, de, "ECONNRESET", ECONNRESET, "Connection reset by peer"); +#else +#ifdef WSAECONNRESET + inscode(d, ds, de, "ECONNRESET", WSAECONNRESET, "Connection reset by peer"); +#endif +#endif +#ifdef EADDRINUSE + inscode(d, ds, de, "EADDRINUSE", EADDRINUSE, "Address already in use"); +#else +#ifdef WSAEADDRINUSE + inscode(d, ds, de, "EADDRINUSE", WSAEADDRINUSE, "Address already in use"); +#endif +#endif +#ifdef EOPNOTSUPP + inscode(d, ds, de, "EOPNOTSUPP", EOPNOTSUPP, "Operation not supported on transport endpoint"); +#else +#ifdef WSAEOPNOTSUPP + inscode(d, ds, de, "EOPNOTSUPP", WSAEOPNOTSUPP, "Operation not supported on transport endpoint"); +#endif +#endif +#ifdef EREMCHG + inscode(d, ds, de, "EREMCHG", EREMCHG, "Remote address changed"); +#endif +#ifdef EAGAIN + inscode(d, ds, de, "EAGAIN", EAGAIN, "Try again"); +#endif +#ifdef ENAMETOOLONG + inscode(d, ds, de, "ENAMETOOLONG", ENAMETOOLONG, "File name too long"); +#else +#ifdef WSAENAMETOOLONG + inscode(d, ds, de, "ENAMETOOLONG", WSAENAMETOOLONG, "File name too long"); +#endif +#endif +#ifdef ENOTTY + inscode(d, ds, de, "ENOTTY", ENOTTY, "Not a typewriter"); +#endif +#ifdef ERESTART + inscode(d, ds, de, "ERESTART", ERESTART, "Interrupted system call should be restarted"); +#endif +#ifdef ESOCKTNOSUPPORT + inscode(d, ds, de, "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT, "Socket type not supported"); +#else +#ifdef WSAESOCKTNOSUPPORT + inscode(d, ds, de, "ESOCKTNOSUPPORT", WSAESOCKTNOSUPPORT, "Socket type not supported"); +#endif +#endif +#ifdef ETIME + inscode(d, ds, de, "ETIME", ETIME, "Timer expired"); +#endif +#ifdef EBFONT + inscode(d, ds, de, "EBFONT", EBFONT, "Bad font file format"); +#endif +#ifdef EDEADLOCK + inscode(d, ds, de, "EDEADLOCK", EDEADLOCK, "Error EDEADLOCK"); +#endif +#ifdef ETOOMANYREFS + inscode(d, ds, de, "ETOOMANYREFS", ETOOMANYREFS, "Too many references: cannot splice"); +#else +#ifdef WSAETOOMANYREFS + inscode(d, ds, de, "ETOOMANYREFS", WSAETOOMANYREFS, "Too many references: cannot splice"); +#endif +#endif +#ifdef EMFILE + inscode(d, ds, de, "EMFILE", EMFILE, "Too many open files"); +#else +#ifdef WSAEMFILE + inscode(d, ds, de, "EMFILE", WSAEMFILE, "Too many open files"); +#endif +#endif +#ifdef ETXTBSY + inscode(d, ds, de, "ETXTBSY", ETXTBSY, "Text file busy"); +#endif +#ifdef EINPROGRESS + inscode(d, ds, de, "EINPROGRESS", EINPROGRESS, "Operation now in progress"); +#else +#ifdef WSAEINPROGRESS + inscode(d, ds, de, "EINPROGRESS", WSAEINPROGRESS, "Operation now in progress"); +#endif +#endif +#ifdef ENXIO + inscode(d, ds, de, "ENXIO", ENXIO, "No such device or address"); +#endif +#ifdef ENOPKG + inscode(d, ds, de, "ENOPKG", ENOPKG, "Package not installed"); +#endif +#ifdef WSASY + inscode(d, ds, de, "WSASY", WSASY, "Error WSASY"); +#endif +#ifdef WSAEHOSTDOWN + inscode(d, ds, de, "WSAEHOSTDOWN", WSAEHOSTDOWN, "Host is down"); +#endif +#ifdef WSAENETDOWN + inscode(d, ds, de, "WSAENETDOWN", WSAENETDOWN, "Network is down"); +#endif +#ifdef WSAENOTSOCK + inscode(d, ds, de, "WSAENOTSOCK", WSAENOTSOCK, "Socket operation on non-socket"); +#endif +#ifdef WSAEHOSTUNREACH + inscode(d, ds, de, "WSAEHOSTUNREACH", WSAEHOSTUNREACH, "No route to host"); +#endif +#ifdef WSAELOOP + inscode(d, ds, de, "WSAELOOP", WSAELOOP, "Too many symbolic links encountered"); +#endif +#ifdef WSAEMFILE + inscode(d, ds, de, "WSAEMFILE", WSAEMFILE, "Too many open files"); +#endif +#ifdef WSAESTALE + inscode(d, ds, de, "WSAESTALE", WSAESTALE, "Stale NFS file handle"); +#endif +#ifdef WSAVERNOTSUPPORTED + inscode(d, ds, de, "WSAVERNOTSUPPORTED", WSAVERNOTSUPPORTED, "Error WSAVERNOTSUPPORTED"); +#endif +#ifdef WSAENETUNREACH + inscode(d, ds, de, "WSAENETUNREACH", WSAENETUNREACH, "Network is unreachable"); +#endif +#ifdef WSAEPROCLIM + inscode(d, ds, de, "WSAEPROCLIM", WSAEPROCLIM, "Error WSAEPROCLIM"); +#endif +#ifdef WSAEFAULT + inscode(d, ds, de, "WSAEFAULT", WSAEFAULT, "Bad address"); +#endif +#ifdef WSANOTINITIALISED + inscode(d, ds, de, "WSANOTINITIALISED", WSANOTINITIALISED, "Error WSANOTINITIALISED"); +#endif +#ifdef WSAEUSERS + inscode(d, ds, de, "WSAEUSERS", WSAEUSERS, "Too many users"); +#endif +#ifdef WSAMAKEASYNCREPL + inscode(d, ds, de, "WSAMAKEASYNCREPL", WSAMAKEASYNCREPL, "Error WSAMAKEASYNCREPL"); +#endif +#ifdef WSAENOPROTOOPT + inscode(d, ds, de, "WSAENOPROTOOPT", WSAENOPROTOOPT, "Protocol not available"); +#endif +#ifdef WSAECONNABORTED + inscode(d, ds, de, "WSAECONNABORTED", WSAECONNABORTED, "Software caused connection abort"); +#endif +#ifdef WSAENAMETOOLONG + inscode(d, ds, de, "WSAENAMETOOLONG", WSAENAMETOOLONG, "File name too long"); +#endif +#ifdef WSAENOTEMPTY + inscode(d, ds, de, "WSAENOTEMPTY", WSAENOTEMPTY, "Directory not empty"); +#endif +#ifdef WSAESHUTDOWN + inscode(d, ds, de, "WSAESHUTDOWN", WSAESHUTDOWN, "Cannot send after transport endpoint shutdown"); +#endif +#ifdef WSAEAFNOSUPPORT + inscode(d, ds, de, "WSAEAFNOSUPPORT", WSAEAFNOSUPPORT, "Address family not supported by protocol"); +#endif +#ifdef WSAETOOMANYREFS + inscode(d, ds, de, "WSAETOOMANYREFS", WSAETOOMANYREFS, "Too many references: cannot splice"); +#endif +#ifdef WSAEACCES + inscode(d, ds, de, "WSAEACCES", WSAEACCES, "Permission denied"); +#endif +#ifdef WSATR + inscode(d, ds, de, "WSATR", WSATR, "Error WSATR"); +#endif +#ifdef WSABASEERR + inscode(d, ds, de, "WSABASEERR", WSABASEERR, "Error WSABASEERR"); +#endif +#ifdef WSADESCRIPTIO + inscode(d, ds, de, "WSADESCRIPTIO", WSADESCRIPTIO, "Error WSADESCRIPTIO"); +#endif +#ifdef WSAEMSGSIZE + inscode(d, ds, de, "WSAEMSGSIZE", WSAEMSGSIZE, "Message too long"); +#endif +#ifdef WSAEBADF + inscode(d, ds, de, "WSAEBADF", WSAEBADF, "Bad file number"); +#endif +#ifdef WSAECONNRESET + inscode(d, ds, de, "WSAECONNRESET", WSAECONNRESET, "Connection reset by peer"); +#endif +#ifdef WSAGETSELECTERRO + inscode(d, ds, de, "WSAGETSELECTERRO", WSAGETSELECTERRO, "Error WSAGETSELECTERRO"); +#endif +#ifdef WSAETIMEDOUT + inscode(d, ds, de, "WSAETIMEDOUT", WSAETIMEDOUT, "Connection timed out"); +#endif +#ifdef WSAENOBUFS + inscode(d, ds, de, "WSAENOBUFS", WSAENOBUFS, "No buffer space available"); +#endif +#ifdef WSAEDISCON + inscode(d, ds, de, "WSAEDISCON", WSAEDISCON, "Error WSAEDISCON"); +#endif +#ifdef WSAEINTR + inscode(d, ds, de, "WSAEINTR", WSAEINTR, "Interrupted system call"); +#endif +#ifdef WSAEPROTOTYPE + inscode(d, ds, de, "WSAEPROTOTYPE", WSAEPROTOTYPE, "Protocol wrong type for socket"); +#endif +#ifdef WSAHOS + inscode(d, ds, de, "WSAHOS", WSAHOS, "Error WSAHOS"); +#endif +#ifdef WSAEADDRINUSE + inscode(d, ds, de, "WSAEADDRINUSE", WSAEADDRINUSE, "Address already in use"); +#endif +#ifdef WSAEADDRNOTAVAIL + inscode(d, ds, de, "WSAEADDRNOTAVAIL", WSAEADDRNOTAVAIL, "Cannot assign requested address"); +#endif +#ifdef WSAEALREADY + inscode(d, ds, de, "WSAEALREADY", WSAEALREADY, "Operation already in progress"); +#endif +#ifdef WSAEPROTONOSUPPORT + inscode(d, ds, de, "WSAEPROTONOSUPPORT", WSAEPROTONOSUPPORT, "Protocol not supported"); +#endif +#ifdef WSASYSNOTREADY + inscode(d, ds, de, "WSASYSNOTREADY", WSASYSNOTREADY, "Error WSASYSNOTREADY"); +#endif +#ifdef WSAEWOULDBLOCK + inscode(d, ds, de, "WSAEWOULDBLOCK", WSAEWOULDBLOCK, "Operation would block"); +#endif +#ifdef WSAEPFNOSUPPORT + inscode(d, ds, de, "WSAEPFNOSUPPORT", WSAEPFNOSUPPORT, "Protocol family not supported"); +#endif +#ifdef WSAEOPNOTSUPP + inscode(d, ds, de, "WSAEOPNOTSUPP", WSAEOPNOTSUPP, "Operation not supported on transport endpoint"); +#endif +#ifdef WSAEISCONN + inscode(d, ds, de, "WSAEISCONN", WSAEISCONN, "Transport endpoint is already connected"); +#endif +#ifdef WSAEDQUOT + inscode(d, ds, de, "WSAEDQUOT", WSAEDQUOT, "Quota exceeded"); +#endif +#ifdef WSAENOTCONN + inscode(d, ds, de, "WSAENOTCONN", WSAENOTCONN, "Transport endpoint is not connected"); +#endif +#ifdef WSAEREMOTE + inscode(d, ds, de, "WSAEREMOTE", WSAEREMOTE, "Object is remote"); +#endif +#ifdef WSAEINVAL + inscode(d, ds, de, "WSAEINVAL", WSAEINVAL, "Invalid argument"); +#endif +#ifdef WSAEINPROGRESS + inscode(d, ds, de, "WSAEINPROGRESS", WSAEINPROGRESS, "Operation now in progress"); +#endif +#ifdef WSAGETSELECTEVEN + inscode(d, ds, de, "WSAGETSELECTEVEN", WSAGETSELECTEVEN, "Error WSAGETSELECTEVEN"); +#endif +#ifdef WSAESOCKTNOSUPPORT + inscode(d, ds, de, "WSAESOCKTNOSUPPORT", WSAESOCKTNOSUPPORT, "Socket type not supported"); +#endif +#ifdef WSAGETASYNCERRO + inscode(d, ds, de, "WSAGETASYNCERRO", WSAGETASYNCERRO, "Error WSAGETASYNCERRO"); +#endif +#ifdef WSAMAKESELECTREPL + inscode(d, ds, de, "WSAMAKESELECTREPL", WSAMAKESELECTREPL, "Error WSAMAKESELECTREPL"); +#endif +#ifdef WSAGETASYNCBUFLE + inscode(d, ds, de, "WSAGETASYNCBUFLE", WSAGETASYNCBUFLE, "Error WSAGETASYNCBUFLE"); +#endif +#ifdef WSAEDESTADDRREQ + inscode(d, ds, de, "WSAEDESTADDRREQ", WSAEDESTADDRREQ, "Destination address required"); +#endif +#ifdef WSAECONNREFUSED + inscode(d, ds, de, "WSAECONNREFUSED", WSAECONNREFUSED, "Connection refused"); +#endif +#ifdef WSAENETRESET + inscode(d, ds, de, "WSAENETRESET", WSAENETRESET, "Network dropped connection because of reset"); +#endif +#ifdef WSAN + inscode(d, ds, de, "WSAN", WSAN, "Error WSAN"); +#endif + + Py_DECREF(de); +} diff --git a/sys/src/cmd/python/Modules/expat/amigaconfig.h b/sys/src/cmd/python/Modules/expat/amigaconfig.h new file mode 100644 index 000000000..6781a714a --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/amigaconfig.h @@ -0,0 +1,96 @@ +#ifndef AMIGACONFIG_H +#define AMIGACONFIG_H + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 4321 + +/* Define to 1 if you have the `bcopy' function. */ +#define HAVE_BCOPY 1 + +/* Define to 1 if you have the <check.h> header file. */ +#undef HAVE_CHECK_H + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the <stdint.h> header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "expat-bugs@mail.libexpat.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "expat" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "expat 1.95.8" + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.95.8" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* whether byteorder is bigendian */ +#define WORDS_BIGENDIAN + +/* Define to specify how much context to retain around the current parse + point. */ +#define XML_CONTEXT_BYTES 1024 + +/* Define to make parameter entity parsing functionality available. */ +#define XML_DTD + +/* Define to make XML Namespaces functionality available. */ +#define XML_NS + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `long' if <sys/types.h> does not define. */ +#undef off_t + +/* Define to `unsigned' if <sys/types.h> does not define. */ +#undef size_t + + +#endif /* AMIGACONFIG_H */ diff --git a/sys/src/cmd/python/Modules/expat/ascii.h b/sys/src/cmd/python/Modules/expat/ascii.h new file mode 100644 index 000000000..337e5bb7e --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/ascii.h @@ -0,0 +1,85 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#define ASCII_A 0x41 +#define ASCII_B 0x42 +#define ASCII_C 0x43 +#define ASCII_D 0x44 +#define ASCII_E 0x45 +#define ASCII_F 0x46 +#define ASCII_G 0x47 +#define ASCII_H 0x48 +#define ASCII_I 0x49 +#define ASCII_J 0x4A +#define ASCII_K 0x4B +#define ASCII_L 0x4C +#define ASCII_M 0x4D +#define ASCII_N 0x4E +#define ASCII_O 0x4F +#define ASCII_P 0x50 +#define ASCII_Q 0x51 +#define ASCII_R 0x52 +#define ASCII_S 0x53 +#define ASCII_T 0x54 +#define ASCII_U 0x55 +#define ASCII_V 0x56 +#define ASCII_W 0x57 +#define ASCII_X 0x58 +#define ASCII_Y 0x59 +#define ASCII_Z 0x5A + +#define ASCII_a 0x61 +#define ASCII_b 0x62 +#define ASCII_c 0x63 +#define ASCII_d 0x64 +#define ASCII_e 0x65 +#define ASCII_f 0x66 +#define ASCII_g 0x67 +#define ASCII_h 0x68 +#define ASCII_i 0x69 +#define ASCII_j 0x6A +#define ASCII_k 0x6B +#define ASCII_l 0x6C +#define ASCII_m 0x6D +#define ASCII_n 0x6E +#define ASCII_o 0x6F +#define ASCII_p 0x70 +#define ASCII_q 0x71 +#define ASCII_r 0x72 +#define ASCII_s 0x73 +#define ASCII_t 0x74 +#define ASCII_u 0x75 +#define ASCII_v 0x76 +#define ASCII_w 0x77 +#define ASCII_x 0x78 +#define ASCII_y 0x79 +#define ASCII_z 0x7A + +#define ASCII_0 0x30 +#define ASCII_1 0x31 +#define ASCII_2 0x32 +#define ASCII_3 0x33 +#define ASCII_4 0x34 +#define ASCII_5 0x35 +#define ASCII_6 0x36 +#define ASCII_7 0x37 +#define ASCII_8 0x38 +#define ASCII_9 0x39 + +#define ASCII_TAB 0x09 +#define ASCII_SPACE 0x20 +#define ASCII_EXCL 0x21 +#define ASCII_QUOT 0x22 +#define ASCII_AMP 0x26 +#define ASCII_APOS 0x27 +#define ASCII_MINUS 0x2D +#define ASCII_PERIOD 0x2E +#define ASCII_COLON 0x3A +#define ASCII_SEMI 0x3B +#define ASCII_LT 0x3C +#define ASCII_EQUALS 0x3D +#define ASCII_GT 0x3E +#define ASCII_LSQB 0x5B +#define ASCII_RSQB 0x5D +#define ASCII_UNDERSCORE 0x5F diff --git a/sys/src/cmd/python/Modules/expat/asciitab.h b/sys/src/cmd/python/Modules/expat/asciitab.h new file mode 100644 index 000000000..79a15c28c --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/asciitab.h @@ -0,0 +1,36 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/sys/src/cmd/python/Modules/expat/expat.h b/sys/src/cmd/python/Modules/expat/expat.h new file mode 100644 index 000000000..cf113eeaf --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/expat.h @@ -0,0 +1,1013 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_INCLUDED +#define Expat_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler +#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler +#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler +#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg +#endif + +#include <stdlib.h> +#include "expat_external.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct XML_ParserStruct; +typedef struct XML_ParserStruct *XML_Parser; + +/* Should this be defined using stdbool.h when C99 is available? */ +typedef unsigned char XML_Bool; +#define XML_TRUE ((XML_Bool) 1) +#define XML_FALSE ((XML_Bool) 0) + +/* The XML_Status enum gives the possible return values for several + API functions. The preprocessor #defines are included so this + stanza can be added to code that still needs to support older + versions of Expat 1.95.x: + + #ifndef XML_STATUS_OK + #define XML_STATUS_OK 1 + #define XML_STATUS_ERROR 0 + #endif + + Otherwise, the #define hackery is quite ugly and would have been + dropped. +*/ +enum XML_Status { + XML_STATUS_ERROR = 0, +#define XML_STATUS_ERROR XML_STATUS_ERROR + XML_STATUS_OK = 1, +#define XML_STATUS_OK XML_STATUS_OK + XML_STATUS_SUSPENDED = 2 +#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED +}; + +enum XML_Error { + XML_ERROR_NONE, + XML_ERROR_NO_MEMORY, + XML_ERROR_SYNTAX, + XML_ERROR_NO_ELEMENTS, + XML_ERROR_INVALID_TOKEN, + XML_ERROR_UNCLOSED_TOKEN, + XML_ERROR_PARTIAL_CHAR, + XML_ERROR_TAG_MISMATCH, + XML_ERROR_DUPLICATE_ATTRIBUTE, + XML_ERROR_JUNK_AFTER_DOC_ELEMENT, + XML_ERROR_PARAM_ENTITY_REF, + XML_ERROR_UNDEFINED_ENTITY, + XML_ERROR_RECURSIVE_ENTITY_REF, + XML_ERROR_ASYNC_ENTITY, + XML_ERROR_BAD_CHAR_REF, + XML_ERROR_BINARY_ENTITY_REF, + XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, + XML_ERROR_MISPLACED_XML_PI, + XML_ERROR_UNKNOWN_ENCODING, + XML_ERROR_INCORRECT_ENCODING, + XML_ERROR_UNCLOSED_CDATA_SECTION, + XML_ERROR_EXTERNAL_ENTITY_HANDLING, + XML_ERROR_NOT_STANDALONE, + XML_ERROR_UNEXPECTED_STATE, + XML_ERROR_ENTITY_DECLARED_IN_PE, + XML_ERROR_FEATURE_REQUIRES_XML_DTD, + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING, + /* Added in 1.95.7. */ + XML_ERROR_UNBOUND_PREFIX, + /* Added in 1.95.8. */ + XML_ERROR_UNDECLARING_PREFIX, + XML_ERROR_INCOMPLETE_PE, + XML_ERROR_XML_DECL, + XML_ERROR_TEXT_DECL, + XML_ERROR_PUBLICID, + XML_ERROR_SUSPENDED, + XML_ERROR_NOT_SUSPENDED, + XML_ERROR_ABORTED, + XML_ERROR_FINISHED, + XML_ERROR_SUSPEND_PE, + /* Added in 2.0. */ + XML_ERROR_RESERVED_PREFIX_XML, + XML_ERROR_RESERVED_PREFIX_XMLNS, + XML_ERROR_RESERVED_NAMESPACE_URI +}; + +enum XML_Content_Type { + XML_CTYPE_EMPTY = 1, + XML_CTYPE_ANY, + XML_CTYPE_MIXED, + XML_CTYPE_NAME, + XML_CTYPE_CHOICE, + XML_CTYPE_SEQ +}; + +enum XML_Content_Quant { + XML_CQUANT_NONE, + XML_CQUANT_OPT, + XML_CQUANT_REP, + XML_CQUANT_PLUS +}; + +/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be + XML_CQUANT_NONE, and the other fields will be zero or NULL. + If type == XML_CTYPE_MIXED, then quant will be NONE or REP and + numchildren will contain number of elements that may be mixed in + and children point to an array of XML_Content cells that will be + all of XML_CTYPE_NAME type with no quantification. + + If type == XML_CTYPE_NAME, then the name points to the name, and + the numchildren field will be zero and children will be NULL. The + quant fields indicates any quantifiers placed on the name. + + CHOICE and SEQ will have name NULL, the number of children in + numchildren and children will point, recursively, to an array + of XML_Content cells. + + The EMPTY, ANY, and MIXED types will only occur at top level. +*/ + +typedef struct XML_cp XML_Content; + +struct XML_cp { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + XML_Char * name; + unsigned int numchildren; + XML_Content * children; +}; + + +/* This is called for an element declaration. See above for + description of the model argument. It's the caller's responsibility + to free model when finished with it. +*/ +typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData, + const XML_Char *name, + XML_Content *model); + +XMLPARSEAPI(void) +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl); + +/* The Attlist declaration handler is called for *each* attribute. So + a single Attlist declaration with multiple attributes declared will + generate multiple calls to this handler. The "default" parameter + may be NULL in the case of the "#IMPLIED" or "#REQUIRED" + keyword. The "isrequired" parameter will be true and the default + value will be NULL in the case of "#REQUIRED". If "isrequired" is + true and default is non-NULL, then this is a "#FIXED" default. +*/ +typedef void (XMLCALL *XML_AttlistDeclHandler) ( + void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired); + +XMLPARSEAPI(void) +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl); + +/* The XML declaration handler is called for *both* XML declarations + and text declarations. The way to distinguish is that the version + parameter will be NULL for text declarations. The encoding + parameter may be NULL for XML declarations. The standalone + parameter will be -1, 0, or 1 indicating respectively that there + was no standalone parameter in the declaration, that it was given + as no, or that it was given as yes. +*/ +typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone); + +XMLPARSEAPI(void) +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler xmldecl); + + +typedef struct { + void *(*malloc_fcn)(size_t size); + void *(*realloc_fcn)(void *ptr, size_t size); + void (*free_fcn)(void *ptr); +} XML_Memory_Handling_Suite; + +/* Constructs a new parser; encoding is the encoding specified by the + external protocol or NULL if there is none specified. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate(const XML_Char *encoding); + +/* Constructs a new parser and namespace processor. Element type + names and attribute names that belong to a namespace will be + expanded; unprefixed attribute names are never expanded; unprefixed + element type names are expanded only if there is a default + namespace. The expanded name is the concatenation of the namespace + URI, the namespace separator character, and the local part of the + name. If the namespace separator is '\0' then the namespace URI + and the local part will be concatenated without any separator. + It is a programming error to use the separator '\0' with namespace + triplets (see XML_SetReturnNSTriplet). +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator); + + +/* Constructs a new parser using the memory management suite referred to + by memsuite. If memsuite is NULL, then use the standard library memory + suite. If namespaceSeparator is non-NULL it creates a parser with + namespace processing as described above. The character pointed at + will serve as the namespace separator. + + All further memory operations used for the created parser will come from + the given suite. +*/ +XMLPARSEAPI(XML_Parser) +XML_ParserCreate_MM(const XML_Char *encoding, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *namespaceSeparator); + +/* Prepare a parser object to be re-used. This is particularly + valuable when memory allocation overhead is disproportionatly high, + such as when a large number of small documnents need to be parsed. + All handlers are cleared from the parser, except for the + unknownEncodingHandler. The parser's external state is re-initialized + except for the values of ns and ns_triplets. + + Added in Expat 1.95.3. +*/ +XMLPARSEAPI(XML_Bool) +XML_ParserReset(XML_Parser parser, const XML_Char *encoding); + +/* atts is array of name/value pairs, terminated by 0; + names and values are 0 terminated. +*/ +typedef void (XMLCALL *XML_StartElementHandler) (void *userData, + const XML_Char *name, + const XML_Char **atts); + +typedef void (XMLCALL *XML_EndElementHandler) (void *userData, + const XML_Char *name); + + +/* s is not 0 terminated. */ +typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData, + const XML_Char *s, + int len); + +/* target and data are 0 terminated */ +typedef void (XMLCALL *XML_ProcessingInstructionHandler) ( + void *userData, + const XML_Char *target, + const XML_Char *data); + +/* data is 0 terminated */ +typedef void (XMLCALL *XML_CommentHandler) (void *userData, + const XML_Char *data); + +typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData); +typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData); + +/* This is called for any characters in the XML document for which + there is no applicable handler. This includes both characters that + are part of markup which is of a kind that is not reported + (comments, markup declarations), or characters that are part of a + construct which could be reported but for which no handler has been + supplied. The characters are passed exactly as they were in the XML + document except that they will be encoded in UTF-8 or UTF-16. + Line boundaries are not normalized. Note that a byte order mark + character is not passed to the default handler. There are no + guarantees about how characters are divided between calls to the + default handler: for example, a comment might be split between + multiple calls. +*/ +typedef void (XMLCALL *XML_DefaultHandler) (void *userData, + const XML_Char *s, + int len); + +/* This is called for the start of the DOCTYPE declaration, before + any DTD or internal subset is parsed. +*/ +typedef void (XMLCALL *XML_StartDoctypeDeclHandler) ( + void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset); + +/* This is called for the start of the DOCTYPE declaration when the + closing > is encountered, but after processing any external + subset. +*/ +typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData); + +/* This is called for entity declarations. The is_parameter_entity + argument will be non-zero if the entity is a parameter entity, zero + otherwise. + + For internal entities (<!ENTITY foo "bar">), value will + be non-NULL and systemId, publicID, and notationName will be NULL. + The value string is NOT nul-terminated; the length is provided in + the value_length argument. Since it is legal to have zero-length + values, do not use this argument to test for internal entities. + + For external entities, value will be NULL and systemId will be + non-NULL. The publicId argument will be NULL unless a public + identifier was provided. The notationName argument will have a + non-NULL value only for unparsed entity declarations. + + Note that is_parameter_entity can't be changed to XML_Bool, since + that would break binary compatibility. +*/ +typedef void (XMLCALL *XML_EntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +XMLPARSEAPI(void) +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler); + +/* OBSOLETE -- OBSOLETE -- OBSOLETE + This handler has been superceded by the EntityDeclHandler above. + It is provided here for backward compatibility. + + This is called for a declaration of an unparsed (NDATA) entity. + The base argument is whatever was set by XML_SetBase. The + entityName, systemId and notationName arguments will never be + NULL. The other arguments may be. +*/ +typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) ( + void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName); + +/* This is called for a declaration of notation. The base argument is + whatever was set by XML_SetBase. The notationName will never be + NULL. The other arguments can be. +*/ +typedef void (XMLCALL *XML_NotationDeclHandler) ( + void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* When namespace processing is enabled, these are called once for + each namespace declaration. The call to the start and end element + handlers occur between the calls to the start and end namespace + declaration handlers. For an xmlns attribute, prefix will be + NULL. For an xmlns="" attribute, uri will be NULL. +*/ +typedef void (XMLCALL *XML_StartNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix, + const XML_Char *uri); + +typedef void (XMLCALL *XML_EndNamespaceDeclHandler) ( + void *userData, + const XML_Char *prefix); + +/* This is called if the document is not standalone, that is, it has an + external subset or a reference to a parameter entity, but does not + have standalone="yes". If this handler returns XML_STATUS_ERROR, + then processing will not continue, and the parser will return a + XML_ERROR_NOT_STANDALONE error. + If parameter entity parsing is enabled, then in addition to the + conditions above this handler will only be called if the referenced + entity was actually read. +*/ +typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData); + +/* This is called for a reference to an external parsed general + entity. The referenced entity is not automatically parsed. The + application can parse it immediately or later using + XML_ExternalEntityParserCreate. + + The parser argument is the parser parsing the entity containing the + reference; it can be passed as the parser argument to + XML_ExternalEntityParserCreate. The systemId argument is the + system identifier as specified in the entity declaration; it will + not be NULL. + + The base argument is the system identifier that should be used as + the base for resolving systemId if systemId was relative; this is + set by XML_SetBase; it may be NULL. + + The publicId argument is the public identifier as specified in the + entity declaration, or NULL if none was specified; the whitespace + in the public identifier will have been normalized as required by + the XML spec. + + The context argument specifies the parsing context in the format + expected by the context argument to XML_ExternalEntityParserCreate; + context is valid only until the handler returns, so if the + referenced entity is to be parsed later, it must be copied. + context is NULL only when the entity is a parameter entity. + + The handler should return XML_STATUS_ERROR if processing should not + continue because of a fatal error in the handling of the external + entity. In this case the calling parser will return an + XML_ERROR_EXTERNAL_ENTITY_HANDLING error. + + Note that unlike other handlers the first argument is the parser, + not userData. +*/ +typedef int (XMLCALL *XML_ExternalEntityRefHandler) ( + XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId); + +/* This is called in two situations: + 1) An entity reference is encountered for which no declaration + has been read *and* this is not an error. + 2) An internal entity reference is read, but not expanded, because + XML_SetDefaultHandler has been called. + Note: skipped parameter entities in declarations and skipped general + entities in attribute values cannot be reported, because + the event would be out of sync with the reporting of the + declarations or attribute values +*/ +typedef void (XMLCALL *XML_SkippedEntityHandler) ( + void *userData, + const XML_Char *entityName, + int is_parameter_entity); + +/* This structure is filled in by the XML_UnknownEncodingHandler to + provide information to the parser about encodings that are unknown + to the parser. + + The map[b] member gives information about byte sequences whose + first byte is b. + + If map[b] is c where c is >= 0, then b by itself encodes the + Unicode scalar value c. + + If map[b] is -1, then the byte sequence is malformed. + + If map[b] is -n, where n >= 2, then b is the first byte of an + n-byte sequence that encodes a single Unicode scalar value. + + The data member will be passed as the first argument to the convert + function. + + The convert function is used to convert multibyte sequences; s will + point to a n-byte sequence where map[(unsigned char)*s] == -n. The + convert function must return the Unicode scalar value represented + by this byte sequence or -1 if the byte sequence is malformed. + + The convert function may be NULL if the encoding is a single-byte + encoding, that is if map[b] >= -1 for all bytes b. + + When the parser is finished with the encoding, then if release is + not NULL, it will call release passing it the data member; once + release has been called, the convert function will not be called + again. + + Expat places certain restrictions on the encodings that are supported + using this mechanism. + + 1. Every ASCII character that can appear in a well-formed XML document, + other than the characters + + $@\^`{}~ + + must be represented by a single byte, and that byte must be the + same byte that represents that character in ASCII. + + 2. No character may require more than 4 bytes to encode. + + 3. All characters encoded must have Unicode scalar values <= + 0xFFFF, (i.e., characters that would be encoded by surrogates in + UTF-16 are not allowed). Note that this restriction doesn't + apply to the built-in support for UTF-8 and UTF-16. + + 4. No Unicode character may be encoded by more than one distinct + sequence of bytes. +*/ +typedef struct { + int map[256]; + void *data; + int (XMLCALL *convert)(void *data, const char *s); + void (XMLCALL *release)(void *data); +} XML_Encoding; + +/* This is called for an encoding that is unknown to the parser. + + The encodingHandlerData argument is that which was passed as the + second argument to XML_SetUnknownEncodingHandler. + + The name argument gives the name of the encoding as specified in + the encoding declaration. + + If the callback can provide information about the encoding, it must + fill in the XML_Encoding structure, and return XML_STATUS_OK. + Otherwise it must return XML_STATUS_ERROR. + + If info does not describe a suitable encoding, then the parser will + return an XML_UNKNOWN_ENCODING error. +*/ +typedef int (XMLCALL *XML_UnknownEncodingHandler) ( + void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info); + +XMLPARSEAPI(void) +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end); + +XMLPARSEAPI(void) +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler handler); + +XMLPARSEAPI(void) +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler handler); + +XMLPARSEAPI(void) +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler); + +XMLPARSEAPI(void) +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler); +XMLPARSEAPI(void) +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler); + +XMLPARSEAPI(void) +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end); + +XMLPARSEAPI(void) +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start); + +XMLPARSEAPI(void) +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end); + +/* This sets the default handler and also inhibits expansion of + internal entities. These entity references will be passed to the + default handler, or to the skipped entity handler, if one is set. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler); + +/* This sets the default handler but does not inhibit expansion of + internal entities. The entity reference will not be passed to the + default handler. +*/ +XMLPARSEAPI(void) +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler); + +XMLPARSEAPI(void) +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end); + +XMLPARSEAPI(void) +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler); + +XMLPARSEAPI(void) +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start); + +XMLPARSEAPI(void) +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end); + +XMLPARSEAPI(void) +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler); + +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler); + +/* If a non-NULL value for arg is specified here, then it will be + passed as the first argument to the external entity ref handler + instead of the parser object. +*/ +XMLPARSEAPI(void) +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, + void *arg); + +XMLPARSEAPI(void) +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler); + +XMLPARSEAPI(void) +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *encodingHandlerData); + +/* This can be called within a handler for a start element, end + element, processing instruction or character data. It causes the + corresponding markup to be passed to the default handler. +*/ +XMLPARSEAPI(void) +XML_DefaultCurrent(XML_Parser parser); + +/* If do_nst is non-zero, and namespace processing is in effect, and + a name has a prefix (i.e. an explicit namespace qualifier) then + that name is returned as a triplet in a single string separated by + the separator character specified when the parser was created: URI + + sep + local_name + sep + prefix. + + If do_nst is zero, then namespace information is returned in the + default manner (URI + sep + local_name) whether or not the name + has a prefix. + + Note: Calling XML_SetReturnNSTriplet after XML_Parse or + XML_ParseBuffer has no effect. +*/ + +XMLPARSEAPI(void) +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst); + +/* This value is passed as the userData argument to callbacks. */ +XMLPARSEAPI(void) +XML_SetUserData(XML_Parser parser, void *userData); + +/* Returns the last value set by XML_SetUserData or NULL. */ +#define XML_GetUserData(parser) (*(void **)(parser)) + +/* This is equivalent to supplying an encoding argument to + XML_ParserCreate. On success XML_SetEncoding returns non-zero, + zero otherwise. + Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer + has no effect and returns XML_STATUS_ERROR. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetEncoding(XML_Parser parser, const XML_Char *encoding); + +/* If this function is called, then the parser will be passed as the + first argument to callbacks instead of userData. The userData will + still be accessible using XML_GetUserData. +*/ +XMLPARSEAPI(void) +XML_UseParserAsHandlerArg(XML_Parser parser); + +/* If useDTD == XML_TRUE is passed to this function, then the parser + will assume that there is an external subset, even if none is + specified in the document. In such a case the parser will call the + externalEntityRefHandler with a value of NULL for the systemId + argument (the publicId and context arguments will be NULL as well). + Note: For the purpose of checking WFC: Entity Declared, passing + useDTD == XML_TRUE will make the parser behave as if the document + had a DTD with an external subset. + Note: If this function is called, then this must be done before + the first call to XML_Parse or XML_ParseBuffer, since it will + have no effect after that. Returns + XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING. + Note: If the document does not have a DOCTYPE declaration at all, + then startDoctypeDeclHandler and endDoctypeDeclHandler will not + be called, despite an external subset being parsed. + Note: If XML_DTD is not defined when Expat is compiled, returns + XML_ERROR_FEATURE_REQUIRES_XML_DTD. +*/ +XMLPARSEAPI(enum XML_Error) +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD); + + +/* Sets the base to be used for resolving relative URIs in system + identifiers in declarations. Resolving relative identifiers is + left to the application: this value will be passed through as the + base argument to the XML_ExternalEntityRefHandler, + XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base + argument will be copied. Returns XML_STATUS_ERROR if out of memory, + XML_STATUS_OK otherwise. +*/ +XMLPARSEAPI(enum XML_Status) +XML_SetBase(XML_Parser parser, const XML_Char *base); + +XMLPARSEAPI(const XML_Char *) +XML_GetBase(XML_Parser parser); + +/* Returns the number of the attribute/value pairs passed in last call + to the XML_StartElementHandler that were specified in the start-tag + rather than defaulted. Each attribute/value pair counts as 2; thus + this correspondds to an index into the atts array passed to the + XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetSpecifiedAttributeCount(XML_Parser parser); + +/* Returns the index of the ID attribute passed in the last call to + XML_StartElementHandler, or -1 if there is no ID attribute. Each + attribute/value pair counts as 2; thus this correspondds to an + index into the atts array passed to the XML_StartElementHandler. +*/ +XMLPARSEAPI(int) +XML_GetIdAttributeIndex(XML_Parser parser); + +/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is + detected. The last call to XML_Parse must have isFinal true; len + may be zero for this call (or any other). + + Though the return values for these functions has always been + described as a Boolean value, the implementation, at least for the + 1.95.x series, has always returned exactly one of the XML_Status + values. +*/ +XMLPARSEAPI(enum XML_Status) +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal); + +XMLPARSEAPI(void *) +XML_GetBuffer(XML_Parser parser, int len); + +XMLPARSEAPI(enum XML_Status) +XML_ParseBuffer(XML_Parser parser, int len, int isFinal); + +/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return. + Must be called from within a call-back handler, except when aborting + (resumable = 0) an already suspended parser. Some call-backs may + still follow because they would otherwise get lost. Examples: + - endElementHandler() for empty elements when stopped in + startElementHandler(), + - endNameSpaceDeclHandler() when stopped in endElementHandler(), + and possibly others. + + Can be called from most handlers, including DTD related call-backs, + except when parsing an external parameter entity and resumable != 0. + Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise. + Possible error codes: + - XML_ERROR_SUSPENDED: when suspending an already suspended parser. + - XML_ERROR_FINISHED: when the parser has already finished. + - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE. + + When resumable != 0 (true) then parsing is suspended, that is, + XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED. + Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer() + return XML_STATUS_ERROR with error code XML_ERROR_ABORTED. + + *Note*: + This will be applied to the current parser instance only, that is, if + there is a parent parser then it will continue parsing when the + externalEntityRefHandler() returns. It is up to the implementation of + the externalEntityRefHandler() to call XML_StopParser() on the parent + parser (recursively), if one wants to stop parsing altogether. + + When suspended, parsing can be resumed by calling XML_ResumeParser(). +*/ +XMLPARSEAPI(enum XML_Status) +XML_StopParser(XML_Parser parser, XML_Bool resumable); + +/* Resumes parsing after it has been suspended with XML_StopParser(). + Must not be called from within a handler call-back. Returns same + status codes as XML_Parse() or XML_ParseBuffer(). + Additional error code XML_ERROR_NOT_SUSPENDED possible. + + *Note*: + This must be called on the most deeply nested child parser instance + first, and on its parent parser only after the child parser has finished, + to be applied recursively until the document entity's parser is restarted. + That is, the parent parser will not resume by itself and it is up to the + application to call XML_ResumeParser() on it at the appropriate moment. +*/ +XMLPARSEAPI(enum XML_Status) +XML_ResumeParser(XML_Parser parser); + +enum XML_Parsing { + XML_INITIALIZED, + XML_PARSING, + XML_FINISHED, + XML_SUSPENDED +}; + +typedef struct { + enum XML_Parsing parsing; + XML_Bool finalBuffer; +} XML_ParsingStatus; + +/* Returns status of parser with respect to being initialized, parsing, + finished, or suspended and processing the final buffer. + XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus, + XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED +*/ +XMLPARSEAPI(void) +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status); + +/* Creates an XML_Parser object that can parse an external general + entity; context is a '\0'-terminated string specifying the parse + context; encoding is a '\0'-terminated string giving the name of + the externally specified encoding, or NULL if there is no + externally specified encoding. The context string consists of a + sequence of tokens separated by formfeeds (\f); a token consisting + of a name specifies that the general entity of the name is open; a + token of the form prefix=uri specifies the namespace for a + particular prefix; a token of the form =uri specifies the default + namespace. This can be called at any point after the first call to + an ExternalEntityRefHandler so longer as the parser has not yet + been freed. The new parser is completely independent and may + safely be used in a separate thread. The handlers and userData are + initialized from the parser argument. Returns NULL if out of memory. + Otherwise returns a new XML_Parser object. +*/ +XMLPARSEAPI(XML_Parser) +XML_ExternalEntityParserCreate(XML_Parser parser, + const XML_Char *context, + const XML_Char *encoding); + +enum XML_ParamEntityParsing { + XML_PARAM_ENTITY_PARSING_NEVER, + XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE, + XML_PARAM_ENTITY_PARSING_ALWAYS +}; + +/* Controls parsing of parameter entities (including the external DTD + subset). If parsing of parameter entities is enabled, then + references to external parameter entities (including the external + DTD subset) will be passed to the handler set with + XML_SetExternalEntityRefHandler. The context passed will be 0. + + Unlike external general entities, external parameter entities can + only be parsed synchronously. If the external parameter entity is + to be parsed, it must be parsed during the call to the external + entity ref handler: the complete sequence of + XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and + XML_ParserFree calls must be made during this call. After + XML_ExternalEntityParserCreate has been called to create the parser + for the external parameter entity (context must be 0 for this + call), it is illegal to make any calls on the old parser until + XML_ParserFree has been called on the newly created parser. + If the library has been compiled without support for parameter + entity parsing (ie without XML_DTD being defined), then + XML_SetParamEntityParsing will return 0 if parsing of parameter + entities is requested; otherwise it will return non-zero. + Note: If XML_SetParamEntityParsing is called after XML_Parse or + XML_ParseBuffer, then it has no effect and will always return 0. +*/ +XMLPARSEAPI(int) +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing parsing); + +/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then + XML_GetErrorCode returns information about the error. +*/ +XMLPARSEAPI(enum XML_Error) +XML_GetErrorCode(XML_Parser parser); + +/* These functions return information about the current parse + location. They may be called from any callback called to report + some parse event; in this case the location is the location of the + first of the sequence of characters that generated the event. When + called from callbacks generated by declarations in the document + prologue, the location identified isn't as neatly defined, but will + be within the relevant markup. When called outside of the callback + functions, the position indicated will be just past the last parse + event (regardless of whether there was an associated callback). + + They may also be called after returning from a call to XML_Parse + or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then + the location is the location of the character at which the error + was detected; otherwise the location is the location of the last + parse event, as described above. +*/ +XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser); +XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser); +XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser); + +/* Return the number of bytes in the current event. + Returns 0 if the event is in an internal entity. +*/ +XMLPARSEAPI(int) +XML_GetCurrentByteCount(XML_Parser parser); + +/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets + the integer pointed to by offset to the offset within this buffer + of the current parse position, and sets the integer pointed to by size + to the size of this buffer (the number of input bytes). Otherwise + returns a NULL pointer. Also returns a NULL pointer if a parse isn't + active. + + NOTE: The character pointer returned should not be used outside + the handler that makes the call. +*/ +XMLPARSEAPI(const char *) +XML_GetInputContext(XML_Parser parser, + int *offset, + int *size); + +/* For backwards compatibility with previous versions. */ +#define XML_GetErrorLineNumber XML_GetCurrentLineNumber +#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber +#define XML_GetErrorByteIndex XML_GetCurrentByteIndex + +/* Frees the content model passed to the element declaration handler */ +XMLPARSEAPI(void) +XML_FreeContentModel(XML_Parser parser, XML_Content *model); + +/* Exposing the memory handling functions used in Expat */ +XMLPARSEAPI(void *) +XML_MemMalloc(XML_Parser parser, size_t size); + +XMLPARSEAPI(void *) +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size); + +XMLPARSEAPI(void) +XML_MemFree(XML_Parser parser, void *ptr); + +/* Frees memory used by the parser. */ +XMLPARSEAPI(void) +XML_ParserFree(XML_Parser parser); + +/* Returns a string describing the error. */ +XMLPARSEAPI(const XML_LChar *) +XML_ErrorString(enum XML_Error code); + +/* Return a string containing the version number of this expat */ +XMLPARSEAPI(const XML_LChar *) +XML_ExpatVersion(void); + +typedef struct { + int major; + int minor; + int micro; +} XML_Expat_Version; + +/* Return an XML_Expat_Version structure containing numeric version + number information for this version of expat. +*/ +XMLPARSEAPI(XML_Expat_Version) +XML_ExpatVersionInfo(void); + +/* Added in Expat 1.95.5. */ +enum XML_FeatureEnum { + XML_FEATURE_END = 0, + XML_FEATURE_UNICODE, + XML_FEATURE_UNICODE_WCHAR_T, + XML_FEATURE_DTD, + XML_FEATURE_CONTEXT_BYTES, + XML_FEATURE_MIN_SIZE, + XML_FEATURE_SIZEOF_XML_CHAR, + XML_FEATURE_SIZEOF_XML_LCHAR, + XML_FEATURE_NS + /* Additional features must be added to the end of this enum. */ +}; + +typedef struct { + enum XML_FeatureEnum feature; + const XML_LChar *name; + long int value; +} XML_Feature; + +XMLPARSEAPI(const XML_Feature *) +XML_GetFeatureList(void); + + +/* Expat follows the GNU/Linux convention of odd number minor version for + beta/development releases and even number minor version for stable + releases. Micro is bumped with each release, and set to 0 with each + change to major or minor version. +*/ +#define XML_MAJOR_VERSION 2 +#define XML_MINOR_VERSION 0 +#define XML_MICRO_VERSION 0 + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_INCLUDED */ diff --git a/sys/src/cmd/python/Modules/expat/expat_config.h b/sys/src/cmd/python/Modules/expat/expat_config.h new file mode 100644 index 000000000..b8c1639b9 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/expat_config.h @@ -0,0 +1,19 @@ +/* + * Expat configuration for python. This file is not part of the expat + * distribution. + */ +#ifndef EXPAT_CONFIG_H +#define EXPAT_CONFIG_H + +#include <pyconfig.h> +#ifdef WORDS_BIGENDIAN +#define BYTEORDER 4321 +#else +#define BYTEORDER 1234 +#endif + +#define XML_NS 1 +#define XML_DTD 1 +#define XML_CONTEXT_BYTES 1024 + +#endif /* EXPAT_CONFIG_H */ diff --git a/sys/src/cmd/python/Modules/expat/expat_external.h b/sys/src/cmd/python/Modules/expat/expat_external.h new file mode 100644 index 000000000..f05401419 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/expat_external.h @@ -0,0 +1,119 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef Expat_External_INCLUDED +#define Expat_External_INCLUDED 1 + +/* External API definitions */ + +/* Namespace external symbols to allow multiple libexpat version to + co-exist. */ +#include "pyexpatns.h" + +#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__) +#define XML_USE_MSC_EXTENSIONS 1 +#endif + +/* Expat tries very hard to make the API boundary very specifically + defined. There are two macros defined to control this boundary; + each of these can be defined before including this header to + achieve some different behavior, but doing so it not recommended or + tested frequently. + + XMLCALL - The calling convention to use for all calls across the + "library boundary." This will default to cdecl, and + try really hard to tell the compiler that's what we + want. + + XMLIMPORT - Whatever magic is needed to note that a function is + to be imported from a dynamically loaded library + (.dll, .so, or .sl, depending on your platform). + + The XMLCALL macro was added in Expat 1.95.7. The only one which is + expected to be directly useful in client code is XMLCALL. + + Note that on at least some Unix versions, the Expat library must be + compiled with the cdecl calling convention as the default since + system headers may assume the cdecl convention. +*/ +#ifndef XMLCALL +#if defined(XML_USE_MSC_EXTENSIONS) +#define XMLCALL __cdecl +#elif defined(__GNUC__) && defined(__i386) +#define XMLCALL __attribute__((cdecl)) +#else +/* For any platform which uses this definition and supports more than + one calling convention, we need to extend this definition to + declare the convention used on that platform, if it's possible to + do so. + + If this is the case for your platform, please file a bug report + with information on how to identify your platform via the C + pre-processor and how to specify the same calling convention as the + platform's malloc() implementation. +*/ +#define XMLCALL +#endif +#endif /* not defined XMLCALL */ + + +#if !defined(XML_STATIC) && !defined(XMLIMPORT) +#ifndef XML_BUILDING_EXPAT +/* using Expat from an application */ + +#ifdef XML_USE_MSC_EXTENSIONS +#define XMLIMPORT __declspec(dllimport) +#endif + +#endif +#endif /* not defined XML_STATIC */ + + +/* If we didn't define it above, define it away: */ +#ifndef XMLIMPORT +#define XMLIMPORT +#endif + + +#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef XML_UNICODE_WCHAR_T +#define XML_UNICODE +#endif + +#ifdef XML_UNICODE /* Information is UTF-16 encoded. */ +#ifdef XML_UNICODE_WCHAR_T +typedef wchar_t XML_Char; +typedef wchar_t XML_LChar; +#else +typedef unsigned short XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE_WCHAR_T */ +#else /* Information is UTF-8 encoded. */ +typedef char XML_Char; +typedef char XML_LChar; +#endif /* XML_UNICODE */ + +#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */ +#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400 +typedef __int64 XML_Index; +typedef unsigned __int64 XML_Size; +#else +typedef long long XML_Index; +typedef unsigned long long XML_Size; +#endif +#else +typedef long XML_Index; +typedef unsigned long XML_Size; +#endif /* XML_LARGE_SIZE */ + +#ifdef __cplusplus +} +#endif + +#endif /* not Expat_External_INCLUDED */ diff --git a/sys/src/cmd/python/Modules/expat/iasciitab.h b/sys/src/cmd/python/Modules/expat/iasciitab.h new file mode 100644 index 000000000..24a1d5ccc --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/iasciitab.h @@ -0,0 +1,37 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */ +/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML, +/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML, +/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM, +/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS, +/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS, +/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL, +/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT, +/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI, +/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST, +/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB, +/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT, +/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX, +/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT, +/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER, diff --git a/sys/src/cmd/python/Modules/expat/internal.h b/sys/src/cmd/python/Modules/expat/internal.h new file mode 100644 index 000000000..ff056c659 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/internal.h @@ -0,0 +1,73 @@ +/* internal.h + + Internal definitions used by Expat. This is not needed to compile + client code. + + The following calling convention macros are defined for frequently + called functions: + + FASTCALL - Used for those internal functions that have a simple + body and a low number of arguments and local variables. + + PTRCALL - Used for functions called though function pointers. + + PTRFASTCALL - Like PTRCALL, but for low number of arguments. + + inline - Used for selected internal functions for which inlining + may improve performance on some platforms. + + Note: Use of these macros is based on judgement, not hard rules, + and therefore subject to change. +*/ + +#if defined(__GNUC__) && defined(__i386__) +/* We'll use this version by default only where we know it helps. + + regparm() generates warnings on Solaris boxes. See SF bug #692878. + + Instability reported with egcs on a RedHat Linux 7.3. + Let's comment out: + #define FASTCALL __attribute__((stdcall, regparm(3))) + and let's try this: +*/ +#define FASTCALL __attribute__((regparm(3))) +#define PTRFASTCALL __attribute__((regparm(3))) +#endif + +/* Using __fastcall seems to have an unexpected negative effect under + MS VC++, especially for function pointers, so we won't use it for + now on that platform. It may be reconsidered for a future release + if it can be made more effective. + Likely reason: __fastcall on Windows is like stdcall, therefore + the compiler cannot perform stack optimizations for call clusters. +*/ + +/* Make sure all of these are defined if they aren't already. */ + +#ifndef FASTCALL +#define FASTCALL +#endif + +#ifndef PTRCALL +#define PTRCALL +#endif + +#ifndef PTRFASTCALL +#define PTRFASTCALL +#endif + +#ifndef XML_MIN_SIZE +#if !defined(__cplusplus) && !defined(inline) +#ifdef __GNUC__ +#define inline __inline +#endif /* __GNUC__ */ +#endif +#endif /* XML_MIN_SIZE */ + +#ifdef __cplusplus +#define inline inline +#else +#ifndef inline +#define inline +#endif +#endif diff --git a/sys/src/cmd/python/Modules/expat/latin1tab.h b/sys/src/cmd/python/Modules/expat/latin1tab.h new file mode 100644 index 000000000..53c25d76b --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/latin1tab.h @@ -0,0 +1,36 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME, +/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER, +/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER, +/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER, +/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, +/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, diff --git a/sys/src/cmd/python/Modules/expat/macconfig.h b/sys/src/cmd/python/Modules/expat/macconfig.h new file mode 100644 index 000000000..2725caaf5 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/macconfig.h @@ -0,0 +1,53 @@ +/*================================================================ +** Copyright 2000, Clark Cooper +** All rights reserved. +** +** This is free software. You are permitted to copy, distribute, or modify +** it under the terms of the MIT/X license (contained in the COPYING file +** with this distribution.) +** +*/ + +#ifndef MACCONFIG_H +#define MACCONFIG_H + + +/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ +#define BYTEORDER 4321 + +/* Define to 1 if you have the `bcopy' function. */ +#undef HAVE_BCOPY + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* whether byteorder is bigendian */ +#define WORDS_BIGENDIAN + +/* Define to specify how much context to retain around the current parse + point. */ +#undef XML_CONTEXT_BYTES + +/* Define to make parameter entity parsing functionality available. */ +#define XML_DTD + +/* Define to make XML Namespaces functionality available. */ +#define XML_NS + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `long' if <sys/types.h> does not define. */ +#define off_t long + +/* Define to `unsigned' if <sys/types.h> does not define. */ +#undef size_t + + +#endif /* ifndef MACCONFIG_H */ diff --git a/sys/src/cmd/python/Modules/expat/nametab.h b/sys/src/cmd/python/Modules/expat/nametab.h new file mode 100644 index 000000000..b05e62c77 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/nametab.h @@ -0,0 +1,150 @@ +static const unsigned namingBitmap[] = { +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF, +0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000, +0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060, +0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003, +0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003, +0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000, +0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001, +0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003, +0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000, +0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003, +0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003, +0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000, +0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000, +0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF, +0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB, +0x40000000, 0xF580C900, 0x00000007, 0x02010800, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF, +0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF, +0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF, +0x00000000, 0x00004C40, 0x00000000, 0x00000000, +0x00000007, 0x00000000, 0x00000000, 0x00000000, +0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF, +0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF, +0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, +0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000, +0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE, +0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF, +0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, +0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000, +0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003, +0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD, +0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF, +0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF, +0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE, +0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF, +0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF, +0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF, +0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF, +0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF, +0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0, +0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1, +0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3, +0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80, +0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3, +0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000, +0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000, +0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF, +0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x00000000, 0x00000000, +0x00000000, 0x00000000, 0x1FFF0000, 0x00000002, +0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF, +0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF, +}; +static const unsigned char nmstrtPages[] = { +0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00, +0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char namePages[] = { +0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00, +0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, +0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13, +0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, +0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/sys/src/cmd/python/Modules/expat/pyexpatns.h b/sys/src/cmd/python/Modules/expat/pyexpatns.h new file mode 100644 index 000000000..7fbd341c2 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/pyexpatns.h @@ -0,0 +1,124 @@ +/* Copyright (c) 2005-2006 ActiveState Software Inc. + * + * Namespace all expat exported symbols to avoid dynamic loading symbol + * collisions when embedding Python. + * + * The Problem: + * - you embed Python in some app + * - the app dynamically loads libexpat of version X + * - the embedded Python imports pyexpat (which was built against + * libexpat version X+n) + * --> pyexpat gets the expat symbols from the already loaded and *older* + * libexpat: crash (Specifically the crash we observed was in + * getting an old XML_ErrorString (from xmlparse.c) and then calling + * it with newer values in the XML_Error enum: + * + * // pyexpat.c, line 1970 + * ... + * // Added in Expat 1.95.7. + * MYCONST(XML_ERROR_UNBOUND_PREFIX); + * ... + * + * + * The Solution: + * Prefix all a exported symbols with "PyExpat_". This is similar to + * what Mozilla does for some common libs: + * http://lxr.mozilla.org/seamonkey/source/modules/libimg/png/mozpngconf.h#115 + * + * The list of relevant exported symbols can be had with this command: + * + nm pyexpat.so \ + | grep -v " [a-zBUA] " \ + | grep -v "_fini\|_init\|initpyexpat" + * + * If any of those symbols are NOT prefixed with "PyExpat_" then + * a #define should be added for it here. + */ + +#ifndef PYEXPATNS_H +#define PYEXPATNS_H + +#define XML_DefaultCurrent PyExpat_XML_DefaultCurrent +#define XML_ErrorString PyExpat_XML_ErrorString +#define XML_ExpatVersion PyExpat_XML_ExpatVersion +#define XML_ExpatVersionInfo PyExpat_XML_ExpatVersionInfo +#define XML_ExternalEntityParserCreate PyExpat_XML_ExternalEntityParserCreate +#define XML_FreeContentModel PyExpat_XML_FreeContentModel +#define XML_GetBase PyExpat_XML_GetBase +#define XML_GetBuffer PyExpat_XML_GetBuffer +#define XML_GetCurrentByteCount PyExpat_XML_GetCurrentByteCount +#define XML_GetCurrentByteIndex PyExpat_XML_GetCurrentByteIndex +#define XML_GetCurrentColumnNumber PyExpat_XML_GetCurrentColumnNumber +#define XML_GetCurrentLineNumber PyExpat_XML_GetCurrentLineNumber +#define XML_GetErrorCode PyExpat_XML_GetErrorCode +#define XML_GetFeatureList PyExpat_XML_GetFeatureList +#define XML_GetIdAttributeIndex PyExpat_XML_GetIdAttributeIndex +#define XML_GetInputContext PyExpat_XML_GetInputContext +#define XML_GetParsingStatus PyExpat_XML_GetParsingStatus +#define XML_GetSpecifiedAttributeCount PyExpat_XML_GetSpecifiedAttributeCount +#define XmlGetUtf16InternalEncoding PyExpat_XmlGetUtf16InternalEncoding +#define XmlGetUtf16InternalEncodingNS PyExpat_XmlGetUtf16InternalEncodingNS +#define XmlGetUtf8InternalEncoding PyExpat_XmlGetUtf8InternalEncoding +#define XmlGetUtf8InternalEncodingNS PyExpat_XmlGetUtf8InternalEncodingNS +#define XmlInitEncoding PyExpat_XmlInitEncoding +#define XmlInitEncodingNS PyExpat_XmlInitEncodingNS +#define XmlInitUnknownEncoding PyExpat_XmlInitUnknownEncoding +#define XmlInitUnknownEncodingNS PyExpat_XmlInitUnknownEncodingNS +#define XML_MemFree PyExpat_XML_MemFree +#define XML_MemMalloc PyExpat_XML_MemMalloc +#define XML_MemRealloc PyExpat_XML_MemRealloc +#define XML_Parse PyExpat_XML_Parse +#define XML_ParseBuffer PyExpat_XML_ParseBuffer +#define XML_ParserCreate PyExpat_XML_ParserCreate +#define XML_ParserCreate_MM PyExpat_XML_ParserCreate_MM +#define XML_ParserCreateNS PyExpat_XML_ParserCreateNS +#define XML_ParserFree PyExpat_XML_ParserFree +#define XML_ParserReset PyExpat_XML_ParserReset +#define XmlParseXmlDecl PyExpat_XmlParseXmlDecl +#define XmlParseXmlDeclNS PyExpat_XmlParseXmlDeclNS +#define XmlPrologStateInit PyExpat_XmlPrologStateInit +#define XmlPrologStateInitExternalEntity PyExpat_XmlPrologStateInitExternalEntity +#define XML_ResumeParser PyExpat_XML_ResumeParser +#define XML_SetAttlistDeclHandler PyExpat_XML_SetAttlistDeclHandler +#define XML_SetBase PyExpat_XML_SetBase +#define XML_SetCdataSectionHandler PyExpat_XML_SetCdataSectionHandler +#define XML_SetCharacterDataHandler PyExpat_XML_SetCharacterDataHandler +#define XML_SetCommentHandler PyExpat_XML_SetCommentHandler +#define XML_SetDefaultHandler PyExpat_XML_SetDefaultHandler +#define XML_SetDefaultHandlerExpand PyExpat_XML_SetDefaultHandlerExpand +#define XML_SetDoctypeDeclHandler PyExpat_XML_SetDoctypeDeclHandler +#define XML_SetElementDeclHandler PyExpat_XML_SetElementDeclHandler +#define XML_SetElementHandler PyExpat_XML_SetElementHandler +#define XML_SetEncoding PyExpat_XML_SetEncoding +#define XML_SetEndCdataSectionHandler PyExpat_XML_SetEndCdataSectionHandler +#define XML_SetEndDoctypeDeclHandler PyExpat_XML_SetEndDoctypeDeclHandler +#define XML_SetEndElementHandler PyExpat_XML_SetEndElementHandler +#define XML_SetEndNamespaceDeclHandler PyExpat_XML_SetEndNamespaceDeclHandler +#define XML_SetEntityDeclHandler PyExpat_XML_SetEntityDeclHandler +#define XML_SetExternalEntityRefHandler PyExpat_XML_SetExternalEntityRefHandler +#define XML_SetExternalEntityRefHandlerArg PyExpat_XML_SetExternalEntityRefHandlerArg +#define XML_SetNamespaceDeclHandler PyExpat_XML_SetNamespaceDeclHandler +#define XML_SetNotationDeclHandler PyExpat_XML_SetNotationDeclHandler +#define XML_SetNotStandaloneHandler PyExpat_XML_SetNotStandaloneHandler +#define XML_SetParamEntityParsing PyExpat_XML_SetParamEntityParsing +#define XML_SetProcessingInstructionHandler PyExpat_XML_SetProcessingInstructionHandler +#define XML_SetReturnNSTriplet PyExpat_XML_SetReturnNSTriplet +#define XML_SetSkippedEntityHandler PyExpat_XML_SetSkippedEntityHandler +#define XML_SetStartCdataSectionHandler PyExpat_XML_SetStartCdataSectionHandler +#define XML_SetStartDoctypeDeclHandler PyExpat_XML_SetStartDoctypeDeclHandler +#define XML_SetStartElementHandler PyExpat_XML_SetStartElementHandler +#define XML_SetStartNamespaceDeclHandler PyExpat_XML_SetStartNamespaceDeclHandler +#define XML_SetUnknownEncodingHandler PyExpat_XML_SetUnknownEncodingHandler +#define XML_SetUnparsedEntityDeclHandler PyExpat_XML_SetUnparsedEntityDeclHandler +#define XML_SetUserData PyExpat_XML_SetUserData +#define XML_SetXmlDeclHandler PyExpat_XML_SetXmlDeclHandler +#define XmlSizeOfUnknownEncoding PyExpat_XmlSizeOfUnknownEncoding +#define XML_StopParser PyExpat_XML_StopParser +#define XML_UseForeignDTD PyExpat_XML_UseForeignDTD +#define XML_UseParserAsHandlerArg PyExpat_XML_UseParserAsHandlerArg +#define XmlUtf16Encode PyExpat_XmlUtf16Encode +#define XmlUtf8Encode PyExpat_XmlUtf8Encode + + +#endif /* !PYEXPATNS_H */ + diff --git a/sys/src/cmd/python/Modules/expat/utf8tab.h b/sys/src/cmd/python/Modules/expat/utf8tab.h new file mode 100644 index 000000000..7bb3e7760 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/utf8tab.h @@ -0,0 +1,37 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + + +/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL, +/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2, +/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3, +/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4, +/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML, +/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM, diff --git a/sys/src/cmd/python/Modules/expat/winconfig.h b/sys/src/cmd/python/Modules/expat/winconfig.h new file mode 100644 index 000000000..c1b791d62 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/winconfig.h @@ -0,0 +1,30 @@ +/*================================================================ +** Copyright 2000, Clark Cooper +** All rights reserved. +** +** This is free software. You are permitted to copy, distribute, or modify +** it under the terms of the MIT/X license (contained in the COPYING file +** with this distribution.) +*/ + +#ifndef WINCONFIG_H +#define WINCONFIG_H + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#undef WIN32_LEAN_AND_MEAN + +#include <memory.h> +#include <string.h> + +#define XML_NS 1 +#define XML_DTD 1 +#define XML_CONTEXT_BYTES 1024 + +/* we will assume all Windows platforms are little endian */ +#define BYTEORDER 1234 + +/* Windows has memmove() available. */ +#define HAVE_MEMMOVE + +#endif /* ndef WINCONFIG_H */ diff --git a/sys/src/cmd/python/Modules/expat/xmlparse.c b/sys/src/cmd/python/Modules/expat/xmlparse.c new file mode 100644 index 000000000..e04426d0c --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmlparse.c @@ -0,0 +1,6268 @@ +/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#define XML_BUILDING_EXPAT 1 + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos4__) +#include "amigaconfig.h" +#elif defined(HAVE_EXPAT_CONFIG_H) +#include <expat_config.h> +#endif /* ndef COMPILED_FROM_DSP */ + +#include <stddef.h> +#include <string.h> /* memset(), memcpy() */ +#include <assert.h> + +#include "expat.h" + +#ifdef XML_UNICODE +#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX +#define XmlConvert XmlUtf16Convert +#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS +#define XmlEncode XmlUtf16Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1)) +typedef unsigned short ICHAR; +#else +#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX +#define XmlConvert XmlUtf8Convert +#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding +#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS +#define XmlEncode XmlUtf8Encode +#define MUST_CONVERT(enc, s) (!(enc)->isUtf8) +typedef char ICHAR; +#endif + + +#ifndef XML_NS + +#define XmlInitEncodingNS XmlInitEncoding +#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding +#undef XmlGetInternalEncodingNS +#define XmlGetInternalEncodingNS XmlGetInternalEncoding +#define XmlParseXmlDeclNS XmlParseXmlDecl + +#endif + +#ifdef XML_UNICODE + +#ifdef XML_UNICODE_WCHAR_T +#define XML_T(x) (const wchar_t)x +#define XML_L(x) L ## x +#else +#define XML_T(x) (const unsigned short)x +#define XML_L(x) x +#endif + +#else + +#define XML_T(x) x +#define XML_L(x) x + +#endif + +/* Round up n to be a multiple of sz, where sz is a power of 2. */ +#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1)) + +/* Handle the case where memmove() doesn't exist. */ +#ifndef HAVE_MEMMOVE +#ifdef HAVE_BCOPY +#define memmove(d,s,l) bcopy((s),(d),(l)) +#else +#error memmove does not exist on this platform, nor is a substitute available +#endif /* HAVE_BCOPY */ +#endif /* HAVE_MEMMOVE */ + +#include "internal.h" +#include "xmltok.h" +#include "xmlrole.h" + +typedef const XML_Char *KEY; + +typedef struct { + KEY name; +} NAMED; + +typedef struct { + NAMED **v; + unsigned char power; + size_t size; + size_t used; + const XML_Memory_Handling_Suite *mem; +} HASH_TABLE; + +/* Basic character hash algorithm, taken from Python's string hash: + h = h * 1000003 ^ character, the constant being a prime number. + +*/ +#ifdef XML_UNICODE +#define CHAR_HASH(h, c) \ + (((h) * 0xF4243) ^ (unsigned short)(c)) +#else +#define CHAR_HASH(h, c) \ + (((h) * 0xF4243) ^ (unsigned char)(c)) +#endif + +/* For probing (after a collision) we need a step size relative prime + to the hash table size, which is a power of 2. We use double-hashing, + since we can calculate a second hash value cheaply by taking those bits + of the first hash value that were discarded (masked out) when the table + index was calculated: index = hash & mask, where mask = table->size - 1. + We limit the maximum step size to table->size / 4 (mask >> 2) and make + it odd, since odd numbers are always relative prime to a power of 2. +*/ +#define SECOND_HASH(hash, mask, power) \ + ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2)) +#define PROBE_STEP(hash, mask, power) \ + ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1)) + +typedef struct { + NAMED **p; + NAMED **end; +} HASH_TABLE_ITER; + +#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */ +#define INIT_DATA_BUF_SIZE 1024 +#define INIT_ATTS_SIZE 16 +#define INIT_ATTS_VERSION 0xFFFFFFFF +#define INIT_BLOCK_SIZE 1024 +#define INIT_BUFFER_SIZE 1024 + +#define EXPAND_SPARE 24 + +typedef struct binding { + struct prefix *prefix; + struct binding *nextTagBinding; + struct binding *prevPrefixBinding; + const struct attribute_id *attId; + XML_Char *uri; + int uriLen; + int uriAlloc; +} BINDING; + +typedef struct prefix { + const XML_Char *name; + BINDING *binding; +} PREFIX; + +typedef struct { + const XML_Char *str; + const XML_Char *localPart; + const XML_Char *prefix; + int strLen; + int uriLen; + int prefixLen; +} TAG_NAME; + +/* TAG represents an open element. + The name of the element is stored in both the document and API + encodings. The memory buffer 'buf' is a separately-allocated + memory area which stores the name. During the XML_Parse()/ + XMLParseBuffer() when the element is open, the memory for the 'raw' + version of the name (in the document encoding) is shared with the + document buffer. If the element is open across calls to + XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to + contain the 'raw' name as well. + + A parser re-uses these structures, maintaining a list of allocated + TAG objects in a free list. +*/ +typedef struct tag { + struct tag *parent; /* parent of this element */ + const char *rawName; /* tagName in the original encoding */ + int rawNameLength; + TAG_NAME name; /* tagName in the API encoding */ + char *buf; /* buffer for name components */ + char *bufEnd; /* end of the buffer */ + BINDING *bindings; +} TAG; + +typedef struct { + const XML_Char *name; + const XML_Char *textPtr; + int textLen; /* length in XML_Chars */ + int processed; /* # of processed bytes - when suspended */ + const XML_Char *systemId; + const XML_Char *base; + const XML_Char *publicId; + const XML_Char *notation; + XML_Bool open; + XML_Bool is_param; + XML_Bool is_internal; /* true if declared in internal subset outside PE */ +} ENTITY; + +typedef struct { + enum XML_Content_Type type; + enum XML_Content_Quant quant; + const XML_Char * name; + int firstchild; + int lastchild; + int childcnt; + int nextsib; +} CONTENT_SCAFFOLD; + +#define INIT_SCAFFOLD_ELEMENTS 32 + +typedef struct block { + struct block *next; + int size; + XML_Char s[1]; +} BLOCK; + +typedef struct { + BLOCK *blocks; + BLOCK *freeBlocks; + const XML_Char *end; + XML_Char *ptr; + XML_Char *start; + const XML_Memory_Handling_Suite *mem; +} STRING_POOL; + +/* The XML_Char before the name is used to determine whether + an attribute has been specified. */ +typedef struct attribute_id { + XML_Char *name; + PREFIX *prefix; + XML_Bool maybeTokenized; + XML_Bool xmlns; +} ATTRIBUTE_ID; + +typedef struct { + const ATTRIBUTE_ID *id; + XML_Bool isCdata; + const XML_Char *value; +} DEFAULT_ATTRIBUTE; + +typedef struct { + unsigned long version; + unsigned long hash; + const XML_Char *uriName; +} NS_ATT; + +typedef struct { + const XML_Char *name; + PREFIX *prefix; + const ATTRIBUTE_ID *idAtt; + int nDefaultAtts; + int allocDefaultAtts; + DEFAULT_ATTRIBUTE *defaultAtts; +} ELEMENT_TYPE; + +typedef struct { + HASH_TABLE generalEntities; + HASH_TABLE elementTypes; + HASH_TABLE attributeIds; + HASH_TABLE prefixes; + STRING_POOL pool; + STRING_POOL entityValuePool; + /* false once a parameter entity reference has been skipped */ + XML_Bool keepProcessing; + /* true once an internal or external PE reference has been encountered; + this includes the reference to an external subset */ + XML_Bool hasParamEntityRefs; + XML_Bool standalone; +#ifdef XML_DTD + /* indicates if external PE has been read */ + XML_Bool paramEntityRead; + HASH_TABLE paramEntities; +#endif /* XML_DTD */ + PREFIX defaultPrefix; + /* === scaffolding for building content model === */ + XML_Bool in_eldecl; + CONTENT_SCAFFOLD *scaffold; + unsigned contentStringLen; + unsigned scaffSize; + unsigned scaffCount; + int scaffLevel; + int *scaffIndex; +} DTD; + +typedef struct open_internal_entity { + const char *internalEventPtr; + const char *internalEventEndPtr; + struct open_internal_entity *next; + ENTITY *entity; + int startTagLevel; + XML_Bool betweenDecl; /* WFC: PE Between Declarations */ +} OPEN_INTERNAL_ENTITY; + +typedef enum XML_Error PTRCALL Processor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr); + +static Processor prologProcessor; +static Processor prologInitProcessor; +static Processor contentProcessor; +static Processor cdataSectionProcessor; +#ifdef XML_DTD +static Processor ignoreSectionProcessor; +static Processor externalParEntProcessor; +static Processor externalParEntInitProcessor; +static Processor entityValueProcessor; +static Processor entityValueInitProcessor; +#endif /* XML_DTD */ +static Processor epilogProcessor; +static Processor errorProcessor; +static Processor externalEntityInitProcessor; +static Processor externalEntityInitProcessor2; +static Processor externalEntityInitProcessor3; +static Processor externalEntityContentProcessor; +static Processor internalEntityProcessor; + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName); +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next); +static enum XML_Error +initializeEncoding(XML_Parser parser); +static enum XML_Error +doProlog(XML_Parser parser, const ENCODING *enc, const char *s, + const char *end, int tok, const char *next, const char **nextPtr, + XML_Bool haveMore); +static enum XML_Error +processInternalEntity(XML_Parser parser, ENTITY *entity, + XML_Bool betweenDecl); +static enum XML_Error +doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc, + const char *start, const char *end, const char **endPtr, + XML_Bool haveMore); +static enum XML_Error +doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore); +#ifdef XML_DTD +static enum XML_Error +doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, + const char *end, const char **nextPtr, XML_Bool haveMore); +#endif /* XML_DTD */ + +static enum XML_Error +storeAtts(XML_Parser parser, const ENCODING *, const char *s, + TAG_NAME *tagNamePtr, BINDING **bindingsPtr); +static enum XML_Error +addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr); +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata, + XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser); +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, + const char *, const char *, STRING_POOL *); +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata, + const char *, const char *, STRING_POOL *); +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static int +setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *); +static enum XML_Error +storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end); +static int +reportComment(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); +static void +reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, + const char *end); + +static const XML_Char * getContext(XML_Parser parser); +static XML_Bool +setContext(XML_Parser parser, const XML_Char *context); + +static void FASTCALL normalizePublicId(XML_Char *s); + +static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms); +/* do not call if parentParser != NULL */ +static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms); +static void +dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms); +static int +dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms); +static int +copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *); + +static NAMED * +lookup(HASH_TABLE *table, KEY name, size_t createSize); +static void FASTCALL +hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms); +static void FASTCALL hashTableClear(HASH_TABLE *); +static void FASTCALL hashTableDestroy(HASH_TABLE *); +static void FASTCALL +hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *); +static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *); + +static void FASTCALL +poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms); +static void FASTCALL poolClear(STRING_POOL *); +static void FASTCALL poolDestroy(STRING_POOL *); +static XML_Char * +poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Char * +poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end); +static XML_Bool FASTCALL poolGrow(STRING_POOL *pool); +static const XML_Char * FASTCALL +poolCopyString(STRING_POOL *pool, const XML_Char *s); +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n); +static const XML_Char * FASTCALL +poolAppendString(STRING_POOL *pool, const XML_Char *s); + +static int FASTCALL nextScaffoldPart(XML_Parser parser); +static XML_Content * build_model(XML_Parser parser); +static ELEMENT_TYPE * +getElementType(XML_Parser parser, const ENCODING *enc, + const char *ptr, const char *end); + +static XML_Parser +parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep, + DTD *dtd); +static void +parserInit(XML_Parser parser, const XML_Char *encodingName); + +#define poolStart(pool) ((pool)->start) +#define poolEnd(pool) ((pool)->ptr) +#define poolLength(pool) ((pool)->ptr - (pool)->start) +#define poolChop(pool) ((void)--(pool->ptr)) +#define poolLastChar(pool) (((pool)->ptr)[-1]) +#define poolDiscard(pool) ((pool)->ptr = (pool)->start) +#define poolFinish(pool) ((pool)->start = (pool)->ptr) +#define poolAppendChar(pool, c) \ + (((pool)->ptr == (pool)->end && !poolGrow(pool)) \ + ? 0 \ + : ((*((pool)->ptr)++ = c), 1)) + +struct XML_ParserStruct { + /* The first member must be userData so that the XML_GetUserData + macro works. */ + void *m_userData; + void *m_handlerArg; + char *m_buffer; + const XML_Memory_Handling_Suite m_mem; + /* first character to be parsed */ + const char *m_bufferPtr; + /* past last character to be parsed */ + char *m_bufferEnd; + /* allocated end of buffer */ + const char *m_bufferLim; + XML_Index m_parseEndByteIndex; + const char *m_parseEndPtr; + XML_Char *m_dataBuf; + XML_Char *m_dataBufEnd; + XML_StartElementHandler m_startElementHandler; + XML_EndElementHandler m_endElementHandler; + XML_CharacterDataHandler m_characterDataHandler; + XML_ProcessingInstructionHandler m_processingInstructionHandler; + XML_CommentHandler m_commentHandler; + XML_StartCdataSectionHandler m_startCdataSectionHandler; + XML_EndCdataSectionHandler m_endCdataSectionHandler; + XML_DefaultHandler m_defaultHandler; + XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler; + XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler; + XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler; + XML_NotationDeclHandler m_notationDeclHandler; + XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler; + XML_NotStandaloneHandler m_notStandaloneHandler; + XML_ExternalEntityRefHandler m_externalEntityRefHandler; + XML_Parser m_externalEntityRefHandlerArg; + XML_SkippedEntityHandler m_skippedEntityHandler; + XML_UnknownEncodingHandler m_unknownEncodingHandler; + XML_ElementDeclHandler m_elementDeclHandler; + XML_AttlistDeclHandler m_attlistDeclHandler; + XML_EntityDeclHandler m_entityDeclHandler; + XML_XmlDeclHandler m_xmlDeclHandler; + const ENCODING *m_encoding; + INIT_ENCODING m_initEncoding; + const ENCODING *m_internalEncoding; + const XML_Char *m_protocolEncodingName; + XML_Bool m_ns; + XML_Bool m_ns_triplets; + void *m_unknownEncodingMem; + void *m_unknownEncodingData; + void *m_unknownEncodingHandlerData; + void (XMLCALL *m_unknownEncodingRelease)(void *); + PROLOG_STATE m_prologState; + Processor *m_processor; + enum XML_Error m_errorCode; + const char *m_eventPtr; + const char *m_eventEndPtr; + const char *m_positionPtr; + OPEN_INTERNAL_ENTITY *m_openInternalEntities; + OPEN_INTERNAL_ENTITY *m_freeInternalEntities; + XML_Bool m_defaultExpandInternalEntities; + int m_tagLevel; + ENTITY *m_declEntity; + const XML_Char *m_doctypeName; + const XML_Char *m_doctypeSysid; + const XML_Char *m_doctypePubid; + const XML_Char *m_declAttributeType; + const XML_Char *m_declNotationName; + const XML_Char *m_declNotationPublicId; + ELEMENT_TYPE *m_declElementType; + ATTRIBUTE_ID *m_declAttributeId; + XML_Bool m_declAttributeIsCdata; + XML_Bool m_declAttributeIsId; + DTD *m_dtd; + const XML_Char *m_curBase; + TAG *m_tagStack; + TAG *m_freeTagList; + BINDING *m_inheritedBindings; + BINDING *m_freeBindingList; + int m_attsSize; + int m_nSpecifiedAtts; + int m_idAttIndex; + ATTRIBUTE *m_atts; + NS_ATT *m_nsAtts; + unsigned long m_nsAttsVersion; + unsigned char m_nsAttsPower; + POSITION m_position; + STRING_POOL m_tempPool; + STRING_POOL m_temp2Pool; + char *m_groupConnector; + unsigned int m_groupSize; + XML_Char m_namespaceSeparator; + XML_Parser m_parentParser; + XML_ParsingStatus m_parsingStatus; +#ifdef XML_DTD + XML_Bool m_isParamEntity; + XML_Bool m_useForeignDTD; + enum XML_ParamEntityParsing m_paramEntityParsing; +#endif +}; + +#define MALLOC(s) (parser->m_mem.malloc_fcn((s))) +#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s))) +#define FREE(p) (parser->m_mem.free_fcn((p))) + +#define userData (parser->m_userData) +#define handlerArg (parser->m_handlerArg) +#define startElementHandler (parser->m_startElementHandler) +#define endElementHandler (parser->m_endElementHandler) +#define characterDataHandler (parser->m_characterDataHandler) +#define processingInstructionHandler \ + (parser->m_processingInstructionHandler) +#define commentHandler (parser->m_commentHandler) +#define startCdataSectionHandler \ + (parser->m_startCdataSectionHandler) +#define endCdataSectionHandler (parser->m_endCdataSectionHandler) +#define defaultHandler (parser->m_defaultHandler) +#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler) +#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler) +#define unparsedEntityDeclHandler \ + (parser->m_unparsedEntityDeclHandler) +#define notationDeclHandler (parser->m_notationDeclHandler) +#define startNamespaceDeclHandler \ + (parser->m_startNamespaceDeclHandler) +#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler) +#define notStandaloneHandler (parser->m_notStandaloneHandler) +#define externalEntityRefHandler \ + (parser->m_externalEntityRefHandler) +#define externalEntityRefHandlerArg \ + (parser->m_externalEntityRefHandlerArg) +#define internalEntityRefHandler \ + (parser->m_internalEntityRefHandler) +#define skippedEntityHandler (parser->m_skippedEntityHandler) +#define unknownEncodingHandler (parser->m_unknownEncodingHandler) +#define elementDeclHandler (parser->m_elementDeclHandler) +#define attlistDeclHandler (parser->m_attlistDeclHandler) +#define entityDeclHandler (parser->m_entityDeclHandler) +#define xmlDeclHandler (parser->m_xmlDeclHandler) +#define encoding (parser->m_encoding) +#define initEncoding (parser->m_initEncoding) +#define internalEncoding (parser->m_internalEncoding) +#define unknownEncodingMem (parser->m_unknownEncodingMem) +#define unknownEncodingData (parser->m_unknownEncodingData) +#define unknownEncodingHandlerData \ + (parser->m_unknownEncodingHandlerData) +#define unknownEncodingRelease (parser->m_unknownEncodingRelease) +#define protocolEncodingName (parser->m_protocolEncodingName) +#define ns (parser->m_ns) +#define ns_triplets (parser->m_ns_triplets) +#define prologState (parser->m_prologState) +#define processor (parser->m_processor) +#define errorCode (parser->m_errorCode) +#define eventPtr (parser->m_eventPtr) +#define eventEndPtr (parser->m_eventEndPtr) +#define positionPtr (parser->m_positionPtr) +#define position (parser->m_position) +#define openInternalEntities (parser->m_openInternalEntities) +#define freeInternalEntities (parser->m_freeInternalEntities) +#define defaultExpandInternalEntities \ + (parser->m_defaultExpandInternalEntities) +#define tagLevel (parser->m_tagLevel) +#define buffer (parser->m_buffer) +#define bufferPtr (parser->m_bufferPtr) +#define bufferEnd (parser->m_bufferEnd) +#define parseEndByteIndex (parser->m_parseEndByteIndex) +#define parseEndPtr (parser->m_parseEndPtr) +#define bufferLim (parser->m_bufferLim) +#define dataBuf (parser->m_dataBuf) +#define dataBufEnd (parser->m_dataBufEnd) +#define _dtd (parser->m_dtd) +#define curBase (parser->m_curBase) +#define declEntity (parser->m_declEntity) +#define doctypeName (parser->m_doctypeName) +#define doctypeSysid (parser->m_doctypeSysid) +#define doctypePubid (parser->m_doctypePubid) +#define declAttributeType (parser->m_declAttributeType) +#define declNotationName (parser->m_declNotationName) +#define declNotationPublicId (parser->m_declNotationPublicId) +#define declElementType (parser->m_declElementType) +#define declAttributeId (parser->m_declAttributeId) +#define declAttributeIsCdata (parser->m_declAttributeIsCdata) +#define declAttributeIsId (parser->m_declAttributeIsId) +#define freeTagList (parser->m_freeTagList) +#define freeBindingList (parser->m_freeBindingList) +#define inheritedBindings (parser->m_inheritedBindings) +#define tagStack (parser->m_tagStack) +#define atts (parser->m_atts) +#define attsSize (parser->m_attsSize) +#define nSpecifiedAtts (parser->m_nSpecifiedAtts) +#define idAttIndex (parser->m_idAttIndex) +#define nsAtts (parser->m_nsAtts) +#define nsAttsVersion (parser->m_nsAttsVersion) +#define nsAttsPower (parser->m_nsAttsPower) +#define tempPool (parser->m_tempPool) +#define temp2Pool (parser->m_temp2Pool) +#define groupConnector (parser->m_groupConnector) +#define groupSize (parser->m_groupSize) +#define namespaceSeparator (parser->m_namespaceSeparator) +#define parentParser (parser->m_parentParser) +#define ps_parsing (parser->m_parsingStatus.parsing) +#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer) +#ifdef XML_DTD +#define isParamEntity (parser->m_isParamEntity) +#define useForeignDTD (parser->m_useForeignDTD) +#define paramEntityParsing (parser->m_paramEntityParsing) +#endif /* XML_DTD */ + +XML_Parser XMLCALL +XML_ParserCreate(const XML_Char *encodingName) +{ + return XML_ParserCreate_MM(encodingName, NULL, NULL); +} + +XML_Parser XMLCALL +XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) +{ + XML_Char tmp[2]; + *tmp = nsSep; + return XML_ParserCreate_MM(encodingName, NULL, tmp); +} + +static const XML_Char implicitContext[] = { + 'x', 'm', 'l', '=', 'h', 't', 't', 'p', ':', '/', '/', + 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', + 'X', 'M', 'L', '/', '1', '9', '9', '8', '/', + 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' +}; + +XML_Parser XMLCALL +XML_ParserCreate_MM(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep) +{ + XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL); + if (parser != NULL && ns) { + /* implicit context only set for root parser, since child + parsers (i.e. external entity parsers) will inherit it + */ + if (!setContext(parser, implicitContext)) { + XML_ParserFree(parser); + return NULL; + } + } + return parser; +} + +static XML_Parser +parserCreate(const XML_Char *encodingName, + const XML_Memory_Handling_Suite *memsuite, + const XML_Char *nameSep, + DTD *dtd) +{ + XML_Parser parser; + + if (memsuite) { + XML_Memory_Handling_Suite *mtemp; + parser = (XML_Parser) + memsuite->malloc_fcn(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = memsuite->malloc_fcn; + mtemp->realloc_fcn = memsuite->realloc_fcn; + mtemp->free_fcn = memsuite->free_fcn; + } + } + else { + XML_Memory_Handling_Suite *mtemp; + parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct)); + if (parser != NULL) { + mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem); + mtemp->malloc_fcn = malloc; + mtemp->realloc_fcn = realloc; + mtemp->free_fcn = free; + } + } + + if (!parser) + return parser; + + buffer = NULL; + bufferLim = NULL; + + attsSize = INIT_ATTS_SIZE; + atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE)); + if (atts == NULL) { + FREE(parser); + return NULL; + } + dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char)); + if (dataBuf == NULL) { + FREE(atts); + FREE(parser); + return NULL; + } + dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE; + + if (dtd) + _dtd = dtd; + else { + _dtd = dtdCreate(&parser->m_mem); + if (_dtd == NULL) { + FREE(dataBuf); + FREE(atts); + FREE(parser); + return NULL; + } + } + + freeBindingList = NULL; + freeTagList = NULL; + freeInternalEntities = NULL; + + groupSize = 0; + groupConnector = NULL; + + unknownEncodingHandler = NULL; + unknownEncodingHandlerData = NULL; + + namespaceSeparator = '!'; + ns = XML_FALSE; + ns_triplets = XML_FALSE; + + nsAtts = NULL; + nsAttsVersion = 0; + nsAttsPower = 0; + + poolInit(&tempPool, &(parser->m_mem)); + poolInit(&temp2Pool, &(parser->m_mem)); + parserInit(parser, encodingName); + + if (encodingName && !protocolEncodingName) { + XML_ParserFree(parser); + return NULL; + } + + if (nameSep) { + ns = XML_TRUE; + internalEncoding = XmlGetInternalEncodingNS(); + namespaceSeparator = *nameSep; + } + else { + internalEncoding = XmlGetInternalEncoding(); + } + + return parser; +} + +static void +parserInit(XML_Parser parser, const XML_Char *encodingName) +{ + processor = prologInitProcessor; + XmlPrologStateInit(&prologState); + protocolEncodingName = (encodingName != NULL + ? poolCopyString(&tempPool, encodingName) + : NULL); + curBase = NULL; + XmlInitEncoding(&initEncoding, &encoding, 0); + userData = NULL; + handlerArg = NULL; + startElementHandler = NULL; + endElementHandler = NULL; + characterDataHandler = NULL; + processingInstructionHandler = NULL; + commentHandler = NULL; + startCdataSectionHandler = NULL; + endCdataSectionHandler = NULL; + defaultHandler = NULL; + startDoctypeDeclHandler = NULL; + endDoctypeDeclHandler = NULL; + unparsedEntityDeclHandler = NULL; + notationDeclHandler = NULL; + startNamespaceDeclHandler = NULL; + endNamespaceDeclHandler = NULL; + notStandaloneHandler = NULL; + externalEntityRefHandler = NULL; + externalEntityRefHandlerArg = parser; + skippedEntityHandler = NULL; + elementDeclHandler = NULL; + attlistDeclHandler = NULL; + entityDeclHandler = NULL; + xmlDeclHandler = NULL; + bufferPtr = buffer; + bufferEnd = buffer; + parseEndByteIndex = 0; + parseEndPtr = NULL; + declElementType = NULL; + declAttributeId = NULL; + declEntity = NULL; + doctypeName = NULL; + doctypeSysid = NULL; + doctypePubid = NULL; + declAttributeType = NULL; + declNotationName = NULL; + declNotationPublicId = NULL; + declAttributeIsCdata = XML_FALSE; + declAttributeIsId = XML_FALSE; + memset(&position, 0, sizeof(POSITION)); + errorCode = XML_ERROR_NONE; + eventPtr = NULL; + eventEndPtr = NULL; + positionPtr = NULL; + openInternalEntities = NULL; + defaultExpandInternalEntities = XML_TRUE; + tagLevel = 0; + tagStack = NULL; + inheritedBindings = NULL; + nSpecifiedAtts = 0; + unknownEncodingMem = NULL; + unknownEncodingRelease = NULL; + unknownEncodingData = NULL; + parentParser = NULL; + ps_parsing = XML_INITIALIZED; +#ifdef XML_DTD + isParamEntity = XML_FALSE; + useForeignDTD = XML_FALSE; + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif +} + +/* moves list of bindings to freeBindingList */ +static void FASTCALL +moveToFreeBindingList(XML_Parser parser, BINDING *bindings) +{ + while (bindings) { + BINDING *b = bindings; + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + } +} + +XML_Bool XMLCALL +XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) +{ + TAG *tStk; + OPEN_INTERNAL_ENTITY *openEntityList; + if (parentParser) + return XML_FALSE; + /* move tagStack to freeTagList */ + tStk = tagStack; + while (tStk) { + TAG *tag = tStk; + tStk = tStk->parent; + tag->parent = freeTagList; + moveToFreeBindingList(parser, tag->bindings); + tag->bindings = NULL; + freeTagList = tag; + } + /* move openInternalEntities to freeInternalEntities */ + openEntityList = openInternalEntities; + while (openEntityList) { + OPEN_INTERNAL_ENTITY *openEntity = openEntityList; + openEntityList = openEntity->next; + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + moveToFreeBindingList(parser, inheritedBindings); + FREE(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + poolClear(&tempPool); + poolClear(&temp2Pool); + parserInit(parser, encodingName); + dtdReset(_dtd, &parser->m_mem); + return setContext(parser, implicitContext); +} + +enum XML_Status XMLCALL +XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + /* Block after XML_Parse()/XML_ParseBuffer() has been called. + XXX There's no way for the caller to determine which of the + XXX possible error cases caused the XML_STATUS_ERROR return. + */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return XML_STATUS_ERROR; + if (encodingName == NULL) + protocolEncodingName = NULL; + else { + protocolEncodingName = poolCopyString(&tempPool, encodingName); + if (!protocolEncodingName) + return XML_STATUS_ERROR; + } + return XML_STATUS_OK; +} + +XML_Parser XMLCALL +XML_ExternalEntityParserCreate(XML_Parser oldParser, + const XML_Char *context, + const XML_Char *encodingName) +{ + XML_Parser parser = oldParser; + DTD *newDtd = NULL; + DTD *oldDtd = _dtd; + XML_StartElementHandler oldStartElementHandler = startElementHandler; + XML_EndElementHandler oldEndElementHandler = endElementHandler; + XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler; + XML_ProcessingInstructionHandler oldProcessingInstructionHandler + = processingInstructionHandler; + XML_CommentHandler oldCommentHandler = commentHandler; + XML_StartCdataSectionHandler oldStartCdataSectionHandler + = startCdataSectionHandler; + XML_EndCdataSectionHandler oldEndCdataSectionHandler + = endCdataSectionHandler; + XML_DefaultHandler oldDefaultHandler = defaultHandler; + XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler + = unparsedEntityDeclHandler; + XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler; + XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler + = startNamespaceDeclHandler; + XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler + = endNamespaceDeclHandler; + XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler; + XML_ExternalEntityRefHandler oldExternalEntityRefHandler + = externalEntityRefHandler; + XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler; + XML_UnknownEncodingHandler oldUnknownEncodingHandler + = unknownEncodingHandler; + XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler; + XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler; + XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler; + XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler; + ELEMENT_TYPE * oldDeclElementType = declElementType; + + void *oldUserData = userData; + void *oldHandlerArg = handlerArg; + XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities; + XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg; +#ifdef XML_DTD + enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing; + int oldInEntityValue = prologState.inEntityValue; +#endif + XML_Bool oldns_triplets = ns_triplets; + +#ifdef XML_DTD + if (!context) + newDtd = oldDtd; +#endif /* XML_DTD */ + + /* Note that the magical uses of the pre-processor to make field + access look more like C++ require that `parser' be overwritten + here. This makes this function more painful to follow than it + would be otherwise. + */ + if (ns) { + XML_Char tmp[2]; + *tmp = namespaceSeparator; + parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd); + } + else { + parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd); + } + + if (!parser) + return NULL; + + startElementHandler = oldStartElementHandler; + endElementHandler = oldEndElementHandler; + characterDataHandler = oldCharacterDataHandler; + processingInstructionHandler = oldProcessingInstructionHandler; + commentHandler = oldCommentHandler; + startCdataSectionHandler = oldStartCdataSectionHandler; + endCdataSectionHandler = oldEndCdataSectionHandler; + defaultHandler = oldDefaultHandler; + unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler; + notationDeclHandler = oldNotationDeclHandler; + startNamespaceDeclHandler = oldStartNamespaceDeclHandler; + endNamespaceDeclHandler = oldEndNamespaceDeclHandler; + notStandaloneHandler = oldNotStandaloneHandler; + externalEntityRefHandler = oldExternalEntityRefHandler; + skippedEntityHandler = oldSkippedEntityHandler; + unknownEncodingHandler = oldUnknownEncodingHandler; + elementDeclHandler = oldElementDeclHandler; + attlistDeclHandler = oldAttlistDeclHandler; + entityDeclHandler = oldEntityDeclHandler; + xmlDeclHandler = oldXmlDeclHandler; + declElementType = oldDeclElementType; + userData = oldUserData; + if (oldUserData == oldHandlerArg) + handlerArg = userData; + else + handlerArg = parser; + if (oldExternalEntityRefHandlerArg != oldParser) + externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg; + defaultExpandInternalEntities = oldDefaultExpandInternalEntities; + ns_triplets = oldns_triplets; + parentParser = oldParser; +#ifdef XML_DTD + paramEntityParsing = oldParamEntityParsing; + prologState.inEntityValue = oldInEntityValue; + if (context) { +#endif /* XML_DTD */ + if (!dtdCopy(_dtd, oldDtd, &parser->m_mem) + || !setContext(parser, context)) { + XML_ParserFree(parser); + return NULL; + } + processor = externalEntityInitProcessor; +#ifdef XML_DTD + } + else { + /* The DTD instance referenced by _dtd is shared between the document's + root parser and external PE parsers, therefore one does not need to + call setContext. In addition, one also *must* not call setContext, + because this would overwrite existing prefix->binding pointers in + _dtd with ones that get destroyed with the external PE parser. + This would leave those prefixes with dangling pointers. + */ + isParamEntity = XML_TRUE; + XmlPrologStateInitExternalEntity(&prologState); + processor = externalParEntInitProcessor; + } +#endif /* XML_DTD */ + return parser; +} + +static void FASTCALL +destroyBindings(BINDING *bindings, XML_Parser parser) +{ + for (;;) { + BINDING *b = bindings; + if (!b) + break; + bindings = b->nextTagBinding; + FREE(b->uri); + FREE(b); + } +} + +void XMLCALL +XML_ParserFree(XML_Parser parser) +{ + TAG *tagList; + OPEN_INTERNAL_ENTITY *entityList; + if (parser == NULL) + return; + /* free tagStack and freeTagList */ + tagList = tagStack; + for (;;) { + TAG *p; + if (tagList == NULL) { + if (freeTagList == NULL) + break; + tagList = freeTagList; + freeTagList = NULL; + } + p = tagList; + tagList = tagList->parent; + FREE(p->buf); + destroyBindings(p->bindings, parser); + FREE(p); + } + /* free openInternalEntities and freeInternalEntities */ + entityList = openInternalEntities; + for (;;) { + OPEN_INTERNAL_ENTITY *openEntity; + if (entityList == NULL) { + if (freeInternalEntities == NULL) + break; + entityList = freeInternalEntities; + freeInternalEntities = NULL; + } + openEntity = entityList; + entityList = entityList->next; + FREE(openEntity); + } + + destroyBindings(freeBindingList, parser); + destroyBindings(inheritedBindings, parser); + poolDestroy(&tempPool); + poolDestroy(&temp2Pool); +#ifdef XML_DTD + /* external parameter entity parsers share the DTD structure + parser->m_dtd with the root parser, so we must not destroy it + */ + if (!isParamEntity && _dtd) +#else + if (_dtd) +#endif /* XML_DTD */ + dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem); + FREE((void *)atts); + FREE(groupConnector); + FREE(buffer); + FREE(dataBuf); + FREE(nsAtts); + FREE(unknownEncodingMem); + if (unknownEncodingRelease) + unknownEncodingRelease(unknownEncodingData); + FREE(parser); +} + +void XMLCALL +XML_UseParserAsHandlerArg(XML_Parser parser) +{ + handlerArg = parser; +} + +enum XML_Error XMLCALL +XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD) +{ +#ifdef XML_DTD + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING; + useForeignDTD = useDTD; + return XML_ERROR_NONE; +#else + return XML_ERROR_FEATURE_REQUIRES_XML_DTD; +#endif +} + +void XMLCALL +XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return; + ns_triplets = do_nst ? XML_TRUE : XML_FALSE; +} + +void XMLCALL +XML_SetUserData(XML_Parser parser, void *p) +{ + if (handlerArg == userData) + handlerArg = userData = p; + else + userData = p; +} + +enum XML_Status XMLCALL +XML_SetBase(XML_Parser parser, const XML_Char *p) +{ + if (p) { + p = poolCopyString(&_dtd->pool, p); + if (!p) + return XML_STATUS_ERROR; + curBase = p; + } + else + curBase = NULL; + return XML_STATUS_OK; +} + +const XML_Char * XMLCALL +XML_GetBase(XML_Parser parser) +{ + return curBase; +} + +int XMLCALL +XML_GetSpecifiedAttributeCount(XML_Parser parser) +{ + return nSpecifiedAtts; +} + +int XMLCALL +XML_GetIdAttributeIndex(XML_Parser parser) +{ + return idAttIndex; +} + +void XMLCALL +XML_SetElementHandler(XML_Parser parser, + XML_StartElementHandler start, + XML_EndElementHandler end) +{ + startElementHandler = start; + endElementHandler = end; +} + +void XMLCALL +XML_SetStartElementHandler(XML_Parser parser, + XML_StartElementHandler start) { + startElementHandler = start; +} + +void XMLCALL +XML_SetEndElementHandler(XML_Parser parser, + XML_EndElementHandler end) { + endElementHandler = end; +} + +void XMLCALL +XML_SetCharacterDataHandler(XML_Parser parser, + XML_CharacterDataHandler handler) +{ + characterDataHandler = handler; +} + +void XMLCALL +XML_SetProcessingInstructionHandler(XML_Parser parser, + XML_ProcessingInstructionHandler handler) +{ + processingInstructionHandler = handler; +} + +void XMLCALL +XML_SetCommentHandler(XML_Parser parser, + XML_CommentHandler handler) +{ + commentHandler = handler; +} + +void XMLCALL +XML_SetCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start, + XML_EndCdataSectionHandler end) +{ + startCdataSectionHandler = start; + endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetStartCdataSectionHandler(XML_Parser parser, + XML_StartCdataSectionHandler start) { + startCdataSectionHandler = start; +} + +void XMLCALL +XML_SetEndCdataSectionHandler(XML_Parser parser, + XML_EndCdataSectionHandler end) { + endCdataSectionHandler = end; +} + +void XMLCALL +XML_SetDefaultHandler(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = XML_FALSE; +} + +void XMLCALL +XML_SetDefaultHandlerExpand(XML_Parser parser, + XML_DefaultHandler handler) +{ + defaultHandler = handler; + defaultExpandInternalEntities = XML_TRUE; +} + +void XMLCALL +XML_SetDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start, + XML_EndDoctypeDeclHandler end) +{ + startDoctypeDeclHandler = start; + endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetStartDoctypeDeclHandler(XML_Parser parser, + XML_StartDoctypeDeclHandler start) { + startDoctypeDeclHandler = start; +} + +void XMLCALL +XML_SetEndDoctypeDeclHandler(XML_Parser parser, + XML_EndDoctypeDeclHandler end) { + endDoctypeDeclHandler = end; +} + +void XMLCALL +XML_SetUnparsedEntityDeclHandler(XML_Parser parser, + XML_UnparsedEntityDeclHandler handler) +{ + unparsedEntityDeclHandler = handler; +} + +void XMLCALL +XML_SetNotationDeclHandler(XML_Parser parser, + XML_NotationDeclHandler handler) +{ + notationDeclHandler = handler; +} + +void XMLCALL +XML_SetNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start, + XML_EndNamespaceDeclHandler end) +{ + startNamespaceDeclHandler = start; + endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetStartNamespaceDeclHandler(XML_Parser parser, + XML_StartNamespaceDeclHandler start) { + startNamespaceDeclHandler = start; +} + +void XMLCALL +XML_SetEndNamespaceDeclHandler(XML_Parser parser, + XML_EndNamespaceDeclHandler end) { + endNamespaceDeclHandler = end; +} + +void XMLCALL +XML_SetNotStandaloneHandler(XML_Parser parser, + XML_NotStandaloneHandler handler) +{ + notStandaloneHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandler(XML_Parser parser, + XML_ExternalEntityRefHandler handler) +{ + externalEntityRefHandler = handler; +} + +void XMLCALL +XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg) +{ + if (arg) + externalEntityRefHandlerArg = (XML_Parser)arg; + else + externalEntityRefHandlerArg = parser; +} + +void XMLCALL +XML_SetSkippedEntityHandler(XML_Parser parser, + XML_SkippedEntityHandler handler) +{ + skippedEntityHandler = handler; +} + +void XMLCALL +XML_SetUnknownEncodingHandler(XML_Parser parser, + XML_UnknownEncodingHandler handler, + void *data) +{ + unknownEncodingHandler = handler; + unknownEncodingHandlerData = data; +} + +void XMLCALL +XML_SetElementDeclHandler(XML_Parser parser, + XML_ElementDeclHandler eldecl) +{ + elementDeclHandler = eldecl; +} + +void XMLCALL +XML_SetAttlistDeclHandler(XML_Parser parser, + XML_AttlistDeclHandler attdecl) +{ + attlistDeclHandler = attdecl; +} + +void XMLCALL +XML_SetEntityDeclHandler(XML_Parser parser, + XML_EntityDeclHandler handler) +{ + entityDeclHandler = handler; +} + +void XMLCALL +XML_SetXmlDeclHandler(XML_Parser parser, + XML_XmlDeclHandler handler) { + xmlDeclHandler = handler; +} + +int XMLCALL +XML_SetParamEntityParsing(XML_Parser parser, + enum XML_ParamEntityParsing peParsing) +{ + /* block after XML_Parse()/XML_ParseBuffer() has been called */ + if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED) + return 0; +#ifdef XML_DTD + paramEntityParsing = peParsing; + return 1; +#else + return peParsing == XML_PARAM_ENTITY_PARSING_NEVER; +#endif +} + +enum XML_Status XMLCALL +XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + ps_parsing = XML_PARSING; + } + + if (len == 0) { + ps_finalBuffer = (XML_Bool)isFinal; + if (!isFinal) + return XML_STATUS_OK; + positionPtr = bufferPtr; + parseEndPtr = bufferEnd; + + /* If data are left over from last buffer, and we now know that these + data are the final chunk of input, then we have to check them again + to detect errors based on that fact. + */ + errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); + + if (errorCode == XML_ERROR_NONE) { + switch (ps_parsing) { + case XML_SUSPENDED: + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return XML_STATUS_SUSPENDED; + case XML_INITIALIZED: + case XML_PARSING: + ps_parsing = XML_FINISHED; + /* fall through */ + default: + return XML_STATUS_OK; + } + } + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } +#ifndef XML_CONTEXT_BYTES + else if (bufferPtr == bufferEnd) { + const char *end; + int nLeftOver; + enum XML_Error result; + parseEndByteIndex += len; + positionPtr = s; + ps_finalBuffer = (XML_Bool)isFinal; + + errorCode = processor(parser, s, parseEndPtr = s + len, &end); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + result = XML_STATUS_OK; + if (isFinal) { + ps_parsing = XML_FINISHED; + return result; + } + } + } + + XmlUpdatePosition(encoding, positionPtr, end, &position); + nLeftOver = s + len - end; + if (nLeftOver) { + if (buffer == NULL || nLeftOver > bufferLim - buffer) { + /* FIXME avoid integer overflow */ + char *temp; + temp = (buffer == NULL + ? (char *)MALLOC(len * 2) + : (char *)REALLOC(buffer, len * 2)); + if (temp == NULL) { + errorCode = XML_ERROR_NO_MEMORY; + return XML_STATUS_ERROR; + } + buffer = temp; + if (!buffer) { + errorCode = XML_ERROR_NO_MEMORY; + eventPtr = eventEndPtr = NULL; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + bufferLim = buffer + len * 2; + } + memcpy(buffer, end, nLeftOver); + } + bufferPtr = buffer; + bufferEnd = buffer + nLeftOver; + positionPtr = bufferPtr; + parseEndPtr = bufferEnd; + eventPtr = bufferPtr; + eventEndPtr = bufferPtr; + return result; + } +#endif /* not defined XML_CONTEXT_BYTES */ + else { + void *buff = XML_GetBuffer(parser, len); + if (buff == NULL) + return XML_STATUS_ERROR; + else { + memcpy(buff, s, len); + return XML_ParseBuffer(parser, len, isFinal); + } + } +} + +enum XML_Status XMLCALL +XML_ParseBuffer(XML_Parser parser, int len, int isFinal) +{ + const char *start; + enum XML_Status result = XML_STATUS_OK; + + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + ps_parsing = XML_PARSING; + } + + start = bufferPtr; + positionPtr = start; + bufferEnd += len; + parseEndPtr = bufferEnd; + parseEndByteIndex += len; + ps_finalBuffer = (XML_Bool)isFinal; + + errorCode = processor(parser, start, parseEndPtr, &bufferPtr); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (isFinal) { + ps_parsing = XML_FINISHED; + return result; + } + default: ; /* should not happen */ + } + } + + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return result; +} + +void * XMLCALL +XML_GetBuffer(XML_Parser parser, int len) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + errorCode = XML_ERROR_SUSPENDED; + return NULL; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return NULL; + default: ; + } + + if (len > bufferLim - bufferEnd) { + /* FIXME avoid integer overflow */ + int neededSize = len + (int)(bufferEnd - bufferPtr); +#ifdef XML_CONTEXT_BYTES + int keep = (int)(bufferPtr - buffer); + + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + neededSize += keep; +#endif /* defined XML_CONTEXT_BYTES */ + if (neededSize <= bufferLim - buffer) { +#ifdef XML_CONTEXT_BYTES + if (keep < bufferPtr - buffer) { + int offset = (int)(bufferPtr - buffer) - keep; + memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep); + bufferEnd -= offset; + bufferPtr -= offset; + } +#else + memmove(buffer, bufferPtr, bufferEnd - bufferPtr); + bufferEnd = buffer + (bufferEnd - bufferPtr); + bufferPtr = buffer; +#endif /* not defined XML_CONTEXT_BYTES */ + } + else { + char *newBuf; + int bufferSize = (int)(bufferLim - bufferPtr); + if (bufferSize == 0) + bufferSize = INIT_BUFFER_SIZE; + do { + bufferSize *= 2; + } while (bufferSize < neededSize); + newBuf = (char *)MALLOC(bufferSize); + if (newBuf == 0) { + errorCode = XML_ERROR_NO_MEMORY; + return NULL; + } + bufferLim = newBuf + bufferSize; +#ifdef XML_CONTEXT_BYTES + if (bufferPtr) { + int keep = (int)(bufferPtr - buffer); + if (keep > XML_CONTEXT_BYTES) + keep = XML_CONTEXT_BYTES; + memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep); + FREE(buffer); + buffer = newBuf; + bufferEnd = buffer + (bufferEnd - bufferPtr) + keep; + bufferPtr = buffer + keep; + } + else { + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; + } +#else + if (bufferPtr) { + memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr); + FREE(buffer); + } + bufferEnd = newBuf + (bufferEnd - bufferPtr); + bufferPtr = buffer = newBuf; +#endif /* not defined XML_CONTEXT_BYTES */ + } + } + return bufferEnd; +} + +enum XML_Status XMLCALL +XML_StopParser(XML_Parser parser, XML_Bool resumable) +{ + switch (ps_parsing) { + case XML_SUSPENDED: + if (resumable) { + errorCode = XML_ERROR_SUSPENDED; + return XML_STATUS_ERROR; + } + ps_parsing = XML_FINISHED; + break; + case XML_FINISHED: + errorCode = XML_ERROR_FINISHED; + return XML_STATUS_ERROR; + default: + if (resumable) { +#ifdef XML_DTD + if (isParamEntity) { + errorCode = XML_ERROR_SUSPEND_PE; + return XML_STATUS_ERROR; + } +#endif + ps_parsing = XML_SUSPENDED; + } + else + ps_parsing = XML_FINISHED; + } + return XML_STATUS_OK; +} + +enum XML_Status XMLCALL +XML_ResumeParser(XML_Parser parser) +{ + enum XML_Status result = XML_STATUS_OK; + + if (ps_parsing != XML_SUSPENDED) { + errorCode = XML_ERROR_NOT_SUSPENDED; + return XML_STATUS_ERROR; + } + ps_parsing = XML_PARSING; + + errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr); + + if (errorCode != XML_ERROR_NONE) { + eventEndPtr = eventPtr; + processor = errorProcessor; + return XML_STATUS_ERROR; + } + else { + switch (ps_parsing) { + case XML_SUSPENDED: + result = XML_STATUS_SUSPENDED; + break; + case XML_INITIALIZED: + case XML_PARSING: + if (ps_finalBuffer) { + ps_parsing = XML_FINISHED; + return result; + } + default: ; + } + } + + XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position); + positionPtr = bufferPtr; + return result; +} + +void XMLCALL +XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status) +{ + assert(status != NULL); + *status = parser->m_parsingStatus; +} + +enum XML_Error XMLCALL +XML_GetErrorCode(XML_Parser parser) +{ + return errorCode; +} + +XML_Index XMLCALL +XML_GetCurrentByteIndex(XML_Parser parser) +{ + if (eventPtr) + return parseEndByteIndex - (parseEndPtr - eventPtr); + return -1; +} + +int XMLCALL +XML_GetCurrentByteCount(XML_Parser parser) +{ + if (eventEndPtr && eventPtr) + return (int)(eventEndPtr - eventPtr); + return 0; +} + +const char * XMLCALL +XML_GetInputContext(XML_Parser parser, int *offset, int *size) +{ +#ifdef XML_CONTEXT_BYTES + if (eventPtr && buffer) { + *offset = (int)(eventPtr - buffer); + *size = (int)(bufferEnd - buffer); + return buffer; + } +#endif /* defined XML_CONTEXT_BYTES */ + return (char *) 0; +} + +XML_Size XMLCALL +XML_GetCurrentLineNumber(XML_Parser parser) +{ + if (eventPtr && eventPtr >= positionPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.lineNumber + 1; +} + +XML_Size XMLCALL +XML_GetCurrentColumnNumber(XML_Parser parser) +{ + if (eventPtr && eventPtr >= positionPtr) { + XmlUpdatePosition(encoding, positionPtr, eventPtr, &position); + positionPtr = eventPtr; + } + return position.columnNumber; +} + +void XMLCALL +XML_FreeContentModel(XML_Parser parser, XML_Content *model) +{ + FREE(model); +} + +void * XMLCALL +XML_MemMalloc(XML_Parser parser, size_t size) +{ + return MALLOC(size); +} + +void * XMLCALL +XML_MemRealloc(XML_Parser parser, void *ptr, size_t size) +{ + return REALLOC(ptr, size); +} + +void XMLCALL +XML_MemFree(XML_Parser parser, void *ptr) +{ + FREE(ptr); +} + +void XMLCALL +XML_DefaultCurrent(XML_Parser parser) +{ + if (defaultHandler) { + if (openInternalEntities) + reportDefault(parser, + internalEncoding, + openInternalEntities->internalEventPtr, + openInternalEntities->internalEventEndPtr); + else + reportDefault(parser, encoding, eventPtr, eventEndPtr); + } +} + +const XML_LChar * XMLCALL +XML_ErrorString(enum XML_Error code) +{ + static const XML_LChar* const message[] = { + 0, + XML_L("out of memory"), + XML_L("syntax error"), + XML_L("no element found"), + XML_L("not well-formed (invalid token)"), + XML_L("unclosed token"), + XML_L("partial character"), + XML_L("mismatched tag"), + XML_L("duplicate attribute"), + XML_L("junk after document element"), + XML_L("illegal parameter entity reference"), + XML_L("undefined entity"), + XML_L("recursive entity reference"), + XML_L("asynchronous entity"), + XML_L("reference to invalid character number"), + XML_L("reference to binary entity"), + XML_L("reference to external entity in attribute"), + XML_L("XML or text declaration not at start of entity"), + XML_L("unknown encoding"), + XML_L("encoding specified in XML declaration is incorrect"), + XML_L("unclosed CDATA section"), + XML_L("error in processing external entity reference"), + XML_L("document is not standalone"), + XML_L("unexpected parser state - please send a bug report"), + XML_L("entity declared in parameter entity"), + XML_L("requested feature requires XML_DTD support in Expat"), + XML_L("cannot change setting once parsing has begun"), + XML_L("unbound prefix"), + XML_L("must not undeclare prefix"), + XML_L("incomplete markup in parameter entity"), + XML_L("XML declaration not well-formed"), + XML_L("text declaration not well-formed"), + XML_L("illegal character(s) in public id"), + XML_L("parser suspended"), + XML_L("parser not suspended"), + XML_L("parsing aborted"), + XML_L("parsing finished"), + XML_L("cannot suspend in external parameter entity"), + XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"), + XML_L("reserved prefix (xmlns) must not be declared or undeclared"), + XML_L("prefix must not be bound to one of the reserved namespace names") + }; + if (code > 0 && code < sizeof(message)/sizeof(message[0])) + return message[code]; + return NULL; +} + +const XML_LChar * XMLCALL +XML_ExpatVersion(void) { + + /* V1 is used to string-ize the version number. However, it would + string-ize the actual version macro *names* unless we get them + substituted before being passed to V1. CPP is defined to expand + a macro, then rescan for more expansions. Thus, we use V2 to expand + the version macros, then CPP will expand the resulting V1() macro + with the correct numerals. */ + /* ### I'm assuming cpp is portable in this respect... */ + +#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c) +#define V2(a,b,c) XML_L("expat_")V1(a,b,c) + + return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION); + +#undef V1 +#undef V2 +} + +XML_Expat_Version XMLCALL +XML_ExpatVersionInfo(void) +{ + XML_Expat_Version version; + + version.major = XML_MAJOR_VERSION; + version.minor = XML_MINOR_VERSION; + version.micro = XML_MICRO_VERSION; + + return version; +} + +const XML_Feature * XMLCALL +XML_GetFeatureList(void) +{ + static const XML_Feature features[] = { + {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"), + sizeof(XML_Char)}, + {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"), + sizeof(XML_LChar)}, +#ifdef XML_UNICODE + {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0}, +#endif +#ifdef XML_UNICODE_WCHAR_T + {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0}, +#endif +#ifdef XML_DTD + {XML_FEATURE_DTD, XML_L("XML_DTD"), 0}, +#endif +#ifdef XML_CONTEXT_BYTES + {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"), + XML_CONTEXT_BYTES}, +#endif +#ifdef XML_MIN_SIZE + {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0}, +#endif +#ifdef XML_NS + {XML_FEATURE_NS, XML_L("XML_NS"), 0}, +#endif + {XML_FEATURE_END, NULL, 0} + }; + + return features; +} + +/* Initially tag->rawName always points into the parse buffer; + for those TAG instances opened while the current parse buffer was + processed, and not yet closed, we need to store tag->rawName in a more + permanent location, since the parse buffer is about to be discarded. +*/ +static XML_Bool +storeRawNames(XML_Parser parser) +{ + TAG *tag = tagStack; + while (tag) { + int bufSize; + int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1); + char *rawNameBuf = tag->buf + nameLen; + /* Stop if already stored. Since tagStack is a stack, we can stop + at the first entry that has already been copied; everything + below it in the stack is already been accounted for in a + previous call to this function. + */ + if (tag->rawName == rawNameBuf) + break; + /* For re-use purposes we need to ensure that the + size of tag->buf is a multiple of sizeof(XML_Char). + */ + bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)); + if (bufSize > tag->bufEnd - tag->buf) { + char *temp = (char *)REALLOC(tag->buf, bufSize); + if (temp == NULL) + return XML_FALSE; + /* if tag->name.str points to tag->buf (only when namespace + processing is off) then we have to update it + */ + if (tag->name.str == (XML_Char *)tag->buf) + tag->name.str = (XML_Char *)temp; + /* if tag->name.localPart is set (when namespace processing is on) + then update it as well, since it will always point into tag->buf + */ + if (tag->name.localPart) + tag->name.localPart = (XML_Char *)temp + (tag->name.localPart - + (XML_Char *)tag->buf); + tag->buf = temp; + tag->bufEnd = temp + bufSize; + rawNameBuf = temp + nameLen; + } + memcpy(rawNameBuf, tag->rawName, tag->rawNameLength); + tag->rawName = rawNameBuf; + tag = tag->parent; + } + return XML_TRUE; +} + +static enum XML_Error PTRCALL +contentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doContent(parser, 0, encoding, start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result == XML_ERROR_NONE) { + if (!storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = externalEntityInitProcessor2; + return externalEntityInitProcessor2(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor2(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(encoding, start, end, &next); + switch (tok) { + case XML_TOK_BOM: + /* If we are at the end of the buffer, this would cause the next stage, + i.e. externalEntityInitProcessor3, to pass control directly to + doContent (by detecting XML_TOK_NONE) without processing any xml text + declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent. + */ + if (next == end && !ps_finalBuffer) { + *endPtr = next; + return XML_ERROR_NONE; + } + start = next; + break; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + eventPtr = start; + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityInitProcessor3; + return externalEntityInitProcessor3(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityInitProcessor3(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + int tok; + const char *next = start; /* XmlContentTok doesn't always set the last arg */ + eventPtr = start; + tok = XmlContentTok(encoding, start, end, &next); + eventEndPtr = next; + + switch (tok) { + case XML_TOK_XML_DECL: + { + enum XML_Error result; + result = processXmlDecl(parser, 1, start, next); + if (result != XML_ERROR_NONE) + return result; + switch (ps_parsing) { + case XML_SUSPENDED: + *endPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + start = next; + } + } + break; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *endPtr = start; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + } + processor = externalEntityContentProcessor; + tagLevel = 1; + return externalEntityContentProcessor(parser, start, end, endPtr); +} + +static enum XML_Error PTRCALL +externalEntityContentProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doContent(parser, 1, encoding, start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result == XML_ERROR_NONE) { + if (!storeRawNames(parser)) + return XML_ERROR_NO_MEMORY; + } + return result; +} + +static enum XML_Error +doContent(XML_Parser parser, + int startTagLevel, + const ENCODING *enc, + const char *s, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + /* save one level of indirection */ + DTD * const dtd = _dtd; + + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + + for (;;) { + const char *next = s; /* XmlContentTok doesn't always set the last arg */ + int tok = XmlContentTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_TRAILING_CR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + *eventEndPP = end; + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) + return XML_ERROR_NO_ELEMENTS; + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (startTagLevel > 0) { + if (tagLevel != startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_NO_ELEMENTS; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (characterDataHandler) + characterDataHandler(handlerArg, &ch, 1); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + name = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + poolDiscard(&dtd->pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity or default handler. + */ + if (!dtd->hasParamEntityRefs || dtd->standalone) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->notation) + return XML_ERROR_BINARY_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + if (!defaultExpandInternalEntities) { + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, entity->name, 0); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + result = processInternalEntity(parser, entity, XML_FALSE); + if (result != XML_ERROR_NONE) + return result; + } + else if (externalEntityRefHandler) { + const XML_Char *context; + entity->open = XML_TRUE; + context = getContext(parser); + entity->open = XML_FALSE; + if (!context) + return XML_ERROR_NO_MEMORY; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + context, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + poolDiscard(&tempPool); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + case XML_TOK_START_TAG_NO_ATTS: + /* fall through */ + case XML_TOK_START_TAG_WITH_ATTS: + { + TAG *tag; + enum XML_Error result; + XML_Char *toPtr; + if (freeTagList) { + tag = freeTagList; + freeTagList = freeTagList->parent; + } + else { + tag = (TAG *)MALLOC(sizeof(TAG)); + if (!tag) + return XML_ERROR_NO_MEMORY; + tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE); + if (!tag->buf) { + FREE(tag); + return XML_ERROR_NO_MEMORY; + } + tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE; + } + tag->bindings = NULL; + tag->parent = tagStack; + tagStack = tag; + tag->name.localPart = NULL; + tag->name.prefix = NULL; + tag->rawName = s + enc->minBytesPerChar; + tag->rawNameLength = XmlNameLength(enc, tag->rawName); + ++tagLevel; + { + const char *rawNameEnd = tag->rawName + tag->rawNameLength; + const char *fromPtr = tag->rawName; + toPtr = (XML_Char *)tag->buf; + for (;;) { + int bufSize; + int convLen; + XmlConvert(enc, + &fromPtr, rawNameEnd, + (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1); + convLen = (int)(toPtr - (XML_Char *)tag->buf); + if (fromPtr == rawNameEnd) { + tag->name.strLen = convLen; + break; + } + bufSize = (int)(tag->bufEnd - tag->buf) << 1; + { + char *temp = (char *)REALLOC(tag->buf, bufSize); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + tag->buf = temp; + tag->bufEnd = temp + bufSize; + toPtr = (XML_Char *)temp + convLen; + } + } + } + tag->name.str = (XML_Char *)tag->buf; + *toPtr = XML_T('\0'); + result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings)); + if (result) + return result; + if (startElementHandler) + startElementHandler(handlerArg, tag->name.str, + (const XML_Char **)atts); + else if (defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&tempPool); + break; + } + case XML_TOK_EMPTY_ELEMENT_NO_ATTS: + /* fall through */ + case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: + { + const char *rawName = s + enc->minBytesPerChar; + enum XML_Error result; + BINDING *bindings = NULL; + XML_Bool noElmHandlers = XML_TRUE; + TAG_NAME name; + name.str = poolStoreString(&tempPool, enc, rawName, + rawName + XmlNameLength(enc, rawName)); + if (!name.str) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + result = storeAtts(parser, enc, s, &name, &bindings); + if (result) + return result; + poolFinish(&tempPool); + if (startElementHandler) { + startElementHandler(handlerArg, name.str, (const XML_Char **)atts); + noElmHandlers = XML_FALSE; + } + if (endElementHandler) { + if (startElementHandler) + *eventPP = *eventEndPP; + endElementHandler(handlerArg, name.str); + noElmHandlers = XML_FALSE; + } + if (noElmHandlers && defaultHandler) + reportDefault(parser, enc, s, next); + poolClear(&tempPool); + while (bindings) { + BINDING *b = bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + bindings = bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + break; + case XML_TOK_END_TAG: + if (tagLevel == startTagLevel) + return XML_ERROR_ASYNC_ENTITY; + else { + int len; + const char *rawName; + TAG *tag = tagStack; + tagStack = tag->parent; + tag->parent = freeTagList; + freeTagList = tag; + rawName = s + enc->minBytesPerChar*2; + len = XmlNameLength(enc, rawName); + if (len != tag->rawNameLength + || memcmp(tag->rawName, rawName, len) != 0) { + *eventPP = rawName; + return XML_ERROR_TAG_MISMATCH; + } + --tagLevel; + if (endElementHandler) { + const XML_Char *localPart; + const XML_Char *prefix; + XML_Char *uri; + localPart = tag->name.localPart; + if (ns && localPart) { + /* localPart and prefix may have been overwritten in + tag->name.str, since this points to the binding->uri + buffer which gets re-used; so we have to add them again + */ + uri = (XML_Char *)tag->name.str + tag->name.uriLen; + /* don't need to check for space - already done in storeAtts() */ + while (*localPart) *uri++ = *localPart++; + prefix = (XML_Char *)tag->name.prefix; + if (ns_triplets && prefix) { + *uri++ = namespaceSeparator; + while (*prefix) *uri++ = *prefix++; + } + *uri = XML_T('\0'); + } + endElementHandler(handlerArg, tag->name.str); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + while (tag->bindings) { + BINDING *b = tag->bindings; + if (endNamespaceDeclHandler) + endNamespaceDeclHandler(handlerArg, b->prefix->name); + tag->bindings = tag->bindings->nextTagBinding; + b->nextTagBinding = freeBindingList; + freeBindingList = b; + b->prefix->binding = b->prevPrefixBinding; + } + if (tagLevel == 0) + return epilogProcessor(parser, next, end, nextPtr); + } + break; + case XML_TOK_CHAR_REF: + { + int n = XmlCharRefNumber(enc, s); + if (n < 0) + return XML_ERROR_BAD_CHAR_REF; + if (characterDataHandler) { + XML_Char buf[XML_ENCODE_MAX]; + characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + } + break; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_CDATA_SECT_OPEN: + { + enum XML_Error result; + if (startCdataSectionHandler) + startCdataSectionHandler(handlerArg); +#if 0 + /* Suppose you doing a transformation on a document that involves + changing only the character data. You set up a defaultHandler + and a characterDataHandler. The defaultHandler simply copies + characters through. The characterDataHandler does the + transformation and writes the characters out escaping them as + necessary. This case will fail to work if we leave out the + following two lines (because & and < inside CDATA sections will + be incorrectly escaped). + + However, now we have a start/endCdataSectionHandler, so it seems + easier to let the user deal with this. + */ + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore); + if (result != XML_ERROR_NONE) + return result; + else if (!next) { + processor = cdataSectionProcessor; + return result; + } + } + break; + case XML_TOK_TRAILING_RSQB: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + characterDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)end - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, end); + /* We are at the end of the final buffer, should we check for + XML_SUSPENDED, XML_FINISHED? + */ + if (startTagLevel == 0) { + *eventPP = end; + return XML_ERROR_NO_ELEMENTS; + } + if (tagLevel != startTagLevel) { + *eventPP = end; + return XML_ERROR_ASYNC_ENTITY; + } + *nextPtr = end; + return XML_ERROR_NONE; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + characterDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + break; + default: + if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + } + *eventPP = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } + /* not reached */ +} + +/* Precondition: all arguments must be non-NULL; + Purpose: + - normalize attributes + - check attributes for well-formedness + - generate namespace aware attribute names (URI, prefix) + - build list of attributes for startElementHandler + - default attributes + - process namespace declarations (check and report them) + - generate namespace aware element name (URI, prefix) +*/ +static enum XML_Error +storeAtts(XML_Parser parser, const ENCODING *enc, + const char *attStr, TAG_NAME *tagNamePtr, + BINDING **bindingsPtr) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + ELEMENT_TYPE *elementType; + int nDefaultAtts; + const XML_Char **appAtts; /* the attribute list for the application */ + int attIndex = 0; + int prefixLen; + int i; + int n; + XML_Char *uri; + int nPrefixes = 0; + BINDING *binding; + const XML_Char *localPart; + + /* lookup the element type name */ + elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0); + if (!elementType) { + const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str); + if (!name) + return XML_ERROR_NO_MEMORY; + elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name, + sizeof(ELEMENT_TYPE)); + if (!elementType) + return XML_ERROR_NO_MEMORY; + if (ns && !setElementTypePrefix(parser, elementType)) + return XML_ERROR_NO_MEMORY; + } + nDefaultAtts = elementType->nDefaultAtts; + + /* get the attributes from the tokenizer */ + n = XmlGetAttributes(enc, attStr, attsSize, atts); + if (n + nDefaultAtts > attsSize) { + int oldAttsSize = attsSize; + ATTRIBUTE *temp; + attsSize = n + nDefaultAtts + INIT_ATTS_SIZE; + temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + atts = temp; + if (n > oldAttsSize) + XmlGetAttributes(enc, attStr, n, atts); + } + + appAtts = (const XML_Char **)atts; + for (i = 0; i < n; i++) { + /* add the name and value to the attribute list */ + ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name, + atts[i].name + + XmlNameLength(enc, atts[i].name)); + if (!attId) + return XML_ERROR_NO_MEMORY; + /* Detect duplicate attributes by their QNames. This does not work when + namespace processing is turned on and different prefixes for the same + namespace are used. For this case we have a check further down. + */ + if ((attId->name)[-1]) { + if (enc == encoding) + eventPtr = atts[i].name; + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + (attId->name)[-1] = 1; + appAtts[attIndex++] = attId->name; + if (!atts[i].normalized) { + enum XML_Error result; + XML_Bool isCdata = XML_TRUE; + + /* figure out whether declared as other than CDATA */ + if (attId->maybeTokenized) { + int j; + for (j = 0; j < nDefaultAtts; j++) { + if (attId == elementType->defaultAtts[j].id) { + isCdata = elementType->defaultAtts[j].isCdata; + break; + } + } + } + + /* normalize the attribute value */ + result = storeAttributeValue(parser, enc, isCdata, + atts[i].valuePtr, atts[i].valueEnd, + &tempPool); + if (result) + return result; + appAtts[attIndex] = poolStart(&tempPool); + poolFinish(&tempPool); + } + else { + /* the value did not need normalizing */ + appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, + atts[i].valueEnd); + if (appAtts[attIndex] == 0) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + } + /* handle prefixed attribute names */ + if (attId->prefix) { + if (attId->xmlns) { + /* deal with namespace declarations here */ + enum XML_Error result = addBinding(parser, attId->prefix, attId, + appAtts[attIndex], bindingsPtr); + if (result) + return result; + --attIndex; + } + else { + /* deal with other prefixed names later */ + attIndex++; + nPrefixes++; + (attId->name)[-1] = 2; + } + } + else + attIndex++; + } + + /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */ + nSpecifiedAtts = attIndex; + if (elementType->idAtt && (elementType->idAtt->name)[-1]) { + for (i = 0; i < attIndex; i += 2) + if (appAtts[i] == elementType->idAtt->name) { + idAttIndex = i; + break; + } + } + else + idAttIndex = -1; + + /* do attribute defaulting */ + for (i = 0; i < nDefaultAtts; i++) { + const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i; + if (!(da->id->name)[-1] && da->value) { + if (da->id->prefix) { + if (da->id->xmlns) { + enum XML_Error result = addBinding(parser, da->id->prefix, da->id, + da->value, bindingsPtr); + if (result) + return result; + } + else { + (da->id->name)[-1] = 2; + nPrefixes++; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + else { + (da->id->name)[-1] = 1; + appAtts[attIndex++] = da->id->name; + appAtts[attIndex++] = da->value; + } + } + } + appAtts[attIndex] = 0; + + /* expand prefixed attribute names, check for duplicates, + and clear flags that say whether attributes were specified */ + i = 0; + if (nPrefixes) { + int j; /* hash table index */ + unsigned long version = nsAttsVersion; + int nsAttsSize = (int)1 << nsAttsPower; + /* size of hash table must be at least 2 * (# of prefixed attributes) */ + if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */ + NS_ATT *temp; + /* hash table size must also be a power of 2 and >= 8 */ + while (nPrefixes >> nsAttsPower++); + if (nsAttsPower < 3) + nsAttsPower = 3; + nsAttsSize = (int)1 << nsAttsPower; + temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT)); + if (!temp) + return XML_ERROR_NO_MEMORY; + nsAtts = temp; + version = 0; /* force re-initialization of nsAtts hash table */ + } + /* using a version flag saves us from initializing nsAtts every time */ + if (!version) { /* initialize version flags when version wraps around */ + version = INIT_ATTS_VERSION; + for (j = nsAttsSize; j != 0; ) + nsAtts[--j].version = version; + } + nsAttsVersion = --version; + + /* expand prefixed names and check for duplicates */ + for (; i < attIndex; i += 2) { + const XML_Char *s = appAtts[i]; + if (s[-1] == 2) { /* prefixed */ + ATTRIBUTE_ID *id; + const BINDING *b; + unsigned long uriHash = 0; + ((XML_Char *)s)[-1] = 0; /* clear flag */ + id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0); + if (!id) + return XML_ERROR_NO_MEMORY; + b = id->prefix->binding; + if (!b) + return XML_ERROR_UNBOUND_PREFIX; + + /* as we expand the name we also calculate its hash value */ + for (j = 0; j < b->uriLen; j++) { + const XML_Char c = b->uri[j]; + if (!poolAppendChar(&tempPool, c)) + return XML_ERROR_NO_MEMORY; + uriHash = CHAR_HASH(uriHash, c); + } + while (*s++ != XML_T(':')) + ; + do { /* copies null terminator */ + const XML_Char c = *s; + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + uriHash = CHAR_HASH(uriHash, c); + } while (*s++); + + { /* Check hash table for duplicate of expanded name (uriName). + Derived from code in lookup(HASH_TABLE *table, ...). + */ + unsigned char step = 0; + unsigned long mask = nsAttsSize - 1; + j = uriHash & mask; /* index into hash table */ + while (nsAtts[j].version == version) { + /* for speed we compare stored hash values first */ + if (uriHash == nsAtts[j].hash) { + const XML_Char *s1 = poolStart(&tempPool); + const XML_Char *s2 = nsAtts[j].uriName; + /* s1 is null terminated, but not s2 */ + for (; *s1 == *s2 && *s1 != 0; s1++, s2++); + if (*s1 == 0) + return XML_ERROR_DUPLICATE_ATTRIBUTE; + } + if (!step) + step = PROBE_STEP(uriHash, mask, nsAttsPower); + j < step ? (j += nsAttsSize - step) : (j -= step); + } + } + + if (ns_triplets) { /* append namespace separator and prefix */ + tempPool.ptr[-1] = namespaceSeparator; + s = b->prefix->name; + do { + if (!poolAppendChar(&tempPool, *s)) + return XML_ERROR_NO_MEMORY; + } while (*s++); + } + + /* store expanded name in attribute list */ + s = poolStart(&tempPool); + poolFinish(&tempPool); + appAtts[i] = s; + + /* fill empty slot with new version, uriName and hash value */ + nsAtts[j].version = version; + nsAtts[j].hash = uriHash; + nsAtts[j].uriName = s; + + if (!--nPrefixes) { + i += 2; + break; + } + } + else /* not prefixed */ + ((XML_Char *)s)[-1] = 0; /* clear flag */ + } + } + /* clear flags for the remaining attributes */ + for (; i < attIndex; i += 2) + ((XML_Char *)(appAtts[i]))[-1] = 0; + for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding) + binding->attId->name[-1] = 0; + + if (!ns) + return XML_ERROR_NONE; + + /* expand the element type name */ + if (elementType->prefix) { + binding = elementType->prefix->binding; + if (!binding) + return XML_ERROR_UNBOUND_PREFIX; + localPart = tagNamePtr->str; + while (*localPart++ != XML_T(':')) + ; + } + else if (dtd->defaultPrefix.binding) { + binding = dtd->defaultPrefix.binding; + localPart = tagNamePtr->str; + } + else + return XML_ERROR_NONE; + prefixLen = 0; + if (ns_triplets && binding->prefix->name) { + for (; binding->prefix->name[prefixLen++];) + ; /* prefixLen includes null terminator */ + } + tagNamePtr->localPart = localPart; + tagNamePtr->uriLen = binding->uriLen; + tagNamePtr->prefix = binding->prefix->name; + tagNamePtr->prefixLen = prefixLen; + for (i = 0; localPart[i++];) + ; /* i includes null terminator */ + n = i + binding->uriLen + prefixLen; + if (n > binding->uriAlloc) { + TAG *p; + uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char)); + if (!uri) + return XML_ERROR_NO_MEMORY; + binding->uriAlloc = n + EXPAND_SPARE; + memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char)); + for (p = tagStack; p; p = p->parent) + if (p->name.str == binding->uri) + p->name.str = uri; + FREE(binding->uri); + binding->uri = uri; + } + /* if namespaceSeparator != '\0' then uri includes it already */ + uri = binding->uri + binding->uriLen; + memcpy(uri, localPart, i * sizeof(XML_Char)); + /* we always have a namespace separator between localPart and prefix */ + if (prefixLen) { + uri += i - 1; + *uri = namespaceSeparator; /* replace null terminator */ + memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char)); + } + tagNamePtr->str = binding->uri; + return XML_ERROR_NONE; +} + +/* addBinding() overwrites the value of prefix->binding without checking. + Therefore one must keep track of the old value outside of addBinding(). +*/ +static enum XML_Error +addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, + const XML_Char *uri, BINDING **bindingsPtr) +{ + static const XML_Char xmlNamespace[] = { + 'h', 't', 't', 'p', ':', '/', '/', + 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', + 'X', 'M', 'L', '/', '1', '9', '9', '8', '/', + 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0' + }; + static const int xmlLen = + (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1; + static const XML_Char xmlnsNamespace[] = { + 'h', 't', 't', 'p', ':', '/', '/', + 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/', + '2', '0', '0', '0', '/', 'x', 'm', 'l', 'n', 's', '/', '\0' + }; + static const int xmlnsLen = + (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1; + + XML_Bool mustBeXML = XML_FALSE; + XML_Bool isXML = XML_TRUE; + XML_Bool isXMLNS = XML_TRUE; + + BINDING *b; + int len; + + /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */ + if (*uri == XML_T('\0') && prefix->name) + return XML_ERROR_UNDECLARING_PREFIX; + + if (prefix->name + && prefix->name[0] == XML_T('x') + && prefix->name[1] == XML_T('m') + && prefix->name[2] == XML_T('l')) { + + /* Not allowed to bind xmlns */ + if (prefix->name[3] == XML_T('n') + && prefix->name[4] == XML_T('s') + && prefix->name[5] == XML_T('\0')) + return XML_ERROR_RESERVED_PREFIX_XMLNS; + + if (prefix->name[3] == XML_T('\0')) + mustBeXML = XML_TRUE; + } + + for (len = 0; uri[len]; len++) { + if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len])) + isXML = XML_FALSE; + + if (!mustBeXML && isXMLNS + && (len > xmlnsLen || uri[len] != xmlnsNamespace[len])) + isXMLNS = XML_FALSE; + } + isXML = isXML && len == xmlLen; + isXMLNS = isXMLNS && len == xmlnsLen; + + if (mustBeXML != isXML) + return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML + : XML_ERROR_RESERVED_NAMESPACE_URI; + + if (isXMLNS) + return XML_ERROR_RESERVED_NAMESPACE_URI; + + if (namespaceSeparator) + len++; + if (freeBindingList) { + b = freeBindingList; + if (len > b->uriAlloc) { + XML_Char *temp = (XML_Char *)REALLOC(b->uri, + sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + b->uri = temp; + b->uriAlloc = len + EXPAND_SPARE; + } + freeBindingList = b->nextTagBinding; + } + else { + b = (BINDING *)MALLOC(sizeof(BINDING)); + if (!b) + return XML_ERROR_NO_MEMORY; + b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE)); + if (!b->uri) { + FREE(b); + return XML_ERROR_NO_MEMORY; + } + b->uriAlloc = len + EXPAND_SPARE; + } + b->uriLen = len; + memcpy(b->uri, uri, len * sizeof(XML_Char)); + if (namespaceSeparator) + b->uri[len - 1] = namespaceSeparator; + b->prefix = prefix; + b->attId = attId; + b->prevPrefixBinding = prefix->binding; + /* NULL binding when default namespace undeclared */ + if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix) + prefix->binding = NULL; + else + prefix->binding = b; + b->nextTagBinding = *bindingsPtr; + *bindingsPtr = b; + /* if attId == NULL then we are not starting a namespace scope */ + if (attId && startNamespaceDeclHandler) + startNamespaceDeclHandler(handlerArg, prefix->name, + prefix->binding ? uri : 0); + return XML_ERROR_NONE; +} + +/* The idea here is to avoid using stack for each CDATA section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +cdataSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doCdataSection(parser, encoding, &start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result != XML_ERROR_NONE) + return result; + if (start) { + if (parentParser) { /* we are parsing an external entity */ + processor = externalEntityContentProcessor; + return externalEntityContentProcessor(parser, start, end, endPtr); + } + else { + processor = contentProcessor; + return contentProcessor(parser, start, end, endPtr); + } + } + return result; +} + +/* startPtr gets set to non-null if the section is closed, and to null if + the section is not yet closed. +*/ +static enum XML_Error +doCdataSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = NULL; + + for (;;) { + const char *next; + int tok = XmlCdataSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_CDATA_SECT_CLOSE: + if (endCdataSectionHandler) + endCdataSectionHandler(handlerArg); +#if 0 + /* see comment under XML_TOK_CDATA_SECT_OPEN */ + else if (characterDataHandler) + characterDataHandler(handlerArg, dataBuf, 0); +#endif + else if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_DATA_NEWLINE: + if (characterDataHandler) { + XML_Char c = 0xA; + characterDataHandler(handlerArg, &c, 1); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_DATA_CHARS: + if (characterDataHandler) { + if (MUST_CONVERT(enc, s)) { + for (;;) { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = next; + characterDataHandler(handlerArg, dataBuf, + (int)(dataPtr - (ICHAR *)dataBuf)); + if (s == next) + break; + *eventPP = s; + } + } + else + characterDataHandler(handlerArg, + (XML_Char *)s, + (int)((XML_Char *)next - (XML_Char *)s)); + } + else if (defaultHandler) + reportDefault(parser, enc, s, next); + break; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_CDATA_SECTION; + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + + *eventPP = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } + /* not reached */ +} + +#ifdef XML_DTD + +/* The idea here is to avoid using stack for each IGNORE section when + the whole file is parsed with one call. +*/ +static enum XML_Error PTRCALL +ignoreSectionProcessor(XML_Parser parser, + const char *start, + const char *end, + const char **endPtr) +{ + enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, + endPtr, (XML_Bool)!ps_finalBuffer); + if (result != XML_ERROR_NONE) + return result; + if (start) { + processor = prologProcessor; + return prologProcessor(parser, start, end, endPtr); + } + return result; +} + +/* startPtr gets set to non-null is the section is closed, and to null + if the section is not yet closed. +*/ +static enum XML_Error +doIgnoreSection(XML_Parser parser, + const ENCODING *enc, + const char **startPtr, + const char *end, + const char **nextPtr, + XML_Bool haveMore) +{ + const char *next; + int tok; + const char *s = *startPtr; + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + *eventPP = s; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + *eventPP = s; + *startPtr = NULL; + tok = XmlIgnoreSectionTok(enc, s, end, &next); + *eventEndPP = next; + switch (tok) { + case XML_TOK_IGNORE_SECT: + if (defaultHandler) + reportDefault(parser, enc, s, next); + *startPtr = next; + *nextPtr = next; + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + else + return XML_ERROR_NONE; + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_PARTIAL: + case XML_TOK_NONE: + if (haveMore) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */ + default: + *eventPP = next; + return XML_ERROR_UNEXPECTED_STATE; + } + /* not reached */ +} + +#endif /* XML_DTD */ + +static enum XML_Error +initializeEncoding(XML_Parser parser) +{ + const char *s; +#ifdef XML_UNICODE + char encodingBuf[128]; + if (!protocolEncodingName) + s = NULL; + else { + int i; + for (i = 0; protocolEncodingName[i]; i++) { + if (i == sizeof(encodingBuf) - 1 + || (protocolEncodingName[i] & ~0x7f) != 0) { + encodingBuf[0] = '\0'; + break; + } + encodingBuf[i] = (char)protocolEncodingName[i]; + } + encodingBuf[i] = '\0'; + s = encodingBuf; + } +#else + s = protocolEncodingName; +#endif + if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s)) + return XML_ERROR_NONE; + return handleUnknownEncoding(parser, protocolEncodingName); +} + +static enum XML_Error +processXmlDecl(XML_Parser parser, int isGeneralTextEntity, + const char *s, const char *next) +{ + const char *encodingName = NULL; + const XML_Char *storedEncName = NULL; + const ENCODING *newEncoding = NULL; + const char *version = NULL; + const char *versionend; + const XML_Char *storedversion = NULL; + int standalone = -1; + if (!(ns + ? XmlParseXmlDeclNS + : XmlParseXmlDecl)(isGeneralTextEntity, + encoding, + s, + next, + &eventPtr, + &version, + &versionend, + &encodingName, + &newEncoding, + &standalone)) { + if (isGeneralTextEntity) + return XML_ERROR_TEXT_DECL; + else + return XML_ERROR_XML_DECL; + } + if (!isGeneralTextEntity && standalone == 1) { + _dtd->standalone = XML_TRUE; +#ifdef XML_DTD + if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE) + paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER; +#endif /* XML_DTD */ + } + if (xmlDeclHandler) { + if (encodingName != NULL) { + storedEncName = poolStoreString(&temp2Pool, + encoding, + encodingName, + encodingName + + XmlNameLength(encoding, encodingName)); + if (!storedEncName) + return XML_ERROR_NO_MEMORY; + poolFinish(&temp2Pool); + } + if (version) { + storedversion = poolStoreString(&temp2Pool, + encoding, + version, + versionend - encoding->minBytesPerChar); + if (!storedversion) + return XML_ERROR_NO_MEMORY; + } + xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone); + } + else if (defaultHandler) + reportDefault(parser, encoding, s, next); + if (protocolEncodingName == NULL) { + if (newEncoding) { + if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) { + eventPtr = encodingName; + return XML_ERROR_INCORRECT_ENCODING; + } + encoding = newEncoding; + } + else if (encodingName) { + enum XML_Error result; + if (!storedEncName) { + storedEncName = poolStoreString( + &temp2Pool, encoding, encodingName, + encodingName + XmlNameLength(encoding, encodingName)); + if (!storedEncName) + return XML_ERROR_NO_MEMORY; + } + result = handleUnknownEncoding(parser, storedEncName); + poolClear(&temp2Pool); + if (result == XML_ERROR_UNKNOWN_ENCODING) + eventPtr = encodingName; + return result; + } + } + + if (storedEncName || storedversion) + poolClear(&temp2Pool); + + return XML_ERROR_NONE; +} + +static enum XML_Error +handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName) +{ + if (unknownEncodingHandler) { + XML_Encoding info; + int i; + for (i = 0; i < 256; i++) + info.map[i] = -1; + info.convert = NULL; + info.data = NULL; + info.release = NULL; + if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, + &info)) { + ENCODING *enc; + unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding()); + if (!unknownEncodingMem) { + if (info.release) + info.release(info.data); + return XML_ERROR_NO_MEMORY; + } + enc = (ns + ? XmlInitUnknownEncodingNS + : XmlInitUnknownEncoding)(unknownEncodingMem, + info.map, + info.convert, + info.data); + if (enc) { + unknownEncodingData = info.data; + unknownEncodingRelease = info.release; + encoding = enc; + return XML_ERROR_NONE; + } + } + if (info.release != NULL) + info.release(info.data); + } + return XML_ERROR_UNKNOWN_ENCODING; +} + +static enum XML_Error PTRCALL +prologInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + processor = prologProcessor; + return prologProcessor(parser, s, end, nextPtr); +} + +#ifdef XML_DTD + +static enum XML_Error PTRCALL +externalParEntInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + enum XML_Error result = initializeEncoding(parser); + if (result != XML_ERROR_NONE) + return result; + + /* we know now that XML_Parse(Buffer) has been called, + so we consider the external parameter entity read */ + _dtd->paramEntityRead = XML_TRUE; + + if (prologState.inEntityValue) { + processor = entityValueInitProcessor; + return entityValueInitProcessor(parser, s, end, nextPtr); + } + else { + processor = externalParEntProcessor; + return externalParEntProcessor(parser, s, end, nextPtr); + } +} + +static enum XML_Error PTRCALL +entityValueInitProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + int tok; + const char *start = s; + const char *next = start; + eventPtr = start; + + for (;;) { + tok = XmlPrologTok(encoding, start, end, &next); + eventEndPtr = next; + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, encoding, s, end); + } + else if (tok == XML_TOK_XML_DECL) { + enum XML_Error result; + result = processXmlDecl(parser, 0, start, next); + if (result != XML_ERROR_NONE) + return result; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + *nextPtr = next; + } + /* stop scanning for text declaration - we found one */ + processor = entityValueProcessor; + return entityValueProcessor(parser, next, end, nextPtr); + } + /* If we are at the end of the buffer, this would cause XmlPrologTok to + return XML_TOK_NONE on the next call, which would then cause the + function to exit with *nextPtr set to s - that is what we want for other + tokens, but not for the BOM - we would rather like to skip it; + then, when this routine is entered the next time, XmlPrologTok will + return XML_TOK_INVALID, since the BOM is still in the buffer + */ + else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) { + *nextPtr = next; + return XML_ERROR_NONE; + } + start = next; + eventPtr = start; + } +} + +static enum XML_Error PTRCALL +externalParEntProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next = s; + int tok; + + tok = XmlPrologTok(encoding, s, end, &next); + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + } + /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM. + However, when parsing an external subset, doProlog will not accept a BOM + as valid, and report a syntax error, so we have to skip the BOM + */ + else if (tok == XML_TOK_BOM) { + s = next; + tok = XmlPrologTok(encoding, s, end, &next); + } + + processor = prologProcessor; + return doProlog(parser, encoding, s, end, tok, next, + nextPtr, (XML_Bool)!ps_finalBuffer); +} + +static enum XML_Error PTRCALL +entityValueProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *start = s; + const char *next = s; + const ENCODING *enc = encoding; + int tok; + + for (;;) { + tok = XmlPrologTok(enc, start, end, &next); + if (tok <= 0) { + if (!ps_finalBuffer && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: /* start == end */ + default: + break; + } + /* found end of entity value - can store it now */ + return storeEntityValue(parser, enc, s, end); + } + start = next; + } +} + +#endif /* XML_DTD */ + +static enum XML_Error PTRCALL +prologProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + const char *next = s; + int tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, + nextPtr, (XML_Bool)!ps_finalBuffer); +} + +static enum XML_Error +doProlog(XML_Parser parser, + const ENCODING *enc, + const char *s, + const char *end, + int tok, + const char *next, + const char **nextPtr, + XML_Bool haveMore) +{ +#ifdef XML_DTD + static const XML_Char externalSubsetName[] = { '#' , '\0' }; +#endif /* XML_DTD */ + static const XML_Char atypeCDATA[] = { 'C', 'D', 'A', 'T', 'A', '\0' }; + static const XML_Char atypeID[] = { 'I', 'D', '\0' }; + static const XML_Char atypeIDREF[] = { 'I', 'D', 'R', 'E', 'F', '\0' }; + static const XML_Char atypeIDREFS[] = { 'I', 'D', 'R', 'E', 'F', 'S', '\0' }; + static const XML_Char atypeENTITY[] = { 'E', 'N', 'T', 'I', 'T', 'Y', '\0' }; + static const XML_Char atypeENTITIES[] = + { 'E', 'N', 'T', 'I', 'T', 'I', 'E', 'S', '\0' }; + static const XML_Char atypeNMTOKEN[] = { + 'N', 'M', 'T', 'O', 'K', 'E', 'N', '\0' }; + static const XML_Char atypeNMTOKENS[] = { + 'N', 'M', 'T', 'O', 'K', 'E', 'N', 'S', '\0' }; + static const XML_Char notationPrefix[] = { + 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N', '(', '\0' }; + static const XML_Char enumValueSep[] = { '|', '\0' }; + static const XML_Char enumValueStart[] = { '(', '\0' }; + + /* save one level of indirection */ + DTD * const dtd = _dtd; + + const char **eventPP; + const char **eventEndPP; + enum XML_Content_Quant quant; + + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + + for (;;) { + int role; + XML_Bool handleDefault = XML_TRUE; + *eventPP = s; + *eventEndPP = next; + if (tok <= 0) { + if (haveMore && tok != XML_TOK_INVALID) { + *nextPtr = s; + return XML_ERROR_NONE; + } + switch (tok) { + case XML_TOK_INVALID: + *eventPP = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + return XML_ERROR_PARTIAL_CHAR; + case XML_TOK_NONE: +#ifdef XML_DTD + /* for internal PE NOT referenced between declarations */ + if (enc != encoding && !openInternalEntities->betweenDecl) { + *nextPtr = s; + return XML_ERROR_NONE; + } + /* WFC: PE Between Declarations - must check that PE contains + complete markup, not only for external PEs, but also for + internal PEs if the reference occurs between declarations. + */ + if (isParamEntity || enc != encoding) { + if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc) + == XML_ROLE_ERROR) + return XML_ERROR_INCOMPLETE_PE; + *nextPtr = s; + return XML_ERROR_NONE; + } +#endif /* XML_DTD */ + return XML_ERROR_NO_ELEMENTS; + default: + tok = -tok; + next = end; + break; + } + } + role = XmlTokenRole(&prologState, tok, s, next, enc); + switch (role) { + case XML_ROLE_XML_DECL: + { + enum XML_Error result = processXmlDecl(parser, 0, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_DOCTYPE_NAME: + if (startDoctypeDeclHandler) { + doctypeName = poolStoreString(&tempPool, enc, s, next); + if (!doctypeName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + doctypePubid = NULL; + handleDefault = XML_FALSE; + } + doctypeSysid = NULL; /* always initialize to NULL */ + break; + case XML_ROLE_DOCTYPE_INTERNAL_SUBSET: + if (startDoctypeDeclHandler) { + startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid, + doctypePubid, 1); + doctypeName = NULL; + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + break; +#ifdef XML_DTD + case XML_ROLE_TEXT_DECL: + { + enum XML_Error result = processXmlDecl(parser, 1, s, next); + if (result != XML_ERROR_NONE) + return result; + enc = encoding; + handleDefault = XML_FALSE; + } + break; +#endif /* XML_DTD */ + case XML_ROLE_DOCTYPE_PUBLIC_ID: +#ifdef XML_DTD + useForeignDTD = XML_FALSE; + declEntity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (startDoctypeDeclHandler) { + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + doctypePubid = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!doctypePubid) + return XML_ERROR_NO_MEMORY; + normalizePublicId((XML_Char *)doctypePubid); + poolFinish(&tempPool); + handleDefault = XML_FALSE; + goto alreadyChecked; + } + /* fall through */ + case XML_ROLE_ENTITY_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + alreadyChecked: + if (dtd->keepProcessing && declEntity) { + XML_Char *tem = poolStoreString(&dtd->pool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declEntity->publicId = tem; + poolFinish(&dtd->pool); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_DOCTYPE_CLOSE: + if (doctypeName) { + startDoctypeDeclHandler(handlerArg, doctypeName, + doctypeSysid, doctypePubid, 0); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + /* doctypeSysid will be non-NULL in the case of a previous + XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler + was not set, indicating an external subset + */ +#ifdef XML_DTD + if (doctypeSysid || useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!entity) + return XML_ERROR_NO_MEMORY; + if (useForeignDTD) + entity->base = curBase; + dtd->paramEntityRead = XML_FALSE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else if (!doctypeSysid) + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + useForeignDTD = XML_FALSE; + } +#endif /* XML_DTD */ + if (endDoctypeDeclHandler) { + endDoctypeDeclHandler(handlerArg); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_INSTANCE_START: +#ifdef XML_DTD + /* if there is no DOCTYPE declaration then now is the + last chance to read the foreign DTD + */ + if (useForeignDTD) { + XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs; + dtd->hasParamEntityRefs = XML_TRUE; + if (paramEntityParsing && externalEntityRefHandler) { + ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!entity) + return XML_ERROR_NO_MEMORY; + entity->base = curBase; + dtd->paramEntityRead = XML_FALSE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + if (dtd->paramEntityRead) { + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + } + /* if we didn't read the foreign DTD then this means that there + is no external subset and we must reset dtd->hasParamEntityRefs + */ + else + dtd->hasParamEntityRefs = hadParamEntityRefs; + /* end of DTD - no need to update dtd->keepProcessing */ + } + } +#endif /* XML_DTD */ + processor = contentProcessor; + return contentProcessor(parser, s, end, nextPtr); + case XML_ROLE_ATTLIST_ELEMENT_NAME: + declElementType = getElementType(parser, enc, s, next); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_NAME: + declAttributeId = getAttributeId(parser, enc, s, next); + if (!declAttributeId) + return XML_ERROR_NO_MEMORY; + declAttributeIsCdata = XML_FALSE; + declAttributeType = NULL; + declAttributeIsId = XML_FALSE; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_CDATA: + declAttributeIsCdata = XML_TRUE; + declAttributeType = atypeCDATA; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ID: + declAttributeIsId = XML_TRUE; + declAttributeType = atypeID; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREF: + declAttributeType = atypeIDREF; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_IDREFS: + declAttributeType = atypeIDREFS; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITY: + declAttributeType = atypeENTITY; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES: + declAttributeType = atypeENTITIES; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN: + declAttributeType = atypeNMTOKEN; + goto checkAttListDeclHandler; + case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS: + declAttributeType = atypeNMTOKENS; + checkAttListDeclHandler: + if (dtd->keepProcessing && attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTRIBUTE_ENUM_VALUE: + case XML_ROLE_ATTRIBUTE_NOTATION_VALUE: + if (dtd->keepProcessing && attlistDeclHandler) { + const XML_Char *prefix; + if (declAttributeType) { + prefix = enumValueSep; + } + else { + prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE + ? notationPrefix + : enumValueStart); + } + if (!poolAppendString(&tempPool, prefix)) + return XML_ERROR_NO_MEMORY; + if (!poolAppend(&tempPool, enc, s, next)) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE: + case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + if (!defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, declAttributeIsId, + 0, parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == XML_T('(') + || (*declAttributeType == XML_T('N') + && declAttributeType[1] == XML_T('O'))) { + /* Enumerated or Notation type */ + if (!poolAppendChar(&tempPool, XML_T(')')) + || !poolAppendChar(&tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE: + case XML_ROLE_FIXED_ATTRIBUTE_VALUE: + if (dtd->keepProcessing) { + const XML_Char *attVal; + enum XML_Error result = + storeAttributeValue(parser, enc, declAttributeIsCdata, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar, + &dtd->pool); + if (result) + return result; + attVal = poolStart(&dtd->pool); + poolFinish(&dtd->pool); + /* ID attributes aren't allowed to have a default */ + if (!defineAttribute(declElementType, declAttributeId, + declAttributeIsCdata, XML_FALSE, attVal, parser)) + return XML_ERROR_NO_MEMORY; + if (attlistDeclHandler && declAttributeType) { + if (*declAttributeType == XML_T('(') + || (*declAttributeType == XML_T('N') + && declAttributeType[1] == XML_T('O'))) { + /* Enumerated or Notation type */ + if (!poolAppendChar(&tempPool, XML_T(')')) + || !poolAppendChar(&tempPool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + declAttributeType = tempPool.start; + poolFinish(&tempPool); + } + *eventEndPP = s; + attlistDeclHandler(handlerArg, declElementType->name, + declAttributeId->name, declAttributeType, + attVal, + role == XML_ROLE_FIXED_ATTRIBUTE_VALUE); + poolClear(&tempPool); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_ENTITY_VALUE: + if (dtd->keepProcessing) { + enum XML_Error result = storeEntityValue(parser, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (declEntity) { + declEntity->textPtr = poolStart(&dtd->entityValuePool); + declEntity->textLen = (int)(poolLength(&dtd->entityValuePool)); + poolFinish(&dtd->entityValuePool); + if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + declEntity->is_param, + declEntity->textPtr, + declEntity->textLen, + curBase, 0, 0, 0); + handleDefault = XML_FALSE; + } + } + else + poolDiscard(&dtd->entityValuePool); + if (result != XML_ERROR_NONE) + return result; + } + break; + case XML_ROLE_DOCTYPE_SYSTEM_ID: +#ifdef XML_DTD + useForeignDTD = XML_FALSE; +#endif /* XML_DTD */ + dtd->hasParamEntityRefs = XML_TRUE; + if (startDoctypeDeclHandler) { + doctypeSysid = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (doctypeSysid == NULL) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } +#ifdef XML_DTD + else + /* use externalSubsetName to make doctypeSysid non-NULL + for the case where no startDoctypeDeclHandler is set */ + doctypeSysid = externalSubsetName; +#endif /* XML_DTD */ + if (!dtd->standalone +#ifdef XML_DTD + && !paramEntityParsing +#endif /* XML_DTD */ + && notStandaloneHandler + && !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; +#ifndef XML_DTD + break; +#else /* XML_DTD */ + if (!declEntity) { + declEntity = (ENTITY *)lookup(&dtd->paramEntities, + externalSubsetName, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + declEntity->publicId = NULL; + } + /* fall through */ +#endif /* XML_DTD */ + case XML_ROLE_ENTITY_SYSTEM_ID: + if (dtd->keepProcessing && declEntity) { + declEntity->systemId = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!declEntity->systemId) + return XML_ERROR_NO_MEMORY; + declEntity->base = curBase; + poolFinish(&dtd->pool); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_COMPLETE: + if (dtd->keepProcessing && declEntity && entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + declEntity->is_param, + 0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + 0); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_ENTITY_NOTATION_NAME: + if (dtd->keepProcessing && declEntity) { + declEntity->notation = poolStoreString(&dtd->pool, enc, s, next); + if (!declEntity->notation) + return XML_ERROR_NO_MEMORY; + poolFinish(&dtd->pool); + if (unparsedEntityDeclHandler) { + *eventEndPP = s; + unparsedEntityDeclHandler(handlerArg, + declEntity->name, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + handleDefault = XML_FALSE; + } + else if (entityDeclHandler) { + *eventEndPP = s; + entityDeclHandler(handlerArg, + declEntity->name, + 0,0,0, + declEntity->base, + declEntity->systemId, + declEntity->publicId, + declEntity->notation); + handleDefault = XML_FALSE; + } + } + break; + case XML_ROLE_GENERAL_ENTITY_NAME: + { + if (XmlPredefinedEntityName(enc, s, next)) { + declEntity = NULL; + break; + } + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *)lookup(&dtd->generalEntities, name, + sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + else { + poolFinish(&dtd->pool); + declEntity->publicId = NULL; + declEntity->is_param = XML_FALSE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + declEntity->is_internal = !(parentParser || openInternalEntities); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + } + else { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + } + break; + case XML_ROLE_PARAM_ENTITY_NAME: +#ifdef XML_DTD + if (dtd->keepProcessing) { + const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next); + if (!name) + return XML_ERROR_NO_MEMORY; + declEntity = (ENTITY *)lookup(&dtd->paramEntities, + name, sizeof(ENTITY)); + if (!declEntity) + return XML_ERROR_NO_MEMORY; + if (declEntity->name != name) { + poolDiscard(&dtd->pool); + declEntity = NULL; + } + else { + poolFinish(&dtd->pool); + declEntity->publicId = NULL; + declEntity->is_param = XML_TRUE; + /* if we have a parent parser or are reading an internal parameter + entity, then the entity declaration is not considered "internal" + */ + declEntity->is_internal = !(parentParser || openInternalEntities); + if (entityDeclHandler) + handleDefault = XML_FALSE; + } + } + else { + poolDiscard(&dtd->pool); + declEntity = NULL; + } +#else /* not XML_DTD */ + declEntity = NULL; +#endif /* XML_DTD */ + break; + case XML_ROLE_NOTATION_NAME: + declNotationPublicId = NULL; + declNotationName = NULL; + if (notationDeclHandler) { + declNotationName = poolStoreString(&tempPool, enc, s, next); + if (!declNotationName) + return XML_ERROR_NO_MEMORY; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_PUBLIC_ID: + if (!XmlIsPublicId(enc, s, next, eventPP)) + return XML_ERROR_PUBLICID; + if (declNotationName) { /* means notationDeclHandler != NULL */ + XML_Char *tem = poolStoreString(&tempPool, + enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!tem) + return XML_ERROR_NO_MEMORY; + normalizePublicId(tem); + declNotationPublicId = tem; + poolFinish(&tempPool); + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_NOTATION_SYSTEM_ID: + if (declNotationName && notationDeclHandler) { + const XML_Char *systemId + = poolStoreString(&tempPool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!systemId) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + systemId, + declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&tempPool); + break; + case XML_ROLE_NOTATION_NO_SYSTEM_ID: + if (declNotationPublicId && notationDeclHandler) { + *eventEndPP = s; + notationDeclHandler(handlerArg, + declNotationName, + curBase, + 0, + declNotationPublicId); + handleDefault = XML_FALSE; + } + poolClear(&tempPool); + break; + case XML_ROLE_ERROR: + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: + /* PE references in internal subset are + not allowed within declarations. */ + return XML_ERROR_PARAM_ENTITY_REF; + case XML_TOK_XML_DECL: + return XML_ERROR_MISPLACED_XML_PI; + default: + return XML_ERROR_SYNTAX; + } +#ifdef XML_DTD + case XML_ROLE_IGNORE_SECT: + { + enum XML_Error result; + if (defaultHandler) + reportDefault(parser, enc, s, next); + handleDefault = XML_FALSE; + result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore); + if (result != XML_ERROR_NONE) + return result; + else if (!next) { + processor = ignoreSectionProcessor; + return result; + } + } + break; +#endif /* XML_DTD */ + case XML_ROLE_GROUP_OPEN: + if (prologState.level >= groupSize) { + if (groupSize) { + char *temp = (char *)REALLOC(groupConnector, groupSize *= 2); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + groupConnector = temp; + if (dtd->scaffIndex) { + int *temp = (int *)REALLOC(dtd->scaffIndex, + groupSize * sizeof(int)); + if (temp == NULL) + return XML_ERROR_NO_MEMORY; + dtd->scaffIndex = temp; + } + } + else { + groupConnector = (char *)MALLOC(groupSize = 32); + if (!groupConnector) + return XML_ERROR_NO_MEMORY; + } + } + groupConnector[prologState.level] = 0; + if (dtd->in_eldecl) { + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd->scaffIndex[dtd->scaffLevel] = myindex; + dtd->scaffLevel++; + dtd->scaffold[myindex].type = XML_CTYPE_SEQ; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + case XML_ROLE_GROUP_SEQUENCE: + if (groupConnector[prologState.level] == '|') + return XML_ERROR_SYNTAX; + groupConnector[prologState.level] = ','; + if (dtd->in_eldecl && elementDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_GROUP_CHOICE: + if (groupConnector[prologState.level] == ',') + return XML_ERROR_SYNTAX; + if (dtd->in_eldecl + && !groupConnector[prologState.level] + && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + != XML_CTYPE_MIXED) + ) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_CHOICE; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + groupConnector[prologState.level] = '|'; + break; + case XML_ROLE_PARAM_ENTITY_REF: +#ifdef XML_DTD + case XML_ROLE_INNER_PARAM_ENTITY_REF: + dtd->hasParamEntityRefs = XML_TRUE; + if (!paramEntityParsing) + dtd->keepProcessing = dtd->standalone; + else { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&dtd->pool, enc, + s + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + poolDiscard(&dtd->pool); + /* first, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal, + otherwise call the skipped entity handler + */ + if (prologState.documentEntity && + (dtd->standalone + ? !openInternalEntities + : !dtd->hasParamEntityRefs)) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + dtd->keepProcessing = dtd->standalone; + /* cannot report skipped entities in declarations */ + if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) { + skippedEntityHandler(handlerArg, name, 1); + handleDefault = XML_FALSE; + } + break; + } + if (entity->open) + return XML_ERROR_RECURSIVE_ENTITY_REF; + if (entity->textPtr) { + enum XML_Error result; + XML_Bool betweenDecl = + (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE); + result = processInternalEntity(parser, entity, betweenDecl); + if (result != XML_ERROR_NONE) + return result; + handleDefault = XML_FALSE; + break; + } + if (externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = XML_FALSE; + return XML_ERROR_EXTERNAL_ENTITY_HANDLING; + } + entity->open = XML_FALSE; + handleDefault = XML_FALSE; + if (!dtd->paramEntityRead) { + dtd->keepProcessing = dtd->standalone; + break; + } + } + else { + dtd->keepProcessing = dtd->standalone; + break; + } + } +#endif /* XML_DTD */ + if (!dtd->standalone && + notStandaloneHandler && + !notStandaloneHandler(handlerArg)) + return XML_ERROR_NOT_STANDALONE; + break; + + /* Element declaration stuff */ + + case XML_ROLE_ELEMENT_NAME: + if (elementDeclHandler) { + declElementType = getElementType(parser, enc, s, next); + if (!declElementType) + return XML_ERROR_NO_MEMORY; + dtd->scaffLevel = 0; + dtd->scaffCount = 0; + dtd->in_eldecl = XML_TRUE; + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ANY: + case XML_ROLE_CONTENT_EMPTY: + if (dtd->in_eldecl) { + if (elementDeclHandler) { + XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content)); + if (!content) + return XML_ERROR_NO_MEMORY; + content->quant = XML_CQUANT_NONE; + content->name = NULL; + content->numchildren = 0; + content->children = NULL; + content->type = ((role == XML_ROLE_CONTENT_ANY) ? + XML_CTYPE_ANY : + XML_CTYPE_EMPTY); + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, content); + handleDefault = XML_FALSE; + } + dtd->in_eldecl = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_PCDATA: + if (dtd->in_eldecl) { + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type + = XML_CTYPE_MIXED; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_CONTENT_ELEMENT: + quant = XML_CQUANT_NONE; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_OPT: + quant = XML_CQUANT_OPT; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_REP: + quant = XML_CQUANT_REP; + goto elementContent; + case XML_ROLE_CONTENT_ELEMENT_PLUS: + quant = XML_CQUANT_PLUS; + elementContent: + if (dtd->in_eldecl) { + ELEMENT_TYPE *el; + const XML_Char *name; + int nameLen; + const char *nxt = (quant == XML_CQUANT_NONE + ? next + : next - enc->minBytesPerChar); + int myindex = nextScaffoldPart(parser); + if (myindex < 0) + return XML_ERROR_NO_MEMORY; + dtd->scaffold[myindex].type = XML_CTYPE_NAME; + dtd->scaffold[myindex].quant = quant; + el = getElementType(parser, enc, s, nxt); + if (!el) + return XML_ERROR_NO_MEMORY; + name = el->name; + dtd->scaffold[myindex].name = name; + nameLen = 0; + for (; name[nameLen++]; ); + dtd->contentStringLen += nameLen; + if (elementDeclHandler) + handleDefault = XML_FALSE; + } + break; + + case XML_ROLE_GROUP_CLOSE: + quant = XML_CQUANT_NONE; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_OPT: + quant = XML_CQUANT_OPT; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_REP: + quant = XML_CQUANT_REP; + goto closeGroup; + case XML_ROLE_GROUP_CLOSE_PLUS: + quant = XML_CQUANT_PLUS; + closeGroup: + if (dtd->in_eldecl) { + if (elementDeclHandler) + handleDefault = XML_FALSE; + dtd->scaffLevel--; + dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant; + if (dtd->scaffLevel == 0) { + if (!handleDefault) { + XML_Content *model = build_model(parser); + if (!model) + return XML_ERROR_NO_MEMORY; + *eventEndPP = s; + elementDeclHandler(handlerArg, declElementType->name, model); + } + dtd->in_eldecl = XML_FALSE; + dtd->contentStringLen = 0; + } + } + break; + /* End element declaration stuff */ + + case XML_ROLE_PI: + if (!reportProcessingInstruction(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_COMMENT: + if (!reportComment(parser, enc, s, next)) + return XML_ERROR_NO_MEMORY; + handleDefault = XML_FALSE; + break; + case XML_ROLE_NONE: + switch (tok) { + case XML_TOK_BOM: + handleDefault = XML_FALSE; + break; + } + break; + case XML_ROLE_DOCTYPE_NONE: + if (startDoctypeDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ENTITY_NONE: + if (dtd->keepProcessing && entityDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_NOTATION_NONE: + if (notationDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ATTLIST_NONE: + if (dtd->keepProcessing && attlistDeclHandler) + handleDefault = XML_FALSE; + break; + case XML_ROLE_ELEMENT_NONE: + if (elementDeclHandler) + handleDefault = XML_FALSE; + break; + } /* end of big switch */ + + if (handleDefault && defaultHandler) + reportDefault(parser, enc, s, next); + + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: + s = next; + tok = XmlPrologTok(enc, s, end, &next); + } + } + /* not reached */ +} + +static enum XML_Error PTRCALL +epilogProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + processor = epilogProcessor; + eventPtr = s; + for (;;) { + const char *next = NULL; + int tok = XmlPrologTok(encoding, s, end, &next); + eventEndPtr = next; + switch (tok) { + /* report partial linebreak - it might be the last token */ + case -XML_TOK_PROLOG_S: + if (defaultHandler) { + reportDefault(parser, encoding, s, next); + if (ps_parsing == XML_FINISHED) + return XML_ERROR_ABORTED; + } + *nextPtr = next; + return XML_ERROR_NONE; + case XML_TOK_NONE: + *nextPtr = s; + return XML_ERROR_NONE; + case XML_TOK_PROLOG_S: + if (defaultHandler) + reportDefault(parser, encoding, s, next); + break; + case XML_TOK_PI: + if (!reportProcessingInstruction(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_COMMENT: + if (!reportComment(parser, encoding, s, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_INVALID: + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (!ps_finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_UNCLOSED_TOKEN; + case XML_TOK_PARTIAL_CHAR: + if (!ps_finalBuffer) { + *nextPtr = s; + return XML_ERROR_NONE; + } + return XML_ERROR_PARTIAL_CHAR; + default: + return XML_ERROR_JUNK_AFTER_DOC_ELEMENT; + } + eventPtr = s = next; + switch (ps_parsing) { + case XML_SUSPENDED: + *nextPtr = next; + return XML_ERROR_NONE; + case XML_FINISHED: + return XML_ERROR_ABORTED; + default: ; + } + } +} + +static enum XML_Error +processInternalEntity(XML_Parser parser, ENTITY *entity, + XML_Bool betweenDecl) +{ + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity; + + if (freeInternalEntities) { + openEntity = freeInternalEntities; + freeInternalEntities = openEntity->next; + } + else { + openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY)); + if (!openEntity) + return XML_ERROR_NO_MEMORY; + } + entity->open = XML_TRUE; + entity->processed = 0; + openEntity->next = openInternalEntities; + openInternalEntities = openEntity; + openEntity->entity = entity; + openEntity->startTagLevel = tagLevel; + openEntity->betweenDecl = betweenDecl; + openEntity->internalEventPtr = NULL; + openEntity->internalEventEndPtr = NULL; + textStart = (char *)entity->textPtr; + textEnd = (char *)(entity->textPtr + entity->textLen); + +#ifdef XML_DTD + if (entity->is_param) { + int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + next, &next, XML_FALSE); + } + else +#endif /* XML_DTD */ + result = doContent(parser, tagLevel, internalEncoding, textStart, + textEnd, &next, XML_FALSE); + + if (result == XML_ERROR_NONE) { + if (textEnd != next && ps_parsing == XML_SUSPENDED) { + entity->processed = (int)(next - textStart); + processor = internalEntityProcessor; + } + else { + entity->open = XML_FALSE; + openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + } + return result; +} + +static enum XML_Error PTRCALL +internalEntityProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + ENTITY *entity; + const char *textStart, *textEnd; + const char *next; + enum XML_Error result; + OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities; + if (!openEntity) + return XML_ERROR_UNEXPECTED_STATE; + + entity = openEntity->entity; + textStart = ((char *)entity->textPtr) + entity->processed; + textEnd = (char *)(entity->textPtr + entity->textLen); + +#ifdef XML_DTD + if (entity->is_param) { + int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next); + result = doProlog(parser, internalEncoding, textStart, textEnd, tok, + next, &next, XML_FALSE); + } + else +#endif /* XML_DTD */ + result = doContent(parser, openEntity->startTagLevel, internalEncoding, + textStart, textEnd, &next, XML_FALSE); + + if (result != XML_ERROR_NONE) + return result; + else if (textEnd != next && ps_parsing == XML_SUSPENDED) { + entity->processed = (int)(next - (char *)entity->textPtr); + return result; + } + else { + entity->open = XML_FALSE; + openInternalEntities = openEntity->next; + /* put openEntity back in list of free instances */ + openEntity->next = freeInternalEntities; + freeInternalEntities = openEntity; + } + +#ifdef XML_DTD + if (entity->is_param) { + int tok; + processor = prologProcessor; + tok = XmlPrologTok(encoding, s, end, &next); + return doProlog(parser, encoding, s, end, tok, next, nextPtr, + (XML_Bool)!ps_finalBuffer); + } + else +#endif /* XML_DTD */ + { + processor = contentProcessor; + /* see externalEntityContentProcessor vs contentProcessor */ + return doContent(parser, parentParser ? 1 : 0, encoding, s, end, + nextPtr, (XML_Bool)!ps_finalBuffer); + } +} + +static enum XML_Error PTRCALL +errorProcessor(XML_Parser parser, + const char *s, + const char *end, + const char **nextPtr) +{ + return errorCode; +} + +static enum XML_Error +storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, + end, pool); + if (result) + return result; + if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20) + poolChop(pool); + if (!poolAppendChar(pool, XML_T('\0'))) + return XML_ERROR_NO_MEMORY; + return XML_ERROR_NONE; +} + +static enum XML_Error +appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata, + const char *ptr, const char *end, + STRING_POOL *pool) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + for (;;) { + const char *next; + int tok = XmlAttributeValueTok(enc, ptr, end, &next); + switch (tok) { + case XML_TOK_NONE: + return XML_ERROR_NONE; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_INVALID_TOKEN; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, ptr); + if (n < 0) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + if (!isCdata + && n == 0x20 /* space */ + && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BAD_CHAR_REF; + } + for (i = 0; i < n; i++) { + if (!poolAppendChar(pool, buf[i])) + return XML_ERROR_NO_MEMORY; + } + } + break; + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, ptr, next)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_TRAILING_CR: + next = ptr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_ATTRIBUTE_VALUE_S: + case XML_TOK_DATA_NEWLINE: + if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20)) + break; + if (!poolAppendChar(pool, 0x20)) + return XML_ERROR_NO_MEMORY; + break; + case XML_TOK_ENTITY_REF: + { + const XML_Char *name; + ENTITY *entity; + char checkEntityDecl; + XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (ch) { + if (!poolAppendChar(pool, ch)) + return XML_ERROR_NO_MEMORY; + break; + } + name = poolStoreString(&temp2Pool, enc, + ptr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) + return XML_ERROR_NO_MEMORY; + entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0); + poolDiscard(&temp2Pool); + /* First, determine if a check for an existing declaration is needed; + if yes, check that the entity exists, and that it is internal. + */ + if (pool == &dtd->pool) /* are we called from prolog? */ + checkEntityDecl = +#ifdef XML_DTD + prologState.documentEntity && +#endif /* XML_DTD */ + (dtd->standalone + ? !openInternalEntities + : !dtd->hasParamEntityRefs); + else /* if (pool == &tempPool): we are called from content */ + checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone; + if (checkEntityDecl) { + if (!entity) + return XML_ERROR_UNDEFINED_ENTITY; + else if (!entity->is_internal) + return XML_ERROR_ENTITY_DECLARED_IN_PE; + } + else if (!entity) { + /* Cannot report skipped entity here - see comments on + skippedEntityHandler. + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + */ + /* Cannot call the default handler because this would be + out of sync with the call to the startElementHandler. + if ((pool == &tempPool) && defaultHandler) + reportDefault(parser, enc, ptr, next); + */ + break; + } + if (entity->open) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_RECURSIVE_ENTITY_REF; + } + if (entity->notation) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_BINARY_ENTITY_REF; + } + if (!entity->textPtr) { + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF; + } + else { + enum XML_Error result; + const XML_Char *textEnd = entity->textPtr + entity->textLen; + entity->open = XML_TRUE; + result = appendAttributeValue(parser, internalEncoding, isCdata, + (char *)entity->textPtr, + (char *)textEnd, pool); + entity->open = XML_FALSE; + if (result) + return result; + } + } + break; + default: + if (enc == encoding) + eventPtr = ptr; + return XML_ERROR_UNEXPECTED_STATE; + } + ptr = next; + } + /* not reached */ +} + +static enum XML_Error +storeEntityValue(XML_Parser parser, + const ENCODING *enc, + const char *entityTextPtr, + const char *entityTextEnd) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + STRING_POOL *pool = &(dtd->entityValuePool); + enum XML_Error result = XML_ERROR_NONE; +#ifdef XML_DTD + int oldInEntityValue = prologState.inEntityValue; + prologState.inEntityValue = 1; +#endif /* XML_DTD */ + /* never return Null for the value argument in EntityDeclHandler, + since this would indicate an external entity; therefore we + have to make sure that entityValuePool.start is not null */ + if (!pool->blocks) { + if (!poolGrow(pool)) + return XML_ERROR_NO_MEMORY; + } + + for (;;) { + const char *next; + int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next); + switch (tok) { + case XML_TOK_PARAM_ENTITY_REF: +#ifdef XML_DTD + if (isParamEntity || enc != encoding) { + const XML_Char *name; + ENTITY *entity; + name = poolStoreString(&tempPool, enc, + entityTextPtr + enc->minBytesPerChar, + next - enc->minBytesPerChar); + if (!name) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0); + poolDiscard(&tempPool); + if (!entity) { + /* not a well-formedness error - see XML 1.0: WFC Entity Declared */ + /* cannot report skipped entity here - see comments on + skippedEntityHandler + if (skippedEntityHandler) + skippedEntityHandler(handlerArg, name, 0); + */ + dtd->keepProcessing = dtd->standalone; + goto endEntityValue; + } + if (entity->open) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_RECURSIVE_ENTITY_REF; + goto endEntityValue; + } + if (entity->systemId) { + if (externalEntityRefHandler) { + dtd->paramEntityRead = XML_FALSE; + entity->open = XML_TRUE; + if (!externalEntityRefHandler(externalEntityRefHandlerArg, + 0, + entity->base, + entity->systemId, + entity->publicId)) { + entity->open = XML_FALSE; + result = XML_ERROR_EXTERNAL_ENTITY_HANDLING; + goto endEntityValue; + } + entity->open = XML_FALSE; + if (!dtd->paramEntityRead) + dtd->keepProcessing = dtd->standalone; + } + else + dtd->keepProcessing = dtd->standalone; + } + else { + entity->open = XML_TRUE; + result = storeEntityValue(parser, + internalEncoding, + (char *)entity->textPtr, + (char *)(entity->textPtr + + entity->textLen)); + entity->open = XML_FALSE; + if (result) + goto endEntityValue; + } + break; + } +#endif /* XML_DTD */ + /* In the internal subset, PE references are not legal + within markup declarations, e.g entity values in this case. */ + eventPtr = entityTextPtr; + result = XML_ERROR_PARAM_ENTITY_REF; + goto endEntityValue; + case XML_TOK_NONE: + result = XML_ERROR_NONE; + goto endEntityValue; + case XML_TOK_ENTITY_REF: + case XML_TOK_DATA_CHARS: + if (!poolAppend(pool, enc, entityTextPtr, next)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + break; + case XML_TOK_TRAILING_CR: + next = entityTextPtr + enc->minBytesPerChar; + /* fall through */ + case XML_TOK_DATA_NEWLINE: + if (pool->end == pool->ptr && !poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = 0xA; + break; + case XML_TOK_CHAR_REF: + { + XML_Char buf[XML_ENCODE_MAX]; + int i; + int n = XmlCharRefNumber(enc, entityTextPtr); + if (n < 0) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_BAD_CHAR_REF; + goto endEntityValue; + } + n = XmlEncode(n, (ICHAR *)buf); + if (!n) { + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_BAD_CHAR_REF; + goto endEntityValue; + } + for (i = 0; i < n; i++) { + if (pool->end == pool->ptr && !poolGrow(pool)) { + result = XML_ERROR_NO_MEMORY; + goto endEntityValue; + } + *(pool->ptr)++ = buf[i]; + } + } + break; + case XML_TOK_PARTIAL: + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + case XML_TOK_INVALID: + if (enc == encoding) + eventPtr = next; + result = XML_ERROR_INVALID_TOKEN; + goto endEntityValue; + default: + if (enc == encoding) + eventPtr = entityTextPtr; + result = XML_ERROR_UNEXPECTED_STATE; + goto endEntityValue; + } + entityTextPtr = next; + } +endEntityValue: +#ifdef XML_DTD + prologState.inEntityValue = oldInEntityValue; +#endif /* XML_DTD */ + return result; +} + +static void FASTCALL +normalizeLines(XML_Char *s) +{ + XML_Char *p; + for (;; s++) { + if (*s == XML_T('\0')) + return; + if (*s == 0xD) + break; + } + p = s; + do { + if (*s == 0xD) { + *p++ = 0xA; + if (*++s == 0xA) + s++; + } + else + *p++ = *s++; + } while (*s); + *p = XML_T('\0'); +} + +static int +reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + const XML_Char *target; + XML_Char *data; + const char *tem; + if (!processingInstructionHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + start += enc->minBytesPerChar * 2; + tem = start + XmlNameLength(enc, start); + target = poolStoreString(&tempPool, enc, start, tem); + if (!target) + return 0; + poolFinish(&tempPool); + data = poolStoreString(&tempPool, enc, + XmlSkipS(enc, tem), + end - enc->minBytesPerChar*2); + if (!data) + return 0; + normalizeLines(data); + processingInstructionHandler(handlerArg, target, data); + poolClear(&tempPool); + return 1; +} + +static int +reportComment(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + XML_Char *data; + if (!commentHandler) { + if (defaultHandler) + reportDefault(parser, enc, start, end); + return 1; + } + data = poolStoreString(&tempPool, + enc, + start + enc->minBytesPerChar * 4, + end - enc->minBytesPerChar * 3); + if (!data) + return 0; + normalizeLines(data); + commentHandler(handlerArg, data); + poolClear(&tempPool); + return 1; +} + +static void +reportDefault(XML_Parser parser, const ENCODING *enc, + const char *s, const char *end) +{ + if (MUST_CONVERT(enc, s)) { + const char **eventPP; + const char **eventEndPP; + if (enc == encoding) { + eventPP = &eventPtr; + eventEndPP = &eventEndPtr; + } + else { + eventPP = &(openInternalEntities->internalEventPtr); + eventEndPP = &(openInternalEntities->internalEventEndPtr); + } + do { + ICHAR *dataPtr = (ICHAR *)dataBuf; + XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd); + *eventEndPP = s; + defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf)); + *eventPP = s; + } while (s != end); + } + else + defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s)); +} + + +static int +defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, + XML_Bool isId, const XML_Char *value, XML_Parser parser) +{ + DEFAULT_ATTRIBUTE *att; + if (value || isId) { + /* The handling of default attributes gets messed up if we have + a default which duplicates a non-default. */ + int i; + for (i = 0; i < type->nDefaultAtts; i++) + if (attId == type->defaultAtts[i].id) + return 1; + if (isId && !type->idAtt && !attId->xmlns) + type->idAtt = attId; + } + if (type->nDefaultAtts == type->allocDefaultAtts) { + if (type->allocDefaultAtts == 0) { + type->allocDefaultAtts = 8; + type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts + * sizeof(DEFAULT_ATTRIBUTE)); + if (!type->defaultAtts) + return 0; + } + else { + DEFAULT_ATTRIBUTE *temp; + int count = type->allocDefaultAtts * 2; + temp = (DEFAULT_ATTRIBUTE *) + REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE))); + if (temp == NULL) + return 0; + type->allocDefaultAtts = count; + type->defaultAtts = temp; + } + } + att = type->defaultAtts + type->nDefaultAtts; + att->id = attId; + att->value = value; + att->isCdata = isCdata; + if (!isCdata) + attId->maybeTokenized = XML_TRUE; + type->nDefaultAtts += 1; + return 1; +} + +static int +setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *name; + for (name = elementType->name; *name; name++) { + if (*name == XML_T(':')) { + PREFIX *prefix; + const XML_Char *s; + for (s = elementType->name; s != name; s++) { + if (!poolAppendChar(&dtd->pool, *s)) + return 0; + } + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return 0; + prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + sizeof(PREFIX)); + if (!prefix) + return 0; + if (prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + elementType->prefix = prefix; + + } + } + return 1; +} + +static ATTRIBUTE_ID * +getAttributeId(XML_Parser parser, const ENCODING *enc, + const char *start, const char *end) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + ATTRIBUTE_ID *id; + const XML_Char *name; + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + name = poolStoreString(&dtd->pool, enc, start, end); + if (!name) + return NULL; + /* skip quotation mark - its storage will be re-used (like in name[-1]) */ + ++name; + id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID)); + if (!id) + return NULL; + if (id->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (!ns) + ; + else if (name[0] == XML_T('x') + && name[1] == XML_T('m') + && name[2] == XML_T('l') + && name[3] == XML_T('n') + && name[4] == XML_T('s') + && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) { + if (name[5] == XML_T('\0')) + id->prefix = &dtd->defaultPrefix; + else + id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX)); + id->xmlns = XML_TRUE; + } + else { + int i; + for (i = 0; name[i]; i++) { + /* attributes without prefix are *not* in the default namespace */ + if (name[i] == XML_T(':')) { + int j; + for (j = 0; j < i; j++) { + if (!poolAppendChar(&dtd->pool, name[j])) + return NULL; + } + if (!poolAppendChar(&dtd->pool, XML_T('\0'))) + return NULL; + id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool), + sizeof(PREFIX)); + if (!id->prefix) + return NULL; + if (id->prefix->name == poolStart(&dtd->pool)) + poolFinish(&dtd->pool); + else + poolDiscard(&dtd->pool); + break; + } + } + } + } + return id; +} + +#define CONTEXT_SEP XML_T('\f') + +static const XML_Char * +getContext(XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + HASH_TABLE_ITER iter; + XML_Bool needSep = XML_FALSE; + + if (dtd->defaultPrefix.binding) { + int i; + int len; + if (!poolAppendChar(&tempPool, XML_T('='))) + return NULL; + len = dtd->defaultPrefix.binding->uriLen; + if (namespaceSeparator) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) + return NULL; + needSep = XML_TRUE; + } + + hashTableIterInit(&iter, &(dtd->prefixes)); + for (;;) { + int i; + int len; + const XML_Char *s; + PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter); + if (!prefix) + break; + if (!prefix->binding) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return NULL; + for (s = prefix->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return NULL; + if (!poolAppendChar(&tempPool, XML_T('='))) + return NULL; + len = prefix->binding->uriLen; + if (namespaceSeparator) + len--; + for (i = 0; i < len; i++) + if (!poolAppendChar(&tempPool, prefix->binding->uri[i])) + return NULL; + needSep = XML_TRUE; + } + + + hashTableIterInit(&iter, &(dtd->generalEntities)); + for (;;) { + const XML_Char *s; + ENTITY *e = (ENTITY *)hashTableIterNext(&iter); + if (!e) + break; + if (!e->open) + continue; + if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP)) + return NULL; + for (s = e->name; *s; s++) + if (!poolAppendChar(&tempPool, *s)) + return 0; + needSep = XML_TRUE; + } + + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return NULL; + return tempPool.start; +} + +static XML_Bool +setContext(XML_Parser parser, const XML_Char *context) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *s = context; + + while (*context != XML_T('\0')) { + if (*s == CONTEXT_SEP || *s == XML_T('\0')) { + ENTITY *e; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0); + if (e) + e->open = XML_TRUE; + if (*s != XML_T('\0')) + s++; + context = s; + poolDiscard(&tempPool); + } + else if (*s == XML_T('=')) { + PREFIX *prefix; + if (poolLength(&tempPool) == 0) + prefix = &dtd->defaultPrefix; + else { + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool), + sizeof(PREFIX)); + if (!prefix) + return XML_FALSE; + if (prefix->name == poolStart(&tempPool)) { + prefix->name = poolCopyString(&dtd->pool, prefix->name); + if (!prefix->name) + return XML_FALSE; + } + poolDiscard(&tempPool); + } + for (context = s + 1; + *context != CONTEXT_SEP && *context != XML_T('\0'); + context++) + if (!poolAppendChar(&tempPool, *context)) + return XML_FALSE; + if (!poolAppendChar(&tempPool, XML_T('\0'))) + return XML_FALSE; + if (addBinding(parser, prefix, NULL, poolStart(&tempPool), + &inheritedBindings) != XML_ERROR_NONE) + return XML_FALSE; + poolDiscard(&tempPool); + if (*context != XML_T('\0')) + ++context; + s = context; + } + else { + if (!poolAppendChar(&tempPool, *s)) + return XML_FALSE; + s++; + } + } + return XML_TRUE; +} + +static void FASTCALL +normalizePublicId(XML_Char *publicId) +{ + XML_Char *p = publicId; + XML_Char *s; + for (s = publicId; *s; s++) { + switch (*s) { + case 0x20: + case 0xD: + case 0xA: + if (p != publicId && p[-1] != 0x20) + *p++ = 0x20; + break; + default: + *p++ = *s; + } + } + if (p != publicId && p[-1] == 0x20) + --p; + *p = XML_T('\0'); +} + +static DTD * +dtdCreate(const XML_Memory_Handling_Suite *ms) +{ + DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD)); + if (p == NULL) + return p; + poolInit(&(p->pool), ms); + poolInit(&(p->entityValuePool), ms); + hashTableInit(&(p->generalEntities), ms); + hashTableInit(&(p->elementTypes), ms); + hashTableInit(&(p->attributeIds), ms); + hashTableInit(&(p->prefixes), ms); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableInit(&(p->paramEntities), ms); +#endif /* XML_DTD */ + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + p->scaffIndex = NULL; + p->scaffold = NULL; + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; + return p; +} + +static void +dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableClear(&(p->generalEntities)); +#ifdef XML_DTD + p->paramEntityRead = XML_FALSE; + hashTableClear(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableClear(&(p->elementTypes)); + hashTableClear(&(p->attributeIds)); + hashTableClear(&(p->prefixes)); + poolClear(&(p->pool)); + poolClear(&(p->entityValuePool)); + p->defaultPrefix.name = NULL; + p->defaultPrefix.binding = NULL; + + p->in_eldecl = XML_FALSE; + + ms->free_fcn(p->scaffIndex); + p->scaffIndex = NULL; + ms->free_fcn(p->scaffold); + p->scaffold = NULL; + + p->scaffLevel = 0; + p->scaffSize = 0; + p->scaffCount = 0; + p->contentStringLen = 0; + + p->keepProcessing = XML_TRUE; + p->hasParamEntityRefs = XML_FALSE; + p->standalone = XML_FALSE; +} + +static void +dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + hashTableIterInit(&iter, &(p->elementTypes)); + for (;;) { + ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!e) + break; + if (e->allocDefaultAtts != 0) + ms->free_fcn(e->defaultAtts); + } + hashTableDestroy(&(p->generalEntities)); +#ifdef XML_DTD + hashTableDestroy(&(p->paramEntities)); +#endif /* XML_DTD */ + hashTableDestroy(&(p->elementTypes)); + hashTableDestroy(&(p->attributeIds)); + hashTableDestroy(&(p->prefixes)); + poolDestroy(&(p->pool)); + poolDestroy(&(p->entityValuePool)); + if (isDocEntity) { + ms->free_fcn(p->scaffIndex); + ms->free_fcn(p->scaffold); + } + ms->free_fcn(p); +} + +/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise. + The new DTD has already been initialized. +*/ +static int +dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms) +{ + HASH_TABLE_ITER iter; + + /* Copy the prefix table. */ + + hashTableIterInit(&iter, &(oldDtd->prefixes)); + for (;;) { + const XML_Char *name; + const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter); + if (!oldP) + break; + name = poolCopyString(&(newDtd->pool), oldP->name); + if (!name) + return 0; + if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX))) + return 0; + } + + hashTableIterInit(&iter, &(oldDtd->attributeIds)); + + /* Copy the attribute id table. */ + + for (;;) { + ATTRIBUTE_ID *newA; + const XML_Char *name; + const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter); + + if (!oldA) + break; + /* Remember to allocate the scratch byte before the name. */ + if (!poolAppendChar(&(newDtd->pool), XML_T('\0'))) + return 0; + name = poolCopyString(&(newDtd->pool), oldA->name); + if (!name) + return 0; + ++name; + newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, + sizeof(ATTRIBUTE_ID)); + if (!newA) + return 0; + newA->maybeTokenized = oldA->maybeTokenized; + if (oldA->prefix) { + newA->xmlns = oldA->xmlns; + if (oldA->prefix == &oldDtd->defaultPrefix) + newA->prefix = &newDtd->defaultPrefix; + else + newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + oldA->prefix->name, 0); + } + } + + /* Copy the element type table. */ + + hashTableIterInit(&iter, &(oldDtd->elementTypes)); + + for (;;) { + int i; + ELEMENT_TYPE *newE; + const XML_Char *name; + const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(&(newDtd->pool), oldE->name); + if (!name) + return 0; + newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, + sizeof(ELEMENT_TYPE)); + if (!newE) + return 0; + if (oldE->nDefaultAtts) { + newE->defaultAtts = (DEFAULT_ATTRIBUTE *) + ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE)); + if (!newE->defaultAtts) { + ms->free_fcn(newE); + return 0; + } + } + if (oldE->idAtt) + newE->idAtt = (ATTRIBUTE_ID *) + lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0); + newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts; + if (oldE->prefix) + newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), + oldE->prefix->name, 0); + for (i = 0; i < newE->nDefaultAtts; i++) { + newE->defaultAtts[i].id = (ATTRIBUTE_ID *) + lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; + if (oldE->defaultAtts[i].value) { + newE->defaultAtts[i].value + = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value); + if (!newE->defaultAtts[i].value) + return 0; + } + else + newE->defaultAtts[i].value = NULL; + } + } + + /* Copy the entity tables. */ + if (!copyEntityTable(&(newDtd->generalEntities), + &(newDtd->pool), + &(oldDtd->generalEntities))) + return 0; + +#ifdef XML_DTD + if (!copyEntityTable(&(newDtd->paramEntities), + &(newDtd->pool), + &(oldDtd->paramEntities))) + return 0; + newDtd->paramEntityRead = oldDtd->paramEntityRead; +#endif /* XML_DTD */ + + newDtd->keepProcessing = oldDtd->keepProcessing; + newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs; + newDtd->standalone = oldDtd->standalone; + + /* Don't want deep copying for scaffolding */ + newDtd->in_eldecl = oldDtd->in_eldecl; + newDtd->scaffold = oldDtd->scaffold; + newDtd->contentStringLen = oldDtd->contentStringLen; + newDtd->scaffSize = oldDtd->scaffSize; + newDtd->scaffLevel = oldDtd->scaffLevel; + newDtd->scaffIndex = oldDtd->scaffIndex; + + return 1; +} /* End dtdCopy */ + +static int +copyEntityTable(HASH_TABLE *newTable, + STRING_POOL *newPool, + const HASH_TABLE *oldTable) +{ + HASH_TABLE_ITER iter; + const XML_Char *cachedOldBase = NULL; + const XML_Char *cachedNewBase = NULL; + + hashTableIterInit(&iter, oldTable); + + for (;;) { + ENTITY *newE; + const XML_Char *name; + const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter); + if (!oldE) + break; + name = poolCopyString(newPool, oldE->name); + if (!name) + return 0; + newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY)); + if (!newE) + return 0; + if (oldE->systemId) { + const XML_Char *tem = poolCopyString(newPool, oldE->systemId); + if (!tem) + return 0; + newE->systemId = tem; + if (oldE->base) { + if (oldE->base == cachedOldBase) + newE->base = cachedNewBase; + else { + cachedOldBase = oldE->base; + tem = poolCopyString(newPool, cachedOldBase); + if (!tem) + return 0; + cachedNewBase = newE->base = tem; + } + } + if (oldE->publicId) { + tem = poolCopyString(newPool, oldE->publicId); + if (!tem) + return 0; + newE->publicId = tem; + } + } + else { + const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, + oldE->textLen); + if (!tem) + return 0; + newE->textPtr = tem; + newE->textLen = oldE->textLen; + } + if (oldE->notation) { + const XML_Char *tem = poolCopyString(newPool, oldE->notation); + if (!tem) + return 0; + newE->notation = tem; + } + newE->is_param = oldE->is_param; + newE->is_internal = oldE->is_internal; + } + return 1; +} + +#define INIT_POWER 6 + +static XML_Bool FASTCALL +keyeq(KEY s1, KEY s2) +{ + for (; *s1 == *s2; s1++, s2++) + if (*s1 == 0) + return XML_TRUE; + return XML_FALSE; +} + +static unsigned long FASTCALL +hash(KEY s) +{ + unsigned long h = 0; + while (*s) + h = CHAR_HASH(h, *s++); + return h; +} + +static NAMED * +lookup(HASH_TABLE *table, KEY name, size_t createSize) +{ + size_t i; + if (table->size == 0) { + size_t tsize; + if (!createSize) + return NULL; + table->power = INIT_POWER; + /* table->size is a power of 2 */ + table->size = (size_t)1 << INIT_POWER; + tsize = table->size * sizeof(NAMED *); + table->v = (NAMED **)table->mem->malloc_fcn(tsize); + if (!table->v) { + table->size = 0; + return NULL; + } + memset(table->v, 0, tsize); + i = hash(name) & ((unsigned long)table->size - 1); + } + else { + unsigned long h = hash(name); + unsigned long mask = (unsigned long)table->size - 1; + unsigned char step = 0; + i = h & mask; + while (table->v[i]) { + if (keyeq(name, table->v[i]->name)) + return table->v[i]; + if (!step) + step = PROBE_STEP(h, mask, table->power); + i < step ? (i += table->size - step) : (i -= step); + } + if (!createSize) + return NULL; + + /* check for overflow (table is half full) */ + if (table->used >> (table->power - 1)) { + unsigned char newPower = table->power + 1; + size_t newSize = (size_t)1 << newPower; + unsigned long newMask = (unsigned long)newSize - 1; + size_t tsize = newSize * sizeof(NAMED *); + NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize); + if (!newV) + return NULL; + memset(newV, 0, tsize); + for (i = 0; i < table->size; i++) + if (table->v[i]) { + unsigned long newHash = hash(table->v[i]->name); + size_t j = newHash & newMask; + step = 0; + while (newV[j]) { + if (!step) + step = PROBE_STEP(newHash, newMask, newPower); + j < step ? (j += newSize - step) : (j -= step); + } + newV[j] = table->v[i]; + } + table->mem->free_fcn(table->v); + table->v = newV; + table->power = newPower; + table->size = newSize; + i = h & newMask; + step = 0; + while (table->v[i]) { + if (!step) + step = PROBE_STEP(h, newMask, newPower); + i < step ? (i += newSize - step) : (i -= step); + } + } + } + table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize); + if (!table->v[i]) + return NULL; + memset(table->v[i], 0, createSize); + table->v[i]->name = name; + (table->used)++; + return table->v[i]; +} + +static void FASTCALL +hashTableClear(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) { + table->mem->free_fcn(table->v[i]); + table->v[i] = NULL; + } + table->used = 0; +} + +static void FASTCALL +hashTableDestroy(HASH_TABLE *table) +{ + size_t i; + for (i = 0; i < table->size; i++) + table->mem->free_fcn(table->v[i]); + table->mem->free_fcn(table->v); +} + +static void FASTCALL +hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms) +{ + p->power = 0; + p->size = 0; + p->used = 0; + p->v = NULL; + p->mem = ms; +} + +static void FASTCALL +hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table) +{ + iter->p = table->v; + iter->end = iter->p + table->size; +} + +static NAMED * FASTCALL +hashTableIterNext(HASH_TABLE_ITER *iter) +{ + while (iter->p != iter->end) { + NAMED *tem = *(iter->p)++; + if (tem) + return tem; + } + return NULL; +} + +static void FASTCALL +poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms) +{ + pool->blocks = NULL; + pool->freeBlocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; + pool->mem = ms; +} + +static void FASTCALL +poolClear(STRING_POOL *pool) +{ + if (!pool->freeBlocks) + pool->freeBlocks = pool->blocks; + else { + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + p->next = pool->freeBlocks; + pool->freeBlocks = p; + p = tem; + } + } + pool->blocks = NULL; + pool->start = NULL; + pool->ptr = NULL; + pool->end = NULL; +} + +static void FASTCALL +poolDestroy(STRING_POOL *pool) +{ + BLOCK *p = pool->blocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } + p = pool->freeBlocks; + while (p) { + BLOCK *tem = p->next; + pool->mem->free_fcn(p); + p = tem; + } +} + +static XML_Char * +poolAppend(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!pool->ptr && !poolGrow(pool)) + return NULL; + for (;;) { + XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end); + if (ptr == end) + break; + if (!poolGrow(pool)) + return NULL; + } + return pool->start; +} + +static const XML_Char * FASTCALL +poolCopyString(STRING_POOL *pool, const XML_Char *s) +{ + do { + if (!poolAppendChar(pool, *s)) + return NULL; + } while (*s++); + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * +poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n) +{ + if (!pool->ptr && !poolGrow(pool)) + return NULL; + for (; n > 0; --n, s++) { + if (!poolAppendChar(pool, *s)) + return NULL; + } + s = pool->start; + poolFinish(pool); + return s; +} + +static const XML_Char * FASTCALL +poolAppendString(STRING_POOL *pool, const XML_Char *s) +{ + while (*s) { + if (!poolAppendChar(pool, *s)) + return NULL; + s++; + } + return pool->start; +} + +static XML_Char * +poolStoreString(STRING_POOL *pool, const ENCODING *enc, + const char *ptr, const char *end) +{ + if (!poolAppend(pool, enc, ptr, end)) + return NULL; + if (pool->ptr == pool->end && !poolGrow(pool)) + return NULL; + *(pool->ptr)++ = 0; + return pool->start; +} + +static XML_Bool FASTCALL +poolGrow(STRING_POOL *pool) +{ + if (pool->freeBlocks) { + if (pool->start == 0) { + pool->blocks = pool->freeBlocks; + pool->freeBlocks = pool->freeBlocks->next; + pool->blocks->next = NULL; + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + pool->ptr = pool->start; + return XML_TRUE; + } + if (pool->end - pool->start < pool->freeBlocks->size) { + BLOCK *tem = pool->freeBlocks->next; + pool->freeBlocks->next = pool->blocks; + pool->blocks = pool->freeBlocks; + pool->freeBlocks = tem; + memcpy(pool->blocks->s, pool->start, + (pool->end - pool->start) * sizeof(XML_Char)); + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + pool->blocks->size; + return XML_TRUE; + } + } + if (pool->blocks && pool->start == pool->blocks->s) { + int blockSize = (int)(pool->end - pool->start)*2; + pool->blocks = (BLOCK *) + pool->mem->realloc_fcn(pool->blocks, + (offsetof(BLOCK, s) + + blockSize * sizeof(XML_Char))); + if (pool->blocks == NULL) + return XML_FALSE; + pool->blocks->size = blockSize; + pool->ptr = pool->blocks->s + (pool->ptr - pool->start); + pool->start = pool->blocks->s; + pool->end = pool->start + blockSize; + } + else { + BLOCK *tem; + int blockSize = (int)(pool->end - pool->start); + if (blockSize < INIT_BLOCK_SIZE) + blockSize = INIT_BLOCK_SIZE; + else + blockSize *= 2; + tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s) + + blockSize * sizeof(XML_Char)); + if (!tem) + return XML_FALSE; + tem->size = blockSize; + tem->next = pool->blocks; + pool->blocks = tem; + if (pool->ptr != pool->start) + memcpy(tem->s, pool->start, + (pool->ptr - pool->start) * sizeof(XML_Char)); + pool->ptr = tem->s + (pool->ptr - pool->start); + pool->start = tem->s; + pool->end = tem->s + blockSize; + } + return XML_TRUE; +} + +static int FASTCALL +nextScaffoldPart(XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + CONTENT_SCAFFOLD * me; + int next; + + if (!dtd->scaffIndex) { + dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int)); + if (!dtd->scaffIndex) + return -1; + dtd->scaffIndex[0] = 0; + } + + if (dtd->scaffCount >= dtd->scaffSize) { + CONTENT_SCAFFOLD *temp; + if (dtd->scaffold) { + temp = (CONTENT_SCAFFOLD *) + REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize *= 2; + } + else { + temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS + * sizeof(CONTENT_SCAFFOLD)); + if (temp == NULL) + return -1; + dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS; + } + dtd->scaffold = temp; + } + next = dtd->scaffCount++; + me = &dtd->scaffold[next]; + if (dtd->scaffLevel) { + CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]]; + if (parent->lastchild) { + dtd->scaffold[parent->lastchild].nextsib = next; + } + if (!parent->childcnt) + parent->firstchild = next; + parent->lastchild = next; + parent->childcnt++; + } + me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0; + return next; +} + +static void +build_node(XML_Parser parser, + int src_node, + XML_Content *dest, + XML_Content **contpos, + XML_Char **strpos) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + dest->type = dtd->scaffold[src_node].type; + dest->quant = dtd->scaffold[src_node].quant; + if (dest->type == XML_CTYPE_NAME) { + const XML_Char *src; + dest->name = *strpos; + src = dtd->scaffold[src_node].name; + for (;;) { + *(*strpos)++ = *src; + if (!*src) + break; + src++; + } + dest->numchildren = 0; + dest->children = NULL; + } + else { + unsigned int i; + int cn; + dest->numchildren = dtd->scaffold[src_node].childcnt; + dest->children = *contpos; + *contpos += dest->numchildren; + for (i = 0, cn = dtd->scaffold[src_node].firstchild; + i < dest->numchildren; + i++, cn = dtd->scaffold[cn].nextsib) { + build_node(parser, cn, &(dest->children[i]), contpos, strpos); + } + dest->name = NULL; + } +} + +static XML_Content * +build_model (XML_Parser parser) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + XML_Content *ret; + XML_Content *cpos; + XML_Char * str; + int allocsize = (dtd->scaffCount * sizeof(XML_Content) + + (dtd->contentStringLen * sizeof(XML_Char))); + + ret = (XML_Content *)MALLOC(allocsize); + if (!ret) + return NULL; + + str = (XML_Char *) (&ret[dtd->scaffCount]); + cpos = &ret[1]; + + build_node(parser, 0, ret, &cpos, &str); + return ret; +} + +static ELEMENT_TYPE * +getElementType(XML_Parser parser, + const ENCODING *enc, + const char *ptr, + const char *end) +{ + DTD * const dtd = _dtd; /* save one level of indirection */ + const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end); + ELEMENT_TYPE *ret; + + if (!name) + return NULL; + ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE)); + if (!ret) + return NULL; + if (ret->name != name) + poolDiscard(&dtd->pool); + else { + poolFinish(&dtd->pool); + if (!setElementTypePrefix(parser, ret)) + return NULL; + } + return ret; +} diff --git a/sys/src/cmd/python/Modules/expat/xmlrole.c b/sys/src/cmd/python/Modules/expat/xmlrole.c new file mode 100644 index 000000000..15d4d8ff6 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmlrole.c @@ -0,0 +1,1330 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos4__) +#include "amigaconfig.h" +#else +#ifdef HAVE_EXPAT_CONFIG_H +#include <expat_config.h> +#endif +#endif /* ndef COMPILED_FROM_DSP */ + +#include <stddef.h> + +#include "expat_external.h" +#include "internal.h" +#include "xmlrole.h" +#include "ascii.h" + +/* Doesn't check: + + that ,| are not mixed in a model group + content of literals + +*/ + +static const char KW_ANY[] = { + ASCII_A, ASCII_N, ASCII_Y, '\0' }; +static const char KW_ATTLIST[] = { + ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' }; +static const char KW_CDATA[] = { + ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_DOCTYPE[] = { + ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' }; +static const char KW_ELEMENT[] = { + ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' }; +static const char KW_EMPTY[] = { + ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' }; +static const char KW_ENTITIES[] = { + ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, + '\0' }; +static const char KW_ENTITY[] = { + ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' }; +static const char KW_FIXED[] = { + ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' }; +static const char KW_ID[] = { + ASCII_I, ASCII_D, '\0' }; +static const char KW_IDREF[] = { + ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' }; +static const char KW_IDREFS[] = { + ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' }; +static const char KW_IGNORE[] = { + ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' }; +static const char KW_IMPLIED[] = { + ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' }; +static const char KW_INCLUDE[] = { + ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' }; +static const char KW_NDATA[] = { + ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_NMTOKEN[] = { + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' }; +static const char KW_NMTOKENS[] = { + ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, + '\0' }; +static const char KW_NOTATION[] = + { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, + '\0' }; +static const char KW_PCDATA[] = { + ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' }; +static const char KW_PUBLIC[] = { + ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' }; +static const char KW_REQUIRED[] = { + ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, + '\0' }; +static const char KW_SYSTEM[] = { + ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' }; + +#ifndef MIN_BYTES_PER_CHAR +#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar) +#endif + +#ifdef XML_DTD +#define setTopLevel(state) \ + ((state)->handler = ((state)->documentEntity \ + ? internalSubset \ + : externalSubset1)) +#else /* not XML_DTD */ +#define setTopLevel(state) ((state)->handler = internalSubset) +#endif /* not XML_DTD */ + +typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + +static PROLOG_HANDLER + prolog0, prolog1, prolog2, + doctype0, doctype1, doctype2, doctype3, doctype4, doctype5, + internalSubset, + entity0, entity1, entity2, entity3, entity4, entity5, entity6, + entity7, entity8, entity9, entity10, + notation0, notation1, notation2, notation3, notation4, + attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6, + attlist7, attlist8, attlist9, + element0, element1, element2, element3, element4, element5, element6, + element7, +#ifdef XML_DTD + externalSubset0, externalSubset1, + condSect0, condSect1, condSect2, +#endif /* XML_DTD */ + declClose, + error; + +static int FASTCALL common(PROLOG_STATE *state, int tok); + +static int PTRCALL +prolog0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + state->handler = prolog1; + return XML_ROLE_NONE; + case XML_TOK_XML_DECL: + state->handler = prolog1; + return XML_ROLE_XML_DECL; + case XML_TOK_PI: + state->handler = prolog1; + return XML_ROLE_PI; + case XML_TOK_COMMENT: + state->handler = prolog1; + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_BOM: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (!XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_DOCTYPE)) + break; + state->handler = doctype0; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +prolog2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_INSTANCE_START: + state->handler = error; + return XML_ROLE_INSTANCE_START; + } + return common(state, tok); +} + +static int PTRCALL +doctype0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = doctype1; + return XML_ROLE_DOCTYPE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +doctype1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = doctype3; + return XML_ROLE_DOCTYPE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = doctype2; + return XML_ROLE_DOCTYPE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +doctype2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype3; + return XML_ROLE_DOCTYPE_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_LITERAL: + state->handler = doctype4; + return XML_ROLE_DOCTYPE_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +doctype4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = internalSubset; + return XML_ROLE_DOCTYPE_INTERNAL_SUBSET; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +doctype5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_DECL_CLOSE: + state->handler = prolog2; + return XML_ROLE_DOCTYPE_CLOSE; + } + return common(state, tok); +} + +static int PTRCALL +internalSubset(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_DECL_OPEN: + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ENTITY)) { + state->handler = entity0; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ATTLIST)) { + state->handler = attlist0; + return XML_ROLE_ATTLIST_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_ELEMENT)) { + state->handler = element0; + return XML_ROLE_ELEMENT_NONE; + } + if (XmlNameMatchesAscii(enc, + ptr + 2 * MIN_BYTES_PER_CHAR(enc), + end, + KW_NOTATION)) { + state->handler = notation0; + return XML_ROLE_NOTATION_NONE; + } + break; + case XML_TOK_PI: + return XML_ROLE_PI; + case XML_TOK_COMMENT: + return XML_ROLE_COMMENT; + case XML_TOK_PARAM_ENTITY_REF: + return XML_ROLE_PARAM_ENTITY_REF; + case XML_TOK_CLOSE_BRACKET: + state->handler = doctype5; + return XML_ROLE_DOCTYPE_NONE; + case XML_TOK_NONE: + return XML_ROLE_NONE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +externalSubset0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + state->handler = externalSubset1; + if (tok == XML_TOK_XML_DECL) + return XML_ROLE_TEXT_DECL; + return externalSubset1(state, tok, ptr, end, enc); +} + +static int PTRCALL +externalSubset1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_COND_SECT_OPEN: + state->handler = condSect0; + return XML_ROLE_NONE; + case XML_TOK_COND_SECT_CLOSE: + if (state->includeLevel == 0) + break; + state->includeLevel -= 1; + return XML_ROLE_NONE; + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_CLOSE_BRACKET: + break; + case XML_TOK_NONE: + if (state->includeLevel) + break; + return XML_ROLE_NONE; + default: + return internalSubset(state, tok, ptr, end, enc); + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +entity0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_PERCENT: + state->handler = entity1; + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity2; + return XML_ROLE_GENERAL_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = entity7; + return XML_ROLE_PARAM_ENTITY_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity4; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity3; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity4; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity5; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) { + state->handler = entity6; + return XML_ROLE_ENTITY_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +entity6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +entity7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = entity9; + return XML_ROLE_ENTITY_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = entity8; + return XML_ROLE_ENTITY_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_ENTITY_NONE; + return XML_ROLE_ENTITY_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +entity8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity9; + return XML_ROLE_ENTITY_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_LITERAL: + state->handler = entity10; + return XML_ROLE_ENTITY_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +entity10(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ENTITY_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ENTITY_COMPLETE; + } + return common(state, tok); +} + +static int PTRCALL +notation0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + state->handler = notation1; + return XML_ROLE_NOTATION_NAME; + } + return common(state, tok); +} + +static int PTRCALL +notation1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) { + state->handler = notation3; + return XML_ROLE_NOTATION_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) { + state->handler = notation2; + return XML_ROLE_NOTATION_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +notation2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = notation4; + return XML_ROLE_NOTATION_PUBLIC_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +notation4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NOTATION_NONE; + case XML_TOK_LITERAL: + state->handler = declClose; + state->role_none = XML_ROLE_NOTATION_NONE; + return XML_ROLE_NOTATION_SYSTEM_ID; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_NOTATION_NO_SYSTEM_ID; + } + return common(state, tok); +} + +static int PTRCALL +attlist0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist1; + return XML_ROLE_ATTLIST_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist2; + return XML_ROLE_ATTRIBUTE_NAME; + } + return common(state, tok); +} + +static int PTRCALL +attlist2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + { + static const char * const types[] = { + KW_CDATA, + KW_ID, + KW_IDREF, + KW_IDREFS, + KW_ENTITY, + KW_ENTITIES, + KW_NMTOKEN, + KW_NMTOKENS, + }; + int i; + for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++) + if (XmlNameMatchesAscii(enc, ptr, end, types[i])) { + state->handler = attlist8; + return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i; + } + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) { + state->handler = attlist5; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NMTOKEN: + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = attlist4; + return XML_ROLE_ATTRIBUTE_ENUM_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist3; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OPEN_PAREN: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +static int PTRCALL +attlist6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_NAME: + state->handler = attlist7; + return XML_ROLE_ATTRIBUTE_NOTATION_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = attlist8; + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_OR: + state->handler = attlist6; + return XML_ROLE_ATTLIST_NONE; + } + return common(state, tok); +} + +/* default value */ +static int PTRCALL +attlist8(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_IMPLIED)) { + state->handler = attlist1; + return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_REQUIRED)) { + state->handler = attlist1; + return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE; + } + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_FIXED)) { + state->handler = attlist9; + return XML_ROLE_ATTLIST_NONE; + } + break; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +attlist9(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ATTLIST_NONE; + case XML_TOK_LITERAL: + state->handler = attlist1; + return XML_ROLE_FIXED_ATTRIBUTE_VALUE; + } + return common(state, tok); +} + +static int PTRCALL +element0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element1; + return XML_ROLE_ELEMENT_NAME; + } + return common(state, tok); +} + +static int PTRCALL +element1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_EMPTY; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_CONTENT_ANY; + } + break; + case XML_TOK_OPEN_PAREN: + state->handler = element2; + state->level = 1; + return XML_ROLE_GROUP_OPEN; + } + return common(state, tok); +} + +static int PTRCALL +element2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_POUND_NAME: + if (XmlNameMatchesAscii(enc, + ptr + MIN_BYTES_PER_CHAR(enc), + end, + KW_PCDATA)) { + state->handler = element3; + return XML_ROLE_CONTENT_PCDATA; + } + break; + case XML_TOK_OPEN_PAREN: + state->level = 2; + state->handler = element6; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element3(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element4(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element5; + return XML_ROLE_CONTENT_ELEMENT; + } + return common(state, tok); +} + +static int PTRCALL +element5(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_OR: + state->handler = element4; + return XML_ROLE_ELEMENT_NONE; + } + return common(state, tok); +} + +static int PTRCALL +element6(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_OPEN_PAREN: + state->level += 1; + return XML_ROLE_GROUP_OPEN; + case XML_TOK_NAME: + case XML_TOK_PREFIXED_NAME: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT; + case XML_TOK_NAME_QUESTION: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_OPT; + case XML_TOK_NAME_ASTERISK: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_REP; + case XML_TOK_NAME_PLUS: + state->handler = element7; + return XML_ROLE_CONTENT_ELEMENT_PLUS; + } + return common(state, tok); +} + +static int PTRCALL +element7(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_ELEMENT_NONE; + case XML_TOK_CLOSE_PAREN: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE; + case XML_TOK_CLOSE_PAREN_ASTERISK: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_REP; + case XML_TOK_CLOSE_PAREN_QUESTION: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_OPT; + case XML_TOK_CLOSE_PAREN_PLUS: + state->level -= 1; + if (state->level == 0) { + state->handler = declClose; + state->role_none = XML_ROLE_ELEMENT_NONE; + } + return XML_ROLE_GROUP_CLOSE_PLUS; + case XML_TOK_COMMA: + state->handler = element6; + return XML_ROLE_GROUP_SEQUENCE; + case XML_TOK_OR: + state->handler = element6; + return XML_ROLE_GROUP_CHOICE; + } + return common(state, tok); +} + +#ifdef XML_DTD + +static int PTRCALL +condSect0(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_NAME: + if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) { + state->handler = condSect1; + return XML_ROLE_NONE; + } + if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) { + state->handler = condSect2; + return XML_ROLE_NONE; + } + break; + } + return common(state, tok); +} + +static int PTRCALL +condSect1(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + state->includeLevel += 1; + return XML_ROLE_NONE; + } + return common(state, tok); +} + +static int PTRCALL +condSect2(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return XML_ROLE_NONE; + case XML_TOK_OPEN_BRACKET: + state->handler = externalSubset1; + return XML_ROLE_IGNORE_SECT; + } + return common(state, tok); +} + +#endif /* XML_DTD */ + +static int PTRCALL +declClose(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + switch (tok) { + case XML_TOK_PROLOG_S: + return state->role_none; + case XML_TOK_DECL_CLOSE: + setTopLevel(state); + return state->role_none; + } + return common(state, tok); +} + +static int PTRCALL +error(PROLOG_STATE *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc) +{ + return XML_ROLE_NONE; +} + +static int FASTCALL +common(PROLOG_STATE *state, int tok) +{ +#ifdef XML_DTD + if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF) + return XML_ROLE_INNER_PARAM_ENTITY_REF; +#endif + state->handler = error; + return XML_ROLE_ERROR; +} + +void +XmlPrologStateInit(PROLOG_STATE *state) +{ + state->handler = prolog0; +#ifdef XML_DTD + state->documentEntity = 1; + state->includeLevel = 0; + state->inEntityValue = 0; +#endif /* XML_DTD */ +} + +#ifdef XML_DTD + +void +XmlPrologStateInitExternalEntity(PROLOG_STATE *state) +{ + state->handler = externalSubset0; + state->documentEntity = 0; + state->includeLevel = 0; +} + +#endif /* XML_DTD */ diff --git a/sys/src/cmd/python/Modules/expat/xmlrole.h b/sys/src/cmd/python/Modules/expat/xmlrole.h new file mode 100644 index 000000000..4dd9f06f9 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmlrole.h @@ -0,0 +1,114 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlRole_INCLUDED +#define XmlRole_INCLUDED 1 + +#ifdef __VMS +/* 0 1 2 3 0 1 2 3 + 1234567890123456789012345678901 1234567890123456789012345678901 */ +#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt +#endif + +#include "xmltok.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + XML_ROLE_ERROR = -1, + XML_ROLE_NONE = 0, + XML_ROLE_XML_DECL, + XML_ROLE_INSTANCE_START, + XML_ROLE_DOCTYPE_NONE, + XML_ROLE_DOCTYPE_NAME, + XML_ROLE_DOCTYPE_SYSTEM_ID, + XML_ROLE_DOCTYPE_PUBLIC_ID, + XML_ROLE_DOCTYPE_INTERNAL_SUBSET, + XML_ROLE_DOCTYPE_CLOSE, + XML_ROLE_GENERAL_ENTITY_NAME, + XML_ROLE_PARAM_ENTITY_NAME, + XML_ROLE_ENTITY_NONE, + XML_ROLE_ENTITY_VALUE, + XML_ROLE_ENTITY_SYSTEM_ID, + XML_ROLE_ENTITY_PUBLIC_ID, + XML_ROLE_ENTITY_COMPLETE, + XML_ROLE_ENTITY_NOTATION_NAME, + XML_ROLE_NOTATION_NONE, + XML_ROLE_NOTATION_NAME, + XML_ROLE_NOTATION_SYSTEM_ID, + XML_ROLE_NOTATION_NO_SYSTEM_ID, + XML_ROLE_NOTATION_PUBLIC_ID, + XML_ROLE_ATTRIBUTE_NAME, + XML_ROLE_ATTRIBUTE_TYPE_CDATA, + XML_ROLE_ATTRIBUTE_TYPE_ID, + XML_ROLE_ATTRIBUTE_TYPE_IDREF, + XML_ROLE_ATTRIBUTE_TYPE_IDREFS, + XML_ROLE_ATTRIBUTE_TYPE_ENTITY, + XML_ROLE_ATTRIBUTE_TYPE_ENTITIES, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN, + XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS, + XML_ROLE_ATTRIBUTE_ENUM_VALUE, + XML_ROLE_ATTRIBUTE_NOTATION_VALUE, + XML_ROLE_ATTLIST_NONE, + XML_ROLE_ATTLIST_ELEMENT_NAME, + XML_ROLE_IMPLIED_ATTRIBUTE_VALUE, + XML_ROLE_REQUIRED_ATTRIBUTE_VALUE, + XML_ROLE_DEFAULT_ATTRIBUTE_VALUE, + XML_ROLE_FIXED_ATTRIBUTE_VALUE, + XML_ROLE_ELEMENT_NONE, + XML_ROLE_ELEMENT_NAME, + XML_ROLE_CONTENT_ANY, + XML_ROLE_CONTENT_EMPTY, + XML_ROLE_CONTENT_PCDATA, + XML_ROLE_GROUP_OPEN, + XML_ROLE_GROUP_CLOSE, + XML_ROLE_GROUP_CLOSE_REP, + XML_ROLE_GROUP_CLOSE_OPT, + XML_ROLE_GROUP_CLOSE_PLUS, + XML_ROLE_GROUP_CHOICE, + XML_ROLE_GROUP_SEQUENCE, + XML_ROLE_CONTENT_ELEMENT, + XML_ROLE_CONTENT_ELEMENT_REP, + XML_ROLE_CONTENT_ELEMENT_OPT, + XML_ROLE_CONTENT_ELEMENT_PLUS, + XML_ROLE_PI, + XML_ROLE_COMMENT, +#ifdef XML_DTD + XML_ROLE_TEXT_DECL, + XML_ROLE_IGNORE_SECT, + XML_ROLE_INNER_PARAM_ENTITY_REF, +#endif /* XML_DTD */ + XML_ROLE_PARAM_ENTITY_REF +}; + +typedef struct prolog_state { + int (PTRCALL *handler) (struct prolog_state *state, + int tok, + const char *ptr, + const char *end, + const ENCODING *enc); + unsigned level; + int role_none; +#ifdef XML_DTD + unsigned includeLevel; + int documentEntity; + int inEntityValue; +#endif /* XML_DTD */ +} PROLOG_STATE; + +void XmlPrologStateInit(PROLOG_STATE *); +#ifdef XML_DTD +void XmlPrologStateInitExternalEntity(PROLOG_STATE *); +#endif /* XML_DTD */ + +#define XmlTokenRole(state, tok, ptr, end, enc) \ + (((state)->handler)(state, tok, ptr, end, enc)) + +#ifdef __cplusplus +} +#endif + +#endif /* not XmlRole_INCLUDED */ diff --git a/sys/src/cmd/python/Modules/expat/xmltok.c b/sys/src/cmd/python/Modules/expat/xmltok.c new file mode 100644 index 000000000..db92247da --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmltok.c @@ -0,0 +1,1639 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifdef COMPILED_FROM_DSP +#include "winconfig.h" +#elif defined(MACOS_CLASSIC) +#include "macconfig.h" +#elif defined(__amigaos4__) +#include "amigaconfig.h" +#else +#ifdef HAVE_EXPAT_CONFIG_H +#include <expat_config.h> +#endif +#endif /* ndef COMPILED_FROM_DSP */ + +#include <stddef.h> + +#include "expat_external.h" +#include "internal.h" +#include "xmltok.h" +#include "nametab.h" + +#ifdef XML_DTD +#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok) +#else +#define IGNORE_SECTION_TOK_VTABLE /* as nothing */ +#endif + +#define VTABLE1 \ + { PREFIX(prologTok), PREFIX(contentTok), \ + PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \ + { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \ + PREFIX(sameName), \ + PREFIX(nameMatchesAscii), \ + PREFIX(nameLength), \ + PREFIX(skipS), \ + PREFIX(getAtts), \ + PREFIX(charRefNumber), \ + PREFIX(predefinedEntityName), \ + PREFIX(updatePosition), \ + PREFIX(isPublicId) + +#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16) + +#define UCS2_GET_NAMING(pages, hi, lo) \ + (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F))) + +/* A 2 byte UTF-8 representation splits the characters 11 bits between + the bottom 5 and 6 bits of the bytes. We need 8 bits to index into + pages, 3 bits to add to that index and 5 bits to generate the mask. +*/ +#define UTF8_GET_NAMING2(pages, byte) \ + (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \ + + ((((byte)[0]) & 3) << 1) \ + + ((((byte)[1]) >> 5) & 1)] \ + & (1 << (((byte)[1]) & 0x1F))) + +/* A 3 byte UTF-8 representation splits the characters 16 bits between + the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index + into pages, 3 bits to add to that index and 5 bits to generate the + mask. +*/ +#define UTF8_GET_NAMING3(pages, byte) \ + (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \ + + ((((byte)[1]) >> 2) & 0xF)] \ + << 3) \ + + ((((byte)[1]) & 3) << 1) \ + + ((((byte)[2]) >> 5) & 1)] \ + & (1 << (((byte)[2]) & 0x1F))) + +#define UTF8_GET_NAMING(pages, p, n) \ + ((n) == 2 \ + ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \ + : ((n) == 3 \ + ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \ + : 0)) + +/* Detection of invalid UTF-8 sequences is based on Table 3.1B + of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/ + with the additional restriction of not allowing the Unicode + code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE). + Implementation details: + (A & 0x80) == 0 means A < 0x80 + and + (A & 0xC0) == 0xC0 means A > 0xBF +*/ + +#define UTF8_INVALID2(p) \ + ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0) + +#define UTF8_INVALID3(p) \ + (((p)[2] & 0x80) == 0 \ + || \ + ((*p) == 0xEF && (p)[1] == 0xBF \ + ? \ + (p)[2] > 0xBD \ + : \ + ((p)[2] & 0xC0) == 0xC0) \ + || \ + ((*p) == 0xE0 \ + ? \ + (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \ + : \ + ((p)[1] & 0x80) == 0 \ + || \ + ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0))) + +#define UTF8_INVALID4(p) \ + (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \ + || \ + ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \ + || \ + ((*p) == 0xF0 \ + ? \ + (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \ + : \ + ((p)[1] & 0x80) == 0 \ + || \ + ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0))) + +static int PTRFASTCALL +isNever(const ENCODING *enc, const char *p) +{ + return 0; +} + +static int PTRFASTCALL +utf8_isName2(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING2(namePages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isName3(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING3(namePages, (const unsigned char *)p); +} + +#define utf8_isName4 isNever + +static int PTRFASTCALL +utf8_isNmstrt2(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isNmstrt3(const ENCODING *enc, const char *p) +{ + return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p); +} + +#define utf8_isNmstrt4 isNever + +static int PTRFASTCALL +utf8_isInvalid2(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID2((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid3(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID3((const unsigned char *)p); +} + +static int PTRFASTCALL +utf8_isInvalid4(const ENCODING *enc, const char *p) +{ + return UTF8_INVALID4((const unsigned char *)p); +} + +struct normal_encoding { + ENCODING enc; + unsigned char type[256]; +#ifdef XML_MIN_SIZE + int (PTRFASTCALL *byteType)(const ENCODING *, const char *); + int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *); + int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *); + int (PTRCALL *charMatches)(const ENCODING *, const char *, int); +#endif /* XML_MIN_SIZE */ + int (PTRFASTCALL *isName2)(const ENCODING *, const char *); + int (PTRFASTCALL *isName3)(const ENCODING *, const char *); + int (PTRFASTCALL *isName4)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *); + int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *); + int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *); +}; + +#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc)) + +#ifdef XML_MIN_SIZE + +#define STANDARD_VTABLE(E) \ + E ## byteType, \ + E ## isNameMin, \ + E ## isNmstrtMin, \ + E ## byteToAscii, \ + E ## charMatches, + +#else + +#define STANDARD_VTABLE(E) /* as nothing */ + +#endif + +#define NORMAL_VTABLE(E) \ + E ## isName2, \ + E ## isName3, \ + E ## isName4, \ + E ## isNmstrt2, \ + E ## isNmstrt3, \ + E ## isNmstrt4, \ + E ## isInvalid2, \ + E ## isInvalid3, \ + E ## isInvalid4 + +static int FASTCALL checkCharRefNumber(int); + +#include "xmltok_impl.h" +#include "ascii.h" + +#ifdef XML_MIN_SIZE +#define sb_isNameMin isNever +#define sb_isNmstrtMin isNever +#endif + +#ifdef XML_MIN_SIZE +#define MINBPC(enc) ((enc)->minBytesPerChar) +#else +/* minimum bytes per character */ +#define MINBPC(enc) 1 +#endif + +#define SB_BYTE_TYPE(enc, p) \ + (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)]) + +#ifdef XML_MIN_SIZE +static int PTRFASTCALL +sb_byteType(const ENCODING *enc, const char *p) +{ + return SB_BYTE_TYPE(enc, p); +} +#define BYTE_TYPE(enc, p) \ + (AS_NORMAL_ENCODING(enc)->byteType(enc, p)) +#else +#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p) +#endif + +#ifdef XML_MIN_SIZE +#define BYTE_TO_ASCII(enc, p) \ + (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p)) +static int PTRFASTCALL +sb_byteToAscii(const ENCODING *enc, const char *p) +{ + return *p; +} +#else +#define BYTE_TO_ASCII(enc, p) (*(p)) +#endif + +#define IS_NAME_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p)) +#define IS_NMSTRT_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p)) +#define IS_INVALID_CHAR(enc, p, n) \ + (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p)) + +#ifdef XML_MIN_SIZE +#define IS_NAME_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p)) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) \ + (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p)) +#else +#define IS_NAME_CHAR_MINBPC(enc, p) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0) +#endif + +#ifdef XML_MIN_SIZE +#define CHAR_MATCHES(enc, p, c) \ + (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c)) +static int PTRCALL +sb_charMatches(const ENCODING *enc, const char *p, int c) +{ + return *p == c; +} +#else +/* c is an ASCII character */ +#define CHAR_MATCHES(enc, p, c) (*(p) == c) +#endif + +#define PREFIX(ident) normal_ ## ident +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */ + UTF8_cval1 = 0x00, + UTF8_cval2 = 0xc0, + UTF8_cval3 = 0xe0, + UTF8_cval4 = 0xf0 +}; + +static void PTRCALL +utf8_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + char *to; + const char *from; + if (fromLim - *fromP > toLim - *toP) { + /* Avoid copying partial characters. */ + for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--) + if (((unsigned char)fromLim[-1] & 0xc0) != 0x80) + break; + } + for (to = *toP, from = *fromP; from != fromLim; from++, to++) + *to = *from; + *fromP = from; + *toP = to; +} + +static void PTRCALL +utf8_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + unsigned short *to = *toP; + const char *from = *fromP; + while (from != fromLim && to != toLim) { + switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) { + case BT_LEAD2: + *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f)); + from += 2; + break; + case BT_LEAD3: + *to++ = (unsigned short)(((from[0] & 0xf) << 12) + | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f)); + from += 3; + break; + case BT_LEAD4: + { + unsigned long n; + if (to + 1 == toLim) + goto after; + n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) + | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f); + n -= 0x10000; + to[0] = (unsigned short)((n >> 10) | 0xD800); + to[1] = (unsigned short)((n & 0x3FF) | 0xDC00); + to += 2; + from += 4; + } + break; + default: + *to++ = *from++; + break; + } + } +after: + *fromP = from; + *toP = to; +} + +#ifdef XML_NS +static const struct normal_encoding utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; +#endif + +static const struct normal_encoding utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#ifdef XML_NS + +static const struct normal_encoding internal_utf8_encoding_ns = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#include "iasciitab.h" +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +#endif + +static const struct normal_encoding internal_utf8_encoding = { + { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "utf8tab.h" + }, + STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_) +}; + +static void PTRCALL +latin1_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + for (;;) { + unsigned char c; + if (*fromP == fromLim) + break; + c = (unsigned char)**fromP; + if (c & 0x80) { + if (toLim - *toP < 2) + break; + *(*toP)++ = (char)((c >> 6) | UTF8_cval2); + *(*toP)++ = (char)((c & 0x3f) | 0x80); + (*fromP)++; + } + else { + if (*toP == toLim) + break; + *(*toP)++ = *(*fromP)++; + } + } +} + +static void PTRCALL +latin1_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = (unsigned char)*(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding latin1_encoding_ns = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding latin1_encoding = { + { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(sb_) +}; + +static void PTRCALL +ascii_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + while (*fromP != fromLim && *toP != toLim) + *(*toP)++ = *(*fromP)++; +} + +#ifdef XML_NS + +static const struct normal_encoding ascii_encoding_ns = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#include "asciitab.h" +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) +}; + +#endif + +static const struct normal_encoding ascii_encoding = { + { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +/* BT_NONXML == 0 */ + }, + STANDARD_VTABLE(sb_) +}; + +static int PTRFASTCALL +unicode_byte_type(char hi, char lo) +{ + switch ((unsigned char)hi) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + return BT_LEAD4; + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return BT_TRAIL; + case 0xFF: + switch ((unsigned char)lo) { + case 0xFF: + case 0xFE: + return BT_NONXML; + } + break; + } + return BT_NONASCII; +} + +#define DEFINE_UTF16_TO_UTF8(E) \ +static void PTRCALL \ +E ## toUtf8(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + char **toP, const char *toLim) \ +{ \ + const char *from; \ + for (from = *fromP; from != fromLim; from += 2) { \ + int plane; \ + unsigned char lo2; \ + unsigned char lo = GET_LO(from); \ + unsigned char hi = GET_HI(from); \ + switch (hi) { \ + case 0: \ + if (lo < 0x80) { \ + if (*toP == toLim) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = lo; \ + break; \ + } \ + /* fall through */ \ + case 0x1: case 0x2: case 0x3: \ + case 0x4: case 0x5: case 0x6: case 0x7: \ + if (toLim - *toP < 2) { \ + *fromP = from; \ + return; \ + } \ + *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + default: \ + if (toLim - *toP < 3) { \ + *fromP = from; \ + return; \ + } \ + /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \ + *(*toP)++ = ((hi >> 4) | UTF8_cval3); \ + *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \ + *(*toP)++ = ((lo & 0x3f) | 0x80); \ + break; \ + case 0xD8: case 0xD9: case 0xDA: case 0xDB: \ + if (toLim - *toP < 4) { \ + *fromP = from; \ + return; \ + } \ + plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \ + *(*toP)++ = ((plane >> 2) | UTF8_cval4); \ + *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \ + from += 2; \ + lo2 = GET_LO(from); \ + *(*toP)++ = (((lo & 0x3) << 4) \ + | ((GET_HI(from) & 0x3) << 2) \ + | (lo2 >> 6) \ + | 0x80); \ + *(*toP)++ = ((lo2 & 0x3f) | 0x80); \ + break; \ + } \ + } \ + *fromP = from; \ +} + +#define DEFINE_UTF16_TO_UTF16(E) \ +static void PTRCALL \ +E ## toUtf16(const ENCODING *enc, \ + const char **fromP, const char *fromLim, \ + unsigned short **toP, const unsigned short *toLim) \ +{ \ + /* Avoid copying first half only of surrogate */ \ + if (fromLim - *fromP > ((toLim - *toP) << 1) \ + && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \ + fromLim -= 2; \ + for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \ + *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \ +} + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8))) +#define GET_LO(ptr) ((unsigned char)(ptr)[0]) +#define GET_HI(ptr) ((unsigned char)(ptr)[1]) + +DEFINE_UTF16_TO_UTF8(little2_) +DEFINE_UTF16_TO_UTF16(little2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define SET2(ptr, ch) \ + (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF))) +#define GET_LO(ptr) ((unsigned char)(ptr)[1]) +#define GET_HI(ptr) ((unsigned char)(ptr)[0]) + +DEFINE_UTF16_TO_UTF8(big2_) +DEFINE_UTF16_TO_UTF16(big2_) + +#undef SET2 +#undef GET_LO +#undef GET_HI + +#define LITTLE2_BYTE_TYPE(enc, p) \ + ((p)[1] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \ + : unicode_byte_type((p)[1], (p)[0])) +#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1) +#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c) +#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0]) +#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +little2_byteType(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +little2_byteToAscii(const ENCODING *enc, const char *p) +{ + return LITTLE2_BYTE_TO_ASCII(enc, p); +} + +static int PTRCALL +little2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return LITTLE2_CHAR_MATCHES(enc, p, c); +} + +static int PTRFASTCALL +little2_isNameMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static int PTRFASTCALL +little2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) little2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding little2_encoding_ns = { + { VTABLE, 2, 0, +#if BYTEORDER == 1234 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding little2_encoding = { + { VTABLE, 2, 0, +#if BYTEORDER == 1234 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#if BYTEORDER != 4321 + +#ifdef XML_NS + +static const struct normal_encoding internal_little2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + +static const struct normal_encoding internal_little2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(little2_) +}; + +#endif + + +#define BIG2_BYTE_TYPE(enc, p) \ + ((p)[0] == 0 \ + ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \ + : unicode_byte_type((p)[0], (p)[1])) +#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1) +#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c) +#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1]) +#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \ + UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1]) + +#ifdef XML_MIN_SIZE + +static int PTRFASTCALL +big2_byteType(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TYPE(enc, p); +} + +static int PTRFASTCALL +big2_byteToAscii(const ENCODING *enc, const char *p) +{ + return BIG2_BYTE_TO_ASCII(enc, p); +} + +static int PTRCALL +big2_charMatches(const ENCODING *enc, const char *p, int c) +{ + return BIG2_CHAR_MATCHES(enc, p, c); +} + +static int PTRFASTCALL +big2_isNameMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NAME_CHAR_MINBPC(enc, p); +} + +static int PTRFASTCALL +big2_isNmstrtMin(const ENCODING *enc, const char *p) +{ + return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p); +} + +#undef VTABLE +#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16 + +#else /* not XML_MIN_SIZE */ + +#undef PREFIX +#define PREFIX(ident) big2_ ## ident +#define MINBPC(enc) 2 +/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */ +#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p) +#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p) +#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c) +#define IS_NAME_CHAR(enc, p, n) 0 +#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p) +#define IS_NMSTRT_CHAR(enc, p, n) (0) +#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) + +#include "xmltok_impl.c" + +#undef MINBPC +#undef BYTE_TYPE +#undef BYTE_TO_ASCII +#undef CHAR_MATCHES +#undef IS_NAME_CHAR +#undef IS_NAME_CHAR_MINBPC +#undef IS_NMSTRT_CHAR +#undef IS_NMSTRT_CHAR_MINBPC +#undef IS_INVALID_CHAR + +#endif /* not XML_MIN_SIZE */ + +#ifdef XML_NS + +static const struct normal_encoding big2_encoding_ns = { + { VTABLE, 2, 0, +#if BYTEORDER == 4321 + 1 +#else + 0 +#endif + }, + { +#include "asciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding big2_encoding = { + { VTABLE, 2, 0, +#if BYTEORDER == 4321 + 1 +#else + 0 +#endif + }, + { +#define BT_COLON BT_NMSTRT +#include "asciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#if BYTEORDER != 1234 + +#ifdef XML_NS + +static const struct normal_encoding internal_big2_encoding_ns = { + { VTABLE, 2, 0, 1 }, + { +#include "iasciitab.h" +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +static const struct normal_encoding internal_big2_encoding = { + { VTABLE, 2, 0, 1 }, + { +#define BT_COLON BT_NMSTRT +#include "iasciitab.h" +#undef BT_COLON +#include "latin1tab.h" + }, + STANDARD_VTABLE(big2_) +}; + +#endif + +#undef PREFIX + +static int FASTCALL +streqci(const char *s1, const char *s2) +{ + for (;;) { + char c1 = *s1++; + char c2 = *s2++; + if (ASCII_a <= c1 && c1 <= ASCII_z) + c1 += ASCII_A - ASCII_a; + if (ASCII_a <= c2 && c2 <= ASCII_z) + c2 += ASCII_A - ASCII_a; + if (c1 != c2) + return 0; + if (!c1) + break; + } + return 1; +} + +static void PTRCALL +initUpdatePosition(const ENCODING *enc, const char *ptr, + const char *end, POSITION *pos) +{ + normal_updatePosition(&utf8_encoding.enc, ptr, end, pos); +} + +static int +toAscii(const ENCODING *enc, const char *ptr, const char *end) +{ + char buf[1]; + char *p = buf; + XmlUtf8Convert(enc, &ptr, end, &p, p + 1); + if (p == buf) + return -1; + else + return buf[0]; +} + +static int FASTCALL +isSpace(int c) +{ + switch (c) { + case 0x20: + case 0xD: + case 0xA: + case 0x9: + return 1; + } + return 0; +} + +/* Return 1 if there's just optional white space or there's an S + followed by name=val. +*/ +static int +parsePseudoAttribute(const ENCODING *enc, + const char *ptr, + const char *end, + const char **namePtr, + const char **nameEndPtr, + const char **valPtr, + const char **nextTokPtr) +{ + int c; + char open; + if (ptr == end) { + *namePtr = NULL; + return 1; + } + if (!isSpace(toAscii(enc, ptr, end))) { + *nextTokPtr = ptr; + return 0; + } + do { + ptr += enc->minBytesPerChar; + } while (isSpace(toAscii(enc, ptr, end))); + if (ptr == end) { + *namePtr = NULL; + return 1; + } + *namePtr = ptr; + for (;;) { + c = toAscii(enc, ptr, end); + if (c == -1) { + *nextTokPtr = ptr; + return 0; + } + if (c == ASCII_EQUALS) { + *nameEndPtr = ptr; + break; + } + if (isSpace(c)) { + *nameEndPtr = ptr; + do { + ptr += enc->minBytesPerChar; + } while (isSpace(c = toAscii(enc, ptr, end))); + if (c != ASCII_EQUALS) { + *nextTokPtr = ptr; + return 0; + } + break; + } + ptr += enc->minBytesPerChar; + } + if (ptr == *namePtr) { + *nextTokPtr = ptr; + return 0; + } + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + while (isSpace(c)) { + ptr += enc->minBytesPerChar; + c = toAscii(enc, ptr, end); + } + if (c != ASCII_QUOT && c != ASCII_APOS) { + *nextTokPtr = ptr; + return 0; + } + open = (char)c; + ptr += enc->minBytesPerChar; + *valPtr = ptr; + for (;; ptr += enc->minBytesPerChar) { + c = toAscii(enc, ptr, end); + if (c == open) + break; + if (!(ASCII_a <= c && c <= ASCII_z) + && !(ASCII_A <= c && c <= ASCII_Z) + && !(ASCII_0 <= c && c <= ASCII_9) + && c != ASCII_PERIOD + && c != ASCII_MINUS + && c != ASCII_UNDERSCORE) { + *nextTokPtr = ptr; + return 0; + } + } + *nextTokPtr = ptr + enc->minBytesPerChar; + return 1; +} + +static const char KW_version[] = { + ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0' +}; + +static const char KW_encoding[] = { + ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0' +}; + +static const char KW_standalone[] = { + ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, + ASCII_n, ASCII_e, '\0' +}; + +static const char KW_yes[] = { + ASCII_y, ASCII_e, ASCII_s, '\0' +}; + +static const char KW_no[] = { + ASCII_n, ASCII_o, '\0' +}; + +static int +doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *, + const char *, + const char *), + int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + const char *val = NULL; + const char *name = NULL; + const char *nameEnd = NULL; + ptr += 5 * enc->minBytesPerChar; + end -= 2 * enc->minBytesPerChar; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) + || !name) { + *badPtr = ptr; + return 0; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) { + if (!isGeneralTextEntity) { + *badPtr = name; + return 0; + } + } + else { + if (versionPtr) + *versionPtr = val; + if (versionEndPtr) + *versionEndPtr = ptr; + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) { + if (isGeneralTextEntity) { + /* a TextDecl must have an EncodingDecl */ + *badPtr = ptr; + return 0; + } + return 1; + } + } + if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) { + int c = toAscii(enc, val, end); + if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) { + *badPtr = val; + return 0; + } + if (encodingName) + *encodingName = val; + if (encoding) + *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar); + if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) { + *badPtr = ptr; + return 0; + } + if (!name) + return 1; + } + if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) + || isGeneralTextEntity) { + *badPtr = name; + return 0; + } + if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) { + if (standalone) + *standalone = 1; + } + else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) { + if (standalone) + *standalone = 0; + } + else { + *badPtr = val; + return 0; + } + while (isSpace(toAscii(enc, ptr, end))) + ptr += enc->minBytesPerChar; + if (ptr != end) { + *badPtr = ptr; + return 0; + } + return 1; +} + +static int FASTCALL +checkCharRefNumber(int result) +{ + switch (result >> 8) { + case 0xD8: case 0xD9: case 0xDA: case 0xDB: + case 0xDC: case 0xDD: case 0xDE: case 0xDF: + return -1; + case 0: + if (latin1_encoding.type[result] == BT_NONXML) + return -1; + break; + case 0xFF: + if (result == 0xFFFE || result == 0xFFFF) + return -1; + break; + } + return result; +} + +int FASTCALL +XmlUtf8Encode(int c, char *buf) +{ + enum { + /* minN is minimum legal resulting value for N byte sequence */ + min2 = 0x80, + min3 = 0x800, + min4 = 0x10000 + }; + + if (c < 0) + return 0; + if (c < min2) { + buf[0] = (char)(c | UTF8_cval1); + return 1; + } + if (c < min3) { + buf[0] = (char)((c >> 6) | UTF8_cval2); + buf[1] = (char)((c & 0x3f) | 0x80); + return 2; + } + if (c < min4) { + buf[0] = (char)((c >> 12) | UTF8_cval3); + buf[1] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[2] = (char)((c & 0x3f) | 0x80); + return 3; + } + if (c < 0x110000) { + buf[0] = (char)((c >> 18) | UTF8_cval4); + buf[1] = (char)(((c >> 12) & 0x3f) | 0x80); + buf[2] = (char)(((c >> 6) & 0x3f) | 0x80); + buf[3] = (char)((c & 0x3f) | 0x80); + return 4; + } + return 0; +} + +int FASTCALL +XmlUtf16Encode(int charNum, unsigned short *buf) +{ + if (charNum < 0) + return 0; + if (charNum < 0x10000) { + buf[0] = (unsigned short)charNum; + return 1; + } + if (charNum < 0x110000) { + charNum -= 0x10000; + buf[0] = (unsigned short)((charNum >> 10) + 0xD800); + buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00); + return 2; + } + return 0; +} + +struct unknown_encoding { + struct normal_encoding normal; + CONVERTER convert; + void *userData; + unsigned short utf16[256]; + char utf8[256][4]; +}; + +#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc)) + +int +XmlSizeOfUnknownEncoding(void) +{ + return sizeof(struct unknown_encoding); +} + +static int PTRFASTCALL +unknown_isName(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isNmstrt(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + if (c & ~0xFFFF) + return 0; + return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF); +} + +static int PTRFASTCALL +unknown_isInvalid(const ENCODING *enc, const char *p) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + int c = uenc->convert(uenc->userData, p); + return (c & ~0xFFFF) || checkCharRefNumber(c) < 0; +} + +static void PTRCALL +unknown_toUtf8(const ENCODING *enc, + const char **fromP, const char *fromLim, + char **toP, const char *toLim) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + char buf[XML_UTF8_ENCODE_MAX]; + for (;;) { + const char *utf8; + int n; + if (*fromP == fromLim) + break; + utf8 = uenc->utf8[(unsigned char)**fromP]; + n = *utf8++; + if (n == 0) { + int c = uenc->convert(uenc->userData, *fromP); + n = XmlUtf8Encode(c, buf); + if (n > toLim - *toP) + break; + utf8 = buf; + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } + else { + if (n > toLim - *toP) + break; + (*fromP)++; + } + do { + *(*toP)++ = *utf8++; + } while (--n != 0); + } +} + +static void PTRCALL +unknown_toUtf16(const ENCODING *enc, + const char **fromP, const char *fromLim, + unsigned short **toP, const unsigned short *toLim) +{ + const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc); + while (*fromP != fromLim && *toP != toLim) { + unsigned short c = uenc->utf16[(unsigned char)**fromP]; + if (c == 0) { + c = (unsigned short) + uenc->convert(uenc->userData, *fromP); + *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP] + - (BT_LEAD2 - 2)); + } + else + (*fromP)++; + *(*toP)++ = c; + } +} + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + CONVERTER convert, + void *userData) +{ + int i; + struct unknown_encoding *e = (struct unknown_encoding *)mem; + for (i = 0; i < (int)sizeof(struct normal_encoding); i++) + ((char *)mem)[i] = ((char *)&latin1_encoding)[i]; + for (i = 0; i < 128; i++) + if (latin1_encoding.type[i] != BT_OTHER + && latin1_encoding.type[i] != BT_NONXML + && table[i] != i) + return 0; + for (i = 0; i < 256; i++) { + int c = table[i]; + if (c == -1) { + e->normal.type[i] = BT_MALFORM; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else if (c < 0) { + if (c < -4) + return 0; + e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2)); + e->utf8[i][0] = 0; + e->utf16[i] = 0; + } + else if (c < 0x80) { + if (latin1_encoding.type[c] != BT_OTHER + && latin1_encoding.type[c] != BT_NONXML + && c != i) + return 0; + e->normal.type[i] = latin1_encoding.type[c]; + e->utf8[i][0] = 1; + e->utf8[i][1] = (char)c; + e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c); + } + else if (checkCharRefNumber(c) < 0) { + e->normal.type[i] = BT_NONXML; + /* This shouldn't really get used. */ + e->utf16[i] = 0xFFFF; + e->utf8[i][0] = 1; + e->utf8[i][1] = 0; + } + else { + if (c > 0xFFFF) + return 0; + if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NMSTRT; + else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff)) + e->normal.type[i] = BT_NAME; + else + e->normal.type[i] = BT_OTHER; + e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1); + e->utf16[i] = (unsigned short)c; + } + } + e->userData = userData; + e->convert = convert; + if (convert) { + e->normal.isName2 = unknown_isName; + e->normal.isName3 = unknown_isName; + e->normal.isName4 = unknown_isName; + e->normal.isNmstrt2 = unknown_isNmstrt; + e->normal.isNmstrt3 = unknown_isNmstrt; + e->normal.isNmstrt4 = unknown_isNmstrt; + e->normal.isInvalid2 = unknown_isInvalid; + e->normal.isInvalid3 = unknown_isInvalid; + e->normal.isInvalid4 = unknown_isInvalid; + } + e->normal.enc.utf8Convert = unknown_toUtf8; + e->normal.enc.utf16Convert = unknown_toUtf16; + return &(e->normal.enc); +} + +/* If this enumeration is changed, getEncodingIndex and encodings +must also be changed. */ +enum { + UNKNOWN_ENC = -1, + ISO_8859_1_ENC = 0, + US_ASCII_ENC, + UTF_8_ENC, + UTF_16_ENC, + UTF_16BE_ENC, + UTF_16LE_ENC, + /* must match encodingNames up to here */ + NO_ENC +}; + +static const char KW_ISO_8859_1[] = { + ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, + ASCII_MINUS, ASCII_1, '\0' +}; +static const char KW_US_ASCII[] = { + ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, + '\0' +}; +static const char KW_UTF_8[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0' +}; +static const char KW_UTF_16[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0' +}; +static const char KW_UTF_16BE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, + '\0' +}; +static const char KW_UTF_16LE[] = { + ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, + '\0' +}; + +static int FASTCALL +getEncodingIndex(const char *name) +{ + static const char * const encodingNames[] = { + KW_ISO_8859_1, + KW_US_ASCII, + KW_UTF_8, + KW_UTF_16, + KW_UTF_16BE, + KW_UTF_16LE, + }; + int i; + if (name == NULL) + return NO_ENC; + for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++) + if (streqci(name, encodingNames[i])) + return i; + return UNKNOWN_ENC; +} + +/* For binary compatibility, we store the index of the encoding + specified at initialization in the isUtf16 member. +*/ + +#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16) +#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i) + +/* This is what detects the encoding. encodingTable maps from + encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of + the external (protocol) specified encoding; state is + XML_CONTENT_STATE if we're parsing an external text entity, and + XML_PROLOG_STATE otherwise. +*/ + + +static int +initScan(const ENCODING * const *encodingTable, + const INIT_ENCODING *enc, + int state, + const char *ptr, + const char *end, + const char **nextTokPtr) +{ + const ENCODING **encPtr; + + if (ptr == end) + return XML_TOK_NONE; + encPtr = enc->encPtr; + if (ptr + 1 == end) { + /* only a single byte available for auto-detection */ +#ifndef XML_DTD /* FIXME */ + /* a well-formed document entity must have more than one byte */ + if (state != XML_CONTENT_STATE) + return XML_TOK_PARTIAL; +#endif + /* so we're parsing an external text entity... */ + /* if UTF-16 was externally specified, then we need at least 2 bytes */ + switch (INIT_ENC_INDEX(enc)) { + case UTF_16_ENC: + case UTF_16LE_ENC: + case UTF_16BE_ENC: + return XML_TOK_PARTIAL; + } + switch ((unsigned char)*ptr) { + case 0xFE: + case 0xFF: + case 0xEF: /* possibly first byte of UTF-8 BOM */ + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + /* fall through */ + case 0x00: + case 0x3C: + return XML_TOK_PARTIAL; + } + } + else { + switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) { + case 0xFEFF: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XML_TOK_BOM; + /* 00 3C is handled in the default case */ + case 0x3C00: + if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC + || INIT_ENC_INDEX(enc) == UTF_16_ENC) + && state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + case 0xFFFE: + if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC + && state == XML_CONTENT_STATE) + break; + *nextTokPtr = ptr + 2; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XML_TOK_BOM; + case 0xEFBB: + /* Maybe a UTF-8 BOM (EF BB BF) */ + /* If there's an explicitly specified (external) encoding + of ISO-8859-1 or some flavour of UTF-16 + and this is an external text entity, + don't look for the BOM, + because it might be a legal data. + */ + if (state == XML_CONTENT_STATE) { + int e = INIT_ENC_INDEX(enc); + if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC + || e == UTF_16LE_ENC || e == UTF_16_ENC) + break; + } + if (ptr + 2 == end) + return XML_TOK_PARTIAL; + if ((unsigned char)ptr[2] == 0xBF) { + *nextTokPtr = ptr + 3; + *encPtr = encodingTable[UTF_8_ENC]; + return XML_TOK_BOM; + } + break; + default: + if (ptr[0] == '\0') { + /* 0 isn't a legal data character. Furthermore a document + entity can only start with ASCII characters. So the only + way this can fail to be big-endian UTF-16 if it it's an + external parsed general entity that's labelled as + UTF-16LE. + */ + if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC) + break; + *encPtr = encodingTable[UTF_16BE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + else if (ptr[1] == '\0') { + /* We could recover here in the case: + - parsing an external entity + - second byte is 0 + - no externally specified encoding + - no encoding declaration + by assuming UTF-16LE. But we don't, because this would mean when + presented just with a single byte, we couldn't reliably determine + whether we needed further bytes. + */ + if (state == XML_CONTENT_STATE) + break; + *encPtr = encodingTable[UTF_16LE_ENC]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); + } + break; + } + } + *encPtr = encodingTable[INIT_ENC_INDEX(enc)]; + return XmlTok(*encPtr, state, ptr, end, nextTokPtr); +} + + +#define NS(x) x +#define ns(x) x +#include "xmltok_ns.c" +#undef NS +#undef ns + +#ifdef XML_NS + +#define NS(x) x ## NS +#define ns(x) x ## _ns + +#include "xmltok_ns.c" + +#undef NS +#undef ns + +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + CONVERTER convert, + void *userData) +{ + ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData); + if (enc) + ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON; + return enc; +} + +#endif /* XML_NS */ diff --git a/sys/src/cmd/python/Modules/expat/xmltok.h b/sys/src/cmd/python/Modules/expat/xmltok.h new file mode 100644 index 000000000..ca867aa6b --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmltok.h @@ -0,0 +1,316 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef XmlTok_INCLUDED +#define XmlTok_INCLUDED 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* The following token may be returned by XmlContentTok */ +#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be + start of illegal ]]> sequence */ +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_NONE -4 /* The string to be scanned is empty */ +#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan; + might be part of CRLF sequence */ +#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */ +#define XML_TOK_PARTIAL -1 /* only part of a token */ +#define XML_TOK_INVALID 0 + +/* The following tokens are returned by XmlContentTok; some are also + returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok. +*/ +#define XML_TOK_START_TAG_WITH_ATTS 1 +#define XML_TOK_START_TAG_NO_ATTS 2 +#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */ +#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4 +#define XML_TOK_END_TAG 5 +#define XML_TOK_DATA_CHARS 6 +#define XML_TOK_DATA_NEWLINE 7 +#define XML_TOK_CDATA_SECT_OPEN 8 +#define XML_TOK_ENTITY_REF 9 +#define XML_TOK_CHAR_REF 10 /* numeric character reference */ + +/* The following tokens may be returned by both XmlPrologTok and + XmlContentTok. +*/ +#define XML_TOK_PI 11 /* processing instruction */ +#define XML_TOK_XML_DECL 12 /* XML decl or text decl */ +#define XML_TOK_COMMENT 13 +#define XML_TOK_BOM 14 /* Byte order mark */ + +/* The following tokens are returned only by XmlPrologTok */ +#define XML_TOK_PROLOG_S 15 +#define XML_TOK_DECL_OPEN 16 /* <!foo */ +#define XML_TOK_DECL_CLOSE 17 /* > */ +#define XML_TOK_NAME 18 +#define XML_TOK_NMTOKEN 19 +#define XML_TOK_POUND_NAME 20 /* #name */ +#define XML_TOK_OR 21 /* | */ +#define XML_TOK_PERCENT 22 +#define XML_TOK_OPEN_PAREN 23 +#define XML_TOK_CLOSE_PAREN 24 +#define XML_TOK_OPEN_BRACKET 25 +#define XML_TOK_CLOSE_BRACKET 26 +#define XML_TOK_LITERAL 27 +#define XML_TOK_PARAM_ENTITY_REF 28 +#define XML_TOK_INSTANCE_START 29 + +/* The following occur only in element type declarations */ +#define XML_TOK_NAME_QUESTION 30 /* name? */ +#define XML_TOK_NAME_ASTERISK 31 /* name* */ +#define XML_TOK_NAME_PLUS 32 /* name+ */ +#define XML_TOK_COND_SECT_OPEN 33 /* <![ */ +#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */ +#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */ +#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */ +#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */ +#define XML_TOK_COMMA 38 + +/* The following token is returned only by XmlAttributeValueTok */ +#define XML_TOK_ATTRIBUTE_VALUE_S 39 + +/* The following token is returned only by XmlCdataSectionTok */ +#define XML_TOK_CDATA_SECT_CLOSE 40 + +/* With namespace processing this is returned by XmlPrologTok for a + name with a colon. +*/ +#define XML_TOK_PREFIXED_NAME 41 + +#ifdef XML_DTD +#define XML_TOK_IGNORE_SECT 42 +#endif /* XML_DTD */ + +#ifdef XML_DTD +#define XML_N_STATES 4 +#else /* not XML_DTD */ +#define XML_N_STATES 3 +#endif /* not XML_DTD */ + +#define XML_PROLOG_STATE 0 +#define XML_CONTENT_STATE 1 +#define XML_CDATA_SECTION_STATE 2 +#ifdef XML_DTD +#define XML_IGNORE_SECTION_STATE 3 +#endif /* XML_DTD */ + +#define XML_N_LITERAL_TYPES 2 +#define XML_ATTRIBUTE_VALUE_LITERAL 0 +#define XML_ENTITY_VALUE_LITERAL 1 + +/* The size of the buffer passed to XmlUtf8Encode must be at least this. */ +#define XML_UTF8_ENCODE_MAX 4 +/* The size of the buffer passed to XmlUtf16Encode must be at least this. */ +#define XML_UTF16_ENCODE_MAX 2 + +typedef struct position { + /* first line and first column are 0 not 1 */ + XML_Size lineNumber; + XML_Size columnNumber; +} POSITION; + +typedef struct { + const char *name; + const char *valuePtr; + const char *valueEnd; + char normalized; +} ATTRIBUTE; + +struct encoding; +typedef struct encoding ENCODING; + +typedef int (PTRCALL *SCANNER)(const ENCODING *, + const char *, + const char *, + const char **); + +struct encoding { + SCANNER scanners[XML_N_STATES]; + SCANNER literalScanners[XML_N_LITERAL_TYPES]; + int (PTRCALL *sameName)(const ENCODING *, + const char *, + const char *); + int (PTRCALL *nameMatchesAscii)(const ENCODING *, + const char *, + const char *, + const char *); + int (PTRFASTCALL *nameLength)(const ENCODING *, const char *); + const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *); + int (PTRCALL *getAtts)(const ENCODING *enc, + const char *ptr, + int attsMax, + ATTRIBUTE *atts); + int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr); + int (PTRCALL *predefinedEntityName)(const ENCODING *, + const char *, + const char *); + void (PTRCALL *updatePosition)(const ENCODING *, + const char *ptr, + const char *end, + POSITION *); + int (PTRCALL *isPublicId)(const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr); + void (PTRCALL *utf8Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + char **toP, + const char *toLim); + void (PTRCALL *utf16Convert)(const ENCODING *enc, + const char **fromP, + const char *fromLim, + unsigned short **toP, + const unsigned short *toLim); + int minBytesPerChar; + char isUtf8; + char isUtf16; +}; + +/* Scan the string starting at ptr until the end of the next complete + token, but do not scan past eptr. Return an integer giving the + type of token. + + Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set. + + Return XML_TOK_PARTIAL when the string does not contain a complete + token; nextTokPtr will not be set. + + Return XML_TOK_INVALID when the string does not start a valid + token; nextTokPtr will be set to point to the character which made + the token invalid. + + Otherwise the string starts with a valid token; nextTokPtr will be + set to point to the character following the end of that token. + + Each data character counts as a single token, but adjacent data + characters may be returned together. Similarly for characters in + the prolog outside literals, comments and processing instructions. +*/ + + +#define XmlTok(enc, state, ptr, end, nextTokPtr) \ + (((enc)->scanners[state])(enc, ptr, end, nextTokPtr)) + +#define XmlPrologTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr) + +#define XmlContentTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr) + +#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr) + +#ifdef XML_DTD + +#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \ + XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr) + +#endif /* XML_DTD */ + +/* This is used for performing a 2nd-level tokenization on the content + of a literal that has already been returned by XmlTok. +*/ +#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \ + (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr)) + +#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \ + XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr) + +#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2)) + +#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \ + (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2)) + +#define XmlNameLength(enc, ptr) \ + (((enc)->nameLength)(enc, ptr)) + +#define XmlSkipS(enc, ptr) \ + (((enc)->skipS)(enc, ptr)) + +#define XmlGetAttributes(enc, ptr, attsMax, atts) \ + (((enc)->getAtts)(enc, ptr, attsMax, atts)) + +#define XmlCharRefNumber(enc, ptr) \ + (((enc)->charRefNumber)(enc, ptr)) + +#define XmlPredefinedEntityName(enc, ptr, end) \ + (((enc)->predefinedEntityName)(enc, ptr, end)) + +#define XmlUpdatePosition(enc, ptr, end, pos) \ + (((enc)->updatePosition)(enc, ptr, end, pos)) + +#define XmlIsPublicId(enc, ptr, end, badPtr) \ + (((enc)->isPublicId)(enc, ptr, end, badPtr)) + +#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim)) + +#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \ + (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim)) + +typedef struct { + ENCODING initEnc; + const ENCODING **encPtr; +} INIT_ENCODING; + +int XmlParseXmlDecl(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncoding(void); +const ENCODING *XmlGetUtf16InternalEncoding(void); +int FASTCALL XmlUtf8Encode(int charNumber, char *buf); +int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf); +int XmlSizeOfUnknownEncoding(void); + + +typedef int (XMLCALL *CONVERTER) (void *userData, const char *p); + +ENCODING * +XmlInitUnknownEncoding(void *mem, + int *table, + CONVERTER convert, + void *userData); + +int XmlParseXmlDeclNS(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingNamePtr, + const ENCODING **namedEncodingPtr, + int *standalonePtr); + +int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name); +const ENCODING *XmlGetUtf8InternalEncodingNS(void); +const ENCODING *XmlGetUtf16InternalEncodingNS(void); +ENCODING * +XmlInitUnknownEncodingNS(void *mem, + int *table, + CONVERTER convert, + void *userData); +#ifdef __cplusplus +} +#endif + +#endif /* not XmlTok_INCLUDED */ diff --git a/sys/src/cmd/python/Modules/expat/xmltok_impl.c b/sys/src/cmd/python/Modules/expat/xmltok_impl.c new file mode 100644 index 000000000..0ee57abb1 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmltok_impl.c @@ -0,0 +1,1779 @@ +/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd + See the file COPYING for copying permission. +*/ + +#ifndef IS_INVALID_CHAR +#define IS_INVALID_CHAR(enc, ptr, n) (0) +#endif + +#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_INVALID_CHAR(enc, ptr, n)) { \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define INVALID_CASES(ptr, nextTokPtr) \ + INVALID_LEAD_CASE(2, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(3, ptr, nextTokPtr) \ + INVALID_LEAD_CASE(4, ptr, nextTokPtr) \ + case BT_NONXML: \ + case BT_MALFORM: \ + case BT_TRAIL: \ + *(nextTokPtr) = (ptr); \ + return XML_TOK_INVALID; + +#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NAME_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + case BT_DIGIT: \ + case BT_NAME: \ + case BT_MINUS: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr) + +#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + ptr += n; \ + break; + +#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \ + case BT_NONASCII: \ + if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; \ + } \ + case BT_NMSTRT: \ + case BT_HEX: \ + ptr += MINBPC(enc); \ + break; \ + CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \ + CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr) + +#ifndef PREFIX +#define PREFIX(ident) ident +#endif + +/* ptr points to character following "<!-" */ + +static int PTRCALL +PREFIX(scanComment)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + if (ptr != end) { + if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + ptr += MINBPC(enc); + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_MINUS: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMENT; + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "<!" */ + +static int PTRCALL +PREFIX(scanDecl)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_MINUS: + return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COND_SECT_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_PERCNT: + if (ptr + MINBPC(enc) == end) + return XML_TOK_PARTIAL; + /* don't allow <!ENTITY% foo "whatever"> */ + switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) { + case BT_S: case BT_CR: case BT_LF: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* fall through */ + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DECL_OPEN; + case BT_NMSTRT: + case BT_HEX: + ptr += MINBPC(enc); + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, + const char *end, int *tokPtr) +{ + int upper = 0; + *tokPtr = XML_TOK_PI; + if (end - ptr != MINBPC(enc)*3) + return 1; + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_x: + break; + case ASCII_X: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_m: + break; + case ASCII_M: + upper = 1; + break; + default: + return 1; + } + ptr += MINBPC(enc); + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + break; + case ASCII_L: + upper = 1; + break; + default: + return 1; + } + if (upper) + return 0; + *tokPtr = XML_TOK_XML_DECL; + return 1; +} + +/* ptr points to character following "<?" */ + +static int PTRCALL +PREFIX(scanPi)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + int tok; + const char *target = ptr; + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_CR: case BT_LF: + if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + ptr += MINBPC(enc); + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUEST: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr + MINBPC(enc); + return tok; + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; + case BT_QUEST: + if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr + MINBPC(enc); + return tok; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A, + ASCII_T, ASCII_A, ASCII_LSQB }; + int i; + /* CDATA[ */ + if (end - ptr < 6 * MINBPC(enc)) + return XML_TOK_PARTIAL; + for (i = 0; i < 6; i++, ptr += MINBPC(enc)) { + if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + *nextTokPtr = ptr; + return XML_TOK_CDATA_SECT_OPEN; +} + +static int PTRCALL +PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CDATA_SECT_CLOSE; + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + case BT_RSQB: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "</" */ + +static int PTRCALL +PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_CR: case BT_LF: + for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + break; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_END_TAG; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +#ifdef XML_NS + case BT_COLON: + /* no need to check qname syntax here, + since end-tag must match exactly */ + ptr += MINBPC(enc); + break; +#endif + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_END_TAG; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "&#X" */ + +static int PTRCALL +PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + if (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + break; + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CHAR_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "&#" */ + +static int PTRCALL +PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + if (ptr != end) { + if (CHAR_MATCHES(enc, ptr, ASCII_x)) + return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + break; + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CHAR_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "&" */ + +static int PTRCALL +PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_NUM: + return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following first character of attribute name */ + +static int PTRCALL +PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ +#ifdef XML_NS + int hadColon = 0; +#endif + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) +#ifdef XML_NS + case BT_COLON: + if (hadColon) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + hadColon = 1; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + break; +#endif + case BT_S: case BT_CR: case BT_LF: + for (;;) { + int t; + + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + t = BYTE_TYPE(enc, ptr); + if (t == BT_EQUALS) + break; + switch (t) { + case BT_S: + case BT_LF: + case BT_CR: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_EQUALS: + { + int open; +#ifdef XML_NS + hadColon = 0; +#endif + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + open = BYTE_TYPE(enc, ptr); + if (open == BT_QUOT || open == BT_APOS) + break; + switch (open) { + case BT_S: + case BT_LF: + case BT_CR: + break; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + ptr += MINBPC(enc); + /* in attribute value */ + for (;;) { + int t; + if (ptr == end) + return XML_TOK_PARTIAL; + t = BYTE_TYPE(enc, ptr); + if (t == open) + break; + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_AMP: + { + int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr); + if (tok <= 0) { + if (tok == XML_TOK_INVALID) + *nextTokPtr = ptr; + return tok; + } + break; + } + case BT_LT: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + default: + ptr += MINBPC(enc); + break; + } + } + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: + case BT_CR: + case BT_LF: + break; + case BT_SOL: + goto sol; + case BT_GT: + goto gt; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + /* ptr points to closing quote */ + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_CR: case BT_LF: + continue; + case BT_GT: + gt: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_START_TAG_WITH_ATTS; + case BT_SOL: + sol: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_EMPTY_ELEMENT_WITH_ATTS; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + break; + } + break; + } + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +/* ptr points to character following "<" */ + +static int PTRCALL +PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ +#ifdef XML_NS + int hadColon; +#endif + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_EXCL: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_MINUS: + return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LSQB: + return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc), + end, nextTokPtr); + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_SOL: + return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr); + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } +#ifdef XML_NS + hadColon = 0; +#endif + /* we have a start-tag */ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) +#ifdef XML_NS + case BT_COLON: + if (hadColon) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + hadColon = 1; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + break; +#endif + case BT_S: case BT_CR: case BT_LF: + { + ptr += MINBPC(enc); + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: + goto gt; + case BT_SOL: + goto sol; + case BT_S: case BT_CR: case BT_LF: + ptr += MINBPC(enc); + continue; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr); + } + return XML_TOK_PARTIAL; + } + case BT_GT: + gt: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_START_TAG_NO_ATTS; + case BT_SOL: + sol: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_EMPTY_ELEMENT_NO_ATTS; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_LT: + return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_AMP: + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_CR: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + case BT_LF: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB)) + break; + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_RSQB; + if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr -= MINBPC(enc); + break; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + INVALID_CASES(ptr, nextTokPtr) + default: + ptr += MINBPC(enc); + break; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \ + *nextTokPtr = ptr; \ + return XML_TOK_DATA_CHARS; \ + } \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_RSQB: + if (ptr + MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) { + ptr += MINBPC(enc); + break; + } + if (ptr + 2*MINBPC(enc) != end) { + if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) { + ptr += MINBPC(enc); + break; + } + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_INVALID; + } + } + /* fall through */ + case BT_AMP: + case BT_LT: + case BT_NONXML: + case BT_MALFORM: + case BT_TRAIL: + case BT_CR: + case BT_LF: + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +/* ptr points to character following "%" */ + +static int PTRCALL +PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return -XML_TOK_PERCENT; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + case BT_S: case BT_LF: case BT_CR: case BT_PERCNT: + *nextTokPtr = ptr; + return XML_TOK_PERCENT; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_SEMI: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_PARAM_ENTITY_REF; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_CR: case BT_LF: case BT_S: + case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR: + *nextTokPtr = ptr; + return XML_TOK_POUND_NAME; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -XML_TOK_POUND_NAME; +} + +static int PTRCALL +PREFIX(scanLit)(int open, const ENCODING *enc, + const char *ptr, const char *end, + const char **nextTokPtr) +{ + while (ptr != end) { + int t = BYTE_TYPE(enc, ptr); + switch (t) { + INVALID_CASES(ptr, nextTokPtr) + case BT_QUOT: + case BT_APOS: + ptr += MINBPC(enc); + if (t != open) + break; + if (ptr == end) + return -XML_TOK_LITERAL; + *nextTokPtr = ptr; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_CR: case BT_LF: + case BT_GT: case BT_PERCNT: case BT_LSQB: + return XML_TOK_LITERAL; + default: + return XML_TOK_INVALID; + } + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +static int PTRCALL +PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + int tok; + if (ptr == end) + return XML_TOK_NONE; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + if (n == 0) + return XML_TOK_PARTIAL; + end = ptr + n; + } + } + switch (BYTE_TYPE(enc, ptr)) { + case BT_QUOT: + return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_APOS: + return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_LT: + { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_PARTIAL; + switch (BYTE_TYPE(enc, ptr)) { + case BT_EXCL: + return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_QUEST: + return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_NMSTRT: + case BT_HEX: + case BT_NONASCII: + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + *nextTokPtr = ptr - MINBPC(enc); + return XML_TOK_INSTANCE_START; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + case BT_CR: + if (ptr + MINBPC(enc) == end) { + *nextTokPtr = end; + /* indicate that this might be part of a CR/LF pair */ + return -XML_TOK_PROLOG_S; + } + /* fall through */ + case BT_S: case BT_LF: + for (;;) { + ptr += MINBPC(enc); + if (ptr == end) + break; + switch (BYTE_TYPE(enc, ptr)) { + case BT_S: case BT_LF: + break; + case BT_CR: + /* don't split CR/LF pair */ + if (ptr + MINBPC(enc) != end) + break; + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + } + } + *nextTokPtr = ptr; + return XML_TOK_PROLOG_S; + case BT_PERCNT: + return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr); + case BT_COMMA: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_COMMA; + case BT_LSQB: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_BRACKET; + case BT_RSQB: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_BRACKET; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if (ptr + MINBPC(enc) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) { + *nextTokPtr = ptr + 2*MINBPC(enc); + return XML_TOK_COND_SECT_CLOSE; + } + } + *nextTokPtr = ptr; + return XML_TOK_CLOSE_BRACKET; + case BT_LPAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OPEN_PAREN; + case BT_RPAR: + ptr += MINBPC(enc); + if (ptr == end) + return -XML_TOK_CLOSE_PAREN; + switch (BYTE_TYPE(enc, ptr)) { + case BT_AST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_ASTERISK; + case BT_QUEST: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_QUESTION; + case BT_PLUS: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_CLOSE_PAREN_PLUS; + case BT_CR: case BT_LF: case BT_S: + case BT_GT: case BT_COMMA: case BT_VERBAR: + case BT_RPAR: + *nextTokPtr = ptr; + return XML_TOK_CLOSE_PAREN; + } + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_VERBAR: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_OR; + case BT_GT: + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DECL_CLOSE; + case BT_NUM: + return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr); +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (end - ptr < n) \ + return XML_TOK_PARTIAL_CHAR; \ + if (IS_NMSTRT_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NAME; \ + break; \ + } \ + if (IS_NAME_CHAR(enc, ptr, n)) { \ + ptr += n; \ + tok = XML_TOK_NMTOKEN; \ + break; \ + } \ + *nextTokPtr = ptr; \ + return XML_TOK_INVALID; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NMSTRT: + case BT_HEX: + tok = XML_TOK_NAME; + ptr += MINBPC(enc); + break; + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: +#ifdef XML_NS + case BT_COLON: +#endif + tok = XML_TOK_NMTOKEN; + ptr += MINBPC(enc); + break; + case BT_NONASCII: + if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NAME; + break; + } + if (IS_NAME_CHAR_MINBPC(enc, ptr)) { + ptr += MINBPC(enc); + tok = XML_TOK_NMTOKEN; + break; + } + /* fall through */ + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + case BT_GT: case BT_RPAR: case BT_COMMA: + case BT_VERBAR: case BT_LSQB: case BT_PERCNT: + case BT_S: case BT_CR: case BT_LF: + *nextTokPtr = ptr; + return tok; +#ifdef XML_NS + case BT_COLON: + ptr += MINBPC(enc); + switch (tok) { + case XML_TOK_NAME: + if (ptr == end) + return XML_TOK_PARTIAL; + tok = XML_TOK_PREFIXED_NAME; + switch (BYTE_TYPE(enc, ptr)) { + CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) + default: + tok = XML_TOK_NMTOKEN; + break; + } + break; + case XML_TOK_PREFIXED_NAME: + tok = XML_TOK_NMTOKEN; + break; + } + break; +#endif + case BT_PLUS: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_PLUS; + case BT_AST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_ASTERISK; + case BT_QUEST: + if (tok == XML_TOK_NMTOKEN) { + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_NAME_QUESTION; + default: + *nextTokPtr = ptr; + return XML_TOK_INVALID; + } + } + return -tok; +} + +static int PTRCALL +PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LT: + /* this is for inside entity references */ + *nextTokPtr = ptr; + return XML_TOK_INVALID; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_S: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_ATTRIBUTE_VALUE_S; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +static int PTRCALL +PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + const char *start; + if (ptr == end) + return XML_TOK_NONE; + start = ptr; + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_AMP: + if (ptr == start) + return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr); + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_PERCNT: + if (ptr == start) { + int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc), + end, nextTokPtr); + return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_LF: + if (ptr == start) { + *nextTokPtr = ptr + MINBPC(enc); + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + case BT_CR: + if (ptr == start) { + ptr += MINBPC(enc); + if (ptr == end) + return XML_TOK_TRAILING_CR; + if (BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + *nextTokPtr = ptr; + return XML_TOK_DATA_NEWLINE; + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; + default: + ptr += MINBPC(enc); + break; + } + } + *nextTokPtr = ptr; + return XML_TOK_DATA_CHARS; +} + +#ifdef XML_DTD + +static int PTRCALL +PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, + const char *end, const char **nextTokPtr) +{ + int level = 0; + if (MINBPC(enc) > 1) { + size_t n = end - ptr; + if (n & (MINBPC(enc) - 1)) { + n &= ~(MINBPC(enc) - 1); + end = ptr + n; + } + } + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { + INVALID_CASES(ptr, nextTokPtr) + case BT_LT: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) { + ++level; + ptr += MINBPC(enc); + } + } + break; + case BT_RSQB: + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) { + if ((ptr += MINBPC(enc)) == end) + return XML_TOK_PARTIAL; + if (CHAR_MATCHES(enc, ptr, ASCII_GT)) { + ptr += MINBPC(enc); + if (level == 0) { + *nextTokPtr = ptr; + return XML_TOK_IGNORE_SECT; + } + --level; + } + } + break; + default: + ptr += MINBPC(enc); + break; + } + } + return XML_TOK_PARTIAL; +} + +#endif /* XML_DTD */ + +static int PTRCALL +PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end, + const char **badPtr) +{ + ptr += MINBPC(enc); + end -= MINBPC(enc); + for (; ptr != end; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_DIGIT: + case BT_HEX: + case BT_MINUS: + case BT_APOS: + case BT_LPAR: + case BT_RPAR: + case BT_PLUS: + case BT_COMMA: + case BT_SOL: + case BT_EQUALS: + case BT_QUEST: + case BT_CR: + case BT_LF: + case BT_SEMI: + case BT_EXCL: + case BT_AST: + case BT_PERCNT: + case BT_NUM: +#ifdef XML_NS + case BT_COLON: +#endif + break; + case BT_S: + if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) { + *badPtr = ptr; + return 0; + } + break; + case BT_NAME: + case BT_NMSTRT: + if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f)) + break; + default: + switch (BYTE_TO_ASCII(enc, ptr)) { + case 0x24: /* $ */ + case 0x40: /* @ */ + break; + default: + *badPtr = ptr; + return 0; + } + break; + } + } + return 1; +} + +/* This must only be called for a well-formed start-tag or empty + element tag. Returns the number of attributes. Pointers to the + first attsMax attributes are stored in atts. +*/ + +static int PTRCALL +PREFIX(getAtts)(const ENCODING *enc, const char *ptr, + int attsMax, ATTRIBUTE *atts) +{ + enum { other, inName, inValue } state = inName; + int nAtts = 0; + int open = 0; /* defined when state == inValue; + initialization just to shut up compilers */ + + for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) { + switch (BYTE_TYPE(enc, ptr)) { +#define START_NAME \ + if (state == other) { \ + if (nAtts < attsMax) { \ + atts[nAtts].name = ptr; \ + atts[nAtts].normalized = 1; \ + } \ + state = inName; \ + } +#define LEAD_CASE(n) \ + case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: + case BT_HEX: + START_NAME + break; +#undef START_NAME + case BT_QUOT: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_QUOT; + } + else if (open == BT_QUOT) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_APOS: + if (state != inValue) { + if (nAtts < attsMax) + atts[nAtts].valuePtr = ptr + MINBPC(enc); + state = inValue; + open = BT_APOS; + } + else if (open == BT_APOS) { + state = other; + if (nAtts < attsMax) + atts[nAtts].valueEnd = ptr; + nAtts++; + } + break; + case BT_AMP: + if (nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_S: + if (state == inName) + state = other; + else if (state == inValue + && nAtts < attsMax + && atts[nAtts].normalized + && (ptr == atts[nAtts].valuePtr + || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE + || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE + || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open)) + atts[nAtts].normalized = 0; + break; + case BT_CR: case BT_LF: + /* This case ensures that the first attribute name is counted + Apart from that we could just change state on the quote. */ + if (state == inName) + state = other; + else if (state == inValue && nAtts < attsMax) + atts[nAtts].normalized = 0; + break; + case BT_GT: + case BT_SOL: + if (state != inValue) + return nAtts; + break; + default: + break; + } + } + /* not reached */ +} + +static int PTRFASTCALL +PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr) +{ + int result = 0; + /* skip &# */ + ptr += 2*MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_x)) { + for (ptr += MINBPC(enc); + !CHAR_MATCHES(enc, ptr, ASCII_SEMI); + ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + switch (c) { + case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4: + case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9: + result <<= 4; + result |= (c - ASCII_0); + break; + case ASCII_A: case ASCII_B: case ASCII_C: + case ASCII_D: case ASCII_E: case ASCII_F: + result <<= 4; + result += 10 + (c - ASCII_A); + break; + case ASCII_a: case ASCII_b: case ASCII_c: + case ASCII_d: case ASCII_e: case ASCII_f: + result <<= 4; + result += 10 + (c - ASCII_a); + break; + } + if (result >= 0x110000) + return -1; + } + } + else { + for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) { + int c = BYTE_TO_ASCII(enc, ptr); + result *= 10; + result += (c - ASCII_0); + if (result >= 0x110000) + return -1; + } + } + return checkCharRefNumber(result); +} + +static int PTRCALL +PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, + const char *end) +{ + switch ((end - ptr)/MINBPC(enc)) { + case 2: + if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) { + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_l: + return ASCII_LT; + case ASCII_g: + return ASCII_GT; + } + } + break; + case 3: + if (CHAR_MATCHES(enc, ptr, ASCII_a)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_m)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) + return ASCII_AMP; + } + } + break; + case 4: + switch (BYTE_TO_ASCII(enc, ptr)) { + case ASCII_q: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_u)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_t)) + return ASCII_QUOT; + } + } + break; + case ASCII_a: + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_p)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_o)) { + ptr += MINBPC(enc); + if (CHAR_MATCHES(enc, ptr, ASCII_s)) + return ASCII_APOS; + } + } + break; + } + } + return 0; +} + +static int PTRCALL +PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr1)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + if (*ptr1++ != *ptr2++) \ + return 0; + LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2) +#undef LEAD_CASE + /* fall through */ + if (*ptr1++ != *ptr2++) + return 0; + break; + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 1) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 2) { + if (*ptr2++ != *ptr1++) + return 0; + if (MINBPC(enc) > 3) { + if (*ptr2++ != *ptr1++) + return 0; + } + } + } + break; + default: + if (MINBPC(enc) == 1 && *ptr1 == *ptr2) + return 1; + switch (BYTE_TYPE(enc, ptr2)) { + case BT_LEAD2: + case BT_LEAD3: + case BT_LEAD4: + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + return 0; + default: + return 1; + } + } + } + /* not reached */ +} + +static int PTRCALL +PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1, + const char *end1, const char *ptr2) +{ + for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) { + if (ptr1 == end1) + return 0; + if (!CHAR_MATCHES(enc, ptr1, *ptr2)) + return 0; + } + return ptr1 == end1; +} + +static int PTRFASTCALL +PREFIX(nameLength)(const ENCODING *enc, const char *ptr) +{ + const char *start = ptr; + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: ptr += n; break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_NONASCII: + case BT_NMSTRT: +#ifdef XML_NS + case BT_COLON: +#endif + case BT_HEX: + case BT_DIGIT: + case BT_NAME: + case BT_MINUS: + ptr += MINBPC(enc); + break; + default: + return (int)(ptr - start); + } + } +} + +static const char * PTRFASTCALL +PREFIX(skipS)(const ENCODING *enc, const char *ptr) +{ + for (;;) { + switch (BYTE_TYPE(enc, ptr)) { + case BT_LF: + case BT_CR: + case BT_S: + ptr += MINBPC(enc); + break; + default: + return ptr; + } + } +} + +static void PTRCALL +PREFIX(updatePosition)(const ENCODING *enc, + const char *ptr, + const char *end, + POSITION *pos) +{ + while (ptr != end) { + switch (BYTE_TYPE(enc, ptr)) { +#define LEAD_CASE(n) \ + case BT_LEAD ## n: \ + ptr += n; \ + break; + LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4) +#undef LEAD_CASE + case BT_LF: + pos->columnNumber = (XML_Size)-1; + pos->lineNumber++; + ptr += MINBPC(enc); + break; + case BT_CR: + pos->lineNumber++; + ptr += MINBPC(enc); + if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF) + ptr += MINBPC(enc); + pos->columnNumber = (XML_Size)-1; + break; + default: + ptr += MINBPC(enc); + break; + } + pos->columnNumber++; + } +} + +#undef DO_LEAD_CASE +#undef MULTIBYTE_CASES +#undef INVALID_CASES +#undef CHECK_NAME_CASE +#undef CHECK_NAME_CASES +#undef CHECK_NMSTRT_CASE +#undef CHECK_NMSTRT_CASES + diff --git a/sys/src/cmd/python/Modules/expat/xmltok_impl.h b/sys/src/cmd/python/Modules/expat/xmltok_impl.h new file mode 100644 index 000000000..da0ea60a6 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmltok_impl.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd +See the file COPYING for copying permission. +*/ + +enum { + BT_NONXML, + BT_MALFORM, + BT_LT, + BT_AMP, + BT_RSQB, + BT_LEAD2, + BT_LEAD3, + BT_LEAD4, + BT_TRAIL, + BT_CR, + BT_LF, + BT_GT, + BT_QUOT, + BT_APOS, + BT_EQUALS, + BT_QUEST, + BT_EXCL, + BT_SOL, + BT_SEMI, + BT_NUM, + BT_LSQB, + BT_S, + BT_NMSTRT, + BT_COLON, + BT_HEX, + BT_DIGIT, + BT_NAME, + BT_MINUS, + BT_OTHER, /* known not to be a name or name start character */ + BT_NONASCII, /* might be a name or name start character */ + BT_PERCNT, + BT_LPAR, + BT_RPAR, + BT_AST, + BT_PLUS, + BT_COMMA, + BT_VERBAR +}; + +#include <stddef.h> diff --git a/sys/src/cmd/python/Modules/expat/xmltok_ns.c b/sys/src/cmd/python/Modules/expat/xmltok_ns.c new file mode 100644 index 000000000..d2f893836 --- /dev/null +++ b/sys/src/cmd/python/Modules/expat/xmltok_ns.c @@ -0,0 +1,106 @@ +const ENCODING * +NS(XmlGetUtf8InternalEncoding)(void) +{ + return &ns(internal_utf8_encoding).enc; +} + +const ENCODING * +NS(XmlGetUtf16InternalEncoding)(void) +{ +#if BYTEORDER == 1234 + return &ns(internal_little2_encoding).enc; +#elif BYTEORDER == 4321 + return &ns(internal_big2_encoding).enc; +#else + const short n = 1; + return (*(const char *)&n + ? &ns(internal_little2_encoding).enc + : &ns(internal_big2_encoding).enc); +#endif +} + +static const ENCODING * const NS(encodings)[] = { + &ns(latin1_encoding).enc, + &ns(ascii_encoding).enc, + &ns(utf8_encoding).enc, + &ns(big2_encoding).enc, + &ns(big2_encoding).enc, + &ns(little2_encoding).enc, + &ns(utf8_encoding).enc /* NO_ENC */ +}; + +static int PTRCALL +NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, + XML_PROLOG_STATE, ptr, end, nextTokPtr); +} + +static int PTRCALL +NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end, + const char **nextTokPtr) +{ + return initScan(NS(encodings), (const INIT_ENCODING *)enc, + XML_CONTENT_STATE, ptr, end, nextTokPtr); +} + +int +NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, + const char *name) +{ + int i = getEncodingIndex(name); + if (i == UNKNOWN_ENC) + return 0; + SET_INIT_ENC_INDEX(p, i); + p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog); + p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent); + p->initEnc.updatePosition = initUpdatePosition; + p->encPtr = encPtr; + *encPtr = &(p->initEnc); + return 1; +} + +static const ENCODING * +NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end) +{ +#define ENCODING_MAX 128 + char buf[ENCODING_MAX]; + char *p = buf; + int i; + XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1); + if (ptr != end) + return 0; + *p = 0; + if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2) + return enc; + i = getEncodingIndex(buf); + if (i == UNKNOWN_ENC) + return 0; + return NS(encodings)[i]; +} + +int +NS(XmlParseXmlDecl)(int isGeneralTextEntity, + const ENCODING *enc, + const char *ptr, + const char *end, + const char **badPtr, + const char **versionPtr, + const char **versionEndPtr, + const char **encodingName, + const ENCODING **encoding, + int *standalone) +{ + return doParseXmlDecl(NS(findEncoding), + isGeneralTextEntity, + enc, + ptr, + end, + badPtr, + versionPtr, + versionEndPtr, + encodingName, + encoding, + standalone); +} diff --git a/sys/src/cmd/python/Modules/fcntlmodule.c b/sys/src/cmd/python/Modules/fcntlmodule.c new file mode 100644 index 000000000..5198baa5e --- /dev/null +++ b/sys/src/cmd/python/Modules/fcntlmodule.c @@ -0,0 +1,607 @@ + +/* fcntl module */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" + +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif + +#include <sys/ioctl.h> +#include <fcntl.h> +#ifdef HAVE_STROPTS_H +#include <stropts.h> +#endif + +static int +conv_descriptor(PyObject *object, int *target) +{ + int fd = PyObject_AsFileDescriptor(object); + + if (fd < 0) + return 0; + *target = fd; + return 1; +} + + +/* fcntl(fd, opt, [arg]) */ + +static PyObject * +fcntl_fcntl(PyObject *self, PyObject *args) +{ + int fd; + int code; + int arg; + int ret; + char *str; + Py_ssize_t len; + char buf[1024]; + + if (PyArg_ParseTuple(args, "O&is#:fcntl", + conv_descriptor, &fd, &code, &str, &len)) { + if (len > sizeof buf) { + PyErr_SetString(PyExc_ValueError, + "fcntl string arg too long"); + return NULL; + } + memcpy(buf, str, len); + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyString_FromStringAndSize(buf, len); + } + + PyErr_Clear(); + arg = 0; + if (!PyArg_ParseTuple(args, + "O&i|i;fcntl requires a file or file descriptor," + " an integer and optionally a third integer or a string", + conv_descriptor, &fd, &code, &arg)) { + return NULL; + } + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, code, arg); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyInt_FromLong((long)ret); +} + +PyDoc_STRVAR(fcntl_doc, +"fcntl(fd, opt, [arg])\n\ +\n\ +Perform the requested operation on file descriptor fd. The operation\n\ +is defined by op and is operating system dependent. These constants are\n\ +available from the fcntl module. The argument arg is optional, and\n\ +defaults to 0; it may be an int or a string. If arg is given as a string,\n\ +the return value of fcntl is a string of that length, containing the\n\ +resulting value put in the arg buffer by the operating system.The length\n\ +of the arg string is not allowed to exceed 1024 bytes. If the arg given\n\ +is an integer or if none is specified, the result value is an integer\n\ +corresponding to the return value of the fcntl call in the C code."); + + +/* ioctl(fd, opt, [arg]) */ + +static PyObject * +fcntl_ioctl(PyObject *self, PyObject *args) +{ +#define IOCTL_BUFSZ 1024 + int fd; + /* In PyArg_ParseTuple below, use the unsigned int 'I' format for + the signed int 'code' variable, because Python turns 0x8000000 + into a large positive number (PyLong, or PyInt on 64-bit + platforms,) whereas C expects it to be a negative int */ + int code; + int arg; + int ret; + char *str; + Py_ssize_t len; + int mutate_arg = 1; + char buf[IOCTL_BUFSZ+1]; /* argument plus NUL byte */ + + if (PyArg_ParseTuple(args, "O&Iw#|i:ioctl", + conv_descriptor, &fd, &code, + &str, &len, &mutate_arg)) { + char *arg; + + if (mutate_arg) { + if (len <= IOCTL_BUFSZ) { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + else { + arg = str; + } + } + else { + if (len > IOCTL_BUFSZ) { + PyErr_SetString(PyExc_ValueError, + "ioctl string arg too long"); + return NULL; + } + else { + memcpy(buf, str, len); + buf[len] = '\0'; + arg = buf; + } + } + if (buf == arg) { + Py_BEGIN_ALLOW_THREADS /* think array.resize() */ + ret = ioctl(fd, code, arg); + Py_END_ALLOW_THREADS + } + else { + ret = ioctl(fd, code, arg); + } + if (mutate_arg && (len < IOCTL_BUFSZ)) { + memcpy(str, buf, len); + } + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (mutate_arg) { + return PyInt_FromLong(ret); + } + else { + return PyString_FromStringAndSize(buf, len); + } + } + + PyErr_Clear(); + if (PyArg_ParseTuple(args, "O&Is#:ioctl", + conv_descriptor, &fd, &code, &str, &len)) { + if (len > IOCTL_BUFSZ) { + PyErr_SetString(PyExc_ValueError, + "ioctl string arg too long"); + return NULL; + } + memcpy(buf, str, len); + buf[len] = '\0'; + Py_BEGIN_ALLOW_THREADS + ret = ioctl(fd, code, buf); + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyString_FromStringAndSize(buf, len); + } + + PyErr_Clear(); + arg = 0; + if (!PyArg_ParseTuple(args, + "O&I|i;ioctl requires a file or file descriptor," + " an integer and optionally an integer or buffer argument", + conv_descriptor, &fd, &code, &arg)) { + return NULL; + } + Py_BEGIN_ALLOW_THREADS +#ifdef __VMS + ret = ioctl(fd, code, (void *)arg); +#else + ret = ioctl(fd, code, +#ifdef PLAN9APE + (void *) +#endif + arg); +#endif + Py_END_ALLOW_THREADS + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyInt_FromLong((long)ret); +#undef IOCTL_BUFSZ +} + +PyDoc_STRVAR(ioctl_doc, +"ioctl(fd, opt[, arg[, mutate_flag]])\n\ +\n\ +Perform the requested operation on file descriptor fd. The operation is\n\ +defined by opt and is operating system dependent. Typically these codes are\n\ +retrieved from the fcntl or termios library modules.\n\ +\n\ +The argument arg is optional, and defaults to 0; it may be an int or a\n\ +buffer containing character data (most likely a string or an array). \n\ +\n\ +If the argument is a mutable buffer (such as an array) and if the\n\ +mutate_flag argument (which is only allowed in this case) is true then the\n\ +buffer is (in effect) passed to the operating system and changes made by\n\ +the OS will be reflected in the contents of the buffer after the call has\n\ +returned. The return value is the integer returned by the ioctl system\n\ +call.\n\ +\n\ +If the argument is a mutable buffer and the mutable_flag argument is not\n\ +passed or is false, the behavior is as if a string had been passed. This\n\ +behavior will change in future releases of Python.\n\ +\n\ +If the argument is an immutable buffer (most likely a string) then a copy\n\ +of the buffer is passed to the operating system and the return value is a\n\ +string of the same length containing whatever the operating system put in\n\ +the buffer. The length of the arg buffer in this case is not allowed to\n\ +exceed 1024 bytes.\n\ +\n\ +If the arg given is an integer or if none is specified, the result value is\n\ +an integer corresponding to the return value of the ioctl call in the C\n\ +code."); + + +/* flock(fd, operation) */ + +static PyObject * +fcntl_flock(PyObject *self, PyObject *args) +{ + int fd; + int code; + int ret; + + if (!PyArg_ParseTuple(args, "O&i:flock", + conv_descriptor, &fd, &code)) + return NULL; + +#ifdef HAVE_FLOCK + Py_BEGIN_ALLOW_THREADS + ret = flock(fd, code); + Py_END_ALLOW_THREADS +#else + +#ifndef LOCK_SH +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* don't block when locking */ +#define LOCK_UN 8 /* unlock */ +#endif + { + struct flock l; + if (code == LOCK_UN) + l.l_type = F_UNLCK; + else if (code & LOCK_SH) + l.l_type = F_RDLCK; + else if (code & LOCK_EX) + l.l_type = F_WRLCK; + else { + PyErr_SetString(PyExc_ValueError, + "unrecognized flock argument"); + return NULL; + } + l.l_whence = l.l_start = l.l_len = 0; + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l); + Py_END_ALLOW_THREADS + } +#endif /* HAVE_FLOCK */ + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(flock_doc, +"flock(fd, operation)\n\ +\n\ +Perform the lock operation op on file descriptor fd. See the Unix \n\ +manual page for flock(3) for details. (On some systems, this function is\n\ +emulated using fcntl().)"); + + +/* lockf(fd, operation) */ +static PyObject * +fcntl_lockf(PyObject *self, PyObject *args) +{ + int fd, code, ret, whence = 0; + PyObject *lenobj = NULL, *startobj = NULL; + + if (!PyArg_ParseTuple(args, "O&i|OOi:lockf", + conv_descriptor, &fd, &code, + &lenobj, &startobj, &whence)) + return NULL; + +#if defined(PYOS_OS2) && defined(PYCC_GCC) + PyErr_SetString(PyExc_NotImplementedError, + "lockf not supported on OS/2 (EMX)"); + return NULL; +#else +#ifndef LOCK_SH +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* don't block when locking */ +#define LOCK_UN 8 /* unlock */ +#endif /* LOCK_SH */ + { + struct flock l; + if (code == LOCK_UN) + l.l_type = F_UNLCK; + else if (code & LOCK_SH) + l.l_type = F_RDLCK; + else if (code & LOCK_EX) + l.l_type = F_WRLCK; + else { + PyErr_SetString(PyExc_ValueError, + "unrecognized lockf argument"); + return NULL; + } + l.l_start = l.l_len = 0; + if (startobj != NULL) { +#if !defined(HAVE_LARGEFILE_SUPPORT) + l.l_start = PyInt_AsLong(startobj); +#else + l.l_start = PyLong_Check(startobj) ? + PyLong_AsLongLong(startobj) : + PyInt_AsLong(startobj); +#endif + if (PyErr_Occurred()) + return NULL; + } + if (lenobj != NULL) { +#if !defined(HAVE_LARGEFILE_SUPPORT) + l.l_len = PyInt_AsLong(lenobj); +#else + l.l_len = PyLong_Check(lenobj) ? + PyLong_AsLongLong(lenobj) : + PyInt_AsLong(lenobj); +#endif + if (PyErr_Occurred()) + return NULL; + } + l.l_whence = whence; + Py_BEGIN_ALLOW_THREADS + ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l); + Py_END_ALLOW_THREADS + } + if (ret < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +#endif /* defined(PYOS_OS2) && defined(PYCC_GCC) */ +} + +PyDoc_STRVAR(lockf_doc, +"lockf (fd, operation, length=0, start=0, whence=0)\n\ +\n\ +This is essentially a wrapper around the fcntl() locking calls. fd is the\n\ +file descriptor of the file to lock or unlock, and operation is one of the\n\ +following values:\n\ +\n\ + LOCK_UN - unlock\n\ + LOCK_SH - acquire a shared lock\n\ + LOCK_EX - acquire an exclusive lock\n\ +\n\ +When operation is LOCK_SH or LOCK_EX, it can also be bit-wise OR'd with\n\ +LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the\n\ +lock cannot be acquired, an IOError will be raised and the exception will\n\ +have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\ +system -- for portability, check for either value).\n\ +\n\ +length is the number of bytes to lock, with the default meaning to lock to\n\ +EOF. start is the byte offset, relative to whence, to that the lock\n\ +starts. whence is as with fileobj.seek(), specifically:\n\ +\n\ + 0 - relative to the start of the file (SEEK_SET)\n\ + 1 - relative to the current buffer position (SEEK_CUR)\n\ + 2 - relative to the end of the file (SEEK_END)"); + +/* List of functions */ + +static PyMethodDef fcntl_methods[] = { + {"fcntl", fcntl_fcntl, METH_VARARGS, fcntl_doc}, + {"ioctl", fcntl_ioctl, METH_VARARGS, ioctl_doc}, + {"flock", fcntl_flock, METH_VARARGS, flock_doc}, + {"lockf", fcntl_lockf, METH_VARARGS, lockf_doc}, + {NULL, NULL} /* sentinel */ +}; + + +PyDoc_STRVAR(module_doc, +"This module performs file control and I/O control on file \n\ +descriptors. It is an interface to the fcntl() and ioctl() Unix\n\ +routines. File descriptors can be obtained with the fileno() method of\n\ +a file or socket object."); + +/* Module initialisation */ + +static int +ins(PyObject* d, char* symbol, long value) +{ + PyObject* v = PyInt_FromLong(value); + if (!v || PyDict_SetItemString(d, symbol, v) < 0) + return -1; + + Py_DECREF(v); + return 0; +} + +#define INS(x) if (ins(d, #x, (long)x)) return -1 + +static int +all_ins(PyObject* d) +{ + if (ins(d, "LOCK_SH", (long)LOCK_SH)) return -1; + if (ins(d, "LOCK_EX", (long)LOCK_EX)) return -1; + if (ins(d, "LOCK_NB", (long)LOCK_NB)) return -1; + if (ins(d, "LOCK_UN", (long)LOCK_UN)) return -1; +/* GNU extensions, as of glibc 2.2.4 */ +#ifdef LOCK_MAND + if (ins(d, "LOCK_MAND", (long)LOCK_MAND)) return -1; +#endif +#ifdef LOCK_READ + if (ins(d, "LOCK_READ", (long)LOCK_READ)) return -1; +#endif +#ifdef LOCK_WRITE + if (ins(d, "LOCK_WRITE", (long)LOCK_WRITE)) return -1; +#endif +#ifdef LOCK_RW + if (ins(d, "LOCK_RW", (long)LOCK_RW)) return -1; +#endif + +#ifdef F_DUPFD + if (ins(d, "F_DUPFD", (long)F_DUPFD)) return -1; +#endif +#ifdef F_GETFD + if (ins(d, "F_GETFD", (long)F_GETFD)) return -1; +#endif +#ifdef F_SETFD + if (ins(d, "F_SETFD", (long)F_SETFD)) return -1; +#endif +#ifdef F_GETFL + if (ins(d, "F_GETFL", (long)F_GETFL)) return -1; +#endif +#ifdef F_SETFL + if (ins(d, "F_SETFL", (long)F_SETFL)) return -1; +#endif +#ifdef F_GETLK + if (ins(d, "F_GETLK", (long)F_GETLK)) return -1; +#endif +#ifdef F_SETLK + if (ins(d, "F_SETLK", (long)F_SETLK)) return -1; +#endif +#ifdef F_SETLKW + if (ins(d, "F_SETLKW", (long)F_SETLKW)) return -1; +#endif +#ifdef F_GETOWN + if (ins(d, "F_GETOWN", (long)F_GETOWN)) return -1; +#endif +#ifdef F_SETOWN + if (ins(d, "F_SETOWN", (long)F_SETOWN)) return -1; +#endif +#ifdef F_GETSIG + if (ins(d, "F_GETSIG", (long)F_GETSIG)) return -1; +#endif +#ifdef F_SETSIG + if (ins(d, "F_SETSIG", (long)F_SETSIG)) return -1; +#endif +#ifdef F_RDLCK + if (ins(d, "F_RDLCK", (long)F_RDLCK)) return -1; +#endif +#ifdef F_WRLCK + if (ins(d, "F_WRLCK", (long)F_WRLCK)) return -1; +#endif +#ifdef F_UNLCK + if (ins(d, "F_UNLCK", (long)F_UNLCK)) return -1; +#endif +/* LFS constants */ +#ifdef F_GETLK64 + if (ins(d, "F_GETLK64", (long)F_GETLK64)) return -1; +#endif +#ifdef F_SETLK64 + if (ins(d, "F_SETLK64", (long)F_SETLK64)) return -1; +#endif +#ifdef F_SETLKW64 + if (ins(d, "F_SETLKW64", (long)F_SETLKW64)) return -1; +#endif +/* GNU extensions, as of glibc 2.2.4. */ +#ifdef F_SETLEASE + if (ins(d, "F_SETLEASE", (long)F_SETLEASE)) return -1; +#endif +#ifdef F_GETLEASE + if (ins(d, "F_GETLEASE", (long)F_GETLEASE)) return -1; +#endif +#ifdef F_NOTIFY + if (ins(d, "F_NOTIFY", (long)F_NOTIFY)) return -1; +#endif +/* Old BSD flock(). */ +#ifdef F_EXLCK + if (ins(d, "F_EXLCK", (long)F_EXLCK)) return -1; +#endif +#ifdef F_SHLCK + if (ins(d, "F_SHLCK", (long)F_SHLCK)) return -1; +#endif + +/* For F_{GET|SET}FL */ +#ifdef FD_CLOEXEC + if (ins(d, "FD_CLOEXEC", (long)FD_CLOEXEC)) return -1; +#endif + +/* For F_NOTIFY */ +#ifdef DN_ACCESS + if (ins(d, "DN_ACCESS", (long)DN_ACCESS)) return -1; +#endif +#ifdef DN_MODIFY + if (ins(d, "DN_MODIFY", (long)DN_MODIFY)) return -1; +#endif +#ifdef DN_CREATE + if (ins(d, "DN_CREATE", (long)DN_CREATE)) return -1; +#endif +#ifdef DN_DELETE + if (ins(d, "DN_DELETE", (long)DN_DELETE)) return -1; +#endif +#ifdef DN_RENAME + if (ins(d, "DN_RENAME", (long)DN_RENAME)) return -1; +#endif +#ifdef DN_ATTRIB + if (ins(d, "DN_ATTRIB", (long)DN_ATTRIB)) return -1; +#endif +#ifdef DN_MULTISHOT + if (ins(d, "DN_MULTISHOT", (long)DN_MULTISHOT)) return -1; +#endif + +#ifdef HAVE_STROPTS_H + /* Unix 98 guarantees that these are in stropts.h. */ + INS(I_PUSH); + INS(I_POP); + INS(I_LOOK); + INS(I_FLUSH); + INS(I_FLUSHBAND); + INS(I_SETSIG); + INS(I_GETSIG); + INS(I_FIND); + INS(I_PEEK); + INS(I_SRDOPT); + INS(I_GRDOPT); + INS(I_NREAD); + INS(I_FDINSERT); + INS(I_STR); + INS(I_SWROPT); +#ifdef I_GWROPT + /* despite the comment above, old-ish glibcs miss a couple... */ + INS(I_GWROPT); +#endif + INS(I_SENDFD); + INS(I_RECVFD); + INS(I_LIST); + INS(I_ATMARK); + INS(I_CKBAND); + INS(I_GETBAND); + INS(I_CANPUT); + INS(I_SETCLTIME); +#ifdef I_GETCLTIME + INS(I_GETCLTIME); +#endif + INS(I_LINK); + INS(I_UNLINK); + INS(I_PLINK); + INS(I_PUNLINK); +#endif + + return 0; +} + +PyMODINIT_FUNC +initfcntl(void) +{ + PyObject *m, *d; + + /* Create the module and add the functions and documentation */ + m = Py_InitModule3("fcntl", fcntl_methods, module_doc); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + all_ins(d); +} diff --git a/sys/src/cmd/python/Modules/flmodule.c b/sys/src/cmd/python/Modules/flmodule.c new file mode 100644 index 000000000..e507c9fb5 --- /dev/null +++ b/sys/src/cmd/python/Modules/flmodule.c @@ -0,0 +1,2139 @@ +/* FL module -- interface to Mark Overmars' FORMS Library. */ + +/* This code works with FORMS version 2.2 (if you defined + OBSOLETE_FORMS_CALLS), and 2.3. + FORMS can be ftp'ed from ftp.cs.ruu.nl (131.211.80.17), directory + /pub/SGI/FORMS. */ + +/* A half-hearted attempt has been made to allow programs using this + * module to exploit parallelism (through the threads module). No provisions + * have been made for multiple threads to use this module at the same time, + * though. So, a program with a forms thread and a non-forms thread will work + * fine but a program with two threads using forms will probably crash (unless + * the program takes precaution to ensure that only one thread can be in + * this module at any time). This will have to be fixed some time. + * (A fix will probably also have to synchronize with the gl module). + */ + +#include "Python.h" +#include "forms.h" +#include "structmember.h" + +/* Generic Forms Objects */ + +typedef struct { + PyObject_HEAD + FL_OBJECT *ob_generic; + PyMethodDef *ob_methods; + PyObject *ob_callback; + PyObject *ob_callback_arg; +} genericobject; + +static PyTypeObject GenericObjecttype; + +#define is_genericobject(g) ((g)->ob_type == &GenericObjecttype) + +/* List of all objects (XXX this should be a hash table on address...) */ + +static PyObject *allgenerics = NULL; +static int nfreeslots = 0; + +/* Add an object to the list of known objects */ + +static void +knowgeneric(genericobject *g) +{ + int i, n; + /* Create the list if it doesn't already exist */ + if (allgenerics == NULL) { + allgenerics = PyList_New(0); + if (allgenerics == NULL) { + PyErr_Clear(); + return; /* Too bad, live without allgenerics... */ + } + } + if (nfreeslots > 0) { + /* Search the list for reusable slots (NULL items) */ + /* XXX This can be made faster! */ + n = PyList_Size(allgenerics); + for (i = 0; i < n; i++) { + if (PyList_GetItem(allgenerics, i) == NULL) { + Py_INCREF(g); + PyList_SetItem(allgenerics, i, (PyObject *)g); + nfreeslots--; + return; + } + } + /* Strange... no free slots found... */ + nfreeslots = 0; + } + /* No free entries, append new item to the end */ + PyList_Append(allgenerics, (PyObject *)g); +} + +/* Find an object in the list of known objects */ + +static genericobject * +findgeneric(FL_OBJECT *generic) +{ + int i, n; + genericobject *g; + + if (allgenerics == NULL) + return NULL; /* No objects known yet */ + n = PyList_Size(allgenerics); + for (i = 0; i < n; i++) { + g = (genericobject *)PyList_GetItem(allgenerics, i); + if (g != NULL && g->ob_generic == generic) + return g; + } + return NULL; /* Unknown object */ +} + +/* Remove an object from the list of known objects */ + +static void +forgetgeneric(genericobject *g) +{ + int i, n; + + Py_XDECREF(g->ob_callback); + g->ob_callback = NULL; + Py_XDECREF(g->ob_callback_arg); + g->ob_callback_arg = NULL; + if (allgenerics == NULL) + return; /* No objects known yet */ + n = PyList_Size(allgenerics); + for (i = 0; i < n; i++) { + if (g == (genericobject *)PyList_GetItem(allgenerics, i)) { + PyList_SetItem(allgenerics, i, (PyObject *)NULL); + nfreeslots++; + break; + } + } +} + +/* Called when a form is about to be freed -- + remove all the objects that we know about from it. */ + +static void +releaseobjects(FL_FORM *form) +{ + int i, n; + genericobject *g; + + if (allgenerics == NULL) + return; /* No objects known yet */ + n = PyList_Size(allgenerics); + for (i = 0; i < n; i++) { + g = (genericobject *)PyList_GetItem(allgenerics, i); + if (g != NULL && g->ob_generic->form == form) { + fl_delete_object(g->ob_generic); + /* The object is now unreachable for + do_forms and check_forms, so + delete it from the list of known objects */ + Py_XDECREF(g->ob_callback); + g->ob_callback = NULL; + Py_XDECREF(g->ob_callback_arg); + g->ob_callback_arg = NULL; + PyList_SetItem(allgenerics, i, (PyObject *)NULL); + nfreeslots++; + } + } +} + + +/* Methods of generic objects */ + +static PyObject * +generic_set_call_back(genericobject *g, PyObject *args) +{ + if (PyTuple_GET_SIZE(args) == 0) { + Py_XDECREF(g->ob_callback); + Py_XDECREF(g->ob_callback_arg); + g->ob_callback = NULL; + g->ob_callback_arg = NULL; + } + else { + PyObject *a, *b; + if (!PyArg_UnpackTuple(args, "set_call_back", 2, 2, &a, &b) + return NULL; + Py_XDECREF(g->ob_callback); + Py_XDECREF(g->ob_callback_arg); + g->ob_callback = a; + Py_INCREF(g->ob_callback); + g->ob_callback_arg = b; + Py_INCREF(g->ob_callback_arg); + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +generic_call(genericobject *g, void (*func)(FL_OBJECT *)) +{ + (*func)(g->ob_generic); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +generic_delete_object(genericobject *g) +{ + PyObject *res; + res = generic_call(g, fl_delete_object); + if (res != NULL) + forgetgeneric(g); + return res; +} + +static PyObject * +generic_show_object(genericobject *g) +{ + return generic_call(g, fl_show_object); +} + +static PyObject * +generic_hide_object(genericobject *g) +{ + return generic_call(g, fl_hide_object); +} + +static PyObject * +generic_redraw_object(genericobject *g) +{ + return generic_call(g, fl_redraw_object); +} + +#ifdef OBSOLETE_FORMS_CALLS + + /* (un)freeze_object() are obsolete in FORMS 2.2 and unsupported + in 2.3. Since there's no foolproof way to tell which version we're + using, we omit them unconditionally. */ + +static PyObject * +generic_freeze_object(genericobject *g) +{ + return generic_call(g, fl_freeze_object); +} + +static PyObject * +generic_unfreeze_object(genericobject *g) +{ + return generic_call(g, fl_unfreeze_object); +} + +#endif /* OBSOLETE_FORMS_CALLS */ + +static PyObject * +generic_activate_object(genericobject *g) +{ + return generic_call(g, fl_activate_object); +} + +static PyObject * +generic_deactivate_object(genericobject *g) +{ + return generic_call(g, fl_deactivate_object); +} + +static PyObject * +generic_set_object_shortcut(genericobject *g, PyObject *args) +{ + char *str; + if (!PyArg_ParseTuple(args, "s:set_object_shortcut", &str)) + return NULL; + fl_set_object_shortcut(g->ob_generic, str); + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef generic_methods[] = { + {"set_call_back", (PyCFunction)generic_set_call_back, METH_VARARGS}, + {"delete_object", (PyCFunction)generic_delete_object, METH_NOARGS}, + {"show_object", (PyCFunction)generic_show_object, METH_NOARGS}, + {"hide_object", (PyCFunction)generic_hide_object, METH_NOARGS}, + {"redraw_object", (PyCFunction)generic_redraw_object, METH_NOARGS}, +#ifdef OBSOLETE_FORMS_CALLS + {"freeze_object", (PyCFunction)generic_freeze_object, METH_NOARGS}, + {"unfreeze_object", (PyCFunction)generic_unfreeze_object, METH_NOARGS}, +#endif + {"activate_object", (PyCFunction)generic_activate_object, METH_NOARGS}, + {"deactivate_object", (PyCFunction)generic_deactivate_object, METH_NOARGS}, + {"set_object_shortcut", (PyCFunction)generic_set_object_shortcut, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static void +generic_dealloc(genericobject *g) +{ + fl_free_object(g->ob_generic); + Py_XDECREF(g->ob_callback); + Py_XDECREF(g->ob_callback_arg); + PyObject_Del(g); +} + +#define OFF(x) offsetof(FL_OBJECT, x) + +static struct memberlist generic_memberlist[] = { + {"objclass", T_INT, OFF(objclass), RO}, + {"type", T_INT, OFF(type), RO}, + {"boxtype", T_INT, OFF(boxtype)}, + {"x", T_FLOAT, OFF(x)}, + {"y", T_FLOAT, OFF(y)}, + {"w", T_FLOAT, OFF(w)}, + {"h", T_FLOAT, OFF(h)}, + {"col1", T_INT, OFF(col1)}, + {"col2", T_INT, OFF(col2)}, + {"align", T_INT, OFF(align)}, + {"lcol", T_INT, OFF(lcol)}, + {"lsize", T_FLOAT, OFF(lsize)}, + /* "label" is treated specially! */ + {"lstyle", T_INT, OFF(lstyle)}, + {"pushed", T_INT, OFF(pushed), RO}, + {"focus", T_INT, OFF(focus), RO}, + {"belowmouse", T_INT, OFF(belowmouse),RO}, +/* {"frozen", T_INT, OFF(frozen), RO}, */ + {"active", T_INT, OFF(active)}, + {"input", T_INT, OFF(input)}, + {"visible", T_INT, OFF(visible), RO}, + {"radio", T_INT, OFF(radio)}, + {"automatic", T_INT, OFF(automatic)}, + {NULL} /* Sentinel */ +}; + +#undef OFF + +static PyObject * +generic_getattr(genericobject *g, char *name) +{ + PyObject *meth; + + /* XXX Ought to special-case name "__methods__" */ + if (g-> ob_methods) { + meth = Py_FindMethod(g->ob_methods, (PyObject *)g, name); + if (meth != NULL) return meth; + PyErr_Clear(); + } + + meth = Py_FindMethod(generic_methods, (PyObject *)g, name); + if (meth != NULL) + return meth; + PyErr_Clear(); + + /* "label" is an exception, getmember only works for char pointers, + not for char arrays */ + if (strcmp(name, "label") == 0) + return PyString_FromString(g->ob_generic->label); + + return PyMember_Get((char *)g->ob_generic, generic_memberlist, name); +} + +static int +generic_setattr(genericobject *g, char *name, PyObject *v) +{ + int ret; + + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "can't delete forms object attributes"); + return -1; + } + + /* "label" is an exception: setmember doesn't set strings; + and FORMS wants you to call a function to set the label */ + if (strcmp(name, "label") == 0) { + if (!PyString_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "label attr must be string"); + return -1; + } + fl_set_object_label(g->ob_generic, PyString_AsString(v)); + return 0; + } + + ret = PyMember_Set((char *)g->ob_generic, generic_memberlist, name, v); + + /* Rather than calling all the various set_object_* functions, + we call fl_redraw_object here. This is sometimes redundant + but I doubt that's a big problem */ + if (ret == 0) + fl_redraw_object(g->ob_generic); + + return ret; +} + +static PyObject * +generic_repr(genericobject *g) +{ + char buf[100]; + PyOS_snprintf(buf, sizeof(buf), "<FORMS_object at %p, objclass=%d>", + g, g->ob_generic->objclass); + return PyString_FromString(buf); +} + +static PyTypeObject GenericObjecttype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "fl.FORMS_object", /*tp_name*/ + sizeof(genericobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)generic_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)generic_getattr, /*tp_getattr*/ + (setattrfunc)generic_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc)generic_repr, /*tp_repr*/ +}; + +static PyObject * +newgenericobject(FL_OBJECT *generic, PyMethodDef *methods) +{ + genericobject *g; + g = PyObject_New(genericobject, &GenericObjecttype); + if (g == NULL) + return NULL; + g-> ob_generic = generic; + g->ob_methods = methods; + g->ob_callback = NULL; + g->ob_callback_arg = NULL; + knowgeneric(g); + return (PyObject *)g; +} + +/**********************************************************************/ +/* Some common calling sequences */ + +/* void func (object, float) */ +static PyObject * +call_forms_INf (void (*func)(FL_OBJECT *, float), FL_OBJECT *obj, PyObject *args) +{ + float parameter; + + if (!PyArg_Parse(args, "f", &parameter)) return NULL; + + (*func) (obj, parameter); + + Py_INCREF(Py_None); + return Py_None; +} + +/* void func (object, float) */ +static PyObject * +call_forms_INfINf (void (*func)(FL_OBJECT *, float, float), FL_OBJECT *obj, PyObject *args) +{ + float par1, par2; + + if (!PyArg_Parse(args, "(ff)", &par1, &par2)) return NULL; + + (*func) (obj, par1, par2); + + Py_INCREF(Py_None); + return Py_None; +} + +/* void func (object, int) */ +static PyObject * +call_forms_INi (void (*func)(FL_OBJECT *, int), FL_OBJECT *obj, PyObject *args) +{ + int parameter; + + if (!PyArg_Parse(args, "i", &parameter)) return NULL; + + (*func) (obj, parameter); + + Py_INCREF(Py_None); + return Py_None; +} + +/* void func (object, char) */ +static PyObject * +call_forms_INc (void (*func)(FL_OBJECT *, int), FL_OBJECT *obj, PyObject *args) +{ + char *a; + + if (!PyArg_Parse(args, "s", &a)) return NULL; + + (*func) (obj, a[0]); + + Py_INCREF(Py_None); + return Py_None; +} + +/* void func (object, string) */ +static PyObject * +call_forms_INstr (void (*func)(FL_OBJECT *, char *), FL_OBJECT *obj, PyObject *args) +{ + char *a; + + if (!PyArg_Parse(args, "s", &a)) return NULL; + + (*func) (obj, a); + + Py_INCREF(Py_None); + return Py_None; +} + + +/* void func (object, int, string) */ +static PyObject * +call_forms_INiINstr (void (*func)(FL_OBJECT *, int, char *), FL_OBJECT *obj, PyObject *args) +{ + char *b; + int a; + + if (!PyArg_Parse(args, "(is)", &a, &b)) return NULL; + + (*func) (obj, a, b); + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef UNUSED +/* void func (object, int, int) */ +static PyObject * +call_forms_INiINi (void (*func)(FL_OBJECT *, int, int), FL_OBJECT *obj, PyObject *args) +{ + int par1, par2; + + if (!PyArg_Parse(args, "(ii)", &par1, &par2)) return NULL; + + (*func) (obj, par1, par2); + + Py_INCREF(Py_None); + return Py_None; +} +#endif + +/* int func (object) */ +static PyObject * +call_forms_Ri (int (*func)(FL_OBJECT *), FL_OBJECT *obj) +{ + int retval; + + retval = (*func) (obj); + + return PyInt_FromLong ((long) retval); +} + +/* char * func (object) */ +static PyObject * +call_forms_Rstr (char * (*func)(FL_OBJECT *), FL_OBJECT *obj) +{ + char *str; + + str = (*func) (obj); + + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString (str); +} + +/* int func (object) */ +static PyObject * +call_forms_Rf (float (*func)(FL_OBJECT *), FL_OBJECT *obj) +{ + float retval; + + retval = (*func) (obj); + + return PyFloat_FromDouble (retval); +} + +static PyObject * +call_forms_OUTfOUTf (void (*func)(FL_OBJECT *, float *, float *), FL_OBJECT *obj) +{ + float f1, f2; + + (*func) (obj, &f1, &f2); + + return Py_BuildValue("(ff)", f1, f2); +} + +#ifdef UNUSED +static PyObject * +call_forms_OUTf (void (*func)(FL_OBJECT *, float *), FL_OBJECT *obj) +{ + float f; + + (*func) (obj, &f); + + return PyFloat_FromDouble (f); +} +#endif + +/**********************************************************************/ +/* Class : browser */ + +static PyObject * +set_browser_topline(genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_browser_topline, g-> ob_generic, args); +} + +static PyObject * +clear_browser(genericobject *g) +{ + return generic_call (g, fl_clear_browser); +} + +static PyObject * +add_browser_line (genericobject *g, PyObject *args) +{ + return call_forms_INstr (fl_add_browser_line, g-> ob_generic, args); +} + +static PyObject * +addto_browser (genericobject *g, PyObject *args) +{ + return call_forms_INstr (fl_addto_browser, g-> ob_generic, args); +} + +static PyObject * +insert_browser_line (genericobject *g, PyObject *args) +{ + return call_forms_INiINstr (fl_insert_browser_line, + g-> ob_generic, args); +} + +static PyObject * +delete_browser_line (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_delete_browser_line, g-> ob_generic, args); +} + +static PyObject * +replace_browser_line (genericobject *g, PyObject *args) +{ + return call_forms_INiINstr (fl_replace_browser_line, + g-> ob_generic, args); +} + +static PyObject * +get_browser_line(genericobject *g, PyObject *args) +{ + int i; + char *str; + + if (!PyArg_Parse(args, "i", &i)) + return NULL; + + str = fl_get_browser_line (g->ob_generic, i); + + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString (str); +} + +static PyObject * +load_browser (genericobject *g, PyObject *args) +{ + /* XXX strictly speaking this is wrong since fl_load_browser + XXX returns int, not void */ + return call_forms_INstr (fl_load_browser, g-> ob_generic, args); +} + +static PyObject * +get_browser_maxline(genericobject *g) +{ + return call_forms_Ri (fl_get_browser_maxline, g-> ob_generic); +} + +static PyObject * +select_browser_line (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_select_browser_line, g-> ob_generic, args); +} + +static PyObject * +deselect_browser_line (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_deselect_browser_line, g-> ob_generic, args); +} + +static PyObject * +deselect_browser (genericobject *g) +{ + return generic_call (g, fl_deselect_browser); +} + +static PyObject * +isselected_browser_line (genericobject *g, PyObject *args) +{ + int i, j; + + if (!PyArg_Parse(args, "i", &i)) + return NULL; + + j = fl_isselected_browser_line (g->ob_generic, i); + + return PyInt_FromLong (j); +} + +static PyObject * +get_browser (genericobject *g) +{ + return call_forms_Ri (fl_get_browser, g-> ob_generic); +} + +static PyObject * +set_browser_fontsize (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_browser_fontsize, g-> ob_generic, args); +} + +static PyObject * +set_browser_fontstyle (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_browser_fontstyle, g-> ob_generic, args); +} + +static PyObject * +set_browser_specialkey (genericobject *g, PyObject *args) +{ + return call_forms_INc(fl_set_browser_specialkey, g-> ob_generic, args); +} + +static PyMethodDef browser_methods[] = { + {"set_browser_topline", (PyCFunction)set_browser_topline, + METH_OLDARGS}, + {"clear_browser", (PyCFunction)clear_browser, + METH_NOARGS}, + {"add_browser_line", (PyCFunction)add_browser_line, + METH_OLDARGS}, + {"addto_browser", (PyCFunction)addto_browser, + METH_OLDARGS}, + {"insert_browser_line", (PyCFunction)insert_browser_line, + METH_OLDARGS}, + {"delete_browser_line", (PyCFunction)delete_browser_line, + METH_OLDARGS}, + {"replace_browser_line", (PyCFunction)replace_browser_line, + METH_OLDARGS}, + {"get_browser_line", (PyCFunction)get_browser_line, + METH_OLDARGS}, + {"load_browser", (PyCFunction)load_browser, + METH_OLDARGS}, + {"get_browser_maxline", (PyCFunction)get_browser_maxline, + METH_NOARGS,} + {"select_browser_line", (PyCFunction)select_browser_line, + METH_OLDARGS}, + {"deselect_browser_line", (PyCFunction)deselect_browser_line, + METH_OLDARGS}, + {"deselect_browser", (PyCFunction)deselect_browser, + METH_NOARGS,} + {"isselected_browser_line", (PyCFunction)isselected_browser_line, + METH_OLDARGS}, + {"get_browser", (PyCFunction)get_browser, + METH_NOARGS,} + {"set_browser_fontsize", (PyCFunction)set_browser_fontsize, + METH_OLDARGS}, + {"set_browser_fontstyle", (PyCFunction)set_browser_fontstyle, + METH_OLDARGS}, + {"set_browser_specialkey", (PyCFunction)set_browser_specialkey, + METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Class: button */ + +static PyObject * +set_button(genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_button, g-> ob_generic, args); +} + +static PyObject * +get_button(genericobject *g) +{ + return call_forms_Ri (fl_get_button, g-> ob_generic); +} + +static PyObject * +get_button_numb(genericobject *g) +{ + return call_forms_Ri (fl_get_button_numb, g-> ob_generic); +} + +static PyObject * +set_button_shortcut(genericobject *g, PyObject *args) +{ + return call_forms_INstr (fl_set_button_shortcut, g-> ob_generic, args); +} + +static PyMethodDef button_methods[] = { + {"set_button", (PyCFunction)set_button, METH_OLDARGS}, + {"get_button", (PyCFunction)get_button, METH_NOARGS}, + {"get_button_numb", (PyCFunction)get_button_numb, METH_NOARGS}, + {"set_button_shortcut", (PyCFunction)set_button_shortcut, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Class: choice */ + +static PyObject * +set_choice(genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_choice, g-> ob_generic, args); +} + +static PyObject * +get_choice(genericobject *g) +{ + return call_forms_Ri (fl_get_choice, g-> ob_generic); +} + +static PyObject * +clear_choice (genericobject *g) +{ + return generic_call (g, fl_clear_choice); +} + +static PyObject * +addto_choice (genericobject *g, PyObject *args) +{ + return call_forms_INstr (fl_addto_choice, g-> ob_generic, args); +} + +static PyObject * +replace_choice (genericobject *g, PyObject *args) +{ + return call_forms_INiINstr (fl_replace_choice, g-> ob_generic, args); +} + +static PyObject * +delete_choice (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_delete_choice, g-> ob_generic, args); +} + +static PyObject * +get_choice_text (genericobject *g) +{ + return call_forms_Rstr (fl_get_choice_text, g-> ob_generic); +} + +static PyObject * +set_choice_fontsize (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_choice_fontsize, g-> ob_generic, args); +} + +static PyObject * +set_choice_fontstyle (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_choice_fontstyle, g-> ob_generic, args); +} + +static PyMethodDef choice_methods[] = { + {"set_choice", (PyCFunction)set_choice, METH_OLDARGS}, + {"get_choice", (PyCFunction)get_choice, METH_NOARGS}, + {"clear_choice", (PyCFunction)clear_choice, METH_NOARGS}, + {"addto_choice", (PyCFunction)addto_choice, METH_OLDARGS}, + {"replace_choice", (PyCFunction)replace_choice, METH_OLDARGS}, + {"delete_choice", (PyCFunction)delete_choice, METH_OLDARGS}, + {"get_choice_text", (PyCFunction)get_choice_text, METH_NOARGS}, + {"set_choice_fontsize", (PyCFunction)set_choice_fontsize, METH_OLDARGS}, + {"set_choice_fontstyle",(PyCFunction)set_choice_fontstyle, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Class : Clock */ + +static PyObject * +get_clock(genericobject *g) +{ + int i0, i1, i2; + + fl_get_clock (g->ob_generic, &i0, &i1, &i2); + + return Py_BuildValue("(iii)", i0, i1, i2); +} + +static PyMethodDef clock_methods[] = { + {"get_clock", (PyCFunction)get_clock, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* CLass : Counters */ + +static PyObject * +get_counter_value(genericobject *g) +{ + return call_forms_Rf (fl_get_counter_value, g-> ob_generic); +} + +static PyObject * +set_counter_value (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_counter_value, g-> ob_generic, args); +} + +static PyObject * +set_counter_precision (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_counter_precision, g-> ob_generic, args); +} + +static PyObject * +set_counter_bounds (genericobject *g, PyObject *args) +{ + return call_forms_INfINf (fl_set_counter_bounds, g-> ob_generic, args); +} + +static PyObject * +set_counter_step (genericobject *g, PyObject *args) +{ + return call_forms_INfINf (fl_set_counter_step, g-> ob_generic, args); +} + +static PyObject * +set_counter_return (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_counter_return, g-> ob_generic, args); +} + +static PyMethodDef counter_methods[] = { + {"set_counter_value", (PyCFunction)set_counter_value, + METH_OLDARGS}, + {"get_counter_value", (PyCFunction)get_counter_value, + METH_NOARGS}, + {"set_counter_bounds", (PyCFunction)set_counter_bounds, + METH_OLDARGS}, + {"set_counter_step", (PyCFunction)set_counter_step, + METH_OLDARGS}, + {"set_counter_precision", (PyCFunction)set_counter_precision, + METH_OLDARGS}, + {"set_counter_return", (PyCFunction)set_counter_return, + METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + + +/* Class: Dials */ + +static PyObject * +get_dial_value(genericobject *g) +{ + return call_forms_Rf (fl_get_dial_value, g-> ob_generic); +} + +static PyObject * +set_dial_value (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_dial_value, g-> ob_generic, args); +} + +static PyObject * +set_dial_bounds (genericobject *g, PyObject *args) +{ + return call_forms_INfINf (fl_set_dial_bounds, g-> ob_generic, args); +} + +static PyObject * +get_dial_bounds (genericobject *g) +{ + return call_forms_OUTfOUTf (fl_get_dial_bounds, g-> ob_generic); +} + +static PyObject * +set_dial_step (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_dial_step, g-> ob_generic, args); +} + +static PyMethodDef dial_methods[] = { + {"set_dial_value", (PyCFunction)set_dial_value, METH_OLDARGS}, + {"get_dial_value", (PyCFunction)get_dial_value, METH_NOARGS}, + {"set_dial_bounds", (PyCFunction)set_dial_bounds, METH_OLDARGS}, + {"get_dial_bounds", (PyCFunction)get_dial_bounds, METH_NOARGS}, + {"set_dial_step", (PyCFunction)set_dial_step, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Class : Input */ + +static PyObject * +set_input (genericobject *g, PyObject *args) +{ + return call_forms_INstr (fl_set_input, g-> ob_generic, args); +} + +static PyObject * +get_input (genericobject *g) +{ + return call_forms_Rstr (fl_get_input, g-> ob_generic); +} + +static PyObject * +set_input_color (genericobject *g, PyObject *args) +{ + return call_forms_INfINf (fl_set_input_color, g-> ob_generic, args); +} + +static PyObject * +set_input_return (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_input_return, g-> ob_generic, args); +} + +static PyMethodDef input_methods[] = { + {"set_input", (PyCFunction)set_input, METH_OLDARGS}, + {"get_input", (PyCFunction)get_input, METH_NOARGS}, + {"set_input_color", (PyCFunction)set_input_color, METH_OLDARGS}, + {"set_input_return", (PyCFunction)set_input_return, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + + +/* Class : Menu */ + +static PyObject * +set_menu (genericobject *g, PyObject *args) +{ + return call_forms_INstr (fl_set_menu, g-> ob_generic, args); +} + +static PyObject * +get_menu (genericobject *g) +{ + /* XXX strictly speaking this is wrong since fl_get_menu + XXX returns long, not int */ + return call_forms_Ri (fl_get_menu, g-> ob_generic); +} + +static PyObject * +get_menu_text (genericobject *g) +{ + return call_forms_Rstr (fl_get_menu_text, g-> ob_generic); +} + +static PyObject * +addto_menu (genericobject *g, PyObject *args) +{ + return call_forms_INstr (fl_addto_menu, g-> ob_generic, args); +} + +static PyMethodDef menu_methods[] = { + {"set_menu", (PyCFunction)set_menu, METH_OLDARGS}, + {"get_menu", (PyCFunction)get_menu, METH_NOARGS}, + {"get_menu_text", (PyCFunction)get_menu_text, METH_NOARGS}, + {"addto_menu", (PyCFunction)addto_menu, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + + +/* Class: Sliders */ + +static PyObject * +get_slider_value(genericobject *g) +{ + return call_forms_Rf (fl_get_slider_value, g-> ob_generic); +} + +static PyObject * +set_slider_value (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_slider_value, g-> ob_generic, args); +} + +static PyObject * +set_slider_bounds (genericobject *g, PyObject *args) +{ + return call_forms_INfINf (fl_set_slider_bounds, g-> ob_generic, args); +} + +static PyObject * +get_slider_bounds (genericobject *g) +{ + return call_forms_OUTfOUTf(fl_get_slider_bounds, g-> ob_generic); +} + +static PyObject * +set_slider_return (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_slider_return, g-> ob_generic, args); +} + +static PyObject * +set_slider_size (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_slider_size, g-> ob_generic, args); +} + +static PyObject * +set_slider_precision (genericobject *g, PyObject *args) +{ + return call_forms_INi (fl_set_slider_precision, g-> ob_generic, args); +} + +static PyObject * +set_slider_step (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_slider_step, g-> ob_generic, args); +} + + +static PyMethodDef slider_methods[] = { + {"set_slider_value", (PyCFunction)set_slider_value, METH_OLDARGS}, + {"get_slider_value", (PyCFunction)get_slider_value, METH_NOARGS}, + {"set_slider_bounds", (PyCFunction)set_slider_bounds, METH_OLDARGS}, + {"get_slider_bounds", (PyCFunction)get_slider_bounds, METH_NOARGS}, + {"set_slider_return", (PyCFunction)set_slider_return, METH_OLDARGS}, + {"set_slider_size", (PyCFunction)set_slider_size, METH_OLDARGS}, + {"set_slider_precision",(PyCFunction)set_slider_precision, METH_OLDARGS}, + {"set_slider_step", (PyCFunction)set_slider_step, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +set_positioner_xvalue (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_positioner_xvalue, g-> ob_generic, args); +} + +static PyObject * +set_positioner_xbounds (genericobject *g, PyObject *args) +{ + return call_forms_INfINf (fl_set_positioner_xbounds, + g-> ob_generic, args); +} + +static PyObject * +set_positioner_yvalue (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_positioner_yvalue, g-> ob_generic, args); +} + +static PyObject * +set_positioner_ybounds (genericobject *g, PyObject *args) +{ + return call_forms_INfINf (fl_set_positioner_ybounds, + g-> ob_generic, args); +} + +static PyObject * +get_positioner_xvalue (genericobject *g) +{ + return call_forms_Rf (fl_get_positioner_xvalue, g-> ob_generic); +} + +static PyObject * +get_positioner_xbounds (genericobject *g) +{ + return call_forms_OUTfOUTf (fl_get_positioner_xbounds, g-> ob_generic); +} + +static PyObject * +get_positioner_yvalue (genericobject *g) +{ + return call_forms_Rf (fl_get_positioner_yvalue, g-> ob_generic); +} + +static PyObject * +get_positioner_ybounds (genericobject *g) +{ + return call_forms_OUTfOUTf (fl_get_positioner_ybounds, g-> ob_generic); +} + +static PyMethodDef positioner_methods[] = { + {"set_positioner_xvalue", (PyCFunction)set_positioner_xvalue, + METH_OLDARGS}, + {"set_positioner_yvalue", (PyCFunction)set_positioner_yvalue, + METH_OLDARGS}, + {"set_positioner_xbounds", (PyCFunction)set_positioner_xbounds, + METH_OLDARGS}, + {"set_positioner_ybounds", (PyCFunction)set_positioner_ybounds, + METH_OLDARGS}, + {"get_positioner_xvalue", (PyCFunction)get_positioner_xvalue, + METH_NOARGS}, + {"get_positioner_yvalue", (PyCFunction)get_positioner_yvalue, + METH_NOARGS}, + {"get_positioner_xbounds", (PyCFunction)get_positioner_xbounds, + METH_NOARGS}, + {"get_positioner_ybounds", (PyCFunction)get_positioner_ybounds, + METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Class timer */ + +static PyObject * +set_timer (genericobject *g, PyObject *args) +{ + return call_forms_INf (fl_set_timer, g-> ob_generic, args); +} + +static PyObject * +get_timer (genericobject *g) +{ + return call_forms_Rf (fl_get_timer, g-> ob_generic); +} + +static PyMethodDef timer_methods[] = { + {"set_timer", (PyCFunction)set_timer, METH_OLDARGS}, + {"get_timer", (PyCFunction)get_timer, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Form objects */ + +typedef struct { + PyObject_HEAD + FL_FORM *ob_form; +} formobject; + +static PyTypeObject Formtype; + +#define is_formobject(v) ((v)->ob_type == &Formtype) + +static PyObject * +form_show_form(formobject *f, PyObject *args) +{ + int place, border; + char *name; + if (!PyArg_Parse(args, "(iis)", &place, &border, &name)) + return NULL; + fl_show_form(f->ob_form, place, border, name); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +form_call(void (*func)(FL_FORM *), FL_FORM *f) +{ + (*func)(f); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +form_call_INiINi(void (*func)(FL_FORM *, int, int), FL_FORM *f, PyObject *args) +{ + int a, b; + + if (!PyArg_Parse(args, "(ii)", &a, &b)) return NULL; + + (*func)(f, a, b); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +form_call_INfINf(void (*func)(FL_FORM *, float, float), FL_FORM *f, PyObject *args) +{ + float a, b; + + if (!PyArg_Parse(args, "(ff)", &a, &b)) return NULL; + + (*func)(f, a, b); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +form_hide_form(formobject *f) +{ + return form_call(fl_hide_form, f-> ob_form); +} + +static PyObject * +form_redraw_form(formobject *f) +{ + return form_call(fl_redraw_form, f-> ob_form); +} + +static PyObject * +form_set_form_position(formobject *f, PyObject *args) +{ + return form_call_INiINi(fl_set_form_position, f-> ob_form, args); +} + +static PyObject * +form_set_form_size(formobject *f, PyObject *args) +{ + return form_call_INiINi(fl_set_form_size, f-> ob_form, args); +} + +static PyObject * +form_scale_form(formobject *f, PyObject *args) +{ + return form_call_INfINf(fl_scale_form, f-> ob_form, args); +} + +static PyObject * +generic_add_object(formobject *f, PyObject *args, FL_OBJECT *(*func)(int, float, float, float, float, char*), PyMethodDef *internal_methods) +{ + int type; + float x, y, w, h; + char *name; + FL_OBJECT *obj; + + if (!PyArg_Parse(args,"(iffffs)", &type,&x,&y,&w,&h,&name)) + return NULL; + + fl_addto_form (f-> ob_form); + + obj = (*func) (type, x, y, w, h, name); + + fl_end_form(); + + if (obj == NULL) { + PyErr_NoMemory(); + return NULL; + } + + return newgenericobject (obj, internal_methods); +} + +static PyObject * +form_add_button(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_button, button_methods); +} + +static PyObject * +form_add_lightbutton(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_lightbutton, button_methods); +} + +static PyObject * +form_add_roundbutton(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_roundbutton, button_methods); +} + +static PyObject * +form_add_menu (formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_menu, menu_methods); +} + +static PyObject * +form_add_slider(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_slider, slider_methods); +} + +static PyObject * +form_add_valslider(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_valslider, slider_methods); +} + +static PyObject * +form_add_dial(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_dial, dial_methods); +} + +static PyObject * +form_add_counter(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_counter, counter_methods); +} + +static PyObject * +form_add_clock(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_clock, clock_methods); +} + +static PyObject * +form_add_box(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_box, + (PyMethodDef *)NULL); +} + +static PyObject * +form_add_choice(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_choice, choice_methods); +} + +static PyObject * +form_add_browser(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_browser, browser_methods); +} + +static PyObject * +form_add_positioner(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_positioner, + positioner_methods); +} + +static PyObject * +form_add_input(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_input, input_methods); +} + +static PyObject * +form_add_text(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_text, + (PyMethodDef *)NULL); +} + +static PyObject * +form_add_timer(formobject *f, PyObject *args) +{ + return generic_add_object(f, args, fl_add_timer, timer_methods); +} + +static PyObject * +form_freeze_form(formobject *f) +{ + return form_call(fl_freeze_form, f-> ob_form); +} + +static PyObject * +form_unfreeze_form(formobject *f) +{ + return form_call(fl_unfreeze_form, f-> ob_form); +} + +static PyObject * +form_activate_form(formobject *f) +{ + return form_call(fl_activate_form, f-> ob_form); +} + +static PyObject * +form_deactivate_form(formobject *f) +{ + return form_call(fl_deactivate_form, f-> ob_form); +} + +static PyObject * +form_bgn_group(formobject *f, PyObject *args) +{ + FL_OBJECT *obj; + + fl_addto_form(f-> ob_form); + obj = fl_bgn_group(); + fl_end_form(); + + if (obj == NULL) { + PyErr_NoMemory(); + return NULL; + } + + return newgenericobject (obj, (PyMethodDef *) NULL); +} + +static PyObject * +form_end_group(formobject *f, PyObject *args) +{ + fl_addto_form(f-> ob_form); + fl_end_group(); + fl_end_form(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_find_first_or_last(FL_OBJECT *(*func)(FL_FORM *, int, float, float), formobject *f, PyObject *args) +{ + int type; + float mx, my; + FL_OBJECT *generic; + genericobject *g; + + if (!PyArg_Parse(args, "(iff)", &type, &mx, &my)) return NULL; + + generic = (*func) (f-> ob_form, type, mx, my); + + if (generic == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + + g = findgeneric(generic); + if (g == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "forms_find_{first|last} returns unknown object"); + return NULL; + } + Py_INCREF(g); + return (PyObject *) g; +} + +static PyObject * +form_find_first(formobject *f, PyObject *args) +{ + return forms_find_first_or_last(fl_find_first, f, args); +} + +static PyObject * +form_find_last(formobject *f, PyObject *args) +{ + return forms_find_first_or_last(fl_find_last, f, args); +} + +static PyObject * +form_set_object_focus(formobject *f, PyObject *args) +{ + genericobject *g; + if (args == NULL || !is_genericobject(args)) { + PyErr_BadArgument(); + return NULL; + } + g = (genericobject *)args; + fl_set_object_focus(f->ob_form, g->ob_generic); + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef form_methods[] = { +/* adm */ + {"show_form", (PyCFunction)form_show_form, METH_OLDARGS}, + {"hide_form", (PyCFunction)form_hide_form, METH_NOARGS}, + {"redraw_form", (PyCFunction)form_redraw_form, METH_NOARGS}, + {"set_form_position", (PyCFunction)form_set_form_position, METH_OLDARGS}, + {"set_form_size", (PyCFunction)form_set_form_size, METH_OLDARGS}, + {"scale_form", (PyCFunction)form_scale_form, METH_OLDARGS}, + {"freeze_form", (PyCFunction)form_freeze_form, METH_NOARGS}, + {"unfreeze_form", (PyCFunction)form_unfreeze_form, METH_NOARGS}, + {"activate_form", (PyCFunction)form_activate_form, METH_NOARGS}, + {"deactivate_form", (PyCFunction)form_deactivate_form, METH_NOARGS}, + {"bgn_group", (PyCFunction)form_bgn_group, METH_OLDARGS}, + {"end_group", (PyCFunction)form_end_group, METH_OLDARGS}, + {"find_first", (PyCFunction)form_find_first, METH_OLDARGS}, + {"find_last", (PyCFunction)form_find_last, METH_OLDARGS}, + {"set_object_focus", (PyCFunction)form_set_object_focus, METH_OLDARGS}, + +/* basic objects */ + {"add_button", (PyCFunction)form_add_button, METH_OLDARGS}, +/* {"add_bitmap", (method)form_add_bitmap, METH_OLDARGS}, */ + {"add_lightbutton", (PyCFunction)form_add_lightbutton, METH_OLDARGS}, + {"add_roundbutton", (PyCFunction)form_add_roundbutton, METH_OLDARGS}, + {"add_menu", (PyCFunction)form_add_menu, METH_OLDARGS}, + {"add_slider", (PyCFunction)form_add_slider, METH_OLDARGS}, + {"add_positioner", (PyCFunction)form_add_positioner, METH_OLDARGS}, + {"add_valslider", (PyCFunction)form_add_valslider, METH_OLDARGS}, + {"add_dial", (PyCFunction)form_add_dial, METH_OLDARGS}, + {"add_counter", (PyCFunction)form_add_counter, METH_OLDARGS}, + {"add_box", (PyCFunction)form_add_box, METH_OLDARGS}, + {"add_clock", (PyCFunction)form_add_clock, METH_OLDARGS}, + {"add_choice", (PyCFunction)form_add_choice, METH_OLDARGS}, + {"add_browser", (PyCFunction)form_add_browser, METH_OLDARGS}, + {"add_input", (PyCFunction)form_add_input, METH_OLDARGS}, + {"add_timer", (PyCFunction)form_add_timer, METH_OLDARGS}, + {"add_text", (PyCFunction)form_add_text, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +static void +form_dealloc(formobject *f) +{ + releaseobjects(f->ob_form); + if (f->ob_form->visible) + fl_hide_form(f->ob_form); + fl_free_form(f->ob_form); + PyObject_Del(f); +} + +#define OFF(x) offsetof(FL_FORM, x) + +static struct memberlist form_memberlist[] = { + {"window", T_LONG, OFF(window), RO}, + {"w", T_FLOAT, OFF(w)}, + {"h", T_FLOAT, OFF(h)}, + {"x", T_FLOAT, OFF(x), RO}, + {"y", T_FLOAT, OFF(y), RO}, + {"deactivated", T_INT, OFF(deactivated)}, + {"visible", T_INT, OFF(visible), RO}, + {"frozen", T_INT, OFF(frozen), RO}, + {"doublebuf", T_INT, OFF(doublebuf)}, + {NULL} /* Sentinel */ +}; + +#undef OFF + +static PyObject * +form_getattr(formobject *f, char *name) +{ + PyObject *meth; + + meth = Py_FindMethod(form_methods, (PyObject *)f, name); + if (meth != NULL) + return meth; + PyErr_Clear(); + return PyMember_Get((char *)f->ob_form, form_memberlist, name); +} + +static int +form_setattr(formobject *f, char *name, PyObject *v) +{ + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "can't delete form attributes"); + return -1; + } + + return PyMember_Set((char *)f->ob_form, form_memberlist, name, v); +} + +static PyObject * +form_repr(formobject *f) +{ + char buf[100]; + PyOS_snprintf(buf, sizeof(buf), "<FORMS_form at %p, window=%ld>", + f, f->ob_form->window); + return PyString_FromString(buf); +} + +static PyTypeObject Formtype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "fl.FORMS_form", /*tp_name*/ + sizeof(formobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)form_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)form_getattr, /*tp_getattr*/ + (setattrfunc)form_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc)form_repr, /*tp_repr*/ +}; + +static PyObject * +newformobject(FL_FORM *form) +{ + formobject *f; + f = PyObject_New(formobject, &Formtype); + if (f == NULL) + return NULL; + f->ob_form = form; + return (PyObject *)f; +} + + +/* The "fl" module */ + +static PyObject * +forms_make_form(PyObject *dummy, PyObject *args) +{ + int type; + float w, h; + FL_FORM *form; + if (!PyArg_Parse(args, "(iff)", &type, &w, &h)) + return NULL; + form = fl_bgn_form(type, w, h); + if (form == NULL) { + /* XXX Actually, cannot happen! */ + PyErr_NoMemory(); + return NULL; + } + fl_end_form(); + return newformobject(form); +} + +static PyObject * +forms_activate_all_forms(PyObject *f, PyObject *args) +{ + fl_activate_all_forms(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_deactivate_all_forms(PyObject *f, PyObject *args) +{ + fl_deactivate_all_forms(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject *my_event_callback = NULL; + +static PyObject * +forms_set_event_call_back(PyObject *dummy, PyObject *args) +{ + if (args == Py_None) + args = NULL; + my_event_callback = args; + Py_XINCREF(args); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_do_or_check_forms(PyObject *dummy, FL_OBJECT *(*func)(void)) +{ + FL_OBJECT *generic; + genericobject *g; + PyObject *arg, *res; + + for (;;) { + Py_BEGIN_ALLOW_THREADS + generic = (*func)(); + Py_END_ALLOW_THREADS + if (generic == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + if (generic == FL_EVENT) { + int dev; + short val; + if (my_event_callback == NULL) + return PyInt_FromLong(-1L); + dev = fl_qread(&val); + arg = Py_BuildValue("(ih)", dev, val); + if (arg == NULL) + return NULL; + res = PyEval_CallObject(my_event_callback, arg); + Py_XDECREF(res); + Py_DECREF(arg); + if (res == NULL) + return NULL; /* Callback raised exception */ + continue; + } + g = findgeneric(generic); + if (g == NULL) { + /* Object not known to us (some dialogs cause this) */ + continue; /* Ignore it */ + } + if (g->ob_callback == NULL) { + Py_INCREF(g); + return ((PyObject *) g); + } + arg = PyTuple_Pack(2, (PyObject *)g, g->ob_callback_arg); + if (arg == NULL) + return NULL; + res = PyEval_CallObject(g->ob_callback, arg); + Py_XDECREF(res); + Py_DECREF(arg); + if (res == NULL) + return NULL; /* Callback raised exception */ + } +} + +static PyObject * +forms_do_forms(PyObject *dummy) +{ + return forms_do_or_check_forms(dummy, fl_do_forms); +} + +static PyObject * +forms_check_forms(PyObject *dummy) +{ + return forms_do_or_check_forms(dummy, fl_check_forms); +} + +static PyObject * +forms_do_only_forms(PyObject *dummy) +{ + return forms_do_or_check_forms(dummy, fl_do_only_forms); +} + +static PyObject * +forms_check_only_forms(PyObject *dummy) +{ + return forms_do_or_check_forms(dummy, fl_check_only_forms); +} + +#ifdef UNUSED +static PyObject * +fl_call(void (*func)(void)) +{ + (*func)(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + +static PyObject * +forms_set_graphics_mode(PyObject *dummy, PyObject *args) +{ + int rgbmode, doublebuf; + + if (!PyArg_Parse(args, "(ii)", &rgbmode, &doublebuf)) + return NULL; + fl_set_graphics_mode(rgbmode,doublebuf); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_get_rgbmode(PyObject *dummy, PyObject *args) +{ + extern int fl_rgbmode; + + if (args != NULL) { + PyErr_BadArgument(); + return NULL; + } + return PyInt_FromLong((long)fl_rgbmode); +} + +static PyObject * +forms_show_errors(PyObject *dummy, PyObject *args) +{ + int show; + if (!PyArg_Parse(args, "i", &show)) + return NULL; + fl_show_errors(show); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_set_font_name(PyObject *dummy, PyObject *args) +{ + int numb; + char *name; + if (!PyArg_Parse(args, "(is)", &numb, &name)) + return NULL; + fl_set_font_name(numb, name); + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +forms_qdevice(PyObject *self, PyObject *args) +{ + short arg1; + if (!PyArg_Parse(args, "h", &arg1)) + return NULL; + fl_qdevice(arg1); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_unqdevice(PyObject *self, PyObject *args) +{ + short arg1; + if (!PyArg_Parse(args, "h", &arg1)) + return NULL; + fl_unqdevice(arg1); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_isqueued(PyObject *self, PyObject *args) +{ + long retval; + short arg1; + if (!PyArg_Parse(args, "h", &arg1)) + return NULL; + retval = fl_isqueued(arg1); + + return PyInt_FromLong(retval); +} + +static PyObject * +forms_qtest(PyObject *self, PyObject *args) +{ + long retval; + retval = fl_qtest(); + return PyInt_FromLong(retval); +} + + +static PyObject * +forms_qread(PyObject *self, PyObject *args) +{ + int dev; + short val; + Py_BEGIN_ALLOW_THREADS + dev = fl_qread(&val); + Py_END_ALLOW_THREADS + return Py_BuildValue("(ih)", dev, val); +} + +static PyObject * +forms_qreset(PyObject *self) +{ + fl_qreset(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_qenter(PyObject *self, PyObject *args) +{ + short arg1, arg2; + if (!PyArg_Parse(args, "(hh)", &arg1, &arg2)) + return NULL; + fl_qenter(arg1, arg2); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_color(PyObject *self, PyObject *args) +{ + int arg; + + if (!PyArg_Parse(args, "i", &arg)) return NULL; + + fl_color((short) arg); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_mapcolor(PyObject *self, PyObject *args) +{ + int arg0, arg1, arg2, arg3; + + if (!PyArg_Parse(args, "(iiii)", &arg0, &arg1, &arg2, &arg3)) + return NULL; + + fl_mapcolor(arg0, (short) arg1, (short) arg2, (short) arg3); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_getmcolor(PyObject *self, PyObject *args) +{ + int arg; + short r, g, b; + + if (!PyArg_Parse(args, "i", &arg)) return NULL; + + fl_getmcolor(arg, &r, &g, &b); + + return Py_BuildValue("(hhh)", r, g, b); +} + +static PyObject * +forms_get_mouse(PyObject *self) +{ + float x, y; + + fl_get_mouse(&x, &y); + + return Py_BuildValue("(ff)", x, y); +} + +static PyObject * +forms_tie(PyObject *self, PyObject *args) +{ + short arg1, arg2, arg3; + if (!PyArg_Parse(args, "(hhh)", &arg1, &arg2, &arg3)) + return NULL; + fl_tie(arg1, arg2, arg3); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_show_message(PyObject *f, PyObject *args) +{ + char *a, *b, *c; + + if (!PyArg_Parse(args, "(sss)", &a, &b, &c)) return NULL; + + Py_BEGIN_ALLOW_THREADS + fl_show_message(a, b, c); + Py_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +forms_show_choice(PyObject *f, PyObject *args) +{ + char *m1, *m2, *m3, *b1, *b2, *b3; + int nb; + char *format; + long rv; + + if (args == NULL || !PyTuple_Check(args)) { + PyErr_BadArgument(); + return NULL; + } + nb = PyTuple_Size(args) - 3; + if (nb <= 0) { + PyErr_SetString(PyExc_TypeError, + "need at least one button label"); + return NULL; + } + if (PyInt_Check(PyTuple_GetItem(args, 3))) { + PyErr_SetString(PyExc_TypeError, + "'number-of-buttons' argument not needed"); + return NULL; + } + switch (nb) { + case 1: format = "(ssss)"; break; + case 2: format = "(sssss)"; break; + case 3: format = "(ssssss)"; break; + default: + PyErr_SetString(PyExc_TypeError, "too many button labels"); + return NULL; + } + + if (!PyArg_Parse(args, format, &m1, &m2, &m3, &b1, &b2, &b3)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + rv = fl_show_choice(m1, m2, m3, nb, b1, b2, b3); + Py_END_ALLOW_THREADS + return PyInt_FromLong(rv); +} + +static PyObject * +forms_show_question(PyObject *f, PyObject *args) +{ + int ret; + char *a, *b, *c; + + if (!PyArg_Parse(args, "(sss)", &a, &b, &c)) return NULL; + + Py_BEGIN_ALLOW_THREADS + ret = fl_show_question(a, b, c); + Py_END_ALLOW_THREADS + + return PyInt_FromLong((long) ret); +} + +static PyObject * +forms_show_input(PyObject *f, PyObject *args) +{ + char *str; + char *a, *b; + + if (!PyArg_Parse(args, "(ss)", &a, &b)) return NULL; + + Py_BEGIN_ALLOW_THREADS + str = fl_show_input(a, b); + Py_END_ALLOW_THREADS + + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(str); +} + +static PyObject * +forms_file_selector(PyObject *f, PyObject *args) +{ + char *str; + char *a, *b, *c, *d; + + if (!PyArg_Parse(args, "(ssss)", &a, &b, &c, &d)) return NULL; + + Py_BEGIN_ALLOW_THREADS + str = fl_show_file_selector(a, b, c, d); + Py_END_ALLOW_THREADS + + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(str); +} + + +static PyObject * +forms_file_selector_func(PyObject *args, char *(*func)(void)) +{ + char *str; + + str = (*func) (); + + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(str); +} + +static PyObject * +forms_get_directory(PyObject *f, PyObject *args) +{ + return forms_file_selector_func(args, fl_get_directory); +} + +static PyObject * +forms_get_pattern(PyObject *f, PyObject *args) +{ + return forms_file_selector_func(args, fl_get_pattern); +} + +static PyObject * +forms_get_filename(PyObject *f, PyObject *args) +{ + return forms_file_selector_func(args, fl_get_filename); +} + +static PyMethodDef forms_methods[] = { +/* adm */ + {"make_form", forms_make_form, METH_OLDARGS}, + {"activate_all_forms", forms_activate_all_forms, METH_OLDARGS}, + {"deactivate_all_forms",forms_deactivate_all_forms, METH_OLDARGS}, +/* gl support wrappers */ + {"qdevice", forms_qdevice, METH_OLDARGS}, + {"unqdevice", forms_unqdevice, METH_OLDARGS}, + {"isqueued", forms_isqueued, METH_OLDARGS}, + {"qtest", forms_qtest, METH_OLDARGS}, + {"qread", forms_qread, METH_OLDARGS}, +/* {"blkqread", forms_blkqread, METH_OLDARGS}, */ + {"qreset", forms_qreset, METH_NOARGS}, + {"qenter", forms_qenter, METH_OLDARGS}, + {"get_mouse", forms_get_mouse, METH_NOARGS}, + {"tie", forms_tie, METH_OLDARGS}, +/* {"new_events", forms_new_events, METH_OLDARGS}, */ + {"color", forms_color, METH_OLDARGS}, + {"mapcolor", forms_mapcolor, METH_OLDARGS}, + {"getmcolor", forms_getmcolor, METH_OLDARGS}, +/* interaction */ + {"do_forms", forms_do_forms, METH_NOARGS}, + {"do_only_forms", forms_do_only_forms, METH_NOARGS}, + {"check_forms", forms_check_forms, METH_NOARGS}, + {"check_only_forms", forms_check_only_forms, METH_NOARGS}, + {"set_event_call_back", forms_set_event_call_back, METH_OLDARGS}, +/* goodies */ + {"show_message", forms_show_message, METH_OLDARGS}, + {"show_question", forms_show_question, METH_OLDARGS}, + {"show_choice", forms_show_choice, METH_OLDARGS}, + {"show_input", forms_show_input, METH_OLDARGS}, + {"show_file_selector", forms_file_selector, METH_OLDARGS}, + {"file_selector", forms_file_selector, METH_OLDARGS}, /* BW compat */ + {"get_directory", forms_get_directory, METH_OLDARGS}, + {"get_pattern", forms_get_pattern, METH_OLDARGS}, + {"get_filename", forms_get_filename, METH_OLDARGS}, + {"set_graphics_mode", forms_set_graphics_mode, METH_OLDARGS}, + {"get_rgbmode", forms_get_rgbmode, METH_OLDARGS}, + {"show_errors", forms_show_errors, METH_OLDARGS}, + {"set_font_name", forms_set_font_name, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +initfl(void) +{ + Py_InitModule("fl", forms_methods); + if (m == NULL) + return; + foreground(); + fl_init(); +} + + + diff --git a/sys/src/cmd/python/Modules/fmmodule.c b/sys/src/cmd/python/Modules/fmmodule.c new file mode 100644 index 000000000..1f7edb687 --- /dev/null +++ b/sys/src/cmd/python/Modules/fmmodule.c @@ -0,0 +1,264 @@ + +/* Font Manager module */ + +#include "Python.h" + +#include <gl.h> +#include <device.h> +#include <fmclient.h> + + +/* Font Handle object implementation */ + +typedef struct { + PyObject_HEAD + fmfonthandle fh_fh; +} fhobject; + +static PyTypeObject Fhtype; + +#define is_fhobject(v) ((v)->ob_type == &Fhtype) + +static PyObject * +newfhobject(fmfonthandle fh) +{ + fhobject *fhp; + if (fh == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "error creating new font handle"); + return NULL; + } + fhp = PyObject_New(fhobject, &Fhtype); + if (fhp == NULL) + return NULL; + fhp->fh_fh = fh; + return (PyObject *)fhp; +} + +/* Font Handle methods */ + +static PyObject * +fh_scalefont(fhobject *self, PyObject *args) +{ + double size; + if (!PyArg_ParseTuple(args, "d", &size)) + return NULL; + return newfhobject(fmscalefont(self->fh_fh, size)); +} + +/* XXX fmmakefont */ + +static PyObject * +fh_setfont(fhobject *self) +{ + fmsetfont(self->fh_fh); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +fh_getfontname(fhobject *self) +{ + char fontname[256]; + int len; + len = fmgetfontname(self->fh_fh, sizeof fontname, fontname); + if (len < 0) { + PyErr_SetString(PyExc_RuntimeError, "error in fmgetfontname"); + return NULL; + } + return PyString_FromStringAndSize(fontname, len); +} + +static PyObject * +fh_getcomment(fhobject *self) +{ + char comment[256]; + int len; + len = fmgetcomment(self->fh_fh, sizeof comment, comment); + if (len < 0) { + PyErr_SetString(PyExc_RuntimeError, "error in fmgetcomment"); + return NULL; + } + return PyString_FromStringAndSize(comment, len); +} + +static PyObject * +fh_getfontinfo(fhobject *self) +{ + fmfontinfo info; + if (fmgetfontinfo(self->fh_fh, &info) < 0) { + PyErr_SetString(PyExc_RuntimeError, "error in fmgetfontinfo"); + return NULL; + } + return Py_BuildValue("(llllllll)", + info.printermatched, + info.fixed_width, + info.xorig, + info.yorig, + info.xsize, + info.ysize, + info.height, + info.nglyphs); +} + +#if 0 +static PyObject * +fh_getwholemetrics(fhobject *self, PyObject *args) +{ +} +#endif + +static PyObject * +fh_getstrwidth(fhobject *self, PyObject *args) +{ + char *str; + if (!PyArg_ParseTuple(args, "s", &str)) + return NULL; + return PyInt_FromLong(fmgetstrwidth(self->fh_fh, str)); +} + +static PyMethodDef fh_methods[] = { + {"scalefont", (PyCFunction)fh_scalefont, METH_VARARGS}, + {"setfont", (PyCFunction)fh_setfont, METH_NOARGS}, + {"getfontname", (PyCFunction)fh_getfontname, METH_NOARGS}, + {"getcomment", (PyCFunction)fh_getcomment, METH_NOARGS}, + {"getfontinfo", (PyCFunction)fh_getfontinfo, METH_NOARGS}, +#if 0 + {"getwholemetrics", (PyCFunction)fh_getwholemetrics, METH_VARARGS}, +#endif + {"getstrwidth", (PyCFunction)fh_getstrwidth, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +fh_getattr(fhobject *fhp, char *name) +{ + return Py_FindMethod(fh_methods, (PyObject *)fhp, name); +} + +static void +fh_dealloc(fhobject *fhp) +{ + fmfreefont(fhp->fh_fh); + PyObject_Del(fhp); +} + +static PyTypeObject Fhtype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "fm.font handle", /*tp_name*/ + sizeof(fhobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)fh_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)fh_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +/* Font Manager functions */ + +static PyObject * +fm_init(PyObject *self) +{ + fminit(); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +fm_findfont(PyObject *self, PyObject *args) +{ + char *str; + if (!PyArg_ParseTuple(args, "s", &str)) + return NULL; + return newfhobject(fmfindfont(str)); +} + +static PyObject * +fm_prstr(PyObject *self, PyObject *args) +{ + char *str; + if (!PyArg_ParseTuple(args, "s", &str)) + return NULL; + fmprstr(str); + Py_INCREF(Py_None); + return Py_None; +} + +/* XXX This uses a global variable as temporary! Not re-entrant! */ + +static PyObject *fontlist; + +static void +clientproc(char *fontname) +{ + int err; + PyObject *v; + if (fontlist == NULL) + return; + v = PyString_FromString(fontname); + if (v == NULL) + err = -1; + else { + err = PyList_Append(fontlist, v); + Py_DECREF(v); + } + if (err != 0) { + Py_DECREF(fontlist); + fontlist = NULL; + } +} + +static PyObject * +fm_enumerate(PyObject *self) +{ + PyObject *res; + fontlist = PyList_New(0); + if (fontlist == NULL) + return NULL; + fmenumerate(clientproc); + res = fontlist; + fontlist = NULL; + return res; +} + +static PyObject * +fm_setpath(PyObject *self, PyObject *args) +{ + char *str; + if (!PyArg_ParseTuple(args, "s", &str)) + return NULL; + fmsetpath(str); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +fm_fontpath(PyObject *self) +{ + return PyString_FromString(fmfontpath()); +} + +static PyMethodDef fm_methods[] = { + {"init", fm_init, METH_NOARGS}, + {"findfont", fm_findfont, METH_VARARGS}, + {"enumerate", fm_enumerate, METH_NOARGS}, + {"prstr", fm_prstr, METH_VARARGS}, + {"setpath", fm_setpath, METH_VARARGS}, + {"fontpath", fm_fontpath, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + + +void +initfm(void) +{ + Py_InitModule("fm", fm_methods); + if (m == NULL) + return; + fminit(); +} diff --git a/sys/src/cmd/python/Modules/fpectlmodule.c b/sys/src/cmd/python/Modules/fpectlmodule.c new file mode 100644 index 000000000..74354bac5 --- /dev/null +++ b/sys/src/cmd/python/Modules/fpectlmodule.c @@ -0,0 +1,303 @@ +/* + --------------------------------------------------------------------- + / Copyright (c) 1996. \ + | The Regents of the University of California. | + | All rights reserved. | + | | + | Permission to use, copy, modify, and distribute this software for | + | any purpose without fee is hereby granted, provided that this en- | + | tire notice is included in all copies of any software which is or | + | includes a copy or modification of this software and in all | + | copies of the supporting documentation for such software. | + | | + | This work was produced at the University of California, Lawrence | + | Livermore National Laboratory under contract no. W-7405-ENG-48 | + | between the U.S. Department of Energy and The Regents of the | + | University of California for the operation of UC LLNL. | + | | + | DISCLAIMER | + | | + | This software was prepared as an account of work sponsored by an | + | agency of the United States Government. Neither the United States | + | Government nor the University of California nor any of their em- | + | ployees, makes any warranty, express or implied, or assumes any | + | liability or responsibility for the accuracy, completeness, or | + | usefulness of any information, apparatus, product, or process | + | disclosed, or represents that its use would not infringe | + | privately-owned rights. Reference herein to any specific commer- | + | cial products, process, or service by trade name, trademark, | + | manufacturer, or otherwise, does not necessarily constitute or | + | imply its endorsement, recommendation, or favoring by the United | + | States Government or the University of California. The views and | + | opinions of authors expressed herein do not necessarily state or | + | reflect those of the United States Government or the University | + | of California, and shall not be used for advertising or product | + \ endorsement purposes. / + --------------------------------------------------------------------- +*/ + +/* + Floating point exception control module. + + This Python module provides bare-bones control over floating point + units from several hardware manufacturers. Specifically, it allows + the user to turn on the generation of SIGFPE whenever any of the + three serious IEEE 754 exceptions (Division by Zero, Overflow, + Invalid Operation) occurs. We currently ignore Underflow and + Inexact Result exceptions, although those could certainly be added + if desired. + + The module also establishes a signal handler for SIGFPE during + initialization. This builds on code found in the Python + distribution at Include/pyfpe.h and Python/pyfpe.c. If those files + are not in your Python distribution, find them in a patch at + ftp://icf.llnl.gov/pub/python/busby/patches.961108.tgz. + + This module is only useful to you if it happens to include code + specific for your hardware and software environment. If you can + contribute OS-specific code for new platforms, or corrections for + the code provided, it will be greatly appreciated. + + ** Version 1.0: September 20, 1996. Lee Busby, LLNL. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Python.h" +#include <signal.h> + +#if defined(__FreeBSD__) +# include <ieeefp.h> +#elif defined(__VMS) +#define __NEW_STARLET +#include <starlet.h> +#include <ieeedef.h> +#endif + +#ifndef WANT_SIGFPE_HANDLER +/* Define locally if they are not defined in Python. This gives only + * the limited control to induce a core dump in case of an exception. + */ +#include <setjmp.h> +static jmp_buf PyFPE_jbuf; +static int PyFPE_counter = 0; +#endif + +typedef void Sigfunc(int); +static Sigfunc sigfpe_handler; +static void fpe_reset(Sigfunc *); + +static PyObject *fpe_error; +PyMODINIT_FUNC initfpectl(void); +static PyObject *turnon_sigfpe (PyObject *self,PyObject *args); +static PyObject *turnoff_sigfpe (PyObject *self,PyObject *args); + +static PyMethodDef fpectl_methods[] = { + {"turnon_sigfpe", (PyCFunction) turnon_sigfpe, METH_VARARGS}, + {"turnoff_sigfpe", (PyCFunction) turnoff_sigfpe, METH_VARARGS}, + {0,0} +}; + +static PyObject *turnon_sigfpe(PyObject *self,PyObject *args) +{ + /* Do any architecture-specific one-time only initialization here. */ + + fpe_reset(sigfpe_handler); + Py_INCREF (Py_None); + return Py_None; +} + +static void fpe_reset(Sigfunc *handler) +{ + /* Reset the exception handling machinery, and reset the signal + * handler for SIGFPE to the given handler. + */ + +/*-- IRIX -----------------------------------------------------------------*/ +#if defined(sgi) + /* See man page on handle_sigfpes -- must link with -lfpe + * My usage doesn't follow the man page exactly. Maybe somebody + * else can explain handle_sigfpes to me.... + * cc -c -I/usr/local/python/include fpectlmodule.c + * ld -shared -o fpectlmodule.so fpectlmodule.o -lfpe + */ +#include <sigfpe.h> + typedef void user_routine (unsigned[5], int[2]); + typedef void abort_routine (unsigned long); + handle_sigfpes(_OFF, 0, + (user_routine *)0, + _TURN_OFF_HANDLER_ON_ERROR, + NULL); + handle_sigfpes(_ON, _EN_OVERFL | _EN_DIVZERO | _EN_INVALID, + (user_routine *)0, + _ABORT_ON_ERROR, + NULL); + PyOS_setsig(SIGFPE, handler); + +/*-- SunOS and Solaris ----------------------------------------------------*/ +#elif defined(sun) + /* References: ieee_handler, ieee_sun, ieee_functions, and ieee_flags + man pages (SunOS or Solaris) + cc -c -I/usr/local/python/include fpectlmodule.c + ld -G -o fpectlmodule.so -L/opt/SUNWspro/lib fpectlmodule.o -lsunmath -lm + */ +#include <math.h> +#ifndef _SUNMATH_H + extern void nonstandard_arithmetic(void); + extern int ieee_flags(const char*, const char*, const char*, char **); + extern long ieee_handler(const char*, const char*, sigfpe_handler_type); +#endif + + char *mode="exception", *in="all", *out; + (void) nonstandard_arithmetic(); + (void) ieee_flags("clearall",mode,in,&out); + (void) ieee_handler("set","common",(sigfpe_handler_type)handler); + PyOS_setsig(SIGFPE, handler); + +/*-- HPUX -----------------------------------------------------------------*/ +#elif defined(__hppa) || defined(hppa) + /* References: fpsetmask man page */ + /* cc -Aa +z -c -I/usr/local/python/include fpectlmodule.c */ + /* ld -b -o fpectlmodule.sl fpectlmodule.o -lm */ +#include <math.h> + fpsetdefaults(); + PyOS_setsig(SIGFPE, handler); + +/*-- IBM AIX --------------------------------------------------------------*/ +#elif defined(__AIX) || defined(_AIX) + /* References: fp_trap, fp_enable man pages */ +#include <fptrap.h> + fp_trap(FP_TRAP_SYNC); + fp_enable(TRP_INVALID | TRP_DIV_BY_ZERO | TRP_OVERFLOW); + PyOS_setsig(SIGFPE, handler); + +/*-- DEC ALPHA OSF --------------------------------------------------------*/ +#elif defined(__alpha) && defined(__osf__) + /* References: exception_intro, ieee man pages */ + /* cc -c -I/usr/local/python/include fpectlmodule.c */ + /* ld -shared -o fpectlmodule.so fpectlmodule.o */ +#include <machine/fpu.h> + unsigned long fp_control = + IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE | IEEE_TRAP_ENABLE_OVF; + ieee_set_fp_control(fp_control); + PyOS_setsig(SIGFPE, handler); + +/*-- DEC ALPHA LINUX ------------------------------------------------------*/ +#elif defined(__alpha) && defined(linux) +#include <asm/fpu.h> + unsigned long fp_control = + IEEE_TRAP_ENABLE_INV | IEEE_TRAP_ENABLE_DZE | IEEE_TRAP_ENABLE_OVF; + ieee_set_fp_control(fp_control); + PyOS_setsig(SIGFPE, handler); + +/*-- DEC ALPHA VMS --------------------------------------------------------*/ +#elif defined(__ALPHA) && defined(__VMS) + IEEE clrmsk; + IEEE setmsk; + clrmsk.ieee$q_flags = + IEEE$M_TRAP_ENABLE_UNF | IEEE$M_TRAP_ENABLE_INE | + IEEE$M_MAP_UMZ; + setmsk.ieee$q_flags = + IEEE$M_TRAP_ENABLE_INV | IEEE$M_TRAP_ENABLE_DZE | + IEEE$M_TRAP_ENABLE_OVF; + sys$ieee_set_fp_control(&clrmsk, &setmsk, 0); + PyOS_setsig(SIGFPE, handler); + +/*-- HP IA64 VMS --------------------------------------------------------*/ +#elif defined(__ia64) && defined(__VMS) + PyOS_setsig(SIGFPE, handler); + +/*-- Cray Unicos ----------------------------------------------------------*/ +#elif defined(cray) + /* UNICOS delivers SIGFPE by default, but no matherr */ +#ifdef HAS_LIBMSET + libmset(-1); +#endif + PyOS_setsig(SIGFPE, handler); + +/*-- FreeBSD ----------------------------------------------------------------*/ +#elif defined(__FreeBSD__) + fpresetsticky(fpgetsticky()); + fpsetmask(FP_X_INV | FP_X_DZ | FP_X_OFL); + PyOS_setsig(SIGFPE, handler); + +/*-- Linux ----------------------------------------------------------------*/ +#elif defined(linux) +#ifdef __GLIBC__ +#include <fpu_control.h> +#else +#include <i386/fpu_control.h> +#endif +#ifdef _FPU_SETCW + { + fpu_control_t cw = 0x1372; + _FPU_SETCW(cw); + } +#else + __setfpucw(0x1372); +#endif + PyOS_setsig(SIGFPE, handler); + +/*-- Microsoft Windows, NT ------------------------------------------------*/ +#elif defined(_MSC_VER) + /* Reference: Visual C++ Books Online 4.2, + Run-Time Library Reference, _control87, _controlfp */ +#include <float.h> + unsigned int cw = _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW; + (void)_controlfp(0, cw); + PyOS_setsig(SIGFPE, handler); + +/*-- Give Up --------------------------------------------------------------*/ +#else + fputs("Operation not implemented\n", stderr); +#endif + +} + +static PyObject *turnoff_sigfpe(PyObject *self,PyObject *args) +{ +#ifdef __FreeBSD__ + fpresetsticky(fpgetsticky()); + fpsetmask(0); +#elif defined(__VMS) + IEEE clrmsk; + clrmsk.ieee$q_flags = + IEEE$M_TRAP_ENABLE_UNF | IEEE$M_TRAP_ENABLE_INE | + IEEE$M_MAP_UMZ | IEEE$M_TRAP_ENABLE_INV | + IEEE$M_TRAP_ENABLE_DZE | IEEE$M_TRAP_ENABLE_OVF | + IEEE$M_INHERIT; + sys$ieee_set_fp_control(&clrmsk, 0, 0); +#else + fputs("Operation not implemented\n", stderr); +#endif + Py_INCREF(Py_None); + return Py_None; +} + +static void sigfpe_handler(int signo) +{ + fpe_reset(sigfpe_handler); + if(PyFPE_counter) { + longjmp(PyFPE_jbuf, 1); + } else { + Py_FatalError("Unprotected floating point exception"); + } +} + +PyMODINIT_FUNC initfpectl(void) +{ + PyObject *m, *d; + m = Py_InitModule("fpectl", fpectl_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + fpe_error = PyErr_NewException("fpectl.error", NULL, NULL); + if (fpe_error != NULL) + PyDict_SetItemString(d, "error", fpe_error); +} + +#ifdef __cplusplus +} +#endif diff --git a/sys/src/cmd/python/Modules/fpetestmodule.c b/sys/src/cmd/python/Modules/fpetestmodule.c new file mode 100644 index 000000000..22e95dbae --- /dev/null +++ b/sys/src/cmd/python/Modules/fpetestmodule.c @@ -0,0 +1,186 @@ +/* + --------------------------------------------------------------------- + / Copyright (c) 1996. \ + | The Regents of the University of California. | + | All rights reserved. | + | | + | Permission to use, copy, modify, and distribute this software for | + | any purpose without fee is hereby granted, provided that this en- | + | tire notice is included in all copies of any software which is or | + | includes a copy or modification of this software and in all | + | copies of the supporting documentation for such software. | + | | + | This work was produced at the University of California, Lawrence | + | Livermore National Laboratory under contract no. W-7405-ENG-48 | + | between the U.S. Department of Energy and The Regents of the | + | University of California for the operation of UC LLNL. | + | | + | DISCLAIMER | + | | + | This software was prepared as an account of work sponsored by an | + | agency of the United States Government. Neither the United States | + | Government nor the University of California nor any of their em- | + | ployees, makes any warranty, express or implied, or assumes any | + | liability or responsibility for the accuracy, completeness, or | + | usefulness of any information, apparatus, product, or process | + | disclosed, or represents that its use would not infringe | + | privately-owned rights. Reference herein to any specific commer- | + | cial products, process, or service by trade name, trademark, | + | manufacturer, or otherwise, does not necessarily constitute or | + | imply its endorsement, recommendation, or favoring by the United | + | States Government or the University of California. The views and | + | opinions of authors expressed herein do not necessarily state or | + | reflect those of the United States Government or the University | + | of California, and shall not be used for advertising or product | + \ endorsement purposes. / + --------------------------------------------------------------------- +*/ + +/* + Floating point exception test module. + + */ + +#include "Python.h" + +static PyObject *fpe_error; +PyMODINIT_FUNC initfpetest(void); +static PyObject *test(PyObject *self,PyObject *args); +static double db0(double); +static double overflow(double); +static double nest1(int, double); +static double nest2(int, double); +static double nest3(double); +static void printerr(double); + +static PyMethodDef fpetest_methods[] = { + {"test", (PyCFunction) test, METH_VARARGS}, + {0,0} +}; + +static PyObject *test(PyObject *self,PyObject *args) +{ + double r; + + fprintf(stderr,"overflow"); + r = overflow(1.e160); + printerr(r); + + fprintf(stderr,"\ndiv by 0"); + r = db0(0.0); + printerr(r); + + fprintf(stderr,"\nnested outer"); + r = nest1(0, 0.0); + printerr(r); + + fprintf(stderr,"\nnested inner"); + r = nest1(1, 1.0); + printerr(r); + + fprintf(stderr,"\ntrailing outer"); + r = nest1(2, 2.0); + printerr(r); + + fprintf(stderr,"\nnested prior"); + r = nest2(0, 0.0); + printerr(r); + + fprintf(stderr,"\nnested interior"); + r = nest2(1, 1.0); + printerr(r); + + fprintf(stderr,"\nnested trailing"); + r = nest2(2, 2.0); + printerr(r); + + Py_INCREF (Py_None); + return Py_None; +} + +static void printerr(double r) +{ + if(r == 3.1416){ + fprintf(stderr,"\tPASS\n"); + PyErr_Print(); + }else{ + fprintf(stderr,"\tFAIL\n"); + } + PyErr_Clear(); +} + +static double nest1(int i, double x) +{ + double a = 1.0; + + PyFPE_START_PROTECT("Division by zero, outer zone", return 3.1416) + if(i == 0){ + a = 1./x; + }else if(i == 1){ + /* This (following) message is never seen. */ + PyFPE_START_PROTECT("Division by zero, inner zone", return 3.1416) + a = 1./(1. - x); + PyFPE_END_PROTECT(a) + }else if(i == 2){ + a = 1./(2. - x); + } + PyFPE_END_PROTECT(a) + + return a; +} + +static double nest2(int i, double x) +{ + double a = 1.0; + PyFPE_START_PROTECT("Division by zero, prior error", return 3.1416) + if(i == 0){ + a = 1./x; + }else if(i == 1){ + a = nest3(x); + }else if(i == 2){ + a = 1./(2. - x); + } + PyFPE_END_PROTECT(a) + return a; +} + +static double nest3(double x) +{ + double result; + /* This (following) message is never seen. */ + PyFPE_START_PROTECT("Division by zero, nest3 error", return 3.1416) + result = 1./(1. - x); + PyFPE_END_PROTECT(result) + return result; +} + +static double db0(double x) +{ + double a; + PyFPE_START_PROTECT("Division by zero", return 3.1416) + a = 1./x; + PyFPE_END_PROTECT(a) + return a; +} + +static double overflow(double b) +{ + double a; + PyFPE_START_PROTECT("Overflow", return 3.1416) + a = b*b; + PyFPE_END_PROTECT(a) + return a; +} + +PyMODINIT_FUNC initfpetest(void) +{ + PyObject *m, *d; + + m = Py_InitModule("fpetest", fpetest_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + fpe_error = PyErr_NewException("fpetest.error", NULL, NULL); + if (fpe_error != NULL) + PyDict_SetItemString(d, "error", fpe_error); +} diff --git a/sys/src/cmd/python/Modules/gc_weakref.txt b/sys/src/cmd/python/Modules/gc_weakref.txt new file mode 100644 index 000000000..d7be6c3ab --- /dev/null +++ b/sys/src/cmd/python/Modules/gc_weakref.txt @@ -0,0 +1,219 @@ +Intro +===== + +The basic rule for dealing with weakref callbacks (and __del__ methods too, +for that matter) during cyclic gc: + + Once gc has computed the set of unreachable objects, no Python-level + code can be allowed to access an unreachable object. + +If that can happen, then the Python code can resurrect unreachable objects +too, and gc can't detect that without starting over. Since gc eventually +runs tp_clear on all unreachable objects, if an unreachable object is +resurrected then tp_clear will eventually be called on it (or may already +have been called before resurrection). At best (and this has been an +historically common bug), tp_clear empties an instance's __dict__, and +"impossible" AttributeErrors result. At worst, tp_clear leaves behind an +insane object at the C level, and segfaults result (historically, most +often by setting a new-style class's mro pointer to NULL, after which +attribute lookups performed by the class can segfault). + +OTOH, it's OK to run Python-level code that can't access unreachable +objects, and sometimes that's necessary. The chief example is the callback +attached to a reachable weakref W to an unreachable object O. Since O is +going away, and W is still alive, the callback must be invoked. Because W +is still alive, everything reachable from its callback is also reachable, +so it's also safe to invoke the callback (although that's trickier than it +sounds, since other reachable weakrefs to other unreachable objects may +still exist, and be accessible to the callback -- there are lots of painful +details like this covered in the rest of this file). + +Python 2.4/2.3.5 +================ + +The "Before 2.3.3" section below turned out to be wrong in some ways, but +I'm leaving it as-is because it's more right than wrong, and serves as a +wonderful example of how painful analysis can miss not only the forest for +the trees, but also miss the trees for the aphids sucking the trees +dry <wink>. + +The primary thing it missed is that when a weakref to a piece of cyclic +trash (CT) exists, then any call to any Python code whatsoever can end up +materializing a strong reference to that weakref's CT referent, and so +possibly resurrect an insane object (one for which cyclic gc has called-- or +will call before it's done --tp_clear()). It's not even necessarily that a +weakref callback or __del__ method does something nasty on purpose: as +soon as we execute Python code, threads other than the gc thread can run +too, and they can do ordinary things with weakrefs that end up resurrecting +CT while gc is running. + + http://www.python.org/sf/1055820 + +shows how innocent it can be, and also how nasty. Variants of the three +focussed test cases attached to that bug report are now part of Python's +standard Lib/test/test_gc.py. + +Jim Fulton gave the best nutshell summary of the new (in 2.4 and 2.3.5) +approach: + + Clearing cyclic trash can call Python code. If there are weakrefs to + any of the cyclic trash, then those weakrefs can be used to resurrect + the objects. Therefore, *before* clearing cyclic trash, we need to + remove any weakrefs. If any of the weakrefs being removed have + callbacks, then we need to save the callbacks and call them *after* all + of the weakrefs have been cleared. + +Alas, doing just that much doesn't work, because it overlooks what turned +out to be the much subtler problems that were fixed earlier, and described +below. We do clear all weakrefs to CT now before breaking cycles, but not +all callbacks encountered can be run later. That's explained in horrid +detail below. + +Older text follows, with a some later comments in [] brackets: + +Before 2.3.3 +============ + +Before 2.3.3, Python's cyclic gc didn't pay any attention to weakrefs. +Segfaults in Zope3 resulted. + +weakrefs in Python are designed to, at worst, let *other* objects learn +that a given object has died, via a callback function. The weakly +referenced object itself is not passed to the callback, and the presumption +is that the weakly referenced object is unreachable trash at the time the +callback is invoked. + +That's usually true, but not always. Suppose a weakly referenced object +becomes part of a clump of cyclic trash. When enough cycles are broken by +cyclic gc that the object is reclaimed, the callback is invoked. If it's +possible for the callback to get at objects in the cycle(s), then it may be +possible for those objects to access (via strong references in the cycle) +the weakly referenced object being torn down, or other objects in the cycle +that have already suffered a tp_clear() call. There's no guarantee that an +object is in a sane state after tp_clear(). Bad things (including +segfaults) can happen right then, during the callback's execution, or can +happen at any later time if the callback manages to resurrect an insane +object. + +[That missed that, in addition, a weakref to CT can exist outside CT, and + any callback into Python can use such a non-CT weakref to resurrect its CT + referent. The same bad kinds of things can happen then.] + +Note that if it's possible for the callback to get at objects in the trash +cycles, it must also be the case that the callback itself is part of the +trash cycles. Else the callback would have acted as an external root to +the current collection, and nothing reachable from it would be in cyclic +trash either. + +[Except that a non-CT callback can also use a non-CT weakref to get at + CT objects.] + +More, if the callback itself is in cyclic trash, then the weakref to which +the callback is attached must also be trash, and for the same kind of +reason: if the weakref acted as an external root, then the callback could +not have been cyclic trash. + +So a problem here requires that a weakref, that weakref's callback, and the +weakly referenced object, all be in cyclic trash at the same time. This +isn't easy to stumble into by accident while Python is running, and, indeed, +it took quite a while to dream up failing test cases. Zope3 saw segfaults +during shutdown, during the second call of gc in Py_Finalize, after most +modules had been torn down. That creates many trash cycles (esp. those +involving new-style classes), making the problem much more likely. Once you +know what's required to provoke the problem, though, it's easy to create +tests that segfault before shutdown. + +In 2.3.3, before breaking cycles, we first clear all the weakrefs with +callbacks in cyclic trash. Since the weakrefs *are* trash, and there's no +defined-- or even predictable --order in which tp_clear() gets called on +cyclic trash, it's defensible to first clear weakrefs with callbacks. It's +a feature of Python's weakrefs too that when a weakref goes away, the +callback (if any) associated with it is thrown away too, unexecuted. + +[In 2.4/2.3.5, we first clear all weakrefs to CT objects, whether or not + those weakrefs are themselves CT, and whether or not they have callbacks. + The callbacks (if any) on non-CT weakrefs (if any) are invoked later, + after all weakrefs-to-CT have been cleared. The callbacks (if any) on CT + weakrefs (if any) are never invoked, for the excruciating reasons + explained here.] + +Just that much is almost enough to prevent problems, by throwing away +*almost* all the weakref callbacks that could get triggered by gc. The +problem remaining is that clearing a weakref with a callback decrefs the +callback object, and the callback object may *itself* be weakly referenced, +via another weakref with another callback. So the process of clearing +weakrefs can trigger callbacks attached to other weakrefs, and those +latter weakrefs may or may not be part of cyclic trash. + +So, to prevent any Python code from running while gc is invoking tp_clear() +on all the objects in cyclic trash, + +[That was always wrong: we can't stop Python code from running when gc + is breaking cycles. If an object with a __del__ method is not itself in + a cycle, but is reachable only from CT, then breaking cycles will, as a + matter of course, drop the refcount on that object to 0, and its __del__ + will run right then. What we can and must stop is running any Python + code that could access CT.] + it's not quite enough just to invoke +tp_clear() on weakrefs with callbacks first. Instead the weakref module +grew a new private function (_PyWeakref_ClearRef) that does only part of +tp_clear(): it removes the weakref from the weakly-referenced object's list +of weakrefs, but does not decref the callback object. So calling +_PyWeakref_ClearRef(wr) ensures that wr's callback object will never +trigger, and (unlike weakref's tp_clear()) also prevents any callback +associated *with* wr's callback object from triggering. + +[Although we may trigger such callbacks later, as explained below.] + +Then we can call tp_clear on all the cyclic objects and never trigger +Python code. + +[As above, not so: it means never trigger Python code that can access CT.] + +After we do that, the callback objects still need to be decref'ed. Callbacks +(if any) *on* the callback objects that were also part of cyclic trash won't +get invoked, because we cleared all trash weakrefs with callbacks at the +start. Callbacks on the callback objects that were not part of cyclic trash +acted as external roots to everything reachable from them, so nothing +reachable from them was part of cyclic trash, so gc didn't do any damage to +objects reachable from them, and it's safe to call them at the end of gc. + +[That's so. In addition, now we also invoke (if any) the callbacks on + non-CT weakrefs to CT objects, during the same pass that decrefs the + callback objects.] + +An alternative would have been to treat objects with callbacks like objects +with __del__ methods, refusing to collect them, appending them to gc.garbage +instead. That would have been much easier. Jim Fulton gave a strong +argument against that (on Python-Dev): + + There's a big difference between __del__ and weakref callbacks. + The __del__ method is "internal" to a design. When you design a + class with a del method, you know you have to avoid including the + class in cycles. + + Now, suppose you have a design that makes has no __del__ methods but + that does use cyclic data structures. You reason about the design, + run tests, and convince yourself you don't have a leak. + + Now, suppose some external code creates a weakref to one of your + objects. All of a sudden, you start leaking. You can look at your + code all you want and you won't find a reason for the leak. + +IOW, a class designer can out-think __del__ problems, but has no control +over who creates weakrefs to his classes or class instances. The class +user has little chance either of predicting when the weakrefs he creates +may end up in cycles. + +Callbacks on weakref callbacks are executed in an arbitrary order, and +that's not good (a primary reason not to collect cycles with objects with +__del__ methods is to avoid running finalizers in an arbitrary order). +However, a weakref callback on a weakref callback has got to be rare. +It's possible to do such a thing, so gc has to be robust against it, but +I doubt anyone has done it outside the test case I wrote for it. + +[The callbacks (if any) on non-CT weakrefs to CT objects are also executed + in an arbitrary order now. But they were before too, depending on the + vagaries of when tp_clear() happened to break enough cycles to trigger + them. People simply shouldn't try to use __del__ or weakref callbacks to + do fancy stuff.] diff --git a/sys/src/cmd/python/Modules/gcmodule.c b/sys/src/cmd/python/Modules/gcmodule.c new file mode 100644 index 000000000..6c5011cab --- /dev/null +++ b/sys/src/cmd/python/Modules/gcmodule.c @@ -0,0 +1,1390 @@ +/* + + Reference Cycle Garbage Collection + ================================== + + Neil Schemenauer <nas@arctrix.com> + + Based on a post on the python-dev list. Ideas from Guido van Rossum, + Eric Tiedemann, and various others. + + http://www.arctrix.com/nas/python/gc/ + http://www.python.org/pipermail/python-dev/2000-March/003869.html + http://www.python.org/pipermail/python-dev/2000-March/004010.html + http://www.python.org/pipermail/python-dev/2000-March/004022.html + + For a highlevel view of the collection process, read the collect + function. + +*/ + +#include "Python.h" + +/* Get an object's GC head */ +#define AS_GC(o) ((PyGC_Head *)(o)-1) + +/* Get the object given the GC head */ +#define FROM_GC(g) ((PyObject *)(((PyGC_Head *)g)+1)) + +/*** Global GC state ***/ + +struct gc_generation { + PyGC_Head head; + int threshold; /* collection threshold */ + int count; /* count of allocations or collections of younger + generations */ +}; + +#define NUM_GENERATIONS 3 +#define GEN_HEAD(n) (&generations[n].head) + +/* linked lists of container objects */ +static struct gc_generation generations[NUM_GENERATIONS] = { + /* PyGC_Head, threshold, count */ + {{{GEN_HEAD(0), GEN_HEAD(0), 0}}, 700, 0}, + {{{GEN_HEAD(1), GEN_HEAD(1), 0}}, 10, 0}, + {{{GEN_HEAD(2), GEN_HEAD(2), 0}}, 10, 0}, +}; + +PyGC_Head *_PyGC_generation0 = GEN_HEAD(0); + +static int enabled = 1; /* automatic collection enabled? */ + +/* true if we are currently running the collector */ +static int collecting = 0; + +/* list of uncollectable objects */ +static PyObject *garbage = NULL; + +/* Python string to use if unhandled exception occurs */ +static PyObject *gc_str = NULL; + +/* Python string used to look for __del__ attribute. */ +static PyObject *delstr = NULL; + +/* set for debugging information */ +#define DEBUG_STATS (1<<0) /* print collection statistics */ +#define DEBUG_COLLECTABLE (1<<1) /* print collectable objects */ +#define DEBUG_UNCOLLECTABLE (1<<2) /* print uncollectable objects */ +#define DEBUG_INSTANCES (1<<3) /* print instances */ +#define DEBUG_OBJECTS (1<<4) /* print other objects */ +#define DEBUG_SAVEALL (1<<5) /* save all garbage in gc.garbage */ +#define DEBUG_LEAK DEBUG_COLLECTABLE | \ + DEBUG_UNCOLLECTABLE | \ + DEBUG_INSTANCES | \ + DEBUG_OBJECTS | \ + DEBUG_SAVEALL +static int debug; +static PyObject *tmod = NULL; + +/*-------------------------------------------------------------------------- +gc_refs values. + +Between collections, every gc'ed object has one of two gc_refs values: + +GC_UNTRACKED + The initial state; objects returned by PyObject_GC_Malloc are in this + state. The object doesn't live in any generation list, and its + tp_traverse slot must not be called. + +GC_REACHABLE + The object lives in some generation list, and its tp_traverse is safe to + call. An object transitions to GC_REACHABLE when PyObject_GC_Track + is called. + +During a collection, gc_refs can temporarily take on other states: + +>= 0 + At the start of a collection, update_refs() copies the true refcount + to gc_refs, for each object in the generation being collected. + subtract_refs() then adjusts gc_refs so that it equals the number of + times an object is referenced directly from outside the generation + being collected. + gc_refs remains >= 0 throughout these steps. + +GC_TENTATIVELY_UNREACHABLE + move_unreachable() then moves objects not reachable (whether directly or + indirectly) from outside the generation into an "unreachable" set. + Objects that are found to be reachable have gc_refs set to GC_REACHABLE + again. Objects that are found to be unreachable have gc_refs set to + GC_TENTATIVELY_UNREACHABLE. It's "tentatively" because the pass doing + this can't be sure until it ends, and GC_TENTATIVELY_UNREACHABLE may + transition back to GC_REACHABLE. + + Only objects with GC_TENTATIVELY_UNREACHABLE still set are candidates + for collection. If it's decided not to collect such an object (e.g., + it has a __del__ method), its gc_refs is restored to GC_REACHABLE again. +---------------------------------------------------------------------------- +*/ +#define GC_UNTRACKED _PyGC_REFS_UNTRACKED +#define GC_REACHABLE _PyGC_REFS_REACHABLE +#define GC_TENTATIVELY_UNREACHABLE _PyGC_REFS_TENTATIVELY_UNREACHABLE + +#define IS_TRACKED(o) ((AS_GC(o))->gc.gc_refs != GC_UNTRACKED) +#define IS_REACHABLE(o) ((AS_GC(o))->gc.gc_refs == GC_REACHABLE) +#define IS_TENTATIVELY_UNREACHABLE(o) ( \ + (AS_GC(o))->gc.gc_refs == GC_TENTATIVELY_UNREACHABLE) + +/*** list functions ***/ + +static void +gc_list_init(PyGC_Head *list) +{ + list->gc.gc_prev = list; + list->gc.gc_next = list; +} + +static int +gc_list_is_empty(PyGC_Head *list) +{ + return (list->gc.gc_next == list); +} + +#if 0 +/* This became unused after gc_list_move() was introduced. */ +/* Append `node` to `list`. */ +static void +gc_list_append(PyGC_Head *node, PyGC_Head *list) +{ + node->gc.gc_next = list; + node->gc.gc_prev = list->gc.gc_prev; + node->gc.gc_prev->gc.gc_next = node; + list->gc.gc_prev = node; +} +#endif + +/* Remove `node` from the gc list it's currently in. */ +static void +gc_list_remove(PyGC_Head *node) +{ + node->gc.gc_prev->gc.gc_next = node->gc.gc_next; + node->gc.gc_next->gc.gc_prev = node->gc.gc_prev; + node->gc.gc_next = NULL; /* object is not currently tracked */ +} + +/* Move `node` from the gc list it's currently in (which is not explicitly + * named here) to the end of `list`. This is semantically the same as + * gc_list_remove(node) followed by gc_list_append(node, list). + */ +static void +gc_list_move(PyGC_Head *node, PyGC_Head *list) +{ + PyGC_Head *new_prev; + PyGC_Head *current_prev = node->gc.gc_prev; + PyGC_Head *current_next = node->gc.gc_next; + /* Unlink from current list. */ + current_prev->gc.gc_next = current_next; + current_next->gc.gc_prev = current_prev; + /* Relink at end of new list. */ + new_prev = node->gc.gc_prev = list->gc.gc_prev; + new_prev->gc.gc_next = list->gc.gc_prev = node; + node->gc.gc_next = list; +} + +/* append list `from` onto list `to`; `from` becomes an empty list */ +static void +gc_list_merge(PyGC_Head *from, PyGC_Head *to) +{ + PyGC_Head *tail; + assert(from != to); + if (!gc_list_is_empty(from)) { + tail = to->gc.gc_prev; + tail->gc.gc_next = from->gc.gc_next; + tail->gc.gc_next->gc.gc_prev = tail; + to->gc.gc_prev = from->gc.gc_prev; + to->gc.gc_prev->gc.gc_next = to; + } + gc_list_init(from); +} + +static Py_ssize_t +gc_list_size(PyGC_Head *list) +{ + PyGC_Head *gc; + Py_ssize_t n = 0; + for (gc = list->gc.gc_next; gc != list; gc = gc->gc.gc_next) { + n++; + } + return n; +} + +/* Append objects in a GC list to a Python list. + * Return 0 if all OK, < 0 if error (out of memory for list). + */ +static int +append_objects(PyObject *py_list, PyGC_Head *gc_list) +{ + PyGC_Head *gc; + for (gc = gc_list->gc.gc_next; gc != gc_list; gc = gc->gc.gc_next) { + PyObject *op = FROM_GC(gc); + if (op != py_list) { + if (PyList_Append(py_list, op)) { + return -1; /* exception */ + } + } + } + return 0; +} + +/*** end of list stuff ***/ + + +/* Set all gc_refs = ob_refcnt. After this, gc_refs is > 0 for all objects + * in containers, and is GC_REACHABLE for all tracked gc objects not in + * containers. + */ +static void +update_refs(PyGC_Head *containers) +{ + PyGC_Head *gc = containers->gc.gc_next; + for (; gc != containers; gc = gc->gc.gc_next) { + assert(gc->gc.gc_refs == GC_REACHABLE); + gc->gc.gc_refs = FROM_GC(gc)->ob_refcnt; + /* Python's cyclic gc should never see an incoming refcount + * of 0: if something decref'ed to 0, it should have been + * deallocated immediately at that time. + * Possible cause (if the assert triggers): a tp_dealloc + * routine left a gc-aware object tracked during its teardown + * phase, and did something-- or allowed something to happen -- + * that called back into Python. gc can trigger then, and may + * see the still-tracked dying object. Before this assert + * was added, such mistakes went on to allow gc to try to + * delete the object again. In a debug build, that caused + * a mysterious segfault, when _Py_ForgetReference tried + * to remove the object from the doubly-linked list of all + * objects a second time. In a release build, an actual + * double deallocation occurred, which leads to corruption + * of the allocator's internal bookkeeping pointers. That's + * so serious that maybe this should be a release-build + * check instead of an assert? + */ + assert(gc->gc.gc_refs != 0); + } +} + +/* A traversal callback for subtract_refs. */ +static int +visit_decref(PyObject *op, void *data) +{ + assert(op != NULL); + if (PyObject_IS_GC(op)) { + PyGC_Head *gc = AS_GC(op); + /* We're only interested in gc_refs for objects in the + * generation being collected, which can be recognized + * because only they have positive gc_refs. + */ + assert(gc->gc.gc_refs != 0); /* else refcount was too small */ + if (gc->gc.gc_refs > 0) + gc->gc.gc_refs--; + } + return 0; +} + +/* Subtract internal references from gc_refs. After this, gc_refs is >= 0 + * for all objects in containers, and is GC_REACHABLE for all tracked gc + * objects not in containers. The ones with gc_refs > 0 are directly + * reachable from outside containers, and so can't be collected. + */ +static void +subtract_refs(PyGC_Head *containers) +{ + traverseproc traverse; + PyGC_Head *gc = containers->gc.gc_next; + for (; gc != containers; gc=gc->gc.gc_next) { + traverse = FROM_GC(gc)->ob_type->tp_traverse; + (void) traverse(FROM_GC(gc), + (visitproc)visit_decref, + NULL); + } +} + +/* A traversal callback for move_unreachable. */ +static int +visit_reachable(PyObject *op, PyGC_Head *reachable) +{ + if (PyObject_IS_GC(op)) { + PyGC_Head *gc = AS_GC(op); + const Py_ssize_t gc_refs = gc->gc.gc_refs; + + if (gc_refs == 0) { + /* This is in move_unreachable's 'young' list, but + * the traversal hasn't yet gotten to it. All + * we need to do is tell move_unreachable that it's + * reachable. + */ + gc->gc.gc_refs = 1; + } + else if (gc_refs == GC_TENTATIVELY_UNREACHABLE) { + /* This had gc_refs = 0 when move_unreachable got + * to it, but turns out it's reachable after all. + * Move it back to move_unreachable's 'young' list, + * and move_unreachable will eventually get to it + * again. + */ + gc_list_move(gc, reachable); + gc->gc.gc_refs = 1; + } + /* Else there's nothing to do. + * If gc_refs > 0, it must be in move_unreachable's 'young' + * list, and move_unreachable will eventually get to it. + * If gc_refs == GC_REACHABLE, it's either in some other + * generation so we don't care about it, or move_unreachable + * already dealt with it. + * If gc_refs == GC_UNTRACKED, it must be ignored. + */ + else { + assert(gc_refs > 0 + || gc_refs == GC_REACHABLE + || gc_refs == GC_UNTRACKED); + } + } + return 0; +} + +/* Move the unreachable objects from young to unreachable. After this, + * all objects in young have gc_refs = GC_REACHABLE, and all objects in + * unreachable have gc_refs = GC_TENTATIVELY_UNREACHABLE. All tracked + * gc objects not in young or unreachable still have gc_refs = GC_REACHABLE. + * All objects in young after this are directly or indirectly reachable + * from outside the original young; and all objects in unreachable are + * not. + */ +static void +move_unreachable(PyGC_Head *young, PyGC_Head *unreachable) +{ + PyGC_Head *gc = young->gc.gc_next; + + /* Invariants: all objects "to the left" of us in young have gc_refs + * = GC_REACHABLE, and are indeed reachable (directly or indirectly) + * from outside the young list as it was at entry. All other objects + * from the original young "to the left" of us are in unreachable now, + * and have gc_refs = GC_TENTATIVELY_UNREACHABLE. All objects to the + * left of us in 'young' now have been scanned, and no objects here + * or to the right have been scanned yet. + */ + + while (gc != young) { + PyGC_Head *next; + + if (gc->gc.gc_refs) { + /* gc is definitely reachable from outside the + * original 'young'. Mark it as such, and traverse + * its pointers to find any other objects that may + * be directly reachable from it. Note that the + * call to tp_traverse may append objects to young, + * so we have to wait until it returns to determine + * the next object to visit. + */ + PyObject *op = FROM_GC(gc); + traverseproc traverse = op->ob_type->tp_traverse; + assert(gc->gc.gc_refs > 0); + gc->gc.gc_refs = GC_REACHABLE; + (void) traverse(op, + (visitproc)visit_reachable, + (void *)young); + next = gc->gc.gc_next; + } + else { + /* This *may* be unreachable. To make progress, + * assume it is. gc isn't directly reachable from + * any object we've already traversed, but may be + * reachable from an object we haven't gotten to yet. + * visit_reachable will eventually move gc back into + * young if that's so, and we'll see it again. + */ + next = gc->gc.gc_next; + gc_list_move(gc, unreachable); + gc->gc.gc_refs = GC_TENTATIVELY_UNREACHABLE; + } + gc = next; + } +} + +/* Return true if object has a finalization method. + * CAUTION: An instance of an old-style class has to be checked for a + *__del__ method, and earlier versions of this used to call PyObject_HasAttr, + * which in turn could call the class's __getattr__ hook (if any). That + * could invoke arbitrary Python code, mutating the object graph in arbitrary + * ways, and that was the source of some excruciatingly subtle bugs. + */ +static int +has_finalizer(PyObject *op) +{ + if (PyInstance_Check(op)) { + assert(delstr != NULL); + return _PyInstance_Lookup(op, delstr) != NULL; + } + else if (PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE)) + return op->ob_type->tp_del != NULL; + else if (PyGen_CheckExact(op)) + return PyGen_NeedsFinalizing((PyGenObject *)op); + else + return 0; +} + +/* Move the objects in unreachable with __del__ methods into `finalizers`. + * Objects moved into `finalizers` have gc_refs set to GC_REACHABLE; the + * objects remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE. + */ +static void +move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) +{ + PyGC_Head *gc; + PyGC_Head *next; + + /* March over unreachable. Move objects with finalizers into + * `finalizers`. + */ + for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { + PyObject *op = FROM_GC(gc); + + assert(IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; + + if (has_finalizer(op)) { + gc_list_move(gc, finalizers); + gc->gc.gc_refs = GC_REACHABLE; + } + } +} + +/* A traversal callback for move_finalizer_reachable. */ +static int +visit_move(PyObject *op, PyGC_Head *tolist) +{ + if (PyObject_IS_GC(op)) { + if (IS_TENTATIVELY_UNREACHABLE(op)) { + PyGC_Head *gc = AS_GC(op); + gc_list_move(gc, tolist); + gc->gc.gc_refs = GC_REACHABLE; + } + } + return 0; +} + +/* Move objects that are reachable from finalizers, from the unreachable set + * into finalizers set. + */ +static void +move_finalizer_reachable(PyGC_Head *finalizers) +{ + traverseproc traverse; + PyGC_Head *gc = finalizers->gc.gc_next; + for (; gc != finalizers; gc = gc->gc.gc_next) { + /* Note that the finalizers list may grow during this. */ + traverse = FROM_GC(gc)->ob_type->tp_traverse; + (void) traverse(FROM_GC(gc), + (visitproc)visit_move, + (void *)finalizers); + } +} + +/* Clear all weakrefs to unreachable objects, and if such a weakref has a + * callback, invoke it if necessary. Note that it's possible for such + * weakrefs to be outside the unreachable set -- indeed, those are precisely + * the weakrefs whose callbacks must be invoked. See gc_weakref.txt for + * overview & some details. Some weakrefs with callbacks may be reclaimed + * directly by this routine; the number reclaimed is the return value. Other + * weakrefs with callbacks may be moved into the `old` generation. Objects + * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in + * unreachable are left at GC_TENTATIVELY_UNREACHABLE. When this returns, + * no object in `unreachable` is weakly referenced anymore. + */ +static int +handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) +{ + PyGC_Head *gc; + PyObject *op; /* generally FROM_GC(gc) */ + PyWeakReference *wr; /* generally a cast of op */ + PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ + PyGC_Head *next; + int num_freed = 0; + + gc_list_init(&wrcb_to_call); + + /* Clear all weakrefs to the objects in unreachable. If such a weakref + * also has a callback, move it into `wrcb_to_call` if the callback + * needs to be invoked. Note that we cannot invoke any callbacks until + * all weakrefs to unreachable objects are cleared, lest the callback + * resurrect an unreachable object via a still-active weakref. We + * make another pass over wrcb_to_call, invoking callbacks, after this + * pass completes. + */ + for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { + PyWeakReference **wrlist; + + op = FROM_GC(gc); + assert(IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; + + if (! PyType_SUPPORTS_WEAKREFS(op->ob_type)) + continue; + + /* It supports weakrefs. Does it have any? */ + wrlist = (PyWeakReference **) + PyObject_GET_WEAKREFS_LISTPTR(op); + + /* `op` may have some weakrefs. March over the list, clear + * all the weakrefs, and move the weakrefs with callbacks + * that must be called into wrcb_to_call. + */ + for (wr = *wrlist; wr != NULL; wr = *wrlist) { + PyGC_Head *wrasgc; /* AS_GC(wr) */ + + /* _PyWeakref_ClearRef clears the weakref but leaves + * the callback pointer intact. Obscure: it also + * changes *wrlist. + */ + assert(wr->wr_object == op); + _PyWeakref_ClearRef(wr); + assert(wr->wr_object == Py_None); + if (wr->wr_callback == NULL) + continue; /* no callback */ + + /* Headache time. `op` is going away, and is weakly referenced by + * `wr`, which has a callback. Should the callback be invoked? If wr + * is also trash, no: + * + * 1. There's no need to call it. The object and the weakref are + * both going away, so it's legitimate to pretend the weakref is + * going away first. The user has to ensure a weakref outlives its + * referent if they want a guarantee that the wr callback will get + * invoked. + * + * 2. It may be catastrophic to call it. If the callback is also in + * cyclic trash (CT), then although the CT is unreachable from + * outside the current generation, CT may be reachable from the + * callback. Then the callback could resurrect insane objects. + * + * Since the callback is never needed and may be unsafe in this case, + * wr is simply left in the unreachable set. Note that because we + * already called _PyWeakref_ClearRef(wr), its callback will never + * trigger. + * + * OTOH, if wr isn't part of CT, we should invoke the callback: the + * weakref outlived the trash. Note that since wr isn't CT in this + * case, its callback can't be CT either -- wr acted as an external + * root to this generation, and therefore its callback did too. So + * nothing in CT is reachable from the callback either, so it's hard + * to imagine how calling it later could create a problem for us. wr + * is moved to wrcb_to_call in this case. + */ + if (IS_TENTATIVELY_UNREACHABLE(wr)) + continue; + assert(IS_REACHABLE(wr)); + + /* Create a new reference so that wr can't go away + * before we can process it again. + */ + Py_INCREF(wr); + + /* Move wr to wrcb_to_call, for the next pass. */ + wrasgc = AS_GC(wr); + assert(wrasgc != next); /* wrasgc is reachable, but + next isn't, so they can't + be the same */ + gc_list_move(wrasgc, &wrcb_to_call); + } + } + + /* Invoke the callbacks we decided to honor. It's safe to invoke them + * because they can't reference unreachable objects. + */ + while (! gc_list_is_empty(&wrcb_to_call)) { + PyObject *temp; + PyObject *callback; + + gc = wrcb_to_call.gc.gc_next; + op = FROM_GC(gc); + assert(IS_REACHABLE(op)); + assert(PyWeakref_Check(op)); + wr = (PyWeakReference *)op; + callback = wr->wr_callback; + assert(callback != NULL); + + /* copy-paste of weakrefobject.c's handle_callback() */ + temp = PyObject_CallFunctionObjArgs(callback, wr, NULL); + if (temp == NULL) + PyErr_WriteUnraisable(callback); + else + Py_DECREF(temp); + + /* Give up the reference we created in the first pass. When + * op's refcount hits 0 (which it may or may not do right now), + * op's tp_dealloc will decref op->wr_callback too. Note + * that the refcount probably will hit 0 now, and because this + * weakref was reachable to begin with, gc didn't already + * add it to its count of freed objects. Example: a reachable + * weak value dict maps some key to this reachable weakref. + * The callback removes this key->weakref mapping from the + * dict, leaving no other references to the weakref (excepting + * ours). + */ + Py_DECREF(op); + if (wrcb_to_call.gc.gc_next == gc) { + /* object is still alive -- move it */ + gc_list_move(gc, old); + } + else + ++num_freed; + } + + return num_freed; +} + +static void +debug_instance(char *msg, PyInstanceObject *inst) +{ + char *cname; + /* simple version of instance_repr */ + PyObject *classname = inst->in_class->cl_name; + if (classname != NULL && PyString_Check(classname)) + cname = PyString_AsString(classname); + else + cname = "?"; + PySys_WriteStderr("gc: %.100s <%.100s instance at %p>\n", + msg, cname, inst); +} + +static void +debug_cycle(char *msg, PyObject *op) +{ + if ((debug & DEBUG_INSTANCES) && PyInstance_Check(op)) { + debug_instance(msg, (PyInstanceObject *)op); + } + else if (debug & DEBUG_OBJECTS) { + PySys_WriteStderr("gc: %.100s <%.100s %p>\n", + msg, op->ob_type->tp_name, op); + } +} + +/* Handle uncollectable garbage (cycles with finalizers, and stuff reachable + * only from such cycles). + * If DEBUG_SAVEALL, all objects in finalizers are appended to the module + * garbage list (a Python list), else only the objects in finalizers with + * __del__ methods are appended to garbage. All objects in finalizers are + * merged into the old list regardless. + * Returns 0 if all OK, <0 on error (out of memory to grow the garbage list). + * The finalizers list is made empty on a successful return. + */ +static int +handle_finalizers(PyGC_Head *finalizers, PyGC_Head *old) +{ + PyGC_Head *gc = finalizers->gc.gc_next; + + if (garbage == NULL) { + garbage = PyList_New(0); + if (garbage == NULL) + Py_FatalError("gc couldn't create gc.garbage list"); + } + for (; gc != finalizers; gc = gc->gc.gc_next) { + PyObject *op = FROM_GC(gc); + + if ((debug & DEBUG_SAVEALL) || has_finalizer(op)) { + if (PyList_Append(garbage, op) < 0) + return -1; + } + } + + gc_list_merge(finalizers, old); + return 0; +} + +/* Break reference cycles by clearing the containers involved. This is + * tricky business as the lists can be changing and we don't know which + * objects may be freed. It is possible I screwed something up here. + */ +static void +delete_garbage(PyGC_Head *collectable, PyGC_Head *old) +{ + inquiry clear; + + while (!gc_list_is_empty(collectable)) { + PyGC_Head *gc = collectable->gc.gc_next; + PyObject *op = FROM_GC(gc); + + assert(IS_TENTATIVELY_UNREACHABLE(op)); + if (debug & DEBUG_SAVEALL) { + PyList_Append(garbage, op); + } + else { + if ((clear = op->ob_type->tp_clear) != NULL) { + Py_INCREF(op); + clear(op); + Py_DECREF(op); + } + } + if (collectable->gc.gc_next == gc) { + /* object is still alive, move it, it may die later */ + gc_list_move(gc, old); + gc->gc.gc_refs = GC_REACHABLE; + } + } +} + +/* This is the main function. Read this to understand how the + * collection process works. */ +static Py_ssize_t +collect(int generation) +{ + int i; + Py_ssize_t m = 0; /* # objects collected */ + Py_ssize_t n = 0; /* # unreachable objects that couldn't be collected */ + PyGC_Head *young; /* the generation we are examining */ + PyGC_Head *old; /* next older generation */ + PyGC_Head unreachable; /* non-problematic unreachable trash */ + PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ + PyGC_Head *gc; + double t1 = 0.0; + + if (delstr == NULL) { + delstr = PyString_InternFromString("__del__"); + if (delstr == NULL) + Py_FatalError("gc couldn't allocate \"__del__\""); + } + + if (debug & DEBUG_STATS) { + if (tmod != NULL) { + PyObject *f = PyObject_CallMethod(tmod, "time", NULL); + if (f == NULL) { + PyErr_Clear(); + } + else { + t1 = PyFloat_AsDouble(f); + Py_DECREF(f); + } + } + PySys_WriteStderr("gc: collecting generation %d...\n", + generation); + PySys_WriteStderr("gc: objects in each generation:"); + for (i = 0; i < NUM_GENERATIONS; i++) + PySys_WriteStderr(" %" PY_FORMAT_SIZE_T "d", + gc_list_size(GEN_HEAD(i))); + PySys_WriteStderr("\n"); + } + + /* update collection and allocation counters */ + if (generation+1 < NUM_GENERATIONS) + generations[generation+1].count += 1; + for (i = 0; i <= generation; i++) + generations[i].count = 0; + + /* merge younger generations with one we are currently collecting */ + for (i = 0; i < generation; i++) { + gc_list_merge(GEN_HEAD(i), GEN_HEAD(generation)); + } + + /* handy references */ + young = GEN_HEAD(generation); + if (generation < NUM_GENERATIONS-1) + old = GEN_HEAD(generation+1); + else + old = young; + + /* Using ob_refcnt and gc_refs, calculate which objects in the + * container set are reachable from outside the set (i.e., have a + * refcount greater than 0 when all the references within the + * set are taken into account). + */ + update_refs(young); + subtract_refs(young); + + /* Leave everything reachable from outside young in young, and move + * everything else (in young) to unreachable. + * NOTE: This used to move the reachable objects into a reachable + * set instead. But most things usually turn out to be reachable, + * so it's more efficient to move the unreachable things. + */ + gc_list_init(&unreachable); + move_unreachable(young, &unreachable); + + /* Move reachable objects to next generation. */ + if (young != old) + gc_list_merge(young, old); + + /* All objects in unreachable are trash, but objects reachable from + * finalizers can't safely be deleted. Python programmers should take + * care not to create such things. For Python, finalizers means + * instance objects with __del__ methods. Weakrefs with callbacks + * can also call arbitrary Python code but they will be dealt with by + * handle_weakrefs(). + */ + gc_list_init(&finalizers); + move_finalizers(&unreachable, &finalizers); + /* finalizers contains the unreachable objects with a finalizer; + * unreachable objects reachable *from* those are also uncollectable, + * and we move those into the finalizers list too. + */ + move_finalizer_reachable(&finalizers); + + /* Collect statistics on collectable objects found and print + * debugging information. + */ + for (gc = unreachable.gc.gc_next; gc != &unreachable; + gc = gc->gc.gc_next) { + m++; + if (debug & DEBUG_COLLECTABLE) { + debug_cycle("collectable", FROM_GC(gc)); + } + if (tmod != NULL && (debug & DEBUG_STATS)) { + PyObject *f = PyObject_CallMethod(tmod, "time", NULL); + if (f == NULL) { + PyErr_Clear(); + } + else { + t1 = PyFloat_AsDouble(f)-t1; + Py_DECREF(f); + PySys_WriteStderr("gc: %.4fs elapsed.\n", t1); + } + } + } + + /* Clear weakrefs and invoke callbacks as necessary. */ + m += handle_weakrefs(&unreachable, old); + + /* Call tp_clear on objects in the unreachable set. This will cause + * the reference cycles to be broken. It may also cause some objects + * in finalizers to be freed. + */ + delete_garbage(&unreachable, old); + + /* Collect statistics on uncollectable objects found and print + * debugging information. */ + for (gc = finalizers.gc.gc_next; + gc != &finalizers; + gc = gc->gc.gc_next) { + n++; + if (debug & DEBUG_UNCOLLECTABLE) + debug_cycle("uncollectable", FROM_GC(gc)); + } + if (debug & DEBUG_STATS) { + if (m == 0 && n == 0) + PySys_WriteStderr("gc: done.\n"); + else + PySys_WriteStderr( + "gc: done, " + "%" PY_FORMAT_SIZE_T "d unreachable, " + "%" PY_FORMAT_SIZE_T "d uncollectable.\n", + n+m, n); + } + + /* Append instances in the uncollectable set to a Python + * reachable list of garbage. The programmer has to deal with + * this if they insist on creating this type of structure. + */ + (void)handle_finalizers(&finalizers, old); + + if (PyErr_Occurred()) { + if (gc_str == NULL) + gc_str = PyString_FromString("garbage collection"); + PyErr_WriteUnraisable(gc_str); + Py_FatalError("unexpected exception during garbage collection"); + } + return n+m; +} + +static Py_ssize_t +collect_generations(void) +{ + int i; + Py_ssize_t n = 0; + + /* Find the oldest generation (higest numbered) where the count + * exceeds the threshold. Objects in the that generation and + * generations younger than it will be collected. */ + for (i = NUM_GENERATIONS-1; i >= 0; i--) { + if (generations[i].count > generations[i].threshold) { + n = collect(i); + break; + } + } + return n; +} + +PyDoc_STRVAR(gc_enable__doc__, +"enable() -> None\n" +"\n" +"Enable automatic garbage collection.\n"); + +static PyObject * +gc_enable(PyObject *self, PyObject *noargs) +{ + enabled = 1; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(gc_disable__doc__, +"disable() -> None\n" +"\n" +"Disable automatic garbage collection.\n"); + +static PyObject * +gc_disable(PyObject *self, PyObject *noargs) +{ + enabled = 0; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(gc_isenabled__doc__, +"isenabled() -> status\n" +"\n" +"Returns true if automatic garbage collection is enabled.\n"); + +static PyObject * +gc_isenabled(PyObject *self, PyObject *noargs) +{ + return PyBool_FromLong((long)enabled); +} + +PyDoc_STRVAR(gc_collect__doc__, +"collect([generation]) -> n\n" +"\n" +"With no arguments, run a full collection. The optional argument\n" +"may be an integer specifying which generation to collect. A ValueError\n" +"is raised if the generation number is invalid.\n\n" +"The number of unreachable objects is returned.\n"); + +static PyObject * +gc_collect(PyObject *self, PyObject *args, PyObject *kws) +{ + static char *keywords[] = {"generation", NULL}; + int genarg = NUM_GENERATIONS - 1; + Py_ssize_t n; + + if (!PyArg_ParseTupleAndKeywords(args, kws, "|i", keywords, &genarg)) + return NULL; + + else if (genarg < 0 || genarg >= NUM_GENERATIONS) { + PyErr_SetString(PyExc_ValueError, "invalid generation"); + return NULL; + } + + if (collecting) + n = 0; /* already collecting, don't do anything */ + else { + collecting = 1; + n = collect(genarg); + collecting = 0; + } + + return PyInt_FromSsize_t(n); +} + +PyDoc_STRVAR(gc_set_debug__doc__, +"set_debug(flags) -> None\n" +"\n" +"Set the garbage collection debugging flags. Debugging information is\n" +"written to sys.stderr.\n" +"\n" +"flags is an integer and can have the following bits turned on:\n" +"\n" +" DEBUG_STATS - Print statistics during collection.\n" +" DEBUG_COLLECTABLE - Print collectable objects found.\n" +" DEBUG_UNCOLLECTABLE - Print unreachable but uncollectable objects found.\n" +" DEBUG_INSTANCES - Print instance objects.\n" +" DEBUG_OBJECTS - Print objects other than instances.\n" +" DEBUG_SAVEALL - Save objects to gc.garbage rather than freeing them.\n" +" DEBUG_LEAK - Debug leaking programs (everything but STATS).\n"); + +static PyObject * +gc_set_debug(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "i:set_debug", &debug)) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(gc_get_debug__doc__, +"get_debug() -> flags\n" +"\n" +"Get the garbage collection debugging flags.\n"); + +static PyObject * +gc_get_debug(PyObject *self, PyObject *noargs) +{ + return Py_BuildValue("i", debug); +} + +PyDoc_STRVAR(gc_set_thresh__doc__, +"set_threshold(threshold0, [threshold1, threshold2]) -> None\n" +"\n" +"Sets the collection thresholds. Setting threshold0 to zero disables\n" +"collection.\n"); + +static PyObject * +gc_set_thresh(PyObject *self, PyObject *args) +{ + int i; + if (!PyArg_ParseTuple(args, "i|ii:set_threshold", + &generations[0].threshold, + &generations[1].threshold, + &generations[2].threshold)) + return NULL; + for (i = 2; i < NUM_GENERATIONS; i++) { + /* generations higher than 2 get the same threshold */ + generations[i].threshold = generations[2].threshold; + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(gc_get_thresh__doc__, +"get_threshold() -> (threshold0, threshold1, threshold2)\n" +"\n" +"Return the current collection thresholds\n"); + +static PyObject * +gc_get_thresh(PyObject *self, PyObject *noargs) +{ + return Py_BuildValue("(iii)", + generations[0].threshold, + generations[1].threshold, + generations[2].threshold); +} + +PyDoc_STRVAR(gc_get_count__doc__, +"get_count() -> (count0, count1, count2)\n" +"\n" +"Return the current collection counts\n"); + +static PyObject * +gc_get_count(PyObject *self, PyObject *noargs) +{ + return Py_BuildValue("(iii)", + generations[0].count, + generations[1].count, + generations[2].count); +} + +static int +referrersvisit(PyObject* obj, PyObject *objs) +{ + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(objs); i++) + if (PyTuple_GET_ITEM(objs, i) == obj) + return 1; + return 0; +} + +static int +gc_referrers_for(PyObject *objs, PyGC_Head *list, PyObject *resultlist) +{ + PyGC_Head *gc; + PyObject *obj; + traverseproc traverse; + for (gc = list->gc.gc_next; gc != list; gc = gc->gc.gc_next) { + obj = FROM_GC(gc); + traverse = obj->ob_type->tp_traverse; + if (obj == objs || obj == resultlist) + continue; + if (traverse(obj, (visitproc)referrersvisit, objs)) { + if (PyList_Append(resultlist, obj) < 0) + return 0; /* error */ + } + } + return 1; /* no error */ +} + +PyDoc_STRVAR(gc_get_referrers__doc__, +"get_referrers(*objs) -> list\n\ +Return the list of objects that directly refer to any of objs."); + +static PyObject * +gc_get_referrers(PyObject *self, PyObject *args) +{ + int i; + PyObject *result = PyList_New(0); + if (!result) return NULL; + + for (i = 0; i < NUM_GENERATIONS; i++) { + if (!(gc_referrers_for(args, GEN_HEAD(i), result))) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + +/* Append obj to list; return true if error (out of memory), false if OK. */ +static int +referentsvisit(PyObject *obj, PyObject *list) +{ + return PyList_Append(list, obj) < 0; +} + +PyDoc_STRVAR(gc_get_referents__doc__, +"get_referents(*objs) -> list\n\ +Return the list of objects that are directly referred to by objs."); + +static PyObject * +gc_get_referents(PyObject *self, PyObject *args) +{ + Py_ssize_t i; + PyObject *result = PyList_New(0); + + if (result == NULL) + return NULL; + + for (i = 0; i < PyTuple_GET_SIZE(args); i++) { + traverseproc traverse; + PyObject *obj = PyTuple_GET_ITEM(args, i); + + if (! PyObject_IS_GC(obj)) + continue; + traverse = obj->ob_type->tp_traverse; + if (! traverse) + continue; + if (traverse(obj, (visitproc)referentsvisit, result)) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + +PyDoc_STRVAR(gc_get_objects__doc__, +"get_objects() -> [...]\n" +"\n" +"Return a list of objects tracked by the collector (excluding the list\n" +"returned).\n"); + +static PyObject * +gc_get_objects(PyObject *self, PyObject *noargs) +{ + int i; + PyObject* result; + + result = PyList_New(0); + if (result == NULL) + return NULL; + for (i = 0; i < NUM_GENERATIONS; i++) { + if (append_objects(result, GEN_HEAD(i))) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + + +PyDoc_STRVAR(gc__doc__, +"This module provides access to the garbage collector for reference cycles.\n" +"\n" +"enable() -- Enable automatic garbage collection.\n" +"disable() -- Disable automatic garbage collection.\n" +"isenabled() -- Returns true if automatic collection is enabled.\n" +"collect() -- Do a full collection right now.\n" +"get_count() -- Return the current collection counts.\n" +"set_debug() -- Set debugging flags.\n" +"get_debug() -- Get debugging flags.\n" +"set_threshold() -- Set the collection thresholds.\n" +"get_threshold() -- Return the current the collection thresholds.\n" +"get_objects() -- Return a list of all objects tracked by the collector.\n" +"get_referrers() -- Return the list of objects that refer to an object.\n" +"get_referents() -- Return the list of objects that an object refers to.\n"); + +static PyMethodDef GcMethods[] = { + {"enable", gc_enable, METH_NOARGS, gc_enable__doc__}, + {"disable", gc_disable, METH_NOARGS, gc_disable__doc__}, + {"isenabled", gc_isenabled, METH_NOARGS, gc_isenabled__doc__}, + {"set_debug", gc_set_debug, METH_VARARGS, gc_set_debug__doc__}, + {"get_debug", gc_get_debug, METH_NOARGS, gc_get_debug__doc__}, + {"get_count", gc_get_count, METH_NOARGS, gc_get_count__doc__}, + {"set_threshold", gc_set_thresh, METH_VARARGS, gc_set_thresh__doc__}, + {"get_threshold", gc_get_thresh, METH_NOARGS, gc_get_thresh__doc__}, + {"collect", (PyCFunction)gc_collect, + METH_VARARGS | METH_KEYWORDS, gc_collect__doc__}, + {"get_objects", gc_get_objects,METH_NOARGS, gc_get_objects__doc__}, + {"get_referrers", gc_get_referrers, METH_VARARGS, + gc_get_referrers__doc__}, + {"get_referents", gc_get_referents, METH_VARARGS, + gc_get_referents__doc__}, + {NULL, NULL} /* Sentinel */ +}; + +PyMODINIT_FUNC +initgc(void) +{ + PyObject *m; + + m = Py_InitModule4("gc", + GcMethods, + gc__doc__, + NULL, + PYTHON_API_VERSION); + if (m == NULL) + return; + + if (garbage == NULL) { + garbage = PyList_New(0); + if (garbage == NULL) + return; + } + Py_INCREF(garbage); + if (PyModule_AddObject(m, "garbage", garbage) < 0) + return; + + /* Importing can't be done in collect() because collect() + * can be called via PyGC_Collect() in Py_Finalize(). + * This wouldn't be a problem, except that <initialized> is + * reset to 0 before calling collect which trips up + * the import and triggers an assertion. + */ + if (tmod == NULL) { + tmod = PyImport_ImportModule("time"); + if (tmod == NULL) + PyErr_Clear(); + } + +#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return + ADD_INT(DEBUG_STATS); + ADD_INT(DEBUG_COLLECTABLE); + ADD_INT(DEBUG_UNCOLLECTABLE); + ADD_INT(DEBUG_INSTANCES); + ADD_INT(DEBUG_OBJECTS); + ADD_INT(DEBUG_SAVEALL); + ADD_INT(DEBUG_LEAK); +#undef ADD_INT +} + +/* API to invoke gc.collect() from C */ +Py_ssize_t +PyGC_Collect(void) +{ + Py_ssize_t n; + + if (collecting) + n = 0; /* already collecting, don't do anything */ + else { + collecting = 1; + n = collect(NUM_GENERATIONS - 1); + collecting = 0; + } + + return n; +} + +/* for debugging */ +void +_PyGC_Dump(PyGC_Head *g) +{ + _PyObject_Dump(FROM_GC(g)); +} + +/* extension modules might be compiled with GC support so these + functions must always be available */ + +#undef PyObject_GC_Track +#undef PyObject_GC_UnTrack +#undef PyObject_GC_Del +#undef _PyObject_GC_Malloc + +void +PyObject_GC_Track(void *op) +{ + _PyObject_GC_TRACK(op); +} + +/* for binary compatibility with 2.2 */ +void +_PyObject_GC_Track(PyObject *op) +{ + PyObject_GC_Track(op); +} + +void +PyObject_GC_UnTrack(void *op) +{ + /* Obscure: the Py_TRASHCAN mechanism requires that we be able to + * call PyObject_GC_UnTrack twice on an object. + */ + if (IS_TRACKED(op)) + _PyObject_GC_UNTRACK(op); +} + +/* for binary compatibility with 2.2 */ +void +_PyObject_GC_UnTrack(PyObject *op) +{ + PyObject_GC_UnTrack(op); +} + +PyObject * +_PyObject_GC_Malloc(size_t basicsize) +{ + PyObject *op; + PyGC_Head *g = (PyGC_Head *)PyObject_MALLOC( + sizeof(PyGC_Head) + basicsize); + if (g == NULL) + return PyErr_NoMemory(); + g->gc.gc_refs = GC_UNTRACKED; + generations[0].count++; /* number of allocated GC objects */ + if (generations[0].count > generations[0].threshold && + enabled && + generations[0].threshold && + !collecting && + !PyErr_Occurred()) { + collecting = 1; + collect_generations(); + collecting = 0; + } + op = FROM_GC(g); + return op; +} + +PyObject * +_PyObject_GC_New(PyTypeObject *tp) +{ + PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp)); + if (op != NULL) + op = PyObject_INIT(op, tp); + return op; +} + +PyVarObject * +_PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems) +{ + const size_t size = _PyObject_VAR_SIZE(tp, nitems); + PyVarObject *op = (PyVarObject *) _PyObject_GC_Malloc(size); + if (op != NULL) + op = PyObject_INIT_VAR(op, tp, nitems); + return op; +} + +PyVarObject * +_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems) +{ + const size_t basicsize = _PyObject_VAR_SIZE(op->ob_type, nitems); + PyGC_Head *g = AS_GC(op); + g = (PyGC_Head *)PyObject_REALLOC(g, sizeof(PyGC_Head) + basicsize); + if (g == NULL) + return (PyVarObject *)PyErr_NoMemory(); + op = (PyVarObject *) FROM_GC(g); + op->ob_size = nitems; + return op; +} + +void +PyObject_GC_Del(void *op) +{ + PyGC_Head *g = AS_GC(op); + if (IS_TRACKED(op)) + gc_list_remove(g); + if (generations[0].count > 0) { + generations[0].count--; + } + PyObject_FREE(g); +} + +/* for binary compatibility with 2.2 */ +#undef _PyObject_GC_Del +void +_PyObject_GC_Del(PyObject *op) +{ + PyObject_GC_Del(op); +} diff --git a/sys/src/cmd/python/Modules/gdbmmodule.c b/sys/src/cmd/python/Modules/gdbmmodule.c new file mode 100644 index 000000000..cfc6abc37 --- /dev/null +++ b/sys/src/cmd/python/Modules/gdbmmodule.c @@ -0,0 +1,515 @@ + +/* DBM module using dictionary interface */ +/* Author: Anthony Baxter, after dbmmodule.c */ +/* Doc strings: Mitch Chapman */ + + +#include "Python.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "gdbm.h" + +#if defined(WIN32) && !defined(__CYGWIN__) +#include "gdbmerrno.h" +extern const char * gdbm_strerror(gdbm_error); +#endif + +PyDoc_STRVAR(gdbmmodule__doc__, +"This module provides an interface to the GNU DBM (GDBM) library.\n\ +\n\ +This module is quite similar to the dbm module, but uses GDBM instead to\n\ +provide some additional functionality. Please note that the file formats\n\ +created by GDBM and dbm are incompatible. \n\ +\n\ +GDBM objects behave like mappings (dictionaries), except that keys and\n\ +values are always strings. Printing a GDBM object doesn't print the\n\ +keys and values, and the items() and values() methods are not\n\ +supported."); + +typedef struct { + PyObject_HEAD + int di_size; /* -1 means recompute */ + GDBM_FILE di_dbm; +} dbmobject; + +static PyTypeObject Dbmtype; + +#define is_dbmobject(v) ((v)->ob_type == &Dbmtype) +#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \ + { PyErr_SetString(DbmError, "GDBM object has already been closed"); \ + return NULL; } + + + +static PyObject *DbmError; + +PyDoc_STRVAR(gdbm_object__doc__, +"This object represents a GDBM database.\n\ +GDBM objects behave like mappings (dictionaries), except that keys and\n\ +values are always strings. Printing a GDBM object doesn't print the\n\ +keys and values, and the items() and values() methods are not\n\ +supported.\n\ +\n\ +GDBM objects also support additional operations such as firstkey,\n\ +nextkey, reorganize, and sync."); + +static PyObject * +newdbmobject(char *file, int flags, int mode) +{ + dbmobject *dp; + + dp = PyObject_New(dbmobject, &Dbmtype); + if (dp == NULL) + return NULL; + dp->di_size = -1; + errno = 0; + if ((dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0) { + if (errno != 0) + PyErr_SetFromErrno(DbmError); + else + PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); + Py_DECREF(dp); + return NULL; + } + return (PyObject *)dp; +} + +/* Methods */ + +static void +dbm_dealloc(register dbmobject *dp) +{ + if (dp->di_dbm) + gdbm_close(dp->di_dbm); + PyObject_Del(dp); +} + +static Py_ssize_t +dbm_length(dbmobject *dp) +{ + if (dp->di_dbm == NULL) { + PyErr_SetString(DbmError, "GDBM object has already been closed"); + return -1; + } + if (dp->di_size < 0) { + datum key,okey; + int size; + okey.dsize=0; + okey.dptr=NULL; + + size = 0; + for (key=gdbm_firstkey(dp->di_dbm); key.dptr; + key = gdbm_nextkey(dp->di_dbm,okey)) { + size++; + if(okey.dsize) free(okey.dptr); + okey=key; + } + dp->di_size = size; + } + return dp->di_size; +} + +static PyObject * +dbm_subscript(dbmobject *dp, register PyObject *key) +{ + PyObject *v; + datum drec, krec; + + if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) ) + return NULL; + + if (dp->di_dbm == NULL) { + PyErr_SetString(DbmError, + "GDBM object has already been closed"); + return NULL; + } + drec = gdbm_fetch(dp->di_dbm, krec); + if (drec.dptr == 0) { + PyErr_SetString(PyExc_KeyError, + PyString_AS_STRING((PyStringObject *)key)); + return NULL; + } + v = PyString_FromStringAndSize(drec.dptr, drec.dsize); + free(drec.dptr); + return v; +} + +static int +dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w) +{ + datum krec, drec; + + if (!PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) { + PyErr_SetString(PyExc_TypeError, + "gdbm mappings have string indices only"); + return -1; + } + if (dp->di_dbm == NULL) { + PyErr_SetString(DbmError, + "GDBM object has already been closed"); + return -1; + } + dp->di_size = -1; + if (w == NULL) { + if (gdbm_delete(dp->di_dbm, krec) < 0) { + PyErr_SetString(PyExc_KeyError, + PyString_AS_STRING((PyStringObject *)v)); + return -1; + } + } + else { + if (!PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize)) { + PyErr_SetString(PyExc_TypeError, + "gdbm mappings have string elements only"); + return -1; + } + errno = 0; + if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) { + if (errno != 0) + PyErr_SetFromErrno(DbmError); + else + PyErr_SetString(DbmError, + gdbm_strerror(gdbm_errno)); + return -1; + } + } + return 0; +} + +static PyMappingMethods dbm_as_mapping = { + (lenfunc)dbm_length, /*mp_length*/ + (binaryfunc)dbm_subscript, /*mp_subscript*/ + (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/ +}; + +PyDoc_STRVAR(dbm_close__doc__, +"close() -> None\n\ +Closes the database."); + +static PyObject * +dbm_close(register dbmobject *dp, PyObject *unused) +{ + if (dp->di_dbm) + gdbm_close(dp->di_dbm); + dp->di_dbm = NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(dbm_keys__doc__, +"keys() -> list_of_keys\n\ +Get a list of all keys in the database."); + +static PyObject * +dbm_keys(register dbmobject *dp, PyObject *unused) +{ + register PyObject *v, *item; + datum key, nextkey; + int err; + + if (dp == NULL || !is_dbmobject(dp)) { + PyErr_BadInternalCall(); + return NULL; + } + check_dbmobject_open(dp); + + v = PyList_New(0); + if (v == NULL) + return NULL; + + key = gdbm_firstkey(dp->di_dbm); + while (key.dptr) { + item = PyString_FromStringAndSize(key.dptr, key.dsize); + if (item == NULL) { + free(key.dptr); + Py_DECREF(v); + return NULL; + } + err = PyList_Append(v, item); + Py_DECREF(item); + if (err != 0) { + free(key.dptr); + Py_DECREF(v); + return NULL; + } + nextkey = gdbm_nextkey(dp->di_dbm, key); + free(key.dptr); + key = nextkey; + } + return v; +} + +PyDoc_STRVAR(dbm_has_key__doc__, +"has_key(key) -> boolean\n\ +Find out whether or not the database contains a given key."); + +static PyObject * +dbm_has_key(register dbmobject *dp, PyObject *args) +{ + datum key; + + if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &key.dsize)) + return NULL; + check_dbmobject_open(dp); + return PyInt_FromLong((long) gdbm_exists(dp->di_dbm, key)); +} + +PyDoc_STRVAR(dbm_firstkey__doc__, +"firstkey() -> key\n\ +It's possible to loop over every key in the database using this method\n\ +and the nextkey() method. The traversal is ordered by GDBM's internal\n\ +hash values, and won't be sorted by the key values. This method\n\ +returns the starting key."); + +static PyObject * +dbm_firstkey(register dbmobject *dp, PyObject *unused) +{ + register PyObject *v; + datum key; + + check_dbmobject_open(dp); + key = gdbm_firstkey(dp->di_dbm); + if (key.dptr) { + v = PyString_FromStringAndSize(key.dptr, key.dsize); + free(key.dptr); + return v; + } + else { + Py_INCREF(Py_None); + return Py_None; + } +} + +PyDoc_STRVAR(dbm_nextkey__doc__, +"nextkey(key) -> next_key\n\ +Returns the key that follows key in the traversal.\n\ +The following code prints every key in the database db, without having\n\ +to create a list in memory that contains them all:\n\ +\n\ + k = db.firstkey()\n\ + while k != None:\n\ + print k\n\ + k = db.nextkey(k)"); + +static PyObject * +dbm_nextkey(register dbmobject *dp, PyObject *args) +{ + register PyObject *v; + datum key, nextkey; + + if (!PyArg_ParseTuple(args, "s#:nextkey", &key.dptr, &key.dsize)) + return NULL; + check_dbmobject_open(dp); + nextkey = gdbm_nextkey(dp->di_dbm, key); + if (nextkey.dptr) { + v = PyString_FromStringAndSize(nextkey.dptr, nextkey.dsize); + free(nextkey.dptr); + return v; + } + else { + Py_INCREF(Py_None); + return Py_None; + } +} + +PyDoc_STRVAR(dbm_reorganize__doc__, +"reorganize() -> None\n\ +If you have carried out a lot of deletions and would like to shrink\n\ +the space used by the GDBM file, this routine will reorganize the\n\ +database. GDBM will not shorten the length of a database file except\n\ +by using this reorganization; otherwise, deleted file space will be\n\ +kept and reused as new (key,value) pairs are added."); + +static PyObject * +dbm_reorganize(register dbmobject *dp, PyObject *unused) +{ + check_dbmobject_open(dp); + errno = 0; + if (gdbm_reorganize(dp->di_dbm) < 0) { + if (errno != 0) + PyErr_SetFromErrno(DbmError); + else + PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(dbm_sync__doc__, +"sync() -> None\n\ +When the database has been opened in fast mode, this method forces\n\ +any unwritten data to be written to the disk."); + +static PyObject * +dbm_sync(register dbmobject *dp, PyObject *unused) +{ + check_dbmobject_open(dp); + gdbm_sync(dp->di_dbm); + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef dbm_methods[] = { + {"close", (PyCFunction)dbm_close, METH_NOARGS, dbm_close__doc__}, + {"keys", (PyCFunction)dbm_keys, METH_NOARGS, dbm_keys__doc__}, + {"has_key", (PyCFunction)dbm_has_key, METH_VARARGS, dbm_has_key__doc__}, + {"firstkey", (PyCFunction)dbm_firstkey,METH_NOARGS, dbm_firstkey__doc__}, + {"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__}, + {"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__}, + {"sync", (PyCFunction)dbm_sync, METH_NOARGS, dbm_sync__doc__}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +dbm_getattr(dbmobject *dp, char *name) +{ + return Py_FindMethod(dbm_methods, (PyObject *)dp, name); +} + +static PyTypeObject Dbmtype = { + PyObject_HEAD_INIT(0) + 0, + "gdbm.gdbm", + sizeof(dbmobject), + 0, + (destructor)dbm_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)dbm_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + &dbm_as_mapping, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + 0, /*tp_xxx4*/ + gdbm_object__doc__, /*tp_doc*/ +}; + +/* ----------------------------------------------------------------- */ + +PyDoc_STRVAR(dbmopen__doc__, +"open(filename, [flags, [mode]]) -> dbm_object\n\ +Open a dbm database and return a dbm object. The filename argument is\n\ +the name of the database file.\n\ +\n\ +The optional flags argument can be 'r' (to open an existing database\n\ +for reading only -- default), 'w' (to open an existing database for\n\ +reading and writing), 'c' (which creates the database if it doesn't\n\ +exist), or 'n' (which always creates a new empty database).\n\ +\n\ +Some versions of gdbm support additional flags which must be\n\ +appended to one of the flags described above. The module constant\n\ +'open_flags' is a string of valid additional flags. The 'f' flag\n\ +opens the database in fast mode; altered data will not automatically\n\ +be written to the disk after every change. This results in faster\n\ +writes to the database, but may result in an inconsistent database\n\ +if the program crashes while the database is still open. Use the\n\ +sync() method to force any unwritten data to be written to the disk.\n\ +The 's' flag causes all database operations to be synchronized to\n\ +disk. The 'u' flag disables locking of the database file.\n\ +\n\ +The optional mode argument is the Unix mode of the file, used only\n\ +when the database has to be created. It defaults to octal 0666. "); + +static PyObject * +dbmopen(PyObject *self, PyObject *args) +{ + char *name; + char *flags = "r"; + int iflags; + int mode = 0666; + + if (!PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode)) + return NULL; + switch (flags[0]) { + case 'r': + iflags = GDBM_READER; + break; + case 'w': + iflags = GDBM_WRITER; + break; + case 'c': + iflags = GDBM_WRCREAT; + break; + case 'n': + iflags = GDBM_NEWDB; + break; + default: + PyErr_SetString(DbmError, + "First flag must be one of 'r', 'w', 'c' or 'n'"); + return NULL; + } + for (flags++; *flags != '\0'; flags++) { + char buf[40]; + switch (*flags) { +#ifdef GDBM_FAST + case 'f': + iflags |= GDBM_FAST; + break; +#endif +#ifdef GDBM_SYNC + case 's': + iflags |= GDBM_SYNC; + break; +#endif +#ifdef GDBM_NOLOCK + case 'u': + iflags |= GDBM_NOLOCK; + break; +#endif + default: + PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.", + *flags); + PyErr_SetString(DbmError, buf); + return NULL; + } + } + + return newdbmobject(name, iflags, mode); +} + +static char dbmmodule_open_flags[] = "rwcn" +#ifdef GDBM_FAST + "f" +#endif +#ifdef GDBM_SYNC + "s" +#endif +#ifdef GDBM_NOLOCK + "u" +#endif + ; + +static PyMethodDef dbmmodule_methods[] = { + { "open", (PyCFunction)dbmopen, METH_VARARGS, dbmopen__doc__}, + { 0, 0 }, +}; + +PyMODINIT_FUNC +initgdbm(void) { + PyObject *m, *d, *s; + + Dbmtype.ob_type = &PyType_Type; + m = Py_InitModule4("gdbm", dbmmodule_methods, + gdbmmodule__doc__, (PyObject *)NULL, + PYTHON_API_VERSION); + if (m == NULL) + return; + d = PyModule_GetDict(m); + DbmError = PyErr_NewException("gdbm.error", NULL, NULL); + if (DbmError != NULL) { + PyDict_SetItemString(d, "error", DbmError); + s = PyString_FromString(dbmmodule_open_flags); + PyDict_SetItemString(d, "open_flags", s); + Py_DECREF(s); + } +} diff --git a/sys/src/cmd/python/Modules/getaddrinfo.c b/sys/src/cmd/python/Modules/getaddrinfo.c new file mode 100644 index 000000000..4d19c3424 --- /dev/null +++ b/sys/src/cmd/python/Modules/getaddrinfo.c @@ -0,0 +1,638 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * GAI_ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR GAI_ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. + * + * Issues to be discussed: + * - Thread safe-ness must be checked. + * - Return values. There are nonstandard return values defined and used + * in the source code. This is because RFC2133 is silent about which error + * code must be returned for which situation. + * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. + */ + +#if 0 +#include <sys/types.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <ctype.h> +#include <unistd.h> + +#include "addrinfo.h" +#endif + +#if defined(__KAME__) && defined(ENABLE_IPV6) +# define FAITH +#endif + +#define SUCCESS 0 +#define GAI_ANY 0 +#define YES 1 +#define NO 0 + +#ifdef FAITH +static int translate = NO; +static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT; +#endif + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in_loopback[] = { 127, 0, 0, 1 }; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +struct sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +static struct gai_afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; +} gai_afdl [] = { +#ifdef ENABLE_IPV6 +#define N_INET6 0 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback}, +#define N_INET 1 +#else +#define N_INET 0 +#endif + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback}, + {0, 0, 0, 0, NULL, NULL}, +}; + +#ifdef ENABLE_IPV6 +#define PTON_MAX 16 +#else +#define PTON_MAX 4 +#endif + +#ifndef IN_MULTICAST +#define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U) +#endif + +#ifndef IN_EXPERIMENTAL +#define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U) +#endif + +#ifndef IN_LOOPBACKNET +#define IN_LOOPBACKNET 127 +#endif + +static int get_name Py_PROTO((const char *, struct gai_afd *, + struct addrinfo **, char *, struct addrinfo *, + int)); +static int get_addr Py_PROTO((const char *, int, struct addrinfo **, + struct addrinfo *, int)); +static int str_isnumber Py_PROTO((const char *)); + +static char *ai_errlist[] = { + "success.", + "address family for hostname not supported.", /* EAI_ADDRFAMILY */ + "temporary failure in name resolution.", /* EAI_AGAIN */ + "invalid value for ai_flags.", /* EAI_BADFLAGS */ + "non-recoverable failure in name resolution.", /* EAI_FAIL */ + "ai_family not supported.", /* EAI_FAMILY */ + "memory allocation failure.", /* EAI_MEMORY */ + "no address associated with hostname.", /* EAI_NODATA */ + "hostname nor servname provided, or not known.",/* EAI_NONAME */ + "servname not supported for ai_socktype.", /* EAI_SERVICE */ + "ai_socktype not supported.", /* EAI_SOCKTYPE */ + "system error returned in errno.", /* EAI_SYSTEM */ + "invalid value for hints.", /* EAI_BADHINTS */ + "resolved protocol is unknown.", /* EAI_PROTOCOL */ + "unknown error.", /* EAI_MAX */ +}; + +#define GET_CANONNAME(ai, str) \ +if (pai->ai_flags & AI_CANONNAME) {\ + if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ + strcpy((ai)->ai_canonname, (str));\ + } else {\ + error = EAI_MEMORY;\ + goto free;\ + }\ +} + +#ifdef HAVE_SOCKADDR_SA_LEN +#define GET_AI(ai, gai_afd, addr, port) {\ + char *p;\ + if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ + ((gai_afd)->a_socklen)))\ + == NULL) goto free;\ + memcpy(ai, pai, sizeof(struct addrinfo));\ + (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ + memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ + (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\ + (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ + ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ + p = (char *)((ai)->ai_addr);\ + memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ +} +#else +#define GET_AI(ai, gai_afd, addr, port) {\ + char *p;\ + if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ + ((gai_afd)->a_socklen)))\ + == NULL) goto free;\ + memcpy(ai, pai, sizeof(struct addrinfo));\ + (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ + memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ + (ai)->ai_addrlen = (gai_afd)->a_socklen;\ + (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ + ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ + p = (char *)((ai)->ai_addr);\ + memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ +} +#endif + +#define ERR(err) { error = (err); goto bad; } + +char * +gai_strerror(int ecode) +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} + +void +freeaddrinfo(struct addrinfo *ai) +{ + struct addrinfo *next; + + do { + next = ai->ai_next; + if (ai->ai_canonname) + free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + free(ai); + } while ((ai = next) != NULL); +} + +static int +str_isnumber(const char *p) +{ + unsigned char *q = (unsigned char *)p; + while (*q) { + if (! isdigit(*q)) + return NO; + q++; + } + return YES; +} + +int +getaddrinfo(const char*hostname, const char*servname, + const struct addrinfo *hints, struct addrinfo **res) +{ + struct addrinfo sentinel; + struct addrinfo *top = NULL; + struct addrinfo *cur; + int i, error = 0; + char pton[PTON_MAX]; + struct addrinfo ai; + struct addrinfo *pai; + u_short port; + +#ifdef FAITH + static int firsttime = 1; + + if (firsttime) { + /* translator hack */ + { + char *q = getenv("GAI"); + if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) + translate = YES; + } + firsttime = 0; + } +#endif + + /* initialize file static vars */ + sentinel.ai_next = NULL; + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = GAI_ANY; + pai->ai_protocol = GAI_ANY; + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + port = GAI_ANY; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: +#ifdef ENABLE_IPV6 + case PF_INET6: +#endif + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + switch (pai->ai_socktype) { + case GAI_ANY: + switch (pai->ai_protocol) { + case GAI_ANY: + break; + case IPPROTO_UDP: + pai->ai_socktype = SOCK_DGRAM; + break; + case IPPROTO_TCP: + pai->ai_socktype = SOCK_STREAM; + break; + default: + pai->ai_socktype = SOCK_RAW; + break; + } + break; + case SOCK_RAW: + break; + case SOCK_DGRAM: + if (pai->ai_protocol != IPPROTO_UDP && + pai->ai_protocol != GAI_ANY) + ERR(EAI_BADHINTS); /*xxx*/ + pai->ai_protocol = IPPROTO_UDP; + break; + case SOCK_STREAM: + if (pai->ai_protocol != IPPROTO_TCP && + pai->ai_protocol != GAI_ANY) + ERR(EAI_BADHINTS); /*xxx*/ + pai->ai_protocol = IPPROTO_TCP; + break; + default: + ERR(EAI_SOCKTYPE); + /* unreachable */ + } + } + + /* + * service port + */ + if (servname) { + if (str_isnumber(servname)) { + if (pai->ai_socktype == GAI_ANY) { + /* caller accept *GAI_ANY* socktype */ + pai->ai_socktype = SOCK_DGRAM; + pai->ai_protocol = IPPROTO_UDP; + } + port = htons((u_short)atoi(servname)); + } else { + struct servent *sp; + char *proto; + + proto = NULL; + switch (pai->ai_socktype) { + case GAI_ANY: + proto = NULL; + break; + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + fprintf(stderr, "panic!\n"); + break; + } + if ((sp = getservbyname(servname, proto)) == NULL) + ERR(EAI_SERVICE); + port = sp->s_port; + if (pai->ai_socktype == GAI_ANY) { + if (strcmp(sp->s_proto, "udp") == 0) { + pai->ai_socktype = SOCK_DGRAM; + pai->ai_protocol = IPPROTO_UDP; + } else if (strcmp(sp->s_proto, "tcp") == 0) { + pai->ai_socktype = SOCK_STREAM; + pai->ai_protocol = IPPROTO_TCP; + } else + ERR(EAI_PROTOCOL); /*xxx*/ + } + } + } + + /* + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ + if (hostname == NULL) { + struct gai_afd *gai_afd; + + for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) { + if (!(pai->ai_family == PF_UNSPEC + || pai->ai_family == gai_afd->a_af)) { + continue; + } + + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "anyaddr"); + */ + } else { + GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback, + port); + /* xxx meaningless? + * GET_CANONNAME(cur->ai_next, "localhost"); + */ + } + cur = cur->ai_next; + } + top = sentinel.ai_next; + if (top) + goto good; + else + ERR(EAI_FAMILY); + } + + /* hostname as numeric name */ + for (i = 0; gai_afdl[i].a_af; i++) { + if (inet_pton(gai_afdl[i].a_af, hostname, pton)) { + u_long v4a; +#ifdef ENABLE_IPV6 + u_char pfx; +#endif + + switch (gai_afdl[i].a_af) { + case AF_INET: + v4a = ((struct in_addr *)pton)->s_addr; + v4a = ntohl(v4a); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + pai->ai_flags &= ~AI_CANONNAME; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + pai->ai_flags &= ~AI_CANONNAME; + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + pfx = ((struct in6_addr *)pton)->s6_addr8[0]; + if (pfx == 0 || pfx == 0xfe || pfx == 0xff) + pai->ai_flags &= ~AI_CANONNAME; + break; +#endif + } + + if (pai->ai_family == gai_afdl[i].a_af || + pai->ai_family == PF_UNSPEC) { + if (! (pai->ai_flags & AI_CANONNAME)) { + GET_AI(top, &gai_afdl[i], pton, port); + goto good; + } + /* + * if AI_CANONNAME and if reverse lookup + * fail, return ai anyway to pacify + * calling application. + * + * XXX getaddrinfo() is a name->address + * translation function, and it looks strange + * that we do addr->name translation here. + */ + get_name(pton, &gai_afdl[i], &top, pton, pai, port); + goto good; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + } + + if (pai->ai_flags & AI_NUMERICHOST) + ERR(EAI_NONAME); + + /* hostname as alphabetical name */ + error = get_addr(hostname, pai->ai_family, &top, pai, port); + if (error == 0) { + if (top) { + good: + *res = top; + return SUCCESS; + } else + error = EAI_FAIL; + } + free: + if (top) + freeaddrinfo(top); + bad: + *res = NULL; + return error; +} + +static int +get_name(addr, gai_afd, res, numaddr, pai, port0) + const char *addr; + struct gai_afd *gai_afd; + struct addrinfo **res; + char *numaddr; + struct addrinfo *pai; + int port0; +{ + u_short port = port0 & 0xffff; + struct hostent *hp; + struct addrinfo *cur; + int error = 0; +#ifdef ENABLE_IPV6 + int h_error; +#endif + +#ifdef ENABLE_IPV6 + hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error); +#else + hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET); +#endif + if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { + GET_AI(cur, gai_afd, hp->h_addr_list[0], port); + GET_CANONNAME(cur, hp->h_name); + } else + GET_AI(cur, gai_afd, numaddr, port); + +#ifdef ENABLE_IPV6 + if (hp) + freehostent(hp); +#endif + *res = cur; + return SUCCESS; + free: + if (cur) + freeaddrinfo(cur); +#ifdef ENABLE_IPV6 + if (hp) + freehostent(hp); +#endif + /* bad: */ + *res = NULL; + return error; +} + +static int +get_addr(hostname, af, res, pai, port0) + const char *hostname; + int af; + struct addrinfo **res; + struct addrinfo *pai; + int port0; +{ + u_short port = port0 & 0xffff; + struct addrinfo sentinel; + struct hostent *hp; + struct addrinfo *top, *cur; + struct gai_afd *gai_afd; + int i, error = 0, h_error; + char *ap; + + top = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; +#ifdef ENABLE_IPV6 + if (af == AF_UNSPEC) { + hp = getipnodebyname(hostname, AF_INET6, + AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); + } else + hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); +#else + hp = gethostbyname(hostname); + h_error = h_errno; +#endif + if (hp == NULL) { + switch (h_error) { + case HOST_NOT_FOUND: + case NO_DATA: + error = EAI_NODATA; + break; + case TRY_AGAIN: + error = EAI_AGAIN; + break; + case NO_RECOVERY: + default: + error = EAI_FAIL; + break; + } + goto free; + } + + if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || + (hp->h_addr_list[0] == NULL)) { + error = EAI_FAIL; + goto free; + } + + for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { + switch (af) { +#ifdef ENABLE_IPV6 + case AF_INET6: + gai_afd = &gai_afdl[N_INET6]; + break; +#endif +#ifndef ENABLE_IPV6 + default: /* AF_UNSPEC */ +#endif + case AF_INET: + gai_afd = &gai_afdl[N_INET]; + break; +#ifdef ENABLE_IPV6 + default: /* AF_UNSPEC */ + if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { + ap += sizeof(struct in6_addr) - + sizeof(struct in_addr); + gai_afd = &gai_afdl[N_INET]; + } else + gai_afd = &gai_afdl[N_INET6]; + break; +#endif + } +#ifdef FAITH + if (translate && gai_afd->a_af == AF_INET) { + struct in6_addr *in6; + + GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port); + in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; + memcpy(&in6->s6_addr32[0], &faith_prefix, + sizeof(struct in6_addr) - sizeof(struct in_addr)); + memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); + } else +#endif /* FAITH */ + GET_AI(cur->ai_next, gai_afd, ap, port); + if (cur == &sentinel) { + top = cur->ai_next; + GET_CANONNAME(top, hp->h_name); + } + cur = cur->ai_next; + } +#ifdef ENABLE_IPV6 + freehostent(hp); +#endif + *res = top; + return SUCCESS; + free: + if (top) + freeaddrinfo(top); +#ifdef ENABLE_IPV6 + if (hp) + freehostent(hp); +#endif +/* bad: */ + *res = NULL; + return error; +} diff --git a/sys/src/cmd/python/Modules/getbuildinfo.c b/sys/src/cmd/python/Modules/getbuildinfo.c new file mode 100644 index 000000000..a017dab06 --- /dev/null +++ b/sys/src/cmd/python/Modules/getbuildinfo.c @@ -0,0 +1,48 @@ +#include "Python.h" + +#ifndef DONT_HAVE_STDIO_H +#include <stdio.h> +#endif + +#ifndef DATE +#ifdef __DATE__ +#define DATE __DATE__ +#else +#define DATE "xx/xx/xx" +#endif +#endif + +#ifndef TIME +#ifdef __TIME__ +#define TIME __TIME__ +#else +#define TIME "xx:xx:xx" +#endif +#endif + +#ifdef SUBWCREV +#define SVNVERSION "$WCRANGE$$WCMODS?M:$" +#endif + +const char * +Py_GetBuildInfo(void) +{ + static char buildinfo[50]; + const char *revision = Py_SubversionRevision(); + const char *sep = *revision ? ":" : ""; + const char *branch = Py_SubversionShortBranch(); + PyOS_snprintf(buildinfo, sizeof(buildinfo), + "%s%s%s, %.20s, %.9s", branch, sep, revision, + DATE, TIME); + return buildinfo; +} + +const char * +_Py_svnversion(void) +{ +#ifdef SVNVERSION + return SVNVERSION; +#else + return "exported"; +#endif +} diff --git a/sys/src/cmd/python/Modules/getnameinfo.c b/sys/src/cmd/python/Modules/getnameinfo.c new file mode 100644 index 000000000..d3c0ac537 --- /dev/null +++ b/sys/src/cmd/python/Modules/getnameinfo.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + * - Return values. There seems to be no standard for return value (RFC2133) + * but INRIA implementation returns EAI_xxx defined for getaddrinfo(). + */ + +#if 0 +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <arpa/nameser.h> +#include <netdb.h> +#include <resolv.h> +#include <string.h> +#include <stddef.h> + +#include "addrinfo.h" +#endif + +#define SUCCESS 0 +#define YES 1 +#define NO 0 + +static struct gni_afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; +} gni_afdl [] = { +#ifdef ENABLE_IPV6 + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#endif + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0}, +}; + +struct gni_sockinet { + u_char si_len; + u_char si_family; + u_short si_port; +}; + +#define ENI_NOSOCKET 0 +#define ENI_NOSERVNAME 1 +#define ENI_NOHOSTNAME 2 +#define ENI_MEMORY 3 +#define ENI_SYSTEM 4 +#define ENI_FAMILY 5 +#define ENI_SALEN 6 + +/* forward declaration to make gcc happy */ +int getnameinfo Py_PROTO((const struct sockaddr *, size_t, char *, size_t, + char *, size_t, int)); + +int +getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) + const struct sockaddr *sa; + size_t salen; + char *host; + size_t hostlen; + char *serv; + size_t servlen; + int flags; +{ + struct gni_afd *gni_afd; + struct servent *sp; + struct hostent *hp; + u_short port; + int family, len, i; + char *addr, *p; + u_long v4a; +#ifdef ENABLE_IPV6 + u_char pfx; +#endif + int h_error; + char numserv[512]; + char numaddr[512]; + + if (sa == NULL) + return ENI_NOSOCKET; + +#ifdef HAVE_SOCKADDR_SA_LEN + len = sa->sa_len; + if (len != salen) return ENI_SALEN; +#else + len = salen; +#endif + + family = sa->sa_family; + for (i = 0; gni_afdl[i].a_af; i++) + if (gni_afdl[i].a_af == family) { + gni_afd = &gni_afdl[i]; + goto found; + } + return ENI_FAMILY; + + found: + if (len != gni_afd->a_socklen) return ENI_SALEN; + + port = ((struct gni_sockinet *)sa)->si_port; /* network byte order */ + addr = (char *)sa + gni_afd->a_off; + + if (serv == NULL || servlen == 0) { + /* what we should do? */ + } else if (flags & NI_NUMERICSERV) { + sprintf(numserv, "%d", ntohs(port)); + if (strlen(numserv) > servlen) + return ENI_MEMORY; + strcpy(serv, numserv); + } else { + sp = getservbyport(port, (flags & NI_DGRAM) ? "udp" : "tcp"); + if (sp) { + if (strlen(sp->s_name) > servlen) + return ENI_MEMORY; + strcpy(serv, sp->s_name); + } else + return ENI_NOSERVNAME; + } + + switch (sa->sa_family) { + case AF_INET: + v4a = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0 || v4a == IN_LOOPBACKNET) + flags |= NI_NUMERICHOST; + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + pfx = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr8[0]; + if (pfx == 0 || pfx == 0xfe || pfx == 0xff) + flags |= NI_NUMERICHOST; + break; +#endif + } + if (host == NULL || hostlen == 0) { + /* what should we do? */ + } else if (flags & NI_NUMERICHOST) { + if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_SYSTEM; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); + } else { +#ifdef ENABLE_IPV6 + hp = getipnodebyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af, &h_error); +#else + hp = gethostbyaddr(addr, gni_afd->a_addrlen, gni_afd->a_af); + h_error = h_errno; +#endif + + if (hp) { + if (flags & NI_NOFQDN) { + p = strchr(hp->h_name, '.'); + if (p) *p = '\0'; + } + if (strlen(hp->h_name) > hostlen) { +#ifdef ENABLE_IPV6 + freehostent(hp); +#endif + return ENI_MEMORY; + } + strcpy(host, hp->h_name); +#ifdef ENABLE_IPV6 + freehostent(hp); +#endif + } else { + if (flags & NI_NAMEREQD) + return ENI_NOHOSTNAME; + if (inet_ntop(gni_afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return ENI_NOHOSTNAME; + if (strlen(numaddr) > hostlen) + return ENI_MEMORY; + strcpy(host, numaddr); + } + } + return SUCCESS; +} diff --git a/sys/src/cmd/python/Modules/getpath.c b/sys/src/cmd/python/Modules/getpath.c new file mode 100644 index 000000000..78bfaf976 --- /dev/null +++ b/sys/src/cmd/python/Modules/getpath.c @@ -0,0 +1,694 @@ +/* Return the initial module search path. */ + +#include "Python.h" +#include "osdefs.h" + +#include <sys/types.h> +#include <string.h> + +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#endif + +/* Search in some common locations for the associated Python libraries. + * + * Two directories must be found, the platform independent directory + * (prefix), containing the common .py and .pyc files, and the platform + * dependent directory (exec_prefix), containing the shared library + * modules. Note that prefix and exec_prefix can be the same directory, + * but for some installations, they are different. + * + * Py_GetPath() carries out separate searches for prefix and exec_prefix. + * Each search tries a number of different locations until a ``landmark'' + * file or directory is found. If no prefix or exec_prefix is found, a + * warning message is issued and the preprocessor defined PREFIX and + * EXEC_PREFIX are used (even though they will not work); python carries on + * as best as is possible, but most imports will fail. + * + * Before any searches are done, the location of the executable is + * determined. If argv[0] has one or more slashs in it, it is used + * unchanged. Otherwise, it must have been invoked from the shell's path, + * so we search $PATH for the named executable and use that. If the + * executable was not found on $PATH (or there was no $PATH environment + * variable), the original argv[0] string is used. + * + * Next, the executable location is examined to see if it is a symbolic + * link. If so, the link is chased (correctly interpreting a relative + * pathname if one is found) and the directory of the link target is used. + * + * Finally, argv0_path is set to the directory containing the executable + * (i.e. the last component is stripped). + * + * With argv0_path in hand, we perform a number of steps. The same steps + * are performed for prefix and for exec_prefix, but with a different + * landmark. + * + * Step 1. Are we running python out of the build directory? This is + * checked by looking for a different kind of landmark relative to + * argv0_path. For prefix, the landmark's path is derived from the VPATH + * preprocessor variable (taking into account that its value is almost, but + * not quite, what we need). For exec_prefix, the landmark is + * Modules/Setup. If the landmark is found, we're done. + * + * For the remaining steps, the prefix landmark will always be + * lib/python$VERSION/os.py and the exec_prefix will always be + * lib/python$VERSION/lib-dynload, where $VERSION is Python's version + * number as supplied by the Makefile. Note that this means that no more + * build directory checking is performed; if the first step did not find + * the landmarks, the assumption is that python is running from an + * installed setup. + * + * Step 2. See if the $PYTHONHOME environment variable points to the + * installed location of the Python libraries. If $PYTHONHOME is set, then + * it points to prefix and exec_prefix. $PYTHONHOME can be a single + * directory, which is used for both, or the prefix and exec_prefix + * directories separated by a colon. + * + * Step 3. Try to find prefix and exec_prefix relative to argv0_path, + * backtracking up the path until it is exhausted. This is the most common + * step to succeed. Note that if prefix and exec_prefix are different, + * exec_prefix is more likely to be found; however if exec_prefix is a + * subdirectory of prefix, both will be found. + * + * Step 4. Search the directories pointed to by the preprocessor variables + * PREFIX and EXEC_PREFIX. These are supplied by the Makefile but can be + * passed in as options to the configure script. + * + * That's it! + * + * Well, almost. Once we have determined prefix and exec_prefix, the + * preprocessor variable PYTHONPATH is used to construct a path. Each + * relative path on PYTHONPATH is prefixed with prefix. Then the directory + * containing the shared library modules is appended. The environment + * variable $PYTHONPATH is inserted in front of it all. Finally, the + * prefix and exec_prefix globals are tweaked so they reflect the values + * expected by other code, by stripping the "lib/python$VERSION/..." stuff + * off. If either points to the build directory, the globals are reset to + * the corresponding preprocessor variables (so sys.prefix will reflect the + * installation location, even though sys.path points into the build + * directory). This seems to make more sense given that currently the only + * known use of sys.prefix and sys.exec_prefix is for the ILU installation + * process to find the installed Python tree. + */ + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifndef VERSION +#define VERSION "2.1" +#endif + +#ifndef VPATH +#define VPATH "." +#endif + +#ifndef PREFIX +# ifdef __VMS +# define PREFIX "" +# else +# define PREFIX "/usr/local" +# endif +#endif + +#ifndef EXEC_PREFIX +#define EXEC_PREFIX PREFIX +#endif + +#ifndef PYTHONPATH +#define PYTHONPATH PREFIX "/lib/python" VERSION ":" \ + EXEC_PREFIX "/lib/python" VERSION "/lib-dynload" +#endif + +#ifndef LANDMARK +#define LANDMARK "os.py" +#endif + +static char prefix[MAXPATHLEN+1]; +static char exec_prefix[MAXPATHLEN+1]; +static char progpath[MAXPATHLEN+1]; +static char *module_search_path = NULL; +static char lib_python[] = "lib/python" VERSION; + +static void +reduce(char *dir) +{ + size_t i = strlen(dir); + while (i > 0 && dir[i] != SEP) + --i; + dir[i] = '\0'; +} + + +static int +isfile(char *filename) /* Is file, not directory */ +{ + struct stat buf; + if (stat(filename, &buf) != 0) + return 0; + if (!S_ISREG(buf.st_mode)) + return 0; + return 1; +} + + +static int +ismodule(char *filename) /* Is module -- check for .pyc/.pyo too */ +{ + if (isfile(filename)) + return 1; + + /* Check for the compiled version of prefix. */ + if (strlen(filename) < MAXPATHLEN) { + strcat(filename, Py_OptimizeFlag ? "o" : "c"); + if (isfile(filename)) + return 1; + } + return 0; +} + + +static int +isxfile(char *filename) /* Is executable file */ +{ + struct stat buf; + if (stat(filename, &buf) != 0) + return 0; + if (!S_ISREG(buf.st_mode)) + return 0; + if ((buf.st_mode & 0111) == 0) + return 0; + return 1; +} + + +static int +isdir(char *filename) /* Is directory */ +{ + struct stat buf; + if (stat(filename, &buf) != 0) + return 0; + if (!S_ISDIR(buf.st_mode)) + return 0; + return 1; +} + + +/* Add a path component, by appending stuff to buffer. + buffer must have at least MAXPATHLEN + 1 bytes allocated, and contain a + NUL-terminated string with no more than MAXPATHLEN characters (not counting + the trailing NUL). It's a fatal error if it contains a string longer than + that (callers must be careful!). If these requirements are met, it's + guaranteed that buffer will still be a NUL-terminated string with no more + than MAXPATHLEN characters at exit. If stuff is too long, only as much of + stuff as fits will be appended. +*/ +static void +joinpath(char *buffer, char *stuff) +{ + size_t n, k; + if (stuff[0] == SEP) + n = 0; + else { + n = strlen(buffer); + if (n > 0 && buffer[n-1] != SEP && n < MAXPATHLEN) + buffer[n++] = SEP; + } + if (n > MAXPATHLEN) + Py_FatalError("buffer overflow in getpath.c's joinpath()"); + k = strlen(stuff); + if (n + k > MAXPATHLEN) + k = MAXPATHLEN - n; + strncpy(buffer+n, stuff, k); + buffer[n+k] = '\0'; +} + +/* copy_absolute requires that path be allocated at least + MAXPATHLEN + 1 bytes and that p be no more than MAXPATHLEN bytes. */ +static void +copy_absolute(char *path, char *p) +{ + if (p[0] == SEP) + strcpy(path, p); + else { + getcwd(path, MAXPATHLEN); + if (p[0] == '.' && p[1] == SEP) + p += 2; + joinpath(path, p); + } +} + +/* absolutize() requires that path be allocated at least MAXPATHLEN+1 bytes. */ +static void +absolutize(char *path) +{ + char buffer[MAXPATHLEN + 1]; + + if (path[0] == SEP) + return; + copy_absolute(buffer, path); + strcpy(path, buffer); +} + +/* search_for_prefix requires that argv0_path be no more than MAXPATHLEN + bytes long. +*/ +static int +search_for_prefix(char *argv0_path, char *home) +{ + size_t n; + char *vpath; + + /* If PYTHONHOME is set, we believe it unconditionally */ + if (home) { + char *delim; + strncpy(prefix, home, MAXPATHLEN); + delim = strchr(prefix, DELIM); + if (delim) + *delim = '\0'; + joinpath(prefix, lib_python); + joinpath(prefix, LANDMARK); + return 1; + } + + /* Check to see if argv[0] is in the build directory */ + strcpy(prefix, argv0_path); + joinpath(prefix, "Modules/Setup"); + if (isfile(prefix)) { + /* Check VPATH to see if argv0_path is in the build directory. */ + vpath = VPATH; + strcpy(prefix, argv0_path); + joinpath(prefix, vpath); + joinpath(prefix, "Lib"); + joinpath(prefix, LANDMARK); + if (ismodule(prefix)) + return -1; + } + + /* Search from argv0_path, until root is found */ + copy_absolute(prefix, argv0_path); + do { + n = strlen(prefix); + joinpath(prefix, lib_python); + joinpath(prefix, LANDMARK); + if (ismodule(prefix)) + return 1; + prefix[n] = '\0'; + reduce(prefix); + } while (prefix[0]); + + /* Look at configure's PREFIX */ + strncpy(prefix, PREFIX, MAXPATHLEN); + joinpath(prefix, lib_python); + joinpath(prefix, LANDMARK); + if (ismodule(prefix)) + return 1; + + /* Fail */ + return 0; +} + + +/* search_for_exec_prefix requires that argv0_path be no more than + MAXPATHLEN bytes long. +*/ +static int +search_for_exec_prefix(char *argv0_path, char *home) +{ + size_t n; + + /* If PYTHONHOME is set, we believe it unconditionally */ + if (home) { + char *delim; + delim = strchr(home, DELIM); + if (delim) + strncpy(exec_prefix, delim+1, MAXPATHLEN); + else + strncpy(exec_prefix, home, MAXPATHLEN); + joinpath(exec_prefix, lib_python); + joinpath(exec_prefix, "lib-dynload"); + return 1; + } + + /* Check to see if argv[0] is in the build directory */ + strcpy(exec_prefix, argv0_path); + joinpath(exec_prefix, "Modules/Setup"); + if (isfile(exec_prefix)) { + reduce(exec_prefix); + return -1; + } + + /* Search from argv0_path, until root is found */ + copy_absolute(exec_prefix, argv0_path); + do { + n = strlen(exec_prefix); + joinpath(exec_prefix, lib_python); + joinpath(exec_prefix, "lib-dynload"); + if (isdir(exec_prefix)) + return 1; + exec_prefix[n] = '\0'; + reduce(exec_prefix); + } while (exec_prefix[0]); + + /* Look at configure's EXEC_PREFIX */ + strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); + joinpath(exec_prefix, lib_python); + joinpath(exec_prefix, "lib-dynload"); + if (isdir(exec_prefix)) + return 1; + + /* Fail */ + return 0; +} + + +static void +calculate_path(void) +{ + extern char *Py_GetProgramName(void); + + static char delimiter[2] = {DELIM, '\0'}; + static char separator[2] = {SEP, '\0'}; + char *pythonpath = PYTHONPATH; + char *rtpypath = Py_GETENV("PYTHONPATH"); + char *home = Py_GetPythonHome(); + char *path = getenv("PATH"); + char *prog = Py_GetProgramName(); + char argv0_path[MAXPATHLEN+1]; + char zip_path[MAXPATHLEN+1]; + int pfound, efound; /* 1 if found; -1 if found build directory */ + char *buf; + size_t bufsz; + size_t prefixsz; + char *defpath = pythonpath; +#ifdef WITH_NEXT_FRAMEWORK + NSModule pythonModule; +#endif +#ifdef __APPLE__ +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 + uint32_t nsexeclength = MAXPATHLEN; +#else + unsigned long nsexeclength = MAXPATHLEN; +#endif +#endif + + /* If there is no slash in the argv0 path, then we have to + * assume python is on the user's $PATH, since there's no + * other way to find a directory to start the search from. If + * $PATH isn't exported, you lose. + */ + if (strchr(prog, SEP)) + strncpy(progpath, prog, MAXPATHLEN); +#ifdef __APPLE__ + /* On Mac OS X, if a script uses an interpreter of the form + * "#!/opt/python2.3/bin/python", the kernel only passes "python" + * as argv[0], which falls through to the $PATH search below. + * If /opt/python2.3/bin isn't in your path, or is near the end, + * this algorithm may incorrectly find /usr/bin/python. To work + * around this, we can use _NSGetExecutablePath to get a better + * hint of what the intended interpreter was, although this + * will fail if a relative path was used. but in that case, + * absolutize() should help us out below + */ + else if(0 == _NSGetExecutablePath(progpath, &nsexeclength) && progpath[0] == SEP) + ; +#endif /* __APPLE__ */ + else if (path) { + while (1) { + char *delim = strchr(path, DELIM); + + if (delim) { + size_t len = delim - path; + if (len > MAXPATHLEN) + len = MAXPATHLEN; + strncpy(progpath, path, len); + *(progpath + len) = '\0'; + } + else + strncpy(progpath, path, MAXPATHLEN); + + joinpath(progpath, prog); + if (isxfile(progpath)) + break; + + if (!delim) { + progpath[0] = '\0'; + break; + } + path = delim + 1; + } + } + else + progpath[0] = '\0'; + if (progpath[0] != SEP) + absolutize(progpath); + strncpy(argv0_path, progpath, MAXPATHLEN); + argv0_path[MAXPATHLEN] = '\0'; + +#ifdef WITH_NEXT_FRAMEWORK + /* On Mac OS X we have a special case if we're running from a framework. + ** This is because the python home should be set relative to the library, + ** which is in the framework, not relative to the executable, which may + ** be outside of the framework. Except when we're in the build directory... + */ + pythonModule = NSModuleForSymbol(NSLookupAndBindSymbol("_Py_Initialize")); + /* Use dylib functions to find out where the framework was loaded from */ + buf = (char *)NSLibraryNameForModule(pythonModule); + if (buf != NULL) { + /* We're in a framework. */ + /* See if we might be in the build directory. The framework in the + ** build directory is incomplete, it only has the .dylib and a few + ** needed symlinks, it doesn't have the Lib directories and such. + ** If we're running with the framework from the build directory we must + ** be running the interpreter in the build directory, so we use the + ** build-directory-specific logic to find Lib and such. + */ + strncpy(argv0_path, buf, MAXPATHLEN); + reduce(argv0_path); + joinpath(argv0_path, lib_python); + joinpath(argv0_path, LANDMARK); + if (!ismodule(argv0_path)) { + /* We are in the build directory so use the name of the + executable - we know that the absolute path is passed */ + strncpy(argv0_path, prog, MAXPATHLEN); + } + else { + /* Use the location of the library as the progpath */ + strncpy(argv0_path, buf, MAXPATHLEN); + } + } +#endif + +#if HAVE_READLINK + { + char tmpbuffer[MAXPATHLEN+1]; + int linklen = readlink(progpath, tmpbuffer, MAXPATHLEN); + while (linklen != -1) { + /* It's not null terminated! */ + tmpbuffer[linklen] = '\0'; + if (tmpbuffer[0] == SEP) + /* tmpbuffer should never be longer than MAXPATHLEN, + but extra check does not hurt */ + strncpy(argv0_path, tmpbuffer, MAXPATHLEN); + else { + /* Interpret relative to progpath */ + reduce(argv0_path); + joinpath(argv0_path, tmpbuffer); + } + linklen = readlink(argv0_path, tmpbuffer, MAXPATHLEN); + } + } +#endif /* HAVE_READLINK */ + + reduce(argv0_path); + /* At this point, argv0_path is guaranteed to be less than + MAXPATHLEN bytes long. + */ + + if (!(pfound = search_for_prefix(argv0_path, home))) { + if (!Py_FrozenFlag) + fprintf(stderr, + "Could not find platform independent libraries <prefix>\n"); + strncpy(prefix, PREFIX, MAXPATHLEN); + joinpath(prefix, lib_python); + } + else + reduce(prefix); + + strncpy(zip_path, prefix, MAXPATHLEN); + zip_path[MAXPATHLEN] = '\0'; + if (pfound > 0) { /* Use the reduced prefix returned by Py_GetPrefix() */ + reduce(zip_path); + reduce(zip_path); + } + else + strncpy(zip_path, PREFIX, MAXPATHLEN); + joinpath(zip_path, "lib/python00.zip"); + bufsz = strlen(zip_path); /* Replace "00" with version */ + zip_path[bufsz - 6] = VERSION[0]; + zip_path[bufsz - 5] = VERSION[2]; + + if (!(efound = search_for_exec_prefix(argv0_path, home))) { + if (!Py_FrozenFlag) + fprintf(stderr, + "Could not find platform dependent libraries <exec_prefix>\n"); + strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); + joinpath(exec_prefix, "lib/lib-dynload"); + } + /* If we found EXEC_PREFIX do *not* reduce it! (Yet.) */ + + if ((!pfound || !efound) && !Py_FrozenFlag) + fprintf(stderr, + "Consider setting $PYTHONHOME to <prefix>[:<exec_prefix>]\n"); + + /* Calculate size of return buffer. + */ + bufsz = 0; + + if (rtpypath) + bufsz += strlen(rtpypath) + 1; + + prefixsz = strlen(prefix) + 1; + + while (1) { + char *delim = strchr(defpath, DELIM); + + if (defpath[0] != SEP) + /* Paths are relative to prefix */ + bufsz += prefixsz; + + if (delim) + bufsz += delim - defpath + 1; + else { + bufsz += strlen(defpath) + 1; + break; + } + defpath = delim + 1; + } + + bufsz += strlen(zip_path) + 1; + bufsz += strlen(exec_prefix) + 1; + + /* This is the only malloc call in this file */ + buf = (char *)PyMem_Malloc(bufsz); + + if (buf == NULL) { + /* We can't exit, so print a warning and limp along */ + fprintf(stderr, "Not enough memory for dynamic PYTHONPATH.\n"); + fprintf(stderr, "Using default static PYTHONPATH.\n"); + module_search_path = PYTHONPATH; + } + else { + /* Run-time value of $PYTHONPATH goes first */ + if (rtpypath) { + strcpy(buf, rtpypath); + strcat(buf, delimiter); + } + else + buf[0] = '\0'; + + /* Next is the default zip path */ + strcat(buf, zip_path); + strcat(buf, delimiter); + + /* Next goes merge of compile-time $PYTHONPATH with + * dynamically located prefix. + */ + defpath = pythonpath; + while (1) { + char *delim = strchr(defpath, DELIM); + + if (defpath[0] != SEP) { + strcat(buf, prefix); + strcat(buf, separator); + } + + if (delim) { + size_t len = delim - defpath + 1; + size_t end = strlen(buf) + len; + strncat(buf, defpath, len); + *(buf + end) = '\0'; + } + else { + strcat(buf, defpath); + break; + } + defpath = delim + 1; + } + strcat(buf, delimiter); + + /* Finally, on goes the directory for dynamic-load modules */ + strcat(buf, exec_prefix); + + /* And publish the results */ + module_search_path = buf; + } + + /* Reduce prefix and exec_prefix to their essence, + * e.g. /usr/local/lib/python1.5 is reduced to /usr/local. + * If we're loading relative to the build directory, + * return the compiled-in defaults instead. + */ + if (pfound > 0) { + reduce(prefix); + reduce(prefix); + /* The prefix is the root directory, but reduce() chopped + * off the "/". */ + if (!prefix[0]) + strcpy(prefix, separator); + } + else + strncpy(prefix, PREFIX, MAXPATHLEN); + + if (efound > 0) { + reduce(exec_prefix); + reduce(exec_prefix); + reduce(exec_prefix); + if (!exec_prefix[0]) + strcpy(exec_prefix, separator); + } + else + strncpy(exec_prefix, EXEC_PREFIX, MAXPATHLEN); +} + + +/* External interface */ + +char * +Py_GetPath(void) +{ + if (!module_search_path) + calculate_path(); + return module_search_path; +} + +char * +Py_GetPrefix(void) +{ + if (!module_search_path) + calculate_path(); + return prefix; +} + +char * +Py_GetExecPrefix(void) +{ + if (!module_search_path) + calculate_path(); + return exec_prefix; +} + +char * +Py_GetProgramFullPath(void) +{ + if (!module_search_path) + calculate_path(); + return progpath; +} + + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Modules/glmodule.c b/sys/src/cmd/python/Modules/glmodule.c new file mode 100644 index 000000000..659070472 --- /dev/null +++ b/sys/src/cmd/python/Modules/glmodule.c @@ -0,0 +1,7628 @@ + +/* +Input used to generate the Python module "glmodule.c". +The stub generator is a Python script called "cgen.py". + +Each definition must be contained on one line: + +<returntype> <name> <type> <arg> <type> <arg> + +<returntype> can be: void, short, long (XXX maybe others?) + +<type> can be: char, string, short, float, long, or double + string indicates a null terminated string; + if <type> is char and <arg> begins with a *, the * is stripped + and <type> is changed into string + +<arg> has the form <mode> or <mode>[<subscript>] + where <mode> can be + s: arg is sent + r: arg is received (arg is a pointer) + and <subscript> can be (N and I are numbers): + N + argI + retval + N*argI + N*I + N*retval + In the case where the subscript consists of two parts + separated by *, the first part is the width of the matrix, and + the second part is the length of the matrix. This order is + opposite from the order used in C to declare a two-dimensional + matrix. +*/ + +/* + * An attempt has been made to make this module switch threads on qread + * calls. It is far from safe, though. + */ + +#include <gl.h> +#include <device.h> + +#ifdef __sgi +extern int devport(); +extern int textwritemask(); +extern int pagewritemask(); +extern int gewrite(); +extern int gettp(); +#endif + +#include "Python.h" +#include "cgensupport.h" + +/* +Some stubs are too complicated for the stub generator. +We can include manually written versions of them here. +A line starting with '%' gives the name of the function so the stub +generator can include it in the table of functions. +*/ + + +static PyObject * +gl_qread(PyObject *self, PyObject *args) +{ + long retval; + short arg1 ; + Py_BEGIN_ALLOW_THREADS + retval = qread( & arg1 ); + Py_END_ALLOW_THREADS + { PyObject *v = PyTuple_New( 2 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewlongobject(retval)); + PyTuple_SetItem(v, 1, mknewshortobject(arg1)); + return v; + } +} + + +/* +varray -- an array of v.. calls. +The argument is an array (maybe list or tuple) of points. +Each point must be a tuple or list of coordinates (x, y, z). +The points may be 2- or 3-dimensional but must all have the +same dimension. Float and int values may be mixed however. +The points are always converted to 3D double precision points +by assuming z=0.0 if necessary (as indicated in the man page), +and for each point v3d() is called. +*/ + + +static PyObject * +gl_varray(PyObject *self, PyObject *args) +{ + PyObject *v, *w=NULL; + int i, n, width; + double vec[3]; + PyObject * (*getitem)(PyObject *, int); + + if (!PyArg_GetObject(args, 1, 0, &v)) + return NULL; + + if (PyList_Check(v)) { + n = PyList_Size(v); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(v)) { + n = PyTuple_Size(v); + getitem = PyTuple_GetItem; + } + else { + PyErr_BadArgument(); + return NULL; + } + + if (n == 0) { + Py_INCREF(Py_None); + return Py_None; + } + if (n > 0) + w = (*getitem)(v, 0); + + width = 0; + if (w == NULL) { + } + else if (PyList_Check(w)) { + width = PyList_Size(w); + } + else if (PyTuple_Check(w)) { + width = PyTuple_Size(w); + } + + switch (width) { + case 2: + vec[2] = 0.0; + /* Fall through */ + case 3: + break; + default: + PyErr_BadArgument(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!PyArg_GetDoubleArray(w, 1, 0, width, vec)) + return NULL; + v3d(vec); + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* +vnarray, nvarray -- an array of n3f and v3f calls. +The argument is an array (list or tuple) of pairs of points and normals. +Each pair is a tuple (NOT a list) of a point and a normal for that point. +Each point or normal must be a tuple (NOT a list) of coordinates (x, y, z). +Three coordinates must be given. Float and int values may be mixed. +For each pair, n3f() is called for the normal, and then v3f() is called +for the vector. + +vnarray and nvarray differ only in the order of the vector and normal in +the pair: vnarray expects (v, n) while nvarray expects (n, v). +*/ + +static PyObject *gen_nvarray(); /* Forward */ + + +static PyObject * +gl_nvarray(PyObject *self, PyObject *args) +{ + return gen_nvarray(args, 0); +} + + +static PyObject * +gl_vnarray(PyObject *self, PyObject *args) +{ + return gen_nvarray(args, 1); +} + +/* Generic, internal version of {nv,nv}array: inorm indicates the + argument order, 0: normal first, 1: vector first. */ + +static PyObject * +gen_nvarray(PyObject *args, int inorm) +{ + PyObject *v, *w, *wnorm, *wvec; + int i, n; + float norm[3], vec[3]; + PyObject * (*getitem)(PyObject *, int); + + if (!PyArg_GetObject(args, 1, 0, &v)) + return NULL; + + if (PyList_Check(v)) { + n = PyList_Size(v); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(v)) { + n = PyTuple_Size(v); + getitem = PyTuple_GetItem; + } + else { + PyErr_BadArgument(); + return NULL; + } + + for (i = 0; i < n; i++) { + w = (*getitem)(v, i); + if (!PyTuple_Check(w) || PyTuple_Size(w) != 2) { + PyErr_BadArgument(); + return NULL; + } + wnorm = PyTuple_GetItem(w, inorm); + wvec = PyTuple_GetItem(w, 1 - inorm); + if (!PyArg_GetFloatArray(wnorm, 1, 0, 3, norm) || + !PyArg_GetFloatArray(wvec, 1, 0, 3, vec)) + return NULL; + n3f(norm); + v3f(vec); + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* nurbssurface(s_knots[], t_knots[], ctl[][], s_order, t_order, type). + The dimensions of ctl[] are computed as follows: + [len(s_knots) - s_order], [len(t_knots) - t_order] +*/ + + +static PyObject * +gl_nurbssurface(PyObject *self, PyObject *args) +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + double *arg5 ; + long arg6 ; + long arg7 ; + long arg8 ; + long ncoords; + long s_byte_stride, t_byte_stride; + long s_nctl, t_nctl; + long s, t; + PyObject *v, *w, *pt; + double *pnext; + if (!PyArg_GetLongArraySize(args, 6, 0, &arg1)) + return NULL; + if ((arg2 = PyMem_NEW(double, arg1 )) == NULL) { + return PyErr_NoMemory(); + } + if (!PyArg_GetDoubleArray(args, 6, 0, arg1 , arg2)) + return NULL; + if (!PyArg_GetLongArraySize(args, 6, 1, &arg3)) + return NULL; + if ((arg4 = PyMem_NEW(double, arg3 )) == NULL) { + return PyErr_NoMemory(); + } + if (!PyArg_GetDoubleArray(args, 6, 1, arg3 , arg4)) + return NULL; + if (!PyArg_GetLong(args, 6, 3, &arg6)) + return NULL; + if (!PyArg_GetLong(args, 6, 4, &arg7)) + return NULL; + if (!PyArg_GetLong(args, 6, 5, &arg8)) + return NULL; + if (arg8 == N_XYZ) + ncoords = 3; + else if (arg8 == N_XYZW) + ncoords = 4; + else { + PyErr_BadArgument(); + return NULL; + } + s_nctl = arg1 - arg6; + t_nctl = arg3 - arg7; + if (!PyArg_GetObject(args, 6, 2, &v)) + return NULL; + if (!PyList_Check(v) || PyList_Size(v) != s_nctl) { + PyErr_BadArgument(); + return NULL; + } + if ((arg5 = PyMem_NEW(double, s_nctl*t_nctl*ncoords )) == NULL) { + return PyErr_NoMemory(); + } + pnext = arg5; + for (s = 0; s < s_nctl; s++) { + w = PyList_GetItem(v, s); + if (w == NULL || !PyList_Check(w) || + PyList_Size(w) != t_nctl) { + PyErr_BadArgument(); + return NULL; + } + for (t = 0; t < t_nctl; t++) { + pt = PyList_GetItem(w, t); + if (!PyArg_GetDoubleArray(pt, 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + } + s_byte_stride = sizeof(double) * ncoords; + t_byte_stride = s_byte_stride * s_nctl; + nurbssurface( arg1 , arg2 , arg3 , arg4 , + s_byte_stride , t_byte_stride , arg5 , arg6 , arg7 , arg8 ); + PyMem_DEL(arg2); + PyMem_DEL(arg4); + PyMem_DEL(arg5); + Py_INCREF(Py_None); + return Py_None; +} + +/* nurbscurve(knots, ctlpoints, order, type). + The length of ctlpoints is len(knots)-order. */ + + +static PyObject * +gl_nurbscurve(PyObject *self, PyObject *args) +{ + long arg1 ; + double * arg2 ; + long arg3 ; + double * arg4 ; + long arg5 ; + long arg6 ; + int ncoords, npoints; + int i; + PyObject *v; + double *pnext; + if (!PyArg_GetLongArraySize(args, 4, 0, &arg1)) + return NULL; + if ((arg2 = PyMem_NEW(double, arg1 )) == NULL) { + return PyErr_NoMemory(); + } + if (!PyArg_GetDoubleArray(args, 4, 0, arg1 , arg2)) + return NULL; + if (!PyArg_GetLong(args, 4, 2, &arg5)) + return NULL; + if (!PyArg_GetLong(args, 4, 3, &arg6)) + return NULL; + if (arg6 == N_ST) + ncoords = 2; + else if (arg6 == N_STW) + ncoords = 3; + else { + PyErr_BadArgument(); + return NULL; + } + npoints = arg1 - arg5; + if (!PyArg_GetObject(args, 4, 1, &v)) + return NULL; + if (!PyList_Check(v) || PyList_Size(v) != npoints) { + PyErr_BadArgument(); + return NULL; + } + if ((arg4 = PyMem_NEW(double, npoints*ncoords )) == NULL) { + return PyErr_NoMemory(); + } + pnext = arg4; + for (i = 0; i < npoints; i++) { + if (!PyArg_GetDoubleArray(PyList_GetItem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + arg3 = (sizeof(double)) * ncoords; + nurbscurve( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + PyMem_DEL(arg2); + PyMem_DEL(arg4); + Py_INCREF(Py_None); + return Py_None; +} + +/* pwlcurve(points, type). + Points is a list of points. Type must be N_ST. */ + + +static PyObject * +gl_pwlcurve(PyObject *self, PyObject *args) +{ + PyObject *v; + long type; + double *data, *pnext; + long npoints, ncoords; + int i; + if (!PyArg_GetObject(args, 2, 0, &v)) + return NULL; + if (!PyArg_GetLong(args, 2, 1, &type)) + return NULL; + if (!PyList_Check(v)) { + PyErr_BadArgument(); + return NULL; + } + npoints = PyList_Size(v); + if (type == N_ST) + ncoords = 2; + else { + PyErr_BadArgument(); + return NULL; + } + if ((data = PyMem_NEW(double, npoints*ncoords)) == NULL) { + return PyErr_NoMemory(); + } + pnext = data; + for (i = 0; i < npoints; i++) { + if (!PyArg_GetDoubleArray(PyList_GetItem(v, i), 1, 0, ncoords, pnext)) + return NULL; + pnext += ncoords; + } + pwlcurve(npoints, data, sizeof(double)*ncoords, type); + PyMem_DEL(data); + Py_INCREF(Py_None); + return Py_None; +} + + +/* Picking and Selecting */ + +static short *pickbuffer = NULL; +static long pickbuffersize; + +static PyObject * +pick_select(PyObject *args, void (*func)()) +{ + if (!PyArg_GetLong(args, 1, 0, &pickbuffersize)) + return NULL; + if (pickbuffer != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "pick/gselect: already picking/selecting"); + return NULL; + } + if ((pickbuffer = PyMem_NEW(short, pickbuffersize)) == NULL) { + return PyErr_NoMemory(); + } + (*func)(pickbuffer, pickbuffersize); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +endpick_select(long (*func)()) +{ + PyObject *v, *w; + int i, nhits, n; + if (pickbuffer == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "endpick/endselect: not in pick/select mode"); + return NULL; + } + nhits = (*func)(pickbuffer); + if (nhits < 0) { + nhits = -nhits; /* How to report buffer overflow otherwise? */ + } + /* Scan the buffer to see how many integers */ + n = 0; + for (; nhits > 0; nhits--) { + n += 1 + pickbuffer[n]; + } + v = PyList_New(n); + if (v == NULL) + return NULL; + /* XXX Could do it nicer and interpret the data structure here, + returning a list of lists. But this can be done in Python... */ + for (i = 0; i < n; i++) { + w = PyInt_FromLong((long)pickbuffer[i]); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(v, i, w); + } + PyMem_DEL(pickbuffer); + pickbuffer = NULL; + return v; +} + +extern void pick(), gselect(); +extern long endpick(), endselect(); + +static PyObject *gl_pick(PyObject *self, PyObject *args) +{ + return pick_select(args, pick); +} + +static PyObject *gl_endpick(PyObject *self) +{ + return endpick_select(endpick); +} + +static PyObject *gl_gselect(PyObject *self, PyObject *args) +{ + return pick_select(args, gselect); +} + +static PyObject *gl_endselect(PyObject *self) +{ + return endpick_select(endselect); +} + + +/* XXX The generator botches this one. Here's a quick hack to fix it. */ + +/* XXX The generator botches this one. Here's a quick hack to fix it. */ + + +static PyObject * +gl_getmatrix(PyObject *self, PyObject *args) +{ + Matrix arg1; + PyObject *v, *w; + int i, j; + getmatrix( arg1 ); + v = PyList_New(16); + if (v == NULL) { + return PyErr_NoMemory(); + } + for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) { + w = mknewfloatobject(arg1[i][j]); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(v, i*4+j, w); + } + return v; +} + +/* Here's an alternate version that returns a 4x4 matrix instead of + a vector. Unfortunately it is incompatible with loadmatrix and + multmatrix... */ + + +static PyObject * +gl_altgetmatrix(PyObject *self, PyObject *args) +{ + Matrix arg1; + PyObject *v, *w; + int i, j; + getmatrix( arg1 ); + v = PyList_New(4); + if (v == NULL) { + return NULL; + } + for (i = 0; i < 4; i++) { + w = PyList_New(4); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(v, i, w); + } + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + w = mknewfloatobject(arg1[i][j]); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(PyList_GetItem(v, i), j, w); + } + } + return v; +} + + +static PyObject * +gl_lrectwrite(PyObject *self, PyObject *args) +{ + short x1 ; + short y1 ; + short x2 ; + short y2 ; + string parray ; + PyObject *s; +#if 0 + int pixcount; +#endif + if (!PyArg_GetShort(args, 5, 0, &x1)) + return NULL; + if (!PyArg_GetShort(args, 5, 1, &y1)) + return NULL; + if (!PyArg_GetShort(args, 5, 2, &x2)) + return NULL; + if (!PyArg_GetShort(args, 5, 3, &y2)) + return NULL; + if (!PyArg_GetString(args, 5, 4, &parray)) + return NULL; + if (!PyArg_GetObject(args, 5, 4, &s)) + return NULL; +#if 0 +/* Don't check this, it breaks experiments with pixmode(PM_SIZE, ...) */ + pixcount = (long)(x2+1-x1) * (long)(y2+1-y1); + if (!PyString_Check(s) || PyString_Size(s) != pixcount*sizeof(long)) { + PyErr_SetString(PyExc_RuntimeError, + "string arg to lrectwrite has wrong size"); + return NULL; + } +#endif + lrectwrite( x1 , y1 , x2 , y2 , (unsigned long *) parray ); + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +gl_lrectread(PyObject *self, PyObject *args) +{ + short x1 ; + short y1 ; + short x2 ; + short y2 ; + PyObject *parray; + int pixcount; + if (!PyArg_GetShort(args, 4, 0, &x1)) + return NULL; + if (!PyArg_GetShort(args, 4, 1, &y1)) + return NULL; + if (!PyArg_GetShort(args, 4, 2, &x2)) + return NULL; + if (!PyArg_GetShort(args, 4, 3, &y2)) + return NULL; + pixcount = (long)(x2+1-x1) * (long)(y2+1-y1); + parray = PyString_FromStringAndSize((char *)NULL, pixcount*sizeof(long)); + if (parray == NULL) + return NULL; /* No memory */ + lrectread(x1, y1, x2, y2, (unsigned long *) PyString_AsString(parray)); + return parray; +} + + +static PyObject * +gl_readdisplay(PyObject *self, PyObject *args) +{ + short x1, y1, x2, y2; + unsigned long *parray, hints; + long size, size_ret; + PyObject *rv; + + if ( !PyArg_Parse(args, "hhhhl", &x1, &y1, &x2, &y2, &hints) ) + return 0; + size = (long)(x2+1-x1) * (long)(y2+1-y1); + rv = PyString_FromStringAndSize((char *)NULL, size*sizeof(long)); + if ( rv == NULL ) + return NULL; + parray = (unsigned long *)PyString_AsString(rv); + size_ret = readdisplay(x1, y1, x2, y2, parray, hints); + if ( size_ret != size ) { + printf("gl_readdisplay: got %ld pixels, expected %ld\n", + size_ret, size); + PyErr_SetString(PyExc_RuntimeError, "readdisplay returned unexpected length"); + return NULL; + } + return rv; +} + +/* Desperately needed, here are tools to compress and decompress + the data manipulated by lrectread/lrectwrite. + + gl.packrect(width, height, packfactor, bigdata) --> smalldata + makes 'bigdata' 4*(packfactor**2) times smaller by: + - turning it into B/W (a factor 4) + - replacing squares of size pacfactor by one + representative + + gl.unpackrect(width, height, packfactor, smalldata) --> bigdata + is the inverse; the numeric arguments must be *the same*. + + Both work best if width and height are multiples of packfactor + (in fact unpackrect will leave garbage bytes). +*/ + + +static PyObject * +gl_packrect(PyObject *self, PyObject *args) +{ + long width, height, packfactor; + char *s; + PyObject *unpacked, *packed; + int pixcount, packedcount, x, y, r, g, b; + unsigned long pixel; + unsigned char *p; + unsigned long *parray; + if (!PyArg_GetLong(args, 4, 0, &width)) + return NULL; + if (!PyArg_GetLong(args, 4, 1, &height)) + return NULL; + if (!PyArg_GetLong(args, 4, 2, &packfactor)) + return NULL; + if (!PyArg_GetString(args, 4, 3, &s)) /* For type checking only */ + return NULL; + if (!PyArg_GetObject(args, 4, 3, &unpacked)) + return NULL; + if (width <= 0 || height <= 0 || packfactor <= 0) { + PyErr_SetString(PyExc_RuntimeError, "packrect args must be > 0"); + return NULL; + } + pixcount = width*height; + packedcount = ((width+packfactor-1)/packfactor) * + ((height+packfactor-1)/packfactor); + if (PyString_Size(unpacked) != pixcount*sizeof(long)) { + PyErr_SetString(PyExc_RuntimeError, + "string arg to packrect has wrong size"); + return NULL; + } + packed = PyString_FromStringAndSize((char *)NULL, packedcount); + if (packed == NULL) + return NULL; + parray = (unsigned long *) PyString_AsString(unpacked); + p = (unsigned char *) PyString_AsString(packed); + for (y = 0; y < height; y += packfactor, parray += packfactor*width) { + for (x = 0; x < width; x += packfactor) { + pixel = parray[x]; + r = pixel & 0xff; + g = (pixel >> 8) & 0xff; + b = (pixel >> 16) & 0xff; + *p++ = (30*r+59*g+11*b) / 100; + } + } + return packed; +} + + +static unsigned long unpacktab[256]; +static int unpacktab_inited = 0; + +static PyObject * +gl_unpackrect(PyObject *self, PyObject *args) +{ + long width, height, packfactor; + char *s; + PyObject *unpacked, *packed; + int pixcount, packedcount; + register unsigned char *p; + register unsigned long *parray; + if (!unpacktab_inited) { + register int white; + for (white = 256; --white >= 0; ) + unpacktab[white] = white * 0x010101L; + unpacktab_inited++; + } + if (!PyArg_GetLong(args, 4, 0, &width)) + return NULL; + if (!PyArg_GetLong(args, 4, 1, &height)) + return NULL; + if (!PyArg_GetLong(args, 4, 2, &packfactor)) + return NULL; + if (!PyArg_GetString(args, 4, 3, &s)) /* For type checking only */ + return NULL; + if (!PyArg_GetObject(args, 4, 3, &packed)) + return NULL; + if (width <= 0 || height <= 0 || packfactor <= 0) { + PyErr_SetString(PyExc_RuntimeError, "packrect args must be > 0"); + return NULL; + } + pixcount = width*height; + packedcount = ((width+packfactor-1)/packfactor) * + ((height+packfactor-1)/packfactor); + if (PyString_Size(packed) != packedcount) { + PyErr_SetString(PyExc_RuntimeError, + "string arg to unpackrect has wrong size"); + return NULL; + } + unpacked = PyString_FromStringAndSize((char *)NULL, pixcount*sizeof(long)); + if (unpacked == NULL) + return NULL; + parray = (unsigned long *) PyString_AsString(unpacked); + p = (unsigned char *) PyString_AsString(packed); + if (packfactor == 1 && width*height > 0) { + /* Just expand bytes to longs */ + register int x = width * height; + do { + *parray++ = unpacktab[*p++]; + } while (--x >= 0); + } + else { + register int y; + for (y = 0; y < height-packfactor+1; + y += packfactor, parray += packfactor*width) { + register int x; + for (x = 0; x < width-packfactor+1; x += packfactor) { + register unsigned long pixel = unpacktab[*p++]; + register int i; + for (i = packfactor*width; (i-=width) >= 0;) { + register int j; + for (j = packfactor; --j >= 0; ) + parray[i+x+j] = pixel; + } + } + } + } + return unpacked; +} + +static PyObject * +gl_gversion(PyObject *self, PyObject *args) +{ + char buf[20]; + gversion(buf); + return PyString_FromString(buf); +} + + +/* void clear - Manual because of clash with termcap */ +static PyObject * +gl_clear(PyObject *self, PyObject *args) +{ + __GLclear( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* End of manually written stubs */ + + +/* long getshade */ + +static PyObject * +gl_getshade(PyObject *self, PyObject *args) +{ + long retval; + retval = getshade( ); + return mknewlongobject(retval); +} + +/* void devport short s long s */ + +static PyObject * +gl_devport(PyObject *self, PyObject *args) +{ + short arg1 ; + long arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + devport( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rdr2i long s long s */ + +static PyObject * +gl_rdr2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + rdr2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rectfs short s short s short s short s */ + +static PyObject * +gl_rectfs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + rectfs( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rects short s short s short s short s */ + +static PyObject * +gl_rects(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + rects( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rmv2i long s long s */ + +static PyObject * +gl_rmv2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + rmv2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void noport */ + +static PyObject * +gl_noport(PyObject *self, PyObject *args) +{ + noport( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void popviewport */ + +static PyObject * +gl_popviewport(PyObject *self, PyObject *args) +{ + popviewport( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void clearhitcode */ + +static PyObject * +gl_clearhitcode(PyObject *self, PyObject *args) +{ + clearhitcode( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void closeobj */ + +static PyObject * +gl_closeobj(PyObject *self, PyObject *args) +{ + closeobj( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cursoff */ + +static PyObject * +gl_cursoff(PyObject *self, PyObject *args) +{ + cursoff( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void curson */ + +static PyObject * +gl_curson(PyObject *self, PyObject *args) +{ + curson( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void doublebuffer */ + +static PyObject * +gl_doublebuffer(PyObject *self, PyObject *args) +{ + doublebuffer( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void finish */ + +static PyObject * +gl_finish(PyObject *self, PyObject *args) +{ + finish( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void gconfig */ + +static PyObject * +gl_gconfig(PyObject *self, PyObject *args) +{ + gconfig( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void ginit */ + +static PyObject * +gl_ginit(PyObject *self, PyObject *args) +{ + ginit( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void greset */ + +static PyObject * +gl_greset(PyObject *self, PyObject *args) +{ + greset( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void multimap */ + +static PyObject * +gl_multimap(PyObject *self, PyObject *args) +{ + multimap( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void onemap */ + +static PyObject * +gl_onemap(PyObject *self, PyObject *args) +{ + onemap( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void popattributes */ + +static PyObject * +gl_popattributes(PyObject *self, PyObject *args) +{ + popattributes( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void popmatrix */ + +static PyObject * +gl_popmatrix(PyObject *self, PyObject *args) +{ + popmatrix( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pushattributes */ + +static PyObject * +gl_pushattributes(PyObject *self, PyObject *args) +{ + pushattributes( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pushmatrix */ + +static PyObject * +gl_pushmatrix(PyObject *self, PyObject *args) +{ + pushmatrix( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pushviewport */ + +static PyObject * +gl_pushviewport(PyObject *self, PyObject *args) +{ + pushviewport( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void qreset */ + +static PyObject * +gl_qreset(PyObject *self, PyObject *args) +{ + qreset( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void RGBmode */ + +static PyObject * +gl_RGBmode(PyObject *self, PyObject *args) +{ + RGBmode( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void singlebuffer */ + +static PyObject * +gl_singlebuffer(PyObject *self, PyObject *args) +{ + singlebuffer( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void swapbuffers */ + +static PyObject * +gl_swapbuffers(PyObject *self, PyObject *args) +{ + swapbuffers( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void gsync */ + +static PyObject * +gl_gsync(PyObject *self, PyObject *args) +{ + gsync( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void gflush */ + +static PyObject * +gl_gflush(PyObject *self, PyObject *args) +{ + gflush( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void tpon */ + +static PyObject * +gl_tpon(PyObject *self, PyObject *args) +{ + tpon( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void tpoff */ + +static PyObject * +gl_tpoff(PyObject *self, PyObject *args) +{ + tpoff( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void clkon */ + +static PyObject * +gl_clkon(PyObject *self, PyObject *args) +{ + clkon( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void clkoff */ + +static PyObject * +gl_clkoff(PyObject *self, PyObject *args) +{ + clkoff( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void ringbell */ + +static PyObject * +gl_ringbell(PyObject *self, PyObject *args) +{ + ringbell( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void gbegin */ + +static PyObject * +gl_gbegin(PyObject *self, PyObject *args) +{ + gbegin( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void textinit */ + +static PyObject * +gl_textinit(PyObject *self, PyObject *args) +{ + textinit( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void initnames */ + +static PyObject * +gl_initnames(PyObject *self, PyObject *args) +{ + initnames( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pclos */ + +static PyObject * +gl_pclos(PyObject *self, PyObject *args) +{ + pclos( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void popname */ + +static PyObject * +gl_popname(PyObject *self, PyObject *args) +{ + popname( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void spclos */ + +static PyObject * +gl_spclos(PyObject *self, PyObject *args) +{ + spclos( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void zclear */ + +static PyObject * +gl_zclear(PyObject *self, PyObject *args) +{ + zclear( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void screenspace */ + +static PyObject * +gl_screenspace(PyObject *self, PyObject *args) +{ + screenspace( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void reshapeviewport */ + +static PyObject * +gl_reshapeviewport(PyObject *self, PyObject *args) +{ + reshapeviewport( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void winpush */ + +static PyObject * +gl_winpush(PyObject *self, PyObject *args) +{ + winpush( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void winpop */ + +static PyObject * +gl_winpop(PyObject *self, PyObject *args) +{ + winpop( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void foreground */ + +static PyObject * +gl_foreground(PyObject *self, PyObject *args) +{ + foreground( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endfullscrn */ + +static PyObject * +gl_endfullscrn(PyObject *self, PyObject *args) +{ + endfullscrn( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endpupmode */ + +static PyObject * +gl_endpupmode(PyObject *self, PyObject *args) +{ + endpupmode( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void fullscrn */ + +static PyObject * +gl_fullscrn(PyObject *self, PyObject *args) +{ + fullscrn( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pupmode */ + +static PyObject * +gl_pupmode(PyObject *self, PyObject *args) +{ + pupmode( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void winconstraints */ + +static PyObject * +gl_winconstraints(PyObject *self, PyObject *args) +{ + winconstraints( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pagecolor short s */ + +static PyObject * +gl_pagecolor(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + pagecolor( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void textcolor short s */ + +static PyObject * +gl_textcolor(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + textcolor( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void color short s */ + +static PyObject * +gl_color(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + color( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void curveit short s */ + +static PyObject * +gl_curveit(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + curveit( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void font short s */ + +static PyObject * +gl_font(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + font( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void linewidth short s */ + +static PyObject * +gl_linewidth(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + linewidth( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setlinestyle short s */ + +static PyObject * +gl_setlinestyle(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + setlinestyle( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setmap short s */ + +static PyObject * +gl_setmap(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + setmap( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void swapinterval short s */ + +static PyObject * +gl_swapinterval(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + swapinterval( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void writemask short s */ + +static PyObject * +gl_writemask(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + writemask( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void textwritemask short s */ + +static PyObject * +gl_textwritemask(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + textwritemask( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void qdevice short s */ + +static PyObject * +gl_qdevice(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + qdevice( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void unqdevice short s */ + +static PyObject * +gl_unqdevice(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + unqdevice( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void curvebasis short s */ + +static PyObject * +gl_curvebasis(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + curvebasis( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void curveprecision short s */ + +static PyObject * +gl_curveprecision(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + curveprecision( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void loadname short s */ + +static PyObject * +gl_loadname(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + loadname( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void passthrough short s */ + +static PyObject * +gl_passthrough(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + passthrough( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pushname short s */ + +static PyObject * +gl_pushname(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + pushname( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setmonitor short s */ + +static PyObject * +gl_setmonitor(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + setmonitor( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setshade short s */ + +static PyObject * +gl_setshade(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + setshade( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setpattern short s */ + +static PyObject * +gl_setpattern(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + setpattern( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pagewritemask short s */ + +static PyObject * +gl_pagewritemask(PyObject *self, PyObject *args) +{ + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + pagewritemask( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void callobj long s */ + +static PyObject * +gl_callobj(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + callobj( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void delobj long s */ + +static PyObject * +gl_delobj(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + delobj( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void editobj long s */ + +static PyObject * +gl_editobj(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + editobj( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void makeobj long s */ + +static PyObject * +gl_makeobj(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + makeobj( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void maketag long s */ + +static PyObject * +gl_maketag(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + maketag( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void chunksize long s */ + +static PyObject * +gl_chunksize(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + chunksize( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void compactify long s */ + +static PyObject * +gl_compactify(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + compactify( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void deltag long s */ + +static PyObject * +gl_deltag(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + deltag( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lsrepeat long s */ + +static PyObject * +gl_lsrepeat(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + lsrepeat( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void objinsert long s */ + +static PyObject * +gl_objinsert(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + objinsert( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void objreplace long s */ + +static PyObject * +gl_objreplace(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + objreplace( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void winclose long s */ + +static PyObject * +gl_winclose(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + winclose( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void blanktime long s */ + +static PyObject * +gl_blanktime(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + blanktime( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void freepup long s */ + +static PyObject * +gl_freepup(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + freepup( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void backbuffer long s */ + +static PyObject * +gl_backbuffer(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + backbuffer( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void frontbuffer long s */ + +static PyObject * +gl_frontbuffer(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + frontbuffer( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lsbackup long s */ + +static PyObject * +gl_lsbackup(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + lsbackup( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void resetls long s */ + +static PyObject * +gl_resetls(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + resetls( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lampon long s */ + +static PyObject * +gl_lampon(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + lampon( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lampoff long s */ + +static PyObject * +gl_lampoff(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + lampoff( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setbell long s */ + +static PyObject * +gl_setbell(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + setbell( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void blankscreen long s */ + +static PyObject * +gl_blankscreen(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + blankscreen( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void depthcue long s */ + +static PyObject * +gl_depthcue(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + depthcue( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void zbuffer long s */ + +static PyObject * +gl_zbuffer(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + zbuffer( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void backface long s */ + +static PyObject * +gl_backface(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + backface( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cmov2i long s long s */ + +static PyObject * +gl_cmov2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + cmov2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void draw2i long s long s */ + +static PyObject * +gl_draw2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + draw2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void move2i long s long s */ + +static PyObject * +gl_move2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + move2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pnt2i long s long s */ + +static PyObject * +gl_pnt2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + pnt2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void patchbasis long s long s */ + +static PyObject * +gl_patchbasis(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + patchbasis( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void patchprecision long s long s */ + +static PyObject * +gl_patchprecision(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + patchprecision( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pdr2i long s long s */ + +static PyObject * +gl_pdr2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + pdr2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pmv2i long s long s */ + +static PyObject * +gl_pmv2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + pmv2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpdr2i long s long s */ + +static PyObject * +gl_rpdr2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + rpdr2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpmv2i long s long s */ + +static PyObject * +gl_rpmv2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + rpmv2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpt2i long s long s */ + +static PyObject * +gl_xfpt2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + xfpt2i( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void objdelete long s long s */ + +static PyObject * +gl_objdelete(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + objdelete( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void patchcurves long s long s */ + +static PyObject * +gl_patchcurves(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + patchcurves( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void minsize long s long s */ + +static PyObject * +gl_minsize(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + minsize( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void maxsize long s long s */ + +static PyObject * +gl_maxsize(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + maxsize( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void keepaspect long s long s */ + +static PyObject * +gl_keepaspect(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + keepaspect( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void prefsize long s long s */ + +static PyObject * +gl_prefsize(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + prefsize( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void stepunit long s long s */ + +static PyObject * +gl_stepunit(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + stepunit( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void fudge long s long s */ + +static PyObject * +gl_fudge(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + fudge( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void winmove long s long s */ + +static PyObject * +gl_winmove(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + winmove( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void attachcursor short s short s */ + +static PyObject * +gl_attachcursor(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + attachcursor( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void deflinestyle short s short s */ + +static PyObject * +gl_deflinestyle(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + deflinestyle( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void noise short s short s */ + +static PyObject * +gl_noise(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + noise( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void picksize short s short s */ + +static PyObject * +gl_picksize(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + picksize( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void qenter short s short s */ + +static PyObject * +gl_qenter(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + qenter( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setdepth short s short s */ + +static PyObject * +gl_setdepth(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + setdepth( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cmov2s short s short s */ + +static PyObject * +gl_cmov2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + cmov2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void draw2s short s short s */ + +static PyObject * +gl_draw2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + draw2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void move2s short s short s */ + +static PyObject * +gl_move2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + move2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pdr2s short s short s */ + +static PyObject * +gl_pdr2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + pdr2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pmv2s short s short s */ + +static PyObject * +gl_pmv2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + pmv2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pnt2s short s short s */ + +static PyObject * +gl_pnt2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + pnt2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rdr2s short s short s */ + +static PyObject * +gl_rdr2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + rdr2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rmv2s short s short s */ + +static PyObject * +gl_rmv2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + rmv2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpdr2s short s short s */ + +static PyObject * +gl_rpdr2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + rpdr2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpmv2s short s short s */ + +static PyObject * +gl_rpmv2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + rpmv2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpt2s short s short s */ + +static PyObject * +gl_xfpt2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + xfpt2s( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cmov2 float s float s */ + +static PyObject * +gl_cmov2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + cmov2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void draw2 float s float s */ + +static PyObject * +gl_draw2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + draw2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void move2 float s float s */ + +static PyObject * +gl_move2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + move2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pnt2 float s float s */ + +static PyObject * +gl_pnt2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + pnt2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pdr2 float s float s */ + +static PyObject * +gl_pdr2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + pdr2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pmv2 float s float s */ + +static PyObject * +gl_pmv2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + pmv2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rdr2 float s float s */ + +static PyObject * +gl_rdr2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + rdr2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rmv2 float s float s */ + +static PyObject * +gl_rmv2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + rmv2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpdr2 float s float s */ + +static PyObject * +gl_rpdr2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + rpdr2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpmv2 float s float s */ + +static PyObject * +gl_rpmv2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + rpmv2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpt2 float s float s */ + +static PyObject * +gl_xfpt2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + xfpt2( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void loadmatrix float s[4*4] */ + +static PyObject * +gl_loadmatrix(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] [ 4 ] ; + if (!getifloatarray(args, 1, 0, 4 * 4 , (float *) arg1)) + return NULL; + loadmatrix( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void multmatrix float s[4*4] */ + +static PyObject * +gl_multmatrix(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] [ 4 ] ; + if (!getifloatarray(args, 1, 0, 4 * 4 , (float *) arg1)) + return NULL; + multmatrix( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void crv float s[3*4] */ + +static PyObject * +gl_crv(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] [ 3 ] ; + if (!getifloatarray(args, 1, 0, 3 * 4 , (float *) arg1)) + return NULL; + crv( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rcrv float s[4*4] */ + +static PyObject * +gl_rcrv(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] [ 4 ] ; + if (!getifloatarray(args, 1, 0, 4 * 4 , (float *) arg1)) + return NULL; + rcrv( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void addtopup long s char *s long s */ + +static PyObject * +gl_addtopup(PyObject *self, PyObject *args) +{ + long arg1 ; + string arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getistringarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + addtopup( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void charstr char *s */ + +static PyObject * +gl_charstr(PyObject *self, PyObject *args) +{ + string arg1 ; + if (!getistringarg(args, 1, 0, &arg1)) + return NULL; + charstr( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void getport char *s */ + +static PyObject * +gl_getport(PyObject *self, PyObject *args) +{ + string arg1 ; + if (!getistringarg(args, 1, 0, &arg1)) + return NULL; + getport( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long strwidth char *s */ + +static PyObject * +gl_strwidth(PyObject *self, PyObject *args) +{ + long retval; + string arg1 ; + if (!getistringarg(args, 1, 0, &arg1)) + return NULL; + retval = strwidth( arg1 ); + return mknewlongobject(retval); +} + +/* long winopen char *s */ + +static PyObject * +gl_winopen(PyObject *self, PyObject *args) +{ + long retval; + string arg1 ; + if (!getistringarg(args, 1, 0, &arg1)) + return NULL; + retval = winopen( arg1 ); + return mknewlongobject(retval); +} + +/* void wintitle char *s */ + +static PyObject * +gl_wintitle(PyObject *self, PyObject *args) +{ + string arg1 ; + if (!getistringarg(args, 1, 0, &arg1)) + return NULL; + wintitle( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polf long s float s[3*arg1] */ + +static PyObject * +gl_polf(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 3 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (float(*)[3]) PyMem_NEW(float , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 1, 0, 3 * arg1 , (float *) arg2)) + return NULL; + polf( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polf2 long s float s[2*arg1] */ + +static PyObject * +gl_polf2(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 2 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (float(*)[2]) PyMem_NEW(float , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 1, 0, 2 * arg1 , (float *) arg2)) + return NULL; + polf2( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void poly long s float s[3*arg1] */ + +static PyObject * +gl_poly(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 3 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (float(*)[3]) PyMem_NEW(float , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 1, 0, 3 * arg1 , (float *) arg2)) + return NULL; + poly( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void poly2 long s float s[2*arg1] */ + +static PyObject * +gl_poly2(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 2 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (float(*)[2]) PyMem_NEW(float , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 1, 0, 2 * arg1 , (float *) arg2)) + return NULL; + poly2( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void crvn long s float s[3*arg1] */ + +static PyObject * +gl_crvn(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 3 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (float(*)[3]) PyMem_NEW(float , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 1, 0, 3 * arg1 , (float *) arg2)) + return NULL; + crvn( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rcrvn long s float s[4*arg1] */ + +static PyObject * +gl_rcrvn(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 4 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 4; + if ((arg2 = (float(*)[4]) PyMem_NEW(float , 4 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 1, 0, 4 * arg1 , (float *) arg2)) + return NULL; + rcrvn( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polf2i long s long s[2*arg1] */ + +static PyObject * +gl_polf2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long (* arg2) [ 2 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (long(*)[2]) PyMem_NEW(long , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getilongarray(args, 1, 0, 2 * arg1 , (long *) arg2)) + return NULL; + polf2i( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polfi long s long s[3*arg1] */ + +static PyObject * +gl_polfi(PyObject *self, PyObject *args) +{ + long arg1 ; + long (* arg2) [ 3 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (long(*)[3]) PyMem_NEW(long , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getilongarray(args, 1, 0, 3 * arg1 , (long *) arg2)) + return NULL; + polfi( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void poly2i long s long s[2*arg1] */ + +static PyObject * +gl_poly2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long (* arg2) [ 2 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (long(*)[2]) PyMem_NEW(long , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getilongarray(args, 1, 0, 2 * arg1 , (long *) arg2)) + return NULL; + poly2i( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polyi long s long s[3*arg1] */ + +static PyObject * +gl_polyi(PyObject *self, PyObject *args) +{ + long arg1 ; + long (* arg2) [ 3 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (long(*)[3]) PyMem_NEW(long , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getilongarray(args, 1, 0, 3 * arg1 , (long *) arg2)) + return NULL; + polyi( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polf2s long s short s[2*arg1] */ + +static PyObject * +gl_polf2s(PyObject *self, PyObject *args) +{ + long arg1 ; + short (* arg2) [ 2 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (short(*)[2]) PyMem_NEW(short , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 1, 0, 2 * arg1 , (short *) arg2)) + return NULL; + polf2s( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polfs long s short s[3*arg1] */ + +static PyObject * +gl_polfs(PyObject *self, PyObject *args) +{ + long arg1 ; + short (* arg2) [ 3 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (short(*)[3]) PyMem_NEW(short , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 1, 0, 3 * arg1 , (short *) arg2)) + return NULL; + polfs( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polys long s short s[3*arg1] */ + +static PyObject * +gl_polys(PyObject *self, PyObject *args) +{ + long arg1 ; + short (* arg2) [ 3 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (short(*)[3]) PyMem_NEW(short , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 1, 0, 3 * arg1 , (short *) arg2)) + return NULL; + polys( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void poly2s long s short s[2*arg1] */ + +static PyObject * +gl_poly2s(PyObject *self, PyObject *args) +{ + long arg1 ; + short (* arg2) [ 2 ] ; + if (!getilongarraysize(args, 1, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (short(*)[2]) PyMem_NEW(short , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 1, 0, 2 * arg1 , (short *) arg2)) + return NULL; + poly2s( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void defcursor short s u_short s[128] */ + +static PyObject * +gl_defcursor(PyObject *self, PyObject *args) +{ + short arg1 ; + unsigned short arg2 [ 128 ] ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarray(args, 2, 1, 128 , (short *) arg2)) + return NULL; + defcursor( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void writepixels short s u_short s[arg1] */ + +static PyObject * +gl_writepixels(PyObject *self, PyObject *args) +{ + short arg1 ; + unsigned short * arg2 ; + if (!getishortarraysize(args, 1, 0, &arg1)) + return NULL; + if ((arg2 = PyMem_NEW(unsigned short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 1, 0, arg1 , (short *) arg2)) + return NULL; + writepixels( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void defbasis long s float s[4*4] */ + +static PyObject * +gl_defbasis(PyObject *self, PyObject *args) +{ + long arg1 ; + float arg2 [ 4 ] [ 4 ] ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarray(args, 2, 1, 4 * 4 , (float *) arg2)) + return NULL; + defbasis( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void gewrite short s short s[arg1] */ + +static PyObject * +gl_gewrite(PyObject *self, PyObject *args) +{ + short arg1 ; + short * arg2 ; + if (!getishortarraysize(args, 1, 0, &arg1)) + return NULL; + if ((arg2 = PyMem_NEW(short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 1, 0, arg1 , arg2)) + return NULL; + gewrite( arg1 , arg2 ); + PyMem_DEL(arg2); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rotate short s char s */ + +static PyObject * +gl_rotate(PyObject *self, PyObject *args) +{ + short arg1 ; + char arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getichararg(args, 2, 1, &arg2)) + return NULL; + rotate( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rot float s char s */ + +static PyObject * +gl_rot(PyObject *self, PyObject *args) +{ + float arg1 ; + char arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getichararg(args, 2, 1, &arg2)) + return NULL; + rot( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void circfi long s long s long s */ + +static PyObject * +gl_circfi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + circfi( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void circi long s long s long s */ + +static PyObject * +gl_circi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + circi( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cmovi long s long s long s */ + +static PyObject * +gl_cmovi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + cmovi( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void drawi long s long s long s */ + +static PyObject * +gl_drawi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + drawi( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void movei long s long s long s */ + +static PyObject * +gl_movei(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + movei( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pnti long s long s long s */ + +static PyObject * +gl_pnti(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + pnti( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void newtag long s long s long s */ + +static PyObject * +gl_newtag(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + newtag( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pdri long s long s long s */ + +static PyObject * +gl_pdri(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + pdri( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pmvi long s long s long s */ + +static PyObject * +gl_pmvi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + pmvi( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rdri long s long s long s */ + +static PyObject * +gl_rdri(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + rdri( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rmvi long s long s long s */ + +static PyObject * +gl_rmvi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + rmvi( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpdri long s long s long s */ + +static PyObject * +gl_rpdri(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + rpdri( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpmvi long s long s long s */ + +static PyObject * +gl_rpmvi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + rpmvi( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpti long s long s long s */ + +static PyObject * +gl_xfpti(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + xfpti( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void circ float s float s float s */ + +static PyObject * +gl_circ(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + circ( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void circf float s float s float s */ + +static PyObject * +gl_circf(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + circf( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cmov float s float s float s */ + +static PyObject * +gl_cmov(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + cmov( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void draw float s float s float s */ + +static PyObject * +gl_draw(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + draw( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void move float s float s float s */ + +static PyObject * +gl_move(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + move( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pnt float s float s float s */ + +static PyObject * +gl_pnt(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + pnt( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void scale float s float s float s */ + +static PyObject * +gl_scale(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + scale( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void translate float s float s float s */ + +static PyObject * +gl_translate(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + translate( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pdr float s float s float s */ + +static PyObject * +gl_pdr(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + pdr( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pmv float s float s float s */ + +static PyObject * +gl_pmv(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + pmv( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rdr float s float s float s */ + +static PyObject * +gl_rdr(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + rdr( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rmv float s float s float s */ + +static PyObject * +gl_rmv(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + rmv( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpdr float s float s float s */ + +static PyObject * +gl_rpdr(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + rpdr( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpmv float s float s float s */ + +static PyObject * +gl_rpmv(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + rpmv( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpt float s float s float s */ + +static PyObject * +gl_xfpt(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + if (!getifloatarg(args, 3, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 3, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 3, 2, &arg3)) + return NULL; + xfpt( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void RGBcolor short s short s short s */ + +static PyObject * +gl_RGBcolor(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + RGBcolor( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void RGBwritemask short s short s short s */ + +static PyObject * +gl_RGBwritemask(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + RGBwritemask( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setcursor short s short s short s */ + +static PyObject * +gl_setcursor(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + setcursor( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void tie short s short s short s */ + +static PyObject * +gl_tie(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + tie( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void circfs short s short s short s */ + +static PyObject * +gl_circfs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + circfs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void circs short s short s short s */ + +static PyObject * +gl_circs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + circs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cmovs short s short s short s */ + +static PyObject * +gl_cmovs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + cmovs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void draws short s short s short s */ + +static PyObject * +gl_draws(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + draws( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void moves short s short s short s */ + +static PyObject * +gl_moves(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + moves( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pdrs short s short s short s */ + +static PyObject * +gl_pdrs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + pdrs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pmvs short s short s short s */ + +static PyObject * +gl_pmvs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + pmvs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pnts short s short s short s */ + +static PyObject * +gl_pnts(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + pnts( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rdrs short s short s short s */ + +static PyObject * +gl_rdrs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + rdrs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rmvs short s short s short s */ + +static PyObject * +gl_rmvs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + rmvs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpdrs short s short s short s */ + +static PyObject * +gl_rpdrs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + rpdrs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpmvs short s short s short s */ + +static PyObject * +gl_rpmvs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + rpmvs( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpts short s short s short s */ + +static PyObject * +gl_xfpts(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + xfpts( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void curorigin short s short s short s */ + +static PyObject * +gl_curorigin(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + curorigin( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cyclemap short s short s short s */ + +static PyObject * +gl_cyclemap(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + if (!getishortarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + cyclemap( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void patch float s[4*4] float s[4*4] float s[4*4] */ + +static PyObject * +gl_patch(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] [ 4 ] ; + float arg2 [ 4 ] [ 4 ] ; + float arg3 [ 4 ] [ 4 ] ; + if (!getifloatarray(args, 3, 0, 4 * 4 , (float *) arg1)) + return NULL; + if (!getifloatarray(args, 3, 1, 4 * 4 , (float *) arg2)) + return NULL; + if (!getifloatarray(args, 3, 2, 4 * 4 , (float *) arg3)) + return NULL; + patch( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void splf long s float s[3*arg1] u_short s[arg1] */ + +static PyObject * +gl_splf(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 3 ] ; + unsigned short * arg3 ; + if (!getilongarraysize(args, 2, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (float(*)[3]) PyMem_NEW(float , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 2, 0, 3 * arg1 , (float *) arg2)) + return NULL; + if ((arg3 = PyMem_NEW(unsigned short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 1, arg1 , (short *) arg3)) + return NULL; + splf( arg1 , arg2 , arg3 ); + PyMem_DEL(arg2); + PyMem_DEL(arg3); + Py_INCREF(Py_None); + return Py_None; +} + +/* void splf2 long s float s[2*arg1] u_short s[arg1] */ + +static PyObject * +gl_splf2(PyObject *self, PyObject *args) +{ + long arg1 ; + float (* arg2) [ 2 ] ; + unsigned short * arg3 ; + if (!getilongarraysize(args, 2, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (float(*)[2]) PyMem_NEW(float , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 2, 0, 2 * arg1 , (float *) arg2)) + return NULL; + if ((arg3 = PyMem_NEW(unsigned short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 1, arg1 , (short *) arg3)) + return NULL; + splf2( arg1 , arg2 , arg3 ); + PyMem_DEL(arg2); + PyMem_DEL(arg3); + Py_INCREF(Py_None); + return Py_None; +} + +/* void splfi long s long s[3*arg1] u_short s[arg1] */ + +static PyObject * +gl_splfi(PyObject *self, PyObject *args) +{ + long arg1 ; + long (* arg2) [ 3 ] ; + unsigned short * arg3 ; + if (!getilongarraysize(args, 2, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (long(*)[3]) PyMem_NEW(long , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getilongarray(args, 2, 0, 3 * arg1 , (long *) arg2)) + return NULL; + if ((arg3 = PyMem_NEW(unsigned short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 1, arg1 , (short *) arg3)) + return NULL; + splfi( arg1 , arg2 , arg3 ); + PyMem_DEL(arg2); + PyMem_DEL(arg3); + Py_INCREF(Py_None); + return Py_None; +} + +/* void splf2i long s long s[2*arg1] u_short s[arg1] */ + +static PyObject * +gl_splf2i(PyObject *self, PyObject *args) +{ + long arg1 ; + long (* arg2) [ 2 ] ; + unsigned short * arg3 ; + if (!getilongarraysize(args, 2, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (long(*)[2]) PyMem_NEW(long , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getilongarray(args, 2, 0, 2 * arg1 , (long *) arg2)) + return NULL; + if ((arg3 = PyMem_NEW(unsigned short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 1, arg1 , (short *) arg3)) + return NULL; + splf2i( arg1 , arg2 , arg3 ); + PyMem_DEL(arg2); + PyMem_DEL(arg3); + Py_INCREF(Py_None); + return Py_None; +} + +/* void splfs long s short s[3*arg1] u_short s[arg1] */ + +static PyObject * +gl_splfs(PyObject *self, PyObject *args) +{ + long arg1 ; + short (* arg2) [ 3 ] ; + unsigned short * arg3 ; + if (!getilongarraysize(args, 2, 0, &arg1)) + return NULL; + arg1 = arg1 / 3; + if ((arg2 = (short(*)[3]) PyMem_NEW(short , 3 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 0, 3 * arg1 , (short *) arg2)) + return NULL; + if ((arg3 = PyMem_NEW(unsigned short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 1, arg1 , (short *) arg3)) + return NULL; + splfs( arg1 , arg2 , arg3 ); + PyMem_DEL(arg2); + PyMem_DEL(arg3); + Py_INCREF(Py_None); + return Py_None; +} + +/* void splf2s long s short s[2*arg1] u_short s[arg1] */ + +static PyObject * +gl_splf2s(PyObject *self, PyObject *args) +{ + long arg1 ; + short (* arg2) [ 2 ] ; + unsigned short * arg3 ; + if (!getilongarraysize(args, 2, 0, &arg1)) + return NULL; + arg1 = arg1 / 2; + if ((arg2 = (short(*)[2]) PyMem_NEW(short , 2 * arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 0, 2 * arg1 , (short *) arg2)) + return NULL; + if ((arg3 = PyMem_NEW(unsigned short , arg1 )) == NULL) + return PyErr_NoMemory(); + if (!getishortarray(args, 2, 1, arg1 , (short *) arg3)) + return NULL; + splf2s( arg1 , arg2 , arg3 ); + PyMem_DEL(arg2); + PyMem_DEL(arg3); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rpatch float s[4*4] float s[4*4] float s[4*4] float s[4*4] */ + +static PyObject * +gl_rpatch(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] [ 4 ] ; + float arg2 [ 4 ] [ 4 ] ; + float arg3 [ 4 ] [ 4 ] ; + float arg4 [ 4 ] [ 4 ] ; + if (!getifloatarray(args, 4, 0, 4 * 4 , (float *) arg1)) + return NULL; + if (!getifloatarray(args, 4, 1, 4 * 4 , (float *) arg2)) + return NULL; + if (!getifloatarray(args, 4, 2, 4 * 4 , (float *) arg3)) + return NULL; + if (!getifloatarray(args, 4, 3, 4 * 4 , (float *) arg4)) + return NULL; + rpatch( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void ortho2 float s float s float s float s */ + +static PyObject * +gl_ortho2(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + if (!getifloatarg(args, 4, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 4, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 4, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 4, 3, &arg4)) + return NULL; + ortho2( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rect float s float s float s float s */ + +static PyObject * +gl_rect(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + if (!getifloatarg(args, 4, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 4, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 4, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 4, 3, &arg4)) + return NULL; + rect( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rectf float s float s float s float s */ + +static PyObject * +gl_rectf(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + if (!getifloatarg(args, 4, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 4, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 4, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 4, 3, &arg4)) + return NULL; + rectf( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpt4 float s float s float s float s */ + +static PyObject * +gl_xfpt4(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + if (!getifloatarg(args, 4, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 4, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 4, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 4, 3, &arg4)) + return NULL; + xfpt4( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void textport short s short s short s short s */ + +static PyObject * +gl_textport(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + textport( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void mapcolor short s short s short s short s */ + +static PyObject * +gl_mapcolor(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + mapcolor( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void scrmask short s short s short s short s */ + +static PyObject * +gl_scrmask(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + scrmask( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setvaluator short s short s short s short s */ + +static PyObject * +gl_setvaluator(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + setvaluator( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void viewport short s short s short s short s */ + +static PyObject * +gl_viewport(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + viewport( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void shaderange short s short s short s short s */ + +static PyObject * +gl_shaderange(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + shaderange( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpt4s short s short s short s short s */ + +static PyObject * +gl_xfpt4s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + xfpt4s( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rectfi long s long s long s long s */ + +static PyObject * +gl_rectfi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + long arg4 ; + if (!getilongarg(args, 4, 0, &arg1)) + return NULL; + if (!getilongarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + rectfi( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void recti long s long s long s long s */ + +static PyObject * +gl_recti(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + long arg4 ; + if (!getilongarg(args, 4, 0, &arg1)) + return NULL; + if (!getilongarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + recti( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void xfpt4i long s long s long s long s */ + +static PyObject * +gl_xfpt4i(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + long arg4 ; + if (!getilongarg(args, 4, 0, &arg1)) + return NULL; + if (!getilongarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + xfpt4i( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void prefposition long s long s long s long s */ + +static PyObject * +gl_prefposition(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + long arg4 ; + if (!getilongarg(args, 4, 0, &arg1)) + return NULL; + if (!getilongarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + prefposition( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void arc float s float s float s short s short s */ + +static PyObject * +gl_arc(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + short arg4 ; + short arg5 ; + if (!getifloatarg(args, 5, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 5, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 5, 2, &arg3)) + return NULL; + if (!getishortarg(args, 5, 3, &arg4)) + return NULL; + if (!getishortarg(args, 5, 4, &arg5)) + return NULL; + arc( arg1 , arg2 , arg3 , arg4 , arg5 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void arcf float s float s float s short s short s */ + +static PyObject * +gl_arcf(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + short arg4 ; + short arg5 ; + if (!getifloatarg(args, 5, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 5, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 5, 2, &arg3)) + return NULL; + if (!getishortarg(args, 5, 3, &arg4)) + return NULL; + if (!getishortarg(args, 5, 4, &arg5)) + return NULL; + arcf( arg1 , arg2 , arg3 , arg4 , arg5 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void arcfi long s long s long s short s short s */ + +static PyObject * +gl_arcfi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + short arg4 ; + short arg5 ; + if (!getilongarg(args, 5, 0, &arg1)) + return NULL; + if (!getilongarg(args, 5, 1, &arg2)) + return NULL; + if (!getilongarg(args, 5, 2, &arg3)) + return NULL; + if (!getishortarg(args, 5, 3, &arg4)) + return NULL; + if (!getishortarg(args, 5, 4, &arg5)) + return NULL; + arcfi( arg1 , arg2 , arg3 , arg4 , arg5 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void arci long s long s long s short s short s */ + +static PyObject * +gl_arci(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + short arg4 ; + short arg5 ; + if (!getilongarg(args, 5, 0, &arg1)) + return NULL; + if (!getilongarg(args, 5, 1, &arg2)) + return NULL; + if (!getilongarg(args, 5, 2, &arg3)) + return NULL; + if (!getishortarg(args, 5, 3, &arg4)) + return NULL; + if (!getishortarg(args, 5, 4, &arg5)) + return NULL; + arci( arg1 , arg2 , arg3 , arg4 , arg5 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bbox2 short s short s float s float s float s float s */ + +static PyObject * +gl_bbox2(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + float arg3 ; + float arg4 ; + float arg5 ; + float arg6 ; + if (!getishortarg(args, 6, 0, &arg1)) + return NULL; + if (!getishortarg(args, 6, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 6, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 6, 3, &arg4)) + return NULL; + if (!getifloatarg(args, 6, 4, &arg5)) + return NULL; + if (!getifloatarg(args, 6, 5, &arg6)) + return NULL; + bbox2( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bbox2i short s short s long s long s long s long s */ + +static PyObject * +gl_bbox2i(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + long arg3 ; + long arg4 ; + long arg5 ; + long arg6 ; + if (!getishortarg(args, 6, 0, &arg1)) + return NULL; + if (!getishortarg(args, 6, 1, &arg2)) + return NULL; + if (!getilongarg(args, 6, 2, &arg3)) + return NULL; + if (!getilongarg(args, 6, 3, &arg4)) + return NULL; + if (!getilongarg(args, 6, 4, &arg5)) + return NULL; + if (!getilongarg(args, 6, 5, &arg6)) + return NULL; + bbox2i( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bbox2s short s short s short s short s short s short s */ + +static PyObject * +gl_bbox2s(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + short arg6 ; + if (!getishortarg(args, 6, 0, &arg1)) + return NULL; + if (!getishortarg(args, 6, 1, &arg2)) + return NULL; + if (!getishortarg(args, 6, 2, &arg3)) + return NULL; + if (!getishortarg(args, 6, 3, &arg4)) + return NULL; + if (!getishortarg(args, 6, 4, &arg5)) + return NULL; + if (!getishortarg(args, 6, 5, &arg6)) + return NULL; + bbox2s( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void blink short s short s short s short s short s */ + +static PyObject * +gl_blink(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + if (!getishortarg(args, 5, 0, &arg1)) + return NULL; + if (!getishortarg(args, 5, 1, &arg2)) + return NULL; + if (!getishortarg(args, 5, 2, &arg3)) + return NULL; + if (!getishortarg(args, 5, 3, &arg4)) + return NULL; + if (!getishortarg(args, 5, 4, &arg5)) + return NULL; + blink( arg1 , arg2 , arg3 , arg4 , arg5 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void ortho float s float s float s float s float s float s */ + +static PyObject * +gl_ortho(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + float arg5 ; + float arg6 ; + if (!getifloatarg(args, 6, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 6, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 6, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 6, 3, &arg4)) + return NULL; + if (!getifloatarg(args, 6, 4, &arg5)) + return NULL; + if (!getifloatarg(args, 6, 5, &arg6)) + return NULL; + ortho( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void window float s float s float s float s float s float s */ + +static PyObject * +gl_window(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + float arg5 ; + float arg6 ; + if (!getifloatarg(args, 6, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 6, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 6, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 6, 3, &arg4)) + return NULL; + if (!getifloatarg(args, 6, 4, &arg5)) + return NULL; + if (!getifloatarg(args, 6, 5, &arg6)) + return NULL; + window( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lookat float s float s float s float s float s float s short s */ + +static PyObject * +gl_lookat(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + float arg5 ; + float arg6 ; + short arg7 ; + if (!getifloatarg(args, 7, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 7, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 7, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 7, 3, &arg4)) + return NULL; + if (!getifloatarg(args, 7, 4, &arg5)) + return NULL; + if (!getifloatarg(args, 7, 5, &arg6)) + return NULL; + if (!getishortarg(args, 7, 6, &arg7)) + return NULL; + lookat( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void perspective short s float s float s float s */ + +static PyObject * +gl_perspective(PyObject *self, PyObject *args) +{ + short arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 4, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 4, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 4, 3, &arg4)) + return NULL; + perspective( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void polarview float s short s short s short s */ + +static PyObject * +gl_polarview(PyObject *self, PyObject *args) +{ + float arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getifloatarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + polarview( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void arcfs short s short s short s short s short s */ + +static PyObject * +gl_arcfs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + if (!getishortarg(args, 5, 0, &arg1)) + return NULL; + if (!getishortarg(args, 5, 1, &arg2)) + return NULL; + if (!getishortarg(args, 5, 2, &arg3)) + return NULL; + if (!getishortarg(args, 5, 3, &arg4)) + return NULL; + if (!getishortarg(args, 5, 4, &arg5)) + return NULL; + arcfs( arg1 , arg2 , arg3 , arg4 , arg5 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void arcs short s short s short s short s short s */ + +static PyObject * +gl_arcs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + if (!getishortarg(args, 5, 0, &arg1)) + return NULL; + if (!getishortarg(args, 5, 1, &arg2)) + return NULL; + if (!getishortarg(args, 5, 2, &arg3)) + return NULL; + if (!getishortarg(args, 5, 3, &arg4)) + return NULL; + if (!getishortarg(args, 5, 4, &arg5)) + return NULL; + arcs( arg1 , arg2 , arg3 , arg4 , arg5 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rectcopy short s short s short s short s short s short s */ + +static PyObject * +gl_rectcopy(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + short arg6 ; + if (!getishortarg(args, 6, 0, &arg1)) + return NULL; + if (!getishortarg(args, 6, 1, &arg2)) + return NULL; + if (!getishortarg(args, 6, 2, &arg3)) + return NULL; + if (!getishortarg(args, 6, 3, &arg4)) + return NULL; + if (!getishortarg(args, 6, 4, &arg5)) + return NULL; + if (!getishortarg(args, 6, 5, &arg6)) + return NULL; + rectcopy( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void RGBcursor short s short s short s short s short s short s short s */ + +static PyObject * +gl_RGBcursor(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + short arg6 ; + short arg7 ; + if (!getishortarg(args, 7, 0, &arg1)) + return NULL; + if (!getishortarg(args, 7, 1, &arg2)) + return NULL; + if (!getishortarg(args, 7, 2, &arg3)) + return NULL; + if (!getishortarg(args, 7, 3, &arg4)) + return NULL; + if (!getishortarg(args, 7, 4, &arg5)) + return NULL; + if (!getishortarg(args, 7, 5, &arg6)) + return NULL; + if (!getishortarg(args, 7, 6, &arg7)) + return NULL; + RGBcursor( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long getbutton short s */ + +static PyObject * +gl_getbutton(PyObject *self, PyObject *args) +{ + long retval; + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + retval = getbutton( arg1 ); + return mknewlongobject(retval); +} + +/* long getcmmode */ + +static PyObject * +gl_getcmmode(PyObject *self, PyObject *args) +{ + long retval; + retval = getcmmode( ); + return mknewlongobject(retval); +} + +/* long getlsbackup */ + +static PyObject * +gl_getlsbackup(PyObject *self, PyObject *args) +{ + long retval; + retval = getlsbackup( ); + return mknewlongobject(retval); +} + +/* long getresetls */ + +static PyObject * +gl_getresetls(PyObject *self, PyObject *args) +{ + long retval; + retval = getresetls( ); + return mknewlongobject(retval); +} + +/* long getdcm */ + +static PyObject * +gl_getdcm(PyObject *self, PyObject *args) +{ + long retval; + retval = getdcm( ); + return mknewlongobject(retval); +} + +/* long getzbuffer */ + +static PyObject * +gl_getzbuffer(PyObject *self, PyObject *args) +{ + long retval; + retval = getzbuffer( ); + return mknewlongobject(retval); +} + +/* long ismex */ + +static PyObject * +gl_ismex(PyObject *self, PyObject *args) +{ + long retval; + retval = ismex( ); + return mknewlongobject(retval); +} + +/* long isobj long s */ + +static PyObject * +gl_isobj(PyObject *self, PyObject *args) +{ + long retval; + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + retval = isobj( arg1 ); + return mknewlongobject(retval); +} + +/* long isqueued short s */ + +static PyObject * +gl_isqueued(PyObject *self, PyObject *args) +{ + long retval; + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + retval = isqueued( arg1 ); + return mknewlongobject(retval); +} + +/* long istag long s */ + +static PyObject * +gl_istag(PyObject *self, PyObject *args) +{ + long retval; + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + retval = istag( arg1 ); + return mknewlongobject(retval); +} + +/* long genobj */ + +static PyObject * +gl_genobj(PyObject *self, PyObject *args) +{ + long retval; + retval = genobj( ); + return mknewlongobject(retval); +} + +/* long gentag */ + +static PyObject * +gl_gentag(PyObject *self, PyObject *args) +{ + long retval; + retval = gentag( ); + return mknewlongobject(retval); +} + +/* long getbuffer */ + +static PyObject * +gl_getbuffer(PyObject *self, PyObject *args) +{ + long retval; + retval = getbuffer( ); + return mknewlongobject(retval); +} + +/* long getcolor */ + +static PyObject * +gl_getcolor(PyObject *self, PyObject *args) +{ + long retval; + retval = getcolor( ); + return mknewlongobject(retval); +} + +/* long getdisplaymode */ + +static PyObject * +gl_getdisplaymode(PyObject *self, PyObject *args) +{ + long retval; + retval = getdisplaymode( ); + return mknewlongobject(retval); +} + +/* long getfont */ + +static PyObject * +gl_getfont(PyObject *self, PyObject *args) +{ + long retval; + retval = getfont( ); + return mknewlongobject(retval); +} + +/* long getheight */ + +static PyObject * +gl_getheight(PyObject *self, PyObject *args) +{ + long retval; + retval = getheight( ); + return mknewlongobject(retval); +} + +/* long gethitcode */ + +static PyObject * +gl_gethitcode(PyObject *self, PyObject *args) +{ + long retval; + retval = gethitcode( ); + return mknewlongobject(retval); +} + +/* long getlstyle */ + +static PyObject * +gl_getlstyle(PyObject *self, PyObject *args) +{ + long retval; + retval = getlstyle( ); + return mknewlongobject(retval); +} + +/* long getlwidth */ + +static PyObject * +gl_getlwidth(PyObject *self, PyObject *args) +{ + long retval; + retval = getlwidth( ); + return mknewlongobject(retval); +} + +/* long getmap */ + +static PyObject * +gl_getmap(PyObject *self, PyObject *args) +{ + long retval; + retval = getmap( ); + return mknewlongobject(retval); +} + +/* long getplanes */ + +static PyObject * +gl_getplanes(PyObject *self, PyObject *args) +{ + long retval; + retval = getplanes( ); + return mknewlongobject(retval); +} + +/* long getwritemask */ + +static PyObject * +gl_getwritemask(PyObject *self, PyObject *args) +{ + long retval; + retval = getwritemask( ); + return mknewlongobject(retval); +} + +/* long qtest */ + +static PyObject * +gl_qtest(PyObject *self, PyObject *args) +{ + long retval; + retval = qtest( ); + return mknewlongobject(retval); +} + +/* long getlsrepeat */ + +static PyObject * +gl_getlsrepeat(PyObject *self, PyObject *args) +{ + long retval; + retval = getlsrepeat( ); + return mknewlongobject(retval); +} + +/* long getmonitor */ + +static PyObject * +gl_getmonitor(PyObject *self, PyObject *args) +{ + long retval; + retval = getmonitor( ); + return mknewlongobject(retval); +} + +/* long getopenobj */ + +static PyObject * +gl_getopenobj(PyObject *self, PyObject *args) +{ + long retval; + retval = getopenobj( ); + return mknewlongobject(retval); +} + +/* long getpattern */ + +static PyObject * +gl_getpattern(PyObject *self, PyObject *args) +{ + long retval; + retval = getpattern( ); + return mknewlongobject(retval); +} + +/* long winget */ + +static PyObject * +gl_winget(PyObject *self, PyObject *args) +{ + long retval; + retval = winget( ); + return mknewlongobject(retval); +} + +/* long winattach */ + +static PyObject * +gl_winattach(PyObject *self, PyObject *args) +{ + long retval; + retval = winattach( ); + return mknewlongobject(retval); +} + +/* long getothermonitor */ + +static PyObject * +gl_getothermonitor(PyObject *self, PyObject *args) +{ + long retval; + retval = getothermonitor( ); + return mknewlongobject(retval); +} + +/* long newpup */ + +static PyObject * +gl_newpup(PyObject *self, PyObject *args) +{ + long retval; + retval = newpup( ); + return mknewlongobject(retval); +} + +/* long getvaluator short s */ + +static PyObject * +gl_getvaluator(PyObject *self, PyObject *args) +{ + long retval; + short arg1 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + retval = getvaluator( arg1 ); + return mknewlongobject(retval); +} + +/* void winset long s */ + +static PyObject * +gl_winset(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + winset( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long dopup long s */ + +static PyObject * +gl_dopup(PyObject *self, PyObject *args) +{ + long retval; + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + retval = dopup( arg1 ); + return mknewlongobject(retval); +} + +/* void getdepth short r short r */ + +static PyObject * +gl_getdepth(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + getdepth( & arg1 , & arg2 ); + { PyObject *v = PyTuple_New( 2 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject(arg2)); + return v; + } +} + +/* void getcpos short r short r */ + +static PyObject * +gl_getcpos(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + getcpos( & arg1 , & arg2 ); + { PyObject *v = PyTuple_New( 2 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject(arg2)); + return v; + } +} + +/* void getsize long r long r */ + +static PyObject * +gl_getsize(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + getsize( & arg1 , & arg2 ); + { PyObject *v = PyTuple_New( 2 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewlongobject(arg1)); + PyTuple_SetItem(v, 1, mknewlongobject(arg2)); + return v; + } +} + +/* void getorigin long r long r */ + +static PyObject * +gl_getorigin(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + getorigin( & arg1 , & arg2 ); + { PyObject *v = PyTuple_New( 2 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewlongobject(arg1)); + PyTuple_SetItem(v, 1, mknewlongobject(arg2)); + return v; + } +} + +/* void getviewport short r short r short r short r */ + +static PyObject * +gl_getviewport(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + getviewport( & arg1 , & arg2 , & arg3 , & arg4 ); + { PyObject *v = PyTuple_New( 4 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject(arg2)); + PyTuple_SetItem(v, 2, mknewshortobject(arg3)); + PyTuple_SetItem(v, 3, mknewshortobject(arg4)); + return v; + } +} + +/* void gettp short r short r short r short r */ + +static PyObject * +gl_gettp(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + gettp( & arg1 , & arg2 , & arg3 , & arg4 ); + { PyObject *v = PyTuple_New( 4 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject(arg2)); + PyTuple_SetItem(v, 2, mknewshortobject(arg3)); + PyTuple_SetItem(v, 3, mknewshortobject(arg4)); + return v; + } +} + +/* void getgpos float r float r float r float r */ + +static PyObject * +gl_getgpos(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + getgpos( & arg1 , & arg2 , & arg3 , & arg4 ); + { PyObject *v = PyTuple_New( 4 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewfloatobject(arg1)); + PyTuple_SetItem(v, 1, mknewfloatobject(arg2)); + PyTuple_SetItem(v, 2, mknewfloatobject(arg3)); + PyTuple_SetItem(v, 3, mknewfloatobject(arg4)); + return v; + } +} + +/* void winposition long s long s long s long s */ + +static PyObject * +gl_winposition(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + long arg4 ; + if (!getilongarg(args, 4, 0, &arg1)) + return NULL; + if (!getilongarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + winposition( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void gRGBcolor short r short r short r */ + +static PyObject * +gl_gRGBcolor(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + gRGBcolor( & arg1 , & arg2 , & arg3 ); + { PyObject *v = PyTuple_New( 3 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject(arg2)); + PyTuple_SetItem(v, 2, mknewshortobject(arg3)); + return v; + } +} + +/* void gRGBmask short r short r short r */ + +static PyObject * +gl_gRGBmask(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + gRGBmask( & arg1 , & arg2 , & arg3 ); + { PyObject *v = PyTuple_New( 3 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject(arg2)); + PyTuple_SetItem(v, 2, mknewshortobject(arg3)); + return v; + } +} + +/* void getscrmask short r short r short r short r */ + +static PyObject * +gl_getscrmask(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + getscrmask( & arg1 , & arg2 , & arg3 , & arg4 ); + { PyObject *v = PyTuple_New( 4 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject(arg2)); + PyTuple_SetItem(v, 2, mknewshortobject(arg3)); + PyTuple_SetItem(v, 3, mknewshortobject(arg4)); + return v; + } +} + +/* void getmcolor short s short r short r short r */ + +static PyObject * +gl_getmcolor(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 1, 0, &arg1)) + return NULL; + getmcolor( arg1 , & arg2 , & arg3 , & arg4 ); + { PyObject *v = PyTuple_New( 3 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg2)); + PyTuple_SetItem(v, 1, mknewshortobject(arg3)); + PyTuple_SetItem(v, 2, mknewshortobject(arg4)); + return v; + } +} + +/* void mapw long s short s short s float r float r float r float r float r float r */ + +static PyObject * +gl_mapw(PyObject *self, PyObject *args) +{ + long arg1 ; + short arg2 ; + short arg3 ; + float arg4 ; + float arg5 ; + float arg6 ; + float arg7 ; + float arg8 ; + float arg9 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + mapw( arg1 , arg2 , arg3 , & arg4 , & arg5 , & arg6 , & arg7 , & arg8 , & arg9 ); + { PyObject *v = PyTuple_New( 6 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewfloatobject(arg4)); + PyTuple_SetItem(v, 1, mknewfloatobject(arg5)); + PyTuple_SetItem(v, 2, mknewfloatobject(arg6)); + PyTuple_SetItem(v, 3, mknewfloatobject(arg7)); + PyTuple_SetItem(v, 4, mknewfloatobject(arg8)); + PyTuple_SetItem(v, 5, mknewfloatobject(arg9)); + return v; + } +} + +/* void mapw2 long s short s short s float r float r */ + +static PyObject * +gl_mapw2(PyObject *self, PyObject *args) +{ + long arg1 ; + short arg2 ; + short arg3 ; + float arg4 ; + float arg5 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getishortarg(args, 3, 1, &arg2)) + return NULL; + if (!getishortarg(args, 3, 2, &arg3)) + return NULL; + mapw2( arg1 , arg2 , arg3 , & arg4 , & arg5 ); + { PyObject *v = PyTuple_New( 2 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewfloatobject(arg4)); + PyTuple_SetItem(v, 1, mknewfloatobject(arg5)); + return v; + } +} + +/* void getcursor short r u_short r u_short r long r */ + +static PyObject * +gl_getcursor(PyObject *self, PyObject *args) +{ + short arg1 ; + unsigned short arg2 ; + unsigned short arg3 ; + long arg4 ; + getcursor( & arg1 , & arg2 , & arg3 , & arg4 ); + { PyObject *v = PyTuple_New( 4 ); + if (v == NULL) return NULL; + PyTuple_SetItem(v, 0, mknewshortobject(arg1)); + PyTuple_SetItem(v, 1, mknewshortobject((short) arg2)); + PyTuple_SetItem(v, 2, mknewshortobject((short) arg3)); + PyTuple_SetItem(v, 3, mknewlongobject(arg4)); + return v; + } +} + +/* void cmode */ + +static PyObject * +gl_cmode(PyObject *self, PyObject *args) +{ + cmode( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void concave long s */ + +static PyObject * +gl_concave(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + concave( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void curstype long s */ + +static PyObject * +gl_curstype(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + curstype( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void drawmode long s */ + +static PyObject * +gl_drawmode(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + drawmode( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void gammaramp short s[256] short s[256] short s[256] */ + +static PyObject * +gl_gammaramp(PyObject *self, PyObject *args) +{ + short arg1 [ 256 ] ; + short arg2 [ 256 ] ; + short arg3 [ 256 ] ; + if (!getishortarray(args, 3, 0, 256 , arg1)) + return NULL; + if (!getishortarray(args, 3, 1, 256 , arg2)) + return NULL; + if (!getishortarray(args, 3, 2, 256 , arg3)) + return NULL; + gammaramp( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long getbackface */ + +static PyObject * +gl_getbackface(PyObject *self, PyObject *args) +{ + long retval; + retval = getbackface( ); + return mknewlongobject(retval); +} + +/* long getdescender */ + +static PyObject * +gl_getdescender(PyObject *self, PyObject *args) +{ + long retval; + retval = getdescender( ); + return mknewlongobject(retval); +} + +/* long getdrawmode */ + +static PyObject * +gl_getdrawmode(PyObject *self, PyObject *args) +{ + long retval; + retval = getdrawmode( ); + return mknewlongobject(retval); +} + +/* long getmmode */ + +static PyObject * +gl_getmmode(PyObject *self, PyObject *args) +{ + long retval; + retval = getmmode( ); + return mknewlongobject(retval); +} + +/* long getsm */ + +static PyObject * +gl_getsm(PyObject *self, PyObject *args) +{ + long retval; + retval = getsm( ); + return mknewlongobject(retval); +} + +/* long getvideo long s */ + +static PyObject * +gl_getvideo(PyObject *self, PyObject *args) +{ + long retval; + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + retval = getvideo( arg1 ); + return mknewlongobject(retval); +} + +/* void imakebackground */ + +static PyObject * +gl_imakebackground(PyObject *self, PyObject *args) +{ + imakebackground( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lmbind short s short s */ + +static PyObject * +gl_lmbind(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + if (!getishortarg(args, 2, 0, &arg1)) + return NULL; + if (!getishortarg(args, 2, 1, &arg2)) + return NULL; + lmbind( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lmdef long s long s long s float s[arg3] */ + +static PyObject * +gl_lmdef(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + float * arg4 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarraysize(args, 3, 2, &arg3)) + return NULL; + if ((arg4 = PyMem_NEW(float , arg3 )) == NULL) + return PyErr_NoMemory(); + if (!getifloatarray(args, 3, 2, arg3 , arg4)) + return NULL; + lmdef( arg1 , arg2 , arg3 , arg4 ); + PyMem_DEL(arg4); + Py_INCREF(Py_None); + return Py_None; +} + +/* void mmode long s */ + +static PyObject * +gl_mmode(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + mmode( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void normal float s[3] */ + +static PyObject * +gl_normal(PyObject *self, PyObject *args) +{ + float arg1 [ 3 ] ; + if (!getifloatarray(args, 1, 0, 3 , arg1)) + return NULL; + normal( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void overlay long s */ + +static PyObject * +gl_overlay(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + overlay( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void RGBrange short s short s short s short s short s short s short s short s */ + +static PyObject * +gl_RGBrange(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + short arg6 ; + short arg7 ; + short arg8 ; + if (!getishortarg(args, 8, 0, &arg1)) + return NULL; + if (!getishortarg(args, 8, 1, &arg2)) + return NULL; + if (!getishortarg(args, 8, 2, &arg3)) + return NULL; + if (!getishortarg(args, 8, 3, &arg4)) + return NULL; + if (!getishortarg(args, 8, 4, &arg5)) + return NULL; + if (!getishortarg(args, 8, 5, &arg6)) + return NULL; + if (!getishortarg(args, 8, 6, &arg7)) + return NULL; + if (!getishortarg(args, 8, 7, &arg8)) + return NULL; + RGBrange( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setvideo long s long s */ + +static PyObject * +gl_setvideo(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + setvideo( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void shademodel long s */ + +static PyObject * +gl_shademodel(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + shademodel( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void underlay long s */ + +static PyObject * +gl_underlay(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + underlay( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bgnclosedline */ + +static PyObject * +gl_bgnclosedline(PyObject *self, PyObject *args) +{ + bgnclosedline( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bgnline */ + +static PyObject * +gl_bgnline(PyObject *self, PyObject *args) +{ + bgnline( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bgnpoint */ + +static PyObject * +gl_bgnpoint(PyObject *self, PyObject *args) +{ + bgnpoint( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bgnpolygon */ + +static PyObject * +gl_bgnpolygon(PyObject *self, PyObject *args) +{ + bgnpolygon( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bgnsurface */ + +static PyObject * +gl_bgnsurface(PyObject *self, PyObject *args) +{ + bgnsurface( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bgntmesh */ + +static PyObject * +gl_bgntmesh(PyObject *self, PyObject *args) +{ + bgntmesh( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void bgntrim */ + +static PyObject * +gl_bgntrim(PyObject *self, PyObject *args) +{ + bgntrim( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endclosedline */ + +static PyObject * +gl_endclosedline(PyObject *self, PyObject *args) +{ + endclosedline( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endline */ + +static PyObject * +gl_endline(PyObject *self, PyObject *args) +{ + endline( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endpoint */ + +static PyObject * +gl_endpoint(PyObject *self, PyObject *args) +{ + endpoint( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endpolygon */ + +static PyObject * +gl_endpolygon(PyObject *self, PyObject *args) +{ + endpolygon( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endsurface */ + +static PyObject * +gl_endsurface(PyObject *self, PyObject *args) +{ + endsurface( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endtmesh */ + +static PyObject * +gl_endtmesh(PyObject *self, PyObject *args) +{ + endtmesh( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void endtrim */ + +static PyObject * +gl_endtrim(PyObject *self, PyObject *args) +{ + endtrim( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void blendfunction long s long s */ + +static PyObject * +gl_blendfunction(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + blendfunction( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void c3f float s[3] */ + +static PyObject * +gl_c3f(PyObject *self, PyObject *args) +{ + float arg1 [ 3 ] ; + if (!getifloatarray(args, 1, 0, 3 , arg1)) + return NULL; + c3f( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void c3i long s[3] */ + +static PyObject * +gl_c3i(PyObject *self, PyObject *args) +{ + long arg1 [ 3 ] ; + if (!getilongarray(args, 1, 0, 3 , arg1)) + return NULL; + c3i( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void c3s short s[3] */ + +static PyObject * +gl_c3s(PyObject *self, PyObject *args) +{ + short arg1 [ 3 ] ; + if (!getishortarray(args, 1, 0, 3 , arg1)) + return NULL; + c3s( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void c4f float s[4] */ + +static PyObject * +gl_c4f(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] ; + if (!getifloatarray(args, 1, 0, 4 , arg1)) + return NULL; + c4f( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void c4i long s[4] */ + +static PyObject * +gl_c4i(PyObject *self, PyObject *args) +{ + long arg1 [ 4 ] ; + if (!getilongarray(args, 1, 0, 4 , arg1)) + return NULL; + c4i( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void c4s short s[4] */ + +static PyObject * +gl_c4s(PyObject *self, PyObject *args) +{ + short arg1 [ 4 ] ; + if (!getishortarray(args, 1, 0, 4 , arg1)) + return NULL; + c4s( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void colorf float s */ + +static PyObject * +gl_colorf(PyObject *self, PyObject *args) +{ + float arg1 ; + if (!getifloatarg(args, 1, 0, &arg1)) + return NULL; + colorf( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void cpack long s */ + +static PyObject * +gl_cpack(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + cpack( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void czclear long s long s */ + +static PyObject * +gl_czclear(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + czclear( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void dglclose long s */ + +static PyObject * +gl_dglclose(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + dglclose( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long dglopen char *s long s */ + +static PyObject * +gl_dglopen(PyObject *self, PyObject *args) +{ + long retval; + string arg1 ; + long arg2 ; + if (!getistringarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + retval = dglopen( arg1 , arg2 ); + return mknewlongobject(retval); +} + +/* long getgdesc long s */ + +static PyObject * +gl_getgdesc(PyObject *self, PyObject *args) +{ + long retval; + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + retval = getgdesc( arg1 ); + return mknewlongobject(retval); +} + +/* void getnurbsproperty long s float r */ + +static PyObject * +gl_getnurbsproperty(PyObject *self, PyObject *args) +{ + long arg1 ; + float arg2 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + getnurbsproperty( arg1 , & arg2 ); + return mknewfloatobject(arg2); +} + +/* void glcompat long s long s */ + +static PyObject * +gl_glcompat(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + glcompat( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void iconsize long s long s */ + +static PyObject * +gl_iconsize(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + iconsize( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void icontitle char *s */ + +static PyObject * +gl_icontitle(PyObject *self, PyObject *args) +{ + string arg1 ; + if (!getistringarg(args, 1, 0, &arg1)) + return NULL; + icontitle( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lRGBrange short s short s short s short s short s short s long s long s */ + +static PyObject * +gl_lRGBrange(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + short arg5 ; + short arg6 ; + long arg7 ; + long arg8 ; + if (!getishortarg(args, 8, 0, &arg1)) + return NULL; + if (!getishortarg(args, 8, 1, &arg2)) + return NULL; + if (!getishortarg(args, 8, 2, &arg3)) + return NULL; + if (!getishortarg(args, 8, 3, &arg4)) + return NULL; + if (!getishortarg(args, 8, 4, &arg5)) + return NULL; + if (!getishortarg(args, 8, 5, &arg6)) + return NULL; + if (!getilongarg(args, 8, 6, &arg7)) + return NULL; + if (!getilongarg(args, 8, 7, &arg8)) + return NULL; + lRGBrange( arg1 , arg2 , arg3 , arg4 , arg5 , arg6 , arg7 , arg8 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void linesmooth long s */ + +static PyObject * +gl_linesmooth(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + linesmooth( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lmcolor long s */ + +static PyObject * +gl_lmcolor(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + lmcolor( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void logicop long s */ + +static PyObject * +gl_logicop(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + logicop( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lsetdepth long s long s */ + +static PyObject * +gl_lsetdepth(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + lsetdepth( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void lshaderange short s short s long s long s */ + +static PyObject * +gl_lshaderange(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + long arg3 ; + long arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + lshaderange( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void n3f float s[3] */ + +static PyObject * +gl_n3f(PyObject *self, PyObject *args) +{ + float arg1 [ 3 ] ; + if (!getifloatarray(args, 1, 0, 3 , arg1)) + return NULL; + n3f( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void noborder */ + +static PyObject * +gl_noborder(PyObject *self, PyObject *args) +{ + noborder( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pntsmooth long s */ + +static PyObject * +gl_pntsmooth(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + pntsmooth( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void readsource long s */ + +static PyObject * +gl_readsource(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + readsource( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void rectzoom float s float s */ + +static PyObject * +gl_rectzoom(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + if (!getifloatarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + rectzoom( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void sbox float s float s float s float s */ + +static PyObject * +gl_sbox(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + if (!getifloatarg(args, 4, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 4, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 4, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 4, 3, &arg4)) + return NULL; + sbox( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void sboxi long s long s long s long s */ + +static PyObject * +gl_sboxi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + long arg4 ; + if (!getilongarg(args, 4, 0, &arg1)) + return NULL; + if (!getilongarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + sboxi( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void sboxs short s short s short s short s */ + +static PyObject * +gl_sboxs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + sboxs( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void sboxf float s float s float s float s */ + +static PyObject * +gl_sboxf(PyObject *self, PyObject *args) +{ + float arg1 ; + float arg2 ; + float arg3 ; + float arg4 ; + if (!getifloatarg(args, 4, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 4, 1, &arg2)) + return NULL; + if (!getifloatarg(args, 4, 2, &arg3)) + return NULL; + if (!getifloatarg(args, 4, 3, &arg4)) + return NULL; + sboxf( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void sboxfi long s long s long s long s */ + +static PyObject * +gl_sboxfi(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + long arg4 ; + if (!getilongarg(args, 4, 0, &arg1)) + return NULL; + if (!getilongarg(args, 4, 1, &arg2)) + return NULL; + if (!getilongarg(args, 4, 2, &arg3)) + return NULL; + if (!getilongarg(args, 4, 3, &arg4)) + return NULL; + sboxfi( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void sboxfs short s short s short s short s */ + +static PyObject * +gl_sboxfs(PyObject *self, PyObject *args) +{ + short arg1 ; + short arg2 ; + short arg3 ; + short arg4 ; + if (!getishortarg(args, 4, 0, &arg1)) + return NULL; + if (!getishortarg(args, 4, 1, &arg2)) + return NULL; + if (!getishortarg(args, 4, 2, &arg3)) + return NULL; + if (!getishortarg(args, 4, 3, &arg4)) + return NULL; + sboxfs( arg1 , arg2 , arg3 , arg4 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setnurbsproperty long s float s */ + +static PyObject * +gl_setnurbsproperty(PyObject *self, PyObject *args) +{ + long arg1 ; + float arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getifloatarg(args, 2, 1, &arg2)) + return NULL; + setnurbsproperty( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void setpup long s long s long s */ + +static PyObject * +gl_setpup(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + long arg3 ; + if (!getilongarg(args, 3, 0, &arg1)) + return NULL; + if (!getilongarg(args, 3, 1, &arg2)) + return NULL; + if (!getilongarg(args, 3, 2, &arg3)) + return NULL; + setpup( arg1 , arg2 , arg3 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void smoothline long s */ + +static PyObject * +gl_smoothline(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + smoothline( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void subpixel long s */ + +static PyObject * +gl_subpixel(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + subpixel( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void swaptmesh */ + +static PyObject * +gl_swaptmesh(PyObject *self, PyObject *args) +{ + swaptmesh( ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long swinopen long s */ + +static PyObject * +gl_swinopen(PyObject *self, PyObject *args) +{ + long retval; + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + retval = swinopen( arg1 ); + return mknewlongobject(retval); +} + +/* void v2f float s[2] */ + +static PyObject * +gl_v2f(PyObject *self, PyObject *args) +{ + float arg1 [ 2 ] ; + if (!getifloatarray(args, 1, 0, 2 , arg1)) + return NULL; + v2f( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v2i long s[2] */ + +static PyObject * +gl_v2i(PyObject *self, PyObject *args) +{ + long arg1 [ 2 ] ; + if (!getilongarray(args, 1, 0, 2 , arg1)) + return NULL; + v2i( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v2s short s[2] */ + +static PyObject * +gl_v2s(PyObject *self, PyObject *args) +{ + short arg1 [ 2 ] ; + if (!getishortarray(args, 1, 0, 2 , arg1)) + return NULL; + v2s( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v3f float s[3] */ + +static PyObject * +gl_v3f(PyObject *self, PyObject *args) +{ + float arg1 [ 3 ] ; + if (!getifloatarray(args, 1, 0, 3 , arg1)) + return NULL; + v3f( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v3i long s[3] */ + +static PyObject * +gl_v3i(PyObject *self, PyObject *args) +{ + long arg1 [ 3 ] ; + if (!getilongarray(args, 1, 0, 3 , arg1)) + return NULL; + v3i( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v3s short s[3] */ + +static PyObject * +gl_v3s(PyObject *self, PyObject *args) +{ + short arg1 [ 3 ] ; + if (!getishortarray(args, 1, 0, 3 , arg1)) + return NULL; + v3s( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v4f float s[4] */ + +static PyObject * +gl_v4f(PyObject *self, PyObject *args) +{ + float arg1 [ 4 ] ; + if (!getifloatarray(args, 1, 0, 4 , arg1)) + return NULL; + v4f( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v4i long s[4] */ + +static PyObject * +gl_v4i(PyObject *self, PyObject *args) +{ + long arg1 [ 4 ] ; + if (!getilongarray(args, 1, 0, 4 , arg1)) + return NULL; + v4i( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v4s short s[4] */ + +static PyObject * +gl_v4s(PyObject *self, PyObject *args) +{ + short arg1 [ 4 ] ; + if (!getishortarray(args, 1, 0, 4 , arg1)) + return NULL; + v4s( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void videocmd long s */ + +static PyObject * +gl_videocmd(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + videocmd( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long windepth long s */ + +static PyObject * +gl_windepth(PyObject *self, PyObject *args) +{ + long retval; + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + retval = windepth( arg1 ); + return mknewlongobject(retval); +} + +/* void wmpack long s */ + +static PyObject * +gl_wmpack(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + wmpack( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void zdraw long s */ + +static PyObject * +gl_zdraw(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + zdraw( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void zfunction long s */ + +static PyObject * +gl_zfunction(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + zfunction( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void zsource long s */ + +static PyObject * +gl_zsource(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + zsource( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void zwritemask long s */ + +static PyObject * +gl_zwritemask(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + zwritemask( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v2d double s[2] */ + +static PyObject * +gl_v2d(PyObject *self, PyObject *args) +{ + double arg1 [ 2 ] ; + if (!getidoublearray(args, 1, 0, 2 , arg1)) + return NULL; + v2d( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v3d double s[3] */ + +static PyObject * +gl_v3d(PyObject *self, PyObject *args) +{ + double arg1 [ 3 ] ; + if (!getidoublearray(args, 1, 0, 3 , arg1)) + return NULL; + v3d( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void v4d double s[4] */ + +static PyObject * +gl_v4d(PyObject *self, PyObject *args) +{ + double arg1 [ 4 ] ; + if (!getidoublearray(args, 1, 0, 4 , arg1)) + return NULL; + v4d( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* void pixmode long s long s */ + +static PyObject * +gl_pixmode(PyObject *self, PyObject *args) +{ + long arg1 ; + long arg2 ; + if (!getilongarg(args, 2, 0, &arg1)) + return NULL; + if (!getilongarg(args, 2, 1, &arg2)) + return NULL; + pixmode( arg1 , arg2 ); + Py_INCREF(Py_None); + return Py_None; +} + +/* long qgetfd */ + +static PyObject * +gl_qgetfd(PyObject *self, PyObject *args) +{ + long retval; + retval = qgetfd( ); + return mknewlongobject(retval); +} + +/* void dither long s */ + +static PyObject * +gl_dither(PyObject *self, PyObject *args) +{ + long arg1 ; + if (!getilongarg(args, 1, 0, &arg1)) + return NULL; + dither( arg1 ); + Py_INCREF(Py_None); + return Py_None; +} + +static struct PyMethodDef gl_methods[] = { + {"qread", gl_qread, METH_OLDARGS}, + {"varray", gl_varray, METH_OLDARGS}, + {"nvarray", gl_nvarray, METH_OLDARGS}, + {"vnarray", gl_vnarray, METH_OLDARGS}, + {"nurbssurface", gl_nurbssurface, METH_OLDARGS}, + {"nurbscurve", gl_nurbscurve, METH_OLDARGS}, + {"pwlcurve", gl_pwlcurve, METH_OLDARGS}, + {"pick", gl_pick, METH_OLDARGS}, + {"endpick", gl_endpick, METH_NOARGS}, + {"gselect", gl_gselect, METH_OLDARGS}, + {"endselect", gl_endselect, METH_NOARGS}, + {"getmatrix", gl_getmatrix, METH_OLDARGS}, + {"altgetmatrix", gl_altgetmatrix, METH_OLDARGS}, + {"lrectwrite", gl_lrectwrite, METH_OLDARGS}, + {"lrectread", gl_lrectread, METH_OLDARGS}, + {"readdisplay", gl_readdisplay, METH_OLDARGS}, + {"packrect", gl_packrect, METH_OLDARGS}, + {"unpackrect", gl_unpackrect, METH_OLDARGS}, + {"gversion", gl_gversion, METH_OLDARGS}, + {"clear", gl_clear, METH_OLDARGS}, + {"getshade", gl_getshade, METH_OLDARGS}, + {"devport", gl_devport, METH_OLDARGS}, + {"rdr2i", gl_rdr2i, METH_OLDARGS}, + {"rectfs", gl_rectfs, METH_OLDARGS}, + {"rects", gl_rects, METH_OLDARGS}, + {"rmv2i", gl_rmv2i, METH_OLDARGS}, + {"noport", gl_noport, METH_OLDARGS}, + {"popviewport", gl_popviewport, METH_OLDARGS}, + {"clearhitcode", gl_clearhitcode, METH_OLDARGS}, + {"closeobj", gl_closeobj, METH_OLDARGS}, + {"cursoff", gl_cursoff, METH_OLDARGS}, + {"curson", gl_curson, METH_OLDARGS}, + {"doublebuffer", gl_doublebuffer, METH_OLDARGS}, + {"finish", gl_finish, METH_OLDARGS}, + {"gconfig", gl_gconfig, METH_OLDARGS}, + {"ginit", gl_ginit, METH_OLDARGS}, + {"greset", gl_greset, METH_OLDARGS}, + {"multimap", gl_multimap, METH_OLDARGS}, + {"onemap", gl_onemap, METH_OLDARGS}, + {"popattributes", gl_popattributes, METH_OLDARGS}, + {"popmatrix", gl_popmatrix, METH_OLDARGS}, + {"pushattributes", gl_pushattributes,METH_OLDARGS}, + {"pushmatrix", gl_pushmatrix, METH_OLDARGS}, + {"pushviewport", gl_pushviewport, METH_OLDARGS}, + {"qreset", gl_qreset, METH_OLDARGS}, + {"RGBmode", gl_RGBmode, METH_OLDARGS}, + {"singlebuffer", gl_singlebuffer, METH_OLDARGS}, + {"swapbuffers", gl_swapbuffers, METH_OLDARGS}, + {"gsync", gl_gsync, METH_OLDARGS}, + {"gflush", gl_gflush, METH_OLDARGS}, + {"tpon", gl_tpon, METH_OLDARGS}, + {"tpoff", gl_tpoff, METH_OLDARGS}, + {"clkon", gl_clkon, METH_OLDARGS}, + {"clkoff", gl_clkoff, METH_OLDARGS}, + {"ringbell", gl_ringbell, METH_OLDARGS}, + {"gbegin", gl_gbegin, METH_OLDARGS}, + {"textinit", gl_textinit, METH_OLDARGS}, + {"initnames", gl_initnames, METH_OLDARGS}, + {"pclos", gl_pclos, METH_OLDARGS}, + {"popname", gl_popname, METH_OLDARGS}, + {"spclos", gl_spclos, METH_OLDARGS}, + {"zclear", gl_zclear, METH_OLDARGS}, + {"screenspace", gl_screenspace, METH_OLDARGS}, + {"reshapeviewport", gl_reshapeviewport, METH_OLDARGS}, + {"winpush", gl_winpush, METH_OLDARGS}, + {"winpop", gl_winpop, METH_OLDARGS}, + {"foreground", gl_foreground, METH_OLDARGS}, + {"endfullscrn", gl_endfullscrn, METH_OLDARGS}, + {"endpupmode", gl_endpupmode, METH_OLDARGS}, + {"fullscrn", gl_fullscrn, METH_OLDARGS}, + {"pupmode", gl_pupmode, METH_OLDARGS}, + {"winconstraints", gl_winconstraints, METH_OLDARGS}, + {"pagecolor", gl_pagecolor, METH_OLDARGS}, + {"textcolor", gl_textcolor, METH_OLDARGS}, + {"color", gl_color, METH_OLDARGS}, + {"curveit", gl_curveit, METH_OLDARGS}, + {"font", gl_font, METH_OLDARGS}, + {"linewidth", gl_linewidth, METH_OLDARGS}, + {"setlinestyle", gl_setlinestyle, METH_OLDARGS}, + {"setmap", gl_setmap, METH_OLDARGS}, + {"swapinterval", gl_swapinterval, METH_OLDARGS}, + {"writemask", gl_writemask, METH_OLDARGS}, + {"textwritemask", gl_textwritemask, METH_OLDARGS}, + {"qdevice", gl_qdevice, METH_OLDARGS}, + {"unqdevice", gl_unqdevice, METH_OLDARGS}, + {"curvebasis", gl_curvebasis, METH_OLDARGS}, + {"curveprecision", gl_curveprecision,METH_OLDARGS}, + {"loadname", gl_loadname, METH_OLDARGS}, + {"passthrough", gl_passthrough, METH_OLDARGS}, + {"pushname", gl_pushname, METH_OLDARGS}, + {"setmonitor", gl_setmonitor, METH_OLDARGS}, + {"setshade", gl_setshade, METH_OLDARGS}, + {"setpattern", gl_setpattern, METH_OLDARGS}, + {"pagewritemask", gl_pagewritemask, METH_OLDARGS}, + {"callobj", gl_callobj, METH_OLDARGS}, + {"delobj", gl_delobj, METH_OLDARGS}, + {"editobj", gl_editobj, METH_OLDARGS}, + {"makeobj", gl_makeobj, METH_OLDARGS}, + {"maketag", gl_maketag, METH_OLDARGS}, + {"chunksize", gl_chunksize, METH_OLDARGS}, + {"compactify", gl_compactify, METH_OLDARGS}, + {"deltag", gl_deltag, METH_OLDARGS}, + {"lsrepeat", gl_lsrepeat, METH_OLDARGS}, + {"objinsert", gl_objinsert, METH_OLDARGS}, + {"objreplace", gl_objreplace, METH_OLDARGS}, + {"winclose", gl_winclose, METH_OLDARGS}, + {"blanktime", gl_blanktime, METH_OLDARGS}, + {"freepup", gl_freepup, METH_OLDARGS}, + {"backbuffer", gl_backbuffer, METH_OLDARGS}, + {"frontbuffer", gl_frontbuffer, METH_OLDARGS}, + {"lsbackup", gl_lsbackup, METH_OLDARGS}, + {"resetls", gl_resetls, METH_OLDARGS}, + {"lampon", gl_lampon, METH_OLDARGS}, + {"lampoff", gl_lampoff, METH_OLDARGS}, + {"setbell", gl_setbell, METH_OLDARGS}, + {"blankscreen", gl_blankscreen, METH_OLDARGS}, + {"depthcue", gl_depthcue, METH_OLDARGS}, + {"zbuffer", gl_zbuffer, METH_OLDARGS}, + {"backface", gl_backface, METH_OLDARGS}, + {"cmov2i", gl_cmov2i, METH_OLDARGS}, + {"draw2i", gl_draw2i, METH_OLDARGS}, + {"move2i", gl_move2i, METH_OLDARGS}, + {"pnt2i", gl_pnt2i, METH_OLDARGS}, + {"patchbasis", gl_patchbasis, METH_OLDARGS}, + {"patchprecision", gl_patchprecision, METH_OLDARGS}, + {"pdr2i", gl_pdr2i, METH_OLDARGS}, + {"pmv2i", gl_pmv2i, METH_OLDARGS}, + {"rpdr2i", gl_rpdr2i, METH_OLDARGS}, + {"rpmv2i", gl_rpmv2i, METH_OLDARGS}, + {"xfpt2i", gl_xfpt2i, METH_OLDARGS}, + {"objdelete", gl_objdelete, METH_OLDARGS}, + {"patchcurves", gl_patchcurves, METH_OLDARGS}, + {"minsize", gl_minsize, METH_OLDARGS}, + {"maxsize", gl_maxsize, METH_OLDARGS}, + {"keepaspect", gl_keepaspect, METH_OLDARGS}, + {"prefsize", gl_prefsize, METH_OLDARGS}, + {"stepunit", gl_stepunit, METH_OLDARGS}, + {"fudge", gl_fudge, METH_OLDARGS}, + {"winmove", gl_winmove, METH_OLDARGS}, + {"attachcursor", gl_attachcursor, METH_OLDARGS}, + {"deflinestyle", gl_deflinestyle, METH_OLDARGS}, + {"noise", gl_noise, METH_OLDARGS}, + {"picksize", gl_picksize, METH_OLDARGS}, + {"qenter", gl_qenter, METH_OLDARGS}, + {"setdepth", gl_setdepth, METH_OLDARGS}, + {"cmov2s", gl_cmov2s, METH_OLDARGS}, + {"draw2s", gl_draw2s, METH_OLDARGS}, + {"move2s", gl_move2s, METH_OLDARGS}, + {"pdr2s", gl_pdr2s, METH_OLDARGS}, + {"pmv2s", gl_pmv2s, METH_OLDARGS}, + {"pnt2s", gl_pnt2s, METH_OLDARGS}, + {"rdr2s", gl_rdr2s, METH_OLDARGS}, + {"rmv2s", gl_rmv2s, METH_OLDARGS}, + {"rpdr2s", gl_rpdr2s, METH_OLDARGS}, + {"rpmv2s", gl_rpmv2s, METH_OLDARGS}, + {"xfpt2s", gl_xfpt2s, METH_OLDARGS}, + {"cmov2", gl_cmov2, METH_OLDARGS}, + {"draw2", gl_draw2, METH_OLDARGS}, + {"move2", gl_move2, METH_OLDARGS}, + {"pnt2", gl_pnt2, METH_OLDARGS}, + {"pdr2", gl_pdr2, METH_OLDARGS}, + {"pmv2", gl_pmv2, METH_OLDARGS}, + {"rdr2", gl_rdr2, METH_OLDARGS}, + {"rmv2", gl_rmv2, METH_OLDARGS}, + {"rpdr2", gl_rpdr2, METH_OLDARGS}, + {"rpmv2", gl_rpmv2, METH_OLDARGS}, + {"xfpt2", gl_xfpt2, METH_OLDARGS}, + {"loadmatrix", gl_loadmatrix, METH_OLDARGS}, + {"multmatrix", gl_multmatrix, METH_OLDARGS}, + {"crv", gl_crv, METH_OLDARGS}, + {"rcrv", gl_rcrv, METH_OLDARGS}, + {"addtopup", gl_addtopup, METH_OLDARGS}, + {"charstr", gl_charstr, METH_OLDARGS}, + {"getport", gl_getport, METH_OLDARGS}, + {"strwidth", gl_strwidth, METH_OLDARGS}, + {"winopen", gl_winopen, METH_OLDARGS}, + {"wintitle", gl_wintitle, METH_OLDARGS}, + {"polf", gl_polf, METH_OLDARGS}, + {"polf2", gl_polf2, METH_OLDARGS}, + {"poly", gl_poly, METH_OLDARGS}, + {"poly2", gl_poly2, METH_OLDARGS}, + {"crvn", gl_crvn, METH_OLDARGS}, + {"rcrvn", gl_rcrvn, METH_OLDARGS}, + {"polf2i", gl_polf2i, METH_OLDARGS}, + {"polfi", gl_polfi, METH_OLDARGS}, + {"poly2i", gl_poly2i, METH_OLDARGS}, + {"polyi", gl_polyi, METH_OLDARGS}, + {"polf2s", gl_polf2s, METH_OLDARGS}, + {"polfs", gl_polfs, METH_OLDARGS}, + {"polys", gl_polys, METH_OLDARGS}, + {"poly2s", gl_poly2s, METH_OLDARGS}, + {"defcursor", gl_defcursor, METH_OLDARGS}, + {"writepixels", gl_writepixels, METH_OLDARGS}, + {"defbasis", gl_defbasis, METH_OLDARGS}, + {"gewrite", gl_gewrite, METH_OLDARGS}, + {"rotate", gl_rotate, METH_OLDARGS}, + {"rot", gl_rot, METH_OLDARGS}, + {"circfi", gl_circfi, METH_OLDARGS}, + {"circi", gl_circi, METH_OLDARGS}, + {"cmovi", gl_cmovi, METH_OLDARGS}, + {"drawi", gl_drawi, METH_OLDARGS}, + {"movei", gl_movei, METH_OLDARGS}, + {"pnti", gl_pnti, METH_OLDARGS}, + {"newtag", gl_newtag, METH_OLDARGS}, + {"pdri", gl_pdri, METH_OLDARGS}, + {"pmvi", gl_pmvi, METH_OLDARGS}, + {"rdri", gl_rdri, METH_OLDARGS}, + {"rmvi", gl_rmvi, METH_OLDARGS}, + {"rpdri", gl_rpdri, METH_OLDARGS}, + {"rpmvi", gl_rpmvi, METH_OLDARGS}, + {"xfpti", gl_xfpti, METH_OLDARGS}, + {"circ", gl_circ, METH_OLDARGS}, + {"circf", gl_circf, METH_OLDARGS}, + {"cmov", gl_cmov, METH_OLDARGS}, + {"draw", gl_draw, METH_OLDARGS}, + {"move", gl_move, METH_OLDARGS}, + {"pnt", gl_pnt, METH_OLDARGS}, + {"scale", gl_scale, METH_OLDARGS}, + {"translate", gl_translate, METH_OLDARGS}, + {"pdr", gl_pdr, METH_OLDARGS}, + {"pmv", gl_pmv, METH_OLDARGS}, + {"rdr", gl_rdr, METH_OLDARGS}, + {"rmv", gl_rmv, METH_OLDARGS}, + {"rpdr", gl_rpdr, METH_OLDARGS}, + {"rpmv", gl_rpmv, METH_OLDARGS}, + {"xfpt", gl_xfpt, METH_OLDARGS}, + {"RGBcolor", gl_RGBcolor, METH_OLDARGS}, + {"RGBwritemask", gl_RGBwritemask, METH_OLDARGS}, + {"setcursor", gl_setcursor, METH_OLDARGS}, + {"tie", gl_tie, METH_OLDARGS}, + {"circfs", gl_circfs, METH_OLDARGS}, + {"circs", gl_circs, METH_OLDARGS}, + {"cmovs", gl_cmovs, METH_OLDARGS}, + {"draws", gl_draws, METH_OLDARGS}, + {"moves", gl_moves, METH_OLDARGS}, + {"pdrs", gl_pdrs, METH_OLDARGS}, + {"pmvs", gl_pmvs, METH_OLDARGS}, + {"pnts", gl_pnts, METH_OLDARGS}, + {"rdrs", gl_rdrs, METH_OLDARGS}, + {"rmvs", gl_rmvs, METH_OLDARGS}, + {"rpdrs", gl_rpdrs, METH_OLDARGS}, + {"rpmvs", gl_rpmvs, METH_OLDARGS}, + {"xfpts", gl_xfpts, METH_OLDARGS}, + {"curorigin", gl_curorigin, METH_OLDARGS}, + {"cyclemap", gl_cyclemap, METH_OLDARGS}, + {"patch", gl_patch, METH_OLDARGS}, + {"splf", gl_splf, METH_OLDARGS}, + {"splf2", gl_splf2, METH_OLDARGS}, + {"splfi", gl_splfi, METH_OLDARGS}, + {"splf2i", gl_splf2i, METH_OLDARGS}, + {"splfs", gl_splfs, METH_OLDARGS}, + {"splf2s", gl_splf2s, METH_OLDARGS}, + {"rpatch", gl_rpatch, METH_OLDARGS}, + {"ortho2", gl_ortho2, METH_OLDARGS}, + {"rect", gl_rect, METH_OLDARGS}, + {"rectf", gl_rectf, METH_OLDARGS}, + {"xfpt4", gl_xfpt4, METH_OLDARGS}, + {"textport", gl_textport, METH_OLDARGS}, + {"mapcolor", gl_mapcolor, METH_OLDARGS}, + {"scrmask", gl_scrmask, METH_OLDARGS}, + {"setvaluator", gl_setvaluator, METH_OLDARGS}, + {"viewport", gl_viewport, METH_OLDARGS}, + {"shaderange", gl_shaderange, METH_OLDARGS}, + {"xfpt4s", gl_xfpt4s, METH_OLDARGS}, + {"rectfi", gl_rectfi, METH_OLDARGS}, + {"recti", gl_recti, METH_OLDARGS}, + {"xfpt4i", gl_xfpt4i, METH_OLDARGS}, + {"prefposition", gl_prefposition, METH_OLDARGS}, + {"arc", gl_arc, METH_OLDARGS}, + {"arcf", gl_arcf, METH_OLDARGS}, + {"arcfi", gl_arcfi, METH_OLDARGS}, + {"arci", gl_arci, METH_OLDARGS}, + {"bbox2", gl_bbox2, METH_OLDARGS}, + {"bbox2i", gl_bbox2i, METH_OLDARGS}, + {"bbox2s", gl_bbox2s, METH_OLDARGS}, + {"blink", gl_blink, METH_OLDARGS}, + {"ortho", gl_ortho, METH_OLDARGS}, + {"window", gl_window, METH_OLDARGS}, + {"lookat", gl_lookat, METH_OLDARGS}, + {"perspective", gl_perspective, METH_OLDARGS}, + {"polarview", gl_polarview, METH_OLDARGS}, + {"arcfs", gl_arcfs, METH_OLDARGS}, + {"arcs", gl_arcs, METH_OLDARGS}, + {"rectcopy", gl_rectcopy, METH_OLDARGS}, + {"RGBcursor", gl_RGBcursor, METH_OLDARGS}, + {"getbutton", gl_getbutton, METH_OLDARGS}, + {"getcmmode", gl_getcmmode, METH_OLDARGS}, + {"getlsbackup", gl_getlsbackup, METH_OLDARGS}, + {"getresetls", gl_getresetls, METH_OLDARGS}, + {"getdcm", gl_getdcm, METH_OLDARGS}, + {"getzbuffer", gl_getzbuffer, METH_OLDARGS}, + {"ismex", gl_ismex, METH_OLDARGS}, + {"isobj", gl_isobj, METH_OLDARGS}, + {"isqueued", gl_isqueued, METH_OLDARGS}, + {"istag", gl_istag, METH_OLDARGS}, + {"genobj", gl_genobj, METH_OLDARGS}, + {"gentag", gl_gentag, METH_OLDARGS}, + {"getbuffer", gl_getbuffer, METH_OLDARGS}, + {"getcolor", gl_getcolor, METH_OLDARGS}, + {"getdisplaymode", gl_getdisplaymode, METH_OLDARGS}, + {"getfont", gl_getfont, METH_OLDARGS}, + {"getheight", gl_getheight, METH_OLDARGS}, + {"gethitcode", gl_gethitcode, METH_OLDARGS}, + {"getlstyle", gl_getlstyle, METH_OLDARGS}, + {"getlwidth", gl_getlwidth, METH_OLDARGS}, + {"getmap", gl_getmap, METH_OLDARGS}, + {"getplanes", gl_getplanes, METH_OLDARGS}, + {"getwritemask", gl_getwritemask, METH_OLDARGS}, + {"qtest", gl_qtest, METH_OLDARGS}, + {"getlsrepeat", gl_getlsrepeat, METH_OLDARGS}, + {"getmonitor", gl_getmonitor, METH_OLDARGS}, + {"getopenobj", gl_getopenobj, METH_OLDARGS}, + {"getpattern", gl_getpattern, METH_OLDARGS}, + {"winget", gl_winget, METH_OLDARGS}, + {"winattach", gl_winattach, METH_OLDARGS}, + {"getothermonitor", gl_getothermonitor, METH_OLDARGS}, + {"newpup", gl_newpup, METH_OLDARGS}, + {"getvaluator", gl_getvaluator, METH_OLDARGS}, + {"winset", gl_winset, METH_OLDARGS}, + {"dopup", gl_dopup, METH_OLDARGS}, + {"getdepth", gl_getdepth, METH_OLDARGS}, + {"getcpos", gl_getcpos, METH_OLDARGS}, + {"getsize", gl_getsize, METH_OLDARGS}, + {"getorigin", gl_getorigin, METH_OLDARGS}, + {"getviewport", gl_getviewport, METH_OLDARGS}, + {"gettp", gl_gettp, METH_OLDARGS}, + {"getgpos", gl_getgpos, METH_OLDARGS}, + {"winposition", gl_winposition, METH_OLDARGS}, + {"gRGBcolor", gl_gRGBcolor, METH_OLDARGS}, + {"gRGBmask", gl_gRGBmask, METH_OLDARGS}, + {"getscrmask", gl_getscrmask, METH_OLDARGS}, + {"getmcolor", gl_getmcolor, METH_OLDARGS}, + {"mapw", gl_mapw, METH_OLDARGS}, + {"mapw2", gl_mapw2, METH_OLDARGS}, + {"getcursor", gl_getcursor, METH_OLDARGS}, + {"cmode", gl_cmode, METH_OLDARGS}, + {"concave", gl_concave, METH_OLDARGS}, + {"curstype", gl_curstype, METH_OLDARGS}, + {"drawmode", gl_drawmode, METH_OLDARGS}, + {"gammaramp", gl_gammaramp, METH_OLDARGS}, + {"getbackface", gl_getbackface, METH_OLDARGS}, + {"getdescender", gl_getdescender, METH_OLDARGS}, + {"getdrawmode", gl_getdrawmode, METH_OLDARGS}, + {"getmmode", gl_getmmode, METH_OLDARGS}, + {"getsm", gl_getsm, METH_OLDARGS}, + {"getvideo", gl_getvideo, METH_OLDARGS}, + {"imakebackground", gl_imakebackground, METH_OLDARGS}, + {"lmbind", gl_lmbind, METH_OLDARGS}, + {"lmdef", gl_lmdef, METH_OLDARGS}, + {"mmode", gl_mmode, METH_OLDARGS}, + {"normal", gl_normal, METH_OLDARGS}, + {"overlay", gl_overlay, METH_OLDARGS}, + {"RGBrange", gl_RGBrange, METH_OLDARGS}, + {"setvideo", gl_setvideo, METH_OLDARGS}, + {"shademodel", gl_shademodel, METH_OLDARGS}, + {"underlay", gl_underlay, METH_OLDARGS}, + {"bgnclosedline", gl_bgnclosedline, METH_OLDARGS}, + {"bgnline", gl_bgnline, METH_OLDARGS}, + {"bgnpoint", gl_bgnpoint, METH_OLDARGS}, + {"bgnpolygon", gl_bgnpolygon, METH_OLDARGS}, + {"bgnsurface", gl_bgnsurface, METH_OLDARGS}, + {"bgntmesh", gl_bgntmesh, METH_OLDARGS}, + {"bgntrim", gl_bgntrim, METH_OLDARGS}, + {"endclosedline", gl_endclosedline, METH_OLDARGS}, + {"endline", gl_endline, METH_OLDARGS}, + {"endpoint", gl_endpoint, METH_OLDARGS}, + {"endpolygon", gl_endpolygon, METH_OLDARGS}, + {"endsurface", gl_endsurface, METH_OLDARGS}, + {"endtmesh", gl_endtmesh, METH_OLDARGS}, + {"endtrim", gl_endtrim, METH_OLDARGS}, + {"blendfunction", gl_blendfunction, METH_OLDARGS}, + {"c3f", gl_c3f, METH_OLDARGS}, + {"c3i", gl_c3i, METH_OLDARGS}, + {"c3s", gl_c3s, METH_OLDARGS}, + {"c4f", gl_c4f, METH_OLDARGS}, + {"c4i", gl_c4i, METH_OLDARGS}, + {"c4s", gl_c4s, METH_OLDARGS}, + {"colorf", gl_colorf, METH_OLDARGS}, + {"cpack", gl_cpack, METH_OLDARGS}, + {"czclear", gl_czclear, METH_OLDARGS}, + {"dglclose", gl_dglclose, METH_OLDARGS}, + {"dglopen", gl_dglopen, METH_OLDARGS}, + {"getgdesc", gl_getgdesc, METH_OLDARGS}, + {"getnurbsproperty", gl_getnurbsproperty, METH_OLDARGS}, + {"glcompat", gl_glcompat, METH_OLDARGS}, + {"iconsize", gl_iconsize, METH_OLDARGS}, + {"icontitle", gl_icontitle, METH_OLDARGS}, + {"lRGBrange", gl_lRGBrange, METH_OLDARGS}, + {"linesmooth", gl_linesmooth, METH_OLDARGS}, + {"lmcolor", gl_lmcolor, METH_OLDARGS}, + {"logicop", gl_logicop, METH_OLDARGS}, + {"lsetdepth", gl_lsetdepth, METH_OLDARGS}, + {"lshaderange", gl_lshaderange, METH_OLDARGS}, + {"n3f", gl_n3f, METH_OLDARGS}, + {"noborder", gl_noborder, METH_OLDARGS}, + {"pntsmooth", gl_pntsmooth, METH_OLDARGS}, + {"readsource", gl_readsource, METH_OLDARGS}, + {"rectzoom", gl_rectzoom, METH_OLDARGS}, + {"sbox", gl_sbox, METH_OLDARGS}, + {"sboxi", gl_sboxi, METH_OLDARGS}, + {"sboxs", gl_sboxs, METH_OLDARGS}, + {"sboxf", gl_sboxf, METH_OLDARGS}, + {"sboxfi", gl_sboxfi, METH_OLDARGS}, + {"sboxfs", gl_sboxfs, METH_OLDARGS}, + {"setnurbsproperty", gl_setnurbsproperty, METH_OLDARGS}, + {"setpup", gl_setpup, METH_OLDARGS}, + {"smoothline", gl_smoothline, METH_OLDARGS}, + {"subpixel", gl_subpixel, METH_OLDARGS}, + {"swaptmesh", gl_swaptmesh, METH_OLDARGS}, + {"swinopen", gl_swinopen, METH_OLDARGS}, + {"v2f", gl_v2f, METH_OLDARGS}, + {"v2i", gl_v2i, METH_OLDARGS}, + {"v2s", gl_v2s, METH_OLDARGS}, + {"v3f", gl_v3f, METH_OLDARGS}, + {"v3i", gl_v3i, METH_OLDARGS}, + {"v3s", gl_v3s, METH_OLDARGS}, + {"v4f", gl_v4f, METH_OLDARGS}, + {"v4i", gl_v4i, METH_OLDARGS}, + {"v4s", gl_v4s, METH_OLDARGS}, + {"videocmd", gl_videocmd, METH_OLDARGS}, + {"windepth", gl_windepth, METH_OLDARGS}, + {"wmpack", gl_wmpack, METH_OLDARGS}, + {"zdraw", gl_zdraw, METH_OLDARGS}, + {"zfunction", gl_zfunction, METH_OLDARGS}, + {"zsource", gl_zsource, METH_OLDARGS}, + {"zwritemask", gl_zwritemask, METH_OLDARGS}, + {"v2d", gl_v2d, METH_OLDARGS}, + {"v3d", gl_v3d, METH_OLDARGS}, + {"v4d", gl_v4d, METH_OLDARGS}, + {"pixmode", gl_pixmode, METH_OLDARGS}, + {"qgetfd", gl_qgetfd, METH_OLDARGS}, + {"dither", gl_dither, METH_OLDARGS}, + {NULL, NULL} /* Sentinel */ +}; + +void +initgl(void) +{ + (void) Py_InitModule("gl", gl_methods); +} diff --git a/sys/src/cmd/python/Modules/grpmodule.c b/sys/src/cmd/python/Modules/grpmodule.c new file mode 100644 index 000000000..f371b2a78 --- /dev/null +++ b/sys/src/cmd/python/Modules/grpmodule.c @@ -0,0 +1,194 @@ + +/* UNIX group file access module */ + +#include "Python.h" +#include "structseq.h" + +#include <sys/types.h> +#include <grp.h> + +static PyStructSequence_Field struct_group_type_fields[] = { + {"gr_name", "group name"}, + {"gr_passwd", "password"}, + {"gr_gid", "group id"}, + {"gr_mem", "group memebers"}, + {0} +}; + +PyDoc_STRVAR(struct_group__doc__, +"grp.struct_group: Results from getgr*() routines.\n\n\ +This object may be accessed either as a tuple of\n\ + (gr_name,gr_passwd,gr_gid,gr_mem)\n\ +or via the object attributes as named in the above tuple.\n"); + +static PyStructSequence_Desc struct_group_type_desc = { + "grp.struct_group", + struct_group__doc__, + struct_group_type_fields, + 4, +}; + + +static int initialized; +static PyTypeObject StructGrpType; + +static PyObject * +mkgrent(struct group *p) +{ + int setIndex = 0; + PyObject *v = PyStructSequence_New(&StructGrpType), *w; + char **member; + + if (v == NULL) + return NULL; + + if ((w = PyList_New(0)) == NULL) { + Py_DECREF(v); + return NULL; + } + for (member = p->gr_mem; *member != NULL; member++) { + PyObject *x = PyString_FromString(*member); + if (x == NULL || PyList_Append(w, x) != 0) { + Py_XDECREF(x); + Py_DECREF(w); + Py_DECREF(v); + return NULL; + } + Py_DECREF(x); + } + +#define SET(i,val) PyStructSequence_SET_ITEM(v, i, val) + SET(setIndex++, PyString_FromString(p->gr_name)); +#if defined(__VMS) || defined(PLAN9APE) + SET(setIndex++, Py_None); + Py_INCREF(Py_None); +#else + if (p->gr_passwd) + SET(setIndex++, PyString_FromString(p->gr_passwd)); + else { + SET(setIndex++, Py_None); + Py_INCREF(Py_None); + } +#endif + SET(setIndex++, PyInt_FromLong((long) p->gr_gid)); + SET(setIndex++, w); +#undef SET + + if (PyErr_Occurred()) { + Py_DECREF(v); + Py_DECREF(w); + return NULL; + } + + return v; +} + +static PyObject * +grp_getgrgid(PyObject *self, PyObject *pyo_id) +{ + PyObject *py_int_id; + unsigned int gid; + struct group *p; + + py_int_id = PyNumber_Int(pyo_id); + if (!py_int_id) + return NULL; + gid = PyInt_AS_LONG(py_int_id); + Py_DECREF(py_int_id); + + if ((p = getgrgid(gid)) == NULL) { + PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %d", gid); + return NULL; + } + return mkgrent(p); +} + +static PyObject * +grp_getgrnam(PyObject *self, PyObject *pyo_name) +{ + PyObject *py_str_name; + char *name; + struct group *p; + + py_str_name = PyObject_Str(pyo_name); + if (!py_str_name) + return NULL; + name = PyString_AS_STRING(py_str_name); + + if ((p = getgrnam(name)) == NULL) { + PyErr_Format(PyExc_KeyError, "getgrnam(): name not found: %s", name); + Py_DECREF(py_str_name); + return NULL; + } + + Py_DECREF(py_str_name); + return mkgrent(p); +} + +static PyObject * +grp_getgrall(PyObject *self, PyObject *ignore) +{ + PyObject *d; + struct group *p; + + if ((d = PyList_New(0)) == NULL) + return NULL; + setgrent(); + while ((p = getgrent()) != NULL) { + PyObject *v = mkgrent(p); + if (v == NULL || PyList_Append(d, v) != 0) { + Py_XDECREF(v); + Py_DECREF(d); + return NULL; + } + Py_DECREF(v); + } + endgrent(); + return d; +} + +static PyMethodDef grp_methods[] = { + {"getgrgid", grp_getgrgid, METH_O, + "getgrgid(id) -> tuple\n\ +Return the group database entry for the given numeric group ID. If\n\ +id is not valid, raise KeyError."}, + {"getgrnam", grp_getgrnam, METH_O, + "getgrnam(name) -> tuple\n\ +Return the group database entry for the given group name. If\n\ +name is not valid, raise KeyError."}, + {"getgrall", grp_getgrall, METH_NOARGS, + "getgrall() -> list of tuples\n\ +Return a list of all available group entries, in arbitrary order."}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(grp__doc__, +"Access to the Unix group database.\n\ +\n\ +Group entries are reported as 4-tuples containing the following fields\n\ +from the group database, in order:\n\ +\n\ + name - name of the group\n\ + passwd - group password (encrypted); often empty\n\ + gid - numeric ID of the group\n\ + mem - list of members\n\ +\n\ +The gid is an integer, name and password are strings. (Note that most\n\ +users are not explicitly listed as members of the groups they are in\n\ +according to the password database. Check both databases to get\n\ +complete membership information.)"); + + +PyMODINIT_FUNC +initgrp(void) +{ + PyObject *m, *d; + m = Py_InitModule3("grp", grp_methods, grp__doc__); + if (m == NULL) + return; + d = PyModule_GetDict(m); + if (!initialized) + PyStructSequence_InitType(&StructGrpType, &struct_group_type_desc); + PyDict_SetItemString(d, "struct_group", (PyObject *) &StructGrpType); + initialized = 1; +} diff --git a/sys/src/cmd/python/Modules/imageop.c b/sys/src/cmd/python/Modules/imageop.c new file mode 100644 index 000000000..92f805a83 --- /dev/null +++ b/sys/src/cmd/python/Modules/imageop.c @@ -0,0 +1,785 @@ + +/* imageopmodule - Various operations on pictures */ + +#ifdef sun +#define signed +#endif + +#include "Python.h" + +#if SIZEOF_INT == 4 +typedef int Py_Int32; +typedef unsigned int Py_UInt32; +#else +#if SIZEOF_LONG == 4 +typedef long Py_Int32; +typedef unsigned long Py_UInt32; +#else +#error "No 4-byte integral type" +#endif +#endif + +#define CHARP(cp, xmax, x, y) ((char *)(cp+y*xmax+x)) +#define SHORTP(cp, xmax, x, y) ((short *)(cp+2*(y*xmax+x))) +#define LONGP(cp, xmax, x, y) ((Py_Int32 *)(cp+4*(y*xmax+x))) + +static PyObject *ImageopError; +static PyObject *ImageopDict; + +/* If this function returns true (the default if anything goes wrong), we're + behaving in a backward-compatible way with respect to how multi-byte pixels + are stored in the strings. The code in this module was originally written + for an SGI which is a big-endian system, and so the old code assumed that + 4-byte integers hold the R, G, and B values in a particular order. + However, on little-endian systems the order is reversed, and so not + actually compatible with what gl.lrectwrite and imgfile expect. + (gl.lrectwrite and imgfile are also SGI-specific, however, it is + conceivable that the data handled here comes from or goes to an SGI or that + it is otherwise used in the expectation that the byte order in the strings + is as specified.) + + The function returns the value of the module variable + "backward_compatible", or 1 if the variable does not exist or is not an + int. + */ + +static int +imageop_backward_compatible(void) +{ + static PyObject *bcos; + PyObject *bco; + long rc; + + if (ImageopDict == NULL) /* "cannot happen" */ + return 1; + if (bcos == NULL) { + /* cache string object for future use */ + bcos = PyString_FromString("backward_compatible"); + if (bcos == NULL) + return 1; + } + bco = PyDict_GetItem(ImageopDict, bcos); + if (bco == NULL) + return 1; + if (!PyInt_Check(bco)) + return 1; + rc = PyInt_AsLong(bco); + if (PyErr_Occurred()) { + /* not an integer, or too large, or something */ + PyErr_Clear(); + rc = 1; + } + return rc != 0; /* convert to values 0, 1 */ +} + +static PyObject * +imageop_crop(PyObject *self, PyObject *args) +{ + char *cp, *ncp; + short *nsp; + Py_Int32 *nlp; + int len, size, x, y, newx1, newx2, newy1, newy2; + int ix, iy, xstep, ystep; + PyObject *rv; + + if ( !PyArg_ParseTuple(args, "s#iiiiiii", &cp, &len, &size, &x, &y, + &newx1, &newy1, &newx2, &newy2) ) + return 0; + + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(ImageopError, "Size should be 1, 2 or 4"); + return 0; + } + if ( len != size*x*y ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + xstep = (newx1 < newx2)? 1 : -1; + ystep = (newy1 < newy2)? 1 : -1; + + rv = PyString_FromStringAndSize(NULL, + (abs(newx2-newx1)+1)*(abs(newy2-newy1)+1)*size); + if ( rv == 0 ) + return 0; + ncp = (char *)PyString_AsString(rv); + nsp = (short *)ncp; + nlp = (Py_Int32 *)ncp; + newy2 += ystep; + newx2 += xstep; + for( iy = newy1; iy != newy2; iy+=ystep ) { + for ( ix = newx1; ix != newx2; ix+=xstep ) { + if ( iy < 0 || iy >= y || ix < 0 || ix >= x ) { + if ( size == 1 ) + *ncp++ = 0; + else + *nlp++ = 0; + } else { + if ( size == 1 ) + *ncp++ = *CHARP(cp, x, ix, iy); + else if ( size == 2 ) + *nsp++ = *SHORTP(cp, x, ix, iy); + else + *nlp++ = *LONGP(cp, x, ix, iy); + } + } + } + return rv; +} + +static PyObject * +imageop_scale(PyObject *self, PyObject *args) +{ + char *cp, *ncp; + short *nsp; + Py_Int32 *nlp; + int len, size, x, y, newx, newy; + int ix, iy; + int oix, oiy; + PyObject *rv; + + if ( !PyArg_ParseTuple(args, "s#iiiii", + &cp, &len, &size, &x, &y, &newx, &newy) ) + return 0; + + if ( size != 1 && size != 2 && size != 4 ) { + PyErr_SetString(ImageopError, "Size should be 1, 2 or 4"); + return 0; + } + if ( len != size*x*y ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, newx*newy*size); + if ( rv == 0 ) + return 0; + ncp = (char *)PyString_AsString(rv); + nsp = (short *)ncp; + nlp = (Py_Int32 *)ncp; + for( iy = 0; iy < newy; iy++ ) { + for ( ix = 0; ix < newx; ix++ ) { + oix = ix * x / newx; + oiy = iy * y / newy; + if ( size == 1 ) + *ncp++ = *CHARP(cp, x, oix, oiy); + else if ( size == 2 ) + *nsp++ = *SHORTP(cp, x, oix, oiy); + else + *nlp++ = *LONGP(cp, x, oix, oiy); + } + } + return rv; +} + +/* Note: this routine can use a bit of optimizing */ + +static PyObject * +imageop_tovideo(PyObject *self, PyObject *args) +{ + int maxx, maxy, x, y, len; + int i; + unsigned char *cp, *ncp; + int width; + PyObject *rv; + + + if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &width, &maxx, &maxy) ) + return 0; + + if ( width != 1 && width != 4 ) { + PyErr_SetString(ImageopError, "Size should be 1 or 4"); + return 0; + } + if ( maxx*maxy*width != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, len); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + if ( width == 1 ) { + memcpy(ncp, cp, maxx); /* Copy first line */ + ncp += maxx; + for (y=1; y<maxy; y++) { /* Interpolate other lines */ + for(x=0; x<maxx; x++) { + i = y*maxx + x; + *ncp++ = ((int)cp[i] + (int)cp[i-maxx]) >> 1; + } + } + } else { + memcpy(ncp, cp, maxx*4); /* Copy first line */ + ncp += maxx*4; + for (y=1; y<maxy; y++) { /* Interpolate other lines */ + for(x=0; x<maxx; x++) { + i = (y*maxx + x)*4 + 1; + *ncp++ = 0; /* Skip alfa comp */ + *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1; + i++; + *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1; + i++; + *ncp++ = ((int)cp[i] + (int)cp[i-4*maxx]) >> 1; + } + } + } + return rv; +} + +static PyObject * +imageop_grey2mono(PyObject *self, PyObject *args) +{ + int tres, x, y, len; + unsigned char *cp, *ncp; + unsigned char ovalue; + PyObject *rv; + int i, bit; + + + if ( !PyArg_ParseTuple(args, "s#iii", &cp, &len, &x, &y, &tres) ) + return 0; + + if ( x*y != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, (len+7)/8); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + bit = 0x80; + ovalue = 0; + for ( i=0; i < len; i++ ) { + if ( (int)cp[i] > tres ) + ovalue |= bit; + bit >>= 1; + if ( bit == 0 ) { + *ncp++ = ovalue; + bit = 0x80; + ovalue = 0; + } + } + if ( bit != 0x80 ) + *ncp++ = ovalue; + return rv; +} + +static PyObject * +imageop_grey2grey4(PyObject *self, PyObject *args) +{ + int x, y, len; + unsigned char *cp, *ncp; + unsigned char ovalue; + PyObject *rv; + int i; + int pos; + + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + if ( x*y != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, (len+1)/2); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + pos = 0; + ovalue = 0; + for ( i=0; i < len; i++ ) { + ovalue |= ((int)cp[i] & 0xf0) >> pos; + pos += 4; + if ( pos == 8 ) { + *ncp++ = ovalue; + ovalue = 0; + pos = 0; + } + } + if ( pos != 0 ) + *ncp++ = ovalue; + return rv; +} + +static PyObject * +imageop_grey2grey2(PyObject *self, PyObject *args) +{ + int x, y, len; + unsigned char *cp, *ncp; + unsigned char ovalue; + PyObject *rv; + int i; + int pos; + + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + if ( x*y != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, (len+3)/4); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + pos = 0; + ovalue = 0; + for ( i=0; i < len; i++ ) { + ovalue |= ((int)cp[i] & 0xc0) >> pos; + pos += 2; + if ( pos == 8 ) { + *ncp++ = ovalue; + ovalue = 0; + pos = 0; + } + } + if ( pos != 0 ) + *ncp++ = ovalue; + return rv; +} + +static PyObject * +imageop_dither2mono(PyObject *self, PyObject *args) +{ + int sum, x, y, len; + unsigned char *cp, *ncp; + unsigned char ovalue; + PyObject *rv; + int i, bit; + + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + if ( x*y != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, (len+7)/8); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + bit = 0x80; + ovalue = 0; + sum = 0; + for ( i=0; i < len; i++ ) { + sum += cp[i]; + if ( sum >= 256 ) { + sum -= 256; + ovalue |= bit; + } + bit >>= 1; + if ( bit == 0 ) { + *ncp++ = ovalue; + bit = 0x80; + ovalue = 0; + } + } + if ( bit != 0x80 ) + *ncp++ = ovalue; + return rv; +} + +static PyObject * +imageop_dither2grey2(PyObject *self, PyObject *args) +{ + int x, y, len; + unsigned char *cp, *ncp; + unsigned char ovalue; + PyObject *rv; + int i; + int pos; + int sum = 0, nvalue; + + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + if ( x*y != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, (len+3)/4); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + pos = 1; + ovalue = 0; + for ( i=0; i < len; i++ ) { + sum += cp[i]; + nvalue = sum & 0x180; + sum -= nvalue; + ovalue |= nvalue >> pos; + pos += 2; + if ( pos == 9 ) { + *ncp++ = ovalue; + ovalue = 0; + pos = 1; + } + } + if ( pos != 0 ) + *ncp++ = ovalue; + return rv; +} + +static PyObject * +imageop_mono2grey(PyObject *self, PyObject *args) +{ + int v0, v1, x, y, len, nlen; + unsigned char *cp, *ncp; + PyObject *rv; + int i, bit; + + if ( !PyArg_ParseTuple(args, "s#iiii", &cp, &len, &x, &y, &v0, &v1) ) + return 0; + + nlen = x*y; + if ( (nlen+7)/8 != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, nlen); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + bit = 0x80; + for ( i=0; i < nlen; i++ ) { + if ( *cp & bit ) + *ncp++ = v1; + else + *ncp++ = v0; + bit >>= 1; + if ( bit == 0 ) { + bit = 0x80; + cp++; + } + } + return rv; +} + +static PyObject * +imageop_grey22grey(PyObject *self, PyObject *args) +{ + int x, y, len, nlen; + unsigned char *cp, *ncp; + PyObject *rv; + int i, pos, value = 0, nvalue; + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + nlen = x*y; + if ( (nlen+3)/4 != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, nlen); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + pos = 0; + for ( i=0; i < nlen; i++ ) { + if ( pos == 0 ) { + value = *cp++; + pos = 8; + } + pos -= 2; + nvalue = (value >> pos) & 0x03; + *ncp++ = nvalue | (nvalue << 2) | + (nvalue << 4) | (nvalue << 6); + } + return rv; +} + +static PyObject * +imageop_grey42grey(PyObject *self, PyObject *args) +{ + int x, y, len, nlen; + unsigned char *cp, *ncp; + PyObject *rv; + int i, pos, value = 0, nvalue; + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + nlen = x*y; + if ( (nlen+1)/2 != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, nlen); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + pos = 0; + for ( i=0; i < nlen; i++ ) { + if ( pos == 0 ) { + value = *cp++; + pos = 8; + } + pos -= 4; + nvalue = (value >> pos) & 0x0f; + *ncp++ = nvalue | (nvalue << 4); + } + return rv; +} + +static PyObject * +imageop_rgb2rgb8(PyObject *self, PyObject *args) +{ + int x, y, len, nlen; + unsigned char *cp; + unsigned char *ncp; + PyObject *rv; + int i, r, g, b; + int backward_compatible = imageop_backward_compatible(); + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + nlen = x*y; + if ( nlen*4 != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, nlen); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0; i < nlen; i++ ) { + /* Bits in source: aaaaaaaa BBbbbbbb GGGggggg RRRrrrrr */ + if (backward_compatible) { + Py_UInt32 value = * (Py_UInt32 *) cp; + cp += 4; + r = (int) ((value & 0xff) / 255. * 7. + .5); + g = (int) (((value >> 8) & 0xff) / 255. * 7. + .5); + b = (int) (((value >> 16) & 0xff) / 255. * 3. + .5); + } else { + cp++; /* skip alpha channel */ + b = (int) (*cp++ / 255. * 3. + .5); + g = (int) (*cp++ / 255. * 7. + .5); + r = (int) (*cp++ / 255. * 7. + .5); + } + *ncp++ = (unsigned char)((r<<5) | (b<<3) | g); + } + return rv; +} + +static PyObject * +imageop_rgb82rgb(PyObject *self, PyObject *args) +{ + int x, y, len, nlen; + unsigned char *cp; + unsigned char *ncp; + PyObject *rv; + int i, r, g, b; + unsigned char value; + int backward_compatible = imageop_backward_compatible(); + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + nlen = x*y; + if ( nlen != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, nlen*4); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0; i < nlen; i++ ) { + /* Bits in source: RRRBBGGG + ** Red and Green are multiplied by 36.5, Blue by 85 + */ + value = *cp++; + r = (value >> 5) & 7; + g = (value ) & 7; + b = (value >> 3) & 3; + r = (r<<5) | (r<<3) | (r>>1); + g = (g<<5) | (g<<3) | (g>>1); + b = (b<<6) | (b<<4) | (b<<2) | b; + if (backward_compatible) { + Py_UInt32 nvalue = r | (g<<8) | (b<<16); + * (Py_UInt32 *) ncp = nvalue; + ncp += 4; + } else { + *ncp++ = 0; + *ncp++ = b; + *ncp++ = g; + *ncp++ = r; + } + } + return rv; +} + +static PyObject * +imageop_rgb2grey(PyObject *self, PyObject *args) +{ + int x, y, len, nlen; + unsigned char *cp; + unsigned char *ncp; + PyObject *rv; + int i, r, g, b; + int nvalue; + int backward_compatible = imageop_backward_compatible(); + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + nlen = x*y; + if ( nlen*4 != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, nlen); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0; i < nlen; i++ ) { + if (backward_compatible) { + Py_UInt32 value = * (Py_UInt32 *) cp; + cp += 4; + r = (int) ((value & 0xff) / 255. * 7. + .5); + g = (int) (((value >> 8) & 0xff) / 255. * 7. + .5); + b = (int) (((value >> 16) & 0xff) / 255. * 3. + .5); + } else { + cp++; /* skip alpha channel */ + b = *cp++; + g = *cp++; + r = *cp++; + } + nvalue = (int)(0.30*r + 0.59*g + 0.11*b); + if ( nvalue > 255 ) nvalue = 255; + *ncp++ = (unsigned char)nvalue; + } + return rv; +} + +static PyObject * +imageop_grey2rgb(PyObject *self, PyObject *args) +{ + int x, y, len, nlen; + unsigned char *cp; + unsigned char *ncp; + PyObject *rv; + int i; + unsigned char value; + int backward_compatible = imageop_backward_compatible(); + + if ( !PyArg_ParseTuple(args, "s#ii", &cp, &len, &x, &y) ) + return 0; + + nlen = x*y; + if ( nlen != len ) { + PyErr_SetString(ImageopError, "String has incorrect length"); + return 0; + } + + rv = PyString_FromStringAndSize(NULL, nlen*4); + if ( rv == 0 ) + return 0; + ncp = (unsigned char *)PyString_AsString(rv); + + for ( i=0; i < nlen; i++ ) { + value = *cp++; + if (backward_compatible) { + * (Py_UInt32 *) ncp = (Py_UInt32) value | ((Py_UInt32) value << 8 ) | ((Py_UInt32) value << 16); + ncp += 4; + } else { + *ncp++ = 0; + *ncp++ = value; + *ncp++ = value; + *ncp++ = value; + } + } + return rv; +} + +/* +static object * +imageop_mul(object *self, object *args) +{ + char *cp, *ncp; + int len, size, x, y; + object *rv; + int i; + + if ( !getargs(args, "(s#iii)", &cp, &len, &size, &x, &y) ) + return 0; + + if ( size != 1 && size != 4 ) { + err_setstr(ImageopError, "Size should be 1 or 4"); + return 0; + } + if ( len != size*x*y ) { + err_setstr(ImageopError, "String has incorrect length"); + return 0; + } + + rv = newsizedstringobject(NULL, XXXX); + if ( rv == 0 ) + return 0; + ncp = (char *)getstringvalue(rv); + + + for ( i=0; i < len; i += size ) { + } + return rv; +} +*/ + +static PyMethodDef imageop_methods[] = { + { "crop", imageop_crop, METH_VARARGS }, + { "scale", imageop_scale, METH_VARARGS }, + { "grey2mono", imageop_grey2mono, METH_VARARGS }, + { "grey2grey2", imageop_grey2grey2, METH_VARARGS }, + { "grey2grey4", imageop_grey2grey4, METH_VARARGS }, + { "dither2mono", imageop_dither2mono, METH_VARARGS }, + { "dither2grey2", imageop_dither2grey2, METH_VARARGS }, + { "mono2grey", imageop_mono2grey, METH_VARARGS }, + { "grey22grey", imageop_grey22grey, METH_VARARGS }, + { "grey42grey", imageop_grey42grey, METH_VARARGS }, + { "tovideo", imageop_tovideo, METH_VARARGS }, + { "rgb2rgb8", imageop_rgb2rgb8, METH_VARARGS }, + { "rgb82rgb", imageop_rgb82rgb, METH_VARARGS }, + { "rgb2grey", imageop_rgb2grey, METH_VARARGS }, + { "grey2rgb", imageop_grey2rgb, METH_VARARGS }, + { 0, 0 } +}; + + +PyMODINIT_FUNC +initimageop(void) +{ + PyObject *m; + m = Py_InitModule("imageop", imageop_methods); + if (m == NULL) + return; + ImageopDict = PyModule_GetDict(m); + ImageopError = PyErr_NewException("imageop.error", NULL, NULL); + if (ImageopError != NULL) + PyDict_SetItemString(ImageopDict, "error", ImageopError); +} diff --git a/sys/src/cmd/python/Modules/imgfile.c b/sys/src/cmd/python/Modules/imgfile.c new file mode 100644 index 000000000..bb85a78d5 --- /dev/null +++ b/sys/src/cmd/python/Modules/imgfile.c @@ -0,0 +1,504 @@ + +/* IMGFILE module - Interface to sgi libimage */ + +/* XXX This module should be done better at some point. It should return +** an object of image file class, and have routines to manipulate these +** image files in a neater way (so you can get rgb images off a greyscale +** file, for instance, or do a straight display without having to get the +** image bits into python, etc). +** +** Warning: this module is very non-reentrant (esp. the readscaled stuff) +*/ + +#include "Python.h" + +#include <gl/image.h> + +#include "/usr/people/4Dgifts/iristools/include/izoom.h" + +/* Bunch of missing extern decls; keep gcc -Wall happy... */ +extern void i_seterror(); +extern void iclose(); +extern void filterzoom(); +extern void putrow(); +extern void getrow(); + +static PyObject * ImgfileError; /* Exception we raise for various trouble */ + +static int top_to_bottom; /* True if we want top-to-bottom images */ + +/* The image library does not always call the error hander :-(, + therefore we have a global variable indicating that it was called. + It is cleared by imgfile_open(). */ + +static int error_called; + + +/* The error handler */ + +static void +imgfile_error(char *str) +{ + PyErr_SetString(ImgfileError, str); + error_called = 1; + return; /* To imglib, which will return a failure indicator */ +} + + +/* Open an image file and return a pointer to it. + Make sure we raise an exception if we fail. */ + +static IMAGE * +imgfile_open(char *fname) +{ + IMAGE *image; + i_seterror(imgfile_error); + error_called = 0; + errno = 0; + if ( (image = iopen(fname, "r")) == NULL ) { + /* Error may already be set by imgfile_error */ + if ( !error_called ) { + if (errno) + PyErr_SetFromErrno(ImgfileError); + else + PyErr_SetString(ImgfileError, + "Can't open image file"); + } + return NULL; + } + return image; +} + +static PyObject * +imgfile_ttob(PyObject *self, PyObject *args) +{ + int newval; + PyObject *rv; + + if (!PyArg_ParseTuple(args, "i:ttob", &newval)) + return NULL; + rv = PyInt_FromLong(top_to_bottom); + top_to_bottom = newval; + return rv; +} + +static PyObject * +imgfile_read(PyObject *self, PyObject *args) +{ + char *fname; + PyObject *rv; + int xsize, ysize, zsize; + char *cdatap; + long *idatap; + static short rs[8192], gs[8192], bs[8192]; + int x, y; + IMAGE *image; + int yfirst, ylast, ystep; + + if ( !PyArg_ParseTuple(args, "s:read", &fname) ) + return NULL; + + if ( (image = imgfile_open(fname)) == NULL ) + return NULL; + + if ( image->colormap != CM_NORMAL ) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can only handle CM_NORMAL images"); + return NULL; + } + if ( BPP(image->type) != 1 ) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can't handle imgfiles with bpp!=1"); + return NULL; + } + xsize = image->xsize; + ysize = image->ysize; + zsize = image->zsize; + if ( zsize != 1 && zsize != 3) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can only handle 1 or 3 byte pixels"); + return NULL; + } + if ( xsize > 8192 ) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can't handle image with > 8192 columns"); + return NULL; + } + + if ( zsize == 3 ) zsize = 4; + rv = PyString_FromStringAndSize((char *)NULL, xsize*ysize*zsize); + if ( rv == NULL ) { + iclose(image); + return NULL; + } + cdatap = PyString_AsString(rv); + idatap = (long *)cdatap; + + if (top_to_bottom) { + yfirst = ysize-1; + ylast = -1; + ystep = -1; + } else { + yfirst = 0; + ylast = ysize; + ystep = 1; + } + for ( y=yfirst; y != ylast && !error_called; y += ystep ) { + if ( zsize == 1 ) { + getrow(image, rs, y, 0); + for(x=0; x<xsize; x++ ) + *cdatap++ = rs[x]; + } else { + getrow(image, rs, y, 0); + getrow(image, gs, y, 1); + getrow(image, bs, y, 2); + for(x=0; x<xsize; x++ ) + *idatap++ = (rs[x] & 0xff) | + ((gs[x] & 0xff)<<8) | + ((bs[x] & 0xff)<<16); + } + } + iclose(image); + if ( error_called ) { + Py_DECREF(rv); + return NULL; + } + return rv; +} + +static IMAGE *glob_image; +static long *glob_datap; +static int glob_width, glob_z, glob_ysize; + +static void +xs_get(short *buf, int y) +{ + if (top_to_bottom) + getrow(glob_image, buf, (glob_ysize-1-y), glob_z); + else + getrow(glob_image, buf, y, glob_z); +} + +static void +xs_put_c(short *buf, int y) +{ + char *datap = (char *)glob_datap + y*glob_width; + int width = glob_width; + + while ( width-- ) + *datap++ = (*buf++) & 0xff; +} + +static void +xs_put_0(short *buf, int y) +{ + long *datap = glob_datap + y*glob_width; + int width = glob_width; + + while ( width-- ) + *datap++ = (*buf++) & 0xff; +} +static void +xs_put_12(short *buf, int y) +{ + long *datap = glob_datap + y*glob_width; + int width = glob_width; + + while ( width-- ) + *datap++ |= ((*buf++) & 0xff) << (glob_z*8); +} + +static void +xscale(IMAGE *image, int xsize, int ysize, int zsize, + long *datap, int xnew, int ynew, int fmode, double blur) +{ + glob_image = image; + glob_datap = datap; + glob_width = xnew; + glob_ysize = ysize; + if ( zsize == 1 ) { + glob_z = 0; + filterzoom(xs_get, xs_put_c, xsize, ysize, + xnew, ynew, fmode, blur); + } else { + glob_z = 0; + filterzoom(xs_get, xs_put_0, xsize, ysize, + xnew, ynew, fmode, blur); + glob_z = 1; + filterzoom(xs_get, xs_put_12, xsize, ysize, + xnew, ynew, fmode, blur); + glob_z = 2; + filterzoom(xs_get, xs_put_12, xsize, ysize, + xnew, ynew, fmode, blur); + } +} + + +static PyObject * +imgfile_readscaled(PyObject *self, PyObject *args) +{ + char *fname; + PyObject *rv; + int xsize, ysize, zsize; + char *cdatap; + long *idatap; + static short rs[8192], gs[8192], bs[8192]; + int x, y; + int xwtd, ywtd, xorig, yorig; + float xfac, yfac; + IMAGE *image; + char *filter; + double blur = 1.0; + int extended; + int fmode = 0; + int yfirst, ylast, ystep; + + /* + ** Parse args. Funny, since arg 4 and 5 are optional + ** (filter name and blur factor). Also, 4 or 5 arguments indicates + ** extended scale algorithm in stead of simple-minded pixel drop/dup. + */ + extended = PyTuple_Size(args) >= 4; + if ( !PyArg_ParseTuple(args, "sii|sd", + &fname, &xwtd, &ywtd, &filter, &blur) ) + return NULL; + + /* + ** Check parameters, open file and check type, rows, etc. + */ + if ( extended ) { + if ( strcmp(filter, "impulse") == 0 ) + fmode = IMPULSE; + else if ( strcmp( filter, "box") == 0 ) + fmode = BOX; + else if ( strcmp( filter, "triangle") == 0 ) + fmode = TRIANGLE; + else if ( strcmp( filter, "quadratic") == 0 ) + fmode = QUADRATIC; + else if ( strcmp( filter, "gaussian") == 0 ) + fmode = GAUSSIAN; + else { + PyErr_SetString(ImgfileError, "Unknown filter type"); + return NULL; + } + } + + if ( (image = imgfile_open(fname)) == NULL ) + return NULL; + + if ( image->colormap != CM_NORMAL ) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can only handle CM_NORMAL images"); + return NULL; + } + if ( BPP(image->type) != 1 ) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can't handle imgfiles with bpp!=1"); + return NULL; + } + xsize = image->xsize; + ysize = image->ysize; + zsize = image->zsize; + if ( zsize != 1 && zsize != 3) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can only handle 1 or 3 byte pixels"); + return NULL; + } + if ( xsize > 8192 ) { + iclose(image); + PyErr_SetString(ImgfileError, + "Can't handle image with > 8192 columns"); + return NULL; + } + + if ( zsize == 3 ) zsize = 4; + rv = PyString_FromStringAndSize(NULL, xwtd*ywtd*zsize); + if ( rv == NULL ) { + iclose(image); + return NULL; + } + PyFPE_START_PROTECT("readscaled", return 0) + xfac = (float)xsize/(float)xwtd; + yfac = (float)ysize/(float)ywtd; + PyFPE_END_PROTECT(yfac) + cdatap = PyString_AsString(rv); + idatap = (long *)cdatap; + + if ( extended ) { + xscale(image, xsize, ysize, zsize, + idatap, xwtd, ywtd, fmode, blur); + } else { + if (top_to_bottom) { + yfirst = ywtd-1; + ylast = -1; + ystep = -1; + } else { + yfirst = 0; + ylast = ywtd; + ystep = 1; + } + for ( y=yfirst; y != ylast && !error_called; y += ystep ) { + yorig = (int)(y*yfac); + if ( zsize == 1 ) { + getrow(image, rs, yorig, 0); + for(x=0; x<xwtd; x++ ) { + *cdatap++ = rs[(int)(x*xfac)]; + } + } else { + getrow(image, rs, yorig, 0); + getrow(image, gs, yorig, 1); + getrow(image, bs, yorig, 2); + for(x=0; x<xwtd; x++ ) { + xorig = (int)(x*xfac); + *idatap++ = (rs[xorig] & 0xff) | + ((gs[xorig] & 0xff)<<8) | + ((bs[xorig] & 0xff)<<16); + } + } + } + } + iclose(image); + if ( error_called ) { + Py_DECREF(rv); + return NULL; + } + return rv; +} + +static PyObject * +imgfile_getsizes(PyObject *self, PyObject *args) +{ + char *fname; + PyObject *rv; + IMAGE *image; + + if ( !PyArg_ParseTuple(args, "s:getsizes", &fname) ) + return NULL; + + if ( (image = imgfile_open(fname)) == NULL ) + return NULL; + rv = Py_BuildValue("(iii)", image->xsize, image->ysize, image->zsize); + iclose(image); + return rv; +} + +static PyObject * +imgfile_write(PyObject *self, PyObject *args) +{ + IMAGE *image; + char *fname; + int xsize, ysize, zsize, len; + char *cdatap; + long *idatap; + short rs[8192], gs[8192], bs[8192]; + short r, g, b; + long rgb; + int x, y; + int yfirst, ylast, ystep; + + + if ( !PyArg_ParseTuple(args, "ss#iii:write", + &fname, &cdatap, &len, &xsize, &ysize, &zsize) ) + return NULL; + + if ( zsize != 1 && zsize != 3 ) { + PyErr_SetString(ImgfileError, + "Can only handle 1 or 3 byte pixels"); + return NULL; + } + if ( len != xsize * ysize * (zsize == 1 ? 1 : 4) ) { + PyErr_SetString(ImgfileError, "Data does not match sizes"); + return NULL; + } + if ( xsize > 8192 ) { + PyErr_SetString(ImgfileError, + "Can't handle image with > 8192 columns"); + return NULL; + } + + error_called = 0; + errno = 0; + image =iopen(fname, "w", RLE(1), 3, xsize, ysize, zsize); + if ( image == 0 ) { + if ( ! error_called ) { + if (errno) + PyErr_SetFromErrno(ImgfileError); + else + PyErr_SetString(ImgfileError, + "Can't create image file"); + } + return NULL; + } + + idatap = (long *)cdatap; + + if (top_to_bottom) { + yfirst = ysize-1; + ylast = -1; + ystep = -1; + } else { + yfirst = 0; + ylast = ysize; + ystep = 1; + } + for ( y=yfirst; y != ylast && !error_called; y += ystep ) { + if ( zsize == 1 ) { + for( x=0; x<xsize; x++ ) + rs[x] = *cdatap++; + putrow(image, rs, y, 0); + } else { + for( x=0; x<xsize; x++ ) { + rgb = *idatap++; + r = rgb & 0xff; + g = (rgb >> 8 ) & 0xff; + b = (rgb >> 16 ) & 0xff; + rs[x] = r; + gs[x] = g; + bs[x] = b; + } + putrow(image, rs, y, 0); + putrow(image, gs, y, 1); + putrow(image, bs, y, 2); + } + } + iclose(image); + if ( error_called ) + return NULL; + Py_INCREF(Py_None); + return Py_None; + +} + + +static PyMethodDef imgfile_methods[] = { + { "getsizes", imgfile_getsizes, METH_VARARGS }, + { "read", imgfile_read, METH_VARARGS }, + { "readscaled", imgfile_readscaled, METH_VARARGS}, + { "write", imgfile_write, METH_VARARGS }, + { "ttob", imgfile_ttob, METH_VARARGS }, + { NULL, NULL } /* Sentinel */ +}; + + +void +initimgfile(void) +{ + PyObject *m, *d; + m = Py_InitModule("imgfile", imgfile_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + ImgfileError = PyErr_NewException("imgfile.error", NULL, NULL); + if (ImgfileError != NULL) + PyDict_SetItemString(d, "error", ImgfileError); +} + + + diff --git a/sys/src/cmd/python/Modules/itertoolsmodule.c b/sys/src/cmd/python/Modules/itertoolsmodule.c new file mode 100644 index 000000000..70f787f78 --- /dev/null +++ b/sys/src/cmd/python/Modules/itertoolsmodule.c @@ -0,0 +1,2550 @@ + +#include "Python.h" +#include "structmember.h" + +/* Itertools module written and maintained + by Raymond D. Hettinger <python@rcn.com> + Copyright (c) 2003 Python Software Foundation. + All rights reserved. +*/ + + +/* groupby object ***********************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *it; + PyObject *keyfunc; + PyObject *tgtkey; + PyObject *currkey; + PyObject *currvalue; +} groupbyobject; + +static PyTypeObject groupby_type; +static PyObject *_grouper_create(groupbyobject *, PyObject *); + +static PyObject * +groupby_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwargs[] = {"iterable", "key", NULL}; + groupbyobject *gbo; + PyObject *it, *keyfunc = Py_None; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:groupby", kwargs, + &it, &keyfunc)) + return NULL; + + gbo = (groupbyobject *)type->tp_alloc(type, 0); + if (gbo == NULL) + return NULL; + gbo->tgtkey = NULL; + gbo->currkey = NULL; + gbo->currvalue = NULL; + gbo->keyfunc = keyfunc; + Py_INCREF(keyfunc); + gbo->it = PyObject_GetIter(it); + if (gbo->it == NULL) { + Py_DECREF(gbo); + return NULL; + } + return (PyObject *)gbo; +} + +static void +groupby_dealloc(groupbyobject *gbo) +{ + PyObject_GC_UnTrack(gbo); + Py_XDECREF(gbo->it); + Py_XDECREF(gbo->keyfunc); + Py_XDECREF(gbo->tgtkey); + Py_XDECREF(gbo->currkey); + Py_XDECREF(gbo->currvalue); + gbo->ob_type->tp_free(gbo); +} + +static int +groupby_traverse(groupbyobject *gbo, visitproc visit, void *arg) +{ + Py_VISIT(gbo->it); + Py_VISIT(gbo->keyfunc); + Py_VISIT(gbo->tgtkey); + Py_VISIT(gbo->currkey); + Py_VISIT(gbo->currvalue); + return 0; +} + +static PyObject * +groupby_next(groupbyobject *gbo) +{ + PyObject *newvalue, *newkey, *r, *grouper, *tmp; + + /* skip to next iteration group */ + for (;;) { + if (gbo->currkey == NULL) + /* pass */; + else if (gbo->tgtkey == NULL) + break; + else { + int rcmp; + + rcmp = PyObject_RichCompareBool(gbo->tgtkey, + gbo->currkey, Py_EQ); + if (rcmp == -1) + return NULL; + else if (rcmp == 0) + break; + } + + newvalue = PyIter_Next(gbo->it); + if (newvalue == NULL) + return NULL; + + if (gbo->keyfunc == Py_None) { + newkey = newvalue; + Py_INCREF(newvalue); + } else { + newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc, + newvalue, NULL); + if (newkey == NULL) { + Py_DECREF(newvalue); + return NULL; + } + } + + tmp = gbo->currkey; + gbo->currkey = newkey; + Py_XDECREF(tmp); + + tmp = gbo->currvalue; + gbo->currvalue = newvalue; + Py_XDECREF(tmp); + } + + Py_INCREF(gbo->currkey); + tmp = gbo->tgtkey; + gbo->tgtkey = gbo->currkey; + Py_XDECREF(tmp); + + grouper = _grouper_create(gbo, gbo->tgtkey); + if (grouper == NULL) + return NULL; + + r = PyTuple_Pack(2, gbo->currkey, grouper); + Py_DECREF(grouper); + return r; +} + +PyDoc_STRVAR(groupby_doc, +"groupby(iterable[, keyfunc]) -> create an iterator which returns\n\ +(key, sub-iterator) grouped by each value of key(value).\n"); + +static PyTypeObject groupby_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.groupby", /* tp_name */ + sizeof(groupbyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)groupby_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + groupby_doc, /* tp_doc */ + (traverseproc)groupby_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)groupby_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + groupby_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* _grouper object (internal) ************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *parent; + PyObject *tgtkey; +} _grouperobject; + +static PyTypeObject _grouper_type; + +static PyObject * +_grouper_create(groupbyobject *parent, PyObject *tgtkey) +{ + _grouperobject *igo; + + igo = PyObject_New(_grouperobject, &_grouper_type); + if (igo == NULL) + return NULL; + igo->parent = (PyObject *)parent; + Py_INCREF(parent); + igo->tgtkey = tgtkey; + Py_INCREF(tgtkey); + + return (PyObject *)igo; +} + +static void +_grouper_dealloc(_grouperobject *igo) +{ + Py_DECREF(igo->parent); + Py_DECREF(igo->tgtkey); + PyObject_Del(igo); +} + +static PyObject * +_grouper_next(_grouperobject *igo) +{ + groupbyobject *gbo = (groupbyobject *)igo->parent; + PyObject *newvalue, *newkey, *r; + int rcmp; + + if (gbo->currvalue == NULL) { + newvalue = PyIter_Next(gbo->it); + if (newvalue == NULL) + return NULL; + + if (gbo->keyfunc == Py_None) { + newkey = newvalue; + Py_INCREF(newvalue); + } else { + newkey = PyObject_CallFunctionObjArgs(gbo->keyfunc, + newvalue, NULL); + if (newkey == NULL) { + Py_DECREF(newvalue); + return NULL; + } + } + + assert(gbo->currkey == NULL); + gbo->currkey = newkey; + gbo->currvalue = newvalue; + } + + assert(gbo->currkey != NULL); + rcmp = PyObject_RichCompareBool(igo->tgtkey, gbo->currkey, Py_EQ); + if (rcmp <= 0) + /* got any error or current group is end */ + return NULL; + + r = gbo->currvalue; + gbo->currvalue = NULL; + Py_CLEAR(gbo->currkey); + + return r; +} + +static PyTypeObject _grouper_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools._grouper", /* tp_name */ + sizeof(_grouperobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)_grouper_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)_grouper_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + + +/* tee object and with supporting function and objects ***************/ + +/* The teedataobject pre-allocates space for LINKCELLS number of objects. + To help the object fit neatly inside cache lines (space for 16 to 32 + pointers), the value should be a multiple of 16 minus space for + the other structure members including PyHEAD overhead. The larger the + value, the less memory overhead per object and the less time spent + allocating/deallocating new links. The smaller the number, the less + wasted space and the more rapid freeing of older data. +*/ +#define LINKCELLS 57 + +typedef struct { + PyObject_HEAD + PyObject *it; + int numread; + PyObject *nextlink; + PyObject *(values[LINKCELLS]); +} teedataobject; + +typedef struct { + PyObject_HEAD + teedataobject *dataobj; + int index; + PyObject *weakreflist; +} teeobject; + +static PyTypeObject teedataobject_type; + +static PyObject * +teedataobject_new(PyObject *it) +{ + teedataobject *tdo; + + tdo = PyObject_GC_New(teedataobject, &teedataobject_type); + if (tdo == NULL) + return NULL; + + tdo->numread = 0; + tdo->nextlink = NULL; + Py_INCREF(it); + tdo->it = it; + PyObject_GC_Track(tdo); + return (PyObject *)tdo; +} + +static PyObject * +teedataobject_jumplink(teedataobject *tdo) +{ + if (tdo->nextlink == NULL) + tdo->nextlink = teedataobject_new(tdo->it); + Py_XINCREF(tdo->nextlink); + return tdo->nextlink; +} + +static PyObject * +teedataobject_getitem(teedataobject *tdo, int i) +{ + PyObject *value; + + assert(i < LINKCELLS); + if (i < tdo->numread) + value = tdo->values[i]; + else { + /* this is the lead iterator, so fetch more data */ + assert(i == tdo->numread); + value = PyIter_Next(tdo->it); + if (value == NULL) + return NULL; + tdo->numread++; + tdo->values[i] = value; + } + Py_INCREF(value); + return value; +} + +static int +teedataobject_traverse(teedataobject *tdo, visitproc visit, void * arg) +{ + int i; + Py_VISIT(tdo->it); + for (i = 0; i < tdo->numread; i++) + Py_VISIT(tdo->values[i]); + Py_VISIT(tdo->nextlink); + return 0; +} + +static int +teedataobject_clear(teedataobject *tdo) +{ + int i; + Py_CLEAR(tdo->it); + for (i=0 ; i<tdo->numread ; i++) + Py_CLEAR(tdo->values[i]); + Py_CLEAR(tdo->nextlink); + return 0; +} + +static void +teedataobject_dealloc(teedataobject *tdo) +{ + PyObject_GC_UnTrack(tdo); + teedataobject_clear(tdo); + PyObject_GC_Del(tdo); +} + +PyDoc_STRVAR(teedataobject_doc, "Data container common to multiple tee objects."); + +static PyTypeObject teedataobject_type = { + PyObject_HEAD_INIT(0) /* Must fill in type value later */ + 0, /* ob_size */ + "itertools.tee_dataobject", /* tp_name */ + sizeof(teedataobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)teedataobject_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + teedataobject_doc, /* tp_doc */ + (traverseproc)teedataobject_traverse, /* tp_traverse */ + (inquiry)teedataobject_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +static PyTypeObject tee_type; + +static PyObject * +tee_next(teeobject *to) +{ + PyObject *value, *link; + + if (to->index >= LINKCELLS) { + link = teedataobject_jumplink(to->dataobj); + Py_DECREF(to->dataobj); + to->dataobj = (teedataobject *)link; + to->index = 0; + } + value = teedataobject_getitem(to->dataobj, to->index); + if (value == NULL) + return NULL; + to->index++; + return value; +} + +static int +tee_traverse(teeobject *to, visitproc visit, void *arg) +{ + Py_VISIT((PyObject *)to->dataobj); + return 0; +} + +static PyObject * +tee_copy(teeobject *to) +{ + teeobject *newto; + + newto = PyObject_GC_New(teeobject, &tee_type); + if (newto == NULL) + return NULL; + Py_INCREF(to->dataobj); + newto->dataobj = to->dataobj; + newto->index = to->index; + newto->weakreflist = NULL; + PyObject_GC_Track(newto); + return (PyObject *)newto; +} + +PyDoc_STRVAR(teecopy_doc, "Returns an independent iterator."); + +static PyObject * +tee_fromiterable(PyObject *iterable) +{ + teeobject *to; + PyObject *it = NULL; + + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + if (PyObject_TypeCheck(it, &tee_type)) { + to = (teeobject *)tee_copy((teeobject *)it); + goto done; + } + + to = PyObject_GC_New(teeobject, &tee_type); + if (to == NULL) + goto done; + to->dataobj = (teedataobject *)teedataobject_new(it); + if (!to->dataobj) { + PyObject_GC_Del(to); + to = NULL; + goto done; + } + + to->index = 0; + to->weakreflist = NULL; + PyObject_GC_Track(to); +done: + Py_XDECREF(it); + return (PyObject *)to; +} + +static PyObject * +tee_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *iterable; + + if (!PyArg_UnpackTuple(args, "tee", 1, 1, &iterable)) + return NULL; + return tee_fromiterable(iterable); +} + +static int +tee_clear(teeobject *to) +{ + if (to->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) to); + Py_CLEAR(to->dataobj); + return 0; +} + +static void +tee_dealloc(teeobject *to) +{ + PyObject_GC_UnTrack(to); + tee_clear(to); + PyObject_GC_Del(to); +} + +PyDoc_STRVAR(teeobject_doc, +"Iterator wrapped to make it copyable"); + +static PyMethodDef tee_methods[] = { + {"__copy__", (PyCFunction)tee_copy, METH_NOARGS, teecopy_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject tee_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.tee", /* tp_name */ + sizeof(teeobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)tee_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + teeobject_doc, /* tp_doc */ + (traverseproc)tee_traverse, /* tp_traverse */ + (inquiry)tee_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(teeobject, weakreflist), /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)tee_next, /* tp_iternext */ + tee_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + tee_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +static PyObject * +tee(PyObject *self, PyObject *args) +{ + Py_ssize_t i, n=2; + PyObject *it, *iterable, *copyable, *result; + + if (!PyArg_ParseTuple(args, "O|n", &iterable, &n)) + return NULL; + if (n < 0) { + PyErr_SetString(PyExc_ValueError, "n must be >= 0"); + return NULL; + } + result = PyTuple_New(n); + if (result == NULL) + return NULL; + if (n == 0) + return result; + it = PyObject_GetIter(iterable); + if (it == NULL) { + Py_DECREF(result); + return NULL; + } + if (!PyObject_HasAttrString(it, "__copy__")) { + copyable = tee_fromiterable(it); + Py_DECREF(it); + if (copyable == NULL) { + Py_DECREF(result); + return NULL; + } + } else + copyable = it; + PyTuple_SET_ITEM(result, 0, copyable); + for (i=1 ; i<n ; i++) { + copyable = PyObject_CallMethod(copyable, "__copy__", NULL); + if (copyable == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, copyable); + } + return result; +} + +PyDoc_STRVAR(tee_doc, +"tee(iterable, n=2) --> tuple of n independent iterators."); + + +/* cycle object **********************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *it; + PyObject *saved; + int firstpass; +} cycleobject; + +static PyTypeObject cycle_type; + +static PyObject * +cycle_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *it; + PyObject *iterable; + PyObject *saved; + cycleobject *lz; + + if (type == &cycle_type && !_PyArg_NoKeywords("cycle()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, "cycle", 1, 1, &iterable)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + + saved = PyList_New(0); + if (saved == NULL) { + Py_DECREF(it); + return NULL; + } + + /* create cycleobject structure */ + lz = (cycleobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + Py_DECREF(saved); + return NULL; + } + lz->it = it; + lz->saved = saved; + lz->firstpass = 0; + + return (PyObject *)lz; +} + +static void +cycle_dealloc(cycleobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->saved); + Py_XDECREF(lz->it); + lz->ob_type->tp_free(lz); +} + +static int +cycle_traverse(cycleobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + Py_VISIT(lz->saved); + return 0; +} + +static PyObject * +cycle_next(cycleobject *lz) +{ + PyObject *item; + PyObject *it; + PyObject *tmp; + + while (1) { + item = PyIter_Next(lz->it); + if (item != NULL) { + if (!lz->firstpass) + PyList_Append(lz->saved, item); + return item; + } + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + else + return NULL; + } + if (PyList_Size(lz->saved) == 0) + return NULL; + it = PyObject_GetIter(lz->saved); + if (it == NULL) + return NULL; + tmp = lz->it; + lz->it = it; + lz->firstpass = 1; + Py_DECREF(tmp); + } +} + +PyDoc_STRVAR(cycle_doc, +"cycle(iterable) --> cycle object\n\ +\n\ +Return elements from the iterable until it is exhausted.\n\ +Then repeat the sequence indefinitely."); + +static PyTypeObject cycle_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.cycle", /* tp_name */ + sizeof(cycleobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)cycle_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + cycle_doc, /* tp_doc */ + (traverseproc)cycle_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)cycle_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + cycle_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* dropwhile object **********************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *func; + PyObject *it; + long start; +} dropwhileobject; + +static PyTypeObject dropwhile_type; + +static PyObject * +dropwhile_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *func, *seq; + PyObject *it; + dropwhileobject *lz; + + if (type == &dropwhile_type && !_PyArg_NoKeywords("dropwhile()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, "dropwhile", 2, 2, &func, &seq)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(seq); + if (it == NULL) + return NULL; + + /* create dropwhileobject structure */ + lz = (dropwhileobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + Py_INCREF(func); + lz->func = func; + lz->it = it; + lz->start = 0; + + return (PyObject *)lz; +} + +static void +dropwhile_dealloc(dropwhileobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); + lz->ob_type->tp_free(lz); +} + +static int +dropwhile_traverse(dropwhileobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + Py_VISIT(lz->func); + return 0; +} + +static PyObject * +dropwhile_next(dropwhileobject *lz) +{ + PyObject *item, *good; + PyObject *it = lz->it; + long ok; + PyObject *(*iternext)(PyObject *); + + assert(PyIter_Check(it)); + iternext = *it->ob_type->tp_iternext; + for (;;) { + item = iternext(it); + if (item == NULL) + return NULL; + if (lz->start == 1) + return item; + + good = PyObject_CallFunctionObjArgs(lz->func, item, NULL); + if (good == NULL) { + Py_DECREF(item); + return NULL; + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + if (!ok) { + lz->start = 1; + return item; + } + Py_DECREF(item); + } +} + +PyDoc_STRVAR(dropwhile_doc, +"dropwhile(predicate, iterable) --> dropwhile object\n\ +\n\ +Drop items from the iterable while predicate(item) is true.\n\ +Afterwards, return every element until the iterable is exhausted."); + +static PyTypeObject dropwhile_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.dropwhile", /* tp_name */ + sizeof(dropwhileobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)dropwhile_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + dropwhile_doc, /* tp_doc */ + (traverseproc)dropwhile_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)dropwhile_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + dropwhile_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* takewhile object **********************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *func; + PyObject *it; + long stop; +} takewhileobject; + +static PyTypeObject takewhile_type; + +static PyObject * +takewhile_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *func, *seq; + PyObject *it; + takewhileobject *lz; + + if (type == &takewhile_type && !_PyArg_NoKeywords("takewhile()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, "takewhile", 2, 2, &func, &seq)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(seq); + if (it == NULL) + return NULL; + + /* create takewhileobject structure */ + lz = (takewhileobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + Py_INCREF(func); + lz->func = func; + lz->it = it; + lz->stop = 0; + + return (PyObject *)lz; +} + +static void +takewhile_dealloc(takewhileobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); + lz->ob_type->tp_free(lz); +} + +static int +takewhile_traverse(takewhileobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + Py_VISIT(lz->func); + return 0; +} + +static PyObject * +takewhile_next(takewhileobject *lz) +{ + PyObject *item, *good; + PyObject *it = lz->it; + long ok; + + if (lz->stop == 1) + return NULL; + + assert(PyIter_Check(it)); + item = (*it->ob_type->tp_iternext)(it); + if (item == NULL) + return NULL; + + good = PyObject_CallFunctionObjArgs(lz->func, item, NULL); + if (good == NULL) { + Py_DECREF(item); + return NULL; + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + if (ok) + return item; + Py_DECREF(item); + lz->stop = 1; + return NULL; +} + +PyDoc_STRVAR(takewhile_doc, +"takewhile(predicate, iterable) --> takewhile object\n\ +\n\ +Return successive entries from an iterable as long as the \n\ +predicate evaluates to true for each entry."); + +static PyTypeObject takewhile_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.takewhile", /* tp_name */ + sizeof(takewhileobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)takewhile_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + takewhile_doc, /* tp_doc */ + (traverseproc)takewhile_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)takewhile_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + takewhile_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* islice object ************************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *it; + Py_ssize_t next; + Py_ssize_t stop; + Py_ssize_t step; + Py_ssize_t cnt; +} isliceobject; + +static PyTypeObject islice_type; + +static PyObject * +islice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *seq; + Py_ssize_t start=0, stop=-1, step=1; + PyObject *it, *a1=NULL, *a2=NULL, *a3=NULL; + Py_ssize_t numargs; + isliceobject *lz; + + if (type == &islice_type && !_PyArg_NoKeywords("islice()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, "islice", 2, 4, &seq, &a1, &a2, &a3)) + return NULL; + + numargs = PyTuple_Size(args); + if (numargs == 2) { + if (a1 != Py_None) { + stop = PyInt_AsSsize_t(a1); + if (stop == -1) { + if (PyErr_Occurred()) + PyErr_Clear(); + PyErr_SetString(PyExc_ValueError, + "Stop argument for islice() must be a non-negative integer or None."); + return NULL; + } + } + } else { + if (a1 != Py_None) + start = PyInt_AsSsize_t(a1); + if (start == -1 && PyErr_Occurred()) + PyErr_Clear(); + if (a2 != Py_None) { + stop = PyInt_AsSsize_t(a2); + if (stop == -1) { + if (PyErr_Occurred()) + PyErr_Clear(); + PyErr_SetString(PyExc_ValueError, + "Stop argument for islice() must be a non-negative integer or None."); + return NULL; + } + } + } + if (start<0 || stop<-1) { + PyErr_SetString(PyExc_ValueError, + "Indices for islice() must be non-negative integers or None."); + return NULL; + } + + if (a3 != NULL) { + if (a3 != Py_None) + step = PyInt_AsSsize_t(a3); + if (step == -1 && PyErr_Occurred()) + PyErr_Clear(); + } + if (step<1) { + PyErr_SetString(PyExc_ValueError, + "Step for islice() must be a positive integer or None."); + return NULL; + } + + /* Get iterator. */ + it = PyObject_GetIter(seq); + if (it == NULL) + return NULL; + + /* create isliceobject structure */ + lz = (isliceobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + lz->it = it; + lz->next = start; + lz->stop = stop; + lz->step = step; + lz->cnt = 0L; + + return (PyObject *)lz; +} + +static void +islice_dealloc(isliceobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->it); + lz->ob_type->tp_free(lz); +} + +static int +islice_traverse(isliceobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + return 0; +} + +static PyObject * +islice_next(isliceobject *lz) +{ + PyObject *item; + PyObject *it = lz->it; + Py_ssize_t oldnext; + PyObject *(*iternext)(PyObject *); + + assert(PyIter_Check(it)); + iternext = *it->ob_type->tp_iternext; + while (lz->cnt < lz->next) { + item = iternext(it); + if (item == NULL) + return NULL; + Py_DECREF(item); + lz->cnt++; + } + if (lz->stop != -1 && lz->cnt >= lz->stop) + return NULL; + assert(PyIter_Check(it)); + item = iternext(it); + if (item == NULL) + return NULL; + lz->cnt++; + oldnext = lz->next; + lz->next += lz->step; + if (lz->next < oldnext) /* Check for overflow */ + lz->next = lz->stop; + return item; +} + +PyDoc_STRVAR(islice_doc, +"islice(iterable, [start,] stop [, step]) --> islice object\n\ +\n\ +Return an iterator whose next() method returns selected values from an\n\ +iterable. If start is specified, will skip all preceding elements;\n\ +otherwise, start defaults to zero. Step defaults to one. If\n\ +specified as another value, step determines how many values are \n\ +skipped between successive calls. Works like a slice() on a list\n\ +but returns an iterator."); + +static PyTypeObject islice_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.islice", /* tp_name */ + sizeof(isliceobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)islice_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + islice_doc, /* tp_doc */ + (traverseproc)islice_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)islice_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + islice_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* starmap object ************************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *func; + PyObject *it; +} starmapobject; + +static PyTypeObject starmap_type; + +static PyObject * +starmap_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *func, *seq; + PyObject *it; + starmapobject *lz; + + if (type == &starmap_type && !_PyArg_NoKeywords("starmap()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, "starmap", 2, 2, &func, &seq)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(seq); + if (it == NULL) + return NULL; + + /* create starmapobject structure */ + lz = (starmapobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + Py_INCREF(func); + lz->func = func; + lz->it = it; + + return (PyObject *)lz; +} + +static void +starmap_dealloc(starmapobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); + lz->ob_type->tp_free(lz); +} + +static int +starmap_traverse(starmapobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + Py_VISIT(lz->func); + return 0; +} + +static PyObject * +starmap_next(starmapobject *lz) +{ + PyObject *args; + PyObject *result; + PyObject *it = lz->it; + + assert(PyIter_Check(it)); + args = (*it->ob_type->tp_iternext)(it); + if (args == NULL) + return NULL; + if (!PyTuple_CheckExact(args)) { + Py_DECREF(args); + PyErr_SetString(PyExc_TypeError, + "iterator must return a tuple"); + return NULL; + } + result = PyObject_Call(lz->func, args, NULL); + Py_DECREF(args); + return result; +} + +PyDoc_STRVAR(starmap_doc, +"starmap(function, sequence) --> starmap object\n\ +\n\ +Return an iterator whose values are returned from the function evaluated\n\ +with a argument tuple taken from the given sequence."); + +static PyTypeObject starmap_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.starmap", /* tp_name */ + sizeof(starmapobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)starmap_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + starmap_doc, /* tp_doc */ + (traverseproc)starmap_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)starmap_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + starmap_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* imap object ************************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *iters; + PyObject *func; +} imapobject; + +static PyTypeObject imap_type; + +static PyObject * +imap_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *it, *iters, *func; + imapobject *lz; + Py_ssize_t numargs, i; + + if (type == &imap_type && !_PyArg_NoKeywords("imap()", kwds)) + return NULL; + + numargs = PyTuple_Size(args); + if (numargs < 2) { + PyErr_SetString(PyExc_TypeError, + "imap() must have at least two arguments."); + return NULL; + } + + iters = PyTuple_New(numargs-1); + if (iters == NULL) + return NULL; + + for (i=1 ; i<numargs ; i++) { + /* Get iterator. */ + it = PyObject_GetIter(PyTuple_GET_ITEM(args, i)); + if (it == NULL) { + Py_DECREF(iters); + return NULL; + } + PyTuple_SET_ITEM(iters, i-1, it); + } + + /* create imapobject structure */ + lz = (imapobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(iters); + return NULL; + } + lz->iters = iters; + func = PyTuple_GET_ITEM(args, 0); + Py_INCREF(func); + lz->func = func; + + return (PyObject *)lz; +} + +static void +imap_dealloc(imapobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->iters); + Py_XDECREF(lz->func); + lz->ob_type->tp_free(lz); +} + +static int +imap_traverse(imapobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->iters); + Py_VISIT(lz->func); + return 0; +} + +/* +imap() is an iterator version of __builtins__.map() except that it does +not have the None fill-in feature. That was intentionally left out for +the following reasons: + + 1) Itertools are designed to be easily combined and chained together. + Having all tools stop with the shortest input is a unifying principle + that makes it easier to combine finite iterators (supplying data) with + infinite iterators like count() and repeat() (for supplying sequential + or constant arguments to a function). + + 2) In typical use cases for combining itertools, having one finite data + supplier run out before another is likely to be an error condition which + should not pass silently by automatically supplying None. + + 3) The use cases for automatic None fill-in are rare -- not many functions + do something useful when a parameter suddenly switches type and becomes + None. + + 4) If a need does arise, it can be met by __builtins__.map() or by + writing: chain(iterable, repeat(None)). + + 5) Similar toolsets in Haskell and SML do not have automatic None fill-in. +*/ + +static PyObject * +imap_next(imapobject *lz) +{ + PyObject *val; + PyObject *argtuple; + PyObject *result; + Py_ssize_t numargs, i; + + numargs = PyTuple_Size(lz->iters); + argtuple = PyTuple_New(numargs); + if (argtuple == NULL) + return NULL; + + for (i=0 ; i<numargs ; i++) { + val = PyIter_Next(PyTuple_GET_ITEM(lz->iters, i)); + if (val == NULL) { + Py_DECREF(argtuple); + return NULL; + } + PyTuple_SET_ITEM(argtuple, i, val); + } + if (lz->func == Py_None) + return argtuple; + result = PyObject_Call(lz->func, argtuple, NULL); + Py_DECREF(argtuple); + return result; +} + +PyDoc_STRVAR(imap_doc, +"imap(func, *iterables) --> imap object\n\ +\n\ +Make an iterator that computes the function using arguments from\n\ +each of the iterables. Like map() except that it returns\n\ +an iterator instead of a list and that it stops when the shortest\n\ +iterable is exhausted instead of filling in None for shorter\n\ +iterables."); + +static PyTypeObject imap_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.imap", /* tp_name */ + sizeof(imapobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)imap_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + imap_doc, /* tp_doc */ + (traverseproc)imap_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)imap_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + imap_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* chain object ************************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t tuplesize; + Py_ssize_t iternum; /* which iterator is active */ + PyObject *ittuple; /* tuple of iterators */ +} chainobject; + +static PyTypeObject chain_type; + +static PyObject * +chain_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + chainobject *lz; + Py_ssize_t tuplesize = PySequence_Length(args); + Py_ssize_t i; + PyObject *ittuple; + + if (type == &chain_type && !_PyArg_NoKeywords("chain()", kwds)) + return NULL; + + /* obtain iterators */ + assert(PyTuple_Check(args)); + ittuple = PyTuple_New(tuplesize); + if (ittuple == NULL) + return NULL; + for (i=0; i < tuplesize; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + PyObject *it = PyObject_GetIter(item); + if (it == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "chain argument #%zd must support iteration", + i+1); + Py_DECREF(ittuple); + return NULL; + } + PyTuple_SET_ITEM(ittuple, i, it); + } + + /* create chainobject structure */ + lz = (chainobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(ittuple); + return NULL; + } + + lz->ittuple = ittuple; + lz->iternum = 0; + lz->tuplesize = tuplesize; + + return (PyObject *)lz; +} + +static void +chain_dealloc(chainobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->ittuple); + lz->ob_type->tp_free(lz); +} + +static int +chain_traverse(chainobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->ittuple); + return 0; +} + +static PyObject * +chain_next(chainobject *lz) +{ + PyObject *it; + PyObject *item; + + while (lz->iternum < lz->tuplesize) { + it = PyTuple_GET_ITEM(lz->ittuple, lz->iternum); + item = PyIter_Next(it); + if (item != NULL) + return item; + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + else + return NULL; + } + lz->iternum++; + } + return NULL; +} + +PyDoc_STRVAR(chain_doc, +"chain(*iterables) --> chain object\n\ +\n\ +Return a chain object whose .next() method returns elements from the\n\ +first iterable until it is exhausted, then elements from the next\n\ +iterable, until all of the iterables are exhausted."); + +static PyTypeObject chain_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.chain", /* tp_name */ + sizeof(chainobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)chain_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + chain_doc, /* tp_doc */ + (traverseproc)chain_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)chain_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + chain_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* ifilter object ************************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *func; + PyObject *it; +} ifilterobject; + +static PyTypeObject ifilter_type; + +static PyObject * +ifilter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *func, *seq; + PyObject *it; + ifilterobject *lz; + + if (type == &ifilter_type && !_PyArg_NoKeywords("ifilter()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, "ifilter", 2, 2, &func, &seq)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(seq); + if (it == NULL) + return NULL; + + /* create ifilterobject structure */ + lz = (ifilterobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + Py_INCREF(func); + lz->func = func; + lz->it = it; + + return (PyObject *)lz; +} + +static void +ifilter_dealloc(ifilterobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); + lz->ob_type->tp_free(lz); +} + +static int +ifilter_traverse(ifilterobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + Py_VISIT(lz->func); + return 0; +} + +static PyObject * +ifilter_next(ifilterobject *lz) +{ + PyObject *item; + PyObject *it = lz->it; + long ok; + PyObject *(*iternext)(PyObject *); + + assert(PyIter_Check(it)); + iternext = *it->ob_type->tp_iternext; + for (;;) { + item = iternext(it); + if (item == NULL) + return NULL; + + if (lz->func == Py_None) { + ok = PyObject_IsTrue(item); + } else { + PyObject *good; + good = PyObject_CallFunctionObjArgs(lz->func, + item, NULL); + if (good == NULL) { + Py_DECREF(item); + return NULL; + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + } + if (ok) + return item; + Py_DECREF(item); + } +} + +PyDoc_STRVAR(ifilter_doc, +"ifilter(function or None, sequence) --> ifilter object\n\ +\n\ +Return those items of sequence for which function(item) is true.\n\ +If function is None, return the items that are true."); + +static PyTypeObject ifilter_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.ifilter", /* tp_name */ + sizeof(ifilterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)ifilter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + ifilter_doc, /* tp_doc */ + (traverseproc)ifilter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)ifilter_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + ifilter_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* ifilterfalse object ************************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *func; + PyObject *it; +} ifilterfalseobject; + +static PyTypeObject ifilterfalse_type; + +static PyObject * +ifilterfalse_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *func, *seq; + PyObject *it; + ifilterfalseobject *lz; + + if (type == &ifilterfalse_type && + !_PyArg_NoKeywords("ifilterfalse()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, "ifilterfalse", 2, 2, &func, &seq)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(seq); + if (it == NULL) + return NULL; + + /* create ifilterfalseobject structure */ + lz = (ifilterfalseobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + Py_INCREF(func); + lz->func = func; + lz->it = it; + + return (PyObject *)lz; +} + +static void +ifilterfalse_dealloc(ifilterfalseobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->func); + Py_XDECREF(lz->it); + lz->ob_type->tp_free(lz); +} + +static int +ifilterfalse_traverse(ifilterfalseobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + Py_VISIT(lz->func); + return 0; +} + +static PyObject * +ifilterfalse_next(ifilterfalseobject *lz) +{ + PyObject *item; + PyObject *it = lz->it; + long ok; + PyObject *(*iternext)(PyObject *); + + assert(PyIter_Check(it)); + iternext = *it->ob_type->tp_iternext; + for (;;) { + item = iternext(it); + if (item == NULL) + return NULL; + + if (lz->func == Py_None) { + ok = PyObject_IsTrue(item); + } else { + PyObject *good; + good = PyObject_CallFunctionObjArgs(lz->func, + item, NULL); + if (good == NULL) { + Py_DECREF(item); + return NULL; + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + } + if (!ok) + return item; + Py_DECREF(item); + } +} + +PyDoc_STRVAR(ifilterfalse_doc, +"ifilterfalse(function or None, sequence) --> ifilterfalse object\n\ +\n\ +Return those items of sequence for which function(item) is false.\n\ +If function is None, return the items that are false."); + +static PyTypeObject ifilterfalse_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.ifilterfalse", /* tp_name */ + sizeof(ifilterfalseobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)ifilterfalse_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + ifilterfalse_doc, /* tp_doc */ + (traverseproc)ifilterfalse_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)ifilterfalse_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + ifilterfalse_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* count object ************************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t cnt; +} countobject; + +static PyTypeObject count_type; + +static PyObject * +count_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + countobject *lz; + Py_ssize_t cnt = 0; + + if (type == &count_type && !_PyArg_NoKeywords("count()", kwds)) + return NULL; + + if (!PyArg_ParseTuple(args, "|n:count", &cnt)) + return NULL; + + /* create countobject structure */ + lz = (countobject *)PyObject_New(countobject, &count_type); + if (lz == NULL) + return NULL; + lz->cnt = cnt; + + return (PyObject *)lz; +} + +static PyObject * +count_next(countobject *lz) +{ + if (lz->cnt == LONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "cannot count beyond LONG_MAX"); + return NULL; + } + return PyInt_FromSsize_t(lz->cnt++); +} + +static PyObject * +count_repr(countobject *lz) +{ + return PyString_FromFormat("count(%zd)", lz->cnt); +} + +PyDoc_STRVAR(count_doc, +"count([firstval]) --> count object\n\ +\n\ +Return a count object whose .next() method returns consecutive\n\ +integers starting from zero or, if specified, from firstval."); + +static PyTypeObject count_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.count", /* tp_name */ + sizeof(countobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)PyObject_Del, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)count_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + count_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)count_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + count_new, /* tp_new */ +}; + + +/* izip object ************************************************************/ + +#include "Python.h" + +typedef struct { + PyObject_HEAD + Py_ssize_t tuplesize; + PyObject *ittuple; /* tuple of iterators */ + PyObject *result; +} izipobject; + +static PyTypeObject izip_type; + +static PyObject * +izip_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + izipobject *lz; + Py_ssize_t i; + PyObject *ittuple; /* tuple of iterators */ + PyObject *result; + Py_ssize_t tuplesize = PySequence_Length(args); + + if (type == &izip_type && !_PyArg_NoKeywords("izip()", kwds)) + return NULL; + + /* args must be a tuple */ + assert(PyTuple_Check(args)); + + /* obtain iterators */ + ittuple = PyTuple_New(tuplesize); + if (ittuple == NULL) + return NULL; + for (i=0; i < tuplesize; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + PyObject *it = PyObject_GetIter(item); + if (it == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "izip argument #%zd must support iteration", + i+1); + Py_DECREF(ittuple); + return NULL; + } + PyTuple_SET_ITEM(ittuple, i, it); + } + + /* create a result holder */ + result = PyTuple_New(tuplesize); + if (result == NULL) { + Py_DECREF(ittuple); + return NULL; + } + for (i=0 ; i < tuplesize ; i++) { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(result, i, Py_None); + } + + /* create izipobject structure */ + lz = (izipobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(ittuple); + Py_DECREF(result); + return NULL; + } + lz->ittuple = ittuple; + lz->tuplesize = tuplesize; + lz->result = result; + + return (PyObject *)lz; +} + +static void +izip_dealloc(izipobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->ittuple); + Py_XDECREF(lz->result); + lz->ob_type->tp_free(lz); +} + +static int +izip_traverse(izipobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->ittuple); + Py_VISIT(lz->result); + return 0; +} + +static PyObject * +izip_next(izipobject *lz) +{ + Py_ssize_t i; + Py_ssize_t tuplesize = lz->tuplesize; + PyObject *result = lz->result; + PyObject *it; + PyObject *item; + PyObject *olditem; + + if (tuplesize == 0) + return NULL; + if (result->ob_refcnt == 1) { + Py_INCREF(result); + for (i=0 ; i < tuplesize ; i++) { + it = PyTuple_GET_ITEM(lz->ittuple, i); + assert(PyIter_Check(it)); + item = (*it->ob_type->tp_iternext)(it); + if (item == NULL) { + Py_DECREF(result); + return NULL; + } + olditem = PyTuple_GET_ITEM(result, i); + PyTuple_SET_ITEM(result, i, item); + Py_DECREF(olditem); + } + } else { + result = PyTuple_New(tuplesize); + if (result == NULL) + return NULL; + for (i=0 ; i < tuplesize ; i++) { + it = PyTuple_GET_ITEM(lz->ittuple, i); + assert(PyIter_Check(it)); + item = (*it->ob_type->tp_iternext)(it); + if (item == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, item); + } + } + return result; +} + +PyDoc_STRVAR(izip_doc, +"izip(iter1 [,iter2 [...]]) --> izip object\n\ +\n\ +Return a izip object whose .next() method returns a tuple where\n\ +the i-th element comes from the i-th iterable argument. The .next()\n\ +method continues until the shortest iterable in the argument sequence\n\ +is exhausted and then it raises StopIteration. Works like the zip()\n\ +function but consumes less memory by returning an iterator instead of\n\ +a list."); + +static PyTypeObject izip_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.izip", /* tp_name */ + sizeof(izipobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)izip_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + izip_doc, /* tp_doc */ + (traverseproc)izip_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)izip_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + izip_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* repeat object ************************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *element; + Py_ssize_t cnt; +} repeatobject; + +static PyTypeObject repeat_type; + +static PyObject * +repeat_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + repeatobject *ro; + PyObject *element; + Py_ssize_t cnt = -1; + + if (type == &repeat_type && !_PyArg_NoKeywords("repeat()", kwds)) + return NULL; + + if (!PyArg_ParseTuple(args, "O|n:repeat", &element, &cnt)) + return NULL; + + if (PyTuple_Size(args) == 2 && cnt < 0) + cnt = 0; + + ro = (repeatobject *)type->tp_alloc(type, 0); + if (ro == NULL) + return NULL; + Py_INCREF(element); + ro->element = element; + ro->cnt = cnt; + return (PyObject *)ro; +} + +static void +repeat_dealloc(repeatobject *ro) +{ + PyObject_GC_UnTrack(ro); + Py_XDECREF(ro->element); + ro->ob_type->tp_free(ro); +} + +static int +repeat_traverse(repeatobject *ro, visitproc visit, void *arg) +{ + Py_VISIT(ro->element); + return 0; +} + +static PyObject * +repeat_next(repeatobject *ro) +{ + if (ro->cnt == 0) + return NULL; + if (ro->cnt > 0) + ro->cnt--; + Py_INCREF(ro->element); + return ro->element; +} + +static PyObject * +repeat_repr(repeatobject *ro) +{ + PyObject *result, *objrepr; + + objrepr = PyObject_Repr(ro->element); + if (objrepr == NULL) + return NULL; + + if (ro->cnt == -1) + result = PyString_FromFormat("repeat(%s)", + PyString_AS_STRING(objrepr)); + else + result = PyString_FromFormat("repeat(%s, %zd)", + PyString_AS_STRING(objrepr), ro->cnt); + Py_DECREF(objrepr); + return result; +} + +static PyObject * +repeat_len(repeatobject *ro) +{ + if (ro->cnt == -1) { + PyErr_SetString(PyExc_TypeError, "len() of unsized object"); + return NULL; + } + return PyInt_FromSize_t(ro->cnt); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef repeat_methods[] = { + {"__length_hint__", (PyCFunction)repeat_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(repeat_doc, +"repeat(element [,times]) -> create an iterator which returns the element\n\ +for the specified number of times. If not specified, returns the element\n\ +endlessly."); + +static PyTypeObject repeat_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "itertools.repeat", /* tp_name */ + sizeof(repeatobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)repeat_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)repeat_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + repeat_doc, /* tp_doc */ + (traverseproc)repeat_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)repeat_next, /* tp_iternext */ + repeat_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + repeat_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* module level code ********************************************************/ + +PyDoc_STRVAR(module_doc, +"Functional tools for creating and using iterators.\n\ +\n\ +Infinite iterators:\n\ +count([n]) --> n, n+1, n+2, ...\n\ +cycle(p) --> p0, p1, ... plast, p0, p1, ...\n\ +repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\ +\n\ +Iterators terminating on the shortest input sequence:\n\ +izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ... \n\ +ifilter(pred, seq) --> elements of seq where pred(elem) is True\n\ +ifilterfalse(pred, seq) --> elements of seq where pred(elem) is False\n\ +islice(seq, [start,] stop [, step]) --> elements from\n\ + seq[start:stop:step]\n\ +imap(fun, p, q, ...) --> fun(p0, q0), fun(p1, q1), ...\n\ +starmap(fun, seq) --> fun(*seq[0]), fun(*seq[1]), ...\n\ +tee(it, n=2) --> (it1, it2 , ... itn) splits one iterator into n\n\ +chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\ +takewhile(pred, seq) --> seq[0], seq[1], until pred fails\n\ +dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\ +groupby(iterable[, keyfunc]) --> sub-iterators grouped by value of keyfunc(v)\n\ +"); + + +static PyMethodDef module_methods[] = { + {"tee", (PyCFunction)tee, METH_VARARGS, tee_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +inititertools(void) +{ + int i; + PyObject *m; + char *name; + PyTypeObject *typelist[] = { + &cycle_type, + &dropwhile_type, + &takewhile_type, + &islice_type, + &starmap_type, + &imap_type, + &chain_type, + &ifilter_type, + &ifilterfalse_type, + &count_type, + &izip_type, + &repeat_type, + &groupby_type, + NULL + }; + + teedataobject_type.ob_type = &PyType_Type; + m = Py_InitModule3("itertools", module_methods, module_doc); + if (m == NULL) + return; + + for (i=0 ; typelist[i] != NULL ; i++) { + if (PyType_Ready(typelist[i]) < 0) + return; + name = strchr(typelist[i]->tp_name, '.'); + assert (name != NULL); + Py_INCREF(typelist[i]); + PyModule_AddObject(m, name+1, (PyObject *)typelist[i]); + } + + if (PyType_Ready(&teedataobject_type) < 0) + return; + if (PyType_Ready(&tee_type) < 0) + return; + if (PyType_Ready(&_grouper_type) < 0) + return; +} diff --git a/sys/src/cmd/python/Modules/ld_so_aix b/sys/src/cmd/python/Modules/ld_so_aix new file mode 100755 index 000000000..76afa6e48 --- /dev/null +++ b/sys/src/cmd/python/Modules/ld_so_aix @@ -0,0 +1,187 @@ +#!/bin/sh +# +# ======================================================================== +# FILE: ld_so_aix +# TYPE: executable, uses makexp_aix +# SYSTEM: AIX +# +# DESCRIPTION: Creates a shareable .o from a set of pre-compiled +# (unshared) .o files +# +# USAGE: ld_so_aix [CC] [arguments] +# +# ARGUMENTS: Same as for "ld". The following arguments are processed +# or supplied by this script (those marked with an asterisk +# can be overriden from command line): +# +# Argument Default value +# (*) -o [OutputFileName] -o shr.o +# (*) -e [EntryPointLabel] -e init[OutputBaseName] +# (*) -bE:[ExportFile] -bE:[OutputBaseName].exp +# (*) -bI:[ImportFile] -bI:./python.exp +# -bM:[ModuleType] -bM:SRE +# -bhalt:[Number] -bhalt:4 +# -T[Number] -T512 +# -H[Number] -H512 +# -lm +# +# The compiler specific ("-lc" or "-lc_r", "-lpthreads",...) +# arguments will be automatically passed to "ld" according +# to the CC command provided as a first argument to this +# script. Usually, the same CC command was used to produce +# the pre-compiled .o file(s). +# +# NOTES: 1. Since "ld_so_aix" was originally written for building +# shared modules for the Python interpreter, the -e and +# -bI default values match Python's conventions. In +# Python, the entry point for a shared module is based +# on the module's name (e.g., the "mathmodule" will +# expect an entry point of "initmath"). +# 2. The script accepts multiple .o or .a input files and +# creates a single (shared) output file. The export list +# that is created is based on the output file's basename +# with the suffix ".exp". +# 3. The resulting shared object file is left in the +# current directory. +# 4. Uncommenting the "echo" lines gives detailed output +# about the commands executed in the script. +# +# +# HISTORY: Oct-1996 -- Support added for multiple .o files -- +# -- and optional arguments processing. -- +# Chris Myers (myers@tc.cornell.edu), Keith Kwok +# (kkwok@tc.cornell.edu) and Vladimir Marangozov +# +# Aug-6-1996 -- Take care of the compiler specific -- +# -- args by leaving CC to invoke "ld". -- +# Vladimir Marangozov +# +# Jul-1-1996 -- Make sure to use /usr/ccs/bin/ld -- +# -- Use makexp_aix for the export list. -- +# Vladimir Marangozov (Vladimir.Marangozov@imag.fr) +# +# Manus Hand (mhand@csn.net) -- Initial code -- 6/24/96 +# ======================================================================== +# + +usage="Usage: ld_so_aix [CC command] [ld arguments]" +if test ! -n "$*"; then + echo $usage; exit 2 +fi + +makexp=`dirname $0`/makexp_aix + +# Check for existence of compiler. +CC=$1; shift +whichcc=`which $CC` + +if test ! -x "$whichcc"; then + echo "ld_so_aix: Compiler '$CC' not found; exiting." + exit 2 +fi + +if test ! -n "$*"; then + echo $usage; exit 2 +fi + +# Default import file for Python +# Can be overriden by providing a -bI: argument. +impfile="./python.exp" + +# Parse arguments +while test -n "$1" +do + case "$1" in + -e | -Wl,-e) + if test -z "$2"; then + echo "ld_so_aix: The -e flag needs a parameter; exiting."; exit 2 + else + shift; entry=$1 + fi + ;; + -e* | -Wl,-e*) + entry=`echo $1 | sed -e "s/-Wl,//" -e "s/-e//"` + ;; + -o) + if test -z "$2"; then + echo "ld_so_aix: The -o flag needs a parameter; exiting."; exit 2 + else + shift; objfile=$1 + fi + ;; + -o*) + objfile=`echo $1 | sed "s/-o//"` + ;; + -bI:* | -Wl,-bI:*) + impfile=`echo $1 | sed -e "s/-Wl,//" -e "s/-bI://"` + ;; + -bE:* | -Wl,-bE:*) + expfile=`echo $1 | sed -e "s/-Wl,//" -e "s/-bE://"` + ;; + *.o | *.a) + objs="$objs $1" + args="$args $1" + ;; + -bM:* | -Wl,-bM:* | -H* | -Wl,-H* | -T* | -Wl,-T* | -lm) + ;; + *) + args="$args $1" + ;; + esac + shift +done + + +if test -z "$objs"; then + echo "ld_so_aix: No input files; exiting." + exit 2 +elif test ! -r "$impfile"; then + echo "ld_so_aix: Import file '$impfile' not found or not readable; exiting." + exit 2 +fi + +# If -o wasn't specified, assume "-o shr.o" +if test -z "$objfile"; then + objfile=shr.o +fi + +filename=`basename $objfile | sed "s/\.[^.]*$//"` + +# If -bE: wasn't specified, assume "-bE:$filename.exp" +if test -z "$expfile"; then + expfile="$filename.exp" +fi + +# Default entry symbol for Python modules = init[modulename] +# Can be overriden by providing a -e argument. +if test -z "$entry"; then + entry=init`echo $filename | sed "s/module.*//"` +fi + +#echo "ld_so_aix: Debug info section" +#echo " -> output file : $objfile" +#echo " -> import file : $impfile" +#echo " -> export file : $expfile" +#echo " -> entry point : $entry" +#echo " -> object files: $objs" +#echo " -> CC arguments: $args" + +CCOPT="-Wl,-e$entry -Wl,-bE:$expfile -Wl,-bI:$impfile -Wl,-bhalt:4" +CCOPT="$CCOPT -Wl,-bM:SRE -Wl,-T512 -Wl,-H512 -lm -o $objfile" +# Note: to use dynamic libraries like libtcl8.4.so and libtk8.4.so +# you may need to replace the second CCOPT line above with the following: +# CCOPT="$CCOPT -Wl,-bM:SRE -Wl,-T512 -Wl,-H512 -brtl -bnortllib -lm -o $objfile" + +CCARGS="$args" + +# Export list generation. +#echo $makexp $expfile "$objfile" $objs +$makexp $expfile "$objfile" $objs + +# Perform the link. +#echo $CC $CCOPT $CCARGS +$CC $CCOPT $CCARGS + +# Delete the module's export list file. +# Comment this line if you need it. +rm -f $expfile diff --git a/sys/src/cmd/python/Modules/ld_so_beos b/sys/src/cmd/python/Modules/ld_so_beos new file mode 100755 index 000000000..0b867fbde --- /dev/null +++ b/sys/src/cmd/python/Modules/ld_so_beos @@ -0,0 +1,78 @@ +#! /bin/sh +# +# linkmodule for Python +# Chris Herborth (chrish@qnx.com) +# +# This is covered by the same copyright/licensing terms as the rest of +# Python. +# +# Shell script to build shared library versions of the modules; since +# the change to the *ahem* "proper" import/export mechanism, this script +# is much simpler. It handles PowerPC and x86, too. +# +# This is called by the Modules/Makefile as $(LDSHARED): +# +# $(LDSHARED) foomodule.o -o foomodule$(SO) +# +# Could also be called as: +# +# $(LDSHARED) readline.o -L/boot/home/config/lib -lreadline -ltermcap \ +# -o readline$(SO) +# +# so we need to preserve the arguments, sort of. + +# Make sure we got reasonable arguments. +TARGET="" +ARGS="" + +while [ "$#" != "0" ]; do + case "$1" in + -o) TARGET="$2"; shift; shift;; + *) ARGS="$ARGS $1"; shift;; + esac +done + +if [ "$TARGET" = "" ] ; then + echo "Usage:" + echo + echo " $0 [args] -o foomodule.so [args] foomodule.o [args]" + echo + echo "Where:" + echo + echo " [args] normal compiler arguments" + exit 1 +fi + +# The shared libraries and glue objects we need to link against; these +# libs are overkill for most of the standard modules, but it makes life +# in this shell script easier. +LIBS="-lbe -lnet -lroot" + +case $BE_HOST_CPU in + ppc) + # Boy, do we need a lot of crap... + GLUE_LOC=/boot/develop/lib/ppc + GLUE="${GLUE_LOC}/glue-noinit.a ${GLUE_LOC}/init_term_dyn.o" + case $(uname -r) in + 4.0*) CC="mwcc -xms -export pragma -nodup" ;; + *) CC="mwcc -shared -export pragma -nodup" ;; + esac + ;; + + x86) + # We don't need as much crap here... + GLUE="" + CC="gcc -nostart -Wl,-soname=${TARGET}" + ;; + + *) + # What the?!? + echo "$0 doesn't support $BE_HOST_CPU systems..." + echo "You're on your own... I'd be surprised if this works." + GLUE="" + CC="cc" + ;; +esac + +# Now link that shared lib... +$CC -o $TARGET $ARGS $GLUE $LIBS diff --git a/sys/src/cmd/python/Modules/linuxaudiodev.c b/sys/src/cmd/python/Modules/linuxaudiodev.c new file mode 100644 index 000000000..b435d768a --- /dev/null +++ b/sys/src/cmd/python/Modules/linuxaudiodev.c @@ -0,0 +1,502 @@ +/* Hey Emacs, this is -*-C-*- + ****************************************************************************** + * linuxaudiodev.c -- Linux audio device for python. + * + * Author : Peter Bosch + * Created On : Thu Mar 2 21:10:33 2000 + * Status : Unknown, Use with caution! + * + * Unless other notices are present in any part of this file + * explicitly claiming copyrights for other people and/or + * organizations, the contents of this file is fully copyright + * (C) 2000 Peter Bosch, all rights reserved. + ****************************************************************************** + */ + +#include "Python.h" +#include "structmember.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#else +#define O_RDONLY 00 +#define O_WRONLY 01 +#endif + + +#include <sys/ioctl.h> +#if defined(linux) +#include <linux/soundcard.h> + +#ifndef HAVE_STDINT_H +typedef unsigned long uint32_t; +#endif + +#elif defined(__FreeBSD__) +#include <machine/soundcard.h> + +#ifndef SNDCTL_DSP_CHANNELS +#define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS +#endif + +#endif + +typedef struct { + PyObject_HEAD + int x_fd; /* The open file */ + int x_mode; /* file mode */ + int x_icount; /* Input count */ + int x_ocount; /* Output count */ + uint32_t x_afmts; /* Audio formats supported by hardware*/ +} lad_t; + +/* XXX several format defined in soundcard.h are not supported, + including _NE (native endian) options and S32 options +*/ + +static struct { + int a_bps; + uint32_t a_fmt; + char *a_name; +} audio_types[] = { + { 8, AFMT_MU_LAW, "logarithmic mu-law 8-bit audio" }, + { 8, AFMT_A_LAW, "logarithmic A-law 8-bit audio" }, + { 8, AFMT_U8, "linear unsigned 8-bit audio" }, + { 8, AFMT_S8, "linear signed 8-bit audio" }, + { 16, AFMT_U16_BE, "linear unsigned 16-bit big-endian audio" }, + { 16, AFMT_U16_LE, "linear unsigned 16-bit little-endian audio" }, + { 16, AFMT_S16_BE, "linear signed 16-bit big-endian audio" }, + { 16, AFMT_S16_LE, "linear signed 16-bit little-endian audio" }, + { 16, AFMT_S16_NE, "linear signed 16-bit native-endian audio" }, +}; + +static int n_audio_types = sizeof(audio_types) / sizeof(audio_types[0]); + +static PyTypeObject Ladtype; + +static PyObject *LinuxAudioError; + +static lad_t * +newladobject(PyObject *arg) +{ + lad_t *xp; + int fd, afmts, imode; + char *basedev = NULL; + char *mode = NULL; + + /* Two ways to call linuxaudiodev.open(): + open(device, mode) (for consistency with builtin open()) + open(mode) (for backwards compatibility) + because the *first* argument is optional, parsing args is + a wee bit tricky. */ + if (!PyArg_ParseTuple(arg, "s|s:open", &basedev, &mode)) + return NULL; + if (mode == NULL) { /* only one arg supplied */ + mode = basedev; + basedev = NULL; + } + + if (strcmp(mode, "r") == 0) + imode = O_RDONLY; + else if (strcmp(mode, "w") == 0) + imode = O_WRONLY; + else { + PyErr_SetString(LinuxAudioError, "mode should be 'r' or 'w'"); + return NULL; + } + + /* Open the correct device. The base device name comes from the + * AUDIODEV environment variable first, then /dev/dsp. The + * control device tacks "ctl" onto the base device name. + * + * Note that the only difference between /dev/audio and /dev/dsp + * is that the former uses logarithmic mu-law encoding and the + * latter uses 8-bit unsigned encoding. + */ + + if (basedev == NULL) { /* called with one arg */ + basedev = getenv("AUDIODEV"); + if (basedev == NULL) /* $AUDIODEV not set */ + basedev = "/dev/dsp"; + } + + if ((fd = open(basedev, imode)) == -1) { + PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev); + return NULL; + } + if (imode == O_WRONLY && ioctl(fd, SNDCTL_DSP_NONBLOCK, NULL) == -1) { + PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev); + return NULL; + } + if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) == -1) { + PyErr_SetFromErrnoWithFilename(LinuxAudioError, basedev); + return NULL; + } + /* Create and initialize the object */ + if ((xp = PyObject_New(lad_t, &Ladtype)) == NULL) { + close(fd); + return NULL; + } + xp->x_fd = fd; + xp->x_mode = imode; + xp->x_icount = xp->x_ocount = 0; + xp->x_afmts = afmts; + return xp; +} + +static void +lad_dealloc(lad_t *xp) +{ + /* if already closed, don't reclose it */ + if (xp->x_fd != -1) + close(xp->x_fd); + PyObject_Del(xp); +} + +static PyObject * +lad_read(lad_t *self, PyObject *args) +{ + int size, count; + char *cp; + PyObject *rv; + + if (!PyArg_ParseTuple(args, "i:read", &size)) + return NULL; + rv = PyString_FromStringAndSize(NULL, size); + if (rv == NULL) + return NULL; + cp = PyString_AS_STRING(rv); + if ((count = read(self->x_fd, cp, size)) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + Py_DECREF(rv); + return NULL; + } + self->x_icount += count; + _PyString_Resize(&rv, count); + return rv; +} + +static PyObject * +lad_write(lad_t *self, PyObject *args) +{ + char *cp; + int rv, size; + fd_set write_set_fds; + struct timeval tv; + int select_retval; + + if (!PyArg_ParseTuple(args, "s#:write", &cp, &size)) + return NULL; + + /* use select to wait for audio device to be available */ + FD_ZERO(&write_set_fds); + FD_SET(self->x_fd, &write_set_fds); + tv.tv_sec = 4; /* timeout values */ + tv.tv_usec = 0; + + while (size > 0) { + select_retval = select(self->x_fd+1, NULL, &write_set_fds, NULL, &tv); + tv.tv_sec = 1; tv.tv_usec = 0; /* willing to wait this long next time*/ + if (select_retval) { + if ((rv = write(self->x_fd, cp, size)) == -1) { + if (errno != EAGAIN) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } else { + errno = 0; /* EAGAIN: buffer is full, try again */ + } + } else { + self->x_ocount += rv; + size -= rv; + cp += rv; + } + } else { + /* printf("Not able to write to linux audio device within %ld seconds\n", tv.tv_sec); */ + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +lad_close(lad_t *self, PyObject *unused) +{ + if (self->x_fd >= 0) { + close(self->x_fd); + self->x_fd = -1; + } + Py_RETURN_NONE; +} + +static PyObject * +lad_fileno(lad_t *self, PyObject *unused) +{ + return PyInt_FromLong(self->x_fd); +} + +static PyObject * +lad_setparameters(lad_t *self, PyObject *args) +{ + int rate, ssize, nchannels, n, fmt, emulate=0; + + if (!PyArg_ParseTuple(args, "iiii|i:setparameters", + &rate, &ssize, &nchannels, &fmt, &emulate)) + return NULL; + + if (rate < 0) { + PyErr_Format(PyExc_ValueError, "expected rate >= 0, not %d", + rate); + return NULL; + } + if (ssize < 0) { + PyErr_Format(PyExc_ValueError, "expected sample size >= 0, not %d", + ssize); + return NULL; + } + if (nchannels != 1 && nchannels != 2) { + PyErr_Format(PyExc_ValueError, "nchannels must be 1 or 2, not %d", + nchannels); + return NULL; + } + + for (n = 0; n < n_audio_types; n++) + if (fmt == audio_types[n].a_fmt) + break; + if (n == n_audio_types) { + PyErr_Format(PyExc_ValueError, "unknown audio encoding: %d", fmt); + return NULL; + } + if (audio_types[n].a_bps != ssize) { + PyErr_Format(PyExc_ValueError, + "for %s, expected sample size %d, not %d", + audio_types[n].a_name, audio_types[n].a_bps, ssize); + return NULL; + } + + if (emulate == 0) { + if ((self->x_afmts & audio_types[n].a_fmt) == 0) { + PyErr_Format(PyExc_ValueError, + "%s format not supported by device", + audio_types[n].a_name); + return NULL; + } + } + if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, + &audio_types[n].a_fmt) == -1) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + if (ioctl(self->x_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + if (ioctl(self->x_fd, SNDCTL_DSP_SPEED, &rate) == -1) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static int +_ssize(lad_t *self, int *nchannels, int *ssize) +{ + int fmt; + + fmt = 0; + if (ioctl(self->x_fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + return -errno; + + switch (fmt) { + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + *ssize = sizeof(char); + break; + case AFMT_S16_LE: + case AFMT_S16_BE: + case AFMT_U16_LE: + case AFMT_U16_BE: + *ssize = sizeof(short); + break; + case AFMT_MPEG: + case AFMT_IMA_ADPCM: + default: + return -EOPNOTSUPP; + } + if (ioctl(self->x_fd, SNDCTL_DSP_CHANNELS, nchannels) < 0) + return -errno; + return 0; +} + + +/* bufsize returns the size of the hardware audio buffer in number + of samples */ +static PyObject * +lad_bufsize(lad_t *self, PyObject *unused) +{ + audio_buf_info ai; + int nchannels=0, ssize=0; + + if (_ssize(self, &nchannels, &ssize) < 0 || !ssize || !nchannels) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + return PyInt_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize)); +} + +/* obufcount returns the number of samples that are available in the + hardware for playing */ +static PyObject * +lad_obufcount(lad_t *self, PyObject *unused) +{ + audio_buf_info ai; + int nchannels=0, ssize=0; + + if (_ssize(self, &nchannels, &ssize) < 0 || !ssize || !nchannels) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + return PyInt_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) / + (ssize * nchannels)); +} + +/* obufcount returns the number of samples that can be played without + blocking */ +static PyObject * +lad_obuffree(lad_t *self, PyObject *unused) +{ + audio_buf_info ai; + int nchannels=0, ssize=0; + + if (_ssize(self, &nchannels, &ssize) < 0 || !ssize || !nchannels) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + if (ioctl(self->x_fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + return PyInt_FromLong(ai.bytes / (ssize * nchannels)); +} + +/* Flush the device */ +static PyObject * +lad_flush(lad_t *self, PyObject *unused) +{ + if (ioctl(self->x_fd, SNDCTL_DSP_SYNC, NULL) == -1) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + Py_RETURN_NONE; +} + +static PyObject * +lad_getptr(lad_t *self, PyObject *unused) +{ + count_info info; + int req; + + if (self->x_mode == O_RDONLY) + req = SNDCTL_DSP_GETIPTR; + else + req = SNDCTL_DSP_GETOPTR; + if (ioctl(self->x_fd, req, &info) == -1) { + PyErr_SetFromErrno(LinuxAudioError); + return NULL; + } + return Py_BuildValue("iii", info.bytes, info.blocks, info.ptr); +} + +static PyMethodDef lad_methods[] = { + { "read", (PyCFunction)lad_read, METH_VARARGS }, + { "write", (PyCFunction)lad_write, METH_VARARGS }, + { "setparameters", (PyCFunction)lad_setparameters, METH_VARARGS }, + { "bufsize", (PyCFunction)lad_bufsize, METH_VARARGS }, + { "obufcount", (PyCFunction)lad_obufcount, METH_NOARGS }, + { "obuffree", (PyCFunction)lad_obuffree, METH_NOARGS }, + { "flush", (PyCFunction)lad_flush, METH_NOARGS }, + { "close", (PyCFunction)lad_close, METH_NOARGS }, + { "fileno", (PyCFunction)lad_fileno, METH_NOARGS }, + { "getptr", (PyCFunction)lad_getptr, METH_NOARGS }, + { NULL, NULL} /* sentinel */ +}; + +static PyObject * +lad_getattr(lad_t *xp, char *name) +{ + return Py_FindMethod(lad_methods, (PyObject *)xp, name); +} + +static PyTypeObject Ladtype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "linuxaudiodev.linux_audio_device", /*tp_name*/ + sizeof(lad_t), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)lad_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)lad_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyObject * +ladopen(PyObject *self, PyObject *args) +{ + return (PyObject *)newladobject(args); +} + +static PyMethodDef linuxaudiodev_methods[] = { + { "open", ladopen, METH_VARARGS }, + { 0, 0 }, +}; + +void +initlinuxaudiodev(void) +{ + PyObject *m; + + m = Py_InitModule("linuxaudiodev", linuxaudiodev_methods); + if (m == NULL) + return; + + LinuxAudioError = PyErr_NewException("linuxaudiodev.error", NULL, NULL); + if (LinuxAudioError) + PyModule_AddObject(m, "error", LinuxAudioError); + + if (PyModule_AddIntConstant(m, "AFMT_MU_LAW", (long)AFMT_MU_LAW) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_A_LAW", (long)AFMT_A_LAW) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_U8", (long)AFMT_U8) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_S8", (long)AFMT_S8) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_U16_BE", (long)AFMT_U16_BE) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_U16_LE", (long)AFMT_U16_LE) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_S16_BE", (long)AFMT_S16_BE) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_S16_LE", (long)AFMT_S16_LE) == -1) + return; + if (PyModule_AddIntConstant(m, "AFMT_S16_NE", (long)AFMT_S16_NE) == -1) + return; + + return; +} diff --git a/sys/src/cmd/python/Modules/main.c b/sys/src/cmd/python/Modules/main.c new file mode 100644 index 000000000..83d567fed --- /dev/null +++ b/sys/src/cmd/python/Modules/main.c @@ -0,0 +1,584 @@ +/* Python interpreter main program */ + +#include "Python.h" +#include "osdefs.h" +#include "code.h" /* For CO_FUTURE_DIVISION */ +#include "import.h" + +#ifdef __VMS +#include <unixlib.h> +#endif + +#if defined(MS_WINDOWS) || defined(__CYGWIN__) +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#endif + +#if (defined(PYOS_OS2) && !defined(PYCC_GCC)) || defined(MS_WINDOWS) +#define PYTHONHOMEHELP "<prefix>\\lib" +#else +#if defined(PYOS_OS2) && defined(PYCC_GCC) +#define PYTHONHOMEHELP "<prefix>/Lib" +#else +#define PYTHONHOMEHELP "<prefix>/pythonX.X" +#endif +#endif + +#include "pygetopt.h" + +#define COPYRIGHT \ + "Type \"help\", \"copyright\", \"credits\" or \"license\" " \ + "for more information." + +#ifdef __cplusplus +extern "C" { +#endif + +/* For Py_GetArgcArgv(); set by main() */ +static char **orig_argv; +static int orig_argc; + +/* command line options */ +#define BASE_OPTS "c:dEhim:OQ:StuUvVW:xX?" + +#ifndef RISCOS +#define PROGRAM_OPTS BASE_OPTS +#else /*RISCOS*/ +/* extra option saying that we are running under a special task window + frontend; especially my_readline will behave different */ +#define PROGRAM_OPTS BASE_OPTS "w" +/* corresponding flag */ +extern int Py_RISCOSWimpFlag; +#endif /*RISCOS*/ + +/* Short usage message (with %s for argv0) */ +static char *usage_line = +"usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...\n"; + +/* Long usage message, split into parts < 512 bytes */ +static char *usage_1 = "\ +Options and arguments (and corresponding environment variables):\n\ +-c cmd : program passed in as string (terminates option list)\n\ +-d : debug output from parser (also PYTHONDEBUG=x)\n\ +-E : ignore environment variables (such as PYTHONPATH)\n\ +-h : print this help message and exit (also --help)\n\ +-i : inspect interactively after running script, (also PYTHONINSPECT=x)\n\ + and force prompts, even if stdin does not appear to be a terminal\n\ +"; +static char *usage_2 = "\ +-m mod : run library module as a script (terminates option list)\n\ +-O : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n\ +-OO : remove doc-strings in addition to the -O optimizations\n\ +-Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\n\ +-S : don't imply 'import site' on initialization\n\ +-t : issue warnings about inconsistent tab usage (-tt: issue errors)\n\ +-u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)\n\ +"; +static char *usage_3 = "\ + see man page for details on internal buffering relating to '-u'\n\ +-v : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\ +-V : print the Python version number and exit (also --version)\n\ +-W arg : warning control (arg is action:message:category:module:lineno)\n\ +-x : skip first line of source, allowing use of non-Unix forms of #!cmd\n\ +file : program read from script file\n\ +- : program read from stdin (default; interactive mode if a tty)\n\ +"; +static char *usage_4 = "\ +arg ...: arguments passed to program in sys.argv[1:]\n\ +Other environment variables:\n\ +PYTHONSTARTUP: file executed on interactive startup (no default)\n\ +PYTHONPATH : '%c'-separated list of directories prefixed to the\n\ + default module search path. The result is sys.path.\n\ +PYTHONHOME : alternate <prefix> directory (or <prefix>%c<exec_prefix>).\n\ + The default module search path uses %s.\n\ +PYTHONCASEOK : ignore case in 'import' statements (Windows).\n\ +"; + + +static int +usage(int exitcode, char* program) +{ + FILE *f = exitcode ? stderr : stdout; + + fprintf(f, usage_line, program); + if (exitcode) + fprintf(f, "Try `python -h' for more information.\n"); + else { + fprintf(f, usage_1); + fprintf(f, usage_2); + fprintf(f, usage_3); + fprintf(f, usage_4, DELIM, DELIM, PYTHONHOMEHELP); + } +#if defined(__VMS) + if (exitcode == 0) { + /* suppress 'error' message */ + return 1; + } + else { + /* STS$M_INHIB_MSG + SS$_ABORT */ + return 0x1000002c; + } +#else + return exitcode; +#endif + /*NOTREACHED*/ +} + +static void RunStartupFile(PyCompilerFlags *cf) +{ + char *startup = Py_GETENV("PYTHONSTARTUP"); + if (startup != NULL && startup[0] != '\0') { + FILE *fp = fopen(startup, "r"); + if (fp != NULL) { + (void) PyRun_SimpleFileExFlags(fp, startup, 0, cf); + PyErr_Clear(); + fclose(fp); + } + } +} + + +static int RunModule(char *module) +{ + PyObject *runpy, *runmodule, *runargs, *result; + runpy = PyImport_ImportModule("runpy"); + if (runpy == NULL) { + fprintf(stderr, "Could not import runpy module\n"); + return -1; + } + runmodule = PyObject_GetAttrString(runpy, "run_module"); + if (runmodule == NULL) { + fprintf(stderr, "Could not access runpy.run_module\n"); + Py_DECREF(runpy); + return -1; + } + runargs = Py_BuildValue("sOsO", module, + Py_None, "__main__", Py_True); + if (runargs == NULL) { + fprintf(stderr, + "Could not create arguments for runpy.run_module\n"); + Py_DECREF(runpy); + Py_DECREF(runmodule); + return -1; + } + result = PyObject_Call(runmodule, runargs, NULL); + if (result == NULL) { + PyErr_Print(); + } + Py_DECREF(runpy); + Py_DECREF(runmodule); + Py_DECREF(runargs); + if (result == NULL) { + return -1; + } + Py_DECREF(result); + return 0; +} + +/* Wait until threading._shutdown completes, provided + the threading module was imported in the first place. + The shutdown routine will wait until all non-daemon + "threading" threads have completed. */ +#include "abstract.h" +static void +WaitForThreadShutdown() +{ +#ifdef WITH_THREAD + PyObject *result; + PyThreadState *tstate = PyThreadState_GET(); + PyObject *threading = PyMapping_GetItemString(tstate->interp->modules, + "threading"); + if (threading == NULL) { + /* threading not imported */ + PyErr_Clear(); + return; + } + result = PyObject_CallMethod(threading, "_shutdown", ""); + if (result == NULL) + PyErr_WriteUnraisable(threading); + else + Py_DECREF(result); + Py_DECREF(threading); +#endif +} + +/* Main program */ + +int +Py_Main(int argc, char **argv) +{ + int c; + int sts; + char *command = NULL; + char *filename = NULL; + char *module = NULL; + FILE *fp = stdin; + char *p; + int inspect = 0; + int unbuffered = 0; + int skipfirstline = 0; + int stdin_is_interactive = 0; + int help = 0; + int version = 0; + int saw_inspect_flag = 0; + int saw_unbuffered_flag = 0; + PyCompilerFlags cf; + + cf.cf_flags = 0; + + orig_argc = argc; /* For Py_GetArgcArgv() */ + orig_argv = argv; + +#ifdef RISCOS + Py_RISCOSWimpFlag = 0; +#endif + + PySys_ResetWarnOptions(); + + while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) { + if (c == 'c') { + /* -c is the last option; following arguments + that look like options are left for the + command to interpret. */ + command = (char *)malloc(strlen(_PyOS_optarg) + 2); + if (command == NULL) + Py_FatalError( + "not enough memory to copy -c argument"); + strcpy(command, _PyOS_optarg); + strcat(command, "\n"); + break; + } + + if (c == 'm') { + /* -m is the last option; following arguments + that look like options are left for the + module to interpret. */ + module = (char *)malloc(strlen(_PyOS_optarg) + 2); + if (module == NULL) + Py_FatalError( + "not enough memory to copy -m argument"); + strcpy(module, _PyOS_optarg); + break; + } + + switch (c) { + + case 'd': + Py_DebugFlag++; + break; + + case 'Q': + if (strcmp(_PyOS_optarg, "old") == 0) { + Py_DivisionWarningFlag = 0; + break; + } + if (strcmp(_PyOS_optarg, "warn") == 0) { + Py_DivisionWarningFlag = 1; + break; + } + if (strcmp(_PyOS_optarg, "warnall") == 0) { + Py_DivisionWarningFlag = 2; + break; + } + if (strcmp(_PyOS_optarg, "new") == 0) { + /* This only affects __main__ */ + cf.cf_flags |= CO_FUTURE_DIVISION; + /* And this tells the eval loop to treat + BINARY_DIVIDE as BINARY_TRUE_DIVIDE */ + _Py_QnewFlag = 1; + break; + } + fprintf(stderr, + "-Q option should be `-Qold', " + "`-Qwarn', `-Qwarnall', or `-Qnew' only\n"); + return usage(2, argv[0]); + /* NOTREACHED */ + + case 'i': + inspect++; + saw_inspect_flag = 1; + Py_InteractiveFlag++; + break; + + case 'O': + Py_OptimizeFlag++; + break; + + case 'S': + Py_NoSiteFlag++; + break; + + case 'E': + Py_IgnoreEnvironmentFlag++; + break; + + case 't': + Py_TabcheckFlag++; + break; + + case 'u': + unbuffered++; + saw_unbuffered_flag = 1; + break; + + case 'v': + Py_VerboseFlag++; + break; + +#ifdef RISCOS + case 'w': + Py_RISCOSWimpFlag = 1; + break; +#endif + + case 'x': + skipfirstline = 1; + break; + + case 'U': + Py_UnicodeFlag++; + break; + case 'h': + case '?': + help++; + break; + case 'V': + version++; + break; + + case 'W': + PySys_AddWarnOption(_PyOS_optarg); + break; + + /* This space reserved for other options */ + + default: + return usage(2, argv[0]); + /*NOTREACHED*/ + + } + } + + if (help) + return usage(0, argv[0]); + + if (version) { + fprintf(stderr, "Python %s\n", PY_VERSION); + return 0; + } + + if (!saw_inspect_flag && + (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') + inspect = 1; + if (!saw_unbuffered_flag && + (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') + unbuffered = 1; + + if (command == NULL && module == NULL && _PyOS_optind < argc && + strcmp(argv[_PyOS_optind], "-") != 0) + { +#ifdef __VMS + filename = decc$translate_vms(argv[_PyOS_optind]); + if (filename == (char *)0 || filename == (char *)-1) + filename = argv[_PyOS_optind]; + +#else + filename = argv[_PyOS_optind]; +#endif + if (filename != NULL) { + if ((fp = fopen(filename, "r")) == NULL) { +#ifdef HAVE_STRERROR + fprintf(stderr, "%s: can't open file '%s': [Errno %d] %s\n", + argv[0], filename, errno, strerror(errno)); +#else + fprintf(stderr, "%s: can't open file '%s': Errno %d\n", + argv[0], filename, errno); +#endif + return 2; + } + else if (skipfirstline) { + int ch; + /* Push back first newline so line numbers + remain the same */ + while ((ch = getc(fp)) != EOF) { + if (ch == '\n') { + (void)ungetc(ch, fp); + break; + } + } + } + { + /* XXX: does this work on Win/Win64? (see posix_fstat) */ + struct stat sb; + if (fstat(fileno(fp), &sb) == 0 && + S_ISDIR(sb.st_mode)) { + fprintf(stderr, "%s: '%s' is a directory, cannot continue\n", argv[0], filename); + return 1; + } + } + } + } + + stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0); + + if (unbuffered) { +#if defined(MS_WINDOWS) || defined(__CYGWIN__) + _setmode(fileno(stdin), O_BINARY); + _setmode(fileno(stdout), O_BINARY); +#endif +#ifdef HAVE_SETVBUF + setvbuf(stdin, (char *)NULL, _IONBF, BUFSIZ); + setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ); + setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ); +#else /* !HAVE_SETVBUF */ + setbuf(stdin, (char *)NULL); + setbuf(stdout, (char *)NULL); + setbuf(stderr, (char *)NULL); +#endif /* !HAVE_SETVBUF */ + } + else if (Py_InteractiveFlag) { +#ifdef MS_WINDOWS + /* Doesn't have to have line-buffered -- use unbuffered */ + /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */ + setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ); +#else /* !MS_WINDOWS */ +#ifdef HAVE_SETVBUF + setvbuf(stdin, (char *)NULL, _IOLBF, BUFSIZ); + setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ); +#endif /* HAVE_SETVBUF */ +#endif /* !MS_WINDOWS */ + /* Leave stderr alone - it should be unbuffered anyway. */ + } +#ifdef __VMS + else { + setvbuf (stdout, (char *)NULL, _IOLBF, BUFSIZ); + } +#endif /* __VMS */ + +#ifdef __APPLE__ + /* On MacOS X, when the Python interpreter is embedded in an + application bundle, it gets executed by a bootstrapping script + that does os.execve() with an argv[0] that's different from the + actual Python executable. This is needed to keep the Finder happy, + or rather, to work around Apple's overly strict requirements of + the process name. However, we still need a usable sys.executable, + so the actual executable path is passed in an environment variable. + See Lib/plat-mac/bundlebuiler.py for details about the bootstrap + script. */ + if ((p = Py_GETENV("PYTHONEXECUTABLE")) && *p != '\0') + Py_SetProgramName(p); + else + Py_SetProgramName(argv[0]); +#else + Py_SetProgramName(argv[0]); +#endif + Py_Initialize(); + + if (Py_VerboseFlag || + (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) { + fprintf(stderr, "Python %s on %s\n", + Py_GetVersion(), Py_GetPlatform()); + if (!Py_NoSiteFlag) + fprintf(stderr, "%s\n", COPYRIGHT); + } + + if (command != NULL) { + /* Backup _PyOS_optind and force sys.argv[0] = '-c' */ + _PyOS_optind--; + argv[_PyOS_optind] = "-c"; + } + + if (module != NULL) { + /* Backup _PyOS_optind and force sys.argv[0] = '-c' + so that PySys_SetArgv correctly sets sys.path[0] to ''*/ + _PyOS_optind--; + argv[_PyOS_optind] = "-c"; + } + + PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind); + + if ((inspect || (command == NULL && filename == NULL && module == NULL)) && + isatty(fileno(stdin))) { + PyObject *v; + v = PyImport_ImportModule("readline"); + if (v == NULL) + PyErr_Clear(); + else + Py_DECREF(v); + } + + if (command) { + sts = PyRun_SimpleStringFlags(command, &cf) != 0; + free(command); + } else if (module) { + sts = RunModule(module); + free(module); + } + else { + if (filename == NULL && stdin_is_interactive) { + RunStartupFile(&cf); + } + /* XXX */ + sts = PyRun_AnyFileExFlags( + fp, + filename == NULL ? "<stdin>" : filename, + filename != NULL, &cf) != 0; + } + + /* Check this environment variable at the end, to give programs the + * opportunity to set it from Python. + */ + if (!saw_inspect_flag && + (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') + { + inspect = 1; + } + + if (inspect && stdin_is_interactive && + (filename != NULL || command != NULL || module != NULL)) + /* XXX */ + sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0; + + WaitForThreadShutdown(); + + Py_Finalize(); +#ifdef RISCOS + if (Py_RISCOSWimpFlag) + fprintf(stderr, "\x0cq\x0c"); /* make frontend quit */ +#endif + +#ifdef __INSURE__ + /* Insure++ is a memory analysis tool that aids in discovering + * memory leaks and other memory problems. On Python exit, the + * interned string dictionary is flagged as being in use at exit + * (which it is). Under normal circumstances, this is fine because + * the memory will be automatically reclaimed by the system. Under + * memory debugging, it's a huge source of useless noise, so we + * trade off slower shutdown for less distraction in the memory + * reports. -baw + */ + _Py_ReleaseInternedStrings(); +#endif /* __INSURE__ */ + + return sts; +} + +/* this is gonna seem *real weird*, but if you put some other code between + Py_Main() and Py_GetArgcArgv() you will need to adjust the test in the + while statement in Misc/gdbinit:ppystack */ + +/* Make the *original* argc/argv available to other modules. + This is rare, but it is needed by the secureware extension. */ + +void +Py_GetArgcArgv(int *argc, char ***argv) +{ + *argc = orig_argc; + *argv = orig_argv; +} + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Modules/makesetup b/sys/src/cmd/python/Modules/makesetup new file mode 100755 index 000000000..bc1b1b915 --- /dev/null +++ b/sys/src/cmd/python/Modules/makesetup @@ -0,0 +1,297 @@ +#! /bin/sh + +# Convert templates into Makefile and config.c, based on the module +# definitions found in the file Setup. +# +# Usage: makesetup [-s dir] [-c file] [-m file] [Setup] ... [-n [Setup] ...] +# +# Options: +# -s directory: alternative source directory (default .) +# -l directory: library source directory (default derived from $0) +# -c file: alternative config.c template (default $libdir/config.c.in) +# -c -: don't write config.c +# -m file: alternative Makefile template (default ./Makefile.pre) +# -m -: don't write Makefile +# +# Remaining arguments are one or more Setup files (default ./Setup). +# Setup files after a -n option are used for their variables, modules +# and libraries but not for their .o files. +# +# See Setup.dist for a description of the format of the Setup file. +# +# The following edits are made: +# +# Copying config.c.in to config.c: +# - insert an identifying comment at the start +# - for each <module> mentioned in Setup before *noconfig*: +# + insert 'extern void init<module>(void);' before MARKER 1 +# + insert '{"<module>", initmodule},' before MARKER 2 +# +# Copying Makefile.pre to Makefile: +# - insert an identifying comment at the start +# - replace _MODOBJS_ by the list of objects from Setup (except for +# Setup files after a -n option) +# - replace _MODLIBS_ by the list of libraries from Setup +# - for each object file mentioned in Setup, append a rule +# '<file>.o: <file>.c; <build commands>' to the end of the Makefile +# - for each module mentioned in Setup, append a rule +# which creates a shared library version to the end of the Makefile +# - for each variable definition found in Setup, insert the definition +# before the comment 'Definitions added by makesetup' + +# Loop over command line options +usage=' +usage: makesetup [-s srcdir] [-l libdir] [-c config.c.in] [-m Makefile.pre] + [Setup] ... [-n [Setup] ...]' +srcdir='.' +libdir='' +config='' +makepre='' +noobjects='' +doconfig=yes +while : +do + case $1 in + -s) shift; srcdir=$1; shift;; + -l) shift; libdir=$1; shift;; + -c) shift; config=$1; shift;; + -m) shift; makepre=$1; shift;; + --) shift; break;; + -n) noobjects=yes;; + -*) echo "$usage" 1>&2; exit 2;; + *) break;; + esac +done + +# Set default libdir and config if not set by command line +# (Not all systems have dirname) +case $libdir in +'') case $0 in + */*) libdir=`echo $0 | sed 's,/[^/]*$,,'`;; + *) libdir=.;; + esac;; +esac +case $config in +'') config=$libdir/config.c.in;; +esac +case $makepre in +'') makepre=Makefile.pre;; +esac + +# Newline for sed i and a commands +NL='\ +' + +# Setup to link with extra libraries when makeing shared extensions. +# Currently, only Cygwin needs this baggage. +case `uname -s` in +CYGWIN*) if test $libdir = . + then + ExtraLibDir=. + else + ExtraLibDir='$(LIBPL)' + fi + ExtraLibs="-L$ExtraLibDir -lpython\$(VERSION)";; +esac + +# Main loop +for i in ${*-Setup} +do + case $i in + -n) echo '*noobjects*';; + *) echo '*doconfig*'; cat "$i";; + esac +done | +sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' | +( + rulesf="@rules.$$" + trap 'rm -f $rulesf' 0 1 2 3 + echo " +# Rules appended by makedepend +" >$rulesf + DEFS= + MODS= + SHAREDMODS= + OBJS= + LIBS= + LOCALLIBS= + BASELIBS= + while read line + do + # to handle backslashes for sh's that don't automatically + # continue a read when the last char is a backslash + while echo $line | grep '\\$' > /dev/null + do + read extraline + line=`echo $line| sed s/.$//`$extraline + done + + # Output DEFS in reverse order so first definition overrides + case $line in + *=*) DEFS="$line$NL$DEFS"; continue;; + 'include '*) DEFS="$line$NL$DEFS"; continue;; + '*noobjects*') + case $noobjects in + yes) ;; + *) LOCALLIBS=$LIBS; LIBS=;; + esac + noobjects=yes; + continue;; + '*doconfig*') doconfig=yes; continue;; + '*static*') doconfig=yes; continue;; + '*noconfig*') doconfig=no; continue;; + '*shared*') doconfig=no; continue;; + esac + srcs= + cpps= + libs= + mods= + skip= + for arg in $line + do + case $skip in + libs) libs="$libs $arg"; skip=; continue;; + cpps) cpps="$cpps $arg"; skip=; continue;; + srcs) srcs="$srcs $arg"; skip=; continue;; + esac + case $arg in + -framework) libs="$libs $arg"; skip=libs; + # OSX/OSXS/Darwin framework link cmd + ;; + -[IDUCfF]*) cpps="$cpps $arg";; + -Xcompiler) skip=cpps;; + -Xlinker) libs="$libs $arg"; skip=libs;; + -rpath) libs="$libs $arg"; skip=libs;; + --rpath) libs="$libs $arg"; skip=libs;; + -[A-Zl]*) libs="$libs $arg";; + *.a) libs="$libs $arg";; + *.so) libs="$libs $arg";; + *.sl) libs="$libs $arg";; + /*.o) libs="$libs $arg";; + *.def) libs="$libs $arg";; + *.o) srcs="$srcs `basename $arg .o`.c";; + *.[cC]) srcs="$srcs $arg";; + *.m) srcs="$srcs $arg";; # Objective-C src + *.cc) srcs="$srcs $arg";; + *.c++) srcs="$srcs $arg";; + *.cxx) srcs="$srcs $arg";; + *.cpp) srcs="$srcs $arg";; + \$*) libs="$libs $arg" + cpps="$cpps $arg";; + *.*) echo 1>&2 "bad word $arg in $line" + exit 1;; + -u) skip=libs; libs="$libs -u";; + [a-zA-Z_]*) mods="$mods $arg";; + *) echo 1>&2 "bad word $arg in $line" + exit 1;; + esac + done + case $doconfig in + yes) + LIBS="$LIBS $libs" + MODS="$MODS $mods" + ;; + esac + case $noobjects in + yes) continue;; + esac + objs='' + for src in $srcs + do + case $src in + *.c) obj=`basename $src .c`.o; cc='$(CC)';; + *.cc) obj=`basename $src .cc`.o; cc='$(CXX)';; + *.c++) obj=`basename $src .c++`.o; cc='$(CXX)';; + *.C) obj=`basename $src .C`.o; cc='$(CXX)';; + *.cxx) obj=`basename $src .cxx`.o; cc='$(CXX)';; + *.cpp) obj=`basename $src .cpp`.o; cc='$(CXX)';; + *.m) obj=`basename $src .m`.o; cc='$(CC)';; # Obj-C + *) continue;; + esac + obj="$srcdir/$obj" + objs="$objs $obj" + case $src in + glmodule.c) ;; + /*) ;; + \$*) ;; + *) src='$(srcdir)/'"$srcdir/$src";; + esac + case $doconfig in + no) cc="$cc \$(CCSHARED) \$(CFLAGS) \$(CPPFLAGS)";; + *) + cc="$cc \$(PY_CFLAGS)";; + esac + rule="$obj: $src; $cc $cpps -c $src -o $obj" + echo "$rule" >>$rulesf + done + case $doconfig in + yes) OBJS="$OBJS $objs";; + esac + for mod in $mods + do + case $objs in + *$mod.o*) base=$mod;; + *) base=${mod}module;; + esac + file="$srcdir/$base\$(SO)" + case $doconfig in + no) SHAREDMODS="$SHAREDMODS $file";; + esac + rule="$file: $objs" + rule="$rule; \$(LDSHARED) $objs $libs $ExtraLibs -o $file" + echo "$rule" >>$rulesf + done + done + + case $SHAREDMODS in + '') ;; + *) DEFS="SHAREDMODS=$SHAREDMODS$NL$DEFS";; + esac + + case $noobjects in + yes) BASELIBS=$LIBS;; + *) LOCALLIBS=$LIBS;; + esac + LIBS='$(LOCALMODLIBS) $(BASEMODLIBS)' + DEFS="BASEMODLIBS=$BASELIBS$NL$DEFS" + DEFS="LOCALMODLIBS=$LOCALLIBS$NL$DEFS" + + EXTDECLS= + INITBITS= + for mod in $MODS + do + EXTDECLS="${EXTDECLS}extern void init$mod(void);$NL" + INITBITS="${INITBITS} {\"$mod\", init$mod},$NL" + done + + + case $config in + -) ;; + *) sed -e " + 1i$NL/* Generated automatically from $config by makesetup. */ + /MARKER 1/i$NL$EXTDECLS + + /MARKER 2/i$NL$INITBITS + + " $config >config.c + ;; + esac + + case $makepre in + -) ;; + *) sedf="@sed.in.$$" + trap 'rm -f $sedf' 0 1 2 3 + echo "1i\\" >$sedf + str="# Generated automatically from $makepre by makesetup." + echo "$str" >>$sedf + echo "s%_MODOBJS_%$OBJS%" >>$sedf + echo "s%_MODLIBS_%$LIBS%" >>$sedf + echo "/Definitions added by makesetup/a$NL$NL$DEFS" >>$sedf + sed -f $sedf $makepre >Makefile + cat $rulesf >>Makefile + rm -f $sedf + ;; + esac + + rm -f $rulesf +) diff --git a/sys/src/cmd/python/Modules/makexp_aix b/sys/src/cmd/python/Modules/makexp_aix new file mode 100755 index 000000000..cb349c287 --- /dev/null +++ b/sys/src/cmd/python/Modules/makexp_aix @@ -0,0 +1,81 @@ +#!/bin/sh +# +# =========================================================================== +# FILE: makexp_aix +# TYPE: standalone executable +# SYSTEM: AIX 3.2.5 and AIX 4 +# +# DESCRIPTION: This script creates an export list of ALL global symbols +# from a list of object or archive files. +# +# USAGE: makexp_aix <OutputFile> "<FirstLine>" <InputFile> ... +# +# where: +# <OutputFile> is the target export list filename. +# <FirstLine> is the path/file string to be appended +# after the "#!" symbols in the first line of the +# export file. Passing "" means deferred resolution. +# <InputFile> is an object (.o) or an archive file (.a). +# +# HISTORY: +# 3-Apr-1998 -- remove C++ entries of the form Class::method +# Vladimir Marangozov +# +# 1-Jul-1996 -- added header information +# Vladimir Marangozov +# +# 28-Jun-1996 -- initial code +# Vladimir Marangozov (Vladimir.Marangozov@imag.fr) +# ========================================================================== + +# Variables +expFileName=$1 +toAppendStr=$2 +shift; shift; +inputFiles=$* +automsg="Generated automatically by makexp_aix" +notemsg="NOTE: lists _all_ global symbols defined in the above file(s)." +curwdir=`pwd` + +# Create the export file and setup the header info +echo "#!"$toAppendStr > $expFileName +echo "*" >> $expFileName +echo "* $automsg (`date -u`)" >> $expFileName +echo "*" >> $expFileName +echo "* Base Directory: $curwdir" >> $expFileName +echo "* Input File(s) : $inputFiles" >> $expFileName +echo "*" >> $expFileName +echo "* $notemsg" >> $expFileName +echo "*" >> $expFileName + +# Extract the symbol list using 'nm' which produces quite +# different output under AIX 4 than under AIX 3.2.5. +# The following handles both versions by using a common flagset. +# Here are some hidden tricks: +# 1. Use /usr/ccs/bin/nm. Relevant to AIX 3.2.5 which has +# another version under /usr/ucb/bin/nm. +# 2. Use the -B flag to have a standard BSD representation +# of the symbol list on both AIX 3.2.5 and AIX 4. The "-B" +# flag is missing in the AIX 3.2.5 online usage help of 'nm'. +# 3. Use the -x flag to have a hex representation of the symbol +# values. This fills the leading whitespaces on AIX 4, +# thus simplifying the sed statement. +# 4. Eliminate all entries except those with either "B", "D" +# or "T" key letters. We are interested only in the global +# (extern) BSS, DATA and TEXT symbols. With the same statement +# we eliminate object member lines relevant to AIX 4. +# 5. Eliminate entries containing a dot. We can have a dot only +# as a symbol prefix, but such symbols are undefined externs. +# 6. Eliminate everything including the key letter, so that we're +# left with just the symbol name. +# 7. Eliminate all entries containing two colons, like Class::method +# + +# Use -X32_64 if it appears to be implemented in this version of 'nm'. +NM=/usr/ccs/bin/nm +xopt=-X32_64 +$NM -e $xopt $1 >/dev/null 2>&1 || xopt="" + +$NM -Bex $xopt $inputFiles \ +| sed -e '/ [^BDT] /d' -e '/\./d' -e 's/.* [BDT] //' -e '/::/d' \ +| sort | uniq >> $expFileName diff --git a/sys/src/cmd/python/Modules/mathmodule.c b/sys/src/cmd/python/Modules/mathmodule.c new file mode 100644 index 000000000..e7fc6dd70 --- /dev/null +++ b/sys/src/cmd/python/Modules/mathmodule.c @@ -0,0 +1,376 @@ +/* Math module -- standard C math library functions, pi and e */ + +#include "Python.h" +#include "longintrepr.h" /* just for SHIFT */ + +#ifndef _MSC_VER +#ifndef __STDC__ +extern double fmod (double, double); +extern double frexp (double, int *); +extern double ldexp (double, int); +extern double modf (double, double *); +#endif /* __STDC__ */ +#endif /* _MSC_VER */ + +/* Call is_error when errno != 0, and where x is the result libm + * returned. is_error will usually set up an exception and return + * true (1), but may return false (0) without setting up an exception. + */ +static int +is_error(double x) +{ + int result = 1; /* presumption of guilt */ + assert(errno); /* non-zero errno is a precondition for calling */ + if (errno == EDOM) + PyErr_SetString(PyExc_ValueError, "math domain error"); + + else if (errno == ERANGE) { + /* ANSI C generally requires libm functions to set ERANGE + * on overflow, but also generally *allows* them to set + * ERANGE on underflow too. There's no consistency about + * the latter across platforms. + * Alas, C99 never requires that errno be set. + * Here we suppress the underflow errors (libm functions + * should return a zero on underflow, and +- HUGE_VAL on + * overflow, so testing the result for zero suffices to + * distinguish the cases). + */ + if (x) + PyErr_SetString(PyExc_OverflowError, + "math range error"); + else + result = 0; + } + else + /* Unexpected math error */ + PyErr_SetFromErrno(PyExc_ValueError); + return result; +} + +static PyObject * +math_1(PyObject *args, double (*func) (double), char *argsfmt) +{ + double x; + if (! PyArg_ParseTuple(args, argsfmt, &x)) + return NULL; + errno = 0; + PyFPE_START_PROTECT("in math_1", return 0) + x = (*func)(x); + PyFPE_END_PROTECT(x) + Py_SET_ERRNO_ON_MATH_ERROR(x); + if (errno && is_error(x)) + return NULL; + else + return PyFloat_FromDouble(x); +} + +static PyObject * +math_2(PyObject *args, double (*func) (double, double), char *argsfmt) +{ + double x, y; + if (! PyArg_ParseTuple(args, argsfmt, &x, &y)) + return NULL; + errno = 0; + PyFPE_START_PROTECT("in math_2", return 0) + x = (*func)(x, y); + PyFPE_END_PROTECT(x) + Py_SET_ERRNO_ON_MATH_ERROR(x); + if (errno && is_error(x)) + return NULL; + else + return PyFloat_FromDouble(x); +} + +#define FUNC1(funcname, func, docstring) \ + static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ + return math_1(args, func, "d:" #funcname); \ + }\ + PyDoc_STRVAR(math_##funcname##_doc, docstring); + +#define FUNC2(funcname, func, docstring) \ + static PyObject * math_##funcname(PyObject *self, PyObject *args) { \ + return math_2(args, func, "dd:" #funcname); \ + }\ + PyDoc_STRVAR(math_##funcname##_doc, docstring); + +FUNC1(acos, acos, + "acos(x)\n\nReturn the arc cosine (measured in radians) of x.") +FUNC1(asin, asin, + "asin(x)\n\nReturn the arc sine (measured in radians) of x.") +FUNC1(atan, atan, + "atan(x)\n\nReturn the arc tangent (measured in radians) of x.") +FUNC2(atan2, atan2, + "atan2(y, x)\n\nReturn the arc tangent (measured in radians) of y/x.\n" + "Unlike atan(y/x), the signs of both x and y are considered.") +FUNC1(ceil, ceil, + "ceil(x)\n\nReturn the ceiling of x as a float.\n" + "This is the smallest integral value >= x.") +FUNC1(cos, cos, + "cos(x)\n\nReturn the cosine of x (measured in radians).") +FUNC1(cosh, cosh, + "cosh(x)\n\nReturn the hyperbolic cosine of x.") +FUNC1(exp, exp, + "exp(x)\n\nReturn e raised to the power of x.") +FUNC1(fabs, fabs, + "fabs(x)\n\nReturn the absolute value of the float x.") +FUNC1(floor, floor, + "floor(x)\n\nReturn the floor of x as a float.\n" + "This is the largest integral value <= x.") +FUNC2(fmod, fmod, + "fmod(x,y)\n\nReturn fmod(x, y), according to platform C." + " x % y may differ.") +FUNC2(hypot, hypot, + "hypot(x,y)\n\nReturn the Euclidean distance, sqrt(x*x + y*y).") +FUNC2(pow, pow, + "pow(x,y)\n\nReturn x**y (x to the power of y).") +FUNC1(sin, sin, + "sin(x)\n\nReturn the sine of x (measured in radians).") +FUNC1(sinh, sinh, + "sinh(x)\n\nReturn the hyperbolic sine of x.") +FUNC1(sqrt, sqrt, + "sqrt(x)\n\nReturn the square root of x.") +FUNC1(tan, tan, + "tan(x)\n\nReturn the tangent of x (measured in radians).") +FUNC1(tanh, tanh, + "tanh(x)\n\nReturn the hyperbolic tangent of x.") + +static PyObject * +math_frexp(PyObject *self, PyObject *args) +{ + double x; + int i; + if (! PyArg_ParseTuple(args, "d:frexp", &x)) + return NULL; + errno = 0; + x = frexp(x, &i); + Py_SET_ERRNO_ON_MATH_ERROR(x); + if (errno && is_error(x)) + return NULL; + else + return Py_BuildValue("(di)", x, i); +} + +PyDoc_STRVAR(math_frexp_doc, +"frexp(x)\n" +"\n" +"Return the mantissa and exponent of x, as pair (m, e).\n" +"m is a float and e is an int, such that x = m * 2.**e.\n" +"If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0."); + +static PyObject * +math_ldexp(PyObject *self, PyObject *args) +{ + double x; + int exp; + if (! PyArg_ParseTuple(args, "di:ldexp", &x, &exp)) + return NULL; + errno = 0; + PyFPE_START_PROTECT("ldexp", return 0) + x = ldexp(x, exp); + PyFPE_END_PROTECT(x) + Py_SET_ERRNO_ON_MATH_ERROR(x); + if (errno && is_error(x)) + return NULL; + else + return PyFloat_FromDouble(x); +} + +PyDoc_STRVAR(math_ldexp_doc, +"ldexp(x, i) -> x * (2**i)"); + +static PyObject * +math_modf(PyObject *self, PyObject *args) +{ + double x, y; + if (! PyArg_ParseTuple(args, "d:modf", &x)) + return NULL; + errno = 0; + x = modf(x, &y); + Py_SET_ERRNO_ON_MATH_ERROR(x); + if (errno && is_error(x)) + return NULL; + else + return Py_BuildValue("(dd)", x, y); +} + +PyDoc_STRVAR(math_modf_doc, +"modf(x)\n" +"\n" +"Return the fractional and integer parts of x. Both results carry the sign\n" +"of x. The integer part is returned as a real."); + +/* A decent logarithm is easy to compute even for huge longs, but libm can't + do that by itself -- loghelper can. func is log or log10, and name is + "log" or "log10". Note that overflow isn't possible: a long can contain + no more than INT_MAX * SHIFT bits, so has value certainly less than + 2**(2**64 * 2**16) == 2**2**80, and log2 of that is 2**80, which is + small enough to fit in an IEEE single. log and log10 are even smaller. +*/ + +static PyObject* +loghelper(PyObject* args, double (*func)(double), char *format, PyObject *arg) +{ + /* If it is long, do it ourselves. */ + if (PyLong_Check(arg)) { + double x; + int e; + x = _PyLong_AsScaledDouble(arg, &e); + if (x <= 0.0) { + PyErr_SetString(PyExc_ValueError, + "math domain error"); + return NULL; + } + /* Value is ~= x * 2**(e*SHIFT), so the log ~= + log(x) + log(2) * e * SHIFT. + CAUTION: e*SHIFT may overflow using int arithmetic, + so force use of double. */ + x = func(x) + (e * (double)SHIFT) * func(2.0); + return PyFloat_FromDouble(x); + } + + /* Else let libm handle it by itself. */ + return math_1(args, func, format); +} + +static PyObject * +math_log(PyObject *self, PyObject *args) +{ + PyObject *arg; + PyObject *base = NULL; + PyObject *num, *den; + PyObject *ans; + PyObject *newargs; + + if (!PyArg_UnpackTuple(args, "log", 1, 2, &arg, &base)) + return NULL; + if (base == NULL) + return loghelper(args, log, "d:log", arg); + + newargs = PyTuple_Pack(1, arg); + if (newargs == NULL) + return NULL; + num = loghelper(newargs, log, "d:log", arg); + Py_DECREF(newargs); + if (num == NULL) + return NULL; + + newargs = PyTuple_Pack(1, base); + if (newargs == NULL) { + Py_DECREF(num); + return NULL; + } + den = loghelper(newargs, log, "d:log", base); + Py_DECREF(newargs); + if (den == NULL) { + Py_DECREF(num); + return NULL; + } + + ans = PyNumber_Divide(num, den); + Py_DECREF(num); + Py_DECREF(den); + return ans; +} + +PyDoc_STRVAR(math_log_doc, +"log(x[, base]) -> the logarithm of x to the given base.\n\ +If the base not specified, returns the natural logarithm (base e) of x."); + +static PyObject * +math_log10(PyObject *self, PyObject *args) +{ + PyObject *arg; + + if (!PyArg_UnpackTuple(args, "log10", 1, 1, &arg)) + return NULL; + return loghelper(args, log10, "d:log10", arg); +} + +PyDoc_STRVAR(math_log10_doc, +"log10(x) -> the base 10 logarithm of x."); + +static const double degToRad = 3.141592653589793238462643383 / 180.0; + +static PyObject * +math_degrees(PyObject *self, PyObject *args) +{ + double x; + if (! PyArg_ParseTuple(args, "d:degrees", &x)) + return NULL; + return PyFloat_FromDouble(x / degToRad); +} + +PyDoc_STRVAR(math_degrees_doc, +"degrees(x) -> converts angle x from radians to degrees"); + +static PyObject * +math_radians(PyObject *self, PyObject *args) +{ + double x; + if (! PyArg_ParseTuple(args, "d:radians", &x)) + return NULL; + return PyFloat_FromDouble(x * degToRad); +} + +PyDoc_STRVAR(math_radians_doc, +"radians(x) -> converts angle x from degrees to radians"); + +static PyMethodDef math_methods[] = { + {"acos", math_acos, METH_VARARGS, math_acos_doc}, + {"asin", math_asin, METH_VARARGS, math_asin_doc}, + {"atan", math_atan, METH_VARARGS, math_atan_doc}, + {"atan2", math_atan2, METH_VARARGS, math_atan2_doc}, + {"ceil", math_ceil, METH_VARARGS, math_ceil_doc}, + {"cos", math_cos, METH_VARARGS, math_cos_doc}, + {"cosh", math_cosh, METH_VARARGS, math_cosh_doc}, + {"degrees", math_degrees, METH_VARARGS, math_degrees_doc}, + {"exp", math_exp, METH_VARARGS, math_exp_doc}, + {"fabs", math_fabs, METH_VARARGS, math_fabs_doc}, + {"floor", math_floor, METH_VARARGS, math_floor_doc}, + {"fmod", math_fmod, METH_VARARGS, math_fmod_doc}, + {"frexp", math_frexp, METH_VARARGS, math_frexp_doc}, + {"hypot", math_hypot, METH_VARARGS, math_hypot_doc}, + {"ldexp", math_ldexp, METH_VARARGS, math_ldexp_doc}, + {"log", math_log, METH_VARARGS, math_log_doc}, + {"log10", math_log10, METH_VARARGS, math_log10_doc}, + {"modf", math_modf, METH_VARARGS, math_modf_doc}, + {"pow", math_pow, METH_VARARGS, math_pow_doc}, + {"radians", math_radians, METH_VARARGS, math_radians_doc}, + {"sin", math_sin, METH_VARARGS, math_sin_doc}, + {"sinh", math_sinh, METH_VARARGS, math_sinh_doc}, + {"sqrt", math_sqrt, METH_VARARGS, math_sqrt_doc}, + {"tan", math_tan, METH_VARARGS, math_tan_doc}, + {"tanh", math_tanh, METH_VARARGS, math_tanh_doc}, + {NULL, NULL} /* sentinel */ +}; + + +PyDoc_STRVAR(module_doc, +"This module is always available. It provides access to the\n" +"mathematical functions defined by the C standard."); + +PyMODINIT_FUNC +initmath(void) +{ + PyObject *m, *d, *v; + + m = Py_InitModule3("math", math_methods, module_doc); + if (m == NULL) + goto finally; + d = PyModule_GetDict(m); + + if (!(v = PyFloat_FromDouble(atan(1.0) * 4.0))) + goto finally; + if (PyDict_SetItemString(d, "pi", v) < 0) + goto finally; + Py_DECREF(v); + + if (!(v = PyFloat_FromDouble(exp(1.0)))) + goto finally; + if (PyDict_SetItemString(d, "e", v) < 0) + goto finally; + Py_DECREF(v); + + finally: + return; +} diff --git a/sys/src/cmd/python/Modules/md5.c b/sys/src/cmd/python/Modules/md5.c new file mode 100644 index 000000000..c35d96c5e --- /dev/null +++ b/sys/src/cmd/python/Modules/md5.c @@ -0,0 +1,381 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include <string.h> + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include <stdio.h> in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include <string.h> + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/sys/src/cmd/python/Modules/md5.h b/sys/src/cmd/python/Modules/md5.h new file mode 100644 index 000000000..1718401f3 --- /dev/null +++ b/sys/src/cmd/python/Modules/md5.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.h 43594 2006-04-03 16:27:50Z matthias.klose $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + <ghost@aladdin.com>. Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke <purschke@bnl.gov>. + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/sys/src/cmd/python/Modules/md5module.c b/sys/src/cmd/python/Modules/md5module.c new file mode 100644 index 000000000..5e4f11632 --- /dev/null +++ b/sys/src/cmd/python/Modules/md5module.c @@ -0,0 +1,312 @@ + +/* MD5 module */ + +/* This module provides an interface to the RSA Data Security, + Inc. MD5 Message-Digest Algorithm, described in RFC 1321. + It requires the files md5c.c and md5.h (which are slightly changed + from the versions in the RFC to avoid the "global.h" file.) */ + + +/* MD5 objects */ + +#include "Python.h" +#include "structmember.h" +#include "md5.h" + +typedef struct { + PyObject_HEAD + md5_state_t md5; /* the context holder */ +} md5object; + +static PyTypeObject MD5type; + +#define is_md5object(v) ((v)->ob_type == &MD5type) + +static md5object * +newmd5object(void) +{ + md5object *md5p; + + md5p = PyObject_New(md5object, &MD5type); + if (md5p == NULL) + return NULL; + + md5_init(&md5p->md5); /* actual initialisation */ + return md5p; +} + + +/* MD5 methods */ + +static void +md5_dealloc(md5object *md5p) +{ + PyObject_Del(md5p); +} + + +/* MD5 methods-as-attributes */ + +static PyObject * +md5_update(md5object *self, PyObject *args) +{ + unsigned char *cp; + int len; + + if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + return NULL; + + md5_append(&self->md5, cp, len); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(update_doc, +"update (arg)\n\ +\n\ +Update the md5 object with the string arg. Repeated calls are\n\ +equivalent to a single call with the concatenation of all the\n\ +arguments."); + + +static PyObject * +md5_digest(md5object *self) +{ + md5_state_t mdContext; + unsigned char aDigest[16]; + + /* make a temporary copy, and perform the final */ + mdContext = self->md5; + md5_finish(&mdContext, aDigest); + + return PyString_FromStringAndSize((char *)aDigest, 16); +} + +PyDoc_STRVAR(digest_doc, +"digest() -> string\n\ +\n\ +Return the digest of the strings passed to the update() method so\n\ +far. This is a 16-byte string which may contain non-ASCII characters,\n\ +including null bytes."); + + +static PyObject * +md5_hexdigest(md5object *self) +{ + md5_state_t mdContext; + unsigned char digest[16]; + unsigned char hexdigest[32]; + int i, j; + + /* make a temporary copy, and perform the final */ + mdContext = self->md5; + md5_finish(&mdContext, digest); + + /* Make hex version of the digest */ + for(i=j=0; i<16; i++) { + char c; + c = (digest[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + hexdigest[j++] = c; + c = (digest[i] & 0xf); + c = (c>9) ? c+'a'-10 : c + '0'; + hexdigest[j++] = c; + } + return PyString_FromStringAndSize((char*)hexdigest, 32); +} + + +PyDoc_STRVAR(hexdigest_doc, +"hexdigest() -> string\n\ +\n\ +Like digest(), but returns the digest as a string of hexadecimal digits."); + + +static PyObject * +md5_copy(md5object *self) +{ + md5object *md5p; + + if ((md5p = newmd5object()) == NULL) + return NULL; + + md5p->md5 = self->md5; + + return (PyObject *)md5p; +} + +PyDoc_STRVAR(copy_doc, +"copy() -> md5 object\n\ +\n\ +Return a copy (``clone'') of the md5 object."); + + +static PyMethodDef md5_methods[] = { + {"update", (PyCFunction)md5_update, METH_VARARGS, update_doc}, + {"digest", (PyCFunction)md5_digest, METH_NOARGS, digest_doc}, + {"hexdigest", (PyCFunction)md5_hexdigest, METH_NOARGS, hexdigest_doc}, + {"copy", (PyCFunction)md5_copy, METH_NOARGS, copy_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +md5_get_block_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(64); +} + +static PyObject * +md5_get_digest_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(16); +} + +static PyObject * +md5_get_name(PyObject *self, void *closure) +{ + return PyString_FromStringAndSize("MD5", 3); +} + +static PyGetSetDef md5_getseters[] = { + {"digest_size", + (getter)md5_get_digest_size, NULL, + NULL, + NULL}, + {"block_size", + (getter)md5_get_block_size, NULL, + NULL, + NULL}, + {"name", + (getter)md5_get_name, NULL, + NULL, + NULL}, + /* the old md5 and sha modules support 'digest_size' as in PEP 247. + * the old sha module also supported 'digestsize'. ugh. */ + {"digestsize", + (getter)md5_get_digest_size, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +}; + + +PyDoc_STRVAR(module_doc, +"This module implements the interface to RSA's MD5 message digest\n\ +algorithm (see also Internet RFC 1321). Its use is quite\n\ +straightforward: use the new() to create an md5 object. You can now\n\ +feed this object with arbitrary strings using the update() method, and\n\ +at any point you can ask it for the digest (a strong kind of 128-bit\n\ +checksum, a.k.a. ``fingerprint'') of the concatenation of the strings\n\ +fed to it so far using the digest() method.\n\ +\n\ +Functions:\n\ +\n\ +new([arg]) -- return a new md5 object, initialized with arg if provided\n\ +md5([arg]) -- DEPRECATED, same as new, but for compatibility\n\ +\n\ +Special Objects:\n\ +\n\ +MD5Type -- type object for md5 objects"); + +PyDoc_STRVAR(md5type_doc, +"An md5 represents the object used to calculate the MD5 checksum of a\n\ +string of information.\n\ +\n\ +Methods:\n\ +\n\ +update() -- updates the current digest with an additional string\n\ +digest() -- return the current digest value\n\ +hexdigest() -- return the current digest as a string of hexadecimal digits\n\ +copy() -- return a copy of the current md5 object"); + +static PyTypeObject MD5type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_md5.md5", /*tp_name*/ + sizeof(md5object), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)md5_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + md5type_doc, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + md5_methods, /*tp_methods*/ + 0, /*tp_members*/ + md5_getseters, /*tp_getset*/ +}; + + +/* MD5 functions */ + +static PyObject * +MD5_new(PyObject *self, PyObject *args) +{ + md5object *md5p; + unsigned char *cp = NULL; + int len = 0; + + if (!PyArg_ParseTuple(args, "|s#:new", &cp, &len)) + return NULL; + + if ((md5p = newmd5object()) == NULL) + return NULL; + + if (cp) + md5_append(&md5p->md5, cp, len); + + return (PyObject *)md5p; +} + +PyDoc_STRVAR(new_doc, +"new([arg]) -> md5 object\n\ +\n\ +Return a new md5 object. If arg is present, the method call update(arg)\n\ +is made."); + + +/* List of functions exported by this module */ + +static PyMethodDef md5_functions[] = { + {"new", (PyCFunction)MD5_new, METH_VARARGS, new_doc}, + {NULL, NULL} /* Sentinel */ +}; + + +/* Initialize this module. */ + +PyMODINIT_FUNC +init_md5(void) +{ + PyObject *m, *d; + + MD5type.ob_type = &PyType_Type; + if (PyType_Ready(&MD5type) < 0) + return; + m = Py_InitModule3("_md5", md5_functions, module_doc); + if (m == NULL) + return; + d = PyModule_GetDict(m); + PyDict_SetItemString(d, "MD5Type", (PyObject *)&MD5type); + PyModule_AddIntConstant(m, "digest_size", 16); + /* No need to check the error here, the caller will do that */ +} diff --git a/sys/src/cmd/python/Modules/mkfile b/sys/src/cmd/python/Modules/mkfile new file mode 100644 index 000000000..ff1bd7198 --- /dev/null +++ b/sys/src/cmd/python/Modules/mkfile @@ -0,0 +1,135 @@ +APE=/sys/src/ape +<$APE/config + +LIB=/$objtype/lib/ape/libpython.a + +OFILES=\ + _bisectmodule.$O\ +# _bsddb.$O\ + _codecsmodule.$O\ + _csv.$O\ +# _curses_panel.$O\ +# _cursesmodule.$O\ + _elementtree.$O\ + _functoolsmodule.$O\ + _hashopenssl.$O\ + _heapqmodule.$O\ +# _hotshot.$O\ + _localemodule.$O\ + _lsprof.$O\ + _randommodule.$O\ + _sre.$O\ + _ssl.$O\ + _struct.$O\ + _testcapimodule.$O\ +# _tkinter.$O\ + _typesmodule.$O\ + _weakref.$O\ +# almodule.$O\ + arraymodule.$O\ + audioop.$O\ + binascii.$O\ +# bsddbmodule.$O\ + bz2module.$O\ + cPickle.$O\ + cStringIO.$O\ +# cdmodule.$O\ + cgensupport.$O\ +# clmodule.$O\ + cmathmodule.$O\ + collectionsmodule.$O\ +# cryptmodule.$O\ + datetimemodule.$O\ +# dbmmodule.$O\ +# dlmodule.$O\ + errnomodule.$O\ + fcntlmodule.$O\ +# flmodule.$O\ +# fmmodule.$O\ + fpectlmodule.$O\ + fpetestmodule.$O\ + gcmodule.$O\ +# gdbmmodule.$O\ + getbuildinfo.$O\ +# getpath.$O\ +# glmodule.$O\ + grpmodule.$O\ + imageop.$O\ +# imgfile.$O\ + itertoolsmodule.$O\ +# linuxaudiodev.$O\ + main.$O\ + mathmodule.$O\ + md5.$O\ + md5module.$O\ +# mmapmodule.$O\ +# nismodule.$O\ + operator.$O\ +# ossaudiodev.$O\ + parsermodule.$O\ + posixmodule.$O\ + puremodule.$O\ + pwdmodule.$O\ + pyexpat.$O\ +# readline.$O\ +# resource.$O\ + rgbimgmodule.$O\ + rotatingtree.$O\ + selectmodule.$O\ +# sgimodule.$O\ + sha256module.$O\ +# sha512module.$O\ + shamodule.$O\ + signalmodule.$O\ + socketmodule.$O\ +# spwdmodule.$O\ + stropmodule.$O\ +# sunaudiodev.$O\ +# svmodule.$O\ + symtablemodule.$O\ +# syslogmodule.$O\ +# termios.$O\ + threadmodule.$O\ + timemodule.$O\ + timingmodule.$O\ + unicodedata.$O\ + xxmodule.$O\ + xxsubtype.$O\ + yuvconvert.$O\ + zipimport.$O\ + zlibmodule.$O\ +# expat \ + xmlparse.$O\ + xmlrole.$O\ + xmltok.$O\ +# cjkcodecs \ + _codecs_cn.$O\ + _codecs_hk.$O\ + _codecs_iso2022.$O\ + _codecs_jp.$O\ + _codecs_kr.$O\ + _codecs_tw.$O\ + multibytecodec.$O\ + + +</sys/src/cmd/mksyslib + +CFLAGS=-c -I. -I.. -I../Include -DT$objtype -DNDEBUG + +%.$O: expat/%.c + $CC $CFLAGS -DHAVE_EXPAT_CONFIG_H'=1' -DUSE_PYEXPAT_CAPI expat/$stem.c + +%.$O: cjkcodecs/%.c + $CC $CFLAGS cjkcodecs/$stem.c + +_elementtree.$O: _elementtree.c + $CC $CFLAGS -Iexpat _elementtree.c + +pyexpat.$O: pyexpat.c + $CC $CFLAGS -Iexpat pyexpat.c + +_hashopenssl.$O: _hashopenssl.c + $CC $CFLAGS -DPLAN9 _hashopenssl.c + +_ssl.$O: _ssl.c + $CC $CFLAGS -DPLAN9 _ssl.c diff --git a/sys/src/cmd/python/Modules/mmapmodule.c b/sys/src/cmd/python/Modules/mmapmodule.c new file mode 100644 index 000000000..9716e303d --- /dev/null +++ b/sys/src/cmd/python/Modules/mmapmodule.c @@ -0,0 +1,1186 @@ +/* + / Author: Sam Rushing <rushing@nightmare.com> + / Hacked for Unix by AMK + / $Id: mmapmodule.c 51474 2006-08-22 13:57:07Z neal.norwitz $ + + / mmapmodule.cpp -- map a view of a file into memory + / + / todo: need permission flags, perhaps a 'chsize' analog + / not all functions check range yet!!! + / + / + / This version of mmapmodule.c has been changed significantly + / from the original mmapfile.c on which it was based. + / The original version of mmapfile is maintained by Sam at + / ftp://squirl.nightmare.com/pub/python/python-ext. +*/ + +#define PY_SSIZE_T_CLEAN +#include <Python.h> + +#ifndef MS_WINDOWS +#define UNIX +#endif + +#ifdef MS_WINDOWS +#include <windows.h> +static int +my_getpagesize(void) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +} +#endif + +#ifdef UNIX +#include <sys/mman.h> +#include <sys/stat.h> + +#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) +static int +my_getpagesize(void) +{ + return sysconf(_SC_PAGESIZE); +} +#else +#define my_getpagesize getpagesize +#endif + +#endif /* UNIX */ + +#include <string.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +/* Prefer MAP_ANONYMOUS since MAP_ANON is deprecated according to man page. */ +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +# define MAP_ANONYMOUS MAP_ANON +#endif + +static PyObject *mmap_module_error; + +typedef enum +{ + ACCESS_DEFAULT, + ACCESS_READ, + ACCESS_WRITE, + ACCESS_COPY +} access_mode; + +typedef struct { + PyObject_HEAD + char * data; + size_t size; + size_t pos; + +#ifdef MS_WINDOWS + HANDLE map_handle; + HANDLE file_handle; + char * tagname; +#endif + +#ifdef UNIX + int fd; +#endif + + access_mode access; +} mmap_object; + + +static void +mmap_object_dealloc(mmap_object *m_obj) +{ +#ifdef MS_WINDOWS + if (m_obj->data != NULL) + UnmapViewOfFile (m_obj->data); + if (m_obj->map_handle != INVALID_HANDLE_VALUE) + CloseHandle (m_obj->map_handle); + if (m_obj->file_handle != INVALID_HANDLE_VALUE) + CloseHandle (m_obj->file_handle); + if (m_obj->tagname) + PyMem_Free(m_obj->tagname); +#endif /* MS_WINDOWS */ + +#ifdef UNIX + if (m_obj->fd >= 0) + (void) close(m_obj->fd); + if (m_obj->data!=NULL) { + msync(m_obj->data, m_obj->size, MS_SYNC); + munmap(m_obj->data, m_obj->size); + } +#endif /* UNIX */ + + PyObject_Del(m_obj); +} + +static PyObject * +mmap_close_method(mmap_object *self, PyObject *unused) +{ +#ifdef MS_WINDOWS + /* For each resource we maintain, we need to check + the value is valid, and if so, free the resource + and set the member value to an invalid value so + the dealloc does not attempt to resource clearing + again. + TODO - should we check for errors in the close operations??? + */ + if (self->data != NULL) { + UnmapViewOfFile(self->data); + self->data = NULL; + } + if (self->map_handle != INVALID_HANDLE_VALUE) { + CloseHandle(self->map_handle); + self->map_handle = INVALID_HANDLE_VALUE; + } + if (self->file_handle != INVALID_HANDLE_VALUE) { + CloseHandle(self->file_handle); + self->file_handle = INVALID_HANDLE_VALUE; + } +#endif /* MS_WINDOWS */ + +#ifdef UNIX + (void) close(self->fd); + self->fd = -1; + if (self->data != NULL) { + munmap(self->data, self->size); + self->data = NULL; + } +#endif + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef MS_WINDOWS +#define CHECK_VALID(err) \ +do { \ + if (self->map_handle == INVALID_HANDLE_VALUE) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + return err; \ + } \ +} while (0) +#endif /* MS_WINDOWS */ + +#ifdef UNIX +#define CHECK_VALID(err) \ +do { \ + if (self->data == NULL) { \ + PyErr_SetString(PyExc_ValueError, "mmap closed or invalid"); \ + return err; \ + } \ +} while (0) +#endif /* UNIX */ + +static PyObject * +mmap_read_byte_method(mmap_object *self, + PyObject *unused) +{ + CHECK_VALID(NULL); + if (self->pos < self->size) { + char value = self->data[self->pos]; + self->pos += 1; + return Py_BuildValue("c", value); + } else { + PyErr_SetString(PyExc_ValueError, "read byte out of range"); + return NULL; + } +} + +static PyObject * +mmap_read_line_method(mmap_object *self, + PyObject *unused) +{ + char *start = self->data+self->pos; + char *eof = self->data+self->size; + char *eol; + PyObject *result; + + CHECK_VALID(NULL); + + eol = memchr(start, '\n', self->size - self->pos); + if (!eol) + eol = eof; + else + ++eol; /* we're interested in the position after the + newline. */ + result = PyString_FromStringAndSize(start, (eol - start)); + self->pos += (eol - start); + return result; +} + +static PyObject * +mmap_read_method(mmap_object *self, + PyObject *args) +{ + Py_ssize_t num_bytes; + PyObject *result; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "n:read", &num_bytes)) + return(NULL); + + /* silently 'adjust' out-of-range requests */ + if ((self->pos + num_bytes) > self->size) { + num_bytes -= (self->pos+num_bytes) - self->size; + } + result = Py_BuildValue("s#", self->data+self->pos, num_bytes); + self->pos += num_bytes; + return result; +} + +static PyObject * +mmap_find_method(mmap_object *self, + PyObject *args) +{ + Py_ssize_t start = self->pos; + char *needle; + Py_ssize_t len; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "s#|n:find", &needle, &len, &start)) { + return NULL; + } else { + char *p; + char *e = self->data + self->size; + + if (start < 0) + start += self->size; + if (start < 0) + start = 0; + else if ((size_t)start > self->size) + start = self->size; + + for (p = self->data + start; p + len <= e; ++p) { + Py_ssize_t i; + for (i = 0; i < len && needle[i] == p[i]; ++i) + /* nothing */; + if (i == len) { + return PyInt_FromSsize_t(p - self->data); + } + } + return PyInt_FromLong(-1); + } +} + +static int +is_writeable(mmap_object *self) +{ + if (self->access != ACCESS_READ) + return 1; + PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map."); + return 0; +} + +static int +is_resizeable(mmap_object *self) +{ + if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT)) + return 1; + PyErr_Format(PyExc_TypeError, + "mmap can't resize a readonly or copy-on-write memory map."); + return 0; +} + + +static PyObject * +mmap_write_method(mmap_object *self, + PyObject *args) +{ + Py_ssize_t length; + char *data; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "s#:write", &data, &length)) + return(NULL); + + if (!is_writeable(self)) + return NULL; + + if ((self->pos + length) > self->size) { + PyErr_SetString(PyExc_ValueError, "data out of range"); + return NULL; + } + memcpy(self->data+self->pos, data, length); + self->pos = self->pos+length; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +mmap_write_byte_method(mmap_object *self, + PyObject *args) +{ + char value; + + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "c:write_byte", &value)) + return(NULL); + + if (!is_writeable(self)) + return NULL; + *(self->data+self->pos) = value; + self->pos += 1; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +mmap_size_method(mmap_object *self, + PyObject *unused) +{ + CHECK_VALID(NULL); + +#ifdef MS_WINDOWS + if (self->file_handle != INVALID_HANDLE_VALUE) { + DWORD low,high; + PY_LONG_LONG size; + low = GetFileSize(self->file_handle, &high); + if (low == INVALID_FILE_SIZE) { + /* It might be that the function appears to have failed, + when indeed its size equals INVALID_FILE_SIZE */ + DWORD error = GetLastError(); + if (error != NO_ERROR) + return PyErr_SetFromWindowsErr(error); + } + if (!high && low < LONG_MAX) + return PyInt_FromLong((long)low); + size = (((PY_LONG_LONG)high)<<32) + low; + return PyLong_FromLongLong(size); + } else { + return PyInt_FromSsize_t(self->size); + } +#endif /* MS_WINDOWS */ + +#ifdef UNIX + { + struct stat buf; + if (-1 == fstat(self->fd, &buf)) { + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + return PyInt_FromSsize_t(buf.st_size); + } +#endif /* UNIX */ +} + +/* This assumes that you want the entire file mapped, + / and when recreating the map will make the new file + / have the new size + / + / Is this really necessary? This could easily be done + / from python by just closing and re-opening with the + / new size? + */ + +static PyObject * +mmap_resize_method(mmap_object *self, + PyObject *args) +{ + Py_ssize_t new_size; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "n:resize", &new_size) || + !is_resizeable(self)) { + return NULL; +#ifdef MS_WINDOWS + } else { + DWORD dwErrCode = 0; + DWORD newSizeLow, newSizeHigh; + /* First, unmap the file view */ + UnmapViewOfFile(self->data); + /* Close the mapping object */ + CloseHandle(self->map_handle); + /* Move to the desired EOF position */ +#if SIZEOF_SIZE_T > 4 + newSizeHigh = (DWORD)(new_size >> 32); + newSizeLow = (DWORD)(new_size & 0xFFFFFFFF); +#else + newSizeHigh = 0; + newSizeLow = (DWORD)new_size; +#endif + SetFilePointer(self->file_handle, + newSizeLow, &newSizeHigh, FILE_BEGIN); + /* Change the size of the file */ + SetEndOfFile(self->file_handle); + /* Create another mapping object and remap the file view */ + self->map_handle = CreateFileMapping( + self->file_handle, + NULL, + PAGE_READWRITE, + newSizeHigh, + newSizeLow, + self->tagname); + if (self->map_handle != NULL) { + self->data = (char *) MapViewOfFile(self->map_handle, + FILE_MAP_WRITE, + 0, + 0, + 0); + if (self->data != NULL) { + self->size = new_size; + Py_INCREF(Py_None); + return Py_None; + } else { + dwErrCode = GetLastError(); + } + } else { + dwErrCode = GetLastError(); + } + PyErr_SetFromWindowsErr(dwErrCode); + return NULL; +#endif /* MS_WINDOWS */ + +#ifdef UNIX +#ifndef HAVE_MREMAP + } else { + PyErr_SetString(PyExc_SystemError, + "mmap: resizing not available--no mremap()"); + return NULL; +#else + } else { + void *newmap; + + if (ftruncate(self->fd, new_size) == -1) { + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + +#ifdef MREMAP_MAYMOVE + newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE); +#else + newmap = mremap(self->data, self->size, new_size, 0); +#endif + if (newmap == (void *)-1) + { + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + self->data = newmap; + self->size = new_size; + Py_INCREF(Py_None); + return Py_None; +#endif /* HAVE_MREMAP */ +#endif /* UNIX */ + } +} + +static PyObject * +mmap_tell_method(mmap_object *self, PyObject *unused) +{ + CHECK_VALID(NULL); + return PyInt_FromSize_t(self->pos); +} + +static PyObject * +mmap_flush_method(mmap_object *self, PyObject *args) +{ + Py_ssize_t offset = 0; + Py_ssize_t size = self->size; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) + return NULL; + if ((size_t)(offset + size) > self->size) { + PyErr_SetString(PyExc_ValueError, "flush values out of range"); + return NULL; + } else { +#ifdef MS_WINDOWS + return PyInt_FromLong((long) + FlushViewOfFile(self->data+offset, size)); +#endif /* MS_WINDOWS */ +#ifdef UNIX + /* XXX semantics of return value? */ + /* XXX flags for msync? */ + if (-1 == msync(self->data + offset, size, + MS_SYNC)) + { + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + return PyInt_FromLong(0); +#endif /* UNIX */ + } +} + +static PyObject * +mmap_seek_method(mmap_object *self, PyObject *args) +{ + Py_ssize_t dist; + int how=0; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) + return NULL; + else { + size_t where; + switch (how) { + case 0: /* relative to start */ + if (dist < 0) + goto onoutofrange; + where = dist; + break; + case 1: /* relative to current position */ + if ((Py_ssize_t)self->pos + dist < 0) + goto onoutofrange; + where = self->pos + dist; + break; + case 2: /* relative to end */ + if ((Py_ssize_t)self->size + dist < 0) + goto onoutofrange; + where = self->size + dist; + break; + default: + PyErr_SetString(PyExc_ValueError, "unknown seek type"); + return NULL; + } + if (where > self->size) + goto onoutofrange; + self->pos = where; + Py_INCREF(Py_None); + return Py_None; + } + + onoutofrange: + PyErr_SetString(PyExc_ValueError, "seek out of range"); + return NULL; +} + +static PyObject * +mmap_move_method(mmap_object *self, PyObject *args) +{ + unsigned long dest, src, count; + CHECK_VALID(NULL); + if (!PyArg_ParseTuple(args, "kkk:move", &dest, &src, &count) || + !is_writeable(self)) { + return NULL; + } else { + /* bounds check the values */ + if (/* end of source after end of data?? */ + ((src+count) > self->size) + /* dest will fit? */ + || (dest+count > self->size)) { + PyErr_SetString(PyExc_ValueError, + "source or destination out of range"); + return NULL; + } else { + memmove(self->data+dest, self->data+src, count); + Py_INCREF(Py_None); + return Py_None; + } + } +} + +static struct PyMethodDef mmap_object_methods[] = { + {"close", (PyCFunction) mmap_close_method, METH_NOARGS}, + {"find", (PyCFunction) mmap_find_method, METH_VARARGS}, + {"flush", (PyCFunction) mmap_flush_method, METH_VARARGS}, + {"move", (PyCFunction) mmap_move_method, METH_VARARGS}, + {"read", (PyCFunction) mmap_read_method, METH_VARARGS}, + {"read_byte", (PyCFunction) mmap_read_byte_method, METH_NOARGS}, + {"readline", (PyCFunction) mmap_read_line_method, METH_NOARGS}, + {"resize", (PyCFunction) mmap_resize_method, METH_VARARGS}, + {"seek", (PyCFunction) mmap_seek_method, METH_VARARGS}, + {"size", (PyCFunction) mmap_size_method, METH_NOARGS}, + {"tell", (PyCFunction) mmap_tell_method, METH_NOARGS}, + {"write", (PyCFunction) mmap_write_method, METH_VARARGS}, + {"write_byte", (PyCFunction) mmap_write_byte_method, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +/* Functions for treating an mmap'ed file as a buffer */ + +static Py_ssize_t +mmap_buffer_getreadbuf(mmap_object *self, Py_ssize_t index, const void **ptr) +{ + CHECK_VALID(-1); + if (index != 0) { + PyErr_SetString(PyExc_SystemError, + "Accessing non-existent mmap segment"); + return -1; + } + *ptr = self->data; + return self->size; +} + +static Py_ssize_t +mmap_buffer_getwritebuf(mmap_object *self, Py_ssize_t index, const void **ptr) +{ + CHECK_VALID(-1); + if (index != 0) { + PyErr_SetString(PyExc_SystemError, + "Accessing non-existent mmap segment"); + return -1; + } + if (!is_writeable(self)) + return -1; + *ptr = self->data; + return self->size; +} + +static Py_ssize_t +mmap_buffer_getsegcount(mmap_object *self, Py_ssize_t *lenp) +{ + CHECK_VALID(-1); + if (lenp) + *lenp = self->size; + return 1; +} + +static Py_ssize_t +mmap_buffer_getcharbuffer(mmap_object *self, Py_ssize_t index, const void **ptr) +{ + if (index != 0) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent buffer segment"); + return -1; + } + *ptr = (const char *)self->data; + return self->size; +} + +static PyObject * +mmap_object_getattr(mmap_object *self, char *name) +{ + return Py_FindMethod(mmap_object_methods, (PyObject *)self, name); +} + +static Py_ssize_t +mmap_length(mmap_object *self) +{ + CHECK_VALID(-1); + return self->size; +} + +static PyObject * +mmap_item(mmap_object *self, Py_ssize_t i) +{ + CHECK_VALID(NULL); + if (i < 0 || (size_t)i >= self->size) { + PyErr_SetString(PyExc_IndexError, "mmap index out of range"); + return NULL; + } + return PyString_FromStringAndSize(self->data + i, 1); +} + +static PyObject * +mmap_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh) +{ + CHECK_VALID(NULL); + if (ilow < 0) + ilow = 0; + else if ((size_t)ilow > self->size) + ilow = self->size; + if (ihigh < 0) + ihigh = 0; + if (ihigh < ilow) + ihigh = ilow; + else if ((size_t)ihigh > self->size) + ihigh = self->size; + + return PyString_FromStringAndSize(self->data + ilow, ihigh-ilow); +} + +static PyObject * +mmap_concat(mmap_object *self, PyObject *bb) +{ + CHECK_VALID(NULL); + PyErr_SetString(PyExc_SystemError, + "mmaps don't support concatenation"); + return NULL; +} + +static PyObject * +mmap_repeat(mmap_object *self, Py_ssize_t n) +{ + CHECK_VALID(NULL); + PyErr_SetString(PyExc_SystemError, + "mmaps don't support repeat operation"); + return NULL; +} + +static int +mmap_ass_slice(mmap_object *self, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) +{ + const char *buf; + + CHECK_VALID(-1); + if (ilow < 0) + ilow = 0; + else if ((size_t)ilow > self->size) + ilow = self->size; + if (ihigh < 0) + ihigh = 0; + if (ihigh < ilow) + ihigh = ilow; + else if ((size_t)ihigh > self->size) + ihigh = self->size; + + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "mmap object doesn't support slice deletion"); + return -1; + } + if (! (PyString_Check(v)) ) { + PyErr_SetString(PyExc_IndexError, + "mmap slice assignment must be a string"); + return -1; + } + if (PyString_Size(v) != (ihigh - ilow)) { + PyErr_SetString(PyExc_IndexError, + "mmap slice assignment is wrong size"); + return -1; + } + if (!is_writeable(self)) + return -1; + buf = PyString_AsString(v); + memcpy(self->data + ilow, buf, ihigh-ilow); + return 0; +} + +static int +mmap_ass_item(mmap_object *self, Py_ssize_t i, PyObject *v) +{ + const char *buf; + + CHECK_VALID(-1); + if (i < 0 || (size_t)i >= self->size) { + PyErr_SetString(PyExc_IndexError, "mmap index out of range"); + return -1; + } + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "mmap object doesn't support item deletion"); + return -1; + } + if (! (PyString_Check(v) && PyString_Size(v)==1) ) { + PyErr_SetString(PyExc_IndexError, + "mmap assignment must be single-character string"); + return -1; + } + if (!is_writeable(self)) + return -1; + buf = PyString_AsString(v); + self->data[i] = buf[0]; + return 0; +} + +static PySequenceMethods mmap_as_sequence = { + (lenfunc)mmap_length, /*sq_length*/ + (binaryfunc)mmap_concat, /*sq_concat*/ + (ssizeargfunc)mmap_repeat, /*sq_repeat*/ + (ssizeargfunc)mmap_item, /*sq_item*/ + (ssizessizeargfunc)mmap_slice, /*sq_slice*/ + (ssizeobjargproc)mmap_ass_item, /*sq_ass_item*/ + (ssizessizeobjargproc)mmap_ass_slice, /*sq_ass_slice*/ +}; + +static PyBufferProcs mmap_as_buffer = { + (readbufferproc)mmap_buffer_getreadbuf, + (writebufferproc)mmap_buffer_getwritebuf, + (segcountproc)mmap_buffer_getsegcount, + (charbufferproc)mmap_buffer_getcharbuffer, +}; + +static PyTypeObject mmap_object_type = { + PyObject_HEAD_INIT(0) /* patched in module init */ + 0, /* ob_size */ + "mmap.mmap", /* tp_name */ + sizeof(mmap_object), /* tp_size */ + 0, /* tp_itemsize */ + /* methods */ + (destructor) mmap_object_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + (getattrfunc) mmap_object_getattr, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &mmap_as_sequence, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + &mmap_as_buffer, /*tp_as_buffer*/ + Py_TPFLAGS_HAVE_GETCHARBUFFER, /*tp_flags*/ + 0, /*tp_doc*/ +}; + + +/* extract the map size from the given PyObject + + Returns -1 on error, with an appropriate Python exception raised. On + success, the map size is returned. */ +static Py_ssize_t +_GetMapSize(PyObject *o) +{ + if (PyIndex_Check(o)) { + Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError); + if (i==-1 && PyErr_Occurred()) + return -1; + if (i < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped size must be positive"); + return -1; + } + return i; + } + + PyErr_SetString(PyExc_TypeError, "map size must be an integral value"); + return -1; +} + +#ifdef UNIX +static PyObject * +new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict) +{ +#ifdef HAVE_FSTAT + struct stat st; +#endif + mmap_object *m_obj; + PyObject *map_size_obj = NULL; + Py_ssize_t map_size; + int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ; + int devzero = -1; + int access = (int)ACCESS_DEFAULT; + static char *keywords[] = {"fileno", "length", + "flags", "prot", + "access", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords, + &fd, &map_size_obj, &flags, &prot, + &access)) + return NULL; + map_size = _GetMapSize(map_size_obj); + if (map_size < 0) + return NULL; + + if ((access != (int)ACCESS_DEFAULT) && + ((flags != MAP_SHARED) || (prot != (PROT_WRITE | PROT_READ)))) + return PyErr_Format(PyExc_ValueError, + "mmap can't specify both access and flags, prot."); + switch ((access_mode)access) { + case ACCESS_READ: + flags = MAP_SHARED; + prot = PROT_READ; + break; + case ACCESS_WRITE: + flags = MAP_SHARED; + prot = PROT_READ | PROT_WRITE; + break; + case ACCESS_COPY: + flags = MAP_PRIVATE; + prot = PROT_READ | PROT_WRITE; + break; + case ACCESS_DEFAULT: + /* use the specified or default values of flags and prot */ + break; + default: + return PyErr_Format(PyExc_ValueError, + "mmap invalid access parameter."); + } + +#ifdef HAVE_FSTAT +# ifdef __VMS + /* on OpenVMS we must ensure that all bytes are written to the file */ + fsync(fd); +# endif + if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) { + if (map_size == 0) { + map_size = st.st_size; + } else if ((size_t)map_size > st.st_size) { + PyErr_SetString(PyExc_ValueError, + "mmap length is greater than file size"); + return NULL; + } + } +#endif + m_obj = PyObject_New(mmap_object, &mmap_object_type); + if (m_obj == NULL) {return NULL;} + m_obj->data = NULL; + m_obj->size = (size_t) map_size; + m_obj->pos = (size_t) 0; + if (fd == -1) { + m_obj->fd = -1; + /* Assume the caller wants to map anonymous memory. + This is the same behaviour as Windows. mmap.mmap(-1, size) + on both Windows and Unix map anonymous memory. + */ +#ifdef MAP_ANONYMOUS + /* BSD way to map anonymous memory */ + flags |= MAP_ANONYMOUS; +#else + /* SVR4 method to map anonymous memory is to open /dev/zero */ + fd = devzero = open("/dev/zero", O_RDWR); + if (devzero == -1) { + Py_DECREF(m_obj); + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } +#endif + } else { + m_obj->fd = dup(fd); + if (m_obj->fd == -1) { + Py_DECREF(m_obj); + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + } + + m_obj->data = mmap(NULL, map_size, + prot, flags, + fd, 0); + + if (devzero != -1) { + close(devzero); + } + + if (m_obj->data == (char *)-1) { + m_obj->data = NULL; + Py_DECREF(m_obj); + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + m_obj->access = (access_mode)access; + return (PyObject *)m_obj; +} +#endif /* UNIX */ + +#ifdef MS_WINDOWS +static PyObject * +new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict) +{ + mmap_object *m_obj; + PyObject *map_size_obj = NULL; + Py_ssize_t map_size; + DWORD size_hi; /* upper 32 bits of m_obj->size */ + DWORD size_lo; /* lower 32 bits of m_obj->size */ + char *tagname = ""; + DWORD dwErr = 0; + int fileno; + HANDLE fh = 0; + int access = (access_mode)ACCESS_DEFAULT; + DWORD flProtect, dwDesiredAccess; + static char *keywords[] = { "fileno", "length", + "tagname", + "access", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords, + &fileno, &map_size_obj, + &tagname, &access)) { + return NULL; + } + + switch((access_mode)access) { + case ACCESS_READ: + flProtect = PAGE_READONLY; + dwDesiredAccess = FILE_MAP_READ; + break; + case ACCESS_DEFAULT: case ACCESS_WRITE: + flProtect = PAGE_READWRITE; + dwDesiredAccess = FILE_MAP_WRITE; + break; + case ACCESS_COPY: + flProtect = PAGE_WRITECOPY; + dwDesiredAccess = FILE_MAP_COPY; + break; + default: + return PyErr_Format(PyExc_ValueError, + "mmap invalid access parameter."); + } + + map_size = _GetMapSize(map_size_obj); + if (map_size < 0) + return NULL; + + /* assume -1 and 0 both mean invalid filedescriptor + to 'anonymously' map memory. + XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5. + XXX: Should this code be added? + if (fileno == 0) + PyErr_Warn(PyExc_DeprecationWarning, + "don't use 0 for anonymous memory"); + */ + if (fileno != -1 && fileno != 0) { + fh = (HANDLE)_get_osfhandle(fileno); + if (fh==(HANDLE)-1) { + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + /* Win9x appears to need us seeked to zero */ + lseek(fileno, 0, SEEK_SET); + } + + m_obj = PyObject_New(mmap_object, &mmap_object_type); + if (m_obj == NULL) + return NULL; + /* Set every field to an invalid marker, so we can safely + destruct the object in the face of failure */ + m_obj->data = NULL; + m_obj->file_handle = INVALID_HANDLE_VALUE; + m_obj->map_handle = INVALID_HANDLE_VALUE; + m_obj->tagname = NULL; + + if (fh) { + /* It is necessary to duplicate the handle, so the + Python code can close it on us */ + if (!DuplicateHandle( + GetCurrentProcess(), /* source process handle */ + fh, /* handle to be duplicated */ + GetCurrentProcess(), /* target proc handle */ + (LPHANDLE)&m_obj->file_handle, /* result */ + 0, /* access - ignored due to options value */ + FALSE, /* inherited by child processes? */ + DUPLICATE_SAME_ACCESS)) { /* options */ + dwErr = GetLastError(); + Py_DECREF(m_obj); + PyErr_SetFromWindowsErr(dwErr); + return NULL; + } + if (!map_size) { + DWORD low,high; + low = GetFileSize(fh, &high); + /* low might just happen to have the value INVALID_FILE_SIZE; + so we need to check the last error also. */ + if (low == INVALID_FILE_SIZE && + (dwErr = GetLastError()) != NO_ERROR) { + Py_DECREF(m_obj); + return PyErr_SetFromWindowsErr(dwErr); + } + +#if SIZEOF_SIZE_T > 4 + m_obj->size = (((size_t)high)<<32) + low; +#else + if (high) + /* File is too large to map completely */ + m_obj->size = (size_t)-1; + else + m_obj->size = low; +#endif + } else { + m_obj->size = map_size; + } + } + else { + m_obj->size = map_size; + } + + /* set the initial position */ + m_obj->pos = (size_t) 0; + + /* set the tag name */ + if (tagname != NULL && *tagname != '\0') { + m_obj->tagname = PyMem_Malloc(strlen(tagname)+1); + if (m_obj->tagname == NULL) { + PyErr_NoMemory(); + Py_DECREF(m_obj); + return NULL; + } + strcpy(m_obj->tagname, tagname); + } + else + m_obj->tagname = NULL; + + m_obj->access = (access_mode)access; + /* DWORD is a 4-byte int. If we're on a box where size_t consumes + * more than 4 bytes, we need to break it apart. Else (size_t + * consumes 4 bytes), C doesn't define what happens if we shift + * right by 32, so we need different code. + */ +#if SIZEOF_SIZE_T > 4 + size_hi = (DWORD)(m_obj->size >> 32); + size_lo = (DWORD)(m_obj->size & 0xFFFFFFFF); +#else + size_hi = 0; + size_lo = (DWORD)m_obj->size; +#endif + m_obj->map_handle = CreateFileMapping(m_obj->file_handle, + NULL, + flProtect, + size_hi, + size_lo, + m_obj->tagname); + if (m_obj->map_handle != NULL) { + m_obj->data = (char *) MapViewOfFile(m_obj->map_handle, + dwDesiredAccess, + 0, + 0, + 0); + if (m_obj->data != NULL) + return (PyObject *)m_obj; + else + dwErr = GetLastError(); + } else + dwErr = GetLastError(); + Py_DECREF(m_obj); + PyErr_SetFromWindowsErr(dwErr); + return NULL; +} +#endif /* MS_WINDOWS */ + +/* List of functions exported by this module */ +static struct PyMethodDef mmap_functions[] = { + {"mmap", (PyCFunction) new_mmap_object, + METH_VARARGS|METH_KEYWORDS}, + {NULL, NULL} /* Sentinel */ +}; + +static void +setint(PyObject *d, const char *name, long value) +{ + PyObject *o = PyInt_FromLong(value); + if (o && PyDict_SetItemString(d, name, o) == 0) { + Py_DECREF(o); + } +} + +PyMODINIT_FUNC + initmmap(void) +{ + PyObject *dict, *module; + + /* Patch the object type */ + mmap_object_type.ob_type = &PyType_Type; + + module = Py_InitModule("mmap", mmap_functions); + if (module == NULL) + return; + dict = PyModule_GetDict(module); + if (!dict) + return; + mmap_module_error = PyExc_EnvironmentError; + PyDict_SetItemString(dict, "error", mmap_module_error); +#ifdef PROT_EXEC + setint(dict, "PROT_EXEC", PROT_EXEC); +#endif +#ifdef PROT_READ + setint(dict, "PROT_READ", PROT_READ); +#endif +#ifdef PROT_WRITE + setint(dict, "PROT_WRITE", PROT_WRITE); +#endif + +#ifdef MAP_SHARED + setint(dict, "MAP_SHARED", MAP_SHARED); +#endif +#ifdef MAP_PRIVATE + setint(dict, "MAP_PRIVATE", MAP_PRIVATE); +#endif +#ifdef MAP_DENYWRITE + setint(dict, "MAP_DENYWRITE", MAP_DENYWRITE); +#endif +#ifdef MAP_EXECUTABLE + setint(dict, "MAP_EXECUTABLE", MAP_EXECUTABLE); +#endif +#ifdef MAP_ANONYMOUS + setint(dict, "MAP_ANON", MAP_ANONYMOUS); + setint(dict, "MAP_ANONYMOUS", MAP_ANONYMOUS); +#endif + + setint(dict, "PAGESIZE", (long)my_getpagesize()); + + setint(dict, "ACCESS_READ", ACCESS_READ); + setint(dict, "ACCESS_WRITE", ACCESS_WRITE); + setint(dict, "ACCESS_COPY", ACCESS_COPY); +} diff --git a/sys/src/cmd/python/Modules/nismodule.c b/sys/src/cmd/python/Modules/nismodule.c new file mode 100644 index 000000000..0811430cf --- /dev/null +++ b/sys/src/cmd/python/Modules/nismodule.c @@ -0,0 +1,444 @@ +/*********************************************************** + Written by: + Fred Gansevles <Fred.Gansevles@cs.utwente.nl> + B&O group, + Faculteit der Informatica, + Universiteit Twente, + Enschede, + the Netherlands. +******************************************************************/ + +/* NIS module implementation */ + +#include "Python.h" + +#include <sys/time.h> +#include <sys/types.h> +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> + +#ifdef __sgi +/* This is missing from rpcsvc/ypclnt.h */ +extern int yp_get_default_domain(char **); +#endif + +PyDoc_STRVAR(get_default_domain__doc__, +"get_default_domain() -> str\n\ +Corresponds to the C library yp_get_default_domain() call, returning\n\ +the default NIS domain.\n"); + +PyDoc_STRVAR(match__doc__, +"match(key, map, domain = defaultdomain)\n\ +Corresponds to the C library yp_match() call, returning the value of\n\ +key in the given map. Optionally domain can be specified but it\n\ +defaults to the system default domain.\n"); + +PyDoc_STRVAR(cat__doc__, +"cat(map, domain = defaultdomain)\n\ +Returns the entire map as a dictionary. Optionally domain can be\n\ +specified but it defaults to the system default domain.\n"); + +PyDoc_STRVAR(maps__doc__, +"maps(domain = defaultdomain)\n\ +Returns an array of all available NIS maps within a domain. If domain\n\ +is not specified it defaults to the system default domain.\n"); + +static PyObject *NisError; + +static PyObject * +nis_error (int err) +{ + PyErr_SetString(NisError, yperr_string(err)); + return NULL; +} + +static struct nis_map { + char *alias; + char *map; + int fix; +} aliases [] = { + {"passwd", "passwd.byname", 0}, + {"group", "group.byname", 0}, + {"networks", "networks.byaddr", 0}, + {"hosts", "hosts.byname", 0}, + {"protocols", "protocols.bynumber", 0}, + {"services", "services.byname", 0}, + {"aliases", "mail.aliases", 1}, /* created with 'makedbm -a' */ + {"ethers", "ethers.byname", 0}, + {0L, 0L, 0} +}; + +static char * +nis_mapname (char *map, int *pfix) +{ + int i; + + *pfix = 0; + for (i=0; aliases[i].alias != 0L; i++) { + if (!strcmp (aliases[i].alias, map)) { + *pfix = aliases[i].fix; + return aliases[i].map; + } + if (!strcmp (aliases[i].map, map)) { + *pfix = aliases[i].fix; + return aliases[i].map; + } + } + + return map; +} + +#ifdef __APPLE__ +typedef int (*foreachfunc)(unsigned long, char *, int, char *, int, void *); +#else +typedef int (*foreachfunc)(int, char *, int, char *, int, char *); +#endif + +struct ypcallback_data { + PyObject *dict; + int fix; +}; + +static int +nis_foreach (int instatus, char *inkey, int inkeylen, char *inval, + int invallen, struct ypcallback_data *indata) +{ + if (instatus == YP_TRUE) { + PyObject *key; + PyObject *val; + int err; + + if (indata->fix) { + if (inkeylen > 0 && inkey[inkeylen-1] == '\0') + inkeylen--; + if (invallen > 0 && inval[invallen-1] == '\0') + invallen--; + } + key = PyString_FromStringAndSize(inkey, inkeylen); + val = PyString_FromStringAndSize(inval, invallen); + if (key == NULL || val == NULL) { + /* XXX error -- don't know how to handle */ + PyErr_Clear(); + Py_XDECREF(key); + Py_XDECREF(val); + return 1; + } + err = PyDict_SetItem(indata->dict, key, val); + Py_DECREF(key); + Py_DECREF(val); + if (err != 0) { + PyErr_Clear(); + return 1; + } + return 0; + } + return 1; +} + +static PyObject * +nis_get_default_domain (PyObject *self) +{ + char *domain; + int err; + PyObject *res; + + if ((err = yp_get_default_domain(&domain)) != 0) + return nis_error(err); + + res = PyString_FromStringAndSize (domain, strlen(domain)); + return res; +} + +static PyObject * +nis_match (PyObject *self, PyObject *args, PyObject *kwdict) +{ + char *match; + char *domain = NULL; + int keylen, len; + char *key, *map; + int err; + PyObject *res; + int fix; + static char *kwlist[] = {"key", "map", "domain", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, + "t#s|s:match", kwlist, + &key, &keylen, &map, &domain)) + return NULL; + if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) + return nis_error(err); + map = nis_mapname (map, &fix); + if (fix) + keylen++; + Py_BEGIN_ALLOW_THREADS + err = yp_match (domain, map, key, keylen, &match, &len); + Py_END_ALLOW_THREADS + if (fix) + len--; + if (err != 0) + return nis_error(err); + res = PyString_FromStringAndSize (match, len); + free (match); + return res; +} + +static PyObject * +nis_cat (PyObject *self, PyObject *args, PyObject *kwdict) +{ + char *domain = NULL; + char *map; + struct ypall_callback cb; + struct ypcallback_data data; + PyObject *dict; + int err; + static char *kwlist[] = {"map", "domain", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "s|s:cat", + kwlist, &map, &domain)) + return NULL; + if (!domain && ((err = yp_get_default_domain(&domain)) != 0)) + return nis_error(err); + dict = PyDict_New (); + if (dict == NULL) + return NULL; + cb.foreach = (foreachfunc)nis_foreach; + data.dict = dict; + map = nis_mapname (map, &data.fix); + cb.data = (char *)&data; + Py_BEGIN_ALLOW_THREADS + err = yp_all (domain, map, &cb); + Py_END_ALLOW_THREADS + if (err != 0) { + Py_DECREF(dict); + return nis_error(err); + } + return dict; +} + +/* These should be u_long on Sun h/w but not on 64-bit h/w. + This is not portable to machines with 16-bit ints and no prototypes */ +#ifndef YPPROC_MAPLIST +#define YPPROC_MAPLIST 11 +#endif +#ifndef YPPROG +#define YPPROG 100004 +#endif +#ifndef YPVERS +#define YPVERS 2 +#endif + +typedef char *domainname; +typedef char *mapname; + +enum nisstat { + NIS_TRUE = 1, + NIS_NOMORE = 2, + NIS_FALSE = 0, + NIS_NOMAP = -1, + NIS_NODOM = -2, + NIS_NOKEY = -3, + NIS_BADOP = -4, + NIS_BADDB = -5, + NIS_YPERR = -6, + NIS_BADARGS = -7, + NIS_VERS = -8 +}; +typedef enum nisstat nisstat; + +struct nismaplist { + mapname map; + struct nismaplist *next; +}; +typedef struct nismaplist nismaplist; + +struct nisresp_maplist { + nisstat stat; + nismaplist *maps; +}; +typedef struct nisresp_maplist nisresp_maplist; + +static struct timeval TIMEOUT = { 25, 0 }; + +static +bool_t +nis_xdr_domainname(XDR *xdrs, domainname *objp) +{ + if (!xdr_string(xdrs, objp, YPMAXDOMAIN)) { + return (FALSE); + } + return (TRUE); +} + +static +bool_t +nis_xdr_mapname(XDR *xdrs, mapname *objp) +{ + if (!xdr_string(xdrs, objp, YPMAXMAP)) { + return (FALSE); + } + return (TRUE); +} + +static +bool_t +nis_xdr_ypmaplist(XDR *xdrs, nismaplist *objp) +{ + if (!nis_xdr_mapname(xdrs, &objp->map)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->next, + sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist)) + { + return (FALSE); + } + return (TRUE); +} + +static +bool_t +nis_xdr_ypstat(XDR *xdrs, nisstat *objp) +{ + if (!xdr_enum(xdrs, (enum_t *)objp)) { + return (FALSE); + } + return (TRUE); +} + + +static +bool_t +nis_xdr_ypresp_maplist(XDR *xdrs, nisresp_maplist *objp) +{ + if (!nis_xdr_ypstat(xdrs, &objp->stat)) { + return (FALSE); + } + if (!xdr_pointer(xdrs, (char **)&objp->maps, + sizeof(nismaplist), (xdrproc_t)nis_xdr_ypmaplist)) + { + return (FALSE); + } + return (TRUE); +} + + +static +nisresp_maplist * +nisproc_maplist_2(domainname *argp, CLIENT *clnt) +{ + static nisresp_maplist res; + + memset(&res, 0, sizeof(res)); + if (clnt_call(clnt, YPPROC_MAPLIST, + (xdrproc_t)nis_xdr_domainname, (caddr_t)argp, + (xdrproc_t)nis_xdr_ypresp_maplist, (caddr_t)&res, + TIMEOUT) != RPC_SUCCESS) + { + return (NULL); + } + return (&res); +} + +static +nismaplist * +nis_maplist (char *dom) +{ + nisresp_maplist *list; + CLIENT *cl; + char *server = NULL; + int mapi = 0; + + while (!server && aliases[mapi].map != 0L) { + yp_master (dom, aliases[mapi].map, &server); + mapi++; + } + if (!server) { + PyErr_SetString(NisError, "No NIS master found for any map"); + return NULL; + } + cl = clnt_create(server, YPPROG, YPVERS, "tcp"); + if (cl == NULL) { + PyErr_SetString(NisError, clnt_spcreateerror(server)); + goto finally; + } + list = nisproc_maplist_2 (&dom, cl); + clnt_destroy(cl); + if (list == NULL) + goto finally; + if (list->stat != NIS_TRUE) + goto finally; + + free(server); + return list->maps; + + finally: + free(server); + return NULL; +} + +static PyObject * +nis_maps (PyObject *self, PyObject *args, PyObject *kwdict) +{ + char *domain = NULL; + nismaplist *maps; + PyObject *list; + int err; + static char *kwlist[] = {"domain", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, + "|s:maps", kwlist, &domain)) + return NULL; + if (!domain && ((err = yp_get_default_domain (&domain)) != 0)) { + nis_error(err); + return NULL; + } + + if ((maps = nis_maplist (domain)) == NULL) + return NULL; + if ((list = PyList_New(0)) == NULL) + return NULL; + for (maps = maps; maps; maps = maps->next) { + PyObject *str = PyString_FromString(maps->map); + if (!str || PyList_Append(list, str) < 0) + { + Py_DECREF(list); + list = NULL; + break; + } + Py_DECREF(str); + } + /* XXX Shouldn't we free the list of maps now? */ + return list; +} + +static PyMethodDef nis_methods[] = { + {"match", (PyCFunction)nis_match, + METH_VARARGS | METH_KEYWORDS, + match__doc__}, + {"cat", (PyCFunction)nis_cat, + METH_VARARGS | METH_KEYWORDS, + cat__doc__}, + {"maps", (PyCFunction)nis_maps, + METH_VARARGS | METH_KEYWORDS, + maps__doc__}, + {"get_default_domain", (PyCFunction)nis_get_default_domain, + METH_NOARGS, + get_default_domain__doc__}, + {NULL, NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(nis__doc__, +"This module contains functions for accessing NIS maps.\n"); + +void +initnis (void) +{ + PyObject *m, *d; + m = Py_InitModule3("nis", nis_methods, nis__doc__); + if (m == NULL) + return; + d = PyModule_GetDict(m); + NisError = PyErr_NewException("nis.error", NULL, NULL); + if (NisError != NULL) + PyDict_SetItemString(d, "error", NisError); +} diff --git a/sys/src/cmd/python/Modules/operator.c b/sys/src/cmd/python/Modules/operator.c new file mode 100644 index 000000000..0a7222a72 --- /dev/null +++ b/sys/src/cmd/python/Modules/operator.c @@ -0,0 +1,602 @@ + +#include "Python.h" + +PyDoc_STRVAR(operator_doc, +"Operator interface.\n\ +\n\ +This module exports a set of functions implemented in C corresponding\n\ +to the intrinsic operators of Python. For example, operator.add(x, y)\n\ +is equivalent to the expression x+y. The function names are those\n\ +used for special class methods; variants without leading and trailing\n\ +'__' are also provided for convenience."); + +#define spam1(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \ + return AOP(a1); } + +#define spam2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + return AOP(a1,a2); } + +#define spamoi(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1; int a2; \ + if(! PyArg_ParseTuple(a,"Oi:" #OP,&a1,&a2)) return NULL; \ + return AOP(a1,a2); } + +#define spam2n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == AOP(a1,a2)) return NULL; \ + Py_INCREF(Py_None); \ + return Py_None; } + +#define spam3n(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2, *a3; \ + if(! PyArg_UnpackTuple(a,#OP,3,3,&a1,&a2,&a3)) return NULL; \ + if(-1 == AOP(a1,a2,a3)) return NULL; \ + Py_INCREF(Py_None); \ + return Py_None; } + +#define spami(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a1) { \ + long r; \ + if(-1 == (r=AOP(a1))) return NULL; \ + return PyBool_FromLong(r); } + +#define spami2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; long r; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == (r=AOP(a1,a2))) return NULL; \ + return PyInt_FromLong(r); } + +#define spamn2(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; Py_ssize_t r; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == (r=AOP(a1,a2))) return NULL; \ + return PyInt_FromSsize_t(r); } + +#define spami2b(OP,AOP) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; long r; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + if(-1 == (r=AOP(a1,a2))) return NULL; \ + return PyBool_FromLong(r); } + +#define spamrc(OP,A) static PyObject *OP(PyObject *s, PyObject *a) { \ + PyObject *a1, *a2; \ + if(! PyArg_UnpackTuple(a,#OP,2,2,&a1,&a2)) return NULL; \ + return PyObject_RichCompare(a1,a2,A); } + +spami(isCallable , PyCallable_Check) +spami(isNumberType , PyNumber_Check) +spami(truth , PyObject_IsTrue) +spam2(op_add , PyNumber_Add) +spam2(op_sub , PyNumber_Subtract) +spam2(op_mul , PyNumber_Multiply) +spam2(op_div , PyNumber_Divide) +spam2(op_floordiv , PyNumber_FloorDivide) +spam2(op_truediv , PyNumber_TrueDivide) +spam2(op_mod , PyNumber_Remainder) +spam1(op_neg , PyNumber_Negative) +spam1(op_pos , PyNumber_Positive) +spam1(op_abs , PyNumber_Absolute) +spam1(op_inv , PyNumber_Invert) +spam1(op_invert , PyNumber_Invert) +spam2(op_lshift , PyNumber_Lshift) +spam2(op_rshift , PyNumber_Rshift) +spami(op_not_ , PyObject_Not) +spam2(op_and_ , PyNumber_And) +spam2(op_xor , PyNumber_Xor) +spam2(op_or_ , PyNumber_Or) +spam2(op_iadd , PyNumber_InPlaceAdd) +spam2(op_isub , PyNumber_InPlaceSubtract) +spam2(op_imul , PyNumber_InPlaceMultiply) +spam2(op_idiv , PyNumber_InPlaceDivide) +spam2(op_ifloordiv , PyNumber_InPlaceFloorDivide) +spam2(op_itruediv , PyNumber_InPlaceTrueDivide) +spam2(op_imod , PyNumber_InPlaceRemainder) +spam2(op_ilshift , PyNumber_InPlaceLshift) +spam2(op_irshift , PyNumber_InPlaceRshift) +spam2(op_iand , PyNumber_InPlaceAnd) +spam2(op_ixor , PyNumber_InPlaceXor) +spam2(op_ior , PyNumber_InPlaceOr) +spami(isSequenceType , PySequence_Check) +spam2(op_concat , PySequence_Concat) +spamoi(op_repeat , PySequence_Repeat) +spam2(op_iconcat , PySequence_InPlaceConcat) +spamoi(op_irepeat , PySequence_InPlaceRepeat) +spami2b(op_contains , PySequence_Contains) +spami2b(sequenceIncludes, PySequence_Contains) +spamn2(indexOf , PySequence_Index) +spamn2(countOf , PySequence_Count) +spami(isMappingType , PyMapping_Check) +spam2(op_getitem , PyObject_GetItem) +spam2n(op_delitem , PyObject_DelItem) +spam3n(op_setitem , PyObject_SetItem) +spamrc(op_lt , Py_LT) +spamrc(op_le , Py_LE) +spamrc(op_eq , Py_EQ) +spamrc(op_ne , Py_NE) +spamrc(op_gt , Py_GT) +spamrc(op_ge , Py_GE) + +static PyObject* +op_pow(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2; + if (PyArg_UnpackTuple(a,"pow", 2, 2, &a1, &a2)) + return PyNumber_Power(a1, a2, Py_None); + return NULL; +} + +static PyObject* +op_ipow(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2; + if (PyArg_UnpackTuple(a,"ipow", 2, 2, &a1, &a2)) + return PyNumber_InPlacePower(a1, a2, Py_None); + return NULL; +} + +static PyObject * +op_index(PyObject *s, PyObject *a) +{ + return PyNumber_Index(a); +} + +static PyObject* +is_(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2, *result = NULL; + if (PyArg_UnpackTuple(a,"is_", 2, 2, &a1, &a2)) { + result = (a1 == a2) ? Py_True : Py_False; + Py_INCREF(result); + } + return result; +} + +static PyObject* +is_not(PyObject *s, PyObject *a) +{ + PyObject *a1, *a2, *result = NULL; + if (PyArg_UnpackTuple(a,"is_not", 2, 2, &a1, &a2)) { + result = (a1 != a2) ? Py_True : Py_False; + Py_INCREF(result); + } + return result; +} + +static PyObject* +op_getslice(PyObject *s, PyObject *a) +{ + PyObject *a1; + Py_ssize_t a2, a3; + + if (!PyArg_ParseTuple(a, "Onn:getslice", &a1, &a2, &a3)) + return NULL; + return PySequence_GetSlice(a1, a2, a3); +} + +static PyObject* +op_setslice(PyObject *s, PyObject *a) +{ + PyObject *a1, *a4; + Py_ssize_t a2, a3; + + if (!PyArg_ParseTuple(a, "OnnO:setslice", &a1, &a2, &a3, &a4)) + return NULL; + + if (-1 == PySequence_SetSlice(a1, a2, a3, a4)) + return NULL; + + Py_RETURN_NONE; +} + +static PyObject* +op_delslice(PyObject *s, PyObject *a) +{ + PyObject *a1; + Py_ssize_t a2, a3; + + if (!PyArg_ParseTuple(a, "Onn:delslice", &a1, &a2, &a3)) + return NULL; + + if (-1 == PySequence_DelSlice(a1, a2, a3)) + return NULL; + + Py_RETURN_NONE; +} + +#undef spam1 +#undef spam2 +#undef spam1o +#undef spam1o +#define spam1(OP,DOC) {#OP, OP, METH_VARARGS, PyDoc_STR(DOC)}, +#define spam2(OP,ALTOP,DOC) {#OP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)}, \ + {#ALTOP, op_##OP, METH_VARARGS, PyDoc_STR(DOC)}, +#define spam1o(OP,DOC) {#OP, OP, METH_O, PyDoc_STR(DOC)}, +#define spam2o(OP,ALTOP,DOC) {#OP, op_##OP, METH_O, PyDoc_STR(DOC)}, \ + {#ALTOP, op_##OP, METH_O, PyDoc_STR(DOC)}, + +static struct PyMethodDef operator_methods[] = { + +spam1o(isCallable, + "isCallable(a) -- Same as callable(a).") +spam1o(isNumberType, + "isNumberType(a) -- Return True if a has a numeric type, False otherwise.") +spam1o(isSequenceType, + "isSequenceType(a) -- Return True if a has a sequence type, False otherwise.") +spam1o(truth, + "truth(a) -- Return True if a is true, False otherwise.") +spam2(contains,__contains__, + "contains(a, b) -- Same as b in a (note reversed operands).") +spam1(sequenceIncludes, + "sequenceIncludes(a, b) -- Same as b in a (note reversed operands; deprecated).") +spam1(indexOf, + "indexOf(a, b) -- Return the first index of b in a.") +spam1(countOf, + "countOf(a, b) -- Return the number of times b occurs in a.") +spam1o(isMappingType, + "isMappingType(a) -- Return True if a has a mapping type, False otherwise.") + +spam1(is_, "is_(a, b) -- Same as a is b.") +spam1(is_not, "is_not(a, b) -- Same as a is not b.") +spam2o(index, __index__, "index(a) -- Same as a.__index__()") +spam2(add,__add__, "add(a, b) -- Same as a + b.") +spam2(sub,__sub__, "sub(a, b) -- Same as a - b.") +spam2(mul,__mul__, "mul(a, b) -- Same as a * b.") +spam2(div,__div__, "div(a, b) -- Same as a / b when __future__.division is not in effect.") +spam2(floordiv,__floordiv__, "floordiv(a, b) -- Same as a // b.") +spam2(truediv,__truediv__, "truediv(a, b) -- Same as a / b when __future__.division is in effect.") +spam2(mod,__mod__, "mod(a, b) -- Same as a % b.") +spam2o(neg,__neg__, "neg(a) -- Same as -a.") +spam2o(pos,__pos__, "pos(a) -- Same as +a.") +spam2o(abs,__abs__, "abs(a) -- Same as abs(a).") +spam2o(inv,__inv__, "inv(a) -- Same as ~a.") +spam2o(invert,__invert__, "invert(a) -- Same as ~a.") +spam2(lshift,__lshift__, "lshift(a, b) -- Same as a << b.") +spam2(rshift,__rshift__, "rshift(a, b) -- Same as a >> b.") +spam2o(not_,__not__, "not_(a) -- Same as not a.") +spam2(and_,__and__, "and_(a, b) -- Same as a & b.") +spam2(xor,__xor__, "xor(a, b) -- Same as a ^ b.") +spam2(or_,__or__, "or_(a, b) -- Same as a | b.") +spam2(iadd,__iadd__, "iadd(a, b) -- Same as a += b.") +spam2(isub,__isub__, "isub(a, b) -- Same as a -= b.") +spam2(imul,__imul__, "imul(a, b) -- Same as a *= b.") +spam2(idiv,__idiv__, "idiv(a, b) -- Same as a /= b when __future__.division is not in effect.") +spam2(ifloordiv,__ifloordiv__, "ifloordiv(a, b) -- Same as a //= b.") +spam2(itruediv,__itruediv__, "itruediv(a, b) -- Same as a /= b when __future__.division is in effect.") +spam2(imod,__imod__, "imod(a, b) -- Same as a %= b.") +spam2(ilshift,__ilshift__, "ilshift(a, b) -- Same as a <<= b.") +spam2(irshift,__irshift__, "irshift(a, b) -- Same as a >>= b.") +spam2(iand,__iand__, "iand(a, b) -- Same as a &= b.") +spam2(ixor,__ixor__, "ixor(a, b) -- Same as a ^= b.") +spam2(ior,__ior__, "ior(a, b) -- Same as a |= b.") +spam2(concat,__concat__, + "concat(a, b) -- Same as a + b, for a and b sequences.") +spam2(repeat,__repeat__, + "repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.") +spam2(iconcat,__iconcat__, + "iconcat(a, b) -- Same as a += b, for a and b sequences.") +spam2(irepeat,__irepeat__, + "irepeat(a, b) -- Same as a *= b, where a is a sequence, and b is an integer.") +spam2(getitem,__getitem__, + "getitem(a, b) -- Same as a[b].") +spam2(setitem,__setitem__, + "setitem(a, b, c) -- Same as a[b] = c.") +spam2(delitem,__delitem__, + "delitem(a, b) -- Same as del a[b].") +spam2(pow,__pow__, "pow(a, b) -- Same as a ** b.") +spam2(ipow,__ipow__, "ipow(a, b) -- Same as a **= b.") +spam2(getslice,__getslice__, + "getslice(a, b, c) -- Same as a[b:c].") +spam2(setslice,__setslice__, +"setslice(a, b, c, d) -- Same as a[b:c] = d.") +spam2(delslice,__delslice__, +"delslice(a, b, c) -- Same as del a[b:c].") +spam2(lt,__lt__, "lt(a, b) -- Same as a<b.") +spam2(le,__le__, "le(a, b) -- Same as a<=b.") +spam2(eq,__eq__, "eq(a, b) -- Same as a==b.") +spam2(ne,__ne__, "ne(a, b) -- Same as a!=b.") +spam2(gt,__gt__, "gt(a, b) -- Same as a>b.") +spam2(ge,__ge__, "ge(a, b) -- Same as a>=b.") + + {NULL, NULL} /* sentinel */ + +}; + +/* itemgetter object **********************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t nitems; + PyObject *item; +} itemgetterobject; + +static PyTypeObject itemgetter_type; + +static PyObject * +itemgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + itemgetterobject *ig; + PyObject *item; + Py_ssize_t nitems; + + if (!_PyArg_NoKeywords("itemgetter()", kwds)) + return NULL; + + nitems = PyTuple_GET_SIZE(args); + if (nitems <= 1) { + if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item)) + return NULL; + } else + item = args; + + /* create itemgetterobject structure */ + ig = PyObject_GC_New(itemgetterobject, &itemgetter_type); + if (ig == NULL) + return NULL; + + Py_INCREF(item); + ig->item = item; + ig->nitems = nitems; + + PyObject_GC_Track(ig); + return (PyObject *)ig; +} + +static void +itemgetter_dealloc(itemgetterobject *ig) +{ + PyObject_GC_UnTrack(ig); + Py_XDECREF(ig->item); + PyObject_GC_Del(ig); +} + +static int +itemgetter_traverse(itemgetterobject *ig, visitproc visit, void *arg) +{ + Py_VISIT(ig->item); + return 0; +} + +static PyObject * +itemgetter_call(itemgetterobject *ig, PyObject *args, PyObject *kw) +{ + PyObject *obj, *result; + Py_ssize_t i, nitems=ig->nitems; + + if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &obj)) + return NULL; + if (nitems == 1) + return PyObject_GetItem(obj, ig->item); + + assert(PyTuple_Check(ig->item)); + assert(PyTuple_GET_SIZE(ig->item) == nitems); + + result = PyTuple_New(nitems); + if (result == NULL) + return NULL; + + for (i=0 ; i < nitems ; i++) { + PyObject *item, *val; + item = PyTuple_GET_ITEM(ig->item, i); + val = PyObject_GetItem(obj, item); + if (val == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, val); + } + return result; +} + +PyDoc_STRVAR(itemgetter_doc, +"itemgetter(item, ...) --> itemgetter object\n\ +\n\ +Return a callable object that fetches the given item(s) from its operand.\n\ +After, f=itemgetter(2), the call f(r) returns r[2].\n\ +After, g=itemgetter(2,5,3), the call g(r) returns (r[2], r[5], r[3])"); + +static PyTypeObject itemgetter_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "operator.itemgetter", /* tp_name */ + sizeof(itemgetterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)itemgetter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)itemgetter_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + itemgetter_doc, /* tp_doc */ + (traverseproc)itemgetter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + itemgetter_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/* attrgetter object **********************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t nattrs; + PyObject *attr; +} attrgetterobject; + +static PyTypeObject attrgetter_type; + +static PyObject * +attrgetter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + attrgetterobject *ag; + PyObject *attr; + Py_ssize_t nattrs; + + if (!_PyArg_NoKeywords("attrgetter()", kwds)) + return NULL; + + nattrs = PyTuple_GET_SIZE(args); + if (nattrs <= 1) { + if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &attr)) + return NULL; + } else + attr = args; + + /* create attrgetterobject structure */ + ag = PyObject_GC_New(attrgetterobject, &attrgetter_type); + if (ag == NULL) + return NULL; + + Py_INCREF(attr); + ag->attr = attr; + ag->nattrs = nattrs; + + PyObject_GC_Track(ag); + return (PyObject *)ag; +} + +static void +attrgetter_dealloc(attrgetterobject *ag) +{ + PyObject_GC_UnTrack(ag); + Py_XDECREF(ag->attr); + PyObject_GC_Del(ag); +} + +static int +attrgetter_traverse(attrgetterobject *ag, visitproc visit, void *arg) +{ + Py_VISIT(ag->attr); + return 0; +} + +static PyObject * +attrgetter_call(attrgetterobject *ag, PyObject *args, PyObject *kw) +{ + PyObject *obj, *result; + Py_ssize_t i, nattrs=ag->nattrs; + + if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &obj)) + return NULL; + if (ag->nattrs == 1) + return PyObject_GetAttr(obj, ag->attr); + + assert(PyTuple_Check(ag->attr)); + assert(PyTuple_GET_SIZE(ag->attr) == nattrs); + + result = PyTuple_New(nattrs); + if (result == NULL) + return NULL; + + for (i=0 ; i < nattrs ; i++) { + PyObject *attr, *val; + attr = PyTuple_GET_ITEM(ag->attr, i); + val = PyObject_GetAttr(obj, attr); + if (val == NULL) { + Py_DECREF(result); + return NULL; + } + PyTuple_SET_ITEM(result, i, val); + } + return result; +} + +PyDoc_STRVAR(attrgetter_doc, +"attrgetter(attr, ...) --> attrgetter object\n\ +\n\ +Return a callable object that fetches the given attribute(s) from its operand.\n\ +After, f=attrgetter('name'), the call f(r) returns r.name.\n\ +After, g=attrgetter('name', 'date'), the call g(r) returns (r.name, r.date)."); + +static PyTypeObject attrgetter_type = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "operator.attrgetter", /* tp_name */ + sizeof(attrgetterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)attrgetter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)attrgetter_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + attrgetter_doc, /* tp_doc */ + (traverseproc)attrgetter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + attrgetter_new, /* tp_new */ + 0, /* tp_free */ +}; +/* Initialization function for the module (*must* be called initoperator) */ + +PyMODINIT_FUNC +initoperator(void) +{ + PyObject *m; + + /* Create the module and add the functions */ + m = Py_InitModule4("operator", operator_methods, operator_doc, + (PyObject*)NULL, PYTHON_API_VERSION); + if (m == NULL) + return; + + if (PyType_Ready(&itemgetter_type) < 0) + return; + Py_INCREF(&itemgetter_type); + PyModule_AddObject(m, "itemgetter", (PyObject *)&itemgetter_type); + + if (PyType_Ready(&attrgetter_type) < 0) + return; + Py_INCREF(&attrgetter_type); + PyModule_AddObject(m, "attrgetter", (PyObject *)&attrgetter_type); +} diff --git a/sys/src/cmd/python/Modules/ossaudiodev.c b/sys/src/cmd/python/Modules/ossaudiodev.c new file mode 100644 index 000000000..dc14ded07 --- /dev/null +++ b/sys/src/cmd/python/Modules/ossaudiodev.c @@ -0,0 +1,1138 @@ +/* + * ossaudiodev -- Python interface to the OSS (Open Sound System) API. + * This is the standard audio API for Linux and some + * flavours of BSD [XXX which ones?]; it is also available + * for a wide range of commercial Unices. + * + * Originally written by Peter Bosch, March 2000, as linuxaudiodev. + * + * Renamed to ossaudiodev and rearranged/revised/hacked up + * by Greg Ward <gward@python.net>, November 2002. + * Mixer interface by Nicholas FitzRoy-Dale <wzdd@lardcave.net>, Dec 2002. + * + * (c) 2000 Peter Bosch. All Rights Reserved. + * (c) 2002 Gregory P. Ward. All Rights Reserved. + * (c) 2002 Python Software Foundation. All Rights Reserved. + * + * XXX need a license statement + * + * $Id: ossaudiodev.c 52137 2006-10-04 10:23:57Z armin.rigo $ + */ + +#include "Python.h" +#include "structmember.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#else +#define O_RDONLY 00 +#define O_WRONLY 01 +#endif + +#include <sys/ioctl.h> +#include <sys/soundcard.h> + +#if defined(linux) + +#ifndef HAVE_STDINT_H +typedef unsigned long uint32_t; +#endif + +#elif defined(__FreeBSD__) + +# ifndef SNDCTL_DSP_CHANNELS +# define SNDCTL_DSP_CHANNELS SOUND_PCM_WRITE_CHANNELS +# endif + +#endif + +typedef struct { + PyObject_HEAD + char *devicename; /* name of the device file */ + int fd; /* file descriptor */ + int mode; /* file mode (O_RDONLY, etc.) */ + int icount; /* input count */ + int ocount; /* output count */ + uint32_t afmts; /* audio formats supported by hardware */ +} oss_audio_t; + +typedef struct { + PyObject_HEAD + int fd; /* The open mixer device */ +} oss_mixer_t; + + +static PyTypeObject OSSAudioType; +static PyTypeObject OSSMixerType; + +static PyObject *OSSAudioError; + + +/* ---------------------------------------------------------------------- + * DSP object initialization/deallocation + */ + +static oss_audio_t * +newossobject(PyObject *arg) +{ + oss_audio_t *self; + int fd, afmts, imode; + char *devicename = NULL; + char *mode = NULL; + + /* Two ways to call open(): + open(device, mode) (for consistency with builtin open()) + open(mode) (for backwards compatibility) + because the *first* argument is optional, parsing args is + a wee bit tricky. */ + if (!PyArg_ParseTuple(arg, "s|s:open", &devicename, &mode)) + return NULL; + if (mode == NULL) { /* only one arg supplied */ + mode = devicename; + devicename = NULL; + } + + if (strcmp(mode, "r") == 0) + imode = O_RDONLY; + else if (strcmp(mode, "w") == 0) + imode = O_WRONLY; + else if (strcmp(mode, "rw") == 0) + imode = O_RDWR; + else { + PyErr_SetString(OSSAudioError, "mode must be 'r', 'w', or 'rw'"); + return NULL; + } + + /* Open the correct device: either the 'device' argument, + or the AUDIODEV environment variable, or "/dev/dsp". */ + if (devicename == NULL) { /* called with one arg */ + devicename = getenv("AUDIODEV"); + if (devicename == NULL) /* $AUDIODEV not set */ + devicename = "/dev/dsp"; + } + + /* Open with O_NONBLOCK to avoid hanging on devices that only allow + one open at a time. This does *not* affect later I/O; OSS + provides a special ioctl() for non-blocking read/write, which is + exposed via oss_nonblock() below. */ + if ((fd = open(devicename, imode|O_NONBLOCK)) == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); + return NULL; + } + + /* And (try to) put it back in blocking mode so we get the + expected write() semantics. */ + if (fcntl(fd, F_SETFL, 0) == -1) { + close(fd); + PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); + return NULL; + } + + if (ioctl(fd, SNDCTL_DSP_GETFMTS, &afmts) == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); + return NULL; + } + /* Create and initialize the object */ + if ((self = PyObject_New(oss_audio_t, &OSSAudioType)) == NULL) { + close(fd); + return NULL; + } + self->devicename = devicename; + self->fd = fd; + self->mode = imode; + self->icount = self->ocount = 0; + self->afmts = afmts; + return self; +} + +static void +oss_dealloc(oss_audio_t *self) +{ + /* if already closed, don't reclose it */ + if (self->fd != -1) + close(self->fd); + PyObject_Del(self); +} + + +/* ---------------------------------------------------------------------- + * Mixer object initialization/deallocation + */ + +static oss_mixer_t * +newossmixerobject(PyObject *arg) +{ + char *devicename = NULL; + int fd; + oss_mixer_t *self; + + if (!PyArg_ParseTuple(arg, "|s", &devicename)) { + return NULL; + } + + if (devicename == NULL) { + devicename = getenv("MIXERDEV"); + if (devicename == NULL) /* MIXERDEV not set */ + devicename = "/dev/mixer"; + } + + if ((fd = open(devicename, O_RDWR)) == -1) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, devicename); + return NULL; + } + + if ((self = PyObject_New(oss_mixer_t, &OSSMixerType)) == NULL) { + close(fd); + return NULL; + } + + self->fd = fd; + + return self; +} + +static void +oss_mixer_dealloc(oss_mixer_t *self) +{ + /* if already closed, don't reclose it */ + if (self->fd != -1) + close(self->fd); + PyObject_Del(self); +} + + +/* Methods to wrap the OSS ioctls. The calling convention is pretty + simple: + nonblock() -> ioctl(fd, SNDCTL_DSP_NONBLOCK) + fmt = setfmt(fmt) -> ioctl(fd, SNDCTL_DSP_SETFMT, &fmt) + etc. +*/ + + +/* ---------------------------------------------------------------------- + * Helper functions + */ + +/* _do_ioctl_1() is a private helper function used for the OSS ioctls -- + SNDCTL_DSP_{SETFMT,CHANNELS,SPEED} -- that that are called from C + like this: + ioctl(fd, SNDCTL_DSP_cmd, &arg) + + where arg is the value to set, and on return the driver sets arg to + the value that was actually set. Mapping this to Python is obvious: + arg = dsp.xxx(arg) +*/ +static PyObject * +_do_ioctl_1(int fd, PyObject *args, char *fname, int cmd) +{ + char argfmt[33] = "i:"; + int arg; + + assert(strlen(fname) <= 30); + strcat(argfmt, fname); + if (!PyArg_ParseTuple(args, argfmt, &arg)) + return NULL; + + if (ioctl(fd, cmd, &arg) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + return PyInt_FromLong(arg); +} + + +/* _do_ioctl_1_internal() is a wrapper for ioctls that take no inputs + but return an output -- ie. we need to pass a pointer to a local C + variable so the driver can write its output there, but from Python + all we see is the return value. For example, + SOUND_MIXER_READ_DEVMASK returns a bitmask of available mixer + devices, but does not use the value of the parameter passed-in in any + way. +*/ +static PyObject * +_do_ioctl_1_internal(int fd, PyObject *args, char *fname, int cmd) +{ + char argfmt[32] = ":"; + int arg = 0; + + assert(strlen(fname) <= 30); + strcat(argfmt, fname); + if (!PyArg_ParseTuple(args, argfmt, &arg)) + return NULL; + + if (ioctl(fd, cmd, &arg) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + return PyInt_FromLong(arg); +} + + + +/* _do_ioctl_0() is a private helper for the no-argument ioctls: + SNDCTL_DSP_{SYNC,RESET,POST}. */ +static PyObject * +_do_ioctl_0(int fd, PyObject *args, char *fname, int cmd) +{ + char argfmt[32] = ":"; + int rv; + + assert(strlen(fname) <= 30); + strcat(argfmt, fname); + if (!PyArg_ParseTuple(args, argfmt)) + return NULL; + + /* According to hannu@opensound.com, all three of the ioctls that + use this function can block, so release the GIL. This is + especially important for SYNC, which can block for several + seconds. */ + Py_BEGIN_ALLOW_THREADS + rv = ioctl(fd, cmd, 0); + Py_END_ALLOW_THREADS + + if (rv == -1) + return PyErr_SetFromErrno(PyExc_IOError); + Py_INCREF(Py_None); + return Py_None; +} + + +/* ---------------------------------------------------------------------- + * Methods of DSP objects (OSSAudioType) + */ + +static PyObject * +oss_nonblock(oss_audio_t *self, PyObject *unused) +{ + /* Hmmm: it doesn't appear to be possible to return to blocking + mode once we're in non-blocking mode! */ + if (ioctl(self->fd, SNDCTL_DSP_NONBLOCK, NULL) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +oss_setfmt(oss_audio_t *self, PyObject *args) +{ + return _do_ioctl_1(self->fd, args, "setfmt", SNDCTL_DSP_SETFMT); +} + +static PyObject * +oss_getfmts(oss_audio_t *self, PyObject *unused) +{ + int mask; + if (ioctl(self->fd, SNDCTL_DSP_GETFMTS, &mask) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + return PyInt_FromLong(mask); +} + +static PyObject * +oss_channels(oss_audio_t *self, PyObject *args) +{ + return _do_ioctl_1(self->fd, args, "channels", SNDCTL_DSP_CHANNELS); +} + +static PyObject * +oss_speed(oss_audio_t *self, PyObject *args) +{ + return _do_ioctl_1(self->fd, args, "speed", SNDCTL_DSP_SPEED); +} + +static PyObject * +oss_sync(oss_audio_t *self, PyObject *args) +{ + return _do_ioctl_0(self->fd, args, "sync", SNDCTL_DSP_SYNC); +} + +static PyObject * +oss_reset(oss_audio_t *self, PyObject *args) +{ + return _do_ioctl_0(self->fd, args, "reset", SNDCTL_DSP_RESET); +} + +static PyObject * +oss_post(oss_audio_t *self, PyObject *args) +{ + return _do_ioctl_0(self->fd, args, "post", SNDCTL_DSP_POST); +} + + +/* Regular file methods: read(), write(), close(), etc. as well + as one convenience method, writeall(). */ + +static PyObject * +oss_read(oss_audio_t *self, PyObject *args) +{ + int size, count; + char *cp; + PyObject *rv; + + if (!PyArg_ParseTuple(args, "i:read", &size)) + return NULL; + rv = PyString_FromStringAndSize(NULL, size); + if (rv == NULL) + return NULL; + cp = PyString_AS_STRING(rv); + + Py_BEGIN_ALLOW_THREADS + count = read(self->fd, cp, size); + Py_END_ALLOW_THREADS + + if (count < 0) { + PyErr_SetFromErrno(PyExc_IOError); + Py_DECREF(rv); + return NULL; + } + self->icount += count; + _PyString_Resize(&rv, count); + return rv; +} + +static PyObject * +oss_write(oss_audio_t *self, PyObject *args) +{ + char *cp; + int rv, size; + + if (!PyArg_ParseTuple(args, "s#:write", &cp, &size)) { + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + rv = write(self->fd, cp, size); + Py_END_ALLOW_THREADS + + if (rv == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } else { + self->ocount += rv; + } + return PyInt_FromLong(rv); +} + +static PyObject * +oss_writeall(oss_audio_t *self, PyObject *args) +{ + char *cp; + int rv, size; + fd_set write_set_fds; + int select_rv; + + /* NB. writeall() is only useful in non-blocking mode: according to + Guenter Geiger <geiger@xdv.org> on the linux-audio-dev list + (http://eca.cx/lad/2002/11/0380.html), OSS guarantees that + write() in blocking mode consumes the whole buffer. In blocking + mode, the behaviour of write() and writeall() from Python is + indistinguishable. */ + + if (!PyArg_ParseTuple(args, "s#:write", &cp, &size)) + return NULL; + + /* use select to wait for audio device to be available */ + FD_ZERO(&write_set_fds); + FD_SET(self->fd, &write_set_fds); + + while (size > 0) { + Py_BEGIN_ALLOW_THREADS + select_rv = select(self->fd+1, NULL, &write_set_fds, NULL, NULL); + Py_END_ALLOW_THREADS + assert(select_rv != 0); /* no timeout, can't expire */ + if (select_rv == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + Py_BEGIN_ALLOW_THREADS + rv = write(self->fd, cp, size); + Py_END_ALLOW_THREADS + if (rv == -1) { + if (errno == EAGAIN) { /* buffer is full, try again */ + errno = 0; + continue; + } else /* it's a real error */ + return PyErr_SetFromErrno(PyExc_IOError); + } else { /* wrote rv bytes */ + self->ocount += rv; + size -= rv; + cp += rv; + } + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +oss_close(oss_audio_t *self, PyObject *unused) +{ + if (self->fd >= 0) { + Py_BEGIN_ALLOW_THREADS + close(self->fd); + Py_END_ALLOW_THREADS + self->fd = -1; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +oss_fileno(oss_audio_t *self, PyObject *unused) +{ + return PyInt_FromLong(self->fd); +} + + +/* Convenience methods: these generally wrap a couple of ioctls into one + common task. */ + +static PyObject * +oss_setparameters(oss_audio_t *self, PyObject *args) +{ + int wanted_fmt, wanted_channels, wanted_rate, strict=0; + int fmt, channels, rate; + PyObject * rv; /* return tuple (fmt, channels, rate) */ + + if (!PyArg_ParseTuple(args, "iii|i:setparameters", + &wanted_fmt, &wanted_channels, &wanted_rate, + &strict)) + return NULL; + + fmt = wanted_fmt; + if (ioctl(self->fd, SNDCTL_DSP_SETFMT, &fmt) == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } + if (strict && fmt != wanted_fmt) { + return PyErr_Format + (OSSAudioError, + "unable to set requested format (wanted %d, got %d)", + wanted_fmt, fmt); + } + + channels = wanted_channels; + if (ioctl(self->fd, SNDCTL_DSP_CHANNELS, &channels) == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } + if (strict && channels != wanted_channels) { + return PyErr_Format + (OSSAudioError, + "unable to set requested channels (wanted %d, got %d)", + wanted_channels, channels); + } + + rate = wanted_rate; + if (ioctl(self->fd, SNDCTL_DSP_SPEED, &rate) == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } + if (strict && rate != wanted_rate) { + return PyErr_Format + (OSSAudioError, + "unable to set requested rate (wanted %d, got %d)", + wanted_rate, rate); + } + + /* Construct the return value: a (fmt, channels, rate) tuple that + tells what the audio hardware was actually set to. */ + rv = PyTuple_New(3); + if (rv == NULL) + return NULL; + PyTuple_SET_ITEM(rv, 0, PyInt_FromLong(fmt)); + PyTuple_SET_ITEM(rv, 1, PyInt_FromLong(channels)); + PyTuple_SET_ITEM(rv, 2, PyInt_FromLong(rate)); + return rv; +} + +static int +_ssize(oss_audio_t *self, int *nchannels, int *ssize) +{ + int fmt; + + fmt = 0; + if (ioctl(self->fd, SNDCTL_DSP_SETFMT, &fmt) < 0) + return -errno; + + switch (fmt) { + case AFMT_MU_LAW: + case AFMT_A_LAW: + case AFMT_U8: + case AFMT_S8: + *ssize = 1; /* 8 bit formats: 1 byte */ + break; + case AFMT_S16_LE: + case AFMT_S16_BE: + case AFMT_U16_LE: + case AFMT_U16_BE: + *ssize = 2; /* 16 bit formats: 2 byte */ + break; + case AFMT_MPEG: + case AFMT_IMA_ADPCM: + default: + return -EOPNOTSUPP; + } + if (ioctl(self->fd, SNDCTL_DSP_CHANNELS, nchannels) < 0) + return -errno; + return 0; +} + + +/* bufsize returns the size of the hardware audio buffer in number + of samples */ +static PyObject * +oss_bufsize(oss_audio_t *self, PyObject *unused) +{ + audio_buf_info ai; + int nchannels=0, ssize=0; + + if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyInt_FromLong((ai.fragstotal * ai.fragsize) / (nchannels * ssize)); +} + +/* obufcount returns the number of samples that are available in the + hardware for playing */ +static PyObject * +oss_obufcount(oss_audio_t *self, PyObject *unused) +{ + audio_buf_info ai; + int nchannels=0, ssize=0; + + if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyInt_FromLong((ai.fragstotal * ai.fragsize - ai.bytes) / + (ssize * nchannels)); +} + +/* obufcount returns the number of samples that can be played without + blocking */ +static PyObject * +oss_obuffree(oss_audio_t *self, PyObject *unused) +{ + audio_buf_info ai; + int nchannels=0, ssize=0; + + if (_ssize(self, &nchannels, &ssize) < 0 || !nchannels || !ssize) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + if (ioctl(self->fd, SNDCTL_DSP_GETOSPACE, &ai) < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyInt_FromLong(ai.bytes / (ssize * nchannels)); +} + +static PyObject * +oss_getptr(oss_audio_t *self, PyObject *unused) +{ + count_info info; + int req; + + if (self->mode == O_RDONLY) + req = SNDCTL_DSP_GETIPTR; + else + req = SNDCTL_DSP_GETOPTR; + if (ioctl(self->fd, req, &info) == -1) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return Py_BuildValue("iii", info.bytes, info.blocks, info.ptr); +} + + +/* ---------------------------------------------------------------------- + * Methods of mixer objects (OSSMixerType) + */ + +static PyObject * +oss_mixer_close(oss_mixer_t *self, PyObject *unused) +{ + if (self->fd >= 0) { + close(self->fd); + self->fd = -1; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +oss_mixer_fileno(oss_mixer_t *self, PyObject *unused) +{ + return PyInt_FromLong(self->fd); +} + +/* Simple mixer interface methods */ + +static PyObject * +oss_mixer_controls(oss_mixer_t *self, PyObject *args) +{ + return _do_ioctl_1_internal(self->fd, args, "controls", + SOUND_MIXER_READ_DEVMASK); +} + +static PyObject * +oss_mixer_stereocontrols(oss_mixer_t *self, PyObject *args) +{ + return _do_ioctl_1_internal(self->fd, args, "stereocontrols", + SOUND_MIXER_READ_STEREODEVS); +} + +static PyObject * +oss_mixer_reccontrols(oss_mixer_t *self, PyObject *args) +{ + return _do_ioctl_1_internal(self->fd, args, "reccontrols", + SOUND_MIXER_READ_RECMASK); +} + +static PyObject * +oss_mixer_get(oss_mixer_t *self, PyObject *args) +{ + int channel, volume; + + /* Can't use _do_ioctl_1 because of encoded arg thingy. */ + if (!PyArg_ParseTuple(args, "i:get", &channel)) + return NULL; + + if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) { + PyErr_SetString(OSSAudioError, "Invalid mixer channel specified."); + return NULL; + } + + if (ioctl(self->fd, MIXER_READ(channel), &volume) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8); +} + +static PyObject * +oss_mixer_set(oss_mixer_t *self, PyObject *args) +{ + int channel, volume, leftVol, rightVol; + + /* Can't use _do_ioctl_1 because of encoded arg thingy. */ + if (!PyArg_ParseTuple(args, "i(ii):set", &channel, &leftVol, &rightVol)) + return NULL; + + if (channel < 0 || channel > SOUND_MIXER_NRDEVICES) { + PyErr_SetString(OSSAudioError, "Invalid mixer channel specified."); + return NULL; + } + + if (leftVol < 0 || rightVol < 0 || leftVol > 100 || rightVol > 100) { + PyErr_SetString(OSSAudioError, "Volumes must be between 0 and 100."); + return NULL; + } + + volume = (rightVol << 8) | leftVol; + + if (ioctl(self->fd, MIXER_WRITE(channel), &volume) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + + return Py_BuildValue("(ii)", volume & 0xff, (volume & 0xff00) >> 8); +} + +static PyObject * +oss_mixer_get_recsrc(oss_mixer_t *self, PyObject *args) +{ + return _do_ioctl_1_internal(self->fd, args, "get_recsrc", + SOUND_MIXER_READ_RECSRC); +} + +static PyObject * +oss_mixer_set_recsrc(oss_mixer_t *self, PyObject *args) +{ + return _do_ioctl_1(self->fd, args, "set_recsrc", + SOUND_MIXER_WRITE_RECSRC); +} + + +/* ---------------------------------------------------------------------- + * Method tables and other bureaucracy + */ + +static PyMethodDef oss_methods[] = { + /* Regular file methods */ + { "read", (PyCFunction)oss_read, METH_VARARGS }, + { "write", (PyCFunction)oss_write, METH_VARARGS }, + { "writeall", (PyCFunction)oss_writeall, METH_VARARGS }, + { "close", (PyCFunction)oss_close, METH_NOARGS }, + { "fileno", (PyCFunction)oss_fileno, METH_NOARGS }, + + /* Simple ioctl wrappers */ + { "nonblock", (PyCFunction)oss_nonblock, METH_NOARGS }, + { "setfmt", (PyCFunction)oss_setfmt, METH_VARARGS }, + { "getfmts", (PyCFunction)oss_getfmts, METH_NOARGS }, + { "channels", (PyCFunction)oss_channels, METH_VARARGS }, + { "speed", (PyCFunction)oss_speed, METH_VARARGS }, + { "sync", (PyCFunction)oss_sync, METH_VARARGS }, + { "reset", (PyCFunction)oss_reset, METH_VARARGS }, + { "post", (PyCFunction)oss_post, METH_VARARGS }, + + /* Convenience methods -- wrap a couple of ioctls together */ + { "setparameters", (PyCFunction)oss_setparameters, METH_VARARGS }, + { "bufsize", (PyCFunction)oss_bufsize, METH_NOARGS }, + { "obufcount", (PyCFunction)oss_obufcount, METH_NOARGS }, + { "obuffree", (PyCFunction)oss_obuffree, METH_NOARGS }, + { "getptr", (PyCFunction)oss_getptr, METH_NOARGS }, + + /* Aliases for backwards compatibility */ + { "flush", (PyCFunction)oss_sync, METH_VARARGS }, + + { NULL, NULL} /* sentinel */ +}; + +static PyMethodDef oss_mixer_methods[] = { + /* Regular file method - OSS mixers are ioctl-only interface */ + { "close", (PyCFunction)oss_mixer_close, METH_NOARGS }, + { "fileno", (PyCFunction)oss_mixer_fileno, METH_NOARGS }, + + /* Simple ioctl wrappers */ + { "controls", (PyCFunction)oss_mixer_controls, METH_VARARGS }, + { "stereocontrols", (PyCFunction)oss_mixer_stereocontrols, METH_VARARGS}, + { "reccontrols", (PyCFunction)oss_mixer_reccontrols, METH_VARARGS}, + { "get", (PyCFunction)oss_mixer_get, METH_VARARGS }, + { "set", (PyCFunction)oss_mixer_set, METH_VARARGS }, + { "get_recsrc", (PyCFunction)oss_mixer_get_recsrc, METH_VARARGS }, + { "set_recsrc", (PyCFunction)oss_mixer_set_recsrc, METH_VARARGS }, + + { NULL, NULL} +}; + +static PyObject * +oss_getattr(oss_audio_t *self, char *name) +{ + PyObject * rval = NULL; + if (strcmp(name, "closed") == 0) { + rval = (self->fd == -1) ? Py_True : Py_False; + Py_INCREF(rval); + } + else if (strcmp(name, "name") == 0) { + rval = PyString_FromString(self->devicename); + } + else if (strcmp(name, "mode") == 0) { + /* No need for a "default" in this switch: from newossobject(), + self->mode can only be one of these three values. */ + switch(self->mode) { + case O_RDONLY: + rval = PyString_FromString("r"); + break; + case O_RDWR: + rval = PyString_FromString("rw"); + break; + case O_WRONLY: + rval = PyString_FromString("w"); + break; + } + } + else { + rval = Py_FindMethod(oss_methods, (PyObject *)self, name); + } + return rval; +} + +static PyObject * +oss_mixer_getattr(oss_mixer_t *self, char *name) +{ + return Py_FindMethod(oss_mixer_methods, (PyObject *)self, name); +} + +static PyTypeObject OSSAudioType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "ossaudiodev.oss_audio_device", /*tp_name*/ + sizeof(oss_audio_t), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)oss_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)oss_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyTypeObject OSSMixerType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "ossaudiodev.oss_mixer_device", /*tp_name*/ + sizeof(oss_mixer_t), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)oss_mixer_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)oss_mixer_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + + +static PyObject * +ossopen(PyObject *self, PyObject *args) +{ + return (PyObject *)newossobject(args); +} + +static PyObject * +ossopenmixer(PyObject *self, PyObject *args) +{ + return (PyObject *)newossmixerobject(args); +} + +static PyMethodDef ossaudiodev_methods[] = { + { "open", ossopen, METH_VARARGS }, + { "openmixer", ossopenmixer, METH_VARARGS }, + { 0, 0 }, +}; + + +#define _EXPORT_INT(mod, name) \ + if (PyModule_AddIntConstant(mod, #name, (long) (name)) == -1) return; + + +static char *control_labels[] = SOUND_DEVICE_LABELS; +static char *control_names[] = SOUND_DEVICE_NAMES; + + +static int +build_namelists (PyObject *module) +{ + PyObject *labels; + PyObject *names; + PyObject *s; + int num_controls; + int i; + + num_controls = sizeof(control_labels) / sizeof(control_labels[0]); + assert(num_controls == sizeof(control_names) / sizeof(control_names[0])); + + labels = PyList_New(num_controls); + names = PyList_New(num_controls); + if (labels == NULL || names == NULL) + goto error2; + for (i = 0; i < num_controls; i++) { + s = PyString_FromString(control_labels[i]); + if (s == NULL) + goto error2; + PyList_SET_ITEM(labels, i, s); + + s = PyString_FromString(control_names[i]); + if (s == NULL) + goto error2; + PyList_SET_ITEM(names, i, s); + } + + if (PyModule_AddObject(module, "control_labels", labels) == -1) + goto error2; + if (PyModule_AddObject(module, "control_names", names) == -1) + goto error1; + + return 0; + +error2: + Py_XDECREF(labels); +error1: + Py_XDECREF(names); + return -1; +} + + +void +initossaudiodev(void) +{ + PyObject *m; + + m = Py_InitModule("ossaudiodev", ossaudiodev_methods); + if (m == NULL) + return; + + OSSAudioError = PyErr_NewException("ossaudiodev.OSSAudioError", + NULL, NULL); + if (OSSAudioError) { + /* Each call to PyModule_AddObject decrefs it; compensate: */ + Py_INCREF(OSSAudioError); + Py_INCREF(OSSAudioError); + PyModule_AddObject(m, "error", OSSAudioError); + PyModule_AddObject(m, "OSSAudioError", OSSAudioError); + } + + /* Build 'control_labels' and 'control_names' lists and add them + to the module. */ + if (build_namelists(m) == -1) /* XXX what to do here? */ + return; + + /* Expose the audio format numbers -- essential! */ + _EXPORT_INT(m, AFMT_QUERY); + _EXPORT_INT(m, AFMT_MU_LAW); + _EXPORT_INT(m, AFMT_A_LAW); + _EXPORT_INT(m, AFMT_IMA_ADPCM); + _EXPORT_INT(m, AFMT_U8); + _EXPORT_INT(m, AFMT_S16_LE); + _EXPORT_INT(m, AFMT_S16_BE); + _EXPORT_INT(m, AFMT_S8); + _EXPORT_INT(m, AFMT_U16_LE); + _EXPORT_INT(m, AFMT_U16_BE); + _EXPORT_INT(m, AFMT_MPEG); +#ifdef AFMT_AC3 + _EXPORT_INT(m, AFMT_AC3); +#endif +#ifdef AFMT_S16_NE + _EXPORT_INT(m, AFMT_S16_NE); +#endif +#ifdef AFMT_U16_NE + _EXPORT_INT(m, AFMT_U16_NE); +#endif +#ifdef AFMT_S32_LE + _EXPORT_INT(m, AFMT_S32_LE); +#endif +#ifdef AFMT_S32_BE + _EXPORT_INT(m, AFMT_S32_BE); +#endif +#ifdef AFMT_MPEG + _EXPORT_INT(m, AFMT_MPEG); +#endif + + /* Expose the sound mixer device numbers. */ + _EXPORT_INT(m, SOUND_MIXER_NRDEVICES); + _EXPORT_INT(m, SOUND_MIXER_VOLUME); + _EXPORT_INT(m, SOUND_MIXER_BASS); + _EXPORT_INT(m, SOUND_MIXER_TREBLE); + _EXPORT_INT(m, SOUND_MIXER_SYNTH); + _EXPORT_INT(m, SOUND_MIXER_PCM); + _EXPORT_INT(m, SOUND_MIXER_SPEAKER); + _EXPORT_INT(m, SOUND_MIXER_LINE); + _EXPORT_INT(m, SOUND_MIXER_MIC); + _EXPORT_INT(m, SOUND_MIXER_CD); + _EXPORT_INT(m, SOUND_MIXER_IMIX); + _EXPORT_INT(m, SOUND_MIXER_ALTPCM); + _EXPORT_INT(m, SOUND_MIXER_RECLEV); + _EXPORT_INT(m, SOUND_MIXER_IGAIN); + _EXPORT_INT(m, SOUND_MIXER_OGAIN); + _EXPORT_INT(m, SOUND_MIXER_LINE1); + _EXPORT_INT(m, SOUND_MIXER_LINE2); + _EXPORT_INT(m, SOUND_MIXER_LINE3); +#ifdef SOUND_MIXER_DIGITAL1 + _EXPORT_INT(m, SOUND_MIXER_DIGITAL1); +#endif +#ifdef SOUND_MIXER_DIGITAL2 + _EXPORT_INT(m, SOUND_MIXER_DIGITAL2); +#endif +#ifdef SOUND_MIXER_DIGITAL3 + _EXPORT_INT(m, SOUND_MIXER_DIGITAL3); +#endif +#ifdef SOUND_MIXER_PHONEIN + _EXPORT_INT(m, SOUND_MIXER_PHONEIN); +#endif +#ifdef SOUND_MIXER_PHONEOUT + _EXPORT_INT(m, SOUND_MIXER_PHONEOUT); +#endif +#ifdef SOUND_MIXER_VIDEO + _EXPORT_INT(m, SOUND_MIXER_VIDEO); +#endif +#ifdef SOUND_MIXER_RADIO + _EXPORT_INT(m, SOUND_MIXER_RADIO); +#endif +#ifdef SOUND_MIXER_MONITOR + _EXPORT_INT(m, SOUND_MIXER_MONITOR); +#endif + + /* Expose all the ioctl numbers for masochists who like to do this + stuff directly. */ + _EXPORT_INT(m, SNDCTL_COPR_HALT); + _EXPORT_INT(m, SNDCTL_COPR_LOAD); + _EXPORT_INT(m, SNDCTL_COPR_RCODE); + _EXPORT_INT(m, SNDCTL_COPR_RCVMSG); + _EXPORT_INT(m, SNDCTL_COPR_RDATA); + _EXPORT_INT(m, SNDCTL_COPR_RESET); + _EXPORT_INT(m, SNDCTL_COPR_RUN); + _EXPORT_INT(m, SNDCTL_COPR_SENDMSG); + _EXPORT_INT(m, SNDCTL_COPR_WCODE); + _EXPORT_INT(m, SNDCTL_COPR_WDATA); +#ifdef SNDCTL_DSP_BIND_CHANNEL + _EXPORT_INT(m, SNDCTL_DSP_BIND_CHANNEL); +#endif + _EXPORT_INT(m, SNDCTL_DSP_CHANNELS); + _EXPORT_INT(m, SNDCTL_DSP_GETBLKSIZE); + _EXPORT_INT(m, SNDCTL_DSP_GETCAPS); +#ifdef SNDCTL_DSP_GETCHANNELMASK + _EXPORT_INT(m, SNDCTL_DSP_GETCHANNELMASK); +#endif + _EXPORT_INT(m, SNDCTL_DSP_GETFMTS); + _EXPORT_INT(m, SNDCTL_DSP_GETIPTR); + _EXPORT_INT(m, SNDCTL_DSP_GETISPACE); +#ifdef SNDCTL_DSP_GETODELAY + _EXPORT_INT(m, SNDCTL_DSP_GETODELAY); +#endif + _EXPORT_INT(m, SNDCTL_DSP_GETOPTR); + _EXPORT_INT(m, SNDCTL_DSP_GETOSPACE); +#ifdef SNDCTL_DSP_GETSPDIF + _EXPORT_INT(m, SNDCTL_DSP_GETSPDIF); +#endif + _EXPORT_INT(m, SNDCTL_DSP_GETTRIGGER); + _EXPORT_INT(m, SNDCTL_DSP_MAPINBUF); + _EXPORT_INT(m, SNDCTL_DSP_MAPOUTBUF); + _EXPORT_INT(m, SNDCTL_DSP_NONBLOCK); + _EXPORT_INT(m, SNDCTL_DSP_POST); +#ifdef SNDCTL_DSP_PROFILE + _EXPORT_INT(m, SNDCTL_DSP_PROFILE); +#endif + _EXPORT_INT(m, SNDCTL_DSP_RESET); + _EXPORT_INT(m, SNDCTL_DSP_SAMPLESIZE); + _EXPORT_INT(m, SNDCTL_DSP_SETDUPLEX); + _EXPORT_INT(m, SNDCTL_DSP_SETFMT); + _EXPORT_INT(m, SNDCTL_DSP_SETFRAGMENT); +#ifdef SNDCTL_DSP_SETSPDIF + _EXPORT_INT(m, SNDCTL_DSP_SETSPDIF); +#endif + _EXPORT_INT(m, SNDCTL_DSP_SETSYNCRO); + _EXPORT_INT(m, SNDCTL_DSP_SETTRIGGER); + _EXPORT_INT(m, SNDCTL_DSP_SPEED); + _EXPORT_INT(m, SNDCTL_DSP_STEREO); + _EXPORT_INT(m, SNDCTL_DSP_SUBDIVIDE); + _EXPORT_INT(m, SNDCTL_DSP_SYNC); + _EXPORT_INT(m, SNDCTL_FM_4OP_ENABLE); + _EXPORT_INT(m, SNDCTL_FM_LOAD_INSTR); + _EXPORT_INT(m, SNDCTL_MIDI_INFO); + _EXPORT_INT(m, SNDCTL_MIDI_MPUCMD); + _EXPORT_INT(m, SNDCTL_MIDI_MPUMODE); + _EXPORT_INT(m, SNDCTL_MIDI_PRETIME); + _EXPORT_INT(m, SNDCTL_SEQ_CTRLRATE); + _EXPORT_INT(m, SNDCTL_SEQ_GETINCOUNT); + _EXPORT_INT(m, SNDCTL_SEQ_GETOUTCOUNT); +#ifdef SNDCTL_SEQ_GETTIME + _EXPORT_INT(m, SNDCTL_SEQ_GETTIME); +#endif + _EXPORT_INT(m, SNDCTL_SEQ_NRMIDIS); + _EXPORT_INT(m, SNDCTL_SEQ_NRSYNTHS); + _EXPORT_INT(m, SNDCTL_SEQ_OUTOFBAND); + _EXPORT_INT(m, SNDCTL_SEQ_PANIC); + _EXPORT_INT(m, SNDCTL_SEQ_PERCMODE); + _EXPORT_INT(m, SNDCTL_SEQ_RESET); + _EXPORT_INT(m, SNDCTL_SEQ_RESETSAMPLES); + _EXPORT_INT(m, SNDCTL_SEQ_SYNC); + _EXPORT_INT(m, SNDCTL_SEQ_TESTMIDI); + _EXPORT_INT(m, SNDCTL_SEQ_THRESHOLD); +#ifdef SNDCTL_SYNTH_CONTROL + _EXPORT_INT(m, SNDCTL_SYNTH_CONTROL); +#endif +#ifdef SNDCTL_SYNTH_ID + _EXPORT_INT(m, SNDCTL_SYNTH_ID); +#endif + _EXPORT_INT(m, SNDCTL_SYNTH_INFO); + _EXPORT_INT(m, SNDCTL_SYNTH_MEMAVL); +#ifdef SNDCTL_SYNTH_REMOVESAMPLE + _EXPORT_INT(m, SNDCTL_SYNTH_REMOVESAMPLE); +#endif + _EXPORT_INT(m, SNDCTL_TMR_CONTINUE); + _EXPORT_INT(m, SNDCTL_TMR_METRONOME); + _EXPORT_INT(m, SNDCTL_TMR_SELECT); + _EXPORT_INT(m, SNDCTL_TMR_SOURCE); + _EXPORT_INT(m, SNDCTL_TMR_START); + _EXPORT_INT(m, SNDCTL_TMR_STOP); + _EXPORT_INT(m, SNDCTL_TMR_TEMPO); + _EXPORT_INT(m, SNDCTL_TMR_TIMEBASE); +} diff --git a/sys/src/cmd/python/Modules/parsermodule.c b/sys/src/cmd/python/Modules/parsermodule.c new file mode 100644 index 000000000..e33197e39 --- /dev/null +++ b/sys/src/cmd/python/Modules/parsermodule.c @@ -0,0 +1,3279 @@ +/* parsermodule.c + * + * Copyright 1995-1996 by Fred L. Drake, Jr. and Virginia Polytechnic + * Institute and State University, Blacksburg, Virginia, USA. + * Portions copyright 1991-1995 by Stichting Mathematisch Centrum, + * Amsterdam, The Netherlands. Copying is permitted under the terms + * associated with the main Python distribution, with the additional + * restriction that this additional notice be included and maintained + * on all distributed copies. + * + * This module serves to replace the original parser module written + * by Guido. The functionality is not matched precisely, but the + * original may be implemented on top of this. This is desirable + * since the source of the text to be parsed is now divorced from + * this interface. + * + * Unlike the prior interface, the ability to give a parse tree + * produced by Python code as a tuple to the compiler is enabled by + * this module. See the documentation for more details. + * + * I've added some annotations that help with the lint code-checking + * program, but they're not complete by a long shot. The real errors + * that lint detects are gone, but there are still warnings with + * Py_[X]DECREF() and Py_[X]INCREF() macros. The lint annotations + * look like "NOTE(...)". + */ + +#include "Python.h" /* general Python API */ +#include "graminit.h" /* symbols defined in the grammar */ +#include "node.h" /* internal parser structure */ +#include "errcode.h" /* error codes for PyNode_*() */ +#include "token.h" /* token definitions */ + /* ISTERMINAL() / ISNONTERMINAL() */ +#include "compile.h" /* PyNode_Compile() */ + +#ifdef lint +#include <note.h> +#else +#define NOTE(x) +#endif + +/* String constants used to initialize module attributes. + * + */ +static char parser_copyright_string[] = +"Copyright 1995-1996 by Virginia Polytechnic Institute & State\n\ +University, Blacksburg, Virginia, USA, and Fred L. Drake, Jr., Reston,\n\ +Virginia, USA. Portions copyright 1991-1995 by Stichting Mathematisch\n\ +Centrum, Amsterdam, The Netherlands."; + + +PyDoc_STRVAR(parser_doc_string, +"This is an interface to Python's internal parser."); + +static char parser_version_string[] = "0.5"; + + +typedef PyObject* (*SeqMaker) (Py_ssize_t length); +typedef int (*SeqInserter) (PyObject* sequence, + Py_ssize_t index, + PyObject* element); + +/* The function below is copyrighted by Stichting Mathematisch Centrum. The + * original copyright statement is included below, and continues to apply + * in full to the function immediately following. All other material is + * original, copyrighted by Fred L. Drake, Jr. and Virginia Polytechnic + * Institute and State University. Changes were made to comply with the + * new naming conventions. Added arguments to provide support for creating + * lists as well as tuples, and optionally including the line numbers. + */ + + +static PyObject* +node2tuple(node *n, /* node to convert */ + SeqMaker mkseq, /* create sequence */ + SeqInserter addelem, /* func. to add elem. in seq. */ + int lineno) /* include line numbers? */ +{ + if (n == NULL) { + Py_INCREF(Py_None); + return (Py_None); + } + if (ISNONTERMINAL(TYPE(n))) { + int i; + PyObject *v; + PyObject *w; + + v = mkseq(1 + NCH(n) + (TYPE(n) == encoding_decl)); + if (v == NULL) + return (v); + w = PyInt_FromLong(TYPE(n)); + if (w == NULL) { + Py_DECREF(v); + return ((PyObject*) NULL); + } + (void) addelem(v, 0, w); + for (i = 0; i < NCH(n); i++) { + w = node2tuple(CHILD(n, i), mkseq, addelem, lineno); + if (w == NULL) { + Py_DECREF(v); + return ((PyObject*) NULL); + } + (void) addelem(v, i+1, w); + } + + if (TYPE(n) == encoding_decl) + (void) addelem(v, i+1, PyString_FromString(STR(n))); + return (v); + } + else if (ISTERMINAL(TYPE(n))) { + PyObject *result = mkseq(2 + lineno); + if (result != NULL) { + (void) addelem(result, 0, PyInt_FromLong(TYPE(n))); + (void) addelem(result, 1, PyString_FromString(STR(n))); + if (lineno == 1) + (void) addelem(result, 2, PyInt_FromLong(n->n_lineno)); + } + return (result); + } + else { + PyErr_SetString(PyExc_SystemError, + "unrecognized parse tree node type"); + return ((PyObject*) NULL); + } +} +/* + * End of material copyrighted by Stichting Mathematisch Centrum. + */ + + + +/* There are two types of intermediate objects we're interested in: + * 'eval' and 'exec' types. These constants can be used in the st_type + * field of the object type to identify which any given object represents. + * These should probably go in an external header to allow other extensions + * to use them, but then, we really should be using C++ too. ;-) + */ + +#define PyST_EXPR 1 +#define PyST_SUITE 2 + + +/* These are the internal objects and definitions required to implement the + * ST type. Most of the internal names are more reminiscent of the 'old' + * naming style, but the code uses the new naming convention. + */ + +static PyObject* +parser_error = 0; + + +typedef struct { + PyObject_HEAD /* standard object header */ + node* st_node; /* the node* returned by the parser */ + int st_type; /* EXPR or SUITE ? */ +} PyST_Object; + + +static void parser_free(PyST_Object *st); +static int parser_compare(PyST_Object *left, PyST_Object *right); +static PyObject *parser_getattr(PyObject *self, char *name); + + +static +PyTypeObject PyST_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "parser.st", /* tp_name */ + (int) sizeof(PyST_Object), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)parser_free, /* tp_dealloc */ + 0, /* tp_print */ + parser_getattr, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)parser_compare, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + + /* Functions to access object as input/output buffer */ + 0, /* tp_as_buffer */ + + Py_TPFLAGS_DEFAULT, /* tp_flags */ + + /* __doc__ */ + "Intermediate representation of a Python parse tree." +}; /* PyST_Type */ + + +static int +parser_compare_nodes(node *left, node *right) +{ + int j; + + if (TYPE(left) < TYPE(right)) + return (-1); + + if (TYPE(right) < TYPE(left)) + return (1); + + if (ISTERMINAL(TYPE(left))) + return (strcmp(STR(left), STR(right))); + + if (NCH(left) < NCH(right)) + return (-1); + + if (NCH(right) < NCH(left)) + return (1); + + for (j = 0; j < NCH(left); ++j) { + int v = parser_compare_nodes(CHILD(left, j), CHILD(right, j)); + + if (v != 0) + return (v); + } + return (0); +} + + +/* int parser_compare(PyST_Object* left, PyST_Object* right) + * + * Comparison function used by the Python operators ==, !=, <, >, <=, >= + * This really just wraps a call to parser_compare_nodes() with some easy + * checks and protection code. + * + */ +static int +parser_compare(PyST_Object *left, PyST_Object *right) +{ + if (left == right) + return (0); + + if ((left == 0) || (right == 0)) + return (-1); + + return (parser_compare_nodes(left->st_node, right->st_node)); +} + + +/* parser_newstobject(node* st) + * + * Allocates a new Python object representing an ST. This is simply the + * 'wrapper' object that holds a node* and allows it to be passed around in + * Python code. + * + */ +static PyObject* +parser_newstobject(node *st, int type) +{ + PyST_Object* o = PyObject_New(PyST_Object, &PyST_Type); + + if (o != 0) { + o->st_node = st; + o->st_type = type; + } + else { + PyNode_Free(st); + } + return ((PyObject*)o); +} + + +/* void parser_free(PyST_Object* st) + * + * This is called by a del statement that reduces the reference count to 0. + * + */ +static void +parser_free(PyST_Object *st) +{ + PyNode_Free(st->st_node); + PyObject_Del(st); +} + + +/* parser_st2tuple(PyObject* self, PyObject* args, PyObject* kw) + * + * This provides conversion from a node* to a tuple object that can be + * returned to the Python-level caller. The ST object is not modified. + * + */ +static PyObject* +parser_st2tuple(PyST_Object *self, PyObject *args, PyObject *kw) +{ + PyObject *line_option = 0; + PyObject *res = 0; + int ok; + + static char *keywords[] = {"ast", "line_info", NULL}; + + if (self == NULL) { + ok = PyArg_ParseTupleAndKeywords(args, kw, "O!|O:st2tuple", keywords, + &PyST_Type, &self, &line_option); + } + else + ok = PyArg_ParseTupleAndKeywords(args, kw, "|O:totuple", &keywords[1], + &line_option); + if (ok != 0) { + int lineno = 0; + if (line_option != NULL) { + lineno = (PyObject_IsTrue(line_option) != 0) ? 1 : 0; + } + /* + * Convert ST into a tuple representation. Use Guido's function, + * since it's known to work already. + */ + res = node2tuple(((PyST_Object*)self)->st_node, + PyTuple_New, PyTuple_SetItem, lineno); + } + return (res); +} + + +/* parser_st2list(PyObject* self, PyObject* args, PyObject* kw) + * + * This provides conversion from a node* to a list object that can be + * returned to the Python-level caller. The ST object is not modified. + * + */ +static PyObject* +parser_st2list(PyST_Object *self, PyObject *args, PyObject *kw) +{ + PyObject *line_option = 0; + PyObject *res = 0; + int ok; + + static char *keywords[] = {"ast", "line_info", NULL}; + + if (self == NULL) + ok = PyArg_ParseTupleAndKeywords(args, kw, "O!|O:st2list", keywords, + &PyST_Type, &self, &line_option); + else + ok = PyArg_ParseTupleAndKeywords(args, kw, "|O:tolist", &keywords[1], + &line_option); + if (ok) { + int lineno = 0; + if (line_option != 0) { + lineno = PyObject_IsTrue(line_option) ? 1 : 0; + } + /* + * Convert ST into a tuple representation. Use Guido's function, + * since it's known to work already. + */ + res = node2tuple(self->st_node, + PyList_New, PyList_SetItem, lineno); + } + return (res); +} + + +/* parser_compilest(PyObject* self, PyObject* args) + * + * This function creates code objects from the parse tree represented by + * the passed-in data object. An optional file name is passed in as well. + * + */ +static PyObject* +parser_compilest(PyST_Object *self, PyObject *args, PyObject *kw) +{ + PyObject* res = 0; + char* str = "<syntax-tree>"; + int ok; + + static char *keywords[] = {"ast", "filename", NULL}; + + if (self == NULL) + ok = PyArg_ParseTupleAndKeywords(args, kw, "O!|s:compilest", keywords, + &PyST_Type, &self, &str); + else + ok = PyArg_ParseTupleAndKeywords(args, kw, "|s:compile", &keywords[1], + &str); + + if (ok) + res = (PyObject *)PyNode_Compile(self->st_node, str); + + return (res); +} + + +/* PyObject* parser_isexpr(PyObject* self, PyObject* args) + * PyObject* parser_issuite(PyObject* self, PyObject* args) + * + * Checks the passed-in ST object to determine if it is an expression or + * a statement suite, respectively. The return is a Python truth value. + * + */ +static PyObject* +parser_isexpr(PyST_Object *self, PyObject *args, PyObject *kw) +{ + PyObject* res = 0; + int ok; + + static char *keywords[] = {"ast", NULL}; + + if (self == NULL) + ok = PyArg_ParseTupleAndKeywords(args, kw, "O!:isexpr", keywords, + &PyST_Type, &self); + else + ok = PyArg_ParseTupleAndKeywords(args, kw, ":isexpr", &keywords[1]); + + if (ok) { + /* Check to see if the ST represents an expression or not. */ + res = (self->st_type == PyST_EXPR) ? Py_True : Py_False; + Py_INCREF(res); + } + return (res); +} + + +static PyObject* +parser_issuite(PyST_Object *self, PyObject *args, PyObject *kw) +{ + PyObject* res = 0; + int ok; + + static char *keywords[] = {"ast", NULL}; + + if (self == NULL) + ok = PyArg_ParseTupleAndKeywords(args, kw, "O!:issuite", keywords, + &PyST_Type, &self); + else + ok = PyArg_ParseTupleAndKeywords(args, kw, ":issuite", &keywords[1]); + + if (ok) { + /* Check to see if the ST represents an expression or not. */ + res = (self->st_type == PyST_EXPR) ? Py_False : Py_True; + Py_INCREF(res); + } + return (res); +} + + +#define PUBLIC_METHOD_TYPE (METH_VARARGS|METH_KEYWORDS) + +static PyMethodDef +parser_methods[] = { + {"compile", (PyCFunction)parser_compilest, PUBLIC_METHOD_TYPE, + PyDoc_STR("Compile this ST object into a code object.")}, + {"isexpr", (PyCFunction)parser_isexpr, PUBLIC_METHOD_TYPE, + PyDoc_STR("Determines if this ST object was created from an expression.")}, + {"issuite", (PyCFunction)parser_issuite, PUBLIC_METHOD_TYPE, + PyDoc_STR("Determines if this ST object was created from a suite.")}, + {"tolist", (PyCFunction)parser_st2list, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates a list-tree representation of this ST.")}, + {"totuple", (PyCFunction)parser_st2tuple, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates a tuple-tree representation of this ST.")}, + + {NULL, NULL, 0, NULL} +}; + + +static PyObject* +parser_getattr(PyObject *self, char *name) +{ + return (Py_FindMethod(parser_methods, self, name)); +} + + +/* err_string(char* message) + * + * Sets the error string for an exception of type ParserError. + * + */ +static void +err_string(char *message) +{ + PyErr_SetString(parser_error, message); +} + + +/* PyObject* parser_do_parse(PyObject* args, int type) + * + * Internal function to actually execute the parse and return the result if + * successful or set an exception if not. + * + */ +static PyObject* +parser_do_parse(PyObject *args, PyObject *kw, char *argspec, int type) +{ + char* string = 0; + PyObject* res = 0; + + static char *keywords[] = {"source", NULL}; + + if (PyArg_ParseTupleAndKeywords(args, kw, argspec, keywords, &string)) { + node* n = PyParser_SimpleParseString(string, + (type == PyST_EXPR) + ? eval_input : file_input); + + if (n) + res = parser_newstobject(n, type); + } + return (res); +} + + +/* PyObject* parser_expr(PyObject* self, PyObject* args) + * PyObject* parser_suite(PyObject* self, PyObject* args) + * + * External interfaces to the parser itself. Which is called determines if + * the parser attempts to recognize an expression ('eval' form) or statement + * suite ('exec' form). The real work is done by parser_do_parse() above. + * + */ +static PyObject* +parser_expr(PyST_Object *self, PyObject *args, PyObject *kw) +{ + NOTE(ARGUNUSED(self)) + return (parser_do_parse(args, kw, "s:expr", PyST_EXPR)); +} + + +static PyObject* +parser_suite(PyST_Object *self, PyObject *args, PyObject *kw) +{ + NOTE(ARGUNUSED(self)) + return (parser_do_parse(args, kw, "s:suite", PyST_SUITE)); +} + + + +/* This is the messy part of the code. Conversion from a tuple to an ST + * object requires that the input tuple be valid without having to rely on + * catching an exception from the compiler. This is done to allow the + * compiler itself to remain fast, since most of its input will come from + * the parser directly, and therefore be known to be syntactically correct. + * This validation is done to ensure that we don't core dump the compile + * phase, returning an exception instead. + * + * Two aspects can be broken out in this code: creating a node tree from + * the tuple passed in, and verifying that it is indeed valid. It may be + * advantageous to expand the number of ST types to include funcdefs and + * lambdadefs to take advantage of the optimizer, recognizing those STs + * here. They are not necessary, and not quite as useful in a raw form. + * For now, let's get expressions and suites working reliably. + */ + + +static node* build_node_tree(PyObject *tuple); +static int validate_expr_tree(node *tree); +static int validate_file_input(node *tree); +static int validate_encoding_decl(node *tree); + +/* PyObject* parser_tuple2st(PyObject* self, PyObject* args) + * + * This is the public function, called from the Python code. It receives a + * single tuple object from the caller, and creates an ST object if the + * tuple can be validated. It does this by checking the first code of the + * tuple, and, if acceptable, builds the internal representation. If this + * step succeeds, the internal representation is validated as fully as + * possible with the various validate_*() routines defined below. + * + * This function must be changed if support is to be added for PyST_FRAGMENT + * ST objects. + * + */ +static PyObject* +parser_tuple2st(PyST_Object *self, PyObject *args, PyObject *kw) +{ + NOTE(ARGUNUSED(self)) + PyObject *st = 0; + PyObject *tuple; + node *tree; + + static char *keywords[] = {"sequence", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "O:sequence2st", keywords, + &tuple)) + return (0); + if (!PySequence_Check(tuple)) { + PyErr_SetString(PyExc_ValueError, + "sequence2st() requires a single sequence argument"); + return (0); + } + /* + * Convert the tree to the internal form before checking it. + */ + tree = build_node_tree(tuple); + if (tree != 0) { + int start_sym = TYPE(tree); + if (start_sym == eval_input) { + /* Might be an eval form. */ + if (validate_expr_tree(tree)) + st = parser_newstobject(tree, PyST_EXPR); + else + PyNode_Free(tree); + } + else if (start_sym == file_input) { + /* This looks like an exec form so far. */ + if (validate_file_input(tree)) + st = parser_newstobject(tree, PyST_SUITE); + else + PyNode_Free(tree); + } + else if (start_sym == encoding_decl) { + /* This looks like an encoding_decl so far. */ + if (validate_encoding_decl(tree)) + st = parser_newstobject(tree, PyST_SUITE); + else + PyNode_Free(tree); + } + else { + /* This is a fragment, at best. */ + PyNode_Free(tree); + err_string("parse tree does not use a valid start symbol"); + } + } + /* Make sure we throw an exception on all errors. We should never + * get this, but we'd do well to be sure something is done. + */ + if (st == NULL && !PyErr_Occurred()) + err_string("unspecified ST error occurred"); + + return st; +} + + +/* node* build_node_children() + * + * Iterate across the children of the current non-terminal node and build + * their structures. If successful, return the root of this portion of + * the tree, otherwise, 0. Any required exception will be specified already, + * and no memory will have been deallocated. + * + */ +static node* +build_node_children(PyObject *tuple, node *root, int *line_num) +{ + Py_ssize_t len = PyObject_Size(tuple); + Py_ssize_t i; + int err; + + for (i = 1; i < len; ++i) { + /* elem must always be a sequence, however simple */ + PyObject* elem = PySequence_GetItem(tuple, i); + int ok = elem != NULL; + long type = 0; + char *strn = 0; + + if (ok) + ok = PySequence_Check(elem); + if (ok) { + PyObject *temp = PySequence_GetItem(elem, 0); + if (temp == NULL) + ok = 0; + else { + ok = PyInt_Check(temp); + if (ok) + type = PyInt_AS_LONG(temp); + Py_DECREF(temp); + } + } + if (!ok) { + PyObject *err = Py_BuildValue("os", elem, + "Illegal node construct."); + PyErr_SetObject(parser_error, err); + Py_XDECREF(err); + Py_XDECREF(elem); + return (0); + } + if (ISTERMINAL(type)) { + Py_ssize_t len = PyObject_Size(elem); + PyObject *temp; + + if ((len != 2) && (len != 3)) { + err_string("terminal nodes must have 2 or 3 entries"); + return 0; + } + temp = PySequence_GetItem(elem, 1); + if (temp == NULL) + return 0; + if (!PyString_Check(temp)) { + PyErr_Format(parser_error, + "second item in terminal node must be a string," + " found %s", + temp->ob_type->tp_name); + Py_DECREF(temp); + return 0; + } + if (len == 3) { + PyObject *o = PySequence_GetItem(elem, 2); + if (o != NULL) { + if (PyInt_Check(o)) + *line_num = PyInt_AS_LONG(o); + else { + PyErr_Format(parser_error, + "third item in terminal node must be an" + " integer, found %s", + temp->ob_type->tp_name); + Py_DECREF(o); + Py_DECREF(temp); + return 0; + } + Py_DECREF(o); + } + } + len = PyString_GET_SIZE(temp) + 1; + strn = (char *)PyObject_MALLOC(len); + if (strn != NULL) + (void) memcpy(strn, PyString_AS_STRING(temp), len); + Py_DECREF(temp); + } + else if (!ISNONTERMINAL(type)) { + /* + * It has to be one or the other; this is an error. + * Throw an exception. + */ + PyObject *err = Py_BuildValue("os", elem, "unknown node type."); + PyErr_SetObject(parser_error, err); + Py_XDECREF(err); + Py_XDECREF(elem); + return (0); + } + err = PyNode_AddChild(root, type, strn, *line_num, 0); + if (err == E_NOMEM) { + PyObject_FREE(strn); + return (node *) PyErr_NoMemory(); + } + if (err == E_OVERFLOW) { + PyObject_FREE(strn); + PyErr_SetString(PyExc_ValueError, + "unsupported number of child nodes"); + return NULL; + } + + if (ISNONTERMINAL(type)) { + node* new_child = CHILD(root, i - 1); + + if (new_child != build_node_children(elem, new_child, line_num)) { + Py_XDECREF(elem); + return (0); + } + } + else if (type == NEWLINE) { /* It's true: we increment the */ + ++(*line_num); /* line number *after* the newline! */ + } + Py_XDECREF(elem); + } + return root; +} + + +static node* +build_node_tree(PyObject *tuple) +{ + node* res = 0; + PyObject *temp = PySequence_GetItem(tuple, 0); + long num = -1; + + if (temp != NULL) + num = PyInt_AsLong(temp); + Py_XDECREF(temp); + if (ISTERMINAL(num)) { + /* + * The tuple is simple, but it doesn't start with a start symbol. + * Throw an exception now and be done with it. + */ + tuple = Py_BuildValue("os", tuple, + "Illegal syntax-tree; cannot start with terminal symbol."); + PyErr_SetObject(parser_error, tuple); + Py_XDECREF(tuple); + } + else if (ISNONTERMINAL(num)) { + /* + * Not efficient, but that can be handled later. + */ + int line_num = 0; + PyObject *encoding = NULL; + + if (num == encoding_decl) { + encoding = PySequence_GetItem(tuple, 2); + /* tuple isn't borrowed anymore here, need to DECREF */ + tuple = PySequence_GetSlice(tuple, 0, 2); + } + res = PyNode_New(num); + if (res != NULL) { + if (res != build_node_children(tuple, res, &line_num)) { + PyNode_Free(res); + res = NULL; + } + if (res && encoding) { + Py_ssize_t len; + len = PyString_GET_SIZE(encoding) + 1; + res->n_str = (char *)PyObject_MALLOC(len); + if (res->n_str != NULL) + (void) memcpy(res->n_str, PyString_AS_STRING(encoding), len); + Py_DECREF(encoding); + Py_DECREF(tuple); + } + } + } + else { + /* The tuple is illegal -- if the number is neither TERMINAL nor + * NONTERMINAL, we can't use it. Not sure the implementation + * allows this condition, but the API doesn't preclude it. + */ + PyObject *err = Py_BuildValue("os", tuple, + "Illegal component tuple."); + PyErr_SetObject(parser_error, err); + Py_XDECREF(err); + } + + return (res); +} + + +/* + * Validation routines used within the validation section: + */ +static int validate_terminal(node *terminal, int type, char *string); + +#define validate_ampersand(ch) validate_terminal(ch, AMPER, "&") +#define validate_circumflex(ch) validate_terminal(ch, CIRCUMFLEX, "^") +#define validate_colon(ch) validate_terminal(ch, COLON, ":") +#define validate_comma(ch) validate_terminal(ch, COMMA, ",") +#define validate_dedent(ch) validate_terminal(ch, DEDENT, "") +#define validate_equal(ch) validate_terminal(ch, EQUAL, "=") +#define validate_indent(ch) validate_terminal(ch, INDENT, (char*)NULL) +#define validate_lparen(ch) validate_terminal(ch, LPAR, "(") +#define validate_newline(ch) validate_terminal(ch, NEWLINE, (char*)NULL) +#define validate_rparen(ch) validate_terminal(ch, RPAR, ")") +#define validate_semi(ch) validate_terminal(ch, SEMI, ";") +#define validate_star(ch) validate_terminal(ch, STAR, "*") +#define validate_vbar(ch) validate_terminal(ch, VBAR, "|") +#define validate_doublestar(ch) validate_terminal(ch, DOUBLESTAR, "**") +#define validate_dot(ch) validate_terminal(ch, DOT, ".") +#define validate_at(ch) validate_terminal(ch, AT, "@") +#define validate_name(ch, str) validate_terminal(ch, NAME, str) + +#define VALIDATER(n) static int validate_##n(node *tree) + +VALIDATER(node); VALIDATER(small_stmt); +VALIDATER(class); VALIDATER(node); +VALIDATER(parameters); VALIDATER(suite); +VALIDATER(testlist); VALIDATER(varargslist); +VALIDATER(fpdef); VALIDATER(fplist); +VALIDATER(stmt); VALIDATER(simple_stmt); +VALIDATER(expr_stmt); VALIDATER(power); +VALIDATER(print_stmt); VALIDATER(del_stmt); +VALIDATER(return_stmt); VALIDATER(list_iter); +VALIDATER(raise_stmt); VALIDATER(import_stmt); +VALIDATER(import_name); VALIDATER(import_from); +VALIDATER(global_stmt); VALIDATER(list_if); +VALIDATER(assert_stmt); VALIDATER(list_for); +VALIDATER(exec_stmt); VALIDATER(compound_stmt); +VALIDATER(while); VALIDATER(for); +VALIDATER(try); VALIDATER(except_clause); +VALIDATER(test); VALIDATER(and_test); +VALIDATER(not_test); VALIDATER(comparison); +VALIDATER(comp_op); VALIDATER(expr); +VALIDATER(xor_expr); VALIDATER(and_expr); +VALIDATER(shift_expr); VALIDATER(arith_expr); +VALIDATER(term); VALIDATER(factor); +VALIDATER(atom); VALIDATER(lambdef); +VALIDATER(trailer); VALIDATER(subscript); +VALIDATER(subscriptlist); VALIDATER(sliceop); +VALIDATER(exprlist); VALIDATER(dictmaker); +VALIDATER(arglist); VALIDATER(argument); +VALIDATER(listmaker); VALIDATER(yield_stmt); +VALIDATER(testlist1); VALIDATER(gen_for); +VALIDATER(gen_iter); VALIDATER(gen_if); +VALIDATER(testlist_gexp); VALIDATER(yield_expr); +VALIDATER(yield_or_testlist); VALIDATER(or_test); +VALIDATER(old_test); VALIDATER(old_lambdef); + +#undef VALIDATER + +#define is_even(n) (((n) & 1) == 0) +#define is_odd(n) (((n) & 1) == 1) + + +static int +validate_ntype(node *n, int t) +{ + if (TYPE(n) != t) { + PyErr_Format(parser_error, "Expected node type %d, got %d.", + t, TYPE(n)); + return 0; + } + return 1; +} + + +/* Verifies that the number of child nodes is exactly 'num', raising + * an exception if it isn't. The exception message does not indicate + * the exact number of nodes, allowing this to be used to raise the + * "right" exception when the wrong number of nodes is present in a + * specific variant of a statement's syntax. This is commonly used + * in that fashion. + */ +static int +validate_numnodes(node *n, int num, const char *const name) +{ + if (NCH(n) != num) { + PyErr_Format(parser_error, + "Illegal number of children for %s node.", name); + return 0; + } + return 1; +} + + +static int +validate_terminal(node *terminal, int type, char *string) +{ + int res = (validate_ntype(terminal, type) + && ((string == 0) || (strcmp(string, STR(terminal)) == 0))); + + if (!res && !PyErr_Occurred()) { + PyErr_Format(parser_error, + "Illegal terminal: expected \"%s\"", string); + } + return (res); +} + + +/* X (',' X) [','] + */ +static int +validate_repeating_list(node *tree, int ntype, int (*vfunc)(node *), + const char *const name) +{ + int nch = NCH(tree); + int res = (nch && validate_ntype(tree, ntype) + && vfunc(CHILD(tree, 0))); + + if (!res && !PyErr_Occurred()) + (void) validate_numnodes(tree, 1, name); + else { + if (is_even(nch)) + res = validate_comma(CHILD(tree, --nch)); + if (res && nch > 1) { + int pos = 1; + for ( ; res && pos < nch; pos += 2) + res = (validate_comma(CHILD(tree, pos)) + && vfunc(CHILD(tree, pos + 1))); + } + } + return (res); +} + + +/* validate_class() + * + * classdef: + * 'class' NAME ['(' testlist ')'] ':' suite + */ +static int +validate_class(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, classdef) && + ((nch == 4) || (nch == 6) || (nch == 7))); + + if (res) { + res = (validate_name(CHILD(tree, 0), "class") + && validate_ntype(CHILD(tree, 1), NAME) + && validate_colon(CHILD(tree, nch - 2)) + && validate_suite(CHILD(tree, nch - 1))); + } + else { + (void) validate_numnodes(tree, 4, "class"); + } + + if (res) { + if (nch == 7) { + res = ((validate_lparen(CHILD(tree, 2)) && + validate_testlist(CHILD(tree, 3)) && + validate_rparen(CHILD(tree, 4)))); + } + else if (nch == 6) { + res = (validate_lparen(CHILD(tree,2)) && + validate_rparen(CHILD(tree,3))); + } + } + return (res); +} + + +/* if_stmt: + * 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] + */ +static int +validate_if(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, if_stmt) + && (nch >= 4) + && validate_name(CHILD(tree, 0), "if") + && validate_test(CHILD(tree, 1)) + && validate_colon(CHILD(tree, 2)) + && validate_suite(CHILD(tree, 3))); + + if (res && ((nch % 4) == 3)) { + /* ... 'else' ':' suite */ + res = (validate_name(CHILD(tree, nch - 3), "else") + && validate_colon(CHILD(tree, nch - 2)) + && validate_suite(CHILD(tree, nch - 1))); + nch -= 3; + } + else if (!res && !PyErr_Occurred()) + (void) validate_numnodes(tree, 4, "if"); + if ((nch % 4) != 0) + /* Will catch the case for nch < 4 */ + res = validate_numnodes(tree, 0, "if"); + else if (res && (nch > 4)) { + /* ... ('elif' test ':' suite)+ ... */ + int j = 4; + while ((j < nch) && res) { + res = (validate_name(CHILD(tree, j), "elif") + && validate_colon(CHILD(tree, j + 2)) + && validate_test(CHILD(tree, j + 1)) + && validate_suite(CHILD(tree, j + 3))); + j += 4; + } + } + return (res); +} + + +/* parameters: + * '(' [varargslist] ')' + * + */ +static int +validate_parameters(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, parameters) && ((nch == 2) || (nch == 3)); + + if (res) { + res = (validate_lparen(CHILD(tree, 0)) + && validate_rparen(CHILD(tree, nch - 1))); + if (res && (nch == 3)) + res = validate_varargslist(CHILD(tree, 1)); + } + else { + (void) validate_numnodes(tree, 2, "parameters"); + } + return (res); +} + + +/* validate_suite() + * + * suite: + * simple_stmt + * | NEWLINE INDENT stmt+ DEDENT + */ +static int +validate_suite(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, suite) && ((nch == 1) || (nch >= 4))); + + if (res && (nch == 1)) + res = validate_simple_stmt(CHILD(tree, 0)); + else if (res) { + /* NEWLINE INDENT stmt+ DEDENT */ + res = (validate_newline(CHILD(tree, 0)) + && validate_indent(CHILD(tree, 1)) + && validate_stmt(CHILD(tree, 2)) + && validate_dedent(CHILD(tree, nch - 1))); + + if (res && (nch > 4)) { + int i = 3; + --nch; /* forget the DEDENT */ + for ( ; res && (i < nch); ++i) + res = validate_stmt(CHILD(tree, i)); + } + else if (nch < 4) + res = validate_numnodes(tree, 4, "suite"); + } + return (res); +} + + +static int +validate_testlist(node *tree) +{ + return (validate_repeating_list(tree, testlist, + validate_test, "testlist")); +} + + +static int +validate_testlist1(node *tree) +{ + return (validate_repeating_list(tree, testlist1, + validate_test, "testlist1")); +} + + +static int +validate_testlist_safe(node *tree) +{ + return (validate_repeating_list(tree, testlist_safe, + validate_old_test, "testlist_safe")); +} + + +/* '*' NAME [',' '**' NAME] | '**' NAME + */ +static int +validate_varargslist_trailer(node *tree, int start) +{ + int nch = NCH(tree); + int res = 0; + int sym; + + if (nch <= start) { + err_string("expected variable argument trailer for varargslist"); + return 0; + } + sym = TYPE(CHILD(tree, start)); + if (sym == STAR) { + /* + * ('*' NAME [',' '**' NAME] + */ + if (nch-start == 2) + res = validate_name(CHILD(tree, start+1), NULL); + else if (nch-start == 5) + res = (validate_name(CHILD(tree, start+1), NULL) + && validate_comma(CHILD(tree, start+2)) + && validate_doublestar(CHILD(tree, start+3)) + && validate_name(CHILD(tree, start+4), NULL)); + } + else if (sym == DOUBLESTAR) { + /* + * '**' NAME + */ + if (nch-start == 2) + res = validate_name(CHILD(tree, start+1), NULL); + } + if (!res) + err_string("illegal variable argument trailer for varargslist"); + return res; +} + + +/* validate_varargslist() + * + * varargslist: + * (fpdef ['=' test] ',')* + * ('*' NAME [',' '**' NAME] + * | '**' NAME) + * | fpdef ['=' test] (',' fpdef ['=' test])* [','] + * + */ +static int +validate_varargslist(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, varargslist) && (nch != 0); + int sym; + + if (!res) + return 0; + if (nch < 1) { + err_string("varargslist missing child nodes"); + return 0; + } + sym = TYPE(CHILD(tree, 0)); + if (sym == STAR || sym == DOUBLESTAR) + /* whole thing matches: + * '*' NAME [',' '**' NAME] | '**' NAME + */ + res = validate_varargslist_trailer(tree, 0); + else if (sym == fpdef) { + int i = 0; + + sym = TYPE(CHILD(tree, nch-1)); + if (sym == NAME) { + /* + * (fpdef ['=' test] ',')+ + * ('*' NAME [',' '**' NAME] + * | '**' NAME) + */ + /* skip over (fpdef ['=' test] ',')+ */ + while (res && (i+2 <= nch)) { + res = validate_fpdef(CHILD(tree, i)); + ++i; + if (res && TYPE(CHILD(tree, i)) == EQUAL && (i+2 <= nch)) { + res = (validate_equal(CHILD(tree, i)) + && validate_test(CHILD(tree, i+1))); + if (res) + i += 2; + } + if (res && i < nch) { + res = validate_comma(CHILD(tree, i)); + ++i; + if (res && i < nch + && (TYPE(CHILD(tree, i)) == DOUBLESTAR + || TYPE(CHILD(tree, i)) == STAR)) + break; + } + } + /* ... '*' NAME [',' '**' NAME] | '**' NAME + * i --^^^ + */ + if (res) + res = validate_varargslist_trailer(tree, i); + } + else { + /* + * fpdef ['=' test] (',' fpdef ['=' test])* [','] + */ + /* strip trailing comma node */ + if (sym == COMMA) { + res = validate_comma(CHILD(tree, nch-1)); + if (!res) + return 0; + --nch; + } + /* + * fpdef ['=' test] (',' fpdef ['=' test])* + */ + res = validate_fpdef(CHILD(tree, 0)); + ++i; + if (res && (i+2 <= nch) && TYPE(CHILD(tree, i)) == EQUAL) { + res = (validate_equal(CHILD(tree, i)) + && validate_test(CHILD(tree, i+1))); + i += 2; + } + /* + * ... (',' fpdef ['=' test])* + * i ---^^^ + */ + while (res && (nch - i) >= 2) { + res = (validate_comma(CHILD(tree, i)) + && validate_fpdef(CHILD(tree, i+1))); + i += 2; + if (res && (nch - i) >= 2 && TYPE(CHILD(tree, i)) == EQUAL) { + res = (validate_equal(CHILD(tree, i)) + && validate_test(CHILD(tree, i+1))); + i += 2; + } + } + if (res && nch - i != 0) { + res = 0; + err_string("illegal formation for varargslist"); + } + } + } + return res; +} + + +/* list_iter: list_for | list_if + */ +static int +validate_list_iter(node *tree) +{ + int res = (validate_ntype(tree, list_iter) + && validate_numnodes(tree, 1, "list_iter")); + if (res && TYPE(CHILD(tree, 0)) == list_for) + res = validate_list_for(CHILD(tree, 0)); + else + res = validate_list_if(CHILD(tree, 0)); + + return res; +} + +/* gen_iter: gen_for | gen_if + */ +static int +validate_gen_iter(node *tree) +{ + int res = (validate_ntype(tree, gen_iter) + && validate_numnodes(tree, 1, "gen_iter")); + if (res && TYPE(CHILD(tree, 0)) == gen_for) + res = validate_gen_for(CHILD(tree, 0)); + else + res = validate_gen_if(CHILD(tree, 0)); + + return res; +} + +/* list_for: 'for' exprlist 'in' testlist [list_iter] + */ +static int +validate_list_for(node *tree) +{ + int nch = NCH(tree); + int res; + + if (nch == 5) + res = validate_list_iter(CHILD(tree, 4)); + else + res = validate_numnodes(tree, 4, "list_for"); + + if (res) + res = (validate_name(CHILD(tree, 0), "for") + && validate_exprlist(CHILD(tree, 1)) + && validate_name(CHILD(tree, 2), "in") + && validate_testlist_safe(CHILD(tree, 3))); + + return res; +} + +/* gen_for: 'for' exprlist 'in' test [gen_iter] + */ +static int +validate_gen_for(node *tree) +{ + int nch = NCH(tree); + int res; + + if (nch == 5) + res = validate_gen_iter(CHILD(tree, 4)); + else + res = validate_numnodes(tree, 4, "gen_for"); + + if (res) + res = (validate_name(CHILD(tree, 0), "for") + && validate_exprlist(CHILD(tree, 1)) + && validate_name(CHILD(tree, 2), "in") + && validate_or_test(CHILD(tree, 3))); + + return res; +} + +/* list_if: 'if' old_test [list_iter] + */ +static int +validate_list_if(node *tree) +{ + int nch = NCH(tree); + int res; + + if (nch == 3) + res = validate_list_iter(CHILD(tree, 2)); + else + res = validate_numnodes(tree, 2, "list_if"); + + if (res) + res = (validate_name(CHILD(tree, 0), "if") + && validate_old_test(CHILD(tree, 1))); + + return res; +} + +/* gen_if: 'if' old_test [gen_iter] + */ +static int +validate_gen_if(node *tree) +{ + int nch = NCH(tree); + int res; + + if (nch == 3) + res = validate_gen_iter(CHILD(tree, 2)); + else + res = validate_numnodes(tree, 2, "gen_if"); + + if (res) + res = (validate_name(CHILD(tree, 0), "if") + && validate_old_test(CHILD(tree, 1))); + + return res; +} + +/* validate_fpdef() + * + * fpdef: + * NAME + * | '(' fplist ')' + */ +static int +validate_fpdef(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, fpdef); + + if (res) { + if (nch == 1) + res = validate_ntype(CHILD(tree, 0), NAME); + else if (nch == 3) + res = (validate_lparen(CHILD(tree, 0)) + && validate_fplist(CHILD(tree, 1)) + && validate_rparen(CHILD(tree, 2))); + else + res = validate_numnodes(tree, 1, "fpdef"); + } + return (res); +} + + +static int +validate_fplist(node *tree) +{ + return (validate_repeating_list(tree, fplist, + validate_fpdef, "fplist")); +} + + +/* simple_stmt | compound_stmt + * + */ +static int +validate_stmt(node *tree) +{ + int res = (validate_ntype(tree, stmt) + && validate_numnodes(tree, 1, "stmt")); + + if (res) { + tree = CHILD(tree, 0); + + if (TYPE(tree) == simple_stmt) + res = validate_simple_stmt(tree); + else + res = validate_compound_stmt(tree); + } + return (res); +} + + +/* small_stmt (';' small_stmt)* [';'] NEWLINE + * + */ +static int +validate_simple_stmt(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, simple_stmt) + && (nch >= 2) + && validate_small_stmt(CHILD(tree, 0)) + && validate_newline(CHILD(tree, nch - 1))); + + if (nch < 2) + res = validate_numnodes(tree, 2, "simple_stmt"); + --nch; /* forget the NEWLINE */ + if (res && is_even(nch)) + res = validate_semi(CHILD(tree, --nch)); + if (res && (nch > 2)) { + int i; + + for (i = 1; res && (i < nch); i += 2) + res = (validate_semi(CHILD(tree, i)) + && validate_small_stmt(CHILD(tree, i + 1))); + } + return (res); +} + + +static int +validate_small_stmt(node *tree) +{ + int nch = NCH(tree); + int res = validate_numnodes(tree, 1, "small_stmt"); + + if (res) { + int ntype = TYPE(CHILD(tree, 0)); + + if ( (ntype == expr_stmt) + || (ntype == print_stmt) + || (ntype == del_stmt) + || (ntype == pass_stmt) + || (ntype == flow_stmt) + || (ntype == import_stmt) + || (ntype == global_stmt) + || (ntype == assert_stmt) + || (ntype == exec_stmt)) + res = validate_node(CHILD(tree, 0)); + else { + res = 0; + err_string("illegal small_stmt child type"); + } + } + else if (nch == 1) { + res = 0; + PyErr_Format(parser_error, + "Unrecognized child node of small_stmt: %d.", + TYPE(CHILD(tree, 0))); + } + return (res); +} + + +/* compound_stmt: + * if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef + */ +static int +validate_compound_stmt(node *tree) +{ + int res = (validate_ntype(tree, compound_stmt) + && validate_numnodes(tree, 1, "compound_stmt")); + int ntype; + + if (!res) + return (0); + + tree = CHILD(tree, 0); + ntype = TYPE(tree); + if ( (ntype == if_stmt) + || (ntype == while_stmt) + || (ntype == for_stmt) + || (ntype == try_stmt) + || (ntype == funcdef) + || (ntype == classdef)) + res = validate_node(tree); + else { + res = 0; + PyErr_Format(parser_error, + "Illegal compound statement type: %d.", TYPE(tree)); + } + return (res); +} + + +static int +validate_yield_or_testlist(node *tree) +{ + if (TYPE(tree) == yield_expr) + return validate_yield_expr(tree); + else + return validate_testlist(tree); +} + +static int +validate_expr_stmt(node *tree) +{ + int j; + int nch = NCH(tree); + int res = (validate_ntype(tree, expr_stmt) + && is_odd(nch) + && validate_testlist(CHILD(tree, 0))); + + if (res && nch == 3 + && TYPE(CHILD(tree, 1)) == augassign) { + res = validate_numnodes(CHILD(tree, 1), 1, "augassign") + && validate_yield_or_testlist(CHILD(tree, 2)); + + if (res) { + char *s = STR(CHILD(CHILD(tree, 1), 0)); + + res = (strcmp(s, "+=") == 0 + || strcmp(s, "-=") == 0 + || strcmp(s, "*=") == 0 + || strcmp(s, "/=") == 0 + || strcmp(s, "//=") == 0 + || strcmp(s, "%=") == 0 + || strcmp(s, "&=") == 0 + || strcmp(s, "|=") == 0 + || strcmp(s, "^=") == 0 + || strcmp(s, "<<=") == 0 + || strcmp(s, ">>=") == 0 + || strcmp(s, "**=") == 0); + if (!res) + err_string("illegal augmmented assignment operator"); + } + } + else { + for (j = 1; res && (j < nch); j += 2) + res = validate_equal(CHILD(tree, j)) + && validate_yield_or_testlist(CHILD(tree, j + 1)); + } + return (res); +} + + +/* print_stmt: + * + * 'print' ( [ test (',' test)* [','] ] + * | '>>' test [ (',' test)+ [','] ] ) + */ +static int +validate_print_stmt(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, print_stmt) + && (nch > 0) + && validate_name(CHILD(tree, 0), "print")); + + if (res && nch > 1) { + int sym = TYPE(CHILD(tree, 1)); + int i = 1; + int allow_trailing_comma = 1; + + if (sym == test) + res = validate_test(CHILD(tree, i++)); + else { + if (nch < 3) + res = validate_numnodes(tree, 3, "print_stmt"); + else { + res = (validate_ntype(CHILD(tree, i), RIGHTSHIFT) + && validate_test(CHILD(tree, i+1))); + i += 2; + allow_trailing_comma = 0; + } + } + if (res) { + /* ... (',' test)* [','] */ + while (res && i+2 <= nch) { + res = (validate_comma(CHILD(tree, i)) + && validate_test(CHILD(tree, i+1))); + allow_trailing_comma = 1; + i += 2; + } + if (res && !allow_trailing_comma) + res = validate_numnodes(tree, i, "print_stmt"); + else if (res && i < nch) + res = validate_comma(CHILD(tree, i)); + } + } + return (res); +} + + +static int +validate_del_stmt(node *tree) +{ + return (validate_numnodes(tree, 2, "del_stmt") + && validate_name(CHILD(tree, 0), "del") + && validate_exprlist(CHILD(tree, 1))); +} + + +static int +validate_return_stmt(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, return_stmt) + && ((nch == 1) || (nch == 2)) + && validate_name(CHILD(tree, 0), "return")); + + if (res && (nch == 2)) + res = validate_testlist(CHILD(tree, 1)); + + return (res); +} + + +static int +validate_raise_stmt(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, raise_stmt) + && ((nch == 1) || (nch == 2) || (nch == 4) || (nch == 6))); + + if (res) { + res = validate_name(CHILD(tree, 0), "raise"); + if (res && (nch >= 2)) + res = validate_test(CHILD(tree, 1)); + if (res && nch > 2) { + res = (validate_comma(CHILD(tree, 2)) + && validate_test(CHILD(tree, 3))); + if (res && (nch > 4)) + res = (validate_comma(CHILD(tree, 4)) + && validate_test(CHILD(tree, 5))); + } + } + else + (void) validate_numnodes(tree, 2, "raise"); + if (res && (nch == 4)) + res = (validate_comma(CHILD(tree, 2)) + && validate_test(CHILD(tree, 3))); + + return (res); +} + + +/* yield_expr: 'yield' [testlist] + */ +static int +validate_yield_expr(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, yield_expr) + && ((nch == 1) || (nch == 2)) + && validate_name(CHILD(tree, 0), "yield")); + + if (res && (nch == 2)) + res = validate_testlist(CHILD(tree, 1)); + + return (res); +} + + +/* yield_stmt: yield_expr + */ +static int +validate_yield_stmt(node *tree) +{ + return (validate_ntype(tree, yield_stmt) + && validate_numnodes(tree, 1, "yield_stmt") + && validate_yield_expr(CHILD(tree, 0))); +} + + +static int +validate_import_as_name(node *tree) +{ + int nch = NCH(tree); + int ok = validate_ntype(tree, import_as_name); + + if (ok) { + if (nch == 1) + ok = validate_name(CHILD(tree, 0), NULL); + else if (nch == 3) + ok = (validate_name(CHILD(tree, 0), NULL) + && validate_name(CHILD(tree, 1), "as") + && validate_name(CHILD(tree, 2), NULL)); + else + ok = validate_numnodes(tree, 3, "import_as_name"); + } + return ok; +} + + +/* dotted_name: NAME ("." NAME)* + */ +static int +validate_dotted_name(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, dotted_name) + && is_odd(nch) + && validate_name(CHILD(tree, 0), NULL)); + int i; + + for (i = 1; res && (i < nch); i += 2) { + res = (validate_dot(CHILD(tree, i)) + && validate_name(CHILD(tree, i+1), NULL)); + } + return res; +} + + +/* dotted_as_name: dotted_name [NAME NAME] + */ +static int +validate_dotted_as_name(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, dotted_as_name); + + if (res) { + if (nch == 1) + res = validate_dotted_name(CHILD(tree, 0)); + else if (nch == 3) + res = (validate_dotted_name(CHILD(tree, 0)) + && validate_name(CHILD(tree, 1), "as") + && validate_name(CHILD(tree, 2), NULL)); + else { + res = 0; + err_string("illegal number of children for dotted_as_name"); + } + } + return res; +} + + +/* dotted_as_name (',' dotted_as_name)* */ +static int +validate_dotted_as_names(node *tree) +{ + int nch = NCH(tree); + int res = is_odd(nch) && validate_dotted_as_name(CHILD(tree, 0)); + int i; + + for (i = 1; res && (i < nch); i += 2) + res = (validate_comma(CHILD(tree, i)) + && validate_dotted_as_name(CHILD(tree, i + 1))); + return (res); +} + + +/* import_as_name (',' import_as_name)* [','] */ +static int +validate_import_as_names(node *tree) +{ + int nch = NCH(tree); + int res = validate_import_as_name(CHILD(tree, 0)); + int i; + + for (i = 1; res && (i + 1 < nch); i += 2) + res = (validate_comma(CHILD(tree, i)) + && validate_import_as_name(CHILD(tree, i + 1))); + return (res); +} + + +/* 'import' dotted_as_names */ +static int +validate_import_name(node *tree) +{ + return (validate_ntype(tree, import_name) + && validate_numnodes(tree, 2, "import_name") + && validate_name(CHILD(tree, 0), "import") + && validate_dotted_as_names(CHILD(tree, 1))); +} + +/* Helper function to count the number of leading dots in + * 'from ...module import name' + */ +static int +count_from_dots(node *tree) +{ + int i; + for (i = 0; i < NCH(tree); i++) + if (TYPE(CHILD(tree, i)) != DOT) + break; + return i; +} + +/* 'from' ('.'* dotted_name | '.') 'import' ('*' | '(' import_as_names ')' | + * import_as_names + */ +static int +validate_import_from(node *tree) +{ + int nch = NCH(tree); + int ndots = count_from_dots(tree); + int havename = (TYPE(CHILD(tree, ndots + 1)) == dotted_name); + int offset = ndots + havename; + int res = validate_ntype(tree, import_from) + && (nch >= 4 + ndots) + && validate_name(CHILD(tree, 0), "from") + && (!havename || validate_dotted_name(CHILD(tree, ndots + 1))) + && validate_name(CHILD(tree, offset + 1), "import"); + + if (res && TYPE(CHILD(tree, offset + 2)) == LPAR) + res = ((nch == offset + 5) + && validate_lparen(CHILD(tree, offset + 2)) + && validate_import_as_names(CHILD(tree, offset + 3)) + && validate_rparen(CHILD(tree, offset + 4))); + else if (res && TYPE(CHILD(tree, offset + 2)) != STAR) + res = validate_import_as_names(CHILD(tree, offset + 2)); + return (res); +} + + +/* import_stmt: import_name | import_from */ +static int +validate_import_stmt(node *tree) +{ + int nch = NCH(tree); + int res = validate_numnodes(tree, 1, "import_stmt"); + + if (res) { + int ntype = TYPE(CHILD(tree, 0)); + + if (ntype == import_name || ntype == import_from) + res = validate_node(CHILD(tree, 0)); + else { + res = 0; + err_string("illegal import_stmt child type"); + } + } + else if (nch == 1) { + res = 0; + PyErr_Format(parser_error, + "Unrecognized child node of import_stmt: %d.", + TYPE(CHILD(tree, 0))); + } + return (res); +} + + + + +static int +validate_global_stmt(node *tree) +{ + int j; + int nch = NCH(tree); + int res = (validate_ntype(tree, global_stmt) + && is_even(nch) && (nch >= 2)); + + if (!res && !PyErr_Occurred()) + err_string("illegal global statement"); + + if (res) + res = (validate_name(CHILD(tree, 0), "global") + && validate_ntype(CHILD(tree, 1), NAME)); + for (j = 2; res && (j < nch); j += 2) + res = (validate_comma(CHILD(tree, j)) + && validate_ntype(CHILD(tree, j + 1), NAME)); + + return (res); +} + + +/* exec_stmt: + * + * 'exec' expr ['in' test [',' test]] + */ +static int +validate_exec_stmt(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, exec_stmt) + && ((nch == 2) || (nch == 4) || (nch == 6)) + && validate_name(CHILD(tree, 0), "exec") + && validate_expr(CHILD(tree, 1))); + + if (!res && !PyErr_Occurred()) + err_string("illegal exec statement"); + if (res && (nch > 2)) + res = (validate_name(CHILD(tree, 2), "in") + && validate_test(CHILD(tree, 3))); + if (res && (nch == 6)) + res = (validate_comma(CHILD(tree, 4)) + && validate_test(CHILD(tree, 5))); + + return (res); +} + + +/* assert_stmt: + * + * 'assert' test [',' test] + */ +static int +validate_assert_stmt(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, assert_stmt) + && ((nch == 2) || (nch == 4)) + && (validate_name(CHILD(tree, 0), "assert")) + && validate_test(CHILD(tree, 1))); + + if (!res && !PyErr_Occurred()) + err_string("illegal assert statement"); + if (res && (nch > 2)) + res = (validate_comma(CHILD(tree, 2)) + && validate_test(CHILD(tree, 3))); + + return (res); +} + + +static int +validate_while(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, while_stmt) + && ((nch == 4) || (nch == 7)) + && validate_name(CHILD(tree, 0), "while") + && validate_test(CHILD(tree, 1)) + && validate_colon(CHILD(tree, 2)) + && validate_suite(CHILD(tree, 3))); + + if (res && (nch == 7)) + res = (validate_name(CHILD(tree, 4), "else") + && validate_colon(CHILD(tree, 5)) + && validate_suite(CHILD(tree, 6))); + + return (res); +} + + +static int +validate_for(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, for_stmt) + && ((nch == 6) || (nch == 9)) + && validate_name(CHILD(tree, 0), "for") + && validate_exprlist(CHILD(tree, 1)) + && validate_name(CHILD(tree, 2), "in") + && validate_testlist(CHILD(tree, 3)) + && validate_colon(CHILD(tree, 4)) + && validate_suite(CHILD(tree, 5))); + + if (res && (nch == 9)) + res = (validate_name(CHILD(tree, 6), "else") + && validate_colon(CHILD(tree, 7)) + && validate_suite(CHILD(tree, 8))); + + return (res); +} + + +/* try_stmt: + * 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] + * | 'try' ':' suite 'finally' ':' suite + * + */ +static int +validate_try(node *tree) +{ + int nch = NCH(tree); + int pos = 3; + int res = (validate_ntype(tree, try_stmt) + && (nch >= 6) && ((nch % 3) == 0)); + + if (res) + res = (validate_name(CHILD(tree, 0), "try") + && validate_colon(CHILD(tree, 1)) + && validate_suite(CHILD(tree, 2)) + && validate_colon(CHILD(tree, nch - 2)) + && validate_suite(CHILD(tree, nch - 1))); + else if (!PyErr_Occurred()) { + const char* name = "except"; + if (TYPE(CHILD(tree, nch - 3)) != except_clause) + name = STR(CHILD(tree, nch - 3)); + + PyErr_Format(parser_error, + "Illegal number of children for try/%s node.", name); + } + /* Skip past except_clause sections: */ + while (res && (TYPE(CHILD(tree, pos)) == except_clause)) { + res = (validate_except_clause(CHILD(tree, pos)) + && validate_colon(CHILD(tree, pos + 1)) + && validate_suite(CHILD(tree, pos + 2))); + pos += 3; + } + if (res && (pos < nch)) { + res = validate_ntype(CHILD(tree, pos), NAME); + if (res && (strcmp(STR(CHILD(tree, pos)), "finally") == 0)) + res = (validate_numnodes(tree, 6, "try/finally") + && validate_colon(CHILD(tree, 4)) + && validate_suite(CHILD(tree, 5))); + else if (res) { + if (nch == (pos + 3)) { + res = ((strcmp(STR(CHILD(tree, pos)), "except") == 0) + || (strcmp(STR(CHILD(tree, pos)), "else") == 0)); + if (!res) + err_string("illegal trailing triple in try statement"); + } + else if (nch == (pos + 6)) { + res = (validate_name(CHILD(tree, pos), "except") + && validate_colon(CHILD(tree, pos + 1)) + && validate_suite(CHILD(tree, pos + 2)) + && validate_name(CHILD(tree, pos + 3), "else")); + } + else + res = validate_numnodes(tree, pos + 3, "try/except"); + } + } + return (res); +} + + +static int +validate_except_clause(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, except_clause) + && ((nch == 1) || (nch == 2) || (nch == 4)) + && validate_name(CHILD(tree, 0), "except")); + + if (res && (nch > 1)) + res = validate_test(CHILD(tree, 1)); + if (res && (nch == 4)) + res = (validate_comma(CHILD(tree, 2)) + && validate_test(CHILD(tree, 3))); + + return (res); +} + + +static int +validate_test(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, test) && is_odd(nch); + + if (res && (TYPE(CHILD(tree, 0)) == lambdef)) + res = ((nch == 1) + && validate_lambdef(CHILD(tree, 0))); + else if (res) { + res = validate_or_test(CHILD(tree, 0)); + res = (res && (nch == 1 || (nch == 5 && + validate_name(CHILD(tree, 1), "if") && + validate_or_test(CHILD(tree, 2)) && + validate_name(CHILD(tree, 3), "else") && + validate_test(CHILD(tree, 4))))); + } + return (res); +} + +static int +validate_old_test(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, old_test) && (nch == 1); + + if (res && (TYPE(CHILD(tree, 0)) == old_lambdef)) + res = (validate_old_lambdef(CHILD(tree, 0))); + else if (res) { + res = (validate_or_test(CHILD(tree, 0))); + } + return (res); +} + +static int +validate_or_test(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, or_test) && is_odd(nch); + + if (res) { + int pos; + res = validate_and_test(CHILD(tree, 0)); + for (pos = 1; res && (pos < nch); pos += 2) + res = (validate_name(CHILD(tree, pos), "or") + && validate_and_test(CHILD(tree, pos + 1))); + } + return (res); +} + + +static int +validate_and_test(node *tree) +{ + int pos; + int nch = NCH(tree); + int res = (validate_ntype(tree, and_test) + && is_odd(nch) + && validate_not_test(CHILD(tree, 0))); + + for (pos = 1; res && (pos < nch); pos += 2) + res = (validate_name(CHILD(tree, pos), "and") + && validate_not_test(CHILD(tree, 0))); + + return (res); +} + + +static int +validate_not_test(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, not_test) && ((nch == 1) || (nch == 2)); + + if (res) { + if (nch == 2) + res = (validate_name(CHILD(tree, 0), "not") + && validate_not_test(CHILD(tree, 1))); + else if (nch == 1) + res = validate_comparison(CHILD(tree, 0)); + } + return (res); +} + + +static int +validate_comparison(node *tree) +{ + int pos; + int nch = NCH(tree); + int res = (validate_ntype(tree, comparison) + && is_odd(nch) + && validate_expr(CHILD(tree, 0))); + + for (pos = 1; res && (pos < nch); pos += 2) + res = (validate_comp_op(CHILD(tree, pos)) + && validate_expr(CHILD(tree, pos + 1))); + + return (res); +} + + +static int +validate_comp_op(node *tree) +{ + int res = 0; + int nch = NCH(tree); + + if (!validate_ntype(tree, comp_op)) + return (0); + if (nch == 1) { + /* + * Only child will be a terminal with a well-defined symbolic name + * or a NAME with a string of either 'is' or 'in' + */ + tree = CHILD(tree, 0); + switch (TYPE(tree)) { + case LESS: + case GREATER: + case EQEQUAL: + case EQUAL: + case LESSEQUAL: + case GREATEREQUAL: + case NOTEQUAL: + res = 1; + break; + case NAME: + res = ((strcmp(STR(tree), "in") == 0) + || (strcmp(STR(tree), "is") == 0)); + if (!res) { + PyErr_Format(parser_error, + "illegal operator '%s'", STR(tree)); + } + break; + default: + err_string("illegal comparison operator type"); + break; + } + } + else if ((res = validate_numnodes(tree, 2, "comp_op")) != 0) { + res = (validate_ntype(CHILD(tree, 0), NAME) + && validate_ntype(CHILD(tree, 1), NAME) + && (((strcmp(STR(CHILD(tree, 0)), "is") == 0) + && (strcmp(STR(CHILD(tree, 1)), "not") == 0)) + || ((strcmp(STR(CHILD(tree, 0)), "not") == 0) + && (strcmp(STR(CHILD(tree, 1)), "in") == 0)))); + if (!res && !PyErr_Occurred()) + err_string("unknown comparison operator"); + } + return (res); +} + + +static int +validate_expr(node *tree) +{ + int j; + int nch = NCH(tree); + int res = (validate_ntype(tree, expr) + && is_odd(nch) + && validate_xor_expr(CHILD(tree, 0))); + + for (j = 2; res && (j < nch); j += 2) + res = (validate_xor_expr(CHILD(tree, j)) + && validate_vbar(CHILD(tree, j - 1))); + + return (res); +} + + +static int +validate_xor_expr(node *tree) +{ + int j; + int nch = NCH(tree); + int res = (validate_ntype(tree, xor_expr) + && is_odd(nch) + && validate_and_expr(CHILD(tree, 0))); + + for (j = 2; res && (j < nch); j += 2) + res = (validate_circumflex(CHILD(tree, j - 1)) + && validate_and_expr(CHILD(tree, j))); + + return (res); +} + + +static int +validate_and_expr(node *tree) +{ + int pos; + int nch = NCH(tree); + int res = (validate_ntype(tree, and_expr) + && is_odd(nch) + && validate_shift_expr(CHILD(tree, 0))); + + for (pos = 1; res && (pos < nch); pos += 2) + res = (validate_ampersand(CHILD(tree, pos)) + && validate_shift_expr(CHILD(tree, pos + 1))); + + return (res); +} + + +static int +validate_chain_two_ops(node *tree, int (*termvalid)(node *), int op1, int op2) + { + int pos = 1; + int nch = NCH(tree); + int res = (is_odd(nch) + && (*termvalid)(CHILD(tree, 0))); + + for ( ; res && (pos < nch); pos += 2) { + if (TYPE(CHILD(tree, pos)) != op1) + res = validate_ntype(CHILD(tree, pos), op2); + if (res) + res = (*termvalid)(CHILD(tree, pos + 1)); + } + return (res); +} + + +static int +validate_shift_expr(node *tree) +{ + return (validate_ntype(tree, shift_expr) + && validate_chain_two_ops(tree, validate_arith_expr, + LEFTSHIFT, RIGHTSHIFT)); +} + + +static int +validate_arith_expr(node *tree) +{ + return (validate_ntype(tree, arith_expr) + && validate_chain_two_ops(tree, validate_term, PLUS, MINUS)); +} + + +static int +validate_term(node *tree) +{ + int pos = 1; + int nch = NCH(tree); + int res = (validate_ntype(tree, term) + && is_odd(nch) + && validate_factor(CHILD(tree, 0))); + + for ( ; res && (pos < nch); pos += 2) + res = (((TYPE(CHILD(tree, pos)) == STAR) + || (TYPE(CHILD(tree, pos)) == SLASH) + || (TYPE(CHILD(tree, pos)) == DOUBLESLASH) + || (TYPE(CHILD(tree, pos)) == PERCENT)) + && validate_factor(CHILD(tree, pos + 1))); + + return (res); +} + + +/* factor: + * + * factor: ('+'|'-'|'~') factor | power + */ +static int +validate_factor(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, factor) + && (((nch == 2) + && ((TYPE(CHILD(tree, 0)) == PLUS) + || (TYPE(CHILD(tree, 0)) == MINUS) + || (TYPE(CHILD(tree, 0)) == TILDE)) + && validate_factor(CHILD(tree, 1))) + || ((nch == 1) + && validate_power(CHILD(tree, 0))))); + return (res); +} + + +/* power: + * + * power: atom trailer* ('**' factor)* + */ +static int +validate_power(node *tree) +{ + int pos = 1; + int nch = NCH(tree); + int res = (validate_ntype(tree, power) && (nch >= 1) + && validate_atom(CHILD(tree, 0))); + + while (res && (pos < nch) && (TYPE(CHILD(tree, pos)) == trailer)) + res = validate_trailer(CHILD(tree, pos++)); + if (res && (pos < nch)) { + if (!is_even(nch - pos)) { + err_string("illegal number of nodes for 'power'"); + return (0); + } + for ( ; res && (pos < (nch - 1)); pos += 2) + res = (validate_doublestar(CHILD(tree, pos)) + && validate_factor(CHILD(tree, pos + 1))); + } + return (res); +} + + +static int +validate_atom(node *tree) +{ + int pos; + int nch = NCH(tree); + int res = validate_ntype(tree, atom); + + if (res && nch < 1) + res = validate_numnodes(tree, nch+1, "atom"); + if (res) { + switch (TYPE(CHILD(tree, 0))) { + case LPAR: + res = ((nch <= 3) + && (validate_rparen(CHILD(tree, nch - 1)))); + + if (res && (nch == 3)) { + if (TYPE(CHILD(tree, 1))==yield_expr) + res = validate_yield_expr(CHILD(tree, 1)); + else + res = validate_testlist_gexp(CHILD(tree, 1)); + } + break; + case LSQB: + if (nch == 2) + res = validate_ntype(CHILD(tree, 1), RSQB); + else if (nch == 3) + res = (validate_listmaker(CHILD(tree, 1)) + && validate_ntype(CHILD(tree, 2), RSQB)); + else { + res = 0; + err_string("illegal list display atom"); + } + break; + case LBRACE: + res = ((nch <= 3) + && validate_ntype(CHILD(tree, nch - 1), RBRACE)); + + if (res && (nch == 3)) + res = validate_dictmaker(CHILD(tree, 1)); + break; + case BACKQUOTE: + res = ((nch == 3) + && validate_testlist1(CHILD(tree, 1)) + && validate_ntype(CHILD(tree, 2), BACKQUOTE)); + break; + case NAME: + case NUMBER: + res = (nch == 1); + break; + case STRING: + for (pos = 1; res && (pos < nch); ++pos) + res = validate_ntype(CHILD(tree, pos), STRING); + break; + default: + res = 0; + break; + } + } + return (res); +} + + +/* listmaker: + * test ( list_for | (',' test)* [','] ) + */ +static int +validate_listmaker(node *tree) +{ + int nch = NCH(tree); + int ok = nch; + + if (nch == 0) + err_string("missing child nodes of listmaker"); + else + ok = validate_test(CHILD(tree, 0)); + + /* + * list_for | (',' test)* [','] + */ + if (nch == 2 && TYPE(CHILD(tree, 1)) == list_for) + ok = validate_list_for(CHILD(tree, 1)); + else { + /* (',' test)* [','] */ + int i = 1; + while (ok && nch - i >= 2) { + ok = (validate_comma(CHILD(tree, i)) + && validate_test(CHILD(tree, i+1))); + i += 2; + } + if (ok && i == nch-1) + ok = validate_comma(CHILD(tree, i)); + else if (i != nch) { + ok = 0; + err_string("illegal trailing nodes for listmaker"); + } + } + return ok; +} + +/* testlist_gexp: + * test ( gen_for | (',' test)* [','] ) + */ +static int +validate_testlist_gexp(node *tree) +{ + int nch = NCH(tree); + int ok = nch; + + if (nch == 0) + err_string("missing child nodes of testlist_gexp"); + else { + ok = validate_test(CHILD(tree, 0)); + } + + /* + * gen_for | (',' test)* [','] + */ + if (nch == 2 && TYPE(CHILD(tree, 1)) == gen_for) + ok = validate_gen_for(CHILD(tree, 1)); + else { + /* (',' test)* [','] */ + int i = 1; + while (ok && nch - i >= 2) { + ok = (validate_comma(CHILD(tree, i)) + && validate_test(CHILD(tree, i+1))); + i += 2; + } + if (ok && i == nch-1) + ok = validate_comma(CHILD(tree, i)); + else if (i != nch) { + ok = 0; + err_string("illegal trailing nodes for testlist_gexp"); + } + } + return ok; +} + +/* decorator: + * '@' dotted_name [ '(' [arglist] ')' ] NEWLINE + */ +static int +validate_decorator(node *tree) +{ + int ok; + int nch = NCH(tree); + ok = (validate_ntype(tree, decorator) && + (nch == 3 || nch == 5 || nch == 6) && + validate_at(CHILD(tree, 0)) && + validate_dotted_name(CHILD(tree, 1)) && + validate_newline(RCHILD(tree, -1))); + + if (ok && nch != 3) { + ok = (validate_lparen(CHILD(tree, 2)) && + validate_rparen(RCHILD(tree, -2))); + + if (ok && nch == 6) + ok = validate_arglist(CHILD(tree, 3)); + } + + return ok; +} + +/* decorators: + * decorator+ + */ +static int +validate_decorators(node *tree) +{ + int i, nch, ok; + nch = NCH(tree); + ok = validate_ntype(tree, decorators) && nch >= 1; + + for (i = 0; ok && i < nch; ++i) + ok = validate_decorator(CHILD(tree, i)); + + return ok; +} + +/* funcdef: + * + * -6 -5 -4 -3 -2 -1 + * [decorators] 'def' NAME parameters ':' suite + */ +static int +validate_funcdef(node *tree) +{ + int nch = NCH(tree); + int ok = (validate_ntype(tree, funcdef) + && ((nch == 5) || (nch == 6)) + && validate_name(RCHILD(tree, -5), "def") + && validate_ntype(RCHILD(tree, -4), NAME) + && validate_colon(RCHILD(tree, -2)) + && validate_parameters(RCHILD(tree, -3)) + && validate_suite(RCHILD(tree, -1))); + + if (ok && (nch == 6)) + ok = validate_decorators(CHILD(tree, 0)); + + return ok; +} + + +static int +validate_lambdef(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, lambdef) + && ((nch == 3) || (nch == 4)) + && validate_name(CHILD(tree, 0), "lambda") + && validate_colon(CHILD(tree, nch - 2)) + && validate_test(CHILD(tree, nch - 1))); + + if (res && (nch == 4)) + res = validate_varargslist(CHILD(tree, 1)); + else if (!res && !PyErr_Occurred()) + (void) validate_numnodes(tree, 3, "lambdef"); + + return (res); +} + + +static int +validate_old_lambdef(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, old_lambdef) + && ((nch == 3) || (nch == 4)) + && validate_name(CHILD(tree, 0), "lambda") + && validate_colon(CHILD(tree, nch - 2)) + && validate_test(CHILD(tree, nch - 1))); + + if (res && (nch == 4)) + res = validate_varargslist(CHILD(tree, 1)); + else if (!res && !PyErr_Occurred()) + (void) validate_numnodes(tree, 3, "old_lambdef"); + + return (res); +} + + +/* arglist: + * + * (argument ',')* (argument [','] | '*' test [',' '**' test] | '**' test) + */ +static int +validate_arglist(node *tree) +{ + int nch = NCH(tree); + int i = 0; + int ok = 1; + + if (nch <= 0) + /* raise the right error from having an invalid number of children */ + return validate_numnodes(tree, nch + 1, "arglist"); + + if (nch > 1) { + for (i=0; i<nch; i++) { + if (TYPE(CHILD(tree, i)) == argument) { + node *ch = CHILD(tree, i); + if (NCH(ch) == 2 && TYPE(CHILD(ch, 1)) == gen_for) { + err_string("need '(', ')' for generator expression"); + return 0; + } + } + } + } + + while (ok && nch-i >= 2) { + /* skip leading (argument ',') */ + ok = (validate_argument(CHILD(tree, i)) + && validate_comma(CHILD(tree, i+1))); + if (ok) + i += 2; + else + PyErr_Clear(); + } + ok = 1; + if (nch-i > 0) { + /* + * argument | '*' test [',' '**' test] | '**' test + */ + int sym = TYPE(CHILD(tree, i)); + + if (sym == argument) { + ok = validate_argument(CHILD(tree, i)); + if (ok && i+1 != nch) { + err_string("illegal arglist specification" + " (extra stuff on end)"); + ok = 0; + } + } + else if (sym == STAR) { + ok = validate_star(CHILD(tree, i)); + if (ok && (nch-i == 2)) + ok = validate_test(CHILD(tree, i+1)); + else if (ok && (nch-i == 5)) + ok = (validate_test(CHILD(tree, i+1)) + && validate_comma(CHILD(tree, i+2)) + && validate_doublestar(CHILD(tree, i+3)) + && validate_test(CHILD(tree, i+4))); + else { + err_string("illegal use of '*' in arglist"); + ok = 0; + } + } + else if (sym == DOUBLESTAR) { + if (nch-i == 2) + ok = (validate_doublestar(CHILD(tree, i)) + && validate_test(CHILD(tree, i+1))); + else { + err_string("illegal use of '**' in arglist"); + ok = 0; + } + } + else { + err_string("illegal arglist specification"); + ok = 0; + } + } + return (ok); +} + + + +/* argument: + * + * [test '='] test [gen_for] + */ +static int +validate_argument(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, argument) + && ((nch == 1) || (nch == 2) || (nch == 3)) + && validate_test(CHILD(tree, 0))); + + if (res && (nch == 2)) + res = validate_gen_for(CHILD(tree, 1)); + else if (res && (nch == 3)) + res = (validate_equal(CHILD(tree, 1)) + && validate_test(CHILD(tree, 2))); + + return (res); +} + + + +/* trailer: + * + * '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME + */ +static int +validate_trailer(node *tree) +{ + int nch = NCH(tree); + int res = validate_ntype(tree, trailer) && ((nch == 2) || (nch == 3)); + + if (res) { + switch (TYPE(CHILD(tree, 0))) { + case LPAR: + res = validate_rparen(CHILD(tree, nch - 1)); + if (res && (nch == 3)) + res = validate_arglist(CHILD(tree, 1)); + break; + case LSQB: + res = (validate_numnodes(tree, 3, "trailer") + && validate_subscriptlist(CHILD(tree, 1)) + && validate_ntype(CHILD(tree, 2), RSQB)); + break; + case DOT: + res = (validate_numnodes(tree, 2, "trailer") + && validate_ntype(CHILD(tree, 1), NAME)); + break; + default: + res = 0; + break; + } + } + else { + (void) validate_numnodes(tree, 2, "trailer"); + } + return (res); +} + + +/* subscriptlist: + * + * subscript (',' subscript)* [','] + */ +static int +validate_subscriptlist(node *tree) +{ + return (validate_repeating_list(tree, subscriptlist, + validate_subscript, "subscriptlist")); +} + + +/* subscript: + * + * '.' '.' '.' | test | [test] ':' [test] [sliceop] + */ +static int +validate_subscript(node *tree) +{ + int offset = 0; + int nch = NCH(tree); + int res = validate_ntype(tree, subscript) && (nch >= 1) && (nch <= 4); + + if (!res) { + if (!PyErr_Occurred()) + err_string("invalid number of arguments for subscript node"); + return (0); + } + if (TYPE(CHILD(tree, 0)) == DOT) + /* take care of ('.' '.' '.') possibility */ + return (validate_numnodes(tree, 3, "subscript") + && validate_dot(CHILD(tree, 0)) + && validate_dot(CHILD(tree, 1)) + && validate_dot(CHILD(tree, 2))); + if (nch == 1) { + if (TYPE(CHILD(tree, 0)) == test) + res = validate_test(CHILD(tree, 0)); + else + res = validate_colon(CHILD(tree, 0)); + return (res); + } + /* Must be [test] ':' [test] [sliceop], + * but at least one of the optional components will + * be present, but we don't know which yet. + */ + if ((TYPE(CHILD(tree, 0)) != COLON) || (nch == 4)) { + res = validate_test(CHILD(tree, 0)); + offset = 1; + } + if (res) + res = validate_colon(CHILD(tree, offset)); + if (res) { + int rem = nch - ++offset; + if (rem) { + if (TYPE(CHILD(tree, offset)) == test) { + res = validate_test(CHILD(tree, offset)); + ++offset; + --rem; + } + if (res && rem) + res = validate_sliceop(CHILD(tree, offset)); + } + } + return (res); +} + + +static int +validate_sliceop(node *tree) +{ + int nch = NCH(tree); + int res = ((nch == 1) || validate_numnodes(tree, 2, "sliceop")) + && validate_ntype(tree, sliceop); + if (!res && !PyErr_Occurred()) { + res = validate_numnodes(tree, 1, "sliceop"); + } + if (res) + res = validate_colon(CHILD(tree, 0)); + if (res && (nch == 2)) + res = validate_test(CHILD(tree, 1)); + + return (res); +} + + +static int +validate_exprlist(node *tree) +{ + return (validate_repeating_list(tree, exprlist, + validate_expr, "exprlist")); +} + + +static int +validate_dictmaker(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, dictmaker) + && (nch >= 3) + && validate_test(CHILD(tree, 0)) + && validate_colon(CHILD(tree, 1)) + && validate_test(CHILD(tree, 2))); + + if (res && ((nch % 4) == 0)) + res = validate_comma(CHILD(tree, --nch)); + else if (res) + res = ((nch % 4) == 3); + + if (res && (nch > 3)) { + int pos = 3; + /* ( ',' test ':' test )* */ + while (res && (pos < nch)) { + res = (validate_comma(CHILD(tree, pos)) + && validate_test(CHILD(tree, pos + 1)) + && validate_colon(CHILD(tree, pos + 2)) + && validate_test(CHILD(tree, pos + 3))); + pos += 4; + } + } + return (res); +} + + +static int +validate_eval_input(node *tree) +{ + int pos; + int nch = NCH(tree); + int res = (validate_ntype(tree, eval_input) + && (nch >= 2) + && validate_testlist(CHILD(tree, 0)) + && validate_ntype(CHILD(tree, nch - 1), ENDMARKER)); + + for (pos = 1; res && (pos < (nch - 1)); ++pos) + res = validate_ntype(CHILD(tree, pos), NEWLINE); + + return (res); +} + + +static int +validate_node(node *tree) +{ + int nch = 0; /* num. children on current node */ + int res = 1; /* result value */ + node* next = 0; /* node to process after this one */ + + while (res && (tree != 0)) { + nch = NCH(tree); + next = 0; + switch (TYPE(tree)) { + /* + * Definition nodes. + */ + case funcdef: + res = validate_funcdef(tree); + break; + case classdef: + res = validate_class(tree); + break; + /* + * "Trivial" parse tree nodes. + * (Why did I call these trivial?) + */ + case stmt: + res = validate_stmt(tree); + break; + case small_stmt: + /* + * expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt + * | import_stmt | global_stmt | exec_stmt | assert_stmt + */ + res = validate_small_stmt(tree); + break; + case flow_stmt: + res = (validate_numnodes(tree, 1, "flow_stmt") + && ((TYPE(CHILD(tree, 0)) == break_stmt) + || (TYPE(CHILD(tree, 0)) == continue_stmt) + || (TYPE(CHILD(tree, 0)) == yield_stmt) + || (TYPE(CHILD(tree, 0)) == return_stmt) + || (TYPE(CHILD(tree, 0)) == raise_stmt))); + if (res) + next = CHILD(tree, 0); + else if (nch == 1) + err_string("illegal flow_stmt type"); + break; + case yield_stmt: + res = validate_yield_stmt(tree); + break; + /* + * Compound statements. + */ + case simple_stmt: + res = validate_simple_stmt(tree); + break; + case compound_stmt: + res = validate_compound_stmt(tree); + break; + /* + * Fundamental statements. + */ + case expr_stmt: + res = validate_expr_stmt(tree); + break; + case print_stmt: + res = validate_print_stmt(tree); + break; + case del_stmt: + res = validate_del_stmt(tree); + break; + case pass_stmt: + res = (validate_numnodes(tree, 1, "pass") + && validate_name(CHILD(tree, 0), "pass")); + break; + case break_stmt: + res = (validate_numnodes(tree, 1, "break") + && validate_name(CHILD(tree, 0), "break")); + break; + case continue_stmt: + res = (validate_numnodes(tree, 1, "continue") + && validate_name(CHILD(tree, 0), "continue")); + break; + case return_stmt: + res = validate_return_stmt(tree); + break; + case raise_stmt: + res = validate_raise_stmt(tree); + break; + case import_stmt: + res = validate_import_stmt(tree); + break; + case import_name: + res = validate_import_name(tree); + break; + case import_from: + res = validate_import_from(tree); + break; + case global_stmt: + res = validate_global_stmt(tree); + break; + case exec_stmt: + res = validate_exec_stmt(tree); + break; + case assert_stmt: + res = validate_assert_stmt(tree); + break; + case if_stmt: + res = validate_if(tree); + break; + case while_stmt: + res = validate_while(tree); + break; + case for_stmt: + res = validate_for(tree); + break; + case try_stmt: + res = validate_try(tree); + break; + case suite: + res = validate_suite(tree); + break; + /* + * Expression nodes. + */ + case testlist: + res = validate_testlist(tree); + break; + case yield_expr: + res = validate_yield_expr(tree); + break; + case testlist1: + res = validate_testlist1(tree); + break; + case test: + res = validate_test(tree); + break; + case and_test: + res = validate_and_test(tree); + break; + case not_test: + res = validate_not_test(tree); + break; + case comparison: + res = validate_comparison(tree); + break; + case exprlist: + res = validate_exprlist(tree); + break; + case comp_op: + res = validate_comp_op(tree); + break; + case expr: + res = validate_expr(tree); + break; + case xor_expr: + res = validate_xor_expr(tree); + break; + case and_expr: + res = validate_and_expr(tree); + break; + case shift_expr: + res = validate_shift_expr(tree); + break; + case arith_expr: + res = validate_arith_expr(tree); + break; + case term: + res = validate_term(tree); + break; + case factor: + res = validate_factor(tree); + break; + case power: + res = validate_power(tree); + break; + case atom: + res = validate_atom(tree); + break; + + default: + /* Hopefully never reached! */ + err_string("unrecognized node type"); + res = 0; + break; + } + tree = next; + } + return (res); +} + + +static int +validate_expr_tree(node *tree) +{ + int res = validate_eval_input(tree); + + if (!res && !PyErr_Occurred()) + err_string("could not validate expression tuple"); + + return (res); +} + + +/* file_input: + * (NEWLINE | stmt)* ENDMARKER + */ +static int +validate_file_input(node *tree) +{ + int j; + int nch = NCH(tree) - 1; + int res = ((nch >= 0) + && validate_ntype(CHILD(tree, nch), ENDMARKER)); + + for (j = 0; res && (j < nch); ++j) { + if (TYPE(CHILD(tree, j)) == stmt) + res = validate_stmt(CHILD(tree, j)); + else + res = validate_newline(CHILD(tree, j)); + } + /* This stays in to prevent any internal failures from getting to the + * user. Hopefully, this won't be needed. If a user reports getting + * this, we have some debugging to do. + */ + if (!res && !PyErr_Occurred()) + err_string("VALIDATION FAILURE: report this to the maintainer!"); + + return (res); +} + +static int +validate_encoding_decl(node *tree) +{ + int nch = NCH(tree); + int res = ((nch == 1) + && validate_file_input(CHILD(tree, 0))); + + if (!res && !PyErr_Occurred()) + err_string("Error Parsing encoding_decl"); + + return res; +} + +static PyObject* +pickle_constructor = NULL; + + +static PyObject* +parser__pickler(PyObject *self, PyObject *args) +{ + NOTE(ARGUNUSED(self)) + PyObject *result = NULL; + PyObject *st = NULL; + PyObject *empty_dict = NULL; + + if (PyArg_ParseTuple(args, "O!:_pickler", &PyST_Type, &st)) { + PyObject *newargs; + PyObject *tuple; + + if ((empty_dict = PyDict_New()) == NULL) + goto finally; + if ((newargs = Py_BuildValue("Oi", st, 1)) == NULL) + goto finally; + tuple = parser_st2tuple((PyST_Object*)NULL, newargs, empty_dict); + if (tuple != NULL) { + result = Py_BuildValue("O(O)", pickle_constructor, tuple); + Py_DECREF(tuple); + } + Py_DECREF(empty_dict); + Py_DECREF(newargs); + } + finally: + Py_XDECREF(empty_dict); + + return (result); +} + + +/* Functions exported by this module. Most of this should probably + * be converted into an ST object with methods, but that is better + * done directly in Python, allowing subclasses to be created directly. + * We'd really have to write a wrapper around it all anyway to allow + * inheritance. + */ +static PyMethodDef parser_functions[] = { + {"ast2tuple", (PyCFunction)parser_st2tuple, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates a tuple-tree representation of an ST.")}, + {"ast2list", (PyCFunction)parser_st2list, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates a list-tree representation of an ST.")}, + {"compileast", (PyCFunction)parser_compilest, PUBLIC_METHOD_TYPE, + PyDoc_STR("Compiles an ST object into a code object.")}, + {"compilest", (PyCFunction)parser_compilest, PUBLIC_METHOD_TYPE, + PyDoc_STR("Compiles an ST object into a code object.")}, + {"expr", (PyCFunction)parser_expr, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates an ST object from an expression.")}, + {"isexpr", (PyCFunction)parser_isexpr, PUBLIC_METHOD_TYPE, + PyDoc_STR("Determines if an ST object was created from an expression.")}, + {"issuite", (PyCFunction)parser_issuite, PUBLIC_METHOD_TYPE, + PyDoc_STR("Determines if an ST object was created from a suite.")}, + {"suite", (PyCFunction)parser_suite, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates an ST object from a suite.")}, + {"sequence2ast", (PyCFunction)parser_tuple2st, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates an ST object from a tree representation.")}, + {"sequence2st", (PyCFunction)parser_tuple2st, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates an ST object from a tree representation.")}, + {"st2tuple", (PyCFunction)parser_st2tuple, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates a tuple-tree representation of an ST.")}, + {"st2list", (PyCFunction)parser_st2list, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates a list-tree representation of an ST.")}, + {"tuple2ast", (PyCFunction)parser_tuple2st, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates an ST object from a tree representation.")}, + {"tuple2st", (PyCFunction)parser_tuple2st, PUBLIC_METHOD_TYPE, + PyDoc_STR("Creates an ST object from a tree representation.")}, + + /* private stuff: support pickle module */ + {"_pickler", (PyCFunction)parser__pickler, METH_VARARGS, + PyDoc_STR("Returns the pickle magic to allow ST objects to be pickled.")}, + + {NULL, NULL, 0, NULL} + }; + + +PyMODINIT_FUNC initparser(void); /* supply a prototype */ + +PyMODINIT_FUNC +initparser(void) +{ + PyObject *module, *copyreg; + + PyST_Type.ob_type = &PyType_Type; + module = Py_InitModule("parser", parser_functions); + if (module == NULL) + return; + + if (parser_error == 0) + parser_error = PyErr_NewException("parser.ParserError", NULL, NULL); + + if (parser_error == 0) + /* caller will check PyErr_Occurred() */ + return; + /* CAUTION: The code next used to skip bumping the refcount on + * parser_error. That's a disaster if initparser() gets called more + * than once. By incref'ing, we ensure that each module dict that + * gets created owns its reference to the shared parser_error object, + * and the file static parser_error vrbl owns a reference too. + */ + Py_INCREF(parser_error); + if (PyModule_AddObject(module, "ParserError", parser_error) != 0) + return; + + Py_INCREF(&PyST_Type); + PyModule_AddObject(module, "ASTType", (PyObject*)&PyST_Type); + Py_INCREF(&PyST_Type); + PyModule_AddObject(module, "STType", (PyObject*)&PyST_Type); + + PyModule_AddStringConstant(module, "__copyright__", + parser_copyright_string); + PyModule_AddStringConstant(module, "__doc__", + parser_doc_string); + PyModule_AddStringConstant(module, "__version__", + parser_version_string); + + /* Register to support pickling. + * If this fails, the import of this module will fail because an + * exception will be raised here; should we clear the exception? + */ + copyreg = PyImport_ImportModule("copy_reg"); + if (copyreg != NULL) { + PyObject *func, *pickler; + + func = PyObject_GetAttrString(copyreg, "pickle"); + pickle_constructor = PyObject_GetAttrString(module, "sequence2st"); + pickler = PyObject_GetAttrString(module, "_pickler"); + Py_XINCREF(pickle_constructor); + if ((func != NULL) && (pickle_constructor != NULL) + && (pickler != NULL)) { + PyObject *res; + + res = PyObject_CallFunctionObjArgs(func, &PyST_Type, pickler, + pickle_constructor, NULL); + Py_XDECREF(res); + } + Py_XDECREF(func); + Py_XDECREF(pickle_constructor); + Py_XDECREF(pickler); + Py_DECREF(copyreg); + } +} diff --git a/sys/src/cmd/python/Modules/posixmodule.c b/sys/src/cmd/python/Modules/posixmodule.c new file mode 100644 index 000000000..958fb63d3 --- /dev/null +++ b/sys/src/cmd/python/Modules/posixmodule.c @@ -0,0 +1,8752 @@ + +/* POSIX module implementation */ + +/* This file is also used for Windows NT/MS-Win and OS/2. In that case the + module actually calls itself 'nt' or 'os2', not 'posix', and a few + functions are either unimplemented or implemented differently. The source + assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent + of the compiler used. Different compilers define their own feature + test macro, e.g. '__BORLANDC__' or '_MSC_VER'. For OS/2, the compiler + independent macro PYOS_OS2 should be defined. On OS/2 the default + compiler is assumed to be IBM's VisualAge C++ (VACPP). PYCC_GCC is used + as the compiler specific macro for the EMX port of gcc to OS/2. */ + +/* See also ../Dos/dosmodule.c */ + +#ifdef __APPLE__ + /* + * Step 1 of support for weak-linking a number of symbols existing on + * OSX 10.4 and later, see the comment in the #ifdef __APPLE__ block + * at the end of this file for more information. + */ +# pragma weak lchown +# pragma weak statvfs +# pragma weak fstatvfs + +#endif /* __APPLE__ */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" +#include "structseq.h" + +#if defined(__VMS) +# include <unixio.h> +#endif /* defined(__VMS) */ + +#ifdef __cplusplus +extern "C" { +#endif + +PyDoc_STRVAR(posix__doc__, +"This module provides access to operating system functionality that is\n\ +standardized by the C Standard and the POSIX standard (a thinly\n\ +disguised Unix interface). Refer to the library manual and\n\ +corresponding Unix manual entries for more information on calls."); + +#ifndef Py_USING_UNICODE +/* This is used in signatures of functions. */ +#define Py_UNICODE void +#endif + +#if defined(PYOS_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#define INCL_NOPMAPI +#include <os2.h> +#if defined(PYCC_GCC) +#include <ctype.h> +#include <io.h> +#include <stdio.h> +#include <process.h> +#endif +#include "osdefs.h" +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /* HAVE_SYS_STAT_H */ + +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> /* For WNOHANG */ +#endif + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif /* HAVE_FCNTL_H */ + +#ifdef HAVE_GRP_H +#include <grp.h> +#endif + +#ifdef HAVE_SYSEXITS_H +#include <sysexits.h> +#endif /* HAVE_SYSEXITS_H */ + +#ifdef HAVE_SYS_LOADAVG_H +#include <sys/loadavg.h> +#endif + +/* Various compilers have only certain posix functions */ +/* XXX Gosh I wish these were all moved into pyconfig.h */ +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +#include <process.h> +#else +#if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */ +#define HAVE_GETCWD 1 +#define HAVE_OPENDIR 1 +#define HAVE_SYSTEM 1 +#if defined(__OS2__) +#define HAVE_EXECV 1 +#define HAVE_WAIT 1 +#endif +#include <process.h> +#else +#ifdef __BORLANDC__ /* Borland compiler */ +#define HAVE_EXECV 1 +#define HAVE_GETCWD 1 +#define HAVE_OPENDIR 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#define HAVE_WAIT 1 +#else +#ifdef _MSC_VER /* Microsoft compiler */ +#define HAVE_GETCWD 1 +#define HAVE_SPAWNV 1 +#define HAVE_EXECV 1 +#define HAVE_PIPE 1 +#define HAVE_POPEN 1 +#define HAVE_SYSTEM 1 +#define HAVE_CWAIT 1 +#define HAVE_FSYNC 1 +#define fsync _commit +#else +#if defined(PYOS_OS2) && defined(PYCC_GCC) || defined(__VMS) +/* Everything needed is defined in PC/os2emx/pyconfig.h or vms/pyconfig.h */ +#else /* all other compilers */ +/* Unix functions that the configure script doesn't check for */ +#define HAVE_EXECV 1 +#define HAVE_FORK 1 +#if defined(__USLC__) && defined(__SCO_VERSION__) /* SCO UDK Compiler */ +#define HAVE_FORK1 1 +#endif +#define HAVE_GETCWD 1 +#define HAVE_GETEGID 1 +#define HAVE_GETEUID 1 +#define HAVE_GETGID 1 +#define HAVE_GETPPID 1 +#define HAVE_GETUID 1 +#define HAVE_KILL 1 +#define HAVE_OPENDIR 1 +#define HAVE_PIPE 1 +#ifndef __rtems__ +#define HAVE_POPEN 1 +#endif +#define HAVE_SYSTEM 1 +#define HAVE_WAIT 1 +#define HAVE_TTYNAME 1 +#endif /* PYOS_OS2 && PYCC_GCC && __VMS */ +#endif /* _MSC_VER */ +#endif /* __BORLANDC__ */ +#endif /* ! __WATCOMC__ || __QNX__ */ +#endif /* ! __IBMC__ */ + +#ifndef _MSC_VER + +#if defined(__sgi)&&_COMPILER_VERSION>=700 +/* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode + (default) */ +extern char *ctermid_r(char *); +#endif + +#ifndef HAVE_UNISTD_H +#if defined(PYCC_VACPP) +extern int mkdir(char *); +#else +#if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__) +extern int mkdir(const char *); +#else +extern int mkdir(const char *, mode_t); +#endif +#endif +#if defined(__IBMC__) || defined(__IBMCPP__) +extern int chdir(char *); +extern int rmdir(char *); +#else +extern int chdir(const char *); +extern int rmdir(const char *); +#endif +#ifdef __BORLANDC__ +extern int chmod(const char *, int); +#else +extern int chmod(const char *, mode_t); +#endif +extern int chown(const char *, uid_t, gid_t); +extern char *getcwd(char *, int); +extern char *strerror(int); +extern int link(const char *, const char *); +extern int rename(const char *, const char *); +extern int stat(const char *, struct stat *); +extern int unlink(const char *); +extern int pclose(FILE *); +#ifdef HAVE_SYMLINK +extern int symlink(const char *, const char *); +#endif /* HAVE_SYMLINK */ +#ifdef HAVE_LSTAT +extern int lstat(const char *, struct stat *); +#endif /* HAVE_LSTAT */ +#endif /* !HAVE_UNISTD_H */ + +#endif /* !_MSC_VER */ + +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif /* HAVE_UTIME_H */ + +#ifdef HAVE_SYS_UTIME_H +#include <sys/utime.h> +#define HAVE_UTIME_H /* pretend we do for the rest of this file */ +#endif /* HAVE_SYS_UTIME_H */ + +#ifdef HAVE_SYS_TIMES_H +#include <sys/times.h> +#endif /* HAVE_SYS_TIMES_H */ + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif /* HAVE_SYS_PARAM_H */ + +#ifdef HAVE_SYS_UTSNAME_H +#include <sys/utsname.h> +#endif /* HAVE_SYS_UTSNAME_H */ + +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#if defined(__WATCOMC__) && !defined(__QNX__) +#include <direct.h> +#define NAMLEN(dirent) strlen((dirent)->d_name) +#else +#define dirent direct +#define NAMLEN(dirent) (dirent)->d_namlen +#endif +#ifdef HAVE_SYS_NDIR_H +#include <sys/ndir.h> +#endif +#ifdef HAVE_SYS_DIR_H +#include <sys/dir.h> +#endif +#ifdef HAVE_NDIR_H +#include <ndir.h> +#endif +#endif + +#ifdef _MSC_VER +#ifdef HAVE_DIRECT_H +#include <direct.h> +#endif +#ifdef HAVE_IO_H +#include <io.h> +#endif +#ifdef HAVE_PROCESS_H +#include <process.h> +#endif +#include "osdefs.h" +#define _WIN32_WINNT 0x0400 /* Needed for CryptoAPI on some systems */ +#include <windows.h> +#include <shellapi.h> /* for ShellExecute() */ +#define popen _popen +#define pclose _pclose +#endif /* _MSC_VER */ + +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +#include <io.h> +#endif /* OS2 */ + +#ifndef MAXPATHLEN +#if defined(PATH_MAX) && PATH_MAX > 1024 +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 1024 +#endif +#endif /* MAXPATHLEN */ + +#ifdef UNION_WAIT +/* Emulate some macros on systems that have a union instead of macros */ + +#ifndef WIFEXITED +#define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump) +#endif + +#ifndef WEXITSTATUS +#define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1) +#endif + +#ifndef WTERMSIG +#define WTERMSIG(u_wait) ((u_wait).w_termsig) +#endif + +#define WAIT_TYPE union wait +#define WAIT_STATUS_INT(s) (s.w_status) + +#else /* !UNION_WAIT */ +#define WAIT_TYPE int +#define WAIT_STATUS_INT(s) (s) +#endif /* UNION_WAIT */ + +/* Don't use the "_r" form if we don't need it (also, won't have a + prototype for it, at least on Solaris -- maybe others as well?). */ +#if defined(HAVE_CTERMID_R) && defined(WITH_THREAD) +#define USE_CTERMID_R +#endif + +#if defined(HAVE_TMPNAM_R) && defined(WITH_THREAD) +#define USE_TMPNAM_R +#endif + +/* choose the appropriate stat and fstat functions and return structs */ +#undef STAT +#if defined(MS_WIN64) || defined(MS_WINDOWS) +# define STAT win32_stat +# define FSTAT win32_fstat +# define STRUCT_STAT struct win32_stat +#else +# define STAT stat +# define FSTAT fstat +# define STRUCT_STAT struct stat +#endif + +#if defined(MAJOR_IN_MKDEV) +#include <sys/mkdev.h> +#else +#if defined(MAJOR_IN_SYSMACROS) +#include <sys/sysmacros.h> +#endif +#if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H) +#include <sys/mkdev.h> +#endif +#endif + +/* Return a dictionary corresponding to the POSIX environment table */ +#ifdef WITH_NEXT_FRAMEWORK +/* On Darwin/MacOSX a shared library or framework has no access to +** environ directly, we must obtain it with _NSGetEnviron(). +*/ +#include <crt_externs.h> +static char **environ; +#elif !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) ) +extern char **environ; +#endif /* !_MSC_VER */ + +static PyObject * +convertenviron(void) +{ + PyObject *d; + char **e; + d = PyDict_New(); + if (d == NULL) + return NULL; +#ifdef WITH_NEXT_FRAMEWORK + if (environ == NULL) + environ = *_NSGetEnviron(); +#endif + if (environ == NULL) + return d; + /* This part ignores errors */ + for (e = environ; *e != NULL; e++) { + PyObject *k; + PyObject *v; + char *p = strchr(*e, '='); + if (p == NULL) + continue; + k = PyString_FromStringAndSize(*e, (int)(p-*e)); + if (k == NULL) { + PyErr_Clear(); + continue; + } + v = PyString_FromString(p+1); + if (v == NULL) { + PyErr_Clear(); + Py_DECREF(k); + continue; + } + if (PyDict_GetItem(d, k) == NULL) { + if (PyDict_SetItem(d, k, v) != 0) + PyErr_Clear(); + } + Py_DECREF(k); + Py_DECREF(v); + } +#if defined(PYOS_OS2) + { + APIRET rc; + char buffer[1024]; /* OS/2 Provides a Documented Max of 1024 Chars */ + + rc = DosQueryExtLIBPATH(buffer, BEGIN_LIBPATH); + if (rc == NO_ERROR) { /* (not a type, envname is NOT 'BEGIN_LIBPATH') */ + PyObject *v = PyString_FromString(buffer); + PyDict_SetItemString(d, "BEGINLIBPATH", v); + Py_DECREF(v); + } + rc = DosQueryExtLIBPATH(buffer, END_LIBPATH); + if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'END_LIBPATH') */ + PyObject *v = PyString_FromString(buffer); + PyDict_SetItemString(d, "ENDLIBPATH", v); + Py_DECREF(v); + } + } +#endif + return d; +} + + +/* Set a POSIX-specific error from errno, and return NULL */ + +static PyObject * +posix_error(void) +{ + return PyErr_SetFromErrno(PyExc_OSError); +} +static PyObject * +posix_error_with_filename(char* name) +{ + return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); +} + +#ifdef Py_WIN_WIDE_FILENAMES +static PyObject * +posix_error_with_unicode_filename(Py_UNICODE* name) +{ + return PyErr_SetFromErrnoWithUnicodeFilename(PyExc_OSError, name); +} +#endif /* Py_WIN_WIDE_FILENAMES */ + + +static PyObject * +posix_error_with_allocated_filename(char* name) +{ + PyObject *rc = PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); + PyMem_Free(name); + return rc; +} + +#ifdef MS_WINDOWS +static PyObject * +win32_error(char* function, char* filename) +{ + /* XXX We should pass the function name along in the future. + (_winreg.c also wants to pass the function name.) + This would however require an additional param to the + Windows error object, which is non-trivial. + */ + errno = GetLastError(); + if (filename) + return PyErr_SetFromWindowsErrWithFilename(errno, filename); + else + return PyErr_SetFromWindowsErr(errno); +} + +#ifdef Py_WIN_WIDE_FILENAMES +static PyObject * +win32_error_unicode(char* function, Py_UNICODE* filename) +{ + /* XXX - see win32_error for comments on 'function' */ + errno = GetLastError(); + if (filename) + return PyErr_SetFromWindowsErrWithUnicodeFilename(errno, filename); + else + return PyErr_SetFromWindowsErr(errno); +} + +static PyObject *_PyUnicode_FromFileSystemEncodedObject(register PyObject *obj) +{ +} + +/* Function suitable for O& conversion */ +static int +convert_to_unicode(PyObject *arg, void* _param) +{ + PyObject **param = (PyObject**)_param; + if (PyUnicode_CheckExact(arg)) { + Py_INCREF(arg); + *param = arg; + } + else if (PyUnicode_Check(arg)) { + /* For a Unicode subtype that's not a Unicode object, + return a true Unicode object with the same data. */ + *param = PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(arg), + PyUnicode_GET_SIZE(arg)); + return *param != NULL; + } + else + *param = PyUnicode_FromEncodedObject(arg, + Py_FileSystemDefaultEncoding, + "strict"); + return (*param) != NULL; +} + +#endif /* Py_WIN_WIDE_FILENAMES */ + +#endif + +#if defined(PYOS_OS2) +/********************************************************************** + * Helper Function to Trim and Format OS/2 Messages + **********************************************************************/ + static void +os2_formatmsg(char *msgbuf, int msglen, char *reason) +{ + msgbuf[msglen] = '\0'; /* OS/2 Doesn't Guarantee a Terminator */ + + if (strlen(msgbuf) > 0) { /* If Non-Empty Msg, Trim CRLF */ + char *lastc = &msgbuf[ strlen(msgbuf)-1 ]; + + while (lastc > msgbuf && isspace(Py_CHARMASK(*lastc))) + *lastc-- = '\0'; /* Trim Trailing Whitespace (CRLF) */ + } + + /* Add Optional Reason Text */ + if (reason) { + strcat(msgbuf, " : "); + strcat(msgbuf, reason); + } +} + +/********************************************************************** + * Decode an OS/2 Operating System Error Code + * + * A convenience function to lookup an OS/2 error code and return a + * text message we can use to raise a Python exception. + * + * Notes: + * The messages for errors returned from the OS/2 kernel reside in + * the file OSO001.MSG in the \OS2 directory hierarchy. + * + **********************************************************************/ + static char * +os2_strerror(char *msgbuf, int msgbuflen, int errorcode, char *reason) +{ + APIRET rc; + ULONG msglen; + + /* Retrieve Kernel-Related Error Message from OSO001.MSG File */ + Py_BEGIN_ALLOW_THREADS + rc = DosGetMessage(NULL, 0, msgbuf, msgbuflen, + errorcode, "oso001.msg", &msglen); + Py_END_ALLOW_THREADS + + if (rc == NO_ERROR) + os2_formatmsg(msgbuf, msglen, reason); + else + PyOS_snprintf(msgbuf, msgbuflen, + "unknown OS error #%d", errorcode); + + return msgbuf; +} + +/* Set an OS/2-specific error and return NULL. OS/2 kernel + errors are not in a global variable e.g. 'errno' nor are + they congruent with posix error numbers. */ + +static PyObject * os2_error(int code) +{ + char text[1024]; + PyObject *v; + + os2_strerror(text, sizeof(text), code, ""); + + v = Py_BuildValue("(is)", code, text); + if (v != NULL) { + PyErr_SetObject(PyExc_OSError, v); + Py_DECREF(v); + } + return NULL; /* Signal to Python that an Exception is Pending */ +} + +#endif /* OS2 */ + +/* POSIX generic methods */ + +static PyObject * +posix_fildes(PyObject *fdobj, int (*func)(int)) +{ + int fd; + int res; + fd = PyObject_AsFileDescriptor(fdobj); + if (fd < 0) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(fd); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef Py_WIN_WIDE_FILENAMES +static int +unicode_file_names(void) +{ + static int canusewide = -1; + if (canusewide == -1) { + /* As per doc for ::GetVersion(), this is the correct test for + the Windows NT family. */ + canusewide = (GetVersion() < 0x80000000) ? 1 : 0; + } + return canusewide; +} +#endif + +static PyObject * +posix_1str(PyObject *args, char *format, int (*func)(const char*)) +{ + char *path1 = NULL; + int res; + if (!PyArg_ParseTuple(args, format, + Py_FileSystemDefaultEncoding, &path1)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path1); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_allocated_filename(path1); + PyMem_Free(path1); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +posix_2str(PyObject *args, + char *format, + int (*func)(const char *, const char *)) +{ + char *path1 = NULL, *path2 = NULL; + int res; + if (!PyArg_ParseTuple(args, format, + Py_FileSystemDefaultEncoding, &path1, + Py_FileSystemDefaultEncoding, &path2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = (*func)(path1, path2); + Py_END_ALLOW_THREADS + PyMem_Free(path1); + PyMem_Free(path2); + if (res != 0) + /* XXX how to report both path1 and path2??? */ + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef Py_WIN_WIDE_FILENAMES +static PyObject* +win32_1str(PyObject* args, char* func, + char* format, BOOL (__stdcall *funcA)(LPCSTR), + char* wformat, BOOL (__stdcall *funcW)(LPWSTR)) +{ + PyObject *uni; + char *ansi; + BOOL result; + if (unicode_file_names()) { + if (!PyArg_ParseTuple(args, wformat, &uni)) + PyErr_Clear(); + else { + Py_BEGIN_ALLOW_THREADS + result = funcW(PyUnicode_AsUnicode(uni)); + Py_END_ALLOW_THREADS + if (!result) + return win32_error_unicode(func, PyUnicode_AsUnicode(uni)); + Py_INCREF(Py_None); + return Py_None; + } + } + if (!PyArg_ParseTuple(args, format, &ansi)) + return NULL; + Py_BEGIN_ALLOW_THREADS + result = funcA(ansi); + Py_END_ALLOW_THREADS + if (!result) + return win32_error(func, ansi); + Py_INCREF(Py_None); + return Py_None; + +} + +/* This is a reimplementation of the C library's chdir function, + but one that produces Win32 errors instead of DOS error codes. + chdir is essentially a wrapper around SetCurrentDirectory; however, + it also needs to set "magic" environment variables indicating + the per-drive current directory, which are of the form =<drive>: */ +BOOL __stdcall +win32_chdir(LPCSTR path) +{ + char new_path[MAX_PATH+1]; + int result; + char env[4] = "=x:"; + + if(!SetCurrentDirectoryA(path)) + return FALSE; + result = GetCurrentDirectoryA(MAX_PATH+1, new_path); + if (!result) + return FALSE; + /* In the ANSI API, there should not be any paths longer + than MAX_PATH. */ + assert(result <= MAX_PATH+1); + if (strncmp(new_path, "\\\\", 2) == 0 || + strncmp(new_path, "//", 2) == 0) + /* UNC path, nothing to do. */ + return TRUE; + env[1] = new_path[0]; + return SetEnvironmentVariableA(env, new_path); +} + +/* The Unicode version differs from the ANSI version + since the current directory might exceed MAX_PATH characters */ +BOOL __stdcall +win32_wchdir(LPCWSTR path) +{ + wchar_t _new_path[MAX_PATH+1], *new_path = _new_path; + int result; + wchar_t env[4] = L"=x:"; + + if(!SetCurrentDirectoryW(path)) + return FALSE; + result = GetCurrentDirectoryW(MAX_PATH+1, new_path); + if (!result) + return FALSE; + if (result > MAX_PATH+1) { + new_path = malloc(result); + if (!new_path) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + } + if (wcsncmp(new_path, L"\\\\", 2) == 0 || + wcsncmp(new_path, L"//", 2) == 0) + /* UNC path, nothing to do. */ + return TRUE; + env[1] = new_path[0]; + result = SetEnvironmentVariableW(env, new_path); + if (new_path != _new_path) + free(new_path); + return result; +} +#endif + +#ifdef MS_WINDOWS +/* The CRT of Windows has a number of flaws wrt. its stat() implementation: + - time stamps are restricted to second resolution + - file modification times suffer from forth-and-back conversions between + UTC and local time + Therefore, we implement our own stat, based on the Win32 API directly. +*/ +#define HAVE_STAT_NSEC 1 + +struct win32_stat{ + int st_dev; + __int64 st_ino; + unsigned short st_mode; + int st_nlink; + int st_uid; + int st_gid; + int st_rdev; + __int64 st_size; + int st_atime; + int st_atime_nsec; + int st_mtime; + int st_mtime_nsec; + int st_ctime; + int st_ctime_nsec; +}; + +static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ + +static void +FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, int *time_out, int* nsec_out) +{ + /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ + /* Cannot simply cast and dereference in_ptr, + since it might not be aligned properly */ + __int64 in; + memcpy(&in, in_ptr, sizeof(in)); + *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ + /* XXX Win32 supports time stamps past 2038; we currently don't */ + *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, int); +} + +static void +time_t_to_FILE_TIME(int time_in, int nsec_in, FILETIME *out_ptr) +{ + /* XXX endianness */ + __int64 out; + out = time_in + secs_between_epochs; + out = out * 10000000 + nsec_in / 100; + memcpy(out_ptr, &out, sizeof(out)); +} + +/* Below, we *know* that ugo+r is 0444 */ +#if _S_IREAD != 0400 +#error Unsupported C library +#endif +static int +attributes_to_mode(DWORD attr) +{ + int m = 0; + if (attr & FILE_ATTRIBUTE_DIRECTORY) + m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */ + else + m |= _S_IFREG; + if (attr & FILE_ATTRIBUTE_READONLY) + m |= 0444; + else + m |= 0666; + return m; +} + +static int +attribute_data_to_stat(WIN32_FILE_ATTRIBUTE_DATA *info, struct win32_stat *result) +{ + memset(result, 0, sizeof(*result)); + result->st_mode = attributes_to_mode(info->dwFileAttributes); + result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; + FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + + return 0; +} + +/* Emulate GetFileAttributesEx[AW] on Windows 95 */ +static int checked = 0; +static BOOL (CALLBACK *gfaxa)(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID); +static BOOL (CALLBACK *gfaxw)(LPCWSTR, GET_FILEEX_INFO_LEVELS, LPVOID); +static void +check_gfax() +{ + HINSTANCE hKernel32; + if (checked) + return; + checked = 1; + hKernel32 = GetModuleHandle("KERNEL32"); + *(FARPROC*)&gfaxa = GetProcAddress(hKernel32, "GetFileAttributesExA"); + *(FARPROC*)&gfaxw = GetProcAddress(hKernel32, "GetFileAttributesExW"); +} + +static BOOL +attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad) +{ + HANDLE hFindFile; + WIN32_FIND_DATAA FileData; + hFindFile = FindFirstFileA(pszFile, &FileData); + if (hFindFile == INVALID_HANDLE_VALUE) + return FALSE; + FindClose(hFindFile); + pfad->dwFileAttributes = FileData.dwFileAttributes; + pfad->ftCreationTime = FileData.ftCreationTime; + pfad->ftLastAccessTime = FileData.ftLastAccessTime; + pfad->ftLastWriteTime = FileData.ftLastWriteTime; + pfad->nFileSizeHigh = FileData.nFileSizeHigh; + pfad->nFileSizeLow = FileData.nFileSizeLow; + return TRUE; +} + +static BOOL +attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad) +{ + HANDLE hFindFile; + WIN32_FIND_DATAW FileData; + hFindFile = FindFirstFileW(pszFile, &FileData); + if (hFindFile == INVALID_HANDLE_VALUE) + return FALSE; + FindClose(hFindFile); + pfad->dwFileAttributes = FileData.dwFileAttributes; + pfad->ftCreationTime = FileData.ftCreationTime; + pfad->ftLastAccessTime = FileData.ftLastAccessTime; + pfad->ftLastWriteTime = FileData.ftLastWriteTime; + pfad->nFileSizeHigh = FileData.nFileSizeHigh; + pfad->nFileSizeLow = FileData.nFileSizeLow; + return TRUE; +} + +static BOOL WINAPI +Py_GetFileAttributesExA(LPCSTR pszFile, + GET_FILEEX_INFO_LEVELS level, + LPVOID pv) +{ + BOOL result; + LPWIN32_FILE_ATTRIBUTE_DATA pfad = pv; + /* First try to use the system's implementation, if that is + available and either succeeds to gives an error other than + that it isn't implemented. */ + check_gfax(); + if (gfaxa) { + result = gfaxa(pszFile, level, pv); + if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return result; + } + /* It's either not present, or not implemented. + Emulate using FindFirstFile. */ + if (level != GetFileExInfoStandard) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + /* Use GetFileAttributes to validate that the file name + does not contain wildcards (which FindFirstFile would + accept). */ + if (GetFileAttributesA(pszFile) == 0xFFFFFFFF) + return FALSE; + return attributes_from_dir(pszFile, pfad); +} + +static BOOL WINAPI +Py_GetFileAttributesExW(LPCWSTR pszFile, + GET_FILEEX_INFO_LEVELS level, + LPVOID pv) +{ + BOOL result; + LPWIN32_FILE_ATTRIBUTE_DATA pfad = pv; + /* First try to use the system's implementation, if that is + available and either succeeds to gives an error other than + that it isn't implemented. */ + check_gfax(); + if (gfaxa) { + result = gfaxw(pszFile, level, pv); + if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return result; + } + /* It's either not present, or not implemented. + Emulate using FindFirstFile. */ + if (level != GetFileExInfoStandard) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + /* Use GetFileAttributes to validate that the file name + does not contain wildcards (which FindFirstFile would + accept). */ + if (GetFileAttributesW(pszFile) == 0xFFFFFFFF) + return FALSE; + return attributes_from_dir_w(pszFile, pfad); +} + +static int +win32_stat(const char* path, struct win32_stat *result) +{ + WIN32_FILE_ATTRIBUTE_DATA info; + int code; + char *dot; + /* XXX not supported on Win95 and NT 3.x */ + if (!Py_GetFileAttributesExA(path, GetFileExInfoStandard, &info)) { + if (GetLastError() != ERROR_SHARING_VIOLATION) { + /* Protocol violation: we explicitly clear errno, instead of + setting it to a POSIX error. Callers should use GetLastError. */ + errno = 0; + return -1; + } else { + /* Could not get attributes on open file. Fall back to + reading the directory. */ + if (!attributes_from_dir(path, &info)) { + /* Very strange. This should not fail now */ + errno = 0; + return -1; + } + } + } + code = attribute_data_to_stat(&info, result); + if (code != 0) + return code; + /* Set S_IFEXEC if it is an .exe, .bat, ... */ + dot = strrchr(path, '.'); + if (dot) { + if (stricmp(dot, ".bat") == 0 || + stricmp(dot, ".cmd") == 0 || + stricmp(dot, ".exe") == 0 || + stricmp(dot, ".com") == 0) + result->st_mode |= 0111; + } + return code; +} + +static int +win32_wstat(const wchar_t* path, struct win32_stat *result) +{ + int code; + const wchar_t *dot; + WIN32_FILE_ATTRIBUTE_DATA info; + /* XXX not supported on Win95 and NT 3.x */ + if (!Py_GetFileAttributesExW(path, GetFileExInfoStandard, &info)) { + if (GetLastError() != ERROR_SHARING_VIOLATION) { + /* Protocol violation: we explicitly clear errno, instead of + setting it to a POSIX error. Callers should use GetLastError. */ + errno = 0; + return -1; + } else { + /* Could not get attributes on open file. Fall back to + reading the directory. */ + if (!attributes_from_dir_w(path, &info)) { + /* Very strange. This should not fail now */ + errno = 0; + return -1; + } + } + } + code = attribute_data_to_stat(&info, result); + if (code < 0) + return code; + /* Set IFEXEC if it is an .exe, .bat, ... */ + dot = wcsrchr(path, '.'); + if (dot) { + if (_wcsicmp(dot, L".bat") == 0 || + _wcsicmp(dot, L".cmd") == 0 || + _wcsicmp(dot, L".exe") == 0 || + _wcsicmp(dot, L".com") == 0) + result->st_mode |= 0111; + } + return code; +} + +static int +win32_fstat(int file_number, struct win32_stat *result) +{ + BY_HANDLE_FILE_INFORMATION info; + HANDLE h; + int type; + + h = (HANDLE)_get_osfhandle(file_number); + + /* Protocol violation: we explicitly clear errno, instead of + setting it to a POSIX error. Callers should use GetLastError. */ + errno = 0; + + if (h == INVALID_HANDLE_VALUE) { + /* This is really a C library error (invalid file handle). + We set the Win32 error to the closes one matching. */ + SetLastError(ERROR_INVALID_HANDLE); + return -1; + } + memset(result, 0, sizeof(*result)); + + type = GetFileType(h); + if (type == FILE_TYPE_UNKNOWN) { + DWORD error = GetLastError(); + if (error != 0) { + return -1; + } + /* else: valid but unknown file */ + } + + if (type != FILE_TYPE_DISK) { + if (type == FILE_TYPE_CHAR) + result->st_mode = _S_IFCHR; + else if (type == FILE_TYPE_PIPE) + result->st_mode = _S_IFIFO; + return 0; + } + + if (!GetFileInformationByHandle(h, &info)) { + return -1; + } + + /* similar to stat() */ + result->st_mode = attributes_to_mode(info.dwFileAttributes); + result->st_size = (((__int64)info.nFileSizeHigh)<<32) + info.nFileSizeLow; + FILE_TIME_to_time_t_nsec(&info.ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); + FILE_TIME_to_time_t_nsec(&info.ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); + FILE_TIME_to_time_t_nsec(&info.ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + /* specific to fstat() */ + result->st_nlink = info.nNumberOfLinks; + result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; + return 0; +} + +#endif /* MS_WINDOWS */ + +PyDoc_STRVAR(stat_result__doc__, +"stat_result: Result from stat or lstat.\n\n\ +This object may be accessed either as a tuple of\n\ + (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\ +or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\ +\n\ +Posix/windows: If your platform supports st_blksize, st_blocks, st_rdev,\n\ +or st_flags, they are available as attributes only.\n\ +\n\ +See os.stat for more information."); + +static PyStructSequence_Field stat_result_fields[] = { + {"st_mode", "protection bits"}, + {"st_ino", "inode"}, + {"st_dev", "device"}, + {"st_nlink", "number of hard links"}, + {"st_uid", "user ID of owner"}, + {"st_gid", "group ID of owner"}, + {"st_size", "total size, in bytes"}, + /* The NULL is replaced with PyStructSequence_UnnamedField later. */ + {NULL, "integer time of last access"}, + {NULL, "integer time of last modification"}, + {NULL, "integer time of last change"}, + {"st_atime", "time of last access"}, + {"st_mtime", "time of last modification"}, + {"st_ctime", "time of last change"}, +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + {"st_blksize", "blocksize for filesystem I/O"}, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + {"st_blocks", "number of blocks allocated"}, +#endif +#ifdef HAVE_STRUCT_STAT_ST_RDEV + {"st_rdev", "device type (if inode device)"}, +#endif +#ifdef HAVE_STRUCT_STAT_ST_FLAGS + {"st_flags", "user defined flags for file"}, +#endif +#ifdef HAVE_STRUCT_STAT_ST_GEN + {"st_gen", "generation number"}, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME + {"st_birthtime", "time of creation"}, +#endif + {0} +}; + +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE +#define ST_BLKSIZE_IDX 13 +#else +#define ST_BLKSIZE_IDX 12 +#endif + +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS +#define ST_BLOCKS_IDX (ST_BLKSIZE_IDX+1) +#else +#define ST_BLOCKS_IDX ST_BLKSIZE_IDX +#endif + +#ifdef HAVE_STRUCT_STAT_ST_RDEV +#define ST_RDEV_IDX (ST_BLOCKS_IDX+1) +#else +#define ST_RDEV_IDX ST_BLOCKS_IDX +#endif + +#ifdef HAVE_STRUCT_STAT_ST_FLAGS +#define ST_FLAGS_IDX (ST_RDEV_IDX+1) +#else +#define ST_FLAGS_IDX ST_RDEV_IDX +#endif + +#ifdef HAVE_STRUCT_STAT_ST_GEN +#define ST_GEN_IDX (ST_FLAGS_IDX+1) +#else +#define ST_GEN_IDX ST_FLAGS_IDX +#endif + +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#define ST_BIRTHTIME_IDX (ST_GEN_IDX+1) +#else +#define ST_BIRTHTIME_IDX ST_GEN_IDX +#endif + +static PyStructSequence_Desc stat_result_desc = { + "stat_result", /* name */ + stat_result__doc__, /* doc */ + stat_result_fields, + 10 +}; + +PyDoc_STRVAR(statvfs_result__doc__, +"statvfs_result: Result from statvfs or fstatvfs.\n\n\ +This object may be accessed either as a tuple of\n\ + (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax),\n\ +or via the attributes f_bsize, f_frsize, f_blocks, f_bfree, and so on.\n\ +\n\ +See os.statvfs for more information."); + +static PyStructSequence_Field statvfs_result_fields[] = { + {"f_bsize", }, + {"f_frsize", }, + {"f_blocks", }, + {"f_bfree", }, + {"f_bavail", }, + {"f_files", }, + {"f_ffree", }, + {"f_favail", }, + {"f_flag", }, + {"f_namemax",}, + {0} +}; + +static PyStructSequence_Desc statvfs_result_desc = { + "statvfs_result", /* name */ + statvfs_result__doc__, /* doc */ + statvfs_result_fields, + 10 +}; + +static int initialized; +static PyTypeObject StatResultType; +static PyTypeObject StatVFSResultType; +static newfunc structseq_new; + +static PyObject * +statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyStructSequence *result; + int i; + + result = (PyStructSequence*)structseq_new(type, args, kwds); + if (!result) + return NULL; + /* If we have been initialized from a tuple, + st_?time might be set to None. Initialize it + from the int slots. */ + for (i = 7; i <= 9; i++) { + if (result->ob_item[i+3] == Py_None) { + Py_DECREF(Py_None); + Py_INCREF(result->ob_item[i]); + result->ob_item[i+3] = result->ob_item[i]; + } + } + return (PyObject*)result; +} + + + +/* If true, st_?time is float. */ +static int _stat_float_times = 1; + +PyDoc_STRVAR(stat_float_times__doc__, +"stat_float_times([newval]) -> oldval\n\n\ +Determine whether os.[lf]stat represents time stamps as float objects.\n\ +If newval is True, future calls to stat() return floats, if it is False,\n\ +future calls return ints. \n\ +If newval is omitted, return the current setting.\n"); + +static PyObject* +stat_float_times(PyObject* self, PyObject *args) +{ + int newval = -1; + if (!PyArg_ParseTuple(args, "|i:stat_float_times", &newval)) + return NULL; + if (newval == -1) + /* Return old value */ + return PyBool_FromLong(_stat_float_times); + _stat_float_times = newval; + Py_INCREF(Py_None); + return Py_None; +} + +static void +fill_time(PyObject *v, int index, time_t sec, unsigned long nsec) +{ + PyObject *fval,*ival; +#if SIZEOF_TIME_T > SIZEOF_LONG + ival = PyLong_FromLongLong((PY_LONG_LONG)sec); +#else + ival = PyInt_FromLong((long)sec); +#endif + if (!ival) + return; + if (_stat_float_times) { + fval = PyFloat_FromDouble(sec + 1e-9*nsec); + } else { + fval = ival; + Py_INCREF(fval); + } + PyStructSequence_SET_ITEM(v, index, ival); + PyStructSequence_SET_ITEM(v, index+3, fval); +} + +/* pack a system stat C structure into the Python stat tuple + (used by posix_stat() and posix_fstat()) */ +static PyObject* +_pystat_fromstructstat(STRUCT_STAT *st) +{ + unsigned long ansec, mnsec, cnsec; + PyObject *v = PyStructSequence_New(&StatResultType); + if (v == NULL) + return NULL; + + PyStructSequence_SET_ITEM(v, 0, PyInt_FromLong((long)st->st_mode)); +#ifdef HAVE_LARGEFILE_SUPPORT + PyStructSequence_SET_ITEM(v, 1, + PyLong_FromLongLong((PY_LONG_LONG)st->st_ino)); +#else + PyStructSequence_SET_ITEM(v, 1, PyInt_FromLong((long)st->st_ino)); +#endif +#if defined(HAVE_LONG_LONG) && !defined(MS_WINDOWS) + PyStructSequence_SET_ITEM(v, 2, + PyLong_FromLongLong((PY_LONG_LONG)st->st_dev)); +#else + PyStructSequence_SET_ITEM(v, 2, PyInt_FromLong((long)st->st_dev)); +#endif + PyStructSequence_SET_ITEM(v, 3, PyInt_FromLong((long)st->st_nlink)); + PyStructSequence_SET_ITEM(v, 4, PyInt_FromLong((long)st->st_uid)); + PyStructSequence_SET_ITEM(v, 5, PyInt_FromLong((long)st->st_gid)); +#ifdef HAVE_LARGEFILE_SUPPORT + PyStructSequence_SET_ITEM(v, 6, + PyLong_FromLongLong((PY_LONG_LONG)st->st_size)); +#else + PyStructSequence_SET_ITEM(v, 6, PyInt_FromLong(st->st_size)); +#endif + +#if defined(HAVE_STAT_TV_NSEC) + ansec = st->st_atim.tv_nsec; + mnsec = st->st_mtim.tv_nsec; + cnsec = st->st_ctim.tv_nsec; +#elif defined(HAVE_STAT_TV_NSEC2) + ansec = st->st_atimespec.tv_nsec; + mnsec = st->st_mtimespec.tv_nsec; + cnsec = st->st_ctimespec.tv_nsec; +#elif defined(HAVE_STAT_NSEC) + ansec = st->st_atime_nsec; + mnsec = st->st_mtime_nsec; + cnsec = st->st_ctime_nsec; +#else + ansec = mnsec = cnsec = 0; +#endif + fill_time(v, 7, st->st_atime, ansec); + fill_time(v, 8, st->st_mtime, mnsec); + fill_time(v, 9, st->st_ctime, cnsec); + +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE + PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX, + PyInt_FromLong((long)st->st_blksize)); +#endif +#ifdef HAVE_STRUCT_STAT_ST_BLOCKS + PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX, + PyInt_FromLong((long)st->st_blocks)); +#endif +#ifdef HAVE_STRUCT_STAT_ST_RDEV + PyStructSequence_SET_ITEM(v, ST_RDEV_IDX, + PyInt_FromLong((long)st->st_rdev)); +#endif +#ifdef HAVE_STRUCT_STAT_ST_GEN + PyStructSequence_SET_ITEM(v, ST_GEN_IDX, + PyInt_FromLong((long)st->st_gen)); +#endif +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME + { + PyObject *val; + unsigned long bsec,bnsec; + bsec = (long)st->st_birthtime; +#ifdef HAVE_STAT_TV_NSEC2 + bnsec = st->st_birthtimespec.tv_nsec; +#else + bnsec = 0; +#endif + if (_stat_float_times) { + val = PyFloat_FromDouble(bsec + 1e-9*bnsec); + } else { + val = PyInt_FromLong((long)bsec); + } + PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, + val); + } +#endif +#ifdef HAVE_STRUCT_STAT_ST_FLAGS + PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, + PyInt_FromLong((long)st->st_flags)); +#endif + + if (PyErr_Occurred()) { + Py_DECREF(v); + return NULL; + } + + return v; +} + +#ifdef MS_WINDOWS + +/* IsUNCRoot -- test whether the supplied path is of the form \\SERVER\SHARE\, + where / can be used in place of \ and the trailing slash is optional. + Both SERVER and SHARE must have at least one character. +*/ + +#define ISSLASHA(c) ((c) == '\\' || (c) == '/') +#define ISSLASHW(c) ((c) == L'\\' || (c) == L'/') +#ifndef ARRAYSIZE +#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0])) +#endif + +static BOOL +IsUNCRootA(char *path, int pathlen) +{ + #define ISSLASH ISSLASHA + + int i, share; + + if (pathlen < 5 || !ISSLASH(path[0]) || !ISSLASH(path[1])) + /* minimum UNCRoot is \\x\y */ + return FALSE; + for (i = 2; i < pathlen ; i++) + if (ISSLASH(path[i])) break; + if (i == 2 || i == pathlen) + /* do not allow \\\SHARE or \\SERVER */ + return FALSE; + share = i+1; + for (i = share; i < pathlen; i++) + if (ISSLASH(path[i])) break; + return (i != share && (i == pathlen || i == pathlen-1)); + + #undef ISSLASH +} + +#ifdef Py_WIN_WIDE_FILENAMES +static BOOL +IsUNCRootW(Py_UNICODE *path, int pathlen) +{ + #define ISSLASH ISSLASHW + + int i, share; + + if (pathlen < 5 || !ISSLASH(path[0]) || !ISSLASH(path[1])) + /* minimum UNCRoot is \\x\y */ + return FALSE; + for (i = 2; i < pathlen ; i++) + if (ISSLASH(path[i])) break; + if (i == 2 || i == pathlen) + /* do not allow \\\SHARE or \\SERVER */ + return FALSE; + share = i+1; + for (i = share; i < pathlen; i++) + if (ISSLASH(path[i])) break; + return (i != share && (i == pathlen || i == pathlen-1)); + + #undef ISSLASH +} +#endif /* Py_WIN_WIDE_FILENAMES */ +#endif /* MS_WINDOWS */ + +static PyObject * +posix_do_stat(PyObject *self, PyObject *args, + char *format, +#ifdef __VMS + int (*statfunc)(const char *, STRUCT_STAT *, ...), +#else + int (*statfunc)(const char *, STRUCT_STAT *), +#endif + char *wformat, + int (*wstatfunc)(const Py_UNICODE *, STRUCT_STAT *)) +{ + STRUCT_STAT st; + char *path = NULL; /* pass this to stat; do not free() it */ + char *pathfree = NULL; /* this memory must be free'd */ + int res; + PyObject *result; + +#ifdef Py_WIN_WIDE_FILENAMES + /* If on wide-character-capable OS see if argument + is Unicode and if so use wide API. */ + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, wformat, &po)) { + Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po); + + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE result OK without + thread lock as it is a simple dereference. */ + res = wstatfunc(wpath, &st); + Py_END_ALLOW_THREADS + + if (res != 0) + return win32_error_unicode("stat", wpath); + return _pystat_fromstructstat(&st); + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } +#endif + + if (!PyArg_ParseTuple(args, format, + Py_FileSystemDefaultEncoding, &path)) + return NULL; + pathfree = path; + + Py_BEGIN_ALLOW_THREADS + res = (*statfunc)(path, &st); + Py_END_ALLOW_THREADS + + if (res != 0) { +#ifdef MS_WINDOWS + result = win32_error("stat", pathfree); +#else + result = posix_error_with_filename(pathfree); +#endif + } + else + result = _pystat_fromstructstat(&st); + + PyMem_Free(pathfree); + return result; +} + +/* POSIX methods */ + +PyDoc_STRVAR(posix_access__doc__, +"access(path, mode) -> True if granted, False otherwise\n\n\ +Use the real uid/gid to test for access to a path. Note that most\n\ +operations will use the effective uid/gid, therefore this routine can\n\ +be used in a suid/sgid environment to test if the invoking user has the\n\ +specified access to the path. The mode argument can be F_OK to test\n\ +existence, or the inclusive-OR of R_OK, W_OK, and X_OK."); + +static PyObject * +posix_access(PyObject *self, PyObject *args) +{ + char *path; + int mode; + +#ifdef Py_WIN_WIDE_FILENAMES + DWORD attr; + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "Ui:access", &po, &mode)) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread lock as + it is a simple dereference. */ + attr = GetFileAttributesW(PyUnicode_AS_UNICODE(po)); + Py_END_ALLOW_THREADS + goto finish; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } + if (!PyArg_ParseTuple(args, "eti:access", + Py_FileSystemDefaultEncoding, &path, &mode)) + return 0; + Py_BEGIN_ALLOW_THREADS + attr = GetFileAttributesA(path); + Py_END_ALLOW_THREADS + PyMem_Free(path); +finish: + if (attr == 0xFFFFFFFF) + /* File does not exist, or cannot read attributes */ + return PyBool_FromLong(0); + /* Access is possible if either write access wasn't requested, or + the file isn't read-only. */ + return PyBool_FromLong(!(mode & 2) || !(attr & FILE_ATTRIBUTE_READONLY)); +#else + int res; + if (!PyArg_ParseTuple(args, "eti:access", + Py_FileSystemDefaultEncoding, &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = access(path, mode); + Py_END_ALLOW_THREADS + PyMem_Free(path); + return PyBool_FromLong(res == 0); +#endif +} + +#ifndef F_OK +#define F_OK 0 +#endif +#ifndef R_OK +#define R_OK 4 +#endif +#ifndef W_OK +#define W_OK 2 +#endif +#ifndef X_OK +#define X_OK 1 +#endif + +#ifdef HAVE_TTYNAME +PyDoc_STRVAR(posix_ttyname__doc__, +"ttyname(fd) -> string\n\n\ +Return the name of the terminal device connected to 'fd'."); + +static PyObject * +posix_ttyname(PyObject *self, PyObject *args) +{ + int id; + char *ret; + + if (!PyArg_ParseTuple(args, "i:ttyname", &id)) + return NULL; + +#if defined(__VMS) + /* file descriptor 0 only, the default input device (stdin) */ + if (id == 0) { + ret = ttyname(); + } + else { + ret = NULL; + } +#else + ret = ttyname(id); +#endif + if (ret == NULL) + return posix_error(); + return PyString_FromString(ret); +} +#endif + +#ifdef HAVE_CTERMID +PyDoc_STRVAR(posix_ctermid__doc__, +"ctermid() -> string\n\n\ +Return the name of the controlling terminal for this process."); + +static PyObject * +posix_ctermid(PyObject *self, PyObject *noargs) +{ + char *ret; + char buffer[L_ctermid]; + +#ifdef USE_CTERMID_R + ret = ctermid_r(buffer); +#else + ret = ctermid(buffer); +#endif + if (ret == NULL) + return posix_error(); + return PyString_FromString(buffer); +} +#endif + +PyDoc_STRVAR(posix_chdir__doc__, +"chdir(path)\n\n\ +Change the current working directory to the specified path."); + +static PyObject * +posix_chdir(PyObject *self, PyObject *args) +{ +#ifdef MS_WINDOWS + return win32_1str(args, "chdir", "s:chdir", win32_chdir, "U:chdir", win32_wchdir); +#elif defined(PYOS_OS2) && defined(PYCC_GCC) + return posix_1str(args, "et:chdir", _chdir2); +#elif defined(__VMS) + return posix_1str(args, "et:chdir", (int (*)(const char *))chdir); +#else + return posix_1str(args, "et:chdir", chdir); +#endif +} + +#ifdef HAVE_FCHDIR +PyDoc_STRVAR(posix_fchdir__doc__, +"fchdir(fildes)\n\n\ +Change to the directory of the given file descriptor. fildes must be\n\ +opened on a directory, not a file."); + +static PyObject * +posix_fchdir(PyObject *self, PyObject *fdobj) +{ + return posix_fildes(fdobj, fchdir); +} +#endif /* HAVE_FCHDIR */ + + +PyDoc_STRVAR(posix_chmod__doc__, +"chmod(path, mode)\n\n\ +Change the access permissions of a file."); + +static PyObject * +posix_chmod(PyObject *self, PyObject *args) +{ + char *path = NULL; + int i; + int res; +#ifdef Py_WIN_WIDE_FILENAMES + DWORD attr; + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "Ui|:chmod", &po, &i)) { + Py_BEGIN_ALLOW_THREADS + attr = GetFileAttributesW(PyUnicode_AS_UNICODE(po)); + if (attr != 0xFFFFFFFF) { + if (i & _S_IWRITE) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + res = SetFileAttributesW(PyUnicode_AS_UNICODE(po), attr); + } + else + res = 0; + Py_END_ALLOW_THREADS + if (!res) + return win32_error_unicode("chmod", + PyUnicode_AS_UNICODE(po)); + Py_INCREF(Py_None); + return Py_None; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } + if (!PyArg_ParseTuple(args, "eti:chmod", Py_FileSystemDefaultEncoding, + &path, &i)) + return NULL; + Py_BEGIN_ALLOW_THREADS + attr = GetFileAttributesA(path); + if (attr != 0xFFFFFFFF) { + if (i & _S_IWRITE) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + res = SetFileAttributesA(path, attr); + } + else + res = 0; + Py_END_ALLOW_THREADS + if (!res) { + win32_error("chmod", path); + PyMem_Free(path); + return NULL; + } + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +#else /* Py_WIN_WIDE_FILENAMES */ + if (!PyArg_ParseTuple(args, "eti:chmod", Py_FileSystemDefaultEncoding, + &path, &i)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = chmod(path, i); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_allocated_filename(path); + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +#endif +} + + +#ifdef HAVE_CHROOT +PyDoc_STRVAR(posix_chroot__doc__, +"chroot(path)\n\n\ +Change root directory to path."); + +static PyObject * +posix_chroot(PyObject *self, PyObject *args) +{ + return posix_1str(args, "et:chroot", chroot); +} +#endif + +#ifdef HAVE_FSYNC +PyDoc_STRVAR(posix_fsync__doc__, +"fsync(fildes)\n\n\ +force write of file with filedescriptor to disk."); + +static PyObject * +posix_fsync(PyObject *self, PyObject *fdobj) +{ + return posix_fildes(fdobj, fsync); +} +#endif /* HAVE_FSYNC */ + +#ifdef HAVE_FDATASYNC + +#ifdef __hpux +extern int fdatasync(int); /* On HP-UX, in libc but not in unistd.h */ +#endif + +PyDoc_STRVAR(posix_fdatasync__doc__, +"fdatasync(fildes)\n\n\ +force write of file with filedescriptor to disk.\n\ + does not force update of metadata."); + +static PyObject * +posix_fdatasync(PyObject *self, PyObject *fdobj) +{ + return posix_fildes(fdobj, fdatasync); +} +#endif /* HAVE_FDATASYNC */ + + +#ifdef HAVE_CHOWN +PyDoc_STRVAR(posix_chown__doc__, +"chown(path, uid, gid)\n\n\ +Change the owner and group id of path to the numeric uid and gid."); + +static PyObject * +posix_chown(PyObject *self, PyObject *args) +{ + char *path = NULL; + int uid, gid; + int res; + if (!PyArg_ParseTuple(args, "etii:chown", + Py_FileSystemDefaultEncoding, &path, + &uid, &gid)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = chown(path, (uid_t) uid, (gid_t) gid); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_allocated_filename(path); + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_CHOWN */ + +#ifdef HAVE_LCHOWN +PyDoc_STRVAR(posix_lchown__doc__, +"lchown(path, uid, gid)\n\n\ +Change the owner and group id of path to the numeric uid and gid.\n\ +This function will not follow symbolic links."); + +static PyObject * +posix_lchown(PyObject *self, PyObject *args) +{ + char *path = NULL; + int uid, gid; + int res; + if (!PyArg_ParseTuple(args, "etii:lchown", + Py_FileSystemDefaultEncoding, &path, + &uid, &gid)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = lchown(path, (uid_t) uid, (gid_t) gid); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_allocated_filename(path); + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_LCHOWN */ + + +#ifdef HAVE_GETCWD +PyDoc_STRVAR(posix_getcwd__doc__, +"getcwd() -> path\n\n\ +Return a string representing the current working directory."); + +static PyObject * +posix_getcwd(PyObject *self, PyObject *noargs) +{ + char buf[1026]; + char *res; + + Py_BEGIN_ALLOW_THREADS +#if defined(PYOS_OS2) && defined(PYCC_GCC) + res = _getcwd2(buf, sizeof buf); +#else + res = getcwd(buf, sizeof buf); +#endif + Py_END_ALLOW_THREADS + if (res == NULL) + return posix_error(); + return PyString_FromString(buf); +} + +#ifdef Py_USING_UNICODE +PyDoc_STRVAR(posix_getcwdu__doc__, +"getcwdu() -> path\n\n\ +Return a unicode string representing the current working directory."); + +static PyObject * +posix_getcwdu(PyObject *self, PyObject *noargs) +{ + char buf[1026]; + char *res; + +#ifdef Py_WIN_WIDE_FILENAMES + DWORD len; + if (unicode_file_names()) { + wchar_t wbuf[1026]; + wchar_t *wbuf2 = wbuf; + PyObject *resobj; + Py_BEGIN_ALLOW_THREADS + len = GetCurrentDirectoryW(sizeof wbuf/ sizeof wbuf[0], wbuf); + /* If the buffer is large enough, len does not include the + terminating \0. If the buffer is too small, len includes + the space needed for the terminator. */ + if (len >= sizeof wbuf/ sizeof wbuf[0]) { + wbuf2 = malloc(len * sizeof(wchar_t)); + if (wbuf2) + len = GetCurrentDirectoryW(len, wbuf2); + } + Py_END_ALLOW_THREADS + if (!wbuf2) { + PyErr_NoMemory(); + return NULL; + } + if (!len) { + if (wbuf2 != wbuf) free(wbuf2); + return win32_error("getcwdu", NULL); + } + resobj = PyUnicode_FromWideChar(wbuf2, len); + if (wbuf2 != wbuf) free(wbuf2); + return resobj; + } +#endif + + Py_BEGIN_ALLOW_THREADS +#if defined(PYOS_OS2) && defined(PYCC_GCC) + res = _getcwd2(buf, sizeof buf); +#else + res = getcwd(buf, sizeof buf); +#endif + Py_END_ALLOW_THREADS + if (res == NULL) + return posix_error(); + return PyUnicode_Decode(buf, strlen(buf), Py_FileSystemDefaultEncoding,"strict"); +} +#endif +#endif + + +#ifdef HAVE_LINK +PyDoc_STRVAR(posix_link__doc__, +"link(src, dst)\n\n\ +Create a hard link to a file."); + +static PyObject * +posix_link(PyObject *self, PyObject *args) +{ + return posix_2str(args, "etet:link", link); +} +#endif /* HAVE_LINK */ + + +PyDoc_STRVAR(posix_listdir__doc__, +"listdir(path) -> list_of_strings\n\n\ +Return a list containing the names of the entries in the directory.\n\ +\n\ + path: path of directory to list\n\ +\n\ +The list is in arbitrary order. It does not include the special\n\ +entries '.' and '..' even if they are present in the directory."); + +static PyObject * +posix_listdir(PyObject *self, PyObject *args) +{ + /* XXX Should redo this putting the (now four) versions of opendir + in separate files instead of having them all here... */ +#if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR) + + PyObject *d, *v; + HANDLE hFindFile; + BOOL result; + WIN32_FIND_DATA FileData; + char namebuf[MAX_PATH+5]; /* Overallocate for \\*.*\0 */ + char *bufptr = namebuf; + Py_ssize_t len = sizeof(namebuf)-5; /* only claim to have space for MAX_PATH */ + +#ifdef Py_WIN_WIDE_FILENAMES + /* If on wide-character-capable OS see if argument + is Unicode and if so use wide API. */ + if (unicode_file_names()) { + PyObject *po; + if (PyArg_ParseTuple(args, "U:listdir", &po)) { + WIN32_FIND_DATAW wFileData; + Py_UNICODE *wnamebuf; + Py_UNICODE wch; + /* Overallocate for \\*.*\0 */ + len = PyUnicode_GET_SIZE(po); + wnamebuf = malloc((len + 5) * sizeof(wchar_t)); + if (!wnamebuf) { + PyErr_NoMemory(); + return NULL; + } + wcscpy(wnamebuf, PyUnicode_AS_UNICODE(po)); + wch = len > 0 ? wnamebuf[len-1] : '\0'; + if (wch != L'/' && wch != L'\\' && wch != L':') + wnamebuf[len++] = L'\\'; + wcscpy(wnamebuf + len, L"*.*"); + if ((d = PyList_New(0)) == NULL) { + free(wnamebuf); + return NULL; + } + hFindFile = FindFirstFileW(wnamebuf, &wFileData); + if (hFindFile == INVALID_HANDLE_VALUE) { + int error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) { + free(wnamebuf); + return d; + } + Py_DECREF(d); + win32_error_unicode("FindFirstFileW", wnamebuf); + free(wnamebuf); + return NULL; + } + do { + /* Skip over . and .. */ + if (wcscmp(wFileData.cFileName, L".") != 0 && + wcscmp(wFileData.cFileName, L"..") != 0) { + v = PyUnicode_FromUnicode(wFileData.cFileName, wcslen(wFileData.cFileName)); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } + Py_BEGIN_ALLOW_THREADS + result = FindNextFileW(hFindFile, &wFileData); + Py_END_ALLOW_THREADS + /* FindNextFile sets error to ERROR_NO_MORE_FILES if + it got to the end of the directory. */ + if (!result && GetLastError() != ERROR_NO_MORE_FILES) { + Py_DECREF(d); + win32_error_unicode("FindNextFileW", wnamebuf); + FindClose(hFindFile); + free(wnamebuf); + return NULL; + } + } while (result == TRUE); + + if (FindClose(hFindFile) == FALSE) { + Py_DECREF(d); + win32_error_unicode("FindClose", wnamebuf); + free(wnamebuf); + return NULL; + } + free(wnamebuf); + return d; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } +#endif + + if (!PyArg_ParseTuple(args, "et#:listdir", + Py_FileSystemDefaultEncoding, &bufptr, &len)) + return NULL; + if (len > 0) { + char ch = namebuf[len-1]; + if (ch != SEP && ch != ALTSEP && ch != ':') + namebuf[len++] = '/'; + } + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + hFindFile = FindFirstFile(namebuf, &FileData); + if (hFindFile == INVALID_HANDLE_VALUE) { + int error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) + return d; + Py_DECREF(d); + return win32_error("FindFirstFile", namebuf); + } + do { + /* Skip over . and .. */ + if (strcmp(FileData.cFileName, ".") != 0 && + strcmp(FileData.cFileName, "..") != 0) { + v = PyString_FromString(FileData.cFileName); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } + Py_BEGIN_ALLOW_THREADS + result = FindNextFile(hFindFile, &FileData); + Py_END_ALLOW_THREADS + /* FindNextFile sets error to ERROR_NO_MORE_FILES if + it got to the end of the directory. */ + if (!result && GetLastError() != ERROR_NO_MORE_FILES) { + Py_DECREF(d); + win32_error("FindNextFile", namebuf); + FindClose(hFindFile); + return NULL; + } + } while (result == TRUE); + + if (FindClose(hFindFile) == FALSE) { + Py_DECREF(d); + return win32_error("FindClose", namebuf); + } + + return d; + +#elif defined(PYOS_OS2) + +#ifndef MAX_PATH +#define MAX_PATH CCHMAXPATH +#endif + char *name, *pt; + Py_ssize_t len; + PyObject *d, *v; + char namebuf[MAX_PATH+5]; + HDIR hdir = 1; + ULONG srchcnt = 1; + FILEFINDBUF3 ep; + APIRET rc; + + if (!PyArg_ParseTuple(args, "t#:listdir", &name, &len)) + return NULL; + if (len >= MAX_PATH) { + PyErr_SetString(PyExc_ValueError, "path too long"); + return NULL; + } + strcpy(namebuf, name); + for (pt = namebuf; *pt; pt++) + if (*pt == ALTSEP) + *pt = SEP; + if (namebuf[len-1] != SEP) + namebuf[len++] = SEP; + strcpy(namebuf + len, "*.*"); + + if ((d = PyList_New(0)) == NULL) + return NULL; + + rc = DosFindFirst(namebuf, /* Wildcard Pattern to Match */ + &hdir, /* Handle to Use While Search Directory */ + FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, + &ep, sizeof(ep), /* Structure to Receive Directory Entry */ + &srchcnt, /* Max and Actual Count of Entries Per Iteration */ + FIL_STANDARD); /* Format of Entry (EAs or Not) */ + + if (rc != NO_ERROR) { + errno = ENOENT; + return posix_error_with_filename(name); + } + + if (srchcnt > 0) { /* If Directory is NOT Totally Empty, */ + do { + if (ep.achName[0] == '.' + && (ep.achName[1] == '\0' || (ep.achName[1] == '.' && ep.achName[2] == '\0'))) + continue; /* Skip Over "." and ".." Names */ + + strcpy(namebuf, ep.achName); + + /* Leave Case of Name Alone -- In Native Form */ + /* (Removed Forced Lowercasing Code) */ + + v = PyString_FromString(namebuf); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } while (DosFindNext(hdir, &ep, sizeof(ep), &srchcnt) == NO_ERROR && srchcnt > 0); + } + + return d; +#else + + char *name = NULL; + PyObject *d, *v; + DIR *dirp; + struct dirent *ep; + int arg_is_unicode = 1; + + errno = 0; + if (!PyArg_ParseTuple(args, "U:listdir", &v)) { + arg_is_unicode = 0; + PyErr_Clear(); + } + if (!PyArg_ParseTuple(args, "et:listdir", Py_FileSystemDefaultEncoding, &name)) + return NULL; + if ((dirp = opendir(name)) == NULL) { + return posix_error_with_allocated_filename(name); + } + if ((d = PyList_New(0)) == NULL) { + closedir(dirp); + PyMem_Free(name); + return NULL; + } + for (;;) { + Py_BEGIN_ALLOW_THREADS + ep = readdir(dirp); + Py_END_ALLOW_THREADS + if (ep == NULL) + break; + if (ep->d_name[0] == '.' && + (NAMLEN(ep) == 1 || + (ep->d_name[1] == '.' && NAMLEN(ep) == 2))) + continue; + v = PyString_FromStringAndSize(ep->d_name, NAMLEN(ep)); + if (v == NULL) { + Py_DECREF(d); + d = NULL; + break; + } +#ifdef Py_USING_UNICODE + if (arg_is_unicode) { + PyObject *w; + + w = PyUnicode_FromEncodedObject(v, + Py_FileSystemDefaultEncoding, + "strict"); + if (w != NULL) { + Py_DECREF(v); + v = w; + } + else { + /* fall back to the original byte string, as + discussed in patch #683592 */ + PyErr_Clear(); + } + } +#endif + if (PyList_Append(d, v) != 0) { + Py_DECREF(v); + Py_DECREF(d); + d = NULL; + break; + } + Py_DECREF(v); + } + if (errno != 0 && d != NULL) { + /* readdir() returned NULL and set errno */ + closedir(dirp); + Py_DECREF(d); + return posix_error_with_allocated_filename(name); + } + closedir(dirp); + PyMem_Free(name); + + return d; + +#endif /* which OS */ +} /* end of posix_listdir */ + +#ifdef MS_WINDOWS +/* A helper function for abspath on win32 */ +static PyObject * +posix__getfullpathname(PyObject *self, PyObject *args) +{ + /* assume encoded strings wont more than double no of chars */ + char inbuf[MAX_PATH*2]; + char *inbufp = inbuf; + Py_ssize_t insize = sizeof(inbuf); + char outbuf[MAX_PATH*2]; + char *temp; +#ifdef Py_WIN_WIDE_FILENAMES + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "U|:_getfullpathname", &po)) { + Py_UNICODE woutbuf[MAX_PATH*2]; + Py_UNICODE *wtemp; + if (!GetFullPathNameW(PyUnicode_AS_UNICODE(po), + sizeof(woutbuf)/sizeof(woutbuf[0]), + woutbuf, &wtemp)) + return win32_error("GetFullPathName", ""); + return PyUnicode_FromUnicode(woutbuf, wcslen(woutbuf)); + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } +#endif + if (!PyArg_ParseTuple (args, "et#:_getfullpathname", + Py_FileSystemDefaultEncoding, &inbufp, + &insize)) + return NULL; + if (!GetFullPathName(inbuf, sizeof(outbuf)/sizeof(outbuf[0]), + outbuf, &temp)) + return win32_error("GetFullPathName", inbuf); + if (PyUnicode_Check(PyTuple_GetItem(args, 0))) { + return PyUnicode_Decode(outbuf, strlen(outbuf), + Py_FileSystemDefaultEncoding, NULL); + } + return PyString_FromString(outbuf); +} /* end of posix__getfullpathname */ +#endif /* MS_WINDOWS */ + +PyDoc_STRVAR(posix_mkdir__doc__, +"mkdir(path [, mode=0777])\n\n\ +Create a directory."); + +static PyObject * +posix_mkdir(PyObject *self, PyObject *args) +{ + int res; + char *path = NULL; + int mode = 0777; + +#ifdef Py_WIN_WIDE_FILENAMES + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "U|i:mkdir", &po, &mode)) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread lock as + it is a simple dereference. */ + res = CreateDirectoryW(PyUnicode_AS_UNICODE(po), NULL); + Py_END_ALLOW_THREADS + if (!res) + return win32_error_unicode("mkdir", PyUnicode_AS_UNICODE(po)); + Py_INCREF(Py_None); + return Py_None; + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } + if (!PyArg_ParseTuple(args, "et|i:mkdir", + Py_FileSystemDefaultEncoding, &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread lock as + it is a simple dereference. */ + res = CreateDirectoryA(path, NULL); + Py_END_ALLOW_THREADS + if (!res) { + win32_error("mkdir", path); + PyMem_Free(path); + return NULL; + } + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +#else + + if (!PyArg_ParseTuple(args, "et|i:mkdir", + Py_FileSystemDefaultEncoding, &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS +#if ( defined(__WATCOMC__) || defined(PYCC_VACPP) ) && !defined(__QNX__) + res = mkdir(path); +#else + res = mkdir(path, mode); +#endif + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_allocated_filename(path); + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +#endif +} + + +/* sys/resource.h is needed for at least: wait3(), wait4(), broken nice. */ +#if defined(HAVE_SYS_RESOURCE_H) +#include <sys/resource.h> +#endif + + +#ifdef HAVE_NICE +PyDoc_STRVAR(posix_nice__doc__, +"nice(inc) -> new_priority\n\n\ +Decrease the priority of process by inc and return the new priority."); + +static PyObject * +posix_nice(PyObject *self, PyObject *args) +{ + int increment, value; + + if (!PyArg_ParseTuple(args, "i:nice", &increment)) + return NULL; + + /* There are two flavours of 'nice': one that returns the new + priority (as required by almost all standards out there) and the + Linux/FreeBSD/BSDI one, which returns '0' on success and advices + the use of getpriority() to get the new priority. + + If we are of the nice family that returns the new priority, we + need to clear errno before the call, and check if errno is filled + before calling posix_error() on a returnvalue of -1, because the + -1 may be the actual new priority! */ + + errno = 0; + value = nice(increment); +#if defined(HAVE_BROKEN_NICE) && defined(HAVE_GETPRIORITY) + if (value == 0) + value = getpriority(PRIO_PROCESS, 0); +#endif + if (value == -1 && errno != 0) + /* either nice() or getpriority() returned an error */ + return posix_error(); + return PyInt_FromLong((long) value); +} +#endif /* HAVE_NICE */ + +PyDoc_STRVAR(posix_rename__doc__, +"rename(old, new)\n\n\ +Rename a file or directory."); + +static PyObject * +posix_rename(PyObject *self, PyObject *args) +{ +#ifdef MS_WINDOWS + PyObject *o1, *o2; + char *p1, *p2; + BOOL result; + if (unicode_file_names()) { + if (!PyArg_ParseTuple(args, "O&O&:rename", + convert_to_unicode, &o1, + convert_to_unicode, &o2)) + PyErr_Clear(); + else { + Py_BEGIN_ALLOW_THREADS + result = MoveFileW(PyUnicode_AsUnicode(o1), + PyUnicode_AsUnicode(o2)); + Py_END_ALLOW_THREADS + Py_DECREF(o1); + Py_DECREF(o2); + if (!result) + return win32_error("rename", NULL); + Py_INCREF(Py_None); + return Py_None; + } + } + if (!PyArg_ParseTuple(args, "ss:rename", &p1, &p2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + result = MoveFileA(p1, p2); + Py_END_ALLOW_THREADS + if (!result) + return win32_error("rename", NULL); + Py_INCREF(Py_None); + return Py_None; +#else + return posix_2str(args, "etet:rename", rename); +#endif +} + + +PyDoc_STRVAR(posix_rmdir__doc__, +"rmdir(path)\n\n\ +Remove a directory."); + +static PyObject * +posix_rmdir(PyObject *self, PyObject *args) +{ +#ifdef MS_WINDOWS + return win32_1str(args, "rmdir", "s:rmdir", RemoveDirectoryA, "U:rmdir", RemoveDirectoryW); +#else + return posix_1str(args, "et:rmdir", rmdir); +#endif +} + + +PyDoc_STRVAR(posix_stat__doc__, +"stat(path) -> stat result\n\n\ +Perform a stat system call on the given path."); + +static PyObject * +posix_stat(PyObject *self, PyObject *args) +{ +#ifdef MS_WINDOWS + return posix_do_stat(self, args, "et:stat", STAT, "U:stat", win32_wstat); +#else + return posix_do_stat(self, args, "et:stat", STAT, NULL, NULL); +#endif +} + + +#ifdef HAVE_SYSTEM +PyDoc_STRVAR(posix_system__doc__, +"system(command) -> exit_status\n\n\ +Execute the command (a string) in a subshell."); + +static PyObject * +posix_system(PyObject *self, PyObject *args) +{ + char *command; + long sts; + if (!PyArg_ParseTuple(args, "s:system", &command)) + return NULL; + Py_BEGIN_ALLOW_THREADS + sts = system(command); + Py_END_ALLOW_THREADS + return PyInt_FromLong(sts); +} +#endif + + +PyDoc_STRVAR(posix_umask__doc__, +"umask(new_mask) -> old_mask\n\n\ +Set the current numeric umask and return the previous umask."); + +static PyObject * +posix_umask(PyObject *self, PyObject *args) +{ + int i; + if (!PyArg_ParseTuple(args, "i:umask", &i)) + return NULL; + i = (int)umask(i); + if (i < 0) + return posix_error(); + return PyInt_FromLong((long)i); +} + + +PyDoc_STRVAR(posix_unlink__doc__, +"unlink(path)\n\n\ +Remove a file (same as remove(path))."); + +PyDoc_STRVAR(posix_remove__doc__, +"remove(path)\n\n\ +Remove a file (same as unlink(path))."); + +static PyObject * +posix_unlink(PyObject *self, PyObject *args) +{ +#ifdef MS_WINDOWS + return win32_1str(args, "remove", "s:remove", DeleteFileA, "U:remove", DeleteFileW); +#else + return posix_1str(args, "et:remove", unlink); +#endif +} + + +#ifdef HAVE_UNAME +PyDoc_STRVAR(posix_uname__doc__, +"uname() -> (sysname, nodename, release, version, machine)\n\n\ +Return a tuple identifying the current operating system."); + +static PyObject * +posix_uname(PyObject *self, PyObject *noargs) +{ + struct utsname u; + int res; + + Py_BEGIN_ALLOW_THREADS + res = uname(&u); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + return Py_BuildValue("(sssss)", + u.sysname, + u.nodename, + u.release, + u.version, + u.machine); +} +#endif /* HAVE_UNAME */ + +static int +extract_time(PyObject *t, long* sec, long* usec) +{ + long intval; + if (PyFloat_Check(t)) { + double tval = PyFloat_AsDouble(t); + PyObject *intobj = t->ob_type->tp_as_number->nb_int(t); + if (!intobj) + return -1; + intval = PyInt_AsLong(intobj); + Py_DECREF(intobj); + if (intval == -1 && PyErr_Occurred()) + return -1; + *sec = intval; + *usec = (long)((tval - intval) * 1e6); /* can't exceed 1000000 */ + if (*usec < 0) + /* If rounding gave us a negative number, + truncate. */ + *usec = 0; + return 0; + } + intval = PyInt_AsLong(t); + if (intval == -1 && PyErr_Occurred()) + return -1; + *sec = intval; + *usec = 0; + return 0; +} + +PyDoc_STRVAR(posix_utime__doc__, +"utime(path, (atime, mtime))\n\ +utime(path, None)\n\n\ +Set the access and modified time of the file to the given values. If the\n\ +second form is used, set the access and modified times to the current time."); + +static PyObject * +posix_utime(PyObject *self, PyObject *args) +{ +#ifdef Py_WIN_WIDE_FILENAMES + PyObject *arg; + PyUnicodeObject *obwpath; + wchar_t *wpath = NULL; + char *apath = NULL; + HANDLE hFile; + long atimesec, mtimesec, ausec, musec; + FILETIME atime, mtime; + PyObject *result = NULL; + + if (unicode_file_names()) { + if (PyArg_ParseTuple(args, "UO|:utime", &obwpath, &arg)) { + wpath = PyUnicode_AS_UNICODE(obwpath); + Py_BEGIN_ALLOW_THREADS + hFile = CreateFileW(wpath, FILE_WRITE_ATTRIBUTES, 0, + NULL, OPEN_EXISTING, 0, NULL); + Py_END_ALLOW_THREADS + if (hFile == INVALID_HANDLE_VALUE) + return win32_error_unicode("utime", wpath); + } else + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } + if (!wpath) { + if (!PyArg_ParseTuple(args, "etO:utime", + Py_FileSystemDefaultEncoding, &apath, &arg)) + return NULL; + Py_BEGIN_ALLOW_THREADS + hFile = CreateFileA(apath, FILE_WRITE_ATTRIBUTES, 0, + NULL, OPEN_EXISTING, 0, NULL); + Py_END_ALLOW_THREADS + if (hFile == INVALID_HANDLE_VALUE) { + win32_error("utime", apath); + PyMem_Free(apath); + return NULL; + } + PyMem_Free(apath); + } + + if (arg == Py_None) { + SYSTEMTIME now; + GetSystemTime(&now); + if (!SystemTimeToFileTime(&now, &mtime) || + !SystemTimeToFileTime(&now, &atime)) { + win32_error("utime", NULL); + goto done; + } + } + else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) { + PyErr_SetString(PyExc_TypeError, + "utime() arg 2 must be a tuple (atime, mtime)"); + goto done; + } + else { + if (extract_time(PyTuple_GET_ITEM(arg, 0), + &atimesec, &ausec) == -1) + goto done; + time_t_to_FILE_TIME(atimesec, 1000*ausec, &atime); + if (extract_time(PyTuple_GET_ITEM(arg, 1), + &mtimesec, &musec) == -1) + goto done; + time_t_to_FILE_TIME(mtimesec, 1000*musec, &mtime); + } + if (!SetFileTime(hFile, NULL, &atime, &mtime)) { + /* Avoid putting the file name into the error here, + as that may confuse the user into believing that + something is wrong with the file, when it also + could be the time stamp that gives a problem. */ + win32_error("utime", NULL); + } + Py_INCREF(Py_None); + result = Py_None; +done: + CloseHandle(hFile); + return result; +#else /* Py_WIN_WIDE_FILENAMES */ + + char *path = NULL; + long atime, mtime, ausec, musec; + int res; + PyObject* arg; + +#if defined(HAVE_UTIMES) + struct timeval buf[2]; +#define ATIME buf[0].tv_sec +#define MTIME buf[1].tv_sec +#elif defined(HAVE_UTIME_H) +/* XXX should define struct utimbuf instead, above */ + struct utimbuf buf; +#define ATIME buf.actime +#define MTIME buf.modtime +#define UTIME_ARG &buf +#else /* HAVE_UTIMES */ + time_t buf[2]; +#define ATIME buf[0] +#define MTIME buf[1] +#define UTIME_ARG buf +#endif /* HAVE_UTIMES */ + + + if (!PyArg_ParseTuple(args, "etO:utime", + Py_FileSystemDefaultEncoding, &path, &arg)) + return NULL; + if (arg == Py_None) { + /* optional time values not given */ + Py_BEGIN_ALLOW_THREADS + res = utime(path, NULL); + Py_END_ALLOW_THREADS + } + else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) { + PyErr_SetString(PyExc_TypeError, + "utime() arg 2 must be a tuple (atime, mtime)"); + PyMem_Free(path); + return NULL; + } + else { + if (extract_time(PyTuple_GET_ITEM(arg, 0), + &atime, &ausec) == -1) { + PyMem_Free(path); + return NULL; + } + if (extract_time(PyTuple_GET_ITEM(arg, 1), + &mtime, &musec) == -1) { + PyMem_Free(path); + return NULL; + } + ATIME = atime; + MTIME = mtime; +#ifdef HAVE_UTIMES + buf[0].tv_usec = ausec; + buf[1].tv_usec = musec; + Py_BEGIN_ALLOW_THREADS + res = utimes(path, buf); + Py_END_ALLOW_THREADS +#else + Py_BEGIN_ALLOW_THREADS + res = utime(path, UTIME_ARG); + Py_END_ALLOW_THREADS +#endif /* HAVE_UTIMES */ + } + if (res < 0) { + return posix_error_with_allocated_filename(path); + } + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +#undef UTIME_ARG +#undef ATIME +#undef MTIME +#endif /* Py_WIN_WIDE_FILENAMES */ +} + + +/* Process operations */ + +PyDoc_STRVAR(posix__exit__doc__, +"_exit(status)\n\n\ +Exit to the system with specified status, without normal exit processing."); + +static PyObject * +posix__exit(PyObject *self, PyObject *args) +{ + int sts; + if (!PyArg_ParseTuple(args, "i:_exit", &sts)) + return NULL; + _exit(sts); + return NULL; /* Make gcc -Wall happy */ +} + +#if defined(HAVE_EXECV) || defined(HAVE_SPAWNV) +static void +free_string_array(char **array, Py_ssize_t count) +{ + Py_ssize_t i; + for (i = 0; i < count; i++) + PyMem_Free(array[i]); + PyMem_DEL(array); +} +#endif + + +#ifdef HAVE_EXECV +PyDoc_STRVAR(posix_execv__doc__, +"execv(path, args)\n\n\ +Execute an executable path with arguments, replacing current process.\n\ +\n\ + path: path of executable file\n\ + args: tuple or list of strings"); + +static PyObject * +posix_execv(PyObject *self, PyObject *args) +{ + char *path; + PyObject *argv; + char **argvlist; + Py_ssize_t i, argc; + PyObject *(*getitem)(PyObject *, Py_ssize_t); + + /* execv has two arguments: (path, argv), where + argv is a list or tuple of strings. */ + + if (!PyArg_ParseTuple(args, "etO:execv", + Py_FileSystemDefaultEncoding, + &path, &argv)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, "execv() arg 2 must be a tuple or list"); + PyMem_Free(path); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyMem_Free(path); + return PyErr_NoMemory(); + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), "et", + Py_FileSystemDefaultEncoding, + &argvlist[i])) { + free_string_array(argvlist, i); + PyErr_SetString(PyExc_TypeError, + "execv() arg 2 must contain only strings"); + PyMem_Free(path); + return NULL; + + } + } + argvlist[argc] = NULL; + + execv(path, argvlist); + + /* If we get here it's definitely an error */ + + free_string_array(argvlist, argc); + PyMem_Free(path); + return posix_error(); +} + + +PyDoc_STRVAR(posix_execve__doc__, +"execve(path, args, env)\n\n\ +Execute a path with arguments and environment, replacing current process.\n\ +\n\ + path: path of executable file\n\ + args: tuple or list of arguments\n\ + env: dictionary of strings mapping to strings"); + +static PyObject * +posix_execve(PyObject *self, PyObject *args) +{ + char *path; + PyObject *argv, *env; + char **argvlist; + char **envlist; + PyObject *key, *val, *keys=NULL, *vals=NULL; + Py_ssize_t i, pos, argc, envc; + PyObject *(*getitem)(PyObject *, Py_ssize_t); + Py_ssize_t lastarg = 0; + + /* execve has three arguments: (path, argv, env), where + argv is a list or tuple of strings and env is a dictionary + like posix.environ. */ + + if (!PyArg_ParseTuple(args, "etOO:execve", + Py_FileSystemDefaultEncoding, + &path, &argv, &env)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, + "execve() arg 2 must be a tuple or list"); + goto fail_0; + } + if (!PyMapping_Check(env)) { + PyErr_SetString(PyExc_TypeError, + "execve() arg 3 must be a mapping object"); + goto fail_0; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyErr_NoMemory(); + goto fail_0; + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), + "et;execve() arg 2 must contain only strings", + Py_FileSystemDefaultEncoding, + &argvlist[i])) + { + lastarg = i; + goto fail_1; + } + } + lastarg = argc; + argvlist[argc] = NULL; + + i = PyMapping_Size(env); + if (i < 0) + goto fail_1; + envlist = PyMem_NEW(char *, i + 1); + if (envlist == NULL) { + PyErr_NoMemory(); + goto fail_1; + } + envc = 0; + keys = PyMapping_Keys(env); + vals = PyMapping_Values(env); + if (!keys || !vals) + goto fail_2; + if (!PyList_Check(keys) || !PyList_Check(vals)) { + PyErr_SetString(PyExc_TypeError, + "execve(): env.keys() or env.values() is not a list"); + goto fail_2; + } + + for (pos = 0; pos < i; pos++) { + char *p, *k, *v; + size_t len; + + key = PyList_GetItem(keys, pos); + val = PyList_GetItem(vals, pos); + if (!key || !val) + goto fail_2; + + if (!PyArg_Parse( + key, + "s;execve() arg 3 contains a non-string key", + &k) || + !PyArg_Parse( + val, + "s;execve() arg 3 contains a non-string value", + &v)) + { + goto fail_2; + } + +#if defined(PYOS_OS2) + /* Omit Pseudo-Env Vars that Would Confuse Programs if Passed On */ + if (stricmp(k, "BEGINLIBPATH") != 0 && stricmp(k, "ENDLIBPATH") != 0) { +#endif + len = PyString_Size(key) + PyString_Size(val) + 2; + p = PyMem_NEW(char, len); + if (p == NULL) { + PyErr_NoMemory(); + goto fail_2; + } + PyOS_snprintf(p, len, "%s=%s", k, v); + envlist[envc++] = p; +#if defined(PYOS_OS2) + } +#endif + } + envlist[envc] = 0; + + execve(path, argvlist, envlist); + + /* If we get here it's definitely an error */ + + (void) posix_error(); + + fail_2: + while (--envc >= 0) + PyMem_DEL(envlist[envc]); + PyMem_DEL(envlist); + fail_1: + free_string_array(argvlist, lastarg); + Py_XDECREF(vals); + Py_XDECREF(keys); + fail_0: + PyMem_Free(path); + return NULL; +} +#endif /* HAVE_EXECV */ + + +#ifdef HAVE_SPAWNV +PyDoc_STRVAR(posix_spawnv__doc__, +"spawnv(mode, path, args)\n\n\ +Execute the program 'path' in a new process.\n\ +\n\ + mode: mode of process creation\n\ + path: path of executable file\n\ + args: tuple or list of strings"); + +static PyObject * +posix_spawnv(PyObject *self, PyObject *args) +{ + char *path; + PyObject *argv; + char **argvlist; + int mode, i; + Py_ssize_t argc; + Py_intptr_t spawnval; + PyObject *(*getitem)(PyObject *, Py_ssize_t); + + /* spawnv has three arguments: (mode, path, argv), where + argv is a list or tuple of strings. */ + + if (!PyArg_ParseTuple(args, "ietO:spawnv", &mode, + Py_FileSystemDefaultEncoding, + &path, &argv)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, + "spawnv() arg 2 must be a tuple or list"); + PyMem_Free(path); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyMem_Free(path); + return PyErr_NoMemory(); + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), "et", + Py_FileSystemDefaultEncoding, + &argvlist[i])) { + free_string_array(argvlist, i); + PyErr_SetString( + PyExc_TypeError, + "spawnv() arg 2 must contain only strings"); + PyMem_Free(path); + return NULL; + } + } + argvlist[argc] = NULL; + +#if defined(PYOS_OS2) && defined(PYCC_GCC) + Py_BEGIN_ALLOW_THREADS + spawnval = spawnv(mode, path, argvlist); + Py_END_ALLOW_THREADS +#else + if (mode == _OLD_P_OVERLAY) + mode = _P_OVERLAY; + + Py_BEGIN_ALLOW_THREADS + spawnval = _spawnv(mode, path, argvlist); + Py_END_ALLOW_THREADS +#endif + + free_string_array(argvlist, argc); + PyMem_Free(path); + + if (spawnval == -1) + return posix_error(); + else +#if SIZEOF_LONG == SIZEOF_VOID_P + return Py_BuildValue("l", (long) spawnval); +#else + return Py_BuildValue("L", (PY_LONG_LONG) spawnval); +#endif +} + + +PyDoc_STRVAR(posix_spawnve__doc__, +"spawnve(mode, path, args, env)\n\n\ +Execute the program 'path' in a new process.\n\ +\n\ + mode: mode of process creation\n\ + path: path of executable file\n\ + args: tuple or list of arguments\n\ + env: dictionary of strings mapping to strings"); + +static PyObject * +posix_spawnve(PyObject *self, PyObject *args) +{ + char *path; + PyObject *argv, *env; + char **argvlist; + char **envlist; + PyObject *key, *val, *keys=NULL, *vals=NULL, *res=NULL; + int mode, pos, envc; + Py_ssize_t argc, i; + Py_intptr_t spawnval; + PyObject *(*getitem)(PyObject *, Py_ssize_t); + Py_ssize_t lastarg = 0; + + /* spawnve has four arguments: (mode, path, argv, env), where + argv is a list or tuple of strings and env is a dictionary + like posix.environ. */ + + if (!PyArg_ParseTuple(args, "ietOO:spawnve", &mode, + Py_FileSystemDefaultEncoding, + &path, &argv, &env)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, + "spawnve() arg 2 must be a tuple or list"); + goto fail_0; + } + if (!PyMapping_Check(env)) { + PyErr_SetString(PyExc_TypeError, + "spawnve() arg 3 must be a mapping object"); + goto fail_0; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyErr_NoMemory(); + goto fail_0; + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), + "et;spawnve() arg 2 must contain only strings", + Py_FileSystemDefaultEncoding, + &argvlist[i])) + { + lastarg = i; + goto fail_1; + } + } + lastarg = argc; + argvlist[argc] = NULL; + + i = PyMapping_Size(env); + if (i < 0) + goto fail_1; + envlist = PyMem_NEW(char *, i + 1); + if (envlist == NULL) { + PyErr_NoMemory(); + goto fail_1; + } + envc = 0; + keys = PyMapping_Keys(env); + vals = PyMapping_Values(env); + if (!keys || !vals) + goto fail_2; + if (!PyList_Check(keys) || !PyList_Check(vals)) { + PyErr_SetString(PyExc_TypeError, + "spawnve(): env.keys() or env.values() is not a list"); + goto fail_2; + } + + for (pos = 0; pos < i; pos++) { + char *p, *k, *v; + size_t len; + + key = PyList_GetItem(keys, pos); + val = PyList_GetItem(vals, pos); + if (!key || !val) + goto fail_2; + + if (!PyArg_Parse( + key, + "s;spawnve() arg 3 contains a non-string key", + &k) || + !PyArg_Parse( + val, + "s;spawnve() arg 3 contains a non-string value", + &v)) + { + goto fail_2; + } + len = PyString_Size(key) + PyString_Size(val) + 2; + p = PyMem_NEW(char, len); + if (p == NULL) { + PyErr_NoMemory(); + goto fail_2; + } + PyOS_snprintf(p, len, "%s=%s", k, v); + envlist[envc++] = p; + } + envlist[envc] = 0; + +#if defined(PYOS_OS2) && defined(PYCC_GCC) + Py_BEGIN_ALLOW_THREADS + spawnval = spawnve(mode, path, argvlist, envlist); + Py_END_ALLOW_THREADS +#else + if (mode == _OLD_P_OVERLAY) + mode = _P_OVERLAY; + + Py_BEGIN_ALLOW_THREADS + spawnval = _spawnve(mode, path, argvlist, envlist); + Py_END_ALLOW_THREADS +#endif + + if (spawnval == -1) + (void) posix_error(); + else +#if SIZEOF_LONG == SIZEOF_VOID_P + res = Py_BuildValue("l", (long) spawnval); +#else + res = Py_BuildValue("L", (PY_LONG_LONG) spawnval); +#endif + + fail_2: + while (--envc >= 0) + PyMem_DEL(envlist[envc]); + PyMem_DEL(envlist); + fail_1: + free_string_array(argvlist, lastarg); + Py_XDECREF(vals); + Py_XDECREF(keys); + fail_0: + PyMem_Free(path); + return res; +} + +/* OS/2 supports spawnvp & spawnvpe natively */ +#if defined(PYOS_OS2) +PyDoc_STRVAR(posix_spawnvp__doc__, +"spawnvp(mode, file, args)\n\n\ +Execute the program 'file' in a new process, using the environment\n\ +search path to find the file.\n\ +\n\ + mode: mode of process creation\n\ + file: executable file name\n\ + args: tuple or list of strings"); + +static PyObject * +posix_spawnvp(PyObject *self, PyObject *args) +{ + char *path; + PyObject *argv; + char **argvlist; + int mode, i, argc; + Py_intptr_t spawnval; + PyObject *(*getitem)(PyObject *, Py_ssize_t); + + /* spawnvp has three arguments: (mode, path, argv), where + argv is a list or tuple of strings. */ + + if (!PyArg_ParseTuple(args, "ietO:spawnvp", &mode, + Py_FileSystemDefaultEncoding, + &path, &argv)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, + "spawnvp() arg 2 must be a tuple or list"); + PyMem_Free(path); + return NULL; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyMem_Free(path); + return PyErr_NoMemory(); + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), "et", + Py_FileSystemDefaultEncoding, + &argvlist[i])) { + free_string_array(argvlist, i); + PyErr_SetString( + PyExc_TypeError, + "spawnvp() arg 2 must contain only strings"); + PyMem_Free(path); + return NULL; + } + } + argvlist[argc] = NULL; + + Py_BEGIN_ALLOW_THREADS +#if defined(PYCC_GCC) + spawnval = spawnvp(mode, path, argvlist); +#else + spawnval = _spawnvp(mode, path, argvlist); +#endif + Py_END_ALLOW_THREADS + + free_string_array(argvlist, argc); + PyMem_Free(path); + + if (spawnval == -1) + return posix_error(); + else + return Py_BuildValue("l", (long) spawnval); +} + + +PyDoc_STRVAR(posix_spawnvpe__doc__, +"spawnvpe(mode, file, args, env)\n\n\ +Execute the program 'file' in a new process, using the environment\n\ +search path to find the file.\n\ +\n\ + mode: mode of process creation\n\ + file: executable file name\n\ + args: tuple or list of arguments\n\ + env: dictionary of strings mapping to strings"); + +static PyObject * +posix_spawnvpe(PyObject *self, PyObject *args) +{ + char *path; + PyObject *argv, *env; + char **argvlist; + char **envlist; + PyObject *key, *val, *keys=NULL, *vals=NULL, *res=NULL; + int mode, i, pos, argc, envc; + Py_intptr_t spawnval; + PyObject *(*getitem)(PyObject *, Py_ssize_t); + int lastarg = 0; + + /* spawnvpe has four arguments: (mode, path, argv, env), where + argv is a list or tuple of strings and env is a dictionary + like posix.environ. */ + + if (!PyArg_ParseTuple(args, "ietOO:spawnvpe", &mode, + Py_FileSystemDefaultEncoding, + &path, &argv, &env)) + return NULL; + if (PyList_Check(argv)) { + argc = PyList_Size(argv); + getitem = PyList_GetItem; + } + else if (PyTuple_Check(argv)) { + argc = PyTuple_Size(argv); + getitem = PyTuple_GetItem; + } + else { + PyErr_SetString(PyExc_TypeError, + "spawnvpe() arg 2 must be a tuple or list"); + goto fail_0; + } + if (!PyMapping_Check(env)) { + PyErr_SetString(PyExc_TypeError, + "spawnvpe() arg 3 must be a mapping object"); + goto fail_0; + } + + argvlist = PyMem_NEW(char *, argc+1); + if (argvlist == NULL) { + PyErr_NoMemory(); + goto fail_0; + } + for (i = 0; i < argc; i++) { + if (!PyArg_Parse((*getitem)(argv, i), + "et;spawnvpe() arg 2 must contain only strings", + Py_FileSystemDefaultEncoding, + &argvlist[i])) + { + lastarg = i; + goto fail_1; + } + } + lastarg = argc; + argvlist[argc] = NULL; + + i = PyMapping_Size(env); + if (i < 0) + goto fail_1; + envlist = PyMem_NEW(char *, i + 1); + if (envlist == NULL) { + PyErr_NoMemory(); + goto fail_1; + } + envc = 0; + keys = PyMapping_Keys(env); + vals = PyMapping_Values(env); + if (!keys || !vals) + goto fail_2; + if (!PyList_Check(keys) || !PyList_Check(vals)) { + PyErr_SetString(PyExc_TypeError, + "spawnvpe(): env.keys() or env.values() is not a list"); + goto fail_2; + } + + for (pos = 0; pos < i; pos++) { + char *p, *k, *v; + size_t len; + + key = PyList_GetItem(keys, pos); + val = PyList_GetItem(vals, pos); + if (!key || !val) + goto fail_2; + + if (!PyArg_Parse( + key, + "s;spawnvpe() arg 3 contains a non-string key", + &k) || + !PyArg_Parse( + val, + "s;spawnvpe() arg 3 contains a non-string value", + &v)) + { + goto fail_2; + } + len = PyString_Size(key) + PyString_Size(val) + 2; + p = PyMem_NEW(char, len); + if (p == NULL) { + PyErr_NoMemory(); + goto fail_2; + } + PyOS_snprintf(p, len, "%s=%s", k, v); + envlist[envc++] = p; + } + envlist[envc] = 0; + + Py_BEGIN_ALLOW_THREADS +#if defined(PYCC_GCC) + spawnval = spawnve(mode, path, argvlist, envlist); +#else + spawnval = _spawnve(mode, path, argvlist, envlist); +#endif + Py_END_ALLOW_THREADS + + if (spawnval == -1) + (void) posix_error(); + else + res = Py_BuildValue("l", (long) spawnval); + + fail_2: + while (--envc >= 0) + PyMem_DEL(envlist[envc]); + PyMem_DEL(envlist); + fail_1: + free_string_array(argvlist, lastarg); + Py_XDECREF(vals); + Py_XDECREF(keys); + fail_0: + PyMem_Free(path); + return res; +} +#endif /* PYOS_OS2 */ +#endif /* HAVE_SPAWNV */ + + +#ifdef HAVE_FORK1 +PyDoc_STRVAR(posix_fork1__doc__, +"fork1() -> pid\n\n\ +Fork a child process with a single multiplexed (i.e., not bound) thread.\n\ +\n\ +Return 0 to child process and PID of child to parent process."); + +static PyObject * +posix_fork1(PyObject *self, PyObject *noargs) +{ + int pid = fork1(); + if (pid == -1) + return posix_error(); + PyOS_AfterFork(); + return PyInt_FromLong((long)pid); +} +#endif + + +#ifdef HAVE_FORK +PyDoc_STRVAR(posix_fork__doc__, +"fork() -> pid\n\n\ +Fork a child process.\n\ +Return 0 to child process and PID of child to parent process."); + +static PyObject * +posix_fork(PyObject *self, PyObject *noargs) +{ + int pid = fork(); + if (pid == -1) + return posix_error(); + if (pid == 0) + PyOS_AfterFork(); + return PyInt_FromLong((long)pid); +} +#endif + +/* AIX uses /dev/ptc but is otherwise the same as /dev/ptmx */ +/* IRIX has both /dev/ptc and /dev/ptmx, use ptmx */ +#if defined(HAVE_DEV_PTC) && !defined(HAVE_DEV_PTMX) +#define DEV_PTY_FILE "/dev/ptc" +#define HAVE_DEV_PTMX +#else +#define DEV_PTY_FILE "/dev/ptmx" +#endif + +#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX) +#ifdef HAVE_PTY_H +#include <pty.h> +#else +#ifdef HAVE_LIBUTIL_H +#include <libutil.h> +#endif /* HAVE_LIBUTIL_H */ +#endif /* HAVE_PTY_H */ +#ifdef HAVE_STROPTS_H +#include <stropts.h> +#endif +#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX */ + +#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) +PyDoc_STRVAR(posix_openpty__doc__, +"openpty() -> (master_fd, slave_fd)\n\n\ +Open a pseudo-terminal, returning open fd's for both master and slave end.\n"); + +static PyObject * +posix_openpty(PyObject *self, PyObject *noargs) +{ + int master_fd, slave_fd; +#ifndef HAVE_OPENPTY + char * slave_name; +#endif +#if defined(HAVE_DEV_PTMX) && !defined(HAVE_OPENPTY) && !defined(HAVE__GETPTY) + PyOS_sighandler_t sig_saved; +#ifdef sun + extern char *ptsname(int fildes); +#endif +#endif + +#ifdef HAVE_OPENPTY + if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) != 0) + return posix_error(); +#elif defined(HAVE__GETPTY) + slave_name = _getpty(&master_fd, O_RDWR, 0666, 0); + if (slave_name == NULL) + return posix_error(); + + slave_fd = open(slave_name, O_RDWR); + if (slave_fd < 0) + return posix_error(); +#else + master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */ + if (master_fd < 0) + return posix_error(); + sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL); + /* change permission of slave */ + if (grantpt(master_fd) < 0) { + PyOS_setsig(SIGCHLD, sig_saved); + return posix_error(); + } + /* unlock slave */ + if (unlockpt(master_fd) < 0) { + PyOS_setsig(SIGCHLD, sig_saved); + return posix_error(); + } + PyOS_setsig(SIGCHLD, sig_saved); + slave_name = ptsname(master_fd); /* get name of slave */ + if (slave_name == NULL) + return posix_error(); + slave_fd = open(slave_name, O_RDWR | O_NOCTTY); /* open slave */ + if (slave_fd < 0) + return posix_error(); +#if !defined(__CYGWIN__) && !defined(HAVE_DEV_PTC) + ioctl(slave_fd, I_PUSH, "ptem"); /* push ptem */ + ioctl(slave_fd, I_PUSH, "ldterm"); /* push ldterm */ +#ifndef __hpux + ioctl(slave_fd, I_PUSH, "ttcompat"); /* push ttcompat */ +#endif /* __hpux */ +#endif /* HAVE_CYGWIN */ +#endif /* HAVE_OPENPTY */ + + return Py_BuildValue("(ii)", master_fd, slave_fd); + +} +#endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */ + +#ifdef HAVE_FORKPTY +PyDoc_STRVAR(posix_forkpty__doc__, +"forkpty() -> (pid, master_fd)\n\n\ +Fork a new process with a new pseudo-terminal as controlling tty.\n\n\ +Like fork(), return 0 as pid to child process, and PID of child to parent.\n\ +To both, return fd of newly opened pseudo-terminal.\n"); + +static PyObject * +posix_forkpty(PyObject *self, PyObject *noargs) +{ + int master_fd = -1, pid; + + pid = forkpty(&master_fd, NULL, NULL, NULL); + if (pid == -1) + return posix_error(); + if (pid == 0) + PyOS_AfterFork(); + return Py_BuildValue("(ii)", pid, master_fd); +} +#endif + +#ifdef HAVE_GETEGID +PyDoc_STRVAR(posix_getegid__doc__, +"getegid() -> egid\n\n\ +Return the current process's effective group id."); + +static PyObject * +posix_getegid(PyObject *self, PyObject *noargs) +{ + return PyInt_FromLong((long)getegid()); +} +#endif + + +#ifdef HAVE_GETEUID +PyDoc_STRVAR(posix_geteuid__doc__, +"geteuid() -> euid\n\n\ +Return the current process's effective user id."); + +static PyObject * +posix_geteuid(PyObject *self, PyObject *noargs) +{ + return PyInt_FromLong((long)geteuid()); +} +#endif + + +#ifdef HAVE_GETGID +PyDoc_STRVAR(posix_getgid__doc__, +"getgid() -> gid\n\n\ +Return the current process's group id."); + +static PyObject * +posix_getgid(PyObject *self, PyObject *noargs) +{ + return PyInt_FromLong((long)getgid()); +} +#endif + + +PyDoc_STRVAR(posix_getpid__doc__, +"getpid() -> pid\n\n\ +Return the current process id"); + +static PyObject * +posix_getpid(PyObject *self, PyObject *noargs) +{ + return PyInt_FromLong((long)getpid()); +} + + +#ifdef HAVE_GETGROUPS +PyDoc_STRVAR(posix_getgroups__doc__, +"getgroups() -> list of group IDs\n\n\ +Return list of supplemental group IDs for the process."); + +static PyObject * +posix_getgroups(PyObject *self, PyObject *noargs) +{ + PyObject *result = NULL; + +#ifdef NGROUPS_MAX +#define MAX_GROUPS NGROUPS_MAX +#else + /* defined to be 16 on Solaris7, so this should be a small number */ +#define MAX_GROUPS 64 +#endif + gid_t grouplist[MAX_GROUPS]; + int n; + + n = getgroups(MAX_GROUPS, grouplist); + if (n < 0) + posix_error(); + else { + result = PyList_New(n); + if (result != NULL) { + int i; + for (i = 0; i < n; ++i) { + PyObject *o = PyInt_FromLong((long)grouplist[i]); + if (o == NULL) { + Py_DECREF(result); + result = NULL; + break; + } + PyList_SET_ITEM(result, i, o); + } + } + } + + return result; +} +#endif + +#ifdef HAVE_GETPGID +PyDoc_STRVAR(posix_getpgid__doc__, +"getpgid(pid) -> pgid\n\n\ +Call the system call getpgid()."); + +static PyObject * +posix_getpgid(PyObject *self, PyObject *args) +{ + int pid, pgid; + if (!PyArg_ParseTuple(args, "i:getpgid", &pid)) + return NULL; + pgid = getpgid(pid); + if (pgid < 0) + return posix_error(); + return PyInt_FromLong((long)pgid); +} +#endif /* HAVE_GETPGID */ + + +#ifdef HAVE_GETPGRP +PyDoc_STRVAR(posix_getpgrp__doc__, +"getpgrp() -> pgrp\n\n\ +Return the current process group id."); + +static PyObject * +posix_getpgrp(PyObject *self, PyObject *noargs) +{ +#ifdef GETPGRP_HAVE_ARG + return PyInt_FromLong((long)getpgrp(0)); +#else /* GETPGRP_HAVE_ARG */ + return PyInt_FromLong((long)getpgrp()); +#endif /* GETPGRP_HAVE_ARG */ +} +#endif /* HAVE_GETPGRP */ + + +#ifdef HAVE_SETPGRP +PyDoc_STRVAR(posix_setpgrp__doc__, +"setpgrp()\n\n\ +Make this process a session leader."); + +static PyObject * +posix_setpgrp(PyObject *self, PyObject *noargs) +{ +#ifdef SETPGRP_HAVE_ARG + if (setpgrp(0, 0) < 0) +#else /* SETPGRP_HAVE_ARG */ + if (setpgrp() < 0) +#endif /* SETPGRP_HAVE_ARG */ + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + +#endif /* HAVE_SETPGRP */ + +#ifdef HAVE_GETPPID +PyDoc_STRVAR(posix_getppid__doc__, +"getppid() -> ppid\n\n\ +Return the parent's process id."); + +static PyObject * +posix_getppid(PyObject *self, PyObject *noargs) +{ + return PyInt_FromLong((long)getppid()); +} +#endif + + +#ifdef HAVE_GETLOGIN +PyDoc_STRVAR(posix_getlogin__doc__, +"getlogin() -> string\n\n\ +Return the actual login name."); + +static PyObject * +posix_getlogin(PyObject *self, PyObject *noargs) +{ + PyObject *result = NULL; + char *name; + int old_errno = errno; + + errno = 0; + name = getlogin(); + if (name == NULL) { + if (errno) + posix_error(); + else + PyErr_SetString(PyExc_OSError, + "unable to determine login name"); + } + else + result = PyString_FromString(name); + errno = old_errno; + + return result; +} +#endif + +#ifdef HAVE_GETUID +PyDoc_STRVAR(posix_getuid__doc__, +"getuid() -> uid\n\n\ +Return the current process's user id."); + +static PyObject * +posix_getuid(PyObject *self, PyObject *noargs) +{ + return PyInt_FromLong((long)getuid()); +} +#endif + + +#ifdef HAVE_KILL +PyDoc_STRVAR(posix_kill__doc__, +"kill(pid, sig)\n\n\ +Kill a process with a signal."); + +static PyObject * +posix_kill(PyObject *self, PyObject *args) +{ + int pid, sig; + if (!PyArg_ParseTuple(args, "ii:kill", &pid, &sig)) + return NULL; +#if defined(PYOS_OS2) && !defined(PYCC_GCC) + if (sig == XCPT_SIGNAL_INTR || sig == XCPT_SIGNAL_BREAK) { + APIRET rc; + if ((rc = DosSendSignalException(pid, sig)) != NO_ERROR) + return os2_error(rc); + + } else if (sig == XCPT_SIGNAL_KILLPROC) { + APIRET rc; + if ((rc = DosKillProcess(DKP_PROCESS, pid)) != NO_ERROR) + return os2_error(rc); + + } else + return NULL; /* Unrecognized Signal Requested */ +#else + if (kill(pid, sig) == -1) + return posix_error(); +#endif + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_KILLPG +PyDoc_STRVAR(posix_killpg__doc__, +"killpg(pgid, sig)\n\n\ +Kill a process group with a signal."); + +static PyObject * +posix_killpg(PyObject *self, PyObject *args) +{ + int pgid, sig; + if (!PyArg_ParseTuple(args, "ii:killpg", &pgid, &sig)) + return NULL; + if (killpg(pgid, sig) == -1) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_PLOCK + +#ifdef HAVE_SYS_LOCK_H +#include <sys/lock.h> +#endif + +PyDoc_STRVAR(posix_plock__doc__, +"plock(op)\n\n\ +Lock program segments into memory."); + +static PyObject * +posix_plock(PyObject *self, PyObject *args) +{ + int op; + if (!PyArg_ParseTuple(args, "i:plock", &op)) + return NULL; + if (plock(op) == -1) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#ifdef HAVE_POPEN +PyDoc_STRVAR(posix_popen__doc__, +"popen(command [, mode='r' [, bufsize]]) -> pipe\n\n\ +Open a pipe to/from a command returning a file object."); + +#if defined(PYOS_OS2) +#if defined(PYCC_VACPP) +static int +async_system(const char *command) +{ + char errormsg[256], args[1024]; + RESULTCODES rcodes; + APIRET rc; + + char *shell = getenv("COMSPEC"); + if (!shell) + shell = "cmd"; + + /* avoid overflowing the argument buffer */ + if (strlen(shell) + 3 + strlen(command) >= 1024) + return ERROR_NOT_ENOUGH_MEMORY + + args[0] = '\0'; + strcat(args, shell); + strcat(args, "/c "); + strcat(args, command); + + /* execute asynchronously, inheriting the environment */ + rc = DosExecPgm(errormsg, + sizeof(errormsg), + EXEC_ASYNC, + args, + NULL, + &rcodes, + shell); + return rc; +} + +static FILE * +popen(const char *command, const char *mode, int pipesize, int *err) +{ + int oldfd, tgtfd; + HFILE pipeh[2]; + APIRET rc; + + /* mode determines which of stdin or stdout is reconnected to + * the pipe to the child + */ + if (strchr(mode, 'r') != NULL) { + tgt_fd = 1; /* stdout */ + } else if (strchr(mode, 'w')) { + tgt_fd = 0; /* stdin */ + } else { + *err = ERROR_INVALID_ACCESS; + return NULL; + } + + /* setup the pipe */ + if ((rc = DosCreatePipe(&pipeh[0], &pipeh[1], pipesize)) != NO_ERROR) { + *err = rc; + return NULL; + } + + /* prevent other threads accessing stdio */ + DosEnterCritSec(); + + /* reconnect stdio and execute child */ + oldfd = dup(tgtfd); + close(tgtfd); + if (dup2(pipeh[tgtfd], tgtfd) == 0) { + DosClose(pipeh[tgtfd]); + rc = async_system(command); + } + + /* restore stdio */ + dup2(oldfd, tgtfd); + close(oldfd); + + /* allow other threads access to stdio */ + DosExitCritSec(); + + /* if execution of child was successful return file stream */ + if (rc == NO_ERROR) + return fdopen(pipeh[1 - tgtfd], mode); + else { + DosClose(pipeh[1 - tgtfd]); + *err = rc; + return NULL; + } +} + +static PyObject * +posix_popen(PyObject *self, PyObject *args) +{ + char *name; + char *mode = "r"; + int err, bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "s|si:popen", &name, &mode, &bufsize)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fp = popen(name, mode, (bufsize > 0) ? bufsize : 4096, &err); + Py_END_ALLOW_THREADS + if (fp == NULL) + return os2_error(err); + + f = PyFile_FromFile(fp, name, mode, fclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + +#elif defined(PYCC_GCC) + +/* standard posix version of popen() support */ +static PyObject * +posix_popen(PyObject *self, PyObject *args) +{ + char *name; + char *mode = "r"; + int bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "s|si:popen", &name, &mode, &bufsize)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fp = popen(name, mode); + Py_END_ALLOW_THREADS + if (fp == NULL) + return posix_error(); + f = PyFile_FromFile(fp, name, mode, pclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + +/* fork() under OS/2 has lots'o'warts + * EMX supports pipe() and spawn*() so we can synthesize popen[234]() + * most of this code is a ripoff of the win32 code, but using the + * capabilities of EMX's C library routines + */ + +/* These tell _PyPopen() whether to return 1, 2, or 3 file objects. */ +#define POPEN_1 1 +#define POPEN_2 2 +#define POPEN_3 3 +#define POPEN_4 4 + +static PyObject *_PyPopen(char *, int, int, int); +static int _PyPclose(FILE *file); + +/* + * Internal dictionary mapping popen* file pointers to process handles, + * for use when retrieving the process exit code. See _PyPclose() below + * for more information on this dictionary's use. + */ +static PyObject *_PyPopenProcs = NULL; + +/* os2emx version of popen2() + * + * The result of this function is a pipe (file) connected to the + * process's stdin, and a pipe connected to the process's stdout. + */ + +static PyObject * +os2emx_popen2(PyObject *self, PyObject *args) +{ + PyObject *f; + int tm=0; + + char *cmdstring; + char *mode = "t"; + int bufsize = -1; + if (!PyArg_ParseTuple(args, "s|si:popen2", &cmdstring, &mode, &bufsize)) + return NULL; + + if (*mode == 't') + tm = O_TEXT; + else if (*mode != 'b') { + PyErr_SetString(PyExc_ValueError, "mode must be 't' or 'b'"); + return NULL; + } else + tm = O_BINARY; + + f = _PyPopen(cmdstring, tm, POPEN_2, bufsize); + + return f; +} + +/* + * Variation on os2emx.popen2 + * + * The result of this function is 3 pipes - the process's stdin, + * stdout and stderr + */ + +static PyObject * +os2emx_popen3(PyObject *self, PyObject *args) +{ + PyObject *f; + int tm = 0; + + char *cmdstring; + char *mode = "t"; + int bufsize = -1; + if (!PyArg_ParseTuple(args, "s|si:popen3", &cmdstring, &mode, &bufsize)) + return NULL; + + if (*mode == 't') + tm = O_TEXT; + else if (*mode != 'b') { + PyErr_SetString(PyExc_ValueError, "mode must be 't' or 'b'"); + return NULL; + } else + tm = O_BINARY; + + f = _PyPopen(cmdstring, tm, POPEN_3, bufsize); + + return f; +} + +/* + * Variation on os2emx.popen2 + * + * The result of this function is 2 pipes - the processes stdin, + * and stdout+stderr combined as a single pipe. + */ + +static PyObject * +os2emx_popen4(PyObject *self, PyObject *args) +{ + PyObject *f; + int tm = 0; + + char *cmdstring; + char *mode = "t"; + int bufsize = -1; + if (!PyArg_ParseTuple(args, "s|si:popen4", &cmdstring, &mode, &bufsize)) + return NULL; + + if (*mode == 't') + tm = O_TEXT; + else if (*mode != 'b') { + PyErr_SetString(PyExc_ValueError, "mode must be 't' or 'b'"); + return NULL; + } else + tm = O_BINARY; + + f = _PyPopen(cmdstring, tm, POPEN_4, bufsize); + + return f; +} + +/* a couple of structures for convenient handling of multiple + * file handles and pipes + */ +struct file_ref +{ + int handle; + int flags; +}; + +struct pipe_ref +{ + int rd; + int wr; +}; + +/* The following code is derived from the win32 code */ + +static PyObject * +_PyPopen(char *cmdstring, int mode, int n, int bufsize) +{ + struct file_ref stdio[3]; + struct pipe_ref p_fd[3]; + FILE *p_s[3]; + int file_count, i, pipe_err, pipe_pid; + char *shell, *sh_name, *opt, *rd_mode, *wr_mode; + PyObject *f, *p_f[3]; + + /* file modes for subsequent fdopen's on pipe handles */ + if (mode == O_TEXT) + { + rd_mode = "rt"; + wr_mode = "wt"; + } + else + { + rd_mode = "rb"; + wr_mode = "wb"; + } + + /* prepare shell references */ + if ((shell = getenv("EMXSHELL")) == NULL) + if ((shell = getenv("COMSPEC")) == NULL) + { + errno = ENOENT; + return posix_error(); + } + + sh_name = _getname(shell); + if (stricmp(sh_name, "cmd.exe") == 0 || stricmp(sh_name, "4os2.exe") == 0) + opt = "/c"; + else + opt = "-c"; + + /* save current stdio fds + their flags, and set not inheritable */ + i = pipe_err = 0; + while (pipe_err >= 0 && i < 3) + { + pipe_err = stdio[i].handle = dup(i); + stdio[i].flags = fcntl(i, F_GETFD, 0); + fcntl(stdio[i].handle, F_SETFD, stdio[i].flags | FD_CLOEXEC); + i++; + } + if (pipe_err < 0) + { + /* didn't get them all saved - clean up and bail out */ + int saved_err = errno; + while (i-- > 0) + { + close(stdio[i].handle); + } + errno = saved_err; + return posix_error(); + } + + /* create pipe ends */ + file_count = 2; + if (n == POPEN_3) + file_count = 3; + i = pipe_err = 0; + while ((pipe_err == 0) && (i < file_count)) + pipe_err = pipe((int *)&p_fd[i++]); + if (pipe_err < 0) + { + /* didn't get them all made - clean up and bail out */ + while (i-- > 0) + { + close(p_fd[i].wr); + close(p_fd[i].rd); + } + errno = EPIPE; + return posix_error(); + } + + /* change the actual standard IO streams over temporarily, + * making the retained pipe ends non-inheritable + */ + pipe_err = 0; + + /* - stdin */ + if (dup2(p_fd[0].rd, 0) == 0) + { + close(p_fd[0].rd); + i = fcntl(p_fd[0].wr, F_GETFD, 0); + fcntl(p_fd[0].wr, F_SETFD, i | FD_CLOEXEC); + if ((p_s[0] = fdopen(p_fd[0].wr, wr_mode)) == NULL) + { + close(p_fd[0].wr); + pipe_err = -1; + } + } + else + { + pipe_err = -1; + } + + /* - stdout */ + if (pipe_err == 0) + { + if (dup2(p_fd[1].wr, 1) == 1) + { + close(p_fd[1].wr); + i = fcntl(p_fd[1].rd, F_GETFD, 0); + fcntl(p_fd[1].rd, F_SETFD, i | FD_CLOEXEC); + if ((p_s[1] = fdopen(p_fd[1].rd, rd_mode)) == NULL) + { + close(p_fd[1].rd); + pipe_err = -1; + } + } + else + { + pipe_err = -1; + } + } + + /* - stderr, as required */ + if (pipe_err == 0) + switch (n) + { + case POPEN_3: + { + if (dup2(p_fd[2].wr, 2) == 2) + { + close(p_fd[2].wr); + i = fcntl(p_fd[2].rd, F_GETFD, 0); + fcntl(p_fd[2].rd, F_SETFD, i | FD_CLOEXEC); + if ((p_s[2] = fdopen(p_fd[2].rd, rd_mode)) == NULL) + { + close(p_fd[2].rd); + pipe_err = -1; + } + } + else + { + pipe_err = -1; + } + break; + } + + case POPEN_4: + { + if (dup2(1, 2) != 2) + { + pipe_err = -1; + } + break; + } + } + + /* spawn the child process */ + if (pipe_err == 0) + { + pipe_pid = spawnlp(P_NOWAIT, shell, shell, opt, cmdstring, (char *)0); + if (pipe_pid == -1) + { + pipe_err = -1; + } + else + { + /* save the PID into the FILE structure + * NOTE: this implementation doesn't actually + * take advantage of this, but do it for + * completeness - AIM Apr01 + */ + for (i = 0; i < file_count; i++) + p_s[i]->_pid = pipe_pid; + } + } + + /* reset standard IO to normal */ + for (i = 0; i < 3; i++) + { + dup2(stdio[i].handle, i); + fcntl(i, F_SETFD, stdio[i].flags); + close(stdio[i].handle); + } + + /* if any remnant problems, clean up and bail out */ + if (pipe_err < 0) + { + for (i = 0; i < 3; i++) + { + close(p_fd[i].rd); + close(p_fd[i].wr); + } + errno = EPIPE; + return posix_error_with_filename(cmdstring); + } + + /* build tuple of file objects to return */ + if ((p_f[0] = PyFile_FromFile(p_s[0], cmdstring, wr_mode, _PyPclose)) != NULL) + PyFile_SetBufSize(p_f[0], bufsize); + if ((p_f[1] = PyFile_FromFile(p_s[1], cmdstring, rd_mode, _PyPclose)) != NULL) + PyFile_SetBufSize(p_f[1], bufsize); + if (n == POPEN_3) + { + if ((p_f[2] = PyFile_FromFile(p_s[2], cmdstring, rd_mode, _PyPclose)) != NULL) + PyFile_SetBufSize(p_f[0], bufsize); + f = PyTuple_Pack(3, p_f[0], p_f[1], p_f[2]); + } + else + f = PyTuple_Pack(2, p_f[0], p_f[1]); + + /* + * Insert the files we've created into the process dictionary + * all referencing the list with the process handle and the + * initial number of files (see description below in _PyPclose). + * Since if _PyPclose later tried to wait on a process when all + * handles weren't closed, it could create a deadlock with the + * child, we spend some energy here to try to ensure that we + * either insert all file handles into the dictionary or none + * at all. It's a little clumsy with the various popen modes + * and variable number of files involved. + */ + if (!_PyPopenProcs) + { + _PyPopenProcs = PyDict_New(); + } + + if (_PyPopenProcs) + { + PyObject *procObj, *pidObj, *intObj, *fileObj[3]; + int ins_rc[3]; + + fileObj[0] = fileObj[1] = fileObj[2] = NULL; + ins_rc[0] = ins_rc[1] = ins_rc[2] = 0; + + procObj = PyList_New(2); + pidObj = PyInt_FromLong((long) pipe_pid); + intObj = PyInt_FromLong((long) file_count); + + if (procObj && pidObj && intObj) + { + PyList_SetItem(procObj, 0, pidObj); + PyList_SetItem(procObj, 1, intObj); + + fileObj[0] = PyLong_FromVoidPtr(p_s[0]); + if (fileObj[0]) + { + ins_rc[0] = PyDict_SetItem(_PyPopenProcs, + fileObj[0], + procObj); + } + fileObj[1] = PyLong_FromVoidPtr(p_s[1]); + if (fileObj[1]) + { + ins_rc[1] = PyDict_SetItem(_PyPopenProcs, + fileObj[1], + procObj); + } + if (file_count >= 3) + { + fileObj[2] = PyLong_FromVoidPtr(p_s[2]); + if (fileObj[2]) + { + ins_rc[2] = PyDict_SetItem(_PyPopenProcs, + fileObj[2], + procObj); + } + } + + if (ins_rc[0] < 0 || !fileObj[0] || + ins_rc[1] < 0 || (file_count > 1 && !fileObj[1]) || + ins_rc[2] < 0 || (file_count > 2 && !fileObj[2])) + { + /* Something failed - remove any dictionary + * entries that did make it. + */ + if (!ins_rc[0] && fileObj[0]) + { + PyDict_DelItem(_PyPopenProcs, + fileObj[0]); + } + if (!ins_rc[1] && fileObj[1]) + { + PyDict_DelItem(_PyPopenProcs, + fileObj[1]); + } + if (!ins_rc[2] && fileObj[2]) + { + PyDict_DelItem(_PyPopenProcs, + fileObj[2]); + } + } + } + + /* + * Clean up our localized references for the dictionary keys + * and value since PyDict_SetItem will Py_INCREF any copies + * that got placed in the dictionary. + */ + Py_XDECREF(procObj); + Py_XDECREF(fileObj[0]); + Py_XDECREF(fileObj[1]); + Py_XDECREF(fileObj[2]); + } + + /* Child is launched. */ + return f; +} + +/* + * Wrapper for fclose() to use for popen* files, so we can retrieve the + * exit code for the child process and return as a result of the close. + * + * This function uses the _PyPopenProcs dictionary in order to map the + * input file pointer to information about the process that was + * originally created by the popen* call that created the file pointer. + * The dictionary uses the file pointer as a key (with one entry + * inserted for each file returned by the original popen* call) and a + * single list object as the value for all files from a single call. + * The list object contains the Win32 process handle at [0], and a file + * count at [1], which is initialized to the total number of file + * handles using that list. + * + * This function closes whichever handle it is passed, and decrements + * the file count in the dictionary for the process handle pointed to + * by this file. On the last close (when the file count reaches zero), + * this function will wait for the child process and then return its + * exit code as the result of the close() operation. This permits the + * files to be closed in any order - it is always the close() of the + * final handle that will return the exit code. + * + * NOTE: This function is currently called with the GIL released. + * hence we use the GILState API to manage our state. + */ + +static int _PyPclose(FILE *file) +{ + int result; + int exit_code; + int pipe_pid; + PyObject *procObj, *pidObj, *intObj, *fileObj; + int file_count; +#ifdef WITH_THREAD + PyGILState_STATE state; +#endif + + /* Close the file handle first, to ensure it can't block the + * child from exiting if it's the last handle. + */ + result = fclose(file); + +#ifdef WITH_THREAD + state = PyGILState_Ensure(); +#endif + if (_PyPopenProcs) + { + if ((fileObj = PyLong_FromVoidPtr(file)) != NULL && + (procObj = PyDict_GetItem(_PyPopenProcs, + fileObj)) != NULL && + (pidObj = PyList_GetItem(procObj,0)) != NULL && + (intObj = PyList_GetItem(procObj,1)) != NULL) + { + pipe_pid = (int) PyInt_AsLong(pidObj); + file_count = (int) PyInt_AsLong(intObj); + + if (file_count > 1) + { + /* Still other files referencing process */ + file_count--; + PyList_SetItem(procObj,1, + PyInt_FromLong((long) file_count)); + } + else + { + /* Last file for this process */ + if (result != EOF && + waitpid(pipe_pid, &exit_code, 0) == pipe_pid) + { + /* extract exit status */ + if (WIFEXITED(exit_code)) + { + result = WEXITSTATUS(exit_code); + } + else + { + errno = EPIPE; + result = -1; + } + } + else + { + /* Indicate failure - this will cause the file object + * to raise an I/O error and translate the last + * error code from errno. We do have a problem with + * last errors that overlap the normal errno table, + * but that's a consistent problem with the file object. + */ + result = -1; + } + } + + /* Remove this file pointer from dictionary */ + PyDict_DelItem(_PyPopenProcs, fileObj); + + if (PyDict_Size(_PyPopenProcs) == 0) + { + Py_DECREF(_PyPopenProcs); + _PyPopenProcs = NULL; + } + + } /* if object retrieval ok */ + + Py_XDECREF(fileObj); + } /* if _PyPopenProcs */ + +#ifdef WITH_THREAD + PyGILState_Release(state); +#endif + return result; +} + +#endif /* PYCC_??? */ + +#elif defined(MS_WINDOWS) + +/* + * Portable 'popen' replacement for Win32. + * + * Written by Bill Tutt <billtut@microsoft.com>. Minor tweaks + * and 2.0 integration by Fredrik Lundh <fredrik@pythonware.com> + * Return code handling by David Bolen <db3l@fitlinxx.com>. + */ + +#include <malloc.h> +#include <io.h> +#include <fcntl.h> + +/* These tell _PyPopen() wether to return 1, 2, or 3 file objects. */ +#define POPEN_1 1 +#define POPEN_2 2 +#define POPEN_3 3 +#define POPEN_4 4 + +static PyObject *_PyPopen(char *, int, int); +static int _PyPclose(FILE *file); + +/* + * Internal dictionary mapping popen* file pointers to process handles, + * for use when retrieving the process exit code. See _PyPclose() below + * for more information on this dictionary's use. + */ +static PyObject *_PyPopenProcs = NULL; + + +/* popen that works from a GUI. + * + * The result of this function is a pipe (file) connected to the + * processes stdin or stdout, depending on the requested mode. + */ + +static PyObject * +posix_popen(PyObject *self, PyObject *args) +{ + PyObject *f; + int tm = 0; + + char *cmdstring; + char *mode = "r"; + int bufsize = -1; + if (!PyArg_ParseTuple(args, "s|si:popen", &cmdstring, &mode, &bufsize)) + return NULL; + + if (*mode == 'r') + tm = _O_RDONLY; + else if (*mode != 'w') { + PyErr_SetString(PyExc_ValueError, "popen() arg 2 must be 'r' or 'w'"); + return NULL; + } else + tm = _O_WRONLY; + + if (bufsize != -1) { + PyErr_SetString(PyExc_ValueError, "popen() arg 3 must be -1"); + return NULL; + } + + if (*(mode+1) == 't') + f = _PyPopen(cmdstring, tm | _O_TEXT, POPEN_1); + else if (*(mode+1) == 'b') + f = _PyPopen(cmdstring, tm | _O_BINARY, POPEN_1); + else + f = _PyPopen(cmdstring, tm | _O_TEXT, POPEN_1); + + return f; +} + +/* Variation on win32pipe.popen + * + * The result of this function is a pipe (file) connected to the + * process's stdin, and a pipe connected to the process's stdout. + */ + +static PyObject * +win32_popen2(PyObject *self, PyObject *args) +{ + PyObject *f; + int tm=0; + + char *cmdstring; + char *mode = "t"; + int bufsize = -1; + if (!PyArg_ParseTuple(args, "s|si:popen2", &cmdstring, &mode, &bufsize)) + return NULL; + + if (*mode == 't') + tm = _O_TEXT; + else if (*mode != 'b') { + PyErr_SetString(PyExc_ValueError, "popen2() arg 2 must be 't' or 'b'"); + return NULL; + } else + tm = _O_BINARY; + + if (bufsize != -1) { + PyErr_SetString(PyExc_ValueError, "popen2() arg 3 must be -1"); + return NULL; + } + + f = _PyPopen(cmdstring, tm, POPEN_2); + + return f; +} + +/* + * Variation on <om win32pipe.popen> + * + * The result of this function is 3 pipes - the process's stdin, + * stdout and stderr + */ + +static PyObject * +win32_popen3(PyObject *self, PyObject *args) +{ + PyObject *f; + int tm = 0; + + char *cmdstring; + char *mode = "t"; + int bufsize = -1; + if (!PyArg_ParseTuple(args, "s|si:popen3", &cmdstring, &mode, &bufsize)) + return NULL; + + if (*mode == 't') + tm = _O_TEXT; + else if (*mode != 'b') { + PyErr_SetString(PyExc_ValueError, "popen3() arg 2 must be 't' or 'b'"); + return NULL; + } else + tm = _O_BINARY; + + if (bufsize != -1) { + PyErr_SetString(PyExc_ValueError, "popen3() arg 3 must be -1"); + return NULL; + } + + f = _PyPopen(cmdstring, tm, POPEN_3); + + return f; +} + +/* + * Variation on win32pipe.popen + * + * The result of this function is 2 pipes - the processes stdin, + * and stdout+stderr combined as a single pipe. + */ + +static PyObject * +win32_popen4(PyObject *self, PyObject *args) +{ + PyObject *f; + int tm = 0; + + char *cmdstring; + char *mode = "t"; + int bufsize = -1; + if (!PyArg_ParseTuple(args, "s|si:popen4", &cmdstring, &mode, &bufsize)) + return NULL; + + if (*mode == 't') + tm = _O_TEXT; + else if (*mode != 'b') { + PyErr_SetString(PyExc_ValueError, "popen4() arg 2 must be 't' or 'b'"); + return NULL; + } else + tm = _O_BINARY; + + if (bufsize != -1) { + PyErr_SetString(PyExc_ValueError, "popen4() arg 3 must be -1"); + return NULL; + } + + f = _PyPopen(cmdstring, tm, POPEN_4); + + return f; +} + +static BOOL +_PyPopenCreateProcess(char *cmdstring, + HANDLE hStdin, + HANDLE hStdout, + HANDLE hStderr, + HANDLE *hProcess) +{ + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + DWORD dwProcessFlags = 0; /* no NEW_CONSOLE by default for Ctrl+C handling */ + char *s1,*s2, *s3 = " /c "; + const char *szConsoleSpawn = "w9xpopen.exe"; + int i; + Py_ssize_t x; + + if (i = GetEnvironmentVariable("COMSPEC",NULL,0)) { + char *comshell; + + s1 = (char *)alloca(i); + if (!(x = GetEnvironmentVariable("COMSPEC", s1, i))) + /* x < i, so x fits into an integer */ + return (int)x; + + /* Explicitly check if we are using COMMAND.COM. If we are + * then use the w9xpopen hack. + */ + comshell = s1 + x; + while (comshell >= s1 && *comshell != '\\') + --comshell; + ++comshell; + + if (GetVersion() < 0x80000000 && + _stricmp(comshell, "command.com") != 0) { + /* NT/2000 and not using command.com. */ + x = i + strlen(s3) + strlen(cmdstring) + 1; + s2 = (char *)alloca(x); + ZeroMemory(s2, x); + PyOS_snprintf(s2, x, "%s%s%s", s1, s3, cmdstring); + } + else { + /* + * Oh gag, we're on Win9x or using COMMAND.COM. Use + * the workaround listed in KB: Q150956 + */ + char modulepath[_MAX_PATH]; + struct stat statinfo; + GetModuleFileName(NULL, modulepath, sizeof(modulepath)); + for (x = i = 0; modulepath[i]; i++) + if (modulepath[i] == SEP) + x = i+1; + modulepath[x] = '\0'; + /* Create the full-name to w9xpopen, so we can test it exists */ + strncat(modulepath, + szConsoleSpawn, + (sizeof(modulepath)/sizeof(modulepath[0])) + -strlen(modulepath)); + if (stat(modulepath, &statinfo) != 0) { + /* Eeek - file-not-found - possibly an embedding + situation - see if we can locate it in sys.prefix + */ + strncpy(modulepath, + Py_GetExecPrefix(), + sizeof(modulepath)/sizeof(modulepath[0])); + if (modulepath[strlen(modulepath)-1] != '\\') + strcat(modulepath, "\\"); + strncat(modulepath, + szConsoleSpawn, + (sizeof(modulepath)/sizeof(modulepath[0])) + -strlen(modulepath)); + /* No where else to look - raise an easily identifiable + error, rather than leaving Windows to report + "file not found" - as the user is probably blissfully + unaware this shim EXE is used, and it will confuse them. + (well, it confused me for a while ;-) + */ + if (stat(modulepath, &statinfo) != 0) { + PyErr_Format(PyExc_RuntimeError, + "Can not locate '%s' which is needed " + "for popen to work with your shell " + "or platform.", + szConsoleSpawn); + return FALSE; + } + } + x = i + strlen(s3) + strlen(cmdstring) + 1 + + strlen(modulepath) + + strlen(szConsoleSpawn) + 1; + + s2 = (char *)alloca(x); + ZeroMemory(s2, x); + /* To maintain correct argument passing semantics, + we pass the command-line as it stands, and allow + quoting to be applied. w9xpopen.exe will then + use its argv vector, and re-quote the necessary + args for the ultimate child process. + */ + PyOS_snprintf( + s2, x, + "\"%s\" %s%s%s", + modulepath, + s1, + s3, + cmdstring); + /* Not passing CREATE_NEW_CONSOLE has been known to + cause random failures on win9x. Specifically a + dialog: + "Your program accessed mem currently in use at xxx" + and a hopeful warning about the stability of your + system. + Cost is Ctrl+C wont kill children, but anyone + who cares can have a go! + */ + dwProcessFlags |= CREATE_NEW_CONSOLE; + } + } + + /* Could be an else here to try cmd.exe / command.com in the path + Now we'll just error out.. */ + else { + PyErr_SetString(PyExc_RuntimeError, + "Cannot locate a COMSPEC environment variable to " + "use as the shell"); + return FALSE; + } + + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; + siStartInfo.hStdInput = hStdin; + siStartInfo.hStdOutput = hStdout; + siStartInfo.hStdError = hStderr; + siStartInfo.wShowWindow = SW_HIDE; + + if (CreateProcess(NULL, + s2, + NULL, + NULL, + TRUE, + dwProcessFlags, + NULL, + NULL, + &siStartInfo, + &piProcInfo) ) { + /* Close the handles now so anyone waiting is woken. */ + CloseHandle(piProcInfo.hThread); + + /* Return process handle */ + *hProcess = piProcInfo.hProcess; + return TRUE; + } + win32_error("CreateProcess", s2); + return FALSE; +} + +/* The following code is based off of KB: Q190351 */ + +static PyObject * +_PyPopen(char *cmdstring, int mode, int n) +{ + HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr, + hChildStderrRd, hChildStderrWr, hChildStdinWrDup, hChildStdoutRdDup, + hChildStderrRdDup, hProcess; /* hChildStdoutWrDup; */ + + SECURITY_ATTRIBUTES saAttr; + BOOL fSuccess; + int fd1, fd2, fd3; + FILE *f1, *f2, *f3; + long file_count; + PyObject *f; + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) + return win32_error("CreatePipe", NULL); + + /* Create new output read handle and the input write handle. Set + * the inheritance properties to FALSE. Otherwise, the child inherits + * these handles; resulting in non-closeable handles to the pipes + * being created. */ + fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, + GetCurrentProcess(), &hChildStdinWrDup, 0, + FALSE, + DUPLICATE_SAME_ACCESS); + if (!fSuccess) + return win32_error("DuplicateHandle", NULL); + + /* Close the inheritable version of ChildStdin + that we're using. */ + CloseHandle(hChildStdinWr); + + if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) + return win32_error("CreatePipe", NULL); + + fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, + GetCurrentProcess(), &hChildStdoutRdDup, 0, + FALSE, DUPLICATE_SAME_ACCESS); + if (!fSuccess) + return win32_error("DuplicateHandle", NULL); + + /* Close the inheritable version of ChildStdout + that we're using. */ + CloseHandle(hChildStdoutRd); + + if (n != POPEN_4) { + if (!CreatePipe(&hChildStderrRd, &hChildStderrWr, &saAttr, 0)) + return win32_error("CreatePipe", NULL); + fSuccess = DuplicateHandle(GetCurrentProcess(), + hChildStderrRd, + GetCurrentProcess(), + &hChildStderrRdDup, 0, + FALSE, DUPLICATE_SAME_ACCESS); + if (!fSuccess) + return win32_error("DuplicateHandle", NULL); + /* Close the inheritable version of ChildStdErr that we're using. */ + CloseHandle(hChildStderrRd); + } + + switch (n) { + case POPEN_1: + switch (mode & (_O_RDONLY | _O_TEXT | _O_BINARY | _O_WRONLY)) { + case _O_WRONLY | _O_TEXT: + /* Case for writing to child Stdin in text mode. */ + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); + f1 = _fdopen(fd1, "w"); + f = PyFile_FromFile(f1, cmdstring, "w", _PyPclose); + PyFile_SetBufSize(f, 0); + /* We don't care about these pipes anymore, so close them. */ + CloseHandle(hChildStdoutRdDup); + CloseHandle(hChildStderrRdDup); + break; + + case _O_RDONLY | _O_TEXT: + /* Case for reading from child Stdout in text mode. */ + fd1 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); + f1 = _fdopen(fd1, "r"); + f = PyFile_FromFile(f1, cmdstring, "r", _PyPclose); + PyFile_SetBufSize(f, 0); + /* We don't care about these pipes anymore, so close them. */ + CloseHandle(hChildStdinWrDup); + CloseHandle(hChildStderrRdDup); + break; + + case _O_RDONLY | _O_BINARY: + /* Case for readinig from child Stdout in binary mode. */ + fd1 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); + f1 = _fdopen(fd1, "rb"); + f = PyFile_FromFile(f1, cmdstring, "rb", _PyPclose); + PyFile_SetBufSize(f, 0); + /* We don't care about these pipes anymore, so close them. */ + CloseHandle(hChildStdinWrDup); + CloseHandle(hChildStderrRdDup); + break; + + case _O_WRONLY | _O_BINARY: + /* Case for writing to child Stdin in binary mode. */ + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); + f1 = _fdopen(fd1, "wb"); + f = PyFile_FromFile(f1, cmdstring, "wb", _PyPclose); + PyFile_SetBufSize(f, 0); + /* We don't care about these pipes anymore, so close them. */ + CloseHandle(hChildStdoutRdDup); + CloseHandle(hChildStderrRdDup); + break; + } + file_count = 1; + break; + + case POPEN_2: + case POPEN_4: + { + char *m1, *m2; + PyObject *p1, *p2; + + if (mode & _O_TEXT) { + m1 = "r"; + m2 = "w"; + } else { + m1 = "rb"; + m2 = "wb"; + } + + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); + f1 = _fdopen(fd1, m2); + fd2 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); + f2 = _fdopen(fd2, m1); + p1 = PyFile_FromFile(f1, cmdstring, m2, _PyPclose); + PyFile_SetBufSize(p1, 0); + p2 = PyFile_FromFile(f2, cmdstring, m1, _PyPclose); + PyFile_SetBufSize(p2, 0); + + if (n != 4) + CloseHandle(hChildStderrRdDup); + + f = PyTuple_Pack(2,p1,p2); + Py_XDECREF(p1); + Py_XDECREF(p2); + file_count = 2; + break; + } + + case POPEN_3: + { + char *m1, *m2; + PyObject *p1, *p2, *p3; + + if (mode & _O_TEXT) { + m1 = "r"; + m2 = "w"; + } else { + m1 = "rb"; + m2 = "wb"; + } + + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); + f1 = _fdopen(fd1, m2); + fd2 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); + f2 = _fdopen(fd2, m1); + fd3 = _open_osfhandle((Py_intptr_t)hChildStderrRdDup, mode); + f3 = _fdopen(fd3, m1); + p1 = PyFile_FromFile(f1, cmdstring, m2, _PyPclose); + p2 = PyFile_FromFile(f2, cmdstring, m1, _PyPclose); + p3 = PyFile_FromFile(f3, cmdstring, m1, _PyPclose); + PyFile_SetBufSize(p1, 0); + PyFile_SetBufSize(p2, 0); + PyFile_SetBufSize(p3, 0); + f = PyTuple_Pack(3,p1,p2,p3); + Py_XDECREF(p1); + Py_XDECREF(p2); + Py_XDECREF(p3); + file_count = 3; + break; + } + } + + if (n == POPEN_4) { + if (!_PyPopenCreateProcess(cmdstring, + hChildStdinRd, + hChildStdoutWr, + hChildStdoutWr, + &hProcess)) + return NULL; + } + else { + if (!_PyPopenCreateProcess(cmdstring, + hChildStdinRd, + hChildStdoutWr, + hChildStderrWr, + &hProcess)) + return NULL; + } + + /* + * Insert the files we've created into the process dictionary + * all referencing the list with the process handle and the + * initial number of files (see description below in _PyPclose). + * Since if _PyPclose later tried to wait on a process when all + * handles weren't closed, it could create a deadlock with the + * child, we spend some energy here to try to ensure that we + * either insert all file handles into the dictionary or none + * at all. It's a little clumsy with the various popen modes + * and variable number of files involved. + */ + if (!_PyPopenProcs) { + _PyPopenProcs = PyDict_New(); + } + + if (_PyPopenProcs) { + PyObject *procObj, *hProcessObj, *intObj, *fileObj[3]; + int ins_rc[3]; + + fileObj[0] = fileObj[1] = fileObj[2] = NULL; + ins_rc[0] = ins_rc[1] = ins_rc[2] = 0; + + procObj = PyList_New(2); + hProcessObj = PyLong_FromVoidPtr(hProcess); + intObj = PyInt_FromLong(file_count); + + if (procObj && hProcessObj && intObj) { + PyList_SetItem(procObj,0,hProcessObj); + PyList_SetItem(procObj,1,intObj); + + fileObj[0] = PyLong_FromVoidPtr(f1); + if (fileObj[0]) { + ins_rc[0] = PyDict_SetItem(_PyPopenProcs, + fileObj[0], + procObj); + } + if (file_count >= 2) { + fileObj[1] = PyLong_FromVoidPtr(f2); + if (fileObj[1]) { + ins_rc[1] = PyDict_SetItem(_PyPopenProcs, + fileObj[1], + procObj); + } + } + if (file_count >= 3) { + fileObj[2] = PyLong_FromVoidPtr(f3); + if (fileObj[2]) { + ins_rc[2] = PyDict_SetItem(_PyPopenProcs, + fileObj[2], + procObj); + } + } + + if (ins_rc[0] < 0 || !fileObj[0] || + ins_rc[1] < 0 || (file_count > 1 && !fileObj[1]) || + ins_rc[2] < 0 || (file_count > 2 && !fileObj[2])) { + /* Something failed - remove any dictionary + * entries that did make it. + */ + if (!ins_rc[0] && fileObj[0]) { + PyDict_DelItem(_PyPopenProcs, + fileObj[0]); + } + if (!ins_rc[1] && fileObj[1]) { + PyDict_DelItem(_PyPopenProcs, + fileObj[1]); + } + if (!ins_rc[2] && fileObj[2]) { + PyDict_DelItem(_PyPopenProcs, + fileObj[2]); + } + } + } + + /* + * Clean up our localized references for the dictionary keys + * and value since PyDict_SetItem will Py_INCREF any copies + * that got placed in the dictionary. + */ + Py_XDECREF(procObj); + Py_XDECREF(fileObj[0]); + Py_XDECREF(fileObj[1]); + Py_XDECREF(fileObj[2]); + } + + /* Child is launched. Close the parents copy of those pipe + * handles that only the child should have open. You need to + * make sure that no handles to the write end of the output pipe + * are maintained in this process or else the pipe will not close + * when the child process exits and the ReadFile will hang. */ + + if (!CloseHandle(hChildStdinRd)) + return win32_error("CloseHandle", NULL); + + if (!CloseHandle(hChildStdoutWr)) + return win32_error("CloseHandle", NULL); + + if ((n != 4) && (!CloseHandle(hChildStderrWr))) + return win32_error("CloseHandle", NULL); + + return f; +} + +/* + * Wrapper for fclose() to use for popen* files, so we can retrieve the + * exit code for the child process and return as a result of the close. + * + * This function uses the _PyPopenProcs dictionary in order to map the + * input file pointer to information about the process that was + * originally created by the popen* call that created the file pointer. + * The dictionary uses the file pointer as a key (with one entry + * inserted for each file returned by the original popen* call) and a + * single list object as the value for all files from a single call. + * The list object contains the Win32 process handle at [0], and a file + * count at [1], which is initialized to the total number of file + * handles using that list. + * + * This function closes whichever handle it is passed, and decrements + * the file count in the dictionary for the process handle pointed to + * by this file. On the last close (when the file count reaches zero), + * this function will wait for the child process and then return its + * exit code as the result of the close() operation. This permits the + * files to be closed in any order - it is always the close() of the + * final handle that will return the exit code. + * + * NOTE: This function is currently called with the GIL released. + * hence we use the GILState API to manage our state. + */ + +static int _PyPclose(FILE *file) +{ + int result; + DWORD exit_code; + HANDLE hProcess; + PyObject *procObj, *hProcessObj, *intObj, *fileObj; + long file_count; +#ifdef WITH_THREAD + PyGILState_STATE state; +#endif + + /* Close the file handle first, to ensure it can't block the + * child from exiting if it's the last handle. + */ + result = fclose(file); +#ifdef WITH_THREAD + state = PyGILState_Ensure(); +#endif + if (_PyPopenProcs) { + if ((fileObj = PyLong_FromVoidPtr(file)) != NULL && + (procObj = PyDict_GetItem(_PyPopenProcs, + fileObj)) != NULL && + (hProcessObj = PyList_GetItem(procObj,0)) != NULL && + (intObj = PyList_GetItem(procObj,1)) != NULL) { + + hProcess = PyLong_AsVoidPtr(hProcessObj); + file_count = PyInt_AsLong(intObj); + + if (file_count > 1) { + /* Still other files referencing process */ + file_count--; + PyList_SetItem(procObj,1, + PyInt_FromLong(file_count)); + } else { + /* Last file for this process */ + if (result != EOF && + WaitForSingleObject(hProcess, INFINITE) != WAIT_FAILED && + GetExitCodeProcess(hProcess, &exit_code)) { + /* Possible truncation here in 16-bit environments, but + * real exit codes are just the lower byte in any event. + */ + result = exit_code; + } else { + /* Indicate failure - this will cause the file object + * to raise an I/O error and translate the last Win32 + * error code from errno. We do have a problem with + * last errors that overlap the normal errno table, + * but that's a consistent problem with the file object. + */ + if (result != EOF) { + /* If the error wasn't from the fclose(), then + * set errno for the file object error handling. + */ + errno = GetLastError(); + } + result = -1; + } + + /* Free up the native handle at this point */ + CloseHandle(hProcess); + } + + /* Remove this file pointer from dictionary */ + PyDict_DelItem(_PyPopenProcs, fileObj); + + if (PyDict_Size(_PyPopenProcs) == 0) { + Py_DECREF(_PyPopenProcs); + _PyPopenProcs = NULL; + } + + } /* if object retrieval ok */ + + Py_XDECREF(fileObj); + } /* if _PyPopenProcs */ + +#ifdef WITH_THREAD + PyGILState_Release(state); +#endif + return result; +} + +#else /* which OS? */ +static PyObject * +posix_popen(PyObject *self, PyObject *args) +{ + char *name; + char *mode = "r"; + int bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "s|si:popen", &name, &mode, &bufsize)) + return NULL; + /* Strip mode of binary or text modifiers */ + if (strcmp(mode, "rb") == 0 || strcmp(mode, "rt") == 0) + mode = "r"; + else if (strcmp(mode, "wb") == 0 || strcmp(mode, "wt") == 0) + mode = "w"; + Py_BEGIN_ALLOW_THREADS + fp = popen(name, mode); + Py_END_ALLOW_THREADS + if (fp == NULL) + return posix_error(); + f = PyFile_FromFile(fp, name, mode, pclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + +#endif /* PYOS_??? */ +#endif /* HAVE_POPEN */ + + +#ifdef HAVE_SETUID +PyDoc_STRVAR(posix_setuid__doc__, +"setuid(uid)\n\n\ +Set the current process's user id."); + +static PyObject * +posix_setuid(PyObject *self, PyObject *args) +{ + int uid; + if (!PyArg_ParseTuple(args, "i:setuid", &uid)) + return NULL; + if (setuid(uid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETUID */ + + +#ifdef HAVE_SETEUID +PyDoc_STRVAR(posix_seteuid__doc__, +"seteuid(uid)\n\n\ +Set the current process's effective user id."); + +static PyObject * +posix_seteuid (PyObject *self, PyObject *args) +{ + int euid; + if (!PyArg_ParseTuple(args, "i", &euid)) { + return NULL; + } else if (seteuid(euid) < 0) { + return posix_error(); + } else { + Py_INCREF(Py_None); + return Py_None; + } +} +#endif /* HAVE_SETEUID */ + +#ifdef HAVE_SETEGID +PyDoc_STRVAR(posix_setegid__doc__, +"setegid(gid)\n\n\ +Set the current process's effective group id."); + +static PyObject * +posix_setegid (PyObject *self, PyObject *args) +{ + int egid; + if (!PyArg_ParseTuple(args, "i", &egid)) { + return NULL; + } else if (setegid(egid) < 0) { + return posix_error(); + } else { + Py_INCREF(Py_None); + return Py_None; + } +} +#endif /* HAVE_SETEGID */ + +#ifdef HAVE_SETREUID +PyDoc_STRVAR(posix_setreuid__doc__, +"setreuid(ruid, euid)\n\n\ +Set the current process's real and effective user ids."); + +static PyObject * +posix_setreuid (PyObject *self, PyObject *args) +{ + int ruid, euid; + if (!PyArg_ParseTuple(args, "ii", &ruid, &euid)) { + return NULL; + } else if (setreuid(ruid, euid) < 0) { + return posix_error(); + } else { + Py_INCREF(Py_None); + return Py_None; + } +} +#endif /* HAVE_SETREUID */ + +#ifdef HAVE_SETREGID +PyDoc_STRVAR(posix_setregid__doc__, +"setregid(rgid, egid)\n\n\ +Set the current process's real and effective group ids."); + +static PyObject * +posix_setregid (PyObject *self, PyObject *args) +{ + int rgid, egid; + if (!PyArg_ParseTuple(args, "ii", &rgid, &egid)) { + return NULL; + } else if (setregid(rgid, egid) < 0) { + return posix_error(); + } else { + Py_INCREF(Py_None); + return Py_None; + } +} +#endif /* HAVE_SETREGID */ + +#ifdef HAVE_SETGID +PyDoc_STRVAR(posix_setgid__doc__, +"setgid(gid)\n\n\ +Set the current process's group id."); + +static PyObject * +posix_setgid(PyObject *self, PyObject *args) +{ + int gid; + if (!PyArg_ParseTuple(args, "i:setgid", &gid)) + return NULL; + if (setgid(gid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETGID */ + +#ifdef HAVE_SETGROUPS +PyDoc_STRVAR(posix_setgroups__doc__, +"setgroups(list)\n\n\ +Set the groups of the current process to list."); + +static PyObject * +posix_setgroups(PyObject *self, PyObject *groups) +{ + int i, len; + gid_t grouplist[MAX_GROUPS]; + + if (!PySequence_Check(groups)) { + PyErr_SetString(PyExc_TypeError, "setgroups argument must be a sequence"); + return NULL; + } + len = PySequence_Size(groups); + if (len > MAX_GROUPS) { + PyErr_SetString(PyExc_ValueError, "too many groups"); + return NULL; + } + for(i = 0; i < len; i++) { + PyObject *elem; + elem = PySequence_GetItem(groups, i); + if (!elem) + return NULL; + if (!PyInt_Check(elem)) { + if (!PyLong_Check(elem)) { + PyErr_SetString(PyExc_TypeError, + "groups must be integers"); + Py_DECREF(elem); + return NULL; + } else { + unsigned long x = PyLong_AsUnsignedLong(elem); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "group id too big"); + Py_DECREF(elem); + return NULL; + } + grouplist[i] = x; + /* read back the value to see if it fitted in gid_t */ + if (grouplist[i] != x) { + PyErr_SetString(PyExc_TypeError, + "group id too big"); + Py_DECREF(elem); + return NULL; + } + } + } else { + long x = PyInt_AsLong(elem); + grouplist[i] = x; + if (grouplist[i] != x) { + PyErr_SetString(PyExc_TypeError, + "group id too big"); + Py_DECREF(elem); + return NULL; + } + } + Py_DECREF(elem); + } + + if (setgroups(len, grouplist) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETGROUPS */ + +#if defined(HAVE_WAIT3) || defined(HAVE_WAIT4) +static PyObject * +wait_helper(int pid, int status, struct rusage *ru) +{ + PyObject *result; + static PyObject *struct_rusage; + + if (pid == -1) + return posix_error(); + + if (struct_rusage == NULL) { + PyObject *m = PyImport_ImportModule("resource"); + if (m == NULL) + return NULL; + struct_rusage = PyObject_GetAttrString(m, "struct_rusage"); + Py_DECREF(m); + if (struct_rusage == NULL) + return NULL; + } + + /* XXX(nnorwitz): Copied (w/mods) from resource.c, there should be only one. */ + result = PyStructSequence_New((PyTypeObject*) struct_rusage); + if (!result) + return NULL; + +#ifndef doubletime +#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001) +#endif + + PyStructSequence_SET_ITEM(result, 0, + PyFloat_FromDouble(doubletime(ru->ru_utime))); + PyStructSequence_SET_ITEM(result, 1, + PyFloat_FromDouble(doubletime(ru->ru_stime))); +#define SET_INT(result, index, value)\ + PyStructSequence_SET_ITEM(result, index, PyInt_FromLong(value)) + SET_INT(result, 2, ru->ru_maxrss); + SET_INT(result, 3, ru->ru_ixrss); + SET_INT(result, 4, ru->ru_idrss); + SET_INT(result, 5, ru->ru_isrss); + SET_INT(result, 6, ru->ru_minflt); + SET_INT(result, 7, ru->ru_majflt); + SET_INT(result, 8, ru->ru_nswap); + SET_INT(result, 9, ru->ru_inblock); + SET_INT(result, 10, ru->ru_oublock); + SET_INT(result, 11, ru->ru_msgsnd); + SET_INT(result, 12, ru->ru_msgrcv); + SET_INT(result, 13, ru->ru_nsignals); + SET_INT(result, 14, ru->ru_nvcsw); + SET_INT(result, 15, ru->ru_nivcsw); +#undef SET_INT + + if (PyErr_Occurred()) { + Py_DECREF(result); + return NULL; + } + + return Py_BuildValue("iiN", pid, status, result); +} +#endif /* HAVE_WAIT3 || HAVE_WAIT4 */ + +#ifdef HAVE_WAIT3 +PyDoc_STRVAR(posix_wait3__doc__, +"wait3(options) -> (pid, status, rusage)\n\n\ +Wait for completion of a child process."); + +static PyObject * +posix_wait3(PyObject *self, PyObject *args) +{ + int pid, options; + struct rusage ru; + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:wait3", &options)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + pid = wait3(&status, options, &ru); + Py_END_ALLOW_THREADS + + return wait_helper(pid, WAIT_STATUS_INT(status), &ru); +} +#endif /* HAVE_WAIT3 */ + +#ifdef HAVE_WAIT4 +PyDoc_STRVAR(posix_wait4__doc__, +"wait4(pid, options) -> (pid, status, rusage)\n\n\ +Wait for completion of a given child process."); + +static PyObject * +posix_wait4(PyObject *self, PyObject *args) +{ + int pid, options; + struct rusage ru; + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "ii:wait4", &pid, &options)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + pid = wait4(pid, &status, options, &ru); + Py_END_ALLOW_THREADS + + return wait_helper(pid, WAIT_STATUS_INT(status), &ru); +} +#endif /* HAVE_WAIT4 */ + +#ifdef HAVE_WAITPID +PyDoc_STRVAR(posix_waitpid__doc__, +"waitpid(pid, options) -> (pid, status)\n\n\ +Wait for completion of a given child process."); + +static PyObject * +posix_waitpid(PyObject *self, PyObject *args) +{ + int pid, options; + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "ii:waitpid", &pid, &options)) + return NULL; + Py_BEGIN_ALLOW_THREADS + pid = waitpid(pid, &status, options); + Py_END_ALLOW_THREADS + if (pid == -1) + return posix_error(); + + return Py_BuildValue("ii", pid, WAIT_STATUS_INT(status)); +} + +#elif defined(HAVE_CWAIT) + +/* MS C has a variant of waitpid() that's usable for most purposes. */ +PyDoc_STRVAR(posix_waitpid__doc__, +"waitpid(pid, options) -> (pid, status << 8)\n\n" +"Wait for completion of a given process. options is ignored on Windows."); + +static PyObject * +posix_waitpid(PyObject *self, PyObject *args) +{ + Py_intptr_t pid; + int status, options; + + if (!PyArg_ParseTuple(args, "ii:waitpid", &pid, &options)) + return NULL; + Py_BEGIN_ALLOW_THREADS + pid = _cwait(&status, pid, options); + Py_END_ALLOW_THREADS + if (pid == -1) + return posix_error(); + + /* shift the status left a byte so this is more like the POSIX waitpid */ + return Py_BuildValue("ii", pid, status << 8); +} +#endif /* HAVE_WAITPID || HAVE_CWAIT */ + +#ifdef HAVE_WAIT +PyDoc_STRVAR(posix_wait__doc__, +"wait() -> (pid, status)\n\n\ +Wait for completion of a child process."); + +static PyObject * +posix_wait(PyObject *self, PyObject *noargs) +{ + int pid; + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + Py_BEGIN_ALLOW_THREADS + pid = wait(&status); + Py_END_ALLOW_THREADS + if (pid == -1) + return posix_error(); + + return Py_BuildValue("ii", pid, WAIT_STATUS_INT(status)); +} +#endif + + +PyDoc_STRVAR(posix_lstat__doc__, +"lstat(path) -> stat result\n\n\ +Like stat(path), but do not follow symbolic links."); + +static PyObject * +posix_lstat(PyObject *self, PyObject *args) +{ +#ifdef HAVE_LSTAT + return posix_do_stat(self, args, "et:lstat", lstat, NULL, NULL); +#else /* !HAVE_LSTAT */ +#ifdef MS_WINDOWS + return posix_do_stat(self, args, "et:lstat", STAT, "U:lstat", win32_wstat); +#else + return posix_do_stat(self, args, "et:lstat", STAT, NULL, NULL); +#endif +#endif /* !HAVE_LSTAT */ +} + + +#ifdef HAVE_READLINK +PyDoc_STRVAR(posix_readlink__doc__, +"readlink(path) -> path\n\n\ +Return a string representing the path to which the symbolic link points."); + +static PyObject * +posix_readlink(PyObject *self, PyObject *args) +{ + char buf[MAXPATHLEN]; + char *path; + int n; + if (!PyArg_ParseTuple(args, "s:readlink", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + n = readlink(path, buf, (int) sizeof buf); + Py_END_ALLOW_THREADS + if (n < 0) + return posix_error_with_filename(path); + return PyString_FromStringAndSize(buf, n); +} +#endif /* HAVE_READLINK */ + + +#ifdef HAVE_SYMLINK +PyDoc_STRVAR(posix_symlink__doc__, +"symlink(src, dst)\n\n\ +Create a symbolic link pointing to src named dst."); + +static PyObject * +posix_symlink(PyObject *self, PyObject *args) +{ + return posix_2str(args, "etet:symlink", symlink); +} +#endif /* HAVE_SYMLINK */ + + +#ifdef HAVE_TIMES +#ifndef HZ +#define HZ 60 /* Universal constant :-) */ +#endif /* HZ */ + +#if defined(PYCC_VACPP) && defined(PYOS_OS2) +static long +system_uptime(void) +{ + ULONG value = 0; + + Py_BEGIN_ALLOW_THREADS + DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &value, sizeof(value)); + Py_END_ALLOW_THREADS + + return value; +} + +static PyObject * +posix_times(PyObject *self, PyObject *noargs) +{ + /* Currently Only Uptime is Provided -- Others Later */ + return Py_BuildValue("ddddd", + (double)0 /* t.tms_utime / HZ */, + (double)0 /* t.tms_stime / HZ */, + (double)0 /* t.tms_cutime / HZ */, + (double)0 /* t.tms_cstime / HZ */, + (double)system_uptime() / 1000); +} +#else /* not OS2 */ +static PyObject * +posix_times(PyObject *self, PyObject *noargs) +{ + struct tms t; + clock_t c; + errno = 0; + c = times(&t); + if (c == (clock_t) -1) + return posix_error(); + return Py_BuildValue("ddddd", + (double)t.tms_utime / HZ, + (double)t.tms_stime / HZ, + (double)t.tms_cutime / HZ, + (double)t.tms_cstime / HZ, + (double)c / HZ); +} +#endif /* not OS2 */ +#endif /* HAVE_TIMES */ + + +#ifdef MS_WINDOWS +#define HAVE_TIMES /* so the method table will pick it up */ +static PyObject * +posix_times(PyObject *self, PyObject *noargs) +{ + FILETIME create, exit, kernel, user; + HANDLE hProc; + hProc = GetCurrentProcess(); + GetProcessTimes(hProc, &create, &exit, &kernel, &user); + /* The fields of a FILETIME structure are the hi and lo part + of a 64-bit value expressed in 100 nanosecond units. + 1e7 is one second in such units; 1e-7 the inverse. + 429.4967296 is 2**32 / 1e7 or 2**32 * 1e-7. + */ + return Py_BuildValue( + "ddddd", + (double)(kernel.dwHighDateTime*429.4967296 + + kernel.dwLowDateTime*1e-7), + (double)(user.dwHighDateTime*429.4967296 + + user.dwLowDateTime*1e-7), + (double)0, + (double)0, + (double)0); +} +#endif /* MS_WINDOWS */ + +#ifdef HAVE_TIMES +PyDoc_STRVAR(posix_times__doc__, +"times() -> (utime, stime, cutime, cstime, elapsed_time)\n\n\ +Return a tuple of floating point numbers indicating process times."); +#endif + + +#ifdef HAVE_GETSID +PyDoc_STRVAR(posix_getsid__doc__, +"getsid(pid) -> sid\n\n\ +Call the system call getsid()."); + +static PyObject * +posix_getsid(PyObject *self, PyObject *args) +{ + int pid, sid; + if (!PyArg_ParseTuple(args, "i:getsid", &pid)) + return NULL; + sid = getsid(pid); + if (sid < 0) + return posix_error(); + return PyInt_FromLong((long)sid); +} +#endif /* HAVE_GETSID */ + + +#ifdef HAVE_SETSID +PyDoc_STRVAR(posix_setsid__doc__, +"setsid()\n\n\ +Call the system call setsid()."); + +static PyObject * +posix_setsid(PyObject *self, PyObject *noargs) +{ + if (setsid() < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETSID */ + +#ifdef HAVE_SETPGID +PyDoc_STRVAR(posix_setpgid__doc__, +"setpgid(pid, pgrp)\n\n\ +Call the system call setpgid()."); + +static PyObject * +posix_setpgid(PyObject *self, PyObject *args) +{ + int pid, pgrp; + if (!PyArg_ParseTuple(args, "ii:setpgid", &pid, &pgrp)) + return NULL; + if (setpgid(pid, pgrp) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_SETPGID */ + + +#ifdef HAVE_TCGETPGRP +PyDoc_STRVAR(posix_tcgetpgrp__doc__, +"tcgetpgrp(fd) -> pgid\n\n\ +Return the process group associated with the terminal given by a fd."); + +static PyObject * +posix_tcgetpgrp(PyObject *self, PyObject *args) +{ + int fd, pgid; + if (!PyArg_ParseTuple(args, "i:tcgetpgrp", &fd)) + return NULL; + pgid = tcgetpgrp(fd); + if (pgid < 0) + return posix_error(); + return PyInt_FromLong((long)pgid); +} +#endif /* HAVE_TCGETPGRP */ + + +#ifdef HAVE_TCSETPGRP +PyDoc_STRVAR(posix_tcsetpgrp__doc__, +"tcsetpgrp(fd, pgid)\n\n\ +Set the process group associated with the terminal given by a fd."); + +static PyObject * +posix_tcsetpgrp(PyObject *self, PyObject *args) +{ + int fd, pgid; + if (!PyArg_ParseTuple(args, "ii:tcsetpgrp", &fd, &pgid)) + return NULL; + if (tcsetpgrp(fd, pgid) < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAVE_TCSETPGRP */ + +/* Functions acting on file descriptors */ + +PyDoc_STRVAR(posix_open__doc__, +"open(filename, flag [, mode=0777]) -> fd\n\n\ +Open a file (for low level IO)."); + +static PyObject * +posix_open(PyObject *self, PyObject *args) +{ + char *file = NULL; + int flag; + int mode = 0777; + int fd; + +#ifdef MS_WINDOWS + if (unicode_file_names()) { + PyUnicodeObject *po; + if (PyArg_ParseTuple(args, "Ui|i:mkdir", &po, &flag, &mode)) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread + lock as it is a simple dereference. */ + fd = _wopen(PyUnicode_AS_UNICODE(po), flag, mode); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error(); + return PyInt_FromLong((long)fd); + } + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } +#endif + + if (!PyArg_ParseTuple(args, "eti|i", + Py_FileSystemDefaultEncoding, &file, + &flag, &mode)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + fd = open(file, flag, mode); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error_with_allocated_filename(file); + PyMem_Free(file); + return PyInt_FromLong((long)fd); +} + + +PyDoc_STRVAR(posix_close__doc__, +"close(fd)\n\n\ +Close a file descriptor (for low level IO)."); + +static PyObject * +posix_close(PyObject *self, PyObject *args) +{ + int fd, res; + if (!PyArg_ParseTuple(args, "i:close", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = close(fd); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +PyDoc_STRVAR(posix_dup__doc__, +"dup(fd) -> fd2\n\n\ +Return a duplicate of a file descriptor."); + +static PyObject * +posix_dup(PyObject *self, PyObject *args) +{ + int fd; + if (!PyArg_ParseTuple(args, "i:dup", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + fd = dup(fd); + Py_END_ALLOW_THREADS + if (fd < 0) + return posix_error(); + return PyInt_FromLong((long)fd); +} + + +PyDoc_STRVAR(posix_dup2__doc__, +"dup2(old_fd, new_fd)\n\n\ +Duplicate file descriptor."); + +static PyObject * +posix_dup2(PyObject *self, PyObject *args) +{ + int fd, fd2, res; + if (!PyArg_ParseTuple(args, "ii:dup2", &fd, &fd2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = dup2(fd, fd2); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} + + +PyDoc_STRVAR(posix_lseek__doc__, +"lseek(fd, pos, how) -> newpos\n\n\ +Set the current position of a file descriptor."); + +static PyObject * +posix_lseek(PyObject *self, PyObject *args) +{ + int fd, how; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + PY_LONG_LONG pos, res; +#else + off_t pos, res; +#endif + PyObject *posobj; + if (!PyArg_ParseTuple(args, "iOi:lseek", &fd, &posobj, &how)) + return NULL; +#ifdef SEEK_SET + /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ + switch (how) { + case 0: how = SEEK_SET; break; + case 1: how = SEEK_CUR; break; + case 2: how = SEEK_END; break; + } +#endif /* SEEK_END */ + +#if !defined(HAVE_LARGEFILE_SUPPORT) + pos = PyInt_AsLong(posobj); +#else + pos = PyLong_Check(posobj) ? + PyLong_AsLongLong(posobj) : PyInt_AsLong(posobj); +#endif + if (PyErr_Occurred()) + return NULL; + + Py_BEGIN_ALLOW_THREADS +#if defined(MS_WIN64) || defined(MS_WINDOWS) + res = _lseeki64(fd, pos, how); +#else + res = lseek(fd, pos, how); +#endif + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + +#if !defined(HAVE_LARGEFILE_SUPPORT) + return PyInt_FromLong(res); +#else + return PyLong_FromLongLong(res); +#endif +} + + +PyDoc_STRVAR(posix_read__doc__, +"read(fd, buffersize) -> string\n\n\ +Read a file descriptor."); + +static PyObject * +posix_read(PyObject *self, PyObject *args) +{ + int fd, size, n; + PyObject *buffer; + if (!PyArg_ParseTuple(args, "ii:read", &fd, &size)) + return NULL; + if (size < 0) { + errno = EINVAL; + return posix_error(); + } + buffer = PyString_FromStringAndSize((char *)NULL, size); + if (buffer == NULL) + return NULL; + Py_BEGIN_ALLOW_THREADS + n = read(fd, PyString_AsString(buffer), size); + Py_END_ALLOW_THREADS + if (n < 0) { + Py_DECREF(buffer); + return posix_error(); + } + if (n != size) + _PyString_Resize(&buffer, n); + return buffer; +} + + +PyDoc_STRVAR(posix_write__doc__, +"write(fd, string) -> byteswritten\n\n\ +Write a string to a file descriptor."); + +static PyObject * +posix_write(PyObject *self, PyObject *args) +{ + int fd; + Py_ssize_t size; + char *buffer; + + if (!PyArg_ParseTuple(args, "is#:write", &fd, &buffer, &size)) + return NULL; + Py_BEGIN_ALLOW_THREADS + size = write(fd, buffer, (size_t)size); + Py_END_ALLOW_THREADS + if (size < 0) + return posix_error(); + return PyInt_FromSsize_t(size); +} + + +PyDoc_STRVAR(posix_fstat__doc__, +"fstat(fd) -> stat result\n\n\ +Like stat(), but for an open file descriptor."); + +static PyObject * +posix_fstat(PyObject *self, PyObject *args) +{ + int fd; + STRUCT_STAT st; + int res; + if (!PyArg_ParseTuple(args, "i:fstat", &fd)) + return NULL; +#ifdef __VMS + /* on OpenVMS we must ensure that all bytes are written to the file */ + fsync(fd); +#endif + Py_BEGIN_ALLOW_THREADS + res = FSTAT(fd, &st); + Py_END_ALLOW_THREADS + if (res != 0) { +#ifdef MS_WINDOWS + return win32_error("fstat", NULL); +#else + return posix_error(); +#endif + } + + return _pystat_fromstructstat(&st); +} + + +PyDoc_STRVAR(posix_fdopen__doc__, +"fdopen(fd [, mode='r' [, bufsize]]) -> file_object\n\n\ +Return an open file object connected to a file descriptor."); + +static PyObject * +posix_fdopen(PyObject *self, PyObject *args) +{ + int fd; + char *mode = "r"; + int bufsize = -1; + FILE *fp; + PyObject *f; + if (!PyArg_ParseTuple(args, "i|si", &fd, &mode, &bufsize)) + return NULL; + + if (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a') { + PyErr_Format(PyExc_ValueError, + "invalid file mode '%s'", mode); + return NULL; + } + Py_BEGIN_ALLOW_THREADS +#if !defined(MS_WINDOWS) && defined(HAVE_FCNTL_H) + if (mode[0] == 'a') { + /* try to make sure the O_APPEND flag is set */ + int flags; + flags = fcntl(fd, F_GETFL); + if (flags != -1) + fcntl(fd, F_SETFL, flags | O_APPEND); + fp = fdopen(fd, mode); + if (fp == NULL && flags != -1) + /* restore old mode if fdopen failed */ + fcntl(fd, F_SETFL, flags); + } else { + fp = fdopen(fd, mode); + } +#else + fp = fdopen(fd, mode); +#endif + Py_END_ALLOW_THREADS + if (fp == NULL) + return posix_error(); + f = PyFile_FromFile(fp, "<fdopen>", mode, fclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + +PyDoc_STRVAR(posix_isatty__doc__, +"isatty(fd) -> bool\n\n\ +Return True if the file descriptor 'fd' is an open file descriptor\n\ +connected to the slave end of a terminal."); + +static PyObject * +posix_isatty(PyObject *self, PyObject *args) +{ + int fd; + if (!PyArg_ParseTuple(args, "i:isatty", &fd)) + return NULL; + return PyBool_FromLong(isatty(fd)); +} + +#ifdef HAVE_PIPE +PyDoc_STRVAR(posix_pipe__doc__, +"pipe() -> (read_end, write_end)\n\n\ +Create a pipe."); + +static PyObject * +posix_pipe(PyObject *self, PyObject *noargs) +{ +#if defined(PYOS_OS2) + HFILE read, write; + APIRET rc; + + Py_BEGIN_ALLOW_THREADS + rc = DosCreatePipe( &read, &write, 4096); + Py_END_ALLOW_THREADS + if (rc != NO_ERROR) + return os2_error(rc); + + return Py_BuildValue("(ii)", read, write); +#else +#if !defined(MS_WINDOWS) + int fds[2]; + int res; + Py_BEGIN_ALLOW_THREADS + res = pipe(fds); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); + return Py_BuildValue("(ii)", fds[0], fds[1]); +#else /* MS_WINDOWS */ + HANDLE read, write; + int read_fd, write_fd; + BOOL ok; + Py_BEGIN_ALLOW_THREADS + ok = CreatePipe(&read, &write, NULL, 0); + Py_END_ALLOW_THREADS + if (!ok) + return win32_error("CreatePipe", NULL); + read_fd = _open_osfhandle((Py_intptr_t)read, 0); + write_fd = _open_osfhandle((Py_intptr_t)write, 1); + return Py_BuildValue("(ii)", read_fd, write_fd); +#endif /* MS_WINDOWS */ +#endif +} +#endif /* HAVE_PIPE */ + + +#ifdef HAVE_MKFIFO +PyDoc_STRVAR(posix_mkfifo__doc__, +"mkfifo(filename [, mode=0666])\n\n\ +Create a FIFO (a POSIX named pipe)."); + +static PyObject * +posix_mkfifo(PyObject *self, PyObject *args) +{ + char *filename; + int mode = 0666; + int res; + if (!PyArg_ParseTuple(args, "s|i:mkfifo", &filename, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = mkfifo(filename, mode); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) +PyDoc_STRVAR(posix_mknod__doc__, +"mknod(filename [, mode=0600, device])\n\n\ +Create a filesystem node (file, device special file or named pipe)\n\ +named filename. mode specifies both the permissions to use and the\n\ +type of node to be created, being combined (bitwise OR) with one of\n\ +S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,\n\ +device defines the newly created device special file (probably using\n\ +os.makedev()), otherwise it is ignored."); + + +static PyObject * +posix_mknod(PyObject *self, PyObject *args) +{ + char *filename; + int mode = 0600; + int device = 0; + int res; + if (!PyArg_ParseTuple(args, "s|ii:mknod", &filename, &mode, &device)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = mknod(filename, mode, device); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_DEVICE_MACROS +PyDoc_STRVAR(posix_major__doc__, +"major(device) -> major number\n\ +Extracts a device major number from a raw device number."); + +static PyObject * +posix_major(PyObject *self, PyObject *args) +{ + int device; + if (!PyArg_ParseTuple(args, "i:major", &device)) + return NULL; + return PyInt_FromLong((long)major(device)); +} + +PyDoc_STRVAR(posix_minor__doc__, +"minor(device) -> minor number\n\ +Extracts a device minor number from a raw device number."); + +static PyObject * +posix_minor(PyObject *self, PyObject *args) +{ + int device; + if (!PyArg_ParseTuple(args, "i:minor", &device)) + return NULL; + return PyInt_FromLong((long)minor(device)); +} + +PyDoc_STRVAR(posix_makedev__doc__, +"makedev(major, minor) -> device number\n\ +Composes a raw device number from the major and minor device numbers."); + +static PyObject * +posix_makedev(PyObject *self, PyObject *args) +{ + int major, minor; + if (!PyArg_ParseTuple(args, "ii:makedev", &major, &minor)) + return NULL; + return PyInt_FromLong((long)makedev(major, minor)); +} +#endif /* device macros */ + + +#ifdef HAVE_FTRUNCATE +PyDoc_STRVAR(posix_ftruncate__doc__, +"ftruncate(fd, length)\n\n\ +Truncate a file to a specified length."); + +static PyObject * +posix_ftruncate(PyObject *self, PyObject *args) +{ + int fd; + off_t length; + int res; + PyObject *lenobj; + + if (!PyArg_ParseTuple(args, "iO:ftruncate", &fd, &lenobj)) + return NULL; + +#if !defined(HAVE_LARGEFILE_SUPPORT) + length = PyInt_AsLong(lenobj); +#else + length = PyLong_Check(lenobj) ? + PyLong_AsLongLong(lenobj) : PyInt_AsLong(lenobj); +#endif + if (PyErr_Occurred()) + return NULL; + + Py_BEGIN_ALLOW_THREADS + res = ftruncate(fd, length); + Py_END_ALLOW_THREADS + if (res < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_PUTENV +PyDoc_STRVAR(posix_putenv__doc__, +"putenv(key, value)\n\n\ +Change or add an environment variable."); + +/* Save putenv() parameters as values here, so we can collect them when they + * get re-set with another call for the same key. */ +static PyObject *posix_putenv_garbage; + +static PyObject * +posix_putenv(PyObject *self, PyObject *args) +{ + char *s1, *s2; + char *newenv; + PyObject *newstr; + size_t len; + + if (!PyArg_ParseTuple(args, "ss:putenv", &s1, &s2)) + return NULL; + +#if defined(PYOS_OS2) + if (stricmp(s1, "BEGINLIBPATH") == 0) { + APIRET rc; + + rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH); + if (rc != NO_ERROR) + return os2_error(rc); + + } else if (stricmp(s1, "ENDLIBPATH") == 0) { + APIRET rc; + + rc = DosSetExtLIBPATH(s2, END_LIBPATH); + if (rc != NO_ERROR) + return os2_error(rc); + } else { +#endif + + /* XXX This can leak memory -- not easy to fix :-( */ + len = strlen(s1) + strlen(s2) + 2; + /* len includes space for a trailing \0; the size arg to + PyString_FromStringAndSize does not count that */ + newstr = PyString_FromStringAndSize(NULL, (int)len - 1); + if (newstr == NULL) + return PyErr_NoMemory(); + newenv = PyString_AS_STRING(newstr); + PyOS_snprintf(newenv, len, "%s=%s", s1, s2); + if (putenv(newenv)) { + Py_DECREF(newstr); + posix_error(); + return NULL; + } + /* Install the first arg and newstr in posix_putenv_garbage; + * this will cause previous value to be collected. This has to + * happen after the real putenv() call because the old value + * was still accessible until then. */ + if (PyDict_SetItem(posix_putenv_garbage, + PyTuple_GET_ITEM(args, 0), newstr)) { + /* really not much we can do; just leak */ + PyErr_Clear(); + } + else { + Py_DECREF(newstr); + } + +#if defined(PYOS_OS2) + } +#endif + Py_INCREF(Py_None); + return Py_None; +} +#endif /* putenv */ + +#ifdef HAVE_UNSETENV +PyDoc_STRVAR(posix_unsetenv__doc__, +"unsetenv(key)\n\n\ +Delete an environment variable."); + +static PyObject * +posix_unsetenv(PyObject *self, PyObject *args) +{ + char *s1; + + if (!PyArg_ParseTuple(args, "s:unsetenv", &s1)) + return NULL; + + unsetenv(s1); + + /* Remove the key from posix_putenv_garbage; + * this will cause it to be collected. This has to + * happen after the real unsetenv() call because the + * old value was still accessible until then. + */ + if (PyDict_DelItem(posix_putenv_garbage, + PyTuple_GET_ITEM(args, 0))) { + /* really not much we can do; just leak */ + PyErr_Clear(); + } + + Py_INCREF(Py_None); + return Py_None; +} +#endif /* unsetenv */ + +#ifdef HAVE_STRERROR +PyDoc_STRVAR(posix_strerror__doc__, +"strerror(code) -> string\n\n\ +Translate an error code to a message string."); + +static PyObject * +posix_strerror(PyObject *self, PyObject *args) +{ + int code; + char *message; + if (!PyArg_ParseTuple(args, "i:strerror", &code)) + return NULL; + message = strerror(code); + if (message == NULL) { + PyErr_SetString(PyExc_ValueError, + "strerror() argument out of range"); + return NULL; + } + return PyString_FromString(message); +} +#endif /* strerror */ + + +#ifdef HAVE_SYS_WAIT_H + +#ifdef WCOREDUMP +PyDoc_STRVAR(posix_WCOREDUMP__doc__, +"WCOREDUMP(status) -> bool\n\n\ +Return True if the process returning 'status' was dumped to a core file."); + +static PyObject * +posix_WCOREDUMP(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WCOREDUMP", &WAIT_STATUS_INT(status))) + return NULL; + + return PyBool_FromLong(WCOREDUMP(status)); +} +#endif /* WCOREDUMP */ + +#ifdef WIFCONTINUED +PyDoc_STRVAR(posix_WIFCONTINUED__doc__, +"WIFCONTINUED(status) -> bool\n\n\ +Return True if the process returning 'status' was continued from a\n\ +job control stop."); + +static PyObject * +posix_WIFCONTINUED(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WCONTINUED", &WAIT_STATUS_INT(status))) + return NULL; + + return PyBool_FromLong(WIFCONTINUED(status)); +} +#endif /* WIFCONTINUED */ + +#ifdef WIFSTOPPED +PyDoc_STRVAR(posix_WIFSTOPPED__doc__, +"WIFSTOPPED(status) -> bool\n\n\ +Return True if the process returning 'status' was stopped."); + +static PyObject * +posix_WIFSTOPPED(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WIFSTOPPED", &WAIT_STATUS_INT(status))) + return NULL; + + return PyBool_FromLong(WIFSTOPPED(status)); +} +#endif /* WIFSTOPPED */ + +#ifdef WIFSIGNALED +PyDoc_STRVAR(posix_WIFSIGNALED__doc__, +"WIFSIGNALED(status) -> bool\n\n\ +Return True if the process returning 'status' was terminated by a signal."); + +static PyObject * +posix_WIFSIGNALED(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WIFSIGNALED", &WAIT_STATUS_INT(status))) + return NULL; + + return PyBool_FromLong(WIFSIGNALED(status)); +} +#endif /* WIFSIGNALED */ + +#ifdef WIFEXITED +PyDoc_STRVAR(posix_WIFEXITED__doc__, +"WIFEXITED(status) -> bool\n\n\ +Return true if the process returning 'status' exited using the exit()\n\ +system call."); + +static PyObject * +posix_WIFEXITED(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WIFEXITED", &WAIT_STATUS_INT(status))) + return NULL; + + return PyBool_FromLong(WIFEXITED(status)); +} +#endif /* WIFEXITED */ + +#ifdef WEXITSTATUS +PyDoc_STRVAR(posix_WEXITSTATUS__doc__, +"WEXITSTATUS(status) -> integer\n\n\ +Return the process return code from 'status'."); + +static PyObject * +posix_WEXITSTATUS(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WEXITSTATUS", &WAIT_STATUS_INT(status))) + return NULL; + + return Py_BuildValue("i", WEXITSTATUS(status)); +} +#endif /* WEXITSTATUS */ + +#ifdef WTERMSIG +PyDoc_STRVAR(posix_WTERMSIG__doc__, +"WTERMSIG(status) -> integer\n\n\ +Return the signal that terminated the process that provided the 'status'\n\ +value."); + +static PyObject * +posix_WTERMSIG(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WTERMSIG", &WAIT_STATUS_INT(status))) + return NULL; + + return Py_BuildValue("i", WTERMSIG(status)); +} +#endif /* WTERMSIG */ + +#ifdef WSTOPSIG +PyDoc_STRVAR(posix_WSTOPSIG__doc__, +"WSTOPSIG(status) -> integer\n\n\ +Return the signal that stopped the process that provided\n\ +the 'status' value."); + +static PyObject * +posix_WSTOPSIG(PyObject *self, PyObject *args) +{ + WAIT_TYPE status; + WAIT_STATUS_INT(status) = 0; + + if (!PyArg_ParseTuple(args, "i:WSTOPSIG", &WAIT_STATUS_INT(status))) + return NULL; + + return Py_BuildValue("i", WSTOPSIG(status)); +} +#endif /* WSTOPSIG */ + +#endif /* HAVE_SYS_WAIT_H */ + + +#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) +#ifdef _SCO_DS +/* SCO OpenServer 5.0 and later requires _SVID3 before it reveals the + needed definitions in sys/statvfs.h */ +#define _SVID3 +#endif +#include <sys/statvfs.h> + +static PyObject* +_pystatvfs_fromstructstatvfs(struct statvfs st) { + PyObject *v = PyStructSequence_New(&StatVFSResultType); + if (v == NULL) + return NULL; + +#if !defined(HAVE_LARGEFILE_SUPPORT) + PyStructSequence_SET_ITEM(v, 0, PyInt_FromLong((long) st.f_bsize)); + PyStructSequence_SET_ITEM(v, 1, PyInt_FromLong((long) st.f_frsize)); + PyStructSequence_SET_ITEM(v, 2, PyInt_FromLong((long) st.f_blocks)); + PyStructSequence_SET_ITEM(v, 3, PyInt_FromLong((long) st.f_bfree)); + PyStructSequence_SET_ITEM(v, 4, PyInt_FromLong((long) st.f_bavail)); + PyStructSequence_SET_ITEM(v, 5, PyInt_FromLong((long) st.f_files)); + PyStructSequence_SET_ITEM(v, 6, PyInt_FromLong((long) st.f_ffree)); + PyStructSequence_SET_ITEM(v, 7, PyInt_FromLong((long) st.f_favail)); + PyStructSequence_SET_ITEM(v, 8, PyInt_FromLong((long) st.f_flag)); + PyStructSequence_SET_ITEM(v, 9, PyInt_FromLong((long) st.f_namemax)); +#else + PyStructSequence_SET_ITEM(v, 0, PyInt_FromLong((long) st.f_bsize)); + PyStructSequence_SET_ITEM(v, 1, PyInt_FromLong((long) st.f_frsize)); + PyStructSequence_SET_ITEM(v, 2, + PyLong_FromLongLong((PY_LONG_LONG) st.f_blocks)); + PyStructSequence_SET_ITEM(v, 3, + PyLong_FromLongLong((PY_LONG_LONG) st.f_bfree)); + PyStructSequence_SET_ITEM(v, 4, + PyLong_FromLongLong((PY_LONG_LONG) st.f_bavail)); + PyStructSequence_SET_ITEM(v, 5, + PyLong_FromLongLong((PY_LONG_LONG) st.f_files)); + PyStructSequence_SET_ITEM(v, 6, + PyLong_FromLongLong((PY_LONG_LONG) st.f_ffree)); + PyStructSequence_SET_ITEM(v, 7, + PyLong_FromLongLong((PY_LONG_LONG) st.f_favail)); + PyStructSequence_SET_ITEM(v, 8, PyInt_FromLong((long) st.f_flag)); + PyStructSequence_SET_ITEM(v, 9, PyInt_FromLong((long) st.f_namemax)); +#endif + + return v; +} + +PyDoc_STRVAR(posix_fstatvfs__doc__, +"fstatvfs(fd) -> statvfs result\n\n\ +Perform an fstatvfs system call on the given fd."); + +static PyObject * +posix_fstatvfs(PyObject *self, PyObject *args) +{ + int fd, res; + struct statvfs st; + + if (!PyArg_ParseTuple(args, "i:fstatvfs", &fd)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = fstatvfs(fd, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error(); + + return _pystatvfs_fromstructstatvfs(st); +} +#endif /* HAVE_FSTATVFS && HAVE_SYS_STATVFS_H */ + + +#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) +#include <sys/statvfs.h> + +PyDoc_STRVAR(posix_statvfs__doc__, +"statvfs(path) -> statvfs result\n\n\ +Perform a statvfs system call on the given path."); + +static PyObject * +posix_statvfs(PyObject *self, PyObject *args) +{ + char *path; + int res; + struct statvfs st; + if (!PyArg_ParseTuple(args, "s:statvfs", &path)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = statvfs(path, &st); + Py_END_ALLOW_THREADS + if (res != 0) + return posix_error_with_filename(path); + + return _pystatvfs_fromstructstatvfs(st); +} +#endif /* HAVE_STATVFS */ + + +#ifdef HAVE_TEMPNAM +PyDoc_STRVAR(posix_tempnam__doc__, +"tempnam([dir[, prefix]]) -> string\n\n\ +Return a unique name for a temporary file.\n\ +The directory and a prefix may be specified as strings; they may be omitted\n\ +or None if not needed."); + +static PyObject * +posix_tempnam(PyObject *self, PyObject *args) +{ + PyObject *result = NULL; + char *dir = NULL; + char *pfx = NULL; + char *name; + + if (!PyArg_ParseTuple(args, "|zz:tempnam", &dir, &pfx)) + return NULL; + + if (PyErr_Warn(PyExc_RuntimeWarning, + "tempnam is a potential security risk to your program") < 0) + return NULL; + +#ifdef MS_WINDOWS + name = _tempnam(dir, pfx); +#else + name = tempnam(dir, pfx); +#endif + if (name == NULL) + return PyErr_NoMemory(); + result = PyString_FromString(name); + free(name); + return result; +} +#endif + + +#ifdef HAVE_TMPFILE +PyDoc_STRVAR(posix_tmpfile__doc__, +"tmpfile() -> file object\n\n\ +Create a temporary file with no directory entries."); + +static PyObject * +posix_tmpfile(PyObject *self, PyObject *noargs) +{ + FILE *fp; + + fp = tmpfile(); + if (fp == NULL) + return posix_error(); + return PyFile_FromFile(fp, "<tmpfile>", "w+b", fclose); +} +#endif + + +#ifdef HAVE_TMPNAM +PyDoc_STRVAR(posix_tmpnam__doc__, +"tmpnam() -> string\n\n\ +Return a unique name for a temporary file."); + +static PyObject * +posix_tmpnam(PyObject *self, PyObject *noargs) +{ + char buffer[L_tmpnam]; + char *name; + + if (PyErr_Warn(PyExc_RuntimeWarning, + "tmpnam is a potential security risk to your program") < 0) + return NULL; + +#ifdef USE_TMPNAM_R + name = tmpnam_r(buffer); +#else + name = tmpnam(buffer); +#endif + if (name == NULL) { + PyObject *err = Py_BuildValue("is", 0, +#ifdef USE_TMPNAM_R + "unexpected NULL from tmpnam_r" +#else + "unexpected NULL from tmpnam" +#endif + ); + PyErr_SetObject(PyExc_OSError, err); + Py_XDECREF(err); + return NULL; + } + return PyString_FromString(buffer); +} +#endif + + +/* This is used for fpathconf(), pathconf(), confstr() and sysconf(). + * It maps strings representing configuration variable names to + * integer values, allowing those functions to be called with the + * magic names instead of polluting the module's namespace with tons of + * rarely-used constants. There are three separate tables that use + * these definitions. + * + * This code is always included, even if none of the interfaces that + * need it are included. The #if hackery needed to avoid it would be + * sufficiently pervasive that it's not worth the loss of readability. + */ +struct constdef { + char *name; + long value; +}; + +static int +conv_confname(PyObject *arg, int *valuep, struct constdef *table, + size_t tablesize) +{ + if (PyInt_Check(arg)) { + *valuep = PyInt_AS_LONG(arg); + return 1; + } + if (PyString_Check(arg)) { + /* look up the value in the table using a binary search */ + size_t lo = 0; + size_t mid; + size_t hi = tablesize; + int cmp; + char *confname = PyString_AS_STRING(arg); + while (lo < hi) { + mid = (lo + hi) / 2; + cmp = strcmp(confname, table[mid].name); + if (cmp < 0) + hi = mid; + else if (cmp > 0) + lo = mid + 1; + else { + *valuep = table[mid].value; + return 1; + } + } + PyErr_SetString(PyExc_ValueError, "unrecognized configuration name"); + } + else + PyErr_SetString(PyExc_TypeError, + "configuration names must be strings or integers"); + return 0; +} + + +#if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF) +static struct constdef posix_constants_pathconf[] = { +#ifdef _PC_ABI_AIO_XFER_MAX + {"PC_ABI_AIO_XFER_MAX", _PC_ABI_AIO_XFER_MAX}, +#endif +#ifdef _PC_ABI_ASYNC_IO + {"PC_ABI_ASYNC_IO", _PC_ABI_ASYNC_IO}, +#endif +#ifdef _PC_ASYNC_IO + {"PC_ASYNC_IO", _PC_ASYNC_IO}, +#endif +#ifdef _PC_CHOWN_RESTRICTED + {"PC_CHOWN_RESTRICTED", _PC_CHOWN_RESTRICTED}, +#endif +#ifdef _PC_FILESIZEBITS + {"PC_FILESIZEBITS", _PC_FILESIZEBITS}, +#endif +#ifdef _PC_LAST + {"PC_LAST", _PC_LAST}, +#endif +#ifdef _PC_LINK_MAX + {"PC_LINK_MAX", _PC_LINK_MAX}, +#endif +#ifdef _PC_MAX_CANON + {"PC_MAX_CANON", _PC_MAX_CANON}, +#endif +#ifdef _PC_MAX_INPUT + {"PC_MAX_INPUT", _PC_MAX_INPUT}, +#endif +#ifdef _PC_NAME_MAX + {"PC_NAME_MAX", _PC_NAME_MAX}, +#endif +#ifdef _PC_NO_TRUNC + {"PC_NO_TRUNC", _PC_NO_TRUNC}, +#endif +#ifdef _PC_PATH_MAX + {"PC_PATH_MAX", _PC_PATH_MAX}, +#endif +#ifdef _PC_PIPE_BUF + {"PC_PIPE_BUF", _PC_PIPE_BUF}, +#endif +#ifdef _PC_PRIO_IO + {"PC_PRIO_IO", _PC_PRIO_IO}, +#endif +#ifdef _PC_SOCK_MAXBUF + {"PC_SOCK_MAXBUF", _PC_SOCK_MAXBUF}, +#endif +#ifdef _PC_SYNC_IO + {"PC_SYNC_IO", _PC_SYNC_IO}, +#endif +#ifdef _PC_VDISABLE + {"PC_VDISABLE", _PC_VDISABLE}, +#endif +}; + +static int +conv_path_confname(PyObject *arg, int *valuep) +{ + return conv_confname(arg, valuep, posix_constants_pathconf, + sizeof(posix_constants_pathconf) + / sizeof(struct constdef)); +} +#endif + +#ifdef HAVE_FPATHCONF +PyDoc_STRVAR(posix_fpathconf__doc__, +"fpathconf(fd, name) -> integer\n\n\ +Return the configuration limit name for the file descriptor fd.\n\ +If there is no limit, return -1."); + +static PyObject * +posix_fpathconf(PyObject *self, PyObject *args) +{ + PyObject *result = NULL; + int name, fd; + + if (PyArg_ParseTuple(args, "iO&:fpathconf", &fd, + conv_path_confname, &name)) { + long limit; + + errno = 0; + limit = fpathconf(fd, name); + if (limit == -1 && errno != 0) + posix_error(); + else + result = PyInt_FromLong(limit); + } + return result; +} +#endif + + +#ifdef HAVE_PATHCONF +PyDoc_STRVAR(posix_pathconf__doc__, +"pathconf(path, name) -> integer\n\n\ +Return the configuration limit name for the file or directory path.\n\ +If there is no limit, return -1."); + +static PyObject * +posix_pathconf(PyObject *self, PyObject *args) +{ + PyObject *result = NULL; + int name; + char *path; + + if (PyArg_ParseTuple(args, "sO&:pathconf", &path, + conv_path_confname, &name)) { + long limit; + + errno = 0; + limit = pathconf(path, name); + if (limit == -1 && errno != 0) { + if (errno == EINVAL) + /* could be a path or name problem */ + posix_error(); + else + posix_error_with_filename(path); + } + else + result = PyInt_FromLong(limit); + } + return result; +} +#endif + +#ifdef HAVE_CONFSTR +static struct constdef posix_constants_confstr[] = { +#ifdef _CS_ARCHITECTURE + {"CS_ARCHITECTURE", _CS_ARCHITECTURE}, +#endif +#ifdef _CS_HOSTNAME + {"CS_HOSTNAME", _CS_HOSTNAME}, +#endif +#ifdef _CS_HW_PROVIDER + {"CS_HW_PROVIDER", _CS_HW_PROVIDER}, +#endif +#ifdef _CS_HW_SERIAL + {"CS_HW_SERIAL", _CS_HW_SERIAL}, +#endif +#ifdef _CS_INITTAB_NAME + {"CS_INITTAB_NAME", _CS_INITTAB_NAME}, +#endif +#ifdef _CS_LFS64_CFLAGS + {"CS_LFS64_CFLAGS", _CS_LFS64_CFLAGS}, +#endif +#ifdef _CS_LFS64_LDFLAGS + {"CS_LFS64_LDFLAGS", _CS_LFS64_LDFLAGS}, +#endif +#ifdef _CS_LFS64_LIBS + {"CS_LFS64_LIBS", _CS_LFS64_LIBS}, +#endif +#ifdef _CS_LFS64_LINTFLAGS + {"CS_LFS64_LINTFLAGS", _CS_LFS64_LINTFLAGS}, +#endif +#ifdef _CS_LFS_CFLAGS + {"CS_LFS_CFLAGS", _CS_LFS_CFLAGS}, +#endif +#ifdef _CS_LFS_LDFLAGS + {"CS_LFS_LDFLAGS", _CS_LFS_LDFLAGS}, +#endif +#ifdef _CS_LFS_LIBS + {"CS_LFS_LIBS", _CS_LFS_LIBS}, +#endif +#ifdef _CS_LFS_LINTFLAGS + {"CS_LFS_LINTFLAGS", _CS_LFS_LINTFLAGS}, +#endif +#ifdef _CS_MACHINE + {"CS_MACHINE", _CS_MACHINE}, +#endif +#ifdef _CS_PATH + {"CS_PATH", _CS_PATH}, +#endif +#ifdef _CS_RELEASE + {"CS_RELEASE", _CS_RELEASE}, +#endif +#ifdef _CS_SRPC_DOMAIN + {"CS_SRPC_DOMAIN", _CS_SRPC_DOMAIN}, +#endif +#ifdef _CS_SYSNAME + {"CS_SYSNAME", _CS_SYSNAME}, +#endif +#ifdef _CS_VERSION + {"CS_VERSION", _CS_VERSION}, +#endif +#ifdef _CS_XBS5_ILP32_OFF32_CFLAGS + {"CS_XBS5_ILP32_OFF32_CFLAGS", _CS_XBS5_ILP32_OFF32_CFLAGS}, +#endif +#ifdef _CS_XBS5_ILP32_OFF32_LDFLAGS + {"CS_XBS5_ILP32_OFF32_LDFLAGS", _CS_XBS5_ILP32_OFF32_LDFLAGS}, +#endif +#ifdef _CS_XBS5_ILP32_OFF32_LIBS + {"CS_XBS5_ILP32_OFF32_LIBS", _CS_XBS5_ILP32_OFF32_LIBS}, +#endif +#ifdef _CS_XBS5_ILP32_OFF32_LINTFLAGS + {"CS_XBS5_ILP32_OFF32_LINTFLAGS", _CS_XBS5_ILP32_OFF32_LINTFLAGS}, +#endif +#ifdef _CS_XBS5_ILP32_OFFBIG_CFLAGS + {"CS_XBS5_ILP32_OFFBIG_CFLAGS", _CS_XBS5_ILP32_OFFBIG_CFLAGS}, +#endif +#ifdef _CS_XBS5_ILP32_OFFBIG_LDFLAGS + {"CS_XBS5_ILP32_OFFBIG_LDFLAGS", _CS_XBS5_ILP32_OFFBIG_LDFLAGS}, +#endif +#ifdef _CS_XBS5_ILP32_OFFBIG_LIBS + {"CS_XBS5_ILP32_OFFBIG_LIBS", _CS_XBS5_ILP32_OFFBIG_LIBS}, +#endif +#ifdef _CS_XBS5_ILP32_OFFBIG_LINTFLAGS + {"CS_XBS5_ILP32_OFFBIG_LINTFLAGS", _CS_XBS5_ILP32_OFFBIG_LINTFLAGS}, +#endif +#ifdef _CS_XBS5_LP64_OFF64_CFLAGS + {"CS_XBS5_LP64_OFF64_CFLAGS", _CS_XBS5_LP64_OFF64_CFLAGS}, +#endif +#ifdef _CS_XBS5_LP64_OFF64_LDFLAGS + {"CS_XBS5_LP64_OFF64_LDFLAGS", _CS_XBS5_LP64_OFF64_LDFLAGS}, +#endif +#ifdef _CS_XBS5_LP64_OFF64_LIBS + {"CS_XBS5_LP64_OFF64_LIBS", _CS_XBS5_LP64_OFF64_LIBS}, +#endif +#ifdef _CS_XBS5_LP64_OFF64_LINTFLAGS + {"CS_XBS5_LP64_OFF64_LINTFLAGS", _CS_XBS5_LP64_OFF64_LINTFLAGS}, +#endif +#ifdef _CS_XBS5_LPBIG_OFFBIG_CFLAGS + {"CS_XBS5_LPBIG_OFFBIG_CFLAGS", _CS_XBS5_LPBIG_OFFBIG_CFLAGS}, +#endif +#ifdef _CS_XBS5_LPBIG_OFFBIG_LDFLAGS + {"CS_XBS5_LPBIG_OFFBIG_LDFLAGS", _CS_XBS5_LPBIG_OFFBIG_LDFLAGS}, +#endif +#ifdef _CS_XBS5_LPBIG_OFFBIG_LIBS + {"CS_XBS5_LPBIG_OFFBIG_LIBS", _CS_XBS5_LPBIG_OFFBIG_LIBS}, +#endif +#ifdef _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS + {"CS_XBS5_LPBIG_OFFBIG_LINTFLAGS", _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS}, +#endif +#ifdef _MIPS_CS_AVAIL_PROCESSORS + {"MIPS_CS_AVAIL_PROCESSORS", _MIPS_CS_AVAIL_PROCESSORS}, +#endif +#ifdef _MIPS_CS_BASE + {"MIPS_CS_BASE", _MIPS_CS_BASE}, +#endif +#ifdef _MIPS_CS_HOSTID + {"MIPS_CS_HOSTID", _MIPS_CS_HOSTID}, +#endif +#ifdef _MIPS_CS_HW_NAME + {"MIPS_CS_HW_NAME", _MIPS_CS_HW_NAME}, +#endif +#ifdef _MIPS_CS_NUM_PROCESSORS + {"MIPS_CS_NUM_PROCESSORS", _MIPS_CS_NUM_PROCESSORS}, +#endif +#ifdef _MIPS_CS_OSREL_MAJ + {"MIPS_CS_OSREL_MAJ", _MIPS_CS_OSREL_MAJ}, +#endif +#ifdef _MIPS_CS_OSREL_MIN + {"MIPS_CS_OSREL_MIN", _MIPS_CS_OSREL_MIN}, +#endif +#ifdef _MIPS_CS_OSREL_PATCH + {"MIPS_CS_OSREL_PATCH", _MIPS_CS_OSREL_PATCH}, +#endif +#ifdef _MIPS_CS_OS_NAME + {"MIPS_CS_OS_NAME", _MIPS_CS_OS_NAME}, +#endif +#ifdef _MIPS_CS_OS_PROVIDER + {"MIPS_CS_OS_PROVIDER", _MIPS_CS_OS_PROVIDER}, +#endif +#ifdef _MIPS_CS_PROCESSORS + {"MIPS_CS_PROCESSORS", _MIPS_CS_PROCESSORS}, +#endif +#ifdef _MIPS_CS_SERIAL + {"MIPS_CS_SERIAL", _MIPS_CS_SERIAL}, +#endif +#ifdef _MIPS_CS_VENDOR + {"MIPS_CS_VENDOR", _MIPS_CS_VENDOR}, +#endif +}; + +static int +conv_confstr_confname(PyObject *arg, int *valuep) +{ + return conv_confname(arg, valuep, posix_constants_confstr, + sizeof(posix_constants_confstr) + / sizeof(struct constdef)); +} + +PyDoc_STRVAR(posix_confstr__doc__, +"confstr(name) -> string\n\n\ +Return a string-valued system configuration variable."); + +static PyObject * +posix_confstr(PyObject *self, PyObject *args) +{ + PyObject *result = NULL; + int name; + char buffer[256]; + + if (PyArg_ParseTuple(args, "O&:confstr", conv_confstr_confname, &name)) { + int len; + + errno = 0; + len = confstr(name, buffer, sizeof(buffer)); + if (len == 0) { + if (errno) { + posix_error(); + } + else { + result = Py_None; + Py_INCREF(Py_None); + } + } + else { + if ((unsigned int)len >= sizeof(buffer)) { + result = PyString_FromStringAndSize(NULL, len-1); + if (result != NULL) + confstr(name, PyString_AS_STRING(result), len); + } + else + result = PyString_FromStringAndSize(buffer, len-1); + } + } + return result; +} +#endif + + +#ifdef HAVE_SYSCONF +static struct constdef posix_constants_sysconf[] = { +#ifdef _SC_2_CHAR_TERM + {"SC_2_CHAR_TERM", _SC_2_CHAR_TERM}, +#endif +#ifdef _SC_2_C_BIND + {"SC_2_C_BIND", _SC_2_C_BIND}, +#endif +#ifdef _SC_2_C_DEV + {"SC_2_C_DEV", _SC_2_C_DEV}, +#endif +#ifdef _SC_2_C_VERSION + {"SC_2_C_VERSION", _SC_2_C_VERSION}, +#endif +#ifdef _SC_2_FORT_DEV + {"SC_2_FORT_DEV", _SC_2_FORT_DEV}, +#endif +#ifdef _SC_2_FORT_RUN + {"SC_2_FORT_RUN", _SC_2_FORT_RUN}, +#endif +#ifdef _SC_2_LOCALEDEF + {"SC_2_LOCALEDEF", _SC_2_LOCALEDEF}, +#endif +#ifdef _SC_2_SW_DEV + {"SC_2_SW_DEV", _SC_2_SW_DEV}, +#endif +#ifdef _SC_2_UPE + {"SC_2_UPE", _SC_2_UPE}, +#endif +#ifdef _SC_2_VERSION + {"SC_2_VERSION", _SC_2_VERSION}, +#endif +#ifdef _SC_ABI_ASYNCHRONOUS_IO + {"SC_ABI_ASYNCHRONOUS_IO", _SC_ABI_ASYNCHRONOUS_IO}, +#endif +#ifdef _SC_ACL + {"SC_ACL", _SC_ACL}, +#endif +#ifdef _SC_AIO_LISTIO_MAX + {"SC_AIO_LISTIO_MAX", _SC_AIO_LISTIO_MAX}, +#endif +#ifdef _SC_AIO_MAX + {"SC_AIO_MAX", _SC_AIO_MAX}, +#endif +#ifdef _SC_AIO_PRIO_DELTA_MAX + {"SC_AIO_PRIO_DELTA_MAX", _SC_AIO_PRIO_DELTA_MAX}, +#endif +#ifdef _SC_ARG_MAX + {"SC_ARG_MAX", _SC_ARG_MAX}, +#endif +#ifdef _SC_ASYNCHRONOUS_IO + {"SC_ASYNCHRONOUS_IO", _SC_ASYNCHRONOUS_IO}, +#endif +#ifdef _SC_ATEXIT_MAX + {"SC_ATEXIT_MAX", _SC_ATEXIT_MAX}, +#endif +#ifdef _SC_AUDIT + {"SC_AUDIT", _SC_AUDIT}, +#endif +#ifdef _SC_AVPHYS_PAGES + {"SC_AVPHYS_PAGES", _SC_AVPHYS_PAGES}, +#endif +#ifdef _SC_BC_BASE_MAX + {"SC_BC_BASE_MAX", _SC_BC_BASE_MAX}, +#endif +#ifdef _SC_BC_DIM_MAX + {"SC_BC_DIM_MAX", _SC_BC_DIM_MAX}, +#endif +#ifdef _SC_BC_SCALE_MAX + {"SC_BC_SCALE_MAX", _SC_BC_SCALE_MAX}, +#endif +#ifdef _SC_BC_STRING_MAX + {"SC_BC_STRING_MAX", _SC_BC_STRING_MAX}, +#endif +#ifdef _SC_CAP + {"SC_CAP", _SC_CAP}, +#endif +#ifdef _SC_CHARCLASS_NAME_MAX + {"SC_CHARCLASS_NAME_MAX", _SC_CHARCLASS_NAME_MAX}, +#endif +#ifdef _SC_CHAR_BIT + {"SC_CHAR_BIT", _SC_CHAR_BIT}, +#endif +#ifdef _SC_CHAR_MAX + {"SC_CHAR_MAX", _SC_CHAR_MAX}, +#endif +#ifdef _SC_CHAR_MIN + {"SC_CHAR_MIN", _SC_CHAR_MIN}, +#endif +#ifdef _SC_CHILD_MAX + {"SC_CHILD_MAX", _SC_CHILD_MAX}, +#endif +#ifdef _SC_CLK_TCK + {"SC_CLK_TCK", _SC_CLK_TCK}, +#endif +#ifdef _SC_COHER_BLKSZ + {"SC_COHER_BLKSZ", _SC_COHER_BLKSZ}, +#endif +#ifdef _SC_COLL_WEIGHTS_MAX + {"SC_COLL_WEIGHTS_MAX", _SC_COLL_WEIGHTS_MAX}, +#endif +#ifdef _SC_DCACHE_ASSOC + {"SC_DCACHE_ASSOC", _SC_DCACHE_ASSOC}, +#endif +#ifdef _SC_DCACHE_BLKSZ + {"SC_DCACHE_BLKSZ", _SC_DCACHE_BLKSZ}, +#endif +#ifdef _SC_DCACHE_LINESZ + {"SC_DCACHE_LINESZ", _SC_DCACHE_LINESZ}, +#endif +#ifdef _SC_DCACHE_SZ + {"SC_DCACHE_SZ", _SC_DCACHE_SZ}, +#endif +#ifdef _SC_DCACHE_TBLKSZ + {"SC_DCACHE_TBLKSZ", _SC_DCACHE_TBLKSZ}, +#endif +#ifdef _SC_DELAYTIMER_MAX + {"SC_DELAYTIMER_MAX", _SC_DELAYTIMER_MAX}, +#endif +#ifdef _SC_EQUIV_CLASS_MAX + {"SC_EQUIV_CLASS_MAX", _SC_EQUIV_CLASS_MAX}, +#endif +#ifdef _SC_EXPR_NEST_MAX + {"SC_EXPR_NEST_MAX", _SC_EXPR_NEST_MAX}, +#endif +#ifdef _SC_FSYNC + {"SC_FSYNC", _SC_FSYNC}, +#endif +#ifdef _SC_GETGR_R_SIZE_MAX + {"SC_GETGR_R_SIZE_MAX", _SC_GETGR_R_SIZE_MAX}, +#endif +#ifdef _SC_GETPW_R_SIZE_MAX + {"SC_GETPW_R_SIZE_MAX", _SC_GETPW_R_SIZE_MAX}, +#endif +#ifdef _SC_ICACHE_ASSOC + {"SC_ICACHE_ASSOC", _SC_ICACHE_ASSOC}, +#endif +#ifdef _SC_ICACHE_BLKSZ + {"SC_ICACHE_BLKSZ", _SC_ICACHE_BLKSZ}, +#endif +#ifdef _SC_ICACHE_LINESZ + {"SC_ICACHE_LINESZ", _SC_ICACHE_LINESZ}, +#endif +#ifdef _SC_ICACHE_SZ + {"SC_ICACHE_SZ", _SC_ICACHE_SZ}, +#endif +#ifdef _SC_INF + {"SC_INF", _SC_INF}, +#endif +#ifdef _SC_INT_MAX + {"SC_INT_MAX", _SC_INT_MAX}, +#endif +#ifdef _SC_INT_MIN + {"SC_INT_MIN", _SC_INT_MIN}, +#endif +#ifdef _SC_IOV_MAX + {"SC_IOV_MAX", _SC_IOV_MAX}, +#endif +#ifdef _SC_IP_SECOPTS + {"SC_IP_SECOPTS", _SC_IP_SECOPTS}, +#endif +#ifdef _SC_JOB_CONTROL + {"SC_JOB_CONTROL", _SC_JOB_CONTROL}, +#endif +#ifdef _SC_KERN_POINTERS + {"SC_KERN_POINTERS", _SC_KERN_POINTERS}, +#endif +#ifdef _SC_KERN_SIM + {"SC_KERN_SIM", _SC_KERN_SIM}, +#endif +#ifdef _SC_LINE_MAX + {"SC_LINE_MAX", _SC_LINE_MAX}, +#endif +#ifdef _SC_LOGIN_NAME_MAX + {"SC_LOGIN_NAME_MAX", _SC_LOGIN_NAME_MAX}, +#endif +#ifdef _SC_LOGNAME_MAX + {"SC_LOGNAME_MAX", _SC_LOGNAME_MAX}, +#endif +#ifdef _SC_LONG_BIT + {"SC_LONG_BIT", _SC_LONG_BIT}, +#endif +#ifdef _SC_MAC + {"SC_MAC", _SC_MAC}, +#endif +#ifdef _SC_MAPPED_FILES + {"SC_MAPPED_FILES", _SC_MAPPED_FILES}, +#endif +#ifdef _SC_MAXPID + {"SC_MAXPID", _SC_MAXPID}, +#endif +#ifdef _SC_MB_LEN_MAX + {"SC_MB_LEN_MAX", _SC_MB_LEN_MAX}, +#endif +#ifdef _SC_MEMLOCK + {"SC_MEMLOCK", _SC_MEMLOCK}, +#endif +#ifdef _SC_MEMLOCK_RANGE + {"SC_MEMLOCK_RANGE", _SC_MEMLOCK_RANGE}, +#endif +#ifdef _SC_MEMORY_PROTECTION + {"SC_MEMORY_PROTECTION", _SC_MEMORY_PROTECTION}, +#endif +#ifdef _SC_MESSAGE_PASSING + {"SC_MESSAGE_PASSING", _SC_MESSAGE_PASSING}, +#endif +#ifdef _SC_MMAP_FIXED_ALIGNMENT + {"SC_MMAP_FIXED_ALIGNMENT", _SC_MMAP_FIXED_ALIGNMENT}, +#endif +#ifdef _SC_MQ_OPEN_MAX + {"SC_MQ_OPEN_MAX", _SC_MQ_OPEN_MAX}, +#endif +#ifdef _SC_MQ_PRIO_MAX + {"SC_MQ_PRIO_MAX", _SC_MQ_PRIO_MAX}, +#endif +#ifdef _SC_NACLS_MAX + {"SC_NACLS_MAX", _SC_NACLS_MAX}, +#endif +#ifdef _SC_NGROUPS_MAX + {"SC_NGROUPS_MAX", _SC_NGROUPS_MAX}, +#endif +#ifdef _SC_NL_ARGMAX + {"SC_NL_ARGMAX", _SC_NL_ARGMAX}, +#endif +#ifdef _SC_NL_LANGMAX + {"SC_NL_LANGMAX", _SC_NL_LANGMAX}, +#endif +#ifdef _SC_NL_MSGMAX + {"SC_NL_MSGMAX", _SC_NL_MSGMAX}, +#endif +#ifdef _SC_NL_NMAX + {"SC_NL_NMAX", _SC_NL_NMAX}, +#endif +#ifdef _SC_NL_SETMAX + {"SC_NL_SETMAX", _SC_NL_SETMAX}, +#endif +#ifdef _SC_NL_TEXTMAX + {"SC_NL_TEXTMAX", _SC_NL_TEXTMAX}, +#endif +#ifdef _SC_NPROCESSORS_CONF + {"SC_NPROCESSORS_CONF", _SC_NPROCESSORS_CONF}, +#endif +#ifdef _SC_NPROCESSORS_ONLN + {"SC_NPROCESSORS_ONLN", _SC_NPROCESSORS_ONLN}, +#endif +#ifdef _SC_NPROC_CONF + {"SC_NPROC_CONF", _SC_NPROC_CONF}, +#endif +#ifdef _SC_NPROC_ONLN + {"SC_NPROC_ONLN", _SC_NPROC_ONLN}, +#endif +#ifdef _SC_NZERO + {"SC_NZERO", _SC_NZERO}, +#endif +#ifdef _SC_OPEN_MAX + {"SC_OPEN_MAX", _SC_OPEN_MAX}, +#endif +#ifdef _SC_PAGESIZE + {"SC_PAGESIZE", _SC_PAGESIZE}, +#endif +#ifdef _SC_PAGE_SIZE + {"SC_PAGE_SIZE", _SC_PAGE_SIZE}, +#endif +#ifdef _SC_PASS_MAX + {"SC_PASS_MAX", _SC_PASS_MAX}, +#endif +#ifdef _SC_PHYS_PAGES + {"SC_PHYS_PAGES", _SC_PHYS_PAGES}, +#endif +#ifdef _SC_PII + {"SC_PII", _SC_PII}, +#endif +#ifdef _SC_PII_INTERNET + {"SC_PII_INTERNET", _SC_PII_INTERNET}, +#endif +#ifdef _SC_PII_INTERNET_DGRAM + {"SC_PII_INTERNET_DGRAM", _SC_PII_INTERNET_DGRAM}, +#endif +#ifdef _SC_PII_INTERNET_STREAM + {"SC_PII_INTERNET_STREAM", _SC_PII_INTERNET_STREAM}, +#endif +#ifdef _SC_PII_OSI + {"SC_PII_OSI", _SC_PII_OSI}, +#endif +#ifdef _SC_PII_OSI_CLTS + {"SC_PII_OSI_CLTS", _SC_PII_OSI_CLTS}, +#endif +#ifdef _SC_PII_OSI_COTS + {"SC_PII_OSI_COTS", _SC_PII_OSI_COTS}, +#endif +#ifdef _SC_PII_OSI_M + {"SC_PII_OSI_M", _SC_PII_OSI_M}, +#endif +#ifdef _SC_PII_SOCKET + {"SC_PII_SOCKET", _SC_PII_SOCKET}, +#endif +#ifdef _SC_PII_XTI + {"SC_PII_XTI", _SC_PII_XTI}, +#endif +#ifdef _SC_POLL + {"SC_POLL", _SC_POLL}, +#endif +#ifdef _SC_PRIORITIZED_IO + {"SC_PRIORITIZED_IO", _SC_PRIORITIZED_IO}, +#endif +#ifdef _SC_PRIORITY_SCHEDULING + {"SC_PRIORITY_SCHEDULING", _SC_PRIORITY_SCHEDULING}, +#endif +#ifdef _SC_REALTIME_SIGNALS + {"SC_REALTIME_SIGNALS", _SC_REALTIME_SIGNALS}, +#endif +#ifdef _SC_RE_DUP_MAX + {"SC_RE_DUP_MAX", _SC_RE_DUP_MAX}, +#endif +#ifdef _SC_RTSIG_MAX + {"SC_RTSIG_MAX", _SC_RTSIG_MAX}, +#endif +#ifdef _SC_SAVED_IDS + {"SC_SAVED_IDS", _SC_SAVED_IDS}, +#endif +#ifdef _SC_SCHAR_MAX + {"SC_SCHAR_MAX", _SC_SCHAR_MAX}, +#endif +#ifdef _SC_SCHAR_MIN + {"SC_SCHAR_MIN", _SC_SCHAR_MIN}, +#endif +#ifdef _SC_SELECT + {"SC_SELECT", _SC_SELECT}, +#endif +#ifdef _SC_SEMAPHORES + {"SC_SEMAPHORES", _SC_SEMAPHORES}, +#endif +#ifdef _SC_SEM_NSEMS_MAX + {"SC_SEM_NSEMS_MAX", _SC_SEM_NSEMS_MAX}, +#endif +#ifdef _SC_SEM_VALUE_MAX + {"SC_SEM_VALUE_MAX", _SC_SEM_VALUE_MAX}, +#endif +#ifdef _SC_SHARED_MEMORY_OBJECTS + {"SC_SHARED_MEMORY_OBJECTS", _SC_SHARED_MEMORY_OBJECTS}, +#endif +#ifdef _SC_SHRT_MAX + {"SC_SHRT_MAX", _SC_SHRT_MAX}, +#endif +#ifdef _SC_SHRT_MIN + {"SC_SHRT_MIN", _SC_SHRT_MIN}, +#endif +#ifdef _SC_SIGQUEUE_MAX + {"SC_SIGQUEUE_MAX", _SC_SIGQUEUE_MAX}, +#endif +#ifdef _SC_SIGRT_MAX + {"SC_SIGRT_MAX", _SC_SIGRT_MAX}, +#endif +#ifdef _SC_SIGRT_MIN + {"SC_SIGRT_MIN", _SC_SIGRT_MIN}, +#endif +#ifdef _SC_SOFTPOWER + {"SC_SOFTPOWER", _SC_SOFTPOWER}, +#endif +#ifdef _SC_SPLIT_CACHE + {"SC_SPLIT_CACHE", _SC_SPLIT_CACHE}, +#endif +#ifdef _SC_SSIZE_MAX + {"SC_SSIZE_MAX", _SC_SSIZE_MAX}, +#endif +#ifdef _SC_STACK_PROT + {"SC_STACK_PROT", _SC_STACK_PROT}, +#endif +#ifdef _SC_STREAM_MAX + {"SC_STREAM_MAX", _SC_STREAM_MAX}, +#endif +#ifdef _SC_SYNCHRONIZED_IO + {"SC_SYNCHRONIZED_IO", _SC_SYNCHRONIZED_IO}, +#endif +#ifdef _SC_THREADS + {"SC_THREADS", _SC_THREADS}, +#endif +#ifdef _SC_THREAD_ATTR_STACKADDR + {"SC_THREAD_ATTR_STACKADDR", _SC_THREAD_ATTR_STACKADDR}, +#endif +#ifdef _SC_THREAD_ATTR_STACKSIZE + {"SC_THREAD_ATTR_STACKSIZE", _SC_THREAD_ATTR_STACKSIZE}, +#endif +#ifdef _SC_THREAD_DESTRUCTOR_ITERATIONS + {"SC_THREAD_DESTRUCTOR_ITERATIONS", _SC_THREAD_DESTRUCTOR_ITERATIONS}, +#endif +#ifdef _SC_THREAD_KEYS_MAX + {"SC_THREAD_KEYS_MAX", _SC_THREAD_KEYS_MAX}, +#endif +#ifdef _SC_THREAD_PRIORITY_SCHEDULING + {"SC_THREAD_PRIORITY_SCHEDULING", _SC_THREAD_PRIORITY_SCHEDULING}, +#endif +#ifdef _SC_THREAD_PRIO_INHERIT + {"SC_THREAD_PRIO_INHERIT", _SC_THREAD_PRIO_INHERIT}, +#endif +#ifdef _SC_THREAD_PRIO_PROTECT + {"SC_THREAD_PRIO_PROTECT", _SC_THREAD_PRIO_PROTECT}, +#endif +#ifdef _SC_THREAD_PROCESS_SHARED + {"SC_THREAD_PROCESS_SHARED", _SC_THREAD_PROCESS_SHARED}, +#endif +#ifdef _SC_THREAD_SAFE_FUNCTIONS + {"SC_THREAD_SAFE_FUNCTIONS", _SC_THREAD_SAFE_FUNCTIONS}, +#endif +#ifdef _SC_THREAD_STACK_MIN + {"SC_THREAD_STACK_MIN", _SC_THREAD_STACK_MIN}, +#endif +#ifdef _SC_THREAD_THREADS_MAX + {"SC_THREAD_THREADS_MAX", _SC_THREAD_THREADS_MAX}, +#endif +#ifdef _SC_TIMERS + {"SC_TIMERS", _SC_TIMERS}, +#endif +#ifdef _SC_TIMER_MAX + {"SC_TIMER_MAX", _SC_TIMER_MAX}, +#endif +#ifdef _SC_TTY_NAME_MAX + {"SC_TTY_NAME_MAX", _SC_TTY_NAME_MAX}, +#endif +#ifdef _SC_TZNAME_MAX + {"SC_TZNAME_MAX", _SC_TZNAME_MAX}, +#endif +#ifdef _SC_T_IOV_MAX + {"SC_T_IOV_MAX", _SC_T_IOV_MAX}, +#endif +#ifdef _SC_UCHAR_MAX + {"SC_UCHAR_MAX", _SC_UCHAR_MAX}, +#endif +#ifdef _SC_UINT_MAX + {"SC_UINT_MAX", _SC_UINT_MAX}, +#endif +#ifdef _SC_UIO_MAXIOV + {"SC_UIO_MAXIOV", _SC_UIO_MAXIOV}, +#endif +#ifdef _SC_ULONG_MAX + {"SC_ULONG_MAX", _SC_ULONG_MAX}, +#endif +#ifdef _SC_USHRT_MAX + {"SC_USHRT_MAX", _SC_USHRT_MAX}, +#endif +#ifdef _SC_VERSION + {"SC_VERSION", _SC_VERSION}, +#endif +#ifdef _SC_WORD_BIT + {"SC_WORD_BIT", _SC_WORD_BIT}, +#endif +#ifdef _SC_XBS5_ILP32_OFF32 + {"SC_XBS5_ILP32_OFF32", _SC_XBS5_ILP32_OFF32}, +#endif +#ifdef _SC_XBS5_ILP32_OFFBIG + {"SC_XBS5_ILP32_OFFBIG", _SC_XBS5_ILP32_OFFBIG}, +#endif +#ifdef _SC_XBS5_LP64_OFF64 + {"SC_XBS5_LP64_OFF64", _SC_XBS5_LP64_OFF64}, +#endif +#ifdef _SC_XBS5_LPBIG_OFFBIG + {"SC_XBS5_LPBIG_OFFBIG", _SC_XBS5_LPBIG_OFFBIG}, +#endif +#ifdef _SC_XOPEN_CRYPT + {"SC_XOPEN_CRYPT", _SC_XOPEN_CRYPT}, +#endif +#ifdef _SC_XOPEN_ENH_I18N + {"SC_XOPEN_ENH_I18N", _SC_XOPEN_ENH_I18N}, +#endif +#ifdef _SC_XOPEN_LEGACY + {"SC_XOPEN_LEGACY", _SC_XOPEN_LEGACY}, +#endif +#ifdef _SC_XOPEN_REALTIME + {"SC_XOPEN_REALTIME", _SC_XOPEN_REALTIME}, +#endif +#ifdef _SC_XOPEN_REALTIME_THREADS + {"SC_XOPEN_REALTIME_THREADS", _SC_XOPEN_REALTIME_THREADS}, +#endif +#ifdef _SC_XOPEN_SHM + {"SC_XOPEN_SHM", _SC_XOPEN_SHM}, +#endif +#ifdef _SC_XOPEN_UNIX + {"SC_XOPEN_UNIX", _SC_XOPEN_UNIX}, +#endif +#ifdef _SC_XOPEN_VERSION + {"SC_XOPEN_VERSION", _SC_XOPEN_VERSION}, +#endif +#ifdef _SC_XOPEN_XCU_VERSION + {"SC_XOPEN_XCU_VERSION", _SC_XOPEN_XCU_VERSION}, +#endif +#ifdef _SC_XOPEN_XPG2 + {"SC_XOPEN_XPG2", _SC_XOPEN_XPG2}, +#endif +#ifdef _SC_XOPEN_XPG3 + {"SC_XOPEN_XPG3", _SC_XOPEN_XPG3}, +#endif +#ifdef _SC_XOPEN_XPG4 + {"SC_XOPEN_XPG4", _SC_XOPEN_XPG4}, +#endif +}; + +static int +conv_sysconf_confname(PyObject *arg, int *valuep) +{ + return conv_confname(arg, valuep, posix_constants_sysconf, + sizeof(posix_constants_sysconf) + / sizeof(struct constdef)); +} + +PyDoc_STRVAR(posix_sysconf__doc__, +"sysconf(name) -> integer\n\n\ +Return an integer-valued system configuration variable."); + +static PyObject * +posix_sysconf(PyObject *self, PyObject *args) +{ + PyObject *result = NULL; + int name; + + if (PyArg_ParseTuple(args, "O&:sysconf", conv_sysconf_confname, &name)) { + int value; + + errno = 0; + value = sysconf(name); + if (value == -1 && errno != 0) + posix_error(); + else + result = PyInt_FromLong(value); + } + return result; +} +#endif + + +/* This code is used to ensure that the tables of configuration value names + * are in sorted order as required by conv_confname(), and also to build the + * the exported dictionaries that are used to publish information about the + * names available on the host platform. + * + * Sorting the table at runtime ensures that the table is properly ordered + * when used, even for platforms we're not able to test on. It also makes + * it easier to add additional entries to the tables. + */ + +static int +cmp_constdefs(const void *v1, const void *v2) +{ + const struct constdef *c1 = + (const struct constdef *) v1; + const struct constdef *c2 = + (const struct constdef *) v2; + + return strcmp(c1->name, c2->name); +} + +static int +setup_confname_table(struct constdef *table, size_t tablesize, + char *tablename, PyObject *module) +{ + PyObject *d = NULL; + size_t i; + + qsort(table, tablesize, sizeof(struct constdef), cmp_constdefs); + d = PyDict_New(); + if (d == NULL) + return -1; + + for (i=0; i < tablesize; ++i) { + PyObject *o = PyInt_FromLong(table[i].value); + if (o == NULL || PyDict_SetItemString(d, table[i].name, o) == -1) { + Py_XDECREF(o); + Py_DECREF(d); + return -1; + } + Py_DECREF(o); + } + return PyModule_AddObject(module, tablename, d); +} + +/* Return -1 on failure, 0 on success. */ +static int +setup_confname_tables(PyObject *module) +{ +#if defined(HAVE_FPATHCONF) || defined(HAVE_PATHCONF) + if (setup_confname_table(posix_constants_pathconf, + sizeof(posix_constants_pathconf) + / sizeof(struct constdef), + "pathconf_names", module)) + return -1; +#endif +#ifdef HAVE_CONFSTR + if (setup_confname_table(posix_constants_confstr, + sizeof(posix_constants_confstr) + / sizeof(struct constdef), + "confstr_names", module)) + return -1; +#endif +#ifdef HAVE_SYSCONF + if (setup_confname_table(posix_constants_sysconf, + sizeof(posix_constants_sysconf) + / sizeof(struct constdef), + "sysconf_names", module)) + return -1; +#endif + return 0; +} + + +PyDoc_STRVAR(posix_abort__doc__, +"abort() -> does not return!\n\n\ +Abort the interpreter immediately. This 'dumps core' or otherwise fails\n\ +in the hardest way possible on the hosting operating system."); + +static PyObject * +posix_abort(PyObject *self, PyObject *noargs) +{ + abort(); + /*NOTREACHED*/ + Py_FatalError("abort() called from Python code didn't abort!"); + return NULL; +} + +#ifdef MS_WINDOWS +PyDoc_STRVAR(win32_startfile__doc__, +"startfile(filepath [, operation]) - Start a file with its associated\n\ +application.\n\ +\n\ +When \"operation\" is not specified or \"open\", this acts like\n\ +double-clicking the file in Explorer, or giving the file name as an\n\ +argument to the DOS \"start\" command: the file is opened with whatever\n\ +application (if any) its extension is associated.\n\ +When another \"operation\" is given, it specifies what should be done with\n\ +the file. A typical operation is \"print\".\n\ +\n\ +startfile returns as soon as the associated application is launched.\n\ +There is no option to wait for the application to close, and no way\n\ +to retrieve the application's exit status.\n\ +\n\ +The filepath is relative to the current directory. If you want to use\n\ +an absolute path, make sure the first character is not a slash (\"/\");\n\ +the underlying Win32 ShellExecute function doesn't work if it is."); + +static PyObject * +win32_startfile(PyObject *self, PyObject *args) +{ + char *filepath; + char *operation = NULL; + HINSTANCE rc; +#ifdef Py_WIN_WIDE_FILENAMES + if (unicode_file_names()) { + PyObject *unipath, *woperation = NULL; + if (!PyArg_ParseTuple(args, "U|s:startfile", + &unipath, &operation)) { + PyErr_Clear(); + goto normal; + } + + + if (operation) { + woperation = PyUnicode_DecodeASCII(operation, + strlen(operation), NULL); + if (!woperation) { + PyErr_Clear(); + operation = NULL; + goto normal; + } + } + + Py_BEGIN_ALLOW_THREADS + rc = ShellExecuteW((HWND)0, woperation ? PyUnicode_AS_UNICODE(woperation) : 0, + PyUnicode_AS_UNICODE(unipath), + NULL, NULL, SW_SHOWNORMAL); + Py_END_ALLOW_THREADS + + Py_XDECREF(woperation); + if (rc <= (HINSTANCE)32) { + PyObject *errval = win32_error_unicode("startfile", + PyUnicode_AS_UNICODE(unipath)); + return errval; + } + Py_INCREF(Py_None); + return Py_None; + } +#endif + +normal: + if (!PyArg_ParseTuple(args, "et|s:startfile", + Py_FileSystemDefaultEncoding, &filepath, + &operation)) + return NULL; + Py_BEGIN_ALLOW_THREADS + rc = ShellExecute((HWND)0, operation, filepath, + NULL, NULL, SW_SHOWNORMAL); + Py_END_ALLOW_THREADS + if (rc <= (HINSTANCE)32) { + PyObject *errval = win32_error("startfile", filepath); + PyMem_Free(filepath); + return errval; + } + PyMem_Free(filepath); + Py_INCREF(Py_None); + return Py_None; +} +#endif + +#ifdef HAVE_GETLOADAVG +PyDoc_STRVAR(posix_getloadavg__doc__, +"getloadavg() -> (float, float, float)\n\n\ +Return the number of processes in the system run queue averaged over\n\ +the last 1, 5, and 15 minutes or raises OSError if the load average\n\ +was unobtainable"); + +static PyObject * +posix_getloadavg(PyObject *self, PyObject *noargs) +{ + double loadavg[3]; + if (getloadavg(loadavg, 3)!=3) { + PyErr_SetString(PyExc_OSError, "Load averages are unobtainable"); + return NULL; + } else + return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]); +} +#endif + +#ifdef MS_WINDOWS + +PyDoc_STRVAR(win32_urandom__doc__, +"urandom(n) -> str\n\n\ +Return a string of n random bytes suitable for cryptographic use."); + +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\ + LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\ + DWORD dwFlags ); +typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\ + BYTE *pbBuffer ); + +static CRYPTGENRANDOM pCryptGenRandom = NULL; +static HCRYPTPROV hCryptProv = 0; + +static PyObject* +win32_urandom(PyObject *self, PyObject *args) +{ + int howMany; + PyObject* result; + + /* Read arguments */ + if (! PyArg_ParseTuple(args, "i:urandom", &howMany)) + return NULL; + if (howMany < 0) + return PyErr_Format(PyExc_ValueError, + "negative argument not allowed"); + + if (hCryptProv == 0) { + HINSTANCE hAdvAPI32 = NULL; + CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; + + /* Obtain handle to the DLL containing CryptoAPI + This should not fail */ + hAdvAPI32 = GetModuleHandle("advapi32.dll"); + if(hAdvAPI32 == NULL) + return win32_error("GetModuleHandle", NULL); + + /* Obtain pointers to the CryptoAPI functions + This will fail on some early versions of Win95 */ + pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress( + hAdvAPI32, + "CryptAcquireContextA"); + if (pCryptAcquireContext == NULL) + return PyErr_Format(PyExc_NotImplementedError, + "CryptAcquireContextA not found"); + + pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress( + hAdvAPI32, "CryptGenRandom"); + if (pCryptGenRandom == NULL) + return PyErr_Format(PyExc_NotImplementedError, + "CryptGenRandom not found"); + + /* Acquire context */ + if (! pCryptAcquireContext(&hCryptProv, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + return win32_error("CryptAcquireContext", NULL); + } + + /* Allocate bytes */ + result = PyString_FromStringAndSize(NULL, howMany); + if (result != NULL) { + /* Get random data */ + if (! pCryptGenRandom(hCryptProv, howMany, (unsigned char*) + PyString_AS_STRING(result))) { + Py_DECREF(result); + return win32_error("CryptGenRandom", NULL); + } + } + return result; +} +#endif + +#ifdef __VMS +/* Use openssl random routine */ +#include <openssl/rand.h> +PyDoc_STRVAR(vms_urandom__doc__, +"urandom(n) -> str\n\n\ +Return a string of n random bytes suitable for cryptographic use."); + +static PyObject* +vms_urandom(PyObject *self, PyObject *args) +{ + int howMany; + PyObject* result; + + /* Read arguments */ + if (! PyArg_ParseTuple(args, "i:urandom", &howMany)) + return NULL; + if (howMany < 0) + return PyErr_Format(PyExc_ValueError, + "negative argument not allowed"); + + /* Allocate bytes */ + result = PyString_FromStringAndSize(NULL, howMany); + if (result != NULL) { + /* Get random data */ + if (RAND_pseudo_bytes((unsigned char*) + PyString_AS_STRING(result), + howMany) < 0) { + Py_DECREF(result); + return PyErr_Format(PyExc_ValueError, + "RAND_pseudo_bytes"); + } + } + return result; +} +#endif + +static PyMethodDef posix_methods[] = { + {"access", posix_access, METH_VARARGS, posix_access__doc__}, +#ifdef HAVE_TTYNAME + {"ttyname", posix_ttyname, METH_VARARGS, posix_ttyname__doc__}, +#endif + {"chdir", posix_chdir, METH_VARARGS, posix_chdir__doc__}, + {"chmod", posix_chmod, METH_VARARGS, posix_chmod__doc__}, +#ifdef HAVE_CHOWN + {"chown", posix_chown, METH_VARARGS, posix_chown__doc__}, +#endif /* HAVE_CHOWN */ +#ifdef HAVE_LCHOWN + {"lchown", posix_lchown, METH_VARARGS, posix_lchown__doc__}, +#endif /* HAVE_LCHOWN */ +#ifdef HAVE_CHROOT + {"chroot", posix_chroot, METH_VARARGS, posix_chroot__doc__}, +#endif +#ifdef HAVE_CTERMID + {"ctermid", posix_ctermid, METH_NOARGS, posix_ctermid__doc__}, +#endif +#ifdef HAVE_GETCWD + {"getcwd", posix_getcwd, METH_NOARGS, posix_getcwd__doc__}, +#ifdef Py_USING_UNICODE + {"getcwdu", posix_getcwdu, METH_NOARGS, posix_getcwdu__doc__}, +#endif +#endif +#ifdef HAVE_LINK + {"link", posix_link, METH_VARARGS, posix_link__doc__}, +#endif /* HAVE_LINK */ + {"listdir", posix_listdir, METH_VARARGS, posix_listdir__doc__}, + {"lstat", posix_lstat, METH_VARARGS, posix_lstat__doc__}, + {"mkdir", posix_mkdir, METH_VARARGS, posix_mkdir__doc__}, +#ifdef HAVE_NICE + {"nice", posix_nice, METH_VARARGS, posix_nice__doc__}, +#endif /* HAVE_NICE */ +#ifdef HAVE_READLINK + {"readlink", posix_readlink, METH_VARARGS, posix_readlink__doc__}, +#endif /* HAVE_READLINK */ + {"rename", posix_rename, METH_VARARGS, posix_rename__doc__}, + {"rmdir", posix_rmdir, METH_VARARGS, posix_rmdir__doc__}, + {"stat", posix_stat, METH_VARARGS, posix_stat__doc__}, + {"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__}, +#ifdef HAVE_SYMLINK + {"symlink", posix_symlink, METH_VARARGS, posix_symlink__doc__}, +#endif /* HAVE_SYMLINK */ +#ifdef HAVE_SYSTEM + {"system", posix_system, METH_VARARGS, posix_system__doc__}, +#endif + {"umask", posix_umask, METH_VARARGS, posix_umask__doc__}, +#ifdef HAVE_UNAME + {"uname", posix_uname, METH_NOARGS, posix_uname__doc__}, +#endif /* HAVE_UNAME */ + {"unlink", posix_unlink, METH_VARARGS, posix_unlink__doc__}, + {"remove", posix_unlink, METH_VARARGS, posix_remove__doc__}, + {"utime", posix_utime, METH_VARARGS, posix_utime__doc__}, +#ifdef HAVE_TIMES + {"times", posix_times, METH_NOARGS, posix_times__doc__}, +#endif /* HAVE_TIMES */ + {"_exit", posix__exit, METH_VARARGS, posix__exit__doc__}, +#ifdef HAVE_EXECV + {"execv", posix_execv, METH_VARARGS, posix_execv__doc__}, + {"execve", posix_execve, METH_VARARGS, posix_execve__doc__}, +#endif /* HAVE_EXECV */ +#ifdef HAVE_SPAWNV + {"spawnv", posix_spawnv, METH_VARARGS, posix_spawnv__doc__}, + {"spawnve", posix_spawnve, METH_VARARGS, posix_spawnve__doc__}, +#if defined(PYOS_OS2) + {"spawnvp", posix_spawnvp, METH_VARARGS, posix_spawnvp__doc__}, + {"spawnvpe", posix_spawnvpe, METH_VARARGS, posix_spawnvpe__doc__}, +#endif /* PYOS_OS2 */ +#endif /* HAVE_SPAWNV */ +#ifdef HAVE_FORK1 + {"fork1", posix_fork1, METH_NOARGS, posix_fork1__doc__}, +#endif /* HAVE_FORK1 */ +#ifdef HAVE_FORK + {"fork", posix_fork, METH_NOARGS, posix_fork__doc__}, +#endif /* HAVE_FORK */ +#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) + {"openpty", posix_openpty, METH_NOARGS, posix_openpty__doc__}, +#endif /* HAVE_OPENPTY || HAVE__GETPTY || HAVE_DEV_PTMX */ +#ifdef HAVE_FORKPTY + {"forkpty", posix_forkpty, METH_NOARGS, posix_forkpty__doc__}, +#endif /* HAVE_FORKPTY */ +#ifdef HAVE_GETEGID + {"getegid", posix_getegid, METH_NOARGS, posix_getegid__doc__}, +#endif /* HAVE_GETEGID */ +#ifdef HAVE_GETEUID + {"geteuid", posix_geteuid, METH_NOARGS, posix_geteuid__doc__}, +#endif /* HAVE_GETEUID */ +#ifdef HAVE_GETGID + {"getgid", posix_getgid, METH_NOARGS, posix_getgid__doc__}, +#endif /* HAVE_GETGID */ +#ifdef HAVE_GETGROUPS + {"getgroups", posix_getgroups, METH_NOARGS, posix_getgroups__doc__}, +#endif + {"getpid", posix_getpid, METH_NOARGS, posix_getpid__doc__}, +#ifdef HAVE_GETPGRP + {"getpgrp", posix_getpgrp, METH_NOARGS, posix_getpgrp__doc__}, +#endif /* HAVE_GETPGRP */ +#ifdef HAVE_GETPPID + {"getppid", posix_getppid, METH_NOARGS, posix_getppid__doc__}, +#endif /* HAVE_GETPPID */ +#ifdef HAVE_GETUID + {"getuid", posix_getuid, METH_NOARGS, posix_getuid__doc__}, +#endif /* HAVE_GETUID */ +#ifdef HAVE_GETLOGIN + {"getlogin", posix_getlogin, METH_NOARGS, posix_getlogin__doc__}, +#endif +#ifdef HAVE_KILL + {"kill", posix_kill, METH_VARARGS, posix_kill__doc__}, +#endif /* HAVE_KILL */ +#ifdef HAVE_KILLPG + {"killpg", posix_killpg, METH_VARARGS, posix_killpg__doc__}, +#endif /* HAVE_KILLPG */ +#ifdef HAVE_PLOCK + {"plock", posix_plock, METH_VARARGS, posix_plock__doc__}, +#endif /* HAVE_PLOCK */ +#ifdef HAVE_POPEN + {"popen", posix_popen, METH_VARARGS, posix_popen__doc__}, +#ifdef MS_WINDOWS + {"popen2", win32_popen2, METH_VARARGS}, + {"popen3", win32_popen3, METH_VARARGS}, + {"popen4", win32_popen4, METH_VARARGS}, + {"startfile", win32_startfile, METH_VARARGS, win32_startfile__doc__}, +#else +#if defined(PYOS_OS2) && defined(PYCC_GCC) + {"popen2", os2emx_popen2, METH_VARARGS}, + {"popen3", os2emx_popen3, METH_VARARGS}, + {"popen4", os2emx_popen4, METH_VARARGS}, +#endif +#endif +#endif /* HAVE_POPEN */ +#ifdef HAVE_SETUID + {"setuid", posix_setuid, METH_VARARGS, posix_setuid__doc__}, +#endif /* HAVE_SETUID */ +#ifdef HAVE_SETEUID + {"seteuid", posix_seteuid, METH_VARARGS, posix_seteuid__doc__}, +#endif /* HAVE_SETEUID */ +#ifdef HAVE_SETEGID + {"setegid", posix_setegid, METH_VARARGS, posix_setegid__doc__}, +#endif /* HAVE_SETEGID */ +#ifdef HAVE_SETREUID + {"setreuid", posix_setreuid, METH_VARARGS, posix_setreuid__doc__}, +#endif /* HAVE_SETREUID */ +#ifdef HAVE_SETREGID + {"setregid", posix_setregid, METH_VARARGS, posix_setregid__doc__}, +#endif /* HAVE_SETREGID */ +#ifdef HAVE_SETGID + {"setgid", posix_setgid, METH_VARARGS, posix_setgid__doc__}, +#endif /* HAVE_SETGID */ +#ifdef HAVE_SETGROUPS + {"setgroups", posix_setgroups, METH_O, posix_setgroups__doc__}, +#endif /* HAVE_SETGROUPS */ +#ifdef HAVE_GETPGID + {"getpgid", posix_getpgid, METH_VARARGS, posix_getpgid__doc__}, +#endif /* HAVE_GETPGID */ +#ifdef HAVE_SETPGRP + {"setpgrp", posix_setpgrp, METH_NOARGS, posix_setpgrp__doc__}, +#endif /* HAVE_SETPGRP */ +#ifdef HAVE_WAIT + {"wait", posix_wait, METH_NOARGS, posix_wait__doc__}, +#endif /* HAVE_WAIT */ +#ifdef HAVE_WAIT3 + {"wait3", posix_wait3, METH_VARARGS, posix_wait3__doc__}, +#endif /* HAVE_WAIT3 */ +#ifdef HAVE_WAIT4 + {"wait4", posix_wait4, METH_VARARGS, posix_wait4__doc__}, +#endif /* HAVE_WAIT4 */ +#if defined(HAVE_WAITPID) || defined(HAVE_CWAIT) + {"waitpid", posix_waitpid, METH_VARARGS, posix_waitpid__doc__}, +#endif /* HAVE_WAITPID */ +#ifdef HAVE_GETSID + {"getsid", posix_getsid, METH_VARARGS, posix_getsid__doc__}, +#endif /* HAVE_GETSID */ +#ifdef HAVE_SETSID + {"setsid", posix_setsid, METH_NOARGS, posix_setsid__doc__}, +#endif /* HAVE_SETSID */ +#ifdef HAVE_SETPGID + {"setpgid", posix_setpgid, METH_VARARGS, posix_setpgid__doc__}, +#endif /* HAVE_SETPGID */ +#ifdef HAVE_TCGETPGRP + {"tcgetpgrp", posix_tcgetpgrp, METH_VARARGS, posix_tcgetpgrp__doc__}, +#endif /* HAVE_TCGETPGRP */ +#ifdef HAVE_TCSETPGRP + {"tcsetpgrp", posix_tcsetpgrp, METH_VARARGS, posix_tcsetpgrp__doc__}, +#endif /* HAVE_TCSETPGRP */ + {"open", posix_open, METH_VARARGS, posix_open__doc__}, + {"close", posix_close, METH_VARARGS, posix_close__doc__}, + {"dup", posix_dup, METH_VARARGS, posix_dup__doc__}, + {"dup2", posix_dup2, METH_VARARGS, posix_dup2__doc__}, + {"lseek", posix_lseek, METH_VARARGS, posix_lseek__doc__}, + {"read", posix_read, METH_VARARGS, posix_read__doc__}, + {"write", posix_write, METH_VARARGS, posix_write__doc__}, + {"fstat", posix_fstat, METH_VARARGS, posix_fstat__doc__}, + {"fdopen", posix_fdopen, METH_VARARGS, posix_fdopen__doc__}, + {"isatty", posix_isatty, METH_VARARGS, posix_isatty__doc__}, +#ifdef HAVE_PIPE + {"pipe", posix_pipe, METH_NOARGS, posix_pipe__doc__}, +#endif +#ifdef HAVE_MKFIFO + {"mkfifo", posix_mkfifo, METH_VARARGS, posix_mkfifo__doc__}, +#endif +#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) + {"mknod", posix_mknod, METH_VARARGS, posix_mknod__doc__}, +#endif +#ifdef HAVE_DEVICE_MACROS + {"major", posix_major, METH_VARARGS, posix_major__doc__}, + {"minor", posix_minor, METH_VARARGS, posix_minor__doc__}, + {"makedev", posix_makedev, METH_VARARGS, posix_makedev__doc__}, +#endif +#ifdef HAVE_FTRUNCATE + {"ftruncate", posix_ftruncate, METH_VARARGS, posix_ftruncate__doc__}, +#endif +#ifdef HAVE_PUTENV + {"putenv", posix_putenv, METH_VARARGS, posix_putenv__doc__}, +#endif +#ifdef HAVE_UNSETENV + {"unsetenv", posix_unsetenv, METH_VARARGS, posix_unsetenv__doc__}, +#endif +#ifdef HAVE_STRERROR + {"strerror", posix_strerror, METH_VARARGS, posix_strerror__doc__}, +#endif +#ifdef HAVE_FCHDIR + {"fchdir", posix_fchdir, METH_O, posix_fchdir__doc__}, +#endif +#ifdef HAVE_FSYNC + {"fsync", posix_fsync, METH_O, posix_fsync__doc__}, +#endif +#ifdef HAVE_FDATASYNC + {"fdatasync", posix_fdatasync, METH_O, posix_fdatasync__doc__}, +#endif +#ifdef HAVE_SYS_WAIT_H +#ifdef WCOREDUMP + {"WCOREDUMP", posix_WCOREDUMP, METH_VARARGS, posix_WCOREDUMP__doc__}, +#endif /* WCOREDUMP */ +#ifdef WIFCONTINUED + {"WIFCONTINUED",posix_WIFCONTINUED, METH_VARARGS, posix_WIFCONTINUED__doc__}, +#endif /* WIFCONTINUED */ +#ifdef WIFSTOPPED + {"WIFSTOPPED", posix_WIFSTOPPED, METH_VARARGS, posix_WIFSTOPPED__doc__}, +#endif /* WIFSTOPPED */ +#ifdef WIFSIGNALED + {"WIFSIGNALED", posix_WIFSIGNALED, METH_VARARGS, posix_WIFSIGNALED__doc__}, +#endif /* WIFSIGNALED */ +#ifdef WIFEXITED + {"WIFEXITED", posix_WIFEXITED, METH_VARARGS, posix_WIFEXITED__doc__}, +#endif /* WIFEXITED */ +#ifdef WEXITSTATUS + {"WEXITSTATUS", posix_WEXITSTATUS, METH_VARARGS, posix_WEXITSTATUS__doc__}, +#endif /* WEXITSTATUS */ +#ifdef WTERMSIG + {"WTERMSIG", posix_WTERMSIG, METH_VARARGS, posix_WTERMSIG__doc__}, +#endif /* WTERMSIG */ +#ifdef WSTOPSIG + {"WSTOPSIG", posix_WSTOPSIG, METH_VARARGS, posix_WSTOPSIG__doc__}, +#endif /* WSTOPSIG */ +#endif /* HAVE_SYS_WAIT_H */ +#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) + {"fstatvfs", posix_fstatvfs, METH_VARARGS, posix_fstatvfs__doc__}, +#endif +#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) + {"statvfs", posix_statvfs, METH_VARARGS, posix_statvfs__doc__}, +#endif +#ifdef HAVE_TMPFILE + {"tmpfile", posix_tmpfile, METH_NOARGS, posix_tmpfile__doc__}, +#endif +#ifdef HAVE_TEMPNAM + {"tempnam", posix_tempnam, METH_VARARGS, posix_tempnam__doc__}, +#endif +#ifdef HAVE_TMPNAM + {"tmpnam", posix_tmpnam, METH_NOARGS, posix_tmpnam__doc__}, +#endif +#ifdef HAVE_CONFSTR + {"confstr", posix_confstr, METH_VARARGS, posix_confstr__doc__}, +#endif +#ifdef HAVE_SYSCONF + {"sysconf", posix_sysconf, METH_VARARGS, posix_sysconf__doc__}, +#endif +#ifdef HAVE_FPATHCONF + {"fpathconf", posix_fpathconf, METH_VARARGS, posix_fpathconf__doc__}, +#endif +#ifdef HAVE_PATHCONF + {"pathconf", posix_pathconf, METH_VARARGS, posix_pathconf__doc__}, +#endif + {"abort", posix_abort, METH_NOARGS, posix_abort__doc__}, +#ifdef MS_WINDOWS + {"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL}, +#endif +#ifdef HAVE_GETLOADAVG + {"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__}, +#endif + #ifdef MS_WINDOWS + {"urandom", win32_urandom, METH_VARARGS, win32_urandom__doc__}, + #endif + #ifdef __VMS + {"urandom", vms_urandom, METH_VARARGS, vms_urandom__doc__}, + #endif + {NULL, NULL} /* Sentinel */ +}; + + +static int +ins(PyObject *module, char *symbol, long value) +{ + return PyModule_AddIntConstant(module, symbol, value); +} + +#if defined(PYOS_OS2) +/* Insert Platform-Specific Constant Values (Strings & Numbers) of Common Use */ +static int insertvalues(PyObject *module) +{ + APIRET rc; + ULONG values[QSV_MAX+1]; + PyObject *v; + char *ver, tmp[50]; + + Py_BEGIN_ALLOW_THREADS + rc = DosQuerySysInfo(1L, QSV_MAX, &values[1], sizeof(ULONG) * QSV_MAX); + Py_END_ALLOW_THREADS + + if (rc != NO_ERROR) { + os2_error(rc); + return -1; + } + + if (ins(module, "meminstalled", values[QSV_TOTPHYSMEM])) return -1; + if (ins(module, "memkernel", values[QSV_TOTRESMEM])) return -1; + if (ins(module, "memvirtual", values[QSV_TOTAVAILMEM])) return -1; + if (ins(module, "maxpathlen", values[QSV_MAX_PATH_LENGTH])) return -1; + if (ins(module, "maxnamelen", values[QSV_MAX_COMP_LENGTH])) return -1; + if (ins(module, "revision", values[QSV_VERSION_REVISION])) return -1; + if (ins(module, "timeslice", values[QSV_MIN_SLICE])) return -1; + + switch (values[QSV_VERSION_MINOR]) { + case 0: ver = "2.00"; break; + case 10: ver = "2.10"; break; + case 11: ver = "2.11"; break; + case 30: ver = "3.00"; break; + case 40: ver = "4.00"; break; + case 50: ver = "5.00"; break; + default: + PyOS_snprintf(tmp, sizeof(tmp), + "%d-%d", values[QSV_VERSION_MAJOR], + values[QSV_VERSION_MINOR]); + ver = &tmp[0]; + } + + /* Add Indicator of the Version of the Operating System */ + if (PyModule_AddStringConstant(module, "version", tmp) < 0) + return -1; + + /* Add Indicator of Which Drive was Used to Boot the System */ + tmp[0] = 'A' + values[QSV_BOOT_DRIVE] - 1; + tmp[1] = ':'; + tmp[2] = '\0'; + + return PyModule_AddStringConstant(module, "bootdrive", tmp); +} +#endif + +static int +all_ins(PyObject *d) +{ +#ifdef F_OK + if (ins(d, "F_OK", (long)F_OK)) return -1; +#endif +#ifdef R_OK + if (ins(d, "R_OK", (long)R_OK)) return -1; +#endif +#ifdef W_OK + if (ins(d, "W_OK", (long)W_OK)) return -1; +#endif +#ifdef X_OK + if (ins(d, "X_OK", (long)X_OK)) return -1; +#endif +#ifdef NGROUPS_MAX + if (ins(d, "NGROUPS_MAX", (long)NGROUPS_MAX)) return -1; +#endif +#ifdef TMP_MAX + if (ins(d, "TMP_MAX", (long)TMP_MAX)) return -1; +#endif +#ifdef WCONTINUED + if (ins(d, "WCONTINUED", (long)WCONTINUED)) return -1; +#endif +#ifdef WNOHANG + if (ins(d, "WNOHANG", (long)WNOHANG)) return -1; +#endif +#ifdef WUNTRACED + if (ins(d, "WUNTRACED", (long)WUNTRACED)) return -1; +#endif +#ifdef O_RDONLY + if (ins(d, "O_RDONLY", (long)O_RDONLY)) return -1; +#endif +#ifdef O_WRONLY + if (ins(d, "O_WRONLY", (long)O_WRONLY)) return -1; +#endif +#ifdef O_RDWR + if (ins(d, "O_RDWR", (long)O_RDWR)) return -1; +#endif +#ifdef O_NDELAY + if (ins(d, "O_NDELAY", (long)O_NDELAY)) return -1; +#endif +#ifdef O_NONBLOCK + if (ins(d, "O_NONBLOCK", (long)O_NONBLOCK)) return -1; +#endif +#ifdef O_APPEND + if (ins(d, "O_APPEND", (long)O_APPEND)) return -1; +#endif +#ifdef O_DSYNC + if (ins(d, "O_DSYNC", (long)O_DSYNC)) return -1; +#endif +#ifdef O_RSYNC + if (ins(d, "O_RSYNC", (long)O_RSYNC)) return -1; +#endif +#ifdef O_SYNC + if (ins(d, "O_SYNC", (long)O_SYNC)) return -1; +#endif +#ifdef O_NOCTTY + if (ins(d, "O_NOCTTY", (long)O_NOCTTY)) return -1; +#endif +#ifdef O_CREAT + if (ins(d, "O_CREAT", (long)O_CREAT)) return -1; +#endif +#ifdef O_EXCL + if (ins(d, "O_EXCL", (long)O_EXCL)) return -1; +#endif +#ifdef O_TRUNC + if (ins(d, "O_TRUNC", (long)O_TRUNC)) return -1; +#endif +#ifdef O_BINARY + if (ins(d, "O_BINARY", (long)O_BINARY)) return -1; +#endif +#ifdef O_TEXT + if (ins(d, "O_TEXT", (long)O_TEXT)) return -1; +#endif +#ifdef O_LARGEFILE + if (ins(d, "O_LARGEFILE", (long)O_LARGEFILE)) return -1; +#endif +#ifdef O_SHLOCK + if (ins(d, "O_SHLOCK", (long)O_SHLOCK)) return -1; +#endif +#ifdef O_EXLOCK + if (ins(d, "O_EXLOCK", (long)O_EXLOCK)) return -1; +#endif + +/* MS Windows */ +#ifdef O_NOINHERIT + /* Don't inherit in child processes. */ + if (ins(d, "O_NOINHERIT", (long)O_NOINHERIT)) return -1; +#endif +#ifdef _O_SHORT_LIVED + /* Optimize for short life (keep in memory). */ + /* MS forgot to define this one with a non-underscore form too. */ + if (ins(d, "O_SHORT_LIVED", (long)_O_SHORT_LIVED)) return -1; +#endif +#ifdef O_TEMPORARY + /* Automatically delete when last handle is closed. */ + if (ins(d, "O_TEMPORARY", (long)O_TEMPORARY)) return -1; +#endif +#ifdef O_RANDOM + /* Optimize for random access. */ + if (ins(d, "O_RANDOM", (long)O_RANDOM)) return -1; +#endif +#ifdef O_SEQUENTIAL + /* Optimize for sequential access. */ + if (ins(d, "O_SEQUENTIAL", (long)O_SEQUENTIAL)) return -1; +#endif + +/* GNU extensions. */ +#ifdef O_DIRECT + /* Direct disk access. */ + if (ins(d, "O_DIRECT", (long)O_DIRECT)) return -1; +#endif +#ifdef O_DIRECTORY + /* Must be a directory. */ + if (ins(d, "O_DIRECTORY", (long)O_DIRECTORY)) return -1; +#endif +#ifdef O_NOFOLLOW + /* Do not follow links. */ + if (ins(d, "O_NOFOLLOW", (long)O_NOFOLLOW)) return -1; +#endif + + /* These come from sysexits.h */ +#ifdef EX_OK + if (ins(d, "EX_OK", (long)EX_OK)) return -1; +#endif /* EX_OK */ +#ifdef EX_USAGE + if (ins(d, "EX_USAGE", (long)EX_USAGE)) return -1; +#endif /* EX_USAGE */ +#ifdef EX_DATAERR + if (ins(d, "EX_DATAERR", (long)EX_DATAERR)) return -1; +#endif /* EX_DATAERR */ +#ifdef EX_NOINPUT + if (ins(d, "EX_NOINPUT", (long)EX_NOINPUT)) return -1; +#endif /* EX_NOINPUT */ +#ifdef EX_NOUSER + if (ins(d, "EX_NOUSER", (long)EX_NOUSER)) return -1; +#endif /* EX_NOUSER */ +#ifdef EX_NOHOST + if (ins(d, "EX_NOHOST", (long)EX_NOHOST)) return -1; +#endif /* EX_NOHOST */ +#ifdef EX_UNAVAILABLE + if (ins(d, "EX_UNAVAILABLE", (long)EX_UNAVAILABLE)) return -1; +#endif /* EX_UNAVAILABLE */ +#ifdef EX_SOFTWARE + if (ins(d, "EX_SOFTWARE", (long)EX_SOFTWARE)) return -1; +#endif /* EX_SOFTWARE */ +#ifdef EX_OSERR + if (ins(d, "EX_OSERR", (long)EX_OSERR)) return -1; +#endif /* EX_OSERR */ +#ifdef EX_OSFILE + if (ins(d, "EX_OSFILE", (long)EX_OSFILE)) return -1; +#endif /* EX_OSFILE */ +#ifdef EX_CANTCREAT + if (ins(d, "EX_CANTCREAT", (long)EX_CANTCREAT)) return -1; +#endif /* EX_CANTCREAT */ +#ifdef EX_IOERR + if (ins(d, "EX_IOERR", (long)EX_IOERR)) return -1; +#endif /* EX_IOERR */ +#ifdef EX_TEMPFAIL + if (ins(d, "EX_TEMPFAIL", (long)EX_TEMPFAIL)) return -1; +#endif /* EX_TEMPFAIL */ +#ifdef EX_PROTOCOL + if (ins(d, "EX_PROTOCOL", (long)EX_PROTOCOL)) return -1; +#endif /* EX_PROTOCOL */ +#ifdef EX_NOPERM + if (ins(d, "EX_NOPERM", (long)EX_NOPERM)) return -1; +#endif /* EX_NOPERM */ +#ifdef EX_CONFIG + if (ins(d, "EX_CONFIG", (long)EX_CONFIG)) return -1; +#endif /* EX_CONFIG */ +#ifdef EX_NOTFOUND + if (ins(d, "EX_NOTFOUND", (long)EX_NOTFOUND)) return -1; +#endif /* EX_NOTFOUND */ + +#ifdef HAVE_SPAWNV +#if defined(PYOS_OS2) && defined(PYCC_GCC) + if (ins(d, "P_WAIT", (long)P_WAIT)) return -1; + if (ins(d, "P_NOWAIT", (long)P_NOWAIT)) return -1; + if (ins(d, "P_OVERLAY", (long)P_OVERLAY)) return -1; + if (ins(d, "P_DEBUG", (long)P_DEBUG)) return -1; + if (ins(d, "P_SESSION", (long)P_SESSION)) return -1; + if (ins(d, "P_DETACH", (long)P_DETACH)) return -1; + if (ins(d, "P_PM", (long)P_PM)) return -1; + if (ins(d, "P_DEFAULT", (long)P_DEFAULT)) return -1; + if (ins(d, "P_MINIMIZE", (long)P_MINIMIZE)) return -1; + if (ins(d, "P_MAXIMIZE", (long)P_MAXIMIZE)) return -1; + if (ins(d, "P_FULLSCREEN", (long)P_FULLSCREEN)) return -1; + if (ins(d, "P_WINDOWED", (long)P_WINDOWED)) return -1; + if (ins(d, "P_FOREGROUND", (long)P_FOREGROUND)) return -1; + if (ins(d, "P_BACKGROUND", (long)P_BACKGROUND)) return -1; + if (ins(d, "P_NOCLOSE", (long)P_NOCLOSE)) return -1; + if (ins(d, "P_NOSESSION", (long)P_NOSESSION)) return -1; + if (ins(d, "P_QUOTE", (long)P_QUOTE)) return -1; + if (ins(d, "P_TILDE", (long)P_TILDE)) return -1; + if (ins(d, "P_UNRELATED", (long)P_UNRELATED)) return -1; + if (ins(d, "P_DEBUGDESC", (long)P_DEBUGDESC)) return -1; +#else + if (ins(d, "P_WAIT", (long)_P_WAIT)) return -1; + if (ins(d, "P_NOWAIT", (long)_P_NOWAIT)) return -1; + if (ins(d, "P_OVERLAY", (long)_OLD_P_OVERLAY)) return -1; + if (ins(d, "P_NOWAITO", (long)_P_NOWAITO)) return -1; + if (ins(d, "P_DETACH", (long)_P_DETACH)) return -1; +#endif +#endif + +#if defined(PYOS_OS2) + if (insertvalues(d)) return -1; +#endif + return 0; +} + + +#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__)) && !defined(__QNX__) +#define INITFUNC initnt +#define MODNAME "nt" + +#elif defined(PYOS_OS2) +#define INITFUNC initos2 +#define MODNAME "os2" + +#else +#define INITFUNC initposix +#define MODNAME "posix" +#endif + +PyMODINIT_FUNC +INITFUNC(void) +{ + PyObject *m, *v; + + m = Py_InitModule3(MODNAME, + posix_methods, + posix__doc__); + if (m == NULL) + return; + + /* Initialize environ dictionary */ + v = convertenviron(); + Py_XINCREF(v); + if (v == NULL || PyModule_AddObject(m, "environ", v) != 0) + return; + Py_DECREF(v); + + if (all_ins(m)) + return; + + if (setup_confname_tables(m)) + return; + + Py_INCREF(PyExc_OSError); + PyModule_AddObject(m, "error", PyExc_OSError); + +#ifdef HAVE_PUTENV + if (posix_putenv_garbage == NULL) + posix_putenv_garbage = PyDict_New(); +#endif + + if (!initialized) { + stat_result_desc.name = MODNAME ".stat_result"; + stat_result_desc.fields[7].name = PyStructSequence_UnnamedField; + stat_result_desc.fields[8].name = PyStructSequence_UnnamedField; + stat_result_desc.fields[9].name = PyStructSequence_UnnamedField; + PyStructSequence_InitType(&StatResultType, &stat_result_desc); + structseq_new = StatResultType.tp_new; + StatResultType.tp_new = statresult_new; + + statvfs_result_desc.name = MODNAME ".statvfs_result"; + PyStructSequence_InitType(&StatVFSResultType, &statvfs_result_desc); + } + Py_INCREF((PyObject*) &StatResultType); + PyModule_AddObject(m, "stat_result", (PyObject*) &StatResultType); + Py_INCREF((PyObject*) &StatVFSResultType); + PyModule_AddObject(m, "statvfs_result", + (PyObject*) &StatVFSResultType); + initialized = 1; + +#ifdef __APPLE__ + /* + * Step 2 of weak-linking support on Mac OS X. + * + * The code below removes functions that are not available on the + * currently active platform. + * + * This block allow one to use a python binary that was build on + * OSX 10.4 on OSX 10.3, without loosing access to new APIs on + * OSX 10.4. + */ +#ifdef HAVE_FSTATVFS + if (fstatvfs == NULL) { + if (PyObject_DelAttrString(m, "fstatvfs") == -1) { + return; + } + } +#endif /* HAVE_FSTATVFS */ + +#ifdef HAVE_STATVFS + if (statvfs == NULL) { + if (PyObject_DelAttrString(m, "statvfs") == -1) { + return; + } + } +#endif /* HAVE_STATVFS */ + +# ifdef HAVE_LCHOWN + if (lchown == NULL) { + if (PyObject_DelAttrString(m, "lchown") == -1) { + return; + } + } +#endif /* HAVE_LCHOWN */ + + +#endif /* __APPLE__ */ + +} + +#ifdef __cplusplus +} +#endif + + diff --git a/sys/src/cmd/python/Modules/puremodule.c b/sys/src/cmd/python/Modules/puremodule.c new file mode 100644 index 000000000..95f4bdecd --- /dev/null +++ b/sys/src/cmd/python/Modules/puremodule.c @@ -0,0 +1,988 @@ +/* This module exports the C API to such Pure Software Inc. (tm) (now + * called Pure Atria Corporation) products as Purify (tm) and Quantify + * (tm). Other packages could be added, but I didn't have those products + * and thus lack the API documentation. + * + * Currently supported: Quantify 2.x, Purify 3.x + * + * You need to decide which products you want to incorporate into the + * module when you compile this file. The way to do this is to edit + * <Python>/Modules/Setup to pass the appropriate flags to the compiler. + * -DWITH_PURIFY compiles in the Purify support, and -DWITH_QUANTIFY + * compiles in the Quantify support. -DWITH_ALL_PURE compiles in both. + * You can also build a Purify'd or Quantify'd interpreter by passing in + * the LINKCC variable to make. E.g. if you want to build a Purify'd + * interpreter and are using gcc, build Python with this command: + * + * make LINKCC='purify gcc' + * + * It would be nice (and probably easy) to provide this file as a shared + * library, however since it doesn't appear that Pure gives us shared + * libraries of the stubs, it doesn't really matter. For now, you have to + * link this file in statically. + * + * Major bogosity. The purify.h header file exports purify_exit(), but + * guess what? It is not defined in the libpurify_stubs.a file! I tried + * to fake one here, hoping the Pure linker would Do The Right Thing when + * instrumented for Purify, but it doesn't seem to, so I don't export + * purify_exit() to the Python layer. In Python you should raise a + * SystemExit exception anyway. + * + * The actual purify.h and quantify.h files which embody the APIs are + * copyrighted by Pure Software, Inc. and are only attainable through them. + * This module assumes you have legally installed licenses of their + * software. Contact them on the Web via <http://www.pureatria.com/> + * + * Author: Barry Warsaw <bwarsaw@python.org> + * <bwarsaw@cnri.reston.va.us> + */ + +#include "Python.h" + +#if defined(WITH_PURIFY) || defined(WITH_ALL_PURE) +# include <purify.h> +# define HAS_PURIFY_EXIT 0 /* See note at top of file */ +# define PURE_PURIFY_VERSION 3 /* not provided by purify.h */ +#endif +#if defined(WITH_QUANTIFY) || defined(WITH_ALL_PURE) +# include <quantify.h> +# define PURE_QUANTIFY_VERSION 2 /* not provided by quantify.h */ +#endif +#if defined(PURIFY_H) || defined(QUANTIFY_H) +# define COMMON_PURE_FUNCTIONS +#endif /* PURIFY_H || QUANTIFY_H */ + +typedef int (*VoidArgFunc)(void); +typedef int (*StringArgFunc)(char*); +typedef int (*PrintfishFunc)(const char*, ...); +typedef int (*StringIntArgFunc)(const char*, int); + + + +static PyObject* +call_voidarg_function(VoidArgFunc func, PyObject *self, PyObject *args) +{ + int status; + + if (!PyArg_ParseTuple(args, "")) + return NULL; + + status = func(); + return Py_BuildValue("i", status); +} + +static PyObject* +call_stringarg_function(StringArgFunc func, PyObject *self, PyObject *args) +{ + int status; + char* stringarg; + + if (!PyArg_ParseTuple(args, "s", &stringarg)) + return NULL; + + status = func(stringarg); + return Py_BuildValue("i", status); +} + +static PyObject* +call_stringorint_function(StringArgFunc func, PyObject *self, PyObject *args) +{ + int status; + int intarg; + char* stringarg; + + /* according to the quantify.h file, the argument to + * quantify_*_recording_system_call can be an integer or a string, + * but the functions are prototyped as taking a single char* + * argument. Yikes! + */ + if (PyArg_ParseTuple(args, "i", &intarg)) + /* func is prototyped as int(*)(char*) + * better shut up the compiler + */ + status = func((char*)intarg); + + else { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "s", &stringarg)) + return NULL; + else + status = func(stringarg); + } + return Py_BuildValue("i", status); +} + +static PyObject* +call_printfish_function(PrintfishFunc func, PyObject *self, PyObject *args) +{ + /* we support the printf() style vararg functions by requiring the + * formatting be done in Python. At the C level we pass just a string + * to the printf() style function. + */ + int status; + char* argstring; + + if (!PyArg_ParseTuple(args, "s", &argstring)) + return NULL; + + status = func("%s", argstring); + return Py_BuildValue("i", status); +} + +static PyObject* +call_intasaddr_function(StringArgFunc func, PyObject *self, PyObject *args) +{ + long memrep; + int id; + + if (!PyArg_ParseTuple(args, "l", &memrep)) + return NULL; + + id = func((char*)memrep); + return Py_BuildValue("i", id); +} + +static PyObject* +call_stringandint_function(StringIntArgFunc func, PyObject *self, + PyObject *args) +{ + long srcrep; + int size; + int status; + + if (!PyArg_ParseTuple(args, "li", &srcrep, &size)) + return NULL; + + status = func((char*)srcrep, size); + return Py_BuildValue("i", status); +} + + + +/* functions common to all products + * + * N.B. These printf() style functions are a bit of a kludge. Since the + * API doesn't provide vprintf versions of them, we can't call them + * directly. They don't support all the standard printf % modifiers + * anyway. The way to use these is to use Python's % string operator to do + * the formatting. By the time these functions get the thing to print, + * it's already a string, and they just use "%s" as the format string. + */ + +#ifdef COMMON_PURE_FUNCTIONS + +static PyObject* +pure_pure_logfile_printf(PyObject* self, PyObject* args) +{ + return call_printfish_function(pure_logfile_printf, self, args); +} + +static PyObject* +pure_pure_printf(PyObject* self, PyObject* args) +{ + return call_printfish_function(pure_printf, self, args); +} + +static PyObject* +pure_pure_printf_with_banner(PyObject* self, PyObject* args) +{ + return call_printfish_function(pure_printf_with_banner, self, args); +} + + +#endif /* COMMON_PURE_FUNCTIONS */ + + + +/* Purify functions + * + * N.B. There are some interfaces described in the purify.h file that are + * not described in the manual. + * + * Unsigned longs purify_report_{address,number,type,result} are not + * accessible from the Python layer since they seem mostly useful when + * purify_stop_here() is called by the (C) debugger. The same is true of + * the purify_stop_here_internal() function so it isn't exported either. + * And purify_stop_here() should never be called directly. + * + * The header file says purify_{new,all,clear_new}_reports() are obsolete + * so they aren't exported. + * + * None of the custom dynamic loader functions are exported. + * + * purify_unsafe_memcpy() isn't exported. + * + * purify_{start,size}_of_block() aren't exported. + * + * The manual that I have says that the prototype for the second argument + * to purify_map_pool is: + * + * void (*fn)(char*) + * + * but the purify.h file declares it as: + * + * void (*fn)(char*, int, void*) + * + * and does not explain what the other arguments are for. I support the + * latter but I don't know if I do it right or usefully. + * + * The header file says that purify_describe() returns a char* which is the + * pointer passed to it. The manual says it returns an int, but I believe + * that is a typo. + */ +#ifdef PURIFY_H + +static PyObject* +pure_purify_all_inuse(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_all_inuse, self, args); +} +static PyObject* +pure_purify_all_leaks(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_all_leaks, self, args); +} +static PyObject* +pure_purify_new_inuse(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_new_inuse, self, args); +} +static PyObject* +pure_purify_new_leaks(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_new_leaks, self, args); +} +static PyObject* +pure_purify_clear_inuse(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_clear_inuse, self, args); +} +static PyObject* +pure_purify_clear_leaks(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_clear_leaks, self, args); +} +static PyObject* +pure_purify_all_fds_inuse(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_all_fds_inuse, self, args); +} +static PyObject* +pure_purify_new_fds_inuse(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_new_fds_inuse, self, args); +} +static PyObject* +pure_purify_printf_with_call_chain(PyObject *self, PyObject *args) +{ + return call_printfish_function(purify_printf_with_call_chain, + self, args); +} +static PyObject* +pure_purify_set_pool_id(PyObject *self, PyObject *args) +{ + long memrep; + int id; + + if (!PyArg_ParseTuple(args, "li:purify_set_pool_id", &memrep, &id)) + return NULL; + + purify_set_pool_id((char*)memrep, id); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject* +pure_purify_get_pool_id(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_get_pool_id, self, args); +} +static PyObject* +pure_purify_set_user_data(PyObject *self, PyObject *args) +{ + long memrep; + long datarep; + + if (!PyArg_ParseTuple(args, "ll:purify_set_user_data", &memrep, &datarep)) + return NULL; + + purify_set_user_data((char*)memrep, (void*)datarep); + Py_INCREF(Py_None); + return Py_None; +} +static PyObject* +pure_purify_get_user_data(PyObject *self, PyObject *args) +{ + /* can't use call_intasaddr_function() since purify_get_user_data() + * returns a void* + */ + long memrep; + void* data; + + if (!PyArg_ParseTuple(args, "l:purify_get_user_data", &memrep)) + return NULL; + + data = purify_get_user_data((char*)memrep); + return Py_BuildValue("l", (long)data); +} + + +/* this global variable is shared by both mapping functions: + * pure_purify_map_pool() and pure_purify_map_pool_id(). Since they cache + * this variable it should be safe in the face of recursion or cross + * calling. + * + * Further note that the prototype for the callback function is wrong in + * the Purify manual. The manual says the function takes a single char*, + * but the header file says it takes an additional int and void*. I have + * no idea what these are for! + */ +static PyObject* MapCallable = NULL; + +static void +map_pool_callback(char* mem, int user_size, void *user_aux_data) +{ + long memrep = (long)mem; + long user_aux_data_rep = (long)user_aux_data; + PyObject* result; + PyObject* memobj = Py_BuildValue("lil", memrep, user_size, + user_aux_data_rep); + + if (memobj == NULL) + return; + + result = PyEval_CallObject(MapCallable, memobj); + Py_DECREF(result); + Py_DECREF(memobj); +} + +static PyObject* +pure_purify_map_pool(PyObject *self, PyObject *args) +{ + /* cache global variable in case of recursion */ + PyObject* saved_callable = MapCallable; + PyObject* arg_callable; + int id; + + if (!PyArg_ParseTuple(args, "iO:purify_map_pool", &id, &arg_callable)) + return NULL; + + if (!PyCallable_Check(arg_callable)) { + PyErr_SetString(PyExc_TypeError, + "Second argument must be callable"); + return NULL; + } + MapCallable = arg_callable; + purify_map_pool(id, map_pool_callback); + MapCallable = saved_callable; + + Py_INCREF(Py_None); + return Py_None; +} + +static void +PurifyMapPoolIdCallback(int id) +{ + PyObject* result; + PyObject* intobj = Py_BuildValue("i", id); + + if (intobj == NULL) + return; + + result = PyEval_CallObject(MapCallable, intobj); + Py_DECREF(result); + Py_DECREF(intobj); +} + +static PyObject* +pure_purify_map_pool_id(PyObject *self, PyObject *args) +{ + /* cache global variable in case of recursion */ + PyObject* saved_callable = MapCallable; + PyObject* arg_callable; + + if (!PyArg_ParseTuple(args, "O:purify_map_pool_id", &arg_callable)) + return NULL; + + if (!PyCallable_Check(arg_callable)) { + PyErr_SetString(PyExc_TypeError, "Argument must be callable."); + return NULL; + } + + MapCallable = arg_callable; + purify_map_pool_id(PurifyMapPoolIdCallback); + MapCallable = saved_callable; + + Py_INCREF(Py_None); + return Py_None; +} + + + +static PyObject* +pure_purify_new_messages(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_new_messages, self, args); +} +static PyObject* +pure_purify_all_messages(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_all_messages, self, args); +} +static PyObject* +pure_purify_clear_messages(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_clear_messages, self, args); +} +static PyObject* +pure_purify_clear_new_messages(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_clear_new_messages, self, args); +} +static PyObject* +pure_purify_start_batch(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_start_batch, self, args); +} +static PyObject* +pure_purify_start_batch_show_first(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_start_batch_show_first, + self, args); +} +static PyObject* +pure_purify_stop_batch(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_stop_batch, self, args); +} +static PyObject* +pure_purify_name_thread(PyObject *self, PyObject *args) +{ + /* can't strictly use call_stringarg_function since + * purify_name_thread takes a const char*, not a char* + */ + int status; + char* stringarg; + + if (!PyArg_ParseTuple(args, "s:purify_name_thread", &stringarg)) + return NULL; + + status = purify_name_thread(stringarg); + return Py_BuildValue("i", status); +} +static PyObject* +pure_purify_watch(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch, self, args); +} +static PyObject* +pure_purify_watch_1(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_1, self, args); +} +static PyObject* +pure_purify_watch_2(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_2, self, args); +} +static PyObject* +pure_purify_watch_4(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_4, self, args); +} +static PyObject* +pure_purify_watch_8(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_8, self, args); +} +static PyObject* +pure_purify_watch_w_1(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_w_1, self, args); +} +static PyObject* +pure_purify_watch_w_2(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_w_2, self, args); +} +static PyObject* +pure_purify_watch_w_4(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_w_4, self, args); +} +static PyObject* +pure_purify_watch_w_8(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_w_8, self, args); +} +static PyObject* +pure_purify_watch_r_1(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_r_1, self, args); +} +static PyObject* +pure_purify_watch_r_2(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_r_2, self, args); +} +static PyObject* +pure_purify_watch_r_4(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_r_4, self, args); +} +static PyObject* +pure_purify_watch_r_8(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_r_8, self, args); +} +static PyObject* +pure_purify_watch_rw_1(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_rw_1, self, args); +} +static PyObject* +pure_purify_watch_rw_2(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_rw_2, self, args); +} +static PyObject* +pure_purify_watch_rw_4(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_rw_4, self, args); +} +static PyObject* +pure_purify_watch_rw_8(PyObject *self, PyObject *args) +{ + return call_intasaddr_function(purify_watch_rw_8, self, args); +} + +static PyObject* +pure_purify_watch_n(PyObject *self, PyObject *args) +{ + long addrrep; + unsigned int size; + char* type; + int status; + + if (!PyArg_ParseTuple(args, "lis:purify_watch_n", &addrrep, &size, &type)) + return NULL; + + status = purify_watch_n((char*)addrrep, size, type); + return Py_BuildValue("i", status); +} + +static PyObject* +pure_purify_watch_info(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_watch_info, self, args); +} + +static PyObject* +pure_purify_watch_remove(PyObject *self, PyObject *args) +{ + int watchno; + int status; + + if (!PyArg_ParseTuple(args, "i:purify_watch_remove", &watchno)) + return NULL; + + status = purify_watch_remove(watchno); + return Py_BuildValue("i", status); +} + +static PyObject* +pure_purify_watch_remove_all(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_watch_remove_all, self, args); +} +static PyObject* +pure_purify_describe(PyObject *self, PyObject *args) +{ + long addrrep; + char* rtn; + + if (!PyArg_ParseTuple(args, "l:purify_describe", &addrrep)) + return NULL; + + rtn = purify_describe((char*)addrrep); + return Py_BuildValue("l", (long)rtn); +} + +static PyObject* +pure_purify_what_colors(PyObject *self, PyObject *args) +{ + long addrrep; + unsigned int size; + int status; + + if (!PyArg_ParseTuple(args, "li:purify_what_colors", &addrrep, &size)) + return NULL; + + status = purify_what_colors((char*)addrrep, size); + return Py_BuildValue("i", status); +} + +static PyObject* +pure_purify_is_running(PyObject *self, PyObject *args) +{ + return call_voidarg_function(purify_is_running, self, args); +} + +static PyObject* +pure_purify_assert_is_readable(PyObject *self, PyObject *args) +{ + return call_stringandint_function(purify_assert_is_readable, + self, args); +} +static PyObject* +pure_purify_assert_is_writable(PyObject *self, PyObject *args) +{ + return call_stringandint_function(purify_assert_is_writable, + self, args); +} + +#if HAS_PURIFY_EXIT + +/* I wish I could include this, but I can't. See the notes at the top of + * the file. + */ + +static PyObject* +pure_purify_exit(PyObject *self, PyObject *args) +{ + int status; + + if (!PyArg_ParseTuple(args, "i:purify_exit", &status)) + return NULL; + + /* purify_exit doesn't always act like exit(). See the manual */ + purify_exit(status); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* HAS_PURIFY_EXIT */ + +#endif /* PURIFY_H */ + + + +/* Quantify functions + * + * N.B. Some of these functions are only described in the quantify.h file, + * not in the version of the hardcopy manual that I had. If you're not + * sure what some of these do, check the header file, it is documented + * fairly well. + * + * None of the custom dynamic loader functions are exported. + * + */ +#ifdef QUANTIFY_H + +static PyObject* +pure_quantify_is_running(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_is_running, self, args); +} +static PyObject* +pure_quantify_help(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_help, self, args); +} +static PyObject* +pure_quantify_print_recording_state(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_print_recording_state, + self, args); +} +static PyObject* +pure_quantify_start_recording_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_start_recording_data, + self, args); +} +static PyObject* +pure_quantify_stop_recording_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_stop_recording_data, self, args); +} +static PyObject* +pure_quantify_is_recording_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_is_recording_data, self, args); +} +static PyObject* +pure_quantify_start_recording_system_calls(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_start_recording_system_calls, + self, args); +} +static PyObject* +pure_quantify_stop_recording_system_calls(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_stop_recording_system_calls, + self, args); +} +static PyObject* +pure_quantify_is_recording_system_calls(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_is_recording_system_calls, + self, args); +} +static PyObject* +pure_quantify_start_recording_system_call(PyObject *self, PyObject *args) +{ + return call_stringorint_function(quantify_start_recording_system_call, + self, args); +} +static PyObject* +pure_quantify_stop_recording_system_call(PyObject *self, PyObject *args) +{ + return call_stringorint_function(quantify_stop_recording_system_call, + self, args); +} +static PyObject* +pure_quantify_is_recording_system_call(PyObject *self, PyObject *args) +{ + return call_stringorint_function(quantify_is_recording_system_call, + self, args); +} +static PyObject* +pure_quantify_start_recording_dynamic_library_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function( + quantify_start_recording_dynamic_library_data, + self, args); +} +static PyObject* +pure_quantify_stop_recording_dynamic_library_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function( + quantify_stop_recording_dynamic_library_data, + self, args); +} +static PyObject* +pure_quantify_is_recording_dynamic_library_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function( + quantify_is_recording_dynamic_library_data, + self, args); +} +static PyObject* +pure_quantify_start_recording_register_window_traps(PyObject *self, PyObject *args) +{ + return call_voidarg_function( + quantify_start_recording_register_window_traps, + self, args); +} +static PyObject* +pure_quantify_stop_recording_register_window_traps(PyObject *self, PyObject *args) +{ + return call_voidarg_function( + quantify_stop_recording_register_window_traps, + self, args); +} +static PyObject* +pure_quantify_is_recording_register_window_traps(PyObject *self, PyObject *args) +{ + return call_voidarg_function( + quantify_is_recording_register_window_traps, + self, args); +} +static PyObject* +pure_quantify_disable_recording_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_disable_recording_data, + self, args); +} +static PyObject* +pure_quantify_clear_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_clear_data, self, args); +} +static PyObject* +pure_quantify_save_data(PyObject *self, PyObject *args) +{ + return call_voidarg_function(quantify_save_data, self, args); +} +static PyObject* +pure_quantify_save_data_to_file(PyObject *self, PyObject *args) +{ + return call_stringarg_function(quantify_save_data_to_file, self, args); +} +static PyObject* +pure_quantify_add_annotation(PyObject *self, PyObject *args) +{ + return call_stringarg_function(quantify_add_annotation, self, args); +} + +#endif /* QUANTIFY_H */ + + + +/* external interface + */ +static struct PyMethodDef +pure_methods[] = { +#ifdef COMMON_PURE_FUNCTIONS + {"pure_logfile_printf", pure_pure_logfile_printf, METH_VARARGS}, + {"pure_printf", pure_pure_printf, METH_VARARGS}, + {"pure_printf_with_banner", pure_pure_printf_with_banner, METH_VARARGS}, +#endif /* COMMON_PURE_FUNCTIONS */ +#ifdef PURIFY_H + {"purify_all_inuse", pure_purify_all_inuse, METH_VARARGS}, + {"purify_all_leaks", pure_purify_all_leaks, METH_VARARGS}, + {"purify_new_inuse", pure_purify_new_inuse, METH_VARARGS}, + {"purify_new_leaks", pure_purify_new_leaks, METH_VARARGS}, + {"purify_clear_inuse", pure_purify_clear_inuse, METH_VARARGS}, + {"purify_clear_leaks", pure_purify_clear_leaks, METH_VARARGS}, + {"purify_all_fds_inuse", pure_purify_all_fds_inuse, METH_VARARGS}, + {"purify_new_fds_inuse", pure_purify_new_fds_inuse, METH_VARARGS}, + /* see purify.h */ + {"purify_logfile_printf", pure_pure_logfile_printf, METH_VARARGS}, + {"purify_printf", pure_pure_printf, METH_VARARGS}, + {"purify_printf_with_banner", pure_pure_printf_with_banner, METH_VARARGS}, + /**/ + {"purify_printf_with_call_chain", pure_purify_printf_with_call_chain, METH_VARARGS}, + {"purify_set_pool_id", pure_purify_set_pool_id, METH_VARARGS}, + {"purify_get_pool_id", pure_purify_get_pool_id, METH_VARARGS}, + {"purify_set_user_data", pure_purify_set_user_data, METH_VARARGS}, + {"purify_get_user_data", pure_purify_get_user_data, METH_VARARGS}, + {"purify_map_pool", pure_purify_map_pool, METH_VARARGS}, + {"purify_map_pool_id", pure_purify_map_pool_id, METH_VARARGS}, + {"purify_new_messages", pure_purify_new_messages, METH_VARARGS}, + {"purify_all_messages", pure_purify_all_messages, METH_VARARGS}, + {"purify_clear_messages", pure_purify_clear_messages, METH_VARARGS}, + {"purify_clear_new_messages", pure_purify_clear_new_messages, METH_VARARGS}, + {"purify_start_batch", pure_purify_start_batch, METH_VARARGS}, + {"purify_start_batch_show_first", pure_purify_start_batch_show_first, METH_VARARGS}, + {"purify_stop_batch", pure_purify_stop_batch, METH_VARARGS}, + {"purify_name_thread", pure_purify_name_thread, METH_VARARGS}, + {"purify_watch", pure_purify_watch, METH_VARARGS}, + {"purify_watch_1", pure_purify_watch_1, METH_VARARGS}, + {"purify_watch_2", pure_purify_watch_2, METH_VARARGS}, + {"purify_watch_4", pure_purify_watch_4, METH_VARARGS}, + {"purify_watch_8", pure_purify_watch_8, METH_VARARGS}, + {"purify_watch_w_1", pure_purify_watch_w_1, METH_VARARGS}, + {"purify_watch_w_2", pure_purify_watch_w_2, METH_VARARGS}, + {"purify_watch_w_4", pure_purify_watch_w_4, METH_VARARGS}, + {"purify_watch_w_8", pure_purify_watch_w_8, METH_VARARGS}, + {"purify_watch_r_1", pure_purify_watch_r_1, METH_VARARGS}, + {"purify_watch_r_2", pure_purify_watch_r_2, METH_VARARGS}, + {"purify_watch_r_4", pure_purify_watch_r_4, METH_VARARGS}, + {"purify_watch_r_8", pure_purify_watch_r_8, METH_VARARGS}, + {"purify_watch_rw_1", pure_purify_watch_rw_1, METH_VARARGS}, + {"purify_watch_rw_2", pure_purify_watch_rw_2, METH_VARARGS}, + {"purify_watch_rw_4", pure_purify_watch_rw_4, METH_VARARGS}, + {"purify_watch_rw_8", pure_purify_watch_rw_8, METH_VARARGS}, + {"purify_watch_n", pure_purify_watch_n, METH_VARARGS}, + {"purify_watch_info", pure_purify_watch_info, METH_VARARGS}, + {"purify_watch_remove", pure_purify_watch_remove, METH_VARARGS}, + {"purify_watch_remove_all", pure_purify_watch_remove_all, METH_VARARGS}, + {"purify_describe", pure_purify_describe, METH_VARARGS}, + {"purify_what_colors", pure_purify_what_colors, METH_VARARGS}, + {"purify_is_running", pure_purify_is_running, METH_VARARGS}, + {"purify_assert_is_readable", pure_purify_assert_is_readable, METH_VARARGS}, + {"purify_assert_is_writable", pure_purify_assert_is_writable, METH_VARARGS}, +#if HAS_PURIFY_EXIT + /* I wish I could include this, but I can't. See the notes at the + * top of the file. + */ + {"purify_exit", pure_purify_exit, METH_VARARGS}, +#endif /* HAS_PURIFY_EXIT */ +#endif /* PURIFY_H */ +#ifdef QUANTIFY_H + {"quantify_is_running", pure_quantify_is_running, METH_VARARGS}, + {"quantify_help", pure_quantify_help, METH_VARARGS}, + {"quantify_print_recording_state", pure_quantify_print_recording_state, METH_VARARGS}, + {"quantify_start_recording_data", pure_quantify_start_recording_data, METH_VARARGS}, + {"quantify_stop_recording_data", pure_quantify_stop_recording_data, METH_VARARGS}, + {"quantify_is_recording_data", pure_quantify_is_recording_data, METH_VARARGS}, + {"quantify_start_recording_system_calls", + pure_quantify_start_recording_system_calls, METH_VARARGS}, + {"quantify_stop_recording_system_calls", + pure_quantify_stop_recording_system_calls, METH_VARARGS}, + {"quantify_is_recording_system_calls", + pure_quantify_is_recording_system_calls, METH_VARARGS}, + {"quantify_start_recording_system_call", + pure_quantify_start_recording_system_call, METH_VARARGS}, + {"quantify_stop_recording_system_call", + pure_quantify_stop_recording_system_call, METH_VARARGS}, + {"quantify_is_recording_system_call", + pure_quantify_is_recording_system_call, METH_VARARGS}, + {"quantify_start_recording_dynamic_library_data", + pure_quantify_start_recording_dynamic_library_data, METH_VARARGS}, + {"quantify_stop_recording_dynamic_library_data", + pure_quantify_stop_recording_dynamic_library_data, METH_VARARGS}, + {"quantify_is_recording_dynamic_library_data", + pure_quantify_is_recording_dynamic_library_data, METH_VARARGS}, + {"quantify_start_recording_register_window_traps", + pure_quantify_start_recording_register_window_traps, METH_VARARGS}, + {"quantify_stop_recording_register_window_traps", + pure_quantify_stop_recording_register_window_traps, METH_VARARGS}, + {"quantify_is_recording_register_window_traps", + pure_quantify_is_recording_register_window_traps, METH_VARARGS}, + {"quantify_disable_recording_data", + pure_quantify_disable_recording_data, METH_VARARGS}, + {"quantify_clear_data", pure_quantify_clear_data, METH_VARARGS}, + {"quantify_save_data", pure_quantify_save_data, METH_VARARGS}, + {"quantify_save_data_to_file", pure_quantify_save_data_to_file, METH_VARARGS}, + {"quantify_add_annotation", pure_quantify_add_annotation, METH_VARARGS}, +#endif /* QUANTIFY_H */ + {NULL, NULL} /* sentinel */ +}; + + + +static void +ins(d, name, val) + PyObject *d; + char* name; + long val; +{ + PyObject *v = PyInt_FromLong(val); + if (v) { + (void)PyDict_SetItemString(d, name, v); + Py_DECREF(v); + } +} + + +void +initpure() +{ + PyObject *m, *d; + + m = Py_InitModule("pure", pure_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + /* this is bogus because we should be able to find this information + * out from the header files. Pure's current versions don't + * include this information! + */ +#ifdef PURE_PURIFY_VERSION + ins(d, "PURIFY_VERSION", PURE_PURIFY_VERSION); +#else + PyDict_SetItemString(d, "PURIFY_VERSION", Py_None); +#endif + + /* these aren't terribly useful because purify_exit() isn't + * exported correctly. See the note at the top of the file. + */ +#ifdef PURIFY_EXIT_ERRORS + ins(d, "PURIFY_EXIT_ERRORS", PURIFY_EXIT_ERRORS); +#endif +#ifdef PURIFY_EXIT_LEAKS + ins(d, "PURIFY_EXIT_LEAKS", PURIFY_EXIT_LEAKS); +#endif +#ifdef PURIFY_EXIT_PLEAKS + ins(d, "PURIFY_EXIT_PLEAKS", PURIFY_EXIT_PLEAKS); +#endif + + +#ifdef PURE_QUANTIFY_VERSION + ins(d, "QUANTIFY_VERSION", PURE_QUANTIFY_VERSION); +#else + PyDict_SetItemString(d, "QUANTIFY_VERSION", Py_None); +#endif +} diff --git a/sys/src/cmd/python/Modules/pwdmodule.c b/sys/src/cmd/python/Modules/pwdmodule.c new file mode 100644 index 000000000..7600d05ee --- /dev/null +++ b/sys/src/cmd/python/Modules/pwdmodule.c @@ -0,0 +1,198 @@ + +/* UNIX password file access module */ + +#include "Python.h" +#include "structseq.h" + +#include <sys/types.h> +#include <pwd.h> + +static PyStructSequence_Field struct_pwd_type_fields[] = { + {"pw_name", "user name"}, + {"pw_passwd", "password"}, + {"pw_uid", "user id"}, + {"pw_gid", "group id"}, + {"pw_gecos", "real name"}, + {"pw_dir", "home directory"}, + {"pw_shell", "shell program"}, + {0} +}; + +PyDoc_STRVAR(struct_passwd__doc__, +"pwd.struct_passwd: Results from getpw*() routines.\n\n\ +This object may be accessed either as a tuple of\n\ + (pw_name,pw_passwd,pw_uid,pw_gid,pw_gecos,pw_dir,pw_shell)\n\ +or via the object attributes as named in the above tuple."); + +static PyStructSequence_Desc struct_pwd_type_desc = { + "pwd.struct_passwd", + struct_passwd__doc__, + struct_pwd_type_fields, + 7, +}; + +PyDoc_STRVAR(pwd__doc__, +"This module provides access to the Unix password database.\n\ +It is available on all Unix versions.\n\ +\n\ +Password database entries are reported as 7-tuples containing the following\n\ +items from the password database (see `<pwd.h>'), in order:\n\ +pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell.\n\ +The uid and gid items are integers, all others are strings. An\n\ +exception is raised if the entry asked for cannot be found."); + + +static int initialized; +static PyTypeObject StructPwdType; + +static void +sets(PyObject *v, int i, char* val) +{ + if (val) + PyStructSequence_SET_ITEM(v, i, PyString_FromString(val)); + else { + PyStructSequence_SET_ITEM(v, i, Py_None); + Py_INCREF(Py_None); + } +} + +static PyObject * +mkpwent(struct passwd *p) +{ + int setIndex = 0; + PyObject *v = PyStructSequence_New(&StructPwdType); + if (v == NULL) + return NULL; + +#define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyInt_FromLong((long) val)) +#define SETS(i,val) sets(v, i, val) + + SETS(setIndex++, p->pw_name); +#if defined( __VMS) || defined(PLAN9APE) + SETS(setIndex++, ""); +#else + SETS(setIndex++, p->pw_passwd); +#endif + SETI(setIndex++, p->pw_uid); + SETI(setIndex++, p->pw_gid); +#if defined( __VMS) || defined(PLAN9APE) + SETS(setIndex++, ""); +#else + SETS(setIndex++, p->pw_gecos); +#endif + SETS(setIndex++, p->pw_dir); + SETS(setIndex++, p->pw_shell); + +#undef SETS +#undef SETI + + if (PyErr_Occurred()) { + Py_XDECREF(v); + return NULL; + } + + return v; +} + +PyDoc_STRVAR(pwd_getpwuid__doc__, +"getpwuid(uid) -> (pw_name,pw_passwd,pw_uid,\n\ + pw_gid,pw_gecos,pw_dir,pw_shell)\n\ +Return the password database entry for the given numeric user ID.\n\ +See pwd.__doc__ for more on password database entries."); + +static PyObject * +pwd_getpwuid(PyObject *self, PyObject *args) +{ + unsigned int uid; + struct passwd *p; + if (!PyArg_ParseTuple(args, "I:getpwuid", &uid)) + return NULL; + if ((p = getpwuid(uid)) == NULL) { + PyErr_Format(PyExc_KeyError, + "getpwuid(): uid not found: %d", uid); + return NULL; + } + return mkpwent(p); +} + +PyDoc_STRVAR(pwd_getpwnam__doc__, +"getpwnam(name) -> (pw_name,pw_passwd,pw_uid,\n\ + pw_gid,pw_gecos,pw_dir,pw_shell)\n\ +Return the password database entry for the given user name.\n\ +See pwd.__doc__ for more on password database entries."); + +static PyObject * +pwd_getpwnam(PyObject *self, PyObject *args) +{ + char *name; + struct passwd *p; + if (!PyArg_ParseTuple(args, "s:getpwnam", &name)) + return NULL; + if ((p = getpwnam(name)) == NULL) { + PyErr_Format(PyExc_KeyError, + "getpwnam(): name not found: %s", name); + return NULL; + } + return mkpwent(p); +} + +#ifdef HAVE_GETPWENT +PyDoc_STRVAR(pwd_getpwall__doc__, +"getpwall() -> list_of_entries\n\ +Return a list of all available password database entries, \ +in arbitrary order.\n\ +See pwd.__doc__ for more on password database entries."); + +static PyObject * +pwd_getpwall(PyObject *self) +{ + PyObject *d; + struct passwd *p; + if ((d = PyList_New(0)) == NULL) + return NULL; +#if defined(PYOS_OS2) && defined(PYCC_GCC) + if ((p = getpwuid(0)) != NULL) { +#else + setpwent(); + while ((p = getpwent()) != NULL) { +#endif + PyObject *v = mkpwent(p); + if (v == NULL || PyList_Append(d, v) != 0) { + Py_XDECREF(v); + Py_DECREF(d); + return NULL; + } + Py_DECREF(v); + } + endpwent(); + return d; +} +#endif + +static PyMethodDef pwd_methods[] = { + {"getpwuid", pwd_getpwuid, METH_VARARGS, pwd_getpwuid__doc__}, + {"getpwnam", pwd_getpwnam, METH_VARARGS, pwd_getpwnam__doc__}, +#ifdef HAVE_GETPWENT + {"getpwall", (PyCFunction)pwd_getpwall, + METH_NOARGS, pwd_getpwall__doc__}, +#endif + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +initpwd(void) +{ + PyObject *m; + m = Py_InitModule3("pwd", pwd_methods, pwd__doc__); + if (m == NULL) + return; + + if (!initialized) + PyStructSequence_InitType(&StructPwdType, + &struct_pwd_type_desc); + Py_INCREF((PyObject *) &StructPwdType); + PyModule_AddObject(m, "struct_passwd", (PyObject *) &StructPwdType); + /* And for b/w compatibility (this was defined by mistake): */ + PyModule_AddObject(m, "struct_pwent", (PyObject *) &StructPwdType); + initialized = 1; +} diff --git a/sys/src/cmd/python/Modules/pyexpat.c b/sys/src/cmd/python/Modules/pyexpat.c new file mode 100644 index 000000000..cbf574ae5 --- /dev/null +++ b/sys/src/cmd/python/Modules/pyexpat.c @@ -0,0 +1,2149 @@ +#include "Python.h" +#include <ctype.h> + +#include "frameobject.h" +#include "expat.h" + +#include "pyexpat.h" + +#define XML_COMBINED_VERSION (10000*XML_MAJOR_VERSION+100*XML_MINOR_VERSION+XML_MICRO_VERSION) + +#ifndef PyDoc_STRVAR + +/* + * fdrake says: + * Don't change the PyDoc_STR macro definition to (str), because + * '''the parentheses cause compile failures + * ("non-constant static initializer" or something like that) + * on some platforms (Irix?)''' + */ +#define PyDoc_STR(str) str +#define PyDoc_VAR(name) static char name[] +#define PyDoc_STRVAR(name,str) PyDoc_VAR(name) = PyDoc_STR(str) +#endif + +#if (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 2) +/* In Python 2.0 and 2.1, disabling Unicode was not possible. */ +#define Py_USING_UNICODE +#else +#define FIX_TRACE +#endif + +enum HandlerTypes { + StartElement, + EndElement, + ProcessingInstruction, + CharacterData, + UnparsedEntityDecl, + NotationDecl, + StartNamespaceDecl, + EndNamespaceDecl, + Comment, + StartCdataSection, + EndCdataSection, + Default, + DefaultHandlerExpand, + NotStandalone, + ExternalEntityRef, + StartDoctypeDecl, + EndDoctypeDecl, + EntityDecl, + XmlDecl, + ElementDecl, + AttlistDecl, +#if XML_COMBINED_VERSION >= 19504 + SkippedEntity, +#endif + _DummyDecl +}; + +static PyObject *ErrorObject; + +/* ----------------------------------------------------- */ + +/* Declarations for objects of type xmlparser */ + +typedef struct { + PyObject_HEAD + + XML_Parser itself; + int returns_unicode; /* True if Unicode strings are returned; + if false, UTF-8 strings are returned */ + int ordered_attributes; /* Return attributes as a list. */ + int specified_attributes; /* Report only specified attributes. */ + int in_callback; /* Is a callback active? */ + int ns_prefixes; /* Namespace-triplets mode? */ + XML_Char *buffer; /* Buffer used when accumulating characters */ + /* NULL if not enabled */ + int buffer_size; /* Size of buffer, in XML_Char units */ + int buffer_used; /* Buffer units in use */ + PyObject *intern; /* Dictionary to intern strings */ + PyObject **handlers; +} xmlparseobject; + +#define CHARACTER_DATA_BUFFER_SIZE 8192 + +static PyTypeObject Xmlparsetype; + +typedef void (*xmlhandlersetter)(XML_Parser self, void *meth); +typedef void* xmlhandler; + +struct HandlerInfo { + const char *name; + xmlhandlersetter setter; + xmlhandler handler; + PyCodeObject *tb_code; + PyObject *nameobj; +}; + +static struct HandlerInfo handler_info[64]; + +/* Set an integer attribute on the error object; return true on success, + * false on an exception. + */ +static int +set_error_attr(PyObject *err, char *name, int value) +{ + PyObject *v = PyInt_FromLong(value); + + if (v == NULL || PyObject_SetAttrString(err, name, v) == -1) { + Py_XDECREF(v); + return 0; + } + Py_DECREF(v); + return 1; +} + +/* Build and set an Expat exception, including positioning + * information. Always returns NULL. + */ +static PyObject * +set_error(xmlparseobject *self, enum XML_Error code) +{ + PyObject *err; + char buffer[256]; + XML_Parser parser = self->itself; + int lineno = XML_GetErrorLineNumber(parser); + int column = XML_GetErrorColumnNumber(parser); + + /* There is no risk of overflowing this buffer, since + even for 64-bit integers, there is sufficient space. */ + sprintf(buffer, "%.200s: line %i, column %i", + XML_ErrorString(code), lineno, column); + err = PyObject_CallFunction(ErrorObject, "s", buffer); + if ( err != NULL + && set_error_attr(err, "code", code) + && set_error_attr(err, "offset", column) + && set_error_attr(err, "lineno", lineno)) { + PyErr_SetObject(ErrorObject, err); + } + Py_XDECREF(err); + return NULL; +} + +static int +have_handler(xmlparseobject *self, int type) +{ + PyObject *handler = self->handlers[type]; + return handler != NULL; +} + +static PyObject * +get_handler_name(struct HandlerInfo *hinfo) +{ + PyObject *name = hinfo->nameobj; + if (name == NULL) { + name = PyString_FromString(hinfo->name); + hinfo->nameobj = name; + } + Py_XINCREF(name); + return name; +} + + +#ifdef Py_USING_UNICODE +/* Convert a string of XML_Chars into a Unicode string. + Returns None if str is a null pointer. */ + +static PyObject * +conv_string_to_unicode(const XML_Char *str) +{ + /* XXX currently this code assumes that XML_Char is 8-bit, + and hence in UTF-8. */ + /* UTF-8 from Expat, Unicode desired */ + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyUnicode_DecodeUTF8(str, strlen(str), "strict"); +} + +static PyObject * +conv_string_len_to_unicode(const XML_Char *str, int len) +{ + /* XXX currently this code assumes that XML_Char is 8-bit, + and hence in UTF-8. */ + /* UTF-8 from Expat, Unicode desired */ + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyUnicode_DecodeUTF8((const char *)str, len, "strict"); +} +#endif + +/* Convert a string of XML_Chars into an 8-bit Python string. + Returns None if str is a null pointer. */ + +static PyObject * +conv_string_to_utf8(const XML_Char *str) +{ + /* XXX currently this code assumes that XML_Char is 8-bit, + and hence in UTF-8. */ + /* UTF-8 from Expat, UTF-8 desired */ + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(str); +} + +static PyObject * +conv_string_len_to_utf8(const XML_Char *str, int len) +{ + /* XXX currently this code assumes that XML_Char is 8-bit, + and hence in UTF-8. */ + /* UTF-8 from Expat, UTF-8 desired */ + if (str == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromStringAndSize((const char *)str, len); +} + +/* Callback routines */ + +static void clear_handlers(xmlparseobject *self, int initial); + +/* This handler is used when an error has been detected, in the hope + that actual parsing can be terminated early. This will only help + if an external entity reference is encountered. */ +static int +error_external_entity_ref_handler(XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId) +{ + return 0; +} + +/* Dummy character data handler used when an error (exception) has + been detected, and the actual parsing can be terminated early. + This is needed since character data handler can't be safely removed + from within the character data handler, but can be replaced. It is + used only from the character data handler trampoline, and must be + used right after `flag_error()` is called. */ +static void +noop_character_data_handler(void *userData, const XML_Char *data, int len) +{ + /* Do nothing. */ +} + +static void +flag_error(xmlparseobject *self) +{ + clear_handlers(self, 0); + XML_SetExternalEntityRefHandler(self->itself, + error_external_entity_ref_handler); +} + +static PyCodeObject* +getcode(enum HandlerTypes slot, char* func_name, int lineno) +{ + PyObject *code = NULL; + PyObject *name = NULL; + PyObject *nulltuple = NULL; + PyObject *filename = NULL; + + if (handler_info[slot].tb_code == NULL) { + code = PyString_FromString(""); + if (code == NULL) + goto failed; + name = PyString_FromString(func_name); + if (name == NULL) + goto failed; + nulltuple = PyTuple_New(0); + if (nulltuple == NULL) + goto failed; + filename = PyString_FromString(__FILE__); + handler_info[slot].tb_code = + PyCode_New(0, /* argcount */ + 0, /* nlocals */ + 0, /* stacksize */ + 0, /* flags */ + code, /* code */ + nulltuple, /* consts */ + nulltuple, /* names */ + nulltuple, /* varnames */ +#if PYTHON_API_VERSION >= 1010 + nulltuple, /* freevars */ + nulltuple, /* cellvars */ +#endif + filename, /* filename */ + name, /* name */ + lineno, /* firstlineno */ + code /* lnotab */ + ); + if (handler_info[slot].tb_code == NULL) + goto failed; + Py_DECREF(code); + Py_DECREF(nulltuple); + Py_DECREF(filename); + Py_DECREF(name); + } + return handler_info[slot].tb_code; + failed: + Py_XDECREF(code); + Py_XDECREF(name); + return NULL; +} + +#ifdef FIX_TRACE +static int +trace_frame(PyThreadState *tstate, PyFrameObject *f, int code, PyObject *val) +{ + int result = 0; + if (!tstate->use_tracing || tstate->tracing) + return 0; + if (tstate->c_profilefunc != NULL) { + tstate->tracing++; + result = tstate->c_profilefunc(tstate->c_profileobj, + f, code , val); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + if (result) + return result; + } + if (tstate->c_tracefunc != NULL) { + tstate->tracing++; + result = tstate->c_tracefunc(tstate->c_traceobj, + f, code , val); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + } + return result; +} + +static int +trace_frame_exc(PyThreadState *tstate, PyFrameObject *f) +{ + PyObject *type, *value, *traceback, *arg; + int err; + + if (tstate->c_tracefunc == NULL) + return 0; + + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } +#if PY_VERSION_HEX < 0x02040000 + arg = Py_BuildValue("(OOO)", type, value, traceback); +#else + arg = PyTuple_Pack(3, type, value, traceback); +#endif + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return 0; + } + err = trace_frame(tstate, f, PyTrace_EXCEPTION, arg); + Py_DECREF(arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } + return err; +} +#endif + +static PyObject* +call_with_frame(PyCodeObject *c, PyObject* func, PyObject* args, + xmlparseobject *self) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyFrameObject *f; + PyObject *res; + + if (c == NULL) + return NULL; + + f = PyFrame_New(tstate, c, PyEval_GetGlobals(), NULL); + if (f == NULL) + return NULL; + tstate->frame = f; +#ifdef FIX_TRACE + if (trace_frame(tstate, f, PyTrace_CALL, Py_None) < 0) { + return NULL; + } +#endif + res = PyEval_CallObject(func, args); + if (res == NULL) { + if (tstate->curexc_traceback == NULL) + PyTraceBack_Here(f); + XML_StopParser(self->itself, XML_FALSE); +#ifdef FIX_TRACE + if (trace_frame_exc(tstate, f) < 0) { + return NULL; + } + } + else { + if (trace_frame(tstate, f, PyTrace_RETURN, res) < 0) { + Py_XDECREF(res); + res = NULL; + } + } +#else + } +#endif + tstate->frame = f->f_back; + Py_DECREF(f); + return res; +} + +#ifndef Py_USING_UNICODE +#define STRING_CONV_FUNC conv_string_to_utf8 +#else +/* Python 2.0 and later versions, when built with Unicode support */ +#define STRING_CONV_FUNC (self->returns_unicode \ + ? conv_string_to_unicode : conv_string_to_utf8) +#endif + +static PyObject* +string_intern(xmlparseobject *self, const char* str) +{ + PyObject *result = STRING_CONV_FUNC(str); + PyObject *value; + /* result can be NULL if the unicode conversion failed. */ + if (!result) + return result; + if (!self->intern) + return result; + value = PyDict_GetItem(self->intern, result); + if (!value) { + if (PyDict_SetItem(self->intern, result, result) == 0) + return result; + else + return NULL; + } + Py_INCREF(value); + Py_DECREF(result); + return value; +} + +/* Return 0 on success, -1 on exception. + * flag_error() will be called before return if needed. + */ +static int +call_character_handler(xmlparseobject *self, const XML_Char *buffer, int len) +{ + PyObject *args; + PyObject *temp; + + args = PyTuple_New(1); + if (args == NULL) + return -1; +#ifdef Py_USING_UNICODE + temp = (self->returns_unicode + ? conv_string_len_to_unicode(buffer, len) + : conv_string_len_to_utf8(buffer, len)); +#else + temp = conv_string_len_to_utf8(buffer, len); +#endif + if (temp == NULL) { + Py_DECREF(args); + flag_error(self); + XML_SetCharacterDataHandler(self->itself, + noop_character_data_handler); + return -1; + } + PyTuple_SET_ITEM(args, 0, temp); + /* temp is now a borrowed reference; consider it unused. */ + self->in_callback = 1; + temp = call_with_frame(getcode(CharacterData, "CharacterData", __LINE__), + self->handlers[CharacterData], args, self); + /* temp is an owned reference again, or NULL */ + self->in_callback = 0; + Py_DECREF(args); + if (temp == NULL) { + flag_error(self); + XML_SetCharacterDataHandler(self->itself, + noop_character_data_handler); + return -1; + } + Py_DECREF(temp); + return 0; +} + +static int +flush_character_buffer(xmlparseobject *self) +{ + int rc; + if (self->buffer == NULL || self->buffer_used == 0) + return 0; + rc = call_character_handler(self, self->buffer, self->buffer_used); + self->buffer_used = 0; + return rc; +} + +static void +my_CharacterDataHandler(void *userData, const XML_Char *data, int len) +{ + xmlparseobject *self = (xmlparseobject *) userData; + if (self->buffer == NULL) + call_character_handler(self, data, len); + else { + if ((self->buffer_used + len) > self->buffer_size) { + if (flush_character_buffer(self) < 0) + return; + /* handler might have changed; drop the rest on the floor + * if there isn't a handler anymore + */ + if (!have_handler(self, CharacterData)) + return; + } + if (len > self->buffer_size) { + call_character_handler(self, data, len); + self->buffer_used = 0; + } + else { + memcpy(self->buffer + self->buffer_used, + data, len * sizeof(XML_Char)); + self->buffer_used += len; + } + } +} + +static void +my_StartElementHandler(void *userData, + const XML_Char *name, const XML_Char *atts[]) +{ + xmlparseobject *self = (xmlparseobject *)userData; + + if (have_handler(self, StartElement)) { + PyObject *container, *rv, *args; + int i, max; + + if (flush_character_buffer(self) < 0) + return; + /* Set max to the number of slots filled in atts[]; max/2 is + * the number of attributes we need to process. + */ + if (self->specified_attributes) { + max = XML_GetSpecifiedAttributeCount(self->itself); + } + else { + max = 0; + while (atts[max] != NULL) + max += 2; + } + /* Build the container. */ + if (self->ordered_attributes) + container = PyList_New(max); + else + container = PyDict_New(); + if (container == NULL) { + flag_error(self); + return; + } + for (i = 0; i < max; i += 2) { + PyObject *n = string_intern(self, (XML_Char *) atts[i]); + PyObject *v; + if (n == NULL) { + flag_error(self); + Py_DECREF(container); + return; + } + v = STRING_CONV_FUNC((XML_Char *) atts[i+1]); + if (v == NULL) { + flag_error(self); + Py_DECREF(container); + Py_DECREF(n); + return; + } + if (self->ordered_attributes) { + PyList_SET_ITEM(container, i, n); + PyList_SET_ITEM(container, i+1, v); + } + else if (PyDict_SetItem(container, n, v)) { + flag_error(self); + Py_DECREF(n); + Py_DECREF(v); + return; + } + else { + Py_DECREF(n); + Py_DECREF(v); + } + } + args = string_intern(self, name); + if (args != NULL) + args = Py_BuildValue("(NN)", args, container); + if (args == NULL) { + Py_DECREF(container); + return; + } + /* Container is now a borrowed reference; ignore it. */ + self->in_callback = 1; + rv = call_with_frame(getcode(StartElement, "StartElement", __LINE__), + self->handlers[StartElement], args, self); + self->in_callback = 0; + Py_DECREF(args); + if (rv == NULL) { + flag_error(self); + return; + } + Py_DECREF(rv); + } +} + +#define RC_HANDLER(RC, NAME, PARAMS, INIT, PARAM_FORMAT, CONVERSION, \ + RETURN, GETUSERDATA) \ +static RC \ +my_##NAME##Handler PARAMS {\ + xmlparseobject *self = GETUSERDATA ; \ + PyObject *args = NULL; \ + PyObject *rv = NULL; \ + INIT \ +\ + if (have_handler(self, NAME)) { \ + if (flush_character_buffer(self) < 0) \ + return RETURN; \ + args = Py_BuildValue PARAM_FORMAT ;\ + if (!args) { flag_error(self); return RETURN;} \ + self->in_callback = 1; \ + rv = call_with_frame(getcode(NAME,#NAME,__LINE__), \ + self->handlers[NAME], args, self); \ + self->in_callback = 0; \ + Py_DECREF(args); \ + if (rv == NULL) { \ + flag_error(self); \ + return RETURN; \ + } \ + CONVERSION \ + Py_DECREF(rv); \ + } \ + return RETURN; \ +} + +#define VOID_HANDLER(NAME, PARAMS, PARAM_FORMAT) \ + RC_HANDLER(void, NAME, PARAMS, ;, PARAM_FORMAT, ;, ;,\ + (xmlparseobject *)userData) + +#define INT_HANDLER(NAME, PARAMS, PARAM_FORMAT)\ + RC_HANDLER(int, NAME, PARAMS, int rc=0;, PARAM_FORMAT, \ + rc = PyInt_AsLong(rv);, rc, \ + (xmlparseobject *)userData) + +VOID_HANDLER(EndElement, + (void *userData, const XML_Char *name), + ("(N)", string_intern(self, name))) + +VOID_HANDLER(ProcessingInstruction, + (void *userData, + const XML_Char *target, + const XML_Char *data), + ("(NO&)", string_intern(self, target), STRING_CONV_FUNC,data)) + +VOID_HANDLER(UnparsedEntityDecl, + (void *userData, + const XML_Char *entityName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName), + ("(NNNNN)", + string_intern(self, entityName), string_intern(self, base), + string_intern(self, systemId), string_intern(self, publicId), + string_intern(self, notationName))) + +#ifndef Py_USING_UNICODE +VOID_HANDLER(EntityDecl, + (void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName), + ("NiNNNNN", + string_intern(self, entityName), is_parameter_entity, + conv_string_len_to_utf8(value, value_length), + string_intern(self, base), string_intern(self, systemId), + string_intern(self, publicId), + string_intern(self, notationName))) +#else +VOID_HANDLER(EntityDecl, + (void *userData, + const XML_Char *entityName, + int is_parameter_entity, + const XML_Char *value, + int value_length, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId, + const XML_Char *notationName), + ("NiNNNNN", + string_intern(self, entityName), is_parameter_entity, + (self->returns_unicode + ? conv_string_len_to_unicode(value, value_length) + : conv_string_len_to_utf8(value, value_length)), + string_intern(self, base), string_intern(self, systemId), + string_intern(self, publicId), + string_intern(self, notationName))) +#endif + +VOID_HANDLER(XmlDecl, + (void *userData, + const XML_Char *version, + const XML_Char *encoding, + int standalone), + ("(O&O&i)", + STRING_CONV_FUNC,version, STRING_CONV_FUNC,encoding, + standalone)) + +static PyObject * +conv_content_model(XML_Content * const model, + PyObject *(*conv_string)(const XML_Char *)) +{ + PyObject *result = NULL; + PyObject *children = PyTuple_New(model->numchildren); + int i; + + if (children != NULL) { + assert(model->numchildren < INT_MAX); + for (i = 0; i < (int)model->numchildren; ++i) { + PyObject *child = conv_content_model(&model->children[i], + conv_string); + if (child == NULL) { + Py_XDECREF(children); + return NULL; + } + PyTuple_SET_ITEM(children, i, child); + } + result = Py_BuildValue("(iiO&N)", + model->type, model->quant, + conv_string,model->name, children); + } + return result; +} + +static void +my_ElementDeclHandler(void *userData, + const XML_Char *name, + XML_Content *model) +{ + xmlparseobject *self = (xmlparseobject *)userData; + PyObject *args = NULL; + + if (have_handler(self, ElementDecl)) { + PyObject *rv = NULL; + PyObject *modelobj, *nameobj; + + if (flush_character_buffer(self) < 0) + goto finally; +#ifdef Py_USING_UNICODE + modelobj = conv_content_model(model, + (self->returns_unicode + ? conv_string_to_unicode + : conv_string_to_utf8)); +#else + modelobj = conv_content_model(model, conv_string_to_utf8); +#endif + if (modelobj == NULL) { + flag_error(self); + goto finally; + } + nameobj = string_intern(self, name); + if (nameobj == NULL) { + Py_DECREF(modelobj); + flag_error(self); + goto finally; + } + args = Py_BuildValue("NN", nameobj, modelobj); + if (args == NULL) { + Py_DECREF(modelobj); + flag_error(self); + goto finally; + } + self->in_callback = 1; + rv = call_with_frame(getcode(ElementDecl, "ElementDecl", __LINE__), + self->handlers[ElementDecl], args, self); + self->in_callback = 0; + if (rv == NULL) { + flag_error(self); + goto finally; + } + Py_DECREF(rv); + } + finally: + Py_XDECREF(args); + XML_FreeContentModel(self->itself, model); + return; +} + +VOID_HANDLER(AttlistDecl, + (void *userData, + const XML_Char *elname, + const XML_Char *attname, + const XML_Char *att_type, + const XML_Char *dflt, + int isrequired), + ("(NNO&O&i)", + string_intern(self, elname), string_intern(self, attname), + STRING_CONV_FUNC,att_type, STRING_CONV_FUNC,dflt, + isrequired)) + +#if XML_COMBINED_VERSION >= 19504 +VOID_HANDLER(SkippedEntity, + (void *userData, + const XML_Char *entityName, + int is_parameter_entity), + ("Ni", + string_intern(self, entityName), is_parameter_entity)) +#endif + +VOID_HANDLER(NotationDecl, + (void *userData, + const XML_Char *notationName, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId), + ("(NNNN)", + string_intern(self, notationName), string_intern(self, base), + string_intern(self, systemId), string_intern(self, publicId))) + +VOID_HANDLER(StartNamespaceDecl, + (void *userData, + const XML_Char *prefix, + const XML_Char *uri), + ("(NN)", + string_intern(self, prefix), string_intern(self, uri))) + +VOID_HANDLER(EndNamespaceDecl, + (void *userData, + const XML_Char *prefix), + ("(N)", string_intern(self, prefix))) + +VOID_HANDLER(Comment, + (void *userData, const XML_Char *data), + ("(O&)", STRING_CONV_FUNC,data)) + +VOID_HANDLER(StartCdataSection, + (void *userData), + ("()")) + +VOID_HANDLER(EndCdataSection, + (void *userData), + ("()")) + +#ifndef Py_USING_UNICODE +VOID_HANDLER(Default, + (void *userData, const XML_Char *s, int len), + ("(N)", conv_string_len_to_utf8(s,len))) + +VOID_HANDLER(DefaultHandlerExpand, + (void *userData, const XML_Char *s, int len), + ("(N)", conv_string_len_to_utf8(s,len))) +#else +VOID_HANDLER(Default, + (void *userData, const XML_Char *s, int len), + ("(N)", (self->returns_unicode + ? conv_string_len_to_unicode(s,len) + : conv_string_len_to_utf8(s,len)))) + +VOID_HANDLER(DefaultHandlerExpand, + (void *userData, const XML_Char *s, int len), + ("(N)", (self->returns_unicode + ? conv_string_len_to_unicode(s,len) + : conv_string_len_to_utf8(s,len)))) +#endif + +INT_HANDLER(NotStandalone, + (void *userData), + ("()")) + +RC_HANDLER(int, ExternalEntityRef, + (XML_Parser parser, + const XML_Char *context, + const XML_Char *base, + const XML_Char *systemId, + const XML_Char *publicId), + int rc=0;, + ("(O&NNN)", + STRING_CONV_FUNC,context, string_intern(self, base), + string_intern(self, systemId), string_intern(self, publicId)), + rc = PyInt_AsLong(rv);, rc, + XML_GetUserData(parser)) + +/* XXX UnknownEncodingHandler */ + +VOID_HANDLER(StartDoctypeDecl, + (void *userData, const XML_Char *doctypeName, + const XML_Char *sysid, const XML_Char *pubid, + int has_internal_subset), + ("(NNNi)", string_intern(self, doctypeName), + string_intern(self, sysid), string_intern(self, pubid), + has_internal_subset)) + +VOID_HANDLER(EndDoctypeDecl, (void *userData), ("()")) + +/* ---------------------------------------------------------------- */ + +static PyObject * +get_parse_result(xmlparseobject *self, int rv) +{ + if (PyErr_Occurred()) { + return NULL; + } + if (rv == 0) { + return set_error(self, XML_GetErrorCode(self->itself)); + } + if (flush_character_buffer(self) < 0) { + return NULL; + } + return PyInt_FromLong(rv); +} + +PyDoc_STRVAR(xmlparse_Parse__doc__, +"Parse(data[, isfinal])\n\ +Parse XML data. `isfinal' should be true at end of input."); + +static PyObject * +xmlparse_Parse(xmlparseobject *self, PyObject *args) +{ + char *s; + int slen; + int isFinal = 0; + + if (!PyArg_ParseTuple(args, "s#|i:Parse", &s, &slen, &isFinal)) + return NULL; + + return get_parse_result(self, XML_Parse(self->itself, s, slen, isFinal)); +} + +/* File reading copied from cPickle */ + +#define BUF_SIZE 2048 + +static int +readinst(char *buf, int buf_size, PyObject *meth) +{ + PyObject *arg = NULL; + PyObject *bytes = NULL; + PyObject *str = NULL; + int len = -1; + + if ((bytes = PyInt_FromLong(buf_size)) == NULL) + goto finally; + + if ((arg = PyTuple_New(1)) == NULL) { + Py_DECREF(bytes); + goto finally; + } + + PyTuple_SET_ITEM(arg, 0, bytes); + +#if PY_VERSION_HEX < 0x02020000 + str = PyObject_CallObject(meth, arg); +#else + str = PyObject_Call(meth, arg, NULL); +#endif + if (str == NULL) + goto finally; + + /* XXX what to do if it returns a Unicode string? */ + if (!PyString_Check(str)) { + PyErr_Format(PyExc_TypeError, + "read() did not return a string object (type=%.400s)", + str->ob_type->tp_name); + goto finally; + } + len = PyString_GET_SIZE(str); + if (len > buf_size) { + PyErr_Format(PyExc_ValueError, + "read() returned too much data: " + "%i bytes requested, %i returned", + buf_size, len); + goto finally; + } + memcpy(buf, PyString_AsString(str), len); +finally: + Py_XDECREF(arg); + Py_XDECREF(str); + return len; +} + +PyDoc_STRVAR(xmlparse_ParseFile__doc__, +"ParseFile(file)\n\ +Parse XML data from file-like object."); + +static PyObject * +xmlparse_ParseFile(xmlparseobject *self, PyObject *f) +{ + int rv = 1; + FILE *fp; + PyObject *readmethod = NULL; + + if (PyFile_Check(f)) { + fp = PyFile_AsFile(f); + } + else { + fp = NULL; + readmethod = PyObject_GetAttrString(f, "read"); + if (readmethod == NULL) { + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "argument must have 'read' attribute"); + return NULL; + } + } + for (;;) { + int bytes_read; + void *buf = XML_GetBuffer(self->itself, BUF_SIZE); + if (buf == NULL) { + Py_XDECREF(readmethod); + return PyErr_NoMemory(); + } + + if (fp) { + bytes_read = fread(buf, sizeof(char), BUF_SIZE, fp); + if (bytes_read < 0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + } + else { + bytes_read = readinst(buf, BUF_SIZE, readmethod); + if (bytes_read < 0) { + Py_DECREF(readmethod); + return NULL; + } + } + rv = XML_ParseBuffer(self->itself, bytes_read, bytes_read == 0); + if (PyErr_Occurred()) { + Py_XDECREF(readmethod); + return NULL; + } + + if (!rv || bytes_read == 0) + break; + } + Py_XDECREF(readmethod); + return get_parse_result(self, rv); +} + +PyDoc_STRVAR(xmlparse_SetBase__doc__, +"SetBase(base_url)\n\ +Set the base URL for the parser."); + +static PyObject * +xmlparse_SetBase(xmlparseobject *self, PyObject *args) +{ + char *base; + + if (!PyArg_ParseTuple(args, "s:SetBase", &base)) + return NULL; + if (!XML_SetBase(self->itself, base)) { + return PyErr_NoMemory(); + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(xmlparse_GetBase__doc__, +"GetBase() -> url\n\ +Return base URL string for the parser."); + +static PyObject * +xmlparse_GetBase(xmlparseobject *self, PyObject *unused) +{ + return Py_BuildValue("z", XML_GetBase(self->itself)); +} + +PyDoc_STRVAR(xmlparse_GetInputContext__doc__, +"GetInputContext() -> string\n\ +Return the untranslated text of the input that caused the current event.\n\ +If the event was generated by a large amount of text (such as a start tag\n\ +for an element with many attributes), not all of the text may be available."); + +static PyObject * +xmlparse_GetInputContext(xmlparseobject *self, PyObject *unused) +{ + if (self->in_callback) { + int offset, size; + const char *buffer + = XML_GetInputContext(self->itself, &offset, &size); + + if (buffer != NULL) + return PyString_FromStringAndSize(buffer + offset, + size - offset); + else + Py_RETURN_NONE; + } + else + Py_RETURN_NONE; +} + +PyDoc_STRVAR(xmlparse_ExternalEntityParserCreate__doc__, +"ExternalEntityParserCreate(context[, encoding])\n\ +Create a parser for parsing an external entity based on the\n\ +information passed to the ExternalEntityRefHandler."); + +static PyObject * +xmlparse_ExternalEntityParserCreate(xmlparseobject *self, PyObject *args) +{ + char *context; + char *encoding = NULL; + xmlparseobject *new_parser; + int i; + + if (!PyArg_ParseTuple(args, "z|s:ExternalEntityParserCreate", + &context, &encoding)) { + return NULL; + } + +#ifndef Py_TPFLAGS_HAVE_GC + /* Python versions 2.0 and 2.1 */ + new_parser = PyObject_New(xmlparseobject, &Xmlparsetype); +#else + /* Python versions 2.2 and later */ + new_parser = PyObject_GC_New(xmlparseobject, &Xmlparsetype); +#endif + + if (new_parser == NULL) + return NULL; + new_parser->buffer_size = self->buffer_size; + new_parser->buffer_used = 0; + if (self->buffer != NULL) { + new_parser->buffer = malloc(new_parser->buffer_size); + if (new_parser->buffer == NULL) { +#ifndef Py_TPFLAGS_HAVE_GC + /* Code for versions 2.0 and 2.1 */ + PyObject_Del(new_parser); +#else + /* Code for versions 2.2 and later. */ + PyObject_GC_Del(new_parser); +#endif + return PyErr_NoMemory(); + } + } + else + new_parser->buffer = NULL; + new_parser->returns_unicode = self->returns_unicode; + new_parser->ordered_attributes = self->ordered_attributes; + new_parser->specified_attributes = self->specified_attributes; + new_parser->in_callback = 0; + new_parser->ns_prefixes = self->ns_prefixes; + new_parser->itself = XML_ExternalEntityParserCreate(self->itself, context, + encoding); + new_parser->handlers = 0; + new_parser->intern = self->intern; + Py_XINCREF(new_parser->intern); +#ifdef Py_TPFLAGS_HAVE_GC + PyObject_GC_Track(new_parser); +#else + PyObject_GC_Init(new_parser); +#endif + + if (!new_parser->itself) { + Py_DECREF(new_parser); + return PyErr_NoMemory(); + } + + XML_SetUserData(new_parser->itself, (void *)new_parser); + + /* allocate and clear handlers first */ + for (i = 0; handler_info[i].name != NULL; i++) + /* do nothing */; + + new_parser->handlers = malloc(sizeof(PyObject *) * i); + if (!new_parser->handlers) { + Py_DECREF(new_parser); + return PyErr_NoMemory(); + } + clear_handlers(new_parser, 1); + + /* then copy handlers from self */ + for (i = 0; handler_info[i].name != NULL; i++) { + PyObject *handler = self->handlers[i]; + if (handler != NULL) { + Py_INCREF(handler); + new_parser->handlers[i] = handler; + handler_info[i].setter(new_parser->itself, + handler_info[i].handler); + } + } + return (PyObject *)new_parser; +} + +PyDoc_STRVAR(xmlparse_SetParamEntityParsing__doc__, +"SetParamEntityParsing(flag) -> success\n\ +Controls parsing of parameter entities (including the external DTD\n\ +subset). Possible flag values are XML_PARAM_ENTITY_PARSING_NEVER,\n\ +XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE and\n\ +XML_PARAM_ENTITY_PARSING_ALWAYS. Returns true if setting the flag\n\ +was successful."); + +static PyObject* +xmlparse_SetParamEntityParsing(xmlparseobject *p, PyObject* args) +{ + int flag; + if (!PyArg_ParseTuple(args, "i", &flag)) + return NULL; + flag = XML_SetParamEntityParsing(p->itself, flag); + return PyInt_FromLong(flag); +} + + +#if XML_COMBINED_VERSION >= 19505 +PyDoc_STRVAR(xmlparse_UseForeignDTD__doc__, +"UseForeignDTD([flag])\n\ +Allows the application to provide an artificial external subset if one is\n\ +not specified as part of the document instance. This readily allows the\n\ +use of a 'default' document type controlled by the application, while still\n\ +getting the advantage of providing document type information to the parser.\n\ +'flag' defaults to True if not provided."); + +static PyObject * +xmlparse_UseForeignDTD(xmlparseobject *self, PyObject *args) +{ + PyObject *flagobj = NULL; + XML_Bool flag = XML_TRUE; + enum XML_Error rc; + if (!PyArg_UnpackTuple(args, "UseForeignDTD", 0, 1, &flagobj)) + return NULL; + if (flagobj != NULL) + flag = PyObject_IsTrue(flagobj) ? XML_TRUE : XML_FALSE; + rc = XML_UseForeignDTD(self->itself, flag); + if (rc != XML_ERROR_NONE) { + return set_error(self, rc); + } + Py_INCREF(Py_None); + return Py_None; +} +#endif + +static struct PyMethodDef xmlparse_methods[] = { + {"Parse", (PyCFunction)xmlparse_Parse, + METH_VARARGS, xmlparse_Parse__doc__}, + {"ParseFile", (PyCFunction)xmlparse_ParseFile, + METH_O, xmlparse_ParseFile__doc__}, + {"SetBase", (PyCFunction)xmlparse_SetBase, + METH_VARARGS, xmlparse_SetBase__doc__}, + {"GetBase", (PyCFunction)xmlparse_GetBase, + METH_NOARGS, xmlparse_GetBase__doc__}, + {"ExternalEntityParserCreate", (PyCFunction)xmlparse_ExternalEntityParserCreate, + METH_VARARGS, xmlparse_ExternalEntityParserCreate__doc__}, + {"SetParamEntityParsing", (PyCFunction)xmlparse_SetParamEntityParsing, + METH_VARARGS, xmlparse_SetParamEntityParsing__doc__}, + {"GetInputContext", (PyCFunction)xmlparse_GetInputContext, + METH_NOARGS, xmlparse_GetInputContext__doc__}, +#if XML_COMBINED_VERSION >= 19505 + {"UseForeignDTD", (PyCFunction)xmlparse_UseForeignDTD, + METH_VARARGS, xmlparse_UseForeignDTD__doc__}, +#endif + {NULL, NULL} /* sentinel */ +}; + +/* ---------- */ + + +#ifdef Py_USING_UNICODE + +/* pyexpat international encoding support. + Make it as simple as possible. +*/ + +static char template_buffer[257]; +PyObject *template_string = NULL; + +static void +init_template_buffer(void) +{ + int i; + for (i = 0; i < 256; i++) { + template_buffer[i] = i; + } + template_buffer[256] = 0; +} + +static int +PyUnknownEncodingHandler(void *encodingHandlerData, + const XML_Char *name, + XML_Encoding *info) +{ + PyUnicodeObject *_u_string = NULL; + int result = 0; + int i; + + /* Yes, supports only 8bit encodings */ + _u_string = (PyUnicodeObject *) + PyUnicode_Decode(template_buffer, 256, name, "replace"); + + if (_u_string == NULL) + return result; + + for (i = 0; i < 256; i++) { + /* Stupid to access directly, but fast */ + Py_UNICODE c = _u_string->str[i]; + if (c == Py_UNICODE_REPLACEMENT_CHARACTER) + info->map[i] = -1; + else + info->map[i] = c; + } + info->data = NULL; + info->convert = NULL; + info->release = NULL; + result = 1; + Py_DECREF(_u_string); + return result; +} + +#endif + +static PyObject * +newxmlparseobject(char *encoding, char *namespace_separator, PyObject *intern) +{ + int i; + xmlparseobject *self; + +#ifdef Py_TPFLAGS_HAVE_GC + /* Code for versions 2.2 and later */ + self = PyObject_GC_New(xmlparseobject, &Xmlparsetype); +#else + self = PyObject_New(xmlparseobject, &Xmlparsetype); +#endif + if (self == NULL) + return NULL; + +#ifdef Py_USING_UNICODE + self->returns_unicode = 1; +#else + self->returns_unicode = 0; +#endif + + self->buffer = NULL; + self->buffer_size = CHARACTER_DATA_BUFFER_SIZE; + self->buffer_used = 0; + self->ordered_attributes = 0; + self->specified_attributes = 0; + self->in_callback = 0; + self->ns_prefixes = 0; + self->handlers = NULL; + if (namespace_separator != NULL) { + self->itself = XML_ParserCreateNS(encoding, *namespace_separator); + } + else { + self->itself = XML_ParserCreate(encoding); + } + self->intern = intern; + Py_XINCREF(self->intern); +#ifdef Py_TPFLAGS_HAVE_GC + PyObject_GC_Track(self); +#else + PyObject_GC_Init(self); +#endif + if (self->itself == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "XML_ParserCreate failed"); + Py_DECREF(self); + return NULL; + } + XML_SetUserData(self->itself, (void *)self); +#ifdef Py_USING_UNICODE + XML_SetUnknownEncodingHandler(self->itself, + (XML_UnknownEncodingHandler) PyUnknownEncodingHandler, NULL); +#endif + + for (i = 0; handler_info[i].name != NULL; i++) + /* do nothing */; + + self->handlers = malloc(sizeof(PyObject *) * i); + if (!self->handlers) { + Py_DECREF(self); + return PyErr_NoMemory(); + } + clear_handlers(self, 1); + + return (PyObject*)self; +} + + +static void +xmlparse_dealloc(xmlparseobject *self) +{ + int i; +#ifdef Py_TPFLAGS_HAVE_GC + PyObject_GC_UnTrack(self); +#else + PyObject_GC_Fini(self); +#endif + if (self->itself != NULL) + XML_ParserFree(self->itself); + self->itself = NULL; + + if (self->handlers != NULL) { + PyObject *temp; + for (i = 0; handler_info[i].name != NULL; i++) { + temp = self->handlers[i]; + self->handlers[i] = NULL; + Py_XDECREF(temp); + } + free(self->handlers); + self->handlers = NULL; + } + if (self->buffer != NULL) { + free(self->buffer); + self->buffer = NULL; + } + Py_XDECREF(self->intern); +#ifndef Py_TPFLAGS_HAVE_GC + /* Code for versions 2.0 and 2.1 */ + PyObject_Del(self); +#else + /* Code for versions 2.2 and later. */ + PyObject_GC_Del(self); +#endif +} + +static int +handlername2int(const char *name) +{ + int i; + for (i = 0; handler_info[i].name != NULL; i++) { + if (strcmp(name, handler_info[i].name) == 0) { + return i; + } + } + return -1; +} + +static PyObject * +get_pybool(int istrue) +{ + PyObject *result = istrue ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +static PyObject * +xmlparse_getattr(xmlparseobject *self, char *name) +{ + int handlernum = handlername2int(name); + + if (handlernum != -1) { + PyObject *result = self->handlers[handlernum]; + if (result == NULL) + result = Py_None; + Py_INCREF(result); + return result; + } + if (name[0] == 'E') { + if (strcmp(name, "ErrorCode") == 0) + return PyInt_FromLong((long) + XML_GetErrorCode(self->itself)); + if (strcmp(name, "ErrorLineNumber") == 0) + return PyInt_FromLong((long) + XML_GetErrorLineNumber(self->itself)); + if (strcmp(name, "ErrorColumnNumber") == 0) + return PyInt_FromLong((long) + XML_GetErrorColumnNumber(self->itself)); + if (strcmp(name, "ErrorByteIndex") == 0) + return PyInt_FromLong((long) + XML_GetErrorByteIndex(self->itself)); + } + if (name[0] == 'C') { + if (strcmp(name, "CurrentLineNumber") == 0) + return PyInt_FromLong((long) + XML_GetCurrentLineNumber(self->itself)); + if (strcmp(name, "CurrentColumnNumber") == 0) + return PyInt_FromLong((long) + XML_GetCurrentColumnNumber(self->itself)); + if (strcmp(name, "CurrentByteIndex") == 0) + return PyInt_FromLong((long) + XML_GetCurrentByteIndex(self->itself)); + } + if (name[0] == 'b') { + if (strcmp(name, "buffer_size") == 0) + return PyInt_FromLong((long) self->buffer_size); + if (strcmp(name, "buffer_text") == 0) + return get_pybool(self->buffer != NULL); + if (strcmp(name, "buffer_used") == 0) + return PyInt_FromLong((long) self->buffer_used); + } + if (strcmp(name, "namespace_prefixes") == 0) + return get_pybool(self->ns_prefixes); + if (strcmp(name, "ordered_attributes") == 0) + return get_pybool(self->ordered_attributes); + if (strcmp(name, "returns_unicode") == 0) + return get_pybool((long) self->returns_unicode); + if (strcmp(name, "specified_attributes") == 0) + return get_pybool((long) self->specified_attributes); + if (strcmp(name, "intern") == 0) { + if (self->intern == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + else { + Py_INCREF(self->intern); + return self->intern; + } + } + +#define APPEND(list, str) \ + do { \ + PyObject *o = PyString_FromString(str); \ + if (o != NULL) \ + PyList_Append(list, o); \ + Py_XDECREF(o); \ + } while (0) + + if (strcmp(name, "__members__") == 0) { + int i; + PyObject *rc = PyList_New(0); + if (!rc) + return NULL; + for (i = 0; handler_info[i].name != NULL; i++) { + PyObject *o = get_handler_name(&handler_info[i]); + if (o != NULL) + PyList_Append(rc, o); + Py_XDECREF(o); + } + APPEND(rc, "ErrorCode"); + APPEND(rc, "ErrorLineNumber"); + APPEND(rc, "ErrorColumnNumber"); + APPEND(rc, "ErrorByteIndex"); + APPEND(rc, "CurrentLineNumber"); + APPEND(rc, "CurrentColumnNumber"); + APPEND(rc, "CurrentByteIndex"); + APPEND(rc, "buffer_size"); + APPEND(rc, "buffer_text"); + APPEND(rc, "buffer_used"); + APPEND(rc, "namespace_prefixes"); + APPEND(rc, "ordered_attributes"); + APPEND(rc, "returns_unicode"); + APPEND(rc, "specified_attributes"); + APPEND(rc, "intern"); + +#undef APPEND + return rc; + } + return Py_FindMethod(xmlparse_methods, (PyObject *)self, name); +} + +static int +sethandler(xmlparseobject *self, const char *name, PyObject* v) +{ + int handlernum = handlername2int(name); + if (handlernum >= 0) { + xmlhandler c_handler = NULL; + PyObject *temp = self->handlers[handlernum]; + + if (v == Py_None) { + /* If this is the character data handler, and a character + data handler is already active, we need to be more + careful. What we can safely do is replace the existing + character data handler callback function with a no-op + function that will refuse to call Python. The downside + is that this doesn't completely remove the character + data handler from the C layer if there's any callback + active, so Expat does a little more work than it + otherwise would, but that's really an odd case. A more + elaborate system of handlers and state could remove the + C handler more effectively. */ + if (handlernum == CharacterData && self->in_callback) + c_handler = noop_character_data_handler; + v = NULL; + } + else if (v != NULL) { + Py_INCREF(v); + c_handler = handler_info[handlernum].handler; + } + self->handlers[handlernum] = v; + Py_XDECREF(temp); + handler_info[handlernum].setter(self->itself, c_handler); + return 1; + } + return 0; +} + +static int +xmlparse_setattr(xmlparseobject *self, char *name, PyObject *v) +{ + /* Set attribute 'name' to value 'v'. v==NULL means delete */ + if (v == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute"); + return -1; + } + if (strcmp(name, "buffer_text") == 0) { + if (PyObject_IsTrue(v)) { + if (self->buffer == NULL) { + self->buffer = malloc(self->buffer_size); + if (self->buffer == NULL) { + PyErr_NoMemory(); + return -1; + } + self->buffer_used = 0; + } + } + else if (self->buffer != NULL) { + if (flush_character_buffer(self) < 0) + return -1; + free(self->buffer); + self->buffer = NULL; + } + return 0; + } + if (strcmp(name, "namespace_prefixes") == 0) { + if (PyObject_IsTrue(v)) + self->ns_prefixes = 1; + else + self->ns_prefixes = 0; + XML_SetReturnNSTriplet(self->itself, self->ns_prefixes); + return 0; + } + if (strcmp(name, "ordered_attributes") == 0) { + if (PyObject_IsTrue(v)) + self->ordered_attributes = 1; + else + self->ordered_attributes = 0; + return 0; + } + if (strcmp(name, "returns_unicode") == 0) { + if (PyObject_IsTrue(v)) { +#ifndef Py_USING_UNICODE + PyErr_SetString(PyExc_ValueError, + "Unicode support not available"); + return -1; +#else + self->returns_unicode = 1; +#endif + } + else + self->returns_unicode = 0; + return 0; + } + if (strcmp(name, "specified_attributes") == 0) { + if (PyObject_IsTrue(v)) + self->specified_attributes = 1; + else + self->specified_attributes = 0; + return 0; + } + if (strcmp(name, "CharacterDataHandler") == 0) { + /* If we're changing the character data handler, flush all + * cached data with the old handler. Not sure there's a + * "right" thing to do, though, but this probably won't + * happen. + */ + if (flush_character_buffer(self) < 0) + return -1; + } + if (sethandler(self, name, v)) { + return 0; + } + PyErr_SetString(PyExc_AttributeError, name); + return -1; +} + +#ifdef WITH_CYCLE_GC +static int +xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg) +{ + int i; + for (i = 0; handler_info[i].name != NULL; i++) + Py_VISIT(op->handlers[i]); + return 0; +} + +static int +xmlparse_clear(xmlparseobject *op) +{ + clear_handlers(op, 0); + Py_CLEAR(op->intern); + return 0; +} +#endif + +PyDoc_STRVAR(Xmlparsetype__doc__, "XML parser"); + +static PyTypeObject Xmlparsetype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "pyexpat.xmlparser", /*tp_name*/ + sizeof(xmlparseobject) + PyGC_HEAD_SIZE,/*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)xmlparse_dealloc, /*tp_dealloc*/ + (printfunc)0, /*tp_print*/ + (getattrfunc)xmlparse_getattr, /*tp_getattr*/ + (setattrfunc)xmlparse_setattr, /*tp_setattr*/ + (cmpfunc)0, /*tp_compare*/ + (reprfunc)0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)0, /*tp_hash*/ + (ternaryfunc)0, /*tp_call*/ + (reprfunc)0, /*tp_str*/ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ +#ifdef Py_TPFLAGS_HAVE_GC + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ +#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/ +#endif + Xmlparsetype__doc__, /* tp_doc - Documentation string */ +#ifdef WITH_CYCLE_GC + (traverseproc)xmlparse_traverse, /* tp_traverse */ + (inquiry)xmlparse_clear /* tp_clear */ +#else + 0, 0 +#endif +}; + +/* End of code for xmlparser objects */ +/* -------------------------------------------------------- */ + +PyDoc_STRVAR(pyexpat_ParserCreate__doc__, +"ParserCreate([encoding[, namespace_separator]]) -> parser\n\ +Return a new XML parser object."); + +static PyObject * +pyexpat_ParserCreate(PyObject *notused, PyObject *args, PyObject *kw) +{ + char *encoding = NULL; + char *namespace_separator = NULL; + PyObject *intern = NULL; + PyObject *result; + int intern_decref = 0; + static char *kwlist[] = {"encoding", "namespace_separator", + "intern", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|zzO:ParserCreate", kwlist, + &encoding, &namespace_separator, &intern)) + return NULL; + if (namespace_separator != NULL + && strlen(namespace_separator) > 1) { + PyErr_SetString(PyExc_ValueError, + "namespace_separator must be at most one" + " character, omitted, or None"); + return NULL; + } + /* Explicitly passing None means no interning is desired. + Not passing anything means that a new dictionary is used. */ + if (intern == Py_None) + intern = NULL; + else if (intern == NULL) { + intern = PyDict_New(); + if (!intern) + return NULL; + intern_decref = 1; + } + else if (!PyDict_Check(intern)) { + PyErr_SetString(PyExc_TypeError, "intern must be a dictionary"); + return NULL; + } + + result = newxmlparseobject(encoding, namespace_separator, intern); + if (intern_decref) { + Py_DECREF(intern); + } + return result; +} + +PyDoc_STRVAR(pyexpat_ErrorString__doc__, +"ErrorString(errno) -> string\n\ +Returns string error for given number."); + +static PyObject * +pyexpat_ErrorString(PyObject *self, PyObject *args) +{ + long code = 0; + + if (!PyArg_ParseTuple(args, "l:ErrorString", &code)) + return NULL; + return Py_BuildValue("z", XML_ErrorString((int)code)); +} + +/* List of methods defined in the module */ + +static struct PyMethodDef pyexpat_methods[] = { + {"ParserCreate", (PyCFunction)pyexpat_ParserCreate, + METH_VARARGS|METH_KEYWORDS, pyexpat_ParserCreate__doc__}, + {"ErrorString", (PyCFunction)pyexpat_ErrorString, + METH_VARARGS, pyexpat_ErrorString__doc__}, + + {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ +}; + +/* Module docstring */ + +PyDoc_STRVAR(pyexpat_module_documentation, +"Python wrapper for Expat parser."); + +/* Return a Python string that represents the version number without the + * extra cruft added by revision control, even if the right options were + * given to the "cvs export" command to make it not include the extra + * cruft. + */ +static PyObject * +get_version_string(void) +{ + static char *rcsid = "$Revision: 47253 $"; + char *rev = rcsid; + int i = 0; + + while (!isdigit(Py_CHARMASK(*rev))) + ++rev; + while (rev[i] != ' ' && rev[i] != '\0') + ++i; + + return PyString_FromStringAndSize(rev, i); +} + +/* Initialization function for the module */ + +#ifndef MODULE_NAME +#define MODULE_NAME "pyexpat" +#endif + +#ifndef MODULE_INITFUNC +#define MODULE_INITFUNC initpyexpat +#endif + +#ifndef PyMODINIT_FUNC +# ifdef MS_WINDOWS +# define PyMODINIT_FUNC __declspec(dllexport) void +# else +# define PyMODINIT_FUNC void +# endif +#endif + +PyMODINIT_FUNC MODULE_INITFUNC(void); /* avoid compiler warnings */ + +PyMODINIT_FUNC +MODULE_INITFUNC(void) +{ + PyObject *m, *d; + PyObject *errmod_name = PyString_FromString(MODULE_NAME ".errors"); + PyObject *errors_module; + PyObject *modelmod_name; + PyObject *model_module; + PyObject *sys_modules; + static struct PyExpat_CAPI capi; + PyObject* capi_object; + + if (errmod_name == NULL) + return; + modelmod_name = PyString_FromString(MODULE_NAME ".model"); + if (modelmod_name == NULL) + return; + + Xmlparsetype.ob_type = &PyType_Type; + + /* Create the module and add the functions */ + m = Py_InitModule3(MODULE_NAME, pyexpat_methods, + pyexpat_module_documentation); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + if (ErrorObject == NULL) { + ErrorObject = PyErr_NewException("xml.parsers.expat.ExpatError", + NULL, NULL); + if (ErrorObject == NULL) + return; + } + Py_INCREF(ErrorObject); + PyModule_AddObject(m, "error", ErrorObject); + Py_INCREF(ErrorObject); + PyModule_AddObject(m, "ExpatError", ErrorObject); + Py_INCREF(&Xmlparsetype); + PyModule_AddObject(m, "XMLParserType", (PyObject *) &Xmlparsetype); + + PyModule_AddObject(m, "__version__", get_version_string()); + PyModule_AddStringConstant(m, "EXPAT_VERSION", + (char *) XML_ExpatVersion()); + { + XML_Expat_Version info = XML_ExpatVersionInfo(); + PyModule_AddObject(m, "version_info", + Py_BuildValue("(iii)", info.major, + info.minor, info.micro)); + } +#ifdef Py_USING_UNICODE + init_template_buffer(); +#endif + /* XXX When Expat supports some way of figuring out how it was + compiled, this should check and set native_encoding + appropriately. + */ + PyModule_AddStringConstant(m, "native_encoding", "UTF-8"); + + sys_modules = PySys_GetObject("modules"); + d = PyModule_GetDict(m); + errors_module = PyDict_GetItem(d, errmod_name); + if (errors_module == NULL) { + errors_module = PyModule_New(MODULE_NAME ".errors"); + if (errors_module != NULL) { + PyDict_SetItem(sys_modules, errmod_name, errors_module); + /* gives away the reference to errors_module */ + PyModule_AddObject(m, "errors", errors_module); + } + } + Py_DECREF(errmod_name); + model_module = PyDict_GetItem(d, modelmod_name); + if (model_module == NULL) { + model_module = PyModule_New(MODULE_NAME ".model"); + if (model_module != NULL) { + PyDict_SetItem(sys_modules, modelmod_name, model_module); + /* gives away the reference to model_module */ + PyModule_AddObject(m, "model", model_module); + } + } + Py_DECREF(modelmod_name); + if (errors_module == NULL || model_module == NULL) + /* Don't core dump later! */ + return; + +#if XML_COMBINED_VERSION > 19505 + { + const XML_Feature *features = XML_GetFeatureList(); + PyObject *list = PyList_New(0); + if (list == NULL) + /* just ignore it */ + PyErr_Clear(); + else { + int i = 0; + for (; features[i].feature != XML_FEATURE_END; ++i) { + int ok; + PyObject *item = Py_BuildValue("si", features[i].name, + features[i].value); + if (item == NULL) { + Py_DECREF(list); + list = NULL; + break; + } + ok = PyList_Append(list, item); + Py_DECREF(item); + if (ok < 0) { + PyErr_Clear(); + break; + } + } + if (list != NULL) + PyModule_AddObject(m, "features", list); + } + } +#endif + +#define MYCONST(name) \ + PyModule_AddStringConstant(errors_module, #name, \ + (char*)XML_ErrorString(name)) + + MYCONST(XML_ERROR_NO_MEMORY); + MYCONST(XML_ERROR_SYNTAX); + MYCONST(XML_ERROR_NO_ELEMENTS); + MYCONST(XML_ERROR_INVALID_TOKEN); + MYCONST(XML_ERROR_UNCLOSED_TOKEN); + MYCONST(XML_ERROR_PARTIAL_CHAR); + MYCONST(XML_ERROR_TAG_MISMATCH); + MYCONST(XML_ERROR_DUPLICATE_ATTRIBUTE); + MYCONST(XML_ERROR_JUNK_AFTER_DOC_ELEMENT); + MYCONST(XML_ERROR_PARAM_ENTITY_REF); + MYCONST(XML_ERROR_UNDEFINED_ENTITY); + MYCONST(XML_ERROR_RECURSIVE_ENTITY_REF); + MYCONST(XML_ERROR_ASYNC_ENTITY); + MYCONST(XML_ERROR_BAD_CHAR_REF); + MYCONST(XML_ERROR_BINARY_ENTITY_REF); + MYCONST(XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF); + MYCONST(XML_ERROR_MISPLACED_XML_PI); + MYCONST(XML_ERROR_UNKNOWN_ENCODING); + MYCONST(XML_ERROR_INCORRECT_ENCODING); + MYCONST(XML_ERROR_UNCLOSED_CDATA_SECTION); + MYCONST(XML_ERROR_EXTERNAL_ENTITY_HANDLING); + MYCONST(XML_ERROR_NOT_STANDALONE); + MYCONST(XML_ERROR_UNEXPECTED_STATE); + MYCONST(XML_ERROR_ENTITY_DECLARED_IN_PE); + MYCONST(XML_ERROR_FEATURE_REQUIRES_XML_DTD); + MYCONST(XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING); + /* Added in Expat 1.95.7. */ + MYCONST(XML_ERROR_UNBOUND_PREFIX); + /* Added in Expat 1.95.8. */ + MYCONST(XML_ERROR_UNDECLARING_PREFIX); + MYCONST(XML_ERROR_INCOMPLETE_PE); + MYCONST(XML_ERROR_XML_DECL); + MYCONST(XML_ERROR_TEXT_DECL); + MYCONST(XML_ERROR_PUBLICID); + MYCONST(XML_ERROR_SUSPENDED); + MYCONST(XML_ERROR_NOT_SUSPENDED); + MYCONST(XML_ERROR_ABORTED); + MYCONST(XML_ERROR_FINISHED); + MYCONST(XML_ERROR_SUSPEND_PE); + + PyModule_AddStringConstant(errors_module, "__doc__", + "Constants used to describe error conditions."); + +#undef MYCONST + +#define MYCONST(c) PyModule_AddIntConstant(m, #c, c) + MYCONST(XML_PARAM_ENTITY_PARSING_NEVER); + MYCONST(XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE); + MYCONST(XML_PARAM_ENTITY_PARSING_ALWAYS); +#undef MYCONST + +#define MYCONST(c) PyModule_AddIntConstant(model_module, #c, c) + PyModule_AddStringConstant(model_module, "__doc__", + "Constants used to interpret content model information."); + + MYCONST(XML_CTYPE_EMPTY); + MYCONST(XML_CTYPE_ANY); + MYCONST(XML_CTYPE_MIXED); + MYCONST(XML_CTYPE_NAME); + MYCONST(XML_CTYPE_CHOICE); + MYCONST(XML_CTYPE_SEQ); + + MYCONST(XML_CQUANT_NONE); + MYCONST(XML_CQUANT_OPT); + MYCONST(XML_CQUANT_REP); + MYCONST(XML_CQUANT_PLUS); +#undef MYCONST + + /* initialize pyexpat dispatch table */ + capi.size = sizeof(capi); + capi.magic = PyExpat_CAPI_MAGIC; + capi.MAJOR_VERSION = XML_MAJOR_VERSION; + capi.MINOR_VERSION = XML_MINOR_VERSION; + capi.MICRO_VERSION = XML_MICRO_VERSION; + capi.ErrorString = XML_ErrorString; + capi.GetErrorCode = XML_GetErrorCode; + capi.GetErrorColumnNumber = XML_GetErrorColumnNumber; + capi.GetErrorLineNumber = XML_GetErrorLineNumber; + capi.Parse = XML_Parse; + capi.ParserCreate_MM = XML_ParserCreate_MM; + capi.ParserFree = XML_ParserFree; + capi.SetCharacterDataHandler = XML_SetCharacterDataHandler; + capi.SetCommentHandler = XML_SetCommentHandler; + capi.SetDefaultHandlerExpand = XML_SetDefaultHandlerExpand; + capi.SetElementHandler = XML_SetElementHandler; + capi.SetNamespaceDeclHandler = XML_SetNamespaceDeclHandler; + capi.SetProcessingInstructionHandler = XML_SetProcessingInstructionHandler; + capi.SetUnknownEncodingHandler = XML_SetUnknownEncodingHandler; + capi.SetUserData = XML_SetUserData; + + /* export as cobject */ + capi_object = PyCObject_FromVoidPtr(&capi, NULL); + if (capi_object) + PyModule_AddObject(m, "expat_CAPI", capi_object); +} + +static void +clear_handlers(xmlparseobject *self, int initial) +{ + int i = 0; + PyObject *temp; + + for (; handler_info[i].name != NULL; i++) { + if (initial) + self->handlers[i] = NULL; + else { + temp = self->handlers[i]; + self->handlers[i] = NULL; + Py_XDECREF(temp); + handler_info[i].setter(self->itself, NULL); + } + } +} + +static struct HandlerInfo handler_info[] = { + {"StartElementHandler", + (xmlhandlersetter)XML_SetStartElementHandler, + (xmlhandler)my_StartElementHandler}, + {"EndElementHandler", + (xmlhandlersetter)XML_SetEndElementHandler, + (xmlhandler)my_EndElementHandler}, + {"ProcessingInstructionHandler", + (xmlhandlersetter)XML_SetProcessingInstructionHandler, + (xmlhandler)my_ProcessingInstructionHandler}, + {"CharacterDataHandler", + (xmlhandlersetter)XML_SetCharacterDataHandler, + (xmlhandler)my_CharacterDataHandler}, + {"UnparsedEntityDeclHandler", + (xmlhandlersetter)XML_SetUnparsedEntityDeclHandler, + (xmlhandler)my_UnparsedEntityDeclHandler}, + {"NotationDeclHandler", + (xmlhandlersetter)XML_SetNotationDeclHandler, + (xmlhandler)my_NotationDeclHandler}, + {"StartNamespaceDeclHandler", + (xmlhandlersetter)XML_SetStartNamespaceDeclHandler, + (xmlhandler)my_StartNamespaceDeclHandler}, + {"EndNamespaceDeclHandler", + (xmlhandlersetter)XML_SetEndNamespaceDeclHandler, + (xmlhandler)my_EndNamespaceDeclHandler}, + {"CommentHandler", + (xmlhandlersetter)XML_SetCommentHandler, + (xmlhandler)my_CommentHandler}, + {"StartCdataSectionHandler", + (xmlhandlersetter)XML_SetStartCdataSectionHandler, + (xmlhandler)my_StartCdataSectionHandler}, + {"EndCdataSectionHandler", + (xmlhandlersetter)XML_SetEndCdataSectionHandler, + (xmlhandler)my_EndCdataSectionHandler}, + {"DefaultHandler", + (xmlhandlersetter)XML_SetDefaultHandler, + (xmlhandler)my_DefaultHandler}, + {"DefaultHandlerExpand", + (xmlhandlersetter)XML_SetDefaultHandlerExpand, + (xmlhandler)my_DefaultHandlerExpandHandler}, + {"NotStandaloneHandler", + (xmlhandlersetter)XML_SetNotStandaloneHandler, + (xmlhandler)my_NotStandaloneHandler}, + {"ExternalEntityRefHandler", + (xmlhandlersetter)XML_SetExternalEntityRefHandler, + (xmlhandler)my_ExternalEntityRefHandler}, + {"StartDoctypeDeclHandler", + (xmlhandlersetter)XML_SetStartDoctypeDeclHandler, + (xmlhandler)my_StartDoctypeDeclHandler}, + {"EndDoctypeDeclHandler", + (xmlhandlersetter)XML_SetEndDoctypeDeclHandler, + (xmlhandler)my_EndDoctypeDeclHandler}, + {"EntityDeclHandler", + (xmlhandlersetter)XML_SetEntityDeclHandler, + (xmlhandler)my_EntityDeclHandler}, + {"XmlDeclHandler", + (xmlhandlersetter)XML_SetXmlDeclHandler, + (xmlhandler)my_XmlDeclHandler}, + {"ElementDeclHandler", + (xmlhandlersetter)XML_SetElementDeclHandler, + (xmlhandler)my_ElementDeclHandler}, + {"AttlistDeclHandler", + (xmlhandlersetter)XML_SetAttlistDeclHandler, + (xmlhandler)my_AttlistDeclHandler}, +#if XML_COMBINED_VERSION >= 19504 + {"SkippedEntityHandler", + (xmlhandlersetter)XML_SetSkippedEntityHandler, + (xmlhandler)my_SkippedEntityHandler}, +#endif + + {NULL, NULL, NULL} /* sentinel */ +}; diff --git a/sys/src/cmd/python/Modules/python.c b/sys/src/cmd/python/Modules/python.c new file mode 100644 index 000000000..2739b8b11 --- /dev/null +++ b/sys/src/cmd/python/Modules/python.c @@ -0,0 +1,24 @@ +/* Minimal main program -- everything is loaded from the library */ + +#include "Python.h" + +#ifdef __FreeBSD__ +#include <floatingpoint.h> +#endif + +int +main(int argc, char **argv) +{ + /* 754 requires that FP exceptions run in "no stop" mode by default, + * and until C vendors implement C99's ways to control FP exceptions, + * Python requires non-stop mode. Alas, some platforms enable FP + * exceptions by default. Here we disable them. + */ +#ifdef __FreeBSD__ + fp_except_t m; + + m = fpgetmask(); + fpsetmask(m & ~FP_X_OFL); +#endif + return Py_Main(argc, argv); +} diff --git a/sys/src/cmd/python/Modules/readline.c b/sys/src/cmd/python/Modules/readline.c new file mode 100644 index 000000000..853874be2 --- /dev/null +++ b/sys/src/cmd/python/Modules/readline.c @@ -0,0 +1,941 @@ +/* This module makes GNU readline available to Python. It has ideas + * contributed by Lee Busby, LLNL, and William Magro, Cornell Theory + * Center. The completer interface was inspired by Lele Gaifax. More + * recently, it was largely rewritten by Guido van Rossum. + */ + +/* Standard definitions */ +#include "Python.h" +#include <setjmp.h> +#include <signal.h> +#include <errno.h> +#include <sys/time.h> + +#if defined(HAVE_SETLOCALE) +/* GNU readline() mistakenly sets the LC_CTYPE locale. + * This is evil. Only the user or the app's main() should do this! + * We must save and restore the locale around the rl_initialize() call. + */ +#define SAVE_LOCALE +#include <locale.h> +#endif + +#ifdef SAVE_LOCALE +# define RESTORE_LOCALE(sl) { setlocale(LC_CTYPE, sl); free(sl); } +#else +# define RESTORE_LOCALE(sl) +#endif + +/* GNU readline definitions */ +#undef HAVE_CONFIG_H /* Else readline/chardefs.h includes strings.h */ +#include <readline/readline.h> +#include <readline/history.h> + +#ifdef HAVE_RL_COMPLETION_MATCHES +#define completion_matches(x, y) \ + rl_completion_matches((x), ((rl_compentry_func_t *)(y))) +#endif + + +/* Exported function to send one line to readline's init file parser */ + +static PyObject * +parse_and_bind(PyObject *self, PyObject *args) +{ + char *s, *copy; + if (!PyArg_ParseTuple(args, "s:parse_and_bind", &s)) + return NULL; + /* Make a copy -- rl_parse_and_bind() modifies its argument */ + /* Bernard Herzog */ + copy = malloc(1 + strlen(s)); + if (copy == NULL) + return PyErr_NoMemory(); + strcpy(copy, s); + rl_parse_and_bind(copy); + free(copy); /* Free the copy */ + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_parse_and_bind, +"parse_and_bind(string) -> None\n\ +Parse and execute single line of a readline init file."); + + +/* Exported function to parse a readline init file */ + +static PyObject * +read_init_file(PyObject *self, PyObject *args) +{ + char *s = NULL; + if (!PyArg_ParseTuple(args, "|z:read_init_file", &s)) + return NULL; + errno = rl_read_init_file(s); + if (errno) + return PyErr_SetFromErrno(PyExc_IOError); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_read_init_file, +"read_init_file([filename]) -> None\n\ +Parse a readline initialization file.\n\ +The default filename is the last filename used."); + + +/* Exported function to load a readline history file */ + +static PyObject * +read_history_file(PyObject *self, PyObject *args) +{ + char *s = NULL; + if (!PyArg_ParseTuple(args, "|z:read_history_file", &s)) + return NULL; + errno = read_history(s); + if (errno) + return PyErr_SetFromErrno(PyExc_IOError); + Py_INCREF(Py_None); + return Py_None; +} + +static int _history_length = -1; /* do not truncate history by default */ +PyDoc_STRVAR(doc_read_history_file, +"read_history_file([filename]) -> None\n\ +Load a readline history file.\n\ +The default filename is ~/.history."); + + +/* Exported function to save a readline history file */ + +static PyObject * +write_history_file(PyObject *self, PyObject *args) +{ + char *s = NULL; + if (!PyArg_ParseTuple(args, "|z:write_history_file", &s)) + return NULL; + errno = write_history(s); + if (!errno && _history_length >= 0) + history_truncate_file(s, _history_length); + if (errno) + return PyErr_SetFromErrno(PyExc_IOError); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_write_history_file, +"write_history_file([filename]) -> None\n\ +Save a readline history file.\n\ +The default filename is ~/.history."); + + +/* Set history length */ + +static PyObject* +set_history_length(PyObject *self, PyObject *args) +{ + int length = _history_length; + if (!PyArg_ParseTuple(args, "i:set_history_length", &length)) + return NULL; + _history_length = length; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(set_history_length_doc, +"set_history_length(length) -> None\n\ +set the maximal number of items which will be written to\n\ +the history file. A negative length is used to inhibit\n\ +history truncation."); + + +/* Get history length */ + +static PyObject* +get_history_length(PyObject *self, PyObject *noarg) +{ + return PyInt_FromLong(_history_length); +} + +PyDoc_STRVAR(get_history_length_doc, +"get_history_length() -> int\n\ +return the maximum number of items that will be written to\n\ +the history file."); + + +/* Generic hook function setter */ + +static PyObject * +set_hook(const char *funcname, PyObject **hook_var, PyObject *args) +{ + PyObject *function = Py_None; + char buf[80]; + PyOS_snprintf(buf, sizeof(buf), "|O:set_%.50s", funcname); + if (!PyArg_ParseTuple(args, buf, &function)) + return NULL; + if (function == Py_None) { + Py_XDECREF(*hook_var); + *hook_var = NULL; + } + else if (PyCallable_Check(function)) { + PyObject *tmp = *hook_var; + Py_INCREF(function); + *hook_var = function; + Py_XDECREF(tmp); + } + else { + PyOS_snprintf(buf, sizeof(buf), + "set_%.50s(func): argument not callable", + funcname); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + + +/* Exported functions to specify hook functions in Python */ + +static PyObject *startup_hook = NULL; + +#ifdef HAVE_RL_PRE_INPUT_HOOK +static PyObject *pre_input_hook = NULL; +#endif + +static PyObject * +set_startup_hook(PyObject *self, PyObject *args) +{ + return set_hook("startup_hook", &startup_hook, args); +} + +PyDoc_STRVAR(doc_set_startup_hook, +"set_startup_hook([function]) -> None\n\ +Set or remove the startup_hook function.\n\ +The function is called with no arguments just\n\ +before readline prints the first prompt."); + + +#ifdef HAVE_RL_PRE_INPUT_HOOK + +/* Set pre-input hook */ + +static PyObject * +set_pre_input_hook(PyObject *self, PyObject *args) +{ + return set_hook("pre_input_hook", &pre_input_hook, args); +} + +PyDoc_STRVAR(doc_set_pre_input_hook, +"set_pre_input_hook([function]) -> None\n\ +Set or remove the pre_input_hook function.\n\ +The function is called with no arguments after the first prompt\n\ +has been printed and just before readline starts reading input\n\ +characters."); + +#endif + + +/* Exported function to specify a word completer in Python */ + +static PyObject *completer = NULL; + +static PyObject *begidx = NULL; +static PyObject *endidx = NULL; + + +/* Get the beginning index for the scope of the tab-completion */ + +static PyObject * +get_begidx(PyObject *self, PyObject *noarg) +{ + Py_INCREF(begidx); + return begidx; +} + +PyDoc_STRVAR(doc_get_begidx, +"get_begidx() -> int\n\ +get the beginning index of the readline tab-completion scope"); + + +/* Get the ending index for the scope of the tab-completion */ + +static PyObject * +get_endidx(PyObject *self, PyObject *noarg) +{ + Py_INCREF(endidx); + return endidx; +} + +PyDoc_STRVAR(doc_get_endidx, +"get_endidx() -> int\n\ +get the ending index of the readline tab-completion scope"); + + +/* Set the tab-completion word-delimiters that readline uses */ + +static PyObject * +set_completer_delims(PyObject *self, PyObject *args) +{ + char *break_chars; + + if(!PyArg_ParseTuple(args, "s:set_completer_delims", &break_chars)) { + return NULL; + } + free((void*)rl_completer_word_break_characters); + rl_completer_word_break_characters = strdup(break_chars); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_set_completer_delims, +"set_completer_delims(string) -> None\n\ +set the readline word delimiters for tab-completion"); + +static PyObject * +py_remove_history(PyObject *self, PyObject *args) +{ + int entry_number; + HIST_ENTRY *entry; + + if (!PyArg_ParseTuple(args, "i:remove_history", &entry_number)) + return NULL; + if (entry_number < 0) { + PyErr_SetString(PyExc_ValueError, + "History index cannot be negative"); + return NULL; + } + entry = remove_history(entry_number); + if (!entry) { + PyErr_Format(PyExc_ValueError, + "No history item at position %d", + entry_number); + return NULL; + } + /* free memory allocated for the history entry */ + if (entry->line) + free(entry->line); + if (entry->data) + free(entry->data); + free(entry); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_remove_history, +"remove_history_item(pos) -> None\n\ +remove history item given by its position"); + +static PyObject * +py_replace_history(PyObject *self, PyObject *args) +{ + int entry_number; + char *line; + HIST_ENTRY *old_entry; + + if (!PyArg_ParseTuple(args, "is:replace_history", &entry_number, &line)) { + return NULL; + } + if (entry_number < 0) { + PyErr_SetString(PyExc_ValueError, + "History index cannot be negative"); + return NULL; + } + old_entry = replace_history_entry(entry_number, line, (void *)NULL); + if (!old_entry) { + PyErr_Format(PyExc_ValueError, + "No history item at position %d", + entry_number); + return NULL; + } + /* free memory allocated for the old history entry */ + if (old_entry->line) + free(old_entry->line); + if (old_entry->data) + free(old_entry->data); + free(old_entry); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_replace_history, +"replace_history_item(pos, line) -> None\n\ +replaces history item given by its position with contents of line"); + +/* Add a line to the history buffer */ + +static PyObject * +py_add_history(PyObject *self, PyObject *args) +{ + char *line; + + if(!PyArg_ParseTuple(args, "s:add_history", &line)) { + return NULL; + } + add_history(line); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_add_history, +"add_history(string) -> None\n\ +add a line to the history buffer"); + + +/* Get the tab-completion word-delimiters that readline uses */ + +static PyObject * +get_completer_delims(PyObject *self, PyObject *noarg) +{ + return PyString_FromString(rl_completer_word_break_characters); +} + +PyDoc_STRVAR(doc_get_completer_delims, +"get_completer_delims() -> string\n\ +get the readline word delimiters for tab-completion"); + + +/* Set the completer function */ + +static PyObject * +set_completer(PyObject *self, PyObject *args) +{ + return set_hook("completer", &completer, args); +} + +PyDoc_STRVAR(doc_set_completer, +"set_completer([function]) -> None\n\ +Set or remove the completer function.\n\ +The function is called as function(text, state),\n\ +for state in 0, 1, 2, ..., until it returns a non-string.\n\ +It should return the next possible completion starting with 'text'."); + + +static PyObject * +get_completer(PyObject *self, PyObject *noargs) +{ + if (completer == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + Py_INCREF(completer); + return completer; +} + +PyDoc_STRVAR(doc_get_completer, +"get_completer() -> function\n\ +\n\ +Returns current completer function."); + +/* Exported function to get any element of history */ + +static PyObject * +get_history_item(PyObject *self, PyObject *args) +{ + int idx = 0; + HIST_ENTRY *hist_ent; + + if (!PyArg_ParseTuple(args, "i:index", &idx)) + return NULL; + if ((hist_ent = history_get(idx))) + return PyString_FromString(hist_ent->line); + else { + Py_INCREF(Py_None); + return Py_None; + } +} + +PyDoc_STRVAR(doc_get_history_item, +"get_history_item() -> string\n\ +return the current contents of history item at index."); + + +/* Exported function to get current length of history */ + +static PyObject * +get_current_history_length(PyObject *self, PyObject *noarg) +{ + HISTORY_STATE *hist_st; + + hist_st = history_get_history_state(); + return PyInt_FromLong(hist_st ? (long) hist_st->length : (long) 0); +} + +PyDoc_STRVAR(doc_get_current_history_length, +"get_current_history_length() -> integer\n\ +return the current (not the maximum) length of history."); + + +/* Exported function to read the current line buffer */ + +static PyObject * +get_line_buffer(PyObject *self, PyObject *noarg) +{ + return PyString_FromString(rl_line_buffer); +} + +PyDoc_STRVAR(doc_get_line_buffer, +"get_line_buffer() -> string\n\ +return the current contents of the line buffer."); + + +#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER + +/* Exported function to clear the current history */ + +static PyObject * +py_clear_history(PyObject *self, PyObject *noarg) +{ + clear_history(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_clear_history, +"clear_history() -> None\n\ +Clear the current readline history."); +#endif + + +/* Exported function to insert text into the line buffer */ + +static PyObject * +insert_text(PyObject *self, PyObject *args) +{ + char *s; + if (!PyArg_ParseTuple(args, "s:insert_text", &s)) + return NULL; + rl_insert_text(s); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_insert_text, +"insert_text(string) -> None\n\ +Insert text into the command line."); + + +/* Redisplay the line buffer */ + +static PyObject * +redisplay(PyObject *self, PyObject *noarg) +{ + rl_redisplay(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_redisplay, +"redisplay() -> None\n\ +Change what's displayed on the screen to reflect the current\n\ +contents of the line buffer."); + + +/* Table of functions exported by the module */ + +static struct PyMethodDef readline_methods[] = +{ + {"parse_and_bind", parse_and_bind, METH_VARARGS, doc_parse_and_bind}, + {"get_line_buffer", get_line_buffer, METH_NOARGS, doc_get_line_buffer}, + {"insert_text", insert_text, METH_VARARGS, doc_insert_text}, + {"redisplay", redisplay, METH_NOARGS, doc_redisplay}, + {"read_init_file", read_init_file, METH_VARARGS, doc_read_init_file}, + {"read_history_file", read_history_file, + METH_VARARGS, doc_read_history_file}, + {"write_history_file", write_history_file, + METH_VARARGS, doc_write_history_file}, + {"get_history_item", get_history_item, + METH_VARARGS, doc_get_history_item}, + {"get_current_history_length", (PyCFunction)get_current_history_length, + METH_NOARGS, doc_get_current_history_length}, + {"set_history_length", set_history_length, + METH_VARARGS, set_history_length_doc}, + {"get_history_length", get_history_length, + METH_NOARGS, get_history_length_doc}, + {"set_completer", set_completer, METH_VARARGS, doc_set_completer}, + {"get_completer", get_completer, METH_NOARGS, doc_get_completer}, + {"get_begidx", get_begidx, METH_NOARGS, doc_get_begidx}, + {"get_endidx", get_endidx, METH_NOARGS, doc_get_endidx}, + + {"set_completer_delims", set_completer_delims, + METH_VARARGS, doc_set_completer_delims}, + {"add_history", py_add_history, METH_VARARGS, doc_add_history}, + {"remove_history_item", py_remove_history, METH_VARARGS, doc_remove_history}, + {"replace_history_item", py_replace_history, METH_VARARGS, doc_replace_history}, + {"get_completer_delims", get_completer_delims, + METH_NOARGS, doc_get_completer_delims}, + + {"set_startup_hook", set_startup_hook, + METH_VARARGS, doc_set_startup_hook}, +#ifdef HAVE_RL_PRE_INPUT_HOOK + {"set_pre_input_hook", set_pre_input_hook, + METH_VARARGS, doc_set_pre_input_hook}, +#endif +#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER + {"clear_history", py_clear_history, METH_NOARGS, doc_clear_history}, +#endif + {0, 0} +}; + + +/* C function to call the Python hooks. */ + +static int +on_hook(PyObject *func) +{ + int result = 0; + if (func != NULL) { + PyObject *r; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif + r = PyObject_CallFunction(func, NULL); + if (r == NULL) + goto error; + if (r == Py_None) + result = 0; + else { + result = PyInt_AsLong(r); + if (result == -1 && PyErr_Occurred()) + goto error; + } + Py_DECREF(r); + goto done; + error: + PyErr_Clear(); + Py_XDECREF(r); + done: +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return result; + } + return result; +} + +static int +on_startup_hook(void) +{ + return on_hook(startup_hook); +} + +#ifdef HAVE_RL_PRE_INPUT_HOOK +static int +on_pre_input_hook(void) +{ + return on_hook(pre_input_hook); +} +#endif + + +/* C function to call the Python completer. */ + +static char * +on_completion(char *text, int state) +{ + char *result = NULL; + if (completer != NULL) { + PyObject *r; +#ifdef WITH_THREAD + PyGILState_STATE gilstate = PyGILState_Ensure(); +#endif + rl_attempted_completion_over = 1; + r = PyObject_CallFunction(completer, "si", text, state); + if (r == NULL) + goto error; + if (r == Py_None) { + result = NULL; + } + else { + char *s = PyString_AsString(r); + if (s == NULL) + goto error; + result = strdup(s); + } + Py_DECREF(r); + goto done; + error: + PyErr_Clear(); + Py_XDECREF(r); + done: +#ifdef WITH_THREAD + PyGILState_Release(gilstate); +#endif + return result; + } + return result; +} + + +/* A more flexible constructor that saves the "begidx" and "endidx" + * before calling the normal completer */ + +static char ** +flex_complete(char *text, int start, int end) +{ + Py_XDECREF(begidx); + Py_XDECREF(endidx); + begidx = PyInt_FromLong((long) start); + endidx = PyInt_FromLong((long) end); + return completion_matches(text, *on_completion); +} + + +/* Helper to initialize GNU readline properly. */ + +static void +setup_readline(void) +{ +#ifdef SAVE_LOCALE + char *saved_locale = strdup(setlocale(LC_CTYPE, NULL)); + if (!saved_locale) + Py_FatalError("not enough memory to save locale"); +#endif + + using_history(); + + rl_readline_name = "python"; +#if defined(PYOS_OS2) && defined(PYCC_GCC) + /* Allow $if term= in .inputrc to work */ + rl_terminal_name = getenv("TERM"); +#endif + /* Force rebind of TAB to insert-tab */ + rl_bind_key('\t', rl_insert); + /* Bind both ESC-TAB and ESC-ESC to the completion function */ + rl_bind_key_in_map ('\t', rl_complete, emacs_meta_keymap); + rl_bind_key_in_map ('\033', rl_complete, emacs_meta_keymap); + /* Set our hook functions */ + rl_startup_hook = (Function *)on_startup_hook; +#ifdef HAVE_RL_PRE_INPUT_HOOK + rl_pre_input_hook = (Function *)on_pre_input_hook; +#endif + /* Set our completion function */ + rl_attempted_completion_function = (CPPFunction *)flex_complete; + /* Set Python word break characters */ + rl_completer_word_break_characters = + strdup(" \t\n`~!@#$%^&*()-=+[{]}\\|;:'\",<>/?"); + /* All nonalphanums except '.' */ +#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER + rl_completion_append_character ='\0'; +#endif + + begidx = PyInt_FromLong(0L); + endidx = PyInt_FromLong(0L); + /* Initialize (allows .inputrc to override) + * + * XXX: A bug in the readline-2.2 library causes a memory leak + * inside this function. Nothing we can do about it. + */ + rl_initialize(); + + RESTORE_LOCALE(saved_locale) +} + +/* Wrapper around GNU readline that handles signals differently. */ + + +#if defined(HAVE_RL_CALLBACK) && defined(HAVE_SELECT) + +static char *completed_input_string; +static void +rlhandler(char *text) +{ + completed_input_string = text; + rl_callback_handler_remove(); +} + +extern PyThreadState* _PyOS_ReadlineTState; + +static char * +readline_until_enter_or_signal(char *prompt, int *signal) +{ + char * not_done_reading = ""; + fd_set selectset; + + *signal = 0; +#ifdef HAVE_RL_CATCH_SIGNAL + rl_catch_signals = 0; +#endif + + rl_callback_handler_install (prompt, rlhandler); + FD_ZERO(&selectset); + + completed_input_string = not_done_reading; + + while (completed_input_string == not_done_reading) { + int has_input = 0; + + while (!has_input) + { struct timeval timeout = {0, 100000}; /* 0.1 seconds */ + + /* [Bug #1552726] Only limit the pause if an input hook has been + defined. */ + struct timeval *timeoutp = NULL; + if (PyOS_InputHook) + timeoutp = &timeout; + FD_SET(fileno(rl_instream), &selectset); + /* select resets selectset if no input was available */ + has_input = select(fileno(rl_instream) + 1, &selectset, + NULL, NULL, timeoutp); + if(PyOS_InputHook) PyOS_InputHook(); + } + + if(has_input > 0) { + rl_callback_read_char(); + } + else if (errno == EINTR) { + int s; +#ifdef WITH_THREAD + PyEval_RestoreThread(_PyOS_ReadlineTState); +#endif + s = PyErr_CheckSignals(); +#ifdef WITH_THREAD + PyEval_SaveThread(); +#endif + if (s < 0) { + rl_free_line_state(); + rl_cleanup_after_signal(); + rl_callback_handler_remove(); + *signal = 1; + completed_input_string = NULL; + } + } + } + + return completed_input_string; +} + + +#else + +/* Interrupt handler */ + +static jmp_buf jbuf; + +/* ARGSUSED */ +static void +onintr(int sig) +{ + longjmp(jbuf, 1); +} + + +static char * +readline_until_enter_or_signal(char *prompt, int *signal) +{ + PyOS_sighandler_t old_inthandler; + char *p; + + *signal = 0; + + old_inthandler = PyOS_setsig(SIGINT, onintr); + if (setjmp(jbuf)) { +#ifdef HAVE_SIGRELSE + /* This seems necessary on SunOS 4.1 (Rasmus Hahn) */ + sigrelse(SIGINT); +#endif + PyOS_setsig(SIGINT, old_inthandler); + *signal = 1; + return NULL; + } + rl_event_hook = PyOS_InputHook; + p = readline(prompt); + PyOS_setsig(SIGINT, old_inthandler); + + return p; +} +#endif /*defined(HAVE_RL_CALLBACK) && defined(HAVE_SELECT) */ + + +static char * +call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) +{ + size_t n; + char *p, *q; + int signal; + +#ifdef SAVE_LOCALE + char *saved_locale = strdup(setlocale(LC_CTYPE, NULL)); + if (!saved_locale) + Py_FatalError("not enough memory to save locale"); + setlocale(LC_CTYPE, ""); +#endif + + if (sys_stdin != rl_instream || sys_stdout != rl_outstream) { + rl_instream = sys_stdin; + rl_outstream = sys_stdout; +#ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER + rl_prep_terminal (1); +#endif + } + + p = readline_until_enter_or_signal(prompt, &signal); + + /* we got an interrupt signal */ + if (signal) { + RESTORE_LOCALE(saved_locale) + return NULL; + } + + /* We got an EOF, return a empty string. */ + if (p == NULL) { + p = PyMem_Malloc(1); + if (p != NULL) + *p = '\0'; + RESTORE_LOCALE(saved_locale) + return p; + } + + /* we have a valid line */ + n = strlen(p); + if (n > 0) { + char *line; + HISTORY_STATE *state = history_get_history_state(); + if (state->length > 0) + line = history_get(state->length)->line; + else + line = ""; + if (strcmp(p, line)) + add_history(p); + /* the history docs don't say so, but the address of state + changes each time history_get_history_state is called + which makes me think it's freshly malloc'd memory... + on the other hand, the address of the last line stays the + same as long as history isn't extended, so it appears to + be malloc'd but managed by the history package... */ + free(state); + } + /* Copy the malloc'ed buffer into a PyMem_Malloc'ed one and + release the original. */ + q = p; + p = PyMem_Malloc(n+2); + if (p != NULL) { + strncpy(p, q, n); + p[n] = '\n'; + p[n+1] = '\0'; + } + free(q); + RESTORE_LOCALE(saved_locale) + return p; +} + + +/* Initialize the module */ + +PyDoc_STRVAR(doc_module, +"Importing this module enables command line editing using GNU readline."); + +PyMODINIT_FUNC +initreadline(void) +{ + PyObject *m; + + m = Py_InitModule4("readline", readline_methods, doc_module, + (PyObject *)NULL, PYTHON_API_VERSION); + if (m == NULL) + return; + + PyOS_ReadlineFunctionPointer = call_readline; + setup_readline(); +} diff --git a/sys/src/cmd/python/Modules/resource.c b/sys/src/cmd/python/Modules/resource.c new file mode 100644 index 000000000..fe6f3b6a2 --- /dev/null +++ b/sys/src/cmd/python/Modules/resource.c @@ -0,0 +1,325 @@ + +#include "Python.h" +#include "structseq.h" +#include <sys/resource.h> +#include <sys/time.h> +#include <string.h> +#include <errno.h> +/* for sysconf */ +#if defined(HAVE_UNISTD_H) +#include <unistd.h> +#endif + +/* On some systems, these aren't in any header file. + On others they are, with inconsistent prototypes. + We declare the (default) return type, to shut up gcc -Wall; + but we can't declare the prototype, to avoid errors + when the header files declare it different. + Worse, on some Linuxes, getpagesize() returns a size_t... */ + +#define doubletime(TV) ((double)(TV).tv_sec + (TV).tv_usec * 0.000001) + +static PyObject *ResourceError; + +PyDoc_STRVAR(struct_rusage__doc__, +"struct_rusage: Result from getrusage.\n\n" +"This object may be accessed either as a tuple of\n" +" (utime,stime,maxrss,ixrss,idrss,isrss,minflt,majflt,\n" +" nswap,inblock,oublock,msgsnd,msgrcv,nsignals,nvcsw,nivcsw)\n" +"or via the attributes ru_utime, ru_stime, ru_maxrss, and so on."); + +static PyStructSequence_Field struct_rusage_fields[] = { + {"ru_utime", "user time used"}, + {"ru_stime", "system time used"}, + {"ru_maxrss", "max. resident set size"}, + {"ru_ixrss", "shared memory size"}, + {"ru_idrss", "unshared data size"}, + {"ru_isrss", "unshared stack size"}, + {"ru_minflt", "page faults not requiring I/O"}, + {"ru_majflt", "page faults requiring I/O"}, + {"ru_nswap", "number of swap outs"}, + {"ru_inblock", "block input operations"}, + {"ru_oublock", "block output operations"}, + {"ru_msgsnd", "IPC messages sent"}, + {"ru_msgrcv", "IPC messages received"}, + {"ru_nsignals", "signals received"}, + {"ru_nvcsw", "voluntary context switches"}, + {"ru_nivcsw", "involuntary context switches"}, + {0} +}; + +static PyStructSequence_Desc struct_rusage_desc = { + "resource.struct_rusage", /* name */ + struct_rusage__doc__, /* doc */ + struct_rusage_fields, /* fields */ + 16 /* n_in_sequence */ +}; + +static int initialized; +static PyTypeObject StructRUsageType; + +static PyObject * +resource_getrusage(PyObject *self, PyObject *args) +{ + int who; + struct rusage ru; + PyObject *result; + + if (!PyArg_ParseTuple(args, "i:getrusage", &who)) + return NULL; + + if (getrusage(who, &ru) == -1) { + if (errno == EINVAL) { + PyErr_SetString(PyExc_ValueError, + "invalid who parameter"); + return NULL; + } + PyErr_SetFromErrno(ResourceError); + return NULL; + } + + result = PyStructSequence_New(&StructRUsageType); + if (!result) + return NULL; + + PyStructSequence_SET_ITEM(result, 0, + PyFloat_FromDouble(doubletime(ru.ru_utime))); + PyStructSequence_SET_ITEM(result, 1, + PyFloat_FromDouble(doubletime(ru.ru_stime))); + PyStructSequence_SET_ITEM(result, 2, PyInt_FromLong(ru.ru_maxrss)); + PyStructSequence_SET_ITEM(result, 3, PyInt_FromLong(ru.ru_ixrss)); + PyStructSequence_SET_ITEM(result, 4, PyInt_FromLong(ru.ru_idrss)); + PyStructSequence_SET_ITEM(result, 5, PyInt_FromLong(ru.ru_isrss)); + PyStructSequence_SET_ITEM(result, 6, PyInt_FromLong(ru.ru_minflt)); + PyStructSequence_SET_ITEM(result, 7, PyInt_FromLong(ru.ru_majflt)); + PyStructSequence_SET_ITEM(result, 8, PyInt_FromLong(ru.ru_nswap)); + PyStructSequence_SET_ITEM(result, 9, PyInt_FromLong(ru.ru_inblock)); + PyStructSequence_SET_ITEM(result, 10, PyInt_FromLong(ru.ru_oublock)); + PyStructSequence_SET_ITEM(result, 11, PyInt_FromLong(ru.ru_msgsnd)); + PyStructSequence_SET_ITEM(result, 12, PyInt_FromLong(ru.ru_msgrcv)); + PyStructSequence_SET_ITEM(result, 13, PyInt_FromLong(ru.ru_nsignals)); + PyStructSequence_SET_ITEM(result, 14, PyInt_FromLong(ru.ru_nvcsw)); + PyStructSequence_SET_ITEM(result, 15, PyInt_FromLong(ru.ru_nivcsw)); + + if (PyErr_Occurred()) { + Py_DECREF(result); + return NULL; + } + + return result; +} + + +static PyObject * +resource_getrlimit(PyObject *self, PyObject *args) +{ + struct rlimit rl; + int resource; + + if (!PyArg_ParseTuple(args, "i:getrlimit", &resource)) + return NULL; + + if (resource < 0 || resource >= RLIM_NLIMITS) { + PyErr_SetString(PyExc_ValueError, + "invalid resource specified"); + return NULL; + } + + if (getrlimit(resource, &rl) == -1) { + PyErr_SetFromErrno(ResourceError); + return NULL; + } + +#if defined(HAVE_LONG_LONG) + if (sizeof(rl.rlim_cur) > sizeof(long)) { + return Py_BuildValue("LL", + (PY_LONG_LONG) rl.rlim_cur, + (PY_LONG_LONG) rl.rlim_max); + } +#endif + return Py_BuildValue("ll", (long) rl.rlim_cur, (long) rl.rlim_max); +} + +static PyObject * +resource_setrlimit(PyObject *self, PyObject *args) +{ + struct rlimit rl; + int resource; + PyObject *curobj, *maxobj; + + if (!PyArg_ParseTuple(args, "i(OO):setrlimit", + &resource, &curobj, &maxobj)) + return NULL; + + if (resource < 0 || resource >= RLIM_NLIMITS) { + PyErr_SetString(PyExc_ValueError, + "invalid resource specified"); + return NULL; + } + +#if !defined(HAVE_LARGEFILE_SUPPORT) + rl.rlim_cur = PyInt_AsLong(curobj); + if (rl.rlim_cur == -1 && PyErr_Occurred()) + return NULL; + rl.rlim_max = PyInt_AsLong(maxobj); + if (rl.rlim_max == -1 && PyErr_Occurred()) + return NULL; +#else + /* The limits are probably bigger than a long */ + rl.rlim_cur = PyLong_Check(curobj) ? + PyLong_AsLongLong(curobj) : PyInt_AsLong(curobj); + if (rl.rlim_cur == -1 && PyErr_Occurred()) + return NULL; + rl.rlim_max = PyLong_Check(maxobj) ? + PyLong_AsLongLong(maxobj) : PyInt_AsLong(maxobj); + if (rl.rlim_max == -1 && PyErr_Occurred()) + return NULL; +#endif + + rl.rlim_cur = rl.rlim_cur & RLIM_INFINITY; + rl.rlim_max = rl.rlim_max & RLIM_INFINITY; + if (setrlimit(resource, &rl) == -1) { + if (errno == EINVAL) + PyErr_SetString(PyExc_ValueError, + "current limit exceeds maximum limit"); + else if (errno == EPERM) + PyErr_SetString(PyExc_ValueError, + "not allowed to raise maximum limit"); + else + PyErr_SetFromErrno(ResourceError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +resource_getpagesize(PyObject *self, PyObject *unused) +{ + long pagesize = 0; +#if defined(HAVE_GETPAGESIZE) + pagesize = getpagesize(); +#elif defined(HAVE_SYSCONF) +#if defined(_SC_PAGE_SIZE) + pagesize = sysconf(_SC_PAGE_SIZE); +#else + /* Irix 5.3 has _SC_PAGESIZE, but not _SC_PAGE_SIZE */ + pagesize = sysconf(_SC_PAGESIZE); +#endif +#endif + return Py_BuildValue("i", pagesize); + +} + +/* List of functions */ + +static struct PyMethodDef +resource_methods[] = { + {"getrusage", resource_getrusage, METH_VARARGS}, + {"getrlimit", resource_getrlimit, METH_VARARGS}, + {"setrlimit", resource_setrlimit, METH_VARARGS}, + {"getpagesize", resource_getpagesize, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + + +/* Module initialization */ + +PyMODINIT_FUNC +initresource(void) +{ + PyObject *m, *v; + + /* Create the module and add the functions */ + m = Py_InitModule("resource", resource_methods); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + if (ResourceError == NULL) { + ResourceError = PyErr_NewException("resource.error", + NULL, NULL); + } + Py_INCREF(ResourceError); + PyModule_AddObject(m, "error", ResourceError); + if (!initialized) + PyStructSequence_InitType(&StructRUsageType, + &struct_rusage_desc); + Py_INCREF(&StructRUsageType); + PyModule_AddObject(m, "struct_rusage", + (PyObject*) &StructRUsageType); + + /* insert constants */ +#ifdef RLIMIT_CPU + PyModule_AddIntConstant(m, "RLIMIT_CPU", RLIMIT_CPU); +#endif + +#ifdef RLIMIT_FSIZE + PyModule_AddIntConstant(m, "RLIMIT_FSIZE", RLIMIT_FSIZE); +#endif + +#ifdef RLIMIT_DATA + PyModule_AddIntConstant(m, "RLIMIT_DATA", RLIMIT_DATA); +#endif + +#ifdef RLIMIT_STACK + PyModule_AddIntConstant(m, "RLIMIT_STACK", RLIMIT_STACK); +#endif + +#ifdef RLIMIT_CORE + PyModule_AddIntConstant(m, "RLIMIT_CORE", RLIMIT_CORE); +#endif + +#ifdef RLIMIT_NOFILE + PyModule_AddIntConstant(m, "RLIMIT_NOFILE", RLIMIT_NOFILE); +#endif + +#ifdef RLIMIT_OFILE + PyModule_AddIntConstant(m, "RLIMIT_OFILE", RLIMIT_OFILE); +#endif + +#ifdef RLIMIT_VMEM + PyModule_AddIntConstant(m, "RLIMIT_VMEM", RLIMIT_VMEM); +#endif + +#ifdef RLIMIT_AS + PyModule_AddIntConstant(m, "RLIMIT_AS", RLIMIT_AS); +#endif + +#ifdef RLIMIT_RSS + PyModule_AddIntConstant(m, "RLIMIT_RSS", RLIMIT_RSS); +#endif + +#ifdef RLIMIT_NPROC + PyModule_AddIntConstant(m, "RLIMIT_NPROC", RLIMIT_NPROC); +#endif + +#ifdef RLIMIT_MEMLOCK + PyModule_AddIntConstant(m, "RLIMIT_MEMLOCK", RLIMIT_MEMLOCK); +#endif + +#ifdef RUSAGE_SELF + PyModule_AddIntConstant(m, "RUSAGE_SELF", RUSAGE_SELF); +#endif + +#ifdef RUSAGE_CHILDREN + PyModule_AddIntConstant(m, "RUSAGE_CHILDREN", RUSAGE_CHILDREN); +#endif + +#ifdef RUSAGE_BOTH + PyModule_AddIntConstant(m, "RUSAGE_BOTH", RUSAGE_BOTH); +#endif + +#if defined(HAVE_LONG_LONG) + if (sizeof(RLIM_INFINITY) > sizeof(long)) { + v = PyLong_FromLongLong((PY_LONG_LONG) RLIM_INFINITY); + } else +#endif + { + v = PyInt_FromLong((long) RLIM_INFINITY); + } + if (v) { + PyModule_AddObject(m, "RLIM_INFINITY", v); + } + initialized = 1; +} diff --git a/sys/src/cmd/python/Modules/rgbimgmodule.c b/sys/src/cmd/python/Modules/rgbimgmodule.c new file mode 100644 index 000000000..0f9ee71f2 --- /dev/null +++ b/sys/src/cmd/python/Modules/rgbimgmodule.c @@ -0,0 +1,780 @@ +/* + * fastimg - + * Faster reading and writing of image files. + * + * This code should work on machines with any byte order. + * + * Could someone make this run real fast using multiple processors + * or how about using memory mapped files to speed it up? + * + * Paul Haeberli - 1991 + * + * Changed to return sizes. + * Sjoerd Mullender - 1993 + * Changed to incorporate into Python. + * Sjoerd Mullender - 1993 + */ +#include "Python.h" + +#if SIZEOF_INT == 4 +typedef int Py_Int32; +typedef unsigned int Py_UInt32; +#else +#if SIZEOF_LONG == 4 +typedef long Py_Int32; +typedef unsigned long Py_UInt32; +#else +#error "No 4-byte integral type" +#endif +#endif + +#include <string.h> + +/* + * from image.h + * + */ +typedef struct { + unsigned short imagic; /* stuff saved on disk . . */ + unsigned short type; + unsigned short dim; + unsigned short xsize; + unsigned short ysize; + unsigned short zsize; + Py_UInt32 min; + Py_UInt32 max; + Py_UInt32 wastebytes; + char name[80]; + Py_UInt32 colormap; + + Py_Int32 file; /* stuff used in core only */ + unsigned short flags; + short dorev; + short x; + short y; + short z; + short cnt; + unsigned short *ptr; + unsigned short *base; + unsigned short *tmpbuf; + Py_UInt32 offset; + Py_UInt32 rleend; /* for rle images */ + Py_UInt32 *rowstart; /* for rle images */ + Py_Int32 *rowsize; /* for rle images */ +} IMAGE; + +#define IMAGIC 0732 + +#define TYPEMASK 0xff00 +#define BPPMASK 0x00ff +#define ITYPE_VERBATIM 0x0000 +#define ITYPE_RLE 0x0100 +#define ISRLE(type) (((type) & 0xff00) == ITYPE_RLE) +#define ISVERBATIM(type) (((type) & 0xff00) == ITYPE_VERBATIM) +#define BPP(type) ((type) & BPPMASK) +#define RLE(bpp) (ITYPE_RLE | (bpp)) +#define VERBATIM(bpp) (ITYPE_VERBATIM | (bpp)) +/* + * end of image.h stuff + * + */ + +#define RINTLUM (79) +#define GINTLUM (156) +#define BINTLUM (21) + +#define ILUM(r,g,b) ((int)(RINTLUM*(r)+GINTLUM*(g)+BINTLUM*(b))>>8) + +#define OFFSET_R 3 /* this is byte order dependent */ +#define OFFSET_G 2 +#define OFFSET_B 1 +#define OFFSET_A 0 + +#define CHANOFFSET(z) (3-(z)) /* this is byte order dependent */ + +static void expandrow(unsigned char *, unsigned char *, int); +static void setalpha(unsigned char *, int); +static void copybw(Py_Int32 *, int); +static void interleaverow(unsigned char*, unsigned char*, int, int); +static int compressrow(unsigned char *, unsigned char *, int, int); +static void lumrow(unsigned char *, unsigned char *, int); + +#ifdef ADD_TAGS +#define TAGLEN (5) +#else +#define TAGLEN (0) +#endif + +static PyObject *ImgfileError; + +static int reverse_order; + +#ifdef ADD_TAGS +/* + * addlongimgtag - + * this is used to extract image data from core dumps. + * + */ +static void +addlongimgtag(Py_UInt32 *dptr, int xsize, int ysize) +{ + dptr = dptr + (xsize * ysize); + dptr[0] = 0x12345678; + dptr[1] = 0x59493333; + dptr[2] = 0x69434222; + dptr[3] = xsize; + dptr[4] = ysize; +} +#endif + +/* + * byte order independent read/write of shorts and longs. + * + */ +static unsigned short +getshort(FILE *inf) +{ + unsigned char buf[2]; + + fread(buf, 2, 1, inf); + return (buf[0] << 8) + (buf[1] << 0); +} + +static Py_UInt32 +getlong(FILE *inf) +{ + unsigned char buf[4]; + + fread(buf, 4, 1, inf); + return (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0); +} + +static void +putshort(FILE *outf, unsigned short val) +{ + unsigned char buf[2]; + + buf[0] = (val >> 8); + buf[1] = (val >> 0); + fwrite(buf, 2, 1, outf); +} + +static int +putlong(FILE *outf, Py_UInt32 val) +{ + unsigned char buf[4]; + + buf[0] = (unsigned char) (val >> 24); + buf[1] = (unsigned char) (val >> 16); + buf[2] = (unsigned char) (val >> 8); + buf[3] = (unsigned char) (val >> 0); + return (int)fwrite(buf, 4, 1, outf); +} + +static void +readheader(FILE *inf, IMAGE *image) +{ + memset(image ,0, sizeof(IMAGE)); + image->imagic = getshort(inf); + image->type = getshort(inf); + image->dim = getshort(inf); + image->xsize = getshort(inf); + image->ysize = getshort(inf); + image->zsize = getshort(inf); +} + +static int +writeheader(FILE *outf, IMAGE *image) +{ + IMAGE t; + + memset(&t, 0, sizeof(IMAGE)); + fwrite(&t, sizeof(IMAGE), 1, outf); + fseek(outf, 0, SEEK_SET); + putshort(outf, image->imagic); + putshort(outf, image->type); + putshort(outf, image->dim); + putshort(outf, image->xsize); + putshort(outf, image->ysize); + putshort(outf, image->zsize); + putlong(outf, image->min); + putlong(outf, image->max); + putlong(outf, 0); + return (int)fwrite("no name", 8, 1, outf); +} + +static int +writetab(FILE *outf, /*unsigned*/ Py_Int32 *tab, int len) +{ + int r = 0; + + while(len) { + r = putlong(outf, *tab++); + len--; + } + return r; +} + +static void +readtab(FILE *inf, /*unsigned*/ Py_Int32 *tab, int len) +{ + while(len) { + *tab++ = getlong(inf); + len--; + } +} + +/* + * sizeofimage - + * return the xsize and ysize of an iris image file. + * + */ +static PyObject * +sizeofimage(PyObject *self, PyObject *args) +{ + char *name; + IMAGE image; + FILE *inf; + + if (!PyArg_ParseTuple(args, "s:sizeofimage", &name)) + return NULL; + + inf = fopen(name, "rb"); + if (!inf) { + PyErr_SetString(ImgfileError, "can't open image file"); + return NULL; + } + readheader(inf, &image); + fclose(inf); + if (image.imagic != IMAGIC) { + PyErr_SetString(ImgfileError, + "bad magic number in image file"); + return NULL; + } + return Py_BuildValue("(ii)", image.xsize, image.ysize); +} + +/* + * longimagedata - + * read in a B/W RGB or RGBA iris image file and return a + * pointer to an array of longs. + * + */ +static PyObject * +longimagedata(PyObject *self, PyObject *args) +{ + char *name; + unsigned char *base, *lptr; + unsigned char *rledat = NULL, *verdat = NULL; + Py_Int32 *starttab = NULL, *lengthtab = NULL; + FILE *inf = NULL; + IMAGE image; + int y, z, tablen; + int xsize, ysize, zsize; + int bpp, rle, cur, badorder; + int rlebuflen; + PyObject *rv = NULL; + + if (!PyArg_ParseTuple(args, "s:longimagedata", &name)) + return NULL; + + inf = fopen(name,"rb"); + if (!inf) { + PyErr_SetString(ImgfileError, "can't open image file"); + return NULL; + } + readheader(inf,&image); + if (image.imagic != IMAGIC) { + PyErr_SetString(ImgfileError, + "bad magic number in image file"); + goto finally; + } + rle = ISRLE(image.type); + bpp = BPP(image.type); + if (bpp != 1) { + PyErr_SetString(ImgfileError, + "image must have 1 byte per pix chan"); + goto finally; + } + xsize = image.xsize; + ysize = image.ysize; + zsize = image.zsize; + if (rle) { + tablen = ysize * zsize * sizeof(Py_Int32); + starttab = (Py_Int32 *)malloc(tablen); + lengthtab = (Py_Int32 *)malloc(tablen); + rlebuflen = (int) (1.05 * xsize +10); + rledat = (unsigned char *)malloc(rlebuflen); + if (!starttab || !lengthtab || !rledat) { + PyErr_NoMemory(); + goto finally; + } + + fseek(inf, 512, SEEK_SET); + readtab(inf, starttab, ysize*zsize); + readtab(inf, lengthtab, ysize*zsize); + + /* check data order */ + cur = 0; + badorder = 0; + for(y = 0; y < ysize; y++) { + for(z = 0; z < zsize; z++) { + if (starttab[y + z * ysize] < cur) { + badorder = 1; + break; + } + cur = starttab[y +z * ysize]; + } + if (badorder) + break; + } + + fseek(inf, 512 + 2 * tablen, SEEK_SET); + cur = 512 + 2 * tablen; + rv = PyString_FromStringAndSize((char *)NULL, + (xsize * ysize + TAGLEN) * sizeof(Py_Int32)); + if (rv == NULL) + goto finally; + + base = (unsigned char *) PyString_AsString(rv); +#ifdef ADD_TAGS + addlongimgtag(base,xsize,ysize); +#endif + if (badorder) { + for (z = 0; z < zsize; z++) { + lptr = base; + if (reverse_order) + lptr += (ysize - 1) * xsize + * sizeof(Py_UInt32); + for (y = 0; y < ysize; y++) { + int idx = y + z * ysize; + if (cur != starttab[idx]) { + fseek(inf,starttab[idx], + SEEK_SET); + cur = starttab[idx]; + } + if (lengthtab[idx] > rlebuflen) { + PyErr_SetString(ImgfileError, + "rlebuf is too small"); + Py_DECREF(rv); + rv = NULL; + goto finally; + } + fread(rledat, lengthtab[idx], 1, inf); + cur += lengthtab[idx]; + expandrow(lptr, rledat, 3-z); + if (reverse_order) + lptr -= xsize + * sizeof(Py_UInt32); + else + lptr += xsize + * sizeof(Py_UInt32); + } + } + } else { + lptr = base; + if (reverse_order) + lptr += (ysize - 1) * xsize + * sizeof(Py_UInt32); + for (y = 0; y < ysize; y++) { + for(z = 0; z < zsize; z++) { + int idx = y + z * ysize; + if (cur != starttab[idx]) { + fseek(inf, starttab[idx], + SEEK_SET); + cur = starttab[idx]; + } + fread(rledat, lengthtab[idx], 1, inf); + cur += lengthtab[idx]; + expandrow(lptr, rledat, 3-z); + } + if (reverse_order) + lptr -= xsize * sizeof(Py_UInt32); + else + lptr += xsize * sizeof(Py_UInt32); + } + } + if (zsize == 3) + setalpha(base, xsize * ysize); + else if (zsize < 3) + copybw((Py_Int32 *) base, xsize * ysize); + } + else { + rv = PyString_FromStringAndSize((char *) 0, + (xsize*ysize+TAGLEN)*sizeof(Py_Int32)); + if (rv == NULL) + goto finally; + + base = (unsigned char *) PyString_AsString(rv); +#ifdef ADD_TAGS + addlongimgtag(base, xsize, ysize); +#endif + verdat = (unsigned char *)malloc(xsize); + if (!verdat) { + Py_CLEAR(rv); + goto finally; + } + + fseek(inf, 512, SEEK_SET); + for (z = 0; z < zsize; z++) { + lptr = base; + if (reverse_order) + lptr += (ysize - 1) * xsize + * sizeof(Py_UInt32); + for (y = 0; y < ysize; y++) { + fread(verdat, xsize, 1, inf); + interleaverow(lptr, verdat, 3-z, xsize); + if (reverse_order) + lptr -= xsize * sizeof(Py_UInt32); + else + lptr += xsize * sizeof(Py_UInt32); + } + } + if (zsize == 3) + setalpha(base, xsize * ysize); + else if (zsize < 3) + copybw((Py_Int32 *) base, xsize * ysize); + } + finally: + if (starttab) + free(starttab); + if (lengthtab) + free(lengthtab); + if (rledat) + free(rledat); + if (verdat) + free(verdat); + fclose(inf); + return rv; +} + +/* static utility functions for longimagedata */ + +static void +interleaverow(unsigned char *lptr, unsigned char *cptr, int z, int n) +{ + lptr += z; + while (n--) { + *lptr = *cptr++; + lptr += 4; + } +} + +static void +copybw(Py_Int32 *lptr, int n) +{ + while (n >= 8) { + lptr[0] = 0xff000000 + (0x010101 * (lptr[0] & 0xff)); + lptr[1] = 0xff000000 + (0x010101 * (lptr[1] & 0xff)); + lptr[2] = 0xff000000 + (0x010101 * (lptr[2] & 0xff)); + lptr[3] = 0xff000000 + (0x010101 * (lptr[3] & 0xff)); + lptr[4] = 0xff000000 + (0x010101 * (lptr[4] & 0xff)); + lptr[5] = 0xff000000 + (0x010101 * (lptr[5] & 0xff)); + lptr[6] = 0xff000000 + (0x010101 * (lptr[6] & 0xff)); + lptr[7] = 0xff000000 + (0x010101 * (lptr[7] & 0xff)); + lptr += 8; + n -= 8; + } + while (n--) { + *lptr = 0xff000000 + (0x010101 * (*lptr&0xff)); + lptr++; + } +} + +static void +setalpha(unsigned char *lptr, int n) +{ + while (n >= 8) { + lptr[0 * 4] = 0xff; + lptr[1 * 4] = 0xff; + lptr[2 * 4] = 0xff; + lptr[3 * 4] = 0xff; + lptr[4 * 4] = 0xff; + lptr[5 * 4] = 0xff; + lptr[6 * 4] = 0xff; + lptr[7 * 4] = 0xff; + lptr += 4 * 8; + n -= 8; + } + while (n--) { + *lptr = 0xff; + lptr += 4; + } +} + +static void +expandrow(unsigned char *optr, unsigned char *iptr, int z) +{ + unsigned char pixel, count; + + optr += z; + while (1) { + pixel = *iptr++; + if (!(count = (pixel & 0x7f))) + return; + if (pixel & 0x80) { + while (count >= 8) { + optr[0 * 4] = iptr[0]; + optr[1 * 4] = iptr[1]; + optr[2 * 4] = iptr[2]; + optr[3 * 4] = iptr[3]; + optr[4 * 4] = iptr[4]; + optr[5 * 4] = iptr[5]; + optr[6 * 4] = iptr[6]; + optr[7 * 4] = iptr[7]; + optr += 8 * 4; + iptr += 8; + count -= 8; + } + while (count--) { + *optr = *iptr++; + optr += 4; + } + } + else { + pixel = *iptr++; + while (count >= 8) { + optr[0 * 4] = pixel; + optr[1 * 4] = pixel; + optr[2 * 4] = pixel; + optr[3 * 4] = pixel; + optr[4 * 4] = pixel; + optr[5 * 4] = pixel; + optr[6 * 4] = pixel; + optr[7 * 4] = pixel; + optr += 8 * 4; + count -= 8; + } + while (count--) { + *optr = pixel; + optr += 4; + } + } + } +} + +/* + * longstoimage - + * copy an array of longs to an iris image file. Each long + * represents one pixel. xsize and ysize specify the dimensions of + * the pixel array. zsize specifies what kind of image file to + * write out. if zsize is 1, the luminance of the pixels are + * calculated, and a single channel black and white image is saved. + * If zsize is 3, an RGB image file is saved. If zsize is 4, an + * RGBA image file is saved. + * + */ +static PyObject * +longstoimage(PyObject *self, PyObject *args) +{ + unsigned char *lptr; + char *name; + int xsize, ysize, zsize; + FILE *outf = NULL; + IMAGE image; + int tablen, y, z, pos, len; + Py_Int32 *starttab = NULL, *lengthtab = NULL; + unsigned char *rlebuf = NULL; + unsigned char *lumbuf = NULL; + int rlebuflen; + Py_ssize_t goodwrite; + PyObject *retval = NULL; + + if (!PyArg_ParseTuple(args, "s#iiis:longstoimage", &lptr, &len, + &xsize, &ysize, &zsize, &name)) + return NULL; + + goodwrite = 1; + outf = fopen(name, "wb"); + if (!outf) { + PyErr_SetString(ImgfileError, "can't open output file"); + return NULL; + } + tablen = ysize * zsize * sizeof(Py_Int32); + + starttab = (Py_Int32 *)malloc(tablen); + lengthtab = (Py_Int32 *)malloc(tablen); + rlebuflen = (int) (1.05 * xsize + 10); + rlebuf = (unsigned char *)malloc(rlebuflen); + lumbuf = (unsigned char *)malloc(xsize * sizeof(Py_Int32)); + if (!starttab || !lengthtab || !rlebuf || !lumbuf) { + PyErr_NoMemory(); + goto finally; + } + + memset(&image, 0, sizeof(IMAGE)); + image.imagic = IMAGIC; + image.type = RLE(1); + if (zsize>1) + image.dim = 3; + else + image.dim = 2; + image.xsize = xsize; + image.ysize = ysize; + image.zsize = zsize; + image.min = 0; + image.max = 255; + goodwrite *= writeheader(outf, &image); + pos = 512 + 2 * tablen; + fseek(outf, pos, SEEK_SET); + if (reverse_order) + lptr += (ysize - 1) * xsize * sizeof(Py_UInt32); + for (y = 0; y < ysize; y++) { + for (z = 0; z < zsize; z++) { + if (zsize == 1) { + lumrow(lptr, lumbuf, xsize); + len = compressrow(lumbuf, rlebuf, + CHANOFFSET(z), xsize); + } else { + len = compressrow(lptr, rlebuf, + CHANOFFSET(z), xsize); + } + if(len > rlebuflen) { + PyErr_SetString(ImgfileError, + "rlebuf is too small"); + goto finally; + } + goodwrite *= fwrite(rlebuf, len, 1, outf); + starttab[y + z * ysize] = pos; + lengthtab[y + z * ysize] = len; + pos += len; + } + if (reverse_order) + lptr -= xsize * sizeof(Py_UInt32); + else + lptr += xsize * sizeof(Py_UInt32); + } + + fseek(outf, 512, SEEK_SET); + goodwrite *= writetab(outf, starttab, ysize*zsize); + goodwrite *= writetab(outf, lengthtab, ysize*zsize); + if (goodwrite) { + Py_INCREF(Py_None); + retval = Py_None; + } else + PyErr_SetString(ImgfileError, "not enough space for image"); + + finally: + fclose(outf); + free(starttab); + free(lengthtab); + free(rlebuf); + free(lumbuf); + return retval; +} + +/* static utility functions for longstoimage */ + +static void +lumrow(unsigned char *rgbptr, unsigned char *lumptr, int n) +{ + lumptr += CHANOFFSET(0); + while (n--) { + *lumptr = ILUM(rgbptr[OFFSET_R], + rgbptr[OFFSET_G], + rgbptr[OFFSET_B]); + lumptr += 4; + rgbptr += 4; + } +} + +static int +compressrow(unsigned char *lbuf, unsigned char *rlebuf, int z, int cnt) +{ + unsigned char *iptr, *ibufend, *sptr, *optr; + short todo, cc; + Py_Int32 count; + + lbuf += z; + iptr = lbuf; + ibufend = iptr + cnt * 4; + optr = rlebuf; + + while(iptr < ibufend) { + sptr = iptr; + iptr += 8; + while ((iptr<ibufend) && + ((iptr[-8]!=iptr[-4]) ||(iptr[-4]!=iptr[0]))) + { + iptr += 4; + } + iptr -= 8; + count = (iptr - sptr) / 4; + while (count) { + todo = count > 126 ? 126 : (short)count; + count -= todo; + *optr++ = 0x80 | todo; + while (todo > 8) { + optr[0] = sptr[0 * 4]; + optr[1] = sptr[1 * 4]; + optr[2] = sptr[2 * 4]; + optr[3] = sptr[3 * 4]; + optr[4] = sptr[4 * 4]; + optr[5] = sptr[5 * 4]; + optr[6] = sptr[6 * 4]; + optr[7] = sptr[7 * 4]; + optr += 8; + sptr += 8 * 4; + todo -= 8; + } + while (todo--) { + *optr++ = *sptr; + sptr += 4; + } + } + sptr = iptr; + cc = *iptr; + iptr += 4; + while ((iptr < ibufend) && (*iptr == cc)) + iptr += 4; + count = (iptr - sptr) / 4; + while (count) { + todo = count > 126 ? 126 : (short)count; + count -= todo; + *optr++ = (unsigned char) todo; + *optr++ = (unsigned char) cc; + } + } + *optr++ = 0; + return optr - (unsigned char *)rlebuf; +} + +static PyObject * +ttob(PyObject *self, PyObject *args) +{ + int order, oldorder; + + if (!PyArg_ParseTuple(args, "i:ttob", &order)) + return NULL; + oldorder = reverse_order; + reverse_order = order; + return PyInt_FromLong(oldorder); +} + +static PyMethodDef +rgbimg_methods[] = { + {"sizeofimage", sizeofimage, METH_VARARGS}, + {"longimagedata", longimagedata, METH_VARARGS}, + {"longstoimage", longstoimage, METH_VARARGS}, + {"ttob", ttob, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + + +PyMODINIT_FUNC +initrgbimg(void) +{ + PyObject *m, *d; + m = Py_InitModule("rgbimg", rgbimg_methods); + if (m == NULL) + return; + + if (PyErr_Warn(PyExc_DeprecationWarning, + "the rgbimg module is deprecated")) + return; + + d = PyModule_GetDict(m); + ImgfileError = PyErr_NewException("rgbimg.error", NULL, NULL); + if (ImgfileError != NULL) + PyDict_SetItemString(d, "error", ImgfileError); +} diff --git a/sys/src/cmd/python/Modules/rotatingtree.c b/sys/src/cmd/python/Modules/rotatingtree.c new file mode 100644 index 000000000..39c6dd53e --- /dev/null +++ b/sys/src/cmd/python/Modules/rotatingtree.c @@ -0,0 +1,121 @@ +#include "rotatingtree.h" + +#define KEY_LOWER_THAN(key1, key2) ((char*)(key1) < (char*)(key2)) + +/* The randombits() function below is a fast-and-dirty generator that + * is probably irregular enough for our purposes. Note that it's biased: + * I think that ones are slightly more probable than zeroes. It's not + * important here, though. + */ + +static unsigned int random_value = 1; +static unsigned int random_stream = 0; + +static int +randombits(int bits) +{ + int result; + if (random_stream < (1U << bits)) { + random_value *= 1082527; + random_stream = random_value; + } + result = random_stream & ((1<<bits)-1); + random_stream >>= bits; + return result; +} + + +/* Insert a new node into the tree. + (*root) is modified to point to the new root. */ +void +RotatingTree_Add(rotating_node_t **root, rotating_node_t *node) +{ + while (*root != NULL) { + if (KEY_LOWER_THAN(node->key, (*root)->key)) + root = &((*root)->left); + else + root = &((*root)->right); + } + node->left = NULL; + node->right = NULL; + *root = node; +} + +/* Locate the node with the given key. This is the most complicated + function because it occasionally rebalances the tree to move the + resulting node closer to the root. */ +rotating_node_t * +RotatingTree_Get(rotating_node_t **root, void *key) +{ + if (randombits(3) != 4) { + /* Fast path, no rebalancing */ + rotating_node_t *node = *root; + while (node != NULL) { + if (node->key == key) + return node; + if (KEY_LOWER_THAN(key, node->key)) + node = node->left; + else + node = node->right; + } + return NULL; + } + else { + rotating_node_t **pnode = root; + rotating_node_t *node = *pnode; + rotating_node_t *next; + int rotate; + if (node == NULL) + return NULL; + while (1) { + if (node->key == key) + return node; + rotate = !randombits(1); + if (KEY_LOWER_THAN(key, node->key)) { + next = node->left; + if (next == NULL) + return NULL; + if (rotate) { + node->left = next->right; + next->right = node; + *pnode = next; + } + else + pnode = &(node->left); + } + else { + next = node->right; + if (next == NULL) + return NULL; + if (rotate) { + node->right = next->left; + next->left = node; + *pnode = next; + } + else + pnode = &(node->right); + } + node = next; + } + } +} + +/* Enumerate all nodes in the tree. The callback enumfn() should return + zero to continue the enumeration, or non-zero to interrupt it. + A non-zero value is directly returned by RotatingTree_Enum(). */ +int +RotatingTree_Enum(rotating_node_t *root, rotating_tree_enum_fn enumfn, + void *arg) +{ + int result; + rotating_node_t *node; + while (root != NULL) { + result = RotatingTree_Enum(root->left, enumfn, arg); + if (result != 0) return result; + node = root->right; + result = enumfn(root, arg); + if (result != 0) return result; + root = node; + } + return 0; +} diff --git a/sys/src/cmd/python/Modules/rotatingtree.h b/sys/src/cmd/python/Modules/rotatingtree.h new file mode 100644 index 000000000..3aa0986b4 --- /dev/null +++ b/sys/src/cmd/python/Modules/rotatingtree.h @@ -0,0 +1,27 @@ +/* "Rotating trees" (Armin Rigo) + * + * Google "splay trees" for the general idea. + * + * It's a dict-like data structure that works best when accesses are not + * random, but follow a strong pattern. The one implemented here is for + * access patterns where the same small set of keys is looked up over + * and over again, and this set of keys evolves slowly over time. + */ + +#include <stdlib.h> + +#define EMPTY_ROTATING_TREE ((rotating_node_t *)NULL) + +typedef struct rotating_node_s rotating_node_t; +typedef int (*rotating_tree_enum_fn) (rotating_node_t *node, void *arg); + +struct rotating_node_s { + void *key; + rotating_node_t *left; + rotating_node_t *right; +}; + +void RotatingTree_Add(rotating_node_t **root, rotating_node_t *node); +rotating_node_t* RotatingTree_Get(rotating_node_t **root, void *key); +int RotatingTree_Enum(rotating_node_t *root, rotating_tree_enum_fn enumfn, + void *arg); diff --git a/sys/src/cmd/python/Modules/selectmodule.c b/sys/src/cmd/python/Modules/selectmodule.c new file mode 100644 index 000000000..9eaae8488 --- /dev/null +++ b/sys/src/cmd/python/Modules/selectmodule.c @@ -0,0 +1,734 @@ +/* select - Module containing unix select(2) call. + Under Unix, the file descriptors are small integers. + Under Win32, select only exists for sockets, and sockets may + have any value except INVALID_SOCKET. + Under BeOS, we suffer the same dichotomy as Win32; sockets can be anything + >= 0. +*/ + +#include "Python.h" + +#ifdef __APPLE__ + /* Perform runtime testing for a broken poll on OSX to make it easier + * to use the same binary on multiple releases of the OS. + */ +#undef HAVE_BROKEN_POLL +#endif + +/* Windows #defines FD_SETSIZE to 64 if FD_SETSIZE isn't already defined. + 64 is too small (too many people have bumped into that limit). + Here we boost it. + Users who want even more than the boosted limit should #define + FD_SETSIZE higher before this; e.g., via compiler /D switch. +*/ +#if defined(MS_WINDOWS) && !defined(FD_SETSIZE) +#define FD_SETSIZE 512 +#endif + +#if defined(HAVE_POLL_H) +#include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +#include <sys/poll.h> +#endif + +#ifdef __sgi +/* This is missing from unistd.h */ +extern void bzero(void *, int); +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#if defined(PYOS_OS2) && !defined(PYCC_GCC) +#include <sys/time.h> +#include <utils.h> +#endif + +#ifdef MS_WINDOWS +# include <winsock.h> +#else +# define SOCKET int +# ifdef __BEOS__ +# include <net/socket.h> +# elif defined(__VMS) +# include <socket.h> +# endif +#endif + + +static PyObject *SelectError; + +/* list of Python objects and their file descriptor */ +typedef struct { + PyObject *obj; /* owned reference */ + SOCKET fd; + int sentinel; /* -1 == sentinel */ +} pylist; + +static void +reap_obj(pylist fd2obj[FD_SETSIZE + 1]) +{ + int i; + for (i = 0; i < FD_SETSIZE + 1 && fd2obj[i].sentinel >= 0; i++) { + Py_XDECREF(fd2obj[i].obj); + fd2obj[i].obj = NULL; + } + fd2obj[0].sentinel = -1; +} + + +/* returns -1 and sets the Python exception if an error occurred, otherwise + returns a number >= 0 +*/ +static int +seq2set(PyObject *seq, fd_set *set, pylist fd2obj[FD_SETSIZE + 1]) +{ + int i; + int max = -1; + int index = 0; + int len = -1; + PyObject* fast_seq = NULL; + PyObject* o = NULL; + + fd2obj[0].obj = (PyObject*)0; /* set list to zero size */ + FD_ZERO(set); + + fast_seq=PySequence_Fast(seq, "arguments 1-3 must be sequences"); + if (!fast_seq) + return -1; + + len = PySequence_Fast_GET_SIZE(fast_seq); + + for (i = 0; i < len; i++) { + SOCKET v; + + /* any intervening fileno() calls could decr this refcnt */ + if (!(o = PySequence_Fast_GET_ITEM(fast_seq, i))) + return -1; + + Py_INCREF(o); + v = PyObject_AsFileDescriptor( o ); + if (v == -1) goto finally; + +#if defined(_MSC_VER) + max = 0; /* not used for Win32 */ +#else /* !_MSC_VER */ + if (v < 0 || v >= FD_SETSIZE) { + PyErr_SetString(PyExc_ValueError, + "filedescriptor out of range in select()"); + goto finally; + } + if (v > max) + max = v; +#endif /* _MSC_VER */ + FD_SET(v, set); + + /* add object and its file descriptor to the list */ + if (index >= FD_SETSIZE) { + PyErr_SetString(PyExc_ValueError, + "too many file descriptors in select()"); + goto finally; + } + fd2obj[index].obj = o; + fd2obj[index].fd = v; + fd2obj[index].sentinel = 0; + fd2obj[++index].sentinel = -1; + } + Py_DECREF(fast_seq); + return max+1; + + finally: + Py_XDECREF(o); + Py_DECREF(fast_seq); + return -1; +} + +/* returns NULL and sets the Python exception if an error occurred */ +static PyObject * +set2list(fd_set *set, pylist fd2obj[FD_SETSIZE + 1]) +{ + int i, j, count=0; + PyObject *list, *o; + SOCKET fd; + + for (j = 0; fd2obj[j].sentinel >= 0; j++) { + if (FD_ISSET(fd2obj[j].fd, set)) + count++; + } + list = PyList_New(count); + if (!list) + return NULL; + + i = 0; + for (j = 0; fd2obj[j].sentinel >= 0; j++) { + fd = fd2obj[j].fd; + if (FD_ISSET(fd, set)) { +#ifndef _MSC_VER + if (fd > FD_SETSIZE) { + PyErr_SetString(PyExc_SystemError, + "filedescriptor out of range returned in select()"); + goto finally; + } +#endif + o = fd2obj[j].obj; + fd2obj[j].obj = NULL; + /* transfer ownership */ + if (PyList_SetItem(list, i, o) < 0) + goto finally; + + i++; + } + } + return list; + finally: + Py_DECREF(list); + return NULL; +} + +#undef SELECT_USES_HEAP +#if FD_SETSIZE > 1024 +#define SELECT_USES_HEAP +#endif /* FD_SETSIZE > 1024 */ + +static PyObject * +select_select(PyObject *self, PyObject *args) +{ +#ifdef SELECT_USES_HEAP + pylist *rfd2obj, *wfd2obj, *efd2obj; +#else /* !SELECT_USES_HEAP */ + /* XXX: All this should probably be implemented as follows: + * - find the highest descriptor we're interested in + * - add one + * - that's the size + * See: Stevens, APitUE, $12.5.1 + */ + pylist rfd2obj[FD_SETSIZE + 1]; + pylist wfd2obj[FD_SETSIZE + 1]; + pylist efd2obj[FD_SETSIZE + 1]; +#endif /* SELECT_USES_HEAP */ + PyObject *ifdlist, *ofdlist, *efdlist; + PyObject *ret = NULL; + PyObject *tout = Py_None; + fd_set ifdset, ofdset, efdset; + double timeout; + struct timeval tv, *tvp; + long seconds; + int imax, omax, emax, max; + int n; + + /* convert arguments */ + if (!PyArg_UnpackTuple(args, "select", 3, 4, + &ifdlist, &ofdlist, &efdlist, &tout)) + return NULL; + + if (tout == Py_None) + tvp = (struct timeval *)0; + else if (!PyNumber_Check(tout)) { + PyErr_SetString(PyExc_TypeError, + "timeout must be a float or None"); + return NULL; + } + else { + timeout = PyFloat_AsDouble(tout); + if (timeout == -1 && PyErr_Occurred()) + return NULL; + if (timeout > (double)LONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "timeout period too long"); + return NULL; + } + seconds = (long)timeout; + timeout = timeout - (double)seconds; + tv.tv_sec = seconds; + tv.tv_usec = (long)(timeout*1000000.0); + tvp = &tv; + } + + +#ifdef SELECT_USES_HEAP + /* Allocate memory for the lists */ + rfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 1); + wfd2obj = PyMem_NEW(pylist, FD_SETSIZE + 1); + efd2obj = PyMem_NEW(pylist, FD_SETSIZE + 1); + if (rfd2obj == NULL || wfd2obj == NULL || efd2obj == NULL) { + if (rfd2obj) PyMem_DEL(rfd2obj); + if (wfd2obj) PyMem_DEL(wfd2obj); + if (efd2obj) PyMem_DEL(efd2obj); + return PyErr_NoMemory(); + } +#endif /* SELECT_USES_HEAP */ + /* Convert sequences to fd_sets, and get maximum fd number + * propagates the Python exception set in seq2set() + */ + rfd2obj[0].sentinel = -1; + wfd2obj[0].sentinel = -1; + efd2obj[0].sentinel = -1; + if ((imax=seq2set(ifdlist, &ifdset, rfd2obj)) < 0) + goto finally; + if ((omax=seq2set(ofdlist, &ofdset, wfd2obj)) < 0) + goto finally; + if ((emax=seq2set(efdlist, &efdset, efd2obj)) < 0) + goto finally; + max = imax; + if (omax > max) max = omax; + if (emax > max) max = emax; + + Py_BEGIN_ALLOW_THREADS + n = select(max, &ifdset, &ofdset, &efdset, tvp); + Py_END_ALLOW_THREADS + +#ifdef MS_WINDOWS + if (n == SOCKET_ERROR) { + PyErr_SetExcFromWindowsErr(SelectError, WSAGetLastError()); + } +#else + if (n < 0) { + PyErr_SetFromErrno(SelectError); + } +#endif + else if (n == 0) { + /* optimization */ + ifdlist = PyList_New(0); + if (ifdlist) { + ret = PyTuple_Pack(3, ifdlist, ifdlist, ifdlist); + Py_DECREF(ifdlist); + } + } + else { + /* any of these three calls can raise an exception. it's more + convenient to test for this after all three calls... but + is that acceptable? + */ + ifdlist = set2list(&ifdset, rfd2obj); + ofdlist = set2list(&ofdset, wfd2obj); + efdlist = set2list(&efdset, efd2obj); + if (PyErr_Occurred()) + ret = NULL; + else + ret = PyTuple_Pack(3, ifdlist, ofdlist, efdlist); + + Py_DECREF(ifdlist); + Py_DECREF(ofdlist); + Py_DECREF(efdlist); + } + + finally: + reap_obj(rfd2obj); + reap_obj(wfd2obj); + reap_obj(efd2obj); +#ifdef SELECT_USES_HEAP + PyMem_DEL(rfd2obj); + PyMem_DEL(wfd2obj); + PyMem_DEL(efd2obj); +#endif /* SELECT_USES_HEAP */ + return ret; +} + +#if defined(HAVE_POLL) && !defined(HAVE_BROKEN_POLL) +/* + * poll() support + */ + +typedef struct { + PyObject_HEAD + PyObject *dict; + int ufd_uptodate; + int ufd_len; + struct pollfd *ufds; +} pollObject; + +static PyTypeObject poll_Type; + +/* Update the malloc'ed array of pollfds to match the dictionary + contained within a pollObject. Return 1 on success, 0 on an error. +*/ + +static int +update_ufd_array(pollObject *self) +{ + Py_ssize_t i, pos; + PyObject *key, *value; + + self->ufd_len = PyDict_Size(self->dict); + PyMem_Resize(self->ufds, struct pollfd, self->ufd_len); + if (self->ufds == NULL) { + PyErr_NoMemory(); + return 0; + } + + i = pos = 0; + while (PyDict_Next(self->dict, &pos, &key, &value)) { + self->ufds[i].fd = PyInt_AsLong(key); + self->ufds[i].events = (short)PyInt_AsLong(value); + i++; + } + self->ufd_uptodate = 1; + return 1; +} + +PyDoc_STRVAR(poll_register_doc, +"register(fd [, eventmask] ) -> None\n\n\ +Register a file descriptor with the polling object.\n\ +fd -- either an integer, or an object with a fileno() method returning an\n\ + int.\n\ +events -- an optional bitmask describing the type of events to check for"); + +static PyObject * +poll_register(pollObject *self, PyObject *args) +{ + PyObject *o, *key, *value; + int fd, events = POLLIN | POLLPRI | POLLOUT; + int err; + + if (!PyArg_ParseTuple(args, "O|i:register", &o, &events)) { + return NULL; + } + + fd = PyObject_AsFileDescriptor(o); + if (fd == -1) return NULL; + + /* Add entry to the internal dictionary: the key is the + file descriptor, and the value is the event mask. */ + key = PyInt_FromLong(fd); + if (key == NULL) + return NULL; + value = PyInt_FromLong(events); + if (value == NULL) { + Py_DECREF(key); + return NULL; + } + err = PyDict_SetItem(self->dict, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (err < 0) + return NULL; + + self->ufd_uptodate = 0; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(poll_unregister_doc, +"unregister(fd) -> None\n\n\ +Remove a file descriptor being tracked by the polling object."); + +static PyObject * +poll_unregister(pollObject *self, PyObject *o) +{ + PyObject *key; + int fd; + + fd = PyObject_AsFileDescriptor( o ); + if (fd == -1) + return NULL; + + /* Check whether the fd is already in the array */ + key = PyInt_FromLong(fd); + if (key == NULL) + return NULL; + + if (PyDict_DelItem(self->dict, key) == -1) { + Py_DECREF(key); + /* This will simply raise the KeyError set by PyDict_DelItem + if the file descriptor isn't registered. */ + return NULL; + } + + Py_DECREF(key); + self->ufd_uptodate = 0; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(poll_poll_doc, +"poll( [timeout] ) -> list of (fd, event) 2-tuples\n\n\ +Polls the set of registered file descriptors, returning a list containing \n\ +any descriptors that have events or errors to report."); + +static PyObject * +poll_poll(pollObject *self, PyObject *args) +{ + PyObject *result_list = NULL, *tout = NULL; + int timeout = 0, poll_result, i, j; + PyObject *value = NULL, *num = NULL; + + if (!PyArg_UnpackTuple(args, "poll", 0, 1, &tout)) { + return NULL; + } + + /* Check values for timeout */ + if (tout == NULL || tout == Py_None) + timeout = -1; + else if (!PyNumber_Check(tout)) { + PyErr_SetString(PyExc_TypeError, + "timeout must be an integer or None"); + return NULL; + } + else { + tout = PyNumber_Int(tout); + if (!tout) + return NULL; + timeout = PyInt_AsLong(tout); + Py_DECREF(tout); + if (timeout == -1 && PyErr_Occurred()) + return NULL; + } + + /* Ensure the ufd array is up to date */ + if (!self->ufd_uptodate) + if (update_ufd_array(self) == 0) + return NULL; + + /* call poll() */ + Py_BEGIN_ALLOW_THREADS; + poll_result = poll(self->ufds, self->ufd_len, timeout); + Py_END_ALLOW_THREADS; + + if (poll_result < 0) { + PyErr_SetFromErrno(SelectError); + return NULL; + } + + /* build the result list */ + + result_list = PyList_New(poll_result); + if (!result_list) + return NULL; + else { + for (i = 0, j = 0; j < poll_result; j++) { + /* skip to the next fired descriptor */ + while (!self->ufds[i].revents) { + i++; + } + /* if we hit a NULL return, set value to NULL + and break out of loop; code at end will + clean up result_list */ + value = PyTuple_New(2); + if (value == NULL) + goto error; + num = PyInt_FromLong(self->ufds[i].fd); + if (num == NULL) { + Py_DECREF(value); + goto error; + } + PyTuple_SET_ITEM(value, 0, num); + + /* The &0xffff is a workaround for AIX. 'revents' + is a 16-bit short, and IBM assigned POLLNVAL + to be 0x8000, so the conversion to int results + in a negative number. See SF bug #923315. */ + num = PyInt_FromLong(self->ufds[i].revents & 0xffff); + if (num == NULL) { + Py_DECREF(value); + goto error; + } + PyTuple_SET_ITEM(value, 1, num); + if ((PyList_SetItem(result_list, j, value)) == -1) { + Py_DECREF(value); + goto error; + } + i++; + } + } + return result_list; + + error: + Py_DECREF(result_list); + return NULL; +} + +static PyMethodDef poll_methods[] = { + {"register", (PyCFunction)poll_register, + METH_VARARGS, poll_register_doc}, + {"unregister", (PyCFunction)poll_unregister, + METH_O, poll_unregister_doc}, + {"poll", (PyCFunction)poll_poll, + METH_VARARGS, poll_poll_doc}, + {NULL, NULL} /* sentinel */ +}; + +static pollObject * +newPollObject(void) +{ + pollObject *self; + self = PyObject_New(pollObject, &poll_Type); + if (self == NULL) + return NULL; + /* ufd_uptodate is a Boolean, denoting whether the + array pointed to by ufds matches the contents of the dictionary. */ + self->ufd_uptodate = 0; + self->ufds = NULL; + self->dict = PyDict_New(); + if (self->dict == NULL) { + Py_DECREF(self); + return NULL; + } + return self; +} + +static void +poll_dealloc(pollObject *self) +{ + if (self->ufds != NULL) + PyMem_DEL(self->ufds); + Py_XDECREF(self->dict); + PyObject_Del(self); +} + +static PyObject * +poll_getattr(pollObject *self, char *name) +{ + return Py_FindMethod(poll_methods, (PyObject *)self, name); +} + +static PyTypeObject poll_Type = { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "select.poll", /*tp_name*/ + sizeof(pollObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)poll_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)poll_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +PyDoc_STRVAR(poll_doc, +"Returns a polling object, which supports registering and\n\ +unregistering file descriptors, and then polling them for I/O events."); + +static PyObject * +select_poll(PyObject *self, PyObject *unused) +{ + return (PyObject *)newPollObject(); +} + +#ifdef __APPLE__ +/* + * On some systems poll() sets errno on invalid file descriptors. We test + * for this at runtime because this bug may be fixed or introduced between + * OS releases. + */ +static int select_have_broken_poll(void) +{ + int poll_test; + int filedes[2]; + + struct pollfd poll_struct = { 0, POLLIN|POLLPRI|POLLOUT, 0 }; + + /* Create a file descriptor to make invalid */ + if (pipe(filedes) < 0) { + return 1; + } + poll_struct.fd = filedes[0]; + close(filedes[0]); + close(filedes[1]); + poll_test = poll(&poll_struct, 1, 0); + if (poll_test < 0) { + return 1; + } else if (poll_test == 0 && poll_struct.revents != POLLNVAL) { + return 1; + } + return 0; +} +#endif /* __APPLE__ */ + +#endif /* HAVE_POLL */ + +PyDoc_STRVAR(select_doc, +"select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)\n\ +\n\ +Wait until one or more file descriptors are ready for some kind of I/O.\n\ +The first three arguments are sequences of file descriptors to be waited for:\n\ +rlist -- wait until ready for reading\n\ +wlist -- wait until ready for writing\n\ +xlist -- wait for an ``exceptional condition''\n\ +If only one kind of condition is required, pass [] for the other lists.\n\ +A file descriptor is either a socket or file object, or a small integer\n\ +gotten from a fileno() method call on one of those.\n\ +\n\ +The optional 4th argument specifies a timeout in seconds; it may be\n\ +a floating point number to specify fractions of seconds. If it is absent\n\ +or None, the call will never time out.\n\ +\n\ +The return value is a tuple of three lists corresponding to the first three\n\ +arguments; each contains the subset of the corresponding file descriptors\n\ +that are ready.\n\ +\n\ +*** IMPORTANT NOTICE ***\n\ +On Windows and OpenVMS, only sockets are supported; on Unix, all file descriptors."); + +static PyMethodDef select_methods[] = { + {"select", select_select, METH_VARARGS, select_doc}, +#if defined(HAVE_POLL) + {"poll", select_poll, METH_NOARGS, poll_doc}, +#endif /* HAVE_POLL */ + {0, 0}, /* sentinel */ +}; + +PyDoc_STRVAR(module_doc, +"This module supports asynchronous I/O on multiple file descriptors.\n\ +\n\ +*** IMPORTANT NOTICE ***\n\ +On Windows and OpenVMS, only sockets are supported; on Unix, all file descriptors."); + +PyMODINIT_FUNC +initselect(void) +{ + PyObject *m; + m = Py_InitModule3("select", select_methods, module_doc); + if (m == NULL) + return; + + SelectError = PyErr_NewException("select.error", NULL, NULL); + Py_INCREF(SelectError); + PyModule_AddObject(m, "error", SelectError); +#if defined(HAVE_POLL) + +#ifdef __APPLE__ + if (select_have_broken_poll()) { + if (PyObject_DelAttrString(m, "poll") == -1) { + PyErr_Clear(); + } + } else { +#else + { +#endif + poll_Type.ob_type = &PyType_Type; + PyModule_AddIntConstant(m, "POLLIN", POLLIN); + PyModule_AddIntConstant(m, "POLLPRI", POLLPRI); + PyModule_AddIntConstant(m, "POLLOUT", POLLOUT); + PyModule_AddIntConstant(m, "POLLERR", POLLERR); + PyModule_AddIntConstant(m, "POLLHUP", POLLHUP); + PyModule_AddIntConstant(m, "POLLNVAL", POLLNVAL); + +#ifdef POLLRDNORM + PyModule_AddIntConstant(m, "POLLRDNORM", POLLRDNORM); +#endif +#ifdef POLLRDBAND + PyModule_AddIntConstant(m, "POLLRDBAND", POLLRDBAND); +#endif +#ifdef POLLWRNORM + PyModule_AddIntConstant(m, "POLLWRNORM", POLLWRNORM); +#endif +#ifdef POLLWRBAND + PyModule_AddIntConstant(m, "POLLWRBAND", POLLWRBAND); +#endif +#ifdef POLLMSG + PyModule_AddIntConstant(m, "POLLMSG", POLLMSG); +#endif + } +#endif /* HAVE_POLL */ +} diff --git a/sys/src/cmd/python/Modules/sgimodule.c b/sys/src/cmd/python/Modules/sgimodule.c new file mode 100644 index 000000000..f7e12635c --- /dev/null +++ b/sys/src/cmd/python/Modules/sgimodule.c @@ -0,0 +1,55 @@ + +/* SGI module -- random SGI-specific things */ + +#include "Python.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +static PyObject * +sgi_nap(PyObject *self, PyObject *args) +{ + long ticks; + if (!PyArg_ParseTuple(args, "l:nap", &ticks)) + return NULL; + Py_BEGIN_ALLOW_THREADS + sginap(ticks); + Py_END_ALLOW_THREADS + Py_INCREF(Py_None); + return Py_None; +} + +extern char *_getpty(int *, int, mode_t, int); + +static PyObject * +sgi__getpty(PyObject *self, PyObject *args) +{ + int oflag; + int mode; + int nofork; + char *name; + int fildes; + if (!PyArg_ParseTuple(args, "iii:_getpty", &oflag, &mode, &nofork)) + return NULL; + errno = 0; + name = _getpty(&fildes, oflag, (mode_t)mode, nofork); + if (name == NULL) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return Py_BuildValue("(si)", name, fildes); +} + +static PyMethodDef sgi_methods[] = { + {"nap", sgi_nap, METH_VARARGS}, + {"_getpty", sgi__getpty, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + + +void +initsgi(void) +{ + Py_InitModule("sgi", sgi_methods); +} diff --git a/sys/src/cmd/python/Modules/sha256module.c b/sys/src/cmd/python/Modules/sha256module.c new file mode 100644 index 000000000..0effb0734 --- /dev/null +++ b/sys/src/cmd/python/Modules/sha256module.c @@ -0,0 +1,701 @@ +/* SHA256 module */ + +/* This module provides an interface to NIST's SHA-256 and SHA-224 Algorithms */ + +/* See below for information about the original code this module was + based upon. Additional work performed by: + + Andrew Kuchling (amk@amk.ca) + Greg Stein (gstein@lyra.org) + Trevor Perrin (trevp@trevp.net) + + Copyright (C) 2005 Gregory P. Smith (greg@electricrain.com) + Licensed to PSF under a Contributor Agreement. + +*/ + +/* SHA objects */ + +#include "Python.h" +#include "structmember.h" + + +/* Endianness testing and definitions */ +#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ + if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} + +#define PCT_LITTLE_ENDIAN 1 +#define PCT_BIG_ENDIAN 0 + +/* Some useful types */ + +typedef unsigned char SHA_BYTE; + +#if SIZEOF_INT == 4 +typedef unsigned int SHA_INT32; /* 32-bit integer */ +#else +/* not defined. compilation will die. */ +#endif + +/* The SHA block size and message digest sizes, in bytes */ + +#define SHA_BLOCKSIZE 64 +#define SHA_DIGESTSIZE 32 + +/* The structure for storing SHA info */ + +typedef struct { + PyObject_HEAD + SHA_INT32 digest[8]; /* Message digest */ + SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ + SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ + int Endianness; + int local; /* unprocessed amount in data */ + int digestsize; +} SHAobject; + +/* When run on a little-endian CPU we need to perform byte reversal on an + array of longwords. */ + +static void longReverse(SHA_INT32 *buffer, int byteCount, int Endianness) +{ + SHA_INT32 value; + + if ( Endianness == PCT_BIG_ENDIAN ) + return; + + byteCount /= sizeof(*buffer); + while (byteCount--) { + value = *buffer; + value = ( ( value & 0xFF00FF00L ) >> 8 ) | \ + ( ( value & 0x00FF00FFL ) << 8 ); + *buffer++ = ( value << 16 ) | ( value >> 16 ); + } +} + +static void SHAcopy(SHAobject *src, SHAobject *dest) +{ + dest->Endianness = src->Endianness; + dest->local = src->local; + dest->digestsize = src->digestsize; + dest->count_lo = src->count_lo; + dest->count_hi = src->count_hi; + memcpy(dest->digest, src->digest, sizeof(src->digest)); + memcpy(dest->data, src->data, sizeof(src->data)); +} + + +/* ------------------------------------------------------------------------ + * + * This code for the SHA-256 algorithm was noted as public domain. The + * original headers are pasted below. + * + * Several changes have been made to make it more compatible with the + * Python environment and desired interface. + * + */ + +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * gurantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + + +/* SHA256 by Tom St Denis */ + +/* Various logical functions */ +#define ROR(x, y)\ +( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | \ +((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) + + +static void +sha_transform(SHAobject *sha_info) +{ + int i; + SHA_INT32 S[8], W[64], t0, t1; + + memcpy(W, sha_info->data, sizeof(sha_info->data)); + longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); + + for (i = 16; i < 64; ++i) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } + for (i = 0; i < 8; ++i) { + S[i] = sha_info->digest[i]; + } + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); + +#undef RND + + /* feedback */ + for (i = 0; i < 8; i++) { + sha_info->digest[i] = sha_info->digest[i] + S[i]; + } + +} + + + +/* initialize the SHA digest */ + +static void +sha_init(SHAobject *sha_info) +{ + TestEndianness(sha_info->Endianness) + sha_info->digest[0] = 0x6A09E667L; + sha_info->digest[1] = 0xBB67AE85L; + sha_info->digest[2] = 0x3C6EF372L; + sha_info->digest[3] = 0xA54FF53AL; + sha_info->digest[4] = 0x510E527FL; + sha_info->digest[5] = 0x9B05688CL; + sha_info->digest[6] = 0x1F83D9ABL; + sha_info->digest[7] = 0x5BE0CD19L; + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; + sha_info->digestsize = 32; +} + +static void +sha224_init(SHAobject *sha_info) +{ + TestEndianness(sha_info->Endianness) + sha_info->digest[0] = 0xc1059ed8L; + sha_info->digest[1] = 0x367cd507L; + sha_info->digest[2] = 0x3070dd17L; + sha_info->digest[3] = 0xf70e5939L; + sha_info->digest[4] = 0xffc00b31L; + sha_info->digest[5] = 0x68581511L; + sha_info->digest[6] = 0x64f98fa7L; + sha_info->digest[7] = 0xbefa4fa4L; + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; + sha_info->digestsize = 28; +} + + +/* update the SHA digest */ + +static void +sha_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) +{ + int i; + SHA_INT32 clo; + + clo = sha_info->count_lo + ((SHA_INT32) count << 3); + if (clo < sha_info->count_lo) { + ++sha_info->count_hi; + } + sha_info->count_lo = clo; + sha_info->count_hi += (SHA_INT32) count >> 29; + if (sha_info->local) { + i = SHA_BLOCKSIZE - sha_info->local; + if (i > count) { + i = count; + } + memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); + count -= i; + buffer += i; + sha_info->local += i; + if (sha_info->local == SHA_BLOCKSIZE) { + sha_transform(sha_info); + } + else { + return; + } + } + while (count >= SHA_BLOCKSIZE) { + memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); + buffer += SHA_BLOCKSIZE; + count -= SHA_BLOCKSIZE; + sha_transform(sha_info); + } + memcpy(sha_info->data, buffer, count); + sha_info->local = count; +} + +/* finish computing the SHA digest */ + +static void +sha_final(unsigned char digest[SHA_DIGESTSIZE], SHAobject *sha_info) +{ + int count; + SHA_INT32 lo_bit_count, hi_bit_count; + + lo_bit_count = sha_info->count_lo; + hi_bit_count = sha_info->count_hi; + count = (int) ((lo_bit_count >> 3) & 0x3f); + ((SHA_BYTE *) sha_info->data)[count++] = 0x80; + if (count > SHA_BLOCKSIZE - 8) { + memset(((SHA_BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - count); + sha_transform(sha_info); + memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); + } + else { + memset(((SHA_BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - 8 - count); + } + + /* GJS: note that we add the hi/lo in big-endian. sha_transform will + swap these values into host-order. */ + sha_info->data[56] = (hi_bit_count >> 24) & 0xff; + sha_info->data[57] = (hi_bit_count >> 16) & 0xff; + sha_info->data[58] = (hi_bit_count >> 8) & 0xff; + sha_info->data[59] = (hi_bit_count >> 0) & 0xff; + sha_info->data[60] = (lo_bit_count >> 24) & 0xff; + sha_info->data[61] = (lo_bit_count >> 16) & 0xff; + sha_info->data[62] = (lo_bit_count >> 8) & 0xff; + sha_info->data[63] = (lo_bit_count >> 0) & 0xff; + sha_transform(sha_info); + digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); + digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); + digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); + digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff); + digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); + digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); + digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); + digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff); + digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); + digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); + digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); + digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff); + digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); + digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); + digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); + digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff); + digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); + digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); + digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); + digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); + digest[20] = (unsigned char) ((sha_info->digest[5] >> 24) & 0xff); + digest[21] = (unsigned char) ((sha_info->digest[5] >> 16) & 0xff); + digest[22] = (unsigned char) ((sha_info->digest[5] >> 8) & 0xff); + digest[23] = (unsigned char) ((sha_info->digest[5] ) & 0xff); + digest[24] = (unsigned char) ((sha_info->digest[6] >> 24) & 0xff); + digest[25] = (unsigned char) ((sha_info->digest[6] >> 16) & 0xff); + digest[26] = (unsigned char) ((sha_info->digest[6] >> 8) & 0xff); + digest[27] = (unsigned char) ((sha_info->digest[6] ) & 0xff); + digest[28] = (unsigned char) ((sha_info->digest[7] >> 24) & 0xff); + digest[29] = (unsigned char) ((sha_info->digest[7] >> 16) & 0xff); + digest[30] = (unsigned char) ((sha_info->digest[7] >> 8) & 0xff); + digest[31] = (unsigned char) ((sha_info->digest[7] ) & 0xff); +} + +/* + * End of copied SHA code. + * + * ------------------------------------------------------------------------ + */ + +static PyTypeObject SHA224type; +static PyTypeObject SHA256type; + + +static SHAobject * +newSHA224object(void) +{ + return (SHAobject *)PyObject_New(SHAobject, &SHA224type); +} + +static SHAobject * +newSHA256object(void) +{ + return (SHAobject *)PyObject_New(SHAobject, &SHA256type); +} + +/* Internal methods for a hash object */ + +static void +SHA_dealloc(PyObject *ptr) +{ + PyObject_Del(ptr); +} + + +/* External methods for a hash object */ + +PyDoc_STRVAR(SHA256_copy__doc__, "Return a copy of the hash object."); + +static PyObject * +SHA256_copy(SHAobject *self, PyObject *unused) +{ + SHAobject *newobj; + + if (((PyObject*)self)->ob_type == &SHA256type) { + if ( (newobj = newSHA256object())==NULL) + return NULL; + } else { + if ( (newobj = newSHA224object())==NULL) + return NULL; + } + + SHAcopy(self, newobj); + return (PyObject *)newobj; +} + +PyDoc_STRVAR(SHA256_digest__doc__, +"Return the digest value as a string of binary data."); + +static PyObject * +SHA256_digest(SHAobject *self, PyObject *unused) +{ + unsigned char digest[SHA_DIGESTSIZE]; + SHAobject temp; + + SHAcopy(self, &temp); + sha_final(digest, &temp); + return PyString_FromStringAndSize((const char *)digest, self->digestsize); +} + +PyDoc_STRVAR(SHA256_hexdigest__doc__, +"Return the digest value as a string of hexadecimal digits."); + +static PyObject * +SHA256_hexdigest(SHAobject *self, PyObject *unused) +{ + unsigned char digest[SHA_DIGESTSIZE]; + SHAobject temp; + PyObject *retval; + char *hex_digest; + int i, j; + + /* Get the raw (binary) digest value */ + SHAcopy(self, &temp); + sha_final(digest, &temp); + + /* Create a new string */ + retval = PyString_FromStringAndSize(NULL, self->digestsize * 2); + if (!retval) + return NULL; + hex_digest = PyString_AsString(retval); + if (!hex_digest) { + Py_DECREF(retval); + return NULL; + } + + /* Make hex version of the digest */ + for(i=j=0; i<self->digestsize; i++) { + char c; + c = (digest[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + c = (digest[i] & 0xf); + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + } + return retval; +} + +PyDoc_STRVAR(SHA256_update__doc__, +"Update this hash object's state with the provided string."); + +static PyObject * +SHA256_update(SHAobject *self, PyObject *args) +{ + unsigned char *cp; + int len; + + if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + return NULL; + + sha_update(self, cp, len); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef SHA_methods[] = { + {"copy", (PyCFunction)SHA256_copy, METH_NOARGS, SHA256_copy__doc__}, + {"digest", (PyCFunction)SHA256_digest, METH_NOARGS, SHA256_digest__doc__}, + {"hexdigest", (PyCFunction)SHA256_hexdigest, METH_NOARGS, SHA256_hexdigest__doc__}, + {"update", (PyCFunction)SHA256_update, METH_VARARGS, SHA256_update__doc__}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +SHA256_get_block_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(SHA_BLOCKSIZE); +} + +static PyObject * +SHA256_get_name(PyObject *self, void *closure) +{ + if (((SHAobject *)self)->digestsize == 32) + return PyString_FromStringAndSize("SHA256", 6); + else + return PyString_FromStringAndSize("SHA224", 6); +} + +static PyGetSetDef SHA_getseters[] = { + {"block_size", + (getter)SHA256_get_block_size, NULL, + NULL, + NULL}, + {"name", + (getter)SHA256_get_name, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef SHA_members[] = { + {"digest_size", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, + /* the old md5 and sha modules support 'digest_size' as in PEP 247. + * the old sha module also supported 'digestsize'. ugh. */ + {"digestsize", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject SHA224type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_sha256.sha224", /*tp_name*/ + sizeof(SHAobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + SHA_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + SHA_methods, /* tp_methods */ + SHA_members, /* tp_members */ + SHA_getseters, /* tp_getset */ +}; + +static PyTypeObject SHA256type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_sha256.sha256", /*tp_name*/ + sizeof(SHAobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + SHA_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + SHA_methods, /* tp_methods */ + SHA_members, /* tp_members */ + SHA_getseters, /* tp_getset */ +}; + + +/* The single module-level function: new() */ + +PyDoc_STRVAR(SHA256_new__doc__, +"Return a new SHA-256 hash object; optionally initialized with a string."); + +static PyObject * +SHA256_new(PyObject *self, PyObject *args, PyObject *kwdict) +{ + static char *kwlist[] = {"string", NULL}; + SHAobject *new; + unsigned char *cp = NULL; + int len; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, + &cp, &len)) { + return NULL; + } + + if ((new = newSHA256object()) == NULL) + return NULL; + + sha_init(new); + + if (PyErr_Occurred()) { + Py_DECREF(new); + return NULL; + } + if (cp) + sha_update(new, cp, len); + + return (PyObject *)new; +} + +PyDoc_STRVAR(SHA224_new__doc__, +"Return a new SHA-224 hash object; optionally initialized with a string."); + +static PyObject * +SHA224_new(PyObject *self, PyObject *args, PyObject *kwdict) +{ + static char *kwlist[] = {"string", NULL}; + SHAobject *new; + unsigned char *cp = NULL; + int len; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, + &cp, &len)) { + return NULL; + } + + if ((new = newSHA224object()) == NULL) + return NULL; + + sha224_init(new); + + if (PyErr_Occurred()) { + Py_DECREF(new); + return NULL; + } + if (cp) + sha_update(new, cp, len); + + return (PyObject *)new; +} + + +/* List of functions exported by this module */ + +static struct PyMethodDef SHA_functions[] = { + {"sha256", (PyCFunction)SHA256_new, METH_VARARGS|METH_KEYWORDS, SHA256_new__doc__}, + {"sha224", (PyCFunction)SHA224_new, METH_VARARGS|METH_KEYWORDS, SHA224_new__doc__}, + {NULL, NULL} /* Sentinel */ +}; + + +/* Initialize this module. */ + +#define insint(n,v) { PyModule_AddIntConstant(m,n,v); } + +PyMODINIT_FUNC +init_sha256(void) +{ + PyObject *m; + + SHA224type.ob_type = &PyType_Type; + if (PyType_Ready(&SHA224type) < 0) + return; + SHA256type.ob_type = &PyType_Type; + if (PyType_Ready(&SHA256type) < 0) + return; + m = Py_InitModule("_sha256", SHA_functions); + if (m == NULL) + return; +} diff --git a/sys/src/cmd/python/Modules/sha512module.c b/sys/src/cmd/python/Modules/sha512module.c new file mode 100644 index 000000000..9f47b6128 --- /dev/null +++ b/sys/src/cmd/python/Modules/sha512module.c @@ -0,0 +1,769 @@ +/* SHA512 module */ + +/* This module provides an interface to NIST's SHA-512 and SHA-384 Algorithms */ + +/* See below for information about the original code this module was + based upon. Additional work performed by: + + Andrew Kuchling (amk@amk.ca) + Greg Stein (gstein@lyra.org) + Trevor Perrin (trevp@trevp.net) + + Copyright (C) 2005 Gregory P. Smith (greg@electricrain.com) + Licensed to PSF under a Contributor Agreement. + +*/ + +/* SHA objects */ + +#include "Python.h" +#include "structmember.h" + +#ifdef PY_LONG_LONG /* If no PY_LONG_LONG, don't compile anything! */ + +/* Endianness testing and definitions */ +#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ + if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} + +#define PCT_LITTLE_ENDIAN 1 +#define PCT_BIG_ENDIAN 0 + +/* Some useful types */ + +typedef unsigned char SHA_BYTE; + +#if SIZEOF_INT == 4 +typedef unsigned int SHA_INT32; /* 32-bit integer */ +typedef unsigned PY_LONG_LONG SHA_INT64; /* 64-bit integer */ +#else +/* not defined. compilation will die. */ +#endif + +/* The SHA block size and message digest sizes, in bytes */ + +#define SHA_BLOCKSIZE 128 +#define SHA_DIGESTSIZE 64 + +/* The structure for storing SHA info */ + +typedef struct { + PyObject_HEAD + SHA_INT64 digest[8]; /* Message digest */ + SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ + SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ + int Endianness; + int local; /* unprocessed amount in data */ + int digestsize; +} SHAobject; + +/* When run on a little-endian CPU we need to perform byte reversal on an + array of longwords. */ + +static void longReverse(SHA_INT64 *buffer, int byteCount, int Endianness) +{ + SHA_INT64 value; + + if ( Endianness == PCT_BIG_ENDIAN ) + return; + + byteCount /= sizeof(*buffer); + while (byteCount--) { + value = *buffer; + + ((unsigned char*)buffer)[0] = (unsigned char)(value >> 56) & 0xff; + ((unsigned char*)buffer)[1] = (unsigned char)(value >> 48) & 0xff; + ((unsigned char*)buffer)[2] = (unsigned char)(value >> 40) & 0xff; + ((unsigned char*)buffer)[3] = (unsigned char)(value >> 32) & 0xff; + ((unsigned char*)buffer)[4] = (unsigned char)(value >> 24) & 0xff; + ((unsigned char*)buffer)[5] = (unsigned char)(value >> 16) & 0xff; + ((unsigned char*)buffer)[6] = (unsigned char)(value >> 8) & 0xff; + ((unsigned char*)buffer)[7] = (unsigned char)(value ) & 0xff; + + buffer++; + } +} + +static void SHAcopy(SHAobject *src, SHAobject *dest) +{ + dest->Endianness = src->Endianness; + dest->local = src->local; + dest->digestsize = src->digestsize; + dest->count_lo = src->count_lo; + dest->count_hi = src->count_hi; + memcpy(dest->digest, src->digest, sizeof(src->digest)); + memcpy(dest->data, src->data, sizeof(src->data)); +} + + +/* ------------------------------------------------------------------------ + * + * This code for the SHA-512 algorithm was noted as public domain. The + * original headers are pasted below. + * + * Several changes have been made to make it more compatible with the + * Python environment and desired interface. + * + */ + +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * gurantee it works. + * + * Tom St Denis, tomstdenis@iahu.ca, http://libtomcrypt.org + */ + + +/* SHA512 by Tom St Denis */ + +/* Various logical functions */ +#define ROR64(x, y) \ + ( ((((x) & Py_ULL(0xFFFFFFFFFFFFFFFF))>>((unsigned PY_LONG_LONG)(y) & 63)) | \ + ((x)<<((unsigned PY_LONG_LONG)(64-((y) & 63))))) & Py_ULL(0xFFFFFFFFFFFFFFFF)) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64((x),(n)) +#define R(x, n) (((x) & Py_ULL(0xFFFFFFFFFFFFFFFF)) >> ((unsigned PY_LONG_LONG)n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) + + +static void +sha512_transform(SHAobject *sha_info) +{ + int i; + SHA_INT64 S[8], W[80], t0, t1; + + memcpy(W, sha_info->data, sizeof(sha_info->data)); + longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); + + for (i = 16; i < 80; ++i) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } + for (i = 0; i < 8; ++i) { + S[i] = sha_info->digest[i]; + } + + /* Compress */ +#define RND(a,b,c,d,e,f,g,h,i,ki) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c); \ + d += t0; \ + h = t0 + t1; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,Py_ULL(0x428a2f98d728ae22)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,Py_ULL(0x7137449123ef65cd)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,Py_ULL(0xb5c0fbcfec4d3b2f)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,Py_ULL(0xe9b5dba58189dbbc)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,Py_ULL(0x3956c25bf348b538)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,Py_ULL(0x59f111f1b605d019)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,Py_ULL(0x923f82a4af194f9b)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,Py_ULL(0xab1c5ed5da6d8118)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,Py_ULL(0xd807aa98a3030242)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,Py_ULL(0x12835b0145706fbe)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,Py_ULL(0x243185be4ee4b28c)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,Py_ULL(0x550c7dc3d5ffb4e2)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,Py_ULL(0x72be5d74f27b896f)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,Py_ULL(0x80deb1fe3b1696b1)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,Py_ULL(0x9bdc06a725c71235)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,Py_ULL(0xc19bf174cf692694)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,Py_ULL(0xe49b69c19ef14ad2)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,Py_ULL(0xefbe4786384f25e3)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,Py_ULL(0x0fc19dc68b8cd5b5)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,Py_ULL(0x240ca1cc77ac9c65)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,Py_ULL(0x2de92c6f592b0275)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,Py_ULL(0x4a7484aa6ea6e483)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,Py_ULL(0x5cb0a9dcbd41fbd4)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,Py_ULL(0x76f988da831153b5)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,Py_ULL(0x983e5152ee66dfab)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,Py_ULL(0xa831c66d2db43210)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,Py_ULL(0xb00327c898fb213f)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,Py_ULL(0xbf597fc7beef0ee4)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,Py_ULL(0xc6e00bf33da88fc2)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,Py_ULL(0xd5a79147930aa725)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,Py_ULL(0x06ca6351e003826f)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,Py_ULL(0x142929670a0e6e70)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,Py_ULL(0x27b70a8546d22ffc)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,Py_ULL(0x2e1b21385c26c926)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,Py_ULL(0x4d2c6dfc5ac42aed)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,Py_ULL(0x53380d139d95b3df)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,Py_ULL(0x650a73548baf63de)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,Py_ULL(0x766a0abb3c77b2a8)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,Py_ULL(0x81c2c92e47edaee6)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,Py_ULL(0x92722c851482353b)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,Py_ULL(0xa2bfe8a14cf10364)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,Py_ULL(0xa81a664bbc423001)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,Py_ULL(0xc24b8b70d0f89791)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,Py_ULL(0xc76c51a30654be30)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,Py_ULL(0xd192e819d6ef5218)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,Py_ULL(0xd69906245565a910)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,Py_ULL(0xf40e35855771202a)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,Py_ULL(0x106aa07032bbd1b8)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,Py_ULL(0x19a4c116b8d2d0c8)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,Py_ULL(0x1e376c085141ab53)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,Py_ULL(0x2748774cdf8eeb99)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,Py_ULL(0x34b0bcb5e19b48a8)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,Py_ULL(0x391c0cb3c5c95a63)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,Py_ULL(0x4ed8aa4ae3418acb)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,Py_ULL(0x5b9cca4f7763e373)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,Py_ULL(0x682e6ff3d6b2b8a3)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,Py_ULL(0x748f82ee5defb2fc)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,Py_ULL(0x78a5636f43172f60)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,Py_ULL(0x84c87814a1f0ab72)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,Py_ULL(0x8cc702081a6439ec)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,Py_ULL(0x90befffa23631e28)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,Py_ULL(0xa4506cebde82bde9)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,Py_ULL(0xbef9a3f7b2c67915)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,Py_ULL(0xc67178f2e372532b)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],64,Py_ULL(0xca273eceea26619c)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],65,Py_ULL(0xd186b8c721c0c207)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],66,Py_ULL(0xeada7dd6cde0eb1e)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],67,Py_ULL(0xf57d4f7fee6ed178)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],68,Py_ULL(0x06f067aa72176fba)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],69,Py_ULL(0x0a637dc5a2c898a6)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],70,Py_ULL(0x113f9804bef90dae)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],71,Py_ULL(0x1b710b35131c471b)); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],72,Py_ULL(0x28db77f523047d84)); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],73,Py_ULL(0x32caab7b40c72493)); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],74,Py_ULL(0x3c9ebe0a15c9bebc)); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],75,Py_ULL(0x431d67c49c100d4c)); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],76,Py_ULL(0x4cc5d4becb3e42b6)); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],77,Py_ULL(0x597f299cfc657e2a)); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],78,Py_ULL(0x5fcb6fab3ad6faec)); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],79,Py_ULL(0x6c44198c4a475817)); + +#undef RND + + /* feedback */ + for (i = 0; i < 8; i++) { + sha_info->digest[i] = sha_info->digest[i] + S[i]; + } + +} + + + +/* initialize the SHA digest */ + +static void +sha512_init(SHAobject *sha_info) +{ + TestEndianness(sha_info->Endianness) + sha_info->digest[0] = Py_ULL(0x6a09e667f3bcc908); + sha_info->digest[1] = Py_ULL(0xbb67ae8584caa73b); + sha_info->digest[2] = Py_ULL(0x3c6ef372fe94f82b); + sha_info->digest[3] = Py_ULL(0xa54ff53a5f1d36f1); + sha_info->digest[4] = Py_ULL(0x510e527fade682d1); + sha_info->digest[5] = Py_ULL(0x9b05688c2b3e6c1f); + sha_info->digest[6] = Py_ULL(0x1f83d9abfb41bd6b); + sha_info->digest[7] = Py_ULL(0x5be0cd19137e2179); + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; + sha_info->digestsize = 64; +} + +static void +sha384_init(SHAobject *sha_info) +{ + TestEndianness(sha_info->Endianness) + sha_info->digest[0] = Py_ULL(0xcbbb9d5dc1059ed8); + sha_info->digest[1] = Py_ULL(0x629a292a367cd507); + sha_info->digest[2] = Py_ULL(0x9159015a3070dd17); + sha_info->digest[3] = Py_ULL(0x152fecd8f70e5939); + sha_info->digest[4] = Py_ULL(0x67332667ffc00b31); + sha_info->digest[5] = Py_ULL(0x8eb44a8768581511); + sha_info->digest[6] = Py_ULL(0xdb0c2e0d64f98fa7); + sha_info->digest[7] = Py_ULL(0x47b5481dbefa4fa4); + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; + sha_info->digestsize = 48; +} + + +/* update the SHA digest */ + +static void +sha512_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) +{ + int i; + SHA_INT32 clo; + + clo = sha_info->count_lo + ((SHA_INT32) count << 3); + if (clo < sha_info->count_lo) { + ++sha_info->count_hi; + } + sha_info->count_lo = clo; + sha_info->count_hi += (SHA_INT32) count >> 29; + if (sha_info->local) { + i = SHA_BLOCKSIZE - sha_info->local; + if (i > count) { + i = count; + } + memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); + count -= i; + buffer += i; + sha_info->local += i; + if (sha_info->local == SHA_BLOCKSIZE) { + sha512_transform(sha_info); + } + else { + return; + } + } + while (count >= SHA_BLOCKSIZE) { + memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); + buffer += SHA_BLOCKSIZE; + count -= SHA_BLOCKSIZE; + sha512_transform(sha_info); + } + memcpy(sha_info->data, buffer, count); + sha_info->local = count; +} + +/* finish computing the SHA digest */ + +static void +sha512_final(unsigned char digest[SHA_DIGESTSIZE], SHAobject *sha_info) +{ + int count; + SHA_INT32 lo_bit_count, hi_bit_count; + + lo_bit_count = sha_info->count_lo; + hi_bit_count = sha_info->count_hi; + count = (int) ((lo_bit_count >> 3) & 0x7f); + ((SHA_BYTE *) sha_info->data)[count++] = 0x80; + if (count > SHA_BLOCKSIZE - 16) { + memset(((SHA_BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - count); + sha512_transform(sha_info); + memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 16); + } + else { + memset(((SHA_BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - 16 - count); + } + + /* GJS: note that we add the hi/lo in big-endian. sha512_transform will + swap these values into host-order. */ + sha_info->data[112] = 0; + sha_info->data[113] = 0; + sha_info->data[114] = 0; + sha_info->data[115] = 0; + sha_info->data[116] = 0; + sha_info->data[117] = 0; + sha_info->data[118] = 0; + sha_info->data[119] = 0; + sha_info->data[120] = (hi_bit_count >> 24) & 0xff; + sha_info->data[121] = (hi_bit_count >> 16) & 0xff; + sha_info->data[122] = (hi_bit_count >> 8) & 0xff; + sha_info->data[123] = (hi_bit_count >> 0) & 0xff; + sha_info->data[124] = (lo_bit_count >> 24) & 0xff; + sha_info->data[125] = (lo_bit_count >> 16) & 0xff; + sha_info->data[126] = (lo_bit_count >> 8) & 0xff; + sha_info->data[127] = (lo_bit_count >> 0) & 0xff; + sha512_transform(sha_info); + digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 56) & 0xff); + digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 48) & 0xff); + digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 40) & 0xff); + digest[ 3] = (unsigned char) ((sha_info->digest[0] >> 32) & 0xff); + digest[ 4] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); + digest[ 5] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); + digest[ 6] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); + digest[ 7] = (unsigned char) ((sha_info->digest[0] ) & 0xff); + digest[ 8] = (unsigned char) ((sha_info->digest[1] >> 56) & 0xff); + digest[ 9] = (unsigned char) ((sha_info->digest[1] >> 48) & 0xff); + digest[10] = (unsigned char) ((sha_info->digest[1] >> 40) & 0xff); + digest[11] = (unsigned char) ((sha_info->digest[1] >> 32) & 0xff); + digest[12] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); + digest[13] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); + digest[14] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); + digest[15] = (unsigned char) ((sha_info->digest[1] ) & 0xff); + digest[16] = (unsigned char) ((sha_info->digest[2] >> 56) & 0xff); + digest[17] = (unsigned char) ((sha_info->digest[2] >> 48) & 0xff); + digest[18] = (unsigned char) ((sha_info->digest[2] >> 40) & 0xff); + digest[19] = (unsigned char) ((sha_info->digest[2] >> 32) & 0xff); + digest[20] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); + digest[21] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); + digest[22] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); + digest[23] = (unsigned char) ((sha_info->digest[2] ) & 0xff); + digest[24] = (unsigned char) ((sha_info->digest[3] >> 56) & 0xff); + digest[25] = (unsigned char) ((sha_info->digest[3] >> 48) & 0xff); + digest[26] = (unsigned char) ((sha_info->digest[3] >> 40) & 0xff); + digest[27] = (unsigned char) ((sha_info->digest[3] >> 32) & 0xff); + digest[28] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); + digest[29] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); + digest[30] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); + digest[31] = (unsigned char) ((sha_info->digest[3] ) & 0xff); + digest[32] = (unsigned char) ((sha_info->digest[4] >> 56) & 0xff); + digest[33] = (unsigned char) ((sha_info->digest[4] >> 48) & 0xff); + digest[34] = (unsigned char) ((sha_info->digest[4] >> 40) & 0xff); + digest[35] = (unsigned char) ((sha_info->digest[4] >> 32) & 0xff); + digest[36] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); + digest[37] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); + digest[38] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); + digest[39] = (unsigned char) ((sha_info->digest[4] ) & 0xff); + digest[40] = (unsigned char) ((sha_info->digest[5] >> 56) & 0xff); + digest[41] = (unsigned char) ((sha_info->digest[5] >> 48) & 0xff); + digest[42] = (unsigned char) ((sha_info->digest[5] >> 40) & 0xff); + digest[43] = (unsigned char) ((sha_info->digest[5] >> 32) & 0xff); + digest[44] = (unsigned char) ((sha_info->digest[5] >> 24) & 0xff); + digest[45] = (unsigned char) ((sha_info->digest[5] >> 16) & 0xff); + digest[46] = (unsigned char) ((sha_info->digest[5] >> 8) & 0xff); + digest[47] = (unsigned char) ((sha_info->digest[5] ) & 0xff); + digest[48] = (unsigned char) ((sha_info->digest[6] >> 56) & 0xff); + digest[49] = (unsigned char) ((sha_info->digest[6] >> 48) & 0xff); + digest[50] = (unsigned char) ((sha_info->digest[6] >> 40) & 0xff); + digest[51] = (unsigned char) ((sha_info->digest[6] >> 32) & 0xff); + digest[52] = (unsigned char) ((sha_info->digest[6] >> 24) & 0xff); + digest[53] = (unsigned char) ((sha_info->digest[6] >> 16) & 0xff); + digest[54] = (unsigned char) ((sha_info->digest[6] >> 8) & 0xff); + digest[55] = (unsigned char) ((sha_info->digest[6] ) & 0xff); + digest[56] = (unsigned char) ((sha_info->digest[7] >> 56) & 0xff); + digest[57] = (unsigned char) ((sha_info->digest[7] >> 48) & 0xff); + digest[58] = (unsigned char) ((sha_info->digest[7] >> 40) & 0xff); + digest[59] = (unsigned char) ((sha_info->digest[7] >> 32) & 0xff); + digest[60] = (unsigned char) ((sha_info->digest[7] >> 24) & 0xff); + digest[61] = (unsigned char) ((sha_info->digest[7] >> 16) & 0xff); + digest[62] = (unsigned char) ((sha_info->digest[7] >> 8) & 0xff); + digest[63] = (unsigned char) ((sha_info->digest[7] ) & 0xff); +} + +/* + * End of copied SHA code. + * + * ------------------------------------------------------------------------ + */ + +static PyTypeObject SHA384type; +static PyTypeObject SHA512type; + + +static SHAobject * +newSHA384object(void) +{ + return (SHAobject *)PyObject_New(SHAobject, &SHA384type); +} + +static SHAobject * +newSHA512object(void) +{ + return (SHAobject *)PyObject_New(SHAobject, &SHA512type); +} + +/* Internal methods for a hash object */ + +static void +SHA512_dealloc(PyObject *ptr) +{ + PyObject_Del(ptr); +} + + +/* External methods for a hash object */ + +PyDoc_STRVAR(SHA512_copy__doc__, "Return a copy of the hash object."); + +static PyObject * +SHA512_copy(SHAobject *self, PyObject *unused) +{ + SHAobject *newobj; + + if (((PyObject*)self)->ob_type == &SHA512type) { + if ( (newobj = newSHA512object())==NULL) + return NULL; + } else { + if ( (newobj = newSHA384object())==NULL) + return NULL; + } + + SHAcopy(self, newobj); + return (PyObject *)newobj; +} + +PyDoc_STRVAR(SHA512_digest__doc__, +"Return the digest value as a string of binary data."); + +static PyObject * +SHA512_digest(SHAobject *self, PyObject *unused) +{ + unsigned char digest[SHA_DIGESTSIZE]; + SHAobject temp; + + SHAcopy(self, &temp); + sha512_final(digest, &temp); + return PyString_FromStringAndSize((const char *)digest, self->digestsize); +} + +PyDoc_STRVAR(SHA512_hexdigest__doc__, +"Return the digest value as a string of hexadecimal digits."); + +static PyObject * +SHA512_hexdigest(SHAobject *self, PyObject *unused) +{ + unsigned char digest[SHA_DIGESTSIZE]; + SHAobject temp; + PyObject *retval; + char *hex_digest; + int i, j; + + /* Get the raw (binary) digest value */ + SHAcopy(self, &temp); + sha512_final(digest, &temp); + + /* Create a new string */ + retval = PyString_FromStringAndSize(NULL, self->digestsize * 2); + if (!retval) + return NULL; + hex_digest = PyString_AsString(retval); + if (!hex_digest) { + Py_DECREF(retval); + return NULL; + } + + /* Make hex version of the digest */ + for (i=j=0; i<self->digestsize; i++) { + char c; + c = (digest[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + c = (digest[i] & 0xf); + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + } + return retval; +} + +PyDoc_STRVAR(SHA512_update__doc__, +"Update this hash object's state with the provided string."); + +static PyObject * +SHA512_update(SHAobject *self, PyObject *args) +{ + unsigned char *cp; + int len; + + if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + return NULL; + + sha512_update(self, cp, len); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef SHA_methods[] = { + {"copy", (PyCFunction)SHA512_copy, METH_NOARGS, SHA512_copy__doc__}, + {"digest", (PyCFunction)SHA512_digest, METH_NOARGS, SHA512_digest__doc__}, + {"hexdigest", (PyCFunction)SHA512_hexdigest, METH_NOARGS, SHA512_hexdigest__doc__}, + {"update", (PyCFunction)SHA512_update, METH_VARARGS, SHA512_update__doc__}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +SHA512_get_block_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(SHA_BLOCKSIZE); +} + +static PyObject * +SHA512_get_name(PyObject *self, void *closure) +{ + if (((SHAobject *)self)->digestsize == 64) + return PyString_FromStringAndSize("SHA512", 6); + else + return PyString_FromStringAndSize("SHA384", 6); +} + +static PyGetSetDef SHA_getseters[] = { + {"block_size", + (getter)SHA512_get_block_size, NULL, + NULL, + NULL}, + {"name", + (getter)SHA512_get_name, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +}; + +static PyMemberDef SHA_members[] = { + {"digest_size", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, + /* the old md5 and sha modules support 'digest_size' as in PEP 247. + * the old sha module also supported 'digestsize'. ugh. */ + {"digestsize", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject SHA384type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_sha512.sha384", /*tp_name*/ + sizeof(SHAobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + SHA512_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + SHA_methods, /* tp_methods */ + SHA_members, /* tp_members */ + SHA_getseters, /* tp_getset */ +}; + +static PyTypeObject SHA512type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_sha512.sha512", /*tp_name*/ + sizeof(SHAobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + SHA512_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + SHA_methods, /* tp_methods */ + SHA_members, /* tp_members */ + SHA_getseters, /* tp_getset */ +}; + + +/* The single module-level function: new() */ + +PyDoc_STRVAR(SHA512_new__doc__, +"Return a new SHA-512 hash object; optionally initialized with a string."); + +static PyObject * +SHA512_new(PyObject *self, PyObject *args, PyObject *kwdict) +{ + static char *kwlist[] = {"string", NULL}; + SHAobject *new; + unsigned char *cp = NULL; + int len; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, + &cp, &len)) { + return NULL; + } + + if ((new = newSHA512object()) == NULL) + return NULL; + + sha512_init(new); + + if (PyErr_Occurred()) { + Py_DECREF(new); + return NULL; + } + if (cp) + sha512_update(new, cp, len); + + return (PyObject *)new; +} + +PyDoc_STRVAR(SHA384_new__doc__, +"Return a new SHA-384 hash object; optionally initialized with a string."); + +static PyObject * +SHA384_new(PyObject *self, PyObject *args, PyObject *kwdict) +{ + static char *kwlist[] = {"string", NULL}; + SHAobject *new; + unsigned char *cp = NULL; + int len; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, + &cp, &len)) { + return NULL; + } + + if ((new = newSHA384object()) == NULL) + return NULL; + + sha384_init(new); + + if (PyErr_Occurred()) { + Py_DECREF(new); + return NULL; + } + if (cp) + sha512_update(new, cp, len); + + return (PyObject *)new; +} + + +/* List of functions exported by this module */ + +static struct PyMethodDef SHA_functions[] = { + {"sha512", (PyCFunction)SHA512_new, METH_VARARGS|METH_KEYWORDS, SHA512_new__doc__}, + {"sha384", (PyCFunction)SHA384_new, METH_VARARGS|METH_KEYWORDS, SHA384_new__doc__}, + {NULL, NULL} /* Sentinel */ +}; + + +/* Initialize this module. */ + +#define insint(n,v) { PyModule_AddIntConstant(m,n,v); } + +PyMODINIT_FUNC +init_sha512(void) +{ + PyObject *m; + + SHA384type.ob_type = &PyType_Type; + if (PyType_Ready(&SHA384type) < 0) + return; + SHA512type.ob_type = &PyType_Type; + if (PyType_Ready(&SHA512type) < 0) + return; + m = Py_InitModule("_sha512", SHA_functions); + if (m == NULL) + return; +} + +#endif diff --git a/sys/src/cmd/python/Modules/shamodule.c b/sys/src/cmd/python/Modules/shamodule.c new file mode 100644 index 000000000..8d68d16ea --- /dev/null +++ b/sys/src/cmd/python/Modules/shamodule.c @@ -0,0 +1,593 @@ +/* SHA module */ + +/* This module provides an interface to NIST's Secure Hash Algorithm */ + +/* See below for information about the original code this module was + based upon. Additional work performed by: + + Andrew Kuchling (amk@amk.ca) + Greg Stein (gstein@lyra.org) + + Copyright (C) 2005 Gregory P. Smith (greg@electricrain.com) + Licensed to PSF under a Contributor Agreement. + +*/ + +/* SHA objects */ + +#include "Python.h" +#include "structmember.h" + + +/* Endianness testing and definitions */ +#define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ + if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} + +#define PCT_LITTLE_ENDIAN 1 +#define PCT_BIG_ENDIAN 0 + +/* Some useful types */ + +typedef unsigned char SHA_BYTE; + +#if SIZEOF_INT == 4 +typedef unsigned int SHA_INT32; /* 32-bit integer */ +#else +/* not defined. compilation will die. */ +#endif + +/* The SHA block size and message digest sizes, in bytes */ + +#define SHA_BLOCKSIZE 64 +#define SHA_DIGESTSIZE 20 + +/* The structure for storing SHS info */ + +typedef struct { + PyObject_HEAD + SHA_INT32 digest[5]; /* Message digest */ + SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ + SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ + int Endianness; + int local; /* unprocessed amount in data */ +} SHAobject; + +/* When run on a little-endian CPU we need to perform byte reversal on an + array of longwords. */ + +static void longReverse(SHA_INT32 *buffer, int byteCount, int Endianness) +{ + SHA_INT32 value; + + if ( Endianness == PCT_BIG_ENDIAN ) + return; + + byteCount /= sizeof(*buffer); + while (byteCount--) { + value = *buffer; + value = ( ( value & 0xFF00FF00L ) >> 8 ) | \ + ( ( value & 0x00FF00FFL ) << 8 ); + *buffer++ = ( value << 16 ) | ( value >> 16 ); + } +} + +static void SHAcopy(SHAobject *src, SHAobject *dest) +{ + dest->Endianness = src->Endianness; + dest->local = src->local; + dest->count_lo = src->count_lo; + dest->count_hi = src->count_hi; + memcpy(dest->digest, src->digest, sizeof(src->digest)); + memcpy(dest->data, src->data, sizeof(src->data)); +} + + +/* ------------------------------------------------------------------------ + * + * This code for the SHA algorithm was noted as public domain. The original + * headers are pasted below. + * + * Several changes have been made to make it more compatible with the + * Python environment and desired interface. + * + */ + +/* NIST Secure Hash Algorithm */ +/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */ +/* from Peter C. Gutmann's implementation as found in */ +/* Applied Cryptography by Bruce Schneier */ +/* Further modifications to include the "UNRAVEL" stuff, below */ + +/* This code is in the public domain */ + +/* UNRAVEL should be fastest & biggest */ +/* UNROLL_LOOPS should be just as big, but slightly slower */ +/* both undefined should be smallest and slowest */ + +#define UNRAVEL +/* #define UNROLL_LOOPS */ + +/* The SHA f()-functions. The f1 and f3 functions can be optimized to + save one boolean operation each - thanks to Rich Schroeppel, + rcs@cs.arizona.edu for discovering this */ + +/*#define f1(x,y,z) ((x & y) | (~x & z)) // Rounds 0-19 */ +#define f1(x,y,z) (z ^ (x & (y ^ z))) /* Rounds 0-19 */ +#define f2(x,y,z) (x ^ y ^ z) /* Rounds 20-39 */ +/*#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) // Rounds 40-59 */ +#define f3(x,y,z) ((x & y) | (z & (x | y))) /* Rounds 40-59 */ +#define f4(x,y,z) (x ^ y ^ z) /* Rounds 60-79 */ + +/* SHA constants */ + +#define CONST1 0x5a827999L /* Rounds 0-19 */ +#define CONST2 0x6ed9eba1L /* Rounds 20-39 */ +#define CONST3 0x8f1bbcdcL /* Rounds 40-59 */ +#define CONST4 0xca62c1d6L /* Rounds 60-79 */ + +/* 32-bit rotate */ + +#define R32(x,n) ((x << n) | (x >> (32 - n))) + +/* the generic case, for when the overall rotation is not unraveled */ + +#define FG(n) \ + T = R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n; \ + E = D; D = C; C = R32(B,30); B = A; A = T + +/* specific cases, for when the overall rotation is unraveled */ + +#define FA(n) \ + T = R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n; B = R32(B,30) + +#define FB(n) \ + E = R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n; A = R32(A,30) + +#define FC(n) \ + D = R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n; T = R32(T,30) + +#define FD(n) \ + C = R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n; E = R32(E,30) + +#define FE(n) \ + B = R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n; D = R32(D,30) + +#define FT(n) \ + A = R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n; C = R32(C,30) + +/* do SHA transformation */ + +static void +sha_transform(SHAobject *sha_info) +{ + int i; + SHA_INT32 T, A, B, C, D, E, W[80], *WP; + + memcpy(W, sha_info->data, sizeof(sha_info->data)); + longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); + + for (i = 16; i < 80; ++i) { + W[i] = W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16]; + + /* extra rotation fix */ + W[i] = R32(W[i], 1); + } + A = sha_info->digest[0]; + B = sha_info->digest[1]; + C = sha_info->digest[2]; + D = sha_info->digest[3]; + E = sha_info->digest[4]; + WP = W; +#ifdef UNRAVEL + FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); + FE(1); FT(1); FA(1); FB(1); FC(1); FD(1); FE(1); FT(1); FA(1); FB(1); + FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); + FA(2); FB(2); FC(2); FD(2); FE(2); FT(2); FA(2); FB(2); FC(2); FD(2); + FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); + FC(3); FD(3); FE(3); FT(3); FA(3); FB(3); FC(3); FD(3); FE(3); FT(3); + FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); + FE(4); FT(4); FA(4); FB(4); FC(4); FD(4); FE(4); FT(4); FA(4); FB(4); + sha_info->digest[0] += E; + sha_info->digest[1] += T; + sha_info->digest[2] += A; + sha_info->digest[3] += B; + sha_info->digest[4] += C; +#else /* !UNRAVEL */ +#ifdef UNROLL_LOOPS + FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); + FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); FG(1); + FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); + FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); FG(2); + FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); + FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); FG(3); + FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); + FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); FG(4); +#else /* !UNROLL_LOOPS */ + for (i = 0; i < 20; ++i) { FG(1); } + for (i = 20; i < 40; ++i) { FG(2); } + for (i = 40; i < 60; ++i) { FG(3); } + for (i = 60; i < 80; ++i) { FG(4); } +#endif /* !UNROLL_LOOPS */ + sha_info->digest[0] += A; + sha_info->digest[1] += B; + sha_info->digest[2] += C; + sha_info->digest[3] += D; + sha_info->digest[4] += E; +#endif /* !UNRAVEL */ +} + +/* initialize the SHA digest */ + +static void +sha_init(SHAobject *sha_info) +{ + TestEndianness(sha_info->Endianness) + + sha_info->digest[0] = 0x67452301L; + sha_info->digest[1] = 0xefcdab89L; + sha_info->digest[2] = 0x98badcfeL; + sha_info->digest[3] = 0x10325476L; + sha_info->digest[4] = 0xc3d2e1f0L; + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; +} + +/* update the SHA digest */ + +static void +sha_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) +{ + int i; + SHA_INT32 clo; + + clo = sha_info->count_lo + ((SHA_INT32) count << 3); + if (clo < sha_info->count_lo) { + ++sha_info->count_hi; + } + sha_info->count_lo = clo; + sha_info->count_hi += (SHA_INT32) count >> 29; + if (sha_info->local) { + i = SHA_BLOCKSIZE - sha_info->local; + if (i > count) { + i = count; + } + memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); + count -= i; + buffer += i; + sha_info->local += i; + if (sha_info->local == SHA_BLOCKSIZE) { + sha_transform(sha_info); + } + else { + return; + } + } + while (count >= SHA_BLOCKSIZE) { + memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); + buffer += SHA_BLOCKSIZE; + count -= SHA_BLOCKSIZE; + sha_transform(sha_info); + } + memcpy(sha_info->data, buffer, count); + sha_info->local = count; +} + +/* finish computing the SHA digest */ + +static void +sha_final(unsigned char digest[20], SHAobject *sha_info) +{ + int count; + SHA_INT32 lo_bit_count, hi_bit_count; + + lo_bit_count = sha_info->count_lo; + hi_bit_count = sha_info->count_hi; + count = (int) ((lo_bit_count >> 3) & 0x3f); + ((SHA_BYTE *) sha_info->data)[count++] = 0x80; + if (count > SHA_BLOCKSIZE - 8) { + memset(((SHA_BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - count); + sha_transform(sha_info); + memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); + } + else { + memset(((SHA_BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - 8 - count); + } + + /* GJS: note that we add the hi/lo in big-endian. sha_transform will + swap these values into host-order. */ + sha_info->data[56] = (hi_bit_count >> 24) & 0xff; + sha_info->data[57] = (hi_bit_count >> 16) & 0xff; + sha_info->data[58] = (hi_bit_count >> 8) & 0xff; + sha_info->data[59] = (hi_bit_count >> 0) & 0xff; + sha_info->data[60] = (lo_bit_count >> 24) & 0xff; + sha_info->data[61] = (lo_bit_count >> 16) & 0xff; + sha_info->data[62] = (lo_bit_count >> 8) & 0xff; + sha_info->data[63] = (lo_bit_count >> 0) & 0xff; + sha_transform(sha_info); + digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); + digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); + digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); + digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff); + digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); + digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); + digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); + digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff); + digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); + digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); + digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); + digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff); + digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); + digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); + digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); + digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff); + digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); + digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); + digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); + digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); +} + +/* + * End of copied SHA code. + * + * ------------------------------------------------------------------------ + */ + +static PyTypeObject SHAtype; + + +static SHAobject * +newSHAobject(void) +{ + return (SHAobject *)PyObject_New(SHAobject, &SHAtype); +} + +/* Internal methods for a hashing object */ + +static void +SHA_dealloc(PyObject *ptr) +{ + PyObject_Del(ptr); +} + + +/* External methods for a hashing object */ + +PyDoc_STRVAR(SHA_copy__doc__, "Return a copy of the hashing object."); + +static PyObject * +SHA_copy(SHAobject *self, PyObject *unused) +{ + SHAobject *newobj; + + if ( (newobj = newSHAobject())==NULL) + return NULL; + + SHAcopy(self, newobj); + return (PyObject *)newobj; +} + +PyDoc_STRVAR(SHA_digest__doc__, +"Return the digest value as a string of binary data."); + +static PyObject * +SHA_digest(SHAobject *self, PyObject *unused) +{ + unsigned char digest[SHA_DIGESTSIZE]; + SHAobject temp; + + SHAcopy(self, &temp); + sha_final(digest, &temp); + return PyString_FromStringAndSize((const char *)digest, sizeof(digest)); +} + +PyDoc_STRVAR(SHA_hexdigest__doc__, +"Return the digest value as a string of hexadecimal digits."); + +static PyObject * +SHA_hexdigest(SHAobject *self, PyObject *unused) +{ + unsigned char digest[SHA_DIGESTSIZE]; + SHAobject temp; + PyObject *retval; + char *hex_digest; + int i, j; + + /* Get the raw (binary) digest value */ + SHAcopy(self, &temp); + sha_final(digest, &temp); + + /* Create a new string */ + retval = PyString_FromStringAndSize(NULL, sizeof(digest) * 2); + if (!retval) + return NULL; + hex_digest = PyString_AsString(retval); + if (!hex_digest) { + Py_DECREF(retval); + return NULL; + } + + /* Make hex version of the digest */ + for(i=j=0; i<sizeof(digest); i++) { + char c; + c = (digest[i] >> 4) & 0xf; + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + c = (digest[i] & 0xf); + c = (c>9) ? c+'a'-10 : c + '0'; + hex_digest[j++] = c; + } + return retval; +} + +PyDoc_STRVAR(SHA_update__doc__, +"Update this hashing object's state with the provided string."); + +static PyObject * +SHA_update(SHAobject *self, PyObject *args) +{ + unsigned char *cp; + int len; + + if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) + return NULL; + + sha_update(self, cp, len); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef SHA_methods[] = { + {"copy", (PyCFunction)SHA_copy, METH_NOARGS, SHA_copy__doc__}, + {"digest", (PyCFunction)SHA_digest, METH_NOARGS, SHA_digest__doc__}, + {"hexdigest", (PyCFunction)SHA_hexdigest, METH_NOARGS, SHA_hexdigest__doc__}, + {"update", (PyCFunction)SHA_update, METH_VARARGS, SHA_update__doc__}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +SHA_get_block_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(SHA_BLOCKSIZE); +} + +static PyObject * +SHA_get_digest_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(SHA_DIGESTSIZE); +} + +static PyObject * +SHA_get_name(PyObject *self, void *closure) +{ + return PyString_FromStringAndSize("SHA1", 4); +} + +static PyGetSetDef SHA_getseters[] = { + {"digest_size", + (getter)SHA_get_digest_size, NULL, + NULL, + NULL}, + {"block_size", + (getter)SHA_get_block_size, NULL, + NULL, + NULL}, + {"name", + (getter)SHA_get_name, NULL, + NULL, + NULL}, + /* the old md5 and sha modules support 'digest_size' as in PEP 247. + * the old sha module also supported 'digestsize'. ugh. */ + {"digestsize", + (getter)SHA_get_digest_size, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject SHAtype = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_sha.sha", /*tp_name*/ + sizeof(SHAobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + SHA_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + SHA_methods, /* tp_methods */ + 0, /* tp_members */ + SHA_getseters, /* tp_getset */ +}; + + +/* The single module-level function: new() */ + +PyDoc_STRVAR(SHA_new__doc__, +"Return a new SHA hashing object. An optional string argument\n\ +may be provided; if present, this string will be automatically\n\ +hashed."); + +static PyObject * +SHA_new(PyObject *self, PyObject *args, PyObject *kwdict) +{ + static char *kwlist[] = {"string", NULL}; + SHAobject *new; + unsigned char *cp = NULL; + int len; + + if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, + &cp, &len)) { + return NULL; + } + + if ((new = newSHAobject()) == NULL) + return NULL; + + sha_init(new); + + if (PyErr_Occurred()) { + Py_DECREF(new); + return NULL; + } + if (cp) + sha_update(new, cp, len); + + return (PyObject *)new; +} + + +/* List of functions exported by this module */ + +static struct PyMethodDef SHA_functions[] = { + {"new", (PyCFunction)SHA_new, METH_VARARGS|METH_KEYWORDS, SHA_new__doc__}, + {NULL, NULL} /* Sentinel */ +}; + + +/* Initialize this module. */ + +#define insint(n,v) { PyModule_AddIntConstant(m,n,v); } + +PyMODINIT_FUNC +init_sha(void) +{ + PyObject *m; + + SHAtype.ob_type = &PyType_Type; + if (PyType_Ready(&SHAtype) < 0) + return; + m = Py_InitModule("_sha", SHA_functions); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + insint("blocksize", 1); /* For future use, in case some hash + functions require an integral number of + blocks */ + insint("digestsize", 20); + insint("digest_size", 20); +} diff --git a/sys/src/cmd/python/Modules/signalmodule.c b/sys/src/cmd/python/Modules/signalmodule.c new file mode 100644 index 000000000..a729604a3 --- /dev/null +++ b/sys/src/cmd/python/Modules/signalmodule.c @@ -0,0 +1,676 @@ + +/* Signal module -- many thanks to Lance Ellinghaus */ + +/* XXX Signals should be recorded per thread, now we have thread state. */ + +#include "Python.h" +#include "intrcheck.h" + +#ifdef MS_WINDOWS +#include <process.h> +#endif + +#include <signal.h> + +#ifndef SIG_ERR +#define SIG_ERR ((PyOS_sighandler_t)(-1)) +#endif + +#if defined(PYOS_OS2) && !defined(PYCC_GCC) +#define NSIG 12 +#include <process.h> +#endif + +#ifndef NSIG +# if defined(_NSIG) +# define NSIG _NSIG /* For BSD/SysV */ +# elif defined(_SIGMAX) +# define NSIG (_SIGMAX + 1) /* For QNX */ +# elif defined(SIGMAX) +# define NSIG (SIGMAX + 1) /* For djgpp */ +# else +# define NSIG 64 /* Use a reasonable default value */ +# endif +#endif + + +/* + NOTES ON THE INTERACTION BETWEEN SIGNALS AND THREADS + + When threads are supported, we want the following semantics: + + - only the main thread can set a signal handler + - any thread can get a signal handler + - signals are only delivered to the main thread + + I.e. we don't support "synchronous signals" like SIGFPE (catching + this doesn't make much sense in Python anyway) nor do we support + signals as a means of inter-thread communication, since not all + thread implementations support that (at least our thread library + doesn't). + + We still have the problem that in some implementations signals + generated by the keyboard (e.g. SIGINT) are delivered to all + threads (e.g. SGI), while in others (e.g. Solaris) such signals are + delivered to one random thread (an intermediate possibility would + be to deliver it to the main thread -- POSIX?). For now, we have + a working implementation that works in all three cases -- the + handler ignores signals if getpid() isn't the same as in the main + thread. XXX This is a hack. + + GNU pth is a user-space threading library, and as such, all threads + run within the same process. In this case, if the currently running + thread is not the main_thread, send the signal to the main_thread. +*/ + +#ifdef WITH_THREAD +#include <sys/types.h> /* For pid_t */ +#include "pythread.h" +static long main_thread; +static pid_t main_pid; +#endif + +static struct { + int tripped; + PyObject *func; +} Handlers[NSIG]; + +static int is_tripped = 0; /* Speed up sigcheck() when none tripped */ + +static PyObject *DefaultHandler; +static PyObject *IgnoreHandler; +static PyObject *IntHandler; + +/* On Solaris 8, gcc will produce a warning that the function + declaration is not a prototype. This is caused by the definition of + SIG_DFL as (void (*)())0; the correct declaration would have been + (void (*)(int))0. */ + +static PyOS_sighandler_t old_siginthandler = SIG_DFL; + + +static PyObject * +signal_default_int_handler(PyObject *self, PyObject *args) +{ + PyErr_SetNone(PyExc_KeyboardInterrupt); + return NULL; +} + +PyDoc_STRVAR(default_int_handler_doc, +"default_int_handler(...)\n\ +\n\ +The default handler for SIGINT installed by Python.\n\ +It raises KeyboardInterrupt."); + + +static int +checksignals_witharg(void * unused) +{ + return PyErr_CheckSignals(); +} + +static void +signal_handler(int sig_num) +{ +#ifdef WITH_THREAD +#ifdef WITH_PTH + if (PyThread_get_thread_ident() != main_thread) { + pth_raise(*(pth_t *) main_thread, sig_num); + return; + } +#endif + /* See NOTES section above */ + if (getpid() == main_pid) { +#endif + is_tripped++; + Handlers[sig_num].tripped = 1; + Py_AddPendingCall(checksignals_witharg, NULL); +#ifdef WITH_THREAD + } +#endif +#ifdef SIGCHLD + if (sig_num == SIGCHLD) { + /* To avoid infinite recursion, this signal remains + reset until explicit re-instated. + Don't clear the 'func' field as it is our pointer + to the Python handler... */ + return; + } +#endif + PyOS_setsig(sig_num, signal_handler); +} + + +#ifdef HAVE_ALARM +static PyObject * +signal_alarm(PyObject *self, PyObject *args) +{ + int t; + if (!PyArg_ParseTuple(args, "i:alarm", &t)) + return NULL; + /* alarm() returns the number of seconds remaining */ + return PyInt_FromLong((long)alarm(t)); +} + +PyDoc_STRVAR(alarm_doc, +"alarm(seconds)\n\ +\n\ +Arrange for SIGALRM to arrive after the given number of seconds."); +#endif + +#ifdef HAVE_PAUSE +static PyObject * +signal_pause(PyObject *self) +{ + Py_BEGIN_ALLOW_THREADS + (void)pause(); + Py_END_ALLOW_THREADS + /* make sure that any exceptions that got raised are propagated + * back into Python + */ + if (PyErr_CheckSignals()) + return NULL; + + Py_INCREF(Py_None); + return Py_None; +} +PyDoc_STRVAR(pause_doc, +"pause()\n\ +\n\ +Wait until a signal arrives."); + +#endif + + +static PyObject * +signal_signal(PyObject *self, PyObject *args) +{ + PyObject *obj; + int sig_num; + PyObject *old_handler; + void (*func)(int); + if (!PyArg_ParseTuple(args, "iO:signal", &sig_num, &obj)) + return NULL; +#ifdef WITH_THREAD + if (PyThread_get_thread_ident() != main_thread) { + PyErr_SetString(PyExc_ValueError, + "signal only works in main thread"); + return NULL; + } +#endif + if (sig_num < 1 || sig_num >= NSIG) { + PyErr_SetString(PyExc_ValueError, + "signal number out of range"); + return NULL; + } + if (obj == IgnoreHandler) + func = SIG_IGN; + else if (obj == DefaultHandler) + func = SIG_DFL; + else if (!PyCallable_Check(obj)) { + PyErr_SetString(PyExc_TypeError, +"signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object"); + return NULL; + } + else + func = signal_handler; + if (PyOS_setsig(sig_num, func) == SIG_ERR) { + PyErr_SetFromErrno(PyExc_RuntimeError); + return NULL; + } + old_handler = Handlers[sig_num].func; + Handlers[sig_num].tripped = 0; + Py_INCREF(obj); + Handlers[sig_num].func = obj; + return old_handler; +} + +PyDoc_STRVAR(signal_doc, +"signal(sig, action) -> action\n\ +\n\ +Set the action for the given signal. The action can be SIG_DFL,\n\ +SIG_IGN, or a callable Python object. The previous action is\n\ +returned. See getsignal() for possible return values.\n\ +\n\ +*** IMPORTANT NOTICE ***\n\ +A signal handler function is called with two arguments:\n\ +the first is the signal number, the second is the interrupted stack frame."); + + +static PyObject * +signal_getsignal(PyObject *self, PyObject *args) +{ + int sig_num; + PyObject *old_handler; + if (!PyArg_ParseTuple(args, "i:getsignal", &sig_num)) + return NULL; + if (sig_num < 1 || sig_num >= NSIG) { + PyErr_SetString(PyExc_ValueError, + "signal number out of range"); + return NULL; + } + old_handler = Handlers[sig_num].func; + Py_INCREF(old_handler); + return old_handler; +} + +PyDoc_STRVAR(getsignal_doc, +"getsignal(sig) -> action\n\ +\n\ +Return the current action for the given signal. The return value can be:\n\ +SIG_IGN -- if the signal is being ignored\n\ +SIG_DFL -- if the default action for the signal is in effect\n\ +None -- if an unknown handler is in effect\n\ +anything else -- the callable Python object used as a handler"); + + +/* List of functions defined in the module */ +static PyMethodDef signal_methods[] = { +#ifdef HAVE_ALARM + {"alarm", signal_alarm, METH_VARARGS, alarm_doc}, +#endif + {"signal", signal_signal, METH_VARARGS, signal_doc}, + {"getsignal", signal_getsignal, METH_VARARGS, getsignal_doc}, +#ifdef HAVE_PAUSE + {"pause", (PyCFunction)signal_pause, + METH_NOARGS,pause_doc}, +#endif + {"default_int_handler", signal_default_int_handler, + METH_VARARGS, default_int_handler_doc}, + {NULL, NULL} /* sentinel */ +}; + + +PyDoc_STRVAR(module_doc, +"This module provides mechanisms to use signal handlers in Python.\n\ +\n\ +Functions:\n\ +\n\ +alarm() -- cause SIGALRM after a specified time [Unix only]\n\ +signal() -- set the action for a given signal\n\ +getsignal() -- get the signal action for a given signal\n\ +pause() -- wait until a signal arrives [Unix only]\n\ +default_int_handler() -- default SIGINT handler\n\ +\n\ +Constants:\n\ +\n\ +SIG_DFL -- used to refer to the system default handler\n\ +SIG_IGN -- used to ignore the signal\n\ +NSIG -- number of defined signals\n\ +\n\ +SIGINT, SIGTERM, etc. -- signal numbers\n\ +\n\ +*** IMPORTANT NOTICE ***\n\ +A signal handler function is called with two arguments:\n\ +the first is the signal number, the second is the interrupted stack frame."); + +PyMODINIT_FUNC +initsignal(void) +{ + PyObject *m, *d, *x; + int i; + +#ifdef WITH_THREAD + main_thread = PyThread_get_thread_ident(); + main_pid = getpid(); +#endif + + /* Create the module and add the functions */ + m = Py_InitModule3("signal", signal_methods, module_doc); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + + x = DefaultHandler = PyLong_FromVoidPtr((void *)SIG_DFL); + if (!x || PyDict_SetItemString(d, "SIG_DFL", x) < 0) + goto finally; + + x = IgnoreHandler = PyLong_FromVoidPtr((void *)SIG_IGN); + if (!x || PyDict_SetItemString(d, "SIG_IGN", x) < 0) + goto finally; + + x = PyInt_FromLong((long)NSIG); + if (!x || PyDict_SetItemString(d, "NSIG", x) < 0) + goto finally; + Py_DECREF(x); + + x = IntHandler = PyDict_GetItemString(d, "default_int_handler"); + if (!x) + goto finally; + Py_INCREF(IntHandler); + + Handlers[0].tripped = 0; + for (i = 1; i < NSIG; i++) { + void (*t)(int); + t = PyOS_getsig(i); + Handlers[i].tripped = 0; + if (t == SIG_DFL) + Handlers[i].func = DefaultHandler; + else if (t == SIG_IGN) + Handlers[i].func = IgnoreHandler; + else + Handlers[i].func = Py_None; /* None of our business */ + Py_INCREF(Handlers[i].func); + } + if (Handlers[SIGINT].func == DefaultHandler) { + /* Install default int handler */ + Py_INCREF(IntHandler); + Py_DECREF(Handlers[SIGINT].func); + Handlers[SIGINT].func = IntHandler; + old_siginthandler = PyOS_setsig(SIGINT, signal_handler); + } + +#ifdef SIGHUP + x = PyInt_FromLong(SIGHUP); + PyDict_SetItemString(d, "SIGHUP", x); + Py_XDECREF(x); +#endif +#ifdef SIGINT + x = PyInt_FromLong(SIGINT); + PyDict_SetItemString(d, "SIGINT", x); + Py_XDECREF(x); +#endif +#ifdef SIGBREAK + x = PyInt_FromLong(SIGBREAK); + PyDict_SetItemString(d, "SIGBREAK", x); + Py_XDECREF(x); +#endif +#ifdef SIGQUIT + x = PyInt_FromLong(SIGQUIT); + PyDict_SetItemString(d, "SIGQUIT", x); + Py_XDECREF(x); +#endif +#ifdef SIGILL + x = PyInt_FromLong(SIGILL); + PyDict_SetItemString(d, "SIGILL", x); + Py_XDECREF(x); +#endif +#ifdef SIGTRAP + x = PyInt_FromLong(SIGTRAP); + PyDict_SetItemString(d, "SIGTRAP", x); + Py_XDECREF(x); +#endif +#ifdef SIGIOT + x = PyInt_FromLong(SIGIOT); + PyDict_SetItemString(d, "SIGIOT", x); + Py_XDECREF(x); +#endif +#ifdef SIGABRT + x = PyInt_FromLong(SIGABRT); + PyDict_SetItemString(d, "SIGABRT", x); + Py_XDECREF(x); +#endif +#ifdef SIGEMT + x = PyInt_FromLong(SIGEMT); + PyDict_SetItemString(d, "SIGEMT", x); + Py_XDECREF(x); +#endif +#ifdef SIGFPE + x = PyInt_FromLong(SIGFPE); + PyDict_SetItemString(d, "SIGFPE", x); + Py_XDECREF(x); +#endif +#ifdef SIGKILL + x = PyInt_FromLong(SIGKILL); + PyDict_SetItemString(d, "SIGKILL", x); + Py_XDECREF(x); +#endif +#ifdef SIGBUS + x = PyInt_FromLong(SIGBUS); + PyDict_SetItemString(d, "SIGBUS", x); + Py_XDECREF(x); +#endif +#ifdef SIGSEGV + x = PyInt_FromLong(SIGSEGV); + PyDict_SetItemString(d, "SIGSEGV", x); + Py_XDECREF(x); +#endif +#ifdef SIGSYS + x = PyInt_FromLong(SIGSYS); + PyDict_SetItemString(d, "SIGSYS", x); + Py_XDECREF(x); +#endif +#ifdef SIGPIPE + x = PyInt_FromLong(SIGPIPE); + PyDict_SetItemString(d, "SIGPIPE", x); + Py_XDECREF(x); +#endif +#ifdef SIGALRM + x = PyInt_FromLong(SIGALRM); + PyDict_SetItemString(d, "SIGALRM", x); + Py_XDECREF(x); +#endif +#ifdef SIGTERM + x = PyInt_FromLong(SIGTERM); + PyDict_SetItemString(d, "SIGTERM", x); + Py_XDECREF(x); +#endif +#ifdef SIGUSR1 + x = PyInt_FromLong(SIGUSR1); + PyDict_SetItemString(d, "SIGUSR1", x); + Py_XDECREF(x); +#endif +#ifdef SIGUSR2 + x = PyInt_FromLong(SIGUSR2); + PyDict_SetItemString(d, "SIGUSR2", x); + Py_XDECREF(x); +#endif +#ifdef SIGCLD + x = PyInt_FromLong(SIGCLD); + PyDict_SetItemString(d, "SIGCLD", x); + Py_XDECREF(x); +#endif +#ifdef SIGCHLD + x = PyInt_FromLong(SIGCHLD); + PyDict_SetItemString(d, "SIGCHLD", x); + Py_XDECREF(x); +#endif +#ifdef SIGPWR + x = PyInt_FromLong(SIGPWR); + PyDict_SetItemString(d, "SIGPWR", x); + Py_XDECREF(x); +#endif +#ifdef SIGIO + x = PyInt_FromLong(SIGIO); + PyDict_SetItemString(d, "SIGIO", x); + Py_XDECREF(x); +#endif +#ifdef SIGURG + x = PyInt_FromLong(SIGURG); + PyDict_SetItemString(d, "SIGURG", x); + Py_XDECREF(x); +#endif +#ifdef SIGWINCH + x = PyInt_FromLong(SIGWINCH); + PyDict_SetItemString(d, "SIGWINCH", x); + Py_XDECREF(x); +#endif +#ifdef SIGPOLL + x = PyInt_FromLong(SIGPOLL); + PyDict_SetItemString(d, "SIGPOLL", x); + Py_XDECREF(x); +#endif +#ifdef SIGSTOP + x = PyInt_FromLong(SIGSTOP); + PyDict_SetItemString(d, "SIGSTOP", x); + Py_XDECREF(x); +#endif +#ifdef SIGTSTP + x = PyInt_FromLong(SIGTSTP); + PyDict_SetItemString(d, "SIGTSTP", x); + Py_XDECREF(x); +#endif +#ifdef SIGCONT + x = PyInt_FromLong(SIGCONT); + PyDict_SetItemString(d, "SIGCONT", x); + Py_XDECREF(x); +#endif +#ifdef SIGTTIN + x = PyInt_FromLong(SIGTTIN); + PyDict_SetItemString(d, "SIGTTIN", x); + Py_XDECREF(x); +#endif +#ifdef SIGTTOU + x = PyInt_FromLong(SIGTTOU); + PyDict_SetItemString(d, "SIGTTOU", x); + Py_XDECREF(x); +#endif +#ifdef SIGVTALRM + x = PyInt_FromLong(SIGVTALRM); + PyDict_SetItemString(d, "SIGVTALRM", x); + Py_XDECREF(x); +#endif +#ifdef SIGPROF + x = PyInt_FromLong(SIGPROF); + PyDict_SetItemString(d, "SIGPROF", x); + Py_XDECREF(x); +#endif +#ifdef SIGXCPU + x = PyInt_FromLong(SIGXCPU); + PyDict_SetItemString(d, "SIGXCPU", x); + Py_XDECREF(x); +#endif +#ifdef SIGXFSZ + x = PyInt_FromLong(SIGXFSZ); + PyDict_SetItemString(d, "SIGXFSZ", x); + Py_XDECREF(x); +#endif +#ifdef SIGRTMIN + x = PyInt_FromLong(SIGRTMIN); + PyDict_SetItemString(d, "SIGRTMIN", x); + Py_XDECREF(x); +#endif +#ifdef SIGRTMAX + x = PyInt_FromLong(SIGRTMAX); + PyDict_SetItemString(d, "SIGRTMAX", x); + Py_XDECREF(x); +#endif +#ifdef SIGINFO + x = PyInt_FromLong(SIGINFO); + PyDict_SetItemString(d, "SIGINFO", x); + Py_XDECREF(x); +#endif + if (!PyErr_Occurred()) + return; + + /* Check for errors */ + finally: + return; +} + +static void +finisignal(void) +{ + int i; + PyObject *func; + + PyOS_setsig(SIGINT, old_siginthandler); + old_siginthandler = SIG_DFL; + + for (i = 1; i < NSIG; i++) { + func = Handlers[i].func; + Handlers[i].tripped = 0; + Handlers[i].func = NULL; + if (i != SIGINT && func != NULL && func != Py_None && + func != DefaultHandler && func != IgnoreHandler) + PyOS_setsig(i, SIG_DFL); + Py_XDECREF(func); + } + + Py_XDECREF(IntHandler); + IntHandler = NULL; + Py_XDECREF(DefaultHandler); + DefaultHandler = NULL; + Py_XDECREF(IgnoreHandler); + IgnoreHandler = NULL; +} + + +/* Declared in pyerrors.h */ +int +PyErr_CheckSignals(void) +{ + int i; + PyObject *f; + + if (!is_tripped) + return 0; +#ifdef WITH_THREAD + if (PyThread_get_thread_ident() != main_thread) + return 0; +#endif + if (!(f = (PyObject *)PyEval_GetFrame())) + f = Py_None; + + for (i = 1; i < NSIG; i++) { + if (Handlers[i].tripped) { + PyObject *result = NULL; + PyObject *arglist = Py_BuildValue("(iO)", i, f); + Handlers[i].tripped = 0; + + if (arglist) { + result = PyEval_CallObject(Handlers[i].func, + arglist); + Py_DECREF(arglist); + } + if (!result) + return -1; + + Py_DECREF(result); + } + } + is_tripped = 0; + return 0; +} + + +/* Replacements for intrcheck.c functionality + * Declared in pyerrors.h + */ +void +PyErr_SetInterrupt(void) +{ + is_tripped++; + Handlers[SIGINT].tripped = 1; + Py_AddPendingCall((int (*)(void *))PyErr_CheckSignals, NULL); +} + +void +PyOS_InitInterrupts(void) +{ + initsignal(); + _PyImport_FixupExtension("signal", "signal"); +} + +void +PyOS_FiniInterrupts(void) +{ + finisignal(); +} + +int +PyOS_InterruptOccurred(void) +{ + if (Handlers[SIGINT].tripped) { +#ifdef WITH_THREAD + if (PyThread_get_thread_ident() != main_thread) + return 0; +#endif + Handlers[SIGINT].tripped = 0; + return 1; + } + return 0; +} + +void +PyOS_AfterFork(void) +{ +#ifdef WITH_THREAD + PyEval_ReInitThreads(); + main_thread = PyThread_get_thread_ident(); + main_pid = getpid(); + _PyImport_ReInitLock(); +#endif +} diff --git a/sys/src/cmd/python/Modules/socketmodule.c b/sys/src/cmd/python/Modules/socketmodule.c new file mode 100644 index 000000000..892ee7b16 --- /dev/null +++ b/sys/src/cmd/python/Modules/socketmodule.c @@ -0,0 +1,5100 @@ +/* Socket module */ + +/* + +This module provides an interface to Berkeley socket IPC. + +Limitations: + +- Only AF_INET, AF_INET6 and AF_UNIX address families are supported in a + portable manner, though AF_PACKET and AF_NETLINK are supported under Linux. +- No read/write operations (use sendall/recv or makefile instead). +- Additional restrictions apply on some non-Unix platforms (compensated + for by socket.py). + +Module interface: + +- socket.error: exception raised for socket specific errors +- socket.gaierror: exception raised for getaddrinfo/getnameinfo errors, + a subclass of socket.error +- socket.herror: exception raised for gethostby* errors, + a subclass of socket.error +- socket.fromfd(fd, family, type[, proto]) --> new socket object (created + from an existing file descriptor) +- socket.gethostbyname(hostname) --> host IP address (string: 'dd.dd.dd.dd') +- socket.gethostbyaddr(IP address) --> (hostname, [alias, ...], [IP addr, ...]) +- socket.gethostname() --> host name (string: 'spam' or 'spam.domain.com') +- socket.getprotobyname(protocolname) --> protocol number +- socket.getservbyname(servicename[, protocolname]) --> port number +- socket.getservbyport(portnumber[, protocolname]) --> service name +- socket.socket([family[, type [, proto]]]) --> new socket object +- socket.socketpair([family[, type [, proto]]]) --> (socket, socket) +- socket.ntohs(16 bit value) --> new int object +- socket.ntohl(32 bit value) --> new int object +- socket.htons(16 bit value) --> new int object +- socket.htonl(32 bit value) --> new int object +- socket.getaddrinfo(host, port [, family, socktype, proto, flags]) + --> List of (family, socktype, proto, canonname, sockaddr) +- socket.getnameinfo(sockaddr, flags) --> (host, port) +- socket.AF_INET, socket.SOCK_STREAM, etc.: constants from <socket.h> +- socket.has_ipv6: boolean value indicating if IPv6 is supported +- socket.inet_aton(IP address) -> 32-bit packed IP representation +- socket.inet_ntoa(packed IP) -> IP address string +- socket.getdefaulttimeout() -> None | float +- socket.setdefaulttimeout(None | float) +- an Internet socket address is a pair (hostname, port) + where hostname can be anything recognized by gethostbyname() + (including the dd.dd.dd.dd notation) and port is in host byte order +- where a hostname is returned, the dd.dd.dd.dd notation is used +- a UNIX domain socket address is a string specifying the pathname +- an AF_PACKET socket address is a tuple containing a string + specifying the ethernet interface and an integer specifying + the Ethernet protocol number to be received. For example: + ("eth0",0x1234). Optional 3rd,4th,5th elements in the tuple + specify packet-type and ha-type/addr. + +Local naming conventions: + +- names starting with sock_ are socket object methods +- names starting with socket_ are module-level functions +- names starting with PySocket are exported through socketmodule.h + +*/ + +#ifdef __APPLE__ + /* + * inet_aton is not available on OSX 10.3, yet we want to use a binary + * that was build on 10.4 or later to work on that release, weak linking + * comes to the rescue. + */ +# pragma weak inet_aton +#endif + +#include "Python.h" +#include "structmember.h" + +#undef MAX +#define MAX(x, y) ((x) < (y) ? (y) : (x)) + +/* Socket object documentation */ +PyDoc_STRVAR(sock_doc, +"socket([family[, type[, proto]]]) -> socket object\n\ +\n\ +Open a socket of the given type. The family argument specifies the\n\ +address family; it defaults to AF_INET. The type argument specifies\n\ +whether this is a stream (SOCK_STREAM, this is the default)\n\ +or datagram (SOCK_DGRAM) socket. The protocol argument defaults to 0,\n\ +specifying the default protocol. Keyword arguments are accepted.\n\ +\n\ +A socket object represents one endpoint of a network connection.\n\ +\n\ +Methods of socket objects (keyword arguments not allowed):\n\ +\n\ +accept() -- accept a connection, returning new socket and client address\n\ +bind(addr) -- bind the socket to a local address\n\ +close() -- close the socket\n\ +connect(addr) -- connect the socket to a remote address\n\ +connect_ex(addr) -- connect, return an error code instead of an exception\n\ +dup() -- return a new socket object identical to the current one [*]\n\ +fileno() -- return underlying file descriptor\n\ +getpeername() -- return remote address [*]\n\ +getsockname() -- return local address\n\ +getsockopt(level, optname[, buflen]) -- get socket options\n\ +gettimeout() -- return timeout or None\n\ +listen(n) -- start listening for incoming connections\n\ +makefile([mode, [bufsize]]) -- return a file object for the socket [*]\n\ +recv(buflen[, flags]) -- receive data\n\ +recv_into(buffer[, nbytes[, flags]]) -- receive data (into a buffer)\n\ +recvfrom(buflen[, flags]) -- receive data and sender\'s address\n\ +recvfrom_into(buffer[, nbytes, [, flags])\n\ + -- receive data and sender\'s address (into a buffer)\n\ +sendall(data[, flags]) -- send all data\n\ +send(data[, flags]) -- send data, may not send all of it\n\ +sendto(data[, flags], addr) -- send data to a given address\n\ +setblocking(0 | 1) -- set or clear the blocking I/O flag\n\ +setsockopt(level, optname, value) -- set socket options\n\ +settimeout(None | float) -- set or clear the timeout\n\ +shutdown(how) -- shut down traffic in one or both directions\n\ +\n\ + [*] not available on all platforms!"); + +/* XXX This is a terrible mess of platform-dependent preprocessor hacks. + I hope some day someone can clean this up please... */ + +/* Hacks for gethostbyname_r(). On some non-Linux platforms, the configure + script doesn't get this right, so we hardcode some platform checks below. + On the other hand, not all Linux versions agree, so there the settings + computed by the configure script are needed! */ + +#ifndef linux +# undef HAVE_GETHOSTBYNAME_R_3_ARG +# undef HAVE_GETHOSTBYNAME_R_5_ARG +# undef HAVE_GETHOSTBYNAME_R_6_ARG +#endif + +#ifndef WITH_THREAD +# undef HAVE_GETHOSTBYNAME_R +#endif + +#ifdef HAVE_GETHOSTBYNAME_R +# if defined(_AIX) || defined(__osf__) +# define HAVE_GETHOSTBYNAME_R_3_ARG +# elif defined(__sun) || defined(__sgi) +# define HAVE_GETHOSTBYNAME_R_5_ARG +# elif defined(linux) +/* Rely on the configure script */ +# else +# undef HAVE_GETHOSTBYNAME_R +# endif +#endif + +#if !defined(HAVE_GETHOSTBYNAME_R) && defined(WITH_THREAD) && \ + !defined(MS_WINDOWS) +# define USE_GETHOSTBYNAME_LOCK +#endif + +/* To use __FreeBSD_version */ +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +/* On systems on which getaddrinfo() is believed to not be thread-safe, + (this includes the getaddrinfo emulation) protect access with a lock. */ +#if defined(WITH_THREAD) && (defined(__APPLE__) || \ + (defined(__FreeBSD__) && __FreeBSD_version+0 < 503000) || \ + defined(__OpenBSD__) || defined(__NetBSD__) || \ + defined(__VMS) || !defined(HAVE_GETADDRINFO)) +#define USE_GETADDRINFO_LOCK +#endif + +#ifdef USE_GETADDRINFO_LOCK +#define ACQUIRE_GETADDRINFO_LOCK PyThread_acquire_lock(netdb_lock, 1); +#define RELEASE_GETADDRINFO_LOCK PyThread_release_lock(netdb_lock); +#else +#define ACQUIRE_GETADDRINFO_LOCK +#define RELEASE_GETADDRINFO_LOCK +#endif + +#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK) +# include "pythread.h" +#endif + +#if defined(PYCC_VACPP) +# include <types.h> +# include <io.h> +# include <sys/ioctl.h> +# include <utils.h> +# include <ctype.h> +#endif + +#if defined(__VMS) +# include <ioctl.h> +#endif + +#if defined(PYOS_OS2) +# define INCL_DOS +# define INCL_DOSERRORS +# define INCL_NOPMAPI +# include <os2.h> +#endif + +#if defined(__sgi) && _COMPILER_VERSION>700 && !_SGIAPI +/* make sure that the reentrant (gethostbyaddr_r etc) + functions are declared correctly if compiling with + MIPSPro 7.x in ANSI C mode (default) */ + +/* XXX Using _SGIAPI is the wrong thing, + but I don't know what the right thing is. */ +#undef _SGIAPI /* to avoid warning */ +#define _SGIAPI 1 + +#undef _XOPEN_SOURCE +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +#ifdef _SS_ALIGNSIZE +#define HAVE_GETADDRINFO 1 +#define HAVE_GETNAMEINFO 1 +#endif + +#define HAVE_INET_PTON +#include <netdb.h> +#endif + +/* Irix 6.5 fails to define this variable at all. This is needed + for both GCC and SGI's compiler. I'd say that the SGI headers + are just busted. Same thing for Solaris. */ +#if (defined(__sgi) || defined(sun)) && !defined(INET_ADDRSTRLEN) +#define INET_ADDRSTRLEN 16 +#endif + +/* Generic includes */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +/* Generic socket object definitions and includes */ +#define PySocket_BUILDING_SOCKET +#include "socketmodule.h" + +/* Addressing includes */ + +#ifndef MS_WINDOWS + +/* Non-MS WINDOWS includes */ +# include <netdb.h> + +/* Headers needed for inet_ntoa() and inet_addr() */ +# ifdef __BEOS__ +# include <net/netdb.h> +# elif defined(PYOS_OS2) && defined(PYCC_VACPP) +# include <netdb.h> +typedef size_t socklen_t; +# else +# include <arpa/inet.h> +# endif + +# ifndef RISCOS +# include <fcntl.h> +# else +# include <sys/ioctl.h> +# include <socklib.h> +# define NO_DUP +int h_errno; /* not used */ +# define INET_ADDRSTRLEN 16 +# endif + +#else + +/* MS_WINDOWS includes */ +# ifdef HAVE_FCNTL_H +# include <fcntl.h> +# endif + +#endif + +#include <stddef.h> + +#ifndef offsetof +# define offsetof(type, member) ((size_t)(&((type *)0)->member)) +#endif + +#ifndef O_NONBLOCK +# define O_NONBLOCK O_NDELAY +#endif + +/* include Python's addrinfo.h unless it causes trouble */ +#if defined(__sgi) && _COMPILER_VERSION>700 && defined(_SS_ALIGNSIZE) + /* Do not include addinfo.h on some newer IRIX versions. + * _SS_ALIGNSIZE is defined in sys/socket.h by 6.5.21, + * for example, but not by 6.5.10. + */ +#elif defined(_MSC_VER) && _MSC_VER>1201 + /* Do not include addrinfo.h for MSVC7 or greater. 'addrinfo' and + * EAI_* constants are defined in (the already included) ws2tcpip.h. + */ +#else +# include "addrinfo.h" +#endif + +#ifndef HAVE_INET_PTON +int inet_pton(int af, const char *src, void *dst); +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size); +#endif + +#ifdef __APPLE__ +/* On OS X, getaddrinfo returns no error indication of lookup + failure, so we must use the emulation instead of the libinfo + implementation. Unfortunately, performing an autoconf test + for this bug would require DNS access for the machine performing + the configuration, which is not acceptable. Therefore, we + determine the bug just by checking for __APPLE__. If this bug + gets ever fixed, perhaps checking for sys/version.h would be + appropriate, which is 10/0 on the system with the bug. */ +#ifndef HAVE_GETNAMEINFO +/* This bug seems to be fixed in Jaguar. Ths easiest way I could + Find to check for Jaguar is that it has getnameinfo(), which + older releases don't have */ +#undef HAVE_GETADDRINFO +#endif + +#ifdef HAVE_INET_ATON +#define USE_INET_ATON_WEAKLINK +#endif + +#endif + +/* I know this is a bad practice, but it is the easiest... */ +#if !defined(HAVE_GETADDRINFO) +/* avoid clashes with the C library definition of the symbol. */ +#define getaddrinfo fake_getaddrinfo +#define gai_strerror fake_gai_strerror +#define freeaddrinfo fake_freeaddrinfo +#include "getaddrinfo.c" +#endif +#if !defined(HAVE_GETNAMEINFO) +#define getnameinfo fake_getnameinfo +#include "getnameinfo.c" +#endif + +#if defined(MS_WINDOWS) || defined(__BEOS__) +/* BeOS suffers from the same socket dichotomy as Win32... - [cjh] */ +/* seem to be a few differences in the API */ +#define SOCKETCLOSE closesocket +#define NO_DUP /* Actually it exists on NT 3.5, but what the heck... */ +#endif + +#ifdef MS_WIN32 +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define snprintf _snprintf +#endif + +#if defined(PYOS_OS2) && !defined(PYCC_GCC) +#define SOCKETCLOSE soclose +#define NO_DUP /* Sockets are Not Actual File Handles under OS/2 */ +#endif + +#ifndef SOCKETCLOSE +#define SOCKETCLOSE close +#endif + +#if defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H) +#define USE_BLUETOOTH 1 +#if defined(__FreeBSD__) +#define BTPROTO_L2CAP BLUETOOTH_PROTO_L2CAP +#define BTPROTO_RFCOMM BLUETOOTH_PROTO_RFCOMM +#define sockaddr_l2 sockaddr_l2cap +#define sockaddr_rc sockaddr_rfcomm +#define _BT_L2_MEMB(sa, memb) ((sa)->l2cap_##memb) +#define _BT_RC_MEMB(sa, memb) ((sa)->rfcomm_##memb) +#elif defined(__NetBSD__) +#define sockaddr_l2 sockaddr_bt +#define sockaddr_rc sockaddr_bt +#define sockaddr_sco sockaddr_bt +#define _BT_L2_MEMB(sa, memb) ((sa)->bt_##memb) +#define _BT_RC_MEMB(sa, memb) ((sa)->bt_##memb) +#define _BT_SCO_MEMB(sa, memb) ((sa)->bt_##memb) +#else +#define _BT_L2_MEMB(sa, memb) ((sa)->l2_##memb) +#define _BT_RC_MEMB(sa, memb) ((sa)->rc_##memb) +#define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb) +#endif +#endif + +#ifdef __VMS +/* TCP/IP Services for VMS uses a maximum send/recv buffer length */ +#define SEGMENT_SIZE (32 * 1024 -1) +#endif + +#define SAS2SA(x) ((struct sockaddr *)(x)) + +/* + * Constants for getnameinfo() + */ +#if !defined(NI_MAXHOST) +#define NI_MAXHOST 1025 +#endif +#if !defined(NI_MAXSERV) +#define NI_MAXSERV 32 +#endif + +/* XXX There's a problem here: *static* functions are not supposed to have + a Py prefix (or use CapitalizedWords). Later... */ + +/* Global variable holding the exception type for errors detected + by this module (but not argument type or memory errors, etc.). */ +static PyObject *socket_error; +static PyObject *socket_herror; +static PyObject *socket_gaierror; +static PyObject *socket_timeout; + +#ifdef RISCOS +/* Global variable which is !=0 if Python is running in a RISC OS taskwindow */ +static int taskwindow; +#endif + +/* A forward reference to the socket type object. + The sock_type variable contains pointers to various functions, + some of which call new_sockobject(), which uses sock_type, so + there has to be a circular reference. */ +static PyTypeObject sock_type; + +#if defined(HAVE_POLL_H) +#include <poll.h> +#elif defined(HAVE_SYS_POLL_H) +#include <sys/poll.h> +#endif + +#ifdef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE +/* Platform can select file descriptors beyond FD_SETSIZE */ +#define IS_SELECTABLE(s) 1 +#elif defined(HAVE_POLL) +/* Instead of select(), we'll use poll() since poll() works on any fd. */ +#define IS_SELECTABLE(s) 1 +/* Can we call select() with this socket without a buffer overrun? */ +#else +/* POSIX says selecting file descriptors beyond FD_SETSIZE + has undefined behaviour. If there's no timeout left, we don't have to + call select, so it's a safe, little white lie. */ +#define IS_SELECTABLE(s) ((s)->sock_fd < FD_SETSIZE || s->sock_timeout <= 0.0) +#endif + +static PyObject* +select_error(void) +{ + PyErr_SetString(socket_error, "unable to select on socket"); + return NULL; +} + +/* Convenience function to raise an error according to errno + and return a NULL pointer from a function. */ + +static PyObject * +set_error(void) +{ +#ifdef MS_WINDOWS + int err_no = WSAGetLastError(); + static struct { + int no; + const char *msg; + } *msgp, msgs[] = { + {WSAEINTR, "Interrupted system call"}, + {WSAEBADF, "Bad file descriptor"}, + {WSAEACCES, "Permission denied"}, + {WSAEFAULT, "Bad address"}, + {WSAEINVAL, "Invalid argument"}, + {WSAEMFILE, "Too many open files"}, + {WSAEWOULDBLOCK, + "The socket operation could not complete " + "without blocking"}, + {WSAEINPROGRESS, "Operation now in progress"}, + {WSAEALREADY, "Operation already in progress"}, + {WSAENOTSOCK, "Socket operation on non-socket"}, + {WSAEDESTADDRREQ, "Destination address required"}, + {WSAEMSGSIZE, "Message too long"}, + {WSAEPROTOTYPE, "Protocol wrong type for socket"}, + {WSAENOPROTOOPT, "Protocol not available"}, + {WSAEPROTONOSUPPORT, "Protocol not supported"}, + {WSAESOCKTNOSUPPORT, "Socket type not supported"}, + {WSAEOPNOTSUPP, "Operation not supported"}, + {WSAEPFNOSUPPORT, "Protocol family not supported"}, + {WSAEAFNOSUPPORT, "Address family not supported"}, + {WSAEADDRINUSE, "Address already in use"}, + {WSAEADDRNOTAVAIL, "Can't assign requested address"}, + {WSAENETDOWN, "Network is down"}, + {WSAENETUNREACH, "Network is unreachable"}, + {WSAENETRESET, "Network dropped connection on reset"}, + {WSAECONNABORTED, "Software caused connection abort"}, + {WSAECONNRESET, "Connection reset by peer"}, + {WSAENOBUFS, "No buffer space available"}, + {WSAEISCONN, "Socket is already connected"}, + {WSAENOTCONN, "Socket is not connected"}, + {WSAESHUTDOWN, "Can't send after socket shutdown"}, + {WSAETOOMANYREFS, "Too many references: can't splice"}, + {WSAETIMEDOUT, "Operation timed out"}, + {WSAECONNREFUSED, "Connection refused"}, + {WSAELOOP, "Too many levels of symbolic links"}, + {WSAENAMETOOLONG, "File name too long"}, + {WSAEHOSTDOWN, "Host is down"}, + {WSAEHOSTUNREACH, "No route to host"}, + {WSAENOTEMPTY, "Directory not empty"}, + {WSAEPROCLIM, "Too many processes"}, + {WSAEUSERS, "Too many users"}, + {WSAEDQUOT, "Disc quota exceeded"}, + {WSAESTALE, "Stale NFS file handle"}, + {WSAEREMOTE, "Too many levels of remote in path"}, + {WSASYSNOTREADY, "Network subsystem is unvailable"}, + {WSAVERNOTSUPPORTED, "WinSock version is not supported"}, + {WSANOTINITIALISED, + "Successful WSAStartup() not yet performed"}, + {WSAEDISCON, "Graceful shutdown in progress"}, + /* Resolver errors */ + {WSAHOST_NOT_FOUND, "No such host is known"}, + {WSATRY_AGAIN, "Host not found, or server failed"}, + {WSANO_RECOVERY, "Unexpected server error encountered"}, + {WSANO_DATA, "Valid name without requested data"}, + {WSANO_ADDRESS, "No address, look for MX record"}, + {0, NULL} + }; + if (err_no) { + PyObject *v; + const char *msg = "winsock error"; + + for (msgp = msgs; msgp->msg; msgp++) { + if (err_no == msgp->no) { + msg = msgp->msg; + break; + } + } + + v = Py_BuildValue("(is)", err_no, msg); + if (v != NULL) { + PyErr_SetObject(socket_error, v); + Py_DECREF(v); + } + return NULL; + } + else +#endif + +#if defined(PYOS_OS2) && !defined(PYCC_GCC) + if (sock_errno() != NO_ERROR) { + APIRET rc; + ULONG msglen; + char outbuf[100]; + int myerrorcode = sock_errno(); + + /* Retrieve socket-related error message from MPTN.MSG file */ + rc = DosGetMessage(NULL, 0, outbuf, sizeof(outbuf), + myerrorcode - SOCBASEERR + 26, + "mptn.msg", + &msglen); + if (rc == NO_ERROR) { + PyObject *v; + + /* OS/2 doesn't guarantee a terminator */ + outbuf[msglen] = '\0'; + if (strlen(outbuf) > 0) { + /* If non-empty msg, trim CRLF */ + char *lastc = &outbuf[ strlen(outbuf)-1 ]; + while (lastc > outbuf && + isspace(Py_CHARMASK(*lastc))) { + /* Trim trailing whitespace (CRLF) */ + *lastc-- = '\0'; + } + } + v = Py_BuildValue("(is)", myerrorcode, outbuf); + if (v != NULL) { + PyErr_SetObject(socket_error, v); + Py_DECREF(v); + } + return NULL; + } + } +#endif + +#if defined(RISCOS) + if (_inet_error.errnum != NULL) { + PyObject *v; + v = Py_BuildValue("(is)", errno, _inet_err()); + if (v != NULL) { + PyErr_SetObject(socket_error, v); + Py_DECREF(v); + } + return NULL; + } +#endif + + return PyErr_SetFromErrno(socket_error); +} + + +static PyObject * +set_herror(int h_error) +{ + PyObject *v; + +#ifdef HAVE_HSTRERROR + v = Py_BuildValue("(is)", h_error, (char *)hstrerror(h_error)); +#else + v = Py_BuildValue("(is)", h_error, "host not found"); +#endif + if (v != NULL) { + PyErr_SetObject(socket_herror, v); + Py_DECREF(v); + } + + return NULL; +} + + +static PyObject * +set_gaierror(int error) +{ + PyObject *v; + +#ifdef EAI_SYSTEM + /* EAI_SYSTEM is not available on Windows XP. */ + if (error == EAI_SYSTEM) + return set_error(); +#endif + +#ifdef HAVE_GAI_STRERROR + v = Py_BuildValue("(is)", error, gai_strerror(error)); +#else + v = Py_BuildValue("(is)", error, "getaddrinfo failed"); +#endif + if (v != NULL) { + PyErr_SetObject(socket_gaierror, v); + Py_DECREF(v); + } + + return NULL; +} + +#ifdef __VMS +/* Function to send in segments */ +static int +sendsegmented(int sock_fd, char *buf, int len, int flags) +{ + int n = 0; + int remaining = len; + + while (remaining > 0) { + unsigned int segment; + + segment = (remaining >= SEGMENT_SIZE ? SEGMENT_SIZE : remaining); + n = send(sock_fd, buf, segment, flags); + if (n < 0) { + return n; + } + remaining -= segment; + buf += segment; + } /* end while */ + + return len; +} +#endif + +/* Function to perform the setting of socket blocking mode + internally. block = (1 | 0). */ +static int +internal_setblocking(PySocketSockObject *s, int block) +{ +#ifndef RISCOS +#ifndef MS_WINDOWS + int delay_flag; +#endif +#endif + + Py_BEGIN_ALLOW_THREADS +#ifdef __BEOS__ + block = !block; + setsockopt(s->sock_fd, SOL_SOCKET, SO_NONBLOCK, + (void *)(&block), sizeof(int)); +#else +#ifndef RISCOS +#ifndef MS_WINDOWS +#if defined(PYOS_OS2) && !defined(PYCC_GCC) + block = !block; + ioctl(s->sock_fd, FIONBIO, (caddr_t)&block, sizeof(block)); +#elif defined(__VMS) + block = !block; + ioctl(s->sock_fd, FIONBIO, (unsigned int *)&block); +#else /* !PYOS_OS2 && !__VMS */ + delay_flag = fcntl(s->sock_fd, F_GETFL, 0); + if (block) + delay_flag &= (~O_NONBLOCK); + else + delay_flag |= O_NONBLOCK; + fcntl(s->sock_fd, F_SETFL, delay_flag); +#endif /* !PYOS_OS2 */ +#else /* MS_WINDOWS */ + block = !block; + ioctlsocket(s->sock_fd, FIONBIO, (u_long*)&block); +#endif /* MS_WINDOWS */ +#else /* RISCOS */ + block = !block; + socketioctl(s->sock_fd, FIONBIO, (u_long*)&block); +#endif /* RISCOS */ +#endif /* __BEOS__ */ + Py_END_ALLOW_THREADS + + /* Since these don't return anything */ + return 1; +} + +/* Do a select()/poll() on the socket, if necessary (sock_timeout > 0). + The argument writing indicates the direction. + This does not raise an exception; we'll let our caller do that + after they've reacquired the interpreter lock. + Returns 1 on timeout, -1 on error, 0 otherwise. */ +static int +internal_select(PySocketSockObject *s, int writing) +{ + int n; + + /* Nothing to do unless we're in timeout mode (not non-blocking) */ + if (s->sock_timeout <= 0.0) + return 0; + + /* Guard against closed socket */ + if (s->sock_fd < 0) + return 0; + + /* Prefer poll, if available, since you can poll() any fd + * which can't be done with select(). */ +#ifdef HAVE_POLL + { + struct pollfd pollfd; + int timeout; + + pollfd.fd = s->sock_fd; + pollfd.events = writing ? POLLOUT : POLLIN; + + /* s->sock_timeout is in seconds, timeout in ms */ + timeout = (int)(s->sock_timeout * 1000 + 0.5); + n = poll(&pollfd, 1, timeout); + } +#else + { + /* Construct the arguments to select */ + fd_set fds; + struct timeval tv; + tv.tv_sec = (int)s->sock_timeout; + tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + FD_ZERO(&fds); + FD_SET(s->sock_fd, &fds); + + /* See if the socket is ready */ + if (writing) + n = select(s->sock_fd+1, NULL, &fds, NULL, &tv); + else + n = select(s->sock_fd+1, &fds, NULL, NULL, &tv); + } +#endif + + if (n < 0) + return -1; + if (n == 0) + return 1; + return 0; +} + +/* Initialize a new socket object. */ + +static double defaulttimeout = -1.0; /* Default timeout for new sockets */ + +PyMODINIT_FUNC +init_sockobject(PySocketSockObject *s, + SOCKET_T fd, int family, int type, int proto) +{ +#ifdef RISCOS + int block = 1; +#endif + s->sock_fd = fd; + s->sock_family = family; + s->sock_type = type; + s->sock_proto = proto; + s->sock_timeout = defaulttimeout; + + s->errorhandler = &set_error; + + if (defaulttimeout >= 0.0) + internal_setblocking(s, 0); + +#ifdef RISCOS + if (taskwindow) + socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); +#endif +} + + +/* Create a new socket object. + This just creates the object and initializes it. + If the creation fails, return NULL and set an exception (implicit + in NEWOBJ()). */ + +static PySocketSockObject * +new_sockobject(SOCKET_T fd, int family, int type, int proto) +{ + PySocketSockObject *s; + s = (PySocketSockObject *) + PyType_GenericNew(&sock_type, NULL, NULL); + if (s != NULL) + init_sockobject(s, fd, family, type, proto); + return s; +} + + +/* Lock to allow python interpreter to continue, but only allow one + thread to be in gethostbyname or getaddrinfo */ +#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK) +PyThread_type_lock netdb_lock; +#endif + + +/* Convert a string specifying a host name or one of a few symbolic + names to a numeric IP address. This usually calls gethostbyname() + to do the work; the names "" and "<broadcast>" are special. + Return the length (IPv4 should be 4 bytes), or negative if + an error occurred; then an exception is raised. */ + +static int +setipaddr(char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af) +{ + struct addrinfo hints, *res; + int error; + int d1, d2, d3, d4; + char ch; + + memset((void *) addr_ret, '\0', addr_ret_size); + if (name[0] == '\0') { + int siz; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_PASSIVE; + Py_BEGIN_ALLOW_THREADS + ACQUIRE_GETADDRINFO_LOCK + error = getaddrinfo(NULL, "0", &hints, &res); + Py_END_ALLOW_THREADS + /* We assume that those thread-unsafe getaddrinfo() versions + *are* safe regarding their return value, ie. that a + subsequent call to getaddrinfo() does not destroy the + outcome of the first call. */ + RELEASE_GETADDRINFO_LOCK + if (error) { + set_gaierror(error); + return -1; + } + switch (res->ai_family) { + case AF_INET: + siz = 4; + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + siz = 16; + break; +#endif + default: + freeaddrinfo(res); + PyErr_SetString(socket_error, + "unsupported address family"); + return -1; + } + if (res->ai_next) { + freeaddrinfo(res); + PyErr_SetString(socket_error, + "wildcard resolved to multiple address"); + return -1; + } + if (res->ai_addrlen < addr_ret_size) + addr_ret_size = res->ai_addrlen; + memcpy(addr_ret, res->ai_addr, addr_ret_size); + freeaddrinfo(res); + return siz; + } + if (name[0] == '<' && strcmp(name, "<broadcast>") == 0) { + struct sockaddr_in *sin; + if (af != AF_INET && af != AF_UNSPEC) { + PyErr_SetString(socket_error, + "address family mismatched"); + return -1; + } + sin = (struct sockaddr_in *)addr_ret; + memset((void *) sin, '\0', sizeof(*sin)); + sin->sin_family = AF_INET; +#ifdef HAVE_SOCKADDR_SA_LEN + sin->sin_len = sizeof(*sin); +#endif + sin->sin_addr.s_addr = INADDR_BROADCAST; + return sizeof(sin->sin_addr); + } + if (sscanf(name, "%d.%d.%d.%d%c", &d1, &d2, &d3, &d4, &ch) == 4 && + 0 <= d1 && d1 <= 255 && 0 <= d2 && d2 <= 255 && + 0 <= d3 && d3 <= 255 && 0 <= d4 && d4 <= 255) { + struct sockaddr_in *sin; + sin = (struct sockaddr_in *)addr_ret; + sin->sin_addr.s_addr = htonl( + ((long) d1 << 24) | ((long) d2 << 16) | + ((long) d3 << 8) | ((long) d4 << 0)); + sin->sin_family = AF_INET; +#ifdef HAVE_SOCKADDR_SA_LEN + sin->sin_len = sizeof(*sin); +#endif + return 4; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + Py_BEGIN_ALLOW_THREADS + ACQUIRE_GETADDRINFO_LOCK + error = getaddrinfo(name, NULL, &hints, &res); +#if defined(__digital__) && defined(__unix__) + if (error == EAI_NONAME && af == AF_UNSPEC) { + /* On Tru64 V5.1, numeric-to-addr conversion fails + if no address family is given. Assume IPv4 for now.*/ + hints.ai_family = AF_INET; + error = getaddrinfo(name, NULL, &hints, &res); + } +#endif + Py_END_ALLOW_THREADS + RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */ + if (error) { + set_gaierror(error); + return -1; + } + if (res->ai_addrlen < addr_ret_size) + addr_ret_size = res->ai_addrlen; + memcpy((char *) addr_ret, res->ai_addr, addr_ret_size); + freeaddrinfo(res); + switch (addr_ret->sa_family) { + case AF_INET: + return 4; +#ifdef ENABLE_IPV6 + case AF_INET6: + return 16; +#endif + default: + PyErr_SetString(socket_error, "unknown address family"); + return -1; + } +} + + +/* Create a string object representing an IP address. + This is always a string of the form 'dd.dd.dd.dd' (with variable + size numbers). */ + +static PyObject * +makeipaddr(struct sockaddr *addr, int addrlen) +{ + char buf[NI_MAXHOST]; + int error; + + error = getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, + NI_NUMERICHOST); + if (error) { + set_gaierror(error); + return NULL; + } + return PyString_FromString(buf); +} + + +#ifdef USE_BLUETOOTH +/* Convert a string representation of a Bluetooth address into a numeric + address. Returns the length (6), or raises an exception and returns -1 if + an error occurred. */ + +static int +setbdaddr(char *name, bdaddr_t *bdaddr) +{ + unsigned int b0, b1, b2, b3, b4, b5; + char ch; + int n; + + n = sscanf(name, "%X:%X:%X:%X:%X:%X%c", + &b5, &b4, &b3, &b2, &b1, &b0, &ch); + if (n == 6 && (b0 | b1 | b2 | b3 | b4 | b5) < 256) { + bdaddr->b[0] = b0; + bdaddr->b[1] = b1; + bdaddr->b[2] = b2; + bdaddr->b[3] = b3; + bdaddr->b[4] = b4; + bdaddr->b[5] = b5; + return 6; + } else { + PyErr_SetString(socket_error, "bad bluetooth address"); + return -1; + } +} + +/* Create a string representation of the Bluetooth address. This is always a + string of the form 'XX:XX:XX:XX:XX:XX' where XX is a two digit hexadecimal + value (zero padded if necessary). */ + +static PyObject * +makebdaddr(bdaddr_t *bdaddr) +{ + char buf[(6 * 2) + 5 + 1]; + + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], + bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); + return PyString_FromString(buf); +} +#endif + + +/* Create an object representing the given socket address, + suitable for passing it back to bind(), connect() etc. + The family field of the sockaddr structure is inspected + to determine what kind of address it really is. */ + +/*ARGSUSED*/ +static PyObject * +makesockaddr(int sockfd, struct sockaddr *addr, int addrlen, int proto) +{ + if (addrlen == 0) { + /* No address -- may be recvfrom() from known socket */ + Py_INCREF(Py_None); + return Py_None; + } + +#ifdef __BEOS__ + /* XXX: BeOS version of accept() doesn't set family correctly */ + addr->sa_family = AF_INET; +#endif + + switch (addr->sa_family) { + + case AF_INET: + { + struct sockaddr_in *a; + PyObject *addrobj = makeipaddr(addr, sizeof(*a)); + PyObject *ret = NULL; + if (addrobj) { + a = (struct sockaddr_in *)addr; + ret = Py_BuildValue("Oi", addrobj, ntohs(a->sin_port)); + Py_DECREF(addrobj); + } + return ret; + } + +#if defined(AF_UNIX) + case AF_UNIX: + { + struct sockaddr_un *a = (struct sockaddr_un *) addr; +#ifdef linux + if (a->sun_path[0] == 0) { /* Linux abstract namespace */ + addrlen -= (sizeof(*a) - sizeof(a->sun_path)); + return PyString_FromStringAndSize(a->sun_path, + addrlen); + } + else +#endif /* linux */ + { + /* regular NULL-terminated string */ + return PyString_FromString(a->sun_path); + } + } +#endif /* AF_UNIX */ + +#if defined(AF_NETLINK) + case AF_NETLINK: + { + struct sockaddr_nl *a = (struct sockaddr_nl *) addr; + return Py_BuildValue("II", a->nl_pid, a->nl_groups); + } +#endif /* AF_NETLINK */ + +#ifdef ENABLE_IPV6 + case AF_INET6: + { + struct sockaddr_in6 *a; + PyObject *addrobj = makeipaddr(addr, sizeof(*a)); + PyObject *ret = NULL; + if (addrobj) { + a = (struct sockaddr_in6 *)addr; + ret = Py_BuildValue("Oiii", + addrobj, + ntohs(a->sin6_port), + a->sin6_flowinfo, + a->sin6_scope_id); + Py_DECREF(addrobj); + } + return ret; + } +#endif + +#ifdef USE_BLUETOOTH + case AF_BLUETOOTH: + switch (proto) { + + case BTPROTO_L2CAP: + { + struct sockaddr_l2 *a = (struct sockaddr_l2 *) addr; + PyObject *addrobj = makebdaddr(&_BT_L2_MEMB(a, bdaddr)); + PyObject *ret = NULL; + if (addrobj) { + ret = Py_BuildValue("Oi", + addrobj, + _BT_L2_MEMB(a, psm)); + Py_DECREF(addrobj); + } + return ret; + } + + case BTPROTO_RFCOMM: + { + struct sockaddr_rc *a = (struct sockaddr_rc *) addr; + PyObject *addrobj = makebdaddr(&_BT_RC_MEMB(a, bdaddr)); + PyObject *ret = NULL; + if (addrobj) { + ret = Py_BuildValue("Oi", + addrobj, + _BT_RC_MEMB(a, channel)); + Py_DECREF(addrobj); + } + return ret; + } + +#if !defined(__FreeBSD__) + case BTPROTO_SCO: + { + struct sockaddr_sco *a = (struct sockaddr_sco *) addr; + return makebdaddr(&_BT_SCO_MEMB(a, bdaddr)); + } +#endif + + } +#endif + +#ifdef HAVE_NETPACKET_PACKET_H + case AF_PACKET: + { + struct sockaddr_ll *a = (struct sockaddr_ll *)addr; + char *ifname = ""; + struct ifreq ifr; + /* need to look up interface name give index */ + if (a->sll_ifindex) { + ifr.ifr_ifindex = a->sll_ifindex; + if (ioctl(sockfd, SIOCGIFNAME, &ifr) == 0) + ifname = ifr.ifr_name; + } + return Py_BuildValue("shbhs#", + ifname, + ntohs(a->sll_protocol), + a->sll_pkttype, + a->sll_hatype, + a->sll_addr, + a->sll_halen); + } +#endif + + /* More cases here... */ + + default: + /* If we don't know the address family, don't raise an + exception -- return it as a tuple. */ + return Py_BuildValue("is#", + addr->sa_family, + addr->sa_data, + sizeof(addr->sa_data)); + + } +} + + +/* Parse a socket address argument according to the socket object's + address family. Return 1 if the address was in the proper format, + 0 of not. The address is returned through addr_ret, its length + through len_ret. */ + +static int +getsockaddrarg(PySocketSockObject *s, PyObject *args, + struct sockaddr *addr_ret, int *len_ret) +{ + switch (s->sock_family) { + +#if defined(AF_UNIX) + case AF_UNIX: + { + struct sockaddr_un* addr; + char *path; + int len; + if (!PyArg_Parse(args, "t#", &path, &len)) + return 0; + + addr = (struct sockaddr_un*)addr_ret; +#ifdef linux + if (len > 0 && path[0] == 0) { + /* Linux abstract namespace extension */ + if (len > sizeof addr->sun_path) { + PyErr_SetString(socket_error, + "AF_UNIX path too long"); + return 0; + } + } + else +#endif /* linux */ + { + /* regular NULL-terminated string */ + if (len >= sizeof addr->sun_path) { + PyErr_SetString(socket_error, + "AF_UNIX path too long"); + return 0; + } + addr->sun_path[len] = 0; + } + addr->sun_family = s->sock_family; + memcpy(addr->sun_path, path, len); +#if defined(PYOS_OS2) + *len_ret = sizeof(*addr); +#else + *len_ret = len + sizeof(*addr) - sizeof(addr->sun_path); +#endif + return 1; + } +#endif /* AF_UNIX */ + +#if defined(AF_NETLINK) + case AF_NETLINK: + { + struct sockaddr_nl* addr; + int pid, groups; + addr = (struct sockaddr_nl *)addr_ret; + if (!PyTuple_Check(args)) { + PyErr_Format( + PyExc_TypeError, + "getsockaddrarg: " + "AF_NETLINK address must be tuple, not %.500s", + args->ob_type->tp_name); + return 0; + } + if (!PyArg_ParseTuple(args, "II:getsockaddrarg", &pid, &groups)) + return 0; + addr->nl_family = AF_NETLINK; + addr->nl_pid = pid; + addr->nl_groups = groups; + *len_ret = sizeof(*addr); + return 1; + } +#endif + + case AF_INET: + { + struct sockaddr_in* addr; + char *host; + int port, result; + if (!PyTuple_Check(args)) { + PyErr_Format( + PyExc_TypeError, + "getsockaddrarg: " + "AF_INET address must be tuple, not %.500s", + args->ob_type->tp_name); + return 0; + } + if (!PyArg_ParseTuple(args, "eti:getsockaddrarg", + "idna", &host, &port)) + return 0; + addr=(struct sockaddr_in*)addr_ret; + result = setipaddr(host, (struct sockaddr *)addr, + sizeof(*addr), AF_INET); + PyMem_Free(host); + if (result < 0) + return 0; + addr->sin_family = AF_INET; + addr->sin_port = htons((short)port); + *len_ret = sizeof *addr; + return 1; + } + +#ifdef ENABLE_IPV6 + case AF_INET6: + { + struct sockaddr_in6* addr; + char *host; + int port, flowinfo, scope_id, result; + flowinfo = scope_id = 0; + if (!PyTuple_Check(args)) { + PyErr_Format( + PyExc_TypeError, + "getsockaddrarg: " + "AF_INET6 address must be tuple, not %.500s", + args->ob_type->tp_name); + return 0; + } + if (!PyArg_ParseTuple(args, "eti|ii", + "idna", &host, &port, &flowinfo, + &scope_id)) { + return 0; + } + addr = (struct sockaddr_in6*)addr_ret; + result = setipaddr(host, (struct sockaddr *)addr, + sizeof(*addr), AF_INET6); + PyMem_Free(host); + if (result < 0) + return 0; + addr->sin6_family = s->sock_family; + addr->sin6_port = htons((short)port); + addr->sin6_flowinfo = flowinfo; + addr->sin6_scope_id = scope_id; + *len_ret = sizeof *addr; + return 1; + } +#endif + +#ifdef USE_BLUETOOTH + case AF_BLUETOOTH: + { + switch (s->sock_proto) { + case BTPROTO_L2CAP: + { + struct sockaddr_l2 *addr; + char *straddr; + + addr = (struct sockaddr_l2 *)addr_ret; + _BT_L2_MEMB(addr, family) = AF_BLUETOOTH; + if (!PyArg_ParseTuple(args, "si", &straddr, + &_BT_L2_MEMB(addr, psm))) { + PyErr_SetString(socket_error, "getsockaddrarg: " + "wrong format"); + return 0; + } + if (setbdaddr(straddr, &_BT_L2_MEMB(addr, bdaddr)) < 0) + return 0; + + *len_ret = sizeof *addr; + return 1; + } + case BTPROTO_RFCOMM: + { + struct sockaddr_rc *addr; + char *straddr; + + addr = (struct sockaddr_rc *)addr_ret; + _BT_RC_MEMB(addr, family) = AF_BLUETOOTH; + if (!PyArg_ParseTuple(args, "si", &straddr, + &_BT_RC_MEMB(addr, channel))) { + PyErr_SetString(socket_error, "getsockaddrarg: " + "wrong format"); + return 0; + } + if (setbdaddr(straddr, &_BT_RC_MEMB(addr, bdaddr)) < 0) + return 0; + + *len_ret = sizeof *addr; + return 1; + } +#if !defined(__FreeBSD__) + case BTPROTO_SCO: + { + struct sockaddr_sco *addr; + char *straddr; + + addr = (struct sockaddr_sco *)addr_ret; + _BT_SCO_MEMB(addr, family) = AF_BLUETOOTH; + straddr = PyString_AsString(args); + if (straddr == NULL) { + PyErr_SetString(socket_error, "getsockaddrarg: " + "wrong format"); + return 0; + } + if (setbdaddr(straddr, &_BT_SCO_MEMB(addr, bdaddr)) < 0) + return 0; + + *len_ret = sizeof *addr; + return 1; + } +#endif + default: + PyErr_SetString(socket_error, "getsockaddrarg: unknown Bluetooth protocol"); + return 0; + } + } +#endif + +#ifdef HAVE_NETPACKET_PACKET_H + case AF_PACKET: + { + struct sockaddr_ll* addr; + struct ifreq ifr; + char *interfaceName; + int protoNumber; + int hatype = 0; + int pkttype = 0; + char *haddr = NULL; + unsigned int halen = 0; + + if (!PyTuple_Check(args)) { + PyErr_Format( + PyExc_TypeError, + "getsockaddrarg: " + "AF_PACKET address must be tuple, not %.500s", + args->ob_type->tp_name); + return 0; + } + if (!PyArg_ParseTuple(args, "si|iis#", &interfaceName, + &protoNumber, &pkttype, &hatype, + &haddr, &halen)) + return 0; + strncpy(ifr.ifr_name, interfaceName, sizeof(ifr.ifr_name)); + ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; + if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { + s->errorhandler(); + return 0; + } + if (halen > 8) { + PyErr_SetString(PyExc_ValueError, + "Hardware address must be 8 bytes or less"); + return 0; + } + addr = (struct sockaddr_ll*)addr_ret; + addr->sll_family = AF_PACKET; + addr->sll_protocol = htons((short)protoNumber); + addr->sll_ifindex = ifr.ifr_ifindex; + addr->sll_pkttype = pkttype; + addr->sll_hatype = hatype; + if (halen != 0) { + memcpy(&addr->sll_addr, haddr, halen); + } + addr->sll_halen = halen; + *len_ret = sizeof *addr; + return 1; + } +#endif + + /* More cases here... */ + + default: + PyErr_SetString(socket_error, "getsockaddrarg: bad family"); + return 0; + + } +} + + +/* Get the address length according to the socket object's address family. + Return 1 if the family is known, 0 otherwise. The length is returned + through len_ret. */ + +static int +getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret) +{ + switch (s->sock_family) { + +#if defined(AF_UNIX) + case AF_UNIX: + { + *len_ret = sizeof (struct sockaddr_un); + return 1; + } +#endif /* AF_UNIX */ +#if defined(AF_NETLINK) + case AF_NETLINK: + { + *len_ret = sizeof (struct sockaddr_nl); + return 1; + } +#endif + + case AF_INET: + { + *len_ret = sizeof (struct sockaddr_in); + return 1; + } + +#ifdef ENABLE_IPV6 + case AF_INET6: + { + *len_ret = sizeof (struct sockaddr_in6); + return 1; + } +#endif + +#ifdef USE_BLUETOOTH + case AF_BLUETOOTH: + { + switch(s->sock_proto) + { + + case BTPROTO_L2CAP: + *len_ret = sizeof (struct sockaddr_l2); + return 1; + case BTPROTO_RFCOMM: + *len_ret = sizeof (struct sockaddr_rc); + return 1; +#if !defined(__FreeBSD__) + case BTPROTO_SCO: + *len_ret = sizeof (struct sockaddr_sco); + return 1; +#endif + default: + PyErr_SetString(socket_error, "getsockaddrlen: " + "unknown BT protocol"); + return 0; + + } + } +#endif + +#ifdef HAVE_NETPACKET_PACKET_H + case AF_PACKET: + { + *len_ret = sizeof (struct sockaddr_ll); + return 1; + } +#endif + + /* More cases here... */ + + default: + PyErr_SetString(socket_error, "getsockaddrlen: bad family"); + return 0; + + } +} + + +/* s.accept() method */ + +static PyObject * +sock_accept(PySocketSockObject *s) +{ + sock_addr_t addrbuf; + SOCKET_T newfd; + socklen_t addrlen; + PyObject *sock = NULL; + PyObject *addr = NULL; + PyObject *res = NULL; + int timeout; + + if (!getsockaddrlen(s, &addrlen)) + return NULL; + memset(&addrbuf, 0, addrlen); + +#ifdef MS_WINDOWS + newfd = INVALID_SOCKET; +#else + newfd = -1; +#endif + + if (!IS_SELECTABLE(s)) + return select_error(); + + Py_BEGIN_ALLOW_THREADS + timeout = internal_select(s, 0); + if (!timeout) + newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen); + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return NULL; + } + +#ifdef MS_WINDOWS + if (newfd == INVALID_SOCKET) +#else + if (newfd < 0) +#endif + return s->errorhandler(); + + /* Create the new object with unspecified family, + to avoid calls to bind() etc. on it. */ + sock = (PyObject *) new_sockobject(newfd, + s->sock_family, + s->sock_type, + s->sock_proto); + + if (sock == NULL) { + SOCKETCLOSE(newfd); + goto finally; + } + addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), + addrlen, s->sock_proto); + if (addr == NULL) + goto finally; + + res = PyTuple_Pack(2, sock, addr); + +finally: + Py_XDECREF(sock); + Py_XDECREF(addr); + return res; +} + +PyDoc_STRVAR(accept_doc, +"accept() -> (socket object, address info)\n\ +\n\ +Wait for an incoming connection. Return a new socket representing the\n\ +connection, and the address of the client. For IP sockets, the address\n\ +info is a pair (hostaddr, port)."); + +/* s.setblocking(flag) method. Argument: + False -- non-blocking mode; same as settimeout(0) + True -- blocking mode; same as settimeout(None) +*/ + +static PyObject * +sock_setblocking(PySocketSockObject *s, PyObject *arg) +{ + int block; + + block = PyInt_AsLong(arg); + if (block == -1 && PyErr_Occurred()) + return NULL; + + s->sock_timeout = block ? -1.0 : 0.0; + internal_setblocking(s, block); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setblocking_doc, +"setblocking(flag)\n\ +\n\ +Set the socket to blocking (flag is true) or non-blocking (false).\n\ +setblocking(True) is equivalent to settimeout(None);\n\ +setblocking(False) is equivalent to settimeout(0.0)."); + +/* s.settimeout(timeout) method. Argument: + None -- no timeout, blocking mode; same as setblocking(True) + 0.0 -- non-blocking mode; same as setblocking(False) + > 0 -- timeout mode; operations time out after timeout seconds + < 0 -- illegal; raises an exception +*/ +static PyObject * +sock_settimeout(PySocketSockObject *s, PyObject *arg) +{ + double timeout; + + if (arg == Py_None) + timeout = -1.0; + else { + timeout = PyFloat_AsDouble(arg); + if (timeout < 0.0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, + "Timeout value out of range"); + return NULL; + } + } + + s->sock_timeout = timeout; + internal_setblocking(s, timeout < 0.0); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(settimeout_doc, +"settimeout(timeout)\n\ +\n\ +Set a timeout on socket operations. 'timeout' can be a float,\n\ +giving in seconds, or None. Setting a timeout of None disables\n\ +the timeout feature and is equivalent to setblocking(1).\n\ +Setting a timeout of zero is the same as setblocking(0)."); + +/* s.gettimeout() method. + Returns the timeout associated with a socket. */ +static PyObject * +sock_gettimeout(PySocketSockObject *s) +{ + if (s->sock_timeout < 0.0) { + Py_INCREF(Py_None); + return Py_None; + } + else + return PyFloat_FromDouble(s->sock_timeout); +} + +PyDoc_STRVAR(gettimeout_doc, +"gettimeout() -> timeout\n\ +\n\ +Returns the timeout in floating seconds associated with socket \n\ +operations. A timeout of None indicates that timeouts on socket \n\ +operations are disabled."); + +#ifdef RISCOS +/* s.sleeptaskw(1 | 0) method */ + +static PyObject * +sock_sleeptaskw(PySocketSockObject *s,PyObject *arg) +{ + int block; + block = PyInt_AsLong(arg); + if (block == -1 && PyErr_Occurred()) + return NULL; + Py_BEGIN_ALLOW_THREADS + socketioctl(s->sock_fd, 0x80046679, (u_long*)&block); + Py_END_ALLOW_THREADS + + Py_INCREF(Py_None); + return Py_None; +} +PyDoc_STRVAR(sleeptaskw_doc, +"sleeptaskw(flag)\n\ +\n\ +Allow sleeps in taskwindows."); +#endif + + +/* s.setsockopt() method. + With an integer third argument, sets an integer option. + With a string third argument, sets an option from a buffer; + use optional built-in module 'struct' to encode the string. */ + +static PyObject * +sock_setsockopt(PySocketSockObject *s, PyObject *args) +{ + int level; + int optname; + int res; + char *buf; + int buflen; + int flag; + + if (PyArg_ParseTuple(args, "iii:setsockopt", + &level, &optname, &flag)) { + buf = (char *) &flag; + buflen = sizeof flag; + } + else { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "iis#:setsockopt", + &level, &optname, &buf, &buflen)) + return NULL; + } + res = setsockopt(s->sock_fd, level, optname, (void *)buf, buflen); + if (res < 0) + return s->errorhandler(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setsockopt_doc, +"setsockopt(level, option, value)\n\ +\n\ +Set a socket option. See the Unix manual for level and option.\n\ +The value argument can either be an integer or a string."); + + +/* s.getsockopt() method. + With two arguments, retrieves an integer option. + With a third integer argument, retrieves a string buffer of that size; + use optional built-in module 'struct' to decode the string. */ + +static PyObject * +sock_getsockopt(PySocketSockObject *s, PyObject *args) +{ + int level; + int optname; + int res; + PyObject *buf; + socklen_t buflen = 0; + +#ifdef __BEOS__ + /* We have incomplete socket support. */ + PyErr_SetString(socket_error, "getsockopt not supported"); + return NULL; +#else + + if (!PyArg_ParseTuple(args, "ii|i:getsockopt", + &level, &optname, &buflen)) + return NULL; + + if (buflen == 0) { + int flag = 0; + socklen_t flagsize = sizeof flag; + res = getsockopt(s->sock_fd, level, optname, + (void *)&flag, &flagsize); + if (res < 0) + return s->errorhandler(); + return PyInt_FromLong(flag); + } +#ifdef __VMS + /* socklen_t is unsigned so no negative test is needed, + test buflen == 0 is previously done */ + if (buflen > 1024) { +#else + if (buflen <= 0 || buflen > 1024) { +#endif + PyErr_SetString(socket_error, + "getsockopt buflen out of range"); + return NULL; + } + buf = PyString_FromStringAndSize((char *)NULL, buflen); + if (buf == NULL) + return NULL; + res = getsockopt(s->sock_fd, level, optname, + (void *)PyString_AS_STRING(buf), &buflen); + if (res < 0) { + Py_DECREF(buf); + return s->errorhandler(); + } + _PyString_Resize(&buf, buflen); + return buf; +#endif /* __BEOS__ */ +} + +PyDoc_STRVAR(getsockopt_doc, +"getsockopt(level, option[, buffersize]) -> value\n\ +\n\ +Get a socket option. See the Unix manual for level and option.\n\ +If a nonzero buffersize argument is given, the return value is a\n\ +string of that length; otherwise it is an integer."); + + +/* s.bind(sockaddr) method */ + +static PyObject * +sock_bind(PySocketSockObject *s, PyObject *addro) +{ + sock_addr_t addrbuf; + int addrlen; + int res; + + if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = bind(s->sock_fd, SAS2SA(&addrbuf), addrlen); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(bind_doc, +"bind(address)\n\ +\n\ +Bind the socket to a local address. For IP sockets, the address is a\n\ +pair (host, port); the host must refer to the local host. For raw packet\n\ +sockets the address is a tuple (ifname, proto [,pkttype [,hatype]])"); + + +/* s.close() method. + Set the file descriptor to -1 so operations tried subsequently + will surely fail. */ + +static PyObject * +sock_close(PySocketSockObject *s) +{ + SOCKET_T fd; + + if ((fd = s->sock_fd) != -1) { + s->sock_fd = -1; + Py_BEGIN_ALLOW_THREADS + (void) SOCKETCLOSE(fd); + Py_END_ALLOW_THREADS + } + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(close_doc, +"close()\n\ +\n\ +Close the socket. It cannot be used after this call."); + +static int +internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen, + int *timeoutp) +{ + int res, timeout; + + timeout = 0; + res = connect(s->sock_fd, addr, addrlen); + +#ifdef MS_WINDOWS + + if (s->sock_timeout > 0.0) { + if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK && + IS_SELECTABLE(s)) { + /* This is a mess. Best solution: trust select */ + fd_set fds; + fd_set fds_exc; + struct timeval tv; + tv.tv_sec = (int)s->sock_timeout; + tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6); + FD_ZERO(&fds); + FD_SET(s->sock_fd, &fds); + FD_ZERO(&fds_exc); + FD_SET(s->sock_fd, &fds_exc); + res = select(s->sock_fd+1, NULL, &fds, &fds_exc, &tv); + if (res == 0) { + res = WSAEWOULDBLOCK; + timeout = 1; + } else if (res > 0) { + if (FD_ISSET(s->sock_fd, &fds)) + /* The socket is in the writeable set - this + means connected */ + res = 0; + else { + /* As per MS docs, we need to call getsockopt() + to get the underlying error */ + int res_size = sizeof res; + /* It must be in the exception set */ + assert(FD_ISSET(s->sock_fd, &fds_exc)); + if (0 == getsockopt(s->sock_fd, SOL_SOCKET, SO_ERROR, + (char *)&res, &res_size)) + /* getsockopt also clears WSAGetLastError, + so reset it back. */ + WSASetLastError(res); + else + res = WSAGetLastError(); + } + } + /* else if (res < 0) an error occurred */ + } + } + + if (res < 0) + res = WSAGetLastError(); + +#else + + if (s->sock_timeout > 0.0) { + if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) { + timeout = internal_select(s, 1); + if (timeout == 0) { + res = connect(s->sock_fd, addr, addrlen); + if (res < 0 && errno == EISCONN) + res = 0; + } + else if (timeout == -1) + res = errno; /* had error */ + else + res = EWOULDBLOCK; /* timed out */ + } + } + + if (res < 0) + res = errno; + +#endif + *timeoutp = timeout; + + return res; +} + +/* s.connect(sockaddr) method */ + +static PyObject * +sock_connect(PySocketSockObject *s, PyObject *addro) +{ + sock_addr_t addrbuf; + int addrlen; + int res; + int timeout; + + if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout); + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return NULL; + } + if (res != 0) + return s->errorhandler(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(connect_doc, +"connect(address)\n\ +\n\ +Connect the socket to a remote address. For IP sockets, the address\n\ +is a pair (host, port)."); + + +/* s.connect_ex(sockaddr) method */ + +static PyObject * +sock_connect_ex(PySocketSockObject *s, PyObject *addro) +{ + sock_addr_t addrbuf; + int addrlen; + int res; + int timeout; + + if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + res = internal_connect(s, SAS2SA(&addrbuf), addrlen, &timeout); + Py_END_ALLOW_THREADS + + /* Signals are not errors (though they may raise exceptions). Adapted + from PyErr_SetFromErrnoWithFilenameObject(). */ +#ifdef EINTR + if (res == EINTR && PyErr_CheckSignals()) + return NULL; +#endif + + return PyInt_FromLong((long) res); +} + +PyDoc_STRVAR(connect_ex_doc, +"connect_ex(address) -> errno\n\ +\n\ +This is like connect(address), but returns an error code (the errno value)\n\ +instead of raising an exception when an error occurs."); + + +/* s.fileno() method */ + +static PyObject * +sock_fileno(PySocketSockObject *s) +{ +#if SIZEOF_SOCKET_T <= SIZEOF_LONG + return PyInt_FromLong((long) s->sock_fd); +#else + return PyLong_FromLongLong((PY_LONG_LONG)s->sock_fd); +#endif +} + +PyDoc_STRVAR(fileno_doc, +"fileno() -> integer\n\ +\n\ +Return the integer file descriptor of the socket."); + + +#ifndef NO_DUP +/* s.dup() method */ + +static PyObject * +sock_dup(PySocketSockObject *s) +{ + SOCKET_T newfd; + PyObject *sock; + + newfd = dup(s->sock_fd); + if (newfd < 0) + return s->errorhandler(); + sock = (PyObject *) new_sockobject(newfd, + s->sock_family, + s->sock_type, + s->sock_proto); + if (sock == NULL) + SOCKETCLOSE(newfd); + return sock; +} + +PyDoc_STRVAR(dup_doc, +"dup() -> socket object\n\ +\n\ +Return a new socket object connected to the same system resource."); + +#endif + + +/* s.getsockname() method */ + +static PyObject * +sock_getsockname(PySocketSockObject *s) +{ + sock_addr_t addrbuf; + int res; + socklen_t addrlen; + + if (!getsockaddrlen(s, &addrlen)) + return NULL; + memset(&addrbuf, 0, addrlen); + Py_BEGIN_ALLOW_THREADS + res = getsockname(s->sock_fd, SAS2SA(&addrbuf), &addrlen); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); + return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, + s->sock_proto); +} + +PyDoc_STRVAR(getsockname_doc, +"getsockname() -> address info\n\ +\n\ +Return the address of the local endpoint. For IP sockets, the address\n\ +info is a pair (hostaddr, port)."); + + +#ifdef HAVE_GETPEERNAME /* Cray APP doesn't have this :-( */ +/* s.getpeername() method */ + +static PyObject * +sock_getpeername(PySocketSockObject *s) +{ + sock_addr_t addrbuf; + int res; + socklen_t addrlen; + + if (!getsockaddrlen(s, &addrlen)) + return NULL; + memset(&addrbuf, 0, addrlen); + Py_BEGIN_ALLOW_THREADS + res = getpeername(s->sock_fd, SAS2SA(&addrbuf), &addrlen); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); + return makesockaddr(s->sock_fd, SAS2SA(&addrbuf), addrlen, + s->sock_proto); +} + +PyDoc_STRVAR(getpeername_doc, +"getpeername() -> address info\n\ +\n\ +Return the address of the remote endpoint. For IP sockets, the address\n\ +info is a pair (hostaddr, port)."); + +#endif /* HAVE_GETPEERNAME */ + + +/* s.listen(n) method */ + +static PyObject * +sock_listen(PySocketSockObject *s, PyObject *arg) +{ + int backlog; + int res; + + backlog = PyInt_AsLong(arg); + if (backlog == -1 && PyErr_Occurred()) + return NULL; + Py_BEGIN_ALLOW_THREADS + if (backlog < 1) + backlog = 1; + res = listen(s->sock_fd, backlog); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(listen_doc, +"listen(backlog)\n\ +\n\ +Enable a server to accept connections. The backlog argument must be at\n\ +least 1; it specifies the number of unaccepted connection that the system\n\ +will allow before refusing new connections."); + + +#ifndef NO_DUP +/* s.makefile(mode) method. + Create a new open file object referring to a dupped version of + the socket's file descriptor. (The dup() call is necessary so + that the open file and socket objects may be closed independent + of each other.) + The mode argument specifies 'r' or 'w' passed to fdopen(). */ + +static PyObject * +sock_makefile(PySocketSockObject *s, PyObject *args) +{ + extern int fclose(FILE *); + char *mode = "r"; + int bufsize = -1; +#ifdef MS_WIN32 + Py_intptr_t fd; +#else + int fd; +#endif + FILE *fp; + PyObject *f; +#ifdef __VMS + char *mode_r = "r"; + char *mode_w = "w"; +#endif + + if (!PyArg_ParseTuple(args, "|si:makefile", &mode, &bufsize)) + return NULL; +#ifdef __VMS + if (strcmp(mode,"rb") == 0) { + mode = mode_r; + } + else { + if (strcmp(mode,"wb") == 0) { + mode = mode_w; + } + } +#endif +#ifdef MS_WIN32 + if (((fd = _open_osfhandle(s->sock_fd, _O_BINARY)) < 0) || + ((fd = dup(fd)) < 0) || ((fp = fdopen(fd, mode)) == NULL)) +#else + if ((fd = dup(s->sock_fd)) < 0 || (fp = fdopen(fd, mode)) == NULL) +#endif + { + if (fd >= 0) + SOCKETCLOSE(fd); + return s->errorhandler(); + } + f = PyFile_FromFile(fp, "<socket>", mode, fclose); + if (f != NULL) + PyFile_SetBufSize(f, bufsize); + return f; +} + +PyDoc_STRVAR(makefile_doc, +"makefile([mode[, buffersize]]) -> file object\n\ +\n\ +Return a regular file object corresponding to the socket.\n\ +The mode and buffersize arguments are as for the built-in open() function."); + +#endif /* NO_DUP */ + +/* + * This is the guts of the recv() and recv_into() methods, which reads into a + * char buffer. If you have any inc/def ref to do to the objects that contain + * the buffer, do it in the caller. This function returns the number of bytes + * succesfully read. If there was an error, it returns -1. Note that it is + * also possible that we return a number of bytes smaller than the request + * bytes. + */ +static ssize_t +sock_recv_guts(PySocketSockObject *s, char* cbuf, int len, int flags) +{ + ssize_t outlen = -1; + int timeout; +#ifdef __VMS + int remaining; + char *read_buf; +#endif + + if (!IS_SELECTABLE(s)) { + select_error(); + return -1; + } + +#ifndef __VMS + Py_BEGIN_ALLOW_THREADS + timeout = internal_select(s, 0); + if (!timeout) + outlen = recv(s->sock_fd, cbuf, len, flags); + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return -1; + } + if (outlen < 0) { + /* Note: the call to errorhandler() ALWAYS indirectly returned + NULL, so ignore its return value */ + s->errorhandler(); + return -1; + } +#else + read_buf = cbuf; + remaining = len; + while (remaining != 0) { + unsigned int segment; + int nread = -1; + + segment = remaining /SEGMENT_SIZE; + if (segment != 0) { + segment = SEGMENT_SIZE; + } + else { + segment = remaining; + } + + Py_BEGIN_ALLOW_THREADS + timeout = internal_select(s, 0); + if (!timeout) + nread = recv(s->sock_fd, read_buf, segment, flags); + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return -1; + } + if (nread < 0) { + s->errorhandler(); + return -1; + } + if (nread != remaining) { + read_buf += nread; + break; + } + + remaining -= segment; + read_buf += segment; + } + outlen = read_buf - cbuf; +#endif /* !__VMS */ + + return outlen; +} + + +/* s.recv(nbytes [,flags]) method */ + +static PyObject * +sock_recv(PySocketSockObject *s, PyObject *args) +{ + int recvlen, flags = 0; + ssize_t outlen; + PyObject *buf; + + if (!PyArg_ParseTuple(args, "i|i:recv", &recvlen, &flags)) + return NULL; + + if (recvlen < 0) { + PyErr_SetString(PyExc_ValueError, + "negative buffersize in recv"); + return NULL; + } + + /* Allocate a new string. */ + buf = PyString_FromStringAndSize((char *) 0, recvlen); + if (buf == NULL) + return NULL; + + /* Call the guts */ + outlen = sock_recv_guts(s, PyString_AS_STRING(buf), recvlen, flags); + if (outlen < 0) { + /* An error occurred, release the string and return an + error. */ + Py_DECREF(buf); + return NULL; + } + if (outlen != recvlen) { + /* We did not read as many bytes as we anticipated, resize the + string if possible and be succesful. */ + if (_PyString_Resize(&buf, outlen) < 0) + /* Oopsy, not so succesful after all. */ + return NULL; + } + + return buf; +} + +PyDoc_STRVAR(recv_doc, +"recv(buffersize[, flags]) -> data\n\ +\n\ +Receive up to buffersize bytes from the socket. For the optional flags\n\ +argument, see the Unix manual. When no data is available, block until\n\ +at least one byte is available or until the remote end is closed. When\n\ +the remote end is closed and all data is read, return the empty string."); + + +/* s.recv_into(buffer, [nbytes [,flags]]) method */ + +static PyObject* +sock_recv_into(PySocketSockObject *s, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"buffer", "nbytes", "flags", 0}; + + int recvlen = 0, flags = 0; + ssize_t readlen; + char *buf; + int buflen; + + /* Get the buffer's memory */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recv_into", kwlist, + &buf, &buflen, &recvlen, &flags)) + return NULL; + assert(buf != 0 && buflen > 0); + + if (recvlen < 0) { + PyErr_SetString(PyExc_ValueError, + "negative buffersize in recv_into"); + return NULL; + } + if (recvlen == 0) { + /* If nbytes was not specified, use the buffer's length */ + recvlen = buflen; + } + + /* Check if the buffer is large enough */ + if (buflen < recvlen) { + PyErr_SetString(PyExc_ValueError, + "buffer too small for requested bytes"); + return NULL; + } + + /* Call the guts */ + readlen = sock_recv_guts(s, buf, recvlen, flags); + if (readlen < 0) { + /* Return an error. */ + return NULL; + } + + /* Return the number of bytes read. Note that we do not do anything + special here in the case that readlen < recvlen. */ + return PyInt_FromSsize_t(readlen); +} + +PyDoc_STRVAR(recv_into_doc, +"recv_into(buffer, [nbytes[, flags]]) -> nbytes_read\n\ +\n\ +A version of recv() that stores its data into a buffer rather than creating \n\ +a new string. Receive up to buffersize bytes from the socket. If buffersize \n\ +is not specified (or 0), receive up to the size available in the given buffer.\n\ +\n\ +See recv() for documentation about the flags."); + + +/* + * This is the guts of the recv() and recv_into() methods, which reads into a + * char buffer. If you have any inc/def ref to do to the objects that contain + * the buffer, do it in the caller. This function returns the number of bytes + * succesfully read. If there was an error, it returns -1. Note that it is + * also possible that we return a number of bytes smaller than the request + * bytes. + * + * 'addr' is a return value for the address object. Note that you must decref + * it yourself. + */ +static ssize_t +sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, int len, int flags, + PyObject** addr) +{ + sock_addr_t addrbuf; + int timeout; + ssize_t n = -1; + socklen_t addrlen; + + *addr = NULL; + + if (!getsockaddrlen(s, &addrlen)) + return -1; + + if (!IS_SELECTABLE(s)) { + select_error(); + return -1; + } + + Py_BEGIN_ALLOW_THREADS + memset(&addrbuf, 0, addrlen); + timeout = internal_select(s, 0); + if (!timeout) { +#ifndef MS_WINDOWS +#if defined(PYOS_OS2) && !defined(PYCC_GCC) + n = recvfrom(s->sock_fd, cbuf, len, flags, + SAS2SA(&addrbuf), &addrlen); +#else + n = recvfrom(s->sock_fd, cbuf, len, flags, + (void *) &addrbuf, &addrlen); +#endif +#else + n = recvfrom(s->sock_fd, cbuf, len, flags, + SAS2SA(&addrbuf), &addrlen); +#endif + } + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return -1; + } + if (n < 0) { + s->errorhandler(); + return -1; + } + + if (!(*addr = makesockaddr(s->sock_fd, SAS2SA(&addrbuf), + addrlen, s->sock_proto))) + return -1; + + return n; +} + +/* s.recvfrom(nbytes [,flags]) method */ + +static PyObject * +sock_recvfrom(PySocketSockObject *s, PyObject *args) +{ + PyObject *buf = NULL; + PyObject *addr = NULL; + PyObject *ret = NULL; + int recvlen, flags = 0; + ssize_t outlen; + + if (!PyArg_ParseTuple(args, "i|i:recvfrom", &recvlen, &flags)) + return NULL; + + if (recvlen < 0) { + PyErr_SetString(PyExc_ValueError, + "negative buffersize in recvfrom"); + return NULL; + } + + buf = PyString_FromStringAndSize((char *) 0, recvlen); + if (buf == NULL) + return NULL; + + outlen = sock_recvfrom_guts(s, PyString_AS_STRING(buf), + recvlen, flags, &addr); + if (outlen < 0) { + goto finally; + } + + if (outlen != recvlen) { + /* We did not read as many bytes as we anticipated, resize the + string if possible and be succesful. */ + if (_PyString_Resize(&buf, outlen) < 0) + /* Oopsy, not so succesful after all. */ + goto finally; + } + + ret = PyTuple_Pack(2, buf, addr); + +finally: + Py_XDECREF(buf); + Py_XDECREF(addr); + return ret; +} + +PyDoc_STRVAR(recvfrom_doc, +"recvfrom(buffersize[, flags]) -> (data, address info)\n\ +\n\ +Like recv(buffersize, flags) but also return the sender's address info."); + + +/* s.recvfrom_into(buffer[, nbytes [,flags]]) method */ + +static PyObject * +sock_recvfrom_into(PySocketSockObject *s, PyObject *args, PyObject* kwds) +{ + static char *kwlist[] = {"buffer", "nbytes", "flags", 0}; + + int recvlen = 0, flags = 0; + ssize_t readlen; + char *buf; + int buflen; + + PyObject *addr = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recvfrom_into", + kwlist, &buf, &buflen, + &recvlen, &flags)) + return NULL; + assert(buf != 0 && buflen > 0); + + if (recvlen < 0) { + PyErr_SetString(PyExc_ValueError, + "negative buffersize in recvfrom_into"); + return NULL; + } + if (recvlen == 0) { + /* If nbytes was not specified, use the buffer's length */ + recvlen = buflen; + } + + readlen = sock_recvfrom_guts(s, buf, recvlen, flags, &addr); + if (readlen < 0) { + /* Return an error */ + Py_XDECREF(addr); + return NULL; + } + + /* Return the number of bytes read and the address. Note that we do + not do anything special here in the case that readlen < recvlen. */ + return Py_BuildValue("lN", readlen, addr); +} + +PyDoc_STRVAR(recvfrom_into_doc, +"recvfrom_into(buffer[, nbytes[, flags]]) -> (nbytes, address info)\n\ +\n\ +Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info."); + + +/* s.send(data [,flags]) method */ + +static PyObject * +sock_send(PySocketSockObject *s, PyObject *args) +{ + char *buf; + int len, n = -1, flags = 0, timeout; + + if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags)) + return NULL; + + if (!IS_SELECTABLE(s)) + return select_error(); + + Py_BEGIN_ALLOW_THREADS + timeout = internal_select(s, 1); + if (!timeout) +#ifdef __VMS + n = sendsegmented(s->sock_fd, buf, len, flags); +#else + n = send(s->sock_fd, buf, len, flags); +#endif + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return NULL; + } + if (n < 0) + return s->errorhandler(); + return PyInt_FromLong((long)n); +} + +PyDoc_STRVAR(send_doc, +"send(data[, flags]) -> count\n\ +\n\ +Send a data string to the socket. For the optional flags\n\ +argument, see the Unix manual. Return the number of bytes\n\ +sent; this may be less than len(data) if the network is busy."); + + +/* s.sendall(data [,flags]) method */ + +static PyObject * +sock_sendall(PySocketSockObject *s, PyObject *args) +{ + char *buf; + int len, n = -1, flags = 0, timeout; + + if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags)) + return NULL; + + if (!IS_SELECTABLE(s)) + return select_error(); + + Py_BEGIN_ALLOW_THREADS + do { + timeout = internal_select(s, 1); + n = -1; + if (timeout) + break; +#ifdef __VMS + n = sendsegmented(s->sock_fd, buf, len, flags); +#else + n = send(s->sock_fd, buf, len, flags); +#endif + if (n < 0) + break; + buf += n; + len -= n; + } while (len > 0); + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return NULL; + } + if (n < 0) + return s->errorhandler(); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(sendall_doc, +"sendall(data[, flags])\n\ +\n\ +Send a data string to the socket. For the optional flags\n\ +argument, see the Unix manual. This calls send() repeatedly\n\ +until all data is sent. If an error occurs, it's impossible\n\ +to tell how much data has been sent."); + + +/* s.sendto(data, [flags,] sockaddr) method */ + +static PyObject * +sock_sendto(PySocketSockObject *s, PyObject *args) +{ + PyObject *addro; + char *buf; + sock_addr_t addrbuf; + int addrlen, len, n = -1, flags, timeout; + + flags = 0; + if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "s#iO:sendto", + &buf, &len, &flags, &addro)) + return NULL; + } + + if (!IS_SELECTABLE(s)) + return select_error(); + + if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + timeout = internal_select(s, 1); + if (!timeout) + n = sendto(s->sock_fd, buf, len, flags, SAS2SA(&addrbuf), addrlen); + Py_END_ALLOW_THREADS + + if (timeout == 1) { + PyErr_SetString(socket_timeout, "timed out"); + return NULL; + } + if (n < 0) + return s->errorhandler(); + return PyInt_FromLong((long)n); +} + +PyDoc_STRVAR(sendto_doc, +"sendto(data[, flags], address) -> count\n\ +\n\ +Like send(data, flags) but allows specifying the destination address.\n\ +For IP sockets, the address is a pair (hostaddr, port)."); + + +/* s.shutdown(how) method */ + +static PyObject * +sock_shutdown(PySocketSockObject *s, PyObject *arg) +{ + int how; + int res; + + how = PyInt_AsLong(arg); + if (how == -1 && PyErr_Occurred()) + return NULL; + Py_BEGIN_ALLOW_THREADS + res = shutdown(s->sock_fd, how); + Py_END_ALLOW_THREADS + if (res < 0) + return s->errorhandler(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(shutdown_doc, +"shutdown(flag)\n\ +\n\ +Shut down the reading side of the socket (flag == SHUT_RD), the writing side\n\ +of the socket (flag == SHUT_WR), or both ends (flag == SHUT_RDWR)."); + + +/* List of methods for socket objects */ + +static PyMethodDef sock_methods[] = { + {"accept", (PyCFunction)sock_accept, METH_NOARGS, + accept_doc}, + {"bind", (PyCFunction)sock_bind, METH_O, + bind_doc}, + {"close", (PyCFunction)sock_close, METH_NOARGS, + close_doc}, + {"connect", (PyCFunction)sock_connect, METH_O, + connect_doc}, + {"connect_ex", (PyCFunction)sock_connect_ex, METH_O, + connect_ex_doc}, +#ifndef NO_DUP + {"dup", (PyCFunction)sock_dup, METH_NOARGS, + dup_doc}, +#endif + {"fileno", (PyCFunction)sock_fileno, METH_NOARGS, + fileno_doc}, +#ifdef HAVE_GETPEERNAME + {"getpeername", (PyCFunction)sock_getpeername, + METH_NOARGS, getpeername_doc}, +#endif + {"getsockname", (PyCFunction)sock_getsockname, + METH_NOARGS, getsockname_doc}, + {"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS, + getsockopt_doc}, + {"listen", (PyCFunction)sock_listen, METH_O, + listen_doc}, +#ifndef NO_DUP + {"makefile", (PyCFunction)sock_makefile, METH_VARARGS, + makefile_doc}, +#endif + {"recv", (PyCFunction)sock_recv, METH_VARARGS, + recv_doc}, + {"recv_into", (PyCFunction)sock_recv_into, METH_VARARGS | METH_KEYWORDS, + recv_into_doc}, + {"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS, + recvfrom_doc}, + {"recvfrom_into", (PyCFunction)sock_recvfrom_into, METH_VARARGS | METH_KEYWORDS, + recvfrom_into_doc}, + {"send", (PyCFunction)sock_send, METH_VARARGS, + send_doc}, + {"sendall", (PyCFunction)sock_sendall, METH_VARARGS, + sendall_doc}, + {"sendto", (PyCFunction)sock_sendto, METH_VARARGS, + sendto_doc}, + {"setblocking", (PyCFunction)sock_setblocking, METH_O, + setblocking_doc}, + {"settimeout", (PyCFunction)sock_settimeout, METH_O, + settimeout_doc}, + {"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS, + gettimeout_doc}, + {"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS, + setsockopt_doc}, + {"shutdown", (PyCFunction)sock_shutdown, METH_O, + shutdown_doc}, +#ifdef RISCOS + {"sleeptaskw", (PyCFunction)sock_sleeptaskw, METH_O, + sleeptaskw_doc}, +#endif + {NULL, NULL} /* sentinel */ +}; + +/* SockObject members */ +static PyMemberDef sock_memberlist[] = { + {"family", T_INT, offsetof(PySocketSockObject, sock_family), READONLY, "the socket family"}, + {"type", T_INT, offsetof(PySocketSockObject, sock_type), READONLY, "the socket type"}, + {"proto", T_INT, offsetof(PySocketSockObject, sock_proto), READONLY, "the socket protocol"}, + {"timeout", T_DOUBLE, offsetof(PySocketSockObject, sock_timeout), READONLY, "the socket timeout"}, + {0}, +}; + +/* Deallocate a socket object in response to the last Py_DECREF(). + First close the file description. */ + +static void +sock_dealloc(PySocketSockObject *s) +{ + if (s->sock_fd != -1) + (void) SOCKETCLOSE(s->sock_fd); + s->ob_type->tp_free((PyObject *)s); +} + + +static PyObject * +sock_repr(PySocketSockObject *s) +{ + char buf[512]; +#if SIZEOF_SOCKET_T > SIZEOF_LONG + if (s->sock_fd > LONG_MAX) { + /* this can occur on Win64, and actually there is a special + ugly printf formatter for decimal pointer length integer + printing, only bother if necessary*/ + PyErr_SetString(PyExc_OverflowError, + "no printf formatter to display " + "the socket descriptor in decimal"); + return NULL; + } +#endif + PyOS_snprintf( + buf, sizeof(buf), + "<socket object, fd=%ld, family=%d, type=%d, protocol=%d>", + (long)s->sock_fd, s->sock_family, + s->sock_type, + s->sock_proto); + return PyString_FromString(buf); +} + + +/* Create a new, uninitialized socket object. */ + +static PyObject * +sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *new; + + new = type->tp_alloc(type, 0); + if (new != NULL) { + ((PySocketSockObject *)new)->sock_fd = -1; + ((PySocketSockObject *)new)->sock_timeout = -1.0; + ((PySocketSockObject *)new)->errorhandler = &set_error; + } + return new; +} + + +/* Initialize a new socket object. */ + +/*ARGSUSED*/ +static int +sock_initobj(PyObject *self, PyObject *args, PyObject *kwds) +{ + PySocketSockObject *s = (PySocketSockObject *)self; + SOCKET_T fd; + int family = AF_INET, type = SOCK_STREAM, proto = 0; + static char *keywords[] = {"family", "type", "proto", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, + "|iii:socket", keywords, + &family, &type, &proto)) + return -1; + + Py_BEGIN_ALLOW_THREADS + fd = socket(family, type, proto); + Py_END_ALLOW_THREADS + +#ifdef MS_WINDOWS + if (fd == INVALID_SOCKET) +#else + if (fd < 0) +#endif + { + set_error(); + return -1; + } + init_sockobject(s, fd, family, type, proto); + + return 0; + +} + + +/* Type object for socket objects. */ + +static PyTypeObject sock_type = { + PyObject_HEAD_INIT(0) /* Must fill in type value later */ + 0, /* ob_size */ + "_socket.socket", /* tp_name */ + sizeof(PySocketSockObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)sock_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)sock_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + sock_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + sock_methods, /* tp_methods */ + sock_memberlist, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + sock_initobj, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + sock_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +/* Python interface to gethostname(). */ + +/*ARGSUSED*/ +static PyObject * +socket_gethostname(PyObject *self, PyObject *unused) +{ + char buf[1024]; + int res; + Py_BEGIN_ALLOW_THREADS + res = gethostname(buf, (int) sizeof buf - 1); + Py_END_ALLOW_THREADS + if (res < 0) + return set_error(); + buf[sizeof buf - 1] = '\0'; + return PyString_FromString(buf); +} + +PyDoc_STRVAR(gethostname_doc, +"gethostname() -> string\n\ +\n\ +Return the current host name."); + + +/* Python interface to gethostbyname(name). */ + +/*ARGSUSED*/ +static PyObject * +socket_gethostbyname(PyObject *self, PyObject *args) +{ + char *name; + sock_addr_t addrbuf; + + if (!PyArg_ParseTuple(args, "s:gethostbyname", &name)) + return NULL; + if (setipaddr(name, SAS2SA(&addrbuf), sizeof(addrbuf), AF_INET) < 0) + return NULL; + return makeipaddr(SAS2SA(&addrbuf), sizeof(struct sockaddr_in)); +} + +PyDoc_STRVAR(gethostbyname_doc, +"gethostbyname(host) -> address\n\ +\n\ +Return the IP address (a string of the form '255.255.255.255') for a host."); + + +/* Convenience function common to gethostbyname_ex and gethostbyaddr */ + +static PyObject * +gethost_common(struct hostent *h, struct sockaddr *addr, int alen, int af) +{ + char **pch; + PyObject *rtn_tuple = (PyObject *)NULL; + PyObject *name_list = (PyObject *)NULL; + PyObject *addr_list = (PyObject *)NULL; + PyObject *tmp; + + if (h == NULL) { + /* Let's get real error message to return */ +#ifndef RISCOS + set_herror(h_errno); +#else + PyErr_SetString(socket_error, "host not found"); +#endif + return NULL; + } + + if (h->h_addrtype != af) { +#ifdef HAVE_STRERROR + /* Let's get real error message to return */ + PyErr_SetString(socket_error, + (char *)strerror(EAFNOSUPPORT)); +#else + PyErr_SetString( + socket_error, + "Address family not supported by protocol family"); +#endif + return NULL; + } + + switch (af) { + + case AF_INET: + if (alen < sizeof(struct sockaddr_in)) + return NULL; + break; + +#ifdef ENABLE_IPV6 + case AF_INET6: + if (alen < sizeof(struct sockaddr_in6)) + return NULL; + break; +#endif + + } + + if ((name_list = PyList_New(0)) == NULL) + goto err; + + if ((addr_list = PyList_New(0)) == NULL) + goto err; + + /* SF #1511317: h_aliases can be NULL */ + if (h->h_aliases) { + for (pch = h->h_aliases; *pch != NULL; pch++) { + int status; + tmp = PyString_FromString(*pch); + if (tmp == NULL) + goto err; + + status = PyList_Append(name_list, tmp); + Py_DECREF(tmp); + + if (status) + goto err; + } + } + + for (pch = h->h_addr_list; *pch != NULL; pch++) { + int status; + + switch (af) { + + case AF_INET: + { + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = af; +#ifdef HAVE_SOCKADDR_SA_LEN + sin.sin_len = sizeof(sin); +#endif + memcpy(&sin.sin_addr, *pch, sizeof(sin.sin_addr)); + tmp = makeipaddr((struct sockaddr *)&sin, sizeof(sin)); + + if (pch == h->h_addr_list && alen >= sizeof(sin)) + memcpy((char *) addr, &sin, sizeof(sin)); + break; + } + +#ifdef ENABLE_IPV6 + case AF_INET6: + { + struct sockaddr_in6 sin6; + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = af; +#ifdef HAVE_SOCKADDR_SA_LEN + sin6.sin6_len = sizeof(sin6); +#endif + memcpy(&sin6.sin6_addr, *pch, sizeof(sin6.sin6_addr)); + tmp = makeipaddr((struct sockaddr *)&sin6, + sizeof(sin6)); + + if (pch == h->h_addr_list && alen >= sizeof(sin6)) + memcpy((char *) addr, &sin6, sizeof(sin6)); + break; + } +#endif + + default: /* can't happen */ + PyErr_SetString(socket_error, + "unsupported address family"); + return NULL; + } + + if (tmp == NULL) + goto err; + + status = PyList_Append(addr_list, tmp); + Py_DECREF(tmp); + + if (status) + goto err; + } + + rtn_tuple = Py_BuildValue("sOO", h->h_name, name_list, addr_list); + + err: + Py_XDECREF(name_list); + Py_XDECREF(addr_list); + return rtn_tuple; +} + + +/* Python interface to gethostbyname_ex(name). */ + +/*ARGSUSED*/ +static PyObject * +socket_gethostbyname_ex(PyObject *self, PyObject *args) +{ + char *name; + struct hostent *h; +#ifdef ENABLE_IPV6 + struct sockaddr_storage addr; +#else + struct sockaddr_in addr; +#endif + struct sockaddr *sa; + PyObject *ret; +#ifdef HAVE_GETHOSTBYNAME_R + struct hostent hp_allocated; +#ifdef HAVE_GETHOSTBYNAME_R_3_ARG + struct hostent_data data; +#else + char buf[16384]; + int buf_len = (sizeof buf) - 1; + int errnop; +#endif +#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG) + int result; +#endif +#endif /* HAVE_GETHOSTBYNAME_R */ + + if (!PyArg_ParseTuple(args, "s:gethostbyname_ex", &name)) + return NULL; + if (setipaddr(name, (struct sockaddr *)&addr, sizeof(addr), AF_INET) < 0) + return NULL; + Py_BEGIN_ALLOW_THREADS +#ifdef HAVE_GETHOSTBYNAME_R +#if defined(HAVE_GETHOSTBYNAME_R_6_ARG) + result = gethostbyname_r(name, &hp_allocated, buf, buf_len, + &h, &errnop); +#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) + h = gethostbyname_r(name, &hp_allocated, buf, buf_len, &errnop); +#else /* HAVE_GETHOSTBYNAME_R_3_ARG */ + memset((void *) &data, '\0', sizeof(data)); + result = gethostbyname_r(name, &hp_allocated, &data); + h = (result != 0) ? NULL : &hp_allocated; +#endif +#else /* not HAVE_GETHOSTBYNAME_R */ +#ifdef USE_GETHOSTBYNAME_LOCK + PyThread_acquire_lock(netdb_lock, 1); +#endif + h = gethostbyname(name); +#endif /* HAVE_GETHOSTBYNAME_R */ + Py_END_ALLOW_THREADS + /* Some C libraries would require addr.__ss_family instead of + addr.ss_family. + Therefore, we cast the sockaddr_storage into sockaddr to + access sa_family. */ + sa = (struct sockaddr*)&addr; + ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), + sa->sa_family); +#ifdef USE_GETHOSTBYNAME_LOCK + PyThread_release_lock(netdb_lock); +#endif + return ret; +} + +PyDoc_STRVAR(ghbn_ex_doc, +"gethostbyname_ex(host) -> (name, aliaslist, addresslist)\n\ +\n\ +Return the true host name, a list of aliases, and a list of IP addresses,\n\ +for a host. The host argument is a string giving a host name or IP number."); + + +/* Python interface to gethostbyaddr(IP). */ + +/*ARGSUSED*/ +static PyObject * +socket_gethostbyaddr(PyObject *self, PyObject *args) +{ +#ifdef ENABLE_IPV6 + struct sockaddr_storage addr; +#else + struct sockaddr_in addr; +#endif + struct sockaddr *sa = (struct sockaddr *)&addr; + char *ip_num; + struct hostent *h; + PyObject *ret; +#ifdef HAVE_GETHOSTBYNAME_R + struct hostent hp_allocated; +#ifdef HAVE_GETHOSTBYNAME_R_3_ARG + struct hostent_data data; +#else + char buf[16384]; + int buf_len = (sizeof buf) - 1; + int errnop; +#endif +#if defined(HAVE_GETHOSTBYNAME_R_3_ARG) || defined(HAVE_GETHOSTBYNAME_R_6_ARG) + int result; +#endif +#endif /* HAVE_GETHOSTBYNAME_R */ + char *ap; + int al; + int af; + + if (!PyArg_ParseTuple(args, "s:gethostbyaddr", &ip_num)) + return NULL; + af = AF_UNSPEC; + if (setipaddr(ip_num, sa, sizeof(addr), af) < 0) + return NULL; + af = sa->sa_family; + ap = NULL; + al = 0; + switch (af) { + case AF_INET: + ap = (char *)&((struct sockaddr_in *)sa)->sin_addr; + al = sizeof(((struct sockaddr_in *)sa)->sin_addr); + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + ap = (char *)&((struct sockaddr_in6 *)sa)->sin6_addr; + al = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); + break; +#endif + default: + PyErr_SetString(socket_error, "unsupported address family"); + return NULL; + } + Py_BEGIN_ALLOW_THREADS +#ifdef HAVE_GETHOSTBYNAME_R +#if defined(HAVE_GETHOSTBYNAME_R_6_ARG) + result = gethostbyaddr_r(ap, al, af, + &hp_allocated, buf, buf_len, + &h, &errnop); +#elif defined(HAVE_GETHOSTBYNAME_R_5_ARG) + h = gethostbyaddr_r(ap, al, af, + &hp_allocated, buf, buf_len, &errnop); +#else /* HAVE_GETHOSTBYNAME_R_3_ARG */ + memset((void *) &data, '\0', sizeof(data)); + result = gethostbyaddr_r(ap, al, af, &hp_allocated, &data); + h = (result != 0) ? NULL : &hp_allocated; +#endif +#else /* not HAVE_GETHOSTBYNAME_R */ +#ifdef USE_GETHOSTBYNAME_LOCK + PyThread_acquire_lock(netdb_lock, 1); +#endif + h = gethostbyaddr(ap, al, af); +#endif /* HAVE_GETHOSTBYNAME_R */ + Py_END_ALLOW_THREADS + ret = gethost_common(h, (struct sockaddr *)&addr, sizeof(addr), af); +#ifdef USE_GETHOSTBYNAME_LOCK + PyThread_release_lock(netdb_lock); +#endif + return ret; +} + +PyDoc_STRVAR(gethostbyaddr_doc, +"gethostbyaddr(host) -> (name, aliaslist, addresslist)\n\ +\n\ +Return the true host name, a list of aliases, and a list of IP addresses,\n\ +for a host. The host argument is a string giving a host name or IP number."); + + +/* Python interface to getservbyname(name). + This only returns the port number, since the other info is already + known or not useful (like the list of aliases). */ + +/*ARGSUSED*/ +static PyObject * +socket_getservbyname(PyObject *self, PyObject *args) +{ + char *name, *proto=NULL; + struct servent *sp; + if (!PyArg_ParseTuple(args, "s|s:getservbyname", &name, &proto)) + return NULL; + Py_BEGIN_ALLOW_THREADS + sp = getservbyname(name, proto); + Py_END_ALLOW_THREADS + if (sp == NULL) { + PyErr_SetString(socket_error, "service/proto not found"); + return NULL; + } + return PyInt_FromLong((long) ntohs(sp->s_port)); +} + +PyDoc_STRVAR(getservbyname_doc, +"getservbyname(servicename[, protocolname]) -> integer\n\ +\n\ +Return a port number from a service name and protocol name.\n\ +The optional protocol name, if given, should be 'tcp' or 'udp',\n\ +otherwise any protocol will match."); + + +/* Python interface to getservbyport(port). + This only returns the service name, since the other info is already + known or not useful (like the list of aliases). */ + +/*ARGSUSED*/ +static PyObject * +socket_getservbyport(PyObject *self, PyObject *args) +{ + unsigned short port; + char *proto=NULL; + struct servent *sp; + if (!PyArg_ParseTuple(args, "H|s:getservbyport", &port, &proto)) + return NULL; + Py_BEGIN_ALLOW_THREADS + sp = getservbyport(htons(port), proto); + Py_END_ALLOW_THREADS + if (sp == NULL) { + PyErr_SetString(socket_error, "port/proto not found"); + return NULL; + } + return PyString_FromString(sp->s_name); +} + +PyDoc_STRVAR(getservbyport_doc, +"getservbyport(port[, protocolname]) -> string\n\ +\n\ +Return the service name from a port number and protocol name.\n\ +The optional protocol name, if given, should be 'tcp' or 'udp',\n\ +otherwise any protocol will match."); + +/* Python interface to getprotobyname(name). + This only returns the protocol number, since the other info is + already known or not useful (like the list of aliases). */ + +/*ARGSUSED*/ +static PyObject * +socket_getprotobyname(PyObject *self, PyObject *args) +{ + char *name; + struct protoent *sp; +#ifdef __BEOS__ +/* Not available in BeOS yet. - [cjh] */ + PyErr_SetString(socket_error, "getprotobyname not supported"); + return NULL; +#else + if (!PyArg_ParseTuple(args, "s:getprotobyname", &name)) + return NULL; + Py_BEGIN_ALLOW_THREADS + sp = getprotobyname(name); + Py_END_ALLOW_THREADS + if (sp == NULL) { + PyErr_SetString(socket_error, "protocol not found"); + return NULL; + } + return PyInt_FromLong((long) sp->p_proto); +#endif +} + +PyDoc_STRVAR(getprotobyname_doc, +"getprotobyname(name) -> integer\n\ +\n\ +Return the protocol number for the named protocol. (Rarely used.)"); + + +#ifdef HAVE_SOCKETPAIR +/* Create a pair of sockets using the socketpair() function. + Arguments as for socket() except the default family is AF_UNIX if + defined on the platform; otherwise, the default is AF_INET. */ + +/*ARGSUSED*/ +static PyObject * +socket_socketpair(PyObject *self, PyObject *args) +{ + PySocketSockObject *s0 = NULL, *s1 = NULL; + SOCKET_T sv[2]; + int family, type = SOCK_STREAM, proto = 0; + PyObject *res = NULL; + +#if defined(AF_UNIX) + family = AF_UNIX; +#else + family = AF_INET; +#endif + if (!PyArg_ParseTuple(args, "|iii:socketpair", + &family, &type, &proto)) + return NULL; + /* Create a pair of socket fds */ + if (socketpair(family, type, proto, sv) < 0) + return set_error(); + s0 = new_sockobject(sv[0], family, type, proto); + if (s0 == NULL) + goto finally; + s1 = new_sockobject(sv[1], family, type, proto); + if (s1 == NULL) + goto finally; + res = PyTuple_Pack(2, s0, s1); + +finally: + if (res == NULL) { + if (s0 == NULL) + SOCKETCLOSE(sv[0]); + if (s1 == NULL) + SOCKETCLOSE(sv[1]); + } + Py_XDECREF(s0); + Py_XDECREF(s1); + return res; +} + +PyDoc_STRVAR(socketpair_doc, +"socketpair([family[, type[, proto]]]) -> (socket object, socket object)\n\ +\n\ +Create a pair of socket objects from the sockets returned by the platform\n\ +socketpair() function.\n\ +The arguments are the same as for socket() except the default family is\n\ +AF_UNIX if defined on the platform; otherwise, the default is AF_INET."); + +#endif /* HAVE_SOCKETPAIR */ + + +#ifndef NO_DUP +/* Create a socket object from a numeric file description. + Useful e.g. if stdin is a socket. + Additional arguments as for socket(). */ + +/*ARGSUSED*/ +static PyObject * +socket_fromfd(PyObject *self, PyObject *args) +{ + PySocketSockObject *s; + SOCKET_T fd; + int family, type, proto = 0; + if (!PyArg_ParseTuple(args, "iii|i:fromfd", + &fd, &family, &type, &proto)) + return NULL; + /* Dup the fd so it and the socket can be closed independently */ + fd = dup(fd); + if (fd < 0) + return set_error(); + s = new_sockobject(fd, family, type, proto); + return (PyObject *) s; +} + +PyDoc_STRVAR(fromfd_doc, +"fromfd(fd, family, type[, proto]) -> socket object\n\ +\n\ +Create a socket object from a duplicate of the given\n\ +file descriptor.\n\ +The remaining arguments are the same as for socket()."); + +#endif /* NO_DUP */ + + +static PyObject * +socket_ntohs(PyObject *self, PyObject *args) +{ + int x1, x2; + + if (!PyArg_ParseTuple(args, "i:ntohs", &x1)) { + return NULL; + } + x2 = (int)ntohs((short)x1); + return PyInt_FromLong(x2); +} + +PyDoc_STRVAR(ntohs_doc, +"ntohs(integer) -> integer\n\ +\n\ +Convert a 16-bit integer from network to host byte order."); + + +static PyObject * +socket_ntohl(PyObject *self, PyObject *arg) +{ + unsigned long x; + + if (PyInt_Check(arg)) { + x = PyInt_AS_LONG(arg); + if (x == (unsigned long) -1 && PyErr_Occurred()) + return NULL; + } + else if (PyLong_Check(arg)) { + x = PyLong_AsUnsignedLong(arg); + if (x == (unsigned long) -1 && PyErr_Occurred()) + return NULL; +#if SIZEOF_LONG > 4 + { + unsigned long y; + /* only want the trailing 32 bits */ + y = x & 0xFFFFFFFFUL; + if (y ^ x) + return PyErr_Format(PyExc_OverflowError, + "long int larger than 32 bits"); + x = y; + } +#endif + } + else + return PyErr_Format(PyExc_TypeError, + "expected int/long, %s found", + arg->ob_type->tp_name); + if (x == (unsigned long) -1 && PyErr_Occurred()) + return NULL; + return PyInt_FromLong(ntohl(x)); +} + +PyDoc_STRVAR(ntohl_doc, +"ntohl(integer) -> integer\n\ +\n\ +Convert a 32-bit integer from network to host byte order."); + + +static PyObject * +socket_htons(PyObject *self, PyObject *args) +{ + int x1, x2; + + if (!PyArg_ParseTuple(args, "i:htons", &x1)) { + return NULL; + } + x2 = (int)htons((short)x1); + return PyInt_FromLong(x2); +} + +PyDoc_STRVAR(htons_doc, +"htons(integer) -> integer\n\ +\n\ +Convert a 16-bit integer from host to network byte order."); + + +static PyObject * +socket_htonl(PyObject *self, PyObject *arg) +{ + unsigned long x; + + if (PyInt_Check(arg)) { + x = PyInt_AS_LONG(arg); + if (x == (unsigned long) -1 && PyErr_Occurred()) + return NULL; + } + else if (PyLong_Check(arg)) { + x = PyLong_AsUnsignedLong(arg); + if (x == (unsigned long) -1 && PyErr_Occurred()) + return NULL; +#if SIZEOF_LONG > 4 + { + unsigned long y; + /* only want the trailing 32 bits */ + y = x & 0xFFFFFFFFUL; + if (y ^ x) + return PyErr_Format(PyExc_OverflowError, + "long int larger than 32 bits"); + x = y; + } +#endif + } + else + return PyErr_Format(PyExc_TypeError, + "expected int/long, %s found", + arg->ob_type->tp_name); + return PyInt_FromLong(htonl(x)); +} + +PyDoc_STRVAR(htonl_doc, +"htonl(integer) -> integer\n\ +\n\ +Convert a 32-bit integer from host to network byte order."); + +/* socket.inet_aton() and socket.inet_ntoa() functions. */ + +PyDoc_STRVAR(inet_aton_doc, +"inet_aton(string) -> packed 32-bit IP representation\n\ +\n\ +Convert an IP address in string format (123.45.67.89) to the 32-bit packed\n\ +binary format used in low-level network functions."); + +static PyObject* +socket_inet_aton(PyObject *self, PyObject *args) +{ +#ifndef INADDR_NONE +#define INADDR_NONE (-1) +#endif +#ifdef HAVE_INET_ATON + struct in_addr buf; +#endif + +#if !defined(HAVE_INET_ATON) || defined(USE_INET_ATON_WEAKLINK) + /* Have to use inet_addr() instead */ + unsigned long packed_addr; +#endif + char *ip_addr; + + if (!PyArg_ParseTuple(args, "s:inet_aton", &ip_addr)) + return NULL; + + +#ifdef HAVE_INET_ATON + +#ifdef USE_INET_ATON_WEAKLINK + if (inet_aton != NULL) { +#endif + if (inet_aton(ip_addr, &buf)) + return PyString_FromStringAndSize((char *)(&buf), + sizeof(buf)); + + PyErr_SetString(socket_error, + "illegal IP address string passed to inet_aton"); + return NULL; + +#ifdef USE_INET_ATON_WEAKLINK + } else { +#endif + +#endif + +#if !defined(HAVE_INET_ATON) || defined(USE_INET_ATON_WEAKLINK) + + /* special-case this address as inet_addr might return INADDR_NONE + * for this */ + if (strcmp(ip_addr, "255.255.255.255") == 0) { + packed_addr = 0xFFFFFFFF; + } else { + + packed_addr = inet_addr(ip_addr); + + if (packed_addr == INADDR_NONE) { /* invalid address */ + PyErr_SetString(socket_error, + "illegal IP address string passed to inet_aton"); + return NULL; + } + } + return PyString_FromStringAndSize((char *) &packed_addr, + sizeof(packed_addr)); + +#ifdef USE_INET_ATON_WEAKLINK + } +#endif + +#endif +} + +PyDoc_STRVAR(inet_ntoa_doc, +"inet_ntoa(packed_ip) -> ip_address_string\n\ +\n\ +Convert an IP address from 32-bit packed binary format to string format"); + +static PyObject* +socket_inet_ntoa(PyObject *self, PyObject *args) +{ + char *packed_str; + int addr_len; + struct in_addr packed_addr; + + if (!PyArg_ParseTuple(args, "s#:inet_ntoa", &packed_str, &addr_len)) { + return NULL; + } + + if (addr_len != sizeof(packed_addr)) { + PyErr_SetString(socket_error, + "packed IP wrong length for inet_ntoa"); + return NULL; + } + + memcpy(&packed_addr, packed_str, addr_len); + + return PyString_FromString(inet_ntoa(packed_addr)); +} + +#ifdef HAVE_INET_PTON + +PyDoc_STRVAR(inet_pton_doc, +"inet_pton(af, ip) -> packed IP address string\n\ +\n\ +Convert an IP address from string format to a packed string suitable\n\ +for use with low-level network functions."); + +static PyObject * +socket_inet_pton(PyObject *self, PyObject *args) +{ + int af; + char* ip; + int retval; +#ifdef ENABLE_IPV6 + char packed[MAX(sizeof(struct in_addr), sizeof(struct in6_addr))]; +#else + char packed[sizeof(struct in_addr)]; +#endif + if (!PyArg_ParseTuple(args, "is:inet_pton", &af, &ip)) { + return NULL; + } + +#if !defined(ENABLE_IPV6) && defined(AF_INET6) + if(af == AF_INET6) { + PyErr_SetString(socket_error, + "can't use AF_INET6, IPv6 is disabled"); + return NULL; + } +#endif + + retval = inet_pton(af, ip, packed); + if (retval < 0) { + PyErr_SetFromErrno(socket_error); + return NULL; + } else if (retval == 0) { + PyErr_SetString(socket_error, + "illegal IP address string passed to inet_pton"); + return NULL; + } else if (af == AF_INET) { + return PyString_FromStringAndSize(packed, + sizeof(struct in_addr)); +#ifdef ENABLE_IPV6 + } else if (af == AF_INET6) { + return PyString_FromStringAndSize(packed, + sizeof(struct in6_addr)); +#endif + } else { + PyErr_SetString(socket_error, "unknown address family"); + return NULL; + } +} + +PyDoc_STRVAR(inet_ntop_doc, +"inet_ntop(af, packed_ip) -> string formatted IP address\n\ +\n\ +Convert a packed IP address of the given family to string format."); + +static PyObject * +socket_inet_ntop(PyObject *self, PyObject *args) +{ + int af; + char* packed; + int len; + const char* retval; +#ifdef ENABLE_IPV6 + char ip[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) + 1]; +#else + char ip[INET_ADDRSTRLEN + 1]; +#endif + + /* Guarantee NUL-termination for PyString_FromString() below */ + memset((void *) &ip[0], '\0', sizeof(ip)); + + if (!PyArg_ParseTuple(args, "is#:inet_ntop", &af, &packed, &len)) { + return NULL; + } + + if (af == AF_INET) { + if (len != sizeof(struct in_addr)) { + PyErr_SetString(PyExc_ValueError, + "invalid length of packed IP address string"); + return NULL; + } +#ifdef ENABLE_IPV6 + } else if (af == AF_INET6) { + if (len != sizeof(struct in6_addr)) { + PyErr_SetString(PyExc_ValueError, + "invalid length of packed IP address string"); + return NULL; + } +#endif + } else { + PyErr_Format(PyExc_ValueError, + "unknown address family %d", af); + return NULL; + } + + retval = inet_ntop(af, packed, ip, sizeof(ip)); + if (!retval) { + PyErr_SetFromErrno(socket_error); + return NULL; + } else { + return PyString_FromString(retval); + } + + /* NOTREACHED */ + PyErr_SetString(PyExc_RuntimeError, "invalid handling of inet_ntop"); + return NULL; +} + +#endif /* HAVE_INET_PTON */ + +/* Python interface to getaddrinfo(host, port). */ + +/*ARGSUSED*/ +static PyObject * +socket_getaddrinfo(PyObject *self, PyObject *args) +{ + struct addrinfo hints, *res; + struct addrinfo *res0 = NULL; + PyObject *hobj = NULL; + PyObject *pobj = (PyObject *)NULL; + char pbuf[30]; + char *hptr, *pptr; + int family, socktype, protocol, flags; + int error; + PyObject *all = (PyObject *)NULL; + PyObject *single = (PyObject *)NULL; + PyObject *idna = NULL; + + family = socktype = protocol = flags = 0; + family = AF_UNSPEC; + if (!PyArg_ParseTuple(args, "OO|iiii:getaddrinfo", + &hobj, &pobj, &family, &socktype, + &protocol, &flags)) { + return NULL; + } + if (hobj == Py_None) { + hptr = NULL; + } else if (PyUnicode_Check(hobj)) { + idna = PyObject_CallMethod(hobj, "encode", "s", "idna"); + if (!idna) + return NULL; + hptr = PyString_AsString(idna); + } else if (PyString_Check(hobj)) { + hptr = PyString_AsString(hobj); + } else { + PyErr_SetString(PyExc_TypeError, + "getaddrinfo() argument 1 must be string or None"); + return NULL; + } + if (PyInt_Check(pobj)) { + PyOS_snprintf(pbuf, sizeof(pbuf), "%ld", PyInt_AsLong(pobj)); + pptr = pbuf; + } else if (PyString_Check(pobj)) { + pptr = PyString_AsString(pobj); + } else if (pobj == Py_None) { + pptr = (char *)NULL; + } else { + PyErr_SetString(socket_error, "Int or String expected"); + goto err; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = socktype; + hints.ai_protocol = protocol; + hints.ai_flags = flags; + Py_BEGIN_ALLOW_THREADS + ACQUIRE_GETADDRINFO_LOCK + error = getaddrinfo(hptr, pptr, &hints, &res0); + Py_END_ALLOW_THREADS + RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */ + if (error) { + set_gaierror(error); + goto err; + } + + if ((all = PyList_New(0)) == NULL) + goto err; + for (res = res0; res; res = res->ai_next) { + PyObject *addr = + makesockaddr(-1, res->ai_addr, res->ai_addrlen, protocol); + if (addr == NULL) + goto err; + single = Py_BuildValue("iiisO", res->ai_family, + res->ai_socktype, res->ai_protocol, + res->ai_canonname ? res->ai_canonname : "", + addr); + Py_DECREF(addr); + if (single == NULL) + goto err; + + if (PyList_Append(all, single)) + goto err; + Py_XDECREF(single); + } + Py_XDECREF(idna); + if (res0) + freeaddrinfo(res0); + return all; + err: + Py_XDECREF(single); + Py_XDECREF(all); + Py_XDECREF(idna); + if (res0) + freeaddrinfo(res0); + return (PyObject *)NULL; +} + +PyDoc_STRVAR(getaddrinfo_doc, +"getaddrinfo(host, port [, family, socktype, proto, flags])\n\ + -> list of (family, socktype, proto, canonname, sockaddr)\n\ +\n\ +Resolve host and port into addrinfo struct."); + +/* Python interface to getnameinfo(sa, flags). */ + +/*ARGSUSED*/ +static PyObject * +socket_getnameinfo(PyObject *self, PyObject *args) +{ + PyObject *sa = (PyObject *)NULL; + int flags; + char *hostp; + int port, flowinfo, scope_id; + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + struct addrinfo hints, *res = NULL; + int error; + PyObject *ret = (PyObject *)NULL; + + flags = flowinfo = scope_id = 0; + if (!PyArg_ParseTuple(args, "Oi:getnameinfo", &sa, &flags)) + return NULL; + if (!PyArg_ParseTuple(sa, "si|ii", + &hostp, &port, &flowinfo, &scope_id)) + return NULL; + PyOS_snprintf(pbuf, sizeof(pbuf), "%d", port); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /* make numeric port happy */ + Py_BEGIN_ALLOW_THREADS + ACQUIRE_GETADDRINFO_LOCK + error = getaddrinfo(hostp, pbuf, &hints, &res); + Py_END_ALLOW_THREADS + RELEASE_GETADDRINFO_LOCK /* see comment in setipaddr() */ + if (error) { + set_gaierror(error); + goto fail; + } + if (res->ai_next) { + PyErr_SetString(socket_error, + "sockaddr resolved to multiple addresses"); + goto fail; + } + switch (res->ai_family) { + case AF_INET: + { + char *t1; + int t2; + if (PyArg_ParseTuple(sa, "si", &t1, &t2) == 0) { + PyErr_SetString(socket_error, + "IPv4 sockaddr must be 2 tuple"); + goto fail; + } + break; + } +#ifdef ENABLE_IPV6 + case AF_INET6: + { + struct sockaddr_in6 *sin6; + sin6 = (struct sockaddr_in6 *)res->ai_addr; + sin6->sin6_flowinfo = flowinfo; + sin6->sin6_scope_id = scope_id; + break; + } +#endif + } + error = getnameinfo(res->ai_addr, res->ai_addrlen, + hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags); + if (error) { + set_gaierror(error); + goto fail; + } + ret = Py_BuildValue("ss", hbuf, pbuf); + +fail: + if (res) + freeaddrinfo(res); + return ret; +} + +PyDoc_STRVAR(getnameinfo_doc, +"getnameinfo(sockaddr, flags) --> (host, port)\n\ +\n\ +Get host and port for a sockaddr."); + + +/* Python API to getting and setting the default timeout value. */ + +static PyObject * +socket_getdefaulttimeout(PyObject *self) +{ + if (defaulttimeout < 0.0) { + Py_INCREF(Py_None); + return Py_None; + } + else + return PyFloat_FromDouble(defaulttimeout); +} + +PyDoc_STRVAR(getdefaulttimeout_doc, +"getdefaulttimeout() -> timeout\n\ +\n\ +Returns the default timeout in floating seconds for new socket objects.\n\ +A value of None indicates that new socket objects have no timeout.\n\ +When the socket module is first imported, the default is None."); + +static PyObject * +socket_setdefaulttimeout(PyObject *self, PyObject *arg) +{ + double timeout; + + if (arg == Py_None) + timeout = -1.0; + else { + timeout = PyFloat_AsDouble(arg); + if (timeout < 0.0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, + "Timeout value out of range"); + return NULL; + } + } + + defaulttimeout = timeout; + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setdefaulttimeout_doc, +"setdefaulttimeout(timeout)\n\ +\n\ +Set the default timeout in floating seconds for new socket objects.\n\ +A value of None indicates that new socket objects have no timeout.\n\ +When the socket module is first imported, the default is None."); + + +/* List of functions exported by this module. */ + +static PyMethodDef socket_methods[] = { + {"gethostbyname", socket_gethostbyname, + METH_VARARGS, gethostbyname_doc}, + {"gethostbyname_ex", socket_gethostbyname_ex, + METH_VARARGS, ghbn_ex_doc}, + {"gethostbyaddr", socket_gethostbyaddr, + METH_VARARGS, gethostbyaddr_doc}, + {"gethostname", socket_gethostname, + METH_NOARGS, gethostname_doc}, + {"getservbyname", socket_getservbyname, + METH_VARARGS, getservbyname_doc}, + {"getservbyport", socket_getservbyport, + METH_VARARGS, getservbyport_doc}, + {"getprotobyname", socket_getprotobyname, + METH_VARARGS, getprotobyname_doc}, +#ifndef NO_DUP + {"fromfd", socket_fromfd, + METH_VARARGS, fromfd_doc}, +#endif +#ifdef HAVE_SOCKETPAIR + {"socketpair", socket_socketpair, + METH_VARARGS, socketpair_doc}, +#endif + {"ntohs", socket_ntohs, + METH_VARARGS, ntohs_doc}, + {"ntohl", socket_ntohl, + METH_O, ntohl_doc}, + {"htons", socket_htons, + METH_VARARGS, htons_doc}, + {"htonl", socket_htonl, + METH_O, htonl_doc}, + {"inet_aton", socket_inet_aton, + METH_VARARGS, inet_aton_doc}, + {"inet_ntoa", socket_inet_ntoa, + METH_VARARGS, inet_ntoa_doc}, +#ifdef HAVE_INET_PTON + {"inet_pton", socket_inet_pton, + METH_VARARGS, inet_pton_doc}, + {"inet_ntop", socket_inet_ntop, + METH_VARARGS, inet_ntop_doc}, +#endif + {"getaddrinfo", socket_getaddrinfo, + METH_VARARGS, getaddrinfo_doc}, + {"getnameinfo", socket_getnameinfo, + METH_VARARGS, getnameinfo_doc}, + {"getdefaulttimeout", (PyCFunction)socket_getdefaulttimeout, + METH_NOARGS, getdefaulttimeout_doc}, + {"setdefaulttimeout", socket_setdefaulttimeout, + METH_O, setdefaulttimeout_doc}, + {NULL, NULL} /* Sentinel */ +}; + + +#ifdef RISCOS +#define OS_INIT_DEFINED + +static int +os_init(void) +{ + _kernel_swi_regs r; + + r.r[0] = 0; + _kernel_swi(0x43380, &r, &r); + taskwindow = r.r[0]; + + return 1; +} + +#endif /* RISCOS */ + + +#ifdef MS_WINDOWS +#define OS_INIT_DEFINED + +/* Additional initialization and cleanup for Windows */ + +static void +os_cleanup(void) +{ + WSACleanup(); +} + +static int +os_init(void) +{ + WSADATA WSAData; + int ret; + char buf[100]; + ret = WSAStartup(0x0101, &WSAData); + switch (ret) { + case 0: /* No error */ + Py_AtExit(os_cleanup); + return 1; /* Success */ + case WSASYSNOTREADY: + PyErr_SetString(PyExc_ImportError, + "WSAStartup failed: network not ready"); + break; + case WSAVERNOTSUPPORTED: + case WSAEINVAL: + PyErr_SetString( + PyExc_ImportError, + "WSAStartup failed: requested version not supported"); + break; + default: + PyOS_snprintf(buf, sizeof(buf), + "WSAStartup failed: error code %d", ret); + PyErr_SetString(PyExc_ImportError, buf); + break; + } + return 0; /* Failure */ +} + +#endif /* MS_WINDOWS */ + + +#ifdef PYOS_OS2 +#define OS_INIT_DEFINED + +/* Additional initialization for OS/2 */ + +static int +os_init(void) +{ +#ifndef PYCC_GCC + char reason[64]; + int rc = sock_init(); + + if (rc == 0) { + return 1; /* Success */ + } + + PyOS_snprintf(reason, sizeof(reason), + "OS/2 TCP/IP Error# %d", sock_errno()); + PyErr_SetString(PyExc_ImportError, reason); + + return 0; /* Failure */ +#else + /* No need to initialise sockets with GCC/EMX */ + return 1; /* Success */ +#endif +} + +#endif /* PYOS_OS2 */ + + +#ifndef OS_INIT_DEFINED +static int +os_init(void) +{ + return 1; /* Success */ +} +#endif + + +/* C API table - always add new things to the end for binary + compatibility. */ +static +PySocketModule_APIObject PySocketModuleAPI = +{ + &sock_type, + NULL +}; + + +/* Initialize the _socket module. + + This module is actually called "_socket", and there's a wrapper + "socket.py" which implements some additional functionality. On some + platforms (e.g. Windows and OS/2), socket.py also implements a + wrapper for the socket type that provides missing functionality such + as makefile(), dup() and fromfd(). The import of "_socket" may fail + with an ImportError exception if os-specific initialization fails. + On Windows, this does WINSOCK initialization. When WINSOCK is + initialized succesfully, a call to WSACleanup() is scheduled to be + made at exit time. +*/ + +PyDoc_STRVAR(socket_doc, +"Implementation module for socket operations.\n\ +\n\ +See the socket module for documentation."); + +PyMODINIT_FUNC +init_socket(void) +{ + PyObject *m, *has_ipv6; + + if (!os_init()) + return; + + sock_type.ob_type = &PyType_Type; + m = Py_InitModule3(PySocket_MODULE_NAME, + socket_methods, + socket_doc); + if (m == NULL) + return; + + socket_error = PyErr_NewException("socket.error", NULL, NULL); + if (socket_error == NULL) + return; + PySocketModuleAPI.error = socket_error; + Py_INCREF(socket_error); + PyModule_AddObject(m, "error", socket_error); + socket_herror = PyErr_NewException("socket.herror", + socket_error, NULL); + if (socket_herror == NULL) + return; + Py_INCREF(socket_herror); + PyModule_AddObject(m, "herror", socket_herror); + socket_gaierror = PyErr_NewException("socket.gaierror", socket_error, + NULL); + if (socket_gaierror == NULL) + return; + Py_INCREF(socket_gaierror); + PyModule_AddObject(m, "gaierror", socket_gaierror); + socket_timeout = PyErr_NewException("socket.timeout", + socket_error, NULL); + if (socket_timeout == NULL) + return; + Py_INCREF(socket_timeout); + PyModule_AddObject(m, "timeout", socket_timeout); + Py_INCREF((PyObject *)&sock_type); + if (PyModule_AddObject(m, "SocketType", + (PyObject *)&sock_type) != 0) + return; + Py_INCREF((PyObject *)&sock_type); + if (PyModule_AddObject(m, "socket", + (PyObject *)&sock_type) != 0) + return; + +#ifdef ENABLE_IPV6 + has_ipv6 = Py_True; +#else + has_ipv6 = Py_False; +#endif + Py_INCREF(has_ipv6); + PyModule_AddObject(m, "has_ipv6", has_ipv6); + + /* Export C API */ + if (PyModule_AddObject(m, PySocket_CAPI_NAME, + PyCObject_FromVoidPtr((void *)&PySocketModuleAPI, NULL) + ) != 0) + return; + + /* Address families (we only support AF_INET and AF_UNIX) */ +#ifdef AF_UNSPEC + PyModule_AddIntConstant(m, "AF_UNSPEC", AF_UNSPEC); +#endif + PyModule_AddIntConstant(m, "AF_INET", AF_INET); +#ifdef AF_INET6 + PyModule_AddIntConstant(m, "AF_INET6", AF_INET6); +#endif /* AF_INET6 */ +#if defined(AF_UNIX) + PyModule_AddIntConstant(m, "AF_UNIX", AF_UNIX); +#endif /* AF_UNIX */ +#ifdef AF_AX25 + /* Amateur Radio AX.25 */ + PyModule_AddIntConstant(m, "AF_AX25", AF_AX25); +#endif +#ifdef AF_IPX + PyModule_AddIntConstant(m, "AF_IPX", AF_IPX); /* Novell IPX */ +#endif +#ifdef AF_APPLETALK + /* Appletalk DDP */ + PyModule_AddIntConstant(m, "AF_APPLETALK", AF_APPLETALK); +#endif +#ifdef AF_NETROM + /* Amateur radio NetROM */ + PyModule_AddIntConstant(m, "AF_NETROM", AF_NETROM); +#endif +#ifdef AF_BRIDGE + /* Multiprotocol bridge */ + PyModule_AddIntConstant(m, "AF_BRIDGE", AF_BRIDGE); +#endif +#ifdef AF_ATMPVC + /* ATM PVCs */ + PyModule_AddIntConstant(m, "AF_ATMPVC", AF_ATMPVC); +#endif +#ifdef AF_AAL5 + /* Reserved for Werner's ATM */ + PyModule_AddIntConstant(m, "AF_AAL5", AF_AAL5); +#endif +#ifdef AF_X25 + /* Reserved for X.25 project */ + PyModule_AddIntConstant(m, "AF_X25", AF_X25); +#endif +#ifdef AF_INET6 + PyModule_AddIntConstant(m, "AF_INET6", AF_INET6); /* IP version 6 */ +#endif +#ifdef AF_ROSE + /* Amateur Radio X.25 PLP */ + PyModule_AddIntConstant(m, "AF_ROSE", AF_ROSE); +#endif +#ifdef AF_DECnet + /* Reserved for DECnet project */ + PyModule_AddIntConstant(m, "AF_DECnet", AF_DECnet); +#endif +#ifdef AF_NETBEUI + /* Reserved for 802.2LLC project */ + PyModule_AddIntConstant(m, "AF_NETBEUI", AF_NETBEUI); +#endif +#ifdef AF_SECURITY + /* Security callback pseudo AF */ + PyModule_AddIntConstant(m, "AF_SECURITY", AF_SECURITY); +#endif +#ifdef AF_KEY + /* PF_KEY key management API */ + PyModule_AddIntConstant(m, "AF_KEY", AF_KEY); +#endif +#ifdef AF_NETLINK + /* */ + PyModule_AddIntConstant(m, "AF_NETLINK", AF_NETLINK); + PyModule_AddIntConstant(m, "NETLINK_ROUTE", NETLINK_ROUTE); +#ifdef NETLINK_SKIP + PyModule_AddIntConstant(m, "NETLINK_SKIP", NETLINK_SKIP); +#endif +#ifdef NETLINK_W1 + PyModule_AddIntConstant(m, "NETLINK_W1", NETLINK_W1); +#endif + PyModule_AddIntConstant(m, "NETLINK_USERSOCK", NETLINK_USERSOCK); + PyModule_AddIntConstant(m, "NETLINK_FIREWALL", NETLINK_FIREWALL); +#ifdef NETLINK_TCPDIAG + PyModule_AddIntConstant(m, "NETLINK_TCPDIAG", NETLINK_TCPDIAG); +#endif +#ifdef NETLINK_NFLOG + PyModule_AddIntConstant(m, "NETLINK_NFLOG", NETLINK_NFLOG); +#endif +#ifdef NETLINK_XFRM + PyModule_AddIntConstant(m, "NETLINK_XFRM", NETLINK_XFRM); +#endif +#ifdef NETLINK_ARPD + PyModule_AddIntConstant(m, "NETLINK_ARPD", NETLINK_ARPD); +#endif +#ifdef NETLINK_ROUTE6 + PyModule_AddIntConstant(m, "NETLINK_ROUTE6", NETLINK_ROUTE6); +#endif + PyModule_AddIntConstant(m, "NETLINK_IP6_FW", NETLINK_IP6_FW); +#ifdef NETLINK_DNRTMSG + PyModule_AddIntConstant(m, "NETLINK_DNRTMSG", NETLINK_DNRTMSG); +#endif +#ifdef NETLINK_TAPBASE + PyModule_AddIntConstant(m, "NETLINK_TAPBASE", NETLINK_TAPBASE); +#endif +#endif /* AF_NETLINK */ +#ifdef AF_ROUTE + /* Alias to emulate 4.4BSD */ + PyModule_AddIntConstant(m, "AF_ROUTE", AF_ROUTE); +#endif +#ifdef AF_ASH + /* Ash */ + PyModule_AddIntConstant(m, "AF_ASH", AF_ASH); +#endif +#ifdef AF_ECONET + /* Acorn Econet */ + PyModule_AddIntConstant(m, "AF_ECONET", AF_ECONET); +#endif +#ifdef AF_ATMSVC + /* ATM SVCs */ + PyModule_AddIntConstant(m, "AF_ATMSVC", AF_ATMSVC); +#endif +#ifdef AF_SNA + /* Linux SNA Project (nutters!) */ + PyModule_AddIntConstant(m, "AF_SNA", AF_SNA); +#endif +#ifdef AF_IRDA + /* IRDA sockets */ + PyModule_AddIntConstant(m, "AF_IRDA", AF_IRDA); +#endif +#ifdef AF_PPPOX + /* PPPoX sockets */ + PyModule_AddIntConstant(m, "AF_PPPOX", AF_PPPOX); +#endif +#ifdef AF_WANPIPE + /* Wanpipe API Sockets */ + PyModule_AddIntConstant(m, "AF_WANPIPE", AF_WANPIPE); +#endif +#ifdef AF_LLC + /* Linux LLC */ + PyModule_AddIntConstant(m, "AF_LLC", AF_LLC); +#endif + +#ifdef USE_BLUETOOTH + PyModule_AddIntConstant(m, "AF_BLUETOOTH", AF_BLUETOOTH); + PyModule_AddIntConstant(m, "BTPROTO_L2CAP", BTPROTO_L2CAP); +#if !defined(__FreeBSD__) + PyModule_AddIntConstant(m, "BTPROTO_SCO", BTPROTO_SCO); +#endif + PyModule_AddIntConstant(m, "BTPROTO_RFCOMM", BTPROTO_RFCOMM); + PyModule_AddStringConstant(m, "BDADDR_ANY", "00:00:00:00:00:00"); + PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF"); +#endif + +#ifdef HAVE_NETPACKET_PACKET_H + PyModule_AddIntConstant(m, "AF_PACKET", AF_PACKET); + PyModule_AddIntConstant(m, "PF_PACKET", PF_PACKET); + PyModule_AddIntConstant(m, "PACKET_HOST", PACKET_HOST); + PyModule_AddIntConstant(m, "PACKET_BROADCAST", PACKET_BROADCAST); + PyModule_AddIntConstant(m, "PACKET_MULTICAST", PACKET_MULTICAST); + PyModule_AddIntConstant(m, "PACKET_OTHERHOST", PACKET_OTHERHOST); + PyModule_AddIntConstant(m, "PACKET_OUTGOING", PACKET_OUTGOING); + PyModule_AddIntConstant(m, "PACKET_LOOPBACK", PACKET_LOOPBACK); + PyModule_AddIntConstant(m, "PACKET_FASTROUTE", PACKET_FASTROUTE); +#endif + + /* Socket types */ + PyModule_AddIntConstant(m, "SOCK_STREAM", SOCK_STREAM); + PyModule_AddIntConstant(m, "SOCK_DGRAM", SOCK_DGRAM); +#ifndef __BEOS__ +/* We have incomplete socket support. */ + PyModule_AddIntConstant(m, "SOCK_RAW", SOCK_RAW); + PyModule_AddIntConstant(m, "SOCK_SEQPACKET", SOCK_SEQPACKET); +#if defined(SOCK_RDM) + PyModule_AddIntConstant(m, "SOCK_RDM", SOCK_RDM); +#endif +#endif + +#ifdef SO_DEBUG + PyModule_AddIntConstant(m, "SO_DEBUG", SO_DEBUG); +#endif +#ifdef SO_ACCEPTCONN + PyModule_AddIntConstant(m, "SO_ACCEPTCONN", SO_ACCEPTCONN); +#endif +#ifdef SO_REUSEADDR + PyModule_AddIntConstant(m, "SO_REUSEADDR", SO_REUSEADDR); +#endif +#ifdef SO_EXCLUSIVEADDRUSE + PyModule_AddIntConstant(m, "SO_EXCLUSIVEADDRUSE", SO_EXCLUSIVEADDRUSE); +#endif + +#ifdef SO_KEEPALIVE + PyModule_AddIntConstant(m, "SO_KEEPALIVE", SO_KEEPALIVE); +#endif +#ifdef SO_DONTROUTE + PyModule_AddIntConstant(m, "SO_DONTROUTE", SO_DONTROUTE); +#endif +#ifdef SO_BROADCAST + PyModule_AddIntConstant(m, "SO_BROADCAST", SO_BROADCAST); +#endif +#ifdef SO_USELOOPBACK + PyModule_AddIntConstant(m, "SO_USELOOPBACK", SO_USELOOPBACK); +#endif +#ifdef SO_LINGER + PyModule_AddIntConstant(m, "SO_LINGER", SO_LINGER); +#endif +#ifdef SO_OOBINLINE + PyModule_AddIntConstant(m, "SO_OOBINLINE", SO_OOBINLINE); +#endif +#ifdef SO_REUSEPORT + PyModule_AddIntConstant(m, "SO_REUSEPORT", SO_REUSEPORT); +#endif +#ifdef SO_SNDBUF + PyModule_AddIntConstant(m, "SO_SNDBUF", SO_SNDBUF); +#endif +#ifdef SO_RCVBUF + PyModule_AddIntConstant(m, "SO_RCVBUF", SO_RCVBUF); +#endif +#ifdef SO_SNDLOWAT + PyModule_AddIntConstant(m, "SO_SNDLOWAT", SO_SNDLOWAT); +#endif +#ifdef SO_RCVLOWAT + PyModule_AddIntConstant(m, "SO_RCVLOWAT", SO_RCVLOWAT); +#endif +#ifdef SO_SNDTIMEO + PyModule_AddIntConstant(m, "SO_SNDTIMEO", SO_SNDTIMEO); +#endif +#ifdef SO_RCVTIMEO + PyModule_AddIntConstant(m, "SO_RCVTIMEO", SO_RCVTIMEO); +#endif +#ifdef SO_ERROR + PyModule_AddIntConstant(m, "SO_ERROR", SO_ERROR); +#endif +#ifdef SO_TYPE + PyModule_AddIntConstant(m, "SO_TYPE", SO_TYPE); +#endif + + /* Maximum number of connections for "listen" */ +#ifdef SOMAXCONN + PyModule_AddIntConstant(m, "SOMAXCONN", SOMAXCONN); +#else + PyModule_AddIntConstant(m, "SOMAXCONN", 5); /* Common value */ +#endif + + /* Flags for send, recv */ +#ifdef MSG_OOB + PyModule_AddIntConstant(m, "MSG_OOB", MSG_OOB); +#endif +#ifdef MSG_PEEK + PyModule_AddIntConstant(m, "MSG_PEEK", MSG_PEEK); +#endif +#ifdef MSG_DONTROUTE + PyModule_AddIntConstant(m, "MSG_DONTROUTE", MSG_DONTROUTE); +#endif +#ifdef MSG_DONTWAIT + PyModule_AddIntConstant(m, "MSG_DONTWAIT", MSG_DONTWAIT); +#endif +#ifdef MSG_EOR + PyModule_AddIntConstant(m, "MSG_EOR", MSG_EOR); +#endif +#ifdef MSG_TRUNC + PyModule_AddIntConstant(m, "MSG_TRUNC", MSG_TRUNC); +#endif +#ifdef MSG_CTRUNC + PyModule_AddIntConstant(m, "MSG_CTRUNC", MSG_CTRUNC); +#endif +#ifdef MSG_WAITALL + PyModule_AddIntConstant(m, "MSG_WAITALL", MSG_WAITALL); +#endif +#ifdef MSG_BTAG + PyModule_AddIntConstant(m, "MSG_BTAG", MSG_BTAG); +#endif +#ifdef MSG_ETAG + PyModule_AddIntConstant(m, "MSG_ETAG", MSG_ETAG); +#endif + + /* Protocol level and numbers, usable for [gs]etsockopt */ +#ifdef SOL_SOCKET + PyModule_AddIntConstant(m, "SOL_SOCKET", SOL_SOCKET); +#endif +#ifdef SOL_IP + PyModule_AddIntConstant(m, "SOL_IP", SOL_IP); +#else + PyModule_AddIntConstant(m, "SOL_IP", 0); +#endif +#ifdef SOL_IPX + PyModule_AddIntConstant(m, "SOL_IPX", SOL_IPX); +#endif +#ifdef SOL_AX25 + PyModule_AddIntConstant(m, "SOL_AX25", SOL_AX25); +#endif +#ifdef SOL_ATALK + PyModule_AddIntConstant(m, "SOL_ATALK", SOL_ATALK); +#endif +#ifdef SOL_NETROM + PyModule_AddIntConstant(m, "SOL_NETROM", SOL_NETROM); +#endif +#ifdef SOL_ROSE + PyModule_AddIntConstant(m, "SOL_ROSE", SOL_ROSE); +#endif +#ifdef SOL_TCP + PyModule_AddIntConstant(m, "SOL_TCP", SOL_TCP); +#else + PyModule_AddIntConstant(m, "SOL_TCP", 6); +#endif +#ifdef SOL_UDP + PyModule_AddIntConstant(m, "SOL_UDP", SOL_UDP); +#else + PyModule_AddIntConstant(m, "SOL_UDP", 17); +#endif +#ifdef IPPROTO_IP + PyModule_AddIntConstant(m, "IPPROTO_IP", IPPROTO_IP); +#else + PyModule_AddIntConstant(m, "IPPROTO_IP", 0); +#endif +#ifdef IPPROTO_HOPOPTS + PyModule_AddIntConstant(m, "IPPROTO_HOPOPTS", IPPROTO_HOPOPTS); +#endif +#ifdef IPPROTO_ICMP + PyModule_AddIntConstant(m, "IPPROTO_ICMP", IPPROTO_ICMP); +#else + PyModule_AddIntConstant(m, "IPPROTO_ICMP", 1); +#endif +#ifdef IPPROTO_IGMP + PyModule_AddIntConstant(m, "IPPROTO_IGMP", IPPROTO_IGMP); +#endif +#ifdef IPPROTO_GGP + PyModule_AddIntConstant(m, "IPPROTO_GGP", IPPROTO_GGP); +#endif +#ifdef IPPROTO_IPV4 + PyModule_AddIntConstant(m, "IPPROTO_IPV4", IPPROTO_IPV4); +#endif +#ifdef IPPROTO_IPV6 + PyModule_AddIntConstant(m, "IPPROTO_IPV6", IPPROTO_IPV6); +#endif +#ifdef IPPROTO_IPIP + PyModule_AddIntConstant(m, "IPPROTO_IPIP", IPPROTO_IPIP); +#endif +#ifdef IPPROTO_TCP + PyModule_AddIntConstant(m, "IPPROTO_TCP", IPPROTO_TCP); +#else + PyModule_AddIntConstant(m, "IPPROTO_TCP", 6); +#endif +#ifdef IPPROTO_EGP + PyModule_AddIntConstant(m, "IPPROTO_EGP", IPPROTO_EGP); +#endif +#ifdef IPPROTO_PUP + PyModule_AddIntConstant(m, "IPPROTO_PUP", IPPROTO_PUP); +#endif +#ifdef IPPROTO_UDP + PyModule_AddIntConstant(m, "IPPROTO_UDP", IPPROTO_UDP); +#else + PyModule_AddIntConstant(m, "IPPROTO_UDP", 17); +#endif +#ifdef IPPROTO_IDP + PyModule_AddIntConstant(m, "IPPROTO_IDP", IPPROTO_IDP); +#endif +#ifdef IPPROTO_HELLO + PyModule_AddIntConstant(m, "IPPROTO_HELLO", IPPROTO_HELLO); +#endif +#ifdef IPPROTO_ND + PyModule_AddIntConstant(m, "IPPROTO_ND", IPPROTO_ND); +#endif +#ifdef IPPROTO_TP + PyModule_AddIntConstant(m, "IPPROTO_TP", IPPROTO_TP); +#endif +#ifdef IPPROTO_IPV6 + PyModule_AddIntConstant(m, "IPPROTO_IPV6", IPPROTO_IPV6); +#endif +#ifdef IPPROTO_ROUTING + PyModule_AddIntConstant(m, "IPPROTO_ROUTING", IPPROTO_ROUTING); +#endif +#ifdef IPPROTO_FRAGMENT + PyModule_AddIntConstant(m, "IPPROTO_FRAGMENT", IPPROTO_FRAGMENT); +#endif +#ifdef IPPROTO_RSVP + PyModule_AddIntConstant(m, "IPPROTO_RSVP", IPPROTO_RSVP); +#endif +#ifdef IPPROTO_GRE + PyModule_AddIntConstant(m, "IPPROTO_GRE", IPPROTO_GRE); +#endif +#ifdef IPPROTO_ESP + PyModule_AddIntConstant(m, "IPPROTO_ESP", IPPROTO_ESP); +#endif +#ifdef IPPROTO_AH + PyModule_AddIntConstant(m, "IPPROTO_AH", IPPROTO_AH); +#endif +#ifdef IPPROTO_MOBILE + PyModule_AddIntConstant(m, "IPPROTO_MOBILE", IPPROTO_MOBILE); +#endif +#ifdef IPPROTO_ICMPV6 + PyModule_AddIntConstant(m, "IPPROTO_ICMPV6", IPPROTO_ICMPV6); +#endif +#ifdef IPPROTO_NONE + PyModule_AddIntConstant(m, "IPPROTO_NONE", IPPROTO_NONE); +#endif +#ifdef IPPROTO_DSTOPTS + PyModule_AddIntConstant(m, "IPPROTO_DSTOPTS", IPPROTO_DSTOPTS); +#endif +#ifdef IPPROTO_XTP + PyModule_AddIntConstant(m, "IPPROTO_XTP", IPPROTO_XTP); +#endif +#ifdef IPPROTO_EON + PyModule_AddIntConstant(m, "IPPROTO_EON", IPPROTO_EON); +#endif +#ifdef IPPROTO_PIM + PyModule_AddIntConstant(m, "IPPROTO_PIM", IPPROTO_PIM); +#endif +#ifdef IPPROTO_IPCOMP + PyModule_AddIntConstant(m, "IPPROTO_IPCOMP", IPPROTO_IPCOMP); +#endif +#ifdef IPPROTO_VRRP + PyModule_AddIntConstant(m, "IPPROTO_VRRP", IPPROTO_VRRP); +#endif +#ifdef IPPROTO_BIP + PyModule_AddIntConstant(m, "IPPROTO_BIP", IPPROTO_BIP); +#endif +/**/ +#ifdef IPPROTO_RAW + PyModule_AddIntConstant(m, "IPPROTO_RAW", IPPROTO_RAW); +#else + PyModule_AddIntConstant(m, "IPPROTO_RAW", 255); +#endif +#ifdef IPPROTO_MAX + PyModule_AddIntConstant(m, "IPPROTO_MAX", IPPROTO_MAX); +#endif + + /* Some port configuration */ +#ifdef IPPORT_RESERVED + PyModule_AddIntConstant(m, "IPPORT_RESERVED", IPPORT_RESERVED); +#else + PyModule_AddIntConstant(m, "IPPORT_RESERVED", 1024); +#endif +#ifdef IPPORT_USERRESERVED + PyModule_AddIntConstant(m, "IPPORT_USERRESERVED", IPPORT_USERRESERVED); +#else + PyModule_AddIntConstant(m, "IPPORT_USERRESERVED", 5000); +#endif + + /* Some reserved IP v.4 addresses */ +#ifdef INADDR_ANY + PyModule_AddIntConstant(m, "INADDR_ANY", INADDR_ANY); +#else + PyModule_AddIntConstant(m, "INADDR_ANY", 0x00000000); +#endif +#ifdef INADDR_BROADCAST + PyModule_AddIntConstant(m, "INADDR_BROADCAST", INADDR_BROADCAST); +#else + PyModule_AddIntConstant(m, "INADDR_BROADCAST", 0xffffffff); +#endif +#ifdef INADDR_LOOPBACK + PyModule_AddIntConstant(m, "INADDR_LOOPBACK", INADDR_LOOPBACK); +#else + PyModule_AddIntConstant(m, "INADDR_LOOPBACK", 0x7F000001); +#endif +#ifdef INADDR_UNSPEC_GROUP + PyModule_AddIntConstant(m, "INADDR_UNSPEC_GROUP", INADDR_UNSPEC_GROUP); +#else + PyModule_AddIntConstant(m, "INADDR_UNSPEC_GROUP", 0xe0000000); +#endif +#ifdef INADDR_ALLHOSTS_GROUP + PyModule_AddIntConstant(m, "INADDR_ALLHOSTS_GROUP", + INADDR_ALLHOSTS_GROUP); +#else + PyModule_AddIntConstant(m, "INADDR_ALLHOSTS_GROUP", 0xe0000001); +#endif +#ifdef INADDR_MAX_LOCAL_GROUP + PyModule_AddIntConstant(m, "INADDR_MAX_LOCAL_GROUP", + INADDR_MAX_LOCAL_GROUP); +#else + PyModule_AddIntConstant(m, "INADDR_MAX_LOCAL_GROUP", 0xe00000ff); +#endif +#ifdef INADDR_NONE + PyModule_AddIntConstant(m, "INADDR_NONE", INADDR_NONE); +#else + PyModule_AddIntConstant(m, "INADDR_NONE", 0xffffffff); +#endif + + /* IPv4 [gs]etsockopt options */ +#ifdef IP_OPTIONS + PyModule_AddIntConstant(m, "IP_OPTIONS", IP_OPTIONS); +#endif +#ifdef IP_HDRINCL + PyModule_AddIntConstant(m, "IP_HDRINCL", IP_HDRINCL); +#endif +#ifdef IP_TOS + PyModule_AddIntConstant(m, "IP_TOS", IP_TOS); +#endif +#ifdef IP_TTL + PyModule_AddIntConstant(m, "IP_TTL", IP_TTL); +#endif +#ifdef IP_RECVOPTS + PyModule_AddIntConstant(m, "IP_RECVOPTS", IP_RECVOPTS); +#endif +#ifdef IP_RECVRETOPTS + PyModule_AddIntConstant(m, "IP_RECVRETOPTS", IP_RECVRETOPTS); +#endif +#ifdef IP_RECVDSTADDR + PyModule_AddIntConstant(m, "IP_RECVDSTADDR", IP_RECVDSTADDR); +#endif +#ifdef IP_RETOPTS + PyModule_AddIntConstant(m, "IP_RETOPTS", IP_RETOPTS); +#endif +#ifdef IP_MULTICAST_IF + PyModule_AddIntConstant(m, "IP_MULTICAST_IF", IP_MULTICAST_IF); +#endif +#ifdef IP_MULTICAST_TTL + PyModule_AddIntConstant(m, "IP_MULTICAST_TTL", IP_MULTICAST_TTL); +#endif +#ifdef IP_MULTICAST_LOOP + PyModule_AddIntConstant(m, "IP_MULTICAST_LOOP", IP_MULTICAST_LOOP); +#endif +#ifdef IP_ADD_MEMBERSHIP + PyModule_AddIntConstant(m, "IP_ADD_MEMBERSHIP", IP_ADD_MEMBERSHIP); +#endif +#ifdef IP_DROP_MEMBERSHIP + PyModule_AddIntConstant(m, "IP_DROP_MEMBERSHIP", IP_DROP_MEMBERSHIP); +#endif +#ifdef IP_DEFAULT_MULTICAST_TTL + PyModule_AddIntConstant(m, "IP_DEFAULT_MULTICAST_TTL", + IP_DEFAULT_MULTICAST_TTL); +#endif +#ifdef IP_DEFAULT_MULTICAST_LOOP + PyModule_AddIntConstant(m, "IP_DEFAULT_MULTICAST_LOOP", + IP_DEFAULT_MULTICAST_LOOP); +#endif +#ifdef IP_MAX_MEMBERSHIPS + PyModule_AddIntConstant(m, "IP_MAX_MEMBERSHIPS", IP_MAX_MEMBERSHIPS); +#endif + + /* IPv6 [gs]etsockopt options, defined in RFC2553 */ +#ifdef IPV6_JOIN_GROUP + PyModule_AddIntConstant(m, "IPV6_JOIN_GROUP", IPV6_JOIN_GROUP); +#endif +#ifdef IPV6_LEAVE_GROUP + PyModule_AddIntConstant(m, "IPV6_LEAVE_GROUP", IPV6_LEAVE_GROUP); +#endif +#ifdef IPV6_MULTICAST_HOPS + PyModule_AddIntConstant(m, "IPV6_MULTICAST_HOPS", IPV6_MULTICAST_HOPS); +#endif +#ifdef IPV6_MULTICAST_IF + PyModule_AddIntConstant(m, "IPV6_MULTICAST_IF", IPV6_MULTICAST_IF); +#endif +#ifdef IPV6_MULTICAST_LOOP + PyModule_AddIntConstant(m, "IPV6_MULTICAST_LOOP", IPV6_MULTICAST_LOOP); +#endif +#ifdef IPV6_UNICAST_HOPS + PyModule_AddIntConstant(m, "IPV6_UNICAST_HOPS", IPV6_UNICAST_HOPS); +#endif + /* Additional IPV6 socket options, defined in RFC 3493 */ +#ifdef IPV6_V6ONLY + PyModule_AddIntConstant(m, "IPV6_V6ONLY", IPV6_V6ONLY); +#endif + /* Advanced IPV6 socket options, from RFC 3542 */ +#ifdef IPV6_CHECKSUM + PyModule_AddIntConstant(m, "IPV6_CHECKSUM", IPV6_CHECKSUM); +#endif +#ifdef IPV6_DONTFRAG + PyModule_AddIntConstant(m, "IPV6_DONTFRAG", IPV6_DONTFRAG); +#endif +#ifdef IPV6_DSTOPTS + PyModule_AddIntConstant(m, "IPV6_DSTOPTS", IPV6_DSTOPTS); +#endif +#ifdef IPV6_HOPLIMIT + PyModule_AddIntConstant(m, "IPV6_HOPLIMIT", IPV6_HOPLIMIT); +#endif +#ifdef IPV6_HOPOPTS + PyModule_AddIntConstant(m, "IPV6_HOPOPTS", IPV6_HOPOPTS); +#endif +#ifdef IPV6_NEXTHOP + PyModule_AddIntConstant(m, "IPV6_NEXTHOP", IPV6_NEXTHOP); +#endif +#ifdef IPV6_PATHMTU + PyModule_AddIntConstant(m, "IPV6_PATHMTU", IPV6_PATHMTU); +#endif +#ifdef IPV6_PKTINFO + PyModule_AddIntConstant(m, "IPV6_PKTINFO", IPV6_PKTINFO); +#endif +#ifdef IPV6_RECVDSTOPTS + PyModule_AddIntConstant(m, "IPV6_RECVDSTOPTS", IPV6_RECVDSTOPTS); +#endif +#ifdef IPV6_RECVHOPLIMIT + PyModule_AddIntConstant(m, "IPV6_RECVHOPLIMIT", IPV6_RECVHOPLIMIT); +#endif +#ifdef IPV6_RECVHOPOPTS + PyModule_AddIntConstant(m, "IPV6_RECVHOPOPTS", IPV6_RECVHOPOPTS); +#endif +#ifdef IPV6_RECVPKTINFO + PyModule_AddIntConstant(m, "IPV6_RECVPKTINFO", IPV6_RECVPKTINFO); +#endif +#ifdef IPV6_RECVRTHDR + PyModule_AddIntConstant(m, "IPV6_RECVRTHDR", IPV6_RECVRTHDR); +#endif +#ifdef IPV6_RECVTCLASS + PyModule_AddIntConstant(m, "IPV6_RECVTCLASS", IPV6_RECVTCLASS); +#endif +#ifdef IPV6_RTHDR + PyModule_AddIntConstant(m, "IPV6_RTHDR", IPV6_RTHDR); +#endif +#ifdef IPV6_RTHDRDSTOPTS + PyModule_AddIntConstant(m, "IPV6_RTHDRDSTOPTS", IPV6_RTHDRDSTOPTS); +#endif +#ifdef IPV6_RTHDR_TYPE_0 + PyModule_AddIntConstant(m, "IPV6_RTHDR_TYPE_0", IPV6_RTHDR_TYPE_0); +#endif +#ifdef IPV6_RECVPATHMTU + PyModule_AddIntConstant(m, "IPV6_RECVPATHMTU", IPV6_RECVPATHMTU); +#endif +#ifdef IPV6_TCLASS + PyModule_AddIntConstant(m, "IPV6_TCLASS", IPV6_TCLASS); +#endif +#ifdef IPV6_USE_MIN_MTU + PyModule_AddIntConstant(m, "IPV6_USE_MIN_MTU", IPV6_USE_MIN_MTU); +#endif + + /* TCP options */ +#ifdef TCP_NODELAY + PyModule_AddIntConstant(m, "TCP_NODELAY", TCP_NODELAY); +#endif +#ifdef TCP_MAXSEG + PyModule_AddIntConstant(m, "TCP_MAXSEG", TCP_MAXSEG); +#endif +#ifdef TCP_CORK + PyModule_AddIntConstant(m, "TCP_CORK", TCP_CORK); +#endif +#ifdef TCP_KEEPIDLE + PyModule_AddIntConstant(m, "TCP_KEEPIDLE", TCP_KEEPIDLE); +#endif +#ifdef TCP_KEEPINTVL + PyModule_AddIntConstant(m, "TCP_KEEPINTVL", TCP_KEEPINTVL); +#endif +#ifdef TCP_KEEPCNT + PyModule_AddIntConstant(m, "TCP_KEEPCNT", TCP_KEEPCNT); +#endif +#ifdef TCP_SYNCNT + PyModule_AddIntConstant(m, "TCP_SYNCNT", TCP_SYNCNT); +#endif +#ifdef TCP_LINGER2 + PyModule_AddIntConstant(m, "TCP_LINGER2", TCP_LINGER2); +#endif +#ifdef TCP_DEFER_ACCEPT + PyModule_AddIntConstant(m, "TCP_DEFER_ACCEPT", TCP_DEFER_ACCEPT); +#endif +#ifdef TCP_WINDOW_CLAMP + PyModule_AddIntConstant(m, "TCP_WINDOW_CLAMP", TCP_WINDOW_CLAMP); +#endif +#ifdef TCP_INFO + PyModule_AddIntConstant(m, "TCP_INFO", TCP_INFO); +#endif +#ifdef TCP_QUICKACK + PyModule_AddIntConstant(m, "TCP_QUICKACK", TCP_QUICKACK); +#endif + + + /* IPX options */ +#ifdef IPX_TYPE + PyModule_AddIntConstant(m, "IPX_TYPE", IPX_TYPE); +#endif + + /* get{addr,name}info parameters */ +#ifdef EAI_ADDRFAMILY + PyModule_AddIntConstant(m, "EAI_ADDRFAMILY", EAI_ADDRFAMILY); +#endif +#ifdef EAI_AGAIN + PyModule_AddIntConstant(m, "EAI_AGAIN", EAI_AGAIN); +#endif +#ifdef EAI_BADFLAGS + PyModule_AddIntConstant(m, "EAI_BADFLAGS", EAI_BADFLAGS); +#endif +#ifdef EAI_FAIL + PyModule_AddIntConstant(m, "EAI_FAIL", EAI_FAIL); +#endif +#ifdef EAI_FAMILY + PyModule_AddIntConstant(m, "EAI_FAMILY", EAI_FAMILY); +#endif +#ifdef EAI_MEMORY + PyModule_AddIntConstant(m, "EAI_MEMORY", EAI_MEMORY); +#endif +#ifdef EAI_NODATA + PyModule_AddIntConstant(m, "EAI_NODATA", EAI_NODATA); +#endif +#ifdef EAI_NONAME + PyModule_AddIntConstant(m, "EAI_NONAME", EAI_NONAME); +#endif +#ifdef EAI_OVERFLOW + PyModule_AddIntConstant(m, "EAI_OVERFLOW", EAI_OVERFLOW); +#endif +#ifdef EAI_SERVICE + PyModule_AddIntConstant(m, "EAI_SERVICE", EAI_SERVICE); +#endif +#ifdef EAI_SOCKTYPE + PyModule_AddIntConstant(m, "EAI_SOCKTYPE", EAI_SOCKTYPE); +#endif +#ifdef EAI_SYSTEM + PyModule_AddIntConstant(m, "EAI_SYSTEM", EAI_SYSTEM); +#endif +#ifdef EAI_BADHINTS + PyModule_AddIntConstant(m, "EAI_BADHINTS", EAI_BADHINTS); +#endif +#ifdef EAI_PROTOCOL + PyModule_AddIntConstant(m, "EAI_PROTOCOL", EAI_PROTOCOL); +#endif +#ifdef EAI_MAX + PyModule_AddIntConstant(m, "EAI_MAX", EAI_MAX); +#endif +#ifdef AI_PASSIVE + PyModule_AddIntConstant(m, "AI_PASSIVE", AI_PASSIVE); +#endif +#ifdef AI_CANONNAME + PyModule_AddIntConstant(m, "AI_CANONNAME", AI_CANONNAME); +#endif +#ifdef AI_NUMERICHOST + PyModule_AddIntConstant(m, "AI_NUMERICHOST", AI_NUMERICHOST); +#endif +#ifdef AI_NUMERICSERV + PyModule_AddIntConstant(m, "AI_NUMERICSERV", AI_NUMERICSERV); +#endif +#ifdef AI_MASK + PyModule_AddIntConstant(m, "AI_MASK", AI_MASK); +#endif +#ifdef AI_ALL + PyModule_AddIntConstant(m, "AI_ALL", AI_ALL); +#endif +#ifdef AI_V4MAPPED_CFG + PyModule_AddIntConstant(m, "AI_V4MAPPED_CFG", AI_V4MAPPED_CFG); +#endif +#ifdef AI_ADDRCONFIG + PyModule_AddIntConstant(m, "AI_ADDRCONFIG", AI_ADDRCONFIG); +#endif +#ifdef AI_V4MAPPED + PyModule_AddIntConstant(m, "AI_V4MAPPED", AI_V4MAPPED); +#endif +#ifdef AI_DEFAULT + PyModule_AddIntConstant(m, "AI_DEFAULT", AI_DEFAULT); +#endif +#ifdef NI_MAXHOST + PyModule_AddIntConstant(m, "NI_MAXHOST", NI_MAXHOST); +#endif +#ifdef NI_MAXSERV + PyModule_AddIntConstant(m, "NI_MAXSERV", NI_MAXSERV); +#endif +#ifdef NI_NOFQDN + PyModule_AddIntConstant(m, "NI_NOFQDN", NI_NOFQDN); +#endif +#ifdef NI_NUMERICHOST + PyModule_AddIntConstant(m, "NI_NUMERICHOST", NI_NUMERICHOST); +#endif +#ifdef NI_NAMEREQD + PyModule_AddIntConstant(m, "NI_NAMEREQD", NI_NAMEREQD); +#endif +#ifdef NI_NUMERICSERV + PyModule_AddIntConstant(m, "NI_NUMERICSERV", NI_NUMERICSERV); +#endif +#ifdef NI_DGRAM + PyModule_AddIntConstant(m, "NI_DGRAM", NI_DGRAM); +#endif + + /* shutdown() parameters */ +#ifdef SHUT_RD + PyModule_AddIntConstant(m, "SHUT_RD", SHUT_RD); +#elif defined(SD_RECEIVE) + PyModule_AddIntConstant(m, "SHUT_RD", SD_RECEIVE); +#else + PyModule_AddIntConstant(m, "SHUT_RD", 0); +#endif +#ifdef SHUT_WR + PyModule_AddIntConstant(m, "SHUT_WR", SHUT_WR); +#elif defined(SD_SEND) + PyModule_AddIntConstant(m, "SHUT_WR", SD_SEND); +#else + PyModule_AddIntConstant(m, "SHUT_WR", 1); +#endif +#ifdef SHUT_RDWR + PyModule_AddIntConstant(m, "SHUT_RDWR", SHUT_RDWR); +#elif defined(SD_BOTH) + PyModule_AddIntConstant(m, "SHUT_RDWR", SD_BOTH); +#else + PyModule_AddIntConstant(m, "SHUT_RDWR", 2); +#endif + + /* Initialize gethostbyname lock */ +#if defined(USE_GETHOSTBYNAME_LOCK) || defined(USE_GETADDRINFO_LOCK) + netdb_lock = PyThread_allocate_lock(); +#endif +} + + +#ifndef HAVE_INET_PTON + +/* Simplistic emulation code for inet_pton that only works for IPv4 */ +/* These are not exposed because they do not set errno properly */ + +int +inet_pton(int af, const char *src, void *dst) +{ + if (af == AF_INET) { + long packed_addr; + packed_addr = inet_addr(src); + if (packed_addr == INADDR_NONE) + return 0; +#ifdef PLAN9APE + if(packed_addr == 0) + return 0; +#endif + memcpy(dst, &packed_addr, 4); + return 1; + } + /* Should set errno to EAFNOSUPPORT */ + return -1; +} + +const char * +inet_ntop(int af, const void *src, char *dst, socklen_t size) +{ + if (af == AF_INET) { + struct in_addr packed_addr; + if (size < 16) + /* Should set errno to ENOSPC. */ + return NULL; + memcpy(&packed_addr, src, sizeof(packed_addr)); + return strncpy(dst, inet_ntoa(packed_addr), size); + } + /* Should set errno to EAFNOSUPPORT */ + return NULL; +} + +#endif diff --git a/sys/src/cmd/python/Modules/socketmodule.h b/sys/src/cmd/python/Modules/socketmodule.h new file mode 100644 index 000000000..84f2422f4 --- /dev/null +++ b/sys/src/cmd/python/Modules/socketmodule.h @@ -0,0 +1,252 @@ +/* Socket module header file */ + +/* Includes needed for the sockaddr_* symbols below */ +#ifndef MS_WINDOWS +#ifdef __VMS +# include <socket.h> +# else +# include <sys/socket.h> +# endif +# include <netinet/in.h> +# if !(defined(__BEOS__) || defined(__CYGWIN__) || (defined(PYOS_OS2) && defined(PYCC_VACPP))) +# include <netinet/tcp.h> +# endif + +#else /* MS_WINDOWS */ +#if _MSC_VER >= 1300 +# include <winsock2.h> +# include <ws2tcpip.h> +# define HAVE_ADDRINFO +# define HAVE_SOCKADDR_STORAGE +# define HAVE_GETADDRINFO +# define HAVE_GETNAMEINFO +# define ENABLE_IPV6 +#else +# include <winsock.h> +#endif +#endif + +#ifdef HAVE_SYS_UN_H +# include <sys/un.h> +#else +# undef AF_UNIX +#endif + +#ifdef HAVE_LINUX_NETLINK_H +# ifdef HAVE_ASM_TYPES_H +# include <asm/types.h> +# endif +# include <linux/netlink.h> +#else +# undef AF_NETLINK +#endif + +#ifdef HAVE_BLUETOOTH_BLUETOOTH_H +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> +#include <bluetooth/l2cap.h> +#include <bluetooth/sco.h> +#endif + +#ifdef HAVE_BLUETOOTH_H +#include <bluetooth.h> +#endif + +#ifdef HAVE_NETPACKET_PACKET_H +# include <sys/ioctl.h> +# include <net/if.h> +# include <netpacket/packet.h> +#endif + +#ifndef Py__SOCKET_H +#define Py__SOCKET_H +#ifdef __cplusplus +extern "C" { +#endif + +/* Python module and C API name */ +#define PySocket_MODULE_NAME "_socket" +#define PySocket_CAPI_NAME "CAPI" + +/* Abstract the socket file descriptor type */ +#ifdef MS_WINDOWS +typedef SOCKET SOCKET_T; +# ifdef MS_WIN64 +# define SIZEOF_SOCKET_T 8 +# else +# define SIZEOF_SOCKET_T 4 +# endif +#else +typedef int SOCKET_T; +# define SIZEOF_SOCKET_T SIZEOF_INT +#endif + +/* Socket address */ +typedef union sock_addr { + struct sockaddr_in in; +#ifdef AF_UNIX + struct sockaddr_un un; +#endif +#ifdef AF_NETLINK + struct sockaddr_nl nl; +#endif +#ifdef ENABLE_IPV6 + struct sockaddr_in6 in6; + struct sockaddr_storage storage; +#endif +#ifdef HAVE_BLUETOOTH_BLUETOOTH_H + struct sockaddr_l2 bt_l2; + struct sockaddr_rc bt_rc; + struct sockaddr_sco bt_sco; +#endif +#ifdef HAVE_NETPACKET_PACKET_H + struct sockaddr_ll ll; +#endif +} sock_addr_t; + +/* The object holding a socket. It holds some extra information, + like the address family, which is used to decode socket address + arguments properly. */ + +typedef struct { + PyObject_HEAD + SOCKET_T sock_fd; /* Socket file descriptor */ + int sock_family; /* Address family, e.g., AF_INET */ + int sock_type; /* Socket type, e.g., SOCK_STREAM */ + int sock_proto; /* Protocol type, usually 0 */ + PyObject *(*errorhandler)(void); /* Error handler; checks + errno, returns NULL and + sets a Python exception */ + double sock_timeout; /* Operation timeout in seconds; + 0.0 means non-blocking */ +} PySocketSockObject; + +/* --- C API ----------------------------------------------------*/ + +/* Short explanation of what this C API export mechanism does + and how it works: + + The _ssl module needs access to the type object defined in + the _socket module. Since cross-DLL linking introduces a lot of + problems on many platforms, the "trick" is to wrap the + C API of a module in a struct which then gets exported to + other modules via a PyCObject. + + The code in socketmodule.c defines this struct (which currently + only contains the type object reference, but could very + well also include other C APIs needed by other modules) + and exports it as PyCObject via the module dictionary + under the name "CAPI". + + Other modules can now include the socketmodule.h file + which defines the needed C APIs to import and set up + a static copy of this struct in the importing module. + + After initialization, the importing module can then + access the C APIs from the _socket module by simply + referring to the static struct, e.g. + + Load _socket module and its C API; this sets up the global + PySocketModule: + + if (PySocketModule_ImportModuleAndAPI()) + return; + + + Now use the C API as if it were defined in the using + module: + + if (!PyArg_ParseTuple(args, "O!|zz:ssl", + + PySocketModule.Sock_Type, + + (PyObject*)&Sock, + &key_file, &cert_file)) + return NULL; + + Support could easily be extended to export more C APIs/symbols + this way. Currently, only the type object is exported, + other candidates would be socket constructors and socket + access functions. + +*/ + +/* C API for usage by other Python modules */ +typedef struct { + PyTypeObject *Sock_Type; + PyObject *error; +} PySocketModule_APIObject; + +/* XXX The net effect of the following appears to be to define a function + XXX named PySocketModule_APIObject in _ssl.c. It's unclear why it isn't + XXX defined there directly. + + >>> It's defined here because other modules might also want to use + >>> the C API. + +*/ +#ifndef PySocket_BUILDING_SOCKET + +/* --- C API ----------------------------------------------------*/ + +/* Interfacestructure to C API for other modules. + Call PySocketModule_ImportModuleAndAPI() to initialize this + structure. After that usage is simple: + + if (!PyArg_ParseTuple(args, "O!|zz:ssl", + &PySocketModule.Sock_Type, (PyObject*)&Sock, + &key_file, &cert_file)) + return NULL; + ... +*/ + +static +PySocketModule_APIObject PySocketModule; + +/* You *must* call this before using any of the functions in + PySocketModule and check its outcome; otherwise all accesses will + result in a segfault. Returns 0 on success. */ + +#ifndef DPRINTF +# define DPRINTF if (0) printf +#endif + +static +int PySocketModule_ImportModuleAndAPI(void) +{ + PyObject *mod = 0, *v = 0; + char *apimodule = PySocket_MODULE_NAME; + char *apiname = PySocket_CAPI_NAME; + void *api; + + DPRINTF("Importing the %s C API...\n", apimodule); + mod = PyImport_ImportModule(apimodule); + if (mod == NULL) + goto onError; + DPRINTF(" %s package found\n", apimodule); + v = PyObject_GetAttrString(mod, apiname); + if (v == NULL) + goto onError; + Py_DECREF(mod); + DPRINTF(" API object %s found\n", apiname); + api = PyCObject_AsVoidPtr(v); + if (api == NULL) + goto onError; + Py_DECREF(v); + memcpy(&PySocketModule, api, sizeof(PySocketModule)); + DPRINTF(" API object loaded and initialized.\n"); + return 0; + + onError: + DPRINTF(" not found.\n"); + Py_XDECREF(mod); + Py_XDECREF(v); + return -1; +} + +#endif /* !PySocket_BUILDING_SOCKET */ + +#ifdef __cplusplus +} +#endif +#endif /* !Py__SOCKET_H */ diff --git a/sys/src/cmd/python/Modules/spwdmodule.c b/sys/src/cmd/python/Modules/spwdmodule.c new file mode 100644 index 000000000..d3f309afa --- /dev/null +++ b/sys/src/cmd/python/Modules/spwdmodule.c @@ -0,0 +1,183 @@ + +/* UNIX shadow password file access module */ +/* A lot of code has been taken from pwdmodule.c */ +/* For info also see http://www.unixpapa.com/incnote/passwd.html */ + +#include "Python.h" +#include "structseq.h" + +#include <sys/types.h> +#ifdef HAVE_SHADOW_H +#include <shadow.h> +#endif + + +PyDoc_STRVAR(spwd__doc__, +"This module provides access to the Unix shadow password database.\n\ +It is available on various Unix versions.\n\ +\n\ +Shadow password database entries are reported as 9-tuples of type struct_spwd,\n\ +containing the following items from the password database (see `<shadow.h>'):\n\ +sp_namp, sp_pwdp, sp_lstchg, sp_min, sp_max, sp_warn, sp_inact, sp_expire, sp_flag.\n\ +The sp_namp and sp_pwdp are strings, the rest are integers.\n\ +An exception is raised if the entry asked for cannot be found.\n\ +You have to be root to be able to use this module."); + + +#if defined(HAVE_GETSPNAM) || defined(HAVE_GETSPENT) + +static PyStructSequence_Field struct_spwd_type_fields[] = { + {"sp_nam", "login name"}, + {"sp_pwd", "encrypted password"}, + {"sp_lstchg", "date of last change"}, + {"sp_min", "min #days between changes"}, + {"sp_max", "max #days between changes"}, + {"sp_warn", "#days before pw expires to warn user about it"}, + {"sp_inact", "#days after pw expires until account is blocked"}, + {"sp_expire", "#days since 1970-01-01 until account is disabled"}, + {"sp_flag", "reserved"}, + {0} +}; + +PyDoc_STRVAR(struct_spwd__doc__, +"spwd.struct_spwd: Results from getsp*() routines.\n\n\ +This object may be accessed either as a 9-tuple of\n\ + (sp_nam,sp_pwd,sp_lstchg,sp_min,sp_max,sp_warn,sp_inact,sp_expire,sp_flag)\n\ +or via the object attributes as named in the above tuple."); + +static PyStructSequence_Desc struct_spwd_type_desc = { + "spwd.struct_spwd", + struct_spwd__doc__, + struct_spwd_type_fields, + 9, +}; + +static int initialized; +static PyTypeObject StructSpwdType; + + +static void +sets(PyObject *v, int i, char* val) +{ + if (val) + PyStructSequence_SET_ITEM(v, i, PyString_FromString(val)); + else { + PyStructSequence_SET_ITEM(v, i, Py_None); + Py_INCREF(Py_None); + } +} + +static PyObject *mkspent(struct spwd *p) +{ + int setIndex = 0; + PyObject *v = PyStructSequence_New(&StructSpwdType); + if (v == NULL) + return NULL; + +#define SETI(i,val) PyStructSequence_SET_ITEM(v, i, PyInt_FromLong((long) val)) +#define SETS(i,val) sets(v, i, val) + + SETS(setIndex++, p->sp_namp); + SETS(setIndex++, p->sp_pwdp); + SETI(setIndex++, p->sp_lstchg); + SETI(setIndex++, p->sp_min); + SETI(setIndex++, p->sp_max); + SETI(setIndex++, p->sp_warn); + SETI(setIndex++, p->sp_inact); + SETI(setIndex++, p->sp_expire); + SETI(setIndex++, p->sp_flag); + +#undef SETS +#undef SETI + + if (PyErr_Occurred()) { + Py_DECREF(v); + return NULL; + } + + return v; +} + +#endif /* HAVE_GETSPNAM || HAVE_GETSPENT */ + + +#ifdef HAVE_GETSPNAM + +PyDoc_STRVAR(spwd_getspnam__doc__, +"getspnam(name) -> (sp_namp, sp_pwdp, sp_lstchg, sp_min, sp_max,\n\ + sp_warn, sp_inact, sp_expire, sp_flag)\n\ +Return the shadow password database entry for the given user name.\n\ +See spwd.__doc__ for more on shadow password database entries."); + +static PyObject* spwd_getspnam(PyObject *self, PyObject *args) +{ + char *name; + struct spwd *p; + if (!PyArg_ParseTuple(args, "s:getspnam", &name)) + return NULL; + if ((p = getspnam(name)) == NULL) { + PyErr_SetString(PyExc_KeyError, "getspnam(): name not found"); + return NULL; + } + return mkspent(p); +} + +#endif /* HAVE_GETSPNAM */ + +#ifdef HAVE_GETSPENT + +PyDoc_STRVAR(spwd_getspall__doc__, +"getspall() -> list_of_entries\n\ +Return a list of all available shadow password database entries, \ +in arbitrary order.\n\ +See spwd.__doc__ for more on shadow password database entries."); + +static PyObject * +spwd_getspall(PyObject *self, PyObject *args) +{ + PyObject *d; + struct spwd *p; + if ((d = PyList_New(0)) == NULL) + return NULL; + setspent(); + while ((p = getspent()) != NULL) { + PyObject *v = mkspent(p); + if (v == NULL || PyList_Append(d, v) != 0) { + Py_XDECREF(v); + Py_DECREF(d); + endspent(); + return NULL; + } + Py_DECREF(v); + } + endspent(); + return d; +} + +#endif /* HAVE_GETSPENT */ + +static PyMethodDef spwd_methods[] = { +#ifdef HAVE_GETSPNAM + {"getspnam", spwd_getspnam, METH_VARARGS, spwd_getspnam__doc__}, +#endif +#ifdef HAVE_GETSPENT + {"getspall", spwd_getspall, METH_NOARGS, spwd_getspall__doc__}, +#endif + {NULL, NULL} /* sentinel */ +}; + + +PyMODINIT_FUNC +initspwd(void) +{ + PyObject *m; + m=Py_InitModule3("spwd", spwd_methods, spwd__doc__); + if (m == NULL) + return; + if (!initialized) + PyStructSequence_InitType(&StructSpwdType, + &struct_spwd_type_desc); + Py_INCREF((PyObject *) &StructSpwdType); + PyModule_AddObject(m, "struct_spwd", (PyObject *) &StructSpwdType); + initialized = 1; +} diff --git a/sys/src/cmd/python/Modules/sre.h b/sys/src/cmd/python/Modules/sre.h new file mode 100644 index 000000000..d4af05c04 --- /dev/null +++ b/sys/src/cmd/python/Modules/sre.h @@ -0,0 +1,94 @@ +/* + * Secret Labs' Regular Expression Engine + * + * regular expression matching engine + * + * Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved. + * + * See the _sre.c file for information on usage and redistribution. + */ + +#ifndef SRE_INCLUDED +#define SRE_INCLUDED + +#include "sre_constants.h" + +/* size of a code word (must be unsigned short or larger, and + large enough to hold a Py_UNICODE character) */ +#ifdef Py_UNICODE_WIDE +#define SRE_CODE Py_UCS4 +#else +#define SRE_CODE unsigned short +#endif + +typedef struct { + PyObject_VAR_HEAD + Py_ssize_t groups; /* must be first! */ + PyObject* groupindex; + PyObject* indexgroup; + /* compatibility */ + PyObject* pattern; /* pattern source (or None) */ + int flags; /* flags used when compiling pattern source */ + PyObject *weakreflist; /* List of weak references */ + /* pattern code */ + Py_ssize_t codesize; + SRE_CODE code[1]; +} PatternObject; + +#define PatternObject_GetCode(o) (((PatternObject*)(o))->code) + +typedef struct { + PyObject_VAR_HEAD + PyObject* string; /* link to the target string (must be first) */ + PyObject* regs; /* cached list of matching spans */ + PatternObject* pattern; /* link to the regex (pattern) object */ + Py_ssize_t pos, endpos; /* current target slice */ + Py_ssize_t lastindex; /* last index marker seen by the engine (-1 if none) */ + Py_ssize_t groups; /* number of groups (start/end marks) */ + Py_ssize_t mark[1]; +} MatchObject; + +typedef unsigned int (*SRE_TOLOWER_HOOK)(unsigned int ch); + +/* FIXME: <fl> shouldn't be a constant, really... */ +#define SRE_MARK_SIZE 200 + +typedef struct SRE_REPEAT_T { + Py_ssize_t count; + SRE_CODE* pattern; /* points to REPEAT operator arguments */ + void* last_ptr; /* helper to check for infinite loops */ + struct SRE_REPEAT_T *prev; /* points to previous repeat context */ +} SRE_REPEAT; + +typedef struct { + /* string pointers */ + void* ptr; /* current position (also end of current slice) */ + void* beginning; /* start of original string */ + void* start; /* start of current slice */ + void* end; /* end of original string */ + /* attributes for the match object */ + PyObject* string; + Py_ssize_t pos, endpos; + /* character size */ + int charsize; + /* registers */ + Py_ssize_t lastindex; + Py_ssize_t lastmark; + void* mark[SRE_MARK_SIZE]; + /* dynamically allocated stuff */ + char* data_stack; + size_t data_stack_size; + size_t data_stack_base; + /* current repeat context */ + SRE_REPEAT *repeat; + /* hooks */ + SRE_TOLOWER_HOOK lower; +} SRE_STATE; + +typedef struct { + PyObject_HEAD + PyObject* pattern; + SRE_STATE state; +} ScannerObject; + +#endif diff --git a/sys/src/cmd/python/Modules/sre_constants.h b/sys/src/cmd/python/Modules/sre_constants.h new file mode 100644 index 000000000..13c89583e --- /dev/null +++ b/sys/src/cmd/python/Modules/sre_constants.h @@ -0,0 +1,86 @@ +/* + * Secret Labs' Regular Expression Engine + * + * regular expression matching engine + * + * NOTE: This file is generated by sre_constants.py. If you need + * to change anything in here, edit sre_constants.py and run it. + * + * Copyright (c) 1997-2001 by Secret Labs AB. All rights reserved. + * + * See the _sre.c file for information on usage and redistribution. + */ + +#define SRE_MAGIC 20031017 +#define SRE_OP_FAILURE 0 +#define SRE_OP_SUCCESS 1 +#define SRE_OP_ANY 2 +#define SRE_OP_ANY_ALL 3 +#define SRE_OP_ASSERT 4 +#define SRE_OP_ASSERT_NOT 5 +#define SRE_OP_AT 6 +#define SRE_OP_BRANCH 7 +#define SRE_OP_CALL 8 +#define SRE_OP_CATEGORY 9 +#define SRE_OP_CHARSET 10 +#define SRE_OP_BIGCHARSET 11 +#define SRE_OP_GROUPREF 12 +#define SRE_OP_GROUPREF_EXISTS 13 +#define SRE_OP_GROUPREF_IGNORE 14 +#define SRE_OP_IN 15 +#define SRE_OP_IN_IGNORE 16 +#define SRE_OP_INFO 17 +#define SRE_OP_JUMP 18 +#define SRE_OP_LITERAL 19 +#define SRE_OP_LITERAL_IGNORE 20 +#define SRE_OP_MARK 21 +#define SRE_OP_MAX_UNTIL 22 +#define SRE_OP_MIN_UNTIL 23 +#define SRE_OP_NOT_LITERAL 24 +#define SRE_OP_NOT_LITERAL_IGNORE 25 +#define SRE_OP_NEGATE 26 +#define SRE_OP_RANGE 27 +#define SRE_OP_REPEAT 28 +#define SRE_OP_REPEAT_ONE 29 +#define SRE_OP_SUBPATTERN 30 +#define SRE_OP_MIN_REPEAT_ONE 31 +#define SRE_AT_BEGINNING 0 +#define SRE_AT_BEGINNING_LINE 1 +#define SRE_AT_BEGINNING_STRING 2 +#define SRE_AT_BOUNDARY 3 +#define SRE_AT_NON_BOUNDARY 4 +#define SRE_AT_END 5 +#define SRE_AT_END_LINE 6 +#define SRE_AT_END_STRING 7 +#define SRE_AT_LOC_BOUNDARY 8 +#define SRE_AT_LOC_NON_BOUNDARY 9 +#define SRE_AT_UNI_BOUNDARY 10 +#define SRE_AT_UNI_NON_BOUNDARY 11 +#define SRE_CATEGORY_DIGIT 0 +#define SRE_CATEGORY_NOT_DIGIT 1 +#define SRE_CATEGORY_SPACE 2 +#define SRE_CATEGORY_NOT_SPACE 3 +#define SRE_CATEGORY_WORD 4 +#define SRE_CATEGORY_NOT_WORD 5 +#define SRE_CATEGORY_LINEBREAK 6 +#define SRE_CATEGORY_NOT_LINEBREAK 7 +#define SRE_CATEGORY_LOC_WORD 8 +#define SRE_CATEGORY_LOC_NOT_WORD 9 +#define SRE_CATEGORY_UNI_DIGIT 10 +#define SRE_CATEGORY_UNI_NOT_DIGIT 11 +#define SRE_CATEGORY_UNI_SPACE 12 +#define SRE_CATEGORY_UNI_NOT_SPACE 13 +#define SRE_CATEGORY_UNI_WORD 14 +#define SRE_CATEGORY_UNI_NOT_WORD 15 +#define SRE_CATEGORY_UNI_LINEBREAK 16 +#define SRE_CATEGORY_UNI_NOT_LINEBREAK 17 +#define SRE_FLAG_TEMPLATE 1 +#define SRE_FLAG_IGNORECASE 2 +#define SRE_FLAG_LOCALE 4 +#define SRE_FLAG_MULTILINE 8 +#define SRE_FLAG_DOTALL 16 +#define SRE_FLAG_UNICODE 32 +#define SRE_FLAG_VERBOSE 64 +#define SRE_INFO_PREFIX 1 +#define SRE_INFO_LITERAL 2 +#define SRE_INFO_CHARSET 4 diff --git a/sys/src/cmd/python/Modules/stropmodule.c b/sys/src/cmd/python/Modules/stropmodule.c new file mode 100644 index 000000000..8b00fed69 --- /dev/null +++ b/sys/src/cmd/python/Modules/stropmodule.c @@ -0,0 +1,1248 @@ +/* strop module */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include <ctype.h> + +PyDoc_STRVAR(strop_module__doc__, +"Common string manipulations, optimized for speed.\n" +"\n" +"Always use \"import string\" rather than referencing\n" +"this module directly."); + +/* XXX This file assumes that the <ctype.h> is*() functions + XXX are defined for all 8-bit characters! */ + +#define WARN if (PyErr_Warn(PyExc_DeprecationWarning, \ + "strop functions are obsolete; use string methods")) \ + return NULL + +/* The lstrip(), rstrip() and strip() functions are implemented + in do_strip(), which uses an additional parameter to indicate what + type of strip should occur. */ + +#define LEFTSTRIP 0 +#define RIGHTSTRIP 1 +#define BOTHSTRIP 2 + + +static PyObject * +split_whitespace(char *s, Py_ssize_t len, Py_ssize_t maxsplit) +{ + Py_ssize_t i = 0, j; + int err; + Py_ssize_t countsplit = 0; + PyObject* item; + PyObject *list = PyList_New(0); + + if (list == NULL) + return NULL; + + while (i < len) { + while (i < len && isspace(Py_CHARMASK(s[i]))) { + i = i+1; + } + j = i; + while (i < len && !isspace(Py_CHARMASK(s[i]))) { + i = i+1; + } + if (j < i) { + item = PyString_FromStringAndSize(s+j, i-j); + if (item == NULL) + goto finally; + + err = PyList_Append(list, item); + Py_DECREF(item); + if (err < 0) + goto finally; + + countsplit++; + while (i < len && isspace(Py_CHARMASK(s[i]))) { + i = i+1; + } + if (maxsplit && (countsplit >= maxsplit) && i < len) { + item = PyString_FromStringAndSize( + s+i, len - i); + if (item == NULL) + goto finally; + + err = PyList_Append(list, item); + Py_DECREF(item); + if (err < 0) + goto finally; + + i = len; + } + } + } + return list; + finally: + Py_DECREF(list); + return NULL; +} + + +PyDoc_STRVAR(splitfields__doc__, +"split(s [,sep [,maxsplit]]) -> list of strings\n" +"splitfields(s [,sep [,maxsplit]]) -> list of strings\n" +"\n" +"Return a list of the words in the string s, using sep as the\n" +"delimiter string. If maxsplit is nonzero, splits into at most\n" +"maxsplit words. If sep is not specified, any whitespace string\n" +"is a separator. Maxsplit defaults to 0.\n" +"\n" +"(split and splitfields are synonymous)"); + +static PyObject * +strop_splitfields(PyObject *self, PyObject *args) +{ + Py_ssize_t len, n, i, j, err; + Py_ssize_t splitcount, maxsplit; + char *s, *sub; + PyObject *list, *item; + + WARN; + sub = NULL; + n = 0; + splitcount = 0; + maxsplit = 0; + if (!PyArg_ParseTuple(args, "t#|z#n:split", &s, &len, &sub, &n, &maxsplit)) + return NULL; + if (sub == NULL) + return split_whitespace(s, len, maxsplit); + if (n == 0) { + PyErr_SetString(PyExc_ValueError, "empty separator"); + return NULL; + } + + list = PyList_New(0); + if (list == NULL) + return NULL; + + i = j = 0; + while (i+n <= len) { + if (s[i] == sub[0] && (n == 1 || memcmp(s+i, sub, n) == 0)) { + item = PyString_FromStringAndSize(s+j, i-j); + if (item == NULL) + goto fail; + err = PyList_Append(list, item); + Py_DECREF(item); + if (err < 0) + goto fail; + i = j = i + n; + splitcount++; + if (maxsplit && (splitcount >= maxsplit)) + break; + } + else + i++; + } + item = PyString_FromStringAndSize(s+j, len-j); + if (item == NULL) + goto fail; + err = PyList_Append(list, item); + Py_DECREF(item); + if (err < 0) + goto fail; + + return list; + + fail: + Py_DECREF(list); + return NULL; +} + + +PyDoc_STRVAR(joinfields__doc__, +"join(list [,sep]) -> string\n" +"joinfields(list [,sep]) -> string\n" +"\n" +"Return a string composed of the words in list, with\n" +"intervening occurrences of sep. Sep defaults to a single\n" +"space.\n" +"\n" +"(join and joinfields are synonymous)"); + +static PyObject * +strop_joinfields(PyObject *self, PyObject *args) +{ + PyObject *seq; + char *sep = NULL; + Py_ssize_t seqlen, seplen = 0; + Py_ssize_t i, reslen = 0, slen = 0, sz = 100; + PyObject *res = NULL; + char* p = NULL; + ssizeargfunc getitemfunc; + + WARN; + if (!PyArg_ParseTuple(args, "O|t#:join", &seq, &sep, &seplen)) + return NULL; + if (sep == NULL) { + sep = " "; + seplen = 1; + } + + seqlen = PySequence_Size(seq); + if (seqlen < 0 && PyErr_Occurred()) + return NULL; + + if (seqlen == 1) { + /* Optimization if there's only one item */ + PyObject *item = PySequence_GetItem(seq, 0); + if (item && !PyString_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be sequence of strings"); + Py_DECREF(item); + return NULL; + } + return item; + } + + if (!(res = PyString_FromStringAndSize((char*)NULL, sz))) + return NULL; + p = PyString_AsString(res); + + /* optimize for lists, since it's the most common case. all others + * (tuples and arbitrary sequences) just use the sequence abstract + * interface. + */ + if (PyList_Check(seq)) { + for (i = 0; i < seqlen; i++) { + PyObject *item = PyList_GET_ITEM(seq, i); + if (!PyString_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be sequence of strings"); + Py_DECREF(res); + return NULL; + } + slen = PyString_GET_SIZE(item); + while (reslen + slen + seplen >= sz) { + if (_PyString_Resize(&res, sz * 2) < 0) + return NULL; + sz *= 2; + p = PyString_AsString(res) + reslen; + } + if (i > 0) { + memcpy(p, sep, seplen); + p += seplen; + reslen += seplen; + } + memcpy(p, PyString_AS_STRING(item), slen); + p += slen; + reslen += slen; + } + _PyString_Resize(&res, reslen); + return res; + } + + if (seq->ob_type->tp_as_sequence == NULL || + (getitemfunc = seq->ob_type->tp_as_sequence->sq_item) == NULL) + { + PyErr_SetString(PyExc_TypeError, + "first argument must be a sequence"); + return NULL; + } + /* This is now type safe */ + for (i = 0; i < seqlen; i++) { + PyObject *item = getitemfunc(seq, i); + if (!item || !PyString_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be sequence of strings"); + Py_DECREF(res); + Py_XDECREF(item); + return NULL; + } + slen = PyString_GET_SIZE(item); + while (reslen + slen + seplen >= sz) { + if (_PyString_Resize(&res, sz * 2) < 0) { + Py_DECREF(item); + return NULL; + } + sz *= 2; + p = PyString_AsString(res) + reslen; + } + if (i > 0) { + memcpy(p, sep, seplen); + p += seplen; + reslen += seplen; + } + memcpy(p, PyString_AS_STRING(item), slen); + p += slen; + reslen += slen; + Py_DECREF(item); + } + _PyString_Resize(&res, reslen); + return res; +} + + +PyDoc_STRVAR(find__doc__, +"find(s, sub [,start [,end]]) -> in\n" +"\n" +"Return the lowest index in s where substring sub is found,\n" +"such that sub is contained within s[start,end]. Optional\n" +"arguments start and end are interpreted as in slice notation.\n" +"\n" +"Return -1 on failure."); + +static PyObject * +strop_find(PyObject *self, PyObject *args) +{ + char *s, *sub; + Py_ssize_t len, n, i = 0, last = PY_SSIZE_T_MAX; + + WARN; + if (!PyArg_ParseTuple(args, "t#t#|nn:find", &s, &len, &sub, &n, &i, &last)) + return NULL; + + if (last > len) + last = len; + if (last < 0) + last += len; + if (last < 0) + last = 0; + if (i < 0) + i += len; + if (i < 0) + i = 0; + + if (n == 0 && i <= last) + return PyInt_FromLong((long)i); + + last -= n; + for (; i <= last; ++i) + if (s[i] == sub[0] && + (n == 1 || memcmp(&s[i+1], &sub[1], n-1) == 0)) + return PyInt_FromLong((long)i); + + return PyInt_FromLong(-1L); +} + + +PyDoc_STRVAR(rfind__doc__, +"rfind(s, sub [,start [,end]]) -> int\n" +"\n" +"Return the highest index in s where substring sub is found,\n" +"such that sub is contained within s[start,end]. Optional\n" +"arguments start and end are interpreted as in slice notation.\n" +"\n" +"Return -1 on failure."); + +static PyObject * +strop_rfind(PyObject *self, PyObject *args) +{ + char *s, *sub; + Py_ssize_t len, n, j; + Py_ssize_t i = 0, last = PY_SSIZE_T_MAX; + + WARN; + if (!PyArg_ParseTuple(args, "t#t#|nn:rfind", &s, &len, &sub, &n, &i, &last)) + return NULL; + + if (last > len) + last = len; + if (last < 0) + last += len; + if (last < 0) + last = 0; + if (i < 0) + i += len; + if (i < 0) + i = 0; + + if (n == 0 && i <= last) + return PyInt_FromLong((long)last); + + for (j = last-n; j >= i; --j) + if (s[j] == sub[0] && + (n == 1 || memcmp(&s[j+1], &sub[1], n-1) == 0)) + return PyInt_FromLong((long)j); + + return PyInt_FromLong(-1L); +} + + +static PyObject * +do_strip(PyObject *args, int striptype) +{ + char *s; + Py_ssize_t len, i, j; + + + if (PyString_AsStringAndSize(args, &s, &len)) + return NULL; + + i = 0; + if (striptype != RIGHTSTRIP) { + while (i < len && isspace(Py_CHARMASK(s[i]))) { + i++; + } + } + + j = len; + if (striptype != LEFTSTRIP) { + do { + j--; + } while (j >= i && isspace(Py_CHARMASK(s[j]))); + j++; + } + + if (i == 0 && j == len) { + Py_INCREF(args); + return args; + } + else + return PyString_FromStringAndSize(s+i, j-i); +} + + +PyDoc_STRVAR(strip__doc__, +"strip(s) -> string\n" +"\n" +"Return a copy of the string s with leading and trailing\n" +"whitespace removed."); + +static PyObject * +strop_strip(PyObject *self, PyObject *args) +{ + WARN; + return do_strip(args, BOTHSTRIP); +} + + +PyDoc_STRVAR(lstrip__doc__, +"lstrip(s) -> string\n" +"\n" +"Return a copy of the string s with leading whitespace removed."); + +static PyObject * +strop_lstrip(PyObject *self, PyObject *args) +{ + WARN; + return do_strip(args, LEFTSTRIP); +} + + +PyDoc_STRVAR(rstrip__doc__, +"rstrip(s) -> string\n" +"\n" +"Return a copy of the string s with trailing whitespace removed."); + +static PyObject * +strop_rstrip(PyObject *self, PyObject *args) +{ + WARN; + return do_strip(args, RIGHTSTRIP); +} + + +PyDoc_STRVAR(lower__doc__, +"lower(s) -> string\n" +"\n" +"Return a copy of the string s converted to lowercase."); + +static PyObject * +strop_lower(PyObject *self, PyObject *args) +{ + char *s, *s_new; + Py_ssize_t i, n; + PyObject *newstr; + int changed; + + WARN; + if (PyString_AsStringAndSize(args, &s, &n)) + return NULL; + newstr = PyString_FromStringAndSize(NULL, n); + if (newstr == NULL) + return NULL; + s_new = PyString_AsString(newstr); + changed = 0; + for (i = 0; i < n; i++) { + int c = Py_CHARMASK(*s++); + if (isupper(c)) { + changed = 1; + *s_new = tolower(c); + } else + *s_new = c; + s_new++; + } + if (!changed) { + Py_DECREF(newstr); + Py_INCREF(args); + return args; + } + return newstr; +} + + +PyDoc_STRVAR(upper__doc__, +"upper(s) -> string\n" +"\n" +"Return a copy of the string s converted to uppercase."); + +static PyObject * +strop_upper(PyObject *self, PyObject *args) +{ + char *s, *s_new; + Py_ssize_t i, n; + PyObject *newstr; + int changed; + + WARN; + if (PyString_AsStringAndSize(args, &s, &n)) + return NULL; + newstr = PyString_FromStringAndSize(NULL, n); + if (newstr == NULL) + return NULL; + s_new = PyString_AsString(newstr); + changed = 0; + for (i = 0; i < n; i++) { + int c = Py_CHARMASK(*s++); + if (islower(c)) { + changed = 1; + *s_new = toupper(c); + } else + *s_new = c; + s_new++; + } + if (!changed) { + Py_DECREF(newstr); + Py_INCREF(args); + return args; + } + return newstr; +} + + +PyDoc_STRVAR(capitalize__doc__, +"capitalize(s) -> string\n" +"\n" +"Return a copy of the string s with only its first character\n" +"capitalized."); + +static PyObject * +strop_capitalize(PyObject *self, PyObject *args) +{ + char *s, *s_new; + Py_ssize_t i, n; + PyObject *newstr; + int changed; + + WARN; + if (PyString_AsStringAndSize(args, &s, &n)) + return NULL; + newstr = PyString_FromStringAndSize(NULL, n); + if (newstr == NULL) + return NULL; + s_new = PyString_AsString(newstr); + changed = 0; + if (0 < n) { + int c = Py_CHARMASK(*s++); + if (islower(c)) { + changed = 1; + *s_new = toupper(c); + } else + *s_new = c; + s_new++; + } + for (i = 1; i < n; i++) { + int c = Py_CHARMASK(*s++); + if (isupper(c)) { + changed = 1; + *s_new = tolower(c); + } else + *s_new = c; + s_new++; + } + if (!changed) { + Py_DECREF(newstr); + Py_INCREF(args); + return args; + } + return newstr; +} + + +PyDoc_STRVAR(expandtabs__doc__, +"expandtabs(string, [tabsize]) -> string\n" +"\n" +"Expand tabs in a string, i.e. replace them by one or more spaces,\n" +"depending on the current column and the given tab size (default 8).\n" +"The column number is reset to zero after each newline occurring in the\n" +"string. This doesn't understand other non-printing characters."); + +static PyObject * +strop_expandtabs(PyObject *self, PyObject *args) +{ + /* Original by Fredrik Lundh */ + char* e; + char* p; + char* q; + Py_ssize_t i, j; + PyObject* out; + char* string; + Py_ssize_t stringlen; + int tabsize = 8; + + WARN; + /* Get arguments */ + if (!PyArg_ParseTuple(args, "s#|i:expandtabs", &string, &stringlen, &tabsize)) + return NULL; + if (tabsize < 1) { + PyErr_SetString(PyExc_ValueError, + "tabsize must be at least 1"); + return NULL; + } + + /* First pass: determine size of output string */ + i = j = 0; /* j: current column; i: total of previous lines */ + e = string + stringlen; + for (p = string; p < e; p++) { + if (*p == '\t') + j += tabsize - (j%tabsize); + else { + j++; + if (*p == '\n') { + i += j; + j = 0; + } + } + } + + /* Second pass: create output string and fill it */ + out = PyString_FromStringAndSize(NULL, i+j); + if (out == NULL) + return NULL; + + i = 0; + q = PyString_AS_STRING(out); + + for (p = string; p < e; p++) { + if (*p == '\t') { + j = tabsize - (i%tabsize); + i += j; + while (j-- > 0) + *q++ = ' '; + } else { + *q++ = *p; + i++; + if (*p == '\n') + i = 0; + } + } + + return out; +} + + +PyDoc_STRVAR(count__doc__, +"count(s, sub[, start[, end]]) -> int\n" +"\n" +"Return the number of occurrences of substring sub in string\n" +"s[start:end]. Optional arguments start and end are\n" +"interpreted as in slice notation."); + +static PyObject * +strop_count(PyObject *self, PyObject *args) +{ + char *s, *sub; + Py_ssize_t len, n; + Py_ssize_t i = 0, last = PY_SSIZE_T_MAX; + Py_ssize_t m, r; + + WARN; + if (!PyArg_ParseTuple(args, "t#t#|nn:count", &s, &len, &sub, &n, &i, &last)) + return NULL; + if (last > len) + last = len; + if (last < 0) + last += len; + if (last < 0) + last = 0; + if (i < 0) + i += len; + if (i < 0) + i = 0; + m = last + 1 - n; + if (n == 0) + return PyInt_FromLong((long) (m-i)); + + r = 0; + while (i < m) { + if (!memcmp(s+i, sub, n)) { + r++; + i += n; + } else { + i++; + } + } + return PyInt_FromLong((long) r); +} + + +PyDoc_STRVAR(swapcase__doc__, +"swapcase(s) -> string\n" +"\n" +"Return a copy of the string s with upper case characters\n" +"converted to lowercase and vice versa."); + +static PyObject * +strop_swapcase(PyObject *self, PyObject *args) +{ + char *s, *s_new; + Py_ssize_t i, n; + PyObject *newstr; + int changed; + + WARN; + if (PyString_AsStringAndSize(args, &s, &n)) + return NULL; + newstr = PyString_FromStringAndSize(NULL, n); + if (newstr == NULL) + return NULL; + s_new = PyString_AsString(newstr); + changed = 0; + for (i = 0; i < n; i++) { + int c = Py_CHARMASK(*s++); + if (islower(c)) { + changed = 1; + *s_new = toupper(c); + } + else if (isupper(c)) { + changed = 1; + *s_new = tolower(c); + } + else + *s_new = c; + s_new++; + } + if (!changed) { + Py_DECREF(newstr); + Py_INCREF(args); + return args; + } + return newstr; +} + + +PyDoc_STRVAR(atoi__doc__, +"atoi(s [,base]) -> int\n" +"\n" +"Return the integer represented by the string s in the given\n" +"base, which defaults to 10. The string s must consist of one\n" +"or more digits, possibly preceded by a sign. If base is 0, it\n" +"is chosen from the leading characters of s, 0 for octal, 0x or\n" +"0X for hexadecimal. If base is 16, a preceding 0x or 0X is\n" +"accepted."); + +static PyObject * +strop_atoi(PyObject *self, PyObject *args) +{ + char *s, *end; + int base = 10; + long x; + char buffer[256]; /* For errors */ + + WARN; + if (!PyArg_ParseTuple(args, "s|i:atoi", &s, &base)) + return NULL; + + if ((base != 0 && base < 2) || base > 36) { + PyErr_SetString(PyExc_ValueError, "invalid base for atoi()"); + return NULL; + } + + while (*s && isspace(Py_CHARMASK(*s))) + s++; + errno = 0; + if (base == 0 && s[0] == '0') + x = (long) PyOS_strtoul(s, &end, base); + else + x = PyOS_strtol(s, &end, base); + if (end == s || !isalnum(Py_CHARMASK(end[-1]))) + goto bad; + while (*end && isspace(Py_CHARMASK(*end))) + end++; + if (*end != '\0') { + bad: + PyOS_snprintf(buffer, sizeof(buffer), + "invalid literal for atoi(): %.200s", s); + PyErr_SetString(PyExc_ValueError, buffer); + return NULL; + } + else if (errno != 0) { + PyOS_snprintf(buffer, sizeof(buffer), + "atoi() literal too large: %.200s", s); + PyErr_SetString(PyExc_ValueError, buffer); + return NULL; + } + return PyInt_FromLong(x); +} + + +PyDoc_STRVAR(atol__doc__, +"atol(s [,base]) -> long\n" +"\n" +"Return the long integer represented by the string s in the\n" +"given base, which defaults to 10. The string s must consist\n" +"of one or more digits, possibly preceded by a sign. If base\n" +"is 0, it is chosen from the leading characters of s, 0 for\n" +"octal, 0x or 0X for hexadecimal. If base is 16, a preceding\n" +"0x or 0X is accepted. A trailing L or l is not accepted,\n" +"unless base is 0."); + +static PyObject * +strop_atol(PyObject *self, PyObject *args) +{ + char *s, *end; + int base = 10; + PyObject *x; + char buffer[256]; /* For errors */ + + WARN; + if (!PyArg_ParseTuple(args, "s|i:atol", &s, &base)) + return NULL; + + if ((base != 0 && base < 2) || base > 36) { + PyErr_SetString(PyExc_ValueError, "invalid base for atol()"); + return NULL; + } + + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (s[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "empty string for atol()"); + return NULL; + } + x = PyLong_FromString(s, &end, base); + if (x == NULL) + return NULL; + if (base == 0 && (*end == 'l' || *end == 'L')) + end++; + while (*end && isspace(Py_CHARMASK(*end))) + end++; + if (*end != '\0') { + PyOS_snprintf(buffer, sizeof(buffer), + "invalid literal for atol(): %.200s", s); + PyErr_SetString(PyExc_ValueError, buffer); + Py_DECREF(x); + return NULL; + } + return x; +} + + +PyDoc_STRVAR(atof__doc__, +"atof(s) -> float\n" +"\n" +"Return the floating point number represented by the string s."); + +static PyObject * +strop_atof(PyObject *self, PyObject *args) +{ + char *s, *end; + double x; + char buffer[256]; /* For errors */ + + WARN; + if (!PyArg_ParseTuple(args, "s:atof", &s)) + return NULL; + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (s[0] == '\0') { + PyErr_SetString(PyExc_ValueError, "empty string for atof()"); + return NULL; + } + errno = 0; + PyFPE_START_PROTECT("strop_atof", return 0) + x = PyOS_ascii_strtod(s, &end); + PyFPE_END_PROTECT(x) + while (*end && isspace(Py_CHARMASK(*end))) + end++; + if (*end != '\0') { + PyOS_snprintf(buffer, sizeof(buffer), + "invalid literal for atof(): %.200s", s); + PyErr_SetString(PyExc_ValueError, buffer); + return NULL; + } + else if (errno != 0) { + PyOS_snprintf(buffer, sizeof(buffer), + "atof() literal too large: %.200s", s); + PyErr_SetString(PyExc_ValueError, buffer); + return NULL; + } + return PyFloat_FromDouble(x); +} + + +PyDoc_STRVAR(maketrans__doc__, +"maketrans(frm, to) -> string\n" +"\n" +"Return a translation table (a string of 256 bytes long)\n" +"suitable for use in string.translate. The strings frm and to\n" +"must be of the same length."); + +static PyObject * +strop_maketrans(PyObject *self, PyObject *args) +{ + unsigned char *c, *from=NULL, *to=NULL; + Py_ssize_t i, fromlen=0, tolen=0; + PyObject *result; + + if (!PyArg_ParseTuple(args, "t#t#:maketrans", &from, &fromlen, &to, &tolen)) + return NULL; + + if (fromlen != tolen) { + PyErr_SetString(PyExc_ValueError, + "maketrans arguments must have same length"); + return NULL; + } + + result = PyString_FromStringAndSize((char *)NULL, 256); + if (result == NULL) + return NULL; + c = (unsigned char *) PyString_AS_STRING((PyStringObject *)result); + for (i = 0; i < 256; i++) + c[i]=(unsigned char)i; + for (i = 0; i < fromlen; i++) + c[from[i]]=to[i]; + + return result; +} + + +PyDoc_STRVAR(translate__doc__, +"translate(s,table [,deletechars]) -> string\n" +"\n" +"Return a copy of the string s, where all characters occurring\n" +"in the optional argument deletechars are removed, and the\n" +"remaining characters have been mapped through the given\n" +"translation table, which must be a string of length 256."); + +static PyObject * +strop_translate(PyObject *self, PyObject *args) +{ + register char *input, *table, *output; + Py_ssize_t i; + int c, changed = 0; + PyObject *input_obj; + char *table1, *output_start, *del_table=NULL; + Py_ssize_t inlen, tablen, dellen = 0; + PyObject *result; + int trans_table[256]; + + WARN; + if (!PyArg_ParseTuple(args, "St#|t#:translate", &input_obj, + &table1, &tablen, &del_table, &dellen)) + return NULL; + if (tablen != 256) { + PyErr_SetString(PyExc_ValueError, + "translation table must be 256 characters long"); + return NULL; + } + + table = table1; + inlen = PyString_GET_SIZE(input_obj); + result = PyString_FromStringAndSize((char *)NULL, inlen); + if (result == NULL) + return NULL; + output_start = output = PyString_AsString(result); + input = PyString_AsString(input_obj); + + if (dellen == 0) { + /* If no deletions are required, use faster code */ + for (i = inlen; --i >= 0; ) { + c = Py_CHARMASK(*input++); + if (Py_CHARMASK((*output++ = table[c])) != c) + changed = 1; + } + if (changed) + return result; + Py_DECREF(result); + Py_INCREF(input_obj); + return input_obj; + } + + for (i = 0; i < 256; i++) + trans_table[i] = Py_CHARMASK(table[i]); + + for (i = 0; i < dellen; i++) + trans_table[(int) Py_CHARMASK(del_table[i])] = -1; + + for (i = inlen; --i >= 0; ) { + c = Py_CHARMASK(*input++); + if (trans_table[c] != -1) + if (Py_CHARMASK(*output++ = (char)trans_table[c]) == c) + continue; + changed = 1; + } + if (!changed) { + Py_DECREF(result); + Py_INCREF(input_obj); + return input_obj; + } + /* Fix the size of the resulting string */ + if (inlen > 0) + _PyString_Resize(&result, output - output_start); + return result; +} + + +/* What follows is used for implementing replace(). Perry Stoll. */ + +/* + mymemfind + + strstr replacement for arbitrary blocks of memory. + + Locates the first occurrence in the memory pointed to by MEM of the + contents of memory pointed to by PAT. Returns the index into MEM if + found, or -1 if not found. If len of PAT is greater than length of + MEM, the function returns -1. +*/ +static Py_ssize_t +mymemfind(const char *mem, Py_ssize_t len, const char *pat, Py_ssize_t pat_len) +{ + register Py_ssize_t ii; + + /* pattern can not occur in the last pat_len-1 chars */ + len -= pat_len; + + for (ii = 0; ii <= len; ii++) { + if (mem[ii] == pat[0] && + (pat_len == 1 || + memcmp(&mem[ii+1], &pat[1], pat_len-1) == 0)) { + return ii; + } + } + return -1; +} + +/* + mymemcnt + + Return the number of distinct times PAT is found in MEM. + meaning mem=1111 and pat==11 returns 2. + mem=11111 and pat==11 also return 2. + */ +static Py_ssize_t +mymemcnt(const char *mem, Py_ssize_t len, const char *pat, Py_ssize_t pat_len) +{ + register Py_ssize_t offset = 0; + Py_ssize_t nfound = 0; + + while (len >= 0) { + offset = mymemfind(mem, len, pat, pat_len); + if (offset == -1) + break; + mem += offset + pat_len; + len -= offset + pat_len; + nfound++; + } + return nfound; +} + +/* + mymemreplace + + Return a string in which all occurrences of PAT in memory STR are + replaced with SUB. + + If length of PAT is less than length of STR or there are no occurrences + of PAT in STR, then the original string is returned. Otherwise, a new + string is allocated here and returned. + + on return, out_len is: + the length of output string, or + -1 if the input string is returned, or + unchanged if an error occurs (no memory). + + return value is: + the new string allocated locally, or + NULL if an error occurred. +*/ +static char * +mymemreplace(const char *str, Py_ssize_t len, /* input string */ + const char *pat, Py_ssize_t pat_len, /* pattern string to find */ + const char *sub, Py_ssize_t sub_len, /* substitution string */ + Py_ssize_t count, /* number of replacements */ + Py_ssize_t *out_len) +{ + char *out_s; + char *new_s; + Py_ssize_t nfound, offset, new_len; + + if (len == 0 || pat_len > len) + goto return_same; + + /* find length of output string */ + nfound = mymemcnt(str, len, pat, pat_len); + if (count < 0) + count = PY_SSIZE_T_MAX; + else if (nfound > count) + nfound = count; + if (nfound == 0) + goto return_same; + + new_len = len + nfound*(sub_len - pat_len); + if (new_len == 0) { + /* Have to allocate something for the caller to free(). */ + out_s = (char *)PyMem_MALLOC(1); + if (out_s == NULL) + return NULL; + out_s[0] = '\0'; + } + else { + assert(new_len > 0); + new_s = (char *)PyMem_MALLOC(new_len); + if (new_s == NULL) + return NULL; + out_s = new_s; + + for (; count > 0 && len > 0; --count) { + /* find index of next instance of pattern */ + offset = mymemfind(str, len, pat, pat_len); + if (offset == -1) + break; + + /* copy non matching part of input string */ + memcpy(new_s, str, offset); + str += offset + pat_len; + len -= offset + pat_len; + + /* copy substitute into the output string */ + new_s += offset; + memcpy(new_s, sub, sub_len); + new_s += sub_len; + } + /* copy any remaining values into output string */ + if (len > 0) + memcpy(new_s, str, len); + } + *out_len = new_len; + return out_s; + + return_same: + *out_len = -1; + return (char *)str; /* cast away const */ +} + + +PyDoc_STRVAR(replace__doc__, +"replace (str, old, new[, maxsplit]) -> string\n" +"\n" +"Return a copy of string str with all occurrences of substring\n" +"old replaced by new. If the optional argument maxsplit is\n" +"given, only the first maxsplit occurrences are replaced."); + +static PyObject * +strop_replace(PyObject *self, PyObject *args) +{ + char *str, *pat,*sub,*new_s; + Py_ssize_t len,pat_len,sub_len,out_len; + Py_ssize_t count = -1; + PyObject *newstr; + + WARN; + if (!PyArg_ParseTuple(args, "t#t#t#|n:replace", + &str, &len, &pat, &pat_len, &sub, &sub_len, + &count)) + return NULL; + if (pat_len <= 0) { + PyErr_SetString(PyExc_ValueError, "empty pattern string"); + return NULL; + } + /* CAUTION: strop treats a replace count of 0 as infinity, unlke + * current (2.1) string.py and string methods. Preserve this for + * ... well, hard to say for what <wink>. + */ + if (count == 0) + count = -1; + new_s = mymemreplace(str,len,pat,pat_len,sub,sub_len,count,&out_len); + if (new_s == NULL) { + PyErr_NoMemory(); + return NULL; + } + if (out_len == -1) { + /* we're returning another reference to the input string */ + newstr = PyTuple_GetItem(args, 0); + Py_XINCREF(newstr); + } + else { + newstr = PyString_FromStringAndSize(new_s, out_len); + PyMem_FREE(new_s); + } + return newstr; +} + + +/* List of functions defined in the module */ + +static PyMethodDef +strop_methods[] = { + {"atof", strop_atof, METH_VARARGS, atof__doc__}, + {"atoi", strop_atoi, METH_VARARGS, atoi__doc__}, + {"atol", strop_atol, METH_VARARGS, atol__doc__}, + {"capitalize", strop_capitalize, METH_O, capitalize__doc__}, + {"count", strop_count, METH_VARARGS, count__doc__}, + {"expandtabs", strop_expandtabs, METH_VARARGS, expandtabs__doc__}, + {"find", strop_find, METH_VARARGS, find__doc__}, + {"join", strop_joinfields, METH_VARARGS, joinfields__doc__}, + {"joinfields", strop_joinfields, METH_VARARGS, joinfields__doc__}, + {"lstrip", strop_lstrip, METH_O, lstrip__doc__}, + {"lower", strop_lower, METH_O, lower__doc__}, + {"maketrans", strop_maketrans, METH_VARARGS, maketrans__doc__}, + {"replace", strop_replace, METH_VARARGS, replace__doc__}, + {"rfind", strop_rfind, METH_VARARGS, rfind__doc__}, + {"rstrip", strop_rstrip, METH_O, rstrip__doc__}, + {"split", strop_splitfields, METH_VARARGS, splitfields__doc__}, + {"splitfields", strop_splitfields, METH_VARARGS, splitfields__doc__}, + {"strip", strop_strip, METH_O, strip__doc__}, + {"swapcase", strop_swapcase, METH_O, swapcase__doc__}, + {"translate", strop_translate, METH_VARARGS, translate__doc__}, + {"upper", strop_upper, METH_O, upper__doc__}, + {NULL, NULL} /* sentinel */ +}; + + +PyMODINIT_FUNC +initstrop(void) +{ + PyObject *m, *s; + char buf[256]; + int c, n; + m = Py_InitModule4("strop", strop_methods, strop_module__doc__, + (PyObject*)NULL, PYTHON_API_VERSION); + if (m == NULL) + return; + + /* Create 'whitespace' object */ + n = 0; + for (c = 0; c < 256; c++) { + if (isspace(c)) + buf[n++] = c; + } + s = PyString_FromStringAndSize(buf, n); + if (s) + PyModule_AddObject(m, "whitespace", s); + + /* Create 'lowercase' object */ + n = 0; + for (c = 0; c < 256; c++) { + if (islower(c)) + buf[n++] = c; + } + s = PyString_FromStringAndSize(buf, n); + if (s) + PyModule_AddObject(m, "lowercase", s); + + /* Create 'uppercase' object */ + n = 0; + for (c = 0; c < 256; c++) { + if (isupper(c)) + buf[n++] = c; + } + s = PyString_FromStringAndSize(buf, n); + if (s) + PyModule_AddObject(m, "uppercase", s); +} diff --git a/sys/src/cmd/python/Modules/sunaudiodev.c b/sys/src/cmd/python/Modules/sunaudiodev.c new file mode 100644 index 000000000..802184d0d --- /dev/null +++ b/sys/src/cmd/python/Modules/sunaudiodev.c @@ -0,0 +1,465 @@ + +/* Sad objects */ + +#include "Python.h" +#include "structmember.h" + +#ifdef HAVE_SYS_AUDIOIO_H +#define SOLARIS +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#include <stropts.h> +#include <sys/ioctl.h> +#ifdef SOLARIS +#include <sys/audioio.h> +#else +#include <sun/audioio.h> +#endif + +/* #define offsetof(str,mem) ((int)(((str *)0)->mem)) */ + +typedef struct { + PyObject_HEAD + int x_fd; /* The open file */ + int x_icount; /* # samples read */ + int x_ocount; /* # samples written */ + int x_isctl; /* True if control device */ + +} sadobject; + +typedef struct { + PyObject_HEAD + audio_info_t ai; +} sadstatusobject; + +static PyTypeObject Sadtype; +static PyTypeObject Sadstatustype; +static sadstatusobject *sads_alloc(void); /* Forward */ + +static PyObject *SunAudioError; + +#define is_sadobject(v) ((v)->ob_type == &Sadtype) +#define is_sadstatusobject(v) ((v)->ob_type == &Sadstatustype) + + +static sadobject * +newsadobject(PyObject *args) +{ + sadobject *xp; + int fd; + char *mode; + int imode; + char* basedev; + char* ctldev; + char* opendev; + + /* Check arg for r/w/rw */ + if (!PyArg_ParseTuple(args, "s", &mode)) + return NULL; + if (strcmp(mode, "r") == 0) + imode = 0; + else if (strcmp(mode, "w") == 0) + imode = 1; + else if (strcmp(mode, "rw") == 0) + imode = 2; + else if (strcmp(mode, "control") == 0) + imode = -1; + else { + PyErr_SetString(SunAudioError, + "Mode should be one of 'r', 'w', 'rw' or 'control'"); + return NULL; + } + + /* Open the correct device. The base device name comes from the + * AUDIODEV environment variable first, then /dev/audio. The + * control device tacks "ctl" onto the base device name. + */ + basedev = getenv("AUDIODEV"); + if (!basedev) + basedev = "/dev/audio"; + ctldev = PyMem_NEW(char, strlen(basedev) + 4); + if (!ctldev) { + PyErr_NoMemory(); + return NULL; + } + strcpy(ctldev, basedev); + strcat(ctldev, "ctl"); + + if (imode < 0) { + opendev = ctldev; + fd = open(ctldev, 2); + } + else { + opendev = basedev; + fd = open(basedev, imode); + } + if (fd < 0) { + PyErr_SetFromErrnoWithFilename(SunAudioError, opendev); + PyMem_DEL(ctldev); + return NULL; + } + PyMem_DEL(ctldev); + + /* Create and initialize the object */ + xp = PyObject_New(sadobject, &Sadtype); + if (xp == NULL) { + close(fd); + return NULL; + } + xp->x_fd = fd; + xp->x_icount = xp->x_ocount = 0; + xp->x_isctl = (imode < 0); + + return xp; +} + +/* Sad methods */ + +static void +sad_dealloc(sadobject *xp) +{ + close(xp->x_fd); + PyObject_Del(xp); +} + +static PyObject * +sad_read(sadobject *self, PyObject *args) +{ + int size, count; + char *cp; + PyObject *rv; + + if (!PyArg_ParseTuple(args, "i:read", &size)) + return NULL; + rv = PyString_FromStringAndSize(NULL, size); + if (rv == NULL) + return NULL; + + if (!(cp = PyString_AsString(rv))) + goto finally; + + count = read(self->x_fd, cp, size); + if (count < 0) { + PyErr_SetFromErrno(SunAudioError); + goto finally; + } +#if 0 + /* TBD: why print this message if you can handle the condition? + * assume it's debugging info which we can just as well get rid + * of. in any case this message should *not* be using printf! + */ + if (count != size) + printf("sunaudio: funny read rv %d wtd %d\n", count, size); +#endif + self->x_icount += count; + return rv; + + finally: + Py_DECREF(rv); + return NULL; +} + +static PyObject * +sad_write(sadobject *self, PyObject *args) +{ + char *cp; + int count, size; + + if (!PyArg_ParseTuple(args, "s#:write", &cp, &size)) + return NULL; + + count = write(self->x_fd, cp, size); + if (count < 0) { + PyErr_SetFromErrno(SunAudioError); + return NULL; + } +#if 0 + if (count != size) + printf("sunaudio: funny write rv %d wanted %d\n", count, size); +#endif + self->x_ocount += count; + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sad_getinfo(sadobject *self) +{ + sadstatusobject *rv; + + if (!(rv = sads_alloc())) + return NULL; + + if (ioctl(self->x_fd, AUDIO_GETINFO, &rv->ai) < 0) { + PyErr_SetFromErrno(SunAudioError); + Py_DECREF(rv); + return NULL; + } + return (PyObject *)rv; +} + +static PyObject * +sad_setinfo(sadobject *self, sadstatusobject *arg) +{ + if (!is_sadstatusobject(arg)) { + PyErr_SetString(PyExc_TypeError, + "Must be sun audio status object"); + return NULL; + } + if (ioctl(self->x_fd, AUDIO_SETINFO, &arg->ai) < 0) { + PyErr_SetFromErrno(SunAudioError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sad_ibufcount(sadobject *self) +{ + audio_info_t ai; + + if (ioctl(self->x_fd, AUDIO_GETINFO, &ai) < 0) { + PyErr_SetFromErrno(SunAudioError); + return NULL; + } + return PyInt_FromLong(ai.record.samples - self->x_icount); +} + +static PyObject * +sad_obufcount(sadobject *self) +{ + audio_info_t ai; + + if (ioctl(self->x_fd, AUDIO_GETINFO, &ai) < 0) { + PyErr_SetFromErrno(SunAudioError); + return NULL; + } + /* x_ocount is in bytes, whereas play.samples is in frames */ + /* we want frames */ + return PyInt_FromLong(self->x_ocount / (ai.play.channels * + ai.play.precision / 8) - + ai.play.samples); +} + +static PyObject * +sad_drain(sadobject *self) +{ + if (ioctl(self->x_fd, AUDIO_DRAIN, 0) < 0) { + PyErr_SetFromErrno(SunAudioError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef SOLARIS +static PyObject * +sad_getdev(sadobject *self) +{ + struct audio_device ad; + + if (ioctl(self->x_fd, AUDIO_GETDEV, &ad) < 0) { + PyErr_SetFromErrno(SunAudioError); + return NULL; + } + return Py_BuildValue("(sss)", ad.name, ad.version, ad.config); +} +#endif + +static PyObject * +sad_flush(sadobject *self) +{ + if (ioctl(self->x_fd, I_FLUSH, FLUSHW) < 0) { + PyErr_SetFromErrno(SunAudioError); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sad_close(sadobject *self) +{ + + if (self->x_fd >= 0) { + close(self->x_fd); + self->x_fd = -1; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sad_fileno(sadobject *self) +{ + return PyInt_FromLong(self->x_fd); +} + + +static PyMethodDef sad_methods[] = { + { "read", (PyCFunction)sad_read, METH_VARARGS }, + { "write", (PyCFunction)sad_write, METH_VARARGS }, + { "ibufcount", (PyCFunction)sad_ibufcount, METH_NOARGS }, + { "obufcount", (PyCFunction)sad_obufcount, METH_NOARGS }, +#define CTL_METHODS 4 + { "getinfo", (PyCFunction)sad_getinfo, METH_NOARGS }, + { "setinfo", (PyCFunction)sad_setinfo, METH_O}, + { "drain", (PyCFunction)sad_drain, METH_NOARGS }, + { "flush", (PyCFunction)sad_flush, METH_NOARGS }, +#ifdef SOLARIS + { "getdev", (PyCFunction)sad_getdev, METH_NOARGS }, +#endif + { "close", (PyCFunction)sad_close, METH_NOARGS }, + { "fileno", (PyCFunction)sad_fileno, METH_NOARGS }, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +sad_getattr(sadobject *xp, char *name) +{ + if (xp->x_isctl) + return Py_FindMethod(sad_methods+CTL_METHODS, + (PyObject *)xp, name); + else + return Py_FindMethod(sad_methods, (PyObject *)xp, name); +} + +/* ----------------------------------------------------------------- */ + +static sadstatusobject * +sads_alloc(void) { + return PyObject_New(sadstatusobject, &Sadstatustype); +} + +static void +sads_dealloc(sadstatusobject *xp) +{ + PyMem_DEL(xp); +} + +#define OFF(x) offsetof(audio_info_t,x) +static struct memberlist sads_ml[] = { + { "i_sample_rate", T_UINT, OFF(record.sample_rate) }, + { "i_channels", T_UINT, OFF(record.channels) }, + { "i_precision", T_UINT, OFF(record.precision) }, + { "i_encoding", T_UINT, OFF(record.encoding) }, + { "i_gain", T_UINT, OFF(record.gain) }, + { "i_port", T_UINT, OFF(record.port) }, + { "i_samples", T_UINT, OFF(record.samples) }, + { "i_eof", T_UINT, OFF(record.eof) }, + { "i_pause", T_UBYTE, OFF(record.pause) }, + { "i_error", T_UBYTE, OFF(record.error) }, + { "i_waiting", T_UBYTE, OFF(record.waiting) }, + { "i_open", T_UBYTE, OFF(record.open) , RO}, + { "i_active", T_UBYTE, OFF(record.active) , RO}, +#ifdef SOLARIS + { "i_buffer_size", T_UINT, OFF(record.buffer_size) }, + { "i_balance", T_UBYTE, OFF(record.balance) }, + { "i_avail_ports", T_UINT, OFF(record.avail_ports) }, +#endif + + { "o_sample_rate", T_UINT, OFF(play.sample_rate) }, + { "o_channels", T_UINT, OFF(play.channels) }, + { "o_precision", T_UINT, OFF(play.precision) }, + { "o_encoding", T_UINT, OFF(play.encoding) }, + { "o_gain", T_UINT, OFF(play.gain) }, + { "o_port", T_UINT, OFF(play.port) }, + { "o_samples", T_UINT, OFF(play.samples) }, + { "o_eof", T_UINT, OFF(play.eof) }, + { "o_pause", T_UBYTE, OFF(play.pause) }, + { "o_error", T_UBYTE, OFF(play.error) }, + { "o_waiting", T_UBYTE, OFF(play.waiting) }, + { "o_open", T_UBYTE, OFF(play.open) , RO}, + { "o_active", T_UBYTE, OFF(play.active) , RO}, +#ifdef SOLARIS + { "o_buffer_size", T_UINT, OFF(play.buffer_size) }, + { "o_balance", T_UBYTE, OFF(play.balance) }, + { "o_avail_ports", T_UINT, OFF(play.avail_ports) }, +#endif + + { "monitor_gain", T_UINT, OFF(monitor_gain) }, + { NULL, 0, 0}, +}; + +static PyObject * +sads_getattr(sadstatusobject *xp, char *name) +{ + return PyMember_Get((char *)&xp->ai, sads_ml, name); +} + +static int +sads_setattr(sadstatusobject *xp, char *name, PyObject *v) +{ + + if (v == NULL) { + PyErr_SetString(PyExc_TypeError, + "can't delete sun audio status attributes"); + return -1; + } + return PyMember_Set((char *)&xp->ai, sads_ml, name, v); +} + +/* ------------------------------------------------------------------- */ + + +static PyTypeObject Sadtype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "sunaudiodev.sun_audio_device", /*tp_name*/ + sizeof(sadobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)sad_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)sad_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyTypeObject Sadstatustype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "sunaudiodev.sun_audio_device_status", /*tp_name*/ + sizeof(sadstatusobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)sads_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)sads_getattr, /*tp_getattr*/ + (setattrfunc)sads_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; +/* ------------------------------------------------------------------- */ + +static PyObject * +sadopen(PyObject *self, PyObject *args) +{ + return (PyObject *)newsadobject(args); +} + +static PyMethodDef sunaudiodev_methods[] = { + { "open", sadopen, METH_VARARGS }, + { 0, 0 }, +}; + +void +initsunaudiodev(void) +{ + PyObject *m, *d; + + m = Py_InitModule("sunaudiodev", sunaudiodev_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + SunAudioError = PyErr_NewException("sunaudiodev.error", NULL, NULL); + if (SunAudioError) + PyDict_SetItemString(d, "error", SunAudioError); +} diff --git a/sys/src/cmd/python/Modules/svmodule.c b/sys/src/cmd/python/Modules/svmodule.c new file mode 100644 index 000000000..fb58f19cc --- /dev/null +++ b/sys/src/cmd/python/Modules/svmodule.c @@ -0,0 +1,966 @@ +/* SV module -- interface to the Indigo video board */ + +/* WARNING! This module is for hardware that we don't have any more, + so it hasn't been tested. It has been converted to the new coding + style, and it is possible that this conversion has broken something + -- user beware! */ + +#include <sys/time.h> +#include <svideo.h> +#include "Python.h" +#include "compile.h" +#include "yuv.h" /* for YUV conversion functions */ + +typedef struct { + PyObject_HEAD + SV_nodeP ob_svideo; + svCaptureInfo ob_info; +} svobject; + +typedef struct { + PyObject_HEAD + void *ob_capture; + int ob_mustunlock; + svCaptureInfo ob_info; + svobject *ob_svideo; +} captureobject; + +static PyObject *SvError; /* exception sv.error */ + +static PyObject *newcaptureobject(svobject *, void *, int); + +/* Set a SV-specific error from svideo_errno and return NULL */ +static PyObject * +sv_error(void) +{ + PyErr_SetString(SvError, svStrerror(svideo_errno)); + return NULL; +} + +static PyObject * +svc_conversion(captureobject *self, PyObject *args, void (*function)(), float factor) +{ + PyObject *output; + int invert; + char* outstr; + + if (!PyArg_Parse(args, "i", &invert)) + return NULL; + + if (!(output = PyString_FromStringAndSize( + NULL, + (int)(self->ob_info.width * self->ob_info.height * factor)))) + { + return NULL; + } + if (!(outstr = PyString_AsString(output))) { + Py_DECREF(output); + return NULL; + } + + (*function)((boolean)invert, self->ob_capture, + outstr, + self->ob_info.width, self->ob_info.height); + + return output; +} + +/* + * 3 functions to convert from Starter Video YUV 4:1:1 format to + * Compression Library 4:2:2 Duplicate Chroma format. + */ +static PyObject * +svc_YUVtoYUV422DC(captureobject *self, PyObject *args) +{ + if (self->ob_info.format != SV_YUV411_FRAMES) { + PyErr_SetString(SvError, "data has bad format"); + return NULL; + } + return svc_conversion(self, args, yuv_sv411_to_cl422dc, 2.0); +} + +static PyObject * +svc_YUVtoYUV422DC_quarter(captureobject *self, PyObject *args) +{ + if (self->ob_info.format != SV_YUV411_FRAMES) { + PyErr_SetString(SvError, "data has bad format"); + return NULL; + } + return svc_conversion(self, args, + yuv_sv411_to_cl422dc_quartersize, 0.5); +} + +static PyObject * +svc_YUVtoYUV422DC_sixteenth(captureobject *self, PyObject *args) +{ + if (self->ob_info.format != SV_YUV411_FRAMES) { + PyErr_SetString(SvError, "data has bad format"); + return NULL; + } + return svc_conversion(self, args, + yuv_sv411_to_cl422dc_sixteenthsize, 0.125); +} + +static PyObject * +svc_YUVtoRGB(captureobject *self, PyObject *args) +{ + switch (self->ob_info.format) { + case SV_YUV411_FRAMES: + case SV_YUV411_FRAMES_AND_BLANKING_BUFFER: + break; + default: + PyErr_SetString(SvError, "data had bad format"); + return NULL; + } + return svc_conversion(self, args, svYUVtoRGB, (float) sizeof(long)); +} + +static PyObject * +svc_RGB8toRGB32(captureobject *self, PyObject *args) +{ + if (self->ob_info.format != SV_RGB8_FRAMES) { + PyErr_SetString(SvError, "data has bad format"); + return NULL; + } + return svc_conversion(self, args, svRGB8toRGB32, (float) sizeof(long)); +} + +static PyObject * +svc_InterleaveFields(captureobject *self, PyObject *args) +{ + if (self->ob_info.format != SV_RGB8_FRAMES) { + PyErr_SetString(SvError, "data has bad format"); + return NULL; + } + return svc_conversion(self, args, svInterleaveFields, 1.0); +} + +static PyObject * +svc_GetFields(captureobject *self, PyObject *args) +{ + PyObject *f1 = NULL; + PyObject *f2 = NULL; + PyObject *ret = NULL; + int fieldsize; + char* obcapture; + + if (self->ob_info.format != SV_RGB8_FRAMES) { + PyErr_SetString(SvError, "data has bad format"); + return NULL; + } + + fieldsize = self->ob_info.width * self->ob_info.height / 2; + obcapture = (char*)self->ob_capture; + + if (!(f1 = PyString_FromStringAndSize(obcapture, fieldsize))) + goto finally; + if (!(f2 = PyString_FromStringAndSize(obcapture + fieldsize, + fieldsize))) + goto finally; + ret = PyTuple_Pack(2, f1, f2); + + finally: + Py_XDECREF(f1); + Py_XDECREF(f2); + return ret; +} + +static PyObject * +svc_UnlockCaptureData(captureobject *self, PyObject *args) +{ + if (!PyArg_Parse(args, "")) + return NULL; + + if (!self->ob_mustunlock) { + PyErr_SetString(SvError, "buffer should not be unlocked"); + return NULL; + } + + if (svUnlockCaptureData(self->ob_svideo->ob_svideo, self->ob_capture)) + return sv_error(); + + self->ob_mustunlock = 0; + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef USE_GL +#include <gl.h> + +static PyObject * +svc_lrectwrite(captureobject *self, PyObject *args) +{ + Screencoord x1, x2, y1, y2; + + if (!PyArg_Parse(args, "(hhhh)", &x1, &x2, &y1, &y2)) + return NULL; + + lrectwrite(x1, x2, y1, y2, (unsigned long *) self->ob_capture); + + Py_INCREF(Py_None); + return Py_None; +} +#endif + +static PyObject * +svc_writefile(captureobject *self, PyObject *args) +{ + PyObject *file; + int size; + FILE* fp; + + if (!PyArg_Parse(args, "O", &file)) + return NULL; + + if (!PyFile_Check(file)) { + PyErr_SetString(SvError, "not a file object"); + return NULL; + } + + if (!(fp = PyFile_AsFile(file))) + return NULL; + + size = self->ob_info.width * self->ob_info.height; + + if (fwrite(self->ob_capture, sizeof(long), size, fp) != size) { + PyErr_SetString(SvError, "writing failed"); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +svc_FindVisibleRegion(captureobject *self, PyObject *args) +{ + void *visible; + int width; + + if (!PyArg_Parse(args, "")) + return NULL; + + if (svFindVisibleRegion(self->ob_svideo->ob_svideo, + self->ob_capture, &visible, + self->ob_info.width)) + return sv_error(); + + if (visible == NULL) { + PyErr_SetString(SvError, "data in wrong format"); + return NULL; + } + + return newcaptureobject(self->ob_svideo, visible, 0); +} + +static PyMethodDef capture_methods[] = { + {"YUVtoRGB", (PyCFunction)svc_YUVtoRGB, METH_OLDARGS}, + {"RGB8toRGB32", (PyCFunction)svc_RGB8toRGB32, METH_OLDARGS}, + {"InterleaveFields", (PyCFunction)svc_InterleaveFields, METH_OLDARGS}, + {"UnlockCaptureData", (PyCFunction)svc_UnlockCaptureData, METH_OLDARGS}, + {"FindVisibleRegion", (PyCFunction)svc_FindVisibleRegion, METH_OLDARGS}, + {"GetFields", (PyCFunction)svc_GetFields, METH_OLDARGS}, + {"YUVtoYUV422DC", (PyCFunction)svc_YUVtoYUV422DC, METH_OLDARGS}, + {"YUVtoYUV422DC_quarter",(PyCFunction)svc_YUVtoYUV422DC_quarter, METH_OLDARGS}, + {"YUVtoYUV422DC_sixteenth",(PyCFunction)svc_YUVtoYUV422DC_sixteenth, METH_OLDARGS}, +#ifdef USE_GL + {"lrectwrite", (PyCFunction)svc_lrectwrite, METH_OLDARGS}, +#endif + {"writefile", (PyCFunction)svc_writefile, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +static void +capture_dealloc(captureobject *self) +{ + if (self->ob_capture != NULL) { + if (self->ob_mustunlock) + (void)svUnlockCaptureData(self->ob_svideo->ob_svideo, + self->ob_capture); + self->ob_capture = NULL; + Py_DECREF(self->ob_svideo); + self->ob_svideo = NULL; + } + PyObject_Del(self); +} + +static PyObject * +capture_getattr(svobject *self, char *name) +{ + return Py_FindMethod(capture_methods, (PyObject *)self, name); +} + +PyTypeObject Capturetype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "sv.capture", /*tp_name*/ + sizeof(captureobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)capture_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)capture_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyObject * +newcaptureobject(svobject *self, void *ptr, int mustunlock) +{ + captureobject *p; + + p = PyObject_New(captureobject, &Capturetype); + if (p == NULL) + return NULL; + p->ob_svideo = self; + Py_INCREF(self); + p->ob_capture = ptr; + p->ob_mustunlock = mustunlock; + p->ob_info = self->ob_info; + return (PyObject *) p; +} + +static PyObject * +sv_GetCaptureData(svobject *self, PyObject *args) +{ + void *ptr; + long fieldID; + PyObject *res, *c; + + if (!PyArg_Parse(args, "")) + return NULL; + + if (svGetCaptureData(self->ob_svideo, &ptr, &fieldID)) + return sv_error(); + + if (ptr == NULL) { + PyErr_SetString(SvError, "no data available"); + return NULL; + } + + c = newcaptureobject(self, ptr, 1); + if (c == NULL) + return NULL; + res = Py_BuildValue("(Oi)", c, fieldID); + Py_DECREF(c); + return res; +} + +static PyObject * +sv_BindGLWindow(svobject *self, PyObject *args) +{ + long wid; + int mode; + + if (!PyArg_Parse(args, "(ii)", &wid, &mode)) + return NULL; + + if (svBindGLWindow(self->ob_svideo, wid, mode)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_EndContinuousCapture(svobject *self, PyObject *args) +{ + + if (!PyArg_Parse(args, "")) + return NULL; + + if (svEndContinuousCapture(self->ob_svideo)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_IsVideoDisplayed(svobject *self, PyObject *args) +{ + int v; + + if (!PyArg_Parse(args, "")) + return NULL; + + v = svIsVideoDisplayed(self->ob_svideo); + if (v == -1) + return sv_error(); + + return PyInt_FromLong((long) v); +} + +static PyObject * +sv_OutputOffset(svobject *self, PyObject *args) +{ + int x_offset; + int y_offset; + + if (!PyArg_Parse(args, "(ii)", &x_offset, &y_offset)) + return NULL; + + if (svOutputOffset(self->ob_svideo, x_offset, y_offset)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_PutFrame(svobject *self, PyObject *args) +{ + char *buffer; + + if (!PyArg_Parse(args, "s", &buffer)) + return NULL; + + if (svPutFrame(self->ob_svideo, buffer)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_QuerySize(svobject *self, PyObject *args) +{ + int w; + int h; + int rw; + int rh; + + if (!PyArg_Parse(args, "(ii)", &w, &h)) + return NULL; + + if (svQuerySize(self->ob_svideo, w, h, &rw, &rh)) + return sv_error(); + + return Py_BuildValue("(ii)", (long) rw, (long) rh); +} + +static PyObject * +sv_SetSize(svobject *self, PyObject *args) +{ + int w; + int h; + + if (!PyArg_Parse(args, "(ii)", &w, &h)) + return NULL; + + if (svSetSize(self->ob_svideo, w, h)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_SetStdDefaults(svobject *self, PyObject *args) +{ + + if (!PyArg_Parse(args, "")) + return NULL; + + if (svSetStdDefaults(self->ob_svideo)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_UseExclusive(svobject *self, PyObject *args) +{ + boolean onoff; + int mode; + + if (!PyArg_Parse(args, "(ii)", &onoff, &mode)) + return NULL; + + if (svUseExclusive(self->ob_svideo, onoff, mode)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_WindowOffset(svobject *self, PyObject *args) +{ + int x_offset; + int y_offset; + + if (!PyArg_Parse(args, "(ii)", &x_offset, &y_offset)) + return NULL; + + if (svWindowOffset(self->ob_svideo, x_offset, y_offset)) + return sv_error(); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +sv_CaptureBurst(svobject *self, PyObject *args) +{ + int bytes, i; + svCaptureInfo info; + void *bitvector = NULL; + PyObject *videodata = NULL; + PyObject *bitvecobj = NULL; + PyObject *res = NULL; + static PyObject *evenitem, *odditem; + + if (!PyArg_Parse(args, "(iiiii)", &info.format, + &info.width, &info.height, + &info.size, &info.samplingrate)) + return NULL; + + switch (info.format) { + case SV_RGB8_FRAMES: + bitvector = malloc(SV_BITVEC_SIZE(info.size)); + break; + case SV_YUV411_FRAMES_AND_BLANKING_BUFFER: + break; + default: + PyErr_SetString(SvError, "illegal format specified"); + return NULL; + } + + if (svQueryCaptureBufferSize(self->ob_svideo, &info, &bytes)) { + res = sv_error(); + goto finally; + } + + if (!(videodata = PyString_FromStringAndSize(NULL, bytes))) + goto finally; + + /* XXX -- need to do something about the bitvector */ + { + char* str = PyString_AsString(videodata); + if (!str) + goto finally; + + if (svCaptureBurst(self->ob_svideo, &info, str, bitvector)) { + res = sv_error(); + goto finally; + } + } + + if (bitvector) { + if (evenitem == NULL) { + if (!(evenitem = PyInt_FromLong(0))) + goto finally; + } + if (odditem == NULL) { + if (!(odditem = PyInt_FromLong(1))) + goto finally; + } + if (!(bitvecobj = PyTuple_New(2 * info.size))) + goto finally; + + for (i = 0; i < 2 * info.size; i++) { + int sts; + + if (SV_GET_FIELD(bitvector, i) == SV_EVEN_FIELD) { + Py_INCREF(evenitem); + sts = PyTuple_SetItem(bitvecobj, i, evenitem); + } else { + Py_INCREF(odditem); + sts = PyTuple_SetItem(bitvecobj, i, odditem); + } + if (sts < 0) + goto finally; + } + } else { + bitvecobj = Py_None; + Py_INCREF(Py_None); + } + + res = Py_BuildValue("((iiiii)OO)", info.format, + info.width, info.height, + info.size, info.samplingrate, + videodata, bitvecobj); + + finally: + if (bitvector) + free(bitvector); + + Py_XDECREF(videodata); + Py_XDECREF(bitvecobj); + return res; +} + +static PyObject * +sv_CaptureOneFrame(svobject *self, PyObject *args) +{ + svCaptureInfo info; + int format, width, height; + int bytes; + PyObject *videodata = NULL; + PyObject *res = NULL; + char *str; + + if (!PyArg_Parse(args, "(iii)", &format, &width, &height)) + return NULL; + + info.format = format; + info.width = width; + info.height = height; + info.size = 0; + info.samplingrate = 0; + if (svQueryCaptureBufferSize(self->ob_svideo, &info, &bytes)) + return sv_error(); + + if (!(videodata = PyString_FromStringAndSize(NULL, bytes))) + return NULL; + + str = PyString_AsString(videodata); + if (!str) + goto finally; + + if (svCaptureOneFrame(self->ob_svideo, format, &width, &height, str)) { + res = sv_error(); + goto finally; + } + + res = Py_BuildValue("(iiO)", width, height, videodata); + + finally: + Py_XDECREF(videodata); + return res; +} + +static PyObject * +sv_InitContinuousCapture(svobject *self, PyObject *args) +{ + svCaptureInfo info; + + if (!PyArg_Parse(args, "(iiiii)", &info.format, + &info.width, &info.height, + &info.size, &info.samplingrate)) + return NULL; + + if (svInitContinuousCapture(self->ob_svideo, &info)) + return sv_error(); + + self->ob_info = info; + + return Py_BuildValue("(iiiii)", info.format, info.width, info.height, + info.size, info.samplingrate); +} + +static PyObject * +sv_LoadMap(svobject *self, PyObject *args) +{ + PyObject *rgb; + PyObject *res = NULL; + rgb_tuple *mapp = NULL; + int maptype; + int i, j; /* indices */ + + if (!PyArg_Parse(args, "(iO)", &maptype, &rgb)) + return NULL; + + if (!PyList_Check(rgb) || PyList_Size(rgb) != 256) { + PyErr_BadArgument(); + return NULL; + } + + if (!(mapp = PyMem_NEW(rgb_tuple, 256))) + return PyErr_NoMemory(); + + for (i = 0; i < 256; i++) { + PyObject* v = PyList_GetItem(rgb, i); + if (!v) + goto finally; + + if (!PyTuple_Check(v) || PyTuple_Size(v) != 3) { + PyErr_BadArgument(); + goto finally; + } + for (j = 0; j < 3; j++) { + PyObject* cell = PyTuple_GetItem(v, j); + if (!cell) + goto finally; + + if (!PyInt_Check(cell)) { + PyErr_BadArgument(); + goto finally; + } + switch (j) { + case 0: mapp[i].red = PyInt_AsLong(cell); break; + case 1: mapp[i].blue = PyInt_AsLong(cell); break; + case 2: mapp[i].green = PyInt_AsLong(cell); break; + } + if (PyErr_Occurred()) + goto finally; + } + } + + if (svLoadMap(self->ob_svideo, maptype, mapp)) { + res = sv_error(); + goto finally; + } + + Py_INCREF(Py_None); + res = Py_None; + + finally: + PyMem_DEL(mapp); + return res; +} + +static PyObject * +sv_CloseVideo(svobject *self, PyObject *args) +{ + if (!PyArg_Parse(args, "")) + return NULL; + + if (svCloseVideo(self->ob_svideo)) + return sv_error(); + + self->ob_svideo = NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +doParams(svobject *self, PyObject *args, + int (*func)(SV_nodeP, long *, int), int modified) +{ + PyObject *list; + PyObject *res = NULL; + long *PVbuffer = NULL; + long length; + int i; + + if (!PyArg_Parse(args, "O", &list)) + return NULL; + + if (!PyList_Check(list)) { + PyErr_BadArgument(); + return NULL; + } + + if ((length = PyList_Size(list)) < 0) + return NULL; + + PVbuffer = PyMem_NEW(long, length); + if (PVbuffer == NULL) + return PyErr_NoMemory(); + + for (i = 0; i < length; i++) { + PyObject *v = PyList_GetItem(list, i); + if (!v) + goto finally; + + if (!PyInt_Check(v)) { + PyErr_BadArgument(); + goto finally; + } + PVbuffer[i] = PyInt_AsLong(v); + /* can't just test the return value, because what if the + value was -1?! + */ + if (PVbuffer[i] == -1 && PyErr_Occurred()) + goto finally; + } + + if ((*func)(self->ob_svideo, PVbuffer, length)) { + res = sv_error(); + goto finally; + } + + if (modified) { + for (i = 0; i < length; i++) { + PyObject* v = PyInt_FromLong(PVbuffer[i]); + if (!v || PyList_SetItem(list, i, v) < 0) + goto finally; + } + } + + Py_INCREF(Py_None); + res = Py_None; + + finally: + PyMem_DEL(PVbuffer); + return res; +} + +static PyObject * +sv_GetParam(PyObject *self, PyObject *args) +{ + return doParams(self, args, svGetParam, 1); +} + +static PyObject * +sv_GetParamRange(PyObject *self, PyObject *args) +{ + return doParams(self, args, svGetParamRange, 1); +} + +static PyObject * +sv_SetParam(PyObject *self, PyObject *args) +{ + return doParams(self, args, svSetParam, 0); +} + +static PyMethodDef svideo_methods[] = { + {"BindGLWindow", (PyCFunction)sv_BindGLWindow, METH_OLDARGS}, + {"EndContinuousCapture",(PyCFunction)sv_EndContinuousCapture, METH_OLDARGS}, + {"IsVideoDisplayed", (PyCFunction)sv_IsVideoDisplayed, METH_OLDARGS}, + {"OutputOffset", (PyCFunction)sv_OutputOffset, METH_OLDARGS}, + {"PutFrame", (PyCFunction)sv_PutFrame, METH_OLDARGS}, + {"QuerySize", (PyCFunction)sv_QuerySize, METH_OLDARGS}, + {"SetSize", (PyCFunction)sv_SetSize, METH_OLDARGS}, + {"SetStdDefaults", (PyCFunction)sv_SetStdDefaults, METH_OLDARGS}, + {"UseExclusive", (PyCFunction)sv_UseExclusive, METH_OLDARGS}, + {"WindowOffset", (PyCFunction)sv_WindowOffset, METH_OLDARGS}, + {"InitContinuousCapture",(PyCFunction)sv_InitContinuousCapture, METH_OLDARGS}, + {"CaptureBurst", (PyCFunction)sv_CaptureBurst, METH_OLDARGS}, + {"CaptureOneFrame", (PyCFunction)sv_CaptureOneFrame, METH_OLDARGS}, + {"GetCaptureData", (PyCFunction)sv_GetCaptureData, METH_OLDARGS}, + {"CloseVideo", (PyCFunction)sv_CloseVideo, METH_OLDARGS}, + {"LoadMap", (PyCFunction)sv_LoadMap, METH_OLDARGS}, + {"GetParam", (PyCFunction)sv_GetParam, METH_OLDARGS}, + {"GetParamRange", (PyCFunction)sv_GetParamRange, METH_OLDARGS}, + {"SetParam", (PyCFunction)sv_SetParam, METH_OLDARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +sv_conversion(PyObject *self, PyObject *args, void (*function)(), + int inputfactor, float factor) +{ + int invert, width, height, inputlength; + char *input, *str; + PyObject *output; + + if (!PyArg_Parse(args, "(is#ii)", &invert, + &input, &inputlength, &width, &height)) + return NULL; + + if (width * height * inputfactor > inputlength) { + PyErr_SetString(SvError, "input buffer not long enough"); + return NULL; + } + + if (!(output = PyString_FromStringAndSize(NULL, + (int)(width * height * factor)))) + return NULL; + + str = PyString_AsString(output); + if (!str) { + Py_DECREF(output); + return NULL; + } + (*function)(invert, input, str, width, height); + + return output; +} + +static PyObject * +sv_InterleaveFields(PyObject *self, PyObject *args) +{ + return sv_conversion(self, args, svInterleaveFields, 1, 1.0); +} + +static PyObject * +sv_RGB8toRGB32(PyObject *self, PyObject *args) +{ + return sv_conversion(self, args, svRGB8toRGB32, 1, (float) sizeof(long)); +} + +static PyObject * +sv_YUVtoRGB(PyObject *self, PyObject *args) +{ + return sv_conversion(self, args, svYUVtoRGB, 2, (float) sizeof(long)); +} + +static void +svideo_dealloc(svobject *self) +{ + if (self->ob_svideo != NULL) + (void) svCloseVideo(self->ob_svideo); + PyObject_Del(self); +} + +static PyObject * +svideo_getattr(svobject *self, char *name) +{ + return Py_FindMethod(svideo_methods, (PyObject *)self, name); +} + +PyTypeObject Svtype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "sv.sv", /*tp_name*/ + sizeof(svobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)svideo_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)svideo_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static PyObject * +newsvobject(SV_nodeP svp) +{ + svobject *p; + + p = PyObject_New(svobject, &Svtype); + if (p == NULL) + return NULL; + p->ob_svideo = svp; + p->ob_info.format = 0; + p->ob_info.size = 0; + p->ob_info.width = 0; + p->ob_info.height = 0; + p->ob_info.samplingrate = 0; + return (PyObject *) p; +} + +static PyObject * +sv_OpenVideo(PyObject *self, PyObject *args) +{ + SV_nodeP svp; + + if (!PyArg_Parse(args, "")) + return NULL; + + svp = svOpenVideo(); + if (svp == NULL) + return sv_error(); + + return newsvobject(svp); +} + +static PyMethodDef sv_methods[] = { + {"InterleaveFields", (PyCFunction)sv_InterleaveFields, METH_OLDARGS}, + {"RGB8toRGB32", (PyCFunction)sv_RGB8toRGB32, METH_OLDARGS}, + {"YUVtoRGB", (PyCFunction)sv_YUVtoRGB, METH_OLDARGS}, + {"OpenVideo", (PyCFunction)sv_OpenVideo, METH_OLDARGS}, + {NULL, NULL} /* Sentinel */ +}; + +void +initsv(void) +{ + PyObject *m, *d; + + m = Py_InitModule("sv", sv_methods); + if (m == NULL) + return; + d = PyModule_GetDict(m); + + SvError = PyErr_NewException("sv.error", NULL, NULL); + if (SvError == NULL || PyDict_SetItemString(d, "error", SvError) != 0) + return; +} diff --git a/sys/src/cmd/python/Modules/symtablemodule.c b/sys/src/cmd/python/Modules/symtablemodule.c new file mode 100644 index 000000000..c90d7650a --- /dev/null +++ b/sys/src/cmd/python/Modules/symtablemodule.c @@ -0,0 +1,84 @@ +#include "Python.h" + +#include "code.h" +#include "compile.h" +#include "Python-ast.h" +#include "symtable.h" + +static PyObject * +symtable_symtable(PyObject *self, PyObject *args) +{ + struct symtable *st; + PyObject *t; + + char *str; + char *filename; + char *startstr; + int start; + + if (!PyArg_ParseTuple(args, "sss:symtable", &str, &filename, + &startstr)) + return NULL; + if (strcmp(startstr, "exec") == 0) + start = Py_file_input; + else if (strcmp(startstr, "eval") == 0) + start = Py_eval_input; + else if (strcmp(startstr, "single") == 0) + start = Py_single_input; + else { + PyErr_SetString(PyExc_ValueError, + "symtable() arg 3 must be 'exec' or 'eval' or 'single'"); + return NULL; + } + st = Py_SymtableString(str, filename, start); + if (st == NULL) + return NULL; + t = st->st_symbols; + Py_INCREF(t); + PyMem_Free((void *)st->st_future); + PySymtable_Free(st); + return t; +} + +static PyMethodDef symtable_methods[] = { + {"symtable", symtable_symtable, METH_VARARGS, + PyDoc_STR("Return symbol and scope dictionaries" + " used internally by compiler.")}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +init_symtable(void) +{ + PyObject *m; + + m = Py_InitModule("_symtable", symtable_methods); + if (m == NULL) + return; + PyModule_AddIntConstant(m, "USE", USE); + PyModule_AddIntConstant(m, "DEF_GLOBAL", DEF_GLOBAL); + PyModule_AddIntConstant(m, "DEF_LOCAL", DEF_LOCAL); + PyModule_AddIntConstant(m, "DEF_PARAM", DEF_PARAM); + PyModule_AddIntConstant(m, "DEF_STAR", DEF_STAR); + PyModule_AddIntConstant(m, "DEF_DOUBLESTAR", DEF_DOUBLESTAR); + PyModule_AddIntConstant(m, "DEF_INTUPLE", DEF_INTUPLE); + PyModule_AddIntConstant(m, "DEF_FREE", DEF_FREE); + PyModule_AddIntConstant(m, "DEF_FREE_GLOBAL", DEF_FREE_GLOBAL); + PyModule_AddIntConstant(m, "DEF_FREE_CLASS", DEF_FREE_CLASS); + PyModule_AddIntConstant(m, "DEF_IMPORT", DEF_IMPORT); + PyModule_AddIntConstant(m, "DEF_BOUND", DEF_BOUND); + + PyModule_AddIntConstant(m, "TYPE_FUNCTION", FunctionBlock); + PyModule_AddIntConstant(m, "TYPE_CLASS", ClassBlock); + PyModule_AddIntConstant(m, "TYPE_MODULE", ModuleBlock); + + PyModule_AddIntConstant(m, "OPT_IMPORT_STAR", OPT_IMPORT_STAR); + PyModule_AddIntConstant(m, "OPT_EXEC", OPT_EXEC); + PyModule_AddIntConstant(m, "OPT_BARE_EXEC", OPT_BARE_EXEC); + + PyModule_AddIntConstant(m, "LOCAL", LOCAL); + PyModule_AddIntConstant(m, "GLOBAL_EXPLICIT", GLOBAL_EXPLICIT); + PyModule_AddIntConstant(m, "GLOBAL_IMPLICIT", GLOBAL_IMPLICIT); + PyModule_AddIntConstant(m, "FREE", FREE); + PyModule_AddIntConstant(m, "CELL", CELL); +} diff --git a/sys/src/cmd/python/Modules/syslogmodule.c b/sys/src/cmd/python/Modules/syslogmodule.c new file mode 100644 index 000000000..4a7791694 --- /dev/null +++ b/sys/src/cmd/python/Modules/syslogmodule.c @@ -0,0 +1,223 @@ +/*********************************************************** +Copyright 1994 by Lance Ellinghouse, +Cathedral City, California Republic, United States of America. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Lance Ellinghouse +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +LANCE ELLINGHOUSE DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL LANCE ELLINGHOUSE BE LIABLE FOR ANY SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/****************************************************************** + +Revision history: + +1998/04/28 (Sean Reifschneider) + - When facility not specified to syslog() method, use default from openlog() + (This is how it was claimed to work in the documentation) + - Potential resource leak of o_ident, now cleaned up in closelog() + - Minor comment accuracy fix. + +95/06/29 (Steve Clift) + - Changed arg parsing to use PyArg_ParseTuple. + - Added PyErr_Clear() call(s) where needed. + - Fix core dumps if user message contains format specifiers. + - Change openlog arg defaults to match normal syslog behavior. + - Plug memory leak in openlog(). + - Fix setlogmask() to return previous mask value. + +******************************************************************/ + +/* syslog module */ + +#include "Python.h" + +#include <syslog.h> + +/* only one instance, only one syslog, so globals should be ok */ +static PyObject *S_ident_o = NULL; /* identifier, held by openlog() */ + + +static PyObject * +syslog_openlog(PyObject * self, PyObject * args) +{ + long logopt = 0; + long facility = LOG_USER; + PyObject *new_S_ident_o; + + if (!PyArg_ParseTuple(args, + "S|ll;ident string [, logoption [, facility]]", + &new_S_ident_o, &logopt, &facility)) + return NULL; + + /* This is needed because openlog() does NOT make a copy + * and syslog() later uses it.. cannot trash it. + */ + Py_XDECREF(S_ident_o); + S_ident_o = new_S_ident_o; + Py_INCREF(S_ident_o); + + openlog(PyString_AsString(S_ident_o), logopt, facility); + + Py_INCREF(Py_None); + return Py_None; +} + + +static PyObject * +syslog_syslog(PyObject * self, PyObject * args) +{ + char *message; + int priority = LOG_INFO; + + if (!PyArg_ParseTuple(args, "is;[priority,] message string", + &priority, &message)) { + PyErr_Clear(); + if (!PyArg_ParseTuple(args, "s;[priority,] message string", + &message)) + return NULL; + } + + syslog(priority, "%s", message); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +syslog_closelog(PyObject *self, PyObject *unused) +{ + closelog(); + Py_XDECREF(S_ident_o); + S_ident_o = NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +syslog_setlogmask(PyObject *self, PyObject *args) +{ + long maskpri, omaskpri; + + if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri)) + return NULL; + omaskpri = setlogmask(maskpri); + return PyInt_FromLong(omaskpri); +} + +static PyObject * +syslog_log_mask(PyObject *self, PyObject *args) +{ + long mask; + long pri; + if (!PyArg_ParseTuple(args, "l:LOG_MASK", &pri)) + return NULL; + mask = LOG_MASK(pri); + return PyInt_FromLong(mask); +} + +static PyObject * +syslog_log_upto(PyObject *self, PyObject *args) +{ + long mask; + long pri; + if (!PyArg_ParseTuple(args, "l:LOG_UPTO", &pri)) + return NULL; + mask = LOG_UPTO(pri); + return PyInt_FromLong(mask); +} + +/* List of functions defined in the module */ + +static PyMethodDef syslog_methods[] = { + {"openlog", syslog_openlog, METH_VARARGS}, + {"closelog", syslog_closelog, METH_NOARGS}, + {"syslog", syslog_syslog, METH_VARARGS}, + {"setlogmask", syslog_setlogmask, METH_VARARGS}, + {"LOG_MASK", syslog_log_mask, METH_VARARGS}, + {"LOG_UPTO", syslog_log_upto, METH_VARARGS}, + {NULL, NULL, 0} +}; + +/* Initialization function for the module */ + +PyMODINIT_FUNC +initsyslog(void) +{ + PyObject *m; + + /* Create the module and add the functions */ + m = Py_InitModule("syslog", syslog_methods); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + + /* Priorities */ + PyModule_AddIntConstant(m, "LOG_EMERG", LOG_EMERG); + PyModule_AddIntConstant(m, "LOG_ALERT", LOG_ALERT); + PyModule_AddIntConstant(m, "LOG_CRIT", LOG_CRIT); + PyModule_AddIntConstant(m, "LOG_ERR", LOG_ERR); + PyModule_AddIntConstant(m, "LOG_WARNING", LOG_WARNING); + PyModule_AddIntConstant(m, "LOG_NOTICE", LOG_NOTICE); + PyModule_AddIntConstant(m, "LOG_INFO", LOG_INFO); + PyModule_AddIntConstant(m, "LOG_DEBUG", LOG_DEBUG); + + /* openlog() option flags */ + PyModule_AddIntConstant(m, "LOG_PID", LOG_PID); + PyModule_AddIntConstant(m, "LOG_CONS", LOG_CONS); + PyModule_AddIntConstant(m, "LOG_NDELAY", LOG_NDELAY); +#ifdef LOG_NOWAIT + PyModule_AddIntConstant(m, "LOG_NOWAIT", LOG_NOWAIT); +#endif +#ifdef LOG_PERROR + PyModule_AddIntConstant(m, "LOG_PERROR", LOG_PERROR); +#endif + + /* Facilities */ + PyModule_AddIntConstant(m, "LOG_KERN", LOG_KERN); + PyModule_AddIntConstant(m, "LOG_USER", LOG_USER); + PyModule_AddIntConstant(m, "LOG_MAIL", LOG_MAIL); + PyModule_AddIntConstant(m, "LOG_DAEMON", LOG_DAEMON); + PyModule_AddIntConstant(m, "LOG_AUTH", LOG_AUTH); + PyModule_AddIntConstant(m, "LOG_LPR", LOG_LPR); + PyModule_AddIntConstant(m, "LOG_LOCAL0", LOG_LOCAL0); + PyModule_AddIntConstant(m, "LOG_LOCAL1", LOG_LOCAL1); + PyModule_AddIntConstant(m, "LOG_LOCAL2", LOG_LOCAL2); + PyModule_AddIntConstant(m, "LOG_LOCAL3", LOG_LOCAL3); + PyModule_AddIntConstant(m, "LOG_LOCAL4", LOG_LOCAL4); + PyModule_AddIntConstant(m, "LOG_LOCAL5", LOG_LOCAL5); + PyModule_AddIntConstant(m, "LOG_LOCAL6", LOG_LOCAL6); + PyModule_AddIntConstant(m, "LOG_LOCAL7", LOG_LOCAL7); + +#ifndef LOG_SYSLOG +#define LOG_SYSLOG LOG_DAEMON +#endif +#ifndef LOG_NEWS +#define LOG_NEWS LOG_MAIL +#endif +#ifndef LOG_UUCP +#define LOG_UUCP LOG_MAIL +#endif +#ifndef LOG_CRON +#define LOG_CRON LOG_DAEMON +#endif + + PyModule_AddIntConstant(m, "LOG_SYSLOG", LOG_SYSLOG); + PyModule_AddIntConstant(m, "LOG_CRON", LOG_CRON); + PyModule_AddIntConstant(m, "LOG_UUCP", LOG_UUCP); + PyModule_AddIntConstant(m, "LOG_NEWS", LOG_NEWS); +} diff --git a/sys/src/cmd/python/Modules/termios.c b/sys/src/cmd/python/Modules/termios.c new file mode 100644 index 000000000..c53566c12 --- /dev/null +++ b/sys/src/cmd/python/Modules/termios.c @@ -0,0 +1,926 @@ +/* termiosmodule.c -- POSIX terminal I/O module implementation. */ + +#include "Python.h" + +#define PyInit_termios inittermios + +/* Apparently, on SGI, termios.h won't define CTRL if _XOPEN_SOURCE + is defined, so we define it here. */ +#if defined(__sgi) +#define CTRL(c) ((c)&037) +#endif + +#include <termios.h> +#ifdef __osf__ +/* On OSF, sys/ioctl.h requires that struct termio already be defined, + * so this needs to be included first on that platform. */ +#include <termio.h> +#endif +#include <sys/ioctl.h> + +/* HP-UX requires that this be included to pick up MDCD, MCTS, MDSR, + * MDTR, MRI, and MRTS (appearantly used internally by some things + * defined as macros; these are not used here directly). + */ +#ifdef HAVE_SYS_MODEM_H +#include <sys/modem.h> +#endif +/* HP-UX requires that this be included to pick up TIOCGPGRP and friends */ +#ifdef HAVE_SYS_BSDTTY_H +#include <sys/bsdtty.h> +#endif + +PyDoc_STRVAR(termios__doc__, +"This module provides an interface to the Posix calls for tty I/O control.\n\ +For a complete description of these calls, see the Posix or Unix manual\n\ +pages. It is only available for those Unix versions that support Posix\n\ +termios style tty I/O control.\n\ +\n\ +All functions in this module take a file descriptor fd as their first\n\ +argument. This can be an integer file descriptor, such as returned by\n\ +sys.stdin.fileno(), or a file object, such as sys.stdin itself."); + +static PyObject *TermiosError; + +static int fdconv(PyObject* obj, void* p) +{ + int fd; + + fd = PyObject_AsFileDescriptor(obj); + if (fd >= 0) { + *(int*)p = fd; + return 1; + } + return 0; +} + +PyDoc_STRVAR(termios_tcgetattr__doc__, +"tcgetattr(fd) -> list_of_attrs\n\ +\n\ +Get the tty attributes for file descriptor fd, as follows:\n\ +[iflag, oflag, cflag, lflag, ispeed, ospeed, cc] where cc is a list\n\ +of the tty special characters (each a string of length 1, except the items\n\ +with indices VMIN and VTIME, which are integers when these fields are\n\ +defined). The interpretation of the flags and the speeds as well as the\n\ +indexing in the cc array must be done using the symbolic constants defined\n\ +in this module."); + +static PyObject * +termios_tcgetattr(PyObject *self, PyObject *args) +{ + int fd; + struct termios mode; + PyObject *cc; + speed_t ispeed, ospeed; + PyObject *v; + int i; + char ch; + + if (!PyArg_ParseTuple(args, "O&:tcgetattr", + fdconv, (void*)&fd)) + return NULL; + + if (tcgetattr(fd, &mode) == -1) + return PyErr_SetFromErrno(TermiosError); + + ispeed = cfgetispeed(&mode); + ospeed = cfgetospeed(&mode); + + cc = PyList_New(NCCS); + if (cc == NULL) + return NULL; + for (i = 0; i < NCCS; i++) { + ch = (char)mode.c_cc[i]; + v = PyString_FromStringAndSize(&ch, 1); + if (v == NULL) + goto err; + PyList_SetItem(cc, i, v); + } + + /* Convert the MIN and TIME slots to integer. On some systems, the + MIN and TIME slots are the same as the EOF and EOL slots. So we + only do this in noncanonical input mode. */ + if ((mode.c_lflag & ICANON) == 0) { + v = PyInt_FromLong((long)mode.c_cc[VMIN]); + if (v == NULL) + goto err; + PyList_SetItem(cc, VMIN, v); + v = PyInt_FromLong((long)mode.c_cc[VTIME]); + if (v == NULL) + goto err; + PyList_SetItem(cc, VTIME, v); + } + + if (!(v = PyList_New(7))) + goto err; + + PyList_SetItem(v, 0, PyInt_FromLong((long)mode.c_iflag)); + PyList_SetItem(v, 1, PyInt_FromLong((long)mode.c_oflag)); + PyList_SetItem(v, 2, PyInt_FromLong((long)mode.c_cflag)); + PyList_SetItem(v, 3, PyInt_FromLong((long)mode.c_lflag)); + PyList_SetItem(v, 4, PyInt_FromLong((long)ispeed)); + PyList_SetItem(v, 5, PyInt_FromLong((long)ospeed)); + PyList_SetItem(v, 6, cc); + if (PyErr_Occurred()){ + Py_DECREF(v); + goto err; + } + return v; + err: + Py_DECREF(cc); + return NULL; +} + +PyDoc_STRVAR(termios_tcsetattr__doc__, +"tcsetattr(fd, when, attributes) -> None\n\ +\n\ +Set the tty attributes for file descriptor fd.\n\ +The attributes to be set are taken from the attributes argument, which\n\ +is a list like the one returned by tcgetattr(). The when argument\n\ +determines when the attributes are changed: termios.TCSANOW to\n\ +change immediately, termios.TCSADRAIN to change after transmitting all\n\ +queued output, or termios.TCSAFLUSH to change after transmitting all\n\ +queued output and discarding all queued input. "); + +static PyObject * +termios_tcsetattr(PyObject *self, PyObject *args) +{ + int fd, when; + struct termios mode; + speed_t ispeed, ospeed; + PyObject *term, *cc, *v; + int i; + + if (!PyArg_ParseTuple(args, "O&iO:tcsetattr", + fdconv, &fd, &when, &term)) + return NULL; + if (!PyList_Check(term) || PyList_Size(term) != 7) { + PyErr_SetString(PyExc_TypeError, + "tcsetattr, arg 3: must be 7 element list"); + return NULL; + } + + /* Get the old mode, in case there are any hidden fields... */ + if (tcgetattr(fd, &mode) == -1) + return PyErr_SetFromErrno(TermiosError); + mode.c_iflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 0)); + mode.c_oflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 1)); + mode.c_cflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 2)); + mode.c_lflag = (tcflag_t) PyInt_AsLong(PyList_GetItem(term, 3)); + ispeed = (speed_t) PyInt_AsLong(PyList_GetItem(term, 4)); + ospeed = (speed_t) PyInt_AsLong(PyList_GetItem(term, 5)); + cc = PyList_GetItem(term, 6); + if (PyErr_Occurred()) + return NULL; + + if (!PyList_Check(cc) || PyList_Size(cc) != NCCS) { + PyErr_Format(PyExc_TypeError, + "tcsetattr: attributes[6] must be %d element list", + NCCS); + return NULL; + } + + for (i = 0; i < NCCS; i++) { + v = PyList_GetItem(cc, i); + + if (PyString_Check(v) && PyString_Size(v) == 1) + mode.c_cc[i] = (cc_t) * PyString_AsString(v); + else if (PyInt_Check(v)) + mode.c_cc[i] = (cc_t) PyInt_AsLong(v); + else { + PyErr_SetString(PyExc_TypeError, + "tcsetattr: elements of attributes must be characters or integers"); + return NULL; + } + } + + if (cfsetispeed(&mode, (speed_t) ispeed) == -1) + return PyErr_SetFromErrno(TermiosError); + if (cfsetospeed(&mode, (speed_t) ospeed) == -1) + return PyErr_SetFromErrno(TermiosError); + if (tcsetattr(fd, when, &mode) == -1) + return PyErr_SetFromErrno(TermiosError); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(termios_tcsendbreak__doc__, +"tcsendbreak(fd, duration) -> None\n\ +\n\ +Send a break on file descriptor fd.\n\ +A zero duration sends a break for 0.25-0.5 seconds; a nonzero duration\n\ +has a system dependent meaning."); + +static PyObject * +termios_tcsendbreak(PyObject *self, PyObject *args) +{ + int fd, duration; + + if (!PyArg_ParseTuple(args, "O&i:tcsendbreak", + fdconv, &fd, &duration)) + return NULL; + if (tcsendbreak(fd, duration) == -1) + return PyErr_SetFromErrno(TermiosError); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(termios_tcdrain__doc__, +"tcdrain(fd) -> None\n\ +\n\ +Wait until all output written to file descriptor fd has been transmitted."); + +static PyObject * +termios_tcdrain(PyObject *self, PyObject *args) +{ + int fd; + + if (!PyArg_ParseTuple(args, "O&:tcdrain", + fdconv, &fd)) + return NULL; + if (tcdrain(fd) == -1) + return PyErr_SetFromErrno(TermiosError); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(termios_tcflush__doc__, +"tcflush(fd, queue) -> None\n\ +\n\ +Discard queued data on file descriptor fd.\n\ +The queue selector specifies which queue: termios.TCIFLUSH for the input\n\ +queue, termios.TCOFLUSH for the output queue, or termios.TCIOFLUSH for\n\ +both queues. "); + +static PyObject * +termios_tcflush(PyObject *self, PyObject *args) +{ + int fd, queue; + + if (!PyArg_ParseTuple(args, "O&i:tcflush", + fdconv, &fd, &queue)) + return NULL; + if (tcflush(fd, queue) == -1) + return PyErr_SetFromErrno(TermiosError); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(termios_tcflow__doc__, +"tcflow(fd, action) -> None\n\ +\n\ +Suspend or resume input or output on file descriptor fd.\n\ +The action argument can be termios.TCOOFF to suspend output,\n\ +termios.TCOON to restart output, termios.TCIOFF to suspend input,\n\ +or termios.TCION to restart input."); + +static PyObject * +termios_tcflow(PyObject *self, PyObject *args) +{ + int fd, action; + + if (!PyArg_ParseTuple(args, "O&i:tcflow", + fdconv, &fd, &action)) + return NULL; + if (tcflow(fd, action) == -1) + return PyErr_SetFromErrno(TermiosError); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef termios_methods[] = +{ + {"tcgetattr", termios_tcgetattr, + METH_VARARGS, termios_tcgetattr__doc__}, + {"tcsetattr", termios_tcsetattr, + METH_VARARGS, termios_tcsetattr__doc__}, + {"tcsendbreak", termios_tcsendbreak, + METH_VARARGS, termios_tcsendbreak__doc__}, + {"tcdrain", termios_tcdrain, + METH_VARARGS, termios_tcdrain__doc__}, + {"tcflush", termios_tcflush, + METH_VARARGS, termios_tcflush__doc__}, + {"tcflow", termios_tcflow, + METH_VARARGS, termios_tcflow__doc__}, + {NULL, NULL} +}; + + +#if defined(VSWTCH) && !defined(VSWTC) +#define VSWTC VSWTCH +#endif + +#if defined(VSWTC) && !defined(VSWTCH) +#define VSWTCH VSWTC +#endif + +static struct constant { + char *name; + long value; +} termios_constants[] = { + /* cfgetospeed(), cfsetospeed() constants */ + {"B0", B0}, + {"B50", B50}, + {"B75", B75}, + {"B110", B110}, + {"B134", B134}, + {"B150", B150}, + {"B200", B200}, + {"B300", B300}, + {"B600", B600}, + {"B1200", B1200}, + {"B1800", B1800}, + {"B2400", B2400}, + {"B4800", B4800}, + {"B9600", B9600}, + {"B19200", B19200}, + {"B38400", B38400}, +#ifdef B57600 + {"B57600", B57600}, +#endif +#ifdef B115200 + {"B115200", B115200}, +#endif +#ifdef B230400 + {"B230400", B230400}, +#endif +#ifdef CBAUDEX + {"CBAUDEX", CBAUDEX}, +#endif + + /* tcsetattr() constants */ + {"TCSANOW", TCSANOW}, + {"TCSADRAIN", TCSADRAIN}, + {"TCSAFLUSH", TCSAFLUSH}, + + /* tcflush() constants */ + {"TCIFLUSH", TCIFLUSH}, + {"TCOFLUSH", TCOFLUSH}, + {"TCIOFLUSH", TCIOFLUSH}, + + /* tcflow() constants */ + {"TCOOFF", TCOOFF}, + {"TCOON", TCOON}, + {"TCIOFF", TCIOFF}, + {"TCION", TCION}, + + /* struct termios.c_iflag constants */ + {"IGNBRK", IGNBRK}, + {"BRKINT", BRKINT}, + {"IGNPAR", IGNPAR}, + {"PARMRK", PARMRK}, + {"INPCK", INPCK}, + {"ISTRIP", ISTRIP}, + {"INLCR", INLCR}, + {"IGNCR", IGNCR}, + {"ICRNL", ICRNL}, +#ifdef IUCLC + {"IUCLC", IUCLC}, +#endif + {"IXON", IXON}, + {"IXANY", IXANY}, + {"IXOFF", IXOFF}, +#ifdef IMAXBEL + {"IMAXBEL", IMAXBEL}, +#endif + + /* struct termios.c_oflag constants */ + {"OPOST", OPOST}, +#ifdef OLCUC + {"OLCUC", OLCUC}, +#endif +#ifdef ONLCR + {"ONLCR", ONLCR}, +#endif +#ifdef OCRNL + {"OCRNL", OCRNL}, +#endif +#ifdef ONOCR + {"ONOCR", ONOCR}, +#endif +#ifdef ONLRET + {"ONLRET", ONLRET}, +#endif +#ifdef OFILL + {"OFILL", OFILL}, +#endif +#ifdef OFDEL + {"OFDEL", OFDEL}, +#endif +#ifdef NLDLY + {"NLDLY", NLDLY}, +#endif +#ifdef CRDLY + {"CRDLY", CRDLY}, +#endif +#ifdef TABDLY + {"TABDLY", TABDLY}, +#endif +#ifdef BSDLY + {"BSDLY", BSDLY}, +#endif +#ifdef VTDLY + {"VTDLY", VTDLY}, +#endif +#ifdef FFDLY + {"FFDLY", FFDLY}, +#endif + + /* struct termios.c_oflag-related values (delay mask) */ +#ifdef NL0 + {"NL0", NL0}, +#endif +#ifdef NL1 + {"NL1", NL1}, +#endif +#ifdef CR0 + {"CR0", CR0}, +#endif +#ifdef CR1 + {"CR1", CR1}, +#endif +#ifdef CR2 + {"CR2", CR2}, +#endif +#ifdef CR3 + {"CR3", CR3}, +#endif +#ifdef TAB0 + {"TAB0", TAB0}, +#endif +#ifdef TAB1 + {"TAB1", TAB1}, +#endif +#ifdef TAB2 + {"TAB2", TAB2}, +#endif +#ifdef TAB3 + {"TAB3", TAB3}, +#endif +#ifdef XTABS + {"XTABS", XTABS}, +#endif +#ifdef BS0 + {"BS0", BS0}, +#endif +#ifdef BS1 + {"BS1", BS1}, +#endif +#ifdef VT0 + {"VT0", VT0}, +#endif +#ifdef VT1 + {"VT1", VT1}, +#endif +#ifdef FF0 + {"FF0", FF0}, +#endif +#ifdef FF1 + {"FF1", FF1}, +#endif + + /* struct termios.c_cflag constants */ + {"CSIZE", CSIZE}, + {"CSTOPB", CSTOPB}, + {"CREAD", CREAD}, + {"PARENB", PARENB}, + {"PARODD", PARODD}, + {"HUPCL", HUPCL}, + {"CLOCAL", CLOCAL}, +#ifdef CIBAUD + {"CIBAUD", CIBAUD}, +#endif +#ifdef CRTSCTS + {"CRTSCTS", (long)CRTSCTS}, +#endif + + /* struct termios.c_cflag-related values (character size) */ + {"CS5", CS5}, + {"CS6", CS6}, + {"CS7", CS7}, + {"CS8", CS8}, + + /* struct termios.c_lflag constants */ + {"ISIG", ISIG}, + {"ICANON", ICANON}, +#ifdef XCASE + {"XCASE", XCASE}, +#endif + {"ECHO", ECHO}, + {"ECHOE", ECHOE}, + {"ECHOK", ECHOK}, + {"ECHONL", ECHONL}, +#ifdef ECHOCTL + {"ECHOCTL", ECHOCTL}, +#endif +#ifdef ECHOPRT + {"ECHOPRT", ECHOPRT}, +#endif +#ifdef ECHOKE + {"ECHOKE", ECHOKE}, +#endif +#ifdef FLUSHO + {"FLUSHO", FLUSHO}, +#endif + {"NOFLSH", NOFLSH}, + {"TOSTOP", TOSTOP}, +#ifdef PENDIN + {"PENDIN", PENDIN}, +#endif + {"IEXTEN", IEXTEN}, + + /* indexes into the control chars array returned by tcgetattr() */ + {"VINTR", VINTR}, + {"VQUIT", VQUIT}, + {"VERASE", VERASE}, + {"VKILL", VKILL}, + {"VEOF", VEOF}, + {"VTIME", VTIME}, + {"VMIN", VMIN}, +#ifdef VSWTC + /* The #defines above ensure that if either is defined, both are, + * but both may be omitted by the system headers. ;-( */ + {"VSWTC", VSWTC}, + {"VSWTCH", VSWTCH}, +#endif + {"VSTART", VSTART}, + {"VSTOP", VSTOP}, + {"VSUSP", VSUSP}, + {"VEOL", VEOL}, +#ifdef VREPRINT + {"VREPRINT", VREPRINT}, +#endif +#ifdef VDISCARD + {"VDISCARD", VDISCARD}, +#endif +#ifdef VWERASE + {"VWERASE", VWERASE}, +#endif +#ifdef VLNEXT + {"VLNEXT", VLNEXT}, +#endif +#ifdef VEOL2 + {"VEOL2", VEOL2}, +#endif + + +#ifdef B460800 + {"B460800", B460800}, +#endif +#ifdef CBAUD + {"CBAUD", CBAUD}, +#endif +#ifdef CDEL + {"CDEL", CDEL}, +#endif +#ifdef CDSUSP + {"CDSUSP", CDSUSP}, +#endif +#ifdef CEOF + {"CEOF", CEOF}, +#endif +#ifdef CEOL + {"CEOL", CEOL}, +#endif +#ifdef CEOL2 + {"CEOL2", CEOL2}, +#endif +#ifdef CEOT + {"CEOT", CEOT}, +#endif +#ifdef CERASE + {"CERASE", CERASE}, +#endif +#ifdef CESC + {"CESC", CESC}, +#endif +#ifdef CFLUSH + {"CFLUSH", CFLUSH}, +#endif +#ifdef CINTR + {"CINTR", CINTR}, +#endif +#ifdef CKILL + {"CKILL", CKILL}, +#endif +#ifdef CLNEXT + {"CLNEXT", CLNEXT}, +#endif +#ifdef CNUL + {"CNUL", CNUL}, +#endif +#ifdef COMMON + {"COMMON", COMMON}, +#endif +#ifdef CQUIT + {"CQUIT", CQUIT}, +#endif +#ifdef CRPRNT + {"CRPRNT", CRPRNT}, +#endif +#ifdef CSTART + {"CSTART", CSTART}, +#endif +#ifdef CSTOP + {"CSTOP", CSTOP}, +#endif +#ifdef CSUSP + {"CSUSP", CSUSP}, +#endif +#ifdef CSWTCH + {"CSWTCH", CSWTCH}, +#endif +#ifdef CWERASE + {"CWERASE", CWERASE}, +#endif +#ifdef EXTA + {"EXTA", EXTA}, +#endif +#ifdef EXTB + {"EXTB", EXTB}, +#endif +#ifdef FIOASYNC + {"FIOASYNC", FIOASYNC}, +#endif +#ifdef FIOCLEX + {"FIOCLEX", FIOCLEX}, +#endif +#ifdef FIONBIO + {"FIONBIO", FIONBIO}, +#endif +#ifdef FIONCLEX + {"FIONCLEX", FIONCLEX}, +#endif +#ifdef FIONREAD + {"FIONREAD", FIONREAD}, +#endif +#ifdef IBSHIFT + {"IBSHIFT", IBSHIFT}, +#endif +#ifdef INIT_C_CC + {"INIT_C_CC", INIT_C_CC}, +#endif +#ifdef IOCSIZE_MASK + {"IOCSIZE_MASK", IOCSIZE_MASK}, +#endif +#ifdef IOCSIZE_SHIFT + {"IOCSIZE_SHIFT", IOCSIZE_SHIFT}, +#endif +#ifdef NCC + {"NCC", NCC}, +#endif +#ifdef NCCS + {"NCCS", NCCS}, +#endif +#ifdef NSWTCH + {"NSWTCH", NSWTCH}, +#endif +#ifdef N_MOUSE + {"N_MOUSE", N_MOUSE}, +#endif +#ifdef N_PPP + {"N_PPP", N_PPP}, +#endif +#ifdef N_SLIP + {"N_SLIP", N_SLIP}, +#endif +#ifdef N_STRIP + {"N_STRIP", N_STRIP}, +#endif +#ifdef N_TTY + {"N_TTY", N_TTY}, +#endif +#ifdef TCFLSH + {"TCFLSH", TCFLSH}, +#endif +#ifdef TCGETA + {"TCGETA", TCGETA}, +#endif +#ifdef TCGETS + {"TCGETS", TCGETS}, +#endif +#ifdef TCSBRK + {"TCSBRK", TCSBRK}, +#endif +#ifdef TCSBRKP + {"TCSBRKP", TCSBRKP}, +#endif +#ifdef TCSETA + {"TCSETA", TCSETA}, +#endif +#ifdef TCSETAF + {"TCSETAF", TCSETAF}, +#endif +#ifdef TCSETAW + {"TCSETAW", TCSETAW}, +#endif +#ifdef TCSETS + {"TCSETS", TCSETS}, +#endif +#ifdef TCSETSF + {"TCSETSF", TCSETSF}, +#endif +#ifdef TCSETSW + {"TCSETSW", TCSETSW}, +#endif +#ifdef TCXONC + {"TCXONC", TCXONC}, +#endif +#ifdef TIOCCONS + {"TIOCCONS", TIOCCONS}, +#endif +#ifdef TIOCEXCL + {"TIOCEXCL", TIOCEXCL}, +#endif +#ifdef TIOCGETD + {"TIOCGETD", TIOCGETD}, +#endif +#ifdef TIOCGICOUNT + {"TIOCGICOUNT", TIOCGICOUNT}, +#endif +#ifdef TIOCGLCKTRMIOS + {"TIOCGLCKTRMIOS", TIOCGLCKTRMIOS}, +#endif +#ifdef TIOCGPGRP + {"TIOCGPGRP", TIOCGPGRP}, +#endif +#ifdef TIOCGSERIAL + {"TIOCGSERIAL", TIOCGSERIAL}, +#endif +#ifdef TIOCGSOFTCAR + {"TIOCGSOFTCAR", TIOCGSOFTCAR}, +#endif +#ifdef TIOCGWINSZ + {"TIOCGWINSZ", TIOCGWINSZ}, +#endif +#ifdef TIOCINQ + {"TIOCINQ", TIOCINQ}, +#endif +#ifdef TIOCLINUX + {"TIOCLINUX", TIOCLINUX}, +#endif +#ifdef TIOCMBIC + {"TIOCMBIC", TIOCMBIC}, +#endif +#ifdef TIOCMBIS + {"TIOCMBIS", TIOCMBIS}, +#endif +#ifdef TIOCMGET + {"TIOCMGET", TIOCMGET}, +#endif +#ifdef TIOCMIWAIT + {"TIOCMIWAIT", TIOCMIWAIT}, +#endif +#ifdef TIOCMSET + {"TIOCMSET", TIOCMSET}, +#endif +#ifdef TIOCM_CAR + {"TIOCM_CAR", TIOCM_CAR}, +#endif +#ifdef TIOCM_CD + {"TIOCM_CD", TIOCM_CD}, +#endif +#ifdef TIOCM_CTS + {"TIOCM_CTS", TIOCM_CTS}, +#endif +#ifdef TIOCM_DSR + {"TIOCM_DSR", TIOCM_DSR}, +#endif +#ifdef TIOCM_DTR + {"TIOCM_DTR", TIOCM_DTR}, +#endif +#ifdef TIOCM_LE + {"TIOCM_LE", TIOCM_LE}, +#endif +#ifdef TIOCM_RI + {"TIOCM_RI", TIOCM_RI}, +#endif +#ifdef TIOCM_RNG + {"TIOCM_RNG", TIOCM_RNG}, +#endif +#ifdef TIOCM_RTS + {"TIOCM_RTS", TIOCM_RTS}, +#endif +#ifdef TIOCM_SR + {"TIOCM_SR", TIOCM_SR}, +#endif +#ifdef TIOCM_ST + {"TIOCM_ST", TIOCM_ST}, +#endif +#ifdef TIOCNOTTY + {"TIOCNOTTY", TIOCNOTTY}, +#endif +#ifdef TIOCNXCL + {"TIOCNXCL", TIOCNXCL}, +#endif +#ifdef TIOCOUTQ + {"TIOCOUTQ", TIOCOUTQ}, +#endif +#ifdef TIOCPKT + {"TIOCPKT", TIOCPKT}, +#endif +#ifdef TIOCPKT_DATA + {"TIOCPKT_DATA", TIOCPKT_DATA}, +#endif +#ifdef TIOCPKT_DOSTOP + {"TIOCPKT_DOSTOP", TIOCPKT_DOSTOP}, +#endif +#ifdef TIOCPKT_FLUSHREAD + {"TIOCPKT_FLUSHREAD", TIOCPKT_FLUSHREAD}, +#endif +#ifdef TIOCPKT_FLUSHWRITE + {"TIOCPKT_FLUSHWRITE", TIOCPKT_FLUSHWRITE}, +#endif +#ifdef TIOCPKT_NOSTOP + {"TIOCPKT_NOSTOP", TIOCPKT_NOSTOP}, +#endif +#ifdef TIOCPKT_START + {"TIOCPKT_START", TIOCPKT_START}, +#endif +#ifdef TIOCPKT_STOP + {"TIOCPKT_STOP", TIOCPKT_STOP}, +#endif +#ifdef TIOCSCTTY + {"TIOCSCTTY", TIOCSCTTY}, +#endif +#ifdef TIOCSERCONFIG + {"TIOCSERCONFIG", TIOCSERCONFIG}, +#endif +#ifdef TIOCSERGETLSR + {"TIOCSERGETLSR", TIOCSERGETLSR}, +#endif +#ifdef TIOCSERGETMULTI + {"TIOCSERGETMULTI", TIOCSERGETMULTI}, +#endif +#ifdef TIOCSERGSTRUCT + {"TIOCSERGSTRUCT", TIOCSERGSTRUCT}, +#endif +#ifdef TIOCSERGWILD + {"TIOCSERGWILD", TIOCSERGWILD}, +#endif +#ifdef TIOCSERSETMULTI + {"TIOCSERSETMULTI", TIOCSERSETMULTI}, +#endif +#ifdef TIOCSERSWILD + {"TIOCSERSWILD", TIOCSERSWILD}, +#endif +#ifdef TIOCSER_TEMT + {"TIOCSER_TEMT", TIOCSER_TEMT}, +#endif +#ifdef TIOCSETD + {"TIOCSETD", TIOCSETD}, +#endif +#ifdef TIOCSLCKTRMIOS + {"TIOCSLCKTRMIOS", TIOCSLCKTRMIOS}, +#endif +#ifdef TIOCSPGRP + {"TIOCSPGRP", TIOCSPGRP}, +#endif +#ifdef TIOCSSERIAL + {"TIOCSSERIAL", TIOCSSERIAL}, +#endif +#ifdef TIOCSSOFTCAR + {"TIOCSSOFTCAR", TIOCSSOFTCAR}, +#endif +#ifdef TIOCSTI + {"TIOCSTI", TIOCSTI}, +#endif +#ifdef TIOCSWINSZ + {"TIOCSWINSZ", TIOCSWINSZ}, +#endif +#ifdef TIOCTTYGSTRUCT + {"TIOCTTYGSTRUCT", TIOCTTYGSTRUCT}, +#endif + + /* sentinel */ + {NULL, 0} +}; + + +PyMODINIT_FUNC +PyInit_termios(void) +{ + PyObject *m; + struct constant *constant = termios_constants; + + m = Py_InitModule4("termios", termios_methods, termios__doc__, + (PyObject *)NULL, PYTHON_API_VERSION); + if (m == NULL) + return; + + if (TermiosError == NULL) { + TermiosError = PyErr_NewException("termios.error", NULL, NULL); + } + Py_INCREF(TermiosError); + PyModule_AddObject(m, "error", TermiosError); + + while (constant->name != NULL) { + PyModule_AddIntConstant(m, constant->name, constant->value); + ++constant; + } +} diff --git a/sys/src/cmd/python/Modules/testcapi_long.h b/sys/src/cmd/python/Modules/testcapi_long.h new file mode 100644 index 000000000..8ed6b021e --- /dev/null +++ b/sys/src/cmd/python/Modules/testcapi_long.h @@ -0,0 +1,166 @@ +/* Poor-man's template. Macros used: + TESTNAME name of the test (like test_long_api_inner) + TYPENAME the signed type (like long) + F_S_TO_PY convert signed to pylong; TYPENAME -> PyObject* + F_PY_TO_S convert pylong to signed; PyObject* -> TYPENAME + F_U_TO_PY convert unsigned to pylong; unsigned TYPENAME -> PyObject* + F_PY_TO_U convert pylong to unsigned; PyObject* -> unsigned TYPENAME +*/ + +static PyObject * +TESTNAME(PyObject *error(const char*)) +{ + const int NBITS = sizeof(TYPENAME) * 8; + unsigned TYPENAME base; + PyObject *pyresult; + int i; + + /* Note: This test lets PyObjects leak if an error is raised. Since + an error should never be raised, leaks are impossible <wink>. */ + + /* Test native -> PyLong -> native roundtrip identity. + * Generate all powers of 2, and test them and their negations, + * plus the numbers +-1 off from them. + */ + base = 1; + for (i = 0; + i < NBITS + 1; /* on last, base overflows to 0 */ + ++i, base <<= 1) + { + int j; + for (j = 0; j < 6; ++j) { + TYPENAME in, out; + unsigned TYPENAME uin, uout; + + /* For 0, 1, 2 use base; for 3, 4, 5 use -base */ + uin = j < 3 ? base + : (unsigned TYPENAME)(-(TYPENAME)base); + + /* For 0 & 3, subtract 1. + * For 1 & 4, leave alone. + * For 2 & 5, add 1. + */ + uin += (unsigned TYPENAME)(TYPENAME)(j % 3 - 1); + + pyresult = F_U_TO_PY(uin); + if (pyresult == NULL) + return error( + "unsigned unexpected null result"); + + uout = F_PY_TO_U(pyresult); + if (uout == (unsigned TYPENAME)-1 && PyErr_Occurred()) + return error( + "unsigned unexpected -1 result"); + if (uout != uin) + return error( + "unsigned output != input"); + UNBIND(pyresult); + + in = (TYPENAME)uin; + pyresult = F_S_TO_PY(in); + if (pyresult == NULL) + return error( + "signed unexpected null result"); + + out = F_PY_TO_S(pyresult); + if (out == (TYPENAME)-1 && PyErr_Occurred()) + return error( + "signed unexpected -1 result"); + if (out != in) + return error( + "signed output != input"); + UNBIND(pyresult); + } + } + + /* Overflow tests. The loop above ensured that all limit cases that + * should not overflow don't overflow, so all we need to do here is + * provoke one-over-the-limit cases (not exhaustive, but sharp). + */ + { + PyObject *one, *x, *y; + TYPENAME out; + unsigned TYPENAME uout; + + one = PyLong_FromLong(1); + if (one == NULL) + return error( + "unexpected NULL from PyLong_FromLong"); + + /* Unsigned complains about -1? */ + x = PyNumber_Negative(one); + if (x == NULL) + return error( + "unexpected NULL from PyNumber_Negative"); + + uout = F_PY_TO_U(x); + if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) + return error( + "PyLong_AsUnsignedXXX(-1) didn't complain"); + PyErr_Clear(); + UNBIND(x); + + /* Unsigned complains about 2**NBITS? */ + y = PyLong_FromLong((long)NBITS); + if (y == NULL) + return error( + "unexpected NULL from PyLong_FromLong"); + + x = PyNumber_Lshift(one, y); /* 1L << NBITS, == 2**NBITS */ + UNBIND(y); + if (x == NULL) + return error( + "unexpected NULL from PyNumber_Lshift"); + + uout = F_PY_TO_U(x); + if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) + return error( + "PyLong_AsUnsignedXXX(2**NBITS) didn't " + "complain"); + PyErr_Clear(); + + /* Signed complains about 2**(NBITS-1)? + x still has 2**NBITS. */ + y = PyNumber_Rshift(x, one); /* 2**(NBITS-1) */ + UNBIND(x); + if (y == NULL) + return error( + "unexpected NULL from PyNumber_Rshift"); + + out = F_PY_TO_S(y); + if (out != (TYPENAME)-1 || !PyErr_Occurred()) + return error( + "PyLong_AsXXX(2**(NBITS-1)) didn't " + "complain"); + PyErr_Clear(); + + /* Signed complains about -2**(NBITS-1)-1?; + y still has 2**(NBITS-1). */ + x = PyNumber_Negative(y); /* -(2**(NBITS-1)) */ + UNBIND(y); + if (x == NULL) + return error( + "unexpected NULL from PyNumber_Negative"); + + y = PyNumber_Subtract(x, one); /* -(2**(NBITS-1))-1 */ + UNBIND(x); + if (y == NULL) + return error( + "unexpected NULL from PyNumber_Subtract"); + + out = F_PY_TO_S(y); + if (out != (TYPENAME)-1 || !PyErr_Occurred()) + return error( + "PyLong_AsXXX(-2**(NBITS-1)-1) didn't " + "complain"); + PyErr_Clear(); + UNBIND(y); + + Py_XDECREF(x); + Py_XDECREF(y); + Py_DECREF(one); + } + + Py_INCREF(Py_None); + return Py_None; +} diff --git a/sys/src/cmd/python/Modules/threadmodule.c b/sys/src/cmd/python/Modules/threadmodule.c new file mode 100644 index 000000000..036619a8f --- /dev/null +++ b/sys/src/cmd/python/Modules/threadmodule.c @@ -0,0 +1,720 @@ + +/* Thread module */ +/* Interface to Sjoerd's portable C thread library */ + +#include "Python.h" + +#ifndef WITH_THREAD +#error "Error! The rest of Python is not compiled with thread support." +#error "Rerun configure, adding a --with-threads option." +#error "Then run `make clean' followed by `make'." +#endif + +#include "pythread.h" + +static PyObject *ThreadError; + + +/* Lock objects */ + +typedef struct { + PyObject_HEAD + PyThread_type_lock lock_lock; +} lockobject; + +static void +lock_dealloc(lockobject *self) +{ + assert(self->lock_lock); + /* Unlock the lock so it's safe to free it */ + PyThread_acquire_lock(self->lock_lock, 0); + PyThread_release_lock(self->lock_lock); + + PyThread_free_lock(self->lock_lock); + PyObject_Del(self); +} + +static PyObject * +lock_PyThread_acquire_lock(lockobject *self, PyObject *args) +{ + int i = 1; + + if (!PyArg_ParseTuple(args, "|i:acquire", &i)) + return NULL; + + Py_BEGIN_ALLOW_THREADS + i = PyThread_acquire_lock(self->lock_lock, i); + Py_END_ALLOW_THREADS + + return PyBool_FromLong((long)i); +} + +PyDoc_STRVAR(acquire_doc, +"acquire([wait]) -> None or bool\n\ +(acquire_lock() is an obsolete synonym)\n\ +\n\ +Lock the lock. Without argument, this blocks if the lock is already\n\ +locked (even by the same thread), waiting for another thread to release\n\ +the lock, and return None once the lock is acquired.\n\ +With an argument, this will only block if the argument is true,\n\ +and the return value reflects whether the lock is acquired.\n\ +The blocking operation is not interruptible."); + +static PyObject * +lock_PyThread_release_lock(lockobject *self) +{ + /* Sanity check: the lock must be locked */ + if (PyThread_acquire_lock(self->lock_lock, 0)) { + PyThread_release_lock(self->lock_lock); + PyErr_SetString(ThreadError, "release unlocked lock"); + return NULL; + } + + PyThread_release_lock(self->lock_lock); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(release_doc, +"release()\n\ +(release_lock() is an obsolete synonym)\n\ +\n\ +Release the lock, allowing another thread that is blocked waiting for\n\ +the lock to acquire the lock. The lock must be in the locked state,\n\ +but it needn't be locked by the same thread that unlocks it."); + +static PyObject * +lock_locked_lock(lockobject *self) +{ + if (PyThread_acquire_lock(self->lock_lock, 0)) { + PyThread_release_lock(self->lock_lock); + return PyBool_FromLong(0L); + } + return PyBool_FromLong(1L); +} + +PyDoc_STRVAR(locked_doc, +"locked() -> bool\n\ +(locked_lock() is an obsolete synonym)\n\ +\n\ +Return whether the lock is in the locked state."); + +static PyMethodDef lock_methods[] = { + {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock, + METH_VARARGS, acquire_doc}, + {"acquire", (PyCFunction)lock_PyThread_acquire_lock, + METH_VARARGS, acquire_doc}, + {"release_lock", (PyCFunction)lock_PyThread_release_lock, + METH_NOARGS, release_doc}, + {"release", (PyCFunction)lock_PyThread_release_lock, + METH_NOARGS, release_doc}, + {"locked_lock", (PyCFunction)lock_locked_lock, + METH_NOARGS, locked_doc}, + {"locked", (PyCFunction)lock_locked_lock, + METH_NOARGS, locked_doc}, + {"__enter__", (PyCFunction)lock_PyThread_acquire_lock, + METH_VARARGS, acquire_doc}, + {"__exit__", (PyCFunction)lock_PyThread_release_lock, + METH_VARARGS, release_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +lock_getattr(lockobject *self, char *name) +{ + return Py_FindMethod(lock_methods, (PyObject *)self, name); +} + +static PyTypeObject Locktype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "thread.lock", /*tp_name*/ + sizeof(lockobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)lock_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)lock_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ +}; + +static lockobject * +newlockobject(void) +{ + lockobject *self; + self = PyObject_New(lockobject, &Locktype); + if (self == NULL) + return NULL; + self->lock_lock = PyThread_allocate_lock(); + if (self->lock_lock == NULL) { + PyObject_Del(self); + self = NULL; + PyErr_SetString(ThreadError, "can't allocate lock"); + } + return self; +} + +/* Thread-local objects */ + +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *key; + PyObject *args; + PyObject *kw; + PyObject *dict; +} localobject; + +static PyObject * +local_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + localobject *self; + PyObject *tdict; + + if (type->tp_init == PyBaseObject_Type.tp_init + && ((args && PyObject_IsTrue(args)) + || (kw && PyObject_IsTrue(kw)))) { + PyErr_SetString(PyExc_TypeError, + "Initialization arguments are not supported"); + return NULL; + } + + self = (localobject *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + Py_XINCREF(args); + self->args = args; + Py_XINCREF(kw); + self->kw = kw; + self->dict = NULL; /* making sure */ + self->key = PyString_FromFormat("thread.local.%p", self); + if (self->key == NULL) + goto err; + + self->dict = PyDict_New(); + if (self->dict == NULL) + goto err; + + tdict = PyThreadState_GetDict(); + if (tdict == NULL) { + PyErr_SetString(PyExc_SystemError, + "Couldn't get thread-state dictionary"); + goto err; + } + + if (PyDict_SetItem(tdict, self->key, self->dict) < 0) + goto err; + + return (PyObject *)self; + + err: + Py_DECREF(self); + return NULL; +} + +static int +local_traverse(localobject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->args); + Py_VISIT(self->kw); + Py_VISIT(self->dict); + return 0; +} + +static int +local_clear(localobject *self) +{ + Py_CLEAR(self->key); + Py_CLEAR(self->args); + Py_CLEAR(self->kw); + Py_CLEAR(self->dict); + return 0; +} + +static void +local_dealloc(localobject *self) +{ + PyThreadState *tstate; + if (self->key + && (tstate = PyThreadState_Get()) + && tstate->interp) { + for(tstate = PyInterpreterState_ThreadHead(tstate->interp); + tstate; + tstate = PyThreadState_Next(tstate)) + if (tstate->dict && + PyDict_GetItem(tstate->dict, self->key)) + PyDict_DelItem(tstate->dict, self->key); + } + + local_clear(self); + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject * +_ldict(localobject *self) +{ + PyObject *tdict, *ldict; + + tdict = PyThreadState_GetDict(); + if (tdict == NULL) { + PyErr_SetString(PyExc_SystemError, + "Couldn't get thread-state dictionary"); + return NULL; + } + + ldict = PyDict_GetItem(tdict, self->key); + if (ldict == NULL) { + ldict = PyDict_New(); /* we own ldict */ + + if (ldict == NULL) + return NULL; + else { + int i = PyDict_SetItem(tdict, self->key, ldict); + Py_DECREF(ldict); /* now ldict is borrowed */ + if (i < 0) + return NULL; + } + + Py_CLEAR(self->dict); + Py_INCREF(ldict); + self->dict = ldict; /* still borrowed */ + + if (self->ob_type->tp_init != PyBaseObject_Type.tp_init && + self->ob_type->tp_init((PyObject*)self, + self->args, self->kw) < 0) { + /* we need to get rid of ldict from thread so + we create a new one the next time we do an attr + acces */ + PyDict_DelItem(tdict, self->key); + return NULL; + } + + } + else if (self->dict != ldict) { + Py_CLEAR(self->dict); + Py_INCREF(ldict); + self->dict = ldict; + } + + return ldict; +} + +static int +local_setattro(localobject *self, PyObject *name, PyObject *v) +{ + PyObject *ldict; + + ldict = _ldict(self); + if (ldict == NULL) + return -1; + + return PyObject_GenericSetAttr((PyObject *)self, name, v); +} + +static PyObject * +local_getdict(localobject *self, void *closure) +{ + if (self->dict == NULL) { + PyErr_SetString(PyExc_AttributeError, "__dict__"); + return NULL; + } + + Py_INCREF(self->dict); + return self->dict; +} + +static PyGetSetDef local_getset[] = { + {"__dict__", (getter)local_getdict, (setter)NULL, + "Local-data dictionary", NULL}, + {NULL} /* Sentinel */ +}; + +static PyObject *local_getattro(localobject *, PyObject *); + +static PyTypeObject localtype = { + PyObject_HEAD_INIT(NULL) + /* ob_size */ 0, + /* tp_name */ "thread._local", + /* tp_basicsize */ sizeof(localobject), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)local_dealloc, + /* tp_print */ 0, + /* tp_getattr */ 0, + /* tp_setattr */ 0, + /* tp_compare */ 0, + /* tp_repr */ 0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ 0, + /* tp_call */ 0, + /* tp_str */ 0, + /* tp_getattro */ (getattrofunc)local_getattro, + /* tp_setattro */ (setattrofunc)local_setattro, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + /* tp_doc */ "Thread-local data", + /* tp_traverse */ (traverseproc)local_traverse, + /* tp_clear */ (inquiry)local_clear, + /* tp_richcompare */ 0, + /* tp_weaklistoffset */ 0, + /* tp_iter */ 0, + /* tp_iternext */ 0, + /* tp_methods */ 0, + /* tp_members */ 0, + /* tp_getset */ local_getset, + /* tp_base */ 0, + /* tp_dict */ 0, /* internal use */ + /* tp_descr_get */ 0, + /* tp_descr_set */ 0, + /* tp_dictoffset */ offsetof(localobject, dict), + /* tp_init */ 0, + /* tp_alloc */ 0, + /* tp_new */ local_new, + /* tp_free */ 0, /* Low-level free-mem routine */ + /* tp_is_gc */ 0, /* For PyObject_IS_GC */ +}; + +static PyObject * +local_getattro(localobject *self, PyObject *name) +{ + PyObject *ldict, *value; + + ldict = _ldict(self); + if (ldict == NULL) + return NULL; + + if (self->ob_type != &localtype) + /* use generic lookup for subtypes */ + return PyObject_GenericGetAttr((PyObject *)self, name); + + /* Optimization: just look in dict ourselves */ + value = PyDict_GetItem(ldict, name); + if (value == NULL) + /* Fall back on generic to get __class__ and __dict__ */ + return PyObject_GenericGetAttr((PyObject *)self, name); + + Py_INCREF(value); + return value; +} + +/* Module functions */ + +struct bootstate { + PyInterpreterState *interp; + PyObject *func; + PyObject *args; + PyObject *keyw; +}; + +static void +t_bootstrap(void *boot_raw) +{ + struct bootstate *boot = (struct bootstate *) boot_raw; + PyThreadState *tstate; + PyObject *res; + + tstate = PyThreadState_New(boot->interp); + + PyEval_AcquireThread(tstate); + res = PyEval_CallObjectWithKeywords( + boot->func, boot->args, boot->keyw); + if (res == NULL) { + if (PyErr_ExceptionMatches(PyExc_SystemExit)) + PyErr_Clear(); + else { + PyObject *file; + PySys_WriteStderr( + "Unhandled exception in thread started by "); + file = PySys_GetObject("stderr"); + if (file) + PyFile_WriteObject(boot->func, file, 0); + else + PyObject_Print(boot->func, stderr, 0); + PySys_WriteStderr("\n"); + PyErr_PrintEx(0); + } + } + else + Py_DECREF(res); + Py_DECREF(boot->func); + Py_DECREF(boot->args); + Py_XDECREF(boot->keyw); + PyMem_DEL(boot_raw); + PyThreadState_Clear(tstate); + PyThreadState_DeleteCurrent(); + PyThread_exit_thread(); +} + +static PyObject * +thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) +{ + PyObject *func, *args, *keyw = NULL; + struct bootstate *boot; + long ident; + + if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3, + &func, &args, &keyw)) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "first arg must be callable"); + return NULL; + } + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "2nd arg must be a tuple"); + return NULL; + } + if (keyw != NULL && !PyDict_Check(keyw)) { + PyErr_SetString(PyExc_TypeError, + "optional 3rd arg must be a dictionary"); + return NULL; + } + boot = PyMem_NEW(struct bootstate, 1); + if (boot == NULL) + return PyErr_NoMemory(); + boot->interp = PyThreadState_GET()->interp; + boot->func = func; + boot->args = args; + boot->keyw = keyw; + Py_INCREF(func); + Py_INCREF(args); + Py_XINCREF(keyw); + PyEval_InitThreads(); /* Start the interpreter's thread-awareness */ + ident = PyThread_start_new_thread(t_bootstrap, (void*) boot); + if (ident == -1) { + PyErr_SetString(ThreadError, "can't start new thread"); + Py_DECREF(func); + Py_DECREF(args); + Py_XDECREF(keyw); + PyMem_DEL(boot); + return NULL; + } + return PyInt_FromLong(ident); +} + +PyDoc_STRVAR(start_new_doc, +"start_new_thread(function, args[, kwargs])\n\ +(start_new() is an obsolete synonym)\n\ +\n\ +Start a new thread and return its identifier. The thread will call the\n\ +function with positional arguments from the tuple args and keyword arguments\n\ +taken from the optional dictionary kwargs. The thread exits when the\n\ +function returns; the return value is ignored. The thread will also exit\n\ +when the function raises an unhandled exception; a stack trace will be\n\ +printed unless the exception is SystemExit.\n"); + +static PyObject * +thread_PyThread_exit_thread(PyObject *self) +{ + PyErr_SetNone(PyExc_SystemExit); + return NULL; +} + +PyDoc_STRVAR(exit_doc, +"exit()\n\ +(PyThread_exit_thread() is an obsolete synonym)\n\ +\n\ +This is synonymous to ``raise SystemExit''. It will cause the current\n\ +thread to exit silently unless the exception is caught."); + +static PyObject * +thread_PyThread_interrupt_main(PyObject * self) +{ + PyErr_SetInterrupt(); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(interrupt_doc, +"interrupt_main()\n\ +\n\ +Raise a KeyboardInterrupt in the main thread.\n\ +A subthread can use this function to interrupt the main thread." +); + +#ifndef NO_EXIT_PROG +static PyObject * +thread_PyThread_exit_prog(PyObject *self, PyObject *args) +{ + int sts; + if (!PyArg_ParseTuple(args, "i:exit_prog", &sts)) + return NULL; + Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */ + for (;;) { } /* Should not be reached */ +} +#endif + +static lockobject *newlockobject(void); + +static PyObject * +thread_PyThread_allocate_lock(PyObject *self) +{ + return (PyObject *) newlockobject(); +} + +PyDoc_STRVAR(allocate_doc, +"allocate_lock() -> lock object\n\ +(allocate() is an obsolete synonym)\n\ +\n\ +Create a new lock object. See LockType.__doc__ for information about locks."); + +static PyObject * +thread_get_ident(PyObject *self) +{ + long ident; + ident = PyThread_get_thread_ident(); + if (ident == -1) { + PyErr_SetString(ThreadError, "no current thread ident"); + return NULL; + } + return PyInt_FromLong(ident); +} + +PyDoc_STRVAR(get_ident_doc, +"get_ident() -> integer\n\ +\n\ +Return a non-zero integer that uniquely identifies the current thread\n\ +amongst other threads that exist simultaneously.\n\ +This may be used to identify per-thread resources.\n\ +Even though on some platforms threads identities may appear to be\n\ +allocated consecutive numbers starting at 1, this behavior should not\n\ +be relied upon, and the number should be seen purely as a magic cookie.\n\ +A thread's identity may be reused for another thread after it exits."); + +static PyObject * +thread_stack_size(PyObject *self, PyObject *args) +{ + size_t old_size; + Py_ssize_t new_size = 0; + int rc; + + if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size)) + return NULL; + + if (new_size < 0) { + PyErr_SetString(PyExc_ValueError, + "size must be 0 or a positive value"); + return NULL; + } + + old_size = PyThread_get_stacksize(); + + rc = PyThread_set_stacksize((size_t) new_size); + if (rc == -1) { + PyErr_Format(PyExc_ValueError, + "size not valid: %zd bytes", + new_size); + return NULL; + } + if (rc == -2) { + PyErr_SetString(ThreadError, + "setting stack size not supported"); + return NULL; + } + + return PyInt_FromSsize_t((Py_ssize_t) old_size); +} + +PyDoc_STRVAR(stack_size_doc, +"stack_size([size]) -> size\n\ +\n\ +Return the thread stack size used when creating new threads. The\n\ +optional size argument specifies the stack size (in bytes) to be used\n\ +for subsequently created threads, and must be 0 (use platform or\n\ +configured default) or a positive integer value of at least 32,768 (32k).\n\ +If changing the thread stack size is unsupported, a ThreadError\n\ +exception is raised. If the specified size is invalid, a ValueError\n\ +exception is raised, and the stack size is unmodified. 32k bytes\n\ + currently the minimum supported stack size value to guarantee\n\ +sufficient stack space for the interpreter itself.\n\ +\n\ +Note that some platforms may have particular restrictions on values for\n\ +the stack size, such as requiring a minimum stack size larger than 32kB or\n\ +requiring allocation in multiples of the system memory page size\n\ +- platform documentation should be referred to for more information\n\ +(4kB pages are common; using multiples of 4096 for the stack size is\n\ +the suggested approach in the absence of more specific information)."); + +static PyMethodDef thread_methods[] = { + {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, + METH_VARARGS, + start_new_doc}, + {"start_new", (PyCFunction)thread_PyThread_start_new_thread, + METH_VARARGS, + start_new_doc}, + {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock, + METH_NOARGS, allocate_doc}, + {"allocate", (PyCFunction)thread_PyThread_allocate_lock, + METH_NOARGS, allocate_doc}, + {"exit_thread", (PyCFunction)thread_PyThread_exit_thread, + METH_NOARGS, exit_doc}, + {"exit", (PyCFunction)thread_PyThread_exit_thread, + METH_NOARGS, exit_doc}, + {"interrupt_main", (PyCFunction)thread_PyThread_interrupt_main, + METH_NOARGS, interrupt_doc}, + {"get_ident", (PyCFunction)thread_get_ident, + METH_NOARGS, get_ident_doc}, + {"stack_size", (PyCFunction)thread_stack_size, + METH_VARARGS, + stack_size_doc}, +#ifndef NO_EXIT_PROG + {"exit_prog", (PyCFunction)thread_PyThread_exit_prog, + METH_VARARGS}, +#endif + {NULL, NULL} /* sentinel */ +}; + + +/* Initialization function */ + +PyDoc_STRVAR(thread_doc, +"This module provides primitive operations to write multi-threaded programs.\n\ +The 'threading' module provides a more convenient interface."); + +PyDoc_STRVAR(lock_doc, +"A lock object is a synchronization primitive. To create a lock,\n\ +call the PyThread_allocate_lock() function. Methods are:\n\ +\n\ +acquire() -- lock the lock, possibly blocking until it can be obtained\n\ +release() -- unlock of the lock\n\ +locked() -- test whether the lock is currently locked\n\ +\n\ +A lock is not owned by the thread that locked it; another thread may\n\ +unlock it. A thread attempting to lock a lock that it has already locked\n\ +will block until another thread unlocks it. Deadlocks may ensue."); + +PyMODINIT_FUNC +initthread(void) +{ + PyObject *m, *d; + + /* Initialize types: */ + if (PyType_Ready(&localtype) < 0) + return; + + /* Create the module and add the functions */ + m = Py_InitModule3("thread", thread_methods, thread_doc); + if (m == NULL) + return; + + /* Add a symbolic constant */ + d = PyModule_GetDict(m); + ThreadError = PyErr_NewException("thread.error", NULL, NULL); + PyDict_SetItemString(d, "error", ThreadError); + Locktype.tp_doc = lock_doc; + Py_INCREF(&Locktype); + PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); + + Py_INCREF(&localtype); + if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) + return; + + /* Initialize the C thread library */ + PyThread_init_thread(); +} diff --git a/sys/src/cmd/python/Modules/timemodule.c b/sys/src/cmd/python/Modules/timemodule.c new file mode 100644 index 000000000..7a1e44605 --- /dev/null +++ b/sys/src/cmd/python/Modules/timemodule.c @@ -0,0 +1,1030 @@ + +/* Time module */ + +#include "Python.h" +#include "structseq.h" +#include "timefuncs.h" + +#ifdef __APPLE__ +#if defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME) + /* + * floattime falls back to ftime when getttimeofday fails because the latter + * might fail on some platforms. This fallback is unwanted on MacOSX because + * that makes it impossible to use a binary build on OSX 10.4 on earlier + * releases of the OS. Therefore claim we don't support ftime. + */ +# undef HAVE_FTIME +#endif +#endif + +#include <ctype.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +#ifdef QUICKWIN +#include <io.h> +#endif + +#ifdef HAVE_FTIME +#include <sys/timeb.h> +#if !defined(MS_WINDOWS) && !defined(PYOS_OS2) +extern int ftime(struct timeb *); +#endif /* MS_WINDOWS */ +#endif /* HAVE_FTIME */ + +#if defined(__WATCOMC__) && !defined(__QNX__) +#include <i86.h> +#else +#ifdef MS_WINDOWS +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include "pythread.h" + +/* helper to allow us to interrupt sleep() on Windows*/ +static HANDLE hInterruptEvent = NULL; +static BOOL WINAPI PyCtrlHandler(DWORD dwCtrlType) +{ + SetEvent(hInterruptEvent); + /* allow other default handlers to be called. + Default Python handler will setup the + KeyboardInterrupt exception. + */ + return FALSE; +} +static long main_thread; + + +#if defined(__BORLANDC__) +/* These overrides not needed for Win32 */ +#define timezone _timezone +#define tzname _tzname +#define daylight _daylight +#endif /* __BORLANDC__ */ +#endif /* MS_WINDOWS */ +#endif /* !__WATCOMC__ || __QNX__ */ + +#if defined(MS_WINDOWS) && !defined(__BORLANDC__) +/* Win32 has better clock replacement; we have our own version below. */ +#undef HAVE_CLOCK +#endif /* MS_WINDOWS && !defined(__BORLANDC__) */ + +#if defined(PYOS_OS2) +#define INCL_DOS +#define INCL_ERRORS +#include <os2.h> +#endif + +#if defined(PYCC_VACPP) +#include <sys/time.h> +#endif + +#ifdef __BEOS__ +#include <time.h> +/* For bigtime_t, snooze(). - [cjh] */ +#include <support/SupportDefs.h> +#include <kernel/OS.h> +#endif + +#ifdef RISCOS +extern int riscos_sleep(double); +#endif + +/* Forward declarations */ +static int floatsleep(double); +static double floattime(void); + +/* For Y2K check */ +static PyObject *moddict; + +/* Exposed in timefuncs.h. */ +time_t +_PyTime_DoubleToTimet(double x) +{ + time_t result; + double diff; + + result = (time_t)x; + /* How much info did we lose? time_t may be an integral or + * floating type, and we don't know which. If it's integral, + * we don't know whether C truncates, rounds, returns the floor, + * etc. If we lost a second or more, the C rounding is + * unreasonable, or the input just doesn't fit in a time_t; + * call it an error regardless. Note that the original cast to + * time_t can cause a C error too, but nothing we can do to + * worm around that. + */ + diff = x - (double)result; + if (diff <= -1.0 || diff >= 1.0) { + PyErr_SetString(PyExc_ValueError, + "timestamp out of range for platform time_t"); + result = (time_t)-1; + } + return result; +} + +static PyObject * +time_time(PyObject *self, PyObject *unused) +{ + double secs; + secs = floattime(); + if (secs == 0.0) { + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + return PyFloat_FromDouble(secs); +} + +PyDoc_STRVAR(time_doc, +"time() -> floating point number\n\ +\n\ +Return the current time in seconds since the Epoch.\n\ +Fractions of a second may be present if the system clock provides them."); + +#ifdef HAVE_CLOCK + +#ifndef CLOCKS_PER_SEC +#ifdef CLK_TCK +#define CLOCKS_PER_SEC CLK_TCK +#else +#define CLOCKS_PER_SEC 1000000 +#endif +#endif + +static PyObject * +time_clock(PyObject *self, PyObject *unused) +{ + return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC); +} +#endif /* HAVE_CLOCK */ + +#if defined(MS_WINDOWS) && !defined(__BORLANDC__) +/* Due to Mark Hammond and Tim Peters */ +static PyObject * +time_clock(PyObject *self, PyObject *unused) +{ + static LARGE_INTEGER ctrStart; + static double divisor = 0.0; + LARGE_INTEGER now; + double diff; + + if (divisor == 0.0) { + LARGE_INTEGER freq; + QueryPerformanceCounter(&ctrStart); + if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) { + /* Unlikely to happen - this works on all intel + machines at least! Revert to clock() */ + return PyFloat_FromDouble(((double)clock()) / + CLOCKS_PER_SEC); + } + divisor = (double)freq.QuadPart; + } + QueryPerformanceCounter(&now); + diff = (double)(now.QuadPart - ctrStart.QuadPart); + return PyFloat_FromDouble(diff / divisor); +} + +#define HAVE_CLOCK /* So it gets included in the methods */ +#endif /* MS_WINDOWS && !defined(__BORLANDC__) */ + +#ifdef HAVE_CLOCK +PyDoc_STRVAR(clock_doc, +"clock() -> floating point number\n\ +\n\ +Return the CPU time or real time since the start of the process or since\n\ +the first call to clock(). This has as much precision as the system\n\ +records."); +#endif + +static PyObject * +time_sleep(PyObject *self, PyObject *args) +{ + double secs; + if (!PyArg_ParseTuple(args, "d:sleep", &secs)) + return NULL; + if (floatsleep(secs) != 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(sleep_doc, +"sleep(seconds)\n\ +\n\ +Delay execution for a given number of seconds. The argument may be\n\ +a floating point number for subsecond precision."); + +static PyStructSequence_Field struct_time_type_fields[] = { + {"tm_year", NULL}, + {"tm_mon", NULL}, + {"tm_mday", NULL}, + {"tm_hour", NULL}, + {"tm_min", NULL}, + {"tm_sec", NULL}, + {"tm_wday", NULL}, + {"tm_yday", NULL}, + {"tm_isdst", NULL}, + {0} +}; + +static PyStructSequence_Desc struct_time_type_desc = { + "time.struct_time", + NULL, + struct_time_type_fields, + 9, +}; + +static int initialized; +static PyTypeObject StructTimeType; + +static PyObject * +tmtotuple(struct tm *p) +{ + PyObject *v = PyStructSequence_New(&StructTimeType); + if (v == NULL) + return NULL; + +#define SET(i,val) PyStructSequence_SET_ITEM(v, i, PyInt_FromLong((long) val)) + + SET(0, p->tm_year + 1900); + SET(1, p->tm_mon + 1); /* Want January == 1 */ + SET(2, p->tm_mday); + SET(3, p->tm_hour); + SET(4, p->tm_min); + SET(5, p->tm_sec); + SET(6, (p->tm_wday + 6) % 7); /* Want Monday == 0 */ + SET(7, p->tm_yday + 1); /* Want January, 1 == 1 */ + SET(8, p->tm_isdst); +#undef SET + if (PyErr_Occurred()) { + Py_XDECREF(v); + return NULL; + } + + return v; +} + +static PyObject * +time_convert(double when, struct tm * (*function)(const time_t *)) +{ + struct tm *p; + time_t whent = _PyTime_DoubleToTimet(when); + + if (whent == (time_t)-1 && PyErr_Occurred()) + return NULL; + errno = 0; + p = function(&whent); + if (p == NULL) { +#ifdef EINVAL + if (errno == 0) + errno = EINVAL; +#endif + return PyErr_SetFromErrno(PyExc_ValueError); + } + return tmtotuple(p); +} + +/* Parse arg tuple that can contain an optional float-or-None value; + format needs to be "|O:name". + Returns non-zero on success (parallels PyArg_ParseTuple). +*/ +static int +parse_time_double_args(PyObject *args, char *format, double *pwhen) +{ + PyObject *ot = NULL; + + if (!PyArg_ParseTuple(args, format, &ot)) + return 0; + if (ot == NULL || ot == Py_None) + *pwhen = floattime(); + else { + double when = PyFloat_AsDouble(ot); + if (PyErr_Occurred()) + return 0; + *pwhen = when; + } + return 1; +} + +static PyObject * +time_gmtime(PyObject *self, PyObject *args) +{ + double when; + if (!parse_time_double_args(args, "|O:gmtime", &when)) + return NULL; + return time_convert(when, gmtime); +} + +PyDoc_STRVAR(gmtime_doc, +"gmtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min,\n\ + tm_sec, tm_wday, tm_yday, tm_isdst)\n\ +\n\ +Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a.\n\ +GMT). When 'seconds' is not passed in, convert the current time instead."); + +static PyObject * +time_localtime(PyObject *self, PyObject *args) +{ + double when; + if (!parse_time_double_args(args, "|O:localtime", &when)) + return NULL; + return time_convert(when, localtime); +} + +PyDoc_STRVAR(localtime_doc, +"localtime([seconds]) -> (tm_year,tm_mon,tm_day,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)\n\ +\n\ +Convert seconds since the Epoch to a time tuple expressing local time.\n\ +When 'seconds' is not passed in, convert the current time instead."); + +static int +gettmarg(PyObject *args, struct tm *p) +{ + int y; + memset((void *) p, '\0', sizeof(struct tm)); + + if (!PyArg_Parse(args, "(iiiiiiiii)", + &y, + &p->tm_mon, + &p->tm_mday, + &p->tm_hour, + &p->tm_min, + &p->tm_sec, + &p->tm_wday, + &p->tm_yday, + &p->tm_isdst)) + return 0; + if (y < 1900) { + PyObject *accept = PyDict_GetItemString(moddict, + "accept2dyear"); + if (accept == NULL || !PyInt_Check(accept) || + PyInt_AsLong(accept) == 0) { + PyErr_SetString(PyExc_ValueError, + "year >= 1900 required"); + return 0; + } + if (69 <= y && y <= 99) + y += 1900; + else if (0 <= y && y <= 68) + y += 2000; + else { + PyErr_SetString(PyExc_ValueError, + "year out of range"); + return 0; + } + } + p->tm_year = y - 1900; + p->tm_mon--; + p->tm_wday = (p->tm_wday + 1) % 7; + p->tm_yday--; + return 1; +} + +#ifdef HAVE_STRFTIME +static PyObject * +time_strftime(PyObject *self, PyObject *args) +{ + PyObject *tup = NULL; + struct tm buf; + const char *fmt; + size_t fmtlen, buflen; + char *outbuf = 0; + size_t i; + + memset((void *) &buf, '\0', sizeof(buf)); + + if (!PyArg_ParseTuple(args, "s|O:strftime", &fmt, &tup)) + return NULL; + + if (tup == NULL) { + time_t tt = time(NULL); + buf = *localtime(&tt); + } else if (!gettmarg(tup, &buf)) + return NULL; + + /* Checks added to make sure strftime() does not crash Python by + indexing blindly into some array for a textual representation + by some bad index (fixes bug #897625). + + Also support values of zero from Python code for arguments in which + that is out of range by forcing that value to the lowest value that + is valid (fixed bug #1520914). + + Valid ranges based on what is allowed in struct tm: + + - tm_year: [0, max(int)] (1) + - tm_mon: [0, 11] (2) + - tm_mday: [1, 31] + - tm_hour: [0, 23] + - tm_min: [0, 59] + - tm_sec: [0, 60] + - tm_wday: [0, 6] (1) + - tm_yday: [0, 365] (2) + - tm_isdst: [-max(int), max(int)] + + (1) gettmarg() handles bounds-checking. + (2) Python's acceptable range is one greater than the range in C, + thus need to check against automatic decrement by gettmarg(). + */ + if (buf.tm_mon == -1) + buf.tm_mon = 0; + else if (buf.tm_mon < 0 || buf.tm_mon > 11) { + PyErr_SetString(PyExc_ValueError, "month out of range"); + return NULL; + } + if (buf.tm_mday == 0) + buf.tm_mday = 1; + else if (buf.tm_mday < 0 || buf.tm_mday > 31) { + PyErr_SetString(PyExc_ValueError, "day of month out of range"); + return NULL; + } + if (buf.tm_hour < 0 || buf.tm_hour > 23) { + PyErr_SetString(PyExc_ValueError, "hour out of range"); + return NULL; + } + if (buf.tm_min < 0 || buf.tm_min > 59) { + PyErr_SetString(PyExc_ValueError, "minute out of range"); + return NULL; + } + if (buf.tm_sec < 0 || buf.tm_sec > 61) { + PyErr_SetString(PyExc_ValueError, "seconds out of range"); + return NULL; + } + /* tm_wday does not need checking of its upper-bound since taking + ``% 7`` in gettmarg() automatically restricts the range. */ + if (buf.tm_wday < 0) { + PyErr_SetString(PyExc_ValueError, "day of week out of range"); + return NULL; + } + if (buf.tm_yday == -1) + buf.tm_yday = 0; + else if (buf.tm_yday < 0 || buf.tm_yday > 365) { + PyErr_SetString(PyExc_ValueError, "day of year out of range"); + return NULL; + } + if (buf.tm_isdst < -1 || buf.tm_isdst > 1) { + PyErr_SetString(PyExc_ValueError, + "daylight savings flag out of range"); + return NULL; + } + + fmtlen = strlen(fmt); + + /* I hate these functions that presume you know how big the output + * will be ahead of time... + */ + for (i = 1024; ; i += i) { + outbuf = (char *)malloc(i); + if (outbuf == NULL) { + return PyErr_NoMemory(); + } + buflen = strftime(outbuf, i, fmt, &buf); + if (buflen > 0 || i >= 256 * fmtlen) { + /* If the buffer is 256 times as long as the format, + it's probably not failing for lack of room! + More likely, the format yields an empty result, + e.g. an empty format, or %Z when the timezone + is unknown. */ + PyObject *ret; + ret = PyString_FromStringAndSize(outbuf, buflen); + free(outbuf); + return ret; + } + free(outbuf); +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) + /* VisualStudio .NET 2005 does this properly */ + if (buflen == 0 && errno == EINVAL) { + PyErr_SetString(PyExc_ValueError, "Invalid format string"); + return 0; + } +#endif + + } +} + +PyDoc_STRVAR(strftime_doc, +"strftime(format[, tuple]) -> string\n\ +\n\ +Convert a time tuple to a string according to a format specification.\n\ +See the library reference manual for formatting codes. When the time tuple\n\ +is not present, current time as returned by localtime() is used."); +#endif /* HAVE_STRFTIME */ + +static PyObject * +time_strptime(PyObject *self, PyObject *args) +{ + PyObject *strptime_module = PyImport_ImportModule("_strptime"); + PyObject *strptime_result; + + if (!strptime_module) + return NULL; + strptime_result = PyObject_CallMethod(strptime_module, "strptime", "O", args); + Py_DECREF(strptime_module); + return strptime_result; +} + +PyDoc_STRVAR(strptime_doc, +"strptime(string, format) -> struct_time\n\ +\n\ +Parse a string to a time tuple according to a format specification.\n\ +See the library reference manual for formatting codes (same as strftime())."); + + +static PyObject * +time_asctime(PyObject *self, PyObject *args) +{ + PyObject *tup = NULL; + struct tm buf; + char *p; + if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup)) + return NULL; + if (tup == NULL) { + time_t tt = time(NULL); + buf = *localtime(&tt); + } else if (!gettmarg(tup, &buf)) + return NULL; + p = asctime(&buf); + if (p[24] == '\n') + p[24] = '\0'; + return PyString_FromString(p); +} + +PyDoc_STRVAR(asctime_doc, +"asctime([tuple]) -> string\n\ +\n\ +Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'.\n\ +When the time tuple is not present, current time as returned by localtime()\n\ +is used."); + +static PyObject * +time_ctime(PyObject *self, PyObject *args) +{ + PyObject *ot = NULL; + time_t tt; + char *p; + + if (!PyArg_UnpackTuple(args, "ctime", 0, 1, &ot)) + return NULL; + if (ot == NULL || ot == Py_None) + tt = time(NULL); + else { + double dt = PyFloat_AsDouble(ot); + if (PyErr_Occurred()) + return NULL; + tt = _PyTime_DoubleToTimet(dt); + if (tt == (time_t)-1 && PyErr_Occurred()) + return NULL; + } + p = ctime(&tt); + if (p == NULL) { + PyErr_SetString(PyExc_ValueError, "unconvertible time"); + return NULL; + } + if (p[24] == '\n') + p[24] = '\0'; + return PyString_FromString(p); +} + +PyDoc_STRVAR(ctime_doc, +"ctime(seconds) -> string\n\ +\n\ +Convert a time in seconds since the Epoch to a string in local time.\n\ +This is equivalent to asctime(localtime(seconds)). When the time tuple is\n\ +not present, current time as returned by localtime() is used."); + +#ifdef HAVE_MKTIME +static PyObject * +time_mktime(PyObject *self, PyObject *tup) +{ + struct tm buf; + time_t tt; + tt = time(&tt); + buf = *localtime(&tt); + if (!gettmarg(tup, &buf)) + return NULL; + tt = mktime(&buf); + if (tt == (time_t)(-1)) { + PyErr_SetString(PyExc_OverflowError, + "mktime argument out of range"); + return NULL; + } + return PyFloat_FromDouble((double)tt); +} + +PyDoc_STRVAR(mktime_doc, +"mktime(tuple) -> floating point number\n\ +\n\ +Convert a time tuple in local time to seconds since the Epoch."); +#endif /* HAVE_MKTIME */ + +#ifdef HAVE_WORKING_TZSET +void inittimezone(PyObject *module); + +static PyObject * +time_tzset(PyObject *self, PyObject *unused) +{ + PyObject* m; + + m = PyImport_ImportModule("time"); + if (m == NULL) { + return NULL; + } + + tzset(); + + /* Reset timezone, altzone, daylight and tzname */ + inittimezone(m); + Py_DECREF(m); + + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(tzset_doc, +"tzset(zone)\n\ +\n\ +Initialize, or reinitialize, the local timezone to the value stored in\n\ +os.environ['TZ']. The TZ environment variable should be specified in\n\ +standard Unix timezone format as documented in the tzset man page\n\ +(eg. 'US/Eastern', 'Europe/Amsterdam'). Unknown timezones will silently\n\ +fall back to UTC. If the TZ environment variable is not set, the local\n\ +timezone is set to the systems best guess of wallclock time.\n\ +Changing the TZ environment variable without calling tzset *may* change\n\ +the local timezone used by methods such as localtime, but this behaviour\n\ +should not be relied on."); +#endif /* HAVE_WORKING_TZSET */ + +void inittimezone(PyObject *m) { + /* This code moved from inittime wholesale to allow calling it from + time_tzset. In the future, some parts of it can be moved back + (for platforms that don't HAVE_WORKING_TZSET, when we know what they + are), and the extranious calls to tzset(3) should be removed. + I havn't done this yet, as I don't want to change this code as + little as possible when introducing the time.tzset and time.tzsetwall + methods. This should simply be a method of doing the following once, + at the top of this function and removing the call to tzset() from + time_tzset(): + + #ifdef HAVE_TZSET + tzset() + #endif + + And I'm lazy and hate C so nyer. + */ +#if defined(HAVE_TZNAME) && !defined(__GLIBC__) && !defined(__CYGWIN__) + tzset(); +#ifdef PYOS_OS2 + PyModule_AddIntConstant(m, "timezone", _timezone); +#else /* !PYOS_OS2 */ +#ifdef PLAN9APE + //PyModule_AddIntConstant(m, "timezone", timezone); + PyModule_AddIntConstant(m, "timezone", 0); +#endif +#endif /* PYOS_OS2 */ +#ifdef HAVE_ALTZONE + PyModule_AddIntConstant(m, "altzone", altzone); +#else +#ifdef PYOS_OS2 + PyModule_AddIntConstant(m, "altzone", _timezone-3600); +#else /* !PYOS_OS2 */ +#ifdef PLAN9APE + //PyModule_AddIntConstant(m, "altzone", timezone-3600); + PyModule_AddIntConstant(m, "altzone", 3600); +#endif +#endif /* PYOS_OS2 */ +#endif +#ifdef PLAN9APE + //PyModule_AddIntConstant(m, "daylight", daylight); + PyModule_AddIntConstant(m, "daylight", 0); + PyModule_AddObject(m, "tzname", + Py_BuildValue("(zz)", tzname[0], tzname[1])); +#endif +#else /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/ +#ifdef HAVE_STRUCT_TM_TM_ZONE + { +#define YEAR ((time_t)((365 * 24 + 6) * 3600)) + time_t t; + struct tm *p; + long janzone, julyzone; + char janname[10], julyname[10]; + t = (time((time_t *)0) / YEAR) * YEAR; + p = localtime(&t); + janzone = -p->tm_gmtoff; + strncpy(janname, p->tm_zone ? p->tm_zone : " ", 9); + janname[9] = '\0'; + t += YEAR/2; + p = localtime(&t); + julyzone = -p->tm_gmtoff; + strncpy(julyname, p->tm_zone ? p->tm_zone : " ", 9); + julyname[9] = '\0'; + + if( janzone < julyzone ) { + /* DST is reversed in the southern hemisphere */ + PyModule_AddIntConstant(m, "timezone", julyzone); + PyModule_AddIntConstant(m, "altzone", janzone); + PyModule_AddIntConstant(m, "daylight", + janzone != julyzone); + PyModule_AddObject(m, "tzname", + Py_BuildValue("(zz)", + julyname, janname)); + } else { + PyModule_AddIntConstant(m, "timezone", janzone); + PyModule_AddIntConstant(m, "altzone", julyzone); + PyModule_AddIntConstant(m, "daylight", + janzone != julyzone); + PyModule_AddObject(m, "tzname", + Py_BuildValue("(zz)", + janname, julyname)); + } + } +#else +#endif /* HAVE_STRUCT_TM_TM_ZONE */ +#ifdef __CYGWIN__ + tzset(); + PyModule_AddIntConstant(m, "timezone", _timezone); + PyModule_AddIntConstant(m, "altzone", _timezone-3600); + PyModule_AddIntConstant(m, "daylight", _daylight); + PyModule_AddObject(m, "tzname", + Py_BuildValue("(zz)", _tzname[0], _tzname[1])); +#endif /* __CYGWIN__ */ +#endif /* !HAVE_TZNAME || __GLIBC__ || __CYGWIN__*/ +} + + +static PyMethodDef time_methods[] = { + {"time", time_time, METH_NOARGS, time_doc}, +#ifdef HAVE_CLOCK + {"clock", time_clock, METH_NOARGS, clock_doc}, +#endif + {"sleep", time_sleep, METH_VARARGS, sleep_doc}, + {"gmtime", time_gmtime, METH_VARARGS, gmtime_doc}, + {"localtime", time_localtime, METH_VARARGS, localtime_doc}, + {"asctime", time_asctime, METH_VARARGS, asctime_doc}, + {"ctime", time_ctime, METH_VARARGS, ctime_doc}, +#ifdef HAVE_MKTIME + {"mktime", time_mktime, METH_O, mktime_doc}, +#endif +#ifdef HAVE_STRFTIME + {"strftime", time_strftime, METH_VARARGS, strftime_doc}, +#endif + {"strptime", time_strptime, METH_VARARGS, strptime_doc}, +#ifdef HAVE_WORKING_TZSET + {"tzset", time_tzset, METH_NOARGS, tzset_doc}, +#endif + {NULL, NULL} /* sentinel */ +}; + + +PyDoc_STRVAR(module_doc, +"This module provides various functions to manipulate time values.\n\ +\n\ +There are two standard representations of time. One is the number\n\ +of seconds since the Epoch, in UTC (a.k.a. GMT). It may be an integer\n\ +or a floating point number (to represent fractions of seconds).\n\ +The Epoch is system-defined; on Unix, it is generally January 1st, 1970.\n\ +The actual value can be retrieved by calling gmtime(0).\n\ +\n\ +The other representation is a tuple of 9 integers giving local time.\n\ +The tuple items are:\n\ + year (four digits, e.g. 1998)\n\ + month (1-12)\n\ + day (1-31)\n\ + hours (0-23)\n\ + minutes (0-59)\n\ + seconds (0-59)\n\ + weekday (0-6, Monday is 0)\n\ + Julian day (day in the year, 1-366)\n\ + DST (Daylight Savings Time) flag (-1, 0 or 1)\n\ +If the DST flag is 0, the time is given in the regular time zone;\n\ +if it is 1, the time is given in the DST time zone;\n\ +if it is -1, mktime() should guess based on the date and time.\n\ +\n\ +Variables:\n\ +\n\ +timezone -- difference in seconds between UTC and local standard time\n\ +altzone -- difference in seconds between UTC and local DST time\n\ +daylight -- whether local time should reflect DST\n\ +tzname -- tuple of (standard time zone name, DST time zone name)\n\ +\n\ +Functions:\n\ +\n\ +time() -- return current time in seconds since the Epoch as a float\n\ +clock() -- return CPU time since process start as a float\n\ +sleep() -- delay for a number of seconds given as a float\n\ +gmtime() -- convert seconds since Epoch to UTC tuple\n\ +localtime() -- convert seconds since Epoch to local time tuple\n\ +asctime() -- convert time tuple to string\n\ +ctime() -- convert time in seconds to string\n\ +mktime() -- convert local time tuple to seconds since Epoch\n\ +strftime() -- convert time tuple to string according to format specification\n\ +strptime() -- parse string to time tuple according to format specification\n\ +tzset() -- change the local timezone"); + + +PyMODINIT_FUNC +inittime(void) +{ + PyObject *m; + char *p; + m = Py_InitModule3("time", time_methods, module_doc); + if (m == NULL) + return; + + /* Accept 2-digit dates unless PYTHONY2K is set and non-empty */ + p = Py_GETENV("PYTHONY2K"); + PyModule_AddIntConstant(m, "accept2dyear", (long) (!p || !*p)); + /* Squirrel away the module's dictionary for the y2k check */ + moddict = PyModule_GetDict(m); + Py_INCREF(moddict); + + /* Set, or reset, module variables like time.timezone */ + inittimezone(m); + +#ifdef MS_WINDOWS + /* Helper to allow interrupts for Windows. + If Ctrl+C event delivered while not sleeping + it will be ignored. + */ + main_thread = PyThread_get_thread_ident(); + hInterruptEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + SetConsoleCtrlHandler( PyCtrlHandler, TRUE); +#endif /* MS_WINDOWS */ + if (!initialized) { + PyStructSequence_InitType(&StructTimeType, + &struct_time_type_desc); + } + Py_INCREF(&StructTimeType); + PyModule_AddObject(m, "struct_time", (PyObject*) &StructTimeType); + initialized = 1; +} + + +/* Implement floattime() for various platforms */ + +static double +floattime(void) +{ + /* There are three ways to get the time: + (1) gettimeofday() -- resolution in microseconds + (2) ftime() -- resolution in milliseconds + (3) time() -- resolution in seconds + In all cases the return value is a float in seconds. + Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may + fail, so we fall back on ftime() or time(). + Note: clock resolution does not imply clock accuracy! */ +#ifdef HAVE_GETTIMEOFDAY + { + struct timeval t; +#ifdef GETTIMEOFDAY_NO_TZ + if (gettimeofday(&t) == 0) + return (double)t.tv_sec + t.tv_usec*0.000001; +#else /* !GETTIMEOFDAY_NO_TZ */ + if (gettimeofday(&t, (struct timezone *)NULL) == 0) + return (double)t.tv_sec + t.tv_usec*0.000001; +#endif /* !GETTIMEOFDAY_NO_TZ */ + } + +#endif /* !HAVE_GETTIMEOFDAY */ + { +#if defined(HAVE_FTIME) + struct timeb t; + ftime(&t); + return (double)t.time + (double)t.millitm * (double)0.001; +#else /* !HAVE_FTIME */ + time_t secs; + time(&secs); + return (double)secs; +#endif /* !HAVE_FTIME */ + } +} + + +/* Implement floatsleep() for various platforms. + When interrupted (or when another error occurs), return -1 and + set an exception; else return 0. */ + +static int +floatsleep(double secs) +{ +/* XXX Should test for MS_WINDOWS first! */ +#if defined(HAVE_SELECT) && !defined(__BEOS__) && !defined(__EMX__) + struct timeval t; + double frac; + frac = fmod(secs, 1.0); + secs = floor(secs); + t.tv_sec = (long)secs; + t.tv_usec = (long)(frac*1000000.0); + Py_BEGIN_ALLOW_THREADS + if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) { +#ifdef EINTR + if (errno != EINTR) { +#else + if (1) { +#endif + Py_BLOCK_THREADS + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + } + Py_END_ALLOW_THREADS +#elif defined(__WATCOMC__) && !defined(__QNX__) + /* XXX Can't interrupt this sleep */ + Py_BEGIN_ALLOW_THREADS + delay((int)(secs * 1000 + 0.5)); /* delay() uses milliseconds */ + Py_END_ALLOW_THREADS +#elif defined(MS_WINDOWS) + { + double millisecs = secs * 1000.0; + unsigned long ul_millis; + + if (millisecs > (double)ULONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "sleep length is too large"); + return -1; + } + Py_BEGIN_ALLOW_THREADS + /* Allow sleep(0) to maintain win32 semantics, and as decreed + * by Guido, only the main thread can be interrupted. + */ + ul_millis = (unsigned long)millisecs; + if (ul_millis == 0 || + main_thread != PyThread_get_thread_ident()) + Sleep(ul_millis); + else { + DWORD rc; + ResetEvent(hInterruptEvent); + rc = WaitForSingleObject(hInterruptEvent, ul_millis); + if (rc == WAIT_OBJECT_0) { + /* Yield to make sure real Python signal + * handler called. + */ + Sleep(1); + Py_BLOCK_THREADS + errno = EINTR; + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + } + Py_END_ALLOW_THREADS + } +#elif defined(PYOS_OS2) + /* This Sleep *IS* Interruptable by Exceptions */ + Py_BEGIN_ALLOW_THREADS + if (DosSleep(secs * 1000) != NO_ERROR) { + Py_BLOCK_THREADS + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + Py_END_ALLOW_THREADS +#elif defined(__BEOS__) + /* This sleep *CAN BE* interrupted. */ + { + if( secs <= 0.0 ) { + return; + } + + Py_BEGIN_ALLOW_THREADS + /* BeOS snooze() is in microseconds... */ + if( snooze( (bigtime_t)( secs * 1000.0 * 1000.0 ) ) == B_INTERRUPTED ) { + Py_BLOCK_THREADS + PyErr_SetFromErrno( PyExc_IOError ); + return -1; + } + Py_END_ALLOW_THREADS + } +#elif defined(RISCOS) + if (secs <= 0.0) + return 0; + Py_BEGIN_ALLOW_THREADS + /* This sleep *CAN BE* interrupted. */ + if ( riscos_sleep(secs) ) + return -1; + Py_END_ALLOW_THREADS +#elif defined(PLAN9) + { + double millisecs = secs * 1000.0; + if (millisecs > (double)LONG_MAX) { + PyErr_SetString(PyExc_OverflowError, "sleep length is too large"); + return -1; + } + /* This sleep *CAN BE* interrupted. */ + Py_BEGIN_ALLOW_THREADS + if(sleep((long)millisecs) < 0){ + Py_BLOCK_THREADS + PyErr_SetFromErrno(PyExc_IOError); + return -1; + } + Py_END_ALLOW_THREADS + } +#else + /* XXX Can't interrupt this sleep */ + Py_BEGIN_ALLOW_THREADS + sleep((int)secs); + Py_END_ALLOW_THREADS +#endif + + return 0; +} + + diff --git a/sys/src/cmd/python/Modules/timing.h b/sys/src/cmd/python/Modules/timing.h new file mode 100644 index 000000000..af26f1a6c --- /dev/null +++ b/sys/src/cmd/python/Modules/timing.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1993 George V. Neville-Neil + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by George V. Neville-Neil + * 4. The name, George Neville-Neil may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _TIMING_H_ +#define _TIMING_H_ + +#ifdef TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else /* !TIME_WITH_SYS_TIME */ +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else /* !HAVE_SYS_TIME_H */ +#include <time.h> +#endif /* !HAVE_SYS_TIME_H */ +#endif /* !TIME_WITH_SYS_TIME */ + +static struct timeval aftertp, beforetp; + +#define BEGINTIMING gettimeofday(&beforetp, NULL) + +#define ENDTIMING gettimeofday(&aftertp, NULL); \ + if(beforetp.tv_usec > aftertp.tv_usec) \ + { \ + aftertp.tv_usec += 1000000; \ + aftertp.tv_sec--; \ + } + +#define TIMINGUS (((aftertp.tv_sec - beforetp.tv_sec) * 1000000) + \ + (aftertp.tv_usec - beforetp.tv_usec)) + +#define TIMINGMS (((aftertp.tv_sec - beforetp.tv_sec) * 1000) + \ + ((aftertp.tv_usec - beforetp.tv_usec) / 1000)) + +#define TIMINGS ((aftertp.tv_sec - beforetp.tv_sec) + \ + (aftertp.tv_usec - beforetp.tv_usec) / 1000000) + +#endif /* _TIMING_H_ */ diff --git a/sys/src/cmd/python/Modules/timingmodule.c b/sys/src/cmd/python/Modules/timingmodule.c new file mode 100644 index 000000000..56e057a65 --- /dev/null +++ b/sys/src/cmd/python/Modules/timingmodule.c @@ -0,0 +1,58 @@ +/* + * Author: George V. Neville-Neil + */ + +#include "Python.h" + +/* Our stuff... */ +#include "timing.h" + +static PyObject * +start_timing(PyObject *self) +{ + Py_INCREF(Py_None); + BEGINTIMING; + return Py_None; +} + +static PyObject * +finish_timing(PyObject *self) +{ + ENDTIMING + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +seconds(PyObject *self) +{ + return PyInt_FromLong(TIMINGS); +} + +static PyObject * +milli(PyObject *self) +{ + return PyInt_FromLong(TIMINGMS); +} + +static PyObject * +micro(PyObject *self) +{ + return PyInt_FromLong(TIMINGUS); +} + + +static PyMethodDef timing_methods[] = { + {"start", (PyCFunction)start_timing, METH_NOARGS}, + {"finish", (PyCFunction)finish_timing, METH_NOARGS}, + {"seconds", (PyCFunction)seconds, METH_NOARGS}, + {"milli", (PyCFunction)milli, METH_NOARGS}, + {"micro", (PyCFunction)micro, METH_NOARGS}, + {NULL, NULL} +}; + + +PyMODINIT_FUNC inittiming(void) +{ + (void)Py_InitModule("timing", timing_methods); +} diff --git a/sys/src/cmd/python/Modules/tkappinit.c b/sys/src/cmd/python/Modules/tkappinit.c new file mode 100644 index 000000000..1c676325e --- /dev/null +++ b/sys/src/cmd/python/Modules/tkappinit.c @@ -0,0 +1,149 @@ +/* appinit.c -- Tcl and Tk application initialization. + + The function Tcl_AppInit() below initializes various Tcl packages. + It is called for each Tcl interpreter created by _tkinter.create(). + It needs to be compiled with -DWITH_<package> flags for each package + that you are statically linking with. You may have to add sections + for packages not yet listed below. + + Note that those packages for which Tcl_StaticPackage() is called with + a NULL first argument are known as "static loadable" packages to + Tcl but not actually initialized. To use these, you have to load + it explicitly, e.g. tkapp.eval("load {} Blt"). + */ + +#include <string.h> +#include <tcl.h> +#include <tk.h> + +int +Tcl_AppInit(Tcl_Interp *interp) +{ + Tk_Window main_window; + const char * _tkinter_skip_tk_init; + +#ifdef TK_AQUA +#ifndef MAX_PATH_LEN +#define MAX_PATH_LEN 1024 +#endif + char tclLibPath[MAX_PATH_LEN], tkLibPath[MAX_PATH_LEN]; + Tcl_Obj* pathPtr; + + /* pre- Tcl_Init code copied from tkMacOSXAppInit.c */ + Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tcllibrary", + tclLibPath, MAX_PATH_LEN, 0); + + if (tclLibPath[0] != '\0') { + Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); + } + + if (tclLibPath[0] != '\0') { + Tcl_SetVar(interp, "tcl_library", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tclDefaultLibrary", tclLibPath, TCL_GLOBAL_ONLY); + Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath, TCL_GLOBAL_ONLY); + } +#endif + if (Tcl_Init (interp) == TCL_ERROR) + return TCL_ERROR; + +#ifdef TK_AQUA + /* pre- Tk_Init code copied from tkMacOSXAppInit.c */ + Tk_MacOSXOpenBundleResources (interp, "com.tcltk.tklibrary", + tkLibPath, MAX_PATH_LEN, 1); + + if (tclLibPath[0] != '\0') { + pathPtr = Tcl_NewStringObj(tclLibPath, -1); + } else { + Tcl_Obj *pathPtr = TclGetLibraryPath(); + } + + if (tkLibPath[0] != '\0') { + Tcl_Obj *objPtr; + + Tcl_SetVar(interp, "tk_library", tkLibPath, TCL_GLOBAL_ONLY); + objPtr = Tcl_NewStringObj(tkLibPath, -1); + Tcl_ListObjAppendElement(NULL, pathPtr, objPtr); + } + + TclSetLibraryPath(pathPtr); +#endif + +#ifdef WITH_XXX + // Initialize modules that don't require Tk +#endif + + _tkinter_skip_tk_init = Tcl_GetVar(interp, "_tkinter_skip_tk_init", TCL_GLOBAL_ONLY); + if (_tkinter_skip_tk_init != NULL && strcmp(_tkinter_skip_tk_init, "1") == 0) { + return TCL_OK; + } + if (Tk_Init(interp) == TCL_ERROR) + return TCL_ERROR; + + main_window = Tk_MainWindow(interp); + +#ifdef TK_AQUA + TkMacOSXInitAppleEvents(interp); + TkMacOSXInitMenus(interp); +#endif + +#ifdef WITH_MOREBUTTONS + { + extern Tcl_CmdProc studButtonCmd; + extern Tcl_CmdProc triButtonCmd; + + Tcl_CreateCommand(interp, "studbutton", studButtonCmd, + (ClientData) main_window, NULL); + Tcl_CreateCommand(interp, "tributton", triButtonCmd, + (ClientData) main_window, NULL); + } +#endif + +#ifdef WITH_PIL /* 0.2b5 and later -- not yet released as of May 14 */ + { + extern void TkImaging_Init(Tcl_Interp *); + TkImaging_Init(interp); + /* XXX TkImaging_Init() doesn't have the right return type */ + /*Tcl_StaticPackage(interp, "Imaging", TkImaging_Init, NULL);*/ + } +#endif + +#ifdef WITH_PIL_OLD /* 0.2b4 and earlier */ + { + extern void TkImaging_Init(void); + /* XXX TkImaging_Init() doesn't have the right prototype */ + /*Tcl_StaticPackage(interp, "Imaging", TkImaging_Init, NULL);*/ + } +#endif + +#ifdef WITH_TIX + { + extern int Tix_Init(Tcl_Interp *interp); + extern int Tix_SafeInit(Tcl_Interp *interp); + Tcl_StaticPackage(NULL, "Tix", Tix_Init, Tix_SafeInit); + } +#endif + +#ifdef WITH_BLT + { + extern int Blt_Init(Tcl_Interp *); + extern int Blt_SafeInit(Tcl_Interp *); + Tcl_StaticPackage(NULL, "Blt", Blt_Init, Blt_SafeInit); + } +#endif + +#ifdef WITH_TOGL + { + /* XXX I've heard rumors that this doesn't work */ + extern int Togl_Init(Tcl_Interp *); + /* XXX Is there no Togl_SafeInit? */ + Tcl_StaticPackage(NULL, "Togl", Togl_Init, NULL); + } +#endif + +#ifdef WITH_XXX + +#endif + return TCL_OK; +} diff --git a/sys/src/cmd/python/Modules/unicodedata.c b/sys/src/cmd/python/Modules/unicodedata.c new file mode 100644 index 000000000..a30d30c8e --- /dev/null +++ b/sys/src/cmd/python/Modules/unicodedata.c @@ -0,0 +1,1223 @@ +/* ------------------------------------------------------------------------ + + unicodedata -- Provides access to the Unicode 4.1 data base. + + Data was extracted from the Unicode 4.1 UnicodeData.txt file. + + Written by Marc-Andre Lemburg (mal@lemburg.com). + Modified for Python 2.0 by Fredrik Lundh (fredrik@pythonware.com) + Modified by Martin v. Löwis (martin@v.loewis.de) + + Copyright (c) Corporation for National Research Initiatives. + + ------------------------------------------------------------------------ */ + +#include "Python.h" +#include "ucnhash.h" +#include "structmember.h" + +/* character properties */ + +typedef struct { + const unsigned char category; /* index into + _PyUnicode_CategoryNames */ + const unsigned char combining; /* combining class value 0 - 255 */ + const unsigned char bidirectional; /* index into + _PyUnicode_BidirectionalNames */ + const unsigned char mirrored; /* true if mirrored in bidir mode */ + const unsigned char east_asian_width; /* index into + _PyUnicode_EastAsianWidth */ +} _PyUnicode_DatabaseRecord; + +typedef struct change_record { + /* sequence of fields should be the same as in merge_old_version */ + const unsigned char bidir_changed; + const unsigned char category_changed; + const unsigned char decimal_changed; + const int numeric_changed; +} change_record; + +/* data file generated by Tools/unicode/makeunicodedata.py */ +#include "unicodedata_db.h" + +static const _PyUnicode_DatabaseRecord* +_getrecord_ex(Py_UCS4 code) +{ + int index; + if (code >= 0x110000) + index = 0; + else { + index = index1[(code>>SHIFT)]; + index = index2[(index<<SHIFT)+(code&((1<<SHIFT)-1))]; + } + + return &_PyUnicode_Database_Records[index]; +} + +static const _PyUnicode_DatabaseRecord* +_getrecord(PyUnicodeObject* v) +{ + return _getrecord_ex(*PyUnicode_AS_UNICODE(v)); +} + +/* ------------- Previous-version API ------------------------------------- */ +typedef struct previous_version { + PyObject_HEAD + const char *name; + const change_record* (*getrecord)(Py_UCS4); + Py_UCS4 (*normalization)(Py_UCS4); +} PreviousDBVersion; + +#define get_old_record(self, v) ((((PreviousDBVersion*)self)->getrecord)(v)) + +static PyMemberDef DB_members[] = { + {"unidata_version", T_STRING, offsetof(PreviousDBVersion, name), READONLY}, + {NULL} +}; + +/* forward declaration */ +static PyTypeObject UCD_Type; + +static PyObject* +new_previous_version(const char*name, const change_record* (*getrecord)(Py_UCS4), + Py_UCS4 (*normalization)(Py_UCS4)) +{ + PreviousDBVersion *self; + self = PyObject_New(PreviousDBVersion, &UCD_Type); + if (self == NULL) + return NULL; + self->name = name; + self->getrecord = getrecord; + self->normalization = normalization; + return (PyObject*)self; +} + +/* --- Module API --------------------------------------------------------- */ + +PyDoc_STRVAR(unicodedata_decimal__doc__, +"decimal(unichr[, default])\n\ +\n\ +Returns the decimal value assigned to the Unicode character unichr\n\ +as integer. If no such value is defined, default is returned, or, if\n\ +not given, ValueError is raised."); + +static PyObject * +unicodedata_decimal(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + PyObject *defobj = NULL; + int have_old = 0; + long rc; + + if (!PyArg_ParseTuple(args, "O!|O:decimal", &PyUnicode_Type, &v, &defobj)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed == 0) { + /* unassigned */ + have_old = 1; + rc = -1; + } + else if (old->decimal_changed != 0xFF) { + have_old = 1; + rc = old->decimal_changed; + } + } + + if (!have_old) + rc = Py_UNICODE_TODECIMAL(*PyUnicode_AS_UNICODE(v)); + if (rc < 0) { + if (defobj == NULL) { + PyErr_SetString(PyExc_ValueError, + "not a decimal"); + return NULL; + } + else { + Py_INCREF(defobj); + return defobj; + } + } + return PyInt_FromLong(rc); +} + +PyDoc_STRVAR(unicodedata_digit__doc__, +"digit(unichr[, default])\n\ +\n\ +Returns the digit value assigned to the Unicode character unichr as\n\ +integer. If no such value is defined, default is returned, or, if\n\ +not given, ValueError is raised."); + +static PyObject * +unicodedata_digit(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + PyObject *defobj = NULL; + long rc; + + if (!PyArg_ParseTuple(args, "O!|O:digit", &PyUnicode_Type, &v, &defobj)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + rc = Py_UNICODE_TODIGIT(*PyUnicode_AS_UNICODE(v)); + if (rc < 0) { + if (defobj == NULL) { + PyErr_SetString(PyExc_ValueError, "not a digit"); + return NULL; + } + else { + Py_INCREF(defobj); + return defobj; + } + } + return PyInt_FromLong(rc); +} + +PyDoc_STRVAR(unicodedata_numeric__doc__, +"numeric(unichr[, default])\n\ +\n\ +Returns the numeric value assigned to the Unicode character unichr\n\ +as float. If no such value is defined, default is returned, or, if\n\ +not given, ValueError is raised."); + +static PyObject * +unicodedata_numeric(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + PyObject *defobj = NULL; + int have_old = 0; + double rc; + + if (!PyArg_ParseTuple(args, "O!|O:numeric", &PyUnicode_Type, &v, &defobj)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed == 0) { + /* unassigned */ + have_old = 1; + rc = -1.0; + } + else if (old->decimal_changed != 0xFF) { + have_old = 1; + rc = old->decimal_changed; + } + } + + if (!have_old) + rc = Py_UNICODE_TONUMERIC(*PyUnicode_AS_UNICODE(v)); + if (rc == -1.0) { + if (defobj == NULL) { + PyErr_SetString(PyExc_ValueError, "not a numeric character"); + return NULL; + } + else { + Py_INCREF(defobj); + return defobj; + } + } + return PyFloat_FromDouble(rc); +} + +PyDoc_STRVAR(unicodedata_category__doc__, +"category(unichr)\n\ +\n\ +Returns the general category assigned to the Unicode character\n\ +unichr as string."); + +static PyObject * +unicodedata_category(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + int index; + + if (!PyArg_ParseTuple(args, "O!:category", + &PyUnicode_Type, &v)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + index = (int) _getrecord(v)->category; + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed != 0xFF) + index = old->category_changed; + } + return PyString_FromString(_PyUnicode_CategoryNames[index]); +} + +PyDoc_STRVAR(unicodedata_bidirectional__doc__, +"bidirectional(unichr)\n\ +\n\ +Returns the bidirectional category assigned to the Unicode character\n\ +unichr as string. If no such value is defined, an empty string is\n\ +returned."); + +static PyObject * +unicodedata_bidirectional(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + int index; + + if (!PyArg_ParseTuple(args, "O!:bidirectional", + &PyUnicode_Type, &v)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + index = (int) _getrecord(v)->bidirectional; + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed == 0) + index = 0; /* unassigned */ + else if (old->bidir_changed != 0xFF) + index = old->bidir_changed; + } + return PyString_FromString(_PyUnicode_BidirectionalNames[index]); +} + +PyDoc_STRVAR(unicodedata_combining__doc__, +"combining(unichr)\n\ +\n\ +Returns the canonical combining class assigned to the Unicode\n\ +character unichr as integer. Returns 0 if no combining class is\n\ +defined."); + +static PyObject * +unicodedata_combining(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + int index; + + if (!PyArg_ParseTuple(args, "O!:combining", + &PyUnicode_Type, &v)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + index = (int) _getrecord(v)->combining; + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed == 0) + index = 0; /* unassigned */ + } + return PyInt_FromLong(index); +} + +PyDoc_STRVAR(unicodedata_mirrored__doc__, +"mirrored(unichr)\n\ +\n\ +Returns the mirrored property assigned to the Unicode character\n\ +unichr as integer. Returns 1 if the character has been identified as\n\ +a \"mirrored\" character in bidirectional text, 0 otherwise."); + +static PyObject * +unicodedata_mirrored(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + int index; + + if (!PyArg_ParseTuple(args, "O!:mirrored", + &PyUnicode_Type, &v)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + index = (int) _getrecord(v)->mirrored; + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed == 0) + index = 0; /* unassigned */ + } + return PyInt_FromLong(index); +} + +PyDoc_STRVAR(unicodedata_east_asian_width__doc__, +"east_asian_width(unichr)\n\ +\n\ +Returns the east asian width assigned to the Unicode character\n\ +unichr as string."); + +static PyObject * +unicodedata_east_asian_width(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + int index; + + if (!PyArg_ParseTuple(args, "O!:east_asian_width", + &PyUnicode_Type, &v)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + index = (int) _getrecord(v)->east_asian_width; + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed == 0) + index = 0; /* unassigned */ + } + return PyString_FromString(_PyUnicode_EastAsianWidthNames[index]); +} + +PyDoc_STRVAR(unicodedata_decomposition__doc__, +"decomposition(unichr)\n\ +\n\ +Returns the character decomposition mapping assigned to the Unicode\n\ +character unichr as string. An empty string is returned in case no\n\ +such mapping is defined."); + +static PyObject * +unicodedata_decomposition(PyObject *self, PyObject *args) +{ + PyUnicodeObject *v; + char decomp[256]; + int code, index, count, i; + unsigned int prefix_index; + + if (!PyArg_ParseTuple(args, "O!:decomposition", + &PyUnicode_Type, &v)) + return NULL; + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + + code = (int) *PyUnicode_AS_UNICODE(v); + + if (self) { + const change_record *old = get_old_record(self, *PyUnicode_AS_UNICODE(v)); + if (old->category_changed == 0) + return PyString_FromString(""); /* unassigned */ + } + + if (code < 0 || code >= 0x110000) + index = 0; + else { + index = decomp_index1[(code>>DECOMP_SHIFT)]; + index = decomp_index2[(index<<DECOMP_SHIFT)+ + (code&((1<<DECOMP_SHIFT)-1))]; + } + + /* high byte is number of hex bytes (usually one or two), low byte + is prefix code (from*/ + count = decomp_data[index] >> 8; + + /* XXX: could allocate the PyString up front instead + (strlen(prefix) + 5 * count + 1 bytes) */ + + /* Based on how index is calculated above and decomp_data is generated + from Tools/unicode/makeunicodedata.py, it should not be possible + to overflow decomp_prefix. */ + prefix_index = decomp_data[index] & 255; + assert(prefix_index < (sizeof(decomp_prefix)/sizeof(*decomp_prefix))); + + /* copy prefix */ + i = strlen(decomp_prefix[prefix_index]); + memcpy(decomp, decomp_prefix[prefix_index], i); + + while (count-- > 0) { + if (i) + decomp[i++] = ' '; + assert((size_t)i < sizeof(decomp)); + PyOS_snprintf(decomp + i, sizeof(decomp) - i, "%04X", + decomp_data[++index]); + i += strlen(decomp + i); + } + + decomp[i] = '\0'; + + return PyString_FromString(decomp); +} + +static void +get_decomp_record(PyObject *self, Py_UCS4 code, int *index, int *prefix, int *count) +{ + if (code >= 0x110000) { + *index = 0; + } else if (self && get_old_record(self, code)->category_changed==0) { + /* unassigned in old version */ + *index = 0; + } + else { + *index = decomp_index1[(code>>DECOMP_SHIFT)]; + *index = decomp_index2[(*index<<DECOMP_SHIFT)+ + (code&((1<<DECOMP_SHIFT)-1))]; + } + + /* high byte is number of hex bytes (usually one or two), low byte + is prefix code (from*/ + *count = decomp_data[*index] >> 8; + *prefix = decomp_data[*index] & 255; + + (*index)++; +} + +#define SBase 0xAC00 +#define LBase 0x1100 +#define VBase 0x1161 +#define TBase 0x11A7 +#define LCount 19 +#define VCount 21 +#define TCount 28 +#define NCount (VCount*TCount) +#define SCount (LCount*NCount) + +static PyObject* +nfd_nfkd(PyObject *self, PyObject *input, int k) +{ + PyObject *result; + Py_UNICODE *i, *end, *o; + /* Longest decomposition in Unicode 3.2: U+FDFA */ + Py_UNICODE stack[20]; + Py_ssize_t space, isize; + int index, prefix, count, stackptr; + unsigned char prev, cur; + + stackptr = 0; + isize = PyUnicode_GET_SIZE(input); + /* Overallocate atmost 10 characters. */ + space = (isize > 10 ? 10 : isize) + isize; + result = PyUnicode_FromUnicode(NULL, space); + if (!result) + return NULL; + i = PyUnicode_AS_UNICODE(input); + end = i + isize; + o = PyUnicode_AS_UNICODE(result); + + while (i < end) { + stack[stackptr++] = *i++; + while(stackptr) { + Py_UNICODE code = stack[--stackptr]; + /* Hangul Decomposition adds three characters in + a single step, so we need atleast that much room. */ + if (space < 3) { + Py_ssize_t newsize = PyString_GET_SIZE(result) + 10; + space += 10; + if (PyUnicode_Resize(&result, newsize) == -1) + return NULL; + o = PyUnicode_AS_UNICODE(result) + newsize - space; + } + /* Hangul Decomposition. */ + if (SBase <= code && code < (SBase+SCount)) { + int SIndex = code - SBase; + int L = LBase + SIndex / NCount; + int V = VBase + (SIndex % NCount) / TCount; + int T = TBase + SIndex % TCount; + *o++ = L; + *o++ = V; + space -= 2; + if (T != TBase) { + *o++ = T; + space --; + } + continue; + } + /* normalization changes */ + if (self) { + Py_UCS4 value = ((PreviousDBVersion*)self)->normalization(code); + if (value != 0) { + stack[stackptr++] = value; + continue; + } + } + + /* Other decompositions. */ + get_decomp_record(self, code, &index, &prefix, &count); + + /* Copy character if it is not decomposable, or has a + compatibility decomposition, but we do NFD. */ + if (!count || (prefix && !k)) { + *o++ = code; + space--; + continue; + } + /* Copy decomposition onto the stack, in reverse + order. */ + while(count) { + code = decomp_data[index + (--count)]; + stack[stackptr++] = code; + } + } + } + + /* Drop overallocation. Cannot fail. */ + PyUnicode_Resize(&result, PyUnicode_GET_SIZE(result) - space); + + /* Sort canonically. */ + i = PyUnicode_AS_UNICODE(result); + prev = _getrecord_ex(*i)->combining; + end = i + PyUnicode_GET_SIZE(result); + for (i++; i < end; i++) { + cur = _getrecord_ex(*i)->combining; + if (prev == 0 || cur == 0 || prev <= cur) { + prev = cur; + continue; + } + /* Non-canonical order. Need to switch *i with previous. */ + o = i - 1; + while (1) { + Py_UNICODE tmp = o[1]; + o[1] = o[0]; + o[0] = tmp; + o--; + if (o < PyUnicode_AS_UNICODE(result)) + break; + prev = _getrecord_ex(*o)->combining; + if (prev == 0 || prev <= cur) + break; + } + prev = _getrecord_ex(*i)->combining; + } + return result; +} + +static int +find_nfc_index(PyObject *self, struct reindex* nfc, Py_UNICODE code) +{ + int index; + for (index = 0; nfc[index].start; index++) { + int start = nfc[index].start; + if (code < start) + return -1; + if (code <= start + nfc[index].count) { + int delta = code - start; + return nfc[index].index + delta; + } + } + return -1; +} + +static PyObject* +nfc_nfkc(PyObject *self, PyObject *input, int k) +{ + PyObject *result; + Py_UNICODE *i, *i1, *o, *end; + int f,l,index,index1,comb; + Py_UNICODE code; + Py_UNICODE *skipped[20]; + int cskipped = 0; + + result = nfd_nfkd(self, input, k); + if (!result) + return NULL; + + /* We are going to modify result in-place. + If nfd_nfkd is changed to sometimes return the input, + this code needs to be reviewed. */ + assert(result != input); + + i = PyUnicode_AS_UNICODE(result); + end = i + PyUnicode_GET_SIZE(result); + o = PyUnicode_AS_UNICODE(result); + + again: + while (i < end) { + for (index = 0; index < cskipped; index++) { + if (skipped[index] == i) { + /* *i character is skipped. + Remove from list. */ + skipped[index] = skipped[cskipped-1]; + cskipped--; + i++; + goto again; /* continue while */ + } + } + /* Hangul Composition. We don't need to check for <LV,T> + pairs, since we always have decomposed data. */ + if (LBase <= *i && *i < (LBase+LCount) && + i + 1 < end && + VBase <= i[1] && i[1] <= (VBase+VCount)) { + int LIndex, VIndex; + LIndex = i[0] - LBase; + VIndex = i[1] - VBase; + code = SBase + (LIndex*VCount+VIndex)*TCount; + i+=2; + if (i < end && + TBase <= *i && *i <= (TBase+TCount)) { + code += *i-TBase; + i++; + } + *o++ = code; + continue; + } + + f = find_nfc_index(self, nfc_first, *i); + if (f == -1) { + *o++ = *i++; + continue; + } + /* Find next unblocked character. */ + i1 = i+1; + comb = 0; + while (i1 < end) { + int comb1 = _getrecord_ex(*i1)->combining; + if (comb1 && comb == comb1) { + /* Character is blocked. */ + i1++; + continue; + } + l = find_nfc_index(self, nfc_last, *i1); + /* *i1 cannot be combined with *i. If *i1 + is a starter, we don't need to look further. + Otherwise, record the combining class. */ + if (l == -1) { + not_combinable: + if (comb1 == 0) + break; + comb = comb1; + i1++; + continue; + } + index = f*TOTAL_LAST + l; + index1 = comp_index[index >> COMP_SHIFT]; + code = comp_data[(index1<<COMP_SHIFT)+ + (index&((1<<COMP_SHIFT)-1))]; + if (code == 0) + goto not_combinable; + + /* Replace the original character. */ + *i = code; + /* Mark the second character unused. */ + skipped[cskipped++] = i1; + i1++; + f = find_nfc_index(self, nfc_first, *i); + if (f == -1) + break; + } + *o++ = *i++; + } + if (o != end) + PyUnicode_Resize(&result, o - PyUnicode_AS_UNICODE(result)); + return result; +} + +PyDoc_STRVAR(unicodedata_normalize__doc__, +"normalize(form, unistr)\n\ +\n\ +Return the normal form 'form' for the Unicode string unistr. Valid\n\ +values for form are 'NFC', 'NFKC', 'NFD', and 'NFKD'."); + +static PyObject* +unicodedata_normalize(PyObject *self, PyObject *args) +{ + char *form; + PyObject *input; + + if(!PyArg_ParseTuple(args, "sO!:normalize", + &form, &PyUnicode_Type, &input)) + return NULL; + + if (PyUnicode_GetSize(input) == 0) { + /* Special case empty input strings, since resizing + them later would cause internal errors. */ + Py_INCREF(input); + return input; + } + + if (strcmp(form, "NFC") == 0) + return nfc_nfkc(self, input, 0); + if (strcmp(form, "NFKC") == 0) + return nfc_nfkc(self, input, 1); + if (strcmp(form, "NFD") == 0) + return nfd_nfkd(self, input, 0); + if (strcmp(form, "NFKD") == 0) + return nfd_nfkd(self, input, 1); + PyErr_SetString(PyExc_ValueError, "invalid normalization form"); + return NULL; +} + +/* -------------------------------------------------------------------- */ +/* unicode character name tables */ + +/* data file generated by Tools/unicode/makeunicodedata.py */ +#include "unicodename_db.h" + +/* -------------------------------------------------------------------- */ +/* database code (cut and pasted from the unidb package) */ + +static unsigned long +_gethash(const char *s, int len, int scale) +{ + int i; + unsigned long h = 0; + unsigned long ix; + for (i = 0; i < len; i++) { + h = (h * scale) + (unsigned char) toupper(Py_CHARMASK(s[i])); + ix = h & 0xff000000; + if (ix) + h = (h ^ ((ix>>24) & 0xff)) & 0x00ffffff; + } + return h; +} + +static char *hangul_syllables[][3] = { + { "G", "A", "" }, + { "GG", "AE", "G" }, + { "N", "YA", "GG" }, + { "D", "YAE", "GS" }, + { "DD", "EO", "N", }, + { "R", "E", "NJ" }, + { "M", "YEO", "NH" }, + { "B", "YE", "D" }, + { "BB", "O", "L" }, + { "S", "WA", "LG" }, + { "SS", "WAE", "LM" }, + { "", "OE", "LB" }, + { "J", "YO", "LS" }, + { "JJ", "U", "LT" }, + { "C", "WEO", "LP" }, + { "K", "WE", "LH" }, + { "T", "WI", "M" }, + { "P", "YU", "B" }, + { "H", "EU", "BS" }, + { 0, "YI", "S" }, + { 0, "I", "SS" }, + { 0, 0, "NG" }, + { 0, 0, "J" }, + { 0, 0, "C" }, + { 0, 0, "K" }, + { 0, 0, "T" }, + { 0, 0, "P" }, + { 0, 0, "H" } +}; + +static int +is_unified_ideograph(Py_UCS4 code) +{ + return ( + (0x3400 <= code && code <= 0x4DB5) || /* CJK Ideograph Extension A */ + (0x4E00 <= code && code <= 0x9FBB) || /* CJK Ideograph */ + (0x20000 <= code && code <= 0x2A6D6));/* CJK Ideograph Extension B */ +} + +static int +_getucname(PyObject *self, Py_UCS4 code, char* buffer, int buflen) +{ + int offset; + int i; + int word; + unsigned char* w; + + if (code >= 0x110000) + return 0; + + if (self) { + const change_record *old = get_old_record(self, code); + if (old->category_changed == 0) { + /* unassigned */ + return 0; + } + } + + if (SBase <= code && code < SBase+SCount) { + /* Hangul syllable. */ + int SIndex = code - SBase; + int L = SIndex / NCount; + int V = (SIndex % NCount) / TCount; + int T = SIndex % TCount; + + if (buflen < 27) + /* Worst case: HANGUL SYLLABLE <10chars>. */ + return 0; + strcpy(buffer, "HANGUL SYLLABLE "); + buffer += 16; + strcpy(buffer, hangul_syllables[L][0]); + buffer += strlen(hangul_syllables[L][0]); + strcpy(buffer, hangul_syllables[V][1]); + buffer += strlen(hangul_syllables[V][1]); + strcpy(buffer, hangul_syllables[T][2]); + buffer += strlen(hangul_syllables[T][2]); + *buffer = '\0'; + return 1; + } + + if (is_unified_ideograph(code)) { + if (buflen < 28) + /* Worst case: CJK UNIFIED IDEOGRAPH-20000 */ + return 0; + sprintf(buffer, "CJK UNIFIED IDEOGRAPH-%X", code); + return 1; + } + + /* get offset into phrasebook */ + offset = phrasebook_offset1[(code>>phrasebook_shift)]; + offset = phrasebook_offset2[(offset<<phrasebook_shift) + + (code&((1<<phrasebook_shift)-1))]; + if (!offset) + return 0; + + i = 0; + + for (;;) { + /* get word index */ + word = phrasebook[offset] - phrasebook_short; + if (word >= 0) { + word = (word << 8) + phrasebook[offset+1]; + offset += 2; + } else + word = phrasebook[offset++]; + if (i) { + if (i > buflen) + return 0; /* buffer overflow */ + buffer[i++] = ' '; + } + /* copy word string from lexicon. the last character in the + word has bit 7 set. the last word in a string ends with + 0x80 */ + w = lexicon + lexicon_offset[word]; + while (*w < 128) { + if (i >= buflen) + return 0; /* buffer overflow */ + buffer[i++] = *w++; + } + if (i >= buflen) + return 0; /* buffer overflow */ + buffer[i++] = *w & 127; + if (*w == 128) + break; /* end of word */ + } + + return 1; +} + +static int +_cmpname(PyObject *self, int code, const char* name, int namelen) +{ + /* check if code corresponds to the given name */ + int i; + char buffer[NAME_MAXLEN]; + if (!_getucname(self, code, buffer, sizeof(buffer))) + return 0; + for (i = 0; i < namelen; i++) { + if (toupper(Py_CHARMASK(name[i])) != buffer[i]) + return 0; + } + return buffer[namelen] == '\0'; +} + +static void +find_syllable(const char *str, int *len, int *pos, int count, int column) +{ + int i, len1; + *len = -1; + for (i = 0; i < count; i++) { + char *s = hangul_syllables[i][column]; + len1 = strlen(s); + if (len1 <= *len) + continue; + if (strncmp(str, s, len1) == 0) { + *len = len1; + *pos = i; + } + } + if (*len == -1) { + *len = 0; + } +} + +static int +_getcode(PyObject* self, const char* name, int namelen, Py_UCS4* code) +{ + unsigned int h, v; + unsigned int mask = code_size-1; + unsigned int i, incr; + + /* Check for hangul syllables. */ + if (strncmp(name, "HANGUL SYLLABLE ", 16) == 0) { + int len, L = -1, V = -1, T = -1; + const char *pos = name + 16; + find_syllable(pos, &len, &L, LCount, 0); + pos += len; + find_syllable(pos, &len, &V, VCount, 1); + pos += len; + find_syllable(pos, &len, &T, TCount, 2); + pos += len; + if (L != -1 && V != -1 && T != -1 && pos-name == namelen) { + *code = SBase + (L*VCount+V)*TCount + T; + return 1; + } + /* Otherwise, it's an illegal syllable name. */ + return 0; + } + + /* Check for unified ideographs. */ + if (strncmp(name, "CJK UNIFIED IDEOGRAPH-", 22) == 0) { + /* Four or five hexdigits must follow. */ + v = 0; + name += 22; + namelen -= 22; + if (namelen != 4 && namelen != 5) + return 0; + while (namelen--) { + v *= 16; + if (*name >= '0' && *name <= '9') + v += *name - '0'; + else if (*name >= 'A' && *name <= 'F') + v += *name - 'A' + 10; + else + return 0; + name++; + } + if (!is_unified_ideograph(v)) + return 0; + *code = v; + return 1; + } + + /* the following is the same as python's dictionary lookup, with + only minor changes. see the makeunicodedata script for more + details */ + + h = (unsigned int) _gethash(name, namelen, code_magic); + i = (~h) & mask; + v = code_hash[i]; + if (!v) + return 0; + if (_cmpname(self, v, name, namelen)) { + *code = v; + return 1; + } + incr = (h ^ (h >> 3)) & mask; + if (!incr) + incr = mask; + for (;;) { + i = (i + incr) & mask; + v = code_hash[i]; + if (!v) + return 0; + if (_cmpname(self, v, name, namelen)) { + *code = v; + return 1; + } + incr = incr << 1; + if (incr > mask) + incr = incr ^ code_poly; + } +} + +static const _PyUnicode_Name_CAPI hashAPI = +{ + sizeof(_PyUnicode_Name_CAPI), + _getucname, + _getcode +}; + +/* -------------------------------------------------------------------- */ +/* Python bindings */ + +PyDoc_STRVAR(unicodedata_name__doc__, +"name(unichr[, default])\n\ +Returns the name assigned to the Unicode character unichr as a\n\ +string. If no name is defined, default is returned, or, if not\n\ +given, ValueError is raised."); + +static PyObject * +unicodedata_name(PyObject* self, PyObject* args) +{ + char name[NAME_MAXLEN]; + + PyUnicodeObject* v; + PyObject* defobj = NULL; + if (!PyArg_ParseTuple(args, "O!|O:name", &PyUnicode_Type, &v, &defobj)) + return NULL; + + if (PyUnicode_GET_SIZE(v) != 1) { + PyErr_SetString(PyExc_TypeError, + "need a single Unicode character as parameter"); + return NULL; + } + + if (!_getucname(self, (Py_UCS4) *PyUnicode_AS_UNICODE(v), + name, sizeof(name))) { + if (defobj == NULL) { + PyErr_SetString(PyExc_ValueError, "no such name"); + return NULL; + } + else { + Py_INCREF(defobj); + return defobj; + } + } + + return Py_BuildValue("s", name); +} + +PyDoc_STRVAR(unicodedata_lookup__doc__, +"lookup(name)\n\ +\n\ +Look up character by name. If a character with the\n\ +given name is found, return the corresponding Unicode\n\ +character. If not found, KeyError is raised."); + +static PyObject * +unicodedata_lookup(PyObject* self, PyObject* args) +{ + Py_UCS4 code; + Py_UNICODE str[1]; + char errbuf[256]; + + char* name; + int namelen; + if (!PyArg_ParseTuple(args, "s#:lookup", &name, &namelen)) + return NULL; + + if (!_getcode(self, name, namelen, &code)) { + /* XXX(nnorwitz): why are we allocating for the error msg? + Why not always use snprintf? */ + char fmt[] = "undefined character name '%s'"; + char *buf = PyMem_MALLOC(sizeof(fmt) + namelen); + if (buf) + sprintf(buf, fmt, name); + else { + buf = errbuf; + PyOS_snprintf(buf, sizeof(errbuf), fmt, name); + } + PyErr_SetString(PyExc_KeyError, buf); + if (buf != errbuf) + PyMem_FREE(buf); + return NULL; + } + + str[0] = (Py_UNICODE) code; + return PyUnicode_FromUnicode(str, 1); +} + +/* XXX Add doc strings. */ + +static PyMethodDef unicodedata_functions[] = { + {"decimal", unicodedata_decimal, METH_VARARGS, unicodedata_decimal__doc__}, + {"digit", unicodedata_digit, METH_VARARGS, unicodedata_digit__doc__}, + {"numeric", unicodedata_numeric, METH_VARARGS, unicodedata_numeric__doc__}, + {"category", unicodedata_category, METH_VARARGS, + unicodedata_category__doc__}, + {"bidirectional", unicodedata_bidirectional, METH_VARARGS, + unicodedata_bidirectional__doc__}, + {"combining", unicodedata_combining, METH_VARARGS, + unicodedata_combining__doc__}, + {"mirrored", unicodedata_mirrored, METH_VARARGS, + unicodedata_mirrored__doc__}, + {"east_asian_width", unicodedata_east_asian_width, METH_VARARGS, + unicodedata_east_asian_width__doc__}, + {"decomposition", unicodedata_decomposition, METH_VARARGS, + unicodedata_decomposition__doc__}, + {"name", unicodedata_name, METH_VARARGS, unicodedata_name__doc__}, + {"lookup", unicodedata_lookup, METH_VARARGS, unicodedata_lookup__doc__}, + {"normalize", unicodedata_normalize, METH_VARARGS, + unicodedata_normalize__doc__}, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject UCD_Type = { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "unicodedata.UCD", /*tp_name*/ + sizeof(PreviousDBVersion), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyObject_Del, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + PyObject_GenericGetAttr,/*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + unicodedata_functions, /*tp_methods*/ + DB_members, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +PyDoc_STRVAR(unicodedata_docstring, +"This module provides access to the Unicode Character Database which\n\ +defines character properties for all Unicode characters. The data in\n\ +this database is based on the UnicodeData.txt file version\n\ +4.1.0 which is publically available from ftp://ftp.unicode.org/.\n\ +\n\ +The module uses the same names and symbols as defined by the\n\ +UnicodeData File Format 4.1.0 (see\n\ +http://www.unicode.org/Public/4.1.0/ucd/UCD.html)."); + +PyMODINIT_FUNC +initunicodedata(void) +{ + PyObject *m, *v; + + UCD_Type.ob_type = &PyType_Type; + + m = Py_InitModule3( + "unicodedata", unicodedata_functions, unicodedata_docstring); + if (!m) + return; + + PyModule_AddStringConstant(m, "unidata_version", UNIDATA_VERSION); + Py_INCREF(&UCD_Type); + PyModule_AddObject(m, "UCD", (PyObject*)&UCD_Type); + + /* Previous versions */ + v = new_previous_version("3.2.0", get_change_3_2_0, normalization_3_2_0); + if (v != NULL) + PyModule_AddObject(m, "ucd_3_2_0", v); + + /* Export C API */ + v = PyCObject_FromVoidPtr((void *) &hashAPI, NULL); + if (v != NULL) + PyModule_AddObject(m, "ucnhash_CAPI", v); +} + +/* +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/sys/src/cmd/python/Modules/unicodedata_db.h b/sys/src/cmd/python/Modules/unicodedata_db.h new file mode 100644 index 000000000..d68466a48 --- /dev/null +++ b/sys/src/cmd/python/Modules/unicodedata_db.h @@ -0,0 +1,5135 @@ +/* this file was generated by Tools/unicode/makeunicodedata.py 2.5 */ + +#define UNIDATA_VERSION "4.1.0" +/* a list of unique database records */ +const _PyUnicode_DatabaseRecord _PyUnicode_Database_Records[] = { + {0, 0, 0, 0, 0}, + {13, 0, 15, 0, 5}, + {13, 0, 17, 0, 5}, + {13, 0, 16, 0, 5}, + {13, 0, 18, 0, 5}, + {10, 0, 18, 0, 3}, + {26, 0, 19, 0, 3}, + {26, 0, 11, 0, 3}, + {28, 0, 11, 0, 3}, + {22, 0, 19, 1, 3}, + {23, 0, 19, 1, 3}, + {27, 0, 10, 0, 3}, + {26, 0, 13, 0, 3}, + {21, 0, 10, 0, 3}, + {7, 0, 9, 0, 3}, + {27, 0, 19, 1, 3}, + {27, 0, 19, 0, 3}, + {1, 0, 1, 0, 3}, + {29, 0, 19, 0, 3}, + {20, 0, 19, 0, 3}, + {2, 0, 1, 0, 3}, + {10, 0, 13, 0, 5}, + {26, 0, 19, 0, 4}, + {28, 0, 11, 0, 4}, + {30, 0, 19, 0, 3}, + {30, 0, 19, 0, 4}, + {29, 0, 19, 0, 4}, + {30, 0, 19, 0, 5}, + {2, 0, 1, 0, 4}, + {24, 0, 19, 1, 5}, + {14, 0, 15, 0, 4}, + {30, 0, 11, 0, 4}, + {27, 0, 11, 0, 4}, + {9, 0, 9, 0, 4}, + {2, 0, 1, 0, 5}, + {25, 0, 19, 1, 5}, + {9, 0, 19, 0, 4}, + {1, 0, 1, 0, 5}, + {1, 0, 1, 0, 4}, + {27, 0, 19, 0, 4}, + {19, 0, 1, 0, 5}, + {3, 0, 1, 0, 5}, + {18, 0, 1, 0, 5}, + {18, 0, 19, 0, 5}, + {29, 0, 19, 0, 5}, + {18, 0, 19, 0, 4}, + {18, 0, 1, 0, 4}, + {4, 230, 14, 0, 4}, + {4, 232, 14, 0, 4}, + {4, 220, 14, 0, 4}, + {4, 216, 14, 0, 4}, + {4, 202, 14, 0, 4}, + {4, 1, 14, 0, 4}, + {4, 240, 14, 0, 4}, + {4, 0, 14, 0, 4}, + {4, 233, 14, 0, 4}, + {4, 234, 14, 0, 4}, + {26, 0, 19, 0, 5}, + {27, 0, 19, 0, 5}, + {30, 0, 1, 0, 5}, + {4, 230, 14, 0, 5}, + {6, 0, 14, 0, 5}, + {26, 0, 1, 0, 5}, + {21, 0, 19, 0, 5}, + {4, 220, 14, 0, 5}, + {4, 222, 14, 0, 5}, + {4, 228, 14, 0, 5}, + {4, 10, 14, 0, 5}, + {4, 11, 14, 0, 5}, + {4, 12, 14, 0, 5}, + {4, 13, 14, 0, 5}, + {4, 14, 14, 0, 5}, + {4, 15, 14, 0, 5}, + {4, 16, 14, 0, 5}, + {4, 17, 14, 0, 5}, + {4, 18, 14, 0, 5}, + {4, 19, 14, 0, 5}, + {4, 20, 14, 0, 5}, + {4, 21, 14, 0, 5}, + {4, 22, 14, 0, 5}, + {26, 0, 4, 0, 5}, + {4, 23, 14, 0, 5}, + {4, 24, 14, 0, 5}, + {4, 25, 14, 0, 5}, + {19, 0, 4, 0, 5}, + {14, 0, 5, 0, 5}, + {28, 0, 5, 0, 5}, + {26, 0, 13, 0, 5}, + {26, 0, 5, 0, 5}, + {19, 0, 5, 0, 5}, + {18, 0, 5, 0, 5}, + {4, 27, 14, 0, 5}, + {4, 28, 14, 0, 5}, + {4, 29, 14, 0, 5}, + {4, 30, 14, 0, 5}, + {4, 31, 14, 0, 5}, + {4, 32, 14, 0, 5}, + {4, 33, 14, 0, 5}, + {4, 34, 14, 0, 5}, + {7, 0, 12, 0, 5}, + {26, 0, 11, 0, 5}, + {26, 0, 12, 0, 5}, + {4, 35, 14, 0, 5}, + {7, 0, 9, 0, 5}, + {30, 0, 5, 0, 5}, + {14, 0, 15, 0, 5}, + {4, 36, 14, 0, 5}, + {4, 0, 14, 0, 5}, + {5, 0, 1, 0, 5}, + {4, 7, 14, 0, 5}, + {4, 9, 14, 0, 5}, + {7, 0, 1, 0, 5}, + {28, 0, 11, 0, 5}, + {9, 0, 1, 0, 5}, + {4, 84, 14, 0, 5}, + {4, 91, 14, 0, 5}, + {4, 0, 1, 0, 5}, + {4, 103, 14, 0, 5}, + {4, 107, 14, 0, 5}, + {4, 118, 14, 0, 5}, + {4, 122, 14, 0, 5}, + {4, 216, 14, 0, 5}, + {22, 0, 19, 0, 5}, + {23, 0, 19, 0, 5}, + {4, 129, 14, 0, 5}, + {4, 130, 14, 0, 5}, + {4, 132, 14, 0, 5}, + {19, 0, 1, 0, 2}, + {10, 0, 18, 0, 5}, + {8, 0, 1, 0, 5}, + {14, 0, 1, 0, 5}, + {9, 0, 19, 0, 5}, + {5, 0, 14, 0, 5}, + {14, 0, 4, 0, 5}, + {21, 0, 19, 0, 4}, + {24, 0, 19, 0, 4}, + {25, 0, 19, 0, 4}, + {24, 0, 19, 0, 5}, + {11, 0, 18, 0, 5}, + {12, 0, 16, 0, 5}, + {14, 0, 2, 0, 5}, + {14, 0, 6, 0, 5}, + {14, 0, 8, 0, 5}, + {14, 0, 3, 0, 5}, + {14, 0, 7, 0, 5}, + {26, 0, 11, 0, 4}, + {20, 0, 19, 0, 5}, + {27, 0, 13, 0, 5}, + {22, 0, 19, 1, 5}, + {23, 0, 19, 1, 5}, + {9, 0, 9, 0, 5}, + {27, 0, 10, 0, 5}, + {28, 0, 11, 0, 1}, + {4, 1, 14, 0, 5}, + {30, 0, 11, 0, 5}, + {27, 0, 19, 1, 5}, + {8, 0, 1, 0, 4}, + {27, 0, 19, 1, 4}, + {27, 0, 11, 0, 5}, + {22, 0, 19, 1, 2}, + {23, 0, 19, 1, 2}, + {30, 0, 1, 0, 4}, + {30, 0, 19, 0, 2}, + {10, 0, 18, 0, 0}, + {26, 0, 19, 0, 2}, + {18, 0, 1, 0, 2}, + {8, 0, 1, 0, 2}, + {21, 0, 19, 0, 2}, + {22, 0, 19, 0, 2}, + {23, 0, 19, 0, 2}, + {4, 218, 14, 0, 2}, + {4, 228, 14, 0, 2}, + {4, 232, 14, 0, 2}, + {4, 222, 14, 0, 2}, + {4, 224, 14, 0, 2}, + {4, 8, 14, 0, 2}, + {29, 0, 19, 0, 2}, + {30, 0, 1, 0, 2}, + {9, 0, 1, 0, 2}, + {9, 0, 19, 0, 2}, + {15, 0, 1, 0, 5}, + {16, 0, 1, 0, 4}, + {4, 26, 14, 0, 5}, + {20, 0, 19, 0, 2}, + {26, 0, 13, 0, 2}, + {26, 0, 11, 0, 2}, + {27, 0, 10, 0, 2}, + {21, 0, 10, 0, 2}, + {27, 0, 19, 0, 2}, + {28, 0, 11, 0, 2}, + {26, 0, 19, 0, 0}, + {26, 0, 11, 0, 0}, + {28, 0, 11, 0, 0}, + {22, 0, 19, 1, 0}, + {23, 0, 19, 1, 0}, + {27, 0, 10, 0, 0}, + {26, 0, 13, 0, 0}, + {21, 0, 10, 0, 0}, + {7, 0, 9, 0, 0}, + {27, 0, 19, 1, 0}, + {27, 0, 19, 0, 0}, + {1, 0, 1, 0, 0}, + {29, 0, 19, 0, 0}, + {20, 0, 19, 0, 0}, + {2, 0, 1, 0, 0}, + {26, 0, 19, 0, 1}, + {22, 0, 19, 1, 1}, + {23, 0, 19, 1, 1}, + {19, 0, 1, 0, 1}, + {18, 0, 1, 0, 1}, + {30, 0, 19, 0, 0}, + {30, 0, 19, 0, 1}, + {27, 0, 19, 0, 1}, + {14, 0, 19, 0, 5}, + {8, 0, 19, 0, 5}, + {9, 0, 4, 0, 5}, + {5, 216, 1, 0, 5}, + {5, 226, 1, 0, 5}, + {27, 0, 1, 0, 5}, +}; + +/* Reindexing of NFC first characters. */ +#define TOTAL_FIRST 356 +#define TOTAL_LAST 53 +struct reindex{int start;short count,index;}; +struct reindex nfc_first[] = { + { 60, 2, 0}, + { 65, 15, 3}, + { 82, 8, 19}, + { 97, 15, 28}, + { 114, 8, 44}, + { 168, 0, 53}, + { 194, 0, 54}, + { 196, 3, 55}, + { 202, 0, 59}, + { 207, 0, 60}, + { 212, 2, 61}, + { 216, 0, 64}, + { 220, 0, 65}, + { 226, 0, 66}, + { 228, 3, 67}, + { 234, 0, 71}, + { 239, 0, 72}, + { 244, 2, 73}, + { 248, 0, 76}, + { 252, 0, 77}, + { 258, 1, 78}, + { 274, 1, 80}, + { 332, 1, 82}, + { 346, 1, 84}, + { 352, 1, 86}, + { 360, 3, 88}, + { 383, 0, 92}, + { 416, 1, 93}, + { 431, 1, 95}, + { 439, 0, 97}, + { 490, 1, 98}, + { 550, 3, 100}, + { 558, 1, 104}, + { 658, 0, 106}, + { 913, 0, 107}, + { 917, 0, 108}, + { 919, 0, 109}, + { 921, 0, 110}, + { 927, 0, 111}, + { 929, 0, 112}, + { 933, 0, 113}, + { 937, 0, 114}, + { 940, 0, 115}, + { 942, 0, 116}, + { 945, 0, 117}, + { 949, 0, 118}, + { 951, 0, 119}, + { 953, 0, 120}, + { 959, 0, 121}, + { 961, 0, 122}, + { 965, 0, 123}, + { 969, 2, 124}, + { 974, 0, 127}, + { 978, 0, 128}, + { 1030, 0, 129}, + { 1040, 0, 130}, + { 1043, 0, 131}, + { 1045, 3, 132}, + { 1050, 0, 136}, + { 1054, 0, 137}, + { 1059, 0, 138}, + { 1063, 0, 139}, + { 1067, 0, 140}, + { 1069, 0, 141}, + { 1072, 0, 142}, + { 1075, 0, 143}, + { 1077, 3, 144}, + { 1082, 0, 148}, + { 1086, 0, 149}, + { 1091, 0, 150}, + { 1095, 0, 151}, + { 1099, 0, 152}, + { 1101, 0, 153}, + { 1110, 0, 154}, + { 1140, 1, 155}, + { 1240, 1, 157}, + { 1256, 1, 159}, + { 1575, 0, 161}, + { 1608, 0, 162}, + { 1610, 0, 163}, + { 1729, 0, 164}, + { 1746, 0, 165}, + { 1749, 0, 166}, + { 2344, 0, 167}, + { 2352, 0, 168}, + { 2355, 0, 169}, + { 2503, 0, 170}, + { 2887, 0, 171}, + { 2962, 0, 172}, + { 3014, 1, 173}, + { 3142, 0, 175}, + { 3263, 0, 176}, + { 3270, 0, 177}, + { 3274, 0, 178}, + { 3398, 1, 179}, + { 3545, 0, 181}, + { 3548, 0, 182}, + { 4133, 0, 183}, + { 7734, 1, 184}, + { 7770, 1, 186}, + { 7778, 1, 188}, + { 7840, 1, 190}, + { 7864, 1, 192}, + { 7884, 1, 194}, + { 7936, 17, 196}, + { 7960, 1, 214}, + { 7968, 17, 216}, + { 7992, 1, 234}, + { 8000, 1, 236}, + { 8008, 1, 238}, + { 8016, 1, 240}, + { 8025, 0, 242}, + { 8032, 16, 243}, + { 8052, 0, 260}, + { 8060, 0, 261}, + { 8118, 0, 262}, + { 8127, 0, 263}, + { 8134, 0, 264}, + { 8182, 0, 265}, + { 8190, 0, 266}, + { 8592, 0, 267}, + { 8594, 0, 268}, + { 8596, 0, 269}, + { 8656, 0, 270}, + { 8658, 0, 271}, + { 8660, 0, 272}, + { 8707, 0, 273}, + { 8712, 0, 274}, + { 8715, 0, 275}, + { 8739, 0, 276}, + { 8741, 0, 277}, + { 8764, 0, 278}, + { 8771, 0, 279}, + { 8773, 0, 280}, + { 8776, 0, 281}, + { 8781, 0, 282}, + { 8801, 0, 283}, + { 8804, 1, 284}, + { 8818, 1, 286}, + { 8822, 1, 288}, + { 8826, 3, 290}, + { 8834, 1, 294}, + { 8838, 1, 296}, + { 8849, 1, 298}, + { 8866, 0, 300}, + { 8872, 1, 301}, + { 8875, 0, 303}, + { 8882, 3, 304}, + { 12358, 0, 308}, + { 12363, 0, 309}, + { 12365, 0, 310}, + { 12367, 0, 311}, + { 12369, 0, 312}, + { 12371, 0, 313}, + { 12373, 0, 314}, + { 12375, 0, 315}, + { 12377, 0, 316}, + { 12379, 0, 317}, + { 12381, 0, 318}, + { 12383, 0, 319}, + { 12385, 0, 320}, + { 12388, 0, 321}, + { 12390, 0, 322}, + { 12392, 0, 323}, + { 12399, 0, 324}, + { 12402, 0, 325}, + { 12405, 0, 326}, + { 12408, 0, 327}, + { 12411, 0, 328}, + { 12445, 0, 329}, + { 12454, 0, 330}, + { 12459, 0, 331}, + { 12461, 0, 332}, + { 12463, 0, 333}, + { 12465, 0, 334}, + { 12467, 0, 335}, + { 12469, 0, 336}, + { 12471, 0, 337}, + { 12473, 0, 338}, + { 12475, 0, 339}, + { 12477, 0, 340}, + { 12479, 0, 341}, + { 12481, 0, 342}, + { 12484, 0, 343}, + { 12486, 0, 344}, + { 12488, 0, 345}, + { 12495, 0, 346}, + { 12498, 0, 347}, + { 12501, 0, 348}, + { 12504, 0, 349}, + { 12507, 0, 350}, + { 12527, 3, 351}, + { 12541, 0, 355}, + {0,0,0} +}; + +struct reindex nfc_last[] = { + { 768, 4, 0}, + { 774, 6, 5}, + { 783, 0, 12}, + { 785, 0, 13}, + { 787, 1, 14}, + { 795, 0, 16}, + { 803, 5, 17}, + { 813, 1, 23}, + { 816, 1, 25}, + { 824, 0, 27}, + { 834, 0, 28}, + { 837, 0, 29}, + { 1619, 2, 30}, + { 2364, 0, 33}, + { 2494, 0, 34}, + { 2519, 0, 35}, + { 2878, 0, 36}, + { 2902, 1, 37}, + { 3006, 0, 39}, + { 3031, 0, 40}, + { 3158, 0, 41}, + { 3266, 0, 42}, + { 3285, 1, 43}, + { 3390, 0, 45}, + { 3415, 0, 46}, + { 3530, 0, 47}, + { 3535, 0, 48}, + { 3551, 0, 49}, + { 4142, 0, 50}, + { 12441, 1, 51}, + {0,0,0} +}; + +/* string literals */ +const char *_PyUnicode_CategoryNames[] = { + "Cn", + "Lu", + "Ll", + "Lt", + "Mn", + "Mc", + "Me", + "Nd", + "Nl", + "No", + "Zs", + "Zl", + "Zp", + "Cc", + "Cf", + "Cs", + "Co", + "Cn", + "Lm", + "Lo", + "Pc", + "Pd", + "Ps", + "Pe", + "Pi", + "Pf", + "Po", + "Sm", + "Sc", + "Sk", + "So", + NULL +}; +const char *_PyUnicode_BidirectionalNames[] = { + "", + "L", + "LRE", + "LRO", + "R", + "AL", + "RLE", + "RLO", + "PDF", + "EN", + "ES", + "ET", + "AN", + "CS", + "NSM", + "BN", + "B", + "S", + "WS", + "ON", + NULL +}; +const char *_PyUnicode_EastAsianWidthNames[] = { + "F", + "H", + "W", + "Na", + "A", + "N", + NULL +}; +static const char *decomp_prefix[] = { + "", + "<noBreak>", + "<compat>", + "<super>", + "<fraction>", + "<sub>", + "<font>", + "<circle>", + "<wide>", + "<vertical>", + "<square>", + "<isolated>", + "<final>", + "<initial>", + "<medial>", + "<small>", + "<narrow>", + NULL +}; +/* index tables for the database records */ +#define SHIFT 8 +static unsigned char index1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 8, 8, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 52, 53, 50, 50, 50, 54, 8, 8, + 55, 56, 8, 8, 8, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 57, 58, 58, 58, 58, 58, 58, + 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 50, 60, 61, 62, 63, 64, 65, 66, 67, + 8, 68, 69, 8, 8, 8, 70, 8, 71, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 72, 73, 74, 75, 76, 77, 78, + 79, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 80, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 50, 50, 81, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 82, 83, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 84, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 84, +}; + +static unsigned char index2[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 4, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 3, 2, 5, 6, 6, 7, 8, 7, 6, 6, 9, 10, 6, 11, 12, 13, 12, + 12, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 6, 15, 16, 15, 6, 6, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 9, 6, 10, 18, 19, 18, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 9, 16, 10, 16, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 21, 22, 8, 8, 23, 8, 24, + 25, 26, 27, 28, 29, 16, 30, 25, 18, 31, 32, 33, 33, 26, 34, 25, 22, 26, + 33, 28, 35, 36, 36, 36, 22, 37, 37, 37, 37, 37, 37, 38, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 38, 37, 37, 37, 37, 37, 37, 39, 38, 37, 37, 37, 37, + 37, 38, 28, 28, 28, 34, 34, 34, 34, 28, 34, 28, 28, 28, 34, 28, 28, 34, + 34, 28, 34, 28, 28, 34, 34, 34, 39, 28, 28, 28, 34, 28, 34, 28, 34, 37, + 28, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 28, 37, + 28, 37, 34, 37, 34, 37, 34, 37, 28, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 38, 28, 37, 34, 37, 28, 37, 34, 37, 34, 37, 28, 38, 28, 37, 34, 37, + 34, 28, 37, 34, 37, 34, 37, 34, 38, 28, 38, 28, 37, 28, 37, 34, 37, 28, + 28, 38, 28, 37, 28, 37, 34, 37, 34, 38, 28, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 38, 28, 37, 34, 37, 28, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 37, 34, 37, 34, 37, 34, + 34, 34, 37, 37, 34, 37, 34, 37, 37, 34, 37, 37, 37, 34, 34, 37, 37, 37, + 37, 34, 37, 37, 34, 37, 37, 37, 34, 34, 34, 37, 37, 34, 37, 37, 34, 37, + 34, 37, 34, 37, 37, 34, 37, 34, 34, 37, 34, 37, 37, 34, 37, 37, 37, 34, + 37, 34, 37, 37, 34, 34, 40, 37, 34, 34, 34, 40, 40, 40, 40, 37, 41, 34, + 37, 41, 34, 37, 41, 34, 37, 28, 37, 28, 37, 28, 37, 28, 37, 28, 37, 28, + 37, 28, 37, 28, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 34, 37, 41, 34, 37, 34, 37, 37, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 34, 34, 34, 34, 34, 34, 37, 37, 34, 37, 37, 34, 34, 37, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 43, 43, 42, 42, 42, 42, 42, 42, 42, 44, 44, 26, 44, 43, + 45, 43, 45, 45, 45, 43, 45, 43, 43, 46, 42, 44, 44, 44, 44, 44, 44, 26, + 26, 26, 26, 44, 26, 44, 26, 42, 42, 42, 42, 42, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 42, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 48, 49, 49, 49, 49, 48, 50, 49, 49, 49, 49, 49, + 51, 51, 49, 49, 49, 49, 51, 51, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 52, 52, 52, 52, 52, 49, 49, 49, 49, 47, 47, 47, 47, 47, 47, 47, 47, + 53, 47, 49, 49, 49, 47, 47, 47, 49, 49, 54, 47, 47, 47, 49, 49, 49, 49, + 47, 48, 49, 49, 47, 55, 56, 56, 55, 56, 56, 55, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 0, 0, 0, 0, 44, 44, 0, 0, 0, 0, 42, 0, 0, 0, + 57, 0, 0, 0, 0, 0, 44, 44, 37, 57, 37, 37, 37, 0, 37, 0, 37, 37, 34, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 0, 38, + 38, 38, 38, 38, 38, 38, 37, 37, 34, 34, 34, 34, 34, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 34, 28, 28, 28, 28, 28, + 28, 28, 34, 34, 34, 34, 34, 0, 34, 34, 37, 37, 37, 34, 34, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 34, 34, 34, 34, 37, 34, 58, 37, 34, 37, 37, 34, 34, 37, + 37, 37, 37, 38, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 34, 28, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 59, 60, 60, 60, 60, 0, 61, 61, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 0, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 0, 0, 0, 0, 0, 0, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 0, 0, 42, 62, 62, 62, 62, 62, 62, + 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 0, 62, 63, 0, 0, 0, 0, 0, 0, 64, 60, 60, 60, 60, 64, 60, + 60, 60, 65, 64, 60, 60, 60, 60, 60, 60, 64, 64, 64, 64, 64, 64, 60, 60, + 64, 60, 60, 65, 66, 60, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 0, 77, + 78, 79, 80, 81, 80, 82, 83, 80, 60, 64, 80, 75, 0, 0, 0, 0, 0, 0, 0, 0, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, 0, 0, 0, 84, 84, 84, 80, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 85, 85, 85, 85, 0, 0, 0, 0, 0, 0, 0, 86, + 87, 88, 27, 27, 60, 60, 60, 60, 60, 60, 0, 0, 0, 0, 0, 88, 0, 0, 88, 88, + 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 0, 0, 0, 0, 0, 90, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 91, 92, 93, 94, 95, 96, 97, 98, 60, 60, 64, 64, + 60, 60, 60, 60, 60, 64, 60, 60, 0, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 100, 101, 101, 88, 89, 89, 102, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 88, 89, 60, 60, 60, 60, 60, 60, 60, 85, 61, 60, 60, 60, 60, 64, 60, 90, + 90, 60, 60, 27, 64, 60, 60, 64, 89, 89, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 89, 89, 89, 104, 104, 89, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 0, 105, 89, 106, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 60, 64, 60, 60, 64, 60, 60, 64, 64, 64, 60, 64, 64, + 60, 64, 60, 60, 60, 64, 60, 64, 60, 64, 60, 64, 60, 60, 0, 0, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 107, 107, 108, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 109, 40, 108, 108, 108, 107, + 107, 107, 107, 107, 107, 107, 107, 108, 108, 108, 108, 110, 0, 0, 40, 60, + 64, 60, 60, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 107, 107, + 62, 62, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 62, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 107, 108, 108, 0, 40, 40, 40, 40, + 40, 40, 40, 40, 0, 0, 40, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, + 40, 40, 40, 0, 40, 0, 0, 0, 40, 40, 40, 40, 0, 0, 109, 40, 108, 108, 108, + 107, 107, 107, 107, 0, 0, 108, 108, 0, 0, 108, 108, 110, 40, 0, 0, 0, 0, + 0, 0, 0, 0, 108, 0, 0, 0, 0, 40, 40, 0, 40, 40, 40, 107, 107, 0, 0, 111, + 111, 111, 111, 111, 111, 111, 111, 111, 111, 40, 40, 112, 112, 113, 113, + 113, 113, 113, 113, 59, 0, 0, 0, 0, 0, 0, 107, 107, 108, 0, 40, 40, 40, + 40, 40, 40, 0, 0, 0, 0, 40, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, + 40, 40, 40, 0, 40, 40, 0, 40, 40, 0, 40, 40, 0, 0, 109, 0, 108, 108, 108, + 107, 107, 0, 0, 0, 0, 107, 107, 0, 0, 107, 107, 110, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 40, 40, 40, 40, 0, 40, 0, 0, 0, 0, 0, 0, 0, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 107, 107, 40, 40, 40, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 107, 107, 108, 0, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 0, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 0, 40, + 40, 0, 40, 40, 40, 40, 40, 0, 0, 109, 40, 108, 108, 108, 107, 107, 107, + 107, 107, 0, 107, 107, 108, 0, 108, 108, 110, 0, 0, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 107, 107, 0, 0, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 107, 108, 108, 0, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 40, 40, + 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 0, 40, 40, + 40, 40, 40, 0, 0, 109, 40, 108, 107, 108, 107, 107, 107, 0, 0, 0, 108, + 108, 0, 0, 108, 108, 110, 0, 0, 0, 0, 0, 0, 0, 0, 107, 108, 0, 0, 0, 0, + 40, 40, 0, 40, 40, 40, 0, 0, 0, 0, 111, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 59, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 107, 40, 0, 40, 40, 40, 40, 40, 40, 0, 0, 0, 40, 40, 40, 0, 40, 40, 40, + 40, 0, 0, 0, 40, 40, 0, 40, 0, 40, 40, 0, 0, 0, 40, 40, 0, 0, 0, 40, 40, + 40, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, + 108, 108, 107, 108, 108, 0, 0, 0, 108, 108, 108, 0, 108, 108, 108, 110, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 113, 113, 113, 27, 27, + 27, 27, 27, 27, 112, 27, 0, 0, 0, 0, 0, 0, 108, 108, 108, 0, 40, 40, 40, + 40, 40, 40, 40, 40, 0, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 0, 0, 0, 0, 107, 107, + 107, 108, 108, 108, 108, 0, 107, 107, 107, 0, 107, 107, 107, 110, 0, 0, + 0, 0, 0, 0, 0, 114, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, + 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 108, 0, 40, 40, 40, 40, 40, 40, 40, + 40, 0, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 0, 40, 40, 40, 40, 40, 0, 0, 109, 40, 108, 116, 108, 108, + 108, 108, 108, 0, 116, 108, 108, 0, 108, 108, 107, 110, 0, 0, 0, 0, 0, 0, + 0, 108, 108, 0, 0, 0, 0, 0, 0, 0, 40, 0, 40, 40, 0, 0, 0, 0, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 108, 0, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, + 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 108, 108, 108, 107, 107, 107, 0, + 0, 108, 108, 108, 0, 108, 108, 108, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, + 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 0, 0, 0, 111, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 108, 108, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 0, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 110, 0, 0, + 0, 0, 108, 108, 108, 107, 107, 107, 0, 107, 0, 108, 108, 108, 108, 108, + 108, 108, 108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, + 108, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 107, 40, 40, 107, 107, 107, 107, 117, 117, 110, 0, 0, + 0, 0, 112, 40, 40, 40, 40, 40, 40, 42, 107, 118, 118, 118, 118, 107, 107, + 107, 62, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 62, 62, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 0, 40, 0, 0, 40, 40, 0, 40, 0, + 0, 40, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, + 0, 40, 40, 40, 0, 40, 0, 40, 0, 0, 40, 40, 0, 40, 40, 40, 40, 107, 40, + 40, 107, 107, 107, 107, 119, 119, 0, 107, 107, 40, 0, 0, 40, 40, 40, 40, + 40, 0, 42, 0, 120, 120, 120, 120, 107, 107, 0, 0, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 0, 0, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 40, 59, 59, 59, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 59, 59, 59, 59, 59, 64, 64, 59, 59, 59, 59, 59, 59, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 59, 64, 59, 64, 59, 121, 122, 123, 122, 123, 108, 108, 40, + 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 124, 125, 107, 126, 107, 107, + 107, 107, 107, 125, 125, 125, 125, 107, 108, 125, 107, 60, 60, 110, 62, + 60, 60, 40, 40, 40, 40, 0, 0, 0, 0, 107, 107, 107, 107, 107, 107, 107, + 107, 0, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 107, 107, 107, 107, 107, 107, 107, 107, 0, 59, 59, 59, 59, 59, 59, + 59, 59, 64, 59, 59, 59, 59, 59, 59, 0, 0, 59, 62, 62, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 0, 40, 40, + 0, 108, 107, 107, 107, 107, 108, 107, 0, 0, 0, 107, 109, 108, 110, 0, 0, + 0, 0, 0, 0, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 62, 62, 62, + 62, 62, 62, 40, 40, 40, 40, 40, 40, 108, 108, 107, 107, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 62, 42, 0, 0, 0, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 0, 0, 0, 0, 0, 127, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, + 0, 40, 0, 40, 40, 40, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 0, + 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, + 40, 40, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, 0, 40, 0, 40, 40, 40, 40, + 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 0, 40, 40, 40, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 0, 0, 0, 0, 60, 59, 62, 62, 62, 62, 62, 62, 62, 62, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, + 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 62, 62, 40, 40, 40, 40, + 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 122, 123, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 62, 62, 62, 129, 129, 129, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 107, 107, 110, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 107, 107, 110, 62, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 107, 107, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 0, 40, 40, 40, 0, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 130, + 130, 108, 107, 107, 107, 107, 107, 107, 107, 108, 108, 108, 108, 108, + 108, 108, 108, 107, 108, 108, 107, 107, 107, 107, 107, 107, 107, 107, + 107, 110, 107, 62, 62, 62, 42, 62, 62, 62, 112, 40, 60, 0, 0, 111, 111, + 111, 111, 111, 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 0, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 0, 0, 0, 0, 0, 0, 57, 57, 57, 57, 57, + 57, 63, 57, 57, 57, 57, 107, 107, 107, 128, 0, 111, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 42, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 0, 0, 0, 107, 107, 107, 108, 108, 108, 108, 107, + 107, 132, 132, 132, 0, 0, 0, 0, 108, 108, 107, 108, 108, 108, 108, 108, + 108, 65, 60, 64, 0, 0, 0, 0, 27, 0, 0, 0, 57, 57, 111, 111, 111, 111, + 111, 111, 111, 111, 111, 111, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 0, 0, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 108, 108, 108, 108, 108, 108, 108, 108, + 108, 108, 108, 108, 108, 108, 108, 108, 108, 40, 40, 40, 40, 40, 40, 40, + 108, 108, 0, 0, 0, 0, 0, 0, 111, 111, 111, 111, 111, 111, 111, 111, 111, + 111, 0, 0, 0, 0, 57, 57, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 60, 64, 108, 108, 108, 0, 0, 62, 62, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 42, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 60, 60, + 64, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 34, 34, + 34, 34, 34, 34, 0, 0, 0, 0, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, + 34, 37, 34, 37, 34, 37, 34, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 34, + 34, 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 0, 0, 37, 37, + 37, 37, 37, 37, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, + 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, + 37, 34, 34, 34, 34, 34, 34, 0, 0, 37, 37, 37, 37, 37, 37, 0, 0, 34, 34, + 34, 34, 34, 34, 34, 34, 0, 37, 0, 37, 0, 37, 0, 37, 34, 34, 34, 34, 34, + 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 0, 0, 34, 34, 34, 34, 34, 34, 34, 34, 41, 41, + 41, 41, 41, 41, 41, 41, 34, 34, 34, 34, 34, 34, 34, 34, 41, 41, 41, 41, + 41, 41, 41, 41, 34, 34, 34, 34, 34, 34, 34, 34, 41, 41, 41, 41, 41, 41, + 41, 41, 34, 34, 34, 34, 34, 0, 34, 34, 37, 37, 37, 37, 41, 44, 34, 44, + 44, 44, 34, 34, 34, 0, 34, 34, 37, 37, 37, 37, 41, 44, 44, 44, 34, 34, + 34, 34, 0, 0, 34, 34, 37, 37, 37, 37, 0, 44, 44, 44, 34, 34, 34, 34, 34, + 34, 34, 34, 37, 37, 37, 37, 37, 44, 44, 44, 0, 0, 34, 34, 34, 0, 34, 34, + 37, 37, 37, 37, 41, 44, 44, 0, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 105, 105, 105, 130, 133, 134, 63, 63, 134, 134, 134, 22, + 57, 135, 136, 122, 137, 135, 136, 122, 137, 22, 22, 22, 57, 22, 22, 22, + 22, 138, 139, 140, 141, 142, 143, 144, 21, 145, 100, 145, 145, 100, 22, + 57, 57, 57, 29, 35, 22, 57, 57, 22, 146, 146, 57, 57, 57, 147, 148, 149, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 58, 57, 146, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 128, 105, 105, 105, 105, 0, 0, 0, 0, 0, 0, 105, + 105, 105, 105, 105, 105, 150, 34, 0, 0, 33, 150, 150, 150, 150, 150, 151, + 151, 58, 148, 149, 28, 150, 33, 33, 33, 33, 150, 150, 150, 150, 150, 151, + 151, 58, 148, 149, 0, 42, 42, 42, 42, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 112, 112, 112, 112, 112, 112, 112, 112, 112, 152, 112, 112, 23, 112, + 112, 112, 112, 112, 112, 112, 112, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 60, 153, 153, 60, 60, + 60, 60, 153, 153, 153, 60, 60, 61, 61, 61, 61, 60, 61, 61, 61, 153, 153, + 60, 64, 60, 153, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 27, 27, 37, 25, 27, 25, 27, 37, 27, 25, 34, 37, 37, 37, 34, 34, + 37, 37, 37, 28, 27, 37, 25, 27, 27, 37, 37, 37, 37, 37, 27, 27, 27, 25, + 25, 27, 37, 27, 38, 27, 37, 27, 37, 38, 37, 37, 154, 34, 37, 37, 27, 37, + 34, 40, 40, 40, 40, 34, 27, 27, 34, 34, 37, 37, 155, 58, 58, 58, 58, 37, + 34, 34, 34, 34, 27, 58, 27, 0, 0, 0, 0, 0, 0, 36, 36, 131, 131, 131, 131, + 131, 131, 36, 36, 36, 36, 131, 156, 156, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 129, 129, 129, 129, 156, 156, 156, 156, 156, 156, + 156, 156, 156, 156, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 39, 39, 39, 39, 25, 25, 25, 25, 25, + 58, 58, 27, 27, 27, 27, 58, 27, 27, 58, 27, 27, 58, 27, 27, 27, 27, 27, + 27, 27, 58, 27, 27, 27, 27, 27, 27, 27, 27, 27, 25, 25, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 58, 58, + 27, 27, 39, 27, 39, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 25, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 39, 155, 157, 157, 155, + 58, 58, 39, 157, 155, 155, 157, 155, 155, 58, 39, 58, 157, 151, 158, 58, + 157, 155, 58, 58, 58, 157, 155, 155, 157, 39, 157, 157, 155, 155, 39, + 155, 39, 155, 39, 39, 39, 39, 157, 157, 155, 157, 155, 155, 155, 155, + 155, 39, 39, 39, 39, 58, 155, 58, 155, 157, 157, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 157, 155, 155, 155, 157, 58, 58, 58, 58, 58, + 157, 155, 155, 155, 58, 58, 58, 58, 58, 58, 58, 58, 58, 155, 157, 39, + 155, 58, 157, 157, 157, 157, 155, 155, 157, 157, 58, 58, 157, 157, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 157, 157, 155, 155, 157, 157, 155, 155, 155, 155, 155, 58, + 58, 155, 155, 155, 155, 58, 58, 39, 58, 58, 155, 39, 58, 58, 58, 58, 58, + 58, 58, 58, 155, 155, 58, 39, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 58, 58, 58, 58, + 58, 155, 157, 58, 58, 58, 58, 58, 58, 58, 58, 58, 155, 155, 155, 155, + 155, 58, 58, 155, 155, 58, 58, 58, 58, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 58, 58, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 27, 27, 27, 27, 27, 27, 27, 27, 155, 155, + 155, 155, 27, 27, 27, 27, 27, 27, 25, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 155, 155, 27, 27, 27, 27, 27, 27, 27, 159, 160, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 27, 58, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 59, 27, 27, 27, + 27, 27, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 122, 123, 57, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, + 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 131, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 27, 27, 27, 27, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 25, 25, + 27, 25, 25, 25, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, 27, 27, 25, 25, + 27, 27, 25, 39, 27, 27, 27, 27, 25, 25, 27, 27, 25, 39, 27, 27, 27, 27, + 25, 25, 25, 27, 27, 25, 27, 27, 25, 25, 25, 25, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 25, 25, 25, 25, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 25, 27, 27, 27, 27, 27, 27, 27, 27, 58, 58, 58, 58, + 58, 58, 58, 58, 27, 27, 27, 27, 27, 25, 25, 27, 27, 25, 27, 27, 27, 27, + 25, 25, 27, 27, 27, 27, 25, 25, 27, 27, 27, 27, 27, 27, 25, 27, 25, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 25, 27, 25, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 25, 25, 27, 25, 25, 25, 27, 25, + 25, 25, 25, 27, 25, 25, 27, 39, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, + 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 59, 27, 27, 27, 27, + 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 27, 27, 27, 27, 0, 27, 27, 27, 27, 0, 0, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 25, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 0, 27, 0, 27, 27, 27, 27, 0, 0, 0, 27, 0, + 27, 27, 27, 27, 27, 27, 27, 0, 0, 27, 27, 27, 27, 27, 27, 27, 148, 149, + 148, 149, 148, 149, 148, 149, 148, 149, 148, 149, 148, 149, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 131, 131, 131, 131, 131, 131, 131, 131, 131, + 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 27, 0, 0, 0, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 0, 155, 58, 58, 155, 155, 148, 149, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 58, 58, 58, 155, 155, 155, 155, 58, 58, 58, 58, 58, 155, 155, 155, 58, + 58, 58, 155, 155, 155, 155, 9, 10, 9, 10, 9, 10, 0, 0, 0, 0, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 148, 149, 9, 10, 148, 149, 148, 149, 148, 149, 148, 149, + 148, 149, 148, 149, 148, 149, 148, 149, 148, 149, 58, 58, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 58, 58, 58, 58, 58, 58, 58, 58, 155, 58, 58, 58, 58, + 58, 58, 58, 155, 155, 155, 155, 155, 155, 58, 58, 58, 155, 58, 58, 58, + 58, 155, 155, 155, 155, 155, 58, 155, 155, 58, 58, 148, 149, 148, 149, + 155, 58, 58, 58, 58, 155, 58, 155, 155, 155, 58, 58, 155, 155, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 155, 155, 155, 155, 155, 155, 58, 58, + 148, 149, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 58, 155, 155, 155, 155, 58, 58, 155, 58, 155, 58, 58, 155, 58, + 155, 155, 155, 155, 58, 58, 58, 58, 58, 155, 155, 58, 58, 58, 58, 58, 58, + 155, 155, 155, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 155, 155, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 155, 155, 58, 58, 58, 58, 155, 155, 155, 155, 58, + 155, 155, 58, 58, 155, 155, 58, 58, 58, 58, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 58, 58, 155, 155, 155, 155, + 155, 155, 155, 155, 58, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 58, 58, 58, 58, 58, 155, 58, 155, 58, 58, 58, 155, 155, 155, + 155, 155, 58, 58, 58, 58, 58, 155, 155, 155, 58, 58, 58, 58, 155, 58, 58, + 58, 155, 155, 155, 155, 155, 58, 155, 58, 58, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 0, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, + 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 37, 34, 34, 27, 27, 27, + 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57, 57, 57, 57, + 131, 57, 57, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, + 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, + 40, 0, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 0, 40, + 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 57, 57, 29, 35, 29, 35, 57, 57, 57, 29, 35, 57, 29, 35, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 63, 0, 0, 0, 0, 29, 35, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 0, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 0, 0, 0, 0, 163, 164, 164, 164, + 162, 165, 127, 166, 159, 160, 159, 160, 159, 160, 159, 160, 159, 160, + 162, 162, 159, 160, 159, 160, 159, 160, 159, 160, 167, 168, 169, 169, + 162, 166, 166, 166, 166, 166, 166, 166, 166, 166, 170, 171, 172, 173, + 174, 174, 167, 165, 165, 165, 165, 165, 162, 162, 166, 166, 166, 165, + 127, 164, 162, 27, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 0, 0, 175, 175, 176, 176, 165, 165, 127, + 167, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 164, 165, 165, 165, 127, 0, 0, 0, 0, + 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 177, 177, 178, 178, + 178, 178, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 162, 162, 0, 178, 178, 178, 178, 178, + 178, 178, 178, 178, 178, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 162, 179, 179, 179, + 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 162, 162, + 162, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 179, 179, 179, 179, 179, + 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 162, 162, 162, 162, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 0, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 162, 162, 162, 162, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 162, 162, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, + 177, 177, 177, 177, 177, 177, 162, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 165, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 0, 0, 0, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, + 162, 162, 162, 162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 132, 40, 40, 40, 110, + 40, 40, 40, 40, 107, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 108, 108, 107, 107, 108, 27, 27, + 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, + 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 0, 0, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, + 34, 34, 34, 34, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 34, + 34, 0, 0, 0, 0, 0, 84, 182, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 151, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 84, 84, 84, 84, + 84, 0, 84, 0, 84, 84, 0, 84, 84, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 122, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 0, 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 86, 27, 0, 0, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 164, 164, + 164, 164, 164, 164, 164, 168, 169, 164, 0, 0, 0, 0, 0, 0, 60, 60, 60, 60, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 164, 167, 167, 183, 183, 168, 169, + 168, 169, 168, 169, 168, 169, 168, 169, 168, 169, 168, 169, 168, 169, + 164, 164, 168, 169, 164, 164, 164, 164, 183, 183, 183, 184, 164, 184, 0, + 164, 184, 164, 164, 167, 168, 169, 168, 169, 168, 169, 185, 164, 164, + 186, 187, 188, 188, 188, 0, 164, 189, 185, 164, 0, 0, 0, 0, 89, 89, 89, + 89, 89, 0, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 0, 0, 105, 0, 190, 190, + 191, 192, 191, 190, 190, 193, 194, 190, 195, 196, 197, 196, 196, 198, + 198, 198, 198, 198, 198, 198, 198, 198, 198, 196, 190, 199, 200, 199, + 190, 190, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, + 193, 190, 194, 202, 203, 202, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, + 204, 204, 204, 204, 193, 200, 194, 200, 193, 194, 205, 206, 207, 205, + 205, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 209, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 209, 209, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, + 208, 208, 208, 208, 208, 208, 0, 0, 0, 208, 208, 208, 208, 208, 208, 0, + 0, 208, 208, 208, 208, 208, 208, 0, 0, 208, 208, 208, 208, 208, 208, 0, + 0, 208, 208, 208, 0, 0, 0, 192, 192, 200, 202, 210, 192, 192, 0, 211, + 212, 212, 212, 212, 211, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 213, 213, + 213, 27, 25, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 40, 40, 0, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, 0, 62, 57, 59, 0, 0, + 0, 0, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 113, 113, 113, 113, 0, 0, 0, 59, 59, 59, 59, 59, 59, 59, 59, 59, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 131, 131, 131, 131, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 131, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 113, 113, 113, 113, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 129, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 62, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 0, 0, 0, 0, + 40, 40, 40, 40, 40, 40, 40, 40, 59, 214, 214, 214, 214, 214, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 0, 0, 111, 111, 111, 111, 111, 111, 111, 111, + 111, 111, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 84, 84, 84, 84, + 84, 0, 0, 84, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 84, 84, 0, 0, 0, 84, + 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 84, 107, 107, 107, 0, 107, 107, 0, 0, 0, 0, 0, 107, 64, 107, 60, + 84, 84, 84, 84, 0, 84, 84, 84, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 0, 0, + 0, 0, 60, 153, 64, 0, 0, 0, 0, 110, 215, 215, 215, 215, 215, 215, 215, + 215, 0, 0, 0, 0, 0, 0, 0, 0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 0, 0, 0, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 216, 216, 153, 153, 153, 59, 59, 59, 217, + 216, 216, 216, 216, 216, 105, 105, 105, 105, 105, 105, 105, 105, 64, 64, + 64, 64, 64, 64, 64, 64, 59, 59, 60, 60, 60, 60, 60, 64, 64, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 60, 60, 60, 27, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 0, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, 0, + 37, 37, 0, 0, 37, 0, 0, 37, 37, 0, 0, 37, 37, 37, 37, 0, 37, 37, 37, 37, + 37, 37, 37, 37, 34, 34, 34, 34, 0, 34, 0, 34, 34, 34, 34, 34, 34, 34, 0, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 0, 37, 37, 37, 37, 0, 0, 37, + 37, 37, 37, 37, 37, 37, 37, 0, 37, 37, 37, 37, 37, 37, 37, 0, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 37, 37, 0, 37, 37, 37, 37, 0, 37, 37, 37, 37, 37, 0, + 37, 0, 0, 0, 37, 37, 37, 37, 37, 37, 37, 0, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 0, 0, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 218, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 218, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 218, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 218, 34, 34, 34, 34, 34, 34, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 218, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 218, 34, 34, + 34, 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 218, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 218, 34, 34, 34, 34, 34, 34, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 218, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 218, 34, 34, 34, 34, 34, 34, 0, 0, 0, 0, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, + 103, 103, 103, 103, 103, 103, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, + 105, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 181, 181, 181, 0, 0, +}; + +/* decomposition data */ +static unsigned int decomp_data[] = { + 0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514, + 32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52, + 772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512, + 65, 770, 512, 65, 771, 512, 65, 776, 512, 65, 778, 512, 67, 807, 512, 69, + 768, 512, 69, 769, 512, 69, 770, 512, 69, 776, 512, 73, 768, 512, 73, + 769, 512, 73, 770, 512, 73, 776, 512, 78, 771, 512, 79, 768, 512, 79, + 769, 512, 79, 770, 512, 79, 771, 512, 79, 776, 512, 85, 768, 512, 85, + 769, 512, 85, 770, 512, 85, 776, 512, 89, 769, 512, 97, 768, 512, 97, + 769, 512, 97, 770, 512, 97, 771, 512, 97, 776, 512, 97, 778, 512, 99, + 807, 512, 101, 768, 512, 101, 769, 512, 101, 770, 512, 101, 776, 512, + 105, 768, 512, 105, 769, 512, 105, 770, 512, 105, 776, 512, 110, 771, + 512, 111, 768, 512, 111, 769, 512, 111, 770, 512, 111, 771, 512, 111, + 776, 512, 117, 768, 512, 117, 769, 512, 117, 770, 512, 117, 776, 512, + 121, 769, 512, 121, 776, 512, 65, 772, 512, 97, 772, 512, 65, 774, 512, + 97, 774, 512, 65, 808, 512, 97, 808, 512, 67, 769, 512, 99, 769, 512, 67, + 770, 512, 99, 770, 512, 67, 775, 512, 99, 775, 512, 67, 780, 512, 99, + 780, 512, 68, 780, 512, 100, 780, 512, 69, 772, 512, 101, 772, 512, 69, + 774, 512, 101, 774, 512, 69, 775, 512, 101, 775, 512, 69, 808, 512, 101, + 808, 512, 69, 780, 512, 101, 780, 512, 71, 770, 512, 103, 770, 512, 71, + 774, 512, 103, 774, 512, 71, 775, 512, 103, 775, 512, 71, 807, 512, 103, + 807, 512, 72, 770, 512, 104, 770, 512, 73, 771, 512, 105, 771, 512, 73, + 772, 512, 105, 772, 512, 73, 774, 512, 105, 774, 512, 73, 808, 512, 105, + 808, 512, 73, 775, 514, 73, 74, 514, 105, 106, 512, 74, 770, 512, 106, + 770, 512, 75, 807, 512, 107, 807, 512, 76, 769, 512, 108, 769, 512, 76, + 807, 512, 108, 807, 512, 76, 780, 512, 108, 780, 514, 76, 183, 514, 108, + 183, 512, 78, 769, 512, 110, 769, 512, 78, 807, 512, 110, 807, 512, 78, + 780, 512, 110, 780, 514, 700, 110, 512, 79, 772, 512, 111, 772, 512, 79, + 774, 512, 111, 774, 512, 79, 779, 512, 111, 779, 512, 82, 769, 512, 114, + 769, 512, 82, 807, 512, 114, 807, 512, 82, 780, 512, 114, 780, 512, 83, + 769, 512, 115, 769, 512, 83, 770, 512, 115, 770, 512, 83, 807, 512, 115, + 807, 512, 83, 780, 512, 115, 780, 512, 84, 807, 512, 116, 807, 512, 84, + 780, 512, 116, 780, 512, 85, 771, 512, 117, 771, 512, 85, 772, 512, 117, + 772, 512, 85, 774, 512, 117, 774, 512, 85, 778, 512, 117, 778, 512, 85, + 779, 512, 117, 779, 512, 85, 808, 512, 117, 808, 512, 87, 770, 512, 119, + 770, 512, 89, 770, 512, 121, 770, 512, 89, 776, 512, 90, 769, 512, 122, + 769, 512, 90, 775, 512, 122, 775, 512, 90, 780, 512, 122, 780, 258, 115, + 512, 79, 795, 512, 111, 795, 512, 85, 795, 512, 117, 795, 514, 68, 381, + 514, 68, 382, 514, 100, 382, 514, 76, 74, 514, 76, 106, 514, 108, 106, + 514, 78, 74, 514, 78, 106, 514, 110, 106, 512, 65, 780, 512, 97, 780, + 512, 73, 780, 512, 105, 780, 512, 79, 780, 512, 111, 780, 512, 85, 780, + 512, 117, 780, 512, 220, 772, 512, 252, 772, 512, 220, 769, 512, 252, + 769, 512, 220, 780, 512, 252, 780, 512, 220, 768, 512, 252, 768, 512, + 196, 772, 512, 228, 772, 512, 550, 772, 512, 551, 772, 512, 198, 772, + 512, 230, 772, 512, 71, 780, 512, 103, 780, 512, 75, 780, 512, 107, 780, + 512, 79, 808, 512, 111, 808, 512, 490, 772, 512, 491, 772, 512, 439, 780, + 512, 658, 780, 512, 106, 780, 514, 68, 90, 514, 68, 122, 514, 100, 122, + 512, 71, 769, 512, 103, 769, 512, 78, 768, 512, 110, 768, 512, 197, 769, + 512, 229, 769, 512, 198, 769, 512, 230, 769, 512, 216, 769, 512, 248, + 769, 512, 65, 783, 512, 97, 783, 512, 65, 785, 512, 97, 785, 512, 69, + 783, 512, 101, 783, 512, 69, 785, 512, 101, 785, 512, 73, 783, 512, 105, + 783, 512, 73, 785, 512, 105, 785, 512, 79, 783, 512, 111, 783, 512, 79, + 785, 512, 111, 785, 512, 82, 783, 512, 114, 783, 512, 82, 785, 512, 114, + 785, 512, 85, 783, 512, 117, 783, 512, 85, 785, 512, 117, 785, 512, 83, + 806, 512, 115, 806, 512, 84, 806, 512, 116, 806, 512, 72, 780, 512, 104, + 780, 512, 65, 775, 512, 97, 775, 512, 69, 807, 512, 101, 807, 512, 214, + 772, 512, 246, 772, 512, 213, 772, 512, 245, 772, 512, 79, 775, 512, 111, + 775, 512, 558, 772, 512, 559, 772, 512, 89, 772, 512, 121, 772, 259, 104, + 259, 614, 259, 106, 259, 114, 259, 633, 259, 635, 259, 641, 259, 119, + 259, 121, 514, 32, 774, 514, 32, 775, 514, 32, 778, 514, 32, 808, 514, + 32, 771, 514, 32, 779, 259, 611, 259, 108, 259, 115, 259, 120, 259, 661, + 256, 768, 256, 769, 256, 787, 512, 776, 769, 256, 697, 514, 32, 837, 256, + 59, 514, 32, 769, 512, 168, 769, 512, 913, 769, 256, 183, 512, 917, 769, + 512, 919, 769, 512, 921, 769, 512, 927, 769, 512, 933, 769, 512, 937, + 769, 512, 970, 769, 512, 921, 776, 512, 933, 776, 512, 945, 769, 512, + 949, 769, 512, 951, 769, 512, 953, 769, 512, 971, 769, 512, 953, 776, + 512, 965, 776, 512, 959, 769, 512, 965, 769, 512, 969, 769, 258, 946, + 258, 952, 258, 933, 512, 978, 769, 512, 978, 776, 258, 966, 258, 960, + 258, 954, 258, 961, 258, 962, 258, 920, 258, 949, 258, 931, 512, 1045, + 768, 512, 1045, 776, 512, 1043, 769, 512, 1030, 776, 512, 1050, 769, 512, + 1048, 768, 512, 1059, 774, 512, 1048, 774, 512, 1080, 774, 512, 1077, + 768, 512, 1077, 776, 512, 1075, 769, 512, 1110, 776, 512, 1082, 769, 512, + 1080, 768, 512, 1091, 774, 512, 1140, 783, 512, 1141, 783, 512, 1046, + 774, 512, 1078, 774, 512, 1040, 774, 512, 1072, 774, 512, 1040, 776, 512, + 1072, 776, 512, 1045, 774, 512, 1077, 774, 512, 1240, 776, 512, 1241, + 776, 512, 1046, 776, 512, 1078, 776, 512, 1047, 776, 512, 1079, 776, 512, + 1048, 772, 512, 1080, 772, 512, 1048, 776, 512, 1080, 776, 512, 1054, + 776, 512, 1086, 776, 512, 1256, 776, 512, 1257, 776, 512, 1069, 776, 512, + 1101, 776, 512, 1059, 772, 512, 1091, 772, 512, 1059, 776, 512, 1091, + 776, 512, 1059, 779, 512, 1091, 779, 512, 1063, 776, 512, 1095, 776, 512, + 1067, 776, 512, 1099, 776, 514, 1381, 1410, 512, 1575, 1619, 512, 1575, + 1620, 512, 1608, 1620, 512, 1575, 1621, 512, 1610, 1620, 514, 1575, 1652, + 514, 1608, 1652, 514, 1735, 1652, 514, 1610, 1652, 512, 1749, 1620, 512, + 1729, 1620, 512, 1746, 1620, 512, 2344, 2364, 512, 2352, 2364, 512, 2355, + 2364, 512, 2325, 2364, 512, 2326, 2364, 512, 2327, 2364, 512, 2332, 2364, + 512, 2337, 2364, 512, 2338, 2364, 512, 2347, 2364, 512, 2351, 2364, 512, + 2503, 2494, 512, 2503, 2519, 512, 2465, 2492, 512, 2466, 2492, 512, 2479, + 2492, 512, 2610, 2620, 512, 2616, 2620, 512, 2582, 2620, 512, 2583, 2620, + 512, 2588, 2620, 512, 2603, 2620, 512, 2887, 2902, 512, 2887, 2878, 512, + 2887, 2903, 512, 2849, 2876, 512, 2850, 2876, 512, 2962, 3031, 512, 3014, + 3006, 512, 3015, 3006, 512, 3014, 3031, 512, 3142, 3158, 512, 3263, 3285, + 512, 3270, 3285, 512, 3270, 3286, 512, 3270, 3266, 512, 3274, 3285, 512, + 3398, 3390, 512, 3399, 3390, 512, 3398, 3415, 512, 3545, 3530, 512, 3545, + 3535, 512, 3548, 3530, 512, 3545, 3551, 514, 3661, 3634, 514, 3789, 3762, + 514, 3755, 3737, 514, 3755, 3745, 257, 3851, 512, 3906, 4023, 512, 3916, + 4023, 512, 3921, 4023, 512, 3926, 4023, 512, 3931, 4023, 512, 3904, 4021, + 512, 3953, 3954, 512, 3953, 3956, 512, 4018, 3968, 514, 4018, 3969, 512, + 4019, 3968, 514, 4019, 3969, 512, 3953, 3968, 512, 3986, 4023, 512, 3996, + 4023, 512, 4001, 4023, 512, 4006, 4023, 512, 4011, 4023, 512, 3984, 4021, + 512, 4133, 4142, 259, 4316, 259, 65, 259, 198, 259, 66, 259, 68, 259, 69, + 259, 398, 259, 71, 259, 72, 259, 73, 259, 74, 259, 75, 259, 76, 259, 77, + 259, 78, 259, 79, 259, 546, 259, 80, 259, 82, 259, 84, 259, 85, 259, 87, + 259, 97, 259, 592, 259, 593, 259, 7426, 259, 98, 259, 100, 259, 101, 259, + 601, 259, 603, 259, 604, 259, 103, 259, 107, 259, 109, 259, 331, 259, + 111, 259, 596, 259, 7446, 259, 7447, 259, 112, 259, 116, 259, 117, 259, + 7453, 259, 623, 259, 118, 259, 7461, 259, 946, 259, 947, 259, 948, 259, + 966, 259, 967, 261, 105, 261, 114, 261, 117, 261, 118, 261, 946, 261, + 947, 261, 961, 261, 966, 261, 967, 259, 1085, 259, 594, 259, 99, 259, + 597, 259, 240, 259, 604, 259, 102, 259, 607, 259, 609, 259, 613, 259, + 616, 259, 617, 259, 618, 259, 7547, 259, 669, 259, 621, 259, 7557, 259, + 671, 259, 625, 259, 624, 259, 626, 259, 627, 259, 628, 259, 629, 259, + 632, 259, 642, 259, 643, 259, 427, 259, 649, 259, 650, 259, 7452, 259, + 651, 259, 652, 259, 122, 259, 656, 259, 657, 259, 658, 259, 952, 512, 65, + 805, 512, 97, 805, 512, 66, 775, 512, 98, 775, 512, 66, 803, 512, 98, + 803, 512, 66, 817, 512, 98, 817, 512, 199, 769, 512, 231, 769, 512, 68, + 775, 512, 100, 775, 512, 68, 803, 512, 100, 803, 512, 68, 817, 512, 100, + 817, 512, 68, 807, 512, 100, 807, 512, 68, 813, 512, 100, 813, 512, 274, + 768, 512, 275, 768, 512, 274, 769, 512, 275, 769, 512, 69, 813, 512, 101, + 813, 512, 69, 816, 512, 101, 816, 512, 552, 774, 512, 553, 774, 512, 70, + 775, 512, 102, 775, 512, 71, 772, 512, 103, 772, 512, 72, 775, 512, 104, + 775, 512, 72, 803, 512, 104, 803, 512, 72, 776, 512, 104, 776, 512, 72, + 807, 512, 104, 807, 512, 72, 814, 512, 104, 814, 512, 73, 816, 512, 105, + 816, 512, 207, 769, 512, 239, 769, 512, 75, 769, 512, 107, 769, 512, 75, + 803, 512, 107, 803, 512, 75, 817, 512, 107, 817, 512, 76, 803, 512, 108, + 803, 512, 7734, 772, 512, 7735, 772, 512, 76, 817, 512, 108, 817, 512, + 76, 813, 512, 108, 813, 512, 77, 769, 512, 109, 769, 512, 77, 775, 512, + 109, 775, 512, 77, 803, 512, 109, 803, 512, 78, 775, 512, 110, 775, 512, + 78, 803, 512, 110, 803, 512, 78, 817, 512, 110, 817, 512, 78, 813, 512, + 110, 813, 512, 213, 769, 512, 245, 769, 512, 213, 776, 512, 245, 776, + 512, 332, 768, 512, 333, 768, 512, 332, 769, 512, 333, 769, 512, 80, 769, + 512, 112, 769, 512, 80, 775, 512, 112, 775, 512, 82, 775, 512, 114, 775, + 512, 82, 803, 512, 114, 803, 512, 7770, 772, 512, 7771, 772, 512, 82, + 817, 512, 114, 817, 512, 83, 775, 512, 115, 775, 512, 83, 803, 512, 115, + 803, 512, 346, 775, 512, 347, 775, 512, 352, 775, 512, 353, 775, 512, + 7778, 775, 512, 7779, 775, 512, 84, 775, 512, 116, 775, 512, 84, 803, + 512, 116, 803, 512, 84, 817, 512, 116, 817, 512, 84, 813, 512, 116, 813, + 512, 85, 804, 512, 117, 804, 512, 85, 816, 512, 117, 816, 512, 85, 813, + 512, 117, 813, 512, 360, 769, 512, 361, 769, 512, 362, 776, 512, 363, + 776, 512, 86, 771, 512, 118, 771, 512, 86, 803, 512, 118, 803, 512, 87, + 768, 512, 119, 768, 512, 87, 769, 512, 119, 769, 512, 87, 776, 512, 119, + 776, 512, 87, 775, 512, 119, 775, 512, 87, 803, 512, 119, 803, 512, 88, + 775, 512, 120, 775, 512, 88, 776, 512, 120, 776, 512, 89, 775, 512, 121, + 775, 512, 90, 770, 512, 122, 770, 512, 90, 803, 512, 122, 803, 512, 90, + 817, 512, 122, 817, 512, 104, 817, 512, 116, 776, 512, 119, 778, 512, + 121, 778, 514, 97, 702, 512, 383, 775, 512, 65, 803, 512, 97, 803, 512, + 65, 777, 512, 97, 777, 512, 194, 769, 512, 226, 769, 512, 194, 768, 512, + 226, 768, 512, 194, 777, 512, 226, 777, 512, 194, 771, 512, 226, 771, + 512, 7840, 770, 512, 7841, 770, 512, 258, 769, 512, 259, 769, 512, 258, + 768, 512, 259, 768, 512, 258, 777, 512, 259, 777, 512, 258, 771, 512, + 259, 771, 512, 7840, 774, 512, 7841, 774, 512, 69, 803, 512, 101, 803, + 512, 69, 777, 512, 101, 777, 512, 69, 771, 512, 101, 771, 512, 202, 769, + 512, 234, 769, 512, 202, 768, 512, 234, 768, 512, 202, 777, 512, 234, + 777, 512, 202, 771, 512, 234, 771, 512, 7864, 770, 512, 7865, 770, 512, + 73, 777, 512, 105, 777, 512, 73, 803, 512, 105, 803, 512, 79, 803, 512, + 111, 803, 512, 79, 777, 512, 111, 777, 512, 212, 769, 512, 244, 769, 512, + 212, 768, 512, 244, 768, 512, 212, 777, 512, 244, 777, 512, 212, 771, + 512, 244, 771, 512, 7884, 770, 512, 7885, 770, 512, 416, 769, 512, 417, + 769, 512, 416, 768, 512, 417, 768, 512, 416, 777, 512, 417, 777, 512, + 416, 771, 512, 417, 771, 512, 416, 803, 512, 417, 803, 512, 85, 803, 512, + 117, 803, 512, 85, 777, 512, 117, 777, 512, 431, 769, 512, 432, 769, 512, + 431, 768, 512, 432, 768, 512, 431, 777, 512, 432, 777, 512, 431, 771, + 512, 432, 771, 512, 431, 803, 512, 432, 803, 512, 89, 768, 512, 121, 768, + 512, 89, 803, 512, 121, 803, 512, 89, 777, 512, 121, 777, 512, 89, 771, + 512, 121, 771, 512, 945, 787, 512, 945, 788, 512, 7936, 768, 512, 7937, + 768, 512, 7936, 769, 512, 7937, 769, 512, 7936, 834, 512, 7937, 834, 512, + 913, 787, 512, 913, 788, 512, 7944, 768, 512, 7945, 768, 512, 7944, 769, + 512, 7945, 769, 512, 7944, 834, 512, 7945, 834, 512, 949, 787, 512, 949, + 788, 512, 7952, 768, 512, 7953, 768, 512, 7952, 769, 512, 7953, 769, 512, + 917, 787, 512, 917, 788, 512, 7960, 768, 512, 7961, 768, 512, 7960, 769, + 512, 7961, 769, 512, 951, 787, 512, 951, 788, 512, 7968, 768, 512, 7969, + 768, 512, 7968, 769, 512, 7969, 769, 512, 7968, 834, 512, 7969, 834, 512, + 919, 787, 512, 919, 788, 512, 7976, 768, 512, 7977, 768, 512, 7976, 769, + 512, 7977, 769, 512, 7976, 834, 512, 7977, 834, 512, 953, 787, 512, 953, + 788, 512, 7984, 768, 512, 7985, 768, 512, 7984, 769, 512, 7985, 769, 512, + 7984, 834, 512, 7985, 834, 512, 921, 787, 512, 921, 788, 512, 7992, 768, + 512, 7993, 768, 512, 7992, 769, 512, 7993, 769, 512, 7992, 834, 512, + 7993, 834, 512, 959, 787, 512, 959, 788, 512, 8000, 768, 512, 8001, 768, + 512, 8000, 769, 512, 8001, 769, 512, 927, 787, 512, 927, 788, 512, 8008, + 768, 512, 8009, 768, 512, 8008, 769, 512, 8009, 769, 512, 965, 787, 512, + 965, 788, 512, 8016, 768, 512, 8017, 768, 512, 8016, 769, 512, 8017, 769, + 512, 8016, 834, 512, 8017, 834, 512, 933, 788, 512, 8025, 768, 512, 8025, + 769, 512, 8025, 834, 512, 969, 787, 512, 969, 788, 512, 8032, 768, 512, + 8033, 768, 512, 8032, 769, 512, 8033, 769, 512, 8032, 834, 512, 8033, + 834, 512, 937, 787, 512, 937, 788, 512, 8040, 768, 512, 8041, 768, 512, + 8040, 769, 512, 8041, 769, 512, 8040, 834, 512, 8041, 834, 512, 945, 768, + 256, 940, 512, 949, 768, 256, 941, 512, 951, 768, 256, 942, 512, 953, + 768, 256, 943, 512, 959, 768, 256, 972, 512, 965, 768, 256, 973, 512, + 969, 768, 256, 974, 512, 7936, 837, 512, 7937, 837, 512, 7938, 837, 512, + 7939, 837, 512, 7940, 837, 512, 7941, 837, 512, 7942, 837, 512, 7943, + 837, 512, 7944, 837, 512, 7945, 837, 512, 7946, 837, 512, 7947, 837, 512, + 7948, 837, 512, 7949, 837, 512, 7950, 837, 512, 7951, 837, 512, 7968, + 837, 512, 7969, 837, 512, 7970, 837, 512, 7971, 837, 512, 7972, 837, 512, + 7973, 837, 512, 7974, 837, 512, 7975, 837, 512, 7976, 837, 512, 7977, + 837, 512, 7978, 837, 512, 7979, 837, 512, 7980, 837, 512, 7981, 837, 512, + 7982, 837, 512, 7983, 837, 512, 8032, 837, 512, 8033, 837, 512, 8034, + 837, 512, 8035, 837, 512, 8036, 837, 512, 8037, 837, 512, 8038, 837, 512, + 8039, 837, 512, 8040, 837, 512, 8041, 837, 512, 8042, 837, 512, 8043, + 837, 512, 8044, 837, 512, 8045, 837, 512, 8046, 837, 512, 8047, 837, 512, + 945, 774, 512, 945, 772, 512, 8048, 837, 512, 945, 837, 512, 940, 837, + 512, 945, 834, 512, 8118, 837, 512, 913, 774, 512, 913, 772, 512, 913, + 768, 256, 902, 512, 913, 837, 514, 32, 787, 256, 953, 514, 32, 787, 514, + 32, 834, 512, 168, 834, 512, 8052, 837, 512, 951, 837, 512, 942, 837, + 512, 951, 834, 512, 8134, 837, 512, 917, 768, 256, 904, 512, 919, 768, + 256, 905, 512, 919, 837, 512, 8127, 768, 512, 8127, 769, 512, 8127, 834, + 512, 953, 774, 512, 953, 772, 512, 970, 768, 256, 912, 512, 953, 834, + 512, 970, 834, 512, 921, 774, 512, 921, 772, 512, 921, 768, 256, 906, + 512, 8190, 768, 512, 8190, 769, 512, 8190, 834, 512, 965, 774, 512, 965, + 772, 512, 971, 768, 256, 944, 512, 961, 787, 512, 961, 788, 512, 965, + 834, 512, 971, 834, 512, 933, 774, 512, 933, 772, 512, 933, 768, 256, + 910, 512, 929, 788, 512, 168, 768, 256, 901, 256, 96, 512, 8060, 837, + 512, 969, 837, 512, 974, 837, 512, 969, 834, 512, 8182, 837, 512, 927, + 768, 256, 908, 512, 937, 768, 256, 911, 512, 937, 837, 256, 180, 514, 32, + 788, 256, 8194, 256, 8195, 258, 32, 258, 32, 258, 32, 258, 32, 258, 32, + 257, 32, 258, 32, 258, 32, 258, 32, 257, 8208, 514, 32, 819, 258, 46, + 514, 46, 46, 770, 46, 46, 46, 257, 32, 514, 8242, 8242, 770, 8242, 8242, + 8242, 514, 8245, 8245, 770, 8245, 8245, 8245, 514, 33, 33, 514, 32, 773, + 514, 63, 63, 514, 63, 33, 514, 33, 63, 1026, 8242, 8242, 8242, 8242, 258, + 32, 259, 48, 259, 105, 259, 52, 259, 53, 259, 54, 259, 55, 259, 56, 259, + 57, 259, 43, 259, 8722, 259, 61, 259, 40, 259, 41, 259, 110, 261, 48, + 261, 49, 261, 50, 261, 51, 261, 52, 261, 53, 261, 54, 261, 55, 261, 56, + 261, 57, 261, 43, 261, 8722, 261, 61, 261, 40, 261, 41, 261, 97, 261, + 101, 261, 111, 261, 120, 261, 601, 514, 82, 115, 770, 97, 47, 99, 770, + 97, 47, 115, 262, 67, 514, 176, 67, 770, 99, 47, 111, 770, 99, 47, 117, + 258, 400, 514, 176, 70, 262, 103, 262, 72, 262, 72, 262, 72, 262, 104, + 262, 295, 262, 73, 262, 73, 262, 76, 262, 108, 262, 78, 514, 78, 111, + 262, 80, 262, 81, 262, 82, 262, 82, 262, 82, 515, 83, 77, 770, 84, 69, + 76, 515, 84, 77, 262, 90, 256, 937, 262, 90, 256, 75, 256, 197, 262, 66, + 262, 67, 262, 101, 262, 69, 262, 70, 262, 77, 262, 111, 258, 1488, 258, + 1489, 258, 1490, 258, 1491, 262, 105, 770, 70, 65, 88, 262, 960, 262, + 947, 262, 915, 262, 928, 262, 8721, 262, 68, 262, 100, 262, 101, 262, + 105, 262, 106, 772, 49, 8260, 51, 772, 50, 8260, 51, 772, 49, 8260, 53, + 772, 50, 8260, 53, 772, 51, 8260, 53, 772, 52, 8260, 53, 772, 49, 8260, + 54, 772, 53, 8260, 54, 772, 49, 8260, 56, 772, 51, 8260, 56, 772, 53, + 8260, 56, 772, 55, 8260, 56, 516, 49, 8260, 258, 73, 514, 73, 73, 770, + 73, 73, 73, 514, 73, 86, 258, 86, 514, 86, 73, 770, 86, 73, 73, 1026, 86, + 73, 73, 73, 514, 73, 88, 258, 88, 514, 88, 73, 770, 88, 73, 73, 258, 76, + 258, 67, 258, 68, 258, 77, 258, 105, 514, 105, 105, 770, 105, 105, 105, + 514, 105, 118, 258, 118, 514, 118, 105, 770, 118, 105, 105, 1026, 118, + 105, 105, 105, 514, 105, 120, 258, 120, 514, 120, 105, 770, 120, 105, + 105, 258, 108, 258, 99, 258, 100, 258, 109, 512, 8592, 824, 512, 8594, + 824, 512, 8596, 824, 512, 8656, 824, 512, 8660, 824, 512, 8658, 824, 512, + 8707, 824, 512, 8712, 824, 512, 8715, 824, 512, 8739, 824, 512, 8741, + 824, 514, 8747, 8747, 770, 8747, 8747, 8747, 514, 8750, 8750, 770, 8750, + 8750, 8750, 512, 8764, 824, 512, 8771, 824, 512, 8773, 824, 512, 8776, + 824, 512, 61, 824, 512, 8801, 824, 512, 8781, 824, 512, 60, 824, 512, 62, + 824, 512, 8804, 824, 512, 8805, 824, 512, 8818, 824, 512, 8819, 824, 512, + 8822, 824, 512, 8823, 824, 512, 8826, 824, 512, 8827, 824, 512, 8834, + 824, 512, 8835, 824, 512, 8838, 824, 512, 8839, 824, 512, 8866, 824, 512, + 8872, 824, 512, 8873, 824, 512, 8875, 824, 512, 8828, 824, 512, 8829, + 824, 512, 8849, 824, 512, 8850, 824, 512, 8882, 824, 512, 8883, 824, 512, + 8884, 824, 512, 8885, 824, 256, 12296, 256, 12297, 263, 49, 263, 50, 263, + 51, 263, 52, 263, 53, 263, 54, 263, 55, 263, 56, 263, 57, 519, 49, 48, + 519, 49, 49, 519, 49, 50, 519, 49, 51, 519, 49, 52, 519, 49, 53, 519, 49, + 54, 519, 49, 55, 519, 49, 56, 519, 49, 57, 519, 50, 48, 770, 40, 49, 41, + 770, 40, 50, 41, 770, 40, 51, 41, 770, 40, 52, 41, 770, 40, 53, 41, 770, + 40, 54, 41, 770, 40, 55, 41, 770, 40, 56, 41, 770, 40, 57, 41, 1026, 40, + 49, 48, 41, 1026, 40, 49, 49, 41, 1026, 40, 49, 50, 41, 1026, 40, 49, 51, + 41, 1026, 40, 49, 52, 41, 1026, 40, 49, 53, 41, 1026, 40, 49, 54, 41, + 1026, 40, 49, 55, 41, 1026, 40, 49, 56, 41, 1026, 40, 49, 57, 41, 1026, + 40, 50, 48, 41, 514, 49, 46, 514, 50, 46, 514, 51, 46, 514, 52, 46, 514, + 53, 46, 514, 54, 46, 514, 55, 46, 514, 56, 46, 514, 57, 46, 770, 49, 48, + 46, 770, 49, 49, 46, 770, 49, 50, 46, 770, 49, 51, 46, 770, 49, 52, 46, + 770, 49, 53, 46, 770, 49, 54, 46, 770, 49, 55, 46, 770, 49, 56, 46, 770, + 49, 57, 46, 770, 50, 48, 46, 770, 40, 97, 41, 770, 40, 98, 41, 770, 40, + 99, 41, 770, 40, 100, 41, 770, 40, 101, 41, 770, 40, 102, 41, 770, 40, + 103, 41, 770, 40, 104, 41, 770, 40, 105, 41, 770, 40, 106, 41, 770, 40, + 107, 41, 770, 40, 108, 41, 770, 40, 109, 41, 770, 40, 110, 41, 770, 40, + 111, 41, 770, 40, 112, 41, 770, 40, 113, 41, 770, 40, 114, 41, 770, 40, + 115, 41, 770, 40, 116, 41, 770, 40, 117, 41, 770, 40, 118, 41, 770, 40, + 119, 41, 770, 40, 120, 41, 770, 40, 121, 41, 770, 40, 122, 41, 263, 65, + 263, 66, 263, 67, 263, 68, 263, 69, 263, 70, 263, 71, 263, 72, 263, 73, + 263, 74, 263, 75, 263, 76, 263, 77, 263, 78, 263, 79, 263, 80, 263, 81, + 263, 82, 263, 83, 263, 84, 263, 85, 263, 86, 263, 87, 263, 88, 263, 89, + 263, 90, 263, 97, 263, 98, 263, 99, 263, 100, 263, 101, 263, 102, 263, + 103, 263, 104, 263, 105, 263, 106, 263, 107, 263, 108, 263, 109, 263, + 110, 263, 111, 263, 112, 263, 113, 263, 114, 263, 115, 263, 116, 263, + 117, 263, 118, 263, 119, 263, 120, 263, 121, 263, 122, 263, 48, 1026, + 8747, 8747, 8747, 8747, 770, 58, 58, 61, 514, 61, 61, 770, 61, 61, 61, + 512, 10973, 824, 259, 11617, 258, 27597, 258, 40863, 258, 19968, 258, + 20008, 258, 20022, 258, 20031, 258, 20057, 258, 20101, 258, 20108, 258, + 20128, 258, 20154, 258, 20799, 258, 20837, 258, 20843, 258, 20866, 258, + 20886, 258, 20907, 258, 20960, 258, 20981, 258, 20992, 258, 21147, 258, + 21241, 258, 21269, 258, 21274, 258, 21304, 258, 21313, 258, 21340, 258, + 21353, 258, 21378, 258, 21430, 258, 21448, 258, 21475, 258, 22231, 258, + 22303, 258, 22763, 258, 22786, 258, 22794, 258, 22805, 258, 22823, 258, + 22899, 258, 23376, 258, 23424, 258, 23544, 258, 23567, 258, 23586, 258, + 23608, 258, 23662, 258, 23665, 258, 24027, 258, 24037, 258, 24049, 258, + 24062, 258, 24178, 258, 24186, 258, 24191, 258, 24308, 258, 24318, 258, + 24331, 258, 24339, 258, 24400, 258, 24417, 258, 24435, 258, 24515, 258, + 25096, 258, 25142, 258, 25163, 258, 25903, 258, 25908, 258, 25991, 258, + 26007, 258, 26020, 258, 26041, 258, 26080, 258, 26085, 258, 26352, 258, + 26376, 258, 26408, 258, 27424, 258, 27490, 258, 27513, 258, 27571, 258, + 27595, 258, 27604, 258, 27611, 258, 27663, 258, 27668, 258, 27700, 258, + 28779, 258, 29226, 258, 29238, 258, 29243, 258, 29247, 258, 29255, 258, + 29273, 258, 29275, 258, 29356, 258, 29572, 258, 29577, 258, 29916, 258, + 29926, 258, 29976, 258, 29983, 258, 29992, 258, 30000, 258, 30091, 258, + 30098, 258, 30326, 258, 30333, 258, 30382, 258, 30399, 258, 30446, 258, + 30683, 258, 30690, 258, 30707, 258, 31034, 258, 31160, 258, 31166, 258, + 31348, 258, 31435, 258, 31481, 258, 31859, 258, 31992, 258, 32566, 258, + 32593, 258, 32650, 258, 32701, 258, 32769, 258, 32780, 258, 32786, 258, + 32819, 258, 32895, 258, 32905, 258, 33251, 258, 33258, 258, 33267, 258, + 33276, 258, 33292, 258, 33307, 258, 33311, 258, 33390, 258, 33394, 258, + 33400, 258, 34381, 258, 34411, 258, 34880, 258, 34892, 258, 34915, 258, + 35198, 258, 35211, 258, 35282, 258, 35328, 258, 35895, 258, 35910, 258, + 35925, 258, 35960, 258, 35997, 258, 36196, 258, 36208, 258, 36275, 258, + 36523, 258, 36554, 258, 36763, 258, 36784, 258, 36789, 258, 37009, 258, + 37193, 258, 37318, 258, 37324, 258, 37329, 258, 38263, 258, 38272, 258, + 38428, 258, 38582, 258, 38585, 258, 38632, 258, 38737, 258, 38750, 258, + 38754, 258, 38761, 258, 38859, 258, 38893, 258, 38899, 258, 38913, 258, + 39080, 258, 39131, 258, 39135, 258, 39318, 258, 39321, 258, 39340, 258, + 39592, 258, 39640, 258, 39647, 258, 39717, 258, 39727, 258, 39730, 258, + 39740, 258, 39770, 258, 40165, 258, 40565, 258, 40575, 258, 40613, 258, + 40635, 258, 40643, 258, 40653, 258, 40657, 258, 40697, 258, 40701, 258, + 40718, 258, 40723, 258, 40736, 258, 40763, 258, 40778, 258, 40786, 258, + 40845, 258, 40860, 258, 40864, 264, 32, 258, 12306, 258, 21313, 258, + 21316, 258, 21317, 512, 12363, 12441, 512, 12365, 12441, 512, 12367, + 12441, 512, 12369, 12441, 512, 12371, 12441, 512, 12373, 12441, 512, + 12375, 12441, 512, 12377, 12441, 512, 12379, 12441, 512, 12381, 12441, + 512, 12383, 12441, 512, 12385, 12441, 512, 12388, 12441, 512, 12390, + 12441, 512, 12392, 12441, 512, 12399, 12441, 512, 12399, 12442, 512, + 12402, 12441, 512, 12402, 12442, 512, 12405, 12441, 512, 12405, 12442, + 512, 12408, 12441, 512, 12408, 12442, 512, 12411, 12441, 512, 12411, + 12442, 512, 12358, 12441, 514, 32, 12441, 514, 32, 12442, 512, 12445, + 12441, 521, 12424, 12426, 512, 12459, 12441, 512, 12461, 12441, 512, + 12463, 12441, 512, 12465, 12441, 512, 12467, 12441, 512, 12469, 12441, + 512, 12471, 12441, 512, 12473, 12441, 512, 12475, 12441, 512, 12477, + 12441, 512, 12479, 12441, 512, 12481, 12441, 512, 12484, 12441, 512, + 12486, 12441, 512, 12488, 12441, 512, 12495, 12441, 512, 12495, 12442, + 512, 12498, 12441, 512, 12498, 12442, 512, 12501, 12441, 512, 12501, + 12442, 512, 12504, 12441, 512, 12504, 12442, 512, 12507, 12441, 512, + 12507, 12442, 512, 12454, 12441, 512, 12527, 12441, 512, 12528, 12441, + 512, 12529, 12441, 512, 12530, 12441, 512, 12541, 12441, 521, 12467, + 12488, 258, 4352, 258, 4353, 258, 4522, 258, 4354, 258, 4524, 258, 4525, + 258, 4355, 258, 4356, 258, 4357, 258, 4528, 258, 4529, 258, 4530, 258, + 4531, 258, 4532, 258, 4533, 258, 4378, 258, 4358, 258, 4359, 258, 4360, + 258, 4385, 258, 4361, 258, 4362, 258, 4363, 258, 4364, 258, 4365, 258, + 4366, 258, 4367, 258, 4368, 258, 4369, 258, 4370, 258, 4449, 258, 4450, + 258, 4451, 258, 4452, 258, 4453, 258, 4454, 258, 4455, 258, 4456, 258, + 4457, 258, 4458, 258, 4459, 258, 4460, 258, 4461, 258, 4462, 258, 4463, + 258, 4464, 258, 4465, 258, 4466, 258, 4467, 258, 4468, 258, 4469, 258, + 4448, 258, 4372, 258, 4373, 258, 4551, 258, 4552, 258, 4556, 258, 4558, + 258, 4563, 258, 4567, 258, 4569, 258, 4380, 258, 4573, 258, 4575, 258, + 4381, 258, 4382, 258, 4384, 258, 4386, 258, 4387, 258, 4391, 258, 4393, + 258, 4395, 258, 4396, 258, 4397, 258, 4398, 258, 4399, 258, 4402, 258, + 4406, 258, 4416, 258, 4423, 258, 4428, 258, 4593, 258, 4594, 258, 4439, + 258, 4440, 258, 4441, 258, 4484, 258, 4485, 258, 4488, 258, 4497, 258, + 4498, 258, 4500, 258, 4510, 258, 4513, 259, 19968, 259, 20108, 259, + 19977, 259, 22235, 259, 19978, 259, 20013, 259, 19979, 259, 30002, 259, + 20057, 259, 19993, 259, 19969, 259, 22825, 259, 22320, 259, 20154, 770, + 40, 4352, 41, 770, 40, 4354, 41, 770, 40, 4355, 41, 770, 40, 4357, 41, + 770, 40, 4358, 41, 770, 40, 4359, 41, 770, 40, 4361, 41, 770, 40, 4363, + 41, 770, 40, 4364, 41, 770, 40, 4366, 41, 770, 40, 4367, 41, 770, 40, + 4368, 41, 770, 40, 4369, 41, 770, 40, 4370, 41, 1026, 40, 4352, 4449, 41, + 1026, 40, 4354, 4449, 41, 1026, 40, 4355, 4449, 41, 1026, 40, 4357, 4449, + 41, 1026, 40, 4358, 4449, 41, 1026, 40, 4359, 4449, 41, 1026, 40, 4361, + 4449, 41, 1026, 40, 4363, 4449, 41, 1026, 40, 4364, 4449, 41, 1026, 40, + 4366, 4449, 41, 1026, 40, 4367, 4449, 41, 1026, 40, 4368, 4449, 41, 1026, + 40, 4369, 4449, 41, 1026, 40, 4370, 4449, 41, 1026, 40, 4364, 4462, 41, + 1794, 40, 4363, 4457, 4364, 4453, 4523, 41, 1538, 40, 4363, 4457, 4370, + 4462, 41, 770, 40, 19968, 41, 770, 40, 20108, 41, 770, 40, 19977, 41, + 770, 40, 22235, 41, 770, 40, 20116, 41, 770, 40, 20845, 41, 770, 40, + 19971, 41, 770, 40, 20843, 41, 770, 40, 20061, 41, 770, 40, 21313, 41, + 770, 40, 26376, 41, 770, 40, 28779, 41, 770, 40, 27700, 41, 770, 40, + 26408, 41, 770, 40, 37329, 41, 770, 40, 22303, 41, 770, 40, 26085, 41, + 770, 40, 26666, 41, 770, 40, 26377, 41, 770, 40, 31038, 41, 770, 40, + 21517, 41, 770, 40, 29305, 41, 770, 40, 36001, 41, 770, 40, 31069, 41, + 770, 40, 21172, 41, 770, 40, 20195, 41, 770, 40, 21628, 41, 770, 40, + 23398, 41, 770, 40, 30435, 41, 770, 40, 20225, 41, 770, 40, 36039, 41, + 770, 40, 21332, 41, 770, 40, 31085, 41, 770, 40, 20241, 41, 770, 40, + 33258, 41, 770, 40, 33267, 41, 778, 80, 84, 69, 519, 50, 49, 519, 50, 50, + 519, 50, 51, 519, 50, 52, 519, 50, 53, 519, 50, 54, 519, 50, 55, 519, 50, + 56, 519, 50, 57, 519, 51, 48, 519, 51, 49, 519, 51, 50, 519, 51, 51, 519, + 51, 52, 519, 51, 53, 263, 4352, 263, 4354, 263, 4355, 263, 4357, 263, + 4358, 263, 4359, 263, 4361, 263, 4363, 263, 4364, 263, 4366, 263, 4367, + 263, 4368, 263, 4369, 263, 4370, 519, 4352, 4449, 519, 4354, 4449, 519, + 4355, 4449, 519, 4357, 4449, 519, 4358, 4449, 519, 4359, 4449, 519, 4361, + 4449, 519, 4363, 4449, 519, 4364, 4449, 519, 4366, 4449, 519, 4367, 4449, + 519, 4368, 4449, 519, 4369, 4449, 519, 4370, 4449, 1287, 4366, 4449, + 4535, 4352, 4457, 1031, 4364, 4462, 4363, 4468, 519, 4363, 4462, 263, + 19968, 263, 20108, 263, 19977, 263, 22235, 263, 20116, 263, 20845, 263, + 19971, 263, 20843, 263, 20061, 263, 21313, 263, 26376, 263, 28779, 263, + 27700, 263, 26408, 263, 37329, 263, 22303, 263, 26085, 263, 26666, 263, + 26377, 263, 31038, 263, 21517, 263, 29305, 263, 36001, 263, 31069, 263, + 21172, 263, 31192, 263, 30007, 263, 22899, 263, 36969, 263, 20778, 263, + 21360, 263, 27880, 263, 38917, 263, 20241, 263, 20889, 263, 27491, 263, + 19978, 263, 20013, 263, 19979, 263, 24038, 263, 21491, 263, 21307, 263, + 23447, 263, 23398, 263, 30435, 263, 20225, 263, 36039, 263, 21332, 263, + 22812, 519, 51, 54, 519, 51, 55, 519, 51, 56, 519, 51, 57, 519, 52, 48, + 519, 52, 49, 519, 52, 50, 519, 52, 51, 519, 52, 52, 519, 52, 53, 519, 52, + 54, 519, 52, 55, 519, 52, 56, 519, 52, 57, 519, 53, 48, 514, 49, 26376, + 514, 50, 26376, 514, 51, 26376, 514, 52, 26376, 514, 53, 26376, 514, 54, + 26376, 514, 55, 26376, 514, 56, 26376, 514, 57, 26376, 770, 49, 48, + 26376, 770, 49, 49, 26376, 770, 49, 50, 26376, 522, 72, 103, 778, 101, + 114, 103, 522, 101, 86, 778, 76, 84, 68, 263, 12450, 263, 12452, 263, + 12454, 263, 12456, 263, 12458, 263, 12459, 263, 12461, 263, 12463, 263, + 12465, 263, 12467, 263, 12469, 263, 12471, 263, 12473, 263, 12475, 263, + 12477, 263, 12479, 263, 12481, 263, 12484, 263, 12486, 263, 12488, 263, + 12490, 263, 12491, 263, 12492, 263, 12493, 263, 12494, 263, 12495, 263, + 12498, 263, 12501, 263, 12504, 263, 12507, 263, 12510, 263, 12511, 263, + 12512, 263, 12513, 263, 12514, 263, 12516, 263, 12518, 263, 12520, 263, + 12521, 263, 12522, 263, 12523, 263, 12524, 263, 12525, 263, 12527, 263, + 12528, 263, 12529, 263, 12530, 1034, 12450, 12497, 12540, 12488, 1034, + 12450, 12523, 12501, 12449, 1034, 12450, 12531, 12506, 12450, 778, 12450, + 12540, 12523, 1034, 12452, 12491, 12531, 12464, 778, 12452, 12531, 12481, + 778, 12454, 12457, 12531, 1290, 12456, 12473, 12463, 12540, 12489, 1034, + 12456, 12540, 12459, 12540, 778, 12458, 12531, 12473, 778, 12458, 12540, + 12512, 778, 12459, 12452, 12522, 1034, 12459, 12521, 12483, 12488, 1034, + 12459, 12525, 12522, 12540, 778, 12460, 12525, 12531, 778, 12460, 12531, + 12510, 522, 12462, 12460, 778, 12462, 12491, 12540, 1034, 12461, 12517, + 12522, 12540, 1034, 12462, 12523, 12480, 12540, 522, 12461, 12525, 1290, + 12461, 12525, 12464, 12521, 12512, 1546, 12461, 12525, 12513, 12540, + 12488, 12523, 1290, 12461, 12525, 12527, 12483, 12488, 778, 12464, 12521, + 12512, 1290, 12464, 12521, 12512, 12488, 12531, 1290, 12463, 12523, + 12476, 12452, 12525, 1034, 12463, 12525, 12540, 12493, 778, 12465, 12540, + 12473, 778, 12467, 12523, 12490, 778, 12467, 12540, 12509, 1034, 12469, + 12452, 12463, 12523, 1290, 12469, 12531, 12481, 12540, 12512, 1034, + 12471, 12522, 12531, 12464, 778, 12475, 12531, 12481, 778, 12475, 12531, + 12488, 778, 12480, 12540, 12473, 522, 12487, 12471, 522, 12489, 12523, + 522, 12488, 12531, 522, 12490, 12494, 778, 12494, 12483, 12488, 778, + 12495, 12452, 12484, 1290, 12497, 12540, 12475, 12531, 12488, 778, 12497, + 12540, 12484, 1034, 12496, 12540, 12524, 12523, 1290, 12500, 12450, + 12473, 12488, 12523, 778, 12500, 12463, 12523, 522, 12500, 12467, 522, + 12499, 12523, 1290, 12501, 12449, 12521, 12483, 12489, 1034, 12501, + 12451, 12540, 12488, 1290, 12502, 12483, 12471, 12455, 12523, 778, 12501, + 12521, 12531, 1290, 12504, 12463, 12479, 12540, 12523, 522, 12506, 12477, + 778, 12506, 12491, 12498, 778, 12504, 12523, 12484, 778, 12506, 12531, + 12473, 778, 12506, 12540, 12472, 778, 12505, 12540, 12479, 1034, 12509, + 12452, 12531, 12488, 778, 12508, 12523, 12488, 522, 12507, 12531, 778, + 12509, 12531, 12489, 778, 12507, 12540, 12523, 778, 12507, 12540, 12531, + 1034, 12510, 12452, 12463, 12525, 778, 12510, 12452, 12523, 778, 12510, + 12483, 12495, 778, 12510, 12523, 12463, 1290, 12510, 12531, 12471, 12519, + 12531, 1034, 12511, 12463, 12525, 12531, 522, 12511, 12522, 1290, 12511, + 12522, 12496, 12540, 12523, 522, 12513, 12460, 1034, 12513, 12460, 12488, + 12531, 1034, 12513, 12540, 12488, 12523, 778, 12516, 12540, 12489, 778, + 12516, 12540, 12523, 778, 12518, 12450, 12531, 1034, 12522, 12483, 12488, + 12523, 522, 12522, 12521, 778, 12523, 12500, 12540, 1034, 12523, 12540, + 12502, 12523, 522, 12524, 12512, 1290, 12524, 12531, 12488, 12466, 12531, + 778, 12527, 12483, 12488, 514, 48, 28857, 514, 49, 28857, 514, 50, 28857, + 514, 51, 28857, 514, 52, 28857, 514, 53, 28857, 514, 54, 28857, 514, 55, + 28857, 514, 56, 28857, 514, 57, 28857, 770, 49, 48, 28857, 770, 49, 49, + 28857, 770, 49, 50, 28857, 770, 49, 51, 28857, 770, 49, 52, 28857, 770, + 49, 53, 28857, 770, 49, 54, 28857, 770, 49, 55, 28857, 770, 49, 56, + 28857, 770, 49, 57, 28857, 770, 50, 48, 28857, 770, 50, 49, 28857, 770, + 50, 50, 28857, 770, 50, 51, 28857, 770, 50, 52, 28857, 778, 104, 80, 97, + 522, 100, 97, 522, 65, 85, 778, 98, 97, 114, 522, 111, 86, 522, 112, 99, + 522, 100, 109, 778, 100, 109, 178, 778, 100, 109, 179, 522, 73, 85, 522, + 24179, 25104, 522, 26157, 21644, 522, 22823, 27491, 522, 26126, 27835, + 1034, 26666, 24335, 20250, 31038, 522, 112, 65, 522, 110, 65, 522, 956, + 65, 522, 109, 65, 522, 107, 65, 522, 75, 66, 522, 77, 66, 522, 71, 66, + 778, 99, 97, 108, 1034, 107, 99, 97, 108, 522, 112, 70, 522, 110, 70, + 522, 956, 70, 522, 956, 103, 522, 109, 103, 522, 107, 103, 522, 72, 122, + 778, 107, 72, 122, 778, 77, 72, 122, 778, 71, 72, 122, 778, 84, 72, 122, + 522, 956, 8467, 522, 109, 8467, 522, 100, 8467, 522, 107, 8467, 522, 102, + 109, 522, 110, 109, 522, 956, 109, 522, 109, 109, 522, 99, 109, 522, 107, + 109, 778, 109, 109, 178, 778, 99, 109, 178, 522, 109, 178, 778, 107, 109, + 178, 778, 109, 109, 179, 778, 99, 109, 179, 522, 109, 179, 778, 107, 109, + 179, 778, 109, 8725, 115, 1034, 109, 8725, 115, 178, 522, 80, 97, 778, + 107, 80, 97, 778, 77, 80, 97, 778, 71, 80, 97, 778, 114, 97, 100, 1290, + 114, 97, 100, 8725, 115, 1546, 114, 97, 100, 8725, 115, 178, 522, 112, + 115, 522, 110, 115, 522, 956, 115, 522, 109, 115, 522, 112, 86, 522, 110, + 86, 522, 956, 86, 522, 109, 86, 522, 107, 86, 522, 77, 86, 522, 112, 87, + 522, 110, 87, 522, 956, 87, 522, 109, 87, 522, 107, 87, 522, 77, 87, 522, + 107, 937, 522, 77, 937, 1034, 97, 46, 109, 46, 522, 66, 113, 522, 99, 99, + 522, 99, 100, 1034, 67, 8725, 107, 103, 778, 67, 111, 46, 522, 100, 66, + 522, 71, 121, 522, 104, 97, 522, 72, 80, 522, 105, 110, 522, 75, 75, 522, + 75, 77, 522, 107, 116, 522, 108, 109, 522, 108, 110, 778, 108, 111, 103, + 522, 108, 120, 522, 109, 98, 778, 109, 105, 108, 778, 109, 111, 108, 522, + 80, 72, 1034, 112, 46, 109, 46, 778, 80, 80, 77, 522, 80, 82, 522, 115, + 114, 522, 83, 118, 522, 87, 98, 778, 86, 8725, 109, 778, 65, 8725, 109, + 514, 49, 26085, 514, 50, 26085, 514, 51, 26085, 514, 52, 26085, 514, 53, + 26085, 514, 54, 26085, 514, 55, 26085, 514, 56, 26085, 514, 57, 26085, + 770, 49, 48, 26085, 770, 49, 49, 26085, 770, 49, 50, 26085, 770, 49, 51, + 26085, 770, 49, 52, 26085, 770, 49, 53, 26085, 770, 49, 54, 26085, 770, + 49, 55, 26085, 770, 49, 56, 26085, 770, 49, 57, 26085, 770, 50, 48, + 26085, 770, 50, 49, 26085, 770, 50, 50, 26085, 770, 50, 51, 26085, 770, + 50, 52, 26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, + 26085, 770, 50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, + 51, 49, 26085, 778, 103, 97, 108, 256, 35912, 256, 26356, 256, 36554, + 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256, 40860, 256, 40860, + 256, 22865, 256, 37329, 256, 21895, 256, 22856, 256, 25078, 256, 30313, + 256, 32645, 256, 34367, 256, 34746, 256, 35064, 256, 37007, 256, 27138, + 256, 27931, 256, 28889, 256, 29662, 256, 33853, 256, 37226, 256, 39409, + 256, 20098, 256, 21365, 256, 27396, 256, 29211, 256, 34349, 256, 40478, + 256, 23888, 256, 28651, 256, 34253, 256, 35172, 256, 25289, 256, 33240, + 256, 34847, 256, 24266, 256, 26391, 256, 28010, 256, 29436, 256, 37070, + 256, 20358, 256, 20919, 256, 21214, 256, 25796, 256, 27347, 256, 29200, + 256, 30439, 256, 32769, 256, 34310, 256, 34396, 256, 36335, 256, 38706, + 256, 39791, 256, 40442, 256, 30860, 256, 31103, 256, 32160, 256, 33737, + 256, 37636, 256, 40575, 256, 35542, 256, 22751, 256, 24324, 256, 31840, + 256, 32894, 256, 29282, 256, 30922, 256, 36034, 256, 38647, 256, 22744, + 256, 23650, 256, 27155, 256, 28122, 256, 28431, 256, 32047, 256, 32311, + 256, 38475, 256, 21202, 256, 32907, 256, 20956, 256, 20940, 256, 31260, + 256, 32190, 256, 33777, 256, 38517, 256, 35712, 256, 25295, 256, 27138, + 256, 35582, 256, 20025, 256, 23527, 256, 24594, 256, 29575, 256, 30064, + 256, 21271, 256, 30971, 256, 20415, 256, 24489, 256, 19981, 256, 27852, + 256, 25976, 256, 32034, 256, 21443, 256, 22622, 256, 30465, 256, 33865, + 256, 35498, 256, 27578, 256, 36784, 256, 27784, 256, 25342, 256, 33509, + 256, 25504, 256, 30053, 256, 20142, 256, 20841, 256, 20937, 256, 26753, + 256, 31975, 256, 33391, 256, 35538, 256, 37327, 256, 21237, 256, 21570, + 256, 22899, 256, 24300, 256, 26053, 256, 28670, 256, 31018, 256, 38317, + 256, 39530, 256, 40599, 256, 40654, 256, 21147, 256, 26310, 256, 27511, + 256, 36706, 256, 24180, 256, 24976, 256, 25088, 256, 25754, 256, 28451, + 256, 29001, 256, 29833, 256, 31178, 256, 32244, 256, 32879, 256, 36646, + 256, 34030, 256, 36899, 256, 37706, 256, 21015, 256, 21155, 256, 21693, + 256, 28872, 256, 35010, 256, 35498, 256, 24265, 256, 24565, 256, 25467, + 256, 27566, 256, 31806, 256, 29557, 256, 20196, 256, 22265, 256, 23527, + 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256, 32666, 256, 32838, + 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256, 20363, 256, 31150, + 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256, 20698, 256, 23534, + 256, 23615, 256, 26009, 256, 27138, 256, 29134, 256, 30274, 256, 34044, + 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256, 21129, 256, 26491, + 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256, 30041, 256, 30827, + 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256, 38520, 256, 20523, + 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256, 24900, 256, 26647, + 256, 29575, 256, 38534, 256, 21033, 256, 21519, 256, 23653, 256, 26131, + 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256, 30178, 256, 32633, + 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256, 21311, 256, 28346, + 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256, 38563, 256, 40023, + 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256, 31435, 256, 31520, + 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256, 20160, 256, 33590, + 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256, 31958, 256, 23429, + 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256, 38477, 256, 35211, + 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256, 26228, 256, 20958, + 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256, 31077, 256, 31119, + 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256, 35576, 256, 36920, + 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256, 40372, 256, 20398, + 256, 20711, 256, 20813, 256, 21193, 256, 21220, 256, 21329, 256, 21917, + 256, 22022, 256, 22120, 256, 22592, 256, 22696, 256, 23652, 256, 23662, + 256, 24724, 256, 24936, 256, 24974, 256, 25074, 256, 25935, 256, 26082, + 256, 26257, 256, 26757, 256, 28023, 256, 28186, 256, 28450, 256, 29038, + 256, 29227, 256, 29730, 256, 30865, 256, 31038, 256, 31049, 256, 31048, + 256, 31056, 256, 31062, 256, 31069, 256, 31117, 256, 31118, 256, 31296, + 256, 31361, 256, 31680, 256, 32244, 256, 32265, 256, 32321, 256, 32626, + 256, 32773, 256, 33261, 256, 33401, 256, 33401, 256, 33879, 256, 35088, + 256, 35222, 256, 35585, 256, 35641, 256, 36051, 256, 36104, 256, 36790, + 256, 36920, 256, 38627, 256, 38911, 256, 38971, 256, 20006, 256, 20917, + 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, 21191, 256, 21242, + 256, 21917, 256, 21845, 256, 21913, 256, 21986, 256, 22618, 256, 22707, + 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274, 256, 24281, + 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840, 256, 24974, + 256, 24928, 256, 25074, 256, 25140, 256, 25540, 256, 25628, 256, 25682, + 256, 25942, 256, 26228, 256, 26391, 256, 26395, 256, 26454, 256, 27513, + 256, 27578, 256, 27969, 256, 28379, 256, 28363, 256, 28450, 256, 28702, + 256, 29038, 256, 30631, 256, 29237, 256, 29359, 256, 29482, 256, 29809, + 256, 29958, 256, 30011, 256, 30237, 256, 30239, 256, 30410, 256, 30427, + 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, 31409, 256, 31680, + 256, 31867, 256, 32091, 256, 32244, 256, 32574, 256, 32773, 256, 33618, + 256, 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35222, 256, 35519, + 256, 35576, 256, 35531, 256, 35585, 256, 35582, 256, 35565, 256, 35641, + 256, 35722, 256, 36104, 256, 36664, 256, 36978, 256, 37273, 256, 37494, + 256, 38524, 256, 38627, 256, 38742, 256, 38875, 256, 38911, 256, 38923, + 256, 38971, 256, 39698, 256, 40860, 256, 141386, 256, 141380, 256, + 144341, 256, 15261, 256, 16408, 256, 16441, 256, 152137, 256, 154832, + 256, 163539, 256, 40771, 256, 40846, 514, 102, 102, 514, 102, 105, 514, + 102, 108, 770, 102, 102, 105, 770, 102, 102, 108, 514, 383, 116, 514, + 115, 116, 514, 1396, 1398, 514, 1396, 1381, 514, 1396, 1387, 514, 1406, + 1398, 514, 1396, 1389, 512, 1497, 1460, 512, 1522, 1463, 262, 1506, 262, + 1488, 262, 1491, 262, 1492, 262, 1499, 262, 1500, 262, 1501, 262, 1512, + 262, 1514, 262, 43, 512, 1513, 1473, 512, 1513, 1474, 512, 64329, 1473, + 512, 64329, 1474, 512, 1488, 1463, 512, 1488, 1464, 512, 1488, 1468, 512, + 1489, 1468, 512, 1490, 1468, 512, 1491, 1468, 512, 1492, 1468, 512, 1493, + 1468, 512, 1494, 1468, 512, 1496, 1468, 512, 1497, 1468, 512, 1498, 1468, + 512, 1499, 1468, 512, 1500, 1468, 512, 1502, 1468, 512, 1504, 1468, 512, + 1505, 1468, 512, 1507, 1468, 512, 1508, 1468, 512, 1510, 1468, 512, 1511, + 1468, 512, 1512, 1468, 512, 1513, 1468, 512, 1514, 1468, 512, 1493, 1465, + 512, 1489, 1471, 512, 1499, 1471, 512, 1508, 1471, 514, 1488, 1500, 267, + 1649, 268, 1649, 267, 1659, 268, 1659, 269, 1659, 270, 1659, 267, 1662, + 268, 1662, 269, 1662, 270, 1662, 267, 1664, 268, 1664, 269, 1664, 270, + 1664, 267, 1658, 268, 1658, 269, 1658, 270, 1658, 267, 1663, 268, 1663, + 269, 1663, 270, 1663, 267, 1657, 268, 1657, 269, 1657, 270, 1657, 267, + 1700, 268, 1700, 269, 1700, 270, 1700, 267, 1702, 268, 1702, 269, 1702, + 270, 1702, 267, 1668, 268, 1668, 269, 1668, 270, 1668, 267, 1667, 268, + 1667, 269, 1667, 270, 1667, 267, 1670, 268, 1670, 269, 1670, 270, 1670, + 267, 1671, 268, 1671, 269, 1671, 270, 1671, 267, 1677, 268, 1677, 267, + 1676, 268, 1676, 267, 1678, 268, 1678, 267, 1672, 268, 1672, 267, 1688, + 268, 1688, 267, 1681, 268, 1681, 267, 1705, 268, 1705, 269, 1705, 270, + 1705, 267, 1711, 268, 1711, 269, 1711, 270, 1711, 267, 1715, 268, 1715, + 269, 1715, 270, 1715, 267, 1713, 268, 1713, 269, 1713, 270, 1713, 267, + 1722, 268, 1722, 267, 1723, 268, 1723, 269, 1723, 270, 1723, 267, 1728, + 268, 1728, 267, 1729, 268, 1729, 269, 1729, 270, 1729, 267, 1726, 268, + 1726, 269, 1726, 270, 1726, 267, 1746, 268, 1746, 267, 1747, 268, 1747, + 267, 1709, 268, 1709, 269, 1709, 270, 1709, 267, 1735, 268, 1735, 267, + 1734, 268, 1734, 267, 1736, 268, 1736, 267, 1655, 267, 1739, 268, 1739, + 267, 1733, 268, 1733, 267, 1737, 268, 1737, 267, 1744, 268, 1744, 269, + 1744, 270, 1744, 269, 1609, 270, 1609, 523, 1574, 1575, 524, 1574, 1575, + 523, 1574, 1749, 524, 1574, 1749, 523, 1574, 1608, 524, 1574, 1608, 523, + 1574, 1735, 524, 1574, 1735, 523, 1574, 1734, 524, 1574, 1734, 523, 1574, + 1736, 524, 1574, 1736, 523, 1574, 1744, 524, 1574, 1744, 525, 1574, 1744, + 523, 1574, 1609, 524, 1574, 1609, 525, 1574, 1609, 267, 1740, 268, 1740, + 269, 1740, 270, 1740, 523, 1574, 1580, 523, 1574, 1581, 523, 1574, 1605, + 523, 1574, 1609, 523, 1574, 1610, 523, 1576, 1580, 523, 1576, 1581, 523, + 1576, 1582, 523, 1576, 1605, 523, 1576, 1609, 523, 1576, 1610, 523, 1578, + 1580, 523, 1578, 1581, 523, 1578, 1582, 523, 1578, 1605, 523, 1578, 1609, + 523, 1578, 1610, 523, 1579, 1580, 523, 1579, 1605, 523, 1579, 1609, 523, + 1579, 1610, 523, 1580, 1581, 523, 1580, 1605, 523, 1581, 1580, 523, 1581, + 1605, 523, 1582, 1580, 523, 1582, 1581, 523, 1582, 1605, 523, 1587, 1580, + 523, 1587, 1581, 523, 1587, 1582, 523, 1587, 1605, 523, 1589, 1581, 523, + 1589, 1605, 523, 1590, 1580, 523, 1590, 1581, 523, 1590, 1582, 523, 1590, + 1605, 523, 1591, 1581, 523, 1591, 1605, 523, 1592, 1605, 523, 1593, 1580, + 523, 1593, 1605, 523, 1594, 1580, 523, 1594, 1605, 523, 1601, 1580, 523, + 1601, 1581, 523, 1601, 1582, 523, 1601, 1605, 523, 1601, 1609, 523, 1601, + 1610, 523, 1602, 1581, 523, 1602, 1605, 523, 1602, 1609, 523, 1602, 1610, + 523, 1603, 1575, 523, 1603, 1580, 523, 1603, 1581, 523, 1603, 1582, 523, + 1603, 1604, 523, 1603, 1605, 523, 1603, 1609, 523, 1603, 1610, 523, 1604, + 1580, 523, 1604, 1581, 523, 1604, 1582, 523, 1604, 1605, 523, 1604, 1609, + 523, 1604, 1610, 523, 1605, 1580, 523, 1605, 1581, 523, 1605, 1582, 523, + 1605, 1605, 523, 1605, 1609, 523, 1605, 1610, 523, 1606, 1580, 523, 1606, + 1581, 523, 1606, 1582, 523, 1606, 1605, 523, 1606, 1609, 523, 1606, 1610, + 523, 1607, 1580, 523, 1607, 1605, 523, 1607, 1609, 523, 1607, 1610, 523, + 1610, 1580, 523, 1610, 1581, 523, 1610, 1582, 523, 1610, 1605, 523, 1610, + 1609, 523, 1610, 1610, 523, 1584, 1648, 523, 1585, 1648, 523, 1609, 1648, + 779, 32, 1612, 1617, 779, 32, 1613, 1617, 779, 32, 1614, 1617, 779, 32, + 1615, 1617, 779, 32, 1616, 1617, 779, 32, 1617, 1648, 524, 1574, 1585, + 524, 1574, 1586, 524, 1574, 1605, 524, 1574, 1606, 524, 1574, 1609, 524, + 1574, 1610, 524, 1576, 1585, 524, 1576, 1586, 524, 1576, 1605, 524, 1576, + 1606, 524, 1576, 1609, 524, 1576, 1610, 524, 1578, 1585, 524, 1578, 1586, + 524, 1578, 1605, 524, 1578, 1606, 524, 1578, 1609, 524, 1578, 1610, 524, + 1579, 1585, 524, 1579, 1586, 524, 1579, 1605, 524, 1579, 1606, 524, 1579, + 1609, 524, 1579, 1610, 524, 1601, 1609, 524, 1601, 1610, 524, 1602, 1609, + 524, 1602, 1610, 524, 1603, 1575, 524, 1603, 1604, 524, 1603, 1605, 524, + 1603, 1609, 524, 1603, 1610, 524, 1604, 1605, 524, 1604, 1609, 524, 1604, + 1610, 524, 1605, 1575, 524, 1605, 1605, 524, 1606, 1585, 524, 1606, 1586, + 524, 1606, 1605, 524, 1606, 1606, 524, 1606, 1609, 524, 1606, 1610, 524, + 1609, 1648, 524, 1610, 1585, 524, 1610, 1586, 524, 1610, 1605, 524, 1610, + 1606, 524, 1610, 1609, 524, 1610, 1610, 525, 1574, 1580, 525, 1574, 1581, + 525, 1574, 1582, 525, 1574, 1605, 525, 1574, 1607, 525, 1576, 1580, 525, + 1576, 1581, 525, 1576, 1582, 525, 1576, 1605, 525, 1576, 1607, 525, 1578, + 1580, 525, 1578, 1581, 525, 1578, 1582, 525, 1578, 1605, 525, 1578, 1607, + 525, 1579, 1605, 525, 1580, 1581, 525, 1580, 1605, 525, 1581, 1580, 525, + 1581, 1605, 525, 1582, 1580, 525, 1582, 1605, 525, 1587, 1580, 525, 1587, + 1581, 525, 1587, 1582, 525, 1587, 1605, 525, 1589, 1581, 525, 1589, 1582, + 525, 1589, 1605, 525, 1590, 1580, 525, 1590, 1581, 525, 1590, 1582, 525, + 1590, 1605, 525, 1591, 1581, 525, 1592, 1605, 525, 1593, 1580, 525, 1593, + 1605, 525, 1594, 1580, 525, 1594, 1605, 525, 1601, 1580, 525, 1601, 1581, + 525, 1601, 1582, 525, 1601, 1605, 525, 1602, 1581, 525, 1602, 1605, 525, + 1603, 1580, 525, 1603, 1581, 525, 1603, 1582, 525, 1603, 1604, 525, 1603, + 1605, 525, 1604, 1580, 525, 1604, 1581, 525, 1604, 1582, 525, 1604, 1605, + 525, 1604, 1607, 525, 1605, 1580, 525, 1605, 1581, 525, 1605, 1582, 525, + 1605, 1605, 525, 1606, 1580, 525, 1606, 1581, 525, 1606, 1582, 525, 1606, + 1605, 525, 1606, 1607, 525, 1607, 1580, 525, 1607, 1605, 525, 1607, 1648, + 525, 1610, 1580, 525, 1610, 1581, 525, 1610, 1582, 525, 1610, 1605, 525, + 1610, 1607, 526, 1574, 1605, 526, 1574, 1607, 526, 1576, 1605, 526, 1576, + 1607, 526, 1578, 1605, 526, 1578, 1607, 526, 1579, 1605, 526, 1579, 1607, + 526, 1587, 1605, 526, 1587, 1607, 526, 1588, 1605, 526, 1588, 1607, 526, + 1603, 1604, 526, 1603, 1605, 526, 1604, 1605, 526, 1606, 1605, 526, 1606, + 1607, 526, 1610, 1605, 526, 1610, 1607, 782, 1600, 1614, 1617, 782, 1600, + 1615, 1617, 782, 1600, 1616, 1617, 523, 1591, 1609, 523, 1591, 1610, 523, + 1593, 1609, 523, 1593, 1610, 523, 1594, 1609, 523, 1594, 1610, 523, 1587, + 1609, 523, 1587, 1610, 523, 1588, 1609, 523, 1588, 1610, 523, 1581, 1609, + 523, 1581, 1610, 523, 1580, 1609, 523, 1580, 1610, 523, 1582, 1609, 523, + 1582, 1610, 523, 1589, 1609, 523, 1589, 1610, 523, 1590, 1609, 523, 1590, + 1610, 523, 1588, 1580, 523, 1588, 1581, 523, 1588, 1582, 523, 1588, 1605, + 523, 1588, 1585, 523, 1587, 1585, 523, 1589, 1585, 523, 1590, 1585, 524, + 1591, 1609, 524, 1591, 1610, 524, 1593, 1609, 524, 1593, 1610, 524, 1594, + 1609, 524, 1594, 1610, 524, 1587, 1609, 524, 1587, 1610, 524, 1588, 1609, + 524, 1588, 1610, 524, 1581, 1609, 524, 1581, 1610, 524, 1580, 1609, 524, + 1580, 1610, 524, 1582, 1609, 524, 1582, 1610, 524, 1589, 1609, 524, 1589, + 1610, 524, 1590, 1609, 524, 1590, 1610, 524, 1588, 1580, 524, 1588, 1581, + 524, 1588, 1582, 524, 1588, 1605, 524, 1588, 1585, 524, 1587, 1585, 524, + 1589, 1585, 524, 1590, 1585, 525, 1588, 1580, 525, 1588, 1581, 525, 1588, + 1582, 525, 1588, 1605, 525, 1587, 1607, 525, 1588, 1607, 525, 1591, 1605, + 526, 1587, 1580, 526, 1587, 1581, 526, 1587, 1582, 526, 1588, 1580, 526, + 1588, 1581, 526, 1588, 1582, 526, 1591, 1605, 526, 1592, 1605, 524, 1575, + 1611, 523, 1575, 1611, 781, 1578, 1580, 1605, 780, 1578, 1581, 1580, 781, + 1578, 1581, 1580, 781, 1578, 1581, 1605, 781, 1578, 1582, 1605, 781, + 1578, 1605, 1580, 781, 1578, 1605, 1581, 781, 1578, 1605, 1582, 780, + 1580, 1605, 1581, 781, 1580, 1605, 1581, 780, 1581, 1605, 1610, 780, + 1581, 1605, 1609, 781, 1587, 1581, 1580, 781, 1587, 1580, 1581, 780, + 1587, 1580, 1609, 780, 1587, 1605, 1581, 781, 1587, 1605, 1581, 781, + 1587, 1605, 1580, 780, 1587, 1605, 1605, 781, 1587, 1605, 1605, 780, + 1589, 1581, 1581, 781, 1589, 1581, 1581, 780, 1589, 1605, 1605, 780, + 1588, 1581, 1605, 781, 1588, 1581, 1605, 780, 1588, 1580, 1610, 780, + 1588, 1605, 1582, 781, 1588, 1605, 1582, 780, 1588, 1605, 1605, 781, + 1588, 1605, 1605, 780, 1590, 1581, 1609, 780, 1590, 1582, 1605, 781, + 1590, 1582, 1605, 780, 1591, 1605, 1581, 781, 1591, 1605, 1581, 781, + 1591, 1605, 1605, 780, 1591, 1605, 1610, 780, 1593, 1580, 1605, 780, + 1593, 1605, 1605, 781, 1593, 1605, 1605, 780, 1593, 1605, 1609, 780, + 1594, 1605, 1605, 780, 1594, 1605, 1610, 780, 1594, 1605, 1609, 780, + 1601, 1582, 1605, 781, 1601, 1582, 1605, 780, 1602, 1605, 1581, 780, + 1602, 1605, 1605, 780, 1604, 1581, 1605, 780, 1604, 1581, 1610, 780, + 1604, 1581, 1609, 781, 1604, 1580, 1580, 780, 1604, 1580, 1580, 780, + 1604, 1582, 1605, 781, 1604, 1582, 1605, 780, 1604, 1605, 1581, 781, + 1604, 1605, 1581, 781, 1605, 1581, 1580, 781, 1605, 1581, 1605, 780, + 1605, 1581, 1610, 781, 1605, 1580, 1581, 781, 1605, 1580, 1605, 781, + 1605, 1582, 1580, 781, 1605, 1582, 1605, 781, 1605, 1580, 1582, 781, + 1607, 1605, 1580, 781, 1607, 1605, 1605, 781, 1606, 1581, 1605, 780, + 1606, 1581, 1609, 780, 1606, 1580, 1605, 781, 1606, 1580, 1605, 780, + 1606, 1580, 1609, 780, 1606, 1605, 1610, 780, 1606, 1605, 1609, 780, + 1610, 1605, 1605, 781, 1610, 1605, 1605, 780, 1576, 1582, 1610, 780, + 1578, 1580, 1610, 780, 1578, 1580, 1609, 780, 1578, 1582, 1610, 780, + 1578, 1582, 1609, 780, 1578, 1605, 1610, 780, 1578, 1605, 1609, 780, + 1580, 1605, 1610, 780, 1580, 1581, 1609, 780, 1580, 1605, 1609, 780, + 1587, 1582, 1609, 780, 1589, 1581, 1610, 780, 1588, 1581, 1610, 780, + 1590, 1581, 1610, 780, 1604, 1580, 1610, 780, 1604, 1605, 1610, 780, + 1610, 1581, 1610, 780, 1610, 1580, 1610, 780, 1610, 1605, 1610, 780, + 1605, 1605, 1610, 780, 1602, 1605, 1610, 780, 1606, 1581, 1610, 781, + 1602, 1605, 1581, 781, 1604, 1581, 1605, 780, 1593, 1605, 1610, 780, + 1603, 1605, 1610, 781, 1606, 1580, 1581, 780, 1605, 1582, 1610, 781, + 1604, 1580, 1605, 780, 1603, 1605, 1605, 780, 1604, 1580, 1605, 780, + 1606, 1580, 1581, 780, 1580, 1581, 1610, 780, 1581, 1580, 1610, 780, + 1605, 1580, 1610, 780, 1601, 1605, 1610, 780, 1576, 1581, 1610, 781, + 1603, 1605, 1605, 781, 1593, 1580, 1605, 781, 1589, 1605, 1605, 780, + 1587, 1582, 1610, 780, 1606, 1580, 1610, 779, 1589, 1604, 1746, 779, + 1602, 1604, 1746, 1035, 1575, 1604, 1604, 1607, 1035, 1575, 1603, 1576, + 1585, 1035, 1605, 1581, 1605, 1583, 1035, 1589, 1604, 1593, 1605, 1035, + 1585, 1587, 1608, 1604, 1035, 1593, 1604, 1610, 1607, 1035, 1608, 1587, + 1604, 1605, 779, 1589, 1604, 1609, 4619, 1589, 1604, 1609, 32, 1575, + 1604, 1604, 1607, 32, 1593, 1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, + 2059, 1580, 1604, 32, 1580, 1604, 1575, 1604, 1607, 1035, 1585, 1740, + 1575, 1604, 265, 44, 265, 12289, 265, 12290, 265, 58, 265, 59, 265, 33, + 265, 63, 265, 12310, 265, 12311, 265, 8230, 265, 8229, 265, 8212, 265, + 8211, 265, 95, 265, 95, 265, 40, 265, 41, 265, 123, 265, 125, 265, 12308, + 265, 12309, 265, 12304, 265, 12305, 265, 12298, 265, 12299, 265, 12296, + 265, 12297, 265, 12300, 265, 12301, 265, 12302, 265, 12303, 265, 91, 265, + 93, 258, 8254, 258, 8254, 258, 8254, 258, 8254, 258, 95, 258, 95, 258, + 95, 271, 44, 271, 12289, 271, 46, 271, 59, 271, 58, 271, 63, 271, 33, + 271, 8212, 271, 40, 271, 41, 271, 123, 271, 125, 271, 12308, 271, 12309, + 271, 35, 271, 38, 271, 42, 271, 43, 271, 45, 271, 60, 271, 62, 271, 61, + 271, 92, 271, 36, 271, 37, 271, 64, 523, 32, 1611, 526, 1600, 1611, 523, + 32, 1612, 523, 32, 1613, 523, 32, 1614, 526, 1600, 1614, 523, 32, 1615, + 526, 1600, 1615, 523, 32, 1616, 526, 1600, 1616, 523, 32, 1617, 526, + 1600, 1617, 523, 32, 1618, 526, 1600, 1618, 267, 1569, 267, 1570, 268, + 1570, 267, 1571, 268, 1571, 267, 1572, 268, 1572, 267, 1573, 268, 1573, + 267, 1574, 268, 1574, 269, 1574, 270, 1574, 267, 1575, 268, 1575, 267, + 1576, 268, 1576, 269, 1576, 270, 1576, 267, 1577, 268, 1577, 267, 1578, + 268, 1578, 269, 1578, 270, 1578, 267, 1579, 268, 1579, 269, 1579, 270, + 1579, 267, 1580, 268, 1580, 269, 1580, 270, 1580, 267, 1581, 268, 1581, + 269, 1581, 270, 1581, 267, 1582, 268, 1582, 269, 1582, 270, 1582, 267, + 1583, 268, 1583, 267, 1584, 268, 1584, 267, 1585, 268, 1585, 267, 1586, + 268, 1586, 267, 1587, 268, 1587, 269, 1587, 270, 1587, 267, 1588, 268, + 1588, 269, 1588, 270, 1588, 267, 1589, 268, 1589, 269, 1589, 270, 1589, + 267, 1590, 268, 1590, 269, 1590, 270, 1590, 267, 1591, 268, 1591, 269, + 1591, 270, 1591, 267, 1592, 268, 1592, 269, 1592, 270, 1592, 267, 1593, + 268, 1593, 269, 1593, 270, 1593, 267, 1594, 268, 1594, 269, 1594, 270, + 1594, 267, 1601, 268, 1601, 269, 1601, 270, 1601, 267, 1602, 268, 1602, + 269, 1602, 270, 1602, 267, 1603, 268, 1603, 269, 1603, 270, 1603, 267, + 1604, 268, 1604, 269, 1604, 270, 1604, 267, 1605, 268, 1605, 269, 1605, + 270, 1605, 267, 1606, 268, 1606, 269, 1606, 270, 1606, 267, 1607, 268, + 1607, 269, 1607, 270, 1607, 267, 1608, 268, 1608, 267, 1609, 268, 1609, + 267, 1610, 268, 1610, 269, 1610, 270, 1610, 523, 1604, 1570, 524, 1604, + 1570, 523, 1604, 1571, 524, 1604, 1571, 523, 1604, 1573, 524, 1604, 1573, + 523, 1604, 1575, 524, 1604, 1575, 264, 33, 264, 34, 264, 35, 264, 36, + 264, 37, 264, 38, 264, 39, 264, 40, 264, 41, 264, 42, 264, 43, 264, 44, + 264, 45, 264, 46, 264, 47, 264, 48, 264, 49, 264, 50, 264, 51, 264, 52, + 264, 53, 264, 54, 264, 55, 264, 56, 264, 57, 264, 58, 264, 59, 264, 60, + 264, 61, 264, 62, 264, 63, 264, 64, 264, 65, 264, 66, 264, 67, 264, 68, + 264, 69, 264, 70, 264, 71, 264, 72, 264, 73, 264, 74, 264, 75, 264, 76, + 264, 77, 264, 78, 264, 79, 264, 80, 264, 81, 264, 82, 264, 83, 264, 84, + 264, 85, 264, 86, 264, 87, 264, 88, 264, 89, 264, 90, 264, 91, 264, 92, + 264, 93, 264, 94, 264, 95, 264, 96, 264, 97, 264, 98, 264, 99, 264, 100, + 264, 101, 264, 102, 264, 103, 264, 104, 264, 105, 264, 106, 264, 107, + 264, 108, 264, 109, 264, 110, 264, 111, 264, 112, 264, 113, 264, 114, + 264, 115, 264, 116, 264, 117, 264, 118, 264, 119, 264, 120, 264, 121, + 264, 122, 264, 123, 264, 124, 264, 125, 264, 126, 264, 10629, 264, 10630, + 272, 12290, 272, 12300, 272, 12301, 272, 12289, 272, 12539, 272, 12530, + 272, 12449, 272, 12451, 272, 12453, 272, 12455, 272, 12457, 272, 12515, + 272, 12517, 272, 12519, 272, 12483, 272, 12540, 272, 12450, 272, 12452, + 272, 12454, 272, 12456, 272, 12458, 272, 12459, 272, 12461, 272, 12463, + 272, 12465, 272, 12467, 272, 12469, 272, 12471, 272, 12473, 272, 12475, + 272, 12477, 272, 12479, 272, 12481, 272, 12484, 272, 12486, 272, 12488, + 272, 12490, 272, 12491, 272, 12492, 272, 12493, 272, 12494, 272, 12495, + 272, 12498, 272, 12501, 272, 12504, 272, 12507, 272, 12510, 272, 12511, + 272, 12512, 272, 12513, 272, 12514, 272, 12516, 272, 12518, 272, 12520, + 272, 12521, 272, 12522, 272, 12523, 272, 12524, 272, 12525, 272, 12527, + 272, 12531, 272, 12441, 272, 12442, 272, 12644, 272, 12593, 272, 12594, + 272, 12595, 272, 12596, 272, 12597, 272, 12598, 272, 12599, 272, 12600, + 272, 12601, 272, 12602, 272, 12603, 272, 12604, 272, 12605, 272, 12606, + 272, 12607, 272, 12608, 272, 12609, 272, 12610, 272, 12611, 272, 12612, + 272, 12613, 272, 12614, 272, 12615, 272, 12616, 272, 12617, 272, 12618, + 272, 12619, 272, 12620, 272, 12621, 272, 12622, 272, 12623, 272, 12624, + 272, 12625, 272, 12626, 272, 12627, 272, 12628, 272, 12629, 272, 12630, + 272, 12631, 272, 12632, 272, 12633, 272, 12634, 272, 12635, 272, 12636, + 272, 12637, 272, 12638, 272, 12639, 272, 12640, 272, 12641, 272, 12642, + 272, 12643, 264, 162, 264, 163, 264, 172, 264, 175, 264, 166, 264, 165, + 264, 8361, 272, 9474, 272, 8592, 272, 8593, 272, 8594, 272, 8595, 272, + 9632, 272, 9675, 512, 119127, 119141, 512, 119128, 119141, 512, 119135, + 119150, 512, 119135, 119151, 512, 119135, 119152, 512, 119135, 119153, + 512, 119135, 119154, 512, 119225, 119141, 512, 119226, 119141, 512, + 119227, 119150, 512, 119228, 119150, 512, 119227, 119151, 512, 119228, + 119151, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, + 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, + 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, + 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, + 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, + 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, + 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, + 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, + 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, + 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, + 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, + 102, 262, 103, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, + 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, + 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, + 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, + 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, + 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, + 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, + 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, + 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, + 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 67, 262, 68, + 262, 71, 262, 74, 262, 75, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, + 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, + 262, 98, 262, 99, 262, 100, 262, 102, 262, 104, 262, 105, 262, 106, 262, + 107, 262, 108, 262, 109, 262, 110, 262, 112, 262, 113, 262, 114, 262, + 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, + 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, + 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, + 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, + 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, + 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, + 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, + 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, + 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 74, 262, 75, 262, 76, + 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 262, 84, 262, 85, + 262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, + 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, + 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, + 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, + 262, 122, 262, 65, 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 73, + 262, 74, 262, 75, 262, 76, 262, 77, 262, 79, 262, 83, 262, 84, 262, 85, + 262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, + 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, + 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, + 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, + 262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, + 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, + 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, + 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, + 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, + 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, + 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, + 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, + 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, + 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, + 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, + 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, + 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, + 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, + 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, + 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, + 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, + 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, + 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, + 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, + 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, + 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, + 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, + 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, + 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, + 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, + 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, + 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, + 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, + 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, + 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, + 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, + 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, + 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, + 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 262, 68, + 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, + 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, + 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, + 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, + 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, + 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, + 120, 262, 121, 262, 122, 262, 305, 262, 567, 262, 913, 262, 914, 262, + 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, + 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, + 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, + 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, + 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, + 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, + 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, + 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, + 913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, + 920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, + 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, + 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, + 947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, + 954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, + 961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, + 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, + 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 916, 262, 917, 262, + 918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 923, 262, 924, 262, + 925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, + 932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, + 945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 950, 262, 951, 262, + 952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 957, 262, 958, 262, + 959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 964, 262, 965, 262, + 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, + 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, + 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 922, 262, + 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 929, 262, + 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 936, 262, + 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 949, 262, + 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 956, 262, + 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 963, 262, + 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, + 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, + 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, + 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, + 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, + 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, + 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, + 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, + 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, + 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, + 982, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, + 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, + 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, + 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, + 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, + 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, + 55, 262, 56, 262, 57, 256, 20029, 256, 20024, 256, 20033, 256, 131362, + 256, 20320, 256, 20398, 256, 20411, 256, 20482, 256, 20602, 256, 20633, + 256, 20711, 256, 20687, 256, 13470, 256, 132666, 256, 20813, 256, 20820, + 256, 20836, 256, 20855, 256, 132380, 256, 13497, 256, 20839, 256, 20877, + 256, 132427, 256, 20887, 256, 20900, 256, 20172, 256, 20908, 256, 20917, + 256, 168415, 256, 20981, 256, 20995, 256, 13535, 256, 21051, 256, 21062, + 256, 21106, 256, 21111, 256, 13589, 256, 21191, 256, 21193, 256, 21220, + 256, 21242, 256, 21253, 256, 21254, 256, 21271, 256, 21321, 256, 21329, + 256, 21338, 256, 21363, 256, 21373, 256, 21375, 256, 21375, 256, 21375, + 256, 133676, 256, 28784, 256, 21450, 256, 21471, 256, 133987, 256, 21483, + 256, 21489, 256, 21510, 256, 21662, 256, 21560, 256, 21576, 256, 21608, + 256, 21666, 256, 21750, 256, 21776, 256, 21843, 256, 21859, 256, 21892, + 256, 21892, 256, 21913, 256, 21931, 256, 21939, 256, 21954, 256, 22294, + 256, 22022, 256, 22295, 256, 22097, 256, 22132, 256, 20999, 256, 22766, + 256, 22478, 256, 22516, 256, 22541, 256, 22411, 256, 22578, 256, 22577, + 256, 22700, 256, 136420, 256, 22770, 256, 22775, 256, 22790, 256, 22810, + 256, 22818, 256, 22882, 256, 136872, 256, 136938, 256, 23020, 256, 23067, + 256, 23079, 256, 23000, 256, 23142, 256, 14062, 256, 14076, 256, 23304, + 256, 23358, 256, 23358, 256, 137672, 256, 23491, 256, 23512, 256, 23527, + 256, 23539, 256, 138008, 256, 23551, 256, 23558, 256, 24403, 256, 23586, + 256, 14209, 256, 23648, 256, 23662, 256, 23744, 256, 23693, 256, 138724, + 256, 23875, 256, 138726, 256, 23918, 256, 23915, 256, 23932, 256, 24033, + 256, 24034, 256, 14383, 256, 24061, 256, 24104, 256, 24125, 256, 24169, + 256, 14434, 256, 139651, 256, 14460, 256, 24240, 256, 24243, 256, 24246, + 256, 24266, 256, 172946, 256, 24318, 256, 140081, 256, 140081, 256, + 33281, 256, 24354, 256, 24354, 256, 14535, 256, 144056, 256, 156122, 256, + 24418, 256, 24427, 256, 14563, 256, 24474, 256, 24525, 256, 24535, 256, + 24569, 256, 24705, 256, 14650, 256, 14620, 256, 24724, 256, 141012, 256, + 24775, 256, 24904, 256, 24908, 256, 24910, 256, 24908, 256, 24954, 256, + 24974, 256, 25010, 256, 24996, 256, 25007, 256, 25054, 256, 25074, 256, + 25078, 256, 25104, 256, 25115, 256, 25181, 256, 25265, 256, 25300, 256, + 25424, 256, 142092, 256, 25405, 256, 25340, 256, 25448, 256, 25475, 256, + 25572, 256, 142321, 256, 25634, 256, 25541, 256, 25513, 256, 14894, 256, + 25705, 256, 25726, 256, 25757, 256, 25719, 256, 14956, 256, 25935, 256, + 25964, 256, 143370, 256, 26083, 256, 26360, 256, 26185, 256, 15129, 256, + 26257, 256, 15112, 256, 15076, 256, 20882, 256, 20885, 256, 26368, 256, + 26268, 256, 32941, 256, 17369, 256, 26391, 256, 26395, 256, 26401, 256, + 26462, 256, 26451, 256, 144323, 256, 15177, 256, 26618, 256, 26501, 256, + 26706, 256, 26757, 256, 144493, 256, 26766, 256, 26655, 256, 26900, 256, + 15261, 256, 26946, 256, 27043, 256, 27114, 256, 27304, 256, 145059, 256, + 27355, 256, 15384, 256, 27425, 256, 145575, 256, 27476, 256, 15438, 256, + 27506, 256, 27551, 256, 27578, 256, 27579, 256, 146061, 256, 138507, 256, + 146170, 256, 27726, 256, 146620, 256, 27839, 256, 27853, 256, 27751, 256, + 27926, 256, 27966, 256, 28023, 256, 27969, 256, 28009, 256, 28024, 256, + 28037, 256, 146718, 256, 27956, 256, 28207, 256, 28270, 256, 15667, 256, + 28363, 256, 28359, 256, 147153, 256, 28153, 256, 28526, 256, 147294, 256, + 147342, 256, 28614, 256, 28729, 256, 28702, 256, 28699, 256, 15766, 256, + 28746, 256, 28797, 256, 28791, 256, 28845, 256, 132389, 256, 28997, 256, + 148067, 256, 29084, 256, 148395, 256, 29224, 256, 29237, 256, 29264, 256, + 149000, 256, 29312, 256, 29333, 256, 149301, 256, 149524, 256, 29562, + 256, 29579, 256, 16044, 256, 29605, 256, 16056, 256, 16056, 256, 29767, + 256, 29788, 256, 29809, 256, 29829, 256, 29898, 256, 16155, 256, 29988, + 256, 150582, 256, 30014, 256, 150674, 256, 30064, 256, 139679, 256, + 30224, 256, 151457, 256, 151480, 256, 151620, 256, 16380, 256, 16392, + 256, 30452, 256, 151795, 256, 151794, 256, 151833, 256, 151859, 256, + 30494, 256, 30495, 256, 30495, 256, 30538, 256, 16441, 256, 30603, 256, + 16454, 256, 16534, 256, 152605, 256, 30798, 256, 30860, 256, 30924, 256, + 16611, 256, 153126, 256, 31062, 256, 153242, 256, 153285, 256, 31119, + 256, 31211, 256, 16687, 256, 31296, 256, 31306, 256, 31311, 256, 153980, + 256, 154279, 256, 154279, 256, 31470, 256, 16898, 256, 154539, 256, + 31686, 256, 31689, 256, 16935, 256, 154752, 256, 31954, 256, 17056, 256, + 31976, 256, 31971, 256, 32000, 256, 155526, 256, 32099, 256, 17153, 256, + 32199, 256, 32258, 256, 32325, 256, 17204, 256, 156200, 256, 156231, 256, + 17241, 256, 156377, 256, 32634, 256, 156478, 256, 32661, 256, 32762, 256, + 32773, 256, 156890, 256, 156963, 256, 32864, 256, 157096, 256, 32880, + 256, 144223, 256, 17365, 256, 32946, 256, 33027, 256, 17419, 256, 33086, + 256, 23221, 256, 157607, 256, 157621, 256, 144275, 256, 144284, 256, + 33281, 256, 33284, 256, 36766, 256, 17515, 256, 33425, 256, 33419, 256, + 33437, 256, 21171, 256, 33457, 256, 33459, 256, 33469, 256, 33510, 256, + 158524, 256, 33509, 256, 33565, 256, 33635, 256, 33709, 256, 33571, 256, + 33725, 256, 33767, 256, 33879, 256, 33619, 256, 33738, 256, 33740, 256, + 33756, 256, 158774, 256, 159083, 256, 158933, 256, 17707, 256, 34033, + 256, 34035, 256, 34070, 256, 160714, 256, 34148, 256, 159532, 256, 17757, + 256, 17761, 256, 159665, 256, 159954, 256, 17771, 256, 34384, 256, 34396, + 256, 34407, 256, 34409, 256, 34473, 256, 34440, 256, 34574, 256, 34530, + 256, 34681, 256, 34600, 256, 34667, 256, 34694, 256, 17879, 256, 34785, + 256, 34817, 256, 17913, 256, 34912, 256, 34915, 256, 161383, 256, 35031, + 256, 35038, 256, 17973, 256, 35066, 256, 13499, 256, 161966, 256, 162150, + 256, 18110, 256, 18119, 256, 35488, 256, 35565, 256, 35722, 256, 35925, + 256, 162984, 256, 36011, 256, 36033, 256, 36123, 256, 36215, 256, 163631, + 256, 133124, 256, 36299, 256, 36284, 256, 36336, 256, 133342, 256, 36564, + 256, 36664, 256, 165330, 256, 165357, 256, 37012, 256, 37105, 256, 37137, + 256, 165678, 256, 37147, 256, 37432, 256, 37591, 256, 37592, 256, 37500, + 256, 37881, 256, 37909, 256, 166906, 256, 38283, 256, 18837, 256, 38327, + 256, 167287, 256, 18918, 256, 38595, 256, 23986, 256, 38691, 256, 168261, + 256, 168474, 256, 19054, 256, 19062, 256, 38880, 256, 168970, 256, 19122, + 256, 169110, 256, 38923, 256, 38923, 256, 38953, 256, 169398, 256, 39138, + 256, 19251, 256, 39209, 256, 39335, 256, 39362, 256, 39422, 256, 19406, + 256, 170800, 256, 39698, 256, 40000, 256, 40189, 256, 19662, 256, 19693, + 256, 40295, 256, 172238, 256, 19704, 256, 172293, 256, 172558, 256, + 172689, 256, 40635, 256, 19798, 256, 40697, 256, 40702, 256, 40709, 256, + 40719, 256, 40726, 256, 40763, 256, 173568, +}; + +/* index tables for the decomposition data */ +#define DECOMP_SHIFT 8 +static unsigned char decomp_index1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 16, 17, 18, 19, 20, 21, 22, 23, 7, 7, 7, 7, 7, 24, + 7, 7, 25, 26, 27, 28, 29, 30, 31, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 32, 33, 34, 35, 36, 37, + 38, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 39, 7, 7, 40, 41, + 42, 43, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 44, 45, 46, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +}; + +static unsigned short decomp_index2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27, + 31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81, + 0, 84, 87, 90, 93, 96, 99, 0, 0, 102, 105, 108, 111, 114, 0, 0, 117, 120, + 123, 126, 129, 132, 0, 135, 138, 141, 144, 147, 150, 153, 156, 159, 0, + 162, 165, 168, 171, 174, 177, 0, 0, 180, 183, 186, 189, 192, 0, 195, 198, + 201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, + 243, 0, 0, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, + 282, 285, 288, 291, 294, 297, 300, 303, 0, 0, 306, 309, 312, 315, 318, + 321, 324, 327, 330, 0, 333, 336, 339, 342, 345, 348, 0, 351, 354, 357, + 360, 363, 366, 369, 372, 0, 0, 375, 378, 381, 384, 387, 390, 393, 0, 0, + 396, 399, 402, 405, 408, 411, 0, 0, 414, 417, 420, 423, 426, 429, 432, + 435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 0, 0, 468, 471, + 474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, + 516, 519, 522, 525, 528, 531, 534, 537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 539, 542, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 545, 548, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 551, 554, 557, 560, 563, 566, 569, 572, + 575, 578, 581, 584, 587, 590, 593, 596, 599, 602, 605, 608, 611, 614, + 617, 620, 623, 0, 626, 629, 632, 635, 638, 641, 0, 0, 644, 647, 650, 653, + 656, 659, 662, 665, 668, 671, 674, 677, 680, 683, 686, 689, 0, 0, 692, + 695, 698, 701, 704, 707, 710, 713, 716, 719, 722, 725, 728, 731, 734, + 737, 740, 743, 746, 749, 752, 755, 758, 761, 764, 767, 770, 773, 776, + 779, 782, 785, 788, 791, 794, 797, 0, 0, 800, 803, 0, 0, 0, 0, 0, 0, 806, + 809, 812, 815, 818, 821, 824, 827, 830, 833, 836, 839, 842, 845, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 848, 850, 852, 854, 856, 858, 860, 862, 864, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 866, + 869, 872, 875, 878, 881, 0, 0, 884, 886, 888, 890, 892, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 894, 896, 0, 898, 900, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, + 0, 905, 0, 0, 0, 908, 0, 0, 0, 0, 0, 910, 913, 916, 919, 921, 924, 927, + 0, 930, 0, 933, 936, 939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 942, 945, 948, 951, 954, 957, 960, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 963, 966, + 969, 972, 975, 0, 978, 980, 982, 984, 987, 990, 992, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 994, 996, 998, 0, + 1000, 1002, 0, 0, 0, 1004, 0, 0, 0, 0, 0, 0, 1006, 1009, 0, 1012, 0, 0, + 0, 1015, 0, 0, 0, 0, 1018, 1021, 1024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1033, 1036, 0, 1039, 0, 0, 0, 1042, 0, 0, 0, + 0, 1045, 1048, 1051, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1054, 1057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1060, 1063, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1066, 1069, 1072, 1075, 0, 0, 1078, 1081, 0, 0, 1084, 1087, + 1090, 1093, 1096, 1099, 0, 0, 1102, 1105, 1108, 1111, 1114, 1117, 0, 0, + 1120, 1123, 1126, 1129, 1132, 1135, 1138, 1141, 1144, 1147, 1150, 1153, + 0, 0, 1156, 1159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1165, 1168, 1171, 1174, + 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1180, 1183, 1186, 1189, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1192, 0, 1195, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1201, 0, 0, 0, + 0, 0, 0, 0, 1204, 0, 0, 1207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1210, + 1213, 1216, 1219, 1222, 1225, 1228, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1234, 1237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1240, 1243, + 0, 1246, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1249, 0, 0, 1252, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1255, 1258, 1261, 0, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1267, 0, 0, 1270, 1273, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1276, 1279, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1285, 1288, 1291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1294, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, 0, 0, 1300, 1303, 0, + 1306, 1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1315, 1318, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1321, 0, 1324, 1327, 1330, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1336, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1339, 1342, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1345, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 0, 0, 0, 1353, 0, 0, 0, 0, + 1356, 0, 0, 0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1365, 0, 1368, 1371, 1374, 1377, 1380, 0, 0, 0, 0, + 0, 0, 0, 1383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1386, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1389, 0, 0, 0, 0, 1392, 0, 0, 0, 0, 1395, 0, + 0, 0, 0, 1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1401, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1409, 1411, 1413, 0, 1415, 1417, 1419, 1421, 1423, + 1425, 1427, 1429, 1431, 1433, 1435, 0, 1437, 1439, 1441, 1443, 1445, + 1447, 1449, 1451, 1453, 1455, 1457, 1459, 1461, 1463, 1465, 1467, 1469, + 1471, 0, 1473, 1475, 1477, 1479, 1481, 1483, 1485, 1487, 1489, 1491, + 1493, 1495, 1497, 1499, 1501, 1503, 1505, 1507, 1509, 1511, 1513, 1515, + 1517, 1519, 1521, 1523, 1525, 1527, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1531, 1533, 1535, 1537, 1539, + 1541, 1543, 1545, 1547, 1549, 1551, 1553, 1555, 1557, 1559, 1561, 1563, + 1565, 1567, 1569, 1571, 1573, 1575, 1577, 1579, 1581, 1583, 1585, 1587, + 1589, 1591, 1593, 1595, 1597, 1599, 1601, 1603, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1605, 1608, 1611, 1614, 1617, 1620, 1623, 1626, + 1629, 1632, 1635, 1638, 1641, 1644, 1647, 1650, 1653, 1656, 1659, 1662, + 1665, 1668, 1671, 1674, 1677, 1680, 1683, 1686, 1689, 1692, 1695, 1698, + 1701, 1704, 1707, 1710, 1713, 1716, 1719, 1722, 1725, 1728, 1731, 1734, + 1737, 1740, 1743, 1746, 1749, 1752, 1755, 1758, 1761, 1764, 1767, 1770, + 1773, 1776, 1779, 1782, 1785, 1788, 1791, 1794, 1797, 1800, 1803, 1806, + 1809, 1812, 1815, 1818, 1821, 1824, 1827, 1830, 1833, 1836, 1839, 1842, + 1845, 1848, 1851, 1854, 1857, 1860, 1863, 1866, 1869, 1872, 1875, 1878, + 1881, 1884, 1887, 1890, 1893, 1896, 1899, 1902, 1905, 1908, 1911, 1914, + 1917, 1920, 1923, 1926, 1929, 1932, 1935, 1938, 1941, 1944, 1947, 1950, + 1953, 1956, 1959, 1962, 1965, 1968, 1971, 1974, 1977, 1980, 1983, 1986, + 1989, 1992, 1995, 1998, 2001, 2004, 2007, 2010, 2013, 2016, 2019, 2022, + 2025, 2028, 2031, 2034, 2037, 2040, 2043, 2046, 2049, 2052, 2055, 2058, + 2061, 2064, 2067, 2070, 0, 0, 0, 0, 2073, 2076, 2079, 2082, 2085, 2088, + 2091, 2094, 2097, 2100, 2103, 2106, 2109, 2112, 2115, 2118, 2121, 2124, + 2127, 2130, 2133, 2136, 2139, 2142, 2145, 2148, 2151, 2154, 2157, 2160, + 2163, 2166, 2169, 2172, 2175, 2178, 2181, 2184, 2187, 2190, 2193, 2196, + 2199, 2202, 2205, 2208, 2211, 2214, 2217, 2220, 2223, 2226, 2229, 2232, + 2235, 2238, 2241, 2244, 2247, 2250, 2253, 2256, 2259, 2262, 2265, 2268, + 2271, 2274, 2277, 2280, 2283, 2286, 2289, 2292, 2295, 2298, 2301, 2304, + 2307, 2310, 2313, 2316, 2319, 2322, 2325, 2328, 2331, 2334, 2337, 2340, + 0, 0, 0, 0, 0, 0, 2343, 2346, 2349, 2352, 2355, 2358, 2361, 2364, 2367, + 2370, 2373, 2376, 2379, 2382, 2385, 2388, 2391, 2394, 2397, 2400, 2403, + 2406, 0, 0, 2409, 2412, 2415, 2418, 2421, 2424, 0, 0, 2427, 2430, 2433, + 2436, 2439, 2442, 2445, 2448, 2451, 2454, 2457, 2460, 2463, 2466, 2469, + 2472, 2475, 2478, 2481, 2484, 2487, 2490, 2493, 2496, 2499, 2502, 2505, + 2508, 2511, 2514, 2517, 2520, 2523, 2526, 2529, 2532, 2535, 2538, 0, 0, + 2541, 2544, 2547, 2550, 2553, 2556, 0, 0, 2559, 2562, 2565, 2568, 2571, + 2574, 2577, 2580, 0, 2583, 0, 2586, 0, 2589, 0, 2592, 2595, 2598, 2601, + 2604, 2607, 2610, 2613, 2616, 2619, 2622, 2625, 2628, 2631, 2634, 2637, + 2640, 2643, 2646, 2648, 2651, 2653, 2656, 2658, 2661, 2663, 2666, 2668, + 2671, 2673, 2676, 0, 0, 2678, 2681, 2684, 2687, 2690, 2693, 2696, 2699, + 2702, 2705, 2708, 2711, 2714, 2717, 2720, 2723, 2726, 2729, 2732, 2735, + 2738, 2741, 2744, 2747, 2750, 2753, 2756, 2759, 2762, 2765, 2768, 2771, + 2774, 2777, 2780, 2783, 2786, 2789, 2792, 2795, 2798, 2801, 2804, 2807, + 2810, 2813, 2816, 2819, 2822, 2825, 2828, 2831, 2834, 0, 2837, 2840, + 2843, 2846, 2849, 2852, 2854, 2857, 2860, 2862, 2865, 2868, 2871, 2874, + 2877, 0, 2880, 2883, 2886, 2889, 2891, 2894, 2896, 2899, 2902, 2905, + 2908, 2911, 2914, 2917, 0, 0, 2919, 2922, 2925, 2928, 2931, 2934, 0, + 2936, 2939, 2942, 2945, 2948, 2951, 2954, 2956, 2959, 2962, 2965, 2968, + 2971, 2974, 2977, 2979, 2982, 2985, 2987, 0, 0, 2989, 2992, 2995, 0, + 2998, 3001, 3004, 3007, 3009, 3012, 3014, 3017, 3019, 0, 3022, 3024, + 3026, 3028, 3030, 3032, 3034, 3036, 3038, 3040, 3042, 0, 0, 0, 0, 0, 0, + 3044, 0, 0, 0, 0, 0, 3046, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3049, + 3051, 3054, 0, 0, 0, 0, 0, 0, 0, 0, 3058, 0, 0, 0, 3060, 3063, 0, 3067, + 3070, 0, 0, 0, 0, 3074, 0, 3077, 0, 0, 0, 0, 0, 0, 0, 0, 3080, 3083, + 3086, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3089, 0, 0, 0, 0, 0, 0, 0, + 3094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3096, 3098, 0, 0, + 3100, 3102, 3104, 3106, 3108, 3110, 3112, 3114, 3116, 3118, 3120, 3122, + 3124, 3126, 3128, 3130, 3132, 3134, 3136, 3138, 3140, 3142, 3144, 3146, + 3148, 3150, 3152, 0, 3154, 3156, 3158, 3160, 3162, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3167, 3171, 3175, 3177, 0, 3180, 3184, 3188, 0, 3190, + 3193, 3195, 3197, 3199, 3201, 3203, 3205, 3207, 3209, 3211, 0, 3213, + 3215, 0, 0, 3218, 3220, 3222, 3224, 3226, 0, 0, 3228, 3231, 3235, 0, + 3238, 0, 3240, 0, 3242, 0, 3244, 3246, 3248, 3250, 0, 3252, 3254, 3256, + 0, 3258, 3260, 3262, 3264, 3266, 3268, 3270, 0, 3272, 3276, 3278, 3280, + 3282, 3284, 0, 0, 0, 0, 3286, 3288, 3290, 3292, 3294, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3296, 3300, 3304, 3308, 3312, 3316, 3320, 3324, 3328, 3332, + 3336, 3340, 3344, 3347, 3349, 3352, 3356, 3359, 3361, 3364, 3368, 3373, + 3376, 3378, 3381, 3385, 3387, 3389, 3391, 3393, 3395, 3398, 3402, 3405, + 3407, 3410, 3414, 3419, 3422, 3424, 3427, 3431, 3433, 3435, 3437, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3439, 3442, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3445, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3448, 3451, 3454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3457, 0, 0, 0, 0, 3460, + 0, 0, 3463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 3466, 0, 3469, 0, 0, 0, 0, 0, 3472, 3475, 0, 3479, 3482, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3486, 0, 0, 3489, 0, 0, 3492, + 0, 3495, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3498, 0, 3501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3504, 3507, 3510, 3513, + 3516, 0, 0, 3519, 3522, 0, 0, 3525, 3528, 0, 0, 0, 0, 0, 0, 3531, 3534, + 0, 0, 3537, 3540, 0, 0, 3543, 3546, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3549, + 3552, 3555, 3558, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3561, 3564, 3567, 3570, 0, 0, 0, 0, 0, 0, 3573, 3576, + 3579, 3582, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3585, 3587, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3589, 3591, 3593, 3595, + 3597, 3599, 3601, 3603, 3605, 3607, 3610, 3613, 3616, 3619, 3622, 3625, + 3628, 3631, 3634, 3637, 3640, 3644, 3648, 3652, 3656, 3660, 3664, 3668, + 3672, 3676, 3681, 3686, 3691, 3696, 3701, 3706, 3711, 3716, 3721, 3726, + 3731, 3734, 3737, 3740, 3743, 3746, 3749, 3752, 3755, 3758, 3762, 3766, + 3770, 3774, 3778, 3782, 3786, 3790, 3794, 3798, 3802, 3806, 3810, 3814, + 3818, 3822, 3826, 3830, 3834, 3838, 3842, 3846, 3850, 3854, 3858, 3862, + 3866, 3870, 3874, 3878, 3882, 3886, 3890, 3894, 3898, 3902, 3906, 3908, + 3910, 3912, 3914, 3916, 3918, 3920, 3922, 3924, 3926, 3928, 3930, 3932, + 3934, 3936, 3938, 3940, 3942, 3944, 3946, 3948, 3950, 3952, 3954, 3956, + 3958, 3960, 3962, 3964, 3966, 3968, 3970, 3972, 3974, 3976, 3978, 3980, + 3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, + 4006, 4008, 4010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4012, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4017, 4021, 4024, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4028, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4031, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4033, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4035, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4037, 4039, 4041, 4043, 4045, 4047, + 4049, 4051, 4053, 4055, 4057, 4059, 4061, 4063, 4065, 4067, 4069, 4071, + 4073, 4075, 4077, 4079, 4081, 4083, 4085, 4087, 4089, 4091, 4093, 4095, + 4097, 4099, 4101, 4103, 4105, 4107, 4109, 4111, 4113, 4115, 4117, 4119, + 4121, 4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, + 4145, 4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, + 4169, 4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, + 4193, 4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, + 4217, 4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, + 4241, 4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, + 4265, 4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, + 4289, 4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, + 4313, 4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, + 4337, 4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, + 4361, 4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, + 4385, 4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, + 4409, 4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, + 4433, 4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, + 4457, 4459, 4461, 4463, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4467, 0, 4469, 4471, 4473, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4475, 0, 4478, 0, 4481, 0, 4484, 0, + 4487, 0, 4490, 0, 4493, 0, 4496, 0, 4499, 0, 4502, 0, 4505, 0, 4508, 0, + 0, 4511, 0, 4514, 0, 4517, 0, 0, 0, 0, 0, 0, 4520, 4523, 0, 4526, 4529, + 0, 4532, 4535, 0, 4538, 4541, 0, 4544, 4547, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4550, 0, 0, 0, 0, 0, 0, 4553, + 4556, 0, 4559, 4562, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4565, 0, 4568, + 0, 4571, 0, 4574, 0, 4577, 0, 4580, 0, 4583, 0, 4586, 0, 4589, 0, 4592, + 0, 4595, 0, 4598, 0, 0, 4601, 0, 4604, 0, 4607, 0, 0, 0, 0, 0, 0, 4610, + 4613, 0, 4616, 4619, 0, 4622, 4625, 0, 4628, 4631, 0, 4634, 4637, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4640, 0, 0, + 4643, 4646, 4649, 4652, 0, 0, 0, 4655, 4658, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4661, 4663, 4665, 4667, + 4669, 4671, 4673, 4675, 4677, 4679, 4681, 4683, 4685, 4687, 4689, 4691, + 4693, 4695, 4697, 4699, 4701, 4703, 4705, 4707, 4709, 4711, 4713, 4715, + 4717, 4719, 4721, 4723, 4725, 4727, 4729, 4731, 4733, 4735, 4737, 4739, + 4741, 4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, + 4765, 4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, + 4789, 4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, + 4813, 4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, + 4837, 4839, 4841, 4843, 4845, 4847, 0, 0, 0, 4849, 4851, 4853, 4855, + 4857, 4859, 4861, 4863, 4865, 4867, 4869, 4871, 4873, 4875, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4877, 4881, + 4885, 4889, 4893, 4897, 4901, 4905, 4909, 4913, 4917, 4921, 4925, 4929, + 4933, 4938, 4943, 4948, 4953, 4958, 4963, 4968, 4973, 4978, 4983, 4988, + 4993, 4998, 5003, 5008, 5016, 0, 5023, 5027, 5031, 5035, 5039, 5043, + 5047, 5051, 5055, 5059, 5063, 5067, 5071, 5075, 5079, 5083, 5087, 5091, + 5095, 5099, 5103, 5107, 5111, 5115, 5119, 5123, 5127, 5131, 5135, 5139, + 5143, 5147, 5151, 5155, 5159, 5163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5167, 5171, 5174, 5177, 5180, 5183, 5186, 5189, 5192, 5195, 5198, 5201, + 5204, 5207, 5210, 5213, 5216, 5218, 5220, 5222, 5224, 5226, 5228, 5230, + 5232, 5234, 5236, 5238, 5240, 5242, 5244, 5247, 5250, 5253, 5256, 5259, + 5262, 5265, 5268, 5271, 5274, 5277, 5280, 5283, 5286, 5292, 5297, 0, + 5300, 5302, 5304, 5306, 5308, 5310, 5312, 5314, 5316, 5318, 5320, 5322, + 5324, 5326, 5328, 5330, 5332, 5334, 5336, 5338, 5340, 5342, 5344, 5346, + 5348, 5350, 5352, 5354, 5356, 5358, 5360, 5362, 5364, 5366, 5368, 5370, + 5372, 5374, 5376, 5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, + 5396, 5398, 5401, 5404, 5407, 5410, 5413, 5416, 5419, 5422, 5425, 5428, + 5431, 5434, 5437, 5440, 5443, 5446, 5449, 5452, 5455, 5458, 5461, 5464, + 5467, 5470, 5474, 5478, 5482, 5485, 5489, 5492, 5496, 5498, 5500, 5502, + 5504, 5506, 5508, 5510, 5512, 5514, 5516, 5518, 5520, 5522, 5524, 5526, + 5528, 5530, 5532, 5534, 5536, 5538, 5540, 5542, 5544, 5546, 5548, 5550, + 5552, 5554, 5556, 5558, 5560, 5562, 5564, 5566, 5568, 5570, 5572, 5574, + 5576, 5578, 5580, 5582, 5584, 5586, 5588, 0, 5590, 5595, 5600, 5605, + 5609, 5614, 5618, 5622, 5628, 5633, 5637, 5641, 5645, 5650, 5655, 5659, + 5663, 5666, 5670, 5675, 5680, 5683, 5689, 5696, 5702, 5706, 5712, 5718, + 5723, 5727, 5731, 5735, 5740, 5746, 5751, 5755, 5759, 5763, 5766, 5769, + 5772, 5775, 5779, 5783, 5789, 5793, 5798, 5804, 5808, 5811, 5814, 5820, + 5825, 5831, 5835, 5841, 5844, 5848, 5852, 5856, 5860, 5864, 5869, 5873, + 5876, 5880, 5884, 5888, 5893, 5897, 5901, 5905, 5911, 5916, 5919, 5925, + 5928, 5933, 5938, 5942, 5946, 5950, 5955, 5958, 5962, 5967, 5970, 5976, + 5980, 5983, 5986, 5989, 5992, 5995, 5998, 6001, 6004, 6007, 6010, 6014, + 6018, 6022, 6026, 6030, 6034, 6038, 6042, 6046, 6050, 6054, 6058, 6062, + 6066, 6070, 6074, 6077, 6080, 6084, 6087, 6090, 6093, 6097, 6101, 6104, + 6107, 6110, 6113, 6116, 6121, 6124, 6127, 6130, 6133, 6136, 6139, 6142, + 6145, 6149, 6154, 6157, 6160, 6163, 6166, 6169, 6172, 6175, 6179, 6183, + 6187, 6191, 6194, 6197, 6200, 6203, 6206, 6209, 6212, 6215, 6218, 6221, + 6225, 6229, 6232, 6236, 6240, 6244, 6247, 6251, 6255, 6260, 6263, 6267, + 6271, 6275, 6279, 6285, 6292, 6295, 6298, 6301, 6304, 6307, 6310, 6313, + 6316, 6319, 6322, 6325, 6328, 6331, 6334, 6337, 6340, 6343, 6346, 6351, + 6354, 6357, 6360, 6365, 6369, 6372, 6375, 6378, 6381, 6384, 6387, 6390, + 6393, 6396, 6399, 6403, 6406, 6409, 6413, 6417, 6420, 6425, 6429, 6432, + 6435, 6438, 6441, 6445, 6449, 6452, 6455, 6458, 6461, 6464, 6467, 6470, + 6473, 6476, 6480, 6484, 6488, 6492, 6496, 6500, 6504, 6508, 6512, 6516, + 6520, 6524, 6528, 6532, 6536, 6540, 6544, 6548, 6552, 6556, 6560, 6564, + 6568, 6570, 6572, 6574, 6576, 6578, 6580, 6582, 6584, 6586, 6588, 6590, + 6592, 6594, 6596, 6598, 6600, 6602, 6604, 6606, 6608, 6610, 6612, 6614, + 6616, 6618, 6620, 6622, 6624, 6626, 6628, 6630, 6632, 6634, 6636, 6638, + 6640, 6642, 6644, 6646, 6648, 6650, 6652, 6654, 6656, 6658, 6660, 6662, + 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684, 6686, + 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708, 6710, + 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732, 6734, + 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756, 6758, + 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780, 6782, + 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804, 6806, + 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828, 6830, + 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852, 6854, + 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876, 6878, + 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900, 6902, + 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924, 6926, + 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948, 6950, + 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972, 6974, + 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996, 6998, + 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020, 7022, + 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044, 7046, + 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068, 7070, + 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092, 7094, + 7096, 7098, 7100, 7102, 7104, 7106, 0, 0, 7108, 0, 7110, 0, 0, 7112, + 7114, 7116, 7118, 7120, 7122, 7124, 7126, 7128, 7130, 0, 7132, 0, 7134, + 0, 0, 7136, 7138, 0, 0, 0, 7140, 7142, 7144, 7146, 0, 0, 7148, 7150, + 7152, 7154, 7156, 7158, 7160, 7162, 7164, 7166, 7168, 7170, 7172, 7174, + 7176, 7178, 7180, 7182, 7184, 7186, 7188, 7190, 7192, 7194, 7196, 7198, + 7200, 7202, 7204, 7206, 7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, + 7224, 7226, 7228, 7230, 7232, 7234, 7236, 7238, 7240, 7242, 7244, 7246, + 7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 0, 0, 0, 0, 0, + 7266, 7268, 7270, 7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, + 7290, 7292, 7294, 7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, + 7314, 7316, 7318, 7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, + 7338, 7340, 7342, 7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, + 7362, 7364, 7366, 7368, 7370, 7372, 7374, 7376, 7378, 7380, 7382, 7384, + 7386, 7388, 7390, 7392, 7394, 7396, 7398, 7400, 7402, 7404, 7406, 7408, + 7410, 7412, 7414, 7416, 7418, 7420, 7422, 7424, 7426, 7428, 7430, 7432, + 7434, 7436, 7438, 7440, 7442, 7444, 7446, 7448, 7450, 7452, 7454, 7456, + 7458, 7460, 7462, 7464, 7466, 7468, 7470, 7472, 7474, 7476, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7478, 7481, 7484, 7487, 7491, 7495, 7498, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7501, 7504, 7507, 7510, 7513, 0, 0, + 0, 0, 0, 7516, 0, 7519, 7522, 7524, 7526, 7528, 7530, 7532, 7534, 7536, + 7538, 7540, 7542, 7545, 7548, 7551, 7554, 7557, 7560, 7563, 7566, 7569, + 7572, 7575, 7578, 0, 7581, 7584, 7587, 7590, 7593, 0, 7596, 0, 7599, + 7602, 0, 7605, 7608, 0, 7611, 7614, 7617, 7620, 7623, 7626, 7629, 7632, + 7635, 7638, 7641, 7643, 7645, 7647, 7649, 7651, 7653, 7655, 7657, 7659, + 7661, 7663, 7665, 7667, 7669, 7671, 7673, 7675, 7677, 7679, 7681, 7683, + 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, + 7709, 7711, 7713, 7715, 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, + 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751, 7753, 7755, + 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, + 7781, 7783, 7785, 7787, 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, + 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823, 7825, 7827, + 7829, 7831, 7833, 7835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7837, 7839, 7841, + 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859, 7861, 7863, 7865, + 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7886, 7889, 7892, + 7895, 7898, 7901, 7904, 7907, 7910, 7913, 7916, 7919, 7922, 7925, 7928, + 7931, 7934, 7937, 7939, 7941, 7943, 7945, 7948, 7951, 7954, 7957, 7960, + 7963, 7966, 7969, 7972, 7975, 7978, 7981, 7984, 7987, 7990, 7993, 7996, + 7999, 8002, 8005, 8008, 8011, 8014, 8017, 8020, 8023, 8026, 8029, 8032, + 8035, 8038, 8041, 8044, 8047, 8050, 8053, 8056, 8059, 8062, 8065, 8068, + 8071, 8074, 8077, 8080, 8083, 8086, 8089, 8092, 8095, 8098, 8101, 8104, + 8107, 8110, 8113, 8116, 8119, 8122, 8125, 8128, 8131, 8134, 8137, 8140, + 8143, 8146, 8149, 8152, 8155, 8158, 8161, 8164, 8167, 8170, 8173, 8176, + 8179, 8182, 8185, 8188, 8191, 8194, 8197, 8200, 8203, 8206, 8209, 8212, + 8215, 8218, 8221, 8224, 8227, 8231, 8235, 8239, 8243, 8247, 8251, 8254, + 8257, 8260, 8263, 8266, 8269, 8272, 8275, 8278, 8281, 8284, 8287, 8290, + 8293, 8296, 8299, 8302, 8305, 8308, 8311, 8314, 8317, 8320, 8323, 8326, + 8329, 8332, 8335, 8338, 8341, 8344, 8347, 8350, 8353, 8356, 8359, 8362, + 8365, 8368, 8371, 8374, 8377, 8380, 8383, 8386, 8389, 8392, 8395, 8398, + 8401, 8404, 8407, 8410, 8413, 8416, 8419, 8422, 8425, 8428, 8431, 8434, + 8437, 8440, 8443, 8446, 8449, 8452, 8455, 8458, 8461, 8464, 8467, 8470, + 8473, 8476, 8479, 8482, 8485, 8488, 8491, 8494, 8497, 8500, 8503, 8506, + 8509, 8512, 8515, 8518, 8521, 8524, 8527, 8530, 8533, 8536, 8539, 8542, + 8545, 8548, 8551, 8554, 8557, 8560, 8563, 8566, 8569, 8572, 8575, 8578, + 8581, 8584, 8587, 8590, 8593, 8596, 8599, 8602, 8605, 8608, 8611, 8614, + 8617, 8620, 8623, 8626, 8629, 8632, 8635, 8638, 8641, 8644, 8647, 8650, + 8653, 8656, 8659, 8662, 8665, 8668, 8671, 8674, 8677, 8681, 8685, 8689, + 8692, 8695, 8698, 8701, 8704, 8707, 8710, 8713, 8716, 8719, 8722, 8725, + 8728, 8731, 8734, 8737, 8740, 8743, 8746, 8749, 8752, 8755, 8758, 8761, + 8764, 8767, 8770, 8773, 8776, 8779, 8782, 8785, 8788, 8791, 8794, 8797, + 8800, 8803, 8806, 8809, 8812, 8815, 8818, 8821, 8824, 8827, 8830, 8833, + 8836, 8839, 8842, 8845, 8848, 8851, 8854, 8857, 8860, 8863, 8866, 8869, + 8872, 8875, 8878, 8881, 8884, 8887, 8890, 8893, 8896, 8899, 8902, 8905, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8908, 8912, 8916, + 8920, 8924, 8928, 8932, 8936, 8940, 8944, 8948, 8952, 8956, 8960, 8964, + 8968, 8972, 8976, 8980, 8984, 8988, 8992, 8996, 9000, 9004, 9008, 9012, + 9016, 9020, 9024, 9028, 9032, 9036, 9040, 9044, 9048, 9052, 9056, 9060, + 9064, 9068, 9072, 9076, 9080, 9084, 9088, 9092, 9096, 9100, 9104, 9108, + 9112, 9116, 9120, 9124, 9128, 9132, 9136, 9140, 9144, 9148, 9152, 9156, + 9160, 0, 0, 9164, 9168, 9172, 9176, 9180, 9184, 9188, 9192, 9196, 9200, + 9204, 9208, 9212, 9216, 9220, 9224, 9228, 9232, 9236, 9240, 9244, 9248, + 9252, 9256, 9260, 9264, 9268, 9272, 9276, 9280, 9284, 9288, 9292, 9296, + 9300, 9304, 9308, 9312, 9316, 9320, 9324, 9328, 9332, 9336, 9340, 9344, + 9348, 9352, 9356, 9360, 9364, 9368, 9372, 9376, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9380, 9384, 9388, 9393, 9398, 9403, 9408, 9413, + 9418, 9423, 9427, 9446, 9455, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 9460, 9462, 9464, 9466, 9468, 9470, 9472, 9474, 9476, + 9478, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9480, 9482, 9484, 9486, 9488, 9490, 9492, 9494, 9496, 9498, 9500, 9502, + 9504, 9506, 9508, 9510, 9512, 9514, 9516, 9518, 9520, 0, 0, 9522, 9524, + 9526, 9528, 9530, 9532, 9534, 9536, 9538, 9540, 9542, 9544, 0, 9546, + 9548, 9550, 9552, 9554, 9556, 9558, 9560, 9562, 9564, 9566, 9568, 9570, + 9572, 9574, 9576, 9578, 9580, 9582, 0, 9584, 9586, 9588, 9590, 0, 0, 0, + 0, 9592, 9595, 9598, 0, 9601, 0, 9604, 9607, 9610, 9613, 9616, 9619, + 9622, 9625, 9628, 9631, 9634, 9636, 9638, 9640, 9642, 9644, 9646, 9648, + 9650, 9652, 9654, 9656, 9658, 9660, 9662, 9664, 9666, 9668, 9670, 9672, + 9674, 9676, 9678, 9680, 9682, 9684, 9686, 9688, 9690, 9692, 9694, 9696, + 9698, 9700, 9702, 9704, 9706, 9708, 9710, 9712, 9714, 9716, 9718, 9720, + 9722, 9724, 9726, 9728, 9730, 9732, 9734, 9736, 9738, 9740, 9742, 9744, + 9746, 9748, 9750, 9752, 9754, 9756, 9758, 9760, 9762, 9764, 9766, 9768, + 9770, 9772, 9774, 9776, 9778, 9780, 9782, 9784, 9786, 9788, 9790, 9792, + 9794, 9796, 9798, 9800, 9802, 9804, 9806, 9808, 9810, 9812, 9814, 9816, + 9818, 9820, 9822, 9824, 9826, 9828, 9830, 9832, 9834, 9836, 9838, 9840, + 9842, 9844, 9846, 9848, 9850, 9852, 9854, 9856, 9858, 9860, 9862, 9864, + 9866, 9868, 9871, 9874, 9877, 9880, 9883, 9886, 9889, 0, 0, 0, 0, 9892, + 9894, 9896, 9898, 9900, 9902, 9904, 9906, 9908, 9910, 9912, 9914, 9916, + 9918, 9920, 9922, 9924, 9926, 9928, 9930, 9932, 9934, 9936, 9938, 9940, + 9942, 9944, 9946, 9948, 9950, 9952, 9954, 9956, 9958, 9960, 9962, 9964, + 9966, 9968, 9970, 9972, 9974, 9976, 9978, 9980, 9982, 9984, 9986, 9988, + 9990, 9992, 9994, 9996, 9998, 10000, 10002, 10004, 10006, 10008, 10010, + 10012, 10014, 10016, 10018, 10020, 10022, 10024, 10026, 10028, 10030, + 10032, 10034, 10036, 10038, 10040, 10042, 10044, 10046, 10048, 10050, + 10052, 10054, 10056, 10058, 10060, 10062, 10064, 10066, 10068, 10070, + 10072, 10074, 10076, 10078, 10080, 10082, 10084, 10086, 10088, 10090, + 10092, 10094, 10096, 10098, 10100, 10102, 10104, 10106, 10108, 10110, + 10112, 10114, 10116, 10118, 10120, 10122, 10124, 10126, 10128, 10130, + 10132, 10134, 10136, 10138, 10140, 10142, 10144, 10146, 10148, 10150, + 10152, 10154, 10156, 10158, 10160, 10162, 10164, 10166, 10168, 10170, + 10172, 10174, 10176, 10178, 10180, 10182, 10184, 10186, 10188, 10190, + 10192, 10194, 10196, 10198, 10200, 10202, 10204, 10206, 10208, 10210, + 10212, 10214, 10216, 10218, 10220, 10222, 10224, 10226, 10228, 10230, + 10232, 10234, 10236, 10238, 10240, 10242, 10244, 10246, 10248, 10250, + 10252, 10254, 10256, 10258, 10260, 10262, 10264, 10266, 10268, 10270, 0, + 0, 0, 10272, 10274, 10276, 10278, 10280, 10282, 0, 0, 10284, 10286, + 10288, 10290, 10292, 10294, 0, 0, 10296, 10298, 10300, 10302, 10304, + 10306, 0, 0, 10308, 10310, 10312, 0, 0, 0, 10314, 10316, 10318, 10320, + 10322, 10324, 10326, 0, 10328, 10330, 10332, 10334, 10336, 10338, 10340, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10342, 10345, 10348, 10351, + 10354, 10357, 10360, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10363, + 10366, 10369, 10372, 10375, 10378, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10381, 10383, 10385, 10387, 10389, 10391, 10393, 10395, 10397, + 10399, 10401, 10403, 10405, 10407, 10409, 10411, 10413, 10415, 10417, + 10419, 10421, 10423, 10425, 10427, 10429, 10431, 10433, 10435, 10437, + 10439, 10441, 10443, 10445, 10447, 10449, 10451, 10453, 10455, 10457, + 10459, 10461, 10463, 10465, 10467, 10469, 10471, 10473, 10475, 10477, + 10479, 10481, 10483, 10485, 10487, 10489, 10491, 10493, 10495, 10497, + 10499, 10501, 10503, 10505, 10507, 10509, 10511, 10513, 10515, 10517, + 10519, 10521, 10523, 10525, 10527, 10529, 10531, 10533, 10535, 10537, + 10539, 10541, 10543, 10545, 10547, 10549, 0, 10551, 10553, 10555, 10557, + 10559, 10561, 10563, 10565, 10567, 10569, 10571, 10573, 10575, 10577, + 10579, 10581, 10583, 10585, 10587, 10589, 10591, 10593, 10595, 10597, + 10599, 10601, 10603, 10605, 10607, 10609, 10611, 10613, 10615, 10617, + 10619, 10621, 10623, 10625, 10627, 10629, 10631, 10633, 10635, 10637, + 10639, 10641, 10643, 10645, 10647, 10649, 10651, 10653, 10655, 10657, + 10659, 10661, 10663, 10665, 10667, 10669, 10671, 10673, 10675, 10677, + 10679, 10681, 10683, 10685, 10687, 10689, 10691, 0, 10693, 10695, 0, 0, + 10697, 0, 0, 10699, 10701, 0, 0, 10703, 10705, 10707, 10709, 0, 10711, + 10713, 10715, 10717, 10719, 10721, 10723, 10725, 10727, 10729, 10731, + 10733, 0, 10735, 0, 10737, 10739, 10741, 10743, 10745, 10747, 10749, 0, + 10751, 10753, 10755, 10757, 10759, 10761, 10763, 10765, 10767, 10769, + 10771, 10773, 10775, 10777, 10779, 10781, 10783, 10785, 10787, 10789, + 10791, 10793, 10795, 10797, 10799, 10801, 10803, 10805, 10807, 10809, + 10811, 10813, 10815, 10817, 10819, 10821, 10823, 10825, 10827, 10829, + 10831, 10833, 10835, 10837, 10839, 10841, 10843, 10845, 10847, 10849, + 10851, 10853, 10855, 10857, 10859, 10861, 10863, 10865, 10867, 10869, + 10871, 10873, 10875, 10877, 10879, 0, 10881, 10883, 10885, 10887, 0, 0, + 10889, 10891, 10893, 10895, 10897, 10899, 10901, 10903, 0, 10905, 10907, + 10909, 10911, 10913, 10915, 10917, 0, 10919, 10921, 10923, 10925, 10927, + 10929, 10931, 10933, 10935, 10937, 10939, 10941, 10943, 10945, 10947, + 10949, 10951, 10953, 10955, 10957, 10959, 10961, 10963, 10965, 10967, + 10969, 10971, 10973, 0, 10975, 10977, 10979, 10981, 0, 10983, 10985, + 10987, 10989, 10991, 0, 10993, 0, 0, 0, 10995, 10997, 10999, 11001, + 11003, 11005, 11007, 0, 11009, 11011, 11013, 11015, 11017, 11019, 11021, + 11023, 11025, 11027, 11029, 11031, 11033, 11035, 11037, 11039, 11041, + 11043, 11045, 11047, 11049, 11051, 11053, 11055, 11057, 11059, 11061, + 11063, 11065, 11067, 11069, 11071, 11073, 11075, 11077, 11079, 11081, + 11083, 11085, 11087, 11089, 11091, 11093, 11095, 11097, 11099, 11101, + 11103, 11105, 11107, 11109, 11111, 11113, 11115, 11117, 11119, 11121, + 11123, 11125, 11127, 11129, 11131, 11133, 11135, 11137, 11139, 11141, + 11143, 11145, 11147, 11149, 11151, 11153, 11155, 11157, 11159, 11161, + 11163, 11165, 11167, 11169, 11171, 11173, 11175, 11177, 11179, 11181, + 11183, 11185, 11187, 11189, 11191, 11193, 11195, 11197, 11199, 11201, + 11203, 11205, 11207, 11209, 11211, 11213, 11215, 11217, 11219, 11221, + 11223, 11225, 11227, 11229, 11231, 11233, 11235, 11237, 11239, 11241, + 11243, 11245, 11247, 11249, 11251, 11253, 11255, 11257, 11259, 11261, + 11263, 11265, 11267, 11269, 11271, 11273, 11275, 11277, 11279, 11281, + 11283, 11285, 11287, 11289, 11291, 11293, 11295, 11297, 11299, 11301, + 11303, 11305, 11307, 11309, 11311, 11313, 11315, 11317, 11319, 11321, + 11323, 11325, 11327, 11329, 11331, 11333, 11335, 11337, 11339, 11341, + 11343, 11345, 11347, 11349, 11351, 11353, 11355, 11357, 11359, 11361, + 11363, 11365, 11367, 11369, 11371, 11373, 11375, 11377, 11379, 11381, + 11383, 11385, 11387, 11389, 11391, 11393, 11395, 11397, 11399, 11401, + 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, + 11423, 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, + 11443, 11445, 11447, 11449, 11451, 11453, 11455, 11457, 11459, 11461, + 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, + 11483, 11485, 11487, 11489, 11491, 11493, 11495, 11497, 11499, 11501, + 11503, 11505, 11507, 11509, 11511, 11513, 11515, 11517, 11519, 11521, + 11523, 11525, 11527, 11529, 11531, 11533, 11535, 11537, 11539, 11541, + 11543, 11545, 11547, 11549, 11551, 11553, 11555, 11557, 11559, 11561, + 11563, 11565, 11567, 11569, 11571, 11573, 11575, 11577, 11579, 11581, + 11583, 11585, 11587, 11589, 11591, 11593, 11595, 11597, 11599, 11601, + 11603, 11605, 11607, 11609, 11611, 11613, 11615, 11617, 11619, 11621, + 11623, 11625, 11627, 11629, 11631, 11633, 11635, 11637, 11639, 11641, + 11643, 11645, 11647, 11649, 11651, 11653, 11655, 11657, 11659, 11661, + 11663, 11665, 11667, 11669, 11671, 11673, 11675, 11677, 11679, 11681, + 11683, 11685, 11687, 0, 0, 11689, 11691, 11693, 11695, 11697, 11699, + 11701, 11703, 11705, 11707, 11709, 11711, 11713, 11715, 11717, 11719, + 11721, 11723, 11725, 11727, 11729, 11731, 11733, 11735, 11737, 11739, + 11741, 11743, 11745, 11747, 11749, 11751, 11753, 11755, 11757, 11759, + 11761, 11763, 11765, 11767, 11769, 11771, 11773, 11775, 11777, 11779, + 11781, 11783, 11785, 11787, 11789, 11791, 11793, 11795, 11797, 11799, + 11801, 11803, 11805, 11807, 11809, 11811, 11813, 11815, 11817, 11819, + 11821, 11823, 11825, 11827, 11829, 11831, 11833, 11835, 11837, 11839, + 11841, 11843, 11845, 11847, 11849, 11851, 11853, 11855, 11857, 11859, + 11861, 11863, 11865, 11867, 11869, 11871, 11873, 11875, 11877, 11879, + 11881, 11883, 11885, 11887, 11889, 11891, 11893, 11895, 11897, 11899, + 11901, 11903, 11905, 11907, 11909, 11911, 11913, 11915, 11917, 11919, + 11921, 11923, 11925, 11927, 11929, 11931, 11933, 11935, 11937, 11939, + 11941, 11943, 11945, 11947, 11949, 11951, 11953, 11955, 11957, 11959, + 11961, 11963, 11965, 11967, 11969, 11971, 11973, 11975, 11977, 11979, + 11981, 11983, 11985, 11987, 11989, 11991, 11993, 11995, 11997, 11999, + 12001, 12003, 12005, 12007, 12009, 12011, 12013, 12015, 12017, 12019, + 12021, 12023, 12025, 12027, 12029, 12031, 12033, 12035, 12037, 12039, + 12041, 12043, 12045, 12047, 12049, 12051, 12053, 12055, 12057, 12059, + 12061, 12063, 12065, 12067, 12069, 12071, 12073, 12075, 12077, 12079, + 12081, 12083, 12085, 12087, 12089, 12091, 12093, 12095, 12097, 12099, + 12101, 12103, 12105, 12107, 12109, 12111, 12113, 12115, 12117, 12119, + 12121, 12123, 12125, 12127, 12129, 12131, 12133, 12135, 12137, 12139, + 12141, 12143, 12145, 12147, 12149, 12151, 12153, 12155, 12157, 12159, + 12161, 12163, 12165, 12167, 12169, 12171, 12173, 12175, 12177, 12179, + 12181, 12183, 12185, 12187, 12189, 12191, 12193, 12195, 12197, 12199, + 12201, 12203, 12205, 12207, 12209, 12211, 12213, 12215, 12217, 12219, + 12221, 12223, 12225, 12227, 12229, 12231, 12233, 12235, 12237, 12239, + 12241, 12243, 12245, 12247, 12249, 12251, 12253, 12255, 12257, 12259, + 12261, 12263, 12265, 12267, 0, 0, 0, 0, 12269, 12271, 12273, 12275, + 12277, 12279, 12281, 12283, 12285, 12287, 12289, 12291, 12293, 12295, + 12297, 12299, 12301, 12303, 12305, 12307, 12309, 12311, 12313, 12315, + 12317, 12319, 12321, 12323, 12325, 12327, 12329, 12331, 12333, 12335, + 12337, 12339, 12341, 12343, 12345, 12347, 12349, 12351, 12353, 12355, + 12357, 12359, 12361, 12363, 12365, 12367, 12369, 12371, 12373, 12375, + 12377, 12379, 12381, 12383, 12385, 12387, 12389, 12391, 12393, 12395, + 12397, 12399, 12401, 12403, 12405, 12407, 12409, 12411, 12413, 12415, + 12417, 12419, 12421, 12423, 12425, 12427, 12429, 12431, 12433, 12435, + 12437, 12439, 12441, 12443, 12445, 12447, 12449, 12451, 12453, 12455, + 12457, 12459, 12461, 12463, 12465, 12467, 12469, 12471, 12473, 12475, + 12477, 12479, 12481, 12483, 12485, 12487, 12489, 12491, 12493, 12495, + 12497, 12499, 12501, 12503, 12505, 12507, 12509, 12511, 12513, 12515, + 12517, 12519, 12521, 12523, 12525, 12527, 12529, 12531, 12533, 12535, + 12537, 12539, 12541, 12543, 12545, 12547, 12549, 12551, 12553, 12555, + 12557, 12559, 12561, 12563, 12565, 12567, 12569, 12571, 12573, 12575, + 12577, 12579, 12581, 12583, 12585, 12587, 12589, 12591, 12593, 12595, + 12597, 12599, 12601, 12603, 12605, 12607, 12609, 12611, 12613, 12615, + 12617, 12619, 12621, 12623, 12625, 12627, 12629, 12631, 12633, 12635, + 12637, 12639, 12641, 12643, 12645, 12647, 12649, 12651, 12653, 12655, + 12657, 12659, 12661, 12663, 12665, 12667, 12669, 12671, 12673, 12675, + 12677, 12679, 12681, 12683, 12685, 12687, 12689, 12691, 12693, 12695, + 12697, 12699, 12701, 12703, 12705, 12707, 12709, 12711, 12713, 12715, + 12717, 12719, 12721, 12723, 12725, 12727, 12729, 12731, 12733, 12735, + 12737, 12739, 12741, 12743, 12745, 12747, 12749, 12751, 12753, 12755, + 12757, 12759, 12761, 12763, 12765, 12767, 12769, 12771, 12773, 12775, + 12777, 12779, 12781, 12783, 12785, 12787, 12789, 12791, 12793, 12795, + 12797, 12799, 12801, 12803, 12805, 12807, 12809, 12811, 12813, 12815, + 12817, 12819, 12821, 12823, 12825, 12827, 12829, 12831, 12833, 12835, + 12837, 12839, 12841, 12843, 12845, 12847, 12849, 12851, 12853, 12855, + 12857, 12859, 12861, 12863, 12865, 12867, 12869, 12871, 12873, 12875, + 12877, 12879, 12881, 12883, 12885, 12887, 12889, 12891, 12893, 12895, + 12897, 12899, 12901, 12903, 12905, 12907, 12909, 12911, 12913, 12915, + 12917, 12919, 12921, 12923, 12925, 12927, 12929, 12931, 12933, 12935, + 12937, 12939, 12941, 12943, 12945, 12947, 12949, 12951, 12953, 12955, + 12957, 12959, 12961, 12963, 12965, 12967, 12969, 12971, 12973, 12975, + 12977, 12979, 12981, 12983, 12985, 12987, 12989, 12991, 12993, 12995, + 12997, 12999, 13001, 13003, 13005, 13007, 13009, 13011, 13013, 13015, + 13017, 13019, 13021, 13023, 13025, 13027, 13029, 13031, 13033, 13035, + 13037, 13039, 13041, 13043, 13045, 13047, 13049, 13051, 13053, 13055, + 13057, 13059, 13061, 13063, 13065, 13067, 13069, 13071, 13073, 13075, + 13077, 13079, 13081, 13083, 13085, 13087, 13089, 13091, 13093, 13095, + 13097, 13099, 13101, 13103, 13105, 13107, 13109, 13111, 13113, 13115, + 13117, 13119, 13121, 13123, 13125, 13127, 13129, 13131, 13133, 13135, + 13137, 13139, 13141, 13143, 13145, 13147, 13149, 13151, 13153, 13155, + 13157, 13159, 13161, 13163, 13165, 13167, 13169, 13171, 13173, 13175, + 13177, 13179, 13181, 13183, 13185, 13187, 13189, 13191, 13193, 13195, + 13197, 13199, 13201, 13203, 13205, 13207, 13209, 13211, 13213, 13215, + 13217, 13219, 13221, 13223, 13225, 13227, 13229, 13231, 13233, 13235, + 13237, 13239, 13241, 13243, 13245, 13247, 13249, 13251, 13253, 13255, + 13257, 13259, 13261, 13263, 13265, 13267, 13269, 13271, 13273, 13275, + 13277, 13279, 13281, 13283, 13285, 13287, 13289, 13291, 13293, 13295, + 13297, 13299, 13301, 13303, 13305, 13307, 13309, 13311, 13313, 13315, + 13317, 13319, 13321, 13323, 13325, 13327, 13329, 13331, 13333, 13335, + 13337, 13339, 13341, 13343, 13345, 13347, 13349, 13351, 13353, 13355, + 13357, 13359, 13361, 13363, 13365, 13367, 13369, 13371, 13373, 13375, + 13377, 13379, 13381, 13383, 13385, 13387, 13389, 13391, 13393, 13395, + 13397, 13399, 13401, 13403, 13405, 13407, 13409, 13411, 13413, 13415, + 13417, 13419, 13421, 13423, 13425, 13427, 13429, 13431, 13433, 13435, + 13437, 13439, 13441, 13443, 13445, 13447, 13449, 13451, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +/* NFC pairs */ +#define COMP_SHIFT 3 +static unsigned short comp_index[] = { + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, 4, 5, 6, 7, 0, + 0, 0, 0, 8, 9, 10, 0, 0, 0, 11, 12, 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, 0, + 18, 19, 20, 21, 0, 0, 0, 22, 0, 0, 0, 0, 0, 23, 24, 25, 26, 0, 0, 0, 27, + 28, 29, 30, 0, 0, 31, 32, 33, 34, 35, 0, 0, 36, 0, 0, 0, 0, 0, 0, 37, 38, + 39, 40, 0, 0, 41, 0, 42, 43, 44, 0, 0, 45, 46, 47, 0, 0, 0, 0, 48, 49, + 50, 51, 0, 0, 52, 53, 54, 55, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 58, 59, 60, + 61, 0, 0, 62, 63, 64, 65, 0, 0, 0, 66, 67, 68, 69, 0, 0, 70, 71, 72, 73, + 0, 0, 0, 74, 0, 75, 0, 0, 0, 0, 76, 0, 77, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, + 79, 80, 81, 0, 0, 0, 0, 82, 83, 84, 85, 0, 0, 86, 87, 88, 89, 0, 0, 0, + 90, 0, 91, 92, 0, 0, 93, 94, 95, 96, 0, 0, 0, 0, 97, 98, 99, 0, 0, 0, + 100, 101, 102, 103, 0, 0, 0, 104, 0, 0, 0, 0, 0, 105, 106, 107, 0, 0, 0, + 0, 108, 109, 110, 111, 0, 0, 112, 113, 114, 115, 0, 0, 0, 116, 117, 0, 0, + 0, 0, 118, 0, 119, 120, 121, 0, 0, 122, 123, 124, 125, 0, 0, 0, 126, 0, + 127, 0, 0, 0, 128, 129, 130, 131, 0, 0, 0, 132, 133, 134, 135, 0, 0, 0, + 136, 0, 0, 0, 0, 0, 137, 138, 139, 140, 0, 0, 0, 141, 142, 143, 0, 0, 0, + 0, 144, 145, 146, 147, 0, 0, 148, 149, 150, 151, 0, 0, 0, 152, 0, 153, 0, + 0, 0, 154, 155, 156, 0, 0, 0, 0, 0, 157, 0, 0, 0, 0, 158, 159, 160, 161, + 0, 0, 0, 162, 163, 164, 165, 0, 0, 0, 166, 0, 0, 167, 0, 0, 168, 169, 0, + 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 172, 173, 0, 0, 0, + 0, 0, 174, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0, 0, 177, 0, 0, 0, 0, 0, 0, + 178, 179, 0, 0, 0, 0, 180, 181, 0, 0, 0, 0, 0, 182, 0, 0, 0, 0, 0, 0, + 183, 0, 0, 0, 0, 0, 184, 185, 186, 0, 0, 0, 0, 187, 188, 0, 0, 0, 0, 0, + 189, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 191, 0, 0, 0, 0, 0, 192, 0, 0, + 0, 0, 0, 0, 193, 194, 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, 0, 196, 197, 0, 0, + 0, 0, 0, 198, 199, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 201, 0, 0, 0, 0, 0, + 0, 202, 203, 0, 0, 0, 0, 204, 205, 0, 0, 0, 0, 0, 206, 207, 0, 0, 0, 0, + 0, 208, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, 211, + 212, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 215, 0, + 0, 0, 0, 0, 0, 216, 0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, + 0, 0, 0, 219, 0, 0, 0, 0, 0, 220, 0, 0, 0, 0, 0, 0, 221, 0, 0, 0, 0, 0, + 222, 223, 224, 0, 0, 0, 225, 226, 227, 0, 0, 0, 0, 228, 229, 230, 0, 0, + 0, 0, 231, 232, 233, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 235, 0, 0, 0, 0, 0, + 0, 236, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 239, + 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 242, 0, 0, + 0, 0, 0, 0, 243, 0, 0, 0, 0, 244, 245, 246, 0, 247, 0, 0, 248, 0, 249, 0, + 0, 0, 0, 250, 251, 252, 253, 0, 0, 254, 255, 256, 0, 0, 0, 0, 257, 0, + 258, 0, 0, 0, 0, 0, 259, 0, 0, 0, 0, 260, 261, 262, 0, 0, 0, 0, 263, 0, + 264, 265, 0, 0, 0, 0, 0, 0, 266, 0, 0, 0, 0, 0, 0, 267, 0, 0, 268, 269, + 270, 271, 0, 0, 272, 0, 273, 0, 0, 0, 0, 274, 0, 275, 276, 277, 0, 0, + 278, 279, 0, 280, 0, 0, 281, 0, 282, 0, 0, 0, 0, 0, 0, 283, 0, 0, 0, 284, + 285, 286, 0, 287, 0, 0, 288, 0, 289, 0, 290, 0, 0, 291, 0, 0, 292, 0, 0, + 293, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 295, 0, 0, 296, 0, 0, 0, 0, 0, 0, + 297, 0, 0, 0, 0, 0, 298, 299, 0, 0, 0, 0, 0, 300, 0, 0, 0, 0, 0, 301, + 302, 0, 0, 0, 0, 0, 303, 304, 0, 0, 0, 0, 0, 305, 0, 0, 0, 0, 0, 306, + 307, 0, 0, 0, 0, 0, 308, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 310, 311, + 0, 0, 0, 0, 0, 312, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 314, 0, 0, + 0, 0, 0, 315, 0, 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, 0, + 0, 318, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 320, 321, 0, 0, 0, 0, 0, 322, + 0, 0, 0, 0, 0, 0, 0, 323, 0, 0, 0, 0, 0, 324, 325, 0, 0, 0, 0, 0, 326, 0, + 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, 0, 0, 329, 0, 0, 0, + 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0, 0, 0, 332, 0, 0, 0, 0, 0, + 333, 0, 0, 0, 0, 0, 0, 334, 0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 336, 0, 0, 0, 0, 0, 0, 337, 0, 0, 0, 0, 0, 338, 0, 0, 0, 0, 0, 0, 339, + 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 0, 0, 342, 0, 0, + 0, 0, 0, 0, 343, 0, 0, 0, 0, 0, 344, 0, 0, 0, 0, 0, 0, 345, 0, 0, 0, 0, + 0, 0, 346, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, + 349, 0, 0, 0, 0, 0, 0, 350, 0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 352, + 353, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 356, 0, + 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, 359, 360, 0, 0, + 0, 0, 0, 0, 361, 0, 0, 0, 0, 0, 362, 0, 0, 0, 0, 0, 0, 363, 0, 0, 0, 0, + 0, 0, 364, 0, 0, 0, 0, 0, 365, 0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 367, + 368, 0, 0, 0, 0, 0, 369, 0, 0, 0, 0, 0, 370, 0, 0, 0, 0, 0, 0, 371, 0, 0, + 0, 0, 0, 0, 372, 0, 0, 0, 0, 0, 373, 0, 0, 0, 374, 0, 0, 375, 0, 0, 376, + 0, 0, 0, 0, 0, 0, 377, 0, 0, 0, 0, 0, 0, 378, 0, 0, 0, 0, 0, 379, 0, 0, + 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 382, 0, 0, 383, 0, + 0, 0, 384, 0, 0, 385, 0, 0, 386, 0, 0, 0, 0, 0, 0, 387, 0, 0, 0, 0, 0, 0, + 388, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0, 0, 0, 390, 0, 0, 0, 0, 0, 391, 0, 0, + 0, 0, 0, 0, 392, 0, 0, 393, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 0, 0, 395, 0, + 0, 0, 0, 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 398, 0, 0, 399, 0, 0, 0, + 400, 0, 0, 0, 0, 0, 401, 0, 0, 0, 0, 0, 0, 402, 0, 0, 0, 0, 0, 0, 403, 0, + 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 405, 0, 0, 0, 0, 0, 0, 406, 0, 0, 407, + 0, 0, 408, 0, 0, 409, 0, 0, 0, 410, 0, 0, 0, 0, 0, 411, 0, 0, 0, 0, 0, 0, + 412, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 415, 0, + 0, 0, 0, 0, 0, 416, 0, 0, 417, 0, 0, 418, 0, 0, 419, 0, 0, 0, 420, 0, 0, + 421, 0, 0, 422, 0, 0, 423, 424, 0, 0, 425, 0, 0, 426, 0, 0, 0, 0, 0, 0, + 427, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, 429, 0, 0, 0, 0, 0, 0, 430, 0, + 0, 431, 0, 0, 432, 0, 0, 0, 433, 0, 0, 434, 0, 0, 435, 0, 0, 436, 437, 0, + 0, 438, 0, 0, 439, 0, 0, 0, 440, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, + 442, 0, 0, 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, 444, 0, 0, 0, 0, 0, 0, 445, 0, + 0, 0, 0, 0, 446, 0, 0, 447, 448, 0, 0, 449, 0, 0, 450, 0, 0, 0, 451, 0, + 0, 0, 0, 0, 452, 0, 0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, + 0, 0, 455, 0, 0, 0, 0, 0, 0, 456, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, + 458, 0, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0, 0, 460, 0, 0, 0, 0, 0, 0, 461, 0, + 0, 462, 0, 0, 463, 0, 0, 0, 0, 0, 0, 464, 0, 0, 0, 0, 0, 0, 465, 0, 0, + 466, 0, 0, 467, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0, 0, 469, 0, 0, 0, 0, 0, + 0, 470, 0, 0, 0, 0, 0, 0, 471, 0, 0, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 473, + 0, 0, 0, 0, 0, 0, 474, 0, 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, 0, 476, 0, 0, + 0, 0, 0, 477, 0, 0, 0, 0, 0, 0, 478, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, + 0, 480, 0, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0, 483, + 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 485, 0, 0, 0, 0, 0, 0, 486, 0, 0, + 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 488, 0, 0, 0, 0, 0, 0, 489, 0, 0, 0, 0, + 0, 0, 490, 0, 0, 0, 0, 0, 491, 0, 0, 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, 493, + 0, 0, 0, 0, 0, 0, 494, 0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 496, 0, 0, + 0, 0, 0, 0, 497, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, + 0, 0, 500, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 502, 0, 0, 0, 0, 0, 0, + 503, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 505, 0, 0, 0, 0, 0, 0, 506, 0, + 0, 0, 0, 0, 507, 0, 0, 0, 0, 0, 0, 508, 0, 0, 0, 0, 0, 0, 0, 0, 509, 0, + 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 0, 511, 0, 0, 0, 0, 0, 512, 0, 0, 0, + 0, 0, 0, 513, 0, 0, 0, 0, 0, 0, 514, 0, 0, 0, 0, 0, 515, 0, 0, 0, 0, 0, + 0, 516, 0, 0, 0, 0, 0, 517, 0, 0, 0, 0, 0, 0, 518, 0, 0, 0, 0, 0, 0, 519, + 0, 0, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 522, 0, 0, + 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 525, 526, 0, 0, 0, 0, + 0, 527, 0, 0, 0, 0, 0, 0, 528, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0, 0, 0, 530, + 0, 0, 0, 0, 0, 0, 531, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 533, 0, 0, + 0, 0, 0, 534, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 536, 0, 0, 0, 0, + 0, 537, 0, 0, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 539, 0, 0, 0, 0, 0, 540, + 0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 542, 0, 0, 0, 0, 0, 0, 543, 0, 0, + 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 545, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, + 0, 0, 547, 0, 0, 0, 0, 0, 548, 0, 0, 0, 0, 0, 0, 549, 0, 0, 0, 0, 0, 550, + 551, 0, 0, 0, 0, 0, 552, 0, 0, 0, 0, 0, 0, 553, 0, 0, 0, 0, 0, 554, 0, 0, + 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 556, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, + 0, 0, 558, +}; + +static unsigned short comp_data[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8814, 0, 0, 0, 0, 8800, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 8815, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 193, 194, 195, + 256, 258, 550, 196, 7842, 197, 0, 461, 512, 514, 0, 0, 0, 7840, 0, 7680, + 0, 0, 260, 0, 0, 0, 0, 7682, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7684, 0, 0, 0, + 0, 0, 0, 0, 0, 7686, 0, 0, 0, 262, 264, 0, 0, 0, 266, 0, 0, 0, 0, 268, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 7690, 0, 0, 0, 0, 270, 0, 0, + 0, 0, 0, 7692, 0, 0, 0, 7696, 0, 7698, 0, 0, 7694, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 200, 201, 202, 7868, 274, 276, 278, 203, 7866, 0, 0, 282, 516, + 518, 0, 0, 0, 7864, 0, 0, 0, 552, 280, 7704, 0, 7706, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7710, 0, 0, 0, 0, 0, 0, 0, 500, 284, 0, 7712, 286, 288, 0, 0, 0, + 0, 486, 0, 0, 0, 0, 0, 0, 0, 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, 0, 0, 292, + 0, 0, 0, 7714, 7718, 0, 0, 0, 542, 0, 0, 0, 0, 0, 7716, 0, 0, 0, 7720, 0, + 0, 7722, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 204, 205, 206, 296, 298, + 300, 304, 207, 7880, 0, 0, 463, 520, 522, 0, 0, 0, 7882, 0, 0, 0, 0, 302, + 0, 0, 7724, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 308, 0, 0, 0, 7728, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 488, 0, 0, 0, 0, 0, 7730, 0, 0, 0, 310, 0, 0, 0, + 0, 7732, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 313, 0, 317, 0, 0, 0, 0, 0, + 7734, 0, 0, 0, 315, 0, 7740, 0, 0, 7738, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7742, 0, 0, 0, 0, 7744, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7746, 0, 0, 0, 504, + 323, 0, 209, 0, 0, 7748, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 7750, 0, 0, 0, + 325, 0, 7754, 0, 0, 7752, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 210, 211, 212, + 213, 332, 334, 558, 214, 7886, 0, 336, 465, 524, 526, 0, 0, 416, 7884, 0, + 0, 0, 0, 490, 0, 0, 0, 0, 0, 0, 0, 7764, 0, 0, 0, 0, 7766, 0, 0, 0, 0, 0, + 0, 0, 340, 0, 0, 0, 0, 7768, 0, 0, 0, 0, 344, 528, 530, 0, 0, 0, 7770, 0, + 0, 0, 342, 0, 0, 0, 0, 7774, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 346, 348, + 0, 0, 0, 7776, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 7778, 0, 0, 536, 350, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7786, 0, 0, 0, 0, 356, 0, 0, 0, 0, 0, + 7788, 0, 0, 538, 354, 0, 7792, 0, 0, 7790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 217, 218, 219, 360, 362, 364, 0, 220, 7910, 366, 368, 467, 532, 534, 0, + 0, 431, 7908, 7794, 0, 0, 0, 370, 7798, 0, 7796, 0, 0, 0, 0, 0, 0, 7804, + 0, 0, 0, 0, 0, 7806, 0, 0, 0, 7808, 7810, 372, 0, 0, 0, 7814, 7812, 0, + 7816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7818, 7820, 0, 0, 0, 0, 0, 7922, 221, + 374, 7928, 562, 0, 7822, 376, 7926, 0, 0, 0, 0, 0, 0, 0, 0, 7924, 0, 0, + 0, 0, 377, 7824, 0, 0, 0, 379, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 7826, 0, + 0, 0, 0, 0, 0, 0, 0, 7828, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 225, 226, + 227, 257, 259, 551, 228, 7843, 229, 0, 462, 513, 515, 0, 0, 0, 7841, 0, + 7681, 0, 0, 261, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7683, 0, 0, 7685, 0, + 0, 0, 0, 0, 0, 0, 0, 7687, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 263, 265, 0, + 0, 0, 267, 0, 0, 0, 0, 269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, + 0, 7691, 0, 0, 0, 0, 271, 0, 0, 0, 0, 0, 7693, 0, 0, 0, 7697, 0, 7699, 0, + 0, 7695, 0, 0, 232, 233, 234, 7869, 275, 277, 279, 235, 7867, 0, 0, 283, + 517, 519, 0, 0, 0, 7865, 0, 0, 0, 553, 281, 7705, 0, 7707, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7711, 0, 0, 0, 0, 0, 0, 0, 501, 285, 0, 7713, 287, 289, 0, 0, + 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 0, 0, 291, 0, 293, 0, 0, 0, 7715, 7719, + 0, 0, 0, 543, 0, 0, 0, 0, 0, 7717, 0, 0, 0, 7721, 0, 0, 7723, 0, 7830, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 236, 237, 238, 297, 299, 301, 0, 239, 7881, 0, + 0, 464, 521, 523, 0, 0, 0, 7883, 0, 0, 0, 0, 303, 0, 0, 7725, 0, 0, 0, 0, + 0, 309, 0, 0, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7729, + 0, 489, 0, 0, 0, 0, 0, 7731, 0, 0, 0, 311, 0, 0, 0, 0, 7733, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, 0, 0, 0, 0, 318, 0, 0, 0, 0, 0, + 7735, 0, 0, 0, 316, 0, 7741, 0, 0, 7739, 0, 0, 0, 7743, 0, 0, 0, 0, 7745, + 0, 0, 7747, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 505, 324, 0, 241, 0, 0, + 7749, 0, 0, 0, 0, 328, 0, 0, 0, 0, 0, 7751, 0, 0, 0, 326, 0, 7755, 0, 0, + 7753, 0, 0, 242, 243, 244, 245, 333, 335, 559, 246, 7887, 0, 337, 466, + 525, 527, 0, 0, 417, 7885, 0, 0, 0, 0, 491, 0, 0, 0, 0, 0, 0, 0, 7765, 0, + 0, 0, 0, 7767, 0, 0, 0, 0, 0, 0, 0, 341, 0, 0, 0, 0, 7769, 0, 0, 0, 0, + 345, 529, 531, 0, 0, 0, 7771, 0, 0, 0, 343, 0, 0, 0, 0, 7775, 0, 0, 0, + 347, 349, 0, 0, 0, 7777, 0, 0, 0, 0, 353, 0, 0, 0, 0, 0, 7779, 0, 0, 537, + 351, 0, 0, 0, 0, 0, 7787, 7831, 0, 0, 0, 357, 0, 0, 0, 0, 0, 7789, 0, 0, + 539, 355, 0, 7793, 0, 0, 7791, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 250, + 251, 361, 363, 365, 0, 252, 7911, 367, 369, 468, 533, 535, 0, 0, 432, + 7909, 7795, 0, 0, 0, 371, 7799, 0, 7797, 0, 0, 0, 0, 0, 0, 7805, 0, 0, 0, + 0, 0, 7807, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7809, 7811, 373, 0, 0, 0, + 7815, 7813, 0, 7832, 0, 0, 0, 0, 0, 0, 0, 7817, 0, 7819, 7821, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7923, 253, 375, 7929, 563, 0, 7823, 255, + 7927, 7833, 0, 0, 0, 0, 0, 0, 0, 7925, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 378, 7825, 0, 0, 0, 380, 0, 0, 0, 0, 382, 0, 0, 0, 0, 0, 7827, 0, 0, + 0, 0, 0, 0, 0, 0, 7829, 0, 0, 8173, 901, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8129, 0, 0, 0, 0, 0, 0, 0, 0, 7846, 7844, 0, 7850, 0, 0, 0, 0, 7848, 0, + 0, 0, 0, 0, 0, 0, 0, 478, 0, 506, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 508, 0, 0, 482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7688, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7872, 7870, 0, 7876, 0, 0, 0, 0, 7874, 0, 0, 0, 0, 0, 7726, 0, + 0, 0, 7890, 7888, 0, 7894, 0, 0, 0, 0, 7892, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7756, 0, 0, 556, 0, 0, 7758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 554, + 0, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 475, 471, 0, 0, 469, 0, 0, 0, 0, + 0, 0, 473, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7847, 7845, 0, 7851, 0, 0, 0, 0, + 7849, 0, 0, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 0, 0, 0, 507, 0, 0, + 0, 0, 509, 0, 0, 483, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7689, 0, 0, 0, 7873, + 7871, 0, 7877, 0, 0, 0, 0, 7875, 0, 0, 0, 0, 0, 7727, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7891, 7889, 0, 7895, 0, 0, 0, 0, 7893, 0, 0, 0, 0, 0, + 7757, 0, 0, 557, 0, 0, 7759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 511, 0, 0, 0, 476, 472, 0, 0, 470, 0, 0, 0, 0, 0, 0, 474, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7856, 7854, 0, 7860, 0, 0, 0, 0, 7858, 0, 0, + 0, 0, 7857, 7855, 0, 7861, 0, 0, 0, 0, 7859, 0, 0, 0, 0, 7700, 7702, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7701, 7703, 0, 0, 0, 7760, 7762, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7761, 7763, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7780, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7781, 0, 0, 0, 0, 7782, 0, 0, 0, 0, + 7783, 0, 0, 0, 0, 0, 0, 0, 7800, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7801, 0, 0, 7802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7803, 0, 0, 0, + 7835, 0, 0, 0, 0, 0, 0, 7900, 7898, 0, 7904, 0, 0, 0, 0, 7902, 0, 0, 0, + 0, 0, 0, 0, 0, 7906, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7901, 7899, 0, + 7905, 0, 0, 0, 0, 7903, 0, 0, 0, 0, 0, 0, 0, 0, 7907, 0, 0, 0, 7914, + 7912, 0, 7918, 0, 0, 0, 0, 7916, 0, 0, 0, 0, 0, 0, 0, 0, 7920, 0, 0, 0, + 7915, 7913, 0, 7919, 0, 0, 0, 0, 7917, 0, 0, 0, 0, 0, 0, 0, 0, 7921, 0, + 0, 0, 0, 0, 0, 494, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 492, 0, 0, 0, + 0, 493, 0, 0, 0, 0, 480, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, + 0, 0, 0, 7708, 0, 0, 0, 0, 7709, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 560, 0, + 0, 0, 0, 561, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8122, 902, 0, 0, 8121, 8120, 0, 0, 0, 0, 0, 0, 0, 0, 7944, 7945, 0, + 0, 0, 0, 0, 8124, 0, 0, 0, 0, 0, 0, 0, 8136, 904, 0, 0, 0, 0, 7960, 7961, + 0, 0, 0, 0, 0, 8138, 905, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7976, 7977, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8140, 0, 0, 0, 0, 0, 0, 0, 8154, + 906, 0, 0, 8153, 8152, 0, 938, 0, 0, 0, 0, 0, 0, 7992, 7993, 0, 0, 0, 0, + 0, 8184, 908, 0, 0, 0, 0, 8008, 8009, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8172, 0, 0, 0, 0, 0, 8170, 910, 0, 0, 8169, 8168, 0, 939, 0, 0, 0, 0, 0, + 0, 0, 8025, 0, 0, 0, 0, 0, 8186, 911, 0, 0, 0, 0, 8040, 8041, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8188, 0, 0, 0, 0, 8116, 0, 0, 0, 0, 8132, 0, + 0, 0, 0, 0, 0, 0, 8048, 940, 0, 0, 8113, 8112, 0, 0, 0, 0, 0, 0, 0, 0, + 7936, 7937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8118, 8115, 0, 0, 0, 0, + 0, 0, 0, 8050, 941, 0, 0, 0, 0, 7952, 7953, 0, 0, 0, 0, 0, 8052, 942, 0, + 0, 0, 0, 7968, 7969, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8134, 8131, 0, + 0, 0, 0, 0, 0, 0, 8054, 943, 0, 0, 8145, 8144, 0, 970, 0, 0, 0, 0, 0, 0, + 7984, 7985, 0, 0, 0, 0, 8150, 0, 0, 0, 0, 0, 0, 0, 0, 8056, 972, 0, 0, 0, + 0, 8000, 8001, 0, 0, 0, 8164, 8165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8058, 973, 0, 0, 8161, 8160, 0, 971, 0, 0, 0, 0, 0, 0, 8016, 8017, 0, + 0, 0, 0, 8166, 0, 0, 0, 0, 0, 0, 0, 0, 8060, 974, 0, 0, 0, 0, 8032, 8033, + 0, 0, 0, 0, 8182, 8179, 0, 0, 0, 0, 0, 0, 0, 8146, 912, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8151, 0, 0, 0, 0, 0, 0, 0, 0, 8162, 944, 0, 0, 8167, 0, 0, 0, + 0, 0, 8180, 0, 0, 0, 0, 0, 0, 0, 0, 979, 0, 0, 0, 0, 0, 980, 0, 0, 0, 0, + 1031, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1232, 0, 1234, 0, 0, 0, 0, 0, 0, + 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1024, 0, 0, 0, 0, 1238, 0, 1025, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1217, 0, 1244, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1246, 0, 0, 0, 0, 0, 1037, 0, 0, 0, 1250, 1049, 0, 1252, 0, 0, + 0, 0, 0, 0, 1036, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1254, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1262, 1038, 0, 1264, 0, 0, 1266, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1268, 0, 0, 0, 0, 1272, 0, 0, 0, 0, 1260, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1233, 0, 1235, 0, 0, 0, 0, 0, 0, 1107, 0, 0, 0, 1104, 0, 0, 0, 0, 1239, + 0, 1105, 0, 0, 1218, 0, 1245, 0, 0, 0, 0, 1247, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1117, 0, 0, 0, 1251, 1081, 0, 1253, 0, 0, 0, 0, 0, 0, + 1116, 0, 0, 1255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1263, 1118, 0, 1265, 0, 0, + 1267, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1273, 0, 0, 0, 0, 1261, 0, 0, 0, 0, 1111, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1142, 0, 0, 0, 0, 1143, 0, 0, 0, 0, 0, 0, 0, 1242, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1243, 0, 0, 0, 0, 1258, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1259, 0, 0, 0, 1570, 1571, 1573, 0, 0, 0, 1572, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1574, 0, 0, 0, 0, 1730, 0, 0, 0, 0, 1747, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1728, 0, 0, 0, 0, 0, 0, 2345, 0, 0, 0, 0, 2353, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2356, 0, 0, 0, 0, 0, 2507, 2508, 0, 0, + 0, 0, 0, 2891, 2888, 2892, 0, 0, 0, 0, 0, 0, 2964, 0, 0, 0, 3018, 3020, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3019, 0, 0, 0, 0, 0, 0, 3144, 0, 0, 0, + 0, 0, 0, 3264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3274, 3271, 3272, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3275, 0, 0, 0, 0, 0, 0, 3402, 3404, 0, 0, 0, + 3403, 0, 0, 0, 0, 0, 0, 3546, 3548, 3550, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 3549, 0, 0, 0, 0, 0, 0, 0, 4134, 0, 0, 0, 0, 0, 0, 7736, 0, 0, 0, 0, + 7737, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7772, 0, 0, 0, 0, 7773, 0, 0, + 0, 0, 0, 0, 7784, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7785, 7852, 0, 0, + 7862, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7853, 0, 0, 7863, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7878, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7879, 0, 0, 0, 0, 7896, + 0, 0, 0, 0, 7897, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7938, 7940, 0, 0, 7942, + 8064, 0, 0, 0, 0, 0, 0, 0, 7939, 7941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7943, 8065, 0, 0, 0, 0, 8066, 0, 0, 0, 0, 8067, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8068, 0, 0, 0, 0, 8069, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8070, 0, 0, 0, 0, 8071, 0, 0, 0, 0, 0, 0, 0, 7946, 7948, 0, 0, 7950, + 8072, 0, 0, 0, 0, 0, 0, 0, 7947, 7949, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7951, 8073, 0, 0, 0, 0, 8074, 0, 0, 0, 0, 8075, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8076, 0, 0, 0, 0, 8077, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8078, 0, 0, 0, 0, 8079, 0, 0, 0, 0, 0, 0, 0, 7954, 7956, 0, 0, 0, 7955, + 7957, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7962, 7964, 0, 0, 0, 7963, 7965, + 0, 0, 0, 7970, 7972, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7974, 8080, 0, 0, 0, + 0, 0, 0, 0, 7971, 7973, 0, 0, 7975, 8081, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8082, 0, 0, 0, 0, 8083, 0, 0, 0, 0, 8084, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8085, 0, 0, 0, 0, 8086, 0, 0, 0, 0, 8087, 0, 0, 0, 0, 0, 0, + 0, 7978, 7980, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7982, 8088, 0, 0, 0, 0, 0, + 0, 0, 7979, 7981, 0, 0, 7983, 8089, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8090, 0, 0, 0, 0, 8091, 0, 0, 0, 0, 8092, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8093, 0, 0, 0, 0, 8094, 0, 0, 0, 0, 8095, 0, 0, 0, 0, 0, 0, 0, + 7986, 7988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7990, 0, 0, 0, 0, 0, 0, 0, 0, + 7987, 7989, 0, 0, 7991, 0, 0, 0, 0, 0, 0, 0, 0, 7994, 7996, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7998, 0, 0, 0, 0, 0, 0, 0, 0, 7995, 7997, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7999, 0, 0, 0, 0, 0, 0, 0, 0, 8002, 8004, 0, 0, 0, + 8003, 8005, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8010, 8012, 0, 0, 0, 8011, + 8013, 0, 0, 0, 8018, 8020, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8022, 0, 0, 0, + 0, 0, 0, 0, 0, 8019, 8021, 0, 0, 8023, 0, 0, 0, 0, 0, 0, 0, 0, 8027, + 8029, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8031, 0, 0, 0, 0, 0, 0, 0, 0, 8034, + 8036, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8038, 8096, 0, 0, 0, 0, 0, 0, 0, + 8035, 8037, 0, 0, 8039, 8097, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8098, + 0, 0, 0, 0, 8099, 0, 0, 0, 0, 8100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8101, 0, 0, 0, 0, 8102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8103, 0, 0, + 0, 0, 0, 0, 0, 8042, 8044, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8046, 8104, 0, + 0, 0, 0, 0, 0, 0, 8043, 8045, 0, 0, 8047, 8105, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8106, 0, 0, 0, 0, 8107, 0, 0, 0, 0, 8108, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8109, 0, 0, 0, 0, 8110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8111, 0, 0, 0, 0, 8114, 0, 0, 0, 0, 8130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8178, 0, 0, 0, 0, 8119, 0, 0, 0, 0, 0, 0, 0, 8141, 8142, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 8143, 0, 0, 0, 0, 0, 8135, 0, 0, 0, 0, 8183, + 0, 0, 0, 0, 0, 0, 0, 8157, 8158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8159, 0, + 0, 0, 8602, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8603, 0, 0, 0, 0, 8622, + 0, 0, 0, 0, 8653, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8655, 0, 0, 0, 0, + 8654, 0, 0, 0, 0, 8708, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8713, 0, 0, + 0, 0, 8716, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8740, 0, 0, 0, 0, 8742, + 0, 0, 0, 0, 8769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8772, 0, 0, 0, 0, + 8775, 0, 0, 0, 0, 8777, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8813, 0, 0, + 0, 0, 8802, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8816, 0, 0, 0, 0, 8817, + 0, 0, 0, 0, 8820, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8821, 0, 0, 0, 0, + 8824, 0, 0, 0, 0, 8825, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8832, 0, 0, + 0, 0, 8833, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8928, 0, 0, 0, 0, 8929, + 0, 0, 0, 0, 8836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8837, 0, 0, 0, 0, + 8840, 0, 0, 0, 0, 8841, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8930, 0, 0, + 0, 0, 8931, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8876, 0, 0, 0, 0, 8877, + 0, 0, 0, 0, 8878, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8879, 0, 0, 0, 0, + 8938, 0, 0, 0, 0, 8939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8940, 0, 0, + 0, 0, 8941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12436, 0, 0, 0, 0, 12364, + 0, 0, 0, 0, 12366, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12368, 0, 0, 0, 0, + 12370, 0, 0, 0, 0, 12372, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12374, 0, + 0, 0, 0, 12376, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12378, 0, 0, 0, 0, + 12380, 0, 0, 0, 0, 12382, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12384, 0, + 0, 0, 0, 12386, 0, 0, 0, 0, 12389, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12391, 0, 0, 0, 0, 12393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12400, + 12401, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12403, 12404, 0, 0, 0, 12406, + 12407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12409, 12410, 0, 0, 0, 12412, + 12413, 0, 0, 0, 12446, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12532, 0, 0, + 0, 0, 12460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12462, 0, 0, 0, 0, + 12464, 0, 0, 0, 0, 12466, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12468, 0, + 0, 0, 0, 12470, 0, 0, 0, 0, 12472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12474, 0, 0, 0, 0, 12476, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12478, 0, + 0, 0, 0, 12480, 0, 0, 0, 0, 12482, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 12485, 0, 0, 0, 0, 12487, 0, 0, 0, 0, 12489, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12496, 12497, 0, 0, 0, 12499, 12500, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 12502, 12503, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12505, 12506, 0, 0, + 0, 12508, 12509, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12535, 0, 0, 0, 0, + 12536, 0, 0, 0, 0, 12537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12538, 0, + 0, 0, 0, 12542, 0, +}; + +static const change_record change_records_3_2_0[] = { + { 255, 255, 255, 0 }, + { 11, 255, 255, 0 }, + { 10, 255, 255, 0 }, + { 19, 21, 255, 0 }, + { 255, 255, 2, 0 }, + { 255, 255, 3, 0 }, + { 255, 255, 1, 0 }, + { 255, 0, 255, 0 }, + { 255, 29, 255, 0 }, + { 14, 255, 255, 0 }, + { 255, 7, 1, 0 }, + { 255, 7, 2, 0 }, + { 255, 7, 3, 0 }, + { 255, 7, 4, 0 }, + { 255, 7, 5, 0 }, + { 255, 7, 6, 0 }, + { 255, 7, 7, 0 }, + { 255, 7, 8, 0 }, + { 255, 7, 9, 0 }, + { 255, 5, 255, 0 }, + { 15, 14, 255, 0 }, + { 255, 10, 255, 0 }, + { 18, 255, 255, 0 }, + { 19, 255, 255, 0 }, + { 255, 255, 0, 0 }, + { 255, 255, 4, 0 }, + { 255, 255, 5, 0 }, + { 255, 255, 6, 0 }, + { 255, 255, 7, 0 }, + { 255, 255, 8, 0 }, + { 255, 255, 9, 0 }, + { 9, 255, 255, 0 }, + { 255, 20, 255, 0 }, + { 255, 19, 255, 0 }, + { 15, 255, 255, 0 }, + { 255, 255, 255, -1 }, +}; +static unsigned char changes_3_2_0_index[] = { + 0, 1, 2, 2, 3, 4, 5, 6, 2, 7, 2, 8, 9, 10, 11, 2, 2, 2, 12, 13, 14, 15, + 16, 17, 2, 18, 2, 2, 2, 2, 2, 19, 2, 20, 2, 2, 21, 22, 23, 24, 2, 2, 2, + 2, 2, 2, 2, 25, 26, 2, 27, 28, 29, 2, 2, 2, 2, 2, 30, 31, 2, 2, 2, 2, 32, + 33, 34, 2, 35, 2, 2, 36, 37, 38, 2, 2, 39, 40, 2, 41, 42, 42, 2, 2, 2, 2, + 43, 2, 44, 45, 46, 47, 48, 2, 2, 2, 2, 49, 2, 50, 51, 52, 53, 54, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 55, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 56, 57, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 58, 2, 59, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 60, 61, 62, 2, 2, 2, 2, 63, 64, 2, 65, 66, + 67, 68, 69, 70, 2, 2, 71, 72, 73, 74, 2, 2, 2, 2, 2, 2, 75, 2, 2, 2, 76, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 77, 2, 78, 2, 2, 79, 2, 2, + 2, 80, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 30, 81, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; + +static unsigned char changes_3_2_0_data[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, 5, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 9, 0, 0, 0, 0, 0, 0, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, + 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 0, 0, 0, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 7, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, + 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 25, 26, 27, 28, 29, 30, 1, + 1, 0, 0, 0, 0, 24, 6, 4, 5, 25, 26, 27, 28, 29, 30, 1, 1, 0, 0, 0, 0, 7, + 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, + 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, + 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 34, 34, 0, 0, 0, 0, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 0, 0, 7, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, + 0, 0, 0, 7, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 7, 7, 7, 0, 7, 7, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 0, 7, 7, 7, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 0, 0, 0, 0, 7, 7, 7, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const change_record* get_change_3_2_0(Py_UCS4 n) +{ + int index; + if (n >= 0x110000) index = 0; + else { + index = changes_3_2_0_index[n>>7]; + index = changes_3_2_0_data[(index<<7)+(n & 127)]; + } + return change_records_3_2_0+index; +} + +static Py_UCS4 normalization_3_2_0(Py_UCS4 n) +{ + switch(n) { + case 0x2f868: return 0x2136A; + case 0x2f874: return 0x5F33; + case 0x2f91f: return 0x43AB; + case 0x2f95f: return 0x7AAE; + case 0x2f9bf: return 0x4D57; + default: return 0; + } +} + diff --git a/sys/src/cmd/python/Modules/unicodename_db.h b/sys/src/cmd/python/Modules/unicodename_db.h new file mode 100644 index 000000000..ee24aa976 --- /dev/null +++ b/sys/src/cmd/python/Modules/unicodename_db.h @@ -0,0 +1,12543 @@ +/* this file was generated by Tools/unicode/makeunicodedata.py 2.5 */ + +#define NAME_MAXLEN 256 + +/* lexicon */ +static unsigned char lexicon[] = { + 76, 69, 84, 84, 69, 210, 87, 73, 84, 200, 83, 77, 65, 76, 204, 83, 89, + 76, 76, 65, 66, 76, 197, 67, 65, 80, 73, 84, 65, 204, 89, 201, 67, 74, + 203, 76, 65, 84, 73, 206, 67, 79, 77, 80, 65, 84, 73, 66, 73, 76, 73, 84, + 217, 77, 65, 84, 72, 69, 77, 65, 84, 73, 67, 65, 204, 65, 82, 65, 66, 73, + 195, 83, 89, 77, 66, 79, 204, 70, 79, 82, 77, 128, 67, 65, 78, 65, 68, + 73, 65, 206, 83, 89, 76, 76, 65, 66, 73, 67, 211, 66, 79, 76, 196, 71, + 82, 69, 69, 203, 76, 73, 71, 65, 84, 85, 82, 197, 65, 78, 196, 77, 85, + 83, 73, 67, 65, 204, 83, 73, 71, 206, 69, 84, 72, 73, 79, 80, 73, 195, + 72, 65, 78, 71, 85, 204, 73, 84, 65, 76, 73, 195, 82, 65, 68, 73, 67, 65, + 204, 68, 73, 71, 73, 212, 83, 65, 78, 83, 45, 83, 69, 82, 73, 198, 70, + 79, 210, 67, 73, 82, 67, 76, 69, 196, 70, 73, 78, 65, 204, 83, 81, 85, + 65, 82, 197, 67, 89, 82, 73, 76, 76, 73, 195, 86, 79, 87, 69, 204, 86, + 65, 82, 73, 65, 84, 73, 79, 206, 66, 82, 65, 73, 76, 76, 197, 80, 65, 84, + 84, 69, 82, 206, 66, 89, 90, 65, 78, 84, 73, 78, 197, 82, 73, 71, 72, + 212, 73, 83, 79, 76, 65, 84, 69, 196, 76, 69, 70, 212, 194, 75, 65, 84, + 65, 75, 65, 78, 193, 75, 65, 78, 71, 88, 201, 76, 73, 78, 69, 65, 210, + 68, 79, 85, 66, 76, 197, 66, 69, 76, 79, 87, 128, 84, 73, 66, 69, 84, 65, + 206, 65, 66, 79, 86, 69, 128, 77, 79, 68, 73, 70, 73, 69, 210, 67, 79, + 77, 66, 73, 78, 73, 78, 199, 77, 69, 69, 205, 83, 73, 71, 78, 128, 68, + 79, 212, 73, 78, 73, 84, 73, 65, 204, 67, 65, 82, 82, 73, 69, 210, 65, + 82, 82, 79, 87, 128, 89, 69, 200, 77, 79, 78, 71, 79, 76, 73, 65, 206, + 86, 69, 82, 84, 73, 67, 65, 204, 65, 66, 79, 86, 197, 78, 85, 77, 66, 69, + 210, 67, 79, 80, 84, 73, 195, 75, 72, 77, 69, 210, 87, 72, 73, 84, 197, + 65, 82, 82, 79, 215, 66, 79, 216, 65, 128, 72, 69, 66, 82, 69, 215, 77, + 65, 82, 75, 128, 68, 82, 65, 87, 73, 78, 71, 211, 73, 128, 79, 128, 72, + 65, 76, 70, 87, 73, 68, 84, 200, 71, 69, 79, 82, 71, 73, 65, 206, 82, 73, + 71, 72, 84, 87, 65, 82, 68, 211, 73, 68, 69, 79, 71, 82, 65, 205, 85, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 73, 195, 84, 65, 201, 80, 65, + 82, 69, 78, 84, 72, 69, 83, 73, 90, 69, 196, 65, 76, 69, 198, 83, 67, 82, + 73, 80, 212, 68, 69, 86, 65, 78, 65, 71, 65, 82, 201, 66, 76, 65, 67, + 203, 84, 79, 128, 85, 208, 70, 85, 76, 76, 87, 73, 68, 84, 200, 72, 79, + 79, 75, 128, 83, 89, 77, 66, 79, 76, 128, 68, 79, 87, 206, 70, 82, 65, + 75, 84, 85, 210, 72, 65, 200, 69, 81, 85, 65, 204, 72, 69, 65, 86, 217, + 84, 65, 199, 71, 76, 65, 71, 79, 76, 73, 84, 73, 195, 67, 72, 65, 82, 65, + 67, 84, 69, 210, 65, 82, 77, 69, 78, 73, 65, 206, 66, 69, 78, 71, 65, 76, + 201, 67, 72, 79, 83, 69, 79, 78, 199, 74, 69, 69, 205, 66, 82, 65, 67, + 75, 69, 84, 128, 72, 73, 82, 65, 71, 65, 78, 193, 87, 69, 83, 84, 45, 67, + 82, 69, 197, 84, 72, 65, 201, 83, 84, 82, 79, 75, 69, 128, 67, 72, 69, + 82, 79, 75, 69, 197, 73, 68, 69, 79, 71, 82, 65, 80, 200, 84, 87, 79, + 128, 71, 85, 74, 65, 82, 65, 84, 201, 77, 69, 68, 73, 65, 204, 74, 79, + 78, 71, 83, 69, 79, 78, 199, 75, 65, 78, 78, 65, 68, 193, 78, 69, 215, + 207, 79, 82, 73, 89, 193, 82, 85, 78, 73, 195, 84, 69, 84, 82, 65, 71, + 82, 65, 205, 68, 69, 83, 69, 82, 69, 212, 76, 85, 197, 83, 73, 78, 72, + 65, 76, 193, 84, 69, 76, 85, 71, 213, 66, 65, 82, 128, 78, 79, 84, 65, + 84, 73, 79, 206, 79, 78, 69, 128, 83, 89, 82, 73, 65, 195, 77, 65, 76, + 65, 89, 65, 76, 65, 205, 77, 89, 65, 78, 77, 65, 210, 71, 85, 82, 77, 85, + 75, 72, 201, 65, 67, 85, 84, 69, 128, 76, 73, 71, 72, 212, 72, 65, 76, + 198, 68, 79, 85, 66, 76, 69, 45, 83, 84, 82, 85, 67, 203, 76, 69, 70, 84, + 87, 65, 82, 68, 211, 84, 65, 77, 73, 204, 65, 80, 204, 70, 85, 78, 67, + 84, 73, 79, 78, 65, 204, 72, 65, 77, 90, 193, 84, 69, 76, 69, 71, 82, 65, + 80, 200, 74, 85, 78, 71, 83, 69, 79, 78, 199, 79, 198, 68, 65, 83, 73, + 193, 76, 73, 77, 66, 213, 77, 65, 75, 83, 85, 82, 193, 75, 72, 65, 82, + 79, 83, 72, 84, 72, 201, 76, 65, 207, 84, 207, 66, 65, 82, 194, 66, 79, + 80, 79, 77, 79, 70, 207, 72, 69, 88, 65, 71, 82, 65, 205, 77, 65, 82, + 203, 80, 83, 73, 76, 201, 77, 79, 78, 79, 83, 80, 65, 67, 197, 78, 79, + 212, 72, 79, 82, 73, 90, 79, 78, 84, 65, 204, 75, 72, 65, 200, 86, 79, + 67, 65, 76, 73, 195, 84, 72, 82, 69, 69, 128, 65, 69, 71, 69, 65, 206, + 76, 79, 87, 69, 210, 84, 73, 76, 68, 69, 128, 76, 79, 215, 84, 87, 207, + 67, 89, 80, 82, 73, 79, 212, 84, 73, 70, 73, 78, 65, 71, 200, 68, 73, 65, + 69, 82, 69, 83, 73, 83, 128, 70, 73, 86, 69, 128, 70, 79, 85, 82, 128, + 78, 85, 77, 69, 82, 65, 204, 86, 128, 65, 67, 82, 79, 80, 72, 79, 78, 73, + 195, 68, 79, 84, 211, 76, 79, 78, 199, 80, 69, 82, 83, 73, 65, 206, 65, + 78, 71, 76, 197, 72, 65, 82, 80, 79, 79, 206, 83, 73, 88, 128, 84, 79, + 78, 197, 85, 80, 80, 69, 210, 67, 73, 82, 67, 85, 77, 70, 76, 69, 216, + 71, 82, 65, 86, 69, 128, 72, 128, 65, 76, 80, 72, 193, 69, 73, 71, 72, + 84, 128, 77, 65, 67, 82, 79, 78, 128, 78, 79, 79, 206, 84, 72, 65, 65, + 78, 193, 72, 73, 71, 200, 75, 65, 128, 78, 73, 78, 69, 128, 83, 69, 86, + 69, 78, 128, 84, 72, 82, 69, 197, 84, 85, 82, 78, 69, 196, 83, 72, 65, + 86, 73, 65, 206, 83, 84, 79, 80, 128, 68, 128, 71, 128, 79, 77, 69, 71, + 193, 79, 88, 73, 65, 128, 83, 85, 66, 74, 79, 73, 78, 69, 196, 86, 65, + 82, 73, 65, 128, 89, 65, 128, 66, 128, 67, 73, 82, 67, 76, 197, 72, 65, + 128, 74, 128, 77, 65, 128, 82, 69, 86, 69, 82, 83, 69, 196, 82, 73, 71, + 72, 84, 128, 85, 80, 87, 65, 82, 68, 211, 80, 65, 83, 83, 73, 86, 69, 45, + 80, 85, 76, 76, 45, 68, 79, 87, 78, 45, 79, 85, 84, 80, 85, 212, 66, 89, + 69, 76, 79, 82, 85, 83, 83, 73, 65, 78, 45, 85, 75, 82, 65, 73, 78, 73, + 65, 206, 67, 69, 79, 78, 71, 67, 72, 73, 69, 85, 77, 83, 83, 65, 78, 71, + 67, 73, 69, 85, 67, 128, 80, 65, 83, 83, 73, 86, 69, 45, 80, 85, 76, 76, + 45, 85, 80, 45, 79, 85, 84, 80, 85, 212, 65, 78, 84, 73, 67, 76, 79, 67, + 75, 87, 73, 83, 69, 45, 82, 79, 84, 65, 84, 69, 196, 67, 69, 79, 78, 71, + 67, 72, 73, 69, 85, 77, 83, 83, 65, 78, 71, 83, 73, 79, 83, 128, 80, 83, + 73, 70, 73, 83, 84, 79, 80, 65, 82, 65, 75, 65, 76, 69, 83, 77, 65, 128, + 82, 73, 69, 85, 76, 45, 75, 65, 80, 89, 69, 79, 85, 78, 80, 73, 69, 85, + 80, 128, 75, 65, 80, 89, 69, 79, 85, 78, 83, 83, 65, 78, 71, 80, 73, 69, + 85, 80, 128, 79, 80, 69, 78, 45, 67, 73, 82, 67, 85, 73, 84, 45, 79, 85, + 84, 80, 85, 212, 67, 69, 79, 78, 71, 67, 72, 73, 69, 85, 77, 67, 72, 73, + 69, 85, 67, 72, 128, 67, 72, 73, 84, 85, 69, 85, 77, 83, 83, 65, 78, 71, + 67, 73, 69, 85, 67, 128, 75, 73, 89, 69, 79, 75, 45, 83, 73, 79, 83, 45, + 75, 73, 89, 69, 79, 75, 128, 82, 73, 69, 85, 76, 45, 77, 73, 69, 85, 77, + 45, 75, 73, 89, 69, 79, 75, 128, 82, 73, 69, 85, 76, 45, 84, 73, 75, 69, + 85, 84, 45, 72, 73, 69, 85, 72, 128, 84, 82, 79, 77, 73, 75, 79, 80, 65, + 82, 65, 75, 65, 76, 69, 83, 77, 65, 128, 80, 73, 69, 85, 80, 45, 83, 73, + 79, 83, 45, 75, 73, 89, 69, 79, 75, 128, 80, 73, 69, 85, 80, 45, 83, 73, + 79, 83, 45, 84, 73, 75, 69, 85, 84, 128, 82, 73, 69, 85, 76, 45, 75, 73, + 89, 69, 79, 75, 45, 83, 73, 79, 83, 128, 82, 73, 69, 85, 76, 45, 89, 69, + 79, 82, 73, 78, 72, 73, 69, 85, 72, 128, 67, 72, 73, 84, 85, 69, 85, 77, + 83, 83, 65, 78, 71, 83, 73, 79, 83, 128, 73, 69, 85, 78, 71, 45, 83, 83, + 65, 78, 71, 75, 73, 89, 69, 79, 75, 128, 76, 79, 78, 71, 45, 66, 82, 65, + 78, 67, 72, 45, 72, 65, 71, 65, 76, 204, 80, 65, 82, 84, 73, 65, 76, 76, + 89, 45, 82, 69, 67, 89, 67, 76, 69, 196, 82, 73, 69, 85, 76, 45, 80, 73, + 69, 85, 80, 45, 72, 73, 69, 85, 72, 128, 83, 72, 79, 82, 84, 45, 84, 87, + 73, 71, 45, 66, 74, 65, 82, 75, 65, 206, 83, 73, 79, 83, 45, 80, 73, 69, + 85, 80, 45, 75, 73, 89, 69, 79, 75, 128, 75, 65, 84, 65, 75, 65, 78, 65, + 45, 72, 73, 82, 65, 71, 65, 78, 193, 82, 73, 69, 85, 76, 45, 80, 73, 69, + 85, 80, 45, 83, 73, 79, 83, 128, 89, 69, 83, 73, 69, 85, 78, 71, 45, 80, + 65, 78, 83, 73, 79, 83, 128, 67, 69, 79, 78, 71, 67, 72, 73, 69, 85, 77, + 67, 73, 69, 85, 67, 128, 77, 65, 82, 67, 65, 84, 79, 45, 83, 84, 65, 67, + 67, 65, 84, 79, 128, 80, 73, 69, 85, 80, 45, 83, 73, 79, 83, 45, 67, 73, + 69, 85, 67, 128, 80, 73, 69, 85, 80, 45, 83, 73, 79, 83, 45, 80, 73, 69, + 85, 80, 128, 82, 73, 69, 85, 76, 45, 77, 73, 69, 85, 77, 45, 83, 73, 79, + 83, 128, 83, 72, 79, 82, 84, 45, 84, 87, 73, 71, 45, 72, 65, 71, 65, 76, + 204, 83, 79, 70, 84, 87, 65, 82, 69, 45, 70, 85, 78, 67, 84, 73, 79, 206, + 84, 82, 79, 77, 73, 75, 79, 80, 83, 73, 70, 73, 83, 84, 79, 78, 128, 75, + 65, 80, 89, 69, 79, 85, 78, 80, 72, 73, 69, 85, 80, 72, 128, 65, 78, 84, + 73, 82, 69, 83, 84, 82, 73, 67, 84, 73, 79, 78, 128, 65, 67, 67, 69, 78, + 84, 45, 83, 84, 65, 67, 67, 65, 84, 79, 128, 65, 78, 84, 73, 75, 69, 78, + 79, 75, 89, 76, 73, 83, 77, 65, 128, 67, 69, 79, 78, 71, 67, 72, 73, 69, + 85, 77, 83, 73, 79, 83, 128, 67, 72, 73, 69, 85, 67, 72, 45, 75, 72, 73, + 69, 85, 75, 72, 128, 67, 72, 73, 84, 85, 69, 85, 77, 67, 72, 73, 69, 85, + 67, 72, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 49, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 50, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 51, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 48, 52, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 48, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 48, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 48, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 48, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 57, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 65, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 66, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 48, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 48, 68, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 48, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 48, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 49, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 49, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 51, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 52, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 53, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 49, 54, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 49, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 49, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 49, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 49, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 66, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 67, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 68, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 49, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 49, 70, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 50, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 50, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 50, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 50, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 50, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 50, 53, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 50, 54, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 50, 55, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 50, 56, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 50, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 50, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 50, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 50, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 50, 68, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 50, 69, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 50, 70, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 51, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 51, 49, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 51, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 51, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 51, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 51, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 51, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 51, 55, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 51, 56, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 51, 57, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 51, 65, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 51, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 51, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 51, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 51, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 51, 70, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 52, 48, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 52, 49, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 52, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 52, 51, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 52, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 52, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 52, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 52, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 52, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 52, 57, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 52, 65, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 52, 66, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 52, 67, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 52, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 52, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 52, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 53, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 49, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 50, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 51, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 53, 53, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 53, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 53, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 53, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 53, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 66, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 67, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 53, 68, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 53, 69, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 53, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 54, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 54, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 54, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 51, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 52, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 53, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 54, 55, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 54, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 54, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 54, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 54, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 68, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 69, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 54, 70, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 55, 48, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 55, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 55, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 55, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 55, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 55, 53, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 55, 54, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 55, 55, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 55, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 55, 57, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 55, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 55, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 55, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 55, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 55, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 55, 70, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 56, 48, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 56, 49, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 56, 50, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 56, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 56, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 56, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 56, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 56, 55, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 56, 56, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 56, 57, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 56, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 56, 66, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 56, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 56, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 56, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 56, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 49, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 50, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 51, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 57, 52, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 57, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 57, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 57, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 57, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 57, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 65, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 66, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 57, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 57, 68, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 57, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 57, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 65, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 65, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 51, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 52, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 53, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 65, 54, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 65, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 65, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 65, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 65, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 66, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 67, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 68, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 65, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 65, 70, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 66, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 66, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 66, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 66, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 66, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 66, 53, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 66, 54, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 66, 55, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 66, 56, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 66, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 66, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 66, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 66, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 66, 68, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 66, 69, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 66, 70, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 67, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 67, 49, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 67, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 67, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 67, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 67, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 67, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 67, 55, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 67, 56, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 67, 57, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 67, 65, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 67, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 67, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 67, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 67, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 67, 70, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 68, 48, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 68, 49, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 68, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 68, 51, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 68, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 68, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 68, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 68, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 68, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 68, 57, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 68, 65, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 68, 66, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 68, 67, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 68, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 68, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 68, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 69, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 49, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 50, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 51, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 69, 53, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 69, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 69, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 69, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 69, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 66, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 67, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 69, 68, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 69, 69, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 69, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 70, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 70, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 70, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 51, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 52, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 53, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 56, 70, 55, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 56, 70, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 56, 70, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 56, 70, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, + 70, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 68, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 69, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 56, 70, 70, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 48, 48, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 48, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 48, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 48, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 48, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 48, 53, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 48, 54, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 48, 55, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 48, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 48, 57, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 48, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 48, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 48, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 48, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 48, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 48, 70, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 49, 48, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 49, 49, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 49, 50, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 49, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 49, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 49, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 49, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 49, 55, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 49, 56, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 49, 57, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 49, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 49, 66, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 49, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 49, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 49, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 49, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 49, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 50, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 51, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 50, 52, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 50, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 50, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 50, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 50, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 57, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 65, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 66, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 50, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 50, 68, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 50, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 50, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 51, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 51, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 51, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 52, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 53, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 51, 54, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 51, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 51, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 51, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 51, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 66, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 67, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 68, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 51, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 51, 70, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 52, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 52, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 52, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 52, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 52, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 52, 53, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 52, 54, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 52, 55, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 52, 56, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 52, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 52, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 52, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 52, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 52, 68, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 52, 69, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 52, 70, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 53, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 53, 49, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 53, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 53, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 53, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 53, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 53, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 53, 55, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 53, 56, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 53, 57, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 53, 65, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 53, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 53, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 53, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 53, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 53, 70, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 54, 48, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 54, 49, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 54, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 54, 51, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 54, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 54, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 54, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 54, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 54, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 54, 57, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 54, 65, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 54, 66, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 54, 67, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 54, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 54, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 54, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 55, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 49, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 50, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 51, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 55, 53, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 55, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 55, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 55, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 55, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 66, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 67, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 55, 68, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 55, 69, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 55, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 56, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 56, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 56, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 51, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 52, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 53, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 56, 55, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 56, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 56, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 56, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 56, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 68, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 69, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 56, 70, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 57, 48, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 57, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 57, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 57, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 57, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 57, 53, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 57, 54, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 57, 55, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 57, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 57, 57, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 57, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 57, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 57, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 57, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 57, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 57, 70, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 65, 48, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 65, 49, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 65, 50, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 65, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 65, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 65, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 65, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 65, 55, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 65, 56, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 65, 57, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 65, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 65, 66, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 65, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 65, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 65, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 65, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 49, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 50, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 51, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 66, 52, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 66, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 66, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 66, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 66, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 57, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 65, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 66, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 66, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 66, 68, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 66, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 66, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 67, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 67, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 51, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 52, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 53, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 67, 54, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 67, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 67, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 67, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 67, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 66, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 67, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 68, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 67, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 67, 70, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 68, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 68, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 68, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 68, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 68, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 68, 53, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 68, 54, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 68, 55, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 68, 56, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 68, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 68, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 68, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 68, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 68, 68, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 68, 69, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 68, 70, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 69, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 69, 49, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 69, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 69, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 69, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 69, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 69, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 69, 55, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 69, 56, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 69, 57, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 69, 65, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 69, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 69, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 69, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 69, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 69, 70, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 70, 48, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 70, 49, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 70, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 70, 51, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 70, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 70, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 70, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, + 70, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 70, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 70, 57, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 70, 65, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 57, 70, 66, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 57, 70, 67, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 57, 70, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 57, 70, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 57, 70, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, + 48, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 49, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 50, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 51, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 65, 48, 53, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 65, 48, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 65, 48, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 65, 48, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, + 48, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 66, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 67, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 48, 68, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 65, 48, 69, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 65, 48, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 65, 49, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 65, 49, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, + 49, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 49, 51, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 49, 52, 128, 73, + 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 49, 53, 128, 73, 68, 69, + 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 49, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 50, 70, 65, 49, 55, 128, 73, 68, 69, 79, 71, 82, 65, + 80, 72, 45, 50, 70, 65, 49, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, + 45, 50, 70, 65, 49, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, + 70, 65, 49, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, + 49, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 49, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 50, 70, 65, 49, 68, 128, 74, + 65, 76, 76, 65, 74, 65, 76, 65, 76, 79, 85, 72, 79, 85, 128, 75, 82, 65, + 84, 73, 77, 79, 75, 79, 85, 70, 73, 83, 77, 65, 128, 75, 82, 65, 84, 73, + 77, 79, 89, 80, 79, 82, 82, 79, 79, 78, 128, 76, 79, 78, 71, 45, 66, 82, + 65, 78, 67, 72, 45, 77, 65, 68, 210, 77, 73, 69, 85, 77, 45, 83, 83, 65, + 78, 71, 83, 73, 79, 83, 128, 80, 69, 84, 65, 83, 84, 79, 75, 79, 85, 70, + 73, 83, 77, 65, 128, 80, 73, 69, 85, 80, 45, 83, 83, 65, 78, 71, 83, 73, + 79, 83, 128, 80, 83, 73, 70, 73, 83, 84, 79, 76, 89, 71, 73, 83, 77, 65, + 128, 80, 83, 73, 70, 73, 83, 84, 79, 83, 89, 78, 65, 71, 77, 65, 128, 82, + 73, 69, 85, 76, 45, 83, 83, 65, 78, 71, 83, 73, 79, 83, 128, 84, 69, 65, + 82, 68, 82, 79, 80, 45, 83, 72, 65, 78, 75, 69, 196, 80, 82, 79, 83, 71, + 69, 71, 82, 65, 77, 77, 69, 78, 73, 128, 84, 69, 65, 82, 68, 82, 79, 80, + 45, 83, 80, 79, 75, 69, 196, 66, 76, 65, 67, 75, 45, 70, 69, 65, 84, 72, + 69, 82, 69, 196, 84, 82, 73, 65, 78, 71, 76, 69, 45, 72, 69, 65, 68, 69, + 196, 67, 79, 78, 71, 82, 65, 84, 85, 76, 65, 84, 73, 79, 78, 128, 72, 73, + 71, 72, 45, 82, 69, 86, 69, 82, 83, 69, 68, 45, 185, 65, 70, 79, 82, 69, + 77, 69, 78, 84, 73, 79, 78, 69, 68, 128, 65, 82, 79, 85, 78, 68, 45, 80, + 82, 79, 70, 73, 76, 69, 128, 67, 79, 78, 67, 65, 86, 69, 45, 80, 79, 73, + 78, 84, 69, 196, 71, 79, 82, 71, 79, 83, 89, 78, 84, 72, 69, 84, 79, 78, + 128, 73, 68, 69, 78, 84, 73, 70, 73, 67, 65, 84, 73, 79, 78, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 48, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 48, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 48, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 48, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 48, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 48, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 48, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 48, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 48, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 48, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 48, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 48, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 48, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 48, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 48, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 48, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 49, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 49, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 49, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 49, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 55, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 49, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 49, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 49, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 68, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 49, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 49, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 50, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 50, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 50, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 50, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 50, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 50, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 50, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 50, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 50, 70, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 51, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 51, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 51, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 51, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 51, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 51, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 51, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 51, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 51, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 51, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 51, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 51, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 51, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 51, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 51, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 51, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 49, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 52, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 52, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 52, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 55, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 52, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 52, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 52, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 68, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 52, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 52, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 53, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 53, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 53, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 53, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 53, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 53, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 53, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 53, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 53, 70, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 54, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 54, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 54, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 54, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 54, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 54, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 54, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 54, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 54, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 54, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 54, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 54, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 54, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 54, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 54, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 54, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 49, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 55, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 55, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 55, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 55, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 55, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 55, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 55, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 68, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 55, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 55, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 56, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 56, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 56, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 56, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 56, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 56, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 56, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 56, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 56, 70, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 57, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 57, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 57, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 57, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 57, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 57, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 57, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 57, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 57, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 57, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 57, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 57, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 57, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 57, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 57, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 57, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 49, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 65, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 65, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 65, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 55, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 65, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 65, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 65, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 68, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 65, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 65, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 66, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 66, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 66, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 66, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 66, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 66, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 66, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 66, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 66, 70, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 67, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 67, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 67, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 67, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 67, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 67, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 67, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 67, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 67, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 67, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 67, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 67, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 67, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 67, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 67, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 67, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 49, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 68, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 68, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 68, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 55, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 68, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 68, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 68, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 68, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 68, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 68, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 69, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 69, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 69, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 69, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 69, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 69, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 69, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 69, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 69, 70, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 70, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 70, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 70, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 70, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 70, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 70, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 70, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 70, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 70, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 70, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 70, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 70, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 57, 70, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 57, 70, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 57, 70, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 57, 70, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 49, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 48, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 48, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 48, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 55, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 48, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 48, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 48, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 68, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 48, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 48, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 49, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 49, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 49, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 49, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 49, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 49, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 49, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 49, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 49, 70, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 50, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 50, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 50, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 50, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 50, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 50, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 50, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 50, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 50, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 50, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 50, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 50, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 50, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 50, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 51, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 51, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 51, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 51, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 51, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 51, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 51, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 51, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 69, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 51, 70, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 52, 48, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 52, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 52, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 52, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 52, 52, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 52, 53, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 52, 54, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 52, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 52, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 52, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 52, 65, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 52, 66, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 52, 67, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 52, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 52, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 52, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 48, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 49, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 50, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 53, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 53, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 53, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 54, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 55, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 56, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 53, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 53, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 53, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 67, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 68, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 53, 69, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 53, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 54, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 54, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 54, 50, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 54, 51, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 54, 52, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 54, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 54, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 54, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 54, 56, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 54, 57, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 54, 65, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 55, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 55, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 55, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 55, 51, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 55, 52, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 55, 53, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 55, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 55, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 55, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 55, 57, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 55, 65, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 55, 66, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 55, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 55, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 55, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 55, 70, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 48, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 49, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 56, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 56, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 56, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 53, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 54, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 55, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 56, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 56, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 56, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 66, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 67, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 56, 68, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 56, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 56, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 57, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 49, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 50, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 51, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 57, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 57, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 57, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 55, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 56, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 57, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 57, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 57, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 57, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 68, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 69, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 57, 70, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 65, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 65, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 65, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 65, 51, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 65, 52, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 65, 53, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 65, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 65, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 65, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 65, 57, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 65, 65, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 65, 66, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 65, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 65, 68, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 65, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 65, 70, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 48, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 49, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 66, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 66, 51, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 66, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 53, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 54, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 55, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 66, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 66, 57, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 66, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 66, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 67, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 66, 68, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 66, 69, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 66, 70, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 67, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 49, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 50, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 51, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 67, 52, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 67, 53, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 67, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 55, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 56, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 57, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 67, 65, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 67, 66, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 67, 67, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 68, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 69, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 67, 70, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 68, 48, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 68, 49, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 68, 50, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 68, 51, + 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 68, 52, 128, 73, 68, + 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 68, 53, 128, 73, 68, 69, 79, 71, + 82, 65, 80, 72, 45, 70, 65, 68, 54, 128, 73, 68, 69, 79, 71, 82, 65, 80, + 72, 45, 70, 65, 68, 55, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, + 65, 68, 56, 128, 73, 68, 69, 79, 71, 82, 65, 80, 72, 45, 70, 65, 68, 57, + 128, 76, 79, 78, 71, 45, 66, 82, 65, 78, 67, 72, 45, 79, 83, 211, 76, 79, + 78, 71, 45, 66, 82, 65, 78, 67, 72, 45, 83, 79, 204, 76, 79, 78, 71, 45, + 66, 82, 65, 78, 67, 72, 45, 89, 82, 128, 77, 85, 76, 84, 73, 80, 76, 73, + 67, 65, 84, 73, 79, 78, 128, 80, 65, 76, 65, 84, 65, 76, 73, 90, 65, 84, + 73, 79, 78, 128, 83, 72, 79, 82, 84, 45, 84, 87, 73, 71, 45, 77, 65, 68, + 210, 83, 72, 79, 82, 84, 45, 84, 87, 73, 71, 45, 78, 65, 85, 196, 83, 73, + 79, 83, 45, 83, 83, 65, 78, 71, 83, 73, 79, 83, 128, 84, 69, 65, 82, 68, + 82, 79, 80, 45, 66, 65, 82, 66, 69, 196, 84, 82, 79, 77, 73, 75, 79, 76, + 89, 71, 73, 83, 77, 65, 128, 84, 82, 79, 77, 73, 75, 79, 83, 89, 78, 65, + 71, 77, 65, 128, 87, 72, 73, 84, 69, 45, 70, 69, 65, 84, 72, 69, 82, 69, + 196, 89, 80, 79, 71, 69, 71, 82, 65, 77, 77, 69, 78, 73, 128, 82, 73, 71, + 72, 84, 45, 80, 79, 73, 78, 84, 73, 78, 199, 77, 85, 76, 84, 73, 80, 76, + 73, 67, 65, 84, 73, 79, 206, 82, 73, 71, 72, 84, 45, 83, 72, 65, 68, 79, + 87, 69, 196, 66, 65, 76, 76, 79, 79, 78, 45, 83, 80, 79, 75, 69, 196, 75, + 65, 80, 89, 69, 79, 85, 78, 77, 73, 69, 85, 77, 128, 82, 73, 69, 85, 76, + 45, 80, 72, 73, 69, 85, 80, 72, 128, 82, 73, 69, 85, 76, 45, 84, 72, 73, + 69, 85, 84, 72, 128, 65, 82, 71, 79, 83, 89, 78, 84, 72, 69, 84, 79, 78, + 128, 65, 83, 89, 77, 80, 84, 79, 84, 73, 67, 65, 76, 76, 217, 77, 73, 69, + 85, 77, 45, 80, 65, 78, 83, 73, 79, 83, 128, 78, 73, 69, 85, 78, 45, 80, + 65, 78, 83, 73, 79, 83, 128, 80, 65, 82, 65, 76, 76, 69, 76, 79, 71, 82, + 65, 77, 128, 80, 69, 82, 80, 69, 78, 68, 73, 67, 85, 76, 65, 82, 128, 80, + 72, 73, 69, 85, 80, 72, 45, 80, 73, 69, 85, 80, 128, 80, 73, 69, 85, 80, + 45, 80, 72, 73, 69, 85, 80, 72, 128, 80, 73, 69, 85, 80, 45, 84, 72, 73, + 69, 85, 84, 72, 128, 80, 82, 69, 80, 79, 78, 68, 69, 82, 65, 78, 67, 69, + 128, 82, 73, 69, 85, 76, 45, 80, 65, 78, 83, 73, 79, 83, 128, 84, 69, 84, + 65, 82, 84, 73, 77, 79, 82, 73, 79, 78, 128, 84, 73, 75, 69, 85, 84, 45, + 75, 73, 89, 69, 79, 75, 128, 84, 82, 73, 65, 78, 71, 76, 69, 45, 82, 79, + 85, 78, 196, 89, 69, 83, 73, 69, 85, 78, 71, 45, 83, 73, 79, 83, 128, 65, + 86, 65, 75, 82, 65, 72, 65, 83, 65, 78, 89, 65, 128, 66, 79, 84, 84, 79, + 77, 45, 76, 73, 71, 72, 84, 69, 196, 67, 72, 73, 69, 85, 67, 72, 45, 72, + 73, 69, 85, 72, 128, 67, 72, 73, 84, 85, 69, 85, 77, 67, 73, 69, 85, 67, + 128, 67, 79, 78, 84, 69, 77, 80, 76, 65, 84, 73, 79, 78, 128, 68, 79, 84, + 83, 45, 49, 50, 51, 52, 53, 54, 55, 56, 128, 69, 77, 66, 69, 76, 76, 73, + 83, 72, 77, 69, 78, 84, 128, 73, 69, 85, 78, 71, 45, 67, 72, 73, 69, 85, + 67, 72, 128, 73, 69, 85, 78, 71, 45, 75, 72, 73, 69, 85, 75, 72, 128, 73, + 69, 85, 78, 71, 45, 80, 72, 73, 69, 85, 80, 72, 128, 73, 69, 85, 78, 71, + 45, 84, 72, 73, 69, 85, 84, 72, 128, 75, 65, 80, 89, 69, 79, 85, 78, 82, + 73, 69, 85, 76, 128, 76, 79, 78, 71, 45, 66, 82, 65, 78, 67, 72, 45, 65, + 210, 77, 73, 69, 85, 77, 45, 67, 72, 73, 69, 85, 67, 72, 128, 78, 73, 69, + 85, 78, 45, 84, 72, 73, 69, 85, 84, 72, 128, 80, 73, 69, 85, 80, 45, 67, + 72, 73, 69, 85, 67, 72, 128, 82, 73, 69, 85, 76, 45, 75, 72, 73, 69, 85, + 75, 72, 128, 83, 72, 79, 82, 84, 45, 84, 87, 73, 71, 45, 79, 83, 211, 83, + 72, 79, 82, 84, 45, 84, 87, 73, 71, 45, 83, 79, 204, 83, 72, 79, 82, 84, + 45, 84, 87, 73, 71, 45, 84, 89, 210, 83, 72, 79, 82, 84, 45, 84, 87, 73, + 71, 45, 89, 82, 128, 83, 84, 65, 67, 67, 65, 84, 73, 83, 83, 73, 77, 79, + 128, 83, 84, 82, 73, 75, 69, 84, 72, 82, 79, 85, 71, 72, 128, 84, 72, 69, + 82, 77, 79, 68, 89, 78, 65, 77, 73, 67, 128, 89, 85, 85, 75, 65, 76, 69, + 65, 80, 73, 78, 84, 85, 128, 71, 82, 69, 65, 84, 69, 82, 45, 84, 72, 65, + 78, 128, 65, 78, 84, 73, 67, 76, 79, 67, 75, 87, 73, 83, 197, 76, 69, 70, + 84, 45, 80, 79, 73, 78, 84, 73, 78, 199, 73, 78, 84, 69, 82, 83, 69, 67, + 84, 73, 79, 78, 128, 65, 80, 80, 82, 79, 88, 73, 77, 65, 84, 69, 76, 217, + 68, 73, 70, 70, 69, 82, 69, 78, 84, 73, 65, 76, 128, 68, 79, 87, 78, 45, + 80, 79, 73, 78, 84, 73, 78, 199, 80, 65, 82, 69, 83, 84, 73, 71, 77, 69, + 78, 79, 206, 67, 82, 89, 80, 84, 79, 71, 82, 65, 77, 77, 73, 195, 72, 89, + 80, 72, 69, 78, 45, 77, 73, 78, 85, 83, 128, 67, 79, 78, 67, 65, 86, 69, + 45, 83, 73, 68, 69, 196, 76, 69, 70, 84, 45, 84, 79, 45, 82, 73, 71, 72, + 212, 78, 73, 69, 85, 78, 45, 84, 73, 75, 69, 85, 84, 128, 82, 73, 69, 85, + 76, 45, 75, 73, 89, 69, 79, 75, 128, 82, 73, 71, 72, 84, 45, 84, 79, 45, + 76, 69, 70, 212, 84, 82, 65, 78, 83, 80, 79, 83, 73, 84, 73, 79, 206, 67, + 82, 79, 83, 83, 69, 68, 45, 84, 65, 73, 76, 128, 68, 73, 77, 73, 78, 85, + 84, 73, 79, 78, 45, 49, 128, 68, 82, 79, 80, 45, 83, 72, 65, 68, 79, 87, + 69, 196, 71, 65, 69, 84, 84, 65, 45, 80, 73, 76, 76, 65, 128, 71, 69, 79, + 77, 69, 84, 82, 73, 67, 65, 76, 76, 217, 73, 69, 85, 78, 71, 45, 75, 73, + 89, 69, 79, 75, 128, 73, 78, 84, 69, 82, 80, 79, 76, 65, 84, 73, 79, 206, + 78, 73, 69, 85, 78, 45, 75, 73, 89, 69, 79, 75, 128, 80, 73, 69, 85, 80, + 45, 84, 73, 75, 69, 85, 84, 128, 82, 73, 69, 85, 76, 45, 84, 73, 75, 69, + 85, 84, 128, 84, 72, 73, 82, 84, 89, 45, 83, 69, 67, 79, 78, 196, 84, 87, + 69, 78, 84, 89, 45, 69, 73, 71, 72, 84, 200, 84, 87, 69, 78, 84, 89, 45, + 84, 72, 82, 69, 69, 128, 65, 67, 67, 85, 77, 85, 76, 65, 84, 73, 79, 78, + 128, 65, 78, 65, 84, 82, 73, 67, 72, 73, 83, 77, 65, 128, 65, 85, 82, 65, + 77, 65, 90, 68, 65, 65, 45, 50, 128, 65, 85, 82, 65, 77, 65, 90, 68, 65, + 65, 72, 65, 128, 66, 82, 69, 65, 75, 84, 72, 82, 79, 85, 71, 72, 128, 67, + 72, 73, 84, 85, 69, 85, 77, 83, 73, 79, 83, 128, 67, 89, 76, 73, 78, 68, + 82, 73, 67, 73, 84, 89, 128, 68, 69, 67, 73, 83, 73, 86, 69, 78, 69, 83, + 83, 128, 68, 69, 70, 69, 67, 84, 73, 86, 69, 78, 69, 83, 211, 68, 73, 70, + 70, 73, 67, 85, 76, 84, 73, 69, 83, 128, 68, 73, 77, 73, 78, 73, 83, 72, + 77, 69, 78, 84, 128, 68, 73, 77, 73, 78, 85, 84, 73, 79, 78, 45, 50, 128, + 68, 73, 77, 73, 78, 85, 84, 73, 79, 78, 45, 51, 128, 68, 73, 83, 67, 79, + 78, 84, 73, 78, 85, 79, 85, 211, 68, 79, 84, 83, 45, 49, 50, 51, 52, 53, + 54, 55, 128, 68, 79, 84, 83, 45, 49, 50, 51, 52, 53, 54, 56, 128, 68, 79, + 84, 83, 45, 49, 50, 51, 52, 53, 55, 56, 128, 68, 79, 84, 83, 45, 49, 50, + 51, 52, 54, 55, 56, 128, 68, 79, 84, 83, 45, 49, 50, 51, 53, 54, 55, 56, + 128, 68, 79, 84, 83, 45, 49, 50, 52, 53, 54, 55, 56, 128, 68, 79, 84, 83, + 45, 49, 51, 52, 53, 54, 55, 56, 128, 68, 79, 84, 83, 45, 50, 51, 52, 53, + 54, 55, 56, 128, 69, 85, 82, 79, 45, 67, 85, 82, 82, 69, 78, 67, 217, 70, + 76, 69, 85, 82, 45, 68, 69, 45, 76, 73, 83, 128, 71, 82, 79, 78, 84, 72, + 73, 83, 77, 65, 84, 65, 128, 72, 89, 80, 79, 68, 73, 65, 83, 84, 79, 76, + 69, 128, 73, 67, 69, 76, 65, 78, 68, 73, 67, 45, 89, 82, 128, 73, 69, 85, + 78, 71, 45, 84, 73, 75, 69, 85, 84, 128, 73, 78, 84, 69, 82, 83, 89, 76, + 76, 65, 66, 73, 195, 74, 85, 68, 69, 79, 45, 83, 80, 65, 78, 73, 83, 200, + 75, 73, 89, 69, 79, 75, 45, 82, 73, 69, 85, 76, 128, 76, 65, 66, 73, 65, + 76, 73, 90, 65, 84, 73, 79, 206, 77, 73, 78, 85, 83, 45, 79, 82, 45, 80, + 76, 85, 211, 77, 79, 82, 80, 72, 79, 76, 79, 71, 73, 67, 65, 204, 79, 80, + 69, 78, 45, 79, 85, 84, 76, 73, 78, 69, 196, 80, 69, 82, 80, 69, 78, 68, + 73, 67, 85, 76, 65, 210, 82, 85, 76, 69, 45, 68, 69, 76, 65, 89, 69, 68, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 48, 48, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 49, 48, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 49, 48, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 48, 51, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 49, 48, 52, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 49, 48, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 48, + 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 48, 55, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 49, 48, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 48, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 49, 48, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 49, 49, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 49, 49, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, + 49, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 49, 52, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 49, 53, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 49, 49, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 49, 55, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 49, 56, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 49, 49, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 49, 50, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 50, 49, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 49, 50, 50, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 49, 50, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 50, + 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 50, 53, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 49, 50, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 50, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 50, 56, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 50, 57, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 49, 51, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, + 51, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 51, 50, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 51, 51, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 49, 51, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 51, 53, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 51, 54, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 49, 51, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 49, 51, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 51, 57, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 49, 52, 48, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 49, 52, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 52, + 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 52, 51, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 49, 52, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 52, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 52, 54, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 52, 55, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 49, 52, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, + 52, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 53, 48, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 53, 49, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 49, 53, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 53, 51, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 53, 52, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 49, 53, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 49, 53, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 53, 55, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 49, 53, 56, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 49, 53, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 54, + 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 54, 49, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 49, 54, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 54, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 54, 52, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 54, 53, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 49, 54, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, + 54, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 54, 56, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 54, 57, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 49, 55, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 55, 49, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 55, 50, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 49, 55, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 49, 55, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 55, 53, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 49, 55, 54, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 49, 55, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 55, + 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 55, 57, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 49, 56, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 56, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 56, 50, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 56, 51, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 49, 56, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, + 56, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 56, 54, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 56, 55, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 49, 56, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 56, 57, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 57, 48, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 49, 57, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 49, 57, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 57, 51, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 49, 57, 52, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 49, 57, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 57, + 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 57, 55, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 49, 57, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 57, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 48, 48, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 48, 49, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 50, 48, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, + 48, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 48, 52, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 50, 48, 53, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 50, 48, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 48, 55, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 48, 56, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 50, 48, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 50, 49, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 49, 49, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 50, 49, 50, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 50, 49, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 49, + 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 49, 53, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 50, 49, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 50, 49, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 49, 56, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 49, 57, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 50, 50, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, + 50, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 50, 50, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 50, 50, 51, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 50, 50, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 50, 53, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 50, 54, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 50, 50, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 50, 50, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 50, 57, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 50, 51, 48, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 50, 51, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 51, + 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 51, 51, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 50, 51, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 50, 51, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 51, 54, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 51, 55, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 50, 51, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, + 51, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 52, 48, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 50, 52, 49, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 50, 52, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 52, 51, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 52, 52, 128, 83, 69, 76, 69, + 67, 84, 79, 82, 45, 50, 52, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, + 50, 52, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 52, 55, 128, 83, + 69, 76, 69, 67, 84, 79, 82, 45, 50, 52, 56, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 50, 52, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 53, + 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 53, 49, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 50, 53, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 50, 53, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 53, 52, 128, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 53, 53, 128, 83, 69, 76, 69, 67, + 84, 79, 82, 45, 50, 53, 54, 128, 83, 72, 79, 82, 84, 45, 84, 87, 73, 71, + 45, 65, 210, 83, 73, 79, 83, 45, 67, 72, 73, 69, 85, 67, 72, 128, 83, 73, + 79, 83, 45, 75, 72, 73, 69, 85, 75, 72, 128, 83, 73, 79, 83, 45, 80, 72, + 73, 69, 85, 80, 72, 128, 83, 73, 79, 83, 45, 84, 72, 73, 69, 85, 84, 72, + 128, 83, 84, 82, 65, 71, 71, 73, 83, 77, 65, 84, 65, 128, 84, 72, 85, 78, + 68, 69, 82, 83, 84, 79, 82, 77, 128, 84, 73, 75, 69, 85, 84, 45, 82, 73, + 69, 85, 76, 128, 84, 82, 65, 78, 83, 77, 73, 83, 83, 73, 79, 78, 128, 84, + 87, 69, 78, 84, 89, 45, 69, 73, 71, 72, 84, 128, 84, 87, 69, 78, 84, 89, + 45, 83, 69, 86, 69, 78, 128, 86, 79, 87, 69, 76, 45, 67, 65, 82, 82, 73, + 69, 210, 88, 83, 72, 65, 65, 89, 65, 84, 72, 73, 89, 65, 128, 89, 79, 85, + 84, 72, 70, 85, 76, 78, 69, 83, 83, 128, 71, 82, 69, 65, 84, 69, 82, 45, + 84, 72, 65, 206, 73, 78, 83, 84, 82, 85, 77, 69, 78, 84, 65, 204, 80, 82, + 69, 83, 69, 78, 84, 65, 84, 73, 79, 206, 80, 69, 82, 73, 83, 80, 79, 77, + 69, 78, 73, 128, 67, 45, 83, 73, 77, 80, 76, 73, 70, 73, 69, 196, 65, 82, + 65, 66, 73, 67, 45, 73, 78, 68, 73, 195, 80, 65, 82, 69, 78, 84, 72, 69, + 83, 73, 83, 128, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 78, 128, 73, 78, + 84, 69, 82, 83, 69, 67, 84, 73, 79, 206, 67, 65, 78, 68, 82, 65, 66, 73, + 78, 68, 85, 128, 69, 82, 82, 79, 82, 45, 66, 65, 82, 82, 69, 196, 83, 85, + 66, 83, 84, 73, 84, 85, 84, 73, 79, 206, 66, 76, 65, 67, 75, 45, 76, 69, + 84, 84, 69, 210, 65, 80, 80, 82, 79, 88, 73, 77, 65, 84, 69, 128, 67, 65, + 78, 84, 73, 76, 76, 65, 84, 73, 79, 206, 69, 75, 70, 79, 78, 73, 84, 73, + 75, 79, 78, 128, 74, 45, 83, 73, 77, 80, 76, 73, 70, 73, 69, 196, 82, 73, + 69, 85, 76, 45, 72, 73, 69, 85, 72, 128, 83, 79, 85, 84, 72, 45, 83, 76, + 65, 86, 69, 217, 65, 66, 66, 82, 69, 86, 73, 65, 84, 73, 79, 206, 65, 83, + 84, 82, 79, 76, 79, 71, 73, 67, 65, 204, 71, 65, 89, 65, 78, 85, 75, 73, + 84, 84, 65, 128, 77, 73, 69, 85, 77, 45, 80, 73, 69, 85, 80, 128, 78, 73, + 69, 85, 78, 45, 67, 73, 69, 85, 67, 128, 78, 73, 69, 85, 78, 45, 72, 73, + 69, 85, 72, 128, 80, 65, 82, 65, 71, 82, 65, 80, 72, 79, 83, 128, 82, 73, + 69, 85, 76, 45, 77, 73, 69, 85, 77, 128, 82, 73, 69, 85, 76, 45, 80, 73, + 69, 85, 80, 128, 83, 69, 77, 73, 67, 73, 82, 67, 85, 76, 65, 210, 83, 83, + 65, 78, 71, 84, 73, 75, 69, 85, 84, 128, 65, 67, 75, 78, 79, 87, 76, 69, + 68, 71, 69, 128, 67, 79, 77, 80, 79, 83, 73, 84, 73, 79, 78, 128, 73, 78, + 84, 69, 82, 83, 69, 67, 84, 73, 78, 199, 80, 73, 69, 85, 80, 45, 67, 73, + 69, 85, 67, 128, 81, 85, 73, 78, 68, 73, 67, 69, 83, 73, 77, 193, 82, 73, + 69, 85, 76, 45, 78, 73, 69, 85, 78, 128, 83, 73, 88, 84, 89, 45, 70, 79, + 85, 82, 84, 200, 84, 82, 73, 84, 73, 77, 79, 82, 73, 79, 78, 128, 84, 87, + 69, 78, 84, 89, 45, 70, 79, 85, 82, 128, 87, 69, 68, 71, 69, 45, 84, 65, + 73, 76, 69, 196, 65, 69, 83, 67, 85, 76, 65, 80, 73, 85, 83, 128, 65, 71, + 71, 82, 65, 86, 65, 84, 73, 79, 78, 128, 65, 77, 65, 76, 71, 65, 77, 65, + 84, 73, 79, 206, 65, 80, 80, 76, 73, 67, 65, 84, 73, 79, 78, 128, 65, 85, + 71, 77, 69, 78, 84, 65, 84, 73, 79, 206, 67, 65, 78, 67, 69, 76, 76, 65, + 84, 73, 79, 206, 67, 73, 69, 85, 67, 45, 73, 69, 85, 78, 71, 128, 67, 79, + 78, 74, 85, 78, 67, 84, 73, 79, 78, 128, 67, 79, 78, 84, 82, 65, 67, 84, + 73, 79, 78, 128, 67, 79, 78, 84, 82, 65, 82, 73, 69, 84, 89, 128, 67, 79, + 82, 80, 79, 82, 65, 84, 73, 79, 78, 128, 67, 79, 85, 78, 84, 69, 82, 66, + 79, 82, 69, 128, 67, 79, 85, 78, 84, 69, 82, 83, 73, 78, 75, 128, 68, 65, + 72, 89, 65, 65, 85, 83, 72, 45, 50, 128, 68, 69, 67, 82, 69, 83, 67, 69, + 78, 68, 79, 128, 68, 69, 76, 73, 86, 69, 82, 65, 78, 67, 69, 128, 68, 69, + 78, 79, 77, 73, 78, 65, 84, 79, 82, 128, 68, 69, 82, 69, 84, 45, 72, 73, + 68, 69, 84, 128, 68, 69, 86, 69, 76, 79, 80, 77, 69, 78, 84, 128, 68, 73, + 83, 84, 73, 78, 71, 85, 73, 83, 72, 128, 68, 79, 65, 67, 72, 65, 83, 72, + 77, 69, 69, 128, 68, 79, 84, 83, 45, 49, 50, 51, 52, 53, 54, 128, 68, 79, + 84, 83, 45, 49, 50, 51, 52, 53, 55, 128, 68, 79, 84, 83, 45, 49, 50, 51, + 52, 53, 56, 128, 68, 79, 84, 83, 45, 49, 50, 51, 52, 54, 55, 128, 68, 79, + 84, 83, 45, 49, 50, 51, 52, 54, 56, 128, 68, 79, 84, 83, 45, 49, 50, 51, + 52, 55, 56, 128, 68, 79, 84, 83, 45, 49, 50, 51, 53, 54, 55, 128, 68, 79, + 84, 83, 45, 49, 50, 51, 53, 54, 56, 128, 68, 79, 84, 83, 45, 49, 50, 51, + 53, 55, 56, 128, 68, 79, 84, 83, 45, 49, 50, 51, 54, 55, 56, 128, 68, 79, + 84, 83, 45, 49, 50, 52, 53, 54, 55, 128, 68, 79, 84, 83, 45, 49, 50, 52, + 53, 54, 56, 128, 68, 79, 84, 83, 45, 49, 50, 52, 53, 55, 56, 128, 68, 79, + 84, 83, 45, 49, 50, 52, 54, 55, 56, 128, 68, 79, 84, 83, 45, 49, 50, 53, + 54, 55, 56, 128, 68, 79, 84, 83, 45, 49, 51, 52, 53, 54, 55, 128, 68, 79, + 84, 83, 45, 49, 51, 52, 53, 54, 56, 128, 68, 79, 84, 83, 45, 49, 51, 52, + 53, 55, 56, 128, 68, 79, 84, 83, 45, 49, 51, 52, 54, 55, 56, 128, 68, 79, + 84, 83, 45, 49, 51, 53, 54, 55, 56, 128, 68, 79, 84, 83, 45, 49, 52, 53, + 54, 55, 56, 128, 68, 79, 84, 83, 45, 50, 51, 52, 53, 54, 55, 128, 68, 79, + 84, 83, 45, 50, 51, 52, 53, 54, 56, 128, 68, 79, 84, 83, 45, 50, 51, 52, + 53, 55, 56, 128, 68, 79, 84, 83, 45, 50, 51, 52, 54, 55, 56, 128, 68, 79, + 84, 83, 45, 50, 51, 53, 54, 55, 56, 128, 68, 79, 84, 83, 45, 50, 52, 53, + 54, 55, 56, 128, 68, 79, 84, 83, 45, 51, 52, 53, 54, 55, 56, 128, 68, 79, + 85, 66, 76, 69, 45, 69, 78, 68, 69, 196, 69, 65, 77, 72, 65, 78, 67, 72, + 79, 76, 76, 128, 69, 78, 76, 65, 82, 71, 69, 77, 69, 78, 84, 128, 70, 73, + 78, 71, 69, 82, 78, 65, 73, 76, 83, 128, 70, 82, 79, 78, 84, 45, 84, 73, + 76, 84, 69, 196, 71, 85, 65, 82, 68, 69, 68, 78, 69, 83, 83, 128, 72, 65, + 85, 80, 84, 83, 84, 73, 77, 77, 69, 128, 72, 73, 69, 85, 72, 45, 77, 73, + 69, 85, 77, 128, 72, 73, 69, 85, 72, 45, 78, 73, 69, 85, 78, 128, 72, 73, + 69, 85, 72, 45, 80, 73, 69, 85, 80, 128, 72, 73, 69, 85, 72, 45, 82, 73, + 69, 85, 76, 128, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, 76, 217, 73, 69, + 85, 78, 71, 45, 67, 73, 69, 85, 67, 128, 73, 69, 85, 78, 71, 45, 77, 73, + 69, 85, 77, 128, 73, 69, 85, 78, 71, 45, 80, 73, 69, 85, 80, 128, 73, 78, + 84, 69, 71, 82, 65, 84, 73, 79, 78, 128, 73, 78, 84, 69, 82, 67, 65, 76, + 65, 84, 69, 128, 73, 78, 84, 69, 82, 82, 79, 66, 65, 78, 71, 128, 75, 73, + 82, 79, 77, 69, 69, 84, 79, 82, 85, 128, 76, 65, 75, 75, 72, 65, 78, 71, + 89, 65, 79, 128, 77, 73, 69, 85, 77, 45, 72, 73, 69, 85, 72, 128, 77, 73, + 69, 85, 77, 45, 82, 73, 69, 85, 76, 128, 77, 85, 85, 83, 73, 75, 65, 84, + 79, 65, 78, 128, 78, 65, 65, 75, 83, 73, 75, 89, 65, 89, 65, 128, 78, 69, + 66, 69, 78, 83, 84, 73, 77, 77, 69, 128, 78, 73, 69, 85, 78, 45, 80, 73, + 69, 85, 80, 128, 78, 79, 78, 45, 66, 82, 69, 65, 75, 73, 78, 199, 79, 66, + 83, 84, 82, 85, 67, 84, 73, 79, 78, 128, 80, 65, 82, 65, 75, 76, 73, 84, + 73, 75, 73, 128, 80, 69, 78, 69, 84, 82, 65, 84, 73, 79, 78, 128, 80, 69, + 82, 83, 80, 69, 67, 84, 73, 86, 69, 128, 80, 73, 69, 85, 80, 45, 78, 73, + 69, 85, 78, 128, 80, 73, 69, 85, 80, 45, 82, 73, 69, 85, 76, 128, 80, 79, + 83, 84, 80, 79, 83, 73, 84, 73, 79, 206, 80, 82, 69, 83, 67, 82, 73, 80, + 84, 73, 79, 206, 80, 82, 79, 80, 79, 82, 84, 73, 79, 78, 65, 204, 82, 73, + 71, 72, 84, 45, 83, 72, 65, 68, 69, 196, 82, 73, 78, 70, 79, 82, 90, 65, + 78, 68, 79, 128, 82, 79, 85, 78, 68, 45, 84, 73, 80, 80, 69, 196, 83, 65, + 71, 73, 84, 84, 65, 82, 73, 85, 83, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 49, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 52, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 55, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 49, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 49, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 48, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 50, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 50, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 51, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 50, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 50, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 54, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 50, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 50, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 50, 57, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 51, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 51, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 51, 50, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 51, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 51, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 51, 53, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 51, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 51, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 51, 56, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 51, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 52, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 52, 49, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 52, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 52, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 52, 52, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 52, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 52, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 52, 55, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 52, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 52, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 53, 48, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 53, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 53, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 53, 51, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 53, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 53, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 53, 54, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 53, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 53, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 53, 57, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 54, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 54, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 54, 50, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 54, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 54, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 54, 53, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 54, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 54, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 54, 56, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 54, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 55, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 55, 49, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 55, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 55, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 55, 52, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 55, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 55, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 55, 55, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 55, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 55, 57, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 56, 48, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 56, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 56, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 56, 51, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 56, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 56, 53, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 56, 54, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 56, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 56, 56, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 56, 57, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 57, 48, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 57, 49, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 57, 50, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 57, 51, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 57, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 57, 53, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 57, 54, 128, 83, 69, 76, 69, 67, 84, 79, 82, + 45, 57, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 57, 56, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 57, 57, 128, 83, 80, 82, 69, 67, 72, 71, 69, + 83, 65, 78, 199, 83, 85, 80, 69, 82, 73, 77, 80, 79, 83, 69, 196, 84, 69, + 84, 82, 65, 70, 79, 78, 73, 65, 83, 128, 84, 72, 65, 78, 84, 72, 65, 75, + 72, 65, 84, 128, 84, 72, 82, 69, 69, 45, 80, 69, 82, 45, 69, 205, 84, 79, + 65, 78, 68, 65, 75, 72, 73, 65, 84, 128, 84, 82, 65, 78, 83, 77, 73, 83, + 83, 73, 79, 206, 84, 87, 69, 78, 84, 89, 45, 70, 73, 86, 69, 128, 84, 87, + 69, 78, 84, 89, 45, 78, 73, 78, 69, 128, 85, 78, 65, 83, 80, 73, 82, 65, + 84, 69, 68, 128, 67, 73, 82, 67, 85, 77, 70, 76, 69, 88, 128, 83, 85, 80, + 69, 82, 83, 67, 82, 73, 80, 212, 72, 79, 82, 73, 90, 79, 78, 84, 65, 76, + 128, 80, 85, 78, 67, 84, 85, 65, 84, 73, 79, 206, 73, 78, 68, 69, 80, 69, + 78, 68, 69, 78, 212, 80, 69, 82, 73, 83, 80, 79, 77, 69, 78, 201, 69, 88, + 67, 76, 65, 77, 65, 84, 73, 79, 206, 68, 69, 83, 67, 82, 73, 80, 84, 73, + 79, 206, 80, 65, 82, 69, 78, 84, 72, 69, 83, 73, 211, 68, 79, 85, 66, 76, + 69, 45, 76, 73, 78, 197, 77, 65, 72, 65, 65, 80, 82, 65, 65, 78, 193, 65, + 80, 79, 83, 84, 82, 79, 80, 72, 69, 128, 85, 80, 45, 80, 79, 73, 78, 84, + 73, 78, 199, 83, 73, 78, 71, 76, 69, 45, 76, 73, 78, 197, 73, 77, 80, 69, + 82, 70, 69, 67, 84, 85, 205, 82, 73, 71, 72, 84, 87, 65, 82, 68, 83, 128, + 65, 82, 82, 79, 87, 45, 84, 65, 73, 76, 128, 68, 79, 65, 67, 72, 65, 83, + 72, 77, 69, 197, 65, 69, 76, 65, 45, 80, 73, 76, 76, 65, 128, 65, 76, 84, + 69, 82, 78, 65, 84, 73, 86, 197, 67, 79, 77, 80, 76, 69, 84, 73, 79, 78, + 128, 73, 78, 84, 69, 71, 82, 65, 84, 73, 79, 206, 73, 78, 84, 69, 82, 76, + 73, 78, 69, 65, 210, 79, 80, 69, 78, 45, 72, 69, 65, 68, 69, 196, 79, 80, + 80, 79, 83, 73, 84, 73, 79, 78, 128, 82, 73, 69, 85, 76, 45, 83, 73, 79, + 83, 128, 83, 69, 77, 73, 45, 86, 79, 73, 67, 69, 196, 83, 83, 65, 78, 71, + 73, 69, 85, 78, 71, 128, 83, 85, 80, 82, 65, 76, 73, 78, 69, 65, 210, 65, + 69, 68, 65, 45, 80, 73, 76, 76, 65, 128, 67, 79, 78, 83, 69, 67, 85, 84, + 73, 86, 197, 68, 73, 86, 73, 78, 65, 84, 73, 79, 78, 128, 69, 78, 84, 69, + 82, 80, 82, 73, 83, 69, 128, 73, 77, 80, 69, 82, 70, 69, 67, 84, 65, 128, + 77, 79, 78, 79, 70, 79, 78, 73, 65, 83, 128, 77, 79, 78, 79, 71, 82, 65, + 77, 77, 79, 211, 78, 65, 65, 83, 73, 75, 89, 65, 89, 65, 128, 78, 73, 69, + 85, 78, 45, 83, 73, 79, 83, 128, 79, 86, 69, 82, 76, 65, 80, 80, 73, 78, + 199, 80, 65, 82, 65, 75, 65, 76, 69, 83, 77, 193, 80, 65, 82, 65, 75, 76, + 73, 84, 73, 75, 201, 80, 65, 82, 84, 78, 69, 82, 83, 72, 73, 208, 80, 69, + 82, 67, 85, 83, 83, 73, 86, 69, 128, 80, 82, 79, 80, 79, 82, 84, 73, 79, + 78, 128, 82, 69, 67, 84, 65, 78, 71, 85, 76, 65, 210, 82, 69, 67, 84, 73, + 76, 73, 78, 69, 65, 210, 82, 69, 80, 76, 65, 67, 69, 77, 69, 78, 212, 83, + 65, 76, 76, 65, 76, 76, 65, 72, 79, 213, 83, 73, 79, 83, 45, 78, 73, 69, + 85, 78, 128, 83, 73, 79, 83, 45, 82, 73, 69, 85, 76, 128, 83, 83, 65, 78, + 71, 72, 73, 69, 85, 72, 128, 83, 83, 65, 78, 71, 78, 73, 69, 85, 78, 128, + 83, 83, 65, 78, 71, 82, 73, 69, 85, 76, 128, 84, 65, 66, 85, 76, 65, 84, + 73, 79, 78, 128, 84, 69, 84, 82, 65, 83, 73, 77, 79, 85, 128, 84, 72, 69, + 77, 65, 84, 73, 83, 77, 79, 211, 84, 87, 69, 78, 84, 89, 45, 79, 78, 69, + 128, 84, 87, 69, 78, 84, 89, 45, 84, 87, 79, 128, 65, 76, 84, 69, 82, 78, + 65, 84, 73, 79, 206, 65, 78, 71, 75, 72, 65, 78, 75, 72, 85, 128, 65, 78, + 84, 73, 75, 69, 78, 79, 77, 65, 128, 65, 78, 85, 83, 86, 65, 82, 65, 89, + 65, 128, 65, 80, 79, 83, 84, 82, 79, 70, 79, 83, 128, 65, 83, 84, 69, 82, + 73, 83, 67, 85, 83, 128, 65, 85, 82, 65, 77, 65, 90, 68, 65, 65, 128, 66, + 65, 67, 75, 45, 84, 73, 76, 84, 69, 196, 66, 65, 82, 73, 89, 79, 79, 83, + 65, 78, 128, 66, 65, 84, 72, 65, 77, 65, 83, 65, 84, 128, 67, 73, 82, 67, + 85, 76, 65, 84, 73, 79, 206, 67, 76, 85, 66, 45, 83, 80, 79, 75, 69, 196, + 67, 79, 77, 80, 76, 69, 77, 69, 78, 84, 128, 67, 79, 77, 80, 76, 73, 65, + 78, 67, 69, 128, 67, 79, 77, 80, 79, 83, 73, 84, 73, 79, 206, 67, 79, 78, + 84, 69, 78, 84, 73, 79, 78, 128, 67, 79, 82, 82, 69, 83, 80, 79, 78, 68, + 211, 67, 82, 79, 83, 83, 66, 79, 78, 69, 83, 128, 68, 69, 70, 73, 78, 73, + 84, 73, 79, 78, 128, 68, 69, 78, 79, 77, 73, 78, 65, 84, 79, 210, 68, 73, + 65, 69, 82, 69, 83, 73, 90, 69, 196, 68, 73, 77, 69, 78, 83, 73, 79, 78, + 65, 204, 68, 73, 82, 69, 67, 84, 73, 79, 78, 65, 204, 68, 73, 83, 80, 69, + 82, 83, 73, 79, 78, 128, 68, 73, 83, 84, 79, 82, 84, 73, 79, 78, 128, 68, + 73, 86, 69, 82, 71, 69, 78, 67, 69, 128, 68, 79, 84, 83, 45, 49, 50, 51, + 52, 53, 128, 68, 79, 84, 83, 45, 49, 50, 51, 52, 54, 128, 68, 79, 84, 83, + 45, 49, 50, 51, 52, 55, 128, 68, 79, 84, 83, 45, 49, 50, 51, 52, 56, 128, + 68, 79, 84, 83, 45, 49, 50, 51, 53, 54, 128, 68, 79, 84, 83, 45, 49, 50, + 51, 53, 55, 128, 68, 79, 84, 83, 45, 49, 50, 51, 53, 56, 128, 68, 79, 84, + 83, 45, 49, 50, 51, 54, 55, 128, 68, 79, 84, 83, 45, 49, 50, 51, 54, 56, + 128, 68, 79, 84, 83, 45, 49, 50, 51, 55, 56, 128, 68, 79, 84, 83, 45, 49, + 50, 52, 53, 54, 128, 68, 79, 84, 83, 45, 49, 50, 52, 53, 55, 128, 68, 79, + 84, 83, 45, 49, 50, 52, 53, 56, 128, 68, 79, 84, 83, 45, 49, 50, 52, 54, + 55, 128, 68, 79, 84, 83, 45, 49, 50, 52, 54, 56, 128, 68, 79, 84, 83, 45, + 49, 50, 52, 55, 56, 128, 68, 79, 84, 83, 45, 49, 50, 53, 54, 55, 128, 68, + 79, 84, 83, 45, 49, 50, 53, 54, 56, 128, 68, 79, 84, 83, 45, 49, 50, 53, + 55, 56, 128, 68, 79, 84, 83, 45, 49, 50, 54, 55, 56, 128, 68, 79, 84, 83, + 45, 49, 51, 52, 53, 54, 128, 68, 79, 84, 83, 45, 49, 51, 52, 53, 55, 128, + 68, 79, 84, 83, 45, 49, 51, 52, 53, 56, 128, 68, 79, 84, 83, 45, 49, 51, + 52, 54, 55, 128, 68, 79, 84, 83, 45, 49, 51, 52, 54, 56, 128, 68, 79, 84, + 83, 45, 49, 51, 52, 55, 56, 128, 68, 79, 84, 83, 45, 49, 51, 53, 54, 55, + 128, 68, 79, 84, 83, 45, 49, 51, 53, 54, 56, 128, 68, 79, 84, 83, 45, 49, + 51, 53, 55, 56, 128, 68, 79, 84, 83, 45, 49, 51, 54, 55, 56, 128, 68, 79, + 84, 83, 45, 49, 52, 53, 54, 55, 128, 68, 79, 84, 83, 45, 49, 52, 53, 54, + 56, 128, 68, 79, 84, 83, 45, 49, 52, 53, 55, 56, 128, 68, 79, 84, 83, 45, + 49, 52, 54, 55, 56, 128, 68, 79, 84, 83, 45, 49, 53, 54, 55, 56, 128, 68, + 79, 84, 83, 45, 50, 51, 52, 53, 54, 128, 68, 79, 84, 83, 45, 50, 51, 52, + 53, 55, 128, 68, 79, 84, 83, 45, 50, 51, 52, 53, 56, 128, 68, 79, 84, 83, + 45, 50, 51, 52, 54, 55, 128, 68, 79, 84, 83, 45, 50, 51, 52, 54, 56, 128, + 68, 79, 84, 83, 45, 50, 51, 52, 55, 56, 128, 68, 79, 84, 83, 45, 50, 51, + 53, 54, 55, 128, 68, 79, 84, 83, 45, 50, 51, 53, 54, 56, 128, 68, 79, 84, + 83, 45, 50, 51, 53, 55, 56, 128, 68, 79, 84, 83, 45, 50, 51, 54, 55, 56, + 128, 68, 79, 84, 83, 45, 50, 52, 53, 54, 55, 128, 68, 79, 84, 83, 45, 50, + 52, 53, 54, 56, 128, 68, 79, 84, 83, 45, 50, 52, 53, 55, 56, 128, 68, 79, + 84, 83, 45, 50, 52, 54, 55, 56, 128, 68, 79, 84, 83, 45, 50, 53, 54, 55, + 56, 128, 68, 79, 84, 83, 45, 51, 52, 53, 54, 55, 128, 68, 79, 84, 83, 45, + 51, 52, 53, 54, 56, 128, 68, 79, 84, 83, 45, 51, 52, 53, 55, 56, 128, 68, + 79, 84, 83, 45, 51, 52, 54, 55, 56, 128, 68, 79, 84, 83, 45, 51, 53, 54, + 55, 56, 128, 68, 79, 84, 83, 45, 52, 53, 54, 55, 56, 128, 69, 75, 83, 84, + 82, 69, 80, 84, 79, 78, 128, 69, 77, 66, 82, 79, 73, 68, 69, 82, 89, 128, + 69, 78, 67, 79, 85, 78, 84, 69, 82, 83, 128, 69, 78, 84, 72, 85, 83, 73, + 65, 83, 77, 128, 69, 81, 85, 73, 65, 78, 71, 85, 76, 65, 210, 69, 88, 72, + 65, 85, 83, 84, 73, 79, 78, 128, 70, 65, 72, 82, 69, 78, 72, 69, 73, 84, + 128, 70, 69, 76, 76, 79, 87, 83, 72, 73, 80, 128, 70, 79, 82, 77, 65, 84, + 84, 73, 78, 71, 128, 70, 79, 85, 82, 45, 80, 69, 82, 45, 69, 205, 70, 79, + 85, 82, 45, 83, 84, 82, 73, 78, 199, 72, 66, 65, 83, 65, 45, 69, 83, 65, + 83, 193, 72, 79, 77, 79, 84, 72, 69, 84, 73, 67, 128, 72, 89, 80, 72, 69, + 78, 65, 84, 73, 79, 206, 73, 77, 73, 68, 73, 65, 82, 71, 79, 78, 128, 73, + 77, 73, 70, 84, 72, 79, 82, 79, 78, 128, 73, 78, 70, 79, 82, 77, 65, 84, + 73, 79, 206, 73, 78, 84, 69, 82, 76, 79, 67, 75, 69, 196, 75, 73, 82, 79, + 71, 85, 82, 65, 77, 85, 128, 75, 85, 78, 68, 68, 65, 76, 73, 89, 65, 128, + 76, 69, 70, 84, 45, 83, 72, 65, 68, 69, 196, 76, 73, 77, 73, 84, 65, 84, + 73, 79, 78, 128, 77, 69, 77, 66, 69, 82, 83, 72, 73, 80, 128, 78, 65, 78, + 71, 77, 79, 78, 84, 72, 79, 128, 78, 79, 78, 45, 74, 79, 73, 78, 69, 82, + 128, 78, 79, 78, 70, 79, 82, 75, 73, 78, 71, 128, 79, 80, 80, 82, 69, 83, + 83, 73, 79, 78, 128, 80, 65, 76, 65, 84, 65, 76, 73, 90, 69, 196, 80, 65, + 84, 72, 65, 77, 65, 83, 65, 84, 128, 80, 79, 83, 83, 69, 83, 83, 73, 79, + 78, 128, 80, 82, 79, 74, 69, 67, 84, 73, 79, 78, 128, 80, 82, 79, 74, 69, + 67, 84, 73, 86, 69, 128, 82, 65, 68, 73, 79, 65, 67, 84, 73, 86, 197, 82, + 65, 72, 77, 65, 84, 85, 76, 76, 65, 200, 82, 69, 83, 73, 83, 84, 65, 78, + 67, 69, 128, 82, 69, 83, 79, 76, 85, 84, 73, 79, 78, 128, 82, 69, 86, 79, + 76, 85, 84, 73, 79, 78, 128, 83, 65, 67, 82, 73, 70, 73, 67, 73, 65, 204, + 83, 69, 76, 69, 67, 84, 79, 82, 45, 49, 128, 83, 69, 76, 69, 67, 84, 79, + 82, 45, 50, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 51, 128, 83, 69, 76, + 69, 67, 84, 79, 82, 45, 52, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 53, + 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 54, 128, 83, 69, 76, 69, 67, 84, + 79, 82, 45, 55, 128, 83, 69, 76, 69, 67, 84, 79, 82, 45, 56, 128, 83, 69, + 76, 69, 67, 84, 79, 82, 45, 57, 128, 83, 72, 65, 76, 83, 72, 69, 76, 69, + 84, 128, 83, 73, 79, 83, 45, 72, 73, 69, 85, 72, 128, 83, 73, 79, 83, 45, + 73, 69, 85, 78, 71, 128, 83, 73, 79, 83, 45, 77, 73, 69, 85, 77, 128, 83, + 83, 65, 78, 71, 65, 82, 65, 69, 65, 128, 83, 84, 65, 78, 68, 83, 84, 73, + 76, 76, 128, 83, 85, 66, 80, 85, 78, 67, 84, 73, 83, 128, 83, 85, 66, 83, + 84, 73, 84, 85, 84, 69, 128, 83, 89, 78, 67, 72, 82, 79, 78, 79, 85, 211, + 84, 69, 82, 77, 73, 78, 65, 84, 79, 82, 128, 84, 72, 73, 82, 84, 89, 45, + 79, 78, 69, 128, 84, 79, 80, 45, 76, 73, 71, 72, 84, 69, 196, 84, 82, 65, + 78, 83, 86, 69, 82, 83, 65, 204, 84, 87, 69, 78, 84, 89, 45, 83, 73, 88, + 128, 86, 69, 82, 84, 73, 67, 65, 76, 76, 89, 128, 87, 73, 68, 69, 45, 72, + 69, 65, 68, 69, 196, 68, 69, 83, 67, 69, 78, 68, 69, 82, 128, 76, 69, 83, + 83, 45, 84, 72, 65, 78, 128, 65, 78, 78, 79, 84, 65, 84, 73, 79, 206, 69, + 81, 85, 73, 86, 65, 76, 69, 78, 212, 83, 69, 80, 65, 82, 65, 84, 79, 82, + 128, 65, 82, 82, 79, 87, 72, 69, 65, 68, 128, 65, 76, 80, 65, 80, 82, 65, + 65, 78, 193, 68, 79, 87, 78, 87, 65, 82, 68, 83, 128, 69, 88, 84, 69, 78, + 83, 73, 79, 78, 128, 76, 69, 78, 84, 73, 67, 85, 76, 65, 210, 80, 72, 65, + 82, 89, 78, 71, 69, 65, 204, 80, 82, 79, 76, 65, 84, 73, 79, 78, 197, 83, + 69, 77, 73, 67, 79, 76, 79, 78, 128, 84, 85, 82, 78, 83, 84, 73, 76, 69, + 128, 84, 87, 79, 45, 72, 69, 65, 68, 69, 196, 65, 77, 80, 69, 82, 83, 65, + 78, 68, 128, 76, 69, 70, 84, 87, 65, 82, 68, 83, 128, 84, 82, 79, 69, 90, + 69, 78, 73, 65, 206, 67, 79, 77, 77, 69, 82, 67, 73, 65, 204, 83, 69, 77, + 73, 68, 73, 82, 69, 67, 212, 83, 69, 86, 69, 78, 84, 69, 69, 78, 128, 87, + 79, 79, 68, 83, 45, 67, 82, 69, 197, 66, 65, 67, 75, 83, 76, 65, 83, 72, + 128, 68, 73, 65, 76, 89, 84, 73, 75, 65, 128, 69, 88, 84, 82, 65, 45, 72, + 73, 71, 200, 70, 73, 88, 69, 68, 45, 70, 79, 82, 205, 73, 77, 80, 69, 82, + 70, 69, 67, 84, 193, 73, 78, 68, 73, 67, 65, 84, 79, 82, 128, 82, 69, 67, + 84, 65, 78, 71, 76, 69, 128, 86, 69, 82, 84, 73, 67, 65, 76, 76, 217, 67, + 79, 78, 84, 65, 73, 78, 73, 78, 199, 68, 69, 76, 73, 77, 73, 84, 69, 82, + 128, 69, 78, 67, 76, 79, 83, 85, 82, 69, 128, 69, 80, 73, 68, 65, 85, 82, + 69, 65, 206, 72, 69, 82, 77, 73, 79, 78, 73, 65, 206, 72, 79, 85, 82, 71, + 76, 65, 83, 83, 128, 83, 69, 77, 73, 66, 82, 69, 86, 73, 211, 83, 69, 77, + 73, 77, 73, 78, 73, 77, 193, 83, 78, 79, 87, 70, 76, 65, 75, 69, 128, 84, + 82, 73, 65, 78, 71, 85, 76, 65, 210, 65, 80, 79, 83, 84, 82, 79, 70, 79, + 201, 65, 80, 79, 83, 84, 82, 79, 70, 79, 211, 65, 82, 80, 69, 71, 71, 73, + 65, 84, 207, 65, 84, 72, 65, 80, 65, 83, 67, 65, 206, 67, 69, 78, 84, 82, + 69, 76, 73, 78, 197, 67, 72, 65, 82, 65, 67, 84, 69, 82, 128, 67, 79, 80, + 82, 79, 68, 85, 67, 84, 128, 67, 82, 79, 83, 83, 72, 65, 84, 67, 200, 69, + 77, 66, 69, 68, 68, 73, 78, 71, 128, 70, 73, 78, 65, 78, 67, 73, 65, 76, + 128, 70, 79, 76, 76, 79, 87, 73, 78, 71, 128, 70, 82, 69, 84, 66, 79, 65, + 82, 68, 128, 71, 69, 82, 83, 72, 65, 89, 73, 77, 128, 71, 79, 82, 84, 72, + 77, 73, 75, 79, 206, 73, 67, 72, 73, 77, 65, 84, 79, 83, 128, 75, 72, 65, + 75, 65, 83, 83, 73, 65, 206, 80, 65, 65, 45, 80, 73, 76, 76, 65, 128, 80, + 65, 82, 65, 80, 72, 82, 65, 83, 197, 80, 69, 78, 84, 65, 83, 69, 77, 69, + 128, 80, 72, 73, 76, 73, 80, 80, 73, 78, 197, 83, 69, 77, 73, 67, 73, 82, + 67, 76, 197, 83, 85, 77, 77, 65, 84, 73, 79, 78, 128, 83, 85, 80, 69, 82, + 86, 73, 83, 69, 128, 83, 89, 77, 66, 79, 76, 45, 49, 49, 128, 83, 89, 77, + 66, 79, 76, 45, 49, 50, 128, 83, 89, 77, 66, 79, 76, 45, 49, 51, 128, 83, + 89, 77, 66, 79, 76, 45, 49, 52, 128, 83, 89, 77, 66, 79, 76, 45, 49, 55, + 128, 83, 89, 77, 66, 79, 76, 45, 49, 56, 128, 83, 89, 77, 66, 79, 76, 45, + 49, 57, 128, 83, 89, 77, 66, 79, 76, 45, 50, 51, 128, 83, 89, 77, 66, 79, + 76, 45, 50, 52, 128, 83, 89, 77, 66, 79, 76, 45, 53, 48, 128, 83, 89, 77, + 66, 79, 76, 45, 53, 49, 128, 83, 89, 77, 66, 79, 76, 45, 53, 50, 128, 83, + 89, 77, 66, 79, 76, 45, 53, 51, 128, 83, 89, 77, 66, 79, 76, 45, 53, 52, + 128, 84, 69, 76, 69, 80, 72, 79, 78, 69, 128, 84, 69, 84, 82, 65, 83, 69, + 77, 69, 128, 84, 82, 69, 77, 79, 76, 79, 45, 49, 128, 84, 82, 69, 77, 79, + 76, 79, 45, 50, 128, 84, 82, 69, 77, 79, 76, 79, 45, 51, 128, 84, 82, 73, + 71, 82, 65, 77, 77, 79, 211, 84, 82, 79, 75, 85, 84, 65, 83, 84, 201, 65, + 65, 66, 65, 65, 70, 73, 76, 73, 128, 65, 66, 85, 78, 68, 65, 78, 67, 69, + 128, 65, 76, 45, 76, 65, 75, 85, 78, 65, 128, 65, 78, 84, 73, 70, 79, 78, + 73, 65, 128, 65, 80, 80, 82, 79, 65, 67, 72, 69, 211, 65, 82, 45, 82, 65, + 72, 69, 69, 77, 128, 65, 83, 83, 69, 82, 84, 73, 79, 78, 128, 65, 84, 84, + 69, 78, 84, 73, 79, 78, 128, 66, 65, 67, 75, 83, 80, 65, 67, 69, 128, 66, + 69, 71, 73, 78, 78, 73, 78, 71, 128, 66, 73, 66, 76, 69, 45, 67, 82, 69, + 197, 67, 65, 80, 82, 73, 67, 79, 82, 78, 128, 67, 72, 65, 86, 73, 89, 65, + 78, 73, 128, 67, 76, 79, 83, 69, 78, 69, 83, 83, 128, 67, 79, 77, 80, 76, + 69, 84, 69, 68, 128, 67, 79, 78, 83, 84, 65, 78, 67, 89, 128, 67, 79, 80, + 89, 82, 73, 71, 72, 84, 128, 68, 65, 72, 89, 65, 65, 85, 83, 72, 128, 68, + 65, 82, 75, 69, 78, 73, 78, 71, 128, 68, 69, 80, 65, 82, 84, 85, 82, 69, + 128, 68, 69, 83, 67, 69, 78, 68, 73, 78, 199, 68, 73, 70, 70, 69, 82, 69, + 78, 67, 197, 68, 73, 70, 70, 73, 67, 85, 76, 84, 217, 68, 79, 84, 83, 45, + 49, 50, 51, 52, 128, 68, 79, 84, 83, 45, 49, 50, 51, 53, 128, 68, 79, 84, + 83, 45, 49, 50, 51, 54, 128, 68, 79, 84, 83, 45, 49, 50, 51, 55, 128, 68, + 79, 84, 83, 45, 49, 50, 51, 56, 128, 68, 79, 84, 83, 45, 49, 50, 52, 53, + 128, 68, 79, 84, 83, 45, 49, 50, 52, 54, 128, 68, 79, 84, 83, 45, 49, 50, + 52, 55, 128, 68, 79, 84, 83, 45, 49, 50, 52, 56, 128, 68, 79, 84, 83, 45, + 49, 50, 53, 54, 128, 68, 79, 84, 83, 45, 49, 50, 53, 55, 128, 68, 79, 84, + 83, 45, 49, 50, 53, 56, 128, 68, 79, 84, 83, 45, 49, 50, 54, 55, 128, 68, + 79, 84, 83, 45, 49, 50, 54, 56, 128, 68, 79, 84, 83, 45, 49, 50, 55, 56, + 128, 68, 79, 84, 83, 45, 49, 51, 52, 53, 128, 68, 79, 84, 83, 45, 49, 51, + 52, 54, 128, 68, 79, 84, 83, 45, 49, 51, 52, 55, 128, 68, 79, 84, 83, 45, + 49, 51, 52, 56, 128, 68, 79, 84, 83, 45, 49, 51, 53, 54, 128, 68, 79, 84, + 83, 45, 49, 51, 53, 55, 128, 68, 79, 84, 83, 45, 49, 51, 53, 56, 128, 68, + 79, 84, 83, 45, 49, 51, 54, 55, 128, 68, 79, 84, 83, 45, 49, 51, 54, 56, + 128, 68, 79, 84, 83, 45, 49, 51, 55, 56, 128, 68, 79, 84, 83, 45, 49, 52, + 53, 54, 128, 68, 79, 84, 83, 45, 49, 52, 53, 55, 128, 68, 79, 84, 83, 45, + 49, 52, 53, 56, 128, 68, 79, 84, 83, 45, 49, 52, 54, 55, 128, 68, 79, 84, + 83, 45, 49, 52, 54, 56, 128, 68, 79, 84, 83, 45, 49, 52, 55, 56, 128, 68, + 79, 84, 83, 45, 49, 53, 54, 55, 128, 68, 79, 84, 83, 45, 49, 53, 54, 56, + 128, 68, 79, 84, 83, 45, 49, 53, 55, 56, 128, 68, 79, 84, 83, 45, 49, 54, + 55, 56, 128, 68, 79, 84, 83, 45, 50, 51, 52, 53, 128, 68, 79, 84, 83, 45, + 50, 51, 52, 54, 128, 68, 79, 84, 83, 45, 50, 51, 52, 55, 128, 68, 79, 84, + 83, 45, 50, 51, 52, 56, 128, 68, 79, 84, 83, 45, 50, 51, 53, 54, 128, 68, + 79, 84, 83, 45, 50, 51, 53, 55, 128, 68, 79, 84, 83, 45, 50, 51, 53, 56, + 128, 68, 79, 84, 83, 45, 50, 51, 54, 55, 128, 68, 79, 84, 83, 45, 50, 51, + 54, 56, 128, 68, 79, 84, 83, 45, 50, 51, 55, 56, 128, 68, 79, 84, 83, 45, + 50, 52, 53, 54, 128, 68, 79, 84, 83, 45, 50, 52, 53, 55, 128, 68, 79, 84, + 83, 45, 50, 52, 53, 56, 128, 68, 79, 84, 83, 45, 50, 52, 54, 55, 128, 68, + 79, 84, 83, 45, 50, 52, 54, 56, 128, 68, 79, 84, 83, 45, 50, 52, 55, 56, + 128, 68, 79, 84, 83, 45, 50, 53, 54, 55, 128, 68, 79, 84, 83, 45, 50, 53, + 54, 56, 128, 68, 79, 84, 83, 45, 50, 53, 55, 56, 128, 68, 79, 84, 83, 45, + 50, 54, 55, 56, 128, 68, 79, 84, 83, 45, 51, 52, 53, 54, 128, 68, 79, 84, + 83, 45, 51, 52, 53, 55, 128, 68, 79, 84, 83, 45, 51, 52, 53, 56, 128, 68, + 79, 84, 83, 45, 51, 52, 54, 55, 128, 68, 79, 84, 83, 45, 51, 52, 54, 56, + 128, 68, 79, 84, 83, 45, 51, 52, 55, 56, 128, 68, 79, 84, 83, 45, 51, 53, + 54, 55, 128, 68, 79, 84, 83, 45, 51, 53, 54, 56, 128, 68, 79, 84, 83, 45, + 51, 53, 55, 56, 128, 68, 79, 84, 83, 45, 51, 54, 55, 56, 128, 68, 79, 84, + 83, 45, 52, 53, 54, 55, 128, 68, 79, 84, 83, 45, 52, 53, 54, 56, 128, 68, + 79, 84, 83, 45, 52, 53, 55, 56, 128, 68, 79, 84, 83, 45, 52, 54, 55, 56, + 128, 68, 79, 84, 83, 45, 53, 54, 55, 56, 128, 69, 69, 66, 69, 69, 70, 73, + 76, 73, 128, 69, 78, 65, 82, 77, 79, 78, 73, 79, 211, 69, 78, 68, 69, 65, + 86, 79, 85, 82, 128, 69, 78, 68, 79, 70, 79, 78, 79, 78, 128, 69, 83, 84, + 73, 77, 65, 84, 69, 83, 128, 69, 88, 67, 69, 76, 76, 69, 78, 84, 128, 69, + 89, 66, 69, 89, 70, 73, 76, 73, 128, 70, 79, 79, 84, 83, 84, 79, 79, 76, + 128, 70, 79, 83, 84, 69, 82, 73, 78, 71, 128, 70, 82, 73, 67, 65, 84, 73, + 86, 69, 128, 71, 65, 84, 72, 69, 82, 73, 78, 71, 128, 71, 69, 77, 73, 78, + 65, 84, 73, 79, 206, 71, 78, 65, 86, 73, 89, 65, 78, 73, 128, 71, 79, 82, + 71, 79, 84, 69, 82, 73, 128, 71, 82, 69, 65, 84, 78, 69, 83, 83, 128, 71, + 85, 82, 65, 77, 85, 84, 79, 78, 128, 72, 69, 75, 85, 84, 65, 65, 82, 85, + 128, 72, 79, 77, 79, 84, 72, 69, 84, 73, 195, 72, 89, 83, 84, 69, 82, 69, + 83, 73, 211, 73, 76, 85, 85, 89, 65, 78, 78, 65, 128, 73, 77, 73, 70, 84, + 72, 79, 82, 65, 128, 73, 78, 67, 79, 77, 80, 76, 69, 84, 197, 73, 78, 67, + 82, 69, 77, 69, 78, 84, 128, 73, 78, 68, 85, 83, 84, 82, 73, 65, 204, 73, + 78, 70, 76, 85, 69, 78, 67, 69, 128, 73, 78, 78, 79, 67, 69, 78, 67, 69, + 128, 73, 82, 85, 85, 89, 65, 78, 78, 65, 128, 74, 69, 82, 85, 83, 65, 76, + 69, 77, 128, 75, 65, 84, 65, 86, 65, 83, 77, 65, 128, 75, 69, 77, 80, 72, + 82, 69, 78, 71, 128, 75, 69, 78, 84, 73, 77, 65, 84, 65, 128, 75, 73, 82, + 79, 87, 65, 84, 84, 79, 128, 75, 82, 65, 84, 73, 77, 65, 84, 65, 128, 75, + 85, 82, 85, 90, 69, 73, 82, 79, 128, 76, 65, 66, 79, 85, 82, 73, 78, 71, + 128, 76, 72, 65, 86, 73, 89, 65, 78, 73, 128, 76, 73, 71, 72, 84, 78, 73, + 78, 71, 128, 77, 65, 73, 84, 65, 73, 75, 72, 85, 128, 77, 65, 84, 69, 82, + 73, 65, 76, 83, 128, 77, 69, 84, 79, 66, 69, 76, 85, 83, 128, 77, 73, 82, + 73, 66, 65, 65, 82, 85, 128, 77, 79, 78, 79, 83, 84, 65, 66, 76, 197, 77, + 79, 79, 83, 69, 45, 67, 82, 69, 197, 77, 85, 75, 80, 72, 82, 69, 78, 71, + 128, 78, 73, 71, 71, 65, 72, 73, 84, 65, 128, 79, 65, 66, 79, 65, 70, 73, + 76, 73, 128, 79, 79, 66, 79, 79, 70, 73, 76, 73, 128, 79, 82, 84, 72, 79, + 71, 79, 78, 65, 204, 80, 65, 73, 89, 65, 78, 78, 79, 73, 128, 80, 65, 82, + 65, 71, 82, 65, 80, 72, 128, 80, 73, 65, 83, 85, 84, 79, 82, 85, 128, 80, + 73, 84, 67, 72, 70, 79, 82, 75, 128, 80, 73, 90, 90, 73, 67, 65, 84, 79, + 128, 80, 76, 85, 83, 45, 77, 73, 78, 85, 211, 80, 79, 82, 82, 69, 67, 84, + 85, 83, 128, 80, 82, 65, 77, 45, 66, 85, 79, 78, 128, 80, 82, 65, 77, 45, + 77, 85, 79, 89, 128, 80, 82, 79, 84, 79, 86, 65, 82, 89, 211, 81, 85, 65, + 84, 69, 82, 78, 73, 79, 206, 81, 85, 69, 83, 84, 73, 79, 78, 69, 196, 81, + 85, 83, 72, 83, 72, 65, 89, 65, 128, 82, 69, 71, 73, 83, 84, 69, 82, 69, + 196, 82, 69, 76, 65, 84, 73, 79, 78, 65, 204, 82, 69, 80, 82, 69, 83, 69, + 78, 84, 128, 82, 69, 83, 73, 68, 69, 78, 67, 69, 128, 82, 69, 83, 85, 80, + 73, 78, 85, 83, 128, 82, 73, 71, 72, 84, 45, 83, 73, 68, 197, 83, 67, 65, + 78, 68, 73, 67, 85, 83, 128, 83, 69, 80, 84, 69, 77, 66, 69, 82, 128, 83, + 69, 86, 69, 82, 65, 78, 67, 69, 128, 83, 72, 65, 86, 73, 89, 65, 78, 73, + 128, 83, 72, 79, 82, 84, 69, 78, 69, 82, 128, 83, 72, 79, 85, 76, 68, 69, + 82, 69, 196, 83, 73, 88, 45, 80, 69, 82, 45, 69, 205, 83, 73, 88, 45, 83, + 84, 82, 73, 78, 199, 83, 84, 82, 79, 75, 69, 45, 49, 48, 128, 83, 84, 82, + 79, 75, 69, 45, 49, 49, 128, 83, 85, 66, 83, 84, 73, 84, 85, 84, 197, 83, + 85, 83, 80, 69, 78, 83, 73, 79, 206, 83, 89, 77, 66, 79, 76, 45, 49, 48, + 128, 83, 89, 77, 66, 79, 76, 45, 49, 53, 128, 83, 89, 77, 66, 79, 76, 45, + 49, 54, 128, 83, 89, 77, 66, 79, 76, 45, 50, 48, 128, 83, 89, 77, 66, 79, + 76, 45, 50, 49, 128, 83, 89, 77, 66, 79, 76, 45, 50, 50, 128, 83, 89, 77, + 66, 79, 76, 45, 50, 53, 128, 83, 89, 77, 66, 79, 76, 45, 50, 54, 128, 83, + 89, 77, 66, 79, 76, 45, 50, 55, 128, 83, 89, 77, 66, 79, 76, 45, 50, 57, + 128, 83, 89, 77, 66, 79, 76, 45, 51, 48, 128, 83, 89, 77, 66, 79, 76, 45, + 51, 50, 128, 83, 89, 77, 66, 79, 76, 45, 51, 54, 128, 83, 89, 77, 66, 79, + 76, 45, 51, 55, 128, 83, 89, 77, 66, 79, 76, 45, 51, 56, 128, 83, 89, 77, + 66, 79, 76, 45, 51, 57, 128, 83, 89, 77, 66, 79, 76, 45, 52, 48, 128, 83, + 89, 77, 66, 79, 76, 45, 52, 50, 128, 83, 89, 77, 66, 79, 76, 45, 52, 51, + 128, 83, 89, 77, 66, 79, 76, 45, 52, 53, 128, 83, 89, 77, 66, 79, 76, 45, + 52, 55, 128, 83, 89, 77, 66, 79, 76, 45, 52, 56, 128, 83, 89, 77, 66, 79, + 76, 45, 52, 57, 128, 83, 89, 82, 77, 65, 84, 73, 75, 73, 128, 84, 65, 75, + 72, 65, 76, 76, 85, 83, 128, 84, 65, 87, 69, 76, 76, 69, 77, 69, 212, 84, + 72, 69, 82, 69, 70, 79, 82, 69, 128, 84, 72, 82, 69, 69, 45, 76, 73, 78, + 197, 84, 82, 73, 70, 79, 76, 73, 65, 84, 197, 84, 82, 73, 70, 79, 78, 73, + 65, 83, 128, 84, 82, 73, 71, 79, 82, 71, 79, 78, 128, 84, 85, 84, 69, 89, + 65, 83, 65, 84, 128, 86, 73, 83, 65, 82, 71, 65, 89, 65, 128, 87, 65, 83, + 83, 65, 76, 76, 65, 77, 128, 87, 72, 69, 69, 76, 67, 72, 65, 73, 210, 87, + 79, 82, 68, 83, 80, 65, 67, 69, 128, 89, 80, 79, 75, 82, 73, 83, 73, 83, + 128, 76, 69, 83, 83, 45, 84, 72, 65, 206, 68, 79, 87, 78, 87, 65, 82, 68, + 211, 84, 82, 73, 65, 78, 71, 76, 69, 128, 79, 80, 69, 82, 65, 84, 79, 82, + 128, 83, 85, 66, 83, 67, 82, 73, 80, 212, 84, 72, 79, 85, 83, 65, 78, 68, + 128, 85, 78, 68, 69, 82, 66, 65, 82, 128, 81, 85, 79, 84, 65, 84, 73, 79, + 206, 65, 83, 84, 69, 82, 73, 83, 75, 128, 79, 82, 78, 65, 77, 69, 78, 84, + 128, 82, 69, 84, 82, 79, 70, 76, 69, 216, 65, 82, 67, 72, 65, 73, 79, 78, + 128, 68, 73, 65, 69, 82, 69, 83, 73, 211, 66, 76, 65, 67, 75, 70, 79, 79, + 212, 68, 69, 78, 84, 73, 83, 84, 82, 217, 68, 73, 65, 76, 89, 84, 73, 75, + 193, 73, 78, 84, 69, 71, 82, 65, 76, 128, 65, 78, 85, 83, 86, 65, 82, 65, + 128, 86, 69, 82, 84, 73, 67, 65, 76, 128, 76, 69, 70, 84, 45, 83, 84, 69, + 205, 82, 69, 67, 89, 67, 76, 73, 78, 199, 65, 66, 75, 72, 65, 83, 73, 65, + 206, 68, 73, 65, 76, 69, 67, 84, 45, 208, 68, 79, 68, 69, 75, 65, 84, 65, + 128, 69, 76, 76, 73, 80, 83, 73, 83, 128, 81, 85, 65, 68, 82, 65, 78, 84, + 128, 81, 85, 65, 68, 82, 85, 80, 76, 197, 68, 73, 65, 84, 79, 78, 73, 75, + 201, 69, 78, 67, 76, 79, 83, 73, 78, 199, 79, 86, 69, 82, 76, 73, 78, 69, + 128, 80, 76, 65, 83, 84, 73, 67, 83, 128, 65, 82, 82, 79, 87, 72, 69, 65, + 196, 73, 84, 69, 82, 65, 84, 73, 79, 206, 78, 79, 84, 69, 72, 69, 65, 68, + 128, 78, 85, 77, 69, 82, 65, 84, 79, 210, 65, 86, 65, 71, 82, 65, 72, 65, + 128, 69, 73, 71, 72, 84, 69, 69, 78, 128, 70, 79, 85, 82, 84, 69, 69, 78, + 128, 78, 73, 78, 69, 84, 69, 69, 78, 128, 83, 85, 80, 69, 82, 83, 69, 84, + 128, 84, 72, 73, 82, 84, 69, 69, 78, 128, 68, 73, 65, 71, 79, 78, 65, 76, + 128, 69, 88, 84, 82, 65, 45, 76, 79, 215, 70, 76, 79, 82, 69, 84, 84, 69, + 128, 73, 68, 69, 78, 84, 73, 67, 65, 204, 75, 69, 78, 84, 73, 77, 65, 84, + 193, 80, 65, 82, 65, 71, 82, 65, 80, 200, 82, 69, 76, 65, 84, 73, 79, 78, + 128, 83, 67, 73, 83, 83, 79, 82, 83, 128, 83, 69, 66, 65, 84, 66, 69, 73, + 212, 83, 69, 80, 65, 82, 65, 84, 79, 210, 65, 76, 84, 69, 82, 78, 65, 84, + 197, 68, 68, 65, 89, 65, 78, 78, 65, 128, 68, 69, 80, 65, 82, 84, 73, 78, + 199, 70, 65, 78, 69, 82, 79, 83, 73, 211, 70, 73, 83, 72, 72, 79, 79, 75, + 128, 73, 78, 70, 73, 78, 73, 84, 89, 128, 77, 79, 85, 78, 84, 65, 73, 78, + 128, 77, 85, 76, 84, 73, 77, 65, 80, 128, 77, 85, 85, 82, 68, 72, 65, 74, + 193, 80, 65, 82, 65, 76, 76, 69, 76, 128, 80, 82, 69, 67, 69, 68, 69, 83, + 128, 83, 73, 88, 84, 69, 69, 78, 84, 200, 83, 80, 72, 69, 82, 73, 67, 65, + 204, 83, 85, 66, 76, 73, 78, 69, 65, 210, 83, 85, 67, 67, 69, 69, 68, 83, + 128, 83, 85, 77, 77, 65, 84, 73, 79, 206, 84, 69, 76, 69, 80, 72, 79, 78, + 197, 84, 72, 79, 85, 83, 65, 78, 68, 211, 89, 69, 83, 73, 69, 85, 78, 71, + 128, 65, 76, 76, 73, 65, 78, 67, 69, 128, 67, 65, 85, 76, 68, 82, 79, 78, + 128, 67, 79, 78, 83, 84, 65, 78, 84, 128, 68, 73, 70, 79, 78, 73, 65, 83, + 128, 68, 73, 71, 82, 65, 77, 77, 79, 211, 68, 82, 65, 67, 72, 77, 65, 83, + 128, 70, 76, 65, 84, 84, 69, 78, 69, 196, 71, 65, 82, 83, 72, 85, 78, 73, + 128, 71, 65, 84, 72, 69, 82, 73, 78, 199, 71, 76, 73, 83, 83, 65, 78, 68, + 207, 71, 82, 69, 71, 79, 82, 73, 65, 206, 73, 78, 67, 82, 69, 65, 83, 69, + 128, 73, 78, 83, 69, 82, 84, 73, 79, 206, 73, 78, 86, 73, 83, 73, 66, 76, + 197, 73, 83, 45, 80, 73, 76, 76, 65, 128, 79, 86, 69, 82, 82, 73, 68, 69, + 128, 79, 89, 82, 65, 78, 73, 83, 77, 193, 80, 69, 68, 69, 83, 84, 65, 76, + 128, 80, 78, 69, 85, 77, 65, 84, 65, 128, 80, 82, 65, 77, 45, 66, 85, 79, + 206, 80, 82, 65, 77, 45, 77, 85, 79, 217, 80, 82, 79, 76, 79, 78, 71, 69, + 196, 80, 82, 79, 80, 69, 76, 76, 69, 210, 82, 69, 83, 79, 85, 82, 67, 69, + 128, 82, 69, 83, 80, 79, 78, 83, 69, 128, 82, 69, 86, 69, 82, 83, 69, 68, + 128, 83, 69, 77, 73, 86, 79, 87, 69, 204, 83, 85, 66, 71, 82, 79, 85, 80, + 128, 83, 87, 65, 80, 80, 73, 78, 71, 128, 83, 89, 77, 66, 79, 76, 45, 49, + 128, 83, 89, 77, 66, 79, 76, 45, 50, 128, 83, 89, 77, 66, 79, 76, 45, 52, + 128, 83, 89, 77, 66, 79, 76, 45, 53, 128, 83, 89, 77, 66, 79, 76, 45, 55, + 128, 83, 89, 77, 66, 79, 76, 45, 56, 128, 83, 89, 77, 77, 69, 84, 82, 73, + 195, 84, 79, 71, 69, 84, 72, 69, 82, 128, 84, 82, 73, 83, 73, 77, 79, 85, + 128, 84, 84, 65, 89, 65, 78, 78, 65, 128, 85, 78, 68, 69, 82, 76, 73, 78, + 197, 85, 78, 68, 69, 82, 84, 73, 69, 128, 85, 78, 73, 86, 69, 82, 83, 65, + 204, 65, 68, 68, 82, 69, 83, 83, 69, 196, 65, 69, 69, 89, 65, 78, 78, 65, + 128, 65, 73, 82, 80, 76, 65, 78, 69, 128, 65, 78, 85, 68, 65, 84, 84, 65, + 128, 65, 80, 79, 68, 69, 88, 73, 65, 128, 65, 80, 79, 84, 72, 69, 77, 65, + 128, 65, 80, 80, 82, 79, 65, 67, 72, 128, 65, 81, 85, 65, 82, 73, 85, 83, + 128, 65, 82, 45, 82, 65, 72, 77, 65, 206, 65, 82, 65, 69, 65, 45, 69, 79, + 128, 65, 82, 71, 79, 84, 69, 82, 73, 128, 65, 82, 73, 83, 84, 69, 82, 65, + 128, 65, 83, 67, 69, 78, 68, 73, 78, 199, 65, 83, 84, 69, 82, 73, 83, 75, + 211, 65, 83, 84, 69, 82, 73, 83, 77, 128, 65, 84, 84, 72, 65, 67, 65, 78, + 128, 66, 65, 67, 75, 83, 76, 65, 83, 200, 66, 69, 86, 69, 82, 65, 71, 69, + 128, 66, 73, 79, 72, 65, 90, 65, 82, 196, 66, 73, 83, 69, 67, 84, 73, 78, + 199, 66, 73, 83, 77, 73, 76, 76, 65, 200, 66, 82, 65, 78, 67, 72, 73, 78, + 199, 66, 85, 76, 76, 83, 69, 89, 69, 128, 66, 85, 83, 83, 89, 69, 82, 85, + 128, 67, 65, 68, 85, 67, 69, 85, 83, 128, 67, 65, 82, 89, 83, 84, 73, 65, + 206, 67, 72, 65, 77, 73, 76, 79, 78, 128, 67, 72, 65, 84, 84, 65, 87, 65, + 128, 67, 73, 86, 73, 76, 73, 65, 78, 128, 67, 76, 73, 77, 65, 67, 85, 83, + 128, 67, 79, 78, 70, 76, 73, 67, 84, 128, 67, 79, 78, 71, 82, 85, 69, 78, + 212, 67, 79, 78, 74, 85, 71, 65, 84, 197, 67, 79, 78, 84, 79, 85, 82, 69, + 196, 67, 79, 80, 89, 82, 73, 71, 72, 212, 67, 82, 69, 83, 67, 69, 78, 84, + 128, 68, 65, 77, 77, 65, 84, 65, 78, 128, 68, 65, 82, 75, 69, 78, 73, 78, + 199, 68, 65, 86, 73, 89, 65, 78, 73, 128, 68, 69, 67, 69, 77, 66, 69, 82, + 128, 68, 69, 67, 82, 69, 65, 83, 69, 128, 68, 69, 76, 73, 77, 73, 84, 69, + 210, 68, 73, 70, 84, 79, 71, 71, 79, 211, 68, 73, 71, 79, 82, 71, 79, 78, + 128, 68, 73, 77, 69, 78, 83, 73, 79, 206, 68, 79, 84, 83, 45, 49, 50, 51, + 128, 68, 79, 84, 83, 45, 49, 50, 52, 128, 68, 79, 84, 83, 45, 49, 50, 53, + 128, 68, 79, 84, 83, 45, 49, 50, 54, 128, 68, 79, 84, 83, 45, 49, 50, 55, + 128, 68, 79, 84, 83, 45, 49, 50, 56, 128, 68, 79, 84, 83, 45, 49, 51, 52, + 128, 68, 79, 84, 83, 45, 49, 51, 53, 128, 68, 79, 84, 83, 45, 49, 51, 54, + 128, 68, 79, 84, 83, 45, 49, 51, 55, 128, 68, 79, 84, 83, 45, 49, 51, 56, + 128, 68, 79, 84, 83, 45, 49, 52, 53, 128, 68, 79, 84, 83, 45, 49, 52, 54, + 128, 68, 79, 84, 83, 45, 49, 52, 55, 128, 68, 79, 84, 83, 45, 49, 52, 56, + 128, 68, 79, 84, 83, 45, 49, 53, 54, 128, 68, 79, 84, 83, 45, 49, 53, 55, + 128, 68, 79, 84, 83, 45, 49, 53, 56, 128, 68, 79, 84, 83, 45, 49, 54, 55, + 128, 68, 79, 84, 83, 45, 49, 54, 56, 128, 68, 79, 84, 83, 45, 49, 55, 56, + 128, 68, 79, 84, 83, 45, 50, 51, 52, 128, 68, 79, 84, 83, 45, 50, 51, 53, + 128, 68, 79, 84, 83, 45, 50, 51, 54, 128, 68, 79, 84, 83, 45, 50, 51, 55, + 128, 68, 79, 84, 83, 45, 50, 51, 56, 128, 68, 79, 84, 83, 45, 50, 52, 53, + 128, 68, 79, 84, 83, 45, 50, 52, 54, 128, 68, 79, 84, 83, 45, 50, 52, 55, + 128, 68, 79, 84, 83, 45, 50, 52, 56, 128, 68, 79, 84, 83, 45, 50, 53, 54, + 128, 68, 79, 84, 83, 45, 50, 53, 55, 128, 68, 79, 84, 83, 45, 50, 53, 56, + 128, 68, 79, 84, 83, 45, 50, 54, 55, 128, 68, 79, 84, 83, 45, 50, 54, 56, + 128, 68, 79, 84, 83, 45, 50, 55, 56, 128, 68, 79, 84, 83, 45, 51, 52, 53, + 128, 68, 79, 84, 83, 45, 51, 52, 54, 128, 68, 79, 84, 83, 45, 51, 52, 55, + 128, 68, 79, 84, 83, 45, 51, 52, 56, 128, 68, 79, 84, 83, 45, 51, 53, 54, + 128, 68, 79, 84, 83, 45, 51, 53, 55, 128, 68, 79, 84, 83, 45, 51, 53, 56, + 128, 68, 79, 84, 83, 45, 51, 54, 55, 128, 68, 79, 84, 83, 45, 51, 54, 56, + 128, 68, 79, 84, 83, 45, 51, 55, 56, 128, 68, 79, 84, 83, 45, 52, 53, 54, + 128, 68, 79, 84, 83, 45, 52, 53, 55, 128, 68, 79, 84, 83, 45, 52, 53, 56, + 128, 68, 79, 84, 83, 45, 52, 54, 55, 128, 68, 79, 84, 83, 45, 52, 54, 56, + 128, 68, 79, 84, 83, 45, 52, 55, 56, 128, 68, 79, 84, 83, 45, 53, 54, 55, + 128, 68, 79, 84, 83, 45, 53, 54, 56, 128, 68, 79, 84, 83, 45, 53, 55, 56, + 128, 68, 79, 84, 83, 45, 54, 55, 56, 128, 68, 79, 84, 84, 69, 68, 45, 76, + 128, 68, 79, 84, 84, 69, 68, 45, 78, 128, 68, 79, 84, 84, 69, 68, 45, 80, + 128, 68, 85, 82, 65, 84, 73, 79, 78, 128, 68, 86, 73, 83, 86, 65, 82, 65, + 128, 69, 68, 73, 84, 79, 82, 73, 65, 204, 69, 78, 86, 69, 76, 79, 80, 69, + 128, 69, 80, 69, 71, 69, 82, 77, 65, 128, 69, 83, 84, 73, 77, 65, 84, 69, + 196, 69, 83, 85, 75, 85, 85, 68, 79, 128, 69, 84, 69, 82, 78, 73, 84, 89, + 128, 70, 65, 67, 83, 73, 77, 73, 76, 197, 70, 65, 84, 72, 65, 84, 65, 78, + 128, 70, 69, 66, 82, 85, 65, 82, 89, 128, 70, 69, 83, 84, 73, 86, 65, 76, + 128, 70, 73, 71, 85, 82, 69, 45, 49, 128, 70, 73, 71, 85, 82, 69, 45, 50, + 128, 70, 73, 71, 85, 82, 69, 45, 51, 128, 70, 73, 86, 69, 45, 76, 73, 78, + 197, 70, 79, 85, 82, 45, 76, 73, 78, 197, 70, 82, 65, 71, 77, 69, 78, 84, + 128, 70, 82, 65, 71, 82, 65, 78, 84, 128, 70, 85, 76, 76, 78, 69, 83, 83, + 128, 70, 85, 78, 67, 84, 73, 79, 78, 128, 71, 69, 78, 73, 84, 73, 86, 69, + 128, 71, 69, 79, 77, 69, 84, 82, 73, 195, 72, 65, 78, 45, 65, 75, 65, 84, + 128, 72, 65, 82, 68, 78, 69, 83, 83, 128, 72, 65, 82, 77, 79, 78, 73, 67, + 128, 72, 69, 82, 77, 73, 84, 73, 65, 206, 72, 85, 65, 82, 65, 68, 68, 79, + 128, 73, 76, 85, 89, 65, 78, 78, 65, 128, 73, 77, 73, 70, 79, 78, 79, 78, + 128, 73, 78, 67, 76, 85, 68, 73, 78, 199, 73, 78, 67, 82, 69, 65, 83, 69, + 211, 73, 82, 85, 89, 65, 78, 78, 65, 128, 74, 65, 86, 73, 89, 65, 78, 73, + 128, 75, 65, 83, 82, 65, 84, 65, 78, 128, 75, 65, 84, 72, 73, 83, 84, 73, + 128, 75, 69, 89, 66, 79, 65, 82, 68, 128, 75, 79, 78, 84, 69, 86, 77, 65, + 128, 75, 82, 69, 77, 65, 83, 84, 73, 128, 76, 65, 82, 89, 78, 71, 69, 65, + 204, 76, 69, 70, 84, 45, 83, 73, 68, 197, 76, 73, 65, 66, 73, 76, 73, 84, + 217, 76, 79, 67, 65, 84, 73, 86, 69, 128, 76, 79, 82, 82, 65, 73, 78, 69, + 128, 77, 65, 72, 65, 80, 65, 75, 72, 128, 77, 65, 73, 77, 65, 76, 65, 73, + 128, 77, 65, 73, 89, 65, 77, 79, 75, 128, 77, 65, 78, 71, 65, 76, 65, 77, + 128, 77, 65, 83, 67, 85, 76, 73, 78, 197, 77, 69, 68, 73, 67, 73, 78, 69, + 128, 77, 69, 83, 83, 69, 78, 73, 65, 206, 77, 73, 78, 73, 83, 84, 69, 82, + 128, 77, 85, 76, 84, 73, 83, 69, 84, 128, 78, 73, 75, 72, 65, 72, 73, 84, + 128, 78, 79, 82, 84, 72, 87, 69, 83, 212, 78, 79, 86, 69, 77, 66, 69, 82, + 128, 79, 86, 69, 82, 76, 65, 73, 68, 128, 80, 65, 65, 83, 69, 78, 84, 79, + 128, 80, 65, 73, 82, 84, 72, 82, 65, 128, 80, 65, 76, 79, 67, 72, 75, 65, + 128, 80, 65, 77, 85, 68, 80, 79, 68, 128, 80, 65, 82, 73, 67, 72, 79, 78, + 128, 80, 65, 86, 73, 89, 65, 78, 73, 128, 80, 69, 76, 65, 83, 84, 79, 78, + 128, 80, 69, 82, 77, 65, 78, 69, 78, 212, 80, 73, 84, 67, 72, 70, 79, 82, + 203, 80, 76, 69, 84, 72, 82, 79, 78, 128, 80, 79, 82, 82, 69, 67, 84, 85, + 211, 80, 82, 65, 77, 45, 66, 69, 73, 128, 80, 82, 65, 77, 45, 80, 73, 73, + 128, 80, 82, 79, 70, 79, 85, 78, 68, 128, 80, 82, 79, 71, 82, 69, 83, 83, + 128, 80, 83, 73, 70, 73, 83, 84, 79, 206, 81, 65, 73, 82, 84, 72, 82, 65, + 128, 81, 85, 65, 82, 84, 69, 82, 83, 128, 81, 85, 69, 83, 84, 73, 79, 78, + 128, 82, 69, 67, 69, 80, 84, 73, 86, 197, 82, 69, 67, 79, 82, 68, 69, 82, + 128, 82, 69, 67, 79, 82, 68, 73, 78, 199, 82, 69, 67, 84, 65, 78, 71, 76, + 197, 82, 69, 70, 69, 82, 69, 78, 67, 197, 82, 69, 76, 73, 71, 73, 79, 78, + 128, 82, 69, 78, 84, 79, 71, 69, 78, 128, 82, 73, 71, 72, 84, 72, 65, 78, + 196, 82, 85, 75, 75, 65, 75, 72, 65, 128, 83, 65, 78, 84, 73, 73, 77, 85, + 128, 83, 65, 88, 73, 77, 65, 84, 65, 128, 83, 67, 65, 78, 68, 73, 67, 85, + 211, 83, 67, 79, 82, 80, 73, 85, 83, 128, 83, 69, 77, 73, 67, 79, 76, 79, + 206, 83, 69, 86, 69, 78, 84, 69, 69, 206, 83, 72, 65, 77, 82, 79, 67, 75, + 128, 83, 72, 69, 45, 71, 79, 65, 84, 128, 83, 73, 67, 75, 78, 69, 83, 83, + 128, 83, 80, 76, 73, 84, 84, 73, 78, 199, 83, 84, 65, 76, 76, 73, 79, 78, + 128, 83, 84, 79, 80, 80, 65, 71, 69, 128, 83, 84, 79, 80, 80, 73, 78, 71, + 128, 83, 84, 82, 69, 78, 71, 84, 72, 128, 83, 84, 82, 69, 84, 67, 72, 69, + 196, 83, 84, 82, 79, 75, 69, 45, 49, 128, 83, 84, 82, 79, 75, 69, 45, 50, + 128, 83, 84, 82, 79, 75, 69, 45, 51, 128, 83, 84, 82, 79, 75, 69, 45, 52, + 128, 83, 84, 82, 79, 75, 69, 45, 53, 128, 83, 84, 82, 79, 75, 69, 45, 54, + 128, 83, 84, 82, 79, 75, 69, 45, 55, 128, 83, 84, 82, 79, 75, 69, 45, 56, + 128, 83, 84, 82, 79, 75, 69, 45, 57, 128, 83, 85, 73, 84, 65, 66, 76, 69, + 128, 83, 85, 82, 82, 79, 85, 78, 68, 128, 83, 89, 77, 66, 79, 76, 45, 51, + 128, 83, 89, 77, 66, 79, 76, 45, 54, 128, 83, 89, 77, 66, 79, 76, 45, 57, + 128, 83, 89, 77, 77, 69, 84, 82, 89, 128, 83, 89, 78, 68, 69, 83, 77, 79, + 211, 84, 65, 86, 73, 89, 65, 78, 73, 128, 84, 69, 84, 82, 65, 80, 76, 73, + 128, 84, 79, 82, 67, 85, 76, 85, 83, 128, 84, 82, 69, 65, 68, 73, 78, 71, + 128, 84, 82, 73, 67, 79, 76, 79, 78, 128, 84, 82, 79, 77, 73, 75, 79, 78, + 128, 84, 82, 85, 78, 67, 65, 84, 69, 196, 85, 73, 76, 76, 69, 65, 78, 78, + 128, 85, 77, 66, 82, 69, 76, 76, 65, 128, 85, 78, 68, 69, 82, 68, 79, 84, + 128, 85, 78, 77, 65, 82, 82, 73, 69, 196, 86, 69, 82, 83, 73, 67, 76, 69, + 128, 87, 65, 78, 68, 69, 82, 69, 82, 128, 87, 65, 83, 65, 76, 76, 65, 77, + 128, 89, 65, 77, 65, 75, 75, 65, 78, 128, 89, 80, 79, 75, 82, 73, 83, 73, + 211, 90, 65, 86, 73, 89, 65, 78, 73, 128, 90, 87, 65, 82, 65, 75, 65, 89, + 128, 73, 78, 86, 69, 82, 84, 69, 196, 78, 69, 71, 65, 84, 73, 86, 197, + 85, 71, 65, 82, 73, 84, 73, 195, 66, 85, 71, 73, 78, 69, 83, 197, 72, 85, + 78, 68, 82, 69, 68, 128, 67, 69, 68, 73, 76, 76, 65, 128, 84, 82, 73, 65, + 78, 71, 76, 197, 78, 79, 84, 69, 72, 69, 65, 196, 83, 85, 80, 69, 82, 83, + 69, 212, 70, 82, 65, 67, 84, 73, 79, 206, 81, 85, 69, 83, 84, 73, 79, + 206, 84, 65, 71, 66, 65, 78, 87, 193, 81, 85, 65, 68, 82, 65, 78, 212, + 68, 73, 65, 71, 79, 78, 65, 204, 85, 80, 83, 73, 76, 79, 78, 128, 79, 86, + 69, 82, 76, 65, 89, 128, 77, 65, 82, 84, 89, 82, 73, 193, 79, 86, 69, 82, + 66, 65, 82, 128, 68, 73, 65, 77, 79, 78, 68, 128, 69, 80, 83, 73, 76, 79, + 78, 128, 72, 65, 78, 71, 90, 72, 79, 213, 73, 78, 84, 69, 71, 82, 65, + 204, 77, 69, 65, 83, 85, 82, 69, 196, 79, 77, 73, 67, 82, 79, 78, 128, + 84, 79, 82, 84, 79, 73, 83, 197, 79, 82, 78, 65, 77, 69, 78, 212, 86, 73, + 83, 65, 82, 71, 65, 128, 69, 88, 84, 69, 78, 68, 69, 196, 72, 65, 82, 80, + 79, 79, 78, 128, 80, 82, 69, 67, 69, 68, 69, 211, 83, 79, 76, 73, 68, 85, + 83, 128, 83, 85, 67, 67, 69, 69, 68, 211, 84, 72, 69, 83, 80, 73, 65, + 206, 67, 79, 78, 84, 65, 73, 78, 211, 68, 73, 71, 82, 65, 80, 72, 128, + 77, 69, 84, 82, 73, 67, 65, 204, 77, 79, 78, 79, 71, 82, 65, 205, 67, 82, + 79, 83, 83, 73, 78, 199, 83, 73, 77, 65, 78, 83, 73, 211, 83, 84, 65, 84, + 69, 82, 83, 128, 83, 85, 66, 85, 78, 73, 84, 128, 83, 73, 68, 69, 87, 65, + 89, 211, 83, 81, 85, 65, 82, 69, 68, 128, 84, 65, 76, 69, 78, 84, 83, + 128, 84, 72, 79, 85, 83, 65, 78, 196, 66, 65, 82, 76, 73, 78, 69, 128, + 68, 73, 86, 73, 83, 73, 79, 206, 73, 79, 84, 73, 70, 73, 69, 196, 80, 65, + 82, 65, 76, 76, 69, 204, 83, 73, 88, 84, 69, 69, 78, 128, 83, 85, 66, 71, + 82, 79, 85, 208, 83, 85, 82, 82, 79, 85, 78, 196, 85, 80, 87, 65, 82, 68, + 83, 128, 70, 73, 70, 84, 69, 69, 78, 128, 79, 80, 69, 82, 65, 84, 79, + 210, 79, 82, 73, 71, 73, 78, 65, 204, 68, 73, 65, 83, 84, 79, 76, 201, + 68, 73, 86, 73, 68, 69, 82, 128, 70, 65, 84, 72, 65, 84, 65, 206, 73, 90, + 72, 73, 84, 83, 65, 128, 77, 89, 83, 76, 73, 84, 69, 128, 80, 79, 73, 78, + 84, 69, 82, 128, 83, 84, 82, 65, 73, 71, 72, 212, 65, 83, 84, 69, 82, 73, + 83, 203, 66, 65, 89, 65, 78, 78, 65, 128, 67, 72, 82, 79, 78, 79, 78, + 128, 68, 73, 71, 79, 82, 71, 79, 206, 69, 73, 71, 72, 84, 72, 83, 128, + 70, 73, 78, 71, 69, 82, 69, 196, 71, 65, 89, 65, 78, 78, 65, 128, 72, 65, + 82, 75, 76, 69, 65, 206, 74, 65, 89, 65, 78, 78, 65, 128, 75, 79, 82, 79, + 78, 73, 83, 128, 76, 69, 65, 84, 72, 69, 82, 128, 76, 79, 90, 69, 78, 71, + 69, 128, 77, 65, 75, 83, 85, 82, 65, 128, 78, 79, 45, 66, 82, 69, 65, + 203, 80, 73, 78, 87, 72, 69, 69, 204, 81, 85, 65, 82, 84, 69, 82, 211, + 82, 69, 80, 69, 65, 84, 69, 196, 83, 65, 89, 65, 78, 78, 65, 128, 83, 69, + 76, 69, 67, 84, 79, 210, 83, 81, 85, 73, 71, 71, 76, 197, 84, 69, 84, 65, + 82, 84, 79, 211, 84, 82, 79, 77, 73, 75, 79, 206, 65, 67, 84, 73, 86, 65, + 84, 197, 65, 67, 84, 85, 65, 76, 76, 217, 65, 75, 72, 77, 73, 77, 73, + 195, 65, 80, 79, 68, 69, 82, 77, 193, 65, 82, 73, 83, 84, 69, 82, 193, + 66, 69, 84, 87, 69, 69, 78, 128, 66, 73, 76, 65, 66, 73, 65, 204, 67, 65, + 89, 65, 78, 78, 65, 128, 67, 69, 73, 76, 73, 78, 71, 128, 67, 72, 65, 82, + 73, 79, 84, 128, 67, 72, 79, 82, 69, 86, 77, 193, 67, 72, 82, 79, 78, 79, + 85, 128, 67, 76, 79, 84, 72, 69, 83, 128, 67, 79, 82, 78, 69, 82, 83, + 128, 68, 65, 77, 77, 65, 84, 65, 206, 68, 65, 80, 45, 66, 85, 79, 206, + 68, 65, 80, 45, 77, 85, 79, 217, 68, 65, 80, 45, 80, 82, 65, 205, 68, 69, + 89, 84, 69, 82, 79, 211, 68, 73, 71, 65, 77, 77, 65, 128, 68, 73, 83, 73, + 77, 79, 85, 128, 69, 77, 80, 72, 65, 83, 73, 211, 70, 69, 77, 73, 78, 73, + 78, 197, 70, 69, 82, 77, 65, 84, 65, 128, 70, 73, 83, 72, 72, 79, 79, + 203, 71, 76, 65, 71, 79, 76, 73, 128, 73, 78, 72, 69, 82, 69, 78, 212, + 73, 78, 84, 69, 82, 73, 79, 210, 75, 65, 83, 82, 65, 84, 65, 206, 75, 65, + 89, 65, 78, 78, 65, 128, 75, 79, 77, 66, 85, 86, 65, 128, 76, 45, 83, 72, + 65, 80, 69, 196, 76, 65, 84, 73, 78, 65, 84, 197, 76, 65, 89, 65, 78, 78, + 65, 128, 76, 74, 85, 68, 73, 74, 69, 128, 76, 79, 71, 79, 84, 89, 80, + 197, 77, 69, 65, 83, 85, 82, 69, 128, 77, 85, 76, 84, 73, 83, 69, 212, + 78, 65, 89, 65, 78, 78, 65, 128, 79, 77, 73, 83, 83, 73, 79, 206, 80, 65, + 89, 65, 78, 78, 65, 128, 80, 69, 68, 69, 83, 84, 65, 204, 80, 69, 84, 65, + 76, 76, 69, 196, 80, 82, 65, 77, 45, 66, 69, 201, 80, 82, 65, 77, 45, 80, + 73, 201, 81, 85, 65, 82, 84, 69, 82, 128, 82, 71, 89, 73, 78, 71, 83, + 128, 83, 45, 83, 72, 65, 80, 69, 196, 83, 69, 77, 73, 83, 79, 70, 212, + 83, 69, 77, 75, 65, 84, 72, 128, 83, 69, 86, 69, 78, 84, 89, 128, 83, 72, + 65, 80, 73, 78, 71, 128, 83, 72, 84, 65, 80, 73, 67, 128, 83, 79, 67, 73, + 69, 84, 89, 128, 83, 80, 65, 82, 75, 76, 69, 128, 83, 80, 69, 67, 73, 65, + 76, 128, 83, 84, 65, 78, 68, 65, 82, 196, 83, 84, 82, 79, 75, 69, 83, + 128, 84, 72, 69, 83, 69, 79, 83, 128, 84, 72, 85, 78, 68, 69, 82, 128, + 84, 82, 73, 83, 69, 77, 69, 128, 85, 66, 65, 68, 65, 77, 65, 128, 87, 65, + 73, 84, 73, 78, 71, 128, 90, 72, 73, 86, 69, 84, 69, 128, 65, 65, 89, 65, + 78, 78, 65, 128, 65, 66, 65, 70, 73, 76, 73, 128, 65, 68, 86, 65, 78, 67, + 69, 128, 65, 69, 89, 65, 78, 78, 65, 128, 65, 73, 89, 65, 78, 78, 65, + 128, 65, 76, 69, 77, 66, 73, 67, 128, 65, 76, 86, 69, 79, 76, 65, 210, + 65, 78, 71, 83, 84, 82, 79, 205, 65, 78, 71, 85, 76, 65, 82, 128, 65, 78, + 85, 83, 86, 65, 82, 193, 65, 80, 79, 84, 72, 69, 83, 128, 65, 82, 65, 69, + 65, 45, 73, 128, 65, 82, 65, 69, 65, 45, 85, 128, 65, 82, 67, 72, 65, 73, + 79, 206, 65, 82, 79, 85, 83, 73, 78, 199, 65, 85, 89, 65, 78, 78, 65, + 128, 66, 65, 65, 82, 69, 82, 85, 128, 66, 65, 73, 82, 75, 65, 78, 128, + 66, 65, 82, 82, 69, 75, 72, 128, 66, 65, 82, 82, 73, 69, 82, 128, 66, 65, + 84, 72, 84, 85, 66, 128, 66, 69, 67, 65, 85, 83, 69, 128, 66, 69, 76, 71, + 84, 72, 79, 210, 66, 69, 82, 75, 65, 78, 65, 206, 66, 73, 68, 69, 78, 84, + 65, 204, 66, 79, 85, 78, 68, 65, 82, 217, 66, 82, 65, 75, 67, 69, 84, + 128, 66, 82, 73, 83, 84, 76, 69, 128, 66, 85, 85, 77, 73, 83, 72, 128, + 67, 65, 69, 83, 85, 82, 65, 128, 67, 65, 80, 73, 84, 65, 76, 128, 67, 65, + 82, 82, 73, 65, 71, 197, 67, 69, 76, 83, 73, 85, 83, 128, 67, 72, 65, 77, + 73, 76, 73, 128, 67, 76, 73, 78, 71, 73, 78, 199, 67, 79, 77, 80, 65, 82, + 69, 128, 67, 79, 78, 83, 84, 65, 78, 212, 67, 79, 78, 84, 65, 67, 84, + 128, 67, 79, 82, 79, 78, 73, 83, 128, 67, 79, 82, 82, 69, 67, 84, 128, + 67, 82, 69, 65, 84, 73, 86, 197, 67, 82, 69, 83, 67, 69, 78, 212, 67, 82, + 85, 90, 69, 73, 82, 207, 67, 85, 83, 84, 79, 77, 69, 210, 67, 87, 69, 79, + 82, 84, 72, 128, 67, 89, 80, 69, 82, 85, 83, 128, 67, 89, 82, 69, 78, 65, + 73, 195, 68, 65, 71, 65, 76, 71, 65, 128, 68, 69, 67, 65, 89, 69, 68, + 128, 68, 69, 89, 84, 69, 82, 79, 213, 68, 72, 65, 76, 65, 84, 72, 128, + 68, 73, 65, 77, 69, 84, 69, 210, 68, 73, 65, 84, 79, 78, 79, 206, 68, 73, + 71, 82, 65, 77, 77, 193, 68, 73, 77, 77, 73, 78, 71, 128, 68, 73, 80, 76, + 79, 85, 78, 128, 68, 73, 82, 69, 67, 84, 76, 217, 68, 73, 86, 73, 68, 69, + 83, 128, 68, 79, 84, 83, 45, 49, 50, 128, 68, 79, 84, 83, 45, 49, 51, + 128, 68, 79, 84, 83, 45, 49, 52, 128, 68, 79, 84, 83, 45, 49, 53, 128, + 68, 79, 84, 83, 45, 49, 54, 128, 68, 79, 84, 83, 45, 49, 55, 128, 68, 79, + 84, 83, 45, 49, 56, 128, 68, 79, 84, 83, 45, 50, 51, 128, 68, 79, 84, 83, + 45, 50, 52, 128, 68, 79, 84, 83, 45, 50, 53, 128, 68, 79, 84, 83, 45, 50, + 54, 128, 68, 79, 84, 83, 45, 50, 55, 128, 68, 79, 84, 83, 45, 50, 56, + 128, 68, 79, 84, 83, 45, 51, 52, 128, 68, 79, 84, 83, 45, 51, 53, 128, + 68, 79, 84, 83, 45, 51, 54, 128, 68, 79, 84, 83, 45, 51, 55, 128, 68, 79, + 84, 83, 45, 51, 56, 128, 68, 79, 84, 83, 45, 52, 53, 128, 68, 79, 84, 83, + 45, 52, 54, 128, 68, 79, 84, 83, 45, 52, 55, 128, 68, 79, 84, 83, 45, 52, + 56, 128, 68, 79, 84, 83, 45, 53, 54, 128, 68, 79, 84, 83, 45, 53, 55, + 128, 68, 79, 84, 83, 45, 53, 56, 128, 68, 79, 84, 83, 45, 54, 55, 128, + 68, 79, 84, 83, 45, 54, 56, 128, 68, 79, 84, 83, 45, 55, 56, 128, 68, 82, + 65, 67, 72, 77, 65, 128, 68, 82, 65, 70, 84, 73, 78, 199, 69, 65, 66, 72, + 65, 68, 72, 128, 69, 65, 68, 72, 65, 68, 72, 128, 69, 66, 69, 70, 73, 76, + 73, 128, 69, 73, 71, 72, 84, 69, 69, 206, 69, 76, 65, 70, 82, 79, 78, + 128, 69, 76, 69, 67, 84, 82, 73, 195, 69, 78, 81, 85, 73, 82, 89, 128, + 69, 78, 84, 69, 82, 73, 78, 199, 69, 84, 78, 65, 72, 84, 65, 128, 69, 86, + 69, 78, 73, 78, 71, 128, 70, 65, 73, 76, 85, 82, 69, 128, 70, 65, 89, 65, + 78, 78, 65, 128, 70, 69, 65, 84, 72, 69, 82, 128, 70, 73, 83, 72, 69, 89, + 69, 128, 70, 79, 78, 71, 77, 65, 78, 128, 70, 79, 79, 84, 78, 79, 84, + 197, 70, 79, 85, 82, 84, 69, 69, 206, 70, 82, 79, 87, 78, 73, 78, 199, + 71, 65, 82, 77, 69, 78, 84, 128, 71, 73, 82, 85, 68, 65, 65, 128, 71, 82, + 65, 80, 72, 69, 77, 197, 72, 65, 70, 85, 75, 72, 65, 128, 72, 65, 76, 65, + 78, 84, 65, 128, 72, 65, 76, 66, 69, 82, 68, 128, 72, 65, 83, 65, 78, 84, + 65, 128, 72, 65, 89, 65, 78, 78, 65, 128, 72, 69, 65, 68, 73, 78, 71, + 128, 72, 69, 65, 86, 69, 78, 76, 217, 73, 45, 65, 82, 65, 69, 65, 128, + 73, 66, 73, 70, 73, 76, 73, 128, 73, 67, 72, 65, 68, 73, 78, 128, 73, 73, + 89, 65, 78, 78, 65, 128, 73, 78, 68, 73, 82, 69, 67, 212, 73, 78, 70, 73, + 78, 73, 84, 217, 73, 78, 84, 69, 82, 69, 83, 212, 73, 79, 68, 72, 65, 68, + 72, 128, 74, 65, 78, 85, 65, 82, 89, 128, 74, 65, 80, 65, 78, 69, 83, + 197, 74, 85, 80, 73, 84, 69, 82, 128, 75, 65, 75, 65, 66, 65, 84, 128, + 75, 65, 82, 65, 84, 84, 79, 128, 75, 65, 82, 79, 82, 73, 73, 128, 75, 73, + 78, 83, 72, 73, 80, 128, 75, 79, 78, 84, 69, 86, 77, 193, 75, 79, 79, 77, + 85, 85, 84, 128, 75, 85, 82, 79, 79, 78, 69, 128, 76, 65, 78, 71, 85, 65, + 71, 197, 76, 79, 67, 65, 84, 73, 79, 206, 77, 65, 73, 75, 85, 82, 79, + 128, 77, 65, 73, 77, 85, 65, 78, 128, 77, 65, 78, 83, 89, 79, 78, 128, + 77, 65, 82, 66, 85, 84, 65, 128, 77, 65, 82, 67, 65, 84, 79, 128, 77, 65, + 82, 82, 73, 65, 71, 197, 77, 65, 82, 82, 89, 73, 78, 199, 77, 65, 83, 83, + 73, 78, 71, 128, 77, 65, 89, 65, 78, 78, 65, 128, 77, 69, 71, 65, 84, 79, + 78, 128, 77, 69, 82, 67, 85, 82, 89, 128, 77, 69, 84, 82, 69, 84, 69, + 211, 77, 73, 75, 85, 82, 79, 78, 128, 77, 73, 76, 76, 73, 79, 78, 211, + 77, 79, 68, 69, 83, 84, 89, 128, 77, 79, 72, 65, 77, 77, 65, 196, 77, 79, + 82, 78, 73, 78, 71, 128, 77, 85, 76, 84, 73, 80, 76, 197, 78, 65, 84, 73, + 79, 78, 65, 204, 78, 69, 71, 65, 84, 73, 79, 206, 78, 69, 80, 84, 85, 78, + 69, 128, 78, 69, 87, 76, 73, 78, 69, 128, 78, 71, 69, 65, 68, 65, 76, + 128, 78, 73, 75, 65, 72, 73, 84, 128, 78, 73, 78, 69, 84, 69, 69, 206, + 79, 66, 79, 70, 73, 76, 73, 128, 79, 67, 84, 79, 66, 69, 82, 128, 79, 78, + 69, 45, 76, 73, 78, 197, 79, 78, 69, 83, 69, 76, 70, 128, 79, 79, 89, 65, + 78, 78, 65, 128, 79, 82, 84, 72, 79, 68, 79, 216, 79, 85, 84, 76, 73, 78, + 69, 128, 80, 65, 67, 75, 73, 78, 71, 128, 80, 65, 76, 76, 65, 87, 65, + 128, 80, 65, 84, 84, 69, 82, 78, 128, 80, 69, 76, 65, 83, 84, 79, 206, + 80, 69, 84, 65, 83, 77, 65, 128, 80, 69, 84, 65, 83, 84, 73, 128, 80, 72, + 73, 78, 84, 72, 85, 128, 80, 72, 85, 84, 72, 65, 79, 128, 80, 79, 68, 65, + 84, 85, 83, 128, 80, 82, 69, 67, 69, 68, 69, 128, 80, 82, 69, 67, 69, 68, + 69, 196, 80, 82, 69, 86, 73, 79, 85, 211, 80, 82, 73, 86, 65, 84, 69, + 128, 80, 82, 79, 80, 69, 82, 84, 217, 82, 65, 75, 72, 65, 78, 71, 128, + 82, 65, 80, 73, 83, 77, 65, 128, 82, 65, 89, 65, 78, 78, 65, 128, 82, 69, + 65, 72, 77, 85, 75, 128, 82, 69, 76, 69, 65, 83, 69, 128, 82, 69, 84, 82, + 69, 65, 84, 128, 82, 73, 84, 84, 79, 82, 85, 128, 82, 85, 85, 66, 85, 82, + 85, 128, 83, 65, 73, 75, 85, 82, 85, 128, 83, 65, 76, 84, 73, 82, 69, + 128, 83, 65, 77, 80, 72, 65, 79, 128, 83, 65, 78, 89, 79, 79, 71, 193, + 83, 67, 72, 79, 76, 65, 82, 128, 83, 67, 82, 85, 80, 76, 69, 128, 83, 69, + 71, 77, 69, 78, 84, 128, 83, 73, 77, 73, 76, 65, 82, 128, 83, 73, 78, 75, + 73, 78, 71, 128, 83, 73, 82, 73, 78, 71, 85, 128, 83, 73, 88, 45, 76, 73, + 78, 197, 83, 78, 79, 87, 77, 65, 78, 128, 83, 80, 73, 82, 65, 78, 84, + 128, 83, 80, 82, 73, 78, 71, 83, 128, 83, 81, 85, 65, 82, 69, 83, 128, + 83, 84, 65, 85, 82, 79, 83, 128, 83, 84, 65, 86, 82, 79, 83, 128, 83, 84, + 65, 86, 82, 79, 85, 128, 83, 84, 82, 65, 84, 73, 65, 206, 83, 84, 82, 73, + 67, 84, 76, 217, 83, 85, 66, 74, 69, 67, 84, 128, 83, 85, 67, 67, 69, 69, + 68, 128, 83, 89, 78, 69, 86, 77, 65, 128, 84, 65, 73, 83, 89, 79, 85, + 128, 84, 65, 84, 87, 69, 69, 76, 128, 84, 67, 72, 69, 72, 69, 72, 128, + 84, 69, 83, 83, 65, 82, 79, 206, 84, 69, 83, 83, 69, 82, 65, 128, 84, 72, + 73, 82, 84, 69, 69, 206, 84, 72, 85, 82, 73, 83, 65, 218, 84, 73, 78, 65, + 71, 77, 65, 128, 84, 73, 82, 79, 78, 73, 65, 206, 84, 79, 82, 67, 85, 76, + 85, 211, 84, 82, 73, 73, 83, 65, 80, 128, 84, 82, 89, 66, 76, 73, 79, + 206, 84, 86, 73, 77, 65, 68, 85, 210, 84, 87, 79, 45, 76, 73, 78, 197, + 85, 45, 69, 79, 45, 69, 85, 128, 85, 66, 85, 70, 73, 76, 73, 128, 85, 77, + 66, 82, 69, 76, 76, 193, 86, 65, 83, 84, 78, 69, 83, 211, 86, 65, 89, 65, + 78, 78, 65, 128, 86, 73, 69, 87, 68, 65, 84, 193, 86, 73, 76, 76, 65, 71, + 69, 128, 86, 79, 73, 67, 73, 78, 71, 128, 87, 65, 83, 65, 76, 76, 65, + 205, 87, 65, 83, 84, 73, 78, 71, 128, 89, 65, 89, 65, 78, 78, 65, 128, + 89, 79, 85, 84, 72, 70, 85, 204, 89, 80, 79, 82, 82, 79, 73, 128, 79, 83, + 77, 65, 78, 89, 193, 67, 73, 82, 67, 76, 69, 128, 66, 82, 65, 67, 75, 69, + 212, 85, 80, 83, 73, 76, 79, 206, 65, 67, 67, 69, 78, 84, 128, 68, 73, + 78, 71, 66, 65, 212, 69, 80, 83, 73, 76, 79, 206, 83, 76, 65, 78, 84, 69, + 196, 83, 81, 85, 65, 82, 69, 128, 72, 65, 78, 85, 78, 79, 207, 68, 65, + 71, 69, 83, 72, 128, 71, 76, 79, 84, 84, 65, 204, 84, 65, 71, 65, 76, 79, + 199, 79, 77, 73, 67, 82, 79, 206, 80, 65, 76, 65, 84, 65, 204, 78, 65, + 83, 75, 65, 80, 201, 67, 79, 82, 78, 69, 82, 128, 69, 76, 69, 77, 69, 78, + 212, 66, 85, 76, 76, 69, 84, 128, 68, 79, 84, 76, 69, 83, 211, 79, 71, + 79, 78, 69, 75, 128, 86, 73, 82, 65, 77, 65, 128, 75, 73, 82, 71, 72, 73, + 218, 82, 69, 86, 69, 82, 83, 197, 68, 73, 65, 77, 79, 78, 196, 84, 87, + 69, 78, 84, 89, 128, 68, 79, 85, 66, 76, 69, 128, 78, 69, 73, 84, 72, 69, + 210, 81, 85, 65, 82, 84, 69, 210, 83, 73, 77, 73, 76, 65, 210, 83, 73, + 78, 71, 76, 69, 128, 83, 79, 76, 73, 68, 85, 211, 83, 81, 85, 65, 82, 69, + 196, 67, 72, 73, 78, 69, 83, 197, 78, 85, 78, 65, 86, 73, 203, 83, 85, + 66, 83, 69, 84, 128, 84, 72, 45, 67, 82, 69, 197, 84, 82, 73, 71, 82, 65, + 205, 65, 82, 75, 84, 73, 75, 207, 69, 76, 69, 86, 69, 78, 128, 72, 85, + 78, 68, 82, 69, 196, 72, 89, 80, 72, 69, 78, 128, 73, 78, 83, 73, 68, 69, + 128, 77, 65, 82, 75, 69, 82, 128, 79, 80, 69, 78, 73, 78, 199, 84, 87, + 69, 76, 86, 69, 128, 69, 73, 71, 72, 84, 72, 211, 80, 65, 82, 84, 73, 65, + 204, 84, 72, 73, 82, 84, 89, 128, 86, 82, 65, 67, 72, 89, 128, 65, 82, + 82, 79, 87, 83, 128, 70, 65, 76, 76, 73, 78, 199, 79, 66, 76, 73, 81, 85, + 197, 80, 69, 82, 67, 69, 78, 212, 84, 72, 82, 79, 85, 71, 200, 67, 69, + 68, 73, 76, 76, 193, 67, 79, 78, 84, 82, 79, 204, 67, 85, 82, 86, 73, 78, + 199, 68, 73, 71, 82, 65, 80, 200, 69, 81, 85, 65, 76, 83, 128, 70, 73, + 76, 76, 69, 82, 128, 71, 65, 78, 71, 73, 65, 128, 73, 78, 86, 69, 82, 83, + 197, 73, 79, 84, 65, 84, 69, 196, 75, 69, 78, 84, 73, 77, 193, 77, 69, + 65, 83, 85, 82, 197, 82, 79, 85, 78, 68, 69, 196, 83, 65, 78, 89, 65, 75, + 193, 84, 67, 72, 69, 72, 69, 200, 84, 79, 80, 66, 65, 82, 128, 84, 85, + 82, 84, 76, 69, 128, 89, 73, 68, 68, 73, 83, 200, 45, 75, 72, 89, 73, 76, + 128, 66, 79, 84, 84, 79, 77, 128, 67, 69, 78, 84, 82, 69, 128, 67, 69, + 78, 84, 82, 69, 196, 67, 79, 78, 84, 65, 73, 206, 67, 79, 78, 84, 79, 85, + 210, 67, 82, 79, 83, 83, 69, 196, 68, 65, 78, 84, 65, 74, 193, 68, 73, + 86, 73, 68, 69, 196, 68, 79, 84, 84, 69, 68, 128, 68, 82, 65, 71, 79, 78, + 128, 70, 73, 70, 84, 72, 83, 128, 72, 69, 65, 86, 69, 78, 128, 75, 79, + 77, 66, 85, 86, 193, 75, 82, 65, 84, 73, 77, 193, 76, 69, 65, 68, 69, 82, + 128, 77, 65, 82, 66, 85, 84, 193, 77, 69, 77, 66, 69, 82, 128, 78, 65, + 84, 85, 82, 65, 204, 78, 73, 78, 69, 84, 89, 128, 80, 69, 78, 67, 73, 76, + 128, 81, 65, 77, 65, 84, 83, 128, 83, 75, 76, 73, 82, 79, 206, 83, 79, + 71, 68, 73, 65, 206, 83, 84, 73, 71, 77, 65, 128, 83, 89, 78, 65, 71, 77, + 193, 84, 65, 65, 76, 85, 74, 193, 84, 72, 69, 83, 69, 79, 211, 84, 79, + 78, 71, 85, 69, 128, 65, 67, 65, 68, 69, 77, 217, 65, 67, 67, 79, 85, 78, + 212, 65, 78, 67, 72, 79, 82, 128, 65, 78, 67, 79, 82, 65, 128, 65, 80, + 76, 79, 85, 78, 128, 65, 82, 67, 72, 65, 73, 195, 66, 65, 76, 85, 68, 65, + 128, 66, 65, 77, 66, 79, 79, 128, 66, 65, 83, 72, 75, 73, 210, 66, 73, + 78, 68, 73, 78, 199, 66, 73, 83, 72, 79, 80, 128, 66, 79, 87, 84, 73, 69, + 128, 67, 72, 73, 69, 85, 67, 200, 67, 72, 82, 73, 86, 73, 128, 67, 76, + 85, 83, 84, 69, 210, 68, 65, 71, 71, 69, 82, 128, 68, 65, 80, 45, 66, 69, + 201, 68, 65, 80, 45, 80, 73, 201, 68, 69, 67, 73, 77, 65, 204, 68, 73, + 86, 73, 68, 69, 128, 68, 74, 69, 82, 86, 73, 128, 68, 79, 85, 66, 76, 69, + 196, 68, 82, 65, 67, 72, 77, 193, 69, 65, 82, 84, 72, 76, 217, 69, 73, + 71, 72, 84, 89, 128, 69, 83, 67, 65, 80, 69, 128, 70, 69, 65, 84, 72, 69, + 210, 70, 76, 69, 88, 85, 83, 128, 71, 69, 82, 69, 83, 72, 128, 71, 72, + 85, 78, 78, 65, 128, 71, 82, 69, 65, 84, 69, 210, 72, 79, 76, 68, 73, 78, + 199, 73, 78, 72, 73, 66, 73, 212, 73, 83, 83, 72, 65, 82, 128, 73, 90, + 72, 73, 84, 83, 193, 75, 69, 69, 80, 73, 78, 199, 75, 72, 73, 69, 85, 75, + 200, 75, 76, 65, 83, 77, 65, 128, 75, 78, 73, 71, 72, 84, 128, 75, 79, + 82, 65, 78, 73, 195, 76, 69, 71, 69, 84, 79, 211, 77, 65, 76, 65, 75, 79, + 206, 77, 65, 82, 75, 45, 49, 128, 77, 65, 82, 75, 45, 50, 128, 77, 79, + 82, 84, 65, 82, 128, 78, 69, 71, 65, 84, 69, 196, 78, 79, 84, 67, 72, 69, + 196, 79, 82, 68, 73, 78, 65, 204, 80, 72, 73, 69, 85, 80, 200, 80, 72, + 82, 65, 83, 69, 128, 80, 73, 76, 67, 82, 79, 215, 80, 76, 65, 71, 73, 79, + 211, 80, 79, 75, 79, 74, 73, 128, 82, 69, 84, 85, 82, 78, 128, 82, 73, + 75, 82, 73, 75, 128, 83, 69, 82, 73, 70, 83, 128, 83, 72, 65, 80, 69, 83, + 128, 83, 73, 88, 84, 69, 69, 206, 83, 76, 79, 80, 73, 78, 199, 83, 77, + 65, 76, 76, 69, 210, 83, 77, 73, 76, 73, 78, 199, 83, 80, 69, 69, 67, 72, + 128, 83, 80, 73, 68, 69, 82, 217, 84, 65, 77, 73, 78, 71, 128, 84, 69, + 76, 69, 73, 65, 128, 84, 69, 76, 73, 83, 72, 193, 84, 69, 83, 83, 69, 82, + 193, 84, 72, 69, 84, 72, 69, 128, 84, 72, 73, 69, 85, 84, 200, 84, 72, + 82, 69, 65, 68, 128, 84, 72, 82, 69, 69, 45, 196, 84, 86, 82, 73, 68, 79, + 128, 85, 80, 84, 85, 82, 78, 128, 89, 69, 76, 76, 79, 87, 128, 89, 79, + 45, 89, 65, 69, 128, 89, 85, 45, 89, 69, 79, 128, 90, 69, 77, 76, 74, 65, + 128, 65, 66, 89, 83, 77, 65, 204, 65, 70, 71, 72, 65, 78, 201, 65, 70, + 82, 73, 67, 65, 206, 65, 72, 65, 71, 71, 65, 210, 65, 73, 72, 86, 85, 83, + 128, 65, 73, 86, 73, 76, 73, 203, 65, 76, 65, 89, 72, 69, 128, 65, 76, + 73, 71, 78, 69, 196, 65, 78, 78, 85, 73, 84, 217, 65, 80, 65, 65, 84, 79, + 128, 65, 82, 65, 69, 65, 69, 128, 65, 82, 77, 79, 85, 82, 128, 65, 82, + 82, 73, 86, 69, 128, 65, 82, 83, 69, 79, 83, 128, 65, 82, 85, 72, 85, 65, + 128, 65, 83, 67, 69, 78, 84, 128, 65, 85, 71, 85, 83, 84, 128, 65, 85, + 83, 84, 82, 65, 204, 65, 86, 69, 82, 65, 71, 197, 66, 65, 68, 71, 69, 82, + 128, 66, 65, 73, 77, 65, 73, 128, 66, 65, 78, 84, 79, 67, 128, 66, 65, + 82, 76, 69, 89, 128, 66, 65, 82, 82, 69, 69, 128, 66, 69, 78, 90, 69, 78, + 197, 66, 69, 84, 87, 69, 69, 206, 66, 69, 89, 89, 65, 76, 128, 66, 73, + 84, 84, 69, 82, 128, 66, 79, 82, 85, 84, 79, 128, 66, 82, 65, 78, 67, 72, + 128, 66, 82, 69, 86, 73, 83, 128, 66, 82, 79, 78, 90, 69, 128, 66, 85, + 67, 75, 76, 69, 128, 67, 65, 78, 67, 69, 76, 128, 67, 65, 78, 67, 69, 82, + 128, 67, 65, 84, 65, 87, 65, 128, 67, 65, 85, 84, 73, 79, 206, 67, 72, + 65, 77, 75, 79, 128, 67, 72, 65, 78, 71, 69, 128, 67, 72, 65, 82, 73, 79, + 212, 67, 72, 69, 86, 82, 79, 206, 67, 72, 73, 82, 69, 84, 128, 67, 72, + 85, 82, 67, 72, 128, 67, 76, 69, 70, 45, 49, 128, 67, 76, 69, 70, 45, 50, + 128, 67, 76, 73, 86, 73, 83, 128, 67, 76, 79, 83, 69, 68, 128, 67, 79, + 70, 70, 73, 78, 128, 67, 79, 78, 73, 67, 65, 204, 67, 79, 82, 80, 83, 69, + 128, 67, 85, 82, 82, 69, 78, 212, 68, 65, 65, 68, 72, 85, 128, 68, 65, + 76, 65, 84, 72, 128, 68, 65, 77, 65, 82, 85, 128, 68, 65, 83, 69, 73, 65, + 128, 68, 68, 65, 72, 65, 76, 128, 68, 69, 76, 69, 84, 69, 128, 68, 69, + 76, 80, 72, 73, 195, 68, 72, 65, 65, 76, 85, 128, 68, 72, 65, 82, 77, 65, + 128, 68, 73, 69, 83, 73, 83, 128, 68, 73, 80, 80, 69, 82, 128, 68, 73, + 86, 79, 82, 67, 197, 68, 79, 84, 83, 45, 49, 128, 68, 79, 84, 83, 45, 50, + 128, 68, 79, 84, 83, 45, 51, 128, 68, 79, 84, 83, 45, 52, 128, 68, 79, + 84, 83, 45, 53, 128, 68, 79, 84, 83, 45, 54, 128, 68, 79, 84, 83, 45, 55, + 128, 68, 79, 84, 83, 45, 56, 128, 68, 85, 84, 73, 69, 83, 128, 69, 73, + 71, 72, 84, 72, 128, 69, 78, 65, 82, 88, 73, 211, 69, 88, 67, 69, 83, 83, + 128, 69, 88, 73, 83, 84, 83, 128, 70, 65, 67, 69, 45, 49, 128, 70, 65, + 67, 69, 45, 50, 128, 70, 65, 67, 69, 45, 51, 128, 70, 65, 67, 69, 45, 52, + 128, 70, 65, 67, 69, 45, 53, 128, 70, 65, 67, 69, 45, 54, 128, 70, 65, + 77, 73, 76, 89, 128, 70, 65, 84, 72, 69, 82, 128, 70, 69, 77, 65, 76, 69, + 128, 70, 69, 82, 77, 65, 84, 193, 70, 73, 70, 84, 69, 69, 206, 70, 76, + 65, 71, 45, 49, 128, 70, 76, 65, 71, 45, 50, 128, 70, 76, 65, 71, 45, 51, + 128, 70, 76, 65, 71, 45, 52, 128, 70, 76, 65, 71, 45, 53, 128, 70, 76, + 73, 71, 72, 84, 128, 70, 76, 79, 87, 69, 82, 128, 70, 79, 82, 67, 69, 83, + 128, 70, 85, 78, 69, 82, 65, 204, 71, 69, 68, 79, 76, 65, 128, 71, 69, + 77, 73, 78, 73, 128, 71, 69, 78, 69, 82, 73, 195, 71, 72, 65, 73, 78, 85, + 128, 71, 72, 65, 77, 65, 76, 128, 71, 82, 79, 85, 78, 68, 128, 71, 85, + 65, 82, 65, 78, 201, 72, 65, 70, 85, 75, 72, 128, 72, 69, 73, 83, 69, 73, + 128, 72, 69, 76, 77, 69, 84, 128, 72, 69, 82, 65, 69, 85, 205, 72, 69, + 82, 77, 69, 83, 128, 72, 69, 82, 85, 84, 85, 128, 72, 82, 89, 86, 78, 73, + 193, 72, 85, 73, 73, 84, 79, 128, 73, 45, 66, 69, 65, 77, 128, 73, 77, + 73, 83, 69, 79, 211, 73, 78, 71, 87, 65, 90, 128, 73, 78, 73, 78, 71, 85, + 128, 73, 78, 83, 69, 67, 84, 128, 73, 78, 83, 85, 76, 65, 210, 74, 79, + 73, 78, 69, 68, 128, 75, 65, 78, 65, 75, 79, 128, 75, 65, 78, 84, 65, 74, + 193, 75, 69, 70, 85, 76, 65, 128, 75, 69, 89, 67, 65, 80, 128, 75, 72, + 79, 77, 85, 84, 128, 75, 76, 73, 84, 79, 78, 128, 75, 79, 82, 85, 78, 65, + 128, 75, 89, 65, 84, 72, 79, 211, 75, 89, 85, 82, 73, 73, 128, 76, 65, + 77, 65, 68, 72, 128, 76, 65, 84, 69, 82, 65, 204, 76, 69, 71, 73, 79, 78, + 128, 76, 69, 73, 77, 77, 65, 128, 76, 69, 84, 84, 69, 82, 128, 76, 73, + 77, 73, 84, 69, 196, 76, 73, 78, 69, 45, 49, 128, 76, 73, 78, 69, 45, 51, + 128, 76, 73, 78, 69, 45, 55, 128, 76, 73, 78, 69, 45, 57, 128, 76, 73, + 78, 75, 73, 78, 199, 76, 79, 90, 69, 78, 71, 197, 77, 65, 73, 68, 69, 78, + 128, 77, 65, 76, 84, 69, 83, 197, 77, 65, 82, 75, 45, 51, 128, 77, 65, + 82, 75, 45, 52, 128, 77, 65, 82, 85, 75, 85, 128, 77, 65, 84, 82, 73, 88, + 128, 77, 65, 88, 73, 77, 65, 128, 77, 69, 68, 73, 85, 77, 128, 77, 69, + 71, 65, 76, 73, 128, 77, 69, 82, 75, 72, 65, 128, 77, 69, 84, 82, 73, 65, + 128, 77, 73, 68, 76, 73, 78, 197, 77, 73, 76, 76, 69, 84, 128, 77, 73, + 78, 73, 77, 65, 128, 77, 79, 68, 69, 76, 83, 128, 77, 79, 84, 72, 69, 82, + 128, 77, 85, 81, 68, 65, 77, 128, 78, 65, 85, 84, 72, 83, 128, 78, 69, + 78, 65, 78, 79, 128, 78, 73, 82, 85, 71, 85, 128, 78, 79, 75, 72, 85, 75, + 128, 78, 79, 77, 73, 78, 65, 204, 78, 85, 77, 66, 69, 82, 128, 78, 85, + 78, 65, 86, 85, 212, 79, 66, 69, 76, 79, 83, 128, 79, 77, 65, 76, 79, 78, + 128, 79, 80, 69, 78, 45, 80, 128, 79, 80, 80, 79, 83, 69, 128, 79, 82, + 73, 71, 73, 78, 128, 79, 84, 72, 65, 76, 65, 206, 80, 65, 76, 85, 84, 65, + 128, 80, 65, 83, 72, 84, 65, 128, 80, 69, 78, 73, 72, 73, 128, 80, 69, + 82, 83, 79, 78, 128, 80, 73, 75, 85, 82, 85, 128, 80, 73, 80, 73, 78, 71, + 128, 80, 73, 83, 67, 69, 83, 128, 80, 79, 73, 78, 84, 79, 128, 80, 82, + 69, 67, 69, 68, 197, 80, 82, 69, 70, 65, 67, 197, 80, 82, 79, 68, 85, 67, + 212, 80, 85, 82, 73, 84, 89, 128, 80, 85, 83, 72, 73, 78, 199, 81, 69, + 84, 65, 78, 65, 128, 81, 85, 66, 85, 84, 83, 128, 82, 69, 80, 69, 65, 84, + 128, 82, 73, 84, 85, 65, 76, 128, 82, 85, 78, 79, 85, 84, 128, 83, 65, + 65, 68, 72, 85, 128, 83, 65, 74, 68, 65, 72, 128, 83, 65, 77, 69, 75, 72, + 128, 83, 65, 78, 78, 89, 65, 128, 83, 65, 84, 85, 82, 78, 128, 83, 67, + 65, 76, 69, 83, 128, 83, 67, 82, 69, 69, 78, 128, 83, 67, 82, 73, 80, 84, + 128, 83, 69, 65, 71, 85, 76, 204, 83, 69, 67, 79, 78, 68, 128, 83, 69, + 67, 82, 69, 84, 128, 83, 69, 67, 84, 79, 82, 128, 83, 69, 73, 83, 77, 65, + 128, 83, 69, 82, 86, 73, 67, 197, 83, 69, 86, 69, 78, 84, 217, 83, 72, + 65, 68, 68, 65, 128, 83, 72, 65, 75, 84, 73, 128, 83, 72, 69, 69, 78, 85, + 128, 83, 72, 79, 82, 84, 83, 128, 83, 72, 85, 70, 70, 76, 197, 83, 73, + 67, 75, 76, 69, 128, 83, 73, 88, 84, 72, 83, 128, 83, 76, 79, 87, 76, 89, + 128, 83, 80, 65, 84, 72, 73, 128, 83, 80, 73, 82, 73, 84, 128, 83, 80, + 82, 79, 85, 84, 128, 83, 84, 65, 86, 82, 79, 211, 83, 84, 82, 65, 73, 70, + 128, 83, 84, 82, 73, 68, 69, 128, 83, 84, 82, 79, 75, 69, 211, 83, 85, + 66, 73, 84, 79, 128, 83, 85, 67, 67, 69, 69, 196, 83, 85, 82, 70, 65, 67, + 197, 83, 87, 79, 82, 68, 83, 128, 83, 89, 78, 65, 70, 73, 128, 83, 89, + 79, 85, 87, 65, 128, 84, 65, 84, 87, 69, 69, 204, 84, 65, 85, 82, 85, 83, + 128, 84, 69, 78, 85, 84, 79, 128, 84, 72, 65, 65, 76, 85, 128, 84, 72, + 65, 72, 65, 78, 128, 84, 72, 65, 78, 78, 65, 128, 84, 72, 73, 82, 68, 83, + 128, 84, 72, 73, 85, 84, 72, 128, 84, 73, 80, 69, 72, 65, 128, 84, 79, + 78, 69, 45, 50, 128, 84, 79, 78, 69, 45, 51, 128, 84, 79, 78, 69, 45, 52, + 128, 84, 79, 78, 69, 45, 53, 128, 84, 79, 78, 69, 45, 54, 128, 84, 82, + 73, 80, 76, 73, 128, 84, 82, 73, 80, 79, 68, 128, 84, 83, 72, 85, 71, 83, + 128, 84, 84, 69, 72, 69, 72, 128, 84, 85, 82, 66, 65, 78, 128, 85, 80, + 82, 73, 71, 72, 212, 85, 80, 87, 65, 82, 68, 128, 85, 82, 65, 78, 85, 83, + 128, 86, 65, 76, 76, 69, 89, 128, 86, 65, 82, 69, 73, 65, 201, 86, 65, + 82, 73, 65, 78, 212, 86, 65, 82, 73, 75, 65, 128, 86, 73, 67, 84, 79, 82, + 217, 86, 73, 82, 73, 65, 77, 128, 86, 73, 83, 65, 82, 71, 193, 86, 79, + 76, 84, 65, 71, 197, 87, 65, 82, 78, 73, 78, 199, 87, 69, 65, 80, 79, 78, + 128, 87, 72, 69, 69, 76, 69, 196, 87, 82, 73, 84, 73, 78, 199, 89, 70, + 69, 83, 73, 83, 128, 89, 79, 45, 89, 69, 79, 128, 89, 80, 83, 73, 76, 73, + 128, 83, 89, 76, 79, 84, 201, 67, 65, 82, 79, 78, 128, 66, 82, 69, 86, + 69, 128, 66, 76, 65, 67, 75, 128, 77, 73, 68, 68, 76, 197, 65, 67, 67, + 69, 78, 212, 84, 82, 73, 80, 76, 197, 68, 79, 84, 84, 69, 196, 83, 84, + 82, 79, 75, 197, 86, 69, 83, 83, 69, 204, 69, 81, 85, 65, 76, 211, 71, + 79, 84, 72, 73, 195, 72, 69, 65, 86, 89, 128, 83, 73, 78, 71, 76, 197, + 66, 76, 79, 67, 75, 128, 77, 65, 78, 67, 72, 213, 84, 79, 78, 79, 83, + 128, 66, 79, 84, 84, 79, 205, 70, 84, 72, 79, 82, 193, 77, 69, 68, 73, + 85, 205, 79, 77, 69, 71, 65, 128, 83, 73, 71, 77, 65, 128, 65, 76, 80, + 72, 65, 128, 67, 76, 79, 83, 69, 196, 68, 65, 83, 73, 65, 128, 83, 85, + 66, 83, 69, 212, 67, 79, 77, 77, 65, 128, 68, 69, 76, 84, 65, 128, 86, + 85, 76, 71, 65, 210, 67, 79, 82, 78, 69, 210, 69, 81, 85, 65, 76, 128, + 76, 65, 77, 68, 65, 128, 67, 82, 79, 83, 83, 128, 73, 67, 72, 79, 83, + 128, 83, 65, 89, 73, 83, 201, 84, 72, 69, 84, 65, 128, 87, 72, 73, 84, + 69, 128, 65, 76, 77, 79, 83, 212, 75, 65, 80, 80, 65, 128, 77, 65, 67, + 82, 79, 206, 78, 85, 66, 73, 65, 206, 89, 45, 67, 82, 69, 197, 66, 69, + 83, 73, 68, 197, 67, 69, 78, 84, 82, 197, 83, 72, 65, 68, 68, 193, 84, + 87, 69, 78, 84, 217, 69, 65, 82, 84, 72, 128, 70, 73, 70, 84, 89, 128, + 76, 69, 78, 71, 84, 200, 78, 79, 82, 77, 65, 204, 84, 72, 73, 82, 84, + 217, 68, 65, 83, 72, 69, 196, 68, 73, 71, 82, 65, 205, 80, 82, 73, 77, + 69, 128, 85, 78, 73, 79, 78, 128, 67, 65, 78, 68, 82, 193, 82, 69, 80, + 69, 65, 212, 84, 69, 77, 80, 85, 211, 84, 85, 65, 82, 69, 199, 76, 85, + 78, 65, 84, 197, 82, 73, 83, 73, 78, 199, 82, 84, 65, 71, 83, 128, 68, + 73, 69, 83, 73, 211, 68, 73, 80, 76, 73, 128, 73, 78, 68, 69, 88, 128, + 75, 79, 80, 80, 65, 128, 78, 65, 66, 76, 65, 128, 78, 85, 75, 84, 65, + 128, 79, 84, 84, 65, 86, 193, 82, 65, 73, 83, 69, 196, 83, 67, 72, 87, + 65, 128, 83, 72, 73, 77, 65, 128, 83, 84, 65, 70, 70, 128, 89, 70, 69, + 83, 73, 211, 66, 65, 76, 76, 79, 212, 66, 65, 82, 82, 69, 197, 67, 76, + 73, 67, 75, 128, 67, 85, 66, 69, 68, 128, 67, 85, 82, 86, 69, 196, 70, + 69, 77, 65, 76, 197, 70, 69, 78, 67, 69, 128, 75, 79, 82, 69, 65, 206, + 76, 69, 73, 77, 77, 193, 76, 73, 84, 84, 76, 197, 78, 69, 83, 84, 69, + 196, 85, 73, 71, 72, 85, 210, 87, 65, 84, 69, 82, 128, 87, 69, 73, 71, + 72, 212, 65, 76, 65, 89, 72, 197, 66, 65, 83, 83, 65, 128, 66, 82, 73, + 68, 71, 197, 67, 72, 82, 79, 77, 193, 68, 65, 78, 68, 65, 128, 68, 69, + 71, 82, 69, 197, 68, 69, 86, 73, 67, 197, 68, 79, 76, 76, 65, 210, 80, + 65, 73, 82, 69, 196, 80, 65, 84, 65, 72, 128, 80, 73, 69, 67, 69, 128, + 80, 79, 69, 84, 82, 217, 83, 65, 77, 80, 73, 128, 83, 75, 69, 87, 69, + 196, 84, 73, 77, 69, 83, 128, 84, 84, 69, 72, 69, 200, 87, 73, 71, 71, + 76, 217, 90, 73, 71, 90, 65, 199, 65, 82, 79, 85, 78, 196, 65, 82, 83, + 69, 79, 211, 66, 82, 79, 75, 69, 206, 67, 65, 82, 69, 84, 128, 67, 76, + 73, 70, 70, 128, 67, 76, 79, 84, 72, 128, 68, 65, 71, 69, 83, 200, 68, + 65, 77, 77, 65, 128, 70, 76, 79, 82, 65, 204, 70, 79, 82, 84, 89, 128, + 72, 69, 65, 82, 84, 128, 76, 65, 77, 69, 68, 128, 77, 65, 80, 73, 81, + 128, 78, 45, 67, 82, 69, 197, 80, 79, 83, 84, 65, 204, 80, 84, 72, 65, + 72, 193, 83, 67, 72, 69, 77, 193, 83, 69, 71, 79, 76, 128, 83, 72, 65, + 68, 69, 128, 83, 77, 65, 76, 76, 128, 83, 84, 82, 69, 83, 211, 84, 72, + 79, 82, 78, 128, 84, 73, 84, 76, 79, 128, 84, 79, 79, 84, 72, 128, 86, + 65, 82, 69, 73, 193, 87, 72, 69, 65, 84, 128, 90, 81, 65, 80, 72, 193, + 65, 76, 65, 80, 72, 128, 66, 69, 65, 77, 69, 196, 66, 69, 82, 66, 69, + 210, 66, 73, 78, 65, 82, 217, 66, 73, 78, 68, 73, 128, 66, 79, 87, 84, + 73, 197, 67, 72, 69, 67, 75, 128, 67, 85, 82, 86, 69, 128, 68, 65, 76, + 68, 65, 128, 68, 65, 76, 69, 84, 128, 68, 68, 65, 72, 65, 204, 68, 69, + 65, 84, 72, 128, 68, 79, 66, 82, 79, 128, 68, 90, 69, 76, 79, 128, 69, + 84, 69, 82, 79, 206, 70, 65, 67, 84, 79, 210, 70, 73, 71, 85, 82, 197, + 70, 76, 79, 79, 82, 128, 70, 79, 82, 75, 69, 196, 70, 82, 73, 84, 85, + 128, 71, 65, 80, 80, 69, 196, 71, 69, 78, 73, 75, 201, 71, 72, 65, 73, + 78, 128, 71, 72, 79, 83, 84, 128, 71, 72, 85, 78, 78, 193, 71, 78, 89, + 73, 83, 128, 71, 79, 82, 71, 73, 128, 72, 65, 77, 77, 69, 210, 72, 65, + 77, 90, 65, 128, 72, 73, 82, 73, 81, 128, 72, 79, 76, 65, 77, 128, 72, + 79, 82, 83, 69, 128, 72, 87, 65, 73, 82, 128, 73, 65, 85, 68, 65, 128, + 75, 65, 90, 65, 75, 200, 75, 73, 89, 69, 79, 203, 75, 76, 65, 83, 77, + 193, 76, 65, 66, 79, 82, 128, 76, 65, 82, 71, 69, 210, 76, 65, 85, 76, + 65, 128, 76, 69, 83, 83, 69, 210, 77, 69, 84, 65, 76, 128, 77, 79, 85, + 84, 72, 128, 78, 65, 83, 72, 73, 128, 78, 79, 84, 69, 83, 128, 79, 71, + 79, 78, 69, 203, 79, 76, 73, 71, 79, 206, 79, 82, 78, 65, 84, 197, 80, + 73, 65, 83, 77, 193, 80, 76, 65, 78, 67, 203, 80, 79, 73, 78, 84, 128, + 80, 79, 87, 69, 82, 128, 80, 82, 79, 84, 79, 211, 81, 65, 84, 65, 78, + 128, 81, 85, 69, 69, 78, 128, 81, 85, 73, 76, 76, 128, 82, 69, 65, 67, + 72, 128, 82, 71, 89, 65, 78, 128, 82, 73, 84, 83, 73, 128, 83, 67, 82, + 69, 69, 206, 83, 69, 71, 78, 79, 128, 83, 69, 82, 73, 70, 211, 83, 69, + 83, 65, 77, 197, 83, 72, 65, 78, 71, 128, 83, 72, 65, 82, 80, 128, 83, + 72, 67, 72, 65, 128, 83, 72, 69, 69, 80, 128, 83, 72, 69, 76, 70, 128, + 83, 72, 69, 76, 76, 128, 83, 72, 79, 82, 84, 211, 83, 72, 87, 65, 65, + 128, 83, 72, 87, 73, 73, 128, 83, 72, 87, 79, 79, 128, 83, 73, 71, 78, + 83, 128, 83, 73, 78, 68, 72, 201, 83, 73, 88, 84, 89, 128, 83, 76, 79, + 86, 79, 128, 83, 80, 69, 65, 82, 128, 83, 80, 73, 82, 73, 212, 83, 84, + 79, 67, 75, 128, 83, 84, 85, 68, 89, 128, 83, 85, 75, 85, 78, 128, 84, + 65, 78, 78, 69, 196, 84, 69, 76, 79, 85, 211, 84, 72, 87, 65, 65, 128, + 84, 73, 71, 69, 82, 128, 84, 73, 75, 69, 85, 212, 84, 82, 85, 78, 75, + 128, 84, 83, 65, 68, 73, 128, 84, 83, 72, 69, 71, 128, 84, 83, 72, 69, + 83, 128, 84, 87, 69, 76, 86, 197, 87, 65, 84, 67, 72, 128, 87, 79, 77, + 65, 78, 128, 89, 69, 83, 84, 85, 128, 89, 79, 45, 89, 65, 128, 89, 85, + 45, 89, 69, 128, 90, 90, 73, 69, 84, 128, 45, 67, 72, 65, 76, 128, 45, + 75, 72, 89, 85, 196, 45, 80, 72, 82, 85, 128, 65, 68, 68, 65, 75, 128, + 65, 71, 65, 73, 78, 128, 65, 72, 83, 68, 65, 128, 65, 76, 73, 70, 85, + 128, 65, 77, 79, 85, 78, 212, 65, 78, 80, 69, 65, 128, 65, 80, 65, 82, + 84, 128, 65, 80, 82, 73, 76, 128, 65, 82, 69, 80, 65, 128, 65, 82, 73, + 69, 83, 128, 65, 82, 76, 65, 85, 199, 65, 82, 79, 85, 82, 193, 65, 82, + 82, 65, 89, 128, 65, 82, 84, 65, 66, 197, 66, 66, 73, 69, 80, 128, 66, + 66, 73, 69, 84, 128, 66, 66, 73, 69, 88, 128, 66, 66, 85, 79, 80, 128, + 66, 66, 85, 79, 88, 128, 66, 66, 85, 82, 88, 128, 66, 69, 69, 84, 65, + 128, 66, 69, 70, 79, 82, 197, 66, 69, 72, 69, 72, 128, 66, 69, 73, 84, + 72, 128, 66, 72, 69, 84, 72, 128, 66, 73, 82, 71, 65, 128, 66, 73, 84, + 73, 78, 199, 66, 76, 65, 78, 75, 128, 66, 76, 79, 79, 68, 128, 66, 82, + 65, 67, 69, 128, 66, 82, 65, 78, 67, 200, 66, 82, 69, 65, 84, 200, 66, + 82, 85, 83, 72, 128, 66, 83, 84, 65, 82, 128, 66, 85, 76, 76, 69, 212, + 67, 65, 77, 78, 85, 195, 67, 65, 78, 67, 69, 204, 67, 65, 85, 68, 65, + 128, 67, 67, 72, 65, 65, 128, 67, 67, 72, 69, 69, 128, 67, 69, 65, 76, + 67, 128, 67, 69, 73, 82, 84, 128, 67, 72, 65, 68, 65, 128, 67, 72, 65, + 73, 82, 128, 67, 72, 65, 78, 71, 128, 67, 72, 73, 76, 68, 128, 67, 72, + 73, 78, 71, 128, 67, 72, 79, 75, 69, 128, 67, 72, 85, 76, 65, 128, 67, + 72, 85, 79, 80, 128, 67, 72, 85, 79, 84, 128, 67, 72, 85, 79, 88, 128, + 67, 72, 85, 82, 88, 128, 67, 72, 89, 82, 88, 128, 67, 76, 79, 85, 68, + 128, 67, 79, 69, 78, 71, 128, 67, 79, 76, 79, 82, 128, 67, 79, 77, 69, + 84, 128, 67, 79, 77, 73, 78, 199, 67, 79, 77, 77, 79, 206, 67, 79, 86, + 69, 82, 128, 67, 82, 69, 68, 73, 212, 67, 82, 79, 73, 88, 128, 68, 65, + 65, 83, 85, 128, 68, 65, 76, 65, 84, 200, 68, 65, 82, 71, 65, 128, 68, + 65, 86, 73, 68, 128, 68, 68, 68, 72, 65, 128, 68, 68, 73, 69, 80, 128, + 68, 68, 73, 69, 88, 128, 68, 68, 85, 79, 80, 128, 68, 68, 85, 79, 88, + 128, 68, 68, 85, 82, 88, 128, 68, 69, 76, 69, 84, 197, 68, 69, 82, 69, + 84, 128, 68, 73, 70, 65, 84, 128, 68, 73, 80, 84, 69, 128, 68, 73, 86, + 73, 68, 197, 68, 79, 77, 65, 73, 206, 68, 79, 85, 66, 84, 128, 68, 82, + 73, 86, 69, 128, 68, 82, 79, 80, 83, 128, 69, 69, 75, 65, 65, 128, 69, + 73, 71, 72, 84, 217, 69, 76, 69, 86, 69, 206, 69, 76, 73, 70, 73, 128, + 69, 78, 84, 69, 82, 128, 69, 79, 76, 72, 88, 128, 69, 81, 85, 73, 68, + 128, 69, 85, 45, 69, 85, 128, 69, 88, 73, 83, 84, 128, 70, 65, 65, 70, + 85, 128, 70, 65, 73, 72, 85, 128, 70, 65, 84, 72, 65, 128, 70, 69, 65, + 82, 78, 128, 70, 72, 84, 79, 82, 193, 70, 73, 69, 76, 68, 128, 70, 73, + 70, 84, 72, 128, 70, 73, 71, 72, 84, 128, 70, 73, 76, 76, 69, 196, 70, + 73, 78, 73, 84, 197, 70, 76, 79, 87, 69, 210, 70, 76, 85, 84, 69, 128, + 70, 79, 76, 76, 89, 128, 70, 79, 82, 67, 69, 128, 70, 79, 82, 84, 69, + 128, 70, 82, 65, 77, 69, 128, 70, 82, 69, 78, 67, 200, 70, 82, 79, 87, + 78, 128, 71, 65, 65, 70, 85, 128, 71, 65, 68, 79, 76, 128, 71, 65, 77, + 65, 76, 128, 71, 65, 77, 76, 65, 128, 71, 65, 78, 77, 65, 128, 71, 65, + 82, 79, 78, 128, 71, 69, 78, 84, 76, 197, 71, 69, 82, 69, 83, 200, 71, + 69, 82, 77, 65, 206, 71, 71, 73, 69, 80, 128, 71, 71, 73, 69, 88, 128, + 71, 71, 85, 79, 80, 128, 71, 71, 85, 79, 84, 128, 71, 71, 85, 79, 88, + 128, 71, 71, 85, 82, 88, 128, 71, 71, 87, 65, 65, 128, 71, 71, 87, 69, + 69, 128, 71, 73, 77, 69, 76, 128, 71, 73, 78, 73, 73, 128, 71, 76, 69, + 73, 67, 200, 71, 82, 65, 67, 69, 128, 71, 82, 65, 73, 78, 128, 71, 82, + 65, 83, 83, 128, 72, 45, 84, 89, 80, 197, 72, 65, 45, 72, 65, 128, 72, + 65, 71, 76, 65, 218, 72, 65, 73, 84, 85, 128, 72, 65, 78, 68, 83, 128, + 72, 69, 65, 86, 69, 206, 72, 73, 68, 73, 78, 199, 72, 76, 73, 69, 80, + 128, 72, 76, 73, 69, 88, 128, 72, 76, 85, 79, 80, 128, 72, 76, 85, 79, + 88, 128, 72, 76, 85, 82, 88, 128, 72, 76, 89, 82, 88, 128, 72, 77, 73, + 69, 80, 128, 72, 77, 73, 69, 88, 128, 72, 77, 85, 79, 80, 128, 72, 77, + 85, 79, 88, 128, 72, 77, 85, 82, 88, 128, 72, 77, 89, 82, 88, 128, 72, + 78, 73, 69, 80, 128, 72, 78, 73, 69, 84, 128, 72, 78, 73, 69, 88, 128, + 72, 78, 85, 79, 88, 128, 72, 79, 79, 82, 85, 128, 72, 79, 85, 83, 69, + 128, 72, 85, 77, 65, 78, 128, 72, 85, 82, 65, 78, 128, 72, 88, 73, 69, + 80, 128, 72, 88, 73, 69, 84, 128, 72, 88, 73, 69, 88, 128, 72, 88, 85, + 79, 80, 128, 72, 88, 85, 79, 84, 128, 72, 88, 85, 79, 88, 128, 72, 89, + 80, 72, 69, 206, 73, 67, 72, 79, 85, 128, 73, 71, 71, 87, 83, 128, 73, + 78, 78, 69, 82, 128, 73, 83, 65, 75, 73, 193, 74, 74, 73, 69, 80, 128, + 74, 74, 73, 69, 84, 128, 74, 74, 73, 69, 88, 128, 74, 74, 85, 79, 80, + 128, 74, 74, 85, 79, 88, 128, 74, 74, 85, 82, 88, 128, 74, 79, 89, 79, + 85, 211, 74, 85, 68, 71, 69, 128, 74, 85, 69, 85, 73, 128, 75, 65, 65, + 70, 85, 128, 75, 65, 73, 82, 73, 128, 75, 65, 83, 82, 65, 128, 75, 65, + 84, 65, 86, 193, 75, 65, 85, 78, 65, 128, 75, 69, 69, 83, 85, 128, 75, + 69, 72, 69, 72, 128, 75, 69, 76, 86, 73, 206, 75, 69, 78, 65, 84, 128, + 75, 72, 65, 78, 68, 193, 75, 72, 65, 80, 72, 128, 75, 72, 85, 65, 84, + 128, 75, 72, 87, 65, 73, 128, 75, 78, 73, 70, 69, 128, 75, 79, 79, 80, + 79, 128, 75, 85, 83, 77, 65, 128, 75, 88, 87, 65, 65, 128, 75, 88, 87, + 69, 69, 128, 76, 45, 84, 89, 80, 197, 76, 65, 65, 77, 85, 128, 76, 65, + 71, 85, 83, 128, 76, 65, 77, 66, 68, 193, 76, 65, 85, 75, 65, 218, 76, + 69, 77, 79, 73, 128, 76, 73, 66, 82, 65, 128, 76, 73, 77, 73, 84, 128, + 76, 73, 78, 69, 83, 128, 76, 73, 81, 85, 73, 196, 76, 79, 78, 71, 65, + 128, 76, 79, 84, 85, 83, 128, 76, 79, 85, 82, 69, 128, 77, 65, 68, 68, + 65, 128, 77, 65, 68, 68, 65, 200, 77, 65, 72, 72, 65, 128, 77, 65, 73, + 82, 85, 128, 77, 65, 78, 78, 65, 128, 77, 65, 78, 78, 65, 218, 77, 65, + 81, 65, 70, 128, 77, 65, 82, 67, 72, 128, 77, 65, 83, 79, 82, 193, 77, + 69, 69, 77, 85, 128, 77, 69, 73, 90, 73, 128, 77, 69, 76, 79, 78, 128, + 77, 69, 77, 66, 69, 210, 77, 69, 82, 75, 72, 193, 77, 69, 84, 69, 71, + 128, 77, 69, 90, 90, 79, 128, 77, 71, 73, 69, 88, 128, 77, 71, 85, 79, + 80, 128, 77, 71, 85, 79, 88, 128, 77, 71, 85, 82, 88, 128, 77, 73, 75, + 82, 73, 128, 77, 73, 75, 82, 79, 206, 77, 73, 82, 69, 68, 128, 77, 73, + 83, 82, 65, 128, 77, 79, 68, 69, 76, 128, 77, 79, 68, 85, 76, 207, 77, + 79, 78, 84, 72, 128, 77, 79, 85, 78, 68, 128, 77, 85, 78, 65, 72, 128, + 77, 85, 83, 73, 67, 128, 78, 65, 82, 82, 79, 215, 78, 65, 85, 68, 73, + 218, 78, 65, 88, 73, 65, 206, 78, 66, 73, 69, 80, 128, 78, 66, 73, 69, + 88, 128, 78, 66, 85, 82, 88, 128, 78, 66, 89, 82, 88, 128, 78, 68, 73, + 69, 88, 128, 78, 68, 85, 82, 88, 128, 78, 71, 65, 65, 73, 128, 78, 71, + 73, 69, 80, 128, 78, 71, 73, 69, 88, 128, 78, 71, 79, 69, 72, 128, 78, + 71, 85, 79, 84, 128, 78, 71, 85, 79, 88, 128, 78, 73, 78, 69, 84, 217, + 78, 74, 73, 69, 80, 128, 78, 74, 73, 69, 84, 128, 78, 74, 73, 69, 88, + 128, 78, 74, 85, 79, 88, 128, 78, 74, 85, 82, 88, 128, 78, 74, 89, 82, + 88, 128, 78, 78, 71, 65, 65, 128, 78, 78, 71, 73, 73, 128, 78, 78, 71, + 79, 79, 128, 78, 79, 79, 78, 85, 128, 78, 79, 84, 67, 72, 128, 78, 79, + 84, 84, 79, 128, 78, 82, 85, 82, 88, 128, 78, 82, 89, 82, 88, 128, 78, + 85, 77, 69, 82, 207, 78, 89, 73, 69, 80, 128, 78, 89, 73, 69, 84, 128, + 78, 89, 73, 69, 88, 128, 78, 89, 85, 79, 80, 128, 78, 89, 85, 79, 88, + 128, 78, 90, 73, 69, 80, 128, 78, 90, 73, 69, 88, 128, 78, 90, 85, 79, + 88, 128, 78, 90, 85, 82, 88, 128, 78, 90, 89, 82, 88, 128, 79, 66, 74, + 69, 67, 212, 79, 74, 69, 79, 78, 128, 79, 76, 73, 86, 69, 128, 79, 78, + 75, 65, 82, 128, 79, 80, 84, 73, 79, 206, 79, 84, 72, 65, 76, 128, 79, + 85, 78, 75, 73, 193, 79, 88, 69, 73, 65, 201, 80, 65, 65, 84, 85, 128, + 80, 65, 83, 69, 81, 128, 80, 65, 83, 85, 81, 128, 80, 65, 84, 65, 75, + 128, 80, 65, 90, 69, 82, 128, 80, 69, 65, 67, 69, 128, 80, 69, 69, 90, + 73, 128, 80, 69, 72, 69, 72, 128, 80, 69, 73, 84, 72, 128, 80, 69, 78, + 83, 85, 128, 80, 69, 79, 82, 84, 200, 80, 69, 82, 84, 72, 207, 80, 69, + 83, 69, 84, 193, 80, 72, 78, 65, 69, 203, 80, 72, 85, 78, 71, 128, 80, + 73, 65, 78, 79, 128, 80, 76, 85, 84, 79, 128, 80, 79, 69, 84, 73, 195, + 80, 79, 78, 68, 79, 128, 80, 82, 73, 78, 84, 128, 80, 82, 79, 79, 70, + 128, 80, 82, 79, 86, 69, 128, 81, 65, 65, 70, 85, 128, 81, 65, 68, 77, + 65, 128, 81, 65, 77, 65, 84, 211, 81, 65, 82, 78, 69, 217, 81, 72, 87, + 65, 65, 128, 81, 72, 87, 69, 69, 128, 82, 45, 67, 82, 69, 197, 82, 65, + 73, 68, 65, 128, 82, 65, 83, 72, 65, 128, 82, 65, 83, 79, 85, 204, 82, + 65, 84, 73, 79, 128, 82, 69, 67, 79, 82, 196, 82, 69, 84, 85, 82, 206, + 82, 69, 86, 73, 65, 128, 82, 69, 86, 77, 65, 128, 82, 72, 79, 84, 73, + 195, 82, 73, 86, 69, 82, 128, 82, 78, 79, 79, 78, 128, 82, 79, 66, 65, + 84, 128, 82, 82, 85, 79, 88, 128, 82, 82, 85, 82, 88, 128, 82, 82, 89, + 82, 88, 128, 82, 85, 80, 73, 73, 128, 82, 87, 65, 72, 65, 128, 83, 65, + 68, 72, 69, 128, 83, 65, 70, 72, 65, 128, 83, 65, 77, 69, 75, 200, 83, + 65, 77, 75, 65, 128, 83, 65, 77, 89, 79, 203, 83, 65, 78, 65, 72, 128, + 83, 65, 85, 73, 76, 128, 83, 69, 69, 78, 85, 128, 83, 69, 73, 83, 77, + 193, 83, 69, 78, 84, 73, 128, 83, 72, 69, 69, 78, 128, 83, 72, 69, 81, + 69, 204, 83, 72, 69, 86, 65, 128, 83, 72, 73, 73, 78, 128, 83, 72, 79, + 79, 84, 128, 83, 72, 79, 82, 84, 128, 83, 72, 85, 79, 80, 128, 83, 72, + 85, 79, 88, 128, 83, 72, 85, 82, 88, 128, 83, 72, 89, 82, 88, 128, 83, + 73, 88, 84, 72, 128, 83, 76, 65, 86, 69, 128, 83, 76, 73, 67, 69, 128, + 83, 76, 79, 80, 69, 128, 83, 77, 69, 65, 82, 128, 83, 77, 73, 76, 69, + 128, 83, 78, 65, 75, 69, 128, 83, 78, 79, 85, 84, 128, 83, 79, 85, 78, + 68, 128, 83, 79, 87, 73, 76, 207, 83, 80, 73, 67, 69, 128, 83, 80, 79, + 79, 78, 128, 83, 80, 85, 78, 71, 211, 83, 81, 85, 73, 83, 200, 83, 83, + 73, 69, 80, 128, 83, 83, 73, 69, 88, 128, 83, 83, 89, 82, 88, 128, 83, + 84, 65, 78, 68, 128, 83, 84, 65, 82, 75, 128, 83, 84, 69, 65, 77, 128, + 83, 84, 79, 78, 69, 128, 83, 84, 79, 86, 69, 128, 83, 87, 69, 69, 84, + 128, 83, 87, 79, 82, 68, 128, 83, 89, 82, 77, 65, 128, 84, 65, 76, 69, + 78, 212, 84, 65, 80, 69, 82, 128, 84, 67, 72, 69, 72, 128, 84, 69, 73, + 87, 83, 128, 84, 69, 86, 73, 82, 128, 84, 72, 73, 71, 72, 128, 84, 72, + 73, 82, 68, 128, 84, 72, 73, 82, 68, 211, 84, 72, 73, 84, 65, 128, 84, + 72, 79, 78, 71, 128, 84, 72, 85, 78, 71, 128, 84, 73, 78, 78, 69, 128, + 84, 73, 80, 80, 73, 128, 84, 76, 72, 69, 69, 128, 84, 82, 65, 67, 75, + 128, 84, 82, 73, 84, 79, 211, 84, 82, 85, 84, 72, 128, 84, 83, 69, 82, + 69, 128, 84, 84, 83, 69, 69, 128, 84, 84, 84, 72, 65, 128, 84, 85, 71, + 82, 73, 203, 84, 85, 82, 79, 50, 128, 84, 89, 80, 69, 45, 177, 84, 89, + 80, 69, 45, 178, 84, 89, 80, 69, 45, 179, 84, 89, 80, 69, 45, 180, 84, + 89, 80, 69, 45, 181, 84, 89, 80, 69, 45, 182, 84, 89, 80, 69, 45, 183, + 85, 78, 73, 84, 89, 128, 85, 80, 87, 65, 82, 196, 86, 65, 65, 86, 85, + 128, 86, 65, 83, 73, 83, 128, 86, 65, 84, 72, 89, 128, 86, 69, 67, 84, + 79, 210, 86, 69, 82, 71, 69, 128, 86, 73, 82, 71, 65, 128, 86, 73, 82, + 71, 79, 128, 86, 79, 76, 85, 77, 197, 87, 65, 65, 86, 85, 128, 87, 65, + 83, 76, 65, 128, 87, 72, 69, 69, 76, 128, 87, 73, 78, 74, 65, 128, 87, + 82, 69, 65, 84, 200, 87, 82, 79, 78, 71, 128, 88, 69, 83, 84, 69, 211, + 89, 65, 45, 89, 79, 128, 89, 65, 65, 68, 79, 128, 89, 65, 65, 82, 85, + 128, 89, 65, 68, 68, 72, 128, 89, 65, 71, 72, 72, 128, 89, 65, 75, 72, + 72, 128, 89, 69, 79, 45, 79, 128, 89, 69, 79, 45, 85, 128, 89, 69, 84, + 73, 86, 128, 89, 73, 90, 69, 84, 128, 89, 85, 45, 69, 79, 128, 90, 65, + 82, 81, 65, 128, 90, 65, 89, 73, 78, 128, 90, 72, 65, 73, 78, 128, 90, + 72, 85, 79, 80, 128, 90, 72, 85, 79, 88, 128, 90, 72, 85, 82, 88, 128, + 90, 72, 89, 82, 88, 128, 90, 73, 76, 68, 69, 128, 90, 73, 78, 79, 82, + 128, 90, 89, 71, 79, 83, 128, 90, 90, 73, 69, 80, 128, 90, 90, 73, 69, + 88, 128, 90, 90, 85, 82, 88, 128, 90, 90, 89, 82, 88, 128, 78, 65, 71, + 82, 201, 83, 72, 79, 82, 212, 83, 72, 69, 69, 206, 90, 69, 82, 79, 128, + 82, 79, 77, 65, 206, 84, 73, 76, 68, 197, 76, 69, 70, 84, 128, 79, 71, + 72, 65, 205, 86, 79, 67, 65, 204, 78, 79, 82, 84, 200, 67, 85, 82, 76, + 217, 65, 84, 84, 73, 195, 83, 79, 85, 84, 200, 66, 69, 76, 79, 215, 66, + 85, 72, 73, 196, 80, 79, 73, 78, 212, 84, 65, 67, 75, 128, 68, 65, 83, + 72, 128, 68, 79, 87, 78, 128, 73, 79, 84, 65, 128, 78, 45, 65, 82, 217, + 82, 69, 83, 84, 128, 71, 72, 65, 73, 206, 65, 67, 85, 84, 197, 66, 69, + 84, 65, 128, 66, 82, 69, 86, 197, 67, 79, 77, 77, 193, 71, 82, 65, 86, + 197, 75, 79, 69, 84, 128, 86, 65, 82, 73, 193, 90, 69, 84, 65, 128, 67, + 72, 69, 83, 211, 67, 85, 82, 76, 128, 83, 72, 69, 76, 204, 84, 72, 69, + 84, 193, 83, 79, 85, 78, 196, 85, 78, 73, 79, 206, 65, 76, 69, 70, 128, + 65, 84, 84, 65, 203, 68, 79, 84, 83, 128, 70, 79, 82, 84, 217, 72, 65, + 76, 70, 128, 78, 79, 84, 69, 128, 84, 79, 78, 65, 204, 73, 77, 65, 71, + 197, 80, 76, 85, 83, 128, 65, 71, 79, 71, 201, 69, 77, 80, 84, 217, 72, + 69, 65, 82, 212, 83, 85, 73, 84, 128, 70, 73, 70, 84, 217, 70, 73, 76, + 76, 128, 75, 65, 84, 79, 128, 75, 69, 72, 69, 200, 76, 65, 82, 71, 197, + 83, 72, 65, 68, 128, 66, 69, 71, 73, 206, 67, 65, 82, 69, 212, 70, 65, + 82, 83, 201, 70, 73, 82, 69, 128, 72, 79, 82, 73, 128, 75, 65, 80, 80, + 193, 77, 79, 79, 78, 128, 83, 69, 86, 69, 206, 83, 72, 69, 73, 128, 83, + 72, 73, 78, 128, 83, 85, 78, 71, 128, 84, 73, 67, 75, 128, 67, 76, 69, + 70, 128, 67, 82, 79, 83, 211, 70, 65, 84, 72, 193, 70, 73, 82, 83, 212, + 77, 65, 68, 68, 193, 81, 85, 65, 68, 128, 82, 85, 80, 69, 197, 83, 73, + 71, 77, 193, 83, 84, 69, 77, 128, 84, 67, 72, 69, 200, 84, 73, 77, 69, + 211, 84, 83, 72, 69, 199, 89, 65, 78, 71, 128, 65, 76, 84, 65, 128, 66, + 69, 72, 69, 200, 67, 72, 69, 67, 203, 67, 82, 79, 80, 128, 68, 65, 77, + 77, 193, 70, 73, 84, 65, 128, 71, 82, 69, 65, 212, 72, 65, 78, 68, 128, + 73, 90, 72, 69, 128, 74, 79, 73, 78, 128, 75, 65, 80, 65, 128, 75, 65, + 83, 82, 193, 75, 72, 69, 73, 128, 75, 87, 65, 65, 128, 76, 79, 78, 71, + 128, 78, 71, 79, 69, 200, 79, 66, 79, 76, 211, 80, 69, 72, 69, 200, 82, + 65, 70, 69, 128, 82, 78, 79, 79, 206, 82, 84, 65, 71, 211, 83, 67, 72, + 87, 193, 83, 72, 65, 82, 208, 84, 72, 65, 65, 128, 84, 72, 69, 69, 128, + 86, 65, 78, 69, 128, 87, 65, 86, 69, 128, 87, 73, 78, 68, 128, 65, 76, + 76, 79, 128, 66, 73, 82, 68, 128, 67, 65, 82, 79, 206, 67, 72, 65, 82, + 128, 67, 72, 73, 78, 128, 67, 72, 82, 79, 193, 67, 73, 69, 85, 195, 67, + 87, 65, 65, 128, 68, 69, 76, 84, 193, 70, 79, 79, 84, 128, 71, 72, 65, + 78, 128, 71, 79, 76, 68, 128, 71, 82, 65, 83, 211, 72, 65, 84, 65, 198, + 73, 69, 85, 78, 199, 74, 72, 65, 78, 128, 75, 69, 84, 84, 201, 75, 72, + 65, 82, 128, 76, 76, 76, 65, 128, 76, 79, 79, 80, 128, 77, 78, 65, 83, + 128, 77, 85, 83, 73, 195, 77, 87, 65, 65, 128, 78, 87, 65, 65, 128, 79, + 85, 84, 69, 210, 79, 88, 69, 73, 193, 80, 65, 80, 69, 210, 80, 69, 68, + 65, 204, 80, 72, 65, 82, 128, 80, 79, 76, 69, 128, 80, 82, 73, 77, 197, + 80, 87, 65, 65, 128, 82, 79, 79, 84, 128, 83, 69, 69, 78, 128, 83, 72, + 87, 65, 128, 83, 73, 76, 75, 128, 83, 73, 77, 65, 128, 83, 84, 65, 82, + 212, 83, 87, 65, 65, 128, 83, 87, 65, 83, 200, 84, 72, 73, 73, 128, 84, + 72, 73, 82, 196, 84, 83, 72, 65, 128, 84, 84, 72, 79, 128, 84, 87, 65, + 65, 128, 87, 73, 78, 69, 128, 89, 65, 71, 72, 128, 89, 65, 90, 72, 128, + 89, 73, 87, 78, 128, 89, 87, 65, 65, 128, 90, 72, 65, 82, 128, 90, 72, + 69, 69, 128, 45, 68, 90, 85, 196, 65, 76, 70, 65, 128, 65, 80, 69, 83, + 207, 65, 82, 71, 73, 128, 66, 66, 85, 84, 128, 66, 69, 65, 84, 128, 66, + 76, 65, 68, 197, 66, 76, 85, 69, 128, 66, 79, 78, 69, 128, 66, 82, 85, + 83, 200, 66, 85, 75, 89, 128, 66, 90, 85, 78, 199, 67, 65, 82, 84, 128, + 67, 85, 79, 80, 128, 67, 85, 82, 86, 197, 67, 87, 73, 73, 128, 67, 87, + 79, 79, 128, 68, 65, 76, 69, 212, 68, 68, 85, 82, 128, 68, 69, 69, 82, + 128, 68, 90, 72, 65, 128, 68, 90, 72, 69, 128, 68, 90, 74, 69, 128, 69, + 65, 82, 84, 200, 69, 82, 65, 83, 197, 70, 69, 69, 68, 128, 70, 73, 83, + 72, 128, 70, 76, 65, 71, 128, 70, 76, 65, 84, 128, 70, 82, 79, 71, 128, + 70, 87, 65, 65, 128, 71, 65, 84, 69, 128, 71, 67, 73, 71, 128, 71, 71, + 79, 80, 128, 71, 71, 85, 79, 128, 71, 72, 65, 68, 128, 71, 72, 72, 65, + 128, 71, 73, 77, 69, 204, 71, 79, 65, 76, 128, 71, 82, 65, 67, 197, 71, + 83, 85, 77, 128, 71, 89, 65, 83, 128, 71, 89, 79, 78, 128, 72, 65, 84, + 69, 128, 72, 65, 86, 69, 128, 72, 66, 65, 83, 193, 72, 69, 82, 85, 128, + 72, 72, 65, 65, 128, 72, 73, 69, 85, 200, 72, 88, 73, 84, 128, 72, 88, + 79, 80, 128, 72, 88, 85, 79, 128, 74, 65, 68, 69, 128, 74, 69, 69, 77, + 128, 74, 72, 69, 72, 128, 74, 74, 73, 69, 128, 74, 74, 85, 84, 128, 75, + 65, 75, 79, 128, 75, 72, 65, 72, 128, 75, 72, 65, 78, 199, 75, 72, 72, + 65, 128, 75, 78, 73, 70, 197, 75, 83, 83, 65, 128, 75, 87, 73, 73, 128, + 75, 87, 79, 79, 128, 76, 69, 65, 70, 128, 76, 73, 87, 78, 128, 76, 79, + 78, 71, 193, 76, 79, 87, 45, 185, 76, 87, 65, 65, 128, 76, 87, 73, 73, + 128, 76, 87, 79, 79, 128, 77, 69, 65, 84, 128, 77, 69, 69, 77, 128, 77, + 69, 69, 84, 128, 77, 69, 83, 79, 128, 77, 73, 69, 85, 205, 77, 79, 85, + 78, 196, 77, 87, 73, 73, 128, 77, 87, 79, 79, 128, 78, 65, 77, 69, 128, + 78, 65, 78, 65, 128, 78, 66, 73, 69, 128, 78, 73, 69, 85, 206, 78, 78, + 78, 65, 128, 78, 79, 68, 69, 128, 78, 89, 73, 80, 128, 78, 89, 79, 80, + 128, 78, 90, 85, 80, 128, 80, 65, 87, 78, 128, 80, 73, 69, 85, 208, 80, + 73, 87, 82, 128, 80, 76, 65, 67, 197, 80, 79, 85, 78, 196, 80, 87, 73, + 73, 128, 80, 87, 79, 79, 128, 81, 85, 79, 84, 197, 82, 65, 89, 83, 128, + 82, 66, 65, 83, 193, 82, 73, 69, 85, 204, 82, 73, 83, 72, 128, 82, 79, + 79, 75, 128, 82, 87, 65, 65, 128, 83, 65, 76, 76, 193, 83, 65, 76, 84, + 128, 83, 69, 65, 76, 128, 83, 72, 65, 65, 128, 83, 72, 65, 84, 128, 83, + 72, 69, 69, 128, 83, 72, 72, 65, 128, 83, 72, 73, 70, 212, 83, 72, 79, + 71, 201, 83, 72, 85, 82, 128, 83, 72, 87, 69, 128, 83, 72, 87, 73, 128, + 83, 72, 87, 79, 128, 83, 76, 85, 82, 128, 83, 77, 65, 83, 200, 83, 78, + 79, 85, 212, 83, 80, 65, 68, 197, 83, 81, 85, 65, 212, 83, 84, 65, 70, + 198, 83, 85, 75, 85, 206, 83, 87, 73, 73, 128, 83, 87, 79, 79, 128, 84, + 69, 88, 84, 128, 84, 72, 69, 82, 197, 84, 72, 79, 79, 128, 84, 73, 77, + 69, 128, 84, 73, 87, 78, 128, 84, 76, 72, 65, 128, 84, 76, 72, 69, 128, + 84, 76, 72, 73, 128, 84, 76, 72, 79, 128, 84, 82, 69, 69, 128, 84, 82, + 85, 69, 128, 84, 83, 72, 69, 128, 84, 87, 73, 73, 128, 84, 87, 79, 79, + 128, 85, 78, 68, 69, 210, 86, 69, 68, 69, 128, 86, 73, 68, 65, 128, 87, + 65, 76, 75, 128, 87, 65, 83, 76, 193, 87, 65, 84, 69, 210, 87, 72, 79, + 76, 197, 87, 79, 79, 68, 128, 87, 79, 79, 76, 128, 87, 89, 78, 78, 128, + 89, 65, 75, 72, 128, 89, 65, 84, 73, 128, 89, 69, 82, 73, 128, 89, 79, + 45, 73, 128, 89, 79, 71, 72, 128, 89, 85, 45, 73, 128, 89, 87, 73, 73, + 128, 89, 87, 79, 79, 128, 90, 65, 73, 78, 128, 90, 65, 81, 69, 198, 90, + 65, 84, 65, 128, 90, 76, 65, 77, 193, 45, 67, 72, 65, 210, 65, 69, 83, + 67, 128, 65, 70, 84, 69, 210, 65, 72, 83, 65, 128, 65, 73, 76, 77, 128, + 65, 73, 78, 78, 128, 65, 75, 66, 65, 210, 65, 76, 71, 73, 218, 65, 76, + 76, 65, 200, 65, 76, 80, 65, 128, 65, 77, 80, 83, 128, 65, 78, 72, 85, + 128, 65, 78, 75, 72, 128, 65, 78, 83, 85, 218, 65, 82, 77, 89, 128, 65, + 84, 78, 65, 200, 65, 85, 78, 78, 128, 65, 89, 65, 72, 128, 66, 48, 49, + 56, 128, 66, 48, 49, 57, 128, 66, 48, 50, 50, 128, 66, 48, 51, 52, 128, + 66, 48, 52, 55, 128, 66, 48, 52, 57, 128, 66, 48, 53, 54, 128, 66, 48, + 54, 51, 128, 66, 48, 54, 52, 128, 66, 48, 55, 57, 128, 66, 48, 56, 50, + 128, 66, 48, 56, 51, 128, 66, 48, 56, 54, 128, 66, 48, 56, 57, 128, 66, + 49, 48, 53, 198, 66, 49, 48, 53, 205, 66, 49, 48, 54, 198, 66, 49, 48, + 54, 205, 66, 49, 48, 55, 198, 66, 49, 48, 55, 205, 66, 49, 48, 56, 198, + 66, 49, 48, 56, 205, 66, 49, 48, 57, 198, 66, 49, 48, 57, 205, 66, 49, + 51, 50, 128, 66, 49, 52, 50, 128, 66, 49, 52, 54, 128, 66, 49, 53, 48, + 128, 66, 49, 53, 50, 128, 66, 49, 53, 51, 128, 66, 49, 53, 52, 128, 66, + 49, 53, 53, 128, 66, 49, 53, 55, 128, 66, 49, 53, 56, 128, 66, 49, 54, + 48, 128, 66, 49, 54, 49, 128, 66, 49, 54, 52, 128, 66, 49, 54, 53, 128, + 66, 49, 54, 54, 128, 66, 49, 54, 55, 128, 66, 49, 54, 56, 128, 66, 49, + 54, 57, 128, 66, 49, 55, 48, 128, 66, 49, 55, 49, 128, 66, 49, 55, 50, + 128, 66, 49, 55, 52, 128, 66, 49, 55, 55, 128, 66, 49, 55, 56, 128, 66, + 49, 55, 57, 128, 66, 49, 56, 48, 128, 66, 49, 56, 49, 128, 66, 49, 56, + 50, 128, 66, 49, 56, 51, 128, 66, 49, 56, 52, 128, 66, 49, 56, 53, 128, + 66, 49, 56, 57, 128, 66, 49, 57, 48, 128, 66, 50, 48, 48, 128, 66, 50, + 48, 49, 128, 66, 50, 48, 50, 128, 66, 50, 48, 51, 128, 66, 50, 48, 52, + 128, 66, 50, 48, 53, 128, 66, 50, 48, 54, 128, 66, 50, 48, 55, 128, 66, + 50, 48, 56, 128, 66, 50, 48, 57, 128, 66, 50, 49, 48, 128, 66, 50, 49, + 49, 128, 66, 50, 49, 50, 128, 66, 50, 49, 51, 128, 66, 50, 49, 52, 128, + 66, 50, 49, 53, 128, 66, 50, 49, 54, 128, 66, 50, 49, 55, 128, 66, 50, + 49, 56, 128, 66, 50, 49, 57, 128, 66, 50, 50, 49, 128, 66, 50, 50, 50, + 128, 66, 50, 50, 54, 128, 66, 50, 50, 55, 128, 66, 50, 50, 56, 128, 66, + 50, 50, 57, 128, 66, 50, 51, 50, 128, 66, 50, 51, 52, 128, 66, 50, 51, + 54, 128, 66, 50, 52, 53, 128, 66, 50, 52, 54, 128, 66, 50, 52, 56, 128, + 66, 50, 52, 57, 128, 66, 50, 53, 48, 128, 66, 50, 53, 49, 128, 66, 50, + 53, 50, 128, 66, 50, 53, 51, 128, 66, 50, 53, 53, 128, 66, 50, 53, 54, + 128, 66, 50, 53, 55, 128, 66, 50, 53, 56, 128, 66, 50, 53, 57, 128, 66, + 51, 48, 53, 128, 66, 65, 67, 75, 128, 66, 65, 71, 65, 128, 66, 65, 72, + 84, 128, 66, 65, 82, 83, 128, 66, 65, 83, 69, 128, 66, 66, 65, 80, 128, + 66, 66, 65, 84, 128, 66, 66, 65, 88, 128, 66, 66, 69, 80, 128, 66, 66, + 69, 88, 128, 66, 66, 73, 69, 128, 66, 66, 73, 80, 128, 66, 66, 73, 84, + 128, 66, 66, 73, 88, 128, 66, 66, 79, 80, 128, 66, 66, 79, 84, 128, 66, + 66, 79, 88, 128, 66, 66, 85, 79, 128, 66, 66, 85, 80, 128, 66, 66, 85, + 82, 128, 66, 66, 85, 88, 128, 66, 66, 89, 80, 128, 66, 66, 89, 84, 128, + 66, 66, 89, 88, 128, 66, 67, 65, 68, 128, 66, 69, 65, 78, 128, 66, 69, + 69, 72, 128, 66, 69, 76, 76, 128, 66, 69, 76, 84, 128, 66, 69, 78, 68, + 128, 66, 69, 79, 82, 195, 66, 69, 84, 72, 128, 66, 73, 82, 85, 128, 66, + 76, 65, 78, 203, 66, 79, 65, 82, 128, 66, 79, 65, 84, 128, 66, 79, 68, + 89, 128, 66, 83, 68, 85, 211, 66, 83, 75, 65, 173, 66, 83, 75, 85, 210, + 66, 85, 76, 76, 128, 66, 85, 77, 80, 217, 66, 87, 69, 69, 128, 67, 65, + 65, 73, 128, 67, 65, 76, 67, 128, 67, 65, 76, 76, 128, 67, 65, 80, 79, + 128, 67, 65, 86, 69, 128, 67, 65, 89, 78, 128, 67, 67, 65, 65, 128, 67, + 67, 69, 69, 128, 67, 67, 72, 65, 128, 67, 67, 72, 69, 128, 67, 67, 72, + 73, 128, 67, 67, 72, 79, 128, 67, 67, 72, 85, 128, 67, 72, 65, 78, 128, + 67, 72, 65, 80, 128, 67, 72, 65, 84, 128, 67, 72, 65, 88, 128, 67, 72, + 69, 80, 128, 67, 72, 69, 84, 128, 67, 72, 69, 88, 128, 67, 72, 79, 65, + 128, 67, 72, 79, 69, 128, 67, 72, 79, 80, 128, 67, 72, 79, 84, 128, 67, + 72, 79, 88, 128, 67, 72, 85, 79, 128, 67, 72, 85, 80, 128, 67, 72, 85, + 82, 128, 67, 72, 85, 88, 128, 67, 72, 89, 80, 128, 67, 72, 89, 82, 128, + 67, 72, 89, 84, 128, 67, 72, 89, 88, 128, 67, 73, 69, 80, 128, 67, 73, + 69, 84, 128, 67, 73, 69, 88, 128, 67, 76, 65, 78, 128, 67, 76, 65, 87, + 128, 67, 76, 69, 65, 210, 67, 76, 79, 83, 197, 67, 79, 68, 65, 128, 67, + 79, 76, 76, 128, 67, 79, 80, 89, 128, 67, 85, 79, 88, 128, 67, 85, 82, + 88, 128, 67, 89, 82, 88, 128, 68, 65, 71, 65, 218, 68, 65, 71, 83, 128, + 68, 65, 73, 82, 128, 68, 65, 77, 80, 128, 68, 65, 82, 84, 128, 68, 68, + 65, 65, 128, 68, 68, 65, 76, 128, 68, 68, 65, 80, 128, 68, 68, 65, 84, + 128, 68, 68, 65, 88, 128, 68, 68, 69, 69, 128, 68, 68, 69, 80, 128, 68, + 68, 69, 88, 128, 68, 68, 72, 79, 128, 68, 68, 73, 69, 128, 68, 68, 73, + 80, 128, 68, 68, 73, 84, 128, 68, 68, 73, 88, 128, 68, 68, 79, 65, 128, + 68, 68, 79, 80, 128, 68, 68, 79, 84, 128, 68, 68, 79, 88, 128, 68, 68, + 85, 79, 128, 68, 68, 85, 80, 128, 68, 68, 85, 84, 128, 68, 68, 85, 88, + 128, 68, 68, 87, 65, 128, 68, 69, 65, 68, 128, 68, 69, 66, 73, 212, 68, + 69, 69, 76, 128, 68, 69, 72, 73, 128, 68, 69, 75, 65, 128, 68, 69, 83, + 73, 128, 68, 72, 65, 76, 128, 68, 73, 80, 76, 201, 68, 73, 83, 72, 128, + 68, 73, 84, 84, 207, 68, 76, 69, 69, 128, 68, 79, 73, 84, 128, 68, 79, + 79, 82, 128, 68, 79, 82, 85, 128, 68, 82, 85, 77, 128, 68, 89, 69, 72, + 128, 68, 90, 69, 69, 128, 69, 72, 87, 65, 218, 69, 74, 69, 67, 212, 69, + 78, 84, 69, 210, 69, 84, 72, 69, 204, 69, 85, 45, 85, 128, 69, 85, 76, + 69, 210, 70, 65, 65, 73, 128, 70, 65, 78, 71, 128, 70, 76, 73, 80, 128, + 70, 79, 82, 77, 211, 70, 82, 65, 78, 195, 70, 85, 82, 88, 128, 70, 85, + 83, 69, 128, 70, 87, 69, 69, 128, 71, 65, 77, 65, 204, 71, 68, 65, 78, + 128, 71, 69, 65, 82, 128, 71, 71, 65, 65, 128, 71, 71, 65, 80, 128, 71, + 71, 65, 84, 128, 71, 71, 65, 88, 128, 71, 71, 69, 69, 128, 71, 71, 69, + 80, 128, 71, 71, 69, 84, 128, 71, 71, 69, 88, 128, 71, 71, 73, 69, 128, + 71, 71, 73, 84, 128, 71, 71, 73, 88, 128, 71, 71, 79, 84, 128, 71, 71, + 79, 88, 128, 71, 71, 85, 80, 128, 71, 71, 85, 82, 128, 71, 71, 85, 84, + 128, 71, 71, 85, 88, 128, 71, 71, 87, 65, 128, 71, 71, 87, 69, 128, 71, + 71, 87, 73, 128, 71, 72, 69, 69, 128, 71, 73, 66, 65, 128, 71, 73, 69, + 84, 128, 71, 73, 71, 65, 128, 71, 79, 73, 78, 199, 71, 79, 82, 84, 128, + 71, 85, 69, 72, 128, 71, 89, 65, 65, 128, 71, 89, 69, 69, 128, 72, 65, + 69, 71, 204, 72, 65, 71, 76, 128, 72, 69, 77, 80, 128, 72, 72, 69, 69, + 128, 72, 72, 87, 65, 128, 72, 73, 69, 88, 128, 72, 73, 90, 66, 128, 72, + 76, 65, 80, 128, 72, 76, 65, 84, 128, 72, 76, 65, 88, 128, 72, 76, 69, + 80, 128, 72, 76, 69, 88, 128, 72, 76, 73, 69, 128, 72, 76, 73, 80, 128, + 72, 76, 73, 84, 128, 72, 76, 73, 88, 128, 72, 76, 79, 80, 128, 72, 76, + 79, 88, 128, 72, 76, 85, 79, 128, 72, 76, 85, 80, 128, 72, 76, 85, 82, + 128, 72, 76, 85, 84, 128, 72, 76, 85, 88, 128, 72, 76, 89, 80, 128, 72, + 76, 89, 82, 128, 72, 76, 89, 84, 128, 72, 76, 89, 88, 128, 72, 77, 65, + 80, 128, 72, 77, 65, 84, 128, 72, 77, 65, 88, 128, 72, 77, 73, 69, 128, + 72, 77, 73, 80, 128, 72, 77, 73, 84, 128, 72, 77, 73, 88, 128, 72, 77, + 79, 80, 128, 72, 77, 79, 84, 128, 72, 77, 79, 88, 128, 72, 77, 85, 79, + 128, 72, 77, 85, 80, 128, 72, 77, 85, 82, 128, 72, 77, 85, 84, 128, 72, + 77, 85, 88, 128, 72, 77, 89, 80, 128, 72, 77, 89, 82, 128, 72, 77, 89, + 88, 128, 72, 78, 65, 80, 128, 72, 78, 65, 84, 128, 72, 78, 65, 88, 128, + 72, 78, 69, 80, 128, 72, 78, 69, 88, 128, 72, 78, 73, 69, 128, 72, 78, + 73, 80, 128, 72, 78, 73, 84, 128, 72, 78, 73, 88, 128, 72, 78, 79, 80, + 128, 72, 78, 79, 84, 128, 72, 78, 79, 88, 128, 72, 78, 85, 79, 128, 72, + 78, 85, 84, 128, 72, 79, 79, 78, 128, 72, 79, 84, 65, 128, 72, 80, 87, + 71, 128, 72, 85, 77, 65, 206, 72, 88, 65, 80, 128, 72, 88, 65, 84, 128, + 72, 88, 65, 88, 128, 72, 88, 69, 80, 128, 72, 88, 69, 88, 128, 72, 88, + 73, 69, 128, 72, 88, 73, 80, 128, 72, 88, 73, 88, 128, 72, 88, 79, 84, + 128, 72, 88, 79, 88, 128, 72, 90, 87, 71, 128, 72, 90, 90, 80, 128, 72, + 90, 90, 90, 128, 73, 45, 69, 85, 128, 73, 45, 89, 65, 128, 73, 68, 76, + 69, 128, 73, 70, 73, 78, 128, 73, 76, 85, 89, 128, 73, 78, 67, 72, 128, + 73, 78, 78, 69, 210, 73, 78, 78, 78, 128, 73, 78, 84, 73, 128, 73, 83, + 79, 78, 128, 73, 84, 69, 77, 128, 73, 85, 74, 65, 128, 74, 69, 82, 65, + 206, 74, 74, 69, 69, 128, 74, 74, 73, 80, 128, 74, 74, 73, 84, 128, 74, + 74, 73, 88, 128, 74, 74, 79, 80, 128, 74, 74, 79, 84, 128, 74, 74, 79, + 88, 128, 74, 74, 85, 79, 128, 74, 74, 85, 80, 128, 74, 74, 85, 82, 128, + 74, 74, 85, 88, 128, 74, 74, 89, 80, 128, 74, 74, 89, 84, 128, 74, 74, + 89, 88, 128, 74, 85, 76, 89, 128, 74, 85, 78, 69, 128, 74, 85, 79, 84, + 128, 75, 65, 65, 70, 128, 75, 65, 65, 73, 128, 75, 65, 80, 72, 128, 75, + 65, 80, 79, 128, 75, 67, 65, 76, 128, 75, 72, 65, 65, 128, 75, 72, 65, + 73, 128, 75, 72, 65, 78, 128, 75, 72, 69, 69, 128, 75, 72, 79, 78, 128, + 75, 73, 67, 75, 128, 75, 73, 69, 80, 128, 75, 73, 69, 88, 128, 75, 73, + 82, 79, 128, 75, 75, 69, 69, 128, 75, 79, 77, 66, 213, 75, 79, 84, 79, + 128, 75, 85, 79, 80, 128, 75, 85, 79, 88, 128, 75, 85, 82, 84, 128, 75, + 85, 82, 88, 128, 75, 85, 85, 72, 128, 75, 87, 69, 69, 128, 75, 88, 65, + 65, 128, 75, 88, 69, 69, 128, 75, 88, 87, 65, 128, 75, 88, 87, 69, 128, + 75, 88, 87, 73, 128, 75, 89, 65, 65, 128, 75, 89, 69, 69, 128, 76, 65, + 65, 73, 128, 76, 65, 65, 78, 128, 76, 65, 69, 86, 128, 76, 65, 77, 69, + 128, 76, 65, 77, 69, 196, 76, 68, 65, 78, 128, 76, 69, 69, 75, 128, 76, + 69, 71, 83, 128, 76, 69, 86, 69, 204, 76, 69, 90, 72, 128, 76, 72, 65, + 65, 128, 76, 72, 73, 73, 128, 76, 72, 79, 79, 128, 76, 73, 69, 84, 128, + 76, 73, 70, 69, 128, 76, 73, 84, 82, 193, 76, 79, 76, 76, 128, 76, 79, + 79, 84, 128, 76, 85, 73, 83, 128, 76, 85, 79, 84, 128, 77, 65, 65, 73, + 128, 77, 65, 82, 69, 128, 77, 69, 82, 73, 128, 77, 69, 83, 72, 128, 77, + 69, 83, 73, 128, 77, 71, 65, 80, 128, 77, 71, 65, 84, 128, 77, 71, 65, + 88, 128, 77, 71, 69, 80, 128, 77, 71, 69, 88, 128, 77, 71, 73, 69, 128, + 77, 71, 79, 80, 128, 77, 71, 79, 84, 128, 77, 71, 79, 88, 128, 77, 71, + 85, 79, 128, 77, 71, 85, 80, 128, 77, 71, 85, 82, 128, 77, 71, 85, 84, + 128, 77, 71, 85, 88, 128, 77, 73, 67, 82, 207, 77, 73, 73, 78, 128, 77, + 73, 76, 76, 197, 77, 73, 77, 69, 128, 77, 73, 78, 89, 128, 77, 73, 82, + 73, 128, 77, 78, 89, 65, 205, 77, 79, 78, 84, 200, 77, 79, 85, 84, 200, + 77, 79, 86, 69, 196, 77, 85, 73, 78, 128, 77, 85, 76, 84, 201, 77, 85, + 79, 84, 128, 77, 87, 69, 69, 128, 78, 65, 65, 73, 128, 78, 65, 73, 82, + 193, 78, 65, 78, 68, 128, 78, 66, 65, 80, 128, 78, 66, 65, 84, 128, 78, + 66, 65, 88, 128, 78, 66, 73, 80, 128, 78, 66, 73, 84, 128, 78, 66, 73, + 88, 128, 78, 66, 79, 80, 128, 78, 66, 79, 84, 128, 78, 66, 79, 88, 128, + 78, 66, 85, 80, 128, 78, 66, 85, 82, 128, 78, 66, 85, 84, 128, 78, 66, + 85, 88, 128, 78, 66, 89, 80, 128, 78, 66, 89, 82, 128, 78, 66, 89, 84, + 128, 78, 66, 89, 88, 128, 78, 68, 65, 80, 128, 78, 68, 65, 84, 128, 78, + 68, 65, 88, 128, 78, 68, 69, 80, 128, 78, 68, 73, 69, 128, 78, 68, 73, + 80, 128, 78, 68, 73, 84, 128, 78, 68, 73, 88, 128, 78, 68, 79, 80, 128, + 78, 68, 79, 84, 128, 78, 68, 79, 88, 128, 78, 68, 85, 80, 128, 78, 68, + 85, 82, 128, 78, 68, 85, 84, 128, 78, 68, 85, 88, 128, 78, 71, 65, 73, + 128, 78, 71, 65, 80, 128, 78, 71, 65, 84, 128, 78, 71, 65, 88, 128, 78, + 71, 69, 80, 128, 78, 71, 69, 88, 128, 78, 71, 73, 69, 128, 78, 71, 75, + 65, 128, 78, 71, 79, 80, 128, 78, 71, 79, 84, 128, 78, 71, 79, 88, 128, + 78, 71, 85, 79, 128, 78, 74, 73, 69, 128, 78, 74, 73, 80, 128, 78, 74, + 73, 84, 128, 78, 74, 73, 88, 128, 78, 74, 79, 80, 128, 78, 74, 79, 84, + 128, 78, 74, 79, 88, 128, 78, 74, 85, 79, 128, 78, 74, 85, 80, 128, 78, + 74, 85, 82, 128, 78, 74, 85, 88, 128, 78, 74, 89, 80, 128, 78, 74, 89, + 82, 128, 78, 74, 89, 84, 128, 78, 74, 89, 88, 128, 78, 78, 71, 65, 128, + 78, 78, 71, 73, 128, 78, 78, 71, 79, 128, 78, 79, 83, 69, 128, 78, 82, + 65, 80, 128, 78, 82, 65, 84, 128, 78, 82, 65, 88, 128, 78, 82, 69, 80, + 128, 78, 82, 69, 84, 128, 78, 82, 69, 88, 128, 78, 82, 79, 80, 128, 78, + 82, 79, 88, 128, 78, 82, 85, 80, 128, 78, 82, 85, 82, 128, 78, 82, 85, + 84, 128, 78, 82, 85, 88, 128, 78, 82, 89, 80, 128, 78, 82, 89, 82, 128, + 78, 82, 89, 84, 128, 78, 82, 89, 88, 128, 78, 85, 76, 76, 128, 78, 85, + 79, 80, 128, 78, 85, 82, 88, 128, 78, 85, 85, 78, 128, 78, 89, 65, 65, + 128, 78, 89, 67, 65, 128, 78, 89, 69, 69, 128, 78, 89, 69, 72, 128, 78, + 89, 73, 69, 128, 78, 89, 73, 84, 128, 78, 89, 73, 88, 128, 78, 89, 79, + 65, 128, 78, 89, 79, 84, 128, 78, 89, 79, 88, 128, 78, 89, 85, 79, 128, + 78, 89, 85, 80, 128, 78, 89, 85, 84, 128, 78, 89, 85, 88, 128, 78, 89, + 87, 65, 128, 78, 90, 65, 80, 128, 78, 90, 65, 84, 128, 78, 90, 65, 88, + 128, 78, 90, 69, 88, 128, 78, 90, 73, 69, 128, 78, 90, 73, 80, 128, 78, + 90, 73, 84, 128, 78, 90, 73, 88, 128, 78, 90, 79, 80, 128, 78, 90, 79, + 88, 128, 78, 90, 85, 79, 128, 78, 90, 85, 82, 128, 78, 90, 85, 88, 128, + 78, 90, 89, 80, 128, 78, 90, 89, 82, 128, 78, 90, 89, 84, 128, 78, 90, + 89, 88, 128, 79, 45, 69, 79, 128, 79, 45, 89, 69, 128, 79, 78, 83, 85, + 128, 79, 79, 77, 85, 128, 79, 79, 90, 69, 128, 79, 85, 78, 67, 197, 80, + 65, 65, 73, 128, 80, 65, 68, 77, 193, 80, 65, 82, 65, 128, 80, 69, 65, + 67, 197, 80, 69, 69, 80, 128, 80, 69, 78, 78, 217, 80, 69, 83, 79, 128, + 80, 72, 65, 65, 128, 80, 72, 65, 78, 128, 80, 72, 69, 69, 128, 80, 72, + 79, 65, 128, 80, 72, 87, 65, 128, 80, 73, 67, 75, 128, 80, 73, 69, 80, + 128, 80, 73, 69, 88, 128, 80, 73, 75, 79, 128, 80, 76, 79, 87, 128, 80, + 82, 65, 77, 128, 80, 82, 73, 78, 212, 80, 85, 79, 80, 128, 80, 85, 79, + 88, 128, 80, 85, 82, 88, 128, 80, 87, 69, 69, 128, 80, 89, 82, 88, 128, + 81, 65, 65, 70, 128, 81, 65, 65, 73, 128, 81, 65, 80, 72, 128, 81, 72, + 65, 65, 128, 81, 72, 69, 69, 128, 81, 72, 87, 65, 128, 81, 72, 87, 69, + 128, 81, 72, 87, 73, 128, 81, 73, 69, 80, 128, 81, 73, 69, 84, 128, 81, + 73, 69, 88, 128, 81, 79, 80, 65, 128, 81, 85, 79, 80, 128, 81, 85, 79, + 84, 128, 81, 85, 79, 88, 128, 81, 85, 82, 88, 128, 81, 85, 85, 86, 128, + 81, 87, 65, 65, 128, 81, 87, 69, 69, 128, 81, 89, 65, 65, 128, 81, 89, + 69, 69, 128, 81, 89, 82, 88, 128, 82, 65, 65, 73, 128, 82, 65, 73, 68, + 207, 82, 65, 78, 71, 197, 82, 69, 77, 85, 128, 82, 73, 67, 69, 128, 82, + 73, 69, 76, 128, 82, 73, 82, 65, 128, 82, 79, 65, 82, 128, 82, 82, 65, + 88, 128, 82, 82, 69, 72, 128, 82, 82, 69, 80, 128, 82, 82, 69, 84, 128, + 82, 82, 69, 88, 128, 82, 82, 79, 80, 128, 82, 82, 79, 84, 128, 82, 82, + 79, 88, 128, 82, 82, 85, 79, 128, 82, 82, 85, 80, 128, 82, 82, 85, 82, + 128, 82, 82, 85, 84, 128, 82, 82, 85, 88, 128, 82, 82, 89, 80, 128, 82, + 82, 89, 82, 128, 82, 82, 89, 84, 128, 82, 82, 89, 88, 128, 82, 85, 73, + 83, 128, 82, 85, 76, 69, 128, 82, 85, 79, 80, 128, 82, 85, 83, 73, 128, + 83, 65, 45, 73, 128, 83, 65, 65, 73, 128, 83, 65, 68, 69, 128, 83, 65, + 73, 76, 128, 83, 65, 76, 65, 128, 83, 65, 76, 65, 205, 83, 66, 82, 85, + 204, 83, 67, 87, 65, 128, 83, 68, 79, 78, 199, 83, 72, 65, 80, 128, 83, + 72, 65, 88, 128, 83, 72, 69, 80, 128, 83, 72, 69, 84, 128, 83, 72, 69, + 88, 128, 83, 72, 73, 73, 128, 83, 72, 73, 77, 193, 83, 72, 79, 65, 128, + 83, 72, 79, 79, 128, 83, 72, 79, 84, 128, 83, 72, 79, 88, 128, 83, 72, + 85, 79, 128, 83, 72, 85, 80, 128, 83, 72, 85, 84, 128, 83, 72, 85, 88, + 128, 83, 72, 89, 80, 128, 83, 72, 89, 82, 128, 83, 72, 89, 84, 128, 83, + 72, 89, 88, 128, 83, 73, 71, 69, 204, 83, 73, 88, 84, 217, 83, 75, 73, + 78, 128, 83, 75, 85, 76, 204, 83, 75, 87, 65, 128, 83, 78, 65, 75, 197, + 83, 80, 79, 84, 128, 83, 80, 87, 65, 128, 83, 83, 65, 65, 128, 83, 83, + 65, 80, 128, 83, 83, 65, 84, 128, 83, 83, 65, 88, 128, 83, 83, 69, 69, + 128, 83, 83, 69, 80, 128, 83, 83, 69, 88, 128, 83, 83, 73, 69, 128, 83, + 83, 73, 80, 128, 83, 83, 73, 84, 128, 83, 83, 73, 88, 128, 83, 83, 79, + 80, 128, 83, 83, 79, 84, 128, 83, 83, 79, 88, 128, 83, 83, 85, 80, 128, + 83, 83, 85, 84, 128, 83, 83, 85, 88, 128, 83, 83, 89, 80, 128, 83, 83, + 89, 82, 128, 83, 83, 89, 84, 128, 83, 83, 89, 88, 128, 83, 84, 65, 78, + 128, 83, 84, 69, 80, 128, 83, 84, 73, 76, 197, 83, 84, 73, 76, 204, 83, + 84, 87, 65, 128, 83, 85, 79, 80, 128, 83, 85, 79, 88, 128, 83, 85, 82, + 88, 128, 83, 87, 85, 78, 199, 83, 90, 65, 65, 128, 83, 90, 69, 69, 128, + 83, 90, 87, 65, 128, 83, 90, 87, 71, 128, 84, 65, 65, 73, 128, 84, 65, + 75, 69, 128, 84, 65, 76, 76, 128, 84, 69, 45, 85, 128, 84, 69, 78, 84, + 128, 84, 69, 84, 72, 128, 84, 72, 69, 72, 128, 84, 72, 69, 77, 193, 84, + 72, 69, 89, 128, 84, 72, 79, 65, 128, 84, 72, 85, 82, 211, 84, 72, 87, + 65, 128, 84, 73, 69, 80, 128, 84, 73, 69, 88, 128, 84, 73, 71, 72, 212, + 84, 73, 78, 89, 128, 84, 73, 87, 65, 218, 84, 76, 69, 69, 128, 84, 76, + 72, 85, 128, 84, 79, 84, 65, 204, 84, 82, 65, 68, 197, 84, 82, 73, 79, + 206, 84, 83, 65, 65, 128, 84, 83, 65, 68, 201, 84, 83, 87, 65, 128, 84, + 84, 65, 65, 128, 84, 84, 69, 69, 128, 84, 84, 69, 72, 128, 84, 84, 72, + 69, 128, 84, 84, 72, 73, 128, 84, 84, 83, 65, 128, 84, 84, 83, 69, 128, + 84, 84, 83, 73, 128, 84, 84, 83, 79, 128, 84, 84, 83, 85, 128, 84, 85, + 79, 80, 128, 84, 85, 79, 84, 128, 84, 85, 79, 88, 128, 84, 85, 82, 88, + 128, 84, 90, 65, 65, 128, 84, 90, 69, 69, 128, 84, 90, 79, 65, 128, 85, + 45, 65, 69, 128, 85, 65, 84, 72, 128, 86, 73, 69, 80, 128, 86, 73, 69, + 84, 128, 86, 73, 69, 88, 128, 86, 85, 82, 88, 128, 86, 89, 82, 88, 128, + 87, 65, 69, 78, 128, 87, 65, 76, 76, 128, 87, 69, 76, 76, 128, 87, 69, + 83, 84, 128, 87, 79, 82, 75, 128, 87, 82, 65, 80, 128, 87, 85, 78, 74, + 207, 87, 85, 79, 80, 128, 87, 85, 79, 88, 128, 88, 73, 82, 79, 206, 88, + 89, 65, 65, 128, 88, 89, 69, 69, 128, 88, 89, 82, 88, 128, 89, 65, 45, + 79, 128, 89, 65, 65, 73, 128, 89, 65, 66, 72, 128, 89, 65, 67, 72, 128, + 89, 65, 68, 68, 128, 89, 65, 68, 72, 128, 89, 65, 71, 78, 128, 89, 65, + 72, 72, 128, 89, 65, 82, 82, 128, 89, 65, 83, 72, 128, 89, 65, 83, 83, + 128, 89, 65, 84, 72, 128, 89, 65, 84, 84, 128, 89, 65, 90, 90, 128, 89, + 69, 82, 65, 200, 89, 73, 45, 85, 128, 89, 73, 78, 71, 128, 89, 79, 45, + 79, 128, 89, 79, 77, 79, 128, 89, 79, 82, 73, 128, 89, 85, 45, 65, 128, + 89, 85, 45, 69, 128, 89, 85, 45, 85, 128, 89, 85, 65, 78, 128, 89, 85, + 68, 72, 128, 89, 85, 79, 84, 128, 89, 85, 82, 88, 128, 89, 89, 82, 88, + 128, 90, 65, 89, 73, 206, 90, 72, 65, 65, 128, 90, 72, 65, 80, 128, 90, + 72, 65, 84, 128, 90, 72, 65, 88, 128, 90, 72, 69, 80, 128, 90, 72, 69, + 84, 128, 90, 72, 69, 88, 128, 90, 72, 79, 80, 128, 90, 72, 79, 84, 128, + 90, 72, 79, 88, 128, 90, 72, 85, 79, 128, 90, 72, 85, 80, 128, 90, 72, + 85, 82, 128, 90, 72, 85, 84, 128, 90, 72, 85, 88, 128, 90, 72, 87, 65, + 128, 90, 72, 89, 80, 128, 90, 72, 89, 82, 128, 90, 72, 89, 84, 128, 90, + 72, 89, 88, 128, 90, 85, 79, 80, 128, 90, 90, 65, 65, 128, 90, 90, 65, + 80, 128, 90, 90, 65, 84, 128, 90, 90, 65, 88, 128, 90, 90, 69, 69, 128, + 90, 90, 69, 80, 128, 90, 90, 69, 88, 128, 90, 90, 73, 69, 128, 90, 90, + 73, 80, 128, 90, 90, 73, 84, 128, 90, 90, 73, 88, 128, 90, 90, 79, 80, + 128, 90, 90, 79, 88, 128, 90, 90, 85, 80, 128, 90, 90, 85, 82, 128, 90, + 90, 85, 88, 128, 90, 90, 89, 80, 128, 90, 90, 89, 82, 128, 90, 90, 89, + 84, 128, 90, 90, 89, 88, 128, 79, 80, 69, 206, 70, 85, 76, 204, 83, 69, + 69, 206, 73, 79, 84, 193, 69, 65, 83, 212, 70, 82, 79, 205, 84, 79, 68, + 207, 70, 73, 86, 197, 72, 79, 85, 210, 84, 69, 78, 128, 83, 73, 66, 197, + 70, 79, 85, 210, 79, 86, 69, 210, 72, 79, 82, 206, 81, 85, 65, 196, 68, + 65, 83, 200, 78, 69, 79, 128, 80, 72, 73, 128, 80, 83, 73, 128, 84, 72, + 69, 200, 75, 79, 77, 201, 82, 72, 79, 128, 89, 85, 83, 128, 71, 72, 65, + 128, 79, 88, 73, 193, 82, 79, 67, 128, 66, 72, 65, 128, 83, 65, 82, 193, + 84, 65, 67, 203, 84, 65, 85, 128, 68, 79, 69, 211, 74, 72, 65, 128, 82, + 82, 65, 128, 87, 73, 68, 197, 82, 68, 69, 204, 83, 72, 73, 206, 87, 65, + 86, 217, 90, 65, 73, 206, 68, 73, 71, 193, 83, 72, 79, 128, 65, 82, 67, + 128, 75, 65, 70, 128, 76, 69, 71, 128, 83, 84, 79, 208, 84, 65, 77, 128, + 89, 65, 78, 199, 68, 90, 69, 128, 71, 72, 69, 128, 71, 79, 65, 204, 71, + 84, 69, 210, 78, 85, 78, 128, 78, 89, 79, 128, 83, 84, 65, 210, 83, 85, + 78, 128, 84, 65, 73, 204, 87, 65, 86, 197, 87, 65, 87, 128, 87, 79, 82, + 196, 90, 69, 82, 207, 65, 80, 76, 201, 66, 69, 69, 200, 67, 76, 69, 198, + 68, 74, 69, 128, 68, 75, 65, 210, 68, 89, 69, 200, 68, 90, 65, 128, 69, + 73, 69, 128, 70, 69, 72, 128, 70, 73, 83, 200, 71, 65, 78, 128, 71, 85, + 69, 200, 72, 73, 69, 128, 75, 83, 73, 128, 76, 65, 77, 197, 76, 74, 69, + 128, 77, 69, 77, 128, 77, 71, 79, 128, 77, 85, 67, 200, 77, 87, 65, 128, + 78, 65, 77, 197, 78, 65, 82, 128, 78, 74, 69, 128, 78, 79, 87, 128, 78, + 87, 65, 128, 78, 89, 69, 200, 78, 89, 73, 128, 79, 79, 85, 128, 80, 69, + 69, 128, 82, 65, 65, 128, 84, 72, 69, 206, 84, 73, 67, 203, 84, 84, 69, + 200, 89, 79, 68, 128, 66, 65, 83, 197, 66, 69, 69, 128, 66, 79, 87, 128, + 66, 90, 72, 201, 67, 79, 87, 128, 68, 79, 78, 128, 70, 76, 65, 212, 70, + 82, 69, 197, 72, 65, 69, 128, 74, 73, 76, 128, 75, 69, 72, 128, 75, 72, + 73, 128, 75, 72, 79, 128, 75, 87, 69, 128, 75, 87, 73, 128, 76, 65, 83, + 128, 76, 79, 79, 128, 76, 87, 65, 128, 77, 69, 78, 128, 77, 87, 69, 128, + 77, 87, 73, 128, 78, 65, 65, 128, 78, 89, 73, 211, 80, 65, 82, 128, 80, + 69, 72, 128, 80, 72, 79, 128, 80, 87, 69, 128, 80, 87, 73, 128, 81, 65, + 65, 128, 81, 65, 82, 128, 82, 65, 69, 128, 82, 72, 65, 128, 83, 72, 79, + 197, 83, 72, 85, 128, 83, 83, 73, 128, 83, 83, 79, 128, 83, 83, 85, 128, + 84, 72, 65, 204, 84, 79, 79, 128, 84, 87, 69, 128, 86, 69, 69, 128, 86, + 73, 78, 128, 87, 65, 69, 128, 87, 65, 76, 203, 87, 69, 79, 128, 88, 65, + 78, 128, 88, 69, 72, 128, 89, 65, 75, 128, 89, 65, 84, 128, 89, 89, 65, + 128, 90, 69, 78, 128, 65, 76, 76, 201, 65, 89, 66, 128, 65, 90, 85, 128, + 66, 65, 65, 128, 66, 69, 72, 128, 66, 69, 78, 128, 66, 79, 76, 212, 66, + 87, 65, 128, 67, 73, 80, 128, 67, 76, 85, 194, 67, 79, 79, 128, 67, 85, + 80, 128, 67, 87, 69, 128, 67, 87, 73, 128, 67, 87, 79, 128, 67, 89, 80, + 128, 67, 89, 84, 128, 68, 68, 65, 204, 68, 68, 69, 128, 68, 68, 73, 128, + 68, 68, 85, 128, 68, 69, 73, 128, 68, 74, 65, 128, 68, 76, 65, 128, 68, + 79, 71, 128, 68, 82, 85, 205, 69, 87, 69, 128, 70, 65, 65, 128, 70, 69, + 69, 128, 70, 69, 73, 128, 70, 76, 89, 128, 70, 85, 82, 128, 70, 85, 83, + 193, 70, 87, 65, 128, 71, 65, 89, 128, 71, 71, 65, 128, 71, 71, 69, 128, + 71, 71, 73, 128, 71, 71, 79, 128, 71, 71, 85, 128, 71, 72, 79, 128, 71, + 73, 77, 128, 71, 74, 69, 128, 72, 65, 82, 196, 72, 77, 79, 128, 72, 78, + 65, 128, 73, 83, 79, 206, 74, 74, 73, 128, 74, 74, 79, 128, 74, 74, 85, + 128, 74, 74, 89, 128, 75, 65, 73, 128, 75, 69, 78, 128, 75, 72, 69, 128, + 75, 73, 84, 128, 75, 74, 69, 128, 75, 75, 65, 128, 75, 79, 79, 128, 75, + 86, 65, 128, 75, 87, 79, 128, 76, 65, 65, 128, 76, 87, 69, 128, 76, 87, + 73, 128, 76, 87, 79, 128, 77, 65, 65, 128, 77, 79, 79, 128, 77, 79, 79, + 206, 77, 80, 65, 128, 77, 87, 79, 128, 78, 69, 69, 128, 78, 71, 65, 211, + 78, 73, 66, 128, 78, 79, 79, 128, 78, 82, 65, 128, 78, 87, 69, 128, 78, + 89, 85, 128, 79, 72, 77, 128, 79, 73, 76, 128, 79, 75, 84, 207, 79, 78, + 78, 128, 79, 84, 85, 128, 80, 65, 65, 128, 80, 65, 82, 212, 80, 65, 84, + 200, 80, 72, 85, 210, 80, 79, 76, 201, 80, 79, 79, 128, 80, 85, 84, 128, + 80, 87, 79, 128, 80, 89, 84, 128, 81, 65, 73, 128, 81, 73, 73, 128, 81, + 79, 84, 128, 81, 85, 79, 128, 81, 85, 85, 128, 82, 71, 89, 193, 82, 78, + 65, 205, 82, 82, 69, 200, 82, 82, 79, 128, 83, 69, 72, 128, 83, 72, 65, + 196, 83, 72, 79, 199, 83, 72, 89, 128, 83, 73, 79, 211, 83, 74, 69, 128, + 83, 79, 79, 128, 83, 79, 85, 128, 83, 83, 69, 128, 83, 87, 69, 128, 83, + 87, 73, 128, 83, 87, 79, 128, 84, 65, 71, 128, 84, 65, 84, 128, 84, 65, + 86, 128, 84, 69, 84, 128, 84, 74, 69, 128, 84, 76, 65, 128, 84, 76, 73, + 128, 84, 76, 85, 128, 84, 79, 84, 128, 84, 82, 69, 197, 84, 84, 73, 128, + 84, 87, 73, 128, 85, 83, 69, 196, 86, 65, 86, 128, 86, 69, 80, 128, 86, + 69, 82, 217, 86, 69, 87, 128, 86, 79, 85, 128, 86, 85, 82, 128, 87, 65, + 85, 128, 88, 86, 65, 128, 89, 65, 74, 128, 89, 65, 81, 128, 89, 65, 90, + 128, 89, 69, 65, 210, 89, 69, 82, 213, 89, 70, 69, 206, 89, 79, 79, 128, + 89, 87, 69, 128, 89, 87, 73, 128, 89, 87, 79, 128, 90, 72, 73, 128, 90, + 72, 79, 128, 90, 72, 85, 128, 90, 79, 84, 128, 90, 90, 65, 128, 90, 90, + 69, 128, 90, 90, 73, 128, 90, 90, 85, 128, 65, 65, 89, 128, 65, 68, 65, + 203, 65, 77, 66, 193, 65, 82, 67, 200, 65, 84, 79, 205, 65, 85, 69, 128, + 65, 87, 69, 128, 65, 88, 69, 128, 65, 89, 69, 210, 66, 48, 48, 177, 66, + 48, 48, 178, 66, 48, 48, 179, 66, 48, 48, 180, 66, 48, 48, 181, 66, 48, + 48, 182, 66, 48, 48, 183, 66, 48, 48, 184, 66, 48, 48, 185, 66, 48, 49, + 176, 66, 48, 49, 177, 66, 48, 49, 178, 66, 48, 49, 179, 66, 48, 49, 180, + 66, 48, 49, 181, 66, 48, 49, 182, 66, 48, 49, 183, 66, 48, 50, 176, 66, + 48, 50, 177, 66, 48, 50, 179, 66, 48, 50, 180, 66, 48, 50, 181, 66, 48, + 50, 182, 66, 48, 50, 183, 66, 48, 50, 184, 66, 48, 50, 185, 66, 48, 51, + 176, 66, 48, 51, 177, 66, 48, 51, 178, 66, 48, 51, 179, 66, 48, 51, 182, + 66, 48, 51, 183, 66, 48, 51, 184, 66, 48, 51, 185, 66, 48, 52, 176, 66, + 48, 52, 177, 66, 48, 52, 178, 66, 48, 52, 179, 66, 48, 52, 180, 66, 48, + 52, 181, 66, 48, 52, 182, 66, 48, 52, 184, 66, 48, 53, 176, 66, 48, 53, + 177, 66, 48, 53, 178, 66, 48, 53, 179, 66, 48, 53, 180, 66, 48, 53, 181, + 66, 48, 53, 183, 66, 48, 53, 184, 66, 48, 53, 185, 66, 48, 54, 176, 66, + 48, 54, 177, 66, 48, 54, 178, 66, 48, 54, 181, 66, 48, 54, 182, 66, 48, + 54, 183, 66, 48, 54, 184, 66, 48, 54, 185, 66, 48, 55, 176, 66, 48, 55, + 177, 66, 48, 55, 178, 66, 48, 55, 179, 66, 48, 55, 180, 66, 48, 55, 181, + 66, 48, 55, 182, 66, 48, 55, 183, 66, 48, 55, 184, 66, 48, 56, 176, 66, + 48, 56, 177, 66, 48, 56, 181, 66, 48, 56, 183, 66, 48, 57, 176, 66, 48, + 57, 177, 66, 49, 48, 176, 66, 49, 48, 178, 66, 49, 48, 180, 66, 49, 48, + 181, 66, 49, 50, 176, 66, 49, 50, 177, 66, 49, 50, 178, 66, 49, 50, 179, + 66, 49, 50, 181, 66, 49, 50, 183, 66, 49, 50, 184, 66, 49, 51, 176, 66, + 49, 51, 177, 66, 49, 51, 179, 66, 49, 51, 181, 66, 49, 52, 176, 66, 49, + 52, 177, 66, 49, 52, 181, 66, 49, 53, 177, 66, 49, 53, 182, 66, 49, 53, + 185, 66, 49, 54, 178, 66, 49, 54, 179, 66, 49, 55, 179, 66, 49, 55, 182, + 66, 49, 57, 177, 66, 50, 50, 176, 66, 50, 50, 181, 66, 50, 51, 176, 66, + 50, 51, 177, 66, 50, 51, 179, 66, 50, 52, 176, 66, 50, 52, 177, 66, 50, + 52, 178, 66, 50, 52, 179, 66, 50, 52, 183, 66, 50, 53, 180, 66, 65, 78, + 203, 66, 66, 65, 128, 66, 66, 69, 128, 66, 66, 73, 128, 66, 66, 79, 128, + 66, 66, 85, 128, 66, 66, 89, 128, 66, 67, 65, 196, 66, 69, 76, 204, 66, + 69, 76, 212, 66, 69, 84, 128, 66, 69, 84, 193, 66, 72, 79, 128, 66, 73, + 66, 128, 66, 73, 71, 128, 66, 75, 65, 173, 66, 79, 65, 128, 66, 87, 69, + 128, 66, 87, 73, 128, 66, 88, 71, 128, 67, 65, 68, 193, 67, 65, 78, 199, + 67, 65, 82, 197, 67, 65, 84, 128, 67, 65, 88, 128, 67, 67, 65, 128, 67, + 67, 69, 128, 67, 67, 73, 128, 67, 67, 79, 128, 67, 67, 85, 128, 67, 69, + 68, 201, 67, 69, 78, 128, 67, 69, 80, 128, 67, 69, 88, 128, 67, 72, 65, + 196, 67, 72, 69, 206, 67, 73, 69, 128, 67, 73, 73, 128, 67, 73, 84, 128, + 67, 73, 88, 128, 67, 79, 65, 128, 67, 79, 80, 128, 67, 79, 84, 128, 67, + 79, 88, 128, 67, 85, 66, 197, 67, 85, 79, 128, 67, 85, 82, 128, 67, 85, + 84, 128, 67, 85, 88, 128, 67, 89, 65, 128, 67, 89, 82, 128, 67, 89, 88, + 128, 68, 65, 68, 128, 68, 65, 69, 199, 68, 65, 77, 208, 68, 65, 82, 203, + 68, 65, 84, 197, 68, 69, 75, 128, 68, 69, 90, 200, 68, 76, 73, 128, 68, + 76, 79, 128, 68, 76, 85, 128, 68, 82, 73, 204, 68, 82, 89, 128, 68, 85, + 76, 128, 68, 87, 69, 128, 68, 87, 79, 128, 68, 89, 79, 128, 68, 90, 73, + 128, 68, 90, 79, 128, 68, 90, 85, 128, 69, 71, 71, 128, 69, 73, 83, 128, + 69, 75, 83, 128, 69, 78, 78, 128, 69, 78, 79, 211, 69, 79, 72, 128, 69, + 82, 71, 128, 69, 82, 82, 128, 69, 85, 82, 207, 69, 88, 79, 128, 70, 65, + 78, 128, 70, 65, 80, 128, 70, 65, 88, 128, 70, 69, 69, 196, 70, 69, 72, + 213, 70, 69, 78, 199, 70, 69, 79, 200, 70, 70, 73, 128, 70, 70, 76, 128, + 70, 73, 73, 128, 70, 73, 76, 197, 70, 73, 76, 204, 70, 73, 80, 128, 70, + 73, 84, 128, 70, 73, 88, 128, 70, 79, 79, 128, 70, 79, 80, 128, 70, 79, + 88, 128, 70, 85, 80, 128, 70, 85, 84, 128, 70, 85, 88, 128, 70, 87, 69, + 128, 70, 87, 73, 128, 70, 89, 65, 128, 70, 89, 80, 128, 70, 89, 84, 128, + 70, 89, 88, 128, 71, 65, 70, 128, 71, 65, 71, 128, 71, 65, 76, 128, 71, + 65, 82, 128, 71, 67, 65, 206, 71, 69, 66, 207, 71, 69, 84, 193, 71, 72, + 73, 128, 71, 72, 85, 128, 71, 72, 90, 128, 71, 73, 80, 128, 71, 79, 65, + 128, 71, 80, 65, 128, 71, 83, 85, 205, 71, 89, 65, 128, 71, 89, 69, 128, + 71, 89, 70, 213, 71, 89, 73, 128, 71, 89, 79, 128, 71, 89, 85, 128, 72, + 69, 76, 205, 72, 69, 78, 199, 72, 72, 69, 128, 72, 72, 73, 128, 72, 72, + 79, 128, 72, 72, 85, 128, 72, 76, 65, 128, 72, 76, 69, 128, 72, 76, 73, + 128, 72, 76, 79, 128, 72, 76, 85, 128, 72, 76, 89, 128, 72, 77, 73, 128, + 72, 77, 85, 128, 72, 77, 89, 128, 72, 78, 69, 128, 72, 78, 73, 128, 72, + 80, 65, 128, 72, 87, 85, 128, 72, 88, 65, 128, 72, 88, 69, 128, 72, 88, + 73, 128, 72, 88, 79, 128, 72, 90, 71, 128, 72, 90, 84, 128, 72, 90, 87, + 128, 72, 90, 90, 128, 73, 45, 65, 128, 73, 45, 79, 128, 73, 79, 82, 128, + 74, 65, 65, 128, 74, 65, 82, 128, 74, 69, 72, 128, 74, 69, 82, 128, 74, + 72, 79, 128, 74, 73, 65, 128, 74, 74, 65, 128, 74, 74, 69, 128, 74, 79, + 65, 128, 74, 79, 89, 128, 74, 87, 65, 128, 75, 65, 72, 128, 75, 65, 80, + 128, 75, 65, 85, 206, 75, 65, 88, 128, 75, 69, 80, 128, 75, 69, 88, 128, + 75, 69, 89, 128, 75, 72, 90, 128, 75, 73, 69, 128, 75, 73, 72, 128, 75, + 73, 73, 128, 75, 73, 80, 128, 75, 73, 88, 128, 75, 75, 69, 128, 75, 75, + 73, 128, 75, 75, 79, 128, 75, 75, 85, 128, 75, 79, 65, 128, 75, 79, 72, + 128, 75, 79, 80, 128, 75, 79, 84, 128, 75, 79, 88, 128, 75, 80, 65, 128, + 75, 82, 65, 128, 75, 85, 79, 128, 75, 85, 80, 128, 75, 85, 82, 128, 75, + 85, 84, 128, 75, 85, 88, 128, 75, 88, 65, 128, 75, 88, 69, 128, 75, 88, + 73, 128, 75, 88, 79, 128, 75, 88, 85, 128, 75, 89, 65, 128, 75, 89, 69, + 128, 75, 89, 73, 128, 75, 89, 79, 128, 75, 89, 85, 128, 76, 65, 69, 128, + 76, 65, 71, 213, 76, 65, 83, 212, 76, 65, 90, 217, 76, 69, 79, 128, 76, + 72, 65, 199, 76, 73, 68, 128, 76, 73, 73, 128, 76, 73, 78, 203, 76, 73, + 82, 193, 76, 79, 65, 128, 76, 79, 71, 128, 76, 79, 71, 210, 76, 79, 84, + 128, 76, 89, 89, 128, 77, 65, 83, 213, 77, 65, 89, 128, 77, 67, 72, 213, + 77, 68, 85, 206, 77, 69, 84, 193, 77, 69, 88, 128, 77, 71, 65, 128, 77, + 71, 69, 128, 77, 71, 85, 128, 77, 72, 90, 128, 77, 73, 73, 128, 77, 73, + 76, 128, 77, 73, 76, 204, 77, 73, 77, 128, 77, 79, 65, 128, 77, 79, 76, + 128, 77, 89, 65, 128, 77, 89, 84, 128, 78, 65, 71, 128, 78, 65, 79, 211, + 78, 66, 65, 128, 78, 66, 73, 128, 78, 66, 79, 128, 78, 66, 85, 128, 78, + 66, 89, 128, 78, 68, 69, 128, 78, 69, 78, 128, 78, 69, 84, 128, 78, 69, + 88, 212, 78, 71, 71, 128, 78, 74, 73, 128, 78, 74, 79, 128, 78, 74, 85, + 128, 78, 74, 89, 128, 78, 78, 71, 128, 78, 78, 79, 128, 78, 79, 65, 128, + 78, 82, 69, 128, 78, 82, 79, 128, 78, 82, 85, 128, 78, 82, 89, 128, 78, + 85, 76, 204, 78, 85, 80, 128, 78, 85, 82, 128, 78, 85, 88, 128, 78, 89, + 69, 128, 78, 90, 65, 128, 78, 90, 73, 128, 78, 90, 85, 128, 78, 90, 89, + 128, 79, 45, 69, 128, 79, 65, 75, 128, 79, 65, 89, 128, 79, 66, 79, 204, + 80, 65, 80, 128, 80, 65, 84, 128, 80, 65, 88, 128, 80, 72, 85, 128, 80, + 73, 69, 128, 80, 73, 71, 128, 80, 73, 80, 128, 80, 73, 84, 128, 80, 73, + 88, 128, 80, 76, 65, 128, 80, 79, 65, 128, 80, 79, 80, 128, 80, 79, 88, + 128, 80, 80, 77, 128, 80, 85, 50, 128, 80, 85, 79, 128, 80, 85, 80, 128, + 80, 85, 82, 128, 80, 85, 88, 128, 80, 89, 80, 128, 80, 89, 82, 128, 80, + 89, 88, 128, 81, 65, 76, 193, 81, 65, 81, 128, 81, 65, 85, 128, 81, 69, + 69, 128, 81, 72, 65, 128, 81, 72, 69, 128, 81, 72, 73, 128, 81, 72, 79, + 128, 81, 72, 85, 128, 81, 73, 69, 128, 81, 73, 80, 128, 81, 73, 84, 128, + 81, 73, 88, 128, 81, 79, 65, 128, 81, 79, 70, 128, 81, 79, 79, 128, 81, + 79, 80, 128, 81, 79, 88, 128, 81, 85, 65, 128, 81, 85, 69, 128, 81, 85, + 73, 128, 81, 85, 75, 128, 81, 85, 80, 128, 81, 85, 82, 128, 81, 85, 84, + 128, 81, 85, 86, 128, 81, 85, 88, 128, 81, 87, 65, 128, 81, 87, 69, 128, + 81, 87, 73, 128, 81, 89, 65, 128, 81, 89, 69, 128, 81, 89, 73, 128, 81, + 89, 79, 128, 81, 89, 80, 128, 81, 89, 82, 128, 81, 89, 84, 128, 81, 89, + 85, 128, 81, 89, 88, 128, 82, 65, 50, 128, 82, 65, 51, 128, 82, 65, 68, + 128, 82, 65, 68, 201, 82, 65, 73, 206, 82, 65, 77, 211, 82, 69, 73, 196, + 82, 73, 80, 128, 82, 74, 69, 128, 82, 74, 69, 211, 82, 79, 65, 128, 82, + 79, 79, 128, 82, 82, 69, 128, 82, 82, 85, 128, 82, 82, 89, 128, 82, 85, + 65, 128, 82, 85, 78, 128, 82, 87, 65, 128, 82, 89, 65, 128, 82, 89, 89, + 128, 83, 45, 87, 128, 83, 65, 68, 128, 83, 65, 89, 128, 83, 66, 85, 194, + 83, 71, 65, 194, 83, 71, 79, 210, 83, 71, 82, 193, 83, 73, 73, 128, 83, + 73, 78, 197, 83, 75, 87, 128, 83, 78, 65, 208, 83, 79, 65, 128, 83, 79, + 87, 128, 83, 83, 89, 128, 83, 85, 65, 128, 83, 85, 79, 128, 83, 85, 82, + 128, 83, 90, 65, 128, 83, 90, 69, 128, 83, 90, 73, 128, 83, 90, 79, 128, + 83, 90, 85, 128, 84, 65, 50, 128, 84, 65, 79, 128, 84, 65, 80, 128, 84, + 65, 80, 197, 84, 65, 87, 128, 84, 65, 88, 128, 84, 69, 83, 200, 84, 69, + 84, 200, 84, 69, 88, 128, 84, 72, 69, 211, 84, 72, 73, 206, 84, 72, 90, + 128, 84, 73, 73, 128, 84, 73, 80, 128, 84, 73, 84, 128, 84, 73, 88, 128, + 84, 76, 86, 128, 84, 79, 65, 128, 84, 79, 88, 128, 84, 82, 73, 128, 84, + 83, 86, 128, 84, 84, 72, 128, 84, 84, 85, 128, 84, 85, 79, 128, 84, 85, + 80, 128, 84, 85, 82, 128, 84, 85, 84, 128, 84, 85, 88, 128, 84, 89, 65, + 128, 84, 89, 69, 128, 84, 89, 73, 128, 84, 89, 79, 128, 84, 90, 65, 128, + 84, 90, 69, 128, 84, 90, 73, 128, 84, 90, 79, 128, 84, 90, 85, 128, 85, + 69, 69, 128, 85, 69, 89, 128, 85, 78, 68, 207, 85, 78, 73, 212, 85, 82, + 85, 218, 86, 65, 65, 128, 86, 65, 80, 128, 86, 65, 84, 128, 86, 65, 88, + 128, 86, 69, 72, 128, 86, 69, 88, 128, 86, 73, 69, 128, 86, 73, 80, 128, + 86, 73, 84, 128, 86, 73, 88, 128, 86, 79, 73, 196, 86, 79, 80, 128, 86, + 79, 84, 128, 86, 79, 87, 128, 86, 79, 88, 128, 86, 85, 80, 128, 86, 85, + 84, 128, 86, 85, 88, 128, 86, 87, 65, 128, 86, 89, 80, 128, 86, 89, 82, + 128, 86, 89, 84, 128, 86, 89, 88, 128, 87, 65, 80, 128, 87, 65, 84, 128, + 87, 65, 88, 128, 87, 69, 80, 128, 87, 69, 88, 128, 87, 79, 65, 128, 87, + 79, 69, 128, 87, 79, 80, 128, 87, 79, 82, 203, 87, 79, 88, 128, 87, 85, + 79, 128, 87, 89, 78, 206, 88, 79, 65, 128, 88, 79, 82, 128, 88, 89, 65, + 128, 88, 89, 69, 128, 88, 89, 73, 128, 88, 89, 79, 128, 88, 89, 80, 128, + 88, 89, 82, 128, 88, 89, 84, 128, 88, 89, 85, 128, 88, 89, 88, 128, 89, + 65, 66, 128, 89, 65, 68, 128, 89, 65, 70, 128, 89, 65, 71, 128, 89, 65, + 77, 128, 89, 65, 80, 128, 89, 65, 82, 128, 89, 65, 86, 128, 89, 65, 87, + 128, 89, 65, 89, 128, 89, 69, 65, 128, 89, 69, 87, 128, 89, 69, 89, 128, + 89, 73, 73, 128, 89, 85, 68, 200, 89, 85, 82, 128, 89, 89, 80, 128, 89, + 89, 82, 128, 89, 89, 84, 128, 89, 89, 88, 128, 90, 65, 72, 128, 90, 72, + 89, 128, 90, 76, 65, 128, 90, 79, 79, 128, 90, 82, 65, 128, 90, 85, 84, + 128, 90, 90, 89, 128, 75, 65, 198, 66, 69, 200, 68, 65, 217, 84, 72, 197, + 70, 69, 200, 68, 65, 196, 83, 65, 196, 69, 78, 196, 81, 65, 198, 84, 65, + 200, 65, 82, 195, 78, 79, 210, 76, 69, 203, 77, 65, 201, 79, 67, 210, 66, + 73, 199, 82, 72, 207, 84, 69, 206, 87, 65, 215, 89, 73, 199, 67, 72, 197, + 77, 71, 207, 65, 82, 205, 66, 85, 212, 67, 85, 205, 71, 72, 197, 78, 69, + 207, 80, 85, 128, 84, 73, 208, 71, 65, 198, 75, 72, 207, 90, 65, 200, 68, + 73, 197, 80, 72, 201, 90, 72, 197, 80, 72, 207, 81, 73, 128, 81, 85, 128, + 83, 73, 216, 67, 72, 207, 77, 69, 206, 77, 73, 196, 78, 69, 212, 80, 69, + 200, 81, 79, 128, 86, 69, 200, 89, 79, 196, 66, 65, 199, 66, 69, 212, 68, + 89, 207, 70, 79, 128, 72, 65, 193, 75, 65, 201, 78, 65, 199, 81, 69, 128, + 82, 65, 196, 83, 73, 206, 86, 65, 214, 45, 85, 205, 67, 72, 201, 68, 65, + 208, 68, 85, 204, 68, 90, 128, 69, 88, 207, 71, 82, 213, 71, 85, 199, 72, + 79, 212, 72, 80, 128, 72, 86, 128, 73, 74, 128, 73, 85, 128, 73, 89, 128, + 74, 69, 200, 74, 79, 212, 75, 69, 217, 75, 71, 128, 75, 75, 128, 76, 74, + 128, 77, 73, 199, 78, 74, 128, 78, 85, 206, 78, 86, 128, 78, 89, 201, 79, + 72, 205, 80, 65, 215, 81, 79, 207, 82, 68, 207, 83, 85, 206, 83, 87, 128, + 87, 79, 206, 89, 69, 206, 89, 85, 211, 65, 78, 207, 66, 69, 206, 66, 79, + 215, 66, 81, 128, 67, 77, 128, 67, 85, 212, 68, 76, 128, 68, 77, 128, 68, + 82, 217, 68, 86, 128, 69, 67, 200, 70, 77, 128, 70, 89, 128, 71, 66, 128, + 71, 86, 128, 71, 89, 128, 72, 71, 128, 72, 75, 128, 73, 83, 211, 75, 66, + 128, 75, 73, 208, 75, 76, 128, 75, 77, 128, 75, 84, 128, 75, 86, 128, 76, + 65, 215, 76, 67, 197, 76, 67, 201, 76, 72, 128, 76, 78, 128, 76, 88, 128, + 77, 66, 128, 77, 69, 205, 77, 71, 128, 77, 72, 128, 77, 76, 128, 77, 77, + 128, 77, 83, 128, 77, 86, 128, 77, 87, 128, 78, 65, 193, 78, 70, 128, 78, + 71, 207, 78, 72, 128, 78, 77, 128, 78, 87, 128, 78, 89, 196, 79, 86, 128, + 80, 67, 128, 80, 69, 211, 80, 70, 128, 80, 79, 208, 80, 82, 128, 80, 86, + 128, 80, 87, 128, 81, 79, 198, 81, 89, 128, 82, 73, 206, 82, 74, 197, 82, + 85, 194, 83, 78, 193, 83, 79, 198, 83, 82, 128, 84, 65, 213, 84, 65, 214, + 84, 69, 197, 84, 69, 212, 84, 73, 210, 84, 82, 128, 86, 69, 197, 86, 69, + 215, 87, 66, 128, 87, 86, 128, 88, 89, 128, 89, 65, 210, 89, 86, 128, 90, + 76, 193, 66, 217, 77, 213, 65, 197, 89, 213, 68, 218, 90, 197, 75, 205, + 67, 205, 68, 205, 75, 213, 77, 205, 68, 194, 76, 218, 77, 194, 77, 207, + 77, 214, 77, 215, 80, 207, 81, 208, 84, 195, 202, 209, +}; + +static unsigned short lexicon_offset[] = { + 0, 0, 6, 10, 15, 23, 30, 32, 35, 40, 53, 65, 71, 77, 82, 90, 99, 103, + 108, 116, 119, 126, 130, 138, 144, 150, 157, 162, 172, 175, 182, 187, + 193, 201, 206, 215, 222, 229, 238, 243, 251, 255, 256, 264, 270, 276, + 282, 288, 295, 301, 309, 318, 322, 327, 330, 337, 344, 350, 353, 362, + 370, 375, 381, 387, 392, 397, 402, 405, 407, 413, 418, 426, 299, 428, + 430, 439, 100, 447, 457, 465, 467, 478, 481, 494, 498, 504, 514, 519, + 522, 524, 533, 538, 545, 549, 556, 559, 564, 569, 572, 582, 591, 599, + 606, 614, 618, 626, 634, 643, 647, 654, 662, 671, 675, 683, 689, 698, + 705, 708, 709, 714, 719, 728, 735, 738, 745, 751, 755, 763, 173, 767, + 773, 782, 750, 789, 263, 797, 803, 808, 812, 825, 834, 839, 842, 852, + 753, 857, 866, 875, 877, 882, 887, 894, 904, 907, 909, 913, 921, 22, 929, + 933, 938, 947, 543, 950, 960, 964, 971, 977, 983, 988, 994, 997, 1000, + 80, 1007, 1015, 1025, 1030, 1035, 1042, 1044, 1054, 779, 1058, 1062, + 1069, 1074, 1081, 1085, 1089, 1094, 1104, 1110, 1023, 1112, 1117, 1123, + 325, 1130, 1134, 1140, 1144, 1147, 1152, 1158, 1163, 1083, 1169, 1176, + 1181, 1183, 1185, 1190, 1195, 624, 1204, 1210, 1213, 1215, 1221, 31, + 1224, 1226, 1179, 1229, 1237, 1243, 1250, 1274, 1296, 1318, 1340, 1361, + 1382, 1402, 1422, 1441, 1460, 1479, 1498, 1517, 1536, 1555, 1574, 1592, + 1610, 1628, 1646, 1664, 1682, 1700, 1718, 1736, 1754, 1772, 1789, 1806, + 1823, 1840, 1857, 1874, 1891, 1908, 1925, 1942, 1959, 1975, 1991, 2007, + 2023, 2039, 2055, 2071, 2087, 2103, 2119, 2135, 2151, 2167, 2183, 2199, + 2215, 2231, 2247, 2263, 2279, 2295, 2311, 2327, 2343, 2359, 2375, 2391, + 2407, 2423, 2439, 2455, 2471, 2487, 2503, 2519, 2535, 2551, 2567, 2583, + 2599, 2615, 2631, 2647, 2663, 2679, 2695, 2711, 2727, 2743, 2759, 2775, + 2791, 2807, 2823, 2839, 2855, 2871, 2887, 2903, 2919, 2935, 2951, 2967, + 2983, 2999, 3015, 3031, 3047, 3063, 3079, 3095, 3111, 3127, 3143, 3159, + 3175, 3191, 3207, 3223, 3239, 3255, 3271, 3287, 3303, 3319, 3335, 3351, + 3367, 3383, 3399, 3415, 3431, 3447, 3463, 3479, 3495, 3511, 3527, 3543, + 3559, 3575, 3591, 3607, 3623, 3639, 3655, 3671, 3687, 3703, 3719, 3735, + 3751, 3767, 3783, 3799, 3815, 3831, 3847, 3863, 3879, 3895, 3911, 3927, + 3943, 3959, 3975, 3991, 4007, 4023, 4039, 4055, 4071, 4087, 4103, 4119, + 4135, 4151, 4167, 4183, 4199, 4215, 4231, 4247, 4263, 4279, 4295, 4311, + 4327, 4343, 4359, 4375, 4391, 4407, 4423, 4439, 4455, 4471, 4487, 4503, + 4519, 4535, 4551, 4567, 4583, 4599, 4615, 4631, 4647, 4663, 4679, 4695, + 4711, 4727, 4743, 4759, 4775, 4791, 4807, 4823, 4839, 4855, 4871, 4887, + 4903, 4919, 4935, 4951, 4967, 4983, 4999, 5015, 5031, 5047, 5063, 5079, + 5095, 5111, 5127, 5143, 5159, 5175, 5191, 5207, 5223, 5239, 5255, 5271, + 5287, 5303, 5319, 5335, 5351, 5367, 5383, 5399, 5415, 5431, 5447, 5463, + 5479, 5495, 5511, 5527, 5543, 5559, 5575, 5591, 5607, 5623, 5639, 5655, + 5671, 5687, 5703, 5719, 5735, 5751, 5767, 5783, 5799, 5815, 5831, 5847, + 5863, 5879, 5895, 5911, 5927, 5943, 5959, 5975, 5991, 6007, 6023, 6039, + 6055, 6071, 6087, 6103, 6119, 6135, 6151, 6167, 6183, 6199, 6215, 6231, + 6247, 6263, 6279, 6295, 6311, 6327, 6343, 6359, 6375, 6391, 6407, 6423, + 6439, 6455, 6471, 6487, 6503, 6519, 6535, 6551, 6567, 6583, 6599, 6615, + 6631, 6647, 6663, 6679, 6695, 6711, 6727, 6743, 6759, 6775, 6791, 6807, + 6823, 6839, 6855, 6871, 6887, 6903, 6919, 6935, 6951, 6967, 6983, 6999, + 7015, 7031, 7047, 7063, 7079, 7095, 7111, 7127, 7143, 7159, 7175, 7191, + 7207, 7223, 7239, 7255, 7271, 7287, 7303, 7319, 7335, 7351, 7367, 7383, + 7399, 7415, 7431, 7447, 7463, 7479, 7495, 7511, 7527, 7543, 7559, 7575, + 7591, 7607, 7623, 7639, 7655, 7671, 7687, 7703, 7719, 7735, 7751, 7767, + 7783, 7799, 7815, 7831, 7847, 7863, 7879, 7895, 7911, 7927, 7943, 7959, + 7975, 7991, 8007, 8023, 8039, 8055, 8071, 8087, 8103, 8119, 8135, 8151, + 8167, 8183, 8199, 8215, 8231, 8247, 8263, 8279, 8295, 8311, 8327, 8343, + 8359, 8375, 8391, 8407, 8423, 8439, 8455, 8471, 8487, 8503, 8519, 8535, + 8551, 8567, 8583, 8599, 8615, 8631, 8647, 8663, 8679, 8695, 8711, 8727, + 8743, 8759, 8775, 8791, 8807, 8823, 8839, 8855, 8871, 8887, 8903, 8919, + 8935, 8951, 8967, 8983, 8999, 9015, 9031, 9047, 9063, 9079, 9095, 9111, + 9127, 9143, 9159, 9175, 9191, 9207, 9223, 9239, 9255, 9271, 9287, 9303, + 9319, 9335, 9351, 9367, 9383, 9399, 9415, 9431, 9447, 9463, 9479, 9495, + 9511, 9527, 9543, 9559, 9575, 9591, 9607, 9623, 9639, 9655, 9671, 9687, + 9703, 9719, 9735, 9751, 9767, 9783, 9799, 9815, 9831, 9847, 9863, 9879, + 9895, 9911, 9927, 9943, 9959, 9975, 9991, 10007, 10023, 10039, 10055, + 10071, 10087, 10103, 10119, 10135, 10151, 10167, 10183, 10199, 10215, + 10231, 10247, 10263, 10279, 10295, 10311, 10327, 10343, 10359, 10375, + 10391, 10407, 10423, 10439, 10455, 10471, 10487, 10503, 10519, 10535, + 10551, 10567, 10583, 10599, 10615, 10631, 10647, 10663, 10679, 10695, + 10711, 10727, 10743, 10759, 10775, 10791, 10807, 10823, 10839, 10855, + 10871, 10887, 10903, 10919, 10934, 10949, 10964, 10979, 10994, 11009, + 11024, 11039, 11054, 11069, 11084, 11099, 11114, 11129, 11144, 11159, + 11174, 11189, 11204, 11219, 11234, 11249, 11264, 11279, 11294, 11309, + 11324, 11339, 11354, 11369, 11384, 11399, 11414, 11429, 11444, 11459, + 11474, 11489, 11504, 11519, 11534, 11549, 11564, 11579, 11594, 11609, + 11624, 11639, 11654, 11669, 11684, 11699, 11714, 11729, 11744, 11759, + 11774, 11789, 11804, 11819, 11834, 11849, 11864, 11879, 11894, 11909, + 11924, 11939, 11954, 11969, 11984, 11999, 12014, 12029, 12044, 12059, + 12074, 12089, 12104, 12119, 12134, 12149, 12164, 12179, 12194, 12209, + 12224, 12239, 12254, 12269, 12284, 12299, 12314, 12329, 12344, 12359, + 12374, 12389, 12404, 12419, 12434, 12449, 12464, 12479, 12494, 12509, + 12524, 12539, 12554, 12569, 12584, 12599, 12614, 12629, 12644, 12659, + 12674, 12689, 12704, 12719, 12734, 12749, 12764, 12779, 12794, 12809, + 12824, 12839, 12854, 12869, 12884, 12899, 12914, 12929, 12944, 12959, + 12974, 12989, 13004, 13019, 13034, 13049, 13064, 13079, 13094, 13109, + 13124, 13139, 13154, 13169, 13184, 13199, 13214, 13229, 13244, 13259, + 13274, 13289, 13304, 13319, 13334, 13349, 13364, 13379, 13394, 13409, + 13424, 13439, 13454, 13469, 13484, 13499, 13514, 13529, 13544, 13559, + 13574, 13589, 13604, 13619, 13634, 13649, 13664, 13679, 13694, 13709, + 13724, 13739, 13754, 13769, 13784, 13799, 13814, 13829, 13844, 13859, + 13874, 13889, 13904, 13919, 13934, 13949, 13964, 13979, 13994, 14009, + 14024, 14039, 14054, 14069, 14084, 14099, 14114, 14129, 14144, 14159, + 14174, 14189, 14204, 14219, 14234, 14249, 14264, 14279, 14294, 14309, + 14324, 14339, 14354, 14369, 14384, 14399, 14414, 14429, 14444, 14459, + 14474, 14489, 14504, 14519, 14534, 14549, 14564, 14579, 14594, 14609, + 14624, 14639, 14654, 14669, 14684, 14699, 14714, 14729, 14744, 14759, + 14774, 14789, 14804, 14819, 14834, 14849, 14864, 14879, 14894, 14909, + 14924, 14939, 14954, 14969, 14984, 14999, 15014, 15029, 15044, 15059, + 15074, 15089, 15104, 15119, 15134, 15149, 15164, 15179, 15194, 15209, + 15224, 15239, 15254, 15269, 15284, 15299, 15314, 15329, 15344, 15359, + 15374, 15389, 15404, 15419, 15434, 15449, 15464, 15479, 15494, 15509, + 15524, 15539, 15554, 15569, 15584, 15599, 15614, 15629, 15644, 15659, + 15674, 15689, 15704, 15719, 15734, 15749, 15764, 15779, 15794, 15809, + 15824, 15839, 15854, 15869, 15884, 15899, 15914, 15929, 15944, 15959, + 15974, 15989, 16004, 16019, 16034, 16049, 16064, 16079, 16094, 16109, + 16124, 16139, 16154, 16169, 16184, 16199, 16214, 16229, 16244, 16259, + 16274, 16289, 16304, 16319, 16334, 16349, 16364, 16379, 16394, 16409, + 16424, 16439, 16454, 16469, 16484, 16499, 16514, 16529, 16544, 16559, + 16574, 16589, 16604, 16619, 16634, 16649, 16664, 16679, 16694, 16709, + 16724, 16739, 16754, 16769, 16784, 16799, 16814, 16829, 16844, 16859, + 16874, 16889, 16904, 16919, 16934, 16949, 16964, 16979, 16994, 17009, + 17024, 17039, 17054, 17069, 17084, 17099, 17114, 17129, 17144, 17159, + 17174, 17189, 17204, 17219, 17234, 17249, 17264, 17279, 17294, 17309, + 17324, 17339, 17354, 17369, 17384, 17399, 17414, 17429, 17444, 17459, + 17474, 17489, 17504, 17519, 17534, 17549, 17564, 17579, 17594, 17609, + 17624, 17639, 17654, 17669, 17684, 17699, 17714, 17729, 17744, 17759, + 17774, 17789, 17804, 17819, 17834, 17849, 17864, 17879, 17894, 17909, + 17924, 17939, 17954, 17969, 17984, 17999, 18014, 18029, 18044, 18059, + 18074, 18089, 18104, 18119, 18134, 18149, 18164, 18179, 18194, 18209, + 18224, 18239, 18254, 18269, 18283, 18297, 18311, 18325, 18339, 1408, + 18353, 18367, 18381, 18395, 18409, 18423, 18437, 18451, 18465, 18479, + 18493, 18507, 18521, 18535, 18549, 18563, 18577, 18591, 18605, 18619, + 18633, 18647, 18661, 18675, 18689, 18703, 1809, 18717, 18731, 18745, + 18759, 18773, 18787, 18801, 18815, 18829, 18843, 18857, 18871, 18885, + 18899, 18913, 18927, 18941, 18954, 18967, 18980, 18993, 19006, 19019, + 19032, 19045, 19058, 19071, 19084, 19097, 19110, 19123, 19136, 19149, + 19162, 19175, 19188, 19201, 19214, 19227, 19240, 1759, 19253, 19266, + 19279, 19292, 19305, 19318, 19331, 19344, 19357, 19370, 19383, 19396, + 19409, 19422, 19435, 19448, 19461, 19474, 19487, 19500, 19513, 19526, + 19539, 19552, 19565, 19578, 19591, 19604, 19617, 19630, 19643, 19656, + 19669, 19682, 19695, 19708, 19721, 1523, 19734, 19747, 19760, 19773, + 19786, 19799, 19812, 19825, 19838, 19851, 19864, 19877, 19890, 19903, + 19916, 19929, 19942, 19955, 19968, 19981, 19994, 20007, 20020, 20033, + 20046, 20059, 20072, 20085, 20098, 20111, 20124, 20137, 20150, 20163, + 20176, 20189, 20202, 20215, 20228, 20241, 20254, 20267, 20280, 20293, + 20306, 20319, 20332, 20345, 20358, 20371, 20384, 20397, 20410, 20423, + 20436, 20449, 20462, 20475, 20488, 20501, 20514, 20527, 20540, 20553, + 20566, 20579, 20592, 20605, 20618, 20631, 20644, 20657, 20670, 20683, + 20696, 20709, 20722, 20735, 20748, 20761, 20774, 20787, 20800, 20813, + 20826, 20839, 20852, 20865, 20878, 20891, 20904, 20917, 20930, 20943, + 20956, 20969, 20982, 20995, 21008, 21021, 21034, 21047, 21060, 21073, + 21086, 21099, 21112, 21125, 21138, 21151, 21164, 21177, 21190, 21203, + 21216, 21229, 21242, 21255, 21268, 21281, 21294, 21307, 21320, 21333, + 21346, 21359, 21372, 21385, 21398, 21411, 21424, 21437, 21450, 21463, + 21476, 21489, 21502, 21515, 21528, 21541, 21554, 21567, 21580, 21593, + 21606, 21619, 21632, 21645, 21658, 21671, 21684, 21697, 21710, 21723, + 21736, 21749, 21762, 21775, 21788, 21801, 21814, 21827, 21840, 21853, + 21866, 21879, 21892, 21905, 21918, 21931, 21944, 21957, 21970, 21983, + 21996, 22009, 22022, 22034, 22046, 22058, 22070, 22082, 22094, 22106, + 22118, 22130, 22142, 22154, 22166, 22178, 22190, 22202, 22214, 22226, + 22238, 1670, 22250, 22262, 22274, 1616, 22286, 22298, 22310, 22322, + 22334, 22346, 22358, 1505, 1598, 22370, 1634, 22382, 22394, 22406, 22418, + 22430, 22442, 22454, 22466, 22478, 22490, 22502, 22514, 22526, 22538, + 22550, 22562, 22574, 22586, 22598, 22610, 22622, 22634, 22646, 22658, + 22670, 22682, 22694, 22706, 22718, 22730, 22742, 22754, 22766, 22778, + 22790, 22802, 22814, 22826, 22838, 22850, 22862, 22874, 22886, 22898, + 22910, 22922, 22934, 22946, 22958, 22970, 22982, 22994, 23006, 23018, + 23030, 23042, 23054, 23066, 23078, 23090, 23102, 23114, 23126, 23138, + 23150, 23162, 23174, 23186, 23198, 23210, 23222, 23234, 23246, 23258, + 23270, 23282, 23294, 23306, 23318, 23330, 23342, 23354, 23366, 23378, + 23390, 23402, 23414, 1390, 23426, 23438, 23450, 1724, 23462, 23474, + 23486, 23498, 23510, 23522, 23534, 23546, 23558, 23570, 23582, 23594, + 23606, 23618, 23630, 23642, 23654, 23666, 23678, 23690, 23702, 23714, + 23726, 23738, 23750, 23762, 23774, 23786, 23798, 23810, 23822, 23834, + 23846, 23858, 23870, 23882, 23894, 23906, 23918, 23930, 23942, 23954, + 23966, 23978, 23990, 24002, 24014, 24026, 24038, 24050, 24062, 24074, + 24086, 24098, 24110, 24122, 24134, 24146, 24158, 24170, 24182, 24194, + 24206, 24218, 24230, 24242, 24254, 24266, 24278, 24290, 24302, 24314, + 24326, 24338, 24350, 24362, 24374, 24386, 24398, 24410, 24422, 24434, + 24446, 24458, 24470, 24482, 24494, 24506, 24518, 24530, 24542, 24554, + 24566, 24578, 24590, 24602, 24614, 24626, 24638, 24650, 24662, 24674, + 24686, 24698, 24710, 24722, 24734, 24746, 24758, 24770, 24781, 24792, + 24803, 24814, 24825, 24836, 24847, 24858, 24869, 24880, 24891, 24902, + 24913, 24924, 24935, 24946, 24957, 1795, 24968, 24979, 24990, 25001, + 25012, 25023, 25034, 25045, 25056, 1880, 1307, 25067, 1430, 25078, 25089, + 25100, 25111, 25122, 25133, 1897, 25144, 25155, 25166, 25177, 25188, + 25199, 25210, 25221, 25232, 25243, 25254, 25265, 25276, 25287, 1863, + 25298, 25309, 25320, 25331, 25342, 25353, 25364, 25375, 25386, 25397, + 25408, 25419, 25430, 25441, 25452, 25463, 25474, 25485, 25496, 25507, + 25518, 25529, 25540, 25551, 25562, 25573, 25584, 25595, 25606, 25617, + 25628, 25639, 25650, 25661, 25672, 25683, 25694, 25705, 25716, 25727, + 25738, 25749, 25760, 25771, 25782, 25793, 25804, 25815, 25826, 25837, + 25848, 25859, 25870, 25881, 25892, 25903, 25914, 25925, 25936, 25947, + 25958, 25969, 25980, 25991, 26002, 26013, 26024, 26035, 26046, 26057, + 26068, 26079, 26090, 26101, 26112, 26123, 26134, 26145, 26156, 26167, + 26178, 26189, 26200, 26211, 26222, 26233, 26244, 26255, 26266, 26277, + 26288, 26299, 26310, 26321, 26332, 26343, 26354, 26365, 26376, 26387, + 26398, 26409, 26420, 26431, 26442, 26453, 18580, 26464, 26475, 26486, + 26497, 26508, 26519, 26530, 26541, 26552, 26563, 26574, 26585, 26596, + 26607, 26618, 26629, 26640, 26651, 26662, 26673, 26684, 26695, 26706, + 26717, 26728, 26739, 26750, 26761, 26772, 26783, 26794, 26805, 26816, + 26827, 26838, 26849, 26860, 26871, 26882, 26893, 26904, 26915, 26926, + 26937, 26948, 26959, 26970, 26981, 26992, 27003, 27013, 27023, 27033, + 27043, 27053, 27063, 27073, 27083, 27093, 27103, 27113, 27123, 27133, + 27143, 27153, 27163, 27173, 27183, 27193, 27203, 22072, 27213, 27223, + 27233, 27243, 27253, 27263, 27273, 27283, 1372, 27293, 27303, 27313, + 27323, 27333, 27343, 27353, 27363, 27373, 27383, 27393, 27403, 27413, + 27423, 27433, 27443, 27453, 27463, 27473, 27483, 27493, 27503, 27513, + 27523, 27533, 27543, 27553, 27563, 27573, 27583, 27593, 27603, 27613, + 27623, 27633, 27643, 27653, 27663, 27673, 27683, 27693, 27703, 27713, + 27723, 27733, 27743, 27753, 27763, 27773, 27783, 27793, 27803, 27813, + 27823, 27833, 27843, 27853, 27863, 27873, 27883, 27893, 27903, 27913, + 27923, 27933, 27943, 27953, 27963, 27973, 27983, 27993, 19490, 28003, + 22672, 28013, 28023, 28033, 28043, 28053, 28063, 28073, 28083, 28093, + 28103, 28113, 28123, 28133, 28143, 28153, 28163, 28173, 28183, 28193, + 28203, 28213, 28223, 28233, 28243, 28253, 28263, 28273, 28283, 28293, + 28303, 28313, 28323, 28333, 28343, 28353, 28363, 28373, 28383, 28393, + 28403, 28413, 28423, 28433, 28443, 28453, 28463, 28473, 28483, 28493, + 28503, 28513, 28523, 28533, 28543, 28553, 28563, 28573, 28583, 28593, + 28603, 28613, 28623, 28633, 28643, 28653, 28663, 28673, 28683, 28693, + 28703, 28713, 28723, 28733, 28743, 28753, 28763, 28773, 28783, 28793, + 28803, 28813, 28823, 28833, 28843, 28853, 28863, 28873, 28883, 28893, + 28903, 28913, 28923, 28933, 28943, 28953, 28963, 28973, 28983, 28993, + 29003, 29013, 29023, 29033, 29043, 29053, 29063, 29073, 29083, 29093, + 29103, 29113, 29123, 29133, 29143, 29153, 29163, 29173, 29183, 29193, + 29203, 29213, 29223, 29233, 29243, 29253, 29263, 29273, 29283, 29293, + 29303, 29313, 29323, 29333, 29343, 1949, 29353, 29363, 29373, 29383, + 29393, 29403, 29413, 29423, 29433, 29443, 29453, 29463, 29473, 29483, + 29493, 29503, 29513, 29523, 29533, 29543, 29553, 29563, 29573, 29583, + 29593, 29603, 29613, 29623, 29633, 29643, 29653, 29663, 29673, 29683, + 29693, 29703, 29713, 29723, 29733, 29743, 29753, 29763, 29773, 29783, + 29793, 29803, 29813, 29823, 29833, 29843, 29853, 29863, 29873, 29883, + 29893, 29903, 29913, 29923, 29933, 29942, 29951, 29960, 29969, 29978, + 29987, 29996, 30005, 30014, 30023, 30032, 30041, 30050, 30059, 30068, + 30077, 30086, 18958, 30095, 30104, 30113, 30122, 30131, 30140, 30149, + 30158, 30167, 30176, 30185, 30194, 30203, 30212, 30221, 30230, 30239, + 30248, 30257, 30266, 30275, 30284, 30293, 30302, 30311, 30320, 30329, + 30338, 30347, 30356, 30365, 30374, 30383, 30392, 30401, 30410, 30419, + 30428, 30437, 30446, 30455, 30464, 30473, 24926, 30482, 30491, 30500, + 30509, 30518, 30527, 30536, 30545, 30554, 30563, 30572, 30581, 30590, + 30599, 30608, 30617, 30626, 30635, 30644, 30653, 30662, 30671, 30680, + 30689, 30698, 30707, 30716, 25135, 30725, 30734, 30743, 30752, 30761, + 30770, 30779, 30788, 30797, 30806, 30815, 30824, 30833, 30842, 30851, + 30860, 30869, 30878, 30887, 30896, 30905, 1287, 30914, 30923, 30932, + 30941, 30950, 30959, 30968, 30977, 30986, 30995, 31004, 31013, 31022, + 31031, 31040, 31049, 29894, 31058, 31067, 31076, 31085, 31094, 31103, + 31112, 31121, 31130, 31139, 31148, 31157, 31166, 31175, 31184, 31193, + 31202, 31211, 31220, 31229, 31238, 31247, 31256, 31265, 31274, 31283, + 31292, 31301, 31310, 31319, 31328, 31337, 31346, 31355, 31364, 31373, + 31382, 31391, 31400, 31409, 31418, 31427, 31436, 31445, 31454, 31463, + 31472, 31481, 31490, 31499, 31508, 31517, 31526, 31535, 31544, 31553, + 31562, 31571, 31580, 31589, 31598, 31607, 31616, 31625, 31634, 31643, + 31652, 31661, 31670, 31679, 31688, 31697, 31706, 31715, 31724, 31733, + 31742, 31751, 31760, 31769, 31778, 31787, 31796, 31805, 31814, 31823, + 31832, 31841, 31850, 31859, 31868, 31877, 31886, 31895, 31904, 31913, + 31922, 31931, 31940, 31949, 31958, 31967, 31976, 31985, 31994, 32003, + 32012, 32021, 32030, 32039, 32048, 32057, 32066, 32075, 32084, 32093, + 32102, 32111, 32120, 32129, 32138, 32147, 32156, 32165, 32174, 32183, + 32192, 32201, 32210, 10766, 32219, 32228, 32237, 32246, 32255, 32264, + 32273, 32282, 32291, 32300, 32309, 32318, 32327, 32336, 32345, 32354, + 32363, 32372, 32381, 32390, 32399, 32408, 32417, 32426, 32435, 32444, + 32453, 32462, 32471, 32480, 32489, 32498, 32507, 32516, 32525, 32534, + 32543, 32552, 32561, 32570, 32579, 32588, 32597, 32606, 32615, 32624, + 32633, 32642, 32651, 32660, 32669, 32678, 32687, 32696, 32705, 32714, + 32723, 1848, 32732, 32741, 32750, 32759, 32768, 32777, 32786, 32795, + 32804, 32813, 32822, 32831, 32840, 32849, 32858, 32867, 32876, 32885, + 32894, 32903, 32912, 32921, 32930, 32939, 32948, 32957, 32966, 32975, + 32984, 32993, 33002, 33011, 33020, 33029, 33038, 33047, 33056, 33065, + 33074, 33083, 33091, 33099, 33107, 33115, 18289, 33123, 33131, 33139, + 33147, 33155, 33163, 33171, 33179, 33187, 33195, 33203, 33211, 33219, + 33227, 33235, 33243, 33251, 33259, 33267, 27465, 33275, 33283, 33291, + 33299, 33307, 33315, 33323, 33331, 33339, 33347, 19609, 33355, 33363, + 33371, 33379, 33387, 33395, 33403, 18317, 33411, 33419, 33427, 33435, + 33443, 1471, 33451, 33459, 2047, 19765, 33467, 1967, 33475, 33483, 33491, + 18373, 33499, 33507, 33515, 33523, 18985, 22362, 33531, 33539, 33547, + 33555, 33563, 33571, 33579, 33587, 33595, 33603, 30402, 33611, 33619, + 33627, 33635, 33643, 33651, 33659, 33667, 33675, 33683, 33691, 1815, + 33699, 33707, 33715, 33723, 33731, 33739, 33747, 33755, 33763, 33771, + 33779, 33787, 33795, 33803, 33811, 33819, 33827, 33835, 33843, 33851, + 33859, 33867, 33875, 33883, 33891, 33899, 33907, 33915, 33923, 33931, + 33939, 33947, 33955, 33963, 33971, 33979, 33987, 33995, 34003, 34011, + 34019, 34027, 34035, 34043, 34051, 34059, 34067, 34075, 34083, 34091, + 27265, 34099, 34107, 34115, 34123, 34131, 34139, 34147, 34155, 34163, + 34171, 34179, 34187, 34195, 34203, 34211, 34219, 30906, 34227, 34235, + 34243, 34251, 34259, 34267, 34275, 34283, 34291, 34299, 34307, 34315, + 34323, 34331, 34339, 34347, 34355, 34363, 34371, 34379, 34387, 34395, + 34403, 34411, 34419, 34427, 34435, 34443, 34451, 34459, 34467, 34475, + 34483, 34491, 34499, 34507, 34515, 34523, 34531, 34539, 34547, 27325, + 34555, 34563, 34571, 34579, 34587, 34595, 34603, 34611, 34619, 34627, + 34635, 34643, 34651, 34659, 34667, 34675, 34683, 26467, 34691, 34699, + 34707, 34715, 34723, 34731, 34739, 34747, 34755, 34763, 34771, 34779, + 34787, 34795, 34803, 34811, 34819, 34827, 34835, 34843, 34851, 34859, + 34867, 34875, 34883, 34891, 34899, 34907, 34915, 34923, 34931, 34939, + 34947, 34955, 34963, 34971, 34979, 34987, 34995, 30951, 35003, 35011, + 35019, 35027, 35035, 35043, 35051, 35059, 35067, 35075, 35083, 35091, + 35099, 26588, 35107, 35115, 1934, 35123, 35131, 35139, 35147, 35155, + 35163, 35171, 35179, 32706, 35187, 35195, 35203, 35211, 35219, 35227, + 35235, 35243, 35251, 35259, 35267, 35275, 35283, 35291, 35299, 35307, + 35315, 35323, 35331, 35339, 2015, 35347, 35355, 10863, 35363, 35371, + 35379, 35387, 35395, 35403, 35411, 35419, 35427, 23310, 35435, 35443, + 35451, 35459, 35467, 35475, 35483, 35491, 35499, 35507, 35515, 35523, + 35531, 35539, 35547, 35555, 35563, 35571, 35579, 35587, 35595, 35603, + 35611, 35619, 35627, 35635, 35643, 35651, 35659, 35667, 35675, 35683, + 19141, 35691, 35699, 35707, 35715, 35723, 35731, 35739, 35747, 35755, + 1710, 35763, 35771, 35779, 35787, 35795, 35803, 35811, 35819, 35827, + 35835, 35843, 35851, 35859, 35867, 35875, 35883, 35891, 35899, 35907, + 35915, 35923, 35931, 35939, 35947, 35955, 35963, 35971, 35979, 35987, + 35995, 36003, 36011, 36019, 18905, 36027, 36035, 36043, 36051, 36059, + 36067, 36075, 36083, 36091, 36099, 36107, 28965, 36115, 36123, 36131, + 36139, 36147, 36155, 36163, 36171, 36179, 36187, 36195, 36202, 36209, + 36216, 36223, 36230, 19753, 36237, 36244, 36251, 36258, 36265, 36272, + 36279, 36286, 36293, 36300, 36307, 36314, 36321, 36328, 36335, 36342, + 36349, 11047, 36356, 36363, 36370, 36377, 36384, 36391, 36398, 36405, + 36412, 36419, 36426, 36433, 36440, 36447, 36454, 36461, 36468, 36475, + 36482, 36489, 36496, 36503, 36510, 36517, 1510, 36524, 36531, 1603, + 36538, 36545, 36552, 36559, 36566, 36573, 36580, 36587, 36594, 36601, + 36608, 36615, 36622, 36629, 36636, 36643, 36650, 1354, 36657, 36664, + 36671, 36678, 36685, 36692, 36699, 36706, 36713, 36720, 36727, 36734, + 36741, 36748, 36755, 36762, 36769, 36776, 36783, 26578, 36790, 36797, + 36804, 36811, 36818, 36825, 36832, 36839, 36846, 36853, 36860, 36867, + 36874, 36881, 36888, 36895, 36902, 36909, 36916, 36923, 36930, 36937, + 36944, 36951, 36958, 36965, 36972, 36979, 36986, 36993, 30187, 37000, + 37007, 37014, 37021, 37028, 37035, 37042, 37049, 37056, 37063, 37070, + 37077, 37084, 37091, 37098, 37105, 37112, 37119, 37126, 37133, 37140, + 37147, 37154, 37161, 37168, 37175, 37182, 37189, 37196, 37203, 37210, + 37217, 37224, 37231, 37238, 37245, 37252, 37259, 37266, 37273, 37280, + 22123, 37287, 37294, 37301, 37308, 37315, 37322, 37329, 37336, 37343, + 37350, 37357, 37364, 37371, 37378, 37385, 37392, 37399, 37406, 37413, + 37420, 37427, 37434, 37441, 37448, 37455, 37462, 37469, 37476, 37483, + 37490, 25291, 37497, 37504, 37511, 37518, 37525, 37532, 37539, 37546, + 37553, 37560, 37567, 30403, 37574, 37581, 37588, 37595, 37602, 37609, + 37616, 37623, 37630, 1747, 37637, 37644, 37651, 37658, 37665, 37672, + 37679, 37686, 37693, 37700, 37707, 37714, 37721, 37728, 37735, 37742, + 37749, 37756, 37763, 37770, 37777, 37784, 37791, 37798, 37805, 37812, + 37819, 37826, 37833, 37840, 37847, 37854, 37861, 37868, 37875, 37882, + 37889, 37896, 37903, 37910, 37917, 37924, 37931, 37938, 37945, 37952, + 37959, 37966, 30952, 37973, 37980, 37987, 37994, 38001, 38008, 38015, + 38022, 38029, 38036, 38043, 38050, 38057, 38064, 38071, 38078, 38085, + 38092, 38099, 38106, 38113, 38120, 38127, 38134, 38141, 38148, 38155, + 26512, 38162, 38169, 38176, 38183, 38190, 38197, 38204, 38211, 38218, + 38225, 38232, 38239, 38246, 38253, 34308, 38260, 38267, 38274, 38281, + 38288, 38295, 38302, 38309, 38316, 38323, 38330, 38337, 38344, 38351, + 38358, 38365, 38372, 38379, 38386, 38393, 38400, 38407, 38414, 38421, + 38428, 38435, 38442, 38449, 38456, 38463, 38470, 38477, 38484, 38491, + 38498, 38505, 38512, 38519, 38526, 38533, 38540, 38547, 38554, 38561, + 38568, 38575, 38582, 29166, 38589, 38596, 38603, 38610, 38617, 35596, + 38624, 38631, 38638, 38645, 38652, 38659, 38666, 38673, 38680, 38687, + 38694, 33196, 38701, 38708, 38715, 38722, 38729, 38736, 38743, 38750, + 38757, 38764, 38771, 38778, 38785, 38792, 38799, 38806, 38813, 38820, + 38827, 38834, 38841, 38848, 38855, 38862, 38869, 38876, 38883, 38890, + 38897, 38904, 30772, 38911, 38918, 38925, 38932, 23167, 38939, 38946, + 38953, 38960, 38967, 38974, 38981, 38988, 38995, 39002, 39009, 39016, + 39023, 39030, 39037, 39044, 39051, 39058, 39065, 39072, 39079, 39086, + 39093, 39100, 39107, 39114, 39121, 39128, 30970, 39135, 39142, 39149, + 28966, 39156, 39163, 39170, 39177, 39184, 39191, 39198, 39205, 39212, + 39219, 39226, 39233, 39240, 39247, 39254, 39261, 39267, 39273, 39279, + 39285, 39291, 39297, 39303, 39309, 39315, 39321, 39327, 38086, 33917, + 39333, 39339, 39345, 39351, 27927, 39357, 39363, 39369, 39375, 39381, + 39387, 39393, 39399, 27127, 39405, 39411, 39417, 39423, 39255, 39429, + 39435, 39441, 39447, 39453, 39459, 39465, 27227, 39471, 39477, 39483, + 39489, 39495, 39501, 39507, 39513, 39519, 39525, 39531, 39537, 39543, + 39549, 39555, 39561, 27287, 39567, 39573, 39579, 39585, 25061, 22148, + 39591, 19299, 28047, 39597, 39603, 39609, 39615, 19065, 39621, 39627, + 1312, 39633, 39639, 1549, 22580, 39645, 39651, 18347, 39657, 22448, + 39663, 39669, 1416, 39675, 18753, 39681, 19286, 39687, 39693, 39699, + 39705, 39711, 39717, 39723, 39729, 39735, 39741, 33613, 39747, 39753, + 39759, 39765, 27137, 39771, 39777, 39783, 39789, 39795, 39801, 39807, + 39813, 39819, 39825, 39831, 10973, 1198, 39837, 39843, 39849, 39855, + 39861, 39867, 39873, 39879, 39885, 39891, 39897, 39903, 39909, 39915, + 39921, 39927, 39933, 39939, 39945, 39951, 22460, 39957, 39963, 39969, + 39975, 39981, 39987, 39993, 39999, 40005, 40011, 40017, 40023, 40029, + 40035, 40041, 40047, 40053, 40059, 26876, 40065, 40071, 40077, 40083, + 40089, 40095, 40101, 40107, 40113, 40119, 40125, 30980, 27197, 40131, + 40137, 40143, 40149, 40155, 40161, 40167, 40173, 40179, 40185, 40191, + 40197, 40203, 40209, 40215, 40221, 40227, 40233, 40239, 40245, 40251, + 40257, 40263, 40269, 40275, 40281, 40287, 40293, 40299, 40305, 27377, + 40311, 40317, 40323, 40329, 40335, 40341, 40347, 40353, 40359, 40365, + 40371, 40377, 40383, 40389, 40395, 40401, 40407, 40413, 40419, 40425, + 40431, 40437, 40443, 40449, 40455, 40461, 40467, 40473, 40479, 40485, + 40491, 40497, 40503, 40509, 40515, 40521, 40527, 40533, 40539, 40545, + 32861, 40551, 40557, 40563, 40569, 40575, 40581, 40587, 40593, 40599, + 40605, 40611, 40617, 40623, 40629, 40635, 40641, 40647, 40653, 40659, + 40665, 40671, 40677, 40683, 40689, 40695, 40701, 40707, 40713, 26469, + 40719, 40725, 40731, 40737, 40743, 40749, 40755, 40761, 40767, 40773, + 40779, 40785, 40791, 40797, 40803, 40809, 40815, 40821, 40827, 40833, + 40839, 40845, 40851, 27367, 40857, 40863, 40869, 40875, 40881, 40887, + 40893, 40899, 40905, 40911, 40917, 40923, 40929, 40935, 40941, 40947, + 40953, 40959, 40965, 40971, 40977, 40983, 40989, 40995, 41001, 41007, + 41013, 41019, 41025, 41031, 41037, 41043, 37827, 41049, 41055, 41061, + 41067, 41073, 41079, 41085, 41091, 41097, 41103, 34469, 41109, 41115, + 41121, 41127, 41133, 41139, 41145, 41151, 41157, 41163, 41169, 41175, + 41181, 36093, 41187, 41193, 41199, 41205, 41211, 41217, 41223, 41229, + 41235, 41241, 41247, 41253, 41259, 41265, 41271, 41277, 41283, 41289, + 41295, 41301, 41307, 41313, 41319, 41325, 41331, 41337, 41343, 41349, + 41355, 41361, 41367, 41373, 41379, 41385, 41391, 41397, 41403, 41409, + 41415, 41421, 41427, 41433, 41439, 41445, 34701, 41451, 41457, 41463, + 41469, 41475, 41481, 41487, 22712, 41493, 41499, 41505, 41511, 41517, + 41523, 41529, 41535, 41541, 41547, 41553, 41559, 41565, 41571, 41577, + 41583, 41589, 41595, 41601, 41607, 41613, 41619, 41625, 41631, 41637, + 41643, 41649, 41655, 41661, 41667, 41673, 41679, 41685, 41691, 41697, + 41703, 41709, 41715, 41721, 41727, 41733, 41739, 41745, 41751, 41757, + 41763, 41769, 41775, 41781, 41787, 41793, 41799, 41805, 41811, 41817, + 41823, 41829, 41835, 41841, 41847, 41853, 41859, 41865, 41871, 41877, + 41883, 41889, 41895, 41901, 41907, 41913, 41919, 41925, 41931, 41937, + 41943, 41949, 41955, 41961, 41967, 41973, 41979, 41985, 41991, 41997, + 42003, 42009, 42015, 42021, 42027, 42033, 42039, 42045, 42051, 42057, + 42063, 42069, 42075, 42081, 42087, 42093, 42099, 42105, 42111, 42117, + 42123, 42129, 42135, 42141, 42147, 42153, 42159, 42165, 42171, 42177, + 42183, 42189, 37169, 42195, 42201, 42207, 42213, 42219, 42225, 42231, + 42237, 42243, 42249, 42255, 42261, 42267, 42273, 42279, 42285, 42291, + 42297, 42303, 42309, 42315, 42321, 42327, 42333, 42339, 42345, 42351, + 42357, 42363, 42369, 42375, 42381, 42387, 42393, 42399, 42405, 42411, + 42417, 42423, 42429, 42435, 42441, 42447, 42453, 42459, 42465, 42471, + 42477, 42483, 42489, 42495, 42501, 42507, 42513, 42519, 42525, 42531, + 42537, 42543, 42549, 42555, 42561, 42567, 42573, 42579, 42585, 42591, + 42597, 42603, 42609, 42615, 42621, 42627, 42633, 42639, 42645, 42651, + 42657, 42663, 42669, 42675, 42681, 42687, 42693, 42699, 42705, 42711, + 42717, 42723, 42729, 32393, 42735, 42741, 42747, 42753, 42759, 42765, + 42771, 42777, 42783, 42789, 42795, 42801, 42807, 42813, 42819, 42825, + 42831, 42837, 42843, 42849, 42855, 10943, 42861, 42867, 42873, 42879, + 42885, 42891, 42897, 42903, 42909, 42915, 42921, 42927, 42933, 42939, + 22496, 42945, 42951, 42957, 39122, 42963, 42969, 30989, 42975, 42981, + 42987, 42993, 42999, 43005, 43011, 43017, 43023, 43029, 43035, 43041, + 43047, 43053, 43059, 43065, 43071, 43077, 43083, 43089, 43095, 43101, + 43107, 43113, 43119, 43125, 43131, 43137, 43143, 43149, 43155, 43161, + 43167, 43173, 43179, 43185, 29087, 43191, 43197, 43203, 43209, 43215, + 43221, 43227, 43233, 43239, 43245, 43251, 43257, 43263, 43269, 43275, + 43281, 43287, 43293, 43299, 43305, 43311, 43317, 43323, 43329, 43335, + 43341, 43347, 43353, 43359, 43365, 43371, 43376, 43381, 43386, 43391, + 43396, 43401, 43406, 43411, 43416, 30198, 43421, 19157, 43426, 43431, + 40864, 43436, 43441, 43446, 28858, 43451, 43456, 43461, 43466, 43471, + 43476, 43481, 43486, 43491, 43496, 43501, 43506, 43511, 43060, 43516, + 41068, 29308, 43521, 43526, 43531, 39784, 43536, 43541, 43546, 43551, + 43556, 43561, 43566, 43571, 43576, 40024, 43581, 43586, 43591, 43596, + 43601, 32682, 43606, 43611, 43616, 43621, 43626, 43631, 43636, 43641, + 43646, 43651, 43656, 43661, 43666, 43671, 43676, 43681, 43686, 43691, + 43696, 1377, 43701, 43706, 43711, 43716, 17919, 43721, 43726, 43731, + 43736, 43741, 43746, 43751, 43756, 43761, 43766, 43771, 43776, 43781, + 43786, 40900, 43791, 43796, 43801, 43806, 43811, 43816, 43821, 43826, + 43831, 43836, 43841, 43846, 43851, 43856, 43861, 43866, 43871, 43876, + 43881, 43886, 39880, 43891, 43896, 42916, 43901, 43906, 434, 43911, + 31152, 43916, 43921, 43926, 43931, 43936, 43941, 43946, 43951, 43956, + 1153, 43961, 43966, 43971, 43976, 43981, 27058, 43986, 43991, 43996, + 44001, 44006, 44011, 39382, 44016, 44021, 44026, 44031, 44036, 44041, + 44046, 44051, 44056, 44061, 44066, 44071, 44076, 44081, 44086, 44091, + 44096, 44101, 44106, 44111, 18949, 44116, 44121, 44126, 44131, 44136, + 44141, 44146, 44151, 44156, 44161, 44166, 44171, 44176, 44181, 44186, + 44191, 43294, 44196, 38220, 44201, 44206, 44211, 44216, 44221, 44226, + 44231, 44236, 42958, 19404, 44241, 44246, 44251, 44256, 40120, 44261, + 44266, 44271, 44276, 44281, 44286, 44291, 44296, 26437, 44301, 44306, + 44311, 44316, 29288, 44321, 44326, 44331, 44336, 44341, 44346, 44351, + 44356, 44361, 44366, 44371, 44376, 44381, 44386, 44391, 44396, 44401, + 44406, 44411, 44416, 44421, 44426, 44431, 44436, 44441, 44446, 44451, + 44456, 44461, 44466, 44471, 44476, 26591, 44481, 44486, 44491, 44496, + 27388, 44501, 33830, 44506, 44511, 44516, 44521, 44526, 44531, 44536, + 44541, 44546, 44551, 44556, 44561, 44566, 44571, 44576, 44581, 44586, + 44591, 44596, 44601, 42634, 44606, 44611, 44616, 32745, 44621, 44626, + 30819, 44631, 44636, 44641, 44646, 44651, 44656, 41446, 44661, 44666, + 37100, 44671, 44676, 44681, 18572, 44686, 44691, 44696, 44701, 35590, + 44706, 44711, 44716, 44721, 44726, 44731, 36974, 38633, 44736, 44741, + 44746, 44751, 44756, 44761, 44766, 44771, 44776, 44781, 44786, 44791, + 44796, 44801, 44806, 44811, 44816, 44821, 44826, 44831, 44836, 44841, + 44846, 44851, 43054, 44856, 37275, 44861, 44866, 44871, 44876, 36358, + 44881, 44886, 44891, 44896, 44901, 44906, 44911, 44916, 44921, 44926, + 44931, 44936, 44941, 44946, 44951, 44956, 44961, 44966, 44971, 44976, + 44981, 28938, 44986, 44991, 44996, 45001, 45006, 38136, 45011, 45016, + 45021, 45026, 45031, 45036, 45041, 45046, 32934, 45051, 45056, 45061, + 45066, 45071, 45076, 45081, 45086, 45091, 45096, 45101, 45106, 45111, + 45116, 45121, 45126, 45131, 45136, 45141, 45146, 45151, 45156, 45161, + 45166, 45171, 45176, 45181, 45186, 45191, 45196, 45201, 45206, 45211, + 45216, 45221, 45226, 45231, 45236, 45241, 45246, 45251, 45256, 45261, + 45266, 45271, 45276, 45281, 45286, 45291, 45296, 45301, 45306, 45311, + 45316, 45321, 45326, 45331, 45336, 45341, 45346, 45351, 45356, 45361, + 45366, 45371, 45376, 45381, 45386, 45391, 45396, 45401, 45406, 45411, + 45416, 45421, 45426, 45431, 45436, 45441, 45446, 45451, 45456, 45461, + 45466, 45471, 45476, 45481, 45486, 45491, 45496, 45501, 45506, 45511, + 45516, 45521, 45526, 45531, 45536, 45541, 45546, 45551, 45556, 45561, + 45566, 45571, 45576, 45581, 45586, 45591, 45596, 45601, 45606, 45611, + 45616, 45621, 45626, 45631, 45636, 45641, 45646, 45651, 45656, 45661, + 45666, 45671, 45676, 45681, 45686, 45691, 45696, 45701, 45706, 45711, + 45716, 45721, 45726, 40750, 40756, 40762, 45731, 45736, 45741, 45746, + 45751, 45756, 45761, 45766, 45771, 45776, 29328, 40768, 40774, 40780, + 45781, 42142, 45786, 45791, 45796, 45801, 45806, 45811, 45816, 45821, + 45826, 45831, 45836, 45841, 45846, 40894, 45851, 45856, 45861, 45866, + 45871, 45876, 45881, 45886, 45891, 45896, 45901, 45906, 45911, 45916, + 45921, 45926, 39682, 45931, 45936, 45941, 45946, 45951, 45956, 45961, + 45966, 45971, 45976, 45981, 45986, 45991, 45996, 46001, 46006, 46011, + 46016, 46021, 46026, 46031, 46036, 46041, 46046, 46051, 46056, 46061, + 46066, 46071, 46076, 46081, 46086, 46091, 46096, 46101, 46106, 46111, + 46116, 46121, 46126, 46131, 46136, 46141, 46146, 46151, 46156, 46161, + 46166, 46171, 46176, 46181, 41074, 41080, 46186, 46191, 46196, 46201, + 46206, 46211, 46216, 46221, 41092, 41098, 46226, 46231, 30666, 46236, + 46241, 46246, 43258, 43264, 46251, 46256, 46261, 46266, 46271, 46276, + 46281, 46286, 46291, 46296, 46301, 46306, 46311, 46316, 46321, 46326, + 46331, 46336, 46341, 46346, 46351, 46356, 46361, 46366, 46371, 46376, + 46381, 46386, 46391, 46396, 46401, 46406, 46411, 46416, 46421, 46426, + 41374, 46431, 41380, 46436, 46441, 46446, 18446, 33486, 46451, 41386, + 41392, 41398, 41404, 41410, 41416, 46456, 46461, 46466, 46471, 40924, + 46476, 40810, 46481, 46486, 46491, 42976, 46496, 46501, 46506, 46511, + 46516, 46521, 46526, 46531, 46536, 46541, 46546, 46551, 46556, 46561, + 46566, 46571, 46576, 46581, 46586, 46591, 46596, 46601, 46606, 46611, + 46616, 46621, 46626, 46631, 46636, 46641, 46646, 46651, 46656, 46661, + 46666, 46671, 46676, 46681, 46686, 46691, 46696, 46701, 46706, 46711, + 46716, 46721, 46726, 46731, 46736, 46741, 46746, 46751, 46756, 46761, + 46766, 46771, 46776, 42484, 40960, 40966, 40972, 42562, 46781, 46786, + 46791, 46796, 46801, 46806, 46811, 46816, 46821, 46826, 46831, 46836, + 46841, 46846, 46851, 46856, 46861, 46866, 46871, 46876, 46881, 46886, + 46891, 46896, 46901, 46906, 41686, 41692, 41698, 46911, 46916, 46921, + 46926, 46931, 46936, 46941, 46946, 46951, 46956, 46961, 46966, 46971, + 46976, 46981, 46986, 41704, 46991, 41710, 41716, 42232, 46996, 47001, + 47006, 47011, 47016, 47021, 47026, 47031, 47036, 47041, 47046, 47051, + 47056, 47061, 47066, 47071, 47076, 47081, 47086, 47091, 47096, 47101, + 47106, 47111, 47116, 47121, 47126, 47131, 47136, 47141, 47146, 47151, + 39280, 47156, 47161, 47166, 47171, 47176, 47181, 47186, 47191, 47196, + 43024, 47201, 47206, 41500, 47211, 41506, 47216, 47221, 47226, 47231, + 47236, 41512, 47241, 41518, 41524, 41530, 47246, 38031, 47251, 47256, + 47261, 47266, 47271, 47276, 47281, 47286, 47291, 47296, 47301, 47306, + 47311, 47316, 47321, 47326, 47331, 47336, 47341, 41536, 41542, 47346, + 47351, 47356, 47361, 47366, 47371, 47376, 47381, 47386, 35374, 47391, + 47396, 41548, 47401, 41554, 29338, 41560, 47406, 47411, 47416, 47421, + 38542, 47426, 47431, 47436, 47441, 47446, 47451, 47456, 47461, 47466, + 47471, 47476, 47481, 47486, 47491, 47496, 47501, 47506, 47511, 47516, + 47521, 47526, 39646, 47531, 47536, 47541, 47546, 47551, 47556, 47561, + 47566, 47571, 47576, 47581, 42238, 47586, 47591, 47596, 47601, 47606, + 47611, 47616, 42244, 47621, 42250, 47626, 47631, 47636, 47641, 41572, + 41584, 39586, 47646, 47651, 47656, 47661, 47666, 47671, 47676, 47681, + 47686, 47691, 47696, 47701, 47706, 47711, 47716, 47721, 47726, 47731, + 38773, 47736, 47741, 47746, 47751, 47756, 47761, 47766, 47771, 47776, + 47781, 47786, 47791, 47796, 47801, 47806, 47811, 47816, 47821, 47826, + 41590, 47831, 47836, 47841, 47846, 47851, 47856, 47861, 47866, 47871, + 47876, 47881, 47886, 47891, 47896, 47901, 47906, 47911, 47916, 47921, + 47926, 47931, 47936, 47941, 47946, 47951, 47956, 47961, 47966, 47971, + 47976, 47981, 47986, 47991, 47996, 48001, 48006, 48011, 48016, 48021, + 48026, 48031, 48036, 48041, 48046, 48051, 48056, 48061, 48066, 48071, + 48076, 48081, 48086, 48091, 48096, 48101, 48106, 48111, 48116, 48121, + 48126, 48131, 48136, 48141, 48146, 48151, 48156, 48161, 48166, 48171, + 48176, 48181, 48186, 48191, 48196, 48201, 48206, 48211, 48216, 48221, + 48226, 48231, 48236, 48241, 48246, 48251, 48256, 48261, 48266, 48271, + 48276, 48281, 48286, 48291, 48296, 42520, 48301, 48306, 48311, 48316, + 48321, 48326, 48331, 48336, 48341, 48346, 48351, 48356, 48361, 48366, + 48371, 48376, 48381, 48386, 48391, 48396, 42646, 42274, 48401, 42280, + 48406, 48411, 48416, 48421, 48426, 48431, 48436, 48441, 48446, 48451, + 48456, 48461, 48466, 48471, 48476, 48481, 48486, 48491, 48496, 48501, + 48506, 48511, 48516, 48521, 48526, 48531, 48536, 48541, 42880, 42886, + 48546, 48551, 48556, 48561, 48566, 31089, 48571, 942, 48576, 48581, + 48586, 48591, 48596, 48601, 48606, 48611, 48616, 48621, 48626, 48631, + 48636, 48641, 48646, 48651, 48656, 48661, 48666, 48671, 48676, 48681, + 48686, 48691, 48696, 48701, 48706, 48711, 48716, 48721, 27328, 48726, + 48731, 42892, 48736, 48741, 48746, 48751, 48756, 48761, 48766, 48771, + 48776, 48781, 42382, 48786, 48791, 48796, 48801, 48806, 48811, 48816, + 48821, 48826, 27138, 48831, 48836, 48841, 48846, 48851, 48856, 38486, + 48861, 48866, 48871, 48876, 48881, 48886, 48891, 48896, 48901, 48906, + 48911, 48916, 48921, 48926, 48931, 48936, 48941, 48946, 48951, 48956, + 48961, 48966, 40636, 48971, 33406, 39011, 29348, 48976, 48981, 48986, + 48991, 48996, 49001, 49006, 49011, 49016, 33702, 49021, 49026, 49031, + 49036, 49041, 41620, 41626, 41632, 49046, 41650, 41836, 41842, 49051, + 49056, 49061, 49066, 49071, 49076, 49081, 49086, 49091, 49096, 49101, + 49106, 49111, 49116, 49121, 49126, 49131, 49136, 49141, 42292, 42298, + 42304, 49146, 49151, 49156, 49161, 49166, 49171, 49176, 49181, 49186, + 42310, 49191, 42316, 49196, 49201, 49206, 49211, 49216, 49221, 49226, + 49231, 49236, 49241, 49246, 49251, 49256, 49261, 49266, 49271, 49276, + 49281, 49286, 49291, 49296, 49301, 49306, 42322, 42328, 49311, 42334, + 42340, 42346, 49316, 49321, 49326, 49331, 49336, 49341, 49346, 49351, + 49356, 49361, 49366, 49371, 49376, 49381, 49386, 49391, 49396, 49401, + 49406, 49411, 49416, 602, 49420, 27259, 49424, 33007, 24876, 49428, + 49432, 49436, 33959, 42581, 49440, 49444, 19743, 41909, 26427, 49448, + 49452, 49456, 41225, 32368, 40451, 49460, 49464, 49468, 32638, 49472, + 49476, 49480, 39395, 39797, 45837, 49484, 49488, 49492, 22282, 49496, + 49500, 49504, 38858, 41069, 49508, 18601, 49512, 49516, 49520, 28969, + 49524, 49528, 49532, 49536, 39473, 45832, 49540, 33559, 27159, 45652, + 36268, 19197, 39737, 49544, 26570, 49548, 44277, 31081, 49552, 49556, + 49560, 49564, 30451, 38543, 49568, 29069, 40811, 49572, 37374, 48912, + 49576, 40895, 46937, 49580, 49584, 44857, 49588, 49592, 38914, 49596, + 43817, 23302, 45842, 49600, 49604, 49608, 49612, 260, 35095, 49616, + 49620, 25503, 49624, 49628, 39845, 49632, 30928, 40409, 49636, 49640, + 49644, 46227, 49648, 49652, 49656, 49660, 46067, 49664, 49668, 49672, + 49676, 49680, 47192, 49684, 49688, 49692, 49696, 49700, 46912, 33052, + 49704, 49708, 49712, 49716, 49720, 49724, 49728, 49732, 49736, 47732, + 33943, 49740, 49744, 49748, 49752, 49756, 49760, 49764, 48582, 49768, + 27439, 43055, 40319, 34151, 49772, 49776, 49780, 40481, 46457, 46462, + 49784, 46232, 39131, 49788, 49792, 49796, 49800, 45847, 36842, 49804, + 48442, 32125, 49808, 40523, 35775, 37332, 49812, 49816, 42239, 49820, + 37136, 24694, 45892, 38123, 49824, 49828, 49832, 49836, 48567, 49840, + 49844, 49848, 44827, 49852, 49856, 49860, 49864, 49868, 49872, 47727, + 46742, 49876, 38746, 49880, 49884, 49888, 49892, 49896, 49900, 49904, + 49908, 47742, 48307, 49912, 49916, 49920, 49924, 49928, 49932, 48877, + 31270, 37213, 48887, 49936, 22030, 49940, 1177, 48922, 48927, 29089, + 48712, 49944, 34047, 49948, 49952, 49956, 49960, 49964, 40493, 49968, + 49972, 37423, 45067, 49976, 49980, 37430, 43295, 49984, 49988, 40013, + 49992, 49996, 50000, 50004, 50008, 50012, 50016, 30739, 45667, 50020, + 45817, 38291, 34607, 50024, 50028, 50032, 50036, 50040, 50044, 50048, + 50052, 50056, 50060, 50064, 50068, 50072, 50076, 50080, 50084, 50088, + 50092, 50096, 31144, 50100, 50104, 50108, 50112, 50116, 50120, 50124, + 50128, 46342, 46347, 50132, 50136, 50140, 50144, 50148, 50152, 50156, + 50160, 46377, 50164, 40901, 43692, 50168, 50172, 42809, 50176, 50180, + 50184, 50188, 50192, 41159, 50196, 33079, 50200, 50204, 50208, 50212, + 50216, 50220, 50224, 50228, 50232, 46202, 44837, 44842, 46527, 50236, + 50240, 50244, 46587, 50248, 22750, 50252, 50256, 46637, 50260, 30748, + 50264, 50268, 50272, 50276, 50280, 35103, 50284, 50288, 50292, 50296, + 50300, 50304, 43972, 50308, 42257, 50312, 50316, 50320, 50324, 24898, + 50328, 32503, 50332, 50336, 33903, 50340, 50344, 50348, 41963, 50352, + 50356, 50360, 50364, 50368, 18447, 47747, 973, 50372, 50376, 50380, + 50384, 48587, 50388, 30289, 50392, 50396, 50400, 50404, 50408, 50412, + 50416, 50420, 50424, 50428, 50432, 48882, 50436, 50440, 50444, 50448, + 35671, 50452, 50456, 34495, 50460, 40031, 50464, 50468, 50472, 30325, + 50476, 42605, 50480, 38445, 50484, 50488, 50492, 50496, 50500, 50504, + 50508, 50512, 41417, 40487, 50516, 50520, 40403, 50524, 50528, 50532, + 50536, 50540, 47867, 50544, 47882, 47912, 50548, 50552, 50556, 48737, + 50560, 50564, 50568, 44287, 50572, 44617, 47972, 50576, 50580, 50584, + 42017, 50588, 49067, 34375, 42161, 50592, 50596, 43229, 31099, 40253, + 50600, 32989, 50604, 34559, 27229, 50608, 50612, 50616, 50620, 50624, + 50628, 50632, 50636, 50640, 50644, 50648, 50652, 50656, 50660, 50664, + 50668, 50672, 50676, 50680, 50684, 50688, 50692, 50696, 50700, 50704, + 50708, 50712, 50716, 50720, 50724, 50728, 50732, 50736, 50740, 50744, + 50748, 50752, 50756, 50760, 50764, 50768, 50772, 50776, 50780, 50784, + 50788, 50792, 50796, 50800, 50804, 50808, 50812, 50816, 50820, 50824, + 50828, 50832, 50836, 50840, 50844, 50848, 50852, 50856, 50860, 50864, + 50868, 50872, 50876, 50880, 50884, 50888, 50892, 50896, 50900, 50904, + 50908, 50912, 50916, 50920, 50924, 50928, 50932, 50936, 50940, 50944, + 50948, 50952, 50956, 50960, 50964, 50968, 50972, 50976, 50980, 50984, + 50988, 50992, 50996, 51000, 51004, 51008, 51012, 51016, 51020, 51024, + 51028, 51032, 51036, 51040, 51044, 51048, 51052, 51056, 51060, 51064, + 51068, 51072, 45597, 35295, 45607, 51076, 51080, 51084, 51088, 51092, + 51096, 51100, 32494, 51104, 51108, 45612, 51112, 51116, 45617, 51120, + 51124, 44587, 51128, 45627, 45632, 45637, 51132, 51136, 45642, 45647, + 45657, 45662, 44197, 45672, 51140, 51144, 51148, 45677, 47497, 45682, + 45687, 51152, 30100, 51156, 51160, 51164, 51168, 51172, 51176, 51180, + 51184, 51188, 51192, 45822, 51196, 51200, 51204, 51208, 51212, 36541, + 51216, 51220, 51224, 51228, 51232, 51236, 51240, 51244, 51248, 51252, + 51256, 51260, 51264, 51268, 51272, 51276, 25481, 51280, 51284, 35543, + 51288, 46052, 51292, 46057, 36135, 51296, 46062, 51300, 42071, 46072, + 39647, 51304, 46082, 46087, 46092, 46097, 46102, 46857, 51308, 51312, + 51316, 46107, 48447, 46112, 46122, 51320, 51324, 51328, 46127, 46132, + 44267, 46137, 46142, 46147, 51332, 51336, 51340, 51344, 51348, 51352, + 51356, 51360, 51364, 51368, 51372, 51376, 51380, 51384, 26339, 44552, + 51388, 51392, 51396, 51400, 41117, 51404, 51408, 51412, 51416, 51420, + 51424, 51428, 51432, 51436, 51440, 51444, 51448, 51452, 51456, 51460, + 51464, 51468, 51472, 51476, 51480, 51484, 51488, 51492, 51496, 51500, + 51504, 51508, 51512, 46327, 51516, 46332, 46337, 51520, 51524, 37010, + 46352, 51528, 46357, 51532, 51536, 51540, 46362, 51544, 46367, 46372, + 51548, 44342, 46382, 51552, 461, 51556, 44347, 46387, 46392, 46397, + 46402, 46407, 46412, 46417, 51560, 51564, 51568, 51572, 51576, 51580, + 44467, 29909, 45857, 45867, 30217, 35999, 51584, 51588, 45872, 45877, + 45882, 41939, 51592, 51596, 51600, 51604, 44117, 26394, 32359, 51608, + 51612, 51616, 51620, 51624, 51628, 34967, 51632, 51636, 51640, 51644, + 51648, 45887, 32431, 44812, 36975, 45902, 45907, 51652, 45912, 39683, + 44742, 44747, 44752, 51656, 51660, 51664, 51668, 51672, 51676, 51680, + 51684, 51688, 51692, 51696, 49142, 31198, 40751, 40643, 40763, 26405, + 45007, 51700, 41747, 36031, 48837, 51704, 51708, 51712, 51716, 51720, + 51724, 44452, 46917, 46922, 46927, 51728, 51732, 51736, 46932, 46942, + 51740, 46947, 46952, 46957, 44457, 46962, 51744, 46967, 47707, 46972, + 46977, 51748, 51752, 32089, 51756, 51760, 47067, 51764, 622, 51768, + 51772, 25426, 51776, 51780, 51784, 51788, 51792, 51796, 51800, 51804, + 51808, 51812, 51816, 51820, 22210, 51824, 51828, 51832, 51836, 51840, + 51844, 51848, 51852, 51856, 51860, 51864, 51868, 51872, 51876, 51880, + 51884, 51888, 51892, 51896, 51900, 51904, 51908, 29899, 46502, 51912, + 44317, 46512, 51916, 51920, 46517, 36331, 24777, 51924, 44832, 48847, + 51928, 51932, 51936, 46277, 51940, 46537, 46542, 51944, 51948, 51952, + 46547, 51956, 284, 46552, 46557, 46562, 44757, 46572, 46577, 46582, + 46592, 46597, 51960, 30460, 51964, 46607, 46612, 51968, 51972, 51976, + 51980, 51984, 51988, 51992, 51996, 52000, 46617, 52004, 52008, 52012, + 52016, 46622, 41891, 46632, 52020, 52024, 46642, 46647, 46652, 46657, + 46662, 38298, 46672, 52028, 46677, 52032, 46687, 52036, 42095, 52040, + 46692, 18190, 46702, 52044, 52048, 52052, 52056, 52060, 39815, 52064, + 40085, 22678, 22138, 52068, 46707, 52072, 46712, 52076, 33679, 52080, + 35871, 27879, 46717, 41429, 46722, 33407, 46732, 52084, 52088, 52092, + 52096, 52100, 52104, 52108, 46737, 43337, 46747, 52112, 52116, 52120, + 52124, 52128, 46752, 52132, 52136, 46757, 52140, 52144, 52148, 37661, + 52152, 52156, 52160, 52164, 43259, 43265, 52168, 52172, 52176, 19652, + 43001, 52180, 52184, 52188, 44187, 52192, 52196, 52200, 52204, 52208, + 52212, 52216, 52220, 52224, 48577, 52228, 52232, 41123, 52236, 52240, + 52244, 52248, 52252, 52256, 52260, 52264, 52268, 52272, 52276, 52280, + 52284, 52288, 52292, 52296, 52300, 52304, 52308, 52312, 52316, 52320, + 52324, 52328, 52332, 52336, 52340, 52344, 52348, 52352, 52356, 52360, + 52364, 52368, 52372, 52376, 52380, 52384, 52388, 52392, 52396, 52400, + 52404, 52408, 52412, 52416, 52420, 52424, 52428, 52432, 52436, 52440, + 52444, 47752, 33119, 52448, 47757, 41363, 47767, 29009, 35311, 52452, + 52456, 52460, 43073, 52464, 52468, 43792, 48332, 47777, 52472, 52476, + 52480, 52484, 52488, 48342, 47782, 47787, 47792, 47797, 52492, 52496, + 47802, 47807, 47812, 47817, 52500, 52504, 52508, 36063, 25514, 48602, + 52512, 52516, 48612, 48617, 52520, 52524, 52528, 48622, 52532, 52536, + 48627, 48632, 52540, 52544, 52548, 38648, 48642, 48647, 52552, 48652, + 52556, 30109, 52560, 44377, 52564, 48657, 52568, 48662, 48667, 48672, + 48677, 48682, 48687, 52572, 52576, 52580, 52584, 52588, 52592, 52596, + 52600, 52604, 52608, 52612, 48892, 48697, 52616, 52620, 52624, 52628, + 52632, 52636, 52640, 52644, 52648, 52652, 52656, 52660, 1955, 52664, + 52668, 52672, 52676, 52680, 52684, 52688, 52692, 52696, 52700, 52704, + 52708, 52712, 52716, 52720, 52724, 52728, 52732, 52736, 49167, 46257, + 52740, 52744, 27869, 52748, 52752, 45062, 29329, 40769, 40775, 33687, + 37276, 52756, 34447, 52760, 52764, 52768, 52772, 52776, 52780, 52784, + 52788, 52792, 52796, 52800, 52804, 52808, 52812, 52816, 52820, 52824, + 52828, 52832, 52836, 52840, 52844, 52848, 52852, 52856, 52860, 52864, + 52868, 52872, 52876, 52880, 52884, 52888, 52892, 52896, 47112, 47117, + 46807, 46812, 44422, 46817, 52900, 44427, 52904, 46822, 46827, 44432, + 47122, 47127, 47132, 52908, 52912, 52916, 52920, 52924, 52928, 52932, + 52936, 52940, 52944, 52948, 52952, 52956, 37626, 52960, 52964, 52968, + 44382, 52972, 52976, 52980, 52984, 52988, 52992, 47862, 52996, 44607, + 47872, 47877, 44612, 47887, 53000, 47892, 47897, 53004, 47902, 47907, + 53008, 53012, 53016, 53020, 53024, 47917, 47922, 47927, 49342, 47932, + 53028, 47937, 47942, 47947, 47952, 53032, 48962, 53036, 47957, 47962, + 53040, 47967, 53044, 47977, 48747, 47982, 47987, 47992, 47997, 53048, + 42474, 36675, 1086, 19640, 49781, 603, 39492, 28980, 27870, 33560, 5572, + 19198, 53052, 53055, 53058, 31190, 33296, 4804, 5060, 32504, 50381, + 45013, 53061, 37438, 39864, 50369, 32288, 38138, 49533, 5316, 53064, + 26516, 53067, 36955, 53070, 36731, 49589, 29110, 50293, 43224, 40230, + 974, 53073, 10931, 53076, 24899, 53079, 44743, 34008, 651, 38544, 42522, + 31910, 1419, 672, 4868, 6084, 51633, 18896, 49108, 53082, 26571, 23315, + 44553, 44748, 51669, 49757, 37704, 23111, 53085, 45893, 22643, 800, + 18938, 764, 40410, 44053, 991, 40086, 1155, 38446, 53088, 53091, 23171, + 53094, 41826, 28910, 25130, 41046, 32198, 53097, 38642, 23435, 40032, + 43290, 53100, 53103, 53106, 53109, 42018, 53112, 51185, 22679, 53115, + 22703, 37662, 53118, 53121, 53124, 22139, 53127, 43170, 35872, 25427, + 30929, 53130, 53133, 42468, 53136, 5124, 51093, 51305, 38992, 53139, + 30452, 50185, 53142, 11036, 27850, 36899, 51661, 31145, 53145, 38761, + 51089, 53148, 30479, 26582, 22391, 40218, 37270, 37851, 1127, 10756, + 53151, 298, 40518, 51657, 49208, 53154, 41988, 50001, 18951, 24695, 5908, + 27900, 19445, 34040, 50189, 22583, 53157, 53160, 53163, 33152, 53166, + 18448, 33080, 51085, 53169, 36000, 33800, 39936, 53172, 53175, 53178, + 29260, 36710, 53181, 53184, 18378, 53187, 36997, 43134, 53190, 12, 53193, + 53196, 5380, 51181, 49553, 53199, 39600, 31028, 623, 36096, 6148, 53202, + 53205, 53208, 53211, 33008, 1091, 34120, 53214, 53217, 22739, 53220, + 37543, 22451, 53223, 51961, 49168, 53226, 24659, 34112, 51097, 53229, + 51189, 28000, 53232, 53235, 53238, 32495, 36339, 50501, 53241, 40686, + 53244, 53247, 53250, 53253, 53256, 53259, 42594, 53262, 53265, 53268, + 53271, 53274, 53277, 53280, 52541, 53283, 26989, 31019, 53286, 53289, + 53292, 53295, 53298, 45888, 51377, 53301, 1178, 285, 53304, 53307, 53310, + 26329, 53313, 52673, 53316, 37144, 35760, 53319, 50621, 51393, 53322, + 18131, 53325, 4676, 4692, 48873, 53328, 30461, 50525, 24683, 45608, + 53331, 53334, 53337, 27440, 5348, 5364, 1476, 53340, 53343, 5588, 53346, + 53349, 53352, 53355, 53358, 47158, 24778, 6164, 51429, 53361, 53364, + 53367, 51357, 324, 53370, 53373, 53376, 53379, 51541, 38943, 27530, + 26395, 40254, 53382, 26384, 1082, 50193, 53385, 42006, 794, 53388, 53391, + 53394, 53397, 53400, 53403, 53406, 53409, 53412, 45003, 53415, 52657, + 53418, 786, 53421, 40068, 53424, 53427, 53430, 53433, 53436, 53439, + 53442, 53445, 45053, 53448, 53451, 44513, 53454, 53457, 53460, 40500, + 53463, 53466, 53469, 40776, 29340, 53472, 53475, 53478, 1972, 52233, + 53481, 53484, 41154, 53487, 53490, 45998, 53493, 53496, 53499, 53502, + 53505, 30011, 53508, 53511, 53514, 37557, 52557, 53517, 53520, 53523, + 53526, 40092, 53529, 53532, 18868, 44348, 1032, 46868, 53535, 53538, + 39336, 53541, 46773, 53544, 51149, 51881, 53547, 53550, 45813, 53553, + 44153, 53556, 52161, 19407, 416, 286, 38237, 1316, 2325, 39973, 21, 38, + 32694, 50274, 53559, 30075, 53561, 320, 36305, 53563, 36235, 42469, + 49918, 213, 44189, 53565, 479, 34049, 53518, 53567, 919, 40093, 42079, + 316, 395, 53569, 885, 30651, 204, 53571, 53329, 53573, 53575, 4, 27891, + 1102, 43604, 1115, 36466, 53577, 53579, 24834, 892, 50538, 373, 53200, + 771, 88, 51526, 703, 53581, 351, 106, 44484, 53116, 39793, 24867, 39325, + 53583, 53585, 35145, 49498, 53587, 53589, 53591, 25164, 43679, 53593, + 53595, 34617, 51966, 53597, 8, 1056, 554, 998, 36034, 39, 98, 14, 5, 161, + 102, 317, 70, 9, 52, 321, 34, 53225, 401, 171, 404, 523, 53599, 53600, +}; + +/* code->name phrasebook */ +#define phrasebook_shift 7 +#define phrasebook_short 226 +static unsigned char phrasebook[] = { + 0, 240, 15, 233, 54, 69, 235, 51, 69, 61, 52, 240, 114, 52, 238, 107, 52, + 234, 17, 233, 59, 40, 232, 74, 38, 232, 74, 235, 52, 248, 49, 52, 240, + 27, 231, 94, 248, 37, 208, 236, 177, 26, 242, 217, 26, 127, 26, 111, 26, + 166, 26, 177, 26, 176, 26, 187, 26, 203, 26, 195, 26, 202, 240, 24, 234, + 14, 235, 44, 52, 240, 7, 52, 232, 68, 52, 236, 156, 69, 234, 20, 254, 20, + 8, 5, 1, 67, 8, 5, 1, 217, 8, 5, 1, 255, 18, 8, 5, 1, 209, 8, 5, 1, 72, + 8, 5, 1, 255, 19, 8, 5, 1, 210, 8, 5, 1, 192, 8, 5, 1, 71, 8, 5, 1, 221, + 8, 5, 1, 255, 15, 8, 5, 1, 162, 8, 5, 1, 173, 8, 5, 1, 197, 8, 5, 1, 73, + 8, 5, 1, 223, 8, 5, 1, 255, 20, 8, 5, 1, 144, 8, 5, 1, 193, 8, 5, 1, 214, + 8, 5, 1, 79, 8, 5, 1, 179, 8, 5, 1, 255, 16, 8, 5, 1, 206, 8, 5, 1, 255, + 14, 8, 5, 1, 255, 17, 40, 31, 104, 238, 75, 236, 177, 38, 31, 104, 190, + 238, 54, 170, 242, 224, 242, 245, 238, 54, 8, 3, 1, 67, 8, 3, 1, 217, 8, + 3, 1, 255, 18, 8, 3, 1, 209, 8, 3, 1, 72, 8, 3, 1, 255, 19, 8, 3, 1, 210, + 8, 3, 1, 192, 8, 3, 1, 71, 8, 3, 1, 221, 8, 3, 1, 255, 15, 8, 3, 1, 162, + 8, 3, 1, 173, 8, 3, 1, 197, 8, 3, 1, 73, 8, 3, 1, 223, 8, 3, 1, 255, 20, + 8, 3, 1, 144, 8, 3, 1, 193, 8, 3, 1, 214, 8, 3, 1, 79, 8, 3, 1, 179, 8, + 3, 1, 255, 16, 8, 3, 1, 206, 8, 3, 1, 255, 14, 8, 3, 1, 255, 17, 40, 242, + 225, 104, 59, 242, 224, 38, 242, 225, 104, 169, 236, 233, 240, 15, 236, + 145, 233, 54, 69, 249, 39, 52, 243, 246, 52, 236, 181, 52, 254, 134, 52, + 240, 129, 125, 238, 213, 52, 175, 235, 195, 52, 237, 9, 238, 205, 234, + 30, 231, 87, 45, 185, 235, 51, 69, 161, 52, 248, 186, 238, 93, 234, 245, + 52, 196, 240, 112, 52, 234, 236, 52, 233, 49, 111, 233, 49, 166, 242, + 241, 238, 54, 246, 81, 52, 238, 208, 52, 240, 1, 248, 40, 236, 151, 233, + 49, 127, 236, 58, 238, 205, 234, 30, 231, 36, 45, 185, 235, 51, 69, 240, + 30, 236, 155, 253, 125, 237, 33, 240, 30, 236, 155, 253, 125, 243, 7, + 240, 30, 236, 155, 204, 236, 84, 236, 145, 236, 156, 69, 8, 5, 1, 134, 2, + 191, 8, 5, 1, 134, 2, 135, 8, 5, 1, 134, 2, 233, 48, 8, 5, 1, 134, 2, + 169, 8, 5, 1, 134, 2, 175, 8, 5, 1, 134, 2, 248, 51, 48, 8, 5, 1, 253, + 178, 8, 5, 1, 255, 105, 2, 236, 151, 8, 5, 1, 157, 2, 191, 8, 5, 1, 157, + 2, 135, 8, 5, 1, 157, 2, 233, 48, 8, 5, 1, 157, 2, 175, 8, 5, 1, 220, 2, + 191, 8, 5, 1, 220, 2, 135, 8, 5, 1, 220, 2, 233, 48, 8, 5, 1, 220, 2, + 175, 8, 5, 1, 248, 109, 8, 5, 1, 255, 98, 2, 169, 8, 5, 1, 117, 2, 191, + 8, 5, 1, 117, 2, 135, 8, 5, 1, 117, 2, 233, 48, 8, 5, 1, 117, 2, 169, 8, + 5, 1, 117, 2, 175, 231, 37, 52, 8, 5, 1, 117, 2, 108, 8, 5, 1, 132, 2, + 191, 8, 5, 1, 132, 2, 135, 8, 5, 1, 132, 2, 233, 48, 8, 5, 1, 132, 2, + 175, 8, 5, 1, 255, 107, 2, 135, 8, 5, 1, 240, 149, 8, 3, 1, 243, 74, 193, + 8, 3, 1, 134, 2, 191, 8, 3, 1, 134, 2, 135, 8, 3, 1, 134, 2, 233, 48, 8, + 3, 1, 134, 2, 169, 8, 3, 1, 134, 2, 175, 8, 3, 1, 134, 2, 248, 51, 48, 8, + 3, 1, 253, 178, 8, 3, 1, 255, 105, 2, 236, 151, 8, 3, 1, 157, 2, 191, 8, + 3, 1, 157, 2, 135, 8, 3, 1, 157, 2, 233, 48, 8, 3, 1, 157, 2, 175, 8, 3, + 1, 220, 2, 191, 8, 3, 1, 220, 2, 135, 8, 3, 1, 220, 2, 233, 48, 8, 3, 1, + 220, 2, 175, 8, 3, 1, 248, 109, 8, 3, 1, 255, 98, 2, 169, 8, 3, 1, 117, + 2, 191, 8, 3, 1, 117, 2, 135, 8, 3, 1, 117, 2, 233, 48, 8, 3, 1, 117, 2, + 169, 8, 3, 1, 117, 2, 175, 236, 196, 52, 8, 3, 1, 117, 2, 108, 8, 3, 1, + 132, 2, 191, 8, 3, 1, 132, 2, 135, 8, 3, 1, 132, 2, 233, 48, 8, 3, 1, + 132, 2, 175, 8, 3, 1, 255, 107, 2, 135, 8, 3, 1, 240, 149, 8, 3, 1, 255, + 107, 2, 175, 8, 5, 1, 134, 2, 196, 8, 3, 1, 134, 2, 196, 8, 5, 1, 134, 2, + 239, 255, 8, 3, 1, 134, 2, 239, 255, 8, 5, 1, 134, 2, 238, 71, 8, 3, 1, + 134, 2, 238, 71, 8, 5, 1, 255, 105, 2, 135, 8, 3, 1, 255, 105, 2, 135, 8, + 5, 1, 255, 105, 2, 233, 48, 8, 3, 1, 255, 105, 2, 233, 48, 8, 5, 1, 255, + 105, 2, 53, 48, 8, 3, 1, 255, 105, 2, 53, 48, 8, 5, 1, 255, 105, 2, 239, + 254, 8, 3, 1, 255, 105, 2, 239, 254, 8, 5, 1, 255, 103, 2, 239, 254, 8, + 3, 1, 255, 103, 2, 239, 254, 8, 5, 1, 255, 103, 2, 108, 8, 3, 1, 255, + 103, 2, 108, 8, 5, 1, 157, 2, 196, 8, 3, 1, 157, 2, 196, 8, 5, 1, 157, 2, + 239, 255, 8, 3, 1, 157, 2, 239, 255, 8, 5, 1, 157, 2, 53, 48, 8, 3, 1, + 157, 2, 53, 48, 8, 5, 1, 157, 2, 238, 71, 8, 3, 1, 157, 2, 238, 71, 8, 5, + 1, 157, 2, 239, 254, 8, 3, 1, 157, 2, 239, 254, 8, 5, 1, 255, 104, 2, + 233, 48, 8, 3, 1, 255, 104, 2, 233, 48, 8, 5, 1, 255, 104, 2, 239, 255, + 8, 3, 1, 255, 104, 2, 239, 255, 8, 5, 1, 255, 104, 2, 53, 48, 8, 3, 1, + 255, 104, 2, 53, 48, 8, 5, 1, 255, 104, 2, 236, 151, 8, 3, 1, 255, 104, + 2, 236, 151, 8, 5, 1, 255, 106, 2, 233, 48, 8, 3, 1, 255, 106, 2, 233, + 48, 8, 5, 1, 255, 106, 2, 108, 8, 3, 1, 255, 106, 2, 108, 8, 5, 1, 220, + 2, 169, 8, 3, 1, 220, 2, 169, 8, 5, 1, 220, 2, 196, 8, 3, 1, 220, 2, 196, + 8, 5, 1, 220, 2, 239, 255, 8, 3, 1, 220, 2, 239, 255, 8, 5, 1, 220, 2, + 238, 71, 8, 3, 1, 220, 2, 238, 71, 8, 5, 1, 220, 2, 53, 48, 8, 3, 1, 238, + 70, 71, 8, 5, 18, 254, 99, 8, 3, 18, 254, 99, 8, 5, 1, 255, 115, 2, 233, + 48, 8, 3, 1, 255, 115, 2, 233, 48, 8, 5, 1, 255, 109, 2, 236, 151, 8, 3, + 1, 255, 109, 2, 236, 151, 8, 3, 1, 251, 164, 8, 5, 1, 255, 100, 2, 135, + 8, 3, 1, 255, 100, 2, 135, 8, 5, 1, 255, 100, 2, 236, 151, 8, 3, 1, 255, + 100, 2, 236, 151, 8, 5, 1, 255, 100, 2, 239, 254, 8, 3, 1, 255, 100, 2, + 239, 254, 8, 5, 1, 255, 100, 2, 240, 1, 248, 40, 8, 3, 1, 255, 100, 2, + 240, 1, 248, 40, 8, 5, 1, 255, 100, 2, 108, 8, 3, 1, 255, 100, 2, 108, 8, + 5, 1, 255, 98, 2, 135, 8, 3, 1, 255, 98, 2, 135, 8, 5, 1, 255, 98, 2, + 236, 151, 8, 3, 1, 255, 98, 2, 236, 151, 8, 5, 1, 255, 98, 2, 239, 254, + 8, 3, 1, 255, 98, 2, 239, 254, 8, 3, 1, 255, 98, 237, 241, 255, 25, 233, + 59, 8, 5, 1, 248, 108, 8, 3, 1, 248, 108, 8, 5, 1, 117, 2, 196, 8, 3, 1, + 117, 2, 196, 8, 5, 1, 117, 2, 239, 255, 8, 3, 1, 117, 2, 239, 255, 8, 5, + 1, 117, 2, 45, 135, 8, 3, 1, 117, 2, 45, 135, 8, 5, 18, 253, 193, 8, 3, + 18, 253, 193, 8, 5, 1, 255, 101, 2, 135, 8, 3, 1, 255, 101, 2, 135, 8, 5, + 1, 255, 101, 2, 236, 151, 8, 3, 1, 255, 101, 2, 236, 151, 8, 5, 1, 255, + 101, 2, 239, 254, 8, 3, 1, 255, 101, 2, 239, 254, 8, 5, 1, 255, 99, 2, + 135, 8, 3, 1, 255, 99, 2, 135, 8, 5, 1, 255, 99, 2, 233, 48, 8, 3, 1, + 255, 99, 2, 233, 48, 8, 5, 1, 255, 99, 2, 236, 151, 8, 3, 1, 255, 99, 2, + 236, 151, 8, 5, 1, 255, 99, 2, 239, 254, 8, 3, 1, 255, 99, 2, 239, 254, + 8, 5, 1, 255, 102, 2, 236, 151, 8, 3, 1, 255, 102, 2, 236, 151, 8, 5, 1, + 255, 102, 2, 239, 254, 8, 3, 1, 255, 102, 2, 239, 254, 8, 5, 1, 255, 102, + 2, 108, 8, 3, 1, 255, 102, 2, 108, 8, 5, 1, 132, 2, 169, 8, 3, 1, 132, 2, + 169, 8, 5, 1, 132, 2, 196, 8, 3, 1, 132, 2, 196, 8, 5, 1, 132, 2, 239, + 255, 8, 3, 1, 132, 2, 239, 255, 8, 5, 1, 132, 2, 248, 51, 48, 8, 3, 1, + 132, 2, 248, 51, 48, 8, 5, 1, 132, 2, 45, 135, 8, 3, 1, 132, 2, 45, 135, + 8, 5, 1, 132, 2, 238, 71, 8, 3, 1, 132, 2, 238, 71, 8, 5, 1, 255, 111, 2, + 233, 48, 8, 3, 1, 255, 111, 2, 233, 48, 8, 5, 1, 255, 107, 2, 233, 48, 8, + 3, 1, 255, 107, 2, 233, 48, 8, 5, 1, 255, 107, 2, 175, 8, 5, 1, 255, 97, + 2, 135, 8, 3, 1, 255, 97, 2, 135, 8, 5, 1, 255, 97, 2, 53, 48, 8, 3, 1, + 255, 97, 2, 53, 48, 8, 5, 1, 255, 97, 2, 239, 254, 8, 3, 1, 255, 97, 2, + 239, 254, 8, 3, 1, 183, 193, 8, 3, 1, 41, 2, 108, 8, 5, 1, 41, 2, 90, 8, + 5, 1, 41, 2, 238, 124, 8, 3, 1, 41, 2, 238, 124, 8, 5, 1, 188, 187, 8, 3, + 1, 188, 187, 8, 5, 1, 248, 35, 73, 8, 5, 1, 255, 105, 2, 90, 8, 3, 1, + 255, 105, 2, 90, 8, 5, 1, 238, 238, 209, 8, 5, 1, 255, 103, 2, 90, 8, 5, + 1, 255, 103, 2, 238, 124, 8, 3, 1, 255, 103, 2, 238, 124, 8, 3, 1, 205, + 240, 28, 8, 5, 1, 224, 72, 8, 5, 1, 240, 86, 8, 5, 1, 248, 35, 72, 8, 5, + 1, 255, 112, 2, 90, 8, 3, 1, 255, 112, 2, 90, 8, 5, 1, 255, 104, 2, 90, + 8, 5, 1, 240, 10, 8, 3, 1, 254, 98, 8, 5, 1, 242, 237, 8, 5, 1, 220, 2, + 108, 8, 5, 1, 255, 109, 2, 90, 8, 3, 1, 255, 109, 2, 90, 8, 3, 1, 255, + 100, 2, 125, 8, 3, 1, 241, 212, 2, 108, 8, 5, 1, 205, 173, 8, 5, 1, 255, + 98, 2, 40, 90, 8, 3, 1, 255, 98, 2, 183, 38, 248, 117, 8, 5, 1, 117, 2, + 240, 1, 169, 8, 5, 1, 117, 2, 243, 8, 8, 3, 1, 117, 2, 243, 8, 8, 5, 1, + 254, 42, 8, 3, 1, 254, 42, 8, 5, 1, 255, 114, 2, 90, 8, 3, 1, 255, 114, + 2, 90, 8, 1, 254, 135, 8, 5, 1, 188, 111, 8, 3, 1, 188, 111, 8, 5, 1, + 248, 93, 8, 1, 224, 254, 38, 243, 105, 8, 3, 1, 255, 102, 2, 238, 65, 90, + 8, 5, 1, 255, 102, 2, 90, 8, 3, 1, 255, 102, 2, 90, 8, 5, 1, 255, 102, 2, + 235, 54, 90, 8, 5, 1, 132, 2, 243, 8, 8, 3, 1, 132, 2, 243, 8, 8, 5, 1, + 236, 160, 8, 5, 1, 255, 110, 2, 90, 8, 5, 1, 255, 107, 2, 90, 8, 3, 1, + 255, 107, 2, 90, 8, 5, 1, 255, 97, 2, 108, 8, 3, 1, 255, 97, 2, 108, 8, + 5, 1, 248, 155, 8, 5, 1, 253, 244, 235, 142, 8, 3, 1, 253, 244, 235, 142, + 8, 3, 1, 253, 244, 2, 242, 226, 8, 1, 171, 2, 108, 8, 5, 1, 188, 176, 8, + 3, 1, 188, 176, 8, 1, 236, 145, 238, 62, 248, 119, 2, 108, 8, 1, 244, 54, + 8, 1, 241, 82, 240, 93, 8, 1, 239, 114, 240, 93, 8, 1, 237, 59, 240, 93, + 8, 1, 235, 54, 240, 93, 8, 5, 1, 255, 40, 2, 239, 254, 8, 5, 1, 255, 103, + 2, 3, 1, 255, 97, 2, 239, 254, 8, 3, 1, 255, 40, 2, 239, 254, 8, 5, 1, + 254, 109, 8, 5, 1, 255, 100, 2, 3, 1, 221, 8, 3, 1, 254, 109, 8, 5, 1, + 254, 113, 8, 5, 1, 255, 98, 2, 3, 1, 221, 8, 3, 1, 254, 113, 8, 5, 1, + 134, 2, 239, 254, 8, 3, 1, 134, 2, 239, 254, 8, 5, 1, 220, 2, 239, 254, + 8, 3, 1, 220, 2, 239, 254, 8, 5, 1, 117, 2, 239, 254, 8, 3, 1, 117, 2, + 239, 254, 8, 5, 1, 132, 2, 239, 254, 8, 3, 1, 132, 2, 239, 254, 8, 5, 1, + 132, 2, 235, 56, 19, 196, 8, 3, 1, 132, 2, 235, 56, 19, 196, 8, 5, 1, + 132, 2, 235, 56, 19, 135, 8, 3, 1, 132, 2, 235, 56, 19, 135, 8, 5, 1, + 132, 2, 235, 56, 19, 239, 254, 8, 3, 1, 132, 2, 235, 56, 19, 239, 254, 8, + 5, 1, 132, 2, 235, 56, 19, 191, 8, 3, 1, 132, 2, 235, 56, 19, 191, 8, 3, + 1, 205, 72, 8, 5, 1, 134, 2, 235, 56, 19, 196, 8, 3, 1, 134, 2, 235, 56, + 19, 196, 8, 5, 1, 134, 2, 53, 60, 19, 196, 8, 3, 1, 134, 2, 53, 60, 19, + 196, 8, 5, 1, 255, 30, 2, 196, 8, 3, 1, 255, 30, 2, 196, 8, 5, 1, 255, + 104, 2, 108, 8, 3, 1, 255, 104, 2, 108, 8, 5, 1, 255, 104, 2, 239, 254, + 8, 3, 1, 255, 104, 2, 239, 254, 8, 5, 1, 255, 109, 2, 239, 254, 8, 3, 1, + 255, 109, 2, 239, 254, 8, 5, 1, 117, 2, 238, 71, 8, 3, 1, 117, 2, 238, + 71, 8, 5, 1, 117, 2, 240, 204, 19, 196, 8, 3, 1, 117, 2, 240, 204, 19, + 196, 8, 5, 1, 253, 244, 2, 239, 254, 8, 3, 1, 253, 244, 2, 239, 254, 8, + 3, 1, 255, 115, 2, 239, 254, 8, 5, 1, 254, 88, 8, 5, 1, 255, 103, 2, 3, + 1, 255, 17, 8, 3, 1, 254, 88, 8, 5, 1, 255, 104, 2, 135, 8, 3, 1, 255, + 104, 2, 135, 8, 5, 1, 240, 190, 8, 5, 1, 244, 54, 8, 5, 1, 255, 98, 2, + 191, 8, 3, 1, 255, 98, 2, 191, 8, 5, 1, 134, 2, 248, 51, 60, 19, 135, 8, + 3, 1, 134, 2, 248, 51, 60, 19, 135, 8, 5, 1, 255, 30, 2, 135, 8, 3, 1, + 255, 30, 2, 135, 8, 5, 1, 117, 2, 240, 5, 19, 135, 8, 3, 1, 117, 2, 240, + 5, 19, 135, 8, 5, 1, 134, 2, 45, 191, 8, 3, 1, 134, 2, 45, 191, 8, 5, 1, + 134, 2, 236, 145, 239, 255, 8, 3, 1, 134, 2, 236, 145, 239, 255, 8, 5, 1, + 157, 2, 45, 191, 8, 3, 1, 157, 2, 45, 191, 8, 5, 1, 157, 2, 236, 145, + 239, 255, 8, 3, 1, 157, 2, 236, 145, 239, 255, 8, 5, 1, 220, 2, 45, 191, + 8, 3, 1, 220, 2, 45, 191, 8, 5, 1, 220, 2, 236, 145, 239, 255, 8, 3, 1, + 220, 2, 236, 145, 239, 255, 8, 5, 1, 117, 2, 45, 191, 8, 3, 1, 117, 2, + 45, 191, 8, 5, 1, 117, 2, 236, 145, 239, 255, 8, 3, 1, 117, 2, 236, 145, + 239, 255, 8, 5, 1, 255, 101, 2, 45, 191, 8, 3, 1, 255, 101, 2, 45, 191, + 8, 5, 1, 255, 101, 2, 236, 145, 239, 255, 8, 3, 1, 255, 101, 2, 236, 145, + 239, 255, 8, 5, 1, 132, 2, 45, 191, 8, 3, 1, 132, 2, 45, 191, 8, 5, 1, + 132, 2, 236, 145, 239, 255, 8, 3, 1, 132, 2, 236, 145, 239, 255, 8, 5, 1, + 255, 99, 2, 242, 244, 46, 8, 3, 1, 255, 99, 2, 242, 244, 46, 8, 5, 1, + 255, 102, 2, 242, 244, 46, 8, 3, 1, 255, 102, 2, 242, 244, 46, 8, 5, 1, + 244, 59, 8, 3, 1, 244, 59, 8, 5, 1, 255, 106, 2, 239, 254, 8, 3, 1, 255, + 106, 2, 239, 254, 8, 5, 1, 255, 98, 2, 183, 38, 248, 117, 8, 3, 1, 255, + 103, 2, 242, 253, 8, 5, 1, 254, 10, 8, 3, 1, 254, 10, 8, 5, 1, 255, 97, + 2, 90, 8, 3, 1, 255, 97, 2, 90, 8, 5, 1, 134, 2, 53, 48, 8, 3, 1, 134, 2, + 53, 48, 8, 5, 1, 157, 2, 236, 151, 8, 3, 1, 157, 2, 236, 151, 8, 5, 1, + 117, 2, 235, 56, 19, 196, 8, 3, 1, 117, 2, 235, 56, 19, 196, 8, 5, 1, + 117, 2, 242, 219, 19, 196, 8, 3, 1, 117, 2, 242, 219, 19, 196, 8, 5, 1, + 117, 2, 53, 48, 8, 3, 1, 117, 2, 53, 48, 8, 5, 1, 117, 2, 53, 60, 19, + 196, 8, 3, 1, 117, 2, 53, 60, 19, 196, 8, 5, 1, 255, 107, 2, 196, 8, 3, + 1, 255, 107, 2, 196, 8, 3, 1, 255, 100, 2, 242, 253, 8, 3, 1, 255, 98, 2, + 242, 253, 8, 3, 1, 255, 102, 2, 242, 253, 8, 3, 1, 238, 70, 221, 8, 3, 1, + 255, 71, 236, 182, 8, 3, 1, 255, 89, 236, 182, 8, 5, 1, 134, 2, 108, 8, + 5, 1, 255, 105, 2, 108, 8, 3, 1, 255, 105, 2, 108, 8, 5, 1, 255, 100, 2, + 125, 8, 5, 1, 255, 102, 2, 236, 159, 108, 8, 3, 1, 255, 99, 2, 243, 126, + 242, 226, 8, 3, 1, 255, 97, 2, 243, 126, 242, 226, 8, 5, 1, 238, 62, 208, + 8, 3, 1, 205, 67, 8, 3, 1, 240, 22, 8, 3, 1, 205, 240, 22, 8, 3, 1, 41, + 2, 90, 8, 3, 1, 248, 35, 73, 8, 3, 1, 255, 105, 2, 242, 253, 8, 3, 1, + 255, 103, 2, 242, 226, 8, 3, 1, 255, 103, 2, 90, 8, 3, 1, 224, 72, 8, 3, + 1, 240, 86, 8, 3, 1, 243, 73, 2, 90, 8, 3, 1, 248, 35, 72, 8, 3, 1, 224, + 248, 35, 72, 8, 3, 1, 224, 248, 35, 157, 2, 90, 8, 3, 1, 240, 23, 224, + 248, 35, 72, 8, 3, 1, 238, 70, 255, 115, 2, 108, 8, 3, 1, 255, 104, 2, + 90, 8, 3, 1, 84, 210, 8, 1, 3, 5, 210, 8, 3, 1, 240, 10, 8, 3, 1, 252, + 129, 243, 8, 8, 3, 1, 205, 192, 8, 3, 1, 255, 106, 2, 90, 8, 3, 1, 251, + 52, 2, 90, 8, 3, 1, 220, 2, 108, 8, 3, 1, 242, 237, 8, 1, 3, 5, 71, 8, 3, + 1, 255, 100, 2, 240, 1, 169, 8, 3, 1, 255, 100, 2, 244, 216, 8, 3, 1, + 255, 100, 2, 235, 54, 90, 8, 3, 1, 246, 43, 8, 3, 1, 205, 173, 8, 3, 1, + 205, 255, 108, 2, 183, 248, 117, 8, 3, 1, 255, 108, 2, 90, 8, 3, 1, 255, + 98, 2, 40, 90, 8, 3, 1, 255, 98, 2, 235, 54, 90, 8, 1, 3, 5, 197, 8, 3, + 1, 240, 60, 73, 8, 1, 3, 5, 253, 193, 8, 3, 1, 240, 23, 240, 20, 8, 3, 1, + 248, 68, 8, 3, 1, 205, 144, 8, 3, 1, 205, 255, 101, 2, 183, 248, 117, 8, + 3, 1, 205, 255, 101, 2, 90, 8, 3, 1, 255, 101, 2, 183, 248, 117, 8, 3, 1, + 255, 101, 2, 242, 226, 8, 3, 1, 255, 101, 2, 235, 100, 8, 3, 1, 224, 255, + 101, 2, 235, 100, 8, 1, 3, 5, 144, 8, 1, 3, 5, 236, 145, 144, 8, 3, 1, + 255, 99, 2, 90, 8, 3, 1, 248, 93, 8, 3, 1, 238, 70, 255, 115, 2, 240, 5, + 19, 90, 8, 3, 1, 244, 23, 224, 248, 93, 8, 3, 1, 254, 38, 2, 242, 253, 8, + 3, 1, 205, 214, 8, 3, 1, 255, 102, 2, 235, 54, 90, 8, 3, 1, 132, 125, 8, + 3, 1, 236, 160, 8, 3, 1, 255, 110, 2, 90, 8, 3, 1, 205, 179, 8, 3, 1, + 205, 255, 16, 8, 3, 1, 205, 255, 14, 8, 1, 3, 5, 255, 14, 8, 3, 1, 255, + 97, 2, 235, 54, 90, 8, 3, 1, 255, 97, 2, 242, 253, 8, 3, 1, 248, 155, 8, + 3, 1, 253, 244, 2, 242, 253, 8, 1, 238, 62, 208, 8, 1, 234, 12, 240, 59, + 234, 192, 8, 1, 236, 145, 238, 62, 208, 8, 1, 236, 110, 255, 18, 8, 1, + 236, 249, 240, 93, 8, 1, 3, 5, 217, 8, 3, 1, 240, 23, 248, 35, 72, 8, 1, + 3, 5, 255, 104, 2, 90, 8, 1, 3, 5, 192, 8, 3, 1, 255, 115, 2, 231, 101, + 8, 3, 1, 205, 255, 15, 8, 1, 3, 5, 162, 8, 3, 1, 255, 116, 2, 90, 8, 1, + 238, 62, 248, 119, 2, 108, 8, 1, 224, 238, 62, 248, 119, 2, 108, 8, 3, 1, + 255, 40, 236, 182, 8, 3, 1, 250, 192, 236, 182, 8, 3, 1, 255, 40, 238, + 112, 2, 242, 253, 8, 3, 1, 255, 94, 236, 182, 8, 3, 1, 252, 215, 236, + 182, 8, 3, 1, 255, 92, 238, 112, 2, 242, 253, 8, 3, 1, 250, 239, 236, + 182, 8, 3, 1, 255, 78, 236, 182, 8, 3, 1, 255, 79, 236, 182, 8, 1, 236, + 249, 233, 95, 8, 1, 237, 77, 233, 95, 8, 3, 1, 205, 255, 106, 2, 235, + 100, 8, 3, 1, 205, 255, 106, 2, 237, 11, 19, 242, 226, 49, 1, 3, 192, 49, + 1, 3, 255, 106, 2, 90, 49, 1, 3, 221, 49, 1, 3, 144, 49, 1, 3, 205, 144, + 49, 1, 3, 205, 255, 101, 2, 90, 49, 1, 3, 5, 236, 145, 144, 49, 1, 3, + 255, 16, 49, 1, 3, 255, 14, 49, 1, 240, 57, 49, 1, 45, 240, 57, 49, 1, + 205, 240, 27, 49, 1, 233, 59, 49, 1, 224, 240, 27, 49, 1, 38, 137, 242, + 233, 49, 1, 40, 137, 242, 233, 49, 1, 238, 62, 208, 49, 1, 224, 238, 62, + 208, 49, 1, 40, 234, 7, 49, 1, 38, 234, 7, 49, 1, 88, 234, 7, 49, 1, 92, + 234, 7, 49, 1, 190, 238, 54, 239, 254, 49, 1, 59, 242, 224, 49, 1, 196, + 49, 1, 242, 241, 238, 54, 49, 1, 242, 245, 238, 54, 49, 1, 170, 59, 242, + 224, 49, 1, 170, 196, 49, 1, 170, 242, 245, 238, 54, 49, 1, 170, 242, + 241, 238, 54, 49, 1, 234, 43, 240, 24, 49, 1, 137, 234, 43, 240, 24, 49, + 1, 238, 130, 38, 137, 242, 233, 49, 1, 238, 130, 40, 137, 242, 233, 49, + 1, 88, 242, 234, 49, 1, 92, 242, 234, 49, 1, 248, 49, 52, 49, 1, 242, + 250, 52, 239, 255, 53, 48, 248, 51, 48, 238, 71, 3, 169, 45, 242, 241, + 238, 54, 49, 1, 242, 83, 90, 49, 1, 243, 38, 238, 54, 49, 1, 3, 240, 10, + 49, 1, 3, 162, 49, 1, 3, 193, 49, 1, 3, 206, 49, 1, 3, 224, 238, 62, 208, + 49, 1, 234, 27, 188, 125, 49, 1, 200, 188, 125, 49, 1, 254, 40, 188, 125, + 49, 1, 170, 188, 125, 49, 1, 235, 87, 188, 125, 49, 1, 254, 15, 235, 98, + 188, 69, 49, 1, 248, 122, 235, 98, 188, 69, 49, 1, 238, 44, 49, 1, 233, + 47, 49, 1, 45, 233, 59, 49, 1, 170, 92, 234, 7, 49, 1, 170, 88, 234, 7, + 49, 1, 170, 40, 234, 7, 49, 1, 170, 38, 234, 7, 49, 1, 170, 242, 233, 49, + 1, 240, 1, 242, 245, 238, 54, 49, 1, 240, 1, 45, 242, 245, 238, 54, 49, + 1, 240, 1, 45, 242, 241, 238, 54, 49, 1, 170, 169, 49, 1, 240, 84, 240, + 24, 49, 1, 243, 24, 200, 243, 78, 49, 1, 253, 165, 200, 243, 78, 49, 1, + 243, 24, 170, 243, 78, 49, 1, 253, 165, 170, 243, 78, 49, 1, 240, 226, + 49, 1, 248, 35, 240, 226, 49, 1, 170, 40, 56, 50, 242, 245, 238, 54, 50, + 242, 241, 238, 54, 50, 190, 238, 54, 50, 169, 50, 196, 50, 235, 74, 50, + 239, 255, 50, 53, 48, 50, 175, 50, 248, 45, 48, 50, 248, 51, 48, 50, 45, + 242, 241, 238, 54, 50, 239, 254, 50, 59, 248, 41, 48, 50, 45, 59, 248, + 41, 48, 50, 45, 242, 245, 238, 54, 50, 232, 77, 50, 236, 145, 239, 255, + 50, 205, 242, 244, 48, 50, 242, 244, 48, 50, 224, 242, 244, 48, 50, 242, + 244, 60, 225, 50, 242, 245, 240, 2, 46, 50, 242, 241, 240, 2, 46, 50, 40, + 248, 84, 46, 50, 38, 248, 84, 46, 50, 40, 185, 48, 50, 243, 8, 50, 40, + 137, 248, 51, 46, 50, 88, 248, 84, 46, 50, 92, 248, 84, 46, 50, 248, 49, + 21, 46, 50, 242, 250, 21, 46, 50, 233, 222, 248, 45, 46, 50, 235, 54, + 248, 45, 46, 50, 53, 46, 50, 235, 56, 46, 50, 248, 51, 46, 50, 242, 244, + 46, 50, 236, 151, 50, 238, 71, 50, 59, 248, 41, 46, 50, 240, 109, 46, 50, + 236, 145, 45, 249, 239, 46, 50, 243, 86, 46, 50, 190, 240, 2, 46, 50, + 242, 243, 46, 50, 236, 145, 242, 243, 46, 50, 242, 219, 46, 50, 240, 42, + 46, 50, 170, 242, 224, 50, 45, 170, 242, 224, 50, 242, 219, 236, 161, 50, + 242, 215, 240, 5, 236, 161, 50, 183, 240, 5, 236, 161, 50, 242, 215, 238, + 83, 236, 161, 50, 183, 238, 83, 236, 161, 50, 38, 137, 248, 51, 46, 50, + 236, 145, 240, 109, 46, 50, 31, 46, 50, 239, 184, 46, 50, 255, 113, 48, + 50, 59, 169, 50, 45, 235, 74, 50, 242, 245, 188, 69, 50, 242, 241, 188, + 69, 50, 17, 232, 71, 50, 17, 236, 229, 50, 17, 235, 59, 240, 16, 50, 17, + 231, 35, 50, 240, 109, 48, 50, 240, 7, 21, 46, 50, 45, 59, 248, 41, 46, + 50, 40, 185, 46, 50, 161, 242, 219, 48, 50, 234, 200, 48, 50, 240, 40, + 95, 153, 48, 50, 40, 38, 65, 46, 50, 226, 226, 65, 46, 50, 237, 166, 238, + 140, 50, 38, 235, 76, 48, 50, 40, 137, 248, 51, 48, 50, 237, 10, 50, 255, + 113, 46, 50, 40, 235, 76, 46, 50, 38, 235, 76, 46, 50, 38, 235, 76, 19, + 88, 235, 76, 46, 50, 38, 137, 248, 51, 48, 50, 53, 60, 225, 50, 236, 219, + 46, 50, 45, 248, 51, 46, 50, 240, 126, 48, 50, 45, 242, 243, 46, 50, 45, + 239, 255, 50, 45, 196, 50, 45, 240, 42, 46, 50, 45, 169, 50, 45, 236, + 145, 239, 255, 50, 45, 77, 65, 46, 50, 8, 3, 1, 67, 50, 8, 3, 1, 72, 50, + 8, 3, 1, 71, 50, 8, 3, 1, 73, 50, 8, 3, 1, 79, 50, 8, 3, 1, 255, 18, 50, + 8, 3, 1, 209, 50, 8, 3, 1, 192, 50, 8, 3, 1, 173, 50, 8, 3, 1, 144, 50, + 8, 3, 1, 214, 50, 8, 3, 1, 179, 50, 8, 3, 1, 206, 17, 178, 52, 17, 168, + 178, 52, 17, 231, 35, 17, 236, 156, 69, 17, 240, 16, 17, 235, 59, 240, + 16, 17, 5, 1, 194, 2, 240, 16, 17, 254, 140, 238, 223, 17, 5, 1, 238, 57, + 2, 240, 16, 17, 5, 1, 253, 123, 2, 240, 16, 17, 5, 1, 248, 42, 2, 240, + 16, 17, 5, 1, 238, 64, 2, 240, 16, 17, 5, 1, 238, 53, 2, 240, 16, 17, 5, + 1, 211, 2, 240, 16, 17, 3, 1, 248, 42, 2, 235, 59, 19, 240, 16, 17, 5, 1, + 240, 22, 17, 5, 1, 242, 242, 17, 5, 1, 240, 10, 17, 5, 1, 240, 28, 17, 5, + 1, 236, 165, 17, 5, 1, 242, 251, 17, 5, 1, 248, 87, 17, 5, 1, 240, 38, + 17, 5, 1, 242, 237, 17, 5, 1, 240, 41, 17, 5, 1, 240, 33, 17, 5, 1, 253, + 154, 17, 5, 1, 253, 150, 17, 5, 1, 253, 188, 17, 5, 1, 236, 169, 17, 5, + 1, 253, 147, 17, 5, 1, 248, 73, 17, 5, 1, 240, 21, 17, 5, 1, 248, 85, 17, + 5, 1, 236, 160, 17, 5, 1, 248, 68, 17, 5, 1, 248, 67, 17, 5, 1, 248, 69, + 17, 5, 1, 240, 20, 17, 5, 1, 248, 42, 2, 234, 26, 17, 5, 1, 238, 53, 2, + 234, 26, 17, 3, 1, 194, 2, 240, 16, 17, 3, 1, 238, 57, 2, 240, 16, 17, 3, + 1, 253, 123, 2, 240, 16, 17, 3, 1, 248, 42, 2, 240, 16, 17, 3, 1, 238, + 53, 2, 235, 59, 19, 240, 16, 17, 3, 1, 240, 22, 17, 3, 1, 242, 242, 17, + 3, 1, 240, 10, 17, 3, 1, 240, 28, 17, 3, 1, 236, 165, 17, 3, 1, 242, 251, + 17, 3, 1, 248, 87, 17, 3, 1, 240, 38, 17, 3, 1, 242, 237, 17, 3, 1, 240, + 41, 17, 3, 1, 240, 33, 17, 3, 1, 253, 154, 17, 3, 1, 253, 150, 17, 3, 1, + 253, 188, 17, 3, 1, 236, 169, 17, 3, 1, 253, 147, 17, 3, 1, 248, 73, 17, + 3, 1, 30, 240, 21, 17, 3, 1, 240, 21, 17, 3, 1, 248, 85, 17, 3, 1, 236, + 160, 17, 3, 1, 248, 68, 17, 3, 1, 248, 67, 17, 3, 1, 248, 69, 17, 3, 1, + 240, 20, 17, 3, 1, 248, 42, 2, 234, 26, 17, 3, 1, 238, 53, 2, 234, 26, + 17, 3, 1, 238, 64, 2, 240, 16, 17, 3, 1, 238, 53, 2, 240, 16, 17, 3, 1, + 211, 2, 240, 16, 17, 250, 118, 91, 17, 243, 0, 91, 17, 238, 53, 2, 248, + 45, 91, 17, 238, 53, 2, 242, 241, 19, 248, 45, 91, 17, 238, 53, 2, 235, + 56, 19, 248, 45, 91, 17, 254, 11, 91, 17, 255, 29, 91, 17, 254, 65, 91, + 17, 1, 238, 162, 240, 77, 17, 3, 1, 238, 162, 240, 77, 17, 1, 238, 152, + 17, 3, 1, 238, 152, 17, 1, 237, 6, 17, 3, 1, 237, 6, 17, 1, 240, 77, 17, + 3, 1, 240, 77, 17, 1, 240, 121, 17, 3, 1, 240, 121, 62, 5, 1, 243, 32, + 62, 3, 1, 243, 32, 62, 5, 1, 249, 62, 62, 3, 1, 249, 62, 62, 5, 1, 243, + 64, 62, 3, 1, 243, 64, 62, 5, 1, 243, 28, 62, 3, 1, 243, 28, 62, 5, 1, + 238, 115, 62, 3, 1, 238, 115, 62, 5, 1, 240, 88, 62, 3, 1, 240, 88, 62, + 5, 1, 249, 53, 62, 3, 1, 249, 53, 17, 243, 29, 91, 17, 253, 218, 91, 17, + 240, 67, 243, 45, 91, 17, 1, 249, 211, 17, 5, 243, 0, 91, 17, 240, 67, + 238, 57, 91, 17, 224, 240, 67, 238, 57, 91, 17, 5, 1, 248, 110, 17, 3, 1, + 248, 110, 17, 5, 240, 67, 243, 45, 91, 17, 5, 1, 248, 134, 17, 3, 1, 248, + 134, 17, 253, 218, 2, 240, 5, 91, 17, 5, 224, 240, 67, 243, 45, 91, 17, + 5, 240, 4, 240, 67, 243, 45, 91, 17, 5, 224, 240, 4, 240, 67, 243, 45, + 91, 32, 5, 1, 255, 42, 2, 191, 32, 5, 1, 254, 100, 32, 5, 1, 248, 150, + 32, 5, 1, 249, 77, 32, 5, 1, 235, 156, 253, 237, 32, 5, 1, 248, 126, 32, + 5, 1, 226, 228, 71, 32, 5, 1, 253, 189, 32, 5, 1, 254, 24, 32, 5, 1, 248, + 165, 32, 5, 1, 248, 174, 32, 5, 1, 244, 40, 32, 5, 1, 249, 96, 32, 5, 1, + 220, 2, 191, 32, 5, 1, 242, 215, 79, 32, 5, 1, 243, 166, 32, 5, 1, 67, + 32, 5, 1, 253, 242, 32, 5, 1, 254, 12, 32, 5, 1, 248, 127, 32, 5, 1, 253, + 200, 32, 5, 1, 253, 237, 32, 5, 1, 248, 123, 32, 5, 1, 253, 228, 32, 5, + 1, 71, 32, 5, 1, 242, 215, 71, 32, 5, 1, 201, 32, 5, 1, 254, 3, 32, 5, 1, + 254, 22, 32, 5, 1, 253, 202, 32, 5, 1, 73, 32, 5, 1, 253, 175, 32, 5, 1, + 254, 4, 32, 5, 1, 254, 23, 32, 5, 1, 253, 195, 32, 5, 1, 79, 32, 5, 1, + 254, 21, 32, 5, 1, 219, 32, 5, 1, 248, 112, 32, 5, 1, 248, 88, 32, 5, 1, + 248, 46, 32, 5, 1, 240, 224, 32, 5, 1, 249, 79, 52, 32, 5, 1, 243, 83, + 32, 5, 1, 248, 186, 52, 32, 5, 1, 72, 32, 5, 1, 253, 161, 32, 5, 1, 216, + 32, 3, 1, 67, 32, 3, 1, 253, 242, 32, 3, 1, 254, 12, 32, 3, 1, 248, 127, + 32, 3, 1, 253, 200, 32, 3, 1, 253, 237, 32, 3, 1, 248, 123, 32, 3, 1, + 253, 228, 32, 3, 1, 71, 32, 3, 1, 242, 215, 71, 32, 3, 1, 201, 32, 3, 1, + 254, 3, 32, 3, 1, 254, 22, 32, 3, 1, 253, 202, 32, 3, 1, 73, 32, 3, 1, + 253, 175, 32, 3, 1, 254, 4, 32, 3, 1, 254, 23, 32, 3, 1, 253, 195, 32, 3, + 1, 79, 32, 3, 1, 254, 21, 32, 3, 1, 219, 32, 3, 1, 248, 112, 32, 3, 1, + 248, 88, 32, 3, 1, 248, 46, 32, 3, 1, 240, 224, 32, 3, 1, 249, 79, 52, + 32, 3, 1, 243, 83, 32, 3, 1, 248, 186, 52, 32, 3, 1, 72, 32, 3, 1, 253, + 161, 32, 3, 1, 216, 32, 3, 1, 255, 42, 2, 191, 32, 3, 1, 254, 100, 32, 3, + 1, 248, 150, 32, 3, 1, 249, 77, 32, 3, 1, 235, 156, 253, 237, 32, 3, 1, + 248, 126, 32, 3, 1, 226, 228, 71, 32, 3, 1, 253, 189, 32, 3, 1, 254, 24, + 32, 3, 1, 248, 165, 32, 3, 1, 248, 174, 32, 3, 1, 244, 40, 32, 3, 1, 249, + 96, 32, 3, 1, 220, 2, 191, 32, 3, 1, 242, 215, 79, 32, 3, 1, 243, 166, + 32, 5, 1, 240, 20, 32, 3, 1, 240, 20, 32, 5, 1, 249, 21, 32, 3, 1, 249, + 21, 32, 5, 1, 236, 197, 72, 32, 3, 1, 236, 197, 72, 32, 5, 1, 240, 101, + 248, 74, 32, 3, 1, 240, 101, 248, 74, 32, 5, 1, 236, 197, 240, 101, 248, + 74, 32, 3, 1, 236, 197, 240, 101, 248, 74, 32, 5, 1, 253, 213, 248, 74, + 32, 3, 1, 253, 213, 248, 74, 32, 5, 1, 236, 197, 253, 213, 248, 74, 32, + 3, 1, 236, 197, 253, 213, 248, 74, 32, 5, 1, 248, 163, 32, 3, 1, 248, + 163, 32, 5, 1, 248, 69, 32, 3, 1, 248, 69, 32, 5, 1, 243, 57, 32, 3, 1, + 243, 57, 32, 5, 1, 236, 215, 32, 3, 1, 236, 215, 32, 5, 1, 238, 192, 2, + 45, 242, 245, 238, 54, 32, 3, 1, 238, 192, 2, 45, 242, 245, 238, 54, 32, + 5, 1, 254, 130, 32, 3, 1, 254, 130, 32, 5, 1, 244, 1, 240, 20, 32, 3, 1, + 244, 1, 240, 20, 32, 5, 1, 211, 2, 240, 150, 32, 3, 1, 211, 2, 240, 150, + 32, 5, 1, 254, 67, 32, 3, 1, 254, 67, 32, 5, 1, 240, 77, 32, 3, 1, 240, + 77, 32, 235, 114, 52, 50, 32, 240, 150, 50, 32, 231, 27, 50, 32, 148, + 235, 135, 50, 32, 159, 235, 135, 50, 32, 238, 92, 235, 114, 52, 50, 32, + 237, 211, 52, 32, 5, 1, 242, 215, 220, 2, 242, 226, 32, 3, 1, 242, 215, + 220, 2, 242, 226, 32, 5, 1, 237, 36, 52, 32, 3, 1, 237, 36, 52, 32, 5, 1, + 255, 54, 2, 243, 36, 32, 3, 1, 255, 54, 2, 243, 36, 32, 5, 1, 253, 233, + 2, 238, 231, 32, 3, 1, 253, 233, 2, 238, 231, 32, 5, 1, 253, 233, 2, 108, + 32, 3, 1, 253, 233, 2, 108, 32, 5, 1, 253, 233, 2, 240, 1, 90, 32, 3, 1, + 253, 233, 2, 240, 1, 90, 32, 5, 1, 254, 16, 2, 234, 2, 32, 3, 1, 254, 16, + 2, 234, 2, 32, 5, 1, 255, 46, 2, 234, 2, 32, 3, 1, 255, 46, 2, 234, 2, + 32, 5, 1, 255, 26, 2, 234, 2, 32, 3, 1, 255, 26, 2, 234, 2, 32, 5, 1, + 255, 26, 2, 59, 108, 32, 3, 1, 255, 26, 2, 59, 108, 32, 5, 1, 255, 26, 2, + 108, 32, 3, 1, 255, 26, 2, 108, 32, 5, 1, 238, 165, 201, 32, 3, 1, 238, + 165, 201, 32, 5, 1, 255, 23, 2, 234, 2, 32, 3, 1, 255, 23, 2, 234, 2, 32, + 5, 18, 255, 23, 248, 127, 32, 3, 18, 255, 23, 248, 127, 32, 5, 1, 255, + 38, 2, 240, 1, 90, 32, 3, 1, 255, 38, 2, 240, 1, 90, 32, 5, 1, 235, 66, + 219, 32, 3, 1, 235, 66, 219, 32, 5, 1, 255, 55, 2, 234, 2, 32, 3, 1, 255, + 55, 2, 234, 2, 32, 5, 1, 255, 45, 2, 234, 2, 32, 3, 1, 255, 45, 2, 234, + 2, 32, 5, 1, 236, 218, 79, 32, 3, 1, 236, 218, 79, 32, 5, 1, 236, 218, + 132, 2, 108, 32, 3, 1, 236, 218, 132, 2, 108, 32, 5, 1, 255, 58, 2, 234, + 2, 32, 3, 1, 255, 58, 2, 234, 2, 32, 5, 18, 255, 45, 248, 112, 32, 3, 18, + 255, 45, 248, 112, 32, 5, 1, 253, 223, 2, 234, 2, 32, 3, 1, 253, 223, 2, + 234, 2, 32, 5, 1, 253, 223, 2, 59, 108, 32, 3, 1, 253, 223, 2, 59, 108, + 32, 5, 1, 244, 10, 32, 3, 1, 244, 10, 32, 5, 1, 235, 66, 248, 88, 32, 3, + 1, 235, 66, 248, 88, 32, 5, 1, 235, 66, 253, 223, 2, 234, 2, 32, 3, 1, + 235, 66, 253, 223, 2, 234, 2, 32, 1, 236, 69, 32, 5, 1, 254, 16, 2, 239, + 255, 32, 3, 1, 254, 16, 2, 239, 255, 32, 5, 1, 255, 26, 2, 90, 32, 3, 1, + 255, 26, 2, 90, 32, 5, 1, 255, 49, 2, 242, 226, 32, 3, 1, 255, 49, 2, + 242, 226, 32, 5, 1, 255, 23, 2, 90, 32, 3, 1, 255, 23, 2, 90, 32, 5, 1, + 255, 23, 2, 242, 226, 32, 3, 1, 255, 23, 2, 242, 226, 32, 5, 1, 234, 59, + 248, 88, 32, 3, 1, 234, 59, 248, 88, 32, 5, 1, 255, 28, 2, 242, 226, 32, + 3, 1, 255, 28, 2, 242, 226, 32, 5, 1, 134, 2, 239, 255, 32, 3, 1, 134, 2, + 239, 255, 32, 5, 1, 134, 2, 175, 32, 3, 1, 134, 2, 175, 32, 5, 18, 134, + 253, 237, 32, 3, 18, 134, 253, 237, 32, 5, 1, 255, 42, 2, 239, 255, 32, + 3, 1, 255, 42, 2, 239, 255, 32, 5, 1, 240, 86, 32, 3, 1, 240, 86, 32, 5, + 1, 243, 73, 2, 175, 32, 3, 1, 243, 73, 2, 175, 32, 5, 1, 254, 16, 2, 175, + 32, 3, 1, 254, 16, 2, 175, 32, 5, 1, 255, 46, 2, 175, 32, 3, 1, 255, 46, + 2, 175, 32, 5, 1, 235, 66, 248, 126, 32, 3, 1, 235, 66, 248, 126, 32, 5, + 1, 220, 2, 196, 32, 3, 1, 220, 2, 196, 32, 5, 1, 220, 2, 175, 32, 3, 1, + 220, 2, 175, 32, 5, 1, 117, 2, 175, 32, 3, 1, 117, 2, 175, 32, 5, 1, 240, + 60, 73, 32, 3, 1, 240, 60, 73, 32, 5, 1, 240, 60, 117, 2, 175, 32, 3, 1, + 240, 60, 117, 2, 175, 32, 5, 1, 157, 2, 175, 32, 3, 1, 157, 2, 175, 32, + 5, 1, 132, 2, 196, 32, 3, 1, 132, 2, 196, 32, 5, 1, 132, 2, 175, 32, 3, + 1, 132, 2, 175, 32, 5, 1, 132, 2, 45, 135, 32, 3, 1, 132, 2, 45, 135, 32, + 5, 1, 253, 223, 2, 175, 32, 3, 1, 253, 223, 2, 175, 32, 5, 1, 253, 233, + 2, 234, 2, 32, 3, 1, 253, 233, 2, 234, 2, 32, 5, 1, 249, 207, 2, 175, 32, + 3, 1, 249, 207, 2, 175, 32, 5, 1, 248, 72, 253, 200, 32, 3, 1, 248, 72, + 253, 200, 32, 5, 1, 248, 72, 248, 150, 32, 3, 1, 248, 72, 248, 150, 32, + 5, 1, 248, 72, 249, 220, 32, 3, 1, 248, 72, 249, 220, 32, 5, 1, 248, 72, + 243, 167, 32, 3, 1, 248, 72, 243, 167, 32, 5, 1, 248, 72, 248, 165, 32, + 3, 1, 248, 72, 248, 165, 32, 5, 1, 248, 72, 248, 174, 32, 3, 1, 248, 72, + 248, 174, 32, 5, 1, 248, 72, 249, 165, 32, 3, 1, 248, 72, 249, 165, 32, + 5, 1, 248, 72, 249, 178, 32, 3, 1, 248, 72, 249, 178, 100, 5, 1, 249, 28, + 100, 5, 1, 249, 32, 100, 5, 1, 249, 76, 100, 5, 1, 253, 133, 100, 5, 1, + 248, 208, 100, 5, 1, 253, 163, 100, 5, 1, 254, 36, 100, 5, 1, 254, 60, + 100, 5, 1, 87, 100, 5, 1, 248, 123, 100, 5, 1, 248, 216, 100, 5, 1, 243, + 216, 100, 5, 1, 249, 17, 100, 5, 1, 253, 152, 100, 5, 1, 249, 93, 100, 5, + 1, 253, 184, 100, 5, 1, 253, 146, 100, 5, 1, 243, 182, 100, 5, 1, 243, + 155, 100, 5, 1, 248, 228, 100, 5, 1, 253, 189, 100, 5, 1, 248, 175, 100, + 5, 1, 248, 46, 100, 5, 1, 254, 13, 100, 5, 1, 248, 57, 100, 5, 1, 248, + 237, 100, 5, 1, 243, 201, 100, 5, 1, 253, 130, 100, 5, 1, 249, 159, 100, + 5, 1, 249, 195, 100, 5, 1, 244, 32, 100, 5, 1, 248, 245, 100, 5, 1, 253, + 224, 100, 5, 1, 243, 136, 100, 5, 1, 243, 244, 100, 5, 1, 248, 218, 100, + 5, 1, 254, 118, 100, 5, 1, 248, 156, 100, 49, 1, 40, 137, 242, 233, 100, + 233, 59, 100, 237, 8, 69, 100, 233, 54, 69, 100, 240, 27, 100, 236, 156, + 69, 100, 232, 88, 69, 100, 3, 1, 249, 28, 100, 3, 1, 249, 32, 100, 3, 1, + 249, 76, 100, 3, 1, 253, 133, 100, 3, 1, 248, 208, 100, 3, 1, 253, 163, + 100, 3, 1, 254, 36, 100, 3, 1, 254, 60, 100, 3, 1, 87, 100, 3, 1, 248, + 123, 100, 3, 1, 248, 216, 100, 3, 1, 243, 216, 100, 3, 1, 249, 17, 100, + 3, 1, 253, 152, 100, 3, 1, 249, 93, 100, 3, 1, 253, 184, 100, 3, 1, 253, + 146, 100, 3, 1, 243, 182, 100, 3, 1, 243, 155, 100, 3, 1, 248, 228, 100, + 3, 1, 253, 189, 100, 3, 1, 248, 175, 100, 3, 1, 248, 46, 100, 3, 1, 254, + 13, 100, 3, 1, 248, 57, 100, 3, 1, 248, 237, 100, 3, 1, 243, 201, 100, 3, + 1, 253, 130, 100, 3, 1, 249, 159, 100, 3, 1, 249, 195, 100, 3, 1, 244, + 32, 100, 3, 1, 248, 245, 100, 3, 1, 253, 224, 100, 3, 1, 243, 136, 100, + 3, 1, 243, 244, 100, 3, 1, 248, 218, 100, 3, 1, 254, 118, 100, 3, 1, 248, + 156, 100, 3, 18, 254, 159, 243, 136, 100, 248, 37, 208, 100, 238, 93, 68, + 240, 2, 237, 152, 68, 240, 2, 240, 145, 68, 240, 2, 233, 242, 68, 240, 2, + 244, 64, 240, 212, 68, 240, 2, 244, 64, 241, 120, 68, 240, 2, 239, 222, + 68, 240, 2, 242, 81, 68, 240, 2, 242, 200, 68, 240, 2, 239, 158, 68, 240, + 2, 242, 197, 68, 240, 2, 242, 145, 68, 240, 2, 238, 186, 68, 240, 2, 241, + 126, 239, 141, 68, 240, 2, 234, 56, 68, 240, 2, 242, 71, 246, 238, 68, + 240, 2, 238, 224, 239, 80, 68, 240, 2, 242, 50, 68, 240, 2, 244, 85, 239, + 88, 68, 240, 2, 241, 250, 68, 240, 2, 236, 54, 68, 240, 2, 239, 134, 68, + 240, 2, 241, 235, 239, 106, 68, 240, 2, 241, 73, 68, 240, 2, 242, 69, 68, + 240, 2, 238, 224, 239, 171, 68, 240, 2, 247, 225, 254, 145, 247, 232, 68, + 240, 2, 252, 58, 68, 240, 2, 245, 226, 68, 240, 2, 245, 61, 68, 240, 2, + 242, 208, 68, 158, 241, 230, 238, 51, 68, 242, 232, 242, 105, 68, 242, + 232, 243, 98, 240, 145, 68, 242, 232, 243, 98, 240, 118, 68, 242, 232, + 243, 98, 238, 149, 68, 242, 232, 240, 187, 68, 242, 232, 242, 159, 68, + 242, 232, 240, 145, 68, 242, 232, 240, 118, 68, 242, 232, 238, 149, 68, + 242, 232, 240, 188, 68, 242, 232, 239, 172, 68, 242, 232, 240, 133, 128, + 240, 140, 68, 242, 232, 241, 236, 68, 233, 51, 241, 228, 68, 242, 232, + 243, 70, 68, 233, 51, 242, 47, 68, 242, 232, 248, 102, 248, 40, 68, 242, + 232, 254, 73, 248, 40, 68, 233, 51, 254, 240, 242, 48, 68, 158, 189, 248, + 40, 68, 158, 168, 248, 40, 68, 233, 51, 254, 114, 237, 167, 68, 242, 232, + 242, 70, 240, 212, 68, 1, 243, 3, 68, 1, 250, 117, 68, 1, 241, 136, 68, + 1, 240, 165, 68, 1, 253, 168, 68, 1, 249, 192, 68, 1, 242, 201, 68, 1, + 251, 54, 68, 1, 249, 176, 68, 1, 248, 193, 68, 1, 30, 248, 116, 68, 1, + 248, 116, 68, 1, 240, 139, 68, 1, 30, 248, 166, 68, 1, 248, 166, 68, 1, + 30, 248, 132, 68, 1, 248, 132, 68, 1, 239, 178, 68, 1, 243, 144, 68, 1, + 30, 253, 175, 68, 1, 253, 175, 68, 1, 30, 240, 248, 68, 1, 240, 248, 68, + 1, 252, 99, 68, 1, 243, 253, 68, 1, 243, 33, 68, 1, 249, 175, 68, 18, + 238, 126, 45, 249, 192, 68, 18, 238, 126, 254, 76, 248, 193, 68, 18, 238, + 126, 45, 248, 193, 68, 233, 51, 238, 186, 68, 233, 51, 234, 56, 11, 61, + 52, 11, 21, 242, 97, 11, 237, 159, 238, 95, 11, 21, 242, 93, 238, 237, + 52, 11, 240, 27, 11, 250, 186, 234, 6, 11, 242, 63, 244, 46, 52, 11, 21, + 241, 245, 11, 21, 233, 100, 240, 107, 235, 40, 11, 21, 240, 107, 235, + 173, 11, 21, 233, 228, 238, 242, 11, 21, 252, 127, 238, 244, 244, 80, 11, + 21, 235, 31, 11, 3, 200, 248, 137, 11, 234, 14, 11, 240, 3, 53, 233, 51, + 69, 11, 236, 156, 69, 11, 1, 240, 186, 11, 1, 83, 2, 243, 42, 48, 11, 1, + 83, 2, 143, 48, 11, 1, 253, 220, 2, 143, 48, 11, 1, 83, 2, 143, 46, 11, + 1, 57, 2, 143, 48, 11, 1, 243, 3, 11, 1, 249, 31, 11, 1, 253, 127, 237, + 200, 11, 1, 252, 213, 11, 1, 247, 142, 11, 1, 243, 200, 11, 1, 251, 45, + 11, 1, 243, 205, 11, 1, 250, 180, 11, 1, 247, 141, 11, 1, 248, 245, 11, + 1, 244, 63, 11, 1, 243, 120, 11, 1, 242, 103, 11, 1, 252, 165, 11, 1, + 250, 178, 11, 1, 248, 137, 11, 1, 253, 97, 11, 1, 248, 105, 11, 1, 240, + 180, 11, 238, 22, 11, 1, 248, 156, 11, 1, 249, 145, 11, 1, 248, 116, 11, + 1, 251, 182, 11, 1, 243, 223, 11, 1, 243, 236, 11, 1, 251, 50, 11, 1, + 248, 142, 11, 1, 83, 236, 232, 11, 1, 248, 144, 11, 236, 18, 11, 235, + 197, 11, 236, 43, 11, 241, 103, 11, 240, 134, 11, 241, 193, 11, 239, 191, + 11, 240, 240, 11, 241, 223, 48, 11, 143, 48, 11, 143, 46, 11, 235, 48, + 243, 3, 11, 236, 145, 240, 134, 11, 158, 198, 238, 187, 11, 236, 144, 11, + 33, 21, 3, 255, 110, 48, 11, 33, 21, 236, 145, 3, 255, 110, 48, 11, 33, + 21, 53, 46, 11, 224, 240, 134, 11, 243, 40, 2, 171, 243, 5, 232, 73, 26, + 242, 217, 232, 73, 26, 127, 232, 73, 26, 111, 232, 73, 26, 166, 232, 73, + 26, 177, 232, 73, 26, 176, 232, 73, 26, 187, 232, 73, 26, 203, 232, 73, + 26, 195, 232, 73, 26, 202, 11, 238, 107, 52, 11, 238, 176, 234, 6, 11, + 235, 114, 234, 6, 11, 248, 48, 238, 74, 242, 229, 11, 1, 238, 70, 249, + 31, 11, 1, 238, 70, 249, 145, 11, 1, 233, 49, 243, 3, 11, 1, 83, 242, + 182, 11, 1, 83, 2, 248, 103, 143, 48, 11, 1, 83, 2, 248, 103, 143, 46, + 11, 1, 200, 240, 186, 11, 1, 200, 143, 243, 3, 11, 1, 200, 143, 248, 142, + 11, 1, 132, 2, 143, 48, 11, 1, 200, 143, 248, 144, 11, 1, 247, 165, 11, + 1, 239, 231, 11, 1, 244, 214, 11, 1, 253, 127, 2, 242, 233, 11, 1, 253, + 127, 2, 204, 181, 60, 234, 9, 11, 1, 248, 237, 11, 1, 242, 143, 11, 1, + 241, 28, 11, 1, 94, 2, 143, 48, 11, 1, 94, 2, 171, 181, 59, 48, 11, 1, + 246, 201, 11, 1, 245, 77, 11, 1, 94, 2, 204, 181, 48, 11, 1, 242, 142, + 11, 1, 238, 23, 11, 1, 245, 37, 11, 1, 253, 199, 2, 242, 233, 11, 1, 253, + 199, 2, 53, 46, 11, 1, 253, 199, 2, 53, 242, 230, 19, 3, 248, 137, 11, 1, + 241, 71, 11, 1, 239, 38, 11, 1, 250, 208, 11, 1, 253, 199, 2, 204, 181, + 60, 234, 9, 11, 1, 253, 199, 2, 248, 58, 181, 48, 11, 1, 247, 36, 11, 1, + 253, 143, 2, 3, 179, 11, 1, 253, 143, 2, 242, 233, 11, 1, 253, 143, 2, + 53, 46, 11, 1, 253, 143, 2, 3, 255, 110, 46, 11, 1, 253, 143, 2, 53, 242, + 230, 19, 53, 48, 11, 1, 253, 143, 2, 171, 181, 48, 11, 1, 251, 112, 11, + 1, 253, 143, 2, 248, 58, 181, 48, 11, 1, 248, 39, 2, 53, 242, 230, 19, + 53, 48, 11, 1, 248, 39, 2, 204, 181, 46, 11, 1, 248, 39, 2, 204, 181, + 242, 230, 19, 204, 181, 48, 11, 1, 253, 157, 2, 171, 181, 46, 11, 1, 253, + 157, 2, 204, 181, 48, 11, 1, 253, 169, 2, 204, 181, 48, 11, 1, 253, 158, + 2, 204, 181, 48, 11, 1, 238, 70, 248, 156, 11, 1, 253, 153, 2, 53, 246, + 92, 46, 11, 1, 253, 153, 2, 53, 46, 11, 1, 253, 10, 11, 1, 253, 153, 2, + 204, 181, 46, 11, 1, 242, 53, 11, 1, 253, 167, 2, 53, 48, 11, 1, 253, + 167, 2, 204, 181, 48, 11, 1, 241, 197, 11, 1, 243, 126, 248, 116, 11, 1, + 253, 135, 2, 242, 233, 11, 1, 253, 135, 2, 53, 48, 11, 1, 254, 26, 11, 1, + 253, 135, 2, 204, 181, 46, 11, 1, 251, 5, 11, 1, 253, 246, 2, 242, 233, + 11, 1, 242, 8, 11, 1, 253, 246, 2, 171, 181, 46, 11, 1, 245, 129, 11, 1, + 253, 246, 2, 204, 181, 48, 11, 1, 182, 2, 3, 179, 11, 1, 182, 2, 53, 48, + 11, 1, 182, 2, 204, 181, 48, 11, 1, 182, 2, 204, 181, 46, 11, 1, 198, 2, + 53, 46, 11, 1, 198, 238, 187, 11, 1, 242, 85, 11, 1, 198, 2, 242, 233, + 11, 1, 198, 2, 204, 181, 48, 11, 1, 253, 124, 232, 133, 11, 1, 243, 47, + 2, 53, 48, 11, 1, 253, 124, 2, 57, 48, 11, 1, 253, 124, 243, 185, 11, 1, + 253, 124, 248, 128, 2, 143, 48, 11, 1, 253, 127, 238, 144, 243, 185, 11, + 1, 253, 220, 2, 242, 233, 11, 1, 238, 73, 253, 193, 11, 1, 253, 193, 11, + 1, 79, 11, 1, 253, 161, 11, 1, 238, 73, 253, 161, 11, 1, 253, 220, 2, + 171, 181, 48, 11, 1, 254, 12, 11, 1, 243, 26, 248, 144, 11, 1, 57, 2, + 242, 226, 11, 1, 57, 2, 3, 179, 11, 1, 253, 220, 2, 53, 48, 11, 1, 72, + 11, 1, 57, 2, 204, 181, 46, 11, 1, 57, 239, 5, 11, 1, 57, 240, 92, 2, + 143, 48, 11, 248, 37, 208, 11, 1, 253, 178, 11, 3, 200, 18, 253, 157, 2, + 182, 2, 83, 236, 232, 11, 3, 200, 18, 253, 167, 2, 182, 2, 83, 236, 232, + 11, 3, 200, 51, 54, 13, 11, 3, 200, 182, 243, 3, 11, 3, 200, 243, 200, + 11, 3, 200, 204, 243, 5, 11, 3, 200, 243, 120, 11, 253, 165, 147, 244, + 87, 11, 243, 124, 147, 254, 237, 255, 49, 245, 147, 11, 3, 200, 238, 121, + 242, 217, 11, 3, 200, 239, 234, 233, 97, 242, 217, 11, 3, 200, 238, 70, + 251, 49, 147, 243, 205, 11, 3, 200, 51, 39, 13, 11, 3, 170, 243, 120, 11, + 3, 200, 241, 222, 11, 3, 248, 142, 11, 3, 248, 144, 11, 3, 200, 248, 144, + 11, 3, 200, 243, 236, 11, 243, 245, 147, 239, 177, 11, 243, 15, 240, 46, + 170, 208, 11, 243, 15, 240, 46, 200, 208, 11, 238, 121, 200, 248, 119, 2, + 241, 109, 238, 129, 11, 3, 170, 243, 223, 11, 1, 253, 199, 2, 236, 145, + 179, 11, 1, 253, 143, 2, 236, 145, 179, 236, 174, 232, 73, 26, 242, 217, + 236, 174, 232, 73, 26, 127, 236, 174, 232, 73, 26, 111, 236, 174, 232, + 73, 26, 166, 236, 174, 232, 73, 26, 177, 236, 174, 232, 73, 26, 176, 236, + 174, 232, 73, 26, 187, 236, 174, 232, 73, 26, 203, 236, 174, 232, 73, 26, + 195, 236, 174, 232, 73, 26, 202, 11, 1, 242, 216, 2, 53, 46, 11, 1, 253, + 155, 2, 53, 46, 11, 1, 242, 240, 2, 53, 46, 11, 21, 240, 233, 234, 17, + 11, 21, 240, 233, 232, 197, 248, 228, 11, 1, 253, 124, 2, 236, 145, 179, + 129, 253, 165, 147, 234, 232, 129, 233, 80, 248, 37, 208, 129, 235, 110, + 248, 37, 208, 129, 233, 80, 240, 24, 129, 235, 110, 240, 24, 129, 163, + 240, 24, 129, 243, 14, 240, 122, 242, 220, 129, 243, 14, 240, 122, 225, + 129, 233, 80, 243, 14, 240, 122, 242, 220, 129, 235, 110, 243, 14, 240, + 122, 225, 129, 232, 121, 129, 236, 227, 239, 150, 129, 236, 227, 234, + 222, 129, 236, 227, 233, 117, 129, 232, 88, 69, 129, 1, 240, 155, 129, 1, + 233, 49, 240, 155, 129, 1, 244, 219, 129, 1, 241, 121, 129, 1, 245, 96, + 235, 123, 129, 1, 239, 35, 129, 1, 238, 70, 241, 72, 243, 255, 129, 1, + 253, 168, 129, 1, 248, 142, 129, 1, 244, 63, 129, 1, 245, 142, 129, 1, + 247, 140, 129, 1, 252, 216, 235, 123, 129, 1, 247, 238, 129, 1, 253, 87, + 253, 168, 129, 1, 246, 5, 129, 1, 239, 113, 129, 1, 251, 235, 129, 1, + 248, 132, 129, 1, 237, 37, 129, 1, 30, 237, 37, 129, 1, 72, 129, 1, 253, + 175, 129, 1, 224, 253, 175, 129, 1, 242, 92, 129, 1, 247, 6, 129, 1, 243, + 255, 129, 1, 243, 33, 129, 1, 252, 211, 129, 1, 184, 241, 30, 129, 1, + 184, 239, 84, 129, 1, 184, 237, 104, 129, 240, 143, 48, 129, 240, 143, + 46, 129, 240, 143, 238, 136, 129, 240, 154, 48, 129, 240, 154, 46, 129, + 240, 154, 238, 136, 129, 243, 252, 48, 129, 243, 252, 46, 129, 240, 4, + 244, 66, 233, 50, 129, 240, 4, 244, 66, 237, 61, 129, 243, 192, 48, 129, + 243, 192, 46, 129, 233, 205, 238, 136, 129, 243, 170, 48, 129, 243, 170, + 46, 129, 242, 91, 129, 237, 9, 248, 40, 129, 234, 244, 129, 236, 94, 129, + 171, 59, 181, 48, 129, 171, 59, 181, 46, 129, 204, 181, 48, 129, 204, + 181, 46, 129, 238, 106, 248, 41, 48, 129, 238, 106, 248, 41, 46, 129, + 241, 251, 129, 237, 71, 129, 1, 238, 151, 242, 202, 129, 1, 238, 151, + 241, 201, 129, 1, 238, 151, 254, 62, 11, 1, 253, 136, 2, 204, 181, 232, + 173, 46, 11, 1, 253, 136, 2, 53, 242, 230, 19, 204, 181, 48, 11, 1, 253, + 136, 2, 204, 181, 236, 150, 226, 226, 46, 11, 1, 253, 136, 2, 204, 181, + 236, 150, 226, 226, 242, 230, 19, 171, 181, 48, 11, 1, 253, 136, 2, 171, + 181, 242, 230, 19, 53, 48, 11, 1, 253, 136, 2, 236, 145, 3, 255, 110, 46, + 11, 1, 253, 136, 2, 3, 179, 11, 1, 94, 2, 171, 181, 48, 11, 1, 94, 2, + 204, 181, 236, 150, 226, 226, 46, 11, 1, 253, 199, 2, 171, 181, 234, 33, + 242, 230, 19, 3, 248, 137, 11, 1, 253, 199, 2, 236, 145, 3, 255, 110, 46, + 11, 1, 253, 143, 2, 108, 11, 1, 248, 39, 2, 248, 58, 181, 48, 11, 1, 253, + 158, 2, 171, 181, 48, 11, 1, 253, 158, 2, 204, 181, 236, 150, 235, 45, + 48, 11, 1, 253, 158, 2, 171, 181, 234, 33, 48, 11, 1, 253, 153, 2, 171, + 181, 46, 11, 1, 253, 153, 2, 204, 181, 236, 150, 226, 226, 46, 11, 1, + 243, 21, 2, 53, 48, 11, 1, 243, 21, 2, 204, 181, 48, 11, 1, 243, 21, 2, + 204, 181, 236, 150, 226, 226, 46, 11, 1, 51, 2, 53, 48, 11, 1, 51, 2, 53, + 46, 11, 1, 198, 2, 171, 181, 46, 11, 1, 198, 2, 3, 248, 137, 11, 1, 198, + 2, 3, 179, 11, 1, 182, 2, 125, 11, 1, 253, 143, 2, 171, 181, 234, 33, 48, + 11, 1, 253, 143, 2, 143, 48, 11, 1, 248, 39, 2, 171, 181, 234, 33, 48, + 199, 1, 248, 114, 199, 1, 234, 254, 199, 1, 242, 22, 199, 1, 248, 182, + 199, 1, 249, 30, 199, 1, 234, 218, 199, 1, 241, 191, 199, 1, 241, 8, 199, + 1, 242, 173, 199, 1, 241, 231, 199, 1, 241, 101, 199, 1, 239, 41, 199, 1, + 243, 76, 199, 1, 241, 210, 199, 1, 241, 119, 199, 1, 234, 195, 199, 1, + 242, 99, 199, 1, 235, 199, 199, 1, 236, 143, 199, 1, 236, 127, 199, 1, + 248, 191, 199, 1, 236, 72, 199, 1, 236, 42, 199, 1, 234, 100, 199, 1, + 247, 163, 199, 1, 243, 194, 199, 1, 246, 8, 199, 1, 239, 217, 199, 1, + 249, 216, 199, 1, 239, 193, 199, 1, 239, 176, 199, 1, 239, 34, 199, 1, + 87, 199, 1, 253, 222, 199, 1, 244, 74, 199, 1, 239, 83, 199, 1, 242, 68, + 199, 1, 242, 181, 199, 237, 54, 199, 234, 88, 199, 237, 176, 199, 234, + 183, 199, 238, 37, 199, 234, 229, 199, 237, 145, 199, 234, 189, 199, 237, + 223, 199, 234, 228, 199, 240, 240, 199, 1, 248, 231, 85, 21, 232, 77, 85, + 21, 235, 61, 85, 21, 236, 173, 85, 1, 242, 215, 67, 85, 1, 67, 85, 1, + 253, 140, 85, 1, 71, 85, 1, 253, 142, 85, 1, 79, 85, 1, 253, 148, 85, 1, + 165, 144, 85, 1, 165, 162, 85, 1, 240, 61, 72, 85, 1, 242, 215, 72, 85, + 1, 72, 85, 1, 253, 149, 85, 1, 240, 61, 73, 85, 1, 242, 215, 73, 85, 1, + 73, 85, 1, 253, 151, 85, 1, 201, 85, 1, 248, 61, 85, 1, 253, 139, 85, 1, + 248, 77, 85, 1, 248, 50, 85, 1, 253, 152, 85, 1, 248, 57, 85, 1, 253, + 146, 85, 1, 248, 89, 85, 1, 248, 78, 85, 1, 248, 71, 85, 1, 242, 247, 85, + 1, 248, 75, 85, 1, 242, 249, 85, 1, 248, 82, 85, 1, 253, 126, 85, 1, 248, + 55, 85, 1, 253, 133, 85, 1, 248, 76, 85, 1, 253, 131, 85, 1, 243, 234, + 85, 1, 253, 129, 85, 1, 248, 65, 85, 1, 253, 141, 85, 1, 248, 81, 85, 1, + 222, 85, 1, 216, 85, 1, 253, 130, 85, 1, 248, 96, 85, 1, 253, 134, 85, 1, + 248, 94, 85, 1, 243, 104, 85, 1, 253, 171, 85, 1, 248, 46, 85, 1, 248, + 66, 85, 1, 253, 132, 85, 1, 219, 85, 21, 240, 81, 85, 21, 235, 80, 85, + 33, 21, 253, 140, 85, 33, 21, 71, 85, 33, 21, 253, 142, 85, 33, 21, 79, + 85, 33, 21, 253, 148, 85, 33, 21, 165, 144, 85, 33, 21, 165, 253, 182, + 85, 33, 21, 240, 61, 72, 85, 33, 21, 242, 215, 72, 85, 33, 21, 72, 85, + 33, 21, 253, 149, 85, 33, 21, 240, 61, 73, 85, 33, 21, 242, 215, 73, 85, + 33, 21, 73, 85, 33, 21, 253, 151, 85, 21, 238, 72, 85, 254, 43, 85, 240, + 148, 21, 239, 233, 85, 240, 148, 21, 235, 163, 85, 242, 245, 238, 54, 85, + 242, 241, 238, 54, 85, 1, 253, 217, 85, 1, 243, 207, 85, 1, 243, 183, 85, + 1, 253, 163, 85, 1, 241, 75, 85, 1, 248, 246, 85, 1, 253, 179, 85, 1, + 249, 24, 85, 1, 165, 253, 182, 85, 1, 165, 253, 191, 85, 33, 21, 165, + 162, 85, 33, 21, 165, 253, 191, 85, 240, 111, 85, 45, 240, 111, 85, 26, + 242, 217, 85, 26, 127, 85, 26, 111, 85, 26, 166, 85, 26, 177, 85, 26, + 176, 85, 26, 187, 85, 26, 203, 85, 26, 195, 85, 26, 202, 85, 232, 88, 52, + 85, 1, 238, 62, 208, 101, 21, 232, 77, 101, 21, 235, 61, 101, 21, 236, + 173, 101, 1, 67, 101, 1, 253, 140, 101, 1, 71, 101, 1, 253, 142, 101, 1, + 79, 101, 1, 253, 148, 101, 1, 165, 144, 101, 1, 165, 162, 101, 1, 72, + 101, 1, 253, 149, 101, 1, 73, 101, 1, 253, 151, 101, 1, 201, 101, 1, 248, + 61, 101, 1, 253, 139, 101, 1, 248, 77, 101, 1, 248, 50, 101, 1, 253, 152, + 101, 1, 248, 57, 101, 1, 253, 146, 101, 1, 248, 89, 101, 1, 248, 78, 101, + 1, 248, 71, 101, 1, 242, 247, 101, 1, 248, 75, 101, 1, 242, 249, 101, 1, + 248, 82, 101, 1, 253, 126, 101, 1, 248, 55, 101, 1, 253, 133, 101, 1, + 248, 76, 101, 1, 253, 131, 101, 1, 253, 129, 101, 1, 248, 65, 101, 1, + 253, 141, 101, 1, 248, 81, 101, 1, 222, 101, 1, 216, 101, 1, 253, 130, + 101, 1, 253, 134, 101, 1, 248, 46, 101, 1, 248, 66, 101, 1, 253, 132, + 101, 1, 219, 101, 21, 240, 81, 101, 21, 235, 80, 101, 33, 21, 253, 140, + 101, 33, 21, 71, 101, 33, 21, 253, 142, 101, 33, 21, 79, 101, 33, 21, + 253, 148, 101, 33, 21, 165, 144, 101, 33, 21, 165, 253, 182, 101, 33, 21, + 72, 101, 33, 21, 253, 149, 101, 33, 21, 73, 101, 33, 21, 253, 151, 101, + 21, 238, 72, 101, 1, 241, 200, 253, 126, 101, 255, 39, 240, 51, 69, 101, + 1, 248, 96, 101, 1, 248, 246, 101, 1, 249, 24, 101, 1, 165, 253, 182, + 101, 1, 165, 253, 191, 101, 33, 21, 165, 162, 101, 33, 21, 165, 253, 191, + 101, 26, 242, 217, 101, 26, 127, 101, 26, 111, 101, 26, 166, 101, 26, + 177, 101, 26, 176, 101, 26, 187, 101, 26, 203, 101, 26, 195, 101, 26, + 202, 101, 1, 255, 63, 2, 240, 1, 235, 86, 101, 1, 255, 63, 2, 168, 235, + 86, 101, 243, 44, 69, 101, 243, 44, 52, 101, 236, 181, 235, 79, 127, 101, + 236, 181, 235, 79, 111, 101, 236, 181, 235, 79, 166, 101, 236, 181, 235, + 79, 177, 101, 236, 181, 235, 79, 253, 125, 251, 190, 249, 1, 253, 145, + 232, 129, 101, 236, 181, 233, 131, 236, 202, 101, 238, 191, 133, 21, 249, + 233, 240, 160, 133, 21, 240, 160, 133, 21, 236, 173, 133, 1, 67, 133, 1, + 253, 140, 133, 1, 71, 133, 1, 253, 142, 133, 1, 79, 133, 1, 253, 148, + 133, 1, 253, 164, 133, 1, 253, 149, 133, 1, 253, 156, 133, 1, 253, 151, + 133, 1, 201, 133, 1, 248, 61, 133, 1, 253, 139, 133, 1, 248, 77, 133, 1, + 248, 50, 133, 1, 253, 152, 133, 1, 248, 57, 133, 1, 253, 146, 133, 1, + 248, 89, 133, 1, 248, 78, 133, 1, 248, 71, 133, 1, 242, 247, 133, 1, 248, + 75, 133, 1, 242, 249, 133, 1, 248, 82, 133, 1, 253, 126, 133, 1, 248, 55, + 133, 1, 253, 133, 133, 1, 248, 76, 133, 1, 253, 131, 133, 1, 253, 129, + 133, 1, 248, 65, 133, 1, 253, 141, 133, 1, 248, 81, 133, 1, 222, 133, 1, + 216, 133, 1, 253, 130, 133, 1, 253, 134, 133, 1, 248, 94, 133, 1, 253, + 171, 133, 1, 248, 46, 133, 1, 253, 132, 133, 1, 219, 133, 21, 240, 81, + 133, 33, 21, 253, 140, 133, 33, 21, 71, 133, 33, 21, 253, 142, 133, 33, + 21, 79, 133, 33, 21, 253, 148, 133, 33, 21, 253, 164, 133, 33, 21, 253, + 149, 133, 33, 21, 253, 156, 133, 33, 21, 253, 151, 133, 21, 238, 72, 133, + 1, 243, 207, 133, 1, 243, 183, 133, 1, 253, 163, 133, 1, 248, 96, 133, 1, + 253, 179, 133, 26, 242, 217, 133, 26, 127, 133, 26, 111, 133, 26, 166, + 133, 26, 177, 133, 26, 176, 133, 26, 187, 133, 26, 203, 133, 26, 195, + 133, 26, 202, 133, 242, 154, 133, 241, 5, 133, 251, 107, 133, 253, 2, + 133, 255, 73, 242, 41, 112, 21, 232, 77, 112, 21, 235, 61, 112, 21, 236, + 173, 112, 1, 67, 112, 1, 253, 140, 112, 1, 71, 112, 1, 253, 142, 112, 1, + 79, 112, 1, 253, 148, 112, 1, 165, 144, 112, 1, 165, 162, 112, 33, 240, + 61, 72, 112, 1, 72, 112, 1, 253, 149, 112, 33, 240, 61, 73, 112, 1, 73, + 112, 1, 253, 151, 112, 1, 201, 112, 1, 248, 61, 112, 1, 253, 139, 112, 1, + 248, 77, 112, 1, 248, 50, 112, 1, 253, 152, 112, 1, 248, 57, 112, 1, 253, + 146, 112, 1, 248, 89, 112, 1, 248, 78, 112, 1, 248, 71, 112, 1, 242, 247, + 112, 1, 248, 75, 112, 1, 242, 249, 112, 1, 248, 82, 112, 1, 253, 126, + 112, 1, 248, 55, 112, 1, 253, 133, 112, 1, 248, 76, 112, 1, 253, 131, + 112, 1, 253, 129, 112, 1, 248, 65, 112, 1, 253, 141, 112, 1, 248, 81, + 112, 1, 222, 112, 1, 216, 112, 1, 253, 130, 112, 1, 253, 134, 112, 1, + 248, 94, 112, 1, 253, 171, 112, 1, 248, 46, 112, 1, 248, 66, 112, 1, 253, + 132, 112, 1, 219, 112, 21, 240, 81, 112, 21, 235, 80, 112, 33, 21, 253, + 140, 112, 33, 21, 71, 112, 33, 21, 253, 142, 112, 33, 21, 79, 112, 33, + 21, 253, 148, 112, 33, 21, 165, 144, 112, 33, 21, 165, 253, 182, 112, 33, + 21, 240, 61, 72, 112, 33, 21, 72, 112, 33, 21, 253, 149, 112, 33, 21, + 240, 61, 73, 112, 33, 21, 73, 112, 33, 21, 253, 151, 112, 21, 238, 72, + 112, 254, 43, 112, 1, 165, 253, 182, 112, 1, 165, 253, 191, 112, 33, 21, + 165, 162, 112, 33, 21, 165, 253, 191, 112, 26, 242, 217, 112, 26, 127, + 112, 26, 111, 112, 26, 166, 112, 26, 177, 112, 26, 176, 112, 26, 187, + 112, 26, 203, 112, 26, 195, 112, 26, 202, 112, 243, 44, 52, 118, 21, 232, + 77, 118, 21, 235, 61, 118, 21, 236, 173, 118, 1, 67, 118, 1, 253, 140, + 118, 1, 71, 118, 1, 253, 142, 118, 1, 79, 118, 1, 253, 148, 118, 1, 165, + 144, 118, 1, 165, 162, 118, 1, 72, 118, 1, 253, 149, 118, 1, 73, 118, 1, + 253, 151, 118, 1, 201, 118, 1, 248, 61, 118, 1, 253, 139, 118, 1, 248, + 77, 118, 1, 248, 50, 118, 1, 253, 152, 118, 1, 248, 57, 118, 1, 253, 146, + 118, 1, 248, 89, 118, 1, 248, 78, 118, 1, 248, 71, 118, 1, 242, 247, 118, + 1, 248, 75, 118, 1, 242, 249, 118, 1, 248, 82, 118, 1, 253, 126, 118, 1, + 248, 55, 118, 1, 253, 133, 118, 1, 248, 76, 118, 1, 253, 131, 118, 1, + 253, 129, 118, 1, 248, 65, 118, 1, 253, 141, 118, 1, 248, 81, 118, 1, + 222, 118, 1, 216, 118, 1, 253, 130, 118, 1, 253, 134, 118, 1, 248, 94, + 118, 1, 253, 171, 118, 1, 248, 46, 118, 1, 248, 66, 118, 1, 253, 132, + 118, 1, 219, 118, 21, 240, 81, 118, 21, 235, 80, 118, 33, 21, 253, 140, + 118, 33, 21, 71, 118, 33, 21, 253, 142, 118, 33, 21, 79, 118, 33, 21, + 253, 148, 118, 33, 21, 165, 144, 118, 33, 21, 72, 118, 33, 21, 253, 149, + 118, 33, 21, 73, 118, 33, 21, 253, 151, 118, 21, 238, 72, 118, 255, 37, + 240, 51, 69, 118, 255, 39, 240, 51, 69, 118, 1, 248, 96, 118, 1, 248, + 246, 118, 1, 249, 24, 118, 1, 165, 253, 182, 118, 1, 165, 253, 191, 118, + 26, 242, 217, 118, 26, 127, 118, 26, 111, 118, 26, 166, 118, 26, 177, + 118, 26, 176, 118, 26, 187, 118, 26, 203, 118, 26, 195, 118, 26, 202, + 118, 238, 191, 118, 1, 253, 138, 140, 21, 235, 61, 140, 21, 236, 173, + 140, 1, 67, 140, 1, 253, 140, 140, 1, 71, 140, 1, 253, 142, 140, 1, 79, + 140, 1, 253, 148, 140, 1, 72, 140, 1, 253, 164, 140, 1, 253, 149, 140, 1, + 73, 140, 1, 253, 156, 140, 1, 253, 151, 140, 1, 201, 140, 1, 248, 50, + 140, 1, 253, 152, 140, 1, 253, 146, 140, 1, 248, 78, 140, 1, 248, 71, + 140, 1, 248, 82, 140, 1, 253, 126, 140, 1, 253, 131, 140, 1, 243, 234, + 140, 1, 253, 129, 140, 1, 222, 140, 1, 216, 140, 1, 253, 130, 140, 1, + 248, 96, 140, 1, 253, 134, 140, 1, 248, 94, 140, 1, 243, 104, 140, 1, + 253, 171, 140, 1, 248, 46, 140, 1, 248, 66, 140, 1, 253, 132, 140, 1, + 219, 140, 33, 21, 253, 140, 140, 33, 21, 71, 140, 33, 21, 253, 142, 140, + 33, 21, 79, 140, 33, 21, 253, 148, 140, 33, 21, 72, 140, 33, 21, 253, + 164, 140, 33, 21, 253, 149, 140, 33, 21, 73, 140, 33, 21, 253, 156, 140, + 33, 21, 253, 151, 140, 21, 238, 72, 140, 255, 39, 240, 51, 69, 140, 26, + 242, 217, 140, 26, 127, 140, 26, 111, 140, 26, 166, 140, 26, 177, 140, + 26, 176, 140, 26, 187, 140, 26, 203, 140, 26, 195, 140, 26, 202, 140, 61, + 248, 53, 140, 61, 253, 125, 236, 149, 140, 61, 253, 125, 235, 49, 140, + 253, 137, 52, 140, 246, 90, 52, 140, 249, 206, 52, 140, 245, 59, 52, 140, + 241, 68, 52, 140, 255, 24, 60, 52, 140, 243, 44, 52, 140, 61, 52, 124, + 21, 232, 77, 124, 21, 235, 61, 124, 21, 236, 173, 124, 1, 67, 124, 1, + 253, 140, 124, 1, 71, 124, 1, 253, 142, 124, 1, 79, 124, 1, 253, 148, + 124, 1, 165, 144, 124, 1, 165, 162, 124, 1, 72, 124, 1, 253, 164, 124, 1, + 253, 149, 124, 1, 73, 124, 1, 253, 156, 124, 1, 253, 151, 124, 1, 201, + 124, 1, 248, 61, 124, 1, 253, 139, 124, 1, 248, 77, 124, 1, 248, 50, 124, + 1, 253, 152, 124, 1, 248, 57, 124, 1, 253, 146, 124, 1, 248, 89, 124, 1, + 248, 78, 124, 1, 248, 71, 124, 1, 242, 247, 124, 1, 248, 75, 124, 1, 242, + 249, 124, 1, 248, 82, 124, 1, 253, 126, 124, 1, 248, 55, 124, 1, 253, + 133, 124, 1, 248, 76, 124, 1, 253, 131, 124, 1, 253, 129, 124, 1, 248, + 65, 124, 1, 253, 141, 124, 1, 248, 81, 124, 1, 222, 124, 1, 216, 124, 1, + 253, 130, 124, 1, 248, 96, 124, 1, 253, 134, 124, 1, 248, 94, 124, 1, + 253, 171, 124, 1, 248, 46, 124, 1, 248, 66, 124, 1, 253, 132, 124, 1, + 219, 124, 33, 21, 253, 140, 124, 33, 21, 71, 124, 33, 21, 253, 142, 124, + 33, 21, 79, 124, 33, 21, 253, 148, 124, 33, 21, 165, 144, 124, 33, 21, + 165, 253, 182, 124, 33, 21, 72, 124, 33, 21, 253, 164, 124, 33, 21, 253, + 149, 124, 33, 21, 73, 124, 33, 21, 253, 156, 124, 33, 21, 253, 151, 124, + 21, 238, 72, 124, 240, 51, 69, 124, 255, 37, 240, 51, 69, 124, 1, 165, + 253, 182, 124, 1, 165, 253, 191, 124, 26, 242, 217, 124, 26, 127, 124, + 26, 111, 124, 26, 166, 124, 26, 177, 124, 26, 176, 124, 26, 187, 124, 26, + 203, 124, 26, 195, 124, 26, 202, 115, 21, 235, 61, 115, 21, 236, 173, + 115, 1, 67, 115, 1, 253, 140, 115, 1, 71, 115, 1, 253, 142, 115, 1, 79, + 115, 1, 253, 148, 115, 1, 165, 144, 115, 1, 165, 162, 115, 1, 72, 115, 1, + 253, 164, 115, 1, 253, 149, 115, 1, 73, 115, 1, 253, 156, 115, 1, 253, + 151, 115, 1, 201, 115, 1, 248, 61, 115, 1, 253, 139, 115, 1, 248, 77, + 115, 1, 248, 50, 115, 1, 253, 152, 115, 1, 248, 57, 115, 1, 253, 146, + 115, 1, 248, 89, 115, 1, 248, 78, 115, 1, 248, 71, 115, 1, 242, 247, 115, + 1, 248, 75, 115, 1, 242, 249, 115, 1, 248, 82, 115, 1, 253, 126, 115, 1, + 248, 55, 115, 1, 253, 133, 115, 1, 248, 76, 115, 1, 253, 131, 115, 1, + 253, 129, 115, 1, 248, 65, 115, 1, 253, 141, 115, 1, 248, 81, 115, 1, + 222, 115, 1, 216, 115, 1, 253, 130, 115, 1, 248, 96, 115, 1, 253, 134, + 115, 1, 248, 94, 115, 1, 253, 171, 115, 1, 248, 46, 115, 1, 248, 66, 115, + 1, 253, 132, 115, 1, 219, 115, 21, 240, 81, 115, 21, 235, 80, 115, 33, + 21, 253, 140, 115, 33, 21, 71, 115, 33, 21, 253, 142, 115, 33, 21, 79, + 115, 33, 21, 253, 148, 115, 33, 21, 165, 144, 115, 33, 21, 165, 253, 182, + 115, 33, 21, 72, 115, 33, 21, 253, 164, 115, 33, 21, 253, 149, 115, 33, + 21, 73, 115, 33, 21, 253, 156, 115, 33, 21, 253, 151, 115, 21, 238, 72, + 115, 240, 51, 69, 115, 255, 37, 240, 51, 69, 115, 1, 253, 179, 115, 1, + 165, 253, 182, 115, 1, 165, 253, 191, 115, 26, 242, 217, 115, 26, 127, + 115, 26, 111, 115, 26, 166, 115, 26, 177, 115, 26, 176, 115, 26, 187, + 115, 26, 203, 115, 26, 195, 115, 26, 202, 130, 21, 235, 61, 130, 21, 236, + 173, 130, 1, 67, 130, 1, 253, 140, 130, 1, 71, 130, 1, 253, 142, 130, 1, + 79, 130, 1, 253, 148, 130, 1, 165, 144, 130, 1, 165, 162, 130, 1, 72, + 130, 1, 253, 164, 130, 1, 253, 149, 130, 1, 73, 130, 1, 253, 156, 130, 1, + 253, 151, 130, 1, 201, 130, 1, 248, 61, 130, 1, 253, 139, 130, 1, 248, + 77, 130, 1, 248, 50, 130, 1, 253, 152, 130, 1, 248, 57, 130, 1, 253, 146, + 130, 1, 248, 89, 130, 1, 248, 78, 130, 1, 248, 71, 130, 1, 242, 247, 130, + 1, 248, 75, 130, 1, 242, 249, 130, 1, 248, 82, 130, 1, 253, 126, 130, 1, + 248, 55, 130, 1, 253, 133, 130, 1, 248, 76, 130, 1, 253, 131, 130, 1, + 253, 129, 130, 1, 248, 65, 130, 1, 253, 141, 130, 1, 248, 81, 130, 1, + 222, 130, 1, 216, 130, 1, 253, 130, 130, 1, 248, 96, 130, 1, 253, 134, + 130, 1, 248, 94, 130, 1, 243, 104, 130, 1, 253, 171, 130, 1, 248, 46, + 130, 1, 248, 66, 130, 1, 253, 132, 130, 1, 219, 130, 33, 21, 253, 140, + 130, 33, 21, 71, 130, 33, 21, 253, 142, 130, 33, 21, 79, 130, 33, 21, + 253, 148, 130, 33, 21, 165, 144, 130, 33, 21, 72, 130, 33, 21, 253, 164, + 130, 33, 21, 253, 149, 130, 33, 21, 73, 130, 33, 21, 253, 156, 130, 33, + 21, 253, 151, 130, 21, 238, 72, 130, 255, 39, 240, 51, 69, 130, 1, 165, + 253, 182, 130, 1, 165, 253, 191, 130, 26, 242, 217, 130, 26, 127, 130, + 26, 111, 130, 26, 166, 130, 26, 177, 130, 26, 176, 130, 26, 187, 130, 26, + 203, 130, 26, 195, 130, 26, 202, 123, 21, 233, 115, 123, 21, 235, 39, + 123, 1, 239, 0, 123, 1, 237, 53, 123, 1, 237, 56, 123, 1, 235, 161, 123, + 1, 239, 102, 123, 1, 237, 178, 123, 1, 239, 237, 123, 1, 238, 39, 123, 1, + 236, 41, 123, 1, 234, 209, 123, 1, 236, 37, 123, 1, 234, 202, 123, 1, + 239, 59, 123, 1, 237, 146, 123, 1, 237, 57, 123, 1, 239, 156, 123, 1, + 237, 227, 123, 1, 237, 68, 123, 1, 234, 8, 237, 16, 123, 1, 233, 58, 237, + 16, 123, 1, 234, 8, 236, 226, 123, 1, 233, 58, 236, 226, 123, 1, 239, + 105, 233, 89, 123, 1, 238, 122, 236, 226, 123, 1, 234, 8, 236, 250, 123, + 1, 233, 58, 236, 250, 123, 1, 234, 8, 236, 228, 123, 1, 233, 58, 236, + 228, 123, 1, 238, 154, 233, 89, 123, 1, 238, 154, 238, 1, 232, 185, 123, + 1, 238, 122, 236, 228, 123, 1, 234, 8, 235, 155, 123, 1, 233, 58, 235, + 155, 123, 1, 234, 8, 235, 97, 123, 1, 233, 58, 235, 97, 123, 1, 235, 104, + 237, 25, 123, 1, 238, 122, 235, 97, 123, 1, 234, 8, 237, 46, 123, 1, 233, + 58, 237, 46, 123, 1, 234, 8, 236, 222, 123, 1, 233, 58, 236, 222, 123, 1, + 238, 134, 237, 25, 123, 1, 238, 122, 236, 222, 123, 1, 234, 8, 237, 27, + 123, 1, 233, 58, 237, 27, 123, 1, 234, 8, 236, 220, 123, 1, 233, 58, 236, + 220, 123, 1, 237, 205, 123, 1, 249, 237, 236, 220, 123, 1, 238, 47, 123, + 1, 237, 247, 123, 1, 238, 134, 237, 20, 123, 1, 238, 41, 123, 1, 238, + 154, 236, 238, 123, 1, 235, 104, 236, 238, 123, 1, 238, 134, 236, 238, + 123, 1, 237, 171, 123, 1, 235, 104, 237, 20, 123, 1, 237, 155, 123, 21, + 234, 90, 123, 33, 21, 233, 67, 123, 33, 21, 243, 102, 233, 81, 123, 33, + 21, 248, 107, 233, 81, 123, 33, 21, 243, 102, 235, 130, 123, 33, 21, 248, + 107, 235, 130, 123, 33, 21, 243, 102, 234, 60, 123, 33, 21, 248, 107, + 234, 60, 123, 33, 21, 231, 104, 123, 33, 21, 237, 17, 123, 33, 21, 248, + 107, 237, 17, 123, 33, 21, 246, 18, 245, 62, 123, 33, 21, 238, 141, 254, + 64, 233, 67, 123, 33, 21, 238, 141, 254, 64, 248, 107, 233, 67, 123, 33, + 21, 238, 141, 254, 64, 232, 90, 123, 33, 21, 232, 90, 123, 33, 21, 248, + 107, 231, 104, 123, 33, 21, 248, 107, 232, 90, 123, 233, 51, 233, 214, + 107, 99, 255, 59, 249, 91, 107, 99, 253, 249, 246, 9, 107, 99, 253, 249, + 241, 202, 107, 99, 253, 249, 241, 203, 107, 99, 253, 249, 246, 12, 107, + 99, 253, 249, 237, 245, 107, 99, 254, 213, 252, 19, 107, 99, 254, 35, + 244, 253, 107, 99, 254, 35, 241, 53, 107, 99, 254, 35, 241, 51, 107, 99, + 255, 35, 253, 186, 107, 99, 254, 35, 245, 5, 107, 99, 255, 66, 247, 230, + 107, 99, 255, 48, 241, 49, 107, 99, 153, 242, 49, 107, 99, 253, 240, 243, + 127, 107, 99, 253, 240, 233, 218, 107, 99, 253, 240, 237, 237, 107, 99, + 255, 51, 252, 12, 107, 99, 255, 48, 250, 188, 107, 99, 153, 252, 208, + 107, 99, 253, 240, 242, 152, 107, 99, 253, 240, 239, 218, 107, 99, 253, + 240, 242, 151, 107, 99, 255, 51, 253, 150, 107, 99, 255, 69, 239, 2, 107, + 99, 255, 88, 252, 70, 107, 99, 254, 27, 242, 60, 107, 99, 255, 41, 253, + 179, 107, 99, 254, 27, 246, 244, 107, 99, 255, 41, 250, 233, 107, 99, + 254, 27, 238, 0, 107, 99, 255, 83, 222, 107, 99, 255, 66, 249, 20, 107, + 99, 255, 90, 252, 150, 107, 99, 253, 185, 107, 99, 255, 43, 243, 215, + 107, 99, 254, 8, 107, 99, 255, 96, 247, 191, 107, 99, 255, 35, 247, 63, + 107, 99, 255, 35, 247, 57, 107, 99, 255, 35, 252, 191, 107, 99, 255, 32, + 251, 62, 107, 99, 255, 43, 241, 55, 107, 99, 117, 248, 124, 107, 99, 255, + 32, 239, 145, 107, 99, 234, 231, 107, 99, 248, 83, 67, 107, 99, 253, 205, + 236, 32, 107, 99, 248, 83, 253, 140, 107, 99, 248, 83, 254, 32, 107, 99, + 248, 83, 71, 107, 99, 248, 83, 253, 142, 107, 99, 248, 83, 253, 252, 107, + 99, 248, 83, 252, 249, 107, 99, 248, 83, 79, 107, 99, 248, 83, 253, 148, + 107, 99, 237, 236, 107, 236, 181, 12, 244, 190, 107, 99, 248, 83, 72, + 107, 99, 248, 83, 253, 178, 107, 99, 248, 83, 73, 107, 99, 248, 83, 255, + 37, 237, 198, 107, 99, 248, 83, 255, 37, 236, 55, 107, 99, 232, 181, 107, + 99, 236, 56, 107, 99, 234, 220, 107, 99, 253, 205, 254, 90, 107, 99, 253, + 205, 248, 97, 107, 99, 253, 205, 252, 229, 107, 99, 253, 205, 235, 188, + 107, 99, 233, 41, 107, 99, 236, 63, 107, 99, 236, 141, 107, 99, 237, 158, + 107, 26, 242, 217, 107, 26, 127, 107, 26, 111, 107, 26, 166, 107, 26, + 177, 107, 26, 176, 107, 26, 187, 107, 26, 203, 107, 26, 195, 107, 26, + 202, 107, 99, 233, 113, 107, 99, 239, 108, 152, 1, 253, 190, 152, 1, 253, + 249, 243, 35, 152, 1, 253, 249, 248, 120, 152, 1, 248, 172, 152, 1, 253, + 224, 152, 1, 255, 35, 248, 120, 152, 1, 248, 133, 152, 1, 253, 225, 152, + 1, 87, 152, 1, 253, 240, 243, 35, 152, 1, 253, 240, 248, 120, 152, 1, + 253, 173, 152, 1, 254, 1, 152, 1, 253, 208, 152, 1, 254, 27, 243, 35, + 152, 1, 255, 41, 248, 120, 152, 1, 254, 27, 248, 120, 152, 1, 255, 41, + 243, 35, 152, 1, 253, 181, 152, 1, 253, 162, 152, 1, 255, 43, 243, 215, + 152, 1, 255, 43, 246, 54, 152, 1, 253, 177, 152, 1, 255, 35, 243, 35, + 152, 1, 255, 32, 243, 35, 152, 1, 73, 152, 1, 255, 32, 248, 120, 152, + 235, 69, 152, 33, 21, 67, 152, 33, 21, 253, 205, 248, 162, 152, 33, 21, + 253, 140, 152, 33, 21, 254, 32, 152, 33, 21, 71, 152, 33, 21, 253, 142, + 152, 33, 21, 255, 14, 152, 33, 21, 254, 77, 152, 33, 21, 79, 152, 33, 21, + 253, 148, 152, 33, 21, 253, 205, 251, 159, 152, 235, 143, 21, 253, 216, + 152, 235, 143, 21, 248, 133, 152, 33, 21, 72, 152, 33, 21, 254, 89, 152, + 33, 21, 73, 152, 33, 21, 254, 33, 152, 33, 21, 253, 149, 152, 255, 59, + 253, 134, 152, 188, 253, 205, 254, 90, 152, 188, 253, 205, 248, 97, 152, + 188, 253, 205, 253, 212, 152, 188, 253, 205, 239, 18, 152, 232, 118, 69, + 152, 234, 227, 152, 26, 242, 217, 152, 26, 127, 152, 26, 111, 152, 26, + 166, 152, 26, 177, 152, 26, 176, 152, 26, 187, 152, 26, 203, 152, 26, + 195, 152, 26, 202, 152, 255, 32, 253, 173, 152, 255, 32, 253, 181, 47, 4, + 254, 43, 47, 158, 248, 129, 253, 221, 253, 226, 236, 133, 67, 47, 158, + 248, 129, 253, 221, 253, 226, 254, 79, 249, 155, 250, 112, 222, 47, 158, + 248, 129, 253, 221, 253, 226, 254, 79, 248, 129, 243, 49, 222, 47, 158, + 54, 253, 221, 253, 226, 251, 224, 222, 47, 158, 238, 171, 253, 221, 253, + 226, 252, 173, 222, 47, 158, 243, 25, 253, 221, 253, 226, 249, 137, 249, + 161, 222, 47, 158, 253, 221, 253, 226, 243, 49, 249, 161, 222, 47, 158, + 247, 65, 243, 23, 47, 158, 244, 230, 253, 221, 248, 167, 47, 158, 250, + 127, 249, 162, 253, 221, 248, 167, 47, 158, 231, 143, 240, 249, 47, 158, + 235, 202, 243, 49, 241, 40, 47, 158, 243, 23, 47, 158, 248, 234, 243, 23, + 47, 158, 243, 49, 243, 23, 47, 158, 248, 234, 243, 49, 243, 23, 47, 158, + 254, 235, 250, 159, 242, 126, 243, 23, 47, 158, 249, 154, 251, 29, 243, + 23, 47, 158, 243, 25, 243, 140, 243, 72, 255, 81, 183, 248, 100, 47, 158, + 248, 129, 240, 249, 47, 237, 22, 21, 250, 158, 240, 70, 47, 237, 22, 21, + 251, 192, 240, 70, 47, 232, 89, 21, 252, 175, 251, 12, 244, 67, 240, 70, + 47, 232, 89, 21, 241, 3, 253, 129, 47, 232, 89, 21, 247, 67, 239, 230, + 47, 21, 248, 101, 248, 151, 243, 179, 47, 21, 248, 101, 248, 151, 240, + 183, 47, 21, 248, 101, 248, 151, 243, 187, 47, 21, 248, 101, 254, 66, + 243, 179, 47, 21, 248, 101, 254, 66, 240, 183, 47, 21, 248, 101, 248, + 151, 248, 101, 251, 252, 47, 26, 242, 217, 47, 26, 127, 47, 26, 111, 47, + 26, 166, 47, 26, 177, 47, 26, 176, 47, 26, 187, 47, 26, 203, 47, 26, 195, + 47, 26, 202, 47, 26, 137, 127, 47, 26, 137, 111, 47, 26, 137, 166, 47, + 26, 137, 177, 47, 26, 137, 176, 47, 26, 137, 187, 47, 26, 137, 203, 47, + 26, 137, 195, 47, 26, 137, 202, 47, 26, 137, 242, 217, 47, 158, 244, 228, + 240, 70, 47, 158, 249, 119, 243, 153, 254, 116, 253, 108, 47, 158, 243, + 25, 243, 140, 243, 72, 248, 199, 254, 112, 248, 100, 47, 158, 249, 119, + 243, 153, 252, 174, 240, 70, 47, 158, 253, 223, 248, 167, 47, 158, 254, + 129, 241, 4, 47, 158, 254, 95, 243, 72, 243, 189, 47, 158, 254, 95, 243, + 72, 243, 188, 47, 158, 254, 80, 243, 206, 243, 189, 47, 158, 254, 80, + 243, 206, 243, 188, 47, 21, 255, 8, 240, 250, 47, 21, 254, 198, 240, 250, + 47, 1, 201, 47, 1, 248, 61, 47, 1, 253, 139, 47, 1, 248, 77, 47, 1, 248, + 50, 47, 1, 253, 152, 47, 1, 248, 57, 47, 1, 253, 146, 47, 1, 248, 78, 47, + 1, 248, 71, 47, 1, 242, 247, 47, 1, 248, 75, 47, 1, 242, 249, 47, 1, 248, + 82, 47, 1, 253, 126, 47, 1, 248, 55, 47, 1, 253, 133, 47, 1, 248, 76, 47, + 1, 253, 131, 47, 1, 253, 129, 47, 1, 248, 65, 47, 1, 253, 141, 47, 1, + 248, 81, 47, 1, 222, 47, 1, 248, 90, 47, 1, 243, 130, 47, 1, 248, 153, + 47, 1, 243, 165, 47, 1, 253, 138, 47, 1, 248, 99, 47, 1, 253, 163, 47, 1, + 254, 78, 47, 1, 216, 47, 1, 253, 130, 47, 1, 253, 134, 47, 1, 248, 46, + 47, 1, 248, 66, 47, 1, 253, 132, 47, 1, 219, 47, 1, 67, 47, 1, 243, 210, + 47, 1, 234, 28, 253, 130, 47, 33, 21, 253, 140, 47, 33, 21, 71, 47, 33, + 21, 253, 142, 47, 33, 21, 79, 47, 33, 21, 253, 148, 47, 33, 21, 165, 144, + 47, 33, 21, 165, 253, 182, 47, 33, 21, 165, 162, 47, 33, 21, 165, 253, + 191, 47, 33, 21, 72, 47, 33, 21, 253, 164, 47, 33, 21, 73, 47, 33, 21, + 253, 156, 47, 21, 252, 140, 255, 91, 254, 212, 253, 160, 47, 21, 249, + 155, 244, 212, 47, 33, 21, 224, 71, 47, 33, 21, 224, 253, 142, 47, 21, + 254, 116, 255, 12, 254, 210, 253, 133, 47, 21, 254, 239, 246, 39, 47, + 158, 237, 168, 47, 158, 239, 157, 47, 21, 254, 192, 240, 70, 47, 21, 248, + 122, 240, 70, 47, 21, 254, 191, 254, 129, 248, 100, 47, 21, 251, 223, + 248, 100, 47, 21, 254, 94, 254, 148, 237, 34, 47, 21, 254, 94, 254, 200, + 237, 34, 47, 213, 1, 201, 47, 213, 1, 248, 61, 47, 213, 1, 253, 139, 47, + 213, 1, 248, 77, 47, 213, 1, 248, 50, 47, 213, 1, 253, 152, 47, 213, 1, + 248, 57, 47, 213, 1, 253, 146, 47, 213, 1, 248, 78, 47, 213, 1, 248, 71, + 47, 213, 1, 242, 247, 47, 213, 1, 248, 75, 47, 213, 1, 242, 249, 47, 213, + 1, 248, 82, 47, 213, 1, 253, 126, 47, 213, 1, 248, 55, 47, 213, 1, 253, + 133, 47, 213, 1, 248, 76, 47, 213, 1, 253, 131, 47, 213, 1, 253, 129, 47, + 213, 1, 248, 65, 47, 213, 1, 253, 141, 47, 213, 1, 248, 81, 47, 213, 1, + 222, 47, 213, 1, 248, 90, 47, 213, 1, 243, 130, 47, 213, 1, 248, 153, 47, + 213, 1, 243, 165, 47, 213, 1, 253, 138, 47, 213, 1, 248, 99, 47, 213, 1, + 253, 163, 47, 213, 1, 254, 78, 47, 213, 1, 216, 47, 213, 1, 253, 130, 47, + 213, 1, 253, 134, 47, 213, 1, 248, 46, 47, 213, 1, 248, 66, 47, 213, 1, + 253, 132, 47, 213, 1, 219, 47, 213, 1, 67, 47, 213, 1, 243, 210, 47, 213, + 1, 234, 28, 253, 138, 47, 213, 1, 234, 28, 216, 47, 213, 1, 234, 28, 253, + 130, 47, 255, 60, 255, 64, 248, 61, 47, 255, 60, 255, 64, 254, 183, 248, + 199, 254, 112, 248, 100, 47, 232, 82, 21, 96, 243, 147, 47, 232, 82, 21, + 136, 243, 147, 47, 232, 82, 21, 250, 144, 247, 138, 47, 232, 82, 21, 252, + 170, 241, 2, 47, 12, 250, 206, 253, 243, 47, 12, 254, 124, 252, 139, 47, + 12, 246, 237, 245, 97, 47, 12, 254, 124, 254, 236, 249, 154, 245, 127, + 47, 12, 249, 137, 253, 129, 47, 12, 253, 192, 253, 243, 47, 12, 253, 192, + 255, 47, 248, 234, 238, 127, 47, 12, 253, 192, 255, 47, 251, 30, 238, + 127, 47, 12, 253, 192, 255, 47, 248, 199, 238, 127, 47, 21, 248, 101, + 254, 66, 243, 187, 47, 158, 244, 229, 249, 162, 255, 57, 253, 226, 240, + 216, 47, 158, 246, 89, 253, 221, 255, 57, 253, 226, 240, 216, 131, 1, + 201, 131, 1, 248, 61, 131, 1, 253, 139, 131, 1, 248, 77, 131, 1, 248, 50, + 131, 1, 253, 152, 131, 1, 248, 57, 131, 1, 253, 146, 131, 1, 248, 89, + 131, 1, 248, 78, 131, 1, 246, 175, 131, 1, 248, 71, 131, 1, 242, 247, + 131, 1, 248, 75, 131, 1, 242, 249, 131, 1, 248, 82, 131, 1, 253, 126, + 131, 1, 248, 55, 131, 1, 253, 133, 131, 1, 248, 76, 131, 1, 253, 131, + 131, 1, 253, 129, 131, 1, 248, 65, 131, 1, 253, 141, 131, 1, 248, 81, + 131, 1, 222, 131, 1, 216, 131, 1, 253, 130, 131, 1, 253, 134, 131, 1, + 253, 138, 131, 1, 253, 132, 131, 1, 219, 131, 1, 248, 94, 131, 1, 67, + 131, 1, 71, 131, 1, 253, 142, 131, 1, 79, 131, 1, 253, 148, 131, 1, 72, + 131, 1, 73, 131, 1, 253, 151, 131, 33, 21, 253, 140, 131, 33, 21, 71, + 131, 33, 21, 253, 142, 131, 33, 21, 79, 131, 33, 21, 253, 148, 131, 33, + 21, 72, 131, 33, 21, 253, 149, 131, 21, 235, 61, 131, 21, 53, 46, 131, + 21, 236, 173, 131, 21, 238, 72, 131, 26, 242, 217, 131, 26, 127, 131, 26, + 111, 131, 26, 166, 131, 26, 177, 131, 26, 176, 131, 26, 187, 131, 26, + 203, 131, 26, 195, 131, 26, 202, 131, 21, 240, 101, 236, 210, 131, 21, + 236, 210, 131, 12, 236, 52, 131, 12, 234, 102, 131, 12, 229, 63, 131, 12, + 236, 30, 131, 1, 248, 46, 131, 1, 248, 66, 131, 1, 165, 144, 131, 1, 165, + 253, 182, 131, 1, 165, 162, 131, 1, 165, 253, 191, 131, 33, 21, 165, 144, + 131, 33, 21, 165, 253, 182, 131, 33, 21, 165, 162, 131, 33, 21, 165, 253, + 191, 75, 5, 1, 254, 19, 75, 5, 1, 248, 195, 75, 5, 1, 248, 158, 75, 5, 1, + 248, 205, 75, 5, 1, 253, 202, 75, 5, 1, 249, 11, 75, 5, 1, 249, 25, 75, + 5, 1, 248, 253, 75, 5, 1, 253, 247, 75, 5, 1, 248, 162, 75, 5, 1, 248, + 224, 75, 5, 1, 248, 131, 75, 5, 1, 248, 171, 75, 5, 1, 254, 9, 75, 5, 1, + 248, 236, 75, 5, 1, 243, 138, 75, 5, 1, 248, 243, 75, 5, 1, 248, 134, 75, + 5, 1, 248, 254, 75, 5, 1, 254, 75, 75, 5, 1, 243, 115, 75, 5, 1, 243, + 103, 75, 5, 1, 243, 95, 75, 5, 1, 248, 242, 75, 5, 1, 243, 33, 75, 5, 1, + 243, 88, 75, 5, 1, 248, 100, 75, 5, 1, 248, 217, 75, 5, 1, 248, 201, 75, + 5, 1, 243, 87, 75, 5, 1, 249, 16, 75, 5, 1, 243, 101, 75, 5, 1, 248, 212, + 75, 5, 1, 253, 168, 75, 5, 1, 248, 160, 75, 5, 1, 253, 170, 75, 5, 1, + 248, 213, 75, 5, 1, 248, 215, 75, 1, 254, 19, 75, 1, 248, 195, 75, 1, + 248, 158, 75, 1, 248, 205, 75, 1, 253, 202, 75, 1, 249, 11, 75, 1, 249, + 25, 75, 1, 248, 253, 75, 1, 253, 247, 75, 1, 248, 162, 75, 1, 248, 224, + 75, 1, 248, 131, 75, 1, 248, 171, 75, 1, 254, 9, 75, 1, 248, 236, 75, 1, + 243, 138, 75, 1, 248, 243, 75, 1, 248, 134, 75, 1, 248, 254, 75, 1, 254, + 75, 75, 1, 243, 115, 75, 1, 243, 103, 75, 1, 243, 95, 75, 1, 248, 242, + 75, 1, 243, 33, 75, 1, 243, 88, 75, 1, 248, 100, 75, 1, 248, 217, 75, 1, + 248, 201, 75, 1, 243, 87, 75, 1, 249, 16, 75, 1, 243, 101, 75, 1, 248, + 212, 75, 1, 253, 168, 75, 1, 248, 160, 75, 1, 253, 170, 75, 1, 248, 213, + 75, 1, 248, 215, 75, 1, 253, 245, 75, 1, 255, 9, 75, 1, 241, 94, 75, 1, + 205, 248, 158, 75, 1, 248, 105, 75, 235, 91, 234, 6, 49, 1, 75, 248, 171, + 23, 102, 238, 99, 23, 102, 232, 87, 23, 102, 240, 80, 23, 102, 238, 102, + 23, 102, 232, 101, 23, 102, 240, 85, 23, 102, 240, 78, 23, 102, 240, 83, + 23, 102, 233, 79, 23, 102, 243, 34, 23, 102, 234, 32, 23, 102, 240, 75, + 23, 102, 240, 71, 23, 102, 233, 77, 23, 102, 236, 195, 23, 102, 236, 198, + 23, 102, 236, 205, 23, 102, 236, 201, 23, 102, 240, 74, 23, 102, 231, + 108, 23, 102, 233, 105, 23, 102, 231, 97, 23, 102, 232, 187, 23, 102, + 231, 56, 23, 102, 232, 108, 23, 102, 233, 106, 23, 102, 232, 85, 23, 102, + 231, 71, 23, 102, 232, 92, 23, 102, 231, 40, 23, 102, 231, 109, 23, 102, + 232, 195, 23, 102, 231, 110, 23, 102, 233, 66, 23, 102, 226, 243, 23, + 102, 226, 244, 23, 102, 227, 4, 23, 102, 229, 52, 23, 102, 227, 3, 23, + 102, 232, 106, 23, 102, 231, 75, 23, 102, 231, 52, 23, 102, 231, 51, 23, + 102, 231, 41, 23, 102, 226, 235, 23, 102, 232, 99, 23, 102, 233, 102, 23, + 102, 232, 100, 23, 102, 233, 103, 23, 102, 233, 245, 23, 102, 233, 76, + 23, 102, 226, 253, 23, 102, 231, 30, 23, 102, 233, 244, 23, 102, 233, + 101, 23, 102, 232, 55, 23, 102, 232, 56, 23, 102, 232, 58, 23, 102, 232, + 57, 23, 102, 233, 243, 23, 102, 231, 120, 23, 102, 226, 247, 23, 102, + 227, 13, 23, 102, 226, 232, 23, 102, 236, 234, 23, 102, 231, 106, 23, + 102, 231, 142, 23, 102, 232, 175, 23, 102, 232, 176, 23, 102, 233, 208, + 23, 102, 231, 68, 23, 102, 233, 78, 23, 102, 232, 174, 23, 102, 231, 66, + 23, 102, 231, 70, 23, 102, 231, 69, 23, 102, 235, 115, 23, 102, 232, 119, + 23, 102, 231, 62, 23, 102, 226, 238, 23, 102, 227, 1, 23, 102, 226, 229, + 23, 102, 227, 14, 23, 102, 231, 61, 23, 102, 227, 15, 23, 102, 226, 237, + 23, 102, 231, 50, 23, 102, 227, 9, 23, 102, 233, 104, 23, 102, 232, 102, + 23, 102, 238, 114, 23, 146, 238, 114, 23, 146, 67, 23, 146, 253, 178, 23, + 146, 216, 23, 146, 249, 18, 23, 146, 254, 59, 23, 146, 72, 23, 146, 249, + 22, 23, 146, 253, 254, 23, 146, 73, 23, 146, 253, 138, 23, 146, 249, 12, + 23, 146, 253, 193, 23, 146, 253, 162, 23, 146, 79, 23, 146, 249, 14, 23, + 146, 253, 170, 23, 146, 253, 187, 23, 146, 253, 161, 23, 146, 254, 61, + 23, 146, 253, 189, 23, 146, 71, 23, 146, 249, 229, 23, 146, 249, 230, 23, + 146, 247, 211, 23, 146, 242, 189, 23, 146, 245, 83, 23, 146, 245, 84, 23, + 146, 241, 96, 23, 146, 242, 195, 23, 146, 242, 196, 23, 146, 246, 230, + 23, 146, 252, 52, 23, 146, 246, 231, 23, 146, 252, 53, 23, 146, 252, 54, + 23, 146, 240, 255, 23, 146, 238, 233, 23, 146, 239, 251, 23, 146, 247, + 231, 23, 146, 244, 58, 23, 146, 252, 247, 23, 146, 247, 180, 23, 146, + 238, 36, 23, 146, 247, 181, 23, 146, 252, 248, 23, 146, 247, 234, 23, + 146, 242, 199, 23, 146, 247, 235, 23, 146, 238, 234, 23, 146, 241, 0, 23, + 146, 247, 236, 23, 146, 244, 60, 23, 146, 245, 86, 23, 146, 241, 99, 23, + 146, 247, 226, 23, 146, 251, 97, 23, 146, 245, 223, 23, 146, 251, 98, 23, + 146, 251, 99, 23, 146, 245, 222, 23, 146, 237, 175, 23, 146, 240, 156, + 23, 146, 235, 169, 23, 146, 237, 65, 23, 146, 237, 64, 23, 146, 233, 246, + 23, 114, 238, 99, 23, 114, 232, 87, 23, 114, 232, 91, 23, 114, 240, 80, + 23, 114, 232, 93, 23, 114, 232, 94, 23, 114, 238, 102, 23, 114, 240, 85, + 23, 114, 231, 98, 23, 114, 232, 96, 23, 114, 232, 97, 23, 114, 233, 74, + 23, 114, 231, 43, 23, 114, 231, 42, 23, 114, 232, 85, 23, 114, 240, 78, + 23, 114, 240, 83, 23, 114, 233, 66, 23, 114, 243, 34, 23, 114, 234, 32, + 23, 114, 240, 75, 23, 114, 240, 71, 23, 114, 236, 195, 23, 114, 236, 198, + 23, 114, 236, 205, 23, 114, 236, 201, 23, 114, 240, 74, 23, 114, 231, + 145, 23, 114, 226, 239, 23, 114, 231, 108, 23, 114, 231, 97, 23, 114, + 233, 90, 23, 114, 231, 47, 23, 114, 231, 74, 23, 114, 231, 56, 23, 114, + 232, 61, 23, 114, 226, 245, 23, 114, 232, 108, 23, 114, 231, 111, 23, + 114, 226, 241, 23, 114, 233, 106, 23, 114, 226, 240, 23, 114, 227, 5, 23, + 114, 226, 255, 23, 114, 226, 251, 23, 114, 226, 234, 23, 114, 229, 55, + 23, 114, 231, 54, 23, 114, 231, 76, 23, 114, 226, 246, 23, 114, 231, 147, + 23, 114, 232, 183, 23, 114, 232, 92, 23, 114, 233, 86, 23, 114, 229, 50, + 23, 114, 231, 46, 23, 114, 231, 73, 23, 114, 232, 182, 23, 114, 231, 40, + 23, 114, 232, 196, 23, 114, 231, 51, 23, 114, 232, 194, 23, 114, 231, 41, + 23, 114, 232, 99, 23, 114, 232, 100, 23, 114, 233, 103, 23, 114, 233, 76, + 23, 114, 236, 234, 23, 114, 231, 106, 23, 114, 226, 248, 23, 114, 233, + 78, 23, 114, 231, 67, 23, 114, 235, 115, 23, 114, 231, 58, 23, 114, 227, + 0, 23, 114, 231, 50, 23, 114, 227, 9, 23, 114, 232, 170, 23, 114, 232, + 172, 23, 114, 232, 169, 23, 114, 232, 171, 23, 114, 232, 102, 22, 4, 219, + 22, 4, 253, 236, 22, 4, 253, 214, 22, 4, 248, 114, 22, 4, 249, 80, 22, 4, + 253, 168, 22, 4, 253, 184, 22, 4, 251, 76, 22, 4, 253, 134, 22, 4, 254, + 8, 22, 4, 253, 251, 22, 4, 249, 101, 22, 4, 249, 102, 22, 4, 253, 250, + 22, 4, 253, 216, 22, 4, 248, 227, 22, 4, 251, 56, 22, 4, 251, 60, 22, 4, + 251, 58, 22, 4, 243, 194, 22, 4, 245, 143, 22, 4, 251, 57, 22, 4, 251, + 59, 22, 4, 245, 144, 22, 4, 222, 22, 4, 253, 154, 22, 4, 253, 180, 22, 4, + 249, 110, 22, 4, 249, 111, 22, 4, 253, 206, 22, 4, 253, 181, 22, 4, 248, + 169, 22, 4, 252, 202, 22, 4, 252, 206, 22, 4, 252, 204, 22, 4, 247, 131, + 22, 4, 247, 132, 22, 4, 252, 203, 22, 4, 252, 205, 22, 4, 247, 133, 22, + 4, 253, 130, 22, 4, 253, 185, 22, 4, 253, 209, 22, 4, 248, 182, 22, 4, + 249, 153, 22, 4, 253, 194, 22, 4, 253, 160, 22, 4, 252, 157, 22, 4, 253, + 132, 22, 4, 253, 211, 22, 4, 253, 198, 22, 4, 249, 158, 22, 4, 248, 184, + 22, 4, 253, 210, 22, 4, 253, 186, 22, 4, 248, 252, 22, 4, 248, 46, 22, 4, + 248, 248, 22, 4, 248, 185, 22, 4, 244, 7, 22, 4, 244, 9, 22, 4, 248, 118, + 22, 4, 248, 110, 22, 4, 243, 121, 22, 4, 253, 217, 22, 4, 254, 29, 22, 4, + 254, 28, 22, 4, 248, 241, 22, 4, 252, 88, 22, 4, 254, 70, 22, 4, 254, 45, + 22, 4, 252, 98, 22, 4, 252, 112, 22, 4, 252, 114, 22, 4, 247, 21, 22, 4, + 247, 22, 22, 4, 252, 113, 22, 4, 252, 89, 22, 4, 252, 93, 22, 4, 252, 91, + 22, 4, 247, 7, 22, 4, 247, 8, 22, 4, 252, 90, 22, 4, 252, 92, 22, 4, 247, + 9, 22, 4, 247, 11, 22, 4, 242, 72, 22, 4, 242, 73, 22, 4, 247, 10, 22, 4, + 253, 141, 22, 4, 253, 243, 22, 4, 254, 34, 22, 4, 249, 30, 22, 4, 248, + 197, 22, 4, 253, 242, 22, 4, 254, 1, 22, 4, 249, 36, 22, 4, 253, 171, 22, + 4, 254, 49, 22, 4, 254, 48, 22, 4, 253, 6, 22, 4, 249, 10, 22, 4, 254, + 12, 22, 4, 254, 13, 22, 4, 253, 24, 22, 4, 253, 126, 22, 4, 253, 196, 22, + 4, 253, 212, 22, 4, 249, 172, 22, 4, 248, 255, 22, 4, 253, 195, 22, 4, + 87, 22, 4, 249, 7, 22, 4, 253, 152, 22, 4, 254, 84, 22, 4, 254, 55, 22, + 4, 249, 37, 22, 4, 250, 154, 22, 4, 254, 54, 22, 4, 253, 224, 22, 4, 248, + 203, 22, 4, 253, 253, 22, 4, 255, 6, 22, 4, 253, 188, 22, 4, 253, 41, 22, + 4, 253, 42, 22, 4, 254, 132, 22, 4, 254, 133, 22, 4, 253, 47, 22, 4, 253, + 53, 22, 4, 253, 55, 22, 4, 247, 206, 22, 4, 247, 207, 22, 4, 253, 54, 22, + 4, 253, 131, 22, 4, 253, 150, 22, 4, 253, 166, 22, 4, 248, 231, 22, 4, + 249, 118, 22, 4, 253, 197, 22, 4, 253, 173, 22, 4, 248, 176, 22, 4, 248, + 78, 22, 4, 249, 125, 22, 4, 248, 178, 22, 4, 246, 198, 22, 4, 246, 200, + 22, 4, 252, 46, 22, 4, 248, 133, 22, 4, 246, 212, 22, 4, 238, 62, 67, 22, + 4, 238, 62, 79, 22, 4, 238, 62, 71, 22, 4, 238, 62, 253, 140, 22, 4, 238, + 62, 253, 164, 22, 4, 238, 62, 72, 22, 4, 238, 62, 73, 22, 4, 238, 62, + 253, 138, 22, 4, 201, 22, 4, 253, 203, 22, 4, 253, 215, 22, 4, 249, 90, + 22, 4, 251, 141, 22, 4, 253, 172, 22, 4, 253, 190, 22, 4, 251, 157, 22, + 4, 248, 221, 22, 4, 248, 223, 22, 4, 243, 65, 22, 4, 246, 25, 22, 4, 248, + 222, 22, 4, 251, 170, 22, 4, 251, 174, 22, 4, 251, 172, 22, 4, 246, 26, + 22, 4, 246, 27, 22, 4, 251, 171, 22, 4, 251, 173, 22, 4, 246, 28, 22, 4, + 246, 30, 22, 4, 241, 207, 22, 4, 241, 208, 22, 4, 246, 29, 22, 4, 253, + 138, 22, 4, 254, 14, 22, 4, 253, 187, 22, 4, 248, 190, 22, 4, 249, 199, + 22, 4, 253, 170, 22, 4, 253, 177, 22, 4, 253, 34, 22, 4, 234, 12, 67, 22, + 4, 234, 12, 79, 22, 4, 234, 12, 71, 22, 4, 234, 12, 253, 140, 22, 4, 234, + 12, 253, 164, 22, 4, 234, 12, 72, 22, 4, 234, 12, 73, 22, 4, 253, 163, + 22, 4, 254, 18, 22, 4, 254, 17, 22, 4, 249, 216, 22, 4, 248, 194, 22, 4, + 253, 228, 22, 4, 253, 222, 22, 4, 253, 117, 22, 4, 248, 99, 22, 4, 249, + 219, 22, 4, 249, 217, 22, 4, 247, 245, 22, 4, 243, 139, 22, 4, 248, 123, + 22, 4, 249, 218, 22, 4, 248, 4, 22, 4, 216, 22, 4, 253, 161, 22, 4, 253, + 189, 22, 4, 248, 191, 22, 4, 248, 192, 22, 4, 253, 254, 22, 4, 253, 162, + 22, 4, 253, 84, 22, 4, 253, 133, 22, 4, 253, 232, 22, 4, 253, 201, 22, 4, + 250, 177, 22, 4, 248, 149, 22, 4, 253, 200, 22, 4, 253, 225, 22, 4, 250, + 214, 22, 4, 248, 75, 22, 4, 249, 52, 22, 4, 249, 51, 22, 4, 245, 36, 22, + 4, 245, 41, 22, 4, 249, 50, 22, 4, 248, 204, 22, 4, 245, 57, 22, 4, 253, + 146, 22, 4, 254, 25, 22, 4, 254, 7, 22, 4, 251, 110, 22, 4, 248, 161, 22, + 4, 254, 24, 22, 4, 253, 248, 22, 4, 251, 131, 22, 4, 253, 139, 22, 4, + 253, 235, 22, 4, 254, 6, 22, 4, 248, 211, 22, 4, 249, 68, 22, 4, 254, 5, + 22, 4, 253, 234, 22, 4, 251, 25, 22, 4, 251, 36, 22, 4, 251, 38, 22, 4, + 245, 134, 22, 4, 245, 135, 22, 4, 251, 37, 22, 4, 249, 70, 22, 4, 249, + 74, 22, 4, 249, 72, 22, 4, 245, 99, 22, 4, 245, 103, 22, 4, 249, 71, 22, + 4, 249, 73, 22, 4, 241, 134, 22, 4, 248, 55, 22, 4, 249, 177, 22, 4, 248, + 121, 22, 4, 243, 76, 22, 4, 243, 77, 22, 4, 248, 111, 22, 4, 248, 97, 22, + 4, 247, 147, 22, 4, 248, 57, 22, 4, 248, 200, 22, 4, 248, 67, 22, 4, 244, + 252, 22, 4, 243, 54, 22, 4, 248, 88, 22, 4, 248, 125, 22, 4, 245, 13, 22, + 4, 248, 65, 22, 4, 252, 64, 22, 4, 248, 68, 22, 4, 246, 243, 22, 4, 246, + 245, 22, 4, 249, 136, 22, 4, 248, 238, 22, 4, 246, 247, 22, 4, 248, 90, + 22, 4, 249, 5, 22, 4, 248, 140, 22, 4, 247, 160, 22, 4, 244, 39, 22, 4, + 248, 112, 22, 4, 249, 4, 22, 4, 247, 162, 22, 4, 252, 242, 22, 4, 252, + 246, 22, 4, 252, 244, 22, 4, 247, 177, 22, 4, 247, 178, 22, 4, 252, 243, + 22, 4, 252, 245, 22, 4, 247, 179, 22, 4, 253, 179, 22, 4, 254, 93, 22, 4, + 253, 245, 22, 4, 249, 60, 22, 4, 249, 61, 22, 4, 254, 62, 22, 4, 254, 63, + 22, 4, 249, 66, 22, 4, 253, 129, 22, 4, 253, 239, 22, 4, 253, 147, 22, 4, + 249, 133, 22, 4, 248, 180, 22, 4, 253, 175, 22, 4, 253, 208, 22, 4, 248, + 181, 22, 4, 252, 158, 22, 4, 251, 248, 22, 4, 251, 1, 22, 50, 234, 194, + 69, 22, 238, 213, 69, 22, 235, 42, 22, 248, 37, 208, 22, 240, 27, 22, + 234, 14, 22, 240, 24, 22, 239, 166, 240, 24, 22, 236, 156, 69, 22, 235, + 91, 234, 6, 22, 26, 127, 22, 26, 111, 22, 26, 166, 22, 26, 177, 22, 26, + 176, 22, 26, 187, 22, 26, 203, 22, 26, 195, 22, 26, 202, 22, 61, 248, 53, + 22, 61, 238, 77, 22, 61, 238, 101, 22, 61, 240, 136, 22, 61, 240, 50, 22, + 61, 240, 234, 22, 61, 237, 38, 22, 61, 238, 182, 22, 61, 238, 147, 22, + 61, 236, 149, 22, 61, 253, 219, 235, 49, 22, 4, 235, 94, 248, 169, 22, 4, + 248, 230, 22, 4, 246, 101, 22, 4, 248, 229, 22, 4, 235, 94, 249, 36, 22, + 4, 250, 136, 22, 4, 244, 237, 22, 4, 250, 135, 22, 4, 235, 94, 249, 66, + 22, 4, 251, 0, 22, 4, 245, 95, 22, 4, 250, 255, 22, 4, 235, 94, 248, 181, + 22, 4, 248, 240, 22, 4, 247, 2, 22, 4, 248, 239, 22, 243, 10, 158, 242, + 198, 22, 243, 10, 158, 241, 83, 22, 243, 10, 158, 238, 212, 22, 243, 10, + 158, 242, 215, 238, 212, 22, 243, 10, 158, 241, 84, 22, 243, 10, 158, + 241, 199, 22, 243, 10, 158, 239, 24, 22, 243, 10, 158, 241, 149, 22, 243, + 10, 158, 232, 130, 22, 243, 10, 158, 246, 22, 109, 1, 67, 109, 1, 72, + 109, 1, 71, 109, 1, 73, 109, 1, 79, 109, 1, 179, 109, 1, 253, 139, 109, + 1, 201, 109, 1, 254, 5, 109, 1, 254, 6, 109, 1, 253, 234, 109, 1, 253, + 235, 109, 1, 254, 169, 109, 1, 219, 109, 1, 253, 168, 109, 1, 253, 214, + 109, 1, 253, 184, 109, 1, 253, 236, 109, 1, 254, 98, 109, 1, 253, 134, + 109, 1, 253, 250, 109, 1, 253, 251, 109, 1, 253, 216, 109, 1, 254, 8, + 109, 1, 254, 196, 109, 1, 222, 109, 1, 253, 206, 109, 1, 253, 180, 109, + 1, 253, 181, 109, 1, 253, 154, 109, 1, 253, 131, 109, 1, 249, 83, 109, 1, + 251, 253, 109, 1, 253, 197, 109, 1, 253, 166, 109, 1, 253, 173, 109, 1, + 253, 150, 109, 1, 254, 115, 109, 1, 252, 103, 109, 1, 252, 104, 109, 1, + 252, 105, 109, 1, 249, 149, 109, 1, 249, 150, 109, 1, 252, 110, 109, 1, + 253, 132, 109, 1, 193, 109, 1, 253, 210, 109, 1, 253, 198, 109, 1, 253, + 186, 109, 1, 253, 211, 109, 1, 254, 127, 109, 1, 253, 133, 109, 1, 253, + 126, 109, 1, 253, 200, 109, 1, 253, 195, 109, 1, 253, 201, 109, 1, 253, + 212, 109, 1, 253, 225, 109, 1, 253, 232, 109, 1, 254, 158, 109, 1, 249, + 55, 109, 1, 249, 179, 109, 1, 249, 180, 109, 1, 249, 181, 109, 1, 249, + 182, 109, 1, 249, 183, 109, 1, 252, 225, 109, 1, 248, 90, 109, 1, 248, + 112, 109, 1, 248, 140, 109, 1, 249, 4, 109, 1, 249, 5, 109, 1, 252, 230, + 109, 1, 253, 138, 109, 1, 253, 170, 109, 1, 253, 187, 109, 1, 253, 177, + 109, 1, 254, 14, 109, 1, 255, 4, 109, 1, 216, 109, 1, 253, 254, 109, 1, + 253, 189, 109, 1, 253, 162, 109, 1, 253, 161, 109, 1, 255, 10, 14, 15, + 72, 14, 15, 249, 231, 14, 15, 71, 14, 15, 253, 142, 14, 15, 73, 14, 15, + 253, 156, 14, 15, 240, 44, 253, 156, 14, 15, 55, 253, 164, 14, 15, 55, + 71, 14, 15, 67, 14, 15, 253, 140, 14, 15, 253, 170, 14, 15, 106, 253, + 170, 14, 15, 253, 187, 14, 15, 106, 253, 187, 14, 15, 249, 200, 14, 15, + 106, 249, 200, 14, 15, 253, 177, 14, 15, 106, 253, 177, 14, 15, 249, 15, + 14, 15, 106, 249, 15, 14, 15, 238, 66, 249, 15, 14, 15, 253, 138, 14, 15, + 106, 253, 138, 14, 15, 248, 190, 14, 15, 106, 248, 190, 14, 15, 238, 66, + 248, 190, 14, 15, 253, 149, 14, 15, 240, 44, 255, 16, 14, 15, 238, 62, + 208, 14, 15, 30, 135, 14, 15, 30, 191, 14, 15, 30, 240, 17, 137, 242, + 233, 14, 15, 30, 253, 159, 137, 242, 233, 14, 15, 30, 38, 137, 242, 233, + 14, 15, 30, 242, 233, 14, 15, 30, 45, 135, 14, 15, 30, 45, 242, 215, 59, + 237, 45, 14, 15, 30, 240, 1, 248, 40, 14, 15, 30, 242, 215, 163, 108, 14, + 15, 30, 243, 12, 14, 15, 30, 92, 242, 234, 14, 15, 253, 202, 14, 15, 253, + 247, 14, 15, 254, 9, 14, 15, 254, 19, 14, 15, 253, 175, 14, 15, 246, 236, + 14, 15, 253, 147, 14, 15, 249, 138, 14, 15, 253, 208, 14, 15, 249, 140, + 14, 15, 240, 44, 249, 140, 14, 15, 55, 249, 80, 14, 15, 55, 253, 214, 14, + 15, 253, 129, 14, 15, 249, 133, 14, 15, 248, 239, 14, 15, 106, 248, 239, + 14, 15, 248, 240, 14, 15, 106, 248, 240, 14, 15, 243, 247, 14, 15, 106, + 243, 247, 14, 15, 249, 143, 14, 15, 106, 249, 143, 14, 15, 243, 248, 14, + 15, 106, 243, 248, 14, 15, 248, 181, 14, 15, 106, 248, 181, 14, 15, 243, + 118, 14, 15, 106, 243, 118, 14, 15, 240, 44, 243, 118, 14, 15, 223, 14, + 15, 106, 223, 14, 15, 55, 192, 14, 15, 253, 195, 14, 15, 247, 135, 14, + 15, 253, 212, 14, 15, 252, 221, 14, 15, 87, 14, 15, 249, 2, 14, 15, 240, + 44, 249, 2, 14, 15, 55, 248, 149, 14, 15, 55, 253, 201, 14, 15, 253, 126, + 14, 15, 249, 172, 14, 15, 249, 8, 14, 15, 106, 249, 8, 14, 15, 249, 189, + 14, 15, 106, 249, 189, 14, 15, 244, 42, 14, 15, 106, 244, 42, 14, 15, + 111, 14, 15, 106, 111, 14, 15, 244, 43, 14, 15, 106, 244, 43, 14, 15, + 249, 7, 14, 15, 106, 249, 7, 14, 15, 243, 132, 14, 15, 106, 243, 132, 14, + 15, 238, 66, 243, 132, 14, 15, 214, 14, 15, 249, 186, 14, 15, 249, 187, + 14, 15, 249, 6, 14, 15, 248, 71, 14, 15, 253, 172, 14, 15, 246, 4, 14, + 15, 253, 215, 14, 15, 251, 150, 14, 15, 253, 190, 14, 15, 249, 98, 14, + 15, 240, 44, 249, 98, 14, 15, 201, 14, 15, 249, 90, 14, 15, 248, 222, 14, + 15, 106, 248, 222, 14, 15, 248, 223, 14, 15, 106, 248, 223, 14, 15, 243, + 211, 14, 15, 106, 243, 211, 14, 15, 249, 100, 14, 15, 106, 249, 100, 14, + 15, 243, 212, 14, 15, 106, 243, 212, 14, 15, 248, 221, 14, 15, 106, 248, + 221, 14, 15, 243, 65, 14, 15, 106, 243, 65, 14, 15, 238, 66, 243, 65, 14, + 15, 255, 15, 14, 15, 254, 108, 14, 15, 232, 86, 248, 218, 14, 15, 232, + 86, 251, 149, 14, 15, 232, 86, 251, 158, 14, 15, 232, 86, 251, 136, 14, + 15, 254, 54, 14, 15, 244, 239, 14, 15, 254, 55, 14, 15, 250, 162, 14, 15, + 253, 224, 14, 15, 249, 42, 14, 15, 240, 44, 249, 42, 14, 15, 253, 152, + 14, 15, 249, 37, 14, 15, 249, 44, 14, 15, 106, 249, 44, 14, 15, 249, 45, + 14, 15, 106, 249, 45, 14, 15, 243, 159, 14, 15, 106, 243, 159, 14, 15, + 249, 46, 14, 15, 106, 249, 46, 14, 15, 243, 160, 14, 15, 106, 243, 160, + 14, 15, 248, 203, 14, 15, 106, 248, 203, 14, 15, 243, 91, 14, 15, 106, + 243, 91, 14, 15, 238, 66, 243, 91, 14, 15, 255, 18, 14, 15, 240, 36, 254, + 46, 14, 15, 253, 206, 14, 15, 246, 61, 14, 15, 253, 180, 14, 15, 251, + 232, 14, 15, 253, 181, 14, 15, 249, 112, 14, 15, 240, 44, 249, 112, 14, + 15, 222, 14, 15, 249, 110, 14, 15, 248, 229, 14, 15, 106, 248, 229, 14, + 15, 248, 230, 14, 15, 106, 248, 230, 14, 15, 243, 228, 14, 15, 106, 243, + 228, 14, 15, 249, 117, 14, 15, 106, 249, 117, 14, 15, 243, 229, 14, 15, + 106, 243, 229, 14, 15, 248, 169, 14, 15, 106, 248, 169, 14, 15, 243, 109, + 14, 15, 106, 243, 109, 14, 15, 238, 66, 243, 109, 14, 15, 173, 14, 15, + 106, 173, 14, 15, 254, 203, 14, 15, 234, 47, 173, 14, 15, 240, 36, 173, + 14, 15, 253, 197, 14, 15, 246, 102, 14, 15, 253, 166, 14, 15, 252, 22, + 14, 15, 253, 173, 14, 15, 249, 121, 14, 15, 240, 44, 249, 121, 14, 15, + 253, 131, 14, 15, 248, 231, 14, 15, 249, 124, 14, 15, 106, 249, 124, 14, + 15, 248, 176, 14, 15, 106, 248, 176, 14, 15, 243, 110, 14, 15, 106, 243, + 110, 14, 15, 238, 66, 243, 110, 14, 15, 197, 14, 15, 55, 254, 26, 14, 15, + 254, 214, 14, 15, 253, 250, 14, 15, 246, 33, 14, 15, 253, 251, 14, 15, + 251, 196, 14, 15, 253, 216, 14, 15, 248, 226, 14, 15, 240, 44, 248, 226, + 14, 15, 253, 134, 14, 15, 249, 101, 14, 15, 249, 106, 14, 15, 106, 249, + 106, 14, 15, 249, 107, 14, 15, 106, 249, 107, 14, 15, 243, 220, 14, 15, + 106, 243, 220, 14, 15, 249, 108, 14, 15, 106, 249, 108, 14, 15, 243, 221, + 14, 15, 106, 243, 221, 14, 15, 248, 227, 14, 15, 106, 248, 227, 14, 15, + 243, 219, 14, 15, 106, 243, 219, 14, 15, 162, 14, 15, 106, 162, 14, 15, + 113, 162, 14, 15, 253, 210, 14, 15, 247, 60, 14, 15, 253, 198, 14, 15, + 252, 177, 14, 15, 253, 186, 14, 15, 249, 166, 14, 15, 240, 44, 249, 166, + 14, 15, 253, 132, 14, 15, 249, 158, 14, 15, 249, 169, 14, 15, 106, 249, + 169, 14, 15, 249, 170, 14, 15, 106, 249, 170, 14, 15, 244, 26, 14, 15, + 106, 244, 26, 14, 15, 249, 171, 14, 15, 106, 249, 171, 14, 15, 244, 27, + 14, 15, 106, 244, 27, 14, 15, 248, 252, 14, 15, 106, 248, 252, 14, 15, + 243, 125, 14, 15, 106, 243, 125, 14, 15, 238, 66, 243, 125, 14, 15, 193, + 14, 15, 234, 47, 193, 14, 15, 254, 128, 14, 15, 235, 57, 193, 14, 15, + 234, 225, 254, 238, 14, 15, 238, 66, 252, 181, 14, 15, 238, 66, 252, 164, + 14, 15, 238, 66, 247, 98, 14, 15, 238, 66, 247, 124, 14, 15, 238, 66, + 247, 93, 14, 15, 238, 66, 247, 66, 14, 15, 248, 118, 14, 15, 248, 185, + 14, 15, 247, 73, 14, 15, 248, 110, 14, 15, 247, 76, 14, 15, 248, 46, 14, + 15, 244, 7, 14, 15, 244, 16, 14, 15, 106, 244, 16, 14, 15, 244, 17, 14, + 15, 106, 244, 17, 14, 15, 240, 230, 14, 15, 106, 240, 230, 14, 15, 244, + 18, 14, 15, 106, 244, 18, 14, 15, 240, 231, 14, 15, 106, 240, 231, 14, + 15, 243, 121, 14, 15, 106, 243, 121, 14, 15, 240, 229, 14, 15, 106, 240, + 229, 14, 15, 254, 72, 14, 15, 253, 254, 14, 15, 247, 212, 14, 15, 253, + 189, 14, 15, 253, 81, 14, 15, 253, 162, 14, 15, 249, 210, 14, 15, 240, + 44, 249, 210, 14, 15, 216, 14, 15, 248, 191, 14, 15, 249, 213, 14, 15, + 106, 249, 213, 14, 15, 249, 214, 14, 15, 106, 249, 214, 14, 15, 244, 61, + 14, 15, 106, 244, 61, 14, 15, 249, 215, 14, 15, 106, 249, 215, 14, 15, + 244, 62, 14, 15, 106, 244, 62, 14, 15, 249, 212, 14, 15, 106, 249, 212, + 14, 15, 243, 137, 14, 15, 106, 243, 137, 14, 15, 238, 66, 243, 137, 14, + 15, 255, 14, 14, 15, 234, 98, 255, 14, 14, 15, 106, 255, 14, 14, 15, 240, + 36, 253, 189, 14, 15, 253, 194, 14, 15, 242, 74, 253, 194, 14, 15, 106, + 253, 250, 14, 15, 247, 26, 14, 15, 253, 209, 14, 15, 252, 137, 14, 15, + 253, 160, 14, 15, 252, 143, 14, 15, 106, 253, 216, 14, 15, 253, 130, 14, + 15, 248, 182, 14, 15, 106, 253, 134, 14, 15, 244, 2, 14, 15, 106, 244, 2, + 14, 15, 144, 14, 15, 106, 144, 14, 15, 113, 144, 14, 15, 254, 62, 14, 15, + 245, 88, 14, 15, 253, 245, 14, 15, 250, 243, 14, 15, 254, 63, 14, 15, + 250, 249, 14, 15, 253, 179, 14, 15, 249, 60, 14, 15, 243, 177, 14, 15, + 106, 243, 177, 14, 15, 255, 19, 14, 15, 248, 111, 14, 15, 240, 141, 248, + 111, 14, 15, 248, 121, 14, 15, 240, 141, 248, 121, 14, 15, 243, 128, 14, + 15, 240, 141, 243, 128, 14, 15, 248, 97, 14, 15, 244, 30, 14, 15, 248, + 55, 14, 15, 243, 76, 14, 15, 240, 244, 14, 15, 106, 240, 244, 14, 15, + 254, 46, 14, 15, 247, 166, 14, 15, 247, 167, 14, 15, 243, 131, 14, 15, + 242, 247, 14, 15, 252, 231, 14, 15, 252, 239, 14, 15, 252, 240, 14, 15, + 252, 241, 14, 15, 252, 238, 14, 15, 238, 86, 253, 168, 14, 15, 238, 86, + 253, 214, 14, 15, 238, 86, 251, 61, 14, 15, 238, 86, 253, 184, 14, 15, + 238, 86, 251, 78, 14, 15, 238, 86, 219, 14, 15, 238, 86, 248, 114, 14, + 15, 238, 86, 192, 14, 15, 239, 148, 192, 14, 15, 254, 172, 14, 15, 247, + 5, 14, 15, 254, 28, 14, 15, 249, 147, 14, 15, 254, 45, 14, 15, 252, 100, + 14, 15, 253, 217, 14, 15, 248, 241, 14, 15, 255, 20, 14, 15, 244, 34, 14, + 15, 244, 35, 14, 15, 244, 36, 14, 15, 244, 33, 14, 15, 106, 253, 194, 14, + 15, 106, 253, 209, 14, 15, 106, 253, 160, 14, 15, 106, 253, 130, 14, 15, + 242, 5, 14, 15, 248, 232, 14, 15, 246, 147, 14, 15, 248, 172, 14, 15, + 246, 149, 14, 15, 248, 50, 14, 15, 246, 139, 14, 15, 254, 26, 14, 15, + 252, 30, 14, 15, 240, 36, 248, 118, 14, 15, 240, 36, 248, 185, 14, 15, + 240, 36, 248, 110, 14, 15, 240, 36, 248, 46, 14, 15, 234, 24, 248, 111, + 14, 15, 234, 24, 248, 121, 14, 15, 234, 24, 248, 97, 14, 15, 234, 24, + 248, 55, 14, 15, 234, 24, 254, 46, 14, 15, 249, 103, 14, 15, 246, 46, 14, + 15, 249, 104, 14, 15, 246, 47, 14, 15, 248, 225, 14, 15, 246, 44, 14, 15, + 254, 193, 14, 15, 238, 88, 248, 111, 14, 15, 238, 88, 248, 121, 14, 15, + 238, 88, 243, 128, 14, 15, 238, 88, 248, 97, 14, 15, 238, 88, 244, 30, + 14, 15, 238, 88, 248, 55, 14, 15, 238, 88, 243, 76, 14, 15, 238, 88, 254, + 46, 14, 15, 238, 241, 217, 14, 15, 235, 57, 72, 14, 15, 235, 57, 71, 14, + 15, 235, 57, 73, 14, 15, 235, 57, 67, 14, 15, 235, 57, 253, 170, 14, 15, + 235, 57, 253, 187, 14, 15, 235, 57, 253, 177, 14, 15, 235, 57, 253, 138, + 14, 15, 235, 57, 253, 197, 14, 15, 235, 57, 253, 166, 14, 15, 235, 57, + 253, 173, 14, 15, 235, 57, 253, 131, 14, 15, 235, 57, 253, 172, 14, 15, + 235, 57, 253, 215, 14, 15, 235, 57, 253, 190, 14, 15, 235, 57, 201, 14, + 15, 240, 36, 253, 168, 14, 15, 240, 36, 253, 214, 14, 15, 240, 36, 253, + 184, 14, 15, 240, 36, 219, 14, 15, 55, 251, 19, 14, 15, 55, 249, 75, 14, + 15, 55, 248, 127, 14, 15, 55, 245, 119, 14, 15, 55, 251, 18, 14, 15, 55, + 248, 77, 14, 15, 55, 253, 185, 14, 15, 55, 253, 160, 14, 15, 55, 253, + 194, 14, 15, 55, 249, 153, 14, 15, 55, 253, 209, 14, 15, 55, 253, 130, + 14, 15, 55, 254, 14, 14, 15, 55, 253, 177, 14, 15, 55, 253, 170, 14, 15, + 55, 249, 199, 14, 15, 55, 253, 187, 14, 15, 55, 253, 138, 14, 15, 55, + 251, 88, 14, 15, 55, 251, 87, 14, 15, 55, 251, 85, 14, 15, 55, 245, 208, + 14, 15, 55, 251, 86, 14, 15, 55, 251, 84, 14, 15, 55, 249, 177, 14, 15, + 55, 248, 97, 14, 15, 55, 248, 111, 14, 15, 55, 243, 77, 14, 15, 55, 248, + 121, 14, 15, 55, 248, 55, 14, 15, 55, 252, 232, 14, 15, 55, 249, 6, 14, + 15, 55, 249, 186, 14, 15, 55, 247, 164, 14, 15, 55, 249, 187, 14, 15, 55, + 248, 71, 14, 15, 55, 253, 239, 14, 15, 55, 253, 208, 14, 15, 55, 253, + 175, 14, 15, 55, 248, 180, 14, 15, 55, 253, 147, 14, 15, 55, 253, 129, + 14, 15, 55, 223, 14, 15, 55, 253, 235, 14, 15, 55, 253, 234, 14, 15, 55, + 254, 5, 14, 15, 55, 249, 68, 14, 15, 55, 254, 6, 14, 15, 55, 253, 139, + 14, 15, 55, 251, 146, 14, 15, 55, 248, 220, 14, 15, 55, 249, 94, 14, 15, + 55, 246, 11, 14, 15, 55, 248, 219, 14, 15, 55, 248, 61, 14, 15, 55, 251, + 156, 14, 15, 55, 251, 155, 14, 15, 55, 251, 153, 14, 15, 55, 246, 17, 14, + 15, 55, 251, 154, 14, 15, 55, 249, 97, 14, 15, 55, 254, 107, 14, 15, 55, + 253, 150, 14, 15, 55, 253, 173, 14, 15, 55, 253, 197, 14, 15, 55, 249, + 118, 14, 15, 55, 253, 166, 14, 15, 55, 253, 131, 14, 15, 55, 253, 154, + 14, 15, 55, 253, 181, 14, 15, 55, 253, 206, 14, 15, 55, 249, 111, 14, 15, + 55, 253, 180, 14, 15, 55, 222, 14, 15, 55, 253, 161, 14, 15, 55, 253, + 162, 14, 15, 55, 253, 254, 14, 15, 55, 248, 192, 14, 15, 55, 253, 189, + 14, 15, 55, 216, 14, 15, 55, 254, 25, 14, 15, 240, 36, 254, 25, 14, 15, + 55, 253, 248, 14, 15, 55, 254, 24, 14, 15, 55, 248, 161, 14, 15, 55, 254, + 7, 14, 15, 240, 36, 254, 7, 14, 15, 55, 253, 146, 14, 15, 55, 249, 88, + 14, 15, 55, 249, 87, 14, 15, 55, 251, 121, 14, 15, 55, 245, 238, 14, 15, + 55, 249, 86, 14, 15, 55, 251, 120, 14, 15, 55, 254, 8, 14, 15, 55, 253, + 216, 14, 15, 55, 253, 250, 14, 15, 55, 249, 102, 14, 15, 55, 253, 251, + 14, 15, 55, 253, 134, 14, 15, 55, 250, 201, 14, 15, 55, 250, 200, 14, 15, + 55, 250, 198, 14, 15, 55, 245, 70, 14, 15, 55, 250, 199, 14, 15, 55, 249, + 55, 14, 15, 55, 251, 194, 14, 15, 55, 249, 104, 14, 15, 55, 251, 193, 14, + 15, 55, 246, 45, 14, 15, 55, 249, 103, 14, 15, 55, 248, 225, 14, 15, 55, + 247, 155, 14, 15, 55, 244, 36, 14, 15, 55, 244, 34, 14, 15, 55, 242, 155, + 14, 15, 55, 244, 35, 14, 15, 55, 244, 33, 14, 15, 55, 249, 183, 14, 15, + 55, 249, 182, 14, 15, 55, 249, 180, 14, 15, 55, 247, 154, 14, 15, 55, + 249, 181, 14, 15, 55, 249, 179, 14, 15, 55, 254, 18, 14, 15, 55, 253, + 222, 14, 15, 55, 253, 228, 14, 15, 55, 248, 194, 14, 15, 55, 254, 17, 14, + 15, 55, 253, 163, 14, 15, 55, 255, 17, 14, 15, 55, 54, 255, 17, 14, 15, + 55, 250, 220, 14, 15, 55, 250, 219, 14, 15, 55, 248, 126, 14, 15, 55, + 245, 78, 14, 15, 55, 250, 218, 14, 15, 55, 248, 153, 14, 15, 55, 253, + 211, 14, 15, 55, 253, 186, 14, 15, 55, 253, 210, 14, 15, 55, 248, 184, + 14, 15, 55, 253, 198, 14, 15, 55, 253, 132, 14, 15, 55, 248, 248, 14, 15, + 55, 248, 110, 14, 15, 55, 248, 118, 14, 15, 55, 244, 9, 14, 15, 55, 248, + 185, 14, 15, 55, 248, 46, 14, 15, 55, 254, 72, 14, 15, 55, 249, 5, 14, + 15, 55, 249, 4, 14, 15, 55, 248, 112, 14, 15, 55, 244, 39, 14, 15, 55, + 248, 140, 14, 15, 55, 248, 90, 14, 15, 55, 248, 200, 14, 15, 55, 248, + 125, 14, 15, 55, 248, 88, 14, 15, 55, 243, 54, 14, 15, 55, 248, 67, 14, + 15, 55, 248, 57, 14, 15, 55, 247, 172, 14, 15, 55, 247, 171, 14, 15, 55, + 247, 169, 14, 15, 55, 242, 160, 14, 15, 55, 247, 170, 14, 15, 55, 247, + 168, 14, 15, 254, 83, 52, 14, 15, 248, 37, 208, 14, 15, 249, 146, 14, 15, + 246, 140, 14, 15, 246, 173, 14, 15, 242, 20, 14, 15, 246, 174, 14, 15, + 242, 21, 14, 15, 246, 172, 14, 15, 242, 19, 242, 221, 247, 96, 69, 242, + 221, 1, 241, 29, 242, 221, 1, 246, 55, 242, 221, 1, 241, 104, 242, 221, + 1, 247, 62, 242, 221, 1, 246, 156, 242, 221, 1, 247, 182, 242, 221, 1, + 245, 33, 242, 221, 1, 242, 153, 242, 221, 1, 245, 26, 242, 221, 1, 241, + 48, 242, 221, 1, 246, 94, 242, 221, 1, 245, 126, 242, 221, 1, 237, 220, + 242, 221, 1, 239, 205, 242, 221, 1, 247, 52, 242, 221, 1, 244, 72, 242, + 221, 1, 249, 130, 242, 221, 1, 254, 253, 242, 221, 1, 237, 144, 242, 221, + 1, 237, 182, 242, 221, 1, 237, 143, 242, 221, 1, 253, 227, 242, 221, 1, + 236, 134, 242, 221, 1, 245, 225, 242, 221, 1, 232, 163, 242, 221, 1, 242, + 54, 242, 221, 238, 184, 69, 242, 221, 224, 238, 184, 69, 119, 1, 250, + 238, 250, 240, 255, 74, 255, 19, 119, 1, 179, 119, 1, 253, 4, 255, 95, + 79, 119, 1, 254, 135, 119, 1, 255, 14, 119, 1, 255, 16, 119, 1, 238, 28, + 247, 146, 240, 149, 119, 1, 248, 109, 119, 1, 244, 82, 67, 119, 1, 255, + 86, 73, 119, 1, 255, 67, 67, 119, 1, 244, 69, 119, 1, 231, 23, 73, 119, + 1, 231, 77, 73, 119, 1, 73, 119, 1, 253, 193, 119, 1, 254, 9, 119, 1, + 247, 27, 254, 71, 252, 132, 144, 119, 1, 241, 195, 119, 1, 250, 155, 119, + 1, 251, 139, 255, 15, 119, 1, 210, 119, 1, 248, 108, 119, 1, 251, 13, + 251, 41, 210, 119, 1, 251, 9, 119, 1, 247, 198, 253, 40, 255, 16, 119, 1, + 241, 145, 192, 119, 1, 245, 138, 192, 119, 1, 226, 249, 192, 119, 1, 227, + 6, 192, 119, 1, 241, 253, 254, 218, 252, 0, 197, 119, 1, 231, 29, 197, + 119, 1, 236, 7, 119, 1, 251, 108, 255, 77, 254, 178, 71, 119, 1, 72, 119, + 1, 245, 234, 221, 119, 1, 251, 14, 119, 1, 231, 72, 253, 178, 119, 1, + 232, 54, 67, 119, 1, 251, 109, 250, 226, 119, 1, 242, 57, 242, 56, 223, + 119, 1, 244, 76, 241, 97, 119, 1, 242, 122, 193, 119, 1, 247, 89, 231, + 24, 193, 119, 1, 231, 78, 193, 119, 1, 255, 18, 119, 1, 255, 17, 119, 1, + 247, 153, 254, 249, 254, 251, 214, 119, 1, 231, 79, 214, 119, 1, 209, + 119, 1, 237, 76, 244, 218, 239, 10, 217, 119, 1, 226, 252, 217, 119, 1, + 236, 8, 119, 1, 239, 152, 119, 1, 245, 80, 255, 72, 72, 119, 1, 241, 227, + 254, 111, 173, 119, 1, 229, 49, 173, 119, 1, 231, 28, 173, 119, 1, 241, + 213, 251, 181, 251, 204, 162, 119, 1, 236, 6, 119, 1, 239, 98, 119, 1, + 251, 104, 119, 1, 245, 31, 250, 179, 209, 119, 1, 239, 155, 245, 85, 73, + 119, 1, 248, 206, 119, 1, 251, 106, 119, 1, 237, 98, 119, 1, 244, 240, + 119, 1, 241, 47, 119, 1, 247, 120, 119, 1, 231, 25, 119, 1, 231, 80, 119, + 1, 231, 141, 119, 1, 255, 20, 119, 1, 206, 119, 240, 12, 232, 75, 119, + 237, 215, 232, 75, 119, 243, 38, 232, 75, 119, 241, 16, 91, 119, 238, 34, + 91, 119, 237, 75, 91, 238, 63, 1, 67, 238, 63, 1, 71, 238, 63, 1, 79, + 238, 63, 1, 201, 238, 63, 1, 253, 139, 238, 63, 1, 248, 50, 238, 63, 1, + 253, 126, 238, 63, 1, 253, 133, 238, 63, 1, 253, 131, 238, 63, 1, 253, + 129, 238, 63, 1, 253, 141, 238, 63, 1, 222, 238, 63, 1, 216, 238, 63, 1, + 253, 134, 238, 63, 1, 253, 138, 238, 63, 1, 253, 132, 238, 63, 1, 219, + 238, 63, 33, 21, 71, 238, 63, 33, 21, 79, 238, 63, 21, 238, 72, 238, 60, + 1, 67, 238, 60, 1, 71, 238, 60, 1, 79, 238, 60, 1, 201, 238, 60, 1, 253, + 139, 238, 60, 1, 248, 50, 238, 60, 1, 253, 126, 238, 60, 1, 253, 133, + 238, 60, 1, 253, 131, 238, 60, 1, 253, 129, 238, 60, 1, 253, 141, 238, + 60, 1, 222, 238, 60, 1, 216, 238, 60, 1, 253, 130, 238, 60, 1, 253, 134, + 238, 60, 1, 253, 138, 238, 60, 1, 253, 132, 238, 60, 1, 219, 238, 60, 33, + 21, 71, 238, 60, 33, 21, 79, 238, 60, 21, 236, 70, 234, 63, 240, 12, 232, + 75, 234, 63, 45, 232, 75, 242, 231, 1, 67, 242, 231, 1, 71, 242, 231, 1, + 79, 242, 231, 1, 201, 242, 231, 1, 253, 139, 242, 231, 1, 248, 50, 242, + 231, 1, 253, 126, 242, 231, 1, 253, 133, 242, 231, 1, 253, 131, 242, 231, + 1, 253, 129, 242, 231, 1, 253, 141, 242, 231, 1, 222, 242, 231, 1, 216, + 242, 231, 1, 253, 130, 242, 231, 1, 253, 134, 242, 231, 1, 253, 138, 242, + 231, 1, 253, 132, 242, 231, 1, 219, 242, 231, 33, 21, 71, 242, 231, 33, + 21, 79, 236, 157, 1, 67, 236, 157, 1, 71, 236, 157, 1, 79, 236, 157, 1, + 201, 236, 157, 1, 253, 139, 236, 157, 1, 248, 50, 236, 157, 1, 253, 126, + 236, 157, 1, 253, 133, 236, 157, 1, 253, 131, 236, 157, 1, 253, 129, 236, + 157, 1, 253, 141, 236, 157, 1, 222, 236, 157, 1, 216, 236, 157, 1, 253, + 134, 236, 157, 1, 253, 138, 236, 157, 1, 253, 132, 236, 157, 33, 21, 71, + 236, 157, 33, 21, 79, 63, 1, 201, 63, 1, 248, 61, 63, 1, 253, 190, 63, 1, + 248, 220, 63, 1, 248, 172, 63, 1, 253, 152, 63, 1, 248, 57, 63, 1, 253, + 224, 63, 1, 248, 125, 63, 1, 248, 133, 63, 1, 253, 133, 63, 1, 242, 247, + 63, 1, 253, 225, 63, 1, 243, 131, 63, 1, 252, 31, 63, 1, 253, 126, 63, 1, + 248, 55, 63, 1, 87, 63, 1, 248, 97, 63, 1, 253, 173, 63, 1, 253, 141, 63, + 1, 248, 65, 63, 1, 253, 208, 63, 1, 248, 238, 63, 1, 253, 181, 63, 1, + 253, 162, 63, 1, 253, 160, 63, 1, 253, 216, 63, 1, 254, 13, 63, 1, 248, + 46, 63, 1, 248, 250, 63, 1, 253, 132, 63, 1, 219, 63, 1, 253, 134, 63, 1, + 253, 217, 63, 233, 52, 33, 252, 86, 63, 233, 52, 33, 248, 241, 63, 233, + 52, 33, 254, 28, 63, 233, 52, 33, 249, 147, 63, 233, 52, 33, 254, 29, 63, + 233, 52, 33, 252, 106, 63, 233, 52, 33, 249, 150, 63, 233, 52, 33, 247, + 20, 63, 233, 52, 33, 254, 125, 63, 233, 52, 33, 252, 163, 63, 233, 52, + 33, 254, 110, 63, 233, 52, 33, 251, 217, 63, 233, 52, 33, 254, 70, 63, + 233, 52, 33, 249, 146, 63, 233, 52, 33, 254, 123, 249, 9, 127, 63, 233, + 52, 33, 254, 123, 249, 9, 111, 63, 233, 52, 33, 252, 87, 63, 33, 237, 13, + 254, 142, 63, 33, 237, 13, 253, 140, 63, 33, 21, 253, 140, 63, 33, 21, + 71, 63, 33, 21, 253, 142, 63, 33, 21, 255, 14, 63, 33, 21, 254, 77, 63, + 33, 21, 79, 63, 33, 21, 253, 148, 63, 33, 21, 254, 74, 63, 33, 21, 253, + 193, 63, 33, 21, 216, 63, 33, 21, 253, 237, 63, 33, 21, 72, 63, 33, 21, + 253, 178, 63, 33, 21, 253, 149, 63, 33, 21, 253, 156, 63, 33, 21, 253, + 151, 63, 21, 237, 221, 63, 21, 237, 248, 63, 21, 231, 84, 63, 21, 232, + 184, 63, 21, 238, 32, 63, 21, 239, 3, 63, 21, 242, 86, 63, 21, 233, 43, + 63, 21, 237, 186, 63, 21, 241, 7, 63, 21, 242, 96, 239, 179, 63, 21, 239, + 243, 63, 21, 241, 62, 63, 21, 233, 121, 63, 21, 246, 10, 63, 21, 233, + 120, 63, 21, 241, 42, 254, 69, 246, 24, 63, 21, 253, 204, 249, 2, 63, 21, + 239, 8, 63, 21, 242, 59, 246, 93, 63, 21, 237, 191, 63, 236, 181, 12, + 247, 31, 63, 21, 231, 59, 63, 21, 235, 176, 63, 26, 242, 217, 63, 26, + 127, 63, 26, 111, 63, 26, 166, 63, 26, 177, 63, 26, 176, 63, 26, 187, 63, + 26, 203, 63, 26, 195, 63, 26, 202, 63, 12, 253, 204, 243, 4, 252, 184, + 63, 12, 253, 204, 243, 4, 246, 99, 63, 12, 253, 204, 243, 4, 249, 138, + 63, 12, 253, 204, 243, 4, 250, 113, 63, 12, 253, 204, 243, 4, 244, 233, + 63, 12, 253, 204, 243, 4, 246, 253, 63, 12, 253, 204, 243, 4, 234, 239, + 63, 12, 253, 204, 243, 4, 236, 79, 63, 12, 253, 204, 243, 4, 236, 78, 63, + 12, 253, 204, 243, 4, 234, 238, 58, 241, 31, 58, 235, 69, 58, 240, 27, + 58, 248, 37, 208, 58, 240, 24, 58, 248, 58, 243, 5, 58, 248, 47, 248, + 186, 238, 93, 58, 248, 54, 4, 237, 78, 238, 95, 58, 240, 14, 240, 27, 58, + 240, 14, 248, 37, 208, 58, 239, 144, 58, 248, 210, 34, 236, 239, 127, 58, + 248, 210, 34, 236, 239, 111, 58, 248, 210, 34, 236, 239, 166, 58, 33, + 234, 6, 58, 26, 242, 217, 58, 26, 127, 58, 26, 111, 58, 26, 166, 58, 26, + 177, 58, 26, 176, 58, 26, 187, 58, 26, 203, 58, 26, 195, 58, 26, 202, 58, + 1, 67, 58, 1, 72, 58, 1, 71, 58, 1, 73, 58, 1, 79, 58, 1, 253, 193, 58, + 1, 253, 252, 58, 1, 253, 164, 58, 1, 253, 131, 58, 1, 248, 124, 58, 1, + 253, 141, 58, 1, 253, 129, 58, 1, 253, 217, 58, 1, 253, 139, 58, 1, 222, + 58, 1, 253, 134, 58, 1, 253, 132, 58, 1, 248, 46, 58, 1, 253, 126, 58, 1, + 253, 133, 58, 1, 248, 57, 58, 1, 253, 146, 58, 1, 216, 58, 1, 253, 130, + 58, 1, 253, 138, 58, 1, 253, 179, 58, 1, 201, 58, 1, 248, 61, 58, 1, 248, + 90, 58, 1, 253, 163, 58, 1, 248, 114, 58, 1, 253, 113, 58, 1, 248, 225, + 58, 1, 249, 217, 58, 1, 248, 67, 58, 1, 248, 47, 183, 33, 52, 58, 1, 248, + 47, 72, 58, 1, 248, 47, 71, 58, 1, 248, 47, 73, 58, 1, 248, 47, 79, 58, + 1, 248, 47, 253, 193, 58, 1, 248, 47, 253, 252, 58, 1, 248, 47, 248, 124, + 58, 1, 248, 47, 253, 141, 58, 1, 248, 47, 253, 129, 58, 1, 248, 47, 253, + 217, 58, 1, 248, 47, 253, 139, 58, 1, 248, 47, 222, 58, 1, 248, 47, 253, + 126, 58, 1, 248, 47, 253, 133, 58, 1, 248, 47, 248, 57, 58, 1, 248, 47, + 253, 146, 58, 1, 248, 47, 248, 90, 58, 1, 248, 47, 216, 58, 1, 248, 47, + 253, 138, 58, 1, 248, 47, 201, 58, 1, 248, 47, 248, 211, 58, 1, 248, 47, + 248, 114, 58, 1, 248, 47, 251, 115, 58, 1, 248, 47, 252, 20, 58, 1, 248, + 47, 248, 153, 58, 1, 248, 54, 72, 58, 1, 248, 54, 71, 58, 1, 248, 54, + 254, 102, 58, 1, 248, 54, 253, 252, 58, 1, 248, 54, 79, 58, 1, 248, 54, + 248, 124, 58, 1, 248, 54, 201, 58, 1, 248, 54, 253, 139, 58, 1, 248, 54, + 219, 58, 1, 248, 54, 253, 129, 58, 1, 248, 54, 248, 46, 58, 1, 248, 54, + 253, 126, 58, 1, 248, 54, 253, 133, 58, 1, 248, 54, 253, 146, 58, 1, 248, + 54, 253, 179, 58, 1, 248, 54, 248, 211, 58, 1, 248, 54, 248, 114, 58, 1, + 248, 54, 248, 90, 58, 1, 248, 54, 253, 163, 58, 1, 248, 54, 248, 182, 58, + 1, 248, 54, 248, 57, 58, 1, 248, 54, 248, 99, 58, 1, 240, 14, 71, 58, 1, + 240, 14, 201, 58, 1, 240, 14, 253, 130, 58, 1, 240, 14, 253, 179, 58, 1, + 240, 14, 248, 99, 58, 1, 253, 128, 248, 36, 237, 62, 127, 58, 1, 253, + 128, 248, 36, 239, 244, 127, 58, 1, 253, 128, 248, 36, 239, 36, 58, 1, + 253, 128, 248, 36, 237, 50, 58, 1, 253, 128, 248, 36, 236, 145, 237, 50, + 58, 1, 253, 128, 248, 36, 238, 163, 58, 1, 253, 128, 248, 36, 204, 238, + 163, 58, 1, 253, 128, 248, 36, 67, 58, 1, 253, 128, 248, 36, 71, 58, 1, + 253, 128, 248, 36, 201, 58, 1, 253, 128, 248, 36, 248, 50, 58, 1, 253, + 128, 248, 36, 253, 152, 58, 1, 253, 128, 248, 36, 248, 71, 58, 1, 253, + 128, 248, 36, 242, 247, 58, 1, 253, 128, 248, 36, 248, 75, 58, 1, 253, + 128, 248, 36, 248, 82, 58, 1, 253, 128, 248, 36, 253, 126, 58, 1, 253, + 128, 248, 36, 253, 133, 58, 1, 253, 128, 248, 36, 253, 129, 58, 1, 253, + 128, 248, 36, 248, 65, 58, 1, 253, 128, 248, 36, 248, 66, 58, 1, 253, + 128, 248, 36, 248, 99, 58, 1, 253, 128, 248, 36, 253, 163, 58, 1, 253, + 128, 248, 36, 254, 0, 58, 1, 248, 47, 253, 128, 248, 36, 253, 126, 58, 1, + 248, 47, 253, 128, 248, 36, 248, 99, 58, 1, 240, 14, 253, 128, 248, 36, + 248, 77, 58, 1, 240, 14, 253, 128, 248, 36, 248, 50, 58, 1, 240, 14, 253, + 128, 248, 36, 253, 152, 58, 1, 240, 14, 253, 128, 248, 36, 248, 89, 58, + 1, 240, 14, 253, 128, 248, 36, 248, 71, 58, 1, 240, 14, 253, 128, 248, + 36, 242, 249, 58, 1, 240, 14, 253, 128, 248, 36, 253, 126, 58, 1, 240, + 14, 253, 128, 248, 36, 248, 76, 58, 1, 240, 14, 253, 128, 248, 36, 248, + 66, 58, 1, 240, 14, 253, 128, 248, 36, 250, 174, 58, 1, 240, 14, 253, + 128, 248, 36, 248, 99, 58, 1, 240, 14, 253, 128, 248, 36, 253, 163, 58, + 1, 253, 128, 248, 36, 137, 79, 58, 1, 253, 128, 248, 36, 137, 216, 58, 1, + 240, 14, 253, 128, 248, 36, 248, 81, 58, 1, 253, 128, 248, 36, 237, 101, + 149, 232, 65, 239, 117, 149, 1, 201, 149, 1, 248, 61, 149, 1, 253, 139, + 149, 1, 248, 77, 149, 1, 248, 50, 149, 1, 253, 152, 149, 1, 248, 57, 149, + 1, 253, 146, 149, 1, 248, 89, 149, 1, 249, 203, 149, 1, 253, 126, 149, 1, + 248, 55, 149, 1, 253, 133, 149, 1, 248, 76, 149, 1, 253, 131, 149, 1, + 253, 129, 149, 1, 248, 65, 149, 1, 253, 141, 149, 1, 248, 81, 149, 1, + 222, 149, 1, 216, 149, 1, 253, 130, 149, 1, 253, 134, 149, 1, 253, 138, + 149, 1, 248, 46, 149, 1, 248, 66, 149, 1, 253, 132, 149, 1, 219, 149, 33, + 21, 67, 149, 33, 21, 71, 149, 33, 21, 79, 149, 33, 21, 253, 164, 149, 33, + 21, 253, 149, 149, 33, 21, 253, 156, 149, 33, 21, 253, 151, 149, 33, 21, + 72, 149, 33, 21, 73, 149, 213, 1, 216, 149, 213, 1, 253, 130, 149, 213, + 1, 253, 138, 149, 3, 1, 201, 149, 3, 1, 248, 50, 149, 3, 1, 235, 61, 149, + 3, 1, 253, 126, 149, 3, 1, 253, 131, 149, 3, 1, 253, 129, 149, 3, 1, 222, + 149, 3, 1, 253, 130, 149, 3, 1, 253, 134, 149, 21, 234, 226, 149, 21, + 234, 212, 149, 21, 247, 59, 149, 21, 248, 226, 149, 233, 54, 69, 149, + 236, 156, 69, 149, 26, 242, 217, 149, 26, 127, 149, 26, 111, 149, 26, + 166, 149, 26, 177, 149, 26, 176, 149, 26, 187, 149, 26, 203, 149, 26, + 195, 149, 26, 202, 81, 255, 21, 1, 201, 81, 255, 21, 1, 253, 253, 81, + 255, 21, 1, 248, 50, 81, 255, 21, 1, 248, 90, 81, 255, 21, 1, 253, 132, + 81, 255, 21, 1, 216, 81, 255, 21, 1, 253, 126, 81, 255, 21, 1, 248, 55, + 81, 255, 21, 1, 253, 134, 81, 255, 21, 1, 253, 129, 81, 255, 21, 1, 248, + 65, 81, 255, 21, 1, 222, 81, 255, 21, 1, 253, 179, 81, 255, 21, 1, 253, + 171, 81, 255, 21, 1, 219, 81, 255, 21, 1, 253, 217, 81, 255, 21, 1, 248, + 61, 81, 255, 21, 1, 243, 130, 81, 255, 21, 1, 253, 131, 81, 255, 21, 1, + 67, 81, 255, 21, 1, 71, 81, 255, 21, 1, 253, 164, 81, 255, 21, 1, 254, + 36, 81, 255, 21, 1, 79, 81, 255, 21, 1, 253, 156, 81, 255, 21, 1, 73, 81, + 255, 21, 1, 253, 252, 81, 255, 21, 1, 72, 81, 255, 21, 1, 249, 243, 81, + 255, 21, 1, 253, 149, 81, 255, 21, 1, 239, 223, 81, 255, 21, 1, 239, 224, + 81, 255, 21, 1, 239, 225, 81, 255, 21, 1, 239, 226, 81, 255, 21, 1, 239, + 227, 116, 81, 122, 1, 200, 253, 217, 116, 81, 122, 1, 170, 253, 217, 116, + 81, 122, 1, 200, 201, 116, 81, 122, 1, 200, 253, 253, 116, 81, 122, 1, + 200, 248, 50, 116, 81, 122, 1, 170, 201, 116, 81, 122, 1, 170, 253, 253, + 116, 81, 122, 1, 170, 248, 50, 116, 81, 122, 1, 200, 248, 90, 116, 81, + 122, 1, 200, 253, 132, 116, 81, 122, 1, 200, 216, 116, 81, 122, 1, 170, + 248, 90, 116, 81, 122, 1, 170, 253, 132, 116, 81, 122, 1, 170, 216, 116, + 81, 122, 1, 200, 253, 126, 116, 81, 122, 1, 200, 248, 55, 116, 81, 122, + 1, 200, 253, 131, 116, 81, 122, 1, 170, 253, 126, 116, 81, 122, 1, 170, + 248, 55, 116, 81, 122, 1, 170, 253, 131, 116, 81, 122, 1, 200, 253, 129, + 116, 81, 122, 1, 200, 248, 65, 116, 81, 122, 1, 200, 222, 116, 81, 122, + 1, 170, 253, 129, 116, 81, 122, 1, 170, 248, 65, 116, 81, 122, 1, 170, + 222, 116, 81, 122, 1, 200, 253, 179, 116, 81, 122, 1, 200, 253, 171, 116, + 81, 122, 1, 200, 253, 134, 116, 81, 122, 1, 170, 253, 179, 116, 81, 122, + 1, 170, 253, 171, 116, 81, 122, 1, 170, 253, 134, 116, 81, 122, 1, 200, + 219, 116, 81, 122, 1, 200, 253, 133, 116, 81, 122, 1, 200, 253, 141, 116, + 81, 122, 1, 170, 219, 116, 81, 122, 1, 170, 253, 133, 116, 81, 122, 1, + 170, 253, 141, 116, 81, 122, 1, 200, 249, 99, 116, 81, 122, 1, 200, 249, + 201, 116, 81, 122, 1, 170, 249, 99, 116, 81, 122, 1, 170, 249, 201, 116, + 81, 122, 33, 21, 33, 234, 255, 116, 81, 122, 33, 21, 253, 140, 116, 81, + 122, 33, 21, 253, 142, 116, 81, 122, 33, 21, 79, 116, 81, 122, 33, 21, + 253, 148, 116, 81, 122, 33, 21, 72, 116, 81, 122, 33, 21, 253, 178, 116, + 81, 122, 33, 21, 73, 116, 81, 122, 33, 21, 254, 117, 116, 81, 122, 33, + 21, 253, 252, 116, 81, 122, 33, 21, 254, 33, 116, 81, 122, 33, 21, 249, + 232, 116, 81, 122, 33, 21, 254, 254, 116, 81, 122, 33, 21, 254, 221, 116, + 81, 122, 33, 21, 252, 56, 116, 81, 122, 33, 21, 252, 250, 116, 81, 122, + 33, 21, 254, 102, 116, 81, 122, 1, 30, 179, 116, 81, 122, 1, 30, 254, 26, + 116, 81, 122, 1, 30, 197, 116, 81, 122, 1, 30, 173, 116, 81, 122, 1, 30, + 255, 15, 116, 81, 122, 1, 30, 209, 116, 81, 122, 1, 30, 217, 116, 81, + 122, 188, 238, 200, 116, 81, 122, 188, 238, 201, 116, 81, 122, 26, 242, + 217, 116, 81, 122, 26, 127, 116, 81, 122, 26, 111, 116, 81, 122, 26, 166, + 116, 81, 122, 26, 177, 116, 81, 122, 26, 176, 116, 81, 122, 26, 187, 116, + 81, 122, 26, 203, 116, 81, 122, 26, 195, 116, 81, 122, 26, 202, 116, 81, + 122, 21, 251, 180, 116, 81, 122, 21, 246, 36, 63, 12, 233, 223, 63, 12, + 249, 116, 242, 246, 63, 12, 254, 69, 242, 246, 63, 12, 254, 81, 242, 246, + 63, 12, 249, 34, 242, 246, 63, 12, 249, 141, 242, 246, 63, 12, 235, 137, + 242, 246, 63, 12, 237, 32, 242, 246, 63, 12, 237, 31, 242, 246, 63, 12, + 235, 136, 242, 246, 63, 12, 254, 86, 242, 246, 63, 12, 237, 3, 242, 246, + 63, 12, 238, 175, 242, 246, 63, 12, 238, 174, 242, 246, 63, 12, 237, 2, + 242, 246, 63, 12, 237, 4, 242, 246, 63, 12, 235, 38, 63, 12, 249, 116, + 248, 80, 63, 12, 254, 69, 248, 80, 63, 12, 254, 81, 248, 80, 63, 12, 249, + 34, 248, 80, 63, 12, 249, 141, 248, 80, 63, 12, 235, 137, 248, 80, 63, + 12, 237, 32, 248, 80, 63, 12, 237, 31, 248, 80, 63, 12, 235, 136, 248, + 80, 63, 12, 254, 86, 248, 80, 63, 12, 237, 3, 248, 80, 63, 12, 238, 175, + 248, 80, 63, 12, 238, 174, 248, 80, 63, 12, 237, 2, 248, 80, 63, 12, 237, + 4, 248, 80, 236, 148, 1, 201, 236, 148, 1, 253, 139, 236, 148, 1, 248, + 50, 236, 148, 1, 246, 148, 236, 148, 1, 253, 129, 236, 148, 1, 253, 141, + 236, 148, 1, 222, 236, 148, 1, 249, 115, 236, 148, 1, 253, 126, 236, 148, + 1, 253, 133, 236, 148, 1, 253, 131, 236, 148, 1, 249, 123, 236, 148, 1, + 253, 152, 236, 148, 1, 253, 146, 236, 148, 1, 248, 78, 236, 148, 1, 246, + 199, 236, 148, 1, 216, 236, 148, 1, 253, 130, 236, 148, 1, 253, 134, 236, + 148, 1, 253, 171, 236, 148, 1, 253, 132, 236, 148, 1, 67, 236, 148, 1, + 219, 236, 148, 33, 21, 71, 236, 148, 33, 21, 79, 236, 148, 33, 21, 72, + 236, 148, 33, 21, 73, 236, 148, 33, 21, 253, 178, 236, 148, 237, 231, + 236, 148, 253, 165, 147, 236, 210, 8, 1, 3, 5, 67, 8, 1, 3, 5, 253, 178, + 8, 3, 1, 205, 253, 178, 8, 1, 3, 5, 240, 60, 217, 8, 1, 3, 5, 255, 18, 8, + 1, 3, 5, 209, 8, 1, 3, 5, 248, 109, 8, 1, 3, 5, 72, 8, 3, 1, 205, 248, + 35, 72, 8, 3, 1, 205, 71, 8, 1, 3, 5, 221, 8, 1, 3, 5, 255, 15, 8, 1, 3, + 5, 255, 100, 2, 108, 8, 1, 3, 5, 173, 8, 1, 3, 5, 224, 197, 8, 1, 3, 5, + 73, 8, 1, 3, 5, 248, 35, 73, 8, 3, 1, 236, 190, 73, 8, 3, 1, 236, 190, + 248, 35, 73, 8, 3, 1, 236, 190, 117, 2, 108, 8, 3, 1, 205, 253, 193, 8, + 1, 3, 5, 254, 10, 8, 3, 1, 253, 159, 137, 73, 8, 3, 1, 240, 17, 137, 73, + 8, 1, 3, 5, 223, 8, 1, 3, 5, 224, 144, 8, 1, 3, 5, 205, 144, 8, 1, 3, 5, + 214, 8, 1, 3, 5, 79, 8, 3, 1, 236, 190, 79, 8, 3, 1, 236, 190, 233, 132, + 79, 8, 3, 1, 236, 190, 205, 173, 8, 1, 3, 5, 179, 8, 1, 3, 5, 255, 16, 8, + 1, 3, 5, 255, 17, 8, 1, 3, 5, 248, 155, 8, 1, 240, 59, 236, 49, 238, 10, + 8, 1, 248, 105, 17, 1, 3, 5, 240, 10, 17, 1, 3, 5, 240, 33, 17, 1, 3, 5, + 253, 147, 17, 1, 3, 5, 248, 73, 17, 1, 3, 5, 248, 69, 32, 1, 3, 5, 254, + 3, 49, 1, 5, 67, 49, 1, 5, 253, 178, 49, 1, 5, 217, 49, 1, 5, 240, 60, + 217, 49, 1, 5, 209, 49, 1, 5, 72, 49, 1, 5, 224, 72, 49, 1, 5, 210, 49, + 1, 5, 192, 49, 1, 5, 71, 49, 1, 5, 221, 49, 1, 5, 255, 15, 49, 1, 5, 162, + 49, 1, 5, 173, 49, 1, 5, 197, 49, 1, 5, 224, 197, 49, 1, 5, 73, 49, 1, 5, + 254, 10, 49, 1, 5, 223, 49, 1, 5, 144, 49, 1, 5, 214, 49, 1, 5, 79, 49, + 1, 5, 255, 16, 49, 1, 3, 67, 49, 1, 3, 205, 67, 49, 1, 3, 240, 22, 49, 1, + 3, 205, 253, 178, 49, 1, 3, 217, 49, 1, 3, 209, 49, 1, 3, 72, 49, 1, 3, + 240, 86, 49, 1, 3, 248, 35, 72, 49, 1, 3, 205, 248, 35, 72, 49, 1, 3, + 210, 49, 1, 3, 205, 71, 49, 1, 3, 255, 15, 49, 1, 3, 173, 49, 1, 3, 248, + 108, 49, 1, 3, 73, 49, 1, 3, 248, 35, 73, 49, 1, 3, 253, 159, 137, 73, + 49, 1, 3, 240, 17, 137, 73, 49, 1, 3, 223, 49, 1, 3, 214, 49, 1, 3, 79, + 49, 1, 3, 236, 190, 79, 49, 1, 3, 205, 173, 49, 1, 3, 179, 49, 1, 3, 248, + 105, 49, 1, 3, 242, 242, 49, 1, 3, 17, 240, 10, 49, 1, 3, 240, 28, 49, 1, + 3, 17, 248, 68, 49, 1, 3, 248, 67, 8, 235, 48, 3, 1, 71, 8, 235, 48, 3, + 1, 144, 8, 235, 48, 3, 1, 79, 8, 235, 48, 3, 1, 179, 17, 235, 48, 3, 1, + 242, 242, 17, 235, 48, 3, 1, 240, 10, 17, 235, 48, 3, 1, 248, 73, 17, + 235, 48, 3, 1, 248, 68, 17, 235, 48, 3, 1, 248, 67, 8, 3, 1, 253, 252, 8, + 3, 1, 41, 2, 240, 1, 169, 8, 3, 1, 255, 103, 2, 240, 1, 169, 8, 3, 1, + 255, 112, 2, 240, 1, 169, 8, 3, 1, 255, 108, 2, 240, 1, 169, 8, 3, 1, + 255, 98, 2, 240, 1, 169, 8, 3, 1, 255, 114, 2, 240, 1, 169, 8, 3, 1, 255, + 101, 2, 240, 1, 169, 8, 3, 1, 255, 101, 2, 237, 11, 19, 240, 1, 169, 8, + 3, 1, 255, 99, 2, 240, 1, 169, 8, 3, 1, 255, 102, 2, 240, 1, 169, 8, 3, + 1, 255, 97, 2, 240, 1, 169, 8, 3, 1, 205, 210, 49, 1, 32, 253, 202, 8, 3, + 1, 239, 101, 210, 8, 3, 1, 255, 93, 2, 231, 82, 8, 3, 5, 1, 220, 2, 108, + 8, 3, 1, 248, 42, 2, 108, 8, 3, 1, 255, 114, 2, 108, 8, 3, 5, 1, 132, 2, + 108, 8, 3, 1, 238, 53, 2, 108, 8, 3, 1, 41, 2, 238, 65, 90, 8, 3, 1, 255, + 103, 2, 238, 65, 90, 8, 3, 1, 255, 112, 2, 238, 65, 90, 8, 3, 1, 255, + 104, 2, 238, 65, 90, 8, 3, 1, 255, 109, 2, 238, 65, 90, 8, 3, 1, 255, + 100, 2, 238, 65, 90, 8, 3, 1, 255, 108, 2, 238, 65, 90, 8, 3, 1, 255, 98, + 2, 238, 65, 90, 8, 3, 1, 255, 114, 2, 238, 65, 90, 8, 3, 1, 255, 101, 2, + 238, 65, 90, 8, 3, 1, 255, 99, 2, 238, 65, 90, 8, 3, 1, 254, 38, 2, 238, + 65, 90, 8, 3, 1, 255, 110, 2, 238, 65, 90, 8, 3, 1, 255, 113, 2, 238, 65, + 90, 8, 3, 1, 255, 97, 2, 238, 65, 90, 8, 3, 1, 134, 2, 235, 54, 90, 8, 3, + 1, 194, 2, 235, 54, 90, 8, 3, 1, 255, 103, 2, 248, 45, 19, 242, 226, 8, + 3, 1, 157, 2, 235, 54, 90, 8, 3, 1, 248, 35, 157, 2, 235, 54, 90, 8, 3, + 1, 224, 248, 35, 157, 2, 235, 54, 90, 8, 3, 1, 243, 73, 2, 235, 54, 90, + 8, 3, 1, 220, 2, 235, 54, 90, 8, 3, 1, 248, 35, 117, 2, 235, 54, 90, 8, + 3, 1, 254, 38, 2, 235, 54, 90, 8, 3, 1, 132, 2, 235, 54, 90, 8, 3, 1, + 253, 244, 2, 235, 54, 90, 49, 1, 3, 205, 240, 22, 49, 1, 3, 255, 18, 49, + 1, 3, 255, 105, 2, 242, 253, 49, 1, 3, 248, 109, 49, 1, 3, 224, 248, 35, + 72, 49, 1, 3, 255, 19, 49, 1, 3, 238, 70, 255, 115, 2, 108, 49, 1, 3, 84, + 210, 49, 1, 3, 205, 192, 49, 1, 3, 220, 2, 108, 49, 1, 3, 242, 237, 49, + 1, 3, 5, 71, 49, 1, 3, 5, 220, 2, 108, 49, 1, 3, 255, 115, 2, 231, 101, + 49, 1, 3, 255, 100, 2, 235, 54, 90, 49, 1, 3, 255, 100, 2, 238, 65, 90, + 49, 1, 3, 5, 162, 49, 1, 3, 255, 108, 2, 90, 49, 1, 3, 205, 255, 108, 2, + 183, 248, 117, 49, 1, 3, 255, 98, 2, 40, 90, 49, 1, 3, 255, 98, 2, 235, + 54, 90, 49, 1, 3, 5, 197, 49, 1, 3, 240, 60, 73, 49, 1, 3, 248, 68, 49, + 1, 3, 255, 99, 2, 90, 49, 1, 3, 248, 93, 49, 1, 3, 255, 102, 2, 238, 65, + 90, 49, 1, 3, 132, 125, 49, 1, 3, 236, 160, 49, 1, 3, 5, 79, 49, 1, 3, + 255, 110, 2, 90, 49, 1, 3, 205, 179, 49, 1, 3, 255, 17, 49, 1, 3, 255, + 97, 2, 235, 54, 90, 49, 1, 3, 255, 97, 2, 242, 253, 49, 1, 3, 248, 155, + 49, 1, 3, 240, 38, 50, 240, 4, 242, 245, 238, 54, 50, 240, 4, 242, 241, + 238, 54, 50, 247, 95, 46, 50, 235, 6, 69, 8, 5, 1, 134, 2, 248, 51, 46, + 8, 3, 1, 134, 2, 248, 51, 46, 8, 5, 1, 41, 2, 53, 48, 8, 3, 1, 41, 2, 53, + 48, 8, 5, 1, 41, 2, 53, 46, 8, 3, 1, 41, 2, 53, 46, 8, 5, 1, 41, 2, 248, + 41, 46, 8, 3, 1, 41, 2, 248, 41, 46, 8, 5, 1, 255, 105, 2, 238, 109, 19, + 135, 8, 3, 1, 255, 105, 2, 238, 109, 19, 135, 8, 5, 1, 255, 103, 2, 53, + 48, 8, 3, 1, 255, 103, 2, 53, 48, 8, 5, 1, 255, 103, 2, 53, 46, 8, 3, 1, + 255, 103, 2, 53, 46, 8, 5, 1, 255, 103, 2, 248, 41, 46, 8, 3, 1, 255, + 103, 2, 248, 41, 46, 8, 5, 1, 255, 103, 2, 236, 151, 8, 3, 1, 255, 103, + 2, 236, 151, 8, 5, 1, 255, 103, 2, 190, 46, 8, 3, 1, 255, 103, 2, 190, + 46, 8, 5, 1, 157, 2, 240, 42, 19, 191, 8, 3, 1, 157, 2, 240, 42, 19, 191, + 8, 5, 1, 157, 2, 240, 42, 19, 135, 8, 3, 1, 157, 2, 240, 42, 19, 135, 8, + 5, 1, 157, 2, 190, 46, 8, 3, 1, 157, 2, 190, 46, 8, 5, 1, 157, 2, 242, + 219, 46, 8, 3, 1, 157, 2, 242, 219, 46, 8, 5, 1, 157, 2, 238, 109, 19, + 239, 255, 8, 3, 1, 157, 2, 238, 109, 19, 239, 255, 8, 5, 1, 255, 112, 2, + 53, 48, 8, 3, 1, 255, 112, 2, 53, 48, 8, 5, 1, 255, 104, 2, 196, 8, 3, 1, + 255, 104, 2, 196, 8, 5, 1, 255, 106, 2, 53, 48, 8, 3, 1, 255, 106, 2, 53, + 48, 8, 5, 1, 255, 106, 2, 53, 46, 8, 3, 1, 255, 106, 2, 53, 46, 8, 5, 1, + 255, 106, 2, 175, 8, 3, 1, 255, 106, 2, 175, 8, 5, 1, 255, 106, 2, 236, + 151, 8, 3, 1, 255, 106, 2, 236, 151, 8, 5, 1, 255, 106, 2, 242, 243, 46, + 8, 3, 1, 255, 106, 2, 242, 243, 46, 8, 5, 1, 220, 2, 242, 219, 46, 8, 3, + 1, 220, 2, 242, 219, 46, 8, 5, 1, 220, 2, 235, 56, 19, 135, 8, 3, 1, 220, + 2, 235, 56, 19, 135, 8, 5, 1, 255, 109, 2, 135, 8, 3, 1, 255, 109, 2, + 135, 8, 5, 1, 255, 109, 2, 53, 46, 8, 3, 1, 255, 109, 2, 53, 46, 8, 5, 1, + 255, 109, 2, 248, 41, 46, 8, 3, 1, 255, 109, 2, 248, 41, 46, 8, 5, 1, + 255, 100, 2, 53, 46, 8, 3, 1, 255, 100, 2, 53, 46, 8, 5, 1, 255, 100, 2, + 53, 242, 230, 19, 196, 8, 3, 1, 255, 100, 2, 53, 242, 230, 19, 196, 8, 5, + 1, 255, 100, 2, 248, 41, 46, 8, 3, 1, 255, 100, 2, 248, 41, 46, 8, 5, 1, + 255, 100, 2, 190, 46, 8, 3, 1, 255, 100, 2, 190, 46, 8, 5, 1, 255, 108, + 2, 135, 8, 3, 1, 255, 108, 2, 135, 8, 5, 1, 255, 108, 2, 53, 48, 8, 3, 1, + 255, 108, 2, 53, 48, 8, 5, 1, 255, 108, 2, 53, 46, 8, 3, 1, 255, 108, 2, + 53, 46, 8, 5, 1, 255, 98, 2, 53, 48, 8, 3, 1, 255, 98, 2, 53, 48, 8, 5, + 1, 255, 98, 2, 53, 46, 8, 3, 1, 255, 98, 2, 53, 46, 8, 5, 1, 255, 98, 2, + 248, 41, 46, 8, 3, 1, 255, 98, 2, 248, 41, 46, 8, 5, 1, 255, 98, 2, 190, + 46, 8, 3, 1, 255, 98, 2, 190, 46, 8, 5, 1, 117, 2, 242, 219, 19, 135, 8, + 3, 1, 117, 2, 242, 219, 19, 135, 8, 5, 1, 117, 2, 242, 219, 19, 175, 8, + 3, 1, 117, 2, 242, 219, 19, 175, 8, 5, 1, 117, 2, 240, 42, 19, 191, 8, 3, + 1, 117, 2, 240, 42, 19, 191, 8, 5, 1, 117, 2, 240, 42, 19, 135, 8, 3, 1, + 117, 2, 240, 42, 19, 135, 8, 5, 1, 255, 114, 2, 135, 8, 3, 1, 255, 114, + 2, 135, 8, 5, 1, 255, 114, 2, 53, 48, 8, 3, 1, 255, 114, 2, 53, 48, 8, 5, + 1, 255, 101, 2, 53, 48, 8, 3, 1, 255, 101, 2, 53, 48, 8, 5, 1, 255, 101, + 2, 53, 46, 8, 3, 1, 255, 101, 2, 53, 46, 8, 5, 1, 255, 101, 2, 53, 242, + 230, 19, 196, 8, 3, 1, 255, 101, 2, 53, 242, 230, 19, 196, 8, 5, 1, 255, + 101, 2, 248, 41, 46, 8, 3, 1, 255, 101, 2, 248, 41, 46, 8, 5, 1, 255, 99, + 2, 53, 48, 8, 3, 1, 255, 99, 2, 53, 48, 8, 5, 1, 255, 99, 2, 53, 46, 8, + 3, 1, 255, 99, 2, 53, 46, 8, 5, 1, 255, 99, 2, 242, 241, 19, 53, 48, 8, + 3, 1, 255, 99, 2, 242, 241, 19, 53, 48, 8, 5, 1, 255, 99, 2, 243, 86, 19, + 53, 48, 8, 3, 1, 255, 99, 2, 243, 86, 19, 53, 48, 8, 5, 1, 255, 99, 2, + 53, 242, 230, 19, 53, 48, 8, 3, 1, 255, 99, 2, 53, 242, 230, 19, 53, 48, + 8, 5, 1, 255, 102, 2, 53, 48, 8, 3, 1, 255, 102, 2, 53, 48, 8, 5, 1, 255, + 102, 2, 53, 46, 8, 3, 1, 255, 102, 2, 53, 46, 8, 5, 1, 255, 102, 2, 248, + 41, 46, 8, 3, 1, 255, 102, 2, 248, 41, 46, 8, 5, 1, 255, 102, 2, 190, 46, + 8, 3, 1, 255, 102, 2, 190, 46, 8, 5, 1, 132, 2, 235, 56, 46, 8, 3, 1, + 132, 2, 235, 56, 46, 8, 5, 1, 132, 2, 242, 219, 46, 8, 3, 1, 132, 2, 242, + 219, 46, 8, 5, 1, 132, 2, 190, 46, 8, 3, 1, 132, 2, 190, 46, 8, 5, 1, + 132, 2, 242, 219, 19, 135, 8, 3, 1, 132, 2, 242, 219, 19, 135, 8, 5, 1, + 132, 2, 240, 42, 19, 175, 8, 3, 1, 132, 2, 240, 42, 19, 175, 8, 5, 1, + 255, 110, 2, 169, 8, 3, 1, 255, 110, 2, 169, 8, 5, 1, 255, 110, 2, 53, + 46, 8, 3, 1, 255, 110, 2, 53, 46, 8, 5, 1, 255, 111, 2, 191, 8, 3, 1, + 255, 111, 2, 191, 8, 5, 1, 255, 111, 2, 135, 8, 3, 1, 255, 111, 2, 135, + 8, 5, 1, 255, 111, 2, 175, 8, 3, 1, 255, 111, 2, 175, 8, 5, 1, 255, 111, + 2, 53, 48, 8, 3, 1, 255, 111, 2, 53, 48, 8, 5, 1, 255, 111, 2, 53, 46, 8, + 3, 1, 255, 111, 2, 53, 46, 8, 5, 1, 255, 113, 2, 53, 48, 8, 3, 1, 255, + 113, 2, 53, 48, 8, 5, 1, 255, 113, 2, 175, 8, 3, 1, 255, 113, 2, 175, 8, + 5, 1, 255, 107, 2, 53, 48, 8, 3, 1, 255, 107, 2, 53, 48, 8, 5, 1, 255, + 97, 2, 233, 48, 8, 3, 1, 255, 97, 2, 233, 48, 8, 5, 1, 255, 97, 2, 53, + 46, 8, 3, 1, 255, 97, 2, 53, 46, 8, 5, 1, 255, 97, 2, 248, 41, 46, 8, 3, + 1, 255, 97, 2, 248, 41, 46, 8, 3, 1, 255, 106, 2, 248, 41, 46, 8, 3, 1, + 255, 102, 2, 175, 8, 3, 1, 255, 111, 2, 248, 51, 48, 8, 3, 1, 255, 107, + 2, 248, 51, 48, 8, 3, 1, 134, 2, 38, 137, 242, 233, 8, 3, 1, 183, 255, + 99, 2, 53, 48, 8, 5, 1, 134, 2, 53, 46, 8, 3, 1, 134, 2, 53, 46, 8, 5, 1, + 134, 2, 248, 45, 48, 8, 3, 1, 134, 2, 248, 45, 48, 8, 5, 1, 134, 2, 190, + 19, 135, 8, 3, 1, 134, 2, 190, 19, 135, 8, 5, 1, 134, 2, 190, 19, 191, 8, + 3, 1, 134, 2, 190, 19, 191, 8, 5, 1, 134, 2, 190, 19, 248, 45, 48, 8, 3, + 1, 134, 2, 190, 19, 248, 45, 48, 8, 5, 1, 134, 2, 190, 19, 169, 8, 3, 1, + 134, 2, 190, 19, 169, 8, 5, 1, 134, 2, 190, 19, 53, 46, 8, 3, 1, 134, 2, + 190, 19, 53, 46, 8, 5, 1, 134, 2, 242, 243, 19, 135, 8, 3, 1, 134, 2, + 242, 243, 19, 135, 8, 5, 1, 134, 2, 242, 243, 19, 191, 8, 3, 1, 134, 2, + 242, 243, 19, 191, 8, 5, 1, 134, 2, 242, 243, 19, 248, 45, 48, 8, 3, 1, + 134, 2, 242, 243, 19, 248, 45, 48, 8, 5, 1, 134, 2, 242, 243, 19, 169, 8, + 3, 1, 134, 2, 242, 243, 19, 169, 8, 5, 1, 134, 2, 242, 243, 19, 53, 46, + 8, 3, 1, 134, 2, 242, 243, 19, 53, 46, 8, 5, 1, 157, 2, 53, 46, 8, 3, 1, + 157, 2, 53, 46, 8, 5, 1, 157, 2, 248, 45, 48, 8, 3, 1, 157, 2, 248, 45, + 48, 8, 5, 1, 157, 2, 169, 8, 3, 1, 157, 2, 169, 8, 5, 1, 157, 2, 190, 19, + 135, 8, 3, 1, 157, 2, 190, 19, 135, 8, 5, 1, 157, 2, 190, 19, 191, 8, 3, + 1, 157, 2, 190, 19, 191, 8, 5, 1, 157, 2, 190, 19, 248, 45, 48, 8, 3, 1, + 157, 2, 190, 19, 248, 45, 48, 8, 5, 1, 157, 2, 190, 19, 169, 8, 3, 1, + 157, 2, 190, 19, 169, 8, 5, 1, 157, 2, 190, 19, 53, 46, 8, 3, 1, 157, 2, + 190, 19, 53, 46, 8, 5, 1, 220, 2, 248, 45, 48, 8, 3, 1, 220, 2, 248, 45, + 48, 8, 5, 1, 220, 2, 53, 46, 8, 3, 1, 220, 2, 53, 46, 8, 5, 1, 117, 2, + 53, 46, 8, 3, 1, 117, 2, 53, 46, 8, 5, 1, 117, 2, 248, 45, 48, 8, 3, 1, + 117, 2, 248, 45, 48, 8, 5, 1, 117, 2, 190, 19, 135, 8, 3, 1, 117, 2, 190, + 19, 135, 8, 5, 1, 117, 2, 190, 19, 191, 8, 3, 1, 117, 2, 190, 19, 191, 8, + 5, 1, 117, 2, 190, 19, 248, 45, 48, 8, 3, 1, 117, 2, 190, 19, 248, 45, + 48, 8, 5, 1, 117, 2, 190, 19, 169, 8, 3, 1, 117, 2, 190, 19, 169, 8, 5, + 1, 117, 2, 190, 19, 53, 46, 8, 3, 1, 117, 2, 190, 19, 53, 46, 8, 5, 1, + 117, 2, 248, 60, 19, 135, 8, 3, 1, 117, 2, 248, 60, 19, 135, 8, 5, 1, + 117, 2, 248, 60, 19, 191, 8, 3, 1, 117, 2, 248, 60, 19, 191, 8, 5, 1, + 117, 2, 248, 60, 19, 248, 45, 48, 8, 3, 1, 117, 2, 248, 60, 19, 248, 45, + 48, 8, 5, 1, 117, 2, 248, 60, 19, 169, 8, 3, 1, 117, 2, 248, 60, 19, 169, + 8, 5, 1, 117, 2, 248, 60, 19, 53, 46, 8, 3, 1, 117, 2, 248, 60, 19, 53, + 46, 8, 5, 1, 132, 2, 53, 46, 8, 3, 1, 132, 2, 53, 46, 8, 5, 1, 132, 2, + 248, 45, 48, 8, 3, 1, 132, 2, 248, 45, 48, 8, 5, 1, 132, 2, 248, 60, 19, + 135, 8, 3, 1, 132, 2, 248, 60, 19, 135, 8, 5, 1, 132, 2, 248, 60, 19, + 191, 8, 3, 1, 132, 2, 248, 60, 19, 191, 8, 5, 1, 132, 2, 248, 60, 19, + 248, 45, 48, 8, 3, 1, 132, 2, 248, 60, 19, 248, 45, 48, 8, 5, 1, 132, 2, + 248, 60, 19, 169, 8, 3, 1, 132, 2, 248, 60, 19, 169, 8, 5, 1, 132, 2, + 248, 60, 19, 53, 46, 8, 3, 1, 132, 2, 248, 60, 19, 53, 46, 8, 5, 1, 255, + 107, 2, 191, 8, 3, 1, 255, 107, 2, 191, 8, 5, 1, 255, 107, 2, 53, 46, 8, + 3, 1, 255, 107, 2, 53, 46, 8, 5, 1, 255, 107, 2, 248, 45, 48, 8, 3, 1, + 255, 107, 2, 248, 45, 48, 8, 5, 1, 255, 107, 2, 169, 8, 3, 1, 255, 107, + 2, 169, 17, 3, 1, 194, 2, 240, 29, 17, 3, 1, 194, 2, 240, 25, 17, 3, 1, + 194, 2, 159, 19, 215, 17, 3, 1, 194, 2, 148, 19, 215, 17, 3, 1, 194, 2, + 159, 19, 212, 17, 3, 1, 194, 2, 148, 19, 212, 17, 3, 1, 194, 2, 159, 19, + 232, 71, 17, 3, 1, 194, 2, 148, 19, 232, 71, 17, 5, 1, 194, 2, 240, 29, + 17, 5, 1, 194, 2, 240, 25, 17, 5, 1, 194, 2, 159, 19, 215, 17, 5, 1, 194, + 2, 148, 19, 215, 17, 5, 1, 194, 2, 159, 19, 212, 17, 5, 1, 194, 2, 148, + 19, 212, 17, 5, 1, 194, 2, 159, 19, 232, 71, 17, 5, 1, 194, 2, 148, 19, + 232, 71, 17, 3, 1, 238, 57, 2, 240, 29, 17, 3, 1, 238, 57, 2, 240, 25, + 17, 3, 1, 238, 57, 2, 159, 19, 215, 17, 3, 1, 238, 57, 2, 148, 19, 215, + 17, 3, 1, 238, 57, 2, 159, 19, 212, 17, 3, 1, 238, 57, 2, 148, 19, 212, + 17, 5, 1, 238, 57, 2, 240, 29, 17, 5, 1, 238, 57, 2, 240, 25, 17, 5, 1, + 238, 57, 2, 159, 19, 215, 17, 5, 1, 238, 57, 2, 148, 19, 215, 17, 5, 1, + 238, 57, 2, 159, 19, 212, 17, 5, 1, 238, 57, 2, 148, 19, 212, 17, 3, 1, + 253, 123, 2, 240, 29, 17, 3, 1, 253, 123, 2, 240, 25, 17, 3, 1, 253, 123, + 2, 159, 19, 215, 17, 3, 1, 253, 123, 2, 148, 19, 215, 17, 3, 1, 253, 123, + 2, 159, 19, 212, 17, 3, 1, 253, 123, 2, 148, 19, 212, 17, 3, 1, 253, 123, + 2, 159, 19, 232, 71, 17, 3, 1, 253, 123, 2, 148, 19, 232, 71, 17, 5, 1, + 253, 123, 2, 240, 29, 17, 5, 1, 253, 123, 2, 240, 25, 17, 5, 1, 253, 123, + 2, 159, 19, 215, 17, 5, 1, 253, 123, 2, 148, 19, 215, 17, 5, 1, 253, 123, + 2, 159, 19, 212, 17, 5, 1, 253, 123, 2, 148, 19, 212, 17, 5, 1, 253, 123, + 2, 159, 19, 232, 71, 17, 5, 1, 253, 123, 2, 148, 19, 232, 71, 17, 3, 1, + 248, 42, 2, 240, 29, 17, 3, 1, 248, 42, 2, 240, 25, 17, 3, 1, 248, 42, 2, + 159, 19, 215, 17, 3, 1, 248, 42, 2, 148, 19, 215, 17, 3, 1, 248, 42, 2, + 159, 19, 212, 17, 3, 1, 248, 42, 2, 148, 19, 212, 17, 3, 1, 248, 42, 2, + 159, 19, 232, 71, 17, 3, 1, 248, 42, 2, 148, 19, 232, 71, 17, 5, 1, 248, + 42, 2, 240, 29, 17, 5, 1, 248, 42, 2, 240, 25, 17, 5, 1, 248, 42, 2, 159, + 19, 215, 17, 5, 1, 248, 42, 2, 148, 19, 215, 17, 5, 1, 248, 42, 2, 159, + 19, 212, 17, 5, 1, 248, 42, 2, 148, 19, 212, 17, 5, 1, 248, 42, 2, 159, + 19, 232, 71, 17, 5, 1, 248, 42, 2, 148, 19, 232, 71, 17, 3, 1, 238, 64, + 2, 240, 29, 17, 3, 1, 238, 64, 2, 240, 25, 17, 3, 1, 238, 64, 2, 159, 19, + 215, 17, 3, 1, 238, 64, 2, 148, 19, 215, 17, 3, 1, 238, 64, 2, 159, 19, + 212, 17, 3, 1, 238, 64, 2, 148, 19, 212, 17, 5, 1, 238, 64, 2, 240, 29, + 17, 5, 1, 238, 64, 2, 240, 25, 17, 5, 1, 238, 64, 2, 159, 19, 215, 17, 5, + 1, 238, 64, 2, 148, 19, 215, 17, 5, 1, 238, 64, 2, 159, 19, 212, 17, 5, + 1, 238, 64, 2, 148, 19, 212, 17, 3, 1, 238, 53, 2, 240, 29, 17, 3, 1, + 238, 53, 2, 240, 25, 17, 3, 1, 238, 53, 2, 159, 19, 215, 17, 3, 1, 238, + 53, 2, 148, 19, 215, 17, 3, 1, 238, 53, 2, 159, 19, 212, 17, 3, 1, 238, + 53, 2, 148, 19, 212, 17, 3, 1, 238, 53, 2, 159, 19, 232, 71, 17, 3, 1, + 238, 53, 2, 148, 19, 232, 71, 17, 5, 1, 238, 53, 2, 240, 25, 17, 5, 1, + 238, 53, 2, 148, 19, 215, 17, 5, 1, 238, 53, 2, 148, 19, 212, 17, 5, 1, + 238, 53, 2, 148, 19, 232, 71, 17, 3, 1, 211, 2, 240, 29, 17, 3, 1, 211, + 2, 240, 25, 17, 3, 1, 211, 2, 159, 19, 215, 17, 3, 1, 211, 2, 148, 19, + 215, 17, 3, 1, 211, 2, 159, 19, 212, 17, 3, 1, 211, 2, 148, 19, 212, 17, + 3, 1, 211, 2, 159, 19, 232, 71, 17, 3, 1, 211, 2, 148, 19, 232, 71, 17, + 5, 1, 211, 2, 240, 29, 17, 5, 1, 211, 2, 240, 25, 17, 5, 1, 211, 2, 159, + 19, 215, 17, 5, 1, 211, 2, 148, 19, 215, 17, 5, 1, 211, 2, 159, 19, 212, + 17, 5, 1, 211, 2, 148, 19, 212, 17, 5, 1, 211, 2, 159, 19, 232, 71, 17, + 5, 1, 211, 2, 148, 19, 232, 71, 17, 3, 1, 194, 2, 215, 17, 3, 1, 194, 2, + 212, 17, 3, 1, 238, 57, 2, 215, 17, 3, 1, 238, 57, 2, 212, 17, 3, 1, 253, + 123, 2, 215, 17, 3, 1, 253, 123, 2, 212, 17, 3, 1, 248, 42, 2, 215, 17, + 3, 1, 248, 42, 2, 212, 17, 3, 1, 238, 64, 2, 215, 17, 3, 1, 238, 64, 2, + 212, 17, 3, 1, 238, 53, 2, 215, 17, 3, 1, 238, 53, 2, 212, 17, 3, 1, 211, + 2, 215, 17, 3, 1, 211, 2, 212, 17, 3, 1, 194, 2, 159, 19, 231, 35, 17, 3, + 1, 194, 2, 148, 19, 231, 35, 17, 3, 1, 194, 2, 159, 19, 242, 248, 19, + 231, 35, 17, 3, 1, 194, 2, 148, 19, 242, 248, 19, 231, 35, 17, 3, 1, 194, + 2, 159, 19, 248, 79, 19, 231, 35, 17, 3, 1, 194, 2, 148, 19, 248, 79, 19, + 231, 35, 17, 3, 1, 194, 2, 159, 19, 233, 53, 19, 231, 35, 17, 3, 1, 194, + 2, 148, 19, 233, 53, 19, 231, 35, 17, 5, 1, 194, 2, 159, 19, 229, 57, 17, + 5, 1, 194, 2, 148, 19, 229, 57, 17, 5, 1, 194, 2, 159, 19, 242, 248, 19, + 229, 57, 17, 5, 1, 194, 2, 148, 19, 242, 248, 19, 229, 57, 17, 5, 1, 194, + 2, 159, 19, 248, 79, 19, 229, 57, 17, 5, 1, 194, 2, 148, 19, 248, 79, 19, + 229, 57, 17, 5, 1, 194, 2, 159, 19, 233, 53, 19, 229, 57, 17, 5, 1, 194, + 2, 148, 19, 233, 53, 19, 229, 57, 17, 3, 1, 253, 123, 2, 159, 19, 231, + 35, 17, 3, 1, 253, 123, 2, 148, 19, 231, 35, 17, 3, 1, 253, 123, 2, 159, + 19, 242, 248, 19, 231, 35, 17, 3, 1, 253, 123, 2, 148, 19, 242, 248, 19, + 231, 35, 17, 3, 1, 253, 123, 2, 159, 19, 248, 79, 19, 231, 35, 17, 3, 1, + 253, 123, 2, 148, 19, 248, 79, 19, 231, 35, 17, 3, 1, 253, 123, 2, 159, + 19, 233, 53, 19, 231, 35, 17, 3, 1, 253, 123, 2, 148, 19, 233, 53, 19, + 231, 35, 17, 5, 1, 253, 123, 2, 159, 19, 229, 57, 17, 5, 1, 253, 123, 2, + 148, 19, 229, 57, 17, 5, 1, 253, 123, 2, 159, 19, 242, 248, 19, 229, 57, + 17, 5, 1, 253, 123, 2, 148, 19, 242, 248, 19, 229, 57, 17, 5, 1, 253, + 123, 2, 159, 19, 248, 79, 19, 229, 57, 17, 5, 1, 253, 123, 2, 148, 19, + 248, 79, 19, 229, 57, 17, 5, 1, 253, 123, 2, 159, 19, 233, 53, 19, 229, + 57, 17, 5, 1, 253, 123, 2, 148, 19, 233, 53, 19, 229, 57, 17, 3, 1, 211, + 2, 159, 19, 231, 35, 17, 3, 1, 211, 2, 148, 19, 231, 35, 17, 3, 1, 211, + 2, 159, 19, 242, 248, 19, 231, 35, 17, 3, 1, 211, 2, 148, 19, 242, 248, + 19, 231, 35, 17, 3, 1, 211, 2, 159, 19, 248, 79, 19, 231, 35, 17, 3, 1, + 211, 2, 148, 19, 248, 79, 19, 231, 35, 17, 3, 1, 211, 2, 159, 19, 233, + 53, 19, 231, 35, 17, 3, 1, 211, 2, 148, 19, 233, 53, 19, 231, 35, 17, 5, + 1, 211, 2, 159, 19, 229, 57, 17, 5, 1, 211, 2, 148, 19, 229, 57, 17, 5, + 1, 211, 2, 159, 19, 242, 248, 19, 229, 57, 17, 5, 1, 211, 2, 148, 19, + 242, 248, 19, 229, 57, 17, 5, 1, 211, 2, 159, 19, 248, 79, 19, 229, 57, + 17, 5, 1, 211, 2, 148, 19, 248, 79, 19, 229, 57, 17, 5, 1, 211, 2, 159, + 19, 233, 53, 19, 229, 57, 17, 5, 1, 211, 2, 148, 19, 233, 53, 19, 229, + 57, 17, 3, 1, 194, 2, 238, 103, 17, 3, 1, 194, 2, 196, 17, 3, 1, 194, 2, + 242, 248, 19, 231, 35, 17, 3, 1, 194, 2, 231, 35, 17, 3, 1, 194, 2, 248, + 79, 19, 231, 35, 17, 3, 1, 194, 2, 232, 71, 17, 3, 1, 194, 2, 233, 53, + 19, 231, 35, 17, 5, 1, 194, 2, 238, 103, 17, 5, 1, 194, 2, 196, 17, 5, 1, + 194, 2, 215, 17, 5, 1, 194, 2, 212, 17, 5, 1, 194, 2, 229, 57, 17, 236, + 229, 17, 229, 57, 17, 240, 29, 17, 232, 71, 17, 235, 59, 19, 232, 71, 17, + 3, 1, 253, 123, 2, 242, 248, 19, 231, 35, 17, 3, 1, 253, 123, 2, 231, 35, + 17, 3, 1, 253, 123, 2, 248, 79, 19, 231, 35, 17, 3, 1, 253, 123, 2, 232, + 71, 17, 3, 1, 253, 123, 2, 233, 53, 19, 231, 35, 17, 5, 1, 238, 57, 2, + 215, 17, 5, 1, 238, 57, 2, 212, 17, 5, 1, 253, 123, 2, 215, 17, 5, 1, + 253, 123, 2, 212, 17, 5, 1, 253, 123, 2, 229, 57, 17, 159, 19, 215, 17, + 159, 19, 212, 17, 159, 19, 232, 71, 17, 3, 1, 248, 42, 2, 238, 103, 17, + 3, 1, 248, 42, 2, 196, 17, 3, 1, 248, 42, 2, 235, 59, 19, 215, 17, 3, 1, + 248, 42, 2, 235, 59, 19, 212, 17, 3, 1, 248, 42, 2, 232, 71, 17, 3, 1, + 248, 42, 2, 235, 59, 19, 232, 71, 17, 5, 1, 248, 42, 2, 238, 103, 17, 5, + 1, 248, 42, 2, 196, 17, 5, 1, 248, 42, 2, 215, 17, 5, 1, 248, 42, 2, 212, + 17, 148, 19, 215, 17, 148, 19, 212, 17, 148, 19, 232, 71, 17, 3, 1, 238, + 53, 2, 238, 103, 17, 3, 1, 238, 53, 2, 196, 17, 3, 1, 238, 53, 2, 235, + 59, 19, 215, 17, 3, 1, 238, 53, 2, 235, 59, 19, 212, 17, 3, 1, 253, 218, + 2, 240, 29, 17, 3, 1, 253, 218, 2, 240, 25, 17, 3, 1, 238, 53, 2, 232, + 71, 17, 3, 1, 238, 53, 2, 235, 59, 19, 232, 71, 17, 5, 1, 238, 53, 2, + 238, 103, 17, 5, 1, 238, 53, 2, 196, 17, 5, 1, 238, 53, 2, 215, 17, 5, 1, + 238, 53, 2, 212, 17, 5, 1, 253, 218, 2, 240, 25, 17, 235, 59, 19, 215, + 17, 235, 59, 19, 212, 17, 215, 17, 3, 1, 211, 2, 242, 248, 19, 231, 35, + 17, 3, 1, 211, 2, 231, 35, 17, 3, 1, 211, 2, 248, 79, 19, 231, 35, 17, 3, + 1, 211, 2, 232, 71, 17, 3, 1, 211, 2, 233, 53, 19, 231, 35, 17, 5, 1, + 238, 64, 2, 215, 17, 5, 1, 238, 64, 2, 212, 17, 5, 1, 211, 2, 215, 17, 5, + 1, 211, 2, 212, 17, 5, 1, 211, 2, 229, 57, 17, 212, 17, 240, 25, 255, 23, + 243, 43, 255, 28, 243, 43, 255, 23, 240, 15, 255, 28, 240, 15, 233, 42, + 240, 15, 233, 203, 240, 15, 235, 1, 240, 15, 240, 174, 240, 15, 233, 51, + 240, 15, 252, 219, 240, 15, 251, 46, 240, 15, 248, 145, 243, 81, 240, 15, + 248, 145, 243, 81, 233, 219, 248, 145, 243, 81, 238, 140, 231, 96, 69, + 231, 99, 69, 238, 93, 232, 188, 238, 93, 240, 174, 242, 235, 255, 23, + 242, 235, 255, 28, 242, 235, 163, 125, 45, 59, 242, 224, 45, 170, 242, + 224, 40, 240, 12, 235, 51, 69, 38, 240, 12, 235, 51, 69, 240, 12, 243, + 218, 235, 51, 69, 240, 12, 229, 62, 235, 51, 69, 40, 45, 235, 51, 69, 38, + 45, 235, 51, 69, 45, 243, 218, 235, 51, 69, 45, 229, 62, 235, 51, 69, + 238, 173, 45, 238, 173, 238, 69, 234, 43, 238, 69, 253, 125, 53, 238, + 143, 171, 53, 238, 143, 163, 235, 69, 233, 207, 240, 209, 248, 41, 234, + 6, 235, 91, 234, 6, 231, 96, 234, 52, 231, 99, 234, 52, 254, 227, 233, + 134, 233, 202, 231, 96, 235, 131, 231, 99, 235, 131, 241, 252, 236, 233, + 240, 15, 254, 68, 246, 85, 52, 254, 68, 253, 219, 236, 193, 52, 240, 57, + 45, 240, 57, 240, 3, 240, 57, 224, 240, 57, 224, 45, 240, 57, 224, 240, + 3, 240, 57, 240, 130, 240, 12, 231, 87, 185, 235, 51, 69, 240, 12, 231, + 36, 185, 235, 51, 69, 236, 90, 69, 45, 233, 54, 69, 232, 179, 235, 74, + 235, 158, 99, 248, 139, 243, 25, 235, 128, 240, 209, 235, 175, 241, 177, + 238, 69, 236, 155, 240, 37, 40, 31, 238, 52, 2, 240, 214, 38, 31, 238, + 52, 2, 240, 214, 45, 236, 156, 69, 236, 156, 233, 54, 69, 233, 54, 236, + 156, 69, 238, 30, 21, 254, 60, 224, 238, 208, 52, 86, 139, 238, 69, 86, + 77, 238, 69, 170, 235, 52, 224, 234, 14, 245, 24, 253, 176, 171, 235, + 174, 238, 243, 234, 0, 234, 20, 242, 250, 52, 247, 129, 242, 235, 236, + 145, 235, 158, 241, 111, 233, 51, 69, 204, 53, 232, 75, 235, 71, 240, 57, + 248, 58, 53, 232, 75, 248, 48, 53, 232, 75, 171, 53, 232, 75, 248, 58, + 53, 69, 240, 4, 240, 34, 236, 131, 59, 248, 58, 243, 5, 240, 19, 10, 240, + 15, 248, 143, 238, 140, 237, 163, 232, 116, 235, 129, 240, 123, 235, 129, + 234, 6, 238, 190, 235, 152, 235, 145, 236, 243, 235, 152, 235, 145, 238, + 190, 11, 248, 38, 237, 39, 236, 243, 11, 248, 38, 237, 39, 237, 216, 26, + 238, 215, 239, 146, 26, 238, 215, 233, 49, 242, 217, 233, 49, 8, 3, 1, + 71, 233, 49, 177, 233, 49, 176, 233, 49, 187, 233, 49, 203, 233, 49, 195, + 233, 49, 202, 233, 49, 248, 49, 52, 233, 49, 240, 68, 233, 49, 240, 7, + 52, 233, 49, 40, 232, 74, 233, 49, 38, 232, 74, 233, 49, 8, 3, 1, 197, + 235, 48, 242, 217, 235, 48, 127, 235, 48, 111, 235, 48, 166, 235, 48, + 177, 235, 48, 176, 235, 48, 187, 235, 48, 203, 235, 48, 195, 235, 48, + 202, 235, 48, 248, 49, 52, 235, 48, 240, 68, 235, 48, 240, 7, 52, 235, + 48, 40, 232, 74, 235, 48, 38, 232, 74, 8, 235, 48, 3, 1, 67, 8, 235, 48, + 3, 1, 72, 8, 235, 48, 3, 1, 73, 8, 235, 48, 3, 1, 206, 8, 235, 48, 3, 1, + 240, 86, 231, 137, 52, 243, 14, 52, 237, 96, 52, 241, 117, 245, 92, 52, + 251, 199, 52, 251, 234, 52, 246, 103, 52, 242, 58, 52, 243, 44, 52, 254, + 131, 52, 116, 242, 104, 52, 250, 203, 52, 250, 231, 52, 254, 185, 52, + 242, 162, 52, 238, 180, 52, 241, 127, 246, 241, 52, 252, 63, 52, 239, 86, + 52, 238, 254, 52, 239, 94, 52, 250, 153, 52, 50, 40, 186, 48, 50, 38, + 186, 48, 50, 183, 59, 248, 41, 236, 161, 50, 242, 215, 59, 248, 41, 236, + 161, 50, 231, 86, 65, 48, 50, 235, 62, 65, 48, 50, 40, 65, 48, 50, 38, + 65, 48, 50, 248, 51, 236, 161, 50, 235, 62, 248, 51, 236, 161, 50, 231, + 86, 248, 51, 236, 161, 50, 204, 181, 48, 50, 248, 58, 181, 48, 50, 235, + 73, 238, 51, 50, 235, 73, 238, 59, 50, 235, 73, 236, 164, 50, 235, 73, + 218, 234, 25, 50, 40, 38, 65, 48, 50, 235, 73, 239, 182, 50, 235, 73, + 239, 107, 50, 235, 73, 242, 172, 236, 150, 235, 46, 50, 238, 75, 238, 83, + 236, 161, 50, 45, 59, 240, 5, 236, 161, 50, 238, 245, 91, 50, 240, 3, + 236, 136, 50, 248, 98, 240, 109, 48, 50, 139, 65, 236, 161, 50, 183, 45, + 238, 83, 236, 161, 238, 158, 253, 174, 235, 160, 153, 253, 145, 238, 18, + 138, 5, 255, 18, 240, 112, 237, 85, 240, 46, 248, 41, 91, 250, 145, 253, + 174, 250, 142, 252, 251, 245, 87, 235, 118, 238, 3, 240, 112, 233, 200, + 84, 3, 210, 84, 5, 192, 232, 80, 5, 192, 138, 5, 192, 240, 208, 235, 118, + 240, 208, 237, 90, 248, 59, 171, 253, 147, 84, 5, 71, 232, 80, 5, 71, 84, + 5, 162, 84, 3, 162, 255, 100, 41, 253, 144, 91, 138, 5, 197, 242, 27, 52, + 243, 1, 236, 88, 234, 105, 84, 5, 223, 138, 5, 223, 138, 5, 255, 20, 84, + 5, 144, 232, 80, 5, 144, 138, 5, 144, 232, 198, 247, 136, 235, 141, 239, + 189, 69, 235, 113, 52, 247, 157, 158, 52, 236, 138, 138, 5, 255, 17, 246, + 235, 52, 254, 119, 52, 236, 145, 254, 119, 52, 232, 80, 5, 255, 17, 205, + 17, 3, 1, 242, 237, 241, 198, 52, 237, 60, 52, 84, 5, 217, 232, 80, 5, + 255, 18, 236, 14, 91, 84, 3, 72, 84, 5, 72, 84, 5, 255, 19, 205, 5, 255, + 19, 84, 5, 173, 84, 3, 73, 83, 91, 254, 53, 91, 243, 184, 91, 243, 162, + 91, 233, 211, 239, 199, 238, 120, 5, 255, 20, 236, 17, 52, 138, 3, 253, + 147, 138, 3, 240, 10, 138, 5, 240, 10, 138, 5, 253, 147, 138, 242, 238, + 234, 65, 205, 27, 5, 210, 205, 27, 5, 162, 224, 27, 5, 162, 205, 27, 5, + 255, 14, 138, 24, 5, 209, 138, 24, 3, 209, 138, 24, 3, 72, 138, 24, 3, + 71, 138, 24, 3, 221, 237, 244, 242, 224, 205, 234, 17, 254, 68, 52, 240, + 30, 236, 155, 253, 125, 242, 148, 240, 30, 236, 155, 171, 239, 220, 240, + 30, 236, 155, 253, 125, 241, 107, 240, 30, 236, 155, 171, 238, 138, 240, + 30, 236, 155, 204, 238, 138, 240, 30, 236, 155, 248, 58, 238, 138, 240, + 30, 236, 155, 253, 125, 242, 113, 240, 30, 236, 155, 248, 48, 239, 197, + 240, 30, 236, 155, 253, 125, 239, 55, 240, 30, 236, 155, 204, 236, 224, + 240, 30, 236, 155, 248, 48, 236, 224, 240, 30, 236, 155, 243, 31, 236, + 224, 236, 155, 235, 79, 127, 242, 218, 178, 127, 242, 218, 178, 111, 242, + 218, 178, 166, 242, 218, 178, 177, 242, 218, 178, 176, 242, 218, 178, + 187, 242, 218, 178, 203, 242, 218, 178, 195, 242, 218, 178, 202, 242, + 218, 178, 248, 53, 242, 218, 178, 238, 91, 242, 218, 178, 238, 97, 242, + 218, 178, 240, 50, 242, 218, 178, 253, 125, 236, 149, 242, 218, 178, 248, + 48, 236, 149, 242, 218, 178, 253, 125, 235, 49, 3, 242, 218, 178, 127, 3, + 242, 218, 178, 111, 3, 242, 218, 178, 166, 3, 242, 218, 178, 177, 3, 242, + 218, 178, 176, 3, 242, 218, 178, 187, 3, 242, 218, 178, 203, 3, 242, 218, + 178, 195, 3, 242, 218, 178, 202, 3, 242, 218, 178, 248, 53, 3, 242, 218, + 178, 238, 91, 3, 242, 218, 178, 238, 97, 3, 242, 218, 178, 240, 50, 3, + 242, 218, 178, 253, 125, 236, 149, 3, 242, 218, 178, 248, 48, 236, 149, + 3, 242, 218, 178, 253, 125, 235, 49, 242, 218, 178, 253, 125, 236, 193, + 255, 105, 209, 242, 218, 178, 248, 48, 235, 49, 242, 218, 178, 253, 219, + 235, 49, 242, 218, 178, 224, 253, 125, 236, 149, 139, 56, 226, 226, 56, + 77, 56, 235, 45, 56, 40, 38, 56, 88, 92, 56, 242, 223, 248, 56, 56, 242, + 223, 248, 43, 56, 242, 228, 248, 43, 56, 242, 228, 248, 56, 56, 139, 65, + 2, 108, 77, 65, 2, 108, 139, 248, 141, 56, 77, 248, 141, 56, 139, 171, + 240, 115, 56, 226, 226, 171, 240, 115, 56, 77, 171, 240, 115, 56, 235, + 45, 171, 240, 115, 56, 139, 65, 2, 242, 226, 77, 65, 2, 242, 226, 139, + 65, 248, 44, 125, 226, 226, 65, 248, 44, 125, 77, 65, 248, 44, 125, 235, + 45, 65, 248, 44, 125, 88, 92, 65, 2, 244, 192, 139, 65, 2, 90, 77, 65, 2, + 90, 139, 65, 2, 243, 105, 77, 65, 2, 243, 105, 40, 38, 248, 141, 56, 40, + 38, 65, 2, 108, 235, 45, 240, 126, 56, 226, 226, 65, 2, 253, 241, 234, + 18, 226, 226, 65, 2, 253, 241, 233, 63, 235, 45, 65, 2, 253, 241, 234, + 18, 235, 45, 65, 2, 253, 241, 233, 63, 77, 65, 2, 240, 31, 234, 9, 235, + 45, 65, 2, 240, 31, 234, 18, 231, 86, 253, 159, 234, 64, 56, 235, 62, + 253, 159, 234, 64, 56, 242, 223, 248, 56, 65, 153, 183, 125, 139, 65, + 153, 253, 144, 248, 59, 77, 65, 153, 125, 231, 86, 248, 35, 218, 56, 235, + 62, 248, 35, 218, 56, 139, 186, 2, 154, 236, 206, 139, 186, 2, 154, 234, + 9, 226, 226, 186, 2, 154, 233, 63, 226, 226, 186, 2, 154, 234, 18, 77, + 186, 2, 154, 236, 206, 77, 186, 2, 154, 234, 9, 235, 45, 186, 2, 154, + 233, 63, 235, 45, 186, 2, 154, 234, 18, 77, 65, 248, 59, 139, 56, 226, + 226, 65, 139, 147, 235, 45, 56, 139, 65, 248, 59, 77, 56, 139, 240, 117, + 238, 104, 226, 226, 240, 117, 238, 104, 77, 240, 117, 238, 104, 235, 45, + 240, 117, 238, 104, 139, 186, 248, 59, 77, 236, 175, 77, 186, 248, 59, + 139, 236, 175, 139, 45, 65, 2, 108, 40, 38, 45, 65, 2, 108, 77, 45, 65, + 2, 108, 139, 45, 56, 226, 226, 45, 56, 77, 45, 56, 235, 45, 45, 56, 40, + 38, 45, 56, 88, 92, 45, 56, 242, 223, 248, 56, 45, 56, 242, 223, 248, 43, + 45, 56, 242, 228, 248, 43, 45, 56, 242, 228, 248, 56, 45, 56, 139, 240, + 3, 56, 77, 240, 3, 56, 139, 236, 240, 56, 77, 236, 240, 56, 226, 226, 65, + 2, 45, 108, 235, 45, 65, 2, 45, 108, 139, 240, 55, 56, 226, 226, 240, 55, + 56, 77, 240, 55, 56, 235, 45, 240, 55, 56, 139, 65, 153, 125, 77, 65, + 153, 125, 139, 64, 56, 226, 226, 64, 56, 77, 64, 56, 235, 45, 64, 56, + 226, 226, 64, 65, 248, 44, 125, 226, 226, 64, 65, 255, 34, 235, 133, 226, + 226, 64, 65, 255, 34, 237, 28, 2, 163, 125, 226, 226, 64, 65, 255, 34, + 237, 28, 2, 59, 125, 226, 226, 64, 45, 56, 226, 226, 64, 45, 65, 255, 34, + 235, 133, 77, 64, 65, 248, 44, 247, 192, 242, 223, 248, 56, 65, 153, 238, + 67, 242, 228, 248, 43, 65, 153, 238, 67, 88, 92, 64, 56, 38, 65, 2, 3, + 238, 51, 235, 45, 65, 139, 147, 226, 226, 56, 204, 77, 238, 104, 139, 65, + 2, 59, 108, 77, 65, 2, 59, 108, 40, 38, 65, 2, 59, 108, 139, 65, 2, 45, + 59, 108, 77, 65, 2, 45, 59, 108, 40, 38, 65, 2, 45, 59, 108, 139, 233, + 72, 56, 77, 233, 72, 56, 40, 38, 233, 72, 56, 28, 249, 26, 233, 124, 238, + 100, 231, 90, 244, 29, 239, 58, 244, 29, 248, 86, 161, 241, 100, 243, 15, + 249, 160, 234, 205, 240, 79, 238, 68, 253, 174, 161, 255, 68, 238, 68, + 253, 174, 3, 238, 68, 253, 174, 236, 180, 255, 24, 238, 145, 248, 86, + 161, 238, 131, 255, 24, 238, 145, 3, 236, 180, 255, 24, 238, 145, 253, + 165, 147, 242, 66, 242, 238, 236, 170, 242, 238, 234, 50, 242, 238, 234, + 65, 242, 250, 52, 231, 148, 52, 53, 243, 12, 236, 196, 240, 37, 254, 30, + 240, 68, 236, 219, 235, 47, 248, 51, 235, 47, 241, 41, 235, 47, 31, 243, + 119, 250, 169, 243, 119, 240, 137, 243, 119, 232, 199, 87, 235, 101, 38, + 240, 54, 240, 54, 236, 168, 240, 54, 235, 109, 240, 54, 237, 112, 248, + 86, 161, 238, 177, 236, 200, 87, 161, 236, 200, 87, 238, 56, 248, 91, + 238, 56, 253, 227, 231, 88, 240, 58, 235, 60, 45, 235, 60, 240, 3, 235, + 60, 238, 132, 235, 60, 239, 210, 235, 60, 242, 180, 235, 60, 235, 62, + 235, 60, 235, 62, 238, 132, 235, 60, 231, 86, 238, 132, 235, 60, 235, 33, + 237, 74, 242, 78, 233, 96, 53, 240, 68, 239, 57, 236, 31, 233, 96, 233, + 206, 242, 219, 235, 47, 224, 169, 236, 145, 251, 187, 193, 252, 178, 243, + 80, 242, 186, 236, 170, 161, 169, 242, 250, 169, 231, 45, 95, 87, 161, + 231, 45, 95, 87, 231, 89, 95, 87, 231, 89, 253, 230, 161, 236, 244, 95, + 87, 238, 79, 231, 89, 253, 192, 236, 244, 95, 87, 240, 40, 95, 87, 161, + 240, 40, 95, 87, 240, 40, 95, 128, 95, 87, 240, 3, 169, 254, 51, 95, 87, + 234, 5, 87, 231, 105, 234, 5, 87, 234, 111, 236, 248, 234, 92, 253, 145, + 241, 216, 231, 105, 95, 87, 231, 89, 95, 153, 128, 253, 145, 243, 11, + 253, 174, 243, 11, 147, 128, 231, 89, 95, 87, 243, 14, 238, 113, 240, 7, + 240, 24, 248, 51, 255, 22, 95, 87, 248, 51, 95, 87, 233, 128, 87, 234, + 187, 233, 198, 87, 248, 135, 238, 113, 243, 92, 95, 87, 95, 153, 255, 25, + 233, 130, 236, 168, 254, 82, 234, 243, 95, 87, 161, 95, 87, 235, 89, 87, + 161, 235, 89, 87, 238, 17, 234, 5, 87, 235, 44, 128, 95, 87, 232, 68, + 128, 95, 87, 235, 44, 248, 59, 95, 87, 232, 68, 248, 59, 95, 87, 235, 44, + 253, 230, 161, 95, 87, 232, 68, 253, 230, 161, 95, 87, 248, 168, 234, 3, + 248, 168, 231, 85, 236, 248, 161, 234, 5, 87, 161, 234, 3, 161, 231, 85, + 238, 79, 235, 44, 253, 192, 95, 87, 238, 79, 232, 68, 253, 192, 95, 87, + 235, 44, 128, 234, 5, 87, 232, 68, 128, 234, 5, 87, 238, 79, 235, 44, + 253, 192, 234, 5, 87, 238, 79, 232, 68, 253, 192, 234, 5, 87, 235, 44, + 128, 231, 85, 232, 68, 128, 234, 3, 238, 79, 235, 44, 253, 192, 231, 85, + 238, 79, 232, 68, 253, 192, 234, 3, 235, 107, 235, 111, 236, 176, 128, + 95, 87, 236, 178, 128, 95, 87, 236, 176, 128, 234, 5, 87, 236, 178, 128, + 234, 5, 87, 248, 86, 161, 237, 240, 248, 86, 161, 238, 19, 240, 26, 253, + 174, 236, 154, 253, 174, 161, 134, 240, 26, 253, 174, 161, 134, 236, 154, + 253, 174, 240, 26, 147, 128, 95, 87, 236, 154, 147, 128, 95, 87, 238, 79, + 134, 240, 26, 147, 253, 192, 95, 87, 238, 79, 134, 236, 154, 147, 253, + 192, 95, 87, 240, 26, 147, 2, 161, 95, 87, 236, 154, 147, 2, 161, 95, 87, + 236, 62, 237, 24, 231, 26, 237, 24, 240, 58, 31, 243, 11, 253, 174, 31, + 236, 209, 253, 174, 31, 243, 11, 147, 128, 95, 87, 31, 236, 209, 147, + 128, 95, 87, 31, 249, 38, 31, 249, 43, 29, 243, 12, 29, 240, 68, 29, 240, + 123, 29, 236, 196, 240, 37, 29, 53, 235, 47, 29, 248, 51, 235, 47, 29, + 236, 219, 235, 47, 29, 238, 113, 29, 242, 235, 238, 84, 243, 12, 238, 84, + 240, 68, 238, 84, 240, 123, 238, 84, 53, 235, 47, 38, 242, 234, 40, 242, + 234, 92, 242, 234, 88, 242, 234, 234, 94, 239, 139, 244, 38, 239, 78, + 240, 3, 59, 253, 144, 38, 234, 15, 45, 59, 253, 144, 45, 38, 234, 15, + 248, 86, 161, 242, 67, 161, 244, 38, 248, 86, 161, 241, 114, 238, 203, + 45, 59, 253, 144, 45, 38, 234, 15, 236, 176, 244, 44, 235, 92, 236, 178, + 244, 44, 235, 92, 240, 52, 236, 203, 253, 174, 236, 180, 255, 24, 240, + 52, 235, 144, 240, 52, 236, 203, 147, 128, 95, 87, 236, 180, 255, 24, + 240, 52, 236, 203, 128, 95, 87, 236, 209, 253, 174, 243, 11, 253, 174, + 235, 103, 236, 35, 235, 193, 239, 130, 232, 178, 253, 49, 246, 104, 252, + 34, 38, 185, 2, 248, 113, 38, 235, 46, 242, 238, 238, 56, 248, 91, 242, + 238, 238, 56, 253, 227, 242, 238, 231, 88, 242, 238, 240, 58, 238, 76, + 235, 47, 53, 235, 47, 248, 135, 235, 47, 236, 196, 240, 123, 238, 168, + 40, 240, 52, 240, 173, 234, 21, 236, 170, 38, 240, 52, 240, 173, 234, 21, + 236, 170, 40, 234, 21, 236, 170, 38, 234, 21, 236, 170, 224, 242, 219, + 238, 113, 242, 225, 238, 56, 253, 227, 242, 225, 238, 56, 248, 91, 45, + 238, 87, 45, 235, 84, 45, 231, 88, 45, 240, 58, 234, 234, 95, 19, 236, + 200, 87, 235, 44, 2, 248, 40, 232, 68, 2, 248, 40, 249, 194, 248, 168, + 234, 3, 249, 194, 248, 168, 231, 85, 235, 44, 95, 153, 128, 231, 85, 232, + 68, 95, 153, 128, 234, 3, 95, 153, 128, 234, 3, 95, 153, 128, 231, 85, + 95, 153, 128, 235, 107, 95, 153, 128, 235, 111, 248, 86, 161, 239, 165, + 128, 240, 32, 248, 86, 161, 239, 209, 128, 240, 32, 161, 31, 243, 11, + 147, 128, 95, 87, 161, 31, 236, 209, 147, 128, 95, 87, 31, 243, 11, 147, + 128, 161, 95, 87, 31, 236, 209, 147, 128, 161, 95, 87, 235, 44, 253, 230, + 161, 234, 5, 87, 232, 68, 253, 230, 161, 234, 5, 87, 236, 176, 253, 230, + 161, 234, 5, 87, 236, 178, 253, 230, 161, 234, 5, 87, 161, 240, 52, 236, + 203, 253, 174, 248, 86, 161, 238, 131, 255, 24, 240, 52, 235, 144, 161, + 240, 52, 236, 203, 147, 128, 95, 87, 248, 86, 161, 238, 131, 255, 24, + 240, 52, 236, 203, 128, 240, 32, 59, 235, 69, 239, 136, 163, 235, 69, 88, + 38, 236, 159, 235, 69, 92, 38, 236, 159, 235, 69, 238, 68, 147, 2, 183, + 163, 108, 238, 68, 147, 2, 59, 253, 144, 255, 31, 253, 165, 147, 163, + 108, 3, 238, 68, 147, 2, 59, 253, 144, 255, 31, 253, 165, 147, 163, 108, + 238, 68, 147, 2, 53, 48, 238, 68, 147, 2, 236, 163, 3, 238, 68, 147, 2, + 236, 163, 238, 68, 147, 2, 235, 50, 238, 68, 147, 2, 171, 163, 237, 45, + 236, 180, 2, 183, 163, 108, 236, 180, 2, 59, 253, 144, 255, 31, 253, 165, + 147, 163, 108, 3, 236, 180, 2, 59, 253, 144, 255, 31, 253, 165, 147, 163, + 108, 236, 180, 2, 236, 163, 3, 236, 180, 2, 236, 163, 255, 97, 126, 254, + 52, 233, 217, 237, 105, 52, 237, 149, 56, 241, 168, 88, 234, 7, 92, 234, + 7, 233, 226, 232, 193, 248, 103, 242, 224, 40, 236, 251, 38, 236, 251, + 40, 240, 175, 38, 240, 175, 240, 17, 38, 243, 55, 240, 17, 40, 243, 55, + 253, 159, 38, 243, 55, 253, 159, 40, 243, 55, 224, 161, 52, 31, 236, 231, + 248, 113, 238, 4, 239, 187, 235, 113, 236, 87, 237, 239, 234, 30, 238, + 42, 238, 59, 243, 245, 147, 237, 181, 52, 205, 161, 52, 240, 252, 234, + 39, 253, 159, 40, 238, 67, 253, 159, 38, 238, 67, 240, 17, 40, 238, 67, + 240, 17, 38, 238, 67, 253, 159, 137, 235, 60, 240, 17, 137, 235, 60, 241, + 118, 242, 118, 88, 235, 76, 239, 7, 171, 163, 244, 191, 242, 42, 251, + 145, 243, 169, 153, 253, 145, 225, 255, 113, 255, 22, 134, 236, 89, 248, + 92, 236, 45, 231, 87, 185, 104, 231, 36, 185, 104, 243, 169, 153, 253, + 145, 242, 220, 239, 6, 242, 233, 231, 121, 254, 51, 229, 64, 236, 125, + 247, 156, 239, 175, 235, 205, 239, 154, 239, 31, 242, 141, 242, 116, 232, + 124, 232, 125, 141, 142, 12, 239, 96, 141, 142, 12, 242, 127, 243, 43, + 141, 142, 12, 248, 62, 240, 32, 141, 142, 12, 248, 62, 238, 177, 141, + 142, 12, 248, 62, 236, 164, 141, 142, 12, 248, 62, 248, 115, 141, 142, + 12, 248, 62, 238, 51, 141, 142, 12, 218, 240, 103, 141, 142, 12, 218, + 248, 115, 141, 142, 12, 247, 94, 125, 141, 142, 12, 235, 177, 125, 141, + 142, 12, 248, 62, 240, 37, 141, 142, 12, 248, 62, 234, 25, 141, 142, 12, + 248, 62, 234, 3, 141, 142, 12, 248, 62, 231, 85, 141, 142, 12, 139, 243, + 79, 141, 142, 12, 77, 243, 79, 141, 142, 12, 248, 62, 139, 56, 141, 142, + 12, 248, 62, 77, 56, 141, 142, 12, 218, 234, 25, 141, 142, 12, 92, 248, + 84, 235, 50, 141, 142, 12, 243, 92, 240, 103, 141, 142, 12, 248, 62, 92, + 240, 130, 141, 142, 12, 248, 62, 240, 28, 141, 142, 12, 92, 248, 84, 248, + 115, 141, 142, 12, 226, 226, 243, 79, 141, 142, 12, 248, 62, 226, 226, + 56, 141, 142, 12, 88, 248, 84, 236, 163, 141, 142, 12, 254, 56, 240, 103, + 141, 142, 12, 248, 62, 88, 240, 130, 141, 142, 12, 248, 62, 250, 189, + 141, 142, 12, 88, 248, 84, 248, 115, 141, 142, 12, 235, 45, 243, 79, 141, + 142, 12, 248, 62, 235, 45, 56, 141, 142, 12, 243, 249, 235, 50, 141, 142, + 12, 243, 92, 235, 50, 141, 142, 12, 238, 76, 235, 50, 141, 142, 12, 254, + 104, 235, 50, 141, 142, 12, 218, 235, 50, 141, 142, 12, 88, 248, 247, + 248, 115, 141, 142, 12, 243, 249, 243, 43, 141, 142, 12, 218, 242, 229, + 141, 142, 12, 248, 62, 240, 24, 141, 142, 12, 88, 248, 84, 175, 141, 142, + 12, 254, 56, 175, 141, 142, 12, 248, 135, 175, 141, 142, 12, 254, 104, + 175, 141, 142, 12, 218, 175, 141, 142, 12, 92, 248, 247, 240, 103, 141, + 142, 12, 40, 248, 247, 240, 103, 141, 142, 12, 242, 219, 175, 141, 142, + 12, 232, 68, 175, 141, 142, 12, 242, 244, 125, 141, 142, 12, 254, 56, + 169, 141, 142, 12, 242, 207, 141, 142, 12, 247, 122, 169, 141, 142, 12, + 236, 99, 235, 50, 141, 142, 12, 248, 62, 161, 240, 32, 141, 142, 12, 248, + 62, 236, 85, 141, 142, 12, 92, 243, 25, 169, 141, 142, 12, 88, 243, 25, + 169, 141, 142, 12, 242, 237, 141, 142, 12, 248, 73, 141, 142, 12, 240, + 20, 141, 142, 12, 194, 235, 50, 141, 142, 12, 238, 57, 235, 50, 141, 142, + 12, 248, 42, 235, 50, 141, 142, 12, 211, 235, 50, 141, 142, 12, 240, 22, + 161, 243, 53, 69, 38, 185, 2, 235, 45, 240, 126, 56, 235, 0, 248, 35, + 248, 92, 250, 114, 91, 59, 248, 41, 2, 240, 1, 248, 40, 235, 128, 91, + 234, 104, 235, 157, 91, 231, 128, 235, 157, 91, 237, 8, 91, 233, 126, 91, + 64, 31, 2, 240, 46, 59, 242, 224, 245, 82, 91, 233, 68, 254, 105, 91, + 251, 51, 91, 29, 163, 253, 144, 2, 242, 23, 29, 236, 152, 242, 236, 240, + 129, 218, 2, 236, 64, 56, 252, 252, 91, 234, 224, 91, 234, 201, 91, 226, + 236, 241, 143, 91, 226, 236, 241, 209, 91, 226, 227, 91, 226, 230, 91, + 240, 169, 239, 33, 12, 248, 38, 111, 227, 7, 91, 141, 142, 12, 243, 43, + 238, 176, 235, 95, 254, 105, 91, 237, 242, 243, 240, 252, 16, 243, 240, + 246, 254, 240, 218, 91, 245, 23, 240, 218, 91, 40, 233, 56, 189, 90, 40, + 233, 56, 234, 10, 40, 233, 56, 168, 90, 38, 233, 56, 189, 90, 38, 233, + 56, 234, 10, 38, 233, 56, 168, 90, 40, 31, 238, 52, 189, 238, 67, 40, 31, + 238, 52, 234, 10, 40, 31, 238, 52, 168, 238, 67, 38, 31, 238, 52, 189, + 238, 67, 38, 31, 238, 52, 234, 10, 38, 31, 238, 52, 168, 238, 67, 40, + 242, 225, 238, 52, 189, 90, 40, 242, 225, 238, 52, 240, 1, 240, 119, 40, + 242, 225, 238, 52, 168, 90, 242, 225, 238, 52, 234, 10, 38, 242, 225, + 238, 52, 189, 90, 38, 242, 225, 238, 52, 240, 1, 240, 119, 38, 242, 225, + 238, 52, 168, 90, 236, 167, 234, 10, 163, 248, 41, 234, 10, 189, 40, 128, + 168, 38, 242, 225, 238, 52, 236, 210, 189, 38, 128, 168, 40, 242, 225, + 238, 52, 236, 210, 235, 112, 249, 3, 235, 112, 238, 128, 253, 159, 31, + 104, 240, 17, 31, 104, 240, 17, 31, 238, 52, 248, 59, 253, 159, 31, 104, + 25, 12, 238, 128, 40, 59, 66, 242, 224, 38, 59, 66, 242, 224, 163, 248, + 183, 239, 119, 163, 248, 183, 239, 120, 163, 248, 183, 239, 121, 163, + 248, 183, 239, 122, 235, 58, 12, 136, 59, 19, 253, 159, 225, 235, 58, 12, + 136, 59, 19, 240, 17, 225, 235, 58, 12, 136, 59, 2, 238, 51, 235, 58, 12, + 136, 92, 19, 163, 2, 238, 51, 235, 58, 12, 136, 88, 19, 163, 2, 238, 51, + 235, 58, 12, 136, 59, 2, 235, 46, 235, 58, 12, 136, 92, 19, 163, 2, 235, + 46, 235, 58, 12, 136, 88, 19, 163, 2, 235, 46, 235, 58, 12, 136, 59, 19, + 243, 80, 235, 58, 12, 136, 92, 19, 163, 2, 243, 80, 235, 58, 12, 136, 88, + 19, 163, 2, 243, 80, 235, 58, 12, 136, 92, 19, 233, 50, 235, 58, 12, 136, + 88, 19, 233, 50, 235, 58, 12, 136, 59, 19, 253, 159, 242, 220, 235, 58, + 12, 136, 59, 19, 240, 17, 242, 220, 31, 243, 94, 242, 80, 91, 245, 81, + 91, 59, 248, 41, 234, 10, 236, 183, 239, 255, 236, 183, 183, 248, 59, + 242, 108, 236, 183, 242, 215, 248, 59, 243, 66, 236, 183, 183, 248, 59, + 171, 239, 194, 236, 183, 171, 240, 228, 248, 59, 243, 66, 236, 183, 171, + 240, 228, 239, 103, 236, 183, 237, 49, 236, 183, 234, 82, 236, 183, 234, + 62, 243, 168, 239, 85, 245, 94, 12, 28, 246, 193, 12, 28, 243, 124, 147, + 237, 173, 12, 28, 243, 124, 147, 244, 28, 12, 28, 253, 165, 147, 244, 28, + 12, 28, 253, 165, 147, 232, 62, 12, 28, 237, 150, 12, 28, 232, 103, 12, + 28, 244, 215, 12, 28, 234, 96, 12, 28, 163, 233, 107, 12, 28, 248, 41, + 243, 171, 12, 28, 59, 233, 107, 12, 28, 248, 38, 243, 171, 12, 28, 237, + 84, 238, 211, 12, 28, 244, 11, 248, 235, 12, 28, 244, 11, 253, 247, 12, + 28, 250, 185, 251, 197, 238, 183, 12, 28, 240, 113, 238, 110, 127, 12, + 28, 240, 113, 238, 110, 111, 12, 28, 240, 113, 238, 110, 166, 12, 28, + 240, 113, 238, 110, 177, 12, 28, 236, 146, 232, 103, 12, 28, 233, 250, + 245, 224, 12, 28, 253, 165, 147, 233, 44, 240, 13, 12, 28, 239, 16, 12, + 28, 253, 165, 147, 239, 132, 12, 28, 233, 249, 12, 28, 238, 183, 12, 28, + 250, 244, 234, 6, 12, 28, 245, 128, 234, 6, 12, 28, 242, 79, 234, 6, 12, + 28, 252, 253, 234, 6, 12, 28, 240, 15, 12, 28, 239, 39, 244, 224, 91, + 248, 35, 248, 92, 12, 28, 237, 219, 12, 28, 241, 81, 248, 38, 111, 12, + 28, 235, 5, 248, 38, 111, 253, 207, 90, 253, 207, 241, 50, 253, 207, 243, + 175, 253, 207, 236, 145, 243, 175, 253, 207, 250, 115, 239, 15, 253, 207, + 254, 146, 248, 139, 253, 207, 241, 36, 250, 102, 229, 67, 253, 207, 241, + 9, 147, 240, 162, 253, 207, 242, 235, 253, 207, 237, 97, 238, 158, 239, + 147, 253, 207, 45, 234, 25, 29, 26, 127, 29, 26, 111, 29, 26, 166, 29, + 26, 177, 29, 26, 176, 29, 26, 187, 29, 26, 203, 29, 26, 195, 29, 26, 202, + 29, 61, 248, 53, 29, 61, 238, 91, 29, 61, 238, 97, 29, 61, 235, 85, 29, + 61, 235, 82, 29, 61, 236, 207, 29, 61, 236, 202, 29, 61, 234, 22, 29, 61, + 235, 81, 29, 61, 235, 83, 29, 61, 238, 77, 82, 26, 127, 82, 26, 111, 82, + 26, 166, 82, 26, 177, 82, 26, 176, 82, 26, 187, 82, 26, 203, 82, 26, 195, + 82, 26, 202, 82, 61, 248, 53, 82, 61, 238, 91, 82, 61, 238, 97, 82, 61, + 235, 85, 82, 61, 235, 82, 82, 61, 236, 207, 82, 61, 236, 202, 82, 61, + 234, 22, 82, 61, 235, 81, 82, 61, 235, 83, 82, 61, 238, 77, 26, 253, 125, + 248, 37, 208, 26, 171, 248, 37, 208, 26, 204, 248, 37, 208, 26, 248, 58, + 248, 37, 208, 26, 248, 48, 248, 37, 208, 26, 254, 31, 248, 37, 208, 26, + 243, 31, 248, 37, 208, 26, 242, 254, 248, 37, 208, 26, 248, 173, 248, 37, + 208, 61, 253, 219, 248, 37, 208, 61, 241, 93, 248, 37, 208, 61, 240, 251, + 248, 37, 208, 61, 238, 26, 248, 37, 208, 61, 237, 161, 248, 37, 208, 61, + 239, 70, 248, 37, 208, 61, 238, 216, 248, 37, 208, 61, 236, 100, 248, 37, + 208, 61, 237, 147, 248, 37, 208, 61, 237, 222, 248, 37, 208, 61, 240, 48, + 248, 37, 208, 82, 8, 3, 1, 67, 82, 8, 3, 1, 217, 82, 8, 3, 1, 255, 18, + 82, 8, 3, 1, 209, 82, 8, 3, 1, 72, 82, 8, 3, 1, 255, 19, 82, 8, 3, 1, + 210, 82, 8, 3, 1, 192, 82, 8, 3, 1, 71, 82, 8, 3, 1, 221, 82, 8, 3, 1, + 255, 15, 82, 8, 3, 1, 162, 82, 8, 3, 1, 173, 82, 8, 3, 1, 197, 82, 8, 3, + 1, 73, 82, 8, 3, 1, 223, 82, 8, 3, 1, 255, 20, 82, 8, 3, 1, 144, 82, 8, + 3, 1, 193, 82, 8, 3, 1, 214, 82, 8, 3, 1, 79, 82, 8, 3, 1, 179, 82, 8, 3, + 1, 255, 16, 82, 8, 3, 1, 206, 82, 8, 3, 1, 255, 14, 82, 8, 3, 1, 255, 17, + 29, 8, 5, 1, 67, 29, 8, 5, 1, 217, 29, 8, 5, 1, 255, 18, 29, 8, 5, 1, + 209, 29, 8, 5, 1, 72, 29, 8, 5, 1, 255, 19, 29, 8, 5, 1, 210, 29, 8, 5, + 1, 192, 29, 8, 5, 1, 71, 29, 8, 5, 1, 221, 29, 8, 5, 1, 255, 15, 29, 8, + 5, 1, 162, 29, 8, 5, 1, 173, 29, 8, 5, 1, 197, 29, 8, 5, 1, 73, 29, 8, 5, + 1, 223, 29, 8, 5, 1, 255, 20, 29, 8, 5, 1, 144, 29, 8, 5, 1, 193, 29, 8, + 5, 1, 214, 29, 8, 5, 1, 79, 29, 8, 5, 1, 179, 29, 8, 5, 1, 255, 16, 29, + 8, 5, 1, 206, 29, 8, 5, 1, 255, 14, 29, 8, 5, 1, 255, 17, 29, 8, 3, 1, + 67, 29, 8, 3, 1, 217, 29, 8, 3, 1, 255, 18, 29, 8, 3, 1, 209, 29, 8, 3, + 1, 72, 29, 8, 3, 1, 255, 19, 29, 8, 3, 1, 210, 29, 8, 3, 1, 192, 29, 8, + 3, 1, 71, 29, 8, 3, 1, 221, 29, 8, 3, 1, 255, 15, 29, 8, 3, 1, 162, 29, + 8, 3, 1, 173, 29, 8, 3, 1, 197, 29, 8, 3, 1, 73, 29, 8, 3, 1, 223, 29, 8, + 3, 1, 255, 20, 29, 8, 3, 1, 144, 29, 8, 3, 1, 193, 29, 8, 3, 1, 214, 29, + 8, 3, 1, 79, 29, 8, 3, 1, 179, 29, 8, 3, 1, 255, 16, 29, 8, 3, 1, 206, + 29, 8, 3, 1, 255, 14, 29, 8, 3, 1, 255, 17, 29, 26, 242, 217, 236, 146, + 29, 61, 238, 91, 236, 146, 29, 61, 238, 97, 236, 146, 29, 61, 235, 85, + 236, 146, 29, 61, 235, 82, 236, 146, 29, 61, 236, 207, 236, 146, 29, 61, + 236, 202, 236, 146, 29, 61, 234, 22, 236, 146, 29, 61, 235, 81, 236, 146, + 29, 61, 235, 83, 236, 146, 29, 61, 238, 77, 45, 29, 26, 127, 45, 29, 26, + 111, 45, 29, 26, 166, 45, 29, 26, 177, 45, 29, 26, 176, 45, 29, 26, 187, + 45, 29, 26, 203, 45, 29, 26, 195, 45, 29, 26, 202, 45, 29, 61, 248, 53, + 236, 146, 29, 26, 242, 217, 66, 70, 136, 233, 50, 66, 70, 96, 233, 50, + 66, 70, 136, 235, 63, 66, 70, 96, 235, 63, 66, 70, 136, 240, 3, 248, 63, + 233, 50, 66, 70, 96, 240, 3, 248, 63, 233, 50, 66, 70, 136, 240, 3, 248, + 63, 235, 63, 66, 70, 96, 240, 3, 248, 63, 235, 63, 66, 70, 136, 235, 71, + 248, 63, 233, 50, 66, 70, 96, 235, 71, 248, 63, 233, 50, 66, 70, 136, + 235, 71, 248, 63, 235, 63, 66, 70, 96, 235, 71, 248, 63, 235, 63, 66, 70, + 136, 92, 19, 225, 66, 70, 92, 136, 19, 38, 240, 11, 66, 70, 92, 96, 19, + 38, 240, 9, 66, 70, 96, 92, 19, 225, 66, 70, 136, 92, 19, 242, 220, 66, + 70, 92, 136, 19, 40, 240, 11, 66, 70, 92, 96, 19, 40, 240, 9, 66, 70, 96, + 92, 19, 242, 220, 66, 70, 136, 88, 19, 225, 66, 70, 88, 136, 19, 38, 240, + 11, 66, 70, 88, 96, 19, 38, 240, 9, 66, 70, 96, 88, 19, 225, 66, 70, 136, + 88, 19, 242, 220, 66, 70, 88, 136, 19, 40, 240, 11, 66, 70, 88, 96, 19, + 40, 240, 9, 66, 70, 96, 88, 19, 242, 220, 66, 70, 136, 59, 19, 225, 66, + 70, 59, 136, 19, 38, 240, 11, 66, 70, 88, 96, 19, 38, 92, 240, 9, 66, 70, + 92, 96, 19, 38, 88, 240, 9, 66, 70, 59, 96, 19, 38, 240, 9, 66, 70, 92, + 136, 19, 38, 88, 240, 11, 66, 70, 88, 136, 19, 38, 92, 240, 11, 66, 70, + 96, 59, 19, 225, 66, 70, 136, 59, 19, 242, 220, 66, 70, 59, 136, 19, 40, + 240, 11, 66, 70, 88, 96, 19, 40, 92, 240, 9, 66, 70, 92, 96, 19, 40, 88, + 240, 9, 66, 70, 59, 96, 19, 40, 240, 9, 66, 70, 92, 136, 19, 40, 88, 240, + 11, 66, 70, 88, 136, 19, 40, 92, 240, 11, 66, 70, 96, 59, 19, 242, 220, + 66, 70, 136, 92, 19, 233, 50, 66, 70, 40, 96, 19, 38, 92, 240, 9, 66, 70, + 38, 96, 19, 40, 92, 240, 9, 66, 70, 92, 136, 19, 163, 240, 11, 66, 70, + 92, 96, 19, 163, 240, 9, 66, 70, 38, 136, 19, 40, 92, 240, 11, 66, 70, + 40, 136, 19, 38, 92, 240, 11, 66, 70, 96, 92, 19, 233, 50, 66, 70, 136, + 88, 19, 233, 50, 66, 70, 40, 96, 19, 38, 88, 240, 9, 66, 70, 38, 96, 19, + 40, 88, 240, 9, 66, 70, 88, 136, 19, 163, 240, 11, 66, 70, 88, 96, 19, + 163, 240, 9, 66, 70, 38, 136, 19, 40, 88, 240, 11, 66, 70, 40, 136, 19, + 38, 88, 240, 11, 66, 70, 96, 88, 19, 233, 50, 66, 70, 136, 59, 19, 233, + 50, 66, 70, 40, 96, 19, 38, 59, 240, 9, 66, 70, 38, 96, 19, 40, 59, 240, + 9, 66, 70, 59, 136, 19, 163, 240, 11, 66, 70, 88, 96, 19, 92, 163, 240, + 9, 66, 70, 92, 96, 19, 88, 163, 240, 9, 66, 70, 59, 96, 19, 163, 240, 9, + 66, 70, 40, 88, 96, 19, 38, 92, 240, 9, 66, 70, 38, 88, 96, 19, 40, 92, + 240, 9, 66, 70, 40, 92, 96, 19, 38, 88, 240, 9, 66, 70, 38, 92, 96, 19, + 40, 88, 240, 9, 66, 70, 92, 136, 19, 88, 163, 240, 11, 66, 70, 88, 136, + 19, 92, 163, 240, 11, 66, 70, 38, 136, 19, 40, 59, 240, 11, 66, 70, 40, + 136, 19, 38, 59, 240, 11, 66, 70, 96, 59, 19, 233, 50, 66, 70, 136, 45, + 248, 63, 233, 50, 66, 70, 96, 45, 248, 63, 233, 50, 66, 70, 136, 45, 248, + 63, 235, 63, 66, 70, 96, 45, 248, 63, 235, 63, 66, 70, 45, 233, 50, 66, + 70, 45, 235, 63, 66, 70, 92, 240, 12, 19, 38, 238, 78, 66, 70, 92, 45, + 19, 38, 238, 82, 66, 70, 45, 92, 19, 225, 66, 70, 92, 240, 12, 19, 40, + 238, 78, 66, 70, 92, 45, 19, 40, 238, 82, 66, 70, 45, 92, 19, 242, 220, + 66, 70, 88, 240, 12, 19, 38, 238, 78, 66, 70, 88, 45, 19, 38, 238, 82, + 66, 70, 45, 88, 19, 225, 66, 70, 88, 240, 12, 19, 40, 238, 78, 66, 70, + 88, 45, 19, 40, 238, 82, 66, 70, 45, 88, 19, 242, 220, 66, 70, 59, 240, + 12, 19, 38, 238, 78, 66, 70, 59, 45, 19, 38, 238, 82, 66, 70, 45, 59, 19, + 225, 66, 70, 59, 240, 12, 19, 40, 238, 78, 66, 70, 59, 45, 19, 40, 238, + 82, 66, 70, 45, 59, 19, 242, 220, 66, 70, 92, 240, 12, 19, 163, 238, 78, + 66, 70, 92, 45, 19, 163, 238, 82, 66, 70, 45, 92, 19, 233, 50, 66, 70, + 88, 240, 12, 19, 163, 238, 78, 66, 70, 88, 45, 19, 163, 238, 82, 66, 70, + 45, 88, 19, 233, 50, 66, 70, 59, 240, 12, 19, 163, 238, 78, 66, 70, 59, + 45, 19, 163, 238, 82, 66, 70, 45, 59, 19, 233, 50, 66, 70, 136, 253, 183, + 92, 19, 225, 66, 70, 136, 253, 183, 92, 19, 242, 220, 66, 70, 136, 253, + 183, 88, 19, 242, 220, 66, 70, 136, 253, 183, 88, 19, 225, 66, 70, 136, + 236, 159, 189, 38, 153, 168, 242, 220, 66, 70, 136, 236, 159, 189, 40, + 153, 168, 225, 66, 70, 136, 236, 159, 240, 34, 66, 70, 136, 242, 220, 66, + 70, 136, 253, 176, 66, 70, 136, 225, 66, 70, 136, 242, 236, 66, 70, 96, + 242, 220, 66, 70, 96, 253, 176, 66, 70, 96, 225, 66, 70, 96, 242, 236, + 66, 70, 136, 40, 19, 96, 225, 66, 70, 136, 88, 19, 96, 242, 236, 66, 70, + 96, 40, 19, 136, 225, 66, 70, 96, 88, 19, 136, 242, 236, 189, 137, 240, + 13, 168, 253, 125, 240, 62, 240, 13, 168, 253, 125, 238, 80, 240, 13, + 168, 204, 238, 98, 240, 13, 168, 137, 240, 13, 168, 248, 48, 238, 98, + 240, 13, 168, 204, 236, 236, 240, 13, 168, 243, 31, 238, 98, 240, 13, + 248, 37, 240, 13, 40, 243, 31, 238, 98, 240, 13, 40, 204, 236, 236, 240, + 13, 40, 248, 48, 238, 98, 240, 13, 40, 137, 240, 13, 40, 204, 238, 98, + 240, 13, 40, 253, 125, 238, 80, 240, 13, 40, 253, 125, 240, 62, 240, 13, + 38, 137, 240, 13, 136, 240, 146, 240, 19, 240, 146, 250, 183, 240, 146, + 189, 253, 125, 240, 62, 240, 13, 38, 253, 125, 240, 62, 240, 13, 236, + 158, 168, 242, 220, 236, 158, 168, 225, 236, 158, 189, 242, 220, 236, + 158, 189, 40, 19, 168, 40, 19, 168, 225, 236, 158, 189, 40, 19, 168, 225, + 236, 158, 189, 40, 19, 189, 38, 19, 168, 242, 220, 236, 158, 189, 40, 19, + 189, 38, 19, 168, 225, 236, 158, 189, 225, 236, 158, 189, 38, 19, 168, + 242, 220, 236, 158, 189, 38, 19, 168, 40, 19, 168, 225, 86, 238, 59, 64, + 238, 59, 64, 31, 2, 238, 121, 237, 0, 64, 31, 234, 34, 86, 3, 238, 59, + 31, 2, 163, 243, 19, 31, 2, 59, 243, 19, 31, 2, 234, 230, 234, 51, 243, + 19, 31, 2, 189, 40, 153, 168, 38, 243, 19, 31, 2, 189, 38, 153, 168, 40, + 243, 19, 31, 2, 236, 159, 234, 51, 243, 19, 86, 3, 238, 59, 64, 3, 238, + 59, 86, 234, 31, 64, 234, 31, 86, 59, 234, 31, 64, 59, 234, 31, 86, 231, + 48, 64, 231, 48, 86, 233, 60, 235, 46, 64, 233, 60, 235, 46, 86, 233, 60, + 3, 235, 46, 64, 233, 60, 3, 235, 46, 86, 231, 36, 235, 46, 64, 231, 36, + 235, 46, 86, 231, 36, 3, 235, 46, 64, 231, 36, 3, 235, 46, 86, 231, 36, + 236, 217, 64, 231, 36, 236, 217, 86, 231, 91, 235, 46, 64, 231, 91, 235, + 46, 86, 231, 91, 3, 235, 46, 64, 231, 91, 3, 235, 46, 86, 231, 87, 235, + 46, 64, 231, 87, 235, 46, 86, 231, 87, 3, 235, 46, 64, 231, 87, 3, 235, + 46, 86, 231, 87, 236, 217, 64, 231, 87, 236, 217, 86, 236, 164, 64, 236, + 164, 64, 238, 76, 234, 34, 86, 3, 236, 164, 237, 157, 236, 231, 64, 238, + 51, 240, 4, 238, 51, 218, 2, 59, 243, 19, 235, 183, 86, 238, 51, 218, 2, + 40, 137, 240, 0, 218, 2, 38, 137, 240, 0, 218, 2, 168, 137, 240, 0, 218, + 2, 189, 137, 240, 0, 218, 2, 189, 38, 236, 158, 240, 0, 218, 2, 254, 51, + 253, 230, 189, 40, 236, 158, 240, 0, 40, 137, 86, 238, 51, 38, 137, 86, + 238, 51, 238, 116, 238, 69, 238, 116, 64, 238, 51, 189, 137, 238, 116, + 64, 238, 51, 168, 137, 238, 116, 64, 238, 51, 189, 40, 236, 158, 236, + 211, 248, 113, 189, 38, 236, 158, 236, 211, 248, 113, 168, 38, 236, 158, + 236, 211, 248, 113, 168, 40, 236, 158, 236, 211, 248, 113, 189, 137, 238, + 51, 168, 137, 238, 51, 86, 168, 38, 235, 46, 86, 168, 40, 235, 46, 86, + 189, 40, 235, 46, 86, 189, 38, 235, 46, 64, 238, 69, 31, 2, 40, 137, 240, + 0, 31, 2, 38, 137, 240, 0, 31, 2, 189, 40, 236, 159, 137, 240, 0, 31, 2, + 168, 38, 236, 159, 137, 240, 0, 64, 31, 2, 59, 235, 180, 242, 224, 64, + 233, 60, 236, 152, 2, 248, 40, 233, 60, 236, 152, 2, 40, 137, 240, 0, + 233, 60, 236, 152, 2, 38, 137, 240, 0, 243, 22, 238, 51, 64, 31, 2, 189, + 40, 235, 70, 64, 31, 2, 168, 40, 235, 70, 64, 31, 2, 168, 38, 235, 70, + 64, 31, 2, 189, 38, 235, 70, 64, 218, 2, 189, 40, 235, 70, 64, 218, 2, + 168, 40, 235, 70, 64, 218, 2, 168, 38, 235, 70, 64, 218, 2, 189, 38, 235, + 70, 189, 40, 235, 46, 189, 38, 235, 46, 168, 40, 235, 46, 64, 240, 19, + 238, 59, 86, 240, 19, 238, 59, 64, 240, 19, 3, 238, 59, 86, 240, 19, 3, + 238, 59, 168, 38, 235, 46, 86, 254, 126, 2, 243, 251, 241, 61, 236, 135, + 238, 9, 241, 64, 86, 242, 229, 64, 242, 229, 234, 219, 232, 60, 248, 136, + 235, 172, 243, 235, 234, 110, 243, 235, 232, 120, 233, 73, 86, 234, 81, + 64, 234, 81, 240, 91, 248, 92, 240, 91, 66, 2, 240, 162, 240, 91, 66, 2, + 206, 237, 255, 238, 38, 2, 252, 128, 241, 90, 254, 96, 235, 178, 64, 244, + 12, 240, 119, 86, 244, 12, 240, 119, 236, 101, 224, 238, 120, 240, 135, + 243, 16, 238, 69, 86, 40, 236, 150, 240, 76, 86, 38, 236, 150, 240, 76, + 64, 40, 236, 150, 240, 76, 64, 88, 236, 150, 240, 76, 64, 38, 236, 150, + 240, 76, 64, 92, 236, 150, 240, 76, 247, 92, 19, 233, 129, 239, 19, 52, + 233, 227, 52, 235, 179, 52, 235, 185, 244, 81, 237, 228, 240, 34, 254, + 83, 248, 73, 243, 38, 147, 236, 53, 243, 38, 147, 234, 210, 248, 135, 19, + 235, 196, 243, 26, 91, 254, 139, 239, 192, 240, 185, 19, 239, 196, 246, + 239, 91, 254, 15, 243, 50, 238, 89, 28, 238, 139, 238, 89, 28, 243, 213, + 238, 89, 28, 243, 27, 238, 89, 28, 237, 48, 238, 89, 28, 243, 82, 238, + 89, 28, 240, 105, 238, 89, 28, 235, 102, 238, 89, 28, 240, 49, 247, 195, + 147, 239, 42, 64, 237, 162, 243, 39, 64, 238, 219, 243, 39, 86, 238, 219, + 243, 39, 64, 254, 126, 2, 243, 251, 243, 41, 238, 80, 243, 30, 251, 184, + 238, 80, 243, 30, 237, 208, 240, 96, 52, 240, 49, 248, 95, 52, 237, 185, + 239, 180, 239, 236, 237, 218, 242, 62, 241, 15, 239, 215, 239, 81, 239, + 17, 251, 188, 242, 179, 241, 215, 236, 98, 232, 203, 234, 99, 235, 167, + 239, 163, 64, 242, 252, 243, 208, 64, 242, 252, 240, 213, 64, 242, 252, + 244, 0, 64, 242, 252, 238, 167, 64, 242, 252, 238, 196, 64, 242, 252, + 243, 241, 86, 242, 252, 243, 208, 86, 242, 252, 240, 213, 86, 242, 252, + 244, 0, 86, 242, 252, 238, 167, 86, 242, 252, 238, 196, 86, 242, 252, + 243, 241, 86, 244, 22, 243, 17, 64, 243, 16, 243, 17, 64, 238, 76, 243, + 17, 86, 249, 41, 243, 17, 64, 244, 22, 243, 17, 86, 243, 16, 243, 17, 86, + 238, 76, 243, 17, 64, 249, 41, 243, 17, 254, 96, 238, 11, 238, 80, 243, + 9, 240, 62, 243, 9, 240, 157, 240, 62, 240, 203, 240, 157, 235, 108, 240, + 203, 243, 108, 248, 209, 52, 243, 108, 238, 146, 52, 243, 108, 243, 74, + 52, 248, 56, 129, 240, 34, 248, 43, 129, 240, 34, 235, 159, 235, 65, 91, + 235, 65, 12, 28, 242, 164, 235, 75, 235, 65, 12, 28, 242, 165, 235, 75, + 235, 65, 12, 28, 242, 166, 235, 75, 235, 65, 12, 28, 242, 167, 235, 75, + 235, 65, 12, 28, 242, 168, 235, 75, 235, 65, 12, 28, 242, 169, 235, 75, + 235, 65, 12, 28, 242, 170, 235, 75, 235, 65, 12, 28, 239, 82, 234, 221, + 86, 235, 159, 235, 65, 91, 237, 249, 243, 113, 91, 226, 250, 243, 113, + 91, 236, 74, 243, 113, 52, 235, 41, 91, 254, 2, 239, 60, 254, 2, 239, 61, + 254, 2, 239, 62, 254, 2, 239, 63, 254, 2, 239, 64, 254, 2, 239, 65, 64, + 218, 2, 53, 225, 64, 218, 2, 171, 243, 5, 86, 218, 2, 64, 53, 225, 86, + 218, 2, 171, 64, 243, 5, 236, 184, 28, 243, 50, 236, 184, 28, 249, 23, + 240, 56, 28, 238, 188, 243, 50, 240, 56, 28, 240, 198, 249, 23, 240, 56, + 28, 240, 198, 243, 50, 240, 56, 28, 238, 188, 249, 23, 64, 243, 173, 86, + 243, 173, 240, 185, 19, 246, 248, 238, 159, 238, 133, 239, 211, 244, 24, + 147, 232, 113, 239, 181, 237, 58, 239, 77, 245, 98, 244, 24, 147, 239, + 92, 249, 242, 91, 231, 138, 239, 246, 52, 200, 239, 245, 52, 238, 179, + 240, 96, 52, 238, 179, 248, 95, 52, 233, 212, 240, 96, 19, 248, 95, 52, + 248, 95, 19, 240, 96, 52, 248, 95, 2, 240, 5, 52, 248, 95, 2, 240, 5, 19, + 248, 95, 19, 240, 96, 52, 59, 248, 95, 2, 240, 5, 52, 163, 248, 95, 2, + 240, 5, 52, 240, 19, 64, 238, 51, 240, 19, 86, 238, 51, 240, 19, 3, 64, + 238, 51, 237, 202, 91, 239, 45, 91, 236, 137, 233, 94, 91, 239, 30, 239, + 79, 253, 3, 189, 243, 148, 235, 93, 86, 235, 93, 168, 243, 148, 235, 93, + 64, 235, 93, 235, 113, 237, 195, 52, 252, 210, 241, 89, 235, 162, 236, + 12, 239, 242, 243, 59, 239, 249, 243, 59, 168, 38, 238, 148, 238, 148, + 189, 38, 238, 148, 64, 249, 120, 86, 249, 120, 243, 53, 69, 96, 243, 53, + 69, 231, 37, 206, 96, 231, 37, 206, 240, 91, 206, 96, 240, 91, 206, 236, + 199, 17, 240, 34, 96, 17, 240, 34, 248, 35, 240, 46, 240, 34, 96, 248, + 35, 240, 46, 240, 34, 8, 240, 34, 236, 189, 64, 8, 240, 34, 236, 199, 8, + 240, 34, 239, 126, 240, 34, 248, 135, 147, 241, 74, 248, 58, 229, 58, + 235, 52, 248, 58, 231, 39, 235, 52, 96, 248, 58, 231, 39, 235, 52, 248, + 58, 233, 123, 235, 52, 86, 248, 58, 238, 74, 242, 229, 64, 248, 58, 238, + 74, 242, 229, 240, 148, 236, 199, 64, 242, 229, 29, 64, 242, 229, 248, + 35, 240, 46, 86, 242, 229, 86, 240, 46, 64, 242, 229, 236, 199, 86, 242, + 229, 96, 236, 199, 86, 242, 229, 236, 235, 242, 229, 236, 189, 64, 242, + 229, 96, 235, 52, 248, 35, 240, 46, 235, 52, 242, 254, 242, 124, 235, 52, + 242, 254, 238, 74, 86, 242, 229, 242, 254, 238, 74, 236, 235, 242, 229, + 254, 31, 238, 74, 86, 242, 229, 242, 254, 238, 74, 233, 98, 86, 242, 229, + 96, 242, 254, 238, 74, 233, 98, 86, 242, 229, 240, 251, 238, 74, 86, 242, + 229, 238, 216, 238, 74, 235, 52, 229, 58, 235, 52, 248, 35, 240, 46, 229, + 58, 235, 52, 96, 229, 58, 235, 52, 254, 31, 237, 30, 86, 19, 64, 235, 88, + 86, 235, 88, 64, 235, 88, 242, 254, 237, 30, 236, 199, 86, 235, 88, 29, + 248, 35, 240, 46, 242, 254, 238, 74, 242, 229, 96, 229, 58, 236, 235, + 235, 52, 234, 42, 247, 150, 235, 35, 234, 42, 96, 239, 23, 234, 42, 237, + 42, 96, 237, 42, 231, 39, 235, 52, 242, 254, 229, 58, 235, 139, 235, 52, + 96, 242, 254, 229, 58, 235, 139, 235, 52, 236, 189, 64, 238, 51, 168, 38, + 231, 103, 64, 238, 59, 189, 38, 231, 103, 64, 238, 59, 168, 38, 236, 189, + 64, 238, 59, 189, 38, 236, 189, 64, 238, 59, 86, 238, 76, 242, 250, 64, + 206, 136, 59, 125, 240, 19, 59, 125, 96, 59, 125, 96, 240, 12, 205, 242, + 244, 235, 51, 158, 235, 53, 96, 240, 12, 242, 244, 235, 51, 158, 235, 53, + 96, 45, 205, 242, 244, 235, 51, 158, 235, 53, 96, 45, 242, 244, 235, 51, + 158, 235, 53, 240, 95, 252, 190, 235, 91, 21, 235, 53, 96, 233, 54, 158, + 235, 53, 96, 243, 16, 233, 54, 158, 235, 53, 96, 86, 240, 138, 238, 120, + 96, 86, 243, 16, 238, 69, 240, 135, 240, 138, 238, 120, 240, 135, 243, + 16, 238, 69, 240, 19, 40, 233, 56, 235, 53, 240, 19, 38, 233, 56, 235, + 53, 240, 19, 235, 122, 40, 233, 56, 235, 53, 240, 19, 235, 122, 38, 233, + 56, 235, 53, 240, 19, 231, 87, 185, 238, 52, 235, 53, 240, 19, 231, 36, + 185, 238, 52, 235, 53, 96, 231, 87, 185, 235, 51, 158, 235, 53, 96, 231, + 36, 185, 235, 51, 158, 235, 53, 96, 231, 87, 185, 238, 52, 235, 53, 96, + 231, 36, 185, 238, 52, 235, 53, 136, 40, 236, 171, 242, 255, 238, 52, + 235, 53, 136, 38, 236, 171, 242, 255, 238, 52, 235, 53, 240, 19, 40, 242, + 225, 238, 52, 235, 53, 240, 19, 38, 242, 225, 238, 52, 235, 53, 238, 55, + 236, 146, 29, 26, 127, 238, 55, 236, 146, 29, 26, 111, 238, 55, 236, 146, + 29, 26, 166, 238, 55, 236, 146, 29, 26, 177, 238, 55, 236, 146, 29, 26, + 176, 238, 55, 236, 146, 29, 26, 187, 238, 55, 236, 146, 29, 26, 203, 238, + 55, 236, 146, 29, 26, 195, 238, 55, 236, 146, 29, 26, 202, 238, 55, 236, + 146, 29, 61, 248, 53, 238, 55, 29, 27, 26, 127, 238, 55, 29, 27, 26, 111, + 238, 55, 29, 27, 26, 166, 238, 55, 29, 27, 26, 177, 238, 55, 29, 27, 26, + 176, 238, 55, 29, 27, 26, 187, 238, 55, 29, 27, 26, 203, 238, 55, 29, 27, + 26, 195, 238, 55, 29, 27, 26, 202, 238, 55, 29, 27, 61, 248, 53, 238, 55, + 236, 146, 29, 27, 26, 127, 238, 55, 236, 146, 29, 27, 26, 111, 238, 55, + 236, 146, 29, 27, 26, 166, 238, 55, 236, 146, 29, 27, 26, 177, 238, 55, + 236, 146, 29, 27, 26, 176, 238, 55, 236, 146, 29, 27, 26, 187, 238, 55, + 236, 146, 29, 27, 26, 203, 238, 55, 236, 146, 29, 27, 26, 195, 238, 55, + 236, 146, 29, 27, 26, 202, 238, 55, 236, 146, 29, 27, 61, 248, 53, 96, + 234, 1, 77, 56, 96, 242, 228, 248, 43, 56, 96, 77, 56, 96, 242, 223, 248, + 43, 56, 237, 142, 242, 232, 77, 56, 96, 232, 202, 77, 56, 229, 60, 77, + 56, 96, 229, 60, 77, 56, 240, 55, 229, 60, 77, 56, 96, 240, 55, 229, 60, + 77, 56, 86, 77, 56, 238, 229, 233, 253, 77, 234, 7, 238, 229, 231, 60, + 77, 234, 7, 86, 77, 234, 7, 96, 86, 240, 95, 235, 45, 19, 77, 56, 96, 86, + 240, 95, 226, 226, 19, 77, 56, 244, 23, 86, 77, 56, 96, 229, 65, 86, 77, + 56, 232, 200, 64, 77, 56, 233, 215, 64, 77, 56, 233, 119, 236, 189, 64, + 77, 56, 232, 166, 236, 189, 64, 77, 56, 96, 168, 231, 38, 64, 77, 56, 96, + 189, 231, 38, 64, 77, 56, 238, 204, 168, 231, 38, 64, 77, 56, 238, 204, + 189, 231, 38, 64, 77, 56, 29, 96, 64, 77, 56, 231, 34, 77, 56, 229, 59, + 242, 228, 248, 43, 56, 229, 59, 77, 56, 229, 59, 242, 223, 248, 43, 56, + 96, 229, 59, 242, 228, 248, 43, 56, 96, 229, 59, 77, 56, 96, 229, 59, + 242, 223, 248, 43, 56, 231, 31, 77, 56, 96, 229, 56, 77, 56, 232, 112, + 77, 56, 96, 232, 112, 77, 56, 231, 150, 77, 56, 204, 233, 133, 240, 54, + 64, 236, 152, 234, 34, 3, 64, 235, 46, 231, 49, 248, 35, 238, 87, 248, + 35, 235, 84, 40, 237, 35, 254, 52, 234, 35, 38, 237, 35, 254, 52, 234, + 35, 64, 238, 76, 2, 238, 130, 248, 40, 19, 2, 248, 40, 238, 68, 147, 238, + 96, 236, 206, 168, 38, 240, 31, 2, 248, 40, 189, 40, 240, 31, 2, 248, 40, + 40, 243, 111, 243, 61, 38, 243, 111, 243, 61, 248, 37, 243, 111, 243, 61, + 243, 22, 88, 242, 234, 243, 22, 92, 242, 234, 40, 19, 38, 45, 234, 15, + 40, 19, 38, 242, 234, 40, 235, 103, 183, 38, 242, 234, 183, 40, 242, 234, + 88, 248, 84, 2, 218, 48, 239, 124, 238, 135, 255, 25, 163, 247, 53, 64, + 231, 95, 236, 164, 64, 231, 95, 238, 76, 2, 139, 243, 36, 64, 231, 95, + 238, 76, 2, 77, 243, 36, 64, 31, 2, 139, 243, 36, 64, 31, 2, 77, 243, 36, + 10, 40, 64, 31, 104, 10, 38, 64, 31, 104, 10, 40, 185, 104, 10, 38, 185, + 104, 10, 40, 45, 185, 104, 10, 38, 45, 185, 104, 226, 226, 235, 71, 56, + 235, 45, 235, 71, 56, 231, 86, 240, 178, 218, 56, 235, 62, 240, 178, 218, + 56, 38, 65, 2, 29, 243, 12, 183, 139, 56, 183, 77, 56, 183, 40, 38, 56, + 183, 139, 45, 56, 183, 77, 45, 56, 183, 40, 38, 45, 56, 183, 139, 65, + 248, 44, 125, 183, 77, 65, 248, 44, 125, 183, 139, 45, 65, 248, 44, 125, + 183, 77, 45, 65, 248, 44, 125, 183, 77, 236, 240, 56, 35, 36, 241, 33, + 35, 36, 239, 46, 35, 36, 239, 47, 35, 36, 237, 113, 35, 36, 239, 48, 35, + 36, 237, 114, 35, 36, 237, 120, 35, 36, 235, 206, 35, 36, 239, 49, 35, + 36, 237, 115, 35, 36, 237, 121, 35, 36, 235, 207, 35, 36, 237, 126, 35, + 36, 235, 212, 35, 36, 235, 227, 35, 36, 234, 113, 35, 36, 239, 50, 35, + 36, 237, 116, 35, 36, 237, 122, 35, 36, 235, 208, 35, 36, 237, 127, 35, + 36, 235, 213, 35, 36, 235, 228, 35, 36, 234, 114, 35, 36, 237, 131, 35, + 36, 235, 217, 35, 36, 235, 232, 35, 36, 234, 118, 35, 36, 235, 242, 35, + 36, 234, 128, 35, 36, 234, 148, 35, 36, 233, 138, 35, 36, 239, 51, 35, + 36, 237, 117, 35, 36, 237, 123, 35, 36, 235, 209, 35, 36, 237, 128, 35, + 36, 235, 214, 35, 36, 235, 229, 35, 36, 234, 115, 35, 36, 237, 132, 35, + 36, 235, 218, 35, 36, 235, 233, 35, 36, 234, 119, 35, 36, 235, 243, 35, + 36, 234, 129, 35, 36, 234, 149, 35, 36, 233, 139, 35, 36, 237, 135, 35, + 36, 235, 221, 35, 36, 235, 236, 35, 36, 234, 122, 35, 36, 235, 246, 35, + 36, 234, 132, 35, 36, 234, 152, 35, 36, 233, 142, 35, 36, 235, 252, 35, + 36, 234, 138, 35, 36, 234, 158, 35, 36, 233, 148, 35, 36, 234, 168, 35, + 36, 233, 158, 35, 36, 233, 173, 35, 36, 232, 134, 35, 36, 239, 52, 35, + 36, 237, 118, 35, 36, 237, 124, 35, 36, 235, 210, 35, 36, 237, 129, 35, + 36, 235, 215, 35, 36, 235, 230, 35, 36, 234, 116, 35, 36, 237, 133, 35, + 36, 235, 219, 35, 36, 235, 234, 35, 36, 234, 120, 35, 36, 235, 244, 35, + 36, 234, 130, 35, 36, 234, 150, 35, 36, 233, 140, 35, 36, 237, 136, 35, + 36, 235, 222, 35, 36, 235, 237, 35, 36, 234, 123, 35, 36, 235, 247, 35, + 36, 234, 133, 35, 36, 234, 153, 35, 36, 233, 143, 35, 36, 235, 253, 35, + 36, 234, 139, 35, 36, 234, 159, 35, 36, 233, 149, 35, 36, 234, 169, 35, + 36, 233, 159, 35, 36, 233, 174, 35, 36, 232, 135, 35, 36, 237, 138, 35, + 36, 235, 224, 35, 36, 235, 239, 35, 36, 234, 125, 35, 36, 235, 249, 35, + 36, 234, 135, 35, 36, 234, 155, 35, 36, 233, 145, 35, 36, 235, 255, 35, + 36, 234, 141, 35, 36, 234, 161, 35, 36, 233, 151, 35, 36, 234, 171, 35, + 36, 233, 161, 35, 36, 233, 176, 35, 36, 232, 137, 35, 36, 236, 2, 35, 36, + 234, 144, 35, 36, 234, 164, 35, 36, 233, 154, 35, 36, 234, 174, 35, 36, + 233, 164, 35, 36, 233, 179, 35, 36, 232, 140, 35, 36, 234, 178, 35, 36, + 233, 168, 35, 36, 233, 183, 35, 36, 232, 144, 35, 36, 233, 188, 35, 36, + 232, 149, 35, 36, 232, 155, 35, 36, 231, 129, 35, 36, 239, 53, 35, 36, + 237, 119, 35, 36, 237, 125, 35, 36, 235, 211, 35, 36, 237, 130, 35, 36, + 235, 216, 35, 36, 235, 231, 35, 36, 234, 117, 35, 36, 237, 134, 35, 36, + 235, 220, 35, 36, 235, 235, 35, 36, 234, 121, 35, 36, 235, 245, 35, 36, + 234, 131, 35, 36, 234, 151, 35, 36, 233, 141, 35, 36, 237, 137, 35, 36, + 235, 223, 35, 36, 235, 238, 35, 36, 234, 124, 35, 36, 235, 248, 35, 36, + 234, 134, 35, 36, 234, 154, 35, 36, 233, 144, 35, 36, 235, 254, 35, 36, + 234, 140, 35, 36, 234, 160, 35, 36, 233, 150, 35, 36, 234, 170, 35, 36, + 233, 160, 35, 36, 233, 175, 35, 36, 232, 136, 35, 36, 237, 139, 35, 36, + 235, 225, 35, 36, 235, 240, 35, 36, 234, 126, 35, 36, 235, 250, 35, 36, + 234, 136, 35, 36, 234, 156, 35, 36, 233, 146, 35, 36, 236, 0, 35, 36, + 234, 142, 35, 36, 234, 162, 35, 36, 233, 152, 35, 36, 234, 172, 35, 36, + 233, 162, 35, 36, 233, 177, 35, 36, 232, 138, 35, 36, 236, 3, 35, 36, + 234, 145, 35, 36, 234, 165, 35, 36, 233, 155, 35, 36, 234, 175, 35, 36, + 233, 165, 35, 36, 233, 180, 35, 36, 232, 141, 35, 36, 234, 179, 35, 36, + 233, 169, 35, 36, 233, 184, 35, 36, 232, 145, 35, 36, 233, 189, 35, 36, + 232, 150, 35, 36, 232, 156, 35, 36, 231, 130, 35, 36, 237, 140, 35, 36, + 235, 226, 35, 36, 235, 241, 35, 36, 234, 127, 35, 36, 235, 251, 35, 36, + 234, 137, 35, 36, 234, 157, 35, 36, 233, 147, 35, 36, 236, 1, 35, 36, + 234, 143, 35, 36, 234, 163, 35, 36, 233, 153, 35, 36, 234, 173, 35, 36, + 233, 163, 35, 36, 233, 178, 35, 36, 232, 139, 35, 36, 236, 4, 35, 36, + 234, 146, 35, 36, 234, 166, 35, 36, 233, 156, 35, 36, 234, 176, 35, 36, + 233, 166, 35, 36, 233, 181, 35, 36, 232, 142, 35, 36, 234, 180, 35, 36, + 233, 170, 35, 36, 233, 185, 35, 36, 232, 146, 35, 36, 233, 190, 35, 36, + 232, 151, 35, 36, 232, 157, 35, 36, 231, 131, 35, 36, 236, 5, 35, 36, + 234, 147, 35, 36, 234, 167, 35, 36, 233, 157, 35, 36, 234, 177, 35, 36, + 233, 167, 35, 36, 233, 182, 35, 36, 232, 143, 35, 36, 234, 181, 35, 36, + 233, 171, 35, 36, 233, 186, 35, 36, 232, 147, 35, 36, 233, 191, 35, 36, + 232, 152, 35, 36, 232, 158, 35, 36, 231, 132, 35, 36, 234, 182, 35, 36, + 233, 172, 35, 36, 233, 187, 35, 36, 232, 148, 35, 36, 233, 192, 35, 36, + 232, 153, 35, 36, 232, 159, 35, 36, 231, 133, 35, 36, 233, 193, 35, 36, + 232, 154, 35, 36, 232, 160, 35, 36, 231, 134, 35, 36, 232, 161, 35, 36, + 231, 135, 35, 36, 231, 136, 35, 36, 231, 64, 77, 234, 16, 65, 2, 59, 108, + 77, 234, 16, 65, 2, 45, 59, 108, 139, 45, 65, 2, 59, 108, 77, 45, 65, 2, + 59, 108, 40, 38, 45, 65, 2, 59, 108, 77, 234, 16, 65, 248, 44, 125, 139, + 45, 65, 248, 44, 125, 77, 45, 65, 248, 44, 125, 235, 45, 65, 2, 163, 108, + 226, 226, 65, 2, 163, 108, 226, 226, 240, 3, 56, 235, 45, 240, 3, 56, + 139, 45, 248, 63, 56, 77, 45, 248, 63, 56, 139, 240, 3, 248, 63, 56, 77, + 240, 3, 248, 63, 56, 77, 234, 16, 240, 3, 248, 63, 56, 77, 65, 2, 240, 4, + 243, 46, 226, 226, 65, 153, 125, 235, 45, 65, 153, 125, 77, 65, 2, 248, + 138, 2, 59, 108, 77, 65, 2, 248, 138, 2, 45, 59, 108, 77, 234, 16, 65, 2, + 242, 226, 77, 234, 16, 65, 2, 248, 138, 2, 59, 108, 77, 234, 16, 65, 2, + 248, 138, 2, 45, 59, 108, 139, 233, 64, 77, 233, 64, 139, 45, 233, 64, + 77, 45, 233, 64, 139, 65, 153, 86, 236, 164, 77, 65, 153, 86, 236, 164, + 139, 65, 248, 44, 253, 144, 153, 86, 236, 164, 77, 65, 248, 44, 253, 144, + 153, 86, 236, 164, 242, 223, 248, 56, 19, 242, 228, 248, 43, 56, 242, + 223, 248, 43, 19, 242, 228, 248, 56, 56, 242, 223, 248, 56, 65, 2, 90, + 242, 223, 248, 43, 65, 2, 90, 242, 228, 248, 43, 65, 2, 90, 242, 228, + 248, 56, 65, 2, 90, 242, 223, 248, 56, 65, 19, 242, 223, 248, 43, 56, + 242, 223, 248, 43, 65, 19, 242, 228, 248, 43, 56, 242, 228, 248, 43, 65, + 19, 242, 228, 248, 56, 56, 242, 228, 248, 56, 65, 19, 242, 223, 248, 56, + 56, 240, 69, 236, 159, 236, 185, 238, 105, 235, 86, 238, 105, 236, 159, + 236, 185, 240, 69, 235, 86, 242, 228, 248, 43, 65, 236, 185, 242, 223, + 248, 43, 56, 242, 223, 248, 43, 65, 236, 185, 242, 228, 248, 43, 56, 238, + 105, 236, 159, 236, 185, 242, 223, 248, 43, 56, 240, 69, 236, 159, 236, + 185, 242, 228, 248, 43, 56, 242, 223, 248, 43, 65, 236, 185, 242, 223, + 248, 56, 56, 242, 223, 248, 56, 65, 236, 185, 242, 223, 248, 43, 56, 248, + 141, 65, 236, 150, 237, 111, 225, 65, 236, 150, 77, 248, 187, 238, 111, + 236, 206, 65, 236, 150, 77, 248, 187, 238, 111, 234, 9, 65, 236, 150, + 235, 45, 248, 187, 238, 111, 234, 18, 65, 236, 150, 235, 45, 248, 187, + 238, 111, 233, 63, 234, 250, 253, 183, 235, 62, 56, 236, 50, 253, 183, + 231, 86, 56, 253, 159, 253, 183, 231, 86, 56, 240, 17, 253, 183, 231, 86, + 56, 253, 159, 253, 183, 235, 62, 65, 2, 240, 68, 253, 159, 253, 183, 231, + 86, 65, 2, 243, 12, 168, 38, 232, 98, 235, 62, 56, 168, 40, 232, 98, 231, + 86, 56, 231, 86, 240, 23, 218, 56, 235, 62, 240, 23, 218, 56, 77, 65, 60, + 242, 215, 139, 56, 139, 65, 60, 242, 215, 77, 56, 242, 215, 77, 65, 60, + 139, 56, 77, 65, 2, 248, 49, 46, 139, 65, 2, 248, 49, 46, 77, 65, 238, + 108, 206, 40, 38, 65, 238, 108, 3, 238, 51, 226, 226, 234, 16, 65, 248, + 44, 3, 238, 51, 40, 154, 88, 38, 154, 92, 236, 175, 40, 154, 92, 38, 154, + 88, 236, 175, 88, 154, 38, 92, 154, 40, 236, 175, 88, 154, 40, 92, 154, + 38, 236, 175, 40, 154, 88, 38, 154, 88, 236, 175, 88, 154, 38, 92, 154, + 38, 236, 175, 40, 154, 92, 38, 154, 92, 236, 175, 88, 154, 40, 92, 154, + 40, 236, 175, 139, 186, 2, 154, 88, 153, 125, 77, 186, 2, 154, 88, 153, + 125, 226, 226, 186, 2, 154, 38, 153, 125, 235, 45, 186, 2, 154, 38, 153, + 125, 139, 186, 2, 154, 92, 153, 125, 77, 186, 2, 154, 92, 153, 125, 226, + 226, 186, 2, 154, 40, 153, 125, 235, 45, 186, 2, 154, 40, 153, 125, 139, + 186, 2, 154, 88, 248, 44, 125, 77, 186, 2, 154, 88, 248, 44, 125, 226, + 226, 186, 2, 154, 38, 248, 44, 125, 235, 45, 186, 2, 154, 38, 248, 44, + 125, 139, 186, 2, 154, 92, 248, 44, 125, 77, 186, 2, 154, 92, 248, 44, + 125, 226, 226, 186, 2, 154, 40, 248, 44, 125, 235, 45, 186, 2, 154, 40, + 248, 44, 125, 139, 186, 2, 154, 88, 60, 139, 186, 2, 154, 242, 236, 226, + 226, 186, 2, 154, 40, 240, 45, 226, 226, 186, 2, 154, 225, 77, 186, 2, + 154, 88, 60, 77, 186, 2, 154, 242, 236, 235, 45, 186, 2, 154, 40, 240, + 45, 235, 45, 186, 2, 154, 225, 139, 186, 2, 154, 88, 60, 77, 186, 2, 154, + 253, 176, 139, 186, 2, 154, 92, 60, 77, 186, 2, 154, 242, 236, 77, 186, + 2, 154, 88, 60, 139, 186, 2, 154, 253, 176, 77, 186, 2, 154, 92, 60, 139, + 186, 2, 154, 242, 236, 139, 186, 2, 154, 88, 60, 183, 242, 235, 139, 186, + 2, 154, 92, 242, 230, 183, 242, 235, 77, 186, 2, 154, 88, 60, 183, 242, + 235, 77, 186, 2, 154, 92, 242, 230, 183, 242, 235, 226, 226, 186, 2, 154, + 40, 240, 45, 235, 45, 186, 2, 154, 225, 235, 45, 186, 2, 154, 40, 240, + 45, 226, 226, 186, 2, 154, 225, 38, 45, 65, 2, 238, 121, 243, 99, 240, 7, + 21, 60, 77, 56, 242, 219, 236, 208, 60, 77, 56, 139, 65, 60, 242, 219, + 235, 47, 77, 65, 60, 242, 219, 235, 47, 77, 65, 60, 240, 40, 95, 87, 235, + 44, 60, 139, 56, 139, 65, 238, 108, 234, 3, 232, 68, 60, 77, 56, 240, 26, + 60, 77, 56, 139, 65, 238, 108, 238, 87, 236, 154, 60, 139, 56, 40, 248, + 157, 242, 226, 38, 248, 157, 242, 226, 88, 248, 157, 242, 226, 92, 248, + 157, 242, 226, 240, 3, 59, 253, 144, 234, 35, 255, 97, 126, 247, 97, 255, + 97, 126, 249, 9, 240, 24, 40, 64, 242, 225, 104, 38, 64, 242, 225, 104, + 40, 64, 232, 74, 38, 64, 232, 74, 255, 97, 126, 40, 243, 11, 104, 255, + 97, 126, 38, 243, 11, 104, 255, 97, 126, 40, 238, 166, 104, 255, 97, 126, + 38, 238, 166, 104, 40, 31, 238, 52, 2, 235, 50, 38, 31, 238, 52, 2, 235, + 50, 40, 31, 238, 52, 2, 248, 188, 255, 22, 253, 159, 238, 67, 38, 31, + 238, 52, 2, 248, 188, 255, 22, 240, 17, 238, 67, 40, 31, 238, 52, 2, 248, + 188, 255, 22, 240, 17, 238, 67, 38, 31, 238, 52, 2, 248, 188, 255, 22, + 253, 159, 238, 67, 40, 185, 238, 52, 2, 248, 40, 38, 185, 238, 52, 2, + 248, 40, 40, 253, 183, 235, 44, 104, 38, 253, 183, 232, 68, 104, 45, 40, + 253, 183, 232, 68, 104, 45, 38, 253, 183, 235, 44, 104, 40, 86, 236, 171, + 242, 255, 104, 38, 86, 236, 171, 242, 255, 104, 240, 4, 240, 97, 59, 240, + 126, 242, 224, 236, 168, 185, 238, 96, 242, 220, 38, 185, 239, 240, 2, + 238, 59, 236, 168, 38, 185, 2, 248, 40, 185, 2, 255, 99, 238, 94, 242, + 241, 240, 54, 235, 109, 185, 238, 96, 242, 220, 235, 109, 185, 238, 96, + 253, 176, 205, 240, 54, 224, 240, 54, 185, 2, 235, 50, 224, 185, 2, 235, + 50, 238, 106, 185, 238, 96, 253, 176, 238, 106, 185, 238, 96, 242, 236, + 236, 168, 185, 2, 248, 35, 253, 229, 240, 63, 255, 22, 65, 236, 150, 88, + 19, 225, 236, 168, 185, 2, 248, 35, 253, 229, 240, 63, 255, 22, 65, 236, + 150, 88, 19, 242, 220, 236, 168, 185, 2, 248, 35, 253, 229, 240, 63, 255, + 22, 65, 236, 150, 92, 19, 225, 236, 168, 185, 2, 248, 35, 253, 229, 240, + 63, 255, 22, 65, 236, 150, 92, 19, 242, 220, 236, 168, 185, 2, 248, 35, + 253, 229, 240, 63, 255, 22, 65, 236, 150, 38, 19, 253, 176, 236, 168, + 185, 2, 248, 35, 253, 229, 240, 63, 255, 22, 65, 236, 150, 40, 19, 253, + 176, 236, 168, 185, 2, 248, 35, 253, 229, 240, 63, 255, 22, 65, 236, 150, + 38, 19, 242, 236, 236, 168, 185, 2, 248, 35, 253, 229, 240, 63, 255, 22, + 65, 236, 150, 40, 19, 242, 236, 224, 243, 15, 249, 160, 243, 15, 254, 30, + 2, 236, 163, 243, 15, 254, 30, 2, 3, 218, 48, 243, 15, 254, 30, 2, 38, + 65, 48, 243, 15, 254, 30, 2, 40, 65, 48, 218, 2, 163, 125, 29, 59, 125, + 29, 235, 105, 29, 238, 75, 236, 177, 29, 231, 49, 218, 238, 135, 255, 25, + 163, 253, 144, 19, 253, 159, 137, 238, 135, 255, 25, 59, 125, 218, 2, + 233, 39, 206, 29, 226, 231, 236, 196, 52, 88, 65, 238, 108, 238, 51, 29, + 64, 238, 69, 29, 238, 69, 29, 234, 3, 29, 231, 85, 218, 2, 3, 218, 153, + 253, 145, 225, 218, 2, 171, 163, 239, 207, 153, 253, 145, 225, 238, 84, + 240, 69, 236, 159, 240, 37, 238, 84, 238, 105, 236, 159, 240, 37, 238, + 84, 235, 52, 238, 84, 3, 238, 51, 238, 84, 238, 59, 171, 240, 116, 238, + 12, 236, 152, 2, 53, 48, 236, 152, 2, 235, 50, 255, 99, 255, 22, 235, 46, + 236, 152, 2, 240, 220, 255, 31, 238, 128, 38, 236, 152, 60, 40, 235, 46, + 40, 236, 152, 240, 45, 59, 125, 59, 253, 144, 240, 45, 38, 235, 46, 240, + 161, 2, 40, 137, 240, 0, 240, 161, 2, 38, 137, 240, 0, 86, 238, 168, 243, + 48, 2, 40, 137, 240, 0, 243, 48, 2, 38, 137, 240, 0, 64, 234, 39, 86, + 234, 39, 40, 240, 125, 240, 97, 38, 240, 125, 240, 97, 40, 45, 240, 125, + 240, 97, 38, 45, 240, 125, 240, 97, 234, 204, 235, 101, 254, 248, 248, + 59, 235, 101, 237, 180, 238, 203, 2, 59, 125, 232, 162, 235, 103, 31, 2, + 235, 194, 237, 229, 236, 40, 254, 143, 239, 195, 236, 170, 240, 7, 21, + 19, 238, 58, 235, 105, 240, 7, 21, 19, 238, 58, 236, 200, 2, 242, 219, + 48, 235, 89, 153, 19, 238, 58, 235, 105, 241, 138, 242, 132, 231, 83, + 231, 91, 236, 152, 2, 40, 137, 240, 0, 231, 91, 236, 152, 2, 38, 137, + 240, 0, 86, 238, 76, 2, 92, 56, 86, 236, 231, 64, 218, 2, 92, 56, 86, + 218, 2, 92, 56, 232, 78, 64, 238, 59, 232, 78, 86, 238, 59, 232, 78, 64, + 236, 164, 232, 78, 86, 236, 164, 232, 78, 64, 238, 51, 232, 78, 86, 238, + 51, 231, 152, 238, 75, 238, 83, 235, 47, 238, 83, 2, 236, 163, 238, 75, + 238, 83, 2, 163, 108, 253, 213, 236, 177, 253, 213, 238, 75, 236, 177, + 45, 243, 12, 240, 3, 243, 12, 231, 87, 240, 95, 185, 104, 231, 36, 240, + 95, 185, 104, 247, 152, 246, 87, 242, 238, 29, 53, 235, 47, 242, 238, 29, + 248, 49, 235, 47, 242, 238, 29, 243, 48, 235, 47, 242, 238, 243, 2, 236, + 208, 2, 248, 40, 242, 238, 243, 2, 236, 208, 2, 243, 12, 242, 238, 31, + 232, 76, 235, 47, 242, 238, 31, 243, 2, 235, 47, 171, 238, 56, 19, 235, + 47, 171, 238, 56, 128, 235, 47, 242, 238, 243, 48, 235, 47, 241, 247, + 171, 252, 192, 235, 112, 2, 235, 60, 235, 71, 236, 167, 235, 47, 241, + 110, 249, 134, 235, 60, 236, 167, 2, 45, 108, 236, 167, 238, 255, 2, 240, + 37, 233, 122, 236, 29, 231, 86, 232, 177, 248, 41, 233, 70, 2, 233, 97, + 249, 135, 240, 127, 243, 116, 248, 41, 233, 70, 2, 232, 98, 249, 135, + 240, 127, 243, 116, 248, 41, 233, 70, 161, 236, 39, 253, 145, 243, 116, + 236, 167, 240, 127, 134, 242, 232, 235, 47, 234, 242, 236, 167, 235, 47, + 236, 167, 2, 139, 65, 2, 90, 236, 167, 2, 243, 48, 52, 236, 167, 2, 231, + 88, 236, 167, 2, 240, 58, 236, 167, 2, 236, 163, 236, 167, 2, 235, 50, + 243, 61, 243, 22, 40, 236, 152, 235, 47, 255, 97, 126, 240, 144, 232, + 104, 255, 97, 126, 240, 144, 239, 162, 255, 97, 126, 240, 144, 233, 225, + 248, 49, 21, 2, 3, 218, 48, 248, 49, 21, 2, 190, 240, 2, 48, 248, 49, 21, + 2, 242, 219, 48, 248, 49, 21, 2, 53, 46, 248, 49, 21, 2, 242, 219, 46, + 248, 49, 21, 2, 235, 48, 111, 248, 49, 21, 2, 86, 235, 46, 242, 250, 21, + 2, 242, 244, 48, 242, 250, 21, 2, 53, 46, 242, 250, 21, 2, 238, 105, 243, + 5, 242, 250, 21, 2, 240, 69, 243, 5, 248, 49, 21, 255, 22, 40, 137, 238, + 51, 248, 49, 21, 255, 22, 38, 137, 238, 51, 242, 176, 128, 243, 38, 236, + 170, 231, 37, 21, 2, 53, 48, 231, 37, 21, 2, 235, 50, 234, 21, 239, 167, + 2, 240, 17, 239, 29, 244, 20, 236, 170, 231, 37, 21, 255, 22, 40, 137, + 238, 51, 231, 37, 21, 255, 22, 38, 137, 238, 51, 29, 231, 37, 21, 2, 190, + 238, 54, 231, 37, 21, 255, 22, 45, 238, 51, 29, 236, 196, 52, 248, 49, + 21, 255, 22, 235, 46, 242, 250, 21, 255, 22, 235, 46, 231, 37, 21, 255, + 22, 235, 46, 237, 14, 236, 170, 236, 93, 237, 14, 236, 170, 255, 97, 126, + 234, 246, 232, 104, 232, 115, 128, 234, 50, 232, 76, 2, 248, 40, 243, 2, + 2, 242, 250, 52, 243, 2, 2, 236, 163, 232, 76, 2, 236, 163, 232, 76, 2, + 238, 56, 248, 91, 243, 2, 2, 238, 56, 253, 227, 243, 2, 60, 231, 88, 232, + 76, 60, 240, 58, 243, 2, 60, 253, 144, 60, 231, 88, 232, 76, 60, 253, + 144, 60, 240, 58, 243, 2, 240, 45, 19, 240, 116, 2, 240, 58, 232, 76, + 240, 45, 19, 240, 116, 2, 231, 88, 240, 23, 243, 2, 2, 238, 214, 240, 23, + 232, 76, 2, 238, 214, 45, 31, 231, 88, 45, 31, 240, 58, 240, 23, 243, 2, + 2, 240, 220, 19, 244, 20, 236, 170, 238, 56, 19, 2, 53, 48, 238, 56, 128, + 2, 53, 48, 45, 238, 56, 248, 91, 45, 238, 56, 253, 227, 171, 232, 105, + 238, 56, 248, 91, 171, 232, 105, 238, 56, 253, 227, 238, 217, 243, 22, + 253, 227, 238, 217, 243, 22, 248, 91, 238, 56, 128, 233, 91, 238, 56, + 248, 91, 238, 56, 19, 2, 240, 1, 243, 46, 238, 56, 128, 2, 240, 1, 243, + 46, 238, 56, 19, 2, 163, 242, 235, 238, 56, 128, 2, 163, 242, 235, 238, + 56, 19, 2, 45, 236, 163, 238, 56, 19, 2, 235, 50, 238, 56, 19, 2, 45, + 235, 50, 3, 254, 255, 2, 235, 50, 238, 56, 128, 2, 45, 236, 163, 238, 56, + 128, 2, 45, 235, 50, 255, 97, 126, 241, 87, 227, 10, 255, 97, 126, 247, + 28, 227, 10, 240, 7, 21, 2, 53, 46, 235, 89, 2, 53, 48, 240, 3, 163, 253, + 144, 2, 45, 59, 108, 240, 3, 163, 253, 144, 2, 240, 3, 59, 108, 242, 219, + 236, 208, 2, 53, 48, 242, 219, 236, 208, 2, 240, 69, 243, 5, 238, 81, + 242, 250, 238, 5, 235, 192, 2, 53, 48, 240, 7, 2, 235, 52, 240, 40, 95, + 153, 2, 190, 238, 54, 231, 89, 95, 128, 95, 87, 240, 7, 21, 60, 248, 49, + 52, 248, 49, 21, 60, 240, 7, 52, 240, 7, 21, 60, 242, 219, 235, 47, 45, + 243, 14, 240, 32, 171, 233, 82, 240, 7, 240, 232, 204, 233, 82, 240, 7, + 240, 232, 240, 7, 21, 2, 171, 181, 60, 19, 171, 181, 46, 234, 5, 2, 248, + 58, 181, 48, 235, 44, 2, 218, 238, 94, 232, 68, 2, 218, 238, 94, 235, 44, + 2, 236, 156, 158, 48, 232, 68, 2, 236, 156, 158, 48, 235, 44, 128, 238, + 58, 95, 87, 232, 68, 128, 238, 58, 95, 87, 235, 44, 128, 238, 58, 95, + 153, 2, 53, 238, 94, 232, 68, 128, 238, 58, 95, 153, 2, 53, 238, 94, 235, + 44, 128, 238, 58, 95, 153, 2, 53, 48, 232, 68, 128, 238, 58, 95, 153, 2, + 53, 48, 235, 44, 128, 238, 58, 95, 153, 2, 53, 60, 225, 232, 68, 128, + 238, 58, 95, 153, 2, 53, 60, 242, 220, 235, 44, 128, 232, 81, 232, 68, + 128, 232, 81, 235, 44, 19, 233, 61, 161, 95, 87, 232, 68, 19, 233, 61, + 161, 95, 87, 235, 44, 19, 161, 232, 81, 232, 68, 19, 161, 232, 81, 235, + 44, 60, 233, 57, 95, 60, 231, 85, 232, 68, 60, 233, 57, 95, 60, 234, 3, + 235, 44, 60, 238, 81, 128, 240, 32, 232, 68, 60, 238, 81, 128, 240, 32, + 235, 44, 60, 238, 81, 60, 231, 85, 232, 68, 60, 238, 81, 60, 234, 3, 235, + 44, 60, 232, 68, 60, 233, 57, 240, 32, 232, 68, 60, 235, 44, 60, 233, 57, + 240, 32, 235, 44, 60, 238, 58, 95, 60, 232, 68, 60, 238, 58, 240, 32, + 232, 68, 60, 238, 58, 95, 60, 235, 44, 60, 238, 58, 240, 32, 238, 58, 95, + 153, 128, 234, 3, 238, 58, 95, 153, 128, 231, 85, 238, 58, 95, 153, 128, + 235, 44, 2, 53, 238, 94, 238, 58, 95, 153, 128, 232, 68, 2, 53, 238, 94, + 233, 57, 95, 153, 128, 234, 3, 233, 57, 95, 153, 128, 231, 85, 233, 57, + 238, 58, 95, 153, 128, 234, 3, 233, 57, 238, 58, 95, 153, 128, 231, 85, + 238, 81, 128, 234, 3, 238, 81, 128, 231, 85, 238, 81, 60, 235, 44, 60, + 240, 7, 52, 238, 81, 60, 232, 68, 60, 240, 7, 52, 45, 240, 102, 234, 3, + 45, 240, 102, 231, 85, 45, 240, 102, 235, 44, 2, 235, 50, 232, 68, 233, + 91, 234, 3, 232, 68, 240, 45, 234, 3, 235, 44, 240, 23, 255, 25, 240, + 163, 232, 68, 240, 23, 255, 25, 240, 163, 235, 44, 240, 23, 255, 25, 243, + 158, 60, 238, 58, 240, 32, 232, 68, 240, 23, 255, 25, 243, 158, 60, 238, + 58, 240, 32, 238, 218, 243, 127, 240, 196, 243, 127, 238, 218, 249, 1, + 128, 95, 87, 240, 196, 249, 1, 128, 95, 87, 240, 7, 21, 2, 244, 232, 48, + 236, 176, 60, 233, 61, 240, 7, 52, 236, 178, 60, 233, 61, 240, 7, 52, + 236, 176, 60, 233, 61, 161, 95, 87, 236, 178, 60, 233, 61, 161, 95, 87, + 236, 176, 60, 240, 7, 52, 236, 178, 60, 240, 7, 52, 236, 176, 60, 161, + 95, 87, 236, 178, 60, 161, 95, 87, 236, 176, 60, 240, 40, 95, 87, 236, + 178, 60, 240, 40, 95, 87, 236, 176, 60, 161, 240, 40, 95, 87, 236, 178, + 60, 161, 240, 40, 95, 87, 45, 235, 107, 45, 235, 111, 240, 26, 2, 248, + 40, 236, 154, 2, 248, 40, 240, 26, 2, 248, 49, 21, 46, 236, 154, 2, 248, + 49, 21, 46, 240, 26, 2, 231, 37, 21, 46, 236, 154, 2, 231, 37, 21, 46, + 240, 26, 147, 128, 95, 153, 2, 53, 48, 236, 154, 147, 128, 95, 153, 2, + 53, 48, 240, 26, 147, 60, 240, 7, 52, 236, 154, 147, 60, 240, 7, 52, 240, + 26, 147, 60, 242, 219, 235, 47, 236, 154, 147, 60, 242, 219, 235, 47, + 240, 26, 147, 60, 240, 40, 95, 87, 236, 154, 147, 60, 240, 40, 95, 87, + 240, 26, 147, 60, 161, 95, 87, 236, 154, 147, 60, 161, 95, 87, 31, 40, + 248, 35, 66, 235, 47, 31, 38, 248, 35, 66, 235, 47, 240, 23, 238, 87, + 240, 23, 235, 84, 240, 23, 240, 26, 128, 95, 87, 240, 23, 236, 154, 128, + 95, 87, 240, 26, 60, 235, 84, 236, 154, 60, 238, 87, 240, 26, 60, 238, + 87, 236, 154, 60, 235, 84, 236, 154, 240, 45, 238, 87, 236, 154, 240, 45, + 19, 240, 116, 255, 25, 248, 63, 2, 238, 87, 238, 68, 147, 238, 96, 234, + 9, 236, 75, 2, 254, 246, 249, 3, 233, 254, 231, 88, 237, 160, 233, 220, + 242, 215, 40, 242, 234, 242, 215, 92, 242, 234, 242, 215, 88, 242, 234, + 231, 151, 2, 193, 59, 253, 144, 240, 3, 38, 234, 15, 45, 59, 253, 144, + 40, 234, 15, 59, 253, 144, 45, 40, 234, 15, 45, 59, 253, 144, 45, 40, + 234, 15, 183, 248, 63, 248, 44, 40, 241, 234, 147, 45, 235, 63, 242, 215, + 92, 248, 84, 2, 236, 163, 242, 215, 88, 248, 84, 2, 235, 50, 242, 215, + 88, 248, 84, 60, 242, 215, 92, 242, 234, 45, 92, 242, 234, 45, 88, 242, + 234, 45, 240, 5, 161, 52, 224, 45, 240, 5, 161, 52, 248, 86, 161, 241, + 86, 2, 224, 237, 217, 240, 37, 59, 248, 41, 2, 218, 48, 59, 248, 41, 2, + 218, 46, 92, 248, 84, 2, 218, 46, 236, 200, 2, 163, 108, 236, 200, 2, + 242, 219, 235, 47, 240, 3, 59, 253, 144, 240, 159, 235, 92, 240, 3, 59, + 253, 144, 2, 163, 108, 240, 3, 243, 14, 235, 47, 240, 3, 240, 102, 234, + 3, 240, 3, 240, 102, 231, 85, 233, 57, 238, 58, 235, 44, 128, 95, 87, + 233, 57, 238, 58, 232, 68, 128, 95, 87, 240, 3, 238, 83, 240, 159, 235, + 92, 243, 22, 240, 3, 59, 253, 144, 235, 47, 45, 238, 83, 235, 47, 64, 59, + 125, 242, 238, 64, 59, 125, 242, 223, 248, 43, 64, 56, 242, 223, 248, 56, + 64, 56, 242, 228, 248, 43, 64, 56, 242, 228, 248, 56, 64, 56, 40, 38, 64, + 56, 139, 86, 56, 226, 226, 86, 56, 235, 45, 86, 56, 242, 223, 248, 43, + 86, 56, 242, 223, 248, 56, 86, 56, 242, 228, 248, 43, 86, 56, 242, 228, + 248, 56, 86, 56, 40, 38, 86, 56, 88, 92, 86, 56, 77, 65, 2, 253, 241, + 234, 9, 77, 65, 2, 253, 241, 236, 206, 139, 65, 2, 253, 241, 234, 9, 139, + 65, 2, 253, 241, 236, 206, 31, 2, 253, 159, 137, 240, 0, 31, 2, 240, 17, + 137, 240, 0, 98, 5, 1, 249, 29, 98, 5, 1, 243, 152, 98, 5, 1, 244, 45, + 98, 5, 1, 237, 12, 98, 5, 1, 240, 170, 98, 5, 1, 240, 254, 98, 5, 1, 237, + 52, 98, 5, 1, 240, 171, 98, 5, 1, 238, 235, 98, 5, 1, 243, 60, 98, 5, 1, + 54, 243, 60, 98, 5, 1, 71, 98, 5, 1, 238, 178, 98, 5, 1, 243, 204, 98, 5, + 1, 237, 21, 98, 5, 1, 236, 216, 98, 5, 1, 240, 202, 98, 5, 1, 249, 131, + 98, 5, 1, 238, 210, 98, 5, 1, 240, 217, 98, 5, 1, 240, 235, 98, 5, 1, + 238, 230, 98, 5, 1, 249, 190, 98, 5, 1, 240, 177, 98, 5, 1, 243, 193, 98, + 5, 1, 249, 132, 98, 5, 1, 253, 175, 98, 5, 1, 244, 14, 98, 5, 1, 248, + 140, 98, 5, 1, 238, 170, 98, 5, 1, 248, 46, 98, 5, 1, 243, 83, 98, 5, 1, + 244, 57, 98, 5, 1, 244, 56, 98, 5, 1, 238, 221, 219, 98, 5, 1, 253, 161, + 98, 5, 1, 3, 248, 74, 98, 5, 1, 3, 254, 136, 2, 242, 226, 98, 5, 1, 253, + 162, 98, 5, 1, 238, 117, 3, 248, 74, 98, 5, 1, 253, 213, 248, 74, 98, 5, + 1, 238, 117, 253, 213, 248, 74, 98, 5, 1, 243, 57, 98, 5, 1, 236, 215, + 98, 5, 1, 237, 40, 98, 5, 1, 234, 87, 67, 98, 5, 1, 237, 19, 236, 216, + 98, 3, 1, 249, 29, 98, 3, 1, 243, 152, 98, 3, 1, 244, 45, 98, 3, 1, 237, + 12, 98, 3, 1, 240, 170, 98, 3, 1, 240, 254, 98, 3, 1, 237, 52, 98, 3, 1, + 240, 171, 98, 3, 1, 238, 235, 98, 3, 1, 243, 60, 98, 3, 1, 54, 243, 60, + 98, 3, 1, 71, 98, 3, 1, 238, 178, 98, 3, 1, 243, 204, 98, 3, 1, 237, 21, + 98, 3, 1, 236, 216, 98, 3, 1, 240, 202, 98, 3, 1, 249, 131, 98, 3, 1, + 238, 210, 98, 3, 1, 240, 217, 98, 3, 1, 240, 235, 98, 3, 1, 238, 230, 98, + 3, 1, 249, 190, 98, 3, 1, 240, 177, 98, 3, 1, 243, 193, 98, 3, 1, 249, + 132, 98, 3, 1, 253, 175, 98, 3, 1, 244, 14, 98, 3, 1, 248, 140, 98, 3, 1, + 238, 170, 98, 3, 1, 248, 46, 98, 3, 1, 243, 83, 98, 3, 1, 244, 57, 98, 3, + 1, 244, 56, 98, 3, 1, 238, 221, 219, 98, 3, 1, 253, 161, 98, 3, 1, 3, + 248, 74, 98, 3, 1, 3, 254, 136, 2, 242, 226, 98, 3, 1, 253, 162, 98, 3, + 1, 238, 117, 3, 248, 74, 98, 3, 1, 253, 213, 248, 74, 98, 3, 1, 238, 117, + 253, 213, 248, 74, 98, 3, 1, 243, 57, 98, 3, 1, 236, 215, 98, 3, 1, 237, + 40, 98, 3, 1, 234, 87, 67, 98, 3, 1, 237, 19, 236, 216, 62, 5, 1, 243, + 141, 62, 3, 1, 243, 141, 62, 5, 1, 244, 47, 62, 3, 1, 244, 47, 62, 5, 1, + 240, 10, 62, 3, 1, 240, 10, 62, 5, 1, 240, 164, 62, 3, 1, 240, 164, 62, + 5, 1, 248, 154, 62, 3, 1, 248, 154, 62, 5, 1, 249, 167, 62, 3, 1, 249, + 167, 62, 5, 1, 244, 65, 62, 3, 1, 244, 65, 62, 5, 1, 243, 190, 62, 3, 1, + 243, 190, 62, 5, 1, 238, 226, 62, 3, 1, 238, 226, 62, 5, 1, 240, 191, 62, + 3, 1, 240, 191, 62, 5, 1, 243, 62, 62, 3, 1, 243, 62, 62, 5, 1, 240, 197, + 62, 3, 1, 240, 197, 62, 5, 1, 253, 180, 62, 3, 1, 253, 180, 62, 5, 1, + 253, 166, 62, 3, 1, 253, 166, 62, 5, 1, 248, 163, 62, 3, 1, 248, 163, 62, + 5, 1, 73, 62, 3, 1, 73, 62, 5, 1, 253, 147, 62, 3, 1, 253, 147, 62, 5, 1, + 253, 160, 62, 3, 1, 253, 160, 62, 5, 1, 243, 123, 62, 3, 1, 243, 123, 62, + 5, 1, 248, 85, 62, 3, 1, 248, 85, 62, 5, 1, 254, 74, 62, 3, 1, 254, 74, + 62, 5, 1, 253, 245, 62, 3, 1, 253, 245, 62, 5, 1, 248, 219, 62, 3, 1, + 248, 219, 62, 5, 1, 248, 69, 62, 3, 1, 248, 69, 62, 5, 1, 248, 179, 62, + 3, 1, 248, 179, 62, 5, 1, 235, 67, 243, 3, 62, 3, 1, 235, 67, 243, 3, 62, + 5, 1, 76, 62, 248, 105, 62, 3, 1, 76, 62, 248, 105, 62, 5, 1, 231, 93, + 248, 154, 62, 3, 1, 231, 93, 248, 154, 62, 5, 1, 235, 67, 243, 62, 62, 3, + 1, 235, 67, 243, 62, 62, 5, 1, 235, 67, 253, 166, 62, 3, 1, 235, 67, 253, + 166, 62, 5, 1, 231, 93, 253, 166, 62, 3, 1, 231, 93, 253, 166, 62, 5, 1, + 76, 62, 248, 179, 62, 3, 1, 76, 62, 248, 179, 62, 5, 1, 240, 121, 62, 3, + 1, 240, 121, 62, 5, 1, 238, 133, 243, 32, 62, 3, 1, 238, 133, 243, 32, + 62, 5, 1, 76, 62, 243, 32, 62, 3, 1, 76, 62, 243, 32, 62, 5, 1, 76, 62, + 248, 93, 62, 3, 1, 76, 62, 248, 93, 62, 5, 1, 236, 245, 243, 64, 62, 3, + 1, 236, 245, 243, 64, 62, 5, 1, 235, 67, 243, 28, 62, 3, 1, 235, 67, 243, + 28, 62, 5, 1, 76, 62, 243, 28, 62, 3, 1, 76, 62, 243, 28, 62, 5, 1, 76, + 62, 219, 62, 3, 1, 76, 62, 219, 62, 5, 1, 237, 18, 219, 62, 3, 1, 237, + 18, 219, 62, 5, 1, 76, 62, 249, 81, 62, 3, 1, 76, 62, 249, 81, 62, 5, 1, + 76, 62, 248, 214, 62, 3, 1, 76, 62, 248, 214, 62, 5, 1, 76, 62, 238, 115, + 62, 3, 1, 76, 62, 238, 115, 62, 5, 1, 76, 62, 249, 54, 62, 3, 1, 76, 62, + 249, 54, 62, 5, 1, 76, 62, 240, 88, 62, 3, 1, 76, 62, 240, 88, 62, 5, 1, + 76, 240, 43, 240, 88, 62, 3, 1, 76, 240, 43, 240, 88, 62, 5, 1, 76, 240, + 43, 248, 232, 62, 3, 1, 76, 240, 43, 248, 232, 62, 5, 1, 76, 240, 43, + 248, 178, 62, 3, 1, 76, 240, 43, 248, 178, 62, 5, 1, 76, 240, 43, 249, + 198, 62, 3, 1, 76, 240, 43, 249, 198, 62, 12, 249, 91, 62, 12, 255, 82, + 253, 160, 62, 12, 255, 29, 253, 160, 62, 12, 238, 13, 62, 12, 254, 244, + 253, 160, 62, 12, 254, 184, 253, 160, 62, 12, 247, 74, 243, 123, 62, 76, + 240, 43, 248, 37, 208, 62, 76, 240, 43, 240, 169, 236, 156, 69, 62, 76, + 240, 43, 237, 179, 236, 156, 69, 62, 76, 240, 43, 244, 46, 236, 213, 62, + 236, 155, 253, 125, 243, 7, 62, 248, 37, 208, 62, 231, 149, 236, 213, 75, + 3, 1, 254, 19, 75, 3, 1, 248, 195, 75, 3, 1, 248, 158, 75, 3, 1, 248, + 205, 75, 3, 1, 253, 202, 75, 3, 1, 249, 11, 75, 3, 1, 249, 25, 75, 3, 1, + 248, 253, 75, 3, 1, 253, 247, 75, 3, 1, 248, 162, 75, 3, 1, 248, 224, 75, + 3, 1, 248, 131, 75, 3, 1, 248, 171, 75, 3, 1, 254, 9, 75, 3, 1, 248, 236, + 75, 3, 1, 243, 138, 75, 3, 1, 248, 243, 75, 3, 1, 248, 134, 75, 3, 1, + 248, 254, 75, 3, 1, 254, 75, 75, 3, 1, 243, 115, 75, 3, 1, 243, 103, 75, + 3, 1, 243, 95, 75, 3, 1, 248, 242, 75, 3, 1, 243, 33, 75, 3, 1, 243, 88, + 75, 3, 1, 248, 100, 75, 3, 1, 248, 217, 75, 3, 1, 248, 201, 75, 3, 1, + 243, 87, 75, 3, 1, 249, 16, 75, 3, 1, 243, 101, 75, 3, 1, 248, 212, 75, + 3, 1, 253, 168, 75, 3, 1, 248, 160, 75, 3, 1, 253, 170, 75, 3, 1, 248, + 213, 75, 3, 1, 248, 215, 174, 1, 216, 174, 1, 253, 65, 174, 1, 247, 213, + 174, 1, 253, 68, 174, 1, 242, 193, 174, 1, 240, 158, 238, 157, 249, 202, + 174, 1, 249, 202, 174, 1, 253, 66, 174, 1, 247, 216, 174, 1, 247, 215, + 174, 1, 242, 192, 174, 1, 253, 79, 174, 1, 253, 67, 174, 1, 249, 20, 174, + 1, 240, 66, 249, 20, 174, 1, 242, 194, 174, 1, 249, 19, 174, 1, 240, 158, + 238, 157, 249, 19, 174, 1, 240, 66, 249, 19, 174, 1, 247, 218, 174, 1, + 248, 191, 174, 1, 244, 55, 174, 1, 240, 66, 244, 55, 174, 1, 249, 204, + 174, 1, 240, 66, 249, 204, 174, 1, 253, 189, 174, 1, 243, 135, 174, 1, + 238, 239, 243, 135, 174, 1, 240, 66, 243, 135, 174, 1, 253, 69, 174, 1, + 253, 70, 174, 1, 249, 203, 174, 1, 240, 66, 247, 217, 174, 1, 240, 66, + 243, 50, 174, 1, 253, 71, 174, 1, 253, 161, 174, 1, 253, 72, 174, 1, 247, + 219, 174, 1, 243, 134, 174, 1, 240, 66, 243, 134, 174, 1, 249, 246, 243, + 134, 174, 1, 253, 73, 174, 1, 247, 221, 174, 1, 247, 220, 174, 1, 249, + 21, 174, 1, 247, 222, 174, 1, 247, 214, 174, 1, 247, 223, 174, 1, 253, + 74, 174, 1, 253, 75, 174, 1, 253, 76, 174, 1, 249, 205, 174, 1, 235, 32, + 249, 205, 174, 1, 247, 224, 174, 49, 1, 231, 146, 69, 22, 4, 251, 202, + 22, 4, 251, 239, 22, 4, 252, 142, 22, 4, 252, 183, 22, 4, 247, 75, 22, 4, + 250, 128, 22, 4, 252, 226, 22, 4, 250, 165, 22, 4, 252, 32, 22, 4, 246, + 205, 22, 4, 238, 62, 254, 117, 22, 4, 253, 109, 22, 4, 250, 202, 22, 4, + 245, 49, 22, 4, 251, 122, 22, 4, 247, 145, 22, 4, 245, 4, 22, 4, 246, + 246, 22, 4, 252, 71, 22, 4, 245, 116, 22, 4, 245, 118, 22, 4, 241, 135, + 22, 4, 245, 117, 22, 4, 248, 66, 22, 4, 248, 251, 22, 4, 248, 249, 22, 4, + 247, 99, 22, 4, 247, 103, 22, 4, 249, 168, 22, 4, 248, 250, 22, 4, 250, + 148, 22, 4, 250, 152, 22, 4, 250, 150, 22, 4, 244, 245, 22, 4, 244, 246, + 22, 4, 250, 149, 22, 4, 250, 151, 22, 4, 249, 224, 22, 4, 249, 228, 22, + 4, 249, 226, 22, 4, 248, 15, 22, 4, 248, 19, 22, 4, 249, 225, 22, 4, 249, + 227, 22, 4, 244, 247, 22, 4, 244, 251, 22, 4, 244, 249, 22, 4, 241, 45, + 22, 4, 241, 46, 22, 4, 244, 248, 22, 4, 244, 250, 22, 4, 252, 115, 22, 4, + 252, 122, 22, 4, 252, 117, 22, 4, 247, 23, 22, 4, 247, 24, 22, 4, 252, + 116, 22, 4, 252, 118, 22, 4, 251, 175, 22, 4, 251, 179, 22, 4, 251, 177, + 22, 4, 246, 31, 22, 4, 246, 32, 22, 4, 251, 176, 22, 4, 251, 178, 22, 4, + 253, 56, 22, 4, 253, 63, 22, 4, 253, 58, 22, 4, 247, 208, 22, 4, 247, + 209, 22, 4, 253, 57, 22, 4, 253, 59, 22, 4, 251, 39, 22, 4, 251, 44, 22, + 4, 251, 42, 22, 4, 245, 136, 22, 4, 245, 137, 22, 4, 251, 40, 22, 4, 251, + 43, 38, 185, 232, 79, 238, 95, 38, 185, 240, 4, 232, 79, 238, 95, 40, + 232, 79, 104, 38, 232, 79, 104, 40, 240, 4, 232, 79, 104, 38, 240, 4, + 232, 79, 104, 240, 84, 231, 107, 238, 95, 240, 84, 240, 4, 231, 107, 238, + 95, 240, 4, 231, 100, 238, 95, 40, 231, 100, 104, 38, 231, 100, 104, 240, + 84, 238, 59, 40, 240, 84, 237, 26, 104, 38, 240, 84, 237, 26, 104, 236, + 11, 237, 92, 232, 95, 240, 176, 232, 95, 224, 240, 176, 232, 95, 231, + 140, 240, 4, 239, 149, 235, 45, 238, 160, 226, 226, 238, 160, 240, 4, + 231, 36, 240, 54, 45, 238, 106, 238, 93, 40, 170, 234, 61, 104, 38, 170, + 234, 61, 104, 7, 25, 239, 173, 7, 25, 240, 131, 7, 25, 240, 87, 127, 7, + 25, 240, 87, 111, 7, 25, 240, 87, 166, 7, 25, 239, 160, 7, 25, 248, 92, + 7, 25, 240, 241, 7, 25, 243, 209, 127, 7, 25, 243, 209, 111, 7, 25, 233, + 83, 7, 25, 244, 5, 7, 25, 3, 127, 7, 25, 3, 111, 7, 25, 248, 164, 127, 7, + 25, 248, 164, 111, 7, 25, 248, 164, 166, 7, 25, 248, 164, 177, 7, 25, + 242, 119, 7, 25, 238, 228, 7, 25, 244, 21, 127, 7, 25, 244, 21, 111, 7, + 25, 243, 16, 127, 7, 25, 243, 16, 111, 7, 25, 243, 59, 7, 25, 248, 244, + 7, 25, 241, 54, 7, 25, 248, 136, 7, 25, 243, 30, 7, 25, 240, 167, 7, 25, + 239, 140, 7, 25, 235, 189, 7, 25, 244, 50, 127, 7, 25, 244, 50, 111, 7, + 25, 243, 27, 7, 25, 254, 122, 127, 7, 25, 254, 122, 111, 7, 25, 234, 23, + 137, 249, 185, 240, 247, 7, 25, 248, 202, 7, 25, 249, 56, 7, 25, 243, + 199, 7, 25, 249, 33, 147, 240, 132, 7, 25, 249, 59, 7, 25, 240, 237, 127, + 7, 25, 240, 237, 111, 7, 25, 238, 164, 7, 25, 243, 122, 7, 25, 232, 72, + 243, 122, 7, 25, 254, 41, 127, 7, 25, 254, 41, 111, 7, 25, 254, 41, 166, + 7, 25, 254, 41, 177, 7, 25, 246, 65, 7, 25, 240, 225, 7, 25, 249, 151, 7, + 25, 249, 58, 7, 25, 249, 129, 7, 25, 243, 151, 127, 7, 25, 243, 151, 111, + 7, 25, 243, 222, 7, 25, 238, 202, 7, 25, 243, 97, 127, 7, 25, 243, 97, + 111, 7, 25, 243, 97, 166, 7, 25, 240, 245, 7, 25, 236, 255, 7, 25, 248, + 56, 127, 7, 25, 248, 56, 111, 7, 25, 232, 72, 248, 184, 7, 25, 234, 23, + 243, 8, 7, 25, 243, 8, 7, 25, 232, 72, 238, 220, 7, 25, 232, 72, 240, + 227, 7, 25, 243, 94, 7, 25, 232, 72, 243, 154, 7, 25, 234, 23, 244, 48, + 7, 25, 249, 13, 127, 7, 25, 249, 13, 111, 7, 25, 243, 156, 7, 25, 232, + 72, 243, 96, 7, 25, 183, 127, 7, 25, 183, 111, 7, 25, 232, 72, 243, 66, + 7, 25, 232, 72, 243, 178, 7, 25, 243, 227, 127, 7, 25, 243, 227, 111, 7, + 25, 243, 250, 7, 25, 243, 149, 7, 25, 232, 72, 240, 242, 236, 230, 7, 25, + 232, 72, 243, 214, 7, 25, 232, 72, 243, 82, 7, 25, 232, 72, 249, 63, 7, + 25, 254, 58, 127, 7, 25, 254, 58, 111, 7, 25, 254, 58, 166, 7, 25, 232, + 72, 248, 207, 7, 25, 243, 99, 7, 25, 232, 72, 240, 189, 7, 25, 243, 150, + 7, 25, 240, 181, 7, 25, 232, 72, 243, 172, 7, 25, 232, 72, 243, 85, 7, + 25, 232, 72, 244, 4, 7, 25, 234, 23, 240, 153, 7, 25, 234, 23, 238, 232, + 7, 25, 232, 72, 243, 176, 7, 25, 232, 84, 243, 93, 7, 25, 232, 72, 243, + 93, 7, 25, 232, 84, 240, 151, 7, 25, 232, 72, 240, 151, 7, 25, 232, 84, + 238, 137, 7, 25, 232, 72, 238, 137, 7, 25, 238, 125, 7, 25, 232, 84, 238, + 125, 7, 25, 232, 72, 238, 125, 43, 25, 127, 43, 25, 242, 224, 43, 25, + 248, 40, 43, 25, 240, 37, 43, 25, 239, 185, 43, 25, 90, 43, 25, 111, 43, + 25, 251, 195, 43, 25, 248, 131, 43, 25, 246, 41, 43, 25, 241, 95, 43, 25, + 195, 43, 25, 92, 248, 92, 43, 25, 241, 67, 43, 25, 249, 84, 43, 25, 240, + 241, 43, 25, 248, 35, 248, 92, 43, 25, 241, 204, 43, 25, 240, 210, 43, + 25, 247, 197, 43, 25, 242, 125, 43, 25, 38, 248, 35, 248, 92, 43, 25, + 241, 150, 234, 36, 43, 25, 248, 53, 43, 25, 233, 83, 43, 25, 244, 5, 43, + 25, 240, 131, 43, 25, 237, 243, 43, 25, 241, 6, 43, 25, 240, 201, 43, 25, + 234, 36, 43, 25, 240, 49, 43, 25, 238, 2, 43, 25, 253, 234, 43, 25, 255, + 75, 239, 198, 43, 25, 237, 153, 43, 25, 250, 123, 43, 25, 240, 253, 43, + 25, 241, 52, 43, 25, 247, 34, 43, 25, 245, 227, 43, 25, 240, 147, 43, 25, + 246, 37, 43, 25, 239, 32, 43, 25, 239, 202, 43, 25, 235, 102, 43, 25, + 242, 84, 43, 25, 247, 196, 43, 25, 237, 226, 43, 25, 239, 232, 43, 25, + 250, 207, 43, 25, 242, 215, 238, 228, 43, 25, 240, 4, 240, 131, 43, 25, + 183, 239, 206, 43, 25, 171, 241, 147, 43, 25, 242, 107, 43, 25, 248, 198, + 43, 25, 242, 120, 43, 25, 237, 80, 43, 25, 247, 121, 43, 25, 240, 138, + 43, 25, 237, 169, 43, 25, 245, 72, 43, 25, 243, 59, 43, 25, 239, 12, 43, + 25, 248, 244, 43, 25, 239, 183, 43, 25, 239, 44, 43, 25, 249, 245, 43, + 25, 238, 59, 43, 25, 248, 233, 43, 25, 248, 136, 43, 25, 252, 169, 43, + 25, 243, 30, 43, 25, 244, 37, 43, 25, 246, 35, 43, 25, 208, 43, 25, 240, + 167, 43, 25, 239, 247, 43, 25, 255, 48, 248, 233, 43, 25, 237, 89, 43, + 25, 249, 64, 43, 25, 245, 21, 43, 25, 242, 133, 43, 25, 240, 105, 43, 25, + 243, 27, 43, 25, 245, 22, 43, 25, 239, 67, 43, 25, 45, 206, 43, 25, 137, + 249, 185, 240, 247, 43, 25, 242, 115, 43, 25, 245, 89, 43, 25, 248, 202, + 43, 25, 249, 56, 43, 25, 236, 80, 43, 25, 243, 199, 43, 25, 241, 233, 43, + 25, 247, 151, 43, 25, 242, 136, 43, 25, 246, 51, 43, 25, 253, 5, 43, 25, + 241, 106, 43, 25, 249, 33, 147, 240, 132, 43, 25, 236, 103, 43, 25, 240, + 4, 247, 139, 43, 25, 240, 39, 43, 25, 247, 91, 43, 25, 245, 68, 43, 25, + 249, 59, 43, 25, 240, 236, 43, 25, 56, 43, 25, 242, 134, 43, 25, 239, + 201, 43, 25, 242, 156, 43, 25, 241, 140, 43, 25, 244, 243, 43, 25, 242, + 131, 43, 25, 238, 164, 43, 25, 247, 30, 43, 25, 243, 122, 43, 25, 251, + 111, 43, 25, 252, 14, 43, 25, 240, 225, 43, 25, 237, 156, 43, 25, 249, + 129, 43, 25, 248, 91, 43, 25, 246, 252, 43, 25, 248, 206, 43, 25, 241, + 39, 43, 25, 243, 222, 43, 25, 236, 61, 43, 25, 244, 6, 43, 25, 238, 249, + 43, 25, 238, 202, 43, 25, 238, 156, 43, 25, 239, 153, 43, 25, 244, 226, + 43, 25, 236, 108, 43, 25, 241, 63, 43, 25, 241, 142, 43, 25, 240, 245, + 43, 25, 239, 100, 43, 25, 241, 34, 43, 25, 249, 13, 234, 36, 43, 25, 236, + 255, 43, 25, 247, 194, 43, 25, 248, 184, 43, 25, 243, 8, 43, 25, 238, + 220, 43, 25, 239, 238, 43, 25, 244, 213, 43, 25, 252, 66, 43, 25, 239, 1, + 43, 25, 240, 227, 43, 25, 252, 131, 43, 25, 252, 151, 43, 25, 243, 94, + 43, 25, 244, 227, 43, 25, 243, 154, 43, 25, 239, 9, 43, 25, 237, 214, 43, + 25, 244, 48, 43, 25, 243, 156, 43, 25, 243, 133, 43, 25, 232, 132, 43, + 25, 238, 43, 43, 25, 243, 96, 43, 25, 243, 66, 43, 25, 243, 178, 43, 25, + 241, 249, 43, 25, 242, 114, 43, 25, 242, 215, 242, 139, 243, 85, 43, 25, + 243, 250, 43, 25, 243, 149, 43, 25, 242, 187, 43, 25, 243, 39, 43, 25, + 236, 230, 43, 25, 240, 242, 236, 230, 43, 25, 246, 40, 43, 25, 242, 121, + 43, 25, 243, 214, 43, 25, 243, 82, 43, 25, 249, 63, 43, 25, 248, 207, 43, + 25, 243, 99, 43, 25, 236, 27, 43, 25, 240, 189, 43, 25, 243, 150, 43, 25, + 247, 137, 43, 25, 245, 140, 43, 25, 241, 108, 43, 25, 233, 232, 243, 133, + 43, 25, 235, 117, 43, 25, 240, 181, 43, 25, 243, 172, 43, 25, 243, 85, + 43, 25, 244, 4, 43, 25, 243, 164, 43, 25, 240, 153, 43, 25, 245, 141, 43, + 25, 238, 232, 43, 25, 239, 137, 43, 25, 240, 0, 43, 25, 233, 195, 43, 25, + 243, 176, 43, 25, 239, 229, 43, 25, 245, 74, 43, 25, 249, 152, 43, 25, + 246, 176, 43, 25, 243, 93, 43, 25, 240, 151, 43, 25, 238, 137, 43, 25, + 238, 125, 43, 25, 241, 112, 80, 233, 55, 99, 40, 153, 225, 80, 233, 55, + 99, 60, 153, 46, 80, 233, 55, 99, 40, 153, 240, 1, 19, 225, 80, 233, 55, + 99, 60, 153, 240, 1, 19, 46, 80, 233, 55, 99, 248, 37, 236, 121, 80, 233, + 55, 99, 236, 204, 248, 44, 48, 80, 233, 55, 99, 236, 204, 248, 44, 46, + 80, 233, 55, 99, 236, 204, 248, 44, 242, 220, 80, 233, 55, 99, 236, 204, + 248, 44, 189, 242, 220, 80, 233, 55, 99, 236, 204, 248, 44, 189, 225, 80, + 233, 55, 99, 236, 204, 248, 44, 168, 242, 220, 80, 233, 55, 99, 236, 66, + 80, 240, 15, 80, 240, 27, 80, 248, 37, 208, 245, 69, 69, 237, 184, 234, + 206, 237, 44, 91, 80, 235, 77, 69, 80, 238, 171, 69, 80, 61, 242, 217, + 40, 185, 104, 38, 185, 104, 40, 45, 185, 104, 38, 45, 185, 104, 40, 240, + 31, 104, 38, 240, 31, 104, 40, 64, 240, 31, 104, 38, 64, 240, 31, 104, + 40, 86, 234, 11, 104, 38, 86, 234, 11, 104, 240, 142, 69, 251, 16, 69, + 40, 236, 171, 242, 255, 104, 38, 236, 171, 242, 255, 104, 40, 64, 234, + 11, 104, 38, 64, 234, 11, 104, 40, 64, 236, 171, 242, 255, 104, 38, 64, + 236, 171, 242, 255, 104, 40, 64, 31, 104, 38, 64, 31, 104, 248, 141, 242, + 235, 224, 45, 243, 117, 235, 51, 69, 45, 243, 117, 235, 51, 69, 170, 45, + 243, 117, 235, 51, 69, 240, 142, 158, 243, 39, 236, 166, 178, 127, 236, + 166, 178, 111, 236, 166, 178, 166, 236, 166, 178, 177, 236, 166, 178, + 176, 236, 166, 178, 187, 236, 166, 178, 203, 236, 166, 178, 195, 236, + 166, 178, 202, 80, 246, 42, 188, 69, 80, 240, 69, 188, 69, 80, 235, 98, + 188, 69, 80, 237, 151, 188, 69, 23, 240, 12, 53, 188, 69, 23, 45, 53, + 188, 69, 248, 103, 242, 235, 59, 248, 130, 240, 64, 69, 59, 248, 130, + 240, 64, 2, 240, 59, 243, 1, 69, 59, 248, 130, 240, 64, 158, 189, 243, 7, + 59, 248, 130, 240, 64, 2, 240, 59, 243, 1, 158, 189, 243, 7, 59, 248, + 130, 240, 64, 158, 168, 243, 7, 29, 240, 142, 69, 80, 145, 248, 41, 250, + 237, 235, 95, 91, 236, 166, 178, 248, 53, 236, 166, 178, 238, 77, 236, + 166, 178, 238, 101, 59, 80, 235, 77, 69, 251, 219, 69, 249, 134, 233, + 112, 69, 80, 34, 234, 30, 80, 137, 250, 245, 240, 15, 105, 1, 3, 67, 105, + 1, 67, 105, 1, 3, 71, 105, 1, 71, 105, 1, 3, 79, 105, 1, 79, 105, 1, 3, + 72, 105, 1, 72, 105, 1, 3, 73, 105, 1, 73, 105, 1, 201, 105, 1, 253, 139, + 105, 1, 253, 215, 105, 1, 254, 6, 105, 1, 253, 203, 105, 1, 253, 235, + 105, 1, 253, 172, 105, 1, 254, 5, 105, 1, 253, 190, 105, 1, 253, 234, + 105, 1, 253, 132, 105, 1, 253, 163, 105, 1, 253, 198, 105, 1, 254, 17, + 105, 1, 253, 211, 105, 1, 254, 18, 105, 1, 253, 210, 105, 1, 253, 228, + 105, 1, 253, 186, 105, 1, 253, 222, 105, 1, 253, 126, 105, 1, 253, 133, + 105, 1, 253, 212, 105, 1, 253, 201, 105, 1, 3, 253, 196, 105, 1, 253, + 196, 105, 1, 253, 232, 105, 1, 253, 195, 105, 1, 253, 200, 105, 1, 87, + 105, 1, 253, 225, 105, 1, 253, 131, 105, 1, 253, 166, 105, 1, 253, 150, + 105, 1, 253, 197, 105, 1, 253, 173, 105, 1, 219, 105, 1, 253, 141, 105, + 1, 253, 129, 105, 1, 253, 214, 105, 1, 254, 34, 105, 1, 253, 147, 105, 1, + 253, 236, 105, 1, 253, 243, 105, 1, 253, 239, 105, 1, 253, 168, 105, 1, + 253, 242, 105, 1, 253, 175, 105, 1, 253, 184, 105, 1, 254, 1, 105, 1, + 253, 208, 105, 1, 222, 105, 1, 253, 180, 105, 1, 253, 154, 105, 1, 253, + 206, 105, 1, 253, 181, 105, 1, 3, 216, 105, 1, 216, 105, 1, 3, 253, 161, + 105, 1, 253, 161, 105, 1, 3, 253, 162, 105, 1, 253, 162, 105, 1, 253, + 130, 105, 1, 253, 209, 105, 1, 253, 185, 105, 1, 253, 194, 105, 1, 253, + 160, 105, 1, 3, 253, 138, 105, 1, 253, 138, 105, 1, 253, 187, 105, 1, + 253, 170, 105, 1, 253, 177, 105, 1, 197, 105, 1, 254, 49, 105, 1, 3, 201, + 105, 1, 3, 253, 172, 50, 226, 254, 240, 59, 243, 1, 69, 50, 226, 254, + 233, 75, 243, 1, 69, 226, 254, 240, 59, 243, 1, 69, 226, 254, 233, 75, + 243, 1, 69, 105, 235, 77, 69, 105, 240, 59, 235, 77, 69, 105, 238, 112, + 247, 233, 226, 254, 45, 238, 93, 42, 1, 3, 67, 42, 1, 67, 42, 1, 3, 71, + 42, 1, 71, 42, 1, 3, 79, 42, 1, 79, 42, 1, 3, 72, 42, 1, 72, 42, 1, 3, + 73, 42, 1, 73, 42, 1, 201, 42, 1, 253, 139, 42, 1, 253, 215, 42, 1, 254, + 6, 42, 1, 253, 203, 42, 1, 253, 235, 42, 1, 253, 172, 42, 1, 254, 5, 42, + 1, 253, 190, 42, 1, 253, 234, 42, 1, 253, 132, 42, 1, 253, 163, 42, 1, + 253, 198, 42, 1, 254, 17, 42, 1, 253, 211, 42, 1, 254, 18, 42, 1, 253, + 210, 42, 1, 253, 228, 42, 1, 253, 186, 42, 1, 253, 222, 42, 1, 253, 126, + 42, 1, 253, 133, 42, 1, 253, 212, 42, 1, 253, 201, 42, 1, 3, 253, 196, + 42, 1, 253, 196, 42, 1, 253, 232, 42, 1, 253, 195, 42, 1, 253, 200, 42, + 1, 87, 42, 1, 253, 225, 42, 1, 253, 131, 42, 1, 253, 166, 42, 1, 253, + 150, 42, 1, 253, 197, 42, 1, 253, 173, 42, 1, 219, 42, 1, 253, 141, 42, + 1, 253, 129, 42, 1, 253, 214, 42, 1, 254, 34, 42, 1, 253, 147, 42, 1, + 253, 236, 42, 1, 253, 243, 42, 1, 253, 239, 42, 1, 253, 168, 42, 1, 253, + 242, 42, 1, 253, 175, 42, 1, 253, 184, 42, 1, 254, 1, 42, 1, 253, 208, + 42, 1, 222, 42, 1, 253, 180, 42, 1, 253, 154, 42, 1, 253, 206, 42, 1, + 253, 181, 42, 1, 3, 216, 42, 1, 216, 42, 1, 3, 253, 161, 42, 1, 253, 161, + 42, 1, 3, 253, 162, 42, 1, 253, 162, 42, 1, 253, 130, 42, 1, 253, 209, + 42, 1, 253, 185, 42, 1, 253, 194, 42, 1, 253, 160, 42, 1, 3, 253, 138, + 42, 1, 253, 138, 42, 1, 253, 187, 42, 1, 253, 170, 42, 1, 253, 177, 42, + 1, 197, 42, 1, 254, 49, 42, 1, 3, 201, 42, 1, 3, 253, 172, 42, 1, 253, + 171, 42, 1, 254, 48, 42, 1, 254, 12, 42, 1, 254, 13, 42, 240, 1, 248, 40, + 226, 254, 235, 138, 243, 1, 69, 42, 235, 77, 69, 42, 240, 59, 235, 77, + 69, 42, 238, 112, 246, 19, 155, 1, 217, 155, 1, 223, 155, 1, 173, 155, 1, + 255, 19, 155, 1, 209, 155, 1, 214, 155, 1, 197, 155, 1, 162, 155, 1, 210, + 155, 1, 255, 15, 155, 1, 192, 155, 1, 221, 155, 1, 255, 20, 155, 1, 206, + 155, 1, 255, 11, 155, 1, 254, 151, 155, 1, 254, 72, 155, 1, 144, 155, 1, + 255, 17, 155, 1, 255, 18, 155, 1, 193, 155, 1, 67, 155, 1, 73, 155, 1, + 72, 155, 1, 254, 36, 155, 1, 253, 149, 155, 1, 254, 89, 155, 1, 253, 151, + 155, 1, 254, 10, 155, 1, 254, 19, 155, 1, 253, 202, 155, 1, 248, 124, + 155, 1, 248, 108, 155, 1, 254, 4, 155, 1, 71, 155, 1, 79, 155, 1, 254, + 101, 155, 1, 179, 155, 1, 254, 26, 155, 1, 254, 168, 23, 1, 238, 99, 23, + 1, 232, 87, 23, 1, 232, 91, 23, 1, 240, 80, 23, 1, 232, 93, 23, 1, 232, + 94, 23, 1, 238, 102, 23, 1, 232, 101, 23, 1, 240, 85, 23, 1, 231, 98, 23, + 1, 232, 96, 23, 1, 232, 97, 23, 1, 233, 74, 23, 1, 231, 43, 23, 1, 231, + 42, 23, 1, 232, 85, 23, 1, 240, 78, 23, 1, 240, 83, 23, 1, 233, 79, 23, + 1, 233, 66, 23, 1, 243, 34, 23, 1, 234, 32, 23, 1, 240, 75, 23, 1, 240, + 71, 23, 1, 233, 77, 23, 1, 236, 195, 23, 1, 236, 198, 23, 1, 236, 205, + 23, 1, 236, 201, 23, 1, 240, 74, 23, 1, 67, 23, 1, 253, 178, 23, 1, 216, + 23, 1, 249, 18, 23, 1, 254, 59, 23, 1, 72, 23, 1, 249, 22, 23, 1, 253, + 254, 23, 1, 73, 23, 1, 253, 138, 23, 1, 249, 12, 23, 1, 253, 193, 23, 1, + 253, 162, 23, 1, 79, 23, 1, 249, 14, 23, 1, 253, 170, 23, 1, 253, 187, + 23, 1, 253, 161, 23, 1, 254, 61, 23, 1, 253, 189, 23, 1, 71, 23, 238, + 114, 23, 1, 233, 105, 23, 1, 231, 97, 23, 1, 233, 90, 23, 1, 231, 47, 23, + 1, 226, 245, 23, 1, 231, 111, 23, 1, 226, 255, 23, 1, 231, 54, 23, 1, + 226, 246, 23, 1, 232, 92, 23, 1, 233, 86, 23, 1, 231, 46, 23, 1, 231, 40, + 23, 1, 231, 109, 23, 1, 231, 110, 23, 1, 226, 243, 23, 1, 226, 244, 23, + 1, 232, 106, 23, 1, 231, 52, 23, 1, 231, 41, 23, 1, 226, 235, 23, 1, 232, + 99, 23, 1, 233, 102, 23, 1, 232, 100, 23, 1, 233, 76, 23, 1, 233, 101, + 23, 1, 236, 234, 23, 1, 233, 78, 23, 1, 235, 115, 23, 1, 231, 58, 23, 1, + 227, 0, 23, 1, 227, 9, 23, 1, 233, 104, 23, 1, 232, 102, 23, 1, 240, 255, + 23, 1, 238, 233, 23, 1, 244, 58, 23, 1, 238, 234, 23, 1, 241, 0, 23, 1, + 244, 60, 23, 1, 240, 156, 23, 1, 238, 247, 80, 234, 4, 239, 123, 69, 80, + 234, 4, 238, 75, 69, 80, 234, 4, 253, 125, 69, 80, 234, 4, 171, 69, 80, + 234, 4, 204, 69, 80, 234, 4, 248, 58, 69, 80, 234, 4, 253, 159, 69, 80, + 234, 4, 240, 1, 69, 80, 234, 4, 240, 17, 69, 80, 234, 4, 243, 41, 69, 80, + 234, 4, 240, 87, 69, 80, 234, 4, 243, 129, 69, 80, 234, 4, 240, 137, 69, + 80, 234, 4, 241, 148, 69, 80, 234, 4, 243, 168, 69, 80, 234, 4, 254, 111, + 69, 155, 1, 253, 243, 155, 1, 254, 17, 155, 1, 254, 7, 155, 1, 253, 235, + 155, 1, 253, 164, 155, 1, 250, 224, 155, 1, 253, 156, 155, 1, 249, 130, + 155, 1, 254, 177, 155, 1, 249, 238, 155, 1, 251, 105, 155, 1, 252, 254, + 155, 1, 254, 175, 155, 1, 252, 18, 155, 1, 244, 73, 155, 1, 244, 86, 155, + 1, 254, 32, 155, 1, 254, 43, 155, 1, 252, 59, 155, 1, 245, 229, 155, 30, + 1, 223, 155, 30, 1, 214, 155, 30, 1, 255, 15, 155, 30, 1, 192, 7, 240, 5, + 214, 7, 240, 5, 255, 3, 7, 240, 5, 255, 5, 7, 240, 5, 250, 137, 7, 240, + 5, 254, 128, 7, 240, 5, 251, 96, 7, 240, 5, 251, 93, 7, 240, 5, 254, 97, + 7, 240, 5, 245, 219, 7, 240, 5, 247, 134, 7, 240, 5, 251, 94, 7, 240, 5, + 245, 220, 7, 240, 5, 245, 202, 7, 240, 5, 251, 95, 7, 240, 5, 245, 221, + 7, 240, 5, 197, 42, 1, 3, 253, 203, 42, 1, 3, 253, 198, 42, 1, 3, 253, + 211, 42, 1, 3, 87, 42, 1, 3, 253, 150, 42, 1, 3, 219, 42, 1, 3, 253, 214, + 42, 1, 3, 253, 236, 42, 1, 3, 253, 168, 42, 1, 3, 253, 184, 42, 1, 3, + 253, 154, 42, 1, 3, 253, 130, 42, 1, 3, 253, 209, 42, 1, 3, 253, 185, 42, + 1, 3, 253, 194, 42, 1, 3, 253, 160, 82, 23, 238, 99, 82, 23, 240, 80, 82, + 23, 238, 102, 82, 23, 240, 85, 82, 23, 240, 78, 82, 23, 240, 83, 82, 23, + 243, 34, 82, 23, 240, 75, 82, 23, 240, 71, 82, 23, 236, 195, 82, 23, 236, + 198, 82, 23, 236, 205, 82, 23, 236, 201, 82, 23, 240, 74, 82, 23, 240, + 193, 67, 82, 23, 243, 233, 67, 82, 23, 240, 246, 67, 82, 23, 243, 254, + 67, 82, 23, 243, 226, 67, 82, 23, 243, 242, 67, 82, 23, 249, 164, 67, 82, + 23, 243, 100, 67, 82, 23, 243, 90, 67, 82, 23, 238, 169, 67, 82, 23, 238, + 194, 67, 82, 23, 238, 227, 67, 82, 23, 238, 206, 67, 82, 23, 243, 195, + 67, 82, 23, 243, 90, 79, 82, 240, 99, 99, 242, 39, 82, 240, 99, 99, 117, + 253, 236, 82, 110, 127, 82, 110, 111, 82, 110, 166, 82, 110, 177, 82, + 110, 176, 82, 110, 187, 82, 110, 203, 82, 110, 195, 82, 110, 202, 82, + 110, 248, 53, 82, 110, 243, 30, 82, 110, 243, 27, 82, 110, 240, 105, 82, + 110, 244, 52, 82, 110, 240, 199, 82, 110, 240, 49, 82, 110, 248, 136, 82, + 110, 240, 238, 82, 110, 243, 191, 82, 110, 237, 41, 82, 110, 243, 230, + 82, 110, 237, 43, 82, 110, 234, 53, 82, 110, 229, 61, 82, 110, 240, 195, + 82, 110, 234, 247, 82, 110, 244, 241, 82, 110, 240, 239, 82, 110, 234, + 66, 82, 110, 233, 84, 82, 110, 235, 140, 82, 110, 235, 116, 82, 110, 236, + 20, 82, 110, 242, 239, 82, 110, 244, 6, 82, 110, 240, 215, 233, 94, 52, + 29, 61, 240, 48, 127, 29, 61, 240, 48, 111, 29, 61, 240, 48, 166, 29, 61, + 240, 48, 177, 29, 61, 240, 48, 176, 29, 61, 240, 48, 187, 29, 61, 240, + 48, 203, 29, 61, 240, 48, 195, 29, 61, 240, 48, 202, 29, 61, 238, 101, + 29, 61, 240, 53, 127, 29, 61, 240, 53, 111, 29, 61, 240, 53, 166, 29, 61, + 240, 53, 177, 29, 61, 240, 53, 176, 29, 23, 238, 99, 29, 23, 240, 80, 29, + 23, 238, 102, 29, 23, 240, 85, 29, 23, 240, 78, 29, 23, 240, 83, 29, 23, + 243, 34, 29, 23, 240, 75, 29, 23, 240, 71, 29, 23, 236, 195, 29, 23, 236, + 198, 29, 23, 236, 205, 29, 23, 236, 201, 29, 23, 240, 74, 29, 23, 240, + 193, 67, 29, 23, 243, 233, 67, 29, 23, 240, 246, 67, 29, 23, 243, 254, + 67, 29, 23, 243, 226, 67, 29, 23, 243, 242, 67, 29, 23, 249, 164, 67, 29, + 23, 243, 100, 67, 29, 23, 243, 90, 67, 29, 23, 238, 169, 67, 29, 23, 238, + 194, 67, 29, 23, 238, 227, 67, 29, 23, 238, 206, 67, 29, 23, 243, 195, + 67, 29, 240, 99, 99, 239, 20, 29, 240, 99, 99, 241, 190, 29, 23, 243, + 100, 79, 240, 99, 237, 44, 91, 29, 110, 127, 29, 110, 111, 29, 110, 166, + 29, 110, 177, 29, 110, 176, 29, 110, 187, 29, 110, 203, 29, 110, 195, 29, + 110, 202, 29, 110, 248, 53, 29, 110, 243, 30, 29, 110, 243, 27, 29, 110, + 240, 105, 29, 110, 244, 52, 29, 110, 240, 199, 29, 110, 240, 49, 29, 110, + 248, 136, 29, 110, 240, 238, 29, 110, 243, 191, 29, 110, 237, 41, 29, + 110, 243, 230, 29, 110, 237, 43, 29, 110, 234, 53, 29, 110, 229, 61, 29, + 110, 240, 195, 29, 110, 239, 186, 29, 110, 246, 62, 29, 110, 239, 68, 29, + 110, 236, 120, 29, 110, 234, 188, 29, 110, 242, 65, 29, 110, 234, 95, 29, + 110, 245, 232, 29, 110, 242, 239, 29, 110, 245, 27, 29, 110, 237, 93, 29, + 110, 245, 146, 29, 110, 238, 129, 29, 110, 251, 207, 29, 110, 242, 220, + 29, 110, 225, 29, 110, 236, 59, 29, 110, 236, 91, 29, 110, 240, 239, 29, + 110, 234, 66, 29, 110, 233, 84, 29, 110, 235, 140, 29, 110, 235, 116, 29, + 110, 242, 11, 29, 61, 240, 53, 187, 29, 61, 240, 53, 203, 29, 61, 240, + 53, 195, 29, 61, 240, 53, 202, 29, 61, 240, 136, 29, 61, 243, 6, 127, 29, + 61, 243, 6, 111, 29, 61, 243, 6, 166, 29, 61, 243, 6, 177, 29, 61, 243, + 6, 176, 29, 61, 243, 6, 187, 29, 61, 243, 6, 203, 29, 61, 243, 6, 195, + 29, 61, 243, 6, 202, 29, 61, 240, 50, 80, 145, 12, 28, 237, 183, 80, 145, + 12, 28, 236, 19, 80, 145, 12, 28, 241, 229, 80, 145, 12, 28, 241, 12, 80, + 145, 12, 28, 251, 222, 80, 145, 12, 28, 245, 253, 80, 145, 12, 28, 245, + 252, 80, 145, 12, 28, 238, 253, 80, 145, 12, 28, 234, 252, 80, 145, 12, + 28, 237, 224, 80, 145, 12, 28, 236, 65, 80, 145, 12, 28, 235, 200, 31, + 254, 171, 31, 250, 227, 31, 254, 160, 239, 118, 236, 51, 52, 29, 42, 67, + 29, 42, 71, 29, 42, 79, 29, 42, 72, 29, 42, 73, 29, 42, 201, 29, 42, 253, + 215, 29, 42, 253, 203, 29, 42, 253, 172, 29, 42, 253, 190, 29, 42, 253, + 132, 29, 42, 253, 198, 29, 42, 253, 211, 29, 42, 253, 210, 29, 42, 253, + 186, 29, 42, 253, 126, 29, 42, 253, 212, 29, 42, 253, 196, 29, 42, 253, + 195, 29, 42, 87, 29, 42, 253, 131, 29, 42, 253, 166, 29, 42, 253, 150, + 29, 42, 253, 197, 29, 42, 253, 173, 29, 42, 219, 29, 42, 253, 214, 29, + 42, 253, 236, 29, 42, 253, 168, 29, 42, 253, 184, 29, 42, 222, 29, 42, + 253, 180, 29, 42, 253, 154, 29, 42, 253, 206, 29, 42, 253, 181, 29, 42, + 216, 29, 42, 253, 161, 29, 42, 253, 162, 29, 42, 253, 130, 29, 42, 253, + 209, 29, 42, 253, 185, 29, 42, 253, 194, 29, 42, 253, 160, 29, 42, 253, + 138, 29, 42, 253, 187, 29, 42, 253, 170, 29, 42, 253, 177, 31, 238, 246, + 31, 238, 251, 31, 241, 10, 31, 244, 68, 31, 239, 99, 31, 245, 230, 31, + 252, 255, 31, 236, 15, 31, 241, 91, 31, 246, 232, 31, 246, 233, 31, 241, + 192, 31, 237, 187, 31, 237, 188, 31, 241, 124, 31, 241, 123, 31, 245, + 124, 31, 241, 137, 31, 239, 112, 31, 237, 165, 31, 246, 16, 31, 233, 213, + 31, 232, 180, 31, 234, 214, 31, 239, 87, 31, 234, 198, 31, 234, 216, 31, + 237, 192, 31, 241, 196, 31, 239, 110, 31, 241, 205, 31, 237, 254, 31, + 236, 95, 31, 238, 7, 31, 242, 101, 31, 242, 102, 31, 241, 70, 31, 245, + 63, 31, 245, 73, 31, 252, 227, 31, 246, 105, 31, 242, 24, 31, 241, 146, + 31, 236, 67, 31, 242, 46, 31, 237, 69, 31, 234, 233, 31, 239, 161, 31, + 246, 251, 31, 244, 223, 31, 236, 36, 31, 239, 95, 31, 235, 184, 31, 241, + 170, 31, 234, 199, 31, 246, 242, 31, 239, 159, 31, 239, 93, 31, 242, 55, + 31, 242, 52, 31, 241, 26, 31, 239, 164, 31, 239, 11, 31, 251, 77, 31, + 242, 64, 31, 241, 167, 31, 245, 200, 31, 237, 197, 31, 241, 225, 31, 241, + 224, 31, 239, 129, 31, 237, 199, 31, 237, 210, 31, 246, 88, 31, 234, 223, + 31, 243, 106, 31, 237, 207, 31, 237, 206, 31, 242, 190, 31, 242, 191, 31, + 247, 237, 31, 237, 252, 31, 247, 32, 31, 242, 90, 31, 237, 253, 31, 247, + 29, 31, 236, 92, 31, 242, 183, 80, 145, 12, 28, 248, 52, 242, 217, 80, + 145, 12, 28, 248, 52, 127, 80, 145, 12, 28, 248, 52, 111, 80, 145, 12, + 28, 248, 52, 166, 80, 145, 12, 28, 248, 52, 177, 80, 145, 12, 28, 248, + 52, 176, 80, 145, 12, 28, 248, 52, 187, 80, 145, 12, 28, 248, 52, 203, + 80, 145, 12, 28, 248, 52, 195, 80, 145, 12, 28, 248, 52, 202, 80, 145, + 12, 28, 248, 52, 248, 53, 80, 145, 12, 28, 248, 52, 238, 91, 80, 145, 12, + 28, 248, 52, 238, 97, 80, 145, 12, 28, 248, 52, 235, 85, 80, 145, 12, 28, + 248, 52, 235, 82, 80, 145, 12, 28, 248, 52, 236, 207, 80, 145, 12, 28, + 248, 52, 236, 202, 80, 145, 12, 28, 248, 52, 234, 22, 80, 145, 12, 28, + 248, 52, 235, 81, 80, 145, 12, 28, 248, 52, 235, 83, 80, 145, 12, 28, + 248, 52, 238, 77, 80, 145, 12, 28, 248, 52, 233, 110, 80, 145, 12, 28, + 248, 52, 233, 111, 80, 145, 12, 28, 248, 52, 231, 114, 80, 145, 12, 28, + 248, 52, 232, 111, 31, 251, 82, 31, 253, 133, 31, 253, 151, 31, 125, 31, + 254, 219, 31, 254, 222, 31, 254, 156, 31, 255, 53, 236, 191, 31, 255, 53, + 240, 94, 31, 254, 101, 31, 254, 37, 248, 170, 239, 89, 31, 254, 37, 248, + 170, 239, 213, 31, 254, 37, 248, 170, 238, 21, 31, 254, 37, 248, 170, + 241, 232, 31, 232, 123, 31, 255, 87, 244, 79, 31, 253, 131, 31, 255, 27, + 67, 31, 222, 31, 201, 31, 254, 182, 31, 254, 199, 31, 254, 166, 31, 250, + 143, 31, 246, 7, 31, 254, 224, 31, 254, 211, 31, 255, 27, 255, 19, 31, + 255, 27, 210, 31, 254, 202, 31, 254, 106, 31, 254, 173, 31, 251, 147, 31, + 251, 230, 31, 251, 20, 31, 252, 220, 31, 255, 27, 162, 31, 254, 204, 31, + 254, 155, 31, 254, 186, 31, 254, 164, 31, 254, 215, 31, 255, 27, 173, 31, + 254, 205, 31, 254, 152, 31, 254, 187, 31, 255, 61, 236, 191, 31, 255, 52, + 236, 191, 31, 255, 108, 236, 191, 31, 255, 50, 236, 191, 31, 255, 61, + 240, 94, 31, 255, 52, 240, 94, 31, 255, 108, 240, 94, 31, 255, 50, 240, + 94, 31, 255, 108, 248, 59, 193, 31, 255, 108, 248, 59, 255, 99, 236, 191, + 31, 253, 129, 31, 251, 163, 31, 249, 115, 31, 251, 28, 31, 252, 126, 31, + 254, 71, 248, 59, 193, 31, 254, 71, 248, 59, 255, 99, 236, 191, 31, 254, + 229, 31, 254, 216, 31, 255, 27, 193, 31, 254, 206, 31, 254, 230, 31, 254, + 115, 31, 255, 27, 179, 31, 254, 207, 31, 254, 189, 31, 255, 84, 243, 106, + 31, 254, 231, 31, 254, 217, 31, 255, 27, 255, 16, 31, 254, 208, 31, 254, + 108, 31, 255, 85, 243, 106, 31, 255, 109, 249, 126, 31, 255, 108, 249, + 126, 31, 254, 32, 31, 254, 147, 31, 254, 149, 31, 254, 150, 31, 255, 105, + 248, 59, 254, 106, 31, 253, 224, 31, 254, 154, 31, 254, 170, 31, 219, 31, + 254, 97, 31, 253, 247, 31, 254, 107, 31, 255, 50, 237, 83, 31, 254, 188, + 31, 254, 194, 31, 254, 195, 31, 251, 203, 31, 254, 197, 31, 255, 80, 240, + 147, 31, 251, 233, 31, 251, 240, 31, 254, 225, 31, 254, 226, 31, 252, 75, + 31, 254, 228, 31, 254, 241, 31, 254, 127, 31, 255, 2, 31, 255, 110, 248, + 59, 173, 31, 134, 248, 59, 173, 80, 145, 12, 28, 253, 137, 127, 80, 145, + 12, 28, 253, 137, 111, 80, 145, 12, 28, 253, 137, 166, 80, 145, 12, 28, + 253, 137, 177, 80, 145, 12, 28, 253, 137, 176, 80, 145, 12, 28, 253, 137, + 187, 80, 145, 12, 28, 253, 137, 203, 80, 145, 12, 28, 253, 137, 195, 80, + 145, 12, 28, 253, 137, 202, 80, 145, 12, 28, 253, 137, 248, 53, 80, 145, + 12, 28, 253, 137, 238, 91, 80, 145, 12, 28, 253, 137, 238, 97, 80, 145, + 12, 28, 253, 137, 235, 85, 80, 145, 12, 28, 253, 137, 235, 82, 80, 145, + 12, 28, 253, 137, 236, 207, 80, 145, 12, 28, 253, 137, 236, 202, 80, 145, + 12, 28, 253, 137, 234, 22, 80, 145, 12, 28, 253, 137, 235, 81, 80, 145, + 12, 28, 253, 137, 235, 83, 80, 145, 12, 28, 253, 137, 238, 77, 80, 145, + 12, 28, 253, 137, 233, 110, 80, 145, 12, 28, 253, 137, 233, 111, 80, 145, + 12, 28, 253, 137, 231, 114, 80, 145, 12, 28, 253, 137, 232, 111, 80, 145, + 12, 28, 253, 137, 233, 45, 80, 145, 12, 28, 253, 137, 233, 255, 80, 145, + 12, 28, 253, 137, 232, 64, 80, 145, 12, 28, 253, 137, 232, 63, 80, 145, + 12, 28, 253, 137, 233, 46, 80, 145, 12, 28, 253, 137, 238, 101, 80, 145, + 12, 28, 253, 137, 233, 252, 31, 251, 7, 156, 28, 253, 145, 237, 94, 238, + 139, 156, 28, 253, 145, 236, 86, 240, 49, 156, 28, 234, 112, 255, 31, + 253, 145, 234, 97, 156, 28, 238, 48, 241, 113, 156, 28, 237, 51, 156, 28, + 235, 191, 156, 28, 253, 145, 244, 84, 156, 28, 238, 189, 235, 153, 156, + 28, 3, 238, 222, 156, 28, 236, 130, 156, 28, 242, 51, 156, 28, 233, 247, + 156, 28, 233, 201, 156, 28, 243, 58, 233, 224, 156, 28, 237, 212, 156, + 28, 233, 197, 156, 28, 234, 54, 156, 28, 253, 37, 255, 34, 253, 145, 237, + 102, 156, 28, 235, 166, 156, 28, 231, 63, 156, 28, 241, 32, 238, 27, 156, + 28, 241, 139, 156, 28, 236, 104, 241, 11, 156, 28, 238, 211, 156, 28, + 234, 208, 156, 28, 243, 58, 238, 222, 156, 28, 246, 91, 237, 0, 156, 28, + 243, 58, 231, 53, 156, 28, 253, 145, 238, 236, 240, 105, 156, 28, 253, + 145, 237, 87, 243, 27, 156, 28, 234, 207, 156, 28, 236, 9, 156, 28, 237, + 251, 156, 28, 243, 58, 240, 210, 156, 28, 236, 81, 156, 28, 235, 198, + 147, 253, 145, 240, 9, 156, 28, 253, 145, 239, 66, 156, 28, 233, 73, 156, + 28, 232, 189, 156, 28, 232, 128, 156, 28, 235, 201, 156, 28, 235, 127, + 156, 28, 231, 119, 156, 28, 241, 65, 153, 243, 224, 156, 28, 235, 124, + 235, 153, 156, 28, 239, 170, 239, 235, 156, 28, 233, 221, 156, 28, 253, + 145, 247, 193, 156, 28, 233, 231, 156, 28, 253, 145, 235, 117, 156, 28, + 253, 145, 237, 67, 237, 48, 156, 28, 253, 145, 238, 193, 247, 123, 235, + 102, 156, 28, 232, 131, 156, 28, 253, 145, 237, 203, 239, 125, 156, 28, + 234, 89, 156, 28, 253, 145, 236, 139, 156, 28, 253, 145, 241, 125, 243, + 82, 156, 28, 253, 145, 241, 188, 243, 213, 156, 28, 233, 135, 156, 28, + 233, 216, 156, 28, 245, 228, 242, 158, 156, 28, 3, 231, 53, 156, 28, 244, + 70, 233, 69, 156, 28, 241, 27, 233, 69, 6, 4, 254, 179, 6, 4, 254, 180, + 6, 4, 71, 6, 4, 254, 176, 6, 4, 251, 102, 6, 4, 251, 103, 6, 4, 253, 237, + 6, 4, 251, 101, 6, 4, 254, 20, 6, 4, 254, 144, 6, 4, 67, 6, 4, 254, 141, + 6, 4, 253, 1, 6, 4, 254, 252, 6, 4, 253, 0, 6, 4, 254, 67, 6, 4, 254, + 220, 6, 4, 73, 6, 4, 254, 120, 6, 4, 254, 161, 6, 4, 72, 6, 4, 254, 14, + 6, 4, 250, 125, 6, 4, 250, 126, 6, 4, 254, 34, 6, 4, 250, 124, 6, 4, 244, + 221, 6, 4, 244, 222, 6, 4, 250, 122, 6, 4, 244, 220, 6, 4, 250, 104, 6, + 4, 250, 105, 6, 4, 253, 141, 6, 4, 250, 103, 6, 4, 244, 235, 6, 4, 250, + 131, 6, 4, 244, 234, 6, 4, 250, 130, 6, 4, 248, 92, 6, 4, 254, 1, 6, 4, + 250, 129, 6, 4, 250, 119, 6, 4, 253, 242, 6, 4, 250, 116, 6, 4, 250, 133, + 6, 4, 250, 134, 6, 4, 253, 243, 6, 4, 250, 132, 6, 4, 244, 236, 6, 4, + 249, 35, 6, 4, 250, 140, 6, 4, 250, 141, 6, 4, 254, 82, 6, 4, 250, 138, + 6, 4, 244, 238, 6, 4, 250, 139, 6, 4, 252, 68, 6, 4, 252, 69, 6, 4, 253, + 147, 6, 4, 252, 67, 6, 4, 246, 250, 6, 4, 252, 65, 6, 4, 246, 249, 6, 4, + 252, 61, 6, 4, 252, 62, 6, 4, 253, 129, 6, 4, 252, 60, 6, 4, 247, 0, 6, + 4, 252, 78, 6, 4, 246, 255, 6, 4, 252, 73, 6, 4, 252, 74, 6, 4, 253, 208, + 6, 4, 252, 72, 6, 4, 249, 142, 6, 4, 252, 81, 6, 4, 253, 239, 6, 4, 252, + 79, 6, 4, 247, 1, 6, 4, 252, 80, 6, 4, 249, 144, 6, 4, 252, 84, 6, 4, + 254, 232, 6, 4, 252, 82, 6, 4, 247, 3, 6, 4, 252, 83, 6, 4, 244, 200, 6, + 4, 244, 201, 6, 4, 250, 108, 6, 4, 244, 199, 6, 4, 241, 21, 6, 4, 241, + 22, 6, 4, 244, 198, 6, 4, 241, 20, 6, 4, 244, 194, 6, 4, 244, 195, 6, 4, + 250, 106, 6, 4, 244, 193, 6, 4, 241, 24, 6, 4, 244, 205, 6, 4, 241, 23, + 6, 4, 244, 203, 6, 4, 244, 204, 6, 4, 250, 109, 6, 4, 244, 202, 6, 4, + 244, 197, 6, 4, 250, 107, 6, 4, 244, 196, 6, 4, 243, 145, 6, 4, 244, 208, + 6, 4, 250, 110, 6, 4, 244, 206, 6, 4, 241, 25, 6, 4, 244, 207, 6, 4, 244, + 210, 6, 4, 244, 211, 6, 4, 250, 111, 6, 4, 244, 209, 6, 4, 246, 110, 6, + 4, 246, 111, 6, 4, 252, 3, 6, 4, 246, 109, 6, 4, 242, 0, 6, 4, 243, 232, + 6, 4, 241, 255, 6, 4, 246, 107, 6, 4, 246, 108, 6, 4, 252, 2, 6, 4, 246, + 106, 6, 4, 246, 113, 6, 4, 246, 114, 6, 4, 252, 4, 6, 4, 246, 112, 6, 4, + 246, 117, 6, 4, 246, 118, 6, 4, 252, 5, 6, 4, 246, 115, 6, 4, 242, 1, 6, + 4, 246, 116, 6, 4, 246, 121, 6, 4, 246, 122, 6, 4, 252, 6, 6, 4, 246, + 119, 6, 4, 242, 2, 6, 4, 246, 120, 6, 4, 245, 173, 6, 4, 245, 174, 6, 4, + 251, 71, 6, 4, 245, 172, 6, 4, 241, 158, 6, 4, 245, 171, 6, 4, 241, 157, + 6, 4, 245, 169, 6, 4, 245, 170, 6, 4, 251, 70, 6, 4, 245, 168, 6, 4, 241, + 160, 6, 4, 245, 178, 6, 4, 241, 159, 6, 4, 245, 176, 6, 4, 245, 177, 6, + 4, 249, 82, 6, 4, 245, 175, 6, 4, 245, 181, 6, 4, 245, 182, 6, 4, 251, + 72, 6, 4, 245, 179, 6, 4, 241, 161, 6, 4, 245, 180, 6, 4, 245, 185, 6, 4, + 251, 73, 6, 4, 245, 183, 6, 4, 241, 162, 6, 4, 245, 184, 6, 4, 251, 237, + 6, 4, 251, 238, 6, 4, 253, 180, 6, 4, 251, 236, 6, 4, 246, 83, 6, 4, 251, + 231, 6, 4, 246, 82, 6, 4, 251, 220, 6, 4, 251, 221, 6, 4, 222, 6, 4, 251, + 218, 6, 4, 246, 97, 6, 4, 246, 98, 6, 4, 251, 243, 6, 4, 246, 96, 6, 4, + 251, 241, 6, 4, 251, 242, 6, 4, 253, 181, 6, 4, 249, 114, 6, 4, 251, 226, + 6, 4, 253, 206, 6, 4, 251, 246, 6, 4, 251, 247, 6, 4, 253, 154, 6, 4, + 251, 244, 6, 4, 246, 100, 6, 4, 251, 245, 6, 4, 251, 250, 6, 4, 251, 251, + 6, 4, 254, 209, 6, 4, 251, 249, 6, 4, 250, 247, 6, 4, 250, 248, 6, 4, + 253, 245, 6, 4, 250, 246, 6, 4, 250, 235, 6, 4, 250, 236, 6, 4, 253, 179, + 6, 4, 250, 234, 6, 4, 250, 251, 6, 4, 254, 63, 6, 4, 250, 250, 6, 4, 250, + 253, 6, 4, 250, 254, 6, 4, 254, 93, 6, 4, 250, 252, 6, 4, 245, 93, 6, 4, + 249, 64, 6, 4, 251, 3, 6, 4, 251, 4, 6, 4, 254, 165, 6, 4, 251, 2, 6, 4, + 253, 14, 6, 4, 253, 15, 6, 4, 254, 48, 6, 4, 253, 13, 6, 4, 247, 187, 6, + 4, 247, 188, 6, 4, 253, 12, 6, 4, 247, 186, 6, 4, 253, 8, 6, 4, 253, 9, + 6, 4, 253, 171, 6, 4, 253, 7, 6, 4, 253, 18, 6, 4, 253, 20, 6, 4, 254, + 13, 6, 4, 253, 17, 6, 4, 253, 11, 6, 4, 249, 193, 6, 4, 253, 22, 6, 4, + 253, 23, 6, 4, 254, 49, 6, 4, 253, 21, 6, 4, 247, 189, 6, 4, 249, 197, 6, + 4, 253, 27, 6, 4, 253, 28, 6, 4, 255, 1, 6, 4, 253, 25, 6, 4, 247, 190, + 6, 4, 253, 26, 6, 4, 250, 196, 6, 4, 250, 197, 6, 4, 253, 201, 6, 4, 250, + 195, 6, 4, 245, 66, 6, 4, 250, 194, 6, 4, 245, 65, 6, 4, 250, 184, 6, 4, + 250, 187, 6, 4, 253, 133, 6, 4, 250, 182, 6, 4, 245, 75, 6, 4, 250, 209, + 6, 4, 248, 40, 6, 4, 250, 205, 6, 4, 253, 225, 6, 4, 250, 204, 6, 4, 250, + 191, 6, 4, 253, 200, 6, 4, 250, 190, 6, 4, 250, 212, 6, 4, 250, 213, 6, + 4, 253, 232, 6, 4, 250, 210, 6, 4, 245, 76, 6, 4, 250, 211, 6, 4, 252, + 223, 6, 4, 252, 224, 6, 4, 253, 212, 6, 4, 252, 222, 6, 4, 247, 149, 6, + 4, 248, 139, 6, 4, 247, 148, 6, 4, 249, 174, 6, 4, 252, 212, 6, 4, 253, + 126, 6, 4, 252, 209, 6, 4, 247, 174, 6, 4, 247, 175, 6, 4, 252, 233, 6, + 4, 247, 173, 6, 4, 249, 184, 6, 4, 252, 228, 6, 4, 87, 6, 4, 249, 3, 6, + 4, 252, 217, 6, 4, 253, 195, 6, 4, 252, 214, 6, 4, 252, 236, 6, 4, 252, + 237, 6, 4, 253, 196, 6, 4, 252, 234, 6, 4, 247, 176, 6, 4, 252, 235, 6, + 4, 245, 47, 6, 4, 245, 48, 6, 4, 249, 51, 6, 4, 245, 46, 6, 4, 241, 77, + 6, 4, 245, 45, 6, 4, 241, 76, 6, 4, 245, 39, 6, 4, 245, 40, 6, 4, 248, + 75, 6, 4, 245, 38, 6, 4, 241, 79, 6, 4, 245, 53, 6, 4, 241, 78, 6, 4, + 245, 51, 6, 4, 245, 52, 6, 4, 248, 204, 6, 4, 245, 50, 6, 4, 245, 43, 6, + 4, 249, 50, 6, 4, 245, 42, 6, 4, 245, 55, 6, 4, 245, 56, 6, 4, 249, 52, + 6, 4, 245, 54, 6, 4, 241, 80, 6, 4, 243, 163, 6, 4, 246, 130, 6, 4, 246, + 131, 6, 4, 252, 9, 6, 4, 246, 129, 6, 4, 242, 3, 6, 4, 246, 128, 6, 4, + 246, 124, 6, 4, 246, 125, 6, 4, 252, 7, 6, 4, 246, 123, 6, 4, 246, 133, + 6, 4, 246, 134, 6, 4, 252, 10, 6, 4, 246, 132, 6, 4, 246, 127, 6, 4, 252, + 8, 6, 4, 246, 126, 6, 4, 246, 137, 6, 4, 246, 138, 6, 4, 252, 11, 6, 4, + 246, 135, 6, 4, 242, 4, 6, 4, 246, 136, 6, 4, 245, 193, 6, 4, 245, 194, + 6, 4, 251, 75, 6, 4, 245, 192, 6, 4, 241, 164, 6, 4, 241, 165, 6, 4, 245, + 191, 6, 4, 241, 163, 6, 4, 245, 187, 6, 4, 245, 188, 6, 4, 249, 83, 6, 4, + 245, 186, 6, 4, 241, 166, 6, 4, 245, 198, 6, 4, 245, 196, 6, 4, 245, 197, + 6, 4, 245, 195, 6, 4, 245, 190, 6, 4, 251, 74, 6, 4, 245, 189, 6, 4, 245, + 199, 6, 4, 252, 24, 6, 4, 252, 25, 6, 4, 253, 166, 6, 4, 252, 23, 6, 4, + 246, 155, 6, 4, 252, 21, 6, 4, 246, 154, 6, 4, 252, 1, 6, 4, 253, 131, 6, + 4, 251, 255, 6, 4, 246, 195, 6, 4, 252, 41, 6, 4, 246, 194, 6, 4, 248, + 233, 6, 4, 252, 35, 6, 4, 253, 173, 6, 4, 252, 33, 6, 4, 252, 15, 6, 4, + 253, 197, 6, 4, 252, 13, 6, 4, 252, 44, 6, 4, 252, 45, 6, 4, 253, 150, 6, + 4, 252, 42, 6, 4, 246, 196, 6, 4, 252, 43, 6, 4, 245, 155, 6, 4, 245, + 156, 6, 4, 251, 66, 6, 4, 245, 154, 6, 4, 241, 152, 6, 4, 245, 153, 6, 4, + 241, 151, 6, 4, 245, 149, 6, 4, 245, 150, 6, 4, 251, 64, 6, 4, 245, 148, + 6, 4, 241, 154, 6, 4, 245, 159, 6, 4, 241, 153, 6, 4, 245, 158, 6, 4, + 251, 67, 6, 4, 245, 157, 6, 4, 245, 152, 6, 4, 251, 65, 6, 4, 245, 151, + 6, 4, 245, 162, 6, 4, 245, 163, 6, 4, 251, 68, 6, 4, 245, 160, 6, 4, 241, + 155, 6, 4, 245, 161, 6, 4, 245, 166, 6, 4, 245, 167, 6, 4, 251, 69, 6, 4, + 245, 164, 6, 4, 241, 156, 6, 4, 245, 165, 6, 4, 251, 200, 6, 4, 251, 201, + 6, 4, 253, 251, 6, 4, 251, 198, 6, 4, 246, 49, 6, 4, 246, 50, 6, 4, 249, + 105, 6, 4, 246, 48, 6, 4, 251, 185, 6, 4, 251, 186, 6, 4, 253, 134, 6, 4, + 251, 183, 6, 4, 246, 57, 6, 4, 246, 58, 6, 4, 251, 209, 6, 4, 246, 56, 6, + 4, 251, 206, 6, 4, 251, 208, 6, 4, 253, 216, 6, 4, 251, 205, 6, 4, 251, + 191, 6, 4, 253, 250, 6, 4, 251, 189, 6, 4, 251, 212, 6, 4, 251, 213, 6, + 4, 254, 8, 6, 4, 251, 210, 6, 4, 246, 59, 6, 4, 251, 211, 6, 4, 251, 215, + 6, 4, 251, 216, 6, 4, 254, 110, 6, 4, 251, 214, 6, 4, 246, 60, 6, 4, 249, + 109, 6, 4, 251, 23, 6, 4, 251, 24, 6, 4, 254, 6, 6, 4, 251, 22, 6, 4, + 245, 122, 6, 4, 245, 123, 6, 4, 251, 21, 6, 4, 245, 121, 6, 4, 251, 10, + 6, 4, 251, 11, 6, 4, 253, 139, 6, 4, 251, 8, 6, 4, 245, 131, 6, 4, 245, + 132, 6, 4, 251, 31, 6, 4, 245, 130, 6, 4, 249, 78, 6, 4, 251, 27, 6, 4, + 253, 234, 6, 4, 251, 26, 6, 4, 251, 15, 6, 4, 251, 17, 6, 4, 254, 5, 6, + 4, 249, 69, 6, 4, 251, 34, 6, 4, 251, 35, 6, 4, 253, 235, 6, 4, 251, 32, + 6, 4, 245, 133, 6, 4, 251, 33, 6, 4, 249, 95, 6, 4, 251, 152, 6, 4, 253, + 215, 6, 4, 251, 151, 6, 4, 246, 15, 6, 4, 251, 148, 6, 4, 246, 14, 6, 4, + 251, 138, 6, 4, 251, 140, 6, 4, 201, 6, 4, 251, 137, 6, 4, 246, 21, 6, 4, + 251, 165, 6, 4, 246, 20, 6, 4, 251, 161, 6, 4, 251, 162, 6, 4, 253, 190, + 6, 4, 251, 160, 6, 4, 251, 143, 6, 4, 251, 144, 6, 4, 253, 172, 6, 4, + 251, 142, 6, 4, 251, 168, 6, 4, 251, 169, 6, 4, 253, 203, 6, 4, 251, 166, + 6, 4, 246, 23, 6, 4, 251, 167, 6, 4, 245, 108, 6, 4, 245, 109, 6, 4, 249, + 72, 6, 4, 241, 129, 6, 4, 245, 107, 6, 4, 241, 128, 6, 4, 245, 101, 6, 4, + 245, 102, 6, 4, 249, 70, 6, 4, 245, 100, 6, 4, 241, 131, 6, 4, 241, 132, + 6, 4, 243, 181, 6, 4, 241, 130, 6, 4, 245, 110, 6, 4, 245, 111, 6, 4, + 249, 73, 6, 4, 243, 180, 6, 4, 245, 105, 6, 4, 245, 106, 6, 4, 249, 71, + 6, 4, 245, 104, 6, 4, 245, 114, 6, 4, 245, 115, 6, 4, 249, 74, 6, 4, 245, + 112, 6, 4, 241, 133, 6, 4, 245, 113, 6, 4, 241, 238, 6, 4, 246, 72, 6, 4, + 246, 68, 6, 4, 246, 69, 6, 4, 251, 227, 6, 4, 246, 67, 6, 4, 241, 240, 6, + 4, 246, 76, 6, 4, 241, 239, 6, 4, 246, 74, 6, 4, 246, 75, 6, 4, 248, 167, + 6, 4, 246, 73, 6, 4, 246, 71, 6, 4, 251, 228, 6, 4, 246, 70, 6, 4, 246, + 79, 6, 4, 246, 80, 6, 4, 251, 229, 6, 4, 246, 77, 6, 4, 241, 241, 6, 4, + 246, 78, 6, 4, 243, 196, 6, 4, 245, 216, 6, 4, 251, 91, 6, 4, 245, 215, + 6, 4, 241, 172, 6, 4, 241, 173, 6, 4, 245, 214, 6, 4, 241, 171, 6, 4, + 245, 210, 6, 4, 245, 211, 6, 4, 251, 89, 6, 4, 245, 209, 6, 4, 241, 175, + 6, 4, 241, 176, 6, 4, 243, 198, 6, 4, 241, 174, 6, 4, 245, 217, 6, 4, + 245, 218, 6, 4, 251, 92, 6, 4, 243, 197, 6, 4, 245, 213, 6, 4, 251, 90, + 6, 4, 245, 212, 6, 4, 242, 7, 6, 4, 246, 146, 6, 4, 242, 6, 6, 4, 246, + 142, 6, 4, 246, 143, 6, 4, 248, 50, 6, 4, 246, 141, 6, 4, 242, 9, 6, 4, + 242, 10, 6, 4, 246, 153, 6, 4, 246, 151, 6, 4, 246, 152, 6, 4, 248, 172, + 6, 4, 246, 150, 6, 4, 246, 145, 6, 4, 252, 17, 6, 4, 246, 144, 6, 4, 251, + 63, 6, 4, 245, 145, 6, 4, 248, 160, 6, 4, 248, 214, 6, 4, 251, 48, 6, 4, + 219, 6, 4, 251, 47, 6, 4, 245, 206, 6, 4, 245, 207, 6, 4, 251, 83, 6, 4, + 245, 205, 6, 4, 251, 80, 6, 4, 251, 81, 6, 4, 253, 184, 6, 4, 251, 79, 6, + 4, 251, 55, 6, 4, 253, 168, 6, 4, 251, 53, 6, 4, 253, 30, 6, 4, 253, 31, + 6, 4, 253, 138, 6, 4, 253, 29, 6, 4, 247, 200, 6, 4, 253, 39, 6, 4, 247, + 199, 6, 4, 253, 38, 6, 4, 253, 177, 6, 4, 253, 36, 6, 4, 253, 33, 6, 4, + 253, 170, 6, 4, 253, 32, 6, 4, 253, 106, 6, 4, 253, 107, 6, 4, 254, 17, + 6, 4, 253, 105, 6, 4, 248, 10, 6, 4, 253, 104, 6, 4, 248, 9, 6, 4, 253, + 99, 6, 4, 253, 100, 6, 4, 253, 163, 6, 4, 253, 98, 6, 4, 248, 12, 6, 4, + 253, 114, 6, 4, 248, 11, 6, 4, 249, 221, 6, 4, 253, 112, 6, 4, 253, 222, + 6, 4, 253, 111, 6, 4, 253, 102, 6, 4, 253, 228, 6, 4, 253, 101, 6, 4, + 253, 115, 6, 4, 253, 116, 6, 4, 254, 18, 6, 4, 249, 222, 6, 4, 248, 13, + 6, 4, 249, 223, 6, 4, 253, 120, 6, 4, 253, 121, 6, 4, 255, 13, 6, 4, 253, + 118, 6, 4, 248, 14, 6, 4, 253, 119, 6, 4, 250, 163, 6, 4, 250, 164, 6, 4, + 254, 55, 6, 4, 249, 40, 6, 4, 245, 19, 6, 4, 245, 20, 6, 4, 250, 161, 6, + 4, 245, 18, 6, 4, 250, 146, 6, 4, 250, 147, 6, 4, 253, 152, 6, 4, 249, + 38, 6, 4, 245, 28, 6, 4, 250, 170, 6, 4, 243, 157, 6, 4, 250, 167, 6, 4, + 250, 168, 6, 4, 253, 224, 6, 4, 250, 166, 6, 4, 250, 157, 6, 4, 254, 54, + 6, 4, 250, 156, 6, 4, 250, 172, 6, 4, 250, 173, 6, 4, 254, 84, 6, 4, 249, + 43, 6, 4, 245, 29, 6, 4, 250, 171, 6, 4, 249, 48, 6, 4, 250, 176, 6, 4, + 254, 85, 6, 4, 249, 47, 6, 4, 245, 30, 6, 4, 250, 175, 6, 4, 248, 24, 6, + 4, 248, 25, 6, 4, 249, 226, 6, 4, 248, 23, 6, 4, 241, 1, 6, 4, 242, 211, + 6, 4, 248, 22, 6, 4, 242, 210, 6, 4, 248, 17, 6, 4, 248, 18, 6, 4, 249, + 224, 6, 4, 248, 16, 6, 4, 248, 27, 6, 4, 249, 227, 6, 4, 248, 26, 6, 4, + 248, 21, 6, 4, 249, 225, 6, 4, 248, 20, 6, 4, 248, 30, 6, 4, 249, 228, 6, + 4, 248, 28, 6, 4, 242, 212, 6, 4, 248, 29, 6, 4, 248, 33, 6, 4, 248, 34, + 6, 4, 253, 122, 6, 4, 248, 31, 6, 4, 242, 213, 6, 4, 248, 32, 6, 4, 246, + 219, 6, 4, 246, 220, 6, 4, 252, 49, 6, 4, 246, 218, 6, 4, 242, 34, 6, 4, + 246, 217, 6, 4, 242, 33, 6, 4, 246, 214, 6, 4, 246, 215, 6, 4, 252, 47, + 6, 4, 246, 213, 6, 4, 242, 35, 6, 4, 246, 223, 6, 4, 246, 222, 6, 4, 246, + 221, 6, 4, 246, 216, 6, 4, 252, 48, 6, 4, 246, 225, 6, 4, 252, 50, 6, 4, + 243, 239, 6, 4, 242, 36, 6, 4, 246, 224, 6, 4, 246, 228, 6, 4, 246, 229, + 6, 4, 252, 51, 6, 4, 246, 226, 6, 4, 242, 37, 6, 4, 246, 227, 6, 4, 252, + 180, 6, 4, 187, 6, 4, 253, 198, 6, 4, 252, 179, 6, 4, 247, 88, 6, 4, 252, + 176, 6, 4, 247, 87, 6, 4, 252, 167, 6, 4, 252, 168, 6, 4, 253, 132, 6, 4, + 252, 166, 6, 4, 247, 126, 6, 4, 252, 193, 6, 4, 247, 125, 6, 4, 252, 186, + 6, 4, 252, 188, 6, 4, 253, 186, 6, 4, 252, 185, 6, 4, 252, 172, 6, 4, + 253, 210, 6, 4, 252, 171, 6, 4, 252, 196, 6, 4, 252, 197, 6, 4, 253, 211, + 6, 4, 252, 194, 6, 4, 247, 128, 6, 4, 252, 195, 6, 4, 252, 200, 6, 4, + 252, 201, 6, 4, 254, 243, 6, 4, 252, 198, 6, 4, 247, 130, 6, 4, 252, 199, + 6, 4, 247, 108, 6, 4, 247, 109, 6, 4, 248, 249, 6, 4, 247, 107, 6, 4, + 242, 129, 6, 4, 247, 106, 6, 4, 242, 128, 6, 4, 247, 101, 6, 4, 247, 102, + 6, 4, 248, 66, 6, 4, 247, 100, 6, 4, 247, 111, 6, 4, 247, 112, 6, 4, 248, + 250, 6, 4, 247, 110, 6, 4, 247, 105, 6, 4, 249, 168, 6, 4, 247, 104, 6, + 4, 247, 114, 6, 4, 247, 115, 6, 4, 248, 251, 6, 4, 247, 113, 6, 4, 247, + 118, 6, 4, 247, 119, 6, 4, 252, 189, 6, 4, 247, 116, 6, 4, 242, 130, 6, + 4, 247, 117, 6, 4, 247, 247, 6, 4, 247, 248, 6, 4, 248, 99, 6, 4, 247, + 246, 6, 4, 242, 204, 6, 4, 247, 255, 6, 4, 242, 203, 6, 4, 247, 253, 6, + 4, 247, 254, 6, 4, 249, 218, 6, 4, 247, 252, 6, 4, 247, 250, 6, 4, 247, + 251, 6, 4, 248, 123, 6, 4, 247, 249, 6, 4, 248, 2, 6, 4, 248, 3, 6, 4, + 249, 219, 6, 4, 248, 0, 6, 4, 242, 205, 6, 4, 248, 1, 6, 4, 248, 7, 6, 4, + 248, 8, 6, 4, 253, 103, 6, 4, 248, 5, 6, 4, 242, 206, 6, 4, 248, 6, 6, 4, + 244, 255, 6, 4, 245, 0, 6, 4, 248, 57, 6, 4, 244, 254, 6, 4, 241, 57, 6, + 4, 241, 58, 6, 4, 245, 9, 6, 4, 241, 56, 6, 4, 245, 7, 6, 4, 245, 8, 6, + 4, 248, 125, 6, 4, 245, 6, 6, 4, 245, 2, 6, 4, 245, 3, 6, 4, 248, 88, 6, + 4, 245, 1, 6, 4, 245, 12, 6, 4, 248, 200, 6, 4, 245, 10, 6, 4, 241, 59, + 6, 4, 245, 11, 6, 4, 245, 16, 6, 4, 245, 17, 6, 4, 250, 160, 6, 4, 245, + 14, 6, 4, 241, 60, 6, 4, 245, 15, 6, 4, 247, 35, 6, 4, 248, 96, 6, 4, + 242, 87, 6, 4, 247, 43, 6, 4, 247, 41, 6, 4, 247, 42, 6, 4, 249, 157, 6, + 4, 247, 40, 6, 4, 247, 38, 6, 4, 247, 39, 6, 4, 252, 147, 6, 4, 247, 37, + 6, 4, 247, 46, 6, 4, 247, 47, 6, 4, 252, 148, 6, 4, 247, 44, 6, 4, 242, + 88, 6, 4, 247, 45, 6, 4, 247, 50, 6, 4, 247, 51, 6, 4, 252, 149, 6, 4, + 247, 48, 6, 4, 242, 89, 6, 4, 247, 49, 6, 4, 246, 178, 6, 4, 246, 179, 6, + 4, 249, 123, 6, 4, 246, 177, 6, 4, 246, 184, 6, 4, 252, 37, 6, 4, 246, + 183, 6, 4, 246, 181, 6, 4, 246, 182, 6, 4, 252, 36, 6, 4, 246, 180, 6, 4, + 246, 187, 6, 4, 246, 188, 6, 4, 252, 38, 6, 4, 246, 185, 6, 4, 242, 25, + 6, 4, 246, 186, 6, 4, 246, 191, 6, 4, 246, 192, 6, 4, 252, 39, 6, 4, 246, + 189, 6, 4, 242, 26, 6, 4, 246, 190, 6, 4, 244, 8, 6, 4, 247, 69, 6, 4, + 248, 46, 6, 4, 247, 68, 6, 4, 242, 110, 6, 4, 247, 79, 6, 4, 242, 109, 6, + 4, 247, 77, 6, 4, 247, 78, 6, 4, 248, 110, 6, 4, 244, 13, 6, 4, 247, 71, + 6, 4, 247, 72, 6, 4, 248, 118, 6, 4, 247, 70, 6, 4, 247, 81, 6, 4, 247, + 82, 6, 4, 248, 248, 6, 4, 247, 80, 6, 4, 242, 111, 6, 4, 244, 15, 6, 4, + 247, 85, 6, 4, 247, 86, 6, 4, 249, 163, 6, 4, 247, 83, 6, 4, 242, 112, 6, + 4, 247, 84, 6, 4, 249, 152, 6, 4, 252, 130, 6, 4, 253, 130, 6, 4, 248, + 244, 6, 4, 247, 55, 6, 4, 252, 152, 6, 4, 247, 54, 6, 4, 252, 145, 6, 4, + 252, 146, 6, 4, 253, 160, 6, 4, 252, 144, 6, 4, 252, 135, 6, 4, 253, 194, + 6, 4, 252, 133, 6, 4, 252, 155, 6, 4, 252, 156, 6, 4, 253, 185, 6, 4, + 252, 153, 6, 4, 247, 56, 6, 4, 252, 154, 6, 4, 252, 161, 6, 4, 252, 162, + 6, 4, 254, 125, 6, 4, 252, 159, 6, 4, 247, 58, 6, 4, 252, 160, 6, 4, 251, + 118, 6, 4, 251, 119, 6, 4, 254, 7, 6, 4, 251, 117, 6, 4, 245, 236, 6, 4, + 245, 237, 6, 4, 251, 116, 6, 4, 245, 235, 6, 4, 245, 255, 6, 4, 246, 0, + 6, 4, 251, 126, 6, 4, 245, 254, 6, 4, 248, 115, 6, 4, 251, 124, 6, 4, + 253, 248, 6, 4, 251, 123, 6, 4, 251, 129, 6, 4, 251, 130, 6, 4, 254, 25, + 6, 4, 251, 127, 6, 4, 246, 1, 6, 4, 251, 128, 6, 4, 251, 134, 6, 4, 251, + 135, 6, 4, 254, 181, 6, 4, 251, 132, 6, 4, 246, 2, 6, 4, 251, 133, 6, 4, + 252, 96, 6, 4, 252, 97, 6, 4, 254, 28, 6, 4, 252, 95, 6, 4, 247, 13, 6, + 4, 247, 14, 6, 4, 252, 94, 6, 4, 247, 12, 6, 4, 247, 17, 6, 4, 247, 18, + 6, 4, 249, 149, 6, 4, 247, 16, 6, 4, 249, 148, 6, 4, 252, 102, 6, 4, 254, + 45, 6, 4, 252, 101, 6, 4, 252, 109, 6, 4, 252, 111, 6, 4, 254, 29, 6, 4, + 252, 107, 6, 4, 247, 19, 6, 4, 252, 108, 6, 4, 252, 121, 6, 4, 252, 123, + 6, 4, 254, 234, 6, 4, 252, 119, 6, 4, 247, 25, 6, 4, 252, 120, 6, 4, 245, + 240, 6, 4, 245, 241, 6, 4, 249, 86, 6, 4, 245, 239, 6, 4, 241, 183, 6, 4, + 241, 184, 6, 4, 243, 202, 6, 4, 241, 182, 6, 4, 241, 186, 6, 4, 245, 245, + 6, 4, 241, 185, 6, 4, 245, 243, 6, 4, 245, 244, 6, 4, 249, 87, 6, 4, 245, + 242, 6, 4, 243, 203, 6, 4, 245, 248, 6, 4, 249, 88, 6, 4, 245, 246, 6, 4, + 241, 187, 6, 4, 245, 247, 6, 4, 245, 250, 6, 4, 245, 251, 6, 4, 249, 89, + 6, 4, 245, 249, 6, 4, 246, 159, 6, 4, 246, 160, 6, 4, 252, 26, 6, 4, 246, + 158, 6, 4, 242, 14, 6, 4, 242, 15, 6, 4, 246, 157, 6, 4, 242, 13, 6, 4, + 242, 16, 6, 4, 246, 164, 6, 4, 246, 162, 6, 4, 246, 163, 6, 4, 252, 27, + 6, 4, 246, 161, 6, 4, 246, 167, 6, 4, 252, 28, 6, 4, 246, 165, 6, 4, 242, + 17, 6, 4, 246, 166, 6, 4, 246, 170, 6, 4, 246, 171, 6, 4, 252, 29, 6, 4, + 246, 168, 6, 4, 242, 18, 6, 4, 246, 169, 6, 4, 246, 203, 6, 4, 246, 204, + 6, 4, 248, 178, 6, 4, 243, 237, 6, 4, 242, 29, 6, 4, 242, 30, 6, 4, 246, + 202, 6, 4, 242, 28, 6, 4, 242, 32, 6, 4, 246, 208, 6, 4, 242, 31, 6, 4, + 246, 206, 6, 4, 246, 207, 6, 4, 248, 133, 6, 4, 243, 238, 6, 4, 246, 210, + 6, 4, 246, 211, 6, 4, 249, 125, 6, 4, 246, 209, 6, 4, 253, 45, 6, 4, 253, + 46, 6, 4, 253, 188, 6, 4, 253, 44, 6, 4, 247, 202, 6, 4, 247, 203, 6, 4, + 253, 43, 6, 4, 247, 201, 6, 4, 247, 205, 6, 4, 253, 52, 6, 4, 253, 50, 6, + 4, 253, 51, 6, 4, 254, 133, 6, 4, 253, 48, 6, 4, 253, 62, 6, 4, 253, 64, + 6, 4, 255, 7, 6, 4, 253, 60, 6, 4, 247, 210, 6, 4, 253, 61, 6, 4, 249, + 209, 6, 4, 253, 83, 6, 4, 253, 189, 6, 4, 253, 82, 6, 4, 247, 228, 6, 4, + 247, 229, 6, 4, 253, 80, 6, 4, 247, 227, 6, 4, 247, 240, 6, 4, 247, 241, + 6, 4, 253, 88, 6, 4, 247, 239, 6, 4, 249, 211, 6, 4, 253, 86, 6, 4, 253, + 162, 6, 4, 253, 85, 6, 4, 253, 91, 6, 4, 253, 92, 6, 4, 253, 161, 6, 4, + 253, 89, 6, 4, 247, 242, 6, 4, 253, 90, 6, 4, 253, 95, 6, 4, 253, 96, 6, + 4, 254, 77, 6, 4, 253, 93, 6, 4, 247, 243, 6, 4, 253, 94, 6, 25, 249, + 148, 6, 25, 253, 251, 6, 25, 249, 95, 6, 25, 243, 237, 6, 25, 249, 47, 6, + 25, 248, 249, 6, 25, 243, 180, 6, 25, 249, 69, 6, 25, 253, 180, 6, 25, + 243, 196, 6, 25, 249, 109, 6, 25, 243, 145, 6, 25, 249, 114, 6, 25, 253, + 162, 6, 25, 249, 142, 6, 25, 243, 198, 6, 25, 249, 174, 6, 25, 253, 139, + 6, 25, 249, 222, 6, 25, 249, 48, 6, 25, 243, 163, 6, 25, 249, 35, 6, 25, + 243, 181, 6, 25, 243, 238, 6, 25, 253, 196, 6, 25, 254, 120, 6, 25, 243, + 203, 6, 25, 249, 221, 6, 25, 249, 144, 6, 25, 249, 82, 6, 25, 249, 209, + 6, 25, 249, 197, 6, 25, 249, 163, 6, 25, 249, 193, 6, 25, 253, 163, 6, + 25, 253, 248, 6, 25, 243, 239, 6, 25, 249, 89, 6, 25, 249, 78, 6, 25, + 243, 202, 6, 25, 253, 177, 6, 25, 253, 232, 6, 25, 244, 15, 6, 25, 249, + 105, 6, 25, 254, 85, 6, 25, 243, 157, 6, 25, 249, 40, 6, 25, 243, 197, 6, + 25, 244, 8, 6, 25, 249, 223, 6, 25, 244, 13, 6, 25, 248, 88, 6, 25, 241, + 1, 6, 25, 243, 232, 6, 25, 253, 172, 49, 1, 238, 85, 188, 254, 15, 243, + 243, 49, 1, 238, 85, 188, 248, 122, 243, 243, 49, 1, 238, 85, 188, 254, + 15, 240, 222, 49, 1, 238, 85, 188, 248, 122, 240, 222, 49, 1, 238, 85, + 188, 254, 15, 254, 29, 49, 1, 238, 85, 188, 248, 122, 254, 29, 49, 1, + 238, 85, 188, 254, 15, 253, 185, 49, 1, 238, 85, 188, 248, 122, 253, 185, + 49, 1, 234, 27, 240, 4, 188, 125, 49, 1, 200, 240, 4, 188, 125, 49, 1, + 254, 40, 240, 4, 188, 125, 49, 1, 170, 240, 4, 188, 125, 49, 1, 235, 87, + 240, 4, 188, 125, 49, 1, 234, 27, 240, 4, 235, 64, 188, 125, 49, 1, 200, + 240, 4, 235, 64, 188, 125, 49, 1, 254, 40, 240, 4, 235, 64, 188, 125, 49, + 1, 170, 240, 4, 235, 64, 188, 125, 49, 1, 235, 87, 240, 4, 235, 64, 188, + 125, 49, 1, 234, 27, 235, 64, 188, 125, 49, 1, 200, 235, 64, 188, 125, + 49, 1, 254, 40, 235, 64, 188, 125, 49, 1, 170, 235, 64, 188, 125, 49, 1, + 235, 87, 235, 64, 188, 125, 239, 253, 242, 214, 1, 67, 239, 253, 242, + 214, 1, 71, 239, 253, 242, 214, 21, 236, 10, 239, 253, 242, 214, 1, 79, + 239, 253, 242, 214, 1, 72, 239, 253, 242, 214, 1, 73, 239, 253, 242, 214, + 21, 237, 170, 239, 253, 242, 214, 1, 253, 190, 239, 253, 242, 214, 1, + 248, 220, 239, 253, 242, 214, 1, 253, 234, 239, 253, 242, 214, 1, 249, + 75, 239, 253, 242, 214, 21, 235, 61, 239, 253, 242, 214, 1, 253, 224, + 239, 253, 242, 214, 1, 248, 125, 239, 253, 242, 214, 1, 253, 248, 239, + 253, 242, 214, 1, 251, 114, 239, 253, 242, 214, 1, 249, 6, 239, 253, 242, + 214, 1, 243, 131, 239, 253, 242, 214, 1, 248, 204, 239, 253, 242, 214, 1, + 245, 44, 239, 253, 242, 214, 1, 87, 239, 253, 242, 214, 1, 248, 97, 239, + 253, 242, 214, 1, 253, 225, 239, 253, 242, 214, 1, 250, 193, 239, 253, + 242, 214, 1, 253, 173, 239, 253, 242, 214, 1, 253, 208, 239, 253, 242, + 214, 1, 248, 238, 239, 253, 242, 214, 1, 254, 1, 239, 253, 242, 214, 1, + 250, 120, 239, 253, 242, 214, 1, 253, 181, 239, 253, 242, 214, 1, 253, + 160, 239, 253, 242, 214, 1, 253, 216, 239, 253, 242, 214, 1, 249, 157, + 239, 253, 242, 214, 1, 253, 186, 239, 253, 242, 214, 1, 253, 184, 239, + 253, 242, 214, 33, 21, 67, 239, 253, 242, 214, 33, 21, 71, 239, 253, 242, + 214, 33, 21, 79, 239, 253, 242, 214, 33, 21, 72, 239, 253, 242, 214, 33, + 21, 253, 156, 239, 253, 242, 214, 240, 120, 238, 200, 239, 253, 242, 214, + 240, 120, 238, 201, 239, 253, 242, 214, 240, 120, 239, 127, 239, 253, + 242, 214, 240, 120, 239, 128, 7, 9, 229, 68, 7, 9, 229, 69, 7, 9, 229, + 70, 7, 9, 229, 71, 7, 9, 229, 72, 7, 9, 229, 73, 7, 9, 229, 74, 7, 9, + 229, 75, 7, 9, 229, 76, 7, 9, 229, 77, 7, 9, 229, 78, 7, 9, 229, 79, 7, + 9, 229, 80, 7, 9, 229, 81, 7, 9, 229, 82, 7, 9, 229, 83, 7, 9, 229, 84, + 7, 9, 229, 85, 7, 9, 229, 86, 7, 9, 229, 87, 7, 9, 229, 88, 7, 9, 229, + 89, 7, 9, 229, 90, 7, 9, 229, 91, 7, 9, 229, 92, 7, 9, 229, 93, 7, 9, + 229, 94, 7, 9, 229, 95, 7, 9, 229, 96, 7, 9, 229, 97, 7, 9, 229, 98, 7, + 9, 229, 99, 7, 9, 229, 100, 7, 9, 229, 101, 7, 9, 229, 102, 7, 9, 229, + 103, 7, 9, 229, 104, 7, 9, 229, 105, 7, 9, 229, 106, 7, 9, 229, 107, 7, + 9, 229, 108, 7, 9, 229, 109, 7, 9, 229, 110, 7, 9, 229, 111, 7, 9, 229, + 112, 7, 9, 229, 113, 7, 9, 229, 114, 7, 9, 229, 115, 7, 9, 229, 116, 7, + 9, 229, 117, 7, 9, 229, 118, 7, 9, 229, 119, 7, 9, 229, 120, 7, 9, 229, + 121, 7, 9, 229, 122, 7, 9, 229, 123, 7, 9, 229, 124, 7, 9, 229, 125, 7, + 9, 229, 126, 7, 9, 229, 127, 7, 9, 229, 128, 7, 9, 229, 129, 7, 9, 229, + 130, 7, 9, 229, 131, 7, 9, 229, 132, 7, 9, 229, 133, 7, 9, 229, 134, 7, + 9, 229, 135, 7, 9, 229, 136, 7, 9, 229, 137, 7, 9, 229, 138, 7, 9, 229, + 139, 7, 9, 229, 140, 7, 9, 229, 141, 7, 9, 229, 142, 7, 9, 229, 143, 7, + 9, 229, 144, 7, 9, 229, 145, 7, 9, 229, 146, 7, 9, 229, 147, 7, 9, 229, + 148, 7, 9, 229, 149, 7, 9, 229, 150, 7, 9, 229, 151, 7, 9, 229, 152, 7, + 9, 229, 153, 7, 9, 229, 154, 7, 9, 229, 155, 7, 9, 229, 156, 7, 9, 229, + 157, 7, 9, 229, 158, 7, 9, 229, 159, 7, 9, 229, 160, 7, 9, 229, 161, 7, + 9, 229, 162, 7, 9, 229, 163, 7, 9, 229, 164, 7, 9, 229, 165, 7, 9, 229, + 166, 7, 9, 229, 167, 7, 9, 229, 168, 7, 9, 229, 169, 7, 9, 229, 170, 7, + 9, 229, 171, 7, 9, 229, 172, 7, 9, 229, 173, 7, 9, 229, 174, 7, 9, 229, + 175, 7, 9, 229, 176, 7, 9, 229, 177, 7, 9, 229, 178, 7, 9, 229, 179, 7, + 9, 229, 180, 7, 9, 229, 181, 7, 9, 229, 182, 7, 9, 229, 183, 7, 9, 229, + 184, 7, 9, 229, 185, 7, 9, 229, 186, 7, 9, 229, 187, 7, 9, 229, 188, 7, + 9, 229, 189, 7, 9, 229, 190, 7, 9, 229, 191, 7, 9, 229, 192, 7, 9, 229, + 193, 7, 9, 229, 194, 7, 9, 229, 195, 7, 9, 229, 196, 7, 9, 229, 197, 7, + 9, 229, 198, 7, 9, 229, 199, 7, 9, 229, 200, 7, 9, 229, 201, 7, 9, 229, + 202, 7, 9, 229, 203, 7, 9, 229, 204, 7, 9, 229, 205, 7, 9, 229, 206, 7, + 9, 229, 207, 7, 9, 229, 208, 7, 9, 229, 209, 7, 9, 229, 210, 7, 9, 229, + 211, 7, 9, 229, 212, 7, 9, 229, 213, 7, 9, 229, 214, 7, 9, 229, 215, 7, + 9, 229, 216, 7, 9, 229, 217, 7, 9, 229, 218, 7, 9, 229, 219, 7, 9, 229, + 220, 7, 9, 229, 221, 7, 9, 229, 222, 7, 9, 229, 223, 7, 9, 229, 224, 7, + 9, 229, 225, 7, 9, 229, 226, 7, 9, 229, 227, 7, 9, 229, 228, 7, 9, 229, + 229, 7, 9, 229, 230, 7, 9, 229, 231, 7, 9, 229, 232, 7, 9, 229, 233, 7, + 9, 229, 234, 7, 9, 229, 235, 7, 9, 229, 236, 7, 9, 229, 237, 7, 9, 229, + 238, 7, 9, 229, 239, 7, 9, 229, 240, 7, 9, 229, 241, 7, 9, 229, 242, 7, + 9, 229, 243, 7, 9, 229, 244, 7, 9, 229, 245, 7, 9, 229, 246, 7, 9, 229, + 247, 7, 9, 229, 248, 7, 9, 229, 249, 7, 9, 229, 250, 7, 9, 229, 251, 7, + 9, 229, 252, 7, 9, 229, 253, 7, 9, 229, 254, 7, 9, 229, 255, 7, 9, 230, + 0, 7, 9, 230, 1, 7, 9, 230, 2, 7, 9, 230, 3, 7, 9, 230, 4, 7, 9, 230, 5, + 7, 9, 230, 6, 7, 9, 230, 7, 7, 9, 230, 8, 7, 9, 230, 9, 7, 9, 230, 10, 7, + 9, 230, 11, 7, 9, 230, 12, 7, 9, 230, 13, 7, 9, 230, 14, 7, 9, 230, 15, + 7, 9, 230, 16, 7, 9, 230, 17, 7, 9, 230, 18, 7, 9, 230, 19, 7, 9, 230, + 20, 7, 9, 230, 21, 7, 9, 230, 22, 7, 9, 230, 23, 7, 9, 230, 24, 7, 9, + 230, 25, 7, 9, 230, 26, 7, 9, 230, 27, 7, 9, 230, 28, 7, 9, 230, 29, 7, + 9, 230, 30, 7, 9, 230, 31, 7, 9, 230, 32, 7, 9, 230, 33, 7, 9, 230, 34, + 7, 9, 230, 35, 7, 9, 230, 36, 7, 9, 230, 37, 7, 9, 230, 38, 7, 9, 230, + 39, 7, 9, 230, 40, 7, 9, 230, 41, 7, 9, 230, 42, 7, 9, 230, 43, 7, 9, + 230, 44, 7, 9, 230, 45, 7, 9, 230, 46, 7, 9, 230, 47, 7, 9, 230, 48, 7, + 9, 230, 49, 7, 9, 230, 50, 7, 9, 230, 51, 7, 9, 230, 52, 7, 9, 230, 53, + 7, 9, 230, 54, 7, 9, 230, 55, 7, 9, 230, 56, 7, 9, 230, 57, 7, 9, 230, + 58, 7, 9, 230, 59, 7, 9, 230, 60, 7, 9, 230, 61, 7, 9, 230, 62, 7, 9, + 230, 63, 7, 9, 230, 64, 7, 9, 230, 65, 7, 9, 230, 66, 7, 9, 230, 67, 7, + 9, 230, 68, 7, 9, 230, 69, 7, 9, 230, 70, 7, 9, 230, 71, 7, 9, 230, 72, + 7, 9, 230, 73, 7, 9, 230, 74, 7, 9, 230, 75, 7, 9, 230, 76, 7, 9, 230, + 77, 7, 9, 230, 78, 7, 9, 230, 79, 7, 9, 230, 80, 7, 9, 230, 81, 7, 9, + 230, 82, 7, 9, 230, 83, 7, 9, 230, 84, 7, 9, 230, 85, 7, 9, 230, 86, 7, + 9, 230, 87, 7, 9, 230, 88, 7, 9, 230, 89, 7, 9, 230, 90, 7, 9, 230, 91, + 7, 9, 230, 92, 7, 9, 230, 93, 7, 9, 230, 94, 7, 9, 230, 95, 7, 9, 230, + 96, 7, 9, 230, 97, 7, 9, 230, 98, 7, 9, 230, 99, 7, 9, 230, 100, 7, 9, + 230, 101, 7, 9, 230, 102, 7, 9, 230, 103, 7, 9, 230, 104, 7, 9, 230, 105, + 7, 9, 230, 106, 7, 9, 230, 107, 7, 9, 230, 108, 7, 9, 230, 109, 7, 9, + 230, 110, 7, 9, 230, 111, 7, 9, 230, 112, 7, 9, 230, 113, 7, 9, 230, 114, + 7, 9, 230, 115, 7, 9, 230, 116, 7, 9, 230, 117, 7, 9, 230, 118, 7, 9, + 230, 119, 7, 9, 230, 120, 7, 9, 230, 121, 7, 9, 230, 122, 7, 9, 230, 123, + 7, 9, 230, 124, 7, 9, 230, 125, 7, 9, 230, 126, 7, 9, 230, 127, 7, 9, + 230, 128, 7, 9, 230, 129, 7, 9, 230, 130, 7, 9, 230, 131, 7, 9, 230, 132, + 7, 9, 230, 133, 7, 9, 230, 134, 7, 9, 230, 135, 7, 9, 230, 136, 7, 9, + 230, 137, 7, 9, 230, 138, 7, 9, 230, 139, 7, 9, 230, 140, 7, 9, 230, 141, + 7, 9, 230, 142, 7, 9, 230, 143, 7, 9, 230, 144, 7, 9, 230, 145, 7, 9, + 230, 146, 7, 9, 230, 147, 7, 9, 230, 148, 7, 9, 230, 149, 7, 9, 230, 150, + 7, 9, 230, 151, 7, 9, 230, 152, 7, 9, 230, 153, 7, 9, 230, 154, 7, 9, + 230, 155, 7, 9, 230, 156, 7, 9, 230, 157, 7, 9, 230, 158, 7, 9, 230, 159, + 7, 9, 230, 160, 7, 9, 230, 161, 7, 9, 230, 162, 7, 9, 230, 163, 7, 9, + 230, 164, 7, 9, 230, 165, 7, 9, 230, 166, 7, 9, 230, 167, 7, 9, 230, 168, + 7, 9, 230, 169, 7, 9, 230, 170, 7, 9, 230, 171, 7, 9, 230, 172, 7, 9, + 230, 173, 7, 9, 230, 174, 7, 9, 230, 175, 7, 9, 230, 176, 7, 9, 230, 177, + 7, 9, 230, 178, 7, 9, 230, 179, 7, 9, 230, 180, 7, 9, 230, 181, 7, 9, + 230, 182, 7, 9, 230, 183, 7, 9, 230, 184, 7, 9, 230, 185, 7, 9, 230, 186, + 7, 9, 230, 187, 7, 9, 230, 188, 7, 9, 230, 189, 7, 9, 230, 190, 7, 9, + 230, 191, 7, 9, 230, 192, 7, 9, 230, 193, 7, 9, 230, 194, 7, 9, 230, 195, + 7, 9, 230, 196, 7, 9, 230, 197, 7, 9, 230, 198, 7, 9, 230, 199, 7, 9, + 230, 200, 7, 9, 230, 201, 7, 9, 230, 202, 7, 9, 230, 203, 7, 9, 230, 204, + 7, 9, 230, 205, 7, 9, 230, 206, 7, 9, 230, 207, 7, 9, 230, 208, 7, 9, + 230, 209, 7, 9, 230, 210, 7, 9, 230, 211, 7, 9, 230, 212, 7, 9, 230, 213, + 7, 9, 230, 214, 7, 9, 230, 215, 7, 9, 230, 216, 7, 9, 230, 217, 7, 9, + 230, 218, 7, 9, 230, 219, 7, 9, 230, 220, 7, 9, 230, 221, 7, 9, 230, 222, + 7, 9, 230, 223, 7, 9, 230, 224, 7, 9, 230, 225, 7, 9, 230, 226, 7, 9, + 230, 227, 7, 9, 230, 228, 7, 9, 230, 229, 7, 9, 230, 230, 7, 9, 230, 231, + 7, 9, 230, 232, 7, 9, 230, 233, 7, 9, 230, 234, 7, 9, 230, 235, 7, 9, + 230, 236, 7, 9, 230, 237, 7, 9, 230, 238, 7, 9, 230, 239, 7, 9, 230, 240, + 7, 9, 230, 241, 7, 9, 230, 242, 7, 9, 230, 243, 7, 9, 230, 244, 7, 9, + 230, 245, 7, 9, 230, 246, 7, 9, 230, 247, 7, 9, 230, 248, 7, 9, 230, 249, + 7, 9, 230, 250, 7, 9, 230, 251, 7, 9, 230, 252, 7, 9, 230, 253, 7, 9, + 230, 254, 7, 9, 230, 255, 7, 9, 231, 0, 7, 9, 231, 1, 7, 9, 231, 2, 7, 9, + 231, 3, 7, 9, 231, 4, 7, 9, 231, 5, 7, 9, 231, 6, 7, 9, 231, 7, 7, 9, + 231, 8, 7, 9, 231, 9, 7, 9, 231, 10, 7, 9, 231, 11, 7, 9, 231, 12, 7, 9, + 231, 13, 7, 9, 231, 14, 7, 9, 231, 15, 7, 9, 231, 16, 7, 9, 231, 17, 7, + 9, 231, 18, 7, 9, 231, 19, 7, 9, 231, 20, 7, 9, 231, 21, 7, 9, 231, 22, + 8, 3, 18, 254, 162, 8, 3, 18, 253, 245, 8, 3, 18, 254, 163, 8, 3, 18, + 250, 241, 8, 3, 18, 250, 242, 8, 3, 18, 183, 255, 99, 214, 8, 3, 18, 254, + 242, 100, 3, 18, 254, 39, 248, 175, 100, 3, 18, 254, 39, 248, 208, 100, + 3, 18, 254, 39, 248, 216, 100, 3, 18, 255, 0, 248, 175, 100, 3, 18, 254, + 39, 249, 17, 68, 1, 254, 50, 2, 240, 187, 68, 242, 232, 231, 144, 239, + 241, 68, 18, 238, 126, 254, 50, 254, 50, 240, 118, 68, 1, 233, 68, 243, + 144, 68, 1, 248, 98, 243, 3, 68, 1, 248, 98, 240, 165, 68, 1, 248, 98, + 253, 168, 68, 1, 248, 98, 248, 116, 68, 1, 248, 98, 240, 139, 68, 1, 248, + 98, 30, 248, 166, 68, 1, 248, 98, 243, 253, 68, 1, 248, 98, 249, 175, 68, + 1, 233, 68, 248, 49, 52, 68, 1, 248, 102, 2, 248, 102, 248, 40, 68, 1, + 248, 102, 2, 254, 73, 248, 40, 68, 1, 248, 102, 2, 240, 133, 19, 248, + 102, 248, 40, 68, 1, 248, 102, 2, 240, 133, 19, 254, 73, 248, 40, 68, 1, + 83, 2, 240, 118, 68, 1, 83, 2, 238, 149, 68, 1, 83, 2, 240, 140, 68, 1, + 254, 53, 2, 238, 61, 68, 1, 243, 184, 2, 238, 61, 68, 1, 243, 162, 2, + 238, 61, 68, 1, 255, 76, 2, 240, 140, 68, 1, 254, 76, 2, 238, 61, 68, 1, + 247, 244, 2, 238, 61, 68, 1, 254, 247, 2, 238, 61, 68, 1, 254, 50, 2, + 238, 61, 68, 1, 30, 253, 135, 2, 238, 61, 68, 1, 253, 135, 2, 238, 61, + 68, 1, 246, 38, 2, 238, 61, 68, 1, 254, 201, 2, 238, 61, 68, 1, 254, 114, + 2, 238, 61, 68, 1, 242, 94, 2, 238, 61, 68, 1, 30, 255, 38, 2, 238, 61, + 68, 1, 255, 38, 2, 238, 61, 68, 1, 247, 161, 2, 238, 61, 68, 1, 254, 233, + 2, 238, 61, 68, 1, 252, 134, 2, 238, 61, 68, 1, 248, 102, 2, 238, 61, 68, + 1, 254, 245, 2, 238, 61, 68, 1, 254, 76, 2, 240, 188, 68, 1, 254, 53, 2, + 243, 70, 68, 1, 253, 135, 2, 243, 70, 68, 1, 255, 38, 2, 243, 70, 68, 18, + 83, 240, 139, 11, 1, 83, 244, 49, 39, 13, 11, 1, 83, 244, 49, 30, 13, 11, + 1, 248, 147, 39, 13, 11, 1, 248, 147, 30, 13, 11, 1, 248, 147, 54, 13, + 11, 1, 248, 147, 113, 13, 11, 1, 254, 44, 39, 13, 11, 1, 254, 44, 30, 13, + 11, 1, 254, 44, 54, 13, 11, 1, 254, 44, 113, 13, 11, 1, 243, 52, 39, 13, + 11, 1, 243, 52, 30, 13, 11, 1, 243, 52, 54, 13, 11, 1, 243, 52, 113, 13, + 11, 1, 240, 124, 39, 13, 11, 1, 240, 124, 30, 13, 11, 1, 240, 124, 54, + 13, 11, 1, 240, 124, 113, 13, 11, 1, 243, 75, 39, 13, 11, 1, 243, 75, 30, + 13, 11, 1, 243, 75, 54, 13, 11, 1, 243, 75, 113, 13, 11, 1, 248, 189, 39, + 13, 11, 1, 248, 189, 30, 13, 11, 1, 248, 189, 54, 13, 11, 1, 248, 189, + 113, 13, 11, 1, 254, 47, 39, 13, 11, 1, 254, 47, 30, 13, 11, 1, 254, 47, + 54, 13, 11, 1, 254, 47, 113, 13, 11, 1, 243, 69, 39, 13, 11, 1, 243, 69, + 30, 13, 11, 1, 243, 69, 54, 13, 11, 1, 243, 69, 113, 13, 11, 1, 248, 152, + 39, 13, 11, 1, 248, 152, 30, 13, 11, 1, 248, 152, 54, 13, 11, 1, 248, + 152, 113, 13, 11, 1, 248, 177, 39, 13, 11, 1, 248, 177, 30, 13, 11, 1, + 248, 177, 54, 13, 11, 1, 248, 177, 113, 13, 11, 1, 243, 47, 39, 13, 11, + 1, 243, 47, 30, 13, 11, 1, 243, 47, 54, 13, 11, 1, 243, 47, 113, 13, 11, + 1, 238, 123, 39, 13, 11, 1, 238, 123, 30, 13, 11, 1, 238, 123, 54, 13, + 11, 1, 238, 123, 113, 13, 11, 1, 240, 166, 39, 13, 11, 1, 240, 166, 30, + 13, 11, 1, 243, 161, 39, 13, 11, 1, 243, 161, 30, 13, 11, 1, 254, 87, 39, + 13, 11, 1, 254, 87, 30, 13, 11, 1, 249, 49, 39, 13, 11, 1, 249, 49, 30, + 13, 11, 1, 254, 103, 39, 13, 11, 1, 254, 103, 30, 13, 11, 1, 249, 156, + 39, 13, 11, 1, 249, 156, 30, 13, 11, 1, 243, 21, 39, 13, 11, 1, 243, 21, + 30, 13, 11, 1, 243, 21, 54, 13, 11, 1, 243, 21, 113, 13, 11, 1, 253, 246, + 39, 13, 11, 1, 253, 246, 30, 13, 11, 1, 253, 246, 54, 13, 11, 1, 253, + 246, 113, 13, 11, 1, 248, 159, 39, 13, 11, 1, 248, 159, 30, 13, 11, 1, + 248, 159, 54, 13, 11, 1, 248, 159, 113, 13, 11, 1, 243, 67, 39, 13, 11, + 1, 243, 67, 30, 13, 11, 1, 243, 67, 54, 13, 11, 1, 243, 67, 113, 13, 11, + 1, 198, 240, 182, 39, 13, 11, 1, 198, 240, 182, 30, 13, 11, 1, 243, 71, + 39, 13, 11, 1, 243, 71, 30, 13, 11, 1, 243, 71, 54, 13, 11, 1, 243, 71, + 113, 13, 11, 1, 253, 124, 2, 57, 60, 39, 13, 11, 1, 253, 124, 2, 57, 60, + 30, 13, 11, 1, 253, 124, 248, 128, 39, 13, 11, 1, 253, 124, 248, 128, 30, + 13, 11, 1, 253, 124, 248, 128, 54, 13, 11, 1, 253, 124, 248, 128, 113, + 13, 11, 1, 253, 124, 233, 65, 39, 13, 11, 1, 253, 124, 233, 65, 30, 13, + 11, 1, 253, 124, 233, 65, 54, 13, 11, 1, 253, 124, 233, 65, 113, 13, 11, + 1, 57, 240, 92, 39, 13, 11, 1, 57, 240, 92, 30, 13, 11, 1, 57, 240, 92, + 2, 143, 60, 39, 13, 11, 1, 57, 240, 92, 2, 143, 60, 30, 13, 11, 1, 255, + 44, 39, 13, 11, 1, 255, 44, 30, 13, 11, 1, 255, 44, 54, 13, 11, 1, 255, + 44, 113, 13, 11, 1, 132, 39, 13, 11, 1, 132, 30, 13, 11, 1, 255, 33, 39, + 13, 11, 1, 255, 33, 30, 13, 11, 1, 255, 36, 39, 13, 11, 1, 255, 36, 30, + 13, 11, 1, 132, 2, 143, 60, 39, 13, 11, 1, 255, 65, 39, 13, 11, 1, 255, + 65, 30, 13, 11, 1, 238, 73, 255, 33, 39, 13, 11, 1, 238, 73, 255, 33, 30, + 13, 11, 1, 238, 73, 255, 36, 39, 13, 11, 1, 238, 73, 255, 36, 30, 13, 11, + 1, 157, 39, 13, 11, 1, 157, 30, 13, 11, 1, 157, 54, 13, 11, 1, 157, 113, + 13, 11, 1, 240, 104, 240, 192, 238, 73, 83, 150, 54, 13, 11, 1, 240, 104, + 240, 192, 238, 73, 83, 150, 113, 13, 11, 18, 57, 2, 143, 60, 2, 83, 39, + 13, 11, 18, 57, 2, 143, 60, 2, 83, 30, 13, 11, 18, 57, 2, 143, 60, 2, + 255, 30, 39, 13, 11, 18, 57, 2, 143, 60, 2, 255, 30, 30, 13, 11, 18, 57, + 2, 143, 60, 2, 253, 220, 39, 13, 11, 18, 57, 2, 143, 60, 2, 253, 220, 30, + 13, 11, 18, 57, 2, 143, 60, 2, 132, 39, 13, 11, 18, 57, 2, 143, 60, 2, + 132, 30, 13, 11, 18, 57, 2, 143, 60, 2, 255, 33, 39, 13, 11, 18, 57, 2, + 143, 60, 2, 255, 33, 30, 13, 11, 18, 57, 2, 143, 60, 2, 255, 36, 39, 13, + 11, 18, 57, 2, 143, 60, 2, 255, 36, 30, 13, 11, 18, 57, 2, 143, 60, 2, + 157, 39, 13, 11, 18, 57, 2, 143, 60, 2, 157, 30, 13, 11, 18, 57, 2, 143, + 60, 2, 157, 54, 13, 11, 18, 240, 104, 238, 73, 57, 2, 143, 60, 2, 83, + 150, 39, 13, 11, 18, 240, 104, 238, 73, 57, 2, 143, 60, 2, 83, 150, 30, + 13, 11, 18, 240, 104, 238, 73, 57, 2, 143, 60, 2, 83, 150, 54, 13, 11, 1, + 243, 26, 57, 39, 13, 11, 1, 243, 26, 57, 30, 13, 11, 1, 243, 26, 57, 54, + 13, 11, 1, 243, 26, 57, 113, 13, 11, 18, 57, 2, 143, 60, 2, 103, 39, 13, + 11, 18, 57, 2, 143, 60, 2, 94, 39, 13, 11, 18, 57, 2, 143, 60, 2, 51, 39, + 13, 11, 18, 57, 2, 143, 60, 2, 83, 150, 39, 13, 11, 18, 57, 2, 143, 60, + 2, 57, 39, 13, 11, 18, 253, 136, 2, 103, 39, 13, 11, 18, 253, 136, 2, 94, + 39, 13, 11, 18, 253, 136, 2, 164, 39, 13, 11, 18, 253, 136, 2, 51, 39, + 13, 11, 18, 253, 136, 2, 83, 150, 39, 13, 11, 18, 253, 136, 2, 57, 39, + 13, 11, 18, 253, 127, 2, 103, 39, 13, 11, 18, 253, 127, 2, 94, 39, 13, + 11, 18, 253, 127, 2, 164, 39, 13, 11, 18, 253, 127, 2, 51, 39, 13, 11, + 18, 253, 127, 2, 83, 150, 39, 13, 11, 18, 253, 127, 2, 57, 39, 13, 11, + 18, 248, 70, 2, 103, 39, 13, 11, 18, 248, 70, 2, 51, 39, 13, 11, 18, 248, + 70, 2, 83, 150, 39, 13, 11, 18, 248, 70, 2, 57, 39, 13, 11, 18, 103, 2, + 94, 39, 13, 11, 18, 103, 2, 51, 39, 13, 11, 18, 94, 2, 103, 39, 13, 11, + 18, 94, 2, 51, 39, 13, 11, 18, 164, 2, 103, 39, 13, 11, 18, 164, 2, 94, + 39, 13, 11, 18, 164, 2, 51, 39, 13, 11, 18, 248, 39, 2, 103, 39, 13, 11, + 18, 248, 39, 2, 94, 39, 13, 11, 18, 248, 39, 2, 164, 39, 13, 11, 18, 248, + 39, 2, 51, 39, 13, 11, 18, 253, 157, 2, 94, 39, 13, 11, 18, 253, 157, 2, + 51, 39, 13, 11, 18, 253, 155, 2, 103, 39, 13, 11, 18, 253, 155, 2, 94, + 39, 13, 11, 18, 253, 155, 2, 164, 39, 13, 11, 18, 253, 155, 2, 51, 39, + 13, 11, 18, 253, 169, 2, 94, 39, 13, 11, 18, 253, 169, 2, 51, 39, 13, 11, + 18, 253, 255, 2, 51, 39, 13, 11, 18, 253, 158, 2, 103, 39, 13, 11, 18, + 253, 158, 2, 51, 39, 13, 11, 18, 242, 240, 2, 103, 39, 13, 11, 18, 242, + 240, 2, 51, 39, 13, 11, 18, 253, 153, 2, 103, 39, 13, 11, 18, 253, 153, + 2, 94, 39, 13, 11, 18, 253, 153, 2, 164, 39, 13, 11, 18, 253, 153, 2, 51, + 39, 13, 11, 18, 253, 153, 2, 83, 150, 39, 13, 11, 18, 253, 153, 2, 57, + 39, 13, 11, 18, 253, 167, 2, 94, 39, 13, 11, 18, 253, 167, 2, 51, 39, 13, + 11, 18, 253, 167, 2, 83, 150, 39, 13, 11, 18, 253, 167, 2, 57, 39, 13, + 11, 18, 253, 135, 2, 83, 39, 13, 11, 18, 253, 135, 2, 103, 39, 13, 11, + 18, 253, 135, 2, 94, 39, 13, 11, 18, 253, 135, 2, 164, 39, 13, 11, 18, + 253, 135, 2, 182, 39, 13, 11, 18, 253, 135, 2, 51, 39, 13, 11, 18, 253, + 135, 2, 83, 150, 39, 13, 11, 18, 253, 135, 2, 57, 39, 13, 11, 18, 182, 2, + 103, 39, 13, 11, 18, 182, 2, 94, 39, 13, 11, 18, 182, 2, 164, 39, 13, 11, + 18, 182, 2, 51, 39, 13, 11, 18, 182, 2, 83, 150, 39, 13, 11, 18, 182, 2, + 57, 39, 13, 11, 18, 51, 2, 103, 39, 13, 11, 18, 51, 2, 94, 39, 13, 11, + 18, 51, 2, 164, 39, 13, 11, 18, 51, 2, 51, 39, 13, 11, 18, 51, 2, 83, + 150, 39, 13, 11, 18, 51, 2, 57, 39, 13, 11, 18, 198, 2, 103, 39, 13, 11, + 18, 198, 2, 94, 39, 13, 11, 18, 198, 2, 164, 39, 13, 11, 18, 198, 2, 51, + 39, 13, 11, 18, 198, 2, 83, 150, 39, 13, 11, 18, 198, 2, 57, 39, 13, 11, + 18, 253, 124, 2, 103, 39, 13, 11, 18, 253, 124, 2, 51, 39, 13, 11, 18, + 253, 124, 2, 83, 150, 39, 13, 11, 18, 253, 124, 2, 57, 39, 13, 11, 18, + 57, 2, 103, 39, 13, 11, 18, 57, 2, 94, 39, 13, 11, 18, 57, 2, 164, 39, + 13, 11, 18, 57, 2, 51, 39, 13, 11, 18, 57, 2, 83, 150, 39, 13, 11, 18, + 57, 2, 57, 39, 13, 11, 18, 249, 0, 2, 233, 49, 83, 39, 13, 11, 18, 253, + 143, 2, 233, 49, 83, 39, 13, 11, 18, 83, 150, 2, 233, 49, 83, 39, 13, 11, + 18, 240, 47, 2, 237, 1, 39, 13, 11, 18, 240, 47, 2, 237, 15, 39, 13, 11, + 18, 240, 47, 2, 243, 40, 39, 13, 11, 18, 240, 47, 2, 243, 56, 39, 13, 11, + 18, 240, 47, 2, 243, 63, 39, 13, 11, 18, 240, 47, 2, 233, 49, 83, 39, 13, + 11, 18, 57, 2, 143, 60, 2, 253, 143, 30, 13, 11, 18, 57, 2, 143, 60, 2, + 248, 104, 30, 13, 11, 18, 57, 2, 143, 60, 2, 51, 30, 13, 11, 18, 57, 2, + 143, 60, 2, 198, 30, 13, 11, 18, 57, 2, 143, 60, 2, 83, 150, 30, 13, 11, + 18, 57, 2, 143, 60, 2, 57, 30, 13, 11, 18, 253, 136, 2, 253, 143, 30, 13, + 11, 18, 253, 136, 2, 248, 104, 30, 13, 11, 18, 253, 136, 2, 51, 30, 13, + 11, 18, 253, 136, 2, 198, 30, 13, 11, 18, 253, 136, 2, 83, 150, 30, 13, + 11, 18, 253, 136, 2, 57, 30, 13, 11, 18, 253, 127, 2, 253, 143, 30, 13, + 11, 18, 253, 127, 2, 248, 104, 30, 13, 11, 18, 253, 127, 2, 51, 30, 13, + 11, 18, 253, 127, 2, 198, 30, 13, 11, 18, 253, 127, 2, 83, 150, 30, 13, + 11, 18, 253, 127, 2, 57, 30, 13, 11, 18, 248, 70, 2, 253, 143, 30, 13, + 11, 18, 248, 70, 2, 248, 104, 30, 13, 11, 18, 248, 70, 2, 51, 30, 13, 11, + 18, 248, 70, 2, 198, 30, 13, 11, 18, 248, 70, 2, 83, 150, 30, 13, 11, 18, + 248, 70, 2, 57, 30, 13, 11, 18, 253, 153, 2, 83, 150, 30, 13, 11, 18, + 253, 153, 2, 57, 30, 13, 11, 18, 253, 167, 2, 83, 150, 30, 13, 11, 18, + 253, 167, 2, 57, 30, 13, 11, 18, 253, 135, 2, 83, 30, 13, 11, 18, 253, + 135, 2, 182, 30, 13, 11, 18, 253, 135, 2, 51, 30, 13, 11, 18, 253, 135, + 2, 83, 150, 30, 13, 11, 18, 253, 135, 2, 57, 30, 13, 11, 18, 182, 2, 51, + 30, 13, 11, 18, 182, 2, 83, 150, 30, 13, 11, 18, 182, 2, 57, 30, 13, 11, + 18, 51, 2, 83, 30, 13, 11, 18, 51, 2, 51, 30, 13, 11, 18, 198, 2, 253, + 143, 30, 13, 11, 18, 198, 2, 248, 104, 30, 13, 11, 18, 198, 2, 51, 30, + 13, 11, 18, 198, 2, 198, 30, 13, 11, 18, 198, 2, 83, 150, 30, 13, 11, 18, + 198, 2, 57, 30, 13, 11, 18, 83, 150, 2, 233, 49, 83, 30, 13, 11, 18, 57, + 2, 253, 143, 30, 13, 11, 18, 57, 2, 248, 104, 30, 13, 11, 18, 57, 2, 51, + 30, 13, 11, 18, 57, 2, 198, 30, 13, 11, 18, 57, 2, 83, 150, 30, 13, 11, + 18, 57, 2, 57, 30, 13, 11, 18, 57, 2, 143, 60, 2, 103, 54, 13, 11, 18, + 57, 2, 143, 60, 2, 94, 54, 13, 11, 18, 57, 2, 143, 60, 2, 164, 54, 13, + 11, 18, 57, 2, 143, 60, 2, 51, 54, 13, 11, 18, 57, 2, 143, 60, 2, 253, + 124, 54, 13, 11, 18, 253, 136, 2, 103, 54, 13, 11, 18, 253, 136, 2, 94, + 54, 13, 11, 18, 253, 136, 2, 164, 54, 13, 11, 18, 253, 136, 2, 51, 54, + 13, 11, 18, 253, 136, 2, 253, 124, 54, 13, 11, 18, 253, 127, 2, 103, 54, + 13, 11, 18, 253, 127, 2, 94, 54, 13, 11, 18, 253, 127, 2, 164, 54, 13, + 11, 18, 253, 127, 2, 51, 54, 13, 11, 18, 253, 127, 2, 253, 124, 54, 13, + 11, 18, 248, 70, 2, 51, 54, 13, 11, 18, 103, 2, 94, 54, 13, 11, 18, 103, + 2, 51, 54, 13, 11, 18, 94, 2, 103, 54, 13, 11, 18, 94, 2, 51, 54, 13, 11, + 18, 164, 2, 103, 54, 13, 11, 18, 164, 2, 51, 54, 13, 11, 18, 248, 39, 2, + 103, 54, 13, 11, 18, 248, 39, 2, 94, 54, 13, 11, 18, 248, 39, 2, 164, 54, + 13, 11, 18, 248, 39, 2, 51, 54, 13, 11, 18, 253, 157, 2, 94, 54, 13, 11, + 18, 253, 157, 2, 164, 54, 13, 11, 18, 253, 157, 2, 51, 54, 13, 11, 18, + 253, 155, 2, 103, 54, 13, 11, 18, 253, 155, 2, 94, 54, 13, 11, 18, 253, + 155, 2, 164, 54, 13, 11, 18, 253, 155, 2, 51, 54, 13, 11, 18, 253, 169, + 2, 94, 54, 13, 11, 18, 253, 255, 2, 51, 54, 13, 11, 18, 253, 158, 2, 103, + 54, 13, 11, 18, 253, 158, 2, 51, 54, 13, 11, 18, 242, 240, 2, 103, 54, + 13, 11, 18, 242, 240, 2, 51, 54, 13, 11, 18, 253, 153, 2, 103, 54, 13, + 11, 18, 253, 153, 2, 94, 54, 13, 11, 18, 253, 153, 2, 164, 54, 13, 11, + 18, 253, 153, 2, 51, 54, 13, 11, 18, 253, 167, 2, 94, 54, 13, 11, 18, + 253, 167, 2, 51, 54, 13, 11, 18, 253, 135, 2, 103, 54, 13, 11, 18, 253, + 135, 2, 94, 54, 13, 11, 18, 253, 135, 2, 164, 54, 13, 11, 18, 253, 135, + 2, 182, 54, 13, 11, 18, 253, 135, 2, 51, 54, 13, 11, 18, 182, 2, 103, 54, + 13, 11, 18, 182, 2, 94, 54, 13, 11, 18, 182, 2, 164, 54, 13, 11, 18, 182, + 2, 51, 54, 13, 11, 18, 182, 2, 253, 124, 54, 13, 11, 18, 51, 2, 103, 54, + 13, 11, 18, 51, 2, 94, 54, 13, 11, 18, 51, 2, 164, 54, 13, 11, 18, 51, 2, + 51, 54, 13, 11, 18, 198, 2, 103, 54, 13, 11, 18, 198, 2, 94, 54, 13, 11, + 18, 198, 2, 164, 54, 13, 11, 18, 198, 2, 51, 54, 13, 11, 18, 198, 2, 253, + 124, 54, 13, 11, 18, 253, 124, 2, 103, 54, 13, 11, 18, 253, 124, 2, 51, + 54, 13, 11, 18, 253, 124, 2, 233, 49, 83, 54, 13, 11, 18, 57, 2, 103, 54, + 13, 11, 18, 57, 2, 94, 54, 13, 11, 18, 57, 2, 164, 54, 13, 11, 18, 57, 2, + 51, 54, 13, 11, 18, 57, 2, 253, 124, 54, 13, 11, 18, 57, 2, 143, 60, 2, + 51, 113, 13, 11, 18, 57, 2, 143, 60, 2, 253, 124, 113, 13, 11, 18, 253, + 136, 2, 51, 113, 13, 11, 18, 253, 136, 2, 253, 124, 113, 13, 11, 18, 253, + 127, 2, 51, 113, 13, 11, 18, 253, 127, 2, 253, 124, 113, 13, 11, 18, 248, + 70, 2, 51, 113, 13, 11, 18, 248, 70, 2, 253, 124, 113, 13, 11, 18, 248, + 39, 2, 51, 113, 13, 11, 18, 248, 39, 2, 253, 124, 113, 13, 11, 18, 242, + 216, 2, 51, 113, 13, 11, 18, 242, 216, 2, 253, 124, 113, 13, 11, 18, 253, + 135, 2, 182, 113, 13, 11, 18, 253, 135, 2, 51, 113, 13, 11, 18, 182, 2, + 51, 113, 13, 11, 18, 198, 2, 51, 113, 13, 11, 18, 198, 2, 253, 124, 113, + 13, 11, 18, 57, 2, 51, 113, 13, 11, 18, 57, 2, 253, 124, 113, 13, 11, 18, + 240, 47, 2, 243, 40, 113, 13, 11, 18, 240, 47, 2, 243, 56, 113, 13, 11, + 18, 240, 47, 2, 243, 63, 113, 13, 11, 18, 253, 169, 2, 83, 150, 39, 13, + 11, 18, 253, 169, 2, 57, 39, 13, 11, 18, 253, 158, 2, 83, 150, 39, 13, + 11, 18, 253, 158, 2, 57, 39, 13, 11, 18, 242, 240, 2, 83, 150, 39, 13, + 11, 18, 242, 240, 2, 57, 39, 13, 11, 18, 248, 39, 2, 83, 150, 39, 13, 11, + 18, 248, 39, 2, 57, 39, 13, 11, 18, 242, 216, 2, 83, 150, 39, 13, 11, 18, + 242, 216, 2, 57, 39, 13, 11, 18, 94, 2, 83, 150, 39, 13, 11, 18, 94, 2, + 57, 39, 13, 11, 18, 103, 2, 83, 150, 39, 13, 11, 18, 103, 2, 57, 39, 13, + 11, 18, 164, 2, 83, 150, 39, 13, 11, 18, 164, 2, 57, 39, 13, 11, 18, 253, + 157, 2, 83, 150, 39, 13, 11, 18, 253, 157, 2, 57, 39, 13, 11, 18, 253, + 155, 2, 83, 150, 39, 13, 11, 18, 253, 155, 2, 57, 39, 13, 11, 18, 242, + 216, 2, 103, 39, 13, 11, 18, 242, 216, 2, 94, 39, 13, 11, 18, 242, 216, + 2, 164, 39, 13, 11, 18, 242, 216, 2, 51, 39, 13, 11, 18, 242, 216, 2, + 253, 143, 39, 13, 11, 18, 248, 39, 2, 253, 143, 39, 13, 11, 18, 253, 157, + 2, 253, 143, 39, 13, 11, 18, 253, 155, 2, 253, 143, 39, 13, 11, 18, 253, + 169, 2, 83, 150, 30, 13, 11, 18, 253, 169, 2, 57, 30, 13, 11, 18, 253, + 158, 2, 83, 150, 30, 13, 11, 18, 253, 158, 2, 57, 30, 13, 11, 18, 242, + 240, 2, 83, 150, 30, 13, 11, 18, 242, 240, 2, 57, 30, 13, 11, 18, 248, + 39, 2, 83, 150, 30, 13, 11, 18, 248, 39, 2, 57, 30, 13, 11, 18, 242, 216, + 2, 83, 150, 30, 13, 11, 18, 242, 216, 2, 57, 30, 13, 11, 18, 94, 2, 83, + 150, 30, 13, 11, 18, 94, 2, 57, 30, 13, 11, 18, 103, 2, 83, 150, 30, 13, + 11, 18, 103, 2, 57, 30, 13, 11, 18, 164, 2, 83, 150, 30, 13, 11, 18, 164, + 2, 57, 30, 13, 11, 18, 253, 157, 2, 83, 150, 30, 13, 11, 18, 253, 157, 2, + 57, 30, 13, 11, 18, 253, 155, 2, 83, 150, 30, 13, 11, 18, 253, 155, 2, + 57, 30, 13, 11, 18, 242, 216, 2, 103, 30, 13, 11, 18, 242, 216, 2, 94, + 30, 13, 11, 18, 242, 216, 2, 164, 30, 13, 11, 18, 242, 216, 2, 51, 30, + 13, 11, 18, 242, 216, 2, 253, 143, 30, 13, 11, 18, 248, 39, 2, 253, 143, + 30, 13, 11, 18, 253, 157, 2, 253, 143, 30, 13, 11, 18, 253, 155, 2, 253, + 143, 30, 13, 11, 18, 242, 216, 2, 103, 54, 13, 11, 18, 242, 216, 2, 94, + 54, 13, 11, 18, 242, 216, 2, 164, 54, 13, 11, 18, 242, 216, 2, 51, 54, + 13, 11, 18, 248, 39, 2, 253, 124, 54, 13, 11, 18, 242, 216, 2, 253, 124, + 54, 13, 11, 18, 253, 169, 2, 51, 54, 13, 11, 18, 248, 39, 2, 103, 113, + 13, 11, 18, 248, 39, 2, 94, 113, 13, 11, 18, 248, 39, 2, 164, 113, 13, + 11, 18, 242, 216, 2, 103, 113, 13, 11, 18, 242, 216, 2, 94, 113, 13, 11, + 18, 242, 216, 2, 164, 113, 13, 11, 18, 253, 169, 2, 51, 113, 13, 11, 18, + 253, 255, 2, 51, 113, 13, 11, 18, 83, 2, 236, 214, 30, 13, 11, 18, 83, 2, + 236, 214, 39, 13, 240, 206, 40, 232, 74, 240, 206, 38, 232, 74, 11, 18, + 253, 127, 2, 103, 2, 51, 54, 13, 11, 18, 253, 127, 2, 94, 2, 103, 30, 13, + 11, 18, 253, 127, 2, 94, 2, 103, 54, 13, 11, 18, 253, 127, 2, 94, 2, 51, + 54, 13, 11, 18, 253, 127, 2, 164, 2, 51, 54, 13, 11, 18, 253, 127, 2, 51, + 2, 103, 54, 13, 11, 18, 253, 127, 2, 51, 2, 94, 54, 13, 11, 18, 253, 127, + 2, 51, 2, 164, 54, 13, 11, 18, 103, 2, 51, 2, 94, 30, 13, 11, 18, 103, 2, + 51, 2, 94, 54, 13, 11, 18, 94, 2, 51, 2, 57, 30, 13, 11, 18, 94, 2, 51, + 2, 83, 150, 30, 13, 11, 18, 248, 39, 2, 94, 2, 103, 54, 13, 11, 18, 248, + 39, 2, 103, 2, 94, 54, 13, 11, 18, 248, 39, 2, 103, 2, 83, 150, 30, 13, + 11, 18, 248, 39, 2, 51, 2, 94, 30, 13, 11, 18, 248, 39, 2, 51, 2, 94, 54, + 13, 11, 18, 248, 39, 2, 51, 2, 103, 54, 13, 11, 18, 248, 39, 2, 51, 2, + 51, 30, 13, 11, 18, 248, 39, 2, 51, 2, 51, 54, 13, 11, 18, 253, 157, 2, + 94, 2, 94, 30, 13, 11, 18, 253, 157, 2, 94, 2, 94, 54, 13, 11, 18, 253, + 157, 2, 51, 2, 51, 30, 13, 11, 18, 242, 216, 2, 94, 2, 51, 30, 13, 11, + 18, 242, 216, 2, 94, 2, 51, 54, 13, 11, 18, 242, 216, 2, 103, 2, 57, 30, + 13, 11, 18, 242, 216, 2, 51, 2, 164, 30, 13, 11, 18, 242, 216, 2, 51, 2, + 164, 54, 13, 11, 18, 242, 216, 2, 51, 2, 51, 30, 13, 11, 18, 242, 216, 2, + 51, 2, 51, 54, 13, 11, 18, 253, 155, 2, 94, 2, 83, 150, 30, 13, 11, 18, + 253, 155, 2, 164, 2, 51, 30, 13, 11, 18, 253, 155, 2, 164, 2, 51, 54, 13, + 11, 18, 253, 169, 2, 51, 2, 94, 30, 13, 11, 18, 253, 169, 2, 51, 2, 94, + 54, 13, 11, 18, 253, 169, 2, 51, 2, 51, 54, 13, 11, 18, 253, 169, 2, 51, + 2, 57, 30, 13, 11, 18, 253, 158, 2, 103, 2, 51, 30, 13, 11, 18, 253, 158, + 2, 51, 2, 51, 30, 13, 11, 18, 253, 158, 2, 51, 2, 51, 54, 13, 11, 18, + 253, 158, 2, 51, 2, 83, 150, 30, 13, 11, 18, 242, 240, 2, 51, 2, 51, 30, + 13, 11, 18, 242, 240, 2, 51, 2, 57, 30, 13, 11, 18, 242, 240, 2, 51, 2, + 83, 150, 30, 13, 11, 18, 253, 153, 2, 164, 2, 51, 30, 13, 11, 18, 253, + 153, 2, 164, 2, 51, 54, 13, 11, 18, 253, 167, 2, 51, 2, 94, 30, 13, 11, + 18, 253, 167, 2, 51, 2, 51, 30, 13, 11, 18, 182, 2, 94, 2, 51, 30, 13, + 11, 18, 182, 2, 94, 2, 57, 30, 13, 11, 18, 182, 2, 94, 2, 83, 150, 30, + 13, 11, 18, 182, 2, 103, 2, 103, 54, 13, 11, 18, 182, 2, 103, 2, 103, 30, + 13, 11, 18, 182, 2, 164, 2, 51, 30, 13, 11, 18, 182, 2, 164, 2, 51, 54, + 13, 11, 18, 182, 2, 51, 2, 94, 30, 13, 11, 18, 182, 2, 51, 2, 94, 54, 13, + 11, 18, 51, 2, 94, 2, 103, 54, 13, 11, 18, 51, 2, 94, 2, 51, 54, 13, 11, + 18, 51, 2, 94, 2, 57, 30, 13, 11, 18, 51, 2, 103, 2, 94, 54, 13, 11, 18, + 51, 2, 103, 2, 51, 54, 13, 11, 18, 51, 2, 164, 2, 103, 54, 13, 11, 18, + 51, 2, 164, 2, 51, 54, 13, 11, 18, 51, 2, 103, 2, 164, 54, 13, 11, 18, + 253, 124, 2, 51, 2, 103, 54, 13, 11, 18, 253, 124, 2, 51, 2, 51, 54, 13, + 11, 18, 198, 2, 94, 2, 51, 54, 13, 11, 18, 198, 2, 94, 2, 83, 150, 30, + 13, 11, 18, 198, 2, 103, 2, 51, 30, 13, 11, 18, 198, 2, 103, 2, 51, 54, + 13, 11, 18, 198, 2, 103, 2, 83, 150, 30, 13, 11, 18, 198, 2, 51, 2, 57, + 30, 13, 11, 18, 198, 2, 51, 2, 83, 150, 30, 13, 11, 18, 57, 2, 51, 2, 51, + 30, 13, 11, 18, 57, 2, 51, 2, 51, 54, 13, 11, 18, 253, 136, 2, 164, 2, + 57, 30, 13, 11, 18, 253, 127, 2, 103, 2, 57, 30, 13, 11, 18, 253, 127, 2, + 103, 2, 83, 150, 30, 13, 11, 18, 253, 127, 2, 164, 2, 57, 30, 13, 11, 18, + 253, 127, 2, 164, 2, 83, 150, 30, 13, 11, 18, 253, 127, 2, 51, 2, 57, 30, + 13, 11, 18, 253, 127, 2, 51, 2, 83, 150, 30, 13, 11, 18, 103, 2, 51, 2, + 57, 30, 13, 11, 18, 103, 2, 94, 2, 83, 150, 30, 13, 11, 18, 103, 2, 51, + 2, 83, 150, 30, 13, 11, 18, 248, 39, 2, 164, 2, 83, 150, 30, 13, 11, 18, + 253, 157, 2, 94, 2, 57, 30, 13, 11, 18, 242, 216, 2, 94, 2, 57, 30, 13, + 11, 18, 253, 155, 2, 94, 2, 57, 30, 13, 11, 18, 182, 2, 103, 2, 57, 30, + 13, 11, 18, 182, 2, 51, 2, 57, 30, 13, 11, 18, 57, 2, 94, 2, 57, 30, 13, + 11, 18, 57, 2, 103, 2, 57, 30, 13, 11, 18, 57, 2, 51, 2, 57, 30, 13, 11, + 18, 51, 2, 51, 2, 57, 30, 13, 11, 18, 253, 167, 2, 51, 2, 57, 30, 13, 11, + 18, 198, 2, 94, 2, 57, 30, 13, 11, 18, 253, 167, 2, 51, 2, 94, 54, 13, + 11, 18, 182, 2, 94, 2, 51, 54, 13, 11, 18, 253, 158, 2, 51, 2, 57, 30, + 13, 11, 18, 253, 135, 2, 51, 2, 57, 30, 13, 11, 18, 198, 2, 103, 2, 94, + 54, 13, 11, 18, 51, 2, 164, 2, 57, 30, 13, 11, 18, 182, 2, 103, 2, 51, + 54, 13, 11, 18, 253, 135, 2, 51, 2, 51, 30, 13, 11, 18, 182, 2, 103, 2, + 51, 30, 13, 11, 18, 198, 2, 103, 2, 94, 30, 13, 11, 18, 103, 2, 94, 2, + 57, 30, 13, 11, 18, 94, 2, 103, 2, 57, 30, 13, 11, 18, 51, 2, 103, 2, 57, + 30, 13, 11, 18, 253, 153, 2, 51, 2, 57, 30, 13, 11, 18, 253, 136, 2, 94, + 2, 57, 30, 13, 11, 18, 253, 135, 2, 51, 2, 51, 54, 13, 11, 18, 253, 158, + 2, 103, 2, 51, 54, 13, 11, 18, 253, 157, 2, 51, 2, 51, 54, 13, 11, 18, + 248, 39, 2, 164, 2, 57, 30, 13, 11, 18, 198, 2, 103, 2, 57, 30, 13, 11, + 18, 244, 3, 249, 191, 255, 24, 238, 197, 248, 119, 21, 39, 13, 11, 18, + 252, 85, 249, 191, 255, 24, 238, 197, 248, 119, 21, 39, 13, 11, 18, 244, + 77, 39, 13, 11, 18, 244, 75, 39, 13, 11, 18, 237, 213, 39, 13, 11, 18, + 247, 64, 39, 13, 11, 18, 242, 77, 39, 13, 11, 18, 240, 107, 39, 13, 11, + 18, 238, 45, 39, 13, 11, 18, 244, 3, 39, 13, 11, 18, 233, 100, 240, 107, + 236, 140, 11, 18, 229, 46, 252, 136, 52, 11, 18, 235, 181, 235, 168, 234, + 93, 34, 233, 233, 34, 233, 234, 34, 233, 235, 34, 233, 236, 34, 233, 237, + 34, 233, 238, 34, 233, 239, 34, 233, 240, 34, 233, 241, 34, 232, 204, 34, + 232, 205, 34, 232, 206, 34, 232, 207, 34, 232, 208, 34, 232, 209, 34, + 232, 210, 232, 70, 248, 38, 28, 59, 240, 27, 232, 70, 248, 38, 28, 59, + 80, 240, 27, 232, 70, 248, 38, 28, 59, 80, 248, 37, 208, 232, 70, 248, + 38, 28, 59, 240, 24, 232, 70, 248, 38, 28, 59, 234, 14, 232, 70, 248, 38, + 28, 59, 233, 54, 69, 232, 70, 248, 38, 28, 59, 236, 156, 69, 232, 70, + 248, 38, 28, 59, 40, 64, 234, 11, 104, 232, 70, 248, 38, 28, 59, 38, 64, + 234, 11, 237, 79, 232, 70, 248, 38, 28, 59, 163, 235, 69, 50, 18, 40, + 243, 7, 50, 18, 38, 243, 7, 50, 45, 242, 219, 40, 243, 7, 50, 45, 242, + 219, 38, 243, 7, 232, 70, 248, 38, 28, 59, 171, 53, 238, 143, 232, 70, + 248, 38, 28, 59, 255, 28, 242, 235, 232, 70, 248, 38, 28, 59, 255, 23, + 242, 235, 232, 70, 248, 38, 28, 59, 170, 242, 224, 232, 70, 248, 38, 28, + 59, 248, 103, 170, 242, 224, 232, 70, 248, 38, 28, 59, 40, 232, 74, 232, + 70, 248, 38, 28, 59, 38, 232, 74, 232, 70, 248, 38, 28, 59, 40, 242, 225, + 104, 232, 70, 248, 38, 28, 59, 38, 242, 225, 104, 232, 70, 248, 38, 28, + 59, 40, 236, 171, 242, 255, 104, 232, 70, 248, 38, 28, 59, 38, 236, 171, + 242, 255, 104, 232, 70, 248, 38, 28, 59, 40, 86, 234, 11, 104, 232, 70, + 248, 38, 28, 59, 38, 86, 234, 11, 104, 232, 70, 248, 38, 28, 59, 40, 45, + 185, 104, 232, 70, 248, 38, 28, 59, 38, 45, 185, 104, 232, 70, 248, 38, + 28, 59, 40, 185, 104, 232, 70, 248, 38, 28, 59, 38, 185, 104, 232, 70, + 248, 38, 28, 59, 40, 240, 31, 104, 232, 70, 248, 38, 28, 59, 38, 240, 31, + 104, 232, 70, 248, 38, 28, 59, 40, 64, 240, 31, 104, 232, 70, 248, 38, + 28, 59, 38, 64, 240, 31, 104, 240, 221, 248, 40, 64, 240, 221, 248, 40, + 232, 70, 248, 38, 28, 59, 40, 31, 104, 232, 70, 248, 38, 28, 59, 38, 31, + 104, 240, 55, 235, 74, 234, 48, 235, 74, 248, 103, 235, 74, 45, 248, 103, + 235, 74, 240, 55, 170, 242, 224, 234, 48, 170, 242, 224, 248, 103, 170, + 242, 224, 3, 240, 27, 3, 80, 240, 27, 3, 248, 37, 208, 3, 234, 14, 3, + 240, 24, 3, 236, 156, 69, 3, 233, 54, 69, 3, 255, 28, 242, 235, 3, 40, + 232, 74, 3, 38, 232, 74, 3, 40, 242, 225, 104, 3, 38, 242, 225, 104, 3, + 40, 236, 171, 242, 255, 104, 3, 38, 236, 171, 242, 255, 104, 3, 61, 52, + 3, 234, 17, 3, 235, 52, 3, 248, 49, 52, 3, 231, 94, 3, 235, 44, 52, 3, + 232, 68, 52, 3, 240, 7, 52, 3, 238, 75, 236, 177, 3, 240, 114, 52, 3, + 238, 107, 52, 3, 234, 20, 254, 20, 11, 236, 214, 39, 13, 11, 239, 214, 2, + 236, 214, 48, 11, 237, 1, 39, 13, 11, 248, 138, 236, 26, 11, 237, 15, 39, + 13, 11, 243, 40, 39, 13, 11, 243, 40, 113, 13, 11, 243, 56, 39, 13, 11, + 243, 56, 113, 13, 11, 243, 63, 39, 13, 11, 243, 63, 113, 13, 11, 240, 47, + 39, 13, 11, 240, 47, 113, 13, 11, 244, 25, 39, 13, 11, 244, 25, 113, 13, + 11, 1, 143, 39, 13, 11, 1, 83, 2, 243, 42, 60, 39, 13, 11, 1, 83, 2, 243, + 42, 60, 30, 13, 11, 1, 83, 2, 143, 60, 39, 13, 11, 1, 83, 2, 143, 60, 30, + 13, 11, 1, 253, 220, 2, 143, 60, 39, 13, 11, 1, 253, 220, 2, 143, 60, 30, + 13, 11, 1, 83, 2, 143, 242, 230, 39, 13, 11, 1, 83, 2, 143, 242, 230, 30, + 13, 11, 1, 57, 2, 143, 60, 39, 13, 11, 1, 57, 2, 143, 60, 30, 13, 11, 1, + 57, 2, 143, 60, 54, 13, 11, 1, 57, 2, 143, 60, 113, 13, 11, 1, 83, 39, + 13, 11, 1, 83, 30, 13, 11, 1, 253, 136, 39, 13, 11, 1, 253, 136, 30, 13, + 11, 1, 253, 136, 54, 13, 11, 1, 253, 136, 113, 13, 11, 1, 253, 127, 238, + 144, 39, 13, 11, 1, 253, 127, 238, 144, 30, 13, 11, 1, 253, 127, 39, 13, + 11, 1, 253, 127, 30, 13, 11, 1, 253, 127, 54, 13, 11, 1, 253, 127, 113, + 13, 11, 1, 248, 70, 39, 13, 11, 1, 248, 70, 30, 13, 11, 1, 248, 70, 54, + 13, 11, 1, 248, 70, 113, 13, 11, 1, 103, 39, 13, 11, 1, 103, 30, 13, 11, + 1, 103, 54, 13, 11, 1, 103, 113, 13, 11, 1, 94, 39, 13, 11, 1, 94, 30, + 13, 11, 1, 94, 54, 13, 11, 1, 94, 113, 13, 11, 1, 164, 39, 13, 11, 1, + 164, 30, 13, 11, 1, 164, 54, 13, 11, 1, 164, 113, 13, 11, 1, 253, 199, + 39, 13, 11, 1, 253, 199, 30, 13, 11, 1, 249, 0, 39, 13, 11, 1, 249, 0, + 30, 13, 11, 1, 253, 143, 39, 13, 11, 1, 253, 143, 30, 13, 11, 1, 248, + 104, 39, 13, 11, 1, 248, 104, 30, 13, 11, 1, 248, 39, 39, 13, 11, 1, 248, + 39, 30, 13, 11, 1, 248, 39, 54, 13, 11, 1, 248, 39, 113, 13, 11, 1, 242, + 216, 39, 13, 11, 1, 242, 216, 30, 13, 11, 1, 242, 216, 54, 13, 11, 1, + 242, 216, 113, 13, 11, 1, 253, 157, 39, 13, 11, 1, 253, 157, 30, 13, 11, + 1, 253, 157, 54, 13, 11, 1, 253, 157, 113, 13, 11, 1, 253, 155, 39, 13, + 11, 1, 253, 155, 30, 13, 11, 1, 253, 155, 54, 13, 11, 1, 253, 155, 113, + 13, 11, 1, 253, 169, 39, 13, 11, 1, 253, 169, 30, 13, 11, 1, 253, 169, + 54, 13, 11, 1, 253, 169, 113, 13, 11, 1, 253, 255, 39, 13, 11, 1, 253, + 255, 30, 13, 11, 1, 253, 255, 54, 13, 11, 1, 253, 255, 113, 13, 11, 1, + 253, 158, 39, 13, 11, 1, 253, 158, 30, 13, 11, 1, 253, 158, 54, 13, 11, + 1, 253, 158, 113, 13, 11, 1, 242, 240, 39, 13, 11, 1, 242, 240, 30, 13, + 11, 1, 242, 240, 54, 13, 11, 1, 242, 240, 113, 13, 11, 1, 253, 153, 39, + 13, 11, 1, 253, 153, 30, 13, 11, 1, 253, 153, 54, 13, 11, 1, 253, 153, + 113, 13, 11, 1, 253, 167, 39, 13, 11, 1, 253, 167, 30, 13, 11, 1, 253, + 167, 54, 13, 11, 1, 253, 167, 113, 13, 11, 1, 253, 135, 39, 13, 11, 1, + 253, 135, 30, 13, 11, 1, 253, 135, 54, 13, 11, 1, 253, 135, 113, 13, 11, + 1, 182, 39, 13, 11, 1, 182, 30, 13, 11, 1, 182, 54, 13, 11, 1, 182, 113, + 13, 11, 1, 51, 39, 13, 11, 1, 51, 30, 13, 11, 1, 51, 54, 13, 11, 1, 51, + 113, 13, 11, 1, 198, 39, 13, 11, 1, 198, 30, 13, 11, 1, 198, 54, 13, 11, + 1, 198, 113, 13, 11, 1, 253, 124, 39, 13, 11, 1, 253, 124, 30, 13, 11, 1, + 253, 124, 54, 13, 11, 1, 253, 124, 113, 13, 11, 1, 253, 220, 39, 13, 11, + 1, 253, 220, 30, 13, 11, 1, 83, 150, 39, 13, 11, 1, 83, 150, 30, 13, 11, + 1, 57, 39, 13, 11, 1, 57, 30, 13, 11, 1, 57, 54, 13, 11, 1, 57, 113, 13, + 11, 18, 182, 2, 83, 2, 243, 42, 60, 39, 13, 11, 18, 182, 2, 83, 2, 243, + 42, 60, 30, 13, 11, 18, 182, 2, 83, 2, 143, 60, 39, 13, 11, 18, 182, 2, + 83, 2, 143, 60, 30, 13, 11, 18, 182, 2, 83, 2, 143, 242, 230, 39, 13, 11, + 18, 182, 2, 83, 2, 143, 242, 230, 30, 13, 11, 18, 182, 2, 83, 39, 13, 11, + 18, 182, 2, 83, 30, 13, 248, 145, 243, 81, 236, 233, 240, 15, 89, 233, + 54, 69, 89, 235, 51, 69, 89, 61, 52, 89, 240, 114, 52, 89, 238, 107, 52, + 89, 234, 17, 89, 233, 59, 89, 40, 232, 74, 89, 38, 232, 74, 89, 235, 52, + 89, 248, 49, 52, 89, 240, 27, 89, 231, 94, 89, 248, 37, 208, 89, 236, + 177, 89, 26, 242, 217, 89, 26, 127, 89, 26, 111, 89, 26, 166, 89, 26, + 177, 89, 26, 176, 89, 26, 187, 89, 26, 203, 89, 26, 195, 89, 26, 202, 89, + 240, 24, 89, 234, 14, 89, 235, 44, 52, 89, 240, 7, 52, 89, 232, 68, 52, + 89, 236, 156, 69, 89, 234, 20, 254, 20, 89, 8, 5, 1, 67, 89, 8, 5, 1, + 217, 89, 8, 5, 1, 255, 18, 89, 8, 5, 1, 209, 89, 8, 5, 1, 72, 89, 8, 5, + 1, 255, 19, 89, 8, 5, 1, 210, 89, 8, 5, 1, 192, 89, 8, 5, 1, 71, 89, 8, + 5, 1, 221, 89, 8, 5, 1, 255, 15, 89, 8, 5, 1, 162, 89, 8, 5, 1, 173, 89, + 8, 5, 1, 197, 89, 8, 5, 1, 73, 89, 8, 5, 1, 223, 89, 8, 5, 1, 255, 20, + 89, 8, 5, 1, 144, 89, 8, 5, 1, 193, 89, 8, 5, 1, 214, 89, 8, 5, 1, 79, + 89, 8, 5, 1, 179, 89, 8, 5, 1, 255, 16, 89, 8, 5, 1, 206, 89, 8, 5, 1, + 255, 14, 89, 8, 5, 1, 255, 17, 89, 40, 31, 104, 89, 238, 75, 236, 177, + 89, 38, 31, 104, 89, 190, 238, 54, 89, 170, 242, 224, 89, 242, 245, 238, + 54, 89, 8, 3, 1, 67, 89, 8, 3, 1, 217, 89, 8, 3, 1, 255, 18, 89, 8, 3, 1, + 209, 89, 8, 3, 1, 72, 89, 8, 3, 1, 255, 19, 89, 8, 3, 1, 210, 89, 8, 3, + 1, 192, 89, 8, 3, 1, 71, 89, 8, 3, 1, 221, 89, 8, 3, 1, 255, 15, 89, 8, + 3, 1, 162, 89, 8, 3, 1, 173, 89, 8, 3, 1, 197, 89, 8, 3, 1, 73, 89, 8, 3, + 1, 223, 89, 8, 3, 1, 255, 20, 89, 8, 3, 1, 144, 89, 8, 3, 1, 193, 89, 8, + 3, 1, 214, 89, 8, 3, 1, 79, 89, 8, 3, 1, 179, 89, 8, 3, 1, 255, 16, 89, + 8, 3, 1, 206, 89, 8, 3, 1, 255, 14, 89, 8, 3, 1, 255, 17, 89, 40, 242, + 225, 104, 89, 59, 242, 224, 89, 38, 242, 225, 104, 89, 169, 89, 40, 64, + 232, 74, 89, 38, 64, 232, 74, 74, 80, 248, 37, 208, 74, 40, 240, 31, 104, + 74, 38, 240, 31, 104, 74, 80, 240, 27, 74, 42, 240, 1, 248, 40, 74, 42, + 1, 253, 177, 74, 42, 1, 3, 67, 74, 42, 1, 3, 71, 74, 42, 1, 3, 79, 74, + 42, 1, 3, 72, 74, 42, 1, 3, 73, 74, 42, 1, 3, 216, 74, 42, 1, 3, 253, + 161, 74, 42, 1, 3, 253, 162, 74, 42, 1, 3, 253, 196, 74, 226, 254, 235, + 138, 243, 1, 69, 74, 42, 1, 67, 74, 42, 1, 71, 74, 42, 1, 79, 74, 42, 1, + 72, 74, 42, 1, 73, 74, 42, 1, 201, 74, 42, 1, 253, 215, 74, 42, 1, 253, + 203, 74, 42, 1, 253, 172, 74, 42, 1, 253, 190, 74, 42, 1, 253, 132, 74, + 42, 1, 253, 198, 74, 42, 1, 253, 211, 74, 42, 1, 253, 210, 74, 42, 1, + 253, 186, 74, 42, 1, 253, 126, 74, 42, 1, 253, 212, 74, 42, 1, 253, 196, + 74, 42, 1, 253, 195, 74, 42, 1, 87, 74, 42, 1, 253, 131, 74, 42, 1, 253, + 166, 74, 42, 1, 253, 150, 74, 42, 1, 253, 197, 74, 42, 1, 253, 173, 74, + 42, 1, 219, 74, 42, 1, 253, 214, 74, 42, 1, 253, 236, 74, 42, 1, 253, + 168, 74, 42, 1, 253, 184, 74, 42, 1, 222, 74, 42, 1, 253, 180, 74, 42, 1, + 253, 154, 74, 42, 1, 253, 206, 74, 42, 1, 253, 181, 74, 42, 1, 216, 74, + 42, 1, 253, 161, 74, 42, 1, 253, 162, 74, 42, 1, 253, 130, 74, 42, 1, + 253, 209, 74, 42, 1, 253, 185, 74, 42, 1, 253, 194, 74, 42, 1, 253, 160, + 74, 42, 1, 253, 138, 74, 42, 1, 197, 74, 42, 240, 59, 243, 1, 69, 74, 42, + 233, 75, 243, 1, 69, 74, 23, 238, 114, 74, 23, 1, 238, 99, 74, 23, 1, + 232, 87, 74, 23, 1, 232, 91, 74, 23, 1, 240, 80, 74, 23, 1, 232, 93, 74, + 23, 1, 232, 94, 74, 23, 1, 238, 102, 74, 23, 1, 232, 101, 74, 23, 1, 240, + 85, 74, 23, 1, 231, 98, 74, 23, 1, 232, 96, 74, 23, 1, 232, 97, 74, 23, + 1, 233, 74, 74, 23, 1, 231, 43, 74, 23, 1, 231, 42, 74, 23, 1, 232, 85, + 74, 23, 1, 240, 78, 74, 23, 1, 240, 83, 74, 23, 1, 233, 79, 74, 23, 1, + 233, 66, 74, 23, 1, 243, 34, 74, 23, 1, 234, 32, 74, 23, 1, 240, 75, 74, + 23, 1, 240, 71, 74, 23, 1, 233, 77, 74, 23, 1, 236, 195, 74, 23, 1, 236, + 198, 74, 23, 1, 236, 205, 74, 23, 1, 236, 201, 74, 23, 1, 240, 74, 74, + 23, 1, 67, 74, 23, 1, 253, 178, 74, 23, 1, 216, 74, 23, 1, 249, 18, 74, + 23, 1, 254, 59, 74, 23, 1, 72, 74, 23, 1, 249, 22, 74, 23, 1, 253, 254, + 74, 23, 1, 73, 74, 23, 1, 253, 138, 74, 23, 1, 249, 12, 74, 23, 1, 253, + 193, 74, 23, 1, 253, 162, 74, 23, 1, 79, 74, 23, 1, 249, 14, 74, 23, 1, + 253, 170, 74, 23, 1, 253, 187, 74, 23, 1, 253, 161, 74, 23, 1, 254, 61, + 74, 23, 1, 253, 189, 74, 23, 1, 71, 89, 249, 39, 52, 89, 243, 246, 52, + 89, 161, 52, 89, 196, 89, 240, 129, 125, 89, 254, 134, 52, 89, 254, 131, + 52, 74, 245, 91, 136, 235, 63, 74, 139, 56, 74, 226, 226, 56, 74, 77, 56, + 74, 235, 45, 56, 74, 86, 238, 59, 74, 64, 238, 51, 233, 71, 234, 4, 238, + 159, 233, 71, 234, 4, 234, 6, 233, 71, 234, 4, 233, 251, 242, 38, 233, + 99, 234, 49, 233, 99, 234, 49, 44, 41, 4, 249, 254, 67, 44, 41, 4, 250, + 23, 72, 44, 41, 4, 250, 15, 71, 44, 41, 4, 250, 43, 73, 44, 41, 4, 250, + 0, 79, 44, 41, 4, 249, 247, 253, 133, 44, 41, 4, 250, 30, 253, 200, 44, + 41, 4, 249, 253, 253, 201, 44, 41, 4, 250, 4, 253, 225, 44, 41, 4, 250, + 34, 253, 232, 44, 41, 4, 250, 39, 253, 146, 44, 41, 4, 250, 31, 254, 24, + 44, 41, 4, 250, 21, 253, 248, 44, 41, 4, 250, 45, 254, 25, 44, 41, 4, + 250, 57, 201, 44, 41, 4, 250, 29, 253, 172, 44, 41, 4, 250, 47, 253, 215, + 44, 41, 4, 250, 50, 253, 190, 44, 41, 4, 250, 60, 253, 203, 44, 41, 4, + 250, 59, 222, 44, 41, 4, 250, 3, 253, 206, 44, 41, 4, 250, 53, 253, 180, + 44, 41, 4, 250, 5, 253, 181, 44, 41, 4, 250, 10, 253, 154, 44, 41, 4, + 249, 252, 253, 131, 44, 41, 4, 250, 11, 253, 197, 44, 41, 4, 250, 17, + 253, 166, 44, 41, 4, 250, 35, 253, 173, 44, 41, 4, 250, 38, 253, 150, 44, + 41, 4, 249, 249, 253, 129, 44, 41, 4, 250, 52, 253, 175, 44, 41, 4, 250, + 24, 253, 147, 44, 41, 4, 250, 1, 253, 208, 44, 41, 4, 250, 33, 253, 239, + 44, 41, 4, 250, 6, 253, 217, 44, 41, 4, 250, 58, 254, 70, 44, 41, 4, 250, + 9, 254, 28, 44, 41, 4, 250, 19, 254, 45, 44, 41, 4, 250, 42, 253, 130, + 44, 41, 4, 250, 14, 253, 194, 44, 41, 4, 250, 36, 253, 209, 44, 41, 4, + 249, 248, 253, 160, 44, 41, 4, 250, 13, 253, 185, 44, 41, 4, 250, 18, + 253, 132, 44, 41, 4, 249, 255, 253, 210, 44, 41, 4, 250, 26, 253, 198, + 44, 41, 4, 250, 2, 253, 186, 44, 41, 4, 250, 40, 253, 211, 44, 41, 4, + 250, 41, 253, 126, 44, 41, 4, 249, 250, 253, 195, 44, 41, 4, 250, 22, + 253, 212, 44, 41, 4, 249, 251, 87, 44, 41, 4, 250, 49, 253, 196, 44, 41, + 4, 250, 37, 253, 138, 44, 41, 4, 250, 55, 253, 170, 44, 41, 4, 250, 25, + 253, 187, 44, 41, 4, 250, 27, 253, 177, 44, 41, 4, 250, 7, 253, 163, 44, + 41, 4, 250, 54, 253, 228, 44, 41, 4, 250, 8, 253, 222, 44, 41, 4, 250, + 12, 254, 137, 44, 41, 4, 250, 28, 254, 138, 44, 41, 4, 250, 61, 253, 151, + 44, 41, 4, 250, 51, 250, 215, 44, 41, 4, 250, 63, 250, 216, 44, 41, 4, + 250, 32, 248, 176, 44, 41, 4, 250, 16, 252, 77, 44, 41, 4, 250, 44, 252, + 76, 44, 41, 4, 250, 56, 252, 124, 44, 41, 4, 250, 20, 252, 125, 44, 41, + 4, 250, 48, 252, 141, 44, 41, 4, 250, 46, 252, 207, 44, 41, 4, 250, 62, + 249, 8, 44, 41, 4, 250, 64, 111, 44, 41, 12, 244, 88, 44, 41, 12, 244, + 89, 44, 41, 12, 244, 90, 44, 41, 12, 244, 91, 44, 41, 12, 244, 92, 44, + 41, 12, 244, 93, 44, 41, 12, 244, 94, 44, 41, 12, 244, 95, 44, 41, 12, + 244, 96, 44, 41, 12, 244, 97, 44, 41, 12, 244, 98, 44, 41, 12, 244, 99, + 44, 41, 12, 244, 100, 44, 41, 12, 244, 101, 44, 41, 78, 250, 65, 248, + 131, 44, 41, 78, 250, 66, 240, 253, 44, 41, 78, 250, 67, 243, 164, 44, + 41, 78, 250, 68, 241, 98, 44, 41, 78, 244, 102, 246, 63, 44, 41, 78, 244, + 103, 236, 106, 44, 41, 78, 244, 104, 249, 58, 44, 41, 78, 244, 105, 249, + 151, 44, 41, 78, 244, 106, 236, 102, 44, 41, 78, 244, 107, 237, 172, 44, + 41, 78, 244, 108, 252, 187, 44, 41, 78, 244, 109, 244, 225, 44, 41, 78, + 244, 110, 248, 202, 44, 41, 78, 244, 111, 244, 231, 44, 41, 78, 250, 69, + 240, 153, 44, 41, 78, 250, 70, 239, 4, 44, 41, 78, 250, 71, 242, 40, 44, + 41, 78, 250, 72, 242, 123, 44, 41, 78, 250, 73, 237, 99, 44, 41, 236, + 184, 250, 74, 246, 6, 44, 41, 236, 184, 250, 75, 239, 104, 44, 41, 78, + 250, 76, 249, 127, 44, 41, 78, 250, 77, 243, 133, 44, 41, 78, 244, 112, + 44, 41, 236, 184, 250, 78, 241, 13, 44, 41, 236, 184, 250, 79, 246, 64, + 44, 41, 78, 250, 80, 239, 14, 44, 41, 78, 250, 81, 243, 96, 44, 41, 78, + 244, 113, 44, 41, 78, 250, 82, 244, 53, 44, 41, 78, 244, 114, 44, 41, 78, + 244, 115, 44, 41, 78, 250, 83, 243, 8, 44, 41, 78, 244, 116, 44, 41, 78, + 244, 117, 44, 41, 78, 244, 118, 44, 41, 236, 184, 250, 84, 242, 163, 44, + 41, 78, 244, 120, 44, 41, 78, 244, 121, 44, 41, 78, 250, 85, 240, 132, + 44, 41, 78, 244, 122, 44, 41, 78, 244, 123, 44, 41, 78, 250, 86, 237, + 164, 44, 41, 78, 250, 87, 238, 248, 44, 41, 78, 244, 124, 44, 41, 78, + 244, 125, 44, 41, 78, 244, 126, 44, 41, 78, 244, 127, 44, 41, 78, 244, + 128, 44, 41, 78, 244, 129, 44, 41, 78, 244, 130, 44, 41, 78, 244, 131, + 44, 41, 78, 244, 132, 44, 41, 78, 250, 88, 241, 248, 44, 41, 78, 244, + 133, 44, 41, 78, 250, 89, 244, 37, 44, 41, 78, 244, 134, 44, 41, 78, 244, + 135, 44, 41, 78, 244, 136, 44, 41, 78, 244, 137, 44, 41, 78, 244, 138, + 44, 41, 78, 244, 139, 44, 41, 78, 244, 140, 44, 41, 78, 244, 141, 44, 41, + 78, 244, 142, 44, 41, 78, 244, 143, 44, 41, 78, 244, 144, 44, 41, 78, + 250, 90, 239, 90, 44, 41, 78, 250, 91, 234, 190, 44, 41, 78, 250, 92, + 237, 73, 44, 41, 78, 250, 93, 240, 236, 44, 41, 78, 250, 94, 56, 44, 41, + 78, 244, 171, 44, 41, 78, 250, 95, 242, 137, 44, 41, 78, 244, 172, 44, + 41, 78, 244, 173, 44, 41, 78, 250, 96, 239, 248, 236, 252, 44, 41, 78, + 250, 97, 236, 252, 44, 41, 78, 250, 98, 239, 22, 241, 116, 44, 41, 78, + 250, 99, 242, 184, 44, 41, 78, 244, 174, 44, 41, 78, 244, 175, 44, 41, + 236, 184, 250, 100, 241, 85, 44, 41, 78, 244, 176, 44, 41, 78, 244, 177, + 44, 41, 78, 244, 179, 44, 41, 78, 244, 180, 44, 41, 78, 244, 181, 44, 41, + 78, 250, 101, 245, 35, 44, 41, 78, 244, 182, 44, 41, 78, 244, 183, 44, + 41, 78, 244, 184, 44, 41, 78, 244, 185, 44, 41, 78, 244, 186, 44, 41, 78, + 240, 6, 244, 119, 44, 41, 78, 240, 6, 244, 145, 44, 41, 78, 240, 6, 244, + 146, 44, 41, 78, 240, 6, 244, 147, 44, 41, 78, 240, 6, 244, 148, 44, 41, + 78, 240, 6, 244, 149, 44, 41, 78, 240, 6, 244, 150, 44, 41, 78, 240, 6, + 244, 151, 44, 41, 78, 240, 6, 244, 152, 44, 41, 78, 240, 6, 244, 153, 44, + 41, 78, 240, 6, 244, 154, 44, 41, 78, 240, 6, 244, 155, 44, 41, 78, 240, + 6, 244, 156, 44, 41, 78, 240, 6, 244, 157, 44, 41, 78, 240, 6, 244, 158, + 44, 41, 78, 240, 6, 244, 159, 44, 41, 78, 240, 6, 244, 160, 44, 41, 78, + 240, 6, 244, 161, 44, 41, 78, 240, 6, 244, 162, 44, 41, 78, 240, 6, 244, + 163, 44, 41, 78, 240, 6, 244, 164, 44, 41, 78, 240, 6, 244, 165, 44, 41, + 78, 240, 6, 244, 166, 44, 41, 78, 240, 6, 244, 167, 44, 41, 78, 240, 6, + 244, 168, 44, 41, 78, 240, 6, 244, 169, 44, 41, 78, 240, 6, 244, 170, 44, + 41, 78, 240, 6, 244, 178, 44, 41, 78, 240, 6, 244, 187, 167, 248, 143, + 235, 95, 242, 224, 167, 248, 143, 235, 95, 248, 40, 167, 243, 53, 69, + 167, 61, 127, 167, 61, 111, 167, 61, 166, 167, 61, 177, 167, 61, 176, + 167, 61, 187, 167, 61, 203, 167, 61, 195, 167, 61, 202, 167, 61, 248, 53, + 167, 61, 238, 77, 167, 61, 238, 101, 167, 61, 240, 136, 167, 61, 240, 50, + 167, 61, 240, 234, 167, 61, 237, 38, 167, 61, 238, 182, 167, 61, 238, + 147, 167, 61, 253, 125, 236, 149, 167, 61, 171, 236, 149, 167, 61, 204, + 236, 149, 167, 61, 248, 58, 236, 149, 167, 61, 248, 48, 236, 149, 167, + 61, 254, 31, 236, 149, 167, 61, 243, 31, 236, 149, 167, 61, 242, 254, + 236, 149, 167, 61, 248, 173, 236, 149, 167, 61, 253, 125, 235, 49, 167, + 61, 171, 235, 49, 167, 61, 204, 235, 49, 167, 61, 248, 58, 235, 49, 167, + 61, 248, 48, 235, 49, 167, 61, 254, 31, 235, 49, 167, 61, 243, 31, 235, + 49, 167, 61, 242, 254, 235, 49, 167, 61, 248, 173, 235, 49, 167, 61, 253, + 219, 235, 49, 167, 61, 240, 48, 235, 49, 167, 61, 240, 53, 235, 49, 167, + 61, 243, 6, 235, 49, 167, 61, 243, 18, 235, 49, 167, 61, 247, 90, 235, + 49, 167, 61, 239, 190, 235, 49, 167, 61, 241, 92, 235, 49, 167, 61, 242, + 12, 235, 49, 167, 240, 106, 248, 196, 247, 183, 167, 240, 106, 243, 41, + 236, 188, 167, 240, 106, 240, 87, 236, 188, 167, 240, 106, 243, 129, 236, + 188, 167, 240, 106, 240, 137, 236, 188, 167, 254, 157, 238, 119, 243, 41, + 236, 188, 167, 241, 218, 238, 119, 243, 41, 236, 188, 167, 238, 119, 240, + 87, 236, 188, 167, 238, 119, 243, 129, 236, 188, 17, 180, 242, 227, 253, + 125, 237, 33, 17, 180, 242, 227, 253, 125, 243, 7, 17, 180, 242, 227, + 253, 125, 237, 141, 17, 180, 242, 227, 176, 17, 180, 242, 227, 240, 50, + 17, 180, 242, 227, 248, 48, 236, 149, 17, 180, 242, 227, 248, 48, 235, + 49, 17, 180, 242, 227, 243, 18, 235, 49, 17, 180, 242, 227, 248, 48, 236, + 192, 17, 180, 242, 227, 253, 219, 236, 192, 17, 180, 242, 227, 243, 18, + 236, 192, 17, 180, 242, 227, 253, 125, 238, 92, 236, 192, 17, 180, 242, + 227, 248, 48, 238, 92, 236, 192, 17, 180, 242, 227, 253, 125, 236, 193, + 236, 192, 17, 180, 242, 227, 248, 48, 236, 193, 236, 192, 17, 180, 242, + 227, 248, 48, 236, 187, 17, 180, 242, 227, 253, 219, 236, 187, 17, 180, + 242, 227, 243, 18, 236, 187, 17, 180, 242, 227, 253, 125, 238, 92, 236, + 187, 17, 180, 242, 227, 248, 48, 238, 92, 236, 187, 17, 180, 242, 227, + 253, 125, 236, 193, 236, 187, 17, 180, 242, 227, 253, 219, 236, 193, 236, + 187, 17, 180, 242, 227, 243, 18, 236, 193, 236, 187, 17, 180, 242, 227, + 253, 219, 243, 107, 17, 180, 239, 91, 253, 125, 236, 76, 17, 180, 236, + 179, 127, 17, 180, 234, 38, 127, 17, 180, 234, 37, 111, 17, 180, 236, + 179, 111, 17, 180, 237, 100, 171, 235, 121, 17, 180, 234, 37, 171, 235, + 121, 17, 180, 234, 19, 176, 17, 180, 234, 19, 248, 53, 17, 180, 234, 19, + 253, 219, 235, 96, 13, 17, 180, 234, 38, 248, 53, 17, 180, 236, 60, 248, + 53, 17, 180, 236, 179, 248, 53, 17, 180, 236, 179, 238, 101, 17, 180, + 234, 19, 240, 50, 17, 180, 234, 19, 243, 18, 235, 96, 13, 17, 180, 234, + 38, 240, 50, 17, 180, 236, 179, 240, 50, 17, 180, 236, 179, 253, 125, + 236, 149, 17, 180, 236, 179, 204, 236, 149, 17, 180, 234, 37, 248, 48, + 236, 149, 17, 180, 234, 19, 248, 48, 236, 149, 17, 180, 236, 179, 248, + 48, 236, 149, 17, 180, 235, 186, 248, 48, 236, 149, 17, 180, 241, 254, + 248, 48, 236, 149, 17, 180, 236, 179, 253, 125, 235, 49, 17, 180, 236, + 179, 248, 48, 235, 49, 17, 180, 239, 40, 248, 48, 243, 107, 17, 180, 238, + 16, 243, 18, 243, 107, 17, 253, 125, 137, 52, 17, 253, 125, 137, 21, 235, + 96, 13, 17, 171, 242, 149, 52, 17, 204, 236, 236, 52, 17, 249, 206, 52, + 17, 242, 140, 52, 17, 238, 180, 52, 17, 252, 57, 52, 17, 171, 243, 68, + 52, 17, 204, 243, 68, 52, 17, 248, 58, 243, 68, 52, 17, 248, 48, 243, 68, + 52, 17, 237, 209, 52, 17, 239, 111, 248, 196, 52, 17, 246, 52, 52, 17, + 242, 44, 52, 17, 242, 188, 52, 17, 241, 19, 52, 17, 241, 17, 52, 17, 241, + 141, 52, 17, 238, 33, 248, 196, 52, 17, 248, 145, 52, 76, 24, 1, 67, 76, + 24, 1, 253, 242, 76, 24, 1, 253, 172, 76, 24, 1, 253, 200, 76, 24, 1, 72, + 76, 24, 1, 254, 12, 76, 24, 1, 253, 228, 76, 24, 1, 253, 168, 76, 24, 1, + 248, 111, 76, 24, 1, 71, 76, 24, 1, 201, 76, 24, 1, 254, 3, 76, 24, 1, + 254, 22, 76, 24, 1, 253, 202, 76, 24, 1, 248, 93, 76, 24, 1, 73, 76, 24, + 1, 253, 175, 76, 24, 1, 248, 118, 76, 24, 1, 253, 203, 76, 24, 1, 254, 4, + 76, 24, 1, 254, 23, 76, 24, 1, 253, 195, 76, 24, 1, 79, 76, 24, 1, 250, + 223, 76, 24, 1, 249, 136, 76, 24, 1, 249, 94, 76, 24, 1, 254, 21, 76, 24, + 1, 250, 229, 76, 24, 1, 248, 88, 76, 24, 1, 253, 142, 76, 24, 1, 253, + 148, 76, 24, 178, 127, 76, 24, 178, 176, 76, 24, 178, 248, 53, 76, 24, + 178, 240, 50, 240, 8, 1, 244, 71, 240, 8, 1, 237, 70, 240, 8, 1, 245, + 120, 240, 8, 1, 245, 32, 240, 8, 1, 238, 240, 240, 8, 1, 236, 83, 240, 8, + 1, 245, 233, 240, 8, 1, 245, 139, 240, 8, 1, 239, 221, 240, 8, 1, 250, + 222, 240, 8, 1, 241, 206, 240, 8, 1, 241, 211, 240, 8, 1, 241, 226, 240, + 8, 1, 239, 142, 240, 8, 1, 251, 113, 240, 8, 1, 247, 184, 240, 8, 1, 236, + 68, 240, 8, 1, 238, 147, 240, 8, 1, 242, 75, 240, 8, 1, 242, 98, 240, 8, + 1, 242, 144, 240, 8, 1, 242, 185, 240, 8, 1, 241, 102, 240, 8, 1, 241, + 179, 240, 8, 1, 240, 190, 240, 8, 1, 242, 43, 240, 8, 1, 248, 173, 236, + 149, 236, 147, 1, 244, 78, 236, 147, 1, 242, 242, 236, 147, 1, 241, 122, + 236, 147, 1, 248, 61, 236, 147, 1, 240, 28, 236, 147, 1, 253, 184, 236, + 147, 1, 253, 177, 236, 147, 1, 242, 251, 236, 147, 1, 245, 201, 236, 147, + 1, 249, 176, 236, 147, 1, 248, 193, 236, 147, 1, 248, 116, 236, 147, 1, + 243, 33, 236, 147, 1, 240, 33, 236, 147, 1, 248, 166, 236, 147, 1, 245, + 64, 236, 147, 1, 248, 132, 236, 147, 1, 254, 18, 236, 147, 1, 242, 95, + 236, 147, 1, 248, 105, 236, 147, 1, 253, 239, 236, 147, 1, 247, 61, 236, + 147, 1, 247, 15, 236, 147, 1, 242, 76, 236, 147, 1, 239, 219, 236, 147, + 1, 240, 180, 236, 147, 1, 87, 236, 147, 1, 71, 236, 147, 1, 79, 236, 147, + 1, 248, 251, 236, 147, 248, 143, 236, 213, 76, 184, 21, 67, 76, 184, 21, + 71, 76, 184, 21, 79, 76, 184, 21, 201, 76, 184, 21, 253, 203, 76, 184, + 21, 253, 139, 76, 184, 21, 253, 235, 76, 184, 21, 253, 253, 76, 184, 21, + 253, 152, 76, 184, 21, 253, 146, 76, 184, 21, 254, 7, 76, 184, 21, 253, + 126, 76, 184, 21, 253, 196, 76, 184, 21, 253, 133, 76, 184, 21, 253, 201, + 76, 184, 21, 253, 232, 76, 184, 21, 248, 55, 76, 184, 21, 253, 129, 76, + 184, 21, 253, 141, 76, 184, 21, 253, 179, 76, 184, 21, 253, 131, 76, 184, + 21, 253, 150, 76, 184, 21, 222, 76, 184, 21, 253, 180, 76, 184, 21, 253, + 154, 76, 184, 21, 216, 76, 184, 21, 253, 171, 76, 184, 21, 254, 48, 76, + 184, 21, 253, 130, 76, 184, 21, 253, 185, 76, 184, 21, 253, 134, 76, 184, + 21, 253, 132, 76, 184, 21, 253, 163, 76, 184, 21, 248, 46, 76, 184, 21, + 248, 66, 76, 184, 21, 219, 76, 184, 21, 233, 118, 76, 184, 21, 231, 117, + 76, 184, 21, 231, 118, 76, 184, 21, 232, 66, 76, 184, 21, 234, 107, 76, + 184, 21, 232, 126, 76, 184, 21, 244, 189, 76, 184, 21, 237, 81, 76, 184, + 248, 143, 236, 213, 76, 184, 61, 127, 76, 184, 61, 111, 76, 184, 61, 248, + 53, 76, 184, 61, 238, 77, 76, 184, 61, 236, 149, 121, 5, 1, 183, 71, 121, + 5, 1, 183, 72, 121, 5, 1, 183, 67, 121, 5, 1, 183, 254, 0, 121, 5, 1, + 183, 73, 121, 5, 1, 183, 253, 156, 121, 5, 1, 242, 215, 71, 121, 5, 1, + 242, 215, 72, 121, 5, 1, 242, 215, 67, 121, 5, 1, 242, 215, 254, 0, 121, + 5, 1, 242, 215, 73, 121, 5, 1, 242, 215, 253, 156, 121, 5, 1, 254, 33, + 121, 5, 1, 254, 121, 121, 5, 1, 254, 14, 121, 5, 1, 248, 192, 121, 5, 1, + 192, 121, 5, 1, 248, 180, 121, 5, 1, 248, 197, 121, 5, 1, 248, 255, 121, + 5, 1, 248, 149, 121, 5, 1, 243, 54, 121, 5, 1, 248, 161, 121, 5, 1, 249, + 92, 121, 5, 1, 249, 67, 121, 5, 1, 254, 21, 121, 5, 1, 249, 10, 121, 5, + 1, 248, 109, 121, 5, 1, 243, 77, 121, 5, 1, 254, 23, 121, 5, 1, 248, 194, + 121, 5, 1, 248, 93, 121, 5, 1, 243, 139, 121, 5, 1, 254, 4, 121, 5, 1, + 254, 3, 121, 5, 1, 254, 22, 121, 5, 1, 253, 202, 121, 5, 1, 248, 108, + 121, 5, 1, 254, 42, 121, 5, 1, 254, 91, 121, 3, 1, 183, 71, 121, 3, 1, + 183, 72, 121, 3, 1, 183, 67, 121, 3, 1, 183, 254, 0, 121, 3, 1, 183, 73, + 121, 3, 1, 183, 253, 156, 121, 3, 1, 242, 215, 71, 121, 3, 1, 242, 215, + 72, 121, 3, 1, 242, 215, 67, 121, 3, 1, 242, 215, 254, 0, 121, 3, 1, 242, + 215, 73, 121, 3, 1, 242, 215, 253, 156, 121, 3, 1, 254, 33, 121, 3, 1, + 254, 121, 121, 3, 1, 254, 14, 121, 3, 1, 248, 192, 121, 3, 1, 192, 121, + 3, 1, 248, 180, 121, 3, 1, 248, 197, 121, 3, 1, 248, 255, 121, 3, 1, 248, + 149, 121, 3, 1, 243, 54, 121, 3, 1, 248, 161, 121, 3, 1, 249, 92, 121, 3, + 1, 249, 67, 121, 3, 1, 254, 21, 121, 3, 1, 249, 10, 121, 3, 1, 248, 109, + 121, 3, 1, 243, 77, 121, 3, 1, 254, 23, 121, 3, 1, 248, 194, 121, 3, 1, + 248, 93, 121, 3, 1, 243, 139, 121, 3, 1, 254, 4, 121, 3, 1, 254, 3, 121, + 3, 1, 254, 22, 121, 3, 1, 253, 202, 121, 3, 1, 248, 108, 121, 3, 1, 254, + 42, 121, 3, 1, 254, 91, 207, 1, 246, 240, 207, 1, 249, 184, 207, 1, 246, + 13, 207, 1, 249, 61, 207, 1, 242, 147, 207, 1, 253, 186, 207, 1, 247, + 127, 207, 1, 239, 25, 207, 1, 253, 77, 207, 1, 245, 204, 207, 1, 250, + 121, 207, 1, 245, 58, 207, 1, 251, 6, 207, 1, 253, 19, 207, 1, 247, 144, + 207, 1, 253, 110, 207, 1, 237, 23, 207, 1, 241, 189, 207, 1, 253, 35, + 207, 1, 241, 144, 207, 1, 246, 53, 207, 1, 246, 86, 207, 1, 254, 174, + 207, 1, 250, 221, 207, 1, 249, 241, 207, 1, 249, 234, 207, 1, 254, 9, + 207, 1, 244, 53, 207, 1, 248, 235, 207, 1, 254, 0, 207, 1, 247, 33, 207, + 1, 248, 132, 207, 1, 248, 207, 207, 1, 249, 235, 207, 1, 249, 84, 207, 1, + 253, 176, 207, 1, 252, 55, 207, 1, 246, 234, 207, 1, 249, 127, 207, 1, + 249, 244, 207, 1, 249, 240, 207, 1, 253, 227, 207, 1, 249, 236, 207, 1, + 250, 228, 207, 1, 241, 18, 207, 1, 248, 206, 207, 1, 251, 100, 207, 1, + 253, 78, 238, 50, 1, 243, 3, 238, 50, 1, 253, 141, 238, 50, 1, 253, 126, + 238, 50, 1, 253, 146, 238, 50, 1, 253, 253, 238, 50, 1, 248, 61, 238, 50, + 1, 245, 60, 238, 50, 1, 253, 130, 238, 50, 1, 253, 132, 238, 50, 1, 242, + 106, 238, 50, 1, 248, 76, 238, 50, 1, 244, 244, 238, 50, 1, 253, 139, + 238, 50, 1, 253, 179, 238, 50, 1, 247, 4, 238, 50, 1, 246, 3, 238, 50, 1, + 246, 34, 238, 50, 1, 246, 84, 238, 50, 1, 246, 197, 238, 50, 1, 248, 142, + 238, 50, 1, 219, 238, 50, 1, 216, 238, 50, 1, 67, 238, 50, 1, 72, 238, + 50, 1, 71, 238, 50, 1, 73, 238, 50, 1, 79, 238, 50, 1, 253, 140, 238, 50, + 1, 253, 164, 238, 50, 1, 253, 156, 238, 50, 26, 242, 217, 238, 50, 26, + 127, 238, 50, 26, 111, 238, 50, 26, 166, 238, 50, 26, 177, 238, 50, 26, + 176, 238, 50, 26, 187, 238, 50, 26, 203, 238, 50, 26, 195, 238, 50, 26, + 202, 172, 4, 67, 172, 4, 72, 172, 4, 71, 172, 4, 73, 172, 4, 79, 172, 4, + 253, 146, 172, 4, 253, 248, 172, 4, 201, 172, 4, 253, 172, 172, 4, 253, + 215, 172, 4, 253, 190, 172, 4, 253, 203, 172, 4, 253, 134, 172, 4, 253, + 250, 172, 4, 253, 251, 172, 4, 253, 216, 172, 4, 254, 8, 172, 4, 222, + 172, 4, 253, 206, 172, 4, 253, 180, 172, 4, 253, 181, 172, 4, 253, 154, + 172, 4, 253, 131, 172, 4, 253, 197, 172, 4, 253, 166, 172, 4, 253, 173, + 172, 4, 253, 150, 172, 4, 253, 129, 172, 4, 253, 175, 172, 4, 253, 147, + 172, 4, 253, 208, 172, 4, 253, 239, 172, 4, 253, 130, 172, 4, 253, 194, + 172, 4, 253, 209, 172, 4, 253, 160, 172, 4, 253, 185, 172, 4, 253, 132, + 172, 4, 253, 210, 172, 4, 253, 198, 172, 4, 253, 186, 172, 4, 253, 211, + 172, 4, 253, 126, 172, 4, 253, 195, 172, 4, 253, 212, 172, 4, 87, 172, 4, + 253, 196, 172, 4, 253, 138, 172, 4, 253, 170, 172, 4, 253, 187, 172, 4, + 253, 177, 172, 4, 253, 253, 172, 4, 254, 132, 172, 4, 253, 163, 172, 4, + 253, 222, 151, 1, 67, 151, 33, 21, 71, 151, 33, 21, 79, 151, 33, 21, 165, + 144, 151, 33, 21, 72, 151, 33, 21, 73, 151, 33, 240, 51, 69, 151, 21, 45, + 248, 51, 46, 151, 21, 235, 61, 151, 21, 236, 173, 151, 1, 201, 151, 1, + 248, 61, 151, 1, 253, 139, 151, 1, 248, 77, 151, 1, 253, 152, 151, 1, + 248, 57, 151, 1, 253, 146, 151, 1, 248, 78, 151, 1, 248, 71, 151, 1, 242, + 247, 151, 1, 248, 75, 151, 1, 242, 249, 151, 1, 248, 82, 151, 1, 253, + 126, 151, 1, 248, 55, 151, 1, 253, 133, 151, 1, 248, 76, 151, 1, 253, + 131, 151, 1, 253, 129, 151, 1, 248, 65, 151, 1, 253, 141, 151, 1, 248, + 81, 151, 1, 222, 151, 1, 216, 151, 1, 253, 130, 151, 1, 253, 134, 151, 1, + 253, 171, 151, 1, 248, 46, 151, 1, 248, 66, 151, 1, 253, 132, 151, 1, + 253, 163, 151, 1, 219, 151, 1, 249, 97, 151, 1, 242, 161, 151, 21, 253, + 144, 48, 151, 21, 241, 44, 151, 21, 53, 46, 151, 238, 72, 151, 26, 127, + 151, 26, 111, 151, 26, 166, 151, 26, 177, 151, 61, 248, 53, 151, 61, 238, + 77, 151, 61, 253, 125, 236, 149, 151, 61, 253, 125, 235, 49, 151, 233, + 51, 248, 40, 151, 233, 51, 3, 238, 51, 151, 233, 51, 238, 51, 151, 233, + 51, 237, 95, 125, 151, 233, 51, 236, 57, 151, 233, 51, 241, 220, 151, + 233, 51, 240, 111, 151, 233, 51, 45, 240, 111, 151, 233, 51, 241, 217, + 37, 20, 12, 240, 29, 37, 20, 12, 239, 37, 37, 20, 12, 232, 71, 37, 20, + 12, 243, 112, 232, 83, 37, 20, 12, 243, 112, 240, 73, 37, 20, 12, 240, + 152, 232, 83, 37, 20, 12, 240, 152, 240, 73, 37, 20, 12, 236, 44, 37, 20, + 12, 235, 30, 37, 20, 12, 232, 191, 37, 20, 12, 235, 43, 37, 20, 12, 236, + 142, 240, 73, 37, 20, 12, 236, 48, 37, 20, 12, 243, 142, 232, 83, 37, 20, + 12, 254, 92, 232, 83, 37, 20, 12, 238, 223, 37, 20, 12, 234, 213, 37, 20, + 12, 233, 116, 37, 20, 12, 234, 45, 240, 73, 37, 20, 12, 238, 20, 37, 20, + 12, 242, 150, 37, 20, 12, 240, 205, 235, 55, 37, 20, 12, 240, 98, 235, + 55, 37, 20, 12, 239, 168, 37, 20, 12, 235, 187, 37, 20, 12, 242, 175, 37, + 20, 12, 249, 85, 235, 55, 37, 20, 12, 238, 118, 235, 55, 37, 20, 12, 235, + 90, 235, 55, 37, 20, 12, 236, 96, 37, 20, 12, 236, 71, 37, 20, 12, 239, + 203, 235, 164, 37, 20, 12, 242, 45, 235, 55, 37, 20, 12, 239, 239, 235, + 55, 37, 20, 12, 236, 246, 235, 55, 37, 20, 12, 235, 165, 37, 20, 12, 238, + 195, 37, 20, 12, 242, 82, 37, 20, 12, 240, 207, 235, 55, 37, 20, 12, 238, + 29, 37, 20, 12, 231, 116, 37, 20, 12, 239, 188, 37, 20, 12, 238, 153, + 235, 55, 37, 20, 12, 238, 153, 251, 225, 238, 15, 37, 20, 12, 235, 132, + 235, 55, 37, 20, 12, 242, 146, 37, 20, 12, 241, 214, 37, 20, 12, 250, + 217, 37, 20, 12, 247, 158, 37, 20, 12, 238, 25, 37, 20, 12, 234, 215, 37, + 20, 12, 243, 142, 254, 92, 248, 64, 37, 20, 12, 240, 18, 235, 55, 37, 20, + 12, 234, 203, 37, 20, 12, 236, 242, 235, 55, 37, 20, 12, 241, 194, 236, + 132, 37, 20, 12, 236, 73, 37, 20, 12, 234, 241, 37, 20, 12, 236, 46, 37, + 20, 12, 236, 253, 235, 55, 37, 20, 12, 237, 246, 37, 20, 12, 233, 92, + 235, 55, 37, 20, 12, 233, 93, 235, 55, 37, 20, 12, 237, 177, 37, 20, 12, + 243, 231, 37, 20, 12, 237, 234, 37, 20, 12, 237, 190, 243, 84, 37, 20, + 12, 236, 242, 243, 84, 37, 20, 12, 232, 59, 37, 20, 12, 231, 139, 37, 20, + 12, 249, 85, 248, 64, 37, 20, 12, 240, 205, 248, 64, 37, 20, 12, 243, + 112, 248, 64, 37, 20, 12, 237, 235, 37, 20, 12, 236, 47, 37, 20, 12, 229, + 51, 37, 20, 12, 229, 47, 37, 20, 12, 237, 233, 248, 64, 37, 20, 12, 235, + 90, 253, 238, 248, 106, 37, 20, 12, 238, 118, 253, 238, 248, 106, 37, 20, + 12, 239, 252, 37, 20, 12, 234, 45, 248, 64, 37, 20, 12, 234, 44, 236, + 126, 248, 64, 37, 20, 12, 238, 49, 37, 20, 12, 229, 48, 37, 20, 12, 237, + 148, 37, 20, 12, 237, 86, 37, 20, 12, 241, 243, 245, 231, 37, 20, 12, + 240, 152, 248, 64, 37, 20, 12, 240, 207, 248, 64, 37, 20, 12, 236, 82, + 248, 64, 37, 20, 12, 239, 151, 37, 20, 12, 233, 114, 37, 20, 12, 237, + 196, 37, 20, 12, 233, 93, 248, 64, 37, 20, 12, 233, 92, 248, 64, 37, 20, + 12, 240, 172, 232, 190, 37, 20, 12, 237, 193, 37, 20, 12, 227, 12, 37, + 20, 12, 236, 242, 248, 64, 37, 20, 12, 233, 194, 37, 20, 12, 238, 153, + 248, 64, 37, 20, 12, 242, 138, 37, 20, 12, 236, 253, 248, 64, 37, 20, 12, + 236, 13, 37, 20, 12, 242, 100, 248, 64, 37, 20, 12, 247, 204, 238, 195, + 37, 20, 12, 227, 8, 37, 20, 12, 229, 53, 37, 20, 12, 231, 32, 37, 20, 12, + 226, 242, 37, 20, 12, 226, 233, 37, 20, 12, 231, 33, 37, 20, 12, 229, 54, + 37, 20, 12, 229, 66, 37, 20, 12, 231, 44, 37, 20, 12, 240, 172, 231, 44, + 37, 20, 12, 235, 132, 248, 64, 37, 20, 12, 233, 109, 250, 230, 37, 20, + 12, 233, 109, 250, 232, 37, 20, 12, 247, 143, 238, 161, 37, 20, 12, 252, + 218, 254, 65, 237, 63, 37, 20, 12, 234, 211, 37, 20, 12, 234, 186, 37, + 20, 12, 249, 208, 243, 20, 37, 20, 12, 249, 208, 248, 106, 37, 20, 12, + 238, 14, 37, 20, 12, 240, 194, 248, 106, 37, 20, 12, 245, 67, 235, 55, + 37, 20, 12, 238, 142, 235, 55, 37, 20, 12, 238, 142, 243, 84, 37, 20, 12, + 238, 142, 248, 64, 37, 20, 12, 236, 246, 248, 64, 37, 20, 12, 244, 83, + 37, 20, 12, 240, 73, 37, 20, 12, 239, 228, 37, 20, 12, 236, 128, 37, 20, + 12, 236, 229, 37, 20, 12, 240, 100, 250, 225, 236, 254, 37, 20, 12, 240, + 100, 254, 57, 236, 221, 37, 20, 12, 240, 100, 247, 159, 236, 221, 37, 20, + 12, 240, 100, 238, 24, 236, 221, 37, 20, 12, 240, 100, 239, 97, 236, 254, + 37, 20, 12, 240, 98, 253, 238, 248, 106, 37, 20, 12, 240, 98, 231, 92, + 235, 171, 37, 20, 12, 240, 98, 231, 92, 240, 168, 37, 20, 12, 235, 204, + 37, 20, 12, 236, 223, 231, 92, 236, 247, 243, 20, 37, 20, 12, 236, 223, + 231, 92, 236, 247, 248, 106, 37, 20, 12, 236, 223, 231, 92, 240, 168, 37, + 20, 12, 235, 37, 37, 20, 12, 241, 14, 37, 20, 12, 233, 209, 37, 20, 12, + 237, 106, 37, 20, 12, 243, 13, 249, 139, 243, 143, 37, 20, 12, 243, 13, + 235, 170, 37, 20, 12, 243, 13, 243, 143, 37, 20, 12, 243, 13, 239, 135, + 37, 20, 12, 243, 13, 246, 66, 37, 20, 12, 243, 13, 240, 184, 37, 20, 12, + 243, 13, 234, 196, 37, 20, 12, 243, 13, 249, 139, 240, 184, 37, 20, 12, + 236, 162, 240, 211, 240, 35, 37, 20, 12, 236, 162, 249, 27, 240, 211, + 240, 35, 37, 20, 12, 236, 162, 237, 5, 240, 35, 37, 20, 12, 236, 162, + 249, 27, 237, 5, 240, 35, 37, 20, 12, 236, 162, 242, 157, 240, 35, 37, + 20, 12, 236, 162, 235, 36, 37, 20, 12, 236, 162, 236, 241, 240, 35, 37, + 20, 12, 236, 162, 236, 241, 238, 198, 240, 35, 37, 20, 12, 236, 162, 238, + 198, 240, 35, 37, 20, 12, 236, 162, 238, 209, 240, 35, 37, 20, 12, 241, + 181, 240, 243, 234, 58, 37, 20, 12, 234, 44, 240, 243, 234, 58, 37, 20, + 12, 235, 99, 233, 40, 37, 20, 12, 235, 99, 233, 87, 37, 20, 12, 235, 99, + 235, 119, 37, 20, 12, 236, 162, 247, 185, 240, 35, 37, 20, 12, 236, 162, + 234, 240, 240, 35, 37, 20, 12, 236, 162, 238, 209, 236, 241, 240, 35, 37, + 20, 12, 234, 57, 255, 98, 238, 161, 37, 20, 12, 234, 57, 255, 98, 237, + 110, 37, 20, 12, 239, 56, 254, 65, 240, 18, 249, 196, 37, 20, 12, 236, + 38, 37, 20, 12, 233, 210, 37, 20, 12, 240, 18, 237, 66, 237, 103, 241, + 178, 37, 20, 12, 240, 18, 235, 72, 253, 129, 37, 20, 12, 240, 18, 235, + 72, 243, 231, 37, 20, 12, 240, 18, 251, 254, 240, 35, 37, 20, 12, 240, + 18, 235, 72, 253, 201, 37, 20, 12, 240, 18, 238, 150, 237, 107, 253, 201, + 37, 20, 12, 240, 18, 235, 72, 253, 172, 37, 20, 12, 240, 18, 235, 72, + 253, 222, 37, 20, 12, 240, 18, 235, 72, 255, 62, 243, 20, 37, 20, 12, + 240, 18, 235, 72, 255, 62, 248, 106, 37, 20, 12, 240, 18, 238, 199, 240, + 110, 235, 119, 37, 20, 12, 240, 18, 238, 199, 240, 110, 233, 87, 37, 20, + 12, 241, 105, 238, 150, 240, 110, 242, 174, 37, 20, 12, 240, 18, 238, + 150, 240, 110, 239, 212, 37, 20, 12, 240, 18, 239, 143, 37, 20, 12, 243, + 89, 242, 209, 37, 20, 12, 243, 89, 239, 109, 37, 20, 12, 243, 89, 239, + 200, 37, 20, 12, 240, 18, 220, 240, 90, 231, 55, 37, 20, 12, 240, 18, + 234, 184, 234, 91, 37, 20, 12, 240, 90, 232, 110, 37, 20, 12, 240, 72, + 232, 110, 37, 20, 12, 240, 72, 231, 55, 37, 20, 12, 240, 72, 248, 146, + 254, 57, 235, 68, 37, 20, 12, 240, 72, 233, 88, 238, 225, 235, 68, 37, + 20, 12, 240, 72, 235, 120, 255, 56, 235, 68, 37, 20, 12, 240, 72, 234, + 86, 249, 128, 235, 68, 37, 20, 12, 240, 90, 248, 146, 254, 57, 235, 68, + 37, 20, 12, 240, 90, 233, 88, 238, 225, 235, 68, 37, 20, 12, 240, 90, + 235, 120, 255, 56, 235, 68, 37, 20, 12, 240, 90, 234, 86, 249, 128, 235, + 68, 37, 20, 12, 240, 179, 239, 43, 37, 20, 12, 240, 179, 239, 250, 37, + 20, 12, 236, 212, 248, 146, 241, 242, 37, 20, 12, 236, 212, 248, 146, + 239, 133, 37, 20, 12, 236, 212, 240, 73, 37, 20, 12, 236, 212, 237, 47, + 37, 20, 12, 236, 186, 237, 47, 37, 20, 12, 236, 186, 238, 155, 237, 7, + 37, 20, 12, 236, 186, 238, 155, 235, 154, 37, 20, 12, 236, 186, 238, 155, + 233, 108, 37, 20, 12, 236, 186, 238, 250, 37, 20, 12, 236, 186, 240, 128, + 237, 7, 37, 20, 12, 236, 186, 240, 128, 235, 154, 37, 20, 12, 236, 186, + 240, 128, 233, 108, 37, 20, 12, 237, 108, 254, 167, 37, 20, 12, 235, 203, + 254, 10, 37, 20, 12, 238, 152, 37, 20, 12, 238, 90, 253, 129, 37, 20, 12, + 238, 90, 249, 196, 37, 20, 12, 238, 90, 253, 139, 37, 20, 12, 238, 90, + 253, 201, 37, 20, 12, 238, 90, 253, 172, 37, 20, 12, 238, 90, 253, 222, + 37, 20, 12, 238, 90, 253, 166, 37, 20, 12, 235, 90, 253, 238, 243, 225, + 37, 20, 12, 238, 118, 253, 238, 243, 225, 37, 20, 12, 235, 90, 253, 238, + 243, 20, 37, 20, 12, 238, 118, 253, 238, 243, 20, 37, 20, 12, 240, 194, + 243, 20, 37, 20, 12, 240, 98, 253, 238, 243, 20, 20, 12, 240, 12, 236, + 194, 20, 12, 45, 236, 194, 20, 12, 30, 236, 194, 20, 12, 238, 75, 30, + 236, 194, 20, 12, 240, 55, 236, 194, 20, 12, 242, 215, 236, 194, 20, 12, + 40, 240, 64, 52, 20, 12, 38, 240, 64, 52, 20, 12, 240, 64, 243, 5, 20, + 12, 253, 199, 240, 219, 20, 12, 255, 70, 244, 242, 20, 12, 240, 219, 20, + 12, 245, 25, 20, 12, 236, 237, 236, 21, 20, 12, 236, 237, 236, 22, 20, + 12, 236, 237, 236, 23, 20, 12, 237, 10, 20, 12, 239, 69, 46, 20, 12, 241, + 37, 69, 20, 12, 237, 82, 20, 12, 241, 35, 20, 12, 104, 20, 12, 237, 225, + 240, 89, 20, 12, 238, 35, 240, 89, 20, 12, 235, 34, 240, 89, 20, 12, 236, + 25, 240, 89, 20, 12, 236, 24, 240, 89, 20, 12, 238, 8, 240, 89, 20, 12, + 235, 2, 234, 55, 20, 12, 233, 204, 234, 55, 20, 12, 255, 104, 243, 37, + 20, 12, 255, 104, 248, 148, 240, 82, 243, 51, 20, 12, 255, 104, 248, 148, + 240, 82, 240, 108, 20, 12, 255, 105, 243, 37, 20, 12, 255, 112, 243, 37, + 20, 12, 255, 112, 248, 148, 240, 82, 243, 51, 20, 12, 255, 112, 248, 148, + 240, 82, 240, 108, 20, 12, 249, 57, 239, 26, 20, 12, 249, 57, 239, 27, + 20, 12, 45, 240, 223, 20, 12, 45, 243, 174, 20, 12, 248, 209, 253, 176, + 20, 12, 248, 209, 242, 236, 20, 12, 238, 146, 253, 176, 20, 12, 238, 146, + 242, 236, 20, 12, 243, 74, 253, 176, 20, 12, 243, 74, 242, 236, 20, 12, + 238, 80, 188, 240, 223, 20, 12, 238, 80, 188, 243, 174, 20, 12, 241, 66, + 244, 31, 20, 12, 254, 153, 244, 31, 20, 12, 240, 82, 243, 51, 20, 12, + 240, 82, 240, 108, 20, 12, 232, 107, 243, 51, 20, 12, 232, 107, 240, 108, + 20, 12, 246, 95, 242, 239, 20, 12, 244, 51, 242, 239, 20, 12, 137, 242, + 239, 20, 12, 238, 80, 242, 239, 20, 12, 240, 62, 242, 239, 20, 12, 235, + 108, 242, 239, 20, 12, 231, 112, 242, 239, 20, 12, 232, 109, 242, 239, + 20, 12, 253, 125, 238, 92, 231, 113, 242, 239, 20, 12, 255, 113, 235, 78, + 20, 12, 248, 49, 235, 78, 20, 12, 218, 255, 113, 235, 78, 20, 12, 31, + 236, 153, 240, 39, 20, 12, 31, 236, 153, 240, 0, 20, 12, 236, 152, 236, + 153, 88, 240, 39, 20, 12, 236, 152, 236, 153, 88, 240, 0, 20, 12, 236, + 152, 236, 153, 40, 240, 39, 20, 12, 236, 152, 236, 153, 40, 240, 0, 20, + 12, 236, 152, 236, 153, 38, 240, 39, 20, 12, 236, 152, 236, 153, 38, 240, + 0, 20, 12, 236, 152, 236, 153, 92, 240, 39, 20, 12, 236, 152, 236, 153, + 92, 240, 0, 20, 12, 236, 152, 236, 153, 88, 38, 240, 39, 20, 12, 236, + 152, 236, 153, 88, 38, 240, 0, 20, 12, 249, 113, 236, 153, 240, 39, 20, + 12, 249, 113, 236, 153, 240, 0, 20, 12, 231, 57, 236, 153, 92, 240, 39, + 20, 12, 231, 57, 236, 153, 92, 240, 0, 20, 12, 233, 56, 235, 78, 20, 12, + 253, 16, 235, 78, 20, 12, 236, 153, 240, 0, 20, 12, 252, 40, 235, 78, 20, + 12, 238, 172, 236, 153, 240, 39, 20, 12, 238, 172, 236, 153, 240, 0, 20, + 12, 239, 255, 20, 12, 244, 51, 243, 9, 20, 12, 137, 243, 9, 20, 12, 238, + 80, 243, 9, 20, 12, 240, 62, 243, 9, 20, 12, 235, 108, 243, 9, 20, 12, + 231, 112, 243, 9, 20, 12, 232, 109, 243, 9, 20, 12, 253, 125, 238, 92, + 231, 113, 243, 9, 20, 12, 50, 243, 46, 20, 12, 50, 233, 38, 243, 46, 20, + 12, 50, 234, 83, 20, 12, 50, 234, 84, 20, 12, 50, 234, 85, 20, 12, 236, + 225, 234, 83, 20, 12, 236, 225, 234, 84, 20, 12, 236, 225, 234, 85, 20, + 12, 50, 232, 117, 248, 40, 20, 12, 50, 239, 71, 20, 12, 50, 239, 72, 20, + 12, 50, 239, 73, 20, 12, 50, 239, 74, 20, 12, 50, 239, 75, 20, 12, 243, + 24, 243, 146, 20, 12, 253, 165, 243, 146, 20, 12, 243, 24, 248, 139, 20, + 12, 253, 165, 248, 139, 20, 12, 243, 24, 244, 19, 20, 12, 253, 165, 244, + 19, 20, 12, 243, 24, 238, 207, 20, 12, 253, 165, 238, 207, 20, 12, 50, + 238, 54, 20, 12, 50, 236, 105, 20, 12, 50, 239, 216, 20, 12, 50, 231, 81, + 20, 12, 50, 237, 201, 20, 12, 50, 227, 2, 20, 12, 50, 227, 11, 20, 12, + 50, 241, 221, 20, 12, 234, 46, 253, 176, 20, 12, 234, 46, 242, 236, 20, + 12, 50, 245, 71, 20, 12, 50, 252, 138, 20, 12, 50, 245, 90, 20, 12, 50, + 242, 117, 20, 12, 50, 244, 217, 20, 12, 50, 45, 238, 156, 20, 12, 50, + 240, 3, 238, 156, 20, 12, 232, 201, 20, 12, 239, 208, 20, 12, 255, 17, + 20, 12, 242, 61, 20, 12, 241, 237, 20, 12, 241, 115, 20, 12, 234, 106, + 20, 12, 232, 127, 20, 12, 243, 186, 249, 122, 240, 37, 20, 12, 243, 186, + 249, 122, 255, 51, 240, 37, 20, 12, 254, 250, 20, 12, 244, 41, 20, 12, + 236, 145, 244, 41, 20, 12, 249, 188, 240, 37, 20, 12, 249, 188, 253, 176, + 20, 12, 236, 172, 236, 111, 20, 12, 236, 172, 236, 112, 20, 12, 236, 172, + 236, 113, 20, 12, 236, 172, 236, 114, 20, 12, 236, 172, 236, 115, 20, 12, + 236, 172, 236, 116, 20, 12, 236, 172, 236, 117, 20, 12, 236, 172, 236, + 118, 20, 12, 236, 172, 236, 119, 20, 12, 236, 172, 235, 3, 20, 12, 236, + 172, 235, 4, 20, 12, 232, 168, 20, 12, 232, 186, 20, 12, 253, 165, 147, + 239, 204, 20, 12, 240, 112, 240, 37, 20, 12, 50, 92, 248, 198, 20, 12, + 50, 88, 248, 198, 20, 12, 50, 236, 34, 20, 12, 50, 252, 182, 234, 235, + 20, 12, 243, 114, 69, 20, 12, 243, 114, 88, 69, 20, 12, 137, 243, 114, + 69, 20, 12, 235, 125, 253, 176, 20, 12, 235, 125, 242, 236, 20, 12, 2, + 232, 165, 20, 12, 245, 34, 20, 12, 250, 181, 249, 26, 20, 12, 239, 131, + 20, 12, 241, 219, 20, 12, 239, 13, 20, 12, 234, 40, 240, 39, 20, 12, 234, + 40, 240, 0, 20, 12, 239, 138, 20, 12, 240, 200, 240, 0, 20, 12, 234, 41, + 240, 39, 20, 12, 234, 41, 240, 0, 20, 12, 249, 65, 240, 39, 20, 12, 249, + 65, 240, 0, 20, 12, 243, 217, 237, 29, 242, 239, 20, 12, 243, 217, 234, + 29, 242, 239, 20, 12, 241, 38, 242, 239, 20, 12, 234, 40, 242, 239, 20, + 12, 240, 200, 242, 239, 20, 12, 234, 41, 242, 239, 20, 12, 240, 65, 235, + 106, 253, 231, 234, 13, 235, 134, 20, 12, 240, 65, 235, 106, 253, 231, + 234, 13, 233, 85, 20, 12, 240, 65, 235, 106, 253, 231, 234, 13, 237, 29, + 231, 102, 20, 12, 240, 65, 233, 62, 253, 231, 234, 13, 235, 134, 20, 12, + 240, 65, 233, 62, 253, 231, 234, 13, 233, 85, 20, 12, 240, 65, 233, 62, + 253, 231, 234, 13, 234, 29, 231, 102, 20, 12, 240, 65, 233, 62, 253, 231, + 234, 13, 234, 29, 231, 126, 20, 12, 240, 65, 233, 62, 253, 231, 234, 13, + 234, 29, 231, 127, 20, 12, 241, 69, 20, 12, 235, 126, 255, 105, 243, 37, + 20, 12, 235, 126, 255, 112, 243, 37, 20, 12, 31, 217, 20, 12, 242, 178, + 20, 12, 237, 238, 20, 12, 239, 28, 20, 12, 234, 251, 20, 12, 235, 190, + 20, 12, 236, 129, 20, 12, 234, 237, 20, 12, 236, 77, 238, 185, 20, 12, + 236, 97, 238, 185, 20, 12, 238, 31, 234, 249, 20, 12, 254, 223, 233, 248, + 17, 242, 222, 126, 235, 146, 17, 242, 222, 126, 235, 147, 17, 242, 222, + 126, 236, 122, 17, 242, 222, 126, 235, 148, 17, 242, 222, 126, 235, 149, + 17, 242, 222, 126, 236, 123, 17, 242, 222, 126, 235, 150, 17, 242, 222, + 126, 235, 151, 17, 242, 222, 126, 236, 124, 17, 242, 222, 126, 235, 7, + 17, 242, 222, 126, 234, 67, 17, 242, 222, 126, 234, 68, 17, 242, 222, + 126, 234, 69, 17, 242, 222, 126, 234, 70, 17, 242, 222, 126, 235, 8, 17, + 242, 222, 126, 235, 9, 17, 242, 222, 126, 234, 71, 17, 242, 222, 126, + 234, 72, 17, 242, 222, 126, 234, 73, 17, 242, 222, 126, 235, 10, 17, 242, + 222, 126, 235, 11, 17, 242, 222, 126, 235, 12, 17, 242, 222, 126, 234, + 74, 17, 242, 222, 126, 234, 75, 17, 242, 222, 126, 234, 76, 17, 242, 222, + 126, 234, 77, 17, 242, 222, 126, 234, 78, 17, 242, 222, 126, 234, 79, 17, + 242, 222, 126, 234, 80, 17, 232, 69, 126, 235, 146, 17, 232, 69, 126, + 235, 147, 17, 232, 69, 126, 235, 148, 17, 232, 69, 126, 235, 149, 17, + 232, 69, 126, 235, 150, 17, 232, 69, 126, 235, 151, 17, 232, 69, 126, + 234, 67, 17, 232, 69, 126, 234, 68, 17, 232, 69, 126, 234, 69, 17, 232, + 69, 126, 234, 70, 17, 232, 69, 126, 234, 71, 17, 232, 69, 126, 234, 72, + 17, 232, 69, 126, 234, 73, 17, 232, 69, 126, 234, 74, 17, 232, 69, 126, + 234, 75, 17, 232, 69, 126, 235, 13, 17, 232, 69, 126, 235, 14, 17, 232, + 69, 126, 235, 15, 17, 232, 69, 126, 235, 16, 17, 232, 69, 126, 235, 17, + 17, 232, 69, 126, 235, 18, 17, 232, 69, 126, 235, 19, 17, 232, 69, 126, + 235, 20, 17, 232, 69, 126, 235, 21, 17, 232, 69, 126, 235, 22, 17, 232, + 69, 126, 235, 23, 17, 232, 69, 126, 235, 24, 17, 232, 69, 126, 235, 25, + 17, 232, 69, 126, 235, 26, 17, 232, 69, 126, 235, 27, 17, 232, 69, 126, + 235, 28, 17, 232, 69, 126, 235, 29, 17, 232, 69, 126, 234, 76, 17, 232, + 69, 126, 234, 77, 17, 232, 69, 126, 234, 78, 17, 232, 69, 126, 234, 79, + 17, 232, 69, 126, 234, 80, 50, 17, 20, 237, 49, 50, 17, 20, 234, 82, 50, + 17, 20, 234, 62, 17, 20, 239, 116, 236, 184, 28, 240, 49, 240, 56, 28, + 237, 174, 240, 49, 240, 56, 28, 245, 203, 240, 49, 240, 56, 28, 238, 181, + 238, 139, 240, 56, 28, 238, 181, 241, 169, 240, 56, 28, 240, 49, 120, 28, + 238, 129, 120, 28, 248, 37, 238, 51, 120, 28, 241, 244, 120, 28, 237, 72, + 120, 28, 238, 193, 240, 147, 120, 28, 232, 122, 120, 28, 238, 252, 120, + 28, 233, 73, 120, 28, 235, 182, 248, 235, 120, 28, 231, 123, 128, 233, + 136, 120, 28, 233, 137, 120, 28, 232, 67, 120, 28, 235, 127, 120, 28, + 232, 192, 120, 28, 240, 215, 120, 28, 237, 91, 120, 28, 238, 189, 244, + 188, 120, 28, 237, 51, 120, 28, 234, 54, 120, 28, 237, 55, 120, 28, 237, + 250, 120, 28, 233, 229, 120, 28, 245, 79, 120, 28, 251, 125, 120, 28, + 233, 127, 120, 28, 234, 185, 120, 28, 239, 54, 120, 28, 239, 21, 120, 28, + 231, 122, 120, 28, 16, 233, 230, 120, 28, 237, 230, 120, 28, 239, 115, + 120, 28, 234, 101, 120, 28, 237, 189, 120, 28, 234, 193, 120, 28, 236, + 109, 120, 28, 239, 169, 120, 28, 236, 28, 120, 28, 234, 248, 120, 28, + 254, 190, 128, 241, 246, 120, 28, 235, 141, 120, 28, 245, 125, 153, 243, + 224, 120, 28, 233, 196, 120, 28, 242, 135, 120, 28, 234, 197, 120, 28, + 232, 164, 120, 28, 237, 232, 120, 28, 239, 174, 120, 28, 239, 76, 120, + 28, 238, 40, 128, 238, 46, 120, 28, 234, 103, 120, 28, 237, 23, 120, 28, + 236, 16, 120, 28, 242, 171, 120, 28, 231, 125, 120, 28, 240, 23, 240, + 201, 120, 28, 232, 167, 120, 28, 235, 124, 253, 247, 120, 28, 237, 204, + 120, 28, 231, 115, 120, 28, 231, 65, 120, 28, 241, 88, 120, 28, 240, 252, + 120, 28, 238, 6, 120, 28, 241, 180, 120, 28, 234, 109, 120, 28, 234, 108, + 120, 28, 237, 109, 120, 28, 233, 199, 120, 28, 234, 253, 120, 28, 236, + 107, 120, 28, 236, 33, 120, 28, 233, 69, 120, 28, 237, 88, 120, 28, 237, + 154, 120, 28, 232, 114, 120, 28, 233, 125, 120, 28, 255, 34, 253, 145, + 242, 177, 120, 28, 231, 124, 120, 28, 234, 217, 120, 28, 234, 191, 10, + 16, 5, 67, 10, 16, 5, 217, 10, 16, 5, 255, 18, 10, 16, 5, 209, 10, 16, 5, + 72, 10, 16, 5, 255, 19, 10, 16, 5, 210, 10, 16, 5, 192, 10, 16, 5, 71, + 10, 16, 5, 221, 10, 16, 5, 255, 15, 10, 16, 5, 162, 10, 16, 5, 173, 10, + 16, 5, 197, 10, 16, 5, 73, 10, 16, 5, 223, 10, 16, 5, 255, 20, 10, 16, 5, + 144, 10, 16, 5, 193, 10, 16, 5, 214, 10, 16, 5, 79, 10, 16, 5, 179, 10, + 16, 5, 255, 16, 10, 16, 5, 206, 10, 16, 5, 255, 14, 10, 16, 5, 255, 17, + 10, 16, 3, 67, 10, 16, 3, 217, 10, 16, 3, 255, 18, 10, 16, 3, 209, 10, + 16, 3, 72, 10, 16, 3, 255, 19, 10, 16, 3, 210, 10, 16, 3, 192, 10, 16, 3, + 71, 10, 16, 3, 221, 10, 16, 3, 255, 15, 10, 16, 3, 162, 10, 16, 3, 173, + 10, 16, 3, 197, 10, 16, 3, 73, 10, 16, 3, 223, 10, 16, 3, 255, 20, 10, + 16, 3, 144, 10, 16, 3, 193, 10, 16, 3, 214, 10, 16, 3, 79, 10, 16, 3, + 179, 10, 16, 3, 255, 16, 10, 16, 3, 206, 10, 16, 3, 255, 14, 10, 16, 3, + 255, 17, 10, 24, 5, 67, 10, 24, 5, 217, 10, 24, 5, 255, 18, 10, 24, 5, + 209, 10, 24, 5, 72, 10, 24, 5, 255, 19, 10, 24, 5, 210, 10, 24, 5, 192, + 10, 24, 5, 71, 10, 24, 5, 221, 10, 24, 5, 255, 15, 10, 24, 5, 162, 10, + 24, 5, 173, 10, 24, 5, 197, 10, 24, 5, 73, 10, 24, 5, 223, 10, 24, 5, + 255, 20, 10, 24, 5, 144, 10, 24, 5, 193, 10, 24, 5, 214, 10, 24, 5, 79, + 10, 24, 5, 179, 10, 24, 5, 255, 16, 10, 24, 5, 206, 10, 24, 5, 255, 14, + 10, 24, 5, 255, 17, 10, 24, 3, 67, 10, 24, 3, 217, 10, 24, 3, 255, 18, + 10, 24, 3, 209, 10, 24, 3, 72, 10, 24, 3, 255, 19, 10, 24, 3, 210, 10, + 24, 3, 71, 10, 24, 3, 221, 10, 24, 3, 255, 15, 10, 24, 3, 162, 10, 24, 3, + 173, 10, 24, 3, 197, 10, 24, 3, 73, 10, 24, 3, 223, 10, 24, 3, 255, 20, + 10, 24, 3, 144, 10, 24, 3, 193, 10, 24, 3, 214, 10, 24, 3, 79, 10, 24, 3, + 179, 10, 24, 3, 255, 16, 10, 24, 3, 206, 10, 24, 3, 255, 14, 10, 24, 3, + 255, 17, 10, 16, 24, 5, 67, 10, 16, 24, 5, 217, 10, 16, 24, 5, 255, 18, + 10, 16, 24, 5, 209, 10, 16, 24, 5, 72, 10, 16, 24, 5, 255, 19, 10, 16, + 24, 5, 210, 10, 16, 24, 5, 192, 10, 16, 24, 5, 71, 10, 16, 24, 5, 221, + 10, 16, 24, 5, 255, 15, 10, 16, 24, 5, 162, 10, 16, 24, 5, 173, 10, 16, + 24, 5, 197, 10, 16, 24, 5, 73, 10, 16, 24, 5, 223, 10, 16, 24, 5, 255, + 20, 10, 16, 24, 5, 144, 10, 16, 24, 5, 193, 10, 16, 24, 5, 214, 10, 16, + 24, 5, 79, 10, 16, 24, 5, 179, 10, 16, 24, 5, 255, 16, 10, 16, 24, 5, + 206, 10, 16, 24, 5, 255, 14, 10, 16, 24, 5, 255, 17, 10, 16, 24, 3, 67, + 10, 16, 24, 3, 217, 10, 16, 24, 3, 255, 18, 10, 16, 24, 3, 209, 10, 16, + 24, 3, 72, 10, 16, 24, 3, 255, 19, 10, 16, 24, 3, 210, 10, 16, 24, 3, + 192, 10, 16, 24, 3, 71, 10, 16, 24, 3, 221, 10, 16, 24, 3, 255, 15, 10, + 16, 24, 3, 162, 10, 16, 24, 3, 173, 10, 16, 24, 3, 197, 10, 16, 24, 3, + 73, 10, 16, 24, 3, 223, 10, 16, 24, 3, 255, 20, 10, 16, 24, 3, 144, 10, + 16, 24, 3, 193, 10, 16, 24, 3, 214, 10, 16, 24, 3, 79, 10, 16, 24, 3, + 179, 10, 16, 24, 3, 255, 16, 10, 16, 24, 3, 206, 10, 16, 24, 3, 255, 14, + 10, 16, 24, 3, 255, 17, 10, 84, 5, 67, 10, 84, 5, 255, 18, 10, 84, 5, + 209, 10, 84, 5, 210, 10, 84, 5, 221, 10, 84, 5, 255, 15, 10, 84, 5, 197, + 10, 84, 5, 73, 10, 84, 5, 223, 10, 84, 5, 255, 20, 10, 84, 5, 193, 10, + 84, 5, 214, 10, 84, 5, 79, 10, 84, 5, 179, 10, 84, 5, 255, 16, 10, 84, 5, + 206, 10, 84, 5, 255, 14, 10, 84, 5, 255, 17, 10, 84, 3, 67, 10, 84, 3, + 217, 10, 84, 3, 255, 18, 10, 84, 3, 209, 10, 84, 3, 255, 19, 10, 84, 3, + 192, 10, 84, 3, 71, 10, 84, 3, 221, 10, 84, 3, 255, 15, 10, 84, 3, 162, + 10, 84, 3, 173, 10, 84, 3, 197, 10, 84, 3, 223, 10, 84, 3, 255, 20, 10, + 84, 3, 144, 10, 84, 3, 193, 10, 84, 3, 214, 10, 84, 3, 79, 10, 84, 3, + 179, 10, 84, 3, 255, 16, 10, 84, 3, 206, 10, 84, 3, 255, 14, 10, 84, 3, + 255, 17, 10, 16, 84, 5, 67, 10, 16, 84, 5, 217, 10, 16, 84, 5, 255, 18, + 10, 16, 84, 5, 209, 10, 16, 84, 5, 72, 10, 16, 84, 5, 255, 19, 10, 16, + 84, 5, 210, 10, 16, 84, 5, 192, 10, 16, 84, 5, 71, 10, 16, 84, 5, 221, + 10, 16, 84, 5, 255, 15, 10, 16, 84, 5, 162, 10, 16, 84, 5, 173, 10, 16, + 84, 5, 197, 10, 16, 84, 5, 73, 10, 16, 84, 5, 223, 10, 16, 84, 5, 255, + 20, 10, 16, 84, 5, 144, 10, 16, 84, 5, 193, 10, 16, 84, 5, 214, 10, 16, + 84, 5, 79, 10, 16, 84, 5, 179, 10, 16, 84, 5, 255, 16, 10, 16, 84, 5, + 206, 10, 16, 84, 5, 255, 14, 10, 16, 84, 5, 255, 17, 10, 16, 84, 3, 67, + 10, 16, 84, 3, 217, 10, 16, 84, 3, 255, 18, 10, 16, 84, 3, 209, 10, 16, + 84, 3, 72, 10, 16, 84, 3, 255, 19, 10, 16, 84, 3, 210, 10, 16, 84, 3, + 192, 10, 16, 84, 3, 71, 10, 16, 84, 3, 221, 10, 16, 84, 3, 255, 15, 10, + 16, 84, 3, 162, 10, 16, 84, 3, 173, 10, 16, 84, 3, 197, 10, 16, 84, 3, + 73, 10, 16, 84, 3, 223, 10, 16, 84, 3, 255, 20, 10, 16, 84, 3, 144, 10, + 16, 84, 3, 193, 10, 16, 84, 3, 214, 10, 16, 84, 3, 79, 10, 16, 84, 3, + 179, 10, 16, 84, 3, 255, 16, 10, 16, 84, 3, 206, 10, 16, 84, 3, 255, 14, + 10, 16, 84, 3, 255, 17, 10, 93, 5, 67, 10, 93, 5, 217, 10, 93, 5, 209, + 10, 93, 5, 72, 10, 93, 5, 255, 19, 10, 93, 5, 210, 10, 93, 5, 221, 10, + 93, 5, 255, 15, 10, 93, 5, 162, 10, 93, 5, 173, 10, 93, 5, 197, 10, 93, + 5, 73, 10, 93, 5, 223, 10, 93, 5, 255, 20, 10, 93, 5, 193, 10, 93, 5, + 214, 10, 93, 5, 79, 10, 93, 5, 179, 10, 93, 5, 255, 16, 10, 93, 5, 206, + 10, 93, 5, 255, 14, 10, 93, 3, 67, 10, 93, 3, 217, 10, 93, 3, 255, 18, + 10, 93, 3, 209, 10, 93, 3, 72, 10, 93, 3, 255, 19, 10, 93, 3, 210, 10, + 93, 3, 192, 10, 93, 3, 71, 10, 93, 3, 221, 10, 93, 3, 255, 15, 10, 93, 3, + 162, 10, 93, 3, 173, 10, 93, 3, 197, 10, 93, 3, 73, 10, 93, 3, 223, 10, + 93, 3, 255, 20, 10, 93, 3, 144, 10, 93, 3, 193, 10, 93, 3, 214, 10, 93, + 3, 79, 10, 93, 3, 179, 10, 93, 3, 255, 16, 10, 93, 3, 206, 10, 93, 3, + 255, 14, 10, 93, 3, 255, 17, 10, 138, 5, 67, 10, 138, 5, 217, 10, 138, 5, + 209, 10, 138, 5, 72, 10, 138, 5, 255, 19, 10, 138, 5, 210, 10, 138, 5, + 71, 10, 138, 5, 221, 10, 138, 5, 255, 15, 10, 138, 5, 162, 10, 138, 5, + 173, 10, 138, 5, 73, 10, 138, 5, 193, 10, 138, 5, 214, 10, 138, 5, 79, + 10, 138, 5, 179, 10, 138, 5, 255, 16, 10, 138, 5, 206, 10, 138, 5, 255, + 14, 10, 138, 3, 67, 10, 138, 3, 217, 10, 138, 3, 255, 18, 10, 138, 3, + 209, 10, 138, 3, 72, 10, 138, 3, 255, 19, 10, 138, 3, 210, 10, 138, 3, + 192, 10, 138, 3, 71, 10, 138, 3, 221, 10, 138, 3, 255, 15, 10, 138, 3, + 162, 10, 138, 3, 173, 10, 138, 3, 197, 10, 138, 3, 73, 10, 138, 3, 223, + 10, 138, 3, 255, 20, 10, 138, 3, 144, 10, 138, 3, 193, 10, 138, 3, 214, + 10, 138, 3, 79, 10, 138, 3, 179, 10, 138, 3, 255, 16, 10, 138, 3, 206, + 10, 138, 3, 255, 14, 10, 138, 3, 255, 17, 10, 16, 93, 5, 67, 10, 16, 93, + 5, 217, 10, 16, 93, 5, 255, 18, 10, 16, 93, 5, 209, 10, 16, 93, 5, 72, + 10, 16, 93, 5, 255, 19, 10, 16, 93, 5, 210, 10, 16, 93, 5, 192, 10, 16, + 93, 5, 71, 10, 16, 93, 5, 221, 10, 16, 93, 5, 255, 15, 10, 16, 93, 5, + 162, 10, 16, 93, 5, 173, 10, 16, 93, 5, 197, 10, 16, 93, 5, 73, 10, 16, + 93, 5, 223, 10, 16, 93, 5, 255, 20, 10, 16, 93, 5, 144, 10, 16, 93, 5, + 193, 10, 16, 93, 5, 214, 10, 16, 93, 5, 79, 10, 16, 93, 5, 179, 10, 16, + 93, 5, 255, 16, 10, 16, 93, 5, 206, 10, 16, 93, 5, 255, 14, 10, 16, 93, + 5, 255, 17, 10, 16, 93, 3, 67, 10, 16, 93, 3, 217, 10, 16, 93, 3, 255, + 18, 10, 16, 93, 3, 209, 10, 16, 93, 3, 72, 10, 16, 93, 3, 255, 19, 10, + 16, 93, 3, 210, 10, 16, 93, 3, 192, 10, 16, 93, 3, 71, 10, 16, 93, 3, + 221, 10, 16, 93, 3, 255, 15, 10, 16, 93, 3, 162, 10, 16, 93, 3, 173, 10, + 16, 93, 3, 197, 10, 16, 93, 3, 73, 10, 16, 93, 3, 223, 10, 16, 93, 3, + 255, 20, 10, 16, 93, 3, 144, 10, 16, 93, 3, 193, 10, 16, 93, 3, 214, 10, + 16, 93, 3, 79, 10, 16, 93, 3, 179, 10, 16, 93, 3, 255, 16, 10, 16, 93, 3, + 206, 10, 16, 93, 3, 255, 14, 10, 16, 93, 3, 255, 17, 10, 27, 5, 67, 10, + 27, 5, 217, 10, 27, 5, 255, 18, 10, 27, 5, 209, 10, 27, 5, 72, 10, 27, 5, + 255, 19, 10, 27, 5, 210, 10, 27, 5, 192, 10, 27, 5, 71, 10, 27, 5, 221, + 10, 27, 5, 255, 15, 10, 27, 5, 162, 10, 27, 5, 173, 10, 27, 5, 197, 10, + 27, 5, 73, 10, 27, 5, 223, 10, 27, 5, 255, 20, 10, 27, 5, 144, 10, 27, 5, + 193, 10, 27, 5, 214, 10, 27, 5, 79, 10, 27, 5, 179, 10, 27, 5, 255, 16, + 10, 27, 5, 206, 10, 27, 5, 255, 14, 10, 27, 5, 255, 17, 10, 27, 3, 67, + 10, 27, 3, 217, 10, 27, 3, 255, 18, 10, 27, 3, 209, 10, 27, 3, 72, 10, + 27, 3, 255, 19, 10, 27, 3, 210, 10, 27, 3, 192, 10, 27, 3, 71, 10, 27, 3, + 221, 10, 27, 3, 255, 15, 10, 27, 3, 162, 10, 27, 3, 173, 10, 27, 3, 197, + 10, 27, 3, 73, 10, 27, 3, 223, 10, 27, 3, 255, 20, 10, 27, 3, 144, 10, + 27, 3, 193, 10, 27, 3, 214, 10, 27, 3, 79, 10, 27, 3, 179, 10, 27, 3, + 255, 16, 10, 27, 3, 206, 10, 27, 3, 255, 14, 10, 27, 3, 255, 17, 10, 27, + 16, 5, 67, 10, 27, 16, 5, 217, 10, 27, 16, 5, 255, 18, 10, 27, 16, 5, + 209, 10, 27, 16, 5, 72, 10, 27, 16, 5, 255, 19, 10, 27, 16, 5, 210, 10, + 27, 16, 5, 192, 10, 27, 16, 5, 71, 10, 27, 16, 5, 221, 10, 27, 16, 5, + 255, 15, 10, 27, 16, 5, 162, 10, 27, 16, 5, 173, 10, 27, 16, 5, 197, 10, + 27, 16, 5, 73, 10, 27, 16, 5, 223, 10, 27, 16, 5, 255, 20, 10, 27, 16, 5, + 144, 10, 27, 16, 5, 193, 10, 27, 16, 5, 214, 10, 27, 16, 5, 79, 10, 27, + 16, 5, 179, 10, 27, 16, 5, 255, 16, 10, 27, 16, 5, 206, 10, 27, 16, 5, + 255, 14, 10, 27, 16, 5, 255, 17, 10, 27, 16, 3, 67, 10, 27, 16, 3, 217, + 10, 27, 16, 3, 255, 18, 10, 27, 16, 3, 209, 10, 27, 16, 3, 72, 10, 27, + 16, 3, 255, 19, 10, 27, 16, 3, 210, 10, 27, 16, 3, 192, 10, 27, 16, 3, + 71, 10, 27, 16, 3, 221, 10, 27, 16, 3, 255, 15, 10, 27, 16, 3, 162, 10, + 27, 16, 3, 173, 10, 27, 16, 3, 197, 10, 27, 16, 3, 73, 10, 27, 16, 3, + 223, 10, 27, 16, 3, 255, 20, 10, 27, 16, 3, 144, 10, 27, 16, 3, 193, 10, + 27, 16, 3, 214, 10, 27, 16, 3, 79, 10, 27, 16, 3, 179, 10, 27, 16, 3, + 255, 16, 10, 27, 16, 3, 206, 10, 27, 16, 3, 255, 14, 10, 27, 16, 3, 255, + 17, 10, 27, 24, 5, 67, 10, 27, 24, 5, 217, 10, 27, 24, 5, 255, 18, 10, + 27, 24, 5, 209, 10, 27, 24, 5, 72, 10, 27, 24, 5, 255, 19, 10, 27, 24, 5, + 210, 10, 27, 24, 5, 192, 10, 27, 24, 5, 71, 10, 27, 24, 5, 221, 10, 27, + 24, 5, 255, 15, 10, 27, 24, 5, 162, 10, 27, 24, 5, 173, 10, 27, 24, 5, + 197, 10, 27, 24, 5, 73, 10, 27, 24, 5, 223, 10, 27, 24, 5, 255, 20, 10, + 27, 24, 5, 144, 10, 27, 24, 5, 193, 10, 27, 24, 5, 214, 10, 27, 24, 5, + 79, 10, 27, 24, 5, 179, 10, 27, 24, 5, 255, 16, 10, 27, 24, 5, 206, 10, + 27, 24, 5, 255, 14, 10, 27, 24, 5, 255, 17, 10, 27, 24, 3, 67, 10, 27, + 24, 3, 217, 10, 27, 24, 3, 255, 18, 10, 27, 24, 3, 209, 10, 27, 24, 3, + 72, 10, 27, 24, 3, 255, 19, 10, 27, 24, 3, 210, 10, 27, 24, 3, 192, 10, + 27, 24, 3, 71, 10, 27, 24, 3, 221, 10, 27, 24, 3, 255, 15, 10, 27, 24, 3, + 162, 10, 27, 24, 3, 173, 10, 27, 24, 3, 197, 10, 27, 24, 3, 73, 10, 27, + 24, 3, 223, 10, 27, 24, 3, 255, 20, 10, 27, 24, 3, 144, 10, 27, 24, 3, + 193, 10, 27, 24, 3, 214, 10, 27, 24, 3, 79, 10, 27, 24, 3, 179, 10, 27, + 24, 3, 255, 16, 10, 27, 24, 3, 206, 10, 27, 24, 3, 255, 14, 10, 27, 24, + 3, 255, 17, 10, 27, 16, 24, 5, 67, 10, 27, 16, 24, 5, 217, 10, 27, 16, + 24, 5, 255, 18, 10, 27, 16, 24, 5, 209, 10, 27, 16, 24, 5, 72, 10, 27, + 16, 24, 5, 255, 19, 10, 27, 16, 24, 5, 210, 10, 27, 16, 24, 5, 192, 10, + 27, 16, 24, 5, 71, 10, 27, 16, 24, 5, 221, 10, 27, 16, 24, 5, 255, 15, + 10, 27, 16, 24, 5, 162, 10, 27, 16, 24, 5, 173, 10, 27, 16, 24, 5, 197, + 10, 27, 16, 24, 5, 73, 10, 27, 16, 24, 5, 223, 10, 27, 16, 24, 5, 255, + 20, 10, 27, 16, 24, 5, 144, 10, 27, 16, 24, 5, 193, 10, 27, 16, 24, 5, + 214, 10, 27, 16, 24, 5, 79, 10, 27, 16, 24, 5, 179, 10, 27, 16, 24, 5, + 255, 16, 10, 27, 16, 24, 5, 206, 10, 27, 16, 24, 5, 255, 14, 10, 27, 16, + 24, 5, 255, 17, 10, 27, 16, 24, 3, 67, 10, 27, 16, 24, 3, 217, 10, 27, + 16, 24, 3, 255, 18, 10, 27, 16, 24, 3, 209, 10, 27, 16, 24, 3, 72, 10, + 27, 16, 24, 3, 255, 19, 10, 27, 16, 24, 3, 210, 10, 27, 16, 24, 3, 192, + 10, 27, 16, 24, 3, 71, 10, 27, 16, 24, 3, 221, 10, 27, 16, 24, 3, 255, + 15, 10, 27, 16, 24, 3, 162, 10, 27, 16, 24, 3, 173, 10, 27, 16, 24, 3, + 197, 10, 27, 16, 24, 3, 73, 10, 27, 16, 24, 3, 223, 10, 27, 16, 24, 3, + 255, 20, 10, 27, 16, 24, 3, 144, 10, 27, 16, 24, 3, 193, 10, 27, 16, 24, + 3, 214, 10, 27, 16, 24, 3, 79, 10, 27, 16, 24, 3, 179, 10, 27, 16, 24, 3, + 255, 16, 10, 27, 16, 24, 3, 206, 10, 27, 16, 24, 3, 255, 14, 10, 27, 16, + 24, 3, 255, 17, 10, 160, 5, 67, 10, 160, 5, 217, 10, 160, 5, 255, 18, 10, + 160, 5, 209, 10, 160, 5, 72, 10, 160, 5, 255, 19, 10, 160, 5, 210, 10, + 160, 5, 192, 10, 160, 5, 71, 10, 160, 5, 221, 10, 160, 5, 255, 15, 10, + 160, 5, 162, 10, 160, 5, 173, 10, 160, 5, 197, 10, 160, 5, 73, 10, 160, + 5, 223, 10, 160, 5, 255, 20, 10, 160, 5, 144, 10, 160, 5, 193, 10, 160, + 5, 214, 10, 160, 5, 79, 10, 160, 5, 179, 10, 160, 5, 255, 16, 10, 160, 5, + 206, 10, 160, 5, 255, 14, 10, 160, 5, 255, 17, 10, 160, 3, 67, 10, 160, + 3, 217, 10, 160, 3, 255, 18, 10, 160, 3, 209, 10, 160, 3, 72, 10, 160, 3, + 255, 19, 10, 160, 3, 210, 10, 160, 3, 192, 10, 160, 3, 71, 10, 160, 3, + 221, 10, 160, 3, 255, 15, 10, 160, 3, 162, 10, 160, 3, 173, 10, 160, 3, + 197, 10, 160, 3, 73, 10, 160, 3, 223, 10, 160, 3, 255, 20, 10, 160, 3, + 144, 10, 160, 3, 193, 10, 160, 3, 214, 10, 160, 3, 79, 10, 160, 3, 179, + 10, 160, 3, 255, 16, 10, 160, 3, 206, 10, 160, 3, 255, 14, 10, 160, 3, + 255, 17, 10, 24, 3, 238, 70, 71, 10, 24, 3, 238, 70, 221, 10, 16, 5, 240, + 22, 10, 16, 5, 242, 242, 10, 16, 5, 240, 10, 10, 16, 5, 240, 28, 10, 16, + 5, 236, 165, 10, 16, 5, 242, 251, 10, 16, 5, 248, 87, 10, 16, 5, 240, 38, + 10, 16, 5, 242, 237, 10, 16, 5, 240, 41, 10, 16, 5, 240, 33, 10, 16, 5, + 253, 154, 10, 16, 5, 253, 150, 10, 16, 5, 253, 188, 10, 16, 5, 236, 169, + 10, 16, 5, 253, 147, 10, 16, 5, 248, 73, 10, 16, 5, 243, 0, 91, 10, 16, + 5, 240, 21, 10, 16, 5, 248, 85, 10, 16, 5, 236, 160, 10, 16, 5, 248, 68, + 10, 16, 5, 248, 67, 10, 16, 5, 248, 69, 10, 16, 5, 240, 20, 10, 16, 240, + 79, 10, 16, 3, 240, 22, 10, 16, 3, 242, 242, 10, 16, 3, 240, 10, 10, 16, + 3, 240, 28, 10, 16, 3, 236, 165, 10, 16, 3, 242, 251, 10, 16, 3, 248, 87, + 10, 16, 3, 240, 38, 10, 16, 3, 242, 237, 10, 16, 3, 240, 41, 10, 16, 3, + 240, 33, 10, 16, 3, 253, 154, 10, 16, 3, 253, 150, 10, 16, 3, 253, 188, + 10, 16, 3, 236, 169, 10, 16, 3, 253, 147, 10, 16, 3, 248, 73, 10, 16, 3, + 30, 240, 21, 10, 16, 3, 240, 21, 10, 16, 3, 248, 85, 10, 16, 3, 236, 160, + 10, 16, 3, 248, 68, 10, 16, 3, 248, 67, 10, 16, 3, 248, 69, 10, 16, 3, + 240, 20, 10, 16, 238, 100, 231, 90, 10, 16, 238, 57, 91, 10, 16, 243, 0, + 91, 10, 16, 243, 29, 91, 10, 16, 254, 11, 91, 10, 16, 253, 218, 91, 10, + 16, 255, 29, 91, 10, 24, 5, 240, 22, 10, 24, 5, 242, 242, 10, 24, 5, 240, + 10, 10, 24, 5, 240, 28, 10, 24, 5, 236, 165, 10, 24, 5, 242, 251, 10, 24, + 5, 248, 87, 10, 24, 5, 240, 38, 10, 24, 5, 242, 237, 10, 24, 5, 240, 41, + 10, 24, 5, 240, 33, 10, 24, 5, 253, 154, 10, 24, 5, 253, 150, 10, 24, 5, + 253, 188, 10, 24, 5, 236, 169, 10, 24, 5, 253, 147, 10, 24, 5, 248, 73, + 10, 24, 5, 243, 0, 91, 10, 24, 5, 240, 21, 10, 24, 5, 248, 85, 10, 24, 5, + 236, 160, 10, 24, 5, 248, 68, 10, 24, 5, 248, 67, 10, 24, 5, 248, 69, 10, + 24, 5, 240, 20, 10, 24, 240, 79, 10, 24, 3, 240, 22, 10, 24, 3, 242, 242, + 10, 24, 3, 240, 10, 10, 24, 3, 240, 28, 10, 24, 3, 236, 165, 10, 24, 3, + 242, 251, 10, 24, 3, 248, 87, 10, 24, 3, 240, 38, 10, 24, 3, 242, 237, + 10, 24, 3, 240, 41, 10, 24, 3, 240, 33, 10, 24, 3, 253, 154, 10, 24, 3, + 253, 150, 10, 24, 3, 253, 188, 10, 24, 3, 236, 169, 10, 24, 3, 253, 147, + 10, 24, 3, 248, 73, 10, 24, 3, 30, 240, 21, 10, 24, 3, 240, 21, 10, 24, + 3, 248, 85, 10, 24, 3, 236, 160, 10, 24, 3, 248, 68, 10, 24, 3, 248, 67, + 10, 24, 3, 248, 69, 10, 24, 3, 240, 20, 10, 24, 238, 100, 231, 90, 10, + 24, 238, 57, 91, 10, 24, 243, 0, 91, 10, 24, 243, 29, 91, 10, 24, 254, + 11, 91, 10, 24, 253, 218, 91, 10, 24, 255, 29, 91, 10, 16, 24, 5, 240, + 22, 10, 16, 24, 5, 242, 242, 10, 16, 24, 5, 240, 10, 10, 16, 24, 5, 240, + 28, 10, 16, 24, 5, 236, 165, 10, 16, 24, 5, 242, 251, 10, 16, 24, 5, 248, + 87, 10, 16, 24, 5, 240, 38, 10, 16, 24, 5, 242, 237, 10, 16, 24, 5, 240, + 41, 10, 16, 24, 5, 240, 33, 10, 16, 24, 5, 253, 154, 10, 16, 24, 5, 253, + 150, 10, 16, 24, 5, 253, 188, 10, 16, 24, 5, 236, 169, 10, 16, 24, 5, + 253, 147, 10, 16, 24, 5, 248, 73, 10, 16, 24, 5, 243, 0, 91, 10, 16, 24, + 5, 240, 21, 10, 16, 24, 5, 248, 85, 10, 16, 24, 5, 236, 160, 10, 16, 24, + 5, 248, 68, 10, 16, 24, 5, 248, 67, 10, 16, 24, 5, 248, 69, 10, 16, 24, + 5, 240, 20, 10, 16, 24, 240, 79, 10, 16, 24, 3, 240, 22, 10, 16, 24, 3, + 242, 242, 10, 16, 24, 3, 240, 10, 10, 16, 24, 3, 240, 28, 10, 16, 24, 3, + 236, 165, 10, 16, 24, 3, 242, 251, 10, 16, 24, 3, 248, 87, 10, 16, 24, 3, + 240, 38, 10, 16, 24, 3, 242, 237, 10, 16, 24, 3, 240, 41, 10, 16, 24, 3, + 240, 33, 10, 16, 24, 3, 253, 154, 10, 16, 24, 3, 253, 150, 10, 16, 24, 3, + 253, 188, 10, 16, 24, 3, 236, 169, 10, 16, 24, 3, 253, 147, 10, 16, 24, + 3, 248, 73, 10, 16, 24, 3, 30, 240, 21, 10, 16, 24, 3, 240, 21, 10, 16, + 24, 3, 248, 85, 10, 16, 24, 3, 236, 160, 10, 16, 24, 3, 248, 68, 10, 16, + 24, 3, 248, 67, 10, 16, 24, 3, 248, 69, 10, 16, 24, 3, 240, 20, 10, 16, + 24, 238, 100, 231, 90, 10, 16, 24, 238, 57, 91, 10, 16, 24, 243, 0, 91, + 10, 16, 24, 243, 29, 91, 10, 16, 24, 254, 11, 91, 10, 16, 24, 253, 218, + 91, 10, 16, 24, 255, 29, 91, 10, 27, 16, 5, 240, 22, 10, 27, 16, 5, 242, + 242, 10, 27, 16, 5, 240, 10, 10, 27, 16, 5, 240, 28, 10, 27, 16, 5, 236, + 165, 10, 27, 16, 5, 242, 251, 10, 27, 16, 5, 248, 87, 10, 27, 16, 5, 240, + 38, 10, 27, 16, 5, 242, 237, 10, 27, 16, 5, 240, 41, 10, 27, 16, 5, 240, + 33, 10, 27, 16, 5, 253, 154, 10, 27, 16, 5, 253, 150, 10, 27, 16, 5, 253, + 188, 10, 27, 16, 5, 236, 169, 10, 27, 16, 5, 253, 147, 10, 27, 16, 5, + 248, 73, 10, 27, 16, 5, 243, 0, 91, 10, 27, 16, 5, 240, 21, 10, 27, 16, + 5, 248, 85, 10, 27, 16, 5, 236, 160, 10, 27, 16, 5, 248, 68, 10, 27, 16, + 5, 248, 67, 10, 27, 16, 5, 248, 69, 10, 27, 16, 5, 240, 20, 10, 27, 16, + 240, 79, 10, 27, 16, 3, 240, 22, 10, 27, 16, 3, 242, 242, 10, 27, 16, 3, + 240, 10, 10, 27, 16, 3, 240, 28, 10, 27, 16, 3, 236, 165, 10, 27, 16, 3, + 242, 251, 10, 27, 16, 3, 248, 87, 10, 27, 16, 3, 240, 38, 10, 27, 16, 3, + 242, 237, 10, 27, 16, 3, 240, 41, 10, 27, 16, 3, 240, 33, 10, 27, 16, 3, + 253, 154, 10, 27, 16, 3, 253, 150, 10, 27, 16, 3, 253, 188, 10, 27, 16, + 3, 236, 169, 10, 27, 16, 3, 253, 147, 10, 27, 16, 3, 248, 73, 10, 27, 16, + 3, 30, 240, 21, 10, 27, 16, 3, 240, 21, 10, 27, 16, 3, 248, 85, 10, 27, + 16, 3, 236, 160, 10, 27, 16, 3, 248, 68, 10, 27, 16, 3, 248, 67, 10, 27, + 16, 3, 248, 69, 10, 27, 16, 3, 240, 20, 10, 27, 16, 238, 100, 231, 90, + 10, 27, 16, 238, 57, 91, 10, 27, 16, 243, 0, 91, 10, 27, 16, 243, 29, 91, + 10, 27, 16, 254, 11, 91, 10, 27, 16, 253, 218, 91, 10, 27, 16, 255, 29, + 91, 10, 27, 16, 24, 5, 240, 22, 10, 27, 16, 24, 5, 242, 242, 10, 27, 16, + 24, 5, 240, 10, 10, 27, 16, 24, 5, 240, 28, 10, 27, 16, 24, 5, 236, 165, + 10, 27, 16, 24, 5, 242, 251, 10, 27, 16, 24, 5, 248, 87, 10, 27, 16, 24, + 5, 240, 38, 10, 27, 16, 24, 5, 242, 237, 10, 27, 16, 24, 5, 240, 41, 10, + 27, 16, 24, 5, 240, 33, 10, 27, 16, 24, 5, 253, 154, 10, 27, 16, 24, 5, + 253, 150, 10, 27, 16, 24, 5, 253, 188, 10, 27, 16, 24, 5, 236, 169, 10, + 27, 16, 24, 5, 253, 147, 10, 27, 16, 24, 5, 248, 73, 10, 27, 16, 24, 5, + 243, 0, 91, 10, 27, 16, 24, 5, 240, 21, 10, 27, 16, 24, 5, 248, 85, 10, + 27, 16, 24, 5, 236, 160, 10, 27, 16, 24, 5, 248, 68, 10, 27, 16, 24, 5, + 248, 67, 10, 27, 16, 24, 5, 248, 69, 10, 27, 16, 24, 5, 240, 20, 10, 27, + 16, 24, 240, 79, 10, 27, 16, 24, 3, 240, 22, 10, 27, 16, 24, 3, 242, 242, + 10, 27, 16, 24, 3, 240, 10, 10, 27, 16, 24, 3, 240, 28, 10, 27, 16, 24, + 3, 236, 165, 10, 27, 16, 24, 3, 242, 251, 10, 27, 16, 24, 3, 248, 87, 10, + 27, 16, 24, 3, 240, 38, 10, 27, 16, 24, 3, 242, 237, 10, 27, 16, 24, 3, + 240, 41, 10, 27, 16, 24, 3, 240, 33, 10, 27, 16, 24, 3, 253, 154, 10, 27, + 16, 24, 3, 253, 150, 10, 27, 16, 24, 3, 253, 188, 10, 27, 16, 24, 3, 236, + 169, 10, 27, 16, 24, 3, 253, 147, 10, 27, 16, 24, 3, 248, 73, 10, 27, 16, + 24, 3, 30, 240, 21, 10, 27, 16, 24, 3, 240, 21, 10, 27, 16, 24, 3, 248, + 85, 10, 27, 16, 24, 3, 236, 160, 10, 27, 16, 24, 3, 248, 68, 10, 27, 16, + 24, 3, 248, 67, 10, 27, 16, 24, 3, 248, 69, 10, 27, 16, 24, 3, 240, 20, + 10, 27, 16, 24, 238, 100, 231, 90, 10, 27, 16, 24, 238, 57, 91, 10, 27, + 16, 24, 243, 0, 91, 10, 27, 16, 24, 243, 29, 91, 10, 27, 16, 24, 254, 11, + 91, 10, 27, 16, 24, 253, 218, 91, 10, 27, 16, 24, 255, 29, 91, 10, 16, + 26, 242, 217, 10, 16, 26, 127, 10, 16, 26, 111, 10, 16, 26, 166, 10, 16, + 26, 177, 10, 16, 26, 176, 10, 16, 26, 187, 10, 16, 26, 203, 10, 16, 26, + 195, 10, 16, 26, 202, 10, 138, 26, 242, 217, 10, 138, 26, 127, 10, 138, + 26, 111, 10, 138, 26, 166, 10, 138, 26, 177, 10, 138, 26, 176, 10, 138, + 26, 187, 10, 138, 26, 203, 10, 138, 26, 195, 10, 138, 26, 202, 10, 27, + 26, 242, 217, 10, 27, 26, 127, 10, 27, 26, 111, 10, 27, 26, 166, 10, 27, + 26, 177, 10, 27, 26, 176, 10, 27, 26, 187, 10, 27, 26, 203, 10, 27, 26, + 195, 10, 27, 26, 202, 10, 27, 16, 26, 242, 217, 10, 27, 16, 26, 127, 10, + 27, 16, 26, 111, 10, 27, 16, 26, 166, 10, 27, 16, 26, 177, 10, 27, 16, + 26, 176, 10, 27, 16, 26, 187, 10, 27, 16, 26, 203, 10, 27, 16, 26, 195, + 10, 27, 16, 26, 202, 10, 160, 26, 242, 217, 10, 160, 26, 127, 10, 160, + 26, 111, 10, 160, 26, 166, 10, 160, 26, 177, 10, 160, 26, 176, 10, 160, + 26, 187, 10, 160, 26, 203, 10, 160, 26, 195, 10, 160, 26, 202, 7, 9, 227, + 16, 7, 9, 227, 17, 7, 9, 227, 18, 7, 9, 227, 19, 7, 9, 227, 20, 7, 9, + 227, 21, 7, 9, 227, 22, 7, 9, 227, 23, 7, 9, 227, 24, 7, 9, 227, 25, 7, + 9, 227, 26, 7, 9, 227, 27, 7, 9, 227, 28, 7, 9, 227, 29, 7, 9, 227, 30, + 7, 9, 227, 31, 7, 9, 227, 32, 7, 9, 227, 33, 7, 9, 227, 34, 7, 9, 227, + 35, 7, 9, 227, 36, 7, 9, 227, 37, 7, 9, 227, 38, 7, 9, 227, 39, 7, 9, + 227, 40, 7, 9, 227, 41, 7, 9, 227, 42, 7, 9, 227, 43, 7, 9, 227, 44, 7, + 9, 227, 45, 7, 9, 227, 46, 7, 9, 227, 47, 7, 9, 227, 48, 7, 9, 227, 49, + 7, 9, 227, 50, 7, 9, 227, 51, 7, 9, 227, 52, 7, 9, 227, 53, 7, 9, 227, + 54, 7, 9, 227, 55, 7, 9, 227, 56, 7, 9, 227, 57, 7, 9, 227, 58, 7, 9, + 227, 59, 7, 9, 227, 60, 7, 9, 227, 61, 7, 9, 227, 62, 7, 9, 227, 63, 7, + 9, 227, 64, 7, 9, 227, 65, 7, 9, 227, 66, 7, 9, 227, 67, 7, 9, 227, 68, + 7, 9, 227, 69, 7, 9, 227, 70, 7, 9, 227, 71, 7, 9, 227, 72, 7, 9, 227, + 73, 7, 9, 227, 74, 7, 9, 227, 75, 7, 9, 227, 76, 7, 9, 227, 77, 7, 9, + 227, 78, 7, 9, 227, 79, 7, 9, 227, 80, 7, 9, 227, 81, 7, 9, 227, 82, 7, + 9, 227, 83, 7, 9, 227, 84, 7, 9, 227, 85, 7, 9, 227, 86, 7, 9, 227, 87, + 7, 9, 227, 88, 7, 9, 227, 89, 7, 9, 227, 90, 7, 9, 227, 91, 7, 9, 227, + 92, 7, 9, 227, 93, 7, 9, 227, 94, 7, 9, 227, 95, 7, 9, 227, 96, 7, 9, + 227, 97, 7, 9, 227, 98, 7, 9, 227, 99, 7, 9, 227, 100, 7, 9, 227, 101, 7, + 9, 227, 102, 7, 9, 227, 103, 7, 9, 227, 104, 7, 9, 227, 105, 7, 9, 227, + 106, 7, 9, 227, 107, 7, 9, 227, 108, 7, 9, 227, 109, 7, 9, 227, 110, 7, + 9, 227, 111, 7, 9, 227, 112, 7, 9, 227, 113, 7, 9, 227, 114, 7, 9, 227, + 115, 7, 9, 227, 116, 7, 9, 227, 117, 7, 9, 227, 118, 7, 9, 227, 119, 7, + 9, 227, 120, 7, 9, 227, 121, 7, 9, 227, 122, 7, 9, 227, 123, 7, 9, 227, + 124, 7, 9, 227, 125, 7, 9, 227, 126, 7, 9, 227, 127, 7, 9, 227, 128, 7, + 9, 227, 129, 7, 9, 227, 130, 7, 9, 227, 131, 7, 9, 227, 132, 7, 9, 227, + 133, 7, 9, 227, 134, 7, 9, 227, 135, 7, 9, 227, 136, 7, 9, 227, 137, 7, + 9, 227, 138, 7, 9, 227, 139, 7, 9, 227, 140, 7, 9, 227, 141, 7, 9, 227, + 142, 7, 9, 227, 143, 7, 9, 227, 144, 7, 9, 227, 145, 7, 9, 227, 146, 7, + 9, 227, 147, 7, 9, 227, 148, 7, 9, 227, 149, 7, 9, 227, 150, 7, 9, 227, + 151, 7, 9, 227, 152, 7, 9, 227, 153, 7, 9, 227, 154, 7, 9, 227, 155, 7, + 9, 227, 156, 7, 9, 227, 157, 7, 9, 227, 158, 7, 9, 227, 159, 7, 9, 227, + 160, 7, 9, 227, 161, 7, 9, 227, 162, 7, 9, 227, 163, 7, 9, 227, 164, 7, + 9, 227, 165, 7, 9, 227, 166, 7, 9, 227, 167, 7, 9, 227, 168, 7, 9, 227, + 169, 7, 9, 227, 170, 7, 9, 227, 171, 7, 9, 227, 172, 7, 9, 227, 173, 7, + 9, 227, 174, 7, 9, 227, 175, 7, 9, 227, 176, 7, 9, 227, 177, 7, 9, 227, + 178, 7, 9, 227, 179, 7, 9, 227, 180, 7, 9, 227, 181, 7, 9, 227, 182, 7, + 9, 227, 183, 7, 9, 227, 184, 7, 9, 227, 185, 7, 9, 227, 186, 7, 9, 227, + 187, 7, 9, 227, 188, 7, 9, 227, 189, 7, 9, 227, 190, 7, 9, 227, 191, 7, + 9, 227, 192, 7, 9, 227, 193, 7, 9, 227, 194, 7, 9, 227, 195, 7, 9, 227, + 196, 7, 9, 227, 197, 7, 9, 227, 198, 7, 9, 227, 199, 7, 9, 227, 200, 7, + 9, 227, 201, 7, 9, 227, 202, 7, 9, 227, 203, 7, 9, 227, 204, 7, 9, 227, + 205, 7, 9, 227, 206, 7, 9, 227, 207, 7, 9, 227, 208, 7, 9, 227, 209, 7, + 9, 227, 210, 7, 9, 227, 211, 7, 9, 227, 212, 7, 9, 227, 213, 7, 9, 227, + 214, 7, 9, 227, 215, 7, 9, 227, 216, 7, 9, 227, 217, 7, 9, 227, 218, 7, + 9, 227, 219, 7, 9, 227, 220, 7, 9, 227, 221, 7, 9, 227, 222, 7, 9, 227, + 223, 7, 9, 227, 224, 7, 9, 227, 225, 7, 9, 227, 226, 7, 9, 227, 227, 7, + 9, 227, 228, 7, 9, 227, 229, 7, 9, 227, 230, 7, 9, 227, 231, 7, 9, 227, + 232, 7, 9, 227, 233, 7, 9, 227, 234, 7, 9, 227, 235, 7, 9, 227, 236, 7, + 9, 227, 237, 7, 9, 227, 238, 7, 9, 227, 239, 7, 9, 227, 240, 7, 9, 227, + 241, 7, 9, 227, 242, 7, 9, 227, 243, 7, 9, 227, 244, 7, 9, 227, 245, 7, + 9, 227, 246, 7, 9, 227, 247, 7, 9, 227, 248, 7, 9, 227, 249, 7, 9, 227, + 250, 7, 9, 227, 251, 7, 9, 227, 252, 7, 9, 227, 253, 7, 9, 227, 254, 7, + 9, 227, 255, 7, 9, 228, 0, 7, 9, 228, 1, 7, 9, 228, 2, 7, 9, 228, 3, 7, + 9, 228, 4, 7, 9, 228, 5, 7, 9, 228, 6, 7, 9, 228, 7, 7, 9, 228, 8, 7, 9, + 228, 9, 7, 9, 228, 10, 7, 9, 228, 11, 7, 9, 228, 12, 7, 9, 228, 13, 7, 9, + 228, 14, 7, 9, 228, 15, 7, 9, 228, 16, 7, 9, 228, 17, 7, 9, 228, 18, 7, + 9, 228, 19, 7, 9, 228, 20, 7, 9, 228, 21, 7, 9, 228, 22, 7, 9, 228, 23, + 7, 9, 228, 24, 7, 9, 228, 25, 7, 9, 228, 26, 7, 9, 228, 27, 7, 9, 228, + 28, 7, 9, 228, 29, 7, 9, 228, 30, 7, 9, 228, 31, 7, 9, 228, 32, 7, 9, + 228, 33, 7, 9, 228, 34, 7, 9, 228, 35, 7, 9, 228, 36, 7, 9, 228, 37, 7, + 9, 228, 38, 7, 9, 228, 39, 7, 9, 228, 40, 7, 9, 228, 41, 7, 9, 228, 42, + 7, 9, 228, 43, 7, 9, 228, 44, 7, 9, 228, 45, 7, 9, 228, 46, 7, 9, 228, + 47, 7, 9, 228, 48, 7, 9, 228, 49, 7, 9, 228, 50, 7, 9, 228, 51, 7, 9, + 228, 52, 7, 9, 228, 53, 7, 9, 228, 54, 7, 9, 228, 55, 7, 9, 228, 56, 7, + 9, 228, 57, 7, 9, 228, 58, 7, 9, 228, 59, 7, 9, 228, 60, 7, 9, 228, 61, + 7, 9, 228, 62, 7, 9, 228, 63, 7, 9, 228, 64, 7, 9, 228, 65, 7, 9, 228, + 66, 7, 9, 228, 67, 7, 9, 228, 68, 7, 9, 228, 69, 7, 9, 228, 70, 7, 9, + 228, 71, 7, 9, 228, 72, 7, 9, 228, 73, 7, 9, 228, 74, 7, 9, 228, 75, 7, + 9, 228, 76, 7, 9, 228, 77, 7, 9, 228, 78, 7, 9, 228, 79, 7, 9, 228, 80, + 7, 9, 228, 81, 7, 9, 228, 82, 7, 9, 228, 83, 7, 9, 228, 84, 7, 9, 228, + 85, 7, 9, 228, 86, 7, 9, 228, 87, 7, 9, 228, 88, 7, 9, 228, 89, 7, 9, + 228, 90, 7, 9, 228, 91, 7, 9, 228, 92, 7, 9, 228, 93, 7, 9, 228, 94, 7, + 9, 228, 95, 7, 9, 228, 96, 7, 9, 228, 97, 7, 9, 228, 98, 7, 9, 228, 99, + 7, 9, 228, 100, 7, 9, 228, 101, 7, 9, 228, 102, 7, 9, 228, 103, 7, 9, + 228, 104, 7, 9, 228, 105, 7, 9, 228, 106, 7, 9, 228, 107, 7, 9, 228, 108, + 7, 9, 228, 109, 7, 9, 228, 110, 7, 9, 228, 111, 7, 9, 228, 112, 7, 9, + 228, 113, 7, 9, 228, 114, 7, 9, 228, 115, 7, 9, 228, 116, 7, 9, 228, 117, + 7, 9, 228, 118, 7, 9, 228, 119, 7, 9, 228, 120, 7, 9, 228, 121, 7, 9, + 228, 122, 7, 9, 228, 123, 7, 9, 228, 124, 7, 9, 228, 125, 7, 9, 228, 126, + 7, 9, 228, 127, 7, 9, 228, 128, 7, 9, 228, 129, 7, 9, 228, 130, 7, 9, + 228, 131, 7, 9, 228, 132, 7, 9, 228, 133, 7, 9, 228, 134, 7, 9, 228, 135, + 7, 9, 228, 136, 7, 9, 228, 137, 7, 9, 228, 138, 7, 9, 228, 139, 7, 9, + 228, 140, 7, 9, 228, 141, 7, 9, 228, 142, 7, 9, 228, 143, 7, 9, 228, 144, + 7, 9, 228, 145, 7, 9, 228, 146, 7, 9, 228, 147, 7, 9, 228, 148, 7, 9, + 228, 149, 7, 9, 228, 150, 7, 9, 228, 151, 7, 9, 228, 152, 7, 9, 228, 153, + 7, 9, 228, 154, 7, 9, 228, 155, 7, 9, 228, 156, 7, 9, 228, 157, 7, 9, + 228, 158, 7, 9, 228, 159, 7, 9, 228, 160, 7, 9, 228, 161, 7, 9, 228, 162, + 7, 9, 228, 163, 7, 9, 228, 164, 7, 9, 228, 165, 7, 9, 228, 166, 7, 9, + 228, 167, 7, 9, 228, 168, 7, 9, 228, 169, 7, 9, 228, 170, 7, 9, 228, 171, + 7, 9, 228, 172, 7, 9, 228, 173, 7, 9, 228, 174, 7, 9, 228, 175, 7, 9, + 228, 176, 7, 9, 228, 177, 7, 9, 228, 178, 7, 9, 228, 179, 7, 9, 228, 180, + 7, 9, 228, 181, 7, 9, 228, 182, 7, 9, 228, 183, 7, 9, 228, 184, 7, 9, + 228, 185, 7, 9, 228, 186, 7, 9, 228, 187, 7, 9, 228, 188, 7, 9, 228, 189, + 7, 9, 228, 190, 7, 9, 228, 191, 7, 9, 228, 192, 7, 9, 228, 193, 7, 9, + 228, 194, 7, 9, 228, 195, 7, 9, 228, 196, 7, 9, 228, 197, 7, 9, 228, 198, + 7, 9, 228, 199, 7, 9, 228, 200, 7, 9, 228, 201, 7, 9, 228, 202, 7, 9, + 228, 203, 7, 9, 228, 204, 7, 9, 228, 205, 7, 9, 228, 206, 7, 9, 228, 207, + 7, 9, 228, 208, 7, 9, 228, 209, 7, 9, 228, 210, 7, 9, 228, 211, 7, 9, + 228, 212, 7, 9, 228, 213, 7, 9, 228, 214, 7, 9, 228, 215, 7, 9, 228, 216, + 7, 9, 228, 217, 7, 9, 228, 218, 7, 9, 228, 219, 7, 9, 228, 220, 7, 9, + 228, 221, 7, 9, 228, 222, 7, 9, 228, 223, 7, 9, 228, 224, 7, 9, 228, 225, + 7, 9, 228, 226, 7, 9, 228, 227, 7, 9, 228, 228, 7, 9, 228, 229, 7, 9, + 228, 230, 7, 9, 228, 231, 7, 9, 228, 232, 7, 9, 228, 233, 7, 9, 228, 234, + 7, 9, 228, 235, 7, 9, 228, 236, 7, 9, 228, 237, 7, 9, 228, 238, 7, 9, + 228, 239, 7, 9, 228, 240, 7, 9, 228, 241, 7, 9, 228, 242, 7, 9, 228, 243, + 7, 9, 228, 244, 7, 9, 228, 245, 7, 9, 228, 246, 7, 9, 228, 247, 7, 9, + 228, 248, 7, 9, 228, 249, 7, 9, 228, 250, 7, 9, 228, 251, 7, 9, 228, 252, + 7, 9, 228, 253, 7, 9, 228, 254, 7, 9, 228, 255, 7, 9, 229, 0, 7, 9, 229, + 1, 7, 9, 229, 2, 7, 9, 229, 3, 7, 9, 229, 4, 7, 9, 229, 5, 7, 9, 229, 6, + 7, 9, 229, 7, 7, 9, 229, 8, 7, 9, 229, 9, 7, 9, 229, 10, 7, 9, 229, 11, + 7, 9, 229, 12, 7, 9, 229, 13, 7, 9, 229, 14, 7, 9, 229, 15, 7, 9, 229, + 16, 7, 9, 229, 17, 7, 9, 229, 18, 7, 9, 229, 19, 7, 9, 229, 20, 7, 9, + 229, 21, 7, 9, 229, 22, 7, 9, 229, 23, 7, 9, 229, 24, 7, 9, 229, 25, 7, + 9, 229, 26, 7, 9, 229, 27, 7, 9, 229, 28, 7, 9, 229, 29, 7, 9, 229, 30, + 7, 9, 229, 31, 7, 9, 229, 32, 7, 9, 229, 33, 7, 9, 229, 34, 7, 9, 229, + 35, 7, 9, 229, 36, 7, 9, 229, 37, 7, 9, 229, 38, 7, 9, 229, 39, 7, 9, + 229, 40, 7, 9, 229, 41, 7, 9, 229, 42, 7, 9, 229, 43, 7, 9, 229, 44, 7, + 9, 229, 45, 237, 194, 249, 173, 97, 240, 15, 97, 233, 54, 69, 97, 235, + 51, 69, 97, 61, 52, 97, 240, 114, 52, 97, 238, 107, 52, 97, 234, 17, 97, + 233, 59, 97, 40, 232, 74, 97, 38, 232, 74, 97, 235, 52, 97, 248, 49, 52, + 97, 240, 27, 97, 231, 94, 97, 248, 37, 208, 97, 236, 177, 97, 26, 242, + 217, 97, 26, 127, 97, 26, 111, 97, 26, 166, 97, 26, 177, 97, 26, 176, 97, + 26, 187, 97, 26, 203, 97, 26, 195, 97, 26, 202, 97, 240, 24, 97, 234, 14, + 97, 235, 44, 52, 97, 240, 7, 52, 97, 232, 68, 52, 97, 236, 156, 69, 97, + 234, 20, 254, 20, 97, 8, 5, 1, 67, 97, 8, 5, 1, 217, 97, 8, 5, 1, 255, + 18, 97, 8, 5, 1, 209, 97, 8, 5, 1, 72, 97, 8, 5, 1, 255, 19, 97, 8, 5, 1, + 210, 97, 8, 5, 1, 192, 97, 8, 5, 1, 71, 97, 8, 5, 1, 221, 97, 8, 5, 1, + 255, 15, 97, 8, 5, 1, 162, 97, 8, 5, 1, 173, 97, 8, 5, 1, 197, 97, 8, 5, + 1, 73, 97, 8, 5, 1, 223, 97, 8, 5, 1, 255, 20, 97, 8, 5, 1, 144, 97, 8, + 5, 1, 193, 97, 8, 5, 1, 214, 97, 8, 5, 1, 79, 97, 8, 5, 1, 179, 97, 8, 5, + 1, 255, 16, 97, 8, 5, 1, 206, 97, 8, 5, 1, 255, 14, 97, 8, 5, 1, 255, 17, + 97, 40, 31, 104, 97, 238, 75, 236, 177, 97, 38, 31, 104, 97, 190, 238, + 54, 97, 170, 242, 224, 97, 242, 245, 238, 54, 97, 8, 3, 1, 67, 97, 8, 3, + 1, 217, 97, 8, 3, 1, 255, 18, 97, 8, 3, 1, 209, 97, 8, 3, 1, 72, 97, 8, + 3, 1, 255, 19, 97, 8, 3, 1, 210, 97, 8, 3, 1, 192, 97, 8, 3, 1, 71, 97, + 8, 3, 1, 221, 97, 8, 3, 1, 255, 15, 97, 8, 3, 1, 162, 97, 8, 3, 1, 173, + 97, 8, 3, 1, 197, 97, 8, 3, 1, 73, 97, 8, 3, 1, 223, 97, 8, 3, 1, 255, + 20, 97, 8, 3, 1, 144, 97, 8, 3, 1, 193, 97, 8, 3, 1, 214, 97, 8, 3, 1, + 79, 97, 8, 3, 1, 179, 97, 8, 3, 1, 255, 16, 97, 8, 3, 1, 206, 97, 8, 3, + 1, 255, 14, 97, 8, 3, 1, 255, 17, 97, 40, 242, 225, 104, 97, 59, 242, + 224, 97, 38, 242, 225, 104, 97, 169, 241, 43, 249, 173, 34, 232, 211, 34, + 232, 212, 34, 232, 213, 34, 232, 214, 34, 232, 215, 34, 232, 216, 34, + 232, 217, 34, 232, 218, 34, 232, 219, 34, 232, 220, 34, 232, 221, 34, + 232, 222, 34, 232, 223, 34, 232, 224, 34, 232, 225, 34, 232, 226, 34, + 232, 227, 34, 232, 228, 34, 232, 229, 34, 232, 230, 34, 232, 231, 34, + 232, 232, 34, 232, 233, 34, 232, 234, 34, 232, 235, 34, 232, 236, 34, + 232, 237, 34, 232, 238, 34, 232, 239, 34, 232, 240, 34, 232, 241, 34, + 232, 242, 34, 232, 243, 34, 232, 244, 34, 232, 245, 34, 232, 246, 34, + 232, 247, 34, 232, 248, 34, 232, 249, 34, 232, 250, 34, 232, 251, 34, + 232, 252, 34, 232, 253, 34, 232, 254, 34, 232, 255, 34, 233, 0, 34, 233, + 1, 34, 233, 2, 34, 233, 3, 34, 233, 4, 34, 233, 5, 34, 233, 6, 34, 233, + 7, 34, 233, 8, 34, 233, 9, 34, 233, 10, 34, 233, 11, 34, 233, 12, 34, + 233, 13, 34, 233, 14, 34, 233, 15, 34, 233, 16, 34, 233, 17, 34, 233, 18, + 34, 233, 19, 34, 233, 20, 34, 233, 21, 34, 233, 22, 34, 233, 23, 34, 233, + 24, 34, 233, 25, 34, 233, 26, 34, 233, 27, 34, 233, 28, 34, 233, 29, 34, + 233, 30, 34, 233, 31, 34, 233, 32, 34, 233, 33, 34, 233, 34, 34, 233, 35, + 34, 233, 36, 34, 233, 37, 34, 231, 153, 34, 231, 154, 34, 231, 155, 34, + 231, 156, 34, 231, 157, 34, 231, 158, 34, 231, 159, 34, 231, 160, 34, + 231, 161, 34, 231, 162, 34, 231, 163, 34, 231, 164, 34, 231, 165, 34, + 231, 166, 34, 231, 167, 34, 231, 168, 34, 231, 169, 34, 231, 170, 34, + 231, 171, 34, 231, 172, 34, 231, 173, 34, 231, 174, 34, 231, 175, 34, + 231, 176, 34, 231, 177, 34, 231, 178, 34, 231, 179, 34, 231, 180, 34, + 231, 181, 34, 231, 182, 34, 231, 183, 34, 231, 184, 34, 231, 185, 34, + 231, 186, 34, 231, 187, 34, 231, 188, 34, 231, 189, 34, 231, 190, 34, + 231, 191, 34, 231, 192, 34, 231, 193, 34, 231, 194, 34, 231, 195, 34, + 231, 196, 34, 231, 197, 34, 231, 198, 34, 231, 199, 34, 231, 200, 34, + 231, 201, 34, 231, 202, 34, 231, 203, 34, 231, 204, 34, 231, 205, 34, + 231, 206, 34, 231, 207, 34, 231, 208, 34, 231, 209, 34, 231, 210, 34, + 231, 211, 34, 231, 212, 34, 231, 213, 34, 231, 214, 34, 231, 215, 34, + 231, 216, 34, 231, 217, 34, 231, 218, 34, 231, 219, 34, 231, 220, 34, + 231, 221, 34, 231, 222, 34, 231, 223, 34, 231, 224, 34, 231, 225, 34, + 231, 226, 34, 231, 227, 34, 231, 228, 34, 231, 229, 34, 231, 230, 34, + 231, 231, 34, 231, 232, 34, 231, 233, 34, 231, 234, 34, 231, 235, 34, + 231, 236, 34, 231, 237, 34, 231, 238, 34, 231, 239, 34, 231, 240, 34, + 231, 241, 34, 231, 242, 34, 231, 243, 34, 231, 244, 34, 231, 245, 34, + 231, 246, 34, 231, 247, 34, 231, 248, 34, 231, 249, 34, 231, 250, 34, + 231, 251, 34, 231, 252, 34, 231, 253, 34, 231, 254, 34, 231, 255, 34, + 232, 0, 34, 232, 1, 34, 232, 2, 34, 232, 3, 34, 232, 4, 34, 232, 5, 34, + 232, 6, 34, 232, 7, 34, 232, 8, 34, 232, 9, 34, 232, 10, 34, 232, 11, 34, + 232, 12, 34, 232, 13, 34, 232, 14, 34, 232, 15, 34, 232, 16, 34, 232, 17, + 34, 232, 18, 34, 232, 19, 34, 232, 20, 34, 232, 21, 34, 232, 22, 34, 232, + 23, 34, 232, 24, 34, 232, 25, 34, 232, 26, 34, 232, 27, 34, 232, 28, 34, + 232, 29, 34, 232, 30, 34, 232, 31, 34, 232, 32, 34, 232, 33, 34, 232, 34, + 34, 232, 35, 34, 232, 36, 34, 232, 37, 34, 232, 38, 34, 232, 39, 34, 232, + 40, 34, 232, 41, 34, 232, 42, 34, 232, 43, 34, 232, 44, 34, 232, 45, 34, + 232, 46, 34, 232, 47, 34, 232, 48, 34, 232, 49, 34, 232, 50, 34, 232, 51, + 34, 232, 52, 34, 232, 53, +}; + +static unsigned char phrasebook_offset1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 16, 16, 16, 16, + 16, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 16, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 97, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 16, 16, 16, 16, 108, 16, 109, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 110, 111, 112, 113, 114, 115, + 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 16, 16, 128, + 129, 130, 131, 16, 16, 16, 16, 16, 16, 132, 16, 16, 16, 133, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 134, 135, 136, + 137, 138, 16, 139, 16, 140, 141, 142, 143, 144, 145, 146, 147, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 148, 149, + 150, 151, 152, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 153, 16, 154, 155, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, +}; + +static unsigned int phrasebook_offset2[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 6, 9, 11, 14, 17, 19, 21, 24, 27, 29, 32, + 34, 36, 39, 41, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 69, 72, + 75, 78, 82, 86, 90, 95, 99, 103, 108, 112, 116, 120, 124, 129, 133, 137, + 141, 145, 149, 154, 158, 162, 166, 170, 174, 179, 183, 188, 193, 196, + 200, 203, 206, 209, 213, 217, 221, 226, 230, 234, 239, 243, 247, 251, + 255, 260, 264, 268, 272, 276, 280, 285, 289, 293, 297, 301, 305, 310, + 314, 319, 324, 328, 331, 335, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 336, 340, 345, + 348, 351, 354, 357, 360, 363, 364, 367, 373, 380, 382, 386, 389, 390, + 393, 396, 399, 402, 406, 409, 412, 416, 418, 421, 427, 434, 442, 450, + 457, 462, 468, 474, 481, 487, 493, 501, 506, 514, 520, 526, 533, 539, + 545, 551, 558, 564, 569, 576, 582, 588, 595, 601, 607, 610, 616, 622, + 628, 635, 641, 648, 653, 659, 665, 671, 678, 684, 690, 698, 703, 711, + 717, 723, 730, 736, 742, 748, 755, 761, 766, 773, 779, 785, 792, 798, + 804, 807, 813, 819, 825, 832, 838, 845, 850, 857, 863, 869, 876, 883, + 890, 897, 904, 911, 919, 927, 935, 943, 951, 959, 967, 975, 982, 989, + 995, 1001, 1008, 1015, 1022, 1029, 1036, 1043, 1050, 1057, 1065, 1073, + 1081, 1089, 1097, 1105, 1113, 1121, 1129, 1137, 1144, 1151, 1157, 1163, + 1169, 1175, 1182, 1189, 1196, 1203, 1210, 1216, 1221, 1226, 1234, 1242, + 1250, 1258, 1263, 1270, 1277, 1285, 1293, 1301, 1309, 1319, 1329, 1336, + 1343, 1350, 1357, 1365, 1373, 1381, 1389, 1400, 1405, 1410, 1416, 1422, + 1429, 1436, 1443, 1450, 1455, 1460, 1467, 1474, 1482, 1490, 1498, 1506, + 1513, 1520, 1528, 1536, 1544, 1552, 1560, 1568, 1576, 1584, 1592, 1600, + 1607, 1614, 1620, 1626, 1632, 1638, 1645, 1652, 1660, 1668, 1675, 1682, + 1689, 1696, 1704, 1712, 1720, 1728, 1735, 1742, 1749, 1757, 1765, 1773, + 1781, 1786, 1792, 1798, 1805, 1812, 1817, 1822, 1828, 1835, 1842, 1848, + 1855, 1863, 1871, 1877, 1882, 1887, 1893, 1900, 1907, 1914, 1919, 1924, + 1929, 1935, 1942, 1949, 1956, 1963, 1968, 1976, 1986, 1994, 2001, 2008, + 2013, 2018, 2025, 2032, 2036, 2041, 2046, 2051, 2058, 2067, 2074, 2081, + 2090, 2097, 2104, 2109, 2116, 2123, 2130, 2137, 2144, 2149, 2156, 2163, + 2171, 2176, 2181, 2186, 2196, 2200, 2206, 2212, 2218, 2224, 2232, 2245, + 2253, 2258, 2267, 2272, 2277, 2286, 2291, 2298, 2305, 2312, 2319, 2326, + 2333, 2340, 2347, 2356, 2365, 2374, 2383, 2393, 2403, 2412, 2421, 2426, + 2435, 2444, 2453, 2462, 2469, 2476, 2483, 2490, 2498, 2506, 2514, 2522, + 2529, 2536, 2545, 2554, 2562, 2570, 2578, 2583, 2593, 2598, 2605, 2612, + 2617, 2622, 2629, 2636, 2646, 2656, 2663, 2670, 2679, 2688, 2695, 2702, + 2711, 2720, 2727, 2734, 2743, 2752, 2759, 2766, 2775, 2784, 2791, 2798, + 2807, 2816, 2824, 2832, 2842, 2852, 2859, 2866, 2875, 2884, 2893, 2902, + 2911, 2920, 2925, 2930, 2938, 2946, 2956, 2964, 2969, 2974, 2981, 2988, + 2995, 3002, 3009, 3016, 3025, 3034, 3043, 3052, 3059, 3066, 3075, 3084, + 3091, 3098, 3106, 3114, 3122, 3128, 3135, 3142, 3148, 3155, 3162, 3169, + 3178, 3188, 3198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3204, 3209, + 3214, 3220, 3226, 3232, 3240, 3248, 3255, 3260, 3265, 3272, 3278, 3285, + 3294, 3303, 3312, 3319, 3324, 3329, 3334, 3341, 3346, 3353, 3360, 3366, + 3371, 3376, 3385, 3393, 3402, 3407, 3412, 3422, 3429, 3437, 3446, 3451, + 3457, 3463, 3470, 3475, 3480, 3490, 3498, 3507, 3515, 3523, 3532, 3537, + 3544, 3551, 3556, 3568, 3576, 3584, 3589, 3598, 3603, 3608, 3615, 3620, + 3626, 3632, 3638, 3647, 3655, 3660, 3668, 3673, 3681, 3688, 3694, 3700, + 3705, 3713, 3721, 3726, 3734, 3740, 3745, 3752, 3760, 3769, 3776, 3783, + 3793, 3800, 3807, 3817, 3824, 3831, 3838, 3844, 3850, 3859, 3871, 3875, + 3882, 3886, 3890, 3895, 3903, 3910, 3915, 3920, 3924, 3929, 3934, 3938, + 3943, 3949, 3955, 3960, 3966, 3971, 3976, 3981, 3986, 3991, 3993, 3998, + 4001, 4007, 4013, 4019, 4023, 4030, 4037, 4043, 4050, 4058, 4066, 4071, + 4076, 4081, 4086, 4088, 4090, 4093, 4095, 4097, 4102, 4107, 4113, 4118, + 4122, 4126, 4130, 4137, 4143, 4148, 4154, 4159, 4165, 4173, 4181, 4185, + 4189, 4194, 4200, 4206, 4212, 4218, 4223, 4231, 4240, 4249, 4253, 4259, + 4266, 4273, 4280, 4287, 4291, 4297, 4302, 4307, 4312, 4316, 4318, 4320, + 4323, 4326, 4329, 4331, 4335, 4339, 4345, 4348, 4353, 4359, 4365, 4368, + 4373, 4378, 4382, 4387, 4392, 4398, 4404, 4409, 4414, 4418, 4421, 4427, + 4432, 4437, 4442, 4447, 4453, 4459, 4462, 4466, 4470, 4474, 4477, 4480, + 4485, 4489, 4496, 4500, 4505, 4509, 4515, 4519, 4523, 4527, 4532, 4537, + 4544, 4550, 4557, 4563, 4569, 4575, 4578, 4582, 4586, 4589, 4593, 4598, + 4603, 4607, 4611, 4617, 4621, 4625, 4630, 4636, 4640, 4645, 4649, 4655, + 4660, 4665, 4670, 4675, 4681, 4684, 4688, 4693, 4698, 4707, 4713, 4717, + 4721, 4726, 4730, 4735, 4739, 4742, 4747, 4750, 4756, 4761, 4766, 4771, + 4776, 4781, 4786, 4792, 4797, 4802, 4807, 4812, 4817, 4822, 0, 0, 0, 0, + 4827, 4830, 0, 0, 0, 0, 4834, 0, 0, 0, 4837, 0, 0, 0, 0, 0, 4841, 4844, + 4849, 4856, 4861, 4869, 4877, 0, 4885, 0, 4893, 4901, 4908, 4919, 4924, + 4929, 4934, 4939, 4944, 4949, 4954, 4959, 4964, 4969, 4974, 4979, 4984, + 4989, 4994, 4999, 0, 5004, 5009, 5014, 5019, 5024, 5029, 5034, 5039, + 5047, 5055, 5062, 5070, 5078, 5086, 5097, 5102, 5107, 5112, 5117, 5122, + 5127, 5132, 5137, 5142, 5147, 5152, 5157, 5162, 5167, 5172, 5177, 5182, + 5188, 5193, 5198, 5203, 5208, 5213, 5218, 5223, 5231, 5239, 5247, 5255, + 0, 5262, 5266, 5270, 5277, 5287, 5297, 5301, 5305, 5309, 5315, 5322, + 5326, 5331, 5335, 5340, 5344, 5349, 5353, 5358, 5363, 5368, 5373, 5378, + 5383, 5388, 5393, 5398, 5403, 5408, 5413, 5418, 5423, 5428, 5432, 5436, + 5442, 5446, 5451, 5457, 5464, 5469, 5474, 5481, 5486, 5491, 5498, 5506, + 5515, 5525, 5532, 5537, 5542, 5547, 5554, 5559, 5565, 5570, 5575, 5580, + 5585, 5590, 5595, 5601, 5607, 5612, 5616, 5621, 5626, 5631, 5636, 5641, + 5646, 5651, 5655, 5661, 5665, 5670, 5675, 5680, 5684, 5689, 5694, 5699, + 5704, 5708, 5713, 5717, 5722, 5727, 5732, 5737, 5743, 5748, 5754, 5758, + 5763, 5767, 5771, 5776, 5781, 5786, 5791, 5796, 5801, 5806, 5810, 5816, + 5820, 5825, 5830, 5835, 5839, 5844, 5849, 5854, 5859, 5863, 5868, 5872, + 5877, 5882, 5887, 5892, 5898, 5903, 5909, 5913, 5918, 5922, 5929, 5934, + 5939, 5944, 5951, 5956, 5962, 5967, 5972, 5977, 5982, 5987, 5992, 5998, + 6004, 6009, 6014, 6019, 6024, 6029, 6035, 6041, 6048, 6055, 6064, 6073, + 6080, 6087, 6096, 6105, 6110, 6115, 6120, 6125, 6130, 6135, 6140, 6145, + 6156, 6167, 6172, 6177, 6184, 6191, 6198, 6205, 6210, 6215, 6220, 6225, + 6229, 6233, 6237, 6242, 0, 6247, 6254, 6259, 6268, 6277, 6283, 6289, + 6297, 6305, 6313, 6321, 6328, 6335, 6344, 6353, 6361, 6369, 6377, 6385, + 6393, 6401, 6409, 6417, 6424, 6431, 6437, 6443, 6451, 6459, 6466, 6473, + 6482, 6491, 6497, 6503, 6511, 6519, 6527, 6535, 6541, 6547, 6555, 6563, + 6571, 6579, 6586, 6593, 6601, 6609, 6617, 6625, 6630, 6635, 6642, 6649, + 6659, 6669, 6673, 6681, 6689, 6696, 6703, 6711, 6719, 6726, 6733, 6741, + 6749, 6756, 6763, 6771, 0, 6779, 6786, 6793, 6799, 6805, 6811, 6817, + 6825, 6833, 6838, 6843, 6850, 6857, 6864, 6871, 6878, 6885, 6892, 6899, + 6905, 6911, 6917, 6923, 6929, 6935, 6941, 6947, 6955, 6963, 6969, 6975, + 6981, 6987, 6993, 6999, 7006, 7013, 7020, 7027, 7035, 7043, 7050, 0, 0, + 0, 0, 0, 0, 7057, 7064, 7071, 7078, 7085, 7092, 7099, 7106, 7113, 7120, + 7127, 7134, 7141, 7148, 7155, 7162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7169, + 7174, 7179, 7184, 7189, 7194, 7199, 7204, 7209, 7213, 7218, 7223, 7228, + 7233, 7238, 7243, 7248, 7253, 7258, 7263, 7268, 7273, 7278, 7283, 7288, + 7293, 7298, 7303, 7308, 7313, 7318, 7323, 7328, 7333, 7338, 7343, 7348, + 7353, 0, 0, 7358, 7365, 7368, 7372, 7376, 7379, 7383, 0, 7387, 7392, + 7397, 7402, 7407, 7412, 7417, 7422, 7427, 7431, 7436, 7441, 7446, 7451, + 7456, 7461, 7466, 7471, 7476, 7481, 7486, 7491, 7496, 7501, 7506, 7511, + 7516, 7521, 7526, 7531, 7536, 7541, 7546, 7551, 7556, 7561, 7566, 7571, + 7576, 0, 7583, 7587, 0, 0, 0, 0, 0, 0, 7590, 7595, 7600, 7605, 7612, + 7619, 7624, 7629, 7634, 7639, 7644, 7649, 7654, 7661, 7666, 7673, 7680, + 7685, 7692, 7697, 7702, 7707, 7714, 7719, 7724, 7731, 7740, 7745, 7750, + 7755, 7760, 7766, 7771, 7778, 7785, 7792, 7797, 7802, 7807, 7812, 7817, + 0, 7822, 7827, 7835, 7840, 7845, 7850, 7855, 7862, 7869, 7876, 7881, + 7886, 7893, 0, 0, 0, 0, 0, 0, 0, 0, 7900, 7904, 7908, 7912, 7916, 7920, + 7924, 7928, 7932, 7936, 7940, 7945, 7949, 7953, 7958, 7962, 7967, 7971, + 7975, 7979, 7984, 7988, 7993, 7997, 8001, 8005, 8009, 0, 0, 0, 0, 0, + 8013, 8020, 8028, 8035, 8040, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8045, + 8048, 8052, 8057, 0, 0, 0, 0, 0, 0, 0, 8061, 8064, 8067, 8072, 8078, + 8082, 8090, 8096, 8102, 8110, 8114, 0, 0, 0, 0, 0, 8119, 0, 0, 8122, + 8129, 0, 8133, 8137, 8144, 8150, 8157, 8163, 8169, 8173, 8177, 8183, + 8187, 8191, 8195, 8199, 8203, 8207, 8211, 8215, 8219, 8223, 8227, 8231, + 8235, 8239, 8243, 8247, 0, 0, 0, 0, 0, 8251, 8254, 8258, 8262, 8266, + 8270, 8274, 8278, 8282, 8286, 8291, 8295, 8298, 8301, 8304, 8307, 8310, + 8313, 8316, 8319, 8323, 8326, 8329, 8334, 8339, 8344, 8347, 8354, 8363, + 8368, 8372, 0, 8379, 8384, 8388, 8392, 8396, 8400, 8404, 8408, 8412, + 8416, 8420, 8424, 8429, 8434, 8441, 8447, 8453, 8459, 8464, 8472, 8480, + 8485, 8491, 8497, 8503, 8509, 8513, 8517, 8521, 8528, 8538, 8542, 8546, + 8550, 8556, 8564, 8568, 8572, 8579, 8583, 8587, 8591, 8598, 8605, 8617, + 8621, 8625, 8629, 8639, 8648, 8652, 8659, 8666, 8673, 8682, 8693, 8701, + 8705, 8714, 8725, 8733, 8746, 8754, 8762, 8770, 8778, 8784, 8793, 8800, + 8804, 8812, 8816, 8823, 8831, 8835, 8841, 8848, 8855, 8859, 8867, 8871, + 8878, 8882, 8890, 8894, 8902, 8908, 8914, 8921, 8928, 8934, 8939, 8943, + 8949, 8956, 8962, 8969, 8976, 8982, 8991, 8999, 9006, 9012, 9016, 9019, + 9023, 9029, 9037, 9041, 9047, 9053, 9059, 9066, 9069, 9076, 9081, 9089, + 9093, 9097, 9109, 9121, 9127, 9133, 9138, 9144, 9149, 9155, 9165, 9172, + 9181, 9191, 9197, 9202, 9207, 9211, 9215, 9220, 9225, 9231, 9238, 9245, + 9256, 9261, 9269, 9277, 9284, 9290, 9296, 9302, 9308, 9314, 9320, 9326, + 9332, 9338, 9345, 9352, 9359, 9365, 9373, 9381, 9387, 9393, 9399, 9404, + 9409, 9413, 9420, 9426, 9435, 9443, 9446, 9451, 9456, 0, 9461, 9465, + 9469, 9475, 9479, 9483, 9489, 9493, 9501, 9505, 9509, 9513, 9517, 9521, + 9527, 9531, 9537, 9541, 9545, 9549, 9553, 9557, 9562, 9565, 9569, 9574, + 9578, 9582, 9586, 9590, 9594, 9599, 9604, 9609, 9613, 9617, 9622, 9626, + 9630, 9635, 9639, 9643, 9650, 9657, 9661, 9665, 9670, 9674, 9678, 9681, + 9686, 9689, 9692, 9697, 9702, 9706, 9710, 9716, 9722, 9725, 0, 0, 9728, + 9734, 9740, 9746, 9756, 9768, 9780, 9797, 9809, 9820, 9827, 9834, 9845, + 9860, 9871, 9877, 9886, 9894, 9906, 9916, 9924, 9936, 9943, 9951, 9963, + 9969, 9975, 9982, 9989, 9995, 10000, 10010, 10017, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10027, 10031, 10035, 10039, 10043, + 10047, 10051, 10055, 10059, 10063, 10067, 10071, 10075, 10079, 10083, + 10087, 10091, 10095, 10099, 10103, 10107, 10111, 10115, 10119, 10123, + 10127, 10131, 10135, 10139, 10143, 10147, 10151, 10155, 10158, 10162, + 10166, 10170, 10174, 10178, 10181, 10184, 10187, 10190, 10193, 10196, + 10199, 10202, 10205, 10208, 10211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10215, 10219, 10223, 10227, 10232, 10235, 10239, 10242, 10246, + 10249, 10253, 10257, 10261, 10266, 10271, 10274, 10278, 10283, 10288, + 10291, 10295, 10298, 10302, 10306, 10310, 10314, 10318, 10322, 10326, + 10330, 10334, 10338, 10342, 10346, 10350, 10354, 10358, 10362, 10366, + 10370, 10374, 10378, 10382, 10386, 10390, 10394, 10397, 10400, 10404, + 10408, 10412, 10416, 10420, 10424, 10428, 10432, 10436, 0, 0, 10439, + 10443, 10447, 10452, 10456, 10461, 10465, 10470, 10475, 10481, 10487, + 10493, 10497, 10502, 10508, 10514, 10518, 10523, 0, 0, 10527, 10530, + 10536, 10542, 10547, 0, 0, 0, 10552, 10556, 10560, 10564, 10568, 10572, + 10576, 10580, 10584, 10589, 10594, 10599, 10605, 10608, 10612, 10616, + 10619, 10622, 10625, 10628, 10631, 10634, 10637, 10640, 10643, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 10647, 0, 0, 0, 10652, 10656, 10660, 0, 10664, + 10667, 10671, 10674, 10678, 10681, 10685, 10689, 0, 0, 10693, 10696, 0, + 0, 10700, 10703, 10707, 10710, 10714, 10718, 10722, 10726, 10730, 10734, + 10738, 10742, 10746, 10750, 10754, 10758, 10762, 10766, 10770, 10774, + 10778, 10782, 0, 10786, 10790, 10794, 10798, 10802, 10805, 10808, 0, + 10812, 0, 0, 0, 10816, 10820, 10824, 10828, 0, 0, 10831, 10835, 10839, + 10844, 10848, 10853, 10857, 10862, 10867, 0, 0, 10873, 10877, 0, 0, + 10882, 10886, 10891, 10895, 0, 0, 0, 0, 0, 0, 0, 0, 10901, 0, 0, 0, 0, + 10907, 10911, 0, 10915, 10919, 10924, 10929, 10934, 0, 0, 10940, 10944, + 10947, 10950, 10953, 10956, 10959, 10962, 10965, 10968, 10971, 10980, + 10988, 10992, 10996, 11002, 11008, 11014, 11020, 11035, 11042, 0, 0, 0, + 0, 0, 0, 11045, 11051, 11055, 0, 11059, 11062, 11066, 11069, 11073, + 11076, 0, 0, 0, 0, 11080, 11084, 0, 0, 11088, 11092, 11096, 11099, 11103, + 11107, 11111, 11115, 11119, 11123, 11127, 11131, 11135, 11139, 11143, + 11147, 11151, 11155, 11159, 11163, 11167, 11171, 0, 11175, 11179, 11183, + 11187, 11191, 11194, 11197, 0, 11201, 11205, 0, 11209, 11213, 0, 11217, + 11221, 0, 0, 11224, 0, 11228, 11233, 11237, 11242, 11246, 0, 0, 0, 0, + 11251, 11256, 0, 0, 11261, 11266, 11271, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 11275, 11279, 11283, 11287, 0, 11291, 0, 0, 0, 0, 0, 0, 0, 11295, 11299, + 11302, 11305, 11308, 11311, 11314, 11317, 11320, 11323, 11326, 11329, + 11332, 11335, 11338, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11343, 11347, + 11351, 0, 11355, 11358, 11362, 11365, 11369, 11372, 11376, 11380, 11384, + 0, 11389, 11392, 11396, 0, 11401, 11404, 11408, 11411, 11415, 11419, + 11423, 11427, 11431, 11435, 11439, 11443, 11447, 11451, 11455, 11459, + 11463, 11467, 11471, 11475, 11479, 11483, 0, 11487, 11491, 11495, 11499, + 11503, 11506, 11509, 0, 11513, 11517, 0, 11521, 11525, 11529, 11533, + 11537, 0, 0, 11540, 11544, 11548, 11553, 11557, 11562, 11566, 11571, + 11576, 11582, 0, 11588, 11592, 11597, 0, 11603, 11607, 11612, 0, 0, + 11616, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11619, 11624, 11629, + 11634, 0, 0, 11640, 11644, 11647, 11650, 11653, 11656, 11659, 11662, + 11665, 11668, 0, 11671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 11675, 11679, 11683, 0, 11687, 11690, 11694, 11697, 11701, 11704, 11708, + 11712, 0, 0, 11716, 11719, 0, 0, 11723, 11726, 11730, 11733, 11737, + 11741, 11745, 11749, 11753, 11757, 11761, 11765, 11769, 11773, 11777, + 11781, 11785, 11789, 11793, 11797, 11801, 11805, 0, 11809, 11813, 11817, + 11821, 11825, 11828, 11831, 0, 11835, 11839, 0, 11843, 11847, 11851, + 11855, 11859, 0, 0, 11862, 11866, 11870, 11875, 11879, 11884, 11888, + 11893, 0, 0, 0, 11898, 11902, 0, 0, 11907, 11911, 11916, 0, 0, 0, 0, 0, + 0, 0, 0, 11920, 11926, 0, 0, 0, 0, 11932, 11936, 0, 11940, 11944, 11949, + 0, 0, 0, 0, 11954, 11958, 11961, 11964, 11967, 11970, 11973, 11976, + 11979, 11982, 11985, 11988, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 11992, 11996, 0, 12000, 12003, 12007, 12010, 12014, 12017, 0, 0, 0, + 12021, 12024, 12028, 0, 12032, 12035, 12039, 12043, 0, 0, 0, 12046, + 12050, 0, 12054, 0, 12058, 12062, 0, 0, 0, 12066, 12070, 0, 0, 0, 12074, + 12078, 12082, 0, 0, 0, 12086, 12089, 12092, 12096, 12100, 12104, 12108, + 12112, 12116, 12120, 12124, 12128, 0, 0, 0, 0, 12131, 12136, 12140, + 12145, 12149, 0, 0, 0, 12154, 12158, 12163, 0, 12168, 12172, 12177, + 12182, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12186, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12192, 12196, 12199, 12202, 12205, 12208, 12211, 12214, 12217, + 12220, 12223, 12227, 12233, 12239, 12243, 12247, 12251, 12255, 12259, + 12264, 12268, 0, 0, 0, 0, 0, 0, 12271, 12275, 12279, 0, 12283, 12286, + 12290, 12293, 12297, 12300, 12304, 12308, 0, 12312, 12315, 12319, 0, + 12323, 12326, 12330, 12334, 12337, 12341, 12345, 12349, 12353, 12357, + 12361, 12365, 12369, 12373, 12377, 12381, 12385, 12389, 12393, 12397, + 12401, 12405, 12409, 0, 12413, 12417, 12421, 12425, 12429, 12432, 12435, + 12439, 12443, 12447, 0, 12451, 12455, 12459, 12463, 12467, 0, 0, 0, 0, + 12470, 12475, 12479, 12484, 12488, 12493, 12498, 0, 12504, 12508, 12513, + 0, 12518, 12522, 12527, 12532, 0, 0, 0, 0, 0, 0, 0, 12536, 12540, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12546, 12551, 0, 0, 0, 0, 12556, 12560, 12563, + 12566, 12569, 12572, 12575, 12578, 12581, 12584, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12587, 12591, 0, 12595, 12598, 12602, + 12605, 12609, 12612, 12616, 12620, 0, 12624, 12627, 12631, 0, 12635, + 12638, 12642, 12646, 12649, 12653, 12657, 12661, 12665, 12669, 12673, + 12677, 12681, 12685, 12689, 12693, 12697, 12701, 12705, 12709, 12713, + 12717, 12721, 0, 12725, 12729, 12733, 12737, 12741, 12744, 12747, 12751, + 12755, 12759, 0, 12763, 12767, 12771, 12775, 12779, 0, 0, 12782, 12786, + 12790, 12795, 12799, 12804, 12808, 12813, 12818, 0, 12824, 12828, 12833, + 0, 12838, 12842, 12847, 12852, 0, 0, 0, 0, 0, 0, 0, 12856, 12860, 0, 0, + 0, 0, 0, 0, 0, 12866, 0, 12870, 12875, 0, 0, 0, 0, 12880, 12884, 12887, + 12890, 12893, 12896, 12899, 12902, 12905, 12908, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12911, 12915, 0, 12919, 12922, 12926, + 12929, 12933, 12936, 12940, 12944, 0, 12948, 12951, 12955, 0, 12959, + 12962, 12966, 12970, 12973, 12977, 12981, 12985, 12989, 12993, 12997, + 13001, 13005, 13009, 13013, 13017, 13021, 13025, 13029, 13033, 13037, + 13041, 13045, 0, 13049, 13053, 13057, 13061, 13065, 13068, 13071, 13075, + 13079, 13083, 13087, 13091, 13095, 13099, 13103, 13107, 0, 0, 0, 0, + 13110, 13115, 13119, 13124, 13128, 13133, 0, 0, 13138, 13142, 13147, 0, + 13152, 13156, 13161, 13166, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13170, 0, 0, 0, 0, + 0, 0, 0, 0, 13176, 13181, 0, 0, 0, 0, 13186, 13190, 13193, 13196, 13199, + 13202, 13205, 13208, 13211, 13214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13217, 13221, 0, 13225, 13229, 13233, 13237, 13241, 13245, + 13249, 13253, 13257, 13261, 13265, 13269, 13273, 13277, 13281, 13285, + 13289, 13293, 0, 0, 0, 13297, 13303, 13309, 13315, 13321, 13327, 13333, + 13339, 13345, 13351, 13357, 13363, 13371, 13377, 13383, 13389, 13395, + 13401, 13407, 13413, 13419, 13425, 13431, 13437, 0, 13443, 13449, 13455, + 13461, 13467, 13473, 13477, 13483, 13487, 0, 13491, 0, 0, 13497, 13501, + 13507, 13513, 13519, 13523, 13529, 0, 0, 0, 13533, 0, 0, 0, 0, 13537, + 13542, 13549, 13556, 13563, 13570, 0, 13577, 0, 13584, 13589, 13594, + 13601, 13608, 13617, 13628, 13637, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 13642, 13649, 13656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 13661, 13667, 13673, 13679, 13685, 13691, 13697, 13703, 13709, 13715, + 13721, 13727, 13733, 13739, 13745, 13750, 13756, 13762, 13768, 13774, + 13780, 13785, 13791, 13797, 13803, 13809, 13815, 13821, 13827, 13833, + 13839, 13845, 13851, 13856, 13862, 13868, 13872, 13878, 13882, 13888, + 13894, 13900, 13906, 13912, 13918, 13923, 13929, 13933, 13938, 13944, + 13950, 13956, 13961, 13967, 13973, 13979, 13984, 13990, 0, 0, 0, 0, + 13994, 14000, 14005, 14011, 14016, 14024, 14032, 14036, 14040, 14044, + 14050, 14056, 14062, 14068, 14072, 14076, 14080, 14084, 14088, 14091, + 14094, 14097, 14100, 14103, 14106, 14109, 14112, 14115, 14119, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14123, 14127, 0, 14133, 0, 0, 14139, 14143, + 0, 14147, 0, 0, 14153, 0, 0, 0, 0, 0, 0, 14157, 14161, 14164, 14170, 0, + 14176, 14180, 14184, 14188, 14194, 14200, 14206, 0, 14212, 14216, 14220, + 0, 14226, 0, 14232, 0, 0, 14236, 14242, 0, 14248, 14251, 14257, 14260, + 14264, 14271, 14276, 14281, 14285, 14290, 14295, 14300, 14304, 0, 14309, + 14316, 14322, 0, 0, 14328, 14332, 14337, 14341, 14346, 0, 14351, 0, + 14356, 14362, 14368, 14374, 14380, 14384, 0, 0, 14387, 14391, 14394, + 14397, 14400, 14403, 14406, 14409, 14412, 14415, 0, 0, 14418, 14423, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 14428, 14432, 14443, 14458, 14473, 14483, + 14494, 14507, 14518, 14524, 14532, 14542, 14548, 14556, 14560, 14566, + 14572, 14580, 14590, 14598, 14611, 14617, 14625, 14633, 14645, 14653, + 14661, 14669, 14677, 14685, 14693, 14701, 14711, 14715, 14718, 14721, + 14724, 14727, 14730, 14733, 14736, 14739, 14742, 14746, 14750, 14754, + 14758, 14762, 14766, 14770, 14774, 14778, 14783, 14789, 14799, 14813, + 14823, 14829, 14835, 14843, 14851, 14859, 14867, 14873, 14879, 14882, + 14886, 14890, 14894, 14898, 14902, 14906, 0, 14910, 14914, 14918, 14922, + 14926, 14930, 14934, 14938, 14942, 14946, 14950, 14954, 14958, 14962, + 14966, 14970, 14973, 14977, 14981, 14985, 14989, 14993, 14997, 15001, + 15005, 15008, 15012, 15016, 15020, 15024, 15028, 15031, 15034, 15038, 0, + 0, 0, 0, 0, 0, 15044, 15049, 15053, 15058, 15062, 15067, 15072, 15078, + 15083, 15089, 15093, 15098, 15102, 15107, 15117, 15123, 15128, 15134, + 15144, 15150, 15154, 15158, 15164, 15170, 15178, 15184, 15192, 0, 0, 0, + 0, 15200, 15204, 15209, 15214, 15219, 15224, 15229, 15234, 0, 15239, + 15244, 15249, 15254, 15259, 15264, 15269, 15274, 15279, 15284, 15289, + 15294, 15299, 15304, 15309, 15314, 15318, 15323, 15328, 15333, 15338, + 15343, 15348, 15353, 15358, 15362, 15367, 15372, 15377, 15382, 15387, + 15391, 15395, 15400, 15407, 15413, 0, 15420, 15427, 15440, 15447, 15454, + 15462, 15470, 15476, 15482, 15488, 15498, 15504, 15510, 15520, 15530, 0, + 0, 15540, 15548, 15560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 15572, 15575, 15579, 15583, 15587, 15591, 15595, 15599, + 15603, 15607, 15611, 15615, 15619, 15623, 15627, 15631, 15635, 15639, + 15643, 15647, 15651, 15655, 15659, 15663, 15667, 15671, 15674, 15677, + 15681, 15685, 15689, 15693, 15696, 15700, 0, 15703, 15706, 15710, 15713, + 15717, 0, 15720, 15723, 0, 15727, 15732, 15736, 15741, 15745, 15750, + 15754, 0, 0, 0, 15759, 15763, 15767, 15771, 0, 0, 0, 0, 0, 0, 15775, + 15779, 15782, 15785, 15788, 15791, 15794, 15797, 15800, 15803, 15806, + 15812, 15816, 15820, 15824, 15828, 15832, 15836, 15840, 15844, 15849, + 15853, 15858, 15863, 15869, 15874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 15880, 15885, 15890, 15895, 15900, 15905, + 15910, 15915, 15920, 15925, 15930, 15935, 15940, 15945, 15950, 15955, + 15960, 15965, 15970, 15975, 15980, 15985, 15990, 15995, 16000, 16005, + 16010, 16015, 16020, 16025, 16030, 16035, 16040, 16045, 16050, 16055, + 16060, 16065, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16070, 16074, 16078, 16082, + 16086, 16090, 16094, 16098, 16102, 16106, 16110, 16114, 16118, 16122, + 16126, 16130, 16134, 16138, 16142, 16146, 16150, 16154, 16158, 16162, + 16166, 16170, 16174, 16178, 16182, 16186, 16190, 16194, 16198, 16202, + 16206, 16210, 16214, 16218, 16222, 16226, 16230, 16234, 16239, 16243, + 16248, 0, 0, 0, 16253, 16257, 16261, 16265, 16269, 16273, 16277, 16281, + 16285, 16289, 16293, 16297, 16301, 16305, 16309, 16313, 16317, 16321, + 16325, 16329, 16333, 16337, 16341, 16345, 16349, 16353, 16357, 16361, + 16365, 16369, 16373, 16377, 16381, 16385, 16389, 16393, 16397, 16401, + 16405, 16409, 16413, 16417, 16421, 16425, 16429, 16433, 16437, 16441, + 16445, 16449, 16453, 16457, 16461, 16465, 16469, 16473, 16477, 16481, + 16485, 16489, 16493, 16497, 16501, 16505, 16509, 16513, 16517, 16521, + 16525, 16529, 16533, 16537, 16541, 16545, 16549, 16553, 16557, 16561, + 16565, 16569, 16573, 16577, 16581, 16585, 16589, 16593, 16597, 16601, + 16605, 16609, 0, 0, 0, 0, 0, 16613, 16617, 16621, 16624, 16628, 16631, + 16635, 16639, 16642, 16646, 16650, 16653, 16657, 16661, 16665, 16669, + 16672, 16676, 16680, 16684, 16688, 16692, 16696, 16699, 16703, 16707, + 16711, 16715, 16719, 16723, 16727, 16731, 16735, 16739, 16743, 16747, + 16751, 16755, 16759, 16763, 16767, 16771, 16775, 16779, 16783, 16787, + 16791, 16795, 16799, 16803, 16807, 16811, 16815, 16819, 16823, 16827, + 16831, 16835, 16839, 16843, 16847, 16851, 16855, 16859, 16863, 16867, + 16871, 16875, 0, 0, 0, 0, 0, 16879, 16883, 16887, 16891, 16895, 16899, + 16903, 16907, 16911, 16915, 16919, 16923, 16927, 16931, 16935, 16939, + 16943, 16947, 16951, 16955, 16959, 16963, 16967, 16971, 16975, 16979, + 16983, 16987, 16991, 16995, 16999, 17003, 17007, 17011, 17015, 17019, + 17023, 17027, 17031, 17035, 17039, 17043, 17047, 17051, 17055, 17059, + 17063, 17067, 17071, 17075, 17079, 17083, 17087, 17091, 17095, 17099, + 17103, 17107, 17111, 17115, 17119, 17123, 17127, 17131, 17135, 17139, + 17143, 17147, 17151, 17155, 17159, 17163, 17167, 17171, 17175, 17179, + 17183, 17187, 17191, 17195, 17199, 17203, 0, 0, 0, 0, 0, 0, 17207, 17210, + 17214, 17218, 17222, 17226, 17230, 17234, 17238, 17242, 17246, 17250, + 17254, 17258, 17262, 17266, 17270, 17274, 17278, 17282, 17286, 17290, + 17294, 17298, 17302, 17305, 17309, 17313, 17317, 17321, 17325, 17329, + 17333, 17337, 17341, 17345, 17349, 17353, 17357, 17361, 17365, 17369, + 17373, 17377, 17381, 17385, 17389, 17393, 17397, 17401, 17405, 17409, + 17413, 17417, 17421, 17425, 17429, 17433, 17437, 17441, 17445, 17449, + 17453, 17457, 17461, 17465, 17469, 17473, 17477, 17481, 17485, 17489, + 17493, 0, 17497, 17501, 17505, 17509, 0, 0, 17513, 17517, 17521, 17525, + 17529, 17533, 17537, 0, 17541, 0, 17545, 17549, 17553, 17557, 0, 0, + 17561, 17565, 17569, 17573, 17577, 17581, 17585, 17589, 17593, 17597, + 17601, 17605, 17609, 17613, 17617, 17621, 17625, 17629, 17633, 17637, + 17641, 17645, 17649, 17652, 17656, 17660, 17664, 17668, 17672, 17676, + 17680, 17684, 17688, 17692, 17696, 17700, 17704, 17708, 17712, 17716, + 17720, 0, 17724, 17728, 17732, 17736, 0, 0, 17740, 17744, 17748, 17752, + 17756, 17760, 17764, 17768, 17772, 17776, 17780, 17784, 17788, 17792, + 17796, 17800, 17804, 17809, 17814, 17819, 17825, 17831, 17836, 17841, + 17847, 17850, 17854, 17858, 17862, 17866, 17870, 17874, 17878, 0, 17882, + 17886, 17890, 17894, 0, 0, 17898, 17902, 17906, 17910, 17914, 17918, + 17922, 0, 17926, 0, 17930, 17934, 17938, 17942, 0, 0, 17946, 17950, + 17954, 17958, 17962, 17966, 17970, 17974, 17978, 17983, 17988, 17993, + 17999, 18005, 18010, 0, 18015, 18019, 18023, 18027, 18031, 18035, 18039, + 18043, 18047, 18051, 18055, 18059, 18063, 18067, 18071, 18075, 18079, + 18082, 18086, 18090, 18094, 18098, 18102, 18106, 18110, 18114, 18118, + 18122, 18126, 18130, 18134, 18138, 18142, 18146, 18150, 18154, 18158, + 18162, 18166, 18170, 18174, 18178, 18182, 18186, 18190, 18194, 18198, + 18202, 18206, 18210, 18214, 18218, 18222, 18226, 18230, 18234, 18238, 0, + 18242, 18246, 18250, 18254, 0, 0, 18258, 18262, 18266, 18270, 18274, + 18278, 18282, 18286, 18290, 18294, 18298, 18302, 18306, 18310, 18314, + 18318, 18322, 18326, 18330, 18334, 18338, 18342, 18346, 18350, 18354, + 18358, 18362, 18366, 18370, 18374, 18378, 18382, 18386, 18390, 18394, + 18398, 18402, 18406, 18410, 18414, 18418, 18422, 18426, 18430, 18434, + 18438, 18442, 18446, 18450, 18454, 18458, 18462, 18466, 18470, 18474, + 18478, 18482, 18486, 18490, 18494, 18498, 18502, 18506, 18510, 18514, + 18518, 18522, 0, 0, 0, 0, 18526, 18531, 18535, 18538, 18542, 18545, + 18548, 18551, 18556, 18560, 18565, 18568, 18571, 18574, 18577, 18580, + 18583, 18586, 18589, 18592, 18596, 18600, 18604, 18608, 18612, 18616, + 18620, 18624, 18628, 18632, 0, 0, 0, 18638, 18644, 18648, 18652, 18656, + 18662, 18666, 18670, 18674, 18680, 18684, 18688, 18692, 18698, 18702, + 18706, 18710, 18716, 18722, 18728, 18736, 18742, 18748, 18754, 18760, + 18766, 0, 0, 0, 0, 0, 0, 18772, 18775, 18778, 18781, 18784, 18787, 18790, + 18794, 18797, 18801, 18805, 18809, 18813, 18817, 18820, 18824, 18828, + 18832, 18836, 18840, 18844, 18848, 18852, 18856, 18860, 18864, 18867, + 18871, 18875, 18879, 18883, 18887, 18891, 18895, 18899, 18903, 18907, + 18911, 18915, 18919, 18923, 18927, 18931, 18935, 18939, 18943, 18946, + 18950, 18954, 18958, 18962, 18966, 18970, 18974, 18978, 18982, 18986, + 18990, 18994, 18998, 19002, 19006, 19010, 19014, 19018, 19022, 19026, + 19030, 19034, 19038, 19042, 19046, 19050, 19054, 19058, 19062, 19066, + 19070, 19074, 19078, 19081, 19085, 19089, 19093, 19097, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 19101, 19104, 19108, 19111, 19115, 19118, 19122, 19128, + 19133, 19137, 19140, 19144, 19148, 19153, 19157, 19162, 19166, 19171, + 19175, 19180, 19184, 19189, 19195, 19199, 19204, 19208, 19213, 19219, + 19223, 19229, 19234, 19238, 19242, 19250, 19258, 19265, 19270, 19275, + 19284, 19291, 19298, 19303, 19309, 19313, 19317, 19321, 19325, 19329, + 19333, 19337, 19341, 19345, 19349, 19355, 19360, 19365, 19369, 19373, + 19377, 19382, 19386, 19391, 19395, 19400, 19404, 19409, 19413, 19418, + 19422, 19427, 19431, 19436, 19442, 19445, 19449, 19453, 19457, 19461, + 19465, 19469, 19472, 19476, 19482, 19487, 19492, 19496, 19500, 19504, + 19509, 19513, 19518, 19522, 19527, 19530, 19534, 19538, 19543, 19547, + 19552, 19556, 19561, 19567, 19570, 19574, 19578, 19582, 19586, 19590, + 19594, 19598, 19602, 19606, 19610, 19616, 19619, 19623, 19627, 19632, + 19636, 19641, 19645, 19650, 19654, 19659, 19663, 19668, 19672, 19677, + 19681, 19686, 19692, 19696, 19700, 19706, 19712, 19718, 19724, 19728, + 19732, 19736, 19740, 19744, 19748, 19754, 19758, 19762, 19766, 19771, + 19775, 19780, 19784, 19789, 19793, 19798, 19802, 19807, 19811, 19816, + 19820, 19825, 19831, 19835, 19841, 19845, 19849, 19853, 19857, 19861, + 19865, 19871, 19874, 19878, 19882, 19887, 19891, 19896, 19900, 19905, + 19909, 19914, 19918, 19923, 19927, 19932, 19936, 19941, 19947, 19950, + 19954, 19958, 19963, 19968, 19972, 19976, 19980, 19984, 19988, 19992, + 19998, 20002, 20006, 20010, 20015, 20019, 20024, 20028, 20033, 20039, + 20042, 20047, 20051, 20055, 20059, 20063, 20067, 20071, 20075, 20081, + 20085, 20089, 20093, 20098, 20102, 20107, 20111, 20116, 20120, 20125, + 20129, 20134, 20138, 20143, 20147, 20152, 20155, 20159, 20163, 20167, + 20171, 20175, 20179, 20183, 20187, 20193, 20197, 20201, 20205, 20210, + 20214, 20219, 20223, 20228, 20232, 20237, 20241, 20246, 20250, 20255, + 20259, 20264, 20270, 20273, 20278, 20282, 20287, 20293, 20299, 20305, + 20311, 20317, 20323, 20329, 20333, 20337, 20341, 20345, 20349, 20353, + 20357, 20361, 20366, 20370, 20375, 20379, 20384, 20388, 20393, 20397, + 20402, 20406, 20411, 20415, 20420, 20424, 20428, 20432, 20436, 20440, + 20444, 20448, 20454, 20457, 20461, 20465, 20470, 20474, 20479, 20483, + 20488, 20492, 20497, 20501, 20506, 20510, 20515, 20519, 20524, 20530, + 20534, 20540, 20545, 20551, 20555, 20561, 20566, 20570, 20574, 20578, + 20582, 20586, 20591, 20595, 20599, 20604, 20608, 20613, 20616, 20620, + 20624, 20628, 20632, 20636, 20640, 20644, 20648, 20652, 20656, 20660, + 20665, 20669, 20673, 20679, 20683, 20689, 20693, 20699, 20703, 20707, + 20711, 20715, 20719, 20724, 20728, 20732, 20736, 20740, 20744, 20748, + 20752, 20756, 20760, 20764, 20770, 20776, 20782, 20788, 20794, 20799, + 20805, 20810, 20815, 20819, 20823, 20827, 20831, 20835, 20839, 20843, + 20847, 20851, 20855, 20859, 20863, 20867, 20872, 20877, 20882, 20887, + 20891, 20895, 20899, 20903, 20907, 20911, 20915, 20919, 20923, 20929, + 20935, 20941, 20947, 20953, 20959, 20965, 20971, 20977, 20981, 20985, + 20989, 20993, 20997, 21001, 21005, 21011, 21017, 21023, 21029, 21035, + 21041, 21047, 21053, 21058, 21063, 21068, 21073, 21078, 21084, 21090, + 21096, 21102, 21108, 21114, 21120, 21126, 21132, 21138, 21144, 21149, + 21155, 21161, 21167, 21172, 21177, 21182, 21187, 21192, 21197, 21202, + 21207, 21212, 21217, 21222, 21227, 21232, 21237, 21242, 21247, 21252, + 21257, 21262, 21267, 21272, 21277, 21282, 21287, 21292, 21297, 21302, + 21307, 21312, 21317, 21322, 21327, 21332, 21337, 21342, 21347, 21352, + 21357, 21362, 21367, 21372, 21377, 21382, 21386, 21391, 21396, 21401, + 21406, 21411, 21416, 21421, 21426, 21431, 21436, 21441, 21446, 21451, + 21456, 21461, 21466, 21471, 21476, 21481, 21486, 21491, 21496, 21501, + 21506, 21511, 21516, 21521, 21526, 21531, 21536, 21540, 21545, 21550, + 21555, 21560, 21565, 21569, 21574, 21580, 21585, 21590, 21595, 21600, + 21606, 21611, 21616, 21621, 21626, 21631, 21636, 21641, 21646, 21651, + 21656, 21661, 21666, 21671, 21676, 21681, 21686, 21691, 21696, 21701, + 21706, 21711, 21716, 21721, 21726, 21731, 21736, 21741, 21746, 21751, + 21756, 21761, 21766, 21771, 21776, 21781, 21786, 21791, 21796, 21801, + 21806, 21811, 21816, 21821, 21826, 21832, 21837, 21842, 21847, 21852, + 21857, 21862, 21867, 21872, 21877, 21882, 21887, 21892, 21897, 21902, + 21907, 21912, 21917, 21922, 21927, 21932, 21937, 21942, 21947, 21952, + 21957, 21962, 21967, 21972, 21977, 21982, 21987, 21992, 21997, 22002, + 22007, 22012, 22017, 22022, 22027, 22031, 22035, 22039, 22043, 22047, + 22051, 22055, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22059, 22064, 22069, 22074, + 22079, 22084, 22089, 22094, 22099, 22104, 22109, 22114, 22119, 22124, + 22129, 22134, 22139, 22144, 22149, 22154, 22159, 22164, 22169, 22174, + 22179, 22184, 22189, 22194, 22199, 0, 0, 0, 22205, 22215, 22218, 22225, + 22229, 22233, 22237, 22245, 22249, 22254, 22259, 22264, 22268, 22273, + 22278, 22281, 22285, 22289, 22298, 22302, 22306, 22312, 22315, 22319, + 22326, 22330, 22338, 22343, 22348, 22353, 22358, 22367, 22372, 22376, + 22385, 22388, 22393, 22397, 22403, 22408, 22414, 22421, 22427, 22432, + 22439, 22444, 22448, 22452, 22461, 22466, 22469, 22478, 22483, 22487, + 22491, 22498, 22505, 22510, 22515, 22524, 22528, 22532, 22536, 22543, + 22550, 22554, 22558, 22562, 22566, 22570, 22574, 22578, 22582, 22586, + 22590, 22593, 22598, 22603, 22608, 22612, 22616, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 22620, 22624, 22628, 22632, 22636, 22641, 22646, + 22651, 22656, 22661, 22666, 22671, 22675, 0, 22679, 22684, 22689, 22694, + 22698, 22703, 22708, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22713, 22717, + 22721, 22725, 22729, 22734, 22739, 22744, 22749, 22754, 22759, 22764, + 22768, 22772, 22777, 22782, 22787, 22792, 22796, 22801, 22806, 22811, + 22817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22822, 22826, 22830, 22834, 22838, + 22843, 22848, 22853, 22858, 22863, 22868, 22873, 22877, 22881, 22886, + 22891, 22896, 22901, 22905, 22910, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 22915, 22919, 22923, 22927, 22931, 22936, 22941, 22946, 22951, 22956, + 22961, 22966, 22970, 0, 22974, 22979, 22984, 0, 22989, 22994, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 22999, 23002, 23006, 23010, 23014, 23018, 23022, + 23026, 23030, 23034, 23038, 23042, 23046, 23050, 23054, 23058, 23062, + 23066, 23069, 23073, 23077, 23081, 23085, 23089, 23093, 23097, 23101, + 23105, 23109, 23113, 23117, 23121, 23125, 23128, 23132, 23136, 23142, + 23148, 23154, 23160, 23166, 23172, 23178, 23184, 23190, 23196, 23202, + 23208, 23214, 23220, 23229, 23238, 23244, 23250, 23256, 23261, 23265, + 23270, 23275, 23280, 23284, 23289, 23294, 23299, 23303, 23308, 23312, + 23317, 23322, 23327, 23332, 23336, 23340, 23344, 23348, 23352, 23356, + 23360, 23364, 23368, 23372, 23378, 23382, 23386, 23390, 23394, 23398, + 23406, 23412, 23416, 23422, 23426, 23432, 23436, 0, 0, 23440, 23444, + 23447, 23450, 23453, 23456, 23459, 23462, 23465, 23468, 0, 0, 0, 0, 0, 0, + 23471, 23479, 23487, 23495, 23503, 23511, 23519, 23527, 23535, 23543, 0, + 0, 0, 0, 0, 0, 23551, 23554, 23557, 23560, 23564, 23567, 23572, 23579, + 23587, 23592, 23598, 23601, 23608, 23615, 23622, 0, 23626, 23630, 23633, + 23636, 23639, 23642, 23645, 23648, 23651, 23654, 0, 0, 0, 0, 0, 0, 23657, + 23660, 23663, 23666, 23669, 23672, 23676, 23680, 23684, 23688, 23692, + 23696, 23700, 23704, 23708, 23711, 23715, 23719, 23723, 23727, 23731, + 23735, 23739, 23742, 23746, 23750, 23754, 23757, 23761, 23765, 23769, + 23773, 23777, 23781, 23785, 23789, 23796, 23801, 23806, 23811, 23816, + 23822, 23828, 23834, 23840, 23846, 23852, 23858, 23863, 23869, 23875, + 23881, 23887, 23893, 23898, 23904, 23909, 23915, 23921, 23927, 23933, + 23939, 23944, 23949, 23955, 23961, 23966, 23972, 23977, 23983, 23988, + 23994, 24000, 24006, 24012, 24018, 24024, 24030, 24036, 24042, 24048, + 24054, 24060, 24066, 24071, 24076, 24082, 24088, 0, 0, 0, 0, 0, 0, 0, 0, + 24094, 24103, 24112, 24120, 24128, 24138, 24146, 24155, 24162, 24169, + 24176, 24184, 24192, 24200, 24208, 24216, 24224, 24232, 24240, 24248, + 24256, 24264, 24272, 24280, 24288, 24298, 24308, 24318, 24328, 24338, + 24348, 24358, 24368, 24378, 24388, 24398, 24408, 24418, 24428, 24436, + 24444, 24454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24462, 24467, + 24470, 24474, 24478, 24482, 24486, 24490, 24494, 24498, 24502, 24506, + 24510, 24514, 24518, 24522, 24526, 24530, 24534, 24538, 24542, 24545, + 24548, 24552, 24556, 24560, 24564, 24568, 24572, 0, 0, 0, 24575, 24579, + 24583, 24587, 24592, 24597, 24602, 24607, 24611, 24615, 24619, 24624, 0, + 0, 0, 0, 24629, 24633, 24638, 24643, 24648, 24653, 24658, 24662, 24667, + 24672, 24676, 24680, 0, 0, 0, 0, 24684, 0, 0, 0, 24688, 24692, 24696, + 24700, 24703, 24706, 24709, 24712, 24715, 24718, 24721, 24724, 24727, + 24732, 24738, 24744, 24750, 24756, 24761, 24767, 24773, 24779, 24785, + 24791, 24796, 24802, 24808, 24813, 24819, 24825, 24831, 24837, 24842, + 24847, 24853, 24859, 24864, 24870, 24875, 24881, 24886, 24892, 0, 0, + 24898, 24904, 24910, 24916, 24922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24928, 24935, 24942, 24948, 24955, 24962, 24968, 24975, 24982, 24989, + 24996, 25002, 25009, 25016, 25022, 25029, 25036, 25043, 25050, 25057, + 25064, 25071, 25078, 25084, 25091, 25098, 25104, 25111, 25118, 25125, + 25132, 25139, 25146, 25152, 25159, 25166, 25172, 25179, 25186, 25193, + 25200, 25207, 0, 0, 0, 0, 0, 0, 25214, 25222, 25229, 25236, 25242, 25249, + 25255, 25262, 25268, 25275, 25282, 25289, 25296, 25303, 25310, 25317, + 25324, 25331, 25337, 25344, 25350, 25356, 25363, 25369, 25375, 25381, 0, + 0, 0, 0, 0, 0, 25387, 25393, 25398, 25403, 25408, 25413, 25418, 25423, + 25428, 25433, 0, 0, 0, 0, 25438, 25444, 25450, 25454, 25460, 25466, + 25472, 25478, 25484, 25490, 25496, 25502, 25508, 25514, 25520, 25526, + 25532, 25538, 25544, 25548, 25554, 25560, 25566, 25572, 25578, 25584, + 25590, 25596, 25602, 25608, 25614, 25620, 25626, 25632, 25638, 25642, + 25647, 25652, 25657, 25662, 25667, 25671, 25676, 25681, 25686, 25691, + 25696, 25701, 25706, 25711, 25716, 25720, 25725, 25730, 25735, 25740, + 25744, 25748, 25753, 25758, 25763, 25768, 0, 0, 25774, 25778, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25785, 25790, + 25796, 25802, 25809, 25815, 25820, 25826, 25831, 25838, 25843, 25848, + 25854, 25862, 25867, 25873, 25878, 25885, 25891, 25899, 25907, 25913, + 25919, 25926, 25933, 25938, 25944, 25950, 25955, 25960, 25966, 25974, + 25981, 25986, 25992, 25998, 26004, 26012, 26016, 26022, 26028, 26034, + 26040, 26046, 26052, 26056, 26061, 26065, 26071, 26075, 26079, 26084, + 26088, 26092, 26096, 26100, 26105, 26109, 26113, 26117, 26122, 26126, + 26131, 26135, 26139, 26143, 26147, 26152, 26156, 26161, 26166, 26172, + 26176, 26180, 26184, 26189, 26195, 26202, 26206, 26211, 26216, 26220, + 26225, 26229, 26235, 26242, 26249, 26253, 26257, 26261, 26267, 26272, + 26276, 26281, 26286, 26292, 26297, 26303, 26308, 26314, 26320, 26326, + 26332, 26339, 26346, 26353, 26360, 26367, 26372, 26380, 26389, 26398, + 26407, 26416, 26425, 26434, 26446, 26455, 26464, 26473, 26478, 26483, + 26489, 26497, 26504, 26511, 26518, 26525, 26532, 26540, 26549, 26558, + 26567, 26576, 26585, 26594, 26603, 26612, 26621, 26630, 26639, 26648, + 26657, 26666, 26674, 26682, 26693, 26701, 26711, 26722, 26731, 26739, + 26749, 26758, 26766, 26775, 26781, 26786, 26794, 26799, 26806, 26811, + 26820, 26825, 26830, 26836, 26841, 26846, 26853, 26861, 26870, 26879, + 26884, 26891, 26901, 26909, 26918, 26923, 26929, 26934, 26941, 26946, + 26955, 26960, 26965, 26970, 26977, 26982, 26987, 26996, 27004, 27009, + 27014, 27021, 27028, 27032, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27036, + 27044, 27052, 27059, 27066, 27073, 27080, 27088, 27096, 27106, 27116, + 27124, 27132, 27140, 27148, 27157, 27166, 27174, 27182, 27190, 27198, + 27207, 27216, 27225, 27234, 27241, 27248, 27256, 27264, 27274, 27284, + 27292, 27300, 27307, 27314, 27322, 27330, 27338, 27346, 27353, 27360, + 27368, 27376, 27385, 27394, 27402, 27410, 27419, 27428, 27435, 27442, + 27450, 27458, 27467, 27476, 27484, 27492, 27503, 27514, 27523, 27532, + 27540, 27548, 27555, 27562, 27570, 27578, 27586, 27594, 27602, 27610, + 27618, 27626, 27635, 27644, 27652, 27660, 27669, 27678, 27687, 27696, + 27705, 27714, 27723, 27732, 27739, 27746, 27754, 27762, 27770, 27778, + 27786, 27794, 27805, 27816, 27825, 27834, 27842, 27850, 27858, 27866, + 27877, 27888, 27899, 27910, 27922, 27934, 27942, 27950, 27958, 27966, + 27975, 27984, 27992, 28000, 28008, 28016, 28024, 28032, 28039, 28046, + 28055, 28064, 28073, 28082, 28089, 28096, 28104, 28112, 28119, 28126, + 28133, 28140, 28147, 28154, 28162, 28170, 28178, 28186, 28194, 28202, + 28209, 28216, 28224, 28232, 28240, 28248, 28256, 28264, 28273, 28282, + 28291, 28298, 28307, 28316, 28325, 0, 0, 0, 0, 28334, 28341, 28348, + 28356, 28364, 28372, 28380, 28388, 28396, 28406, 28416, 28424, 28432, + 28441, 28450, 28459, 28468, 28477, 28486, 28497, 28508, 28517, 28526, + 28536, 28546, 28553, 28560, 28568, 28576, 28582, 28588, 28596, 28604, + 28612, 28620, 28630, 28640, 28648, 28656, 28665, 28674, 28682, 28690, + 28697, 28704, 28711, 28718, 28726, 28734, 28742, 28750, 28758, 28766, + 28776, 28786, 28794, 28802, 28811, 28820, 28829, 28838, 28847, 28856, + 28867, 28878, 28887, 28896, 28906, 28916, 28923, 28930, 28938, 28946, + 28955, 28964, 28973, 28982, 28993, 29004, 29013, 29022, 29032, 29042, + 29049, 29056, 29064, 29072, 29081, 29090, 29097, 0, 0, 0, 0, 0, 0, 29104, + 29111, 29118, 29126, 29134, 29142, 29150, 29159, 29168, 29175, 29182, + 29190, 29198, 29206, 29214, 29223, 29232, 29240, 29248, 29257, 29266, + 29275, 0, 0, 29284, 29292, 29300, 29309, 29318, 29327, 0, 0, 29336, + 29344, 29352, 29361, 29370, 29379, 29388, 29398, 29408, 29416, 29424, + 29433, 29442, 29451, 29460, 29470, 29480, 29488, 29496, 29505, 29514, + 29523, 29532, 29542, 29552, 29560, 29568, 29577, 29586, 29595, 29604, + 29614, 29624, 29632, 29640, 29649, 29658, 29667, 0, 0, 29676, 29684, + 29692, 29701, 29710, 29719, 0, 0, 29728, 29736, 29744, 29753, 29762, + 29771, 29780, 29790, 0, 29800, 0, 29808, 0, 29817, 0, 29826, 29836, + 29843, 29850, 29858, 29866, 29874, 29882, 29891, 29900, 29907, 29914, + 29922, 29930, 29938, 29946, 29955, 29964, 29970, 29976, 29983, 29990, + 29997, 30004, 30011, 30018, 30025, 30032, 30039, 30046, 30052, 0, 0, + 30058, 30067, 30076, 30088, 30100, 30112, 30124, 30136, 30148, 30157, + 30166, 30178, 30190, 30202, 30214, 30226, 30238, 30248, 30258, 30271, + 30284, 30297, 30310, 30323, 30336, 30346, 30356, 30369, 30382, 30395, + 30408, 30421, 30434, 30443, 30452, 30464, 30476, 30488, 30500, 30512, + 30524, 30533, 30542, 30554, 30566, 30578, 30590, 30602, 30614, 30621, + 30627, 30637, 30644, 0, 30654, 30661, 30671, 30678, 30684, 30690, 30696, + 30703, 30706, 30709, 30712, 30715, 30721, 30732, 30740, 0, 30751, 30759, + 30770, 30777, 30784, 30791, 30798, 30806, 30810, 30814, 30819, 30827, + 30834, 30844, 0, 0, 30854, 30862, 30873, 30881, 30888, 30895, 0, 30902, + 30906, 30910, 30915, 30923, 30930, 30940, 30950, 30958, 30966, 30974, + 30985, 30993, 31000, 31007, 31014, 31022, 31027, 31032, 0, 0, 31034, + 31044, 31051, 0, 31061, 31068, 31078, 31085, 31092, 31098, 31104, 31111, + 31113, 0, 31116, 31120, 31124, 31128, 31132, 31136, 31140, 31144, 31148, + 31152, 31156, 31160, 31166, 31172, 31178, 31181, 31184, 31186, 31190, + 31194, 31198, 31202, 31204, 31208, 31212, 31218, 31224, 31231, 31238, + 31243, 31248, 31254, 31260, 31262, 31265, 31267, 31271, 31276, 31280, + 31283, 31287, 31291, 31295, 31299, 31303, 31309, 31313, 31317, 31323, + 31328, 31335, 31337, 31340, 31344, 31347, 31351, 31356, 31358, 31366, + 31374, 31377, 31381, 31383, 31385, 31387, 31390, 31396, 31398, 31402, + 31406, 31413, 31420, 31424, 31429, 31434, 31439, 31443, 31447, 31451, + 31454, 31457, 31461, 31468, 31473, 31477, 31481, 31486, 31490, 31494, + 31499, 31504, 31508, 31512, 31516, 31518, 31523, 31528, 31532, 31536, + 31540, 0, 0, 0, 0, 0, 0, 31544, 31550, 31556, 31563, 31570, 31575, 31580, + 31584, 0, 0, 31590, 31593, 31596, 31599, 31602, 31605, 31608, 31613, + 31617, 31622, 31627, 31632, 31638, 31642, 31645, 31648, 31651, 31654, + 31657, 31660, 31663, 31666, 31669, 31674, 31678, 31683, 31688, 0, 31693, + 31699, 31705, 31711, 31717, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31724, + 31727, 31730, 31733, 31738, 31741, 31744, 31747, 31750, 31753, 31756, + 31760, 31763, 31766, 31769, 31772, 31775, 31780, 31783, 31786, 31789, + 31792, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 31795, 31799, 31803, 31810, 31818, 31823, 31828, 31832, + 31836, 31841, 31848, 31855, 31859, 31864, 31869, 31874, 31879, 31885, + 31890, 31895, 31900, 31909, 31916, 31923, 31927, 31932, 31938, 31943, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31950, 31954, + 31961, 31965, 31969, 31974, 31978, 31982, 31986, 31988, 31992, 31995, + 31998, 32002, 32005, 32009, 32018, 32021, 32025, 32028, 32031, 32037, + 32040, 32043, 32049, 32052, 32055, 32059, 32062, 32066, 32069, 32073, + 32075, 32078, 32081, 32085, 32087, 32091, 32094, 32097, 32102, 32107, + 32113, 32116, 32119, 32122, 32127, 32130, 32133, 32136, 32140, 32144, + 32147, 32150, 32152, 32155, 32158, 32161, 32165, 32170, 32173, 32177, + 32181, 32185, 32189, 32194, 32198, 32202, 32206, 32211, 32215, 32219, + 32223, 32227, 32231, 32235, 32238, 0, 0, 0, 0, 0, 0, 32241, 32249, 32256, + 32264, 32271, 32278, 32286, 32294, 32302, 32310, 32317, 32325, 32333, + 32338, 32342, 32346, 32350, 32354, 32358, 32362, 32366, 32370, 32374, + 32379, 32384, 32389, 32394, 32401, 32408, 32415, 32420, 32425, 32430, + 32435, 32440, 32445, 32450, 32455, 32460, 32466, 32472, 32478, 32484, + 32492, 32500, 32508, 32518, 32525, 32532, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 32540, 32542, 32545, 32547, 32550, 32553, 32556, 32561, 32566, + 32571, 32576, 32580, 32584, 32588, 32592, 32597, 32603, 32608, 32614, + 32619, 32624, 32629, 32635, 32640, 32646, 32652, 32656, 32660, 32665, + 32670, 32675, 32680, 32685, 32693, 32701, 32709, 32717, 32724, 32732, + 32739, 32746, 32754, 32765, 32771, 32777, 32783, 32789, 32796, 32803, + 32809, 32815, 32822, 32829, 32835, 32843, 32849, 32854, 32860, 32865, + 32871, 32878, 32885, 32890, 32896, 32901, 32904, 32908, 32911, 32915, + 32919, 32923, 32929, 32935, 32941, 32947, 32951, 32955, 32959, 32963, + 32969, 32975, 32979, 32984, 32988, 32993, 32997, 33001, 33004, 33008, + 33011, 33015, 33022, 33030, 33041, 33052, 33057, 33066, 33073, 33081, + 33089, 33093, 33099, 33107, 33111, 33116, 33121, 33127, 33133, 33139, + 33146, 33150, 33154, 33159, 33162, 33164, 33168, 33172, 33179, 33183, + 33185, 33187, 33191, 33198, 33203, 33209, 33218, 33225, 33230, 33234, + 33238, 33242, 33245, 33248, 33251, 33255, 33259, 33263, 33267, 33271, + 33274, 33278, 33282, 33285, 33287, 33290, 33292, 33296, 33300, 33302, + 33307, 33310, 33314, 33318, 33322, 33324, 33326, 33328, 33331, 33335, + 33339, 33343, 33347, 33351, 33357, 33363, 33365, 33367, 33369, 33371, + 33374, 33376, 33380, 33382, 33386, 33388, 33393, 33397, 33401, 33403, + 33406, 33410, 33415, 33419, 33428, 33438, 33442, 33447, 33453, 33456, + 33460, 33463, 33468, 33472, 33478, 33482, 33493, 33501, 33505, 33509, + 33515, 33519, 33522, 33524, 33527, 33531, 33535, 33541, 33545, 33549, + 33552, 33555, 33559, 33564, 33569, 33574, 33580, 33586, 33593, 33600, + 33604, 33608, 33610, 33614, 33617, 33620, 33628, 33636, 33642, 33648, + 33657, 33666, 33671, 33676, 33684, 33692, 33694, 33696, 33701, 33706, + 33712, 33718, 33723, 33728, 33732, 33736, 33742, 33748, 33754, 33760, + 33770, 33780, 33787, 33794, 33796, 33800, 33804, 33809, 33814, 33821, + 33828, 33831, 33834, 33837, 33840, 33843, 33848, 33852, 33857, 33862, + 33865, 33868, 33872, 33876, 33880, 33885, 33888, 33891, 33894, 33897, + 33899, 33901, 33903, 33905, 33913, 33921, 33926, 33929, 33934, 33944, + 33950, 33956, 33962, 33970, 33978, 33989, 33993, 33997, 33999, 34005, + 34007, 34009, 34011, 34013, 34018, 34021, 34027, 34033, 34037, 34041, + 34045, 34048, 34052, 34056, 34058, 34067, 34076, 34081, 34086, 34091, + 34097, 34103, 34106, 34109, 34112, 34115, 34117, 34122, 34127, 34132, + 34138, 34144, 34151, 34158, 34163, 34168, 34173, 34178, 34186, 34194, + 34202, 34210, 34218, 34226, 34234, 34242, 34250, 34258, 34265, 34276, + 34285, 34299, 34302, 34307, 34313, 34319, 34326, 34340, 34355, 34361, + 34367, 34374, 34380, 34388, 34394, 34407, 34421, 34426, 34432, 34439, + 34442, 34445, 34447, 34450, 34453, 34455, 34457, 34461, 34464, 34467, + 34470, 34473, 34478, 34483, 34488, 34493, 34496, 34499, 34501, 34503, + 34505, 34509, 34513, 34517, 34523, 34526, 34528, 34530, 34535, 34540, + 34545, 34550, 34555, 34560, 34562, 34564, 34573, 34577, 34583, 34592, + 34594, 34598, 34602, 34609, 34613, 34615, 34619, 34621, 34625, 34629, + 34633, 34635, 34637, 34639, 34644, 34651, 34658, 34665, 34672, 34679, + 34686, 34692, 34698, 34704, 34710, 34717, 34724, 34731, 34738, 34744, + 34750, 34757, 34764, 34770, 34778, 34785, 34793, 34800, 34808, 34815, + 34823, 34831, 34838, 34846, 34853, 34861, 34868, 34876, 34883, 34890, + 34897, 34904, 34910, 34918, 34925, 34931, 34938, 34945, 34951, 34957, + 34963, 34968, 34976, 34984, 34990, 34996, 35002, 35008, 35013, 35019, + 35026, 35034, 35041, 35048, 35055, 35060, 35065, 35070, 35076, 35083, + 35090, 35096, 35101, 35105, 35113, 35119, 35122, 35130, 35133, 35138, + 35143, 35146, 35149, 35157, 35160, 35165, 35168, 35175, 35180, 35187, + 35190, 35193, 35196, 35201, 35206, 35209, 35212, 35220, 35223, 35228, + 35235, 35239, 35243, 35248, 35253, 35258, 35263, 35268, 35273, 35278, + 35283, 35290, 35296, 35303, 35310, 35316, 35323, 35330, 35339, 35346, + 35352, 35359, 35368, 35375, 35379, 35384, 35395, 35406, 35410, 35414, + 35418, 35422, 35433, 35437, 35442, 35447, 35452, 35457, 35462, 35467, + 35476, 35485, 35493, 35503, 35513, 35521, 35531, 35541, 35549, 35559, + 35569, 35577, 35585, 35595, 35605, 35608, 35611, 35614, 35619, 35623, + 35630, 35638, 35646, 35655, 35662, 35666, 35670, 35674, 35678, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 35680, 35684, 35691, 35698, 35705, 35712, + 35716, 35720, 35724, 35728, 35733, 35739, 35744, 35750, 35756, 35762, + 35768, 35776, 35783, 35790, 35797, 35804, 35810, 35816, 35825, 35829, + 35836, 35840, 35844, 35850, 35856, 35862, 35868, 35872, 35876, 35879, + 35883, 35887, 35894, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 35901, 35904, 35908, 35912, 35918, 35924, 35930, + 35938, 35945, 35949, 35957, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 35962, 35965, 35968, 35971, 35974, 35977, 35980, 35983, + 35986, 35989, 35993, 35997, 36001, 36005, 36009, 36013, 36017, 36021, + 36025, 36029, 36033, 36036, 36039, 36042, 36045, 36048, 36051, 36054, + 36057, 36060, 36064, 36068, 36072, 36076, 36080, 36084, 36088, 36092, + 36096, 36100, 36104, 36110, 36115, 36120, 36126, 36132, 36138, 36144, + 36150, 36156, 36162, 36168, 36174, 36180, 36186, 36192, 36198, 36204, + 36210, 36216, 36222, 36227, 36232, 36238, 36243, 36248, 36254, 36259, + 36264, 36269, 36274, 36280, 36285, 36290, 36295, 36300, 36305, 36311, + 36316, 36321, 36326, 36331, 36336, 36342, 36347, 36353, 36359, 36364, + 36369, 36375, 36380, 36385, 36391, 36396, 36401, 36406, 36411, 36417, + 36422, 36427, 36432, 36437, 36442, 36448, 36453, 36458, 36463, 36468, + 36473, 36479, 36484, 36490, 36496, 36501, 36506, 36512, 36517, 36522, + 36528, 36533, 36538, 36543, 36548, 36554, 36559, 36564, 36569, 36574, + 36579, 36585, 36590, 36595, 36600, 36605, 36610, 36616, 36621, 36627, + 36633, 36637, 36643, 36649, 36655, 36661, 36667, 36673, 36679, 36685, + 36691, 36697, 36701, 36705, 36709, 36713, 36717, 36721, 36725, 36729, + 36733, 36738, 36744, 36749, 36754, 36759, 36764, 36773, 36782, 36791, + 36800, 36809, 36818, 36827, 36836, 36842, 36850, 36858, 36864, 36871, + 36879, 36887, 36894, 36900, 36908, 36916, 36922, 36929, 36937, 36945, + 36952, 36958, 36966, 36975, 36984, 36992, 37001, 37010, 37016, 37023, + 37031, 37040, 37049, 37057, 37066, 37075, 37082, 37089, 37098, 37107, + 37115, 37123, 37132, 37141, 37148, 37155, 37164, 37173, 37181, 37189, + 37198, 37207, 37214, 37221, 37230, 37239, 37247, 37256, 37265, 37273, + 37283, 37293, 37303, 37313, 37322, 37331, 37340, 37349, 37356, 37364, + 37372, 37380, 37388, 37393, 37398, 37407, 37415, 37421, 37430, 37438, + 37445, 37454, 37462, 37468, 37477, 37485, 37492, 37501, 37509, 37515, + 37524, 37532, 37539, 37548, 37556, 37563, 37572, 37580, 37587, 37596, + 37604, 37611, 37619, 37628, 37637, 37645, 37656, 37666, 37673, 37678, + 37683, 37687, 37692, 37697, 37702, 37706, 37711, 37718, 37726, 37733, + 37741, 37745, 37752, 37759, 37765, 37769, 37776, 37782, 37789, 37793, + 37800, 37806, 37813, 37817, 37823, 37830, 37837, 37841, 37844, 37848, + 37852, 37859, 37866, 37871, 37875, 37880, 37890, 37897, 37908, 37918, + 37922, 37930, 37940, 37943, 37946, 37953, 37961, 37966, 37971, 37979, + 37988, 37997, 38005, 38009, 38013, 38016, 38019, 38023, 38027, 38030, + 38033, 38038, 38043, 38049, 38055, 38060, 38065, 38071, 38077, 38082, + 38087, 38092, 38097, 38103, 38109, 38114, 38119, 38125, 38131, 38136, + 38141, 38144, 38147, 38156, 38158, 38160, 38163, 38167, 38172, 38174, + 38177, 38183, 38189, 38195, 38201, 38209, 38221, 38226, 38231, 38235, + 38240, 38247, 38254, 38262, 38270, 38278, 38286, 38290, 38294, 38299, + 38304, 38309, 38314, 38317, 38323, 38329, 38338, 38347, 38355, 38363, + 38372, 38381, 38385, 38392, 38399, 38406, 38413, 38420, 38427, 38434, + 38441, 38445, 38449, 38453, 38458, 38463, 38469, 38475, 38479, 38485, + 38487, 38489, 38491, 38493, 38496, 38499, 38501, 38503, 38505, 38509, + 38513, 38515, 38517, 38520, 38523, 38527, 38533, 38538, 38540, 38547, + 38551, 38556, 38561, 38563, 38572, 38578, 38584, 38590, 38596, 38602, + 38608, 38613, 38616, 38619, 38622, 38624, 38626, 38630, 38634, 38639, + 38644, 38649, 38652, 38656, 38661, 38664, 38668, 38673, 38678, 38683, + 38688, 38693, 38698, 38703, 38708, 38713, 38718, 38723, 38728, 38734, + 38740, 38746, 38748, 38751, 38753, 38756, 38758, 38760, 38762, 38764, + 38766, 38768, 38770, 38772, 38774, 38776, 38778, 38780, 38782, 38784, + 38786, 38788, 38790, 38795, 38800, 38805, 38810, 38815, 38820, 38825, + 38830, 38835, 38840, 38845, 38850, 38855, 38860, 38865, 38870, 38875, + 38880, 38885, 38890, 38894, 38898, 38902, 38908, 38914, 38919, 38924, + 38929, 38934, 38939, 38944, 38952, 38960, 38968, 38976, 38984, 38992, + 39000, 39008, 39014, 39019, 39024, 39029, 39032, 39036, 39040, 39044, + 39048, 39052, 39056, 39061, 39067, 39073, 39080, 39085, 39090, 39097, + 39104, 39111, 39118, 39121, 39124, 39129, 39131, 39135, 39140, 39142, + 39144, 39146, 39148, 39153, 39156, 0, 0, 0, 39158, 39161, 39165, 39170, + 39175, 39183, 39189, 39195, 39207, 39214, 39221, 39226, 39231, 39237, + 39240, 39243, 39248, 39250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39254, 39259, 39262, + 39267, 0, 39270, 39275, 39279, 39281, 0, 0, 39283, 39287, 39291, 39295, + 39297, 39301, 39304, 39307, 39310, 39314, 39317, 39321, 39324, 39328, + 39333, 39337, 39343, 39350, 39353, 39359, 39364, 39368, 39373, 39379, + 39385, 39392, 39398, 39405, 0, 39412, 39419, 39423, 39430, 39436, 39441, + 39447, 39451, 39456, 39459, 39465, 39471, 39478, 39486, 39493, 39502, + 39512, 39519, 39525, 39529, 39537, 39542, 39551, 39554, 39557, 39566, + 39577, 39584, 39586, 39592, 39597, 39599, 39602, 39606, 39614, 0, 39623, + 0, 39628, 39635, 39642, 39649, 0, 0, 0, 39656, 0, 39663, 39666, 39670, + 39673, 39684, 39694, 39704, 0, 0, 39713, 39722, 39728, 39736, 39740, + 39748, 39752, 39760, 39767, 39774, 39783, 39792, 39801, 39810, 39819, + 39828, 39836, 39844, 39854, 39864, 39873, 39882, 39889, 39896, 39903, + 39910, 39917, 39924, 39931, 39938, 39945, 39953, 39959, 39965, 39971, + 39977, 39983, 39989, 39995, 40001, 40007, 40014, 40022, 40030, 40038, + 40046, 40054, 40062, 40070, 40078, 40086, 40095, 0, 0, 0, 40100, 40106, + 40109, 40115, 40121, 40126, 40130, 40135, 40141, 40148, 40151, 40158, + 40165, 40169, 40178, 40187, 40192, 40198, 40203, 40208, 40215, 40222, + 40229, 40236, 0, 40244, 40252, 40257, 40261, 40268, 40272, 40279, 40287, + 40292, 40300, 40304, 40309, 40313, 40318, 0, 40322, 40327, 40336, 40338, + 40342, 40346, 40353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40360, 40368, 40372, + 40379, 40386, 40393, 40398, 40403, 40409, 40414, 40419, 40425, 40430, + 40433, 40437, 40441, 40447, 40456, 40461, 40470, 40479, 40485, 40491, + 40496, 40501, 40505, 40509, 40514, 0, 0, 0, 0, 40519, 40524, 40529, + 40535, 40541, 40547, 40550, 40553, 40557, 40561, 40565, 40570, 40576, + 40582, 40589, 40596, 40601, 40605, 40609, 40613, 40617, 40621, 40625, + 40629, 40633, 40637, 40641, 40645, 40649, 40653, 40657, 40661, 40665, + 40669, 40673, 40677, 40681, 40685, 40689, 40693, 40697, 40701, 40705, + 40709, 40713, 40717, 40721, 40725, 40729, 40733, 40737, 40741, 40745, + 40749, 40753, 40757, 40761, 40765, 40769, 40773, 40777, 40781, 40785, + 40789, 40793, 40797, 40801, 40805, 40809, 40813, 40817, 40821, 40825, + 40829, 40833, 40837, 40841, 40845, 40849, 40853, 40857, 40861, 40865, + 40869, 40873, 40877, 40881, 40885, 40889, 40893, 40897, 40901, 40905, + 40909, 40913, 40917, 40921, 40925, 40929, 40933, 40937, 40941, 40945, + 40949, 40953, 40957, 40961, 40965, 40969, 40973, 40977, 40981, 40985, + 40989, 40993, 40997, 41001, 41005, 41009, 41013, 41017, 41021, 41025, + 41029, 41033, 41037, 41041, 41045, 41049, 41053, 41057, 41061, 41065, + 41069, 41073, 41077, 41081, 41085, 41089, 41093, 41097, 41101, 41105, + 41109, 41113, 41117, 41121, 41125, 41129, 41133, 41137, 41141, 41145, + 41149, 41153, 41157, 41161, 41165, 41169, 41173, 41177, 41181, 41185, + 41189, 41193, 41197, 41201, 41205, 41209, 41213, 41217, 41221, 41225, + 41229, 41233, 41237, 41241, 41245, 41249, 41253, 41257, 41261, 41265, + 41269, 41273, 41277, 41281, 41285, 41289, 41293, 41297, 41301, 41305, + 41309, 41313, 41317, 41321, 41325, 41329, 41333, 41337, 41341, 41345, + 41349, 41353, 41357, 41361, 41365, 41369, 41373, 41377, 41381, 41385, + 41389, 41393, 41397, 41401, 41405, 41409, 41413, 41417, 41421, 41425, + 41429, 41433, 41437, 41441, 41445, 41449, 41453, 41457, 41461, 41465, + 41469, 41473, 41477, 41481, 41485, 41489, 41493, 41497, 41501, 41505, + 41509, 41513, 41517, 41521, 41525, 41529, 41533, 41537, 41541, 41545, + 41549, 41553, 41557, 41561, 41565, 41569, 41573, 41577, 41581, 41585, + 41589, 41593, 41597, 41601, 41605, 41609, 41613, 41617, 41621, 41625, + 41632, 41640, 41646, 41652, 41659, 41666, 41672, 41678, 41684, 41690, + 41695, 41700, 41705, 41710, 41716, 41722, 41730, 41737, 41742, 41747, + 41755, 41764, 41771, 41781, 41792, 41795, 41798, 41802, 41806, 41812, + 41818, 41828, 41838, 41848, 41858, 41865, 41872, 41879, 41886, 41897, + 41908, 41919, 41930, 41940, 41950, 41962, 41974, 41985, 41996, 42008, + 42020, 42028, 42038, 42048, 42059, 42070, 42077, 42084, 42091, 42098, + 42108, 42118, 42125, 42132, 42138, 42144, 42151, 42158, 42165, 42171, + 42177, 42182, 42190, 42200, 42208, 42216, 42224, 42232, 42240, 42248, + 42256, 42264, 42271, 42278, 42286, 42294, 42301, 42308, 42316, 42324, + 42332, 42340, 42349, 42358, 42366, 42374, 42383, 42392, 42404, 42418, + 42430, 42444, 42456, 42468, 42480, 42492, 42501, 42511, 42520, 42530, + 42544, 42558, 42566, 42572, 42579, 42586, 42593, 42600, 42605, 42611, + 42616, 42621, 42627, 42632, 42637, 42642, 42647, 42652, 42659, 42664, + 42671, 42676, 42681, 42685, 42689, 42696, 42703, 42710, 42717, 42724, + 42731, 42744, 42757, 42770, 42783, 42790, 42797, 42803, 42809, 42816, + 42823, 42830, 42837, 42841, 42846, 42853, 42860, 42867, 42873, 42877, + 42884, 42891, 42894, 42897, 42901, 42906, 42913, 42920, 42938, 42957, + 42975, 42994, 43013, 43032, 43051, 43070, 43075, 43082, 43090, 43098, + 43106, 43110, 43113, 43116, 43121, 43124, 43142, 43147, 43153, 43159, + 43163, 43166, 43169, 43172, 43180, 43190, 43198, 43206, 43210, 43215, + 43219, 43224, 43229, 43234, 43240, 43249, 43256, 43263, 43271, 43278, + 43285, 43288, 43295, 43302, 43305, 43308, 43313, 43318, 43324, 43330, + 43334, 43340, 43347, 43351, 43357, 43361, 43365, 43373, 43385, 43393, + 43397, 43399, 43408, 43417, 43423, 43426, 43431, 43436, 43441, 43446, + 43451, 43456, 43461, 43466, 43468, 43474, 43479, 43486, 43490, 43496, + 43499, 43503, 43509, 43515, 43517, 43519, 43525, 43532, 43539, 43548, + 43557, 43564, 43571, 43577, 43583, 43589, 43594, 43599, 43605, 43611, + 43616, 43623, 43627, 43631, 43644, 43657, 43668, 43677, 43683, 43690, + 43696, 43701, 43706, 43711, 43716, 43718, 43725, 43732, 43739, 43746, + 43753, 43761, 43768, 43774, 43781, 43788, 43795, 43802, 43808, 43816, + 43824, 43833, 43842, 43849, 43855, 43861, 43870, 43874, 43883, 43892, + 43900, 43908, 43912, 43919, 43926, 43933, 43937, 43943, 43950, 43955, + 43960, 43966, 43971, 43976, 43983, 43990, 43995, 44000, 44008, 44016, + 44026, 44036, 44043, 44050, 44054, 44058, 44070, 44076, 44082, 44087, + 44092, 44099, 44106, 44112, 44118, 44127, 44135, 44143, 44150, 44157, + 44164, 44170, 44177, 44183, 44190, 44197, 44204, 44211, 44217, 44222, + 44231, 44241, 44248, 44257, 44263, 44268, 44273, 44281, 44287, 44294, + 44301, 44309, 44314, 44321, 44328, 44339, 44346, 44352, 44358, 44365, + 44372, 44379, 44386, 44397, 44408, 44418, 44428, 44439, 44451, 44456, + 44461, 44469, 44477, 44483, 44489, 44498, 44507, 44515, 44523, 44531, + 44539, 44549, 44559, 44573, 44587, 44594, 44601, 44612, 44623, 44630, + 44637, 44646, 44655, 44660, 44665, 44674, 44683, 44688, 44693, 44701, + 44707, 44713, 44721, 44729, 44742, 44755, 44759, 44763, 44770, 44777, + 44784, 44792, 44800, 44808, 44816, 44822, 44828, 44834, 44840, 44847, + 44854, 44862, 44870, 44873, 44876, 44881, 44886, 44893, 44900, 44907, + 44914, 44923, 44932, 44939, 44946, 44954, 44962, 44970, 44978, 44985, + 44992, 44999, 45006, 45010, 45014, 45021, 45028, 45033, 45038, 45043, + 45048, 45054, 45068, 45075, 45082, 45086, 45088, 45090, 45095, 45100, + 45105, 45109, 45117, 45124, 45131, 45139, 45151, 45159, 45167, 45178, + 45182, 45186, 45191, 45197, 45208, 45214, 45220, 45226, 45231, 45238, + 45247, 45255, 45261, 45267, 45273, 45282, 45291, 45299, 45308, 45313, + 45316, 45321, 45327, 45333, 45339, 45345, 45349, 45352, 45356, 45360, + 45366, 45372, 45378, 45384, 45388, 45392, 45399, 45406, 45413, 45420, + 45427, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45434, 45439, 45444, 45449, + 45454, 45459, 45464, 45469, 45474, 45479, 45484, 45490, 45494, 45499, + 45504, 45509, 45514, 45519, 45524, 45529, 45534, 45539, 45544, 45549, + 45554, 45559, 45564, 45569, 45574, 45579, 45584, 45589, 45594, 45599, + 45604, 45610, 45615, 45621, 45630, 45635, 45643, 45650, 45659, 45664, + 45669, 45674, 45680, 0, 45687, 45692, 45697, 45702, 45707, 45712, 45717, + 45722, 45727, 45732, 45737, 45743, 45747, 45752, 45757, 45762, 45767, + 45772, 45777, 45782, 45787, 45792, 45797, 45802, 45807, 45812, 45817, + 45822, 45827, 45832, 45837, 45842, 45847, 45852, 45857, 45863, 45868, + 45874, 45883, 45888, 45896, 45903, 45912, 45917, 45922, 45927, 45933, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 45940, 45945, 45950, 45955, 45960, 45965, 45970, + 45975, 45980, 45985, 45990, 45995, 46000, 46005, 46010, 46015, 46020, + 46025, 46030, 46035, 46040, 46045, 46050, 46055, 46060, 46065, 46070, + 46075, 46080, 46085, 46090, 46094, 46098, 46103, 46108, 46113, 46118, + 46123, 46128, 46133, 46138, 46143, 46148, 46153, 46158, 46163, 46168, + 46173, 46178, 46183, 46188, 46195, 46202, 46209, 46216, 46223, 46230, + 46237, 46244, 46251, 46258, 46265, 46272, 46279, 46286, 46291, 46296, + 46303, 46310, 46317, 46324, 46331, 46338, 46345, 46352, 46359, 46366, + 46373, 46380, 46386, 46392, 46398, 46404, 46411, 46418, 46425, 46432, + 46439, 46446, 46453, 46460, 46467, 46474, 46482, 46490, 46498, 46506, + 46514, 46522, 46530, 46538, 46542, 46548, 46554, 46558, 46564, 46570, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46576, 46583, 46592, 46601, 46609, + 46616, 46620, 46625, 46630, 46635, 46640, 46645, 46650, 46655, 46660, + 46665, 46670, 46675, 46680, 46685, 46690, 46695, 46700, 46705, 46710, + 46715, 46720, 46725, 46730, 46735, 46740, 46745, 46750, 46755, 46760, + 46765, 46770, 46775, 46780, 46785, 46790, 46795, 46800, 46805, 46810, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 46815, 46818, 46822, 46826, 46830, 46834, + 46842, 46846, 46850, 46854, 46858, 46862, 46866, 46870, 46874, 46880, + 46884, 46888, 46896, 46902, 46906, 46910, 46914, 46920, 46924, 46930, + 46934, 46938, 46944, 46950, 46954, 46958, 46962, 46968, 46974, 46978, + 46982, 46986, 46990, 46994, 47000, 47006, 47010, 47014, 47018, 47022, + 47026, 47030, 47034, 47038, 47042, 47046, 47050, 47056, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 47060, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47066, + 47070, 47074, 47078, 47082, 47086, 47090, 47094, 47098, 47102, 47106, + 47112, 47116, 47120, 47124, 47128, 47132, 47136, 47140, 47144, 47148, + 47152, 47156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47160, 47164, 47168, 47172, + 47176, 47180, 47184, 0, 47188, 47192, 47196, 47200, 47204, 47208, 47212, + 0, 47216, 47220, 47224, 47228, 47232, 47236, 47240, 0, 47244, 47248, + 47252, 47256, 47260, 47264, 47268, 0, 47272, 47276, 47280, 47284, 47288, + 47292, 47296, 0, 47300, 47304, 47308, 47312, 47316, 47320, 47324, 0, + 47328, 47332, 47336, 47340, 47344, 47348, 47352, 0, 47356, 47360, 47364, + 47368, 47372, 47376, 47380, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47384, 47390, + 47398, 47402, 47406, 47412, 47418, 47424, 47432, 47438, 47442, 47446, + 47450, 47456, 47462, 47466, 47468, 47472, 47477, 47479, 47483, 47487, + 47491, 47497, 0, 0, 0, 0, 47502, 47507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47512, 47516, 47520, 47525, + 47530, 47535, 47539, 47543, 47547, 47552, 47557, 47561, 47565, 47569, + 47573, 47578, 47583, 47588, 47593, 47597, 47601, 47606, 47611, 47616, + 47621, 47625, 0, 47629, 47633, 47637, 47641, 47645, 47649, 47653, 47658, + 47663, 47667, 47672, 47677, 47686, 47690, 47694, 47698, 47705, 47709, + 47714, 47719, 47723, 47727, 47733, 47738, 47743, 47748, 47753, 47757, + 47761, 47765, 47769, 47773, 47778, 47783, 47787, 47791, 47796, 47801, + 47806, 47810, 47814, 47819, 47824, 47830, 47836, 47840, 47846, 47852, + 47856, 47862, 47868, 47873, 47878, 47882, 47888, 47892, 47896, 47902, + 47908, 47913, 47918, 47922, 47926, 47934, 47940, 47946, 47952, 47957, + 47962, 47967, 47973, 47977, 47983, 47987, 47991, 47997, 48003, 48009, + 48015, 48021, 48027, 48033, 48039, 48045, 48051, 48057, 48063, 48067, + 48073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48079, 48082, 48086, 48090, + 48094, 48098, 48101, 48104, 48108, 48112, 48116, 48120, 48123, 48128, + 48132, 48136, 48140, 48146, 48150, 48154, 48158, 48162, 48169, 48175, + 48179, 48183, 48187, 48191, 48195, 48199, 48203, 48207, 48211, 48215, + 48219, 48225, 48229, 48233, 48237, 48241, 48245, 48249, 48253, 48257, + 48261, 48265, 48269, 48273, 48277, 48281, 48285, 48289, 48295, 48301, + 48306, 48311, 48315, 48319, 48323, 48327, 48331, 48335, 48339, 48343, + 48347, 48351, 48355, 48359, 48363, 48367, 48371, 48375, 48379, 48383, + 48387, 48391, 48395, 48398, 48402, 48406, 48412, 48416, 48420, 48424, + 48428, 48432, 48436, 48440, 48444, 48448, 48455, 48459, 48463, 48467, + 48471, 48475, 48479, 48483, 48487, 48491, 48495, 48499, 48503, 48510, + 48514, 48520, 48524, 48528, 48532, 48536, 48540, 48543, 48547, 48551, + 48555, 48559, 48563, 48567, 48571, 48575, 48579, 48583, 48587, 48591, + 48595, 48599, 48603, 48607, 48611, 48615, 48619, 48623, 48627, 48631, + 48635, 48639, 48643, 48647, 48651, 48655, 48659, 48663, 48667, 48671, + 48677, 48681, 48685, 48689, 48693, 48697, 48701, 48705, 48709, 48713, + 48717, 48721, 48725, 48729, 48733, 48737, 48741, 48745, 48749, 48753, + 48757, 48761, 48765, 48769, 48773, 48777, 48781, 48785, 48793, 48797, + 48801, 48805, 48809, 48813, 48819, 48823, 48827, 48831, 48835, 48839, + 48843, 48847, 48851, 48855, 48859, 48863, 48867, 48871, 48877, 48881, + 48885, 48889, 48893, 48897, 48901, 48905, 48909, 48913, 48917, 48921, + 48925, 48929, 48933, 48937, 48941, 48945, 48949, 48953, 48957, 48961, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 48965, 48972, 48979, 48989, 48999, 49007, 49016, 49025, 49035, 49046, + 49056, 49067, 0, 0, 0, 0, 49073, 49076, 49079, 49083, 49086, 49093, + 49097, 49101, 49105, 49108, 49111, 49115, 49119, 49123, 49127, 49132, + 49137, 49142, 49147, 49150, 49153, 49159, 49165, 49170, 49175, 49182, + 49189, 49193, 49197, 49201, 49208, 49214, 49221, 49226, 49230, 49234, + 49238, 49242, 49246, 49250, 49254, 49258, 49262, 49267, 49272, 49277, + 49282, 49288, 49293, 49297, 49303, 49314, 49323, 49337, 49346, 49350, + 49359, 49364, 49369, 49374, 49379, 49382, 49387, 49391, 0, 49397, 49401, + 49404, 49408, 49411, 49415, 49418, 49422, 49425, 49429, 49432, 49435, + 49439, 49443, 49447, 49451, 49455, 49459, 49463, 49467, 49471, 49475, + 49479, 49483, 49487, 49491, 49495, 49499, 49503, 49507, 49511, 49515, + 49519, 49523, 49527, 49532, 49536, 49540, 49544, 49548, 49551, 49555, + 49559, 49563, 49567, 49571, 49575, 49578, 49582, 49586, 49590, 49594, + 49598, 49602, 49606, 49610, 49614, 49618, 49622, 49626, 49630, 49634, + 49637, 49641, 49645, 49649, 49653, 49657, 49660, 49665, 49669, 49674, + 49678, 49682, 49686, 49690, 49694, 49698, 49703, 49707, 49711, 49715, + 49719, 49722, 49726, 49730, 0, 0, 49735, 49743, 49751, 49758, 49765, + 49769, 49775, 49780, 49785, 49789, 49792, 49796, 49799, 49803, 49806, + 49810, 49813, 49817, 49820, 49823, 49827, 49831, 49835, 49839, 49843, + 49847, 49851, 49855, 49859, 49863, 49867, 49871, 49875, 49879, 49883, + 49887, 49891, 49895, 49899, 49903, 49907, 49911, 49915, 49920, 49924, + 49928, 49932, 49936, 49939, 49943, 49947, 49951, 49955, 49959, 49963, + 49966, 49970, 49974, 49978, 49982, 49986, 49990, 49994, 49998, 50002, + 50006, 50010, 50014, 50018, 50022, 50025, 50029, 50033, 50037, 50041, + 50045, 50048, 50053, 50057, 50062, 50066, 50070, 50074, 50078, 50082, + 50086, 50091, 50095, 50099, 50103, 50107, 50110, 50114, 50118, 50123, + 50127, 50131, 50135, 50139, 50144, 50151, 50155, 50161, 0, 0, 0, 0, 0, + 50166, 50169, 50172, 50175, 50179, 50182, 50185, 50188, 50191, 50194, + 50198, 50201, 50204, 50208, 50211, 50215, 50219, 50223, 50226, 50230, + 50234, 50237, 50240, 50243, 50246, 50250, 50254, 50258, 50262, 50266, + 50270, 50274, 50278, 50282, 50286, 50289, 50292, 50296, 50299, 50303, 0, + 0, 0, 0, 50307, 50311, 50315, 50319, 50323, 50327, 50331, 50335, 50339, + 50343, 50347, 50351, 50355, 50359, 50363, 50367, 50371, 50375, 50379, + 50383, 50387, 50391, 50395, 50399, 50403, 50407, 50411, 50415, 50419, + 50423, 50427, 50430, 50434, 50437, 50441, 50445, 50448, 50452, 50456, + 50459, 50463, 50467, 50471, 50475, 50478, 50482, 50486, 50490, 50494, + 50498, 50502, 50505, 50508, 50512, 50516, 50520, 50524, 50528, 50532, + 50536, 50540, 50544, 50548, 50552, 50556, 50560, 50564, 50568, 50572, + 50576, 50580, 50584, 50588, 50592, 50596, 50600, 50604, 50608, 50612, + 50616, 50620, 50624, 50628, 50632, 50636, 50640, 50644, 50648, 50652, + 50656, 50660, 50664, 50668, 50672, 0, 50676, 50682, 50688, 50694, 50699, + 50704, 50710, 50716, 50722, 50728, 50734, 50740, 50746, 50752, 50758, + 50764, 50770, 50774, 50778, 50782, 50786, 50790, 50794, 50798, 50802, + 50806, 50810, 50814, 50818, 50822, 50826, 50830, 50834, 50838, 50842, + 50846, 50850, 50854, 50858, 50863, 0, 0, 0, 0, 0, 0, 0, 0, 50867, 50871, + 50876, 50881, 50886, 50891, 50896, 50901, 50906, 50911, 50916, 50921, + 50926, 50931, 50936, 50941, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50945, 50950, 50955, + 50960, 50964, 50969, 50973, 50978, 50983, 50988, 50993, 50998, 51003, + 51008, 51013, 51018, 51023, 51027, 51031, 51035, 51039, 51043, 51047, + 51051, 51055, 51059, 51063, 51067, 51071, 51075, 51079, 51084, 51089, + 51094, 51099, 51104, 51109, 51114, 51119, 51124, 51129, 51134, 51139, + 51144, 51149, 51154, 51160, 0, 51167, 51170, 51173, 51176, 51179, 51182, + 51185, 51188, 51191, 51194, 51198, 51202, 51206, 51210, 51214, 51218, + 51222, 51226, 51230, 51234, 51238, 51242, 51246, 51250, 51254, 51258, + 51262, 51266, 51270, 51274, 51278, 51282, 51286, 51290, 51294, 51298, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51302, 51305, 51310, 51315, 51320, + 51325, 51330, 51335, 51340, 51345, 51350, 51354, 51359, 51364, 51369, + 51374, 51379, 51383, 51387, 51391, 51395, 51399, 51403, 51407, 51411, + 51415, 51419, 51423, 51427, 51431, 51435, 51440, 51445, 51450, 51455, + 51460, 51465, 51470, 51475, 51480, 51485, 51490, 51495, 51500, 51505, + 51511, 51517, 51522, 51527, 51530, 51533, 51536, 51539, 51542, 51545, + 51548, 51551, 51554, 51558, 51562, 51566, 51570, 51574, 51578, 51582, + 51586, 51590, 51594, 51598, 51602, 51606, 51610, 51614, 51618, 51622, + 51626, 51630, 51634, 51638, 51642, 51646, 51650, 51654, 51658, 51662, + 51666, 51670, 51674, 51678, 51681, 51685, 51689, 51693, 51697, 51701, + 51705, 51709, 51713, 51718, 51723, 51728, 51733, 51737, 51742, 51747, + 51752, 51757, 51762, 51767, 51772, 51777, 51782, 51786, 51792, 51798, + 51804, 51810, 51816, 51822, 51828, 51834, 51840, 51846, 51852, 51858, + 51861, 51864, 51867, 51872, 51875, 51878, 51881, 51884, 51887, 51890, + 51894, 51898, 51902, 51906, 51910, 51914, 51918, 51922, 51926, 51930, + 51934, 51938, 51942, 51945, 51949, 51953, 51957, 51961, 51965, 51968, + 51972, 51976, 51980, 51984, 51987, 51991, 51995, 51999, 52003, 52006, + 52010, 52014, 52018, 52022, 52026, 52030, 52034, 52038, 52042, 52046, 0, + 52050, 52053, 52056, 52059, 52062, 52065, 52068, 52071, 52074, 52077, + 52080, 52083, 52086, 52089, 52092, 52095, 52098, 52101, 52104, 52107, + 52110, 52113, 52116, 52119, 52122, 52125, 52128, 52131, 52134, 52137, + 52140, 52143, 52146, 52149, 52152, 52155, 52158, 52161, 52164, 52167, + 52170, 52173, 52176, 52179, 52182, 52185, 52188, 52191, 52194, 52197, + 52200, 52203, 52206, 52209, 52212, 52215, 52218, 52221, 52224, 52227, + 52230, 52233, 52236, 52239, 52242, 52245, 52248, 52251, 52254, 52257, + 52260, 52263, 52266, 52269, 52272, 52275, 52278, 52281, 52284, 52287, + 52290, 52293, 52296, 52299, 52302, 52305, 52308, 52311, 52314, 52322, + 52329, 52336, 52343, 52350, 52357, 52364, 52371, 52378, 52385, 52393, + 52401, 52409, 52417, 52425, 52433, 52441, 52449, 52457, 52465, 52473, + 52481, 52489, 52497, 52505, 52508, 52511, 52514, 52516, 52519, 52522, + 52525, 52530, 52535, 52538, 52545, 52552, 52559, 52566, 52569, 52574, + 52577, 52581, 52583, 52585, 52588, 52591, 52594, 52597, 52600, 52603, + 52606, 52611, 52615, 52618, 52621, 52624, 52627, 52630, 52633, 52636, + 52640, 52643, 52646, 52649, 52652, 52655, 52659, 52662, 52665, 52668, + 52673, 52678, 52683, 52688, 52693, 52698, 52703, 52708, 52714, 52723, + 52726, 52729, 52732, 52735, 52738, 52744, 52753, 52756, 52759, 52763, + 52766, 52769, 52772, 52776, 52779, 52782, 52787, 52790, 52793, 52798, + 52801, 52804, 52809, 52814, 52819, 52822, 52825, 52828, 52831, 52838, + 52841, 52844, 52847, 52849, 52852, 52855, 52858, 52863, 52866, 52869, + 52872, 52875, 52878, 52883, 52886, 52889, 52892, 52895, 52898, 52901, + 52904, 52907, 52910, 52916, 52921, 52928, 52935, 52942, 52949, 52956, + 52963, 52970, 52977, 52984, 52992, 53000, 53008, 53016, 53024, 53032, + 53040, 53048, 53056, 53064, 53072, 53080, 53088, 53096, 53104, 53112, + 53120, 53128, 53136, 53144, 53152, 53160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 53163, 53171, 53179, 53189, 53195, 53199, 53203, 53209, + 53215, 53220, 53224, 53228, 53232, 53236, 53242, 53246, 53250, 53254, + 53264, 53268, 53272, 53278, 53282, 53288, 53292, 53296, 53302, 53308, + 53314, 53322, 53330, 53334, 53338, 53342, 53348, 53352, 53361, 53367, + 53371, 53375, 53379, 53383, 53387, 53391, 53398, 53404, 53410, 53414, + 53420, 53424, 53430, 53438, 53448, 53452, 53460, 53464, 53470, 53478, + 53486, 53490, 53494, 53500, 53505, 53511, 53517, 53521, 53525, 53528, + 53532, 53536, 53540, 53544, 53548, 53552, 53556, 53559, 53563, 53567, + 53571, 53575, 53579, 53583, 53586, 53590, 53594, 53597, 53601, 53605, + 53609, 53613, 53617, 53621, 53625, 53629, 53633, 53637, 53641, 53645, + 53649, 53653, 53657, 53661, 53665, 53669, 53673, 53677, 53681, 53685, + 53689, 53693, 53697, 53701, 53705, 53709, 53713, 53717, 53721, 53725, + 53729, 53733, 53737, 53741, 53745, 53749, 53753, 53757, 53761, 53765, + 53769, 53773, 53777, 53781, 53785, 53789, 53793, 53797, 53801, 53805, + 53809, 53813, 53817, 53821, 53825, 53829, 53833, 53837, 53841, 53845, + 53849, 53853, 53857, 53861, 53865, 53869, 53873, 53877, 53881, 53885, + 53889, 53893, 53897, 53901, 53905, 53909, 53913, 53917, 53921, 53925, + 53929, 53933, 53937, 53941, 53945, 53949, 53953, 53957, 53961, 53965, + 53969, 53973, 53977, 53981, 53985, 53989, 53993, 53997, 54001, 54005, + 54009, 54013, 54017, 54021, 54025, 54029, 54033, 54037, 54041, 54045, + 54049, 54053, 54057, 54061, 54065, 54069, 54073, 54077, 54081, 54085, + 54089, 54093, 54097, 54101, 54105, 54109, 54113, 54117, 54121, 54125, + 54129, 54133, 54137, 54141, 54145, 54149, 54153, 54157, 54161, 54165, + 54169, 54173, 54177, 54181, 54185, 54189, 54193, 54197, 54201, 54205, + 54209, 54213, 54217, 54221, 54225, 54229, 54233, 54237, 54241, 54245, + 54248, 54252, 54256, 54260, 54264, 54268, 54272, 54276, 54280, 54284, + 54288, 54292, 54296, 54300, 54304, 54308, 54312, 54316, 54320, 54324, + 54328, 54332, 54336, 54340, 54344, 54348, 54352, 54356, 54360, 54364, + 54368, 54372, 54376, 54380, 54384, 54388, 54392, 54396, 54400, 54404, + 54408, 54412, 54416, 54420, 54424, 54428, 54432, 54436, 54440, 54444, + 54448, 54452, 54456, 54460, 54464, 54468, 54472, 54476, 54480, 54484, + 54488, 54492, 54496, 54500, 54504, 54508, 54512, 54516, 54520, 54524, + 54528, 54532, 54536, 54540, 54544, 54548, 54552, 54556, 54560, 54564, + 54568, 54572, 54576, 54580, 54584, 54588, 54592, 54596, 54600, 54604, + 54608, 54612, 54616, 54620, 54624, 54628, 54632, 54636, 54640, 54644, + 54648, 54652, 54656, 54660, 54664, 54668, 54672, 54676, 54680, 54684, + 54688, 54692, 54696, 54700, 54704, 54708, 54711, 54715, 54719, 54723, + 54727, 54731, 54735, 54739, 54743, 54747, 54751, 54755, 54759, 54763, + 54767, 54771, 54775, 54779, 54783, 54787, 54791, 54795, 54799, 54803, + 54807, 54811, 54815, 54819, 54823, 54827, 54831, 54835, 54839, 54843, + 54847, 54851, 54855, 54859, 54863, 54867, 54871, 54875, 54879, 54883, + 54887, 54891, 54895, 54899, 54903, 54907, 54911, 54915, 54919, 54923, + 54927, 54931, 54935, 54939, 54943, 54947, 54951, 54955, 54959, 54963, + 54967, 54971, 54975, 54979, 54983, 54987, 54991, 54995, 54999, 55003, + 55007, 55011, 55015, 55019, 55023, 55027, 55031, 55035, 55039, 55043, + 55047, 55051, 55055, 55059, 55063, 55067, 55071, 55075, 55079, 55083, + 55087, 55091, 55095, 55099, 55103, 55107, 55111, 55115, 55119, 55123, + 55127, 55131, 55135, 55139, 55143, 55147, 55151, 55155, 55159, 55163, + 55167, 55171, 55175, 55179, 55183, 55187, 55191, 55195, 55199, 55203, + 55207, 55211, 55215, 55219, 55223, 55227, 55231, 55235, 55239, 55243, + 55247, 55251, 55255, 55259, 55263, 55267, 55271, 55275, 55279, 55283, + 55287, 55291, 55295, 55299, 55303, 55307, 55311, 55315, 55319, 55323, + 55327, 55331, 55335, 55339, 55343, 55347, 55351, 55355, 55359, 55363, + 55367, 55371, 55375, 55379, 55383, 55387, 55391, 55395, 55399, 55403, + 55407, 55411, 55415, 55419, 55423, 55427, 55431, 55435, 55439, 55443, + 55447, 55451, 55455, 55459, 55463, 55467, 55471, 55475, 55479, 55483, + 55487, 55491, 55495, 55499, 55503, 55507, 55511, 55515, 55519, 55523, + 55527, 55531, 55535, 55539, 55543, 55547, 55551, 55555, 55559, 55563, + 55566, 55570, 55574, 55578, 55582, 55586, 55590, 55594, 55598, 55602, + 55606, 55610, 55614, 55618, 55622, 55626, 55630, 55634, 55638, 55642, + 55646, 55650, 55654, 55658, 55662, 55666, 55670, 55674, 55678, 55682, + 55686, 55690, 55694, 55698, 55702, 55706, 55710, 55714, 55718, 55722, + 55726, 55730, 55734, 55738, 55742, 55746, 55750, 55754, 55758, 55762, + 55766, 55770, 55774, 55778, 55782, 55786, 55790, 55794, 55798, 55802, + 55806, 55810, 55814, 55818, 55822, 55826, 55830, 55834, 55838, 55842, + 55846, 55850, 55854, 55858, 55862, 55866, 55870, 55874, 55878, 55882, + 55886, 55890, 55894, 55898, 55902, 55906, 55910, 55914, 55918, 55922, + 55926, 55930, 55934, 55938, 55942, 55946, 55950, 55954, 55958, 55962, + 55966, 55970, 55974, 55978, 55982, 55986, 55990, 55994, 55998, 56002, + 56006, 56010, 56014, 56018, 56021, 56025, 56029, 56033, 56037, 56041, + 56045, 56049, 56053, 56057, 56061, 56065, 56069, 56073, 56077, 56081, + 56085, 56089, 56093, 56097, 56101, 56105, 56109, 56113, 56117, 56121, + 56125, 56129, 56133, 56137, 56141, 56145, 56149, 56153, 56157, 56161, + 56165, 56169, 56173, 56177, 56181, 56185, 56189, 56193, 56197, 56201, + 56205, 56209, 56213, 56217, 56221, 56225, 56229, 56233, 56237, 56241, + 56245, 56249, 56253, 56257, 56261, 56265, 56269, 56273, 56277, 56281, + 56285, 56289, 56293, 56297, 56301, 56305, 56309, 56313, 56317, 56321, + 56325, 56329, 56333, 56337, 56341, 56345, 56349, 56353, 56357, 56361, + 56365, 56369, 56373, 56377, 56381, 56385, 56389, 56393, 56397, 56401, + 56405, 56409, 56413, 56417, 56421, 56425, 56429, 56433, 56437, 56441, + 56445, 56449, 56453, 56457, 56461, 56465, 56469, 56473, 56477, 56481, + 56485, 56489, 56493, 56497, 56501, 56505, 56509, 56513, 56517, 56521, + 56525, 56529, 56533, 56537, 56541, 56545, 56549, 56553, 56557, 56561, + 56565, 56569, 56573, 56577, 56581, 56585, 56589, 56593, 56597, 56601, + 56605, 56609, 56613, 56617, 56621, 56624, 56628, 56632, 56636, 56640, + 56644, 56648, 56652, 56656, 56660, 56664, 56668, 56672, 56676, 56680, + 56684, 56688, 56692, 56696, 56700, 56704, 56708, 56712, 56716, 56720, + 56724, 56728, 56732, 56736, 56740, 56744, 56748, 56752, 56756, 56760, + 56764, 56768, 56772, 56776, 56780, 56784, 56788, 56792, 56796, 56800, + 56804, 56808, 56812, 56816, 56820, 56824, 56828, 56832, 56836, 56840, + 56844, 56848, 56852, 56856, 56860, 56864, 56868, 56872, 56876, 56880, + 56884, 56888, 56892, 56896, 56900, 56904, 56908, 56912, 56916, 56920, + 56924, 56928, 56932, 56936, 56940, 56944, 56948, 56952, 56956, 56960, + 56964, 56968, 56972, 56976, 56980, 56984, 56988, 56992, 56996, 57000, + 57004, 57008, 57012, 57016, 57020, 57024, 57028, 57032, 57036, 57040, + 57044, 57048, 57052, 57056, 57060, 57064, 57068, 57072, 57076, 57080, + 57084, 57088, 57092, 57096, 57100, 57104, 57108, 57112, 57116, 57120, + 57124, 57128, 57132, 57136, 57140, 57144, 57148, 57152, 57156, 57160, + 57164, 57168, 57172, 57176, 57180, 57184, 57188, 57192, 57196, 57200, + 57204, 57208, 57212, 57216, 57220, 57224, 57228, 57232, 57236, 57240, + 57244, 57248, 57252, 57256, 57260, 57264, 57268, 57272, 57276, 57280, + 57284, 57288, 57292, 57296, 57300, 57304, 57308, 57312, 57316, 57320, + 57324, 57328, 57332, 57336, 57340, 57344, 57348, 57352, 57356, 57360, + 57364, 57368, 57372, 57376, 57380, 57384, 57388, 57392, 57396, 57400, + 57404, 57408, 57412, 57416, 57420, 57424, 57428, 57432, 57436, 57440, + 57444, 57448, 57452, 57456, 57460, 57464, 57468, 57472, 57476, 57480, + 57484, 57488, 57492, 57496, 57500, 57504, 57508, 57512, 57516, 57520, + 57524, 57528, 57532, 57536, 57540, 57544, 57548, 57552, 57556, 57560, + 57564, 57568, 57572, 57576, 57580, 57584, 57588, 57592, 57596, 57600, + 57604, 57608, 57612, 57616, 57620, 57624, 57628, 57632, 57636, 57640, + 57644, 57648, 57652, 57656, 57660, 57664, 57668, 57672, 57676, 57680, + 57684, 57688, 57692, 57696, 57700, 57704, 57708, 57712, 57716, 57720, + 57724, 57728, 57732, 57736, 57740, 57744, 57748, 57752, 57756, 57760, + 57764, 57768, 57772, 57776, 57780, 57784, 57788, 57792, 57796, 57800, + 57804, 57808, 57812, 57816, 57820, 57824, 57828, 57832, 57836, 57840, + 57844, 57848, 57852, 57856, 57860, 57864, 57868, 57872, 57876, 57880, + 57884, 57888, 57892, 57896, 57900, 57904, 57908, 57912, 57916, 57920, + 57924, 57928, 57932, 57936, 57940, 57944, 57948, 57952, 57956, 57960, + 57964, 57968, 57972, 57976, 57980, 57984, 57988, 57992, 57996, 58000, + 58004, 58008, 58012, 58016, 58020, 58024, 58028, 58032, 58036, 58040, + 58044, 58048, 58052, 58056, 58060, 58064, 58068, 58072, 58076, 58080, + 58084, 58088, 58092, 58096, 58100, 58104, 58108, 58112, 58116, 58120, + 58124, 58128, 58132, 58136, 58140, 58144, 58148, 58152, 58156, 58160, + 58164, 0, 0, 0, 58168, 58172, 58176, 58180, 58184, 58188, 58192, 58196, + 58200, 58204, 58208, 58212, 58216, 58220, 58224, 58228, 58232, 58236, + 58240, 58244, 58248, 58252, 58256, 58260, 58264, 58268, 58272, 58276, + 58280, 58284, 58288, 58292, 58296, 58300, 58304, 58308, 58312, 58316, + 58320, 58324, 58328, 58332, 58336, 58340, 58344, 58348, 58352, 58356, + 58360, 58364, 58368, 58372, 58376, 58380, 58384, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 58388, 58397, 58406, 58415, 58424, 58433, 58442, 58451, 58460, 58468, + 58475, 58483, 58490, 58498, 58508, 58517, 58527, 58536, 58546, 58554, + 58561, 58569, 58576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58584, 58590, 58596, + 58603, 58609, 58615, 58621, 58628, 58635, 58642, 58649, 58656, 58663, + 58670, 58677, 58684, 58691, 58698, 58705, 58712, 58719, 58725, 58732, + 58739, 58746, 58753, 58760, 58767, 58774, 58781, 58788, 58795, 58802, + 58809, 58816, 58823, 58830, 58837, 58844, 58851, 58859, 58867, 58875, + 58883, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58891, 58895, 58899, 58903, + 58907, 58911, 58915, 58919, 58923, 58927, 58931, 58935, 58939, 58943, + 58947, 58951, 58955, 58959, 58963, 58967, 58971, 58975, 58979, 58983, + 58987, 58991, 58995, 58999, 59003, 59007, 59011, 59015, 59019, 59023, + 59027, 59031, 59035, 59039, 59043, 59047, 59051, 59055, 59059, 59063, + 59067, 59071, 59075, 59079, 59083, 59087, 59091, 59095, 59099, 59103, + 59107, 59111, 59115, 59119, 59123, 59127, 59131, 59135, 59139, 59143, + 59147, 59151, 59155, 59159, 59163, 59167, 59171, 59175, 59179, 59183, + 59187, 59191, 59195, 59199, 59203, 59207, 59211, 59215, 59219, 59223, + 59227, 59231, 59235, 59239, 59243, 59247, 59251, 59255, 59259, 59263, + 59267, 59271, 59275, 59279, 59283, 59287, 59291, 59295, 59299, 59303, + 59307, 59311, 59315, 59319, 59323, 59327, 59331, 59335, 59339, 59343, + 59347, 59351, 59355, 59359, 59363, 59367, 59371, 59375, 59379, 59383, + 59387, 59391, 59395, 59399, 59403, 59407, 59411, 59415, 59419, 59423, + 59427, 59431, 59435, 59439, 59443, 59447, 59451, 59455, 59459, 59463, + 59467, 59471, 59475, 59479, 59483, 59487, 59491, 59495, 59499, 59503, + 59507, 59511, 59515, 59519, 59523, 59527, 59531, 59535, 59539, 59543, + 59547, 59551, 59555, 59559, 59563, 59567, 59571, 59575, 59579, 59583, + 59587, 59591, 59595, 59599, 59603, 59607, 59611, 59615, 59619, 59623, + 59627, 59631, 59635, 59639, 59643, 59647, 59651, 59655, 59659, 59663, + 59667, 59671, 59675, 59679, 59683, 59687, 59691, 59695, 59699, 59703, + 59707, 59711, 59715, 59719, 59723, 59727, 59731, 59735, 59739, 59743, + 59747, 59751, 59755, 59759, 59763, 59767, 59771, 59775, 59779, 59783, + 59787, 59791, 59795, 59799, 59803, 59807, 59811, 59815, 59819, 59823, + 59827, 59831, 59835, 59839, 59843, 59847, 59851, 59855, 59859, 59863, + 59867, 59871, 59875, 59879, 59883, 59887, 59891, 59895, 59899, 59903, + 59907, 59911, 59915, 59919, 59923, 59927, 59931, 59935, 59939, 59943, + 59947, 59951, 59955, 59959, 59963, 59967, 59971, 59975, 59979, 59983, + 59987, 59991, 59995, 59999, 60003, 60007, 60011, 60015, 60019, 60023, + 60027, 60031, 60035, 60039, 60043, 60047, 60051, 60055, 60059, 60063, + 60067, 60071, 60075, 60079, 60083, 60087, 60091, 60095, 0, 0, 60099, + 60103, 60107, 60111, 60115, 60119, 60123, 60127, 60131, 60135, 60139, + 60143, 60147, 60151, 60155, 60159, 60163, 60167, 60171, 60175, 60179, + 60183, 60187, 60191, 60195, 60199, 60203, 60207, 60211, 60215, 60219, + 60223, 60227, 60231, 60235, 60239, 60243, 60247, 60251, 60255, 60259, + 60263, 60267, 60271, 60275, 60279, 60283, 60287, 60291, 60295, 60299, + 60303, 60307, 60311, 60315, 60319, 60323, 60327, 60331, 0, 0, 0, 0, 0, + 60335, 60339, 60343, 60347, 60351, 60355, 60359, 60363, 60367, 60371, + 60375, 60379, 60383, 60387, 60391, 60395, 60399, 60403, 60407, 60411, + 60415, 60419, 60423, 60427, 60431, 60435, 60439, 60443, 60447, 60451, + 60455, 60459, 60463, 60467, 60471, 60475, 60479, 60483, 60487, 60491, + 60495, 60499, 60503, 60507, 60511, 60515, 60519, 60523, 60527, 60531, + 60535, 60539, 60543, 60547, 60551, 60555, 60559, 60563, 60567, 60571, + 60575, 60579, 60583, 60587, 60591, 60595, 60599, 60603, 60607, 60611, + 60615, 60619, 60623, 60627, 60631, 60635, 60639, 60643, 60647, 60651, + 60655, 60659, 60663, 60667, 60671, 60675, 60679, 60683, 60687, 60691, + 60695, 60699, 60703, 60707, 60711, 60715, 60719, 60723, 60727, 60731, + 60735, 60739, 60743, 60747, 60751, 60755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 60759, 60764, 60769, 60774, 60779, 60784, 60791, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 60796, 60803, 60810, 60817, 60824, 0, 0, 0, 0, 0, + 60831, 60838, 60845, 60855, 60861, 60867, 60873, 60879, 60885, 60891, + 60898, 60904, 60910, 60917, 60926, 60935, 60947, 60959, 60965, 60971, + 60977, 60984, 60991, 60998, 61005, 61012, 0, 61019, 61026, 61033, 61041, + 61048, 0, 61055, 0, 61062, 61069, 0, 61076, 61084, 0, 61091, 61098, + 61105, 61112, 61119, 61126, 61133, 61140, 61147, 61154, 61159, 61166, + 61173, 61179, 61185, 61191, 61197, 61203, 61209, 61215, 61221, 61227, + 61233, 61239, 61245, 61251, 61257, 61263, 61269, 61275, 61281, 61287, + 61293, 61299, 61305, 61311, 61317, 61323, 61329, 61335, 61341, 61347, + 61353, 61359, 61365, 61371, 61377, 61383, 61389, 61395, 61401, 61407, + 61413, 61419, 61425, 61431, 61437, 61443, 61449, 61455, 61461, 61467, + 61473, 61479, 61485, 61491, 61497, 61503, 61509, 61515, 61521, 61527, + 61533, 61539, 61545, 61551, 61557, 61563, 61569, 61575, 61581, 61587, + 61593, 61599, 61605, 61611, 61617, 61623, 61629, 61636, 61643, 61649, + 61655, 61661, 61667, 61676, 61685, 61693, 61701, 61709, 61717, 61725, + 61733, 61741, 61749, 61756, 61763, 61773, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 61783, 61789, 61795, 61801, 61807, 61812, 61817, 61823, 61829, 61835, + 61841, 61849, 61855, 61861, 61869, 61877, 61885, 61893, 61898, 61903, + 61908, 61913, 61925, 61937, 61947, 61957, 61968, 61979, 61990, 62001, + 62011, 62021, 62032, 62043, 62054, 62065, 62075, 62085, 62095, 62110, + 62125, 62140, 62147, 62154, 62161, 62168, 62178, 62188, 62198, 62209, + 62219, 62227, 62235, 62243, 62251, 62260, 62268, 62276, 62284, 62292, + 62300, 62309, 62317, 62325, 62333, 62342, 62350, 62357, 62364, 62371, + 62378, 62385, 62392, 62399, 62407, 62415, 62423, 62431, 62439, 62447, + 62455, 62463, 62471, 62479, 62487, 62495, 62503, 62511, 62519, 62527, + 62535, 62543, 62551, 62559, 62567, 62576, 62584, 62592, 62600, 62609, + 62617, 62625, 62633, 62641, 62649, 62657, 62665, 62674, 62682, 62689, + 62696, 62703, 62710, 62718, 62725, 62732, 62739, 62746, 62753, 62761, + 62768, 62775, 62782, 62789, 62796, 62804, 62811, 62819, 62827, 62836, + 62844, 62851, 62858, 62865, 62872, 62880, 62887, 62897, 62907, 62917, + 62926, 62935, 62944, 62953, 62962, 62972, 62983, 62994, 63004, 63014, + 63025, 63035, 63044, 63053, 63061, 63069, 63078, 63086, 63095, 63104, + 63112, 63120, 63129, 63137, 63146, 63155, 63163, 63171, 63180, 63188, + 63197, 63205, 63214, 63222, 63230, 63238, 63246, 63255, 63263, 63270, + 63278, 63285, 63292, 63299, 63307, 63315, 63322, 63329, 63337, 63344, + 63354, 63362, 63370, 63377, 63384, 63392, 63399, 63409, 63419, 63429, + 63439, 63450, 63458, 63466, 63474, 63482, 63491, 63499, 63507, 63515, + 63523, 63532, 63540, 63547, 63554, 63561, 63568, 63575, 63582, 63590, + 63598, 63606, 63614, 63622, 63630, 63638, 63646, 63654, 63662, 63670, + 63678, 63686, 63694, 63702, 63710, 63718, 63726, 63734, 63742, 63750, + 63758, 63766, 63774, 63782, 63790, 63798, 63806, 63813, 63820, 63827, + 63834, 63842, 63849, 63856, 63863, 63870, 63877, 63884, 63891, 63898, + 63906, 63914, 63922, 63932, 63939, 63946, 63953, 63960, 63968, 63978, + 63989, 63997, 64006, 64014, 64023, 64031, 64040, 64048, 64057, 64065, + 64074, 64082, 64090, 64097, 64104, 64112, 64119, 64127, 64136, 64145, + 64154, 64163, 64171, 64180, 64188, 64197, 64205, 64214, 64222, 64231, + 64239, 64247, 64254, 64262, 64269, 64277, 64284, 64293, 64301, 64310, + 64318, 64326, 64334, 64342, 64350, 64359, 64368, 64377, 64386, 64395, + 64403, 64412, 64420, 64429, 64437, 64446, 64454, 64463, 64471, 64479, + 64486, 64494, 64501, 64509, 64516, 64525, 64533, 64542, 64550, 64558, + 64566, 64574, 64582, 64591, 64600, 64609, 64618, 64626, 64634, 64642, + 64650, 64659, 64668, 64676, 64684, 64692, 64700, 64708, 64716, 64724, + 64732, 64740, 64748, 64756, 64761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 64766, 64776, 64786, 64796, 64806, 64816, 64826, 64836, 64846, + 64855, 64864, 64873, 64883, 64893, 64903, 64914, 64924, 64934, 64944, + 64954, 64964, 64974, 64984, 64994, 65004, 65014, 65024, 65034, 65044, + 65054, 65064, 65075, 65085, 65095, 65105, 65115, 65125, 65135, 65145, + 65155, 65165, 65176, 65186, 65196, 65207, 65217, 65227, 65237, 65247, + 65256, 65265, 65275, 65284, 65293, 65302, 65311, 65320, 65329, 65338, + 65347, 65356, 65365, 65374, 65383, 0, 0, 65392, 65401, 65411, 65421, + 65430, 65440, 65449, 65458, 65468, 65477, 65487, 65496, 65505, 65515, + 65525, 65536, 65546, 65557, 65567, 65578, 65587, 65597, 65607, 65618, + 65628, 65638, 65648, 65657, 65666, 65675, 65684, 65693, 65702, 65712, + 65721, 65731, 65740, 65750, 65760, 65769, 65778, 65787, 65797, 65806, + 65815, 65824, 65833, 65842, 65852, 65862, 65872, 65882, 65892, 65902, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65911, 65926, 65941, 65947, + 65953, 65959, 65965, 65971, 65977, 65983, 65989, 65997, 66001, 66004, 0, + 0, 66012, 66015, 66018, 66021, 66024, 66027, 66030, 66033, 66036, 66039, + 66042, 66045, 66048, 66051, 66054, 66057, 66060, 66068, 66077, 66087, + 66095, 66103, 66112, 66121, 66132, 66144, 0, 0, 0, 0, 0, 0, 66153, 66158, + 66163, 66170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66177, 66187, 66197, + 66207, 66216, 66227, 66236, 66245, 66255, 66265, 66277, 66289, 66300, + 66311, 66321, 66331, 66340, 66349, 66359, 66369, 66380, 66391, 66395, + 66400, 66409, 66418, 66422, 66426, 66430, 66435, 66440, 66445, 66450, + 66453, 66457, 0, 66461, 66464, 66467, 66471, 66475, 66480, 66484, 66488, + 66493, 66498, 66505, 66512, 66515, 66518, 66521, 66525, 66528, 66532, + 66536, 0, 66540, 66545, 66549, 66553, 0, 0, 0, 0, 66558, 66563, 66570, + 66575, 66580, 0, 66585, 66590, 66595, 66600, 66605, 66610, 66615, 66620, + 66625, 66630, 66635, 66640, 66649, 66658, 66666, 66674, 66683, 66692, + 66701, 66710, 66718, 66726, 66734, 66742, 66747, 66752, 66758, 66764, + 66770, 66776, 66784, 66792, 66798, 66804, 66810, 66816, 66822, 66828, + 66834, 66840, 66845, 66850, 66855, 66860, 66865, 66870, 66875, 66880, + 66885, 66890, 66895, 66900, 66906, 66912, 66918, 66924, 66930, 66936, + 66942, 66948, 66954, 66960, 66966, 66972, 66978, 66984, 66990, 66996, + 67002, 67008, 67014, 67020, 67026, 67032, 67038, 67044, 67050, 67056, + 67062, 67068, 67074, 67080, 67086, 67092, 67098, 67104, 67110, 67116, + 67122, 67128, 67134, 67140, 67146, 67152, 67158, 67164, 67170, 67176, + 67182, 67188, 67194, 67200, 67206, 67212, 67217, 67222, 67227, 67232, + 67237, 67242, 67247, 67252, 67257, 67262, 67267, 67272, 67278, 67284, + 67290, 67296, 67302, 67308, 67314, 67320, 67325, 67330, 67335, 67340, + 67351, 67362, 67372, 67382, 67393, 67404, 67411, 0, 0, 67418, 0, 67426, + 67430, 67434, 67437, 67441, 67445, 67448, 67451, 67455, 67459, 67462, + 67466, 67469, 67472, 67476, 67479, 67483, 67486, 67489, 67492, 67495, + 67498, 67501, 67504, 67507, 67510, 67513, 67516, 67520, 67524, 67528, + 67532, 67537, 67542, 67547, 67553, 67558, 67563, 67569, 67574, 67579, + 67584, 67589, 67595, 67600, 67605, 67610, 67615, 67620, 67626, 67631, + 67636, 67641, 67646, 67651, 67657, 67662, 67668, 67674, 67678, 67683, + 67687, 67691, 67695, 67700, 67705, 67710, 67716, 67721, 67726, 67732, + 67737, 67742, 67747, 67752, 67758, 67763, 67768, 67773, 67778, 67783, + 67789, 67794, 67799, 67804, 67809, 67814, 67820, 67825, 67831, 67837, + 67842, 67846, 67851, 67853, 67858, 67863, 67868, 67873, 67878, 67882, + 67888, 67893, 67898, 67903, 67908, 67913, 67918, 67923, 67929, 67935, + 67941, 67949, 67953, 67957, 67961, 67965, 67969, 67973, 67978, 67983, + 67988, 67993, 67998, 68003, 68008, 68013, 68018, 68023, 68028, 68033, + 68038, 68042, 68047, 68052, 68057, 68062, 68067, 68071, 68076, 68081, + 68086, 68091, 68095, 68100, 68105, 68110, 68115, 68119, 68124, 68129, + 68134, 68139, 68144, 68149, 68154, 68159, 68163, 68170, 68177, 68181, + 68186, 68191, 68196, 68201, 68206, 68211, 68216, 68221, 68226, 68231, + 68236, 68241, 68246, 68251, 68256, 68261, 68266, 68271, 68276, 68281, + 68286, 68291, 68296, 68301, 68306, 68311, 68316, 68321, 68326, 0, 0, 0, + 68331, 68335, 68340, 68344, 68349, 68354, 0, 0, 68358, 68363, 68368, + 68372, 68377, 68382, 0, 0, 68387, 68392, 68396, 68401, 68406, 68411, 0, + 0, 68416, 68421, 68426, 0, 0, 0, 68430, 68434, 68438, 68441, 68443, + 68447, 68451, 0, 68455, 68461, 68464, 68468, 68471, 68475, 68479, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 68483, 68489, 68495, 68501, 68507, 0, 0, 68511, + 68517, 68523, 68529, 68535, 68541, 68548, 68555, 68562, 68569, 68576, + 68583, 0, 68590, 68597, 68604, 68610, 68617, 68624, 68631, 68638, 68644, + 68651, 68658, 68665, 68672, 68679, 68686, 68693, 68700, 68707, 68714, + 68721, 68728, 68735, 68742, 68749, 68756, 68763, 0, 68770, 68777, 68784, + 68791, 68798, 68805, 68812, 68819, 68826, 68833, 68840, 68847, 68854, + 68861, 68867, 68874, 68881, 68888, 68895, 0, 68902, 68909, 0, 68916, + 68923, 68930, 68937, 68944, 68951, 68958, 68965, 68972, 68979, 68986, + 68993, 69000, 69007, 69014, 0, 0, 69020, 69025, 69030, 69035, 69040, + 69045, 69050, 69055, 69060, 69065, 69070, 69075, 69080, 69085, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 69090, 69097, 69104, 69111, 69118, 69125, 69132, + 69139, 69146, 69153, 69160, 69167, 69174, 69181, 69188, 69195, 69202, + 69209, 69216, 69223, 69231, 69239, 69246, 69253, 69258, 69266, 69274, + 69281, 69288, 69293, 69300, 69305, 69310, 69317, 69322, 69327, 69332, + 69340, 69345, 69350, 69357, 69362, 69367, 69374, 69381, 69386, 69391, + 69396, 69401, 69406, 69411, 69416, 69421, 69426, 69433, 69438, 69445, + 69450, 69455, 69460, 69465, 69470, 69475, 69480, 69485, 69490, 69495, + 69500, 69507, 69514, 69521, 69528, 69534, 69539, 69546, 69551, 69556, + 69565, 69572, 69581, 69588, 69593, 69598, 69606, 69611, 69616, 69621, + 69626, 69631, 69638, 69643, 69648, 69653, 69658, 69663, 69670, 69677, + 69684, 69691, 69698, 69705, 69712, 69719, 69726, 69733, 69740, 69747, + 69754, 69761, 69768, 69775, 69782, 69789, 69796, 69803, 69810, 69817, + 69824, 69831, 69838, 69845, 69852, 69859, 0, 0, 0, 0, 0, 69866, 69873, + 69880, 0, 0, 0, 0, 69884, 69887, 69890, 69893, 69896, 69899, 69902, + 69905, 69908, 69911, 69915, 69919, 69923, 69927, 69931, 69935, 69939, + 69943, 69947, 69953, 69958, 69963, 69969, 69975, 69981, 69987, 69993, + 69999, 70005, 70010, 70015, 70021, 70027, 70033, 70039, 70045, 70051, + 70057, 70063, 70069, 70075, 70081, 70087, 70093, 70099, 0, 0, 0, 70105, + 70112, 70119, 70126, 70133, 70140, 70149, 70158, 70165, 70172, 70180, + 70188, 70196, 70201, 70207, 70215, 70223, 70231, 70239, 70247, 70255, + 70265, 70275, 70285, 70295, 70303, 70311, 70319, 70329, 70339, 70349, + 70359, 70369, 70377, 70385, 70390, 70395, 70400, 70405, 70412, 70419, + 70424, 70430, 70439, 70445, 70451, 70457, 70463, 70469, 70478, 70484, + 70490, 70498, 70505, 70513, 70521, 70529, 70537, 70545, 70553, 70561, + 70569, 70577, 70582, 70590, 70595, 70600, 70604, 70608, 70612, 70616, + 70621, 70626, 70632, 70638, 70642, 70648, 70652, 70656, 70660, 70664, + 70668, 70672, 70678, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 70682, 70686, 70691, 70696, 70701, 70705, 70710, 70715, + 70720, 70725, 70729, 70733, 70738, 70743, 70748, 70753, 70757, 70762, + 70767, 70772, 70777, 70782, 70787, 70791, 70796, 70801, 70806, 70811, + 70816, 70821, 70826, 0, 70831, 70835, 70839, 70844, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 70849, 70854, 70859, 70864, 70869, 70874, 70879, 70884, + 70889, 70894, 70899, 70904, 70909, 70914, 70919, 70924, 70929, 70934, + 70939, 70944, 70949, 70954, 70959, 70964, 70969, 70974, 70979, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 70986, 70991, 70996, 71001, 71006, 71011, 71016, 71021, 71026, + 71031, 71036, 71041, 71046, 71051, 71056, 71061, 71066, 71071, 71076, + 71081, 71086, 71091, 71096, 71101, 71106, 71111, 71116, 71120, 71124, + 71128, 0, 71133, 71139, 71143, 71147, 71151, 71155, 71160, 71165, 71170, + 71175, 71180, 71185, 71190, 71195, 71200, 71205, 71210, 71215, 71220, + 71225, 71230, 71235, 71240, 71245, 71249, 71254, 71259, 71263, 71268, + 71273, 71278, 71283, 71288, 71293, 71298, 71303, 71308, 0, 0, 0, 0, + 71312, 71317, 71322, 71327, 71332, 71337, 71342, 71347, 71352, 71358, + 71362, 71366, 71371, 71376, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 71381, 71386, 71391, 71396, 71402, 71407, 71413, 71419, 71425, + 71431, 71438, 71444, 71451, 71456, 71461, 71466, 71471, 71475, 71480, + 71485, 71490, 71495, 71500, 71505, 71510, 71515, 71520, 71525, 71530, + 71535, 71540, 71545, 71550, 71555, 71560, 71565, 71570, 71575, 71580, + 71585, 71590, 71595, 71600, 71605, 71611, 71616, 71622, 71628, 71634, + 71640, 71647, 71653, 71660, 71665, 71670, 71675, 71680, 71684, 71689, + 71694, 71699, 71704, 71709, 71714, 71719, 71724, 71729, 71734, 71739, + 71744, 71749, 71754, 71759, 71764, 71769, 71774, 71779, 71784, 71789, + 71794, 71799, 71803, 71807, 71811, 71815, 71819, 71823, 71827, 71831, + 71835, 71839, 71843, 71847, 71851, 71855, 71859, 71863, 71867, 71871, + 71875, 71879, 71883, 71887, 71891, 71895, 71899, 71903, 71907, 71911, + 71915, 71919, 71923, 71927, 71931, 71935, 71939, 71943, 71947, 71951, + 71955, 71959, 71963, 71967, 71971, 71975, 71979, 71983, 71987, 71991, + 71996, 72001, 72006, 72011, 72016, 72021, 72026, 72031, 72036, 72041, + 72046, 72051, 72056, 72061, 72066, 72071, 72076, 72081, 72086, 72091, + 72095, 72099, 72103, 72107, 72111, 72115, 72119, 72124, 72129, 0, 0, + 72134, 72139, 72143, 72147, 72151, 72155, 72159, 72163, 72167, 72171, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72175, 72178, 72181, 72184, 72187, + 72190, 0, 0, 72194, 0, 72198, 72201, 72205, 72209, 72213, 72217, 72221, + 72225, 72229, 72233, 72237, 72240, 72244, 72248, 72252, 72256, 72260, + 72264, 72268, 72272, 72276, 72280, 72284, 72288, 72292, 72296, 72300, + 72304, 72308, 72312, 72316, 72320, 72324, 72328, 72332, 72336, 72340, + 72344, 72348, 72351, 72355, 72359, 72363, 72367, 0, 72371, 72375, 0, 0, + 0, 72379, 0, 0, 72383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 72387, 72390, 72394, 72398, 0, 72403, 72407, 0, 0, 0, 0, 0, 72411, 72416, + 72422, 72426, 72430, 72433, 72437, 72441, 0, 72445, 72449, 72453, 0, + 72457, 72461, 72465, 72469, 72473, 72477, 72481, 72485, 72489, 72493, + 72497, 72501, 72505, 72509, 72513, 72517, 72520, 72523, 72527, 72531, + 72535, 72539, 72543, 72547, 72551, 72554, 72558, 0, 0, 0, 0, 72562, + 72567, 72571, 0, 0, 0, 0, 72575, 72578, 72581, 72584, 72587, 72590, + 72594, 72598, 72604, 0, 0, 0, 0, 0, 0, 0, 0, 72610, 72615, 72621, 72626, + 72632, 72637, 72642, 72647, 72653, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 72658, 72663, 72668, 72673, 72680, 72687, 72694, 72701, 72706, + 72711, 72716, 72721, 72728, 72733, 72740, 72747, 72752, 72757, 72762, + 72769, 72774, 72779, 72786, 72793, 72798, 72803, 72808, 72815, 72822, + 72829, 72834, 72839, 72846, 72853, 72860, 72867, 72872, 72877, 72882, + 72889, 72894, 72899, 72904, 72911, 72920, 72927, 72932, 72937, 72942, + 72947, 72952, 72957, 72966, 72973, 72978, 72985, 72992, 72997, 73002, + 73007, 73014, 73019, 73026, 73033, 73038, 73043, 73048, 73055, 73062, + 73067, 73072, 73079, 73086, 73093, 73098, 73103, 73108, 73113, 73120, + 73129, 73138, 73143, 73150, 73159, 73164, 73169, 73174, 73179, 73186, + 73193, 73200, 73207, 73212, 73217, 73222, 73229, 73236, 73243, 73248, + 73253, 73260, 73265, 73272, 73277, 73284, 73289, 73296, 73303, 73308, + 73313, 73318, 73323, 73328, 73333, 73338, 73343, 73348, 73355, 73362, + 73369, 73376, 73383, 73392, 73397, 73402, 73409, 73416, 73421, 73428, + 73435, 73442, 73449, 73456, 73463, 73468, 73473, 73478, 73483, 73488, + 73497, 73506, 73515, 73524, 73533, 73542, 73551, 73560, 73565, 73576, + 73587, 73596, 73601, 73606, 73611, 73616, 73625, 73632, 73639, 73646, + 73653, 73660, 73667, 73676, 73685, 73696, 73705, 73716, 73725, 73732, + 73741, 73752, 73761, 73770, 73779, 73788, 73795, 73802, 73809, 73818, + 73827, 73838, 73847, 73856, 73867, 73872, 73877, 73888, 73897, 73906, + 73915, 73924, 73935, 73944, 73953, 73964, 73975, 73986, 73997, 74008, + 74019, 74026, 74033, 74040, 74047, 74057, 74066, 74073, 74080, 74087, + 74098, 74109, 74120, 74131, 74142, 74153, 74164, 74175, 74182, 74189, + 74198, 74207, 74214, 74221, 74228, 74237, 74246, 74255, 74262, 74271, + 74280, 74289, 74296, 74303, 74308, 74315, 74322, 74329, 74336, 74343, + 74350, 74357, 74366, 74375, 74384, 74393, 74400, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 74409, 74415, 74420, 74425, 74432, 74438, 74444, 74450, 74456, + 74462, 74468, 74474, 74478, 74482, 74488, 74494, 74500, 74504, 74509, + 74514, 74518, 74522, 74525, 74531, 74537, 74543, 74549, 74555, 74561, + 74567, 74573, 74579, 74589, 74599, 74605, 74611, 74621, 74631, 74637, 0, + 0, 0, 74643, 74648, 74653, 74659, 74665, 74671, 74677, 74683, 74689, + 74696, 74703, 74709, 74715, 74721, 74727, 74733, 74739, 74745, 74751, + 74756, 74762, 74768, 74774, 74780, 74786, 74796, 74802, 74808, 74815, + 74822, 74829, 74838, 74847, 74856, 74865, 74874, 74883, 74892, 74901, + 74911, 74921, 74929, 74937, 74946, 74955, 74961, 74967, 74973, 74979, + 74987, 74995, 74999, 75005, 75010, 75016, 75022, 75028, 75034, 75040, + 75050, 75055, 75062, 75067, 75072, 75077, 75083, 75089, 75095, 75102, + 75107, 75112, 75117, 75122, 75127, 75133, 75139, 75145, 75151, 75157, + 75163, 75169, 75175, 75180, 75185, 75190, 75195, 75200, 75205, 75210, + 75215, 75221, 75227, 75232, 75237, 75242, 75247, 75252, 75258, 75265, + 75269, 75273, 75277, 75281, 75285, 75289, 75293, 75297, 75305, 75315, + 75319, 75323, 75329, 75335, 75341, 75347, 75353, 75359, 75365, 75371, + 75377, 75383, 75389, 75395, 75401, 75407, 75411, 75415, 75422, 75428, + 75434, 75440, 75445, 75452, 75457, 75463, 75469, 75475, 75481, 75486, + 75490, 75496, 75500, 75504, 75508, 75514, 75520, 75524, 75530, 75536, + 75542, 75548, 75554, 75562, 75570, 75576, 75582, 75588, 75594, 75606, + 75618, 75632, 75644, 75656, 75670, 75684, 75698, 75702, 75710, 75718, + 75722, 75726, 75730, 75734, 75738, 75742, 75746, 75750, 75756, 75762, + 75768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75774, 75780, 75786, 75792, 75798, + 75804, 75810, 75816, 75822, 75828, 75834, 75840, 75846, 75852, 75858, + 75864, 75870, 75876, 75882, 75888, 75894, 75900, 75906, 75912, 75918, + 75924, 75930, 75936, 75942, 75948, 75954, 75960, 75966, 75972, 75978, + 75984, 75990, 75996, 76002, 76008, 76014, 76020, 76026, 76032, 76038, + 76044, 76050, 76056, 76062, 76068, 76074, 76080, 76086, 76092, 76098, + 76104, 76110, 76116, 76122, 76128, 76134, 76140, 76146, 76152, 76158, + 76164, 76170, 76175, 76180, 76185, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76189, + 76194, 76201, 76208, 76215, 76222, 76227, 76231, 76237, 76241, 76245, + 76251, 76255, 76259, 76263, 76269, 76276, 76280, 76284, 76288, 76292, + 76296, 76300, 76306, 76310, 76314, 76318, 76322, 76326, 76330, 76334, + 76338, 76342, 76346, 76350, 76354, 76359, 76363, 76367, 76371, 76375, + 76379, 76383, 76387, 76391, 76395, 76402, 76406, 76413, 76417, 76421, + 76425, 76429, 76433, 76437, 76441, 76448, 76452, 76456, 76460, 76464, + 76468, 76474, 76478, 76484, 76488, 76492, 76496, 76500, 76504, 76508, + 76512, 76516, 76520, 76524, 76528, 76532, 76536, 76540, 76544, 76548, + 76552, 76556, 76560, 76568, 76572, 76576, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 76580, 76584, 76588, 76593, 76597, 76601, 76606, + 76610, 76614, 76618, 76622, 76627, 76631, 76635, 76639, 76643, 76647, + 76652, 76656, 76660, 76664, 76668, 76672, 76677, 76681, 76686, 76691, + 76695, 76699, 76704, 76708, 76712, 76717, 76721, 76725, 76729, 76733, + 76738, 76742, 76746, 76750, 76754, 76758, 76763, 76767, 76771, 76775, + 76779, 76783, 76788, 76792, 76797, 76802, 76806, 76810, 76815, 76819, + 76823, 76828, 76832, 76836, 76840, 76844, 76849, 76853, 76857, 76861, + 76865, 76869, 76874, 76878, 76882, 76886, 76890, 76894, 76899, 76903, + 76908, 76913, 76917, 76921, 76926, 76930, 76934, 76939, 0, 76943, 76947, + 76951, 76956, 76960, 76964, 76968, 76972, 76976, 76981, 76985, 76989, + 76993, 76997, 77001, 77006, 77010, 77015, 77020, 77025, 77030, 77036, + 77041, 77046, 77052, 77057, 77062, 77067, 77072, 77078, 77083, 77088, + 77093, 77098, 77103, 77109, 77114, 77119, 77124, 77129, 77134, 77140, + 77145, 77151, 77157, 77162, 77167, 77173, 77178, 77183, 77189, 77194, + 77199, 77204, 77209, 77215, 77220, 77225, 77230, 77235, 77240, 77246, + 77251, 77256, 77261, 77266, 77271, 77277, 77282, 77288, 77294, 0, 77298, + 77303, 0, 0, 77307, 0, 0, 77311, 77315, 0, 0, 77320, 77324, 77328, 77332, + 0, 77337, 77341, 77345, 77349, 77353, 77358, 77362, 77367, 77372, 77376, + 77380, 77385, 0, 77389, 0, 77394, 77398, 77402, 77406, 77411, 77415, + 77419, 0, 77423, 77427, 77432, 77436, 77440, 77444, 77448, 77452, 77457, + 77461, 77466, 77471, 77476, 77481, 77487, 77492, 77497, 77503, 77508, + 77513, 77518, 77523, 77529, 77534, 77539, 77544, 77549, 77554, 77560, + 77565, 77570, 77575, 77580, 77585, 77591, 77596, 77602, 77608, 77613, + 77618, 77624, 77629, 77634, 77640, 77645, 77650, 77655, 77660, 77666, + 77671, 77676, 77681, 77686, 77691, 77697, 77702, 77707, 77712, 77717, + 77722, 77728, 77733, 77739, 77745, 77749, 0, 77753, 77757, 77761, 77766, + 0, 0, 77770, 77774, 77779, 77783, 77787, 77791, 77795, 77799, 0, 77804, + 77808, 77812, 77816, 77820, 77825, 77829, 0, 77834, 77838, 77842, 77847, + 77851, 77855, 77860, 77864, 77868, 77872, 77876, 77881, 77885, 77889, + 77893, 77897, 77901, 77906, 77910, 77914, 77918, 77922, 77926, 77931, + 77935, 77940, 77945, 77949, 0, 77953, 77957, 77961, 77966, 0, 77970, + 77974, 77978, 77983, 77987, 0, 77991, 0, 0, 0, 77995, 77999, 78003, + 78007, 78011, 78016, 78020, 0, 78025, 78029, 78033, 78038, 78042, 78046, + 78051, 78055, 78059, 78063, 78067, 78072, 78076, 78080, 78084, 78088, + 78092, 78097, 78101, 78105, 78109, 78113, 78117, 78122, 78126, 78131, + 78136, 78141, 78146, 78152, 78157, 78162, 78168, 78173, 78178, 78183, + 78188, 78194, 78199, 78204, 78209, 78214, 78219, 78225, 78230, 78235, + 78240, 78245, 78250, 78256, 78261, 78267, 78273, 78278, 78283, 78289, + 78294, 78299, 78305, 78310, 78315, 78320, 78325, 78331, 78336, 78341, + 78346, 78351, 78356, 78362, 78367, 78372, 78377, 78382, 78387, 78393, + 78398, 78404, 78410, 78414, 78418, 78423, 78427, 78431, 78436, 78440, + 78444, 78448, 78452, 78457, 78461, 78465, 78469, 78473, 78477, 78482, + 78486, 78490, 78494, 78498, 78502, 78507, 78511, 78516, 78521, 78525, + 78529, 78534, 78538, 78542, 78547, 78551, 78555, 78559, 78563, 78568, + 78572, 78576, 78580, 78584, 78588, 78593, 78597, 78601, 78605, 78609, + 78613, 78618, 78622, 78627, 78632, 78637, 78642, 78648, 78653, 78658, + 78664, 78669, 78674, 78679, 78684, 78690, 78695, 78700, 78705, 78710, + 78715, 78721, 78726, 78731, 78736, 78741, 78746, 78752, 78757, 78763, + 78769, 78774, 78779, 78785, 78790, 78795, 78801, 78806, 78811, 78816, + 78821, 78827, 78832, 78837, 78842, 78847, 78852, 78858, 78863, 78868, + 78873, 78878, 78883, 78889, 78894, 78900, 78906, 78911, 78916, 78922, + 78927, 78932, 78938, 78943, 78948, 78953, 78958, 78964, 78969, 78974, + 78979, 78984, 78989, 78995, 79000, 79005, 79010, 79015, 79020, 79026, + 79031, 79037, 79043, 79048, 79053, 79059, 79064, 79069, 79075, 79080, + 79085, 79090, 79095, 79101, 79106, 79111, 79116, 79121, 79126, 79132, + 79137, 79142, 79147, 79152, 79157, 79163, 79168, 79174, 79180, 79186, + 79192, 79199, 79205, 79211, 79218, 79224, 79230, 79236, 79242, 79249, + 79255, 79261, 79267, 79273, 79279, 79286, 79292, 79298, 79304, 79310, + 79316, 79323, 79329, 79336, 79343, 79349, 79355, 79362, 79368, 79374, + 79381, 79387, 79393, 79399, 79405, 79412, 79418, 79424, 79430, 79436, + 79442, 79449, 79455, 79461, 79467, 79473, 79479, 79486, 79492, 79499, + 79506, 79510, 79514, 79519, 79523, 79527, 79532, 79536, 79540, 79544, + 79548, 79553, 79557, 79561, 79565, 79569, 79573, 79578, 79582, 79586, + 79590, 79594, 79598, 79603, 79607, 79612, 79617, 79621, 79625, 79630, + 79634, 79638, 79643, 79647, 79651, 79655, 79659, 79664, 79668, 79672, + 79676, 79680, 79684, 79689, 79693, 79697, 79701, 79705, 79709, 79714, + 79718, 79723, 79728, 79734, 0, 0, 79740, 79745, 79750, 79755, 79760, + 79765, 79770, 79775, 79780, 79785, 79790, 79795, 79800, 79805, 79810, + 79815, 79820, 79825, 79831, 79836, 79841, 79846, 79851, 79856, 79861, + 79866, 79870, 79875, 79880, 79885, 79890, 79895, 79900, 79905, 79910, + 79915, 79920, 79925, 79930, 79935, 79940, 79945, 79950, 79955, 79961, + 79966, 79971, 79976, 79981, 79986, 79991, 79996, 80002, 80007, 80012, + 80017, 80022, 80027, 80032, 80037, 80042, 80047, 80052, 80057, 80062, + 80067, 80072, 80077, 80082, 80087, 80092, 80097, 80102, 80107, 80112, + 80117, 80123, 80128, 80133, 80138, 80143, 80148, 80153, 80158, 80162, + 80167, 80172, 80177, 80182, 80187, 80192, 80197, 80202, 80207, 80212, + 80217, 80222, 80227, 80232, 80237, 80242, 80247, 80253, 80258, 80263, + 80268, 80273, 80278, 80283, 80288, 80294, 80299, 80304, 80309, 80314, + 80319, 80324, 80330, 80336, 80342, 80348, 80354, 80360, 80366, 80372, + 80378, 80384, 80390, 80396, 80402, 80408, 80414, 80420, 80426, 80433, + 80439, 80445, 80451, 80457, 80463, 80469, 80475, 80480, 80486, 80492, + 80498, 80504, 80510, 80516, 80522, 80528, 80534, 80540, 80546, 80552, + 80558, 80564, 80570, 80576, 80582, 80589, 80595, 80601, 80607, 80613, + 80619, 80625, 80631, 80638, 80644, 80650, 80656, 80662, 80668, 80674, + 80680, 80686, 80692, 80698, 80704, 80710, 80716, 80722, 80728, 80734, + 80740, 80746, 80752, 80758, 80764, 80770, 80776, 80783, 80789, 80795, + 80801, 80807, 80813, 80819, 80825, 80830, 80836, 80842, 80848, 80854, + 80860, 80866, 80872, 80878, 80884, 80890, 80896, 80902, 80908, 80914, + 80920, 80926, 80932, 80939, 80945, 80951, 80957, 80963, 80969, 80975, + 80981, 80988, 80994, 81000, 81006, 81012, 81018, 81024, 81031, 81038, + 81045, 81052, 81059, 81066, 81073, 81080, 81087, 81094, 81101, 81108, + 81115, 81122, 81129, 81136, 81143, 81151, 81158, 81165, 81172, 81179, + 81186, 81193, 81200, 81206, 81213, 81220, 81227, 81234, 81241, 81248, + 81255, 81262, 81269, 81276, 81283, 81290, 81297, 81304, 81311, 81318, + 81325, 81333, 81340, 81347, 81354, 81361, 81368, 81375, 81382, 81390, + 81397, 81404, 81411, 81418, 81425, 0, 0, 0, 0, 81432, 81437, 81441, + 81445, 81449, 81453, 81457, 81461, 81465, 81469, 81473, 81478, 81482, + 81486, 81490, 81494, 81498, 81502, 81506, 81510, 81514, 81519, 81523, + 81527, 81531, 81535, 81539, 81543, 81547, 81551, 81555, 81561, 81566, + 81571, 81576, 81581, 81586, 81591, 81596, 81601, 81606, 81611, 81615, + 81619, 81623, 81627, 81631, 81635, 81639, 81643, 81647, 81651, 81655, + 81659, 81663, 81667, 81671, 81675, 81679, 81683, 81687, 81691, 81695, + 81699, 81703, 81707, 81711, 81715, 81719, 81723, 81727, 81731, 81735, + 81739, 81743, 81747, 81751, 81755, 81759, 81763, 81767, 81771, 81775, + 81779, 81783, 81787, 81791, 81795, 81799, 81803, 81807, 81811, 81815, + 81819, 81823, 81827, 81831, 81835, 81839, 81843, 81847, 81851, 81855, + 81859, 81863, 81867, 81871, 81875, 81879, 81883, 81887, 81891, 81895, + 81899, 81903, 81907, 81911, 81915, 81919, 81923, 81927, 81931, 81935, + 81939, 81943, 81947, 81951, 81955, 81959, 81963, 81967, 81971, 81975, + 81979, 81983, 81987, 81991, 81995, 81999, 82003, 82007, 82011, 82015, + 82019, 82023, 82027, 82031, 82035, 82039, 82043, 82047, 82051, 82055, + 82059, 82063, 82067, 82071, 82075, 82079, 82083, 82087, 82091, 82095, + 82099, 82103, 82107, 82111, 82115, 82119, 82123, 82127, 82131, 82135, + 82139, 82143, 82147, 82151, 82155, 82159, 82163, 82167, 82171, 82175, + 82179, 82183, 82187, 82191, 82195, 82199, 82203, 82207, 82211, 82215, + 82219, 82223, 82227, 82231, 82235, 82239, 82243, 82247, 82251, 82255, + 82259, 82263, 82267, 82271, 82275, 82279, 82283, 82287, 82291, 82295, + 82299, 82303, 82307, 82311, 82315, 82319, 82323, 82327, 82331, 82335, + 82339, 82343, 82347, 82351, 82355, 82359, 82363, 82367, 82371, 82375, + 82379, 82383, 82387, 82391, 82395, 82399, 82403, 82407, 82411, 82415, + 82419, 82423, 82427, 82431, 82435, 82439, 82443, 82447, 82451, 82455, + 82459, 82463, 82467, 82471, 82475, 82479, 82483, 82487, 82491, 82495, + 82499, 82503, 82507, 82511, 82515, 82519, 82523, 82527, 82531, 82535, + 82539, 82543, 82547, 82551, 82555, 82559, 82563, 82567, 82571, 82575, + 82579, 82583, 82587, 82591, 82595, 82599, 82603, 82607, 82611, 82615, + 82619, 82623, 82627, 82631, 82635, 82639, 82643, 82647, 82651, 82655, + 82659, 82663, 82667, 82671, 82675, 82679, 82683, 82687, 82691, 82695, + 82699, 82703, 82707, 82711, 82715, 82719, 82723, 82727, 82731, 82735, + 82739, 82743, 82747, 82751, 82755, 82759, 82763, 82767, 82771, 82775, + 82779, 82783, 82787, 82791, 82795, 82799, 82803, 82807, 82811, 82815, + 82819, 82823, 82827, 82831, 82835, 82839, 82843, 82847, 82851, 82855, + 82859, 82863, 82867, 82871, 82875, 82879, 82883, 82887, 82891, 82895, + 82899, 82903, 82907, 82911, 82915, 82919, 82923, 82927, 82931, 82935, + 82939, 82943, 82947, 82951, 82955, 82959, 82963, 82967, 82971, 82975, + 82979, 82983, 82987, 82991, 82995, 82999, 83003, 83007, 83011, 83015, + 83019, 83023, 83027, 83031, 83035, 83039, 83043, 83047, 83051, 83055, + 83059, 83063, 83067, 83071, 83075, 83079, 83083, 83087, 83091, 83095, + 83099, 83103, 83107, 83111, 83115, 83119, 83123, 83127, 83131, 83135, + 83139, 83143, 83147, 83151, 83155, 83159, 83163, 83167, 83171, 83175, + 83179, 83183, 83187, 83191, 83195, 83199, 83203, 83207, 83211, 83215, + 83219, 83223, 83227, 83231, 83235, 83239, 83243, 83247, 83251, 83255, + 83259, 83263, 83267, 83271, 83275, 83279, 83283, 83287, 83291, 83295, + 83299, 83303, 83307, 83311, 83315, 83319, 83323, 83327, 83331, 83335, + 83339, 83343, 83347, 83351, 83355, 83359, 83363, 83367, 83371, 83375, + 83379, 83383, 83387, 83391, 83395, 83399, 83403, 83407, 83411, 83415, + 83419, 83423, 83427, 83431, 83435, 83439, 83443, 83447, 83451, 83455, + 83459, 83463, 83467, 83471, 83475, 83479, 83483, 83487, 83491, 83495, + 83499, 83503, 83507, 83511, 83515, 83519, 83523, 83527, 83531, 83535, + 83539, 83543, 83547, 83551, 83555, 83559, 83563, 83567, 83571, 83575, + 83579, 83583, 83587, 83591, 83595, 83599, 83603, 83607, 83611, 83615, + 83619, 83623, 83627, 83631, 83635, 83639, 83643, 83647, 83651, 83655, + 83659, 83663, 83667, 83671, 83675, 83679, 83683, 83687, 83691, 83695, + 83699, 83703, 83707, 83711, 83715, 83719, 83723, 83727, 83731, 83735, + 83739, 83743, 83747, 83751, 83755, 83759, 83763, 83767, 83771, 83775, + 83779, 83783, 83787, 83791, 83795, 83799, 83803, 83807, 83811, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 83815, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 83819, 83822, 83826, 83830, 83833, 83837, 83841, + 83844, 83847, 83851, 83855, 83858, 83862, 83865, 83868, 83872, 83875, + 83879, 83882, 83885, 83888, 83891, 83894, 83897, 83900, 83903, 83906, + 83909, 83912, 83916, 83920, 83924, 83928, 83933, 83938, 83943, 83949, + 83954, 83959, 83965, 83970, 83975, 83980, 83985, 83991, 83996, 84001, + 84006, 84011, 84016, 84022, 84027, 84032, 84037, 84042, 84047, 84053, + 84058, 84064, 84070, 84074, 84079, 84083, 84087, 84091, 84096, 84101, + 84106, 84112, 84117, 84122, 84128, 84133, 84138, 84143, 84148, 84154, + 84159, 84164, 84169, 84174, 84179, 84185, 84190, 84195, 84200, 84205, + 84210, 84216, 84221, 84227, 84233, 84238, 84242, 84247, 84249, 84253, + 84256, 84259, 84262, 84265, 84268, 84271, 84274, 84277, 84280, 84283, + 84286, 84289, 84292, 84295, 84298, 84301, 84304, 84307, 84310, 84313, + 84316, 84319, 84322, 84325, 84328, 84331, 84334, 84337, 84340, 84343, + 84346, 84349, 84352, 84355, 84358, 84361, 84364, 84367, 84370, 84373, + 84376, 84379, 84382, 84385, 84388, 84391, 84394, 84397, 84400, 84403, + 84406, 84409, 84412, 84415, 84418, 84421, 84424, 84427, 84430, 84433, + 84436, 84439, 84442, 84445, 84448, 84451, 84454, 84457, 84460, 84463, + 84466, 84469, 84472, 84475, 84478, 84481, 84484, 84487, 84490, 84493, + 84496, 84499, 84502, 84505, 84508, 84511, 84514, 84517, 84520, 84523, + 84526, 84529, 84532, 84535, 84538, 84541, 84544, 84547, 84550, 84553, + 84556, 84559, 84562, 84565, 84568, 84571, 84574, 84577, 84580, 84583, + 84586, 84589, 84592, 84595, 84598, 84601, 84604, 84607, 84610, 84613, + 84616, 84619, 84622, 84625, 84628, 84631, 84634, 84637, 84640, 84643, + 84646, 84649, 84652, 84655, 84658, 84661, 84664, 84667, 84670, 84673, + 84676, 84679, 84682, 84685, 84688, 84691, 84694, 84697, 84700, 84703, + 84706, 84709, 84712, 84715, 84718, 84721, 84724, 84727, 84730, 84733, + 84736, 84739, 84742, 84745, 84748, 84751, 84754, 84757, 84760, 84763, + 84766, 84769, 84772, 84775, 84778, 84781, 84784, 84787, 84790, 84793, + 84796, 84799, 84802, 84805, 84808, 84811, 84814, 84817, 84820, 84823, + 84826, 84829, 84832, 84835, 84838, 84841, 84844, 84847, 84850, 84853, + 84856, 84859, 84862, 84865, 84868, 84871, 84874, 84877, 84880, 84883, + 84886, 84889, 84892, 84895, 84898, 84901, 84904, 84907, 84910, 84913, + 84916, 84919, 84922, 84925, 84928, 84931, 84934, 84937, 84940, 84943, + 84946, 84949, 84952, 84955, 84958, 84961, 84964, 84967, 84970, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +/* name->code dictionary */ +static unsigned int code_hash[] = { + 120470, 4851, 118860, 43024, 0, 66306, 7929, 64584, 9518, 6609, 120203, + 42166, 11319, 1097, 917856, 12064, 41730, 596, 8570, 66517, 12650, 8651, + 41728, 12738, 41835, 12995, 41202, 1373, 0, 11403, 5816, 119067, 64810, + 1000, 120676, 11951, 41140, 1209, 9717, 195073, 118972, 1073, 194579, + 65470, 41138, 8851, 917962, 64500, 12167, 1115, 8874, 9794, 194660, + 917846, 120753, 12237, 3966, 41603, 6587, 9290, 65222, 41600, 9231, + 120183, 2959, 1457, 3535, 195021, 42179, 63860, 41538, 6671, 8618, 42175, + 3404, 64661, 5148, 41737, 1759, 917565, 119974, 65257, 118949, 12290, + 66577, 120019, 9386, 12312, 10151, 8205, 118818, 5131, 917899, 9627, + 65930, 9834, 3055, 9852, 1944, 1248, 10148, 11398, 119990, 64543, 12701, + 119204, 9348, 603, 917851, 65327, 119998, 63781, 65111, 3350, 66576, + 64318, 917828, 8154, 3390, 119985, 41817, 119956, 64603, 66328, 65668, + 120013, 3400, 120015, 6041, 65020, 41899, 66446, 8002, 8562, 4364, 63991, + 4043, 8712, 64134, 7813, 11297, 120759, 10124, 7526, 8601, 6069, 10143, + 4814, 12041, 1418, 10885, 12673, 118961, 65307, 9660, 2764, 13012, 4571, + 5704, 120483, 119946, 12078, 2970, 5457, 5440, 8857, 917898, 118803, + 2843, 5355, 41599, 118883, 119004, 5194, 11657, 119362, 3486, 65324, + 12472, 10123, 65167, 194738, 10717, 8714, 2637, 64629, 8460, 10682, 8476, + 10602, 800, 917613, 66506, 65673, 1019, 64335, 11631, 8465, 12289, 64144, + 762, 13172, 10681, 8488, 5412, 10906, 1353, 194636, 41351, 41823, 5828, + 8206, 120166, 8933, 1601, 9072, 858, 13302, 12458, 120774, 8090, 5418, + 12452, 120081, 9483, 3351, 120602, 64510, 10817, 917939, 41539, 2750, + 11570, 556, 41855, 41246, 65564, 11277, 65892, 2760, 10620, 12195, 7608, + 65809, 64156, 5498, 9998, 41536, 64151, 63876, 9242, 3459, 8997, 11787, + 64153, 64152, 65734, 120184, 4839, 6615, 68115, 1874, 119016, 4975, 4635, + 295, 64124, 64123, 6050, 64898, 917804, 7600, 7590, 63903, 9036, 63901, + 19941, 3971, 66609, 119195, 2952, 64116, 6287, 8031, 2725, 63899, 63898, + 5482, 667, 12332, 1177, 6086, 12322, 11027, 5172, 41617, 64102, 7859, + 1945, 64099, 9815, 10453, 19934, 63882, 7997, 8555, 63878, 63877, 8705, + 64097, 64096, 9571, 528, 9172, 120170, 9828, 41723, 63875, 41578, 11460, + 7432, 63854, 41913, 9056, 195005, 6188, 64593, 6155, 10806, 446, 6494, + 64065, 41318, 63850, 63, 41878, 63846, 2972, 9455, 6639, 64064, 63849, + 63848, 63847, 1176, 120649, 8302, 8276, 63842, 4178, 13208, 13188, 10948, + 10041, 8105, 4333, 9855, 64112, 1105, 4180, 5388, 12094, 65879, 65197, + 7714, 63890, 5443, 7768, 5538, 9987, 194803, 118932, 1678, 917611, 552, + 9560, 64077, 10785, 8996, 4992, 4471, 12080, 9159, 10171, 63861, 10486, + 5540, 63858, 41781, 281, 63863, 12075, 42041, 64646, 5174, 120337, 3589, + 1388, 3123, 43018, 1077, 13272, 8408, 11531, 120387, 43042, 9223, 195029, + 65318, 42773, 119117, 42105, 1116, 13274, 43049, 3663, 43050, 1112, + 119122, 8686, 8881, 5334, 42108, 119937, 13087, 64091, 9322, 194701, + 6509, 64095, 5327, 8111, 19907, 41877, 3478, 7583, 6199, 2903, 195093, + 3001, 1158, 8745, 11329, 4741, 63866, 4737, 4370, 4846, 41616, 4742, + 41335, 4118, 1797, 64600, 805, 65691, 46, 12070, 8760, 298, 65452, 12212, + 120123, 65174, 63836, 32, 5965, 65469, 11495, 12225, 3665, 63837, 64793, + 65330, 41336, 4305, 66360, 8083, 917590, 119333, 63821, 4412, 63819, + 63818, 12244, 5227, 9047, 12283, 4181, 4752, 9029, 4634, 560, 5643, 8226, + 6181, 63812, 13247, 63810, 63790, 3639, 63815, 10122, 63813, 6047, 7937, + 63961, 780, 206, 42008, 4936, 7498, 1098, 19923, 120205, 1093, 9882, + 3016, 4869, 63932, 917554, 63929, 3546, 1605, 65058, 6182, 65566, 13176, + 8400, 11343, 63920, 917550, 5471, 2984, 5314, 9287, 5473, 44, 194667, + 194682, 13169, 5290, 5283, 1695, 63827, 1088, 5961, 1900, 1084, 1085, + 63829, 1083, 6581, 5576, 917793, 64184, 4263, 1092, 4754, 8947, 5252, + 120431, 65253, 64183, 917819, 7908, 11011, 120390, 6579, 194878, 2965, + 119177, 8808, 64710, 1089, 7761, 41641, 42119, 12355, 63889, 940, 5787, + 9992, 63938, 5057, 64679, 12463, 2994, 5054, 41694, 65794, 9664, 41026, + 1437, 9399, 658, 3497, 12920, 7486, 660, 5060, 666, 9022, 5532, 118941, + 5533, 5059, 4727, 6118, 222, 979, 3884, 12459, 7488, 5773, 978, 120163, + 7489, 41619, 10239, 12465, 917761, 118902, 64411, 13271, 1707, 120319, + 12461, 63895, 63949, 63948, 63947, 3376, 6038, 63943, 63942, 63894, + 65323, 194944, 65508, 7776, 64278, 2379, 8703, 63893, 64668, 801, 8125, + 1690, 63919, 63918, 63917, 2369, 65042, 12844, 65800, 119235, 5486, 2334, + 64893, 4463, 5483, 10207, 917608, 2367, 5484, 63909, 264, 2375, 8060, + 6194, 5485, 1844, 64035, 9061, 5534, 10672, 4502, 13178, 253, 118819, + 1823, 8800, 10746, 7912, 0, 10256, 6192, 194946, 42771, 11576, 119616, + 725, 4550, 13257, 120800, 118944, 12892, 917868, 64087, 41775, 8413, + 194805, 120146, 5693, 10397, 120440, 13209, 5074, 5073, 120438, 8983, + 120525, 41132, 66586, 5072, 19964, 6198, 11614, 65731, 196, 13206, 3111, + 64725, 4929, 12445, 0, 119074, 194646, 66606, 6628, 1076, 11294, 1436, + 4934, 64415, 41323, 7543, 195098, 12807, 63907, 63906, 4548, 4329, 6113, + 4979, 3048, 4423, 41320, 194963, 10515, 6218, 8971, 5071, 65583, 3642, + 1430, 5070, 10042, 118835, 3987, 5068, 7619, 3255, 3493, 917952, 8905, + 10735, 120134, 41635, 3378, 4531, 1245, 9105, 66311, 4921, 4481, 3771, + 65544, 2710, 41693, 64084, 41724, 64709, 41682, 41690, 120120, 4922, 325, + 992, 120305, 4925, 1628, 0, 9526, 4920, 65262, 948, 10783, 120208, 4930, + 917570, 4462, 194855, 4933, 5339, 6115, 65359, 4928, 917603, 4457, + 120506, 65290, 42163, 722, 5684, 8678, 12637, 65624, 5689, 8753, 1509, + 120180, 5468, 9511, 194968, 65183, 1672, 6205, 5832, 6310, 5686, 194931, + 64800, 64536, 120713, 41475, 50, 917926, 9871, 120115, 1679, 11982, + 10759, 41883, 66468, 3183, 13259, 4448, 119225, 401, 6427, 64930, 64763, + 5761, 342, 8553, 1151, 8143, 67589, 11983, 64384, 624, 65443, 42014, + 119630, 5078, 12501, 5656, 120168, 5076, 118870, 8812, 119170, 11538, + 685, 9025, 1524, 8003, 66467, 5539, 8087, 12971, 120101, 9894, 1252, + 12925, 194611, 4636, 194615, 118985, 8053, 9732, 917983, 5080, 13121, + 5036, 5035, 118968, 12277, 65904, 194780, 8074, 275, 12158, 194594, 8741, + 4432, 120610, 5033, 120668, 64605, 4836, 3888, 473, 65584, 8502, 120250, + 1873, 1087, 12499, 917808, 63844, 12345, 3601, 1922, 6409, 64965, 65422, + 12502, 120683, 12505, 66321, 66477, 9489, 119140, 3432, 4384, 63964, + 6094, 41530, 8815, 12851, 64753, 119950, 1676, 1154, 3857, 1205, 5030, + 917917, 13100, 12958, 10519, 9622, 194674, 64723, 4421, 10592, 0, 495, + 119007, 10544, 7983, 118882, 10749, 64186, 8494, 11980, 10979, 41710, + 947, 64187, 437, 41709, 10969, 65894, 7613, 9465, 13290, 4795, 4997, + 64306, 8826, 11486, 4999, 120611, 8626, 4590, 4711, 120255, 65037, 2739, + 19942, 8044, 40964, 251, 12686, 7895, 4395, 119927, 119926, 119929, 1779, + 6600, 6601, 41543, 5325, 642, 65830, 8880, 7685, 120071, 66729, 6234, + 13229, 625, 8187, 9990, 1113, 194643, 7915, 1104, 120176, 8179, 10655, + 195043, 9316, 10980, 2489, 1082, 8150, 1359, 194645, 194726, 119304, + 119555, 5042, 5041, 42769, 12084, 8049, 7509, 194806, 6458, 120182, + 119575, 4761, 10506, 4766, 1616, 1273, 120187, 8795, 118876, 194835, + 63957, 9232, 1138, 10483, 12677, 41545, 12881, 3239, 65517, 119558, + 66614, 119111, 42128, 3484, 64545, 11778, 11572, 8503, 5122, 41527, 5040, + 4924, 119014, 119085, 120201, 120748, 5039, 41926, 8303, 8282, 5038, + 65736, 10003, 7427, 65611, 120586, 1686, 120190, 9359, 11467, 3664, + 65921, 8238, 6662, 66472, 119329, 3863, 126, 4835, 68119, 120605, 13245, + 4309, 7744, 63867, 119846, 119023, 13184, 63870, 65431, 569, 8136, + 119010, 711, 1633, 120583, 63869, 4762, 1103, 194560, 12281, 4765, 41331, + 1006, 13040, 4760, 1550, 8201, 10871, 917990, 1102, 5031, 118904, 66671, + 64499, 11546, 13042, 337, 194781, 65781, 65678, 12279, 1111, 65780, + 119900, 4707, 194635, 5008, 7883, 8822, 7880, 4522, 8255, 5512, 13010, + 119232, 8304, 64313, 11611, 5906, 1119, 13039, 13038, 64910, 2455, 64734, + 13008, 41652, 4385, 12492, 11020, 6499, 64775, 119161, 13009, 160, 68110, + 120679, 64262, 5052, 64031, 5821, 6186, 41792, 42770, 5051, 65773, 1429, + 64573, 5050, 302, 388, 12058, 735, 6637, 1079, 3867, 5708, 12726, 119879, + 9117, 5706, 10679, 5513, 6666, 4005, 0, 5510, 10991, 120454, 65458, 2470, + 917581, 13305, 1925, 65760, 194914, 41924, 10092, 5048, 5047, 41532, + 10058, 917559, 119999, 9070, 12049, 3339, 8089, 1106, 639, 65764, 63967, + 3340, 3109, 3653, 4599, 10799, 6674, 10605, 917585, 1476, 648, 1754, + 11001, 3233, 864, 41782, 10164, 8972, 41865, 3530, 9750, 120690, 11024, + 6656, 5192, 4338, 5046, 8512, 63770, 13199, 8967, 1236, 5045, 12012, + 13189, 7986, 5044, 120102, 7440, 13128, 5043, 9553, 1590, 63777, 63776, + 9669, 12341, 8654, 8402, 63779, 1583, 4740, 13260, 3586, 13276, 11444, + 120306, 67634, 119606, 41523, 13296, 517, 12922, 11354, 11700, 41528, + 123, 65454, 12393, 11394, 41997, 10531, 7784, 13194, 1334, 11978, 4479, + 1126, 65586, 120663, 195061, 8520, 3925, 917621, 8069, 4357, 42154, 489, + 120450, 119836, 8848, 6476, 8450, 43044, 11926, 41557, 1145, 63788, 7910, + 63785, 63784, 754, 8711, 6183, 8183, 120741, 8928, 65166, 7952, 10747, + 125, 9235, 64861, 64207, 12689, 66445, 10779, 10990, 3523, 1074, 13258, + 9536, 8477, 11014, 4427, 10517, 63757, 7726, 11325, 19922, 267, 1349, + 10713, 1371, 12149, 195003, 2458, 63753, 6201, 41084, 41074, 4266, 10652, + 6483, 41077, 3402, 9050, 3398, 8140, 42084, 6260, 3391, 41075, 2476, + 41956, 11988, 3898, 10625, 10201, 10988, 11524, 63794, 10367, 12521, + 10431, 13014, 6289, 1068, 6673, 12523, 12945, 12524, 12438, 7950, 10804, + 13233, 12082, 4386, 9053, 12473, 2793, 12475, 704, 195020, 6195, 9530, + 6660, 12232, 194892, 64159, 5681, 12629, 4595, 63760, 792, 65538, 13004, + 9897, 8742, 195013, 64947, 65448, 63744, 12948, 64787, 7588, 63748, 1693, + 63746, 63745, 5055, 9883, 4287, 1090, 4902, 1131, 11665, 194602, 4558, + 1816, 9523, 41712, 168, 194897, 4898, 63857, 6157, 12960, 4901, 1821, + 13191, 12170, 3500, 3139, 791, 9162, 12485, 10306, 119001, 64200, 13006, + 64433, 8354, 10033, 941, 12037, 7557, 65570, 10565, 8234, 64559, 8228, + 8424, 10246, 64193, 12811, 65925, 3946, 42764, 8057, 41990, 673, 194853, + 64357, 917971, 194799, 9547, 288, 8752, 120820, 2448, 10025, 10267, 2918, + 2452, 65300, 41529, 8729, 64726, 2790, 7845, 3793, 194715, 4408, 4122, + 11568, 41535, 8723, 10709, 10087, 119302, 731, 42109, 11548, 2438, 64587, + 65396, 119169, 1175, 13256, 1282, 373, 119172, 5396, 8653, 8557, 7723, 0, + 3330, 120278, 41952, 917566, 5273, 8248, 5269, 3304, 5202, 2404, 5267, + 119357, 1627, 65549, 5277, 12963, 5371, 6189, 4125, 1826, 12133, 65241, + 8260, 1271, 917589, 195006, 64643, 9035, 3864, 12707, 4631, 3879, 118785, + 68125, 4166, 164, 9331, 7567, 7459, 119568, 10212, 5384, 41882, 67647, + 64346, 0, 68159, 917822, 41388, 120518, 12005, 12666, 13175, 13207, 8706, + 5552, 10172, 700, 5929, 5553, 12978, 120384, 5356, 7499, 8563, 41888, + 3180, 917818, 917960, 5554, 971, 12344, 8724, 194608, 6665, 63874, + 120275, 2866, 8517, 11455, 13190, 64632, 120227, 5555, 10045, 12882, + 13275, 120672, 41522, 11480, 9143, 6668, 41525, 120539, 195035, 656, + 118808, 43034, 4577, 12229, 8715, 68133, 194613, 120261, 4269, 64813, + 119163, 41609, 10476, 950, 118980, 3932, 41450, 68140, 66683, 68130, + 120014, 11974, 118884, 369, 119096, 41784, 66459, 5097, 4935, 9848, + 64216, 10293, 4796, 10317, 3651, 10127, 120603, 10269, 5102, 5101, 66628, + 9064, 8138, 120455, 404, 5100, 1439, 12093, 1247, 8092, 119330, 5099, + 1831, 1441, 4793, 3063, 650, 12292, 746, 120165, 120769, 7461, 12018, + 9031, 12182, 10115, 9078, 8545, 4422, 4708, 3799, 3268, 64556, 9118, + 119127, 2676, 7750, 4374, 64398, 6190, 1364, 64589, 8038, 68121, 9857, + 120638, 9858, 195033, 64170, 12129, 13174, 8481, 12412, 6202, 64380, + 10920, 10872, 2365, 7841, 120059, 5108, 5107, 11010, 13210, 6176, 65561, + 5541, 41785, 41171, 11291, 5284, 4372, 207, 194904, 4275, 119930, 854, + 68147, 120189, 12965, 384, 5103, 10404, 10340, 10702, 1556, 488, 13236, + 12937, 10017, 9733, 13187, 10014, 7844, 41373, 13198, 5203, 120517, + 13232, 5106, 349, 4863, 41371, 10965, 41367, 5105, 11721, 12861, 4398, + 5104, 5672, 304, 1096, 120557, 0, 932, 12441, 6567, 238, 65681, 4318, + 10452, 19905, 8032, 13243, 13237, 12719, 67640, 66570, 64814, 64884, + 119872, 10670, 8597, 1178, 64017, 9864, 13195, 8803, 309, 6622, 8151, + 10858, 64961, 7722, 12553, 10459, 12568, 12066, 12549, 66590, 12570, + 9712, 41417, 41496, 194943, 9805, 4965, 13150, 10538, 19944, 41401, + 120252, 120164, 6191, 6261, 119342, 119341, 11965, 1957, 10420, 982, + 2756, 9370, 2720, 12357, 41455, 2925, 118817, 13056, 3222, 13212, 10116, + 41644, 10105, 10378, 41581, 10834, 118793, 64407, 5242, 41963, 64476, + 1694, 8216, 10814, 67598, 7781, 6306, 64568, 917916, 120738, 11793, + 42057, 7594, 64598, 120325, 64799, 3475, 64206, 2479, 9709, 3632, 120322, + 10698, 65616, 3648, 3907, 10297, 67639, 3636, 19928, 2979, 8837, 8286, + 1843, 3936, 119052, 11699, 41347, 65119, 13235, 3640, 41248, 120579, + 4379, 13239, 12692, 7969, 12927, 66353, 194951, 12703, 120509, 41846, + 2529, 734, 10808, 65146, 42083, 9872, 957, 42055, 1846, 66367, 12181, + 9634, 120310, 9988, 12991, 1670, 5740, 119597, 10072, 5379, 120318, + 41163, 41157, 785, 8236, 194812, 9027, 63897, 13267, 64383, 64688, 925, + 41955, 120541, 41773, 41071, 9586, 120312, 41984, 9217, 6151, 12110, + 120689, 65572, 64580, 4016, 13265, 13264, 381, 12386, 6100, 42077, + 120768, 5808, 5184, 8200, 12967, 10810, 5612, 4583, 19943, 5860, 67633, + 64575, 194842, 812, 3615, 65284, 5178, 194929, 119015, 9825, 5188, 9698, + 7814, 120063, 10692, 1166, 64429, 41921, 924, 9756, 12359, 119258, + 194843, 2442, 10703, 120696, 67632, 8012, 5674, 12353, 119561, 12361, + 5677, 67626, 66657, 40972, 12453, 41920, 5673, 12751, 5676, 8542, 12694, + 118978, 2468, 1294, 41294, 3336, 3883, 64388, 1727, 194680, 64054, 3605, + 119632, 195015, 12034, 8718, 3550, 736, 7806, 4505, 2715, 806, 5826, + 41884, 5813, 64279, 65391, 5841, 5837, 64731, 12702, 3105, 2405, 5838, + 5796, 120604, 65259, 5793, 5735, 5866, 5797, 1432, 5865, 12143, 7956, + 598, 66448, 41886, 2480, 120152, 19952, 9037, 5671, 5537, 12749, 67601, + 10932, 41359, 1211, 847, 65690, 9529, 11799, 12318, 120766, 43026, 5645, + 10622, 41391, 194967, 64378, 6566, 917913, 5650, 11358, 119102, 13110, + 194834, 9624, 194928, 8284, 65896, 2748, 1554, 194733, 4035, 6492, 66504, + 4265, 2929, 3977, 65344, 12051, 836, 5698, 2488, 194634, 4582, 66514, + 5644, 10292, 12926, 8046, 7528, 8372, 11707, 65116, 119206, 11439, 13201, + 1374, 64878, 12742, 41013, 10568, 41374, 4030, 2869, 120776, 41015, + 65897, 2785, 400, 12597, 42051, 120540, 64477, 6661, 5659, 9884, 4759, + 118906, 390, 10266, 41349, 1170, 3473, 7718, 118962, 1609, 902, 917855, + 120062, 66352, 11661, 8122, 5712, 66308, 8004, 1887, 9540, 10278, 2554, + 5158, 5714, 41136, 194970, 64351, 807, 66652, 120793, 64677, 976, 5511, + 6146, 65518, 771, 10954, 41356, 9673, 11412, 11026, 41143, 8676, 7904, + 5579, 953, 451, 119560, 5578, 12635, 11491, 9724, 194697, 118881, 9524, + 7490, 118789, 1440, 3379, 10310, 7487, 12561, 471, 7484, 7482, 3795, + 7480, 7479, 7478, 7477, 6501, 7475, 64900, 7473, 7472, 2474, 7470, 6546, + 93, 10615, 10213, 8128, 12551, 10049, 8171, 3544, 194628, 6017, 65311, + 383, 120216, 13306, 10533, 7870, 63884, 5187, 119991, 1456, 120217, + 42164, 64217, 194702, 5232, 917994, 19961, 2472, 41005, 120699, 8710, + 6019, 4256, 119959, 4980, 8860, 9640, 10028, 12845, 66607, 13182, 65121, + 120685, 120308, 10631, 65126, 7972, 118928, 8066, 119623, 7900, 8316, + 11309, 11273, 119040, 64211, 120309, 64212, 10347, 445, 119029, 195074, + 12931, 64927, 8330, 65783, 66597, 64213, 64366, 64369, 8814, 3902, 64607, + 1770, 194723, 12836, 64208, 64552, 65821, 4584, 9684, 120714, 917944, + 10866, 65792, 1118, 7464, 194989, 8964, 1081, 7436, 64565, 8162, 9342, + 5996, 119245, 4903, 64332, 41386, 5162, 41007, 1330, 64486, 40995, 12209, + 12047, 41384, 194789, 195067, 1848, 4334, 65352, 9880, 64066, 10674, + 5522, 195014, 61, 120157, 195065, 3633, 41980, 65162, 41234, 12089, + 65871, 9771, 66685, 13251, 41959, 64749, 6262, 2784, 195040, 9334, 8126, + 66483, 64967, 7975, 441, 194591, 917599, 11608, 4884, 40999, 120269, + 120334, 10495, 6313, 10890, 119354, 65834, 8324, 7855, 2345, 67599, 463, + 64737, 194821, 119607, 3117, 5460, 119356, 1193, 10056, 1148, 12396, + 13252, 7829, 42173, 118994, 7743, 917981, 13248, 5499, 63763, 118960, + 9034, 6039, 120544, 5663, 119182, 41018, 65683, 10338, 2482, 1471, + 120086, 120077, 66370, 12378, 41966, 41970, 3084, 12374, 10903, 6638, + 10422, 911, 2460, 120499, 11944, 12376, 41032, 40996, 120614, 12380, + 5520, 64473, 10869, 5870, 64670, 13310, 2603, 12326, 539, 10826, 65105, + 917932, 3853, 11949, 64901, 120260, 64883, 10722, 41810, 8659, 120090, + 12474, 66721, 5857, 65342, 2478, 119120, 4162, 7942, 4260, 12953, 42028, + 120089, 12470, 64941, 11798, 2742, 12476, 1891, 10946, 9101, 5000, 66647, + 12302, 3018, 12942, 5748, 194584, 7771, 6161, 917934, 8796, 0, 6412, + 118986, 8519, 13146, 41973, 12906, 9422, 10333, 2882, 4366, 119123, + 12843, 4520, 917810, 65626, 10648, 118898, 4014, 12842, 194724, 12015, + 13117, 8275, 3893, 66362, 5810, 12210, 195071, 42147, 11536, 13292, + 65685, 12938, 10427, 9154, 3844, 63934, 9755, 1110, 6612, 10892, 8231, + 10775, 6473, 41968, 783, 10219, 3591, 41969, 917997, 2453, 8518, 3620, + 11466, 12443, 4556, 10349, 10413, 194569, 41159, 3202, 8599, 10510, 4382, + 66482, 195002, 10842, 687, 9177, 8902, 63950, 1840, 41751, 12400, 120177, + 4883, 285, 4723, 41917, 9788, 4459, 64158, 1634, 41958, 9155, 240, 9786, + 65082, 41919, 8579, 9743, 7981, 13134, 118878, 4508, 64178, 41999, 11328, + 119817, 65589, 63887, 3081, 11463, 120080, 119051, 119353, 10445, 41720, + 194662, 120229, 2614, 9024, 64620, 1729, 119840, 64289, 65221, 63883, + 65466, 64852, 64509, 41447, 63916, 64855, 41203, 5001, 41879, 11355, + 4121, 5003, 884, 41214, 63879, 4943, 5150, 7500, 5278, 7773, 643, 3086, + 118912, 64652, 120068, 58, 194621, 6167, 66656, 63872, 6594, 66366, + 11295, 41495, 3624, 43036, 118901, 64655, 2721, 9616, 63988, 19929, + 11296, 10500, 10440, 9611, 4264, 119303, 194657, 7738, 41857, 11446, + 12638, 64522, 3435, 3094, 12916, 9754, 66314, 4437, 41292, 8899, 12748, + 42058, 9517, 11518, 917889, 65360, 120700, 119047, 63956, 4306, 41380, + 11995, 63960, 9591, 8323, 10217, 67602, 11469, 120578, 12456, 2723, + 120061, 5088, 5086, 917783, 8524, 7752, 11397, 2880, 0, 194669, 2872, + 1386, 65034, 3498, 4378, 65039, 4270, 12392, 65036, 7853, 6633, 12101, + 5822, 5230, 194573, 710, 917790, 11663, 1666, 8161, 371, 12013, 63891, + 42092, 119103, 415, 63851, 63892, 11708, 42096, 5183, 1877, 7538, 7924, + 2927, 4324, 6608, 4472, 1244, 331, 194858, 12683, 10662, 64678, 4756, + 63831, 65852, 10730, 7691, 10331, 65320, 41964, 6238, 8938, 8628, 6043, + 118801, 64895, 1604, 9565, 10539, 120814, 41220, 13032, 120519, 120193, + 10032, 8750, 12373, 63828, 11992, 1351, 194868, 8698, 12190, 3622, 1930, + 65237, 9621, 10463, 63981, 4967, 13031, 1966, 2330, 195099, 3657, 120498, + 65202, 6000, 4347, 4416, 42098, 11009, 10694, 8099, 402, 41916, 13147, + 41912, 42100, 12217, 9695, 1897, 7562, 3515, 5170, 11805, 11796, 676, + 6259, 41742, 65558, 41870, 65553, 3536, 65093, 9752, 63902, 6162, 10532, + 66490, 10113, 41829, 65886, 5159, 12422, 41832, 439, 66640, 119611, + 11280, 12481, 2325, 40970, 41830, 120647, 917799, 5145, 12486, 65018, + 66516, 5409, 8976, 120051, 12336, 4135, 9685, 341, 2727, 4129, 3539, + 66616, 11530, 41736, 7913, 5405, 63859, 4131, 41267, 64721, 63865, 4133, + 63864, 210, 4600, 8082, 3254, 4137, 119205, 119853, 119062, 194577, + 120534, 4591, 65077, 64671, 194671, 3355, 9508, 3393, 561, 5723, 195, + 64261, 3377, 12497, 41269, 917545, 13135, 917993, 8368, 119224, 41499, + 917798, 11435, 917920, 41498, 120628, 1379, 246, 12603, 9680, 3788, 2924, + 42168, 12812, 8728, 64906, 119213, 8917, 120645, 301, 64765, 3969, 64964, + 9575, 64562, 40966, 9652, 64919, 42064, 42086, 120542, 194728, 8491, + 194962, 41876, 63772, 3182, 327, 120323, 9042, 118827, 917776, 42169, + 4755, 194684, 64660, 11443, 12431, 8668, 12434, 608, 600, 5999, 1219, + 3934, 9494, 11483, 917919, 1726, 1015, 64686, 8212, 11395, 64202, 13160, + 7759, 65363, 485, 43037, 65291, 8811, 927, 42102, 194979, 12436, 9351, + 7778, 64379, 7496, 65335, 7491, 1208, 7495, 64757, 9337, 64362, 917778, + 11348, 12235, 9021, 194949, 917830, 120066, 19914, 3742, 8758, 9648, + 64617, 63834, 9150, 63835, 1117, 13037, 2594, 63809, 10691, 12052, 6550, + 10469, 65212, 11265, 2546, 119216, 213, 65309, 10554, 3972, 917972, + 194678, 64194, 6554, 12416, 11914, 5452, 8230, 64197, 41951, 12418, + 42049, 3882, 8532, 2713, 1573, 9650, 42136, 4596, 66339, 1406, 120041, + 40990, 194593, 12414, 8287, 4143, 120378, 10489, 1143, 4141, 9682, 12415, + 1508, 42763, 8779, 10569, 8725, 120783, 65045, 11724, 119064, 4145, + 64872, 65751, 66613, 119576, 8027, 41505, 9171, 9550, 11400, 12518, + 65178, 65397, 6528, 10740, 65753, 64816, 10998, 66333, 12955, 10596, + 2888, 119572, 65033, 7715, 3881, 41487, 12118, 67622, 2878, 5390, 64167, + 3009, 41476, 41489, 63765, 3007, 1448, 2975, 10429, 3889, 8521, 5083, + 5082, 7503, 5235, 803, 194590, 3014, 5081, 8986, 11002, 10632, 11934, + 11452, 1332, 64802, 3929, 4597, 65532, 64767, 1791, 5191, 9288, 9657, + 2892, 10577, 6031, 555, 64173, 0, 194927, 12367, 42170, 11540, 63930, + 629, 1924, 119880, 11270, 64162, 5858, 8462, 8005, 12365, 1784, 1361, + 118939, 12369, 7905, 67644, 5077, 194668, 10880, 63927, 5075, 120065, + 9371, 65075, 41193, 11007, 1625, 10997, 917907, 1342, 66684, 64171, 3434, + 4843, 4506, 195060, 5266, 120521, 5272, 4482, 4507, 9578, 63923, 66319, + 7979, 64381, 9831, 64417, 65529, 461, 7984, 41972, 4504, 444, 42145, + 9127, 5276, 43021, 118922, 120179, 119638, 11349, 12848, 5177, 41324, + 12055, 8722, 120805, 1197, 65512, 1149, 4114, 409, 4383, 8900, 8948, + 7684, 3492, 721, 10182, 9108, 119005, 195041, 11954, 119191, 12993, + 40963, 3099, 917979, 65088, 41087, 119834, 12587, 66643, 120374, 12036, + 194736, 65123, 41576, 8152, 120721, 64428, 12227, 8578, 5995, 7573, + 41575, 2922, 63946, 63944, 11493, 194883, 2670, 4167, 194873, 11723, + 120025, 65173, 68154, 13023, 938, 917954, 195044, 11737, 9721, 118937, + 41017, 9606, 8504, 4024, 41063, 11411, 12334, 65231, 4153, 11911, 10793, + 5250, 12407, 3395, 4404, 6056, 12401, 11490, 5775, 42005, 41607, 68183, + 41091, 12205, 1344, 8870, 194744, 4940, 4735, 7683, 1167, 12822, 4983, + 120554, 861, 64907, 120045, 120458, 65149, 63896, 120651, 12039, 10559, + 11956, 119841, 118892, 9472, 4282, 6631, 120188, 12816, 9596, 7618, + 12710, 64147, 11579, 4101, 0, 64704, 5992, 7616, 65828, 64422, 1004, + 9632, 120185, 853, 0, 12627, 10953, 194681, 5016, 65619, 120441, 11300, + 9491, 9686, 5890, 917914, 7558, 12712, 195077, 65627, 10718, 13154, 3461, + 9139, 64756, 194990, 119151, 65628, 0, 13227, 12585, 6669, 119152, 12177, + 41708, 12860, 41098, 10015, 10838, 4900, 10352, 120742, 10061, 5903, + 4119, 5140, 209, 64002, 11520, 9702, 11702, 8277, 9245, 13048, 4927, + 4138, 41093, 65286, 64412, 2410, 993, 41025, 13054, 12394, 120020, + 917579, 68162, 12685, 64938, 65475, 10781, 41230, 64299, 5010, 1680, + 9107, 118809, 10659, 3600, 10968, 120027, 1336, 41518, 194796, 5896, + 119838, 5993, 2819, 12950, 12706, 12966, 1893, 120462, 63915, 917768, + 8184, 272, 1363, 8793, 8411, 63908, 41502, 3077, 983, 68118, 1512, + 119941, 1190, 4109, 1335, 841, 5888, 41358, 9836, 9544, 120021, 41481, + 8313, 7832, 65515, 3090, 2409, 817, 1664, 1850, 66690, 3079, 4731, 10118, + 66629, 64541, 12033, 1255, 11689, 9247, 64350, 66633, 12389, 66610, + 195078, 41996, 11526, 63985, 5864, 1147, 11690, 5835, 1551, 66625, 5480, + 7858, 11653, 4116, 11688, 66634, 1094, 194, 12384, 118987, 8180, 41686, + 12313, 41531, 63904, 13273, 6114, 10898, 195082, 64578, 8247, 507, 91, + 7545, 10695, 10952, 7534, 10896, 10036, 7857, 6067, 774, 65915, 2744, + 119815, 5994, 12539, 41420, 41601, 8359, 65264, 6028, 66511, 13167, + 120277, 7719, 119875, 2486, 7893, 41059, 162, 5436, 917583, 119809, 9687, + 64956, 6304, 65457, 6051, 120495, 5262, 5904, 66658, 12681, 194710, + 194616, 12406, 12219, 3652, 10537, 917946, 10492, 64550, 6549, 279, + 195030, 119978, 64619, 12403, 1489, 120771, 4132, 4899, 3899, 1007, + 42124, 4976, 2343, 4103, 19946, 120806, 10750, 1345, 120355, 120801, + 12859, 8956, 4098, 65267, 5861, 65559, 11999, 12151, 64804, 194856, + 12645, 5146, 11320, 64730, 64174, 41094, 492, 8685, 12974, 41060, 67613, + 41551, 5147, 2582, 11470, 64538, 7444, 1928, 118998, 9594, 5991, 10862, + 67609, 2527, 194809, 197, 2799, 8241, 64181, 65348, 65874, 194840, 64179, + 767, 4127, 120464, 10138, 119808, 0, 8897, 63911, 41553, 8357, 4124, + 1799, 65371, 42148, 194663, 12954, 120231, 65340, 1123, 963, 2434, 10120, + 12405, 41339, 2493, 398, 392, 9723, 6407, 119011, 7945, 64935, 4402, + 7570, 12402, 65926, 41392, 8414, 12408, 41265, 65713, 406, 120326, 9164, + 12411, 0, 4560, 6623, 4961, 64494, 1575, 64682, 5438, 165, 9993, 41467, + 63953, 8064, 9093, 9599, 9147, 118831, 63958, 4987, 9148, 2399, 4096, 53, + 10944, 12368, 65435, 119192, 8178, 64149, 3367, 12910, 10884, 727, 65272, + 119238, 5805, 1947, 11527, 194589, 42176, 12370, 11655, 1705, 5411, 8898, + 118810, 12372, 120642, 195023, 8017, 65287, 8813, 12366, 10963, 6066, + 1329, 4909, 3052, 9220, 66464, 4904, 66666, 10803, 1365, 9253, 42757, + 41264, 7462, 120712, 119350, 119814, 1499, 66727, 8055, 120803, 8740, + 5398, 63962, 13120, 8924, 917764, 5988, 3660, 12017, 11781, 9476, 8788, + 1357, 42113, 65743, 3629, 8774, 13005, 119082, 3628, 120172, 64394, 1933, + 3469, 1567, 42116, 11969, 64809, 2928, 4905, 2487, 851, 3121, 1804, 3311, + 67615, 9114, 194880, 12083, 9315, 4822, 4906, 3852, 2847, 6675, 3236, + 11317, 1251, 7777, 41852, 7951, 1198, 9132, 120767, 12274, 510, 10259, + 9865, 65686, 4561, 6018, 1398, 917869, 12276, 66487, 19931, 119061, + 11406, 8167, 12127, 41932, 840, 120300, 2443, 10918, 10410, 120338, 1001, + 9241, 1927, 333, 41930, 120272, 8144, 8034, 10680, 119598, 66663, 64199, + 12867, 64198, 6678, 7769, 7519, 12621, 65150, 8904, 518, 4764, 65165, + 41168, 13204, 4387, 857, 10530, 65369, 12736, 120724, 41044, 66458, + 11543, 9358, 67594, 42078, 5136, 1968, 19937, 66605, 1337, 10581, 1629, + 4533, 796, 66494, 6490, 194921, 12038, 119338, 12664, 195037, 65461, + 9798, 6120, 478, 1948, 68128, 10962, 952, 6016, 195055, 195088, 9512, + 4276, 1206, 3619, 41638, 13263, 3843, 8142, 8853, 3361, 41795, 490, + 10715, 3436, 65011, 63841, 12817, 9847, 6676, 3930, 12854, 13240, 6154, + 9551, 65354, 65346, 784, 65357, 334, 64797, 1453, 7541, 8940, 120329, + 8500, 10428, 10364, 64715, 778, 4317, 10004, 7989, 64676, 3227, 119583, + 67606, 120514, 120684, 10855, 13102, 41702, 10309, 6672, 10277, 194958, + 66691, 41624, 5415, 9613, 9001, 4526, 3462, 65215, 64520, 41020, 6664, + 66701, 42056, 9759, 64957, 3963, 120304, 8114, 1469, 65244, 65381, 41744, + 4988, 66453, 118956, 9598, 904, 352, 194760, 1451, 1356, 8453, 4134, + 120377, 917802, 1619, 9703, 41745, 3955, 8575, 119180, 1201, 64732, + 12846, 917980, 41860, 11919, 64962, 41550, 5289, 13144, 8511, 9460, 823, + 9675, 12305, 5940, 226, 2649, 12387, 1253, 13183, 65766, 500, 64521, + 9081, 1658, 11936, 64735, 65761, 8702, 11606, 64784, 9785, 42123, 64783, + 194619, 917779, 5152, 8935, 7533, 119101, 5304, 119820, 616, 4323, 64666, + 4684, 65103, 120613, 65735, 65339, 10560, 6048, 4763, 4112, 118935, + 10870, 5260, 5328, 65129, 326, 9681, 4475, 917933, 10771, 2876, 194915, + 119935, 6035, 41398, 41192, 9802, 13261, 120532, 453, 41396, 917564, + 6481, 12140, 9572, 41937, 10392, 10328, 40998, 7704, 66432, 120317, 9800, + 4123, 917900, 42103, 41000, 7854, 119239, 6487, 8334, 64061, 10344, 9808, + 11271, 5394, 4126, 12800, 9521, 9589, 41200, 41306, 4425, 119856, 10464, + 63802, 64769, 1288, 64514, 11528, 63984, 12173, 679, 64012, 41914, 5850, + 758, 7536, 10796, 4474, 10742, 10693, 64006, 1587, 64005, 10541, 64581, + 65490, 1369, 12134, 119050, 7927, 64009, 1139, 64030, 64026, 64029, 8970, + 64948, 4430, 195016, 10774, 4514, 66434, 12421, 8194, 194765, 1852, 3057, + 65483, 8893, 64032, 12542, 12973, 65341, 120497, 41206, 7925, 12423, + 10475, 917572, 3496, 1352, 10933, 7707, 9102, 627, 42034, 6158, 8327, + 64497, 65605, 6040, 917592, 10129, 64863, 9336, 11696, 5730, 1018, 7798, + 64474, 64259, 1682, 64290, 7820, 42756, 12951, 119873, 7746, 1492, 0, + 8288, 12563, 10728, 5127, 11285, 65509, 5495, 4273, 11577, 9644, 10849, + 1833, 2999, 120612, 64373, 120471, 185, 65085, 6023, 169, 5497, 7535, + 8085, 917909, 65717, 9749, 8224, 6131, 1949, 4117, 7847, 120489, 119982, + 5321, 66355, 65765, 9313, 2589, 64408, 1689, 7802, 4683, 120167, 12303, + 64667, 66704, 1184, 0, 815, 8273, 120807, 6049, 120530, 4027, 834, + 119833, 1803, 64683, 1503, 8995, 120653, 917924, 5731, 1381, 2387, 64511, + 12430, 8289, 10981, 12654, 2881, 65514, 917600, 9601, 332, 9668, 9766, + 5142, 2407, 65618, 66601, 6036, 64881, 4026, 8645, 64789, 2887, 6489, + 3526, 6298, 119136, 64475, 4833, 1834, 65621, 8572, 6021, 10940, 65249, + 119848, 8662, 65739, 119604, 2652, 7463, 11539, 10784, 120720, 64391, + 166, 19913, 8635, 9706, 10623, 408, 1828, 195084, 13298, 194889, 7426, + 8168, 6280, 12324, 7607, 10639, 66713, 4832, 64557, 41643, 6279, 12508, + 8713, 10690, 9161, 41645, 1620, 6645, 646, 66726, 66711, 42129, 609, + 11555, 3472, 8697, 41086, 119594, 4343, 6212, 917557, 11413, 5809, 1950, + 239, 119021, 637, 65785, 41592, 43029, 917539, 120285, 194837, 3247, + 120754, 12985, 12696, 65213, 66668, 65260, 12929, 10983, 712, 120291, + 119337, 41567, 65592, 194969, 120171, 119852, 120178, 119137, 1506, 8285, + 65617, 4509, 65608, 12651, 12216, 64628, 40988, 11961, 6204, 41727, 7494, + 64341, 2396, 41703, 41493, 13062, 41757, 355, 9719, 3886, 9814, 63912, + 68123, 65444, 996, 42075, 64880, 43045, 65199, 194810, 8655, 8222, + 194839, 7939, 10342, 64720, 3178, 68184, 120552, 5907, 19932, 3976, + 917849, 42161, 9471, 5833, 11966, 12555, 5969, 5699, 12562, 12550, 9488, + 40982, 8489, 0, 1488, 194829, 13149, 119997, 9799, 5265, 66612, 1563, + 11487, 9619, 12464, 119210, 120758, 118952, 41704, 5803, 7797, 6070, + 10006, 41181, 465, 6082, 13078, 9692, 194745, 12567, 8116, 795, 66480, + 7843, 12462, 3607, 10831, 10046, 9612, 42153, 8218, 9485, 66714, 120301, + 12468, 8607, 1008, 65322, 3306, 66485, 65138, 6057, 508, 120264, 1766, + 11282, 11996, 1820, 4547, 0, 638, 6083, 120160, 12308, 0, 2305, 917595, + 64777, 9470, 4345, 6659, 65236, 4818, 6085, 9899, 65207, 3915, 41634, + 5382, 41639, 119591, 6235, 119060, 4028, 1787, 19920, 41979, 120786, + 3249, 1768, 1130, 12328, 501, 42016, 10601, 43023, 6503, 65294, 7742, + 63992, 13280, 41922, 6505, 118925, 5310, 9475, 66716, 120810, 6500, 5526, + 65049, 11408, 65889, 8568, 119818, 11449, 9678, 5403, 120311, 9869, + 63780, 1771, 12460, 8936, 120631, 118832, 64903, 10760, 119115, 9158, + 66567, 120259, 119025, 120582, 5410, 5783, 10365, 8403, 5400, 11594, + 120295, 5027, 9326, 10491, 119348, 4831, 120698, 5028, 5587, 66492, 7540, + 5026, 4923, 65086, 8981, 12382, 8931, 120755, 1415, 8866, 917785, 65513, + 10461, 12103, 119602, 8642, 5029, 42766, 1580, 3598, 120067, 41070, + 10053, 120819, 6663, 119325, 6026, 41515, 118796, 64592, 1716, 1461, 910, + 11907, 620, 41001, 3658, 41541, 119980, 66728, 7617, 5024, 12888, 41003, + 68180, 5025, 11529, 41514, 64561, 5703, 119124, 41517, 41504, 41519, + 66473, 9726, 119160, 5849, 623, 781, 670, 10660, 5769, 613, 6105, 11584, + 477, 1268, 65275, 8906, 592, 1578, 2636, 64404, 10815, 11619, 8225, + 119578, 654, 6451, 653, 652, 7721, 647, 7869, 633, 120224, 42152, 64361, + 12480, 6119, 829, 39, 12487, 19950, 120399, 65865, 6616, 65672, 12489, + 9667, 391, 5550, 194870, 482, 917886, 1203, 120345, 1813, 64544, 41311, + 9503, 120623, 2877, 120249, 64135, 1675, 4939, 5315, 194801, 64128, + 10070, 10595, 13293, 4576, 42094, 12808, 119569, 4277, 40997, 4039, + 120429, 64472, 368, 13036, 3960, 65460, 8406, 68176, 120121, 66679, 3958, + 12132, 1849, 194564, 270, 13086, 10714, 194617, 11929, 11959, 917824, + 64657, 41608, 3618, 65009, 9069, 6273, 5156, 364, 9595, 929, 67616, + 42035, 707, 1555, 41725, 8691, 66435, 224, 41662, 68164, 9332, 4966, + 194977, 917538, 4578, 64513, 3841, 194647, 65922, 10732, 13074, 850, + 4972, 9356, 12820, 2909, 63968, 1286, 10166, 8682, 11544, 10203, 9608, + 12815, 7730, 11962, 41540, 12507, 1196, 0, 66471, 777, 10020, 4375, + 41372, 6641, 525, 12198, 120443, 8763, 120526, 41628, 533, 11931, 8658, + 120743, 41520, 2705, 65010, 13126, 9838, 4377, 8559, 7765, 119925, 8280, + 13193, 2701, 11666, 8679, 5767, 1576, 7735, 9809, 8353, 11513, 41960, + 42007, 66452, 10889, 1748, 7757, 65265, 120226, 12803, 66493, 2718, 4168, + 3061, 13308, 63764, 6596, 1179, 4440, 194759, 7694, 363, 8896, 63768, + 3485, 12987, 41586, 64908, 120332, 41149, 1591, 6593, 64625, 10192, + 64143, 66455, 13053, 10013, 5630, 194622, 120686, 9492, 10390, 13083, + 12833, 5543, 41327, 1640, 12495, 630, 120091, 3138, 10996, 41127, 1043, + 120674, 12498, 10090, 917568, 917609, 313, 65543, 8615, 119144, 12540, + 493, 41426, 5750, 1717, 9417, 479, 9405, 11268, 0, 9398, 9403, 3520, + 8426, 12490, 63855, 65185, 12586, 12493, 5815, 10707, 1002, 12491, + 194884, 12934, 631, 66474, 64922, 13161, 41303, 917957, 10546, 67635, + 65711, 11600, 65786, 2797, 13107, 65599, 306, 714, 3058, 8507, 65576, + 66700, 119961, 120731, 120694, 11607, 65591, 64711, 68166, 7909, 9157, + 4569, 63758, 63805, 13297, 7603, 40986, 180, 244, 11542, 12898, 12494, + 12674, 8244, 362, 65776, 64145, 8037, 194830, 11535, 120680, 4882, 5185, + 64866, 5521, 4885, 5519, 42155, 10302, 4880, 10104, 1027, 1360, 248, + 12424, 10523, 1446, 4319, 41646, 991, 5189, 63754, 10494, 65777, 1722, + 1870, 120151, 470, 9427, 65271, 5523, 194716, 64527, 4579, 120446, 9549, + 12511, 10549, 12514, 9661, 66486, 12000, 9602, 8623, 65172, 120042, + 119855, 13095, 12512, 11615, 13041, 6150, 9846, 659, 6098, 0, 1174, + 10334, 194592, 8311, 12510, 63856, 12107, 120341, 12513, 9284, 12471, + 120733, 12330, 917571, 63853, 119854, 2323, 65288, 2319, 6293, 12477, + 118807, 2311, 194661, 4415, 237, 6281, 917902, 0, 9010, 2309, 7897, 8173, + 64894, 12469, 7483, 118979, 1736, 10609, 3894, 12228, 9397, 10987, 3383, + 9396, 9393, 693, 9130, 314, 9389, 6209, 9387, 9388, 4932, 3842, 9383, + 5332, 12204, 9285, 10436, 8185, 41808, 1751, 273, 8165, 13166, 2313, + 65449, 7948, 9236, 8544, 4528, 2584, 6301, 41880, 6133, 10484, 9463, + 917823, 9339, 7943, 3757, 3147, 195092, 12420, 10421, 120488, 2310, + 41112, 2326, 9382, 2565, 9380, 7596, 7921, 9375, 9376, 1683, 9374, 2567, + 8596, 12444, 4044, 41274, 12527, 8210, 120756, 1023, 474, 12331, 0, + 42032, 8744, 726, 9839, 120313, 5005, 120383, 41276, 42030, 5007, 12522, + 9835, 65442, 4951, 634, 12213, 10895, 65492, 274, 120236, 1858, 4744, + 4746, 917852, 9548, 65899, 403, 120117, 12503, 9610, 8068, 8197, 63996, + 699, 42000, 41665, 1819, 10496, 13007, 42182, 7581, 13262, 194649, 41667, + 12506, 10840, 1923, 13084, 12500, 64507, 12509, 64393, 10507, 120692, + 10589, 6464, 41047, 2996, 1937, 41931, 12990, 8084, 4047, 3608, 8281, + 65016, 1107, 68101, 9076, 8862, 120636, 293, 9369, 64766, 64791, 7803, + 13222, 65416, 10579, 8560, 8546, 11553, 12678, 4803, 9043, 1739, 1941, + 498, 64471, 1713, 119091, 12529, 8042, 11407, 2344, 12528, 6297, 2414, + 64139, 66710, 3231, 11716, 6422, 9902, 65156, 12530, 2537, 969, 41429, + 12658, 13034, 6165, 13035, 917620, 6632, 4719, 469, 119240, 4363, 5211, + 8914, 119299, 119334, 1772, 1435, 64876, 2969, 6046, 64812, 6208, 64101, + 5746, 12215, 119332, 4931, 1951, 8612, 119363, 9607, 917904, 338, 118797, + 5061, 10675, 41106, 10767, 1491, 8115, 65459, 11941, 10139, 8227, 8270, + 1218, 12126, 41993, 12168, 6642, 63808, 12889, 1622, 41108, 4486, 41995, + 1075, 1958, 10925, 41992, 41506, 118975, 10249, 64122, 10257, 41569, + 10273, 120327, 7692, 12669, 8008, 120320, 330, 8566, 65083, 9046, 41117, + 41126, 12532, 120648, 64131, 3508, 7794, 119943, 64129, 9645, 64662, + 10770, 3669, 3968, 64115, 66644, 13028, 120302, 12537, 194802, 64120, + 65720, 12536, 2350, 13029, 6583, 120072, 12116, 13030, 66678, 4527, 1588, + 12538, 8409, 65718, 10683, 41670, 787, 9502, 4948, 12484, 4032, 118940, + 7449, 65399, 6207, 120536, 6117, 65401, 8412, 65247, 7438, 8734, 644, + 9769, 41657, 10149, 3659, 9533, 184, 1553, 10827, 12488, 65382, 10502, + 41556, 12623, 65474, 2354, 120214, 8220, 118856, 6295, 901, 41510, 7953, + 118826, 5157, 4020, 63811, 11927, 66584, 13079, 194959, 41687, 64303, + 120735, 7520, 848, 9868, 65620, 6424, 194714, 65916, 66495, 64094, + 118926, 7877, 2352, 41826, 120726, 64576, 11289, 1407, 10911, 65607, + 13026, 120503, 7941, 11715, 8362, 8903, 9777, 66715, 1871, 5869, 8636, + 120290, 1343, 65160, 12649, 9325, 13025, 6283, 11738, 12643, 194623, + 65181, 11741, 8543, 10051, 9216, 8263, 11279, 41258, 8625, 118840, 11290, + 10477, 3136, 8733, 11582, 8315, 13022, 8772, 64588, 0, 6152, 41456, 5477, + 6629, 10112, 19916, 13020, 66723, 8675, 120324, 194766, 67600, 120351, + 10978, 8029, 6091, 120350, 4485, 3335, 64591, 3590, 9776, 41397, 66578, + 5215, 194750, 3333, 1632, 63900, 3588, 3342, 9341, 5363, 12957, 12725, + 68113, 63852, 64076, 223, 64079, 1611, 13246, 13018, 65835, 63792, 65245, + 3337, 1171, 11275, 11736, 41097, 1805, 6482, 41423, 64113, 11945, 8708, + 13046, 8838, 425, 4025, 5013, 41868, 120235, 2392, 13047, 4530, 120105, + 10617, 1213, 119233, 120103, 797, 118814, 7888, 13050, 120349, 64387, + 4115, 65557, 65862, 65587, 3277, 8929, 4947, 41055, 195072, 64276, 426, + 66497, 13045, 8251, 10136, 7751, 120109, 8371, 119253, 1224, 12806, 8768, + 13044, 10701, 1764, 3101, 64469, 8480, 1078, 9757, 65223, 41057, 65567, + 120572, 8663, 9312, 4413, 4539, 3787, 42160, 9222, 67617, 9165, 1572, + 9092, 12593, 41961, 2346, 12724, 8958, 66653, 9646, 3773, 41825, 1293, + 7947, 12003, 120228, 13043, 8056, 2454, 5349, 208, 194718, 65869, 64849, + 65888, 8816, 10699, 6408, 0, 7825, 5661, 917587, 12595, 3603, 41109, + 2398, 3548, 1157, 64291, 8638, 68167, 917821, 3115, 194771, 11321, + 118787, 8235, 4405, 10086, 4876, 194808, 195085, 119256, 65430, 10624, + 6079, 12646, 10764, 8158, 41561, 41472, 998, 13051, 13105, 3143, 120156, + 194673, 41559, 1896, 7882, 13052, 118948, 5665, 530, 65814, 11269, + 120566, 12002, 64526, 5742, 5664, 4692, 8979, 12310, 4007, 5004, 11330, + 7896, 751, 6595, 3382, 63959, 66373, 13231, 11533, 64874, 4732, 6311, + 194936, 11596, 63976, 1626, 63977, 10110, 64056, 41705, 6420, 6598, + 64327, 6599, 2795, 4910, 65308, 118825, 119328, 6275, 6597, 41699, 8340, + 119335, 3229, 6423, 42774, 11019, 65390, 5407, 12823, 2331, 41678, 42026, + 6137, 2336, 7524, 194816, 66720, 42759, 8339, 1921, 120003, 19927, + 195038, 822, 64870, 9903, 4284, 119593, 194648, 43010, 12841, 9229, + 10956, 41255, 12607, 5311, 1795, 965, 3521, 10587, 5774, 8325, 917931, + 65403, 917915, 1854, 10794, 119250, 10057, 6294, 3144, 64780, 5280, + 65019, 4344, 12905, 41610, 6076, 748, 12385, 768, 535, 442, 9507, 194641, + 119346, 10556, 2475, 12388, 4889, 8968, 6071, 3593, 64093, 4804, 2342, + 917797, 1800, 120098, 4894, 467, 4890, 120342, 64644, 120707, 4893, 8421, + 12433, 10666, 4888, 502, 64080, 64615, 41490, 120142, 12043, 10119, 316, + 65878, 10230, 65191, 41297, 64924, 64086, 64746, 2332, 4860, 412, 65728, + 11997, 12432, 9583, 8058, 5546, 8019, 194597, 66561, 63750, 12203, 5544, + 2355, 8913, 65725, 4875, 10613, 66692, 12137, 5548, 9344, 6250, 7944, + 65582, 13104, 6077, 12383, 64519, 119132, 11301, 3134, 119339, 65696, + 4669, 917812, 917789, 194894, 3050, 63839, 10319, 119075, 10383, 118842, + 4592, 11008, 10809, 194800, 4691, 6543, 9345, 621, 917597, 120055, 4328, + 10734, 120032, 64631, 917906, 7804, 19904, 10811, 8457, 10545, 4914, + 10271, 3786, 8886, 4917, 66461, 64914, 7923, 3716, 5464, 9996, 8508, + 2361, 7971, 8195, 194706, 9566, 7682, 3722, 8086, 41707, 10845, 545, + 2312, 40977, 10050, 10874, 8305, 8859, 41458, 40980, 65110, 13202, + 195028, 12582, 9119, 2787, 7920, 41521, 4021, 6288, 7985, 119349, 5653, + 65802, 10891, 7698, 5658, 410, 41552, 1802, 12220, 4913, 120466, 41659, + 41671, 1827, 917894, 64396, 41668, 9077, 2327, 8810, 11422, 120372, + 12705, 3860, 10756, 9239, 8821, 6153, 2867, 119118, 42158, 698, 120359, + 8749, 10356, 12698, 64858, 361, 12641, 845, 194599, 41560, 11970, 4562, + 63756, 2926, 119566, 4099, 66439, 194695, 7936, 120303, 611, 68124, 4716, + 118891, 41382, 119207, 7686, 120568, 194595, 68178, 120543, 118875, + 119612, 6291, 5462, 10823, 41669, 9734, 65455, 9071, 4655, 4151, 13295, + 0, 66632, 839, 42162, 7695, 8769, 65246, 10737, 119194, 4859, 64467, + 65504, 4826, 64157, 41090, 917837, 6647, 64727, 66447, 63845, 2700, + 12576, 7842, 12839, 120825, 804, 2699, 66596, 10542, 2985, 119222, 64806, + 8271, 10091, 11915, 9468, 119312, 9827, 64106, 119311, 286, 12323, + 118830, 11481, 118942, 119305, 1425, 35, 119229, 65084, 66694, 41210, + 64432, 8482, 119113, 6090, 5032, 7812, 10534, 7894, 664, 119588, 5034, + 4272, 65211, 40967, 40965, 42024, 12704, 13294, 66589, 64869, 6032, + 120367, 9129, 7430, 917922, 119609, 68112, 194813, 5244, 6130, 65714, + 41161, 5518, 4174, 1879, 8189, 968, 12222, 1169, 434, 11541, 66573, 6034, + 9739, 64744, 12574, 118867, 194995, 524, 118990, 118934, 788, 120433, + 12679, 64506, 64150, 1663, 10419, 8574, 41227, 118805, 12346, 12855, + 64848, 41030, 10415, 41562, 120599, 65623, 118850, 64571, 0, 19939, + 67614, 959, 8885, 12564, 64333, 118855, 9469, 5195, 5445, 9355, 64323, + 42151, 4644, 8989, 221, 310, 41253, 41564, 8010, 119301, 4962, 63766, + 8855, 10054, 6497, 9091, 917544, 9012, 19958, 12088, 41002, 13215, 65047, + 10451, 64260, 374, 120153, 816, 64634, 120148, 120054, 41934, 3873, 8367, + 917784, 64608, 4715, 6101, 11987, 41936, 194572, 4879, 12723, 65089, + 11683, 307, 120416, 9585, 5374, 64286, 1462, 10235, 41390, 8627, 65579, + 12119, 65028, 13024, 1929, 120426, 12142, 8611, 12236, 41419, 194618, + 66507, 12982, 64374, 5378, 194666, 64295, 41421, 917838, 741, 10083, + 119309, 65026, 821, 65350, 2498, 5800, 10755, 2992, 1760, 8124, 4469, + 2324, 828, 3611, 119084, 757, 1185, 120271, 531, 120728, 10628, 119020, + 120437, 7999, 8204, 3614, 2827, 9696, 10942, 7713, 2348, 4354, 10904, + 4380, 19936, 7833, 10573, 5320, 41240, 862, 3000, 10301, 1810, 3673, + 5137, 9525, 64569, 9354, 65622, 0, 7566, 10121, 64940, 120716, 66693, + 12824, 13066, 3062, 7970, 64741, 12608, 194600, 5871, 41160, 9700, 12580, + 917591, 65748, 119811, 3967, 7898, 13137, 8775, 64560, 12713, 2963, 9090, + 8410, 4454, 723, 1734, 966, 4449, 917815, 64594, 2456, 231, 2320, 120225, + 339, 4968, 120535, 40989, 8075, 1230, 120795, 8047, 3597, 9761, 10584, + 41542, 65404, 1290, 66358, 8352, 917874, 5687, 66698, 3840, 1584, 119963, + 6045, 0, 10498, 9704, 64136, 64138, 10992, 7537, 12311, 8660, 120357, + 8365, 8643, 65029, 119049, 4483, 1709, 64399, 7466, 6080, 13092, 64140, + 1746, 6072, 8667, 12121, 65604, 13140, 11414, 65031, 2531, 4480, 120765, + 64141, 1226, 1259, 7517, 10394, 41231, 10897, 120257, 605, 67619, 641, + 5219, 12342, 64100, 41500, 41129, 311, 11453, 6221, 9075, 120358, 5466, + 10877, 118868, 11451, 120737, 4535, 2667, 4271, 65406, 64188, 345, 41410, + 10829, 41198, 195027, 41407, 64104, 5037, 41131, 1776, 8422, 11266, + 64103, 41508, 4660, 323, 65305, 917813, 6649, 1295, 120010, 4625, 2563, + 4630, 247, 119135, 119870, 12338, 4651, 2668, 6657, 194941, 13223, 11933, + 2519, 119973, 41903, 41079, 5053, 194787, 5049, 119924, 11335, 706, 7754, + 7727, 8738, 4031, 6278, 5009, 9672, 649, 5514, 118920, 66702, 10280, + 12670, 1013, 41218, 3877, 705, 41591, 8755, 194900, 1183, 4184, 8268, + 65918, 65301, 8157, 9736, 64503, 65418, 118921, 4747, 4712, 43013, 11913, + 4718, 194632, 10837, 5141, 10614, 65733, 7962, 12211, 9837, 65831, 64722, + 119008, 5719, 65706, 9773, 119068, 119147, 1857, 65547, 4626, 8464, 859, + 194795, 4629, 8499, 6059, 41134, 4624, 7818, 8535, 119914, 65179, 7805, + 64805, 11488, 12242, 41011, 120220, 64119, 10558, 917955, 917918, 118950, + 8492, 8250, 8459, 120597, 1788, 1579, 10766, 64117, 195050, 8048, 9543, + 9028, 120522, 64516, 65849, 13185, 1285, 64114, 120777, 8240, 8684, 8170, + 6102, 41762, 5298, 12625, 5294, 65204, 42013, 3940, 41597, 119917, + 917873, 9816, 8665, 65851, 11436, 12630, 1653, 64669, 10153, 120601, + 6166, 118791, 118989, 41377, 5292, 66673, 65046, 1939, 913, 3970, 64599, + 12455, 1793, 66637, 120162, 118837, 6643, 8211, 65263, 0, 194703, 64127, + 64081, 119125, 3514, 13219, 9569, 10865, 11958, 5263, 13286, 64126, 5500, + 10022, 65387, 65500, 65384, 5322, 980, 66354, 10008, 5324, 66600, 3784, + 41614, 64751, 6230, 194767, 63885, 10085, 3360, 8098, 11523, 6634, 41734, + 10096, 41613, 8072, 119321, 119322, 41821, 1249, 7783, 41731, 12032, + 8237, 63840, 64899, 12395, 7425, 12818, 120565, 10462, 41150, 194574, + 9795, 66680, 64664, 13213, 194601, 120222, 41152, 194679, 9249, 6565, + 7808, 1829, 120479, 11670, 4358, 65315, 6670, 11426, 194865, 120223, + 12391, 1710, 12160, 10168, 8777, 9781, 49, 6627, 66708, 6258, 8269, + 120594, 9741, 194923, 5649, 119100, 315, 12813, 1643, 119988, 12397, + 3470, 8884, 65175, 41099, 65314, 13299, 1378, 65163, 1072, 120607, + 118802, 3066, 6576, 119300, 120002, 65675, 1080, 41293, 8787, 194828, + 1101, 41618, 120001, 8405, 0, 12632, 1086, 1869, 42088, 7680, 8847, + 10805, 65884, 12639, 3380, 8123, 1091, 6121, 7977, 4501, 12665, 8119, + 12998, 66309, 917927, 1494, 11693, 3127, 194567, 64945, 12930, 1394, + 119230, 65872, 12363, 5345, 9789, 2998, 9527, 120659, 64582, 12977, + 12309, 42090, 3861, 10635, 12939, 12404, 12413, 42003, 2495, 5848, 8726, + 5570, 1881, 12410, 41722, 1012, 8100, 7890, 120296, 11298, 10649, 5569, + 6229, 1593, 65319, 6063, 619, 65128, 65080, 6053, 65602, 4120, 65337, + 64372, 9160, 917928, 119214, 11776, 9366, 9016, 42006, 6055, 3870, 4279, + 2500, 10757, 1507, 8497, 8602, 65316, 13021, 65334, 65333, 11694, 65331, + 42059, 42061, 9080, 120099, 9128, 64480, 5571, 3674, 9740, 9121, 4371, + 5798, 10408, 42085, 10107, 4106, 41989, 65313, 42074, 63999, 11326, 0, + 10233, 13098, 65813, 41239, 10094, 195026, 8182, 0, 119831, 68152, 11947, + 9803, 5847, 1505, 9131, 65161, 4615, 12695, 41988, 41250, 12175, 917864, + 19966, 119582, 7809, 120626, 120445, 562, 8120, 6590, 194565, 13033, + 64738, 3219, 68097, 10664, 1366, 1037, 67623, 4551, 65545, 68131, 66334, + 10637, 4568, 549, 1570, 10478, 2835, 12517, 557, 9457, 5952, 64649, + 41056, 12519, 41004, 119307, 2825, 66636, 10825, 8079, 2821, 41046, 0, + 42071, 12111, 3927, 13071, 12515, 452, 5271, 5492, 64718, 2831, 10604, + 10144, 11465, 5212, 5493, 41120, 8916, 13027, 9747, 12019, 41332, 1618, + 12069, 917584, 1668, 10430, 917766, 5853, 1187, 10363, 1121, 12956, + 120656, 119107, 11314, 3240, 12060, 12194, 65180, 41631, 11591, 5323, + 8166, 4557, 6415, 2707, 8309, 1623, 65297, 41052, 571, 2697, 4918, 11339, + 4912, 2695, 11598, 65048, 66438, 8864, 64755, 64798, 10736, 2693, 12125, + 7615, 12826, 1164, 194583, 6411, 1035, 41067, 119142, 7881, 701, 9758, + 3489, 119296, 7469, 11569, 5248, 12218, 120538, 6303, 3796, 41123, 65688, + 3994, 11421, 10457, 9991, 41128, 64485, 5792, 12347, 9873, 42171, 2855, + 7994, 64762, 6104, 65351, 6591, 9340, 9532, 1589, 119226, 296, 3246, + 7906, 2879, 41981, 41620, 64942, 7815, 65855, 120482, 917817, 66457, + 10585, 12579, 1496, 747, 6416, 942, 2378, 10960, 11618, 5299, 0, 9320, + 5449, 1232, 8139, 6216, 41431, 917970, 11409, 5295, 66624, 64392, 1223, + 1642, 174, 120824, 11612, 4161, 2374, 120546, 8475, 3212, 66313, 3211, + 194576, 5286, 119297, 0, 64142, 9728, 3846, 8070, 5536, 6636, 7705, + 11942, 11305, 12136, 3309, 67612, 66377, 41491, 66325, 4986, 12189, + 41653, 1280, 1241, 917537, 4257, 8496, 67608, 6220, 9004, 65411, 65203, + 41513, 41650, 120791, 194578, 120608, 12914, 12884, 194575, 9890, 6078, + 10237, 917943, 1475, 64917, 11979, 6084, 118900, 41064, 41061, 9635, + 12600, 3256, 41236, 42039, 0, 6469, 65377, 8727, 10654, 4679, 41237, + 64073, 64867, 6531, 65285, 65329, 64069, 10640, 3248, 2613, 3261, 9015, + 119829, 66568, 3635, 64337, 41651, 41241, 64944, 3494, 6449, 6555, 10588, + 66588, 120581, 194783, 67597, 635, 13139, 65898, 65613, 65312, 5447, + 68108, 194826, 64382, 4010, 7445, 8600, 41915, 65804, 4176, 41105, 5812, + 65820, 6232, 65891, 68142, 194588, 318, 5302, 195022, 6538, 4335, 3649, + 3941, 41122, 41110, 3634, 64892, 9113, 1954, 12155, 7866, 120297, 11402, + 11733, 64296, 120138, 66470, 2849, 66375, 66697, 7938, 11728, 1761, 4586, + 65379, 350, 10930, 119090, 509, 194792, 119603, 9365, 66687, 542, 5133, + 41680, 64551, 9500, 11534, 1514, 11668, 65823, 5453, 65533, 64921, + 119967, 2496, 8493, 944, 9368, 3890, 1624, 1438, 8817, 120592, 10818, + 41947, 1220, 120828, 63931, 1194, 3242, 1571, 9555, 8598, 11457, 6169, + 943, 564, 2798, 312, 194999, 11532, 66363, 120161, 8877, 269, 3495, 6272, + 9617, 1460, 8988, 120660, 4891, 195031, 10641, 0, 41119, 41416, 917602, + 4173, 120289, 63786, 120574, 12895, 64955, 41418, 11357, 119022, 120286, + 41415, 6296, 9582, 193, 12188, 917835, 64680, 11428, 1730, 2457, 4493, + 2314, 8427, 1362, 9822, 7703, 8840, 5807, 119054, 120451, 8534, 6658, + 4426, 917796, 41612, 42758, 11497, 7874, 8681, 5220, 120281, 13136, + 119825, 2416, 3310, 10972, 63886, 379, 119215, 13220, 63787, 120449, + 3223, 5517, 1284, 8041, 4549, 120475, 5240, 9811, 10012, 3096, 65239, + 42768, 43040, 8515, 8688, 12866, 64146, 3294, 9501, 119631, 1272, 65485, + 7564, 64654, 7467, 65210, 1467, 10158, 10040, 5288, 9519, 41861, 8132, + 64090, 118899, 12193, 66615, 65493, 3215, 917863, 7710, 1610, 65114, + 12307, 63881, 65682, 66465, 5181, 5275, 120195, 228, 8637, 1501, 66676, + 3789, 5179, 11471, 6225, 10765, 11474, 1725, 66603, 8196, 9352, 12042, + 42752, 917543, 9537, 3961, 5762, 1967, 2605, 4500, 63873, 8104, 4981, + 7474, 3405, 64862, 11667, 10414, 9821, 8141, 9559, 2600, 1557, 7589, + 64851, 64549, 3237, 8631, 2545, 10466, 8541, 917616, 194747, 41866, + 917973, 120430, 42762, 7481, 0, 1650, 262, 1637, 10958, 7901, 3238, + 41945, 65556, 41941, 3308, 65158, 10860, 8614, 65220, 7527, 120624, + 41943, 6419, 120244, 45, 6401, 120022, 8106, 4128, 10065, 64083, 4494, + 9590, 4012, 10395, 917762, 9084, 4537, 8737, 64089, 11004, 695, 739, 696, + 7611, 2620, 42755, 194913, 9227, 7506, 179, 5098, 691, 738, 2853, 7512, + 7515, 3868, 688, 119009, 690, 2548, 737, 974, 2801, 119837, 10854, + 119012, 10034, 3985, 8783, 65860, 9362, 10177, 120247, 4682, 118869, + 12809, 6406, 4685, 3158, 10879, 4389, 4680, 923, 41863, 3851, 292, 13002, + 119845, 119844, 3221, 1763, 64468, 4612, 119851, 119850, 12999, 41219, + 11718, 41314, 10782, 3637, 12996, 119141, 11717, 63922, 10594, 3228, + 11712, 64624, 120405, 10967, 2731, 194721, 9651, 651, 3891, 7696, 66706, + 2337, 1735, 120630, 917891, 4177, 11283, 9089, 66312, 64695, 120580, + 11438, 1860, 2654, 7580, 1856, 7497, 7584, 194722, 66356, 10914, 3458, + 3208, 12975, 8498, 119121, 8949, 3065, 9450, 120472, 1569, 63888, 12534, + 12124, 7690, 119254, 12533, 120251, 6418, 4543, 41471, 917629, 64674, + 42180, 194881, 0, 10859, 917615, 41544, 41689, 63789, 12282, 64909, 6646, + 11790, 8108, 8850, 9238, 5066, 8561, 4573, 13108, 6421, 12791, 119849, 0, + 8257, 12891, 8778, 10630, 12900, 917992, 10950, 8314, 6459, 12790, 8804, + 65092, 41153, 12792, 11342, 42018, 1744, 12789, 10366, 12317, 10137, + 67610, 13164, 10723, 967, 120253, 64546, 12690, 41307, 3257, 65550, 9862, + 1845, 2974, 10446, 11315, 0, 278, 10580, 10089, 870, 66569, 3499, 8609, + 42149, 876, 871, 877, 6002, 878, 42015, 879, 120336, 4563, 65176, 41308, + 7591, 65306, 867, 9520, 872, 8646, 868, 873, 119868, 11514, 869, 874, + 63989, 1940, 875, 790, 220, 65193, 194845, 10678, 10044, 41589, 5429, + 13082, 194585, 6403, 5707, 10393, 120005, 120267, 42067, 41890, 5433, + 10657, 7911, 120266, 1547, 9775, 3959, 119316, 5425, 4977, 2467, 5317, + 5423, 4611, 63843, 8040, 5069, 9679, 4182, 119244, 4676, 120501, 41073, + 4418, 2510, 4628, 10208, 12989, 118784, 10399, 1851, 12186, 119574, + 11908, 120254, 9360, 9083, 13180, 41764, 11601, 12837, 8829, 7711, 64423, + 12115, 67636, 12377, 41281, 8809, 41647, 365, 12056, 10857, 917831, + 41716, 65395, 41228, 119865, 5516, 2845, 7717, 4588, 41717, 63830, 544, + 12045, 2433, 917897, 5515, 3352, 65373, 64377, 65437, 793, 65194, 194740, + 305, 567, 119002, 842, 66627, 8208, 917556, 41695, 1647, 118877, 5608, + 63824, 65407, 818, 5337, 119143, 13278, 65597, 9638, 8061, 8735, 12483, + 120468, 13003, 6667, 10973, 66359, 1372, 118858, 7556, 4969, 1254, 11264, + 989, 64257, 118862, 65228, 6060, 65266, 4326, 2840, 64601, 13068, 194985, + 65242, 3245, 5768, 65601, 949, 119351, 194893, 6148, 8605, 2651, 119634, + 64570, 917912, 119563, 194888, 65106, 120418, 41451, 63871, 41796, 1269, + 6530, 63868, 41777, 6414, 5144, 3226, 655, 752, 4431, 4331, 7452, 3285, + 41834, 5279, 12908, 10336, 8312, 41754, 12091, 671, 250, 7434, 618, 668, + 610, 6428, 7431, 1152, 5256, 640, 41229, 7448, 1067, 255, 3905, 65196, + 9493, 65588, 41014, 10795, 194791, 194741, 120421, 917772, 10653, 41272, + 195001, 13287, 917805, 6560, 9019, 118943, 195052, 65409, 987, 64410, + 5527, 2768, 10684, 3365, 5135, 118924, 12796, 11953, 120412, 65732, 5139, + 346, 11334, 6305, 12609, 4675, 5168, 5530, 5210, 917774, 4627, 8253, + 5208, 1136, 65433, 120587, 5218, 7976, 118864, 11963, 3244, 5529, 0, + 194742, 917794, 5432, 64258, 4041, 8784, 2357, 11521, 5528, 229, 42140, + 65876, 12350, 65848, 119881, 12241, 119197, 4000, 7429, 7428, 665, 7424, + 3206, 7770, 7884, 64853, 0, 65838, 194779, 211, 2509, 7790, 10470, 7861, + 3220, 9156, 64050, 450, 8951, 5214, 10432, 8118, 5450, 10768, 1233, 4661, + 5852, 8984, 66338, 41802, 1708, 1839, 40985, 2623, 10927, 1701, 195064, + 2388, 4698, 41761, 1066, 8361, 4701, 41758, 5444, 2617, 64889, 8267, + 66645, 65610, 194642, 7516, 118958, 2625, 8801, 3053, 4340, 120139, 3631, + 10955, 7850, 120292, 8416, 119977, 4008, 65507, 12644, 12660, 8232, + 12156, 194807, 194624, 41069, 41719, 65812, 12099, 4310, 4336, 6252, 713, + 41068, 7990, 3990, 119203, 65113, 64638, 5017, 13145, 4489, 118959, + 42138, 1030, 5358, 64577, 9513, 10196, 9357, 194764, 1773, 10250, 10258, + 2712, 1635, 7745, 1410, 12077, 64650, 94, 1880, 120149, 194731, 8908, + 559, 118879, 12862, 194984, 10752, 4892, 10876, 64537, 6542, 8732, 8472, + 5777, 1757, 759, 4696, 2586, 65248, 8945, 8466, 3641, 5419, 41803, 42062, + 67596, 118806, 120344, 3668, 65754, 8610, 12226, 7592, 856, 2340, 936, + 13289, 64478, 66631, 1459, 65747, 10499, 2962, 19953, 2321, 1504, 10465, + 41312, 8921, 120548, 7529, 65154, 64525, 41901, 63814, 4113, 2949, 2372, + 336, 194774, 2958, 12152, 5348, 682, 2395, 65252, 13291, 7513, 10593, + 1703, 4013, 64764, 8033, 120064, 65152, 9810, 6534, 4150, 12970, 8318, + 41790, 10109, 41893, 2360, 41794, 12858, 120493, 3999, 3777, 65629, 1965, + 9796, 2411, 11336, 799, 195097, 10276, 10308, 10372, 41714, 8501, 63833, + 2317, 10260, 41317, 65767, 5417, 917969, 10384, 120073, 9353, 917546, + 7753, 2351, 6655, 64489, 6569, 13119, 119812, 41287, 119236, 230, 11293, + 12009, 119813, 4855, 4165, 8746, 5441, 9654, 10288, 10320, 65665, 855, + 120396, 6109, 4784, 12337, 13270, 7786, 10098, 41147, 194570, 63769, 680, + 6274, 10312, 1181, 19915, 3174, 13127, 120011, 64822, 41887, 41444, 4862, + 9735, 6537, 119237, 66650, 3914, 41037, 10828, 9007, 12961, 41039, + 118861, 9033, 6231, 289, 65302, 4694, 11420, 4690, 120654, 42760, 194898, + 4693, 63816, 40987, 4667, 4688, 120591, 8828, 194637, 65763, 1246, 3110, + 19940, 12197, 11021, 4749, 917895, 43035, 921, 218, 64868, 1520, 242, + 4786, 1566, 8217, 8932, 64653, 7834, 10088, 6548, 118908, 64681, 5313, + 951, 8888, 64534, 4816, 7604, 43032, 4009, 194694, 194717, 65440, 41549, + 119069, 12340, 119138, 119887, 4689, 119888, 4048, 120158, 119209, 6507, + 1646, 41755, 119891, 4040, 194734, 65118, 68134, 2579, 119905, 3177, + 8207, 9099, 4107, 120130, 119894, 662, 120706, 9244, 66623, 13059, 10084, + 120339, 65669, 65836, 10179, 41929, 3399, 9851, 40991, 8739, 9059, 0, + 7687, 64637, 8854, 40993, 52, 13241, 6475, 917901, 120444, 1777, 9151, + 1137, 118914, 749, 65169, 120584, 5385, 3978, 65842, 120283, 11592, 5989, + 65827, 10170, 65013, 6544, 41685, 64702, 119365, 8425, 41684, 917780, + 519, 10369, 11740, 1585, 194987, 9888, 422, 1500, 10305, 986, 41170, + 3666, 5781, 5599, 3098, 2494, 120202, 4861, 0, 64334, 63986, 6558, 64818, + 41221, 42165, 8961, 252, 10243, 10245, 63936, 917505, 120398, 194707, + 63751, 9478, 2508, 9060, 119587, 202, 10761, 119114, 1242, 12899, 120447, + 11734, 63940, 11730, 917937, 9593, 10543, 2403, 12979, 64609, 0, 9787, + 2504, 9784, 41024, 7764, 42076, 9514, 64132, 5859, 119259, 2858, 8298, + 12333, 65040, 65478, 9691, 4971, 12992, 2753, 1936, 917877, 8456, 2751, + 12662, 2763, 8953, 42104, 10731, 7774, 4780, 9792, 63990, 194753, 194871, + 194693, 118927, 2856, 10019, 47, 10482, 2823, 4365, 120629, 917551, 3647, + 7899, 2602, 8417, 65903, 917558, 41135, 118824, 4033, 118854, 194761, + 172, 194720, 212, 41137, 1889, 12320, 6545, 64623, 917859, 7597, 8915, + 2759, 945, 3732, 120230, 917567, 5344, 194851, 1291, 11485, 9062, 119252, + 9531, 13155, 8505, 64479, 12062, 119018, 64703, 65487, 42065, 10900, + 10370, 1263, 3720, 12048, 63935, 64292, 41524, 64692, 12652, 6099, 41534, + 64133, 63933, 64426, 299, 65540, 118859, 63951, 3524, 12933, 8831, 65752, + 8674, 3075, 119890, 8245, 917867, 12624, 120559, 1673, 4811, 63928, 5845, + 9338, 3046, 65414, 2581, 4001, 41811, 9820, 64098, 12187, 5551, 68114, + 5984, 63791, 120687, 4393, 10566, 68182, 8680, 65555, 118851, 2588, 5422, + 65900, 43028, 3491, 2471, 917626, 2883, 2749, 63921, 195054, 7492, 7740, + 119355, 119134, 675, 120551, 63924, 194568, 7502, 6219, 63926, 65726, + 41232, 9329, 63925, 7610, 219, 63945, 41330, 692, 65200, 120775, 9240, + 3181, 9688, 119816, 1222, 65775, 8262, 11785, 64530, 0, 64610, 3092, + 12092, 9615, 7453, 120128, 8013, 119857, 120456, 195019, 8895, 5253, + 65774, 5458, 917816, 922, 65923, 119318, 11338, 194930, 3218, 12618, + 63997, 120469, 11664, 8962, 8569, 9641, 11932, 12202, 3214, 120461, 9604, + 12053, 3207, 120465, 63826, 1901, 63939, 120141, 63825, 2844, 3205, + 41974, 41286, 12139, 65666, 64708, 119580, 3358, 2606, 119364, 3104, + 2608, 11496, 1173, 10901, 5308, 120079, 290, 917988, 11779, 2862, 2792, + 64498, 66371, 378, 2610, 66591, 65079, 6552, 65372, 66707, 37, 64195, + 120154, 1814, 64860, 3209, 118843, 120804, 10638, 9768, 64648, 917984, + 66372, 7606, 2591, 2837, 4341, 41403, 64105, 42159, 5233, 65270, 64792, + 120794, 3570, 9112, 119948, 863, 9490, 63761, 1685, 595, 12715, 118871, + 1292, 6222, 65705, 3654, 66638, 9637, 120268, 2535, 6541, 119181, 10656, + 120246, 3243, 9014, 5606, 63762, 538, 11006, 5602, 7807, 8073, 6547, + 10629, 8203, 63994, 3056, 8458, 41778, 8495, 8762, 10508, 917552, 779, + 9818, 64367, 2465, 3463, 8193, 65721, 9730, 8695, 4738, 11322, 5811, + 4346, 64904, 194735, 504, 64321, 10899, 8982, 119954, 0, 0, 782, 4867, + 10883, 1262, 64771, 732, 3737, 194954, 1548, 13151, 120589, 1832, 5604, + 5611, 41141, 7460, 4376, 64612, 11991, 3745, 41738, 10011, 1502, 65712, + 194670, 3869, 11937, 5702, 3655, 1783, 119899, 5728, 120564, 13285, + 42174, 11918, 9603, 5724, 5254, 5727, 7724, 119573, 119901, 764, 5129, + 120655, 120460, 10597, 7579, 5614, 5893, 6223, 11720, 42073, 11423, + 119863, 64409, 119862, 4792, 917770, 1964, 6559, 11726, 12146, 65378, + 10687, 43019, 119629, 894, 300, 65744, 10037, 12223, 118936, 1478, 9783, + 2562, 2607, 64740, 64830, 0, 11652, 917627, 11777, 41780, 6132, 64946, + 5096, 5095, 2863, 3424, 0, 10454, 68146, 5094, 10093, 4369, 13156, 12306, + 5401, 5093, 119909, 12004, 65251, 5092, 526, 11327, 41295, 5091, 176, + 41691, 8985, 4104, 119911, 6285, 1215, 11985, 5744, 12272, 9832, 65590, + 3713, 13218, 41191, 119343, 8980, 118988, 12293, 8844, 7433, 11794, + 42036, 4278, 1737, 8987, 12917, 195068, 9074, 4348, 9335, 7760, 118991, + 6553, 10339, 5255, 1786, 661, 120126, 5475, 917876, 41854, 68102, 194754, + 12419, 1160, 1267, 68143, 41217, 65858, 10018, 360, 67586, 3621, 64635, + 5863, 3137, 11345, 6562, 12928, 41216, 1228, 2616, 119190, 64401, 65234, + 10745, 1714, 3135, 120637, 120143, 0, 3142, 119186, 119995, 10819, 64163, + 6577, 65772, 64, 1470, 194566, 10291, 6227, 2826, 41749, 66433, 119864, + 6163, 9708, 13250, 0, 42011, 41224, 8603, 12206, 5839, 1702, 1240, 41461, + 6286, 119882, 5834, 66451, 3858, 119089, 1765, 12086, 42001, 1600, 13228, + 64729, 0, 8401, 120520, 11310, 9282, 8882, 118929, 10479, 2570, 2852, + 5367, 4601, 120818, 64075, 1234, 6540, 13115, 66310, 12667, 194686, 5002, + 10147, 12935, 917601, 194965, 118829, 194672, 8163, 6551, 12727, 120744, + 120533, 41289, 0, 13129, 2864, 8977, 602, 10435, 9395, 41675, 119554, + 2765, 64540, 41279, 120414, 65924, 0, 119922, 66662, 119220, 10887, + 65206, 118963, 64920, 66593, 63914, 12150, 263, 120012, 41288, 917982, + 9633, 10886, 119042, 7831, 12067, 10381, 917978, 11484, 8076, 43048, + 8290, 8291, 43051, 65833, 11616, 2596, 10852, 10285, 13113, 120711, + 42019, 2393, 8766, 9087, 750, 65232, 41574, 10163, 11015, 63913, 10441, + 5954, 10225, 4314, 65856, 198, 917956, 730, 41441, 7819, 120199, 917555, + 13165, 1720, 63905, 8619, 678, 6529, 68122, 41654, 3751, 917769, 119923, + 4262, 1798, 709, 917841, 1354, 1876, 13152, 6557, 3892, 8137, 10449, + 120035, 120428, 41470, 245, 41045, 11456, 41233, 64801, 120315, 497, + 6136, 5953, 65677, 7796, 41235, 65434, 42045, 9804, 8449, 432, 1281, + 64355, 65393, 64339, 10677, 604, 7511, 9120, 1859, 65541, 10460, 3425, + 917870, 65782, 2836, 8797, 8490, 9052, 64888, 120206, 2356, 95, 64786, + 1738, 120415, 194654, 2832, 64640, 9670, 6096, 917871, 64918, 65151, + 10063, 2822, 12199, 4436, 194852, 2566, 11971, 12090, 13064, 1065, 1331, + 119097, 0, 2576, 12708, 41142, 5090, 5089, 120263, 9505, 67595, 514, + 41692, 319, 2921, 11659, 9477, 5772, 12968, 5087, 118822, 41310, 96, + 2580, 0, 10522, 41223, 5085, 1463, 41342, 11346, 5293, 10550, 64389, + 3733, 3772, 13090, 12054, 4748, 12482, 64300, 12575, 13091, 63982, + 194794, 6677, 7601, 119078, 41413, 64419, 118953, 195086, 195100, 66648, + 118945, 64597, 10939, 6106, 65757, 1270, 1132, 120746, 4534, 41270, + 66655, 9224, 65574, 66331, 64761, 917881, 3671, 8510, 120695, 65770, + 41275, 120823, 917935, 10807, 7963, 42012, 119877, 568, 65227, 6187, + 13109, 3854, 41479, 13141, 9715, 66696, 8258, 13253, 4185, 41334, 65148, + 8871, 42, 8509, 0, 4102, 120258, 7458, 118995, 65863, 2353, 6308, 41604, + 7457, 2611, 7456, 41021, 120563, 194631, 66336, 8045, 11550, 12946, 4484, + 8747, 118976, 11789, 41065, 5557, 11990, 9737, 13216, 3747, 9467, 5291, + 8878, 1691, 41226, 7451, 7435, 10146, 10905, 9086, 64566, 697, 194675, + 628, 7454, 12594, 65261, 10468, 4546, 7731, 65256, 12010, 0, 120598, + 3805, 64304, 64293, 120284, 9844, 68111, 6307, 19949, 0, 7544, 12166, + 64697, 10516, 120074, 10152, 12648, 10354, 0, 7602, 5785, 41309, 9764, + 41316, 65877, 194640, 13230, 41299, 5559, 119835, 8704, 2397, 5556, 9877, + 66368, 13122, 9011, 191, 9630, 41837, 42040, 5506, 119842, 120697, 64850, + 41072, 12598, 8845, 41577, 194790, 10002, 8889, 6533, 11620, 41570, + 41838, 683, 396, 41580, 12526, 917610, 12901, 12351, 65115, 343, 7552, + 120553, 41360, 9898, 10481, 4559, 0, 1956, 118857, 917836, 64048, 1724, + 1210, 119323, 9412, 3739, 6263, 1886, 194869, 3964, 6592, 38, 8533, 9234, + 10947, 65073, 13063, 194752, 1778, 3956, 65091, 42070, 6563, 119324, + 8743, 8369, 11739, 10941, 12467, 65722, 5547, 66618, 120432, 120513, + 8175, 8843, 284, 2429, 934, 5696, 917996, 173, 65560, 8652, 12699, 11650, + 1750, 120709, 4394, 65056, 1807, 6613, 12606, 64528, 5889, 63783, 917949, + 64714, 41848, 11516, 12162, 12120, 12478, 1721, 7767, 7891, 65864, 10563, + 2583, 4512, 63973, 2462, 7693, 1837, 10434, 3855, 8107, 41337, 63972, + 4952, 65413, 64405, 5504, 41340, 3975, 65715, 65716, 65420, 12672, 3798, + 2703, 194709, 64347, 9349, 9774, 41847, 1127, 455, 41095, 3962, 10100, + 3483, 41101, 3954, 6457, 4513, 9104, 3503, 7688, 41298, 1468, 65386, + 1864, 41851, 63970, 41446, 2540, 7736, 41080, 41849, 917619, 4320, 3224, + 12909, 9705, 41565, 8604, 118903, 1510, 11306, 6149, 3887, 11393, 1411, + 2824, 194708, 10106, 8770, 1403, 120811, 1347, 9631, 8671, 65737, 4283, + 64074, 119936, 8640, 13124, 258, 1654, 41408, 8858, 65738, 42139, 3741, + 42761, 4042, 4581, 2873, 11617, 11522, 120114, 8549, 10861, 194784, + 41673, 64829, 1733, 4392, 2568, 10786, 63983, 67629, 376, 41486, 9221, + 64871, 119907, 8823, 41222, 12857, 6217, 7965, 4896, 64911, 10154, + 119108, 41350, 8301, 118823, 7446, 1684, 64501, 10974, 458, 41199, + 917562, 917576, 194798, 11916, 340, 119000, 12298, 10864, 119918, 12288, + 120287, 4388, 1493, 10521, 7553, 4097, 194971, 13080, 11656, 65808, 6610, + 6030, 8059, 3210, 13131, 119073, 194827, 13301, 8794, 41278, 41629, + 12154, 119131, 9461, 64658, 1186, 41571, 6625, 617, 9464, 12691, 3675, + 5207, 63955, 5213, 118896, 833, 41348, 41568, 917775, 3253, 63954, 41088, + 8630, 6062, 41440, 5596, 5545, 119313, 933, 1341, 9842, 5217, 194886, + 8942, 40962, 194730, 68126, 9905, 2635, 64504, 65130, 12620, 7493, + 917577, 7835, 41434, 9002, 19918, 194770, 64558, 194974, 9716, 19954, + 5651, 5990, 900, 5784, 194775, 9317, 119057, 3612, 4011, 64376, 41953, + 5389, 7864, 917548, 65336, 2839, 5600, 3903, 65609, 10447, 3749, 1207, + 7569, 194980, 3501, 194685, 64705, 4403, 19962, 1124, 5597, 195009, + 119921, 9321, 4429, 65810, 120515, 119072, 1719, 7598, 546, 9671, 1125, + 4399, 9542, 472, 7716, 8452, 5488, 41946, 42025, 194903, 5491, 3602, + 8328, 41182, 2604, 41949, 5490, 41183, 5489, 8522, 10287, 684, 6300, + 194777, 2854, 119586, 4390, 454, 7823, 65750, 9875, 7593, 65338, 119310, + 120625, 64487, 8478, 9881, 2394, 2575, 3415, 3746, 11016, 8648, 66515, + 65421, 43047, 119092, 11989, 65142, 418, 65025, 66378, 10295, 8249, + 10391, 41752, 4565, 6640, 41449, 2598, 513, 120763, 6586, 8656, 65826, + 1024, 11621, 7961, 120809, 8941, 917563, 4554, 11681, 9023, 11682, + 120788, 10176, 10964, 119315, 11437, 9509, 0, 1036, 12850, 917787, 1723, + 120577, 9049, 41185, 41579, 2444, 11680, 10705, 11686, 118792, 65224, + 63804, 740, 63963, 120113, 118874, 120681, 5300, 10407, 9459, 194739, + 1875, 66466, 7856, 8121, 10438, 5524, 41698, 2860, 12157, 5238, 120797, + 5690, 5743, 10424, 12065, 65805, 7578, 65859, 195051, 8875, 8694, 9506, + 13254, 5575, 12847, 2413, 68099, 119340, 962, 12176, 1122, 317, 9040, + 119116, 1582, 119251, 1920, 41477, 10173, 827, 10801, 195096, 118798, + 120401, 5223, 496, 10439, 4313, 5226, 12602, 7860, 120627, 906, 7758, + 2842, 6405, 5224, 5487, 798, 5692, 12801, 7791, 1153, 5695, 12100, 64627, + 8054, 9174, 120131, 5691, 287, 866, 233, 4642, 66574, 11556, 7514, 66436, + 65140, 42089, 8830, 9008, 120417, 10524, 41175, 42079, 7587, 65709, 5296, + 120505, 10688, 10663, 917814, 3302, 66478, 6437, 6516, 6515, 6514, 6513, + 6512, 41798, 3920, 8690, 119590, 41201, 12122, 4580, 6568, 6116, 1785, + 41965, 120635, 3021, 42004, 5138, 120129, 194587, 41998, 41867, 4540, + 41179, 194804, 6200, 11462, 5134, 42021, 322, 4643, 5132, 42010, 194988, + 43008, 5143, 64875, 8790, 917807, 65594, 64604, 6626, 8869, 66510, 64400, + 42060, 19908, 9878, 194814, 41133, 10270, 10286, 10318, 10382, 65671, + 4110, 120507, 11286, 10929, 64277, 3234, 66703, 13058, 8617, 41982, 6025, + 120736, 12805, 8767, 194580, 194690, 9597, 41283, 5201, 120293, 6215, + 12714, 6214, 13101, 65282, 120490, 65268, 120504, 64524, 120215, 187, 0, + 10059, 10511, 4963, 9767, 789, 1749, 7441, 64574, 9901, 320, 41948, + 41833, 194831, 3049, 41139, 6471, 9449, 10081, 10528, 42121, 118894, + 120562, 4960, 5549, 119359, 65882, 8485, 4671, 1189, 905, 480, 10985, + 10240, 10610, 5414, 3064, 1745, 4286, 5421, 5427, 9554, 119077, 66357, + 65465, 6653, 8806, 42047, 9442, 6213, 9443, 9436, 7867, 11613, 6236, + 42052, 195070, 2406, 119858, 11430, 4566, 348, 5474, 3801, 3103, 10406, + 5246, 5236, 64395, 195059, 5200, 64305, 41739, 41733, 64518, 10931, + 13181, 41402, 395, 5391, 5198, 8786, 9428, 41259, 5196, 120037, 2691, + 42009, 5205, 41244, 5562, 917578, 118973, 41262, 66364, 64421, 119615, + 41251, 9126, 435, 3979, 12014, 12893, 8093, 9079, 3203, 192, 119912, + 3385, 41266, 64430, 5383, 10294, 10326, 65741, 5738, 9574, 2666, 119861, + 5361, 831, 419, 8256, 10716, 7872, 64583, 66688, 1260, 3149, 5359, 7766, + 6432, 7914, 5357, 916, 769, 2624, 5364, 64739, 6433, 5563, 547, 1943, + 6439, 5560, 4994, 487, 119553, 4497, 3754, 120082, 120615, 9039, 10619, + 41776, 194797, 8716, 41622, 40983, 64072, 41516, 0, 9319, 195024, 41376, + 11610, 3232, 12185, 119928, 119331, 65905, 119347, 41889, 64071, 8634, + 1161, 41895, 118804, 9701, 8622, 41385, 120403, 65612, 120588, 669, 5679, + 41362, 43011, 64210, 11921, 42087, 5678, 120750, 66489, 41364, 460, + 64636, 41352, 41361, 194824, 41366, 0, 3356, 6178, 917, 7799, 118812, + 64068, 7782, 9044, 4974, 677, 119916, 7577, 64189, 41507, 1216, 12504, + 11952, 3349, 194683, 12296, 8927, 4739, 3738, 5802, 120474, 5683, 10368, + 120661, 491, 1549, 119621, 194659, 0, 5682, 6206, 8670, 9891, 5680, + 64297, 10001, 7586, 65580, 1449, 10241, 3768, 65255, 3776, 9095, 7741, + 12684, 41885, 1046, 120547, 5567, 2717, 4620, 5171, 5564, 41967, 41908, + 41786, 5565, 12819, 12578, 64743, 65708, 5169, 5566, 3465, 64694, 3175, + 11904, 1537, 119155, 5176, 5942, 8468, 4871, 10361, 10425, 65697, 65698, + 41991, 1128, 65920, 10548, 9711, 10647, 9408, 9409, 9410, 457, 3662, + 9413, 1934, 9415, 9416, 8802, 9418, 8909, 9420, 9421, 5897, 9423, 5165, + 5126, 9889, 8043, 8950, 65694, 8955, 3374, 9400, 9401, 9402, 8939, 9404, + 3507, 9406, 9407, 119241, 19925, 9499, 10035, 183, 65078, 2631, 119308, + 10636, 41130, 64958, 3996, 120650, 64675, 1667, 41584, 65486, 41582, + 6580, 4332, 64825, 10741, 10726, 12912, 11281, 5899, 8101, 3610, 12085, + 41748, 574, 955, 120092, 5340, 5350, 41058, 5446, 63799, 10875, 64796, + 5442, 65692, 12437, 9782, 5451, 12896, 3616, 64857, 917959, 3874, 7708, + 64370, 5505, 65867, 10345, 10409, 65603, 11909, 65687, 43015, 41038, + 120719, 120561, 4447, 8536, 64701, 65143, 66661, 120194, 724, 42048, + 1455, 205, 917593, 10351, 64618, 8571, 4175, 6588, 119059, 120380, 939, + 41355, 4743, 119154, 5503, 8021, 64622, 119150, 9819, 41357, 8011, 6088, + 5507, 12044, 190, 120282, 10026, 4356, 8188, 1191, 13106, 4417, 10329, + 5476, 8991, 195008, 7827, 120361, 5829, 8550, 67627, 5592, 2919, 64925, + 2675, 5595, 917967, 7918, 4367, 194626, 65554, 5478, 1728, 5594, 120710, + 178, 12972, 5590, 10727, 13067, 118909, 65254, 917941, 9731, 120600, + 64633, 917987, 12113, 13065, 118863, 9252, 12278, 4652, 119041, 12349, + 65907, 194704, 120688, 12887, 10551, 10710, 194833, 195017, 64663, + 120570, 41804, 5199, 9497, 1120, 11429, 8333, 1444, 9486, 7554, 13142, + 4538, 65096, 1442, 6177, 5894, 917833, 11910, 13224, 8278, 5591, 4034, + 9452, 65389, 3334, 64003, 41747, 10708, 194571, 8677, 118828, 1651, 9350, + 8861, 120040, 8836, 1142, 12747, 4396, 10928, 66705, 8922, 8856, 66611, + 4002, 119188, 10442, 10676, 3344, 11012, 64963, 10813, 2592, 12853, + 120242, 66642, 3438, 6536, 7871, 120239, 65516, 12321, 68141, 118890, + 120389, 10007, 11784, 9588, 10126, 4700, 11308, 41994, 65801, 8661, + 41721, 66572, 12240, 119876, 4973, 5573, 12588, 9629, 40981, 119176, + 118981, 5006, 64328, 42002, 64754, 41766, 8825, 13016, 195062, 0, 10346, + 6107, 42093, 9243, 2464, 194677, 6108, 3372, 335, 6247, 64689, 438, 4510, + 5765, 8721, 119878, 4036, 6092, 11654, 65914, 8876, 10303, 8096, 10284, + 3354, 10268, 119830, 9289, 8689, 10316, 3876, 10335, 9725, 42044, 11783, + 917893, 119581, 8050, 120030, 195025, 11603, 194820, 120053, 6589, 843, + 120419, 119260, 120770, 195053, 10117, 66560, 41902, 12829, 6312, 215, + 1963, 13225, 13192, 1953, 9579, 7550, 1256, 3910, 13015, 6242, 41329, + 9662, 41257, 41900, 3366, 10700, 8805, 1742, 5542, 9333, 8202, 120459, + 120232, 41611, 65895, 120159, 120385, 499, 118846, 8593, 119627, 917974, + 41169, 1712, 5932, 8097, 41642, 11519, 119562, 11967, 1775, 65296, 41243, + 118957, 5662, 416, 9458, 64687, 6470, 195081, 66675, 10984, 64386, 64672, + 65274, 12880, 195083, 41172, 41254, 64758, 120669, 41062, 194825, 9006, + 65446, 565, 41760, 5794, 201, 2662, 9419, 11332, 8254, 41726, 10975, + 120173, 1021, 65131, 1022, 4108, 3880, 8023, 1200, 12243, 194991, 5282, + 7507, 41881, 11545, 5891, 64406, 3343, 1636, 67587, 1885, 65024, 3896, + 195056, 9674, 2947, 99, 98, 97, 120571, 64414, 4049, 8221, 64085, 3381, + 194978, 7892, 120705, 10777, 194687, 5867, 3913, 66376, 66722, 64315, + 8039, 1265, 4316, 6309, 118815, 12969, 12596, 66595, 11791, 12541, 5593, + 67585, 5998, 9163, 12300, 6061, 64854, 119, 118, 117, 116, 8930, 122, + 121, 120, 111, 110, 109, 108, 115, 114, 113, 112, 103, 102, 101, 100, + 107, 106, 105, 104, 6436, 194788, 534, 41212, 119599, 1536, 12114, + 120381, 64287, 64936, 64324, 6020, 12716, 10561, 10075, 475, 118888, + 13266, 9144, 64590, 917580, 118887, 65749, 10645, 1212, 5079, 119619, + 8134, 8483, 2913, 6624, 4908, 1866, 1639, 119189, 194762, 8923, 1645, + 12059, 64505, 917977, 194664, 41503, 4817, 5935, 1250, 194727, 8174, + 9600, 9856, 9859, 7916, 9861, 5343, 5258, 1882, 1892, 11304, 10882, 405, + 11454, 4659, 12343, 657, 12610, 4970, 4461, 1134, 1838, 1454, 41242, + 6477, 4468, 5987, 65803, 9762, 4456, 5206, 10720, 194625, 10480, 41718, + 5818, 194773, 8264, 10229, 260, 645, 119827, 7609, 40973, 4821, 4466, + 120500, 5824, 984, 119027, 8791, 5851, 5705, 7729, 41166, 10591, 41797, + 119983, 65438, 66580, 119984, 42101, 41404, 1165, 7879, 4451, 11401, + 194849, 11284, 119987, 66566, 41909, 43014, 2791, 9363, 9552, 3375, 8641, + 5900, 7539, 7889, 2722, 194854, 13173, 2381, 11602, 10994, 10529, 10773, + 11574, 8644, 11581, 12425, 10661, 10856, 9614, 194917, 41478, 11571, + 10064, 8308, 10748, 66695, 11005, 4868, 119162, 1952, 41406, 8455, 10082, + 11575, 8467, 12577, 12721, 5182, 12183, 6145, 41759, 64929, 4465, 42120, + 12135, 5732, 4464, 7728, 3922, 977, 4458, 120043, 120545, 64770, 119556, + 3353, 344, 917963, 41626, 1395, 41939, 65832, 5776, 8558, 786, 65153, + 120191, 64340, 119352, 10202, 120084, 41027, 7612, 10132, 64413, 120087, + 12840, 119119, 119913, 119314, 119139, 63862, 41896, 8657, 194996, 8594, + 10204, 195049, 120477, 120069, 65819, 1399, 41375, 120056, 917938, 8852, + 64492, 241, 68135, 4907, 194757, 9738, 194975, 9727, 7851, 119196, 10951, + 4439, 11588, 119199, 65008, 9085, 65853, 41911, 9327, 6160, 917594, 8650, + 64865, 8088, 64933, 41910, 118872, 65217, 3965, 120050, 194713, 0, 13300, + 65902, 66654, 65491, 65145, 9041, 65847, 65017, 7504, 4420, 9900, 6410, + 7501, 11278, 65825, 9577, 120047, 13217, 8748, 65415, 0, 9867, 9066, + 12924, 11993, 917829, 2626, 7762, 10902, 7510, 119577, 41526, 64285, + 10472, 2995, 120704, 12907, 41184, 2371, 194994, 10038, 259, 1009, + 118838, 2402, 2333, 6440, 194768, 12050, 65125, 0, 12417, 65380, 9103, + 10181, 3148, 65873, 6434, 7779, 10198, 194952, 9479, 6029, 65325, 65157, + 9689, 41261, 119175, 8993, 8613, 0, 41167, 3368, 606, 41492, 7697, 10228, + 41596, 1890, 194769, 6027, 8370, 4322, 41661, 7991, 66512, 10578, 119168, + 41465, 41054, 2735, 41664, 120330, 63778, 65273, 1287, 65408, 6635, + 66659, 6164, 194563, 41273, 917951, 65027, 41271, 9576, 65043, 3347, + 4160, 5154, 917541, 3794, 66564, 9175, 11925, 7709, 9088, 3743, 65099, + 1396, 4572, 7546, 3847, 66327, 65081, 4985, 1615, 672, 809, 12980, 63806, + 0, 65218, 5799, 41615, 65072, 1577, 194934, 65875, 5928, 4525, 10658, + 65911, 1266, 10180, 120702, 6129, 12622, 9347, 917986, 6532, 64424, + 41048, 7789, 773, 19933, 1539, 283, 64416, 66374, 532, 917800, 120049, + 41115, 3051, 5862, 3370, 120789, 43033, 5439, 3250, 8153, 0, 66649, 9510, + 120279, 64647, 9541, 118916, 41066, 64706, 194612, 43038, 3505, 8707, + 9466, 11479, 8537, 120802, 3626, 3471, 194860, 915, 194689, 6686, 119584, + 120238, 5011, 42754, 120723, 41906, 65569, 119128, 119552, 64365, 119886, + 3225, 68161, 4433, 5186, 194957, 41933, 1443, 4381, 9829, 65124, 10926, + 194746, 195076, 64879, 10562, 194751, 65476, 64579, 66456, 10021, 5160, + 1387, 65495, 6103, 118923, 41480, 12786, 195000, 217, 119898, 11714, + 12466, 10443, 10789, 41158, 41460, 1630, 120782, 41483, 65818, 12565, + 41700, 10077, 12890, 5931, 194732, 9283, 7700, 41252, 6042, 65499, + 119637, 41249, 512, 2990, 917786, 120240, 6413, 917985, 632, 12940, + 194875, 41296, 9545, 41291, 5957, 120353, 8926, 3511, 41282, 5923, 10400, + 10174, 12073, 760, 5386, 4274, 5786, 10633, 120531, 5056, 119860, 417, + 41474, 120773, 11022, 9812, 5934, 4460, 66583, 119231, 64877, 65410, + 64481, 194692, 194705, 10937, 194748, 120218, 10509, 65829, 917540, 2953, + 5819, 1801, 12835, 194942, 120484, 194743, 65910, 41985, 8867, 702, + 120410, 1237, 10274, 4552, 65447, 119966, 194961, 1375, 12106, 120815, + 10264, 1755, 9065, 9228, 10376, 1163, 2951, 7840, 64336, 13282, 10252, + 120033, 3384, 120703, 10167, 830, 194656, 65425, 10769, 8451, 41368, + 12520, 9753, 120147, 8944, 194882, 120248, 10473, 2908, 119614, 19965, + 43025, 10299, 65041, 12097, 64733, 12952, 4441, 10503, 917839, 41430, + 9330, 194859, 6614, 411, 10315, 9676, 4996, 120213, 13281, 10009, 7865, + 2730, 10388, 9677, 5428, 118993, 3364, 7565, 12828, 41711, 118816, 65463, + 9535, 216, 10332, 1401, 119895, 622, 65095, 885, 64772, 1602, 4467, + 41405, 852, 119635, 12108, 41328, 484, 65187, 41051, 12071, 9609, 9806, + 41008, 3338, 120796, 572, 10411, 2736, 10255, 10263, 10279, 2794, 8807, + 64491, 10330, 4315, 5222, 5381, 119058, 917995, 5193, 5125, 5456, 5509, + 41177, 917832, 9534, 195042, 64431, 1603, 3430, 118982, 10298, 120407, + 917885, 981, 41176, 4330, 994, 65841, 1824, 10908, 917879, 41681, 41683, + 5921, 65600, 2597, 3957, 5922, 64547, 65784, 674, 119839, 194945, 2946, + 5354, 5251, 4406, 5307, 3759, 10131, 8364, 5123, 1433, 5281, 5469, 5121, + 5924, 5920, 65758, 5130, 64606, 66481, 119624, 8418, 7576, 1221, 2733, 0, + 742, 5216, 2893, 10772, 65276, 5937, 3468, 2553, 9230, 5939, 3997, + 195091, 8363, 120677, 2993, 7772, 3916, 10289, 64613, 1141, 41706, 8159, + 718, 7572, 973, 9666, 120718, 3235, 2415, 5938, 119620, 8018, 12448, + 120556, 9592, 10337, 194918, 917622, 11729, 120727, 8719, 1202, 195080, + 64651, 12983, 118970, 12165, 119095, 63747, 9067, 3260, 8077, 65388, + 68179, 8419, 63773, 65419, 63774, 194986, 63775, 10725, 10433, 64496, + 194861, 1431, 41843, 66565, 10821, 4359, 12804, 12192, 8229, 1235, 3307, + 11472, 120617, 3146, 4544, 9009, 8551, 118820, 1740, 194749, 7575, 985, + 2724, 13076, 65233, 12068, 119949, 515, 10141, 119944, 9539, 8785, 4476, + 119146, 10959, 12655, 8907, 13226, 4589, 4521, 64205, 9141, 64645, 10665, + 2741, 41572, 6197, 1370, 10101, 41573, 64294, 3931, 194924, 120585, 6184, + 8606, 3303, 11968, 11786, 9473, 13103, 63771, 8879, 11593, 66508, 4478, + 917588, 41735, 65837, 717, 10754, 4477, 120376, 814, 42066, 119962, + 63767, 1780, 41031, 119958, 41387, 819, 10611, 9694, 11955, 65919, + 119953, 41111, 9462, 119071, 7788, 4847, 65542, 6578, 8338, 7523, 120666, + 1581, 6535, 7525, 3346, 430, 64698, 66699, 575, 268, 194940, 4945, 66463, + 4950, 12918, 9456, 8336, 5936, 43017, 5964, 8337, 13081, 308, 917964, + 7522, 64309, 41746, 4949, 118946, 443, 11658, 4944, 5467, 65885, 5926, + 1862, 6044, 65392, 8820, 4946, 119247, 9038, 7887, 65667, 7830, 11651, + 13093, 2698, 41144, 65742, 12072, 41753, 11590, 41304, 824, 120095, 8595, + 65225, 42141, 11415, 4673, 41354, 4678, 13283, 12697, 65059, 12381, 3488, + 5933, 5481, 3490, 1199, 65014, 8356, 12297, 119153, 1955, 12375, 3102, + 10474, 4672, 118849, 119821, 5531, 119823, 119826, 66332, 8835, 4674, + 119006, 5831, 194932, 64896, 12379, 8025, 119947, 64542, 1855, 11957, + 5472, 64425, 7852, 119867, 64951, 120467, 11445, 2745, 5470, 65171, 9124, + 119110, 4654, 65289, 291, 120762, 12688, 10525, 4649, 65209, 11797, + 12647, 4648, 4640, 64713, 10224, 64902, 6246, 64950, 7828, 4650, 41464, + 917624, 119086, 4653, 7822, 120331, 12923, 65674, 8669, 194655, 10729, + 43031, 5778, 6302, 2716, 194606, 12680, 119130, 1417, 10916, 917569, + 6441, 8547, 2711, 11552, 120798, 64953, 7992, 12429, 41907, 4662, 65453, + 120408, 9149, 9146, 599, 4641, 9179, 64819, 63782, 4656, 10130, 41469, + 7811, 40994, 12426, 4646, 5967, 865, 3725, 5713, 5814, 4645, 42033, + 120422, 41756, 13132, 64728, 9026, 10833, 64673, 1659, 919, 41935, 1671, + 11459, 3054, 9219, 9744, 1661, 7605, 4622, 119087, 10140, 9713, 12427, + 41938, 66674, 9045, 2306, 10485, 19926, 6068, 10612, 10401, 4617, 119596, + 120463, 41462, 4616, 10518, 10423, 10359, 66491, 5958, 917842, 9564, + 4618, 826, 65577, 4321, 4621, 195048, 41313, 522, 5368, 1808, 7848, + 194992, 5366, 12201, 5372, 10913, 12668, 917781, 4391, 64331, 2696, + 120155, 11003, 4638, 64490, 1790, 66304, 167, 10921, 9791, 917631, 9840, + 5376, 1835, 5335, 10313, 41370, 4633, 64320, 10265, 1180, 4632, 43009, + 5387, 5333, 64256, 12903, 41, 5331, 1792, 11928, 41548, 5338, 4637, + 120373, 5971, 4289, 120393, 385, 4152, 2585, 194605, 10909, 3126, 1427, + 65551, 10957, 5970, 3431, 64890, 10358, 7531, 4758, 917573, 1608, 2738, + 7443, 10455, 4753, 917854, 11344, 65729, 6240, 5231, 119013, 12147, + 65216, 6248, 0, 2593, 8463, 7810, 65807, 5229, 4757, 65192, 66581, 2728, + 4411, 64563, 65235, 5234, 41124, 120424, 9580, 10066, 9746, 119559, 2622, + 6033, 13061, 8016, 41196, 8954, 64831, 65189, 2632, 12390, 10108, 1011, + 5574, 1853, 2709, 65139, 5577, 42091, 41165, 393, 12450, 8965, 11458, + 42177, 5316, 917940, 171, 5941, 5572, 68127, 5312, 12531, 5525, 5330, + 5319, 10043, 65710, 42080, 8937, 63798, 12454, 7548, 42132, 12063, + 917991, 64343, 3230, 0, 10350, 10644, 5209, 297, 5721, 12109, 8415, 8632, + 10102, 11267, 120219, 2497, 5720, 960, 1692, 42146, 4610, 8696, 4292, + 64760, 4609, 10512, 4614, 541, 194890, 5287, 5309, 2503, 119243, 1762, + 4647, 56, 10743, 5844, 41381, 601, 4613, 10194, 4663, 1899, 4608, 2507, + 11025, 5190, 67628, 63759, 68145, 11405, 8892, 120348, 67620, 66639, + 2734, 5782, 420, 64368, 63795, 41649, 10797, 5960, 63797, 8992, 65293, + 41238, 1782, 12814, 8959, 12525, 10686, 41383, 5501, 41842, 3650, 7442, + 120749, 359, 4183, 119957, 6239, 12787, 41256, 329, 66582, 12573, 120452, + 7437, 9346, 41188, 13196, 7439, 42167, 3767, 5737, 5380, 4865, 195047, + 1155, 120434, 5736, 4368, 64724, 63749, 68137, 5601, 5739, 41023, 4866, + 9985, 7987, 41928, 1172, 64572, 917596, 6253, 120365, 6650, 5603, 41666, + 4473, 64148, 4870, 65901, 65347, 41799, 65345, 8199, 195007, 5347, + 119063, 9280, 4864, 10398, 4144, 119633, 120567, 6245, 120478, 2732, + 5598, 745, 4555, 5341, 119847, 4777, 7821, 5351, 120747, 119589, 41950, + 120729, 120210, 3097, 63817, 5966, 120363, 4778, 120596, 10863, 1660, + 4781, 66460, 271, 41940, 65370, 8577, 65368, 12653, 65366, 10216, 4782, + 10000, 65362, 65361, 11912, 12325, 11323, 8717, 41583, 65355, 4776, + 65353, 11492, 8700, 761, 13168, 10575, 10426, 917905, 120150, 10362, + 11272, 1715, 4849, 8242, 9561, 194982, 195090, 10607, 120511, 120675, + 5963, 66563, 41509, 4916, 4850, 380, 1607, 466, 4853, 194905, 4854, + 917625, 5164, 41096, 1350, 5124, 64420, 120354, 5362, 8471, 2708, 64716, + 7946, 3785, 234, 19963, 120481, 41268, 4848, 2530, 41636, 4798, 1225, + 6630, 65684, 10458, 120595, 8576, 5197, 195087, 2704, 4794, 8329, 63823, + 8322, 4797, 66326, 5725, 2694, 2595, 3363, 2439, 65104, 5607, 41089, 303, + 41162, 119044, 2665, 2437, 917791, 9817, 4844, 8764, 13013, 8934, 65398, + 917929, 4492, 120347, 9843, 2441, 10739, 65090, 1188, 119327, 1100, 2451, + 2714, 41081, 2912, 194817, 4937, 65746, 753, 3572, 10023, 4959, 11722, + 9248, 65815, 9729, 11725, 65190, 119094, 2726, 3107, 194658, 4941, 7996, + 10995, 9140, 1408, 5261, 41412, 9068, 181, 119819, 4942, 43043, 4938, + 41341, 972, 5259, 4004, 64185, 4142, 5257, 194712, 120529, 4964, 5264, + 9538, 64177, 64176, 41225, 64182, 63800, 64180, 11396, 9482, 4873, 3265, + 1822, 194867, 12601, 41078, 3865, 261, 5927, 7568, 118931, 118930, + 917858, 10696, 9830, 6073, 389, 10467, 6255, 6075, 4872, 282, 194633, + 3125, 9567, 195012, 4878, 5459, 4874, 119046, 9557, 3474, 64774, 120356, + 11494, 6081, 9563, 9411, 11017, 13017, 11940, 41033, 65928, 10788, 64190, + 8751, 10385, 120273, 7816, 9414, 4665, 12628, 4670, 119871, 41555, + 120485, 9642, 10912, 958, 12959, 3082, 119112, 4666, 0, 4915, 917896, + 2891, 5856, 12096, 5163, 4664, 10836, 1817, 66724, 12231, 41554, 10564, + 7450, 13077, 42099, 4400, 9697, 3606, 10275, 8925, 10371, 10307, 1063, + 10227, 11410, 9772, 4541, 6299, 1389, 64203, 64201, 9823, 42081, 12941, + 19906, 10520, 118839, 119557, 12301, 64192, 10505, 10878, 42772, 64196, + 12172, 41814, 1017, 64175, 523, 505, 1447, 846, 0, 41813, 917827, 8608, + 120537, 65482, 2543, 12163, 3108, 9745, 4529, 64166, 64165, 64164, 7919, + 120639, 1641, 64168, 64949, 8966, 10251, 10247, 5908, 715, 64161, 64160, + 7542, 1699, 10943, 10763, 120379, 11352, 550, 10169, 11515, 64385, 66579, + 3766, 64856, 5780, 9504, 6611, 257, 10373, 13153, 12061, 10261, 10253, + 6404, 2599, 9433, 6496, 1552, 5930, 66664, 11476, 11447, 3128, 4789, + 5067, 4911, 3760, 1718, 9438, 8827, 1146, 5065, 41435, 4352, 68136, 2435, + 41839, 5064, 5326, 120453, 3778, 1809, 8873, 7824, 19919, 5062, 1264, + 64817, 765, 11697, 3764, 8473, 64092, 8469, 3933, 12947, 4564, 7954, + 917908, 10375, 917872, 119902, 64768, 194983, 41012, 5225, 63910, 42130, + 7903, 5151, 194862, 64121, 64685, 5626, 2569, 66498, 3800, 65424, 119859, + 917575, 5353, 5625, 10894, 954, 8022, 1010, 41043, 65456, 41438, 41439, + 9904, 10711, 4593, 119564, 119003, 2590, 5629, 13309, 7551, 10325, 5632, + 10471, 120038, 64759, 42054, 5166, 5628, 120031, 970, 120029, 4772, 2400, + 5627, 64130, 120018, 12885, 3119, 63998, 10961, 3060, 203, 9986, 917574, + 64344, 636, 11698, 120652, 63832, 42111, 11701, 120448, 554, 64137, 8320, + 64275, 8863, 120442, 42042, 1477, 63803, 194864, 120792, 5694, 7689, + 42142, 9323, 4325, 3047, 3937, 175, 194815, 3169, 64016, 64781, 912, + 1243, 4536, 5431, 6652, 120058, 6244, 65839, 120480, 3935, 120665, 1129, + 917936, 11950, 5392, 68177, 7846, 64024, 5397, 120008, 12046, 12599, + 3845, 4490, 5395, 6556, 5393, 354, 7530, 11977, 41029, 8366, 119183, + 7756, 3901, 65484, 51, 626, 41602, 5895, 9568, 64057, 456, 120333, 8145, + 1168, 9251, 9082, 119964, 9854, 4311, 3866, 8818, 41512, 119952, 118865, + 10324, 3918, 5377, 3797, 1644, 10405, 9658, 4140, 13057, 42029, 42037, + 9030, 813, 119945, 41454, 4146, 195036, 5360, 2466, 236, 195032, 119942, + 6249, 42117, 5898, 120670, 41457, 119148, 5855, 1969, 2384, 988, 119106, + 12838, 64483, 917834, 10341, 10552, 65479, 5854, 120397, 10583, 118933, + 119989, 119940, 10416, 11981, 3872, 119361, 64014, 120725, 6093, 9748, + 2838, 119939, 65843, 170, 120516, 13143, 4169, 118847, 13311, 6058, 6448, + 10553, 1662, 65295, 917782, 64342, 5892, 120822, 10178, 42106, 66, 65, + 68, 67, 70, 69, 72, 71, 74, 73, 76, 75, 78, 77, 80, 79, 82, 81, 84, 83, + 86, 85, 88, 87, 90, 89, 4736, 10357, 64155, 849, 1704, 8556, 120402, + 9659, 64926, 1743, 120512, 9556, 9496, 4503, 11353, 9647, 7876, 68132, + 120575, 3928, 11948, 65283, 10706, 63975, 65427, 4842, 6438, 66509, 9109, + 4841, 1289, 4171, 12008, 6251, 3923, 1490, 2447, 65539, 119187, 10907, + 5245, 119218, 10114, 64000, 9790, 4845, 8332, 10582, 119622, 4840, 5675, + 254, 1747, 65429, 4825, 10626, 8918, 10281, 5716, 64004, 65799, 120576, + 19955, 917989, 8080, 118895, 367, 1472, 120386, 6687, 4829, 64693, 5905, + 12339, 8919, 9515, 4435, 118992, 11023, 119109, 4830, 9134, 41365, 64125, + 41978, 1412, 4594, 1391, 10536, 7720, 4824, 7775, 120425, 120392, 1888, + 1960, 3140, 66449, 7960, 41836, 41844, 6052, 6064, 54, 1428, 12214, + 68098, 6211, 7699, 358, 66592, 10557, 11442, 10758, 8223, 65759, 4261, + 12642, 194844, 120343, 120400, 120496, 119053, 41858, 119055, 64118, + 194902, 64554, 10574, 3878, 4017, 12827, 1752, 65195, 12962, 41118, 3924, + 10199, 118965, 64966, 119019, 120107, 65664, 41116, 720, 324, 194964, + 41977, 12057, 11917, 1464, 41343, 4721, 7974, 64353, 8957, 66484, 64488, + 120371, 9853, 64041, 195058, 12740, 12640, 4722, 917617, 917820, 0, 4725, + 9690, 4726, 194756, 41173, 119843, 118969, 5204, 119248, 67588, 67605, + 4015, 3995, 8052, 476, 3714, 10073, 3595, 10232, 10999, 1382, 64209, + 12636, 64215, 64214, 1656, 41831, 8130, 8672, 8832, 8720, 3908, 1452, + 13111, 64523, 64067, 194926, 8552, 12398, 41845, 3849, 120657, 195063, + 9778, 468, 612, 42150, 55, 65546, 917911, 64515, 1674, 118951, 5823, + 120276, 1114, 42110, 540, 120052, 119017, 12516, 41743, 3938, 120057, + 65417, 64316, 120060, 11340, 820, 41741, 6292, 65303, 7955, 6452, 4713, + 3359, 7800, 41566, 65177, 6226, 353, 719, 9656, 9474, 64742, 41986, 4532, + 65412, 42114, 10868, 4717, 2349, 5902, 66450, 1884, 9481, 64070, 65400, + 3623, 8155, 1195, 3942, 4714, 9625, 41151, 194653, 5012, 12006, 917604, + 12074, 12409, 42027, 4360, 12964, 6454, 1229, 63793, 66437, 41344, + 917880, 8539, 65100, 120508, 4809, 9623, 4788, 120299, 64885, 64745, + 120207, 65405, 65032, 13075, 194866, 5365, 4545, 8901, 8000, 2492, 4813, + 65432, 917999, 5925, 4808, 64330, 9649, 41154, 65030, 5128, 4038, 12718, + 4810, 64859, 12794, 64928, 1648, 5435, 3522, 11303, 414, 10236, 65439, + 12709, 6456, 120494, 65120, 11905, 41082, 65243, 12581, 10374, 5175, + 63796, 68181, 10254, 63820, 9751, 10262, 64088, 41363, 3919, 607, 194698, + 120288, 9018, 5270, 10314, 10282, 65477, 6564, 64310, 40976, 8265, 7737, + 120752, 40975, 5840, 65436, 10162, 40978, 41632, 8454, 42072, 42038, 387, + 119098, 12737, 120294, 2550, 917910, 42069, 118971, 6442, 3525, 66617, + 9860, 64641, 41590, 5619, 41346, 13157, 375, 7455, 66444, 5616, 8531, + 11473, 42753, 119202, 9454, 5615, 194652, 2315, 120830, 1938, 5455, + 64752, 808, 5568, 11347, 119198, 1026, 5620, 65593, 120787, 11350, 5617, + 10893, 9225, 64639, 12902, 9145, 64595, 1338, 120352, 119178, 9863, + 12161, 2587, 64553, 120274, 6455, 6037, 12834, 3974, 7998, 10290, 10888, + 3083, 10322, 2316, 12348, 64027, 41036, 120369, 66442, 12552, 65606, + 119822, 12739, 5373, 120784, 64700, 3762, 1445, 40961, 65304, 11986, + 120708, 40960, 917923, 3780, 7485, 5779, 64952, 10402, 12011, 3906, 9707, + 10603, 8326, 0, 65498, 3763, 11468, 5618, 194688, 3779, 120078, 9324, + 118852, 63822, 9073, 66585, 64302, 10704, 280, 4787, 917861, 68138, + 13072, 1894, 41180, 120111, 9570, 64020, 8699, 2689, 7878, 65426, 65793, + 42135, 41824, 2551, 10456, 6453, 10200, 3998, 65229, 66562, 503, 194691, + 4470, 2690, 118853, 7780, 5369, 41954, 5249, 1652, 772, 8756, 8310, + 65428, 3487, 64873, 3585, 1688, 194956, 119159, 41822, 194874, 6468, + 41904, 9720, 41697, 41319, 13125, 10650, 5836, 12358, 4668, 4355, 9048, + 1465, 10850, 3943, 19947, 41205, 41315, 41488, 120827, 119613, 5352, + 12362, 12435, 8839, 41053, 3266, 7785, 12356, 8616, 12104, 917875, 65625, + 11450, 194755, 3638, 5420, 3897, 3216, 195011, 2358, 4018, 8633, 2850, + 13304, 9639, 65445, 0, 41263, 2561, 63807, 3542, 120023, 12076, 5303, + 8078, 12676, 64418, 6276, 1706, 194785, 41819, 41422, 12943, 11464, + 10792, 41484, 194607, 10847, 41050, 8872, 860, 13099, 118844, 194819, + 118886, 6435, 10830, 194935, 615, 10668, 7574, 917582, 10504, 9779, 3625, + 43016, 41409, 66651, 41425, 65087, 9178, 8789, 41427, 4022, 64531, 11804, + 118889, 11288, 41424, 917598, 118811, 41820, 195010, 65292, 4812, 1261, + 120340, 3911, 12102, 119179, 1033, 64939, 64642, 917921, 3904, 65822, + 10514, 3275, 65226, 917961, 13123, 10846, 11392, 41321, 66513, 12138, + 10989, 119048, 6233, 10598, 449, 2669, 903, 118997, 2920, 9636, 65240, + 10738, 118897, 9367, 593, 41085, 3917, 64172, 11732, 64307, 120457, + 41448, 3596, 119832, 0, 9763, 64082, 8819, 8113, 124, 12981, 41113, 232, + 12234, 120646, 9168, 65811, 10820, 194895, 64053, 9094, 1769, 41715, + 2463, 119065, 1064, 13307, 41976, 1538, 19924, 0, 120476, 7862, 7795, + 1474, 8516, 4828, 1258, 7561, 12744, 11585, 1878, 9498, 0, 2911, 120094, + 41178, 3939, 64823, 8846, 8943, 12617, 41174, 2650, 4491, 1961, 41463, + 11525, 11292, 1959, 775, 66488, 41732, 41016, 6074, 9618, 64827, 1511, + 3613, 66440, 4259, 41436, 3656, 19930, 64533, 41019, 12428, 68160, 11333, + 6243, 8514, 8513, 9054, 1613, 41828, 119360, 65531, 194879, 68139, + 194877, 67604, 5741, 10145, 8865, 6402, 119099, 5788, 7917, 64808, 65730, + 7733, 64359, 4998, 120375, 119904, 65494, 917968, 4268, 41247, 120524, + 120370, 3871, 8036, 10881, 9111, 10621, 41696, 65462, 67584, 10993, + 120745, 9765, 120368, 195089, 11648, 42118, 10321, 65281, 41587, 10949, + 194644, 42107, 917607, 917860, 5416, 10802, 41164, 66318, 65298, 65723, + 5685, 118845, 12633, 7928, 10848, 8094, 41595, 118821, 6474, 794, 65909, + 12656, 10355, 64665, 5274, 1665, 41598, 3993, 119165, 64512, 40971, 536, + 189, 12611, 119234, 194651, 2859, 4838, 63838, 4834, 2338, 195075, + 119145, 4837, 41944, 770, 41452, 811, 1687, 41042, 66620, 120730, 64427, + 64326, 40969, 10526, 3895, 5406, 40968, 1339, 11731, 120473, 10193, 3116, + 7747, 119185, 8020, 10843, 11554, 12825, 0, 8266, 41006, 12371, 2871, + 64614, 41245, 999, 119129, 64567, 12745, 2663, 64586, 119636, 64191, + 68096, 10150, 65367, 64308, 1522, 597, 4775, 10917, 12571, 10448, 12583, + 12560, 12558, 12556, 12584, 1741, 65097, 1227, 4783, 12566, 11013, 12554, + 120558, 10812, 1586, 4978, 195046, 3078, 1402, 5285, 9391, 40984, 9379, + 9372, 394, 3088, 6284, 917966, 41663, 3991, 9377, 120785, 9237, 424, + 41648, 41208, 120366, 9384, 41076, 1830, 120816, 8647, 41656, 8246, + 120307, 917948, 195039, 41840, 119605, 2377, 41676, 64864, 12572, 11318, + 12557, 12559, 5479, 2796, 1003, 2373, 9446, 9447, 9448, 48, 194920, 9480, + 481, 2359, 9125, 9439, 9440, 9441, 548, 9153, 9444, 9445, 9430, 9431, + 9432, 397, 9434, 9435, 3984, 9437, 195057, 1614, 9424, 9425, 9426, 6651, + 1358, 9429, 428, 9620, 9655, 917760, 10982, 9096, 1333, 65170, 407, 6425, + 917630, 917763, 5955, 66320, 1108, 5804, 11976, 8554, 41466, 64782, 3926, + 9057, 11434, 8798, 120734, 917857, 1392, 1883, 7476, 5986, 5985, 8065, + 41326, 10353, 7468, 0, 917866, 4407, 6502, 4019, 119595, 118919, 8448, + 8219, 41688, 1812, 12675, 12659, 41793, 194823, 119167, 42172, 42068, + 6054, 10697, 2386, 119810, 9170, 10642, 3909, 64585, 10296, 41763, + 119171, 10977, 42082, 4164, 1049, 195045, 65707, 11943, 41806, 8709, + 10606, 3921, 12275, 64691, 12936, 8994, 1038, 118966, 8470, 65695, 0, + 577, 119585, 8773, 10733, 36, 194793, 5153, 41805, 13097, 194782, 763, + 8736, 1414, 64495, 9683, 194841, 66681, 120831, 2536, 119951, 66330, + 119625, 8621, 8963, 12852, 3031, 120034, 41345, 66317, 182, 66315, 64402, + 65562, 10210, 120492, 9058, 366, 120764, 9892, 961, 63755, 6426, 4570, + 11478, 3106, 65917, 41284, 1696, 41189, 4003, 12105, 68109, 5766, 12802, + 3264, 8824, 13268, 917801, 10936, 63980, 11287, 6128, 119083, 19956, + 10923, 2322, 12797, 65506, 8300, 65861, 917536, 41285, 3547, 120144, + 8112, 119600, 41459, 41369, 6089, 13000, 43027, 12117, 4170, 1029, 10540, + 12315, 9063, 65101, 119979, 744, 120821, 12897, 3792, 4926, 917623, 6065, + 3551, 194598, 118800, 4623, 41186, 41816, 4598, 41818, 12795, 5968, 7922, + 12614, 10851, 8523, 6179, 119066, 6180, 1863, 4710, 194981, 5956, 11972, + 41290, 65552, 4705, 716, 177, 120739, 4704, 12360, 120270, 64719, 161, + 9020, 3362, 119931, 4706, 10646, 66594, 64788, 4709, 7518, 8754, 19909, + 120237, 120245, 119164, 68144, 7508, 9136, 1700, 4401, 41280, 194711, + 8974, 2308, 119910, 10634, 41791, 2318, 8506, 66361, 8198, 42022, 1005, + 937, 118996, 4734, 2870, 41277, 12319, 66619, 5404, 4729, 3667, 235, + 1384, 4728, 41049, 120420, 120644, 120017, 8109, 65505, 119920, 4730, + 447, 13186, 1513, 4733, 8664, 63978, 65219, 119221, 12911, 9665, 1383, + 8565, 2469, 119866, 12663, 6156, 68117, 917586, 7993, 4288, 119828, 2674, + 13238, 11922, 41145, 41468, 3510, 13234, 41148, 8683, 5605, 42095, 10497, + 12221, 1380, 12314, 41146, 118964, 11441, 13197, 3512, 120682, 9495, + 8103, 194596, 5959, 65184, 11780, 41563, 11586, 120028, 41925, 13205, + 13211, 5801, 41923, 119344, 120316, 1283, 11924, 4779, 7988, 3719, 4006, + 3271, 19957, 64038, 8355, 118799, 8842, 64747, 3804, 13070, 11557, 3875, + 5962, 1095, 64371, 3599, 65880, 5827, 120411, 7787, 120140, 41378, 7465, + 64493, 12207, 4773, 11684, 64034, 119565, 917865, 12785, 42043, 64943, + 66677, 917965, 42046, 9742, 521, 65136, 10800, 41473, 8404, 66725, 483, + 0, 1450, 12986, 928, 11605, 65441, 917882, 10599, 120435, 3989, 10971, + 120016, 5771, 9841, 6539, 12145, 118983, 10074, 194778, 9807, 3769, + 41190, 3973, 12821, 4575, 9573, 7982, 429, 8849, 118967, 65573, 41771, + 1796, 118918, 64887, 6417, 8164, 41301, 3502, 120382, 194912, 64959, + 4919, 10590, 5825, 7755, 68165, 0, 64548, 12661, 1621, 10214, 10418, + 41962, 65868, 41971, 1409, 11551, 1617, 3112, 10824, 5015, 1390, 64403, + 194976, 421, 1756, 5846, 66476, 8666, 120132, 7595, 120360, 7555, 3630, + 5408, 2817, 1214, 12883, 120124, 10218, 41769, 3168, 194916, 42134, 7957, + 2370, 2846, 1056, 119070, 12798, 118910, 120314, 1836, 8757, 65850, + 12327, 3740, 119028, 5622, 65374, 41765, 2341, 3944, 8484, 8474, 120817, + 6135, 3118, 8461, 41942, 12153, 5621, 12799, 8127, 8975, 9451, 7571, + 13073, 12169, 10618, 681, 194562, 703, 120812, 3272, 8781, 12894, 120527, + 11709, 119601, 4815, 42053, 6561, 8279, 8776, 64954, 3276, 917976, 6290, + 4267, 120104, 41325, 65021, 11706, 917825, 12171, 10047, 9710, 3262, + 194604, 194939, 119200, 42020, 118788, 163, 576, 9895, 1655, 5842, 12479, + 3122, 10417, 7793, 65581, 9328, 64352, 10039, 6003, 12569, 5623, 120026, + 5717, 3986, 120634, 42023, 8912, 64555, 12604, 64078, 65700, 3627, 4523, + 64934, 11595, 8540, 11498, 8887, 4574, 41040, 2459, 64886, 13060, 41041, + 8946, 10348, 10412, 5718, 120088, 10450, 8147, 13221, 66329, 9999, 3765, + 119885, 68153, 1606, 12178, 686, 3093, 119126, 4619, 10600, 6654, 7712, + 64826, 4312, 41918, 65689, 10128, 11923, 4023, 41892, 5763, 120335, 4827, + 2401, 12810, 8792, 120346, 4455, 7826, 433, 64824, 66660, 2499, 41812, + 12886, 65375, 11973, 13089, 4293, 10300, 10161, 10396, 12196, 66322, + 66630, 194901, 119319, 3010, 5817, 65719, 1458, 3120, 9797, 9643, 119317, + 4984, 10389, 66682, 9100, 9017, 120364, 120243, 1061, 4699, 9115, 3509, + 0, 486, 4290, 9896, 12291, 120620, 194887, 1045, 120204, 5631, 10380, + 9626, 2380, 0, 194863, 120678, 2376, 8486, 120618, 9824, 2335, 4362, + 12174, 194909, 2366, 1025, 195101, 12634, 120760, 65423, 41443, 120732, + 917847, 11713, 1774, 1523, 917561, 5058, 41445, 65762, 65310, 8567, + 41442, 3988, 0, 64882, 1847, 917947, 10403, 8564, 65385, 65076, 65117, + 120413, 194811, 65908, 12616, 65887, 6256, 119628, 12671, 194933, 10206, + 118974, 917792, 2673, 11960, 5820, 9318, 4488, 119567, 7926, 65358, + 10444, 42137, 9893, 2754, 9850, 41437, 4487, 12722, 41957, 1032, 65530, + 1711, 12984, 43039, 3114, 614, 120691, 13116, 64923, 120790, 926, 120640, + 65670, 64204, 194848, 194676, 10832, 120362, 1050, 7549, 41035, 11583, + 9314, 41801, 119088, 120616, 520, 10437, 9558, 8331, 917806, 3091, 41034, + 917887, 2307, 8360, 10097, 65768, 321, 41028, 12750, 917903, 65563, + 120241, 120262, 2861, 10360, 10095, 0, 66307, 440, 1861, 13085, 9233, + 120265, 64532, 43041, 119158, 12123, 13133, 3859, 10570, 41660, 8209, + 65778, 118841, 10910, 120423, 1521, 7875, 41658, 10487, 120606, 5760, + 13011, 743, 4414, 119571, 118873, 65769, 5243, 9849, 5239, 65771, 10778, + 1405, 5237, 917878, 65112, 10103, 5247, 4769, 42063, 5508, 120829, 5764, + 11792, 3513, 3008, 9378, 120395, 194960, 10125, 65364, 41103, 9394, 6485, + 1397, 64795, 65365, 119093, 4770, 120590, 9392, 8731, 7471, 12079, + 120619, 11316, 9122, 194725, 4774, 3019, 9997, 11549, 194919, 1099, + 10215, 65565, 1340, 9390, 66717, 41453, 464, 4281, 4768, 9385, 64470, + 1346, 4995, 65679, 12087, 9780, 423, 1818, 65144, 66665, 8272, 917844, + 66324, 12904, 3087, 64960, 10111, 19967, 64707, 0, 9584, 8214, 194998, + 12159, 12626, 9106, 118907, 40979, 5806, 64750, 64517, 8243, 9123, 5709, + 0, 265, 10922, 13255, 12605, 917628, 2752, 64626, 120256, 1434, 59, 5637, + 11573, 0, 64897, 68129, 19951, 10379, 66305, 119345, 41809, 10283, 41983, + 7547, 64684, 1156, 8009, 3305, 3782, 511, 12496, 63752, 1014, 64360, + 11906, 120125, 10835, 10157, 65536, 1400, 10323, 10685, 7702, 41211, + 10387, 4453, 2440, 3758, 1150, 10547, 5700, 19910, 65349, 65383, 2339, + 64019, 5697, 41156, 6617, 9116, 119227, 0, 462, 41841, 10493, 3862, 8129, + 917958, 120404, 12864, 6644, 9845, 64794, 8261, 5701, 9722, 9581, 1385, + 1426, 119992, 41125, 41872, 194620, 11404, 6493, 119896, 13288, 120108, + 5167, 120717, 1681, 12184, 1204, 3755, 11935, 7748, 8213, 3286, 8911, + 64712, 10744, 65356, 990, 5647, 5726, 64915, 10377, 118947, 11477, 5646, + 65044, 11018, 2851, 3945, 120096, 120119, 4373, 194948, 12997, 9587, + 1789, 1020, 120097, 3100, 41497, 5648, 64748, 13162, 119336, 10205, 3545, + 8190, 10016, 64616, 917890, 6506, 64312, 66669, 2368, 63993, 4419, 65727, + 66469, 3439, 1825, 1192, 119166, 8891, 3080, 118836, 2347, 5430, 1140, + 8990, 2848, 10159, 41859, 120212, 249, 917777, 9173, 12191, 1815, 194832, + 890, 8883, 3267, 728, 42144, 995, 120633, 4410, 1041, 10576, 8102, 10099, + 10343, 19945, 8091, 558, 120110, 12273, 13163, 19938, 12112, 12446, + 41389, 64482, 65214, 5375, 10142, 8548, 8215, 3129, 6134, 12913, 9005, + 41856, 13242, 64891, 7725, 11938, 11662, 119326, 8624, 5173, 19959, 527, + 120701, 41894, 10327, 6277, 10608, 10010, 9879, 917612, 3540, 41672, 835, + 2329, 120813, 12238, 13001, 7849, 12245, 5426, 4258, 63987, 41787, 5424, + 12016, 8283, 120808, 5434, 194561, 194937, 8067, 6144, 194758, 10311, + 118977, 1404, 3095, 11432, 120211, 3464, 494, 4819, 119608, 65098, 570, + 956, 3672, 13112, 1498, 120100, 65857, 119184, 431, 10029, 65159, 195066, + 8761, 41537, 13171, 13096, 194953, 65108, 118911, 9516, 1044, 5268, 0, + 4954, 194972, 4450, 11795, 11547, 64358, 11946, 356, 3477, 227, 10488, + 13214, 382, 11418, 12295, 120641, 11475, 917845, 3020, 11537, 6484, 2541, + 917998, 12364, 11337, 65568, 1057, 566, 9110, 119104, 2743, 64931, 63965, + 64338, 9097, 66571, 41305, 8782, 3006, 776, 2524, 1592, 8573, 917843, + 10924, 65164, 63941, 41593, 4397, 8952, 3856, 66505, 119892, 5872, 6495, + 120510, 6486, 41155, 1698, 13177, 12830, 5413, 3953, 1053, 19917, 65094, + 11448, 4339, 1052, 1051, 459, 1060, 917853, 66479, 65299, 65703, 5228, + 119955, 7868, 689, 6508, 4163, 120757, 8639, 66641, 43022, 65510, 1162, + 12130, 2671, 65806, 8095, 64375, 7521, 42178, 4553, 195034, 0, 12299, + 41433, 195004, 19921, 64298, 11424, 64169, 4567, 41891, 1926, 66646, + 119056, 4820, 8110, 10935, 64690, 194665, 5830, 119212, 1377, 119889, + 4897, 12932, 9250, 8693, 4438, 194947, 917560, 1753, 11331, 6147, 11431, + 64621, 8833, 120671, 0, 6504, 41428, 64596, 10719, 43012, 1898, 1413, + 194763, 65394, 802, 12141, 917953, 5561, 6648, 10671, 2528, 41774, 41379, + 9169, 838, 5669, 64484, 844, 5014, 65854, 256, 0, 5583, 41987, 120280, + 41399, 5580, 65464, 2923, 10853, 5582, 10048, 65699, 13069, 5795, 13158, + 66598, 65702, 6087, 65701, 41322, 12180, 65704, 120662, 194850, 194582, + 8894, 5370, 64055, 118917, 1638, 10966, 12200, 194630, 118848, 5733, + 67631, 64288, 194966, 8172, 42017, 5729, 10844, 8319, 6498, 9760, 0, + 120106, 1238, 200, 120555, 1062, 119993, 118893, 118905, 917606, 195069, + 1070, 9361, 917942, 6095, 3394, 120664, 3015, 120609, 41827, 4037, 7763, + 6400, 65186, 66626, 7817, 1841, 11276, 12976, 65724, 372, 1669, 10776, + 63937, 7701, 41585, 64397, 119211, 1732, 276, 41862, 2828, 33, 65326, + 41768, 6491, 65332, 41588, 914, 427, 8071, 3538, 3900, 65321, 41864, + 1031, 6257, 7614, 41869, 120826, 120573, 2328, 12399, 1071, 41400, 65537, + 13249, 10841, 41627, 5301, 1047, 195094, 5734, 8960, 11312, 8001, 10651, + 119970, 65012, 9663, 66441, 12304, 41621, 5711, 12921, 12098, 65571, + 9166, 12164, 5710, 64363, 65585, 65168, 12447, 10571, 917975, 119617, + 119246, 64611, 5558, 917888, 5715, 10915, 120118, 12007, 3670, 2761, + 11975, 64811, 3074, 5722, 194876, 8629, 120632, 11307, 4499, 2757, 4496, + 9718, 120116, 8910, 10689, 120391, 12717, 65451, 11782, 194822, 66316, + 194729, 41630, 41640, 65596, 917840, 11416, 4280, 13118, 8765, 12784, + 7792, 1393, 917542, 8701, 6585, 8487, 8233, 917788, 119874, 6683, 120009, + 4495, 12144, 2841, 12543, 119320, 1473, 10490, 64329, 118984, 65467, + 120006, 6488, 357, 1048, 41100, 917809, 41104, 65122, 8035, 1054, 917950, + 1040, 65450, 5454, 4434, 1069, 195095, 13019, 194906, 119261, 5084, + 65402, 119133, 9693, 12354, 733, 10762, 41677, 41102, 4353, 41674, 1059, + 9218, 1731, 917883, 120528, 120000, 120643, 41679, 8299, 11994, 118833, + 64390, 194922, 5155, 11599, 12743, 42122, 6480, 65740, 41779, 0, 3587, + 12131, 41432, 10986, 66602, 9605, 64807, 12788, 43020, 41767, 3371, + 917549, 13114, 8771, 1479, 41022, 194950, 1109, 11000, 120740, 64508, + 9770, 9246, 12230, 63801, 8868, 399, 65137, 41783, 41772, 64045, 11742, + 2755, 551, 917803, 10156, 4857, 9874, 4428, 2544, 65074, 194614, 120209, + 917811, 194786, 351, 5747, 12179, 194603, 7978, 41092, 118954, 120502, + 10791, 19935, 10712, 65015, 120667, 563, 64815, 120722, 9013, 5588, 57, + 0, 10386, 65269, 119043, 5585, 65881, 2549, 694, 66712, 9876, 5584, 8358, + 64717, 10238, 65279, 10919, 277, 7980, 119298, 41815, 120233, 41800, + 5589, 41807, 2664, 12793, 5586, 1574, 10513, 11356, 2525, 4852, 5749, + 917765, 41605, 64696, 119306, 1039, 9801, 10155, 5745, 188, 8135, 6450, + 10055, 66604, 9055, 41853, 4858, 5657, 194700, 436, 4771, 194639, 2786, + 5654, 4856, 8051, 120799, 119026, 194891, 5652, 10945, 194581, 120761, + 12280, 3661, 7863, 118834, 119933, 41302, 66608, 64699, 5402, 10234, + 5843, 11939, 5655, 42157, 195079, 3157, 1055, 194955, 917553, 3504, + 64785, 118790, 10822, 5149, 41927, 10226, 41871, 13159, 3594, 10272, + 10304, 40, 12657, 594, 10244, 386, 9453, 8834, 10816, 118866, 3467, + 41010, 119579, 3331, 946, 10231, 1495, 8131, 13179, 119045, 9562, 4304, + 65927, 8160, 120234, 63974, 64529, 64656, 63995, 1348, 12239, 64013, + 5666, 13303, 10555, 120751, 119919, 7599, 10798, 65230, 13269, 10195, + 119932, 7732, 41905, 9793, 0, 6097, 5668, 8780, 4982, 119883, 5670, + 63969, 120298, 12741, 2672, 3735, 5667, 13138, 119915, 9484, 10724, + 13203, 119024, 65258, 66496, 4361, 9487, 64314, 9286, 1497, 120169, 1932, + 12442, 6193, 3571, 11984, 917945, 7973, 119157, 64821, 11964, 12613, + 7873, 11399, 119219, 553, 13049, 41533, 194857, 3604, 65912, 4587, 66709, + 120048, 66667, 12746, 1962, 120083, 194696, 5633, 11660, 66337, 7559, + 120593, 64905, 12856, 5437, 65208, 10669, 6443, 7964, 63971, 9135, 199, + 10976, 4105, 63880, 120622, 120181, 65816, 12148, 13148, 7560, 66686, + 9226, 120439, 11669, 6472, 5634, 4524, 12720, 4724, 67625, 8407, 66323, + 12224, 119201, 194938, 5221, 64348, 328, 7886, 41701, 5448, 5636, 6680, + 5329, 194650, 5638, 6679, 7940, 119076, 118938, 65182, 5635, 3373, 2986, + 118880, 194629, 3437, 119358, 6203, 9833, 12693, 11920, 8274, 194838, + 11685, 1657, 41558, 119610, 7585, 5639, 2954, 5660, 5640, 65376, 194818, + 65102, 19960, 66475, 5297, 41637, 13284, 6112, 7968, 41625, 194737, + 194699, 118955, 11705, 5642, 0, 64630, 42181, 4342, 11710, 67630, 1677, + 64803, 4585, 5641, 8259, 10643, 1058, 2719, 119570, 194638, 194993, 1144, + 5868, 120436, 10867, 11302, 13277, 4308, 2539, 917848, 7505, 543, 64916, + 64736, 2547, 10209, 66670, 65317, 5399, 19911, 917850, 41633, 7902, + 64932, 9000, 12233, 11299, 66499, 1865, 119618, 5613, 194772, 12994, + 65057, 5610, 0, 6228, 4307, 3482, 42133, 10787, 194609, 2997, 506, 5609, + 41194, 12863, 194776, 12316, 41195, 2412, 8169, 8186, 8841, 9522, 516, + 13130, 41197, 917795, 34, 64007, 10030, 5306, 1612, 66622, 42765, 11704, + 65756, 12001, 10211, 119869, 64564, 66365, 65147, 6584, 7749, 120175, + 65693, 1758, 413, 10667, 4677, 120197, 9133, 1935, 11517, 1042, 120196, + 64779, 1931, 10248, 6185, 64776, 1217, 10242, 708, 825, 118913, 65680, + 12294, 41207, 119903, 9138, 2534, 810, 12631, 194911, 120491, 4424, + 119255, 4895, 1239, 2364, 11313, 119149, 3403, 119193, 194610, 64364, + 63952, 65250, 10027, 8998, 194627, 917771, 9152, 194896, 67592, 2980, + 755, 41850, 931, 3433, 13170, 12615, 1594, 42767, 11274, 67603, 12944, + 41623, 8730, 41353, 11587, 67611, 4337, 65188, 41394, 918, 119223, 935, + 7681, 65676, 377, 41393, 11649, 120621, 2477, 64301, 66454, 917826, + 194899, 65201, 9528, 65155, 573, 19912, 7907, 11417, 120186, 194885, + 65328, 10673, 119217, 119938, 67607, 11482, 1781, 5496, 3357, 62, 1649, + 120549, 964, 119242, 64535, 41009, 917773, 11589, 65035, 194872, 65038, + 917605, 64602, 67618, 65840, 11580, 12711, 66575, 4542, 65779, 8423, + 3348, 448, 119173, 2991, 9364, 120036, 997, 7949, 120772, 12849, 11341, + 11440, 3073, 9866, 9714, 11692, 4657, 12988, 4658, 6478, 12335, 119228, + 41975, 6241, 2818, 4877, 2385, 5463, 41897, 4172, 10052, 4409, 8373, + 10873, 12095, 65745, 5346, 120328, 194925, 6237, 5461, 64058, 9176, + 11597, 40974, 64937, 64828, 11419, 120406, 766, 1257, 917547, 10970, + 2408, 3251, 64154, 3274, 5465, 41501, 2461, 120523, 120321, 5342, 8317, + 120394, 68163, 3263, 120046, 8673, 194719, 3270, 64539, 11489, 118999, + 120388, 66672, 120560, 5535, 9142, 195018, 756, 8687, 10938, 120658, + 66443, 1182, 2542, 186, 917862, 119156, 5770, 529, 42115, 12612, 12949, + 10586, 10790, 10839, 8920, 5241, 6479, 41713, 120427, 41594, 225, 11578, + 5688, 41300, 41204, 119105, 118794, 10721, 41209, 9254, 42097, 1794, + 41875, 65238, 5624, 266, 120221, 67637, 41873, 3617, 11324, 41494, + 119824, 8420, 13088, 65755, 1872, 41338, 3734, 7734, 120174, 5502, 65890, + 4452, 41260, 917767, 0, 4511, 5161, 10572, 917614, 11425, 42050, 64349, + 41083, 917884, 917925, 63979, 9003, 8192, 120039, 5305, 9653, 10616, + 1697, 9546, 917930, 194847, 119174, 41482, 65205, 10031, 64063, 9870, + 12535, 8620, 65824, 5581, 8799, 42131, 42031, 64062, 1028, 64060, 64059, + 837, 10567, 119960, 41606, 3176, 64773, 11427, 2902, 64043, 64042, 41740, + 3609, 120550, 13200, 832, 64044, 42156, 10076, 64040, 64039, 12919, 1034, + 3392, 10753, 5180, 64033, 41395, 65468, 11691, 64037, 64036, 41898, 4291, + 63966, 64015, 41114, 243, 8479, 64354, 6024, 11351, 12128, 194908, 3476, + 8973, 8538, 64011, 64010, 64008, 4285, 4800, 7706, 41750, 11604, 2538, + 11609, 204, 7563, 4802, 4111, 8239, 9098, 4805, 64001, 214, 7885, 42143, + 8321, 65893, 12208, 4767, 9343, 64049, 41729, 119986, 1133, 19948, 64052, + 64051, 41187, 8692, 6022, 11788, 10005, 12329, 41333, 120569, 43, 1942, + 12682, 1016, 41107, 12619, 41121, 3885, 92, 64023, 64022, 64021, 6582, + 43030, 12451, 64025, 9167, 41485, 12035, 119208, 6254, 10501, 64018, + 8890, 12457, 66587, 194836, 7582, 64778, 118915, 118813, 66635, 120044, + 66621, 7995, 8759, 41411, 13094, 12449, 7532, 41414, 65109, 3179, 13279, + 4720, 10165, 917618, 119249, 120673, 10751, 9051, 12915, 65913, 10535, + 917892, 4993, 194586, 6168, 10934, 1946, 294, 41874, 5494, 4639, 65929, + 12040, 6196, 4498, 194907, 64028, 8146, 41789, 41788, 2960, 118786, + 118795, 8969, 119884, 10197, 66599, 67621, 2950, 11998, 6210, 11433, 370, + 3549, 64790, 7801, 4953, 11461, 64356, 194973, 3297, 9699, 120693, 1135, + 12700, 7447, 5063, 3517, 2964, 119257, 0, 2552, 41546, 60, 10627, 8649, + 8252, 729, 67624, 119934, 6682, 120007, 43046, 41770, 41547, 9032, 64820, + 65906, 65817, 41215, 119897, 65883, 12832, 119592, 8081, 3761, 3537, + 119908, 9137, 119906, 8999, 65343, 3850, 3466, 4327, 120112, 9373, 66369, + 908, 6282, 6681, 9813, 194997, 41655, 537, 41511, 4179, 8978, 41213, + 65866, 1842, 10527, 120409, 9628, 3848, 12081, 9826, 64502, 1767, 5336, + 120200, 64659, 663, 194846, 10780, 0, 3059, 120024, 119626, 120198, + 66689, 347, 42112, 40992, 4100, 920, 1811, 1355, 7739, 65198, 3592, + 10078, 5318, 194910, 65578, 8592, 65870, 6224, 120192, 9381, 13244, + 64345, 118885, 9281, 3296, 12865, 120715, 1895, +}; + +#define code_magic 47 +#define code_size 16384 +#define code_poly 16427 diff --git a/sys/src/cmd/python/Modules/xxmodule.c b/sys/src/cmd/python/Modules/xxmodule.c new file mode 100644 index 000000000..ea66eefa0 --- /dev/null +++ b/sys/src/cmd/python/Modules/xxmodule.c @@ -0,0 +1,376 @@ + +/* Use this file as a template to start implementing a module that + also declares object types. All occurrences of 'Xxo' should be changed + to something reasonable for your objects. After that, all other + occurrences of 'xx' should be changed to something reasonable for your + module. If your module is named foo your sourcefile should be named + foomodule.c. + + You will probably want to delete all references to 'x_attr' and add + your own types of attributes instead. Maybe you want to name your + local variables other than 'self'. If your object type is needed in + other files, you'll have to create a file "foobarobject.h"; see + intobject.h for an example. */ + +/* Xxo objects */ + +#include "Python.h" + +static PyObject *ErrorObject; + +typedef struct { + PyObject_HEAD + PyObject *x_attr; /* Attributes dictionary */ +} XxoObject; + +static PyTypeObject Xxo_Type; + +#define XxoObject_Check(v) ((v)->ob_type == &Xxo_Type) + +static XxoObject * +newXxoObject(PyObject *arg) +{ + XxoObject *self; + self = PyObject_New(XxoObject, &Xxo_Type); + if (self == NULL) + return NULL; + self->x_attr = NULL; + return self; +} + +/* Xxo methods */ + +static void +Xxo_dealloc(XxoObject *self) +{ + Py_XDECREF(self->x_attr); + PyObject_Del(self); +} + +static PyObject * +Xxo_demo(XxoObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":demo")) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef Xxo_methods[] = { + {"demo", (PyCFunction)Xxo_demo, METH_VARARGS, + PyDoc_STR("demo() -> None")}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +Xxo_getattr(XxoObject *self, char *name) +{ + if (self->x_attr != NULL) { + PyObject *v = PyDict_GetItemString(self->x_attr, name); + if (v != NULL) { + Py_INCREF(v); + return v; + } + } + return Py_FindMethod(Xxo_methods, (PyObject *)self, name); +} + +static int +Xxo_setattr(XxoObject *self, char *name, PyObject *v) +{ + if (self->x_attr == NULL) { + self->x_attr = PyDict_New(); + if (self->x_attr == NULL) + return -1; + } + if (v == NULL) { + int rv = PyDict_DelItemString(self->x_attr, name); + if (rv < 0) + PyErr_SetString(PyExc_AttributeError, + "delete non-existing Xxo attribute"); + return rv; + } + else + return PyDict_SetItemString(self->x_attr, name, v); +} + +static PyTypeObject Xxo_Type = { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "xxmodule.Xxo", /*tp_name*/ + sizeof(XxoObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)Xxo_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)Xxo_getattr, /*tp_getattr*/ + (setattrfunc)Xxo_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; +/* --------------------------------------------------------------------- */ + +/* Function of two integers returning integer */ + +PyDoc_STRVAR(xx_foo_doc, +"foo(i,j)\n\ +\n\ +Return the sum of i and j."); + +static PyObject * +xx_foo(PyObject *self, PyObject *args) +{ + long i, j; + long res; + if (!PyArg_ParseTuple(args, "ll:foo", &i, &j)) + return NULL; + res = i+j; /* XXX Do something here */ + return PyInt_FromLong(res); +} + + +/* Function of no arguments returning new Xxo object */ + +static PyObject * +xx_new(PyObject *self, PyObject *args) +{ + XxoObject *rv; + + if (!PyArg_ParseTuple(args, ":new")) + return NULL; + rv = newXxoObject(args); + if (rv == NULL) + return NULL; + return (PyObject *)rv; +} + +/* Example with subtle bug from extensions manual ("Thin Ice"). */ + +static PyObject * +xx_bug(PyObject *self, PyObject *args) +{ + PyObject *list, *item; + + if (!PyArg_ParseTuple(args, "O:bug", &list)) + return NULL; + + item = PyList_GetItem(list, 0); + /* Py_INCREF(item); */ + PyList_SetItem(list, 1, PyInt_FromLong(0L)); + PyObject_Print(item, stdout, 0); + printf("\n"); + /* Py_DECREF(item); */ + + Py_INCREF(Py_None); + return Py_None; +} + +/* Test bad format character */ + +static PyObject * +xx_roj(PyObject *self, PyObject *args) +{ + PyObject *a; + long b; + if (!PyArg_ParseTuple(args, "O#:roj", &a, &b)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + + +/* ---------- */ + +static PyTypeObject Str_Type = { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "xxmodule.Str", /*tp_name*/ + 0, /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + &PyString_Type, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +/* ---------- */ + +static PyObject * +null_richcompare(PyObject *self, PyObject *other, int op) +{ + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyTypeObject Null_Type = { + /* The ob_type field must be initialized in the module init function + * to be portable to Windows without using C++. */ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "xxmodule.Null", /*tp_name*/ + 0, /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + null_richcompare, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + &PyBaseObject_Type, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + PyType_GenericNew, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + + +/* ---------- */ + + +/* List of functions defined in the module */ + +static PyMethodDef xx_methods[] = { + {"roj", xx_roj, METH_VARARGS, + PyDoc_STR("roj(a,b) -> None")}, + {"foo", xx_foo, METH_VARARGS, + xx_foo_doc}, + {"new", xx_new, METH_VARARGS, + PyDoc_STR("new() -> new Xx object")}, + {"bug", xx_bug, METH_VARARGS, + PyDoc_STR("bug(o) -> None")}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(module_doc, +"This is a template module just for instruction."); + +/* Initialization function for the module (*must* be called initxx) */ + +PyMODINIT_FUNC +initxx(void) +{ + PyObject *m; + + /* Finalize the type object including setting type of the new type + * object; doing it here is required for portability to Windows + * without requiring C++. */ + if (PyType_Ready(&Xxo_Type) < 0) + return; + + /* Create the module and add the functions */ + m = Py_InitModule3("xx", xx_methods, module_doc); + if (m == NULL) + return; + + /* Add some symbolic constants to the module */ + if (ErrorObject == NULL) { + ErrorObject = PyErr_NewException("xx.error", NULL, NULL); + if (ErrorObject == NULL) + return; + } + Py_INCREF(ErrorObject); + PyModule_AddObject(m, "error", ErrorObject); + + /* Add Str */ + if (PyType_Ready(&Str_Type) < 0) + return; + PyModule_AddObject(m, "Str", (PyObject *)&Str_Type); + + /* Add Null */ + if (PyType_Ready(&Null_Type) < 0) + return; + PyModule_AddObject(m, "Null", (PyObject *)&Null_Type); +} diff --git a/sys/src/cmd/python/Modules/xxsubtype.c b/sys/src/cmd/python/Modules/xxsubtype.c new file mode 100644 index 000000000..88ce6c5bb --- /dev/null +++ b/sys/src/cmd/python/Modules/xxsubtype.c @@ -0,0 +1,299 @@ +#include "Python.h" +#include "structmember.h" + +PyDoc_STRVAR(xxsubtype__doc__, +"xxsubtype is an example module showing how to subtype builtin types from C.\n" +"test_descr.py in the standard test suite requires it in order to complete.\n" +"If you don't care about the examples, and don't intend to run the Python\n" +"test suite, you can recompile Python without Modules/xxsubtype.c."); + +/* We link this module statically for convenience. If compiled as a shared + library instead, some compilers don't allow addresses of Python objects + defined in other libraries to be used in static initializers here. The + DEFERRED_ADDRESS macro is used to tag the slots where such addresses + appear; the module init function must fill in the tagged slots at runtime. + The argument is for documentation -- the macro ignores it. +*/ +#define DEFERRED_ADDRESS(ADDR) 0 + +/* spamlist -- a list subtype */ + +typedef struct { + PyListObject list; + int state; +} spamlistobject; + +static PyObject * +spamlist_getstate(spamlistobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":getstate")) + return NULL; + return PyInt_FromLong(self->state); +} + +static PyObject * +spamlist_setstate(spamlistobject *self, PyObject *args) +{ + int state; + + if (!PyArg_ParseTuple(args, "i:setstate", &state)) + return NULL; + self->state = state; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +spamlist_specialmeth(PyObject *self, PyObject *args, PyObject *kw) +{ + PyObject *result = PyTuple_New(3); + + if (result != NULL) { + if (self == NULL) + self = Py_None; + if (kw == NULL) + kw = Py_None; + Py_INCREF(self); + PyTuple_SET_ITEM(result, 0, self); + Py_INCREF(args); + PyTuple_SET_ITEM(result, 1, args); + Py_INCREF(kw); + PyTuple_SET_ITEM(result, 2, kw); + } + return result; +} + +static PyMethodDef spamlist_methods[] = { + {"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS, + PyDoc_STR("getstate() -> state")}, + {"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS, + PyDoc_STR("setstate(state)")}, + /* These entries differ only in the flags; they are used by the tests + in test.test_descr. */ + {"classmeth", (PyCFunction)spamlist_specialmeth, + METH_VARARGS | METH_KEYWORDS | METH_CLASS, + PyDoc_STR("classmeth(*args, **kw)")}, + {"staticmeth", (PyCFunction)spamlist_specialmeth, + METH_VARARGS | METH_KEYWORDS | METH_STATIC, + PyDoc_STR("staticmeth(*args, **kw)")}, + {NULL, NULL}, +}; + +static int +spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + +static PyObject * +spamlist_state_get(spamlistobject *self) +{ + return PyInt_FromLong(self->state); +} + +static PyGetSetDef spamlist_getsets[] = { + {"state", (getter)spamlist_state_get, NULL, + PyDoc_STR("an int variable for demonstration purposes")}, + {0} +}; + +static PyTypeObject spamlist_type = { + PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) + 0, + "xxsubtype.spamlist", + sizeof(spamlistobject), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + spamlist_methods, /* tp_methods */ + 0, /* tp_members */ + spamlist_getsets, /* tp_getset */ + DEFERRED_ADDRESS(&PyList_Type), /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)spamlist_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +/* spamdict -- a dict subtype */ + +typedef struct { + PyDictObject dict; + int state; +} spamdictobject; + +static PyObject * +spamdict_getstate(spamdictobject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":getstate")) + return NULL; + return PyInt_FromLong(self->state); +} + +static PyObject * +spamdict_setstate(spamdictobject *self, PyObject *args) +{ + int state; + + if (!PyArg_ParseTuple(args, "i:setstate", &state)) + return NULL; + self->state = state; + Py_INCREF(Py_None); + return Py_None; +} + +static PyMethodDef spamdict_methods[] = { + {"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS, + PyDoc_STR("getstate() -> state")}, + {"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS, + PyDoc_STR("setstate(state)")}, + {NULL, NULL}, +}; + +static int +spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds) +{ + if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + +static PyMemberDef spamdict_members[] = { + {"state", T_INT, offsetof(spamdictobject, state), READONLY, + PyDoc_STR("an int variable for demonstration purposes")}, + {0} +}; + +static PyTypeObject spamdict_type = { + PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) + 0, + "xxsubtype.spamdict", + sizeof(spamdictobject), + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + spamdict_methods, /* tp_methods */ + spamdict_members, /* tp_members */ + 0, /* tp_getset */ + DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)spamdict_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +static PyObject * +spam_bench(PyObject *self, PyObject *args) +{ + PyObject *obj, *name, *res; + int n = 1000; + time_t t0, t1; + + if (!PyArg_ParseTuple(args, "OS|i", &obj, &name, &n)) + return NULL; + t0 = clock(); + while (--n >= 0) { + res = PyObject_GetAttr(obj, name); + if (res == NULL) + return NULL; + Py_DECREF(res); + } + t1 = clock(); + return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC); +} + +static PyMethodDef xxsubtype_functions[] = { + {"bench", spam_bench, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +initxxsubtype(void) +{ + PyObject *m; + + /* Fill in deferred data addresses. This must be done before + PyType_Ready() is called. Note that PyType_Ready() automatically + initializes the ob.ob_type field to &PyType_Type if it's NULL, + so it's not necessary to fill in ob_type first. */ + spamdict_type.tp_base = &PyDict_Type; + if (PyType_Ready(&spamdict_type) < 0) + return; + + spamlist_type.tp_base = &PyList_Type; + if (PyType_Ready(&spamlist_type) < 0) + return; + + m = Py_InitModule3("xxsubtype", + xxsubtype_functions, + xxsubtype__doc__); + if (m == NULL) + return; + + if (PyType_Ready(&spamlist_type) < 0) + return; + if (PyType_Ready(&spamdict_type) < 0) + return; + + Py_INCREF(&spamlist_type); + if (PyModule_AddObject(m, "spamlist", + (PyObject *) &spamlist_type) < 0) + return; + + Py_INCREF(&spamdict_type); + if (PyModule_AddObject(m, "spamdict", + (PyObject *) &spamdict_type) < 0) + return; +} diff --git a/sys/src/cmd/python/Modules/yuv.h b/sys/src/cmd/python/Modules/yuv.h new file mode 100644 index 000000000..738c4e50c --- /dev/null +++ b/sys/src/cmd/python/Modules/yuv.h @@ -0,0 +1,99 @@ + +#ifndef Py_YUV_H +#define Py_YUV_H +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SVideo YUV 4:1:1 format. + * + * 4 consecutive quadwords describe 8 pixels on 2 lines, as depicted + * below. An array of (width/4) of the below structure describes 2 + * scan lines. + * + * +-------------------+ + * | 00 | 01 | 02 | 03 | . . . + * +-------------------+ + * | 10 | 11 | 12 | 13 | . . . + * +-------------------+ + */ +struct yuv411 { + struct { + unsigned int dummy:8; + unsigned int y0:8; + unsigned int u0:2; + unsigned int v0:2; + unsigned int y1:8; + unsigned int u1:2; + unsigned int v1:2; + } v[4]; +}; + +#define YUV411_Y00(y) (y).v[0].y0 +#define YUV411_Y01(y) (y).v[1].y0 +#define YUV411_Y02(y) (y).v[2].y0 +#define YUV411_Y03(y) (y).v[3].y0 +#define YUV411_Y10(y) (y).v[0].y1 +#define YUV411_Y11(y) (y).v[1].y1 +#define YUV411_Y12(y) (y).v[2].y1 +#define YUV411_Y13(y) (y).v[3].y1 +#define YUV411_U00(y) ((y).v[0].u0<<6|(y).v[1].u0<<4|(y).v[2].u0<<2|(y).v[3].u0) +#define YUV411_U01(y) YUV411_U00(y) +#define YUV411_U02(y) YUV411_U00(y) +#define YUV411_U03(y) YUV411_U00(y) +#define YUV411_U10(y) ((y).v[0].u1<<6|(y).v[1].u1<<4|(y).v[2].u1<<2|(y).v[3].u1) +#define YUV411_U11(y) YUV411_U10(y) +#define YUV411_U12(y) YUV411_U10(y) +#define YUV411_U13(y) YUV411_U10(y) +#define YUV411_V00(y) ((y).v[0].v0<<6|(y).v[1].v0<<4|(y).v[2].v0<<2|(y).v[3].v0) +#define YUV411_V01(y) YUV411_V00(y) +#define YUV411_V02(y) YUV411_V00(y) +#define YUV411_V03(y) YUV411_V00(y) +#define YUV411_V10(y) ((y).v[0].v1<<6|(y).v[1].v1<<4|(y).v[2].v1<<2|(y).v[3].v1) +#define YUV411_V11(y) YUV411_V10(y) +#define YUV411_V12(y) YUV411_V10(y) +#define YUV411_V13(y) YUV411_V10(y) + +/* + * Compression Library YUV 4:2:2 format. + * + * 1 longword describes 2 pixels. + * + * +-------+ + * | 0 | 1 | + * +-------+ + */ +struct yuv422 { + unsigned int u:8; + unsigned int y0:8; + unsigned int v:8; + unsigned int y1:8; +}; +#define YUV422_Y0(y) (y).y0 +#define YUV422_Y1(y) (y).y1 +#define YUV422_U0(y) (y).u +#define YUV422_U1(y) (y).u +#define YUV422_V0(y) (y).v +#define YUV422_V1(y) (y).v + +/* + * Compression library YUV 4:2:2 Duplicate Chroma format. + * + * This is like the previous format, but the U and V values are + * duplicated vertically (and hence there is some redundancy in the + * data). With other words, lines 2*n and 2*n+1 have the same U and V + * values but different Y values. + */ + +/* + * Conversion functions. + */ +void yuv_sv411_to_cl422dc(int, void *, void *, int, int); +void yuv_sv411_to_cl422dc_quartersize(int, void *, void *, int, int); +void yuv_sv411_to_cl422dc_sixteenthsize(int, void *, void *, int, int); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_YUV_H */ diff --git a/sys/src/cmd/python/Modules/yuvconvert.c b/sys/src/cmd/python/Modules/yuvconvert.c new file mode 100644 index 000000000..e5333d9c3 --- /dev/null +++ b/sys/src/cmd/python/Modules/yuvconvert.c @@ -0,0 +1,118 @@ + +#include "yuv.h" + +void +yuv_sv411_to_cl422dc(int invert, void *data, void *yuv, int width, int height) +{ + struct yuv411 *in = data; + struct yuv422 *out_even = yuv; + struct yuv422 *out_odd = out_even + width / 2; + int i, j; /* counters */ + + for (i = height / 2; i--; ) { + for (j = width / 4; j--; ) { + YUV422_Y0(*out_even) = YUV411_Y00(*in); + YUV422_U0(*out_even) = YUV411_U00(*in); + YUV422_V0(*out_even) = YUV411_V00(*in); + YUV422_Y1(*out_even) = YUV411_Y01(*in); + out_even++; + YUV422_Y0(*out_even) = YUV411_Y02(*in); + YUV422_U0(*out_even) = YUV411_U02(*in); + YUV422_V0(*out_even) = YUV411_V02(*in); + YUV422_Y1(*out_even) = YUV411_Y03(*in); + out_even++; + YUV422_Y0(*out_odd) = YUV411_Y10(*in); + YUV422_U0(*out_odd) = YUV411_U10(*in); + YUV422_V0(*out_odd) = YUV411_V10(*in); + YUV422_Y1(*out_odd) = YUV411_Y11(*in); + out_odd++; + YUV422_Y0(*out_odd) = YUV411_Y12(*in); + YUV422_U0(*out_odd) = YUV411_U12(*in); + YUV422_V0(*out_odd) = YUV411_V12(*in); + YUV422_Y1(*out_odd) = YUV411_Y13(*in); + out_odd++; + in++; + } + out_even += width / 2; + out_odd += width / 2; + } +} + +void +yuv_sv411_to_cl422dc_quartersize(int invert, void *data, void *yuv, + int width, int height) +{ + int w4 = width / 4; /* quarter of width is used often */ + struct yuv411 *in_even = data; + struct yuv411 *in_odd = in_even + w4; + struct yuv422 *out_even = yuv; + struct yuv422 *out_odd = out_even + w4; + int i, j; /* counters */ + int u, v; /* U and V values */ + + for (i = height / 4; i--; ) { + for (j = w4; j--; ) { + u = YUV411_U00(*in_even); + v = YUV411_V00(*in_even); + + YUV422_Y0(*out_even) = YUV411_Y00(*in_even); + YUV422_U0(*out_even) = u; + YUV422_V0(*out_even) = v; + YUV422_Y1(*out_even) = YUV411_Y02(*in_even); + + YUV422_Y0(*out_odd) = YUV411_Y10(*in_odd); + YUV422_U0(*out_odd) = u; + YUV422_V0(*out_odd) = v; + YUV422_Y1(*out_odd) = YUV411_Y12(*in_odd); + + in_even++; + in_odd++; + out_even++; + out_odd++; + } + in_even += w4; + in_odd += w4; + out_even += w4; + out_odd += w4; + } +} + +void +yuv_sv411_to_cl422dc_sixteenthsize(int invert, void *data, void *yuv, + int width, int height) +{ + int w4_3 = 3 * width / 4; /* three quarters of width is used often */ + int w8 = width / 8; /* and so is one eighth */ + struct yuv411 *in_even = data; + struct yuv411 *in_odd = in_even + width / 2; + struct yuv422 *out_even = yuv; + struct yuv422 *out_odd = out_even + w8; + int i, j; /* counters */ + int u, v; /* U and V values */ + + for (i = height / 8; i--; ) { + for (j = w8; j--; ) { + u = YUV411_U00(in_even[0]); + v = YUV411_V00(in_even[0]); + + YUV422_Y0(*out_even) = YUV411_Y00(in_even[0]); + YUV422_U0(*out_even) = u; + YUV422_V0(*out_even) = v; + YUV422_Y1(*out_even) = YUV411_Y00(in_even[1]); + + YUV422_Y0(*out_odd) = YUV411_Y00(in_odd[0]); + YUV422_U0(*out_odd) = u; + YUV422_V0(*out_odd) = v; + YUV422_Y1(*out_odd) = YUV411_Y00(in_even[1]); + + in_even += 2; + in_odd += 2; + out_even++; + out_odd++; + } + in_even += w4_3; + in_odd += w4_3; + out_even += w8; + out_odd += w8; + } +} diff --git a/sys/src/cmd/python/Modules/zipimport.c b/sys/src/cmd/python/Modules/zipimport.c new file mode 100644 index 000000000..69b28813c --- /dev/null +++ b/sys/src/cmd/python/Modules/zipimport.c @@ -0,0 +1,1191 @@ +#include "Python.h" +#include "structmember.h" +#include "osdefs.h" +#include "marshal.h" +#include <time.h> + + +#define IS_SOURCE 0x0 +#define IS_BYTECODE 0x1 +#define IS_PACKAGE 0x2 + +struct st_zip_searchorder { + char suffix[14]; + int type; +}; + +/* zip_searchorder defines how we search for a module in the Zip + archive: we first search for a package __init__, then for + non-package .pyc, .pyo and .py entries. The .pyc and .pyo entries + are swapped by initzipimport() if we run in optimized mode. Also, + '/' is replaced by SEP there. */ +static struct st_zip_searchorder zip_searchorder[] = { + {"/__init__.pyc", IS_PACKAGE | IS_BYTECODE}, + {"/__init__.pyo", IS_PACKAGE | IS_BYTECODE}, + {"/__init__.py", IS_PACKAGE | IS_SOURCE}, + {".pyc", IS_BYTECODE}, + {".pyo", IS_BYTECODE}, + {".py", IS_SOURCE}, + {"", 0} +}; + +/* zipimporter object definition and support */ + +typedef struct _zipimporter ZipImporter; + +struct _zipimporter { + PyObject_HEAD + PyObject *archive; /* pathname of the Zip archive */ + PyObject *prefix; /* file prefix: "a/sub/directory/" */ + PyObject *files; /* dict with file info {path: toc_entry} */ +}; + +static PyObject *ZipImportError; +static PyObject *zip_directory_cache = NULL; + +/* forward decls */ +static PyObject *read_directory(char *archive); +static PyObject *get_data(char *archive, PyObject *toc_entry); +static PyObject *get_module_code(ZipImporter *self, char *fullname, + int *p_ispackage, char **p_modpath); + + +#define ZipImporter_Check(op) PyObject_TypeCheck(op, &ZipImporter_Type) + + +/* zipimporter.__init__ + Split the "subdirectory" from the Zip archive path, lookup a matching + entry in sys.path_importer_cache, fetch the file directory from there + if found, or else read it from the archive. */ +static int +zipimporter_init(ZipImporter *self, PyObject *args, PyObject *kwds) +{ + char *path, *p, *prefix, buf[MAXPATHLEN+2]; + size_t len; + + if (!_PyArg_NoKeywords("zipimporter()", kwds)) + return -1; + + if (!PyArg_ParseTuple(args, "s:zipimporter", + &path)) + return -1; + + len = strlen(path); + if (len == 0) { + PyErr_SetString(ZipImportError, "archive path is empty"); + return -1; + } + if (len >= MAXPATHLEN) { + PyErr_SetString(ZipImportError, + "archive path too long"); + return -1; + } + strcpy(buf, path); + +#ifdef ALTSEP + for (p = buf; *p; p++) { + if (*p == ALTSEP) + *p = SEP; + } +#endif + + path = NULL; + prefix = NULL; + for (;;) { +#ifndef RISCOS + struct stat statbuf; + int rv; + + rv = stat(buf, &statbuf); + if (rv == 0) { + /* it exists */ + if (S_ISREG(statbuf.st_mode)) + /* it's a file */ + path = buf; + break; + } +#else + if (object_exists(buf)) { + /* it exists */ + if (isfile(buf)) + /* it's a file */ + path = buf; + break; + } +#endif + /* back up one path element */ + p = strrchr(buf, SEP); + if (prefix != NULL) + *prefix = SEP; + if (p == NULL) + break; + *p = '\0'; + prefix = p; + } + if (path != NULL) { + PyObject *files; + files = PyDict_GetItemString(zip_directory_cache, path); + if (files == NULL) { + files = read_directory(buf); + if (files == NULL) + return -1; + if (PyDict_SetItemString(zip_directory_cache, path, + files) != 0) + return -1; + } + else + Py_INCREF(files); + self->files = files; + } + else { + PyErr_SetString(ZipImportError, "not a Zip file"); + return -1; + } + + if (prefix == NULL) + prefix = ""; + else { + prefix++; + len = strlen(prefix); + if (prefix[len-1] != SEP) { + /* add trailing SEP */ + prefix[len] = SEP; + prefix[len + 1] = '\0'; + } + } + + self->archive = PyString_FromString(buf); + if (self->archive == NULL) + return -1; + + self->prefix = PyString_FromString(prefix); + if (self->prefix == NULL) + return -1; + + return 0; +} + +/* GC support. */ +static int +zipimporter_traverse(PyObject *obj, visitproc visit, void *arg) +{ + ZipImporter *self = (ZipImporter *)obj; + Py_VISIT(self->files); + return 0; +} + +static void +zipimporter_dealloc(ZipImporter *self) +{ + PyObject_GC_UnTrack(self); + Py_XDECREF(self->archive); + Py_XDECREF(self->prefix); + Py_XDECREF(self->files); + self->ob_type->tp_free((PyObject *)self); +} + +static PyObject * +zipimporter_repr(ZipImporter *self) +{ + char buf[500]; + char *archive = "???"; + char *prefix = ""; + + if (self->archive != NULL && PyString_Check(self->archive)) + archive = PyString_AsString(self->archive); + if (self->prefix != NULL && PyString_Check(self->prefix)) + prefix = PyString_AsString(self->prefix); + if (prefix != NULL && *prefix) + PyOS_snprintf(buf, sizeof(buf), + "<zipimporter object \"%.300s%c%.150s\">", + archive, SEP, prefix); + else + PyOS_snprintf(buf, sizeof(buf), + "<zipimporter object \"%.300s\">", + archive); + return PyString_FromString(buf); +} + +/* return fullname.split(".")[-1] */ +static char * +get_subname(char *fullname) +{ + char *subname = strrchr(fullname, '.'); + if (subname == NULL) + subname = fullname; + else + subname++; + return subname; +} + +/* Given a (sub)modulename, write the potential file path in the + archive (without extension) to the path buffer. Return the + length of the resulting string. */ +static int +make_filename(char *prefix, char *name, char *path) +{ + size_t len; + char *p; + + len = strlen(prefix); + + /* self.prefix + name [+ SEP + "__init__"] + ".py[co]" */ + if (len + strlen(name) + 13 >= MAXPATHLEN) { + PyErr_SetString(ZipImportError, "path too long"); + return -1; + } + + strcpy(path, prefix); + strcpy(path + len, name); + for (p = path + len; *p; p++) { + if (*p == '.') + *p = SEP; + } + len += strlen(name); + assert(len < INT_MAX); + return (int)len; +} + +enum zi_module_info { + MI_ERROR, + MI_NOT_FOUND, + MI_MODULE, + MI_PACKAGE +}; + +/* Return some information about a module. */ +static enum zi_module_info +get_module_info(ZipImporter *self, char *fullname) +{ + char *subname, path[MAXPATHLEN + 1]; + int len; + struct st_zip_searchorder *zso; + + subname = get_subname(fullname); + + len = make_filename(PyString_AsString(self->prefix), subname, path); + if (len < 0) + return MI_ERROR; + + for (zso = zip_searchorder; *zso->suffix; zso++) { + strcpy(path + len, zso->suffix); + if (PyDict_GetItemString(self->files, path) != NULL) { + if (zso->type & IS_PACKAGE) + return MI_PACKAGE; + else + return MI_MODULE; + } + } + return MI_NOT_FOUND; +} + +/* Check whether we can satisfy the import of the module named by + 'fullname'. Return self if we can, None if we can't. */ +static PyObject * +zipimporter_find_module(PyObject *obj, PyObject *args) +{ + ZipImporter *self = (ZipImporter *)obj; + PyObject *path = NULL; + char *fullname; + enum zi_module_info mi; + + if (!PyArg_ParseTuple(args, "s|O:zipimporter.find_module", + &fullname, &path)) + return NULL; + + mi = get_module_info(self, fullname); + if (mi == MI_ERROR) + return NULL; + if (mi == MI_NOT_FOUND) { + Py_INCREF(Py_None); + return Py_None; + } + Py_INCREF(self); + return (PyObject *)self; +} + +/* Load and return the module named by 'fullname'. */ +static PyObject * +zipimporter_load_module(PyObject *obj, PyObject *args) +{ + ZipImporter *self = (ZipImporter *)obj; + PyObject *code, *mod, *dict; + char *fullname, *modpath; + int ispackage; + + if (!PyArg_ParseTuple(args, "s:zipimporter.load_module", + &fullname)) + return NULL; + + code = get_module_code(self, fullname, &ispackage, &modpath); + if (code == NULL) + return NULL; + + mod = PyImport_AddModule(fullname); + if (mod == NULL) { + Py_DECREF(code); + return NULL; + } + dict = PyModule_GetDict(mod); + + /* mod.__loader__ = self */ + if (PyDict_SetItemString(dict, "__loader__", (PyObject *)self) != 0) + goto error; + + if (ispackage) { + /* add __path__ to the module *before* the code gets + executed */ + PyObject *pkgpath, *fullpath; + char *prefix = PyString_AsString(self->prefix); + char *subname = get_subname(fullname); + int err; + + fullpath = PyString_FromFormat("%s%c%s%s", + PyString_AsString(self->archive), + SEP, + *prefix ? prefix : "", + subname); + if (fullpath == NULL) + goto error; + + pkgpath = Py_BuildValue("[O]", fullpath); + Py_DECREF(fullpath); + if (pkgpath == NULL) + goto error; + err = PyDict_SetItemString(dict, "__path__", pkgpath); + Py_DECREF(pkgpath); + if (err != 0) + goto error; + } + mod = PyImport_ExecCodeModuleEx(fullname, code, modpath); + Py_DECREF(code); + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # loaded from Zip %s\n", + fullname, modpath); + return mod; +error: + Py_DECREF(code); + Py_DECREF(mod); + return NULL; +} + +/* Return a bool signifying whether the module is a package or not. */ +static PyObject * +zipimporter_is_package(PyObject *obj, PyObject *args) +{ + ZipImporter *self = (ZipImporter *)obj; + char *fullname; + enum zi_module_info mi; + + if (!PyArg_ParseTuple(args, "s:zipimporter.is_package", + &fullname)) + return NULL; + + mi = get_module_info(self, fullname); + if (mi == MI_ERROR) + return NULL; + if (mi == MI_NOT_FOUND) { + PyErr_Format(ZipImportError, "can't find module '%.200s'", + fullname); + return NULL; + } + return PyBool_FromLong(mi == MI_PACKAGE); +} + +static PyObject * +zipimporter_get_data(PyObject *obj, PyObject *args) +{ + ZipImporter *self = (ZipImporter *)obj; + char *path; +#ifdef ALTSEP + char *p, buf[MAXPATHLEN + 1]; +#endif + PyObject *toc_entry; + Py_ssize_t len; + + if (!PyArg_ParseTuple(args, "s:zipimporter.get_data", &path)) + return NULL; + +#ifdef ALTSEP + if (strlen(path) >= MAXPATHLEN) { + PyErr_SetString(ZipImportError, "path too long"); + return NULL; + } + strcpy(buf, path); + for (p = buf; *p; p++) { + if (*p == ALTSEP) + *p = SEP; + } + path = buf; +#endif + len = PyString_Size(self->archive); + if ((size_t)len < strlen(path) && + strncmp(path, PyString_AsString(self->archive), len) == 0 && + path[len] == SEP) { + path = path + len + 1; + } + + toc_entry = PyDict_GetItemString(self->files, path); + if (toc_entry == NULL) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, path); + return NULL; + } + return get_data(PyString_AsString(self->archive), toc_entry); +} + +static PyObject * +zipimporter_get_code(PyObject *obj, PyObject *args) +{ + ZipImporter *self = (ZipImporter *)obj; + char *fullname; + + if (!PyArg_ParseTuple(args, "s:zipimporter.get_code", &fullname)) + return NULL; + + return get_module_code(self, fullname, NULL, NULL); +} + +static PyObject * +zipimporter_get_source(PyObject *obj, PyObject *args) +{ + ZipImporter *self = (ZipImporter *)obj; + PyObject *toc_entry; + char *fullname, *subname, path[MAXPATHLEN+1]; + int len; + enum zi_module_info mi; + + if (!PyArg_ParseTuple(args, "s:zipimporter.get_source", &fullname)) + return NULL; + + mi = get_module_info(self, fullname); + if (mi == MI_ERROR) + return NULL; + if (mi == MI_NOT_FOUND) { + PyErr_Format(ZipImportError, "can't find module '%.200s'", + fullname); + return NULL; + } + subname = get_subname(fullname); + + len = make_filename(PyString_AsString(self->prefix), subname, path); + if (len < 0) + return NULL; + + if (mi == MI_PACKAGE) { + path[len] = SEP; + strcpy(path + len + 1, "__init__.py"); + } + else + strcpy(path + len, ".py"); + + toc_entry = PyDict_GetItemString(self->files, path); + if (toc_entry != NULL) + return get_data(PyString_AsString(self->archive), toc_entry); + + /* we have the module, but no source */ + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(doc_find_module, +"find_module(fullname, path=None) -> self or None.\n\ +\n\ +Search for a module specified by 'fullname'. 'fullname' must be the\n\ +fully qualified (dotted) module name. It returns the zipimporter\n\ +instance itself if the module was found, or None if it wasn't.\n\ +The optional 'path' argument is ignored -- it's there for compatibility\n\ +with the importer protocol."); + +PyDoc_STRVAR(doc_load_module, +"load_module(fullname) -> module.\n\ +\n\ +Load the module specified by 'fullname'. 'fullname' must be the\n\ +fully qualified (dotted) module name. It returns the imported\n\ +module, or raises ZipImportError if it wasn't found."); + +PyDoc_STRVAR(doc_get_data, +"get_data(pathname) -> string with file data.\n\ +\n\ +Return the data associated with 'pathname'. Raise IOError if\n\ +the file wasn't found."); + +PyDoc_STRVAR(doc_is_package, +"is_package(fullname) -> bool.\n\ +\n\ +Return True if the module specified by fullname is a package.\n\ +Raise ZipImportError is the module couldn't be found."); + +PyDoc_STRVAR(doc_get_code, +"get_code(fullname) -> code object.\n\ +\n\ +Return the code object for the specified module. Raise ZipImportError\n\ +is the module couldn't be found."); + +PyDoc_STRVAR(doc_get_source, +"get_source(fullname) -> source string.\n\ +\n\ +Return the source code for the specified module. Raise ZipImportError\n\ +is the module couldn't be found, return None if the archive does\n\ +contain the module, but has no source for it."); + +static PyMethodDef zipimporter_methods[] = { + {"find_module", zipimporter_find_module, METH_VARARGS, + doc_find_module}, + {"load_module", zipimporter_load_module, METH_VARARGS, + doc_load_module}, + {"get_data", zipimporter_get_data, METH_VARARGS, + doc_get_data}, + {"get_code", zipimporter_get_code, METH_VARARGS, + doc_get_code}, + {"get_source", zipimporter_get_source, METH_VARARGS, + doc_get_source}, + {"is_package", zipimporter_is_package, METH_VARARGS, + doc_is_package}, + {NULL, NULL} /* sentinel */ +}; + +static PyMemberDef zipimporter_members[] = { + {"archive", T_OBJECT, offsetof(ZipImporter, archive), READONLY}, + {"prefix", T_OBJECT, offsetof(ZipImporter, prefix), READONLY}, + {"_files", T_OBJECT, offsetof(ZipImporter, files), READONLY}, + {NULL} +}; + +PyDoc_STRVAR(zipimporter_doc, +"zipimporter(archivepath) -> zipimporter object\n\ +\n\ +Create a new zipimporter instance. 'archivepath' must be a path to\n\ +a zipfile. ZipImportError is raised if 'archivepath' doesn't point to\n\ +a valid Zip archive."); + +#define DEFERRED_ADDRESS(ADDR) 0 + +static PyTypeObject ZipImporter_Type = { + PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type)) + 0, + "zipimport.zipimporter", + sizeof(ZipImporter), + 0, /* tp_itemsize */ + (destructor)zipimporter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)zipimporter_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC, /* tp_flags */ + zipimporter_doc, /* tp_doc */ + zipimporter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + zipimporter_methods, /* tp_methods */ + zipimporter_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)zipimporter_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/* implementation */ + +/* Given a buffer, return the long that is represented by the first + 4 bytes, encoded as little endian. This partially reimplements + marshal.c:r_long() */ +static long +get_long(unsigned char *buf) { + long x; + x = buf[0]; + x |= (long)buf[1] << 8; + x |= (long)buf[2] << 16; + x |= (long)buf[3] << 24; +#if SIZEOF_LONG > 4 + /* Sign extension for 64-bit machines */ + x |= -(x & 0x80000000L); +#endif + return x; +} + +/* + read_directory(archive) -> files dict (new reference) + + Given a path to a Zip archive, build a dict, mapping file names + (local to the archive, using SEP as a separator) to toc entries. + + A toc_entry is a tuple: + + (__file__, # value to use for __file__, available for all files + compress, # compression kind; 0 for uncompressed + data_size, # size of compressed data on disk + file_size, # size of decompressed data + file_offset, # offset of file header from start of archive + time, # mod time of file (in dos format) + date, # mod data of file (in dos format) + crc, # crc checksum of the data + ) + + Directories can be recognized by the trailing SEP in the name, + data_size and file_offset are 0. +*/ +static PyObject * +read_directory(char *archive) +{ + PyObject *files = NULL; + FILE *fp; + long compress, crc, data_size, file_size, file_offset, date, time; + long header_offset, name_size, header_size, header_position; + long i, l, count; + size_t length; + char path[MAXPATHLEN + 5]; + char name[MAXPATHLEN + 5]; + char *p, endof_central_dir[22]; + long arc_offset; /* offset from beginning of file to start of zip-archive */ + + if (strlen(archive) > MAXPATHLEN) { + PyErr_SetString(PyExc_OverflowError, + "Zip path name is too long"); + return NULL; + } + strcpy(path, archive); + + fp = fopen(archive, "rb"); + if (fp == NULL) { + PyErr_Format(ZipImportError, "can't open Zip file: " + "'%.200s'", archive); + return NULL; + } + fseek(fp, -22, SEEK_END); + header_position = ftell(fp); + if (fread(endof_central_dir, 1, 22, fp) != 22) { + fclose(fp); + PyErr_Format(ZipImportError, "can't read Zip file: " + "'%.200s'", archive); + return NULL; + } + if (get_long((unsigned char *)endof_central_dir) != 0x06054B50) { + /* Bad: End of Central Dir signature */ + fclose(fp); + PyErr_Format(ZipImportError, "not a Zip file: " + "'%.200s'", archive); + return NULL; + } + + header_size = get_long((unsigned char *)endof_central_dir + 12); + header_offset = get_long((unsigned char *)endof_central_dir + 16); + arc_offset = header_position - header_offset - header_size; + header_offset += arc_offset; + + files = PyDict_New(); + if (files == NULL) + goto error; + + length = (long)strlen(path); + path[length] = SEP; + + /* Start of Central Directory */ + count = 0; + for (;;) { + PyObject *t; + int err; + + fseek(fp, header_offset, 0); /* Start of file header */ + l = PyMarshal_ReadLongFromFile(fp); + if (l != 0x02014B50) + break; /* Bad: Central Dir File Header */ + fseek(fp, header_offset + 10, 0); + compress = PyMarshal_ReadShortFromFile(fp); + time = PyMarshal_ReadShortFromFile(fp); + date = PyMarshal_ReadShortFromFile(fp); + crc = PyMarshal_ReadLongFromFile(fp); + data_size = PyMarshal_ReadLongFromFile(fp); + file_size = PyMarshal_ReadLongFromFile(fp); + name_size = PyMarshal_ReadShortFromFile(fp); + header_size = 46 + name_size + + PyMarshal_ReadShortFromFile(fp) + + PyMarshal_ReadShortFromFile(fp); + fseek(fp, header_offset + 42, 0); + file_offset = PyMarshal_ReadLongFromFile(fp) + arc_offset; + if (name_size > MAXPATHLEN) + name_size = MAXPATHLEN; + + p = name; + for (i = 0; i < name_size; i++) { + *p = (char)getc(fp); + if (*p == '/') + *p = SEP; + p++; + } + *p = 0; /* Add terminating null byte */ + header_offset += header_size; + + strncpy(path + length + 1, name, MAXPATHLEN - length - 1); + + t = Py_BuildValue("siiiiiii", path, compress, data_size, + file_size, file_offset, time, date, crc); + if (t == NULL) + goto error; + err = PyDict_SetItemString(files, name, t); + Py_DECREF(t); + if (err != 0) + goto error; + count++; + } + fclose(fp); + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport: found %ld names in %s\n", + count, archive); + return files; +error: + fclose(fp); + Py_XDECREF(files); + return NULL; +} + +/* Return the zlib.decompress function object, or NULL if zlib couldn't + be imported. The function is cached when found, so subsequent calls + don't import zlib again. Returns a *borrowed* reference. + XXX This makes zlib.decompress immortal. */ +static PyObject * +get_decompress_func(void) +{ + static PyObject *decompress = NULL; + + if (decompress == NULL) { + PyObject *zlib; + static int importing_zlib = 0; + + if (importing_zlib != 0) + /* Someone has a zlib.py[co] in their Zip file; + let's avoid a stack overflow. */ + return NULL; + importing_zlib = 1; + zlib = PyImport_ImportModule("zlib"); /* import zlib */ + importing_zlib = 0; + if (zlib != NULL) { + decompress = PyObject_GetAttrString(zlib, + "decompress"); + Py_DECREF(zlib); + } + else + PyErr_Clear(); + if (Py_VerboseFlag) + PySys_WriteStderr("# zipimport: zlib %s\n", + zlib != NULL ? "available": "UNAVAILABLE"); + } + return decompress; +} + +/* Given a path to a Zip file and a toc_entry, return the (uncompressed) + data as a new reference. */ +static PyObject * +get_data(char *archive, PyObject *toc_entry) +{ + PyObject *raw_data, *data = NULL, *decompress; + char *buf; + FILE *fp; + int err; + Py_ssize_t bytes_read = 0; + long l; + char *datapath; + long compress, data_size, file_size, file_offset; + long time, date, crc; + + if (!PyArg_ParseTuple(toc_entry, "slllllll", &datapath, &compress, + &data_size, &file_size, &file_offset, &time, + &date, &crc)) { + return NULL; + } + + fp = fopen(archive, "rb"); + if (!fp) { + PyErr_Format(PyExc_IOError, + "zipimport: can not open file %s", archive); + return NULL; + } + + /* Check to make sure the local file header is correct */ + fseek(fp, file_offset, 0); + l = PyMarshal_ReadLongFromFile(fp); + if (l != 0x04034B50) { + /* Bad: Local File Header */ + PyErr_Format(ZipImportError, + "bad local file header in %s", + archive); + fclose(fp); + return NULL; + } + fseek(fp, file_offset + 26, 0); + l = 30 + PyMarshal_ReadShortFromFile(fp) + + PyMarshal_ReadShortFromFile(fp); /* local header size */ + file_offset += l; /* Start of file data */ + + raw_data = PyString_FromStringAndSize((char *)NULL, compress == 0 ? + data_size : data_size + 1); + if (raw_data == NULL) { + fclose(fp); + return NULL; + } + buf = PyString_AsString(raw_data); + + err = fseek(fp, file_offset, 0); + if (err == 0) + bytes_read = fread(buf, 1, data_size, fp); + fclose(fp); + if (err || bytes_read != data_size) { + PyErr_SetString(PyExc_IOError, + "zipimport: can't read data"); + Py_DECREF(raw_data); + return NULL; + } + + if (compress != 0) { + buf[data_size] = 'Z'; /* saw this in zipfile.py */ + data_size++; + } + buf[data_size] = '\0'; + + if (compress == 0) /* data is not compressed */ + return raw_data; + + /* Decompress with zlib */ + decompress = get_decompress_func(); + if (decompress == NULL) { + PyErr_SetString(ZipImportError, + "can't decompress data; " + "zlib not available"); + goto error; + } + data = PyObject_CallFunction(decompress, "Oi", raw_data, -15); +error: + Py_DECREF(raw_data); + return data; +} + +/* Lenient date/time comparison function. The precision of the mtime + in the archive is lower than the mtime stored in a .pyc: we + must allow a difference of at most one second. */ +static int +eq_mtime(time_t t1, time_t t2) +{ + time_t d = t1 - t2; + if (d < 0) + d = -d; + /* dostime only stores even seconds, so be lenient */ + return d <= 1; +} + +/* Given the contents of a .py[co] file in a buffer, unmarshal the data + and return the code object. Return None if it the magic word doesn't + match (we do this instead of raising an exception as we fall back + to .py if available and we don't want to mask other errors). + Returns a new reference. */ +static PyObject * +unmarshal_code(char *pathname, PyObject *data, time_t mtime) +{ + PyObject *code; + char *buf = PyString_AsString(data); + Py_ssize_t size = PyString_Size(data); + + if (size <= 9) { + PyErr_SetString(ZipImportError, + "bad pyc data"); + return NULL; + } + + if (get_long((unsigned char *)buf) != PyImport_GetMagicNumber()) { + if (Py_VerboseFlag) + PySys_WriteStderr("# %s has bad magic\n", + pathname); + Py_INCREF(Py_None); + return Py_None; /* signal caller to try alternative */ + } + + if (mtime != 0 && !eq_mtime(get_long((unsigned char *)buf + 4), + mtime)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# %s has bad mtime\n", + pathname); + Py_INCREF(Py_None); + return Py_None; /* signal caller to try alternative */ + } + + code = PyMarshal_ReadObjectFromString(buf + 8, size - 8); + if (code == NULL) + return NULL; + if (!PyCode_Check(code)) { + Py_DECREF(code); + PyErr_Format(PyExc_TypeError, + "compiled module %.200s is not a code object", + pathname); + return NULL; + } + return code; +} + +/* Replace any occurances of "\r\n?" in the input string with "\n". + This converts DOS and Mac line endings to Unix line endings. + Also append a trailing "\n" to be compatible with + PyParser_SimpleParseFile(). Returns a new reference. */ +static PyObject * +normalize_line_endings(PyObject *source) +{ + char *buf, *q, *p = PyString_AsString(source); + PyObject *fixed_source; + + if (!p) + return NULL; + + /* one char extra for trailing \n and one for terminating \0 */ + buf = (char *)PyMem_Malloc(PyString_Size(source) + 2); + if (buf == NULL) { + PyErr_SetString(PyExc_MemoryError, + "zipimport: no memory to allocate " + "source buffer"); + return NULL; + } + /* replace "\r\n?" by "\n" */ + for (q = buf; *p != '\0'; p++) { + if (*p == '\r') { + *q++ = '\n'; + if (*(p + 1) == '\n') + p++; + } + else + *q++ = *p; + } + *q++ = '\n'; /* add trailing \n */ + *q = '\0'; + fixed_source = PyString_FromString(buf); + PyMem_Free(buf); + return fixed_source; +} + +/* Given a string buffer containing Python source code, compile it + return and return a code object as a new reference. */ +static PyObject * +compile_source(char *pathname, PyObject *source) +{ + PyObject *code, *fixed_source; + + fixed_source = normalize_line_endings(source); + if (fixed_source == NULL) + return NULL; + + code = Py_CompileString(PyString_AsString(fixed_source), pathname, + Py_file_input); + Py_DECREF(fixed_source); + return code; +} + +/* Convert the date/time values found in the Zip archive to a value + that's compatible with the time stamp stored in .pyc files. */ +static time_t +parse_dostime(int dostime, int dosdate) +{ + struct tm stm; + + stm.tm_sec = (dostime & 0x1f) * 2; + stm.tm_min = (dostime >> 5) & 0x3f; + stm.tm_hour = (dostime >> 11) & 0x1f; + stm.tm_mday = dosdate & 0x1f; + stm.tm_mon = ((dosdate >> 5) & 0x0f) - 1; + stm.tm_year = ((dosdate >> 9) & 0x7f) + 80; + stm.tm_isdst = -1; /* wday/yday is ignored */ + + return mktime(&stm); +} + +/* Given a path to a .pyc or .pyo file in the archive, return the + modifictaion time of the matching .py file, or 0 if no source + is available. */ +static time_t +get_mtime_of_source(ZipImporter *self, char *path) +{ + PyObject *toc_entry; + time_t mtime = 0; + Py_ssize_t lastchar = strlen(path) - 1; + char savechar = path[lastchar]; + path[lastchar] = '\0'; /* strip 'c' or 'o' from *.py[co] */ + toc_entry = PyDict_GetItemString(self->files, path); + if (toc_entry != NULL && PyTuple_Check(toc_entry) && + PyTuple_Size(toc_entry) == 8) { + /* fetch the time stamp of the .py file for comparison + with an embedded pyc time stamp */ + int time, date; + time = PyInt_AsLong(PyTuple_GetItem(toc_entry, 5)); + date = PyInt_AsLong(PyTuple_GetItem(toc_entry, 6)); + mtime = parse_dostime(time, date); + } + path[lastchar] = savechar; + return mtime; +} + +/* Return the code object for the module named by 'fullname' from the + Zip archive as a new reference. */ +static PyObject * +get_code_from_data(ZipImporter *self, int ispackage, int isbytecode, + time_t mtime, PyObject *toc_entry) +{ + PyObject *data, *code; + char *modpath; + char *archive = PyString_AsString(self->archive); + + if (archive == NULL) + return NULL; + + data = get_data(archive, toc_entry); + if (data == NULL) + return NULL; + + modpath = PyString_AsString(PyTuple_GetItem(toc_entry, 0)); + + if (isbytecode) { + code = unmarshal_code(modpath, data, mtime); + } + else { + code = compile_source(modpath, data); + } + Py_DECREF(data); + return code; +} + +/* Get the code object assoiciated with the module specified by + 'fullname'. */ +static PyObject * +get_module_code(ZipImporter *self, char *fullname, + int *p_ispackage, char **p_modpath) +{ + PyObject *toc_entry; + char *subname, path[MAXPATHLEN + 1]; + int len; + struct st_zip_searchorder *zso; + + subname = get_subname(fullname); + + len = make_filename(PyString_AsString(self->prefix), subname, path); + if (len < 0) + return NULL; + + for (zso = zip_searchorder; *zso->suffix; zso++) { + PyObject *code = NULL; + + strcpy(path + len, zso->suffix); + if (Py_VerboseFlag > 1) + PySys_WriteStderr("# trying %s%c%s\n", + PyString_AsString(self->archive), + SEP, path); + toc_entry = PyDict_GetItemString(self->files, path); + if (toc_entry != NULL) { + time_t mtime = 0; + int ispackage = zso->type & IS_PACKAGE; + int isbytecode = zso->type & IS_BYTECODE; + + if (isbytecode) + mtime = get_mtime_of_source(self, path); + if (p_ispackage != NULL) + *p_ispackage = ispackage; + code = get_code_from_data(self, ispackage, + isbytecode, mtime, + toc_entry); + if (code == Py_None) { + /* bad magic number or non-matching mtime + in byte code, try next */ + Py_DECREF(code); + continue; + } + if (code != NULL && p_modpath != NULL) + *p_modpath = PyString_AsString( + PyTuple_GetItem(toc_entry, 0)); + return code; + } + } + PyErr_Format(ZipImportError, "can't find module '%.200s'", fullname); + return NULL; +} + + +/* Module init */ + +PyDoc_STRVAR(zipimport_doc, +"zipimport provides support for importing Python modules from Zip archives.\n\ +\n\ +This module exports three objects:\n\ +- zipimporter: a class; its constructor takes a path to a Zip archive.\n\ +- ZipImportError: exception raised by zipimporter objects. It's a\n\ + subclass of ImportError, so it can be caught as ImportError, too.\n\ +- _zip_directory_cache: a dict, mapping archive paths to zip directory\n\ + info dicts, as used in zipimporter._files.\n\ +\n\ +It is usually not needed to use the zipimport module explicitly; it is\n\ +used by the builtin import mechanism for sys.path items that are paths\n\ +to Zip archives."); + +PyMODINIT_FUNC +initzipimport(void) +{ + PyObject *mod; + + if (PyType_Ready(&ZipImporter_Type) < 0) + return; + + /* Correct directory separator */ + zip_searchorder[0].suffix[0] = SEP; + zip_searchorder[1].suffix[0] = SEP; + zip_searchorder[2].suffix[0] = SEP; + if (Py_OptimizeFlag) { + /* Reverse *.pyc and *.pyo */ + struct st_zip_searchorder tmp; + tmp = zip_searchorder[0]; + zip_searchorder[0] = zip_searchorder[1]; + zip_searchorder[1] = tmp; + tmp = zip_searchorder[3]; + zip_searchorder[3] = zip_searchorder[4]; + zip_searchorder[4] = tmp; + } + + mod = Py_InitModule4("zipimport", NULL, zipimport_doc, + NULL, PYTHON_API_VERSION); + if (mod == NULL) + return; + + ZipImportError = PyErr_NewException("zipimport.ZipImportError", + PyExc_ImportError, NULL); + if (ZipImportError == NULL) + return; + + Py_INCREF(ZipImportError); + if (PyModule_AddObject(mod, "ZipImportError", + ZipImportError) < 0) + return; + + Py_INCREF(&ZipImporter_Type); + if (PyModule_AddObject(mod, "zipimporter", + (PyObject *)&ZipImporter_Type) < 0) + return; + + zip_directory_cache = PyDict_New(); + if (zip_directory_cache == NULL) + return; + Py_INCREF(zip_directory_cache); + if (PyModule_AddObject(mod, "_zip_directory_cache", + zip_directory_cache) < 0) + return; +} diff --git a/sys/src/cmd/python/Modules/zlib/ChangeLog b/sys/src/cmd/python/Modules/zlib/ChangeLog new file mode 100644 index 000000000..7f6869d32 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/ChangeLog @@ -0,0 +1,855 @@ + + ChangeLog file for zlib + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Added zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard <memory.h> in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant <info@winimage.com> + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu> + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no> + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es> + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl> + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/sys/src/cmd/python/Modules/zlib/FAQ b/sys/src/cmd/python/Modules/zlib/FAQ new file mode 100644 index 000000000..441d910da --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/FAQ @@ -0,0 +1,339 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://www.zlib.org which may have more recent information. +The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. + See the file win32/DLL_FAQ.txt in the zlib distribution. + Pointers to the precompiled DLL are found in the zlib web site at + http://www.zlib.org. + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://www.dogma.net/markn/articles/zlibtool/zlibtool.htm + * contrib/visual-basic.txt in the zlib distribution + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress, the length of the compressed + buffer is equal to the total size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not + zero. When setting the parameter flush equal to Z_FINISH, also make sure + that avail_out is big enough to allow processing all pending input. + Note that a Z_BUF_ERROR is not fatal--another call to deflate() or + inflate() can be made with more input or output space. A Z_BUF_ERROR + may in fact be unavoidable depending on how the functions are used, since + it is not possible to tell whether or not there is more output pending + when strm.avail_out returns with zero. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h for the moment, and Francis S. Lin has converted it to a + web page zlib.html. Volunteers to transform this to Unix-style man pages, + please contact us (zlib@gzip.org). Examples of zlib usage are in the files + example.c and minigzip.c. + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple + package. zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of + zlib. Please try to reproduce the problem with a small program and send + the corresponding source to us at zlib@gzip.org . Do not send + multi-megabyte data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + make clean + ./configure -s + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include <zlib.h>, it's there. The -lz option will probably link to it. + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.fastio.com/ (ClibPDF), or http://www.pdflib.com/ . + To modify PDF forms, see http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip + formats use the same compressed data format internally, but have different + headers and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about + a single file, such as the name and last modification date. The zlib + format on the other hand was designed for in-memory and communication + channel applications, and has a much more compact header and trailer and + uses a faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode + the gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's Init functions allow + for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + It should. It has been tested on 64-bit machines, and has no dependence + on any data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format + than does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically + use Z_FULL_FLUSH, carefully write all the pending data at those points, + and keep an index of those locations, then you can start decompression + at those points. You have to be careful to not use Z_FULL_FLUSH too + often, since it can significantly degrade compression. + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + We don't know for sure. We have heard occasional reports of success on + these systems. If you do use it on one of these, please provide us with + a report, instructions, and patches that we can reference when we get + these questions. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at + to understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit + only if the compiler's "long" type is 32 bits. If the compiler's "long" + type is 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib + is compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of a 4K string space, other than the caller of + gzprintf() assuring that the output will not exceed 4K. On the other + hand, if zlib is compiled to use snprintf() or vsnprintf(), which should + normally be the case, then there is no vulnerability. The ./configure + script will display warnings if an insecure variation of sprintf() will + be used by gzprintf(). Also the zlibCompileFlags() function will return + information on what variant of sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://www.zlib.org/ + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly. So now, we simply make sure that the code always + works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of + deflate is not affected. This only started showing up recently since + zlib 1.2.x uses malloc() by default for allocations, whereas earlier + versions used calloc(), which zeros out the allocated memory. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very weak + and can be broken with freely available programs. To get strong encryption, + use GnuPG, http://www.gnupg.org/ , which already includes zlib compression. + For PKZIP compatible "encryption", look at http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion + with the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specficiation in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. + In any case, the compression improvements are so modest compared to other + more modern approaches, that it's not worth the effort to implement. + +41. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/sys/src/cmd/python/Modules/zlib/INDEX b/sys/src/cmd/python/Modules/zlib/INDEX new file mode 100644 index 000000000..0587e5902 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/INDEX @@ -0,0 +1,51 @@ +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile makefile for Unix (generated by configure) +Makefile.in makefile for Unix (template for configure) +README guess what +algorithm.txt description of the (de)compression algorithm +configure configure script for Unix +zconf.in.h template for zconf.h (used by configure) + +amiga/ makefiles for Amiga SAS C +as400/ makefiles for IBM AS/400 +msdos/ makefiles for MSDOS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +projects/ projects for various Integrated Development Environments +qnx/ makefiles for QNX +win32/ makefiles for Windows + + zlib public header files (must be kept): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzio.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs: +example.c +minigzip.c + + unsupported contribution by third parties +See contrib/README.contrib diff --git a/sys/src/cmd/python/Modules/zlib/Makefile b/sys/src/cmd/python/Modules/zlib/Makefile new file mode 100644 index 000000000..2fd6e45c4 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/Makefile @@ -0,0 +1,154 @@ +# Makefile for zlib +# Copyright (C) 1995-2005 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +LIBS=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.3 +SHAREDLIBM=libz.so.1 + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example$(EXE) minigzip$(EXE) + +check: test +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIBV): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + +example$(EXE): example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip$(EXE): minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi + -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi + -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIB) $(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(SHAREDLIBM); \ + (ldconfig || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(man3dir) + chmod 644 $(man3dir)/zlib.3 +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(man3dir); rm -f zlib.3 + +mostlyclean: clean +clean: + rm -f *.o *~ example$(EXE) minigzip$(EXE) \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + +maintainer-clean: distclean +distclean: clean + cp -p Makefile.in Makefile + cp -p zconf.in.h zconf.h + rm -f .DS_Store + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/sys/src/cmd/python/Modules/zlib/Makefile.in b/sys/src/cmd/python/Modules/zlib/Makefile.in new file mode 100644 index 000000000..2fd6e45c4 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/Makefile.in @@ -0,0 +1,154 @@ +# Makefile for zlib +# Copyright (C) 1995-2005 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# The call of configure is optional if you don't have special requirements +# If you wish to build zlib as a shared library, use: ./configure -s + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +LDFLAGS=libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +LIBS=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.3 +SHAREDLIBM=libz.so.1 + +AR=ar rc +RANLIB=ranlib +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example$(EXE) minigzip$(EXE) + +check: test +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +$(SHAREDLIBV): $(OBJS) + $(LDSHARED) -o $@ $(OBJS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + +example$(EXE): example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip$(EXE): minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +install: $(LIBS) + -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi + -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi + -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi + -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi + cp zlib.h zconf.h $(includedir) + chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h + cp $(LIBS) $(libdir) + cd $(libdir); chmod 755 $(LIBS) + -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1 + cd $(libdir); if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIB) $(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(SHAREDLIBM); \ + (ldconfig || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(man3dir) + chmod 644 $(man3dir)/zlib.3 +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +uninstall: + cd $(includedir); \ + cd $(libdir); rm -f libz.a; \ + if test -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(man3dir); rm -f zlib.3 + +mostlyclean: clean +clean: + rm -f *.o *~ example$(EXE) minigzip$(EXE) \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + +maintainer-clean: distclean +distclean: clean + cp -p Makefile.in Makefile + cp -p zconf.in.h zconf.h + rm -f .DS_Store + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/sys/src/cmd/python/Modules/zlib/README b/sys/src/cmd/python/Modules/zlib/README new file mode 100644 index 000000000..758cc5002 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/README @@ -0,0 +1,125 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.3 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). These documents are also available in other +formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file example.c which also tests that the library +is working correctly. Another example is given in the file minigzip.c. The +compression library itself is composed of all source files except example.c and +minigzip.c. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile. In short "make test; make install" should work for most +machines. For Unix: "./configure; make test; make install". For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use make_vms.com. + +Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant +<info@winimage.com> for the Windows DLL version. The zlib home page is +http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem, +please check this site to verify that you have the latest version of zlib; +otherwise get the latest version and check whether the problem still exists or +not. + +PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking +for help. + +Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available in +http://dogma.net/markn/articles/zlibtool/zlibtool.htm + +The changes made in version 1.2.3 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory "contrib". + +A Java implementation of zlib is available in the Java Development Kit +http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html +See the zlib home page http://www.zlib.org for details. + +A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the +CPAN (Comprehensive Perl Archive Network) sites +http://www.cpan.org/modules/by-module/Compress/ + +A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is +available in Python 1.5 and later versions, see +http://www.python.org/doc/lib/module-zlib.html + +A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is +availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant <info@winimage.com>, is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + +- When building a shared, i.e. dynamic library on Mac OS X, the library must be + installed before testing (do "make install" before "make test"), since the + library location is specified in the library. + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-2004 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. Please +read the FAQ for more information on the distribution of modified source +versions. diff --git a/sys/src/cmd/python/Modules/zlib/adler32.c b/sys/src/cmd/python/Modules/zlib/adler32.c new file mode 100644 index 000000000..007ba2627 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/adler32.c @@ -0,0 +1,149 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +#define BASE 65521UL /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware */ +#ifdef NO_DIVIDE +# define MOD(a) \ + do { \ + if (a >= (BASE << 16)) a -= (BASE << 16); \ + if (a >= (BASE << 15)) a -= (BASE << 15); \ + if (a >= (BASE << 14)) a -= (BASE << 14); \ + if (a >= (BASE << 13)) a -= (BASE << 13); \ + if (a >= (BASE << 12)) a -= (BASE << 12); \ + if (a >= (BASE << 11)) a -= (BASE << 11); \ + if (a >= (BASE << 10)) a -= (BASE << 10); \ + if (a >= (BASE << 9)) a -= (BASE << 9); \ + if (a >= (BASE << 8)) a -= (BASE << 8); \ + if (a >= (BASE << 7)) a -= (BASE << 7); \ + if (a >= (BASE << 6)) a -= (BASE << 6); \ + if (a >= (BASE << 5)) a -= (BASE << 5); \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD4(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} diff --git a/sys/src/cmd/python/Modules/zlib/algorithm.txt b/sys/src/cmd/python/Modules/zlib/algorithm.txt new file mode 100644 index 000000000..b022dde31 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend two much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +http://www.ietf.org/rfc/rfc1951.txt diff --git a/sys/src/cmd/python/Modules/zlib/compress.c b/sys/src/cmd/python/Modules/zlib/compress.c new file mode 100644 index 000000000..df04f0148 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/compress.c @@ -0,0 +1,79 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ +int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; + int level; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11; +} diff --git a/sys/src/cmd/python/Modules/zlib/configure b/sys/src/cmd/python/Modules/zlib/configure new file mode 100755 index 000000000..d7ffdc345 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/configure @@ -0,0 +1,459 @@ +#!/bin/sh +# configure script for zlib. This script is needed only if +# you wish to build a shared library and your system supports them, +# of if you need special compiler, flags or install directory. +# Otherwise, you can just use directly "make test; make install" +# +# To create a shared library, use "configure --shared"; by default a static +# library is created. If the primitive shared library support provided here +# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) +# LDSHARED is the command to be used to create a shared library + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +LIBS=libz.a +LDFLAGS="-L. ${LIBS}" +VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h` +VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h` +VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h` +AR=${AR-"ar rc"} +RANLIB=${RANLIB-"ranlib"} +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +libdir=${libdir-'${exec_prefix}/lib'} +includedir=${includedir-'${prefix}/include'} +mandir=${mandir-'${prefix}/share/man'} +shared_ext='.so' +shared=0 +gcc=0 +old_cc="$CC" +old_cflags="$CFLAGS" + +while test $# -ge 1 +do +case "$1" in + -h* | --h*) + echo 'usage:' + echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]' + echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]' + exit 0;; + -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;; + -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;; + -p* | --p*) prefix="$2"; shift; shift;; + -e* | --e*) exec_prefix="$2"; shift; shift;; + -l* | --l*) libdir="$2"; shift; shift;; + -i* | --i*) includedir="$2"; shift; shift;; + -s* | --s*) shared=1; shift;; + *) echo "unknown option: $1"; echo "$0 --help for help"; exit 1;; + esac +done + +test=ztest$$ +cat > $test.c <<EOF +extern int getchar(); +int hello() {return getchar();} +EOF + +test -z "$CC" && echo Checking for gcc... +cc=${CC-gcc} +cflags=${CFLAGS-"-O3"} +# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure +case "$cc" in + *gcc*) gcc=1;; +esac + +if test "$gcc" -eq 1 && ($cc -c $cflags $test.c) 2>/dev/null; then + CC="$cc" + SFLAGS=${CFLAGS-"-fPIC -O3"} + CFLAGS="$cflags" + case `(uname -s || echo unknown) 2>/dev/null` in + Linux | linux | GNU | GNU/*) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1"};; + CYGWIN* | Cygwin* | cygwin* | OS/2* ) + EXE='.exe';; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"};; + HP-UX*) + LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so';; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl';; + esac;; + Darwin*) shared_ext='.dylib' + SHAREDLIB=libz$shared_ext + SHAREDLIBV=libz.$VER$shared_ext + SHAREDLIBM=libz.$VER1$shared_ext + LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER"};; + *) LDSHARED=${LDSHARED-"$cc -shared"};; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + case `(uname -sr || echo unknown) 2>/dev/null` in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} +# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"} + LDSHARED=${LDSHARED-"ld -b"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so';; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl';; + esac;; + IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."} + CFLAGS=${CFLAGS-"-ansi -O2"} + LDSHARED=${LDSHARED-"cc -shared"};; + OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};; + OSF1*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared"};; + QNX*) SFLAGS=${CFLAGS-"-4 -O"} + CFLAGS=${CFLAGS-"-4 -O"} + LDSHARED=${LDSHARED-"cc"} + RANLIB=${RANLIB-"true"} + AR="cc -A";; + SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "} + CFLAGS=${CFLAGS-"-O3"} + LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};; + SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."} + CFLAGS=${CFLAGS-"-fast -xcg89"} + LDSHARED=${LDSHARED-"cc -G"};; + SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"} + CFLAGS=${CFLAGS-"-O2"} + LDSHARED=${LDSHARED-"ld"};; + SunStudio\ 9*) SFLAGS=${CFLAGS-"-DUSE_MMAP -fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"} + CFLAGS=${CFLAGS-"-DUSE_MMAP -fast -xtarget=ultra3 -xarch=v9b"} + LDSHARED=${LDSHARED-"cc -xarch=v9b"};; + UNIX_System_V\ 4.2.0) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + UNIX_SV\ 4.2MP) + SFLAGS=${CFLAGS-"-Kconform_pic -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + OpenUNIX\ 5) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"};; + AIX*) # Courtesy of dbakker@arrayasolutions.com + SFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + CFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + LDSHARED=${LDSHARED-"xlc -G"};; + # send working options for other systems to support@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -shared"};; + esac +fi + +SHAREDLIB=${SHAREDLIB-"libz$shared_ext"} +SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"} +SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"} + +if test $shared -eq 1; then + echo Checking for shared library support... + # we must test in two steps (cc then ld), required at least on SunOS 4.x + if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" && + test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then + CFLAGS="$SFLAGS" + LIBS="$SHAREDLIBV" + echo Building shared library $SHAREDLIBV with $CC. + elif test -z "$old_cc" -a -z "$old_cflags"; then + echo No shared library support. + shared=0; + else + echo 'No shared library support; try without defining CC and CFLAGS' + shared=0; + fi +fi +if test $shared -eq 0; then + LDSHARED="$CC" + echo Building static library $LIBS version $VER with $CC. +else + LDFLAGS="-L. ${SHAREDLIBV}" +fi + +cat > $test.c <<EOF +#include <unistd.h> +int main() { return 0; } +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + sed < zconf.in.h "/HAVE_UNISTD_H/s%0%1%" > zconf.h + echo "Checking for unistd.h... Yes." +else + cp -p zconf.in.h zconf.h + echo "Checking for unistd.h... No." +fi + +cat > $test.c <<EOF +#include <stdio.h> +#include <stdarg.h> +#include "zconf.h" + +int main() +{ +#ifndef STDC + choke me +#endif + + return 0; +} +EOF + +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()" + + cat > $test.c <<EOF +#include <stdio.h> +#include <stdarg.h> + +int mytest(char *fmt, ...) +{ + char buf[20]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then + echo "Checking for vsnprintf() in stdio.h... Yes." + + cat >$test.c <<EOF +#include <stdio.h> +#include <stdarg.h> + +int mytest(char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return n; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of vsnprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_vsnprintf_void" + echo "Checking for return value of vsnprintf()... No." + echo " WARNING: apparently vsnprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + CFLAGS="$CFLAGS -DNO_vsnprintf" + echo "Checking for vsnprintf() in stdio.h... No." + echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c <<EOF +#include <stdio.h> +#include <stdarg.h> + +int mytest(char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + + va_start(ap, fmt); + n = vsprintf(buf, fmt, ap); + va_end(ap); + return n; +} + +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of vsprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_vsprintf_void" + echo "Checking for return value of vsprintf()... No." + echo " WARNING: apparently vsprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +else + echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()" + + cat >$test.c <<EOF +#include <stdio.h> + +int mytest() +{ + char buf[20]; + + snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then + echo "Checking for snprintf() in stdio.h... Yes." + + cat >$test.c <<EOF +#include <stdio.h> + +int mytest() +{ + char buf[20]; + + return snprintf(buf, sizeof(buf), "%s", "foo"); +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of snprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_snprintf_void" + echo "Checking for return value of snprintf()... No." + echo " WARNING: apparently snprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + else + CFLAGS="$CFLAGS -DNO_snprintf" + echo "Checking for snprintf() in stdio.h... No." + echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" + echo " can build but will be open to possible buffer-overflow security" + echo " vulnerabilities." + + cat >$test.c <<EOF +#include <stdio.h> + +int mytest() +{ + char buf[20]; + + return sprintf(buf, "%s", "foo"); +} + +int main() +{ + return (mytest()); +} +EOF + + if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for return value of sprintf()... Yes." + else + CFLAGS="$CFLAGS -DHAS_sprintf_void" + echo "Checking for return value of sprintf()... No." + echo " WARNING: apparently sprintf() does not return a value. zlib" + echo " can build but will be open to possible string-format security" + echo " vulnerabilities." + fi + fi +fi + +cat >$test.c <<EOF +#include <errno.h> +int main() { return 0; } +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + echo "Checking for errno.h... Yes." +else + echo "Checking for errno.h... No." + CFLAGS="$CFLAGS -DNO_ERRNO_H" +fi + +cat > $test.c <<EOF +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> +caddr_t hello() { + return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0); +} +EOF +if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then + CFLAGS="$CFLAGS -DUSE_MMAP" + echo Checking for mmap support... Yes. +else + echo Checking for mmap support... No. +fi + +CPP=${CPP-"$CC -E"} +case $CFLAGS in + *ASMV*) + if test "`nm $test.o | grep _hello`" = ""; then + CPP="$CPP -DNO_UNDERLINE" + echo Checking for underline in external names... No. + else + echo Checking for underline in external names... Yes. + fi;; +esac + +rm -f $test.[co] $test $test$shared_ext + +# udpate Makefile +sed < Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^CPP *=/s#=.*#=$CPP# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^LIBS *=/s#=.*#=$LIBS# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^RANLIB *=/s#=.*#=$RANLIB# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +" > Makefile diff --git a/sys/src/cmd/python/Modules/zlib/crc32.c b/sys/src/cmd/python/Modules/zlib/crc32.c new file mode 100644 index 000000000..f658a9ef5 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/crc32.c @@ -0,0 +1,423 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + */ + +#ifdef MAKECRCH +# include <stdio.h> +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Find a four-byte integer type for crc32_little() and crc32_big(). */ +#ifndef NOBYFOUR +# ifdef STDC /* need ANSI C limits.h to determine sizes */ +# include <limits.h> +# define BYFOUR +# if (UINT_MAX == 0xffffffffUL) + typedef unsigned int u4; +# else +# if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long u4; +# else +# if (USHRT_MAX == 0xffffffffUL) + typedef unsigned short u4; +# else +# undef BYFOUR /* can't find a four-byte integer type! */ +# endif +# endif +# endif +# endif /* STDC */ +#endif /* !NOBYFOUR */ + +/* Definitions for doing the crc four data bytes at a time. */ +#ifdef BYFOUR +# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \ + (((w)&0xff00)<<8)+(((w)&0xff)<<24)) + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local unsigned long FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const unsigned long FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + unsigned long c; + int n, k; + unsigned long poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0UL; + for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++) + poly |= 1UL << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (unsigned long)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = REV(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = REV(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const unsigned long FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const unsigned long FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n], + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const unsigned long FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const unsigned long FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + u4 endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = (u4)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register u4 c; + register const u4 FAR *buf4; + + c = REV((u4)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const u4 FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(REV(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/sys/src/cmd/python/Modules/zlib/crc32.h b/sys/src/cmd/python/Modules/zlib/crc32.h new file mode 100644 index 000000000..8053b6117 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const unsigned long FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/sys/src/cmd/python/Modules/zlib/deflate.c b/sys/src/cmd/python/Modules/zlib/deflate.c new file mode 100644 index 000000000..29ce1f64a --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/deflate.c @@ -0,0 +1,1736 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://www.ietf.org/rfc/rfc1951.txt + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifndef FASTEST +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif +#endif +local uInt longest_match_fast OF((deflate_state *s, IPos cur_match)); + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->wrap == 2 || + (strm->state->wrap == 1 && strm->state->status != INIT_STATE)) + return Z_STREAM_ERROR; + + s = strm->state; + if (s->wrap) + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; /* use the tail of the dictionary */ + } + zmemcpy(s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + strm->state->bi_valid = bits; + strm->state->bi_buf = (ush)(value & ((1 << bits) - 1)); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds + * for every combination of windowBits and memLevel, as well as wrap. + * But even the conservative upper bound of about 14% expansion does not + * seem onerous for output buffer allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong destLen; + + /* conservative upper bound */ + destLen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11; + + /* if can't get parameters, return conservative bound */ + if (strm == Z_NULL || strm->state == Z_NULL) + return destLen; + + /* if not default parameters, return conservative bound */ + s = strm->state; + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return destLen; + + /* default settings: return tight bound for that case */ + return compressBound(sourceLen); +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy(dest, source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy(ds, ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, strm->next_in, len); + } +#endif + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ +#endif /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for level == 1 or strategy == Z_RLE only + */ +local uInt longest_match_fast(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + /* %%% avoid this when Z_RLE */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ +#ifdef FASTEST + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || + (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { + s->match_length = longest_match_fast (s, hash_head); + } +#else + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } +#endif + /* longest_match() or longest_match_fast() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { + s->match_length = longest_match (s, hash_head); + } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { + s->match_length = longest_match_fast (s, hash_head); + } + /* longest_match() or longest_match_fast() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/sys/src/cmd/python/Modules/zlib/deflate.h b/sys/src/cmd/python/Modules/zlib/deflate.h new file mode 100644 index 000000000..05a5ab3a2 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/deflate.h @@ -0,0 +1,331 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2004 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch _length_code[]; + extern uch _dist_code[]; +#else + extern const uch _length_code[]; + extern const uch _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/sys/src/cmd/python/Modules/zlib/example.c b/sys/src/cmd/python/Modules/zlib/example.c new file mode 100644 index 000000000..6c8a0ee76 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/example.c @@ -0,0 +1,565 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2004 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include <stdio.h> +#include "zlib.h" + +#ifdef STDC +# include <string.h> +# include <stdlib.h> +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/sys/src/cmd/python/Modules/zlib/gzio.c b/sys/src/cmd/python/Modules/zlib/gzio.c new file mode 100644 index 000000000..7e90f4928 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/gzio.c @@ -0,0 +1,1026 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. + */ + +/* @(#) $Id$ */ + +#include <stdio.h> + +#include "zutil.h" + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +#ifndef Z_BUFSIZE +# ifdef MAXSEG_64K +# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ +# else +# define Z_BUFSIZE 16384 +# endif +#endif +#ifndef Z_PRINTF_BUFSIZE +# define Z_PRINTF_BUFSIZE 4096 +#endif + +#ifdef __MVS__ +# pragma map (fdopen , "\174\174FDOPEN") + FILE *fdopen(int, const char *); +#endif + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern void free OF((voidpf ptr)); +#endif + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ + z_off_t start; /* start of compressed data in file (header skipped) */ + z_off_t in; /* bytes into deflate or inflate */ + z_off_t out; /* bytes out of deflate or inflate */ + int back; /* one character push-back */ + int last; /* true if push-back is last character */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int do_flush OF((gzFile file, int flush)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->in = 0; + s->out = 0; + s->back = EOF; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else if (*p == 'f') { + strategy = Z_FILTERED; + } else if (*p == 'h') { + strategy = Z_HUFFMAN_ONLY; + } else if (*p == 'R') { + strategy = Z_RLE; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); +#endif + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + err = inflateInit2(&(s->stream), -MAX_WBITS); + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + * present after the compressed stream. + */ + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + s->start = 10L; + /* We use 10L instead of ftell(s->file) to because ftell causes an + * fflush on some systems. This version of the library doesn't use + * start anyway in write mode, so this initialization is not + * necessary. + */ + } else { + check_header(s); /* skip the .gz header */ + s->start = ftell(s->file) - s->stream.avail_in; + } + + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +gzFile ZEXPORT gzopen (path, mode) + const char *path; + const char *mode; +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +gzFile ZEXPORT gzdopen (fd, mode) + int fd; + const char *mode; +{ + char name[46]; /* allow for up to 128-bit integers */ + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "<fd:%d>", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + * Update the compression level and strategy + */ +int ZEXPORT gzsetparams (file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + /* Make room to allow flushing */ + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + } + s->stream.avail_out = Z_BUFSIZE; + } + + return deflateParams (&(s->stream), level, strategy); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Assure two bytes in the buffer so we can peek ahead -- handle case + where first byte of header is at the end of the buffer after the last + gzip segment */ + len = s->stream.avail_in; + if (len < 2) { + if (len) s->inbuf[0] = s->stream.next_in[0]; + errno = 0; + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; + s->stream.avail_in += len; + s->stream.next_in = s->inbuf; + if (s->stream.avail_in < 2) { + s->transparent = s->stream.avail_in; + return; + } + } + + /* Peek ahead to check the gzip magic header */ + if (s->stream.next_in[0] != gz_magic[0] || + s->stream.next_in[1] != gz_magic[1]) { + s->transparent = 1; + return; + } + s->stream.avail_in -= 2; + s->stream.next_in += 2; + + /* Check the rest of the gzip header */ + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + err = Z_STREAM_ERROR; +#else + err = deflateEnd(&(s->stream)); +#endif + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { +#ifdef ESPIPE + if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ +#endif + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +int ZEXPORT gzread (file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = (Bytef*)buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + next_out = (Byte*)buf; + s->stream.next_out = (Bytef*)buf; + s->stream.avail_out = len; + + if (s->stream.avail_out && s->back != EOF) { + *next_out++ = s->back; + s->stream.next_out++; + s->stream.avail_out--; + s->back = EOF; + s->out++; + start++; + if (s->last) { + s->z_err = Z_STREAM_END; + return 1; + } + } + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); + } + len -= s->stream.avail_out; + s->in += len; + s->out += len; + if (len == 0) s->z_eof = 1; + return (int)len; + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc) { + s->z_err = Z_DATA_ERROR; + } else { + (void)getLong(s); + /* The uncompressed length returned by above getlong() may be + * different from s->out in case of concatenated .gz files. + * Check for such files: + */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; + return (int)(len - s->stream.avail_out); +} + + +/* =========================================================================== + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ +int ZEXPORT gzgetc(file) + gzFile file; +{ + unsigned char c; + + return gzread(file, &c, 1) == 1 ? c : -1; +} + + +/* =========================================================================== + Push one byte back onto the stream. +*/ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF; + s->back = c; + s->out--; + s->last = (s->z_err == Z_STREAM_END); + if (s->last) s->z_err = Z_OK; + s->z_eof = 0; + return c; +} + + +/* =========================================================================== + Reads bytes from the compressed file until len-1 characters are + read, or a newline character is read and transferred to buf, or an + end-of-file condition is encountered. The string is then terminated + with a null character. + gzgets returns buf, or Z_NULL in case of error. + + The current implementation is not optimized at all. +*/ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + char *b = buf; + if (buf == Z_NULL || len <= 0) return Z_NULL; + + while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ; + *buf = '\0'; + return b == buf && len > 0 ? Z_NULL : b; +} + + +#ifndef NO_GZCOMPRESS +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +int ZEXPORT gzwrite (file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = (Bytef*)buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->in += s->stream.avail_in; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + s->in -= s->stream.avail_in; + s->out -= s->stream.avail_out; + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, (const Bytef *)buf, len); + + return (int)(len - s->stream.avail_in); +} + + +/* =========================================================================== + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ +#ifdef STDC +#include <stdarg.h> + +int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...) +{ + char buf[Z_PRINTF_BUFSIZE]; + va_list va; + int len; + + buf[sizeof(buf) - 1] = 0; + va_start(va, format); +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf(buf, format, va); + va_end(va); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = vsprintf(buf, format, va); + va_end(va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf(buf, sizeof(buf), format, va); + va_end(va); + len = strlen(buf); +# else + len = vsnprintf(buf, sizeof(buf), format, va); + va_end(va); +# endif +#endif + if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, (unsigned)len); +} +#else /* not ANSI C */ + +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + char buf[Z_PRINTF_BUFSIZE]; + int len; + + buf[sizeof(buf) - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < sizeof(buf); len++) + if (buf[len] == 0) break; +# else + len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(buf); +# else + len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#endif + if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0) + return 0; + return gzwrite(file, buf, len); +} +#endif + +/* =========================================================================== + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned char cc = (unsigned char) c; /* required for big endian systems */ + + return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1; +} + + +/* =========================================================================== + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ +int ZEXPORT gzputs(file, s) + gzFile file; + const char *s; +{ + return gzwrite(file, (char*)s, (unsigned)strlen(s)); +} + + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. +*/ +local int do_flush (file, flush) + gzFile file; + int flush; +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->out += s->stream.avail_out; + s->z_err = deflate(&(s->stream), flush); + s->out -= s->stream.avail_out; + + /* Ignore the second of two consecutive flushes: */ + if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK; + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +int ZEXPORT gzflush (file, flush) + gzFile file; + int flush; +{ + gz_stream *s = (gz_stream*)file; + int err = do_flush (file, flush); + + if (err) return err; + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} +#endif /* NO_GZCOMPRESS */ + +/* =========================================================================== + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error. + SEEK_END is not implemented, returns error. + In this version of the library, gzseek can be extremely slow. +*/ +z_off_t ZEXPORT gzseek (file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || whence == SEEK_END || + s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) { + return -1L; + } + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return -1L; +#else + if (whence == SEEK_SET) { + offset -= s->in; + } + if (offset < 0) return -1L; + + /* At this point, offset is the number of zero bytes to write. */ + if (s->inbuf == Z_NULL) { + s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */ + if (s->inbuf == Z_NULL) return -1L; + zmemzero(s->inbuf, Z_BUFSIZE); + } + while (offset > 0) { + uInt size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (uInt)offset; + + size = gzwrite(file, s->inbuf, size); + if (size == 0) return -1L; + + offset -= size; + } + return s->in; +#endif + } + /* Rest of function is for reading only */ + + /* compute absolute position */ + if (whence == SEEK_CUR) { + offset += s->out; + } + if (offset < 0) return -1L; + + if (s->transparent) { + /* map to fseek */ + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + if (fseek(s->file, offset, SEEK_SET) < 0) return -1L; + + s->in = s->out = offset; + return offset; + } + + /* For a negative seek, rewind and use positive seek */ + if (offset >= s->out) { + offset -= s->out; + } else if (gzrewind(file) < 0) { + return -1L; + } + /* offset is now the number of bytes to skip. */ + + if (offset != 0 && s->outbuf == Z_NULL) { + s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + if (s->outbuf == Z_NULL) return -1L; + } + if (offset && s->back != EOF) { + s->back = EOF; + s->out++; + offset--; + if (s->last) s->z_err = Z_STREAM_END; + } + while (offset > 0) { + int size = Z_BUFSIZE; + if (offset < Z_BUFSIZE) size = (int)offset; + + size = gzread(file, s->outbuf, (uInt)size); + if (size <= 0) return -1L; + offset -= size; + } + return s->out; +} + +/* =========================================================================== + Rewinds input file. +*/ +int ZEXPORT gzrewind (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return -1; + + s->z_err = Z_OK; + s->z_eof = 0; + s->back = EOF; + s->stream.avail_in = 0; + s->stream.next_in = s->inbuf; + s->crc = crc32(0L, Z_NULL, 0); + if (!s->transparent) (void)inflateReset(&s->stream); + s->in = 0; + s->out = 0; + return fseek(s->file, s->start, SEEK_SET); +} + +/* =========================================================================== + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. +*/ +z_off_t ZEXPORT gztell (file) + gzFile file; +{ + return gzseek(file, 0L, SEEK_CUR); +} + +/* =========================================================================== + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ +int ZEXPORT gzeof (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + /* With concatenated compressed files that can have embedded + * crc trailers, z_eof is no longer the only/best indicator of EOF + * on a gz_stream. Handle end-of-stream error explicitly here. + */ + if (s == NULL || s->mode != 'r') return 0; + if (s->z_eof) return 1; + return s->z_err == Z_STREAM_END; +} + +/* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets z_err in case + of error. +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +int ZEXPORT gzclose (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { +#ifdef NO_GZCOMPRESS + return Z_STREAM_ERROR; +#else + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); + + putLong (s->file, s->crc); + putLong (s->file, (uLong)(s->in & 0xffffffff)); +#endif + } + return destroy((gz_stream*)file); +} + +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +/* =========================================================================== + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +const char * ZEXPORT gzerror (file, errnum) + gzFile file; + int *errnum; +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} + +/* =========================================================================== + Clear the error and end-of-file flags, and do the same for the real file. +*/ +void ZEXPORT gzclearerr (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return; + if (s->z_err != Z_STREAM_END) s->z_err = Z_OK; + s->z_eof = 0; + clearerr(s->file); +} diff --git a/sys/src/cmd/python/Modules/zlib/infback.c b/sys/src/cmd/python/Modules/zlib/infback.c new file mode 100644 index 000000000..455dbc9ee --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/infback.c @@ -0,0 +1,623 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->write = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + + /* process literal */ + if (this.op == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(this.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/sys/src/cmd/python/Modules/zlib/inffast.c b/sys/src/cmd/python/Modules/zlib/inffast.c new file mode 100644 index 000000000..bbee92ed1 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/inffast.c @@ -0,0 +1,318 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + unsigned char FAR *in; /* local strm->next_in */ + unsigned char FAR *last; /* while in < last, enough input available */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code this; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + write = state->write; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = lcode[hold & lmask]; + dolen: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op == 0) { /* literal */ + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + PUP(out) = (unsigned char)(this.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + this = dcode[hold & dmask]; + dodist: + op = (unsigned)(this.bits); + hold >>= op; + bits -= op; + op = (unsigned)(this.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(this.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + from = window - OFF; + if (write == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (write < op) { /* wrap around window */ + from += wsize + write - op; + op -= write; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (write < len) { /* some from start of window */ + op = write; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += write - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + this = dcode[this.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + this = lcode[this.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and write == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/sys/src/cmd/python/Modules/zlib/inffast.h b/sys/src/cmd/python/Modules/zlib/inffast.h new file mode 100644 index 000000000..1e88d2d97 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/sys/src/cmd/python/Modules/zlib/inffixed.h b/sys/src/cmd/python/Modules/zlib/inffixed.h new file mode 100644 index 000000000..75ed4b597 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. It + is part of the implementation of the compression library and + is subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/sys/src/cmd/python/Modules/zlib/inflate.c b/sys/src/cmd/python/Modules/zlib/inflate.c new file mode 100644 index 000000000..792fdee8e --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/inflate.c @@ -0,0 +1,1368 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common write == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, unsigned out)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + strm->adler = 1; /* to support ill-conceived Java test suite */ + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->wsize = 0; + state->whave = 0; + state->write = 0; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + if (windowBits < 0) { + state->wrap = 0; + windowBits = -windowBits; + } + else { + state->wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) windowBits &= 15; +#endif + } + if (windowBits < 8 || windowBits > 15) { + ZFREE(strm, state); + strm->state = Z_NULL; + return Z_STREAM_ERROR; + } + state->wbits = (unsigned)windowBits; + state->window = Z_NULL; + return inflateReset(strm); +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include <stdio.h> + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits, + state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, out) +z_streamp strm; +unsigned out; +{ + struct inflate_state FAR *state; + unsigned copy, dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->write = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + copy = out - strm->avail_out; + if (copy >= state->wsize) { + zmemcpy(state->window, strm->next_out - state->wsize, state->wsize); + state->write = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->write; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->write, strm->next_out - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, strm->next_out - copy, copy); + state->write = copy; + state->whave = state->wsize; + } + else { + state->write += dist; + if (state->write == state->wsize) state->write = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Reverse the bytes in a 32-bit value */ +#define REVERSE(q) \ + ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code this; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = REVERSE(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.val < 16) { + NEEDBITS(this.bits); + DROPBITS(this.bits); + state->lens[state->have++] = this.val; + } + else { + if (this.val == 16) { + NEEDBITS(this.bits + 2); + DROPBITS(this.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (this.val == 17) { + NEEDBITS(this.bits + 3); + DROPBITS(this.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(this.bits + 7); + DROPBITS(this.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* build code tables */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + break; + } + for (;;) { + this = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if (this.op && (this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + state->length = (unsigned)this.val; + if ((int)(this.op) == 0) { + Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", this.val)); + state->mode = LIT; + break; + } + if (this.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + if (this.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(this.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->mode = DIST; + case DIST: + for (;;) { + this = state->distcode[BITS(state->distbits)]; + if ((unsigned)(this.bits) <= bits) break; + PULLBYTE(); + } + if ((this.op & 0xf0) == 0) { + last = this; + for (;;) { + this = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + this.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(this.bits); + if (this.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)this.val; + state->extra = (unsigned)(this.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + if (state->offset > state->whave + out - left) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->write) { + copy -= state->write; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->write - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + REVERSE(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) + if (updatewindow(strm, out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long id; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary id */ + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window */ + if (updatewindow(strm, strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + if (dictLength > state->wsize) { + zmemcpy(state->window, dictionary + dictLength - state->wsize, + state->wsize); + state->whave = state->wsize; + } + else { + zmemcpy(state->window + state->wsize - dictLength, dictionary, + dictLength); + state->whave = dictLength; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} diff --git a/sys/src/cmd/python/Modules/zlib/inflate.h b/sys/src/cmd/python/Modules/zlib/inflate.h new file mode 100644 index 000000000..07bd3e78a --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/inflate.h @@ -0,0 +1,115 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2004 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN, /* i: waiting for length/lit code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD or MEM mode -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME + NAME -> COMMENT -> HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or CHECK + STORED -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned write; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/sys/src/cmd/python/Modules/zlib/inftrees.c b/sys/src/cmd/python/Modules/zlib/inftrees.c new file mode 100644 index 000000000..8a9c13ff0 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/inftrees.c @@ -0,0 +1,329 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)1; + this.val = (unsigned short)0; + *(*table)++ = this; /* make a table to force an error */ + *(*table)++ = this; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked when a LENS table is being made + against the space in *table, ENOUGH, minus the maximum space needed by + the worst case distance code, MAXD. This should never happen, but the + sufficiency of ENOUGH has not been proven exhaustively, hence the check. + This assumes that when type == LENS, bits == 9. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if (type == LENS && used >= ENOUGH - MAXD) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/sys/src/cmd/python/Modules/zlib/inftrees.h b/sys/src/cmd/python/Modules/zlib/inftrees.h new file mode 100644 index 000000000..b1104c87e --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/inftrees.h @@ -0,0 +1,55 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1444 code structures (852 for length/literals + and 592 for distances, the latter actually the result of an + exhaustive search). The true maximum is not known, but the value + below is more than safe. */ +#define ENOUGH 2048 +#define MAXD 592 + +/* Type of code to build for inftable() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/sys/src/cmd/python/Modules/zlib/make_vms.com b/sys/src/cmd/python/Modules/zlib/make_vms.com new file mode 100644 index 000000000..c2a1fb54b --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/make_vms.com @@ -0,0 +1,461 @@ +$! make libz under VMS written by +$! Martin P.J. Zinser +$! <zinser@zinser.no-ip.info or zinser@sysdev.deutsche-boerse.com> +$! +$ on error then goto err_exit +$! +$! +$! Just some general constants... +$! +$ true = 1 +$ false = 0 +$ tmpnam = "temp_" + f$getjpi("","pid") +$ SAY = "WRITE SYS$OUTPUT" +$! +$! Setup variables holding "config" information +$! +$ Make = "" +$ name = "Zlib" +$ version = "?.?.?" +$ v_string = "ZLIB_VERSION" +$ v_file = "zlib.h" +$ ccopt = "" +$ lopts = "" +$ linkonly = false +$ optfile = name + ".opt" +$ its_decc = false +$ its_vaxc = false +$ its_gnuc = false +$ axp = f$getsyi("HW_MODEL").ge.1024 +$ s_case = false +$! Check for MMK/MMS +$! +$ If F$Search ("Sys$System:MMS.EXE") .nes. "" Then Make = "MMS" +$ If F$Type (MMK) .eqs. "STRING" Then Make = "MMK" +$! +$! +$ gosub find_version +$! +$ gosub check_opts +$! +$! Look for the compiler used +$! +$ gosub check_compiler +$ if its_decc +$ then +$ ccopt = "/prefix=all" + ccopt +$ if f$trnlnm("SYS") .eqs. "" +$ then +$ if axp +$ then +$ define sys sys$library: +$ else +$ ccopt = "/decc" + ccopt +$ define sys decc$library_include: +$ endif +$ endif +$ endif +$ if its_vaxc .or. its_gnuc +$ then +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ endif +$! +$! Build the thing plain or with mms +$! +$ write sys$output "Compiling Zlib sources ..." +$ if make.eqs."" +$ then +$ dele example.obj;*,minigzip.obj;* +$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" - + adler32.c zlib.h zconf.h +$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" - + compress.c zlib.h zconf.h +$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" - + crc32.c zlib.h zconf.h +$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" - + deflate.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE gzio.OBJ "CC ''CCOPT' gzio" - + gzio.c zutil.h zlib.h zconf.h +$ CALL MAKE infback.OBJ "CC ''CCOPT' infback" - + infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" - + inffast.c zutil.h zlib.h zconf.h inffast.h +$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" - + inflate.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" - + inftrees.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" - + trees.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" - + uncompr.c zlib.h zconf.h +$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" - + zutil.c zutil.h zlib.h zconf.h +$ write sys$output "Building Zlib ..." +$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ +$ write sys$output "Building example..." +$ CALL MAKE example.OBJ "CC ''CCOPT' example" - + example.c zlib.h zconf.h +$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb +$ if f$search("x11vms:xvmsutils.olb") .nes. "" +$ then +$ write sys$output "Building minigzip..." +$ CALL MAKE minigzip.OBJ "CC ''CCOPT' minigzip" - + minigzip.c zlib.h zconf.h +$ call make minigzip.exe - + "LINK minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib" - + minigzip.obj libz.olb +$ endif +$ else +$ gosub crea_mms +$ SAY "Make ''name' ''version' with ''Make' " +$ 'make' +$ endif +$! +$! Alpha gets a shareable image +$! +$ If axp +$ Then +$ gosub crea_olist +$ write sys$output "Creating libzshr.exe" +$ call anal_obj_axp modules.opt _link.opt +$ if s_case +$ then +$ open/append optf modules.opt +$ write optf "case_sensitive=YES" +$ close optf +$ endif +$ LINK_'lopts'/SHARE=libzshr.exe modules.opt/opt,_link.opt/opt +$ endif +$ write sys$output "Zlib build completed" +$ exit +$CC_ERR: +$ write sys$output "C compiler required to build ''name'" +$ goto err_exit +$ERR_EXIT: +$ set message/facil/ident/sever/text +$ write sys$output "Exiting..." +$ exit 2 +$! +$! +$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES +$ V = 'F$Verify(0) +$! P1 = What we are trying to make +$! P2 = Command to make it +$! P3 - P8 What it depends on +$ +$ If F$Search(P1) .Eqs. "" Then Goto Makeit +$ Time = F$CvTime(F$File(P1,"RDT")) +$arg=3 +$Loop: +$ Argument = P'arg +$ If Argument .Eqs. "" Then Goto Exit +$ El=0 +$Loop2: +$ File = F$Element(El," ",Argument) +$ If File .Eqs. " " Then Goto Endl +$ AFile = "" +$Loop3: +$ OFile = AFile +$ AFile = F$Search(File) +$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl +$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit +$ Goto Loop3 +$NextEL: +$ El = El + 1 +$ Goto Loop2 +$EndL: +$ arg=arg+1 +$ If arg .Le. 8 Then Goto Loop +$ Goto Exit +$ +$Makeit: +$ VV=F$VERIFY(0) +$ write sys$output P2 +$ 'P2 +$ VV='F$Verify(VV) +$Exit: +$ If V Then Set Verify +$ENDSUBROUTINE +$!------------------------------------------------------------------------------ +$! +$! Check command line options and set symbols accordingly +$! +$ CHECK_OPTS: +$ i = 1 +$ OPT_LOOP: +$ if i .lt. 9 +$ then +$ cparm = f$edit(p'i',"upcase") +$ if cparm .eqs. "DEBUG" +$ then +$ ccopt = ccopt + "/noopt/deb" +$ lopts = lopts + "/deb" +$ endif +$ if f$locate("CCOPT=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ ccopt = ccopt + f$extract(start,len,cparm) +$ if f$locate("AS_IS",f$edit(ccopt,"UPCASE")) .lt. f$length(ccopt) - + then s_case = true +$ endif +$ if cparm .eqs. "LINK" then linkonly = true +$ if f$locate("LOPTS=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ lopts = lopts + f$extract(start,len,cparm) +$ endif +$ if f$locate("CC=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ cc_com = f$extract(start,len,cparm) + if (cc_com .nes. "DECC") .and. - + (cc_com .nes. "VAXC") .and. - + (cc_com .nes. "GNUC") +$ then +$ write sys$output "Unsupported compiler choice ''cc_com' ignored" +$ write sys$output "Use DECC, VAXC, or GNUC instead" +$ else +$ if cc_com .eqs. "DECC" then its_decc = true +$ if cc_com .eqs. "VAXC" then its_vaxc = true +$ if cc_com .eqs. "GNUC" then its_gnuc = true +$ endif +$ endif +$ if f$locate("MAKE=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ mmks = f$extract(start,len,cparm) +$ if (mmks .eqs. "MMK") .or. (mmks .eqs. "MMS") +$ then +$ make = mmks +$ else +$ write sys$output "Unsupported make choice ''mmks' ignored" +$ write sys$output "Use MMK or MMS instead" +$ endif +$ endif +$ i = i + 1 +$ goto opt_loop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Look for the compiler used +$! +$CHECK_COMPILER: +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then +$ its_decc = (f$search("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "") +$ its_vaxc = .not. its_decc .and. (F$Search("SYS$System:VAXC.Exe") .nes. "") +$ its_gnuc = .not. (its_decc .or. its_vaxc) .and. (f$trnlnm("gnu_cc") .nes. "") +$ endif +$! +$! Exit if no compiler available +$! +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then goto CC_ERR +$ else +$ if its_decc then write sys$output "CC compiler check ... Compaq C" +$ if its_vaxc then write sys$output "CC compiler check ... VAX C" +$ if its_gnuc then write sys$output "CC compiler check ... GNU C" +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! If MMS/MMK are available dump out the descrip.mms if required +$! +$CREA_MMS: +$ write sys$output "Creating descrip.mms..." +$ create descrip.mms +$ open/append out descrip.mms +$ copy sys$input: out +$ deck +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser +# <zinser@zinser.no-ip.info or zinser@sysdev.deutsche-boerse.com> + +OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj, infback.obj\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, \ + inftrees.obj, inffast.obj + +$ eod +$ write out "CFLAGS=", ccopt +$ write out "LOPTS=", lopts +$ copy sys$input: out +$ deck + +all : example.exe minigzip.exe libz.olb + @ write sys$output " Example applications available" + +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link $(LOPTS) example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link $(LOPTS) minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib + +clean : + delete *.obj;*,libz.olb;*,*.opt;*,*.exe;* + + +# Other dependencies. +adler32.obj : adler32.c zutil.h zlib.h zconf.h +compress.obj : compress.c zlib.h zconf.h +crc32.obj : crc32.c zutil.h zlib.h zconf.h +deflate.obj : deflate.c deflate.h zutil.h zlib.h zconf.h +example.obj : example.c zlib.h zconf.h +gzio.obj : gzio.c zutil.h zlib.h zconf.h +inffast.obj : inffast.c zutil.h zlib.h zconf.h inftrees.h inffast.h +inflate.obj : inflate.c zutil.h zlib.h zconf.h +inftrees.obj : inftrees.c zutil.h zlib.h zconf.h inftrees.h +minigzip.obj : minigzip.c zlib.h zconf.h +trees.obj : trees.c deflate.h zutil.h zlib.h zconf.h +uncompr.obj : uncompr.c zlib.h zconf.h +zutil.obj : zutil.c zutil.h zlib.h zconf.h +infback.obj : infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ eod +$ close out +$ return +$!------------------------------------------------------------------------------ +$! +$! Read list of core library sources from makefile.in and create options +$! needed to build shareable image +$! +$CREA_OLIST: +$ open/read min makefile.in +$ open/write mod modules.opt +$ src_check = "OBJS =" +$MRLOOP: +$ read/end=mrdone min rec +$ if (f$extract(0,6,rec) .nes. src_check) then goto mrloop +$ rec = rec - src_check +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .eqs. "\") then goto mrdone +$MRSLOOP: +$ read/end=mrdone min rec +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .nes. "\") then goto mrsloop +$MRDONE: +$ close min +$ close mod +$ return +$!------------------------------------------------------------------------------ +$! +$! Take record extracted in crea_olist and split it into single filenames +$! +$EXTRA_FILNAM: +$ myrec = f$edit(rec - "\", "trim,compress") +$ i = 0 +$FELOOP: +$ srcfil = f$element(i," ", myrec) +$ if (srcfil .nes. " ") +$ then +$ write mod f$parse(srcfil,,,"NAME"), ".obj" +$ i = i + 1 +$ goto feloop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Find current Zlib version number +$! +$FIND_VERSION: +$ open/read h_in 'v_file' +$hloop: +$ read/end=hdone h_in rec +$ rec = f$edit(rec,"TRIM") +$ if (f$extract(0,1,rec) .nes. "#") then goto hloop +$ rec = f$edit(rec - "#", "TRIM") +$ if f$element(0," ",rec) .nes. "define" then goto hloop +$ if f$element(1," ",rec) .eqs. v_string +$ then +$ version = 'f$element(2," ",rec)' +$ goto hdone +$ endif +$ goto hloop +$hdone: +$ close h_in +$ return +$!------------------------------------------------------------------------------ +$! +$! Analyze Object files for OpenVMS AXP to extract Procedure and Data +$! information to build a symbol vector for a shareable image +$! All the "brains" of this logic was suggested by Hartmut Becker +$! (Hartmut.Becker@compaq.com). All the bugs were introduced by me +$! (zinser@decus.de), so if you do have problem reports please do not +$! bother Hartmut/HP, but get in touch with me +$! +$ ANAL_OBJ_AXP: Subroutine +$ V = 'F$Verify(0) +$ SAY := "WRITE_ SYS$OUTPUT" +$ +$ IF F$SEARCH("''P1'") .EQS. "" +$ THEN +$ SAY "ANAL_OBJ_AXP-E-NOSUCHFILE: Error, inputfile ''p1' not available" +$ goto exit_aa +$ ENDIF +$ IF "''P2'" .EQS. "" +$ THEN +$ SAY "ANAL_OBJ_AXP: Error, no output file provided" +$ goto exit_aa +$ ENDIF +$ +$ open/read in 'p1 +$ create a.tmp +$ open/append atmp a.tmp +$ loop: +$ read/end=end_loop in line +$ f= f$search(line) +$ if f .eqs. "" +$ then +$ write sys$output "ANAL_OBJ_AXP-w-nosuchfile, ''line'" +$ goto loop +$ endif +$ define/user sys$output nl: +$ define/user sys$error nl: +$ anal/obj/gsd 'f /out=x.tmp +$ open/read xtmp x.tmp +$ XLOOP: +$ read/end=end_xloop xtmp xline +$ xline = f$edit(xline,"compress") +$ write atmp xline +$ goto xloop +$ END_XLOOP: +$ close xtmp +$ goto loop +$ end_loop: +$ close in +$ close atmp +$ if f$search("a.tmp") .eqs. "" - + then $ exit +$ ! all global definitions +$ search a.tmp "symbol:","EGSY$V_DEF 1","EGSY$V_NORM 1"/out=b.tmp +$ ! all procedures +$ search b.tmp "EGSY$V_NORM 1"/wind=(0,1) /out=c.tmp +$ search c.tmp "symbol:"/out=d.tmp +$ define/user sys$output nl: +$ edito/edt/command=sys$input d.tmp +sub/symbol: "/symbol_vector=(/whole +sub/"/=PROCEDURE)/whole +exit +$ ! all data +$ search b.tmp "EGSY$V_DEF 1"/wind=(0,1) /out=e.tmp +$ search e.tmp "symbol:"/out=f.tmp +$ define/user sys$output nl: +$ edito/edt/command=sys$input f.tmp +sub/symbol: "/symbol_vector=(/whole +sub/"/=DATA)/whole +exit +$ sort/nodupl d.tmp,f.tmp 'p2' +$ delete a.tmp;*,b.tmp;*,c.tmp;*,d.tmp;*,e.tmp;*,f.tmp;* +$ if f$search("x.tmp") .nes. "" - + then $ delete x.tmp;* +$! +$ EXIT_AA: +$ if V then set verify +$ endsubroutine +$!------------------------------------------------------------------------------ diff --git a/sys/src/cmd/python/Modules/zlib/minigzip.c b/sys/src/cmd/python/Modules/zlib/minigzip.c new file mode 100644 index 000000000..4524b96a1 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/minigzip.c @@ -0,0 +1,322 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include <stdio.h> +#include "zlib.h" + +#ifdef STDC +# include <string.h> +# include <stdlib.h> +#endif + +#ifdef USE_MMAP +# include <sys/types.h> +# include <sys/mman.h> +# include <sys/stat.h> +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include <fcntl.h> +# include <io.h> +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include <unix.h> /* for fileno */ +#endif + +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + uInt len = (uInt)strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + char outmode[20]; + + strcpy(outmode, "wb6 "); + + prog = argv[0]; + argc--, argv++; + + while (argc > 0) { + if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (outmode[3] == ' ') + outmode[3] = 0; + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv, outmode); + } + } while (argv++, --argc); + } + return 0; +} diff --git a/sys/src/cmd/python/Modules/zlib/trees.c b/sys/src/cmd/python/Modules/zlib/trees.c new file mode 100644 index 000000000..395e4e168 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/trees.c @@ -0,0 +1,1219 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2005 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include <ctype.h> +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1<<extra_lbits[code]); n++) { + _length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + _length_code[length-1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<<extra_dbits[code]); n++) { + _dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include <stdio.h> +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; +#endif + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (eof) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local void set_data_type(s) + deflate_state *s; +{ + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/sys/src/cmd/python/Modules/zlib/trees.h b/sys/src/cmd/python/Modules/zlib/trees.h new file mode 100644 index 000000000..72facf900 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/sys/src/cmd/python/Modules/zlib/uncompr.c b/sys/src/cmd/python/Modules/zlib/uncompr.c new file mode 100644 index 000000000..b59e3d0de --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/uncompr.c @@ -0,0 +1,61 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/sys/src/cmd/python/Modules/zlib/zconf.h b/sys/src/cmd/python/Modules/zlib/zconf.h new file mode 100644 index 000000000..03a9431c8 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/zconf.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include <windows.h> + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# ifdef VMS +# include <unixio.h> /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/sys/src/cmd/python/Modules/zlib/zconf.in.h b/sys/src/cmd/python/Modules/zlib/zconf.in.h new file mode 100644 index 000000000..03a9431c8 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/zconf.in.h @@ -0,0 +1,332 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define deflateBound z_deflateBound +# define deflatePrime z_deflatePrime +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateCopy z_inflateCopy +# define inflateReset z_inflateReset +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table +# define zError z_zError + +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include <windows.h> + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ +# include <sys/types.h> /* for off_t */ +# include <unistd.h> /* for SEEK_* and off_t */ +# ifdef VMS +# include <unixio.h> /* for off_t */ +# endif +# define z_off_t off_t +#endif +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif +#ifndef z_off_t +# define z_off_t long +#endif + +#if defined(__OS400__) +# define NO_vsnprintf +#endif + +#if defined(__MVS__) +# define NO_vsnprintf +# ifdef FAR +# undef FAR +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) +# pragma map(deflateInit_,"DEIN") +# pragma map(deflateInit2_,"DEIN2") +# pragma map(deflateEnd,"DEEND") +# pragma map(deflateBound,"DEBND") +# pragma map(inflateInit_,"ININ") +# pragma map(inflateInit2_,"ININ2") +# pragma map(inflateEnd,"INEND") +# pragma map(inflateSync,"INSY") +# pragma map(inflateSetDictionary,"INSEDI") +# pragma map(compressBound,"CMBND") +# pragma map(inflate_table,"INTABL") +# pragma map(inflate_fast,"INFA") +# pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/sys/src/cmd/python/Modules/zlib/zlib.3 b/sys/src/cmd/python/Modules/zlib/zlib.3 new file mode 100644 index 000000000..90b816287 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/zlib.3 @@ -0,0 +1,159 @@ +.TH ZLIB 3 "18 July 2005" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms will be added later +and will have the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +(for example if an input file is mmap'ed), +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I example.c +and +.IR minigzip.c . +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source, +and are concerned primarily with bug fixes and portability enhancements. +.LP +A Java implementation of +.I zlib +is available in the Java Development Kit 1.1: +.IP +http://www.javasoft.com/products/JDK/1.1/docs/api/Package-java.util.zip.html +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmqs@cpan.org), +is available at CPAN (Comprehensive Perl Archive Network) sites, +including: +.IP +http://www.cpan.org/modules/by-module/Compress/ +.LP +A Python interface to +.IR zlib , +written by A.M. Kuchling (amk@magnet.com), +is available in Python 1.5 and later versions: +.IP +http://www.python.org/doc/lib/module-zlib.html +.LP +A +.I zlib +binding for +.IR tcl (1), +written by Andreas Kupries (a.kupries@westend.com), +is availlable at: +.IP +http://www.westend.com/~kupries/doc/trf/man/man.html +.LP +An experimental package to read and write files in .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/unzip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +web site. +.SH "SEE ALSO" +The +.I zlib +web site can be found at either of these locations: +.IP +http://www.zlib.org +.br +http://www.gzip.org/zlib/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://www.ietf.org/rfc/rfc1950.txt (concerning zlib format) +.br +http://www.ietf.org/rfc/rfc1951.txt (concerning deflate format) +.br +http://www.ietf.org/rfc/rfc1952.txt (concerning gzip format) +.LP +These documents are also available in other formats from: +.IP +ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html +.LP +Mark Nelson (markn@ieee.org) wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://dogma.net/markn/articles/zlibtool/zlibtool.htm +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://www.gzip.org/zlib/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS +Version 1.2.3 +Copyright (C) 1995-2005 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/sys/src/cmd/python/Modules/zlib/zlib.h b/sys/src/cmd/python/Modules/zlib/zlib.h new file mode 100644 index 000000000..022817927 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/zlib.h @@ -0,0 +1,1357 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.3, July 18th, 2005 + + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + the value returned by deflateBound (see below). If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, + Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() stop + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 + if inflate() is currently decoding the last block in the deflate stream, + plus 128 if inflate() returned immediately after decoding an end-of-block + code or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to strm->next_out. The + number of unused bits may in general be greater than seven, except when + bit 7 of data_type is set, in which case the number of unused bits will be + less than eight. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster approach + may be used for the single inflate() call. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the only effect of the flush parameter in this implementation + is on the return value of inflate(), as noted below, or when it returns early + because Z_BLOCK is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the adler32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the adler32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() will decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically. Any information + contained in the gzip header is not retained, so applications that need that + information should instead use raw inflate, see inflateInit2() below, or + inflateBack() and perform their own processing of the gzip header and + trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may then + call inflateSync() to look for a good compression block if a partial recovery + of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), + no header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as + Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy + parameter only affects the compression ratio but not the correctness of the + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() + or deflateInit2(). This would be used to allocate an output buffer + for deflation in a single pass, and so would be called before deflate(). +*/ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the + bits leftover from a previous deflate stream when appending to it. As such, + this function can only be used for raw deflate, and must be used before the + first deflate() call after a deflateInit2() or deflateReset(). bits must be + less than or equal to 16, and that many of the least significant bits of + value will be inserted in the output. + + deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is + a crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the paramaters are invalid, Z_MEM_ERROR if the internal state could not + be allocated, or Z_VERSION_ERROR if the version of the library does not + match the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is more efficient than inflate() for + file i/o applications in that it avoids copying between the output and the + sliding window by simply making the window itself the output buffer. This + function trusts the application to not change the output buffer passed by + the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free + the allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects + only the raw deflate stream to decompress. This is different from the + normal behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format + error in the deflate stream (in which case strm->msg is set to indicate the + nature of the error), or Z_STREAM_ERROR if the stream was not properly + initialized. In the case of Z_BUF_ERROR, an input or output error can be + distinguished using strm->next_in which will be Z_NULL only if in() returned + an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to + out() returning non-zero. (in() will always be called before out(), so + strm->next_in is assured to be defined if out() returns non-zero.) Note + that inflateBack() cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least the value returned + by compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before + a compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. +*/ + + +typedef voidp gzFile; + +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h", or 'R' for run-length encoding + as in "wb1R". (See the description of deflateInit2 for more information + about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). The number of + uncompressed bytes written is limited to 4095. The caller should assure that + this limit is not exceeded. If it is exceeded, then gzprintf() will return + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read again later. + Only one character of push-back is allowed. gzungetc() returns the + character pushed, or -1 on failure. gzungetc() will fail if a + character has been pushed but not read yet, or if c is -1. The pushed + character will be discarded if the stream is repositioned with gzseek() + or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + + +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z)); +ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void)); + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/sys/src/cmd/python/Modules/zlib/zutil.c b/sys/src/cmd/python/Modules/zlib/zutil.c new file mode 100644 index 000000000..d55f5948a --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/zutil.c @@ -0,0 +1,318 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch (sizeof(uInt)) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch (sizeof(uLong)) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch (sizeof(voidpf)) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch (sizeof(z_off_t)) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#ifdef STDC +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int z_verbose = verbose; + +void z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/sys/src/cmd/python/Modules/zlib/zutil.h b/sys/src/cmd/python/Modules/zlib/zutil.h new file mode 100644 index 000000000..b7d5eff81 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlib/zutil.h @@ -0,0 +1,269 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2005 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#define ZLIB_INTERNAL +#include "zlib.h" + +#ifdef STDC +# ifndef _WIN32_WCE +# include <stddef.h> +# endif +# include <string.h> +# include <stdlib.h> +#endif +#ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif + extern int errno; +#else +# ifndef _WIN32_WCE +# include <errno.h> +# endif +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include <alloc.h> +# endif +# else /* MSC or DJGPP */ +# include <malloc.h> +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# ifdef M_I86 + #include <malloc.h> +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include <unix.h> /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS + /* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 + /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# define vsnprintf _vsnprintf +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +#endif +#ifdef VMS +# define NO_vsnprintf +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include <stdio.h> + extern int z_verbose; + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* ZUTIL_H */ diff --git a/sys/src/cmd/python/Modules/zlibmodule.c b/sys/src/cmd/python/Modules/zlibmodule.c new file mode 100644 index 000000000..da31e8b28 --- /dev/null +++ b/sys/src/cmd/python/Modules/zlibmodule.c @@ -0,0 +1,1027 @@ +/* zlibmodule.c -- gzip-compatible data compression */ +/* See http://www.gzip.org/zlib/ */ + +/* Windows users: read Python's PCbuild\readme.txt */ + + +#include "Python.h" +#include "zlib.h" + +#ifdef WITH_THREAD +#include "pythread.h" + +/* #defs ripped off from _tkinter.c, even though the situation here is much + simpler, because we don't have to worry about waiting for Tcl + events! And, since zlib itself is threadsafe, we don't need to worry + about re-entering zlib functions. + + N.B. + + Since ENTER_ZLIB and LEAVE_ZLIB only need to be called on functions + that modify the components of preexisting de/compress objects, it + could prove to be a performance gain on multiprocessor machines if + there was an de/compress object-specific lock. However, for the + moment the ENTER_ZLIB and LEAVE_ZLIB calls are global for ALL + de/compress objects. + */ + +static PyThread_type_lock zlib_lock = NULL; /* initialized on module load */ + +#define ENTER_ZLIB \ + Py_BEGIN_ALLOW_THREADS \ + PyThread_acquire_lock(zlib_lock, 1); \ + Py_END_ALLOW_THREADS + +#define LEAVE_ZLIB \ + PyThread_release_lock(zlib_lock); + +#else + +#define ENTER_ZLIB +#define LEAVE_ZLIB + +#endif + +/* The following parameters are copied from zutil.h, version 0.95 */ +#define DEFLATED 8 +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#define DEF_WBITS MAX_WBITS + +/* The output buffer will be increased in chunks of DEFAULTALLOC bytes. */ +#define DEFAULTALLOC (16*1024) +#define PyInit_zlib initzlib + +static PyTypeObject Comptype; +static PyTypeObject Decomptype; + +static PyObject *ZlibError; + +typedef struct +{ + PyObject_HEAD + z_stream zst; + PyObject *unused_data; + PyObject *unconsumed_tail; + int is_initialised; +} compobject; + +static void +zlib_error(z_stream zst, int err, char *msg) +{ + if (zst.msg == Z_NULL) + PyErr_Format(ZlibError, "Error %d %s", err, msg); + else + PyErr_Format(ZlibError, "Error %d %s: %.200s", err, msg, zst.msg); +} + +PyDoc_STRVAR(compressobj__doc__, +"compressobj([level]) -- Return a compressor object.\n" +"\n" +"Optional arg level is the compression level, in 1-9."); + +PyDoc_STRVAR(decompressobj__doc__, +"decompressobj([wbits]) -- Return a decompressor object.\n" +"\n" +"Optional arg wbits is the window buffer size."); + +static compobject * +newcompobject(PyTypeObject *type) +{ + compobject *self; + self = PyObject_New(compobject, type); + if (self == NULL) + return NULL; + self->is_initialised = 0; + self->unused_data = PyString_FromString(""); + if (self->unused_data == NULL) { + Py_DECREF(self); + return NULL; + } + self->unconsumed_tail = PyString_FromString(""); + if (self->unconsumed_tail == NULL) { + Py_DECREF(self); + return NULL; + } + return self; +} + +PyDoc_STRVAR(compress__doc__, +"compress(string[, level]) -- Returned compressed string.\n" +"\n" +"Optional arg level is the compression level, in 1-9."); + +static PyObject * +PyZlib_compress(PyObject *self, PyObject *args) +{ + PyObject *ReturnVal = NULL; + Byte *input, *output; + int length, level=Z_DEFAULT_COMPRESSION, err; + z_stream zst; + + /* require Python string object, optional 'level' arg */ + if (!PyArg_ParseTuple(args, "s#|i:compress", &input, &length, &level)) + return NULL; + + zst.avail_out = length + length/1000 + 12 + 1; + + output = (Byte*)malloc(zst.avail_out); + if (output == NULL) { + PyErr_SetString(PyExc_MemoryError, + "Can't allocate memory to compress data"); + return NULL; + } + + /* Past the point of no return. From here on out, we need to make sure + we clean up mallocs & INCREFs. */ + + zst.zalloc = (alloc_func)NULL; + zst.zfree = (free_func)Z_NULL; + zst.next_out = (Byte *)output; + zst.next_in = (Byte *)input; + zst.avail_in = length; + err = deflateInit(&zst, level); + + switch(err) { + case(Z_OK): + break; + case(Z_MEM_ERROR): + PyErr_SetString(PyExc_MemoryError, + "Out of memory while compressing data"); + goto error; + case(Z_STREAM_ERROR): + PyErr_SetString(ZlibError, + "Bad compression level"); + goto error; + default: + deflateEnd(&zst); + zlib_error(zst, err, "while compressing data"); + goto error; + } + + Py_BEGIN_ALLOW_THREADS; + err = deflate(&zst, Z_FINISH); + Py_END_ALLOW_THREADS; + + if (err != Z_STREAM_END) { + zlib_error(zst, err, "while compressing data"); + deflateEnd(&zst); + goto error; + } + + err=deflateEnd(&zst); + if (err == Z_OK) + ReturnVal = PyString_FromStringAndSize((char *)output, + zst.total_out); + else + zlib_error(zst, err, "while finishing compression"); + + error: + free(output); + + return ReturnVal; +} + +PyDoc_STRVAR(decompress__doc__, +"decompress(string[, wbits[, bufsize]]) -- Return decompressed string.\n" +"\n" +"Optional arg wbits is the window buffer size. Optional arg bufsize is\n" +"the initial output buffer size."); + +static PyObject * +PyZlib_decompress(PyObject *self, PyObject *args) +{ + PyObject *result_str; + Byte *input; + int length, err; + int wsize=DEF_WBITS, r_strlen=DEFAULTALLOC; + z_stream zst; + + if (!PyArg_ParseTuple(args, "s#|ii:decompress", + &input, &length, &wsize, &r_strlen)) + return NULL; + + if (r_strlen <= 0) + r_strlen = 1; + + zst.avail_in = length; + zst.avail_out = r_strlen; + + if (!(result_str = PyString_FromStringAndSize(NULL, r_strlen))) + return NULL; + + zst.zalloc = (alloc_func)NULL; + zst.zfree = (free_func)Z_NULL; + zst.next_out = (Byte *)PyString_AS_STRING(result_str); + zst.next_in = (Byte *)input; + err = inflateInit2(&zst, wsize); + + switch(err) { + case(Z_OK): + break; + case(Z_MEM_ERROR): + PyErr_SetString(PyExc_MemoryError, + "Out of memory while decompressing data"); + goto error; + default: + inflateEnd(&zst); + zlib_error(zst, err, "while preparing to decompress data"); + goto error; + } + + do { + Py_BEGIN_ALLOW_THREADS + err=inflate(&zst, Z_FINISH); + Py_END_ALLOW_THREADS + + switch(err) { + case(Z_STREAM_END): + break; + case(Z_BUF_ERROR): + /* + * If there is at least 1 byte of room according to zst.avail_out + * and we get this error, assume that it means zlib cannot + * process the inflate call() due to an error in the data. + */ + if (zst.avail_out > 0) { + PyErr_Format(ZlibError, "Error %i while decompressing data", + err); + inflateEnd(&zst); + goto error; + } + /* fall through */ + case(Z_OK): + /* need more memory */ + if (_PyString_Resize(&result_str, r_strlen << 1) < 0) { + inflateEnd(&zst); + goto error; + } + zst.next_out = (unsigned char *)PyString_AS_STRING(result_str) \ + + r_strlen; + zst.avail_out = r_strlen; + r_strlen = r_strlen << 1; + break; + default: + inflateEnd(&zst); + zlib_error(zst, err, "while decompressing data"); + goto error; + } + } while (err != Z_STREAM_END); + + err = inflateEnd(&zst); + if (err != Z_OK) { + zlib_error(zst, err, "while finishing data decompression"); + goto error; + } + + _PyString_Resize(&result_str, zst.total_out); + return result_str; + + error: + Py_XDECREF(result_str); + return NULL; +} + +static PyObject * +PyZlib_compressobj(PyObject *selfptr, PyObject *args) +{ + compobject *self; + int level=Z_DEFAULT_COMPRESSION, method=DEFLATED; + int wbits=MAX_WBITS, memLevel=DEF_MEM_LEVEL, strategy=0, err; + + if (!PyArg_ParseTuple(args, "|iiiii:compressobj", &level, &method, &wbits, + &memLevel, &strategy)) + return NULL; + + self = newcompobject(&Comptype); + if (self==NULL) + return(NULL); + self->zst.zalloc = (alloc_func)NULL; + self->zst.zfree = (free_func)Z_NULL; + self->zst.next_in = NULL; + self->zst.avail_in = 0; + err = deflateInit2(&self->zst, level, method, wbits, memLevel, strategy); + switch(err) { + case (Z_OK): + self->is_initialised = 1; + return (PyObject*)self; + case (Z_MEM_ERROR): + Py_DECREF(self); + PyErr_SetString(PyExc_MemoryError, + "Can't allocate memory for compression object"); + return NULL; + case(Z_STREAM_ERROR): + Py_DECREF(self); + PyErr_SetString(PyExc_ValueError, "Invalid initialization option"); + return NULL; + default: + zlib_error(self->zst, err, "while creating compression object"); + Py_DECREF(self); + return NULL; + } +} + +static PyObject * +PyZlib_decompressobj(PyObject *selfptr, PyObject *args) +{ + int wbits=DEF_WBITS, err; + compobject *self; + if (!PyArg_ParseTuple(args, "|i:decompressobj", &wbits)) + return NULL; + + self = newcompobject(&Decomptype); + if (self == NULL) + return(NULL); + self->zst.zalloc = (alloc_func)NULL; + self->zst.zfree = (free_func)Z_NULL; + self->zst.next_in = NULL; + self->zst.avail_in = 0; + err = inflateInit2(&self->zst, wbits); + switch(err) { + case (Z_OK): + self->is_initialised = 1; + return (PyObject*)self; + case(Z_STREAM_ERROR): + Py_DECREF(self); + PyErr_SetString(PyExc_ValueError, "Invalid initialization option"); + return NULL; + case (Z_MEM_ERROR): + Py_DECREF(self); + PyErr_SetString(PyExc_MemoryError, + "Can't allocate memory for decompression object"); + return NULL; + default: + zlib_error(self->zst, err, "while creating decompression object"); + Py_DECREF(self); + return NULL; + } +} + +static void +Comp_dealloc(compobject *self) +{ + if (self->is_initialised) + deflateEnd(&self->zst); + Py_XDECREF(self->unused_data); + Py_XDECREF(self->unconsumed_tail); + PyObject_Del(self); +} + +static void +Decomp_dealloc(compobject *self) +{ + if (self->is_initialised) + inflateEnd(&self->zst); + Py_XDECREF(self->unused_data); + Py_XDECREF(self->unconsumed_tail); + PyObject_Del(self); +} + +PyDoc_STRVAR(comp_compress__doc__, +"compress(data) -- Return a string containing data compressed.\n" +"\n" +"After calling this function, some of the input data may still\n" +"be stored in internal buffers for later processing.\n" +"Call the flush() method to clear these buffers."); + + +static PyObject * +PyZlib_objcompress(compobject *self, PyObject *args) +{ + int err, inplen, length = DEFAULTALLOC; + PyObject *RetVal; + Byte *input; + unsigned long start_total_out; + + if (!PyArg_ParseTuple(args, "s#:compress", &input, &inplen)) + return NULL; + + if (!(RetVal = PyString_FromStringAndSize(NULL, length))) + return NULL; + + ENTER_ZLIB + + start_total_out = self->zst.total_out; + self->zst.avail_in = inplen; + self->zst.next_in = input; + self->zst.avail_out = length; + self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal); + + Py_BEGIN_ALLOW_THREADS + err = deflate(&(self->zst), Z_NO_FLUSH); + Py_END_ALLOW_THREADS + + /* while Z_OK and the output buffer is full, there might be more output, + so extend the output buffer and try again */ + while (err == Z_OK && self->zst.avail_out == 0) { + if (_PyString_Resize(&RetVal, length << 1) < 0) + goto error; + self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal) \ + + length; + self->zst.avail_out = length; + length = length << 1; + + Py_BEGIN_ALLOW_THREADS + err = deflate(&(self->zst), Z_NO_FLUSH); + Py_END_ALLOW_THREADS + } + /* We will only get Z_BUF_ERROR if the output buffer was full but + there wasn't more output when we tried again, so it is not an error + condition. + */ + + if (err != Z_OK && err != Z_BUF_ERROR) { + zlib_error(self->zst, err, "while compressing"); + Py_DECREF(RetVal); + RetVal = NULL; + goto error; + } + _PyString_Resize(&RetVal, self->zst.total_out - start_total_out); + + error: + LEAVE_ZLIB + return RetVal; +} + +PyDoc_STRVAR(decomp_decompress__doc__, +"decompress(data, max_length) -- Return a string containing the decompressed\n" +"version of the data.\n" +"\n" +"After calling this function, some of the input data may still be stored in\n" +"internal buffers for later processing.\n" +"Call the flush() method to clear these buffers.\n" +"If the max_length parameter is specified then the return value will be\n" +"no longer than max_length. Unconsumed input data will be stored in\n" +"the unconsumed_tail attribute."); + +static PyObject * +PyZlib_objdecompress(compobject *self, PyObject *args) +{ + int err, inplen, old_length, length = DEFAULTALLOC; + int max_length = 0; + PyObject *RetVal; + Byte *input; + unsigned long start_total_out; + + if (!PyArg_ParseTuple(args, "s#|i:decompress", &input, + &inplen, &max_length)) + return NULL; + if (max_length < 0) { + PyErr_SetString(PyExc_ValueError, + "max_length must be greater than zero"); + return NULL; + } + + /* limit amount of data allocated to max_length */ + if (max_length && length > max_length) + length = max_length; + if (!(RetVal = PyString_FromStringAndSize(NULL, length))) + return NULL; + + ENTER_ZLIB + + start_total_out = self->zst.total_out; + self->zst.avail_in = inplen; + self->zst.next_in = input; + self->zst.avail_out = length; + self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal); + + Py_BEGIN_ALLOW_THREADS + err = inflate(&(self->zst), Z_SYNC_FLUSH); + Py_END_ALLOW_THREADS + + /* While Z_OK and the output buffer is full, there might be more output. + So extend the output buffer and try again. + */ + while (err == Z_OK && self->zst.avail_out == 0) { + /* If max_length set, don't continue decompressing if we've already + reached the limit. + */ + if (max_length && length >= max_length) + break; + + /* otherwise, ... */ + old_length = length; + length = length << 1; + if (max_length && length > max_length) + length = max_length; + + if (_PyString_Resize(&RetVal, length) < 0) + goto error; + self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal) \ + + old_length; + self->zst.avail_out = length - old_length; + + Py_BEGIN_ALLOW_THREADS + err = inflate(&(self->zst), Z_SYNC_FLUSH); + Py_END_ALLOW_THREADS + } + + /* Not all of the compressed data could be accommodated in the output buffer + of specified size. Return the unconsumed tail in an attribute.*/ + if(max_length) { + Py_DECREF(self->unconsumed_tail); + self->unconsumed_tail = PyString_FromStringAndSize((char *)self->zst.next_in, + self->zst.avail_in); + if(!self->unconsumed_tail) { + Py_DECREF(RetVal); + RetVal = NULL; + goto error; + } + } + + /* The end of the compressed data has been reached, so set the + unused_data attribute to a string containing the remainder of the + data in the string. Note that this is also a logical place to call + inflateEnd, but the old behaviour of only calling it on flush() is + preserved. + */ + if (err == Z_STREAM_END) { + Py_XDECREF(self->unused_data); /* Free original empty string */ + self->unused_data = PyString_FromStringAndSize( + (char *)self->zst.next_in, self->zst.avail_in); + if (self->unused_data == NULL) { + Py_DECREF(RetVal); + goto error; + } + /* We will only get Z_BUF_ERROR if the output buffer was full + but there wasn't more output when we tried again, so it is + not an error condition. + */ + } else if (err != Z_OK && err != Z_BUF_ERROR) { + zlib_error(self->zst, err, "while decompressing"); + Py_DECREF(RetVal); + RetVal = NULL; + goto error; + } + + _PyString_Resize(&RetVal, self->zst.total_out - start_total_out); + + error: + LEAVE_ZLIB + + return RetVal; +} + +PyDoc_STRVAR(comp_flush__doc__, +"flush( [mode] ) -- Return a string containing any remaining compressed data.\n" +"\n" +"mode can be one of the constants Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH; the\n" +"default value used when mode is not specified is Z_FINISH.\n" +"If mode == Z_FINISH, the compressor object can no longer be used after\n" +"calling the flush() method. Otherwise, more data can still be compressed."); + +static PyObject * +PyZlib_flush(compobject *self, PyObject *args) +{ + int err, length = DEFAULTALLOC; + PyObject *RetVal; + int flushmode = Z_FINISH; + unsigned long start_total_out; + + if (!PyArg_ParseTuple(args, "|i:flush", &flushmode)) + return NULL; + + /* Flushing with Z_NO_FLUSH is a no-op, so there's no point in + doing any work at all; just return an empty string. */ + if (flushmode == Z_NO_FLUSH) { + return PyString_FromStringAndSize(NULL, 0); + } + + if (!(RetVal = PyString_FromStringAndSize(NULL, length))) + return NULL; + + ENTER_ZLIB + + start_total_out = self->zst.total_out; + self->zst.avail_in = 0; + self->zst.avail_out = length; + self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal); + + Py_BEGIN_ALLOW_THREADS + err = deflate(&(self->zst), flushmode); + Py_END_ALLOW_THREADS + + /* while Z_OK and the output buffer is full, there might be more output, + so extend the output buffer and try again */ + while (err == Z_OK && self->zst.avail_out == 0) { + if (_PyString_Resize(&RetVal, length << 1) < 0) + goto error; + self->zst.next_out = (unsigned char *)PyString_AS_STRING(RetVal) \ + + length; + self->zst.avail_out = length; + length = length << 1; + + Py_BEGIN_ALLOW_THREADS + err = deflate(&(self->zst), flushmode); + Py_END_ALLOW_THREADS + } + + /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free + various data structures. Note we should only get Z_STREAM_END when + flushmode is Z_FINISH, but checking both for safety*/ + if (err == Z_STREAM_END && flushmode == Z_FINISH) { + err = deflateEnd(&(self->zst)); + if (err != Z_OK) { + zlib_error(self->zst, err, "from deflateEnd()"); + Py_DECREF(RetVal); + RetVal = NULL; + goto error; + } + else + self->is_initialised = 0; + + /* We will only get Z_BUF_ERROR if the output buffer was full + but there wasn't more output when we tried again, so it is + not an error condition. + */ + } else if (err!=Z_OK && err!=Z_BUF_ERROR) { + zlib_error(self->zst, err, "while flushing"); + Py_DECREF(RetVal); + RetVal = NULL; + goto error; + } + + _PyString_Resize(&RetVal, self->zst.total_out - start_total_out); + + error: + LEAVE_ZLIB + + return RetVal; +} + +#ifdef HAVE_ZLIB_COPY +PyDoc_STRVAR(comp_copy__doc__, +"copy() -- Return a copy of the compression object."); + +static PyObject * +PyZlib_copy(compobject *self) +{ + compobject *retval = NULL; + int err; + + retval = newcompobject(&Comptype); + if (!retval) return NULL; + + /* Copy the zstream state + * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe + */ + ENTER_ZLIB + err = deflateCopy(&retval->zst, &self->zst); + switch(err) { + case(Z_OK): + break; + case(Z_STREAM_ERROR): + PyErr_SetString(PyExc_ValueError, "Inconsistent stream state"); + goto error; + case(Z_MEM_ERROR): + PyErr_SetString(PyExc_MemoryError, + "Can't allocate memory for compression object"); + goto error; + default: + zlib_error(self->zst, err, "while copying compression object"); + goto error; + } + + Py_INCREF(self->unused_data); + Py_INCREF(self->unconsumed_tail); + Py_XDECREF(retval->unused_data); + Py_XDECREF(retval->unconsumed_tail); + retval->unused_data = self->unused_data; + retval->unconsumed_tail = self->unconsumed_tail; + + /* Mark it as being initialized */ + retval->is_initialised = 1; + + LEAVE_ZLIB + return (PyObject *)retval; + +error: + LEAVE_ZLIB + Py_XDECREF(retval); + return NULL; +} + +PyDoc_STRVAR(decomp_copy__doc__, +"copy() -- Return a copy of the decompression object."); + +static PyObject * +PyZlib_uncopy(compobject *self) +{ + compobject *retval = NULL; + int err; + + retval = newcompobject(&Decomptype); + if (!retval) return NULL; + + /* Copy the zstream state + * We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe + */ + ENTER_ZLIB + err = inflateCopy(&retval->zst, &self->zst); + switch(err) { + case(Z_OK): + break; + case(Z_STREAM_ERROR): + PyErr_SetString(PyExc_ValueError, "Inconsistent stream state"); + goto error; + case(Z_MEM_ERROR): + PyErr_SetString(PyExc_MemoryError, + "Can't allocate memory for decompression object"); + goto error; + default: + zlib_error(self->zst, err, "while copying decompression object"); + goto error; + } + + Py_INCREF(self->unused_data); + Py_INCREF(self->unconsumed_tail); + Py_XDECREF(retval->unused_data); + Py_XDECREF(retval->unconsumed_tail); + retval->unused_data = self->unused_data; + retval->unconsumed_tail = self->unconsumed_tail; + + /* Mark it as being initialized */ + retval->is_initialised = 1; + + LEAVE_ZLIB + return (PyObject *)retval; + +error: + LEAVE_ZLIB + Py_XDECREF(retval); + return NULL; +} +#endif + +PyDoc_STRVAR(decomp_flush__doc__, +"flush( [length] ) -- Return a string containing any remaining\n" +"decompressed data. length, if given, is the initial size of the\n" +"output buffer.\n" +"\n" +"The decompressor object can no longer be used after this call."); + +static PyObject * +PyZlib_unflush(compobject *self, PyObject *args) +{ + int err, length = DEFAULTALLOC; + PyObject * retval = NULL; + unsigned long start_total_out; + + if (!PyArg_ParseTuple(args, "|i:flush", &length)) + return NULL; + if (!(retval = PyString_FromStringAndSize(NULL, length))) + return NULL; + + + ENTER_ZLIB + + start_total_out = self->zst.total_out; + self->zst.avail_out = length; + self->zst.next_out = (Byte *)PyString_AS_STRING(retval); + + Py_BEGIN_ALLOW_THREADS + err = inflate(&(self->zst), Z_FINISH); + Py_END_ALLOW_THREADS + + /* while Z_OK and the output buffer is full, there might be more output, + so extend the output buffer and try again */ + while ((err == Z_OK || err == Z_BUF_ERROR) && self->zst.avail_out == 0) { + if (_PyString_Resize(&retval, length << 1) < 0) + goto error; + self->zst.next_out = (Byte *)PyString_AS_STRING(retval) + length; + self->zst.avail_out = length; + length = length << 1; + + Py_BEGIN_ALLOW_THREADS + err = inflate(&(self->zst), Z_FINISH); + Py_END_ALLOW_THREADS + } + + /* If flushmode is Z_FINISH, we also have to call deflateEnd() to free + various data structures. Note we should only get Z_STREAM_END when + flushmode is Z_FINISH */ + if (err == Z_STREAM_END) { + err = inflateEnd(&(self->zst)); + self->is_initialised = 0; + if (err != Z_OK) { + zlib_error(self->zst, err, "from inflateEnd()"); + Py_DECREF(retval); + retval = NULL; + goto error; + } + } + _PyString_Resize(&retval, self->zst.total_out - start_total_out); + +error: + + LEAVE_ZLIB + + return retval; +} + +static PyMethodDef comp_methods[] = +{ + {"compress", (binaryfunc)PyZlib_objcompress, METH_VARARGS, + comp_compress__doc__}, + {"flush", (binaryfunc)PyZlib_flush, METH_VARARGS, + comp_flush__doc__}, +#ifdef HAVE_ZLIB_COPY + {"copy", (PyCFunction)PyZlib_copy, METH_NOARGS, + comp_copy__doc__}, +#endif + {NULL, NULL} +}; + +static PyMethodDef Decomp_methods[] = +{ + {"decompress", (binaryfunc)PyZlib_objdecompress, METH_VARARGS, + decomp_decompress__doc__}, + {"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS, + decomp_flush__doc__}, +#ifdef HAVE_ZLIB_COPY + {"copy", (PyCFunction)PyZlib_uncopy, METH_NOARGS, + decomp_copy__doc__}, +#endif + {NULL, NULL} +}; + +static PyObject * +Comp_getattr(compobject *self, char *name) +{ + /* No ENTER/LEAVE_ZLIB is necessary because this fn doesn't touch + internal data. */ + + return Py_FindMethod(comp_methods, (PyObject *)self, name); +} + +static PyObject * +Decomp_getattr(compobject *self, char *name) +{ + PyObject * retval; + + ENTER_ZLIB + + if (strcmp(name, "unused_data") == 0) { + Py_INCREF(self->unused_data); + retval = self->unused_data; + } else if (strcmp(name, "unconsumed_tail") == 0) { + Py_INCREF(self->unconsumed_tail); + retval = self->unconsumed_tail; + } else + retval = Py_FindMethod(Decomp_methods, (PyObject *)self, name); + + LEAVE_ZLIB + + return retval; +} + +PyDoc_STRVAR(adler32__doc__, +"adler32(string[, start]) -- Compute an Adler-32 checksum of string.\n" +"\n" +"An optional starting value can be specified. The returned checksum is\n" +"an integer."); + +static PyObject * +PyZlib_adler32(PyObject *self, PyObject *args) +{ + uLong adler32val = adler32(0L, Z_NULL, 0); + Byte *buf; + int len; + + if (!PyArg_ParseTuple(args, "s#|k:adler32", &buf, &len, &adler32val)) + return NULL; + adler32val = adler32(adler32val, buf, len); + return PyInt_FromLong(adler32val); +} + +PyDoc_STRVAR(crc32__doc__, +"crc32(string[, start]) -- Compute a CRC-32 checksum of string.\n" +"\n" +"An optional starting value can be specified. The returned checksum is\n" +"an integer."); + +static PyObject * +PyZlib_crc32(PyObject *self, PyObject *args) +{ + uLong crc32val = crc32(0L, Z_NULL, 0); + Byte *buf; + int len; + if (!PyArg_ParseTuple(args, "s#|k:crc32", &buf, &len, &crc32val)) + return NULL; + crc32val = crc32(crc32val, buf, len); + return PyInt_FromLong(crc32val); +} + + +static PyMethodDef zlib_methods[] = +{ + {"adler32", (PyCFunction)PyZlib_adler32, METH_VARARGS, + adler32__doc__}, + {"compress", (PyCFunction)PyZlib_compress, METH_VARARGS, + compress__doc__}, + {"compressobj", (PyCFunction)PyZlib_compressobj, METH_VARARGS, + compressobj__doc__}, + {"crc32", (PyCFunction)PyZlib_crc32, METH_VARARGS, + crc32__doc__}, + {"decompress", (PyCFunction)PyZlib_decompress, METH_VARARGS, + decompress__doc__}, + {"decompressobj", (PyCFunction)PyZlib_decompressobj, METH_VARARGS, + decompressobj__doc__}, + {NULL, NULL} +}; + +static PyTypeObject Comptype = { + PyObject_HEAD_INIT(0) + 0, + "zlib.Compress", + sizeof(compobject), + 0, + (destructor)Comp_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)Comp_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +static PyTypeObject Decomptype = { + PyObject_HEAD_INIT(0) + 0, + "zlib.Decompress", + sizeof(compobject), + 0, + (destructor)Decomp_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)Decomp_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ +}; + +PyDoc_STRVAR(zlib_module_documentation, +"The functions in this module allow compression and decompression using the\n" +"zlib library, which is based on GNU zip.\n" +"\n" +"adler32(string[, start]) -- Compute an Adler-32 checksum.\n" +"compress(string[, level]) -- Compress string, with compression level in 1-9.\n" +"compressobj([level]) -- Return a compressor object.\n" +"crc32(string[, start]) -- Compute a CRC-32 checksum.\n" +"decompress(string,[wbits],[bufsize]) -- Decompresses a compressed string.\n" +"decompressobj([wbits]) -- Return a decompressor object.\n" +"\n" +"'wbits' is window buffer size.\n" +"Compressor objects support compress() and flush() methods; decompressor\n" +"objects support decompress() and flush()."); + +PyMODINIT_FUNC +PyInit_zlib(void) +{ + PyObject *m, *ver; + Comptype.ob_type = &PyType_Type; + Decomptype.ob_type = &PyType_Type; + m = Py_InitModule4("zlib", zlib_methods, + zlib_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); + if (m == NULL) + return; + + ZlibError = PyErr_NewException("zlib.error", NULL, NULL); + if (ZlibError != NULL) { + Py_INCREF(ZlibError); + PyModule_AddObject(m, "error", ZlibError); + } + PyModule_AddIntConstant(m, "MAX_WBITS", MAX_WBITS); + PyModule_AddIntConstant(m, "DEFLATED", DEFLATED); + PyModule_AddIntConstant(m, "DEF_MEM_LEVEL", DEF_MEM_LEVEL); + PyModule_AddIntConstant(m, "Z_BEST_SPEED", Z_BEST_SPEED); + PyModule_AddIntConstant(m, "Z_BEST_COMPRESSION", Z_BEST_COMPRESSION); + PyModule_AddIntConstant(m, "Z_DEFAULT_COMPRESSION", Z_DEFAULT_COMPRESSION); + PyModule_AddIntConstant(m, "Z_FILTERED", Z_FILTERED); + PyModule_AddIntConstant(m, "Z_HUFFMAN_ONLY", Z_HUFFMAN_ONLY); + PyModule_AddIntConstant(m, "Z_DEFAULT_STRATEGY", Z_DEFAULT_STRATEGY); + + PyModule_AddIntConstant(m, "Z_FINISH", Z_FINISH); + PyModule_AddIntConstant(m, "Z_NO_FLUSH", Z_NO_FLUSH); + PyModule_AddIntConstant(m, "Z_SYNC_FLUSH", Z_SYNC_FLUSH); + PyModule_AddIntConstant(m, "Z_FULL_FLUSH", Z_FULL_FLUSH); + + ver = PyString_FromString(ZLIB_VERSION); + if (ver != NULL) + PyModule_AddObject(m, "ZLIB_VERSION", ver); + + PyModule_AddStringConstant(m, "__version__", "1.0"); + +#ifdef WITH_THREAD + zlib_lock = PyThread_allocate_lock(); +#endif /* WITH_THREAD */ +} diff --git a/sys/src/cmd/python/Objects/abstract.c b/sys/src/cmd/python/Objects/abstract.c new file mode 100644 index 000000000..f7a3bfefb --- /dev/null +++ b/sys/src/cmd/python/Objects/abstract.c @@ -0,0 +1,2381 @@ +/* Abstract Object Interface (many thanks to Jim Fulton) */ + +#include "Python.h" +#include <ctype.h> +#include "structmember.h" /* we need the offsetof() macro from there */ +#include "longintrepr.h" + +#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \ + Py_TPFLAGS_CHECKTYPES) + + +/* Shorthands to return certain errors */ + +static PyObject * +type_error(const char *msg, PyObject *obj) +{ + PyErr_Format(PyExc_TypeError, msg, obj->ob_type->tp_name); + return NULL; +} + +static PyObject * +null_error(void) +{ + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "null argument to internal routine"); + return NULL; +} + +/* Operations on any object */ + +int +PyObject_Cmp(PyObject *o1, PyObject *o2, int *result) +{ + int r; + + if (o1 == NULL || o2 == NULL) { + null_error(); + return -1; + } + r = PyObject_Compare(o1, o2); + if (PyErr_Occurred()) + return -1; + *result = r; + return 0; +} + +PyObject * +PyObject_Type(PyObject *o) +{ + PyObject *v; + + if (o == NULL) + return null_error(); + v = (PyObject *)o->ob_type; + Py_INCREF(v); + return v; +} + +Py_ssize_t +PyObject_Size(PyObject *o) +{ + PySequenceMethods *m; + + if (o == NULL) { + null_error(); + return -1; + } + + m = o->ob_type->tp_as_sequence; + if (m && m->sq_length) + return m->sq_length(o); + + return PyMapping_Size(o); +} + +#undef PyObject_Length +Py_ssize_t +PyObject_Length(PyObject *o) +{ + return PyObject_Size(o); +} +#define PyObject_Length PyObject_Size + +Py_ssize_t +_PyObject_LengthHint(PyObject *o) +{ + Py_ssize_t rv = PyObject_Size(o); + if (rv != -1) + return rv; + if (PyErr_ExceptionMatches(PyExc_TypeError) || + PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyObject *err_type, *err_value, *err_tb, *ro; + + PyErr_Fetch(&err_type, &err_value, &err_tb); + ro = PyObject_CallMethod(o, "__length_hint__", NULL); + if (ro != NULL) { + rv = PyInt_AsLong(ro); + Py_DECREF(ro); + Py_XDECREF(err_type); + Py_XDECREF(err_value); + Py_XDECREF(err_tb); + return rv; + } + PyErr_Restore(err_type, err_value, err_tb); + } + return -1; +} + +PyObject * +PyObject_GetItem(PyObject *o, PyObject *key) +{ + PyMappingMethods *m; + + if (o == NULL || key == NULL) + return null_error(); + + m = o->ob_type->tp_as_mapping; + if (m && m->mp_subscript) + return m->mp_subscript(o, key); + + if (o->ob_type->tp_as_sequence) { + if (PyIndex_Check(key)) { + Py_ssize_t key_value; + key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (key_value == -1 && PyErr_Occurred()) + return NULL; + return PySequence_GetItem(o, key_value); + } + else if (o->ob_type->tp_as_sequence->sq_item) + return type_error("sequence index must " + "be integer, not '%.200s'", key); + } + + return type_error("'%.200s' object is unsubscriptable", o); +} + +int +PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) +{ + PyMappingMethods *m; + + if (o == NULL || key == NULL || value == NULL) { + null_error(); + return -1; + } + m = o->ob_type->tp_as_mapping; + if (m && m->mp_ass_subscript) + return m->mp_ass_subscript(o, key, value); + + if (o->ob_type->tp_as_sequence) { + if (PyIndex_Check(key)) { + Py_ssize_t key_value; + key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (key_value == -1 && PyErr_Occurred()) + return -1; + return PySequence_SetItem(o, key_value, value); + } + else if (o->ob_type->tp_as_sequence->sq_ass_item) { + type_error("sequence index must be " + "integer, not '%.200s'", key); + return -1; + } + } + + type_error("'%.200s' object does not support item assignment", o); + return -1; +} + +int +PyObject_DelItem(PyObject *o, PyObject *key) +{ + PyMappingMethods *m; + + if (o == NULL || key == NULL) { + null_error(); + return -1; + } + m = o->ob_type->tp_as_mapping; + if (m && m->mp_ass_subscript) + return m->mp_ass_subscript(o, key, (PyObject*)NULL); + + if (o->ob_type->tp_as_sequence) { + if (PyIndex_Check(key)) { + Py_ssize_t key_value; + key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); + if (key_value == -1 && PyErr_Occurred()) + return -1; + return PySequence_DelItem(o, key_value); + } + else if (o->ob_type->tp_as_sequence->sq_ass_item) { + type_error("sequence index must be " + "integer, not '%.200s'", key); + return -1; + } + } + + type_error("'%.200s' object does not support item deletion", o); + return -1; +} + +int +PyObject_DelItemString(PyObject *o, char *key) +{ + PyObject *okey; + int ret; + + if (o == NULL || key == NULL) { + null_error(); + return -1; + } + okey = PyString_FromString(key); + if (okey == NULL) + return -1; + ret = PyObject_DelItem(o, okey); + Py_DECREF(okey); + return ret; +} + +int +PyObject_AsCharBuffer(PyObject *obj, + const char **buffer, + Py_ssize_t *buffer_len) +{ + PyBufferProcs *pb; + char *pp; + Py_ssize_t len; + + if (obj == NULL || buffer == NULL || buffer_len == NULL) { + null_error(); + return -1; + } + pb = obj->ob_type->tp_as_buffer; + if (pb == NULL || + pb->bf_getcharbuffer == NULL || + pb->bf_getsegcount == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a character buffer object"); + return -1; + } + if ((*pb->bf_getsegcount)(obj,NULL) != 1) { + PyErr_SetString(PyExc_TypeError, + "expected a single-segment buffer object"); + return -1; + } + len = (*pb->bf_getcharbuffer)(obj, 0, &pp); + if (len < 0) + return -1; + *buffer = pp; + *buffer_len = len; + return 0; +} + +int +PyObject_CheckReadBuffer(PyObject *obj) +{ + PyBufferProcs *pb = obj->ob_type->tp_as_buffer; + + if (pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL || + (*pb->bf_getsegcount)(obj, NULL) != 1) + return 0; + return 1; +} + +int PyObject_AsReadBuffer(PyObject *obj, + const void **buffer, + Py_ssize_t *buffer_len) +{ + PyBufferProcs *pb; + void *pp; + Py_ssize_t len; + + if (obj == NULL || buffer == NULL || buffer_len == NULL) { + null_error(); + return -1; + } + pb = obj->ob_type->tp_as_buffer; + if (pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a readable buffer object"); + return -1; + } + if ((*pb->bf_getsegcount)(obj, NULL) != 1) { + PyErr_SetString(PyExc_TypeError, + "expected a single-segment buffer object"); + return -1; + } + len = (*pb->bf_getreadbuffer)(obj, 0, &pp); + if (len < 0) + return -1; + *buffer = pp; + *buffer_len = len; + return 0; +} + +int PyObject_AsWriteBuffer(PyObject *obj, + void **buffer, + Py_ssize_t *buffer_len) +{ + PyBufferProcs *pb; + void*pp; + Py_ssize_t len; + + if (obj == NULL || buffer == NULL || buffer_len == NULL) { + null_error(); + return -1; + } + pb = obj->ob_type->tp_as_buffer; + if (pb == NULL || + pb->bf_getwritebuffer == NULL || + pb->bf_getsegcount == NULL) { + PyErr_SetString(PyExc_TypeError, + "expected a writeable buffer object"); + return -1; + } + if ((*pb->bf_getsegcount)(obj, NULL) != 1) { + PyErr_SetString(PyExc_TypeError, + "expected a single-segment buffer object"); + return -1; + } + len = (*pb->bf_getwritebuffer)(obj,0,&pp); + if (len < 0) + return -1; + *buffer = pp; + *buffer_len = len; + return 0; +} + +/* Operations on numbers */ + +int +PyNumber_Check(PyObject *o) +{ + return o && o->ob_type->tp_as_number && + (o->ob_type->tp_as_number->nb_int || + o->ob_type->tp_as_number->nb_float); +} + +/* Binary operators */ + +/* New style number protocol support */ + +#define NB_SLOT(x) offsetof(PyNumberMethods, x) +#define NB_BINOP(nb_methods, slot) \ + (*(binaryfunc*)(& ((char*)nb_methods)[slot])) +#define NB_TERNOP(nb_methods, slot) \ + (*(ternaryfunc*)(& ((char*)nb_methods)[slot])) + +/* + Calling scheme used for binary operations: + + v w Action + ------------------------------------------------------------------- + new new w.op(v,w)[*], v.op(v,w), w.op(v,w) + new old v.op(v,w), coerce(v,w), v.op(v,w) + old new w.op(v,w), coerce(v,w), v.op(v,w) + old old coerce(v,w), v.op(v,w) + + [*] only when v->ob_type != w->ob_type && w->ob_type is a subclass of + v->ob_type + + Legend: + ------- + * new == new style number + * old == old style number + * Action indicates the order in which operations are tried until either + a valid result is produced or an error occurs. + + */ + +static PyObject * +binary_op1(PyObject *v, PyObject *w, const int op_slot) +{ + PyObject *x; + binaryfunc slotv = NULL; + binaryfunc slotw = NULL; + + if (v->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(v)) + slotv = NB_BINOP(v->ob_type->tp_as_number, op_slot); + if (w->ob_type != v->ob_type && + w->ob_type->tp_as_number != NULL && NEW_STYLE_NUMBER(w)) { + slotw = NB_BINOP(w->ob_type->tp_as_number, op_slot); + if (slotw == slotv) + slotw = NULL; + } + if (slotv) { + if (slotw && PyType_IsSubtype(w->ob_type, v->ob_type)) { + x = slotw(v, w); + if (x != Py_NotImplemented) + return x; + Py_DECREF(x); /* can't do it */ + slotw = NULL; + } + x = slotv(v, w); + if (x != Py_NotImplemented) + return x; + Py_DECREF(x); /* can't do it */ + } + if (slotw) { + x = slotw(v, w); + if (x != Py_NotImplemented) + return x; + Py_DECREF(x); /* can't do it */ + } + if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w)) { + int err = PyNumber_CoerceEx(&v, &w); + if (err < 0) { + return NULL; + } + if (err == 0) { + PyNumberMethods *mv = v->ob_type->tp_as_number; + if (mv) { + binaryfunc slot; + slot = NB_BINOP(mv, op_slot); + if (slot) { + x = slot(v, w); + Py_DECREF(v); + Py_DECREF(w); + return x; + } + } + /* CoerceEx incremented the reference counts */ + Py_DECREF(v); + Py_DECREF(w); + } + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyObject * +binop_type_error(PyObject *v, PyObject *w, const char *op_name) +{ + PyErr_Format(PyExc_TypeError, + "unsupported operand type(s) for %.100s: " + "'%.100s' and '%.100s'", + op_name, + v->ob_type->tp_name, + w->ob_type->tp_name); + return NULL; +} + +static PyObject * +binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) +{ + PyObject *result = binary_op1(v, w, op_slot); + if (result == Py_NotImplemented) { + Py_DECREF(result); + return binop_type_error(v, w, op_name); + } + return result; +} + + +/* + Calling scheme used for ternary operations: + + *** In some cases, w.op is called before v.op; see binary_op1. *** + + v w z Action + ------------------------------------------------------------------- + new new new v.op(v,w,z), w.op(v,w,z), z.op(v,w,z) + new old new v.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z) + old new new w.op(v,w,z), z.op(v,w,z), coerce(v,w,z), v.op(v,w,z) + old old new z.op(v,w,z), coerce(v,w,z), v.op(v,w,z) + new new old v.op(v,w,z), w.op(v,w,z), coerce(v,w,z), v.op(v,w,z) + new old old v.op(v,w,z), coerce(v,w,z), v.op(v,w,z) + old new old w.op(v,w,z), coerce(v,w,z), v.op(v,w,z) + old old old coerce(v,w,z), v.op(v,w,z) + + Legend: + ------- + * new == new style number + * old == old style number + * Action indicates the order in which operations are tried until either + a valid result is produced or an error occurs. + * coerce(v,w,z) actually does: coerce(v,w), coerce(v,z), coerce(w,z) and + only if z != Py_None; if z == Py_None, then it is treated as absent + variable and only coerce(v,w) is tried. + + */ + +static PyObject * +ternary_op(PyObject *v, + PyObject *w, + PyObject *z, + const int op_slot, + const char *op_name) +{ + PyNumberMethods *mv, *mw, *mz; + PyObject *x = NULL; + ternaryfunc slotv = NULL; + ternaryfunc slotw = NULL; + ternaryfunc slotz = NULL; + + mv = v->ob_type->tp_as_number; + mw = w->ob_type->tp_as_number; + if (mv != NULL && NEW_STYLE_NUMBER(v)) + slotv = NB_TERNOP(mv, op_slot); + if (w->ob_type != v->ob_type && + mw != NULL && NEW_STYLE_NUMBER(w)) { + slotw = NB_TERNOP(mw, op_slot); + if (slotw == slotv) + slotw = NULL; + } + if (slotv) { + if (slotw && PyType_IsSubtype(w->ob_type, v->ob_type)) { + x = slotw(v, w, z); + if (x != Py_NotImplemented) + return x; + Py_DECREF(x); /* can't do it */ + slotw = NULL; + } + x = slotv(v, w, z); + if (x != Py_NotImplemented) + return x; + Py_DECREF(x); /* can't do it */ + } + if (slotw) { + x = slotw(v, w, z); + if (x != Py_NotImplemented) + return x; + Py_DECREF(x); /* can't do it */ + } + mz = z->ob_type->tp_as_number; + if (mz != NULL && NEW_STYLE_NUMBER(z)) { + slotz = NB_TERNOP(mz, op_slot); + if (slotz == slotv || slotz == slotw) + slotz = NULL; + if (slotz) { + x = slotz(v, w, z); + if (x != Py_NotImplemented) + return x; + Py_DECREF(x); /* can't do it */ + } + } + + if (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w) || + (z != Py_None && !NEW_STYLE_NUMBER(z))) { + /* we have an old style operand, coerce */ + PyObject *v1, *z1, *w2, *z2; + int c; + + c = PyNumber_Coerce(&v, &w); + if (c != 0) + goto error3; + + /* Special case: if the third argument is None, it is + treated as absent argument and not coerced. */ + if (z == Py_None) { + if (v->ob_type->tp_as_number) { + slotz = NB_TERNOP(v->ob_type->tp_as_number, + op_slot); + if (slotz) + x = slotz(v, w, z); + else + c = -1; + } + else + c = -1; + goto error2; + } + v1 = v; + z1 = z; + c = PyNumber_Coerce(&v1, &z1); + if (c != 0) + goto error2; + w2 = w; + z2 = z1; + c = PyNumber_Coerce(&w2, &z2); + if (c != 0) + goto error1; + + if (v1->ob_type->tp_as_number != NULL) { + slotv = NB_TERNOP(v1->ob_type->tp_as_number, + op_slot); + if (slotv) + x = slotv(v1, w2, z2); + else + c = -1; + } + else + c = -1; + + Py_DECREF(w2); + Py_DECREF(z2); + error1: + Py_DECREF(v1); + Py_DECREF(z1); + error2: + Py_DECREF(v); + Py_DECREF(w); + error3: + if (c >= 0) + return x; + } + + if (z == Py_None) + PyErr_Format( + PyExc_TypeError, + "unsupported operand type(s) for ** or pow(): " + "'%.100s' and '%.100s'", + v->ob_type->tp_name, + w->ob_type->tp_name); + else + PyErr_Format( + PyExc_TypeError, + "unsupported operand type(s) for pow(): " + "'%.100s', '%.100s', '%.100s'", + v->ob_type->tp_name, + w->ob_type->tp_name, + z->ob_type->tp_name); + return NULL; +} + +#define BINARY_FUNC(func, op, op_name) \ + PyObject * \ + func(PyObject *v, PyObject *w) { \ + return binary_op(v, w, NB_SLOT(op), op_name); \ + } + +BINARY_FUNC(PyNumber_Or, nb_or, "|") +BINARY_FUNC(PyNumber_Xor, nb_xor, "^") +BINARY_FUNC(PyNumber_And, nb_and, "&") +BINARY_FUNC(PyNumber_Lshift, nb_lshift, "<<") +BINARY_FUNC(PyNumber_Rshift, nb_rshift, ">>") +BINARY_FUNC(PyNumber_Subtract, nb_subtract, "-") +BINARY_FUNC(PyNumber_Divide, nb_divide, "/") +BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()") + +PyObject * +PyNumber_Add(PyObject *v, PyObject *w) +{ + PyObject *result = binary_op1(v, w, NB_SLOT(nb_add)); + if (result == Py_NotImplemented) { + PySequenceMethods *m = v->ob_type->tp_as_sequence; + Py_DECREF(result); + if (m && m->sq_concat) { + return (*m->sq_concat)(v, w); + } + result = binop_type_error(v, w, "+"); + } + return result; +} + +static PyObject * +sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) +{ + Py_ssize_t count; + if (PyIndex_Check(n)) { + count = PyNumber_AsSsize_t(n, PyExc_OverflowError); + if (count == -1 && PyErr_Occurred()) + return NULL; + } + else { + return type_error("can't multiply sequence by " + "non-int of type '%.200s'", n); + } + return (*repeatfunc)(seq, count); +} + +PyObject * +PyNumber_Multiply(PyObject *v, PyObject *w) +{ + PyObject *result = binary_op1(v, w, NB_SLOT(nb_multiply)); + if (result == Py_NotImplemented) { + PySequenceMethods *mv = v->ob_type->tp_as_sequence; + PySequenceMethods *mw = w->ob_type->tp_as_sequence; + Py_DECREF(result); + if (mv && mv->sq_repeat) { + return sequence_repeat(mv->sq_repeat, v, w); + } + else if (mw && mw->sq_repeat) { + return sequence_repeat(mw->sq_repeat, w, v); + } + result = binop_type_error(v, w, "*"); + } + return result; +} + +PyObject * +PyNumber_FloorDivide(PyObject *v, PyObject *w) +{ + /* XXX tp_flags test */ + return binary_op(v, w, NB_SLOT(nb_floor_divide), "//"); +} + +PyObject * +PyNumber_TrueDivide(PyObject *v, PyObject *w) +{ + /* XXX tp_flags test */ + return binary_op(v, w, NB_SLOT(nb_true_divide), "/"); +} + +PyObject * +PyNumber_Remainder(PyObject *v, PyObject *w) +{ + return binary_op(v, w, NB_SLOT(nb_remainder), "%"); +} + +PyObject * +PyNumber_Power(PyObject *v, PyObject *w, PyObject *z) +{ + return ternary_op(v, w, z, NB_SLOT(nb_power), "** or pow()"); +} + +/* Binary in-place operators */ + +/* The in-place operators are defined to fall back to the 'normal', + non in-place operations, if the in-place methods are not in place. + + - If the left hand object has the appropriate struct members, and + they are filled, call the appropriate function and return the + result. No coercion is done on the arguments; the left-hand object + is the one the operation is performed on, and it's up to the + function to deal with the right-hand object. + + - Otherwise, in-place modification is not supported. Handle it exactly as + a non in-place operation of the same kind. + + */ + +#define HASINPLACE(t) \ + PyType_HasFeature((t)->ob_type, Py_TPFLAGS_HAVE_INPLACEOPS) + +static PyObject * +binary_iop1(PyObject *v, PyObject *w, const int iop_slot, const int op_slot) +{ + PyNumberMethods *mv = v->ob_type->tp_as_number; + if (mv != NULL && HASINPLACE(v)) { + binaryfunc slot = NB_BINOP(mv, iop_slot); + if (slot) { + PyObject *x = (slot)(v, w); + if (x != Py_NotImplemented) { + return x; + } + Py_DECREF(x); + } + } + return binary_op1(v, w, op_slot); +} + +static PyObject * +binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot, + const char *op_name) +{ + PyObject *result = binary_iop1(v, w, iop_slot, op_slot); + if (result == Py_NotImplemented) { + Py_DECREF(result); + return binop_type_error(v, w, op_name); + } + return result; +} + +#define INPLACE_BINOP(func, iop, op, op_name) \ + PyObject * \ + func(PyObject *v, PyObject *w) { \ + return binary_iop(v, w, NB_SLOT(iop), NB_SLOT(op), op_name); \ + } + +INPLACE_BINOP(PyNumber_InPlaceOr, nb_inplace_or, nb_or, "|=") +INPLACE_BINOP(PyNumber_InPlaceXor, nb_inplace_xor, nb_xor, "^=") +INPLACE_BINOP(PyNumber_InPlaceAnd, nb_inplace_and, nb_and, "&=") +INPLACE_BINOP(PyNumber_InPlaceLshift, nb_inplace_lshift, nb_lshift, "<<=") +INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=") +INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=") +INPLACE_BINOP(PyNumber_InPlaceDivide, nb_inplace_divide, nb_divide, "/=") + +PyObject * +PyNumber_InPlaceFloorDivide(PyObject *v, PyObject *w) +{ + /* XXX tp_flags test */ + return binary_iop(v, w, NB_SLOT(nb_inplace_floor_divide), + NB_SLOT(nb_floor_divide), "//="); +} + +PyObject * +PyNumber_InPlaceTrueDivide(PyObject *v, PyObject *w) +{ + /* XXX tp_flags test */ + return binary_iop(v, w, NB_SLOT(nb_inplace_true_divide), + NB_SLOT(nb_true_divide), "/="); +} + +PyObject * +PyNumber_InPlaceAdd(PyObject *v, PyObject *w) +{ + PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_add), + NB_SLOT(nb_add)); + if (result == Py_NotImplemented) { + PySequenceMethods *m = v->ob_type->tp_as_sequence; + Py_DECREF(result); + if (m != NULL) { + binaryfunc f = NULL; + if (HASINPLACE(v)) + f = m->sq_inplace_concat; + if (f == NULL) + f = m->sq_concat; + if (f != NULL) + return (*f)(v, w); + } + result = binop_type_error(v, w, "+="); + } + return result; +} + +PyObject * +PyNumber_InPlaceMultiply(PyObject *v, PyObject *w) +{ + PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_multiply), + NB_SLOT(nb_multiply)); + if (result == Py_NotImplemented) { + ssizeargfunc f = NULL; + PySequenceMethods *mv = v->ob_type->tp_as_sequence; + PySequenceMethods *mw = w->ob_type->tp_as_sequence; + Py_DECREF(result); + if (mv != NULL) { + if (HASINPLACE(v)) + f = mv->sq_inplace_repeat; + if (f == NULL) + f = mv->sq_repeat; + if (f != NULL) + return sequence_repeat(f, v, w); + } + else if (mw != NULL) { + /* Note that the right hand operand should not be + * mutated in this case so sq_inplace_repeat is not + * used. */ + if (mw->sq_repeat) + return sequence_repeat(mw->sq_repeat, w, v); + } + result = binop_type_error(v, w, "*="); + } + return result; +} + +PyObject * +PyNumber_InPlaceRemainder(PyObject *v, PyObject *w) +{ + return binary_iop(v, w, NB_SLOT(nb_inplace_remainder), + NB_SLOT(nb_remainder), "%="); +} + +PyObject * +PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z) +{ + if (HASINPLACE(v) && v->ob_type->tp_as_number && + v->ob_type->tp_as_number->nb_inplace_power != NULL) { + return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**="); + } + else { + return ternary_op(v, w, z, NB_SLOT(nb_power), "**="); + } +} + + +/* Unary operators and functions */ + +PyObject * +PyNumber_Negative(PyObject *o) +{ + PyNumberMethods *m; + + if (o == NULL) + return null_error(); + m = o->ob_type->tp_as_number; + if (m && m->nb_negative) + return (*m->nb_negative)(o); + + return type_error("bad operand type for unary -: '%.200s'", o); +} + +PyObject * +PyNumber_Positive(PyObject *o) +{ + PyNumberMethods *m; + + if (o == NULL) + return null_error(); + m = o->ob_type->tp_as_number; + if (m && m->nb_positive) + return (*m->nb_positive)(o); + + return type_error("bad operand type for unary +: '%.200s'", o); +} + +PyObject * +PyNumber_Invert(PyObject *o) +{ + PyNumberMethods *m; + + if (o == NULL) + return null_error(); + m = o->ob_type->tp_as_number; + if (m && m->nb_invert) + return (*m->nb_invert)(o); + + return type_error("bad operand type for unary ~: '%.200s'", o); +} + +PyObject * +PyNumber_Absolute(PyObject *o) +{ + PyNumberMethods *m; + + if (o == NULL) + return null_error(); + m = o->ob_type->tp_as_number; + if (m && m->nb_absolute) + return m->nb_absolute(o); + + return type_error("bad operand type for abs(): '%.200s'", o); +} + +/* Add a check for embedded NULL-bytes in the argument. */ +static PyObject * +int_from_string(const char *s, Py_ssize_t len) +{ + char *end; + PyObject *x; + + x = PyInt_FromString((char*)s, &end, 10); + if (x == NULL) + return NULL; + if (end != s + len) { + PyErr_SetString(PyExc_ValueError, + "null byte in argument for int()"); + Py_DECREF(x); + return NULL; + } + return x; +} + +/* Return a Python Int or Long from the object item + Raise TypeError if the result is not an int-or-long + or if the object cannot be interpreted as an index. +*/ +PyObject * +PyNumber_Index(PyObject *item) +{ + PyObject *result = NULL; + if (item == NULL) + return null_error(); + if (PyInt_Check(item) || PyLong_Check(item)) { + Py_INCREF(item); + return item; + } + if (PyIndex_Check(item)) { + result = item->ob_type->tp_as_number->nb_index(item); + if (result && + !PyInt_Check(result) && !PyLong_Check(result)) { + PyErr_Format(PyExc_TypeError, + "__index__ returned non-(int,long) " \ + "(type %.200s)", + result->ob_type->tp_name); + Py_DECREF(result); + return NULL; + } + } + else { + PyErr_Format(PyExc_TypeError, + "'%.200s' object cannot be interpreted " + "as an index", item->ob_type->tp_name); + } + return result; +} + +/* Return an error on Overflow only if err is not NULL*/ + +Py_ssize_t +PyNumber_AsSsize_t(PyObject *item, PyObject *err) +{ + Py_ssize_t result; + PyObject *runerr; + PyObject *value = PyNumber_Index(item); + if (value == NULL) + return -1; + + /* We're done if PyInt_AsSsize_t() returns without error. */ + result = PyInt_AsSsize_t(value); + if (result != -1 || !(runerr = PyErr_Occurred())) + goto finish; + + /* Error handling code -- only manage OverflowError differently */ + if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) + goto finish; + + PyErr_Clear(); + /* If no error-handling desired then the default clipping + is sufficient. + */ + if (!err) { + assert(PyLong_Check(value)); + /* Whether or not it is less than or equal to + zero is determined by the sign of ob_size + */ + if (_PyLong_Sign(value) < 0) + result = PY_SSIZE_T_MIN; + else + result = PY_SSIZE_T_MAX; + } + else { + /* Otherwise replace the error with caller's error object. */ + PyErr_Format(err, + "cannot fit '%.200s' into an index-sized integer", + item->ob_type->tp_name); + } + + finish: + Py_DECREF(value); + return result; +} + + +PyObject * +PyNumber_Int(PyObject *o) +{ + PyNumberMethods *m; + const char *buffer; + Py_ssize_t buffer_len; + + if (o == NULL) + return null_error(); + if (PyInt_CheckExact(o)) { + Py_INCREF(o); + return o; + } + m = o->ob_type->tp_as_number; + if (m && m->nb_int) { /* This should include subclasses of int */ + PyObject *res = m->nb_int(o); + if (res && (!PyInt_Check(res) && !PyLong_Check(res))) { + PyErr_Format(PyExc_TypeError, + "__int__ returned non-int (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; + } + if (PyInt_Check(o)) { /* A int subclass without nb_int */ + PyIntObject *io = (PyIntObject*)o; + return PyInt_FromLong(io->ob_ival); + } + if (PyString_Check(o)) + return int_from_string(PyString_AS_STRING(o), + PyString_GET_SIZE(o)); +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(o)) + return PyInt_FromUnicode(PyUnicode_AS_UNICODE(o), + PyUnicode_GET_SIZE(o), + 10); +#endif + if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) + return int_from_string((char*)buffer, buffer_len); + + return type_error("int() argument must be a string or a " + "number, not '%.200s'", o); +} + +/* Add a check for embedded NULL-bytes in the argument. */ +static PyObject * +long_from_string(const char *s, Py_ssize_t len) +{ + char *end; + PyObject *x; + + x = PyLong_FromString((char*)s, &end, 10); + if (x == NULL) + return NULL; + if (end != s + len) { + PyErr_SetString(PyExc_ValueError, + "null byte in argument for long()"); + Py_DECREF(x); + return NULL; + } + return x; +} + +PyObject * +PyNumber_Long(PyObject *o) +{ + PyNumberMethods *m; + const char *buffer; + Py_ssize_t buffer_len; + + if (o == NULL) + return null_error(); + m = o->ob_type->tp_as_number; + if (m && m->nb_long) { /* This should include subclasses of long */ + PyObject *res = m->nb_long(o); + if (res && (!PyInt_Check(res) && !PyLong_Check(res))) { + PyErr_Format(PyExc_TypeError, + "__long__ returned non-long (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; + } + if (PyLong_Check(o)) /* A long subclass without nb_long */ + return _PyLong_Copy((PyLongObject *)o); + if (PyString_Check(o)) + /* need to do extra error checking that PyLong_FromString() + * doesn't do. In particular long('9.5') must raise an + * exception, not truncate the float. + */ + return long_from_string(PyString_AS_STRING(o), + PyString_GET_SIZE(o)); +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(o)) + /* The above check is done in PyLong_FromUnicode(). */ + return PyLong_FromUnicode(PyUnicode_AS_UNICODE(o), + PyUnicode_GET_SIZE(o), + 10); +#endif + if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len)) + return long_from_string(buffer, buffer_len); + + return type_error("long() argument must be a string or a " + "number, not '%.200s'", o); +} + +PyObject * +PyNumber_Float(PyObject *o) +{ + PyNumberMethods *m; + + if (o == NULL) + return null_error(); + m = o->ob_type->tp_as_number; + if (m && m->nb_float) { /* This should include subclasses of float */ + PyObject *res = m->nb_float(o); + if (res && !PyFloat_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__float__ returned non-float (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; + } + if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */ + PyFloatObject *po = (PyFloatObject *)o; + return PyFloat_FromDouble(po->ob_fval); + } + return PyFloat_FromString(o, NULL); +} + +/* Operations on sequences */ + +int +PySequence_Check(PyObject *s) +{ + if (s && PyInstance_Check(s)) + return PyObject_HasAttrString(s, "__getitem__"); + if (PyObject_IsInstance(s, (PyObject *)&PyDict_Type)) + return 0; + return s != NULL && s->ob_type->tp_as_sequence && + s->ob_type->tp_as_sequence->sq_item != NULL; +} + +Py_ssize_t +PySequence_Size(PyObject *s) +{ + PySequenceMethods *m; + + if (s == NULL) { + null_error(); + return -1; + } + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_length) + return m->sq_length(s); + + type_error("object of type '%.200s' has no len()", s); + return -1; +} + +#undef PySequence_Length +Py_ssize_t +PySequence_Length(PyObject *s) +{ + return PySequence_Size(s); +} +#define PySequence_Length PySequence_Size + +PyObject * +PySequence_Concat(PyObject *s, PyObject *o) +{ + PySequenceMethods *m; + + if (s == NULL || o == NULL) + return null_error(); + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_concat) + return m->sq_concat(s, o); + + /* Instances of user classes defining an __add__() method only + have an nb_add slot, not an sq_concat slot. So we fall back + to nb_add if both arguments appear to be sequences. */ + if (PySequence_Check(s) && PySequence_Check(o)) { + PyObject *result = binary_op1(s, o, NB_SLOT(nb_add)); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } + return type_error("'%.200s' object can't be concatenated", s); +} + +PyObject * +PySequence_Repeat(PyObject *o, Py_ssize_t count) +{ + PySequenceMethods *m; + + if (o == NULL) + return null_error(); + + m = o->ob_type->tp_as_sequence; + if (m && m->sq_repeat) + return m->sq_repeat(o, count); + + /* Instances of user classes defining a __mul__() method only + have an nb_multiply slot, not an sq_repeat slot. so we fall back + to nb_multiply if o appears to be a sequence. */ + if (PySequence_Check(o)) { + PyObject *n, *result; + n = PyInt_FromSsize_t(count); + if (n == NULL) + return NULL; + result = binary_op1(o, n, NB_SLOT(nb_multiply)); + Py_DECREF(n); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } + return type_error("'%.200s' object can't be repeated", o); +} + +PyObject * +PySequence_InPlaceConcat(PyObject *s, PyObject *o) +{ + PySequenceMethods *m; + + if (s == NULL || o == NULL) + return null_error(); + + m = s->ob_type->tp_as_sequence; + if (m && HASINPLACE(s) && m->sq_inplace_concat) + return m->sq_inplace_concat(s, o); + if (m && m->sq_concat) + return m->sq_concat(s, o); + + if (PySequence_Check(s) && PySequence_Check(o)) { + PyObject *result = binary_iop1(s, o, NB_SLOT(nb_inplace_add), + NB_SLOT(nb_add)); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } + return type_error("'%.200s' object can't be concatenated", s); +} + +PyObject * +PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count) +{ + PySequenceMethods *m; + + if (o == NULL) + return null_error(); + + m = o->ob_type->tp_as_sequence; + if (m && HASINPLACE(o) && m->sq_inplace_repeat) + return m->sq_inplace_repeat(o, count); + if (m && m->sq_repeat) + return m->sq_repeat(o, count); + + if (PySequence_Check(o)) { + PyObject *n, *result; + n = PyInt_FromSsize_t(count); + if (n == NULL) + return NULL; + result = binary_iop1(o, n, NB_SLOT(nb_inplace_multiply), + NB_SLOT(nb_multiply)); + Py_DECREF(n); + if (result != Py_NotImplemented) + return result; + Py_DECREF(result); + } + return type_error("'%.200s' object can't be repeated", o); +} + +PyObject * +PySequence_GetItem(PyObject *s, Py_ssize_t i) +{ + PySequenceMethods *m; + + if (s == NULL) + return null_error(); + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_item) { + if (i < 0) { + if (m->sq_length) { + Py_ssize_t l = (*m->sq_length)(s); + if (l < 0) + return NULL; + i += l; + } + } + return m->sq_item(s, i); + } + + return type_error("'%.200s' object is unindexable", s); +} + +PyObject * +PySequence_GetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) +{ + PySequenceMethods *m; + PyMappingMethods *mp; + + if (!s) return null_error(); + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_slice) { + if (i1 < 0 || i2 < 0) { + if (m->sq_length) { + Py_ssize_t l = (*m->sq_length)(s); + if (l < 0) + return NULL; + if (i1 < 0) + i1 += l; + if (i2 < 0) + i2 += l; + } + } + return m->sq_slice(s, i1, i2); + } else if ((mp = s->ob_type->tp_as_mapping) && mp->mp_subscript) { + PyObject *res; + PyObject *slice = _PySlice_FromIndices(i1, i2); + if (!slice) + return NULL; + res = mp->mp_subscript(s, slice); + Py_DECREF(slice); + return res; + } + + return type_error("'%.200s' object is unsliceable", s); +} + +int +PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o) +{ + PySequenceMethods *m; + + if (s == NULL) { + null_error(); + return -1; + } + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_ass_item) { + if (i < 0) { + if (m->sq_length) { + Py_ssize_t l = (*m->sq_length)(s); + if (l < 0) + return -1; + i += l; + } + } + return m->sq_ass_item(s, i, o); + } + + type_error("'%.200s' object does not support item assignment", s); + return -1; +} + +int +PySequence_DelItem(PyObject *s, Py_ssize_t i) +{ + PySequenceMethods *m; + + if (s == NULL) { + null_error(); + return -1; + } + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_ass_item) { + if (i < 0) { + if (m->sq_length) { + Py_ssize_t l = (*m->sq_length)(s); + if (l < 0) + return -1; + i += l; + } + } + return m->sq_ass_item(s, i, (PyObject *)NULL); + } + + type_error("'%.200s' object doesn't support item deletion", s); + return -1; +} + +int +PySequence_SetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2, PyObject *o) +{ + PySequenceMethods *m; + PyMappingMethods *mp; + + if (s == NULL) { + null_error(); + return -1; + } + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_ass_slice) { + if (i1 < 0 || i2 < 0) { + if (m->sq_length) { + Py_ssize_t l = (*m->sq_length)(s); + if (l < 0) + return -1; + if (i1 < 0) + i1 += l; + if (i2 < 0) + i2 += l; + } + } + return m->sq_ass_slice(s, i1, i2, o); + } else if ((mp = s->ob_type->tp_as_mapping) && mp->mp_ass_subscript) { + int res; + PyObject *slice = _PySlice_FromIndices(i1, i2); + if (!slice) + return -1; + res = mp->mp_ass_subscript(s, slice, o); + Py_DECREF(slice); + return res; + } + + type_error("'%.200s' object doesn't support slice assignment", s); + return -1; +} + +int +PySequence_DelSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) +{ + PySequenceMethods *m; + + if (s == NULL) { + null_error(); + return -1; + } + + m = s->ob_type->tp_as_sequence; + if (m && m->sq_ass_slice) { + if (i1 < 0 || i2 < 0) { + if (m->sq_length) { + Py_ssize_t l = (*m->sq_length)(s); + if (l < 0) + return -1; + if (i1 < 0) + i1 += l; + if (i2 < 0) + i2 += l; + } + } + return m->sq_ass_slice(s, i1, i2, (PyObject *)NULL); + } + type_error("'%.200s' object doesn't support slice deletion", s); + return -1; +} + +PyObject * +PySequence_Tuple(PyObject *v) +{ + PyObject *it; /* iter(v) */ + Py_ssize_t n; /* guess for result tuple size */ + PyObject *result; + Py_ssize_t j; + + if (v == NULL) + return null_error(); + + /* Special-case the common tuple and list cases, for efficiency. */ + if (PyTuple_CheckExact(v)) { + /* Note that we can't know whether it's safe to return + a tuple *subclass* instance as-is, hence the restriction + to exact tuples here. In contrast, lists always make + a copy, so there's no need for exactness below. */ + Py_INCREF(v); + return v; + } + if (PyList_Check(v)) + return PyList_AsTuple(v); + + /* Get iterator. */ + it = PyObject_GetIter(v); + if (it == NULL) + return NULL; + + /* Guess result size and allocate space. */ + n = _PyObject_LengthHint(v); + if (n < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(it); + return NULL; + } + PyErr_Clear(); + n = 10; /* arbitrary */ + } + result = PyTuple_New(n); + if (result == NULL) + goto Fail; + + /* Fill the tuple. */ + for (j = 0; ; ++j) { + PyObject *item = PyIter_Next(it); + if (item == NULL) { + if (PyErr_Occurred()) + goto Fail; + break; + } + if (j >= n) { + Py_ssize_t oldn = n; + /* The over-allocation strategy can grow a bit faster + than for lists because unlike lists the + over-allocation isn't permanent -- we reclaim + the excess before the end of this routine. + So, grow by ten and then add 25%. + */ + n += 10; + n += n >> 2; + if (n < oldn) { + /* Check for overflow */ + PyErr_NoMemory(); + Py_DECREF(item); + goto Fail; + } + if (_PyTuple_Resize(&result, n) != 0) { + Py_DECREF(item); + goto Fail; + } + } + PyTuple_SET_ITEM(result, j, item); + } + + /* Cut tuple back if guess was too large. */ + if (j < n && + _PyTuple_Resize(&result, j) != 0) + goto Fail; + + Py_DECREF(it); + return result; + +Fail: + Py_XDECREF(result); + Py_DECREF(it); + return NULL; +} + +PyObject * +PySequence_List(PyObject *v) +{ + PyObject *result; /* result list */ + PyObject *rv; /* return value from PyList_Extend */ + + if (v == NULL) + return null_error(); + + result = PyList_New(0); + if (result == NULL) + return NULL; + + rv = _PyList_Extend((PyListObject *)result, v); + if (rv == NULL) { + Py_DECREF(result); + return NULL; + } + Py_DECREF(rv); + return result; +} + +PyObject * +PySequence_Fast(PyObject *v, const char *m) +{ + PyObject *it; + + if (v == NULL) + return null_error(); + + if (PyList_CheckExact(v) || PyTuple_CheckExact(v)) { + Py_INCREF(v); + return v; + } + + it = PyObject_GetIter(v); + if (it == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_SetString(PyExc_TypeError, m); + return NULL; + } + + v = PySequence_List(it); + Py_DECREF(it); + + return v; +} + +/* Iterate over seq. Result depends on the operation: + PY_ITERSEARCH_COUNT: -1 if error, else # of times obj appears in seq. + PY_ITERSEARCH_INDEX: 0-based index of first occurence of obj in seq; + set ValueError and return -1 if none found; also return -1 on error. + Py_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on error. +*/ +Py_ssize_t +_PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation) +{ + Py_ssize_t n; + int wrapped; /* for PY_ITERSEARCH_INDEX, true iff n wrapped around */ + PyObject *it; /* iter(seq) */ + + if (seq == NULL || obj == NULL) { + null_error(); + return -1; + } + + it = PyObject_GetIter(seq); + if (it == NULL) { + type_error("argument of type '%.200s' is not iterable", seq); + return -1; + } + + n = wrapped = 0; + for (;;) { + int cmp; + PyObject *item = PyIter_Next(it); + if (item == NULL) { + if (PyErr_Occurred()) + goto Fail; + break; + } + + cmp = PyObject_RichCompareBool(obj, item, Py_EQ); + Py_DECREF(item); + if (cmp < 0) + goto Fail; + if (cmp > 0) { + switch (operation) { + case PY_ITERSEARCH_COUNT: + if (n == PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "count exceeds C integer size"); + goto Fail; + } + ++n; + break; + + case PY_ITERSEARCH_INDEX: + if (wrapped) { + PyErr_SetString(PyExc_OverflowError, + "index exceeds C integer size"); + goto Fail; + } + goto Done; + + case PY_ITERSEARCH_CONTAINS: + n = 1; + goto Done; + + default: + assert(!"unknown operation"); + } + } + + if (operation == PY_ITERSEARCH_INDEX) { + if (n == PY_SSIZE_T_MAX) + wrapped = 1; + ++n; + } + } + + if (operation != PY_ITERSEARCH_INDEX) + goto Done; + + PyErr_SetString(PyExc_ValueError, + "sequence.index(x): x not in sequence"); + /* fall into failure code */ +Fail: + n = -1; + /* fall through */ +Done: + Py_DECREF(it); + return n; + +} + +/* Return # of times o appears in s. */ +Py_ssize_t +PySequence_Count(PyObject *s, PyObject *o) +{ + return _PySequence_IterSearch(s, o, PY_ITERSEARCH_COUNT); +} + +/* Return -1 if error; 1 if ob in seq; 0 if ob not in seq. + * Use sq_contains if possible, else defer to _PySequence_IterSearch(). + */ +int +PySequence_Contains(PyObject *seq, PyObject *ob) +{ + Py_ssize_t result; + if (PyType_HasFeature(seq->ob_type, Py_TPFLAGS_HAVE_SEQUENCE_IN)) { + PySequenceMethods *sqm = seq->ob_type->tp_as_sequence; + if (sqm != NULL && sqm->sq_contains != NULL) + return (*sqm->sq_contains)(seq, ob); + } + result = _PySequence_IterSearch(seq, ob, PY_ITERSEARCH_CONTAINS); + return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); +} + +/* Backwards compatibility */ +#undef PySequence_In +int +PySequence_In(PyObject *w, PyObject *v) +{ + return PySequence_Contains(w, v); +} + +Py_ssize_t +PySequence_Index(PyObject *s, PyObject *o) +{ + return _PySequence_IterSearch(s, o, PY_ITERSEARCH_INDEX); +} + +/* Operations on mappings */ + +int +PyMapping_Check(PyObject *o) +{ + if (o && PyInstance_Check(o)) + return PyObject_HasAttrString(o, "__getitem__"); + + return o && o->ob_type->tp_as_mapping && + o->ob_type->tp_as_mapping->mp_subscript && + !(o->ob_type->tp_as_sequence && + o->ob_type->tp_as_sequence->sq_slice); +} + +Py_ssize_t +PyMapping_Size(PyObject *o) +{ + PyMappingMethods *m; + + if (o == NULL) { + null_error(); + return -1; + } + + m = o->ob_type->tp_as_mapping; + if (m && m->mp_length) + return m->mp_length(o); + + type_error("object of type '%.200s' has no len()", o); + return -1; +} + +#undef PyMapping_Length +Py_ssize_t +PyMapping_Length(PyObject *o) +{ + return PyMapping_Size(o); +} +#define PyMapping_Length PyMapping_Size + +PyObject * +PyMapping_GetItemString(PyObject *o, char *key) +{ + PyObject *okey, *r; + + if (key == NULL) + return null_error(); + + okey = PyString_FromString(key); + if (okey == NULL) + return NULL; + r = PyObject_GetItem(o, okey); + Py_DECREF(okey); + return r; +} + +int +PyMapping_SetItemString(PyObject *o, char *key, PyObject *value) +{ + PyObject *okey; + int r; + + if (key == NULL) { + null_error(); + return -1; + } + + okey = PyString_FromString(key); + if (okey == NULL) + return -1; + r = PyObject_SetItem(o, okey, value); + Py_DECREF(okey); + return r; +} + +int +PyMapping_HasKeyString(PyObject *o, char *key) +{ + PyObject *v; + + v = PyMapping_GetItemString(o, key); + if (v) { + Py_DECREF(v); + return 1; + } + PyErr_Clear(); + return 0; +} + +int +PyMapping_HasKey(PyObject *o, PyObject *key) +{ + PyObject *v; + + v = PyObject_GetItem(o, key); + if (v) { + Py_DECREF(v); + return 1; + } + PyErr_Clear(); + return 0; +} + +/* Operations on callable objects */ + +/* XXX PyCallable_Check() is in object.c */ + +PyObject * +PyObject_CallObject(PyObject *o, PyObject *a) +{ + return PyEval_CallObjectWithKeywords(o, a, NULL); +} + +PyObject * +PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) +{ + ternaryfunc call; + + if ((call = func->ob_type->tp_call) != NULL) { + PyObject *result = (*call)(func, arg, kw); + if (result == NULL && !PyErr_Occurred()) + PyErr_SetString( + PyExc_SystemError, + "NULL result without error in PyObject_Call"); + return result; + } + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + func->ob_type->tp_name); + return NULL; +} + +static PyObject* +call_function_tail(PyObject *callable, PyObject *args) +{ + PyObject *retval; + + if (args == NULL) + return NULL; + + if (!PyTuple_Check(args)) { + PyObject *a; + + a = PyTuple_New(1); + if (a == NULL) { + Py_DECREF(args); + return NULL; + } + PyTuple_SET_ITEM(a, 0, args); + args = a; + } + retval = PyObject_Call(callable, args, NULL); + + Py_DECREF(args); + + return retval; +} + +PyObject * +PyObject_CallFunction(PyObject *callable, char *format, ...) +{ + va_list va; + PyObject *args; + + if (callable == NULL) + return null_error(); + + if (format && *format) { + va_start(va, format); + args = Py_VaBuildValue(format, va); + va_end(va); + } + else + args = PyTuple_New(0); + + return call_function_tail(callable, args); +} + +PyObject * +_PyObject_CallFunction_SizeT(PyObject *callable, char *format, ...) +{ + va_list va; + PyObject *args; + + if (callable == NULL) + return null_error(); + + if (format && *format) { + va_start(va, format); + args = _Py_VaBuildValue_SizeT(format, va); + va_end(va); + } + else + args = PyTuple_New(0); + + return call_function_tail(callable, args); +} + +PyObject * +PyObject_CallMethod(PyObject *o, char *name, char *format, ...) +{ + va_list va; + PyObject *args; + PyObject *func = NULL; + PyObject *retval = NULL; + + if (o == NULL || name == NULL) + return null_error(); + + func = PyObject_GetAttrString(o, name); + if (func == NULL) { + PyErr_SetString(PyExc_AttributeError, name); + return 0; + } + + if (!PyCallable_Check(func)) { + type_error("attribute of type '%.200s' is not callable", func); + goto exit; + } + + if (format && *format) { + va_start(va, format); + args = Py_VaBuildValue(format, va); + va_end(va); + } + else + args = PyTuple_New(0); + + retval = call_function_tail(func, args); + + exit: + /* args gets consumed in call_function_tail */ + Py_XDECREF(func); + + return retval; +} + +PyObject * +_PyObject_CallMethod_SizeT(PyObject *o, char *name, char *format, ...) +{ + va_list va; + PyObject *args; + PyObject *func = NULL; + PyObject *retval = NULL; + + if (o == NULL || name == NULL) + return null_error(); + + func = PyObject_GetAttrString(o, name); + if (func == NULL) { + PyErr_SetString(PyExc_AttributeError, name); + return 0; + } + + if (!PyCallable_Check(func)) { + type_error("attribute of type '%.200s' is not callable", func); + goto exit; + } + + if (format && *format) { + va_start(va, format); + args = _Py_VaBuildValue_SizeT(format, va); + va_end(va); + } + else + args = PyTuple_New(0); + + retval = call_function_tail(func, args); + + exit: + /* args gets consumed in call_function_tail */ + Py_XDECREF(func); + + return retval; +} + + +static PyObject * +objargs_mktuple(va_list va) +{ + int i, n = 0; + va_list countva; + PyObject *result, *tmp; + +#ifdef VA_LIST_IS_ARRAY + memcpy(countva, va, sizeof(va_list)); +#else +#ifdef __va_copy + __va_copy(countva, va); +#else + countva = va; +#endif +#endif + + while (((PyObject *)va_arg(countva, PyObject *)) != NULL) + ++n; + result = PyTuple_New(n); + if (result != NULL && n > 0) { + for (i = 0; i < n; ++i) { + tmp = (PyObject *)va_arg(va, PyObject *); + PyTuple_SET_ITEM(result, i, tmp); + Py_INCREF(tmp); + } + } + return result; +} + +PyObject * +PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) +{ + PyObject *args, *tmp; + va_list vargs; + + if (callable == NULL || name == NULL) + return null_error(); + + callable = PyObject_GetAttr(callable, name); + if (callable == NULL) + return NULL; + + /* count the args */ + va_start(vargs, name); + args = objargs_mktuple(vargs); + va_end(vargs); + if (args == NULL) { + Py_DECREF(callable); + return NULL; + } + tmp = PyObject_Call(callable, args, NULL); + Py_DECREF(args); + Py_DECREF(callable); + + return tmp; +} + +PyObject * +PyObject_CallFunctionObjArgs(PyObject *callable, ...) +{ + PyObject *args, *tmp; + va_list vargs; + + if (callable == NULL) + return null_error(); + + /* count the args */ + va_start(vargs, callable); + args = objargs_mktuple(vargs); + va_end(vargs); + if (args == NULL) + return NULL; + tmp = PyObject_Call(callable, args, NULL); + Py_DECREF(args); + + return tmp; +} + + +/* isinstance(), issubclass() */ + +/* abstract_get_bases() has logically 4 return states, with a sort of 0th + * state that will almost never happen. + * + * 0. creating the __bases__ static string could get a MemoryError + * 1. getattr(cls, '__bases__') could raise an AttributeError + * 2. getattr(cls, '__bases__') could raise some other exception + * 3. getattr(cls, '__bases__') could return a tuple + * 4. getattr(cls, '__bases__') could return something other than a tuple + * + * Only state #3 is a non-error state and only it returns a non-NULL object + * (it returns the retrieved tuple). + * + * Any raised AttributeErrors are masked by clearing the exception and + * returning NULL. If an object other than a tuple comes out of __bases__, + * then again, the return value is NULL. So yes, these two situations + * produce exactly the same results: NULL is returned and no error is set. + * + * If some exception other than AttributeError is raised, then NULL is also + * returned, but the exception is not cleared. That's because we want the + * exception to be propagated along. + * + * Callers are expected to test for PyErr_Occurred() when the return value + * is NULL to decide whether a valid exception should be propagated or not. + * When there's no exception to propagate, it's customary for the caller to + * set a TypeError. + */ +static PyObject * +abstract_get_bases(PyObject *cls) +{ + static PyObject *__bases__ = NULL; + PyObject *bases; + + if (__bases__ == NULL) { + __bases__ = PyString_FromString("__bases__"); + if (__bases__ == NULL) + return NULL; + } + bases = PyObject_GetAttr(cls, __bases__); + if (bases == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + return NULL; + } + if (!PyTuple_Check(bases)) { + Py_DECREF(bases); + return NULL; + } + return bases; +} + + +static int +abstract_issubclass(PyObject *derived, PyObject *cls) +{ + PyObject *bases; + Py_ssize_t i, n; + int r = 0; + + + if (derived == cls) + return 1; + + if (PyTuple_Check(cls)) { + /* Not a general sequence -- that opens up the road to + recursion and stack overflow. */ + n = PyTuple_GET_SIZE(cls); + for (i = 0; i < n; i++) { + if (derived == PyTuple_GET_ITEM(cls, i)) + return 1; + } + } + bases = abstract_get_bases(derived); + if (bases == NULL) { + if (PyErr_Occurred()) + return -1; + return 0; + } + n = PyTuple_GET_SIZE(bases); + for (i = 0; i < n; i++) { + r = abstract_issubclass(PyTuple_GET_ITEM(bases, i), cls); + if (r != 0) + break; + } + + Py_DECREF(bases); + + return r; +} + +static int +check_class(PyObject *cls, const char *error) +{ + PyObject *bases = abstract_get_bases(cls); + if (bases == NULL) { + /* Do not mask errors. */ + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, error); + return 0; + } + Py_DECREF(bases); + return -1; +} + +static int +recursive_isinstance(PyObject *inst, PyObject *cls, int recursion_depth) +{ + PyObject *icls; + static PyObject *__class__ = NULL; + int retval = 0; + + if (__class__ == NULL) { + __class__ = PyString_FromString("__class__"); + if (__class__ == NULL) + return -1; + } + + if (PyClass_Check(cls) && PyInstance_Check(inst)) { + PyObject *inclass = + (PyObject*)((PyInstanceObject*)inst)->in_class; + retval = PyClass_IsSubclass(inclass, cls); + } + else if (PyType_Check(cls)) { + retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); + if (retval == 0) { + PyObject *c = PyObject_GetAttr(inst, __class__); + if (c == NULL) { + PyErr_Clear(); + } + else { + if (c != (PyObject *)(inst->ob_type) && + PyType_Check(c)) + retval = PyType_IsSubtype( + (PyTypeObject *)c, + (PyTypeObject *)cls); + Py_DECREF(c); + } + } + } + else if (PyTuple_Check(cls)) { + Py_ssize_t i, n; + + if (!recursion_depth) { + PyErr_SetString(PyExc_RuntimeError, + "nest level of tuple too deep"); + return -1; + } + + n = PyTuple_GET_SIZE(cls); + for (i = 0; i < n; i++) { + retval = recursive_isinstance( + inst, + PyTuple_GET_ITEM(cls, i), + recursion_depth-1); + if (retval != 0) + break; + } + } + else { + if (!check_class(cls, + "isinstance() arg 2 must be a class, type," + " or tuple of classes and types")) + return -1; + icls = PyObject_GetAttr(inst, __class__); + if (icls == NULL) { + PyErr_Clear(); + retval = 0; + } + else { + retval = abstract_issubclass(icls, cls); + Py_DECREF(icls); + } + } + + return retval; +} + +int +PyObject_IsInstance(PyObject *inst, PyObject *cls) +{ + return recursive_isinstance(inst, cls, Py_GetRecursionLimit()); +} + +static int +recursive_issubclass(PyObject *derived, PyObject *cls, int recursion_depth) +{ + int retval; + + if (!PyClass_Check(derived) || !PyClass_Check(cls)) { + if (!check_class(derived, + "issubclass() arg 1 must be a class")) + return -1; + + if (PyTuple_Check(cls)) { + Py_ssize_t i; + Py_ssize_t n = PyTuple_GET_SIZE(cls); + + if (!recursion_depth) { + PyErr_SetString(PyExc_RuntimeError, + "nest level of tuple too deep"); + return -1; + } + for (i = 0; i < n; ++i) { + retval = recursive_issubclass( + derived, + PyTuple_GET_ITEM(cls, i), + recursion_depth-1); + if (retval != 0) { + /* either found it, or got an error */ + return retval; + } + } + return 0; + } + else { + if (!check_class(cls, + "issubclass() arg 2 must be a class" + " or tuple of classes")) + return -1; + } + + retval = abstract_issubclass(derived, cls); + } + else { + /* shortcut */ + if (!(retval = (derived == cls))) + retval = PyClass_IsSubclass(derived, cls); + } + + return retval; +} + +int +PyObject_IsSubclass(PyObject *derived, PyObject *cls) +{ + return recursive_issubclass(derived, cls, Py_GetRecursionLimit()); +} + + +PyObject * +PyObject_GetIter(PyObject *o) +{ + PyTypeObject *t = o->ob_type; + getiterfunc f = NULL; + if (PyType_HasFeature(t, Py_TPFLAGS_HAVE_ITER)) + f = t->tp_iter; + if (f == NULL) { + if (PySequence_Check(o)) + return PySeqIter_New(o); + return type_error("'%.200s' object is not iterable", o); + } + else { + PyObject *res = (*f)(o); + if (res != NULL && !PyIter_Check(res)) { + PyErr_Format(PyExc_TypeError, + "iter() returned non-iterator " + "of type '%.100s'", + res->ob_type->tp_name); + Py_DECREF(res); + res = NULL; + } + return res; + } +} + +/* Return next item. + * If an error occurs, return NULL. PyErr_Occurred() will be true. + * If the iteration terminates normally, return NULL and clear the + * PyExc_StopIteration exception (if it was set). PyErr_Occurred() + * will be false. + * Else return the next object. PyErr_Occurred() will be false. + */ +PyObject * +PyIter_Next(PyObject *iter) +{ + PyObject *result; + assert(PyIter_Check(iter)); + result = (*iter->ob_type->tp_iternext)(iter); + if (result == NULL && + PyErr_Occurred() && + PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + return result; +} diff --git a/sys/src/cmd/python/Objects/boolobject.c b/sys/src/cmd/python/Objects/boolobject.c new file mode 100644 index 000000000..37be295ac --- /dev/null +++ b/sys/src/cmd/python/Objects/boolobject.c @@ -0,0 +1,201 @@ +/* Boolean type, a subtype of int */ + +#include "Python.h" + +/* We need to define bool_print to override int_print */ + +static int +bool_print(PyBoolObject *self, FILE *fp, int flags) +{ + fputs(self->ob_ival == 0 ? "False" : "True", fp); + return 0; +} + +/* We define bool_repr to return "False" or "True" */ + +static PyObject *false_str = NULL; +static PyObject *true_str = NULL; + +static PyObject * +bool_repr(PyBoolObject *self) +{ + PyObject *s; + + if (self->ob_ival) + s = true_str ? true_str : + (true_str = PyString_InternFromString("True")); + else + s = false_str ? false_str : + (false_str = PyString_InternFromString("False")); + Py_XINCREF(s); + return s; +} + +/* Function to return a bool from a C long */ + +PyObject *PyBool_FromLong(long ok) +{ + PyObject *result; + + if (ok) + result = Py_True; + else + result = Py_False; + Py_INCREF(result); + return result; +} + +/* We define bool_new to always return either Py_True or Py_False */ + +static PyObject * +bool_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"x", 0}; + PyObject *x = Py_False; + long ok; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:bool", kwlist, &x)) + return NULL; + ok = PyObject_IsTrue(x); + if (ok < 0) + return NULL; + return PyBool_FromLong(ok); +} + +/* Arithmetic operations redefined to return bool if both args are bool. */ + +static PyObject * +bool_and(PyObject *a, PyObject *b) +{ + if (!PyBool_Check(a) || !PyBool_Check(b)) + return PyInt_Type.tp_as_number->nb_and(a, b); + return PyBool_FromLong( + ((PyBoolObject *)a)->ob_ival & ((PyBoolObject *)b)->ob_ival); +} + +static PyObject * +bool_or(PyObject *a, PyObject *b) +{ + if (!PyBool_Check(a) || !PyBool_Check(b)) + return PyInt_Type.tp_as_number->nb_or(a, b); + return PyBool_FromLong( + ((PyBoolObject *)a)->ob_ival | ((PyBoolObject *)b)->ob_ival); +} + +static PyObject * +bool_xor(PyObject *a, PyObject *b) +{ + if (!PyBool_Check(a) || !PyBool_Check(b)) + return PyInt_Type.tp_as_number->nb_xor(a, b); + return PyBool_FromLong( + ((PyBoolObject *)a)->ob_ival ^ ((PyBoolObject *)b)->ob_ival); +} + +/* Doc string */ + +PyDoc_STRVAR(bool_doc, +"bool(x) -> bool\n\ +\n\ +Returns True when the argument x is true, False otherwise.\n\ +The builtins True and False are the only two instances of the class bool.\n\ +The class bool is a subclass of the class int, and cannot be subclassed."); + +/* Arithmetic methods -- only so we can override &, |, ^. */ + +static PyNumberMethods bool_as_number = { + 0, /* nb_add */ + 0, /* nb_subtract */ + 0, /* nb_multiply */ + 0, /* nb_divide */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ + 0, /* nb_power */ + 0, /* nb_negative */ + 0, /* nb_positive */ + 0, /* nb_absolute */ + 0, /* nb_nonzero */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + bool_and, /* nb_and */ + bool_xor, /* nb_xor */ + bool_or, /* nb_or */ + 0, /* nb_coerce */ + 0, /* nb_int */ + 0, /* nb_long */ + 0, /* nb_float */ + 0, /* nb_oct */ + 0, /* nb_hex */ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_divide */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + 0, /* nb_floor_divide */ + 0, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ +}; + +/* The type object for bool. Note that this cannot be subclassed! */ + +PyTypeObject PyBool_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "bool", + sizeof(PyIntObject), + 0, + 0, /* tp_dealloc */ + (printfunc)bool_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)bool_repr, /* tp_repr */ + &bool_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)bool_repr, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + bool_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyInt_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + bool_new, /* tp_new */ +}; + +/* The objects representing bool values False and True */ + +/* Named Zero for link-level compatibility */ +PyIntObject _Py_ZeroStruct = { + PyObject_HEAD_INIT(&PyBool_Type) + 0 +}; + +PyIntObject _Py_TrueStruct = { + PyObject_HEAD_INIT(&PyBool_Type) + 1 +}; diff --git a/sys/src/cmd/python/Objects/bufferobject.c b/sys/src/cmd/python/Objects/bufferobject.c new file mode 100644 index 000000000..5f3c7a9ee --- /dev/null +++ b/sys/src/cmd/python/Objects/bufferobject.c @@ -0,0 +1,706 @@ + +/* Buffer object implementation */ + +#include "Python.h" + + +typedef struct { + PyObject_HEAD + PyObject *b_base; + void *b_ptr; + Py_ssize_t b_size; + Py_ssize_t b_offset; + int b_readonly; + long b_hash; +} PyBufferObject; + + +enum buffer_t { + READ_BUFFER, + WRITE_BUFFER, + CHAR_BUFFER, + ANY_BUFFER, +}; + +static int +get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size, + enum buffer_t buffer_type) +{ + if (self->b_base == NULL) { + assert (ptr != NULL); + *ptr = self->b_ptr; + *size = self->b_size; + } + else { + Py_ssize_t count, offset; + readbufferproc proc = 0; + PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer; + if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) { + PyErr_SetString(PyExc_TypeError, + "single-segment buffer object expected"); + return 0; + } + if ((buffer_type == READ_BUFFER) || + ((buffer_type == ANY_BUFFER) && self->b_readonly)) + proc = bp->bf_getreadbuffer; + else if ((buffer_type == WRITE_BUFFER) || + (buffer_type == ANY_BUFFER)) + proc = (readbufferproc)bp->bf_getwritebuffer; + else if (buffer_type == CHAR_BUFFER) { + if (!PyType_HasFeature(self->ob_type, + Py_TPFLAGS_HAVE_GETCHARBUFFER)) { + PyErr_SetString(PyExc_TypeError, + "Py_TPFLAGS_HAVE_GETCHARBUFFER needed"); + return 0; + } + proc = (readbufferproc)bp->bf_getcharbuffer; + } + if (!proc) { + char *buffer_type_name; + switch (buffer_type) { + case READ_BUFFER: + buffer_type_name = "read"; + break; + case WRITE_BUFFER: + buffer_type_name = "write"; + break; + case CHAR_BUFFER: + buffer_type_name = "char"; + break; + default: + buffer_type_name = "no"; + break; + } + PyErr_Format(PyExc_TypeError, + "%s buffer type not available", + buffer_type_name); + return 0; + } + if ((count = (*proc)(self->b_base, 0, ptr)) < 0) + return 0; + /* apply constraints to the start/end */ + if (self->b_offset > count) + offset = count; + else + offset = self->b_offset; + *(char **)ptr = *(char **)ptr + offset; + if (self->b_size == Py_END_OF_BUFFER) + *size = count; + else + *size = self->b_size; + if (offset + *size > count) + *size = count - offset; + } + return 1; +} + + +static PyObject * +buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr, + int readonly) +{ + PyBufferObject * b; + + if (size < 0 && size != Py_END_OF_BUFFER) { + PyErr_SetString(PyExc_ValueError, + "size must be zero or positive"); + return NULL; + } + if (offset < 0) { + PyErr_SetString(PyExc_ValueError, + "offset must be zero or positive"); + return NULL; + } + + b = PyObject_NEW(PyBufferObject, &PyBuffer_Type); + if ( b == NULL ) + return NULL; + + Py_XINCREF(base); + b->b_base = base; + b->b_ptr = ptr; + b->b_size = size; + b->b_offset = offset; + b->b_readonly = readonly; + b->b_hash = -1; + + return (PyObject *) b; +} + +static PyObject * +buffer_from_object(PyObject *base, Py_ssize_t size, Py_ssize_t offset, int readonly) +{ + if (offset < 0) { + PyErr_SetString(PyExc_ValueError, + "offset must be zero or positive"); + return NULL; + } + if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) { + /* another buffer, refer to the base object */ + PyBufferObject *b = (PyBufferObject *)base; + if (b->b_size != Py_END_OF_BUFFER) { + Py_ssize_t base_size = b->b_size - offset; + if (base_size < 0) + base_size = 0; + if (size == Py_END_OF_BUFFER || size > base_size) + size = base_size; + } + offset += b->b_offset; + base = b->b_base; + } + return buffer_from_memory(base, size, offset, NULL, readonly); +} + + +PyObject * +PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size) +{ + PyBufferProcs *pb = base->ob_type->tp_as_buffer; + + if ( pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL ) + { + PyErr_SetString(PyExc_TypeError, "buffer object expected"); + return NULL; + } + + return buffer_from_object(base, size, offset, 1); +} + +PyObject * +PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size) +{ + PyBufferProcs *pb = base->ob_type->tp_as_buffer; + + if ( pb == NULL || + pb->bf_getwritebuffer == NULL || + pb->bf_getsegcount == NULL ) + { + PyErr_SetString(PyExc_TypeError, "buffer object expected"); + return NULL; + } + + return buffer_from_object(base, size, offset, 0); +} + +PyObject * +PyBuffer_FromMemory(void *ptr, Py_ssize_t size) +{ + return buffer_from_memory(NULL, size, 0, ptr, 1); +} + +PyObject * +PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size) +{ + return buffer_from_memory(NULL, size, 0, ptr, 0); +} + +PyObject * +PyBuffer_New(Py_ssize_t size) +{ + PyObject *o; + PyBufferObject * b; + + if (size < 0) { + PyErr_SetString(PyExc_ValueError, + "size must be zero or positive"); + return NULL; + } + /* XXX: check for overflow in multiply */ + /* Inline PyObject_New */ + o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size); + if ( o == NULL ) + return PyErr_NoMemory(); + b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type); + + b->b_base = NULL; + b->b_ptr = (void *)(b + 1); + b->b_size = size; + b->b_offset = 0; + b->b_readonly = 0; + b->b_hash = -1; + + return o; +} + +/* Methods */ + +static PyObject * +buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *ob; + Py_ssize_t offset = 0; + Py_ssize_t size = Py_END_OF_BUFFER; + + if (!_PyArg_NoKeywords("buffer()", kw)) + return NULL; + + if (!PyArg_ParseTuple(args, "O|nn:buffer", &ob, &offset, &size)) + return NULL; + return PyBuffer_FromObject(ob, offset, size); +} + +PyDoc_STRVAR(buffer_doc, +"buffer(object [, offset[, size]])\n\ +\n\ +Create a new buffer object which references the given object.\n\ +The buffer will reference a slice of the target object from the\n\ +start of the object (or at the specified offset). The slice will\n\ +extend to the end of the target object (or with the specified size)."); + + +static void +buffer_dealloc(PyBufferObject *self) +{ + Py_XDECREF(self->b_base); + PyObject_DEL(self); +} + +static int +buffer_compare(PyBufferObject *self, PyBufferObject *other) +{ + void *p1, *p2; + Py_ssize_t len_self, len_other, min_len; + int cmp; + + if (!get_buf(self, &p1, &len_self, ANY_BUFFER)) + return -1; + if (!get_buf(other, &p2, &len_other, ANY_BUFFER)) + return -1; + min_len = (len_self < len_other) ? len_self : len_other; + if (min_len > 0) { + cmp = memcmp(p1, p2, min_len); + if (cmp != 0) + return cmp < 0 ? -1 : 1; + } + return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0; +} + +static PyObject * +buffer_repr(PyBufferObject *self) +{ + const char *status = self->b_readonly ? "read-only" : "read-write"; + + if ( self->b_base == NULL ) + return PyString_FromFormat("<%s buffer ptr %p, size %zd at %p>", + status, + self->b_ptr, + self->b_size, + self); + else + return PyString_FromFormat( + "<%s buffer for %p, size %zd, offset %zd at %p>", + status, + self->b_base, + self->b_size, + self->b_offset, + self); +} + +static long +buffer_hash(PyBufferObject *self) +{ + void *ptr; + Py_ssize_t size; + register Py_ssize_t len; + register unsigned char *p; + register long x; + + if ( self->b_hash != -1 ) + return self->b_hash; + + /* XXX potential bugs here, a readonly buffer does not imply that the + * underlying memory is immutable. b_readonly is a necessary but not + * sufficient condition for a buffer to be hashable. Perhaps it would + * be better to only allow hashing if the underlying object is known to + * be immutable (e.g. PyString_Check() is true). Another idea would + * be to call tp_hash on the underlying object and see if it raises + * an error. */ + if ( !self->b_readonly ) + { + PyErr_SetString(PyExc_TypeError, + "writable buffers are not hashable"); + return -1; + } + + if (!get_buf(self, &ptr, &size, ANY_BUFFER)) + return -1; + p = (unsigned char *) ptr; + len = size; + x = *p << 7; + while (--len >= 0) + x = (1000003*x) ^ *p++; + x ^= size; + if (x == -1) + x = -2; + self->b_hash = x; + return x; +} + +static PyObject * +buffer_str(PyBufferObject *self) +{ + void *ptr; + Py_ssize_t size; + if (!get_buf(self, &ptr, &size, ANY_BUFFER)) + return NULL; + return PyString_FromStringAndSize((const char *)ptr, size); +} + +/* Sequence methods */ + +static Py_ssize_t +buffer_length(PyBufferObject *self) +{ + void *ptr; + Py_ssize_t size; + if (!get_buf(self, &ptr, &size, ANY_BUFFER)) + return -1; + return size; +} + +static PyObject * +buffer_concat(PyBufferObject *self, PyObject *other) +{ + PyBufferProcs *pb = other->ob_type->tp_as_buffer; + void *ptr1, *ptr2; + char *p; + PyObject *ob; + Py_ssize_t size, count; + + if ( pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL ) + { + PyErr_BadArgument(); + return NULL; + } + if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) + { + /* ### use a different exception type/message? */ + PyErr_SetString(PyExc_TypeError, + "single-segment buffer object expected"); + return NULL; + } + + if (!get_buf(self, &ptr1, &size, ANY_BUFFER)) + return NULL; + + /* optimize special case */ + if ( size == 0 ) + { + Py_INCREF(other); + return other; + } + + if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 ) + return NULL; + + ob = PyString_FromStringAndSize(NULL, size + count); + if ( ob == NULL ) + return NULL; + p = PyString_AS_STRING(ob); + memcpy(p, ptr1, size); + memcpy(p + size, ptr2, count); + + /* there is an extra byte in the string object, so this is safe */ + p[size + count] = '\0'; + + return ob; +} + +static PyObject * +buffer_repeat(PyBufferObject *self, Py_ssize_t count) +{ + PyObject *ob; + register char *p; + void *ptr; + Py_ssize_t size; + + if ( count < 0 ) + count = 0; + if (!get_buf(self, &ptr, &size, ANY_BUFFER)) + return NULL; + ob = PyString_FromStringAndSize(NULL, size * count); + if ( ob == NULL ) + return NULL; + + p = PyString_AS_STRING(ob); + while ( count-- ) + { + memcpy(p, ptr, size); + p += size; + } + + /* there is an extra byte in the string object, so this is safe */ + *p = '\0'; + + return ob; +} + +static PyObject * +buffer_item(PyBufferObject *self, Py_ssize_t idx) +{ + void *ptr; + Py_ssize_t size; + if (!get_buf(self, &ptr, &size, ANY_BUFFER)) + return NULL; + if ( idx < 0 || idx >= size ) { + PyErr_SetString(PyExc_IndexError, "buffer index out of range"); + return NULL; + } + return PyString_FromStringAndSize((char *)ptr + idx, 1); +} + +static PyObject * +buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right) +{ + void *ptr; + Py_ssize_t size; + if (!get_buf(self, &ptr, &size, ANY_BUFFER)) + return NULL; + if ( left < 0 ) + left = 0; + if ( right < 0 ) + right = 0; + if ( right > size ) + right = size; + if ( right < left ) + right = left; + return PyString_FromStringAndSize((char *)ptr + left, + right - left); +} + +static int +buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other) +{ + PyBufferProcs *pb; + void *ptr1, *ptr2; + Py_ssize_t size; + Py_ssize_t count; + + if ( self->b_readonly ) { + PyErr_SetString(PyExc_TypeError, + "buffer is read-only"); + return -1; + } + + if (!get_buf(self, &ptr1, &size, ANY_BUFFER)) + return -1; + + if (idx < 0 || idx >= size) { + PyErr_SetString(PyExc_IndexError, + "buffer assignment index out of range"); + return -1; + } + + pb = other ? other->ob_type->tp_as_buffer : NULL; + if ( pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL ) + { + PyErr_BadArgument(); + return -1; + } + if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) + { + /* ### use a different exception type/message? */ + PyErr_SetString(PyExc_TypeError, + "single-segment buffer object expected"); + return -1; + } + + if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 ) + return -1; + if ( count != 1 ) { + PyErr_SetString(PyExc_TypeError, + "right operand must be a single byte"); + return -1; + } + + ((char *)ptr1)[idx] = *(char *)ptr2; + return 0; +} + +static int +buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other) +{ + PyBufferProcs *pb; + void *ptr1, *ptr2; + Py_ssize_t size; + Py_ssize_t slice_len; + Py_ssize_t count; + + if ( self->b_readonly ) { + PyErr_SetString(PyExc_TypeError, + "buffer is read-only"); + return -1; + } + + pb = other ? other->ob_type->tp_as_buffer : NULL; + if ( pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL ) + { + PyErr_BadArgument(); + return -1; + } + if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) + { + /* ### use a different exception type/message? */ + PyErr_SetString(PyExc_TypeError, + "single-segment buffer object expected"); + return -1; + } + if (!get_buf(self, &ptr1, &size, ANY_BUFFER)) + return -1; + if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 ) + return -1; + + if ( left < 0 ) + left = 0; + else if ( left > size ) + left = size; + if ( right < left ) + right = left; + else if ( right > size ) + right = size; + slice_len = right - left; + + if ( count != slice_len ) { + PyErr_SetString( + PyExc_TypeError, + "right operand length must match slice length"); + return -1; + } + + if ( slice_len ) + memcpy((char *)ptr1 + left, ptr2, slice_len); + + return 0; +} + +/* Buffer methods */ + +static Py_ssize_t +buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp) +{ + Py_ssize_t size; + if ( idx != 0 ) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent buffer segment"); + return -1; + } + if (!get_buf(self, pp, &size, READ_BUFFER)) + return -1; + return size; +} + +static Py_ssize_t +buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp) +{ + Py_ssize_t size; + + if ( self->b_readonly ) + { + PyErr_SetString(PyExc_TypeError, "buffer is read-only"); + return -1; + } + + if ( idx != 0 ) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent buffer segment"); + return -1; + } + if (!get_buf(self, pp, &size, WRITE_BUFFER)) + return -1; + return size; +} + +static Py_ssize_t +buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp) +{ + void *ptr; + Py_ssize_t size; + if (!get_buf(self, &ptr, &size, ANY_BUFFER)) + return -1; + if (lenp) + *lenp = size; + return 1; +} + +static Py_ssize_t +buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp) +{ + void *ptr; + Py_ssize_t size; + if ( idx != 0 ) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent buffer segment"); + return -1; + } + if (!get_buf(self, &ptr, &size, CHAR_BUFFER)) + return -1; + *pp = (const char *)ptr; + return size; +} + +static PySequenceMethods buffer_as_sequence = { + (lenfunc)buffer_length, /*sq_length*/ + (binaryfunc)buffer_concat, /*sq_concat*/ + (ssizeargfunc)buffer_repeat, /*sq_repeat*/ + (ssizeargfunc)buffer_item, /*sq_item*/ + (ssizessizeargfunc)buffer_slice, /*sq_slice*/ + (ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/ + (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/ +}; + +static PyBufferProcs buffer_as_buffer = { + (readbufferproc)buffer_getreadbuf, + (writebufferproc)buffer_getwritebuf, + (segcountproc)buffer_getsegcount, + (charbufferproc)buffer_getcharbuf, +}; + +PyTypeObject PyBuffer_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "buffer", + sizeof(PyBufferObject), + 0, + (destructor)buffer_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)buffer_compare, /* tp_compare */ + (reprfunc)buffer_repr, /* tp_repr */ + 0, /* tp_as_number */ + &buffer_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)buffer_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)buffer_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + &buffer_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */ + buffer_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + buffer_new, /* tp_new */ +}; diff --git a/sys/src/cmd/python/Objects/cellobject.c b/sys/src/cmd/python/Objects/cellobject.c new file mode 100644 index 000000000..65a29aaca --- /dev/null +++ b/sys/src/cmd/python/Objects/cellobject.c @@ -0,0 +1,133 @@ +/* Cell object implementation */ + +#include "Python.h" + +PyObject * +PyCell_New(PyObject *obj) +{ + PyCellObject *op; + + op = (PyCellObject *)PyObject_GC_New(PyCellObject, &PyCell_Type); + if (op == NULL) + return NULL; + op->ob_ref = obj; + Py_XINCREF(obj); + + _PyObject_GC_TRACK(op); + return (PyObject *)op; +} + +PyObject * +PyCell_Get(PyObject *op) +{ + if (!PyCell_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + Py_XINCREF(((PyCellObject*)op)->ob_ref); + return PyCell_GET(op); +} + +int +PyCell_Set(PyObject *op, PyObject *obj) +{ + if (!PyCell_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + Py_XDECREF(((PyCellObject*)op)->ob_ref); + Py_XINCREF(obj); + PyCell_SET(op, obj); + return 0; +} + +static void +cell_dealloc(PyCellObject *op) +{ + _PyObject_GC_UNTRACK(op); + Py_XDECREF(op->ob_ref); + PyObject_GC_Del(op); +} + +static int +cell_compare(PyCellObject *a, PyCellObject *b) +{ + if (a->ob_ref == NULL) { + if (b->ob_ref == NULL) + return 0; + return -1; + } else if (b->ob_ref == NULL) + return 1; + return PyObject_Compare(a->ob_ref, b->ob_ref); +} + +static PyObject * +cell_repr(PyCellObject *op) +{ + if (op->ob_ref == NULL) + return PyString_FromFormat("<cell at %p: empty>", op); + + return PyString_FromFormat("<cell at %p: %.80s object at %p>", + op, op->ob_ref->ob_type->tp_name, + op->ob_ref); +} + +static int +cell_traverse(PyCellObject *op, visitproc visit, void *arg) +{ + Py_VISIT(op->ob_ref); + return 0; +} + +static int +cell_clear(PyCellObject *op) +{ + Py_CLEAR(op->ob_ref); + return 0; +} + +static PyObject * +cell_get_contents(PyCellObject *op, void *closure) +{ + Py_XINCREF(op->ob_ref); + return op->ob_ref; +} + +static PyGetSetDef cell_getsetlist[] = { + {"cell_contents", (getter)cell_get_contents, NULL}, + {NULL} /* sentinel */ +}; + +PyTypeObject PyCell_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "cell", + sizeof(PyCellObject), + 0, + (destructor)cell_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)cell_compare, /* tp_compare */ + (reprfunc)cell_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)cell_traverse, /* tp_traverse */ + (inquiry)cell_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + cell_getsetlist, /* tp_getset */ +}; diff --git a/sys/src/cmd/python/Objects/classobject.c b/sys/src/cmd/python/Objects/classobject.c new file mode 100644 index 000000000..8560b6842 --- /dev/null +++ b/sys/src/cmd/python/Objects/classobject.c @@ -0,0 +1,2580 @@ + +/* Class object implementation */ + +#include "Python.h" +#include "structmember.h" + +#define TP_DESCR_GET(t) \ + (PyType_HasFeature(t, Py_TPFLAGS_HAVE_CLASS) ? (t)->tp_descr_get : NULL) + + +/* Forward */ +static PyObject *class_lookup(PyClassObject *, PyObject *, + PyClassObject **); +static PyObject *instance_getattr1(PyInstanceObject *, PyObject *); +static PyObject *instance_getattr2(PyInstanceObject *, PyObject *); + +static PyObject *getattrstr, *setattrstr, *delattrstr; + + +PyObject * +PyClass_New(PyObject *bases, PyObject *dict, PyObject *name) + /* bases is NULL or tuple of classobjects! */ +{ + PyClassObject *op, *dummy; + static PyObject *docstr, *modstr, *namestr; + if (docstr == NULL) { + docstr= PyString_InternFromString("__doc__"); + if (docstr == NULL) + return NULL; + } + if (modstr == NULL) { + modstr= PyString_InternFromString("__module__"); + if (modstr == NULL) + return NULL; + } + if (namestr == NULL) { + namestr= PyString_InternFromString("__name__"); + if (namestr == NULL) + return NULL; + } + if (name == NULL || !PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "PyClass_New: name must be a string"); + return NULL; + } + if (dict == NULL || !PyDict_Check(dict)) { + PyErr_SetString(PyExc_TypeError, + "PyClass_New: dict must be a dictionary"); + return NULL; + } + if (PyDict_GetItem(dict, docstr) == NULL) { + if (PyDict_SetItem(dict, docstr, Py_None) < 0) + return NULL; + } + if (PyDict_GetItem(dict, modstr) == NULL) { + PyObject *globals = PyEval_GetGlobals(); + if (globals != NULL) { + PyObject *modname = PyDict_GetItem(globals, namestr); + if (modname != NULL) { + if (PyDict_SetItem(dict, modstr, modname) < 0) + return NULL; + } + } + } + if (bases == NULL) { + bases = PyTuple_New(0); + if (bases == NULL) + return NULL; + } + else { + Py_ssize_t i, n; + PyObject *base; + if (!PyTuple_Check(bases)) { + PyErr_SetString(PyExc_TypeError, + "PyClass_New: bases must be a tuple"); + return NULL; + } + n = PyTuple_Size(bases); + for (i = 0; i < n; i++) { + base = PyTuple_GET_ITEM(bases, i); + if (!PyClass_Check(base)) { + if (PyCallable_Check( + (PyObject *) base->ob_type)) + return PyObject_CallFunctionObjArgs( + (PyObject *) base->ob_type, + name, bases, dict, NULL); + PyErr_SetString(PyExc_TypeError, + "PyClass_New: base must be a class"); + return NULL; + } + } + Py_INCREF(bases); + } + + if (getattrstr == NULL) { + getattrstr = PyString_InternFromString("__getattr__"); + if (getattrstr == NULL) + goto alloc_error; + setattrstr = PyString_InternFromString("__setattr__"); + if (setattrstr == NULL) + goto alloc_error; + delattrstr = PyString_InternFromString("__delattr__"); + if (delattrstr == NULL) + goto alloc_error; + } + + op = PyObject_GC_New(PyClassObject, &PyClass_Type); + if (op == NULL) { +alloc_error: + Py_DECREF(bases); + return NULL; + } + op->cl_bases = bases; + Py_INCREF(dict); + op->cl_dict = dict; + Py_XINCREF(name); + op->cl_name = name; + + op->cl_getattr = class_lookup(op, getattrstr, &dummy); + op->cl_setattr = class_lookup(op, setattrstr, &dummy); + op->cl_delattr = class_lookup(op, delattrstr, &dummy); + Py_XINCREF(op->cl_getattr); + Py_XINCREF(op->cl_setattr); + Py_XINCREF(op->cl_delattr); + _PyObject_GC_TRACK(op); + return (PyObject *) op; +} + +PyObject * +PyMethod_Function(PyObject *im) +{ + if (!PyMethod_Check(im)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyMethodObject *)im)->im_func; +} + +PyObject * +PyMethod_Self(PyObject *im) +{ + if (!PyMethod_Check(im)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyMethodObject *)im)->im_self; +} + +PyObject * +PyMethod_Class(PyObject *im) +{ + if (!PyMethod_Check(im)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyMethodObject *)im)->im_class; +} + +PyDoc_STRVAR(class_doc, +"classobj(name, bases, dict)\n\ +\n\ +Create a class object. The name must be a string; the second argument\n\ +a tuple of classes, and the third a dictionary."); + +static PyObject * +class_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *name, *bases, *dict; + static char *kwlist[] = {"name", "bases", "dict", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "SOO", kwlist, + &name, &bases, &dict)) + return NULL; + return PyClass_New(bases, dict, name); +} + +/* Class methods */ + +static void +class_dealloc(PyClassObject *op) +{ + _PyObject_GC_UNTRACK(op); + Py_DECREF(op->cl_bases); + Py_DECREF(op->cl_dict); + Py_XDECREF(op->cl_name); + Py_XDECREF(op->cl_getattr); + Py_XDECREF(op->cl_setattr); + Py_XDECREF(op->cl_delattr); + PyObject_GC_Del(op); +} + +static PyObject * +class_lookup(PyClassObject *cp, PyObject *name, PyClassObject **pclass) +{ + Py_ssize_t i, n; + PyObject *value = PyDict_GetItem(cp->cl_dict, name); + if (value != NULL) { + *pclass = cp; + return value; + } + n = PyTuple_Size(cp->cl_bases); + for (i = 0; i < n; i++) { + /* XXX What if one of the bases is not a class? */ + PyObject *v = class_lookup( + (PyClassObject *) + PyTuple_GetItem(cp->cl_bases, i), name, pclass); + if (v != NULL) + return v; + } + return NULL; +} + +static PyObject * +class_getattr(register PyClassObject *op, PyObject *name) +{ + register PyObject *v; + register char *sname = PyString_AsString(name); + PyClassObject *klass; + descrgetfunc f; + + if (sname[0] == '_' && sname[1] == '_') { + if (strcmp(sname, "__dict__") == 0) { + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "class.__dict__ not accessible in restricted mode"); + return NULL; + } + Py_INCREF(op->cl_dict); + return op->cl_dict; + } + if (strcmp(sname, "__bases__") == 0) { + Py_INCREF(op->cl_bases); + return op->cl_bases; + } + if (strcmp(sname, "__name__") == 0) { + if (op->cl_name == NULL) + v = Py_None; + else + v = op->cl_name; + Py_INCREF(v); + return v; + } + } + v = class_lookup(op, name, &klass); + if (v == NULL) { + PyErr_Format(PyExc_AttributeError, + "class %.50s has no attribute '%.400s'", + PyString_AS_STRING(op->cl_name), sname); + return NULL; + } + f = TP_DESCR_GET(v->ob_type); + if (f == NULL) + Py_INCREF(v); + else + v = f(v, (PyObject *)NULL, (PyObject *)op); + return v; +} + +static void +set_slot(PyObject **slot, PyObject *v) +{ + PyObject *temp = *slot; + Py_XINCREF(v); + *slot = v; + Py_XDECREF(temp); +} + +static void +set_attr_slots(PyClassObject *c) +{ + PyClassObject *dummy; + + set_slot(&c->cl_getattr, class_lookup(c, getattrstr, &dummy)); + set_slot(&c->cl_setattr, class_lookup(c, setattrstr, &dummy)); + set_slot(&c->cl_delattr, class_lookup(c, delattrstr, &dummy)); +} + +static char * +set_dict(PyClassObject *c, PyObject *v) +{ + if (v == NULL || !PyDict_Check(v)) + return "__dict__ must be a dictionary object"; + set_slot(&c->cl_dict, v); + set_attr_slots(c); + return ""; +} + +static char * +set_bases(PyClassObject *c, PyObject *v) +{ + Py_ssize_t i, n; + + if (v == NULL || !PyTuple_Check(v)) + return "__bases__ must be a tuple object"; + n = PyTuple_Size(v); + for (i = 0; i < n; i++) { + PyObject *x = PyTuple_GET_ITEM(v, i); + if (!PyClass_Check(x)) + return "__bases__ items must be classes"; + if (PyClass_IsSubclass(x, (PyObject *)c)) + return "a __bases__ item causes an inheritance cycle"; + } + set_slot(&c->cl_bases, v); + set_attr_slots(c); + return ""; +} + +static char * +set_name(PyClassObject *c, PyObject *v) +{ + if (v == NULL || !PyString_Check(v)) + return "__name__ must be a string object"; + if (strlen(PyString_AS_STRING(v)) != (size_t)PyString_GET_SIZE(v)) + return "__name__ must not contain null bytes"; + set_slot(&c->cl_name, v); + return ""; +} + +static int +class_setattr(PyClassObject *op, PyObject *name, PyObject *v) +{ + char *sname; + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "classes are read-only in restricted mode"); + return -1; + } + sname = PyString_AsString(name); + if (sname[0] == '_' && sname[1] == '_') { + Py_ssize_t n = PyString_Size(name); + if (sname[n-1] == '_' && sname[n-2] == '_') { + char *err = NULL; + if (strcmp(sname, "__dict__") == 0) + err = set_dict(op, v); + else if (strcmp(sname, "__bases__") == 0) + err = set_bases(op, v); + else if (strcmp(sname, "__name__") == 0) + err = set_name(op, v); + else if (strcmp(sname, "__getattr__") == 0) + set_slot(&op->cl_getattr, v); + else if (strcmp(sname, "__setattr__") == 0) + set_slot(&op->cl_setattr, v); + else if (strcmp(sname, "__delattr__") == 0) + set_slot(&op->cl_delattr, v); + /* For the last three, we fall through to update the + dictionary as well. */ + if (err != NULL) { + if (*err == '\0') + return 0; + PyErr_SetString(PyExc_TypeError, err); + return -1; + } + } + } + if (v == NULL) { + int rv = PyDict_DelItem(op->cl_dict, name); + if (rv < 0) + PyErr_Format(PyExc_AttributeError, + "class %.50s has no attribute '%.400s'", + PyString_AS_STRING(op->cl_name), sname); + return rv; + } + else + return PyDict_SetItem(op->cl_dict, name, v); +} + +static PyObject * +class_repr(PyClassObject *op) +{ + PyObject *mod = PyDict_GetItemString(op->cl_dict, "__module__"); + char *name; + if (op->cl_name == NULL || !PyString_Check(op->cl_name)) + name = "?"; + else + name = PyString_AsString(op->cl_name); + if (mod == NULL || !PyString_Check(mod)) + return PyString_FromFormat("<class ?.%s at %p>", name, op); + else + return PyString_FromFormat("<class %s.%s at %p>", + PyString_AsString(mod), + name, op); +} + +static PyObject * +class_str(PyClassObject *op) +{ + PyObject *mod = PyDict_GetItemString(op->cl_dict, "__module__"); + PyObject *name = op->cl_name; + PyObject *res; + Py_ssize_t m, n; + + if (name == NULL || !PyString_Check(name)) + return class_repr(op); + if (mod == NULL || !PyString_Check(mod)) { + Py_INCREF(name); + return name; + } + m = PyString_GET_SIZE(mod); + n = PyString_GET_SIZE(name); + res = PyString_FromStringAndSize((char *)NULL, m+1+n); + if (res != NULL) { + char *s = PyString_AS_STRING(res); + memcpy(s, PyString_AS_STRING(mod), m); + s += m; + *s++ = '.'; + memcpy(s, PyString_AS_STRING(name), n); + } + return res; +} + +static int +class_traverse(PyClassObject *o, visitproc visit, void *arg) +{ + Py_VISIT(o->cl_bases); + Py_VISIT(o->cl_dict); + Py_VISIT(o->cl_name); + Py_VISIT(o->cl_getattr); + Py_VISIT(o->cl_setattr); + Py_VISIT(o->cl_delattr); + return 0; +} + +PyTypeObject PyClass_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "classobj", + sizeof(PyClassObject), + 0, + (destructor)class_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)class_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + PyInstance_New, /* tp_call */ + (reprfunc)class_str, /* tp_str */ + (getattrofunc)class_getattr, /* tp_getattro */ + (setattrofunc)class_setattr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + class_doc, /* tp_doc */ + (traverseproc)class_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + class_new, /* tp_new */ +}; + +int +PyClass_IsSubclass(PyObject *klass, PyObject *base) +{ + Py_ssize_t i, n; + PyClassObject *cp; + if (klass == base) + return 1; + if (PyTuple_Check(base)) { + n = PyTuple_GET_SIZE(base); + for (i = 0; i < n; i++) { + if (PyClass_IsSubclass(klass, PyTuple_GET_ITEM(base, i))) + return 1; + } + return 0; + } + if (klass == NULL || !PyClass_Check(klass)) + return 0; + cp = (PyClassObject *)klass; + n = PyTuple_Size(cp->cl_bases); + for (i = 0; i < n; i++) { + if (PyClass_IsSubclass(PyTuple_GetItem(cp->cl_bases, i), base)) + return 1; + } + return 0; +} + + +/* Instance objects */ + +PyObject * +PyInstance_NewRaw(PyObject *klass, PyObject *dict) +{ + PyInstanceObject *inst; + + if (!PyClass_Check(klass)) { + PyErr_BadInternalCall(); + return NULL; + } + if (dict == NULL) { + dict = PyDict_New(); + if (dict == NULL) + return NULL; + } + else { + if (!PyDict_Check(dict)) { + PyErr_BadInternalCall(); + return NULL; + } + Py_INCREF(dict); + } + inst = PyObject_GC_New(PyInstanceObject, &PyInstance_Type); + if (inst == NULL) { + Py_DECREF(dict); + return NULL; + } + inst->in_weakreflist = NULL; + Py_INCREF(klass); + inst->in_class = (PyClassObject *)klass; + inst->in_dict = dict; + _PyObject_GC_TRACK(inst); + return (PyObject *)inst; +} + +PyObject * +PyInstance_New(PyObject *klass, PyObject *arg, PyObject *kw) +{ + register PyInstanceObject *inst; + PyObject *init; + static PyObject *initstr; + + if (initstr == NULL) { + initstr = PyString_InternFromString("__init__"); + if (initstr == NULL) + return NULL; + } + inst = (PyInstanceObject *) PyInstance_NewRaw(klass, NULL); + if (inst == NULL) + return NULL; + init = instance_getattr2(inst, initstr); + if (init == NULL) { + if (PyErr_Occurred()) { + Py_DECREF(inst); + return NULL; + } + if ((arg != NULL && (!PyTuple_Check(arg) || + PyTuple_Size(arg) != 0)) + || (kw != NULL && (!PyDict_Check(kw) || + PyDict_Size(kw) != 0))) { + PyErr_SetString(PyExc_TypeError, + "this constructor takes no arguments"); + Py_DECREF(inst); + inst = NULL; + } + } + else { + PyObject *res = PyEval_CallObjectWithKeywords(init, arg, kw); + Py_DECREF(init); + if (res == NULL) { + Py_DECREF(inst); + inst = NULL; + } + else { + if (res != Py_None) { + PyErr_SetString(PyExc_TypeError, + "__init__() should return None"); + Py_DECREF(inst); + inst = NULL; + } + Py_DECREF(res); + } + } + return (PyObject *)inst; +} + +/* Instance methods */ + +PyDoc_STRVAR(instance_doc, +"instance(class[, dict])\n\ +\n\ +Create an instance without calling its __init__() method.\n\ +The class must be a classic class.\n\ +If present, dict must be a dictionary or None."); + +static PyObject * +instance_new(PyTypeObject* type, PyObject* args, PyObject *kw) +{ + PyObject *klass; + PyObject *dict = Py_None; + + if (!PyArg_ParseTuple(args, "O!|O:instance", + &PyClass_Type, &klass, &dict)) + return NULL; + + if (dict == Py_None) + dict = NULL; + else if (!PyDict_Check(dict)) { + PyErr_SetString(PyExc_TypeError, + "instance() second arg must be dictionary or None"); + return NULL; + } + return PyInstance_NewRaw(klass, dict); +} + + +static void +instance_dealloc(register PyInstanceObject *inst) +{ + PyObject *error_type, *error_value, *error_traceback; + PyObject *del; + static PyObject *delstr; + + _PyObject_GC_UNTRACK(inst); + if (inst->in_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) inst); + + /* Temporarily resurrect the object. */ + assert(inst->ob_type == &PyInstance_Type); + assert(inst->ob_refcnt == 0); + inst->ob_refcnt = 1; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + /* Execute __del__ method, if any. */ + if (delstr == NULL) { + delstr = PyString_InternFromString("__del__"); + if (delstr == NULL) + PyErr_WriteUnraisable((PyObject*)inst); + } + if (delstr && (del = instance_getattr2(inst, delstr)) != NULL) { + PyObject *res = PyEval_CallObject(del, (PyObject *)NULL); + if (res == NULL) + PyErr_WriteUnraisable(del); + else + Py_DECREF(res); + Py_DECREF(del); + } + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ + assert(inst->ob_refcnt > 0); + if (--inst->ob_refcnt == 0) { + Py_DECREF(inst->in_class); + Py_XDECREF(inst->in_dict); + PyObject_GC_Del(inst); + } + else { + Py_ssize_t refcnt = inst->ob_refcnt; + /* __del__ resurrected it! Make it look like the original + * Py_DECREF never happened. + */ + _Py_NewReference((PyObject *)inst); + inst->ob_refcnt = refcnt; + _PyObject_GC_TRACK(inst); + /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so + * we need to undo that. */ + _Py_DEC_REFTOTAL; + /* If Py_TRACE_REFS, _Py_NewReference re-added self to the + * object chain, so no more to do there. + * If COUNT_ALLOCS, the original decref bumped tp_frees, and + * _Py_NewReference bumped tp_allocs: both of those need to be + * undone. + */ +#ifdef COUNT_ALLOCS + --inst->ob_type->tp_frees; + --inst->ob_type->tp_allocs; +#endif + } +} + +static PyObject * +instance_getattr1(register PyInstanceObject *inst, PyObject *name) +{ + register PyObject *v; + register char *sname = PyString_AsString(name); + if (sname[0] == '_' && sname[1] == '_') { + if (strcmp(sname, "__dict__") == 0) { + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "instance.__dict__ not accessible in restricted mode"); + return NULL; + } + Py_INCREF(inst->in_dict); + return inst->in_dict; + } + if (strcmp(sname, "__class__") == 0) { + Py_INCREF(inst->in_class); + return (PyObject *)inst->in_class; + } + } + v = instance_getattr2(inst, name); + if (v == NULL && !PyErr_Occurred()) { + PyErr_Format(PyExc_AttributeError, + "%.50s instance has no attribute '%.400s'", + PyString_AS_STRING(inst->in_class->cl_name), sname); + } + return v; +} + +static PyObject * +instance_getattr2(register PyInstanceObject *inst, PyObject *name) +{ + register PyObject *v; + PyClassObject *klass; + descrgetfunc f; + + v = PyDict_GetItem(inst->in_dict, name); + if (v != NULL) { + Py_INCREF(v); + return v; + } + v = class_lookup(inst->in_class, name, &klass); + if (v != NULL) { + Py_INCREF(v); + f = TP_DESCR_GET(v->ob_type); + if (f != NULL) { + PyObject *w = f(v, (PyObject *)inst, + (PyObject *)(inst->in_class)); + Py_DECREF(v); + v = w; + } + } + return v; +} + +static PyObject * +instance_getattr(register PyInstanceObject *inst, PyObject *name) +{ + register PyObject *func, *res; + res = instance_getattr1(inst, name); + if (res == NULL && (func = inst->in_class->cl_getattr) != NULL) { + PyObject *args; + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + args = PyTuple_Pack(2, inst, name); + if (args == NULL) + return NULL; + res = PyEval_CallObject(func, args); + Py_DECREF(args); + } + return res; +} + +/* See classobject.h comments: this only does dict lookups, and is always + * safe to call. + */ +PyObject * +_PyInstance_Lookup(PyObject *pinst, PyObject *name) +{ + PyObject *v; + PyClassObject *klass; + PyInstanceObject *inst; /* pinst cast to the right type */ + + assert(PyInstance_Check(pinst)); + inst = (PyInstanceObject *)pinst; + + assert(PyString_Check(name)); + + v = PyDict_GetItem(inst->in_dict, name); + if (v == NULL) + v = class_lookup(inst->in_class, name, &klass); + return v; +} + +static int +instance_setattr1(PyInstanceObject *inst, PyObject *name, PyObject *v) +{ + if (v == NULL) { + int rv = PyDict_DelItem(inst->in_dict, name); + if (rv < 0) + PyErr_Format(PyExc_AttributeError, + "%.50s instance has no attribute '%.400s'", + PyString_AS_STRING(inst->in_class->cl_name), + PyString_AS_STRING(name)); + return rv; + } + else + return PyDict_SetItem(inst->in_dict, name, v); +} + +static int +instance_setattr(PyInstanceObject *inst, PyObject *name, PyObject *v) +{ + PyObject *func, *args, *res, *tmp; + char *sname = PyString_AsString(name); + if (sname[0] == '_' && sname[1] == '_') { + Py_ssize_t n = PyString_Size(name); + if (sname[n-1] == '_' && sname[n-2] == '_') { + if (strcmp(sname, "__dict__") == 0) { + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "__dict__ not accessible in restricted mode"); + return -1; + } + if (v == NULL || !PyDict_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "__dict__ must be set to a dictionary"); + return -1; + } + tmp = inst->in_dict; + Py_INCREF(v); + inst->in_dict = v; + Py_DECREF(tmp); + return 0; + } + if (strcmp(sname, "__class__") == 0) { + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "__class__ not accessible in restricted mode"); + return -1; + } + if (v == NULL || !PyClass_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "__class__ must be set to a class"); + return -1; + } + tmp = (PyObject *)(inst->in_class); + Py_INCREF(v); + inst->in_class = (PyClassObject *)v; + Py_DECREF(tmp); + return 0; + } + } + } + if (v == NULL) + func = inst->in_class->cl_delattr; + else + func = inst->in_class->cl_setattr; + if (func == NULL) + return instance_setattr1(inst, name, v); + if (v == NULL) + args = PyTuple_Pack(2, inst, name); + else + args = PyTuple_Pack(3, inst, name, v); + if (args == NULL) + return -1; + res = PyEval_CallObject(func, args); + Py_DECREF(args); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static PyObject * +instance_repr(PyInstanceObject *inst) +{ + PyObject *func; + PyObject *res; + static PyObject *reprstr; + + if (reprstr == NULL) { + reprstr = PyString_InternFromString("__repr__"); + if (reprstr == NULL) + return NULL; + } + func = instance_getattr(inst, reprstr); + if (func == NULL) { + PyObject *classname, *mod; + char *cname; + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + classname = inst->in_class->cl_name; + mod = PyDict_GetItemString(inst->in_class->cl_dict, + "__module__"); + if (classname != NULL && PyString_Check(classname)) + cname = PyString_AsString(classname); + else + cname = "?"; + if (mod == NULL || !PyString_Check(mod)) + return PyString_FromFormat("<?.%s instance at %p>", + cname, inst); + else + return PyString_FromFormat("<%s.%s instance at %p>", + PyString_AsString(mod), + cname, inst); + } + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + return res; +} + +static PyObject * +instance_str(PyInstanceObject *inst) +{ + PyObject *func; + PyObject *res; + static PyObject *strstr; + + if (strstr == NULL) { + strstr = PyString_InternFromString("__str__"); + if (strstr == NULL) + return NULL; + } + func = instance_getattr(inst, strstr); + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + return instance_repr(inst); + } + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + return res; +} + +static long +instance_hash(PyInstanceObject *inst) +{ + PyObject *func; + PyObject *res; + long outcome; + static PyObject *hashstr, *eqstr, *cmpstr; + + if (hashstr == NULL) { + hashstr = PyString_InternFromString("__hash__"); + if (hashstr == NULL) + return -1; + } + func = instance_getattr(inst, hashstr); + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + /* If there is no __eq__ and no __cmp__ method, we hash on the + address. If an __eq__ or __cmp__ method exists, there must + be a __hash__. */ + if (eqstr == NULL) { + eqstr = PyString_InternFromString("__eq__"); + if (eqstr == NULL) + return -1; + } + func = instance_getattr(inst, eqstr); + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + if (cmpstr == NULL) { + cmpstr = PyString_InternFromString("__cmp__"); + if (cmpstr == NULL) + return -1; + } + func = instance_getattr(inst, cmpstr); + if (func == NULL) { + if (!PyErr_ExceptionMatches( + PyExc_AttributeError)) + return -1; + PyErr_Clear(); + return _Py_HashPointer(inst); + } + } + Py_XDECREF(func); + PyErr_SetString(PyExc_TypeError, "unhashable instance"); + return -1; + } + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res == NULL) + return -1; + if (PyInt_Check(res) || PyLong_Check(res)) + /* This already converts a -1 result to -2. */ + outcome = res->ob_type->tp_hash(res); + else { + PyErr_SetString(PyExc_TypeError, + "__hash__() should return an int"); + outcome = -1; + } + Py_DECREF(res); + return outcome; +} + +static int +instance_traverse(PyInstanceObject *o, visitproc visit, void *arg) +{ + Py_VISIT(o->in_class); + Py_VISIT(o->in_dict); + return 0; +} + +static PyObject *getitemstr, *setitemstr, *delitemstr, *lenstr; +static PyObject *iterstr, *nextstr; + +static Py_ssize_t +instance_length(PyInstanceObject *inst) +{ + PyObject *func; + PyObject *res; + Py_ssize_t outcome; + + if (lenstr == NULL) { + lenstr = PyString_InternFromString("__len__"); + if (lenstr == NULL) + return -1; + } + func = instance_getattr(inst, lenstr); + if (func == NULL) + return -1; + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res == NULL) + return -1; + if (PyInt_Check(res)) { + outcome = PyInt_AsSsize_t(res); + if (outcome == -1 && PyErr_Occurred()) { + Py_DECREF(res); + return -1; + } +#if SIZEOF_SIZE_T < SIZEOF_INT + /* Overflow check -- range of PyInt is more than C int */ + if (outcome != (int)outcome) { + PyErr_SetString(PyExc_OverflowError, + "__len__() should return 0 <= outcome < 2**31"); + outcome = -1; + } + else +#endif + if (outcome < 0) { + PyErr_SetString(PyExc_ValueError, + "__len__() should return >= 0"); + outcome = -1; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "__len__() should return an int"); + outcome = -1; + } + Py_DECREF(res); + return outcome; +} + +static PyObject * +instance_subscript(PyInstanceObject *inst, PyObject *key) +{ + PyObject *func; + PyObject *arg; + PyObject *res; + + if (getitemstr == NULL) { + getitemstr = PyString_InternFromString("__getitem__"); + if (getitemstr == NULL) + return NULL; + } + func = instance_getattr(inst, getitemstr); + if (func == NULL) + return NULL; + arg = PyTuple_Pack(1, key); + if (arg == NULL) { + Py_DECREF(func); + return NULL; + } + res = PyEval_CallObject(func, arg); + Py_DECREF(func); + Py_DECREF(arg); + return res; +} + +static int +instance_ass_subscript(PyInstanceObject *inst, PyObject *key, PyObject *value) +{ + PyObject *func; + PyObject *arg; + PyObject *res; + + if (value == NULL) { + if (delitemstr == NULL) { + delitemstr = PyString_InternFromString("__delitem__"); + if (delitemstr == NULL) + return -1; + } + func = instance_getattr(inst, delitemstr); + } + else { + if (setitemstr == NULL) { + setitemstr = PyString_InternFromString("__setitem__"); + if (setitemstr == NULL) + return -1; + } + func = instance_getattr(inst, setitemstr); + } + if (func == NULL) + return -1; + if (value == NULL) + arg = PyTuple_Pack(1, key); + else + arg = PyTuple_Pack(2, key, value); + if (arg == NULL) { + Py_DECREF(func); + return -1; + } + res = PyEval_CallObject(func, arg); + Py_DECREF(func); + Py_DECREF(arg); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static PyMappingMethods instance_as_mapping = { + (lenfunc)instance_length, /* mp_length */ + (binaryfunc)instance_subscript, /* mp_subscript */ + (objobjargproc)instance_ass_subscript, /* mp_ass_subscript */ +}; + +static PyObject * +instance_item(PyInstanceObject *inst, Py_ssize_t i) +{ + PyObject *func, *res; + + if (getitemstr == NULL) { + getitemstr = PyString_InternFromString("__getitem__"); + if (getitemstr == NULL) + return NULL; + } + func = instance_getattr(inst, getitemstr); + if (func == NULL) + return NULL; + res = PyObject_CallFunction(func, "n", i); + Py_DECREF(func); + return res; +} + +static PyObject * +instance_slice(PyInstanceObject *inst, Py_ssize_t i, Py_ssize_t j) +{ + PyObject *func, *arg, *res; + static PyObject *getslicestr; + + if (getslicestr == NULL) { + getslicestr = PyString_InternFromString("__getslice__"); + if (getslicestr == NULL) + return NULL; + } + func = instance_getattr(inst, getslicestr); + + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + + if (getitemstr == NULL) { + getitemstr = PyString_InternFromString("__getitem__"); + if (getitemstr == NULL) + return NULL; + } + func = instance_getattr(inst, getitemstr); + if (func == NULL) + return NULL; + arg = Py_BuildValue("(N)", _PySlice_FromIndices(i, j)); + } else + arg = Py_BuildValue("(nn)", i, j); + + if (arg == NULL) { + Py_DECREF(func); + return NULL; + } + res = PyEval_CallObject(func, arg); + Py_DECREF(func); + Py_DECREF(arg); + return res; +} + +static int +instance_ass_item(PyInstanceObject *inst, Py_ssize_t i, PyObject *item) +{ + PyObject *func, *arg, *res; + + if (item == NULL) { + if (delitemstr == NULL) { + delitemstr = PyString_InternFromString("__delitem__"); + if (delitemstr == NULL) + return -1; + } + func = instance_getattr(inst, delitemstr); + } + else { + if (setitemstr == NULL) { + setitemstr = PyString_InternFromString("__setitem__"); + if (setitemstr == NULL) + return -1; + } + func = instance_getattr(inst, setitemstr); + } + if (func == NULL) + return -1; + if (item == NULL) + arg = PyInt_FromSsize_t(i); + else + arg = Py_BuildValue("(nO)", i, item); + if (arg == NULL) { + Py_DECREF(func); + return -1; + } + res = PyEval_CallObject(func, arg); + Py_DECREF(func); + Py_DECREF(arg); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static int +instance_ass_slice(PyInstanceObject *inst, Py_ssize_t i, Py_ssize_t j, PyObject *value) +{ + PyObject *func, *arg, *res; + static PyObject *setslicestr, *delslicestr; + + if (value == NULL) { + if (delslicestr == NULL) { + delslicestr = + PyString_InternFromString("__delslice__"); + if (delslicestr == NULL) + return -1; + } + func = instance_getattr(inst, delslicestr); + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + if (delitemstr == NULL) { + delitemstr = + PyString_InternFromString("__delitem__"); + if (delitemstr == NULL) + return -1; + } + func = instance_getattr(inst, delitemstr); + if (func == NULL) + return -1; + + arg = Py_BuildValue("(N)", + _PySlice_FromIndices(i, j)); + } else + arg = Py_BuildValue("(nn)", i, j); + } + else { + if (setslicestr == NULL) { + setslicestr = + PyString_InternFromString("__setslice__"); + if (setslicestr == NULL) + return -1; + } + func = instance_getattr(inst, setslicestr); + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + if (setitemstr == NULL) { + setitemstr = + PyString_InternFromString("__setitem__"); + if (setitemstr == NULL) + return -1; + } + func = instance_getattr(inst, setitemstr); + if (func == NULL) + return -1; + + arg = Py_BuildValue("(NO)", + _PySlice_FromIndices(i, j), value); + } else + arg = Py_BuildValue("(nnO)", i, j, value); + } + if (arg == NULL) { + Py_DECREF(func); + return -1; + } + res = PyEval_CallObject(func, arg); + Py_DECREF(func); + Py_DECREF(arg); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static int +instance_contains(PyInstanceObject *inst, PyObject *member) +{ + static PyObject *__contains__; + PyObject *func; + + /* Try __contains__ first. + * If that can't be done, try iterator-based searching. + */ + + if(__contains__ == NULL) { + __contains__ = PyString_InternFromString("__contains__"); + if(__contains__ == NULL) + return -1; + } + func = instance_getattr(inst, __contains__); + if (func) { + PyObject *res; + int ret; + PyObject *arg = PyTuple_Pack(1, member); + if(arg == NULL) { + Py_DECREF(func); + return -1; + } + res = PyEval_CallObject(func, arg); + Py_DECREF(func); + Py_DECREF(arg); + if(res == NULL) + return -1; + ret = PyObject_IsTrue(res); + Py_DECREF(res); + return ret; + } + + /* Couldn't find __contains__. */ + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_ssize_t rc; + /* Assume the failure was simply due to that there is no + * __contains__ attribute, and try iterating instead. + */ + PyErr_Clear(); + rc = _PySequence_IterSearch((PyObject *)inst, member, + PY_ITERSEARCH_CONTAINS); + if (rc >= 0) + return rc > 0; + } + return -1; +} + +static PySequenceMethods +instance_as_sequence = { + (lenfunc)instance_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)instance_item, /* sq_item */ + (ssizessizeargfunc)instance_slice, /* sq_slice */ + (ssizeobjargproc)instance_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc)instance_ass_slice,/* sq_ass_slice */ + (objobjproc)instance_contains, /* sq_contains */ +}; + +static PyObject * +generic_unary_op(PyInstanceObject *self, PyObject *methodname) +{ + PyObject *func, *res; + + if ((func = instance_getattr(self, methodname)) == NULL) + return NULL; + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + return res; +} + +static PyObject * +generic_binary_op(PyObject *v, PyObject *w, char *opname) +{ + PyObject *result; + PyObject *args; + PyObject *func = PyObject_GetAttrString(v, opname); + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + args = PyTuple_Pack(1, w); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObject(func, args); + Py_DECREF(args); + Py_DECREF(func); + return result; +} + + +static PyObject *coerce_obj; + +/* Try one half of a binary operator involving a class instance. */ +static PyObject * +half_binop(PyObject *v, PyObject *w, char *opname, binaryfunc thisfunc, + int swapped) +{ + PyObject *args; + PyObject *coercefunc; + PyObject *coerced = NULL; + PyObject *v1; + PyObject *result; + + if (!PyInstance_Check(v)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (coerce_obj == NULL) { + coerce_obj = PyString_InternFromString("__coerce__"); + if (coerce_obj == NULL) + return NULL; + } + coercefunc = PyObject_GetAttr(v, coerce_obj); + if (coercefunc == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + return generic_binary_op(v, w, opname); + } + + args = PyTuple_Pack(1, w); + if (args == NULL) { + Py_DECREF(coercefunc); + return NULL; + } + coerced = PyEval_CallObject(coercefunc, args); + Py_DECREF(args); + Py_DECREF(coercefunc); + if (coerced == NULL) { + return NULL; + } + if (coerced == Py_None || coerced == Py_NotImplemented) { + Py_DECREF(coerced); + return generic_binary_op(v, w, opname); + } + if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) { + Py_DECREF(coerced); + PyErr_SetString(PyExc_TypeError, + "coercion should return None or 2-tuple"); + return NULL; + } + v1 = PyTuple_GetItem(coerced, 0); + w = PyTuple_GetItem(coerced, 1); + if (v1->ob_type == v->ob_type && PyInstance_Check(v)) { + /* prevent recursion if __coerce__ returns self as the first + * argument */ + result = generic_binary_op(v1, w, opname); + } else { + if (Py_EnterRecursiveCall(" after coercion")) + return NULL; + if (swapped) + result = (thisfunc)(w, v1); + else + result = (thisfunc)(v1, w); + Py_LeaveRecursiveCall(); + } + Py_DECREF(coerced); + return result; +} + +/* Implement a binary operator involving at least one class instance. */ +static PyObject * +do_binop(PyObject *v, PyObject *w, char *opname, char *ropname, + binaryfunc thisfunc) +{ + PyObject *result = half_binop(v, w, opname, thisfunc, 0); + if (result == Py_NotImplemented) { + Py_DECREF(result); + result = half_binop(w, v, ropname, thisfunc, 1); + } + return result; +} + +static PyObject * +do_binop_inplace(PyObject *v, PyObject *w, char *iopname, char *opname, + char *ropname, binaryfunc thisfunc) +{ + PyObject *result = half_binop(v, w, iopname, thisfunc, 0); + if (result == Py_NotImplemented) { + Py_DECREF(result); + result = do_binop(v, w, opname, ropname, thisfunc); + } + return result; +} + +static int +instance_coerce(PyObject **pv, PyObject **pw) +{ + PyObject *v = *pv; + PyObject *w = *pw; + PyObject *coercefunc; + PyObject *args; + PyObject *coerced; + + if (coerce_obj == NULL) { + coerce_obj = PyString_InternFromString("__coerce__"); + if (coerce_obj == NULL) + return -1; + } + coercefunc = PyObject_GetAttr(v, coerce_obj); + if (coercefunc == NULL) { + /* No __coerce__ method */ + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + return 1; + } + /* Has __coerce__ method: call it */ + args = PyTuple_Pack(1, w); + if (args == NULL) { + return -1; + } + coerced = PyEval_CallObject(coercefunc, args); + Py_DECREF(args); + Py_DECREF(coercefunc); + if (coerced == NULL) { + /* __coerce__ call raised an exception */ + return -1; + } + if (coerced == Py_None || coerced == Py_NotImplemented) { + /* __coerce__ says "I can't do it" */ + Py_DECREF(coerced); + return 1; + } + if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) { + /* __coerce__ return value is malformed */ + Py_DECREF(coerced); + PyErr_SetString(PyExc_TypeError, + "coercion should return None or 2-tuple"); + return -1; + } + /* __coerce__ returned two new values */ + *pv = PyTuple_GetItem(coerced, 0); + *pw = PyTuple_GetItem(coerced, 1); + Py_INCREF(*pv); + Py_INCREF(*pw); + Py_DECREF(coerced); + return 0; +} + +#define UNARY(funcname, methodname) \ +static PyObject *funcname(PyInstanceObject *self) { \ + static PyObject *o; \ + if (o == NULL) { o = PyString_InternFromString(methodname); \ + if (o == NULL) return NULL; } \ + return generic_unary_op(self, o); \ +} + +#define BINARY(f, m, n) \ +static PyObject *f(PyObject *v, PyObject *w) { \ + return do_binop(v, w, "__" m "__", "__r" m "__", n); \ +} + +#define BINARY_INPLACE(f, m, n) \ +static PyObject *f(PyObject *v, PyObject *w) { \ + return do_binop_inplace(v, w, "__i" m "__", "__" m "__", \ + "__r" m "__", n); \ +} + +UNARY(instance_neg, "__neg__") +UNARY(instance_pos, "__pos__") +UNARY(instance_abs, "__abs__") + +BINARY(instance_or, "or", PyNumber_Or) +BINARY(instance_and, "and", PyNumber_And) +BINARY(instance_xor, "xor", PyNumber_Xor) +BINARY(instance_lshift, "lshift", PyNumber_Lshift) +BINARY(instance_rshift, "rshift", PyNumber_Rshift) +BINARY(instance_add, "add", PyNumber_Add) +BINARY(instance_sub, "sub", PyNumber_Subtract) +BINARY(instance_mul, "mul", PyNumber_Multiply) +BINARY(instance_div, "div", PyNumber_Divide) +BINARY(instance_mod, "mod", PyNumber_Remainder) +BINARY(instance_divmod, "divmod", PyNumber_Divmod) +BINARY(instance_floordiv, "floordiv", PyNumber_FloorDivide) +BINARY(instance_truediv, "truediv", PyNumber_TrueDivide) + +BINARY_INPLACE(instance_ior, "or", PyNumber_InPlaceOr) +BINARY_INPLACE(instance_ixor, "xor", PyNumber_InPlaceXor) +BINARY_INPLACE(instance_iand, "and", PyNumber_InPlaceAnd) +BINARY_INPLACE(instance_ilshift, "lshift", PyNumber_InPlaceLshift) +BINARY_INPLACE(instance_irshift, "rshift", PyNumber_InPlaceRshift) +BINARY_INPLACE(instance_iadd, "add", PyNumber_InPlaceAdd) +BINARY_INPLACE(instance_isub, "sub", PyNumber_InPlaceSubtract) +BINARY_INPLACE(instance_imul, "mul", PyNumber_InPlaceMultiply) +BINARY_INPLACE(instance_idiv, "div", PyNumber_InPlaceDivide) +BINARY_INPLACE(instance_imod, "mod", PyNumber_InPlaceRemainder) +BINARY_INPLACE(instance_ifloordiv, "floordiv", PyNumber_InPlaceFloorDivide) +BINARY_INPLACE(instance_itruediv, "truediv", PyNumber_InPlaceTrueDivide) + +/* Try a 3-way comparison, returning an int; v is an instance. Return: + -2 for an exception; + -1 if v < w; + 0 if v == w; + 1 if v > w; + 2 if this particular 3-way comparison is not implemented or undefined. +*/ +static int +half_cmp(PyObject *v, PyObject *w) +{ + static PyObject *cmp_obj; + PyObject *args; + PyObject *cmp_func; + PyObject *result; + long l; + + assert(PyInstance_Check(v)); + + if (cmp_obj == NULL) { + cmp_obj = PyString_InternFromString("__cmp__"); + if (cmp_obj == NULL) + return -2; + } + + cmp_func = PyObject_GetAttr(v, cmp_obj); + if (cmp_func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -2; + PyErr_Clear(); + return 2; + } + + args = PyTuple_Pack(1, w); + if (args == NULL) { + Py_DECREF(cmp_func); + return -2; + } + + result = PyEval_CallObject(cmp_func, args); + Py_DECREF(args); + Py_DECREF(cmp_func); + + if (result == NULL) + return -2; + + if (result == Py_NotImplemented) { + Py_DECREF(result); + return 2; + } + + l = PyInt_AsLong(result); + Py_DECREF(result); + if (l == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "comparison did not return an int"); + return -2; + } + + return l < 0 ? -1 : l > 0 ? 1 : 0; +} + +/* Try a 3-way comparison, returning an int; either v or w is an instance. + We first try a coercion. Return: + -2 for an exception; + -1 if v < w; + 0 if v == w; + 1 if v > w; + 2 if this particular 3-way comparison is not implemented or undefined. + THIS IS ONLY CALLED FROM object.c! +*/ +static int +instance_compare(PyObject *v, PyObject *w) +{ + int c; + + c = PyNumber_CoerceEx(&v, &w); + if (c < 0) + return -2; + if (c == 0) { + /* If neither is now an instance, use regular comparison */ + if (!PyInstance_Check(v) && !PyInstance_Check(w)) { + c = PyObject_Compare(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (PyErr_Occurred()) + return -2; + return c < 0 ? -1 : c > 0 ? 1 : 0; + } + } + else { + /* The coercion didn't do anything. + Treat this the same as returning v and w unchanged. */ + Py_INCREF(v); + Py_INCREF(w); + } + + if (PyInstance_Check(v)) { + c = half_cmp(v, w); + if (c <= 1) { + Py_DECREF(v); + Py_DECREF(w); + return c; + } + } + if (PyInstance_Check(w)) { + c = half_cmp(w, v); + if (c <= 1) { + Py_DECREF(v); + Py_DECREF(w); + if (c >= -1) + c = -c; + return c; + } + } + Py_DECREF(v); + Py_DECREF(w); + return 2; +} + +static int +instance_nonzero(PyInstanceObject *self) +{ + PyObject *func, *res; + long outcome; + static PyObject *nonzerostr; + + if (nonzerostr == NULL) { + nonzerostr = PyString_InternFromString("__nonzero__"); + if (nonzerostr == NULL) + return -1; + } + if ((func = instance_getattr(self, nonzerostr)) == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + if (lenstr == NULL) { + lenstr = PyString_InternFromString("__len__"); + if (lenstr == NULL) + return -1; + } + if ((func = instance_getattr(self, lenstr)) == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + /* Fall back to the default behavior: + all instances are nonzero */ + return 1; + } + } + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res == NULL) + return -1; + if (!PyInt_Check(res)) { + Py_DECREF(res); + PyErr_SetString(PyExc_TypeError, + "__nonzero__ should return an int"); + return -1; + } + outcome = PyInt_AsLong(res); + Py_DECREF(res); + if (outcome < 0) { + PyErr_SetString(PyExc_ValueError, + "__nonzero__ should return >= 0"); + return -1; + } + return outcome > 0; +} + +static PyObject * +instance_index(PyInstanceObject *self) +{ + PyObject *func, *res; + static PyObject *indexstr = NULL; + + if (indexstr == NULL) { + indexstr = PyString_InternFromString("__index__"); + if (indexstr == NULL) + return NULL; + } + if ((func = instance_getattr(self, indexstr)) == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "object cannot be interpreted as an index"); + return NULL; + } + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + return res; +} + + +UNARY(instance_invert, "__invert__") +UNARY(instance_int, "__int__") +UNARY(instance_long, "__long__") +UNARY(instance_float, "__float__") +UNARY(instance_oct, "__oct__") +UNARY(instance_hex, "__hex__") + +static PyObject * +bin_power(PyObject *v, PyObject *w) +{ + return PyNumber_Power(v, w, Py_None); +} + +/* This version is for ternary calls only (z != None) */ +static PyObject * +instance_pow(PyObject *v, PyObject *w, PyObject *z) +{ + if (z == Py_None) { + return do_binop(v, w, "__pow__", "__rpow__", bin_power); + } + else { + PyObject *func; + PyObject *args; + PyObject *result; + + /* XXX Doesn't do coercions... */ + func = PyObject_GetAttrString(v, "__pow__"); + if (func == NULL) + return NULL; + args = PyTuple_Pack(2, w, z); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObject(func, args); + Py_DECREF(func); + Py_DECREF(args); + return result; + } +} + +static PyObject * +bin_inplace_power(PyObject *v, PyObject *w) +{ + return PyNumber_InPlacePower(v, w, Py_None); +} + + +static PyObject * +instance_ipow(PyObject *v, PyObject *w, PyObject *z) +{ + if (z == Py_None) { + return do_binop_inplace(v, w, "__ipow__", "__pow__", + "__rpow__", bin_inplace_power); + } + else { + /* XXX Doesn't do coercions... */ + PyObject *func; + PyObject *args; + PyObject *result; + + func = PyObject_GetAttrString(v, "__ipow__"); + if (func == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + return instance_pow(v, w, z); + } + args = PyTuple_Pack(2, w, z); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObject(func, args); + Py_DECREF(func); + Py_DECREF(args); + return result; + } +} + + +/* Map rich comparison operators to their __xx__ namesakes */ +#define NAME_OPS 6 +static PyObject **name_op = NULL; + +static int +init_name_op(void) +{ + int i; + char *_name_op[] = { + "__lt__", + "__le__", + "__eq__", + "__ne__", + "__gt__", + "__ge__", + }; + + name_op = (PyObject **)malloc(sizeof(PyObject *) * NAME_OPS); + if (name_op == NULL) + return -1; + for (i = 0; i < NAME_OPS; ++i) { + name_op[i] = PyString_InternFromString(_name_op[i]); + if (name_op[i] == NULL) + return -1; + } + return 0; +} + +static PyObject * +half_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *method; + PyObject *args; + PyObject *res; + + assert(PyInstance_Check(v)); + + if (name_op == NULL) { + if (init_name_op() < 0) + return NULL; + } + /* If the instance doesn't define an __getattr__ method, use + instance_getattr2 directly because it will not set an + exception on failure. */ + if (((PyInstanceObject *)v)->in_class->cl_getattr == NULL) + method = instance_getattr2((PyInstanceObject *)v, + name_op[op]); + else + method = PyObject_GetAttr(v, name_op[op]); + if (method == NULL) { + if (PyErr_Occurred()) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + } + res = Py_NotImplemented; + Py_INCREF(res); + return res; + } + + args = PyTuple_Pack(1, w); + if (args == NULL) { + Py_DECREF(method); + return NULL; + } + + res = PyEval_CallObject(method, args); + Py_DECREF(args); + Py_DECREF(method); + + return res; +} + +static PyObject * +instance_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *res; + + if (PyInstance_Check(v)) { + res = half_richcompare(v, w, op); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + + if (PyInstance_Check(w)) { + res = half_richcompare(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + + +/* Get the iterator */ +static PyObject * +instance_getiter(PyInstanceObject *self) +{ + PyObject *func; + + if (iterstr == NULL) { + iterstr = PyString_InternFromString("__iter__"); + if (iterstr == NULL) + return NULL; + } + if (getitemstr == NULL) { + getitemstr = PyString_InternFromString("__getitem__"); + if (getitemstr == NULL) + return NULL; + } + + if ((func = instance_getattr(self, iterstr)) != NULL) { + PyObject *res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res != NULL && !PyIter_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__iter__ returned non-iterator " + "of type '%.100s'", + res->ob_type->tp_name); + Py_DECREF(res); + res = NULL; + } + return res; + } + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + if ((func = instance_getattr(self, getitemstr)) == NULL) { + PyErr_SetString(PyExc_TypeError, + "iteration over non-sequence"); + return NULL; + } + Py_DECREF(func); + return PySeqIter_New((PyObject *)self); +} + + +/* Call the iterator's next */ +static PyObject * +instance_iternext(PyInstanceObject *self) +{ + PyObject *func; + + if (nextstr == NULL) { + nextstr = PyString_InternFromString("next"); + if (nextstr == NULL) + return NULL; + } + + if ((func = instance_getattr(self, nextstr)) != NULL) { + PyObject *res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res != NULL) { + return res; + } + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + return NULL; + } + return NULL; + } + PyErr_SetString(PyExc_TypeError, "instance has no next() method"); + return NULL; +} + +static PyObject * +instance_call(PyObject *func, PyObject *arg, PyObject *kw) +{ + PyObject *res, *call = PyObject_GetAttrString(func, "__call__"); + if (call == NULL) { + PyInstanceObject *inst = (PyInstanceObject*) func; + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + PyErr_Format(PyExc_AttributeError, + "%.200s instance has no __call__ method", + PyString_AsString(inst->in_class->cl_name)); + return NULL; + } + /* We must check and increment the recursion depth here. Scenario: + class A: + pass + A.__call__ = A() # that's right + a = A() # ok + a() # infinite recursion + This bounces between instance_call() and PyObject_Call() without + ever hitting eval_frame() (which has the main recursion check). */ + if (Py_EnterRecursiveCall(" in __call__")) { + res = NULL; + } + else { + res = PyObject_Call(call, arg, kw); + Py_LeaveRecursiveCall(); + } + Py_DECREF(call); + return res; +} + + +static PyNumberMethods instance_as_number = { + instance_add, /* nb_add */ + instance_sub, /* nb_subtract */ + instance_mul, /* nb_multiply */ + instance_div, /* nb_divide */ + instance_mod, /* nb_remainder */ + instance_divmod, /* nb_divmod */ + instance_pow, /* nb_power */ + (unaryfunc)instance_neg, /* nb_negative */ + (unaryfunc)instance_pos, /* nb_positive */ + (unaryfunc)instance_abs, /* nb_absolute */ + (inquiry)instance_nonzero, /* nb_nonzero */ + (unaryfunc)instance_invert, /* nb_invert */ + instance_lshift, /* nb_lshift */ + instance_rshift, /* nb_rshift */ + instance_and, /* nb_and */ + instance_xor, /* nb_xor */ + instance_or, /* nb_or */ + instance_coerce, /* nb_coerce */ + (unaryfunc)instance_int, /* nb_int */ + (unaryfunc)instance_long, /* nb_long */ + (unaryfunc)instance_float, /* nb_float */ + (unaryfunc)instance_oct, /* nb_oct */ + (unaryfunc)instance_hex, /* nb_hex */ + instance_iadd, /* nb_inplace_add */ + instance_isub, /* nb_inplace_subtract */ + instance_imul, /* nb_inplace_multiply */ + instance_idiv, /* nb_inplace_divide */ + instance_imod, /* nb_inplace_remainder */ + instance_ipow, /* nb_inplace_power */ + instance_ilshift, /* nb_inplace_lshift */ + instance_irshift, /* nb_inplace_rshift */ + instance_iand, /* nb_inplace_and */ + instance_ixor, /* nb_inplace_xor */ + instance_ior, /* nb_inplace_or */ + instance_floordiv, /* nb_floor_divide */ + instance_truediv, /* nb_true_divide */ + instance_ifloordiv, /* nb_inplace_floor_divide */ + instance_itruediv, /* nb_inplace_true_divide */ + (unaryfunc)instance_index, /* nb_index */ +}; + +PyTypeObject PyInstance_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "instance", + sizeof(PyInstanceObject), + 0, + (destructor)instance_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + instance_compare, /* tp_compare */ + (reprfunc)instance_repr, /* tp_repr */ + &instance_as_number, /* tp_as_number */ + &instance_as_sequence, /* tp_as_sequence */ + &instance_as_mapping, /* tp_as_mapping */ + (hashfunc)instance_hash, /* tp_hash */ + instance_call, /* tp_call */ + (reprfunc)instance_str, /* tp_str */ + (getattrofunc)instance_getattr, /* tp_getattro */ + (setattrofunc)instance_setattr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES,/*tp_flags*/ + instance_doc, /* tp_doc */ + (traverseproc)instance_traverse, /* tp_traverse */ + 0, /* tp_clear */ + instance_richcompare, /* tp_richcompare */ + offsetof(PyInstanceObject, in_weakreflist), /* tp_weaklistoffset */ + (getiterfunc)instance_getiter, /* tp_iter */ + (iternextfunc)instance_iternext, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + instance_new, /* tp_new */ +}; + + +/* Instance method objects are used for two purposes: + (a) as bound instance methods (returned by instancename.methodname) + (b) as unbound methods (returned by ClassName.methodname) + In case (b), im_self is NULL +*/ + +static PyMethodObject *free_list; + +PyObject * +PyMethod_New(PyObject *func, PyObject *self, PyObject *klass) +{ + register PyMethodObject *im; + if (!PyCallable_Check(func)) { + PyErr_BadInternalCall(); + return NULL; + } + im = free_list; + if (im != NULL) { + free_list = (PyMethodObject *)(im->im_self); + PyObject_INIT(im, &PyMethod_Type); + } + else { + im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); + if (im == NULL) + return NULL; + } + im->im_weakreflist = NULL; + Py_INCREF(func); + im->im_func = func; + Py_XINCREF(self); + im->im_self = self; + Py_XINCREF(klass); + im->im_class = klass; + _PyObject_GC_TRACK(im); + return (PyObject *)im; +} + +/* Descriptors for PyMethod attributes */ + +/* im_class, im_func and im_self are stored in the PyMethod object */ + +#define OFF(x) offsetof(PyMethodObject, x) + +static PyMemberDef instancemethod_memberlist[] = { + {"im_class", T_OBJECT, OFF(im_class), READONLY|RESTRICTED, + "the class associated with a method"}, + {"im_func", T_OBJECT, OFF(im_func), READONLY|RESTRICTED, + "the function (or other callable) implementing a method"}, + {"im_self", T_OBJECT, OFF(im_self), READONLY|RESTRICTED, + "the instance to which a method is bound; None for unbound methods"}, + {NULL} /* Sentinel */ +}; + +/* Christian Tismer argued convincingly that method attributes should + (nearly) always override function attributes. + The one exception is __doc__; there's a default __doc__ which + should only be used for the class, not for instances */ + +static PyObject * +instancemethod_get_doc(PyMethodObject *im, void *context) +{ + static PyObject *docstr; + if (docstr == NULL) { + docstr= PyString_InternFromString("__doc__"); + if (docstr == NULL) + return NULL; + } + return PyObject_GetAttr(im->im_func, docstr); +} + +static PyGetSetDef instancemethod_getset[] = { + {"__doc__", (getter)instancemethod_get_doc, NULL, NULL}, + {0} +}; + +static PyObject * +instancemethod_getattro(PyObject *obj, PyObject *name) +{ + PyMethodObject *im = (PyMethodObject *)obj; + PyTypeObject *tp = obj->ob_type; + PyObject *descr = NULL; + + if (PyType_HasFeature(tp, Py_TPFLAGS_HAVE_CLASS)) { + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + return NULL; + } + descr = _PyType_Lookup(tp, name); + } + + if (descr != NULL) { + descrgetfunc f = TP_DESCR_GET(descr->ob_type); + if (f != NULL) + return f(descr, obj, (PyObject *)obj->ob_type); + else { + Py_INCREF(descr); + return descr; + } + } + + return PyObject_GetAttr(im->im_func, name); +} + +PyDoc_STRVAR(instancemethod_doc, +"instancemethod(function, instance, class)\n\ +\n\ +Create an instance method object."); + +static PyObject * +instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw) +{ + PyObject *func; + PyObject *self; + PyObject *classObj = NULL; + + if (!_PyArg_NoKeywords("instancemethod", kw)) + return NULL; + if (!PyArg_UnpackTuple(args, "instancemethod", 2, 3, + &func, &self, &classObj)) + return NULL; + if (!PyCallable_Check(func)) { + PyErr_SetString(PyExc_TypeError, + "first argument must be callable"); + return NULL; + } + if (self == Py_None) + self = NULL; + if (self == NULL && classObj == NULL) { + PyErr_SetString(PyExc_TypeError, + "unbound methods must have non-NULL im_class"); + return NULL; + } + + return PyMethod_New(func, self, classObj); +} + +static void +instancemethod_dealloc(register PyMethodObject *im) +{ + _PyObject_GC_UNTRACK(im); + if (im->im_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *)im); + Py_DECREF(im->im_func); + Py_XDECREF(im->im_self); + Py_XDECREF(im->im_class); + im->im_self = (PyObject *)free_list; + free_list = im; +} + +static int +instancemethod_compare(PyMethodObject *a, PyMethodObject *b) +{ + int cmp; + cmp = PyObject_Compare(a->im_func, b->im_func); + if (cmp) + return cmp; + + if (a->im_self == b->im_self) + return 0; + if (a->im_self == NULL || b->im_self == NULL) + return (a->im_self < b->im_self) ? -1 : 1; + else + return PyObject_Compare(a->im_self, b->im_self); +} + +static PyObject * +instancemethod_repr(PyMethodObject *a) +{ + PyObject *self = a->im_self; + PyObject *func = a->im_func; + PyObject *klass = a->im_class; + PyObject *funcname = NULL, *klassname = NULL, *result = NULL; + char *sfuncname = "?", *sklassname = "?"; + + funcname = PyObject_GetAttrString(func, "__name__"); + if (funcname == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + } + else if (!PyString_Check(funcname)) { + Py_DECREF(funcname); + funcname = NULL; + } + else + sfuncname = PyString_AS_STRING(funcname); + if (klass == NULL) + klassname = NULL; + else { + klassname = PyObject_GetAttrString(klass, "__name__"); + if (klassname == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return NULL; + PyErr_Clear(); + } + else if (!PyString_Check(klassname)) { + Py_DECREF(klassname); + klassname = NULL; + } + else + sklassname = PyString_AS_STRING(klassname); + } + if (self == NULL) + result = PyString_FromFormat("<unbound method %s.%s>", + sklassname, sfuncname); + else { + /* XXX Shouldn't use repr() here! */ + PyObject *selfrepr = PyObject_Repr(self); + if (selfrepr == NULL) + goto fail; + if (!PyString_Check(selfrepr)) { + Py_DECREF(selfrepr); + goto fail; + } + result = PyString_FromFormat("<bound method %s.%s of %s>", + sklassname, sfuncname, + PyString_AS_STRING(selfrepr)); + Py_DECREF(selfrepr); + } + fail: + Py_XDECREF(funcname); + Py_XDECREF(klassname); + return result; +} + +static long +instancemethod_hash(PyMethodObject *a) +{ + long x, y; + if (a->im_self == NULL) + x = PyObject_Hash(Py_None); + else + x = PyObject_Hash(a->im_self); + if (x == -1) + return -1; + y = PyObject_Hash(a->im_func); + if (y == -1) + return -1; + x = x ^ y; + if (x == -1) + x = -2; + return x; +} + +static int +instancemethod_traverse(PyMethodObject *im, visitproc visit, void *arg) +{ + Py_VISIT(im->im_func); + Py_VISIT(im->im_self); + Py_VISIT(im->im_class); + return 0; +} + +static void +getclassname(PyObject *klass, char *buf, int bufsize) +{ + PyObject *name; + + assert(bufsize > 1); + strcpy(buf, "?"); /* Default outcome */ + if (klass == NULL) + return; + name = PyObject_GetAttrString(klass, "__name__"); + if (name == NULL) { + /* This function cannot return an exception */ + PyErr_Clear(); + return; + } + if (PyString_Check(name)) { + strncpy(buf, PyString_AS_STRING(name), bufsize); + buf[bufsize-1] = '\0'; + } + Py_DECREF(name); +} + +static void +getinstclassname(PyObject *inst, char *buf, int bufsize) +{ + PyObject *klass; + + if (inst == NULL) { + assert(bufsize > 0 && (size_t)bufsize > strlen("nothing")); + strcpy(buf, "nothing"); + return; + } + + klass = PyObject_GetAttrString(inst, "__class__"); + if (klass == NULL) { + /* This function cannot return an exception */ + PyErr_Clear(); + klass = (PyObject *)(inst->ob_type); + Py_INCREF(klass); + } + getclassname(klass, buf, bufsize); + Py_XDECREF(klass); +} + +static PyObject * +instancemethod_call(PyObject *func, PyObject *arg, PyObject *kw) +{ + PyObject *self = PyMethod_GET_SELF(func); + PyObject *klass = PyMethod_GET_CLASS(func); + PyObject *result; + + func = PyMethod_GET_FUNCTION(func); + if (self == NULL) { + /* Unbound methods must be called with an instance of + the class (or a derived class) as first argument */ + int ok; + if (PyTuple_Size(arg) >= 1) + self = PyTuple_GET_ITEM(arg, 0); + if (self == NULL) + ok = 0; + else { + ok = PyObject_IsInstance(self, klass); + if (ok < 0) + return NULL; + } + if (!ok) { + char clsbuf[256]; + char instbuf[256]; + getclassname(klass, clsbuf, sizeof(clsbuf)); + getinstclassname(self, instbuf, sizeof(instbuf)); + PyErr_Format(PyExc_TypeError, + "unbound method %s%s must be called with " + "%s instance as first argument " + "(got %s%s instead)", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + clsbuf, + instbuf, + self == NULL ? "" : " instance"); + return NULL; + } + Py_INCREF(arg); + } + else { + Py_ssize_t argcount = PyTuple_Size(arg); + PyObject *newarg = PyTuple_New(argcount + 1); + int i; + if (newarg == NULL) + return NULL; + Py_INCREF(self); + PyTuple_SET_ITEM(newarg, 0, self); + for (i = 0; i < argcount; i++) { + PyObject *v = PyTuple_GET_ITEM(arg, i); + Py_XINCREF(v); + PyTuple_SET_ITEM(newarg, i+1, v); + } + arg = newarg; + } + result = PyObject_Call((PyObject *)func, arg, kw); + Py_DECREF(arg); + return result; +} + +static PyObject * +instancemethod_descr_get(PyObject *meth, PyObject *obj, PyObject *cls) +{ + /* Don't rebind an already bound method, or an unbound method + of a class that's not a base class of cls. */ + + if (PyMethod_GET_SELF(meth) != NULL) { + /* Already bound */ + Py_INCREF(meth); + return meth; + } + /* No, it is an unbound method */ + if (PyMethod_GET_CLASS(meth) != NULL && cls != NULL) { + /* Do subclass test. If it fails, return meth unchanged. */ + int ok = PyObject_IsSubclass(cls, PyMethod_GET_CLASS(meth)); + if (ok < 0) + return NULL; + if (!ok) { + Py_INCREF(meth); + return meth; + } + } + /* Bind it to obj */ + return PyMethod_New(PyMethod_GET_FUNCTION(meth), obj, cls); +} + +PyTypeObject PyMethod_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "instancemethod", + sizeof(PyMethodObject), + 0, + (destructor)instancemethod_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)instancemethod_compare, /* tp_compare */ + (reprfunc)instancemethod_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)instancemethod_hash, /* tp_hash */ + instancemethod_call, /* tp_call */ + 0, /* tp_str */ + instancemethod_getattro, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + instancemethod_doc, /* tp_doc */ + (traverseproc)instancemethod_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + instancemethod_memberlist, /* tp_members */ + instancemethod_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + instancemethod_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + instancemethod_new, /* tp_new */ +}; + +/* Clear out the free list */ + +void +PyMethod_Fini(void) +{ + while (free_list) { + PyMethodObject *im = free_list; + free_list = (PyMethodObject *)(im->im_self); + PyObject_GC_Del(im); + } +} diff --git a/sys/src/cmd/python/Objects/cobject.c b/sys/src/cmd/python/Objects/cobject.c new file mode 100644 index 000000000..b2cae9a40 --- /dev/null +++ b/sys/src/cmd/python/Objects/cobject.c @@ -0,0 +1,161 @@ + +/* Wrap void* pointers to be passed between C modules */ + +#include "Python.h" + + +/* Declarations for objects of type PyCObject */ + +typedef void (*destructor1)(void *); +typedef void (*destructor2)(void *, void*); + +typedef struct { + PyObject_HEAD + void *cobject; + void *desc; + void (*destructor)(void *); +} PyCObject; + +PyObject * +PyCObject_FromVoidPtr(void *cobj, void (*destr)(void *)) +{ + PyCObject *self; + + self = PyObject_NEW(PyCObject, &PyCObject_Type); + if (self == NULL) + return NULL; + self->cobject=cobj; + self->destructor=destr; + self->desc=NULL; + + return (PyObject *)self; +} + +PyObject * +PyCObject_FromVoidPtrAndDesc(void *cobj, void *desc, + void (*destr)(void *, void *)) +{ + PyCObject *self; + + if (!desc) { + PyErr_SetString(PyExc_TypeError, + "PyCObject_FromVoidPtrAndDesc called with null" + " description"); + return NULL; + } + self = PyObject_NEW(PyCObject, &PyCObject_Type); + if (self == NULL) + return NULL; + self->cobject = cobj; + self->destructor = (destructor1)destr; + self->desc = desc; + + return (PyObject *)self; +} + +void * +PyCObject_AsVoidPtr(PyObject *self) +{ + if (self) { + if (self->ob_type == &PyCObject_Type) + return ((PyCObject *)self)->cobject; + PyErr_SetString(PyExc_TypeError, + "PyCObject_AsVoidPtr with non-C-object"); + } + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, + "PyCObject_AsVoidPtr called with null pointer"); + return NULL; +} + +void * +PyCObject_GetDesc(PyObject *self) +{ + if (self) { + if (self->ob_type == &PyCObject_Type) + return ((PyCObject *)self)->desc; + PyErr_SetString(PyExc_TypeError, + "PyCObject_GetDesc with non-C-object"); + } + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, + "PyCObject_GetDesc called with null pointer"); + return NULL; +} + +void * +PyCObject_Import(char *module_name, char *name) +{ + PyObject *m, *c; + void *r = NULL; + + if ((m = PyImport_ImportModule(module_name))) { + if ((c = PyObject_GetAttrString(m,name))) { + r = PyCObject_AsVoidPtr(c); + Py_DECREF(c); + } + Py_DECREF(m); + } + return r; +} + +int +PyCObject_SetVoidPtr(PyObject *self, void *cobj) +{ + PyCObject* cself = (PyCObject*)self; + if (cself == NULL || !PyCObject_Check(cself) || + cself->destructor != NULL) { + PyErr_SetString(PyExc_TypeError, + "Invalid call to PyCObject_SetVoidPtr"); + return 0; + } + cself->cobject = cobj; + return 1; +} + +static void +PyCObject_dealloc(PyCObject *self) +{ + if (self->destructor) { + if(self->desc) + ((destructor2)(self->destructor))(self->cobject, self->desc); + else + (self->destructor)(self->cobject); + } + PyObject_DEL(self); +} + + +PyDoc_STRVAR(PyCObject_Type__doc__, +"C objects to be exported from one extension module to another\n\ +\n\ +C objects are used for communication between extension modules. They\n\ +provide a way for an extension module to export a C interface to other\n\ +extension modules, so that extension modules can use the Python import\n\ +mechanism to link to one another."); + +PyTypeObject PyCObject_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "PyCObject", /*tp_name*/ + sizeof(PyCObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)PyCObject_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + 0, /*tp_flags*/ + PyCObject_Type__doc__ /*tp_doc*/ +}; diff --git a/sys/src/cmd/python/Objects/codeobject.c b/sys/src/cmd/python/Objects/codeobject.c new file mode 100644 index 000000000..89871d6cf --- /dev/null +++ b/sys/src/cmd/python/Objects/codeobject.c @@ -0,0 +1,590 @@ +#include "Python.h" +#include "code.h" +#include "structmember.h" + +#define NAME_CHARS \ + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz" + +/* all_name_chars(s): true iff all chars in s are valid NAME_CHARS */ + +static int +all_name_chars(unsigned char *s) +{ + static char ok_name_char[256]; + static unsigned char *name_chars = (unsigned char *)NAME_CHARS; + + if (ok_name_char[*name_chars] == 0) { + unsigned char *p; + for (p = name_chars; *p; p++) + ok_name_char[*p] = 1; + } + while (*s) { + if (ok_name_char[*s++] == 0) + return 0; + } + return 1; +} + +static void +intern_strings(PyObject *tuple) +{ + Py_ssize_t i; + + for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) { + PyObject *v = PyTuple_GET_ITEM(tuple, i); + if (v == NULL || !PyString_CheckExact(v)) { + Py_FatalError("non-string found in code slot"); + } + PyString_InternInPlace(&PyTuple_GET_ITEM(tuple, i)); + } +} + + +PyCodeObject * +PyCode_New(int argcount, int nlocals, int stacksize, int flags, + PyObject *code, PyObject *consts, PyObject *names, + PyObject *varnames, PyObject *freevars, PyObject *cellvars, + PyObject *filename, PyObject *name, int firstlineno, + PyObject *lnotab) +{ + PyCodeObject *co; + Py_ssize_t i; + /* Check argument types */ + if (argcount < 0 || nlocals < 0 || + code == NULL || + consts == NULL || !PyTuple_Check(consts) || + names == NULL || !PyTuple_Check(names) || + varnames == NULL || !PyTuple_Check(varnames) || + freevars == NULL || !PyTuple_Check(freevars) || + cellvars == NULL || !PyTuple_Check(cellvars) || + name == NULL || !PyString_Check(name) || + filename == NULL || !PyString_Check(filename) || + lnotab == NULL || !PyString_Check(lnotab) || + !PyObject_CheckReadBuffer(code)) { + PyErr_BadInternalCall(); + return NULL; + } + intern_strings(names); + intern_strings(varnames); + intern_strings(freevars); + intern_strings(cellvars); + /* Intern selected string constants */ + for (i = PyTuple_Size(consts); --i >= 0; ) { + PyObject *v = PyTuple_GetItem(consts, i); + if (!PyString_Check(v)) + continue; + if (!all_name_chars((unsigned char *)PyString_AS_STRING(v))) + continue; + PyString_InternInPlace(&PyTuple_GET_ITEM(consts, i)); + } + co = PyObject_NEW(PyCodeObject, &PyCode_Type); + if (co != NULL) { + co->co_argcount = argcount; + co->co_nlocals = nlocals; + co->co_stacksize = stacksize; + co->co_flags = flags; + Py_INCREF(code); + co->co_code = code; + Py_INCREF(consts); + co->co_consts = consts; + Py_INCREF(names); + co->co_names = names; + Py_INCREF(varnames); + co->co_varnames = varnames; + Py_INCREF(freevars); + co->co_freevars = freevars; + Py_INCREF(cellvars); + co->co_cellvars = cellvars; + Py_INCREF(filename); + co->co_filename = filename; + Py_INCREF(name); + co->co_name = name; + co->co_firstlineno = firstlineno; + Py_INCREF(lnotab); + co->co_lnotab = lnotab; + co->co_zombieframe = NULL; + } + return co; +} + + +#define OFF(x) offsetof(PyCodeObject, x) + +static PyMemberDef code_memberlist[] = { + {"co_argcount", T_INT, OFF(co_argcount), READONLY}, + {"co_nlocals", T_INT, OFF(co_nlocals), READONLY}, + {"co_stacksize",T_INT, OFF(co_stacksize), READONLY}, + {"co_flags", T_INT, OFF(co_flags), READONLY}, + {"co_code", T_OBJECT, OFF(co_code), READONLY}, + {"co_consts", T_OBJECT, OFF(co_consts), READONLY}, + {"co_names", T_OBJECT, OFF(co_names), READONLY}, + {"co_varnames", T_OBJECT, OFF(co_varnames), READONLY}, + {"co_freevars", T_OBJECT, OFF(co_freevars), READONLY}, + {"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY}, + {"co_filename", T_OBJECT, OFF(co_filename), READONLY}, + {"co_name", T_OBJECT, OFF(co_name), READONLY}, + {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY}, + {"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY}, + {NULL} /* Sentinel */ +}; + +/* Helper for code_new: return a shallow copy of a tuple that is + guaranteed to contain exact strings, by converting string subclasses + to exact strings and complaining if a non-string is found. */ +static PyObject* +validate_and_copy_tuple(PyObject *tup) +{ + PyObject *newtuple; + PyObject *item; + Py_ssize_t i, len; + + len = PyTuple_GET_SIZE(tup); + newtuple = PyTuple_New(len); + if (newtuple == NULL) + return NULL; + + for (i = 0; i < len; i++) { + item = PyTuple_GET_ITEM(tup, i); + if (PyString_CheckExact(item)) { + Py_INCREF(item); + } + else if (!PyString_Check(item)) { + PyErr_Format( + PyExc_TypeError, + "name tuples must contain only " + "strings, not '%.500s'", + item->ob_type->tp_name); + Py_DECREF(newtuple); + return NULL; + } + else { + item = PyString_FromStringAndSize( + PyString_AS_STRING(item), + PyString_GET_SIZE(item)); + if (item == NULL) { + Py_DECREF(newtuple); + return NULL; + } + } + PyTuple_SET_ITEM(newtuple, i, item); + } + + return newtuple; +} + +PyDoc_STRVAR(code_doc, +"code(argcount, nlocals, stacksize, flags, codestring, constants, names,\n\ + varnames, filename, name, firstlineno, lnotab[, freevars[, cellvars]])\n\ +\n\ +Create a code object. Not for the faint of heart."); + +static PyObject * +code_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + int argcount; + int nlocals; + int stacksize; + int flags; + PyObject *co = NULL; + PyObject *code; + PyObject *consts; + PyObject *names, *ournames = NULL; + PyObject *varnames, *ourvarnames = NULL; + PyObject *freevars = NULL, *ourfreevars = NULL; + PyObject *cellvars = NULL, *ourcellvars = NULL; + PyObject *filename; + PyObject *name; + int firstlineno; + PyObject *lnotab; + + if (!PyArg_ParseTuple(args, "iiiiSO!O!O!SSiS|O!O!:code", + &argcount, &nlocals, &stacksize, &flags, + &code, + &PyTuple_Type, &consts, + &PyTuple_Type, &names, + &PyTuple_Type, &varnames, + &filename, &name, + &firstlineno, &lnotab, + &PyTuple_Type, &freevars, + &PyTuple_Type, &cellvars)) + return NULL; + + if (argcount < 0) { + PyErr_SetString( + PyExc_ValueError, + "code: argcount must not be negative"); + goto cleanup; + } + + if (nlocals < 0) { + PyErr_SetString( + PyExc_ValueError, + "code: nlocals must not be negative"); + goto cleanup; + } + + ournames = validate_and_copy_tuple(names); + if (ournames == NULL) + goto cleanup; + ourvarnames = validate_and_copy_tuple(varnames); + if (ourvarnames == NULL) + goto cleanup; + if (freevars) + ourfreevars = validate_and_copy_tuple(freevars); + else + ourfreevars = PyTuple_New(0); + if (ourfreevars == NULL) + goto cleanup; + if (cellvars) + ourcellvars = validate_and_copy_tuple(cellvars); + else + ourcellvars = PyTuple_New(0); + if (ourcellvars == NULL) + goto cleanup; + + co = (PyObject *)PyCode_New(argcount, nlocals, stacksize, flags, + code, consts, ournames, ourvarnames, + ourfreevars, ourcellvars, filename, + name, firstlineno, lnotab); + cleanup: + Py_XDECREF(ournames); + Py_XDECREF(ourvarnames); + Py_XDECREF(ourfreevars); + Py_XDECREF(ourcellvars); + return co; +} + +static void +code_dealloc(PyCodeObject *co) +{ + Py_XDECREF(co->co_code); + Py_XDECREF(co->co_consts); + Py_XDECREF(co->co_names); + Py_XDECREF(co->co_varnames); + Py_XDECREF(co->co_freevars); + Py_XDECREF(co->co_cellvars); + Py_XDECREF(co->co_filename); + Py_XDECREF(co->co_name); + Py_XDECREF(co->co_lnotab); + if (co->co_zombieframe != NULL) + PyObject_GC_Del(co->co_zombieframe); + PyObject_DEL(co); +} + +static PyObject * +code_repr(PyCodeObject *co) +{ + char buf[500]; + int lineno = -1; + char *filename = "???"; + char *name = "???"; + + if (co->co_firstlineno != 0) + lineno = co->co_firstlineno; + if (co->co_filename && PyString_Check(co->co_filename)) + filename = PyString_AS_STRING(co->co_filename); + if (co->co_name && PyString_Check(co->co_name)) + name = PyString_AS_STRING(co->co_name); + PyOS_snprintf(buf, sizeof(buf), + "<code object %.100s at %p, file \"%.300s\", line %d>", + name, co, filename, lineno); + return PyString_FromString(buf); +} + +static int +code_compare(PyCodeObject *co, PyCodeObject *cp) +{ + int cmp; + cmp = PyObject_Compare(co->co_name, cp->co_name); + if (cmp) return cmp; + cmp = co->co_argcount - cp->co_argcount; + if (cmp) goto normalize; + cmp = co->co_nlocals - cp->co_nlocals; + if (cmp) goto normalize; + cmp = co->co_flags - cp->co_flags; + if (cmp) goto normalize; + cmp = co->co_firstlineno - cp->co_firstlineno; + if (cmp) goto normalize; + cmp = PyObject_Compare(co->co_code, cp->co_code); + if (cmp) return cmp; + cmp = PyObject_Compare(co->co_consts, cp->co_consts); + if (cmp) return cmp; + cmp = PyObject_Compare(co->co_names, cp->co_names); + if (cmp) return cmp; + cmp = PyObject_Compare(co->co_varnames, cp->co_varnames); + if (cmp) return cmp; + cmp = PyObject_Compare(co->co_freevars, cp->co_freevars); + if (cmp) return cmp; + cmp = PyObject_Compare(co->co_cellvars, cp->co_cellvars); + return cmp; + + normalize: + if (cmp > 0) + return 1; + else if (cmp < 0) + return -1; + else + return 0; +} + +static long +code_hash(PyCodeObject *co) +{ + long h, h0, h1, h2, h3, h4, h5, h6; + h0 = PyObject_Hash(co->co_name); + if (h0 == -1) return -1; + h1 = PyObject_Hash(co->co_code); + if (h1 == -1) return -1; + h2 = PyObject_Hash(co->co_consts); + if (h2 == -1) return -1; + h3 = PyObject_Hash(co->co_names); + if (h3 == -1) return -1; + h4 = PyObject_Hash(co->co_varnames); + if (h4 == -1) return -1; + h5 = PyObject_Hash(co->co_freevars); + if (h5 == -1) return -1; + h6 = PyObject_Hash(co->co_cellvars); + if (h6 == -1) return -1; + h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^ + co->co_argcount ^ co->co_nlocals ^ co->co_flags; + if (h == -1) h = -2; + return h; +} + +/* XXX code objects need to participate in GC? */ + +PyTypeObject PyCode_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "code", + sizeof(PyCodeObject), + 0, + (destructor)code_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)code_compare, /* tp_compare */ + (reprfunc)code_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)code_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + code_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + code_memberlist, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + code_new, /* tp_new */ +}; + +/* All about c_lnotab. + +c_lnotab is an array of unsigned bytes disguised as a Python string. In -O +mode, SET_LINENO opcodes aren't generated, and bytecode offsets are mapped +to source code line #s (when needed for tracebacks) via c_lnotab instead. +The array is conceptually a list of + (bytecode offset increment, line number increment) +pairs. The details are important and delicate, best illustrated by example: + + byte code offset source code line number + 0 1 + 6 2 + 50 7 + 350 307 + 361 308 + +The first trick is that these numbers aren't stored, only the increments +from one row to the next (this doesn't really work, but it's a start): + + 0, 1, 6, 1, 44, 5, 300, 300, 11, 1 + +The second trick is that an unsigned byte can't hold negative values, or +values larger than 255, so (a) there's a deep assumption that byte code +offsets and their corresponding line #s both increase monotonically, and (b) +if at least one column jumps by more than 255 from one row to the next, more +than one pair is written to the table. In case #b, there's no way to know +from looking at the table later how many were written. That's the delicate +part. A user of c_lnotab desiring to find the source line number +corresponding to a bytecode address A should do something like this + + lineno = addr = 0 + for addr_incr, line_incr in c_lnotab: + addr += addr_incr + if addr > A: + return lineno + lineno += line_incr + +In order for this to work, when the addr field increments by more than 255, +the line # increment in each pair generated must be 0 until the remaining addr +increment is < 256. So, in the example above, com_set_lineno should not (as +was actually done until 2.2) expand 300, 300 to 255, 255, 45, 45, but to +255, 0, 45, 255, 0, 45. +*/ + +int +PyCode_Addr2Line(PyCodeObject *co, int addrq) +{ + int size = PyString_Size(co->co_lnotab) / 2; + unsigned char *p = (unsigned char*)PyString_AsString(co->co_lnotab); + int line = co->co_firstlineno; + int addr = 0; + while (--size >= 0) { + addr += *p++; + if (addr > addrq) + break; + line += *p++; + } + return line; +} + +/* + Check whether the current instruction is at the start of a line. + + */ + + /* The theory of SET_LINENO-less tracing. + + In a nutshell, we use the co_lnotab field of the code object + to tell when execution has moved onto a different line. + + As mentioned above, the basic idea is so set things up so + that + + *instr_lb <= frame->f_lasti < *instr_ub + + is true so long as execution does not change lines. + + This is all fairly simple. Digging the information out of + co_lnotab takes some work, but is conceptually clear. + + Somewhat harder to explain is why we don't *always* call the + line trace function when the above test fails. + + Consider this code: + + 1: def f(a): + 2: if a: + 3: print 1 + 4: else: + 5: print 2 + + which compiles to this: + + 2 0 LOAD_FAST 0 (a) + 3 JUMP_IF_FALSE 9 (to 15) + 6 POP_TOP + + 3 7 LOAD_CONST 1 (1) + 10 PRINT_ITEM + 11 PRINT_NEWLINE + 12 JUMP_FORWARD 6 (to 21) + >> 15 POP_TOP + + 5 16 LOAD_CONST 2 (2) + 19 PRINT_ITEM + 20 PRINT_NEWLINE + >> 21 LOAD_CONST 0 (None) + 24 RETURN_VALUE + + If 'a' is false, execution will jump to instruction at offset + 15 and the co_lnotab will claim that execution has moved to + line 3. This is at best misleading. In this case we could + associate the POP_TOP with line 4, but that doesn't make + sense in all cases (I think). + + What we do is only call the line trace function if the co_lnotab + indicates we have jumped to the *start* of a line, i.e. if the + current instruction offset matches the offset given for the + start of a line by the co_lnotab. + + This also takes care of the situation where 'a' is true. + Execution will jump from instruction offset 12 to offset 21. + Then the co_lnotab would imply that execution has moved to line + 5, which is again misleading. + + Why do we set f_lineno when tracing? Well, consider the code + above when 'a' is true. If stepping through this with 'n' in + pdb, you would stop at line 1 with a "call" type event, then + line events on lines 2 and 3, then a "return" type event -- but + you would be shown line 5 during this event. This is a change + from the behaviour in 2.2 and before, and I've found it + confusing in practice. By setting and using f_lineno when + tracing, one can report a line number different from that + suggested by f_lasti on this one occasion where it's desirable. + */ + + +int +PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds) +{ + int size, addr, line; + unsigned char* p; + + p = (unsigned char*)PyString_AS_STRING(co->co_lnotab); + size = PyString_GET_SIZE(co->co_lnotab) / 2; + + addr = 0; + line = co->co_firstlineno; + assert(line > 0); + + /* possible optimization: if f->f_lasti == instr_ub + (likely to be a common case) then we already know + instr_lb -- if we stored the matching value of p + somwhere we could skip the first while loop. */ + + /* see comments in compile.c for the description of + co_lnotab. A point to remember: increments to p + should come in pairs -- although we don't care about + the line increments here, treating them as byte + increments gets confusing, to say the least. */ + + bounds->ap_lower = 0; + while (size > 0) { + if (addr + *p > lasti) + break; + addr += *p++; + if (*p) + bounds->ap_lower = addr; + line += *p++; + --size; + } + + /* If lasti and addr don't match exactly, we don't want to + change the lineno slot on the frame or execute a trace + function. Return -1 instead. + */ + if (addr != lasti) + line = -1; + + if (size > 0) { + while (--size >= 0) { + addr += *p++; + if (*p++) + break; + } + bounds->ap_upper = addr; + } + else { + bounds->ap_upper = INT_MAX; + } + + return line; +} diff --git a/sys/src/cmd/python/Objects/complexobject.c b/sys/src/cmd/python/Objects/complexobject.c new file mode 100644 index 000000000..4de1fb658 --- /dev/null +++ b/sys/src/cmd/python/Objects/complexobject.c @@ -0,0 +1,1031 @@ + +/* Complex object implementation */ + +/* Borrows heavily from floatobject.c */ + +/* Submitted by Jim Hugunin */ + +#include "Python.h" +#include "structmember.h" + +#ifndef WITHOUT_COMPLEX + +/* Precisions used by repr() and str(), respectively. + + The repr() precision (17 significant decimal digits) is the minimal number + that is guaranteed to have enough precision so that if the number is read + back in the exact same binary value is recreated. This is true for IEEE + floating point by design, and also happens to work for all other modern + hardware. + + The str() precision is chosen so that in most cases, the rounding noise + created by various operations is suppressed, while giving plenty of + precision for practical use. +*/ + +#define PREC_REPR 17 +#define PREC_STR 12 + +/* elementary operations on complex numbers */ + +static Py_complex c_1 = {1., 0.}; + +Py_complex +c_sum(Py_complex a, Py_complex b) +{ + Py_complex r; + r.real = a.real + b.real; + r.imag = a.imag + b.imag; + return r; +} + +Py_complex +c_diff(Py_complex a, Py_complex b) +{ + Py_complex r; + r.real = a.real - b.real; + r.imag = a.imag - b.imag; + return r; +} + +Py_complex +c_neg(Py_complex a) +{ + Py_complex r; + r.real = -a.real; + r.imag = -a.imag; + return r; +} + +Py_complex +c_prod(Py_complex a, Py_complex b) +{ + Py_complex r; + r.real = a.real*b.real - a.imag*b.imag; + r.imag = a.real*b.imag + a.imag*b.real; + return r; +} + +Py_complex +c_quot(Py_complex a, Py_complex b) +{ + /****************************************************************** + This was the original algorithm. It's grossly prone to spurious + overflow and underflow errors. It also merrily divides by 0 despite + checking for that(!). The code still serves a doc purpose here, as + the algorithm following is a simple by-cases transformation of this + one: + + Py_complex r; + double d = b.real*b.real + b.imag*b.imag; + if (d == 0.) + errno = EDOM; + r.real = (a.real*b.real + a.imag*b.imag)/d; + r.imag = (a.imag*b.real - a.real*b.imag)/d; + return r; + ******************************************************************/ + + /* This algorithm is better, and is pretty obvious: first divide the + * numerators and denominator by whichever of {b.real, b.imag} has + * larger magnitude. The earliest reference I found was to CACM + * Algorithm 116 (Complex Division, Robert L. Smith, Stanford + * University). As usual, though, we're still ignoring all IEEE + * endcases. + */ + Py_complex r; /* the result */ + const double abs_breal = b.real < 0 ? -b.real : b.real; + const double abs_bimag = b.imag < 0 ? -b.imag : b.imag; + + if (abs_breal >= abs_bimag) { + /* divide tops and bottom by b.real */ + if (abs_breal == 0.0) { + errno = EDOM; + r.real = r.imag = 0.0; + } + else { + const double ratio = b.imag / b.real; + const double denom = b.real + b.imag * ratio; + r.real = (a.real + a.imag * ratio) / denom; + r.imag = (a.imag - a.real * ratio) / denom; + } + } + else { + /* divide tops and bottom by b.imag */ + const double ratio = b.real / b.imag; + const double denom = b.real * ratio + b.imag; + assert(b.imag != 0.0); + r.real = (a.real * ratio + a.imag) / denom; + r.imag = (a.imag * ratio - a.real) / denom; + } + return r; +} + +Py_complex +c_pow(Py_complex a, Py_complex b) +{ + Py_complex r; + double vabs,len,at,phase; + if (b.real == 0. && b.imag == 0.) { + r.real = 1.; + r.imag = 0.; + } + else if (a.real == 0. && a.imag == 0.) { + if (b.imag != 0. || b.real < 0.) + errno = EDOM; + r.real = 0.; + r.imag = 0.; + } + else { + vabs = hypot(a.real,a.imag); + len = pow(vabs,b.real); + at = atan2(a.imag, a.real); + phase = at*b.real; + if (b.imag != 0.0) { + len /= exp(at*b.imag); + phase += b.imag*log(vabs); + } + r.real = len*cos(phase); + r.imag = len*sin(phase); + } + return r; +} + +static Py_complex +c_powu(Py_complex x, long n) +{ + Py_complex r, p; + long mask = 1; + r = c_1; + p = x; + while (mask > 0 && n >= mask) { + if (n & mask) + r = c_prod(r,p); + mask <<= 1; + p = c_prod(p,p); + } + return r; +} + +static Py_complex +c_powi(Py_complex x, long n) +{ + Py_complex cn; + + if (n > 100 || n < -100) { + cn.real = (double) n; + cn.imag = 0.; + return c_pow(x,cn); + } + else if (n > 0) + return c_powu(x,n); + else + return c_quot(c_1,c_powu(x,-n)); + +} + +static PyObject * +complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval) +{ + PyObject *op; + + op = type->tp_alloc(type, 0); + if (op != NULL) + ((PyComplexObject *)op)->cval = cval; + return op; +} + +PyObject * +PyComplex_FromCComplex(Py_complex cval) +{ + register PyComplexObject *op; + + /* Inline PyObject_New */ + op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject)); + if (op == NULL) + return PyErr_NoMemory(); + PyObject_INIT(op, &PyComplex_Type); + op->cval = cval; + return (PyObject *) op; +} + +static PyObject * +complex_subtype_from_doubles(PyTypeObject *type, double real, double imag) +{ + Py_complex c; + c.real = real; + c.imag = imag; + return complex_subtype_from_c_complex(type, c); +} + +PyObject * +PyComplex_FromDoubles(double real, double imag) +{ + Py_complex c; + c.real = real; + c.imag = imag; + return PyComplex_FromCComplex(c); +} + +double +PyComplex_RealAsDouble(PyObject *op) +{ + if (PyComplex_Check(op)) { + return ((PyComplexObject *)op)->cval.real; + } + else { + return PyFloat_AsDouble(op); + } +} + +double +PyComplex_ImagAsDouble(PyObject *op) +{ + if (PyComplex_Check(op)) { + return ((PyComplexObject *)op)->cval.imag; + } + else { + return 0.0; + } +} + +Py_complex +PyComplex_AsCComplex(PyObject *op) +{ + Py_complex cv; + if (PyComplex_Check(op)) { + return ((PyComplexObject *)op)->cval; + } + else { + cv.real = PyFloat_AsDouble(op); + cv.imag = 0.; + return cv; + } +} + +static void +complex_dealloc(PyObject *op) +{ + op->ob_type->tp_free(op); +} + + +static void +complex_to_buf(char *buf, int bufsz, PyComplexObject *v, int precision) +{ + char format[32]; + if (v->cval.real == 0.) { + PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); + PyOS_ascii_formatd(buf, bufsz - 1, format, v->cval.imag); + strncat(buf, "j", 1); + } else { + char re[64], im[64]; + /* Format imaginary part with sign, real part without */ + PyOS_snprintf(format, sizeof(format), "%%.%ig", precision); + PyOS_ascii_formatd(re, sizeof(re), format, v->cval.real); + PyOS_snprintf(format, sizeof(format), "%%+.%ig", precision); + PyOS_ascii_formatd(im, sizeof(im), format, v->cval.imag); + PyOS_snprintf(buf, bufsz, "(%s%sj)", re, im); + } +} + +static int +complex_print(PyComplexObject *v, FILE *fp, int flags) +{ + char buf[100]; + complex_to_buf(buf, sizeof(buf), v, + (flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR); + fputs(buf, fp); + return 0; +} + +static PyObject * +complex_repr(PyComplexObject *v) +{ + char buf[100]; + complex_to_buf(buf, sizeof(buf), v, PREC_REPR); + return PyString_FromString(buf); +} + +static PyObject * +complex_str(PyComplexObject *v) +{ + char buf[100]; + complex_to_buf(buf, sizeof(buf), v, PREC_STR); + return PyString_FromString(buf); +} + +static long +complex_hash(PyComplexObject *v) +{ + long hashreal, hashimag, combined; + hashreal = _Py_HashDouble(v->cval.real); + if (hashreal == -1) + return -1; + hashimag = _Py_HashDouble(v->cval.imag); + if (hashimag == -1) + return -1; + /* Note: if the imaginary part is 0, hashimag is 0 now, + * so the following returns hashreal unchanged. This is + * important because numbers of different types that + * compare equal must have the same hash value, so that + * hash(x + 0*j) must equal hash(x). + */ + combined = hashreal + 1000003 * hashimag; + if (combined == -1) + combined = -2; + return combined; +} + +static PyObject * +complex_add(PyComplexObject *v, PyComplexObject *w) +{ + Py_complex result; + PyFPE_START_PROTECT("complex_add", return 0) + result = c_sum(v->cval,w->cval); + PyFPE_END_PROTECT(result) + return PyComplex_FromCComplex(result); +} + +static PyObject * +complex_sub(PyComplexObject *v, PyComplexObject *w) +{ + Py_complex result; + PyFPE_START_PROTECT("complex_sub", return 0) + result = c_diff(v->cval,w->cval); + PyFPE_END_PROTECT(result) + return PyComplex_FromCComplex(result); +} + +static PyObject * +complex_mul(PyComplexObject *v, PyComplexObject *w) +{ + Py_complex result; + PyFPE_START_PROTECT("complex_mul", return 0) + result = c_prod(v->cval,w->cval); + PyFPE_END_PROTECT(result) + return PyComplex_FromCComplex(result); +} + +static PyObject * +complex_div(PyComplexObject *v, PyComplexObject *w) +{ + Py_complex quot; + PyFPE_START_PROTECT("complex_div", return 0) + errno = 0; + quot = c_quot(v->cval,w->cval); + PyFPE_END_PROTECT(quot) + if (errno == EDOM) { + PyErr_SetString(PyExc_ZeroDivisionError, "complex division"); + return NULL; + } + return PyComplex_FromCComplex(quot); +} + +static PyObject * +complex_classic_div(PyComplexObject *v, PyComplexObject *w) +{ + Py_complex quot; + + if (Py_DivisionWarningFlag >= 2 && + PyErr_Warn(PyExc_DeprecationWarning, + "classic complex division") < 0) + return NULL; + + PyFPE_START_PROTECT("complex_classic_div", return 0) + errno = 0; + quot = c_quot(v->cval,w->cval); + PyFPE_END_PROTECT(quot) + if (errno == EDOM) { + PyErr_SetString(PyExc_ZeroDivisionError, "complex division"); + return NULL; + } + return PyComplex_FromCComplex(quot); +} + +static PyObject * +complex_remainder(PyComplexObject *v, PyComplexObject *w) +{ + Py_complex div, mod; + + if (PyErr_Warn(PyExc_DeprecationWarning, + "complex divmod(), // and % are deprecated") < 0) + return NULL; + + errno = 0; + div = c_quot(v->cval,w->cval); /* The raw divisor value. */ + if (errno == EDOM) { + PyErr_SetString(PyExc_ZeroDivisionError, "complex remainder"); + return NULL; + } + div.real = floor(div.real); /* Use the floor of the real part. */ + div.imag = 0.0; + mod = c_diff(v->cval, c_prod(w->cval, div)); + + return PyComplex_FromCComplex(mod); +} + + +static PyObject * +complex_divmod(PyComplexObject *v, PyComplexObject *w) +{ + Py_complex div, mod; + PyObject *d, *m, *z; + + if (PyErr_Warn(PyExc_DeprecationWarning, + "complex divmod(), // and % are deprecated") < 0) + return NULL; + + errno = 0; + div = c_quot(v->cval,w->cval); /* The raw divisor value. */ + if (errno == EDOM) { + PyErr_SetString(PyExc_ZeroDivisionError, "complex divmod()"); + return NULL; + } + div.real = floor(div.real); /* Use the floor of the real part. */ + div.imag = 0.0; + mod = c_diff(v->cval, c_prod(w->cval, div)); + d = PyComplex_FromCComplex(div); + m = PyComplex_FromCComplex(mod); + z = PyTuple_Pack(2, d, m); + Py_XDECREF(d); + Py_XDECREF(m); + return z; +} + +static PyObject * +complex_pow(PyComplexObject *v, PyObject *w, PyComplexObject *z) +{ + Py_complex p; + Py_complex exponent; + long int_exponent; + + if ((PyObject *)z!=Py_None) { + PyErr_SetString(PyExc_ValueError, "complex modulo"); + return NULL; + } + PyFPE_START_PROTECT("complex_pow", return 0) + errno = 0; + exponent = ((PyComplexObject*)w)->cval; + int_exponent = (long)exponent.real; + if (exponent.imag == 0. && exponent.real == int_exponent) + p = c_powi(v->cval,int_exponent); + else + p = c_pow(v->cval,exponent); + + PyFPE_END_PROTECT(p) + Py_ADJUST_ERANGE2(p.real, p.imag); + if (errno == EDOM) { + PyErr_SetString(PyExc_ZeroDivisionError, + "0.0 to a negative or complex power"); + return NULL; + } + else if (errno == ERANGE) { + PyErr_SetString(PyExc_OverflowError, + "complex exponentiation"); + return NULL; + } + return PyComplex_FromCComplex(p); +} + +static PyObject * +complex_int_div(PyComplexObject *v, PyComplexObject *w) +{ + PyObject *t, *r; + + t = complex_divmod(v, w); + if (t != NULL) { + r = PyTuple_GET_ITEM(t, 0); + Py_INCREF(r); + Py_DECREF(t); + return r; + } + return NULL; +} + +static PyObject * +complex_neg(PyComplexObject *v) +{ + Py_complex neg; + neg.real = -v->cval.real; + neg.imag = -v->cval.imag; + return PyComplex_FromCComplex(neg); +} + +static PyObject * +complex_pos(PyComplexObject *v) +{ + if (PyComplex_CheckExact(v)) { + Py_INCREF(v); + return (PyObject *)v; + } + else + return PyComplex_FromCComplex(v->cval); +} + +static PyObject * +complex_abs(PyComplexObject *v) +{ + double result; + PyFPE_START_PROTECT("complex_abs", return 0) + result = hypot(v->cval.real,v->cval.imag); + PyFPE_END_PROTECT(result) + return PyFloat_FromDouble(result); +} + +static int +complex_nonzero(PyComplexObject *v) +{ + return v->cval.real != 0.0 || v->cval.imag != 0.0; +} + +static int +complex_coerce(PyObject **pv, PyObject **pw) +{ + Py_complex cval; + cval.imag = 0.; + if (PyInt_Check(*pw)) { + cval.real = (double)PyInt_AsLong(*pw); + *pw = PyComplex_FromCComplex(cval); + Py_INCREF(*pv); + return 0; + } + else if (PyLong_Check(*pw)) { + cval.real = PyLong_AsDouble(*pw); + if (cval.real == -1.0 && PyErr_Occurred()) + return -1; + *pw = PyComplex_FromCComplex(cval); + Py_INCREF(*pv); + return 0; + } + else if (PyFloat_Check(*pw)) { + cval.real = PyFloat_AsDouble(*pw); + *pw = PyComplex_FromCComplex(cval); + Py_INCREF(*pv); + return 0; + } + else if (PyComplex_Check(*pw)) { + Py_INCREF(*pv); + Py_INCREF(*pw); + return 0; + } + return 1; /* Can't do it */ +} + +static PyObject * +complex_richcompare(PyObject *v, PyObject *w, int op) +{ + int c; + Py_complex i, j; + PyObject *res; + + c = PyNumber_CoerceEx(&v, &w); + if (c < 0) + return NULL; + if (c > 0) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + /* Make sure both arguments are complex. */ + if (!(PyComplex_Check(v) && PyComplex_Check(w))) { + Py_DECREF(v); + Py_DECREF(w); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + i = ((PyComplexObject *)v)->cval; + j = ((PyComplexObject *)w)->cval; + Py_DECREF(v); + Py_DECREF(w); + + if (op != Py_EQ && op != Py_NE) { + PyErr_SetString(PyExc_TypeError, + "no ordering relation is defined for complex numbers"); + return NULL; + } + + if ((i.real == j.real && i.imag == j.imag) == (op == Py_EQ)) + res = Py_True; + else + res = Py_False; + + Py_INCREF(res); + return res; +} + +static PyObject * +complex_int(PyObject *v) +{ + PyErr_SetString(PyExc_TypeError, + "can't convert complex to int; use int(abs(z))"); + return NULL; +} + +static PyObject * +complex_long(PyObject *v) +{ + PyErr_SetString(PyExc_TypeError, + "can't convert complex to long; use long(abs(z))"); + return NULL; +} + +static PyObject * +complex_float(PyObject *v) +{ + PyErr_SetString(PyExc_TypeError, + "can't convert complex to float; use abs(z)"); + return NULL; +} + +static PyObject * +complex_conjugate(PyObject *self) +{ + Py_complex c; + c = ((PyComplexObject *)self)->cval; + c.imag = -c.imag; + return PyComplex_FromCComplex(c); +} + +static PyObject * +complex_getnewargs(PyComplexObject *v) +{ + return Py_BuildValue("(D)", &v->cval); +} + +static PyMethodDef complex_methods[] = { + {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS}, + {"__getnewargs__", (PyCFunction)complex_getnewargs, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyMemberDef complex_members[] = { + {"real", T_DOUBLE, offsetof(PyComplexObject, cval.real), READONLY, + "the real part of a complex number"}, + {"imag", T_DOUBLE, offsetof(PyComplexObject, cval.imag), READONLY, + "the imaginary part of a complex number"}, + {0}, +}; + +static PyObject * +complex_subtype_from_string(PyTypeObject *type, PyObject *v) +{ + const char *s, *start; + char *end; + double x=0.0, y=0.0, z; + int got_re=0, got_im=0, done=0; + int digit_or_dot; + int sw_error=0; + int sign; + char buffer[256]; /* For errors */ +#ifdef Py_USING_UNICODE + char s_buffer[256]; +#endif + Py_ssize_t len; + + if (PyString_Check(v)) { + s = PyString_AS_STRING(v); + len = PyString_GET_SIZE(v); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(v)) { + if (PyUnicode_GET_SIZE(v) >= (Py_ssize_t)sizeof(s_buffer)) { + PyErr_SetString(PyExc_ValueError, + "complex() literal too large to convert"); + return NULL; + } + if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), + PyUnicode_GET_SIZE(v), + s_buffer, + NULL)) + return NULL; + s = s_buffer; + len = strlen(s); + } +#endif + else if (PyObject_AsCharBuffer(v, &s, &len)) { + PyErr_SetString(PyExc_TypeError, + "complex() arg is not a string"); + return NULL; + } + + /* position on first nonblank */ + start = s; + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (s[0] == '\0') { + PyErr_SetString(PyExc_ValueError, + "complex() arg is an empty string"); + return NULL; + } + + z = -1.0; + sign = 1; + do { + + switch (*s) { + + case '\0': + if (s-start != len) { + PyErr_SetString( + PyExc_ValueError, + "complex() arg contains a null byte"); + return NULL; + } + if(!done) sw_error=1; + break; + + case '-': + sign = -1; + /* Fallthrough */ + case '+': + if (done) sw_error=1; + s++; + if ( *s=='\0'||*s=='+'||*s=='-' || + isspace(Py_CHARMASK(*s)) ) sw_error=1; + break; + + case 'J': + case 'j': + if (got_im || done) { + sw_error = 1; + break; + } + if (z<0.0) { + y=sign; + } + else{ + y=sign*z; + } + got_im=1; + s++; + if (*s!='+' && *s!='-' ) + done=1; + break; + + default: + if (isspace(Py_CHARMASK(*s))) { + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (s[0] != '\0') + sw_error=1; + else + done = 1; + break; + } + digit_or_dot = + (*s=='.' || isdigit(Py_CHARMASK(*s))); + if (done||!digit_or_dot) { + sw_error=1; + break; + } + errno = 0; + PyFPE_START_PROTECT("strtod", return 0) + z = PyOS_ascii_strtod(s, &end) ; + PyFPE_END_PROTECT(z) + if (errno != 0) { + PyOS_snprintf(buffer, sizeof(buffer), + "float() out of range: %.150s", s); + PyErr_SetString( + PyExc_ValueError, + buffer); + return NULL; + } + s=end; + if (*s=='J' || *s=='j') { + + break; + } + if (got_re) { + sw_error=1; + break; + } + + /* accept a real part */ + x=sign*z; + got_re=1; + if (got_im) done=1; + z = -1.0; + sign = 1; + break; + + } /* end of switch */ + + } while (s - start < len && !sw_error); + + if (sw_error) { + PyErr_SetString(PyExc_ValueError, + "complex() arg is a malformed string"); + return NULL; + } + + return complex_subtype_from_doubles(type, x, y); +} + +static PyObject * +complex_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *r, *i, *tmp, *f; + PyNumberMethods *nbr, *nbi = NULL; + Py_complex cr, ci; + int own_r = 0; + static PyObject *complexstr; + static char *kwlist[] = {"real", "imag", 0}; + + r = Py_False; + i = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:complex", kwlist, + &r, &i)) + return NULL; + + /* Special-case for single argument that is already complex */ + if (PyComplex_CheckExact(r) && i == NULL && + type == &PyComplex_Type) { + /* Note that we can't know whether it's safe to return + a complex *subclass* instance as-is, hence the restriction + to exact complexes here. */ + Py_INCREF(r); + return r; + } + if (PyString_Check(r) || PyUnicode_Check(r)) { + if (i != NULL) { + PyErr_SetString(PyExc_TypeError, + "complex() can't take second arg" + " if first is a string"); + return NULL; + } + return complex_subtype_from_string(type, r); + } + if (i != NULL && (PyString_Check(i) || PyUnicode_Check(i))) { + PyErr_SetString(PyExc_TypeError, + "complex() second arg can't be a string"); + return NULL; + } + + /* XXX Hack to support classes with __complex__ method */ + if (complexstr == NULL) { + complexstr = PyString_InternFromString("__complex__"); + if (complexstr == NULL) + return NULL; + } + f = PyObject_GetAttr(r, complexstr); + if (f == NULL) + PyErr_Clear(); + else { + PyObject *args = PyTuple_New(0); + if (args == NULL) + return NULL; + r = PyEval_CallObject(f, args); + Py_DECREF(args); + Py_DECREF(f); + if (r == NULL) + return NULL; + own_r = 1; + } + nbr = r->ob_type->tp_as_number; + if (i != NULL) + nbi = i->ob_type->tp_as_number; + if (nbr == NULL || nbr->nb_float == NULL || + ((i != NULL) && (nbi == NULL || nbi->nb_float == NULL))) { + PyErr_SetString(PyExc_TypeError, + "complex() argument must be a string or a number"); + if (own_r) { + Py_DECREF(r); + } + return NULL; + } + if (PyComplex_Check(r)) { + /* Note that if r is of a complex subtype, we're only + retaining its real & imag parts here, and the return + value is (properly) of the builtin complex type. */ + cr = ((PyComplexObject*)r)->cval; + if (own_r) { + Py_DECREF(r); + } + } + else { + tmp = PyNumber_Float(r); + if (own_r) { + Py_DECREF(r); + } + if (tmp == NULL) + return NULL; + if (!PyFloat_Check(tmp)) { + PyErr_SetString(PyExc_TypeError, + "float(r) didn't return a float"); + Py_DECREF(tmp); + return NULL; + } + cr.real = PyFloat_AsDouble(tmp); + Py_DECREF(tmp); + cr.imag = 0.0; + } + if (i == NULL) { + ci.real = 0.0; + ci.imag = 0.0; + } + else if (PyComplex_Check(i)) + ci = ((PyComplexObject*)i)->cval; + else { + tmp = (*nbi->nb_float)(i); + if (tmp == NULL) + return NULL; + ci.real = PyFloat_AsDouble(tmp); + Py_DECREF(tmp); + ci.imag = 0.; + } + cr.real -= ci.imag; + cr.imag += ci.real; + return complex_subtype_from_c_complex(type, cr); +} + +PyDoc_STRVAR(complex_doc, +"complex(real[, imag]) -> complex number\n" +"\n" +"Create a complex number from a real part and an optional imaginary part.\n" +"This is equivalent to (real + imag*1j) where imag defaults to 0."); + +static PyNumberMethods complex_as_number = { + (binaryfunc)complex_add, /* nb_add */ + (binaryfunc)complex_sub, /* nb_subtract */ + (binaryfunc)complex_mul, /* nb_multiply */ + (binaryfunc)complex_classic_div, /* nb_divide */ + (binaryfunc)complex_remainder, /* nb_remainder */ + (binaryfunc)complex_divmod, /* nb_divmod */ + (ternaryfunc)complex_pow, /* nb_power */ + (unaryfunc)complex_neg, /* nb_negative */ + (unaryfunc)complex_pos, /* nb_positive */ + (unaryfunc)complex_abs, /* nb_absolute */ + (inquiry)complex_nonzero, /* nb_nonzero */ + 0, /* nb_invert */ + 0, /* nb_lshift */ + 0, /* nb_rshift */ + 0, /* nb_and */ + 0, /* nb_xor */ + 0, /* nb_or */ + complex_coerce, /* nb_coerce */ + complex_int, /* nb_int */ + complex_long, /* nb_long */ + complex_float, /* nb_float */ + 0, /* nb_oct */ + 0, /* nb_hex */ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply*/ + 0, /* nb_inplace_divide */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + (binaryfunc)complex_int_div, /* nb_floor_divide */ + (binaryfunc)complex_div, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ +}; + +PyTypeObject PyComplex_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "complex", + sizeof(PyComplexObject), + 0, + complex_dealloc, /* tp_dealloc */ + (printfunc)complex_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)complex_repr, /* tp_repr */ + &complex_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)complex_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)complex_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + complex_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + complex_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + complex_methods, /* tp_methods */ + complex_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + complex_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + +#endif diff --git a/sys/src/cmd/python/Objects/descrobject.c b/sys/src/cmd/python/Objects/descrobject.c new file mode 100644 index 000000000..914b6d35a --- /dev/null +++ b/sys/src/cmd/python/Objects/descrobject.c @@ -0,0 +1,1283 @@ +/* Descriptors -- a new, flexible way to describe attributes */ + +#include "Python.h" +#include "structmember.h" /* Why is this not included in Python.h? */ + +static void +descr_dealloc(PyDescrObject *descr) +{ + _PyObject_GC_UNTRACK(descr); + Py_XDECREF(descr->d_type); + Py_XDECREF(descr->d_name); + PyObject_GC_Del(descr); +} + +static char * +descr_name(PyDescrObject *descr) +{ + if (descr->d_name != NULL && PyString_Check(descr->d_name)) + return PyString_AS_STRING(descr->d_name); + else + return "?"; +} + +static PyObject * +descr_repr(PyDescrObject *descr, char *format) +{ + return PyString_FromFormat(format, descr_name(descr), + descr->d_type->tp_name); +} + +static PyObject * +method_repr(PyMethodDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + "<method '%s' of '%s' objects>"); +} + +static PyObject * +member_repr(PyMemberDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + "<member '%s' of '%s' objects>"); +} + +static PyObject * +getset_repr(PyGetSetDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + "<attribute '%s' of '%s' objects>"); +} + +static PyObject * +wrapperdescr_repr(PyWrapperDescrObject *descr) +{ + return descr_repr((PyDescrObject *)descr, + "<slot wrapper '%s' of '%s' objects>"); +} + +static int +descr_check(PyDescrObject *descr, PyObject *obj, PyObject **pres) +{ + if (obj == NULL) { + Py_INCREF(descr); + *pres = (PyObject *)descr; + return 1; + } + if (!PyObject_TypeCheck(obj, descr->d_type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for '%s' objects " + "doesn't apply to '%s' object", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + obj->ob_type->tp_name); + *pres = NULL; + return 1; + } + return 0; +} + +static PyObject * +classmethod_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) +{ + /* Ensure a valid type. Class methods ignore obj. */ + if (type == NULL) { + if (obj != NULL) + type = (PyObject *)obj->ob_type; + else { + /* Wot - no type?! */ + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for type '%s' " + "needs either an object or a type", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; + } + } + if (!PyType_Check(type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for type '%s' " + "needs a type, not a '%s' as arg 2", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + type->ob_type->tp_name); + return NULL; + } + if (!PyType_IsSubtype((PyTypeObject *)type, descr->d_type)) { + PyErr_Format(PyExc_TypeError, + "descriptor '%s' for type '%s' " + "doesn't apply to type '%s'", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + ((PyTypeObject *)type)->tp_name); + return NULL; + } + return PyCFunction_New(descr->d_method, type); +} + +static PyObject * +method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + return PyCFunction_New(descr->d_method, obj); +} + +static PyObject * +member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + return PyMember_GetOne((char *)obj, descr->d_member); +} + +static PyObject * +getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + if (descr->d_getset->get != NULL) + return descr->d_getset->get(obj, descr->d_getset->closure); + PyErr_Format(PyExc_AttributeError, + "attribute '%.300s' of '%.100s' objects is not readable", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; +} + +static PyObject * +wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) +{ + PyObject *res; + + if (descr_check((PyDescrObject *)descr, obj, &res)) + return res; + return PyWrapper_New((PyObject *)descr, obj); +} + +static int +descr_setcheck(PyDescrObject *descr, PyObject *obj, PyObject *value, + int *pres) +{ + assert(obj != NULL); + if (!PyObject_IsInstance(obj, (PyObject *)(descr->d_type))) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.200s' for '%.100s' objects " + "doesn't apply to '%.100s' object", + descr_name(descr), + descr->d_type->tp_name, + obj->ob_type->tp_name); + *pres = -1; + return 1; + } + return 0; +} + +static int +member_set(PyMemberDescrObject *descr, PyObject *obj, PyObject *value) +{ + int res; + + if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) + return res; + return PyMember_SetOne((char *)obj, descr->d_member, value); +} + +static int +getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) +{ + int res; + + if (descr_setcheck((PyDescrObject *)descr, obj, value, &res)) + return res; + if (descr->d_getset->set != NULL) + return descr->d_getset->set(obj, value, + descr->d_getset->closure); + PyErr_Format(PyExc_AttributeError, + "attribute '%.300s' of '%.100s' objects is not writable", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return -1; +} + +static PyObject * +methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) +{ + Py_ssize_t argc; + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + assert(PyTuple_Check(args)); + argc = PyTuple_GET_SIZE(args); + if (argc < 1) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.300s' of '%.100s' " + "object needs an argument", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; + } + self = PyTuple_GET_ITEM(args, 0); + if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.200s' " + "requires a '%.100s' object " + "but received a '%.100s'", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + self->ob_type->tp_name); + return NULL; + } + + func = PyCFunction_New(descr->d_method, self); + if (func == NULL) + return NULL; + args = PyTuple_GetSlice(args, 1, argc); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObjectWithKeywords(func, args, kwds); + Py_DECREF(args); + Py_DECREF(func); + return result; +} + +static PyObject * +classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, + PyObject *kwds) +{ + PyObject *func, *result; + + func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type); + if (func == NULL) + return NULL; + + result = PyEval_CallObjectWithKeywords(func, args, kwds); + Py_DECREF(func); + return result; +} + +static PyObject * +wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) +{ + Py_ssize_t argc; + PyObject *self, *func, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + assert(PyTuple_Check(args)); + argc = PyTuple_GET_SIZE(args); + if (argc < 1) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.300s' of '%.100s' " + "object needs an argument", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name); + return NULL; + } + self = PyTuple_GET_ITEM(args, 0); + if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { + PyErr_Format(PyExc_TypeError, + "descriptor '%.200s' " + "requires a '%.100s' object " + "but received a '%.100s'", + descr_name((PyDescrObject *)descr), + descr->d_type->tp_name, + self->ob_type->tp_name); + return NULL; + } + + func = PyWrapper_New((PyObject *)descr, self); + if (func == NULL) + return NULL; + args = PyTuple_GetSlice(args, 1, argc); + if (args == NULL) { + Py_DECREF(func); + return NULL; + } + result = PyEval_CallObjectWithKeywords(func, args, kwds); + Py_DECREF(args); + Py_DECREF(func); + return result; +} + +static PyObject * +method_get_doc(PyMethodDescrObject *descr, void *closure) +{ + if (descr->d_method->ml_doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_method->ml_doc); +} + +static PyMemberDef descr_members[] = { + {"__objclass__", T_OBJECT, offsetof(PyDescrObject, d_type), READONLY}, + {"__name__", T_OBJECT, offsetof(PyDescrObject, d_name), READONLY}, + {0} +}; + +static PyGetSetDef method_getset[] = { + {"__doc__", (getter)method_get_doc}, + {0} +}; + +static PyObject * +member_get_doc(PyMemberDescrObject *descr, void *closure) +{ + if (descr->d_member->doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_member->doc); +} + +static PyGetSetDef member_getset[] = { + {"__doc__", (getter)member_get_doc}, + {0} +}; + +static PyObject * +getset_get_doc(PyGetSetDescrObject *descr, void *closure) +{ + if (descr->d_getset->doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_getset->doc); +} + +static PyGetSetDef getset_getset[] = { + {"__doc__", (getter)getset_get_doc}, + {0} +}; + +static PyObject * +wrapperdescr_get_doc(PyWrapperDescrObject *descr, void *closure) +{ + if (descr->d_base->doc == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromString(descr->d_base->doc); +} + +static PyGetSetDef wrapperdescr_getset[] = { + {"__doc__", (getter)wrapperdescr_get_doc}, + {0} +}; + +static int +descr_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyDescrObject *descr = (PyDescrObject *)self; + Py_VISIT(descr->d_type); + return 0; +} + +static PyTypeObject PyMethodDescr_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "method_descriptor", + sizeof(PyMethodDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)method_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)methoddescr_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + method_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)method_get, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +/* This is for METH_CLASS in C, not for "f = classmethod(f)" in Python! */ +static PyTypeObject PyClassMethodDescr_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "classmethod_descriptor", + sizeof(PyMethodDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)method_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)classmethoddescr_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + method_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)classmethod_get, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +static PyTypeObject PyMemberDescr_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "member_descriptor", + sizeof(PyMemberDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)member_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + member_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)member_get, /* tp_descr_get */ + (descrsetfunc)member_set, /* tp_descr_set */ +}; + +static PyTypeObject PyGetSetDescr_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "getset_descriptor", + sizeof(PyGetSetDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)getset_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + getset_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)getset_get, /* tp_descr_get */ + (descrsetfunc)getset_set, /* tp_descr_set */ +}; + +PyTypeObject PyWrapperDescr_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "wrapper_descriptor", + sizeof(PyWrapperDescrObject), + 0, + (destructor)descr_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)wrapperdescr_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)wrapperdescr_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + descr_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + descr_members, /* tp_members */ + wrapperdescr_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + (descrgetfunc)wrapperdescr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +static PyDescrObject * +descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name) +{ + PyDescrObject *descr; + + descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0); + if (descr != NULL) { + Py_XINCREF(type); + descr->d_type = type; + descr->d_name = PyString_InternFromString(name); + if (descr->d_name == NULL) { + Py_DECREF(descr); + descr = NULL; + } + } + return descr; +} + +PyObject * +PyDescr_NewMethod(PyTypeObject *type, PyMethodDef *method) +{ + PyMethodDescrObject *descr; + + descr = (PyMethodDescrObject *)descr_new(&PyMethodDescr_Type, + type, method->ml_name); + if (descr != NULL) + descr->d_method = method; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method) +{ + PyMethodDescrObject *descr; + + descr = (PyMethodDescrObject *)descr_new(&PyClassMethodDescr_Type, + type, method->ml_name); + if (descr != NULL) + descr->d_method = method; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewMember(PyTypeObject *type, PyMemberDef *member) +{ + PyMemberDescrObject *descr; + + descr = (PyMemberDescrObject *)descr_new(&PyMemberDescr_Type, + type, member->name); + if (descr != NULL) + descr->d_member = member; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewGetSet(PyTypeObject *type, PyGetSetDef *getset) +{ + PyGetSetDescrObject *descr; + + descr = (PyGetSetDescrObject *)descr_new(&PyGetSetDescr_Type, + type, getset->name); + if (descr != NULL) + descr->d_getset = getset; + return (PyObject *)descr; +} + +PyObject * +PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) +{ + PyWrapperDescrObject *descr; + + descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type, + type, base->name); + if (descr != NULL) { + descr->d_base = base; + descr->d_wrapped = wrapped; + } + return (PyObject *)descr; +} + + +/* --- Readonly proxy for dictionaries (actually any mapping) --- */ + +/* This has no reason to be in this file except that adding new files is a + bit of a pain */ + +typedef struct { + PyObject_HEAD + PyObject *dict; +} proxyobject; + +static Py_ssize_t +proxy_len(proxyobject *pp) +{ + return PyObject_Size(pp->dict); +} + +static PyObject * +proxy_getitem(proxyobject *pp, PyObject *key) +{ + return PyObject_GetItem(pp->dict, key); +} + +static PyMappingMethods proxy_as_mapping = { + (lenfunc)proxy_len, /* mp_length */ + (binaryfunc)proxy_getitem, /* mp_subscript */ + 0, /* mp_ass_subscript */ +}; + +static int +proxy_contains(proxyobject *pp, PyObject *key) +{ + return PyDict_Contains(pp->dict, key); +} + +static PySequenceMethods proxy_as_sequence = { + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)proxy_contains, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyObject * +proxy_has_key(proxyobject *pp, PyObject *key) +{ + int res = PyDict_Contains(pp->dict, key); + if (res < 0) + return NULL; + return PyBool_FromLong(res); +} + +static PyObject * +proxy_get(proxyobject *pp, PyObject *args) +{ + PyObject *key, *def = Py_None; + + if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) + return NULL; + return PyObject_CallMethod(pp->dict, "get", "(OO)", key, def); +} + +static PyObject * +proxy_keys(proxyobject *pp) +{ + return PyMapping_Keys(pp->dict); +} + +static PyObject * +proxy_values(proxyobject *pp) +{ + return PyMapping_Values(pp->dict); +} + +static PyObject * +proxy_items(proxyobject *pp) +{ + return PyMapping_Items(pp->dict); +} + +static PyObject * +proxy_iterkeys(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "iterkeys", NULL); +} + +static PyObject * +proxy_itervalues(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "itervalues", NULL); +} + +static PyObject * +proxy_iteritems(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "iteritems", NULL); +} +static PyObject * +proxy_copy(proxyobject *pp) +{ + return PyObject_CallMethod(pp->dict, "copy", NULL); +} + +static PyMethodDef proxy_methods[] = { + {"has_key", (PyCFunction)proxy_has_key, METH_O, + PyDoc_STR("D.has_key(k) -> True if D has a key k, else False")}, + {"get", (PyCFunction)proxy_get, METH_VARARGS, + PyDoc_STR("D.get(k[,d]) -> D[k] if D.has_key(k), else d." + " d defaults to None.")}, + {"keys", (PyCFunction)proxy_keys, METH_NOARGS, + PyDoc_STR("D.keys() -> list of D's keys")}, + {"values", (PyCFunction)proxy_values, METH_NOARGS, + PyDoc_STR("D.values() -> list of D's values")}, + {"items", (PyCFunction)proxy_items, METH_NOARGS, + PyDoc_STR("D.items() -> list of D's (key, value) pairs, as 2-tuples")}, + {"iterkeys", (PyCFunction)proxy_iterkeys, METH_NOARGS, + PyDoc_STR("D.iterkeys() -> an iterator over the keys of D")}, + {"itervalues",(PyCFunction)proxy_itervalues, METH_NOARGS, + PyDoc_STR("D.itervalues() -> an iterator over the values of D")}, + {"iteritems", (PyCFunction)proxy_iteritems, METH_NOARGS, + PyDoc_STR("D.iteritems() ->" + " an iterator over the (key, value) items of D")}, + {"copy", (PyCFunction)proxy_copy, METH_NOARGS, + PyDoc_STR("D.copy() -> a shallow copy of D")}, + {0} +}; + +static void +proxy_dealloc(proxyobject *pp) +{ + _PyObject_GC_UNTRACK(pp); + Py_DECREF(pp->dict); + PyObject_GC_Del(pp); +} + +static PyObject * +proxy_getiter(proxyobject *pp) +{ + return PyObject_GetIter(pp->dict); +} + +static PyObject * +proxy_str(proxyobject *pp) +{ + return PyObject_Str(pp->dict); +} + +static int +proxy_traverse(PyObject *self, visitproc visit, void *arg) +{ + proxyobject *pp = (proxyobject *)self; + Py_VISIT(pp->dict); + return 0; +} + +static int +proxy_compare(proxyobject *v, PyObject *w) +{ + return PyObject_Compare(v->dict, w); +} + +static PyObject * +proxy_richcompare(proxyobject *v, PyObject *w, int op) +{ + return PyObject_RichCompare(v->dict, w, op); +} + +static PyTypeObject proxytype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "dictproxy", /* tp_name */ + sizeof(proxyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)proxy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)proxy_compare, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &proxy_as_sequence, /* tp_as_sequence */ + &proxy_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)proxy_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + proxy_traverse, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)proxy_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)proxy_getiter, /* tp_iter */ + 0, /* tp_iternext */ + proxy_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +PyObject * +PyDictProxy_New(PyObject *dict) +{ + proxyobject *pp; + + pp = PyObject_GC_New(proxyobject, &proxytype); + if (pp != NULL) { + Py_INCREF(dict); + pp->dict = dict; + _PyObject_GC_TRACK(pp); + } + return (PyObject *)pp; +} + + +/* --- Wrapper object for "slot" methods --- */ + +/* This has no reason to be in this file except that adding new files is a + bit of a pain */ + +typedef struct { + PyObject_HEAD + PyWrapperDescrObject *descr; + PyObject *self; +} wrapperobject; + +static void +wrapper_dealloc(wrapperobject *wp) +{ + PyObject_GC_UnTrack(wp); + Py_TRASHCAN_SAFE_BEGIN(wp) + Py_XDECREF(wp->descr); + Py_XDECREF(wp->self); + PyObject_GC_Del(wp); + Py_TRASHCAN_SAFE_END(wp) +} + +static int +wrapper_compare(wrapperobject *a, wrapperobject *b) +{ + if (a->descr == b->descr) + return PyObject_Compare(a->self, b->self); + else + return (a->descr < b->descr) ? -1 : 1; +} + +static long +wrapper_hash(wrapperobject *wp) +{ + int x, y; + x = _Py_HashPointer(wp->descr); + if (x == -1) + return -1; + y = PyObject_Hash(wp->self); + if (y == -1) + return -1; + x = x ^ y; + if (x == -1) + x = -2; + return x; +} + +static PyObject * +wrapper_repr(wrapperobject *wp) +{ + return PyString_FromFormat("<method-wrapper '%s' of %s object at %p>", + wp->descr->d_base->name, + wp->self->ob_type->tp_name, + wp->self); +} + +static PyMemberDef wrapper_members[] = { + {"__self__", T_OBJECT, offsetof(wrapperobject, self), READONLY}, + {0} +}; + +static PyObject * +wrapper_objclass(wrapperobject *wp) +{ + PyObject *c = (PyObject *)wp->descr->d_type; + + Py_INCREF(c); + return c; +} + +static PyObject * +wrapper_name(wrapperobject *wp) +{ + char *s = wp->descr->d_base->name; + + return PyString_FromString(s); +} + +static PyObject * +wrapper_doc(wrapperobject *wp) +{ + char *s = wp->descr->d_base->doc; + + if (s == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + else { + return PyString_FromString(s); + } +} + +static PyGetSetDef wrapper_getsets[] = { + {"__objclass__", (getter)wrapper_objclass}, + {"__name__", (getter)wrapper_name}, + {"__doc__", (getter)wrapper_doc}, + {0} +}; + +static PyObject * +wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) +{ + wrapperfunc wrapper = wp->descr->d_base->wrapper; + PyObject *self = wp->self; + + if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) { + wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; + return (*wk)(self, args, wp->descr->d_wrapped, kwds); + } + + if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) { + PyErr_Format(PyExc_TypeError, + "wrapper %s doesn't take keyword arguments", + wp->descr->d_base->name); + return NULL; + } + return (*wrapper)(self, args, wp->descr->d_wrapped); +} + +static int +wrapper_traverse(PyObject *self, visitproc visit, void *arg) +{ + wrapperobject *wp = (wrapperobject *)self; + Py_VISIT(wp->descr); + Py_VISIT(wp->self); + return 0; +} + +static PyTypeObject wrappertype = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "method-wrapper", /* tp_name */ + sizeof(wrapperobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)wrapper_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)wrapper_compare, /* tp_compare */ + (reprfunc)wrapper_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)wrapper_hash, /* tp_hash */ + (ternaryfunc)wrapper_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + wrapper_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + wrapper_members, /* tp_members */ + wrapper_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ +}; + +PyObject * +PyWrapper_New(PyObject *d, PyObject *self) +{ + wrapperobject *wp; + PyWrapperDescrObject *descr; + + assert(PyObject_TypeCheck(d, &PyWrapperDescr_Type)); + descr = (PyWrapperDescrObject *)d; + assert(PyObject_IsInstance(self, (PyObject *)(descr->d_type))); + + wp = PyObject_GC_New(wrapperobject, &wrappertype); + if (wp != NULL) { + Py_INCREF(descr); + wp->descr = descr; + Py_INCREF(self); + wp->self = self; + _PyObject_GC_TRACK(wp); + } + return (PyObject *)wp; +} + + +/* A built-in 'property' type */ + +/* + class property(object): + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + if doc is None and fget is not None and hasattr(fget, "__doc__"): + doc = fget.__doc__ + self.__get = fget + self.__set = fset + self.__del = fdel + self.__doc__ = doc + + def __get__(self, inst, type=None): + if inst is None: + return self + if self.__get is None: + raise AttributeError, "unreadable attribute" + return self.__get(inst) + + def __set__(self, inst, value): + if self.__set is None: + raise AttributeError, "can't set attribute" + return self.__set(inst, value) + + def __delete__(self, inst): + if self.__del is None: + raise AttributeError, "can't delete attribute" + return self.__del(inst) + +*/ + +typedef struct { + PyObject_HEAD + PyObject *prop_get; + PyObject *prop_set; + PyObject *prop_del; + PyObject *prop_doc; +} propertyobject; + +static PyMemberDef property_members[] = { + {"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY}, + {"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY}, + {"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY}, + {"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY}, + {0} +}; + + +static void +property_dealloc(PyObject *self) +{ + propertyobject *gs = (propertyobject *)self; + + _PyObject_GC_UNTRACK(self); + Py_XDECREF(gs->prop_get); + Py_XDECREF(gs->prop_set); + Py_XDECREF(gs->prop_del); + Py_XDECREF(gs->prop_doc); + self->ob_type->tp_free(self); +} + +static PyObject * +property_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + propertyobject *gs = (propertyobject *)self; + + if (obj == NULL || obj == Py_None) { + Py_INCREF(self); + return self; + } + if (gs->prop_get == NULL) { + PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); + return NULL; + } + return PyObject_CallFunction(gs->prop_get, "(O)", obj); +} + +static int +property_descr_set(PyObject *self, PyObject *obj, PyObject *value) +{ + propertyobject *gs = (propertyobject *)self; + PyObject *func, *res; + + if (value == NULL) + func = gs->prop_del; + else + func = gs->prop_set; + if (func == NULL) { + PyErr_SetString(PyExc_AttributeError, + value == NULL ? + "can't delete attribute" : + "can't set attribute"); + return -1; + } + if (value == NULL) + res = PyObject_CallFunction(func, "(O)", obj); + else + res = PyObject_CallFunction(func, "(OO)", obj, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static int +property_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *get = NULL, *set = NULL, *del = NULL, *doc = NULL; + static char *kwlist[] = {"fget", "fset", "fdel", "doc", 0}; + propertyobject *gs = (propertyobject *)self; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO:property", + kwlist, &get, &set, &del, &doc)) + return -1; + + if (get == Py_None) + get = NULL; + if (set == Py_None) + set = NULL; + if (del == Py_None) + del = NULL; + + Py_XINCREF(get); + Py_XINCREF(set); + Py_XINCREF(del); + Py_XINCREF(doc); + + /* if no docstring given and the getter has one, use that one */ + if ((doc == NULL || doc == Py_None) && get != NULL) { + PyObject *get_doc = PyObject_GetAttrString(get, "__doc__"); + if (get_doc != NULL) { + Py_XDECREF(doc); + doc = get_doc; /* get_doc already INCREF'd by GetAttr */ + } else { + PyErr_Clear(); + } + } + + gs->prop_get = get; + gs->prop_set = set; + gs->prop_del = del; + gs->prop_doc = doc; + + return 0; +} + +PyDoc_STRVAR(property_doc, +"property(fget=None, fset=None, fdel=None, doc=None) -> property attribute\n" +"\n" +"fget is a function to be used for getting an attribute value, and likewise\n" +"fset is a function for setting, and fdel a function for del'ing, an\n" +"attribute. Typical use is to define a managed attribute x:\n" +"class C(object):\n" +" def getx(self): return self.__x\n" +" def setx(self, value): self.__x = value\n" +" def delx(self): del self.__x\n" +" x = property(getx, setx, delx, \"I'm the 'x' property.\")"); + +static int +property_traverse(PyObject *self, visitproc visit, void *arg) +{ + propertyobject *pp = (propertyobject *)self; + Py_VISIT(pp->prop_get); + Py_VISIT(pp->prop_set); + Py_VISIT(pp->prop_del); + Py_VISIT(pp->prop_doc); + return 0; +} + +PyTypeObject PyProperty_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "property", /* tp_name */ + sizeof(propertyobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + property_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + property_doc, /* tp_doc */ + property_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + property_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + property_descr_get, /* tp_descr_get */ + property_descr_set, /* tp_descr_set */ + 0, /* tp_dictoffset */ + property_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; diff --git a/sys/src/cmd/python/Objects/dictnotes.txt b/sys/src/cmd/python/Objects/dictnotes.txt new file mode 100644 index 000000000..b0e59a7f1 --- /dev/null +++ b/sys/src/cmd/python/Objects/dictnotes.txt @@ -0,0 +1,250 @@ +NOTES ON OPTIMIZING DICTIONARIES +================================ + + +Principal Use Cases for Dictionaries +------------------------------------ + +Passing keyword arguments + Typically, one read and one write for 1 to 3 elements. + Occurs frequently in normal python code. + +Class method lookup + Dictionaries vary in size with 8 to 16 elements being common. + Usually written once with many lookups. + When base classes are used, there are many failed lookups + followed by a lookup in a base class. + +Instance attribute lookup and Global variables + Dictionaries vary in size. 4 to 10 elements are common. + Both reads and writes are common. + +Builtins + Frequent reads. Almost never written. + Size 126 interned strings (as of Py2.3b1). + A few keys are accessed much more frequently than others. + +Uniquification + Dictionaries of any size. Bulk of work is in creation. + Repeated writes to a smaller set of keys. + Single read of each key. + Some use cases have two consecutive accesses to the same key. + + * Removing duplicates from a sequence. + dict.fromkeys(seqn).keys() + + * Counting elements in a sequence. + for e in seqn: + d[e] = d.get(e,0) + 1 + + * Accumulating references in a dictionary of lists: + + for pagenumber, page in enumerate(pages): + for word in page: + d.setdefault(word, []).append(pagenumber) + + Note, the second example is a use case characterized by a get and set + to the same key. There are similar used cases with a __contains__ + followed by a get, set, or del to the same key. Part of the + justification for d.setdefault is combining the two lookups into one. + +Membership Testing + Dictionaries of any size. Created once and then rarely changes. + Single write to each key. + Many calls to __contains__() or has_key(). + Similar access patterns occur with replacement dictionaries + such as with the % formatting operator. + +Dynamic Mappings + Characterized by deletions interspersed with adds and replacements. + Performance benefits greatly from the re-use of dummy entries. + + +Data Layout (assuming a 32-bit box with 64 bytes per cache line) +---------------------------------------------------------------- + +Smalldicts (8 entries) are attached to the dictobject structure +and the whole group nearly fills two consecutive cache lines. + +Larger dicts use the first half of the dictobject structure (one cache +line) and a separate, continuous block of entries (at 12 bytes each +for a total of 5.333 entries per cache line). + + +Tunable Dictionary Parameters +----------------------------- + +* PyDict_MINSIZE. Currently set to 8. + Must be a power of two. New dicts have to zero-out every cell. + Each additional 8 consumes 1.5 cache lines. Increasing improves + the sparseness of small dictionaries but costs time to read in + the additional cache lines if they are not already in cache. + That case is common when keyword arguments are passed. + +* Maximum dictionary load in PyDict_SetItem. Currently set to 2/3. + Increasing this ratio makes dictionaries more dense resulting + in more collisions. Decreasing it improves sparseness at the + expense of spreading entries over more cache lines and at the + cost of total memory consumed. + + The load test occurs in highly time sensitive code. Efforts + to make the test more complex (for example, varying the load + for different sizes) have degraded performance. + +* Growth rate upon hitting maximum load. Currently set to *2. + Raising this to *4 results in half the number of resizes, + less effort to resize, better sparseness for some (but not + all dict sizes), and potentially doubles memory consumption + depending on the size of the dictionary. Setting to *4 + eliminates every other resize step. + +Tune-ups should be measured across a broad range of applications and +use cases. A change to any parameter will help in some situations and +hurt in others. The key is to find settings that help the most common +cases and do the least damage to the less common cases. Results will +vary dramatically depending on the exact number of keys, whether the +keys are all strings, whether reads or writes dominate, the exact +hash values of the keys (some sets of values have fewer collisions than +others). Any one test or benchmark is likely to prove misleading. + +While making a dictionary more sparse reduces collisions, it impairs +iteration and key listing. Those methods loop over every potential +entry. Doubling the size of dictionary results in twice as many +non-overlapping memory accesses for keys(), items(), values(), +__iter__(), iterkeys(), iteritems(), itervalues(), and update(). +Also, every dictionary iterates at least twice, once for the memset() +when it is created and once by dealloc(). + + +Results of Cache Locality Experiments +------------------------------------- + +When an entry is retrieved from memory, 4.333 adjacent entries are also +retrieved into a cache line. Since accessing items in cache is *much* +cheaper than a cache miss, an enticing idea is to probe the adjacent +entries as a first step in collision resolution. Unfortunately, the +introduction of any regularity into collision searches results in more +collisions than the current random chaining approach. + +Exploiting cache locality at the expense of additional collisions fails +to payoff when the entries are already loaded in cache (the expense +is paid with no compensating benefit). This occurs in small dictionaries +where the whole dictionary fits into a pair of cache lines. It also +occurs frequently in large dictionaries which have a common access pattern +where some keys are accessed much more frequently than others. The +more popular entries *and* their collision chains tend to remain in cache. + +To exploit cache locality, change the collision resolution section +in lookdict() and lookdict_string(). Set i^=1 at the top of the +loop and move the i = (i << 2) + i + perturb + 1 to an unrolled +version of the loop. + +This optimization strategy can be leveraged in several ways: + +* If the dictionary is kept sparse (through the tunable parameters), +then the occurrence of additional collisions is lessened. + +* If lookdict() and lookdict_string() are specialized for small dicts +and for largedicts, then the versions for large_dicts can be given +an alternate search strategy without increasing collisions in small dicts +which already have the maximum benefit of cache locality. + +* If the use case for a dictionary is known to have a random key +access pattern (as opposed to a more common pattern with a Zipf's law +distribution), then there will be more benefit for large dictionaries +because any given key is no more likely than another to already be +in cache. + +* In use cases with paired accesses to the same key, the second access +is always in cache and gets no benefit from efforts to further improve +cache locality. + +Optimizing the Search of Small Dictionaries +------------------------------------------- + +If lookdict() and lookdict_string() are specialized for smaller dictionaries, +then a custom search approach can be implemented that exploits the small +search space and cache locality. + +* The simplest example is a linear search of contiguous entries. This is + simple to implement, guaranteed to terminate rapidly, never searches + the same entry twice, and precludes the need to check for dummy entries. + +* A more advanced example is a self-organizing search so that the most + frequently accessed entries get probed first. The organization + adapts if the access pattern changes over time. Treaps are ideally + suited for self-organization with the most common entries at the + top of the heap and a rapid binary search pattern. Most probes and + results are all located at the top of the tree allowing them all to + be located in one or two cache lines. + +* Also, small dictionaries may be made more dense, perhaps filling all + eight cells to take the maximum advantage of two cache lines. + + +Strategy Pattern +---------------- + +Consider allowing the user to set the tunable parameters or to select a +particular search method. Since some dictionary use cases have known +sizes and access patterns, the user may be able to provide useful hints. + +1) For example, if membership testing or lookups dominate runtime and memory + is not at a premium, the user may benefit from setting the maximum load + ratio at 5% or 10% instead of the usual 66.7%. This will sharply + curtail the number of collisions but will increase iteration time. + The builtin namespace is a prime example of a dictionary that can + benefit from being highly sparse. + +2) Dictionary creation time can be shortened in cases where the ultimate + size of the dictionary is known in advance. The dictionary can be + pre-sized so that no resize operations are required during creation. + Not only does this save resizes, but the key insertion will go + more quickly because the first half of the keys will be inserted into + a more sparse environment than before. The preconditions for this + strategy arise whenever a dictionary is created from a key or item + sequence and the number of *unique* keys is known. + +3) If the key space is large and the access pattern is known to be random, + then search strategies exploiting cache locality can be fruitful. + The preconditions for this strategy arise in simulations and + numerical analysis. + +4) If the keys are fixed and the access pattern strongly favors some of + the keys, then the entries can be stored contiguously and accessed + with a linear search or treap. This exploits knowledge of the data, + cache locality, and a simplified search routine. It also eliminates + the need to test for dummy entries on each probe. The preconditions + for this strategy arise in symbol tables and in the builtin dictionary. + + +Readonly Dictionaries +--------------------- +Some dictionary use cases pass through a build stage and then move to a +more heavily exercised lookup stage with no further changes to the +dictionary. + +An idea that emerged on python-dev is to be able to convert a dictionary +to a read-only state. This can help prevent programming errors and also +provide knowledge that can be exploited for lookup optimization. + +The dictionary can be immediately rebuilt (eliminating dummy entries), +resized (to an appropriate level of sparseness), and the keys can be +jostled (to minimize collisions). The lookdict() routine can then +eliminate the test for dummy entries (saving about 1/4 of the time +spent in the collision resolution loop). + +An additional possibility is to insert links into the empty spaces +so that dictionary iteration can proceed in len(d) steps instead of +(mp->mask + 1) steps. Alternatively, a separate tuple of keys can be +kept just for iteration. + + +Caching Lookups +--------------- +The idea is to exploit key access patterns by anticipating future lookups +based on previous lookups. + +The simplest incarnation is to save the most recently accessed entry. +This gives optimal performance for use cases where every get is followed +by a set or del to the same key. diff --git a/sys/src/cmd/python/Objects/dictobject.c b/sys/src/cmd/python/Objects/dictobject.c new file mode 100644 index 000000000..af0d6f37a --- /dev/null +++ b/sys/src/cmd/python/Objects/dictobject.c @@ -0,0 +1,2486 @@ + +/* Dictionary object implementation using a hash table */ + +/* The distribution includes a separate file, Objects/dictnotes.txt, + describing explorations into dictionary design and optimization. + It covers typical dictionary use patterns, the parameters for + tuning dictionaries, and several ideas for possible optimizations. +*/ + +#include "Python.h" + +typedef PyDictEntry dictentry; +typedef PyDictObject dictobject; + +/* Set a key error with the specified argument, wrapping it in a + * tuple automatically so that tuple keys are not unpacked as the + * exception arguments. */ +static void +set_key_error(PyObject *arg) +{ + PyObject *tup; + tup = PyTuple_Pack(1, arg); + if (!tup) + return; /* caller will expect error to be set anyway */ + PyErr_SetObject(PyExc_KeyError, tup); + Py_DECREF(tup); +} + +/* Define this out if you don't want conversion statistics on exit. */ +#undef SHOW_CONVERSION_COUNTS + +/* See large comment block below. This must be >= 1. */ +#define PERTURB_SHIFT 5 + +/* +Major subtleties ahead: Most hash schemes depend on having a "good" hash +function, in the sense of simulating randomness. Python doesn't: its most +important hash functions (for strings and ints) are very regular in common +cases: + +>>> map(hash, (0, 1, 2, 3)) +[0, 1, 2, 3] +>>> map(hash, ("namea", "nameb", "namec", "named")) +[-1658398457, -1658398460, -1658398459, -1658398462] +>>> + +This isn't necessarily bad! To the contrary, in a table of size 2**i, taking +the low-order i bits as the initial table index is extremely fast, and there +are no collisions at all for dicts indexed by a contiguous range of ints. +The same is approximately true when keys are "consecutive" strings. So this +gives better-than-random behavior in common cases, and that's very desirable. + +OTOH, when collisions occur, the tendency to fill contiguous slices of the +hash table makes a good collision resolution strategy crucial. Taking only +the last i bits of the hash code is also vulnerable: for example, consider +[i << 16 for i in range(20000)] as a set of keys. Since ints are their own +hash codes, and this fits in a dict of size 2**15, the last 15 bits of every +hash code are all 0: they *all* map to the same table index. + +But catering to unusual cases should not slow the usual ones, so we just take +the last i bits anyway. It's up to collision resolution to do the rest. If +we *usually* find the key we're looking for on the first try (and, it turns +out, we usually do -- the table load factor is kept under 2/3, so the odds +are solidly in our favor), then it makes best sense to keep the initial index +computation dirt cheap. + +The first half of collision resolution is to visit table indices via this +recurrence: + + j = ((5*j) + 1) mod 2**i + +For any initial j in range(2**i), repeating that 2**i times generates each +int in range(2**i) exactly once (see any text on random-number generation for +proof). By itself, this doesn't help much: like linear probing (setting +j += 1, or j -= 1, on each loop trip), it scans the table entries in a fixed +order. This would be bad, except that's not the only thing we do, and it's +actually *good* in the common cases where hash keys are consecutive. In an +example that's really too small to make this entirely clear, for a table of +size 2**3 the order of indices is: + + 0 -> 1 -> 6 -> 7 -> 4 -> 5 -> 2 -> 3 -> 0 [and here it's repeating] + +If two things come in at index 5, the first place we look after is index 2, +not 6, so if another comes in at index 6 the collision at 5 didn't hurt it. +Linear probing is deadly in this case because there the fixed probe order +is the *same* as the order consecutive keys are likely to arrive. But it's +extremely unlikely hash codes will follow a 5*j+1 recurrence by accident, +and certain that consecutive hash codes do not. + +The other half of the strategy is to get the other bits of the hash code +into play. This is done by initializing a (unsigned) vrbl "perturb" to the +full hash code, and changing the recurrence to: + + j = (5*j) + 1 + perturb; + perturb >>= PERTURB_SHIFT; + use j % 2**i as the next table index; + +Now the probe sequence depends (eventually) on every bit in the hash code, +and the pseudo-scrambling property of recurring on 5*j+1 is more valuable, +because it quickly magnifies small differences in the bits that didn't affect +the initial index. Note that because perturb is unsigned, if the recurrence +is executed often enough perturb eventually becomes and remains 0. At that +point (very rarely reached) the recurrence is on (just) 5*j+1 again, and +that's certain to find an empty slot eventually (since it generates every int +in range(2**i), and we make sure there's always at least one empty slot). + +Selecting a good value for PERTURB_SHIFT is a balancing act. You want it +small so that the high bits of the hash code continue to affect the probe +sequence across iterations; but you want it large so that in really bad cases +the high-order hash bits have an effect on early iterations. 5 was "the +best" in minimizing total collisions across experiments Tim Peters ran (on +both normal and pathological cases), but 4 and 6 weren't significantly worse. + +Historical: Reimer Behrends contributed the idea of using a polynomial-based +approach, using repeated multiplication by x in GF(2**n) where an irreducible +polynomial for each table size was chosen such that x was a primitive root. +Christian Tismer later extended that to use division by x instead, as an +efficient way to get the high bits of the hash code into play. This scheme +also gave excellent collision statistics, but was more expensive: two +if-tests were required inside the loop; computing "the next" index took about +the same number of operations but without as much potential parallelism +(e.g., computing 5*j can go on at the same time as computing 1+perturb in the +above, and then shifting perturb can be done while the table index is being +masked); and the dictobject struct required a member to hold the table's +polynomial. In Tim's experiments the current scheme ran faster, produced +equally good collision statistics, needed less code & used less memory. + +Theoretical Python 2.5 headache: hash codes are only C "long", but +sizeof(Py_ssize_t) > sizeof(long) may be possible. In that case, and if a +dict is genuinely huge, then only the slots directly reachable via indexing +by a C long can be the first slot in a probe sequence. The probe sequence +will still eventually reach every slot in the table, but the collision rate +on initial probes may be much higher than this scheme was designed for. +Getting a hash code as fat as Py_ssize_t is the only real cure. But in +practice, this probably won't make a lick of difference for many years (at +which point everyone will have terabytes of RAM on 64-bit boxes). +*/ + +/* Object used as dummy key to fill deleted entries */ +static PyObject *dummy = NULL; /* Initialized by first call to newdictobject() */ + +#ifdef Py_REF_DEBUG +PyObject * +_PyDict_Dummy(void) +{ + return dummy; +} +#endif + +/* forward declarations */ +static dictentry * +lookdict_string(dictobject *mp, PyObject *key, long hash); + +#ifdef SHOW_CONVERSION_COUNTS +static long created = 0L; +static long converted = 0L; + +static void +show_counts(void) +{ + fprintf(stderr, "created %ld string dicts\n", created); + fprintf(stderr, "converted %ld to normal dicts\n", converted); + fprintf(stderr, "%.2f%% conversion rate\n", (100.0*converted)/created); +} +#endif + +/* Initialization macros. + There are two ways to create a dict: PyDict_New() is the main C API + function, and the tp_new slot maps to dict_new(). In the latter case we + can save a little time over what PyDict_New does because it's guaranteed + that the PyDictObject struct is already zeroed out. + Everyone except dict_new() should use EMPTY_TO_MINSIZE (unless they have + an excellent reason not to). +*/ + +#define INIT_NONZERO_DICT_SLOTS(mp) do { \ + (mp)->ma_table = (mp)->ma_smalltable; \ + (mp)->ma_mask = PyDict_MINSIZE - 1; \ + } while(0) + +#define EMPTY_TO_MINSIZE(mp) do { \ + memset((mp)->ma_smalltable, 0, sizeof((mp)->ma_smalltable)); \ + (mp)->ma_used = (mp)->ma_fill = 0; \ + INIT_NONZERO_DICT_SLOTS(mp); \ + } while(0) + +/* Dictionary reuse scheme to save calls to malloc, free, and memset */ +#define MAXFREEDICTS 80 +static PyDictObject *free_dicts[MAXFREEDICTS]; +static int num_free_dicts = 0; + +PyObject * +PyDict_New(void) +{ + register dictobject *mp; + if (dummy == NULL) { /* Auto-initialize dummy */ + dummy = PyString_FromString("<dummy key>"); + if (dummy == NULL) + return NULL; +#ifdef SHOW_CONVERSION_COUNTS + Py_AtExit(show_counts); +#endif + } + if (num_free_dicts) { + mp = free_dicts[--num_free_dicts]; + assert (mp != NULL); + assert (mp->ob_type == &PyDict_Type); + _Py_NewReference((PyObject *)mp); + if (mp->ma_fill) { + EMPTY_TO_MINSIZE(mp); + } + assert (mp->ma_used == 0); + assert (mp->ma_table == mp->ma_smalltable); + assert (mp->ma_mask == PyDict_MINSIZE - 1); + } else { + mp = PyObject_GC_New(dictobject, &PyDict_Type); + if (mp == NULL) + return NULL; + EMPTY_TO_MINSIZE(mp); + } + mp->ma_lookup = lookdict_string; +#ifdef SHOW_CONVERSION_COUNTS + ++created; +#endif + _PyObject_GC_TRACK(mp); + return (PyObject *)mp; +} + +/* +The basic lookup function used by all operations. +This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. +Open addressing is preferred over chaining since the link overhead for +chaining would be substantial (100% with typical malloc overhead). + +The initial probe index is computed as hash mod the table size. Subsequent +probe indices are computed as explained earlier. + +All arithmetic on hash should ignore overflow. + +(The details in this version are due to Tim Peters, building on many past +contributions by Reimer Behrends, Jyrki Alakuijala, Vladimir Marangozov and +Christian Tismer). + +lookdict() is general-purpose, and may return NULL if (and only if) a +comparison raises an exception (this was new in Python 2.5). +lookdict_string() below is specialized to string keys, comparison of which can +never raise an exception; that function can never return NULL. For both, when +the key isn't found a dictentry* is returned for which the me_value field is +NULL; this is the slot in the dict at which the key would have been found, and +the caller can (if it wishes) add the <key, value> pair to the returned +dictentry*. +*/ +static dictentry * +lookdict(dictobject *mp, PyObject *key, register long hash) +{ + register size_t i; + register size_t perturb; + register dictentry *freeslot; + register size_t mask = (size_t)mp->ma_mask; + dictentry *ep0 = mp->ma_table; + register dictentry *ep; + register int cmp; + PyObject *startkey; + + i = (size_t)hash & mask; + ep = &ep0[i]; + if (ep->me_key == NULL || ep->me_key == key) + return ep; + + if (ep->me_key == dummy) + freeslot = ep; + else { + if (ep->me_hash == hash) { + startkey = ep->me_key; + cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + if (cmp < 0) + return NULL; + if (ep0 == mp->ma_table && ep->me_key == startkey) { + if (cmp > 0) + return ep; + } + else { + /* The compare did major nasty stuff to the + * dict: start over. + * XXX A clever adversary could prevent this + * XXX from terminating. + */ + return lookdict(mp, key, hash); + } + } + freeslot = NULL; + } + + /* In the loop, me_key == dummy is by far (factor of 100s) the + least likely outcome, so test for that last. */ + for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + ep = &ep0[i & mask]; + if (ep->me_key == NULL) + return freeslot == NULL ? ep : freeslot; + if (ep->me_key == key) + return ep; + if (ep->me_hash == hash && ep->me_key != dummy) { + startkey = ep->me_key; + cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + if (cmp < 0) + return NULL; + if (ep0 == mp->ma_table && ep->me_key == startkey) { + if (cmp > 0) + return ep; + } + else { + /* The compare did major nasty stuff to the + * dict: start over. + * XXX A clever adversary could prevent this + * XXX from terminating. + */ + return lookdict(mp, key, hash); + } + } + else if (ep->me_key == dummy && freeslot == NULL) + freeslot = ep; + } + assert(0); /* NOT REACHED */ + return 0; +} + +/* + * Hacked up version of lookdict which can assume keys are always strings; + * this assumption allows testing for errors during PyObject_RichCompareBool() + * to be dropped; string-string comparisons never raise exceptions. This also + * means we don't need to go through PyObject_RichCompareBool(); we can always + * use _PyString_Eq() directly. + * + * This is valuable because dicts with only string keys are very common. + */ +static dictentry * +lookdict_string(dictobject *mp, PyObject *key, register long hash) +{ + register size_t i; + register size_t perturb; + register dictentry *freeslot; + register size_t mask = (size_t)mp->ma_mask; + dictentry *ep0 = mp->ma_table; + register dictentry *ep; + + /* Make sure this function doesn't have to handle non-string keys, + including subclasses of str; e.g., one reason to subclass + strings is to override __eq__, and for speed we don't cater to + that here. */ + if (!PyString_CheckExact(key)) { +#ifdef SHOW_CONVERSION_COUNTS + ++converted; +#endif + mp->ma_lookup = lookdict; + return lookdict(mp, key, hash); + } + i = hash & mask; + ep = &ep0[i]; + if (ep->me_key == NULL || ep->me_key == key) + return ep; + if (ep->me_key == dummy) + freeslot = ep; + else { + if (ep->me_hash == hash && _PyString_Eq(ep->me_key, key)) + return ep; + freeslot = NULL; + } + + /* In the loop, me_key == dummy is by far (factor of 100s) the + least likely outcome, so test for that last. */ + for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + ep = &ep0[i & mask]; + if (ep->me_key == NULL) + return freeslot == NULL ? ep : freeslot; + if (ep->me_key == key + || (ep->me_hash == hash + && ep->me_key != dummy + && _PyString_Eq(ep->me_key, key))) + return ep; + if (ep->me_key == dummy && freeslot == NULL) + freeslot = ep; + } + assert(0); /* NOT REACHED */ + return 0; +} + +/* +Internal routine to insert a new item into the table. +Used both by the internal resize routine and by the public insert routine. +Eats a reference to key and one to value. +Returns -1 if an error occurred, or 0 on success. +*/ +static int +insertdict(register dictobject *mp, PyObject *key, long hash, PyObject *value) +{ + PyObject *old_value; + register dictentry *ep; + typedef PyDictEntry *(*lookupfunc)(PyDictObject *, PyObject *, long); + + assert(mp->ma_lookup != NULL); + ep = mp->ma_lookup(mp, key, hash); + if (ep == NULL) { + Py_DECREF(key); + Py_DECREF(value); + return -1; + } + if (ep->me_value != NULL) { + old_value = ep->me_value; + ep->me_value = value; + Py_DECREF(old_value); /* which **CAN** re-enter */ + Py_DECREF(key); + } + else { + if (ep->me_key == NULL) + mp->ma_fill++; + else { + assert(ep->me_key == dummy); + Py_DECREF(dummy); + } + ep->me_key = key; + ep->me_hash = (Py_ssize_t)hash; + ep->me_value = value; + mp->ma_used++; + } + return 0; +} + +/* +Internal routine used by dictresize() to insert an item which is +known to be absent from the dict. This routine also assumes that +the dict contains no deleted entries. Besides the performance benefit, +using insertdict() in dictresize() is dangerous (SF bug #1456209). +Note that no refcounts are changed by this routine; if needed, the caller +is responsible for incref'ing `key` and `value`. +*/ +static void +insertdict_clean(register dictobject *mp, PyObject *key, long hash, + PyObject *value) +{ + register size_t i; + register size_t perturb; + register size_t mask = (size_t)mp->ma_mask; + dictentry *ep0 = mp->ma_table; + register dictentry *ep; + + i = hash & mask; + ep = &ep0[i]; + for (perturb = hash; ep->me_key != NULL; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + ep = &ep0[i & mask]; + } + assert(ep->me_value == NULL); + mp->ma_fill++; + ep->me_key = key; + ep->me_hash = (Py_ssize_t)hash; + ep->me_value = value; + mp->ma_used++; +} + +/* +Restructure the table by allocating a new table and reinserting all +items again. When entries have been deleted, the new table may +actually be smaller than the old one. +*/ +static int +dictresize(dictobject *mp, Py_ssize_t minused) +{ + Py_ssize_t newsize; + dictentry *oldtable, *newtable, *ep; + Py_ssize_t i; + int is_oldtable_malloced; + dictentry small_copy[PyDict_MINSIZE]; + + assert(minused >= 0); + + /* Find the smallest table size > minused. */ + for (newsize = PyDict_MINSIZE; + newsize <= minused && newsize > 0; + newsize <<= 1) + ; + if (newsize <= 0) { + PyErr_NoMemory(); + return -1; + } + + /* Get space for a new table. */ + oldtable = mp->ma_table; + assert(oldtable != NULL); + is_oldtable_malloced = oldtable != mp->ma_smalltable; + + if (newsize == PyDict_MINSIZE) { + /* A large table is shrinking, or we can't get any smaller. */ + newtable = mp->ma_smalltable; + if (newtable == oldtable) { + if (mp->ma_fill == mp->ma_used) { + /* No dummies, so no point doing anything. */ + return 0; + } + /* We're not going to resize it, but rebuild the + table anyway to purge old dummy entries. + Subtle: This is *necessary* if fill==size, + as lookdict needs at least one virgin slot to + terminate failing searches. If fill < size, it's + merely desirable, as dummies slow searches. */ + assert(mp->ma_fill > mp->ma_used); + memcpy(small_copy, oldtable, sizeof(small_copy)); + oldtable = small_copy; + } + } + else { + newtable = PyMem_NEW(dictentry, newsize); + if (newtable == NULL) { + PyErr_NoMemory(); + return -1; + } + } + + /* Make the dict empty, using the new table. */ + assert(newtable != oldtable); + mp->ma_table = newtable; + mp->ma_mask = newsize - 1; + memset(newtable, 0, sizeof(dictentry) * newsize); + mp->ma_used = 0; + i = mp->ma_fill; + mp->ma_fill = 0; + + /* Copy the data over; this is refcount-neutral for active entries; + dummy entries aren't copied over, of course */ + for (ep = oldtable; i > 0; ep++) { + if (ep->me_value != NULL) { /* active entry */ + --i; + insertdict_clean(mp, ep->me_key, (long)ep->me_hash, + ep->me_value); + } + else if (ep->me_key != NULL) { /* dummy entry */ + --i; + assert(ep->me_key == dummy); + Py_DECREF(ep->me_key); + } + /* else key == value == NULL: nothing to do */ + } + + if (is_oldtable_malloced) + PyMem_DEL(oldtable); + return 0; +} + +/* Note that, for historical reasons, PyDict_GetItem() suppresses all errors + * that may occur (originally dicts supported only string keys, and exceptions + * weren't possible). So, while the original intent was that a NULL return + * meant the key wasn't present, in reality it can mean that, or that an error + * (suppressed) occurred while computing the key's hash, or that some error + * (suppressed) occurred when comparing keys in the dict's internal probe + * sequence. A nasty example of the latter is when a Python-coded comparison + * function hits a stack-depth error, which can cause this to return NULL + * even if the key is present. + */ +PyObject * +PyDict_GetItem(PyObject *op, PyObject *key) +{ + long hash; + dictobject *mp = (dictobject *)op; + dictentry *ep; + PyThreadState *tstate; + if (!PyDict_Check(op)) + return NULL; + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) + { + hash = PyObject_Hash(key); + if (hash == -1) { + PyErr_Clear(); + return NULL; + } + } + + /* We can arrive here with a NULL tstate during initialization: + try running "python -Wi" for an example related to string + interning. Let's just hope that no exception occurs then... */ + tstate = _PyThreadState_Current; + if (tstate != NULL && tstate->curexc_type != NULL) { + /* preserve the existing exception */ + PyObject *err_type, *err_value, *err_tb; + PyErr_Fetch(&err_type, &err_value, &err_tb); + ep = (mp->ma_lookup)(mp, key, hash); + /* ignore errors */ + PyErr_Restore(err_type, err_value, err_tb); + if (ep == NULL) + return NULL; + } + else { + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) { + PyErr_Clear(); + return NULL; + } + } + return ep->me_value; +} + +/* CAUTION: PyDict_SetItem() must guarantee that it won't resize the + * dictionary if it's merely replacing the value for an existing key. + * This means that it's safe to loop over a dictionary with PyDict_Next() + * and occasionally replace a value -- but you can't insert new keys or + * remove them. + */ +int +PyDict_SetItem(register PyObject *op, PyObject *key, PyObject *value) +{ + register dictobject *mp; + register long hash; + register Py_ssize_t n_used; + + if (!PyDict_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + assert(key); + assert(value); + mp = (dictobject *)op; + if (PyString_CheckExact(key)) { + hash = ((PyStringObject *)key)->ob_shash; + if (hash == -1) + hash = PyObject_Hash(key); + } + else { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + assert(mp->ma_fill <= mp->ma_mask); /* at least one empty slot */ + n_used = mp->ma_used; + Py_INCREF(value); + Py_INCREF(key); + if (insertdict(mp, key, hash, value) != 0) + return -1; + /* If we added a key, we can safely resize. Otherwise just return! + * If fill >= 2/3 size, adjust size. Normally, this doubles or + * quaduples the size, but it's also possible for the dict to shrink + * (if ma_fill is much larger than ma_used, meaning a lot of dict + * keys have been * deleted). + * + * Quadrupling the size improves average dictionary sparseness + * (reducing collisions) at the cost of some memory and iteration + * speed (which loops over every possible entry). It also halves + * the number of expensive resize operations in a growing dictionary. + * + * Very large dictionaries (over 50K items) use doubling instead. + * This may help applications with severe memory constraints. + */ + if (!(mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2)) + return 0; + return dictresize(mp, (mp->ma_used > 50000 ? 2 : 4) * mp->ma_used); +} + +int +PyDict_DelItem(PyObject *op, PyObject *key) +{ + register dictobject *mp; + register long hash; + register dictentry *ep; + PyObject *old_value, *old_key; + + if (!PyDict_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + assert(key); + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + mp = (dictobject *)op; + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) + return -1; + if (ep->me_value == NULL) { + set_key_error(key); + return -1; + } + old_key = ep->me_key; + Py_INCREF(dummy); + ep->me_key = dummy; + old_value = ep->me_value; + ep->me_value = NULL; + mp->ma_used--; + Py_DECREF(old_value); + Py_DECREF(old_key); + return 0; +} + +void +PyDict_Clear(PyObject *op) +{ + dictobject *mp; + dictentry *ep, *table; + int table_is_malloced; + Py_ssize_t fill; + dictentry small_copy[PyDict_MINSIZE]; +#ifdef Py_DEBUG + Py_ssize_t i, n; +#endif + + if (!PyDict_Check(op)) + return; + mp = (dictobject *)op; +#ifdef Py_DEBUG + n = mp->ma_mask + 1; + i = 0; +#endif + + table = mp->ma_table; + assert(table != NULL); + table_is_malloced = table != mp->ma_smalltable; + + /* This is delicate. During the process of clearing the dict, + * decrefs can cause the dict to mutate. To avoid fatal confusion + * (voice of experience), we have to make the dict empty before + * clearing the slots, and never refer to anything via mp->xxx while + * clearing. + */ + fill = mp->ma_fill; + if (table_is_malloced) + EMPTY_TO_MINSIZE(mp); + + else if (fill > 0) { + /* It's a small table with something that needs to be cleared. + * Afraid the only safe way is to copy the dict entries into + * another small table first. + */ + memcpy(small_copy, table, sizeof(small_copy)); + table = small_copy; + EMPTY_TO_MINSIZE(mp); + } + /* else it's a small table that's already empty */ + + /* Now we can finally clear things. If C had refcounts, we could + * assert that the refcount on table is 1 now, i.e. that this function + * has unique access to it, so decref side-effects can't alter it. + */ + for (ep = table; fill > 0; ++ep) { +#ifdef Py_DEBUG + assert(i < n); + ++i; +#endif + if (ep->me_key) { + --fill; + Py_DECREF(ep->me_key); + Py_XDECREF(ep->me_value); + } +#ifdef Py_DEBUG + else + assert(ep->me_value == NULL); +#endif + } + + if (table_is_malloced) + PyMem_DEL(table); +} + +/* + * Iterate over a dict. Use like so: + * + * Py_ssize_t i; + * PyObject *key, *value; + * i = 0; # important! i should not otherwise be changed by you + * while (PyDict_Next(yourdict, &i, &key, &value)) { + * Refer to borrowed references in key and value. + * } + * + * CAUTION: In general, it isn't safe to use PyDict_Next in a loop that + * mutates the dict. One exception: it is safe if the loop merely changes + * the values associated with the keys (but doesn't insert new keys or + * delete keys), via PyDict_SetItem(). + */ +int +PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue) +{ + register Py_ssize_t i; + register Py_ssize_t mask; + register dictentry *ep; + + if (!PyDict_Check(op)) + return 0; + i = *ppos; + if (i < 0) + return 0; + ep = ((dictobject *)op)->ma_table; + mask = ((dictobject *)op)->ma_mask; + while (i <= mask && ep[i].me_value == NULL) + i++; + *ppos = i+1; + if (i > mask) + return 0; + if (pkey) + *pkey = ep[i].me_key; + if (pvalue) + *pvalue = ep[i].me_value; + return 1; +} + +/* Internal version of PyDict_Next that returns a hash value in addition to the key and value.*/ +int +_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue, long *phash) +{ + register Py_ssize_t i; + register Py_ssize_t mask; + register dictentry *ep; + + if (!PyDict_Check(op)) + return 0; + i = *ppos; + if (i < 0) + return 0; + ep = ((dictobject *)op)->ma_table; + mask = ((dictobject *)op)->ma_mask; + while (i <= mask && ep[i].me_value == NULL) + i++; + *ppos = i+1; + if (i > mask) + return 0; + *phash = (long)(ep[i].me_hash); + if (pkey) + *pkey = ep[i].me_key; + if (pvalue) + *pvalue = ep[i].me_value; + return 1; +} + +/* Methods */ + +static void +dict_dealloc(register dictobject *mp) +{ + register dictentry *ep; + Py_ssize_t fill = mp->ma_fill; + PyObject_GC_UnTrack(mp); + Py_TRASHCAN_SAFE_BEGIN(mp) + for (ep = mp->ma_table; fill > 0; ep++) { + if (ep->me_key) { + --fill; + Py_DECREF(ep->me_key); + Py_XDECREF(ep->me_value); + } + } + if (mp->ma_table != mp->ma_smalltable) + PyMem_DEL(mp->ma_table); + if (num_free_dicts < MAXFREEDICTS && mp->ob_type == &PyDict_Type) + free_dicts[num_free_dicts++] = mp; + else + mp->ob_type->tp_free((PyObject *)mp); + Py_TRASHCAN_SAFE_END(mp) +} + +static int +dict_print(register dictobject *mp, register FILE *fp, register int flags) +{ + register Py_ssize_t i; + register Py_ssize_t any; + int status; + + status = Py_ReprEnter((PyObject*)mp); + if (status != 0) { + if (status < 0) + return status; + fprintf(fp, "{...}"); + return 0; + } + + fprintf(fp, "{"); + any = 0; + for (i = 0; i <= mp->ma_mask; i++) { + dictentry *ep = mp->ma_table + i; + PyObject *pvalue = ep->me_value; + if (pvalue != NULL) { + /* Prevent PyObject_Repr from deleting value during + key format */ + Py_INCREF(pvalue); + if (any++ > 0) + fprintf(fp, ", "); + if (PyObject_Print((PyObject *)ep->me_key, fp, 0)!=0) { + Py_DECREF(pvalue); + Py_ReprLeave((PyObject*)mp); + return -1; + } + fprintf(fp, ": "); + if (PyObject_Print(pvalue, fp, 0) != 0) { + Py_DECREF(pvalue); + Py_ReprLeave((PyObject*)mp); + return -1; + } + Py_DECREF(pvalue); + } + } + fprintf(fp, "}"); + Py_ReprLeave((PyObject*)mp); + return 0; +} + +static PyObject * +dict_repr(dictobject *mp) +{ + Py_ssize_t i; + PyObject *s, *temp, *colon = NULL; + PyObject *pieces = NULL, *result = NULL; + PyObject *key, *value; + + i = Py_ReprEnter((PyObject *)mp); + if (i != 0) { + return i > 0 ? PyString_FromString("{...}") : NULL; + } + + if (mp->ma_used == 0) { + result = PyString_FromString("{}"); + goto Done; + } + + pieces = PyList_New(0); + if (pieces == NULL) + goto Done; + + colon = PyString_FromString(": "); + if (colon == NULL) + goto Done; + + /* Do repr() on each key+value pair, and insert ": " between them. + Note that repr may mutate the dict. */ + i = 0; + while (PyDict_Next((PyObject *)mp, &i, &key, &value)) { + int status; + /* Prevent repr from deleting value during key format. */ + Py_INCREF(value); + s = PyObject_Repr(key); + PyString_Concat(&s, colon); + PyString_ConcatAndDel(&s, PyObject_Repr(value)); + Py_DECREF(value); + if (s == NULL) + goto Done; + status = PyList_Append(pieces, s); + Py_DECREF(s); /* append created a new ref */ + if (status < 0) + goto Done; + } + + /* Add "{}" decorations to the first and last items. */ + assert(PyList_GET_SIZE(pieces) > 0); + s = PyString_FromString("{"); + if (s == NULL) + goto Done; + temp = PyList_GET_ITEM(pieces, 0); + PyString_ConcatAndDel(&s, temp); + PyList_SET_ITEM(pieces, 0, s); + if (s == NULL) + goto Done; + + s = PyString_FromString("}"); + if (s == NULL) + goto Done; + temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); + PyString_ConcatAndDel(&temp, s); + PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); + if (temp == NULL) + goto Done; + + /* Paste them all together with ", " between. */ + s = PyString_FromString(", "); + if (s == NULL) + goto Done; + result = _PyString_Join(s, pieces); + Py_DECREF(s); + +Done: + Py_XDECREF(pieces); + Py_XDECREF(colon); + Py_ReprLeave((PyObject *)mp); + return result; +} + +static Py_ssize_t +dict_length(dictobject *mp) +{ + return mp->ma_used; +} + +static PyObject * +dict_subscript(dictobject *mp, register PyObject *key) +{ + PyObject *v; + long hash; + dictentry *ep; + assert(mp->ma_table != NULL); + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return NULL; + } + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) + return NULL; + v = ep->me_value; + if (v == NULL) { + if (!PyDict_CheckExact(mp)) { + /* Look up __missing__ method if we're a subclass. */ + PyObject *missing; + static PyObject *missing_str = NULL; + if (missing_str == NULL) + missing_str = + PyString_InternFromString("__missing__"); + missing = _PyType_Lookup(mp->ob_type, missing_str); + if (missing != NULL) + return PyObject_CallFunctionObjArgs(missing, + (PyObject *)mp, key, NULL); + } + set_key_error(key); + return NULL; + } + else + Py_INCREF(v); + return v; +} + +static int +dict_ass_sub(dictobject *mp, PyObject *v, PyObject *w) +{ + if (w == NULL) + return PyDict_DelItem((PyObject *)mp, v); + else + return PyDict_SetItem((PyObject *)mp, v, w); +} + +static PyMappingMethods dict_as_mapping = { + (lenfunc)dict_length, /*mp_length*/ + (binaryfunc)dict_subscript, /*mp_subscript*/ + (objobjargproc)dict_ass_sub, /*mp_ass_subscript*/ +}; + +static PyObject * +dict_keys(register dictobject *mp) +{ + register PyObject *v; + register Py_ssize_t i, j; + dictentry *ep; + Py_ssize_t mask, n; + + again: + n = mp->ma_used; + v = PyList_New(n); + if (v == NULL) + return NULL; + if (n != mp->ma_used) { + /* Durnit. The allocations caused the dict to resize. + * Just start over, this shouldn't normally happen. + */ + Py_DECREF(v); + goto again; + } + ep = mp->ma_table; + mask = mp->ma_mask; + for (i = 0, j = 0; i <= mask; i++) { + if (ep[i].me_value != NULL) { + PyObject *key = ep[i].me_key; + Py_INCREF(key); + PyList_SET_ITEM(v, j, key); + j++; + } + } + assert(j == n); + return v; +} + +static PyObject * +dict_values(register dictobject *mp) +{ + register PyObject *v; + register Py_ssize_t i, j; + dictentry *ep; + Py_ssize_t mask, n; + + again: + n = mp->ma_used; + v = PyList_New(n); + if (v == NULL) + return NULL; + if (n != mp->ma_used) { + /* Durnit. The allocations caused the dict to resize. + * Just start over, this shouldn't normally happen. + */ + Py_DECREF(v); + goto again; + } + ep = mp->ma_table; + mask = mp->ma_mask; + for (i = 0, j = 0; i <= mask; i++) { + if (ep[i].me_value != NULL) { + PyObject *value = ep[i].me_value; + Py_INCREF(value); + PyList_SET_ITEM(v, j, value); + j++; + } + } + assert(j == n); + return v; +} + +static PyObject * +dict_items(register dictobject *mp) +{ + register PyObject *v; + register Py_ssize_t i, j, n; + Py_ssize_t mask; + PyObject *item, *key, *value; + dictentry *ep; + + /* Preallocate the list of tuples, to avoid allocations during + * the loop over the items, which could trigger GC, which + * could resize the dict. :-( + */ + again: + n = mp->ma_used; + v = PyList_New(n); + if (v == NULL) + return NULL; + for (i = 0; i < n; i++) { + item = PyTuple_New(2); + if (item == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SET_ITEM(v, i, item); + } + if (n != mp->ma_used) { + /* Durnit. The allocations caused the dict to resize. + * Just start over, this shouldn't normally happen. + */ + Py_DECREF(v); + goto again; + } + /* Nothing we do below makes any function calls. */ + ep = mp->ma_table; + mask = mp->ma_mask; + for (i = 0, j = 0; i <= mask; i++) { + if ((value=ep[i].me_value) != NULL) { + key = ep[i].me_key; + item = PyList_GET_ITEM(v, j); + Py_INCREF(key); + PyTuple_SET_ITEM(item, 0, key); + Py_INCREF(value); + PyTuple_SET_ITEM(item, 1, value); + j++; + } + } + assert(j == n); + return v; +} + +static PyObject * +dict_fromkeys(PyObject *cls, PyObject *args) +{ + PyObject *seq; + PyObject *value = Py_None; + PyObject *it; /* iter(seq) */ + PyObject *key; + PyObject *d; + int status; + + if (!PyArg_UnpackTuple(args, "fromkeys", 1, 2, &seq, &value)) + return NULL; + + d = PyObject_CallObject(cls, NULL); + if (d == NULL) + return NULL; + + if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { + dictobject *mp = (dictobject *)d; + Py_ssize_t pos = 0; + PyObject *key; + long hash; + + if (dictresize(mp, PySet_GET_SIZE(seq))) + return NULL; + + while (_PySet_NextEntry(seq, &pos, &key, &hash)) { + Py_INCREF(key); + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) + return NULL; + } + return d; + } + + it = PyObject_GetIter(seq); + if (it == NULL){ + Py_DECREF(d); + return NULL; + } + + for (;;) { + key = PyIter_Next(it); + if (key == NULL) { + if (PyErr_Occurred()) + goto Fail; + break; + } + status = PyObject_SetItem(d, key, value); + Py_DECREF(key); + if (status < 0) + goto Fail; + } + + Py_DECREF(it); + return d; + +Fail: + Py_DECREF(it); + Py_DECREF(d); + return NULL; +} + +static int +dict_update_common(PyObject *self, PyObject *args, PyObject *kwds, char *methname) +{ + PyObject *arg = NULL; + int result = 0; + + if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) + result = -1; + + else if (arg != NULL) { + if (PyObject_HasAttrString(arg, "keys")) + result = PyDict_Merge(self, arg, 1); + else + result = PyDict_MergeFromSeq2(self, arg, 1); + } + if (result == 0 && kwds != NULL) + result = PyDict_Merge(self, kwds, 1); + return result; +} + +static PyObject * +dict_update(PyObject *self, PyObject *args, PyObject *kwds) +{ + if (dict_update_common(self, args, kwds, "update") != -1) + Py_RETURN_NONE; + return NULL; +} + +/* Update unconditionally replaces existing items. + Merge has a 3rd argument 'override'; if set, it acts like Update, + otherwise it leaves existing items unchanged. + + PyDict_{Update,Merge} update/merge from a mapping object. + + PyDict_MergeFromSeq2 updates/merges from any iterable object + producing iterable objects of length 2. +*/ + +int +PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override) +{ + PyObject *it; /* iter(seq2) */ + Py_ssize_t i; /* index into seq2 of current element */ + PyObject *item; /* seq2[i] */ + PyObject *fast; /* item as a 2-tuple or 2-list */ + + assert(d != NULL); + assert(PyDict_Check(d)); + assert(seq2 != NULL); + + it = PyObject_GetIter(seq2); + if (it == NULL) + return -1; + + for (i = 0; ; ++i) { + PyObject *key, *value; + Py_ssize_t n; + + fast = NULL; + item = PyIter_Next(it); + if (item == NULL) { + if (PyErr_Occurred()) + goto Fail; + break; + } + + /* Convert item to sequence, and verify length 2. */ + fast = PySequence_Fast(item, ""); + if (fast == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "cannot convert dictionary update " + "sequence element #%zd to a sequence", + i); + goto Fail; + } + n = PySequence_Fast_GET_SIZE(fast); + if (n != 2) { + PyErr_Format(PyExc_ValueError, + "dictionary update sequence element #%zd " + "has length %zd; 2 is required", + i, n); + goto Fail; + } + + /* Update/merge with this (key, value) pair. */ + key = PySequence_Fast_GET_ITEM(fast, 0); + value = PySequence_Fast_GET_ITEM(fast, 1); + if (override || PyDict_GetItem(d, key) == NULL) { + int status = PyDict_SetItem(d, key, value); + if (status < 0) + goto Fail; + } + Py_DECREF(fast); + Py_DECREF(item); + } + + i = 0; + goto Return; +Fail: + Py_XDECREF(item); + Py_XDECREF(fast); + i = -1; +Return: + Py_DECREF(it); + return Py_SAFE_DOWNCAST(i, Py_ssize_t, int); +} + +int +PyDict_Update(PyObject *a, PyObject *b) +{ + return PyDict_Merge(a, b, 1); +} + +int +PyDict_Merge(PyObject *a, PyObject *b, int override) +{ + register PyDictObject *mp, *other; + register Py_ssize_t i; + dictentry *entry; + + /* We accept for the argument either a concrete dictionary object, + * or an abstract "mapping" object. For the former, we can do + * things quite efficiently. For the latter, we only require that + * PyMapping_Keys() and PyObject_GetItem() be supported. + */ + if (a == NULL || !PyDict_Check(a) || b == NULL) { + PyErr_BadInternalCall(); + return -1; + } + mp = (dictobject*)a; + if (PyDict_Check(b)) { + other = (dictobject*)b; + if (other == mp || other->ma_used == 0) + /* a.update(a) or a.update({}); nothing to do */ + return 0; + if (mp->ma_used == 0) + /* Since the target dict is empty, PyDict_GetItem() + * always returns NULL. Setting override to 1 + * skips the unnecessary test. + */ + override = 1; + /* Do one big resize at the start, rather than + * incrementally resizing as we insert new items. Expect + * that there will be no (or few) overlapping keys. + */ + if ((mp->ma_fill + other->ma_used)*3 >= (mp->ma_mask+1)*2) { + if (dictresize(mp, (mp->ma_used + other->ma_used)*2) != 0) + return -1; + } + for (i = 0; i <= other->ma_mask; i++) { + entry = &other->ma_table[i]; + if (entry->me_value != NULL && + (override || + PyDict_GetItem(a, entry->me_key) == NULL)) { + Py_INCREF(entry->me_key); + Py_INCREF(entry->me_value); + if (insertdict(mp, entry->me_key, + (long)entry->me_hash, + entry->me_value) != 0) + return -1; + } + } + } + else { + /* Do it the generic, slower way */ + PyObject *keys = PyMapping_Keys(b); + PyObject *iter; + PyObject *key, *value; + int status; + + if (keys == NULL) + /* Docstring says this is equivalent to E.keys() so + * if E doesn't have a .keys() method we want + * AttributeError to percolate up. Might as well + * do the same for any other error. + */ + return -1; + + iter = PyObject_GetIter(keys); + Py_DECREF(keys); + if (iter == NULL) + return -1; + + for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) { + if (!override && PyDict_GetItem(a, key) != NULL) { + Py_DECREF(key); + continue; + } + value = PyObject_GetItem(b, key); + if (value == NULL) { + Py_DECREF(iter); + Py_DECREF(key); + return -1; + } + status = PyDict_SetItem(a, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (status < 0) { + Py_DECREF(iter); + return -1; + } + } + Py_DECREF(iter); + if (PyErr_Occurred()) + /* Iterator completed, via error */ + return -1; + } + return 0; +} + +static PyObject * +dict_copy(register dictobject *mp) +{ + return PyDict_Copy((PyObject*)mp); +} + +PyObject * +PyDict_Copy(PyObject *o) +{ + PyObject *copy; + + if (o == NULL || !PyDict_Check(o)) { + PyErr_BadInternalCall(); + return NULL; + } + copy = PyDict_New(); + if (copy == NULL) + return NULL; + if (PyDict_Merge(copy, o, 1) == 0) + return copy; + Py_DECREF(copy); + return NULL; +} + +Py_ssize_t +PyDict_Size(PyObject *mp) +{ + if (mp == NULL || !PyDict_Check(mp)) { + PyErr_BadInternalCall(); + return -1; + } + return ((dictobject *)mp)->ma_used; +} + +PyObject * +PyDict_Keys(PyObject *mp) +{ + if (mp == NULL || !PyDict_Check(mp)) { + PyErr_BadInternalCall(); + return NULL; + } + return dict_keys((dictobject *)mp); +} + +PyObject * +PyDict_Values(PyObject *mp) +{ + if (mp == NULL || !PyDict_Check(mp)) { + PyErr_BadInternalCall(); + return NULL; + } + return dict_values((dictobject *)mp); +} + +PyObject * +PyDict_Items(PyObject *mp) +{ + if (mp == NULL || !PyDict_Check(mp)) { + PyErr_BadInternalCall(); + return NULL; + } + return dict_items((dictobject *)mp); +} + +/* Subroutine which returns the smallest key in a for which b's value + is different or absent. The value is returned too, through the + pval argument. Both are NULL if no key in a is found for which b's status + differs. The refcounts on (and only on) non-NULL *pval and function return + values must be decremented by the caller (characterize() increments them + to ensure that mutating comparison and PyDict_GetItem calls can't delete + them before the caller is done looking at them). */ + +static PyObject * +characterize(dictobject *a, dictobject *b, PyObject **pval) +{ + PyObject *akey = NULL; /* smallest key in a s.t. a[akey] != b[akey] */ + PyObject *aval = NULL; /* a[akey] */ + Py_ssize_t i; + int cmp; + + for (i = 0; i <= a->ma_mask; i++) { + PyObject *thiskey, *thisaval, *thisbval; + if (a->ma_table[i].me_value == NULL) + continue; + thiskey = a->ma_table[i].me_key; + Py_INCREF(thiskey); /* keep alive across compares */ + if (akey != NULL) { + cmp = PyObject_RichCompareBool(akey, thiskey, Py_LT); + if (cmp < 0) { + Py_DECREF(thiskey); + goto Fail; + } + if (cmp > 0 || + i > a->ma_mask || + a->ma_table[i].me_value == NULL) + { + /* Not the *smallest* a key; or maybe it is + * but the compare shrunk the dict so we can't + * find its associated value anymore; or + * maybe it is but the compare deleted the + * a[thiskey] entry. + */ + Py_DECREF(thiskey); + continue; + } + } + + /* Compare a[thiskey] to b[thiskey]; cmp <- true iff equal. */ + thisaval = a->ma_table[i].me_value; + assert(thisaval); + Py_INCREF(thisaval); /* keep alive */ + thisbval = PyDict_GetItem((PyObject *)b, thiskey); + if (thisbval == NULL) + cmp = 0; + else { + /* both dicts have thiskey: same values? */ + cmp = PyObject_RichCompareBool( + thisaval, thisbval, Py_EQ); + if (cmp < 0) { + Py_DECREF(thiskey); + Py_DECREF(thisaval); + goto Fail; + } + } + if (cmp == 0) { + /* New winner. */ + Py_XDECREF(akey); + Py_XDECREF(aval); + akey = thiskey; + aval = thisaval; + } + else { + Py_DECREF(thiskey); + Py_DECREF(thisaval); + } + } + *pval = aval; + return akey; + +Fail: + Py_XDECREF(akey); + Py_XDECREF(aval); + *pval = NULL; + return NULL; +} + +static int +dict_compare(dictobject *a, dictobject *b) +{ + PyObject *adiff, *bdiff, *aval, *bval; + int res; + + /* Compare lengths first */ + if (a->ma_used < b->ma_used) + return -1; /* a is shorter */ + else if (a->ma_used > b->ma_used) + return 1; /* b is shorter */ + + /* Same length -- check all keys */ + bdiff = bval = NULL; + adiff = characterize(a, b, &aval); + if (adiff == NULL) { + assert(!aval); + /* Either an error, or a is a subset with the same length so + * must be equal. + */ + res = PyErr_Occurred() ? -1 : 0; + goto Finished; + } + bdiff = characterize(b, a, &bval); + if (bdiff == NULL && PyErr_Occurred()) { + assert(!bval); + res = -1; + goto Finished; + } + res = 0; + if (bdiff) { + /* bdiff == NULL "should be" impossible now, but perhaps + * the last comparison done by the characterize() on a had + * the side effect of making the dicts equal! + */ + res = PyObject_Compare(adiff, bdiff); + } + if (res == 0 && bval != NULL) + res = PyObject_Compare(aval, bval); + +Finished: + Py_XDECREF(adiff); + Py_XDECREF(bdiff); + Py_XDECREF(aval); + Py_XDECREF(bval); + return res; +} + +/* Return 1 if dicts equal, 0 if not, -1 if error. + * Gets out as soon as any difference is detected. + * Uses only Py_EQ comparison. + */ +static int +dict_equal(dictobject *a, dictobject *b) +{ + Py_ssize_t i; + + if (a->ma_used != b->ma_used) + /* can't be equal if # of entries differ */ + return 0; + + /* Same # of entries -- check all of 'em. Exit early on any diff. */ + for (i = 0; i <= a->ma_mask; i++) { + PyObject *aval = a->ma_table[i].me_value; + if (aval != NULL) { + int cmp; + PyObject *bval; + PyObject *key = a->ma_table[i].me_key; + /* temporarily bump aval's refcount to ensure it stays + alive until we're done with it */ + Py_INCREF(aval); + /* ditto for key */ + Py_INCREF(key); + bval = PyDict_GetItem((PyObject *)b, key); + Py_DECREF(key); + if (bval == NULL) { + Py_DECREF(aval); + return 0; + } + cmp = PyObject_RichCompareBool(aval, bval, Py_EQ); + Py_DECREF(aval); + if (cmp <= 0) /* error or not equal */ + return cmp; + } + } + return 1; + } + +static PyObject * +dict_richcompare(PyObject *v, PyObject *w, int op) +{ + int cmp; + PyObject *res; + + if (!PyDict_Check(v) || !PyDict_Check(w)) { + res = Py_NotImplemented; + } + else if (op == Py_EQ || op == Py_NE) { + cmp = dict_equal((dictobject *)v, (dictobject *)w); + if (cmp < 0) + return NULL; + res = (cmp == (op == Py_EQ)) ? Py_True : Py_False; + } + else + res = Py_NotImplemented; + Py_INCREF(res); + return res; + } + +static PyObject * +dict_has_key(register dictobject *mp, PyObject *key) +{ + long hash; + dictentry *ep; + + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return NULL; + } + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) + return NULL; + return PyBool_FromLong(ep->me_value != NULL); +} + +static PyObject * +dict_get(register dictobject *mp, PyObject *args) +{ + PyObject *key; + PyObject *failobj = Py_None; + PyObject *val = NULL; + long hash; + dictentry *ep; + + if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj)) + return NULL; + + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return NULL; + } + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) + return NULL; + val = ep->me_value; + if (val == NULL) + val = failobj; + Py_INCREF(val); + return val; +} + + +static PyObject * +dict_setdefault(register dictobject *mp, PyObject *args) +{ + PyObject *key; + PyObject *failobj = Py_None; + PyObject *val = NULL; + long hash; + dictentry *ep; + + if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &failobj)) + return NULL; + + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return NULL; + } + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) + return NULL; + val = ep->me_value; + if (val == NULL) { + val = failobj; + if (PyDict_SetItem((PyObject*)mp, key, failobj)) + val = NULL; + } + Py_XINCREF(val); + return val; +} + + +static PyObject * +dict_clear(register dictobject *mp) +{ + PyDict_Clear((PyObject *)mp); + Py_RETURN_NONE; +} + +static PyObject * +dict_pop(dictobject *mp, PyObject *args) +{ + long hash; + dictentry *ep; + PyObject *old_value, *old_key; + PyObject *key, *deflt = NULL; + + if(!PyArg_UnpackTuple(args, "pop", 1, 2, &key, &deflt)) + return NULL; + if (mp->ma_used == 0) { + if (deflt) { + Py_INCREF(deflt); + return deflt; + } + PyErr_SetString(PyExc_KeyError, + "pop(): dictionary is empty"); + return NULL; + } + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return NULL; + } + ep = (mp->ma_lookup)(mp, key, hash); + if (ep == NULL) + return NULL; + if (ep->me_value == NULL) { + if (deflt) { + Py_INCREF(deflt); + return deflt; + } + set_key_error(key); + return NULL; + } + old_key = ep->me_key; + Py_INCREF(dummy); + ep->me_key = dummy; + old_value = ep->me_value; + ep->me_value = NULL; + mp->ma_used--; + Py_DECREF(old_key); + return old_value; +} + +static PyObject * +dict_popitem(dictobject *mp) +{ + Py_ssize_t i = 0; + dictentry *ep; + PyObject *res; + + /* Allocate the result tuple before checking the size. Believe it + * or not, this allocation could trigger a garbage collection which + * could empty the dict, so if we checked the size first and that + * happened, the result would be an infinite loop (searching for an + * entry that no longer exists). Note that the usual popitem() + * idiom is "while d: k, v = d.popitem()". so needing to throw the + * tuple away if the dict *is* empty isn't a significant + * inefficiency -- possible, but unlikely in practice. + */ + res = PyTuple_New(2); + if (res == NULL) + return NULL; + if (mp->ma_used == 0) { + Py_DECREF(res); + PyErr_SetString(PyExc_KeyError, + "popitem(): dictionary is empty"); + return NULL; + } + /* Set ep to "the first" dict entry with a value. We abuse the hash + * field of slot 0 to hold a search finger: + * If slot 0 has a value, use slot 0. + * Else slot 0 is being used to hold a search finger, + * and we use its hash value as the first index to look. + */ + ep = &mp->ma_table[0]; + if (ep->me_value == NULL) { + i = ep->me_hash; + /* The hash field may be a real hash value, or it may be a + * legit search finger, or it may be a once-legit search + * finger that's out of bounds now because it wrapped around + * or the table shrunk -- simply make sure it's in bounds now. + */ + if (i > mp->ma_mask || i < 1) + i = 1; /* skip slot 0 */ + while ((ep = &mp->ma_table[i])->me_value == NULL) { + i++; + if (i > mp->ma_mask) + i = 1; + } + } + PyTuple_SET_ITEM(res, 0, ep->me_key); + PyTuple_SET_ITEM(res, 1, ep->me_value); + Py_INCREF(dummy); + ep->me_key = dummy; + ep->me_value = NULL; + mp->ma_used--; + assert(mp->ma_table[0].me_value == NULL); + mp->ma_table[0].me_hash = i + 1; /* next place to start */ + return res; +} + +static int +dict_traverse(PyObject *op, visitproc visit, void *arg) +{ + Py_ssize_t i = 0; + PyObject *pk; + PyObject *pv; + + while (PyDict_Next(op, &i, &pk, &pv)) { + Py_VISIT(pk); + Py_VISIT(pv); + } + return 0; +} + +static int +dict_tp_clear(PyObject *op) +{ + PyDict_Clear(op); + return 0; +} + + +extern PyTypeObject PyDictIterKey_Type; /* Forward */ +extern PyTypeObject PyDictIterValue_Type; /* Forward */ +extern PyTypeObject PyDictIterItem_Type; /* Forward */ +static PyObject *dictiter_new(dictobject *, PyTypeObject *); + +static PyObject * +dict_iterkeys(dictobject *dict) +{ + return dictiter_new(dict, &PyDictIterKey_Type); +} + +static PyObject * +dict_itervalues(dictobject *dict) +{ + return dictiter_new(dict, &PyDictIterValue_Type); +} + +static PyObject * +dict_iteritems(dictobject *dict) +{ + return dictiter_new(dict, &PyDictIterItem_Type); +} + + +PyDoc_STRVAR(has_key__doc__, +"D.has_key(k) -> True if D has a key k, else False"); + +PyDoc_STRVAR(contains__doc__, +"D.__contains__(k) -> True if D has a key k, else False"); + +PyDoc_STRVAR(getitem__doc__, "x.__getitem__(y) <==> x[y]"); + +PyDoc_STRVAR(get__doc__, +"D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."); + +PyDoc_STRVAR(setdefault_doc__, +"D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"); + +PyDoc_STRVAR(pop__doc__, +"D.pop(k[,d]) -> v, remove specified key and return the corresponding value\n\ +If key is not found, d is returned if given, otherwise KeyError is raised"); + +PyDoc_STRVAR(popitem__doc__, +"D.popitem() -> (k, v), remove and return some (key, value) pair as a\n\ +2-tuple; but raise KeyError if D is empty"); + +PyDoc_STRVAR(keys__doc__, +"D.keys() -> list of D's keys"); + +PyDoc_STRVAR(items__doc__, +"D.items() -> list of D's (key, value) pairs, as 2-tuples"); + +PyDoc_STRVAR(values__doc__, +"D.values() -> list of D's values"); + +PyDoc_STRVAR(update__doc__, +"D.update(E, **F) -> None. Update D from E and F: for k in E: D[k] = E[k]\n\ +(if E has keys else: for (k, v) in E: D[k] = v) then: for k in F: D[k] = F[k]"); + +PyDoc_STRVAR(fromkeys__doc__, +"dict.fromkeys(S[,v]) -> New dict with keys from S and values equal to v.\n\ +v defaults to None."); + +PyDoc_STRVAR(clear__doc__, +"D.clear() -> None. Remove all items from D."); + +PyDoc_STRVAR(copy__doc__, +"D.copy() -> a shallow copy of D"); + +PyDoc_STRVAR(iterkeys__doc__, +"D.iterkeys() -> an iterator over the keys of D"); + +PyDoc_STRVAR(itervalues__doc__, +"D.itervalues() -> an iterator over the values of D"); + +PyDoc_STRVAR(iteritems__doc__, +"D.iteritems() -> an iterator over the (key, value) items of D"); + +static PyMethodDef mapp_methods[] = { + {"__contains__",(PyCFunction)dict_has_key, METH_O | METH_COEXIST, + contains__doc__}, + {"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST, + getitem__doc__}, + {"has_key", (PyCFunction)dict_has_key, METH_O, + has_key__doc__}, + {"get", (PyCFunction)dict_get, METH_VARARGS, + get__doc__}, + {"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS, + setdefault_doc__}, + {"pop", (PyCFunction)dict_pop, METH_VARARGS, + pop__doc__}, + {"popitem", (PyCFunction)dict_popitem, METH_NOARGS, + popitem__doc__}, + {"keys", (PyCFunction)dict_keys, METH_NOARGS, + keys__doc__}, + {"items", (PyCFunction)dict_items, METH_NOARGS, + items__doc__}, + {"values", (PyCFunction)dict_values, METH_NOARGS, + values__doc__}, + {"update", (PyCFunction)dict_update, METH_VARARGS | METH_KEYWORDS, + update__doc__}, + {"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS | METH_CLASS, + fromkeys__doc__}, + {"clear", (PyCFunction)dict_clear, METH_NOARGS, + clear__doc__}, + {"copy", (PyCFunction)dict_copy, METH_NOARGS, + copy__doc__}, + {"iterkeys", (PyCFunction)dict_iterkeys, METH_NOARGS, + iterkeys__doc__}, + {"itervalues", (PyCFunction)dict_itervalues, METH_NOARGS, + itervalues__doc__}, + {"iteritems", (PyCFunction)dict_iteritems, METH_NOARGS, + iteritems__doc__}, + {NULL, NULL} /* sentinel */ +}; + +/* Return 1 if `key` is in dict `op`, 0 if not, and -1 on error. */ +int +PyDict_Contains(PyObject *op, PyObject *key) +{ + long hash; + dictobject *mp = (dictobject *)op; + dictentry *ep; + + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + ep = (mp->ma_lookup)(mp, key, hash); + return ep == NULL ? -1 : (ep->me_value != NULL); +} + +/* Internal version of PyDict_Contains used when the hash value is already known */ +int +_PyDict_Contains(PyObject *op, PyObject *key, long hash) +{ + dictobject *mp = (dictobject *)op; + dictentry *ep; + + ep = (mp->ma_lookup)(mp, key, hash); + return ep == NULL ? -1 : (ep->me_value != NULL); +} + +/* Hack to implement "key in dict" */ +static PySequenceMethods dict_as_sequence = { + 0, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + PyDict_Contains, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0, /* sq_inplace_repeat */ +}; + +static PyObject * +dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *self; + + assert(type != NULL && type->tp_alloc != NULL); + self = type->tp_alloc(type, 0); + if (self != NULL) { + PyDictObject *d = (PyDictObject *)self; + /* It's guaranteed that tp->alloc zeroed out the struct. */ + assert(d->ma_table == NULL && d->ma_fill == 0 && d->ma_used == 0); + INIT_NONZERO_DICT_SLOTS(d); + d->ma_lookup = lookdict_string; +#ifdef SHOW_CONVERSION_COUNTS + ++created; +#endif + } + return self; +} + +static int +dict_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + return dict_update_common(self, args, kwds, "dict"); +} + +static long +dict_nohash(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "dict objects are unhashable"); + return -1; +} + +static PyObject * +dict_iter(dictobject *dict) +{ + return dictiter_new(dict, &PyDictIterKey_Type); +} + +PyDoc_STRVAR(dictionary_doc, +"dict() -> new empty dictionary.\n" +"dict(mapping) -> new dictionary initialized from a mapping object's\n" +" (key, value) pairs.\n" +"dict(seq) -> new dictionary initialized as if via:\n" +" d = {}\n" +" for k, v in seq:\n" +" d[k] = v\n" +"dict(**kwargs) -> new dictionary initialized with the name=value pairs\n" +" in the keyword argument list. For example: dict(one=1, two=2)"); + +PyTypeObject PyDict_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "dict", + sizeof(dictobject), + 0, + (destructor)dict_dealloc, /* tp_dealloc */ + (printfunc)dict_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)dict_compare, /* tp_compare */ + (reprfunc)dict_repr, /* tp_repr */ + 0, /* tp_as_number */ + &dict_as_sequence, /* tp_as_sequence */ + &dict_as_mapping, /* tp_as_mapping */ + dict_nohash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + dictionary_doc, /* tp_doc */ + dict_traverse, /* tp_traverse */ + dict_tp_clear, /* tp_clear */ + dict_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)dict_iter, /* tp_iter */ + 0, /* tp_iternext */ + mapp_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + dict_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + dict_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +/* For backward compatibility with old dictionary interface */ + +PyObject * +PyDict_GetItemString(PyObject *v, const char *key) +{ + PyObject *kv, *rv; + kv = PyString_FromString(key); + if (kv == NULL) + return NULL; + rv = PyDict_GetItem(v, kv); + Py_DECREF(kv); + return rv; +} + +int +PyDict_SetItemString(PyObject *v, const char *key, PyObject *item) +{ + PyObject *kv; + int err; + kv = PyString_FromString(key); + if (kv == NULL) + return -1; + PyString_InternInPlace(&kv); /* XXX Should we really? */ + err = PyDict_SetItem(v, kv, item); + Py_DECREF(kv); + return err; +} + +int +PyDict_DelItemString(PyObject *v, const char *key) +{ + PyObject *kv; + int err; + kv = PyString_FromString(key); + if (kv == NULL) + return -1; + err = PyDict_DelItem(v, kv); + Py_DECREF(kv); + return err; +} + +/* Dictionary iterator types */ + +typedef struct { + PyObject_HEAD + dictobject *di_dict; /* Set to NULL when iterator is exhausted */ + Py_ssize_t di_used; + Py_ssize_t di_pos; + PyObject* di_result; /* reusable result tuple for iteritems */ + Py_ssize_t len; +} dictiterobject; + +static PyObject * +dictiter_new(dictobject *dict, PyTypeObject *itertype) +{ + dictiterobject *di; + di = PyObject_New(dictiterobject, itertype); + if (di == NULL) + return NULL; + Py_INCREF(dict); + di->di_dict = dict; + di->di_used = dict->ma_used; + di->di_pos = 0; + di->len = dict->ma_used; + if (itertype == &PyDictIterItem_Type) { + di->di_result = PyTuple_Pack(2, Py_None, Py_None); + if (di->di_result == NULL) { + Py_DECREF(di); + return NULL; + } + } + else + di->di_result = NULL; + return (PyObject *)di; +} + +static void +dictiter_dealloc(dictiterobject *di) +{ + Py_XDECREF(di->di_dict); + Py_XDECREF(di->di_result); + PyObject_Del(di); +} + +static PyObject * +dictiter_len(dictiterobject *di) +{ + Py_ssize_t len = 0; + if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used) + len = di->len; + return PyInt_FromSize_t(len); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef dictiter_methods[] = { + {"__length_hint__", (PyCFunction)dictiter_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject *dictiter_iternextkey(dictiterobject *di) +{ + PyObject *key; + register Py_ssize_t i, mask; + register dictentry *ep; + dictobject *d = di->di_dict; + + if (d == NULL) + return NULL; + assert (PyDict_Check(d)); + + if (di->di_used != d->ma_used) { + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during iteration"); + di->di_used = -1; /* Make this state sticky */ + return NULL; + } + + i = di->di_pos; + if (i < 0) + goto fail; + ep = d->ma_table; + mask = d->ma_mask; + while (i <= mask && ep[i].me_value == NULL) + i++; + di->di_pos = i+1; + if (i > mask) + goto fail; + di->len--; + key = ep[i].me_key; + Py_INCREF(key); + return key; + +fail: + Py_DECREF(d); + di->di_dict = NULL; + return NULL; +} + +PyTypeObject PyDictIterKey_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "dictionary-keyiterator", /* tp_name */ + sizeof(dictiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)dictiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)dictiter_iternextkey, /* tp_iternext */ + dictiter_methods, /* tp_methods */ + 0, +}; + +static PyObject *dictiter_iternextvalue(dictiterobject *di) +{ + PyObject *value; + register Py_ssize_t i, mask; + register dictentry *ep; + dictobject *d = di->di_dict; + + if (d == NULL) + return NULL; + assert (PyDict_Check(d)); + + if (di->di_used != d->ma_used) { + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during iteration"); + di->di_used = -1; /* Make this state sticky */ + return NULL; + } + + i = di->di_pos; + mask = d->ma_mask; + if (i < 0 || i > mask) + goto fail; + ep = d->ma_table; + while ((value=ep[i].me_value) == NULL) { + i++; + if (i > mask) + goto fail; + } + di->di_pos = i+1; + di->len--; + Py_INCREF(value); + return value; + +fail: + Py_DECREF(d); + di->di_dict = NULL; + return NULL; +} + +PyTypeObject PyDictIterValue_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "dictionary-valueiterator", /* tp_name */ + sizeof(dictiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)dictiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)dictiter_iternextvalue, /* tp_iternext */ + dictiter_methods, /* tp_methods */ + 0, +}; + +static PyObject *dictiter_iternextitem(dictiterobject *di) +{ + PyObject *key, *value, *result = di->di_result; + register Py_ssize_t i, mask; + register dictentry *ep; + dictobject *d = di->di_dict; + + if (d == NULL) + return NULL; + assert (PyDict_Check(d)); + + if (di->di_used != d->ma_used) { + PyErr_SetString(PyExc_RuntimeError, + "dictionary changed size during iteration"); + di->di_used = -1; /* Make this state sticky */ + return NULL; + } + + i = di->di_pos; + if (i < 0) + goto fail; + ep = d->ma_table; + mask = d->ma_mask; + while (i <= mask && ep[i].me_value == NULL) + i++; + di->di_pos = i+1; + if (i > mask) + goto fail; + + if (result->ob_refcnt == 1) { + Py_INCREF(result); + Py_DECREF(PyTuple_GET_ITEM(result, 0)); + Py_DECREF(PyTuple_GET_ITEM(result, 1)); + } else { + result = PyTuple_New(2); + if (result == NULL) + return NULL; + } + di->len--; + key = ep[i].me_key; + value = ep[i].me_value; + Py_INCREF(key); + Py_INCREF(value); + PyTuple_SET_ITEM(result, 0, key); + PyTuple_SET_ITEM(result, 1, value); + return result; + +fail: + Py_DECREF(d); + di->di_dict = NULL; + return NULL; +} + +PyTypeObject PyDictIterItem_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "dictionary-itemiterator", /* tp_name */ + sizeof(dictiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)dictiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)dictiter_iternextitem, /* tp_iternext */ + dictiter_methods, /* tp_methods */ + 0, +}; diff --git a/sys/src/cmd/python/Objects/enumobject.c b/sys/src/cmd/python/Objects/enumobject.c new file mode 100644 index 000000000..a456c9daf --- /dev/null +++ b/sys/src/cmd/python/Objects/enumobject.c @@ -0,0 +1,298 @@ +/* enumerate object */ + +#include "Python.h" + +typedef struct { + PyObject_HEAD + long en_index; /* current index of enumeration */ + PyObject* en_sit; /* secondary iterator of enumeration */ + PyObject* en_result; /* result tuple */ +} enumobject; + +static PyObject * +enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + enumobject *en; + PyObject *seq = NULL; + static char *kwlist[] = {"sequence", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:enumerate", kwlist, + &seq)) + return NULL; + + en = (enumobject *)type->tp_alloc(type, 0); + if (en == NULL) + return NULL; + en->en_index = 0; + en->en_sit = PyObject_GetIter(seq); + if (en->en_sit == NULL) { + Py_DECREF(en); + return NULL; + } + en->en_result = PyTuple_Pack(2, Py_None, Py_None); + if (en->en_result == NULL) { + Py_DECREF(en); + return NULL; + } + return (PyObject *)en; +} + +static void +enum_dealloc(enumobject *en) +{ + PyObject_GC_UnTrack(en); + Py_XDECREF(en->en_sit); + Py_XDECREF(en->en_result); + en->ob_type->tp_free(en); +} + +static int +enum_traverse(enumobject *en, visitproc visit, void *arg) +{ + Py_VISIT(en->en_sit); + Py_VISIT(en->en_result); + return 0; +} + +static PyObject * +enum_next(enumobject *en) +{ + PyObject *next_index; + PyObject *next_item; + PyObject *result = en->en_result; + PyObject *it = en->en_sit; + + if (en->en_index == LONG_MAX) { + PyErr_SetString(PyExc_OverflowError, + "enumerate() is limited to LONG_MAX items"); + return NULL; + } + + next_item = (*it->ob_type->tp_iternext)(it); + if (next_item == NULL) + return NULL; + + next_index = PyInt_FromLong(en->en_index); + if (next_index == NULL) { + Py_DECREF(next_item); + return NULL; + } + en->en_index++; + + if (result->ob_refcnt == 1) { + Py_INCREF(result); + Py_DECREF(PyTuple_GET_ITEM(result, 0)); + Py_DECREF(PyTuple_GET_ITEM(result, 1)); + } else { + result = PyTuple_New(2); + if (result == NULL) { + Py_DECREF(next_index); + Py_DECREF(next_item); + return NULL; + } + } + PyTuple_SET_ITEM(result, 0, next_index); + PyTuple_SET_ITEM(result, 1, next_item); + return result; +} + +PyDoc_STRVAR(enum_doc, +"enumerate(iterable) -> iterator for index, value of iterable\n" +"\n" +"Return an enumerate object. iterable must be an other object that supports\n" +"iteration. The enumerate object yields pairs containing a count (from\n" +"zero) and a value yielded by the iterable argument. enumerate is useful\n" +"for obtaining an indexed list: (0, seq[0]), (1, seq[1]), (2, seq[2]), ..."); + +PyTypeObject PyEnum_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "enumerate", /* tp_name */ + sizeof(enumobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)enum_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + enum_doc, /* tp_doc */ + (traverseproc)enum_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)enum_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + enum_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +/* Reversed Object ***************************************************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t index; + PyObject* seq; +} reversedobject; + +static PyObject * +reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Py_ssize_t n; + PyObject *seq; + reversedobject *ro; + + if (!PyArg_UnpackTuple(args, "reversed", 1, 1, &seq)) + return NULL; + + if (PyObject_HasAttrString(seq, "__reversed__")) + return PyObject_CallMethod(seq, "__reversed__", NULL); + + if (!PySequence_Check(seq)) { + PyErr_SetString(PyExc_TypeError, + "argument to reversed() must be a sequence"); + return NULL; + } + + n = PySequence_Size(seq); + if (n == -1) + return NULL; + + ro = (reversedobject *)type->tp_alloc(type, 0); + if (ro == NULL) + return NULL; + + ro->index = n-1; + Py_INCREF(seq); + ro->seq = seq; + return (PyObject *)ro; +} + +static void +reversed_dealloc(reversedobject *ro) +{ + PyObject_GC_UnTrack(ro); + Py_XDECREF(ro->seq); + ro->ob_type->tp_free(ro); +} + +static int +reversed_traverse(reversedobject *ro, visitproc visit, void *arg) +{ + Py_VISIT(ro->seq); + return 0; +} + +static PyObject * +reversed_next(reversedobject *ro) +{ + PyObject *item; + Py_ssize_t index = ro->index; + + if (index >= 0) { + item = PySequence_GetItem(ro->seq, index); + if (item != NULL) { + ro->index--; + return item; + } + if (PyErr_ExceptionMatches(PyExc_IndexError) || + PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + } + ro->index = -1; + Py_CLEAR(ro->seq); + return NULL; +} + +PyDoc_STRVAR(reversed_doc, +"reversed(sequence) -> reverse iterator over values of the sequence\n" +"\n" +"Return a reverse iterator"); + +static PyObject * +reversed_len(reversedobject *ro) +{ + Py_ssize_t position, seqsize; + + if (ro->seq == NULL) + return PyInt_FromLong(0); + seqsize = PySequence_Size(ro->seq); + if (seqsize == -1) + return NULL; + position = ro->index + 1; + return PyInt_FromSsize_t((seqsize < position) ? 0 : position); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef reversediter_methods[] = { + {"__length_hint__", (PyCFunction)reversed_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyTypeObject PyReversed_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "reversed", /* tp_name */ + sizeof(reversedobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)reversed_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + reversed_doc, /* tp_doc */ + (traverseproc)reversed_traverse,/* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)reversed_next, /* tp_iternext */ + reversediter_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + reversed_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; diff --git a/sys/src/cmd/python/Objects/exceptions.c b/sys/src/cmd/python/Objects/exceptions.c new file mode 100644 index 000000000..0cd819c5a --- /dev/null +++ b/sys/src/cmd/python/Objects/exceptions.c @@ -0,0 +1,2147 @@ +/* + * New exceptions.c written in Iceland by Richard Jones and Georg Brandl. + * + * Thanks go to Tim Peters and Michael Hudson for debugging. + */ + +#define PY_SSIZE_T_CLEAN +#include <Python.h> +#include "structmember.h" +#include "osdefs.h" + +#define MAKE_IT_NONE(x) (x) = Py_None; Py_INCREF(Py_None); +#define EXC_MODULE_NAME "exceptions." + +/* NOTE: If the exception class hierarchy changes, don't forget to update + * Lib/test/exception_hierarchy.txt + */ + +PyDoc_STRVAR(exceptions_doc, "Python's standard exception class hierarchy.\n\ +\n\ +Exceptions found here are defined both in the exceptions module and the\n\ +built-in namespace. It is recommended that user-defined exceptions\n\ +inherit from Exception. See the documentation for the exception\n\ +inheritance hierarchy.\n\ +"); + +/* + * BaseException + */ +static PyObject * +BaseException_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyBaseExceptionObject *self; + + self = (PyBaseExceptionObject *)type->tp_alloc(type, 0); + /* the dict is created on the fly in PyObject_GenericSetAttr */ + self->message = self->dict = NULL; + + self->args = PyTuple_New(0); + if (!self->args) { + Py_DECREF(self); + return NULL; + } + + self->message = PyString_FromString(""); + if (!self->message) { + Py_DECREF(self); + return NULL; + } + + return (PyObject *)self; +} + +static int +BaseException_init(PyBaseExceptionObject *self, PyObject *args, PyObject *kwds) +{ + if (!_PyArg_NoKeywords(self->ob_type->tp_name, kwds)) + return -1; + + Py_DECREF(self->args); + self->args = args; + Py_INCREF(self->args); + + if (PyTuple_GET_SIZE(self->args) == 1) { + Py_CLEAR(self->message); + self->message = PyTuple_GET_ITEM(self->args, 0); + Py_INCREF(self->message); + } + return 0; +} + +static int +BaseException_clear(PyBaseExceptionObject *self) +{ + Py_CLEAR(self->dict); + Py_CLEAR(self->args); + Py_CLEAR(self->message); + return 0; +} + +static void +BaseException_dealloc(PyBaseExceptionObject *self) +{ + _PyObject_GC_UNTRACK(self); + BaseException_clear(self); + self->ob_type->tp_free((PyObject *)self); +} + +static int +BaseException_traverse(PyBaseExceptionObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->dict); + Py_VISIT(self->args); + Py_VISIT(self->message); + return 0; +} + +static PyObject * +BaseException_str(PyBaseExceptionObject *self) +{ + PyObject *out; + + switch (PyTuple_GET_SIZE(self->args)) { + case 0: + out = PyString_FromString(""); + break; + case 1: + out = PyObject_Str(PyTuple_GET_ITEM(self->args, 0)); + break; + default: + out = PyObject_Str(self->args); + break; + } + + return out; +} + +static PyObject * +BaseException_repr(PyBaseExceptionObject *self) +{ + PyObject *repr_suffix; + PyObject *repr; + char *name; + char *dot; + + repr_suffix = PyObject_Repr(self->args); + if (!repr_suffix) + return NULL; + + name = (char *)self->ob_type->tp_name; + dot = strrchr(name, '.'); + if (dot != NULL) name = dot+1; + + repr = PyString_FromString(name); + if (!repr) { + Py_DECREF(repr_suffix); + return NULL; + } + + PyString_ConcatAndDel(&repr, repr_suffix); + return repr; +} + +/* Pickling support */ +static PyObject * +BaseException_reduce(PyBaseExceptionObject *self) +{ + if (self->args && self->dict) + return PyTuple_Pack(3, self->ob_type, self->args, self->dict); + else + return PyTuple_Pack(2, self->ob_type, self->args); +} + +/* + * Needed for backward compatibility, since exceptions used to store + * all their attributes in the __dict__. Code is taken from cPickle's + * load_build function. + */ +static PyObject * +BaseException_setstate(PyObject *self, PyObject *state) +{ + PyObject *d_key, *d_value; + Py_ssize_t i = 0; + + if (state != Py_None) { + if (!PyDict_Check(state)) { + PyErr_SetString(PyExc_TypeError, "state is not a dictionary"); + return NULL; + } + while (PyDict_Next(state, &i, &d_key, &d_value)) { + if (PyObject_SetAttr(self, d_key, d_value) < 0) + return NULL; + } + } + Py_RETURN_NONE; +} + + +static PyMethodDef BaseException_methods[] = { + {"__reduce__", (PyCFunction)BaseException_reduce, METH_NOARGS }, + {"__setstate__", (PyCFunction)BaseException_setstate, METH_O }, + {NULL, NULL, 0, NULL}, +}; + + + +static PyObject * +BaseException_getitem(PyBaseExceptionObject *self, Py_ssize_t index) +{ + return PySequence_GetItem(self->args, index); +} + +static PyObject * +BaseException_getslice(PyBaseExceptionObject *self, + Py_ssize_t start, Py_ssize_t stop) +{ + return PySequence_GetSlice(self->args, start, stop); +} + +static PySequenceMethods BaseException_as_sequence = { + 0, /* sq_length; */ + 0, /* sq_concat; */ + 0, /* sq_repeat; */ + (ssizeargfunc)BaseException_getitem, /* sq_item; */ + (ssizessizeargfunc)BaseException_getslice, /* sq_slice; */ + 0, /* sq_ass_item; */ + 0, /* sq_ass_slice; */ + 0, /* sq_contains; */ + 0, /* sq_inplace_concat; */ + 0 /* sq_inplace_repeat; */ +}; + +static PyMemberDef BaseException_members[] = { + {"message", T_OBJECT, offsetof(PyBaseExceptionObject, message), 0, + PyDoc_STR("exception message")}, + {NULL} /* Sentinel */ +}; + + +static PyObject * +BaseException_get_dict(PyBaseExceptionObject *self) +{ + if (self->dict == NULL) { + self->dict = PyDict_New(); + if (!self->dict) + return NULL; + } + Py_INCREF(self->dict); + return self->dict; +} + +static int +BaseException_set_dict(PyBaseExceptionObject *self, PyObject *val) +{ + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, "__dict__ may not be deleted"); + return -1; + } + if (!PyDict_Check(val)) { + PyErr_SetString(PyExc_TypeError, "__dict__ must be a dictionary"); + return -1; + } + Py_CLEAR(self->dict); + Py_INCREF(val); + self->dict = val; + return 0; +} + +static PyObject * +BaseException_get_args(PyBaseExceptionObject *self) +{ + if (self->args == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + Py_INCREF(self->args); + return self->args; +} + +static int +BaseException_set_args(PyBaseExceptionObject *self, PyObject *val) +{ + PyObject *seq; + if (val == NULL) { + PyErr_SetString(PyExc_TypeError, "args may not be deleted"); + return -1; + } + seq = PySequence_Tuple(val); + if (!seq) return -1; + Py_CLEAR(self->args); + self->args = seq; + return 0; +} + +static PyGetSetDef BaseException_getset[] = { + {"__dict__", (getter)BaseException_get_dict, (setter)BaseException_set_dict}, + {"args", (getter)BaseException_get_args, (setter)BaseException_set_args}, + {NULL}, +}; + + +static PyTypeObject _PyExc_BaseException = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + EXC_MODULE_NAME "BaseException", /*tp_name*/ + sizeof(PyBaseExceptionObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)BaseException_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /* tp_compare; */ + (reprfunc)BaseException_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &BaseException_as_sequence, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + (reprfunc)BaseException_str, /*tp_str*/ + PyObject_GenericGetAttr, /*tp_getattro*/ + PyObject_GenericSetAttr, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ + PyDoc_STR("Common base class for all exceptions"), /* tp_doc */ + (traverseproc)BaseException_traverse, /* tp_traverse */ + (inquiry)BaseException_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + BaseException_methods, /* tp_methods */ + BaseException_members, /* tp_members */ + BaseException_getset, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(PyBaseExceptionObject, dict), /* tp_dictoffset */ + (initproc)BaseException_init, /* tp_init */ + 0, /* tp_alloc */ + BaseException_new, /* tp_new */ +}; +/* the CPython API expects exceptions to be (PyObject *) - both a hold-over +from the previous implmentation and also allowing Python objects to be used +in the API */ +PyObject *PyExc_BaseException = (PyObject *)&_PyExc_BaseException; + +/* note these macros omit the last semicolon so the macro invocation may + * include it and not look strange. + */ +#define SimpleExtendsException(EXCBASE, EXCNAME, EXCDOC) \ +static PyTypeObject _PyExc_ ## EXCNAME = { \ + PyObject_HEAD_INIT(NULL) \ + 0, \ + EXC_MODULE_NAME # EXCNAME, \ + sizeof(PyBaseExceptionObject), \ + 0, (destructor)BaseException_dealloc, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, \ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ + PyDoc_STR(EXCDOC), (traverseproc)BaseException_traverse, \ + (inquiry)BaseException_clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ + 0, 0, 0, offsetof(PyBaseExceptionObject, dict), \ + (initproc)BaseException_init, 0, BaseException_new,\ +}; \ +PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME + +#define MiddlingExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCDOC) \ +static PyTypeObject _PyExc_ ## EXCNAME = { \ + PyObject_HEAD_INIT(NULL) \ + 0, \ + EXC_MODULE_NAME # EXCNAME, \ + sizeof(Py ## EXCSTORE ## Object), \ + 0, (destructor)EXCSTORE ## _dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, \ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ + PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ + (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, 0, 0, 0, &_ ## EXCBASE, \ + 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ + (initproc)EXCSTORE ## _init, 0, BaseException_new,\ +}; \ +PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME + +#define ComplexExtendsException(EXCBASE, EXCNAME, EXCSTORE, EXCDEALLOC, EXCMETHODS, EXCMEMBERS, EXCSTR, EXCDOC) \ +static PyTypeObject _PyExc_ ## EXCNAME = { \ + PyObject_HEAD_INIT(NULL) \ + 0, \ + EXC_MODULE_NAME # EXCNAME, \ + sizeof(Py ## EXCSTORE ## Object), 0, \ + (destructor)EXCSTORE ## _dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + (reprfunc)EXCSTR, 0, 0, 0, \ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, \ + PyDoc_STR(EXCDOC), (traverseproc)EXCSTORE ## _traverse, \ + (inquiry)EXCSTORE ## _clear, 0, 0, 0, 0, EXCMETHODS, \ + EXCMEMBERS, 0, &_ ## EXCBASE, \ + 0, 0, 0, offsetof(Py ## EXCSTORE ## Object, dict), \ + (initproc)EXCSTORE ## _init, 0, BaseException_new,\ +}; \ +PyObject *PyExc_ ## EXCNAME = (PyObject *)&_PyExc_ ## EXCNAME + + +/* + * Exception extends BaseException + */ +SimpleExtendsException(PyExc_BaseException, Exception, + "Common base class for all non-exit exceptions."); + + +/* + * StandardError extends Exception + */ +SimpleExtendsException(PyExc_Exception, StandardError, + "Base class for all standard Python exceptions that do not represent\n" + "interpreter exiting."); + + +/* + * TypeError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, TypeError, + "Inappropriate argument type."); + + +/* + * StopIteration extends Exception + */ +SimpleExtendsException(PyExc_Exception, StopIteration, + "Signal the end from iterator.next()."); + + +/* + * GeneratorExit extends Exception + */ +SimpleExtendsException(PyExc_Exception, GeneratorExit, + "Request that a generator exit."); + + +/* + * SystemExit extends BaseException + */ + +static int +SystemExit_init(PySystemExitObject *self, PyObject *args, PyObject *kwds) +{ + Py_ssize_t size = PyTuple_GET_SIZE(args); + + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + + if (size == 0) + return 0; + Py_CLEAR(self->code); + if (size == 1) + self->code = PyTuple_GET_ITEM(args, 0); + else if (size > 1) + self->code = args; + Py_INCREF(self->code); + return 0; +} + +static int +SystemExit_clear(PySystemExitObject *self) +{ + Py_CLEAR(self->code); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +SystemExit_dealloc(PySystemExitObject *self) +{ + _PyObject_GC_UNTRACK(self); + SystemExit_clear(self); + self->ob_type->tp_free((PyObject *)self); +} + +static int +SystemExit_traverse(PySystemExitObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->code); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static PyMemberDef SystemExit_members[] = { + {"message", T_OBJECT, offsetof(PySystemExitObject, message), 0, + PyDoc_STR("exception message")}, + {"code", T_OBJECT, offsetof(PySystemExitObject, code), 0, + PyDoc_STR("exception code")}, + {NULL} /* Sentinel */ +}; + +ComplexExtendsException(PyExc_BaseException, SystemExit, SystemExit, + SystemExit_dealloc, 0, SystemExit_members, 0, + "Request to exit from the interpreter."); + +/* + * KeyboardInterrupt extends BaseException + */ +SimpleExtendsException(PyExc_BaseException, KeyboardInterrupt, + "Program interrupted by user."); + + +/* + * ImportError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, ImportError, + "Import can't find module, or can't find name in module."); + + +/* + * EnvironmentError extends StandardError + */ + +/* Where a function has a single filename, such as open() or some + * of the os module functions, PyErr_SetFromErrnoWithFilename() is + * called, giving a third argument which is the filename. But, so + * that old code using in-place unpacking doesn't break, e.g.: + * + * except IOError, (errno, strerror): + * + * we hack args so that it only contains two items. This also + * means we need our own __str__() which prints out the filename + * when it was supplied. + */ +static int +EnvironmentError_init(PyEnvironmentErrorObject *self, PyObject *args, + PyObject *kwds) +{ + PyObject *myerrno = NULL, *strerror = NULL, *filename = NULL; + PyObject *subslice = NULL; + + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + + if (PyTuple_GET_SIZE(args) <= 1 || PyTuple_GET_SIZE(args) > 3) { + return 0; + } + + if (!PyArg_UnpackTuple(args, "EnvironmentError", 2, 3, + &myerrno, &strerror, &filename)) { + return -1; + } + Py_CLEAR(self->myerrno); /* replacing */ + self->myerrno = myerrno; + Py_INCREF(self->myerrno); + + Py_CLEAR(self->strerror); /* replacing */ + self->strerror = strerror; + Py_INCREF(self->strerror); + + /* self->filename will remain Py_None otherwise */ + if (filename != NULL) { + Py_CLEAR(self->filename); /* replacing */ + self->filename = filename; + Py_INCREF(self->filename); + + subslice = PyTuple_GetSlice(args, 0, 2); + if (!subslice) + return -1; + + Py_DECREF(self->args); /* replacing args */ + self->args = subslice; + } + return 0; +} + +static int +EnvironmentError_clear(PyEnvironmentErrorObject *self) +{ + Py_CLEAR(self->myerrno); + Py_CLEAR(self->strerror); + Py_CLEAR(self->filename); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +EnvironmentError_dealloc(PyEnvironmentErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + EnvironmentError_clear(self); + self->ob_type->tp_free((PyObject *)self); +} + +static int +EnvironmentError_traverse(PyEnvironmentErrorObject *self, visitproc visit, + void *arg) +{ + Py_VISIT(self->myerrno); + Py_VISIT(self->strerror); + Py_VISIT(self->filename); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static PyObject * +EnvironmentError_str(PyEnvironmentErrorObject *self) +{ + PyObject *rtnval = NULL; + + if (self->filename) { + PyObject *fmt; + PyObject *repr; + PyObject *tuple; + + fmt = PyString_FromString("[Errno %s] %s: %s"); + if (!fmt) + return NULL; + + repr = PyObject_Repr(self->filename); + if (!repr) { + Py_DECREF(fmt); + return NULL; + } + tuple = PyTuple_New(3); + if (!tuple) { + Py_DECREF(repr); + Py_DECREF(fmt); + return NULL; + } + + if (self->myerrno) { + Py_INCREF(self->myerrno); + PyTuple_SET_ITEM(tuple, 0, self->myerrno); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 0, Py_None); + } + if (self->strerror) { + Py_INCREF(self->strerror); + PyTuple_SET_ITEM(tuple, 1, self->strerror); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 1, Py_None); + } + + PyTuple_SET_ITEM(tuple, 2, repr); + + rtnval = PyString_Format(fmt, tuple); + + Py_DECREF(fmt); + Py_DECREF(tuple); + } + else if (self->myerrno && self->strerror) { + PyObject *fmt; + PyObject *tuple; + + fmt = PyString_FromString("[Errno %s] %s"); + if (!fmt) + return NULL; + + tuple = PyTuple_New(2); + if (!tuple) { + Py_DECREF(fmt); + return NULL; + } + + if (self->myerrno) { + Py_INCREF(self->myerrno); + PyTuple_SET_ITEM(tuple, 0, self->myerrno); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 0, Py_None); + } + if (self->strerror) { + Py_INCREF(self->strerror); + PyTuple_SET_ITEM(tuple, 1, self->strerror); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 1, Py_None); + } + + rtnval = PyString_Format(fmt, tuple); + + Py_DECREF(fmt); + Py_DECREF(tuple); + } + else + rtnval = BaseException_str((PyBaseExceptionObject *)self); + + return rtnval; +} + +static PyMemberDef EnvironmentError_members[] = { + {"message", T_OBJECT, offsetof(PyEnvironmentErrorObject, message), 0, + PyDoc_STR("exception message")}, + {"errno", T_OBJECT, offsetof(PyEnvironmentErrorObject, myerrno), 0, + PyDoc_STR("exception errno")}, + {"strerror", T_OBJECT, offsetof(PyEnvironmentErrorObject, strerror), 0, + PyDoc_STR("exception strerror")}, + {"filename", T_OBJECT, offsetof(PyEnvironmentErrorObject, filename), 0, + PyDoc_STR("exception filename")}, + {NULL} /* Sentinel */ +}; + + +static PyObject * +EnvironmentError_reduce(PyEnvironmentErrorObject *self) +{ + PyObject *args = self->args; + PyObject *res = NULL, *tmp; + + /* self->args is only the first two real arguments if there was a + * file name given to EnvironmentError. */ + if (PyTuple_GET_SIZE(args) == 2 && self->filename) { + args = PyTuple_New(3); + if (!args) return NULL; + + tmp = PyTuple_GET_ITEM(self->args, 0); + Py_INCREF(tmp); + PyTuple_SET_ITEM(args, 0, tmp); + + tmp = PyTuple_GET_ITEM(self->args, 1); + Py_INCREF(tmp); + PyTuple_SET_ITEM(args, 1, tmp); + + Py_INCREF(self->filename); + PyTuple_SET_ITEM(args, 2, self->filename); + } else + Py_INCREF(args); + + if (self->dict) + res = PyTuple_Pack(3, self->ob_type, args, self->dict); + else + res = PyTuple_Pack(2, self->ob_type, args); + Py_DECREF(args); + return res; +} + + +static PyMethodDef EnvironmentError_methods[] = { + {"__reduce__", (PyCFunction)EnvironmentError_reduce, METH_NOARGS}, + {NULL} +}; + +ComplexExtendsException(PyExc_StandardError, EnvironmentError, + EnvironmentError, EnvironmentError_dealloc, + EnvironmentError_methods, EnvironmentError_members, + EnvironmentError_str, + "Base class for I/O related errors."); + + +/* + * IOError extends EnvironmentError + */ +MiddlingExtendsException(PyExc_EnvironmentError, IOError, + EnvironmentError, "I/O operation failed."); + + +/* + * OSError extends EnvironmentError + */ +MiddlingExtendsException(PyExc_EnvironmentError, OSError, + EnvironmentError, "OS system call failed."); + + +/* + * WindowsError extends OSError + */ +#ifdef MS_WINDOWS +#include "errmap.h" + +static int +WindowsError_clear(PyWindowsErrorObject *self) +{ + Py_CLEAR(self->myerrno); + Py_CLEAR(self->strerror); + Py_CLEAR(self->filename); + Py_CLEAR(self->winerror); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +WindowsError_dealloc(PyWindowsErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + WindowsError_clear(self); + self->ob_type->tp_free((PyObject *)self); +} + +static int +WindowsError_traverse(PyWindowsErrorObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->myerrno); + Py_VISIT(self->strerror); + Py_VISIT(self->filename); + Py_VISIT(self->winerror); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static int +WindowsError_init(PyWindowsErrorObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *o_errcode = NULL; + long errcode; + long posix_errno; + + if (EnvironmentError_init((PyEnvironmentErrorObject *)self, args, kwds) + == -1) + return -1; + + if (self->myerrno == NULL) + return 0; + + /* Set errno to the POSIX errno, and winerror to the Win32 + error code. */ + errcode = PyInt_AsLong(self->myerrno); + if (errcode == -1 && PyErr_Occurred()) + return -1; + posix_errno = winerror_to_errno(errcode); + + Py_CLEAR(self->winerror); + self->winerror = self->myerrno; + + o_errcode = PyInt_FromLong(posix_errno); + if (!o_errcode) + return -1; + + self->myerrno = o_errcode; + + return 0; +} + + +static PyObject * +WindowsError_str(PyWindowsErrorObject *self) +{ + PyObject *rtnval = NULL; + + if (self->filename) { + PyObject *fmt; + PyObject *repr; + PyObject *tuple; + + fmt = PyString_FromString("[Error %s] %s: %s"); + if (!fmt) + return NULL; + + repr = PyObject_Repr(self->filename); + if (!repr) { + Py_DECREF(fmt); + return NULL; + } + tuple = PyTuple_New(3); + if (!tuple) { + Py_DECREF(repr); + Py_DECREF(fmt); + return NULL; + } + + if (self->winerror) { + Py_INCREF(self->winerror); + PyTuple_SET_ITEM(tuple, 0, self->winerror); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 0, Py_None); + } + if (self->strerror) { + Py_INCREF(self->strerror); + PyTuple_SET_ITEM(tuple, 1, self->strerror); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 1, Py_None); + } + + PyTuple_SET_ITEM(tuple, 2, repr); + + rtnval = PyString_Format(fmt, tuple); + + Py_DECREF(fmt); + Py_DECREF(tuple); + } + else if (self->winerror && self->strerror) { + PyObject *fmt; + PyObject *tuple; + + fmt = PyString_FromString("[Error %s] %s"); + if (!fmt) + return NULL; + + tuple = PyTuple_New(2); + if (!tuple) { + Py_DECREF(fmt); + return NULL; + } + + if (self->winerror) { + Py_INCREF(self->winerror); + PyTuple_SET_ITEM(tuple, 0, self->winerror); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 0, Py_None); + } + if (self->strerror) { + Py_INCREF(self->strerror); + PyTuple_SET_ITEM(tuple, 1, self->strerror); + } + else { + Py_INCREF(Py_None); + PyTuple_SET_ITEM(tuple, 1, Py_None); + } + + rtnval = PyString_Format(fmt, tuple); + + Py_DECREF(fmt); + Py_DECREF(tuple); + } + else + rtnval = EnvironmentError_str((PyEnvironmentErrorObject *)self); + + return rtnval; +} + +static PyMemberDef WindowsError_members[] = { + {"message", T_OBJECT, offsetof(PyWindowsErrorObject, message), 0, + PyDoc_STR("exception message")}, + {"errno", T_OBJECT, offsetof(PyWindowsErrorObject, myerrno), 0, + PyDoc_STR("POSIX exception code")}, + {"strerror", T_OBJECT, offsetof(PyWindowsErrorObject, strerror), 0, + PyDoc_STR("exception strerror")}, + {"filename", T_OBJECT, offsetof(PyWindowsErrorObject, filename), 0, + PyDoc_STR("exception filename")}, + {"winerror", T_OBJECT, offsetof(PyWindowsErrorObject, winerror), 0, + PyDoc_STR("Win32 exception code")}, + {NULL} /* Sentinel */ +}; + +ComplexExtendsException(PyExc_OSError, WindowsError, WindowsError, + WindowsError_dealloc, 0, WindowsError_members, + WindowsError_str, "MS-Windows OS system call failed."); + +#endif /* MS_WINDOWS */ + + +/* + * VMSError extends OSError (I think) + */ +#ifdef __VMS +MiddlingExtendsException(PyExc_OSError, VMSError, EnvironmentError, + "OpenVMS OS system call failed."); +#endif + + +/* + * EOFError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, EOFError, + "Read beyond end of file."); + + +/* + * RuntimeError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, RuntimeError, + "Unspecified run-time error."); + + +/* + * NotImplementedError extends RuntimeError + */ +SimpleExtendsException(PyExc_RuntimeError, NotImplementedError, + "Method or function hasn't been implemented yet."); + +/* + * NameError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, NameError, + "Name not found globally."); + +/* + * UnboundLocalError extends NameError + */ +SimpleExtendsException(PyExc_NameError, UnboundLocalError, + "Local name referenced but not bound to a value."); + +/* + * AttributeError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, AttributeError, + "Attribute not found."); + + +/* + * SyntaxError extends StandardError + */ + +static int +SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *info = NULL; + Py_ssize_t lenargs = PyTuple_GET_SIZE(args); + + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + + if (lenargs >= 1) { + Py_CLEAR(self->msg); + self->msg = PyTuple_GET_ITEM(args, 0); + Py_INCREF(self->msg); + } + if (lenargs == 2) { + info = PyTuple_GET_ITEM(args, 1); + info = PySequence_Tuple(info); + if (!info) return -1; + + if (PyTuple_GET_SIZE(info) != 4) { + /* not a very good error message, but it's what Python 2.4 gives */ + PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + Py_DECREF(info); + return -1; + } + + Py_CLEAR(self->filename); + self->filename = PyTuple_GET_ITEM(info, 0); + Py_INCREF(self->filename); + + Py_CLEAR(self->lineno); + self->lineno = PyTuple_GET_ITEM(info, 1); + Py_INCREF(self->lineno); + + Py_CLEAR(self->offset); + self->offset = PyTuple_GET_ITEM(info, 2); + Py_INCREF(self->offset); + + Py_CLEAR(self->text); + self->text = PyTuple_GET_ITEM(info, 3); + Py_INCREF(self->text); + + Py_DECREF(info); + } + return 0; +} + +static int +SyntaxError_clear(PySyntaxErrorObject *self) +{ + Py_CLEAR(self->msg); + Py_CLEAR(self->filename); + Py_CLEAR(self->lineno); + Py_CLEAR(self->offset); + Py_CLEAR(self->text); + Py_CLEAR(self->print_file_and_line); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +SyntaxError_dealloc(PySyntaxErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + SyntaxError_clear(self); + self->ob_type->tp_free((PyObject *)self); +} + +static int +SyntaxError_traverse(PySyntaxErrorObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->msg); + Py_VISIT(self->filename); + Py_VISIT(self->lineno); + Py_VISIT(self->offset); + Py_VISIT(self->text); + Py_VISIT(self->print_file_and_line); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +/* This is called "my_basename" instead of just "basename" to avoid name + conflicts with glibc; basename is already prototyped if _GNU_SOURCE is + defined, and Python does define that. */ +static char * +my_basename(char *name) +{ + char *cp = name; + char *result = name; + + if (name == NULL) + return "???"; + while (*cp != '\0') { + if (*cp == SEP) + result = cp + 1; + ++cp; + } + return result; +} + + +static PyObject * +SyntaxError_str(PySyntaxErrorObject *self) +{ + PyObject *str; + PyObject *result; + int have_filename = 0; + int have_lineno = 0; + char *buffer = NULL; + Py_ssize_t bufsize; + + if (self->msg) + str = PyObject_Str(self->msg); + else + str = PyObject_Str(Py_None); + if (!str) return NULL; + /* Don't fiddle with non-string return (shouldn't happen anyway) */ + if (!PyString_Check(str)) return str; + + /* XXX -- do all the additional formatting with filename and + lineno here */ + + have_filename = (self->filename != NULL) && + PyString_Check(self->filename); + have_lineno = (self->lineno != NULL) && PyInt_Check(self->lineno); + + if (!have_filename && !have_lineno) + return str; + + bufsize = PyString_GET_SIZE(str) + 64; + if (have_filename) + bufsize += PyString_GET_SIZE(self->filename); + + buffer = PyMem_MALLOC(bufsize); + if (buffer == NULL) + return str; + + if (have_filename && have_lineno) + PyOS_snprintf(buffer, bufsize, "%s (%s, line %ld)", + PyString_AS_STRING(str), + my_basename(PyString_AS_STRING(self->filename)), + PyInt_AsLong(self->lineno)); + else if (have_filename) + PyOS_snprintf(buffer, bufsize, "%s (%s)", + PyString_AS_STRING(str), + my_basename(PyString_AS_STRING(self->filename))); + else /* only have_lineno */ + PyOS_snprintf(buffer, bufsize, "%s (line %ld)", + PyString_AS_STRING(str), + PyInt_AsLong(self->lineno)); + + result = PyString_FromString(buffer); + PyMem_FREE(buffer); + + if (result == NULL) + result = str; + else + Py_DECREF(str); + return result; +} + +static PyMemberDef SyntaxError_members[] = { + {"message", T_OBJECT, offsetof(PySyntaxErrorObject, message), 0, + PyDoc_STR("exception message")}, + {"msg", T_OBJECT, offsetof(PySyntaxErrorObject, msg), 0, + PyDoc_STR("exception msg")}, + {"filename", T_OBJECT, offsetof(PySyntaxErrorObject, filename), 0, + PyDoc_STR("exception filename")}, + {"lineno", T_OBJECT, offsetof(PySyntaxErrorObject, lineno), 0, + PyDoc_STR("exception lineno")}, + {"offset", T_OBJECT, offsetof(PySyntaxErrorObject, offset), 0, + PyDoc_STR("exception offset")}, + {"text", T_OBJECT, offsetof(PySyntaxErrorObject, text), 0, + PyDoc_STR("exception text")}, + {"print_file_and_line", T_OBJECT, + offsetof(PySyntaxErrorObject, print_file_and_line), 0, + PyDoc_STR("exception print_file_and_line")}, + {NULL} /* Sentinel */ +}; + +ComplexExtendsException(PyExc_StandardError, SyntaxError, SyntaxError, + SyntaxError_dealloc, 0, SyntaxError_members, + SyntaxError_str, "Invalid syntax."); + + +/* + * IndentationError extends SyntaxError + */ +MiddlingExtendsException(PyExc_SyntaxError, IndentationError, SyntaxError, + "Improper indentation."); + + +/* + * TabError extends IndentationError + */ +MiddlingExtendsException(PyExc_IndentationError, TabError, SyntaxError, + "Improper mixture of spaces and tabs."); + + +/* + * LookupError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, LookupError, + "Base class for lookup errors."); + + +/* + * IndexError extends LookupError + */ +SimpleExtendsException(PyExc_LookupError, IndexError, + "Sequence index out of range."); + + +/* + * KeyError extends LookupError + */ +static PyObject * +KeyError_str(PyBaseExceptionObject *self) +{ + /* If args is a tuple of exactly one item, apply repr to args[0]. + This is done so that e.g. the exception raised by {}[''] prints + KeyError: '' + rather than the confusing + KeyError + alone. The downside is that if KeyError is raised with an explanatory + string, that string will be displayed in quotes. Too bad. + If args is anything else, use the default BaseException__str__(). + */ + if (PyTuple_GET_SIZE(self->args) == 1) { + return PyObject_Repr(PyTuple_GET_ITEM(self->args, 0)); + } + return BaseException_str(self); +} + +ComplexExtendsException(PyExc_LookupError, KeyError, BaseException, + 0, 0, 0, KeyError_str, "Mapping key not found."); + + +/* + * ValueError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, ValueError, + "Inappropriate argument value (of correct type)."); + +/* + * UnicodeError extends ValueError + */ + +SimpleExtendsException(PyExc_ValueError, UnicodeError, + "Unicode related error."); + +#ifdef Py_USING_UNICODE +static int +get_int(PyObject *attr, Py_ssize_t *value, const char *name) +{ + if (!attr) { + PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); + return -1; + } + + if (PyInt_Check(attr)) { + *value = PyInt_AS_LONG(attr); + } else if (PyLong_Check(attr)) { + *value = _PyLong_AsSsize_t(attr); + if (*value == -1 && PyErr_Occurred()) + return -1; + } else { + PyErr_Format(PyExc_TypeError, "%.200s attribute must be int", name); + return -1; + } + return 0; +} + +static int +set_ssize_t(PyObject **attr, Py_ssize_t value) +{ + PyObject *obj = PyInt_FromSsize_t(value); + if (!obj) + return -1; + Py_CLEAR(*attr); + *attr = obj; + return 0; +} + +static PyObject * +get_string(PyObject *attr, const char *name) +{ + if (!attr) { + PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); + return NULL; + } + + if (!PyString_Check(attr)) { + PyErr_Format(PyExc_TypeError, "%.200s attribute must be str", name); + return NULL; + } + Py_INCREF(attr); + return attr; +} + + +static int +set_string(PyObject **attr, const char *value) +{ + PyObject *obj = PyString_FromString(value); + if (!obj) + return -1; + Py_CLEAR(*attr); + *attr = obj; + return 0; +} + + +static PyObject * +get_unicode(PyObject *attr, const char *name) +{ + if (!attr) { + PyErr_Format(PyExc_TypeError, "%.200s attribute not set", name); + return NULL; + } + + if (!PyUnicode_Check(attr)) { + PyErr_Format(PyExc_TypeError, + "%.200s attribute must be unicode", name); + return NULL; + } + Py_INCREF(attr); + return attr; +} + +PyObject * +PyUnicodeEncodeError_GetEncoding(PyObject *exc) +{ + return get_string(((PyUnicodeErrorObject *)exc)->encoding, "encoding"); +} + +PyObject * +PyUnicodeDecodeError_GetEncoding(PyObject *exc) +{ + return get_string(((PyUnicodeErrorObject *)exc)->encoding, "encoding"); +} + +PyObject * +PyUnicodeEncodeError_GetObject(PyObject *exc) +{ + return get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); +} + +PyObject * +PyUnicodeDecodeError_GetObject(PyObject *exc) +{ + return get_string(((PyUnicodeErrorObject *)exc)->object, "object"); +} + +PyObject * +PyUnicodeTranslateError_GetObject(PyObject *exc) +{ + return get_unicode(((PyUnicodeErrorObject *)exc)->object, "object"); +} + +int +PyUnicodeEncodeError_GetStart(PyObject *exc, Py_ssize_t *start) +{ + if (!get_int(((PyUnicodeErrorObject *)exc)->start, start, "start")) { + Py_ssize_t size; + PyObject *obj = get_unicode(((PyUnicodeErrorObject *)exc)->object, + "object"); + if (!obj) return -1; + size = PyUnicode_GET_SIZE(obj); + if (*start<0) + *start = 0; /*XXX check for values <0*/ + if (*start>=size) + *start = size-1; + Py_DECREF(obj); + return 0; + } + return -1; +} + + +int +PyUnicodeDecodeError_GetStart(PyObject *exc, Py_ssize_t *start) +{ + if (!get_int(((PyUnicodeErrorObject *)exc)->start, start, "start")) { + Py_ssize_t size; + PyObject *obj = get_string(((PyUnicodeErrorObject *)exc)->object, + "object"); + if (!obj) return -1; + size = PyString_GET_SIZE(obj); + if (*start<0) + *start = 0; + if (*start>=size) + *start = size-1; + Py_DECREF(obj); + return 0; + } + return -1; +} + + +int +PyUnicodeTranslateError_GetStart(PyObject *exc, Py_ssize_t *start) +{ + return PyUnicodeEncodeError_GetStart(exc, start); +} + + +int +PyUnicodeEncodeError_SetStart(PyObject *exc, Py_ssize_t start) +{ + return set_ssize_t(&((PyUnicodeErrorObject *)exc)->start, start); +} + + +int +PyUnicodeDecodeError_SetStart(PyObject *exc, Py_ssize_t start) +{ + return set_ssize_t(&((PyUnicodeErrorObject *)exc)->start, start); +} + + +int +PyUnicodeTranslateError_SetStart(PyObject *exc, Py_ssize_t start) +{ + return set_ssize_t(&((PyUnicodeErrorObject *)exc)->start, start); +} + + +int +PyUnicodeEncodeError_GetEnd(PyObject *exc, Py_ssize_t *end) +{ + if (!get_int(((PyUnicodeErrorObject *)exc)->end, end, "end")) { + Py_ssize_t size; + PyObject *obj = get_unicode(((PyUnicodeErrorObject *)exc)->object, + "object"); + if (!obj) return -1; + size = PyUnicode_GET_SIZE(obj); + if (*end<1) + *end = 1; + if (*end>size) + *end = size; + Py_DECREF(obj); + return 0; + } + return -1; +} + + +int +PyUnicodeDecodeError_GetEnd(PyObject *exc, Py_ssize_t *end) +{ + if (!get_int(((PyUnicodeErrorObject *)exc)->end, end, "end")) { + Py_ssize_t size; + PyObject *obj = get_string(((PyUnicodeErrorObject *)exc)->object, + "object"); + if (!obj) return -1; + size = PyString_GET_SIZE(obj); + if (*end<1) + *end = 1; + if (*end>size) + *end = size; + Py_DECREF(obj); + return 0; + } + return -1; +} + + +int +PyUnicodeTranslateError_GetEnd(PyObject *exc, Py_ssize_t *start) +{ + return PyUnicodeEncodeError_GetEnd(exc, start); +} + + +int +PyUnicodeEncodeError_SetEnd(PyObject *exc, Py_ssize_t end) +{ + return set_ssize_t(&((PyUnicodeErrorObject *)exc)->end, end); +} + + +int +PyUnicodeDecodeError_SetEnd(PyObject *exc, Py_ssize_t end) +{ + return set_ssize_t(&((PyUnicodeErrorObject *)exc)->end, end); +} + + +int +PyUnicodeTranslateError_SetEnd(PyObject *exc, Py_ssize_t end) +{ + return set_ssize_t(&((PyUnicodeErrorObject *)exc)->end, end); +} + +PyObject * +PyUnicodeEncodeError_GetReason(PyObject *exc) +{ + return get_string(((PyUnicodeErrorObject *)exc)->reason, "reason"); +} + + +PyObject * +PyUnicodeDecodeError_GetReason(PyObject *exc) +{ + return get_string(((PyUnicodeErrorObject *)exc)->reason, "reason"); +} + + +PyObject * +PyUnicodeTranslateError_GetReason(PyObject *exc) +{ + return get_string(((PyUnicodeErrorObject *)exc)->reason, "reason"); +} + + +int +PyUnicodeEncodeError_SetReason(PyObject *exc, const char *reason) +{ + return set_string(&((PyUnicodeErrorObject *)exc)->reason, reason); +} + + +int +PyUnicodeDecodeError_SetReason(PyObject *exc, const char *reason) +{ + return set_string(&((PyUnicodeErrorObject *)exc)->reason, reason); +} + + +int +PyUnicodeTranslateError_SetReason(PyObject *exc, const char *reason) +{ + return set_string(&((PyUnicodeErrorObject *)exc)->reason, reason); +} + + +static int +UnicodeError_init(PyUnicodeErrorObject *self, PyObject *args, PyObject *kwds, + PyTypeObject *objecttype) +{ + Py_CLEAR(self->encoding); + Py_CLEAR(self->object); + Py_CLEAR(self->start); + Py_CLEAR(self->end); + Py_CLEAR(self->reason); + + if (!PyArg_ParseTuple(args, "O!O!O!O!O!", + &PyString_Type, &self->encoding, + objecttype, &self->object, + &PyInt_Type, &self->start, + &PyInt_Type, &self->end, + &PyString_Type, &self->reason)) { + self->encoding = self->object = self->start = self->end = + self->reason = NULL; + return -1; + } + + Py_INCREF(self->encoding); + Py_INCREF(self->object); + Py_INCREF(self->start); + Py_INCREF(self->end); + Py_INCREF(self->reason); + + return 0; +} + +static int +UnicodeError_clear(PyUnicodeErrorObject *self) +{ + Py_CLEAR(self->encoding); + Py_CLEAR(self->object); + Py_CLEAR(self->start); + Py_CLEAR(self->end); + Py_CLEAR(self->reason); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +UnicodeError_dealloc(PyUnicodeErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + UnicodeError_clear(self); + self->ob_type->tp_free((PyObject *)self); +} + +static int +UnicodeError_traverse(PyUnicodeErrorObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->encoding); + Py_VISIT(self->object); + Py_VISIT(self->start); + Py_VISIT(self->end); + Py_VISIT(self->reason); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static PyMemberDef UnicodeError_members[] = { + {"message", T_OBJECT, offsetof(PyUnicodeErrorObject, message), 0, + PyDoc_STR("exception message")}, + {"encoding", T_OBJECT, offsetof(PyUnicodeErrorObject, encoding), 0, + PyDoc_STR("exception encoding")}, + {"object", T_OBJECT, offsetof(PyUnicodeErrorObject, object), 0, + PyDoc_STR("exception object")}, + {"start", T_OBJECT, offsetof(PyUnicodeErrorObject, start), 0, + PyDoc_STR("exception start")}, + {"end", T_OBJECT, offsetof(PyUnicodeErrorObject, end), 0, + PyDoc_STR("exception end")}, + {"reason", T_OBJECT, offsetof(PyUnicodeErrorObject, reason), 0, + PyDoc_STR("exception reason")}, + {NULL} /* Sentinel */ +}; + + +/* + * UnicodeEncodeError extends UnicodeError + */ + +static int +UnicodeEncodeError_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + return UnicodeError_init((PyUnicodeErrorObject *)self, args, + kwds, &PyUnicode_Type); +} + +static PyObject * +UnicodeEncodeError_str(PyObject *self) +{ + Py_ssize_t start; + Py_ssize_t end; + + if (PyUnicodeEncodeError_GetStart(self, &start)) + return NULL; + + if (PyUnicodeEncodeError_GetEnd(self, &end)) + return NULL; + + if (end==start+1) { + int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; + char badchar_str[20]; + if (badchar <= 0xff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); + else if (badchar <= 0xffff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); + else + PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); + return PyString_FromFormat( + "'%.400s' codec can't encode character u'\\%s' in position %zd: %.400s", + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), + badchar_str, + start, + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); + } + return PyString_FromFormat( + "'%.400s' codec can't encode characters in position %zd-%zd: %.400s", + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), + start, + (end-1), + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); +} + +static PyTypeObject _PyExc_UnicodeEncodeError = { + PyObject_HEAD_INIT(NULL) + 0, + EXC_MODULE_NAME "UnicodeEncodeError", + sizeof(PyUnicodeErrorObject), 0, + (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + (reprfunc)UnicodeEncodeError_str, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + PyDoc_STR("Unicode encoding error."), (traverseproc)UnicodeError_traverse, + (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, + 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), + (initproc)UnicodeEncodeError_init, 0, BaseException_new, +}; +PyObject *PyExc_UnicodeEncodeError = (PyObject *)&_PyExc_UnicodeEncodeError; + +PyObject * +PyUnicodeEncodeError_Create( + const char *encoding, const Py_UNICODE *object, Py_ssize_t length, + Py_ssize_t start, Py_ssize_t end, const char *reason) +{ + return PyObject_CallFunction(PyExc_UnicodeEncodeError, "su#nns", + encoding, object, length, start, end, reason); +} + + +/* + * UnicodeDecodeError extends UnicodeError + */ + +static int +UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + return UnicodeError_init((PyUnicodeErrorObject *)self, args, + kwds, &PyString_Type); +} + +static PyObject * +UnicodeDecodeError_str(PyObject *self) +{ + Py_ssize_t start = 0; + Py_ssize_t end = 0; + + if (PyUnicodeDecodeError_GetStart(self, &start)) + return NULL; + + if (PyUnicodeDecodeError_GetEnd(self, &end)) + return NULL; + + if (end==start+1) { + /* FromFormat does not support %02x, so format that separately */ + char byte[4]; + PyOS_snprintf(byte, sizeof(byte), "%02x", + ((int)PyString_AS_STRING(((PyUnicodeErrorObject *)self)->object)[start])&0xff); + return PyString_FromFormat( + "'%.400s' codec can't decode byte 0x%s in position %zd: %.400s", + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), + byte, + start, + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); + } + return PyString_FromFormat( + "'%.400s' codec can't decode bytes in position %zd-%zd: %.400s", + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->encoding), + start, + (end-1), + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); +} + +static PyTypeObject _PyExc_UnicodeDecodeError = { + PyObject_HEAD_INIT(NULL) + 0, + EXC_MODULE_NAME "UnicodeDecodeError", + sizeof(PyUnicodeErrorObject), 0, + (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + (reprfunc)UnicodeDecodeError_str, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + PyDoc_STR("Unicode decoding error."), (traverseproc)UnicodeError_traverse, + (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, + 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), + (initproc)UnicodeDecodeError_init, 0, BaseException_new, +}; +PyObject *PyExc_UnicodeDecodeError = (PyObject *)&_PyExc_UnicodeDecodeError; + +PyObject * +PyUnicodeDecodeError_Create( + const char *encoding, const char *object, Py_ssize_t length, + Py_ssize_t start, Py_ssize_t end, const char *reason) +{ + assert(length < INT_MAX); + assert(start < INT_MAX); + assert(end < INT_MAX); + return PyObject_CallFunction(PyExc_UnicodeDecodeError, "ss#nns", + encoding, object, length, start, end, reason); +} + + +/* + * UnicodeTranslateError extends UnicodeError + */ + +static int +UnicodeTranslateError_init(PyUnicodeErrorObject *self, PyObject *args, + PyObject *kwds) +{ + if (BaseException_init((PyBaseExceptionObject *)self, args, kwds) == -1) + return -1; + + Py_CLEAR(self->object); + Py_CLEAR(self->start); + Py_CLEAR(self->end); + Py_CLEAR(self->reason); + + if (!PyArg_ParseTuple(args, "O!O!O!O!", + &PyUnicode_Type, &self->object, + &PyInt_Type, &self->start, + &PyInt_Type, &self->end, + &PyString_Type, &self->reason)) { + self->object = self->start = self->end = self->reason = NULL; + return -1; + } + + Py_INCREF(self->object); + Py_INCREF(self->start); + Py_INCREF(self->end); + Py_INCREF(self->reason); + + return 0; +} + + +static PyObject * +UnicodeTranslateError_str(PyObject *self) +{ + Py_ssize_t start; + Py_ssize_t end; + + if (PyUnicodeTranslateError_GetStart(self, &start)) + return NULL; + + if (PyUnicodeTranslateError_GetEnd(self, &end)) + return NULL; + + if (end==start+1) { + int badchar = (int)PyUnicode_AS_UNICODE(((PyUnicodeErrorObject *)self)->object)[start]; + char badchar_str[20]; + if (badchar <= 0xff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "x%02x", badchar); + else if (badchar <= 0xffff) + PyOS_snprintf(badchar_str, sizeof(badchar_str), "u%04x", badchar); + else + PyOS_snprintf(badchar_str, sizeof(badchar_str), "U%08x", badchar); + return PyString_FromFormat( + "can't translate character u'\\%s' in position %zd: %.400s", + badchar_str, + start, + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); + } + return PyString_FromFormat( + "can't translate characters in position %zd-%zd: %.400s", + start, + (end-1), + PyString_AS_STRING(((PyUnicodeErrorObject *)self)->reason) + ); +} + +static PyTypeObject _PyExc_UnicodeTranslateError = { + PyObject_HEAD_INIT(NULL) + 0, + EXC_MODULE_NAME "UnicodeTranslateError", + sizeof(PyUnicodeErrorObject), 0, + (destructor)UnicodeError_dealloc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + (reprfunc)UnicodeTranslateError_str, 0, 0, 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + PyDoc_STR("Unicode translation error."), (traverseproc)UnicodeError_traverse, + (inquiry)UnicodeError_clear, 0, 0, 0, 0, 0, UnicodeError_members, + 0, &_PyExc_UnicodeError, 0, 0, 0, offsetof(PyUnicodeErrorObject, dict), + (initproc)UnicodeTranslateError_init, 0, BaseException_new, +}; +PyObject *PyExc_UnicodeTranslateError = (PyObject *)&_PyExc_UnicodeTranslateError; + +PyObject * +PyUnicodeTranslateError_Create( + const Py_UNICODE *object, Py_ssize_t length, + Py_ssize_t start, Py_ssize_t end, const char *reason) +{ + return PyObject_CallFunction(PyExc_UnicodeTranslateError, "u#nns", + object, length, start, end, reason); +} +#endif + + +/* + * AssertionError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, AssertionError, + "Assertion failed."); + + +/* + * ArithmeticError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, ArithmeticError, + "Base class for arithmetic errors."); + + +/* + * FloatingPointError extends ArithmeticError + */ +SimpleExtendsException(PyExc_ArithmeticError, FloatingPointError, + "Floating point operation failed."); + + +/* + * OverflowError extends ArithmeticError + */ +SimpleExtendsException(PyExc_ArithmeticError, OverflowError, + "Result too large to be represented."); + + +/* + * ZeroDivisionError extends ArithmeticError + */ +SimpleExtendsException(PyExc_ArithmeticError, ZeroDivisionError, + "Second argument to a division or modulo operation was zero."); + + +/* + * SystemError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, SystemError, + "Internal error in the Python interpreter.\n" + "\n" + "Please report this to the Python maintainer, along with the traceback,\n" + "the Python version, and the hardware/OS platform and version."); + + +/* + * ReferenceError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, ReferenceError, + "Weak ref proxy used after referent went away."); + + +/* + * MemoryError extends StandardError + */ +SimpleExtendsException(PyExc_StandardError, MemoryError, "Out of memory."); + + +/* Warning category docstrings */ + +/* + * Warning extends Exception + */ +SimpleExtendsException(PyExc_Exception, Warning, + "Base class for warning categories."); + + +/* + * UserWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, UserWarning, + "Base class for warnings generated by user code."); + + +/* + * DeprecationWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, DeprecationWarning, + "Base class for warnings about deprecated features."); + + +/* + * PendingDeprecationWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, PendingDeprecationWarning, + "Base class for warnings about features which will be deprecated\n" + "in the future."); + + +/* + * SyntaxWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, SyntaxWarning, + "Base class for warnings about dubious syntax."); + + +/* + * RuntimeWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, RuntimeWarning, + "Base class for warnings about dubious runtime behavior."); + + +/* + * FutureWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, FutureWarning, + "Base class for warnings about constructs that will change semantically\n" + "in the future."); + + +/* + * ImportWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, ImportWarning, + "Base class for warnings about probable mistakes in module imports"); + + +/* + * UnicodeWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, UnicodeWarning, + "Base class for warnings about Unicode related problems, mostly\n" + "related to conversion problems."); + + +/* Pre-computed MemoryError instance. Best to create this as early as + * possible and not wait until a MemoryError is actually raised! + */ +PyObject *PyExc_MemoryErrorInst=NULL; + +/* module global functions */ +static PyMethodDef functions[] = { + /* Sentinel */ + {NULL, NULL} +}; + +#define PRE_INIT(TYPE) if (PyType_Ready(&_PyExc_ ## TYPE) < 0) \ + Py_FatalError("exceptions bootstrapping error."); + +#define POST_INIT(TYPE) Py_INCREF(PyExc_ ## TYPE); \ + PyModule_AddObject(m, # TYPE, PyExc_ ## TYPE); \ + if (PyDict_SetItemString(bdict, # TYPE, PyExc_ ## TYPE)) \ + Py_FatalError("Module dictionary insertion problem."); + +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) +/* crt variable checking in VisualStudio .NET 2005 */ +#include <crtdbg.h> + +static int prevCrtReportMode; +static _invalid_parameter_handler prevCrtHandler; + +/* Invalid parameter handler. Sets a ValueError exception */ +static void +InvalidParameterHandler( + const wchar_t * expression, + const wchar_t * function, + const wchar_t * file, + unsigned int line, + uintptr_t pReserved) +{ + /* Do nothing, allow execution to continue. Usually this + * means that the CRT will set errno to EINVAL + */ +} +#endif + + +PyMODINIT_FUNC +_PyExc_Init(void) +{ + PyObject *m, *bltinmod, *bdict; + + PRE_INIT(BaseException) + PRE_INIT(Exception) + PRE_INIT(StandardError) + PRE_INIT(TypeError) + PRE_INIT(StopIteration) + PRE_INIT(GeneratorExit) + PRE_INIT(SystemExit) + PRE_INIT(KeyboardInterrupt) + PRE_INIT(ImportError) + PRE_INIT(EnvironmentError) + PRE_INIT(IOError) + PRE_INIT(OSError) +#ifdef MS_WINDOWS + PRE_INIT(WindowsError) +#endif +#ifdef __VMS + PRE_INIT(VMSError) +#endif + PRE_INIT(EOFError) + PRE_INIT(RuntimeError) + PRE_INIT(NotImplementedError) + PRE_INIT(NameError) + PRE_INIT(UnboundLocalError) + PRE_INIT(AttributeError) + PRE_INIT(SyntaxError) + PRE_INIT(IndentationError) + PRE_INIT(TabError) + PRE_INIT(LookupError) + PRE_INIT(IndexError) + PRE_INIT(KeyError) + PRE_INIT(ValueError) + PRE_INIT(UnicodeError) +#ifdef Py_USING_UNICODE + PRE_INIT(UnicodeEncodeError) + PRE_INIT(UnicodeDecodeError) + PRE_INIT(UnicodeTranslateError) +#endif + PRE_INIT(AssertionError) + PRE_INIT(ArithmeticError) + PRE_INIT(FloatingPointError) + PRE_INIT(OverflowError) + PRE_INIT(ZeroDivisionError) + PRE_INIT(SystemError) + PRE_INIT(ReferenceError) + PRE_INIT(MemoryError) + PRE_INIT(Warning) + PRE_INIT(UserWarning) + PRE_INIT(DeprecationWarning) + PRE_INIT(PendingDeprecationWarning) + PRE_INIT(SyntaxWarning) + PRE_INIT(RuntimeWarning) + PRE_INIT(FutureWarning) + PRE_INIT(ImportWarning) + PRE_INIT(UnicodeWarning) + + m = Py_InitModule4("exceptions", functions, exceptions_doc, + (PyObject *)NULL, PYTHON_API_VERSION); + if (m == NULL) return; + + bltinmod = PyImport_ImportModule("__builtin__"); + if (bltinmod == NULL) + Py_FatalError("exceptions bootstrapping error."); + bdict = PyModule_GetDict(bltinmod); + if (bdict == NULL) + Py_FatalError("exceptions bootstrapping error."); + + POST_INIT(BaseException) + POST_INIT(Exception) + POST_INIT(StandardError) + POST_INIT(TypeError) + POST_INIT(StopIteration) + POST_INIT(GeneratorExit) + POST_INIT(SystemExit) + POST_INIT(KeyboardInterrupt) + POST_INIT(ImportError) + POST_INIT(EnvironmentError) + POST_INIT(IOError) + POST_INIT(OSError) +#ifdef MS_WINDOWS + POST_INIT(WindowsError) +#endif +#ifdef __VMS + POST_INIT(VMSError) +#endif + POST_INIT(EOFError) + POST_INIT(RuntimeError) + POST_INIT(NotImplementedError) + POST_INIT(NameError) + POST_INIT(UnboundLocalError) + POST_INIT(AttributeError) + POST_INIT(SyntaxError) + POST_INIT(IndentationError) + POST_INIT(TabError) + POST_INIT(LookupError) + POST_INIT(IndexError) + POST_INIT(KeyError) + POST_INIT(ValueError) + POST_INIT(UnicodeError) +#ifdef Py_USING_UNICODE + POST_INIT(UnicodeEncodeError) + POST_INIT(UnicodeDecodeError) + POST_INIT(UnicodeTranslateError) +#endif + POST_INIT(AssertionError) + POST_INIT(ArithmeticError) + POST_INIT(FloatingPointError) + POST_INIT(OverflowError) + POST_INIT(ZeroDivisionError) + POST_INIT(SystemError) + POST_INIT(ReferenceError) + POST_INIT(MemoryError) + POST_INIT(Warning) + POST_INIT(UserWarning) + POST_INIT(DeprecationWarning) + POST_INIT(PendingDeprecationWarning) + POST_INIT(SyntaxWarning) + POST_INIT(RuntimeWarning) + POST_INIT(FutureWarning) + POST_INIT(ImportWarning) + POST_INIT(UnicodeWarning) + + PyExc_MemoryErrorInst = BaseException_new(&_PyExc_MemoryError, NULL, NULL); + if (!PyExc_MemoryErrorInst) + Py_FatalError("Cannot pre-allocate MemoryError instance\n"); + + Py_DECREF(bltinmod); + +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) + /* Set CRT argument error handler */ + prevCrtHandler = _set_invalid_parameter_handler(InvalidParameterHandler); + /* turn off assertions in debug mode */ + prevCrtReportMode = _CrtSetReportMode(_CRT_ASSERT, 0); +#endif +} + +void +_PyExc_Fini(void) +{ + Py_XDECREF(PyExc_MemoryErrorInst); + PyExc_MemoryErrorInst = NULL; +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) + /* reset CRT error handling */ + _set_invalid_parameter_handler(prevCrtHandler); + _CrtSetReportMode(_CRT_ASSERT, prevCrtReportMode); +#endif +} diff --git a/sys/src/cmd/python/Objects/fileobject.c b/sys/src/cmd/python/Objects/fileobject.c new file mode 100644 index 000000000..869ded916 --- /dev/null +++ b/sys/src/cmd/python/Objects/fileobject.c @@ -0,0 +1,2484 @@ +/* File object implementation */ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" +#include "structmember.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif /* HAVE_SYS_TYPES_H */ + +#ifdef MS_WINDOWS +#define fileno _fileno +/* can simulate truncate with Win32 API functions; see file_truncate */ +#define HAVE_FTRUNCATE +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#ifdef _MSC_VER +/* Need GetVersion to see if on NT so safe to use _wfopen */ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif /* _MSC_VER */ + +#if defined(PYOS_OS2) && defined(PYCC_GCC) +#include <io.h> +#endif + +#define BUF(v) PyString_AS_STRING((PyStringObject *)v) + +#ifndef DONT_HAVE_ERRNO_H +#include <errno.h> +#endif + +#ifdef HAVE_GETC_UNLOCKED +#define GETC(f) getc_unlocked(f) +#define FLOCKFILE(f) flockfile(f) +#define FUNLOCKFILE(f) funlockfile(f) +#else +#define GETC(f) getc(f) +#define FLOCKFILE(f) +#define FUNLOCKFILE(f) +#endif + +/* Bits in f_newlinetypes */ +#define NEWLINE_UNKNOWN 0 /* No newline seen, yet */ +#define NEWLINE_CR 1 /* \r newline seen */ +#define NEWLINE_LF 2 /* \n newline seen */ +#define NEWLINE_CRLF 4 /* \r\n newline seen */ + +#ifdef __cplusplus +extern "C" { +#endif + +FILE * +PyFile_AsFile(PyObject *f) +{ + if (f == NULL || !PyFile_Check(f)) + return NULL; + else + return ((PyFileObject *)f)->f_fp; +} + +PyObject * +PyFile_Name(PyObject *f) +{ + if (f == NULL || !PyFile_Check(f)) + return NULL; + else + return ((PyFileObject *)f)->f_name; +} + +/* On Unix, fopen will succeed for directories. + In Python, there should be no file objects referring to + directories, so we need a check. */ + +static PyFileObject* +dircheck(PyFileObject* f) +{ +#if defined(HAVE_FSTAT) && defined(S_IFDIR) && defined(EISDIR) + struct stat buf; + if (f->f_fp == NULL) + return f; + if (fstat(fileno(f->f_fp), &buf) == 0 && + S_ISDIR(buf.st_mode)) { +#ifdef HAVE_STRERROR + char *msg = strerror(EISDIR); +#else + char *msg = "Is a directory"; +#endif + PyObject *exc = PyObject_CallFunction(PyExc_IOError, "(is)", + EISDIR, msg); + PyErr_SetObject(PyExc_IOError, exc); + Py_XDECREF(exc); + return NULL; + } +#endif + return f; +} + + +static PyObject * +fill_file_fields(PyFileObject *f, FILE *fp, PyObject *name, char *mode, + int (*close)(FILE *)) +{ + assert(name != NULL); + assert(f != NULL); + assert(PyFile_Check(f)); + assert(f->f_fp == NULL); + + Py_DECREF(f->f_name); + Py_DECREF(f->f_mode); + Py_DECREF(f->f_encoding); + + Py_INCREF(name); + f->f_name = name; + + f->f_mode = PyString_FromString(mode); + + f->f_close = close; + f->f_softspace = 0; + f->f_binary = strchr(mode,'b') != NULL; + f->f_buf = NULL; + f->f_univ_newline = (strchr(mode, 'U') != NULL); + f->f_newlinetypes = NEWLINE_UNKNOWN; + f->f_skipnextlf = 0; + Py_INCREF(Py_None); + f->f_encoding = Py_None; + + if (f->f_mode == NULL) + return NULL; + f->f_fp = fp; + f = dircheck(f); + return (PyObject *) f; +} + +/* check for known incorrect mode strings - problem is, platforms are + free to accept any mode characters they like and are supposed to + ignore stuff they don't understand... write or append mode with + universal newline support is expressly forbidden by PEP 278. + Additionally, remove the 'U' from the mode string as platforms + won't know what it is. */ +/* zero return is kewl - one is un-kewl */ +static int +sanitize_the_mode(char *mode) +{ + char *upos; + size_t len = strlen(mode); + + if (!len) { + PyErr_SetString(PyExc_ValueError, "empty mode string"); + return 1; + } + + upos = strchr(mode, 'U'); + if (upos) { + memmove(upos, upos+1, len-(upos-mode)); /* incl null char */ + + if (mode[0] == 'w' || mode[0] == 'a') { + PyErr_Format(PyExc_ValueError, "universal newline " + "mode can only be used with modes " + "starting with 'r'"); + return 1; + } + + if (mode[0] != 'r') { + memmove(mode+1, mode, strlen(mode)+1); + mode[0] = 'r'; + } + + if (!strchr(mode, 'b')) { + memmove(mode+2, mode+1, strlen(mode)); + mode[1] = 'b'; + } + } else if (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a') { + PyErr_Format(PyExc_ValueError, "mode string must begin with " + "one of 'r', 'w', 'a' or 'U', not '%.200s'", mode); + return 1; + } + + return 0; +} + +static PyObject * +open_the_file(PyFileObject *f, char *name, char *mode) +{ + char *newmode; + assert(f != NULL); + assert(PyFile_Check(f)); +#ifdef MS_WINDOWS + /* windows ignores the passed name in order to support Unicode */ + assert(f->f_name != NULL); +#else + assert(name != NULL); +#endif + assert(mode != NULL); + assert(f->f_fp == NULL); + + /* probably need to replace 'U' by 'rb' */ + newmode = PyMem_MALLOC(strlen(mode) + 3); + if (!newmode) { + PyErr_NoMemory(); + return NULL; + } + strcpy(newmode, mode); + + if (sanitize_the_mode(newmode)) { + f = NULL; + goto cleanup; + } + + /* rexec.py can't stop a user from getting the file() constructor -- + all they have to do is get *any* file object f, and then do + type(f). Here we prevent them from doing damage with it. */ + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_IOError, + "file() constructor not accessible in restricted mode"); + f = NULL; + goto cleanup; + } + errno = 0; + +#ifdef MS_WINDOWS + if (PyUnicode_Check(f->f_name)) { + PyObject *wmode; + wmode = PyUnicode_DecodeASCII(newmode, strlen(newmode), NULL); + if (f->f_name && wmode) { + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread + lock as it is a simple dereference. */ + f->f_fp = _wfopen(PyUnicode_AS_UNICODE(f->f_name), + PyUnicode_AS_UNICODE(wmode)); + Py_END_ALLOW_THREADS + } + Py_XDECREF(wmode); + } +#endif + if (NULL == f->f_fp && NULL != name) { + Py_BEGIN_ALLOW_THREADS + f->f_fp = fopen(name, newmode); + Py_END_ALLOW_THREADS + } + + if (f->f_fp == NULL) { +#if defined _MSC_VER && (_MSC_VER < 1400 || !defined(__STDC_SECURE_LIB__)) + /* MSVC 6 (Microsoft) leaves errno at 0 for bad mode strings, + * across all Windows flavors. When it sets EINVAL varies + * across Windows flavors, the exact conditions aren't + * documented, and the answer lies in the OS's implementation + * of Win32's CreateFile function (whose source is secret). + * Seems the best we can do is map EINVAL to ENOENT. + * Starting with Visual Studio .NET 2005, EINVAL is correctly + * set by our CRT error handler (set in exceptions.c.) + */ + if (errno == 0) /* bad mode string */ + errno = EINVAL; + else if (errno == EINVAL) /* unknown, but not a mode string */ + errno = ENOENT; +#endif + if (errno == EINVAL) + PyErr_Format(PyExc_IOError, "invalid mode: %s", + mode); + else + PyErr_SetFromErrnoWithFilenameObject(PyExc_IOError, f->f_name); + f = NULL; + } + if (f != NULL) + f = dircheck(f); + +cleanup: + PyMem_FREE(newmode); + + return (PyObject *)f; +} + +PyObject * +PyFile_FromFile(FILE *fp, char *name, char *mode, int (*close)(FILE *)) +{ + PyFileObject *f = (PyFileObject *)PyFile_Type.tp_new(&PyFile_Type, + NULL, NULL); + if (f != NULL) { + PyObject *o_name = PyString_FromString(name); + if (o_name == NULL) + return NULL; + if (fill_file_fields(f, fp, o_name, mode, close) == NULL) { + Py_DECREF(f); + f = NULL; + } + Py_DECREF(o_name); + } + return (PyObject *) f; +} + +PyObject * +PyFile_FromString(char *name, char *mode) +{ + extern int fclose(FILE *); + PyFileObject *f; + + f = (PyFileObject *)PyFile_FromFile((FILE *)NULL, name, mode, fclose); + if (f != NULL) { + if (open_the_file(f, name, mode) == NULL) { + Py_DECREF(f); + f = NULL; + } + } + return (PyObject *)f; +} + +void +PyFile_SetBufSize(PyObject *f, int bufsize) +{ + PyFileObject *file = (PyFileObject *)f; + if (bufsize >= 0) { + int type; + switch (bufsize) { + case 0: + type = _IONBF; + break; +#ifdef HAVE_SETVBUF + case 1: + type = _IOLBF; + bufsize = BUFSIZ; + break; +#endif + default: + type = _IOFBF; +#ifndef HAVE_SETVBUF + bufsize = BUFSIZ; +#endif + break; + } + fflush(file->f_fp); + if (type == _IONBF) { + PyMem_Free(file->f_setbuf); + file->f_setbuf = NULL; + } else { + file->f_setbuf = (char *)PyMem_Realloc(file->f_setbuf, + bufsize); + } +#ifdef HAVE_SETVBUF + setvbuf(file->f_fp, file->f_setbuf, type, bufsize); +#else /* !HAVE_SETVBUF */ + setbuf(file->f_fp, file->f_setbuf); +#endif /* !HAVE_SETVBUF */ + } +} + +/* Set the encoding used to output Unicode strings. + Returh 1 on success, 0 on failure. */ + +int +PyFile_SetEncoding(PyObject *f, const char *enc) +{ + PyFileObject *file = (PyFileObject*)f; + PyObject *str = PyString_FromString(enc); + + assert(PyFile_Check(f)); + if (!str) + return 0; + Py_DECREF(file->f_encoding); + file->f_encoding = str; + return 1; +} + +static PyObject * +err_closed(void) +{ + PyErr_SetString(PyExc_ValueError, "I/O operation on closed file"); + return NULL; +} + +/* Refuse regular file I/O if there's data in the iteration-buffer. + * Mixing them would cause data to arrive out of order, as the read* + * methods don't use the iteration buffer. */ +static PyObject * +err_iterbuffered(void) +{ + PyErr_SetString(PyExc_ValueError, + "Mixing iteration and read methods would lose data"); + return NULL; +} + +static void drop_readahead(PyFileObject *); + +/* Methods */ + +static void +file_dealloc(PyFileObject *f) +{ + int sts = 0; + if (f->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) f); + if (f->f_fp != NULL && f->f_close != NULL) { + Py_BEGIN_ALLOW_THREADS + sts = (*f->f_close)(f->f_fp); + Py_END_ALLOW_THREADS + if (sts == EOF) +#ifdef HAVE_STRERROR + PySys_WriteStderr("close failed: [Errno %d] %s\n", errno, strerror(errno)); +#else + PySys_WriteStderr("close failed: [Errno %d]\n", errno); +#endif + } + PyMem_Free(f->f_setbuf); + Py_XDECREF(f->f_name); + Py_XDECREF(f->f_mode); + Py_XDECREF(f->f_encoding); + drop_readahead(f); + f->ob_type->tp_free((PyObject *)f); +} + +static PyObject * +file_repr(PyFileObject *f) +{ + if (PyUnicode_Check(f->f_name)) { +#ifdef Py_USING_UNICODE + PyObject *ret = NULL; + PyObject *name = PyUnicode_AsUnicodeEscapeString(f->f_name); + const char *name_str = name ? PyString_AsString(name) : "?"; + ret = PyString_FromFormat("<%s file u'%s', mode '%s' at %p>", + f->f_fp == NULL ? "closed" : "open", + name_str, + PyString_AsString(f->f_mode), + f); + Py_XDECREF(name); + return ret; +#endif + } else { + return PyString_FromFormat("<%s file '%s', mode '%s' at %p>", + f->f_fp == NULL ? "closed" : "open", + PyString_AsString(f->f_name), + PyString_AsString(f->f_mode), + f); + } +} + +static PyObject * +file_close(PyFileObject *f) +{ + int sts = 0; + if (f->f_fp != NULL) { + if (f->f_close != NULL) { + Py_BEGIN_ALLOW_THREADS + errno = 0; + sts = (*f->f_close)(f->f_fp); + Py_END_ALLOW_THREADS + } + f->f_fp = NULL; + } + PyMem_Free(f->f_setbuf); + f->f_setbuf = NULL; + if (sts == EOF) + return PyErr_SetFromErrno(PyExc_IOError); + if (sts != 0) + return PyInt_FromLong((long)sts); + Py_INCREF(Py_None); + return Py_None; +} + + +/* Our very own off_t-like type, 64-bit if possible */ +#if !defined(HAVE_LARGEFILE_SUPPORT) +typedef off_t Py_off_t; +#elif SIZEOF_OFF_T >= 8 +typedef off_t Py_off_t; +#elif SIZEOF_FPOS_T >= 8 +typedef fpos_t Py_off_t; +#else +#error "Large file support, but neither off_t nor fpos_t is large enough." +#endif + + +/* a portable fseek() function + return 0 on success, non-zero on failure (with errno set) */ +static int +_portable_fseek(FILE *fp, Py_off_t offset, int whence) +{ +#if !defined(HAVE_LARGEFILE_SUPPORT) + return fseek(fp, offset, whence); +#elif defined(HAVE_FSEEKO) && SIZEOF_OFF_T >= 8 + return fseeko(fp, offset, whence); +#elif defined(HAVE_FSEEK64) + return fseek64(fp, offset, whence); +#elif defined(__BEOS__) + return _fseek(fp, offset, whence); +#elif SIZEOF_FPOS_T >= 8 + /* lacking a 64-bit capable fseek(), use a 64-bit capable fsetpos() + and fgetpos() to implement fseek()*/ + fpos_t pos; + switch (whence) { + case SEEK_END: +#ifdef MS_WINDOWS + fflush(fp); + if (_lseeki64(fileno(fp), 0, 2) == -1) + return -1; +#else + if (fseek(fp, 0, SEEK_END) != 0) + return -1; +#endif + /* fall through */ + case SEEK_CUR: + if (fgetpos(fp, &pos) != 0) + return -1; + offset += pos; + break; + /* case SEEK_SET: break; */ + } + return fsetpos(fp, &offset); +#else +#error "Large file support, but no way to fseek." +#endif +} + + +/* a portable ftell() function + Return -1 on failure with errno set appropriately, current file + position on success */ +static Py_off_t +_portable_ftell(FILE* fp) +{ +#if !defined(HAVE_LARGEFILE_SUPPORT) + return ftell(fp); +#elif defined(HAVE_FTELLO) && SIZEOF_OFF_T >= 8 + return ftello(fp); +#elif defined(HAVE_FTELL64) + return ftell64(fp); +#elif SIZEOF_FPOS_T >= 8 + fpos_t pos; + if (fgetpos(fp, &pos) != 0) + return -1; + return pos; +#else +#error "Large file support, but no way to ftell." +#endif +} + + +static PyObject * +file_seek(PyFileObject *f, PyObject *args) +{ + int whence; + int ret; + Py_off_t offset; + PyObject *offobj; + + if (f->f_fp == NULL) + return err_closed(); + drop_readahead(f); + whence = 0; + if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &whence)) + return NULL; +#if !defined(HAVE_LARGEFILE_SUPPORT) + offset = PyInt_AsLong(offobj); +#else + offset = PyLong_Check(offobj) ? + PyLong_AsLongLong(offobj) : PyInt_AsLong(offobj); +#endif + if (PyErr_Occurred()) + return NULL; + + Py_BEGIN_ALLOW_THREADS + errno = 0; + ret = _portable_fseek(f->f_fp, offset, whence); + Py_END_ALLOW_THREADS + + if (ret != 0) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + return NULL; + } + f->f_skipnextlf = 0; + Py_INCREF(Py_None); + return Py_None; +} + + +#ifdef HAVE_FTRUNCATE +static PyObject * +file_truncate(PyFileObject *f, PyObject *args) +{ + Py_off_t newsize; + PyObject *newsizeobj = NULL; + Py_off_t initialpos; + int ret; + + if (f->f_fp == NULL) + return err_closed(); + if (!PyArg_UnpackTuple(args, "truncate", 0, 1, &newsizeobj)) + return NULL; + + /* Get current file position. If the file happens to be open for + * update and the last operation was an input operation, C doesn't + * define what the later fflush() will do, but we promise truncate() + * won't change the current position (and fflush() *does* change it + * then at least on Windows). The easiest thing is to capture + * current pos now and seek back to it at the end. + */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + initialpos = _portable_ftell(f->f_fp); + Py_END_ALLOW_THREADS + if (initialpos == -1) + goto onioerror; + + /* Set newsize to current postion if newsizeobj NULL, else to the + * specified value. + */ + if (newsizeobj != NULL) { +#if !defined(HAVE_LARGEFILE_SUPPORT) + newsize = PyInt_AsLong(newsizeobj); +#else + newsize = PyLong_Check(newsizeobj) ? + PyLong_AsLongLong(newsizeobj) : + PyInt_AsLong(newsizeobj); +#endif + if (PyErr_Occurred()) + return NULL; + } + else /* default to current position */ + newsize = initialpos; + + /* Flush the stream. We're mixing stream-level I/O with lower-level + * I/O, and a flush may be necessary to synch both platform views + * of the current file state. + */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + ret = fflush(f->f_fp); + Py_END_ALLOW_THREADS + if (ret != 0) + goto onioerror; + +#ifdef MS_WINDOWS + /* MS _chsize doesn't work if newsize doesn't fit in 32 bits, + so don't even try using it. */ + { + HANDLE hFile; + + /* Have to move current pos to desired endpoint on Windows. */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + ret = _portable_fseek(f->f_fp, newsize, SEEK_SET) != 0; + Py_END_ALLOW_THREADS + if (ret) + goto onioerror; + + /* Truncate. Note that this may grow the file! */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + hFile = (HANDLE)_get_osfhandle(fileno(f->f_fp)); + ret = hFile == (HANDLE)-1; + if (ret == 0) { + ret = SetEndOfFile(hFile) == 0; + if (ret) + errno = EACCES; + } + Py_END_ALLOW_THREADS + if (ret) + goto onioerror; + } +#else + Py_BEGIN_ALLOW_THREADS + errno = 0; + ret = ftruncate(fileno(f->f_fp), newsize); + Py_END_ALLOW_THREADS + if (ret != 0) + goto onioerror; +#endif /* !MS_WINDOWS */ + + /* Restore original file position. */ + Py_BEGIN_ALLOW_THREADS + errno = 0; + ret = _portable_fseek(f->f_fp, initialpos, SEEK_SET) != 0; + Py_END_ALLOW_THREADS + if (ret) + goto onioerror; + + Py_INCREF(Py_None); + return Py_None; + +onioerror: + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + return NULL; +} +#endif /* HAVE_FTRUNCATE */ + +static PyObject * +file_tell(PyFileObject *f) +{ + Py_off_t pos; + + if (f->f_fp == NULL) + return err_closed(); + Py_BEGIN_ALLOW_THREADS + errno = 0; + pos = _portable_ftell(f->f_fp); + Py_END_ALLOW_THREADS + if (pos == -1) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + return NULL; + } + if (f->f_skipnextlf) { + int c; + c = GETC(f->f_fp); + if (c == '\n') { + pos++; + f->f_skipnextlf = 0; + } else if (c != EOF) ungetc(c, f->f_fp); + } +#if !defined(HAVE_LARGEFILE_SUPPORT) + return PyInt_FromLong(pos); +#else + return PyLong_FromLongLong(pos); +#endif +} + +static PyObject * +file_fileno(PyFileObject *f) +{ + if (f->f_fp == NULL) + return err_closed(); + return PyInt_FromLong((long) fileno(f->f_fp)); +} + +static PyObject * +file_flush(PyFileObject *f) +{ + int res; + + if (f->f_fp == NULL) + return err_closed(); + Py_BEGIN_ALLOW_THREADS + errno = 0; + res = fflush(f->f_fp); + Py_END_ALLOW_THREADS + if (res != 0) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +file_isatty(PyFileObject *f) +{ + long res; + if (f->f_fp == NULL) + return err_closed(); + Py_BEGIN_ALLOW_THREADS + res = isatty((int)fileno(f->f_fp)); + Py_END_ALLOW_THREADS + return PyBool_FromLong(res); +} + + +#if BUFSIZ < 8192 +#define SMALLCHUNK 8192 +#else +#define SMALLCHUNK BUFSIZ +#endif + +#if SIZEOF_INT < 4 +#define BIGCHUNK (512 * 32) +#else +#define BIGCHUNK (512 * 1024) +#endif + +static size_t +new_buffersize(PyFileObject *f, size_t currentsize) +{ +#ifdef HAVE_FSTAT + off_t pos, end; + struct stat st; + if (fstat(fileno(f->f_fp), &st) == 0) { + end = st.st_size; + /* The following is not a bug: we really need to call lseek() + *and* ftell(). The reason is that some stdio libraries + mistakenly flush their buffer when ftell() is called and + the lseek() call it makes fails, thereby throwing away + data that cannot be recovered in any way. To avoid this, + we first test lseek(), and only call ftell() if lseek() + works. We can't use the lseek() value either, because we + need to take the amount of buffered data into account. + (Yet another reason why stdio stinks. :-) */ + pos = lseek(fileno(f->f_fp), 0L, SEEK_CUR); + if (pos >= 0) { + pos = ftell(f->f_fp); + } + if (pos < 0) + clearerr(f->f_fp); + if (end > pos && pos >= 0) + return currentsize + end - pos + 1; + /* Add 1 so if the file were to grow we'd notice. */ + } +#endif + if (currentsize > SMALLCHUNK) { + /* Keep doubling until we reach BIGCHUNK; + then keep adding BIGCHUNK. */ + if (currentsize <= BIGCHUNK) + return currentsize + currentsize; + else + return currentsize + BIGCHUNK; + } + return currentsize + SMALLCHUNK; +} + +#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN +#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK || (x) == EAGAIN) +#else +#ifdef EWOULDBLOCK +#define BLOCKED_ERRNO(x) ((x) == EWOULDBLOCK) +#else +#ifdef EAGAIN +#define BLOCKED_ERRNO(x) ((x) == EAGAIN) +#else +#define BLOCKED_ERRNO(x) 0 +#endif +#endif +#endif + +static PyObject * +file_read(PyFileObject *f, PyObject *args) +{ + long bytesrequested = -1; + size_t bytesread, buffersize, chunksize; + PyObject *v; + + if (f->f_fp == NULL) + return err_closed(); + /* refuse to mix with f.next() */ + if (f->f_buf != NULL && + (f->f_bufend - f->f_bufptr) > 0 && + f->f_buf[0] != '\0') + return err_iterbuffered(); + if (!PyArg_ParseTuple(args, "|l:read", &bytesrequested)) + return NULL; + if (bytesrequested < 0) + buffersize = new_buffersize(f, (size_t)0); + else + buffersize = bytesrequested; + if (buffersize > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "requested number of bytes is more than a Python string can hold"); + return NULL; + } + v = PyString_FromStringAndSize((char *)NULL, buffersize); + if (v == NULL) + return NULL; + bytesread = 0; + for (;;) { + Py_BEGIN_ALLOW_THREADS + errno = 0; + chunksize = Py_UniversalNewlineFread(BUF(v) + bytesread, + buffersize - bytesread, f->f_fp, (PyObject *)f); + Py_END_ALLOW_THREADS + if (chunksize == 0) { + if (!ferror(f->f_fp)) + break; + clearerr(f->f_fp); + /* When in non-blocking mode, data shouldn't + * be discarded if a blocking signal was + * received. That will also happen if + * chunksize != 0, but bytesread < buffersize. */ + if (bytesread > 0 && BLOCKED_ERRNO(errno)) + break; + PyErr_SetFromErrno(PyExc_IOError); + Py_DECREF(v); + return NULL; + } + bytesread += chunksize; + if (bytesread < buffersize) { + clearerr(f->f_fp); + break; + } + if (bytesrequested < 0) { + buffersize = new_buffersize(f, buffersize); + if (_PyString_Resize(&v, buffersize) < 0) + return NULL; + } else { + /* Got what was requested. */ + break; + } + } + if (bytesread != buffersize) + _PyString_Resize(&v, bytesread); + return v; +} + +static PyObject * +file_readinto(PyFileObject *f, PyObject *args) +{ + char *ptr; + Py_ssize_t ntodo; + Py_ssize_t ndone, nnow; + + if (f->f_fp == NULL) + return err_closed(); + /* refuse to mix with f.next() */ + if (f->f_buf != NULL && + (f->f_bufend - f->f_bufptr) > 0 && + f->f_buf[0] != '\0') + return err_iterbuffered(); + if (!PyArg_ParseTuple(args, "w#", &ptr, &ntodo)) + return NULL; + ndone = 0; + while (ntodo > 0) { + Py_BEGIN_ALLOW_THREADS + errno = 0; + nnow = Py_UniversalNewlineFread(ptr+ndone, ntodo, f->f_fp, + (PyObject *)f); + Py_END_ALLOW_THREADS + if (nnow == 0) { + if (!ferror(f->f_fp)) + break; + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + return NULL; + } + ndone += nnow; + ntodo -= nnow; + } + return PyInt_FromSsize_t(ndone); +} + +/************************************************************************** +Routine to get next line using platform fgets(). + +Under MSVC 6: + ++ MS threadsafe getc is very slow (multiple layers of function calls before+ + after each character, to lock+unlock the stream). ++ The stream-locking functions are MS-internal -- can't access them from user + code. ++ There's nothing Tim could find in the MS C or platform SDK libraries that + can worm around this. ++ MS fgets locks/unlocks only once per line; it's the only hook we have. + +So we use fgets for speed(!), despite that it's painful. + +MS realloc is also slow. + +Reports from other platforms on this method vs getc_unlocked (which MS doesn't +have): + Linux a wash + Solaris a wash + Tru64 Unix getline_via_fgets significantly faster + +CAUTION: The C std isn't clear about this: in those cases where fgets +writes something into the buffer, can it write into any position beyond the +required trailing null byte? MSVC 6 fgets does not, and no platform is (yet) +known on which it does; and it would be a strange way to code fgets. Still, +getline_via_fgets may not work correctly if it does. The std test +test_bufio.py should fail if platform fgets() routinely writes beyond the +trailing null byte. #define DONT_USE_FGETS_IN_GETLINE to disable this code. +**************************************************************************/ + +/* Use this routine if told to, or by default on non-get_unlocked() + * platforms unless told not to. Yikes! Let's spell that out: + * On a platform with getc_unlocked(): + * By default, use getc_unlocked(). + * If you want to use fgets() instead, #define USE_FGETS_IN_GETLINE. + * On a platform without getc_unlocked(): + * By default, use fgets(). + * If you don't want to use fgets(), #define DONT_USE_FGETS_IN_GETLINE. + */ +#if !defined(USE_FGETS_IN_GETLINE) && !defined(HAVE_GETC_UNLOCKED) +#define USE_FGETS_IN_GETLINE +#endif + +#if defined(DONT_USE_FGETS_IN_GETLINE) && defined(USE_FGETS_IN_GETLINE) +#undef USE_FGETS_IN_GETLINE +#endif + +#ifdef USE_FGETS_IN_GETLINE +static PyObject* +getline_via_fgets(FILE *fp) +{ +/* INITBUFSIZE is the maximum line length that lets us get away with the fast + * no-realloc, one-fgets()-call path. Boosting it isn't free, because we have + * to fill this much of the buffer with a known value in order to figure out + * how much of the buffer fgets() overwrites. So if INITBUFSIZE is larger + * than "most" lines, we waste time filling unused buffer slots. 100 is + * surely adequate for most peoples' email archives, chewing over source code, + * etc -- "regular old text files". + * MAXBUFSIZE is the maximum line length that lets us get away with the less + * fast (but still zippy) no-realloc, two-fgets()-call path. See above for + * cautions about boosting that. 300 was chosen because the worst real-life + * text-crunching job reported on Python-Dev was a mail-log crawler where over + * half the lines were 254 chars. + */ +#define INITBUFSIZE 100 +#define MAXBUFSIZE 300 + char* p; /* temp */ + char buf[MAXBUFSIZE]; + PyObject* v; /* the string object result */ + char* pvfree; /* address of next free slot */ + char* pvend; /* address one beyond last free slot */ + size_t nfree; /* # of free buffer slots; pvend-pvfree */ + size_t total_v_size; /* total # of slots in buffer */ + size_t increment; /* amount to increment the buffer */ + size_t prev_v_size; + + /* Optimize for normal case: avoid _PyString_Resize if at all + * possible via first reading into stack buffer "buf". + */ + total_v_size = INITBUFSIZE; /* start small and pray */ + pvfree = buf; + for (;;) { + Py_BEGIN_ALLOW_THREADS + pvend = buf + total_v_size; + nfree = pvend - pvfree; + memset(pvfree, '\n', nfree); + assert(nfree < INT_MAX); /* Should be atmost MAXBUFSIZE */ + p = fgets(pvfree, (int)nfree, fp); + Py_END_ALLOW_THREADS + + if (p == NULL) { + clearerr(fp); + if (PyErr_CheckSignals()) + return NULL; + v = PyString_FromStringAndSize(buf, pvfree - buf); + return v; + } + /* fgets read *something* */ + p = memchr(pvfree, '\n', nfree); + if (p != NULL) { + /* Did the \n come from fgets or from us? + * Since fgets stops at the first \n, and then writes + * \0, if it's from fgets a \0 must be next. But if + * that's so, it could not have come from us, since + * the \n's we filled the buffer with have only more + * \n's to the right. + */ + if (p+1 < pvend && *(p+1) == '\0') { + /* It's from fgets: we win! In particular, + * we haven't done any mallocs yet, and can + * build the final result on the first try. + */ + ++p; /* include \n from fgets */ + } + else { + /* Must be from us: fgets didn't fill the + * buffer and didn't find a newline, so it + * must be the last and newline-free line of + * the file. + */ + assert(p > pvfree && *(p-1) == '\0'); + --p; /* don't include \0 from fgets */ + } + v = PyString_FromStringAndSize(buf, p - buf); + return v; + } + /* yuck: fgets overwrote all the newlines, i.e. the entire + * buffer. So this line isn't over yet, or maybe it is but + * we're exactly at EOF. If we haven't already, try using the + * rest of the stack buffer. + */ + assert(*(pvend-1) == '\0'); + if (pvfree == buf) { + pvfree = pvend - 1; /* overwrite trailing null */ + total_v_size = MAXBUFSIZE; + } + else + break; + } + + /* The stack buffer isn't big enough; malloc a string object and read + * into its buffer. + */ + total_v_size = MAXBUFSIZE << 1; + v = PyString_FromStringAndSize((char*)NULL, (int)total_v_size); + if (v == NULL) + return v; + /* copy over everything except the last null byte */ + memcpy(BUF(v), buf, MAXBUFSIZE-1); + pvfree = BUF(v) + MAXBUFSIZE - 1; + + /* Keep reading stuff into v; if it ever ends successfully, break + * after setting p one beyond the end of the line. The code here is + * very much like the code above, except reads into v's buffer; see + * the code above for detailed comments about the logic. + */ + for (;;) { + Py_BEGIN_ALLOW_THREADS + pvend = BUF(v) + total_v_size; + nfree = pvend - pvfree; + memset(pvfree, '\n', nfree); + assert(nfree < INT_MAX); + p = fgets(pvfree, (int)nfree, fp); + Py_END_ALLOW_THREADS + + if (p == NULL) { + clearerr(fp); + if (PyErr_CheckSignals()) { + Py_DECREF(v); + return NULL; + } + p = pvfree; + break; + } + p = memchr(pvfree, '\n', nfree); + if (p != NULL) { + if (p+1 < pvend && *(p+1) == '\0') { + /* \n came from fgets */ + ++p; + break; + } + /* \n came from us; last line of file, no newline */ + assert(p > pvfree && *(p-1) == '\0'); + --p; + break; + } + /* expand buffer and try again */ + assert(*(pvend-1) == '\0'); + increment = total_v_size >> 2; /* mild exponential growth */ + prev_v_size = total_v_size; + total_v_size += increment; + /* check for overflow */ + if (total_v_size <= prev_v_size || + total_v_size > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "line is longer than a Python string can hold"); + Py_DECREF(v); + return NULL; + } + if (_PyString_Resize(&v, (int)total_v_size) < 0) + return NULL; + /* overwrite the trailing null byte */ + pvfree = BUF(v) + (prev_v_size - 1); + } + if (BUF(v) + total_v_size != p) + _PyString_Resize(&v, p - BUF(v)); + return v; +#undef INITBUFSIZE +#undef MAXBUFSIZE +} +#endif /* ifdef USE_FGETS_IN_GETLINE */ + +/* Internal routine to get a line. + Size argument interpretation: + > 0: max length; + <= 0: read arbitrary line +*/ + +static PyObject * +get_line(PyFileObject *f, int n) +{ + FILE *fp = f->f_fp; + int c; + char *buf, *end; + size_t total_v_size; /* total # of slots in buffer */ + size_t used_v_size; /* # used slots in buffer */ + size_t increment; /* amount to increment the buffer */ + PyObject *v; + int newlinetypes = f->f_newlinetypes; + int skipnextlf = f->f_skipnextlf; + int univ_newline = f->f_univ_newline; + +#if defined(USE_FGETS_IN_GETLINE) + if (n <= 0 && !univ_newline ) + return getline_via_fgets(fp); +#endif + total_v_size = n > 0 ? n : 100; + v = PyString_FromStringAndSize((char *)NULL, total_v_size); + if (v == NULL) + return NULL; + buf = BUF(v); + end = buf + total_v_size; + + for (;;) { + Py_BEGIN_ALLOW_THREADS + FLOCKFILE(fp); + if (univ_newline) { + c = 'x'; /* Shut up gcc warning */ + while ( buf != end && (c = GETC(fp)) != EOF ) { + if (skipnextlf ) { + skipnextlf = 0; + if (c == '\n') { + /* Seeing a \n here with + * skipnextlf true means we + * saw a \r before. + */ + newlinetypes |= NEWLINE_CRLF; + c = GETC(fp); + if (c == EOF) break; + } else { + newlinetypes |= NEWLINE_CR; + } + } + if (c == '\r') { + skipnextlf = 1; + c = '\n'; + } else if ( c == '\n') + newlinetypes |= NEWLINE_LF; + *buf++ = c; + if (c == '\n') break; + } + if ( c == EOF && skipnextlf ) + newlinetypes |= NEWLINE_CR; + } else /* If not universal newlines use the normal loop */ + while ((c = GETC(fp)) != EOF && + (*buf++ = c) != '\n' && + buf != end) + ; + FUNLOCKFILE(fp); + Py_END_ALLOW_THREADS + f->f_newlinetypes = newlinetypes; + f->f_skipnextlf = skipnextlf; + if (c == '\n') + break; + if (c == EOF) { + if (ferror(fp)) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(fp); + Py_DECREF(v); + return NULL; + } + clearerr(fp); + if (PyErr_CheckSignals()) { + Py_DECREF(v); + return NULL; + } + break; + } + /* Must be because buf == end */ + if (n > 0) + break; + used_v_size = total_v_size; + increment = total_v_size >> 2; /* mild exponential growth */ + total_v_size += increment; + if (total_v_size > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "line is longer than a Python string can hold"); + Py_DECREF(v); + return NULL; + } + if (_PyString_Resize(&v, total_v_size) < 0) + return NULL; + buf = BUF(v) + used_v_size; + end = BUF(v) + total_v_size; + } + + used_v_size = buf - BUF(v); + if (used_v_size != total_v_size) + _PyString_Resize(&v, used_v_size); + return v; +} + +/* External C interface */ + +PyObject * +PyFile_GetLine(PyObject *f, int n) +{ + PyObject *result; + + if (f == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + if (PyFile_Check(f)) { + PyFileObject *fo = (PyFileObject *)f; + if (fo->f_fp == NULL) + return err_closed(); + /* refuse to mix with f.next() */ + if (fo->f_buf != NULL && + (fo->f_bufend - fo->f_bufptr) > 0 && + fo->f_buf[0] != '\0') + return err_iterbuffered(); + result = get_line(fo, n); + } + else { + PyObject *reader; + PyObject *args; + + reader = PyObject_GetAttrString(f, "readline"); + if (reader == NULL) + return NULL; + if (n <= 0) + args = PyTuple_New(0); + else + args = Py_BuildValue("(i)", n); + if (args == NULL) { + Py_DECREF(reader); + return NULL; + } + result = PyEval_CallObject(reader, args); + Py_DECREF(reader); + Py_DECREF(args); + if (result != NULL && !PyString_Check(result) && + !PyUnicode_Check(result)) { + Py_DECREF(result); + result = NULL; + PyErr_SetString(PyExc_TypeError, + "object.readline() returned non-string"); + } + } + + if (n < 0 && result != NULL && PyString_Check(result)) { + char *s = PyString_AS_STRING(result); + Py_ssize_t len = PyString_GET_SIZE(result); + if (len == 0) { + Py_DECREF(result); + result = NULL; + PyErr_SetString(PyExc_EOFError, + "EOF when reading a line"); + } + else if (s[len-1] == '\n') { + if (result->ob_refcnt == 1) + _PyString_Resize(&result, len-1); + else { + PyObject *v; + v = PyString_FromStringAndSize(s, len-1); + Py_DECREF(result); + result = v; + } + } + } +#ifdef Py_USING_UNICODE + if (n < 0 && result != NULL && PyUnicode_Check(result)) { + Py_UNICODE *s = PyUnicode_AS_UNICODE(result); + Py_ssize_t len = PyUnicode_GET_SIZE(result); + if (len == 0) { + Py_DECREF(result); + result = NULL; + PyErr_SetString(PyExc_EOFError, + "EOF when reading a line"); + } + else if (s[len-1] == '\n') { + if (result->ob_refcnt == 1) + PyUnicode_Resize(&result, len-1); + else { + PyObject *v; + v = PyUnicode_FromUnicode(s, len-1); + Py_DECREF(result); + result = v; + } + } + } +#endif + return result; +} + +/* Python method */ + +static PyObject * +file_readline(PyFileObject *f, PyObject *args) +{ + int n = -1; + + if (f->f_fp == NULL) + return err_closed(); + /* refuse to mix with f.next() */ + if (f->f_buf != NULL && + (f->f_bufend - f->f_bufptr) > 0 && + f->f_buf[0] != '\0') + return err_iterbuffered(); + if (!PyArg_ParseTuple(args, "|i:readline", &n)) + return NULL; + if (n == 0) + return PyString_FromString(""); + if (n < 0) + n = 0; + return get_line(f, n); +} + +static PyObject * +file_readlines(PyFileObject *f, PyObject *args) +{ + long sizehint = 0; + PyObject *list; + PyObject *line; + char small_buffer[SMALLCHUNK]; + char *buffer = small_buffer; + size_t buffersize = SMALLCHUNK; + PyObject *big_buffer = NULL; + size_t nfilled = 0; + size_t nread; + size_t totalread = 0; + char *p, *q, *end; + int err; + int shortread = 0; + + if (f->f_fp == NULL) + return err_closed(); + /* refuse to mix with f.next() */ + if (f->f_buf != NULL && + (f->f_bufend - f->f_bufptr) > 0 && + f->f_buf[0] != '\0') + return err_iterbuffered(); + if (!PyArg_ParseTuple(args, "|l:readlines", &sizehint)) + return NULL; + if ((list = PyList_New(0)) == NULL) + return NULL; + for (;;) { + if (shortread) + nread = 0; + else { + Py_BEGIN_ALLOW_THREADS + errno = 0; + nread = Py_UniversalNewlineFread(buffer+nfilled, + buffersize-nfilled, f->f_fp, (PyObject *)f); + Py_END_ALLOW_THREADS + shortread = (nread < buffersize-nfilled); + } + if (nread == 0) { + sizehint = 0; + if (!ferror(f->f_fp)) + break; + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + error: + Py_DECREF(list); + list = NULL; + goto cleanup; + } + totalread += nread; + p = (char *)memchr(buffer+nfilled, '\n', nread); + if (p == NULL) { + /* Need a larger buffer to fit this line */ + nfilled += nread; + buffersize *= 2; + if (buffersize > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "line is longer than a Python string can hold"); + goto error; + } + if (big_buffer == NULL) { + /* Create the big buffer */ + big_buffer = PyString_FromStringAndSize( + NULL, buffersize); + if (big_buffer == NULL) + goto error; + buffer = PyString_AS_STRING(big_buffer); + memcpy(buffer, small_buffer, nfilled); + } + else { + /* Grow the big buffer */ + if ( _PyString_Resize(&big_buffer, buffersize) < 0 ) + goto error; + buffer = PyString_AS_STRING(big_buffer); + } + continue; + } + end = buffer+nfilled+nread; + q = buffer; + do { + /* Process complete lines */ + p++; + line = PyString_FromStringAndSize(q, p-q); + if (line == NULL) + goto error; + err = PyList_Append(list, line); + Py_DECREF(line); + if (err != 0) + goto error; + q = p; + p = (char *)memchr(q, '\n', end-q); + } while (p != NULL); + /* Move the remaining incomplete line to the start */ + nfilled = end-q; + memmove(buffer, q, nfilled); + if (sizehint > 0) + if (totalread >= (size_t)sizehint) + break; + } + if (nfilled != 0) { + /* Partial last line */ + line = PyString_FromStringAndSize(buffer, nfilled); + if (line == NULL) + goto error; + if (sizehint > 0) { + /* Need to complete the last line */ + PyObject *rest = get_line(f, 0); + if (rest == NULL) { + Py_DECREF(line); + goto error; + } + PyString_Concat(&line, rest); + Py_DECREF(rest); + if (line == NULL) + goto error; + } + err = PyList_Append(list, line); + Py_DECREF(line); + if (err != 0) + goto error; + } + cleanup: + Py_XDECREF(big_buffer); + return list; +} + +static PyObject * +file_write(PyFileObject *f, PyObject *args) +{ + char *s; + Py_ssize_t n, n2; + if (f->f_fp == NULL) + return err_closed(); + if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n)) + return NULL; + f->f_softspace = 0; + Py_BEGIN_ALLOW_THREADS + errno = 0; + n2 = fwrite(s, 1, n, f->f_fp); + Py_END_ALLOW_THREADS + if (n2 != n) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +file_writelines(PyFileObject *f, PyObject *seq) +{ +#define CHUNKSIZE 1000 + PyObject *list, *line; + PyObject *it; /* iter(seq) */ + PyObject *result; + int index, islist; + Py_ssize_t i, j, nwritten, len; + + assert(seq != NULL); + if (f->f_fp == NULL) + return err_closed(); + + result = NULL; + list = NULL; + islist = PyList_Check(seq); + if (islist) + it = NULL; + else { + it = PyObject_GetIter(seq); + if (it == NULL) { + PyErr_SetString(PyExc_TypeError, + "writelines() requires an iterable argument"); + return NULL; + } + /* From here on, fail by going to error, to reclaim "it". */ + list = PyList_New(CHUNKSIZE); + if (list == NULL) + goto error; + } + + /* Strategy: slurp CHUNKSIZE lines into a private list, + checking that they are all strings, then write that list + without holding the interpreter lock, then come back for more. */ + for (index = 0; ; index += CHUNKSIZE) { + if (islist) { + Py_XDECREF(list); + list = PyList_GetSlice(seq, index, index+CHUNKSIZE); + if (list == NULL) + goto error; + j = PyList_GET_SIZE(list); + } + else { + for (j = 0; j < CHUNKSIZE; j++) { + line = PyIter_Next(it); + if (line == NULL) { + if (PyErr_Occurred()) + goto error; + break; + } + PyList_SetItem(list, j, line); + } + } + if (j == 0) + break; + + /* Check that all entries are indeed strings. If not, + apply the same rules as for file.write() and + convert the results to strings. This is slow, but + seems to be the only way since all conversion APIs + could potentially execute Python code. */ + for (i = 0; i < j; i++) { + PyObject *v = PyList_GET_ITEM(list, i); + if (!PyString_Check(v)) { + const char *buffer; + if (((f->f_binary && + PyObject_AsReadBuffer(v, + (const void**)&buffer, + &len)) || + PyObject_AsCharBuffer(v, + &buffer, + &len))) { + PyErr_SetString(PyExc_TypeError, + "writelines() argument must be a sequence of strings"); + goto error; + } + line = PyString_FromStringAndSize(buffer, + len); + if (line == NULL) + goto error; + Py_DECREF(v); + PyList_SET_ITEM(list, i, line); + } + } + + /* Since we are releasing the global lock, the + following code may *not* execute Python code. */ + Py_BEGIN_ALLOW_THREADS + f->f_softspace = 0; + errno = 0; + for (i = 0; i < j; i++) { + line = PyList_GET_ITEM(list, i); + len = PyString_GET_SIZE(line); + nwritten = fwrite(PyString_AS_STRING(line), + 1, len, f->f_fp); + if (nwritten != len) { + Py_BLOCK_THREADS + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + goto error; + } + } + Py_END_ALLOW_THREADS + + if (j < CHUNKSIZE) + break; + } + + Py_INCREF(Py_None); + result = Py_None; + error: + Py_XDECREF(list); + Py_XDECREF(it); + return result; +#undef CHUNKSIZE +} + +static PyObject * +file_self(PyFileObject *f) +{ + if (f->f_fp == NULL) + return err_closed(); + Py_INCREF(f); + return (PyObject *)f; +} + +static PyObject * +file_exit(PyFileObject *f, PyObject *args) +{ + PyObject *ret = file_close(f); + if (!ret) + /* If error occurred, pass through */ + return NULL; + Py_DECREF(ret); + /* We cannot return the result of close since a true + * value will be interpreted as "yes, swallow the + * exception if one was raised inside the with block". */ + Py_RETURN_NONE; +} + +PyDoc_STRVAR(readline_doc, +"readline([size]) -> next line from the file, as a string.\n" +"\n" +"Retain newline. A non-negative size argument limits the maximum\n" +"number of bytes to return (an incomplete line may be returned then).\n" +"Return an empty string at EOF."); + +PyDoc_STRVAR(read_doc, +"read([size]) -> read at most size bytes, returned as a string.\n" +"\n" +"If the size argument is negative or omitted, read until EOF is reached.\n" +"Notice that when in non-blocking mode, less data than what was requested\n" +"may be returned, even if no size parameter was given."); + +PyDoc_STRVAR(write_doc, +"write(str) -> None. Write string str to file.\n" +"\n" +"Note that due to buffering, flush() or close() may be needed before\n" +"the file on disk reflects the data written."); + +PyDoc_STRVAR(fileno_doc, +"fileno() -> integer \"file descriptor\".\n" +"\n" +"This is needed for lower-level file interfaces, such os.read()."); + +PyDoc_STRVAR(seek_doc, +"seek(offset[, whence]) -> None. Move to new file position.\n" +"\n" +"Argument offset is a byte count. Optional argument whence defaults to\n" +"0 (offset from start of file, offset should be >= 0); other values are 1\n" +"(move relative to current position, positive or negative), and 2 (move\n" +"relative to end of file, usually negative, although many platforms allow\n" +"seeking beyond the end of a file). If the file is opened in text mode,\n" +"only offsets returned by tell() are legal. Use of other offsets causes\n" +"undefined behavior." +"\n" +"Note that not all file objects are seekable."); + +#ifdef HAVE_FTRUNCATE +PyDoc_STRVAR(truncate_doc, +"truncate([size]) -> None. Truncate the file to at most size bytes.\n" +"\n" +"Size defaults to the current file position, as returned by tell()."); +#endif + +PyDoc_STRVAR(tell_doc, +"tell() -> current file position, an integer (may be a long integer)."); + +PyDoc_STRVAR(readinto_doc, +"readinto() -> Undocumented. Don't use this; it may go away."); + +PyDoc_STRVAR(readlines_doc, +"readlines([size]) -> list of strings, each a line from the file.\n" +"\n" +"Call readline() repeatedly and return a list of the lines so read.\n" +"The optional size argument, if given, is an approximate bound on the\n" +"total number of bytes in the lines returned."); + +PyDoc_STRVAR(xreadlines_doc, +"xreadlines() -> returns self.\n" +"\n" +"For backward compatibility. File objects now include the performance\n" +"optimizations previously implemented in the xreadlines module."); + +PyDoc_STRVAR(writelines_doc, +"writelines(sequence_of_strings) -> None. Write the strings to the file.\n" +"\n" +"Note that newlines are not added. The sequence can be any iterable object\n" +"producing strings. This is equivalent to calling write() for each string."); + +PyDoc_STRVAR(flush_doc, +"flush() -> None. Flush the internal I/O buffer."); + +PyDoc_STRVAR(close_doc, +"close() -> None or (perhaps) an integer. Close the file.\n" +"\n" +"Sets data attribute .closed to True. A closed file cannot be used for\n" +"further I/O operations. close() may be called more than once without\n" +"error. Some kinds of file objects (for example, opened by popen())\n" +"may return an exit status upon closing."); + +PyDoc_STRVAR(isatty_doc, +"isatty() -> true or false. True if the file is connected to a tty device."); + +PyDoc_STRVAR(enter_doc, + "__enter__() -> self."); + +PyDoc_STRVAR(exit_doc, + "__exit__(*excinfo) -> None. Closes the file."); + +static PyMethodDef file_methods[] = { + {"readline", (PyCFunction)file_readline, METH_VARARGS, readline_doc}, + {"read", (PyCFunction)file_read, METH_VARARGS, read_doc}, + {"write", (PyCFunction)file_write, METH_VARARGS, write_doc}, + {"fileno", (PyCFunction)file_fileno, METH_NOARGS, fileno_doc}, + {"seek", (PyCFunction)file_seek, METH_VARARGS, seek_doc}, +#ifdef HAVE_FTRUNCATE + {"truncate", (PyCFunction)file_truncate, METH_VARARGS, truncate_doc}, +#endif + {"tell", (PyCFunction)file_tell, METH_NOARGS, tell_doc}, + {"readinto", (PyCFunction)file_readinto, METH_VARARGS, readinto_doc}, + {"readlines", (PyCFunction)file_readlines,METH_VARARGS, readlines_doc}, + {"xreadlines",(PyCFunction)file_self, METH_NOARGS, xreadlines_doc}, + {"writelines",(PyCFunction)file_writelines, METH_O, writelines_doc}, + {"flush", (PyCFunction)file_flush, METH_NOARGS, flush_doc}, + {"close", (PyCFunction)file_close, METH_NOARGS, close_doc}, + {"isatty", (PyCFunction)file_isatty, METH_NOARGS, isatty_doc}, + {"__enter__", (PyCFunction)file_self, METH_NOARGS, enter_doc}, + {"__exit__", (PyCFunction)file_exit, METH_VARARGS, exit_doc}, + {NULL, NULL} /* sentinel */ +}; + +#define OFF(x) offsetof(PyFileObject, x) + +static PyMemberDef file_memberlist[] = { + {"softspace", T_INT, OFF(f_softspace), 0, + "flag indicating that a space needs to be printed; used by print"}, + {"mode", T_OBJECT, OFF(f_mode), RO, + "file mode ('r', 'U', 'w', 'a', possibly with 'b' or '+' added)"}, + {"name", T_OBJECT, OFF(f_name), RO, + "file name"}, + {"encoding", T_OBJECT, OFF(f_encoding), RO, + "file encoding"}, + /* getattr(f, "closed") is implemented without this table */ + {NULL} /* Sentinel */ +}; + +static PyObject * +get_closed(PyFileObject *f, void *closure) +{ + return PyBool_FromLong((long)(f->f_fp == 0)); +} +static PyObject * +get_newlines(PyFileObject *f, void *closure) +{ + switch (f->f_newlinetypes) { + case NEWLINE_UNKNOWN: + Py_INCREF(Py_None); + return Py_None; + case NEWLINE_CR: + return PyString_FromString("\r"); + case NEWLINE_LF: + return PyString_FromString("\n"); + case NEWLINE_CR|NEWLINE_LF: + return Py_BuildValue("(ss)", "\r", "\n"); + case NEWLINE_CRLF: + return PyString_FromString("\r\n"); + case NEWLINE_CR|NEWLINE_CRLF: + return Py_BuildValue("(ss)", "\r", "\r\n"); + case NEWLINE_LF|NEWLINE_CRLF: + return Py_BuildValue("(ss)", "\n", "\r\n"); + case NEWLINE_CR|NEWLINE_LF|NEWLINE_CRLF: + return Py_BuildValue("(sss)", "\r", "\n", "\r\n"); + default: + PyErr_Format(PyExc_SystemError, + "Unknown newlines value 0x%x\n", + f->f_newlinetypes); + return NULL; + } +} + +static PyGetSetDef file_getsetlist[] = { + {"closed", (getter)get_closed, NULL, "True if the file is closed"}, + {"newlines", (getter)get_newlines, NULL, + "end-of-line convention used in this file"}, + {0}, +}; + +static void +drop_readahead(PyFileObject *f) +{ + if (f->f_buf != NULL) { + PyMem_Free(f->f_buf); + f->f_buf = NULL; + } +} + +/* Make sure that file has a readahead buffer with at least one byte + (unless at EOF) and no more than bufsize. Returns negative value on + error, will set MemoryError if bufsize bytes cannot be allocated. */ +static int +readahead(PyFileObject *f, int bufsize) +{ + Py_ssize_t chunksize; + + if (f->f_buf != NULL) { + if( (f->f_bufend - f->f_bufptr) >= 1) + return 0; + else + drop_readahead(f); + } + if ((f->f_buf = (char *)PyMem_Malloc(bufsize)) == NULL) { + PyErr_NoMemory(); + return -1; + } + Py_BEGIN_ALLOW_THREADS + errno = 0; + chunksize = Py_UniversalNewlineFread( + f->f_buf, bufsize, f->f_fp, (PyObject *)f); + Py_END_ALLOW_THREADS + if (chunksize == 0) { + if (ferror(f->f_fp)) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(f->f_fp); + drop_readahead(f); + return -1; + } + } + f->f_bufptr = f->f_buf; + f->f_bufend = f->f_buf + chunksize; + return 0; +} + +/* Used by file_iternext. The returned string will start with 'skip' + uninitialized bytes followed by the remainder of the line. Don't be + horrified by the recursive call: maximum recursion depth is limited by + logarithmic buffer growth to about 50 even when reading a 1gb line. */ + +static PyStringObject * +readahead_get_line_skip(PyFileObject *f, int skip, int bufsize) +{ + PyStringObject* s; + char *bufptr; + char *buf; + Py_ssize_t len; + + if (f->f_buf == NULL) + if (readahead(f, bufsize) < 0) + return NULL; + + len = f->f_bufend - f->f_bufptr; + if (len == 0) + return (PyStringObject *) + PyString_FromStringAndSize(NULL, skip); + bufptr = (char *)memchr(f->f_bufptr, '\n', len); + if (bufptr != NULL) { + bufptr++; /* Count the '\n' */ + len = bufptr - f->f_bufptr; + s = (PyStringObject *) + PyString_FromStringAndSize(NULL, skip+len); + if (s == NULL) + return NULL; + memcpy(PyString_AS_STRING(s)+skip, f->f_bufptr, len); + f->f_bufptr = bufptr; + if (bufptr == f->f_bufend) + drop_readahead(f); + } else { + bufptr = f->f_bufptr; + buf = f->f_buf; + f->f_buf = NULL; /* Force new readahead buffer */ + assert(skip+len < INT_MAX); + s = readahead_get_line_skip( + f, (int)(skip+len), bufsize + (bufsize>>2) ); + if (s == NULL) { + PyMem_Free(buf); + return NULL; + } + memcpy(PyString_AS_STRING(s)+skip, bufptr, len); + PyMem_Free(buf); + } + return s; +} + +/* A larger buffer size may actually decrease performance. */ +#define READAHEAD_BUFSIZE 8192 + +static PyObject * +file_iternext(PyFileObject *f) +{ + PyStringObject* l; + + if (f->f_fp == NULL) + return err_closed(); + + l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE); + if (l == NULL || PyString_GET_SIZE(l) == 0) { + Py_XDECREF(l); + return NULL; + } + return (PyObject *)l; +} + + +static PyObject * +file_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *self; + static PyObject *not_yet_string; + + assert(type != NULL && type->tp_alloc != NULL); + + if (not_yet_string == NULL) { + not_yet_string = PyString_FromString("<uninitialized file>"); + if (not_yet_string == NULL) + return NULL; + } + + self = type->tp_alloc(type, 0); + if (self != NULL) { + /* Always fill in the name and mode, so that nobody else + needs to special-case NULLs there. */ + Py_INCREF(not_yet_string); + ((PyFileObject *)self)->f_name = not_yet_string; + Py_INCREF(not_yet_string); + ((PyFileObject *)self)->f_mode = not_yet_string; + Py_INCREF(Py_None); + ((PyFileObject *)self)->f_encoding = Py_None; + ((PyFileObject *)self)->weakreflist = NULL; + } + return self; +} + +static int +file_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyFileObject *foself = (PyFileObject *)self; + int ret = 0; + static char *kwlist[] = {"name", "mode", "buffering", 0}; + char *name = NULL; + char *mode = "r"; + int bufsize = -1; + int wideargument = 0; + + assert(PyFile_Check(self)); + if (foself->f_fp != NULL) { + /* Have to close the existing file first. */ + PyObject *closeresult = file_close(foself); + if (closeresult == NULL) + return -1; + Py_DECREF(closeresult); + } + +#ifdef Py_WIN_WIDE_FILENAMES + if (GetVersion() < 0x80000000) { /* On NT, so wide API available */ + PyObject *po; + if (PyArg_ParseTupleAndKeywords(args, kwds, "U|si:file", + kwlist, &po, &mode, &bufsize)) { + wideargument = 1; + if (fill_file_fields(foself, NULL, po, mode, + fclose) == NULL) + goto Error; + } else { + /* Drop the argument parsing error as narrow + strings are also valid. */ + PyErr_Clear(); + } + } +#endif + + if (!wideargument) { + PyObject *o_name; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "et|si:file", kwlist, + Py_FileSystemDefaultEncoding, + &name, + &mode, &bufsize)) + return -1; + + /* We parse again to get the name as a PyObject */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|si:file", + kwlist, &o_name, &mode, + &bufsize)) + goto Error; + + if (fill_file_fields(foself, NULL, o_name, mode, + fclose) == NULL) + goto Error; + } + if (open_the_file(foself, name, mode) == NULL) + goto Error; + foself->f_setbuf = NULL; + PyFile_SetBufSize(self, bufsize); + goto Done; + +Error: + ret = -1; + /* fall through */ +Done: + PyMem_Free(name); /* free the encoded string */ + return ret; +} + +PyDoc_VAR(file_doc) = +PyDoc_STR( +"file(name[, mode[, buffering]]) -> file object\n" +"\n" +"Open a file. The mode can be 'r', 'w' or 'a' for reading (default),\n" +"writing or appending. The file will be created if it doesn't exist\n" +"when opened for writing or appending; it will be truncated when\n" +"opened for writing. Add a 'b' to the mode for binary files.\n" +"Add a '+' to the mode to allow simultaneous reading and writing.\n" +"If the buffering argument is given, 0 means unbuffered, 1 means line\n" +"buffered, and larger numbers specify the buffer size.\n" +) +PyDoc_STR( +"Add a 'U' to mode to open the file for input with universal newline\n" +"support. Any line ending in the input file will be seen as a '\\n'\n" +"in Python. Also, a file so opened gains the attribute 'newlines';\n" +"the value for this attribute is one of None (no newline read yet),\n" +"'\\r', '\\n', '\\r\\n' or a tuple containing all the newline types seen.\n" +"\n" +"'U' cannot be combined with 'w' or '+' mode.\n" +); + +PyTypeObject PyFile_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "file", + sizeof(PyFileObject), + 0, + (destructor)file_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)file_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + /* softspace is writable: we must supply tp_setattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ + file_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyFileObject, weakreflist), /* tp_weaklistoffset */ + (getiterfunc)file_self, /* tp_iter */ + (iternextfunc)file_iternext, /* tp_iternext */ + file_methods, /* tp_methods */ + file_memberlist, /* tp_members */ + file_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + file_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + file_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + +/* Interface for the 'soft space' between print items. */ + +int +PyFile_SoftSpace(PyObject *f, int newflag) +{ + long oldflag = 0; + if (f == NULL) { + /* Do nothing */ + } + else if (PyFile_Check(f)) { + oldflag = ((PyFileObject *)f)->f_softspace; + ((PyFileObject *)f)->f_softspace = newflag; + } + else { + PyObject *v; + v = PyObject_GetAttrString(f, "softspace"); + if (v == NULL) + PyErr_Clear(); + else { + if (PyInt_Check(v)) + oldflag = PyInt_AsLong(v); + assert(oldflag < INT_MAX); + Py_DECREF(v); + } + v = PyInt_FromLong((long)newflag); + if (v == NULL) + PyErr_Clear(); + else { + if (PyObject_SetAttrString(f, "softspace", v) != 0) + PyErr_Clear(); + Py_DECREF(v); + } + } + return (int)oldflag; +} + +/* Interfaces to write objects/strings to file-like objects */ + +int +PyFile_WriteObject(PyObject *v, PyObject *f, int flags) +{ + PyObject *writer, *value, *args, *result; + if (f == NULL) { + PyErr_SetString(PyExc_TypeError, "writeobject with NULL file"); + return -1; + } + else if (PyFile_Check(f)) { + FILE *fp = PyFile_AsFile(f); +#ifdef Py_USING_UNICODE + PyObject *enc = ((PyFileObject*)f)->f_encoding; + int result; +#endif + if (fp == NULL) { + err_closed(); + return -1; + } +#ifdef Py_USING_UNICODE + if ((flags & Py_PRINT_RAW) && + PyUnicode_Check(v) && enc != Py_None) { + char *cenc = PyString_AS_STRING(enc); + value = PyUnicode_AsEncodedString(v, cenc, "strict"); + if (value == NULL) + return -1; + } else { + value = v; + Py_INCREF(value); + } + result = PyObject_Print(value, fp, flags); + Py_DECREF(value); + return result; +#else + return PyObject_Print(v, fp, flags); +#endif + } + writer = PyObject_GetAttrString(f, "write"); + if (writer == NULL) + return -1; + if (flags & Py_PRINT_RAW) { + if (PyUnicode_Check(v)) { + value = v; + Py_INCREF(value); + } else + value = PyObject_Str(v); + } + else + value = PyObject_Repr(v); + if (value == NULL) { + Py_DECREF(writer); + return -1; + } + args = PyTuple_Pack(1, value); + if (args == NULL) { + Py_DECREF(value); + Py_DECREF(writer); + return -1; + } + result = PyEval_CallObject(writer, args); + Py_DECREF(args); + Py_DECREF(value); + Py_DECREF(writer); + if (result == NULL) + return -1; + Py_DECREF(result); + return 0; +} + +int +PyFile_WriteString(const char *s, PyObject *f) +{ + if (f == NULL) { + /* Should be caused by a pre-existing error */ + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "null file for PyFile_WriteString"); + return -1; + } + else if (PyFile_Check(f)) { + FILE *fp = PyFile_AsFile(f); + if (fp == NULL) { + err_closed(); + return -1; + } + fputs(s, fp); + return 0; + } + else if (!PyErr_Occurred()) { + PyObject *v = PyString_FromString(s); + int err; + if (v == NULL) + return -1; + err = PyFile_WriteObject(v, f, Py_PRINT_RAW); + Py_DECREF(v); + return err; + } + else + return -1; +} + +/* Try to get a file-descriptor from a Python object. If the object + is an integer or long integer, its value is returned. If not, the + object's fileno() method is called if it exists; the method must return + an integer or long integer, which is returned as the file descriptor value. + -1 is returned on failure. +*/ + +int PyObject_AsFileDescriptor(PyObject *o) +{ + int fd; + PyObject *meth; + + if (PyInt_Check(o)) { + fd = PyInt_AsLong(o); + } + else if (PyLong_Check(o)) { + fd = PyLong_AsLong(o); + } + else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL) + { + PyObject *fno = PyEval_CallObject(meth, NULL); + Py_DECREF(meth); + if (fno == NULL) + return -1; + + if (PyInt_Check(fno)) { + fd = PyInt_AsLong(fno); + Py_DECREF(fno); + } + else if (PyLong_Check(fno)) { + fd = PyLong_AsLong(fno); + Py_DECREF(fno); + } + else { + PyErr_SetString(PyExc_TypeError, + "fileno() returned a non-integer"); + Py_DECREF(fno); + return -1; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "argument must be an int, or have a fileno() method."); + return -1; + } + + if (fd < 0) { + PyErr_Format(PyExc_ValueError, + "file descriptor cannot be a negative integer (%i)", + fd); + return -1; + } + return fd; +} + +/* From here on we need access to the real fgets and fread */ +#undef fgets +#undef fread + +/* +** Py_UniversalNewlineFgets is an fgets variation that understands +** all of \r, \n and \r\n conventions. +** The stream should be opened in binary mode. +** If fobj is NULL the routine always does newline conversion, and +** it may peek one char ahead to gobble the second char in \r\n. +** If fobj is non-NULL it must be a PyFileObject. In this case there +** is no readahead but in stead a flag is used to skip a following +** \n on the next read. Also, if the file is open in binary mode +** the whole conversion is skipped. Finally, the routine keeps track of +** the different types of newlines seen. +** Note that we need no error handling: fgets() treats error and eof +** identically. +*/ +char * +Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) +{ + char *p = buf; + int c; + int newlinetypes = 0; + int skipnextlf = 0; + int univ_newline = 1; + + if (fobj) { + if (!PyFile_Check(fobj)) { + errno = ENXIO; /* What can you do... */ + return NULL; + } + univ_newline = ((PyFileObject *)fobj)->f_univ_newline; + if ( !univ_newline ) + return fgets(buf, n, stream); + newlinetypes = ((PyFileObject *)fobj)->f_newlinetypes; + skipnextlf = ((PyFileObject *)fobj)->f_skipnextlf; + } + FLOCKFILE(stream); + c = 'x'; /* Shut up gcc warning */ + while (--n > 0 && (c = GETC(stream)) != EOF ) { + if (skipnextlf ) { + skipnextlf = 0; + if (c == '\n') { + /* Seeing a \n here with skipnextlf true + ** means we saw a \r before. + */ + newlinetypes |= NEWLINE_CRLF; + c = GETC(stream); + if (c == EOF) break; + } else { + /* + ** Note that c == EOF also brings us here, + ** so we're okay if the last char in the file + ** is a CR. + */ + newlinetypes |= NEWLINE_CR; + } + } + if (c == '\r') { + /* A \r is translated into a \n, and we skip + ** an adjacent \n, if any. We don't set the + ** newlinetypes flag until we've seen the next char. + */ + skipnextlf = 1; + c = '\n'; + } else if ( c == '\n') { + newlinetypes |= NEWLINE_LF; + } + *p++ = c; + if (c == '\n') break; + } + if ( c == EOF && skipnextlf ) + newlinetypes |= NEWLINE_CR; + FUNLOCKFILE(stream); + *p = '\0'; + if (fobj) { + ((PyFileObject *)fobj)->f_newlinetypes = newlinetypes; + ((PyFileObject *)fobj)->f_skipnextlf = skipnextlf; + } else if ( skipnextlf ) { + /* If we have no file object we cannot save the + ** skipnextlf flag. We have to readahead, which + ** will cause a pause if we're reading from an + ** interactive stream, but that is very unlikely + ** unless we're doing something silly like + ** execfile("/dev/tty"). + */ + c = GETC(stream); + if ( c != '\n' ) + ungetc(c, stream); + } + if (p == buf) + return NULL; + return buf; +} + +/* +** Py_UniversalNewlineFread is an fread variation that understands +** all of \r, \n and \r\n conventions. +** The stream should be opened in binary mode. +** fobj must be a PyFileObject. In this case there +** is no readahead but in stead a flag is used to skip a following +** \n on the next read. Also, if the file is open in binary mode +** the whole conversion is skipped. Finally, the routine keeps track of +** the different types of newlines seen. +*/ +size_t +Py_UniversalNewlineFread(char *buf, size_t n, + FILE *stream, PyObject *fobj) +{ + char *dst = buf; + PyFileObject *f = (PyFileObject *)fobj; + int newlinetypes, skipnextlf; + + assert(buf != NULL); + assert(stream != NULL); + + if (!fobj || !PyFile_Check(fobj)) { + errno = ENXIO; /* What can you do... */ + return 0; + } + if (!f->f_univ_newline) + return fread(buf, 1, n, stream); + newlinetypes = f->f_newlinetypes; + skipnextlf = f->f_skipnextlf; + /* Invariant: n is the number of bytes remaining to be filled + * in the buffer. + */ + while (n) { + size_t nread; + int shortread; + char *src = dst; + + nread = fread(dst, 1, n, stream); + assert(nread <= n); + if (nread == 0) + break; + + n -= nread; /* assuming 1 byte out for each in; will adjust */ + shortread = n != 0; /* true iff EOF or error */ + while (nread--) { + char c = *src++; + if (c == '\r') { + /* Save as LF and set flag to skip next LF. */ + *dst++ = '\n'; + skipnextlf = 1; + } + else if (skipnextlf && c == '\n') { + /* Skip LF, and remember we saw CR LF. */ + skipnextlf = 0; + newlinetypes |= NEWLINE_CRLF; + ++n; + } + else { + /* Normal char to be stored in buffer. Also + * update the newlinetypes flag if either this + * is an LF or the previous char was a CR. + */ + if (c == '\n') + newlinetypes |= NEWLINE_LF; + else if (skipnextlf) + newlinetypes |= NEWLINE_CR; + *dst++ = c; + skipnextlf = 0; + } + } + if (shortread) { + /* If this is EOF, update type flags. */ + if (skipnextlf && feof(stream)) + newlinetypes |= NEWLINE_CR; + break; + } + } + f->f_newlinetypes = newlinetypes; + f->f_skipnextlf = skipnextlf; + return dst - buf; +} + +#ifdef __cplusplus +} +#endif diff --git a/sys/src/cmd/python/Objects/floatobject.c b/sys/src/cmd/python/Objects/floatobject.c new file mode 100644 index 000000000..2087ceba8 --- /dev/null +++ b/sys/src/cmd/python/Objects/floatobject.c @@ -0,0 +1,1748 @@ + +/* Float object implementation */ + +/* XXX There should be overflow checks here, but it's hard to check + for any kind of float exception without losing portability. */ + +#include "Python.h" + +#include <ctype.h> + +#if !defined(__STDC__) +extern double fmod(double, double); +extern double pow(double, double); +#endif + +/* Special free list -- see comments for same code in intobject.c. */ +#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ +#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ +#define N_FLOATOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyFloatObject)) + +struct _floatblock { + struct _floatblock *next; + PyFloatObject objects[N_FLOATOBJECTS]; +}; + +typedef struct _floatblock PyFloatBlock; + +static PyFloatBlock *block_list = NULL; +static PyFloatObject *free_list = NULL; + +static PyFloatObject * +fill_free_list(void) +{ + PyFloatObject *p, *q; + /* XXX Float blocks escape the object heap. Use PyObject_MALLOC ??? */ + p = (PyFloatObject *) PyMem_MALLOC(sizeof(PyFloatBlock)); + if (p == NULL) + return (PyFloatObject *) PyErr_NoMemory(); + ((PyFloatBlock *)p)->next = block_list; + block_list = (PyFloatBlock *)p; + p = &((PyFloatBlock *)p)->objects[0]; + q = p + N_FLOATOBJECTS; + while (--q > p) + q->ob_type = (struct _typeobject *)(q-1); + q->ob_type = NULL; + return p + N_FLOATOBJECTS - 1; +} + +PyObject * +PyFloat_FromDouble(double fval) +{ + register PyFloatObject *op; + if (free_list == NULL) { + if ((free_list = fill_free_list()) == NULL) + return NULL; + } + /* Inline PyObject_New */ + op = free_list; + free_list = (PyFloatObject *)op->ob_type; + PyObject_INIT(op, &PyFloat_Type); + op->ob_fval = fval; + return (PyObject *) op; +} + +/************************************************************************** +RED_FLAG 22-Sep-2000 tim +PyFloat_FromString's pend argument is braindead. Prior to this RED_FLAG, + +1. If v was a regular string, *pend was set to point to its terminating + null byte. That's useless (the caller can find that without any + help from this function!). + +2. If v was a Unicode string, or an object convertible to a character + buffer, *pend was set to point into stack trash (the auto temp + vector holding the character buffer). That was downright dangerous. + +Since we can't change the interface of a public API function, pend is +still supported but now *officially* useless: if pend is not NULL, +*pend is set to NULL. +**************************************************************************/ +PyObject * +PyFloat_FromString(PyObject *v, char **pend) +{ + const char *s, *last, *end; + double x; + char buffer[256]; /* for errors */ +#ifdef Py_USING_UNICODE + char s_buffer[256]; /* for objects convertible to a char buffer */ +#endif + Py_ssize_t len; + + if (pend) + *pend = NULL; + if (PyString_Check(v)) { + s = PyString_AS_STRING(v); + len = PyString_GET_SIZE(v); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(v)) { + if (PyUnicode_GET_SIZE(v) >= (Py_ssize_t)sizeof(s_buffer)) { + PyErr_SetString(PyExc_ValueError, + "Unicode float() literal too long to convert"); + return NULL; + } + if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), + PyUnicode_GET_SIZE(v), + s_buffer, + NULL)) + return NULL; + s = s_buffer; + len = strlen(s); + } +#endif + else if (PyObject_AsCharBuffer(v, &s, &len)) { + PyErr_SetString(PyExc_TypeError, + "float() argument must be a string or a number"); + return NULL; + } + + last = s + len; + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (*s == '\0') { + PyErr_SetString(PyExc_ValueError, "empty string for float()"); + return NULL; + } + /* We don't care about overflow or underflow. If the platform supports + * them, infinities and signed zeroes (on underflow) are fine. + * However, strtod can return 0 for denormalized numbers, where atof + * does not. So (alas!) we special-case a zero result. Note that + * whether strtod sets errno on underflow is not defined, so we can't + * key off errno. + */ + PyFPE_START_PROTECT("strtod", return NULL) + x = PyOS_ascii_strtod(s, (char **)&end); + PyFPE_END_PROTECT(x) + errno = 0; + /* Believe it or not, Solaris 2.6 can move end *beyond* the null + byte at the end of the string, when the input is inf(inity). */ + if (end > last) + end = last; + if (end == s) { + PyOS_snprintf(buffer, sizeof(buffer), + "invalid literal for float(): %.200s", s); + PyErr_SetString(PyExc_ValueError, buffer); + return NULL; + } + /* Since end != s, the platform made *some* kind of sense out + of the input. Trust it. */ + while (*end && isspace(Py_CHARMASK(*end))) + end++; + if (*end != '\0') { + PyOS_snprintf(buffer, sizeof(buffer), + "invalid literal for float(): %.200s", s); + PyErr_SetString(PyExc_ValueError, buffer); + return NULL; + } + else if (end != last) { + PyErr_SetString(PyExc_ValueError, + "null byte in argument for float()"); + return NULL; + } + if (x == 0.0) { + /* See above -- may have been strtod being anal + about denorms. */ + PyFPE_START_PROTECT("atof", return NULL) + x = PyOS_ascii_atof(s); + PyFPE_END_PROTECT(x) + errno = 0; /* whether atof ever set errno is undefined */ + } + return PyFloat_FromDouble(x); +} + +static void +float_dealloc(PyFloatObject *op) +{ + if (PyFloat_CheckExact(op)) { + op->ob_type = (struct _typeobject *)free_list; + free_list = op; + } + else + op->ob_type->tp_free((PyObject *)op); +} + +double +PyFloat_AsDouble(PyObject *op) +{ + PyNumberMethods *nb; + PyFloatObject *fo; + double val; + + if (op && PyFloat_Check(op)) + return PyFloat_AS_DOUBLE((PyFloatObject*) op); + + if (op == NULL) { + PyErr_BadArgument(); + return -1; + } + + if ((nb = op->ob_type->tp_as_number) == NULL || nb->nb_float == NULL) { + PyErr_SetString(PyExc_TypeError, "a float is required"); + return -1; + } + + fo = (PyFloatObject*) (*nb->nb_float) (op); + if (fo == NULL) + return -1; + if (!PyFloat_Check(fo)) { + PyErr_SetString(PyExc_TypeError, + "nb_float should return float object"); + return -1; + } + + val = PyFloat_AS_DOUBLE(fo); + Py_DECREF(fo); + + return val; +} + +/* Methods */ + +static void +format_float(char *buf, size_t buflen, PyFloatObject *v, int precision) +{ + register char *cp; + char format[32]; + /* Subroutine for float_repr and float_print. + We want float numbers to be recognizable as such, + i.e., they should contain a decimal point or an exponent. + However, %g may print the number as an integer; + in such cases, we append ".0" to the string. */ + + assert(PyFloat_Check(v)); + PyOS_snprintf(format, 32, "%%.%ig", precision); + PyOS_ascii_formatd(buf, buflen, format, v->ob_fval); + cp = buf; + if (*cp == '-') + cp++; + for (; *cp != '\0'; cp++) { + /* Any non-digit means it's not an integer; + this takes care of NAN and INF as well. */ + if (!isdigit(Py_CHARMASK(*cp))) + break; + } + if (*cp == '\0') { + *cp++ = '.'; + *cp++ = '0'; + *cp++ = '\0'; + } +} + +/* XXX PyFloat_AsStringEx should not be a public API function (for one + XXX thing, its signature passes a buffer without a length; for another, + XXX it isn't useful outside this file). +*/ +void +PyFloat_AsStringEx(char *buf, PyFloatObject *v, int precision) +{ + format_float(buf, 100, v, precision); +} + +/* Macro and helper that convert PyObject obj to a C double and store + the value in dbl; this replaces the functionality of the coercion + slot function. If conversion to double raises an exception, obj is + set to NULL, and the function invoking this macro returns NULL. If + obj is not of float, int or long type, Py_NotImplemented is incref'ed, + stored in obj, and returned from the function invoking this macro. +*/ +#define CONVERT_TO_DOUBLE(obj, dbl) \ + if (PyFloat_Check(obj)) \ + dbl = PyFloat_AS_DOUBLE(obj); \ + else if (convert_to_double(&(obj), &(dbl)) < 0) \ + return obj; + +static int +convert_to_double(PyObject **v, double *dbl) +{ + register PyObject *obj = *v; + + if (PyInt_Check(obj)) { + *dbl = (double)PyInt_AS_LONG(obj); + } + else if (PyLong_Check(obj)) { + *dbl = PyLong_AsDouble(obj); + if (*dbl == -1.0 && PyErr_Occurred()) { + *v = NULL; + return -1; + } + } + else { + Py_INCREF(Py_NotImplemented); + *v = Py_NotImplemented; + return -1; + } + return 0; +} + +/* Precisions used by repr() and str(), respectively. + + The repr() precision (17 significant decimal digits) is the minimal number + that is guaranteed to have enough precision so that if the number is read + back in the exact same binary value is recreated. This is true for IEEE + floating point by design, and also happens to work for all other modern + hardware. + + The str() precision is chosen so that in most cases, the rounding noise + created by various operations is suppressed, while giving plenty of + precision for practical use. + +*/ + +#define PREC_REPR 17 +#define PREC_STR 12 + +/* XXX PyFloat_AsString and PyFloat_AsReprString should be deprecated: + XXX they pass a char buffer without passing a length. +*/ +void +PyFloat_AsString(char *buf, PyFloatObject *v) +{ + format_float(buf, 100, v, PREC_STR); +} + +void +PyFloat_AsReprString(char *buf, PyFloatObject *v) +{ + format_float(buf, 100, v, PREC_REPR); +} + +/* ARGSUSED */ +static int +float_print(PyFloatObject *v, FILE *fp, int flags) +{ + char buf[100]; + format_float(buf, sizeof(buf), v, + (flags & Py_PRINT_RAW) ? PREC_STR : PREC_REPR); + fputs(buf, fp); + return 0; +} + +static PyObject * +float_repr(PyFloatObject *v) +{ + char buf[100]; + format_float(buf, sizeof(buf), v, PREC_REPR); + return PyString_FromString(buf); +} + +static PyObject * +float_str(PyFloatObject *v) +{ + char buf[100]; + format_float(buf, sizeof(buf), v, PREC_STR); + return PyString_FromString(buf); +} + +/* Comparison is pretty much a nightmare. When comparing float to float, + * we do it as straightforwardly (and long-windedly) as conceivable, so + * that, e.g., Python x == y delivers the same result as the platform + * C x == y when x and/or y is a NaN. + * When mixing float with an integer type, there's no good *uniform* approach. + * Converting the double to an integer obviously doesn't work, since we + * may lose info from fractional bits. Converting the integer to a double + * also has two failure modes: (1) a long int may trigger overflow (too + * large to fit in the dynamic range of a C double); (2) even a C long may have + * more bits than fit in a C double (e.g., on a a 64-bit box long may have + * 63 bits of precision, but a C double probably has only 53), and then + * we can falsely claim equality when low-order integer bits are lost by + * coercion to double. So this part is painful too. + */ + +static PyObject* +float_richcompare(PyObject *v, PyObject *w, int op) +{ + double i, j; + int r = 0; + + assert(PyFloat_Check(v)); + i = PyFloat_AS_DOUBLE(v); + + /* Switch on the type of w. Set i and j to doubles to be compared, + * and op to the richcomp to use. + */ + if (PyFloat_Check(w)) + j = PyFloat_AS_DOUBLE(w); + + else if (!Py_IS_FINITE(i)) { + if (PyInt_Check(w) || PyLong_Check(w)) + /* If i is an infinity, its magnitude exceeds any + * finite integer, so it doesn't matter which int we + * compare i with. If i is a NaN, similarly. + */ + j = 0.0; + else + goto Unimplemented; + } + + else if (PyInt_Check(w)) { + long jj = PyInt_AS_LONG(w); + /* In the worst realistic case I can imagine, C double is a + * Cray single with 48 bits of precision, and long has 64 + * bits. + */ +#if SIZEOF_LONG > 6 + unsigned long abs = (unsigned long)(jj < 0 ? -jj : jj); + if (abs >> 48) { + /* Needs more than 48 bits. Make it take the + * PyLong path. + */ + PyObject *result; + PyObject *ww = PyLong_FromLong(jj); + + if (ww == NULL) + return NULL; + result = float_richcompare(v, ww, op); + Py_DECREF(ww); + return result; + } +#endif + j = (double)jj; + assert((long)j == jj); + } + + else if (PyLong_Check(w)) { + int vsign = i == 0.0 ? 0 : i < 0.0 ? -1 : 1; + int wsign = _PyLong_Sign(w); + size_t nbits; + int exponent; + + if (vsign != wsign) { + /* Magnitudes are irrelevant -- the signs alone + * determine the outcome. + */ + i = (double)vsign; + j = (double)wsign; + goto Compare; + } + /* The signs are the same. */ + /* Convert w to a double if it fits. In particular, 0 fits. */ + nbits = _PyLong_NumBits(w); + if (nbits == (size_t)-1 && PyErr_Occurred()) { + /* This long is so large that size_t isn't big enough + * to hold the # of bits. Replace with little doubles + * that give the same outcome -- w is so large that + * its magnitude must exceed the magnitude of any + * finite float. + */ + PyErr_Clear(); + i = (double)vsign; + assert(wsign != 0); + j = wsign * 2.0; + goto Compare; + } + if (nbits <= 48) { + j = PyLong_AsDouble(w); + /* It's impossible that <= 48 bits overflowed. */ + assert(j != -1.0 || ! PyErr_Occurred()); + goto Compare; + } + assert(wsign != 0); /* else nbits was 0 */ + assert(vsign != 0); /* if vsign were 0, then since wsign is + * not 0, we would have taken the + * vsign != wsign branch at the start */ + /* We want to work with non-negative numbers. */ + if (vsign < 0) { + /* "Multiply both sides" by -1; this also swaps the + * comparator. + */ + i = -i; + op = _Py_SwappedOp[op]; + } + assert(i > 0.0); + (void) frexp(i, &exponent); + /* exponent is the # of bits in v before the radix point; + * we know that nbits (the # of bits in w) > 48 at this point + */ + if (exponent < 0 || (size_t)exponent < nbits) { + i = 1.0; + j = 2.0; + goto Compare; + } + if ((size_t)exponent > nbits) { + i = 2.0; + j = 1.0; + goto Compare; + } + /* v and w have the same number of bits before the radix + * point. Construct two longs that have the same comparison + * outcome. + */ + { + double fracpart; + double intpart; + PyObject *result = NULL; + PyObject *one = NULL; + PyObject *vv = NULL; + PyObject *ww = w; + + if (wsign < 0) { + ww = PyNumber_Negative(w); + if (ww == NULL) + goto Error; + } + else + Py_INCREF(ww); + + fracpart = modf(i, &intpart); + vv = PyLong_FromDouble(intpart); + if (vv == NULL) + goto Error; + + if (fracpart != 0.0) { + /* Shift left, and or a 1 bit into vv + * to represent the lost fraction. + */ + PyObject *temp; + + one = PyInt_FromLong(1); + if (one == NULL) + goto Error; + + temp = PyNumber_Lshift(ww, one); + if (temp == NULL) + goto Error; + Py_DECREF(ww); + ww = temp; + + temp = PyNumber_Lshift(vv, one); + if (temp == NULL) + goto Error; + Py_DECREF(vv); + vv = temp; + + temp = PyNumber_Or(vv, one); + if (temp == NULL) + goto Error; + Py_DECREF(vv); + vv = temp; + } + + r = PyObject_RichCompareBool(vv, ww, op); + if (r < 0) + goto Error; + result = PyBool_FromLong(r); + Error: + Py_XDECREF(vv); + Py_XDECREF(ww); + Py_XDECREF(one); + return result; + } + } /* else if (PyLong_Check(w)) */ + + else /* w isn't float, int, or long */ + goto Unimplemented; + + Compare: + PyFPE_START_PROTECT("richcompare", return NULL) + switch (op) { + case Py_EQ: + r = i == j; + break; + case Py_NE: + r = i != j; + break; + case Py_LE: + r = i <= j; + break; + case Py_GE: + r = i >= j; + break; + case Py_LT: + r = i < j; + break; + case Py_GT: + r = i > j; + break; + } + PyFPE_END_PROTECT(r) + return PyBool_FromLong(r); + + Unimplemented: + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static long +float_hash(PyFloatObject *v) +{ + return _Py_HashDouble(v->ob_fval); +} + +static PyObject * +float_add(PyObject *v, PyObject *w) +{ + double a,b; + CONVERT_TO_DOUBLE(v, a); + CONVERT_TO_DOUBLE(w, b); + PyFPE_START_PROTECT("add", return 0) + a = a + b; + PyFPE_END_PROTECT(a) + return PyFloat_FromDouble(a); +} + +static PyObject * +float_sub(PyObject *v, PyObject *w) +{ + double a,b; + CONVERT_TO_DOUBLE(v, a); + CONVERT_TO_DOUBLE(w, b); + PyFPE_START_PROTECT("subtract", return 0) + a = a - b; + PyFPE_END_PROTECT(a) + return PyFloat_FromDouble(a); +} + +static PyObject * +float_mul(PyObject *v, PyObject *w) +{ + double a,b; + CONVERT_TO_DOUBLE(v, a); + CONVERT_TO_DOUBLE(w, b); + PyFPE_START_PROTECT("multiply", return 0) + a = a * b; + PyFPE_END_PROTECT(a) + return PyFloat_FromDouble(a); +} + +static PyObject * +float_div(PyObject *v, PyObject *w) +{ + double a,b; + CONVERT_TO_DOUBLE(v, a); + CONVERT_TO_DOUBLE(w, b); + if (b == 0.0) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + return NULL; + } + PyFPE_START_PROTECT("divide", return 0) + a = a / b; + PyFPE_END_PROTECT(a) + return PyFloat_FromDouble(a); +} + +static PyObject * +float_classic_div(PyObject *v, PyObject *w) +{ + double a,b; + CONVERT_TO_DOUBLE(v, a); + CONVERT_TO_DOUBLE(w, b); + if (Py_DivisionWarningFlag >= 2 && + PyErr_Warn(PyExc_DeprecationWarning, "classic float division") < 0) + return NULL; + if (b == 0.0) { + PyErr_SetString(PyExc_ZeroDivisionError, "float division"); + return NULL; + } + PyFPE_START_PROTECT("divide", return 0) + a = a / b; + PyFPE_END_PROTECT(a) + return PyFloat_FromDouble(a); +} + +static PyObject * +float_rem(PyObject *v, PyObject *w) +{ + double vx, wx; + double mod; + CONVERT_TO_DOUBLE(v, vx); + CONVERT_TO_DOUBLE(w, wx); + if (wx == 0.0) { + PyErr_SetString(PyExc_ZeroDivisionError, "float modulo"); + return NULL; + } + PyFPE_START_PROTECT("modulo", return 0) + mod = fmod(vx, wx); + /* note: checking mod*wx < 0 is incorrect -- underflows to + 0 if wx < sqrt(smallest nonzero double) */ + if (mod && ((wx < 0) != (mod < 0))) { + mod += wx; + } + PyFPE_END_PROTECT(mod) + return PyFloat_FromDouble(mod); +} + +static PyObject * +float_divmod(PyObject *v, PyObject *w) +{ + double vx, wx; + double div, mod, floordiv; + CONVERT_TO_DOUBLE(v, vx); + CONVERT_TO_DOUBLE(w, wx); + if (wx == 0.0) { + PyErr_SetString(PyExc_ZeroDivisionError, "float divmod()"); + return NULL; + } + PyFPE_START_PROTECT("divmod", return 0) + mod = fmod(vx, wx); + /* fmod is typically exact, so vx-mod is *mathematically* an + exact multiple of wx. But this is fp arithmetic, and fp + vx - mod is an approximation; the result is that div may + not be an exact integral value after the division, although + it will always be very close to one. + */ + div = (vx - mod) / wx; + if (mod) { + /* ensure the remainder has the same sign as the denominator */ + if ((wx < 0) != (mod < 0)) { + mod += wx; + div -= 1.0; + } + } + else { + /* the remainder is zero, and in the presence of signed zeroes + fmod returns different results across platforms; ensure + it has the same sign as the denominator; we'd like to do + "mod = wx * 0.0", but that may get optimized away */ + mod *= mod; /* hide "mod = +0" from optimizer */ + if (wx < 0.0) + mod = -mod; + } + /* snap quotient to nearest integral value */ + if (div) { + floordiv = floor(div); + if (div - floordiv > 0.5) + floordiv += 1.0; + } + else { + /* div is zero - get the same sign as the true quotient */ + div *= div; /* hide "div = +0" from optimizers */ + floordiv = div * vx / wx; /* zero w/ sign of vx/wx */ + } + PyFPE_END_PROTECT(floordiv) + return Py_BuildValue("(dd)", floordiv, mod); +} + +static PyObject * +float_floor_div(PyObject *v, PyObject *w) +{ + PyObject *t, *r; + + t = float_divmod(v, w); + if (t == NULL || t == Py_NotImplemented) + return t; + assert(PyTuple_CheckExact(t)); + r = PyTuple_GET_ITEM(t, 0); + Py_INCREF(r); + Py_DECREF(t); + return r; +} + +static PyObject * +float_pow(PyObject *v, PyObject *w, PyObject *z) +{ + double iv, iw, ix; + + if ((PyObject *)z != Py_None) { + PyErr_SetString(PyExc_TypeError, "pow() 3rd argument not " + "allowed unless all arguments are integers"); + return NULL; + } + + CONVERT_TO_DOUBLE(v, iv); + CONVERT_TO_DOUBLE(w, iw); + + /* Sort out special cases here instead of relying on pow() */ + if (iw == 0) { /* v**0 is 1, even 0**0 */ + PyFPE_START_PROTECT("pow", return NULL) + if ((PyObject *)z != Py_None) { + double iz; + CONVERT_TO_DOUBLE(z, iz); + ix = fmod(1.0, iz); + if (ix != 0 && iz < 0) + ix += iz; + } + else + ix = 1.0; + PyFPE_END_PROTECT(ix) + return PyFloat_FromDouble(ix); + } + if (iv == 0.0) { /* 0**w is error if w<0, else 1 */ + if (iw < 0.0) { + PyErr_SetString(PyExc_ZeroDivisionError, + "0.0 cannot be raised to a negative power"); + return NULL; + } + return PyFloat_FromDouble(0.0); + } + if (iv < 0.0) { + /* Whether this is an error is a mess, and bumps into libm + * bugs so we have to figure it out ourselves. + */ + if (iw != floor(iw)) { + PyErr_SetString(PyExc_ValueError, "negative number " + "cannot be raised to a fractional power"); + return NULL; + } + /* iw is an exact integer, albeit perhaps a very large one. + * -1 raised to an exact integer should never be exceptional. + * Alas, some libms (chiefly glibc as of early 2003) return + * NaN and set EDOM on pow(-1, large_int) if the int doesn't + * happen to be representable in a *C* integer. That's a + * bug; we let that slide in math.pow() (which currently + * reflects all platform accidents), but not for Python's **. + */ + if (iv == -1.0 && Py_IS_FINITE(iw)) { + /* Return 1 if iw is even, -1 if iw is odd; there's + * no guarantee that any C integral type is big + * enough to hold iw, so we have to check this + * indirectly. + */ + ix = floor(iw * 0.5) * 2.0; + return PyFloat_FromDouble(ix == iw ? 1.0 : -1.0); + } + /* Else iv != -1.0, and overflow or underflow are possible. + * Unless we're to write pow() ourselves, we have to trust + * the platform to do this correctly. + */ + } + errno = 0; + PyFPE_START_PROTECT("pow", return NULL) + ix = pow(iv, iw); + PyFPE_END_PROTECT(ix) + Py_ADJUST_ERANGE1(ix); + if (errno != 0) { + /* We don't expect any errno value other than ERANGE, but + * the range of libm bugs appears unbounded. + */ + PyErr_SetFromErrno(errno == ERANGE ? PyExc_OverflowError : + PyExc_ValueError); + return NULL; + } + return PyFloat_FromDouble(ix); +} + +static PyObject * +float_neg(PyFloatObject *v) +{ + return PyFloat_FromDouble(-v->ob_fval); +} + +static PyObject * +float_pos(PyFloatObject *v) +{ + if (PyFloat_CheckExact(v)) { + Py_INCREF(v); + return (PyObject *)v; + } + else + return PyFloat_FromDouble(v->ob_fval); +} + +static PyObject * +float_abs(PyFloatObject *v) +{ + return PyFloat_FromDouble(fabs(v->ob_fval)); +} + +static int +float_nonzero(PyFloatObject *v) +{ + return v->ob_fval != 0.0; +} + +static int +float_coerce(PyObject **pv, PyObject **pw) +{ + if (PyInt_Check(*pw)) { + long x = PyInt_AsLong(*pw); + *pw = PyFloat_FromDouble((double)x); + Py_INCREF(*pv); + return 0; + } + else if (PyLong_Check(*pw)) { + double x = PyLong_AsDouble(*pw); + if (x == -1.0 && PyErr_Occurred()) + return -1; + *pw = PyFloat_FromDouble(x); + Py_INCREF(*pv); + return 0; + } + else if (PyFloat_Check(*pw)) { + Py_INCREF(*pv); + Py_INCREF(*pw); + return 0; + } + return 1; /* Can't do it */ +} + +static PyObject * +float_long(PyObject *v) +{ + double x = PyFloat_AsDouble(v); + return PyLong_FromDouble(x); +} + +static PyObject * +float_int(PyObject *v) +{ + double x = PyFloat_AsDouble(v); + double wholepart; /* integral portion of x, rounded toward 0 */ + + (void)modf(x, &wholepart); + /* Try to get out cheap if this fits in a Python int. The attempt + * to cast to long must be protected, as C doesn't define what + * happens if the double is too big to fit in a long. Some rare + * systems raise an exception then (RISCOS was mentioned as one, + * and someone using a non-default option on Sun also bumped into + * that). Note that checking for >= and <= LONG_{MIN,MAX} would + * still be vulnerable: if a long has more bits of precision than + * a double, casting MIN/MAX to double may yield an approximation, + * and if that's rounded up, then, e.g., wholepart=LONG_MAX+1 would + * yield true from the C expression wholepart<=LONG_MAX, despite + * that wholepart is actually greater than LONG_MAX. + */ + if (LONG_MIN < wholepart && wholepart < LONG_MAX) { + const long aslong = (long)wholepart; + return PyInt_FromLong(aslong); + } + return PyLong_FromDouble(wholepart); +} + +static PyObject * +float_float(PyObject *v) +{ + if (PyFloat_CheckExact(v)) + Py_INCREF(v); + else + v = PyFloat_FromDouble(((PyFloatObject *)v)->ob_fval); + return v; +} + + +static PyObject * +float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static PyObject * +float_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *x = Py_False; /* Integer zero */ + static char *kwlist[] = {"x", 0}; + + if (type != &PyFloat_Type) + return float_subtype_new(type, args, kwds); /* Wimp out */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:float", kwlist, &x)) + return NULL; + if (PyString_Check(x)) + return PyFloat_FromString(x, NULL); + return PyNumber_Float(x); +} + +/* Wimpy, slow approach to tp_new calls for subtypes of float: + first create a regular float from whatever arguments we got, + then allocate a subtype instance and initialize its ob_fval + from the regular float. The regular float is then thrown away. +*/ +static PyObject * +float_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *tmp, *newobj; + + assert(PyType_IsSubtype(type, &PyFloat_Type)); + tmp = float_new(&PyFloat_Type, args, kwds); + if (tmp == NULL) + return NULL; + assert(PyFloat_CheckExact(tmp)); + newobj = type->tp_alloc(type, 0); + if (newobj == NULL) { + Py_DECREF(tmp); + return NULL; + } + ((PyFloatObject *)newobj)->ob_fval = ((PyFloatObject *)tmp)->ob_fval; + Py_DECREF(tmp); + return newobj; +} + +static PyObject * +float_getnewargs(PyFloatObject *v) +{ + return Py_BuildValue("(d)", v->ob_fval); +} + +/* this is for the benefit of the pack/unpack routines below */ + +typedef enum { + unknown_format, ieee_big_endian_format, ieee_little_endian_format +} float_format_type; + +static float_format_type double_format, float_format; +static float_format_type detected_double_format, detected_float_format; + +static PyObject * +float_getformat(PyTypeObject *v, PyObject* arg) +{ + char* s; + float_format_type r; + + if (!PyString_Check(arg)) { + PyErr_Format(PyExc_TypeError, + "__getformat__() argument must be string, not %.500s", + arg->ob_type->tp_name); + return NULL; + } + s = PyString_AS_STRING(arg); + if (strcmp(s, "double") == 0) { + r = double_format; + } + else if (strcmp(s, "float") == 0) { + r = float_format; + } + else { + PyErr_SetString(PyExc_ValueError, + "__getformat__() argument 1 must be " + "'double' or 'float'"); + return NULL; + } + + switch (r) { + case unknown_format: + return PyString_FromString("unknown"); + case ieee_little_endian_format: + return PyString_FromString("IEEE, little-endian"); + case ieee_big_endian_format: + return PyString_FromString("IEEE, big-endian"); + default: + Py_FatalError("insane float_format or double_format"); + return NULL; + } +} + +PyDoc_STRVAR(float_getformat_doc, +"float.__getformat__(tstr) -> string\n" +"\n" +"You probably don't want to use this function. It exists mainly to be\n" +"used in Python's test suite.\n" +"\n" +"tstr must be 'double' or 'float'. This function returns whichever of\n" +"'unknown', 'IEEE, big-endian' or 'IEEE, little-endian' best describes the\n" +"format of floating point numbers used by the C type named by tstr."); + +static PyObject * +float_setformat(PyTypeObject *v, PyObject* args) +{ + char* tstr; + char* format; + float_format_type f; + float_format_type detected; + float_format_type *p; + + if (!PyArg_ParseTuple(args, "ss:__setformat__", &tstr, &format)) + return NULL; + + if (strcmp(tstr, "double") == 0) { + p = &double_format; + detected = detected_double_format; + } + else if (strcmp(tstr, "float") == 0) { + p = &float_format; + detected = detected_float_format; + } + else { + PyErr_SetString(PyExc_ValueError, + "__setformat__() argument 1 must " + "be 'double' or 'float'"); + return NULL; + } + + if (strcmp(format, "unknown") == 0) { + f = unknown_format; + } + else if (strcmp(format, "IEEE, little-endian") == 0) { + f = ieee_little_endian_format; + } + else if (strcmp(format, "IEEE, big-endian") == 0) { + f = ieee_big_endian_format; + } + else { + PyErr_SetString(PyExc_ValueError, + "__setformat__() argument 2 must be " + "'unknown', 'IEEE, little-endian' or " + "'IEEE, big-endian'"); + return NULL; + + } + + if (f != unknown_format && f != detected) { + PyErr_Format(PyExc_ValueError, + "can only set %s format to 'unknown' or the " + "detected platform value", tstr); + return NULL; + } + + *p = f; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(float_setformat_doc, +"float.__setformat__(tstr, fmt) -> None\n" +"\n" +"You probably don't want to use this function. It exists mainly to be\n" +"used in Python's test suite.\n" +"\n" +"tstr must be 'double' or 'float'. fmt must be one of 'unknown',\n" +"'IEEE, big-endian' or 'IEEE, little-endian', and in addition can only be\n" +"one of the latter two if it appears to match the underlying C reality.\n" +"\n" +"Overrides the automatic determination of C-level floating point type.\n" +"This affects how floats are converted to and from binary strings."); + +static PyMethodDef float_methods[] = { + {"__getnewargs__", (PyCFunction)float_getnewargs, METH_NOARGS}, + {"__getformat__", (PyCFunction)float_getformat, + METH_O|METH_CLASS, float_getformat_doc}, + {"__setformat__", (PyCFunction)float_setformat, + METH_VARARGS|METH_CLASS, float_setformat_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(float_doc, +"float(x) -> floating point number\n\ +\n\ +Convert a string or number to a floating point number, if possible."); + + +static PyNumberMethods float_as_number = { + float_add, /*nb_add*/ + float_sub, /*nb_subtract*/ + float_mul, /*nb_multiply*/ + float_classic_div, /*nb_divide*/ + float_rem, /*nb_remainder*/ + float_divmod, /*nb_divmod*/ + float_pow, /*nb_power*/ + (unaryfunc)float_neg, /*nb_negative*/ + (unaryfunc)float_pos, /*nb_positive*/ + (unaryfunc)float_abs, /*nb_absolute*/ + (inquiry)float_nonzero, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + 0, /*nb_and*/ + 0, /*nb_xor*/ + 0, /*nb_or*/ + float_coerce, /*nb_coerce*/ + float_int, /*nb_int*/ + float_long, /*nb_long*/ + float_float, /*nb_float*/ + 0, /* nb_oct */ + 0, /* nb_hex */ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_divide */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + float_floor_div, /* nb_floor_divide */ + float_div, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ +}; + +PyTypeObject PyFloat_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "float", + sizeof(PyFloatObject), + 0, + (destructor)float_dealloc, /* tp_dealloc */ + (printfunc)float_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)float_repr, /* tp_repr */ + &float_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)float_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)float_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + float_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + float_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + float_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + float_new, /* tp_new */ +}; + +void +_PyFloat_Init(void) +{ + /* We attempt to determine if this machine is using IEEE + floating point formats by peering at the bits of some + carefully chosen values. If it looks like we are on an + IEEE platform, the float packing/unpacking routines can + just copy bits, if not they resort to arithmetic & shifts + and masks. The shifts & masks approach works on all finite + values, but what happens to infinities, NaNs and signed + zeroes on packing is an accident, and attempting to unpack + a NaN or an infinity will raise an exception. + + Note that if we're on some whacked-out platform which uses + IEEE formats but isn't strictly little-endian or big- + endian, we will fall back to the portable shifts & masks + method. */ + +#if SIZEOF_DOUBLE == 8 + { + double x = 9006104071832581.0; + if (memcmp(&x, "\x43\x3f\xff\x01\x02\x03\x04\x05", 8) == 0) + detected_double_format = ieee_big_endian_format; + else if (memcmp(&x, "\x05\x04\x03\x02\x01\xff\x3f\x43", 8) == 0) + detected_double_format = ieee_little_endian_format; + else + detected_double_format = unknown_format; + } +#else + detected_double_format = unknown_format; +#endif + +#if SIZEOF_FLOAT == 4 + { + float y = 16711938.0; + if (memcmp(&y, "\x4b\x7f\x01\x02", 4) == 0) + detected_float_format = ieee_big_endian_format; + else if (memcmp(&y, "\x02\x01\x7f\x4b", 4) == 0) + detected_float_format = ieee_little_endian_format; + else + detected_float_format = unknown_format; + } +#else + detected_float_format = unknown_format; +#endif + + double_format = detected_double_format; + float_format = detected_float_format; +} + +void +PyFloat_Fini(void) +{ + PyFloatObject *p; + PyFloatBlock *list, *next; + unsigned i; + int bc, bf; /* block count, number of freed blocks */ + int frem, fsum; /* remaining unfreed floats per block, total */ + + bc = 0; + bf = 0; + fsum = 0; + list = block_list; + block_list = NULL; + free_list = NULL; + while (list != NULL) { + bc++; + frem = 0; + for (i = 0, p = &list->objects[0]; + i < N_FLOATOBJECTS; + i++, p++) { + if (PyFloat_CheckExact(p) && p->ob_refcnt != 0) + frem++; + } + next = list->next; + if (frem) { + list->next = block_list; + block_list = list; + for (i = 0, p = &list->objects[0]; + i < N_FLOATOBJECTS; + i++, p++) { + if (!PyFloat_CheckExact(p) || + p->ob_refcnt == 0) { + p->ob_type = (struct _typeobject *) + free_list; + free_list = p; + } + } + } + else { + PyMem_FREE(list); /* XXX PyObject_FREE ??? */ + bf++; + } + fsum += frem; + list = next; + } + if (!Py_VerboseFlag) + return; + fprintf(stderr, "# cleanup floats"); + if (!fsum) { + fprintf(stderr, "\n"); + } + else { + fprintf(stderr, + ": %d unfreed float%s in %d out of %d block%s\n", + fsum, fsum == 1 ? "" : "s", + bc - bf, bc, bc == 1 ? "" : "s"); + } + if (Py_VerboseFlag > 1) { + list = block_list; + while (list != NULL) { + for (i = 0, p = &list->objects[0]; + i < N_FLOATOBJECTS; + i++, p++) { + if (PyFloat_CheckExact(p) && + p->ob_refcnt != 0) { + char buf[100]; + PyFloat_AsString(buf, p); + /* XXX(twouters) cast refcount to + long until %zd is universally + available + */ + fprintf(stderr, + "# <float at %p, refcnt=%ld, val=%s>\n", + p, (long)p->ob_refcnt, buf); + } + } + list = list->next; + } + } +} + +/*---------------------------------------------------------------------------- + * _PyFloat_{Pack,Unpack}{4,8}. See floatobject.h. + * + * TODO: On platforms that use the standard IEEE-754 single and double + * formats natively, these routines could simply copy the bytes. + */ +int +_PyFloat_Pack4(double x, unsigned char *p, int le) +{ + if (float_format == unknown_format) { + unsigned char sign; + int e; + double f; + unsigned int fbits; + int incr = 1; + + if (le) { + p += 3; + incr = -1; + } + + if (x < 0) { + sign = 1; + x = -x; + } + else + sign = 0; + + f = frexp(x, &e); + + /* Normalize f to be in the range [1.0, 2.0) */ + if (0.5 <= f && f < 1.0) { + f *= 2.0; + e--; + } + else if (f == 0.0) + e = 0; + else { + PyErr_SetString(PyExc_SystemError, + "frexp() result out of range"); + return -1; + } + + if (e >= 128) + goto Overflow; + else if (e < -126) { + /* Gradual underflow */ + f = ldexp(f, 126 + e); + e = 0; + } + else if (!(e == 0 && f == 0.0)) { + e += 127; + f -= 1.0; /* Get rid of leading 1 */ + } + + f *= 8388608.0; /* 2**23 */ + fbits = (unsigned int)(f + 0.5); /* Round */ + assert(fbits <= 8388608); + if (fbits >> 23) { + /* The carry propagated out of a string of 23 1 bits. */ + fbits = 0; + ++e; + if (e >= 255) + goto Overflow; + } + + /* First byte */ + *p = (sign << 7) | (e >> 1); + p += incr; + + /* Second byte */ + *p = (char) (((e & 1) << 7) | (fbits >> 16)); + p += incr; + + /* Third byte */ + *p = (fbits >> 8) & 0xFF; + p += incr; + + /* Fourth byte */ + *p = fbits & 0xFF; + + /* Done */ + return 0; + + Overflow: + PyErr_SetString(PyExc_OverflowError, + "float too large to pack with f format"); + return -1; + } + else { + float y = (float)x; + const char *s = (char*)&y; + int i, incr = 1; + + if ((float_format == ieee_little_endian_format && !le) + || (float_format == ieee_big_endian_format && le)) { + p += 3; + incr = -1; + } + + for (i = 0; i < 4; i++) { + *p = *s++; + p += incr; + } + return 0; + } +} + +int +_PyFloat_Pack8(double x, unsigned char *p, int le) +{ + if (double_format == unknown_format) { + unsigned char sign; + int e; + double f; + unsigned int fhi, flo; + int incr = 1; + + if (le) { + p += 7; + incr = -1; + } + + if (x < 0) { + sign = 1; + x = -x; + } + else + sign = 0; + + f = frexp(x, &e); + + /* Normalize f to be in the range [1.0, 2.0) */ + if (0.5 <= f && f < 1.0) { + f *= 2.0; + e--; + } + else if (f == 0.0) + e = 0; + else { + PyErr_SetString(PyExc_SystemError, + "frexp() result out of range"); + return -1; + } + + if (e >= 1024) + goto Overflow; + else if (e < -1022) { + /* Gradual underflow */ + f = ldexp(f, 1022 + e); + e = 0; + } + else if (!(e == 0 && f == 0.0)) { + e += 1023; + f -= 1.0; /* Get rid of leading 1 */ + } + + /* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */ + f *= 268435456.0; /* 2**28 */ + fhi = (unsigned int)f; /* Truncate */ + assert(fhi < 268435456); + + f -= (double)fhi; + f *= 16777216.0; /* 2**24 */ + flo = (unsigned int)(f + 0.5); /* Round */ + assert(flo <= 16777216); + if (flo >> 24) { + /* The carry propagated out of a string of 24 1 bits. */ + flo = 0; + ++fhi; + if (fhi >> 28) { + /* And it also progagated out of the next 28 bits. */ + fhi = 0; + ++e; + if (e >= 2047) + goto Overflow; + } + } + + /* First byte */ + *p = (sign << 7) | (e >> 4); + p += incr; + + /* Second byte */ + *p = (unsigned char) (((e & 0xF) << 4) | (fhi >> 24)); + p += incr; + + /* Third byte */ + *p = (fhi >> 16) & 0xFF; + p += incr; + + /* Fourth byte */ + *p = (fhi >> 8) & 0xFF; + p += incr; + + /* Fifth byte */ + *p = fhi & 0xFF; + p += incr; + + /* Sixth byte */ + *p = (flo >> 16) & 0xFF; + p += incr; + + /* Seventh byte */ + *p = (flo >> 8) & 0xFF; + p += incr; + + /* Eighth byte */ + *p = flo & 0xFF; + p += incr; + + /* Done */ + return 0; + + Overflow: + PyErr_SetString(PyExc_OverflowError, + "float too large to pack with d format"); + return -1; + } + else { + const char *s = (char*)&x; + int i, incr = 1; + + if ((double_format == ieee_little_endian_format && !le) + || (double_format == ieee_big_endian_format && le)) { + p += 7; + incr = -1; + } + + for (i = 0; i < 8; i++) { + *p = *s++; + p += incr; + } + return 0; + } +} + +double +_PyFloat_Unpack4(const unsigned char *p, int le) +{ + if (float_format == unknown_format) { + unsigned char sign; + int e; + unsigned int f; + double x; + int incr = 1; + + if (le) { + p += 3; + incr = -1; + } + + /* First byte */ + sign = (*p >> 7) & 1; + e = (*p & 0x7F) << 1; + p += incr; + + /* Second byte */ + e |= (*p >> 7) & 1; + f = (*p & 0x7F) << 16; + p += incr; + + if (e == 255) { + PyErr_SetString( + PyExc_ValueError, + "can't unpack IEEE 754 special value " + "on non-IEEE platform"); + return -1; + } + + /* Third byte */ + f |= *p << 8; + p += incr; + + /* Fourth byte */ + f |= *p; + + x = (double)f / 8388608.0; + + /* XXX This sadly ignores Inf/NaN issues */ + if (e == 0) + e = -126; + else { + x += 1.0; + e -= 127; + } + x = ldexp(x, e); + + if (sign) + x = -x; + + return x; + } + else { + float x; + + if ((float_format == ieee_little_endian_format && !le) + || (float_format == ieee_big_endian_format && le)) { + char buf[4]; + char *d = &buf[3]; + int i; + + for (i = 0; i < 4; i++) { + *d-- = *p++; + } + memcpy(&x, buf, 4); + } + else { + memcpy(&x, p, 4); + } + + return x; + } +} + +double +_PyFloat_Unpack8(const unsigned char *p, int le) +{ + if (double_format == unknown_format) { + unsigned char sign; + int e; + unsigned int fhi, flo; + double x; + int incr = 1; + + if (le) { + p += 7; + incr = -1; + } + + /* First byte */ + sign = (*p >> 7) & 1; + e = (*p & 0x7F) << 4; + + p += incr; + + /* Second byte */ + e |= (*p >> 4) & 0xF; + fhi = (*p & 0xF) << 24; + p += incr; + + if (e == 2047) { + PyErr_SetString( + PyExc_ValueError, + "can't unpack IEEE 754 special value " + "on non-IEEE platform"); + return -1.0; + } + + /* Third byte */ + fhi |= *p << 16; + p += incr; + + /* Fourth byte */ + fhi |= *p << 8; + p += incr; + + /* Fifth byte */ + fhi |= *p; + p += incr; + + /* Sixth byte */ + flo = *p << 16; + p += incr; + + /* Seventh byte */ + flo |= *p << 8; + p += incr; + + /* Eighth byte */ + flo |= *p; + + x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */ + x /= 268435456.0; /* 2**28 */ + + if (e == 0) + e = -1022; + else { + x += 1.0; + e -= 1023; + } + x = ldexp(x, e); + + if (sign) + x = -x; + + return x; + } + else { + double x; + + if ((double_format == ieee_little_endian_format && !le) + || (double_format == ieee_big_endian_format && le)) { + char buf[8]; + char *d = &buf[7]; + int i; + + for (i = 0; i < 8; i++) { + *d-- = *p++; + } + memcpy(&x, buf, 8); + } + else { + memcpy(&x, p, 8); + } + + return x; + } +} diff --git a/sys/src/cmd/python/Objects/frameobject.c b/sys/src/cmd/python/Objects/frameobject.c new file mode 100644 index 000000000..3a073b6fa --- /dev/null +++ b/sys/src/cmd/python/Objects/frameobject.c @@ -0,0 +1,849 @@ +/* Frame object implementation */ + +#include "Python.h" + +#include "code.h" +#include "frameobject.h" +#include "opcode.h" +#include "structmember.h" + +#undef MIN +#undef MAX +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +#define OFF(x) offsetof(PyFrameObject, x) + +static PyMemberDef frame_memberlist[] = { + {"f_back", T_OBJECT, OFF(f_back), RO}, + {"f_code", T_OBJECT, OFF(f_code), RO}, + {"f_builtins", T_OBJECT, OFF(f_builtins),RO}, + {"f_globals", T_OBJECT, OFF(f_globals), RO}, + {"f_lasti", T_INT, OFF(f_lasti), RO}, + {"f_exc_type", T_OBJECT, OFF(f_exc_type)}, + {"f_exc_value", T_OBJECT, OFF(f_exc_value)}, + {"f_exc_traceback", T_OBJECT, OFF(f_exc_traceback)}, + {NULL} /* Sentinel */ +}; + +static PyObject * +frame_getlocals(PyFrameObject *f, void *closure) +{ + PyFrame_FastToLocals(f); + Py_INCREF(f->f_locals); + return f->f_locals; +} + +static PyObject * +frame_getlineno(PyFrameObject *f, void *closure) +{ + int lineno; + + if (f->f_trace) + lineno = f->f_lineno; + else + lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); + + return PyInt_FromLong(lineno); +} + +/* Setter for f_lineno - you can set f_lineno from within a trace function in + * order to jump to a given line of code, subject to some restrictions. Most + * lines are OK to jump to because they don't make any assumptions about the + * state of the stack (obvious because you could remove the line and the code + * would still work without any stack errors), but there are some constructs + * that limit jumping: + * + * o Lines with an 'except' statement on them can't be jumped to, because + * they expect an exception to be on the top of the stack. + * o Lines that live in a 'finally' block can't be jumped from or to, since + * the END_FINALLY expects to clean up the stack after the 'try' block. + * o 'try'/'for'/'while' blocks can't be jumped into because the blockstack + * needs to be set up before their code runs, and for 'for' loops the + * iterator needs to be on the stack. + */ +static int +frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno) +{ + int new_lineno = 0; /* The new value of f_lineno */ + int new_lasti = 0; /* The new value of f_lasti */ + int new_iblock = 0; /* The new value of f_iblock */ + char *code = NULL; /* The bytecode for the frame... */ + Py_ssize_t code_len = 0; /* ...and its length */ + char *lnotab = NULL; /* Iterating over co_lnotab */ + Py_ssize_t lnotab_len = 0; /* (ditto) */ + int offset = 0; /* (ditto) */ + int line = 0; /* (ditto) */ + int addr = 0; /* (ditto) */ + int min_addr = 0; /* Scanning the SETUPs and POPs */ + int max_addr = 0; /* (ditto) */ + int delta_iblock = 0; /* (ditto) */ + int min_delta_iblock = 0; /* (ditto) */ + int min_iblock = 0; /* (ditto) */ + int f_lasti_setup_addr = 0; /* Policing no-jump-into-finally */ + int new_lasti_setup_addr = 0; /* (ditto) */ + int blockstack[CO_MAXBLOCKS]; /* Walking the 'finally' blocks */ + int in_finally[CO_MAXBLOCKS]; /* (ditto) */ + int blockstack_top = 0; /* (ditto) */ + int setup_op = 0; /* (ditto) */ + + /* f_lineno must be an integer. */ + if (!PyInt_Check(p_new_lineno)) { + PyErr_SetString(PyExc_ValueError, + "lineno must be an integer"); + return -1; + } + + /* You can only do this from within a trace function, not via + * _getframe or similar hackery. */ + if (!f->f_trace) + { + PyErr_Format(PyExc_ValueError, + "f_lineno can only be set by a trace function"); + return -1; + } + + /* Fail if the line comes before the start of the code block. */ + new_lineno = (int) PyInt_AsLong(p_new_lineno); + if (new_lineno < f->f_code->co_firstlineno) { + PyErr_Format(PyExc_ValueError, + "line %d comes before the current code block", + new_lineno); + return -1; + } + + /* Find the bytecode offset for the start of the given line, or the + * first code-owning line after it. */ + PyString_AsStringAndSize(f->f_code->co_lnotab, &lnotab, &lnotab_len); + addr = 0; + line = f->f_code->co_firstlineno; + new_lasti = -1; + for (offset = 0; offset < lnotab_len; offset += 2) { + addr += lnotab[offset]; + line += lnotab[offset+1]; + if (line >= new_lineno) { + new_lasti = addr; + new_lineno = line; + break; + } + } + + /* If we didn't reach the requested line, return an error. */ + if (new_lasti == -1) { + PyErr_Format(PyExc_ValueError, + "line %d comes after the current code block", + new_lineno); + return -1; + } + + /* We're now ready to look at the bytecode. */ + PyString_AsStringAndSize(f->f_code->co_code, &code, &code_len); + min_addr = MIN(new_lasti, f->f_lasti); + max_addr = MAX(new_lasti, f->f_lasti); + + /* You can't jump onto a line with an 'except' statement on it - + * they expect to have an exception on the top of the stack, which + * won't be true if you jump to them. They always start with code + * that either pops the exception using POP_TOP (plain 'except:' + * lines do this) or duplicates the exception on the stack using + * DUP_TOP (if there's an exception type specified). See compile.c, + * 'com_try_except' for the full details. There aren't any other + * cases (AFAIK) where a line's code can start with DUP_TOP or + * POP_TOP, but if any ever appear, they'll be subject to the same + * restriction (but with a different error message). */ + if (code[new_lasti] == DUP_TOP || code[new_lasti] == POP_TOP) { + PyErr_SetString(PyExc_ValueError, + "can't jump to 'except' line as there's no exception"); + return -1; + } + + /* You can't jump into or out of a 'finally' block because the 'try' + * block leaves something on the stack for the END_FINALLY to clean + * up. So we walk the bytecode, maintaining a simulated blockstack. + * When we reach the old or new address and it's in a 'finally' block + * we note the address of the corresponding SETUP_FINALLY. The jump + * is only legal if neither address is in a 'finally' block or + * they're both in the same one. 'blockstack' is a stack of the + * bytecode addresses of the SETUP_X opcodes, and 'in_finally' tracks + * whether we're in a 'finally' block at each blockstack level. */ + f_lasti_setup_addr = -1; + new_lasti_setup_addr = -1; + memset(blockstack, '\0', sizeof(blockstack)); + memset(in_finally, '\0', sizeof(in_finally)); + blockstack_top = 0; + for (addr = 0; addr < code_len; addr++) { + unsigned char op = code[addr]; + switch (op) { + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + blockstack[blockstack_top++] = addr; + in_finally[blockstack_top-1] = 0; + break; + + case POP_BLOCK: + assert(blockstack_top > 0); + setup_op = code[blockstack[blockstack_top-1]]; + if (setup_op == SETUP_FINALLY) { + in_finally[blockstack_top-1] = 1; + } + else { + blockstack_top--; + } + break; + + case END_FINALLY: + /* Ignore END_FINALLYs for SETUP_EXCEPTs - they exist + * in the bytecode but don't correspond to an actual + * 'finally' block. (If blockstack_top is 0, we must + * be seeing such an END_FINALLY.) */ + if (blockstack_top > 0) { + setup_op = code[blockstack[blockstack_top-1]]; + if (setup_op == SETUP_FINALLY) { + blockstack_top--; + } + } + break; + } + + /* For the addresses we're interested in, see whether they're + * within a 'finally' block and if so, remember the address + * of the SETUP_FINALLY. */ + if (addr == new_lasti || addr == f->f_lasti) { + int i = 0; + int setup_addr = -1; + for (i = blockstack_top-1; i >= 0; i--) { + if (in_finally[i]) { + setup_addr = blockstack[i]; + break; + } + } + + if (setup_addr != -1) { + if (addr == new_lasti) { + new_lasti_setup_addr = setup_addr; + } + + if (addr == f->f_lasti) { + f_lasti_setup_addr = setup_addr; + } + } + } + + if (op >= HAVE_ARGUMENT) { + addr += 2; + } + } + + /* Verify that the blockstack tracking code didn't get lost. */ + assert(blockstack_top == 0); + + /* After all that, are we jumping into / out of a 'finally' block? */ + if (new_lasti_setup_addr != f_lasti_setup_addr) { + PyErr_SetString(PyExc_ValueError, + "can't jump into or out of a 'finally' block"); + return -1; + } + + + /* Police block-jumping (you can't jump into the middle of a block) + * and ensure that the blockstack finishes up in a sensible state (by + * popping any blocks we're jumping out of). We look at all the + * blockstack operations between the current position and the new + * one, and keep track of how many blocks we drop out of on the way. + * By also keeping track of the lowest blockstack position we see, we + * can tell whether the jump goes into any blocks without coming out + * again - in that case we raise an exception below. */ + delta_iblock = 0; + for (addr = min_addr; addr < max_addr; addr++) { + unsigned char op = code[addr]; + switch (op) { + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + delta_iblock++; + break; + + case POP_BLOCK: + delta_iblock--; + break; + } + + min_delta_iblock = MIN(min_delta_iblock, delta_iblock); + + if (op >= HAVE_ARGUMENT) { + addr += 2; + } + } + + /* Derive the absolute iblock values from the deltas. */ + min_iblock = f->f_iblock + min_delta_iblock; + if (new_lasti > f->f_lasti) { + /* Forwards jump. */ + new_iblock = f->f_iblock + delta_iblock; + } + else { + /* Backwards jump. */ + new_iblock = f->f_iblock - delta_iblock; + } + + /* Are we jumping into a block? */ + if (new_iblock > min_iblock) { + PyErr_SetString(PyExc_ValueError, + "can't jump into the middle of a block"); + return -1; + } + + /* Pop any blocks that we're jumping out of. */ + while (f->f_iblock > new_iblock) { + PyTryBlock *b = &f->f_blockstack[--f->f_iblock]; + while ((f->f_stacktop - f->f_valuestack) > b->b_level) { + PyObject *v = (*--f->f_stacktop); + Py_DECREF(v); + } + } + + /* Finally set the new f_lineno and f_lasti and return OK. */ + f->f_lineno = new_lineno; + f->f_lasti = new_lasti; + return 0; +} + +static PyObject * +frame_gettrace(PyFrameObject *f, void *closure) +{ + PyObject* trace = f->f_trace; + + if (trace == NULL) + trace = Py_None; + + Py_INCREF(trace); + + return trace; +} + +static int +frame_settrace(PyFrameObject *f, PyObject* v, void *closure) +{ + /* We rely on f_lineno being accurate when f_trace is set. */ + + PyObject* old_value = f->f_trace; + + Py_XINCREF(v); + f->f_trace = v; + + if (v != NULL) + f->f_lineno = PyCode_Addr2Line(f->f_code, f->f_lasti); + + Py_XDECREF(old_value); + + return 0; +} + +static PyObject * +frame_getrestricted(PyFrameObject *f, void *closure) +{ + return PyBool_FromLong(PyFrame_IsRestricted(f)); +} + +static PyGetSetDef frame_getsetlist[] = { + {"f_locals", (getter)frame_getlocals, NULL, NULL}, + {"f_lineno", (getter)frame_getlineno, + (setter)frame_setlineno, NULL}, + {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL}, + {"f_restricted",(getter)frame_getrestricted,NULL, NULL}, + {0} +}; + +/* Stack frames are allocated and deallocated at a considerable rate. + In an attempt to improve the speed of function calls, we: + + 1. Hold a single "zombie" frame on each code object. This retains + the allocated and initialised frame object from an invocation of + the code object. The zombie is reanimated the next time we need a + frame object for that code object. Doing this saves the malloc/ + realloc required when using a free_list frame that isn't the + correct size. It also saves some field initialisation. + + In zombie mode, no field of PyFrameObject holds a reference, but + the following fields are still valid: + + * ob_type, ob_size, f_code, f_valuestack; + + * f_locals, f_trace, + f_exc_type, f_exc_value, f_exc_traceback are NULL; + + * f_localsplus does not require re-allocation and + the local variables in f_localsplus are NULL. + + 2. We also maintain a separate free list of stack frames (just like + integers are allocated in a special way -- see intobject.c). When + a stack frame is on the free list, only the following members have + a meaning: + ob_type == &Frametype + f_back next item on free list, or NULL + f_stacksize size of value stack + ob_size size of localsplus + Note that the value and block stacks are preserved -- this can save + another malloc() call or two (and two free() calls as well!). + Also note that, unlike for integers, each frame object is a + malloc'ed object in its own right -- it is only the actual calls to + malloc() that we are trying to save here, not the administration. + After all, while a typical program may make millions of calls, a + call depth of more than 20 or 30 is probably already exceptional + unless the program contains run-away recursion. I hope. + + Later, MAXFREELIST was added to bound the # of frames saved on + free_list. Else programs creating lots of cyclic trash involving + frames could provoke free_list into growing without bound. +*/ + +static PyFrameObject *free_list = NULL; +static int numfree = 0; /* number of frames currently in free_list */ +#define MAXFREELIST 200 /* max value for numfree */ + +static void +frame_dealloc(PyFrameObject *f) +{ + PyObject **p, **valuestack; + PyCodeObject *co; + + PyObject_GC_UnTrack(f); + Py_TRASHCAN_SAFE_BEGIN(f) + /* Kill all local variables */ + valuestack = f->f_valuestack; + for (p = f->f_localsplus; p < valuestack; p++) + Py_CLEAR(*p); + + /* Free stack */ + if (f->f_stacktop != NULL) { + for (p = valuestack; p < f->f_stacktop; p++) + Py_XDECREF(*p); + } + + Py_XDECREF(f->f_back); + Py_DECREF(f->f_builtins); + Py_DECREF(f->f_globals); + Py_CLEAR(f->f_locals); + Py_CLEAR(f->f_trace); + Py_CLEAR(f->f_exc_type); + Py_CLEAR(f->f_exc_value); + Py_CLEAR(f->f_exc_traceback); + + co = f->f_code; + if (co->co_zombieframe == NULL) + co->co_zombieframe = f; + else if (numfree < MAXFREELIST) { + ++numfree; + f->f_back = free_list; + free_list = f; + } + else + PyObject_GC_Del(f); + + Py_DECREF(co); + Py_TRASHCAN_SAFE_END(f) +} + +static int +frame_traverse(PyFrameObject *f, visitproc visit, void *arg) +{ + PyObject **fastlocals, **p; + int i, slots; + + Py_VISIT(f->f_back); + Py_VISIT(f->f_code); + Py_VISIT(f->f_builtins); + Py_VISIT(f->f_globals); + Py_VISIT(f->f_locals); + Py_VISIT(f->f_trace); + Py_VISIT(f->f_exc_type); + Py_VISIT(f->f_exc_value); + Py_VISIT(f->f_exc_traceback); + + /* locals */ + slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); + fastlocals = f->f_localsplus; + for (i = slots; --i >= 0; ++fastlocals) + Py_VISIT(*fastlocals); + + /* stack */ + if (f->f_stacktop != NULL) { + for (p = f->f_valuestack; p < f->f_stacktop; p++) + Py_VISIT(*p); + } + return 0; +} + +static void +frame_clear(PyFrameObject *f) +{ + PyObject **fastlocals, **p, **oldtop; + int i, slots; + + /* Before anything else, make sure that this frame is clearly marked + * as being defunct! Else, e.g., a generator reachable from this + * frame may also point to this frame, believe itself to still be + * active, and try cleaning up this frame again. + */ + oldtop = f->f_stacktop; + f->f_stacktop = NULL; + + Py_CLEAR(f->f_exc_type); + Py_CLEAR(f->f_exc_value); + Py_CLEAR(f->f_exc_traceback); + Py_CLEAR(f->f_trace); + + /* locals */ + slots = f->f_code->co_nlocals + PyTuple_GET_SIZE(f->f_code->co_cellvars) + PyTuple_GET_SIZE(f->f_code->co_freevars); + fastlocals = f->f_localsplus; + for (i = slots; --i >= 0; ++fastlocals) + Py_CLEAR(*fastlocals); + + /* stack */ + if (oldtop != NULL) { + for (p = f->f_valuestack; p < oldtop; p++) + Py_CLEAR(*p); + } +} + + +PyTypeObject PyFrame_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "frame", + sizeof(PyFrameObject), + sizeof(PyObject *), + (destructor)frame_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)frame_traverse, /* tp_traverse */ + (inquiry)frame_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + frame_memberlist, /* tp_members */ + frame_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ +}; + +static PyObject *builtin_object; + +int _PyFrame_Init() +{ + builtin_object = PyString_InternFromString("__builtins__"); + return (builtin_object != NULL); +} + +PyFrameObject * +PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, + PyObject *locals) +{ + PyFrameObject *back = tstate->frame; + PyFrameObject *f; + PyObject *builtins; + Py_ssize_t i; + +#ifdef Py_DEBUG + if (code == NULL || globals == NULL || !PyDict_Check(globals) || + (locals != NULL && !PyMapping_Check(locals))) { + PyErr_BadInternalCall(); + return NULL; + } +#endif + if (back == NULL || back->f_globals != globals) { + builtins = PyDict_GetItem(globals, builtin_object); + if (builtins) { + if (PyModule_Check(builtins)) { + builtins = PyModule_GetDict(builtins); + assert(!builtins || PyDict_Check(builtins)); + } + else if (!PyDict_Check(builtins)) + builtins = NULL; + } + if (builtins == NULL) { + /* No builtins! Make up a minimal one + Give them 'None', at least. */ + builtins = PyDict_New(); + if (builtins == NULL || + PyDict_SetItemString( + builtins, "None", Py_None) < 0) + return NULL; + } + else + Py_INCREF(builtins); + + } + else { + /* If we share the globals, we share the builtins. + Save a lookup and a call. */ + builtins = back->f_builtins; + assert(builtins != NULL && PyDict_Check(builtins)); + Py_INCREF(builtins); + } + if (code->co_zombieframe != NULL) { + f = code->co_zombieframe; + code->co_zombieframe = NULL; + _Py_NewReference((PyObject *)f); + assert(f->f_code == code); + } + else { + Py_ssize_t extras, ncells, nfrees; + ncells = PyTuple_GET_SIZE(code->co_cellvars); + nfrees = PyTuple_GET_SIZE(code->co_freevars); + extras = code->co_stacksize + code->co_nlocals + ncells + + nfrees; + if (free_list == NULL) { + f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, + extras); + if (f == NULL) { + Py_DECREF(builtins); + return NULL; + } + } + else { + assert(numfree > 0); + --numfree; + f = free_list; + free_list = free_list->f_back; + if (f->ob_size < extras) { + f = PyObject_GC_Resize(PyFrameObject, f, extras); + if (f == NULL) { + Py_DECREF(builtins); + return NULL; + } + } + _Py_NewReference((PyObject *)f); + } + + f->f_code = code; + extras = code->co_nlocals + ncells + nfrees; + f->f_valuestack = f->f_localsplus + extras; + for (i=0; i<extras; i++) + f->f_localsplus[i] = NULL; + f->f_locals = NULL; + f->f_trace = NULL; + f->f_exc_type = f->f_exc_value = f->f_exc_traceback = NULL; + } + f->f_stacktop = f->f_valuestack; + f->f_builtins = builtins; + Py_XINCREF(back); + f->f_back = back; + Py_INCREF(code); + Py_INCREF(globals); + f->f_globals = globals; + /* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */ + if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == + (CO_NEWLOCALS | CO_OPTIMIZED)) + ; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */ + else if (code->co_flags & CO_NEWLOCALS) { + locals = PyDict_New(); + if (locals == NULL) { + Py_DECREF(f); + return NULL; + } + f->f_locals = locals; + } + else { + if (locals == NULL) + locals = globals; + Py_INCREF(locals); + f->f_locals = locals; + } + f->f_tstate = tstate; + + f->f_lasti = -1; + f->f_lineno = code->co_firstlineno; + f->f_iblock = 0; + + _PyObject_GC_TRACK(f); + return f; +} + +/* Block management */ + +void +PyFrame_BlockSetup(PyFrameObject *f, int type, int handler, int level) +{ + PyTryBlock *b; + if (f->f_iblock >= CO_MAXBLOCKS) + Py_FatalError("XXX block stack overflow"); + b = &f->f_blockstack[f->f_iblock++]; + b->b_type = type; + b->b_level = level; + b->b_handler = handler; +} + +PyTryBlock * +PyFrame_BlockPop(PyFrameObject *f) +{ + PyTryBlock *b; + if (f->f_iblock <= 0) + Py_FatalError("XXX block stack underflow"); + b = &f->f_blockstack[--f->f_iblock]; + return b; +} + +/* Convert between "fast" version of locals and dictionary version */ + +static void +map_to_dict(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, + Py_ssize_t deref) +{ + Py_ssize_t j; + for (j = nmap; --j >= 0; ) { + PyObject *key = PyTuple_GET_ITEM(map, j); + PyObject *value = values[j]; + if (deref) + value = PyCell_GET(value); + if (value == NULL) { + if (PyObject_DelItem(dict, key) != 0) + PyErr_Clear(); + } + else { + if (PyObject_SetItem(dict, key, value) != 0) + PyErr_Clear(); + } + } +} + +static void +dict_to_map(PyObject *map, Py_ssize_t nmap, PyObject *dict, PyObject **values, + Py_ssize_t deref, int clear) +{ + Py_ssize_t j; + for (j = nmap; --j >= 0; ) { + PyObject *key = PyTuple_GET_ITEM(map, j); + PyObject *value = PyObject_GetItem(dict, key); + if (value == NULL) + PyErr_Clear(); + if (deref) { + if (value || clear) { + if (PyCell_GET(values[j]) != value) { + if (PyCell_Set(values[j], value) < 0) + PyErr_Clear(); + } + } + } else if (value != NULL || clear) { + if (values[j] != value) { + Py_XINCREF(value); + Py_XDECREF(values[j]); + values[j] = value; + } + } + Py_XDECREF(value); + } +} + +void +PyFrame_FastToLocals(PyFrameObject *f) +{ + /* Merge fast locals into f->f_locals */ + PyObject *locals, *map; + PyObject **fast; + PyObject *error_type, *error_value, *error_traceback; + PyCodeObject *co; + Py_ssize_t j; + int ncells, nfreevars; + if (f == NULL) + return; + locals = f->f_locals; + if (locals == NULL) { + locals = f->f_locals = PyDict_New(); + if (locals == NULL) { + PyErr_Clear(); /* Can't report it :-( */ + return; + } + } + co = f->f_code; + map = co->co_varnames; + if (!PyTuple_Check(map)) + return; + PyErr_Fetch(&error_type, &error_value, &error_traceback); + fast = f->f_localsplus; + j = PyTuple_GET_SIZE(map); + if (j > co->co_nlocals) + j = co->co_nlocals; + if (co->co_nlocals) + map_to_dict(map, j, locals, fast, 0); + ncells = PyTuple_GET_SIZE(co->co_cellvars); + nfreevars = PyTuple_GET_SIZE(co->co_freevars); + if (ncells || nfreevars) { + map_to_dict(co->co_cellvars, ncells, + locals, fast + co->co_nlocals, 1); + map_to_dict(co->co_freevars, nfreevars, + locals, fast + co->co_nlocals + ncells, 1); + } + PyErr_Restore(error_type, error_value, error_traceback); +} + +void +PyFrame_LocalsToFast(PyFrameObject *f, int clear) +{ + /* Merge f->f_locals into fast locals */ + PyObject *locals, *map; + PyObject **fast; + PyObject *error_type, *error_value, *error_traceback; + PyCodeObject *co; + Py_ssize_t j; + int ncells, nfreevars; + if (f == NULL) + return; + locals = f->f_locals; + co = f->f_code; + map = co->co_varnames; + if (locals == NULL) + return; + if (!PyTuple_Check(map)) + return; + PyErr_Fetch(&error_type, &error_value, &error_traceback); + fast = f->f_localsplus; + j = PyTuple_GET_SIZE(map); + if (j > co->co_nlocals) + j = co->co_nlocals; + if (co->co_nlocals) + dict_to_map(co->co_varnames, j, locals, fast, 0, clear); + ncells = PyTuple_GET_SIZE(co->co_cellvars); + nfreevars = PyTuple_GET_SIZE(co->co_freevars); + if (ncells || nfreevars) { + dict_to_map(co->co_cellvars, ncells, + locals, fast + co->co_nlocals, 1, clear); + dict_to_map(co->co_freevars, nfreevars, + locals, fast + co->co_nlocals + ncells, 1, + clear); + } + PyErr_Restore(error_type, error_value, error_traceback); +} + +/* Clear out the free list */ + +void +PyFrame_Fini(void) +{ + while (free_list != NULL) { + PyFrameObject *f = free_list; + free_list = free_list->f_back; + PyObject_GC_Del(f); + --numfree; + } + assert(numfree == 0); + Py_XDECREF(builtin_object); + builtin_object = NULL; +} diff --git a/sys/src/cmd/python/Objects/funcobject.c b/sys/src/cmd/python/Objects/funcobject.c new file mode 100644 index 000000000..1ba74c5a9 --- /dev/null +++ b/sys/src/cmd/python/Objects/funcobject.c @@ -0,0 +1,888 @@ + +/* Function object implementation */ + +#include "Python.h" +#include "code.h" +#include "eval.h" +#include "structmember.h" + +PyObject * +PyFunction_New(PyObject *code, PyObject *globals) +{ + PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, + &PyFunction_Type); + static PyObject *__name__ = 0; + if (op != NULL) { + PyObject *doc; + PyObject *consts; + PyObject *module; + op->func_weakreflist = NULL; + Py_INCREF(code); + op->func_code = code; + Py_INCREF(globals); + op->func_globals = globals; + op->func_name = ((PyCodeObject *)code)->co_name; + Py_INCREF(op->func_name); + op->func_defaults = NULL; /* No default arguments */ + op->func_closure = NULL; + consts = ((PyCodeObject *)code)->co_consts; + if (PyTuple_Size(consts) >= 1) { + doc = PyTuple_GetItem(consts, 0); + if (!PyString_Check(doc) && !PyUnicode_Check(doc)) + doc = Py_None; + } + else + doc = Py_None; + Py_INCREF(doc); + op->func_doc = doc; + op->func_dict = NULL; + op->func_module = NULL; + + /* __module__: If module name is in globals, use it. + Otherwise, use None. + */ + if (!__name__) { + __name__ = PyString_InternFromString("__name__"); + if (!__name__) { + Py_DECREF(op); + return NULL; + } + } + module = PyDict_GetItem(globals, __name__); + if (module) { + Py_INCREF(module); + op->func_module = module; + } + } + else + return NULL; + _PyObject_GC_TRACK(op); + return (PyObject *)op; +} + +PyObject * +PyFunction_GetCode(PyObject *op) +{ + if (!PyFunction_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyFunctionObject *) op) -> func_code; +} + +PyObject * +PyFunction_GetGlobals(PyObject *op) +{ + if (!PyFunction_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyFunctionObject *) op) -> func_globals; +} + +PyObject * +PyFunction_GetModule(PyObject *op) +{ + if (!PyFunction_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyFunctionObject *) op) -> func_module; +} + +PyObject * +PyFunction_GetDefaults(PyObject *op) +{ + if (!PyFunction_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyFunctionObject *) op) -> func_defaults; +} + +int +PyFunction_SetDefaults(PyObject *op, PyObject *defaults) +{ + if (!PyFunction_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + if (defaults == Py_None) + defaults = NULL; + else if (defaults && PyTuple_Check(defaults)) { + Py_INCREF(defaults); + } + else { + PyErr_SetString(PyExc_SystemError, "non-tuple default args"); + return -1; + } + Py_XDECREF(((PyFunctionObject *) op) -> func_defaults); + ((PyFunctionObject *) op) -> func_defaults = defaults; + return 0; +} + +PyObject * +PyFunction_GetClosure(PyObject *op) +{ + if (!PyFunction_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyFunctionObject *) op) -> func_closure; +} + +int +PyFunction_SetClosure(PyObject *op, PyObject *closure) +{ + if (!PyFunction_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + if (closure == Py_None) + closure = NULL; + else if (PyTuple_Check(closure)) { + Py_INCREF(closure); + } + else { + PyErr_Format(PyExc_SystemError, + "expected tuple for closure, got '%.100s'", + closure->ob_type->tp_name); + return -1; + } + Py_XDECREF(((PyFunctionObject *) op) -> func_closure); + ((PyFunctionObject *) op) -> func_closure = closure; + return 0; +} + +/* Methods */ + +#define OFF(x) offsetof(PyFunctionObject, x) + +static PyMemberDef func_memberlist[] = { + {"func_closure", T_OBJECT, OFF(func_closure), + RESTRICTED|READONLY}, + {"func_doc", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED}, + {"__doc__", T_OBJECT, OFF(func_doc), WRITE_RESTRICTED}, + {"func_globals", T_OBJECT, OFF(func_globals), + RESTRICTED|READONLY}, + {"__module__", T_OBJECT, OFF(func_module), WRITE_RESTRICTED}, + {NULL} /* Sentinel */ +}; + +static int +restricted(void) +{ + if (!PyEval_GetRestricted()) + return 0; + PyErr_SetString(PyExc_RuntimeError, + "function attributes not accessible in restricted mode"); + return 1; +} + +static PyObject * +func_get_dict(PyFunctionObject *op) +{ + if (restricted()) + return NULL; + if (op->func_dict == NULL) { + op->func_dict = PyDict_New(); + if (op->func_dict == NULL) + return NULL; + } + Py_INCREF(op->func_dict); + return op->func_dict; +} + +static int +func_set_dict(PyFunctionObject *op, PyObject *value) +{ + PyObject *tmp; + + if (restricted()) + return -1; + /* It is illegal to del f.func_dict */ + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "function's dictionary may not be deleted"); + return -1; + } + /* Can only set func_dict to a dictionary */ + if (!PyDict_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "setting function's dictionary to a non-dict"); + return -1; + } + tmp = op->func_dict; + Py_INCREF(value); + op->func_dict = value; + Py_XDECREF(tmp); + return 0; +} + +static PyObject * +func_get_code(PyFunctionObject *op) +{ + if (restricted()) + return NULL; + Py_INCREF(op->func_code); + return op->func_code; +} + +static int +func_set_code(PyFunctionObject *op, PyObject *value) +{ + PyObject *tmp; + Py_ssize_t nfree, nclosure; + + if (restricted()) + return -1; + /* Not legal to del f.func_code or to set it to anything + * other than a code object. */ + if (value == NULL || !PyCode_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "func_code must be set to a code object"); + return -1; + } + nfree = PyCode_GetNumFree((PyCodeObject *)value); + nclosure = (op->func_closure == NULL ? 0 : + PyTuple_GET_SIZE(op->func_closure)); + if (nclosure != nfree) { + PyErr_Format(PyExc_ValueError, + "%s() requires a code object with %zd free vars," + " not %zd", + PyString_AsString(op->func_name), + nclosure, nfree); + return -1; + } + tmp = op->func_code; + Py_INCREF(value); + op->func_code = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +func_get_name(PyFunctionObject *op) +{ + Py_INCREF(op->func_name); + return op->func_name; +} + +static int +func_set_name(PyFunctionObject *op, PyObject *value) +{ + PyObject *tmp; + + if (restricted()) + return -1; + /* Not legal to del f.func_name or to set it to anything + * other than a string object. */ + if (value == NULL || !PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "func_name must be set to a string object"); + return -1; + } + tmp = op->func_name; + Py_INCREF(value); + op->func_name = value; + Py_DECREF(tmp); + return 0; +} + +static PyObject * +func_get_defaults(PyFunctionObject *op) +{ + if (restricted()) + return NULL; + if (op->func_defaults == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + Py_INCREF(op->func_defaults); + return op->func_defaults; +} + +static int +func_set_defaults(PyFunctionObject *op, PyObject *value) +{ + PyObject *tmp; + + if (restricted()) + return -1; + /* Legal to del f.func_defaults. + * Can only set func_defaults to NULL or a tuple. */ + if (value == Py_None) + value = NULL; + if (value != NULL && !PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "func_defaults must be set to a tuple object"); + return -1; + } + tmp = op->func_defaults; + Py_XINCREF(value); + op->func_defaults = value; + Py_XDECREF(tmp); + return 0; +} + +static PyGetSetDef func_getsetlist[] = { + {"func_code", (getter)func_get_code, (setter)func_set_code}, + {"func_defaults", (getter)func_get_defaults, + (setter)func_set_defaults}, + {"func_dict", (getter)func_get_dict, (setter)func_set_dict}, + {"__dict__", (getter)func_get_dict, (setter)func_set_dict}, + {"func_name", (getter)func_get_name, (setter)func_set_name}, + {"__name__", (getter)func_get_name, (setter)func_set_name}, + {NULL} /* Sentinel */ +}; + +PyDoc_STRVAR(func_doc, +"function(code, globals[, name[, argdefs[, closure]]])\n\ +\n\ +Create a function object from a code object and a dictionary.\n\ +The optional name string overrides the name from the code object.\n\ +The optional argdefs tuple specifies the default argument values.\n\ +The optional closure tuple supplies the bindings for free variables."); + +/* func_new() maintains the following invariants for closures. The + closure must correspond to the free variables of the code object. + + if len(code.co_freevars) == 0: + closure = NULL + else: + len(closure) == len(code.co_freevars) + for every elt in closure, type(elt) == cell +*/ + +static PyObject * +func_new(PyTypeObject* type, PyObject* args, PyObject* kw) +{ + PyCodeObject *code; + PyObject *globals; + PyObject *name = Py_None; + PyObject *defaults = Py_None; + PyObject *closure = Py_None; + PyFunctionObject *newfunc; + Py_ssize_t nfree, nclosure; + static char *kwlist[] = {"code", "globals", "name", + "argdefs", "closure", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O!|OOO:function", + kwlist, + &PyCode_Type, &code, + &PyDict_Type, &globals, + &name, &defaults, &closure)) + return NULL; + if (name != Py_None && !PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "arg 3 (name) must be None or string"); + return NULL; + } + if (defaults != Py_None && !PyTuple_Check(defaults)) { + PyErr_SetString(PyExc_TypeError, + "arg 4 (defaults) must be None or tuple"); + return NULL; + } + nfree = PyTuple_GET_SIZE(code->co_freevars); + if (!PyTuple_Check(closure)) { + if (nfree && closure == Py_None) { + PyErr_SetString(PyExc_TypeError, + "arg 5 (closure) must be tuple"); + return NULL; + } + else if (closure != Py_None) { + PyErr_SetString(PyExc_TypeError, + "arg 5 (closure) must be None or tuple"); + return NULL; + } + } + + /* check that the closure is well-formed */ + nclosure = closure == Py_None ? 0 : PyTuple_GET_SIZE(closure); + if (nfree != nclosure) + return PyErr_Format(PyExc_ValueError, + "%s requires closure of length %zd, not %zd", + PyString_AS_STRING(code->co_name), + nfree, nclosure); + if (nclosure) { + Py_ssize_t i; + for (i = 0; i < nclosure; i++) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + if (!PyCell_Check(o)) { + return PyErr_Format(PyExc_TypeError, + "arg 5 (closure) expected cell, found %s", + o->ob_type->tp_name); + } + } + } + + newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code, + globals); + if (newfunc == NULL) + return NULL; + + if (name != Py_None) { + Py_INCREF(name); + Py_DECREF(newfunc->func_name); + newfunc->func_name = name; + } + if (defaults != Py_None) { + Py_INCREF(defaults); + newfunc->func_defaults = defaults; + } + if (closure != Py_None) { + Py_INCREF(closure); + newfunc->func_closure = closure; + } + + return (PyObject *)newfunc; +} + +static void +func_dealloc(PyFunctionObject *op) +{ + _PyObject_GC_UNTRACK(op); + if (op->func_weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) op); + Py_DECREF(op->func_code); + Py_DECREF(op->func_globals); + Py_XDECREF(op->func_module); + Py_DECREF(op->func_name); + Py_XDECREF(op->func_defaults); + Py_XDECREF(op->func_doc); + Py_XDECREF(op->func_dict); + Py_XDECREF(op->func_closure); + PyObject_GC_Del(op); +} + +static PyObject* +func_repr(PyFunctionObject *op) +{ + return PyString_FromFormat("<function %s at %p>", + PyString_AsString(op->func_name), + op); +} + +static int +func_traverse(PyFunctionObject *f, visitproc visit, void *arg) +{ + Py_VISIT(f->func_code); + Py_VISIT(f->func_globals); + Py_VISIT(f->func_module); + Py_VISIT(f->func_defaults); + Py_VISIT(f->func_doc); + Py_VISIT(f->func_name); + Py_VISIT(f->func_dict); + Py_VISIT(f->func_closure); + return 0; +} + +static PyObject * +function_call(PyObject *func, PyObject *arg, PyObject *kw) +{ + PyObject *result; + PyObject *argdefs; + PyObject **d, **k; + Py_ssize_t nk, nd; + + argdefs = PyFunction_GET_DEFAULTS(func); + if (argdefs != NULL && PyTuple_Check(argdefs)) { + d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); + nd = PyTuple_Size(argdefs); + } + else { + d = NULL; + nd = 0; + } + + if (kw != NULL && PyDict_Check(kw)) { + Py_ssize_t pos, i; + nk = PyDict_Size(kw); + k = PyMem_NEW(PyObject *, 2*nk); + if (k == NULL) { + PyErr_NoMemory(); + return NULL; + } + pos = i = 0; + while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) + i += 2; + nk = i/2; + /* XXX This is broken if the caller deletes dict items! */ + } + else { + k = NULL; + nk = 0; + } + + result = PyEval_EvalCodeEx( + (PyCodeObject *)PyFunction_GET_CODE(func), + PyFunction_GET_GLOBALS(func), (PyObject *)NULL, + &PyTuple_GET_ITEM(arg, 0), PyTuple_Size(arg), + k, nk, d, nd, + PyFunction_GET_CLOSURE(func)); + + if (k != NULL) + PyMem_DEL(k); + + return result; +} + +/* Bind a function to an object */ +static PyObject * +func_descr_get(PyObject *func, PyObject *obj, PyObject *type) +{ + if (obj == Py_None) + obj = NULL; + return PyMethod_New(func, obj, type); +} + +PyTypeObject PyFunction_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "function", + sizeof(PyFunctionObject), + 0, + (destructor)func_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)func_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + function_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + func_doc, /* tp_doc */ + (traverseproc)func_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyFunctionObject, func_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + func_memberlist, /* tp_members */ + func_getsetlist, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + func_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(PyFunctionObject, func_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + func_new, /* tp_new */ +}; + + +/* Class method object */ + +/* A class method receives the class as implicit first argument, + just like an instance method receives the instance. + To declare a class method, use this idiom: + + class C: + def f(cls, arg1, arg2, ...): ... + f = classmethod(f) + + It can be called either on the class (e.g. C.f()) or on an instance + (e.g. C().f()); the instance is ignored except for its class. + If a class method is called for a derived class, the derived class + object is passed as the implied first argument. + + Class methods are different than C++ or Java static methods. + If you want those, see static methods below. +*/ + +typedef struct { + PyObject_HEAD + PyObject *cm_callable; +} classmethod; + +static void +cm_dealloc(classmethod *cm) +{ + _PyObject_GC_UNTRACK((PyObject *)cm); + Py_XDECREF(cm->cm_callable); + cm->ob_type->tp_free((PyObject *)cm); +} + +static int +cm_traverse(classmethod *cm, visitproc visit, void *arg) +{ + Py_VISIT(cm->cm_callable); + return 0; +} + +static int +cm_clear(classmethod *cm) +{ + Py_CLEAR(cm->cm_callable); + return 0; +} + + +static PyObject * +cm_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + classmethod *cm = (classmethod *)self; + + if (cm->cm_callable == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "uninitialized classmethod object"); + return NULL; + } + if (type == NULL) + type = (PyObject *)(obj->ob_type); + return PyMethod_New(cm->cm_callable, + type, (PyObject *)(type->ob_type)); +} + +static int +cm_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + classmethod *cm = (classmethod *)self; + PyObject *callable; + + if (!PyArg_UnpackTuple(args, "classmethod", 1, 1, &callable)) + return -1; + if (!_PyArg_NoKeywords("classmethod", kwds)) + return -1; + if (!PyCallable_Check(callable)) { + PyErr_Format(PyExc_TypeError, "'%s' object is not callable", + callable->ob_type->tp_name); + return -1; + } + + Py_INCREF(callable); + cm->cm_callable = callable; + return 0; +} + +PyDoc_STRVAR(classmethod_doc, +"classmethod(function) -> method\n\ +\n\ +Convert a function to be a class method.\n\ +\n\ +A class method receives the class as implicit first argument,\n\ +just like an instance method receives the instance.\n\ +To declare a class method, use this idiom:\n\ +\n\ + class C:\n\ + def f(cls, arg1, arg2, ...): ...\n\ + f = classmethod(f)\n\ +\n\ +It can be called either on the class (e.g. C.f()) or on an instance\n\ +(e.g. C().f()). The instance is ignored except for its class.\n\ +If a class method is called for a derived class, the derived class\n\ +object is passed as the implied first argument.\n\ +\n\ +Class methods are different than C++ or Java static methods.\n\ +If you want those, see the staticmethod builtin."); + +PyTypeObject PyClassMethod_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "classmethod", + sizeof(classmethod), + 0, + (destructor)cm_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + classmethod_doc, /* tp_doc */ + (traverseproc)cm_traverse, /* tp_traverse */ + (inquiry)cm_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + cm_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + cm_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +PyObject * +PyClassMethod_New(PyObject *callable) +{ + classmethod *cm = (classmethod *) + PyType_GenericAlloc(&PyClassMethod_Type, 0); + if (cm != NULL) { + Py_INCREF(callable); + cm->cm_callable = callable; + } + return (PyObject *)cm; +} + + +/* Static method object */ + +/* A static method does not receive an implicit first argument. + To declare a static method, use this idiom: + + class C: + def f(arg1, arg2, ...): ... + f = staticmethod(f) + + It can be called either on the class (e.g. C.f()) or on an instance + (e.g. C().f()); the instance is ignored except for its class. + + Static methods in Python are similar to those found in Java or C++. + For a more advanced concept, see class methods above. +*/ + +typedef struct { + PyObject_HEAD + PyObject *sm_callable; +} staticmethod; + +static void +sm_dealloc(staticmethod *sm) +{ + _PyObject_GC_UNTRACK((PyObject *)sm); + Py_XDECREF(sm->sm_callable); + sm->ob_type->tp_free((PyObject *)sm); +} + +static int +sm_traverse(staticmethod *sm, visitproc visit, void *arg) +{ + Py_VISIT(sm->sm_callable); + return 0; +} + +static int +sm_clear(staticmethod *sm) +{ + Py_XDECREF(sm->sm_callable); + sm->sm_callable = NULL; + + return 0; +} + +static PyObject * +sm_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + staticmethod *sm = (staticmethod *)self; + + if (sm->sm_callable == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "uninitialized staticmethod object"); + return NULL; + } + Py_INCREF(sm->sm_callable); + return sm->sm_callable; +} + +static int +sm_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + staticmethod *sm = (staticmethod *)self; + PyObject *callable; + + if (!PyArg_UnpackTuple(args, "staticmethod", 1, 1, &callable)) + return -1; + if (!_PyArg_NoKeywords("staticmethod", kwds)) + return -1; + Py_INCREF(callable); + sm->sm_callable = callable; + return 0; +} + +PyDoc_STRVAR(staticmethod_doc, +"staticmethod(function) -> method\n\ +\n\ +Convert a function to be a static method.\n\ +\n\ +A static method does not receive an implicit first argument.\n\ +To declare a static method, use this idiom:\n\ +\n\ + class C:\n\ + def f(arg1, arg2, ...): ...\n\ + f = staticmethod(f)\n\ +\n\ +It can be called either on the class (e.g. C.f()) or on an instance\n\ +(e.g. C().f()). The instance is ignored except for its class.\n\ +\n\ +Static methods in Python are similar to those found in Java or C++.\n\ +For a more advanced concept, see the classmethod builtin."); + +PyTypeObject PyStaticMethod_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "staticmethod", + sizeof(staticmethod), + 0, + (destructor)sm_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, + staticmethod_doc, /* tp_doc */ + (traverseproc)sm_traverse, /* tp_traverse */ + (inquiry)sm_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + sm_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + sm_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +PyObject * +PyStaticMethod_New(PyObject *callable) +{ + staticmethod *sm = (staticmethod *) + PyType_GenericAlloc(&PyStaticMethod_Type, 0); + if (sm != NULL) { + Py_INCREF(callable); + sm->sm_callable = callable; + } + return (PyObject *)sm; +} diff --git a/sys/src/cmd/python/Objects/genobject.c b/sys/src/cmd/python/Objects/genobject.c new file mode 100644 index 000000000..4d0c4f6ee --- /dev/null +++ b/sys/src/cmd/python/Objects/genobject.c @@ -0,0 +1,383 @@ +/* Generator object implementation */ + +#include "Python.h" +#include "frameobject.h" +#include "genobject.h" +#include "ceval.h" +#include "structmember.h" +#include "opcode.h" + +static int +gen_traverse(PyGenObject *gen, visitproc visit, void *arg) +{ + Py_VISIT((PyObject *)gen->gi_frame); + return 0; +} + +static void +gen_dealloc(PyGenObject *gen) +{ + PyObject *self = (PyObject *) gen; + + _PyObject_GC_UNTRACK(gen); + + if (gen->gi_weakreflist != NULL) + PyObject_ClearWeakRefs(self); + + _PyObject_GC_TRACK(self); + + if (gen->gi_frame != NULL && gen->gi_frame->f_stacktop != NULL) { + /* Generator is paused, so we need to close */ + gen->ob_type->tp_del(self); + if (self->ob_refcnt > 0) + return; /* resurrected. :( */ + } + + _PyObject_GC_UNTRACK(self); + Py_CLEAR(gen->gi_frame); + PyObject_GC_Del(gen); +} + + +static PyObject * +gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyFrameObject *f = gen->gi_frame; + PyObject *result; + + if (gen->gi_running) { + PyErr_SetString(PyExc_ValueError, + "generator already executing"); + return NULL; + } + if (f==NULL || f->f_stacktop == NULL) { + /* Only set exception if called from send() */ + if (arg && !exc) + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } + + if (f->f_lasti == -1) { + if (arg && arg != Py_None) { + PyErr_SetString(PyExc_TypeError, + "can't send non-None value to a " + "just-started generator"); + return NULL; + } + } else { + /* Push arg onto the frame's value stack */ + result = arg ? arg : Py_None; + Py_INCREF(result); + *(f->f_stacktop++) = result; + } + + /* Generators always return to their most recent caller, not + * necessarily their creator. */ + Py_XINCREF(tstate->frame); + assert(f->f_back == NULL); + f->f_back = tstate->frame; + + gen->gi_running = 1; + result = PyEval_EvalFrameEx(f, exc); + gen->gi_running = 0; + + /* Don't keep the reference to f_back any longer than necessary. It + * may keep a chain of frames alive or it could create a reference + * cycle. */ + assert(f->f_back == tstate->frame); + Py_CLEAR(f->f_back); + + /* If the generator just returned (as opposed to yielding), signal + * that the generator is exhausted. */ + if (result == Py_None && f->f_stacktop == NULL) { + Py_DECREF(result); + result = NULL; + /* Set exception if not called by gen_iternext() */ + if (arg) + PyErr_SetNone(PyExc_StopIteration); + } + + if (!result || f->f_stacktop == NULL) { + /* generator can't be rerun, so release the frame */ + Py_DECREF(f); + gen->gi_frame = NULL; + } + + return result; +} + +PyDoc_STRVAR(send_doc, +"send(arg) -> send 'arg' into generator,\n\ +return next yielded value or raise StopIteration."); + +static PyObject * +gen_send(PyGenObject *gen, PyObject *arg) +{ + return gen_send_ex(gen, arg, 0); +} + +PyDoc_STRVAR(close_doc, +"close(arg) -> raise GeneratorExit inside generator."); + +static PyObject * +gen_close(PyGenObject *gen, PyObject *args) +{ + PyObject *retval; + PyErr_SetNone(PyExc_GeneratorExit); + retval = gen_send_ex(gen, Py_None, 1); + if (retval) { + Py_DECREF(retval); + PyErr_SetString(PyExc_RuntimeError, + "generator ignored GeneratorExit"); + return NULL; + } + if (PyErr_ExceptionMatches(PyExc_StopIteration) + || PyErr_ExceptionMatches(PyExc_GeneratorExit)) + { + PyErr_Clear(); /* ignore these errors */ + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} + +static void +gen_del(PyObject *self) +{ + PyObject *res; + PyObject *error_type, *error_value, *error_traceback; + PyGenObject *gen = (PyGenObject *)self; + + if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) + /* Generator isn't paused, so no need to close */ + return; + + /* Temporarily resurrect the object. */ + assert(self->ob_refcnt == 0); + self->ob_refcnt = 1; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + res = gen_close(gen, NULL); + + if (res == NULL) + PyErr_WriteUnraisable(self); + else + Py_DECREF(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ + assert(self->ob_refcnt > 0); + if (--self->ob_refcnt == 0) + return; /* this is the normal path out */ + + /* close() resurrected it! Make it look like the original Py_DECREF + * never happened. + */ + { + Py_ssize_t refcnt = self->ob_refcnt; + _Py_NewReference(self); + self->ob_refcnt = refcnt; + } + assert(PyType_IS_GC(self->ob_type) && + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + + /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so + * we need to undo that. */ + _Py_DEC_REFTOTAL; + /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object + * chain, so no more to do there. + * If COUNT_ALLOCS, the original decref bumped tp_frees, and + * _Py_NewReference bumped tp_allocs: both of those need to be + * undone. + */ +#ifdef COUNT_ALLOCS + --self->ob_type->tp_frees; + --self->ob_type->tp_allocs; +#endif +} + + + +PyDoc_STRVAR(throw_doc, +"throw(typ[,val[,tb]]) -> raise exception in generator,\n\ +return next yielded value or raise StopIteration."); + +static PyObject * +gen_throw(PyGenObject *gen, PyObject *args) +{ + PyObject *typ; + PyObject *tb = NULL; + PyObject *val = NULL; + + if (!PyArg_UnpackTuple(args, "throw", 1, 3, &typ, &val, &tb)) + return NULL; + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) + tb = NULL; + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "throw() third argument must be a traceback object"); + return NULL; + } + + Py_INCREF(typ); + Py_XINCREF(val); + Py_XINCREF(tb); + + if (PyExceptionClass_Check(typ)) { + PyErr_NormalizeException(&typ, &val, &tb); + } + + else if (PyExceptionInstance_Check(typ)) { + /* Raising an instance. The value should be a dummy. */ + if (val && val != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto failed_throw; + } + else { + /* Normalize to raise <class>, <instance> */ + Py_XDECREF(val); + val = typ; + typ = PyExceptionInstance_Class(typ); + Py_INCREF(typ); + } + } + + /* Allow raising builtin string exceptions */ + + else if (!PyString_CheckExact(typ)) { + /* Not something you can raise. throw() fails. */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes, or instances, not %s", + typ->ob_type->tp_name); + goto failed_throw; + } + + PyErr_Restore(typ, val, tb); + return gen_send_ex(gen, Py_None, 1); + +failed_throw: + /* Didn't use our arguments, so restore their original refcounts */ + Py_DECREF(typ); + Py_XDECREF(val); + Py_XDECREF(tb); + return NULL; +} + + +static PyObject * +gen_iternext(PyGenObject *gen) +{ + return gen_send_ex(gen, NULL, 0); +} + + +static PyMemberDef gen_memberlist[] = { + {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), RO}, + {"gi_running", T_INT, offsetof(PyGenObject, gi_running), RO}, + {NULL} /* Sentinel */ +}; + +static PyMethodDef gen_methods[] = { + {"send",(PyCFunction)gen_send, METH_O, send_doc}, + {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, + {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, + {NULL, NULL} /* Sentinel */ +}; + +PyTypeObject PyGen_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "generator", /* tp_name */ + sizeof(PyGenObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)gen_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)gen_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyGenObject, gi_weakreflist), /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)gen_iternext, /* tp_iternext */ + gen_methods, /* tp_methods */ + gen_memberlist, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + gen_del, /* tp_del */ +}; + +PyObject * +PyGen_New(PyFrameObject *f) +{ + PyGenObject *gen = PyObject_GC_New(PyGenObject, &PyGen_Type); + if (gen == NULL) { + Py_DECREF(f); + return NULL; + } + gen->gi_frame = f; + gen->gi_running = 0; + gen->gi_weakreflist = NULL; + _PyObject_GC_TRACK(gen); + return (PyObject *)gen; +} + +int +PyGen_NeedsFinalizing(PyGenObject *gen) +{ + int i; + PyFrameObject *f = gen->gi_frame; + + if (f == NULL || f->f_stacktop == NULL || f->f_iblock <= 0) + return 0; /* no frame or empty blockstack == no finalization */ + + /* Any block type besides a loop requires cleanup. */ + i = f->f_iblock; + while (--i >= 0) { + if (f->f_blockstack[i].b_type != SETUP_LOOP) + return 1; + } + + /* No blocks except loops, it's safe to skip finalization. */ + return 0; +} diff --git a/sys/src/cmd/python/Objects/intobject.c b/sys/src/cmd/python/Objects/intobject.c new file mode 100644 index 000000000..8aa8d0b39 --- /dev/null +++ b/sys/src/cmd/python/Objects/intobject.c @@ -0,0 +1,1280 @@ + +/* Integer object implementation */ + +#include "Python.h" +#include <ctype.h> + +long +PyInt_GetMax(void) +{ + return LONG_MAX; /* To initialize sys.maxint */ +} + +/* Integers are quite normal objects, to make object handling uniform. + (Using odd pointers to represent integers would save much space + but require extra checks for this special case throughout the code.) + Since a typical Python program spends much of its time allocating + and deallocating integers, these operations should be very fast. + Therefore we use a dedicated allocation scheme with a much lower + overhead (in space and time) than straight malloc(): a simple + dedicated free list, filled when necessary with memory from malloc(). + + block_list is a singly-linked list of all PyIntBlocks ever allocated, + linked via their next members. PyIntBlocks are never returned to the + system before shutdown (PyInt_Fini). + + free_list is a singly-linked list of available PyIntObjects, linked + via abuse of their ob_type members. +*/ + +#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */ +#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */ +#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject)) + +struct _intblock { + struct _intblock *next; + PyIntObject objects[N_INTOBJECTS]; +}; + +typedef struct _intblock PyIntBlock; + +static PyIntBlock *block_list = NULL; +static PyIntObject *free_list = NULL; + +static PyIntObject * +fill_free_list(void) +{ + PyIntObject *p, *q; + /* Python's object allocator isn't appropriate for large blocks. */ + p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock)); + if (p == NULL) + return (PyIntObject *) PyErr_NoMemory(); + ((PyIntBlock *)p)->next = block_list; + block_list = (PyIntBlock *)p; + /* Link the int objects together, from rear to front, then return + the address of the last int object in the block. */ + p = &((PyIntBlock *)p)->objects[0]; + q = p + N_INTOBJECTS; + while (--q > p) + q->ob_type = (struct _typeobject *)(q-1); + q->ob_type = NULL; + return p + N_INTOBJECTS - 1; +} + +#ifndef NSMALLPOSINTS +#define NSMALLPOSINTS 257 +#endif +#ifndef NSMALLNEGINTS +#define NSMALLNEGINTS 5 +#endif +#if NSMALLNEGINTS + NSMALLPOSINTS > 0 +/* References to small integers are saved in this array so that they + can be shared. + The integers that are saved are those in the range + -NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive). +*/ +static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS]; +#endif +#ifdef COUNT_ALLOCS +int quick_int_allocs, quick_neg_int_allocs; +#endif + +PyObject * +PyInt_FromLong(long ival) +{ + register PyIntObject *v; +#if NSMALLNEGINTS + NSMALLPOSINTS > 0 + if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) { + v = small_ints[ival + NSMALLNEGINTS]; + Py_INCREF(v); +#ifdef COUNT_ALLOCS + if (ival >= 0) + quick_int_allocs++; + else + quick_neg_int_allocs++; +#endif + return (PyObject *) v; + } +#endif + if (free_list == NULL) { + if ((free_list = fill_free_list()) == NULL) + return NULL; + } + /* Inline PyObject_New */ + v = free_list; + free_list = (PyIntObject *)v->ob_type; + PyObject_INIT(v, &PyInt_Type); + v->ob_ival = ival; + return (PyObject *) v; +} + +PyObject * +PyInt_FromSize_t(size_t ival) +{ + if (ival <= LONG_MAX) + return PyInt_FromLong((long)ival); + return _PyLong_FromSize_t(ival); +} + +PyObject * +PyInt_FromSsize_t(Py_ssize_t ival) +{ + if (ival >= LONG_MIN && ival <= LONG_MAX) + return PyInt_FromLong((long)ival); + return _PyLong_FromSsize_t(ival); +} + +static void +int_dealloc(PyIntObject *v) +{ + if (PyInt_CheckExact(v)) { + v->ob_type = (struct _typeobject *)free_list; + free_list = v; + } + else + v->ob_type->tp_free((PyObject *)v); +} + +static void +int_free(PyIntObject *v) +{ + v->ob_type = (struct _typeobject *)free_list; + free_list = v; +} + +long +PyInt_AsLong(register PyObject *op) +{ + PyNumberMethods *nb; + PyIntObject *io; + long val; + + if (op && PyInt_Check(op)) + return PyInt_AS_LONG((PyIntObject*) op); + + if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || + nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + + io = (PyIntObject*) (*nb->nb_int) (op); + if (io == NULL) + return -1; + if (!PyInt_Check(io)) { + if (PyLong_Check(io)) { + /* got a long? => retry int conversion */ + val = PyLong_AsLong((PyObject *)io); + Py_DECREF(io); + if ((val == -1) && PyErr_Occurred()) + return -1; + return val; + } + else + { + Py_DECREF(io); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return -1; + } + } + + val = PyInt_AS_LONG(io); + Py_DECREF(io); + + return val; +} + +Py_ssize_t +PyInt_AsSsize_t(register PyObject *op) +{ +#if SIZEOF_SIZE_T != SIZEOF_LONG + PyNumberMethods *nb; + PyIntObject *io; + Py_ssize_t val; +#endif + + if (op == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + + if (PyInt_Check(op)) + return PyInt_AS_LONG((PyIntObject*) op); + if (PyLong_Check(op)) + return _PyLong_AsSsize_t(op); +#if SIZEOF_SIZE_T == SIZEOF_LONG + return PyInt_AsLong(op); +#else + + if ((nb = op->ob_type->tp_as_number) == NULL || + (nb->nb_int == NULL && nb->nb_long == 0)) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + + if (nb->nb_long != 0) { + io = (PyIntObject*) (*nb->nb_long) (op); + } else { + io = (PyIntObject*) (*nb->nb_int) (op); + } + if (io == NULL) + return -1; + if (!PyInt_Check(io)) { + if (PyLong_Check(io)) { + /* got a long? => retry int conversion */ + val = _PyLong_AsSsize_t((PyObject *)io); + Py_DECREF(io); + if ((val == -1) && PyErr_Occurred()) + return -1; + return val; + } + else + { + Py_DECREF(io); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return -1; + } + } + + val = PyInt_AS_LONG(io); + Py_DECREF(io); + + return val; +#endif +} + +unsigned long +PyInt_AsUnsignedLongMask(register PyObject *op) +{ + PyNumberMethods *nb; + PyIntObject *io; + unsigned long val; + + if (op && PyInt_Check(op)) + return PyInt_AS_LONG((PyIntObject*) op); + if (op && PyLong_Check(op)) + return PyLong_AsUnsignedLongMask(op); + + if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || + nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return (unsigned long)-1; + } + + io = (PyIntObject*) (*nb->nb_int) (op); + if (io == NULL) + return (unsigned long)-1; + if (!PyInt_Check(io)) { + if (PyLong_Check(io)) { + val = PyLong_AsUnsignedLongMask((PyObject *)io); + Py_DECREF(io); + if (PyErr_Occurred()) + return (unsigned long)-1; + return val; + } + else + { + Py_DECREF(io); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return (unsigned long)-1; + } + } + + val = PyInt_AS_LONG(io); + Py_DECREF(io); + + return val; +} + +#ifdef HAVE_LONG_LONG +unsigned PY_LONG_LONG +PyInt_AsUnsignedLongLongMask(register PyObject *op) +{ + PyNumberMethods *nb; + PyIntObject *io; + unsigned PY_LONG_LONG val; + + if (op && PyInt_Check(op)) + return PyInt_AS_LONG((PyIntObject*) op); + if (op && PyLong_Check(op)) + return PyLong_AsUnsignedLongLongMask(op); + + if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || + nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return (unsigned PY_LONG_LONG)-1; + } + + io = (PyIntObject*) (*nb->nb_int) (op); + if (io == NULL) + return (unsigned PY_LONG_LONG)-1; + if (!PyInt_Check(io)) { + if (PyLong_Check(io)) { + val = PyLong_AsUnsignedLongLongMask((PyObject *)io); + Py_DECREF(io); + if (PyErr_Occurred()) + return (unsigned PY_LONG_LONG)-1; + return val; + } + else + { + Py_DECREF(io); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return (unsigned PY_LONG_LONG)-1; + } + } + + val = PyInt_AS_LONG(io); + Py_DECREF(io); + + return val; +} +#endif + +PyObject * +PyInt_FromString(char *s, char **pend, int base) +{ + char *end; + long x; + Py_ssize_t slen; + PyObject *sobj, *srepr; + + if ((base != 0 && base < 2) || base > 36) { + PyErr_SetString(PyExc_ValueError, + "int() base must be >= 2 and <= 36"); + return NULL; + } + + while (*s && isspace(Py_CHARMASK(*s))) + s++; + errno = 0; + if (base == 0 && s[0] == '0') { + x = (long) PyOS_strtoul(s, &end, base); + if (x < 0) + return PyLong_FromString(s, pend, base); + } + else + x = PyOS_strtol(s, &end, base); + if (end == s || !isalnum(Py_CHARMASK(end[-1]))) + goto bad; + while (*end && isspace(Py_CHARMASK(*end))) + end++; + if (*end != '\0') { + bad: + slen = strlen(s) < 200 ? strlen(s) : 200; + sobj = PyString_FromStringAndSize(s, slen); + if (sobj == NULL) + return NULL; + srepr = PyObject_Repr(sobj); + Py_DECREF(sobj); + if (srepr == NULL) + return NULL; + PyErr_Format(PyExc_ValueError, + "invalid literal for int() with base %d: %s", + base, PyString_AS_STRING(srepr)); + Py_DECREF(srepr); + return NULL; + } + else if (errno != 0) + return PyLong_FromString(s, pend, base); + if (pend) + *pend = end; + return PyInt_FromLong(x); +} + +#ifdef Py_USING_UNICODE +PyObject * +PyInt_FromUnicode(Py_UNICODE *s, Py_ssize_t length, int base) +{ + PyObject *result; + char *buffer = (char *)PyMem_MALLOC(length+1); + + if (buffer == NULL) + return NULL; + + if (PyUnicode_EncodeDecimal(s, length, buffer, NULL)) { + PyMem_FREE(buffer); + return NULL; + } + result = PyInt_FromString(buffer, NULL, base); + PyMem_FREE(buffer); + return result; +} +#endif + +/* Methods */ + +/* Integers are seen as the "smallest" of all numeric types and thus + don't have any knowledge about conversion of other types to + integers. */ + +#define CONVERT_TO_LONG(obj, lng) \ + if (PyInt_Check(obj)) { \ + lng = PyInt_AS_LONG(obj); \ + } \ + else { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } + +/* ARGSUSED */ +static int +int_print(PyIntObject *v, FILE *fp, int flags) + /* flags -- not used but required by interface */ +{ + fprintf(fp, "%ld", v->ob_ival); + return 0; +} + +static PyObject * +int_repr(PyIntObject *v) +{ + char buf[64]; + PyOS_snprintf(buf, sizeof(buf), "%ld", v->ob_ival); + return PyString_FromString(buf); +} + +static int +int_compare(PyIntObject *v, PyIntObject *w) +{ + register long i = v->ob_ival; + register long j = w->ob_ival; + return (i < j) ? -1 : (i > j) ? 1 : 0; +} + +static long +int_hash(PyIntObject *v) +{ + /* XXX If this is changed, you also need to change the way + Python's long, float and complex types are hashed. */ + long x = v -> ob_ival; + if (x == -1) + x = -2; + return x; +} + +static PyObject * +int_add(PyIntObject *v, PyIntObject *w) +{ + register long a, b, x; + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + x = a + b; + if ((x^a) >= 0 || (x^b) >= 0) + return PyInt_FromLong(x); + return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w); +} + +static PyObject * +int_sub(PyIntObject *v, PyIntObject *w) +{ + register long a, b, x; + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + x = a - b; + if ((x^a) >= 0 || (x^~b) >= 0) + return PyInt_FromLong(x); + return PyLong_Type.tp_as_number->nb_subtract((PyObject *)v, + (PyObject *)w); +} + +/* +Integer overflow checking for * is painful: Python tried a couple ways, but +they didn't work on all platforms, or failed in endcases (a product of +-sys.maxint-1 has been a particular pain). + +Here's another way: + +The native long product x*y is either exactly right or *way* off, being +just the last n bits of the true product, where n is the number of bits +in a long (the delivered product is the true product plus i*2**n for +some integer i). + +The native double product (double)x * (double)y is subject to three +rounding errors: on a sizeof(long)==8 box, each cast to double can lose +info, and even on a sizeof(long)==4 box, the multiplication can lose info. +But, unlike the native long product, it's not in *range* trouble: even +if sizeof(long)==32 (256-bit longs), the product easily fits in the +dynamic range of a double. So the leading 50 (or so) bits of the double +product are correct. + +We check these two ways against each other, and declare victory if they're +approximately the same. Else, because the native long product is the only +one that can lose catastrophic amounts of information, it's the native long +product that must have overflowed. +*/ + +static PyObject * +int_mul(PyObject *v, PyObject *w) +{ + long a, b; + long longprod; /* a*b in native long arithmetic */ + double doubled_longprod; /* (double)longprod */ + double doubleprod; /* (double)a * (double)b */ + + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + longprod = a * b; + doubleprod = (double)a * (double)b; + doubled_longprod = (double)longprod; + + /* Fast path for normal case: small multiplicands, and no info + is lost in either method. */ + if (doubled_longprod == doubleprod) + return PyInt_FromLong(longprod); + + /* Somebody somewhere lost info. Close enough, or way off? Note + that a != 0 and b != 0 (else doubled_longprod == doubleprod == 0). + The difference either is or isn't significant compared to the + true value (of which doubleprod is a good approximation). + */ + { + const double diff = doubled_longprod - doubleprod; + const double absdiff = diff >= 0.0 ? diff : -diff; + const double absprod = doubleprod >= 0.0 ? doubleprod : + -doubleprod; + /* absdiff/absprod <= 1/32 iff + 32 * absdiff <= absprod -- 5 good bits is "close enough" */ + if (32.0 * absdiff <= absprod) + return PyInt_FromLong(longprod); + else + return PyLong_Type.tp_as_number->nb_multiply(v, w); + } +} + +/* Integer overflow checking for unary negation: on a 2's-complement + * box, -x overflows iff x is the most negative long. In this case we + * get -x == x. However, -x is undefined (by C) if x /is/ the most + * negative long (it's a signed overflow case), and some compilers care. + * So we cast x to unsigned long first. However, then other compilers + * warn about applying unary minus to an unsigned operand. Hence the + * weird "0-". + */ +#define UNARY_NEG_WOULD_OVERFLOW(x) \ + ((x) < 0 && (unsigned long)(x) == 0-(unsigned long)(x)) + +/* Return type of i_divmod */ +enum divmod_result { + DIVMOD_OK, /* Correct result */ + DIVMOD_OVERFLOW, /* Overflow, try again using longs */ + DIVMOD_ERROR /* Exception raised */ +}; + +static enum divmod_result +i_divmod(register long x, register long y, + long *p_xdivy, long *p_xmody) +{ + long xdivy, xmody; + + if (y == 0) { + PyErr_SetString(PyExc_ZeroDivisionError, + "integer division or modulo by zero"); + return DIVMOD_ERROR; + } + /* (-sys.maxint-1)/-1 is the only overflow case. */ + if (y == -1 && UNARY_NEG_WOULD_OVERFLOW(x)) + return DIVMOD_OVERFLOW; + xdivy = x / y; + xmody = x - xdivy * y; + /* If the signs of x and y differ, and the remainder is non-0, + * C89 doesn't define whether xdivy is now the floor or the + * ceiling of the infinitely precise quotient. We want the floor, + * and we have it iff the remainder's sign matches y's. + */ + if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) { + xmody += y; + --xdivy; + assert(xmody && ((y ^ xmody) >= 0)); + } + *p_xdivy = xdivy; + *p_xmody = xmody; + return DIVMOD_OK; +} + +static PyObject * +int_div(PyIntObject *x, PyIntObject *y) +{ + long xi, yi; + long d, m; + CONVERT_TO_LONG(x, xi); + CONVERT_TO_LONG(y, yi); + switch (i_divmod(xi, yi, &d, &m)) { + case DIVMOD_OK: + return PyInt_FromLong(d); + case DIVMOD_OVERFLOW: + return PyLong_Type.tp_as_number->nb_divide((PyObject *)x, + (PyObject *)y); + default: + return NULL; + } +} + +static PyObject * +int_classic_div(PyIntObject *x, PyIntObject *y) +{ + long xi, yi; + long d, m; + CONVERT_TO_LONG(x, xi); + CONVERT_TO_LONG(y, yi); + if (Py_DivisionWarningFlag && + PyErr_Warn(PyExc_DeprecationWarning, "classic int division") < 0) + return NULL; + switch (i_divmod(xi, yi, &d, &m)) { + case DIVMOD_OK: + return PyInt_FromLong(d); + case DIVMOD_OVERFLOW: + return PyLong_Type.tp_as_number->nb_divide((PyObject *)x, + (PyObject *)y); + default: + return NULL; + } +} + +static PyObject * +int_true_divide(PyObject *v, PyObject *w) +{ + /* If they aren't both ints, give someone else a chance. In + particular, this lets int/long get handled by longs, which + underflows to 0 gracefully if the long is too big to convert + to float. */ + if (PyInt_Check(v) && PyInt_Check(w)) + return PyFloat_Type.tp_as_number->nb_true_divide(v, w); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyObject * +int_mod(PyIntObject *x, PyIntObject *y) +{ + long xi, yi; + long d, m; + CONVERT_TO_LONG(x, xi); + CONVERT_TO_LONG(y, yi); + switch (i_divmod(xi, yi, &d, &m)) { + case DIVMOD_OK: + return PyInt_FromLong(m); + case DIVMOD_OVERFLOW: + return PyLong_Type.tp_as_number->nb_remainder((PyObject *)x, + (PyObject *)y); + default: + return NULL; + } +} + +static PyObject * +int_divmod(PyIntObject *x, PyIntObject *y) +{ + long xi, yi; + long d, m; + CONVERT_TO_LONG(x, xi); + CONVERT_TO_LONG(y, yi); + switch (i_divmod(xi, yi, &d, &m)) { + case DIVMOD_OK: + return Py_BuildValue("(ll)", d, m); + case DIVMOD_OVERFLOW: + return PyLong_Type.tp_as_number->nb_divmod((PyObject *)x, + (PyObject *)y); + default: + return NULL; + } +} + +static PyObject * +int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z) +{ + register long iv, iw, iz=0, ix, temp, prev; + CONVERT_TO_LONG(v, iv); + CONVERT_TO_LONG(w, iw); + if (iw < 0) { + if ((PyObject *)z != Py_None) { + PyErr_SetString(PyExc_TypeError, "pow() 2nd argument " + "cannot be negative when 3rd argument specified"); + return NULL; + } + /* Return a float. This works because we know that + this calls float_pow() which converts its + arguments to double. */ + return PyFloat_Type.tp_as_number->nb_power( + (PyObject *)v, (PyObject *)w, (PyObject *)z); + } + if ((PyObject *)z != Py_None) { + CONVERT_TO_LONG(z, iz); + if (iz == 0) { + PyErr_SetString(PyExc_ValueError, + "pow() 3rd argument cannot be 0"); + return NULL; + } + } + /* + * XXX: The original exponentiation code stopped looping + * when temp hit zero; this code will continue onwards + * unnecessarily, but at least it won't cause any errors. + * Hopefully the speed improvement from the fast exponentiation + * will compensate for the slight inefficiency. + * XXX: Better handling of overflows is desperately needed. + */ + temp = iv; + ix = 1; + while (iw > 0) { + prev = ix; /* Save value for overflow check */ + if (iw & 1) { + ix = ix*temp; + if (temp == 0) + break; /* Avoid ix / 0 */ + if (ix / temp != prev) { + return PyLong_Type.tp_as_number->nb_power( + (PyObject *)v, + (PyObject *)w, + (PyObject *)z); + } + } + iw >>= 1; /* Shift exponent down by 1 bit */ + if (iw==0) break; + prev = temp; + temp *= temp; /* Square the value of temp */ + if (prev != 0 && temp / prev != prev) { + return PyLong_Type.tp_as_number->nb_power( + (PyObject *)v, (PyObject *)w, (PyObject *)z); + } + if (iz) { + /* If we did a multiplication, perform a modulo */ + ix = ix % iz; + temp = temp % iz; + } + } + if (iz) { + long div, mod; + switch (i_divmod(ix, iz, &div, &mod)) { + case DIVMOD_OK: + ix = mod; + break; + case DIVMOD_OVERFLOW: + return PyLong_Type.tp_as_number->nb_power( + (PyObject *)v, (PyObject *)w, (PyObject *)z); + default: + return NULL; + } + } + return PyInt_FromLong(ix); +} + +static PyObject * +int_neg(PyIntObject *v) +{ + register long a; + a = v->ob_ival; + /* check for overflow */ + if (UNARY_NEG_WOULD_OVERFLOW(a)) { + PyObject *o = PyLong_FromLong(a); + if (o != NULL) { + PyObject *result = PyNumber_Negative(o); + Py_DECREF(o); + return result; + } + return NULL; + } + return PyInt_FromLong(-a); +} + +static PyObject * +int_pos(PyIntObject *v) +{ + if (PyInt_CheckExact(v)) { + Py_INCREF(v); + return (PyObject *)v; + } + else + return PyInt_FromLong(v->ob_ival); +} + +static PyObject * +int_abs(PyIntObject *v) +{ + if (v->ob_ival >= 0) + return int_pos(v); + else + return int_neg(v); +} + +static int +int_nonzero(PyIntObject *v) +{ + return v->ob_ival != 0; +} + +static PyObject * +int_invert(PyIntObject *v) +{ + return PyInt_FromLong(~v->ob_ival); +} + +static PyObject * +int_lshift(PyIntObject *v, PyIntObject *w) +{ + long a, b, c; + PyObject *vv, *ww, *result; + + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + if (b < 0) { + PyErr_SetString(PyExc_ValueError, "negative shift count"); + return NULL; + } + if (a == 0 || b == 0) + return int_pos(v); + if (b >= LONG_BIT) { + vv = PyLong_FromLong(PyInt_AS_LONG(v)); + if (vv == NULL) + return NULL; + ww = PyLong_FromLong(PyInt_AS_LONG(w)); + if (ww == NULL) { + Py_DECREF(vv); + return NULL; + } + result = PyNumber_Lshift(vv, ww); + Py_DECREF(vv); + Py_DECREF(ww); + return result; + } + c = a << b; + if (a != Py_ARITHMETIC_RIGHT_SHIFT(long, c, b)) { + vv = PyLong_FromLong(PyInt_AS_LONG(v)); + if (vv == NULL) + return NULL; + ww = PyLong_FromLong(PyInt_AS_LONG(w)); + if (ww == NULL) { + Py_DECREF(vv); + return NULL; + } + result = PyNumber_Lshift(vv, ww); + Py_DECREF(vv); + Py_DECREF(ww); + return result; + } + return PyInt_FromLong(c); +} + +static PyObject * +int_rshift(PyIntObject *v, PyIntObject *w) +{ + register long a, b; + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + if (b < 0) { + PyErr_SetString(PyExc_ValueError, "negative shift count"); + return NULL; + } + if (a == 0 || b == 0) + return int_pos(v); + if (b >= LONG_BIT) { + if (a < 0) + a = -1; + else + a = 0; + } + else { + a = Py_ARITHMETIC_RIGHT_SHIFT(long, a, b); + } + return PyInt_FromLong(a); +} + +static PyObject * +int_and(PyIntObject *v, PyIntObject *w) +{ + register long a, b; + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + return PyInt_FromLong(a & b); +} + +static PyObject * +int_xor(PyIntObject *v, PyIntObject *w) +{ + register long a, b; + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + return PyInt_FromLong(a ^ b); +} + +static PyObject * +int_or(PyIntObject *v, PyIntObject *w) +{ + register long a, b; + CONVERT_TO_LONG(v, a); + CONVERT_TO_LONG(w, b); + return PyInt_FromLong(a | b); +} + +static int +int_coerce(PyObject **pv, PyObject **pw) +{ + if (PyInt_Check(*pw)) { + Py_INCREF(*pv); + Py_INCREF(*pw); + return 0; + } + return 1; /* Can't do it */ +} + +static PyObject * +int_int(PyIntObject *v) +{ + if (PyInt_CheckExact(v)) + Py_INCREF(v); + else + v = (PyIntObject *)PyInt_FromLong(v->ob_ival); + return (PyObject *)v; +} + +static PyObject * +int_long(PyIntObject *v) +{ + return PyLong_FromLong((v -> ob_ival)); +} + +static PyObject * +int_float(PyIntObject *v) +{ + return PyFloat_FromDouble((double)(v -> ob_ival)); +} + +static PyObject * +int_oct(PyIntObject *v) +{ + char buf[100]; + long x = v -> ob_ival; + if (x < 0) + PyOS_snprintf(buf, sizeof(buf), "-0%lo", -x); + else if (x == 0) + strcpy(buf, "0"); + else + PyOS_snprintf(buf, sizeof(buf), "0%lo", x); + return PyString_FromString(buf); +} + +static PyObject * +int_hex(PyIntObject *v) +{ + char buf[100]; + long x = v -> ob_ival; + if (x < 0) + PyOS_snprintf(buf, sizeof(buf), "-0x%lx", -x); + else + PyOS_snprintf(buf, sizeof(buf), "0x%lx", x); + return PyString_FromString(buf); +} + +static PyObject * +int_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static PyObject * +int_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *x = NULL; + int base = -909; + static char *kwlist[] = {"x", "base", 0}; + + if (type != &PyInt_Type) + return int_subtype_new(type, args, kwds); /* Wimp out */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:int", kwlist, + &x, &base)) + return NULL; + if (x == NULL) + return PyInt_FromLong(0L); + if (base == -909) + return PyNumber_Int(x); + if (PyString_Check(x)) { + /* Since PyInt_FromString doesn't have a length parameter, + * check here for possible NULs in the string. */ + char *string = PyString_AS_STRING(x); + if (strlen(string) != PyString_Size(x)) { + /* create a repr() of the input string, + * just like PyInt_FromString does */ + PyObject *srepr; + srepr = PyObject_Repr(x); + if (srepr == NULL) + return NULL; + PyErr_Format(PyExc_ValueError, + "invalid literal for int() with base %d: %s", + base, PyString_AS_STRING(srepr)); + Py_DECREF(srepr); + return NULL; + } + return PyInt_FromString(string, NULL, base); + } +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(x)) + return PyInt_FromUnicode(PyUnicode_AS_UNICODE(x), + PyUnicode_GET_SIZE(x), + base); +#endif + PyErr_SetString(PyExc_TypeError, + "int() can't convert non-string with explicit base"); + return NULL; +} + +/* Wimpy, slow approach to tp_new calls for subtypes of int: + first create a regular int from whatever arguments we got, + then allocate a subtype instance and initialize its ob_ival + from the regular int. The regular int is then thrown away. +*/ +static PyObject * +int_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *tmp, *newobj; + long ival; + + assert(PyType_IsSubtype(type, &PyInt_Type)); + tmp = int_new(&PyInt_Type, args, kwds); + if (tmp == NULL) + return NULL; + if (!PyInt_Check(tmp)) { + ival = PyLong_AsLong(tmp); + if (ival == -1 && PyErr_Occurred()) { + Py_DECREF(tmp); + return NULL; + } + } else { + ival = ((PyIntObject *)tmp)->ob_ival; + } + + newobj = type->tp_alloc(type, 0); + if (newobj == NULL) { + Py_DECREF(tmp); + return NULL; + } + ((PyIntObject *)newobj)->ob_ival = ival; + Py_DECREF(tmp); + return newobj; +} + +static PyObject * +int_getnewargs(PyIntObject *v) +{ + return Py_BuildValue("(l)", v->ob_ival); +} + +static PyMethodDef int_methods[] = { + {"__getnewargs__", (PyCFunction)int_getnewargs, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(int_doc, +"int(x[, base]) -> integer\n\ +\n\ +Convert a string or number to an integer, if possible. A floating point\n\ +argument will be truncated towards zero (this does not include a string\n\ +representation of a floating point number!) When converting a string, use\n\ +the optional base. It is an error to supply a base when converting a\n\ +non-string. If the argument is outside the integer range a long object\n\ +will be returned instead."); + +static PyNumberMethods int_as_number = { + (binaryfunc)int_add, /*nb_add*/ + (binaryfunc)int_sub, /*nb_subtract*/ + (binaryfunc)int_mul, /*nb_multiply*/ + (binaryfunc)int_classic_div, /*nb_divide*/ + (binaryfunc)int_mod, /*nb_remainder*/ + (binaryfunc)int_divmod, /*nb_divmod*/ + (ternaryfunc)int_pow, /*nb_power*/ + (unaryfunc)int_neg, /*nb_negative*/ + (unaryfunc)int_pos, /*nb_positive*/ + (unaryfunc)int_abs, /*nb_absolute*/ + (inquiry)int_nonzero, /*nb_nonzero*/ + (unaryfunc)int_invert, /*nb_invert*/ + (binaryfunc)int_lshift, /*nb_lshift*/ + (binaryfunc)int_rshift, /*nb_rshift*/ + (binaryfunc)int_and, /*nb_and*/ + (binaryfunc)int_xor, /*nb_xor*/ + (binaryfunc)int_or, /*nb_or*/ + int_coerce, /*nb_coerce*/ + (unaryfunc)int_int, /*nb_int*/ + (unaryfunc)int_long, /*nb_long*/ + (unaryfunc)int_float, /*nb_float*/ + (unaryfunc)int_oct, /*nb_oct*/ + (unaryfunc)int_hex, /*nb_hex*/ + 0, /*nb_inplace_add*/ + 0, /*nb_inplace_subtract*/ + 0, /*nb_inplace_multiply*/ + 0, /*nb_inplace_divide*/ + 0, /*nb_inplace_remainder*/ + 0, /*nb_inplace_power*/ + 0, /*nb_inplace_lshift*/ + 0, /*nb_inplace_rshift*/ + 0, /*nb_inplace_and*/ + 0, /*nb_inplace_xor*/ + 0, /*nb_inplace_or*/ + (binaryfunc)int_div, /* nb_floor_divide */ + int_true_divide, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + (unaryfunc)int_int, /* nb_index */ +}; + +PyTypeObject PyInt_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "int", + sizeof(PyIntObject), + 0, + (destructor)int_dealloc, /* tp_dealloc */ + (printfunc)int_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)int_compare, /* tp_compare */ + (reprfunc)int_repr, /* tp_repr */ + &int_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)int_hash, /* tp_hash */ + 0, /* tp_call */ + (reprfunc)int_repr, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + int_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + int_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + int_new, /* tp_new */ + (freefunc)int_free, /* tp_free */ +}; + +int +_PyInt_Init(void) +{ + PyIntObject *v; + int ival; +#if NSMALLNEGINTS + NSMALLPOSINTS > 0 + for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++) { + if (!free_list && (free_list = fill_free_list()) == NULL) + return 0; + /* PyObject_New is inlined */ + v = free_list; + free_list = (PyIntObject *)v->ob_type; + PyObject_INIT(v, &PyInt_Type); + v->ob_ival = ival; + small_ints[ival + NSMALLNEGINTS] = v; + } +#endif + return 1; +} + +void +PyInt_Fini(void) +{ + PyIntObject *p; + PyIntBlock *list, *next; + int i; + unsigned int ctr; + int bc, bf; /* block count, number of freed blocks */ + int irem, isum; /* remaining unfreed ints per block, total */ + +#if NSMALLNEGINTS + NSMALLPOSINTS > 0 + PyIntObject **q; + + i = NSMALLNEGINTS + NSMALLPOSINTS; + q = small_ints; + while (--i >= 0) { + Py_XDECREF(*q); + *q++ = NULL; + } +#endif + bc = 0; + bf = 0; + isum = 0; + list = block_list; + block_list = NULL; + free_list = NULL; + while (list != NULL) { + bc++; + irem = 0; + for (ctr = 0, p = &list->objects[0]; + ctr < N_INTOBJECTS; + ctr++, p++) { + if (PyInt_CheckExact(p) && p->ob_refcnt != 0) + irem++; + } + next = list->next; + if (irem) { + list->next = block_list; + block_list = list; + for (ctr = 0, p = &list->objects[0]; + ctr < N_INTOBJECTS; + ctr++, p++) { + if (!PyInt_CheckExact(p) || + p->ob_refcnt == 0) { + p->ob_type = (struct _typeobject *) + free_list; + free_list = p; + } +#if NSMALLNEGINTS + NSMALLPOSINTS > 0 + else if (-NSMALLNEGINTS <= p->ob_ival && + p->ob_ival < NSMALLPOSINTS && + small_ints[p->ob_ival + + NSMALLNEGINTS] == NULL) { + Py_INCREF(p); + small_ints[p->ob_ival + + NSMALLNEGINTS] = p; + } +#endif + } + } + else { + PyMem_FREE(list); + bf++; + } + isum += irem; + list = next; + } + if (!Py_VerboseFlag) + return; + fprintf(stderr, "# cleanup ints"); + if (!isum) { + fprintf(stderr, "\n"); + } + else { + fprintf(stderr, + ": %d unfreed int%s in %d out of %d block%s\n", + isum, isum == 1 ? "" : "s", + bc - bf, bc, bc == 1 ? "" : "s"); + } + if (Py_VerboseFlag > 1) { + list = block_list; + while (list != NULL) { + for (ctr = 0, p = &list->objects[0]; + ctr < N_INTOBJECTS; + ctr++, p++) { + if (PyInt_CheckExact(p) && p->ob_refcnt != 0) + /* XXX(twouters) cast refcount to + long until %zd is universally + available + */ + fprintf(stderr, + "# <int at %p, refcnt=%ld, val=%ld>\n", + p, (long)p->ob_refcnt, + p->ob_ival); + } + list = list->next; + } + } +} diff --git a/sys/src/cmd/python/Objects/iterobject.c b/sys/src/cmd/python/Objects/iterobject.c new file mode 100644 index 000000000..cf839f478 --- /dev/null +++ b/sys/src/cmd/python/Objects/iterobject.c @@ -0,0 +1,232 @@ +/* Iterator objects */ + +#include "Python.h" + +typedef struct { + PyObject_HEAD + long it_index; + PyObject *it_seq; /* Set to NULL when iterator is exhausted */ +} seqiterobject; + +PyObject * +PySeqIter_New(PyObject *seq) +{ + seqiterobject *it; + + if (!PySequence_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); + if (it == NULL) + return NULL; + it->it_index = 0; + Py_INCREF(seq); + it->it_seq = seq; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} + +static void +iter_dealloc(seqiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); +} + +static int +iter_traverse(seqiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_seq); + return 0; +} + +static PyObject * +iter_iternext(PyObject *iterator) +{ + seqiterobject *it; + PyObject *seq; + PyObject *result; + + assert(PySeqIter_Check(iterator)); + it = (seqiterobject *)iterator; + seq = it->it_seq; + if (seq == NULL) + return NULL; + + result = PySequence_GetItem(seq, it->it_index); + if (result != NULL) { + it->it_index++; + return result; + } + if (PyErr_ExceptionMatches(PyExc_IndexError) || + PyErr_ExceptionMatches(PyExc_StopIteration)) + { + PyErr_Clear(); + Py_DECREF(seq); + it->it_seq = NULL; + } + return NULL; +} + +static PyObject * +iter_len(seqiterobject *it) +{ + Py_ssize_t seqsize, len; + + if (it->it_seq) { + seqsize = PySequence_Size(it->it_seq); + if (seqsize == -1) + return NULL; + len = seqsize - it->it_index; + if (len >= 0) + return PyInt_FromSsize_t(len); + } + return PyInt_FromLong(0); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef seqiter_methods[] = { + {"__length_hint__", (PyCFunction)iter_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyTypeObject PySeqIter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "iterator", /* tp_name */ + sizeof(seqiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)iter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)iter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + iter_iternext, /* tp_iternext */ + seqiter_methods, /* tp_methods */ + 0, /* tp_members */ +}; + +/* -------------------------------------- */ + +typedef struct { + PyObject_HEAD + PyObject *it_callable; /* Set to NULL when iterator is exhausted */ + PyObject *it_sentinel; /* Set to NULL when iterator is exhausted */ +} calliterobject; + +PyObject * +PyCallIter_New(PyObject *callable, PyObject *sentinel) +{ + calliterobject *it; + it = PyObject_GC_New(calliterobject, &PyCallIter_Type); + if (it == NULL) + return NULL; + Py_INCREF(callable); + it->it_callable = callable; + Py_INCREF(sentinel); + it->it_sentinel = sentinel; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} +static void +calliter_dealloc(calliterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_callable); + Py_XDECREF(it->it_sentinel); + PyObject_GC_Del(it); +} + +static int +calliter_traverse(calliterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_callable); + Py_VISIT(it->it_sentinel); + return 0; +} + +static PyObject * +calliter_iternext(calliterobject *it) +{ + if (it->it_callable != NULL) { + PyObject *args = PyTuple_New(0); + PyObject *result; + if (args == NULL) + return NULL; + result = PyObject_Call(it->it_callable, args, NULL); + Py_DECREF(args); + if (result != NULL) { + int ok; + ok = PyObject_RichCompareBool(result, + it->it_sentinel, + Py_EQ); + if (ok == 0) + return result; /* Common case, fast path */ + Py_DECREF(result); + if (ok > 0) { + Py_CLEAR(it->it_callable); + Py_CLEAR(it->it_sentinel); + } + } + else if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + PyErr_Clear(); + Py_CLEAR(it->it_callable); + Py_CLEAR(it->it_sentinel); + } + } + return NULL; +} + +PyTypeObject PyCallIter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "callable-iterator", /* tp_name */ + sizeof(calliterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)calliter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)calliter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)calliter_iternext, /* tp_iternext */ + 0, /* tp_methods */ +}; diff --git a/sys/src/cmd/python/Objects/listobject.c b/sys/src/cmd/python/Objects/listobject.c new file mode 100644 index 000000000..739a571b9 --- /dev/null +++ b/sys/src/cmd/python/Objects/listobject.c @@ -0,0 +1,2930 @@ +/* List object implementation */ + +#include "Python.h" + +#ifdef STDC_HEADERS +#include <stddef.h> +#else +#include <sys/types.h> /* For size_t */ +#endif + +/* Ensure ob_item has room for at least newsize elements, and set + * ob_size to newsize. If newsize > ob_size on entry, the content + * of the new slots at exit is undefined heap trash; it's the caller's + * responsiblity to overwrite them with sane values. + * The number of allocated elements may grow, shrink, or stay the same. + * Failure is impossible if newsize <= self.allocated on entry, although + * that partly relies on an assumption that the system realloc() never + * fails when passed a number of bytes <= the number of bytes last + * allocated (the C standard doesn't guarantee this, but it's hard to + * imagine a realloc implementation where it wouldn't be true). + * Note that self->ob_item may change, and even if newsize is less + * than ob_size on entry. + */ +static int +list_resize(PyListObject *self, Py_ssize_t newsize) +{ + PyObject **items; + size_t new_allocated; + Py_ssize_t allocated = self->allocated; + + /* Bypass realloc() when a previous overallocation is large enough + to accommodate the newsize. If the newsize falls lower than half + the allocated size, then proceed with the realloc() to shrink the list. + */ + if (allocated >= newsize && newsize >= (allocated >> 1)) { + assert(self->ob_item != NULL || newsize == 0); + self->ob_size = newsize; + return 0; + } + + /* This over-allocates proportional to the list size, making room + * for additional growth. The over-allocation is mild, but is + * enough to give linear-time amortized behavior over a long + * sequence of appends() in the presence of a poorly-performing + * system realloc(). + * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... + */ + new_allocated = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; + if (newsize == 0) + new_allocated = 0; + items = self->ob_item; + if (new_allocated <= ((~(size_t)0) / sizeof(PyObject *))) + PyMem_RESIZE(items, PyObject *, new_allocated); + else + items = NULL; + if (items == NULL) { + PyErr_NoMemory(); + return -1; + } + self->ob_item = items; + self->ob_size = newsize; + self->allocated = new_allocated; + return 0; +} + +/* Empty list reuse scheme to save calls to malloc and free */ +#define MAXFREELISTS 80 +static PyListObject *free_lists[MAXFREELISTS]; +static int num_free_lists = 0; + +void +PyList_Fini(void) +{ + PyListObject *op; + + while (num_free_lists) { + num_free_lists--; + op = free_lists[num_free_lists]; + assert(PyList_CheckExact(op)); + PyObject_GC_Del(op); + } +} + +PyObject * +PyList_New(Py_ssize_t size) +{ + PyListObject *op; + size_t nbytes; + + if (size < 0) { + PyErr_BadInternalCall(); + return NULL; + } + nbytes = size * sizeof(PyObject *); + /* Check for overflow */ + if (nbytes / sizeof(PyObject *) != (size_t)size) + return PyErr_NoMemory(); + if (num_free_lists) { + num_free_lists--; + op = free_lists[num_free_lists]; + _Py_NewReference((PyObject *)op); + } else { + op = PyObject_GC_New(PyListObject, &PyList_Type); + if (op == NULL) + return NULL; + } + if (size <= 0) + op->ob_item = NULL; + else { + op->ob_item = (PyObject **) PyMem_MALLOC(nbytes); + if (op->ob_item == NULL) { + Py_DECREF(op); + return PyErr_NoMemory(); + } + memset(op->ob_item, 0, nbytes); + } + op->ob_size = size; + op->allocated = size; + _PyObject_GC_TRACK(op); + return (PyObject *) op; +} + +Py_ssize_t +PyList_Size(PyObject *op) +{ + if (!PyList_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + else + return ((PyListObject *)op) -> ob_size; +} + +static PyObject *indexerr = NULL; + +PyObject * +PyList_GetItem(PyObject *op, Py_ssize_t i) +{ + if (!PyList_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { + if (indexerr == NULL) + indexerr = PyString_FromString( + "list index out of range"); + PyErr_SetObject(PyExc_IndexError, indexerr); + return NULL; + } + return ((PyListObject *)op) -> ob_item[i]; +} + +int +PyList_SetItem(register PyObject *op, register Py_ssize_t i, + register PyObject *newitem) +{ + register PyObject *olditem; + register PyObject **p; + if (!PyList_Check(op)) { + Py_XDECREF(newitem); + PyErr_BadInternalCall(); + return -1; + } + if (i < 0 || i >= ((PyListObject *)op) -> ob_size) { + Py_XDECREF(newitem); + PyErr_SetString(PyExc_IndexError, + "list assignment index out of range"); + return -1; + } + p = ((PyListObject *)op) -> ob_item + i; + olditem = *p; + *p = newitem; + Py_XDECREF(olditem); + return 0; +} + +static int +ins1(PyListObject *self, Py_ssize_t where, PyObject *v) +{ + Py_ssize_t i, n = self->ob_size; + PyObject **items; + if (v == NULL) { + PyErr_BadInternalCall(); + return -1; + } + if (n == PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "cannot add more objects to list"); + return -1; + } + + if (list_resize(self, n+1) == -1) + return -1; + + if (where < 0) { + where += n; + if (where < 0) + where = 0; + } + if (where > n) + where = n; + items = self->ob_item; + for (i = n; --i >= where; ) + items[i+1] = items[i]; + Py_INCREF(v); + items[where] = v; + return 0; +} + +int +PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem) +{ + if (!PyList_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + return ins1((PyListObject *)op, where, newitem); +} + +static int +app1(PyListObject *self, PyObject *v) +{ + Py_ssize_t n = PyList_GET_SIZE(self); + + assert (v != NULL); + if (n == PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "cannot add more objects to list"); + return -1; + } + + if (list_resize(self, n+1) == -1) + return -1; + + Py_INCREF(v); + PyList_SET_ITEM(self, n, v); + return 0; +} + +int +PyList_Append(PyObject *op, PyObject *newitem) +{ + if (PyList_Check(op) && (newitem != NULL)) + return app1((PyListObject *)op, newitem); + PyErr_BadInternalCall(); + return -1; +} + +/* Methods */ + +static void +list_dealloc(PyListObject *op) +{ + Py_ssize_t i; + PyObject_GC_UnTrack(op); + Py_TRASHCAN_SAFE_BEGIN(op) + if (op->ob_item != NULL) { + /* Do it backwards, for Christian Tismer. + There's a simple test case where somehow this reduces + thrashing when a *very* large list is created and + immediately deleted. */ + i = op->ob_size; + while (--i >= 0) { + Py_XDECREF(op->ob_item[i]); + } + PyMem_FREE(op->ob_item); + } + if (num_free_lists < MAXFREELISTS && PyList_CheckExact(op)) + free_lists[num_free_lists++] = op; + else + op->ob_type->tp_free((PyObject *)op); + Py_TRASHCAN_SAFE_END(op) +} + +static int +list_print(PyListObject *op, FILE *fp, int flags) +{ + int rc; + Py_ssize_t i; + + rc = Py_ReprEnter((PyObject*)op); + if (rc != 0) { + if (rc < 0) + return rc; + fprintf(fp, "[...]"); + return 0; + } + fprintf(fp, "["); + for (i = 0; i < op->ob_size; i++) { + if (i > 0) + fprintf(fp, ", "); + if (PyObject_Print(op->ob_item[i], fp, 0) != 0) { + Py_ReprLeave((PyObject *)op); + return -1; + } + } + fprintf(fp, "]"); + Py_ReprLeave((PyObject *)op); + return 0; +} + +static PyObject * +list_repr(PyListObject *v) +{ + Py_ssize_t i; + PyObject *s, *temp; + PyObject *pieces = NULL, *result = NULL; + + i = Py_ReprEnter((PyObject*)v); + if (i != 0) { + return i > 0 ? PyString_FromString("[...]") : NULL; + } + + if (v->ob_size == 0) { + result = PyString_FromString("[]"); + goto Done; + } + + pieces = PyList_New(0); + if (pieces == NULL) + goto Done; + + /* Do repr() on each element. Note that this may mutate the list, + so must refetch the list size on each iteration. */ + for (i = 0; i < v->ob_size; ++i) { + int status; + s = PyObject_Repr(v->ob_item[i]); + if (s == NULL) + goto Done; + status = PyList_Append(pieces, s); + Py_DECREF(s); /* append created a new ref */ + if (status < 0) + goto Done; + } + + /* Add "[]" decorations to the first and last items. */ + assert(PyList_GET_SIZE(pieces) > 0); + s = PyString_FromString("["); + if (s == NULL) + goto Done; + temp = PyList_GET_ITEM(pieces, 0); + PyString_ConcatAndDel(&s, temp); + PyList_SET_ITEM(pieces, 0, s); + if (s == NULL) + goto Done; + + s = PyString_FromString("]"); + if (s == NULL) + goto Done; + temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1); + PyString_ConcatAndDel(&temp, s); + PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces) - 1, temp); + if (temp == NULL) + goto Done; + + /* Paste them all together with ", " between. */ + s = PyString_FromString(", "); + if (s == NULL) + goto Done; + result = _PyString_Join(s, pieces); + Py_DECREF(s); + +Done: + Py_XDECREF(pieces); + Py_ReprLeave((PyObject *)v); + return result; +} + +static Py_ssize_t +list_length(PyListObject *a) +{ + return a->ob_size; +} + +static int +list_contains(PyListObject *a, PyObject *el) +{ + Py_ssize_t i; + int cmp; + + for (i = 0, cmp = 0 ; cmp == 0 && i < a->ob_size; ++i) + cmp = PyObject_RichCompareBool(el, PyList_GET_ITEM(a, i), + Py_EQ); + return cmp; +} + +static PyObject * +list_item(PyListObject *a, Py_ssize_t i) +{ + if (i < 0 || i >= a->ob_size) { + if (indexerr == NULL) + indexerr = PyString_FromString( + "list index out of range"); + PyErr_SetObject(PyExc_IndexError, indexerr); + return NULL; + } + Py_INCREF(a->ob_item[i]); + return a->ob_item[i]; +} + +static PyObject * +list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh) +{ + PyListObject *np; + PyObject **src, **dest; + Py_ssize_t i, len; + if (ilow < 0) + ilow = 0; + else if (ilow > a->ob_size) + ilow = a->ob_size; + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > a->ob_size) + ihigh = a->ob_size; + len = ihigh - ilow; + np = (PyListObject *) PyList_New(len); + if (np == NULL) + return NULL; + + src = a->ob_item + ilow; + dest = np->ob_item; + for (i = 0; i < len; i++) { + PyObject *v = src[i]; + Py_INCREF(v); + dest[i] = v; + } + return (PyObject *)np; +} + +PyObject * +PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh) +{ + if (!PyList_Check(a)) { + PyErr_BadInternalCall(); + return NULL; + } + return list_slice((PyListObject *)a, ilow, ihigh); +} + +static PyObject * +list_concat(PyListObject *a, PyObject *bb) +{ + Py_ssize_t size; + Py_ssize_t i; + PyObject **src, **dest; + PyListObject *np; + if (!PyList_Check(bb)) { + PyErr_Format(PyExc_TypeError, + "can only concatenate list (not \"%.200s\") to list", + bb->ob_type->tp_name); + return NULL; + } +#define b ((PyListObject *)bb) + size = a->ob_size + b->ob_size; + if (size < 0) + return PyErr_NoMemory(); + np = (PyListObject *) PyList_New(size); + if (np == NULL) { + return NULL; + } + src = a->ob_item; + dest = np->ob_item; + for (i = 0; i < a->ob_size; i++) { + PyObject *v = src[i]; + Py_INCREF(v); + dest[i] = v; + } + src = b->ob_item; + dest = np->ob_item + a->ob_size; + for (i = 0; i < b->ob_size; i++) { + PyObject *v = src[i]; + Py_INCREF(v); + dest[i] = v; + } + return (PyObject *)np; +#undef b +} + +static PyObject * +list_repeat(PyListObject *a, Py_ssize_t n) +{ + Py_ssize_t i, j; + Py_ssize_t size; + PyListObject *np; + PyObject **p, **items; + PyObject *elem; + if (n < 0) + n = 0; + size = a->ob_size * n; + if (size == 0) + return PyList_New(0); + if (n && size/n != a->ob_size) + return PyErr_NoMemory(); + np = (PyListObject *) PyList_New(size); + if (np == NULL) + return NULL; + + items = np->ob_item; + if (a->ob_size == 1) { + elem = a->ob_item[0]; + for (i = 0; i < n; i++) { + items[i] = elem; + Py_INCREF(elem); + } + return (PyObject *) np; + } + p = np->ob_item; + items = a->ob_item; + for (i = 0; i < n; i++) { + for (j = 0; j < a->ob_size; j++) { + *p = items[j]; + Py_INCREF(*p); + p++; + } + } + return (PyObject *) np; +} + +static int +list_clear(PyListObject *a) +{ + Py_ssize_t i; + PyObject **item = a->ob_item; + if (item != NULL) { + /* Because XDECREF can recursively invoke operations on + this list, we make it empty first. */ + i = a->ob_size; + a->ob_size = 0; + a->ob_item = NULL; + a->allocated = 0; + while (--i >= 0) { + Py_XDECREF(item[i]); + } + PyMem_FREE(item); + } + /* Never fails; the return value can be ignored. + Note that there is no guarantee that the list is actually empty + at this point, because XDECREF may have populated it again! */ + return 0; +} + +/* a[ilow:ihigh] = v if v != NULL. + * del a[ilow:ihigh] if v == NULL. + * + * Special speed gimmick: when v is NULL and ihigh - ilow <= 8, it's + * guaranteed the call cannot fail. + */ +static int +list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) +{ + /* Because [X]DECREF can recursively invoke list operations on + this list, we must postpone all [X]DECREF activity until + after the list is back in its canonical shape. Therefore + we must allocate an additional array, 'recycle', into which + we temporarily copy the items that are deleted from the + list. :-( */ + PyObject *recycle_on_stack[8]; + PyObject **recycle = recycle_on_stack; /* will allocate more if needed */ + PyObject **item; + PyObject **vitem = NULL; + PyObject *v_as_SF = NULL; /* PySequence_Fast(v) */ + Py_ssize_t n; /* # of elements in replacement list */ + Py_ssize_t norig; /* # of elements in list getting replaced */ + Py_ssize_t d; /* Change in size */ + Py_ssize_t k; + size_t s; + int result = -1; /* guilty until proved innocent */ +#define b ((PyListObject *)v) + if (v == NULL) + n = 0; + else { + if (a == b) { + /* Special case "a[i:j] = a" -- copy b first */ + v = list_slice(b, 0, b->ob_size); + if (v == NULL) + return result; + result = list_ass_slice(a, ilow, ihigh, v); + Py_DECREF(v); + return result; + } + v_as_SF = PySequence_Fast(v, "can only assign an iterable"); + if(v_as_SF == NULL) + goto Error; + n = PySequence_Fast_GET_SIZE(v_as_SF); + vitem = PySequence_Fast_ITEMS(v_as_SF); + } + if (ilow < 0) + ilow = 0; + else if (ilow > a->ob_size) + ilow = a->ob_size; + + if (ihigh < ilow) + ihigh = ilow; + else if (ihigh > a->ob_size) + ihigh = a->ob_size; + + norig = ihigh - ilow; + assert(norig >= 0); + d = n - norig; + if (a->ob_size + d == 0) { + Py_XDECREF(v_as_SF); + return list_clear(a); + } + item = a->ob_item; + /* recycle the items that we are about to remove */ + s = norig * sizeof(PyObject *); + if (s > sizeof(recycle_on_stack)) { + recycle = (PyObject **)PyMem_MALLOC(s); + if (recycle == NULL) { + PyErr_NoMemory(); + goto Error; + } + } + memcpy(recycle, &item[ilow], s); + + if (d < 0) { /* Delete -d items */ + memmove(&item[ihigh+d], &item[ihigh], + (a->ob_size - ihigh)*sizeof(PyObject *)); + list_resize(a, a->ob_size + d); + item = a->ob_item; + } + else if (d > 0) { /* Insert d items */ + k = a->ob_size; + if (list_resize(a, k+d) < 0) + goto Error; + item = a->ob_item; + memmove(&item[ihigh+d], &item[ihigh], + (k - ihigh)*sizeof(PyObject *)); + } + for (k = 0; k < n; k++, ilow++) { + PyObject *w = vitem[k]; + Py_XINCREF(w); + item[ilow] = w; + } + for (k = norig - 1; k >= 0; --k) + Py_XDECREF(recycle[k]); + result = 0; + Error: + if (recycle != recycle_on_stack) + PyMem_FREE(recycle); + Py_XDECREF(v_as_SF); + return result; +#undef b +} + +int +PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) +{ + if (!PyList_Check(a)) { + PyErr_BadInternalCall(); + return -1; + } + return list_ass_slice((PyListObject *)a, ilow, ihigh, v); +} + +static PyObject * +list_inplace_repeat(PyListObject *self, Py_ssize_t n) +{ + PyObject **items; + Py_ssize_t size, i, j, p; + + + size = PyList_GET_SIZE(self); + if (size == 0) { + Py_INCREF(self); + return (PyObject *)self; + } + + if (n < 1) { + (void)list_clear(self); + Py_INCREF(self); + return (PyObject *)self; + } + + if (list_resize(self, size*n) == -1) + return NULL; + + p = size; + items = self->ob_item; + for (i = 1; i < n; i++) { /* Start counting at 1, not 0 */ + for (j = 0; j < size; j++) { + PyObject *o = items[j]; + Py_INCREF(o); + items[p++] = o; + } + } + Py_INCREF(self); + return (PyObject *)self; +} + +static int +list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v) +{ + PyObject *old_value; + if (i < 0 || i >= a->ob_size) { + PyErr_SetString(PyExc_IndexError, + "list assignment index out of range"); + return -1; + } + if (v == NULL) + return list_ass_slice(a, i, i+1, v); + Py_INCREF(v); + old_value = a->ob_item[i]; + a->ob_item[i] = v; + Py_DECREF(old_value); + return 0; +} + +static PyObject * +listinsert(PyListObject *self, PyObject *args) +{ + Py_ssize_t i; + PyObject *v; + if (!PyArg_ParseTuple(args, "nO:insert", &i, &v)) + return NULL; + if (ins1(self, i, v) == 0) + Py_RETURN_NONE; + return NULL; +} + +static PyObject * +listappend(PyListObject *self, PyObject *v) +{ + if (app1(self, v) == 0) + Py_RETURN_NONE; + return NULL; +} + +static PyObject * +listextend(PyListObject *self, PyObject *b) +{ + PyObject *it; /* iter(v) */ + Py_ssize_t m; /* size of self */ + Py_ssize_t n; /* guess for size of b */ + Py_ssize_t mn; /* m + n */ + Py_ssize_t i; + PyObject *(*iternext)(PyObject *); + + /* Special cases: + 1) lists and tuples which can use PySequence_Fast ops + 2) extending self to self requires making a copy first + */ + if (PyList_CheckExact(b) || PyTuple_CheckExact(b) || (PyObject *)self == b) { + PyObject **src, **dest; + b = PySequence_Fast(b, "argument must be iterable"); + if (!b) + return NULL; + n = PySequence_Fast_GET_SIZE(b); + if (n == 0) { + /* short circuit when b is empty */ + Py_DECREF(b); + Py_RETURN_NONE; + } + m = self->ob_size; + if (list_resize(self, m + n) == -1) { + Py_DECREF(b); + return NULL; + } + /* note that we may still have self == b here for the + * situation a.extend(a), but the following code works + * in that case too. Just make sure to resize self + * before calling PySequence_Fast_ITEMS. + */ + /* populate the end of self with b's items */ + src = PySequence_Fast_ITEMS(b); + dest = self->ob_item + m; + for (i = 0; i < n; i++) { + PyObject *o = src[i]; + Py_INCREF(o); + dest[i] = o; + } + Py_DECREF(b); + Py_RETURN_NONE; + } + + it = PyObject_GetIter(b); + if (it == NULL) + return NULL; + iternext = *it->ob_type->tp_iternext; + + /* Guess a result list size. */ + n = _PyObject_LengthHint(b); + if (n < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(it); + return NULL; + } + PyErr_Clear(); + n = 8; /* arbitrary */ + } + m = self->ob_size; + mn = m + n; + if (mn >= m) { + /* Make room. */ + if (list_resize(self, mn) == -1) + goto error; + /* Make the list sane again. */ + self->ob_size = m; + } + /* Else m + n overflowed; on the chance that n lied, and there really + * is enough room, ignore it. If n was telling the truth, we'll + * eventually run out of memory during the loop. + */ + + /* Run iterator to exhaustion. */ + for (;;) { + PyObject *item = iternext(it); + if (item == NULL) { + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + else + goto error; + } + break; + } + if (self->ob_size < self->allocated) { + /* steals ref */ + PyList_SET_ITEM(self, self->ob_size, item); + ++self->ob_size; + } + else { + int status = app1(self, item); + Py_DECREF(item); /* append creates a new ref */ + if (status < 0) + goto error; + } + } + + /* Cut back result list if initial guess was too large. */ + if (self->ob_size < self->allocated) + list_resize(self, self->ob_size); /* shrinking can't fail */ + + Py_DECREF(it); + Py_RETURN_NONE; + + error: + Py_DECREF(it); + return NULL; +} + +PyObject * +_PyList_Extend(PyListObject *self, PyObject *b) +{ + return listextend(self, b); +} + +static PyObject * +list_inplace_concat(PyListObject *self, PyObject *other) +{ + PyObject *result; + + result = listextend(self, other); + if (result == NULL) + return result; + Py_DECREF(result); + Py_INCREF(self); + return (PyObject *)self; +} + +static PyObject * +listpop(PyListObject *self, PyObject *args) +{ + Py_ssize_t i = -1; + PyObject *v; + int status; + + if (!PyArg_ParseTuple(args, "|n:pop", &i)) + return NULL; + + if (self->ob_size == 0) { + /* Special-case most common failure cause */ + PyErr_SetString(PyExc_IndexError, "pop from empty list"); + return NULL; + } + if (i < 0) + i += self->ob_size; + if (i < 0 || i >= self->ob_size) { + PyErr_SetString(PyExc_IndexError, "pop index out of range"); + return NULL; + } + v = self->ob_item[i]; + if (i == self->ob_size - 1) { + status = list_resize(self, self->ob_size - 1); + assert(status >= 0); + return v; /* and v now owns the reference the list had */ + } + Py_INCREF(v); + status = list_ass_slice(self, i, i+1, (PyObject *)NULL); + assert(status >= 0); + /* Use status, so that in a release build compilers don't + * complain about the unused name. + */ + (void) status; + + return v; +} + +/* Reverse a slice of a list in place, from lo up to (exclusive) hi. */ +static void +reverse_slice(PyObject **lo, PyObject **hi) +{ + assert(lo && hi); + + --hi; + while (lo < hi) { + PyObject *t = *lo; + *lo = *hi; + *hi = t; + ++lo; + --hi; + } +} + +/* Lots of code for an adaptive, stable, natural mergesort. There are many + * pieces to this algorithm; read listsort.txt for overviews and details. + */ + +/* Comparison function. Takes care of calling a user-supplied + * comparison function (any callable Python object), which must not be + * NULL (use the ISLT macro if you don't know, or call PyObject_RichCompareBool + * with Py_LT if you know it's NULL). + * Returns -1 on error, 1 if x < y, 0 if x >= y. + */ +static int +islt(PyObject *x, PyObject *y, PyObject *compare) +{ + PyObject *res; + PyObject *args; + Py_ssize_t i; + + assert(compare != NULL); + /* Call the user's comparison function and translate the 3-way + * result into true or false (or error). + */ + args = PyTuple_New(2); + if (args == NULL) + return -1; + Py_INCREF(x); + Py_INCREF(y); + PyTuple_SET_ITEM(args, 0, x); + PyTuple_SET_ITEM(args, 1, y); + res = PyObject_Call(compare, args, NULL); + Py_DECREF(args); + if (res == NULL) + return -1; + if (!PyInt_Check(res)) { + Py_DECREF(res); + PyErr_SetString(PyExc_TypeError, + "comparison function must return int"); + return -1; + } + i = PyInt_AsLong(res); + Py_DECREF(res); + return i < 0; +} + +/* If COMPARE is NULL, calls PyObject_RichCompareBool with Py_LT, else calls + * islt. This avoids a layer of function call in the usual case, and + * sorting does many comparisons. + * Returns -1 on error, 1 if x < y, 0 if x >= y. + */ +#define ISLT(X, Y, COMPARE) ((COMPARE) == NULL ? \ + PyObject_RichCompareBool(X, Y, Py_LT) : \ + islt(X, Y, COMPARE)) + +/* Compare X to Y via "<". Goto "fail" if the comparison raises an + error. Else "k" is set to true iff X<Y, and an "if (k)" block is + started. It makes more sense in context <wink>. X and Y are PyObject*s. +*/ +#define IFLT(X, Y) if ((k = ISLT(X, Y, compare)) < 0) goto fail; \ + if (k) + +/* binarysort is the best method for sorting small arrays: it does + few compares, but can do data movement quadratic in the number of + elements. + [lo, hi) is a contiguous slice of a list, and is sorted via + binary insertion. This sort is stable. + On entry, must have lo <= start <= hi, and that [lo, start) is already + sorted (pass start == lo if you don't know!). + If islt() complains return -1, else 0. + Even in case of error, the output slice will be some permutation of + the input (nothing is lost or duplicated). +*/ +static int +binarysort(PyObject **lo, PyObject **hi, PyObject **start, PyObject *compare) + /* compare -- comparison function object, or NULL for default */ +{ + register Py_ssize_t k; + register PyObject **l, **p, **r; + register PyObject *pivot; + + assert(lo <= start && start <= hi); + /* assert [lo, start) is sorted */ + if (lo == start) + ++start; + for (; start < hi; ++start) { + /* set l to where *start belongs */ + l = lo; + r = start; + pivot = *r; + /* Invariants: + * pivot >= all in [lo, l). + * pivot < all in [r, start). + * The second is vacuously true at the start. + */ + assert(l < r); + do { + p = l + ((r - l) >> 1); + IFLT(pivot, *p) + r = p; + else + l = p+1; + } while (l < r); + assert(l == r); + /* The invariants still hold, so pivot >= all in [lo, l) and + pivot < all in [l, start), so pivot belongs at l. Note + that if there are elements equal to pivot, l points to the + first slot after them -- that's why this sort is stable. + Slide over to make room. + Caution: using memmove is much slower under MSVC 5; + we're not usually moving many slots. */ + for (p = start; p > l; --p) + *p = *(p-1); + *l = pivot; + } + return 0; + + fail: + return -1; +} + +/* +Return the length of the run beginning at lo, in the slice [lo, hi). lo < hi +is required on entry. "A run" is the longest ascending sequence, with + + lo[0] <= lo[1] <= lo[2] <= ... + +or the longest descending sequence, with + + lo[0] > lo[1] > lo[2] > ... + +Boolean *descending is set to 0 in the former case, or to 1 in the latter. +For its intended use in a stable mergesort, the strictness of the defn of +"descending" is needed so that the caller can safely reverse a descending +sequence without violating stability (strict > ensures there are no equal +elements to get out of order). + +Returns -1 in case of error. +*/ +static Py_ssize_t +count_run(PyObject **lo, PyObject **hi, PyObject *compare, int *descending) +{ + Py_ssize_t k; + Py_ssize_t n; + + assert(lo < hi); + *descending = 0; + ++lo; + if (lo == hi) + return 1; + + n = 2; + IFLT(*lo, *(lo-1)) { + *descending = 1; + for (lo = lo+1; lo < hi; ++lo, ++n) { + IFLT(*lo, *(lo-1)) + ; + else + break; + } + } + else { + for (lo = lo+1; lo < hi; ++lo, ++n) { + IFLT(*lo, *(lo-1)) + break; + } + } + + return n; +fail: + return -1; +} + +/* +Locate the proper position of key in a sorted vector; if the vector contains +an element equal to key, return the position immediately to the left of +the leftmost equal element. [gallop_right() does the same except returns +the position to the right of the rightmost equal element (if any).] + +"a" is a sorted vector with n elements, starting at a[0]. n must be > 0. + +"hint" is an index at which to begin the search, 0 <= hint < n. The closer +hint is to the final result, the faster this runs. + +The return value is the int k in 0..n such that + + a[k-1] < key <= a[k] + +pretending that *(a-1) is minus infinity and a[n] is plus infinity. IOW, +key belongs at index k; or, IOW, the first k elements of a should precede +key, and the last n-k should follow key. + +Returns -1 on error. See listsort.txt for info on the method. +*/ +static Py_ssize_t +gallop_left(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint, PyObject *compare) +{ + Py_ssize_t ofs; + Py_ssize_t lastofs; + Py_ssize_t k; + + assert(key && a && n > 0 && hint >= 0 && hint < n); + + a += hint; + lastofs = 0; + ofs = 1; + IFLT(*a, key) { + /* a[hint] < key -- gallop right, until + * a[hint + lastofs] < key <= a[hint + ofs] + */ + const Py_ssize_t maxofs = n - hint; /* &a[n-1] is highest */ + while (ofs < maxofs) { + IFLT(a[ofs], key) { + lastofs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) /* int overflow */ + ofs = maxofs; + } + else /* key <= a[hint + ofs] */ + break; + } + if (ofs > maxofs) + ofs = maxofs; + /* Translate back to offsets relative to &a[0]. */ + lastofs += hint; + ofs += hint; + } + else { + /* key <= a[hint] -- gallop left, until + * a[hint - ofs] < key <= a[hint - lastofs] + */ + const Py_ssize_t maxofs = hint + 1; /* &a[0] is lowest */ + while (ofs < maxofs) { + IFLT(*(a-ofs), key) + break; + /* key <= a[hint - ofs] */ + lastofs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) /* int overflow */ + ofs = maxofs; + } + if (ofs > maxofs) + ofs = maxofs; + /* Translate back to positive offsets relative to &a[0]. */ + k = lastofs; + lastofs = hint - ofs; + ofs = hint - k; + } + a -= hint; + + assert(-1 <= lastofs && lastofs < ofs && ofs <= n); + /* Now a[lastofs] < key <= a[ofs], so key belongs somewhere to the + * right of lastofs but no farther right than ofs. Do a binary + * search, with invariant a[lastofs-1] < key <= a[ofs]. + */ + ++lastofs; + while (lastofs < ofs) { + Py_ssize_t m = lastofs + ((ofs - lastofs) >> 1); + + IFLT(a[m], key) + lastofs = m+1; /* a[m] < key */ + else + ofs = m; /* key <= a[m] */ + } + assert(lastofs == ofs); /* so a[ofs-1] < key <= a[ofs] */ + return ofs; + +fail: + return -1; +} + +/* +Exactly like gallop_left(), except that if key already exists in a[0:n], +finds the position immediately to the right of the rightmost equal value. + +The return value is the int k in 0..n such that + + a[k-1] <= key < a[k] + +or -1 if error. + +The code duplication is massive, but this is enough different given that +we're sticking to "<" comparisons that it's much harder to follow if +written as one routine with yet another "left or right?" flag. +*/ +static Py_ssize_t +gallop_right(PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint, PyObject *compare) +{ + Py_ssize_t ofs; + Py_ssize_t lastofs; + Py_ssize_t k; + + assert(key && a && n > 0 && hint >= 0 && hint < n); + + a += hint; + lastofs = 0; + ofs = 1; + IFLT(key, *a) { + /* key < a[hint] -- gallop left, until + * a[hint - ofs] <= key < a[hint - lastofs] + */ + const Py_ssize_t maxofs = hint + 1; /* &a[0] is lowest */ + while (ofs < maxofs) { + IFLT(key, *(a-ofs)) { + lastofs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) /* int overflow */ + ofs = maxofs; + } + else /* a[hint - ofs] <= key */ + break; + } + if (ofs > maxofs) + ofs = maxofs; + /* Translate back to positive offsets relative to &a[0]. */ + k = lastofs; + lastofs = hint - ofs; + ofs = hint - k; + } + else { + /* a[hint] <= key -- gallop right, until + * a[hint + lastofs] <= key < a[hint + ofs] + */ + const Py_ssize_t maxofs = n - hint; /* &a[n-1] is highest */ + while (ofs < maxofs) { + IFLT(key, a[ofs]) + break; + /* a[hint + ofs] <= key */ + lastofs = ofs; + ofs = (ofs << 1) + 1; + if (ofs <= 0) /* int overflow */ + ofs = maxofs; + } + if (ofs > maxofs) + ofs = maxofs; + /* Translate back to offsets relative to &a[0]. */ + lastofs += hint; + ofs += hint; + } + a -= hint; + + assert(-1 <= lastofs && lastofs < ofs && ofs <= n); + /* Now a[lastofs] <= key < a[ofs], so key belongs somewhere to the + * right of lastofs but no farther right than ofs. Do a binary + * search, with invariant a[lastofs-1] <= key < a[ofs]. + */ + ++lastofs; + while (lastofs < ofs) { + Py_ssize_t m = lastofs + ((ofs - lastofs) >> 1); + + IFLT(key, a[m]) + ofs = m; /* key < a[m] */ + else + lastofs = m+1; /* a[m] <= key */ + } + assert(lastofs == ofs); /* so a[ofs-1] <= key < a[ofs] */ + return ofs; + +fail: + return -1; +} + +/* The maximum number of entries in a MergeState's pending-runs stack. + * This is enough to sort arrays of size up to about + * 32 * phi ** MAX_MERGE_PENDING + * where phi ~= 1.618. 85 is ridiculouslylarge enough, good for an array + * with 2**64 elements. + */ +#define MAX_MERGE_PENDING 85 + +/* When we get into galloping mode, we stay there until both runs win less + * often than MIN_GALLOP consecutive times. See listsort.txt for more info. + */ +#define MIN_GALLOP 7 + +/* Avoid malloc for small temp arrays. */ +#define MERGESTATE_TEMP_SIZE 256 + +/* One MergeState exists on the stack per invocation of mergesort. It's just + * a convenient way to pass state around among the helper functions. + */ +struct s_slice { + PyObject **base; + Py_ssize_t len; +}; + +typedef struct s_MergeState { + /* The user-supplied comparison function. or NULL if none given. */ + PyObject *compare; + + /* This controls when we get *into* galloping mode. It's initialized + * to MIN_GALLOP. merge_lo and merge_hi tend to nudge it higher for + * random data, and lower for highly structured data. + */ + Py_ssize_t min_gallop; + + /* 'a' is temp storage to help with merges. It contains room for + * alloced entries. + */ + PyObject **a; /* may point to temparray below */ + Py_ssize_t alloced; + + /* A stack of n pending runs yet to be merged. Run #i starts at + * address base[i] and extends for len[i] elements. It's always + * true (so long as the indices are in bounds) that + * + * pending[i].base + pending[i].len == pending[i+1].base + * + * so we could cut the storage for this, but it's a minor amount, + * and keeping all the info explicit simplifies the code. + */ + int n; + struct s_slice pending[MAX_MERGE_PENDING]; + + /* 'a' points to this when possible, rather than muck with malloc. */ + PyObject *temparray[MERGESTATE_TEMP_SIZE]; +} MergeState; + +/* Conceptually a MergeState's constructor. */ +static void +merge_init(MergeState *ms, PyObject *compare) +{ + assert(ms != NULL); + ms->compare = compare; + ms->a = ms->temparray; + ms->alloced = MERGESTATE_TEMP_SIZE; + ms->n = 0; + ms->min_gallop = MIN_GALLOP; +} + +/* Free all the temp memory owned by the MergeState. This must be called + * when you're done with a MergeState, and may be called before then if + * you want to free the temp memory early. + */ +static void +merge_freemem(MergeState *ms) +{ + assert(ms != NULL); + if (ms->a != ms->temparray) + PyMem_Free(ms->a); + ms->a = ms->temparray; + ms->alloced = MERGESTATE_TEMP_SIZE; +} + +/* Ensure enough temp memory for 'need' array slots is available. + * Returns 0 on success and -1 if the memory can't be gotten. + */ +static int +merge_getmem(MergeState *ms, Py_ssize_t need) +{ + assert(ms != NULL); + if (need <= ms->alloced) + return 0; + /* Don't realloc! That can cost cycles to copy the old data, but + * we don't care what's in the block. + */ + merge_freemem(ms); + ms->a = (PyObject **)PyMem_Malloc(need * sizeof(PyObject*)); + if (ms->a) { + ms->alloced = need; + return 0; + } + PyErr_NoMemory(); + merge_freemem(ms); /* reset to sane state */ + return -1; +} +#define MERGE_GETMEM(MS, NEED) ((NEED) <= (MS)->alloced ? 0 : \ + merge_getmem(MS, NEED)) + +/* Merge the na elements starting at pa with the nb elements starting at pb + * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. + * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the + * merge, and should have na <= nb. See listsort.txt for more info. + * Return 0 if successful, -1 if error. + */ +static Py_ssize_t +merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, + PyObject **pb, Py_ssize_t nb) +{ + Py_ssize_t k; + PyObject *compare; + PyObject **dest; + int result = -1; /* guilty until proved innocent */ + Py_ssize_t min_gallop = ms->min_gallop; + + assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); + if (MERGE_GETMEM(ms, na) < 0) + return -1; + memcpy(ms->a, pa, na * sizeof(PyObject*)); + dest = pa; + pa = ms->a; + + *dest++ = *pb++; + --nb; + if (nb == 0) + goto Succeed; + if (na == 1) + goto CopyB; + + compare = ms->compare; + for (;;) { + Py_ssize_t acount = 0; /* # of times A won in a row */ + Py_ssize_t bcount = 0; /* # of times B won in a row */ + + /* Do the straightforward thing until (if ever) one run + * appears to win consistently. + */ + for (;;) { + assert(na > 1 && nb > 0); + k = ISLT(*pb, *pa, compare); + if (k) { + if (k < 0) + goto Fail; + *dest++ = *pb++; + ++bcount; + acount = 0; + --nb; + if (nb == 0) + goto Succeed; + if (bcount >= min_gallop) + break; + } + else { + *dest++ = *pa++; + ++acount; + bcount = 0; + --na; + if (na == 1) + goto CopyB; + if (acount >= min_gallop) + break; + } + } + + /* One run is winning so consistently that galloping may + * be a huge win. So try that, and continue galloping until + * (if ever) neither run appears to be winning consistently + * anymore. + */ + ++min_gallop; + do { + assert(na > 1 && nb > 0); + min_gallop -= min_gallop > 1; + ms->min_gallop = min_gallop; + k = gallop_right(*pb, pa, na, 0, compare); + acount = k; + if (k) { + if (k < 0) + goto Fail; + memcpy(dest, pa, k * sizeof(PyObject *)); + dest += k; + pa += k; + na -= k; + if (na == 1) + goto CopyB; + /* na==0 is impossible now if the comparison + * function is consistent, but we can't assume + * that it is. + */ + if (na == 0) + goto Succeed; + } + *dest++ = *pb++; + --nb; + if (nb == 0) + goto Succeed; + + k = gallop_left(*pa, pb, nb, 0, compare); + bcount = k; + if (k) { + if (k < 0) + goto Fail; + memmove(dest, pb, k * sizeof(PyObject *)); + dest += k; + pb += k; + nb -= k; + if (nb == 0) + goto Succeed; + } + *dest++ = *pa++; + --na; + if (na == 1) + goto CopyB; + } while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP); + ++min_gallop; /* penalize it for leaving galloping mode */ + ms->min_gallop = min_gallop; + } +Succeed: + result = 0; +Fail: + if (na) + memcpy(dest, pa, na * sizeof(PyObject*)); + return result; +CopyB: + assert(na == 1 && nb > 0); + /* The last element of pa belongs at the end of the merge. */ + memmove(dest, pb, nb * sizeof(PyObject *)); + dest[nb] = *pa; + return 0; +} + +/* Merge the na elements starting at pa with the nb elements starting at pb + * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. + * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the + * merge, and should have na >= nb. See listsort.txt for more info. + * Return 0 if successful, -1 if error. + */ +static Py_ssize_t +merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t nb) +{ + Py_ssize_t k; + PyObject *compare; + PyObject **dest; + int result = -1; /* guilty until proved innocent */ + PyObject **basea; + PyObject **baseb; + Py_ssize_t min_gallop = ms->min_gallop; + + assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); + if (MERGE_GETMEM(ms, nb) < 0) + return -1; + dest = pb + nb - 1; + memcpy(ms->a, pb, nb * sizeof(PyObject*)); + basea = pa; + baseb = ms->a; + pb = ms->a + nb - 1; + pa += na - 1; + + *dest-- = *pa--; + --na; + if (na == 0) + goto Succeed; + if (nb == 1) + goto CopyA; + + compare = ms->compare; + for (;;) { + Py_ssize_t acount = 0; /* # of times A won in a row */ + Py_ssize_t bcount = 0; /* # of times B won in a row */ + + /* Do the straightforward thing until (if ever) one run + * appears to win consistently. + */ + for (;;) { + assert(na > 0 && nb > 1); + k = ISLT(*pb, *pa, compare); + if (k) { + if (k < 0) + goto Fail; + *dest-- = *pa--; + ++acount; + bcount = 0; + --na; + if (na == 0) + goto Succeed; + if (acount >= min_gallop) + break; + } + else { + *dest-- = *pb--; + ++bcount; + acount = 0; + --nb; + if (nb == 1) + goto CopyA; + if (bcount >= min_gallop) + break; + } + } + + /* One run is winning so consistently that galloping may + * be a huge win. So try that, and continue galloping until + * (if ever) neither run appears to be winning consistently + * anymore. + */ + ++min_gallop; + do { + assert(na > 0 && nb > 1); + min_gallop -= min_gallop > 1; + ms->min_gallop = min_gallop; + k = gallop_right(*pb, basea, na, na-1, compare); + if (k < 0) + goto Fail; + k = na - k; + acount = k; + if (k) { + dest -= k; + pa -= k; + memmove(dest+1, pa+1, k * sizeof(PyObject *)); + na -= k; + if (na == 0) + goto Succeed; + } + *dest-- = *pb--; + --nb; + if (nb == 1) + goto CopyA; + + k = gallop_left(*pa, baseb, nb, nb-1, compare); + if (k < 0) + goto Fail; + k = nb - k; + bcount = k; + if (k) { + dest -= k; + pb -= k; + memcpy(dest+1, pb+1, k * sizeof(PyObject *)); + nb -= k; + if (nb == 1) + goto CopyA; + /* nb==0 is impossible now if the comparison + * function is consistent, but we can't assume + * that it is. + */ + if (nb == 0) + goto Succeed; + } + *dest-- = *pa--; + --na; + if (na == 0) + goto Succeed; + } while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP); + ++min_gallop; /* penalize it for leaving galloping mode */ + ms->min_gallop = min_gallop; + } +Succeed: + result = 0; +Fail: + if (nb) + memcpy(dest-(nb-1), baseb, nb * sizeof(PyObject*)); + return result; +CopyA: + assert(nb == 1 && na > 0); + /* The first element of pb belongs at the front of the merge. */ + dest -= na; + pa -= na; + memmove(dest+1, pa+1, na * sizeof(PyObject *)); + *dest = *pb; + return 0; +} + +/* Merge the two runs at stack indices i and i+1. + * Returns 0 on success, -1 on error. + */ +static Py_ssize_t +merge_at(MergeState *ms, Py_ssize_t i) +{ + PyObject **pa, **pb; + Py_ssize_t na, nb; + Py_ssize_t k; + PyObject *compare; + + assert(ms != NULL); + assert(ms->n >= 2); + assert(i >= 0); + assert(i == ms->n - 2 || i == ms->n - 3); + + pa = ms->pending[i].base; + na = ms->pending[i].len; + pb = ms->pending[i+1].base; + nb = ms->pending[i+1].len; + assert(na > 0 && nb > 0); + assert(pa + na == pb); + + /* Record the length of the combined runs; if i is the 3rd-last + * run now, also slide over the last run (which isn't involved + * in this merge). The current run i+1 goes away in any case. + */ + ms->pending[i].len = na + nb; + if (i == ms->n - 3) + ms->pending[i+1] = ms->pending[i+2]; + --ms->n; + + /* Where does b start in a? Elements in a before that can be + * ignored (already in place). + */ + compare = ms->compare; + k = gallop_right(*pb, pa, na, 0, compare); + if (k < 0) + return -1; + pa += k; + na -= k; + if (na == 0) + return 0; + + /* Where does a end in b? Elements in b after that can be + * ignored (already in place). + */ + nb = gallop_left(pa[na-1], pb, nb, nb-1, compare); + if (nb <= 0) + return nb; + + /* Merge what remains of the runs, using a temp array with + * min(na, nb) elements. + */ + if (na <= nb) + return merge_lo(ms, pa, na, pb, nb); + else + return merge_hi(ms, pa, na, pb, nb); +} + +/* Examine the stack of runs waiting to be merged, merging adjacent runs + * until the stack invariants are re-established: + * + * 1. len[-3] > len[-2] + len[-1] + * 2. len[-2] > len[-1] + * + * See listsort.txt for more info. + * + * Returns 0 on success, -1 on error. + */ +static int +merge_collapse(MergeState *ms) +{ + struct s_slice *p = ms->pending; + + assert(ms); + while (ms->n > 1) { + Py_ssize_t n = ms->n - 2; + if (n > 0 && p[n-1].len <= p[n].len + p[n+1].len) { + if (p[n-1].len < p[n+1].len) + --n; + if (merge_at(ms, n) < 0) + return -1; + } + else if (p[n].len <= p[n+1].len) { + if (merge_at(ms, n) < 0) + return -1; + } + else + break; + } + return 0; +} + +/* Regardless of invariants, merge all runs on the stack until only one + * remains. This is used at the end of the mergesort. + * + * Returns 0 on success, -1 on error. + */ +static int +merge_force_collapse(MergeState *ms) +{ + struct s_slice *p = ms->pending; + + assert(ms); + while (ms->n > 1) { + Py_ssize_t n = ms->n - 2; + if (n > 0 && p[n-1].len < p[n+1].len) + --n; + if (merge_at(ms, n) < 0) + return -1; + } + return 0; +} + +/* Compute a good value for the minimum run length; natural runs shorter + * than this are boosted artificially via binary insertion. + * + * If n < 64, return n (it's too small to bother with fancy stuff). + * Else if n is an exact power of 2, return 32. + * Else return an int k, 32 <= k <= 64, such that n/k is close to, but + * strictly less than, an exact power of 2. + * + * See listsort.txt for more info. + */ +static Py_ssize_t +merge_compute_minrun(Py_ssize_t n) +{ + Py_ssize_t r = 0; /* becomes 1 if any 1 bits are shifted off */ + + assert(n >= 0); + while (n >= 64) { + r |= n & 1; + n >>= 1; + } + return n + r; +} + +/* Special wrapper to support stable sorting using the decorate-sort-undecorate + pattern. Holds a key which is used for comparisons and the original record + which is returned during the undecorate phase. By exposing only the key + during comparisons, the underlying sort stability characteristics are left + unchanged. Also, if a custom comparison function is used, it will only see + the key instead of a full record. */ + +typedef struct { + PyObject_HEAD + PyObject *key; + PyObject *value; +} sortwrapperobject; + +PyDoc_STRVAR(sortwrapper_doc, "Object wrapper with a custom sort key."); +static PyObject * +sortwrapper_richcompare(sortwrapperobject *, sortwrapperobject *, int); +static void +sortwrapper_dealloc(sortwrapperobject *); + +static PyTypeObject sortwrapper_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "sortwrapper", /* tp_name */ + sizeof(sortwrapperobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)sortwrapper_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_HAVE_RICHCOMPARE, /* tp_flags */ + sortwrapper_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)sortwrapper_richcompare, /* tp_richcompare */ +}; + + +static PyObject * +sortwrapper_richcompare(sortwrapperobject *a, sortwrapperobject *b, int op) +{ + if (!PyObject_TypeCheck(b, &sortwrapper_type)) { + PyErr_SetString(PyExc_TypeError, + "expected a sortwrapperobject"); + return NULL; + } + return PyObject_RichCompare(a->key, b->key, op); +} + +static void +sortwrapper_dealloc(sortwrapperobject *so) +{ + Py_XDECREF(so->key); + Py_XDECREF(so->value); + PyObject_Del(so); +} + +/* Returns a new reference to a sortwrapper. + Consumes the references to the two underlying objects. */ + +static PyObject * +build_sortwrapper(PyObject *key, PyObject *value) +{ + sortwrapperobject *so; + + so = PyObject_New(sortwrapperobject, &sortwrapper_type); + if (so == NULL) + return NULL; + so->key = key; + so->value = value; + return (PyObject *)so; +} + +/* Returns a new reference to the value underlying the wrapper. */ +static PyObject * +sortwrapper_getvalue(PyObject *so) +{ + PyObject *value; + + if (!PyObject_TypeCheck(so, &sortwrapper_type)) { + PyErr_SetString(PyExc_TypeError, + "expected a sortwrapperobject"); + return NULL; + } + value = ((sortwrapperobject *)so)->value; + Py_INCREF(value); + return value; +} + +/* Wrapper for user specified cmp functions in combination with a + specified key function. Makes sure the cmp function is presented + with the actual key instead of the sortwrapper */ + +typedef struct { + PyObject_HEAD + PyObject *func; +} cmpwrapperobject; + +static void +cmpwrapper_dealloc(cmpwrapperobject *co) +{ + Py_XDECREF(co->func); + PyObject_Del(co); +} + +static PyObject * +cmpwrapper_call(cmpwrapperobject *co, PyObject *args, PyObject *kwds) +{ + PyObject *x, *y, *xx, *yy; + + if (!PyArg_UnpackTuple(args, "", 2, 2, &x, &y)) + return NULL; + if (!PyObject_TypeCheck(x, &sortwrapper_type) || + !PyObject_TypeCheck(y, &sortwrapper_type)) { + PyErr_SetString(PyExc_TypeError, + "expected a sortwrapperobject"); + return NULL; + } + xx = ((sortwrapperobject *)x)->key; + yy = ((sortwrapperobject *)y)->key; + return PyObject_CallFunctionObjArgs(co->func, xx, yy, NULL); +} + +PyDoc_STRVAR(cmpwrapper_doc, "cmp() wrapper for sort with custom keys."); + +static PyTypeObject cmpwrapper_type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "cmpwrapper", /* tp_name */ + sizeof(cmpwrapperobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)cmpwrapper_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + (ternaryfunc)cmpwrapper_call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + cmpwrapper_doc, /* tp_doc */ +}; + +static PyObject * +build_cmpwrapper(PyObject *cmpfunc) +{ + cmpwrapperobject *co; + + co = PyObject_New(cmpwrapperobject, &cmpwrapper_type); + if (co == NULL) + return NULL; + Py_INCREF(cmpfunc); + co->func = cmpfunc; + return (PyObject *)co; +} + +/* An adaptive, stable, natural mergesort. See listsort.txt. + * Returns Py_None on success, NULL on error. Even in case of error, the + * list will be some permutation of its input state (nothing is lost or + * duplicated). + */ +static PyObject * +listsort(PyListObject *self, PyObject *args, PyObject *kwds) +{ + MergeState ms; + PyObject **lo, **hi; + Py_ssize_t nremaining; + Py_ssize_t minrun; + Py_ssize_t saved_ob_size, saved_allocated; + PyObject **saved_ob_item; + PyObject **final_ob_item; + PyObject *compare = NULL; + PyObject *result = NULL; /* guilty until proved innocent */ + int reverse = 0; + PyObject *keyfunc = NULL; + Py_ssize_t i; + PyObject *key, *value, *kvpair; + static char *kwlist[] = {"cmp", "key", "reverse", 0}; + + assert(self != NULL); + assert (PyList_Check(self)); + if (args != NULL) { + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi:sort", + kwlist, &compare, &keyfunc, &reverse)) + return NULL; + } + if (compare == Py_None) + compare = NULL; + if (keyfunc == Py_None) + keyfunc = NULL; + if (compare != NULL && keyfunc != NULL) { + compare = build_cmpwrapper(compare); + if (compare == NULL) + return NULL; + } else + Py_XINCREF(compare); + + /* The list is temporarily made empty, so that mutations performed + * by comparison functions can't affect the slice of memory we're + * sorting (allowing mutations during sorting is a core-dump + * factory, since ob_item may change). + */ + saved_ob_size = self->ob_size; + saved_ob_item = self->ob_item; + saved_allocated = self->allocated; + self->ob_size = 0; + self->ob_item = NULL; + self->allocated = -1; /* any operation will reset it to >= 0 */ + + if (keyfunc != NULL) { + for (i=0 ; i < saved_ob_size ; i++) { + value = saved_ob_item[i]; + key = PyObject_CallFunctionObjArgs(keyfunc, value, + NULL); + if (key == NULL) { + for (i=i-1 ; i>=0 ; i--) { + kvpair = saved_ob_item[i]; + value = sortwrapper_getvalue(kvpair); + saved_ob_item[i] = value; + Py_DECREF(kvpair); + } + goto dsu_fail; + } + kvpair = build_sortwrapper(key, value); + if (kvpair == NULL) + goto dsu_fail; + saved_ob_item[i] = kvpair; + } + } + + /* Reverse sort stability achieved by initially reversing the list, + applying a stable forward sort, then reversing the final result. */ + if (reverse && saved_ob_size > 1) + reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size); + + merge_init(&ms, compare); + + nremaining = saved_ob_size; + if (nremaining < 2) + goto succeed; + + /* March over the array once, left to right, finding natural runs, + * and extending short natural runs to minrun elements. + */ + lo = saved_ob_item; + hi = lo + nremaining; + minrun = merge_compute_minrun(nremaining); + do { + int descending; + Py_ssize_t n; + + /* Identify next run. */ + n = count_run(lo, hi, compare, &descending); + if (n < 0) + goto fail; + if (descending) + reverse_slice(lo, lo + n); + /* If short, extend to min(minrun, nremaining). */ + if (n < minrun) { + const Py_ssize_t force = nremaining <= minrun ? + nremaining : minrun; + if (binarysort(lo, lo + force, lo + n, compare) < 0) + goto fail; + n = force; + } + /* Push run onto pending-runs stack, and maybe merge. */ + assert(ms.n < MAX_MERGE_PENDING); + ms.pending[ms.n].base = lo; + ms.pending[ms.n].len = n; + ++ms.n; + if (merge_collapse(&ms) < 0) + goto fail; + /* Advance to find next run. */ + lo += n; + nremaining -= n; + } while (nremaining); + assert(lo == hi); + + if (merge_force_collapse(&ms) < 0) + goto fail; + assert(ms.n == 1); + assert(ms.pending[0].base == saved_ob_item); + assert(ms.pending[0].len == saved_ob_size); + +succeed: + result = Py_None; +fail: + if (keyfunc != NULL) { + for (i=0 ; i < saved_ob_size ; i++) { + kvpair = saved_ob_item[i]; + value = sortwrapper_getvalue(kvpair); + saved_ob_item[i] = value; + Py_DECREF(kvpair); + } + } + + if (self->allocated != -1 && result != NULL) { + /* The user mucked with the list during the sort, + * and we don't already have another error to report. + */ + PyErr_SetString(PyExc_ValueError, "list modified during sort"); + result = NULL; + } + + if (reverse && saved_ob_size > 1) + reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size); + + merge_freemem(&ms); + +dsu_fail: + final_ob_item = self->ob_item; + i = self->ob_size; + self->ob_size = saved_ob_size; + self->ob_item = saved_ob_item; + self->allocated = saved_allocated; + if (final_ob_item != NULL) { + /* we cannot use list_clear() for this because it does not + guarantee that the list is really empty when it returns */ + while (--i >= 0) { + Py_XDECREF(final_ob_item[i]); + } + PyMem_FREE(final_ob_item); + } + Py_XDECREF(compare); + Py_XINCREF(result); + return result; +} +#undef IFLT +#undef ISLT + +int +PyList_Sort(PyObject *v) +{ + if (v == NULL || !PyList_Check(v)) { + PyErr_BadInternalCall(); + return -1; + } + v = listsort((PyListObject *)v, (PyObject *)NULL, (PyObject *)NULL); + if (v == NULL) + return -1; + Py_DECREF(v); + return 0; +} + +static PyObject * +listreverse(PyListObject *self) +{ + if (self->ob_size > 1) + reverse_slice(self->ob_item, self->ob_item + self->ob_size); + Py_RETURN_NONE; +} + +int +PyList_Reverse(PyObject *v) +{ + PyListObject *self = (PyListObject *)v; + + if (v == NULL || !PyList_Check(v)) { + PyErr_BadInternalCall(); + return -1; + } + if (self->ob_size > 1) + reverse_slice(self->ob_item, self->ob_item + self->ob_size); + return 0; +} + +PyObject * +PyList_AsTuple(PyObject *v) +{ + PyObject *w; + PyObject **p; + Py_ssize_t n; + if (v == NULL || !PyList_Check(v)) { + PyErr_BadInternalCall(); + return NULL; + } + n = ((PyListObject *)v)->ob_size; + w = PyTuple_New(n); + if (w == NULL) + return NULL; + p = ((PyTupleObject *)w)->ob_item; + memcpy((void *)p, + (void *)((PyListObject *)v)->ob_item, + n*sizeof(PyObject *)); + while (--n >= 0) { + Py_INCREF(*p); + p++; + } + return w; +} + +static PyObject * +listindex(PyListObject *self, PyObject *args) +{ + Py_ssize_t i, start=0, stop=self->ob_size; + PyObject *v; + + if (!PyArg_ParseTuple(args, "O|O&O&:index", &v, + _PyEval_SliceIndex, &start, + _PyEval_SliceIndex, &stop)) + return NULL; + if (start < 0) { + start += self->ob_size; + if (start < 0) + start = 0; + } + if (stop < 0) { + stop += self->ob_size; + if (stop < 0) + stop = 0; + } + for (i = start; i < stop && i < self->ob_size; i++) { + int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); + if (cmp > 0) + return PyInt_FromSsize_t(i); + else if (cmp < 0) + return NULL; + } + PyErr_SetString(PyExc_ValueError, "list.index(x): x not in list"); + return NULL; +} + +static PyObject * +listcount(PyListObject *self, PyObject *v) +{ + Py_ssize_t count = 0; + Py_ssize_t i; + + for (i = 0; i < self->ob_size; i++) { + int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); + if (cmp > 0) + count++; + else if (cmp < 0) + return NULL; + } + return PyInt_FromSsize_t(count); +} + +static PyObject * +listremove(PyListObject *self, PyObject *v) +{ + Py_ssize_t i; + + for (i = 0; i < self->ob_size; i++) { + int cmp = PyObject_RichCompareBool(self->ob_item[i], v, Py_EQ); + if (cmp > 0) { + if (list_ass_slice(self, i, i+1, + (PyObject *)NULL) == 0) + Py_RETURN_NONE; + return NULL; + } + else if (cmp < 0) + return NULL; + } + PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list"); + return NULL; +} + +static int +list_traverse(PyListObject *o, visitproc visit, void *arg) +{ + Py_ssize_t i; + + for (i = o->ob_size; --i >= 0; ) + Py_VISIT(o->ob_item[i]); + return 0; +} + +static PyObject * +list_richcompare(PyObject *v, PyObject *w, int op) +{ + PyListObject *vl, *wl; + Py_ssize_t i; + + if (!PyList_Check(v) || !PyList_Check(w)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + vl = (PyListObject *)v; + wl = (PyListObject *)w; + + if (vl->ob_size != wl->ob_size && (op == Py_EQ || op == Py_NE)) { + /* Shortcut: if the lengths differ, the lists differ */ + PyObject *res; + if (op == Py_EQ) + res = Py_False; + else + res = Py_True; + Py_INCREF(res); + return res; + } + + /* Search for the first index where items are different */ + for (i = 0; i < vl->ob_size && i < wl->ob_size; i++) { + int k = PyObject_RichCompareBool(vl->ob_item[i], + wl->ob_item[i], Py_EQ); + if (k < 0) + return NULL; + if (!k) + break; + } + + if (i >= vl->ob_size || i >= wl->ob_size) { + /* No more items to compare -- compare sizes */ + Py_ssize_t vs = vl->ob_size; + Py_ssize_t ws = wl->ob_size; + int cmp; + PyObject *res; + switch (op) { + case Py_LT: cmp = vs < ws; break; + case Py_LE: cmp = vs <= ws; break; + case Py_EQ: cmp = vs == ws; break; + case Py_NE: cmp = vs != ws; break; + case Py_GT: cmp = vs > ws; break; + case Py_GE: cmp = vs >= ws; break; + default: return NULL; /* cannot happen */ + } + if (cmp) + res = Py_True; + else + res = Py_False; + Py_INCREF(res); + return res; + } + + /* We have an item that differs -- shortcuts for EQ/NE */ + if (op == Py_EQ) { + Py_INCREF(Py_False); + return Py_False; + } + if (op == Py_NE) { + Py_INCREF(Py_True); + return Py_True; + } + + /* Compare the final item again using the proper operator */ + return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op); +} + +static int +list_init(PyListObject *self, PyObject *args, PyObject *kw) +{ + PyObject *arg = NULL; + static char *kwlist[] = {"sequence", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kw, "|O:list", kwlist, &arg)) + return -1; + + /* Verify list invariants established by PyType_GenericAlloc() */ + assert(0 <= self->ob_size); + assert(self->ob_size <= self->allocated || self->allocated == -1); + assert(self->ob_item != NULL || + self->allocated == 0 || self->allocated == -1); + + /* Empty previous contents */ + if (self->ob_item != NULL) { + (void)list_clear(self); + } + if (arg != NULL) { + PyObject *rv = listextend(self, arg); + if (rv == NULL) + return -1; + Py_DECREF(rv); + } + return 0; +} + +static long +list_nohash(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "list objects are unhashable"); + return -1; +} + +static PyObject *list_iter(PyObject *seq); +static PyObject *list_reversed(PyListObject* seq, PyObject* unused); + +PyDoc_STRVAR(getitem_doc, +"x.__getitem__(y) <==> x[y]"); +PyDoc_STRVAR(reversed_doc, +"L.__reversed__() -- return a reverse iterator over the list"); +PyDoc_STRVAR(append_doc, +"L.append(object) -- append object to end"); +PyDoc_STRVAR(extend_doc, +"L.extend(iterable) -- extend list by appending elements from the iterable"); +PyDoc_STRVAR(insert_doc, +"L.insert(index, object) -- insert object before index"); +PyDoc_STRVAR(pop_doc, +"L.pop([index]) -> item -- remove and return item at index (default last)"); +PyDoc_STRVAR(remove_doc, +"L.remove(value) -- remove first occurrence of value"); +PyDoc_STRVAR(index_doc, +"L.index(value, [start, [stop]]) -> integer -- return first index of value"); +PyDoc_STRVAR(count_doc, +"L.count(value) -> integer -- return number of occurrences of value"); +PyDoc_STRVAR(reverse_doc, +"L.reverse() -- reverse *IN PLACE*"); +PyDoc_STRVAR(sort_doc, +"L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;\n\ +cmp(x, y) -> -1, 0, 1"); + +static PyObject *list_subscript(PyListObject*, PyObject*); + +static PyMethodDef list_methods[] = { + {"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, getitem_doc}, + {"__reversed__",(PyCFunction)list_reversed, METH_NOARGS, reversed_doc}, + {"append", (PyCFunction)listappend, METH_O, append_doc}, + {"insert", (PyCFunction)listinsert, METH_VARARGS, insert_doc}, + {"extend", (PyCFunction)listextend, METH_O, extend_doc}, + {"pop", (PyCFunction)listpop, METH_VARARGS, pop_doc}, + {"remove", (PyCFunction)listremove, METH_O, remove_doc}, + {"index", (PyCFunction)listindex, METH_VARARGS, index_doc}, + {"count", (PyCFunction)listcount, METH_O, count_doc}, + {"reverse", (PyCFunction)listreverse, METH_NOARGS, reverse_doc}, + {"sort", (PyCFunction)listsort, METH_VARARGS | METH_KEYWORDS, sort_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PySequenceMethods list_as_sequence = { + (lenfunc)list_length, /* sq_length */ + (binaryfunc)list_concat, /* sq_concat */ + (ssizeargfunc)list_repeat, /* sq_repeat */ + (ssizeargfunc)list_item, /* sq_item */ + (ssizessizeargfunc)list_slice, /* sq_slice */ + (ssizeobjargproc)list_ass_item, /* sq_ass_item */ + (ssizessizeobjargproc)list_ass_slice, /* sq_ass_slice */ + (objobjproc)list_contains, /* sq_contains */ + (binaryfunc)list_inplace_concat, /* sq_inplace_concat */ + (ssizeargfunc)list_inplace_repeat, /* sq_inplace_repeat */ +}; + +PyDoc_STRVAR(list_doc, +"list() -> new list\n" +"list(sequence) -> new list initialized from sequence's items"); + + +static PyObject * +list_subscript(PyListObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyList_GET_SIZE(self); + return list_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, cur, i; + PyObject* result; + PyObject* it; + PyObject **src, **dest; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->ob_size, + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyList_New(0); + } + else { + result = PyList_New(slicelength); + if (!result) return NULL; + + src = self->ob_item; + dest = ((PyListObject *)result)->ob_item; + for (cur = start, i = 0; i < slicelength; + cur += step, i++) { + it = src[cur]; + Py_INCREF(it); + dest[i] = it; + } + + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "list indices must be integers"); + return NULL; + } +} + +static int +list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) + i += PyList_GET_SIZE(self); + return list_ass_item(self, i, value); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength; + + if (PySlice_GetIndicesEx((PySliceObject*)item, self->ob_size, + &start, &stop, &step, &slicelength) < 0) { + return -1; + } + + /* treat L[slice(a,b)] = v _exactly_ like L[a:b] = v */ + if (step == 1 && ((PySliceObject*)item)->step == Py_None) + return list_ass_slice(self, start, stop, value); + + if (value == NULL) { + /* delete slice */ + PyObject **garbage; + Py_ssize_t cur, i; + + if (slicelength <= 0) + return 0; + + if (step < 0) { + stop = start + 1; + start = stop + step*(slicelength - 1) - 1; + step = -step; + } + + garbage = (PyObject**) + PyMem_MALLOC(slicelength*sizeof(PyObject*)); + if (!garbage) { + PyErr_NoMemory(); + return -1; + } + + /* drawing pictures might help + understand these for loops */ + for (cur = start, i = 0; + cur < stop; + cur += step, i++) { + Py_ssize_t lim = step; + + garbage[i] = PyList_GET_ITEM(self, cur); + + if (cur + step >= self->ob_size) { + lim = self->ob_size - cur - 1; + } + + memmove(self->ob_item + cur - i, + self->ob_item + cur + 1, + lim * sizeof(PyObject *)); + } + + for (cur = start + slicelength*step + 1; + cur < self->ob_size; cur++) { + PyList_SET_ITEM(self, cur - slicelength, + PyList_GET_ITEM(self, cur)); + } + + self->ob_size -= slicelength; + list_resize(self, self->ob_size); + + for (i = 0; i < slicelength; i++) { + Py_DECREF(garbage[i]); + } + PyMem_FREE(garbage); + + return 0; + } + else { + /* assign slice */ + PyObject **garbage, *ins, *seq, **seqitems, **selfitems; + Py_ssize_t cur, i; + + /* protect against a[::-1] = a */ + if (self == (PyListObject*)value) { + seq = list_slice((PyListObject*)value, 0, + PyList_GET_SIZE(value)); + } + else { + seq = PySequence_Fast(value, + "must assign iterable to extended slice"); + } + if (!seq) + return -1; + + if (PySequence_Fast_GET_SIZE(seq) != slicelength) { + PyErr_Format(PyExc_ValueError, + "attempt to assign sequence of size %zd to extended slice of size %zd", + PySequence_Fast_GET_SIZE(seq), + slicelength); + Py_DECREF(seq); + return -1; + } + + if (!slicelength) { + Py_DECREF(seq); + return 0; + } + + garbage = (PyObject**) + PyMem_MALLOC(slicelength*sizeof(PyObject*)); + if (!garbage) { + Py_DECREF(seq); + PyErr_NoMemory(); + return -1; + } + + selfitems = self->ob_item; + seqitems = PySequence_Fast_ITEMS(seq); + for (cur = start, i = 0; i < slicelength; + cur += step, i++) { + garbage[i] = selfitems[cur]; + ins = seqitems[i]; + Py_INCREF(ins); + selfitems[cur] = ins; + } + + for (i = 0; i < slicelength; i++) { + Py_DECREF(garbage[i]); + } + + PyMem_FREE(garbage); + Py_DECREF(seq); + + return 0; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "list indices must be integers"); + return -1; + } +} + +static PyMappingMethods list_as_mapping = { + (lenfunc)list_length, + (binaryfunc)list_subscript, + (objobjargproc)list_ass_subscript +}; + +PyTypeObject PyList_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "list", + sizeof(PyListObject), + 0, + (destructor)list_dealloc, /* tp_dealloc */ + (printfunc)list_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)list_repr, /* tp_repr */ + 0, /* tp_as_number */ + &list_as_sequence, /* tp_as_sequence */ + &list_as_mapping, /* tp_as_mapping */ + list_nohash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + list_doc, /* tp_doc */ + (traverseproc)list_traverse, /* tp_traverse */ + (inquiry)list_clear, /* tp_clear */ + list_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + list_iter, /* tp_iter */ + 0, /* tp_iternext */ + list_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)list_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/*********************** List Iterator **************************/ + +typedef struct { + PyObject_HEAD + long it_index; + PyListObject *it_seq; /* Set to NULL when iterator is exhausted */ +} listiterobject; + +static PyObject *list_iter(PyObject *); +static void listiter_dealloc(listiterobject *); +static int listiter_traverse(listiterobject *, visitproc, void *); +static PyObject *listiter_next(listiterobject *); +static PyObject *listiter_len(listiterobject *); + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef listiter_methods[] = { + {"__length_hint__", (PyCFunction)listiter_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyTypeObject PyListIter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "listiterator", /* tp_name */ + sizeof(listiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)listiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)listiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)listiter_next, /* tp_iternext */ + listiter_methods, /* tp_methods */ + 0, /* tp_members */ +}; + + +static PyObject * +list_iter(PyObject *seq) +{ + listiterobject *it; + + if (!PyList_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(listiterobject, &PyListIter_Type); + if (it == NULL) + return NULL; + it->it_index = 0; + Py_INCREF(seq); + it->it_seq = (PyListObject *)seq; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} + +static void +listiter_dealloc(listiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); +} + +static int +listiter_traverse(listiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_seq); + return 0; +} + +static PyObject * +listiter_next(listiterobject *it) +{ + PyListObject *seq; + PyObject *item; + + assert(it != NULL); + seq = it->it_seq; + if (seq == NULL) + return NULL; + assert(PyList_Check(seq)); + + if (it->it_index < PyList_GET_SIZE(seq)) { + item = PyList_GET_ITEM(seq, it->it_index); + ++it->it_index; + Py_INCREF(item); + return item; + } + + Py_DECREF(seq); + it->it_seq = NULL; + return NULL; +} + +static PyObject * +listiter_len(listiterobject *it) +{ + Py_ssize_t len; + if (it->it_seq) { + len = PyList_GET_SIZE(it->it_seq) - it->it_index; + if (len >= 0) + return PyInt_FromSsize_t(len); + } + return PyInt_FromLong(0); +} +/*********************** List Reverse Iterator **************************/ + +typedef struct { + PyObject_HEAD + Py_ssize_t it_index; + PyListObject *it_seq; /* Set to NULL when iterator is exhausted */ +} listreviterobject; + +static PyObject *list_reversed(PyListObject *, PyObject *); +static void listreviter_dealloc(listreviterobject *); +static int listreviter_traverse(listreviterobject *, visitproc, void *); +static PyObject *listreviter_next(listreviterobject *); +static Py_ssize_t listreviter_len(listreviterobject *); + +static PySequenceMethods listreviter_as_sequence = { + (lenfunc)listreviter_len, /* sq_length */ + 0, /* sq_concat */ +}; + +PyTypeObject PyListRevIter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "listreverseiterator", /* tp_name */ + sizeof(listreviterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)listreviter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &listreviter_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)listreviter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)listreviter_next, /* tp_iternext */ + 0, +}; + +static PyObject * +list_reversed(PyListObject *seq, PyObject *unused) +{ + listreviterobject *it; + + it = PyObject_GC_New(listreviterobject, &PyListRevIter_Type); + if (it == NULL) + return NULL; + assert(PyList_Check(seq)); + it->it_index = PyList_GET_SIZE(seq) - 1; + Py_INCREF(seq); + it->it_seq = seq; + PyObject_GC_Track(it); + return (PyObject *)it; +} + +static void +listreviter_dealloc(listreviterobject *it) +{ + PyObject_GC_UnTrack(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); +} + +static int +listreviter_traverse(listreviterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_seq); + return 0; +} + +static PyObject * +listreviter_next(listreviterobject *it) +{ + PyObject *item; + Py_ssize_t index = it->it_index; + PyListObject *seq = it->it_seq; + + if (index>=0 && index < PyList_GET_SIZE(seq)) { + item = PyList_GET_ITEM(seq, index); + it->it_index--; + Py_INCREF(item); + return item; + } + it->it_index = -1; + if (seq != NULL) { + it->it_seq = NULL; + Py_DECREF(seq); + } + return NULL; +} + +static Py_ssize_t +listreviter_len(listreviterobject *it) +{ + Py_ssize_t len = it->it_index + 1; + if (it->it_seq == NULL || PyList_GET_SIZE(it->it_seq) < len) + return 0; + return len; +} + diff --git a/sys/src/cmd/python/Objects/listsort.txt b/sys/src/cmd/python/Objects/listsort.txt new file mode 100644 index 000000000..92269840e --- /dev/null +++ b/sys/src/cmd/python/Objects/listsort.txt @@ -0,0 +1,677 @@ +Intro +----- +This describes an adaptive, stable, natural mergesort, modestly called +timsort (hey, I earned it <wink>). It has supernatural performance on many +kinds of partially ordered arrays (less than lg(N!) comparisons needed, and +as few as N-1), yet as fast as Python's previous highly tuned samplesort +hybrid on random arrays. + +In a nutshell, the main routine marches over the array once, left to right, +alternately identifying the next run, then merging it into the previous +runs "intelligently". Everything else is complication for speed, and some +hard-won measure of memory efficiency. + + +Comparison with Python's Samplesort Hybrid +------------------------------------------ ++ timsort can require a temp array containing as many as N//2 pointers, + which means as many as 2*N extra bytes on 32-bit boxes. It can be + expected to require a temp array this large when sorting random data; on + data with significant structure, it may get away without using any extra + heap memory. This appears to be the strongest argument against it, but + compared to the size of an object, 2 temp bytes worst-case (also expected- + case for random data) doesn't scare me much. + + It turns out that Perl is moving to a stable mergesort, and the code for + that appears always to require a temp array with room for at least N + pointers. (Note that I wouldn't want to do that even if space weren't an + issue; I believe its efforts at memory frugality also save timsort + significant pointer-copying costs, and allow it to have a smaller working + set.) + ++ Across about four hours of generating random arrays, and sorting them + under both methods, samplesort required about 1.5% more comparisons + (the program is at the end of this file). + ++ In real life, this may be faster or slower on random arrays than + samplesort was, depending on platform quirks. Since it does fewer + comparisons on average, it can be expected to do better the more + expensive a comparison function is. OTOH, it does more data movement + (pointer copying) than samplesort, and that may negate its small + comparison advantage (depending on platform quirks) unless comparison + is very expensive. + ++ On arrays with many kinds of pre-existing order, this blows samplesort out + of the water. It's significantly faster than samplesort even on some + cases samplesort was special-casing the snot out of. I believe that lists + very often do have exploitable partial order in real life, and this is the + strongest argument in favor of timsort (indeed, samplesort's special cases + for extreme partial order are appreciated by real users, and timsort goes + much deeper than those, in particular naturally covering every case where + someone has suggested "and it would be cool if list.sort() had a special + case for this too ... and for that ..."). + ++ Here are exact comparison counts across all the tests in sortperf.py, + when run with arguments "15 20 1". + + Column Key: + *sort: random data + \sort: descending data + /sort: ascending data + 3sort: ascending, then 3 random exchanges + +sort: ascending, then 10 random at the end + ~sort: many duplicates + =sort: all equal + !sort: worst case scenario + + First the trivial cases, trivial for samplesort because it special-cased + them, and trivial for timsort because it naturally works on runs. Within + an "n" block, the first line gives the # of compares done by samplesort, + the second line by timsort, and the third line is the percentage by + which the samplesort count exceeds the timsort count: + + n \sort /sort =sort +------- ------ ------ ------ + 32768 32768 32767 32767 samplesort + 32767 32767 32767 timsort + 0.00% 0.00% 0.00% (samplesort - timsort) / timsort + + 65536 65536 65535 65535 + 65535 65535 65535 + 0.00% 0.00% 0.00% + + 131072 131072 131071 131071 + 131071 131071 131071 + 0.00% 0.00% 0.00% + + 262144 262144 262143 262143 + 262143 262143 262143 + 0.00% 0.00% 0.00% + + 524288 524288 524287 524287 + 524287 524287 524287 + 0.00% 0.00% 0.00% + +1048576 1048576 1048575 1048575 + 1048575 1048575 1048575 + 0.00% 0.00% 0.00% + + The algorithms are effectively identical in these cases, except that + timsort does one less compare in \sort. + + Now for the more interesting cases. lg(n!) is the information-theoretic + limit for the best any comparison-based sorting algorithm can do on + average (across all permutations). When a method gets significantly + below that, it's either astronomically lucky, or is finding exploitable + structure in the data. + + n lg(n!) *sort 3sort +sort %sort ~sort !sort +------- ------- ------ ------- ------- ------ ------- -------- + 32768 444255 453096 453614 32908 452871 130491 469141 old + 448885 33016 33007 50426 182083 65534 new + 0.94% 1273.92% -0.30% 798.09% -28.33% 615.87% %ch from new + + 65536 954037 972699 981940 65686 973104 260029 1004607 + 962991 65821 65808 101667 364341 131070 + 1.01% 1391.83% -0.19% 857.15% -28.63% 666.47% + + 131072 2039137 2101881 2091491 131232 2092894 554790 2161379 + 2057533 131410 131361 206193 728871 262142 + 2.16% 1491.58% -0.10% 915.02% -23.88% 724.51% + + 262144 4340409 4464460 4403233 262314 4445884 1107842 4584560 + 4377402 262437 262459 416347 1457945 524286 + 1.99% 1577.82% -0.06% 967.83% -24.01% 774.44% + + 524288 9205096 9453356 9408463 524468 9441930 2218577 9692015 + 9278734 524580 524633 837947 2916107 1048574 + 1.88% 1693.52% -0.03% 1026.79% -23.92% 824.30% + +1048576 19458756 19950272 19838588 1048766 19912134 4430649 20434212 + 19606028 1048958 1048941 1694896 5832445 2097150 + 1.76% 1791.27% -0.02% 1074.83% -24.03% 874.38% + + Discussion of cases: + + *sort: There's no structure in random data to exploit, so the theoretical + limit is lg(n!). Both methods get close to that, and timsort is hugging + it (indeed, in a *marginal* sense, it's a spectacular improvement -- + there's only about 1% left before hitting the wall, and timsort knows + darned well it's doing compares that won't pay on random data -- but so + does the samplesort hybrid). For contrast, Hoare's original random-pivot + quicksort does about 39% more compares than the limit, and the median-of-3 + variant about 19% more. + + 3sort, %sort, and !sort: No contest; there's structure in this data, but + not of the specific kinds samplesort special-cases. Note that structure + in !sort wasn't put there on purpose -- it was crafted as a worst case for + a previous quicksort implementation. That timsort nails it came as a + surprise to me (although it's obvious in retrospect). + + +sort: samplesort special-cases this data, and does a few less compares + than timsort. However, timsort runs this case significantly faster on all + boxes we have timings for, because timsort is in the business of merging + runs efficiently, while samplesort does much more data movement in this + (for it) special case. + + ~sort: samplesort's special cases for large masses of equal elements are + extremely effective on ~sort's specific data pattern, and timsort just + isn't going to get close to that, despite that it's clearly getting a + great deal of benefit out of the duplicates (the # of compares is much less + than lg(n!)). ~sort has a perfectly uniform distribution of just 4 + distinct values, and as the distribution gets more skewed, samplesort's + equal-element gimmicks become less effective, while timsort's adaptive + strategies find more to exploit; in a database supplied by Kevin Altis, a + sort on its highly skewed "on which stock exchange does this company's + stock trade?" field ran over twice as fast under timsort. + + However, despite that timsort does many more comparisons on ~sort, and + that on several platforms ~sort runs highly significantly slower under + timsort, on other platforms ~sort runs highly significantly faster under + timsort. No other kind of data has shown this wild x-platform behavior, + and we don't have an explanation for it. The only thing I can think of + that could transform what "should be" highly significant slowdowns into + highly significant speedups on some boxes are catastrophic cache effects + in samplesort. + + But timsort "should be" slower than samplesort on ~sort, so it's hard + to count that it isn't on some boxes as a strike against it <wink>. + ++ Here's the highwater mark for the number of heap-based temp slots (4 + bytes each on this box) needed by each test, again with arguments + "15 20 1": + + 2**i *sort \sort /sort 3sort +sort %sort ~sort =sort !sort + 32768 16384 0 0 6256 0 10821 12288 0 16383 + 65536 32766 0 0 21652 0 31276 24576 0 32767 + 131072 65534 0 0 17258 0 58112 49152 0 65535 + 262144 131072 0 0 35660 0 123561 98304 0 131071 + 524288 262142 0 0 31302 0 212057 196608 0 262143 +1048576 524286 0 0 312438 0 484942 393216 0 524287 + + Discussion: The tests that end up doing (close to) perfectly balanced + merges (*sort, !sort) need all N//2 temp slots (or almost all). ~sort + also ends up doing balanced merges, but systematically benefits a lot from + the preliminary pre-merge searches described under "Merge Memory" later. + %sort approaches having a balanced merge at the end because the random + selection of elements to replace is expected to produce an out-of-order + element near the midpoint. \sort, /sort, =sort are the trivial one-run + cases, needing no merging at all. +sort ends up having one very long run + and one very short, and so gets all the temp space it needs from the small + temparray member of the MergeState struct (note that the same would be + true if the new random elements were prefixed to the sorted list instead, + but not if they appeared "in the middle"). 3sort approaches N//3 temp + slots twice, but the run lengths that remain after 3 random exchanges + clearly has very high variance. + + +A detailed description of timsort follows. + +Runs +---- +count_run() returns the # of elements in the next run. A run is either +"ascending", which means non-decreasing: + + a0 <= a1 <= a2 <= ... + +or "descending", which means strictly decreasing: + + a0 > a1 > a2 > ... + +Note that a run is always at least 2 long, unless we start at the array's +last element. + +The definition of descending is strict, because the main routine reverses +a descending run in-place, transforming a descending run into an ascending +run. Reversal is done via the obvious fast "swap elements starting at each +end, and converge at the middle" method, and that can violate stability if +the slice contains any equal elements. Using a strict definition of +descending ensures that a descending run contains distinct elements. + +If an array is random, it's very unlikely we'll see long runs. If a natural +run contains less than minrun elements (see next section), the main loop +artificially boosts it to minrun elements, via a stable binary insertion sort +applied to the right number of array elements following the short natural +run. In a random array, *all* runs are likely to be minrun long as a +result. This has two primary good effects: + +1. Random data strongly tends then toward perfectly balanced (both runs have + the same length) merges, which is the most efficient way to proceed when + data is random. + +2. Because runs are never very short, the rest of the code doesn't make + heroic efforts to shave a few cycles off per-merge overheads. For + example, reasonable use of function calls is made, rather than trying to + inline everything. Since there are no more than N/minrun runs to begin + with, a few "extra" function calls per merge is barely measurable. + + +Computing minrun +---------------- +If N < 64, minrun is N. IOW, binary insertion sort is used for the whole +array then; it's hard to beat that given the overheads of trying something +fancier. + +When N is a power of 2, testing on random data showed that minrun values of +16, 32, 64 and 128 worked about equally well. At 256 the data-movement cost +in binary insertion sort clearly hurt, and at 8 the increase in the number +of function calls clearly hurt. Picking *some* power of 2 is important +here, so that the merges end up perfectly balanced (see next section). We +pick 32 as a good value in the sweet range; picking a value at the low end +allows the adaptive gimmicks more opportunity to exploit shorter natural +runs. + +Because sortperf.py only tries powers of 2, it took a long time to notice +that 32 isn't a good choice for the general case! Consider N=2112: + +>>> divmod(2112, 32) +(66, 0) +>>> + +If the data is randomly ordered, we're very likely to end up with 66 runs +each of length 32. The first 64 of these trigger a sequence of perfectly +balanced merges (see next section), leaving runs of lengths 2048 and 64 to +merge at the end. The adaptive gimmicks can do that with fewer than 2048+64 +compares, but it's still more compares than necessary, and-- mergesort's +bugaboo relative to samplesort --a lot more data movement (O(N) copies just +to get 64 elements into place). + +If we take minrun=33 in this case, then we're very likely to end up with 64 +runs each of length 33, and then all merges are perfectly balanced. Better! + +What we want to avoid is picking minrun such that in + + q, r = divmod(N, minrun) + +q is a power of 2 and r>0 (then the last merge only gets r elements into +place, and r < minrun is small compared to N), or q a little larger than a +power of 2 regardless of r (then we've got a case similar to "2112", again +leaving too little work for the last merge to do). + +Instead we pick a minrun in range(32, 65) such that N/minrun is exactly a +power of 2, or if that isn't possible, is close to, but strictly less than, +a power of 2. This is easier to do than it may sound: take the first 6 +bits of N, and add 1 if any of the remaining bits are set. In fact, that +rule covers every case in this section, including small N and exact powers +of 2; merge_compute_minrun() is a deceptively simple function. + + +The Merge Pattern +----------------- +In order to exploit regularities in the data, we're merging on natural +run lengths, and they can become wildly unbalanced. That's a Good Thing +for this sort! It means we have to find a way to manage an assortment of +potentially very different run lengths, though. + +Stability constrains permissible merging patterns. For example, if we have +3 consecutive runs of lengths + + A:10000 B:20000 C:10000 + +we dare not merge A with C first, because if A, B and C happen to contain +a common element, it would get out of order wrt its occurence(s) in B. The +merging must be done as (A+B)+C or A+(B+C) instead. + +So merging is always done on two consecutive runs at a time, and in-place, +although this may require some temp memory (more on that later). + +When a run is identified, its base address and length are pushed on a stack +in the MergeState struct. merge_collapse() is then called to see whether it +should merge it with preceding run(s). We would like to delay merging as +long as possible in order to exploit patterns that may come up later, but we +like even more to do merging as soon as possible to exploit that the run just +found is still high in the memory hierarchy. We also can't delay merging +"too long" because it consumes memory to remember the runs that are still +unmerged, and the stack has a fixed size. + +What turned out to be a good compromise maintains two invariants on the +stack entries, where A, B and C are the lengths of the three righmost not-yet +merged slices: + +1. A > B+C +2. B > C + +Note that, by induction, #2 implies the lengths of pending runs form a +decreasing sequence. #1 implies that, reading the lengths right to left, +the pending-run lengths grow at least as fast as the Fibonacci numbers. +Therefore the stack can never grow larger than about log_base_phi(N) entries, +where phi = (1+sqrt(5))/2 ~= 1.618. Thus a small # of stack slots suffice +for very large arrays. + +If A <= B+C, the smaller of A and C is merged with B (ties favor C, for the +freshness-in-cache reason), and the new run replaces the A,B or B,C entries; +e.g., if the last 3 entries are + + A:30 B:20 C:10 + +then B is merged with C, leaving + + A:30 BC:30 + +on the stack. Or if they were + + A:500 B:400: C:1000 + +then A is merged with B, leaving + + AB:900 C:1000 + +on the stack. + +In both examples, the stack configuration after the merge still violates +invariant #2, and merge_collapse() goes on to continue merging runs until +both invariants are satisfied. As an extreme case, suppose we didn't do the +minrun gimmick, and natural runs were of lengths 128, 64, 32, 16, 8, 4, 2, +and 2. Nothing would get merged until the final 2 was seen, and that would +trigger 7 perfectly balanced merges. + +The thrust of these rules when they trigger merging is to balance the run +lengths as closely as possible, while keeping a low bound on the number of +runs we have to remember. This is maximally effective for random data, +where all runs are likely to be of (artificially forced) length minrun, and +then we get a sequence of perfectly balanced merges (with, perhaps, some +oddballs at the end). + +OTOH, one reason this sort is so good for partly ordered data has to do +with wildly unbalanced run lengths. + + +Merge Memory +------------ +Merging adjacent runs of lengths A and B in-place is very difficult. +Theoretical constructions are known that can do it, but they're too difficult +and slow for practical use. But if we have temp memory equal to min(A, B), +it's easy. + +If A is smaller (function merge_lo), copy A to a temp array, leave B alone, +and then we can do the obvious merge algorithm left to right, from the temp +area and B, starting the stores into where A used to live. There's always a +free area in the original area comprising a number of elements equal to the +number not yet merged from the temp array (trivially true at the start; +proceed by induction). The only tricky bit is that if a comparison raises an +exception, we have to remember to copy the remaining elements back in from +the temp area, lest the array end up with duplicate entries from B. But +that's exactly the same thing we need to do if we reach the end of B first, +so the exit code is pleasantly common to both the normal and error cases. + +If B is smaller (function merge_hi, which is merge_lo's "mirror image"), +much the same, except that we need to merge right to left, copying B into a +temp array and starting the stores at the right end of where B used to live. + +A refinement: When we're about to merge adjacent runs A and B, we first do +a form of binary search (more on that later) to see where B[0] should end up +in A. Elements in A preceding that point are already in their final +positions, effectively shrinking the size of A. Likewise we also search to +see where A[-1] should end up in B, and elements of B after that point can +also be ignored. This cuts the amount of temp memory needed by the same +amount. + +These preliminary searches may not pay off, and can be expected *not* to +repay their cost if the data is random. But they can win huge in all of +time, copying, and memory savings when they do pay, so this is one of the +"per-merge overheads" mentioned above that we're happy to endure because +there is at most one very short run. It's generally true in this algorithm +that we're willing to gamble a little to win a lot, even though the net +expectation is negative for random data. + + +Merge Algorithms +---------------- +merge_lo() and merge_hi() are where the bulk of the time is spent. merge_lo +deals with runs where A <= B, and merge_hi where A > B. They don't know +whether the data is clustered or uniform, but a lovely thing about merging +is that many kinds of clustering "reveal themselves" by how many times in a +row the winning merge element comes from the same run. We'll only discuss +merge_lo here; merge_hi is exactly analogous. + +Merging begins in the usual, obvious way, comparing the first element of A +to the first of B, and moving B[0] to the merge area if it's less than A[0], +else moving A[0] to the merge area. Call that the "one pair at a time" +mode. The only twist here is keeping track of how many times in a row "the +winner" comes from the same run. + +If that count reaches MIN_GALLOP, we switch to "galloping mode". Here +we *search* B for where A[0] belongs, and move over all the B's before +that point in one chunk to the merge area, then move A[0] to the merge +area. Then we search A for where B[0] belongs, and similarly move a +slice of A in one chunk. Then back to searching B for where A[0] belongs, +etc. We stay in galloping mode until both searches find slices to copy +less than MIN_GALLOP elements long, at which point we go back to one-pair- +at-a-time mode. + +A refinement: The MergeState struct contains the value of min_gallop that +controls when we enter galloping mode, initialized to MIN_GALLOP. +merge_lo() and merge_hi() adjust this higher when galloping isn't paying +off, and lower when it is. + + +Galloping +--------- +Still without loss of generality, assume A is the shorter run. In galloping +mode, we first look for A[0] in B. We do this via "galloping", comparing +A[0] in turn to B[0], B[1], B[3], B[7], ..., B[2**j - 1], ..., until finding +the k such that B[2**(k-1) - 1] < A[0] <= B[2**k - 1]. This takes at most +roughly lg(B) comparisons, and, unlike a straight binary search, favors +finding the right spot early in B (more on that later). + +After finding such a k, the region of uncertainty is reduced to 2**(k-1) - 1 +consecutive elements, and a straight binary search requires exactly k-1 +additional comparisons to nail it. Then we copy all the B's up to that +point in one chunk, and then copy A[0]. Note that no matter where A[0] +belongs in B, the combination of galloping + binary search finds it in no +more than about 2*lg(B) comparisons. + +If we did a straight binary search, we could find it in no more than +ceiling(lg(B+1)) comparisons -- but straight binary search takes that many +comparisons no matter where A[0] belongs. Straight binary search thus loses +to galloping unless the run is quite long, and we simply can't guess +whether it is in advance. + +If data is random and runs have the same length, A[0] belongs at B[0] half +the time, at B[1] a quarter of the time, and so on: a consecutive winning +sub-run in B of length k occurs with probability 1/2**(k+1). So long +winning sub-runs are extremely unlikely in random data, and guessing that a +winning sub-run is going to be long is a dangerous game. + +OTOH, if data is lopsided or lumpy or contains many duplicates, long +stretches of winning sub-runs are very likely, and cutting the number of +comparisons needed to find one from O(B) to O(log B) is a huge win. + +Galloping compromises by getting out fast if there isn't a long winning +sub-run, yet finding such very efficiently when they exist. + +I first learned about the galloping strategy in a related context; see: + + "Adaptive Set Intersections, Unions, and Differences" (2000) + Erik D. Demaine, Alejandro López-Ortiz, J. Ian Munro + +and its followup(s). An earlier paper called the same strategy +"exponential search": + + "Optimistic Sorting and Information Theoretic Complexity" + Peter McIlroy + SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms), pp + 467-474, Austin, Texas, 25-27 January 1993. + +and it probably dates back to an earlier paper by Bentley and Yao. The +McIlroy paper in particular has good analysis of a mergesort that's +probably strongly related to this one in its galloping strategy. + + +Galloping with a Broken Leg +--------------------------- +So why don't we always gallop? Because it can lose, on two counts: + +1. While we're willing to endure small per-merge overheads, per-comparison + overheads are a different story. Calling Yet Another Function per + comparison is expensive, and gallop_left() and gallop_right() are + too long-winded for sane inlining. + +2. Galloping can-- alas --require more comparisons than linear one-at-time + search, depending on the data. + +#2 requires details. If A[0] belongs before B[0], galloping requires 1 +compare to determine that, same as linear search, except it costs more +to call the gallop function. If A[0] belongs right before B[1], galloping +requires 2 compares, again same as linear search. On the third compare, +galloping checks A[0] against B[3], and if it's <=, requires one more +compare to determine whether A[0] belongs at B[2] or B[3]. That's a total +of 4 compares, but if A[0] does belong at B[2], linear search would have +discovered that in only 3 compares, and that's a huge loss! Really. It's +an increase of 33% in the number of compares needed, and comparisons are +expensive in Python. + +index in B where # compares linear # gallop # binary gallop +A[0] belongs search needs compares compares total +---------------- ----------------- -------- -------- ------ + 0 1 1 0 1 + + 1 2 2 0 2 + + 2 3 3 1 4 + 3 4 3 1 4 + + 4 5 4 2 6 + 5 6 4 2 6 + 6 7 4 2 6 + 7 8 4 2 6 + + 8 9 5 3 8 + 9 10 5 3 8 + 10 11 5 3 8 + 11 12 5 3 8 + ... + +In general, if A[0] belongs at B[i], linear search requires i+1 comparisons +to determine that, and galloping a total of 2*floor(lg(i))+2 comparisons. +The advantage of galloping is unbounded as i grows, but it doesn't win at +all until i=6. Before then, it loses twice (at i=2 and i=4), and ties +at the other values. At and after i=6, galloping always wins. + +We can't guess in advance when it's going to win, though, so we do one pair +at a time until the evidence seems strong that galloping may pay. MIN_GALLOP +is 7, and that's pretty strong evidence. However, if the data is random, it +simply will trigger galloping mode purely by luck every now and again, and +it's quite likely to hit one of the losing cases next. On the other hand, +in cases like ~sort, galloping always pays, and MIN_GALLOP is larger than it +"should be" then. So the MergeState struct keeps a min_gallop variable +that merge_lo and merge_hi adjust: the longer we stay in galloping mode, +the smaller min_gallop gets, making it easier to transition back to +galloping mode (if we ever leave it in the current merge, and at the +start of the next merge). But whenever the gallop loop doesn't pay, +min_gallop is increased by one, making it harder to transition back +to galloping mode (and again both within a merge and across merges). For +random data, this all but eliminates the gallop penalty: min_gallop grows +large enough that we almost never get into galloping mode. And for cases +like ~sort, min_gallop can fall to as low as 1. This seems to work well, +but in all it's a minor improvement over using a fixed MIN_GALLOP value. + + +Galloping Complication +---------------------- +The description above was for merge_lo. merge_hi has to merge "from the +other end", and really needs to gallop starting at the last element in a run +instead of the first. Galloping from the first still works, but does more +comparisons than it should (this is significant -- I timed it both ways). +For this reason, the gallop_left() and gallop_right() functions have a +"hint" argument, which is the index at which galloping should begin. So +galloping can actually start at any index, and proceed at offsets of 1, 3, +7, 15, ... or -1, -3, -7, -15, ... from the starting index. + +In the code as I type it's always called with either 0 or n-1 (where n is +the # of elements in a run). It's tempting to try to do something fancier, +melding galloping with some form of interpolation search; for example, if +we're merging a run of length 1 with a run of length 10000, index 5000 is +probably a better guess at the final result than either 0 or 9999. But +it's unclear how to generalize that intuition usefully, and merging of +wildly unbalanced runs already enjoys excellent performance. + +~sort is a good example of when balanced runs could benefit from a better +hint value: to the extent possible, this would like to use a starting +offset equal to the previous value of acount/bcount. Doing so saves about +10% of the compares in ~sort. However, doing so is also a mixed bag, +hurting other cases. + + +Comparing Average # of Compares on Random Arrays +------------------------------------------------ +[NOTE: This was done when the new algorithm used about 0.1% more compares + on random data than does its current incarnation.] + +Here list.sort() is samplesort, and list.msort() this sort: + +""" +import random +from time import clock as now + +def fill(n): + from random import random + return [random() for i in xrange(n)] + +def mycmp(x, y): + global ncmp + ncmp += 1 + return cmp(x, y) + +def timeit(values, method): + global ncmp + X = values[:] + bound = getattr(X, method) + ncmp = 0 + t1 = now() + bound(mycmp) + t2 = now() + return t2-t1, ncmp + +format = "%5s %9.2f %11d" +f2 = "%5s %9.2f %11.2f" + +def drive(): + count = sst = sscmp = mst = mscmp = nelts = 0 + while True: + n = random.randrange(100000) + nelts += n + x = fill(n) + + t, c = timeit(x, 'sort') + sst += t + sscmp += c + + t, c = timeit(x, 'msort') + mst += t + mscmp += c + + count += 1 + if count % 10: + continue + + print "count", count, "nelts", nelts + print format % ("sort", sst, sscmp) + print format % ("msort", mst, mscmp) + print f2 % ("", (sst-mst)*1e2/mst, (sscmp-mscmp)*1e2/mscmp) + +drive() +""" + +I ran this on Windows and kept using the computer lightly while it was +running. time.clock() is wall-clock time on Windows, with better than +microsecond resolution. samplesort started with a 1.52% #-of-comparisons +disadvantage, fell quickly to 1.48%, and then fluctuated within that small +range. Here's the last chunk of output before I killed the job: + +count 2630 nelts 130906543 + sort 6110.80 1937887573 +msort 6002.78 1909389381 + 1.80 1.49 + +We've done nearly 2 billion comparisons apiece at Python speed there, and +that's enough <wink>. + +For random arrays of size 2 (yes, there are only 2 interesting ones), +samplesort has a 50%(!) comparison disadvantage. This is a consequence of +samplesort special-casing at most one ascending run at the start, then +falling back to the general case if it doesn't find an ascending run +immediately. The consequence is that it ends up using two compares to sort +[2, 1]. Gratifyingly, timsort doesn't do any special-casing, so had to be +taught how to deal with mixtures of ascending and descending runs +efficiently in all cases. diff --git a/sys/src/cmd/python/Objects/longobject.c b/sys/src/cmd/python/Objects/longobject.c new file mode 100644 index 000000000..cb4900d9d --- /dev/null +++ b/sys/src/cmd/python/Objects/longobject.c @@ -0,0 +1,3458 @@ + + +/* Long (arbitrary precision) integer object implementation */ + +/* XXX The functional organization of this file is terrible */ + +#include "Python.h" +#include "longintrepr.h" + +#include <ctype.h> + +/* For long multiplication, use the O(N**2) school algorithm unless + * both operands contain more than KARATSUBA_CUTOFF digits (this + * being an internal Python long digit, in base BASE). + */ +#define KARATSUBA_CUTOFF 70 +#define KARATSUBA_SQUARE_CUTOFF (2 * KARATSUBA_CUTOFF) + +/* For exponentiation, use the binary left-to-right algorithm + * unless the exponent contains more than FIVEARY_CUTOFF digits. + * In that case, do 5 bits at a time. The potential drawback is that + * a table of 2**5 intermediate results is computed. + */ +#define FIVEARY_CUTOFF 8 + +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +#undef MIN +#undef MAX +#define MAX(x, y) ((x) < (y) ? (y) : (x)) +#define MIN(x, y) ((x) > (y) ? (y) : (x)) + +/* Forward */ +static PyLongObject *long_normalize(PyLongObject *); +static PyLongObject *mul1(PyLongObject *, wdigit); +static PyLongObject *muladd1(PyLongObject *, wdigit, wdigit); +static PyLongObject *divrem1(PyLongObject *, digit, digit *); +static PyObject *long_format(PyObject *aa, int base, int addL); + +#define SIGCHECK(PyTryBlock) \ + if (--_Py_Ticker < 0) { \ + _Py_Ticker = _Py_CheckInterval; \ + if (PyErr_CheckSignals()) PyTryBlock \ + } + +/* Normalize (remove leading zeros from) a long int object. + Doesn't attempt to free the storage--in most cases, due to the nature + of the algorithms used, this could save at most be one word anyway. */ + +static PyLongObject * +long_normalize(register PyLongObject *v) +{ + Py_ssize_t j = ABS(v->ob_size); + Py_ssize_t i = j; + + while (i > 0 && v->ob_digit[i-1] == 0) + --i; + if (i != j) + v->ob_size = (v->ob_size < 0) ? -(i) : i; + return v; +} + +/* Allocate a new long int object with size digits. + Return NULL and set exception if we run out of memory. */ + +PyLongObject * +_PyLong_New(Py_ssize_t size) +{ + if (size > PY_SSIZE_T_MAX) { + PyErr_NoMemory(); + return NULL; + } + return PyObject_NEW_VAR(PyLongObject, &PyLong_Type, size); +} + +PyObject * +_PyLong_Copy(PyLongObject *src) +{ + PyLongObject *result; + Py_ssize_t i; + + assert(src != NULL); + i = src->ob_size; + if (i < 0) + i = -(i); + result = _PyLong_New(i); + if (result != NULL) { + result->ob_size = src->ob_size; + while (--i >= 0) + result->ob_digit[i] = src->ob_digit[i]; + } + return (PyObject *)result; +} + +/* Create a new long int object from a C long int */ + +PyObject * +PyLong_FromLong(long ival) +{ + PyLongObject *v; + unsigned long t; /* unsigned so >> doesn't propagate sign bit */ + int ndigits = 0; + int negative = 0; + + if (ival < 0) { + ival = -ival; + negative = 1; + } + + /* Count the number of Python digits. + We used to pick 5 ("big enough for anything"), but that's a + waste of time and space given that 5*15 = 75 bits are rarely + needed. */ + t = (unsigned long)ival; + while (t) { + ++ndigits; + t >>= SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + v->ob_size = negative ? -ndigits : ndigits; + t = (unsigned long)ival; + while (t) { + *p++ = (digit)(t & MASK); + t >>= SHIFT; + } + } + return (PyObject *)v; +} + +/* Create a new long int object from a C unsigned long int */ + +PyObject * +PyLong_FromUnsignedLong(unsigned long ival) +{ + PyLongObject *v; + unsigned long t; + int ndigits = 0; + + /* Count the number of Python digits. */ + t = (unsigned long)ival; + while (t) { + ++ndigits; + t >>= SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + v->ob_size = ndigits; + while (ival) { + *p++ = (digit)(ival & MASK); + ival >>= SHIFT; + } + } + return (PyObject *)v; +} + +/* Create a new long int object from a C double */ + +PyObject * +PyLong_FromDouble(double dval) +{ + PyLongObject *v; + double frac; + int i, ndig, expo, neg; + neg = 0; + if (Py_IS_INFINITY(dval)) { + PyErr_SetString(PyExc_OverflowError, + "cannot convert float infinity to long"); + return NULL; + } + if (dval < 0.0) { + neg = 1; + dval = -dval; + } + frac = frexp(dval, &expo); /* dval = frac*2**expo; 0.0 <= frac < 1.0 */ + if (expo <= 0) + return PyLong_FromLong(0L); + ndig = (expo-1) / SHIFT + 1; /* Number of 'digits' in result */ + v = _PyLong_New(ndig); + if (v == NULL) + return NULL; + frac = ldexp(frac, (expo-1) % SHIFT + 1); + for (i = ndig; --i >= 0; ) { + long bits = (long)frac; + v->ob_digit[i] = (digit) bits; + frac = frac - (double)bits; + frac = ldexp(frac, SHIFT); + } + if (neg) + v->ob_size = -(v->ob_size); + return (PyObject *)v; +} + +/* Checking for overflow in PyLong_AsLong is a PITA since C doesn't define + * anything about what happens when a signed integer operation overflows, + * and some compilers think they're doing you a favor by being "clever" + * then. The bit pattern for the largest postive signed long is + * (unsigned long)LONG_MAX, and for the smallest negative signed long + * it is abs(LONG_MIN), which we could write -(unsigned long)LONG_MIN. + * However, some other compilers warn about applying unary minus to an + * unsigned operand. Hence the weird "0-". + */ +#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) +#define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN) + +/* Get a C long int from a long int object. + Returns -1 and sets an error condition if overflow occurs. */ + +long +PyLong_AsLong(PyObject *vv) +{ + /* This version by Tim Peters */ + register PyLongObject *v; + unsigned long x, prev; + Py_ssize_t i; + int sign; + + if (vv == NULL || !PyLong_Check(vv)) { + if (vv != NULL && PyInt_Check(vv)) + return PyInt_AsLong(vv); + PyErr_BadInternalCall(); + return -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -(i); + } + while (--i >= 0) { + prev = x; + x = (x << SHIFT) + v->ob_digit[i]; + if ((x >> SHIFT) != prev) + goto overflow; + } + /* Haven't lost any bits, but casting to long requires extra care + * (see comment above). + */ + if (x <= (unsigned long)LONG_MAX) { + return (long)x * sign; + } + else if (sign < 0 && x == PY_ABS_LONG_MIN) { + return LONG_MIN; + } + /* else overflow */ + + overflow: + PyErr_SetString(PyExc_OverflowError, + "long int too large to convert to int"); + return -1; +} + +/* Get a Py_ssize_t from a long int object. + Returns -1 and sets an error condition if overflow occurs. */ + +Py_ssize_t +_PyLong_AsSsize_t(PyObject *vv) { + register PyLongObject *v; + size_t x, prev; + Py_ssize_t i; + int sign; + + if (vv == NULL || !PyLong_Check(vv)) { + PyErr_BadInternalCall(); + return -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -(i); + } + while (--i >= 0) { + prev = x; + x = (x << SHIFT) + v->ob_digit[i]; + if ((x >> SHIFT) != prev) + goto overflow; + } + /* Haven't lost any bits, but casting to a signed type requires + * extra care (see comment above). + */ + if (x <= (size_t)PY_SSIZE_T_MAX) { + return (Py_ssize_t)x * sign; + } + else if (sign < 0 && x == PY_ABS_SSIZE_T_MIN) { + return PY_SSIZE_T_MIN; + } + /* else overflow */ + + overflow: + PyErr_SetString(PyExc_OverflowError, + "long int too large to convert to int"); + return -1; +} + +/* Get a C unsigned long int from a long int object. + Returns -1 and sets an error condition if overflow occurs. */ + +unsigned long +PyLong_AsUnsignedLong(PyObject *vv) +{ + register PyLongObject *v; + unsigned long x, prev; + Py_ssize_t i; + + if (vv == NULL || !PyLong_Check(vv)) { + if (vv != NULL && PyInt_Check(vv)) { + long val = PyInt_AsLong(vv); + if (val < 0) { + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to unsigned long"); + return (unsigned long) -1; + } + return val; + } + PyErr_BadInternalCall(); + return (unsigned long) -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + x = 0; + if (i < 0) { + PyErr_SetString(PyExc_OverflowError, + "can't convert negative value to unsigned long"); + return (unsigned long) -1; + } + while (--i >= 0) { + prev = x; + x = (x << SHIFT) + v->ob_digit[i]; + if ((x >> SHIFT) != prev) { + PyErr_SetString(PyExc_OverflowError, + "long int too large to convert"); + return (unsigned long) -1; + } + } + return x; +} + +/* Get a C unsigned long int from a long int object, ignoring the high bits. + Returns -1 and sets an error condition if an error occurs. */ + +unsigned long +PyLong_AsUnsignedLongMask(PyObject *vv) +{ + register PyLongObject *v; + unsigned long x; + Py_ssize_t i; + int sign; + + if (vv == NULL || !PyLong_Check(vv)) { + if (vv != NULL && PyInt_Check(vv)) + return PyInt_AsUnsignedLongMask(vv); + PyErr_BadInternalCall(); + return (unsigned long) -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -i; + } + while (--i >= 0) { + x = (x << SHIFT) + v->ob_digit[i]; + } + return x * sign; +} + +int +_PyLong_Sign(PyObject *vv) +{ + PyLongObject *v = (PyLongObject *)vv; + + assert(v != NULL); + assert(PyLong_Check(v)); + + return v->ob_size == 0 ? 0 : (v->ob_size < 0 ? -1 : 1); +} + +size_t +_PyLong_NumBits(PyObject *vv) +{ + PyLongObject *v = (PyLongObject *)vv; + size_t result = 0; + Py_ssize_t ndigits; + + assert(v != NULL); + assert(PyLong_Check(v)); + ndigits = ABS(v->ob_size); + assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); + if (ndigits > 0) { + digit msd = v->ob_digit[ndigits - 1]; + + result = (ndigits - 1) * SHIFT; + if (result / SHIFT != (size_t)(ndigits - 1)) + goto Overflow; + do { + ++result; + if (result == 0) + goto Overflow; + msd >>= 1; + } while (msd); + } + return result; + +Overflow: + PyErr_SetString(PyExc_OverflowError, "long has too many bits " + "to express in a platform size_t"); + return (size_t)-1; +} + +PyObject * +_PyLong_FromByteArray(const unsigned char* bytes, size_t n, + int little_endian, int is_signed) +{ + const unsigned char* pstartbyte;/* LSB of bytes */ + int incr; /* direction to move pstartbyte */ + const unsigned char* pendbyte; /* MSB of bytes */ + size_t numsignificantbytes; /* number of bytes that matter */ + size_t ndigits; /* number of Python long digits */ + PyLongObject* v; /* result */ + int idigit = 0; /* next free index in v->ob_digit */ + + if (n == 0) + return PyLong_FromLong(0L); + + if (little_endian) { + pstartbyte = bytes; + pendbyte = bytes + n - 1; + incr = 1; + } + else { + pstartbyte = bytes + n - 1; + pendbyte = bytes; + incr = -1; + } + + if (is_signed) + is_signed = *pendbyte >= 0x80; + + /* Compute numsignificantbytes. This consists of finding the most + significant byte. Leading 0 bytes are insignficant if the number + is positive, and leading 0xff bytes if negative. */ + { + size_t i; + const unsigned char* p = pendbyte; + const int pincr = -incr; /* search MSB to LSB */ + const unsigned char insignficant = is_signed ? 0xff : 0x00; + + for (i = 0; i < n; ++i, p += pincr) { + if (*p != insignficant) + break; + } + numsignificantbytes = n - i; + /* 2's-comp is a bit tricky here, e.g. 0xff00 == -0x0100, so + actually has 2 significant bytes. OTOH, 0xff0001 == + -0x00ffff, so we wouldn't *need* to bump it there; but we + do for 0xffff = -0x0001. To be safe without bothering to + check every case, bump it regardless. */ + if (is_signed && numsignificantbytes < n) + ++numsignificantbytes; + } + + /* How many Python long digits do we need? We have + 8*numsignificantbytes bits, and each Python long digit has SHIFT + bits, so it's the ceiling of the quotient. */ + ndigits = (numsignificantbytes * 8 + SHIFT - 1) / SHIFT; + if (ndigits > (size_t)INT_MAX) + return PyErr_NoMemory(); + v = _PyLong_New((int)ndigits); + if (v == NULL) + return NULL; + + /* Copy the bits over. The tricky parts are computing 2's-comp on + the fly for signed numbers, and dealing with the mismatch between + 8-bit bytes and (probably) 15-bit Python digits.*/ + { + size_t i; + twodigits carry = 1; /* for 2's-comp calculation */ + twodigits accum = 0; /* sliding register */ + unsigned int accumbits = 0; /* number of bits in accum */ + const unsigned char* p = pstartbyte; + + for (i = 0; i < numsignificantbytes; ++i, p += incr) { + twodigits thisbyte = *p; + /* Compute correction for 2's comp, if needed. */ + if (is_signed) { + thisbyte = (0xff ^ thisbyte) + carry; + carry = thisbyte >> 8; + thisbyte &= 0xff; + } + /* Because we're going LSB to MSB, thisbyte is + more significant than what's already in accum, + so needs to be prepended to accum. */ + accum |= thisbyte << accumbits; + accumbits += 8; + if (accumbits >= SHIFT) { + /* There's enough to fill a Python digit. */ + assert(idigit < (int)ndigits); + v->ob_digit[idigit] = (digit)(accum & MASK); + ++idigit; + accum >>= SHIFT; + accumbits -= SHIFT; + assert(accumbits < SHIFT); + } + } + assert(accumbits < SHIFT); + if (accumbits) { + assert(idigit < (int)ndigits); + v->ob_digit[idigit] = (digit)accum; + ++idigit; + } + } + + v->ob_size = is_signed ? -idigit : idigit; + return (PyObject *)long_normalize(v); +} + +int +_PyLong_AsByteArray(PyLongObject* v, + unsigned char* bytes, size_t n, + int little_endian, int is_signed) +{ + int i; /* index into v->ob_digit */ + Py_ssize_t ndigits; /* |v->ob_size| */ + twodigits accum; /* sliding register */ + unsigned int accumbits; /* # bits in accum */ + int do_twos_comp; /* store 2's-comp? is_signed and v < 0 */ + twodigits carry; /* for computing 2's-comp */ + size_t j; /* # bytes filled */ + unsigned char* p; /* pointer to next byte in bytes */ + int pincr; /* direction to move p */ + + assert(v != NULL && PyLong_Check(v)); + + if (v->ob_size < 0) { + ndigits = -(v->ob_size); + if (!is_signed) { + PyErr_SetString(PyExc_TypeError, + "can't convert negative long to unsigned"); + return -1; + } + do_twos_comp = 1; + } + else { + ndigits = v->ob_size; + do_twos_comp = 0; + } + + if (little_endian) { + p = bytes; + pincr = 1; + } + else { + p = bytes + n - 1; + pincr = -1; + } + + /* Copy over all the Python digits. + It's crucial that every Python digit except for the MSD contribute + exactly SHIFT bits to the total, so first assert that the long is + normalized. */ + assert(ndigits == 0 || v->ob_digit[ndigits - 1] != 0); + j = 0; + accum = 0; + accumbits = 0; + carry = do_twos_comp ? 1 : 0; + for (i = 0; i < ndigits; ++i) { + twodigits thisdigit = v->ob_digit[i]; + if (do_twos_comp) { + thisdigit = (thisdigit ^ MASK) + carry; + carry = thisdigit >> SHIFT; + thisdigit &= MASK; + } + /* Because we're going LSB to MSB, thisdigit is more + significant than what's already in accum, so needs to be + prepended to accum. */ + accum |= thisdigit << accumbits; + accumbits += SHIFT; + + /* The most-significant digit may be (probably is) at least + partly empty. */ + if (i == ndigits - 1) { + /* Count # of sign bits -- they needn't be stored, + * although for signed conversion we need later to + * make sure at least one sign bit gets stored. + * First shift conceptual sign bit to real sign bit. + */ + stwodigits s = (stwodigits)(thisdigit << + (8*sizeof(stwodigits) - SHIFT)); + unsigned int nsignbits = 0; + while ((s < 0) == do_twos_comp && nsignbits < SHIFT) { + ++nsignbits; + s <<= 1; + } + accumbits -= nsignbits; + } + + /* Store as many bytes as possible. */ + while (accumbits >= 8) { + if (j >= n) + goto Overflow; + ++j; + *p = (unsigned char)(accum & 0xff); + p += pincr; + accumbits -= 8; + accum >>= 8; + } + } + + /* Store the straggler (if any). */ + assert(accumbits < 8); + assert(carry == 0); /* else do_twos_comp and *every* digit was 0 */ + if (accumbits > 0) { + if (j >= n) + goto Overflow; + ++j; + if (do_twos_comp) { + /* Fill leading bits of the byte with sign bits + (appropriately pretending that the long had an + infinite supply of sign bits). */ + accum |= (~(twodigits)0) << accumbits; + } + *p = (unsigned char)(accum & 0xff); + p += pincr; + } + else if (j == n && n > 0 && is_signed) { + /* The main loop filled the byte array exactly, so the code + just above didn't get to ensure there's a sign bit, and the + loop below wouldn't add one either. Make sure a sign bit + exists. */ + unsigned char msb = *(p - pincr); + int sign_bit_set = msb >= 0x80; + assert(accumbits == 0); + if (sign_bit_set == do_twos_comp) + return 0; + else + goto Overflow; + } + + /* Fill remaining bytes with copies of the sign bit. */ + { + unsigned char signbyte = do_twos_comp ? 0xffU : 0U; + for ( ; j < n; ++j, p += pincr) + *p = signbyte; + } + + return 0; + +Overflow: + PyErr_SetString(PyExc_OverflowError, "long too big to convert"); + return -1; + +} + +double +_PyLong_AsScaledDouble(PyObject *vv, int *exponent) +{ +/* NBITS_WANTED should be > the number of bits in a double's precision, + but small enough so that 2**NBITS_WANTED is within the normal double + range. nbitsneeded is set to 1 less than that because the most-significant + Python digit contains at least 1 significant bit, but we don't want to + bother counting them (catering to the worst case cheaply). + + 57 is one more than VAX-D double precision; I (Tim) don't know of a double + format with more precision than that; it's 1 larger so that we add in at + least one round bit to stand in for the ignored least-significant bits. +*/ +#define NBITS_WANTED 57 + PyLongObject *v; + double x; + const double multiplier = (double)(1L << SHIFT); + Py_ssize_t i; + int sign; + int nbitsneeded; + + if (vv == NULL || !PyLong_Check(vv)) { + PyErr_BadInternalCall(); + return -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + sign = 1; + if (i < 0) { + sign = -1; + i = -(i); + } + else if (i == 0) { + *exponent = 0; + return 0.0; + } + --i; + x = (double)v->ob_digit[i]; + nbitsneeded = NBITS_WANTED - 1; + /* Invariant: i Python digits remain unaccounted for. */ + while (i > 0 && nbitsneeded > 0) { + --i; + x = x * multiplier + (double)v->ob_digit[i]; + nbitsneeded -= SHIFT; + } + /* There are i digits we didn't shift in. Pretending they're all + zeroes, the true value is x * 2**(i*SHIFT). */ + *exponent = i; + assert(x > 0.0); + return x * sign; +#undef NBITS_WANTED +} + +/* Get a C double from a long int object. */ + +double +PyLong_AsDouble(PyObject *vv) +{ + int e = -1; + double x; + + if (vv == NULL || !PyLong_Check(vv)) { + PyErr_BadInternalCall(); + return -1; + } + x = _PyLong_AsScaledDouble(vv, &e); + if (x == -1.0 && PyErr_Occurred()) + return -1.0; + /* 'e' initialized to -1 to silence gcc-4.0.x, but it should be + set correctly after a successful _PyLong_AsScaledDouble() call */ + assert(e >= 0); + if (e > INT_MAX / SHIFT) + goto overflow; + errno = 0; + x = ldexp(x, e * SHIFT); + if (Py_OVERFLOWED(x)) + goto overflow; + return x; + +overflow: + PyErr_SetString(PyExc_OverflowError, + "long int too large to convert to float"); + return -1.0; +} + +/* Create a new long (or int) object from a C pointer */ + +PyObject * +PyLong_FromVoidPtr(void *p) +{ +#if SIZEOF_VOID_P <= SIZEOF_LONG + if ((long)p < 0) + return PyLong_FromUnsignedLong((unsigned long)p); + return PyInt_FromLong((long)p); +#else + +#ifndef HAVE_LONG_LONG +# error "PyLong_FromVoidPtr: sizeof(void*) > sizeof(long), but no long long" +#endif +#if SIZEOF_LONG_LONG < SIZEOF_VOID_P +# error "PyLong_FromVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)" +#endif + /* optimize null pointers */ + if (p == NULL) + return PyInt_FromLong(0); + return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)p); + +#endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ +} + +/* Get a C pointer from a long object (or an int object in some cases) */ + +void * +PyLong_AsVoidPtr(PyObject *vv) +{ + /* This function will allow int or long objects. If vv is neither, + then the PyLong_AsLong*() functions will raise the exception: + PyExc_SystemError, "bad argument to internal function" + */ +#if SIZEOF_VOID_P <= SIZEOF_LONG + long x; + + if (PyInt_Check(vv)) + x = PyInt_AS_LONG(vv); + else if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + x = PyLong_AsLong(vv); + else + x = PyLong_AsUnsignedLong(vv); +#else + +#ifndef HAVE_LONG_LONG +# error "PyLong_AsVoidPtr: sizeof(void*) > sizeof(long), but no long long" +#endif +#if SIZEOF_LONG_LONG < SIZEOF_VOID_P +# error "PyLong_AsVoidPtr: sizeof(PY_LONG_LONG) < sizeof(void*)" +#endif + PY_LONG_LONG x; + + if (PyInt_Check(vv)) + x = PyInt_AS_LONG(vv); + else if (PyLong_Check(vv) && _PyLong_Sign(vv) < 0) + x = PyLong_AsLongLong(vv); + else + x = PyLong_AsUnsignedLongLong(vv); + +#endif /* SIZEOF_VOID_P <= SIZEOF_LONG */ + + if (x == -1 && PyErr_Occurred()) + return NULL; + return (void *)x; +} + +#ifdef HAVE_LONG_LONG + +/* Initial PY_LONG_LONG support by Chris Herborth (chrish@qnx.com), later + * rewritten to use the newer PyLong_{As,From}ByteArray API. + */ + +#define IS_LITTLE_ENDIAN (int)*(unsigned char*)&one + +/* Create a new long int object from a C PY_LONG_LONG int. */ + +PyObject * +PyLong_FromLongLong(PY_LONG_LONG ival) +{ + PyLongObject *v; + unsigned PY_LONG_LONG t; /* unsigned so >> doesn't propagate sign bit */ + int ndigits = 0; + int negative = 0; + + if (ival < 0) { + ival = -ival; + negative = 1; + } + + /* Count the number of Python digits. + We used to pick 5 ("big enough for anything"), but that's a + waste of time and space given that 5*15 = 75 bits are rarely + needed. */ + t = (unsigned PY_LONG_LONG)ival; + while (t) { + ++ndigits; + t >>= SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + v->ob_size = negative ? -ndigits : ndigits; + t = (unsigned PY_LONG_LONG)ival; + while (t) { + *p++ = (digit)(t & MASK); + t >>= SHIFT; + } + } + return (PyObject *)v; +} + +/* Create a new long int object from a C unsigned PY_LONG_LONG int. */ + +PyObject * +PyLong_FromUnsignedLongLong(unsigned PY_LONG_LONG ival) +{ + PyLongObject *v; + unsigned PY_LONG_LONG t; + int ndigits = 0; + + /* Count the number of Python digits. */ + t = (unsigned PY_LONG_LONG)ival; + while (t) { + ++ndigits; + t >>= SHIFT; + } + v = _PyLong_New(ndigits); + if (v != NULL) { + digit *p = v->ob_digit; + v->ob_size = ndigits; + while (ival) { + *p++ = (digit)(ival & MASK); + ival >>= SHIFT; + } + } + return (PyObject *)v; +} + +/* Create a new long int object from a C Py_ssize_t. */ + +PyObject * +_PyLong_FromSsize_t(Py_ssize_t ival) +{ + Py_ssize_t bytes = ival; + int one = 1; + return _PyLong_FromByteArray( + (unsigned char *)&bytes, + SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 0); +} + +/* Create a new long int object from a C size_t. */ + +PyObject * +_PyLong_FromSize_t(size_t ival) +{ + size_t bytes = ival; + int one = 1; + return _PyLong_FromByteArray( + (unsigned char *)&bytes, + SIZEOF_SIZE_T, IS_LITTLE_ENDIAN, 0); +} + +/* Get a C PY_LONG_LONG int from a long int object. + Return -1 and set an error if overflow occurs. */ + +PY_LONG_LONG +PyLong_AsLongLong(PyObject *vv) +{ + PY_LONG_LONG bytes; + int one = 1; + int res; + + if (vv == NULL) { + PyErr_BadInternalCall(); + return -1; + } + if (!PyLong_Check(vv)) { + PyNumberMethods *nb; + PyObject *io; + if (PyInt_Check(vv)) + return (PY_LONG_LONG)PyInt_AsLong(vv); + if ((nb = vv->ob_type->tp_as_number) == NULL || + nb->nb_int == NULL) { + PyErr_SetString(PyExc_TypeError, "an integer is required"); + return -1; + } + io = (*nb->nb_int) (vv); + if (io == NULL) + return -1; + if (PyInt_Check(io)) { + bytes = PyInt_AsLong(io); + Py_DECREF(io); + return bytes; + } + if (PyLong_Check(io)) { + bytes = PyLong_AsLongLong(io); + Py_DECREF(io); + return bytes; + } + Py_DECREF(io); + PyErr_SetString(PyExc_TypeError, "integer conversion failed"); + return -1; + } + + res = _PyLong_AsByteArray( + (PyLongObject *)vv, (unsigned char *)&bytes, + SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 1); + + /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */ + if (res < 0) + return (PY_LONG_LONG)-1; + else + return bytes; +} + +/* Get a C unsigned PY_LONG_LONG int from a long int object. + Return -1 and set an error if overflow occurs. */ + +unsigned PY_LONG_LONG +PyLong_AsUnsignedLongLong(PyObject *vv) +{ + unsigned PY_LONG_LONG bytes; + int one = 1; + int res; + + if (vv == NULL || !PyLong_Check(vv)) { + PyErr_BadInternalCall(); + return (unsigned PY_LONG_LONG)-1; + } + + res = _PyLong_AsByteArray( + (PyLongObject *)vv, (unsigned char *)&bytes, + SIZEOF_LONG_LONG, IS_LITTLE_ENDIAN, 0); + + /* Plan 9 can't handle PY_LONG_LONG in ? : expressions */ + if (res < 0) + return (unsigned PY_LONG_LONG)res; + else + return bytes; +} + +/* Get a C unsigned long int from a long int object, ignoring the high bits. + Returns -1 and sets an error condition if an error occurs. */ + +unsigned PY_LONG_LONG +PyLong_AsUnsignedLongLongMask(PyObject *vv) +{ + register PyLongObject *v; + unsigned PY_LONG_LONG x; + Py_ssize_t i; + int sign; + + if (vv == NULL || !PyLong_Check(vv)) { + PyErr_BadInternalCall(); + return (unsigned long) -1; + } + v = (PyLongObject *)vv; + i = v->ob_size; + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -i; + } + while (--i >= 0) { + x = (x << SHIFT) + v->ob_digit[i]; + } + return x * sign; +} +#undef IS_LITTLE_ENDIAN + +#endif /* HAVE_LONG_LONG */ + + +static int +convert_binop(PyObject *v, PyObject *w, PyLongObject **a, PyLongObject **b) { + if (PyLong_Check(v)) { + *a = (PyLongObject *) v; + Py_INCREF(v); + } + else if (PyInt_Check(v)) { + *a = (PyLongObject *) PyLong_FromLong(PyInt_AS_LONG(v)); + } + else { + return 0; + } + if (PyLong_Check(w)) { + *b = (PyLongObject *) w; + Py_INCREF(w); + } + else if (PyInt_Check(w)) { + *b = (PyLongObject *) PyLong_FromLong(PyInt_AS_LONG(w)); + } + else { + Py_DECREF(*a); + return 0; + } + return 1; +} + +#define CONVERT_BINOP(v, w, a, b) \ + if (!convert_binop(v, w, a, b)) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } + +/* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] + * is modified in place, by adding y to it. Carries are propagated as far as + * x[m-1], and the remaining carry (0 or 1) is returned. + */ +static digit +v_iadd(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n) +{ + int i; + digit carry = 0; + + assert(m >= n); + for (i = 0; i < n; ++i) { + carry += x[i] + y[i]; + x[i] = carry & MASK; + carry >>= SHIFT; + assert((carry & 1) == carry); + } + for (; carry && i < m; ++i) { + carry += x[i]; + x[i] = carry & MASK; + carry >>= SHIFT; + assert((carry & 1) == carry); + } + return carry; +} + +/* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] + * is modified in place, by subtracting y from it. Borrows are propagated as + * far as x[m-1], and the remaining borrow (0 or 1) is returned. + */ +static digit +v_isub(digit *x, Py_ssize_t m, digit *y, Py_ssize_t n) +{ + int i; + digit borrow = 0; + + assert(m >= n); + for (i = 0; i < n; ++i) { + borrow = x[i] - y[i] - borrow; + x[i] = borrow & MASK; + borrow >>= SHIFT; + borrow &= 1; /* keep only 1 sign bit */ + } + for (; borrow && i < m; ++i) { + borrow = x[i] - borrow; + x[i] = borrow & MASK; + borrow >>= SHIFT; + borrow &= 1; + } + return borrow; +} + +/* Multiply by a single digit, ignoring the sign. */ + +static PyLongObject * +mul1(PyLongObject *a, wdigit n) +{ + return muladd1(a, n, (digit)0); +} + +/* Multiply by a single digit and add a single digit, ignoring the sign. */ + +static PyLongObject * +muladd1(PyLongObject *a, wdigit n, wdigit extra) +{ + Py_ssize_t size_a = ABS(a->ob_size); + PyLongObject *z = _PyLong_New(size_a+1); + twodigits carry = extra; + Py_ssize_t i; + + if (z == NULL) + return NULL; + for (i = 0; i < size_a; ++i) { + carry += (twodigits)a->ob_digit[i] * n; + z->ob_digit[i] = (digit) (carry & MASK); + carry >>= SHIFT; + } + z->ob_digit[i] = (digit) carry; + return long_normalize(z); +} + +/* Divide long pin, w/ size digits, by non-zero digit n, storing quotient + in pout, and returning the remainder. pin and pout point at the LSD. + It's OK for pin == pout on entry, which saves oodles of mallocs/frees in + long_format, but that should be done with great care since longs are + immutable. */ + +static digit +inplace_divrem1(digit *pout, digit *pin, Py_ssize_t size, digit n) +{ + twodigits rem = 0; + + assert(n > 0 && n <= MASK); + pin += size; + pout += size; + while (--size >= 0) { + digit hi; + rem = (rem << SHIFT) + *--pin; + *--pout = hi = (digit)(rem / n); + rem -= hi * n; + } + return (digit)rem; +} + +/* Divide a long integer by a digit, returning both the quotient + (as function result) and the remainder (through *prem). + The sign of a is ignored; n should not be zero. */ + +static PyLongObject * +divrem1(PyLongObject *a, digit n, digit *prem) +{ + const Py_ssize_t size = ABS(a->ob_size); + PyLongObject *z; + + assert(n > 0 && n <= MASK); + z = _PyLong_New(size); + if (z == NULL) + return NULL; + *prem = inplace_divrem1(z->ob_digit, a->ob_digit, size, n); + return long_normalize(z); +} + +/* Convert a long int object to a string, using a given conversion base. + Return a string object. + If base is 8 or 16, add the proper prefix '0' or '0x'. */ + +static PyObject * +long_format(PyObject *aa, int base, int addL) +{ + register PyLongObject *a = (PyLongObject *)aa; + PyStringObject *str; + Py_ssize_t i, j, sz; + Py_ssize_t size_a; + char *p; + int bits; + char sign = '\0'; + + if (a == NULL || !PyLong_Check(a)) { + PyErr_BadInternalCall(); + return NULL; + } + assert(base >= 2 && base <= 36); + size_a = ABS(a->ob_size); + + /* Compute a rough upper bound for the length of the string */ + i = base; + bits = 0; + while (i > 1) { + ++bits; + i >>= 1; + } + i = 5 + (addL ? 1 : 0); + j = size_a*SHIFT + bits-1; + sz = i + j / bits; + if (j / SHIFT < size_a || sz < i) { + PyErr_SetString(PyExc_OverflowError, + "long is too large to format"); + return NULL; + } + str = (PyStringObject *) PyString_FromStringAndSize((char *)0, sz); + if (str == NULL) + return NULL; + p = PyString_AS_STRING(str) + sz; + *p = '\0'; + if (addL) + *--p = 'L'; + if (a->ob_size < 0) + sign = '-'; + + if (a->ob_size == 0) { + *--p = '0'; + } + else if ((base & (base - 1)) == 0) { + /* JRH: special case for power-of-2 bases */ + twodigits accum = 0; + int accumbits = 0; /* # of bits in accum */ + int basebits = 1; /* # of bits in base-1 */ + i = base; + while ((i >>= 1) > 1) + ++basebits; + + for (i = 0; i < size_a; ++i) { + accum |= (twodigits)a->ob_digit[i] << accumbits; + accumbits += SHIFT; + assert(accumbits >= basebits); + do { + char cdigit = (char)(accum & (base - 1)); + cdigit += (cdigit < 10) ? '0' : 'a'-10; + assert(p > PyString_AS_STRING(str)); + *--p = cdigit; + accumbits -= basebits; + accum >>= basebits; + } while (i < size_a-1 ? accumbits >= basebits : + accum > 0); + } + } + else { + /* Not 0, and base not a power of 2. Divide repeatedly by + base, but for speed use the highest power of base that + fits in a digit. */ + Py_ssize_t size = size_a; + digit *pin = a->ob_digit; + PyLongObject *scratch; + /* powbasw <- largest power of base that fits in a digit. */ + digit powbase = base; /* powbase == base ** power */ + int power = 1; + for (;;) { + unsigned long newpow = powbase * (unsigned long)base; + if (newpow >> SHIFT) /* doesn't fit in a digit */ + break; + powbase = (digit)newpow; + ++power; + } + + /* Get a scratch area for repeated division. */ + scratch = _PyLong_New(size); + if (scratch == NULL) { + Py_DECREF(str); + return NULL; + } + + /* Repeatedly divide by powbase. */ + do { + int ntostore = power; + digit rem = inplace_divrem1(scratch->ob_digit, + pin, size, powbase); + pin = scratch->ob_digit; /* no need to use a again */ + if (pin[size - 1] == 0) + --size; + SIGCHECK({ + Py_DECREF(scratch); + Py_DECREF(str); + return NULL; + }) + + /* Break rem into digits. */ + assert(ntostore > 0); + do { + digit nextrem = (digit)(rem / base); + char c = (char)(rem - nextrem * base); + assert(p > PyString_AS_STRING(str)); + c += (c < 10) ? '0' : 'a'-10; + *--p = c; + rem = nextrem; + --ntostore; + /* Termination is a bit delicate: must not + store leading zeroes, so must get out if + remaining quotient and rem are both 0. */ + } while (ntostore && (size || rem)); + } while (size != 0); + Py_DECREF(scratch); + } + + if (base == 8) { + if (size_a != 0) + *--p = '0'; + } + else if (base == 16) { + *--p = 'x'; + *--p = '0'; + } + else if (base != 10) { + *--p = '#'; + *--p = '0' + base%10; + if (base > 10) + *--p = '0' + base/10; + } + if (sign) + *--p = sign; + if (p != PyString_AS_STRING(str)) { + char *q = PyString_AS_STRING(str); + assert(p > q); + do { + } while ((*q++ = *p++) != '\0'); + q--; + _PyString_Resize((PyObject **)&str, + (Py_ssize_t) (q - PyString_AS_STRING(str))); + } + return (PyObject *)str; +} + +/* Table of digit values for 8-bit string -> integer conversion. + * '0' maps to 0, ..., '9' maps to 9. + * 'a' and 'A' map to 10, ..., 'z' and 'Z' map to 35. + * All other indices map to 37. + * Note that when converting a base B string, a char c is a legitimate + * base B digit iff _PyLong_DigitValue[Py_CHARMASK(c)] < B. + */ +int _PyLong_DigitValue[256] = { + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 37, 37, 37, 37, 37, 37, + 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37, + 37, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, +}; + +/* *str points to the first digit in a string of base `base` digits. base + * is a power of 2 (2, 4, 8, 16, or 32). *str is set to point to the first + * non-digit (which may be *str!). A normalized long is returned. + * The point to this routine is that it takes time linear in the number of + * string characters. + */ +static PyLongObject * +long_from_binary_base(char **str, int base) +{ + char *p = *str; + char *start = p; + int bits_per_char; + Py_ssize_t n; + PyLongObject *z; + twodigits accum; + int bits_in_accum; + digit *pdigit; + + assert(base >= 2 && base <= 32 && (base & (base - 1)) == 0); + n = base; + for (bits_per_char = -1; n; ++bits_per_char) + n >>= 1; + /* n <- total # of bits needed, while setting p to end-of-string */ + n = 0; + while (_PyLong_DigitValue[Py_CHARMASK(*p)] < base) + ++p; + *str = p; + /* n <- # of Python digits needed, = ceiling(n/SHIFT). */ + n = (p - start) * bits_per_char + SHIFT - 1; + if (n / bits_per_char < p - start) { + PyErr_SetString(PyExc_ValueError, + "long string too large to convert"); + return NULL; + } + n = n / SHIFT; + z = _PyLong_New(n); + if (z == NULL) + return NULL; + /* Read string from right, and fill in long from left; i.e., + * from least to most significant in both. + */ + accum = 0; + bits_in_accum = 0; + pdigit = z->ob_digit; + while (--p >= start) { + int k = _PyLong_DigitValue[Py_CHARMASK(*p)]; + assert(k >= 0 && k < base); + accum |= (twodigits)(k << bits_in_accum); + bits_in_accum += bits_per_char; + if (bits_in_accum >= SHIFT) { + *pdigit++ = (digit)(accum & MASK); + assert(pdigit - z->ob_digit <= (int)n); + accum >>= SHIFT; + bits_in_accum -= SHIFT; + assert(bits_in_accum < SHIFT); + } + } + if (bits_in_accum) { + assert(bits_in_accum <= SHIFT); + *pdigit++ = (digit)accum; + assert(pdigit - z->ob_digit <= (int)n); + } + while (pdigit - z->ob_digit < n) + *pdigit++ = 0; + return long_normalize(z); +} + +PyObject * +PyLong_FromString(char *str, char **pend, int base) +{ + int sign = 1; + char *start, *orig_str = str; + PyLongObject *z; + PyObject *strobj, *strrepr; + Py_ssize_t slen; + + if ((base != 0 && base < 2) || base > 36) { + PyErr_SetString(PyExc_ValueError, + "long() arg 2 must be >= 2 and <= 36"); + return NULL; + } + while (*str != '\0' && isspace(Py_CHARMASK(*str))) + str++; + if (*str == '+') + ++str; + else if (*str == '-') { + ++str; + sign = -1; + } + while (*str != '\0' && isspace(Py_CHARMASK(*str))) + str++; + if (base == 0) { + if (str[0] != '0') + base = 10; + else if (str[1] == 'x' || str[1] == 'X') + base = 16; + else + base = 8; + } + if (base == 16 && str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) + str += 2; + + start = str; + if ((base & (base - 1)) == 0) + z = long_from_binary_base(&str, base); + else { +/*** +Binary bases can be converted in time linear in the number of digits, because +Python's representation base is binary. Other bases (including decimal!) use +the simple quadratic-time algorithm below, complicated by some speed tricks. + +First some math: the largest integer that can be expressed in N base-B digits +is B**N-1. Consequently, if we have an N-digit input in base B, the worst- +case number of Python digits needed to hold it is the smallest integer n s.t. + + BASE**n-1 >= B**N-1 [or, adding 1 to both sides] + BASE**n >= B**N [taking logs to base BASE] + n >= log(B**N)/log(BASE) = N * log(B)/log(BASE) + +The static array log_base_BASE[base] == log(base)/log(BASE) so we can compute +this quickly. A Python long with that much space is reserved near the start, +and the result is computed into it. + +The input string is actually treated as being in base base**i (i.e., i digits +are processed at a time), where two more static arrays hold: + + convwidth_base[base] = the largest integer i such that base**i <= BASE + convmultmax_base[base] = base ** convwidth_base[base] + +The first of these is the largest i such that i consecutive input digits +must fit in a single Python digit. The second is effectively the input +base we're really using. + +Viewing the input as a sequence <c0, c1, ..., c_n-1> of digits in base +convmultmax_base[base], the result is "simply" + + (((c0*B + c1)*B + c2)*B + c3)*B + ... ))) + c_n-1 + +where B = convmultmax_base[base]. + +Error analysis: as above, the number of Python digits `n` needed is worst- +case + + n >= N * log(B)/log(BASE) + +where `N` is the number of input digits in base `B`. This is computed via + + size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1; + +below. Two numeric concerns are how much space this can waste, and whether +the computed result can be too small. To be concrete, assume BASE = 2**15, +which is the default (and it's unlikely anyone changes that). + +Waste isn't a problem: provided the first input digit isn't 0, the difference +between the worst-case input with N digits and the smallest input with N +digits is about a factor of B, but B is small compared to BASE so at most +one allocated Python digit can remain unused on that count. If +N*log(B)/log(BASE) is mathematically an exact integer, then truncating that +and adding 1 returns a result 1 larger than necessary. However, that can't +happen: whenever B is a power of 2, long_from_binary_base() is called +instead, and it's impossible for B**i to be an integer power of 2**15 when +B is not a power of 2 (i.e., it's impossible for N*log(B)/log(BASE) to be +an exact integer when B is not a power of 2, since B**i has a prime factor +other than 2 in that case, but (2**15)**j's only prime factor is 2). + +The computed result can be too small if the true value of N*log(B)/log(BASE) +is a little bit larger than an exact integer, but due to roundoff errors (in +computing log(B), log(BASE), their quotient, and/or multiplying that by N) +yields a numeric result a little less than that integer. Unfortunately, "how +close can a transcendental function get to an integer over some range?" +questions are generally theoretically intractable. Computer analysis via +continued fractions is practical: expand log(B)/log(BASE) via continued +fractions, giving a sequence i/j of "the best" rational approximations. Then +j*log(B)/log(BASE) is approximately equal to (the integer) i. This shows that +we can get very close to being in trouble, but very rarely. For example, +76573 is a denominator in one of the continued-fraction approximations to +log(10)/log(2**15), and indeed: + + >>> log(10)/log(2**15)*76573 + 16958.000000654003 + +is very close to an integer. If we were working with IEEE single-precision, +rounding errors could kill us. Finding worst cases in IEEE double-precision +requires better-than-double-precision log() functions, and Tim didn't bother. +Instead the code checks to see whether the allocated space is enough as each +new Python digit is added, and copies the whole thing to a larger long if not. +This should happen extremely rarely, and in fact I don't have a test case +that triggers it(!). Instead the code was tested by artificially allocating +just 1 digit at the start, so that the copying code was exercised for every +digit beyond the first. +***/ + register twodigits c; /* current input character */ + Py_ssize_t size_z; + int i; + int convwidth; + twodigits convmultmax, convmult; + digit *pz, *pzstop; + char* scan; + + static double log_base_BASE[37] = {0.0e0,}; + static int convwidth_base[37] = {0,}; + static twodigits convmultmax_base[37] = {0,}; + + if (log_base_BASE[base] == 0.0) { + twodigits convmax = base; + int i = 1; + + log_base_BASE[base] = log((double)base) / + log((double)BASE); + for (;;) { + twodigits next = convmax * base; + if (next > BASE) + break; + convmax = next; + ++i; + } + convmultmax_base[base] = convmax; + assert(i > 0); + convwidth_base[base] = i; + } + + /* Find length of the string of numeric characters. */ + scan = str; + while (_PyLong_DigitValue[Py_CHARMASK(*scan)] < base) + ++scan; + + /* Create a long object that can contain the largest possible + * integer with this base and length. Note that there's no + * need to initialize z->ob_digit -- no slot is read up before + * being stored into. + */ + size_z = (Py_ssize_t)((scan - str) * log_base_BASE[base]) + 1; + /* Uncomment next line to test exceedingly rare copy code */ + /* size_z = 1; */ + assert(size_z > 0); + z = _PyLong_New(size_z); + if (z == NULL) + return NULL; + z->ob_size = 0; + + /* `convwidth` consecutive input digits are treated as a single + * digit in base `convmultmax`. + */ + convwidth = convwidth_base[base]; + convmultmax = convmultmax_base[base]; + + /* Work ;-) */ + while (str < scan) { + /* grab up to convwidth digits from the input string */ + c = (digit)_PyLong_DigitValue[Py_CHARMASK(*str++)]; + for (i = 1; i < convwidth && str != scan; ++i, ++str) { + c = (twodigits)(c * base + + _PyLong_DigitValue[Py_CHARMASK(*str)]); + assert(c < BASE); + } + + convmult = convmultmax; + /* Calculate the shift only if we couldn't get + * convwidth digits. + */ + if (i != convwidth) { + convmult = base; + for ( ; i > 1; --i) + convmult *= base; + } + + /* Multiply z by convmult, and add c. */ + pz = z->ob_digit; + pzstop = pz + z->ob_size; + for (; pz < pzstop; ++pz) { + c += (twodigits)*pz * convmult; + *pz = (digit)(c & MASK); + c >>= SHIFT; + } + /* carry off the current end? */ + if (c) { + assert(c < BASE); + if (z->ob_size < size_z) { + *pz = (digit)c; + ++z->ob_size; + } + else { + PyLongObject *tmp; + /* Extremely rare. Get more space. */ + assert(z->ob_size == size_z); + tmp = _PyLong_New(size_z + 1); + if (tmp == NULL) { + Py_DECREF(z); + return NULL; + } + memcpy(tmp->ob_digit, + z->ob_digit, + sizeof(digit) * size_z); + Py_DECREF(z); + z = tmp; + z->ob_digit[size_z] = (digit)c; + ++size_z; + } + } + } + } + if (z == NULL) + return NULL; + if (str == start) + goto onError; + if (sign < 0) + z->ob_size = -(z->ob_size); + if (*str == 'L' || *str == 'l') + str++; + while (*str && isspace(Py_CHARMASK(*str))) + str++; + if (*str != '\0') + goto onError; + if (pend) + *pend = str; + return (PyObject *) z; + + onError: + Py_XDECREF(z); + slen = strlen(orig_str) < 200 ? strlen(orig_str) : 200; + strobj = PyString_FromStringAndSize(orig_str, slen); + if (strobj == NULL) + return NULL; + strrepr = PyObject_Repr(strobj); + Py_DECREF(strobj); + if (strrepr == NULL) + return NULL; + PyErr_Format(PyExc_ValueError, + "invalid literal for long() with base %d: %s", + base, PyString_AS_STRING(strrepr)); + Py_DECREF(strrepr); + return NULL; +} + +#ifdef Py_USING_UNICODE +PyObject * +PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) +{ + PyObject *result; + char *buffer = (char *)PyMem_MALLOC(length+1); + + if (buffer == NULL) + return NULL; + + if (PyUnicode_EncodeDecimal(u, length, buffer, NULL)) { + PyMem_FREE(buffer); + return NULL; + } + result = PyLong_FromString(buffer, NULL, base); + PyMem_FREE(buffer); + return result; +} +#endif + +/* forward */ +static PyLongObject *x_divrem + (PyLongObject *, PyLongObject *, PyLongObject **); +static PyObject *long_pos(PyLongObject *); +static int long_divrem(PyLongObject *, PyLongObject *, + PyLongObject **, PyLongObject **); + +/* Long division with remainder, top-level routine */ + +static int +long_divrem(PyLongObject *a, PyLongObject *b, + PyLongObject **pdiv, PyLongObject **prem) +{ + Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size); + PyLongObject *z; + + if (size_b == 0) { + PyErr_SetString(PyExc_ZeroDivisionError, + "long division or modulo by zero"); + return -1; + } + if (size_a < size_b || + (size_a == size_b && + a->ob_digit[size_a-1] < b->ob_digit[size_b-1])) { + /* |a| < |b|. */ + *pdiv = _PyLong_New(0); + Py_INCREF(a); + *prem = (PyLongObject *) a; + return 0; + } + if (size_b == 1) { + digit rem = 0; + z = divrem1(a, b->ob_digit[0], &rem); + if (z == NULL) + return -1; + *prem = (PyLongObject *) PyLong_FromLong((long)rem); + } + else { + z = x_divrem(a, b, prem); + if (z == NULL) + return -1; + } + /* Set the signs. + The quotient z has the sign of a*b; + the remainder r has the sign of a, + so a = b*z + r. */ + if ((a->ob_size < 0) != (b->ob_size < 0)) + z->ob_size = -(z->ob_size); + if (a->ob_size < 0 && (*prem)->ob_size != 0) + (*prem)->ob_size = -((*prem)->ob_size); + *pdiv = z; + return 0; +} + +/* Unsigned long division with remainder -- the algorithm */ + +static PyLongObject * +x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) +{ + Py_ssize_t size_v = ABS(v1->ob_size), size_w = ABS(w1->ob_size); + digit d = (digit) ((twodigits)BASE / (w1->ob_digit[size_w-1] + 1)); + PyLongObject *v = mul1(v1, d); + PyLongObject *w = mul1(w1, d); + PyLongObject *a; + Py_ssize_t j, k; + + if (v == NULL || w == NULL) { + Py_XDECREF(v); + Py_XDECREF(w); + return NULL; + } + + assert(size_v >= size_w && size_w > 1); /* Assert checks by div() */ + assert(v->ob_refcnt == 1); /* Since v will be used as accumulator! */ + assert(size_w == ABS(w->ob_size)); /* That's how d was calculated */ + + size_v = ABS(v->ob_size); + k = size_v - size_w; + a = _PyLong_New(k + 1); + + for (j = size_v; a != NULL && k >= 0; --j, --k) { + digit vj = (j >= size_v) ? 0 : v->ob_digit[j]; + twodigits q; + stwodigits carry = 0; + int i; + + SIGCHECK({ + Py_DECREF(a); + a = NULL; + break; + }) + if (vj == w->ob_digit[size_w-1]) + q = MASK; + else + q = (((twodigits)vj << SHIFT) + v->ob_digit[j-1]) / + w->ob_digit[size_w-1]; + + while (w->ob_digit[size_w-2]*q > + (( + ((twodigits)vj << SHIFT) + + v->ob_digit[j-1] + - q*w->ob_digit[size_w-1] + ) << SHIFT) + + v->ob_digit[j-2]) + --q; + + for (i = 0; i < size_w && i+k < size_v; ++i) { + twodigits z = w->ob_digit[i] * q; + digit zz = (digit) (z >> SHIFT); + carry += v->ob_digit[i+k] - z + + ((twodigits)zz << SHIFT); + v->ob_digit[i+k] = (digit)(carry & MASK); + carry = Py_ARITHMETIC_RIGHT_SHIFT(BASE_TWODIGITS_TYPE, + carry, SHIFT); + carry -= zz; + } + + if (i+k < size_v) { + carry += v->ob_digit[i+k]; + v->ob_digit[i+k] = 0; + } + + if (carry == 0) + a->ob_digit[k] = (digit) q; + else { + assert(carry == -1); + a->ob_digit[k] = (digit) q-1; + carry = 0; + for (i = 0; i < size_w && i+k < size_v; ++i) { + carry += v->ob_digit[i+k] + w->ob_digit[i]; + v->ob_digit[i+k] = (digit)(carry & MASK); + carry = Py_ARITHMETIC_RIGHT_SHIFT( + BASE_TWODIGITS_TYPE, + carry, SHIFT); + } + } + } /* for j, k */ + + if (a == NULL) + *prem = NULL; + else { + a = long_normalize(a); + *prem = divrem1(v, d, &d); + /* d receives the (unused) remainder */ + if (*prem == NULL) { + Py_DECREF(a); + a = NULL; + } + } + Py_DECREF(v); + Py_DECREF(w); + return a; +} + +/* Methods */ + +static void +long_dealloc(PyObject *v) +{ + v->ob_type->tp_free(v); +} + +static PyObject * +long_repr(PyObject *v) +{ + return long_format(v, 10, 1); +} + +static PyObject * +long_str(PyObject *v) +{ + return long_format(v, 10, 0); +} + +static int +long_compare(PyLongObject *a, PyLongObject *b) +{ + Py_ssize_t sign; + + if (a->ob_size != b->ob_size) { + if (ABS(a->ob_size) == 0 && ABS(b->ob_size) == 0) + sign = 0; + else + sign = a->ob_size - b->ob_size; + } + else { + Py_ssize_t i = ABS(a->ob_size); + while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]) + ; + if (i < 0) + sign = 0; + else { + sign = (int)a->ob_digit[i] - (int)b->ob_digit[i]; + if (a->ob_size < 0) + sign = -sign; + } + } + return sign < 0 ? -1 : sign > 0 ? 1 : 0; +} + +static long +long_hash(PyLongObject *v) +{ + long x; + Py_ssize_t i; + int sign; + + /* This is designed so that Python ints and longs with the + same value hash to the same value, otherwise comparisons + of mapping keys will turn out weird */ + i = v->ob_size; + sign = 1; + x = 0; + if (i < 0) { + sign = -1; + i = -(i); + } +#define LONG_BIT_SHIFT (8*sizeof(long) - SHIFT) + while (--i >= 0) { + /* Force a native long #-bits (32 or 64) circular shift */ + x = ((x << SHIFT) & ~MASK) | ((x >> LONG_BIT_SHIFT) & MASK); + x += v->ob_digit[i]; + } +#undef LONG_BIT_SHIFT + x = x * sign; + if (x == -1) + x = -2; + return x; +} + + +/* Add the absolute values of two long integers. */ + +static PyLongObject * +x_add(PyLongObject *a, PyLongObject *b) +{ + Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size); + PyLongObject *z; + int i; + digit carry = 0; + + /* Ensure a is the larger of the two: */ + if (size_a < size_b) { + { PyLongObject *temp = a; a = b; b = temp; } + { Py_ssize_t size_temp = size_a; + size_a = size_b; + size_b = size_temp; } + } + z = _PyLong_New(size_a+1); + if (z == NULL) + return NULL; + for (i = 0; i < size_b; ++i) { + carry += a->ob_digit[i] + b->ob_digit[i]; + z->ob_digit[i] = carry & MASK; + carry >>= SHIFT; + } + for (; i < size_a; ++i) { + carry += a->ob_digit[i]; + z->ob_digit[i] = carry & MASK; + carry >>= SHIFT; + } + z->ob_digit[i] = carry; + return long_normalize(z); +} + +/* Subtract the absolute values of two integers. */ + +static PyLongObject * +x_sub(PyLongObject *a, PyLongObject *b) +{ + Py_ssize_t size_a = ABS(a->ob_size), size_b = ABS(b->ob_size); + PyLongObject *z; + Py_ssize_t i; + int sign = 1; + digit borrow = 0; + + /* Ensure a is the larger of the two: */ + if (size_a < size_b) { + sign = -1; + { PyLongObject *temp = a; a = b; b = temp; } + { Py_ssize_t size_temp = size_a; + size_a = size_b; + size_b = size_temp; } + } + else if (size_a == size_b) { + /* Find highest digit where a and b differ: */ + i = size_a; + while (--i >= 0 && a->ob_digit[i] == b->ob_digit[i]) + ; + if (i < 0) + return _PyLong_New(0); + if (a->ob_digit[i] < b->ob_digit[i]) { + sign = -1; + { PyLongObject *temp = a; a = b; b = temp; } + } + size_a = size_b = i+1; + } + z = _PyLong_New(size_a); + if (z == NULL) + return NULL; + for (i = 0; i < size_b; ++i) { + /* The following assumes unsigned arithmetic + works module 2**N for some N>SHIFT. */ + borrow = a->ob_digit[i] - b->ob_digit[i] - borrow; + z->ob_digit[i] = borrow & MASK; + borrow >>= SHIFT; + borrow &= 1; /* Keep only one sign bit */ + } + for (; i < size_a; ++i) { + borrow = a->ob_digit[i] - borrow; + z->ob_digit[i] = borrow & MASK; + borrow >>= SHIFT; + borrow &= 1; /* Keep only one sign bit */ + } + assert(borrow == 0); + if (sign < 0) + z->ob_size = -(z->ob_size); + return long_normalize(z); +} + +static PyObject * +long_add(PyLongObject *v, PyLongObject *w) +{ + PyLongObject *a, *b, *z; + + CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); + + if (a->ob_size < 0) { + if (b->ob_size < 0) { + z = x_add(a, b); + if (z != NULL && z->ob_size != 0) + z->ob_size = -(z->ob_size); + } + else + z = x_sub(b, a); + } + else { + if (b->ob_size < 0) + z = x_sub(a, b); + else + z = x_add(a, b); + } + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *)z; +} + +static PyObject * +long_sub(PyLongObject *v, PyLongObject *w) +{ + PyLongObject *a, *b, *z; + + CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); + + if (a->ob_size < 0) { + if (b->ob_size < 0) + z = x_sub(a, b); + else + z = x_add(a, b); + if (z != NULL && z->ob_size != 0) + z->ob_size = -(z->ob_size); + } + else { + if (b->ob_size < 0) + z = x_add(a, b); + else + z = x_sub(a, b); + } + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *)z; +} + +/* Grade school multiplication, ignoring the signs. + * Returns the absolute value of the product, or NULL if error. + */ +static PyLongObject * +x_mul(PyLongObject *a, PyLongObject *b) +{ + PyLongObject *z; + Py_ssize_t size_a = ABS(a->ob_size); + Py_ssize_t size_b = ABS(b->ob_size); + Py_ssize_t i; + + z = _PyLong_New(size_a + size_b); + if (z == NULL) + return NULL; + + memset(z->ob_digit, 0, z->ob_size * sizeof(digit)); + if (a == b) { + /* Efficient squaring per HAC, Algorithm 14.16: + * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + * Gives slightly less than a 2x speedup when a == b, + * via exploiting that each entry in the multiplication + * pyramid appears twice (except for the size_a squares). + */ + for (i = 0; i < size_a; ++i) { + twodigits carry; + twodigits f = a->ob_digit[i]; + digit *pz = z->ob_digit + (i << 1); + digit *pa = a->ob_digit + i + 1; + digit *paend = a->ob_digit + size_a; + + SIGCHECK({ + Py_DECREF(z); + return NULL; + }) + + carry = *pz + f * f; + *pz++ = (digit)(carry & MASK); + carry >>= SHIFT; + assert(carry <= MASK); + + /* Now f is added in twice in each column of the + * pyramid it appears. Same as adding f<<1 once. + */ + f <<= 1; + while (pa < paend) { + carry += *pz + *pa++ * f; + *pz++ = (digit)(carry & MASK); + carry >>= SHIFT; + assert(carry <= (MASK << 1)); + } + if (carry) { + carry += *pz; + *pz++ = (digit)(carry & MASK); + carry >>= SHIFT; + } + if (carry) + *pz += (digit)(carry & MASK); + assert((carry >> SHIFT) == 0); + } + } + else { /* a is not the same as b -- gradeschool long mult */ + for (i = 0; i < size_a; ++i) { + twodigits carry = 0; + twodigits f = a->ob_digit[i]; + digit *pz = z->ob_digit + i; + digit *pb = b->ob_digit; + digit *pbend = b->ob_digit + size_b; + + SIGCHECK({ + Py_DECREF(z); + return NULL; + }) + + while (pb < pbend) { + carry += *pz + *pb++ * f; + *pz++ = (digit)(carry & MASK); + carry >>= SHIFT; + assert(carry <= MASK); + } + if (carry) + *pz += (digit)(carry & MASK); + assert((carry >> SHIFT) == 0); + } + } + return long_normalize(z); +} + +/* A helper for Karatsuba multiplication (k_mul). + Takes a long "n" and an integer "size" representing the place to + split, and sets low and high such that abs(n) == (high << size) + low, + viewing the shift as being by digits. The sign bit is ignored, and + the return values are >= 0. + Returns 0 on success, -1 on failure. +*/ +static int +kmul_split(PyLongObject *n, Py_ssize_t size, PyLongObject **high, PyLongObject **low) +{ + PyLongObject *hi, *lo; + Py_ssize_t size_lo, size_hi; + const Py_ssize_t size_n = ABS(n->ob_size); + + size_lo = MIN(size_n, size); + size_hi = size_n - size_lo; + + if ((hi = _PyLong_New(size_hi)) == NULL) + return -1; + if ((lo = _PyLong_New(size_lo)) == NULL) { + Py_DECREF(hi); + return -1; + } + + memcpy(lo->ob_digit, n->ob_digit, size_lo * sizeof(digit)); + memcpy(hi->ob_digit, n->ob_digit + size_lo, size_hi * sizeof(digit)); + + *high = long_normalize(hi); + *low = long_normalize(lo); + return 0; +} + +static PyLongObject *k_lopsided_mul(PyLongObject *a, PyLongObject *b); + +/* Karatsuba multiplication. Ignores the input signs, and returns the + * absolute value of the product (or NULL if error). + * See Knuth Vol. 2 Chapter 4.3.3 (Pp. 294-295). + */ +static PyLongObject * +k_mul(PyLongObject *a, PyLongObject *b) +{ + Py_ssize_t asize = ABS(a->ob_size); + Py_ssize_t bsize = ABS(b->ob_size); + PyLongObject *ah = NULL; + PyLongObject *al = NULL; + PyLongObject *bh = NULL; + PyLongObject *bl = NULL; + PyLongObject *ret = NULL; + PyLongObject *t1, *t2, *t3; + Py_ssize_t shift; /* the number of digits we split off */ + Py_ssize_t i; + + /* (ah*X+al)(bh*X+bl) = ah*bh*X*X + (ah*bl + al*bh)*X + al*bl + * Let k = (ah+al)*(bh+bl) = ah*bl + al*bh + ah*bh + al*bl + * Then the original product is + * ah*bh*X*X + (k - ah*bh - al*bl)*X + al*bl + * By picking X to be a power of 2, "*X" is just shifting, and it's + * been reduced to 3 multiplies on numbers half the size. + */ + + /* We want to split based on the larger number; fiddle so that b + * is largest. + */ + if (asize > bsize) { + t1 = a; + a = b; + b = t1; + + i = asize; + asize = bsize; + bsize = i; + } + + /* Use gradeschool math when either number is too small. */ + i = a == b ? KARATSUBA_SQUARE_CUTOFF : KARATSUBA_CUTOFF; + if (asize <= i) { + if (asize == 0) + return _PyLong_New(0); + else + return x_mul(a, b); + } + + /* If a is small compared to b, splitting on b gives a degenerate + * case with ah==0, and Karatsuba may be (even much) less efficient + * than "grade school" then. However, we can still win, by viewing + * b as a string of "big digits", each of width a->ob_size. That + * leads to a sequence of balanced calls to k_mul. + */ + if (2 * asize <= bsize) + return k_lopsided_mul(a, b); + + /* Split a & b into hi & lo pieces. */ + shift = bsize >> 1; + if (kmul_split(a, shift, &ah, &al) < 0) goto fail; + assert(ah->ob_size > 0); /* the split isn't degenerate */ + + if (a == b) { + bh = ah; + bl = al; + Py_INCREF(bh); + Py_INCREF(bl); + } + else if (kmul_split(b, shift, &bh, &bl) < 0) goto fail; + + /* The plan: + * 1. Allocate result space (asize + bsize digits: that's always + * enough). + * 2. Compute ah*bh, and copy into result at 2*shift. + * 3. Compute al*bl, and copy into result at 0. Note that this + * can't overlap with #2. + * 4. Subtract al*bl from the result, starting at shift. This may + * underflow (borrow out of the high digit), but we don't care: + * we're effectively doing unsigned arithmetic mod + * BASE**(sizea + sizeb), and so long as the *final* result fits, + * borrows and carries out of the high digit can be ignored. + * 5. Subtract ah*bh from the result, starting at shift. + * 6. Compute (ah+al)*(bh+bl), and add it into the result starting + * at shift. + */ + + /* 1. Allocate result space. */ + ret = _PyLong_New(asize + bsize); + if (ret == NULL) goto fail; +#ifdef Py_DEBUG + /* Fill with trash, to catch reference to uninitialized digits. */ + memset(ret->ob_digit, 0xDF, ret->ob_size * sizeof(digit)); +#endif + + /* 2. t1 <- ah*bh, and copy into high digits of result. */ + if ((t1 = k_mul(ah, bh)) == NULL) goto fail; + assert(t1->ob_size >= 0); + assert(2*shift + t1->ob_size <= ret->ob_size); + memcpy(ret->ob_digit + 2*shift, t1->ob_digit, + t1->ob_size * sizeof(digit)); + + /* Zero-out the digits higher than the ah*bh copy. */ + i = ret->ob_size - 2*shift - t1->ob_size; + if (i) + memset(ret->ob_digit + 2*shift + t1->ob_size, 0, + i * sizeof(digit)); + + /* 3. t2 <- al*bl, and copy into the low digits. */ + if ((t2 = k_mul(al, bl)) == NULL) { + Py_DECREF(t1); + goto fail; + } + assert(t2->ob_size >= 0); + assert(t2->ob_size <= 2*shift); /* no overlap with high digits */ + memcpy(ret->ob_digit, t2->ob_digit, t2->ob_size * sizeof(digit)); + + /* Zero out remaining digits. */ + i = 2*shift - t2->ob_size; /* number of uninitialized digits */ + if (i) + memset(ret->ob_digit + t2->ob_size, 0, i * sizeof(digit)); + + /* 4 & 5. Subtract ah*bh (t1) and al*bl (t2). We do al*bl first + * because it's fresher in cache. + */ + i = ret->ob_size - shift; /* # digits after shift */ + (void)v_isub(ret->ob_digit + shift, i, t2->ob_digit, t2->ob_size); + Py_DECREF(t2); + + (void)v_isub(ret->ob_digit + shift, i, t1->ob_digit, t1->ob_size); + Py_DECREF(t1); + + /* 6. t3 <- (ah+al)(bh+bl), and add into result. */ + if ((t1 = x_add(ah, al)) == NULL) goto fail; + Py_DECREF(ah); + Py_DECREF(al); + ah = al = NULL; + + if (a == b) { + t2 = t1; + Py_INCREF(t2); + } + else if ((t2 = x_add(bh, bl)) == NULL) { + Py_DECREF(t1); + goto fail; + } + Py_DECREF(bh); + Py_DECREF(bl); + bh = bl = NULL; + + t3 = k_mul(t1, t2); + Py_DECREF(t1); + Py_DECREF(t2); + if (t3 == NULL) goto fail; + assert(t3->ob_size >= 0); + + /* Add t3. It's not obvious why we can't run out of room here. + * See the (*) comment after this function. + */ + (void)v_iadd(ret->ob_digit + shift, i, t3->ob_digit, t3->ob_size); + Py_DECREF(t3); + + return long_normalize(ret); + + fail: + Py_XDECREF(ret); + Py_XDECREF(ah); + Py_XDECREF(al); + Py_XDECREF(bh); + Py_XDECREF(bl); + return NULL; +} + +/* (*) Why adding t3 can't "run out of room" above. + +Let f(x) mean the floor of x and c(x) mean the ceiling of x. Some facts +to start with: + +1. For any integer i, i = c(i/2) + f(i/2). In particular, + bsize = c(bsize/2) + f(bsize/2). +2. shift = f(bsize/2) +3. asize <= bsize +4. Since we call k_lopsided_mul if asize*2 <= bsize, asize*2 > bsize in this + routine, so asize > bsize/2 >= f(bsize/2) in this routine. + +We allocated asize + bsize result digits, and add t3 into them at an offset +of shift. This leaves asize+bsize-shift allocated digit positions for t3 +to fit into, = (by #1 and #2) asize + f(bsize/2) + c(bsize/2) - f(bsize/2) = +asize + c(bsize/2) available digit positions. + +bh has c(bsize/2) digits, and bl at most f(size/2) digits. So bh+hl has +at most c(bsize/2) digits + 1 bit. + +If asize == bsize, ah has c(bsize/2) digits, else ah has at most f(bsize/2) +digits, and al has at most f(bsize/2) digits in any case. So ah+al has at +most (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 1 bit. + +The product (ah+al)*(bh+bl) therefore has at most + + c(bsize/2) + (asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits + +and we have asize + c(bsize/2) available digit positions. We need to show +this is always enough. An instance of c(bsize/2) cancels out in both, so +the question reduces to whether asize digits is enough to hold +(asize == bsize ? c(bsize/2) : f(bsize/2)) digits + 2 bits. If asize < bsize, +then we're asking whether asize digits >= f(bsize/2) digits + 2 bits. By #4, +asize is at least f(bsize/2)+1 digits, so this in turn reduces to whether 1 +digit is enough to hold 2 bits. This is so since SHIFT=15 >= 2. If +asize == bsize, then we're asking whether bsize digits is enough to hold +c(bsize/2) digits + 2 bits, or equivalently (by #1) whether f(bsize/2) digits +is enough to hold 2 bits. This is so if bsize >= 2, which holds because +bsize >= KARATSUBA_CUTOFF >= 2. + +Note that since there's always enough room for (ah+al)*(bh+bl), and that's +clearly >= each of ah*bh and al*bl, there's always enough room to subtract +ah*bh and al*bl too. +*/ + +/* b has at least twice the digits of a, and a is big enough that Karatsuba + * would pay off *if* the inputs had balanced sizes. View b as a sequence + * of slices, each with a->ob_size digits, and multiply the slices by a, + * one at a time. This gives k_mul balanced inputs to work with, and is + * also cache-friendly (we compute one double-width slice of the result + * at a time, then move on, never bactracking except for the helpful + * single-width slice overlap between successive partial sums). + */ +static PyLongObject * +k_lopsided_mul(PyLongObject *a, PyLongObject *b) +{ + const Py_ssize_t asize = ABS(a->ob_size); + Py_ssize_t bsize = ABS(b->ob_size); + Py_ssize_t nbdone; /* # of b digits already multiplied */ + PyLongObject *ret; + PyLongObject *bslice = NULL; + + assert(asize > KARATSUBA_CUTOFF); + assert(2 * asize <= bsize); + + /* Allocate result space, and zero it out. */ + ret = _PyLong_New(asize + bsize); + if (ret == NULL) + return NULL; + memset(ret->ob_digit, 0, ret->ob_size * sizeof(digit)); + + /* Successive slices of b are copied into bslice. */ + bslice = _PyLong_New(asize); + if (bslice == NULL) + goto fail; + + nbdone = 0; + while (bsize > 0) { + PyLongObject *product; + const Py_ssize_t nbtouse = MIN(bsize, asize); + + /* Multiply the next slice of b by a. */ + memcpy(bslice->ob_digit, b->ob_digit + nbdone, + nbtouse * sizeof(digit)); + bslice->ob_size = nbtouse; + product = k_mul(a, bslice); + if (product == NULL) + goto fail; + + /* Add into result. */ + (void)v_iadd(ret->ob_digit + nbdone, ret->ob_size - nbdone, + product->ob_digit, product->ob_size); + Py_DECREF(product); + + bsize -= nbtouse; + nbdone += nbtouse; + } + + Py_DECREF(bslice); + return long_normalize(ret); + + fail: + Py_DECREF(ret); + Py_XDECREF(bslice); + return NULL; +} + +static PyObject * +long_mul(PyLongObject *v, PyLongObject *w) +{ + PyLongObject *a, *b, *z; + + if (!convert_binop((PyObject *)v, (PyObject *)w, &a, &b)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + z = k_mul(a, b); + /* Negate if exactly one of the inputs is negative. */ + if (((a->ob_size ^ b->ob_size) < 0) && z) + z->ob_size = -(z->ob_size); + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *)z; +} + +/* The / and % operators are now defined in terms of divmod(). + The expression a mod b has the value a - b*floor(a/b). + The long_divrem function gives the remainder after division of + |a| by |b|, with the sign of a. This is also expressed + as a - b*trunc(a/b), if trunc truncates towards zero. + Some examples: + a b a rem b a mod b + 13 10 3 3 + -13 10 -3 7 + 13 -10 3 -7 + -13 -10 -3 -3 + So, to get from rem to mod, we have to add b if a and b + have different signs. We then subtract one from the 'div' + part of the outcome to keep the invariant intact. */ + +/* Compute + * *pdiv, *pmod = divmod(v, w) + * NULL can be passed for pdiv or pmod, in which case that part of + * the result is simply thrown away. The caller owns a reference to + * each of these it requests (does not pass NULL for). + */ +static int +l_divmod(PyLongObject *v, PyLongObject *w, + PyLongObject **pdiv, PyLongObject **pmod) +{ + PyLongObject *div, *mod; + + if (long_divrem(v, w, &div, &mod) < 0) + return -1; + if ((mod->ob_size < 0 && w->ob_size > 0) || + (mod->ob_size > 0 && w->ob_size < 0)) { + PyLongObject *temp; + PyLongObject *one; + temp = (PyLongObject *) long_add(mod, w); + Py_DECREF(mod); + mod = temp; + if (mod == NULL) { + Py_DECREF(div); + return -1; + } + one = (PyLongObject *) PyLong_FromLong(1L); + if (one == NULL || + (temp = (PyLongObject *) long_sub(div, one)) == NULL) { + Py_DECREF(mod); + Py_DECREF(div); + Py_XDECREF(one); + return -1; + } + Py_DECREF(one); + Py_DECREF(div); + div = temp; + } + if (pdiv != NULL) + *pdiv = div; + else + Py_DECREF(div); + + if (pmod != NULL) + *pmod = mod; + else + Py_DECREF(mod); + + return 0; +} + +static PyObject * +long_div(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b, *div; + + CONVERT_BINOP(v, w, &a, &b); + if (l_divmod(a, b, &div, NULL) < 0) + div = NULL; + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *)div; +} + +static PyObject * +long_classic_div(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b, *div; + + CONVERT_BINOP(v, w, &a, &b); + if (Py_DivisionWarningFlag && + PyErr_Warn(PyExc_DeprecationWarning, "classic long division") < 0) + div = NULL; + else if (l_divmod(a, b, &div, NULL) < 0) + div = NULL; + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *)div; +} + +static PyObject * +long_true_divide(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b; + double ad, bd; + int failed, aexp = -1, bexp = -1; + + CONVERT_BINOP(v, w, &a, &b); + ad = _PyLong_AsScaledDouble((PyObject *)a, &aexp); + bd = _PyLong_AsScaledDouble((PyObject *)b, &bexp); + failed = (ad == -1.0 || bd == -1.0) && PyErr_Occurred(); + Py_DECREF(a); + Py_DECREF(b); + if (failed) + return NULL; + /* 'aexp' and 'bexp' were initialized to -1 to silence gcc-4.0.x, + but should really be set correctly after sucessful calls to + _PyLong_AsScaledDouble() */ + assert(aexp >= 0 && bexp >= 0); + + if (bd == 0.0) { + PyErr_SetString(PyExc_ZeroDivisionError, + "long division or modulo by zero"); + return NULL; + } + + /* True value is very close to ad/bd * 2**(SHIFT*(aexp-bexp)) */ + ad /= bd; /* overflow/underflow impossible here */ + aexp -= bexp; + if (aexp > INT_MAX / SHIFT) + goto overflow; + else if (aexp < -(INT_MAX / SHIFT)) + return PyFloat_FromDouble(0.0); /* underflow to 0 */ + errno = 0; + ad = ldexp(ad, aexp * SHIFT); + if (Py_OVERFLOWED(ad)) /* ignore underflow to 0.0 */ + goto overflow; + return PyFloat_FromDouble(ad); + +overflow: + PyErr_SetString(PyExc_OverflowError, + "long/long too large for a float"); + return NULL; + +} + +static PyObject * +long_mod(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b, *mod; + + CONVERT_BINOP(v, w, &a, &b); + + if (l_divmod(a, b, NULL, &mod) < 0) + mod = NULL; + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *)mod; +} + +static PyObject * +long_divmod(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b, *div, *mod; + PyObject *z; + + CONVERT_BINOP(v, w, &a, &b); + + if (l_divmod(a, b, &div, &mod) < 0) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + z = PyTuple_New(2); + if (z != NULL) { + PyTuple_SetItem(z, 0, (PyObject *) div); + PyTuple_SetItem(z, 1, (PyObject *) mod); + } + else { + Py_DECREF(div); + Py_DECREF(mod); + } + Py_DECREF(a); + Py_DECREF(b); + return z; +} + +/* pow(v, w, x) */ +static PyObject * +long_pow(PyObject *v, PyObject *w, PyObject *x) +{ + PyLongObject *a, *b, *c; /* a,b,c = v,w,x */ + int negativeOutput = 0; /* if x<0 return negative output */ + + PyLongObject *z = NULL; /* accumulated result */ + Py_ssize_t i, j, k; /* counters */ + PyLongObject *temp = NULL; + + /* 5-ary values. If the exponent is large enough, table is + * precomputed so that table[i] == a**i % c for i in range(32). + */ + PyLongObject *table[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + /* a, b, c = v, w, x */ + CONVERT_BINOP(v, w, &a, &b); + if (PyLong_Check(x)) { + c = (PyLongObject *)x; + Py_INCREF(x); + } + else if (PyInt_Check(x)) { + c = (PyLongObject *)PyLong_FromLong(PyInt_AS_LONG(x)); + if (c == NULL) + goto Error; + } + else if (x == Py_None) + c = NULL; + else { + Py_DECREF(a); + Py_DECREF(b); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + if (b->ob_size < 0) { /* if exponent is negative */ + if (c) { + PyErr_SetString(PyExc_TypeError, "pow() 2nd argument " + "cannot be negative when 3rd argument specified"); + goto Error; + } + else { + /* else return a float. This works because we know + that this calls float_pow() which converts its + arguments to double. */ + Py_DECREF(a); + Py_DECREF(b); + return PyFloat_Type.tp_as_number->nb_power(v, w, x); + } + } + + if (c) { + /* if modulus == 0: + raise ValueError() */ + if (c->ob_size == 0) { + PyErr_SetString(PyExc_ValueError, + "pow() 3rd argument cannot be 0"); + goto Error; + } + + /* if modulus < 0: + negativeOutput = True + modulus = -modulus */ + if (c->ob_size < 0) { + negativeOutput = 1; + temp = (PyLongObject *)_PyLong_Copy(c); + if (temp == NULL) + goto Error; + Py_DECREF(c); + c = temp; + temp = NULL; + c->ob_size = - c->ob_size; + } + + /* if modulus == 1: + return 0 */ + if ((c->ob_size == 1) && (c->ob_digit[0] == 1)) { + z = (PyLongObject *)PyLong_FromLong(0L); + goto Done; + } + + /* if base < 0: + base = base % modulus + Having the base positive just makes things easier. */ + if (a->ob_size < 0) { + if (l_divmod(a, c, NULL, &temp) < 0) + goto Error; + Py_DECREF(a); + a = temp; + temp = NULL; + } + } + + /* At this point a, b, and c are guaranteed non-negative UNLESS + c is NULL, in which case a may be negative. */ + + z = (PyLongObject *)PyLong_FromLong(1L); + if (z == NULL) + goto Error; + + /* Perform a modular reduction, X = X % c, but leave X alone if c + * is NULL. + */ +#define REDUCE(X) \ + if (c != NULL) { \ + if (l_divmod(X, c, NULL, &temp) < 0) \ + goto Error; \ + Py_XDECREF(X); \ + X = temp; \ + temp = NULL; \ + } + + /* Multiply two values, then reduce the result: + result = X*Y % c. If c is NULL, skip the mod. */ +#define MULT(X, Y, result) \ +{ \ + temp = (PyLongObject *)long_mul(X, Y); \ + if (temp == NULL) \ + goto Error; \ + Py_XDECREF(result); \ + result = temp; \ + temp = NULL; \ + REDUCE(result) \ +} + + if (b->ob_size <= FIVEARY_CUTOFF) { + /* Left-to-right binary exponentiation (HAC Algorithm 14.79) */ + /* http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf */ + for (i = b->ob_size - 1; i >= 0; --i) { + digit bi = b->ob_digit[i]; + + for (j = 1 << (SHIFT-1); j != 0; j >>= 1) { + MULT(z, z, z) + if (bi & j) + MULT(z, a, z) + } + } + } + else { + /* Left-to-right 5-ary exponentiation (HAC Algorithm 14.82) */ + Py_INCREF(z); /* still holds 1L */ + table[0] = z; + for (i = 1; i < 32; ++i) + MULT(table[i-1], a, table[i]) + + for (i = b->ob_size - 1; i >= 0; --i) { + const digit bi = b->ob_digit[i]; + + for (j = SHIFT - 5; j >= 0; j -= 5) { + const int index = (bi >> j) & 0x1f; + for (k = 0; k < 5; ++k) + MULT(z, z, z) + if (index) + MULT(z, table[index], z) + } + } + } + + if (negativeOutput && (z->ob_size != 0)) { + temp = (PyLongObject *)long_sub(z, c); + if (temp == NULL) + goto Error; + Py_DECREF(z); + z = temp; + temp = NULL; + } + goto Done; + + Error: + if (z != NULL) { + Py_DECREF(z); + z = NULL; + } + /* fall through */ + Done: + if (b->ob_size > FIVEARY_CUTOFF) { + for (i = 0; i < 32; ++i) + Py_XDECREF(table[i]); + } + Py_DECREF(a); + Py_DECREF(b); + Py_XDECREF(c); + Py_XDECREF(temp); + return (PyObject *)z; +} + +static PyObject * +long_invert(PyLongObject *v) +{ + /* Implement ~x as -(x+1) */ + PyLongObject *x; + PyLongObject *w; + w = (PyLongObject *)PyLong_FromLong(1L); + if (w == NULL) + return NULL; + x = (PyLongObject *) long_add(v, w); + Py_DECREF(w); + if (x == NULL) + return NULL; + x->ob_size = -(x->ob_size); + return (PyObject *)x; +} + +static PyObject * +long_pos(PyLongObject *v) +{ + if (PyLong_CheckExact(v)) { + Py_INCREF(v); + return (PyObject *)v; + } + else + return _PyLong_Copy(v); +} + +static PyObject * +long_neg(PyLongObject *v) +{ + PyLongObject *z; + if (v->ob_size == 0 && PyLong_CheckExact(v)) { + /* -0 == 0 */ + Py_INCREF(v); + return (PyObject *) v; + } + z = (PyLongObject *)_PyLong_Copy(v); + if (z != NULL) + z->ob_size = -(v->ob_size); + return (PyObject *)z; +} + +static PyObject * +long_abs(PyLongObject *v) +{ + if (v->ob_size < 0) + return long_neg(v); + else + return long_pos(v); +} + +static int +long_nonzero(PyLongObject *v) +{ + return ABS(v->ob_size) != 0; +} + +static PyObject * +long_rshift(PyLongObject *v, PyLongObject *w) +{ + PyLongObject *a, *b; + PyLongObject *z = NULL; + long shiftby; + Py_ssize_t newsize, wordshift, loshift, hishift, i, j; + digit lomask, himask; + + CONVERT_BINOP((PyObject *)v, (PyObject *)w, &a, &b); + + if (a->ob_size < 0) { + /* Right shifting negative numbers is harder */ + PyLongObject *a1, *a2; + a1 = (PyLongObject *) long_invert(a); + if (a1 == NULL) + goto rshift_error; + a2 = (PyLongObject *) long_rshift(a1, b); + Py_DECREF(a1); + if (a2 == NULL) + goto rshift_error; + z = (PyLongObject *) long_invert(a2); + Py_DECREF(a2); + } + else { + + shiftby = PyLong_AsLong((PyObject *)b); + if (shiftby == -1L && PyErr_Occurred()) + goto rshift_error; + if (shiftby < 0) { + PyErr_SetString(PyExc_ValueError, + "negative shift count"); + goto rshift_error; + } + wordshift = shiftby / SHIFT; + newsize = ABS(a->ob_size) - wordshift; + if (newsize <= 0) { + z = _PyLong_New(0); + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *)z; + } + loshift = shiftby % SHIFT; + hishift = SHIFT - loshift; + lomask = ((digit)1 << hishift) - 1; + himask = MASK ^ lomask; + z = _PyLong_New(newsize); + if (z == NULL) + goto rshift_error; + if (a->ob_size < 0) + z->ob_size = -(z->ob_size); + for (i = 0, j = wordshift; i < newsize; i++, j++) { + z->ob_digit[i] = (a->ob_digit[j] >> loshift) & lomask; + if (i+1 < newsize) + z->ob_digit[i] |= + (a->ob_digit[j+1] << hishift) & himask; + } + z = long_normalize(z); + } +rshift_error: + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *) z; + +} + +static PyObject * +long_lshift(PyObject *v, PyObject *w) +{ + /* This version due to Tim Peters */ + PyLongObject *a, *b; + PyLongObject *z = NULL; + long shiftby; + Py_ssize_t oldsize, newsize, wordshift, remshift, i, j; + twodigits accum; + + CONVERT_BINOP(v, w, &a, &b); + + shiftby = PyLong_AsLong((PyObject *)b); + if (shiftby == -1L && PyErr_Occurred()) + goto lshift_error; + if (shiftby < 0) { + PyErr_SetString(PyExc_ValueError, "negative shift count"); + goto lshift_error; + } + if ((long)(int)shiftby != shiftby) { + PyErr_SetString(PyExc_ValueError, + "outrageous left shift count"); + goto lshift_error; + } + /* wordshift, remshift = divmod(shiftby, SHIFT) */ + wordshift = (int)shiftby / SHIFT; + remshift = (int)shiftby - wordshift * SHIFT; + + oldsize = ABS(a->ob_size); + newsize = oldsize + wordshift; + if (remshift) + ++newsize; + z = _PyLong_New(newsize); + if (z == NULL) + goto lshift_error; + if (a->ob_size < 0) + z->ob_size = -(z->ob_size); + for (i = 0; i < wordshift; i++) + z->ob_digit[i] = 0; + accum = 0; + for (i = wordshift, j = 0; j < oldsize; i++, j++) { + accum |= (twodigits)a->ob_digit[j] << remshift; + z->ob_digit[i] = (digit)(accum & MASK); + accum >>= SHIFT; + } + if (remshift) + z->ob_digit[newsize-1] = (digit)accum; + else + assert(!accum); + z = long_normalize(z); +lshift_error: + Py_DECREF(a); + Py_DECREF(b); + return (PyObject *) z; +} + + +/* Bitwise and/xor/or operations */ + +static PyObject * +long_bitwise(PyLongObject *a, + int op, /* '&', '|', '^' */ + PyLongObject *b) +{ + digit maska, maskb; /* 0 or MASK */ + int negz; + Py_ssize_t size_a, size_b, size_z; + PyLongObject *z; + int i; + digit diga, digb; + PyObject *v; + + if (a->ob_size < 0) { + a = (PyLongObject *) long_invert(a); + if (a == NULL) + return NULL; + maska = MASK; + } + else { + Py_INCREF(a); + maska = 0; + } + if (b->ob_size < 0) { + b = (PyLongObject *) long_invert(b); + if (b == NULL) { + Py_DECREF(a); + return NULL; + } + maskb = MASK; + } + else { + Py_INCREF(b); + maskb = 0; + } + + negz = 0; + switch (op) { + case '^': + if (maska != maskb) { + maska ^= MASK; + negz = -1; + } + break; + case '&': + if (maska && maskb) { + op = '|'; + maska ^= MASK; + maskb ^= MASK; + negz = -1; + } + break; + case '|': + if (maska || maskb) { + op = '&'; + maska ^= MASK; + maskb ^= MASK; + negz = -1; + } + break; + } + + /* JRH: The original logic here was to allocate the result value (z) + as the longer of the two operands. However, there are some cases + where the result is guaranteed to be shorter than that: AND of two + positives, OR of two negatives: use the shorter number. AND with + mixed signs: use the positive number. OR with mixed signs: use the + negative number. After the transformations above, op will be '&' + iff one of these cases applies, and mask will be non-0 for operands + whose length should be ignored. + */ + + size_a = a->ob_size; + size_b = b->ob_size; + size_z = op == '&' + ? (maska + ? size_b + : (maskb ? size_a : MIN(size_a, size_b))) + : MAX(size_a, size_b); + z = _PyLong_New(size_z); + if (z == NULL) { + Py_DECREF(a); + Py_DECREF(b); + return NULL; + } + + for (i = 0; i < size_z; ++i) { + diga = (i < size_a ? a->ob_digit[i] : 0) ^ maska; + digb = (i < size_b ? b->ob_digit[i] : 0) ^ maskb; + switch (op) { + case '&': z->ob_digit[i] = diga & digb; break; + case '|': z->ob_digit[i] = diga | digb; break; + case '^': z->ob_digit[i] = diga ^ digb; break; + } + } + + Py_DECREF(a); + Py_DECREF(b); + z = long_normalize(z); + if (negz == 0) + return (PyObject *) z; + v = long_invert(z); + Py_DECREF(z); + return v; +} + +static PyObject * +long_and(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b; + PyObject *c; + CONVERT_BINOP(v, w, &a, &b); + c = long_bitwise(a, '&', b); + Py_DECREF(a); + Py_DECREF(b); + return c; +} + +static PyObject * +long_xor(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b; + PyObject *c; + CONVERT_BINOP(v, w, &a, &b); + c = long_bitwise(a, '^', b); + Py_DECREF(a); + Py_DECREF(b); + return c; +} + +static PyObject * +long_or(PyObject *v, PyObject *w) +{ + PyLongObject *a, *b; + PyObject *c; + CONVERT_BINOP(v, w, &a, &b); + c = long_bitwise(a, '|', b); + Py_DECREF(a); + Py_DECREF(b); + return c; +} + +static int +long_coerce(PyObject **pv, PyObject **pw) +{ + if (PyInt_Check(*pw)) { + *pw = PyLong_FromLong(PyInt_AS_LONG(*pw)); + Py_INCREF(*pv); + return 0; + } + else if (PyLong_Check(*pw)) { + Py_INCREF(*pv); + Py_INCREF(*pw); + return 0; + } + return 1; /* Can't do it */ +} + +static PyObject * +long_long(PyObject *v) +{ + if (PyLong_CheckExact(v)) + Py_INCREF(v); + else + v = _PyLong_Copy((PyLongObject *)v); + return v; +} + +static PyObject * +long_int(PyObject *v) +{ + long x; + x = PyLong_AsLong(v); + if (PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_Clear(); + if (PyLong_CheckExact(v)) { + Py_INCREF(v); + return v; + } + else + return _PyLong_Copy((PyLongObject *)v); + } + else + return NULL; + } + return PyInt_FromLong(x); +} + +static PyObject * +long_float(PyObject *v) +{ + double result; + result = PyLong_AsDouble(v); + if (result == -1.0 && PyErr_Occurred()) + return NULL; + return PyFloat_FromDouble(result); +} + +static PyObject * +long_oct(PyObject *v) +{ + return long_format(v, 8, 1); +} + +static PyObject * +long_hex(PyObject *v) +{ + return long_format(v, 16, 1); +} + +static PyObject * +long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static PyObject * +long_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *x = NULL; + int base = -909; /* unlikely! */ + static char *kwlist[] = {"x", "base", 0}; + + if (type != &PyLong_Type) + return long_subtype_new(type, args, kwds); /* Wimp out */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:long", kwlist, + &x, &base)) + return NULL; + if (x == NULL) + return PyLong_FromLong(0L); + if (base == -909) + return PyNumber_Long(x); + else if (PyString_Check(x)) { + /* Since PyLong_FromString doesn't have a length parameter, + * check here for possible NULs in the string. */ + char *string = PyString_AS_STRING(x); + if (strlen(string) != PyString_Size(x)) { + /* create a repr() of the input string, + * just like PyLong_FromString does. */ + PyObject *srepr; + srepr = PyObject_Repr(x); + if (srepr == NULL) + return NULL; + PyErr_Format(PyExc_ValueError, + "invalid literal for long() with base %d: %s", + base, PyString_AS_STRING(srepr)); + Py_DECREF(srepr); + return NULL; + } + return PyLong_FromString(PyString_AS_STRING(x), NULL, base); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(x)) + return PyLong_FromUnicode(PyUnicode_AS_UNICODE(x), + PyUnicode_GET_SIZE(x), + base); +#endif + else { + PyErr_SetString(PyExc_TypeError, + "long() can't convert non-string with explicit base"); + return NULL; + } +} + +/* Wimpy, slow approach to tp_new calls for subtypes of long: + first create a regular long from whatever arguments we got, + then allocate a subtype instance and initialize it from + the regular long. The regular long is then thrown away. +*/ +static PyObject * +long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyLongObject *tmp, *newobj; + Py_ssize_t i, n; + + assert(PyType_IsSubtype(type, &PyLong_Type)); + tmp = (PyLongObject *)long_new(&PyLong_Type, args, kwds); + if (tmp == NULL) + return NULL; + assert(PyLong_CheckExact(tmp)); + n = tmp->ob_size; + if (n < 0) + n = -n; + newobj = (PyLongObject *)type->tp_alloc(type, n); + if (newobj == NULL) { + Py_DECREF(tmp); + return NULL; + } + assert(PyLong_Check(newobj)); + newobj->ob_size = tmp->ob_size; + for (i = 0; i < n; i++) + newobj->ob_digit[i] = tmp->ob_digit[i]; + Py_DECREF(tmp); + return (PyObject *)newobj; +} + +static PyObject * +long_getnewargs(PyLongObject *v) +{ + return Py_BuildValue("(N)", _PyLong_Copy(v)); +} + +static PyMethodDef long_methods[] = { + {"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +PyDoc_STRVAR(long_doc, +"long(x[, base]) -> integer\n\ +\n\ +Convert a string or number to a long integer, if possible. A floating\n\ +point argument will be truncated towards zero (this does not include a\n\ +string representation of a floating point number!) When converting a\n\ +string, use the optional base. It is an error to supply a base when\n\ +converting a non-string."); + +static PyNumberMethods long_as_number = { + (binaryfunc) long_add, /*nb_add*/ + (binaryfunc) long_sub, /*nb_subtract*/ + (binaryfunc) long_mul, /*nb_multiply*/ + long_classic_div, /*nb_divide*/ + long_mod, /*nb_remainder*/ + long_divmod, /*nb_divmod*/ + long_pow, /*nb_power*/ + (unaryfunc) long_neg, /*nb_negative*/ + (unaryfunc) long_pos, /*tp_positive*/ + (unaryfunc) long_abs, /*tp_absolute*/ + (inquiry) long_nonzero, /*tp_nonzero*/ + (unaryfunc) long_invert, /*nb_invert*/ + long_lshift, /*nb_lshift*/ + (binaryfunc) long_rshift, /*nb_rshift*/ + long_and, /*nb_and*/ + long_xor, /*nb_xor*/ + long_or, /*nb_or*/ + long_coerce, /*nb_coerce*/ + long_int, /*nb_int*/ + long_long, /*nb_long*/ + long_float, /*nb_float*/ + long_oct, /*nb_oct*/ + long_hex, /*nb_hex*/ + 0, /* nb_inplace_add */ + 0, /* nb_inplace_subtract */ + 0, /* nb_inplace_multiply */ + 0, /* nb_inplace_divide */ + 0, /* nb_inplace_remainder */ + 0, /* nb_inplace_power */ + 0, /* nb_inplace_lshift */ + 0, /* nb_inplace_rshift */ + 0, /* nb_inplace_and */ + 0, /* nb_inplace_xor */ + 0, /* nb_inplace_or */ + long_div, /* nb_floor_divide */ + long_true_divide, /* nb_true_divide */ + 0, /* nb_inplace_floor_divide */ + 0, /* nb_inplace_true_divide */ + long_long, /* nb_index */ +}; + +PyTypeObject PyLong_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "long", /* tp_name */ + sizeof(PyLongObject) - sizeof(digit), /* tp_basicsize */ + sizeof(digit), /* tp_itemsize */ + long_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)long_compare, /* tp_compare */ + long_repr, /* tp_repr */ + &long_as_number, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)long_hash, /* tp_hash */ + 0, /* tp_call */ + long_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + long_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + long_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + long_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; diff --git a/sys/src/cmd/python/Objects/methodobject.c b/sys/src/cmd/python/Objects/methodobject.c new file mode 100644 index 000000000..ecc9a0ab5 --- /dev/null +++ b/sys/src/cmd/python/Objects/methodobject.c @@ -0,0 +1,365 @@ + +/* Method object implementation */ + +#include "Python.h" +#include "structmember.h" + +static PyCFunctionObject *free_list = NULL; + +PyObject * +PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) +{ + PyCFunctionObject *op; + op = free_list; + if (op != NULL) { + free_list = (PyCFunctionObject *)(op->m_self); + PyObject_INIT(op, &PyCFunction_Type); + } + else { + op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); + if (op == NULL) + return NULL; + } + op->m_ml = ml; + Py_XINCREF(self); + op->m_self = self; + Py_XINCREF(module); + op->m_module = module; + _PyObject_GC_TRACK(op); + return (PyObject *)op; +} + +PyCFunction +PyCFunction_GetFunction(PyObject *op) +{ + if (!PyCFunction_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyCFunctionObject *)op) -> m_ml -> ml_meth; +} + +PyObject * +PyCFunction_GetSelf(PyObject *op) +{ + if (!PyCFunction_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return ((PyCFunctionObject *)op) -> m_self; +} + +int +PyCFunction_GetFlags(PyObject *op) +{ + if (!PyCFunction_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + return ((PyCFunctionObject *)op) -> m_ml -> ml_flags; +} + +PyObject * +PyCFunction_Call(PyObject *func, PyObject *arg, PyObject *kw) +{ + PyCFunctionObject* f = (PyCFunctionObject*)func; + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + Py_ssize_t size; + + switch (PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST)) { + case METH_VARARGS: + if (kw == NULL || PyDict_Size(kw) == 0) + return (*meth)(self, arg); + break; + case METH_VARARGS | METH_KEYWORDS: + case METH_OLDARGS | METH_KEYWORDS: + return (*(PyCFunctionWithKeywords)meth)(self, arg, kw); + case METH_NOARGS: + if (kw == NULL || PyDict_Size(kw) == 0) { + size = PyTuple_GET_SIZE(arg); + if (size == 0) + return (*meth)(self, NULL); + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + f->m_ml->ml_name, size); + return NULL; + } + break; + case METH_O: + if (kw == NULL || PyDict_Size(kw) == 0) { + size = PyTuple_GET_SIZE(arg); + if (size == 1) + return (*meth)(self, PyTuple_GET_ITEM(arg, 0)); + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + f->m_ml->ml_name, size); + return NULL; + } + break; + case METH_OLDARGS: + /* the really old style */ + if (kw == NULL || PyDict_Size(kw) == 0) { + size = PyTuple_GET_SIZE(arg); + if (size == 1) + arg = PyTuple_GET_ITEM(arg, 0); + else if (size == 0) + arg = NULL; + return (*meth)(self, arg); + } + break; + default: + PyErr_BadInternalCall(); + return NULL; + } + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + f->m_ml->ml_name); + return NULL; +} + +/* Methods (the standard built-in methods, that is) */ + +static void +meth_dealloc(PyCFunctionObject *m) +{ + _PyObject_GC_UNTRACK(m); + Py_XDECREF(m->m_self); + Py_XDECREF(m->m_module); + m->m_self = (PyObject *)free_list; + free_list = m; +} + +static PyObject * +meth_get__doc__(PyCFunctionObject *m, void *closure) +{ + const char *doc = m->m_ml->ml_doc; + + if (doc != NULL) + return PyString_FromString(doc); + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +meth_get__name__(PyCFunctionObject *m, void *closure) +{ + return PyString_FromString(m->m_ml->ml_name); +} + +static int +meth_traverse(PyCFunctionObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->m_self); + Py_VISIT(m->m_module); + return 0; +} + +static PyObject * +meth_get__self__(PyCFunctionObject *m, void *closure) +{ + PyObject *self; + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "method.__self__ not accessible in restricted mode"); + return NULL; + } + self = m->m_self; + if (self == NULL) + self = Py_None; + Py_INCREF(self); + return self; +} + +static PyGetSetDef meth_getsets [] = { + {"__doc__", (getter)meth_get__doc__, NULL, NULL}, + {"__name__", (getter)meth_get__name__, NULL, NULL}, + {"__self__", (getter)meth_get__self__, NULL, NULL}, + {0} +}; + +#define OFF(x) offsetof(PyCFunctionObject, x) + +static PyMemberDef meth_members[] = { + {"__module__", T_OBJECT, OFF(m_module), WRITE_RESTRICTED}, + {NULL} +}; + +static PyObject * +meth_repr(PyCFunctionObject *m) +{ + if (m->m_self == NULL) + return PyString_FromFormat("<built-in function %s>", + m->m_ml->ml_name); + return PyString_FromFormat("<built-in method %s of %s object at %p>", + m->m_ml->ml_name, + m->m_self->ob_type->tp_name, + m->m_self); +} + +static int +meth_compare(PyCFunctionObject *a, PyCFunctionObject *b) +{ + if (a->m_self != b->m_self) + return (a->m_self < b->m_self) ? -1 : 1; + if (a->m_ml->ml_meth == b->m_ml->ml_meth) + return 0; + if (strcmp(a->m_ml->ml_name, b->m_ml->ml_name) < 0) + return -1; + else + return 1; +} + +static long +meth_hash(PyCFunctionObject *a) +{ + long x,y; + if (a->m_self == NULL) + x = 0; + else { + x = PyObject_Hash(a->m_self); + if (x == -1) + return -1; + } + y = _Py_HashPointer((void*)(a->m_ml->ml_meth)); + if (y == -1) + return -1; + x ^= y; + if (x == -1) + x = -2; + return x; +} + + +PyTypeObject PyCFunction_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "builtin_function_or_method", + sizeof(PyCFunctionObject), + 0, + (destructor)meth_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)meth_compare, /* tp_compare */ + (reprfunc)meth_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)meth_hash, /* tp_hash */ + PyCFunction_Call, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)meth_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + meth_members, /* tp_members */ + meth_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ +}; + +/* List all methods in a chain -- helper for findmethodinchain */ + +static PyObject * +listmethodchain(PyMethodChain *chain) +{ + PyMethodChain *c; + PyMethodDef *ml; + int i, n; + PyObject *v; + + n = 0; + for (c = chain; c != NULL; c = c->link) { + for (ml = c->methods; ml->ml_name != NULL; ml++) + n++; + } + v = PyList_New(n); + if (v == NULL) + return NULL; + i = 0; + for (c = chain; c != NULL; c = c->link) { + for (ml = c->methods; ml->ml_name != NULL; ml++) { + PyList_SetItem(v, i, PyString_FromString(ml->ml_name)); + i++; + } + } + if (PyErr_Occurred()) { + Py_DECREF(v); + return NULL; + } + PyList_Sort(v); + return v; +} + +/* Find a method in a method chain */ + +PyObject * +Py_FindMethodInChain(PyMethodChain *chain, PyObject *self, const char *name) +{ + if (name[0] == '_' && name[1] == '_') { + if (strcmp(name, "__methods__") == 0) + return listmethodchain(chain); + if (strcmp(name, "__doc__") == 0) { + const char *doc = self->ob_type->tp_doc; + if (doc != NULL) + return PyString_FromString(doc); + } + } + while (chain != NULL) { + PyMethodDef *ml = chain->methods; + for (; ml->ml_name != NULL; ml++) { + if (name[0] == ml->ml_name[0] && + strcmp(name+1, ml->ml_name+1) == 0) + /* XXX */ + return PyCFunction_New(ml, self); + } + chain = chain->link; + } + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +/* Find a method in a single method list */ + +PyObject * +Py_FindMethod(PyMethodDef *methods, PyObject *self, const char *name) +{ + PyMethodChain chain; + chain.methods = methods; + chain.link = NULL; + return Py_FindMethodInChain(&chain, self, name); +} + +/* Clear out the free list */ + +void +PyCFunction_Fini(void) +{ + while (free_list) { + PyCFunctionObject *v = free_list; + free_list = (PyCFunctionObject *)(v->m_self); + PyObject_GC_Del(v); + } +} + +/* PyCFunction_New() is now just a macro that calls PyCFunction_NewEx(), + but it's part of the API so we need to keep a function around that + existing C extensions can call. +*/ + +#undef PyCFunction_New +PyAPI_FUNC(PyObject *) PyCFunction_New(PyMethodDef *, PyObject *); + +PyObject * +PyCFunction_New(PyMethodDef *ml, PyObject *self) +{ + return PyCFunction_NewEx(ml, self, NULL); +} diff --git a/sys/src/cmd/python/Objects/mkfile b/sys/src/cmd/python/Objects/mkfile new file mode 100644 index 000000000..ff29a0ec8 --- /dev/null +++ b/sys/src/cmd/python/Objects/mkfile @@ -0,0 +1,46 @@ +APE=/sys/src/ape +<$APE/config + +LIB=/$objtype/lib/ape/libpython.a + +OFILES=\ + abstract.$O\ + boolobject.$O\ + bufferobject.$O\ + cellobject.$O\ + classobject.$O\ + cobject.$O\ + codeobject.$O\ + complexobject.$O\ + descrobject.$O\ + dictobject.$O\ + enumobject.$O\ + exceptions.$O\ + fileobject.$O\ + floatobject.$O\ + frameobject.$O\ + funcobject.$O\ + genobject.$O\ + intobject.$O\ + iterobject.$O\ + listobject.$O\ + longobject.$O\ + methodobject.$O\ + moduleobject.$O\ + object.$O\ + obmalloc.$O\ + rangeobject.$O\ + setobject.$O\ + sliceobject.$O\ + stringobject.$O\ + structseq.$O\ + tupleobject.$O\ + typeobject.$O\ + unicodectype.$O\ + unicodeobject.$O\ + weakrefobject.$O\ + +</sys/src/cmd/mklib + +CFLAGS=-c -I.. -I../Include -DT$objtype -DPy_BUILD_CORE -DNDEBUG + diff --git a/sys/src/cmd/python/Objects/moduleobject.c b/sys/src/cmd/python/Objects/moduleobject.c new file mode 100644 index 000000000..e454fcf32 --- /dev/null +++ b/sys/src/cmd/python/Objects/moduleobject.c @@ -0,0 +1,259 @@ + +/* Module object implementation */ + +#include "Python.h" +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *md_dict; +} PyModuleObject; + +static PyMemberDef module_members[] = { + {"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY}, + {0} +}; + +PyObject * +PyModule_New(const char *name) +{ + PyModuleObject *m; + PyObject *nameobj; + m = PyObject_GC_New(PyModuleObject, &PyModule_Type); + if (m == NULL) + return NULL; + nameobj = PyString_FromString(name); + m->md_dict = PyDict_New(); + if (m->md_dict == NULL || nameobj == NULL) + goto fail; + if (PyDict_SetItemString(m->md_dict, "__name__", nameobj) != 0) + goto fail; + if (PyDict_SetItemString(m->md_dict, "__doc__", Py_None) != 0) + goto fail; + Py_DECREF(nameobj); + PyObject_GC_Track(m); + return (PyObject *)m; + + fail: + Py_XDECREF(nameobj); + Py_DECREF(m); + return NULL; +} + +PyObject * +PyModule_GetDict(PyObject *m) +{ + PyObject *d; + if (!PyModule_Check(m)) { + PyErr_BadInternalCall(); + return NULL; + } + d = ((PyModuleObject *)m) -> md_dict; + if (d == NULL) + ((PyModuleObject *)m) -> md_dict = d = PyDict_New(); + return d; +} + +char * +PyModule_GetName(PyObject *m) +{ + PyObject *d; + PyObject *nameobj; + if (!PyModule_Check(m)) { + PyErr_BadArgument(); + return NULL; + } + d = ((PyModuleObject *)m)->md_dict; + if (d == NULL || + (nameobj = PyDict_GetItemString(d, "__name__")) == NULL || + !PyString_Check(nameobj)) + { + PyErr_SetString(PyExc_SystemError, "nameless module"); + return NULL; + } + return PyString_AsString(nameobj); +} + +char * +PyModule_GetFilename(PyObject *m) +{ + PyObject *d; + PyObject *fileobj; + if (!PyModule_Check(m)) { + PyErr_BadArgument(); + return NULL; + } + d = ((PyModuleObject *)m)->md_dict; + if (d == NULL || + (fileobj = PyDict_GetItemString(d, "__file__")) == NULL || + !PyString_Check(fileobj)) + { + PyErr_SetString(PyExc_SystemError, "module filename missing"); + return NULL; + } + return PyString_AsString(fileobj); +} + +void +_PyModule_Clear(PyObject *m) +{ + /* To make the execution order of destructors for global + objects a bit more predictable, we first zap all objects + whose name starts with a single underscore, before we clear + the entire dictionary. We zap them by replacing them with + None, rather than deleting them from the dictionary, to + avoid rehashing the dictionary (to some extent). */ + + Py_ssize_t pos; + PyObject *key, *value; + PyObject *d; + + d = ((PyModuleObject *)m)->md_dict; + if (d == NULL) + return; + + /* First, clear only names starting with a single underscore */ + pos = 0; + while (PyDict_Next(d, &pos, &key, &value)) { + if (value != Py_None && PyString_Check(key)) { + char *s = PyString_AsString(key); + if (s[0] == '_' && s[1] != '_') { + if (Py_VerboseFlag > 1) + PySys_WriteStderr("# clear[1] %s\n", s); + PyDict_SetItem(d, key, Py_None); + } + } + } + + /* Next, clear all names except for __builtins__ */ + pos = 0; + while (PyDict_Next(d, &pos, &key, &value)) { + if (value != Py_None && PyString_Check(key)) { + char *s = PyString_AsString(key); + if (s[0] != '_' || strcmp(s, "__builtins__") != 0) { + if (Py_VerboseFlag > 1) + PySys_WriteStderr("# clear[2] %s\n", s); + PyDict_SetItem(d, key, Py_None); + } + } + } + + /* Note: we leave __builtins__ in place, so that destructors + of non-global objects defined in this module can still use + builtins, in particularly 'None'. */ + +} + +/* Methods */ + +static int +module_init(PyModuleObject *m, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"name", "doc", NULL}; + PyObject *dict, *name = Py_None, *doc = Py_None; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|O:module.__init__", + kwlist, &name, &doc)) + return -1; + dict = m->md_dict; + if (dict == NULL) { + dict = PyDict_New(); + if (dict == NULL) + return -1; + m->md_dict = dict; + } + if (PyDict_SetItemString(dict, "__name__", name) < 0) + return -1; + if (PyDict_SetItemString(dict, "__doc__", doc) < 0) + return -1; + return 0; +} + +static void +module_dealloc(PyModuleObject *m) +{ + PyObject_GC_UnTrack(m); + if (m->md_dict != NULL) { + _PyModule_Clear((PyObject *)m); + Py_DECREF(m->md_dict); + } + m->ob_type->tp_free((PyObject *)m); +} + +static PyObject * +module_repr(PyModuleObject *m) +{ + char *name; + char *filename; + + name = PyModule_GetName((PyObject *)m); + if (name == NULL) { + PyErr_Clear(); + name = "?"; + } + filename = PyModule_GetFilename((PyObject *)m); + if (filename == NULL) { + PyErr_Clear(); + return PyString_FromFormat("<module '%s' (built-in)>", name); + } + return PyString_FromFormat("<module '%s' from '%s'>", name, filename); +} + +/* We only need a traverse function, no clear function: If the module + is in a cycle, md_dict will be cleared as well, which will break + the cycle. */ +static int +module_traverse(PyModuleObject *m, visitproc visit, void *arg) +{ + Py_VISIT(m->md_dict); + return 0; +} + +PyDoc_STRVAR(module_doc, +"module(name[, doc])\n\ +\n\ +Create a module object.\n\ +The name must be a string; the optional doc argument can have any type."); + +PyTypeObject PyModule_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "module", /* tp_name */ + sizeof(PyModuleObject), /* tp_size */ + 0, /* tp_itemsize */ + (destructor)module_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)module_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + module_doc, /* tp_doc */ + (traverseproc)module_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + module_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(PyModuleObject, md_dict), /* tp_dictoffset */ + (initproc)module_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; diff --git a/sys/src/cmd/python/Objects/object.c b/sys/src/cmd/python/Objects/object.c new file mode 100644 index 000000000..b0672f30e --- /dev/null +++ b/sys/src/cmd/python/Objects/object.c @@ -0,0 +1,2139 @@ + +/* Generic object operations; and implementation of None (NoObject) */ + +#include "Python.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef Py_REF_DEBUG +Py_ssize_t _Py_RefTotal; + +Py_ssize_t +_Py_GetRefTotal(void) +{ + PyObject *o; + Py_ssize_t total = _Py_RefTotal; + /* ignore the references to the dummy object of the dicts and sets + because they are not reliable and not useful (now that the + hash table code is well-tested) */ + o = _PyDict_Dummy(); + if (o != NULL) + total -= o->ob_refcnt; + o = _PySet_Dummy(); + if (o != NULL) + total -= o->ob_refcnt; + return total; +} +#endif /* Py_REF_DEBUG */ + +int Py_DivisionWarningFlag; + +/* Object allocation routines used by NEWOBJ and NEWVAROBJ macros. + These are used by the individual routines for object creation. + Do not call them otherwise, they do not initialize the object! */ + +#ifdef Py_TRACE_REFS +/* Head of circular doubly-linked list of all objects. These are linked + * together via the _ob_prev and _ob_next members of a PyObject, which + * exist only in a Py_TRACE_REFS build. + */ +static PyObject refchain = {&refchain, &refchain}; + +/* Insert op at the front of the list of all objects. If force is true, + * op is added even if _ob_prev and _ob_next are non-NULL already. If + * force is false amd _ob_prev or _ob_next are non-NULL, do nothing. + * force should be true if and only if op points to freshly allocated, + * uninitialized memory, or you've unlinked op from the list and are + * relinking it into the front. + * Note that objects are normally added to the list via _Py_NewReference, + * which is called by PyObject_Init. Not all objects are initialized that + * way, though; exceptions include statically allocated type objects, and + * statically allocated singletons (like Py_True and Py_None). + */ +void +_Py_AddToAllObjects(PyObject *op, int force) +{ +#ifdef Py_DEBUG + if (!force) { + /* If it's initialized memory, op must be in or out of + * the list unambiguously. + */ + assert((op->_ob_prev == NULL) == (op->_ob_next == NULL)); + } +#endif + if (force || op->_ob_prev == NULL) { + op->_ob_next = refchain._ob_next; + op->_ob_prev = &refchain; + refchain._ob_next->_ob_prev = op; + refchain._ob_next = op; + } +} +#endif /* Py_TRACE_REFS */ + +#ifdef COUNT_ALLOCS +static PyTypeObject *type_list; +/* All types are added to type_list, at least when + they get one object created. That makes them + immortal, which unfortunately contributes to + garbage itself. If unlist_types_without_objects + is set, they will be removed from the type_list + once the last object is deallocated. */ +int unlist_types_without_objects; +extern int tuple_zero_allocs, fast_tuple_allocs; +extern int quick_int_allocs, quick_neg_int_allocs; +extern int null_strings, one_strings; +void +dump_counts(FILE* f) +{ + PyTypeObject *tp; + + for (tp = type_list; tp; tp = tp->tp_next) + fprintf(f, "%s alloc'd: %d, freed: %d, max in use: %d\n", + tp->tp_name, tp->tp_allocs, tp->tp_frees, + tp->tp_maxalloc); + fprintf(f, "fast tuple allocs: %d, empty: %d\n", + fast_tuple_allocs, tuple_zero_allocs); + fprintf(f, "fast int allocs: pos: %d, neg: %d\n", + quick_int_allocs, quick_neg_int_allocs); + fprintf(f, "null strings: %d, 1-strings: %d\n", + null_strings, one_strings); +} + +PyObject * +get_counts(void) +{ + PyTypeObject *tp; + PyObject *result; + PyObject *v; + + result = PyList_New(0); + if (result == NULL) + return NULL; + for (tp = type_list; tp; tp = tp->tp_next) { + v = Py_BuildValue("(snnn)", tp->tp_name, tp->tp_allocs, + tp->tp_frees, tp->tp_maxalloc); + if (v == NULL) { + Py_DECREF(result); + return NULL; + } + if (PyList_Append(result, v) < 0) { + Py_DECREF(v); + Py_DECREF(result); + return NULL; + } + Py_DECREF(v); + } + return result; +} + +void +inc_count(PyTypeObject *tp) +{ + if (tp->tp_next == NULL && tp->tp_prev == NULL) { + /* first time; insert in linked list */ + if (tp->tp_next != NULL) /* sanity check */ + Py_FatalError("XXX inc_count sanity check"); + if (type_list) + type_list->tp_prev = tp; + tp->tp_next = type_list; + /* Note that as of Python 2.2, heap-allocated type objects + * can go away, but this code requires that they stay alive + * until program exit. That's why we're careful with + * refcounts here. type_list gets a new reference to tp, + * while ownership of the reference type_list used to hold + * (if any) was transferred to tp->tp_next in the line above. + * tp is thus effectively immortal after this. + */ + Py_INCREF(tp); + type_list = tp; +#ifdef Py_TRACE_REFS + /* Also insert in the doubly-linked list of all objects, + * if not already there. + */ + _Py_AddToAllObjects((PyObject *)tp, 0); +#endif + } + tp->tp_allocs++; + if (tp->tp_allocs - tp->tp_frees > tp->tp_maxalloc) + tp->tp_maxalloc = tp->tp_allocs - tp->tp_frees; +} + +void dec_count(PyTypeObject *tp) +{ + tp->tp_frees++; + if (unlist_types_without_objects && + tp->tp_allocs == tp->tp_frees) { + /* unlink the type from type_list */ + if (tp->tp_prev) + tp->tp_prev->tp_next = tp->tp_next; + else + type_list = tp->tp_next; + if (tp->tp_next) + tp->tp_next->tp_prev = tp->tp_prev; + tp->tp_next = tp->tp_prev = NULL; + Py_DECREF(tp); + } +} + +#endif + +#ifdef Py_REF_DEBUG +/* Log a fatal error; doesn't return. */ +void +_Py_NegativeRefcount(const char *fname, int lineno, PyObject *op) +{ + char buf[300]; + + PyOS_snprintf(buf, sizeof(buf), + "%s:%i object at %p has negative ref count " + "%" PY_FORMAT_SIZE_T "d", + fname, lineno, op, op->ob_refcnt); + Py_FatalError(buf); +} + +#endif /* Py_REF_DEBUG */ + +void +Py_IncRef(PyObject *o) +{ + Py_XINCREF(o); +} + +void +Py_DecRef(PyObject *o) +{ + Py_XDECREF(o); +} + +PyObject * +PyObject_Init(PyObject *op, PyTypeObject *tp) +{ + if (op == NULL) + return PyErr_NoMemory(); + /* Any changes should be reflected in PyObject_INIT (objimpl.h) */ + op->ob_type = tp; + _Py_NewReference(op); + return op; +} + +PyVarObject * +PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) +{ + if (op == NULL) + return (PyVarObject *) PyErr_NoMemory(); + /* Any changes should be reflected in PyObject_INIT_VAR */ + op->ob_size = size; + op->ob_type = tp; + _Py_NewReference((PyObject *)op); + return op; +} + +PyObject * +_PyObject_New(PyTypeObject *tp) +{ + PyObject *op; + op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); + if (op == NULL) + return PyErr_NoMemory(); + return PyObject_INIT(op, tp); +} + +PyVarObject * +_PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) +{ + PyVarObject *op; + const size_t size = _PyObject_VAR_SIZE(tp, nitems); + op = (PyVarObject *) PyObject_MALLOC(size); + if (op == NULL) + return (PyVarObject *)PyErr_NoMemory(); + return PyObject_INIT_VAR(op, tp, nitems); +} + +/* for binary compatibility with 2.2 */ +#undef _PyObject_Del +void +_PyObject_Del(PyObject *op) +{ + PyObject_FREE(op); +} + +/* Implementation of PyObject_Print with recursion checking */ +static int +internal_print(PyObject *op, FILE *fp, int flags, int nesting) +{ + int ret = 0; + if (nesting > 10) { + PyErr_SetString(PyExc_RuntimeError, "print recursion"); + return -1; + } + if (PyErr_CheckSignals()) + return -1; +#ifdef USE_STACKCHECK + if (PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "stack overflow"); + return -1; + } +#endif + clearerr(fp); /* Clear any previous error condition */ + if (op == NULL) { + fprintf(fp, "<nil>"); + } + else { + if (op->ob_refcnt <= 0) + /* XXX(twouters) cast refcount to long until %zd is + universally available */ + fprintf(fp, "<refcnt %ld at %p>", + (long)op->ob_refcnt, op); + else if (op->ob_type->tp_print == NULL) { + PyObject *s; + if (flags & Py_PRINT_RAW) + s = PyObject_Str(op); + else + s = PyObject_Repr(op); + if (s == NULL) + ret = -1; + else { + ret = internal_print(s, fp, Py_PRINT_RAW, + nesting+1); + } + Py_XDECREF(s); + } + else + ret = (*op->ob_type->tp_print)(op, fp, flags); + } + if (ret == 0) { + if (ferror(fp)) { + PyErr_SetFromErrno(PyExc_IOError); + clearerr(fp); + ret = -1; + } + } + return ret; +} + +int +PyObject_Print(PyObject *op, FILE *fp, int flags) +{ + return internal_print(op, fp, flags, 0); +} + + +/* For debugging convenience. See Misc/gdbinit for some useful gdb hooks */ +void _PyObject_Dump(PyObject* op) +{ + if (op == NULL) + fprintf(stderr, "NULL\n"); + else { + fprintf(stderr, "object : "); + (void)PyObject_Print(op, stderr, 0); + /* XXX(twouters) cast refcount to long until %zd is + universally available */ + fprintf(stderr, "\n" + "type : %s\n" + "refcount: %ld\n" + "address : %p\n", + op->ob_type==NULL ? "NULL" : op->ob_type->tp_name, + (long)op->ob_refcnt, + op); + } +} + +PyObject * +PyObject_Repr(PyObject *v) +{ + if (PyErr_CheckSignals()) + return NULL; +#ifdef USE_STACKCHECK + if (PyOS_CheckStack()) { + PyErr_SetString(PyExc_MemoryError, "stack overflow"); + return NULL; + } +#endif + if (v == NULL) + return PyString_FromString("<NULL>"); + else if (v->ob_type->tp_repr == NULL) + return PyString_FromFormat("<%s object at %p>", + v->ob_type->tp_name, v); + else { + PyObject *res; + res = (*v->ob_type->tp_repr)(v); + if (res == NULL) + return NULL; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(res)) { + PyObject* str; + str = PyUnicode_AsEncodedString(res, NULL, NULL); + Py_DECREF(res); + if (str) + res = str; + else + return NULL; + } +#endif + if (!PyString_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__repr__ returned non-string (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; + } +} + +PyObject * +_PyObject_Str(PyObject *v) +{ + PyObject *res; + int type_ok; + if (v == NULL) + return PyString_FromString("<NULL>"); + if (PyString_CheckExact(v)) { + Py_INCREF(v); + return v; + } +#ifdef Py_USING_UNICODE + if (PyUnicode_CheckExact(v)) { + Py_INCREF(v); + return v; + } +#endif + if (v->ob_type->tp_str == NULL) + return PyObject_Repr(v); + + res = (*v->ob_type->tp_str)(v); + if (res == NULL) + return NULL; + type_ok = PyString_Check(res); +#ifdef Py_USING_UNICODE + type_ok = type_ok || PyUnicode_Check(res); +#endif + if (!type_ok) { + PyErr_Format(PyExc_TypeError, + "__str__ returned non-string (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; +} + +PyObject * +PyObject_Str(PyObject *v) +{ + PyObject *res = _PyObject_Str(v); + if (res == NULL) + return NULL; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(res)) { + PyObject* str; + str = PyUnicode_AsEncodedString(res, NULL, NULL); + Py_DECREF(res); + if (str) + res = str; + else + return NULL; + } +#endif + assert(PyString_Check(res)); + return res; +} + +#ifdef Py_USING_UNICODE +PyObject * +PyObject_Unicode(PyObject *v) +{ + PyObject *res; + PyObject *func; + PyObject *str; + static PyObject *unicodestr; + + if (v == NULL) { + res = PyString_FromString("<NULL>"); + if (res == NULL) + return NULL; + str = PyUnicode_FromEncodedObject(res, NULL, "strict"); + Py_DECREF(res); + return str; + } else if (PyUnicode_CheckExact(v)) { + Py_INCREF(v); + return v; + } + /* XXX As soon as we have a tp_unicode slot, we should + check this before trying the __unicode__ + method. */ + if (unicodestr == NULL) { + unicodestr= PyString_InternFromString("__unicode__"); + if (unicodestr == NULL) + return NULL; + } + func = PyObject_GetAttr(v, unicodestr); + if (func != NULL) { + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + } + else { + PyErr_Clear(); + if (PyUnicode_Check(v)) { + /* For a Unicode subtype that's didn't overwrite __unicode__, + return a true Unicode object with the same data. */ + return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(v), + PyUnicode_GET_SIZE(v)); + } + if (PyString_CheckExact(v)) { + Py_INCREF(v); + res = v; + } + else { + if (v->ob_type->tp_str != NULL) + res = (*v->ob_type->tp_str)(v); + else + res = PyObject_Repr(v); + } + } + if (res == NULL) + return NULL; + if (!PyUnicode_Check(res)) { + str = PyUnicode_FromEncodedObject(res, NULL, "strict"); + Py_DECREF(res); + res = str; + } + return res; +} +#endif + + +/* Helper to warn about deprecated tp_compare return values. Return: + -2 for an exception; + -1 if v < w; + 0 if v == w; + 1 if v > w. + (This function cannot return 2.) +*/ +static int +adjust_tp_compare(int c) +{ + if (PyErr_Occurred()) { + if (c != -1 && c != -2) { + PyObject *t, *v, *tb; + PyErr_Fetch(&t, &v, &tb); + if (PyErr_Warn(PyExc_RuntimeWarning, + "tp_compare didn't return -1 or -2 " + "for exception") < 0) { + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); + } + else + PyErr_Restore(t, v, tb); + } + return -2; + } + else if (c < -1 || c > 1) { + if (PyErr_Warn(PyExc_RuntimeWarning, + "tp_compare didn't return -1, 0 or 1") < 0) + return -2; + else + return c < -1 ? -1 : 1; + } + else { + assert(c >= -1 && c <= 1); + return c; + } +} + + +/* Macro to get the tp_richcompare field of a type if defined */ +#define RICHCOMPARE(t) (PyType_HasFeature((t), Py_TPFLAGS_HAVE_RICHCOMPARE) \ + ? (t)->tp_richcompare : NULL) + +/* Map rich comparison operators to their swapped version, e.g. LT --> GT */ +int _Py_SwappedOp[] = {Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE}; + +/* Try a genuine rich comparison, returning an object. Return: + NULL for exception; + NotImplemented if this particular rich comparison is not implemented or + undefined; + some object not equal to NotImplemented if it is implemented + (this latter object may not be a Boolean). +*/ +static PyObject * +try_rich_compare(PyObject *v, PyObject *w, int op) +{ + richcmpfunc f; + PyObject *res; + + if (v->ob_type != w->ob_type && + PyType_IsSubtype(w->ob_type, v->ob_type) && + (f = RICHCOMPARE(w->ob_type)) != NULL) { + res = (*f)(w, v, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + if ((f = RICHCOMPARE(v->ob_type)) != NULL) { + res = (*f)(v, w, op); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + if ((f = RICHCOMPARE(w->ob_type)) != NULL) { + return (*f)(w, v, _Py_SwappedOp[op]); + } + res = Py_NotImplemented; + Py_INCREF(res); + return res; +} + +/* Try a genuine rich comparison, returning an int. Return: + -1 for exception (including the case where try_rich_compare() returns an + object that's not a Boolean); + 0 if the outcome is false; + 1 if the outcome is true; + 2 if this particular rich comparison is not implemented or undefined. +*/ +static int +try_rich_compare_bool(PyObject *v, PyObject *w, int op) +{ + PyObject *res; + int ok; + + if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) + return 2; /* Shortcut, avoid INCREF+DECREF */ + res = try_rich_compare(v, w, op); + if (res == NULL) + return -1; + if (res == Py_NotImplemented) { + Py_DECREF(res); + return 2; + } + ok = PyObject_IsTrue(res); + Py_DECREF(res); + return ok; +} + +/* Try rich comparisons to determine a 3-way comparison. Return: + -2 for an exception; + -1 if v < w; + 0 if v == w; + 1 if v > w; + 2 if this particular rich comparison is not implemented or undefined. +*/ +static int +try_rich_to_3way_compare(PyObject *v, PyObject *w) +{ + static struct { int op; int outcome; } tries[3] = { + /* Try this operator, and if it is true, use this outcome: */ + {Py_EQ, 0}, + {Py_LT, -1}, + {Py_GT, 1}, + }; + int i; + + if (RICHCOMPARE(v->ob_type) == NULL && RICHCOMPARE(w->ob_type) == NULL) + return 2; /* Shortcut */ + + for (i = 0; i < 3; i++) { + switch (try_rich_compare_bool(v, w, tries[i].op)) { + case -1: + return -2; + case 1: + return tries[i].outcome; + } + } + + return 2; +} + +/* Try a 3-way comparison, returning an int. Return: + -2 for an exception; + -1 if v < w; + 0 if v == w; + 1 if v > w; + 2 if this particular 3-way comparison is not implemented or undefined. +*/ +static int +try_3way_compare(PyObject *v, PyObject *w) +{ + int c; + cmpfunc f; + + /* Comparisons involving instances are given to instance_compare, + which has the same return conventions as this function. */ + + f = v->ob_type->tp_compare; + if (PyInstance_Check(v)) + return (*f)(v, w); + if (PyInstance_Check(w)) + return (*w->ob_type->tp_compare)(v, w); + + /* If both have the same (non-NULL) tp_compare, use it. */ + if (f != NULL && f == w->ob_type->tp_compare) { + c = (*f)(v, w); + return adjust_tp_compare(c); + } + + /* If either tp_compare is _PyObject_SlotCompare, that's safe. */ + if (f == _PyObject_SlotCompare || + w->ob_type->tp_compare == _PyObject_SlotCompare) + return _PyObject_SlotCompare(v, w); + + /* If we're here, v and w, + a) are not instances; + b) have different types or a type without tp_compare; and + c) don't have a user-defined tp_compare. + tp_compare implementations in C assume that both arguments + have their type, so we give up if the coercion fails or if + it yields types which are still incompatible (which can + happen with a user-defined nb_coerce). + */ + c = PyNumber_CoerceEx(&v, &w); + if (c < 0) + return -2; + if (c > 0) + return 2; + f = v->ob_type->tp_compare; + if (f != NULL && f == w->ob_type->tp_compare) { + c = (*f)(v, w); + Py_DECREF(v); + Py_DECREF(w); + return adjust_tp_compare(c); + } + + /* No comparison defined */ + Py_DECREF(v); + Py_DECREF(w); + return 2; +} + +/* Final fallback 3-way comparison, returning an int. Return: + -2 if an error occurred; + -1 if v < w; + 0 if v == w; + 1 if v > w. +*/ +static int +default_3way_compare(PyObject *v, PyObject *w) +{ + int c; + const char *vname, *wname; + + if (v->ob_type == w->ob_type) { + /* When comparing these pointers, they must be cast to + * integer types (i.e. Py_uintptr_t, our spelling of C9X's + * uintptr_t). ANSI specifies that pointer compares other + * than == and != to non-related structures are undefined. + */ + Py_uintptr_t vv = (Py_uintptr_t)v; + Py_uintptr_t ww = (Py_uintptr_t)w; + return (vv < ww) ? -1 : (vv > ww) ? 1 : 0; + } + + /* None is smaller than anything */ + if (v == Py_None) + return -1; + if (w == Py_None) + return 1; + + /* different type: compare type names; numbers are smaller */ + if (PyNumber_Check(v)) + vname = ""; + else + vname = v->ob_type->tp_name; + if (PyNumber_Check(w)) + wname = ""; + else + wname = w->ob_type->tp_name; + c = strcmp(vname, wname); + if (c < 0) + return -1; + if (c > 0) + return 1; + /* Same type name, or (more likely) incomparable numeric types */ + return ((Py_uintptr_t)(v->ob_type) < ( + Py_uintptr_t)(w->ob_type)) ? -1 : 1; +} + +/* Do a 3-way comparison, by hook or by crook. Return: + -2 for an exception (but see below); + -1 if v < w; + 0 if v == w; + 1 if v > w; + BUT: if the object implements a tp_compare function, it returns + whatever this function returns (whether with an exception or not). +*/ +static int +do_cmp(PyObject *v, PyObject *w) +{ + int c; + cmpfunc f; + + if (v->ob_type == w->ob_type + && (f = v->ob_type->tp_compare) != NULL) { + c = (*f)(v, w); + if (PyInstance_Check(v)) { + /* Instance tp_compare has a different signature. + But if it returns undefined we fall through. */ + if (c != 2) + return c; + /* Else fall through to try_rich_to_3way_compare() */ + } + else + return adjust_tp_compare(c); + } + /* We only get here if one of the following is true: + a) v and w have different types + b) v and w have the same type, which doesn't have tp_compare + c) v and w are instances, and either __cmp__ is not defined or + __cmp__ returns NotImplemented + */ + c = try_rich_to_3way_compare(v, w); + if (c < 2) + return c; + c = try_3way_compare(v, w); + if (c < 2) + return c; + return default_3way_compare(v, w); +} + +/* Compare v to w. Return + -1 if v < w or exception (PyErr_Occurred() true in latter case). + 0 if v == w. + 1 if v > w. + XXX The docs (C API manual) say the return value is undefined in case + XXX of error. +*/ +int +PyObject_Compare(PyObject *v, PyObject *w) +{ + int result; + + if (v == NULL || w == NULL) { + PyErr_BadInternalCall(); + return -1; + } + if (v == w) + return 0; + if (Py_EnterRecursiveCall(" in cmp")) + return -1; + result = do_cmp(v, w); + Py_LeaveRecursiveCall(); + return result < 0 ? -1 : result; +} + +/* Return (new reference to) Py_True or Py_False. */ +static PyObject * +convert_3way_to_object(int op, int c) +{ + PyObject *result; + switch (op) { + case Py_LT: c = c < 0; break; + case Py_LE: c = c <= 0; break; + case Py_EQ: c = c == 0; break; + case Py_NE: c = c != 0; break; + case Py_GT: c = c > 0; break; + case Py_GE: c = c >= 0; break; + } + result = c ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +/* We want a rich comparison but don't have one. Try a 3-way cmp instead. + Return + NULL if error + Py_True if v op w + Py_False if not (v op w) +*/ +static PyObject * +try_3way_to_rich_compare(PyObject *v, PyObject *w, int op) +{ + int c; + + c = try_3way_compare(v, w); + if (c >= 2) + c = default_3way_compare(v, w); + if (c <= -2) + return NULL; + return convert_3way_to_object(op, c); +} + +/* Do rich comparison on v and w. Return + NULL if error + Else a new reference to an object other than Py_NotImplemented, usually(?): + Py_True if v op w + Py_False if not (v op w) +*/ +static PyObject * +do_richcmp(PyObject *v, PyObject *w, int op) +{ + PyObject *res; + + res = try_rich_compare(v, w, op); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + + return try_3way_to_rich_compare(v, w, op); +} + +/* Return: + NULL for exception; + some object not equal to NotImplemented if it is implemented + (this latter object may not be a Boolean). +*/ +PyObject * +PyObject_RichCompare(PyObject *v, PyObject *w, int op) +{ + PyObject *res; + + assert(Py_LT <= op && op <= Py_GE); + if (Py_EnterRecursiveCall(" in cmp")) + return NULL; + + /* If the types are equal, and not old-style instances, try to + get out cheap (don't bother with coercions etc.). */ + if (v->ob_type == w->ob_type && !PyInstance_Check(v)) { + cmpfunc fcmp; + richcmpfunc frich = RICHCOMPARE(v->ob_type); + /* If the type has richcmp, try it first. try_rich_compare + tries it two-sided, which is not needed since we've a + single type only. */ + if (frich != NULL) { + res = (*frich)(v, w, op); + if (res != Py_NotImplemented) + goto Done; + Py_DECREF(res); + } + /* No richcmp, or this particular richmp not implemented. + Try 3-way cmp. */ + fcmp = v->ob_type->tp_compare; + if (fcmp != NULL) { + int c = (*fcmp)(v, w); + c = adjust_tp_compare(c); + if (c == -2) { + res = NULL; + goto Done; + } + res = convert_3way_to_object(op, c); + goto Done; + } + } + + /* Fast path not taken, or couldn't deliver a useful result. */ + res = do_richcmp(v, w, op); +Done: + Py_LeaveRecursiveCall(); + return res; +} + +/* Return -1 if error; 1 if v op w; 0 if not (v op w). */ +int +PyObject_RichCompareBool(PyObject *v, PyObject *w, int op) +{ + PyObject *res; + int ok; + + /* Quick result when objects are the same. + Guarantees that identity implies equality. */ + if (v == w) { + if (op == Py_EQ) + return 1; + else if (op == Py_NE) + return 0; + } + + res = PyObject_RichCompare(v, w, op); + if (res == NULL) + return -1; + if (PyBool_Check(res)) + ok = (res == Py_True); + else + ok = PyObject_IsTrue(res); + Py_DECREF(res); + return ok; +} + +/* Set of hash utility functions to help maintaining the invariant that + if a==b then hash(a)==hash(b) + + All the utility functions (_Py_Hash*()) return "-1" to signify an error. +*/ + +long +_Py_HashDouble(double v) +{ + double intpart, fractpart; + int expo; + long hipart; + long x; /* the final hash value */ + /* This is designed so that Python numbers of different types + * that compare equal hash to the same value; otherwise comparisons + * of mapping keys will turn out weird. + */ + + fractpart = modf(v, &intpart); + if (fractpart == 0.0) { + /* This must return the same hash as an equal int or long. */ + if (intpart > LONG_MAX || -intpart > LONG_MAX) { + /* Convert to long and use its hash. */ + PyObject *plong; /* converted to Python long */ + if (Py_IS_INFINITY(intpart)) + /* can't convert to long int -- arbitrary */ + v = v < 0 ? -271828.0 : 314159.0; + plong = PyLong_FromDouble(v); + if (plong == NULL) + return -1; + x = PyObject_Hash(plong); + Py_DECREF(plong); + return x; + } + /* Fits in a C long == a Python int, so is its own hash. */ + x = (long)intpart; + if (x == -1) + x = -2; + return x; + } + /* The fractional part is non-zero, so we don't have to worry about + * making this match the hash of some other type. + * Use frexp to get at the bits in the double. + * Since the VAX D double format has 56 mantissa bits, which is the + * most of any double format in use, each of these parts may have as + * many as (but no more than) 56 significant bits. + * So, assuming sizeof(long) >= 4, each part can be broken into two + * longs; frexp and multiplication are used to do that. + * Also, since the Cray double format has 15 exponent bits, which is + * the most of any double format in use, shifting the exponent field + * left by 15 won't overflow a long (again assuming sizeof(long) >= 4). + */ + v = frexp(v, &expo); + v *= 2147483648.0; /* 2**31 */ + hipart = (long)v; /* take the top 32 bits */ + v = (v - (double)hipart) * 2147483648.0; /* get the next 32 bits */ + x = hipart + (long)v + (expo << 15); + if (x == -1) + x = -2; + return x; +} + +long +_Py_HashPointer(void *p) +{ +#if SIZEOF_LONG >= SIZEOF_VOID_P + return (long)p; +#else + /* convert to a Python long and hash that */ + PyObject* longobj; + long x; + + if ((longobj = PyLong_FromVoidPtr(p)) == NULL) { + x = -1; + goto finally; + } + x = PyObject_Hash(longobj); + +finally: + Py_XDECREF(longobj); + return x; +#endif +} + + +long +PyObject_Hash(PyObject *v) +{ + PyTypeObject *tp = v->ob_type; + if (tp->tp_hash != NULL) + return (*tp->tp_hash)(v); + if (tp->tp_compare == NULL && RICHCOMPARE(tp) == NULL) { + return _Py_HashPointer(v); /* Use address as hash value */ + } + /* If there's a cmp but no hash defined, the object can't be hashed */ + PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", + v->ob_type->tp_name); + return -1; +} + +PyObject * +PyObject_GetAttrString(PyObject *v, const char *name) +{ + PyObject *w, *res; + + if (v->ob_type->tp_getattr != NULL) + return (*v->ob_type->tp_getattr)(v, (char*)name); + w = PyString_InternFromString(name); + if (w == NULL) + return NULL; + res = PyObject_GetAttr(v, w); + Py_XDECREF(w); + return res; +} + +int +PyObject_HasAttrString(PyObject *v, const char *name) +{ + PyObject *res = PyObject_GetAttrString(v, name); + if (res != NULL) { + Py_DECREF(res); + return 1; + } + PyErr_Clear(); + return 0; +} + +int +PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w) +{ + PyObject *s; + int res; + + if (v->ob_type->tp_setattr != NULL) + return (*v->ob_type->tp_setattr)(v, (char*)name, w); + s = PyString_InternFromString(name); + if (s == NULL) + return -1; + res = PyObject_SetAttr(v, s, w); + Py_XDECREF(s); + return res; +} + +PyObject * +PyObject_GetAttr(PyObject *v, PyObject *name) +{ + PyTypeObject *tp = v->ob_type; + + if (!PyString_Check(name)) { +#ifdef Py_USING_UNICODE + /* The Unicode to string conversion is done here because the + existing tp_getattro slots expect a string object as name + and we wouldn't want to break those. */ + if (PyUnicode_Check(name)) { + name = _PyUnicode_AsDefaultEncodedString(name, NULL); + if (name == NULL) + return NULL; + } + else +#endif + { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return NULL; + } + } + if (tp->tp_getattro != NULL) + return (*tp->tp_getattro)(v, name); + if (tp->tp_getattr != NULL) + return (*tp->tp_getattr)(v, PyString_AS_STRING(name)); + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(name)); + return NULL; +} + +int +PyObject_HasAttr(PyObject *v, PyObject *name) +{ + PyObject *res = PyObject_GetAttr(v, name); + if (res != NULL) { + Py_DECREF(res); + return 1; + } + PyErr_Clear(); + return 0; +} + +int +PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) +{ + PyTypeObject *tp = v->ob_type; + int err; + + if (!PyString_Check(name)){ +#ifdef Py_USING_UNICODE + /* The Unicode to string conversion is done here because the + existing tp_setattro slots expect a string object as name + and we wouldn't want to break those. */ + if (PyUnicode_Check(name)) { + name = PyUnicode_AsEncodedString(name, NULL, NULL); + if (name == NULL) + return -1; + } + else +#endif + { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return -1; + } + } + else + Py_INCREF(name); + + PyString_InternInPlace(&name); + if (tp->tp_setattro != NULL) { + err = (*tp->tp_setattro)(v, name, value); + Py_DECREF(name); + return err; + } + if (tp->tp_setattr != NULL) { + err = (*tp->tp_setattr)(v, PyString_AS_STRING(name), value); + Py_DECREF(name); + return err; + } + Py_DECREF(name); + if (tp->tp_getattr == NULL && tp->tp_getattro == NULL) + PyErr_Format(PyExc_TypeError, + "'%.100s' object has no attributes " + "(%s .%.100s)", + tp->tp_name, + value==NULL ? "del" : "assign to", + PyString_AS_STRING(name)); + else + PyErr_Format(PyExc_TypeError, + "'%.100s' object has only read-only attributes " + "(%s .%.100s)", + tp->tp_name, + value==NULL ? "del" : "assign to", + PyString_AS_STRING(name)); + return -1; +} + +/* Helper to get a pointer to an object's __dict__ slot, if any */ + +PyObject ** +_PyObject_GetDictPtr(PyObject *obj) +{ + Py_ssize_t dictoffset; + PyTypeObject *tp = obj->ob_type; + + if (!(tp->tp_flags & Py_TPFLAGS_HAVE_CLASS)) + return NULL; + dictoffset = tp->tp_dictoffset; + if (dictoffset == 0) + return NULL; + if (dictoffset < 0) { + Py_ssize_t tsize; + size_t size; + + tsize = ((PyVarObject *)obj)->ob_size; + if (tsize < 0) + tsize = -tsize; + size = _PyObject_VAR_SIZE(tp, tsize); + + dictoffset += (long)size; + assert(dictoffset > 0); + assert(dictoffset % SIZEOF_VOID_P == 0); + } + return (PyObject **) ((char *)obj + dictoffset); +} + +PyObject * +PyObject_SelfIter(PyObject *obj) +{ + Py_INCREF(obj); + return obj; +} + +/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */ + +PyObject * +PyObject_GenericGetAttr(PyObject *obj, PyObject *name) +{ + PyTypeObject *tp = obj->ob_type; + PyObject *descr = NULL; + PyObject *res = NULL; + descrgetfunc f; + Py_ssize_t dictoffset; + PyObject **dictptr; + + if (!PyString_Check(name)){ +#ifdef Py_USING_UNICODE + /* The Unicode to string conversion is done here because the + existing tp_setattro slots expect a string object as name + and we wouldn't want to break those. */ + if (PyUnicode_Check(name)) { + name = PyUnicode_AsEncodedString(name, NULL, NULL); + if (name == NULL) + return NULL; + } + else +#endif + { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return NULL; + } + } + else + Py_INCREF(name); + + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + goto done; + } + + /* Inline _PyType_Lookup */ + { + Py_ssize_t i, n; + PyObject *mro, *base, *dict; + + /* Look in tp_dict of types in MRO */ + mro = tp->tp_mro; + assert(mro != NULL); + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + base = PyTuple_GET_ITEM(mro, i); + if (PyClass_Check(base)) + dict = ((PyClassObject *)base)->cl_dict; + else { + assert(PyType_Check(base)); + dict = ((PyTypeObject *)base)->tp_dict; + } + assert(dict && PyDict_Check(dict)); + descr = PyDict_GetItem(dict, name); + if (descr != NULL) + break; + } + } + + Py_XINCREF(descr); + + f = NULL; + if (descr != NULL && + PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) { + f = descr->ob_type->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + res = f(descr, obj, (PyObject *)obj->ob_type); + Py_DECREF(descr); + goto done; + } + } + + /* Inline _PyObject_GetDictPtr */ + dictoffset = tp->tp_dictoffset; + if (dictoffset != 0) { + PyObject *dict; + if (dictoffset < 0) { + Py_ssize_t tsize; + size_t size; + + tsize = ((PyVarObject *)obj)->ob_size; + if (tsize < 0) + tsize = -tsize; + size = _PyObject_VAR_SIZE(tp, tsize); + + dictoffset += (long)size; + assert(dictoffset > 0); + assert(dictoffset % SIZEOF_VOID_P == 0); + } + dictptr = (PyObject **) ((char *)obj + dictoffset); + dict = *dictptr; + if (dict != NULL) { + res = PyDict_GetItem(dict, name); + if (res != NULL) { + Py_INCREF(res); + Py_XDECREF(descr); + goto done; + } + } + } + + if (f != NULL) { + res = f(descr, obj, (PyObject *)obj->ob_type); + Py_DECREF(descr); + goto done; + } + + if (descr != NULL) { + res = descr; + /* descr was already increfed above */ + goto done; + } + + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%.400s'", + tp->tp_name, PyString_AS_STRING(name)); + done: + Py_DECREF(name); + return res; +} + +int +PyObject_GenericSetAttr(PyObject *obj, PyObject *name, PyObject *value) +{ + PyTypeObject *tp = obj->ob_type; + PyObject *descr; + descrsetfunc f; + PyObject **dictptr; + int res = -1; + + if (!PyString_Check(name)){ +#ifdef Py_USING_UNICODE + /* The Unicode to string conversion is done here because the + existing tp_setattro slots expect a string object as name + and we wouldn't want to break those. */ + if (PyUnicode_Check(name)) { + name = PyUnicode_AsEncodedString(name, NULL, NULL); + if (name == NULL) + return -1; + } + else +#endif + { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return -1; + } + } + else + Py_INCREF(name); + + if (tp->tp_dict == NULL) { + if (PyType_Ready(tp) < 0) + goto done; + } + + descr = _PyType_Lookup(tp, name); + f = NULL; + if (descr != NULL && + PyType_HasFeature(descr->ob_type, Py_TPFLAGS_HAVE_CLASS)) { + f = descr->ob_type->tp_descr_set; + if (f != NULL && PyDescr_IsData(descr)) { + res = f(descr, obj, value); + goto done; + } + } + + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict == NULL && value != NULL) { + dict = PyDict_New(); + if (dict == NULL) + goto done; + *dictptr = dict; + } + if (dict != NULL) { + if (value == NULL) + res = PyDict_DelItem(dict, name); + else + res = PyDict_SetItem(dict, name, value); + if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError)) + PyErr_SetObject(PyExc_AttributeError, name); + goto done; + } + } + + if (f != NULL) { + res = f(descr, obj, value); + goto done; + } + + if (descr == NULL) { + PyErr_Format(PyExc_AttributeError, + "'%.100s' object has no attribute '%.200s'", + tp->tp_name, PyString_AS_STRING(name)); + goto done; + } + + PyErr_Format(PyExc_AttributeError, + "'%.50s' object attribute '%.400s' is read-only", + tp->tp_name, PyString_AS_STRING(name)); + done: + Py_DECREF(name); + return res; +} + +/* Test a value used as condition, e.g., in a for or if statement. + Return -1 if an error occurred */ + +int +PyObject_IsTrue(PyObject *v) +{ + Py_ssize_t res; + if (v == Py_True) + return 1; + if (v == Py_False) + return 0; + if (v == Py_None) + return 0; + else if (v->ob_type->tp_as_number != NULL && + v->ob_type->tp_as_number->nb_nonzero != NULL) + res = (*v->ob_type->tp_as_number->nb_nonzero)(v); + else if (v->ob_type->tp_as_mapping != NULL && + v->ob_type->tp_as_mapping->mp_length != NULL) + res = (*v->ob_type->tp_as_mapping->mp_length)(v); + else if (v->ob_type->tp_as_sequence != NULL && + v->ob_type->tp_as_sequence->sq_length != NULL) + res = (*v->ob_type->tp_as_sequence->sq_length)(v); + else + return 1; + /* if it is negative, it should be either -1 or -2 */ + return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int); +} + +/* equivalent of 'not v' + Return -1 if an error occurred */ + +int +PyObject_Not(PyObject *v) +{ + int res; + res = PyObject_IsTrue(v); + if (res < 0) + return res; + return res == 0; +} + +/* Coerce two numeric types to the "larger" one. + Increment the reference count on each argument. + Return value: + -1 if an error occurred; + 0 if the coercion succeeded (and then the reference counts are increased); + 1 if no coercion is possible (and no error is raised). +*/ +int +PyNumber_CoerceEx(PyObject **pv, PyObject **pw) +{ + register PyObject *v = *pv; + register PyObject *w = *pw; + int res; + + /* Shortcut only for old-style types */ + if (v->ob_type == w->ob_type && + !PyType_HasFeature(v->ob_type, Py_TPFLAGS_CHECKTYPES)) + { + Py_INCREF(v); + Py_INCREF(w); + return 0; + } + if (v->ob_type->tp_as_number && v->ob_type->tp_as_number->nb_coerce) { + res = (*v->ob_type->tp_as_number->nb_coerce)(pv, pw); + if (res <= 0) + return res; + } + if (w->ob_type->tp_as_number && w->ob_type->tp_as_number->nb_coerce) { + res = (*w->ob_type->tp_as_number->nb_coerce)(pw, pv); + if (res <= 0) + return res; + } + return 1; +} + +/* Coerce two numeric types to the "larger" one. + Increment the reference count on each argument. + Return -1 and raise an exception if no coercion is possible + (and then no reference count is incremented). +*/ +int +PyNumber_Coerce(PyObject **pv, PyObject **pw) +{ + int err = PyNumber_CoerceEx(pv, pw); + if (err <= 0) + return err; + PyErr_SetString(PyExc_TypeError, "number coercion failed"); + return -1; +} + + +/* Test whether an object can be called */ + +int +PyCallable_Check(PyObject *x) +{ + if (x == NULL) + return 0; + if (PyInstance_Check(x)) { + PyObject *call = PyObject_GetAttrString(x, "__call__"); + if (call == NULL) { + PyErr_Clear(); + return 0; + } + /* Could test recursively but don't, for fear of endless + recursion if some joker sets self.__call__ = self */ + Py_DECREF(call); + return 1; + } + else { + return x->ob_type->tp_call != NULL; + } +} + +/* Helper for PyObject_Dir. + Merge the __dict__ of aclass into dict, and recursively also all + the __dict__s of aclass's base classes. The order of merging isn't + defined, as it's expected that only the final set of dict keys is + interesting. + Return 0 on success, -1 on error. +*/ + +static int +merge_class_dict(PyObject* dict, PyObject* aclass) +{ + PyObject *classdict; + PyObject *bases; + + assert(PyDict_Check(dict)); + assert(aclass); + + /* Merge in the type's dict (if any). */ + classdict = PyObject_GetAttrString(aclass, "__dict__"); + if (classdict == NULL) + PyErr_Clear(); + else { + int status = PyDict_Update(dict, classdict); + Py_DECREF(classdict); + if (status < 0) + return -1; + } + + /* Recursively merge in the base types' (if any) dicts. */ + bases = PyObject_GetAttrString(aclass, "__bases__"); + if (bases == NULL) + PyErr_Clear(); + else { + /* We have no guarantee that bases is a real tuple */ + Py_ssize_t i, n; + n = PySequence_Size(bases); /* This better be right */ + if (n < 0) + PyErr_Clear(); + else { + for (i = 0; i < n; i++) { + int status; + PyObject *base = PySequence_GetItem(bases, i); + if (base == NULL) { + Py_DECREF(bases); + return -1; + } + status = merge_class_dict(dict, base); + Py_DECREF(base); + if (status < 0) { + Py_DECREF(bases); + return -1; + } + } + } + Py_DECREF(bases); + } + return 0; +} + +/* Helper for PyObject_Dir. + If obj has an attr named attrname that's a list, merge its string + elements into keys of dict. + Return 0 on success, -1 on error. Errors due to not finding the attr, + or the attr not being a list, are suppressed. +*/ + +static int +merge_list_attr(PyObject* dict, PyObject* obj, const char *attrname) +{ + PyObject *list; + int result = 0; + + assert(PyDict_Check(dict)); + assert(obj); + assert(attrname); + + list = PyObject_GetAttrString(obj, attrname); + if (list == NULL) + PyErr_Clear(); + + else if (PyList_Check(list)) { + int i; + for (i = 0; i < PyList_GET_SIZE(list); ++i) { + PyObject *item = PyList_GET_ITEM(list, i); + if (PyString_Check(item)) { + result = PyDict_SetItem(dict, item, Py_None); + if (result < 0) + break; + } + } + } + + Py_XDECREF(list); + return result; +} + +/* Like __builtin__.dir(arg). See bltinmodule.c's builtin_dir for the + docstring, which should be kept in synch with this implementation. */ + +PyObject * +PyObject_Dir(PyObject *arg) +{ + /* Set exactly one of these non-NULL before the end. */ + PyObject *result = NULL; /* result list */ + PyObject *masterdict = NULL; /* result is masterdict.keys() */ + + /* If NULL arg, return the locals. */ + if (arg == NULL) { + PyObject *locals = PyEval_GetLocals(); + if (locals == NULL) + goto error; + result = PyMapping_Keys(locals); + if (result == NULL) + goto error; + } + + /* Elif this is some form of module, we only want its dict. */ + else if (PyModule_Check(arg)) { + masterdict = PyObject_GetAttrString(arg, "__dict__"); + if (masterdict == NULL) + goto error; + if (!PyDict_Check(masterdict)) { + PyErr_SetString(PyExc_TypeError, + "module.__dict__ is not a dictionary"); + goto error; + } + } + + /* Elif some form of type or class, grab its dict and its bases. + We deliberately don't suck up its __class__, as methods belonging + to the metaclass would probably be more confusing than helpful. */ + else if (PyType_Check(arg) || PyClass_Check(arg)) { + masterdict = PyDict_New(); + if (masterdict == NULL) + goto error; + if (merge_class_dict(masterdict, arg) < 0) + goto error; + } + + /* Else look at its dict, and the attrs reachable from its class. */ + else { + PyObject *itsclass; + /* Create a dict to start with. CAUTION: Not everything + responding to __dict__ returns a dict! */ + masterdict = PyObject_GetAttrString(arg, "__dict__"); + if (masterdict == NULL) { + PyErr_Clear(); + masterdict = PyDict_New(); + } + else if (!PyDict_Check(masterdict)) { + Py_DECREF(masterdict); + masterdict = PyDict_New(); + } + else { + /* The object may have returned a reference to its + dict, so copy it to avoid mutating it. */ + PyObject *temp = PyDict_Copy(masterdict); + Py_DECREF(masterdict); + masterdict = temp; + } + if (masterdict == NULL) + goto error; + + /* Merge in __members__ and __methods__ (if any). + XXX Would like this to go away someday; for now, it's + XXX needed to get at im_self etc of method objects. */ + if (merge_list_attr(masterdict, arg, "__members__") < 0) + goto error; + if (merge_list_attr(masterdict, arg, "__methods__") < 0) + goto error; + + /* Merge in attrs reachable from its class. + CAUTION: Not all objects have a __class__ attr. */ + itsclass = PyObject_GetAttrString(arg, "__class__"); + if (itsclass == NULL) + PyErr_Clear(); + else { + int status = merge_class_dict(masterdict, itsclass); + Py_DECREF(itsclass); + if (status < 0) + goto error; + } + } + + assert((result == NULL) ^ (masterdict == NULL)); + if (masterdict != NULL) { + /* The result comes from its keys. */ + assert(result == NULL); + result = PyDict_Keys(masterdict); + if (result == NULL) + goto error; + } + + assert(result); + if (!PyList_Check(result)) { + PyErr_Format(PyExc_TypeError, + "Expected keys() to be a list, not '%.200s'", + result->ob_type->tp_name); + goto error; + } + if (PyList_Sort(result) != 0) + goto error; + else + goto normal_return; + + error: + Py_XDECREF(result); + result = NULL; + /* fall through */ + normal_return: + Py_XDECREF(masterdict); + return result; +} + +/* +NoObject is usable as a non-NULL undefined value, used by the macro None. +There is (and should be!) no way to create other objects of this type, +so there is exactly one (which is indestructible, by the way). +(XXX This type and the type of NotImplemented below should be unified.) +*/ + +/* ARGSUSED */ +static PyObject * +none_repr(PyObject *op) +{ + return PyString_FromString("None"); +} + +/* ARGUSED */ +static void +none_dealloc(PyObject* ignore) +{ + /* This should never get called, but we also don't want to SEGV if + * we accidently decref None out of existance. + */ + Py_FatalError("deallocating None"); +} + + +static PyTypeObject PyNone_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "NoneType", + 0, + 0, + none_dealloc, /*tp_dealloc*/ /*never called*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + none_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ +}; + +PyObject _Py_NoneStruct = { + PyObject_HEAD_INIT(&PyNone_Type) +}; + +/* NotImplemented is an object that can be used to signal that an + operation is not implemented for the given type combination. */ + +static PyObject * +NotImplemented_repr(PyObject *op) +{ + return PyString_FromString("NotImplemented"); +} + +static PyTypeObject PyNotImplemented_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "NotImplementedType", + 0, + 0, + none_dealloc, /*tp_dealloc*/ /*never called*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + NotImplemented_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ +}; + +PyObject _Py_NotImplementedStruct = { + PyObject_HEAD_INIT(&PyNotImplemented_Type) +}; + +void +_Py_ReadyTypes(void) +{ + if (PyType_Ready(&PyType_Type) < 0) + Py_FatalError("Can't initialize 'type'"); + + if (PyType_Ready(&_PyWeakref_RefType) < 0) + Py_FatalError("Can't initialize 'weakref'"); + + if (PyType_Ready(&PyBool_Type) < 0) + Py_FatalError("Can't initialize 'bool'"); + + if (PyType_Ready(&PyString_Type) < 0) + Py_FatalError("Can't initialize 'str'"); + + if (PyType_Ready(&PyList_Type) < 0) + Py_FatalError("Can't initialize 'list'"); + + if (PyType_Ready(&PyNone_Type) < 0) + Py_FatalError("Can't initialize type(None)"); + + if (PyType_Ready(&PyNotImplemented_Type) < 0) + Py_FatalError("Can't initialize type(NotImplemented)"); +} + + +#ifdef Py_TRACE_REFS + +void +_Py_NewReference(PyObject *op) +{ + _Py_INC_REFTOTAL; + op->ob_refcnt = 1; + _Py_AddToAllObjects(op, 1); + _Py_INC_TPALLOCS(op); +} + +void +_Py_ForgetReference(register PyObject *op) +{ +#ifdef SLOW_UNREF_CHECK + register PyObject *p; +#endif + if (op->ob_refcnt < 0) + Py_FatalError("UNREF negative refcnt"); + if (op == &refchain || + op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) + Py_FatalError("UNREF invalid object"); +#ifdef SLOW_UNREF_CHECK + for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) { + if (p == op) + break; + } + if (p == &refchain) /* Not found */ + Py_FatalError("UNREF unknown object"); +#endif + op->_ob_next->_ob_prev = op->_ob_prev; + op->_ob_prev->_ob_next = op->_ob_next; + op->_ob_next = op->_ob_prev = NULL; + _Py_INC_TPFREES(op); +} + +void +_Py_Dealloc(PyObject *op) +{ + destructor dealloc = op->ob_type->tp_dealloc; + _Py_ForgetReference(op); + (*dealloc)(op); +} + +/* Print all live objects. Because PyObject_Print is called, the + * interpreter must be in a healthy state. + */ +void +_Py_PrintReferences(FILE *fp) +{ + PyObject *op; + fprintf(fp, "Remaining objects:\n"); + for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { + fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] ", op, op->ob_refcnt); + if (PyObject_Print(op, fp, 0) != 0) + PyErr_Clear(); + putc('\n', fp); + } +} + +/* Print the addresses of all live objects. Unlike _Py_PrintReferences, this + * doesn't make any calls to the Python C API, so is always safe to call. + */ +void +_Py_PrintReferenceAddresses(FILE *fp) +{ + PyObject *op; + fprintf(fp, "Remaining object addresses:\n"); + for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) + fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] %s\n", op, + op->ob_refcnt, op->ob_type->tp_name); +} + +PyObject * +_Py_GetObjects(PyObject *self, PyObject *args) +{ + int i, n; + PyObject *t = NULL; + PyObject *res, *op; + + if (!PyArg_ParseTuple(args, "i|O", &n, &t)) + return NULL; + op = refchain._ob_next; + res = PyList_New(0); + if (res == NULL) + return NULL; + for (i = 0; (n == 0 || i < n) && op != &refchain; i++) { + while (op == self || op == args || op == res || op == t || + (t != NULL && op->ob_type != (PyTypeObject *) t)) { + op = op->_ob_next; + if (op == &refchain) + return res; + } + if (PyList_Append(res, op) < 0) { + Py_DECREF(res); + return NULL; + } + op = op->_ob_next; + } + return res; +} + +#endif + + +/* Hack to force loading of cobject.o */ +PyTypeObject *_Py_cobject_hack = &PyCObject_Type; + + +/* Hack to force loading of abstract.o */ +Py_ssize_t (*_Py_abstract_hack)(PyObject *) = PyObject_Size; + + +/* Python's malloc wrappers (see pymem.h) */ + +void * +PyMem_Malloc(size_t nbytes) +{ + return PyMem_MALLOC(nbytes); +} + +void * +PyMem_Realloc(void *p, size_t nbytes) +{ + return PyMem_REALLOC(p, nbytes); +} + +void +PyMem_Free(void *p) +{ + PyMem_FREE(p); +} + + +/* These methods are used to control infinite recursion in repr, str, print, + etc. Container objects that may recursively contain themselves, + e.g. builtin dictionaries and lists, should used Py_ReprEnter() and + Py_ReprLeave() to avoid infinite recursion. + + Py_ReprEnter() returns 0 the first time it is called for a particular + object and 1 every time thereafter. It returns -1 if an exception + occurred. Py_ReprLeave() has no return value. + + See dictobject.c and listobject.c for examples of use. +*/ + +#define KEY "Py_Repr" + +int +Py_ReprEnter(PyObject *obj) +{ + PyObject *dict; + PyObject *list; + Py_ssize_t i; + + dict = PyThreadState_GetDict(); + if (dict == NULL) + return 0; + list = PyDict_GetItemString(dict, KEY); + if (list == NULL) { + list = PyList_New(0); + if (list == NULL) + return -1; + if (PyDict_SetItemString(dict, KEY, list) < 0) + return -1; + Py_DECREF(list); + } + i = PyList_GET_SIZE(list); + while (--i >= 0) { + if (PyList_GET_ITEM(list, i) == obj) + return 1; + } + PyList_Append(list, obj); + return 0; +} + +void +Py_ReprLeave(PyObject *obj) +{ + PyObject *dict; + PyObject *list; + Py_ssize_t i; + + dict = PyThreadState_GetDict(); + if (dict == NULL) + return; + list = PyDict_GetItemString(dict, KEY); + if (list == NULL || !PyList_Check(list)) + return; + i = PyList_GET_SIZE(list); + /* Count backwards because we always expect obj to be list[-1] */ + while (--i >= 0) { + if (PyList_GET_ITEM(list, i) == obj) { + PyList_SetSlice(list, i, i + 1, NULL); + break; + } + } +} + +/* Trashcan support. */ + +/* Current call-stack depth of tp_dealloc calls. */ +int _PyTrash_delete_nesting = 0; + +/* List of objects that still need to be cleaned up, singly linked via their + * gc headers' gc_prev pointers. + */ +PyObject *_PyTrash_delete_later = NULL; + +/* Add op to the _PyTrash_delete_later list. Called when the current + * call-stack depth gets large. op must be a currently untracked gc'ed + * object, with refcount 0. Py_DECREF must already have been called on it. + */ +void +_PyTrash_deposit_object(PyObject *op) +{ + assert(PyObject_IS_GC(op)); + assert(_Py_AS_GC(op)->gc.gc_refs == _PyGC_REFS_UNTRACKED); + assert(op->ob_refcnt == 0); + _Py_AS_GC(op)->gc.gc_prev = (PyGC_Head *)_PyTrash_delete_later; + _PyTrash_delete_later = op; +} + +/* Dealloccate all the objects in the _PyTrash_delete_later list. Called when + * the call-stack unwinds again. + */ +void +_PyTrash_destroy_chain(void) +{ + while (_PyTrash_delete_later) { + PyObject *op = _PyTrash_delete_later; + destructor dealloc = op->ob_type->tp_dealloc; + + _PyTrash_delete_later = + (PyObject*) _Py_AS_GC(op)->gc.gc_prev; + + /* Call the deallocator directly. This used to try to + * fool Py_DECREF into calling it indirectly, but + * Py_DECREF was already called on this object, and in + * assorted non-release builds calling Py_DECREF again ends + * up distorting allocation statistics. + */ + assert(op->ob_refcnt == 0); + ++_PyTrash_delete_nesting; + (*dealloc)(op); + --_PyTrash_delete_nesting; + } +} + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Objects/obmalloc.c b/sys/src/cmd/python/Objects/obmalloc.c new file mode 100644 index 000000000..840570e06 --- /dev/null +++ b/sys/src/cmd/python/Objects/obmalloc.c @@ -0,0 +1,1745 @@ +#include "Python.h" + +#ifdef WITH_PYMALLOC + +/* An object allocator for Python. + + Here is an introduction to the layers of the Python memory architecture, + showing where the object allocator is actually used (layer +2), It is + called for every object allocation and deallocation (PyObject_New/Del), + unless the object-specific allocators implement a proprietary allocation + scheme (ex.: ints use a simple free list). This is also the place where + the cyclic garbage collector operates selectively on container objects. + + + Object-specific allocators + _____ ______ ______ ________ + [ int ] [ dict ] [ list ] ... [ string ] Python core | ++3 | <----- Object-specific memory -----> | <-- Non-object memory --> | + _______________________________ | | + [ Python's object allocator ] | | ++2 | ####### Object memory ####### | <------ Internal buffers ------> | + ______________________________________________________________ | + [ Python's raw memory allocator (PyMem_ API) ] | ++1 | <----- Python memory (under PyMem manager's control) ------> | | + __________________________________________________________________ + [ Underlying general-purpose allocator (ex: C library malloc) ] + 0 | <------ Virtual memory allocated for the python process -------> | + + ========================================================================= + _______________________________________________________________________ + [ OS-specific Virtual Memory Manager (VMM) ] +-1 | <--- Kernel dynamic storage allocation & management (page-based) ---> | + __________________________________ __________________________________ + [ ] [ ] +-2 | <-- Physical memory: ROM/RAM --> | | <-- Secondary storage (swap) --> | + +*/ +/*==========================================================================*/ + +/* A fast, special-purpose memory allocator for small blocks, to be used + on top of a general-purpose malloc -- heavily based on previous art. */ + +/* Vladimir Marangozov -- August 2000 */ + +/* + * "Memory management is where the rubber meets the road -- if we do the wrong + * thing at any level, the results will not be good. And if we don't make the + * levels work well together, we are in serious trouble." (1) + * + * (1) Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles, + * "Dynamic Storage Allocation: A Survey and Critical Review", + * in Proc. 1995 Int'l. Workshop on Memory Management, September 1995. + */ + +/* #undef WITH_MEMORY_LIMITS */ /* disable mem limit checks */ + +/*==========================================================================*/ + +/* + * Allocation strategy abstract: + * + * For small requests, the allocator sub-allocates <Big> blocks of memory. + * Requests greater than 256 bytes are routed to the system's allocator. + * + * Small requests are grouped in size classes spaced 8 bytes apart, due + * to the required valid alignment of the returned address. Requests of + * a particular size are serviced from memory pools of 4K (one VMM page). + * Pools are fragmented on demand and contain free lists of blocks of one + * particular size class. In other words, there is a fixed-size allocator + * for each size class. Free pools are shared by the different allocators + * thus minimizing the space reserved for a particular size class. + * + * This allocation strategy is a variant of what is known as "simple + * segregated storage based on array of free lists". The main drawback of + * simple segregated storage is that we might end up with lot of reserved + * memory for the different free lists, which degenerate in time. To avoid + * this, we partition each free list in pools and we share dynamically the + * reserved space between all free lists. This technique is quite efficient + * for memory intensive programs which allocate mainly small-sized blocks. + * + * For small requests we have the following table: + * + * Request in bytes Size of allocated block Size class idx + * ---------------------------------------------------------------- + * 1-8 8 0 + * 9-16 16 1 + * 17-24 24 2 + * 25-32 32 3 + * 33-40 40 4 + * 41-48 48 5 + * 49-56 56 6 + * 57-64 64 7 + * 65-72 72 8 + * ... ... ... + * 241-248 248 30 + * 249-256 256 31 + * + * 0, 257 and up: routed to the underlying allocator. + */ + +/*==========================================================================*/ + +/* + * -- Main tunable settings section -- + */ + +/* + * Alignment of addresses returned to the user. 8-bytes alignment works + * on most current architectures (with 32-bit or 64-bit address busses). + * The alignment value is also used for grouping small requests in size + * classes spaced ALIGNMENT bytes apart. + * + * You shouldn't change this unless you know what you are doing. + */ +#define ALIGNMENT 8 /* must be 2^N */ +#define ALIGNMENT_SHIFT 3 +#define ALIGNMENT_MASK (ALIGNMENT - 1) + +/* Return the number of bytes in size class I, as a uint. */ +#define INDEX2SIZE(I) (((uint)(I) + 1) << ALIGNMENT_SHIFT) + +/* + * Max size threshold below which malloc requests are considered to be + * small enough in order to use preallocated memory pools. You can tune + * this value according to your application behaviour and memory needs. + * + * The following invariants must hold: + * 1) ALIGNMENT <= SMALL_REQUEST_THRESHOLD <= 256 + * 2) SMALL_REQUEST_THRESHOLD is evenly divisible by ALIGNMENT + * + * Although not required, for better performance and space efficiency, + * it is recommended that SMALL_REQUEST_THRESHOLD is set to a power of 2. + */ +#define SMALL_REQUEST_THRESHOLD 256 +#define NB_SMALL_SIZE_CLASSES (SMALL_REQUEST_THRESHOLD / ALIGNMENT) + +/* + * The system's VMM page size can be obtained on most unices with a + * getpagesize() call or deduced from various header files. To make + * things simpler, we assume that it is 4K, which is OK for most systems. + * It is probably better if this is the native page size, but it doesn't + * have to be. In theory, if SYSTEM_PAGE_SIZE is larger than the native page + * size, then `POOL_ADDR(p)->arenaindex' could rarely cause a segmentation + * violation fault. 4K is apparently OK for all the platforms that python + * currently targets. + */ +#define SYSTEM_PAGE_SIZE (4 * 1024) +#define SYSTEM_PAGE_SIZE_MASK (SYSTEM_PAGE_SIZE - 1) + +/* + * Maximum amount of memory managed by the allocator for small requests. + */ +#ifdef WITH_MEMORY_LIMITS +#ifndef SMALL_MEMORY_LIMIT +#define SMALL_MEMORY_LIMIT (64 * 1024 * 1024) /* 64 MB -- more? */ +#endif +#endif + +/* + * The allocator sub-allocates <Big> blocks of memory (called arenas) aligned + * on a page boundary. This is a reserved virtual address space for the + * current process (obtained through a malloc call). In no way this means + * that the memory arenas will be used entirely. A malloc(<Big>) is usually + * an address range reservation for <Big> bytes, unless all pages within this + * space are referenced subsequently. So malloc'ing big blocks and not using + * them does not mean "wasting memory". It's an addressable range wastage... + * + * Therefore, allocating arenas with malloc is not optimal, because there is + * some address space wastage, but this is the most portable way to request + * memory from the system across various platforms. + */ +#define ARENA_SIZE (256 << 10) /* 256KB */ + +#ifdef WITH_MEMORY_LIMITS +#define MAX_ARENAS (SMALL_MEMORY_LIMIT / ARENA_SIZE) +#endif + +/* + * Size of the pools used for small blocks. Should be a power of 2, + * between 1K and SYSTEM_PAGE_SIZE, that is: 1k, 2k, 4k. + */ +#define POOL_SIZE SYSTEM_PAGE_SIZE /* must be 2^N */ +#define POOL_SIZE_MASK SYSTEM_PAGE_SIZE_MASK + +/* + * -- End of tunable settings section -- + */ + +/*==========================================================================*/ + +/* + * Locking + * + * To reduce lock contention, it would probably be better to refine the + * crude function locking with per size class locking. I'm not positive + * however, whether it's worth switching to such locking policy because + * of the performance penalty it might introduce. + * + * The following macros describe the simplest (should also be the fastest) + * lock object on a particular platform and the init/fini/lock/unlock + * operations on it. The locks defined here are not expected to be recursive + * because it is assumed that they will always be called in the order: + * INIT, [LOCK, UNLOCK]*, FINI. + */ + +/* + * Python's threads are serialized, so object malloc locking is disabled. + */ +#define SIMPLELOCK_DECL(lock) /* simple lock declaration */ +#define SIMPLELOCK_INIT(lock) /* allocate (if needed) and initialize */ +#define SIMPLELOCK_FINI(lock) /* free/destroy an existing lock */ +#define SIMPLELOCK_LOCK(lock) /* acquire released lock */ +#define SIMPLELOCK_UNLOCK(lock) /* release acquired lock */ + +/* + * Basic types + * I don't care if these are defined in <sys/types.h> or elsewhere. Axiom. + */ +#undef uchar +#define uchar unsigned char /* assuming == 8 bits */ + +#undef uint +#define uint unsigned int /* assuming >= 16 bits */ + +#undef ulong +#define ulong unsigned long /* assuming >= 32 bits */ + +#undef uptr +#define uptr Py_uintptr_t + +/* When you say memory, my mind reasons in terms of (pointers to) blocks */ +typedef uchar block; + +/* Pool for small blocks. */ +struct pool_header { + union { block *_padding; + uint count; } ref; /* number of allocated blocks */ + block *freeblock; /* pool's free list head */ + struct pool_header *nextpool; /* next pool of this size class */ + struct pool_header *prevpool; /* previous pool "" */ + uint arenaindex; /* index into arenas of base adr */ + uint szidx; /* block size class index */ + uint nextoffset; /* bytes to virgin block */ + uint maxnextoffset; /* largest valid nextoffset */ +}; + +typedef struct pool_header *poolp; + +/* Record keeping for arenas. */ +struct arena_object { + /* The address of the arena, as returned by malloc. Note that 0 + * will never be returned by a successful malloc, and is used + * here to mark an arena_object that doesn't correspond to an + * allocated arena. + */ + uptr address; + + /* Pool-aligned pointer to the next pool to be carved off. */ + block* pool_address; + + /* The number of available pools in the arena: free pools + never- + * allocated pools. + */ + uint nfreepools; + + /* The total number of pools in the arena, whether or not available. */ + uint ntotalpools; + + /* Singly-linked list of available pools. */ + struct pool_header* freepools; + + /* Whenever this arena_object is not associated with an allocated + * arena, the nextarena member is used to link all unassociated + * arena_objects in the singly-linked `unused_arena_objects` list. + * The prevarena member is unused in this case. + * + * When this arena_object is associated with an allocated arena + * with at least one available pool, both members are used in the + * doubly-linked `usable_arenas` list, which is maintained in + * increasing order of `nfreepools` values. + * + * Else this arena_object is associated with an allocated arena + * all of whose pools are in use. `nextarena` and `prevarena` + * are both meaningless in this case. + */ + struct arena_object* nextarena; + struct arena_object* prevarena; +}; + +#undef ROUNDUP +#define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK) +#define POOL_OVERHEAD ROUNDUP(sizeof(struct pool_header)) + +#define DUMMY_SIZE_IDX 0xffff /* size class of newly cached pools */ + +/* Round pointer P down to the closest pool-aligned address <= P, as a poolp */ +#define POOL_ADDR(P) ((poolp)((uptr)(P) & ~(uptr)POOL_SIZE_MASK)) + +/* Return total number of blocks in pool of size index I, as a uint. */ +#define NUMBLOCKS(I) ((uint)(POOL_SIZE - POOL_OVERHEAD) / INDEX2SIZE(I)) + +/*==========================================================================*/ + +/* + * This malloc lock + */ +SIMPLELOCK_DECL(_malloc_lock) +#define LOCK() SIMPLELOCK_LOCK(_malloc_lock) +#define UNLOCK() SIMPLELOCK_UNLOCK(_malloc_lock) +#define LOCK_INIT() SIMPLELOCK_INIT(_malloc_lock) +#define LOCK_FINI() SIMPLELOCK_FINI(_malloc_lock) + +/* + * Pool table -- headed, circular, doubly-linked lists of partially used pools. + +This is involved. For an index i, usedpools[i+i] is the header for a list of +all partially used pools holding small blocks with "size class idx" i. So +usedpools[0] corresponds to blocks of size 8, usedpools[2] to blocks of size +16, and so on: index 2*i <-> blocks of size (i+1)<<ALIGNMENT_SHIFT. + +Pools are carved off an arena's highwater mark (an arena_object's pool_address +member) as needed. Once carved off, a pool is in one of three states forever +after: + +used == partially used, neither empty nor full + At least one block in the pool is currently allocated, and at least one + block in the pool is not currently allocated (note this implies a pool + has room for at least two blocks). + This is a pool's initial state, as a pool is created only when malloc + needs space. + The pool holds blocks of a fixed size, and is in the circular list headed + at usedpools[i] (see above). It's linked to the other used pools of the + same size class via the pool_header's nextpool and prevpool members. + If all but one block is currently allocated, a malloc can cause a + transition to the full state. If all but one block is not currently + allocated, a free can cause a transition to the empty state. + +full == all the pool's blocks are currently allocated + On transition to full, a pool is unlinked from its usedpools[] list. + It's not linked to from anything then anymore, and its nextpool and + prevpool members are meaningless until it transitions back to used. + A free of a block in a full pool puts the pool back in the used state. + Then it's linked in at the front of the appropriate usedpools[] list, so + that the next allocation for its size class will reuse the freed block. + +empty == all the pool's blocks are currently available for allocation + On transition to empty, a pool is unlinked from its usedpools[] list, + and linked to the front of its arena_object's singly-linked freepools list, + via its nextpool member. The prevpool member has no meaning in this case. + Empty pools have no inherent size class: the next time a malloc finds + an empty list in usedpools[], it takes the first pool off of freepools. + If the size class needed happens to be the same as the size class the pool + last had, some pool initialization can be skipped. + + +Block Management + +Blocks within pools are again carved out as needed. pool->freeblock points to +the start of a singly-linked list of free blocks within the pool. When a +block is freed, it's inserted at the front of its pool's freeblock list. Note +that the available blocks in a pool are *not* linked all together when a pool +is initialized. Instead only "the first two" (lowest addresses) blocks are +set up, returning the first such block, and setting pool->freeblock to a +one-block list holding the second such block. This is consistent with that +pymalloc strives at all levels (arena, pool, and block) never to touch a piece +of memory until it's actually needed. + +So long as a pool is in the used state, we're certain there *is* a block +available for allocating, and pool->freeblock is not NULL. If pool->freeblock +points to the end of the free list before we've carved the entire pool into +blocks, that means we simply haven't yet gotten to one of the higher-address +blocks. The offset from the pool_header to the start of "the next" virgin +block is stored in the pool_header nextoffset member, and the largest value +of nextoffset that makes sense is stored in the maxnextoffset member when a +pool is initialized. All the blocks in a pool have been passed out at least +once when and only when nextoffset > maxnextoffset. + + +Major obscurity: While the usedpools vector is declared to have poolp +entries, it doesn't really. It really contains two pointers per (conceptual) +poolp entry, the nextpool and prevpool members of a pool_header. The +excruciating initialization code below fools C so that + + usedpool[i+i] + +"acts like" a genuine poolp, but only so long as you only reference its +nextpool and prevpool members. The "- 2*sizeof(block *)" gibberish is +compensating for that a pool_header's nextpool and prevpool members +immediately follow a pool_header's first two members: + + union { block *_padding; + uint count; } ref; + block *freeblock; + +each of which consume sizeof(block *) bytes. So what usedpools[i+i] really +contains is a fudged-up pointer p such that *if* C believes it's a poolp +pointer, then p->nextpool and p->prevpool are both p (meaning that the headed +circular list is empty). + +It's unclear why the usedpools setup is so convoluted. It could be to +minimize the amount of cache required to hold this heavily-referenced table +(which only *needs* the two interpool pointer members of a pool_header). OTOH, +referencing code has to remember to "double the index" and doing so isn't +free, usedpools[0] isn't a strictly legal pointer, and we're crucially relying +on that C doesn't insert any padding anywhere in a pool_header at or before +the prevpool member. +**************************************************************************** */ + +#define PTA(x) ((poolp )((uchar *)&(usedpools[2*(x)]) - 2*sizeof(block *))) +#define PT(x) PTA(x), PTA(x) + +static poolp usedpools[2 * ((NB_SMALL_SIZE_CLASSES + 7) / 8) * 8] = { + PT(0), PT(1), PT(2), PT(3), PT(4), PT(5), PT(6), PT(7) +#if NB_SMALL_SIZE_CLASSES > 8 + , PT(8), PT(9), PT(10), PT(11), PT(12), PT(13), PT(14), PT(15) +#if NB_SMALL_SIZE_CLASSES > 16 + , PT(16), PT(17), PT(18), PT(19), PT(20), PT(21), PT(22), PT(23) +#if NB_SMALL_SIZE_CLASSES > 24 + , PT(24), PT(25), PT(26), PT(27), PT(28), PT(29), PT(30), PT(31) +#if NB_SMALL_SIZE_CLASSES > 32 + , PT(32), PT(33), PT(34), PT(35), PT(36), PT(37), PT(38), PT(39) +#if NB_SMALL_SIZE_CLASSES > 40 + , PT(40), PT(41), PT(42), PT(43), PT(44), PT(45), PT(46), PT(47) +#if NB_SMALL_SIZE_CLASSES > 48 + , PT(48), PT(49), PT(50), PT(51), PT(52), PT(53), PT(54), PT(55) +#if NB_SMALL_SIZE_CLASSES > 56 + , PT(56), PT(57), PT(58), PT(59), PT(60), PT(61), PT(62), PT(63) +#endif /* NB_SMALL_SIZE_CLASSES > 56 */ +#endif /* NB_SMALL_SIZE_CLASSES > 48 */ +#endif /* NB_SMALL_SIZE_CLASSES > 40 */ +#endif /* NB_SMALL_SIZE_CLASSES > 32 */ +#endif /* NB_SMALL_SIZE_CLASSES > 24 */ +#endif /* NB_SMALL_SIZE_CLASSES > 16 */ +#endif /* NB_SMALL_SIZE_CLASSES > 8 */ +}; + +/*========================================================================== +Arena management. + +`arenas` is a vector of arena_objects. It contains maxarenas entries, some of +which may not be currently used (== they're arena_objects that aren't +currently associated with an allocated arena). Note that arenas proper are +separately malloc'ed. + +Prior to Python 2.5, arenas were never free()'ed. Starting with Python 2.5, +we do try to free() arenas, and use some mild heuristic strategies to increase +the likelihood that arenas eventually can be freed. + +unused_arena_objects + + This is a singly-linked list of the arena_objects that are currently not + being used (no arena is associated with them). Objects are taken off the + head of the list in new_arena(), and are pushed on the head of the list in + PyObject_Free() when the arena is empty. Key invariant: an arena_object + is on this list if and only if its .address member is 0. + +usable_arenas + + This is a doubly-linked list of the arena_objects associated with arenas + that have pools available. These pools are either waiting to be reused, + or have not been used before. The list is sorted to have the most- + allocated arenas first (ascending order based on the nfreepools member). + This means that the next allocation will come from a heavily used arena, + which gives the nearly empty arenas a chance to be returned to the system. + In my unscientific tests this dramatically improved the number of arenas + that could be freed. + +Note that an arena_object associated with an arena all of whose pools are +currently in use isn't on either list. +*/ + +/* Array of objects used to track chunks of memory (arenas). */ +static struct arena_object* arenas = NULL; +/* Number of slots currently allocated in the `arenas` vector. */ +static uint maxarenas = 0; + +/* The head of the singly-linked, NULL-terminated list of available + * arena_objects. + */ +static struct arena_object* unused_arena_objects = NULL; + +/* The head of the doubly-linked, NULL-terminated at each end, list of + * arena_objects associated with arenas that have pools available. + */ +static struct arena_object* usable_arenas = NULL; + +/* How many arena_objects do we initially allocate? + * 16 = can allocate 16 arenas = 16 * ARENA_SIZE = 4MB before growing the + * `arenas` vector. + */ +#define INITIAL_ARENA_OBJECTS 16 + +/* Number of arenas allocated that haven't been free()'d. */ +static size_t narenas_currently_allocated = 0; + +#ifdef PYMALLOC_DEBUG +/* Total number of times malloc() called to allocate an arena. */ +static size_t ntimes_arena_allocated = 0; +/* High water mark (max value ever seen) for narenas_currently_allocated. */ +static size_t narenas_highwater = 0; +#endif + +/* Allocate a new arena. If we run out of memory, return NULL. Else + * allocate a new arena, and return the address of an arena_object + * describing the new arena. It's expected that the caller will set + * `usable_arenas` to the return value. + */ +static struct arena_object* +new_arena(void) +{ + struct arena_object* arenaobj; + uint excess; /* number of bytes above pool alignment */ + +#ifdef PYMALLOC_DEBUG + if (Py_GETENV("PYTHONMALLOCSTATS")) + _PyObject_DebugMallocStats(); +#endif + if (unused_arena_objects == NULL) { + uint i; + uint numarenas; + size_t nbytes; + + /* Double the number of arena objects on each allocation. + * Note that it's possible for `numarenas` to overflow. + */ + numarenas = maxarenas ? maxarenas << 1 : INITIAL_ARENA_OBJECTS; + if (numarenas <= maxarenas) + return NULL; /* overflow */ + nbytes = numarenas * sizeof(*arenas); + if (nbytes / sizeof(*arenas) != numarenas) + return NULL; /* overflow */ + arenaobj = (struct arena_object *)realloc(arenas, nbytes); + if (arenaobj == NULL) + return NULL; + arenas = arenaobj; + + /* We might need to fix pointers that were copied. However, + * new_arena only gets called when all the pages in the + * previous arenas are full. Thus, there are *no* pointers + * into the old array. Thus, we don't have to worry about + * invalid pointers. Just to be sure, some asserts: + */ + assert(usable_arenas == NULL); + assert(unused_arena_objects == NULL); + + /* Put the new arenas on the unused_arena_objects list. */ + for (i = maxarenas; i < numarenas; ++i) { + arenas[i].address = 0; /* mark as unassociated */ + arenas[i].nextarena = i < numarenas - 1 ? + &arenas[i+1] : NULL; + } + + /* Update globals. */ + unused_arena_objects = &arenas[maxarenas]; + maxarenas = numarenas; + } + + /* Take the next available arena object off the head of the list. */ + assert(unused_arena_objects != NULL); + arenaobj = unused_arena_objects; + unused_arena_objects = arenaobj->nextarena; + assert(arenaobj->address == 0); + arenaobj->address = (uptr)malloc(ARENA_SIZE); + if (arenaobj->address == 0) { + /* The allocation failed: return NULL after putting the + * arenaobj back. + */ + arenaobj->nextarena = unused_arena_objects; + unused_arena_objects = arenaobj; + return NULL; + } + + ++narenas_currently_allocated; +#ifdef PYMALLOC_DEBUG + ++ntimes_arena_allocated; + if (narenas_currently_allocated > narenas_highwater) + narenas_highwater = narenas_currently_allocated; +#endif + arenaobj->freepools = NULL; + /* pool_address <- first pool-aligned address in the arena + nfreepools <- number of whole pools that fit after alignment */ + arenaobj->pool_address = (block*)arenaobj->address; + arenaobj->nfreepools = ARENA_SIZE / POOL_SIZE; + assert(POOL_SIZE * arenaobj->nfreepools == ARENA_SIZE); + excess = (uint)(arenaobj->address & POOL_SIZE_MASK); + if (excess != 0) { + --arenaobj->nfreepools; + arenaobj->pool_address += POOL_SIZE - excess; + } + arenaobj->ntotalpools = arenaobj->nfreepools; + + return arenaobj; +} + +/* +Py_ADDRESS_IN_RANGE(P, POOL) + +Return true if and only if P is an address that was allocated by pymalloc. +POOL must be the pool address associated with P, i.e., POOL = POOL_ADDR(P) +(the caller is asked to compute this because the macro expands POOL more than +once, and for efficiency it's best for the caller to assign POOL_ADDR(P) to a +variable and pass the latter to the macro; because Py_ADDRESS_IN_RANGE is +called on every alloc/realloc/free, micro-efficiency is important here). + +Tricky: Let B be the arena base address associated with the pool, B = +arenas[(POOL)->arenaindex].address. Then P belongs to the arena if and only if + + B <= P < B + ARENA_SIZE + +Subtracting B throughout, this is true iff + + 0 <= P-B < ARENA_SIZE + +By using unsigned arithmetic, the "0 <=" half of the test can be skipped. + +Obscure: A PyMem "free memory" function can call the pymalloc free or realloc +before the first arena has been allocated. `arenas` is still NULL in that +case. We're relying on that maxarenas is also 0 in that case, so that +(POOL)->arenaindex < maxarenas must be false, saving us from trying to index +into a NULL arenas. + +Details: given P and POOL, the arena_object corresponding to P is AO = +arenas[(POOL)->arenaindex]. Suppose obmalloc controls P. Then (barring wild +stores, etc), POOL is the correct address of P's pool, AO.address is the +correct base address of the pool's arena, and P must be within ARENA_SIZE of +AO.address. In addition, AO.address is not 0 (no arena can start at address 0 +(NULL)). Therefore Py_ADDRESS_IN_RANGE correctly reports that obmalloc +controls P. + +Now suppose obmalloc does not control P (e.g., P was obtained via a direct +call to the system malloc() or realloc()). (POOL)->arenaindex may be anything +in this case -- it may even be uninitialized trash. If the trash arenaindex +is >= maxarenas, the macro correctly concludes at once that obmalloc doesn't +control P. + +Else arenaindex is < maxarena, and AO is read up. If AO corresponds to an +allocated arena, obmalloc controls all the memory in slice AO.address : +AO.address+ARENA_SIZE. By case assumption, P is not controlled by obmalloc, +so P doesn't lie in that slice, so the macro correctly reports that P is not +controlled by obmalloc. + +Finally, if P is not controlled by obmalloc and AO corresponds to an unused +arena_object (one not currently associated with an allocated arena), +AO.address is 0, and the second test in the macro reduces to: + + P < ARENA_SIZE + +If P >= ARENA_SIZE (extremely likely), the macro again correctly concludes +that P is not controlled by obmalloc. However, if P < ARENA_SIZE, this part +of the test still passes, and the third clause (AO.address != 0) is necessary +to get the correct result: AO.address is 0 in this case, so the macro +correctly reports that P is not controlled by obmalloc (despite that P lies in +slice AO.address : AO.address + ARENA_SIZE). + +Note: The third (AO.address != 0) clause was added in Python 2.5. Before +2.5, arenas were never free()'ed, and an arenaindex < maxarena always +corresponded to a currently-allocated arena, so the "P is not controlled by +obmalloc, AO corresponds to an unused arena_object, and P < ARENA_SIZE" case +was impossible. + +Note that the logic is excruciating, and reading up possibly uninitialized +memory when P is not controlled by obmalloc (to get at (POOL)->arenaindex) +creates problems for some memory debuggers. The overwhelming advantage is +that this test determines whether an arbitrary address is controlled by +obmalloc in a small constant time, independent of the number of arenas +obmalloc controls. Since this test is needed at every entry point, it's +extremely desirable that it be this fast. +*/ +#define Py_ADDRESS_IN_RANGE(P, POOL) \ + ((POOL)->arenaindex < maxarenas && \ + (uptr)(P) - arenas[(POOL)->arenaindex].address < (uptr)ARENA_SIZE && \ + arenas[(POOL)->arenaindex].address != 0) + + +/* This is only useful when running memory debuggers such as + * Purify or Valgrind. Uncomment to use. + * +#define Py_USING_MEMORY_DEBUGGER + */ + +#ifdef Py_USING_MEMORY_DEBUGGER + +/* Py_ADDRESS_IN_RANGE may access uninitialized memory by design + * This leads to thousands of spurious warnings when using + * Purify or Valgrind. By making a function, we can easily + * suppress the uninitialized memory reads in this one function. + * So we won't ignore real errors elsewhere. + * + * Disable the macro and use a function. + */ + +#undef Py_ADDRESS_IN_RANGE + +#if defined(__GNUC__) && ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) || \ + (__GNUC__ >= 4)) +#define Py_NO_INLINE __attribute__((__noinline__)) +#else +#define Py_NO_INLINE +#endif + +/* Don't make static, to try to ensure this isn't inlined. */ +int Py_ADDRESS_IN_RANGE(void *P, poolp pool) Py_NO_INLINE; +#undef Py_NO_INLINE +#endif + +/*==========================================================================*/ + +/* malloc. Note that nbytes==0 tries to return a non-NULL pointer, distinct + * from all other currently live pointers. This may not be possible. + */ + +/* + * The basic blocks are ordered by decreasing execution frequency, + * which minimizes the number of jumps in the most common cases, + * improves branching prediction and instruction scheduling (small + * block allocations typically result in a couple of instructions). + * Unless the optimizer reorders everything, being too smart... + */ + +#undef PyObject_Malloc +void * +PyObject_Malloc(size_t nbytes) +{ + block *bp; + poolp pool; + poolp next; + uint size; + + /* + * This implicitly redirects malloc(0). + */ + if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) { + LOCK(); + /* + * Most frequent paths first + */ + size = (uint)(nbytes - 1) >> ALIGNMENT_SHIFT; + pool = usedpools[size + size]; + if (pool != pool->nextpool) { + /* + * There is a used pool for this size class. + * Pick up the head block of its free list. + */ + ++pool->ref.count; + bp = pool->freeblock; + assert(bp != NULL); + if ((pool->freeblock = *(block **)bp) != NULL) { + UNLOCK(); + return (void *)bp; + } + /* + * Reached the end of the free list, try to extend it. + */ + if (pool->nextoffset <= pool->maxnextoffset) { + /* There is room for another block. */ + pool->freeblock = (block*)pool + + pool->nextoffset; + pool->nextoffset += INDEX2SIZE(size); + *(block **)(pool->freeblock) = NULL; + UNLOCK(); + return (void *)bp; + } + /* Pool is full, unlink from used pools. */ + next = pool->nextpool; + pool = pool->prevpool; + next->prevpool = pool; + pool->nextpool = next; + UNLOCK(); + return (void *)bp; + } + + /* There isn't a pool of the right size class immediately + * available: use a free pool. + */ + if (usable_arenas == NULL) { + /* No arena has a free pool: allocate a new arena. */ +#ifdef WITH_MEMORY_LIMITS + if (narenas_currently_allocated >= MAX_ARENAS) { + UNLOCK(); + goto redirect; + } +#endif + usable_arenas = new_arena(); + if (usable_arenas == NULL) { + UNLOCK(); + goto redirect; + } + usable_arenas->nextarena = + usable_arenas->prevarena = NULL; + } + assert(usable_arenas->address != 0); + + /* Try to get a cached free pool. */ + pool = usable_arenas->freepools; + if (pool != NULL) { + /* Unlink from cached pools. */ + usable_arenas->freepools = pool->nextpool; + + /* This arena already had the smallest nfreepools + * value, so decreasing nfreepools doesn't change + * that, and we don't need to rearrange the + * usable_arenas list. However, if the arena has + * become wholly allocated, we need to remove its + * arena_object from usable_arenas. + */ + --usable_arenas->nfreepools; + if (usable_arenas->nfreepools == 0) { + /* Wholly allocated: remove. */ + assert(usable_arenas->freepools == NULL); + assert(usable_arenas->nextarena == NULL || + usable_arenas->nextarena->prevarena == + usable_arenas); + + usable_arenas = usable_arenas->nextarena; + if (usable_arenas != NULL) { + usable_arenas->prevarena = NULL; + assert(usable_arenas->address != 0); + } + } + else { + /* nfreepools > 0: it must be that freepools + * isn't NULL, or that we haven't yet carved + * off all the arena's pools for the first + * time. + */ + assert(usable_arenas->freepools != NULL || + usable_arenas->pool_address <= + (block*)usable_arenas->address + + ARENA_SIZE - POOL_SIZE); + } + init_pool: + /* Frontlink to used pools. */ + next = usedpools[size + size]; /* == prev */ + pool->nextpool = next; + pool->prevpool = next; + next->nextpool = pool; + next->prevpool = pool; + pool->ref.count = 1; + if (pool->szidx == size) { + /* Luckily, this pool last contained blocks + * of the same size class, so its header + * and free list are already initialized. + */ + bp = pool->freeblock; + pool->freeblock = *(block **)bp; + UNLOCK(); + return (void *)bp; + } + /* + * Initialize the pool header, set up the free list to + * contain just the second block, and return the first + * block. + */ + pool->szidx = size; + size = INDEX2SIZE(size); + bp = (block *)pool + POOL_OVERHEAD; + pool->nextoffset = POOL_OVERHEAD + (size << 1); + pool->maxnextoffset = POOL_SIZE - size; + pool->freeblock = bp + size; + *(block **)(pool->freeblock) = NULL; + UNLOCK(); + return (void *)bp; + } + + /* Carve off a new pool. */ + assert(usable_arenas->nfreepools > 0); + assert(usable_arenas->freepools == NULL); + pool = (poolp)usable_arenas->pool_address; + assert((block*)pool <= (block*)usable_arenas->address + + ARENA_SIZE - POOL_SIZE); + pool->arenaindex = usable_arenas - arenas; + assert(&arenas[pool->arenaindex] == usable_arenas); + pool->szidx = DUMMY_SIZE_IDX; + usable_arenas->pool_address += POOL_SIZE; + --usable_arenas->nfreepools; + + if (usable_arenas->nfreepools == 0) { + assert(usable_arenas->nextarena == NULL || + usable_arenas->nextarena->prevarena == + usable_arenas); + /* Unlink the arena: it is completely allocated. */ + usable_arenas = usable_arenas->nextarena; + if (usable_arenas != NULL) { + usable_arenas->prevarena = NULL; + assert(usable_arenas->address != 0); + } + } + + goto init_pool; + } + + /* The small block allocator ends here. */ + +redirect: + /* Redirect the original request to the underlying (libc) allocator. + * We jump here on bigger requests, on error in the code above (as a + * last chance to serve the request) or when the max memory limit + * has been reached. + */ + if (nbytes == 0) + nbytes = 1; + return (void *)malloc(nbytes); +} + +/* free */ + +#undef PyObject_Free +void +PyObject_Free(void *p) +{ + poolp pool; + block *lastfree; + poolp next, prev; + uint size; + + if (p == NULL) /* free(NULL) has no effect */ + return; + + pool = POOL_ADDR(p); + if (Py_ADDRESS_IN_RANGE(p, pool)) { + /* We allocated this address. */ + LOCK(); + /* Link p to the start of the pool's freeblock list. Since + * the pool had at least the p block outstanding, the pool + * wasn't empty (so it's already in a usedpools[] list, or + * was full and is in no list -- it's not in the freeblocks + * list in any case). + */ + assert(pool->ref.count > 0); /* else it was empty */ + *(block **)p = lastfree = pool->freeblock; + pool->freeblock = (block *)p; + if (lastfree) { + struct arena_object* ao; + uint nf; /* ao->nfreepools */ + + /* freeblock wasn't NULL, so the pool wasn't full, + * and the pool is in a usedpools[] list. + */ + if (--pool->ref.count != 0) { + /* pool isn't empty: leave it in usedpools */ + UNLOCK(); + return; + } + /* Pool is now empty: unlink from usedpools, and + * link to the front of freepools. This ensures that + * previously freed pools will be allocated later + * (being not referenced, they are perhaps paged out). + */ + next = pool->nextpool; + prev = pool->prevpool; + next->prevpool = prev; + prev->nextpool = next; + + /* Link the pool to freepools. This is a singly-linked + * list, and pool->prevpool isn't used there. + */ + ao = &arenas[pool->arenaindex]; + pool->nextpool = ao->freepools; + ao->freepools = pool; + nf = ++ao->nfreepools; + + /* All the rest is arena management. We just freed + * a pool, and there are 4 cases for arena mgmt: + * 1. If all the pools are free, return the arena to + * the system free(). + * 2. If this is the only free pool in the arena, + * add the arena back to the `usable_arenas` list. + * 3. If the "next" arena has a smaller count of free + * pools, we have to "slide this arena right" to + * restore that usable_arenas is sorted in order of + * nfreepools. + * 4. Else there's nothing more to do. + */ + if (nf == ao->ntotalpools) { + /* Case 1. First unlink ao from usable_arenas. + */ + assert(ao->prevarena == NULL || + ao->prevarena->address != 0); + assert(ao ->nextarena == NULL || + ao->nextarena->address != 0); + + /* Fix the pointer in the prevarena, or the + * usable_arenas pointer. + */ + if (ao->prevarena == NULL) { + usable_arenas = ao->nextarena; + assert(usable_arenas == NULL || + usable_arenas->address != 0); + } + else { + assert(ao->prevarena->nextarena == ao); + ao->prevarena->nextarena = + ao->nextarena; + } + /* Fix the pointer in the nextarena. */ + if (ao->nextarena != NULL) { + assert(ao->nextarena->prevarena == ao); + ao->nextarena->prevarena = + ao->prevarena; + } + /* Record that this arena_object slot is + * available to be reused. + */ + ao->nextarena = unused_arena_objects; + unused_arena_objects = ao; + + /* Free the entire arena. */ + free((void *)ao->address); + ao->address = 0; /* mark unassociated */ + --narenas_currently_allocated; + + UNLOCK(); + return; + } + if (nf == 1) { + /* Case 2. Put ao at the head of + * usable_arenas. Note that because + * ao->nfreepools was 0 before, ao isn't + * currently on the usable_arenas list. + */ + ao->nextarena = usable_arenas; + ao->prevarena = NULL; + if (usable_arenas) + usable_arenas->prevarena = ao; + usable_arenas = ao; + assert(usable_arenas->address != 0); + + UNLOCK(); + return; + } + /* If this arena is now out of order, we need to keep + * the list sorted. The list is kept sorted so that + * the "most full" arenas are used first, which allows + * the nearly empty arenas to be completely freed. In + * a few un-scientific tests, it seems like this + * approach allowed a lot more memory to be freed. + */ + if (ao->nextarena == NULL || + nf <= ao->nextarena->nfreepools) { + /* Case 4. Nothing to do. */ + UNLOCK(); + return; + } + /* Case 3: We have to move the arena towards the end + * of the list, because it has more free pools than + * the arena to its right. + * First unlink ao from usable_arenas. + */ + if (ao->prevarena != NULL) { + /* ao isn't at the head of the list */ + assert(ao->prevarena->nextarena == ao); + ao->prevarena->nextarena = ao->nextarena; + } + else { + /* ao is at the head of the list */ + assert(usable_arenas == ao); + usable_arenas = ao->nextarena; + } + ao->nextarena->prevarena = ao->prevarena; + + /* Locate the new insertion point by iterating over + * the list, using our nextarena pointer. + */ + while (ao->nextarena != NULL && + nf > ao->nextarena->nfreepools) { + ao->prevarena = ao->nextarena; + ao->nextarena = ao->nextarena->nextarena; + } + + /* Insert ao at this point. */ + assert(ao->nextarena == NULL || + ao->prevarena == ao->nextarena->prevarena); + assert(ao->prevarena->nextarena == ao->nextarena); + + ao->prevarena->nextarena = ao; + if (ao->nextarena != NULL) + ao->nextarena->prevarena = ao; + + /* Verify that the swaps worked. */ + assert(ao->nextarena == NULL || + nf <= ao->nextarena->nfreepools); + assert(ao->prevarena == NULL || + nf > ao->prevarena->nfreepools); + assert(ao->nextarena == NULL || + ao->nextarena->prevarena == ao); + assert((usable_arenas == ao && + ao->prevarena == NULL) || + ao->prevarena->nextarena == ao); + + UNLOCK(); + return; + } + /* Pool was full, so doesn't currently live in any list: + * link it to the front of the appropriate usedpools[] list. + * This mimics LRU pool usage for new allocations and + * targets optimal filling when several pools contain + * blocks of the same size class. + */ + --pool->ref.count; + assert(pool->ref.count > 0); /* else the pool is empty */ + size = pool->szidx; + next = usedpools[size + size]; + prev = next->prevpool; + /* insert pool before next: prev <-> pool <-> next */ + pool->nextpool = next; + pool->prevpool = prev; + next->prevpool = pool; + prev->nextpool = pool; + UNLOCK(); + return; + } + + /* We didn't allocate this address. */ + free(p); +} + +/* realloc. If p is NULL, this acts like malloc(nbytes). Else if nbytes==0, + * then as the Python docs promise, we do not treat this like free(p), and + * return a non-NULL result. + */ + +#undef PyObject_Realloc +void * +PyObject_Realloc(void *p, size_t nbytes) +{ + void *bp; + poolp pool; + size_t size; + + if (p == NULL) + return PyObject_Malloc(nbytes); + + pool = POOL_ADDR(p); + if (Py_ADDRESS_IN_RANGE(p, pool)) { + /* We're in charge of this block */ + size = INDEX2SIZE(pool->szidx); + if (nbytes <= size) { + /* The block is staying the same or shrinking. If + * it's shrinking, there's a tradeoff: it costs + * cycles to copy the block to a smaller size class, + * but it wastes memory not to copy it. The + * compromise here is to copy on shrink only if at + * least 25% of size can be shaved off. + */ + if (4 * nbytes > 3 * size) { + /* It's the same, + * or shrinking and new/old > 3/4. + */ + return p; + } + size = nbytes; + } + bp = PyObject_Malloc(nbytes); + if (bp != NULL) { + memcpy(bp, p, size); + PyObject_Free(p); + } + return bp; + } + /* We're not managing this block. If nbytes <= + * SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this + * block. However, if we do, we need to copy the valid data from + * the C-managed block to one of our blocks, and there's no portable + * way to know how much of the memory space starting at p is valid. + * As bug 1185883 pointed out the hard way, it's possible that the + * C-managed block is "at the end" of allocated VM space, so that + * a memory fault can occur if we try to copy nbytes bytes starting + * at p. Instead we punt: let C continue to manage this block. + */ + if (nbytes) + return realloc(p, nbytes); + /* C doesn't define the result of realloc(p, 0) (it may or may not + * return NULL then), but Python's docs promise that nbytes==0 never + * returns NULL. We don't pass 0 to realloc(), to avoid that endcase + * to begin with. Even then, we can't be sure that realloc() won't + * return NULL. + */ + bp = realloc(p, 1); + return bp ? bp : p; +} + +#else /* ! WITH_PYMALLOC */ + +/*==========================================================================*/ +/* pymalloc not enabled: Redirect the entry points to malloc. These will + * only be used by extensions that are compiled with pymalloc enabled. */ + +void * +PyObject_Malloc(size_t n) +{ + return PyMem_MALLOC(n); +} + +void * +PyObject_Realloc(void *p, size_t n) +{ + return PyMem_REALLOC(p, n); +} + +void +PyObject_Free(void *p) +{ + PyMem_FREE(p); +} +#endif /* WITH_PYMALLOC */ + +#ifdef PYMALLOC_DEBUG +/*==========================================================================*/ +/* A x-platform debugging allocator. This doesn't manage memory directly, + * it wraps a real allocator, adding extra debugging info to the memory blocks. + */ + +/* Special bytes broadcast into debug memory blocks at appropriate times. + * Strings of these are unlikely to be valid addresses, floats, ints or + * 7-bit ASCII. + */ +#undef CLEANBYTE +#undef DEADBYTE +#undef FORBIDDENBYTE +#define CLEANBYTE 0xCB /* clean (newly allocated) memory */ +#define DEADBYTE 0xDB /* dead (newly freed) memory */ +#define FORBIDDENBYTE 0xFB /* untouchable bytes at each end of a block */ + +static size_t serialno = 0; /* incremented on each debug {m,re}alloc */ + +/* serialno is always incremented via calling this routine. The point is + * to supply a single place to set a breakpoint. + */ +static void +bumpserialno(void) +{ + ++serialno; +} + +#define SST SIZEOF_SIZE_T + +/* Read sizeof(size_t) bytes at p as a big-endian size_t. */ +static size_t +read_size_t(const void *p) +{ + const uchar *q = (const uchar *)p; + size_t result = *q++; + int i; + + for (i = SST; --i > 0; ++q) + result = (result << 8) | *q; + return result; +} + +/* Write n as a big-endian size_t, MSB at address p, LSB at + * p + sizeof(size_t) - 1. + */ +static void +write_size_t(void *p, size_t n) +{ + uchar *q = (uchar *)p + SST - 1; + int i; + + for (i = SST; --i >= 0; --q) { + *q = (uchar)(n & 0xff); + n >>= 8; + } +} + +#ifdef Py_DEBUG +/* Is target in the list? The list is traversed via the nextpool pointers. + * The list may be NULL-terminated, or circular. Return 1 if target is in + * list, else 0. + */ +static int +pool_is_in_list(const poolp target, poolp list) +{ + poolp origlist = list; + assert(target != NULL); + if (list == NULL) + return 0; + do { + if (target == list) + return 1; + list = list->nextpool; + } while (list != NULL && list != origlist); + return 0; +} + +#else +#define pool_is_in_list(X, Y) 1 + +#endif /* Py_DEBUG */ + +/* Let S = sizeof(size_t). The debug malloc asks for 4*S extra bytes and + fills them with useful stuff, here calling the underlying malloc's result p: + +p[0: S] + Number of bytes originally asked for. This is a size_t, big-endian (easier + to read in a memory dump). +p[S: 2*S] + Copies of FORBIDDENBYTE. Used to catch under- writes and reads. +p[2*S: 2*S+n] + The requested memory, filled with copies of CLEANBYTE. + Used to catch reference to uninitialized memory. + &p[2*S] is returned. Note that this is 8-byte aligned if pymalloc + handled the request itself. +p[2*S+n: 2*S+n+S] + Copies of FORBIDDENBYTE. Used to catch over- writes and reads. +p[2*S+n+S: 2*S+n+2*S] + A serial number, incremented by 1 on each call to _PyObject_DebugMalloc + and _PyObject_DebugRealloc. + This is a big-endian size_t. + If "bad memory" is detected later, the serial number gives an + excellent way to set a breakpoint on the next run, to capture the + instant at which this block was passed out. +*/ + +void * +_PyObject_DebugMalloc(size_t nbytes) +{ + uchar *p; /* base address of malloc'ed block */ + uchar *tail; /* p + 2*SST + nbytes == pointer to tail pad bytes */ + size_t total; /* nbytes + 4*SST */ + + bumpserialno(); + total = nbytes + 4*SST; + if (total < nbytes) + /* overflow: can't represent total as a size_t */ + return NULL; + + p = (uchar *)PyObject_Malloc(total); + if (p == NULL) + return NULL; + + write_size_t(p, nbytes); + memset(p + SST, FORBIDDENBYTE, SST); + + if (nbytes > 0) + memset(p + 2*SST, CLEANBYTE, nbytes); + + tail = p + 2*SST + nbytes; + memset(tail, FORBIDDENBYTE, SST); + write_size_t(tail + SST, serialno); + + return p + 2*SST; +} + +/* The debug free first checks the 2*SST bytes on each end for sanity (in + particular, that the FORBIDDENBYTEs are still intact). + Then fills the original bytes with DEADBYTE. + Then calls the underlying free. +*/ +void +_PyObject_DebugFree(void *p) +{ + uchar *q = (uchar *)p - 2*SST; /* address returned from malloc */ + size_t nbytes; + + if (p == NULL) + return; + _PyObject_DebugCheckAddress(p); + nbytes = read_size_t(q); + if (nbytes > 0) + memset(q, DEADBYTE, nbytes); + PyObject_Free(q); +} + +void * +_PyObject_DebugRealloc(void *p, size_t nbytes) +{ + uchar *q = (uchar *)p; + uchar *tail; + size_t total; /* nbytes + 4*SST */ + size_t original_nbytes; + int i; + + if (p == NULL) + return _PyObject_DebugMalloc(nbytes); + + _PyObject_DebugCheckAddress(p); + bumpserialno(); + original_nbytes = read_size_t(q - 2*SST); + total = nbytes + 4*SST; + if (total < nbytes) + /* overflow: can't represent total as a size_t */ + return NULL; + + if (nbytes < original_nbytes) { + /* shrinking: mark old extra memory dead */ + memset(q + nbytes, DEADBYTE, original_nbytes - nbytes); + } + + /* Resize and add decorations. */ + q = (uchar *)PyObject_Realloc(q - 2*SST, total); + if (q == NULL) + return NULL; + + write_size_t(q, nbytes); + for (i = 0; i < SST; ++i) + assert(q[SST + i] == FORBIDDENBYTE); + q += 2*SST; + tail = q + nbytes; + memset(tail, FORBIDDENBYTE, SST); + write_size_t(tail + SST, serialno); + + if (nbytes > original_nbytes) { + /* growing: mark new extra memory clean */ + memset(q + original_nbytes, CLEANBYTE, + nbytes - original_nbytes); + } + + return q; +} + +/* Check the forbidden bytes on both ends of the memory allocated for p. + * If anything is wrong, print info to stderr via _PyObject_DebugDumpAddress, + * and call Py_FatalError to kill the program. + */ + void +_PyObject_DebugCheckAddress(const void *p) +{ + const uchar *q = (const uchar *)p; + char *msg; + size_t nbytes; + const uchar *tail; + int i; + + if (p == NULL) { + msg = "didn't expect a NULL pointer"; + goto error; + } + + /* Check the stuff at the start of p first: if there's underwrite + * corruption, the number-of-bytes field may be nuts, and checking + * the tail could lead to a segfault then. + */ + for (i = SST; i >= 1; --i) { + if (*(q-i) != FORBIDDENBYTE) { + msg = "bad leading pad byte"; + goto error; + } + } + + nbytes = read_size_t(q - 2*SST); + tail = q + nbytes; + for (i = 0; i < SST; ++i) { + if (tail[i] != FORBIDDENBYTE) { + msg = "bad trailing pad byte"; + goto error; + } + } + + return; + +error: + _PyObject_DebugDumpAddress(p); + Py_FatalError(msg); +} + +/* Display info to stderr about the memory block at p. */ +void +_PyObject_DebugDumpAddress(const void *p) +{ + const uchar *q = (const uchar *)p; + const uchar *tail; + size_t nbytes, serial; + int i; + int ok; + + fprintf(stderr, "Debug memory block at address p=%p:\n", p); + if (p == NULL) + return; + + nbytes = read_size_t(q - 2*SST); + fprintf(stderr, " %" PY_FORMAT_SIZE_T "u bytes originally " + "requested\n", nbytes); + + /* In case this is nuts, check the leading pad bytes first. */ + fprintf(stderr, " The %d pad bytes at p-%d are ", SST, SST); + ok = 1; + for (i = 1; i <= SST; ++i) { + if (*(q-i) != FORBIDDENBYTE) { + ok = 0; + break; + } + } + if (ok) + fputs("FORBIDDENBYTE, as expected.\n", stderr); + else { + fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", + FORBIDDENBYTE); + for (i = SST; i >= 1; --i) { + const uchar byte = *(q-i); + fprintf(stderr, " at p-%d: 0x%02x", i, byte); + if (byte != FORBIDDENBYTE) + fputs(" *** OUCH", stderr); + fputc('\n', stderr); + } + + fputs(" Because memory is corrupted at the start, the " + "count of bytes requested\n" + " may be bogus, and checking the trailing pad " + "bytes may segfault.\n", stderr); + } + + tail = q + nbytes; + fprintf(stderr, " The %d pad bytes at tail=%p are ", SST, tail); + ok = 1; + for (i = 0; i < SST; ++i) { + if (tail[i] != FORBIDDENBYTE) { + ok = 0; + break; + } + } + if (ok) + fputs("FORBIDDENBYTE, as expected.\n", stderr); + else { + fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", + FORBIDDENBYTE); + for (i = 0; i < SST; ++i) { + const uchar byte = tail[i]; + fprintf(stderr, " at tail+%d: 0x%02x", + i, byte); + if (byte != FORBIDDENBYTE) + fputs(" *** OUCH", stderr); + fputc('\n', stderr); + } + } + + serial = read_size_t(tail + SST); + fprintf(stderr, " The block was made by call #%" PY_FORMAT_SIZE_T + "u to debug malloc/realloc.\n", serial); + + if (nbytes > 0) { + i = 0; + fputs(" Data at p:", stderr); + /* print up to 8 bytes at the start */ + while (q < tail && i < 8) { + fprintf(stderr, " %02x", *q); + ++i; + ++q; + } + /* and up to 8 at the end */ + if (q < tail) { + if (tail - q > 8) { + fputs(" ...", stderr); + q = tail - 8; + } + while (q < tail) { + fprintf(stderr, " %02x", *q); + ++q; + } + } + fputc('\n', stderr); + } +} + +static size_t +printone(const char* msg, size_t value) +{ + int i, k; + char buf[100]; + size_t origvalue = value; + + fputs(msg, stderr); + for (i = (int)strlen(msg); i < 35; ++i) + fputc(' ', stderr); + fputc('=', stderr); + + /* Write the value with commas. */ + i = 22; + buf[i--] = '\0'; + buf[i--] = '\n'; + k = 3; + do { + size_t nextvalue = value / 10; + uint digit = (uint)(value - nextvalue * 10); + value = nextvalue; + buf[i--] = (char)(digit + '0'); + --k; + if (k == 0 && value && i >= 0) { + k = 3; + buf[i--] = ','; + } + } while (value && i >= 0); + + while (i >= 0) + buf[i--] = ' '; + fputs(buf, stderr); + + return origvalue; +} + +/* Print summary info to stderr about the state of pymalloc's structures. + * In Py_DEBUG mode, also perform some expensive internal consistency + * checks. + */ +void +_PyObject_DebugMallocStats(void) +{ + uint i; + const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT; + /* # of pools, allocated blocks, and free blocks per class index */ + size_t numpools[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; + size_t numblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; + size_t numfreeblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; + /* total # of allocated bytes in used and full pools */ + size_t allocated_bytes = 0; + /* total # of available bytes in used pools */ + size_t available_bytes = 0; + /* # of free pools + pools not yet carved out of current arena */ + uint numfreepools = 0; + /* # of bytes for arena alignment padding */ + size_t arena_alignment = 0; + /* # of bytes in used and full pools used for pool_headers */ + size_t pool_header_bytes = 0; + /* # of bytes in used and full pools wasted due to quantization, + * i.e. the necessarily leftover space at the ends of used and + * full pools. + */ + size_t quantization = 0; + /* # of arenas actually allocated. */ + size_t narenas = 0; + /* running total -- should equal narenas * ARENA_SIZE */ + size_t total; + char buf[128]; + + fprintf(stderr, "Small block threshold = %d, in %u size classes.\n", + SMALL_REQUEST_THRESHOLD, numclasses); + + for (i = 0; i < numclasses; ++i) + numpools[i] = numblocks[i] = numfreeblocks[i] = 0; + + /* Because full pools aren't linked to from anything, it's easiest + * to march over all the arenas. If we're lucky, most of the memory + * will be living in full pools -- would be a shame to miss them. + */ + for (i = 0; i < maxarenas; ++i) { + uint poolsinarena; + uint j; + uptr base = arenas[i].address; + + /* Skip arenas which are not allocated. */ + if (arenas[i].address == (uptr)NULL) + continue; + narenas += 1; + + poolsinarena = arenas[i].ntotalpools; + numfreepools += arenas[i].nfreepools; + + /* round up to pool alignment */ + if (base & (uptr)POOL_SIZE_MASK) { + arena_alignment += POOL_SIZE; + base &= ~(uptr)POOL_SIZE_MASK; + base += POOL_SIZE; + } + + /* visit every pool in the arena */ + assert(base <= (uptr) arenas[i].pool_address); + for (j = 0; + base < (uptr) arenas[i].pool_address; + ++j, base += POOL_SIZE) { + poolp p = (poolp)base; + const uint sz = p->szidx; + uint freeblocks; + + if (p->ref.count == 0) { + /* currently unused */ + assert(pool_is_in_list(p, arenas[i].freepools)); + continue; + } + ++numpools[sz]; + numblocks[sz] += p->ref.count; + freeblocks = NUMBLOCKS(sz) - p->ref.count; + numfreeblocks[sz] += freeblocks; +#ifdef Py_DEBUG + if (freeblocks > 0) + assert(pool_is_in_list(p, usedpools[sz + sz])); +#endif + } + } + assert(narenas == narenas_currently_allocated); + + fputc('\n', stderr); + fputs("class size num pools blocks in use avail blocks\n" + "----- ---- --------- ------------- ------------\n", + stderr); + + for (i = 0; i < numclasses; ++i) { + size_t p = numpools[i]; + size_t b = numblocks[i]; + size_t f = numfreeblocks[i]; + uint size = INDEX2SIZE(i); + if (p == 0) { + assert(b == 0 && f == 0); + continue; + } + fprintf(stderr, "%5u %6u " + "%11" PY_FORMAT_SIZE_T "u " + "%15" PY_FORMAT_SIZE_T "u " + "%13" PY_FORMAT_SIZE_T "u\n", + i, size, p, b, f); + allocated_bytes += b * size; + available_bytes += f * size; + pool_header_bytes += p * POOL_OVERHEAD; + quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size); + } + fputc('\n', stderr); + (void)printone("# times object malloc called", serialno); + + (void)printone("# arenas allocated total", ntimes_arena_allocated); + (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas); + (void)printone("# arenas highwater mark", narenas_highwater); + (void)printone("# arenas allocated current", narenas); + + PyOS_snprintf(buf, sizeof(buf), + "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena", + narenas, ARENA_SIZE); + (void)printone(buf, narenas * ARENA_SIZE); + + fputc('\n', stderr); + + total = printone("# bytes in allocated blocks", allocated_bytes); + total += printone("# bytes in available blocks", available_bytes); + + PyOS_snprintf(buf, sizeof(buf), + "%u unused pools * %d bytes", numfreepools, POOL_SIZE); + total += printone(buf, (size_t)numfreepools * POOL_SIZE); + + total += printone("# bytes lost to pool headers", pool_header_bytes); + total += printone("# bytes lost to quantization", quantization); + total += printone("# bytes lost to arena alignment", arena_alignment); + (void)printone("Total", total); +} + +#endif /* PYMALLOC_DEBUG */ + +#ifdef Py_USING_MEMORY_DEBUGGER +/* Make this function last so gcc won't inline it since the definition is + * after the reference. + */ +int +Py_ADDRESS_IN_RANGE(void *P, poolp pool) +{ + return pool->arenaindex < maxarenas && + (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE && + arenas[pool->arenaindex].address != 0; +} +#endif diff --git a/sys/src/cmd/python/Objects/rangeobject.c b/sys/src/cmd/python/Objects/rangeobject.c new file mode 100644 index 000000000..c48bee016 --- /dev/null +++ b/sys/src/cmd/python/Objects/rangeobject.c @@ -0,0 +1,301 @@ +/* Range object implementation */ + +#include "Python.h" + +typedef struct { + PyObject_HEAD + long start; + long step; + long len; +} rangeobject; + +/* Return number of items in range/xrange (lo, hi, step). step > 0 + * required. Return a value < 0 if & only if the true value is too + * large to fit in a signed long. + */ +static long +get_len_of_range(long lo, long hi, long step) +{ + /* ------------------------------------------------------------- + If lo >= hi, the range is empty. + Else if n values are in the range, the last one is + lo + (n-1)*step, which must be <= hi-1. Rearranging, + n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives + the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so + the RHS is non-negative and so truncation is the same as the + floor. Letting M be the largest positive long, the worst case + for the RHS numerator is hi=M, lo=-M-1, and then + hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough + precision to compute the RHS exactly. + ---------------------------------------------------------------*/ + long n = 0; + if (lo < hi) { + unsigned long uhi = (unsigned long)hi; + unsigned long ulo = (unsigned long)lo; + unsigned long diff = uhi - ulo - 1; + n = (long)(diff / (unsigned long)step + 1); + } + return n; +} + +static PyObject * +range_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + rangeobject *obj; + long ilow = 0, ihigh = 0, istep = 1; + long n; + + if (!_PyArg_NoKeywords("xrange()", kw)) + return NULL; + + if (PyTuple_Size(args) <= 1) { + if (!PyArg_ParseTuple(args, + "l;xrange() requires 1-3 int arguments", + &ihigh)) + return NULL; + } + else { + if (!PyArg_ParseTuple(args, + "ll|l;xrange() requires 1-3 int arguments", + &ilow, &ihigh, &istep)) + return NULL; + } + if (istep == 0) { + PyErr_SetString(PyExc_ValueError, "xrange() arg 3 must not be zero"); + return NULL; + } + if (istep > 0) + n = get_len_of_range(ilow, ihigh, istep); + else + n = get_len_of_range(ihigh, ilow, -istep); + if (n < 0) { + PyErr_SetString(PyExc_OverflowError, + "xrange() result has too many items"); + return NULL; + } + + obj = PyObject_New(rangeobject, &PyRange_Type); + if (obj == NULL) + return NULL; + obj->start = ilow; + obj->len = n; + obj->step = istep; + return (PyObject *) obj; +} + +PyDoc_STRVAR(range_doc, +"xrange([start,] stop[, step]) -> xrange object\n\ +\n\ +Like range(), but instead of returning a list, returns an object that\n\ +generates the numbers in the range on demand. For looping, this is \n\ +slightly faster than range() and more memory efficient."); + +static PyObject * +range_item(rangeobject *r, Py_ssize_t i) +{ + if (i < 0 || i >= r->len) { + PyErr_SetString(PyExc_IndexError, + "xrange object index out of range"); + return NULL; + } + return PyInt_FromSsize_t(r->start + (i % r->len) * r->step); +} + +static Py_ssize_t +range_length(rangeobject *r) +{ + return (Py_ssize_t)(r->len); +} + +static PyObject * +range_repr(rangeobject *r) +{ + PyObject *rtn; + + if (r->start == 0 && r->step == 1) + rtn = PyString_FromFormat("xrange(%ld)", + r->start + r->len * r->step); + + else if (r->step == 1) + rtn = PyString_FromFormat("xrange(%ld, %ld)", + r->start, + r->start + r->len * r->step); + + else + rtn = PyString_FromFormat("xrange(%ld, %ld, %ld)", + r->start, + r->start + r->len * r->step, + r->step); + return rtn; +} + +static PySequenceMethods range_as_sequence = { + (lenfunc)range_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)range_item, /* sq_item */ + 0, /* sq_slice */ +}; + +static PyObject * range_iter(PyObject *seq); +static PyObject * range_reverse(PyObject *seq); + +PyDoc_STRVAR(reverse_doc, +"Returns a reverse iterator."); + +static PyMethodDef range_methods[] = { + {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyTypeObject PyRange_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* Number of items for varobject */ + "xrange", /* Name of this type */ + sizeof(rangeobject), /* Basic object size */ + 0, /* Item size for varobject */ + (destructor)PyObject_Del, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)range_repr, /* tp_repr */ + 0, /* tp_as_number */ + &range_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + range_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + range_iter, /* tp_iter */ + 0, /* tp_iternext */ + range_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + range_new, /* tp_new */ +}; + +/*********************** Xrange Iterator **************************/ + +typedef struct { + PyObject_HEAD + long index; + long start; + long step; + long len; +} rangeiterobject; + +static PyObject * +rangeiter_next(rangeiterobject *r) +{ + if (r->index < r->len) + return PyInt_FromLong(r->start + (r->index++) * r->step); + return NULL; +} + +static PyObject * +rangeiter_len(rangeiterobject *r) +{ + return PyInt_FromLong(r->len - r->index); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef rangeiter_methods[] = { + {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject Pyrangeiter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "rangeiterator", /* tp_name */ + sizeof(rangeiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)PyObject_Del, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)rangeiter_next, /* tp_iternext */ + rangeiter_methods, /* tp_methods */ + 0, +}; + +static PyObject * +range_iter(PyObject *seq) +{ + rangeiterobject *it; + + if (!PyRange_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_New(rangeiterobject, &Pyrangeiter_Type); + if (it == NULL) + return NULL; + it->index = 0; + it->start = ((rangeobject *)seq)->start; + it->step = ((rangeobject *)seq)->step; + it->len = ((rangeobject *)seq)->len; + return (PyObject *)it; +} + +static PyObject * +range_reverse(PyObject *seq) +{ + rangeiterobject *it; + long start, step, len; + + if (!PyRange_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_New(rangeiterobject, &Pyrangeiter_Type); + if (it == NULL) + return NULL; + + start = ((rangeobject *)seq)->start; + step = ((rangeobject *)seq)->step; + len = ((rangeobject *)seq)->len; + + it->index = 0; + it->start = start + (len-1) * step; + it->step = -step; + it->len = len; + + return (PyObject *)it; +} diff --git a/sys/src/cmd/python/Objects/setobject.c b/sys/src/cmd/python/Objects/setobject.c new file mode 100644 index 000000000..b336fba7a --- /dev/null +++ b/sys/src/cmd/python/Objects/setobject.c @@ -0,0 +1,2312 @@ + +/* set object implementation + Written and maintained by Raymond D. Hettinger <python@rcn.com> + Derived from Lib/sets.py and Objects/dictobject.c. + + Copyright (c) 2003-6 Python Software Foundation. + All rights reserved. +*/ + +#include "Python.h" +#include "structmember.h" + +/* Set a key error with the specified argument, wrapping it in a + * tuple automatically so that tuple keys are not unpacked as the + * exception arguments. */ +static void +set_key_error(PyObject *arg) +{ + PyObject *tup; + tup = PyTuple_Pack(1, arg); + if (!tup) + return; /* caller will expect error to be set anyway */ + PyErr_SetObject(PyExc_KeyError, tup); + Py_DECREF(tup); +} + +/* This must be >= 1. */ +#define PERTURB_SHIFT 5 + +/* Object used as dummy key to fill deleted entries */ +static PyObject *dummy = NULL; /* Initialized by first call to make_new_set() */ + +#ifdef Py_REF_DEBUG +PyObject * +_PySet_Dummy(void) +{ + return dummy; +} +#endif + +#define INIT_NONZERO_SET_SLOTS(so) do { \ + (so)->table = (so)->smalltable; \ + (so)->mask = PySet_MINSIZE - 1; \ + (so)->hash = -1; \ + } while(0) + +#define EMPTY_TO_MINSIZE(so) do { \ + memset((so)->smalltable, 0, sizeof((so)->smalltable)); \ + (so)->used = (so)->fill = 0; \ + INIT_NONZERO_SET_SLOTS(so); \ + } while(0) + +/* Reuse scheme to save calls to malloc, free, and memset */ +#define MAXFREESETS 80 +static PySetObject *free_sets[MAXFREESETS]; +static int num_free_sets = 0; + +/* +The basic lookup function used by all operations. +This is based on Algorithm D from Knuth Vol. 3, Sec. 6.4. +Open addressing is preferred over chaining since the link overhead for +chaining would be substantial (100% with typical malloc overhead). + +The initial probe index is computed as hash mod the table size. Subsequent +probe indices are computed as explained in Objects/dictobject.c. + +All arithmetic on hash should ignore overflow. + +Unlike the dictionary implementation, the lookkey functions can return +NULL if the rich comparison returns an error. +*/ + +static setentry * +set_lookkey(PySetObject *so, PyObject *key, register long hash) +{ + register Py_ssize_t i; + register size_t perturb; + register setentry *freeslot; + register size_t mask = so->mask; + setentry *table = so->table; + register setentry *entry; + register int cmp; + PyObject *startkey; + + i = hash & mask; + entry = &table[i]; + if (entry->key == NULL || entry->key == key) + return entry; + + if (entry->key == dummy) + freeslot = entry; + else { + if (entry->hash == hash) { + startkey = entry->key; + cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + if (cmp < 0) + return NULL; + if (table == so->table && entry->key == startkey) { + if (cmp > 0) + return entry; + } + else { + /* The compare did major nasty stuff to the + * set: start over. + */ + return set_lookkey(so, key, hash); + } + } + freeslot = NULL; + } + + /* In the loop, key == dummy is by far (factor of 100s) the + least likely outcome, so test for that last. */ + for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + entry = &table[i & mask]; + if (entry->key == NULL) { + if (freeslot != NULL) + entry = freeslot; + break; + } + if (entry->key == key) + break; + if (entry->hash == hash && entry->key != dummy) { + startkey = entry->key; + cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); + if (cmp < 0) + return NULL; + if (table == so->table && entry->key == startkey) { + if (cmp > 0) + break; + } + else { + /* The compare did major nasty stuff to the + * set: start over. + */ + return set_lookkey(so, key, hash); + } + } + else if (entry->key == dummy && freeslot == NULL) + freeslot = entry; + } + return entry; +} + +/* + * Hacked up version of set_lookkey which can assume keys are always strings; + * This means we can always use _PyString_Eq directly and not have to check to + * see if the comparison altered the table. + */ +static setentry * +set_lookkey_string(PySetObject *so, PyObject *key, register long hash) +{ + register Py_ssize_t i; + register size_t perturb; + register setentry *freeslot; + register size_t mask = so->mask; + setentry *table = so->table; + register setentry *entry; + + /* Make sure this function doesn't have to handle non-string keys, + including subclasses of str; e.g., one reason to subclass + strings is to override __eq__, and for speed we don't cater to + that here. */ + if (!PyString_CheckExact(key)) { + so->lookup = set_lookkey; + return set_lookkey(so, key, hash); + } + i = hash & mask; + entry = &table[i]; + if (entry->key == NULL || entry->key == key) + return entry; + if (entry->key == dummy) + freeslot = entry; + else { + if (entry->hash == hash && _PyString_Eq(entry->key, key)) + return entry; + freeslot = NULL; + } + + /* In the loop, key == dummy is by far (factor of 100s) the + least likely outcome, so test for that last. */ + for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + entry = &table[i & mask]; + if (entry->key == NULL) + return freeslot == NULL ? entry : freeslot; + if (entry->key == key + || (entry->hash == hash + && entry->key != dummy + && _PyString_Eq(entry->key, key))) + return entry; + if (entry->key == dummy && freeslot == NULL) + freeslot = entry; + } + assert(0); /* NOT REACHED */ + return 0; +} + +/* +Internal routine to insert a new key into the table. +Used by the public insert routine. +Eats a reference to key. +*/ +static int +set_insert_key(register PySetObject *so, PyObject *key, long hash) +{ + register setentry *entry; + typedef setentry *(*lookupfunc)(PySetObject *, PyObject *, long); + + assert(so->lookup != NULL); + entry = so->lookup(so, key, hash); + if (entry == NULL) + return -1; + if (entry->key == NULL) { + /* UNUSED */ + so->fill++; + entry->key = key; + entry->hash = hash; + so->used++; + } else if (entry->key == dummy) { + /* DUMMY */ + entry->key = key; + entry->hash = hash; + so->used++; + Py_DECREF(dummy); + } else { + /* ACTIVE */ + Py_DECREF(key); + } + return 0; +} + +/* +Internal routine used by set_table_resize() to insert an item which is +known to be absent from the set. This routine also assumes that +the set contains no deleted entries. Besides the performance benefit, +using set_insert_clean() in set_table_resize() is dangerous (SF bug #1456209). +Note that no refcounts are changed by this routine; if needed, the caller +is responsible for incref'ing `key`. +*/ +static void +set_insert_clean(register PySetObject *so, PyObject *key, long hash) +{ + register size_t i; + register size_t perturb; + register size_t mask = (size_t)so->mask; + setentry *table = so->table; + register setentry *entry; + + i = hash & mask; + entry = &table[i]; + for (perturb = hash; entry->key != NULL; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + entry = &table[i & mask]; + } + so->fill++; + entry->key = key; + entry->hash = hash; + so->used++; +} + +/* +Restructure the table by allocating a new table and reinserting all +keys again. When entries have been deleted, the new table may +actually be smaller than the old one. +*/ +static int +set_table_resize(PySetObject *so, Py_ssize_t minused) +{ + Py_ssize_t newsize; + setentry *oldtable, *newtable, *entry; + Py_ssize_t i; + int is_oldtable_malloced; + setentry small_copy[PySet_MINSIZE]; + + assert(minused >= 0); + + /* Find the smallest table size > minused. */ + for (newsize = PySet_MINSIZE; + newsize <= minused && newsize > 0; + newsize <<= 1) + ; + if (newsize <= 0) { + PyErr_NoMemory(); + return -1; + } + + /* Get space for a new table. */ + oldtable = so->table; + assert(oldtable != NULL); + is_oldtable_malloced = oldtable != so->smalltable; + + if (newsize == PySet_MINSIZE) { + /* A large table is shrinking, or we can't get any smaller. */ + newtable = so->smalltable; + if (newtable == oldtable) { + if (so->fill == so->used) { + /* No dummies, so no point doing anything. */ + return 0; + } + /* We're not going to resize it, but rebuild the + table anyway to purge old dummy entries. + Subtle: This is *necessary* if fill==size, + as set_lookkey needs at least one virgin slot to + terminate failing searches. If fill < size, it's + merely desirable, as dummies slow searches. */ + assert(so->fill > so->used); + memcpy(small_copy, oldtable, sizeof(small_copy)); + oldtable = small_copy; + } + } + else { + newtable = PyMem_NEW(setentry, newsize); + if (newtable == NULL) { + PyErr_NoMemory(); + return -1; + } + } + + /* Make the set empty, using the new table. */ + assert(newtable != oldtable); + so->table = newtable; + so->mask = newsize - 1; + memset(newtable, 0, sizeof(setentry) * newsize); + so->used = 0; + i = so->fill; + so->fill = 0; + + /* Copy the data over; this is refcount-neutral for active entries; + dummy entries aren't copied over, of course */ + for (entry = oldtable; i > 0; entry++) { + if (entry->key == NULL) { + /* UNUSED */ + ; + } else if (entry->key == dummy) { + /* DUMMY */ + --i; + assert(entry->key == dummy); + Py_DECREF(entry->key); + } else { + /* ACTIVE */ + --i; + set_insert_clean(so, entry->key, entry->hash); + } + } + + if (is_oldtable_malloced) + PyMem_DEL(oldtable); + return 0; +} + +/* CAUTION: set_add_key/entry() must guarantee it won't resize the table */ + +static int +set_add_entry(register PySetObject *so, setentry *entry) +{ + register Py_ssize_t n_used; + + assert(so->fill <= so->mask); /* at least one empty slot */ + n_used = so->used; + Py_INCREF(entry->key); + if (set_insert_key(so, entry->key, entry->hash) == -1) { + Py_DECREF(entry->key); + return -1; + } + if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) + return 0; + return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); +} + +static int +set_add_key(register PySetObject *so, PyObject *key) +{ + register long hash; + register Py_ssize_t n_used; + + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + assert(so->fill <= so->mask); /* at least one empty slot */ + n_used = so->used; + Py_INCREF(key); + if (set_insert_key(so, key, hash) == -1) { + Py_DECREF(key); + return -1; + } + if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) + return 0; + return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); +} + +#define DISCARD_NOTFOUND 0 +#define DISCARD_FOUND 1 + +static int +set_discard_entry(PySetObject *so, setentry *oldentry) +{ register setentry *entry; + PyObject *old_key; + + entry = (so->lookup)(so, oldentry->key, oldentry->hash); + if (entry == NULL) + return -1; + if (entry->key == NULL || entry->key == dummy) + return DISCARD_NOTFOUND; + old_key = entry->key; + Py_INCREF(dummy); + entry->key = dummy; + so->used--; + Py_DECREF(old_key); + return DISCARD_FOUND; +} + +static int +set_discard_key(PySetObject *so, PyObject *key) +{ + register long hash; + register setentry *entry; + PyObject *old_key; + + assert (PyAnySet_Check(so)); + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + entry = (so->lookup)(so, key, hash); + if (entry == NULL) + return -1; + if (entry->key == NULL || entry->key == dummy) + return DISCARD_NOTFOUND; + old_key = entry->key; + Py_INCREF(dummy); + entry->key = dummy; + so->used--; + Py_DECREF(old_key); + return DISCARD_FOUND; +} + +static int +set_clear_internal(PySetObject *so) +{ + setentry *entry, *table; + int table_is_malloced; + Py_ssize_t fill; + setentry small_copy[PySet_MINSIZE]; +#ifdef Py_DEBUG + Py_ssize_t i, n; + assert (PyAnySet_Check(so)); + + n = so->mask + 1; + i = 0; +#endif + + table = so->table; + assert(table != NULL); + table_is_malloced = table != so->smalltable; + + /* This is delicate. During the process of clearing the set, + * decrefs can cause the set to mutate. To avoid fatal confusion + * (voice of experience), we have to make the set empty before + * clearing the slots, and never refer to anything via so->ref while + * clearing. + */ + fill = so->fill; + if (table_is_malloced) + EMPTY_TO_MINSIZE(so); + + else if (fill > 0) { + /* It's a small table with something that needs to be cleared. + * Afraid the only safe way is to copy the set entries into + * another small table first. + */ + memcpy(small_copy, table, sizeof(small_copy)); + table = small_copy; + EMPTY_TO_MINSIZE(so); + } + /* else it's a small table that's already empty */ + + /* Now we can finally clear things. If C had refcounts, we could + * assert that the refcount on table is 1 now, i.e. that this function + * has unique access to it, so decref side-effects can't alter it. + */ + for (entry = table; fill > 0; ++entry) { +#ifdef Py_DEBUG + assert(i < n); + ++i; +#endif + if (entry->key) { + --fill; + Py_DECREF(entry->key); + } +#ifdef Py_DEBUG + else + assert(entry->key == NULL); +#endif + } + + if (table_is_malloced) + PyMem_DEL(table); + return 0; +} + +/* + * Iterate over a set table. Use like so: + * + * Py_ssize_t pos; + * setentry *entry; + * pos = 0; # important! pos should not otherwise be changed by you + * while (set_next(yourset, &pos, &entry)) { + * Refer to borrowed reference in entry->key. + * } + * + * CAUTION: In general, it isn't safe to use set_next in a loop that + * mutates the table. + */ +static int +set_next(PySetObject *so, Py_ssize_t *pos_ptr, setentry **entry_ptr) +{ + Py_ssize_t i; + Py_ssize_t mask; + register setentry *table; + + assert (PyAnySet_Check(so)); + i = *pos_ptr; + assert(i >= 0); + table = so->table; + mask = so->mask; + while (i <= mask && (table[i].key == NULL || table[i].key == dummy)) + i++; + *pos_ptr = i+1; + if (i > mask) + return 0; + assert(table[i].key != NULL); + *entry_ptr = &table[i]; + return 1; +} + +static void +set_dealloc(PySetObject *so) +{ + register setentry *entry; + Py_ssize_t fill = so->fill; + PyObject_GC_UnTrack(so); + Py_TRASHCAN_SAFE_BEGIN(so) + if (so->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) so); + + for (entry = so->table; fill > 0; entry++) { + if (entry->key) { + --fill; + Py_DECREF(entry->key); + } + } + if (so->table != so->smalltable) + PyMem_DEL(so->table); + if (num_free_sets < MAXFREESETS && PyAnySet_CheckExact(so)) + free_sets[num_free_sets++] = so; + else + so->ob_type->tp_free(so); + Py_TRASHCAN_SAFE_END(so) +} + +static int +set_tp_print(PySetObject *so, FILE *fp, int flags) +{ + setentry *entry; + Py_ssize_t pos=0; + char *emit = ""; /* No separator emitted on first pass */ + char *separator = ", "; + int status = Py_ReprEnter((PyObject*)so); + + if (status != 0) { + if (status < 0) + return status; + fprintf(fp, "%s(...)", so->ob_type->tp_name); + return 0; + } + + fprintf(fp, "%s([", so->ob_type->tp_name); + while (set_next(so, &pos, &entry)) { + fputs(emit, fp); + emit = separator; + if (PyObject_Print(entry->key, fp, 0) != 0) { + Py_ReprLeave((PyObject*)so); + return -1; + } + } + fputs("])", fp); + Py_ReprLeave((PyObject*)so); + return 0; +} + +static PyObject * +set_repr(PySetObject *so) +{ + PyObject *keys, *result=NULL, *listrepr; + int status = Py_ReprEnter((PyObject*)so); + + if (status != 0) { + if (status < 0) + return NULL; + return PyString_FromFormat("%s(...)", so->ob_type->tp_name); + } + + keys = PySequence_List((PyObject *)so); + if (keys == NULL) + goto done; + listrepr = PyObject_Repr(keys); + Py_DECREF(keys); + if (listrepr == NULL) + goto done; + + result = PyString_FromFormat("%s(%s)", so->ob_type->tp_name, + PyString_AS_STRING(listrepr)); + Py_DECREF(listrepr); +done: + Py_ReprLeave((PyObject*)so); + return result; +} + +static Py_ssize_t +set_len(PyObject *so) +{ + return ((PySetObject *)so)->used; +} + +static int +set_merge(PySetObject *so, PyObject *otherset) +{ + PySetObject *other; + register Py_ssize_t i; + register setentry *entry; + + assert (PyAnySet_Check(so)); + assert (PyAnySet_Check(otherset)); + + other = (PySetObject*)otherset; + if (other == so || other->used == 0) + /* a.update(a) or a.update({}); nothing to do */ + return 0; + /* Do one big resize at the start, rather than + * incrementally resizing as we insert new keys. Expect + * that there will be no (or few) overlapping keys. + */ + if ((so->fill + other->used)*3 >= (so->mask+1)*2) { + if (set_table_resize(so, (so->used + other->used)*2) != 0) + return -1; + } + for (i = 0; i <= other->mask; i++) { + entry = &other->table[i]; + if (entry->key != NULL && + entry->key != dummy) { + Py_INCREF(entry->key); + if (set_insert_key(so, entry->key, entry->hash) == -1) { + Py_DECREF(entry->key); + return -1; + } + } + } + return 0; +} + +static int +set_contains_key(PySetObject *so, PyObject *key) +{ + long hash; + setentry *entry; + + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { + hash = PyObject_Hash(key); + if (hash == -1) + return -1; + } + entry = (so->lookup)(so, key, hash); + if (entry == NULL) + return -1; + key = entry->key; + return key != NULL && key != dummy; +} + +static int +set_contains_entry(PySetObject *so, setentry *entry) +{ + PyObject *key; + setentry *lu_entry; + + lu_entry = (so->lookup)(so, entry->key, entry->hash); + if (lu_entry == NULL) + return -1; + key = lu_entry->key; + return key != NULL && key != dummy; +} + +static PyObject * +set_pop(PySetObject *so) +{ + register Py_ssize_t i = 0; + register setentry *entry; + PyObject *key; + + assert (PyAnySet_Check(so)); + if (so->used == 0) { + PyErr_SetString(PyExc_KeyError, "pop from an empty set"); + return NULL; + } + + /* Set entry to "the first" unused or dummy set entry. We abuse + * the hash field of slot 0 to hold a search finger: + * If slot 0 has a value, use slot 0. + * Else slot 0 is being used to hold a search finger, + * and we use its hash value as the first index to look. + */ + entry = &so->table[0]; + if (entry->key == NULL || entry->key == dummy) { + i = entry->hash; + /* The hash field may be a real hash value, or it may be a + * legit search finger, or it may be a once-legit search + * finger that's out of bounds now because it wrapped around + * or the table shrunk -- simply make sure it's in bounds now. + */ + if (i > so->mask || i < 1) + i = 1; /* skip slot 0 */ + while ((entry = &so->table[i])->key == NULL || entry->key==dummy) { + i++; + if (i > so->mask) + i = 1; + } + } + key = entry->key; + Py_INCREF(dummy); + entry->key = dummy; + so->used--; + so->table[0].hash = i + 1; /* next place to start */ + return key; +} + +PyDoc_STRVAR(pop_doc, "Remove and return an arbitrary set element."); + +static int +set_traverse(PySetObject *so, visitproc visit, void *arg) +{ + Py_ssize_t pos = 0; + setentry *entry; + + while (set_next(so, &pos, &entry)) + Py_VISIT(entry->key); + return 0; +} + +static long +frozenset_hash(PyObject *self) +{ + PySetObject *so = (PySetObject *)self; + long h, hash = 1927868237L; + setentry *entry; + Py_ssize_t pos = 0; + + if (so->hash != -1) + return so->hash; + + hash *= PySet_GET_SIZE(self) + 1; + while (set_next(so, &pos, &entry)) { + /* Work to increase the bit dispersion for closely spaced hash + values. The is important because some use cases have many + combinations of a small number of elements with nearby + hashes so that many distinct combinations collapse to only + a handful of distinct hash values. */ + h = entry->hash; + hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; + } + hash = hash * 69069L + 907133923L; + if (hash == -1) + hash = 590923713L; + so->hash = hash; + return hash; +} + +static long +set_nohash(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "set objects are unhashable"); + return -1; +} + +/***** Set iterator type ***********************************************/ + +typedef struct { + PyObject_HEAD + PySetObject *si_set; /* Set to NULL when iterator is exhausted */ + Py_ssize_t si_used; + Py_ssize_t si_pos; + Py_ssize_t len; +} setiterobject; + +static void +setiter_dealloc(setiterobject *si) +{ + Py_XDECREF(si->si_set); + PyObject_Del(si); +} + +static PyObject * +setiter_len(setiterobject *si) +{ + Py_ssize_t len = 0; + if (si->si_set != NULL && si->si_used == si->si_set->used) + len = si->len; + return PyInt_FromLong(len); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef setiter_methods[] = { + {"__length_hint__", (PyCFunction)setiter_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject *setiter_iternext(setiterobject *si) +{ + PyObject *key; + register Py_ssize_t i, mask; + register setentry *entry; + PySetObject *so = si->si_set; + + if (so == NULL) + return NULL; + assert (PyAnySet_Check(so)); + + if (si->si_used != so->used) { + PyErr_SetString(PyExc_RuntimeError, + "Set changed size during iteration"); + si->si_used = -1; /* Make this state sticky */ + return NULL; + } + + i = si->si_pos; + assert(i>=0); + entry = so->table; + mask = so->mask; + while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) + i++; + si->si_pos = i+1; + if (i > mask) + goto fail; + si->len--; + key = entry[i].key; + Py_INCREF(key); + return key; + +fail: + Py_DECREF(so); + si->si_set = NULL; + return NULL; +} + +static PyTypeObject PySetIter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "setiterator", /* tp_name */ + sizeof(setiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)setiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)setiter_iternext, /* tp_iternext */ + setiter_methods, /* tp_methods */ + 0, +}; + +static PyObject * +set_iter(PySetObject *so) +{ + setiterobject *si = PyObject_New(setiterobject, &PySetIter_Type); + if (si == NULL) + return NULL; + Py_INCREF(so); + si->si_set = so; + si->si_used = so->used; + si->si_pos = 0; + si->len = so->used; + return (PyObject *)si; +} + +static int +set_update_internal(PySetObject *so, PyObject *other) +{ + PyObject *key, *it; + + if (PyAnySet_Check(other)) + return set_merge(so, other); + + if (PyDict_CheckExact(other)) { + PyObject *value; + Py_ssize_t pos = 0; + long hash; + Py_ssize_t dictsize = PyDict_Size(other); + + /* Do one big resize at the start, rather than + * incrementally resizing as we insert new keys. Expect + * that there will be no (or few) overlapping keys. + */ + if (dictsize == -1) + return -1; + if ((so->fill + dictsize)*3 >= (so->mask+1)*2) { + if (set_table_resize(so, (so->used + dictsize)*2) != 0) + return -1; + } + while (_PyDict_Next(other, &pos, &key, &value, &hash)) { + setentry an_entry; + + an_entry.hash = hash; + an_entry.key = key; + if (set_add_entry(so, &an_entry) == -1) + return -1; + } + return 0; + } + + it = PyObject_GetIter(other); + if (it == NULL) + return -1; + + while ((key = PyIter_Next(it)) != NULL) { + if (set_add_key(so, key) == -1) { + Py_DECREF(it); + Py_DECREF(key); + return -1; + } + Py_DECREF(key); + } + Py_DECREF(it); + if (PyErr_Occurred()) + return -1; + return 0; +} + +static PyObject * +set_update(PySetObject *so, PyObject *other) +{ + if (set_update_internal(so, other) == -1) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(update_doc, +"Update a set with the union of itself and another."); + +static PyObject * +make_new_set(PyTypeObject *type, PyObject *iterable) +{ + register PySetObject *so = NULL; + + if (dummy == NULL) { /* Auto-initialize dummy */ + dummy = PyString_FromString("<dummy key>"); + if (dummy == NULL) + return NULL; + } + + /* create PySetObject structure */ + if (num_free_sets && + (type == &PySet_Type || type == &PyFrozenSet_Type)) { + so = free_sets[--num_free_sets]; + assert (so != NULL && PyAnySet_CheckExact(so)); + so->ob_type = type; + _Py_NewReference((PyObject *)so); + EMPTY_TO_MINSIZE(so); + PyObject_GC_Track(so); + } else { + so = (PySetObject *)type->tp_alloc(type, 0); + if (so == NULL) + return NULL; + /* tp_alloc has already zeroed the structure */ + assert(so->table == NULL && so->fill == 0 && so->used == 0); + INIT_NONZERO_SET_SLOTS(so); + } + + so->lookup = set_lookkey_string; + so->weakreflist = NULL; + + if (iterable != NULL) { + if (set_update_internal(so, iterable) == -1) { + Py_DECREF(so); + return NULL; + } + } + + return (PyObject *)so; +} + +/* The empty frozenset is a singleton */ +static PyObject *emptyfrozenset = NULL; + +static PyObject * +frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *iterable = NULL, *result; + + if (type == &PyFrozenSet_Type && !_PyArg_NoKeywords("frozenset()", kwds)) + return NULL; + + if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) + return NULL; + + if (type != &PyFrozenSet_Type) + return make_new_set(type, iterable); + + if (iterable != NULL) { + /* frozenset(f) is idempotent */ + if (PyFrozenSet_CheckExact(iterable)) { + Py_INCREF(iterable); + return iterable; + } + result = make_new_set(type, iterable); + if (result == NULL || PySet_GET_SIZE(result)) + return result; + Py_DECREF(result); + } + /* The empty frozenset is a singleton */ + if (emptyfrozenset == NULL) + emptyfrozenset = make_new_set(type, NULL); + Py_XINCREF(emptyfrozenset); + return emptyfrozenset; +} + +void +PySet_Fini(void) +{ + PySetObject *so; + + while (num_free_sets) { + num_free_sets--; + so = free_sets[num_free_sets]; + PyObject_GC_Del(so); + } + Py_CLEAR(dummy); + Py_CLEAR(emptyfrozenset); +} + +static PyObject * +set_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + if (type == &PySet_Type && !_PyArg_NoKeywords("set()", kwds)) + return NULL; + + return make_new_set(type, NULL); +} + +/* set_swap_bodies() switches the contents of any two sets by moving their + internal data pointers and, if needed, copying the internal smalltables. + Semantically equivalent to: + + t=set(a); a.clear(); a.update(b); b.clear(); b.update(t); del t + + The function always succeeds and it leaves both objects in a stable state. + Useful for creating temporary frozensets from sets for membership testing + in __contains__(), discard(), and remove(). Also useful for operations + that update in-place (by allowing an intermediate result to be swapped + into one of the original inputs). +*/ + +static void +set_swap_bodies(PySetObject *a, PySetObject *b) +{ + Py_ssize_t t; + setentry *u; + setentry *(*f)(PySetObject *so, PyObject *key, long hash); + setentry tab[PySet_MINSIZE]; + long h; + + t = a->fill; a->fill = b->fill; b->fill = t; + t = a->used; a->used = b->used; b->used = t; + t = a->mask; a->mask = b->mask; b->mask = t; + + u = a->table; + if (a->table == a->smalltable) + u = b->smalltable; + a->table = b->table; + if (b->table == b->smalltable) + a->table = a->smalltable; + b->table = u; + + f = a->lookup; a->lookup = b->lookup; b->lookup = f; + + if (a->table == a->smalltable || b->table == b->smalltable) { + memcpy(tab, a->smalltable, sizeof(tab)); + memcpy(a->smalltable, b->smalltable, sizeof(tab)); + memcpy(b->smalltable, tab, sizeof(tab)); + } + + if (PyType_IsSubtype(a->ob_type, &PyFrozenSet_Type) && + PyType_IsSubtype(b->ob_type, &PyFrozenSet_Type)) { + h = a->hash; a->hash = b->hash; b->hash = h; + } else { + a->hash = -1; + b->hash = -1; + } +} + +static PyObject * +set_copy(PySetObject *so) +{ + return make_new_set(so->ob_type, (PyObject *)so); +} + +static PyObject * +frozenset_copy(PySetObject *so) +{ + if (PyFrozenSet_CheckExact(so)) { + Py_INCREF(so); + return (PyObject *)so; + } + return set_copy(so); +} + +PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set."); + +static PyObject * +set_clear(PySetObject *so) +{ + set_clear_internal(so); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); + +static PyObject * +set_union(PySetObject *so, PyObject *other) +{ + PySetObject *result; + + result = (PySetObject *)set_copy(so); + if (result == NULL) + return NULL; + if ((PyObject *)so == other) + return (PyObject *)result; + if (set_update_internal(result, other) == -1) { + Py_DECREF(result); + return NULL; + } + return (PyObject *)result; +} + +PyDoc_STRVAR(union_doc, + "Return the union of two sets as a new set.\n\ +\n\ +(i.e. all elements that are in either set.)"); + +static PyObject * +set_or(PySetObject *so, PyObject *other) +{ + if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return set_union(so, other); +} + +static PyObject * +set_ior(PySetObject *so, PyObject *other) +{ + if (!PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (set_update_internal(so, other) == -1) + return NULL; + Py_INCREF(so); + return (PyObject *)so; +} + +static PyObject * +set_intersection(PySetObject *so, PyObject *other) +{ + PySetObject *result; + PyObject *key, *it, *tmp; + + if ((PyObject *)so == other) + return set_copy(so); + + result = (PySetObject *)make_new_set(so->ob_type, NULL); + if (result == NULL) + return NULL; + + if (PyAnySet_Check(other)) { + Py_ssize_t pos = 0; + setentry *entry; + + if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) { + tmp = (PyObject *)so; + so = (PySetObject *)other; + other = tmp; + } + + while (set_next((PySetObject *)other, &pos, &entry)) { + int rv = set_contains_entry(so, entry); + if (rv == -1) { + Py_DECREF(result); + return NULL; + } + if (rv) { + if (set_add_entry(result, entry) == -1) { + Py_DECREF(result); + return NULL; + } + } + } + return (PyObject *)result; + } + + it = PyObject_GetIter(other); + if (it == NULL) { + Py_DECREF(result); + return NULL; + } + + while ((key = PyIter_Next(it)) != NULL) { + int rv; + setentry entry; + long hash = PyObject_Hash(key); + + if (hash == -1) { + Py_DECREF(it); + Py_DECREF(result); + Py_DECREF(key); + return NULL; + } + entry.hash = hash; + entry.key = key; + rv = set_contains_entry(so, &entry); + if (rv == -1) { + Py_DECREF(it); + Py_DECREF(result); + Py_DECREF(key); + return NULL; + } + if (rv) { + if (set_add_entry(result, &entry) == -1) { + Py_DECREF(it); + Py_DECREF(result); + Py_DECREF(key); + return NULL; + } + } + Py_DECREF(key); + } + Py_DECREF(it); + if (PyErr_Occurred()) { + Py_DECREF(result); + return NULL; + } + return (PyObject *)result; +} + +PyDoc_STRVAR(intersection_doc, +"Return the intersection of two sets as a new set.\n\ +\n\ +(i.e. all elements that are in both sets.)"); + +static PyObject * +set_intersection_update(PySetObject *so, PyObject *other) +{ + PyObject *tmp; + + tmp = set_intersection(so, other); + if (tmp == NULL) + return NULL; + set_swap_bodies(so, (PySetObject *)tmp); + Py_DECREF(tmp); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(intersection_update_doc, +"Update a set with the intersection of itself and another."); + +static PyObject * +set_and(PySetObject *so, PyObject *other) +{ + if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return set_intersection(so, other); +} + +static PyObject * +set_iand(PySetObject *so, PyObject *other) +{ + PyObject *result; + + if (!PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + result = set_intersection_update(so, other); + if (result == NULL) + return NULL; + Py_DECREF(result); + Py_INCREF(so); + return (PyObject *)so; +} + +static int +set_difference_update_internal(PySetObject *so, PyObject *other) +{ + if ((PyObject *)so == other) + return set_clear_internal(so); + + if (PyAnySet_Check(other)) { + setentry *entry; + Py_ssize_t pos = 0; + + while (set_next((PySetObject *)other, &pos, &entry)) + if (set_discard_entry(so, entry) == -1) + return -1; + } else { + PyObject *key, *it; + it = PyObject_GetIter(other); + if (it == NULL) + return -1; + + while ((key = PyIter_Next(it)) != NULL) { + if (set_discard_key(so, key) == -1) { + Py_DECREF(it); + Py_DECREF(key); + return -1; + } + Py_DECREF(key); + } + Py_DECREF(it); + if (PyErr_Occurred()) + return -1; + } + /* If more than 1/5 are dummies, then resize them away. */ + if ((so->fill - so->used) * 5 < so->mask) + return 0; + return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); +} + +static PyObject * +set_difference_update(PySetObject *so, PyObject *other) +{ + if (set_difference_update_internal(so, other) != -1) + Py_RETURN_NONE; + return NULL; +} + +PyDoc_STRVAR(difference_update_doc, +"Remove all elements of another set from this set."); + +static PyObject * +set_difference(PySetObject *so, PyObject *other) +{ + PyObject *result; + setentry *entry; + Py_ssize_t pos = 0; + + if (!PyAnySet_Check(other) && !PyDict_CheckExact(other)) { + result = set_copy(so); + if (result == NULL) + return NULL; + if (set_difference_update_internal((PySetObject *)result, other) != -1) + return result; + Py_DECREF(result); + return NULL; + } + + result = make_new_set(so->ob_type, NULL); + if (result == NULL) + return NULL; + + if (PyDict_CheckExact(other)) { + while (set_next(so, &pos, &entry)) { + setentry entrycopy; + entrycopy.hash = entry->hash; + entrycopy.key = entry->key; + if (!_PyDict_Contains(other, entry->key, entry->hash)) { + if (set_add_entry((PySetObject *)result, &entrycopy) == -1) { + Py_DECREF(result); + return NULL; + } + } + } + return result; + } + + while (set_next(so, &pos, &entry)) { + int rv = set_contains_entry((PySetObject *)other, entry); + if (rv == -1) { + Py_DECREF(result); + return NULL; + } + if (!rv) { + if (set_add_entry((PySetObject *)result, entry) == -1) { + Py_DECREF(result); + return NULL; + } + } + } + return result; +} + +PyDoc_STRVAR(difference_doc, +"Return the difference of two sets as a new set.\n\ +\n\ +(i.e. all elements that are in this set but not the other.)"); +static PyObject * +set_sub(PySetObject *so, PyObject *other) +{ + if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return set_difference(so, other); +} + +static PyObject * +set_isub(PySetObject *so, PyObject *other) +{ + PyObject *result; + + if (!PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + result = set_difference_update(so, other); + if (result == NULL) + return NULL; + Py_DECREF(result); + Py_INCREF(so); + return (PyObject *)so; +} + +static PyObject * +set_symmetric_difference_update(PySetObject *so, PyObject *other) +{ + PySetObject *otherset; + PyObject *key; + Py_ssize_t pos = 0; + setentry *entry; + + if ((PyObject *)so == other) + return set_clear(so); + + if (PyDict_CheckExact(other)) { + PyObject *value; + int rv; + long hash; + while (_PyDict_Next(other, &pos, &key, &value, &hash)) { + setentry an_entry; + + an_entry.hash = hash; + an_entry.key = key; + rv = set_discard_entry(so, &an_entry); + if (rv == -1) + return NULL; + if (rv == DISCARD_NOTFOUND) { + if (set_add_entry(so, &an_entry) == -1) + return NULL; + } + } + Py_RETURN_NONE; + } + + if (PyAnySet_Check(other)) { + Py_INCREF(other); + otherset = (PySetObject *)other; + } else { + otherset = (PySetObject *)make_new_set(so->ob_type, other); + if (otherset == NULL) + return NULL; + } + + while (set_next(otherset, &pos, &entry)) { + int rv = set_discard_entry(so, entry); + if (rv == -1) { + Py_DECREF(otherset); + return NULL; + } + if (rv == DISCARD_NOTFOUND) { + if (set_add_entry(so, entry) == -1) { + Py_DECREF(otherset); + return NULL; + } + } + } + Py_DECREF(otherset); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(symmetric_difference_update_doc, +"Update a set with the symmetric difference of itself and another."); + +static PyObject * +set_symmetric_difference(PySetObject *so, PyObject *other) +{ + PyObject *rv; + PySetObject *otherset; + + otherset = (PySetObject *)make_new_set(so->ob_type, other); + if (otherset == NULL) + return NULL; + rv = set_symmetric_difference_update(otherset, (PyObject *)so); + if (rv == NULL) + return NULL; + Py_DECREF(rv); + return (PyObject *)otherset; +} + +PyDoc_STRVAR(symmetric_difference_doc, +"Return the symmetric difference of two sets as a new set.\n\ +\n\ +(i.e. all elements that are in exactly one of the sets.)"); + +static PyObject * +set_xor(PySetObject *so, PyObject *other) +{ + if (!PyAnySet_Check(so) || !PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return set_symmetric_difference(so, other); +} + +static PyObject * +set_ixor(PySetObject *so, PyObject *other) +{ + PyObject *result; + + if (!PyAnySet_Check(other)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + result = set_symmetric_difference_update(so, other); + if (result == NULL) + return NULL; + Py_DECREF(result); + Py_INCREF(so); + return (PyObject *)so; +} + +static PyObject * +set_issubset(PySetObject *so, PyObject *other) +{ + setentry *entry; + Py_ssize_t pos = 0; + + if (!PyAnySet_Check(other)) { + PyObject *tmp, *result; + tmp = make_new_set(&PySet_Type, other); + if (tmp == NULL) + return NULL; + result = set_issubset(so, tmp); + Py_DECREF(tmp); + return result; + } + if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other)) + Py_RETURN_FALSE; + + while (set_next(so, &pos, &entry)) { + int rv = set_contains_entry((PySetObject *)other, entry); + if (rv == -1) + return NULL; + if (!rv) + Py_RETURN_FALSE; + } + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(issubset_doc, "Report whether another set contains this set."); + +static PyObject * +set_issuperset(PySetObject *so, PyObject *other) +{ + PyObject *tmp, *result; + + if (!PyAnySet_Check(other)) { + tmp = make_new_set(&PySet_Type, other); + if (tmp == NULL) + return NULL; + result = set_issuperset(so, tmp); + Py_DECREF(tmp); + return result; + } + return set_issubset((PySetObject *)other, (PyObject *)so); +} + +PyDoc_STRVAR(issuperset_doc, "Report whether this set contains another set."); + +static PyObject * +set_richcompare(PySetObject *v, PyObject *w, int op) +{ + PyObject *r1, *r2; + + if(!PyAnySet_Check(w)) { + if (op == Py_EQ) + Py_RETURN_FALSE; + if (op == Py_NE) + Py_RETURN_TRUE; + PyErr_SetString(PyExc_TypeError, "can only compare to a set"); + return NULL; + } + switch (op) { + case Py_EQ: + if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w)) + Py_RETURN_FALSE; + if (v->hash != -1 && + ((PySetObject *)w)->hash != -1 && + v->hash != ((PySetObject *)w)->hash) + Py_RETURN_FALSE; + return set_issubset(v, w); + case Py_NE: + r1 = set_richcompare(v, w, Py_EQ); + if (r1 == NULL) + return NULL; + r2 = PyBool_FromLong(PyObject_Not(r1)); + Py_DECREF(r1); + return r2; + case Py_LE: + return set_issubset(v, w); + case Py_GE: + return set_issuperset(v, w); + case Py_LT: + if (PySet_GET_SIZE(v) >= PySet_GET_SIZE(w)) + Py_RETURN_FALSE; + return set_issubset(v, w); + case Py_GT: + if (PySet_GET_SIZE(v) <= PySet_GET_SIZE(w)) + Py_RETURN_FALSE; + return set_issuperset(v, w); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static int +set_nocmp(PyObject *self, PyObject *other) +{ + PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()"); + return -1; +} + +static PyObject * +set_add(PySetObject *so, PyObject *key) +{ + if (set_add_key(so, key) == -1) + return NULL; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(add_doc, +"Add an element to a set.\n\ +\n\ +This has no effect if the element is already present."); + +static int +set_contains(PySetObject *so, PyObject *key) +{ + PyObject *tmpkey; + int rv; + + rv = set_contains_key(so, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return -1; + PyErr_Clear(); + tmpkey = make_new_set(&PyFrozenSet_Type, NULL); + if (tmpkey == NULL) + return -1; + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + rv = set_contains(so, tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + Py_DECREF(tmpkey); + } + return rv; +} + +static PyObject * +set_direct_contains(PySetObject *so, PyObject *key) +{ + long result; + + result = set_contains(so, key); + if (result == -1) + return NULL; + return PyBool_FromLong(result); +} + +PyDoc_STRVAR(contains_doc, "x.__contains__(y) <==> y in x."); + +static PyObject * +set_remove(PySetObject *so, PyObject *key) +{ + PyObject *tmpkey, *result; + int rv; + + rv = set_discard_key(so, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + PyErr_Clear(); + tmpkey = make_new_set(&PyFrozenSet_Type, NULL); + if (tmpkey == NULL) + return NULL; + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + result = set_remove(so, tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + Py_DECREF(tmpkey); + return result; + } else if (rv == DISCARD_NOTFOUND) { + set_key_error(key); + return NULL; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(remove_doc, +"Remove an element from a set; it must be a member.\n\ +\n\ +If the element is not a member, raise a KeyError."); + +static PyObject * +set_discard(PySetObject *so, PyObject *key) +{ + PyObject *tmpkey, *result; + int rv; + + rv = set_discard_key(so, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + PyErr_Clear(); + tmpkey = make_new_set(&PyFrozenSet_Type, NULL); + if (tmpkey == NULL) + return NULL; + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + result = set_discard(so, tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + Py_DECREF(tmpkey); + return result; + } + Py_RETURN_NONE; +} + +PyDoc_STRVAR(discard_doc, +"Remove an element from a set if it is a member.\n\ +\n\ +If the element is not a member, do nothing."); + +static PyObject * +set_reduce(PySetObject *so) +{ + PyObject *keys=NULL, *args=NULL, *result=NULL, *dict=NULL; + + keys = PySequence_List((PyObject *)so); + if (keys == NULL) + goto done; + args = PyTuple_Pack(1, keys); + if (args == NULL) + goto done; + dict = PyObject_GetAttrString((PyObject *)so, "__dict__"); + if (dict == NULL) { + PyErr_Clear(); + dict = Py_None; + Py_INCREF(dict); + } + result = PyTuple_Pack(3, so->ob_type, args, dict); +done: + Py_XDECREF(args); + Py_XDECREF(keys); + Py_XDECREF(dict); + return result; +} + +PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); + +static int +set_init(PySetObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *iterable = NULL; + + if (!PyAnySet_Check(self)) + return -1; + if (!PyArg_UnpackTuple(args, self->ob_type->tp_name, 0, 1, &iterable)) + return -1; + set_clear_internal(self); + self->hash = -1; + if (iterable == NULL) + return 0; + return set_update_internal(self, iterable); +} + +static PySequenceMethods set_as_sequence = { + set_len, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + 0, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)set_contains, /* sq_contains */ +}; + +/* set object ********************************************************/ + +#ifdef Py_DEBUG +static PyObject *test_c_api(PySetObject *so); + +PyDoc_STRVAR(test_c_api_doc, "Exercises C API. Returns True.\n\ +All is well if assertions don't fail."); +#endif + +static PyMethodDef set_methods[] = { + {"add", (PyCFunction)set_add, METH_O, + add_doc}, + {"clear", (PyCFunction)set_clear, METH_NOARGS, + clear_doc}, + {"__contains__",(PyCFunction)set_direct_contains, METH_O | METH_COEXIST, + contains_doc}, + {"copy", (PyCFunction)set_copy, METH_NOARGS, + copy_doc}, + {"discard", (PyCFunction)set_discard, METH_O, + discard_doc}, + {"difference", (PyCFunction)set_difference, METH_O, + difference_doc}, + {"difference_update", (PyCFunction)set_difference_update, METH_O, + difference_update_doc}, + {"intersection",(PyCFunction)set_intersection, METH_O, + intersection_doc}, + {"intersection_update",(PyCFunction)set_intersection_update, METH_O, + intersection_update_doc}, + {"issubset", (PyCFunction)set_issubset, METH_O, + issubset_doc}, + {"issuperset", (PyCFunction)set_issuperset, METH_O, + issuperset_doc}, + {"pop", (PyCFunction)set_pop, METH_NOARGS, + pop_doc}, + {"__reduce__", (PyCFunction)set_reduce, METH_NOARGS, + reduce_doc}, + {"remove", (PyCFunction)set_remove, METH_O, + remove_doc}, + {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, + symmetric_difference_doc}, + {"symmetric_difference_update",(PyCFunction)set_symmetric_difference_update, METH_O, + symmetric_difference_update_doc}, +#ifdef Py_DEBUG + {"test_c_api", (PyCFunction)test_c_api, METH_NOARGS, + test_c_api_doc}, +#endif + {"union", (PyCFunction)set_union, METH_O, + union_doc}, + {"update", (PyCFunction)set_update, METH_O, + update_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyNumberMethods set_as_number = { + 0, /*nb_add*/ + (binaryfunc)set_sub, /*nb_subtract*/ + 0, /*nb_multiply*/ + 0, /*nb_divide*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_negative*/ + 0, /*nb_positive*/ + 0, /*nb_absolute*/ + 0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + (binaryfunc)set_and, /*nb_and*/ + (binaryfunc)set_xor, /*nb_xor*/ + (binaryfunc)set_or, /*nb_or*/ + 0, /*nb_coerce*/ + 0, /*nb_int*/ + 0, /*nb_long*/ + 0, /*nb_float*/ + 0, /*nb_oct*/ + 0, /*nb_hex*/ + 0, /*nb_inplace_add*/ + (binaryfunc)set_isub, /*nb_inplace_subtract*/ + 0, /*nb_inplace_multiply*/ + 0, /*nb_inplace_divide*/ + 0, /*nb_inplace_remainder*/ + 0, /*nb_inplace_power*/ + 0, /*nb_inplace_lshift*/ + 0, /*nb_inplace_rshift*/ + (binaryfunc)set_iand, /*nb_inplace_and*/ + (binaryfunc)set_ixor, /*nb_inplace_xor*/ + (binaryfunc)set_ior, /*nb_inplace_or*/ +}; + +PyDoc_STRVAR(set_doc, +"set(iterable) --> set object\n\ +\n\ +Build an unordered collection of unique elements."); + +PyTypeObject PySet_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "set", /* tp_name */ + sizeof(PySetObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)set_dealloc, /* tp_dealloc */ + (printfunc)set_tp_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + set_nocmp, /* tp_compare */ + (reprfunc)set_repr, /* tp_repr */ + &set_as_number, /* tp_as_number */ + &set_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + set_nohash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + set_doc, /* tp_doc */ + (traverseproc)set_traverse, /* tp_traverse */ + (inquiry)set_clear_internal, /* tp_clear */ + (richcmpfunc)set_richcompare, /* tp_richcompare */ + offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ + (getiterfunc)set_iter, /* tp_iter */ + 0, /* tp_iternext */ + set_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)set_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + set_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +/* frozenset object ********************************************************/ + + +static PyMethodDef frozenset_methods[] = { + {"__contains__",(PyCFunction)set_direct_contains, METH_O | METH_COEXIST, + contains_doc}, + {"copy", (PyCFunction)frozenset_copy, METH_NOARGS, + copy_doc}, + {"difference", (PyCFunction)set_difference, METH_O, + difference_doc}, + {"intersection",(PyCFunction)set_intersection, METH_O, + intersection_doc}, + {"issubset", (PyCFunction)set_issubset, METH_O, + issubset_doc}, + {"issuperset", (PyCFunction)set_issuperset, METH_O, + issuperset_doc}, + {"__reduce__", (PyCFunction)set_reduce, METH_NOARGS, + reduce_doc}, + {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, + symmetric_difference_doc}, + {"union", (PyCFunction)set_union, METH_O, + union_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyNumberMethods frozenset_as_number = { + 0, /*nb_add*/ + (binaryfunc)set_sub, /*nb_subtract*/ + 0, /*nb_multiply*/ + 0, /*nb_divide*/ + 0, /*nb_remainder*/ + 0, /*nb_divmod*/ + 0, /*nb_power*/ + 0, /*nb_negative*/ + 0, /*nb_positive*/ + 0, /*nb_absolute*/ + 0, /*nb_nonzero*/ + 0, /*nb_invert*/ + 0, /*nb_lshift*/ + 0, /*nb_rshift*/ + (binaryfunc)set_and, /*nb_and*/ + (binaryfunc)set_xor, /*nb_xor*/ + (binaryfunc)set_or, /*nb_or*/ +}; + +PyDoc_STRVAR(frozenset_doc, +"frozenset(iterable) --> frozenset object\n\ +\n\ +Build an immutable unordered collection of unique elements."); + +PyTypeObject PyFrozenSet_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "frozenset", /* tp_name */ + sizeof(PySetObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)set_dealloc, /* tp_dealloc */ + (printfunc)set_tp_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + set_nocmp, /* tp_compare */ + (reprfunc)set_repr, /* tp_repr */ + &frozenset_as_number, /* tp_as_number */ + &set_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + frozenset_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + frozenset_doc, /* tp_doc */ + (traverseproc)set_traverse, /* tp_traverse */ + (inquiry)set_clear_internal, /* tp_clear */ + (richcmpfunc)set_richcompare, /* tp_richcompare */ + offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ + (getiterfunc)set_iter, /* tp_iter */ + 0, /* tp_iternext */ + frozenset_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + frozenset_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + + +/***** C API functions *************************************************/ + +PyObject * +PySet_New(PyObject *iterable) +{ + return make_new_set(&PySet_Type, iterable); +} + +PyObject * +PyFrozenSet_New(PyObject *iterable) +{ + PyObject *args, *result; + + if (iterable == NULL) + args = PyTuple_New(0); + else + args = PyTuple_Pack(1, iterable); + if (args == NULL) + return NULL; + result = frozenset_new(&PyFrozenSet_Type, args, NULL); + Py_DECREF(args); + return result; +} + +Py_ssize_t +PySet_Size(PyObject *anyset) +{ + if (!PyAnySet_Check(anyset)) { + PyErr_BadInternalCall(); + return -1; + } + return PySet_GET_SIZE(anyset); +} + +int +PySet_Clear(PyObject *set) +{ + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { + PyErr_BadInternalCall(); + return -1; + } + return set_clear_internal((PySetObject *)set); +} + +int +PySet_Contains(PyObject *anyset, PyObject *key) +{ + if (!PyAnySet_Check(anyset)) { + PyErr_BadInternalCall(); + return -1; + } + return set_contains_key((PySetObject *)anyset, key); +} + +int +PySet_Discard(PyObject *set, PyObject *key) +{ + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { + PyErr_BadInternalCall(); + return -1; + } + return set_discard_key((PySetObject *)set, key); +} + +int +PySet_Add(PyObject *set, PyObject *key) +{ + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { + PyErr_BadInternalCall(); + return -1; + } + return set_add_key((PySetObject *)set, key); +} + +int +_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key) +{ + setentry *entry_ptr; + + if (!PyAnySet_Check(set)) { + PyErr_BadInternalCall(); + return -1; + } + if (set_next((PySetObject *)set, pos, &entry_ptr) == 0) + return 0; + *key = entry_ptr->key; + return 1; +} + +int +_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash) +{ + setentry *entry; + + if (!PyAnySet_Check(set)) { + PyErr_BadInternalCall(); + return -1; + } + if (set_next((PySetObject *)set, pos, &entry) == 0) + return 0; + *key = entry->key; + *hash = entry->hash; + return 1; +} + +PyObject * +PySet_Pop(PyObject *set) +{ + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { + PyErr_BadInternalCall(); + return NULL; + } + return set_pop((PySetObject *)set); +} + +int +_PySet_Update(PyObject *set, PyObject *iterable) +{ + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { + PyErr_BadInternalCall(); + return -1; + } + return set_update_internal((PySetObject *)set, iterable); +} + +#ifdef Py_DEBUG + +/* Test code to be called with any three element set. + Returns True and original set is restored. */ + +#define assertRaises(call_return_value, exception) \ + do { \ + assert(call_return_value); \ + assert(PyErr_ExceptionMatches(exception)); \ + PyErr_Clear(); \ + } while(0) + +static PyObject * +test_c_api(PySetObject *so) +{ + Py_ssize_t count; + char *s; + Py_ssize_t i; + PyObject *elem, *dup, *t, *f, *dup2; + PyObject *ob = (PyObject *)so; + + /* Verify preconditions and exercise type/size checks */ + assert(PyAnySet_Check(ob)); + assert(PyAnySet_CheckExact(ob)); + assert(!PyFrozenSet_CheckExact(ob)); + assert(PySet_Size(ob) == 3); + assert(PySet_GET_SIZE(ob) == 3); + + /* Raise TypeError for non-iterable constructor arguments */ + assertRaises(PySet_New(Py_None) == NULL, PyExc_TypeError); + assertRaises(PyFrozenSet_New(Py_None) == NULL, PyExc_TypeError); + + /* Raise TypeError for unhashable key */ + dup = PySet_New(ob); + assertRaises(PySet_Discard(ob, dup) == -1, PyExc_TypeError); + assertRaises(PySet_Contains(ob, dup) == -1, PyExc_TypeError); + assertRaises(PySet_Add(ob, dup) == -1, PyExc_TypeError); + + /* Exercise successful pop, contains, add, and discard */ + elem = PySet_Pop(ob); + assert(PySet_Contains(ob, elem) == 0); + assert(PySet_GET_SIZE(ob) == 2); + assert(PySet_Add(ob, elem) == 0); + assert(PySet_Contains(ob, elem) == 1); + assert(PySet_GET_SIZE(ob) == 3); + assert(PySet_Discard(ob, elem) == 1); + assert(PySet_GET_SIZE(ob) == 2); + assert(PySet_Discard(ob, elem) == 0); + assert(PySet_GET_SIZE(ob) == 2); + + /* Exercise clear */ + dup2 = PySet_New(dup); + assert(PySet_Clear(dup2) == 0); + assert(PySet_Size(dup2) == 0); + Py_DECREF(dup2); + + /* Raise SystemError on clear or update of frozen set */ + f = PyFrozenSet_New(dup); + assertRaises(PySet_Clear(f) == -1, PyExc_SystemError); + assertRaises(_PySet_Update(f, dup) == -1, PyExc_SystemError); + Py_DECREF(f); + + /* Exercise direct iteration */ + i = 0, count = 0; + while (_PySet_Next((PyObject *)dup, &i, &elem)) { + s = PyString_AsString(elem); + assert(s && (s[0] == 'a' || s[0] == 'b' || s[0] == 'c')); + count++; + } + assert(count == 3); + + /* Exercise updates */ + dup2 = PySet_New(NULL); + assert(_PySet_Update(dup2, dup) == 0); + assert(PySet_Size(dup2) == 3); + assert(_PySet_Update(dup2, dup) == 0); + assert(PySet_Size(dup2) == 3); + Py_DECREF(dup2); + + /* Raise SystemError when self argument is not a set or frozenset. */ + t = PyTuple_New(0); + assertRaises(PySet_Size(t) == -1, PyExc_SystemError); + assertRaises(PySet_Contains(t, elem) == -1, PyExc_SystemError); + Py_DECREF(t); + + /* Raise SystemError when self argument is not a set. */ + f = PyFrozenSet_New(dup); + assert(PySet_Size(f) == 3); + assert(PyFrozenSet_CheckExact(f)); + assertRaises(PySet_Add(f, elem) == -1, PyExc_SystemError); + assertRaises(PySet_Discard(f, elem) == -1, PyExc_SystemError); + assertRaises(PySet_Pop(f) == NULL, PyExc_SystemError); + Py_DECREF(f); + + /* Raise KeyError when popping from an empty set */ + assert(PyNumber_InPlaceSubtract(ob, ob) == ob); + Py_DECREF(ob); + assert(PySet_GET_SIZE(ob) == 0); + assertRaises(PySet_Pop(ob) == NULL, PyExc_KeyError); + + /* Restore the set from the copy using the PyNumber API */ + assert(PyNumber_InPlaceOr(ob, dup) == ob); + Py_DECREF(ob); + + /* Verify constructors accept NULL arguments */ + f = PySet_New(NULL); + assert(f != NULL); + assert(PySet_GET_SIZE(f) == 0); + Py_DECREF(f); + f = PyFrozenSet_New(NULL); + assert(f != NULL); + assert(PyFrozenSet_CheckExact(f)); + assert(PySet_GET_SIZE(f) == 0); + Py_DECREF(f); + + Py_DECREF(elem); + Py_DECREF(dup); + Py_RETURN_TRUE; +} + +#undef assertRaises + +#endif diff --git a/sys/src/cmd/python/Objects/sliceobject.c b/sys/src/cmd/python/Objects/sliceobject.c new file mode 100644 index 000000000..d8a24653a --- /dev/null +++ b/sys/src/cmd/python/Objects/sliceobject.c @@ -0,0 +1,351 @@ +/* +Written by Jim Hugunin and Chris Chase. + +This includes both the singular ellipsis object and slice objects. + +Guido, feel free to do whatever you want in the way of copyrights +for this file. +*/ + +/* +Py_Ellipsis encodes the '...' rubber index token. It is similar to +the Py_NoneStruct in that there is no way to create other objects of +this type and there is exactly one in existence. +*/ + +#include "Python.h" +#include "structmember.h" + +static PyObject * +ellipsis_repr(PyObject *op) +{ + return PyString_FromString("Ellipsis"); +} + +static PyTypeObject PyEllipsis_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "ellipsis", /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /*never called*/ /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + ellipsis_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ +}; + +PyObject _Py_EllipsisObject = { + PyObject_HEAD_INIT(&PyEllipsis_Type) +}; + + +/* Slice object implementation + + start, stop, and step are python objects with None indicating no + index is present. +*/ + +PyObject * +PySlice_New(PyObject *start, PyObject *stop, PyObject *step) +{ + PySliceObject *obj = PyObject_New(PySliceObject, &PySlice_Type); + + if (obj == NULL) + return NULL; + + if (step == NULL) step = Py_None; + Py_INCREF(step); + if (start == NULL) start = Py_None; + Py_INCREF(start); + if (stop == NULL) stop = Py_None; + Py_INCREF(stop); + + obj->step = step; + obj->start = start; + obj->stop = stop; + + return (PyObject *) obj; +} + +PyObject * +_PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop) +{ + PyObject *start, *end, *slice; + start = PyInt_FromSsize_t(istart); + if (!start) + return NULL; + end = PyInt_FromSsize_t(istop); + if (!end) { + Py_DECREF(start); + return NULL; + } + + slice = PySlice_New(start, end, NULL); + Py_DECREF(start); + Py_DECREF(end); + return slice; +} + +int +PySlice_GetIndices(PySliceObject *r, Py_ssize_t length, + Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step) +{ + /* XXX support long ints */ + if (r->step == Py_None) { + *step = 1; + } else { + if (!PyInt_Check(r->step) && !PyLong_Check(r->step)) return -1; + *step = PyInt_AsSsize_t(r->step); + } + if (r->start == Py_None) { + *start = *step < 0 ? length-1 : 0; + } else { + if (!PyInt_Check(r->start) && !PyLong_Check(r->step)) return -1; + *start = PyInt_AsSsize_t(r->start); + if (*start < 0) *start += length; + } + if (r->stop == Py_None) { + *stop = *step < 0 ? -1 : length; + } else { + if (!PyInt_Check(r->stop) && !PyLong_Check(r->step)) return -1; + *stop = PyInt_AsSsize_t(r->stop); + if (*stop < 0) *stop += length; + } + if (*stop > length) return -1; + if (*start >= length) return -1; + if (*step == 0) return -1; + return 0; +} + +int +PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length, + Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength) +{ + /* this is harder to get right than you might think */ + + Py_ssize_t defstart, defstop; + + if (r->step == Py_None) { + *step = 1; + } + else { + if (!_PyEval_SliceIndex(r->step, step)) return -1; + if (*step == 0) { + PyErr_SetString(PyExc_ValueError, + "slice step cannot be zero"); + return -1; + } + } + + defstart = *step < 0 ? length-1 : 0; + defstop = *step < 0 ? -1 : length; + + if (r->start == Py_None) { + *start = defstart; + } + else { + if (!_PyEval_SliceIndex(r->start, start)) return -1; + if (*start < 0) *start += length; + if (*start < 0) *start = (*step < 0) ? -1 : 0; + if (*start >= length) + *start = (*step < 0) ? length - 1 : length; + } + + if (r->stop == Py_None) { + *stop = defstop; + } + else { + if (!_PyEval_SliceIndex(r->stop, stop)) return -1; + if (*stop < 0) *stop += length; + if (*stop < 0) *stop = -1; + if (*stop > length) *stop = length; + } + + if ((*step < 0 && *stop >= *start) + || (*step > 0 && *start >= *stop)) { + *slicelength = 0; + } + else if (*step < 0) { + *slicelength = (*stop-*start+1)/(*step)+1; + } + else { + *slicelength = (*stop-*start-1)/(*step)+1; + } + + return 0; +} + +static PyObject * +slice_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + PyObject *start, *stop, *step; + + start = stop = step = NULL; + + if (!_PyArg_NoKeywords("slice()", kw)) + return NULL; + + if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step)) + return NULL; + + /* This swapping of stop and start is to maintain similarity with + range(). */ + if (stop == NULL) { + stop = start; + start = NULL; + } + return PySlice_New(start, stop, step); +} + +PyDoc_STRVAR(slice_doc, +"slice([start,] stop[, step])\n\ +\n\ +Create a slice object. This is used for extended slicing (e.g. a[0:10:2])."); + +static void +slice_dealloc(PySliceObject *r) +{ + Py_DECREF(r->step); + Py_DECREF(r->start); + Py_DECREF(r->stop); + PyObject_Del(r); +} + +static PyObject * +slice_repr(PySliceObject *r) +{ + PyObject *s, *comma; + + s = PyString_FromString("slice("); + comma = PyString_FromString(", "); + PyString_ConcatAndDel(&s, PyObject_Repr(r->start)); + PyString_Concat(&s, comma); + PyString_ConcatAndDel(&s, PyObject_Repr(r->stop)); + PyString_Concat(&s, comma); + PyString_ConcatAndDel(&s, PyObject_Repr(r->step)); + PyString_ConcatAndDel(&s, PyString_FromString(")")); + Py_DECREF(comma); + return s; +} + +static PyMemberDef slice_members[] = { + {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY}, + {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY}, + {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY}, + {0} +}; + +static PyObject* +slice_indices(PySliceObject* self, PyObject* len) +{ + Py_ssize_t ilen, start, stop, step, slicelength; + + ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError); + + if (ilen == -1 && PyErr_Occurred()) { + return NULL; + } + + if (PySlice_GetIndicesEx(self, ilen, &start, &stop, + &step, &slicelength) < 0) { + return NULL; + } + + return Py_BuildValue("(nnn)", start, stop, step); +} + +PyDoc_STRVAR(slice_indices_doc, +"S.indices(len) -> (start, stop, stride)\n\ +\n\ +Assuming a sequence of length len, calculate the start and stop\n\ +indices, and the stride length of the extended slice described by\n\ +S. Out of bounds indices are clipped in a manner consistent with the\n\ +handling of normal slices."); + +static PyMethodDef slice_methods[] = { + {"indices", (PyCFunction)slice_indices, + METH_O, slice_indices_doc}, + {NULL, NULL} +}; + +static int +slice_compare(PySliceObject *v, PySliceObject *w) +{ + int result = 0; + + if (v == w) + return 0; + + if (PyObject_Cmp(v->start, w->start, &result) < 0) + return -2; + if (result != 0) + return result; + if (PyObject_Cmp(v->stop, w->stop, &result) < 0) + return -2; + if (result != 0) + return result; + if (PyObject_Cmp(v->step, w->step, &result) < 0) + return -2; + return result; +} + +static long +slice_hash(PySliceObject *v) +{ + PyErr_SetString(PyExc_TypeError, "unhashable type"); + return -1L; +} + +PyTypeObject PySlice_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* Number of items for varobject */ + "slice", /* Name of this type */ + sizeof(PySliceObject), /* Basic object size */ + 0, /* Item size for varobject */ + (destructor)slice_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + (cmpfunc)slice_compare, /* tp_compare */ + (reprfunc)slice_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)slice_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + slice_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + slice_methods, /* tp_methods */ + slice_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + slice_new, /* tp_new */ +}; diff --git a/sys/src/cmd/python/Objects/stringlib/README.txt b/sys/src/cmd/python/Objects/stringlib/README.txt new file mode 100644 index 000000000..82a877465 --- /dev/null +++ b/sys/src/cmd/python/Objects/stringlib/README.txt @@ -0,0 +1,34 @@ +bits shared by the stringobject and unicodeobject implementations (and +possibly other modules, in a not too distant future). + +the stuff in here is included into relevant places; see the individual +source files for details. + +-------------------------------------------------------------------- +the following defines used by the different modules: + +STRINGLIB_CHAR + + the type used to hold a character (char or Py_UNICODE) + +STRINGLIB_EMPTY + + a PyObject representing the empty string + +int STRINGLIB_CMP(STRINGLIB_CHAR*, STRINGLIB_CHAR*, Py_ssize_t) + + compares two strings. returns 0 if they match, and non-zero if not. + +Py_ssize_t STRINGLIB_LEN(PyObject*) + + returns the length of the given string object (which must be of the + right type) + +PyObject* STRINGLIB_NEW(STRINGLIB_CHAR*, Py_ssize_t) + + creates a new string object + +STRINGLIB_CHAR* STRINGLIB_STR(PyObject*) + + returns the pointer to the character data for the given string + object (which must be of the right type) diff --git a/sys/src/cmd/python/Objects/stringlib/count.h b/sys/src/cmd/python/Objects/stringlib/count.h new file mode 100644 index 000000000..367a15c51 --- /dev/null +++ b/sys/src/cmd/python/Objects/stringlib/count.h @@ -0,0 +1,37 @@ +/* stringlib: count implementation */ + +#ifndef STRINGLIB_COUNT_H +#define STRINGLIB_COUNT_H + +#ifndef STRINGLIB_FASTSEARCH_H +#error must include "stringlib/fastsearch.h" before including this module +#endif + +Py_LOCAL_INLINE(Py_ssize_t) +stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, + const STRINGLIB_CHAR* sub, Py_ssize_t sub_len) +{ + Py_ssize_t count; + + if (sub_len == 0) { + if (str_len < 0) + return 0; /* start > len(str) */ + return str_len + 1; + } + + count = fastsearch(str, str_len, sub, sub_len, FAST_COUNT); + + if (count < 0) + count = 0; /* no match */ + + return count; +} + +#endif + +/* +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/sys/src/cmd/python/Objects/stringlib/fastsearch.h b/sys/src/cmd/python/Objects/stringlib/fastsearch.h new file mode 100644 index 000000000..8f79c360d --- /dev/null +++ b/sys/src/cmd/python/Objects/stringlib/fastsearch.h @@ -0,0 +1,104 @@ +/* stringlib: fastsearch implementation */ + +#ifndef STRINGLIB_FASTSEARCH_H +#define STRINGLIB_FASTSEARCH_H + +/* fast search/count implementation, based on a mix between boyer- + moore and horspool, with a few more bells and whistles on the top. + for some more background, see: http://effbot.org/stringlib */ + +/* note: fastsearch may access s[n], which isn't a problem when using + Python's ordinary string types, but may cause problems if you're + using this code in other contexts. also, the count mode returns -1 + if there cannot possible be a match in the target string, and 0 if + it has actually checked for matches, but didn't find any. callers + beware! */ + +#define FAST_COUNT 0 +#define FAST_SEARCH 1 + +Py_LOCAL_INLINE(Py_ssize_t) +fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, + const STRINGLIB_CHAR* p, Py_ssize_t m, + int mode) +{ + long mask; + Py_ssize_t skip, count = 0; + Py_ssize_t i, j, mlast, w; + + w = n - m; + + if (w < 0) + return -1; + + /* look for special cases */ + if (m <= 1) { + if (m <= 0) + return -1; + /* use special case for 1-character strings */ + if (mode == FAST_COUNT) { + for (i = 0; i < n; i++) + if (s[i] == p[0]) + count++; + return count; + } else { + for (i = 0; i < n; i++) + if (s[i] == p[0]) + return i; + } + return -1; + } + + mlast = m - 1; + + /* create compressed boyer-moore delta 1 table */ + skip = mlast - 1; + /* process pattern[:-1] */ + for (mask = i = 0; i < mlast; i++) { + mask |= (1 << (p[i] & 0x1F)); + if (p[i] == p[mlast]) + skip = mlast - i - 1; + } + /* process pattern[-1] outside the loop */ + mask |= (1 << (p[mlast] & 0x1F)); + + for (i = 0; i <= w; i++) { + /* note: using mlast in the skip path slows things down on x86 */ + if (s[i+m-1] == p[m-1]) { + /* candidate match */ + for (j = 0; j < mlast; j++) + if (s[i+j] != p[j]) + break; + if (j == mlast) { + /* got a match! */ + if (mode != FAST_COUNT) + return i; + count++; + i = i + mlast; + continue; + } + /* miss: check if next character is part of pattern */ + if (!(mask & (1 << (s[i+m] & 0x1F)))) + i = i + m; + else + i = i + skip; + } else { + /* skip: check if next character is part of pattern */ + if (!(mask & (1 << (s[i+m] & 0x1F)))) + i = i + m; + } + } + + if (mode != FAST_COUNT) + return -1; + return count; +} + +#endif + +/* +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/sys/src/cmd/python/Objects/stringlib/find.h b/sys/src/cmd/python/Objects/stringlib/find.h new file mode 100644 index 000000000..4cdbb096d --- /dev/null +++ b/sys/src/cmd/python/Objects/stringlib/find.h @@ -0,0 +1,113 @@ +/* stringlib: find/index implementation */ + +#ifndef STRINGLIB_FIND_H +#define STRINGLIB_FIND_H + +#ifndef STRINGLIB_FASTSEARCH_H +#error must include "stringlib/fastsearch.h" before including this module +#endif + +Py_LOCAL_INLINE(Py_ssize_t) +stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, + const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, + Py_ssize_t offset) +{ + Py_ssize_t pos; + + if (sub_len == 0) { + if (str_len < 0) + return -1; + return offset; + } + + pos = fastsearch(str, str_len, sub, sub_len, FAST_SEARCH); + + if (pos >= 0) + pos += offset; + + return pos; +} + +Py_LOCAL_INLINE(Py_ssize_t) +stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, + const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, + Py_ssize_t offset) +{ + /* XXX - create reversefastsearch helper! */ + if (sub_len == 0) { + if (str_len < 0) + return -1; + return str_len + offset; + } else { + Py_ssize_t j, pos = -1; + for (j = str_len - sub_len; j >= 0; --j) + if (STRINGLIB_CMP(str+j, sub, sub_len) == 0) { + pos = j + offset; + break; + } + return pos; + } +} + +Py_LOCAL_INLINE(Py_ssize_t) +stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, + const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, + Py_ssize_t start, Py_ssize_t end) +{ + if (start < 0) + start += str_len; + if (start < 0) + start = 0; + if (end > str_len) + end = str_len; + if (end < 0) + end += str_len; + if (end < 0) + end = 0; + + return stringlib_find( + str + start, end - start, + sub, sub_len, start + ); +} + +Py_LOCAL_INLINE(Py_ssize_t) +stringlib_rfind_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, + const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, + Py_ssize_t start, Py_ssize_t end) +{ + if (start < 0) + start += str_len; + if (start < 0) + start = 0; + if (end > str_len) + end = str_len; + if (end < 0) + end += str_len; + if (end < 0) + end = 0; + + return stringlib_rfind(str + start, end - start, sub, sub_len, start); +} + +#ifdef STRINGLIB_STR + +Py_LOCAL_INLINE(int) +stringlib_contains_obj(PyObject* str, PyObject* sub) +{ + return stringlib_find( + STRINGLIB_STR(str), STRINGLIB_LEN(str), + STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0 + ) != -1; +} + +#endif /* STRINGLIB_STR */ + +#endif /* STRINGLIB_FIND_H */ + +/* +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/sys/src/cmd/python/Objects/stringlib/partition.h b/sys/src/cmd/python/Objects/stringlib/partition.h new file mode 100644 index 000000000..105ba317d --- /dev/null +++ b/sys/src/cmd/python/Objects/stringlib/partition.h @@ -0,0 +1,111 @@ +/* stringlib: partition implementation */ + +#ifndef STRINGLIB_PARTITION_H +#define STRINGLIB_PARTITION_H + +#ifndef STRINGLIB_FASTSEARCH_H +#error must include "stringlib/fastsearch.h" before including this module +#endif + +Py_LOCAL_INLINE(PyObject*) +stringlib_partition( + PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, + PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len + ) +{ + PyObject* out; + Py_ssize_t pos; + + if (sep_len == 0) { + PyErr_SetString(PyExc_ValueError, "empty separator"); + return NULL; + } + + out = PyTuple_New(3); + if (!out) + return NULL; + + pos = fastsearch(str, str_len, sep, sep_len, FAST_SEARCH); + + if (pos < 0) { + Py_INCREF(str_obj); + PyTuple_SET_ITEM(out, 0, (PyObject*) str_obj); + Py_INCREF(STRINGLIB_EMPTY); + PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY); + Py_INCREF(STRINGLIB_EMPTY); + PyTuple_SET_ITEM(out, 2, (PyObject*) STRINGLIB_EMPTY); + return out; + } + + PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(str, pos)); + Py_INCREF(sep_obj); + PyTuple_SET_ITEM(out, 1, sep_obj); + pos += sep_len; + PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(str + pos, str_len - pos)); + + if (PyErr_Occurred()) { + Py_DECREF(out); + return NULL; + } + + return out; +} + +Py_LOCAL_INLINE(PyObject*) +stringlib_rpartition( + PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, + PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len + ) +{ + PyObject* out; + Py_ssize_t pos, j; + + if (sep_len == 0) { + PyErr_SetString(PyExc_ValueError, "empty separator"); + return NULL; + } + + out = PyTuple_New(3); + if (!out) + return NULL; + + /* XXX - create reversefastsearch helper! */ + pos = -1; + for (j = str_len - sep_len; j >= 0; --j) + if (STRINGLIB_CMP(str+j, sep, sep_len) == 0) { + pos = j; + break; + } + + if (pos < 0) { + Py_INCREF(STRINGLIB_EMPTY); + PyTuple_SET_ITEM(out, 0, (PyObject*) STRINGLIB_EMPTY); + Py_INCREF(STRINGLIB_EMPTY); + PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY); + Py_INCREF(str_obj); + PyTuple_SET_ITEM(out, 2, (PyObject*) str_obj); + return out; + } + + PyTuple_SET_ITEM(out, 0, STRINGLIB_NEW(str, pos)); + Py_INCREF(sep_obj); + PyTuple_SET_ITEM(out, 1, sep_obj); + pos += sep_len; + PyTuple_SET_ITEM(out, 2, STRINGLIB_NEW(str + pos, str_len - pos)); + + if (PyErr_Occurred()) { + Py_DECREF(out); + return NULL; + } + + return out; +} + +#endif + +/* +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/sys/src/cmd/python/Objects/stringobject.c b/sys/src/cmd/python/Objects/stringobject.c new file mode 100644 index 000000000..5ae2ca06c --- /dev/null +++ b/sys/src/cmd/python/Objects/stringobject.c @@ -0,0 +1,5009 @@ +/* String object implementation */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" + +#include <ctype.h> + +#ifdef COUNT_ALLOCS +int null_strings, one_strings; +#endif + +static PyStringObject *characters[UCHAR_MAX + 1]; +static PyStringObject *nullstring; + +/* This dictionary holds all interned strings. Note that references to + strings in this dictionary are *not* counted in the string's ob_refcnt. + When the interned string reaches a refcnt of 0 the string deallocation + function will delete the reference from this dictionary. + + Another way to look at this is that to say that the actual reference + count of a string is: s->ob_refcnt + (s->ob_sstate?2:0) +*/ +static PyObject *interned; + +/* + For both PyString_FromString() and PyString_FromStringAndSize(), the + parameter `size' denotes number of characters to allocate, not counting any + null terminating character. + + For PyString_FromString(), the parameter `str' points to a null-terminated + string containing exactly `size' bytes. + + For PyString_FromStringAndSize(), the parameter the parameter `str' is + either NULL or else points to a string containing at least `size' bytes. + For PyString_FromStringAndSize(), the string in the `str' parameter does + not have to be null-terminated. (Therefore it is safe to construct a + substring by calling `PyString_FromStringAndSize(origstring, substrlen)'.) + If `str' is NULL then PyString_FromStringAndSize() will allocate `size+1' + bytes (setting the last byte to the null terminating character) and you can + fill in the data yourself. If `str' is non-NULL then the resulting + PyString object must be treated as immutable and you must not fill in nor + alter the data yourself, since the strings may be shared. + + The PyObject member `op->ob_size', which denotes the number of "extra + items" in a variable-size object, will contain the number of bytes + allocated for string data, not counting the null terminating character. It + is therefore equal to the equal to the `size' parameter (for + PyString_FromStringAndSize()) or the length of the string in the `str' + parameter (for PyString_FromString()). +*/ +PyObject * +PyString_FromStringAndSize(const char *str, Py_ssize_t size) +{ + register PyStringObject *op; + assert(size >= 0); + if (size == 0 && (op = nullstring) != NULL) { +#ifdef COUNT_ALLOCS + null_strings++; +#endif + Py_INCREF(op); + return (PyObject *)op; + } + if (size == 1 && str != NULL && + (op = characters[*str & UCHAR_MAX]) != NULL) + { +#ifdef COUNT_ALLOCS + one_strings++; +#endif + Py_INCREF(op); + return (PyObject *)op; + } + + /* Inline PyObject_NewVar */ + op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); + if (op == NULL) + return PyErr_NoMemory(); + PyObject_INIT_VAR(op, &PyString_Type, size); + op->ob_shash = -1; + op->ob_sstate = SSTATE_NOT_INTERNED; + if (str != NULL) + Py_MEMCPY(op->ob_sval, str, size); + op->ob_sval[size] = '\0'; + /* share short strings */ + if (size == 0) { + PyObject *t = (PyObject *)op; + PyString_InternInPlace(&t); + op = (PyStringObject *)t; + nullstring = op; + Py_INCREF(op); + } else if (size == 1 && str != NULL) { + PyObject *t = (PyObject *)op; + PyString_InternInPlace(&t); + op = (PyStringObject *)t; + characters[*str & UCHAR_MAX] = op; + Py_INCREF(op); + } + return (PyObject *) op; +} + +PyObject * +PyString_FromString(const char *str) +{ + register size_t size; + register PyStringObject *op; + + assert(str != NULL); + size = strlen(str); + if (size > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "string is too long for a Python string"); + return NULL; + } + if (size == 0 && (op = nullstring) != NULL) { +#ifdef COUNT_ALLOCS + null_strings++; +#endif + Py_INCREF(op); + return (PyObject *)op; + } + if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) { +#ifdef COUNT_ALLOCS + one_strings++; +#endif + Py_INCREF(op); + return (PyObject *)op; + } + + /* Inline PyObject_NewVar */ + op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); + if (op == NULL) + return PyErr_NoMemory(); + PyObject_INIT_VAR(op, &PyString_Type, size); + op->ob_shash = -1; + op->ob_sstate = SSTATE_NOT_INTERNED; + Py_MEMCPY(op->ob_sval, str, size+1); + /* share short strings */ + if (size == 0) { + PyObject *t = (PyObject *)op; + PyString_InternInPlace(&t); + op = (PyStringObject *)t; + nullstring = op; + Py_INCREF(op); + } else if (size == 1) { + PyObject *t = (PyObject *)op; + PyString_InternInPlace(&t); + op = (PyStringObject *)t; + characters[*str & UCHAR_MAX] = op; + Py_INCREF(op); + } + return (PyObject *) op; +} + +PyObject * +PyString_FromFormatV(const char *format, va_list vargs) +{ + va_list count; + Py_ssize_t n = 0; + const char* f; + char *s; + PyObject* string; + +#ifdef VA_LIST_IS_ARRAY + Py_MEMCPY(count, vargs, sizeof(va_list)); +#else +#ifdef __va_copy + __va_copy(count, vargs); +#else + count = vargs; +#endif +#endif + /* step 1: figure out how large a buffer we need */ + for (f = format; *f; f++) { + if (*f == '%') { + const char* p = f; + while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f))) + ; + + /* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since + * they don't affect the amount of space we reserve. + */ + if ((*f == 'l' || *f == 'z') && + (f[1] == 'd' || f[1] == 'u')) + ++f; + + switch (*f) { + case 'c': + (void)va_arg(count, int); + /* fall through... */ + case '%': + n++; + break; + case 'd': case 'u': case 'i': case 'x': + (void) va_arg(count, int); + /* 20 bytes is enough to hold a 64-bit + integer. Decimal takes the most space. + This isn't enough for octal. */ + n += 20; + break; + case 's': + s = va_arg(count, char*); + n += strlen(s); + break; + case 'p': + (void) va_arg(count, int); + /* maximum 64-bit pointer representation: + * 0xffffffffffffffff + * so 19 characters is enough. + * XXX I count 18 -- what's the extra for? + */ + n += 19; + break; + default: + /* if we stumble upon an unknown + formatting code, copy the rest of + the format string to the output + string. (we cannot just skip the + code, since there's no way to know + what's in the argument list) */ + n += strlen(p); + goto expand; + } + } else + n++; + } + expand: + /* step 2: fill the buffer */ + /* Since we've analyzed how much space we need for the worst case, + use sprintf directly instead of the slower PyOS_snprintf. */ + string = PyString_FromStringAndSize(NULL, n); + if (!string) + return NULL; + + s = PyString_AsString(string); + + for (f = format; *f; f++) { + if (*f == '%') { + const char* p = f++; + Py_ssize_t i; + int longflag = 0; + int size_tflag = 0; + /* parse the width.precision part (we're only + interested in the precision value, if any) */ + n = 0; + while (isdigit(Py_CHARMASK(*f))) + n = (n*10) + *f++ - '0'; + if (*f == '.') { + f++; + n = 0; + while (isdigit(Py_CHARMASK(*f))) + n = (n*10) + *f++ - '0'; + } + while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f))) + f++; + /* handle the long flag, but only for %ld and %lu. + others can be added when necessary. */ + if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) { + longflag = 1; + ++f; + } + /* handle the size_t flag. */ + if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) { + size_tflag = 1; + ++f; + } + + switch (*f) { + case 'c': + *s++ = va_arg(vargs, int); + break; + case 'd': + if (longflag) + sprintf(s, "%ld", va_arg(vargs, long)); + else if (size_tflag) + sprintf(s, "%" PY_FORMAT_SIZE_T "d", + va_arg(vargs, Py_ssize_t)); + else + sprintf(s, "%d", va_arg(vargs, int)); + s += strlen(s); + break; + case 'u': + if (longflag) + sprintf(s, "%lu", + va_arg(vargs, unsigned long)); + else if (size_tflag) + sprintf(s, "%" PY_FORMAT_SIZE_T "u", + va_arg(vargs, size_t)); + else + sprintf(s, "%u", + va_arg(vargs, unsigned int)); + s += strlen(s); + break; + case 'i': + sprintf(s, "%i", va_arg(vargs, int)); + s += strlen(s); + break; + case 'x': + sprintf(s, "%x", va_arg(vargs, int)); + s += strlen(s); + break; + case 's': + p = va_arg(vargs, char*); + i = strlen(p); + if (n > 0 && i > n) + i = n; + Py_MEMCPY(s, p, i); + s += i; + break; + case 'p': + sprintf(s, "%p", va_arg(vargs, void*)); + /* %p is ill-defined: ensure leading 0x. */ + if (s[1] == 'X') + s[1] = 'x'; + else if (s[1] != 'x') { + memmove(s+2, s, strlen(s)+1); + s[0] = '0'; + s[1] = 'x'; + } + s += strlen(s); + break; + case '%': + *s++ = '%'; + break; + default: + strcpy(s, p); + s += strlen(s); + goto end; + } + } else + *s++ = *f; + } + + end: + _PyString_Resize(&string, s - PyString_AS_STRING(string)); + return string; +} + +PyObject * +PyString_FromFormat(const char *format, ...) +{ + PyObject* ret; + va_list vargs; + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + ret = PyString_FromFormatV(format, vargs); + va_end(vargs); + return ret; +} + + +PyObject *PyString_Decode(const char *s, + Py_ssize_t size, + const char *encoding, + const char *errors) +{ + PyObject *v, *str; + + str = PyString_FromStringAndSize(s, size); + if (str == NULL) + return NULL; + v = PyString_AsDecodedString(str, encoding, errors); + Py_DECREF(str); + return v; +} + +PyObject *PyString_AsDecodedObject(PyObject *str, + const char *encoding, + const char *errors) +{ + PyObject *v; + + if (!PyString_Check(str)) { + PyErr_BadArgument(); + goto onError; + } + + if (encoding == NULL) { +#ifdef Py_USING_UNICODE + encoding = PyUnicode_GetDefaultEncoding(); +#else + PyErr_SetString(PyExc_ValueError, "no encoding specified"); + goto onError; +#endif + } + + /* Decode via the codec registry */ + v = PyCodec_Decode(str, encoding, errors); + if (v == NULL) + goto onError; + + return v; + + onError: + return NULL; +} + +PyObject *PyString_AsDecodedString(PyObject *str, + const char *encoding, + const char *errors) +{ + PyObject *v; + + v = PyString_AsDecodedObject(str, encoding, errors); + if (v == NULL) + goto onError; + +#ifdef Py_USING_UNICODE + /* Convert Unicode to a string using the default encoding */ + if (PyUnicode_Check(v)) { + PyObject *temp = v; + v = PyUnicode_AsEncodedString(v, NULL, NULL); + Py_DECREF(temp); + if (v == NULL) + goto onError; + } +#endif + if (!PyString_Check(v)) { + PyErr_Format(PyExc_TypeError, + "decoder did not return a string object (type=%.400s)", + v->ob_type->tp_name); + Py_DECREF(v); + goto onError; + } + + return v; + + onError: + return NULL; +} + +PyObject *PyString_Encode(const char *s, + Py_ssize_t size, + const char *encoding, + const char *errors) +{ + PyObject *v, *str; + + str = PyString_FromStringAndSize(s, size); + if (str == NULL) + return NULL; + v = PyString_AsEncodedString(str, encoding, errors); + Py_DECREF(str); + return v; +} + +PyObject *PyString_AsEncodedObject(PyObject *str, + const char *encoding, + const char *errors) +{ + PyObject *v; + + if (!PyString_Check(str)) { + PyErr_BadArgument(); + goto onError; + } + + if (encoding == NULL) { +#ifdef Py_USING_UNICODE + encoding = PyUnicode_GetDefaultEncoding(); +#else + PyErr_SetString(PyExc_ValueError, "no encoding specified"); + goto onError; +#endif + } + + /* Encode via the codec registry */ + v = PyCodec_Encode(str, encoding, errors); + if (v == NULL) + goto onError; + + return v; + + onError: + return NULL; +} + +PyObject *PyString_AsEncodedString(PyObject *str, + const char *encoding, + const char *errors) +{ + PyObject *v; + + v = PyString_AsEncodedObject(str, encoding, errors); + if (v == NULL) + goto onError; + +#ifdef Py_USING_UNICODE + /* Convert Unicode to a string using the default encoding */ + if (PyUnicode_Check(v)) { + PyObject *temp = v; + v = PyUnicode_AsEncodedString(v, NULL, NULL); + Py_DECREF(temp); + if (v == NULL) + goto onError; + } +#endif + if (!PyString_Check(v)) { + PyErr_Format(PyExc_TypeError, + "encoder did not return a string object (type=%.400s)", + v->ob_type->tp_name); + Py_DECREF(v); + goto onError; + } + + return v; + + onError: + return NULL; +} + +static void +string_dealloc(PyObject *op) +{ + switch (PyString_CHECK_INTERNED(op)) { + case SSTATE_NOT_INTERNED: + break; + + case SSTATE_INTERNED_MORTAL: + /* revive dead object temporarily for DelItem */ + op->ob_refcnt = 3; + if (PyDict_DelItem(interned, op) != 0) + Py_FatalError( + "deletion of interned string failed"); + break; + + case SSTATE_INTERNED_IMMORTAL: + Py_FatalError("Immortal interned string died."); + + default: + Py_FatalError("Inconsistent interned string state."); + } + op->ob_type->tp_free(op); +} + +/* Unescape a backslash-escaped string. If unicode is non-zero, + the string is a u-literal. If recode_encoding is non-zero, + the string is UTF-8 encoded and should be re-encoded in the + specified encoding. */ + +PyObject *PyString_DecodeEscape(const char *s, + Py_ssize_t len, + const char *errors, + Py_ssize_t unicode, + const char *recode_encoding) +{ + int c; + char *p, *buf; + const char *end; + PyObject *v; + Py_ssize_t newlen = recode_encoding ? 4*len:len; + v = PyString_FromStringAndSize((char *)NULL, newlen); + if (v == NULL) + return NULL; + p = buf = PyString_AsString(v); + end = s + len; + while (s < end) { + if (*s != '\\') { + non_esc: +#ifdef Py_USING_UNICODE + if (recode_encoding && (*s & 0x80)) { + PyObject *u, *w; + char *r; + const char* t; + Py_ssize_t rn; + t = s; + /* Decode non-ASCII bytes as UTF-8. */ + while (t < end && (*t & 0x80)) t++; + u = PyUnicode_DecodeUTF8(s, t - s, errors); + if(!u) goto failed; + + /* Recode them in target encoding. */ + w = PyUnicode_AsEncodedString( + u, recode_encoding, errors); + Py_DECREF(u); + if (!w) goto failed; + + /* Append bytes to output buffer. */ + assert(PyString_Check(w)); + r = PyString_AS_STRING(w); + rn = PyString_GET_SIZE(w); + Py_MEMCPY(p, r, rn); + p += rn; + Py_DECREF(w); + s = t; + } else { + *p++ = *s++; + } +#else + *p++ = *s++; +#endif + continue; + } + s++; + if (s==end) { + PyErr_SetString(PyExc_ValueError, + "Trailing \\ in string"); + goto failed; + } + switch (*s++) { + /* XXX This assumes ASCII! */ + case '\n': break; + case '\\': *p++ = '\\'; break; + case '\'': *p++ = '\''; break; + case '\"': *p++ = '\"'; break; + case 'b': *p++ = '\b'; break; + case 'f': *p++ = '\014'; break; /* FF */ + case 't': *p++ = '\t'; break; + case 'n': *p++ = '\n'; break; + case 'r': *p++ = '\r'; break; + case 'v': *p++ = '\013'; break; /* VT */ + case 'a': *p++ = '\007'; break; /* BEL, not classic C */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + c = s[-1] - '0'; + if ('0' <= *s && *s <= '7') { + c = (c<<3) + *s++ - '0'; + if ('0' <= *s && *s <= '7') + c = (c<<3) + *s++ - '0'; + } + *p++ = c; + break; + case 'x': + if (isxdigit(Py_CHARMASK(s[0])) + && isxdigit(Py_CHARMASK(s[1]))) { + unsigned int x = 0; + c = Py_CHARMASK(*s); + s++; + if (isdigit(c)) + x = c - '0'; + else if (islower(c)) + x = 10 + c - 'a'; + else + x = 10 + c - 'A'; + x = x << 4; + c = Py_CHARMASK(*s); + s++; + if (isdigit(c)) + x += c - '0'; + else if (islower(c)) + x += 10 + c - 'a'; + else + x += 10 + c - 'A'; + *p++ = x; + break; + } + if (!errors || strcmp(errors, "strict") == 0) { + PyErr_SetString(PyExc_ValueError, + "invalid \\x escape"); + goto failed; + } + if (strcmp(errors, "replace") == 0) { + *p++ = '?'; + } else if (strcmp(errors, "ignore") == 0) + /* do nothing */; + else { + PyErr_Format(PyExc_ValueError, + "decoding error; " + "unknown error handling code: %.400s", + errors); + goto failed; + } +#ifndef Py_USING_UNICODE + case 'u': + case 'U': + case 'N': + if (unicode) { + PyErr_SetString(PyExc_ValueError, + "Unicode escapes not legal " + "when Unicode disabled"); + goto failed; + } +#endif + default: + *p++ = '\\'; + s--; + goto non_esc; /* an arbitry number of unescaped + UTF-8 bytes may follow. */ + } + } + if (p-buf < newlen) + _PyString_Resize(&v, p - buf); + return v; + failed: + Py_DECREF(v); + return NULL; +} + +/* -------------------------------------------------------------------- */ +/* object api */ + +static Py_ssize_t +string_getsize(register PyObject *op) +{ + char *s; + Py_ssize_t len; + if (PyString_AsStringAndSize(op, &s, &len)) + return -1; + return len; +} + +static /*const*/ char * +string_getbuffer(register PyObject *op) +{ + char *s; + Py_ssize_t len; + if (PyString_AsStringAndSize(op, &s, &len)) + return NULL; + return s; +} + +Py_ssize_t +PyString_Size(register PyObject *op) +{ + if (!PyString_Check(op)) + return string_getsize(op); + return ((PyStringObject *)op) -> ob_size; +} + +/*const*/ char * +PyString_AsString(register PyObject *op) +{ + if (!PyString_Check(op)) + return string_getbuffer(op); + return ((PyStringObject *)op) -> ob_sval; +} + +int +PyString_AsStringAndSize(register PyObject *obj, + register char **s, + register Py_ssize_t *len) +{ + if (s == NULL) { + PyErr_BadInternalCall(); + return -1; + } + + if (!PyString_Check(obj)) { +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(obj)) { + obj = _PyUnicode_AsDefaultEncodedString(obj, NULL); + if (obj == NULL) + return -1; + } + else +#endif + { + PyErr_Format(PyExc_TypeError, + "expected string or Unicode object, " + "%.200s found", obj->ob_type->tp_name); + return -1; + } + } + + *s = PyString_AS_STRING(obj); + if (len != NULL) + *len = PyString_GET_SIZE(obj); + else if (strlen(*s) != (size_t)PyString_GET_SIZE(obj)) { + PyErr_SetString(PyExc_TypeError, + "expected string without null bytes"); + return -1; + } + return 0; +} + +/* -------------------------------------------------------------------- */ +/* Methods */ + +#define STRINGLIB_CHAR char + +#define STRINGLIB_CMP memcmp +#define STRINGLIB_LEN PyString_GET_SIZE +#define STRINGLIB_NEW PyString_FromStringAndSize +#define STRINGLIB_STR PyString_AS_STRING + +#define STRINGLIB_EMPTY nullstring + +#include "stringlib/fastsearch.h" + +#include "stringlib/count.h" +#include "stringlib/find.h" +#include "stringlib/partition.h" + + +static int +string_print(PyStringObject *op, FILE *fp, int flags) +{ + Py_ssize_t i; + char c; + int quote; + + /* XXX Ought to check for interrupts when writing long strings */ + if (! PyString_CheckExact(op)) { + int ret; + /* A str subclass may have its own __str__ method. */ + op = (PyStringObject *) PyObject_Str((PyObject *)op); + if (op == NULL) + return -1; + ret = string_print(op, fp, flags); + Py_DECREF(op); + return ret; + } + if (flags & Py_PRINT_RAW) { + char *data = op->ob_sval; + Py_ssize_t size = op->ob_size; + while (size > INT_MAX) { + /* Very long strings cannot be written atomically. + * But don't write exactly INT_MAX bytes at a time + * to avoid memory aligment issues. + */ + const int chunk_size = INT_MAX & ~0x3FFF; + fwrite(data, 1, chunk_size, fp); + data += chunk_size; + size -= chunk_size; + } +#ifdef __VMS + if (size) fwrite(data, (int)size, 1, fp); +#else + fwrite(data, 1, (int)size, fp); +#endif + return 0; + } + + /* figure out which quote to use; single is preferred */ + quote = '\''; + if (memchr(op->ob_sval, '\'', op->ob_size) && + !memchr(op->ob_sval, '"', op->ob_size)) + quote = '"'; + + fputc(quote, fp); + for (i = 0; i < op->ob_size; i++) { + c = op->ob_sval[i]; + if (c == quote || c == '\\') + fprintf(fp, "\\%c", c); + else if (c == '\t') + fprintf(fp, "\\t"); + else if (c == '\n') + fprintf(fp, "\\n"); + else if (c == '\r') + fprintf(fp, "\\r"); + else if (c < ' ' || c >= 0x7f) + fprintf(fp, "\\x%02x", c & 0xff); + else + fputc(c, fp); + } + fputc(quote, fp); + return 0; +} + +PyObject * +PyString_Repr(PyObject *obj, int smartquotes) +{ + register PyStringObject* op = (PyStringObject*) obj; + size_t newsize = 2 + 4 * op->ob_size; + PyObject *v; + if (newsize > PY_SSIZE_T_MAX || newsize / 4 != op->ob_size) { + PyErr_SetString(PyExc_OverflowError, + "string is too large to make repr"); + } + v = PyString_FromStringAndSize((char *)NULL, newsize); + if (v == NULL) { + return NULL; + } + else { + register Py_ssize_t i; + register char c; + register char *p; + int quote; + + /* figure out which quote to use; single is preferred */ + quote = '\''; + if (smartquotes && + memchr(op->ob_sval, '\'', op->ob_size) && + !memchr(op->ob_sval, '"', op->ob_size)) + quote = '"'; + + p = PyString_AS_STRING(v); + *p++ = quote; + for (i = 0; i < op->ob_size; i++) { + /* There's at least enough room for a hex escape + and a closing quote. */ + assert(newsize - (p - PyString_AS_STRING(v)) >= 5); + c = op->ob_sval[i]; + if (c == quote || c == '\\') + *p++ = '\\', *p++ = c; + else if (c == '\t') + *p++ = '\\', *p++ = 't'; + else if (c == '\n') + *p++ = '\\', *p++ = 'n'; + else if (c == '\r') + *p++ = '\\', *p++ = 'r'; + else if (c < ' ' || c >= 0x7f) { + /* For performance, we don't want to call + PyOS_snprintf here (extra layers of + function call). */ + sprintf(p, "\\x%02x", c & 0xff); + p += 4; + } + else + *p++ = c; + } + assert(newsize - (p - PyString_AS_STRING(v)) >= 1); + *p++ = quote; + *p = '\0'; + _PyString_Resize( + &v, (p - PyString_AS_STRING(v))); + return v; + } +} + +static PyObject * +string_repr(PyObject *op) +{ + return PyString_Repr(op, 1); +} + +static PyObject * +string_str(PyObject *s) +{ + assert(PyString_Check(s)); + if (PyString_CheckExact(s)) { + Py_INCREF(s); + return s; + } + else { + /* Subtype -- return genuine string with the same value. */ + PyStringObject *t = (PyStringObject *) s; + return PyString_FromStringAndSize(t->ob_sval, t->ob_size); + } +} + +static Py_ssize_t +string_length(PyStringObject *a) +{ + return a->ob_size; +} + +static PyObject * +string_concat(register PyStringObject *a, register PyObject *bb) +{ + register Py_ssize_t size; + register PyStringObject *op; + if (!PyString_Check(bb)) { +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(bb)) + return PyUnicode_Concat((PyObject *)a, bb); +#endif + PyErr_Format(PyExc_TypeError, + "cannot concatenate 'str' and '%.200s' objects", + bb->ob_type->tp_name); + return NULL; + } +#define b ((PyStringObject *)bb) + /* Optimize cases with empty left or right operand */ + if ((a->ob_size == 0 || b->ob_size == 0) && + PyString_CheckExact(a) && PyString_CheckExact(b)) { + if (a->ob_size == 0) { + Py_INCREF(bb); + return bb; + } + Py_INCREF(a); + return (PyObject *)a; + } + size = a->ob_size + b->ob_size; + if (size < 0) { + PyErr_SetString(PyExc_OverflowError, + "strings are too large to concat"); + return NULL; + } + + /* Inline PyObject_NewVar */ + op = (PyStringObject *)PyObject_MALLOC(sizeof(PyStringObject) + size); + if (op == NULL) + return PyErr_NoMemory(); + PyObject_INIT_VAR(op, &PyString_Type, size); + op->ob_shash = -1; + op->ob_sstate = SSTATE_NOT_INTERNED; + Py_MEMCPY(op->ob_sval, a->ob_sval, a->ob_size); + Py_MEMCPY(op->ob_sval + a->ob_size, b->ob_sval, b->ob_size); + op->ob_sval[size] = '\0'; + return (PyObject *) op; +#undef b +} + +static PyObject * +string_repeat(register PyStringObject *a, register Py_ssize_t n) +{ + register Py_ssize_t i; + register Py_ssize_t j; + register Py_ssize_t size; + register PyStringObject *op; + size_t nbytes; + if (n < 0) + n = 0; + /* watch out for overflows: the size can overflow int, + * and the # of bytes needed can overflow size_t + */ + size = a->ob_size * n; + if (n && size / n != a->ob_size) { + PyErr_SetString(PyExc_OverflowError, + "repeated string is too long"); + return NULL; + } + if (size == a->ob_size && PyString_CheckExact(a)) { + Py_INCREF(a); + return (PyObject *)a; + } + nbytes = (size_t)size; + if (nbytes + sizeof(PyStringObject) <= nbytes) { + PyErr_SetString(PyExc_OverflowError, + "repeated string is too long"); + return NULL; + } + op = (PyStringObject *) + PyObject_MALLOC(sizeof(PyStringObject) + nbytes); + if (op == NULL) + return PyErr_NoMemory(); + PyObject_INIT_VAR(op, &PyString_Type, size); + op->ob_shash = -1; + op->ob_sstate = SSTATE_NOT_INTERNED; + op->ob_sval[size] = '\0'; + if (a->ob_size == 1 && n > 0) { + memset(op->ob_sval, a->ob_sval[0] , n); + return (PyObject *) op; + } + i = 0; + if (i < size) { + Py_MEMCPY(op->ob_sval, a->ob_sval, a->ob_size); + i = a->ob_size; + } + while (i < size) { + j = (i <= size-i) ? i : size-i; + Py_MEMCPY(op->ob_sval+i, op->ob_sval, j); + i += j; + } + return (PyObject *) op; +} + +/* String slice a[i:j] consists of characters a[i] ... a[j-1] */ + +static PyObject * +string_slice(register PyStringObject *a, register Py_ssize_t i, + register Py_ssize_t j) + /* j -- may be negative! */ +{ + if (i < 0) + i = 0; + if (j < 0) + j = 0; /* Avoid signed/unsigned bug in next line */ + if (j > a->ob_size) + j = a->ob_size; + if (i == 0 && j == a->ob_size && PyString_CheckExact(a)) { + /* It's the same as a */ + Py_INCREF(a); + return (PyObject *)a; + } + if (j < i) + j = i; + return PyString_FromStringAndSize(a->ob_sval + i, j-i); +} + +static int +string_contains(PyObject *str_obj, PyObject *sub_obj) +{ + if (!PyString_CheckExact(sub_obj)) { +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(sub_obj)) + return PyUnicode_Contains(str_obj, sub_obj); +#endif + if (!PyString_Check(sub_obj)) { + PyErr_SetString(PyExc_TypeError, + "'in <string>' requires string as left operand"); + return -1; + } + } + + return stringlib_contains_obj(str_obj, sub_obj); +} + +static PyObject * +string_item(PyStringObject *a, register Py_ssize_t i) +{ + char pchar; + PyObject *v; + if (i < 0 || i >= a->ob_size) { + PyErr_SetString(PyExc_IndexError, "string index out of range"); + return NULL; + } + pchar = a->ob_sval[i]; + v = (PyObject *)characters[pchar & UCHAR_MAX]; + if (v == NULL) + v = PyString_FromStringAndSize(&pchar, 1); + else { +#ifdef COUNT_ALLOCS + one_strings++; +#endif + Py_INCREF(v); + } + return v; +} + +static PyObject* +string_richcompare(PyStringObject *a, PyStringObject *b, int op) +{ + int c; + Py_ssize_t len_a, len_b; + Py_ssize_t min_len; + PyObject *result; + + /* Make sure both arguments are strings. */ + if (!(PyString_Check(a) && PyString_Check(b))) { + result = Py_NotImplemented; + goto out; + } + if (a == b) { + switch (op) { + case Py_EQ:case Py_LE:case Py_GE: + result = Py_True; + goto out; + case Py_NE:case Py_LT:case Py_GT: + result = Py_False; + goto out; + } + } + if (op == Py_EQ) { + /* Supporting Py_NE here as well does not save + much time, since Py_NE is rarely used. */ + if (a->ob_size == b->ob_size + && (a->ob_sval[0] == b->ob_sval[0] + && memcmp(a->ob_sval, b->ob_sval, + a->ob_size) == 0)) { + result = Py_True; + } else { + result = Py_False; + } + goto out; + } + len_a = a->ob_size; len_b = b->ob_size; + min_len = (len_a < len_b) ? len_a : len_b; + if (min_len > 0) { + c = Py_CHARMASK(*a->ob_sval) - Py_CHARMASK(*b->ob_sval); + if (c==0) + c = memcmp(a->ob_sval, b->ob_sval, min_len); + }else + c = 0; + if (c == 0) + c = (len_a < len_b) ? -1 : (len_a > len_b) ? 1 : 0; + switch (op) { + case Py_LT: c = c < 0; break; + case Py_LE: c = c <= 0; break; + case Py_EQ: assert(0); break; /* unreachable */ + case Py_NE: c = c != 0; break; + case Py_GT: c = c > 0; break; + case Py_GE: c = c >= 0; break; + default: + result = Py_NotImplemented; + goto out; + } + result = c ? Py_True : Py_False; + out: + Py_INCREF(result); + return result; +} + +int +_PyString_Eq(PyObject *o1, PyObject *o2) +{ + PyStringObject *a = (PyStringObject*) o1; + PyStringObject *b = (PyStringObject*) o2; + return a->ob_size == b->ob_size + && *a->ob_sval == *b->ob_sval + && memcmp(a->ob_sval, b->ob_sval, a->ob_size) == 0; +} + +static long +string_hash(PyStringObject *a) +{ + register Py_ssize_t len; + register unsigned char *p; + register long x; + + if (a->ob_shash != -1) + return a->ob_shash; + len = a->ob_size; + p = (unsigned char *) a->ob_sval; + x = *p << 7; + while (--len >= 0) + x = (1000003*x) ^ *p++; + x ^= a->ob_size; + if (x == -1) + x = -2; + a->ob_shash = x; + return x; +} + +static PyObject* +string_subscript(PyStringObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyString_GET_SIZE(self); + return string_item(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, cur, i; + char* source_buf; + char* result_buf; + PyObject* result; + + if (PySlice_GetIndicesEx((PySliceObject*)item, + PyString_GET_SIZE(self), + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyString_FromStringAndSize("", 0); + } + else { + source_buf = PyString_AsString((PyObject*)self); + result_buf = (char *)PyMem_Malloc(slicelength); + if (result_buf == NULL) + return PyErr_NoMemory(); + + for (cur = start, i = 0; i < slicelength; + cur += step, i++) { + result_buf[i] = source_buf[cur]; + } + + result = PyString_FromStringAndSize(result_buf, + slicelength); + PyMem_Free(result_buf); + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "string indices must be integers"); + return NULL; + } +} + +static Py_ssize_t +string_buffer_getreadbuf(PyStringObject *self, Py_ssize_t index, const void **ptr) +{ + if ( index != 0 ) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent string segment"); + return -1; + } + *ptr = (void *)self->ob_sval; + return self->ob_size; +} + +static Py_ssize_t +string_buffer_getwritebuf(PyStringObject *self, Py_ssize_t index, const void **ptr) +{ + PyErr_SetString(PyExc_TypeError, + "Cannot use string as modifiable buffer"); + return -1; +} + +static Py_ssize_t +string_buffer_getsegcount(PyStringObject *self, Py_ssize_t *lenp) +{ + if ( lenp ) + *lenp = self->ob_size; + return 1; +} + +static Py_ssize_t +string_buffer_getcharbuf(PyStringObject *self, Py_ssize_t index, const char **ptr) +{ + if ( index != 0 ) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent string segment"); + return -1; + } + *ptr = self->ob_sval; + return self->ob_size; +} + +static PySequenceMethods string_as_sequence = { + (lenfunc)string_length, /*sq_length*/ + (binaryfunc)string_concat, /*sq_concat*/ + (ssizeargfunc)string_repeat, /*sq_repeat*/ + (ssizeargfunc)string_item, /*sq_item*/ + (ssizessizeargfunc)string_slice, /*sq_slice*/ + 0, /*sq_ass_item*/ + 0, /*sq_ass_slice*/ + (objobjproc)string_contains /*sq_contains*/ +}; + +static PyMappingMethods string_as_mapping = { + (lenfunc)string_length, + (binaryfunc)string_subscript, + 0, +}; + +static PyBufferProcs string_as_buffer = { + (readbufferproc)string_buffer_getreadbuf, + (writebufferproc)string_buffer_getwritebuf, + (segcountproc)string_buffer_getsegcount, + (charbufferproc)string_buffer_getcharbuf, +}; + + + +#define LEFTSTRIP 0 +#define RIGHTSTRIP 1 +#define BOTHSTRIP 2 + +/* Arrays indexed by above */ +static const char *stripformat[] = {"|O:lstrip", "|O:rstrip", "|O:strip"}; + +#define STRIPNAME(i) (stripformat[i]+3) + + +/* Don't call if length < 2 */ +#define Py_STRING_MATCH(target, offset, pattern, length) \ + (target[offset] == pattern[0] && \ + target[offset+length-1] == pattern[length-1] && \ + !memcmp(target+offset+1, pattern+1, length-2) ) + + +/* Overallocate the initial list to reduce the number of reallocs for small + split sizes. Eg, "A A A A A A A A A A".split() (10 elements) has three + resizes, to sizes 4, 8, then 16. Most observed string splits are for human + text (roughly 11 words per line) and field delimited data (usually 1-10 + fields). For large strings the split algorithms are bandwidth limited + so increasing the preallocation likely will not improve things.*/ + +#define MAX_PREALLOC 12 + +/* 5 splits gives 6 elements */ +#define PREALLOC_SIZE(maxsplit) \ + (maxsplit >= MAX_PREALLOC ? MAX_PREALLOC : maxsplit+1) + +#define SPLIT_APPEND(data, left, right) \ + str = PyString_FromStringAndSize((data) + (left), \ + (right) - (left)); \ + if (str == NULL) \ + goto onError; \ + if (PyList_Append(list, str)) { \ + Py_DECREF(str); \ + goto onError; \ + } \ + else \ + Py_DECREF(str); + +#define SPLIT_ADD(data, left, right) { \ + str = PyString_FromStringAndSize((data) + (left), \ + (right) - (left)); \ + if (str == NULL) \ + goto onError; \ + if (count < MAX_PREALLOC) { \ + PyList_SET_ITEM(list, count, str); \ + } else { \ + if (PyList_Append(list, str)) { \ + Py_DECREF(str); \ + goto onError; \ + } \ + else \ + Py_DECREF(str); \ + } \ + count++; } + +/* Always force the list to the expected size. */ +#define FIX_PREALLOC_SIZE(list) ((PyListObject *)list)->ob_size = count + +#define SKIP_SPACE(s, i, len) { while (i<len && isspace(Py_CHARMASK(s[i]))) i++; } +#define SKIP_NONSPACE(s, i, len) { while (i<len && !isspace(Py_CHARMASK(s[i]))) i++; } +#define RSKIP_SPACE(s, i) { while (i>=0 && isspace(Py_CHARMASK(s[i]))) i--; } +#define RSKIP_NONSPACE(s, i) { while (i>=0 && !isspace(Py_CHARMASK(s[i]))) i--; } + +Py_LOCAL_INLINE(PyObject *) +split_whitespace(const char *s, Py_ssize_t len, Py_ssize_t maxsplit) +{ + Py_ssize_t i, j, count=0; + PyObject *str; + PyObject *list = PyList_New(PREALLOC_SIZE(maxsplit)); + + if (list == NULL) + return NULL; + + i = j = 0; + + while (maxsplit-- > 0) { + SKIP_SPACE(s, i, len); + if (i==len) break; + j = i; i++; + SKIP_NONSPACE(s, i, len); + SPLIT_ADD(s, j, i); + } + + if (i < len) { + /* Only occurs when maxsplit was reached */ + /* Skip any remaining whitespace and copy to end of string */ + SKIP_SPACE(s, i, len); + if (i != len) + SPLIT_ADD(s, i, len); + } + FIX_PREALLOC_SIZE(list); + return list; + onError: + Py_DECREF(list); + return NULL; +} + +Py_LOCAL_INLINE(PyObject *) +split_char(const char *s, Py_ssize_t len, char ch, Py_ssize_t maxcount) +{ + register Py_ssize_t i, j, count=0; + PyObject *str; + PyObject *list = PyList_New(PREALLOC_SIZE(maxcount)); + + if (list == NULL) + return NULL; + + i = j = 0; + while ((j < len) && (maxcount-- > 0)) { + for(; j<len; j++) { + /* I found that using memchr makes no difference */ + if (s[j] == ch) { + SPLIT_ADD(s, i, j); + i = j = j + 1; + break; + } + } + } + if (i <= len) { + SPLIT_ADD(s, i, len); + } + FIX_PREALLOC_SIZE(list); + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +PyDoc_STRVAR(split__doc__, +"S.split([sep [,maxsplit]]) -> list of strings\n\ +\n\ +Return a list of the words in the string S, using sep as the\n\ +delimiter string. If maxsplit is given, at most maxsplit\n\ +splits are done. If sep is not specified or is None, any\n\ +whitespace string is a separator."); + +static PyObject * +string_split(PyStringObject *self, PyObject *args) +{ + Py_ssize_t len = PyString_GET_SIZE(self), n, i, j; + Py_ssize_t maxsplit = -1, count=0; + const char *s = PyString_AS_STRING(self), *sub; + PyObject *list, *str, *subobj = Py_None; +#ifdef USE_FAST + Py_ssize_t pos; +#endif + + if (!PyArg_ParseTuple(args, "|On:split", &subobj, &maxsplit)) + return NULL; + if (maxsplit < 0) + maxsplit = PY_SSIZE_T_MAX; + if (subobj == Py_None) + return split_whitespace(s, len, maxsplit); + if (PyString_Check(subobj)) { + sub = PyString_AS_STRING(subobj); + n = PyString_GET_SIZE(subobj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(subobj)) + return PyUnicode_Split((PyObject *)self, subobj, maxsplit); +#endif + else if (PyObject_AsCharBuffer(subobj, &sub, &n)) + return NULL; + + if (n == 0) { + PyErr_SetString(PyExc_ValueError, "empty separator"); + return NULL; + } + else if (n == 1) + return split_char(s, len, sub[0], maxsplit); + + list = PyList_New(PREALLOC_SIZE(maxsplit)); + if (list == NULL) + return NULL; + +#ifdef USE_FAST + i = j = 0; + while (maxsplit-- > 0) { + pos = fastsearch(s+i, len-i, sub, n, FAST_SEARCH); + if (pos < 0) + break; + j = i+pos; + SPLIT_ADD(s, i, j); + i = j + n; + } +#else + i = j = 0; + while ((j+n <= len) && (maxsplit-- > 0)) { + for (; j+n <= len; j++) { + if (Py_STRING_MATCH(s, j, sub, n)) { + SPLIT_ADD(s, i, j); + i = j = j + n; + break; + } + } + } +#endif + SPLIT_ADD(s, i, len); + FIX_PREALLOC_SIZE(list); + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +PyDoc_STRVAR(partition__doc__, +"S.partition(sep) -> (head, sep, tail)\n\ +\n\ +Searches for the separator sep in S, and returns the part before it,\n\ +the separator itself, and the part after it. If the separator is not\n\ +found, returns S and two empty strings."); + +static PyObject * +string_partition(PyStringObject *self, PyObject *sep_obj) +{ + const char *sep; + Py_ssize_t sep_len; + + if (PyString_Check(sep_obj)) { + sep = PyString_AS_STRING(sep_obj); + sep_len = PyString_GET_SIZE(sep_obj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(sep_obj)) + return PyUnicode_Partition((PyObject *) self, sep_obj); +#endif + else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len)) + return NULL; + + return stringlib_partition( + (PyObject*) self, + PyString_AS_STRING(self), PyString_GET_SIZE(self), + sep_obj, sep, sep_len + ); +} + +PyDoc_STRVAR(rpartition__doc__, +"S.rpartition(sep) -> (tail, sep, head)\n\ +\n\ +Searches for the separator sep in S, starting at the end of S, and returns\n\ +the part before it, the separator itself, and the part after it. If the\n\ +separator is not found, returns two empty strings and S."); + +static PyObject * +string_rpartition(PyStringObject *self, PyObject *sep_obj) +{ + const char *sep; + Py_ssize_t sep_len; + + if (PyString_Check(sep_obj)) { + sep = PyString_AS_STRING(sep_obj); + sep_len = PyString_GET_SIZE(sep_obj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(sep_obj)) + return PyUnicode_Partition((PyObject *) self, sep_obj); +#endif + else if (PyObject_AsCharBuffer(sep_obj, &sep, &sep_len)) + return NULL; + + return stringlib_rpartition( + (PyObject*) self, + PyString_AS_STRING(self), PyString_GET_SIZE(self), + sep_obj, sep, sep_len + ); +} + +Py_LOCAL_INLINE(PyObject *) +rsplit_whitespace(const char *s, Py_ssize_t len, Py_ssize_t maxsplit) +{ + Py_ssize_t i, j, count=0; + PyObject *str; + PyObject *list = PyList_New(PREALLOC_SIZE(maxsplit)); + + if (list == NULL) + return NULL; + + i = j = len-1; + + while (maxsplit-- > 0) { + RSKIP_SPACE(s, i); + if (i<0) break; + j = i; i--; + RSKIP_NONSPACE(s, i); + SPLIT_ADD(s, i + 1, j + 1); + } + if (i >= 0) { + /* Only occurs when maxsplit was reached */ + /* Skip any remaining whitespace and copy to beginning of string */ + RSKIP_SPACE(s, i); + if (i >= 0) + SPLIT_ADD(s, 0, i + 1); + + } + FIX_PREALLOC_SIZE(list); + if (PyList_Reverse(list) < 0) + goto onError; + return list; + onError: + Py_DECREF(list); + return NULL; +} + +Py_LOCAL_INLINE(PyObject *) +rsplit_char(const char *s, Py_ssize_t len, char ch, Py_ssize_t maxcount) +{ + register Py_ssize_t i, j, count=0; + PyObject *str; + PyObject *list = PyList_New(PREALLOC_SIZE(maxcount)); + + if (list == NULL) + return NULL; + + i = j = len - 1; + while ((i >= 0) && (maxcount-- > 0)) { + for (; i >= 0; i--) { + if (s[i] == ch) { + SPLIT_ADD(s, i + 1, j + 1); + j = i = i - 1; + break; + } + } + } + if (j >= -1) { + SPLIT_ADD(s, 0, j + 1); + } + FIX_PREALLOC_SIZE(list); + if (PyList_Reverse(list) < 0) + goto onError; + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +PyDoc_STRVAR(rsplit__doc__, +"S.rsplit([sep [,maxsplit]]) -> list of strings\n\ +\n\ +Return a list of the words in the string S, using sep as the\n\ +delimiter string, starting at the end of the string and working\n\ +to the front. If maxsplit is given, at most maxsplit splits are\n\ +done. If sep is not specified or is None, any whitespace string\n\ +is a separator."); + +static PyObject * +string_rsplit(PyStringObject *self, PyObject *args) +{ + Py_ssize_t len = PyString_GET_SIZE(self), n, i, j; + Py_ssize_t maxsplit = -1, count=0; + const char *s = PyString_AS_STRING(self), *sub; + PyObject *list, *str, *subobj = Py_None; + + if (!PyArg_ParseTuple(args, "|On:rsplit", &subobj, &maxsplit)) + return NULL; + if (maxsplit < 0) + maxsplit = PY_SSIZE_T_MAX; + if (subobj == Py_None) + return rsplit_whitespace(s, len, maxsplit); + if (PyString_Check(subobj)) { + sub = PyString_AS_STRING(subobj); + n = PyString_GET_SIZE(subobj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(subobj)) + return PyUnicode_RSplit((PyObject *)self, subobj, maxsplit); +#endif + else if (PyObject_AsCharBuffer(subobj, &sub, &n)) + return NULL; + + if (n == 0) { + PyErr_SetString(PyExc_ValueError, "empty separator"); + return NULL; + } + else if (n == 1) + return rsplit_char(s, len, sub[0], maxsplit); + + list = PyList_New(PREALLOC_SIZE(maxsplit)); + if (list == NULL) + return NULL; + + j = len; + i = j - n; + + while ( (i >= 0) && (maxsplit-- > 0) ) { + for (; i>=0; i--) { + if (Py_STRING_MATCH(s, i, sub, n)) { + SPLIT_ADD(s, i + n, j); + j = i; + i -= n; + break; + } + } + } + SPLIT_ADD(s, 0, j); + FIX_PREALLOC_SIZE(list); + if (PyList_Reverse(list) < 0) + goto onError; + return list; + +onError: + Py_DECREF(list); + return NULL; +} + + +PyDoc_STRVAR(join__doc__, +"S.join(sequence) -> string\n\ +\n\ +Return a string which is the concatenation of the strings in the\n\ +sequence. The separator between elements is S."); + +static PyObject * +string_join(PyStringObject *self, PyObject *orig) +{ + char *sep = PyString_AS_STRING(self); + const Py_ssize_t seplen = PyString_GET_SIZE(self); + PyObject *res = NULL; + char *p; + Py_ssize_t seqlen = 0; + size_t sz = 0; + Py_ssize_t i; + PyObject *seq, *item; + + seq = PySequence_Fast(orig, ""); + if (seq == NULL) { + return NULL; + } + + seqlen = PySequence_Size(seq); + if (seqlen == 0) { + Py_DECREF(seq); + return PyString_FromString(""); + } + if (seqlen == 1) { + item = PySequence_Fast_GET_ITEM(seq, 0); + if (PyString_CheckExact(item) || PyUnicode_CheckExact(item)) { + Py_INCREF(item); + Py_DECREF(seq); + return item; + } + } + + /* There are at least two things to join, or else we have a subclass + * of the builtin types in the sequence. + * Do a pre-pass to figure out the total amount of space we'll + * need (sz), see whether any argument is absurd, and defer to + * the Unicode join if appropriate. + */ + for (i = 0; i < seqlen; i++) { + const size_t old_sz = sz; + item = PySequence_Fast_GET_ITEM(seq, i); + if (!PyString_Check(item)){ +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(item)) { + /* Defer to Unicode join. + * CAUTION: There's no gurantee that the + * original sequence can be iterated over + * again, so we must pass seq here. + */ + PyObject *result; + result = PyUnicode_Join((PyObject *)self, seq); + Py_DECREF(seq); + return result; + } +#endif + PyErr_Format(PyExc_TypeError, + "sequence item %zd: expected string," + " %.80s found", + i, item->ob_type->tp_name); + Py_DECREF(seq); + return NULL; + } + sz += PyString_GET_SIZE(item); + if (i != 0) + sz += seplen; + if (sz < old_sz || sz > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "join() result is too long for a Python string"); + Py_DECREF(seq); + return NULL; + } + } + + /* Allocate result space. */ + res = PyString_FromStringAndSize((char*)NULL, sz); + if (res == NULL) { + Py_DECREF(seq); + return NULL; + } + + /* Catenate everything. */ + p = PyString_AS_STRING(res); + for (i = 0; i < seqlen; ++i) { + size_t n; + item = PySequence_Fast_GET_ITEM(seq, i); + n = PyString_GET_SIZE(item); + Py_MEMCPY(p, PyString_AS_STRING(item), n); + p += n; + if (i < seqlen - 1) { + Py_MEMCPY(p, sep, seplen); + p += seplen; + } + } + + Py_DECREF(seq); + return res; +} + +PyObject * +_PyString_Join(PyObject *sep, PyObject *x) +{ + assert(sep != NULL && PyString_Check(sep)); + assert(x != NULL); + return string_join((PyStringObject *)sep, x); +} + +Py_LOCAL_INLINE(void) +string_adjust_indices(Py_ssize_t *start, Py_ssize_t *end, Py_ssize_t len) +{ + if (*end > len) + *end = len; + else if (*end < 0) + *end += len; + if (*end < 0) + *end = 0; + if (*start < 0) + *start += len; + if (*start < 0) + *start = 0; +} + +Py_LOCAL_INLINE(Py_ssize_t) +string_find_internal(PyStringObject *self, PyObject *args, int dir) +{ + PyObject *subobj; + const char *sub; + Py_ssize_t sub_len; + Py_ssize_t start=0, end=PY_SSIZE_T_MAX; + + if (!PyArg_ParseTuple(args, "O|O&O&:find/rfind/index/rindex", &subobj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return -2; + if (PyString_Check(subobj)) { + sub = PyString_AS_STRING(subobj); + sub_len = PyString_GET_SIZE(subobj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(subobj)) + return PyUnicode_Find( + (PyObject *)self, subobj, start, end, dir); +#endif + else if (PyObject_AsCharBuffer(subobj, &sub, &sub_len)) + /* XXX - the "expected a character buffer object" is pretty + confusing for a non-expert. remap to something else ? */ + return -2; + + if (dir > 0) + return stringlib_find_slice( + PyString_AS_STRING(self), PyString_GET_SIZE(self), + sub, sub_len, start, end); + else + return stringlib_rfind_slice( + PyString_AS_STRING(self), PyString_GET_SIZE(self), + sub, sub_len, start, end); +} + + +PyDoc_STRVAR(find__doc__, +"S.find(sub [,start [,end]]) -> int\n\ +\n\ +Return the lowest index in S where substring sub is found,\n\ +such that sub is contained within s[start,end]. Optional\n\ +arguments start and end are interpreted as in slice notation.\n\ +\n\ +Return -1 on failure."); + +static PyObject * +string_find(PyStringObject *self, PyObject *args) +{ + Py_ssize_t result = string_find_internal(self, args, +1); + if (result == -2) + return NULL; + return PyInt_FromSsize_t(result); +} + + +PyDoc_STRVAR(index__doc__, +"S.index(sub [,start [,end]]) -> int\n\ +\n\ +Like S.find() but raise ValueError when the substring is not found."); + +static PyObject * +string_index(PyStringObject *self, PyObject *args) +{ + Py_ssize_t result = string_find_internal(self, args, +1); + if (result == -2) + return NULL; + if (result == -1) { + PyErr_SetString(PyExc_ValueError, + "substring not found"); + return NULL; + } + return PyInt_FromSsize_t(result); +} + + +PyDoc_STRVAR(rfind__doc__, +"S.rfind(sub [,start [,end]]) -> int\n\ +\n\ +Return the highest index in S where substring sub is found,\n\ +such that sub is contained within s[start,end]. Optional\n\ +arguments start and end are interpreted as in slice notation.\n\ +\n\ +Return -1 on failure."); + +static PyObject * +string_rfind(PyStringObject *self, PyObject *args) +{ + Py_ssize_t result = string_find_internal(self, args, -1); + if (result == -2) + return NULL; + return PyInt_FromSsize_t(result); +} + + +PyDoc_STRVAR(rindex__doc__, +"S.rindex(sub [,start [,end]]) -> int\n\ +\n\ +Like S.rfind() but raise ValueError when the substring is not found."); + +static PyObject * +string_rindex(PyStringObject *self, PyObject *args) +{ + Py_ssize_t result = string_find_internal(self, args, -1); + if (result == -2) + return NULL; + if (result == -1) { + PyErr_SetString(PyExc_ValueError, + "substring not found"); + return NULL; + } + return PyInt_FromSsize_t(result); +} + + +Py_LOCAL_INLINE(PyObject *) +do_xstrip(PyStringObject *self, int striptype, PyObject *sepobj) +{ + char *s = PyString_AS_STRING(self); + Py_ssize_t len = PyString_GET_SIZE(self); + char *sep = PyString_AS_STRING(sepobj); + Py_ssize_t seplen = PyString_GET_SIZE(sepobj); + Py_ssize_t i, j; + + i = 0; + if (striptype != RIGHTSTRIP) { + while (i < len && memchr(sep, Py_CHARMASK(s[i]), seplen)) { + i++; + } + } + + j = len; + if (striptype != LEFTSTRIP) { + do { + j--; + } while (j >= i && memchr(sep, Py_CHARMASK(s[j]), seplen)); + j++; + } + + if (i == 0 && j == len && PyString_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*)self; + } + else + return PyString_FromStringAndSize(s+i, j-i); +} + + +Py_LOCAL_INLINE(PyObject *) +do_strip(PyStringObject *self, int striptype) +{ + char *s = PyString_AS_STRING(self); + Py_ssize_t len = PyString_GET_SIZE(self), i, j; + + i = 0; + if (striptype != RIGHTSTRIP) { + while (i < len && isspace(Py_CHARMASK(s[i]))) { + i++; + } + } + + j = len; + if (striptype != LEFTSTRIP) { + do { + j--; + } while (j >= i && isspace(Py_CHARMASK(s[j]))); + j++; + } + + if (i == 0 && j == len && PyString_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*)self; + } + else + return PyString_FromStringAndSize(s+i, j-i); +} + + +Py_LOCAL_INLINE(PyObject *) +do_argstrip(PyStringObject *self, int striptype, PyObject *args) +{ + PyObject *sep = NULL; + + if (!PyArg_ParseTuple(args, (char *)stripformat[striptype], &sep)) + return NULL; + + if (sep != NULL && sep != Py_None) { + if (PyString_Check(sep)) + return do_xstrip(self, striptype, sep); +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(sep)) { + PyObject *uniself = PyUnicode_FromObject((PyObject *)self); + PyObject *res; + if (uniself==NULL) + return NULL; + res = _PyUnicode_XStrip((PyUnicodeObject *)uniself, + striptype, sep); + Py_DECREF(uniself); + return res; + } +#endif + PyErr_Format(PyExc_TypeError, +#ifdef Py_USING_UNICODE + "%s arg must be None, str or unicode", +#else + "%s arg must be None or str", +#endif + STRIPNAME(striptype)); + return NULL; + } + + return do_strip(self, striptype); +} + + +PyDoc_STRVAR(strip__doc__, +"S.strip([chars]) -> string or unicode\n\ +\n\ +Return a copy of the string S with leading and trailing\n\ +whitespace removed.\n\ +If chars is given and not None, remove characters in chars instead.\n\ +If chars is unicode, S will be converted to unicode before stripping"); + +static PyObject * +string_strip(PyStringObject *self, PyObject *args) +{ + if (PyTuple_GET_SIZE(args) == 0) + return do_strip(self, BOTHSTRIP); /* Common case */ + else + return do_argstrip(self, BOTHSTRIP, args); +} + + +PyDoc_STRVAR(lstrip__doc__, +"S.lstrip([chars]) -> string or unicode\n\ +\n\ +Return a copy of the string S with leading whitespace removed.\n\ +If chars is given and not None, remove characters in chars instead.\n\ +If chars is unicode, S will be converted to unicode before stripping"); + +static PyObject * +string_lstrip(PyStringObject *self, PyObject *args) +{ + if (PyTuple_GET_SIZE(args) == 0) + return do_strip(self, LEFTSTRIP); /* Common case */ + else + return do_argstrip(self, LEFTSTRIP, args); +} + + +PyDoc_STRVAR(rstrip__doc__, +"S.rstrip([chars]) -> string or unicode\n\ +\n\ +Return a copy of the string S with trailing whitespace removed.\n\ +If chars is given and not None, remove characters in chars instead.\n\ +If chars is unicode, S will be converted to unicode before stripping"); + +static PyObject * +string_rstrip(PyStringObject *self, PyObject *args) +{ + if (PyTuple_GET_SIZE(args) == 0) + return do_strip(self, RIGHTSTRIP); /* Common case */ + else + return do_argstrip(self, RIGHTSTRIP, args); +} + + +PyDoc_STRVAR(lower__doc__, +"S.lower() -> string\n\ +\n\ +Return a copy of the string S converted to lowercase."); + +/* _tolower and _toupper are defined by SUSv2, but they're not ISO C */ +#ifndef _tolower +#define _tolower tolower +#endif + +static PyObject * +string_lower(PyStringObject *self) +{ + char *s; + Py_ssize_t i, n = PyString_GET_SIZE(self); + PyObject *newobj; + + newobj = PyString_FromStringAndSize(NULL, n); + if (!newobj) + return NULL; + + s = PyString_AS_STRING(newobj); + + Py_MEMCPY(s, PyString_AS_STRING(self), n); + + for (i = 0; i < n; i++) { + int c = Py_CHARMASK(s[i]); + if (isupper(c)) + s[i] = _tolower(c); + } + + return newobj; +} + +PyDoc_STRVAR(upper__doc__, +"S.upper() -> string\n\ +\n\ +Return a copy of the string S converted to uppercase."); + +#ifndef _toupper +#define _toupper toupper +#endif + +static PyObject * +string_upper(PyStringObject *self) +{ + char *s; + Py_ssize_t i, n = PyString_GET_SIZE(self); + PyObject *newobj; + + newobj = PyString_FromStringAndSize(NULL, n); + if (!newobj) + return NULL; + + s = PyString_AS_STRING(newobj); + + Py_MEMCPY(s, PyString_AS_STRING(self), n); + + for (i = 0; i < n; i++) { + int c = Py_CHARMASK(s[i]); + if (islower(c)) + s[i] = _toupper(c); + } + + return newobj; +} + +PyDoc_STRVAR(title__doc__, +"S.title() -> string\n\ +\n\ +Return a titlecased version of S, i.e. words start with uppercase\n\ +characters, all remaining cased characters have lowercase."); + +static PyObject* +string_title(PyStringObject *self) +{ + char *s = PyString_AS_STRING(self), *s_new; + Py_ssize_t i, n = PyString_GET_SIZE(self); + int previous_is_cased = 0; + PyObject *newobj; + + newobj = PyString_FromStringAndSize(NULL, n); + if (newobj == NULL) + return NULL; + s_new = PyString_AsString(newobj); + for (i = 0; i < n; i++) { + int c = Py_CHARMASK(*s++); + if (islower(c)) { + if (!previous_is_cased) + c = toupper(c); + previous_is_cased = 1; + } else if (isupper(c)) { + if (previous_is_cased) + c = tolower(c); + previous_is_cased = 1; + } else + previous_is_cased = 0; + *s_new++ = c; + } + return newobj; +} + +PyDoc_STRVAR(capitalize__doc__, +"S.capitalize() -> string\n\ +\n\ +Return a copy of the string S with only its first character\n\ +capitalized."); + +static PyObject * +string_capitalize(PyStringObject *self) +{ + char *s = PyString_AS_STRING(self), *s_new; + Py_ssize_t i, n = PyString_GET_SIZE(self); + PyObject *newobj; + + newobj = PyString_FromStringAndSize(NULL, n); + if (newobj == NULL) + return NULL; + s_new = PyString_AsString(newobj); + if (0 < n) { + int c = Py_CHARMASK(*s++); + if (islower(c)) + *s_new = toupper(c); + else + *s_new = c; + s_new++; + } + for (i = 1; i < n; i++) { + int c = Py_CHARMASK(*s++); + if (isupper(c)) + *s_new = tolower(c); + else + *s_new = c; + s_new++; + } + return newobj; +} + + +PyDoc_STRVAR(count__doc__, +"S.count(sub[, start[, end]]) -> int\n\ +\n\ +Return the number of non-overlapping occurrences of substring sub in\n\ +string S[start:end]. Optional arguments start and end are interpreted\n\ +as in slice notation."); + +static PyObject * +string_count(PyStringObject *self, PyObject *args) +{ + PyObject *sub_obj; + const char *str = PyString_AS_STRING(self), *sub; + Py_ssize_t sub_len; + Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; + + if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + + if (PyString_Check(sub_obj)) { + sub = PyString_AS_STRING(sub_obj); + sub_len = PyString_GET_SIZE(sub_obj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(sub_obj)) { + Py_ssize_t count; + count = PyUnicode_Count((PyObject *)self, sub_obj, start, end); + if (count == -1) + return NULL; + else + return PyInt_FromSsize_t(count); + } +#endif + else if (PyObject_AsCharBuffer(sub_obj, &sub, &sub_len)) + return NULL; + + string_adjust_indices(&start, &end, PyString_GET_SIZE(self)); + + return PyInt_FromSsize_t( + stringlib_count(str + start, end - start, sub, sub_len) + ); +} + +PyDoc_STRVAR(swapcase__doc__, +"S.swapcase() -> string\n\ +\n\ +Return a copy of the string S with uppercase characters\n\ +converted to lowercase and vice versa."); + +static PyObject * +string_swapcase(PyStringObject *self) +{ + char *s = PyString_AS_STRING(self), *s_new; + Py_ssize_t i, n = PyString_GET_SIZE(self); + PyObject *newobj; + + newobj = PyString_FromStringAndSize(NULL, n); + if (newobj == NULL) + return NULL; + s_new = PyString_AsString(newobj); + for (i = 0; i < n; i++) { + int c = Py_CHARMASK(*s++); + if (islower(c)) { + *s_new = toupper(c); + } + else if (isupper(c)) { + *s_new = tolower(c); + } + else + *s_new = c; + s_new++; + } + return newobj; +} + + +PyDoc_STRVAR(translate__doc__, +"S.translate(table [,deletechars]) -> string\n\ +\n\ +Return a copy of the string S, where all characters occurring\n\ +in the optional argument deletechars are removed, and the\n\ +remaining characters have been mapped through the given\n\ +translation table, which must be a string of length 256."); + +static PyObject * +string_translate(PyStringObject *self, PyObject *args) +{ + register char *input, *output; + register const char *table; + register Py_ssize_t i, c, changed = 0; + PyObject *input_obj = (PyObject*)self; + const char *table1, *output_start, *del_table=NULL; + Py_ssize_t inlen, tablen, dellen = 0; + PyObject *result; + int trans_table[256]; + PyObject *tableobj, *delobj = NULL; + + if (!PyArg_UnpackTuple(args, "translate", 1, 2, + &tableobj, &delobj)) + return NULL; + + if (PyString_Check(tableobj)) { + table1 = PyString_AS_STRING(tableobj); + tablen = PyString_GET_SIZE(tableobj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(tableobj)) { + /* Unicode .translate() does not support the deletechars + parameter; instead a mapping to None will cause characters + to be deleted. */ + if (delobj != NULL) { + PyErr_SetString(PyExc_TypeError, + "deletions are implemented differently for unicode"); + return NULL; + } + return PyUnicode_Translate((PyObject *)self, tableobj, NULL); + } +#endif + else if (PyObject_AsCharBuffer(tableobj, &table1, &tablen)) + return NULL; + + if (tablen != 256) { + PyErr_SetString(PyExc_ValueError, + "translation table must be 256 characters long"); + return NULL; + } + + if (delobj != NULL) { + if (PyString_Check(delobj)) { + del_table = PyString_AS_STRING(delobj); + dellen = PyString_GET_SIZE(delobj); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(delobj)) { + PyErr_SetString(PyExc_TypeError, + "deletions are implemented differently for unicode"); + return NULL; + } +#endif + else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen)) + return NULL; + } + else { + del_table = NULL; + dellen = 0; + } + + table = table1; + inlen = PyString_GET_SIZE(input_obj); + result = PyString_FromStringAndSize((char *)NULL, inlen); + if (result == NULL) + return NULL; + output_start = output = PyString_AsString(result); + input = PyString_AS_STRING(input_obj); + + if (dellen == 0) { + /* If no deletions are required, use faster code */ + for (i = inlen; --i >= 0; ) { + c = Py_CHARMASK(*input++); + if (Py_CHARMASK((*output++ = table[c])) != c) + changed = 1; + } + if (changed || !PyString_CheckExact(input_obj)) + return result; + Py_DECREF(result); + Py_INCREF(input_obj); + return input_obj; + } + + for (i = 0; i < 256; i++) + trans_table[i] = Py_CHARMASK(table[i]); + + for (i = 0; i < dellen; i++) + trans_table[(int) Py_CHARMASK(del_table[i])] = -1; + + for (i = inlen; --i >= 0; ) { + c = Py_CHARMASK(*input++); + if (trans_table[c] != -1) + if (Py_CHARMASK(*output++ = (char)trans_table[c]) == c) + continue; + changed = 1; + } + if (!changed && PyString_CheckExact(input_obj)) { + Py_DECREF(result); + Py_INCREF(input_obj); + return input_obj; + } + /* Fix the size of the resulting string */ + if (inlen > 0) + _PyString_Resize(&result, output - output_start); + return result; +} + + +#define FORWARD 1 +#define REVERSE -1 + +/* find and count characters and substrings */ + +#define findchar(target, target_len, c) \ + ((char *)memchr((const void *)(target), c, target_len)) + +/* String ops must return a string. */ +/* If the object is subclass of string, create a copy */ +Py_LOCAL(PyStringObject *) +return_self(PyStringObject *self) +{ + if (PyString_CheckExact(self)) { + Py_INCREF(self); + return self; + } + return (PyStringObject *)PyString_FromStringAndSize( + PyString_AS_STRING(self), + PyString_GET_SIZE(self)); +} + +Py_LOCAL_INLINE(Py_ssize_t) +countchar(const char *target, int target_len, char c, Py_ssize_t maxcount) +{ + Py_ssize_t count=0; + const char *start=target; + const char *end=target+target_len; + + while ( (start=findchar(start, end-start, c)) != NULL ) { + count++; + if (count >= maxcount) + break; + start += 1; + } + return count; +} + +Py_LOCAL(Py_ssize_t) +findstring(const char *target, Py_ssize_t target_len, + const char *pattern, Py_ssize_t pattern_len, + Py_ssize_t start, + Py_ssize_t end, + int direction) +{ + if (start < 0) { + start += target_len; + if (start < 0) + start = 0; + } + if (end > target_len) { + end = target_len; + } else if (end < 0) { + end += target_len; + if (end < 0) + end = 0; + } + + /* zero-length substrings always match at the first attempt */ + if (pattern_len == 0) + return (direction > 0) ? start : end; + + end -= pattern_len; + + if (direction < 0) { + for (; end >= start; end--) + if (Py_STRING_MATCH(target, end, pattern, pattern_len)) + return end; + } else { + for (; start <= end; start++) + if (Py_STRING_MATCH(target, start, pattern, pattern_len)) + return start; + } + return -1; +} + +Py_LOCAL_INLINE(Py_ssize_t) +countstring(const char *target, Py_ssize_t target_len, + const char *pattern, Py_ssize_t pattern_len, + Py_ssize_t start, + Py_ssize_t end, + int direction, Py_ssize_t maxcount) +{ + Py_ssize_t count=0; + + if (start < 0) { + start += target_len; + if (start < 0) + start = 0; + } + if (end > target_len) { + end = target_len; + } else if (end < 0) { + end += target_len; + if (end < 0) + end = 0; + } + + /* zero-length substrings match everywhere */ + if (pattern_len == 0 || maxcount == 0) { + if (target_len+1 < maxcount) + return target_len+1; + return maxcount; + } + + end -= pattern_len; + if (direction < 0) { + for (; (end >= start); end--) + if (Py_STRING_MATCH(target, end, pattern, pattern_len)) { + count++; + if (--maxcount <= 0) break; + end -= pattern_len-1; + } + } else { + for (; (start <= end); start++) + if (Py_STRING_MATCH(target, start, pattern, pattern_len)) { + count++; + if (--maxcount <= 0) + break; + start += pattern_len-1; + } + } + return count; +} + + +/* Algorithms for different cases of string replacement */ + +/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */ +Py_LOCAL(PyStringObject *) +replace_interleave(PyStringObject *self, + const char *to_s, Py_ssize_t to_len, + Py_ssize_t maxcount) +{ + char *self_s, *result_s; + Py_ssize_t self_len, result_len; + Py_ssize_t count, i, product; + PyStringObject *result; + + self_len = PyString_GET_SIZE(self); + + /* 1 at the end plus 1 after every character */ + count = self_len+1; + if (maxcount < count) + count = maxcount; + + /* Check for overflow */ + /* result_len = count * to_len + self_len; */ + product = count * to_len; + if (product / to_len != count) { + PyErr_SetString(PyExc_OverflowError, + "replace string is too long"); + return NULL; + } + result_len = product + self_len; + if (result_len < 0) { + PyErr_SetString(PyExc_OverflowError, + "replace string is too long"); + return NULL; + } + + if (! (result = (PyStringObject *) + PyString_FromStringAndSize(NULL, result_len)) ) + return NULL; + + self_s = PyString_AS_STRING(self); + result_s = PyString_AS_STRING(result); + + /* TODO: special case single character, which doesn't need memcpy */ + + /* Lay the first one down (guaranteed this will occur) */ + Py_MEMCPY(result_s, to_s, to_len); + result_s += to_len; + count -= 1; + + for (i=0; i<count; i++) { + *result_s++ = *self_s++; + Py_MEMCPY(result_s, to_s, to_len); + result_s += to_len; + } + + /* Copy the rest of the original string */ + Py_MEMCPY(result_s, self_s, self_len-i); + + return result; +} + +/* Special case for deleting a single character */ +/* len(self)>=1, len(from)==1, to="", maxcount>=1 */ +Py_LOCAL(PyStringObject *) +replace_delete_single_character(PyStringObject *self, + char from_c, Py_ssize_t maxcount) +{ + char *self_s, *result_s; + char *start, *next, *end; + Py_ssize_t self_len, result_len; + Py_ssize_t count; + PyStringObject *result; + + self_len = PyString_GET_SIZE(self); + self_s = PyString_AS_STRING(self); + + count = countchar(self_s, self_len, from_c, maxcount); + if (count == 0) { + return return_self(self); + } + + result_len = self_len - count; /* from_len == 1 */ + assert(result_len>=0); + + if ( (result = (PyStringObject *) + PyString_FromStringAndSize(NULL, result_len)) == NULL) + return NULL; + result_s = PyString_AS_STRING(result); + + start = self_s; + end = self_s + self_len; + while (count-- > 0) { + next = findchar(start, end-start, from_c); + if (next == NULL) + break; + Py_MEMCPY(result_s, start, next-start); + result_s += (next-start); + start = next+1; + } + Py_MEMCPY(result_s, start, end-start); + + return result; +} + +/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */ + +Py_LOCAL(PyStringObject *) +replace_delete_substring(PyStringObject *self, + const char *from_s, Py_ssize_t from_len, + Py_ssize_t maxcount) { + char *self_s, *result_s; + char *start, *next, *end; + Py_ssize_t self_len, result_len; + Py_ssize_t count, offset; + PyStringObject *result; + + self_len = PyString_GET_SIZE(self); + self_s = PyString_AS_STRING(self); + + count = countstring(self_s, self_len, + from_s, from_len, + 0, self_len, 1, + maxcount); + + if (count == 0) { + /* no matches */ + return return_self(self); + } + + result_len = self_len - (count * from_len); + assert (result_len>=0); + + if ( (result = (PyStringObject *) + PyString_FromStringAndSize(NULL, result_len)) == NULL ) + return NULL; + + result_s = PyString_AS_STRING(result); + + start = self_s; + end = self_s + self_len; + while (count-- > 0) { + offset = findstring(start, end-start, + from_s, from_len, + 0, end-start, FORWARD); + if (offset == -1) + break; + next = start + offset; + + Py_MEMCPY(result_s, start, next-start); + + result_s += (next-start); + start = next+from_len; + } + Py_MEMCPY(result_s, start, end-start); + return result; +} + +/* len(self)>=1, len(from)==len(to)==1, maxcount>=1 */ +Py_LOCAL(PyStringObject *) +replace_single_character_in_place(PyStringObject *self, + char from_c, char to_c, + Py_ssize_t maxcount) +{ + char *self_s, *result_s, *start, *end, *next; + Py_ssize_t self_len; + PyStringObject *result; + + /* The result string will be the same size */ + self_s = PyString_AS_STRING(self); + self_len = PyString_GET_SIZE(self); + + next = findchar(self_s, self_len, from_c); + + if (next == NULL) { + /* No matches; return the original string */ + return return_self(self); + } + + /* Need to make a new string */ + result = (PyStringObject *) PyString_FromStringAndSize(NULL, self_len); + if (result == NULL) + return NULL; + result_s = PyString_AS_STRING(result); + Py_MEMCPY(result_s, self_s, self_len); + + /* change everything in-place, starting with this one */ + start = result_s + (next-self_s); + *start = to_c; + start++; + end = result_s + self_len; + + while (--maxcount > 0) { + next = findchar(start, end-start, from_c); + if (next == NULL) + break; + *next = to_c; + start = next+1; + } + + return result; +} + +/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */ +Py_LOCAL(PyStringObject *) +replace_substring_in_place(PyStringObject *self, + const char *from_s, Py_ssize_t from_len, + const char *to_s, Py_ssize_t to_len, + Py_ssize_t maxcount) +{ + char *result_s, *start, *end; + char *self_s; + Py_ssize_t self_len, offset; + PyStringObject *result; + + /* The result string will be the same size */ + + self_s = PyString_AS_STRING(self); + self_len = PyString_GET_SIZE(self); + + offset = findstring(self_s, self_len, + from_s, from_len, + 0, self_len, FORWARD); + if (offset == -1) { + /* No matches; return the original string */ + return return_self(self); + } + + /* Need to make a new string */ + result = (PyStringObject *) PyString_FromStringAndSize(NULL, self_len); + if (result == NULL) + return NULL; + result_s = PyString_AS_STRING(result); + Py_MEMCPY(result_s, self_s, self_len); + + /* change everything in-place, starting with this one */ + start = result_s + offset; + Py_MEMCPY(start, to_s, from_len); + start += from_len; + end = result_s + self_len; + + while ( --maxcount > 0) { + offset = findstring(start, end-start, + from_s, from_len, + 0, end-start, FORWARD); + if (offset==-1) + break; + Py_MEMCPY(start+offset, to_s, from_len); + start += offset+from_len; + } + + return result; +} + +/* len(self)>=1, len(from)==1, len(to)>=2, maxcount>=1 */ +Py_LOCAL(PyStringObject *) +replace_single_character(PyStringObject *self, + char from_c, + const char *to_s, Py_ssize_t to_len, + Py_ssize_t maxcount) +{ + char *self_s, *result_s; + char *start, *next, *end; + Py_ssize_t self_len, result_len; + Py_ssize_t count, product; + PyStringObject *result; + + self_s = PyString_AS_STRING(self); + self_len = PyString_GET_SIZE(self); + + count = countchar(self_s, self_len, from_c, maxcount); + if (count == 0) { + /* no matches, return unchanged */ + return return_self(self); + } + + /* use the difference between current and new, hence the "-1" */ + /* result_len = self_len + count * (to_len-1) */ + product = count * (to_len-1); + if (product / (to_len-1) != count) { + PyErr_SetString(PyExc_OverflowError, "replace string is too long"); + return NULL; + } + result_len = self_len + product; + if (result_len < 0) { + PyErr_SetString(PyExc_OverflowError, "replace string is too long"); + return NULL; + } + + if ( (result = (PyStringObject *) + PyString_FromStringAndSize(NULL, result_len)) == NULL) + return NULL; + result_s = PyString_AS_STRING(result); + + start = self_s; + end = self_s + self_len; + while (count-- > 0) { + next = findchar(start, end-start, from_c); + if (next == NULL) + break; + + if (next == start) { + /* replace with the 'to' */ + Py_MEMCPY(result_s, to_s, to_len); + result_s += to_len; + start += 1; + } else { + /* copy the unchanged old then the 'to' */ + Py_MEMCPY(result_s, start, next-start); + result_s += (next-start); + Py_MEMCPY(result_s, to_s, to_len); + result_s += to_len; + start = next+1; + } + } + /* Copy the remainder of the remaining string */ + Py_MEMCPY(result_s, start, end-start); + + return result; +} + +/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */ +Py_LOCAL(PyStringObject *) +replace_substring(PyStringObject *self, + const char *from_s, Py_ssize_t from_len, + const char *to_s, Py_ssize_t to_len, + Py_ssize_t maxcount) { + char *self_s, *result_s; + char *start, *next, *end; + Py_ssize_t self_len, result_len; + Py_ssize_t count, offset, product; + PyStringObject *result; + + self_s = PyString_AS_STRING(self); + self_len = PyString_GET_SIZE(self); + + count = countstring(self_s, self_len, + from_s, from_len, + 0, self_len, FORWARD, maxcount); + if (count == 0) { + /* no matches, return unchanged */ + return return_self(self); + } + + /* Check for overflow */ + /* result_len = self_len + count * (to_len-from_len) */ + product = count * (to_len-from_len); + if (product / (to_len-from_len) != count) { + PyErr_SetString(PyExc_OverflowError, "replace string is too long"); + return NULL; + } + result_len = self_len + product; + if (result_len < 0) { + PyErr_SetString(PyExc_OverflowError, "replace string is too long"); + return NULL; + } + + if ( (result = (PyStringObject *) + PyString_FromStringAndSize(NULL, result_len)) == NULL) + return NULL; + result_s = PyString_AS_STRING(result); + + start = self_s; + end = self_s + self_len; + while (count-- > 0) { + offset = findstring(start, end-start, + from_s, from_len, + 0, end-start, FORWARD); + if (offset == -1) + break; + next = start+offset; + if (next == start) { + /* replace with the 'to' */ + Py_MEMCPY(result_s, to_s, to_len); + result_s += to_len; + start += from_len; + } else { + /* copy the unchanged old then the 'to' */ + Py_MEMCPY(result_s, start, next-start); + result_s += (next-start); + Py_MEMCPY(result_s, to_s, to_len); + result_s += to_len; + start = next+from_len; + } + } + /* Copy the remainder of the remaining string */ + Py_MEMCPY(result_s, start, end-start); + + return result; +} + + +Py_LOCAL(PyStringObject *) +replace(PyStringObject *self, + const char *from_s, Py_ssize_t from_len, + const char *to_s, Py_ssize_t to_len, + Py_ssize_t maxcount) +{ + if (maxcount < 0) { + maxcount = PY_SSIZE_T_MAX; + } else if (maxcount == 0 || PyString_GET_SIZE(self) == 0) { + /* nothing to do; return the original string */ + return return_self(self); + } + + if (maxcount == 0 || + (from_len == 0 && to_len == 0)) { + /* nothing to do; return the original string */ + return return_self(self); + } + + /* Handle zero-length special cases */ + + if (from_len == 0) { + /* insert the 'to' string everywhere. */ + /* >>> "Python".replace("", ".") */ + /* '.P.y.t.h.o.n.' */ + return replace_interleave(self, to_s, to_len, maxcount); + } + + /* Except for "".replace("", "A") == "A" there is no way beyond this */ + /* point for an empty self string to generate a non-empty string */ + /* Special case so the remaining code always gets a non-empty string */ + if (PyString_GET_SIZE(self) == 0) { + return return_self(self); + } + + if (to_len == 0) { + /* delete all occurances of 'from' string */ + if (from_len == 1) { + return replace_delete_single_character( + self, from_s[0], maxcount); + } else { + return replace_delete_substring(self, from_s, from_len, maxcount); + } + } + + /* Handle special case where both strings have the same length */ + + if (from_len == to_len) { + if (from_len == 1) { + return replace_single_character_in_place( + self, + from_s[0], + to_s[0], + maxcount); + } else { + return replace_substring_in_place( + self, from_s, from_len, to_s, to_len, maxcount); + } + } + + /* Otherwise use the more generic algorithms */ + if (from_len == 1) { + return replace_single_character(self, from_s[0], + to_s, to_len, maxcount); + } else { + /* len('from')>=2, len('to')>=1 */ + return replace_substring(self, from_s, from_len, to_s, to_len, maxcount); + } +} + +PyDoc_STRVAR(replace__doc__, +"S.replace (old, new[, count]) -> string\n\ +\n\ +Return a copy of string S with all occurrences of substring\n\ +old replaced by new. If the optional argument count is\n\ +given, only the first count occurrences are replaced."); + +static PyObject * +string_replace(PyStringObject *self, PyObject *args) +{ + Py_ssize_t count = -1; + PyObject *from, *to; + const char *from_s, *to_s; + Py_ssize_t from_len, to_len; + + if (!PyArg_ParseTuple(args, "OO|n:replace", &from, &to, &count)) + return NULL; + + if (PyString_Check(from)) { + from_s = PyString_AS_STRING(from); + from_len = PyString_GET_SIZE(from); + } +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(from)) + return PyUnicode_Replace((PyObject *)self, + from, to, count); +#endif + else if (PyObject_AsCharBuffer(from, &from_s, &from_len)) + return NULL; + + if (PyString_Check(to)) { + to_s = PyString_AS_STRING(to); + to_len = PyString_GET_SIZE(to); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(to)) + return PyUnicode_Replace((PyObject *)self, + from, to, count); +#endif + else if (PyObject_AsCharBuffer(to, &to_s, &to_len)) + return NULL; + + return (PyObject *)replace((PyStringObject *) self, + from_s, from_len, + to_s, to_len, count); +} + +/** End DALKE **/ + +/* Matches the end (direction >= 0) or start (direction < 0) of self + * against substr, using the start and end arguments. Returns + * -1 on error, 0 if not found and 1 if found. + */ +Py_LOCAL(int) +_string_tailmatch(PyStringObject *self, PyObject *substr, Py_ssize_t start, + Py_ssize_t end, int direction) +{ + Py_ssize_t len = PyString_GET_SIZE(self); + Py_ssize_t slen; + const char* sub; + const char* str; + + if (PyString_Check(substr)) { + sub = PyString_AS_STRING(substr); + slen = PyString_GET_SIZE(substr); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(substr)) + return PyUnicode_Tailmatch((PyObject *)self, + substr, start, end, direction); +#endif + else if (PyObject_AsCharBuffer(substr, &sub, &slen)) + return -1; + str = PyString_AS_STRING(self); + + string_adjust_indices(&start, &end, len); + + if (direction < 0) { + /* startswith */ + if (start+slen > len) + return 0; + } else { + /* endswith */ + if (end-start < slen || start > len) + return 0; + + if (end-slen > start) + start = end - slen; + } + if (end-start >= slen) + return ! memcmp(str+start, sub, slen); + return 0; +} + + +PyDoc_STRVAR(startswith__doc__, +"S.startswith(prefix[, start[, end]]) -> bool\n\ +\n\ +Return True if S starts with the specified prefix, False otherwise.\n\ +With optional start, test S beginning at that position.\n\ +With optional end, stop comparing S at that position.\n\ +prefix can also be a tuple of strings to try."); + +static PyObject * +string_startswith(PyStringObject *self, PyObject *args) +{ + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + PyObject *subobj; + int result; + + if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + if (PyTuple_Check(subobj)) { + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { + result = _string_tailmatch(self, + PyTuple_GET_ITEM(subobj, i), + start, end, -1); + if (result == -1) + return NULL; + else if (result) { + Py_RETURN_TRUE; + } + } + Py_RETURN_FALSE; + } + result = _string_tailmatch(self, subobj, start, end, -1); + if (result == -1) + return NULL; + else + return PyBool_FromLong(result); +} + + +PyDoc_STRVAR(endswith__doc__, +"S.endswith(suffix[, start[, end]]) -> bool\n\ +\n\ +Return True if S ends with the specified suffix, False otherwise.\n\ +With optional start, test S beginning at that position.\n\ +With optional end, stop comparing S at that position.\n\ +suffix can also be a tuple of strings to try."); + +static PyObject * +string_endswith(PyStringObject *self, PyObject *args) +{ + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + PyObject *subobj; + int result; + + if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + if (PyTuple_Check(subobj)) { + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { + result = _string_tailmatch(self, + PyTuple_GET_ITEM(subobj, i), + start, end, +1); + if (result == -1) + return NULL; + else if (result) { + Py_RETURN_TRUE; + } + } + Py_RETURN_FALSE; + } + result = _string_tailmatch(self, subobj, start, end, +1); + if (result == -1) + return NULL; + else + return PyBool_FromLong(result); +} + + +PyDoc_STRVAR(encode__doc__, +"S.encode([encoding[,errors]]) -> object\n\ +\n\ +Encodes S using the codec registered for encoding. encoding defaults\n\ +to the default encoding. errors may be given to set a different error\n\ +handling scheme. Default is 'strict' meaning that encoding errors raise\n\ +a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and\n\ +'xmlcharrefreplace' as well as any other name registered with\n\ +codecs.register_error that is able to handle UnicodeEncodeErrors."); + +static PyObject * +string_encode(PyStringObject *self, PyObject *args) +{ + char *encoding = NULL; + char *errors = NULL; + PyObject *v; + + if (!PyArg_ParseTuple(args, "|ss:encode", &encoding, &errors)) + return NULL; + v = PyString_AsEncodedObject((PyObject *)self, encoding, errors); + if (v == NULL) + goto onError; + if (!PyString_Check(v) && !PyUnicode_Check(v)) { + PyErr_Format(PyExc_TypeError, + "encoder did not return a string/unicode object " + "(type=%.400s)", + v->ob_type->tp_name); + Py_DECREF(v); + return NULL; + } + return v; + + onError: + return NULL; +} + + +PyDoc_STRVAR(decode__doc__, +"S.decode([encoding[,errors]]) -> object\n\ +\n\ +Decodes S using the codec registered for encoding. encoding defaults\n\ +to the default encoding. errors may be given to set a different error\n\ +handling scheme. Default is 'strict' meaning that encoding errors raise\n\ +a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'\n\ +as well as any other name registerd with codecs.register_error that is\n\ +able to handle UnicodeDecodeErrors."); + +static PyObject * +string_decode(PyStringObject *self, PyObject *args) +{ + char *encoding = NULL; + char *errors = NULL; + PyObject *v; + + if (!PyArg_ParseTuple(args, "|ss:decode", &encoding, &errors)) + return NULL; + v = PyString_AsDecodedObject((PyObject *)self, encoding, errors); + if (v == NULL) + goto onError; + if (!PyString_Check(v) && !PyUnicode_Check(v)) { + PyErr_Format(PyExc_TypeError, + "decoder did not return a string/unicode object " + "(type=%.400s)", + v->ob_type->tp_name); + Py_DECREF(v); + return NULL; + } + return v; + + onError: + return NULL; +} + + +PyDoc_STRVAR(expandtabs__doc__, +"S.expandtabs([tabsize]) -> string\n\ +\n\ +Return a copy of S where all tab characters are expanded using spaces.\n\ +If tabsize is not given, a tab size of 8 characters is assumed."); + +static PyObject* +string_expandtabs(PyStringObject *self, PyObject *args) +{ + const char *e, *p; + char *q; + Py_ssize_t i, j; + PyObject *u; + int tabsize = 8; + + if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize)) + return NULL; + + /* First pass: determine size of output string */ + i = j = 0; + e = PyString_AS_STRING(self) + PyString_GET_SIZE(self); + for (p = PyString_AS_STRING(self); p < e; p++) + if (*p == '\t') { + if (tabsize > 0) + j += tabsize - (j % tabsize); + } + else { + j++; + if (*p == '\n' || *p == '\r') { + i += j; + j = 0; + } + } + + /* Second pass: create output string and fill it */ + u = PyString_FromStringAndSize(NULL, i + j); + if (!u) + return NULL; + + j = 0; + q = PyString_AS_STRING(u); + + for (p = PyString_AS_STRING(self); p < e; p++) + if (*p == '\t') { + if (tabsize > 0) { + i = tabsize - (j % tabsize); + j += i; + while (i--) + *q++ = ' '; + } + } + else { + j++; + *q++ = *p; + if (*p == '\n' || *p == '\r') + j = 0; + } + + return u; +} + +Py_LOCAL_INLINE(PyObject *) +pad(PyStringObject *self, Py_ssize_t left, Py_ssize_t right, char fill) +{ + PyObject *u; + + if (left < 0) + left = 0; + if (right < 0) + right = 0; + + if (left == 0 && right == 0 && PyString_CheckExact(self)) { + Py_INCREF(self); + return (PyObject *)self; + } + + u = PyString_FromStringAndSize(NULL, + left + PyString_GET_SIZE(self) + right); + if (u) { + if (left) + memset(PyString_AS_STRING(u), fill, left); + Py_MEMCPY(PyString_AS_STRING(u) + left, + PyString_AS_STRING(self), + PyString_GET_SIZE(self)); + if (right) + memset(PyString_AS_STRING(u) + left + PyString_GET_SIZE(self), + fill, right); + } + + return u; +} + +PyDoc_STRVAR(ljust__doc__, +"S.ljust(width[, fillchar]) -> string\n" +"\n" +"Return S left justified in a string of length width. Padding is\n" +"done using the specified fill character (default is a space)."); + +static PyObject * +string_ljust(PyStringObject *self, PyObject *args) +{ + Py_ssize_t width; + char fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|c:ljust", &width, &fillchar)) + return NULL; + + if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + + return pad(self, 0, width - PyString_GET_SIZE(self), fillchar); +} + + +PyDoc_STRVAR(rjust__doc__, +"S.rjust(width[, fillchar]) -> string\n" +"\n" +"Return S right justified in a string of length width. Padding is\n" +"done using the specified fill character (default is a space)"); + +static PyObject * +string_rjust(PyStringObject *self, PyObject *args) +{ + Py_ssize_t width; + char fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|c:rjust", &width, &fillchar)) + return NULL; + + if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + + return pad(self, width - PyString_GET_SIZE(self), 0, fillchar); +} + + +PyDoc_STRVAR(center__doc__, +"S.center(width[, fillchar]) -> string\n" +"\n" +"Return S centered in a string of length width. Padding is\n" +"done using the specified fill character (default is a space)"); + +static PyObject * +string_center(PyStringObject *self, PyObject *args) +{ + Py_ssize_t marg, left; + Py_ssize_t width; + char fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|c:center", &width, &fillchar)) + return NULL; + + if (PyString_GET_SIZE(self) >= width && PyString_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + + marg = width - PyString_GET_SIZE(self); + left = marg / 2 + (marg & width & 1); + + return pad(self, left, marg - left, fillchar); +} + +PyDoc_STRVAR(zfill__doc__, +"S.zfill(width) -> string\n" +"\n" +"Pad a numeric string S with zeros on the left, to fill a field\n" +"of the specified width. The string S is never truncated."); + +static PyObject * +string_zfill(PyStringObject *self, PyObject *args) +{ + Py_ssize_t fill; + PyObject *s; + char *p; + Py_ssize_t width; + + if (!PyArg_ParseTuple(args, "n:zfill", &width)) + return NULL; + + if (PyString_GET_SIZE(self) >= width) { + if (PyString_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + else + return PyString_FromStringAndSize( + PyString_AS_STRING(self), + PyString_GET_SIZE(self) + ); + } + + fill = width - PyString_GET_SIZE(self); + + s = pad(self, fill, 0, '0'); + + if (s == NULL) + return NULL; + + p = PyString_AS_STRING(s); + if (p[fill] == '+' || p[fill] == '-') { + /* move sign to beginning of string */ + p[0] = p[fill]; + p[fill] = '0'; + } + + return (PyObject*) s; +} + +PyDoc_STRVAR(isspace__doc__, +"S.isspace() -> bool\n\ +\n\ +Return True if all characters in S are whitespace\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +string_isspace(PyStringObject *self) +{ + register const unsigned char *p + = (unsigned char *) PyString_AS_STRING(self); + register const unsigned char *e; + + /* Shortcut for single character strings */ + if (PyString_GET_SIZE(self) == 1 && + isspace(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyString_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyString_GET_SIZE(self); + for (; p < e; p++) { + if (!isspace(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + + +PyDoc_STRVAR(isalpha__doc__, +"S.isalpha() -> bool\n\ +\n\ +Return True if all characters in S are alphabetic\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +string_isalpha(PyStringObject *self) +{ + register const unsigned char *p + = (unsigned char *) PyString_AS_STRING(self); + register const unsigned char *e; + + /* Shortcut for single character strings */ + if (PyString_GET_SIZE(self) == 1 && + isalpha(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyString_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyString_GET_SIZE(self); + for (; p < e; p++) { + if (!isalpha(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + + +PyDoc_STRVAR(isalnum__doc__, +"S.isalnum() -> bool\n\ +\n\ +Return True if all characters in S are alphanumeric\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +string_isalnum(PyStringObject *self) +{ + register const unsigned char *p + = (unsigned char *) PyString_AS_STRING(self); + register const unsigned char *e; + + /* Shortcut for single character strings */ + if (PyString_GET_SIZE(self) == 1 && + isalnum(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyString_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyString_GET_SIZE(self); + for (; p < e; p++) { + if (!isalnum(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + + +PyDoc_STRVAR(isdigit__doc__, +"S.isdigit() -> bool\n\ +\n\ +Return True if all characters in S are digits\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +string_isdigit(PyStringObject *self) +{ + register const unsigned char *p + = (unsigned char *) PyString_AS_STRING(self); + register const unsigned char *e; + + /* Shortcut for single character strings */ + if (PyString_GET_SIZE(self) == 1 && + isdigit(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyString_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyString_GET_SIZE(self); + for (; p < e; p++) { + if (!isdigit(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + + +PyDoc_STRVAR(islower__doc__, +"S.islower() -> bool\n\ +\n\ +Return True if all cased characters in S are lowercase and there is\n\ +at least one cased character in S, False otherwise."); + +static PyObject* +string_islower(PyStringObject *self) +{ + register const unsigned char *p + = (unsigned char *) PyString_AS_STRING(self); + register const unsigned char *e; + int cased; + + /* Shortcut for single character strings */ + if (PyString_GET_SIZE(self) == 1) + return PyBool_FromLong(islower(*p) != 0); + + /* Special case for empty strings */ + if (PyString_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyString_GET_SIZE(self); + cased = 0; + for (; p < e; p++) { + if (isupper(*p)) + return PyBool_FromLong(0); + else if (!cased && islower(*p)) + cased = 1; + } + return PyBool_FromLong(cased); +} + + +PyDoc_STRVAR(isupper__doc__, +"S.isupper() -> bool\n\ +\n\ +Return True if all cased characters in S are uppercase and there is\n\ +at least one cased character in S, False otherwise."); + +static PyObject* +string_isupper(PyStringObject *self) +{ + register const unsigned char *p + = (unsigned char *) PyString_AS_STRING(self); + register const unsigned char *e; + int cased; + + /* Shortcut for single character strings */ + if (PyString_GET_SIZE(self) == 1) + return PyBool_FromLong(isupper(*p) != 0); + + /* Special case for empty strings */ + if (PyString_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyString_GET_SIZE(self); + cased = 0; + for (; p < e; p++) { + if (islower(*p)) + return PyBool_FromLong(0); + else if (!cased && isupper(*p)) + cased = 1; + } + return PyBool_FromLong(cased); +} + + +PyDoc_STRVAR(istitle__doc__, +"S.istitle() -> bool\n\ +\n\ +Return True if S is a titlecased string and there is at least one\n\ +character in S, i.e. uppercase characters may only follow uncased\n\ +characters and lowercase characters only cased ones. Return False\n\ +otherwise."); + +static PyObject* +string_istitle(PyStringObject *self, PyObject *uncased) +{ + register const unsigned char *p + = (unsigned char *) PyString_AS_STRING(self); + register const unsigned char *e; + int cased, previous_is_cased; + + /* Shortcut for single character strings */ + if (PyString_GET_SIZE(self) == 1) + return PyBool_FromLong(isupper(*p) != 0); + + /* Special case for empty strings */ + if (PyString_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyString_GET_SIZE(self); + cased = 0; + previous_is_cased = 0; + for (; p < e; p++) { + register const unsigned char ch = *p; + + if (isupper(ch)) { + if (previous_is_cased) + return PyBool_FromLong(0); + previous_is_cased = 1; + cased = 1; + } + else if (islower(ch)) { + if (!previous_is_cased) + return PyBool_FromLong(0); + previous_is_cased = 1; + cased = 1; + } + else + previous_is_cased = 0; + } + return PyBool_FromLong(cased); +} + + +PyDoc_STRVAR(splitlines__doc__, +"S.splitlines([keepends]) -> list of strings\n\ +\n\ +Return a list of the lines in S, breaking at line boundaries.\n\ +Line breaks are not included in the resulting list unless keepends\n\ +is given and true."); + +static PyObject* +string_splitlines(PyStringObject *self, PyObject *args) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len; + int keepends = 0; + PyObject *list; + PyObject *str; + char *data; + + if (!PyArg_ParseTuple(args, "|i:splitlines", &keepends)) + return NULL; + + data = PyString_AS_STRING(self); + len = PyString_GET_SIZE(self); + + /* This does not use the preallocated list because splitlines is + usually run with hundreds of newlines. The overhead of + switching between PyList_SET_ITEM and append causes about a + 2-3% slowdown for that common case. A smarter implementation + could move the if check out, so the SET_ITEMs are done first + and the appends only done when the prealloc buffer is full. + That's too much work for little gain.*/ + + list = PyList_New(0); + if (!list) + goto onError; + + for (i = j = 0; i < len; ) { + Py_ssize_t eol; + + /* Find a line and append it */ + while (i < len && data[i] != '\n' && data[i] != '\r') + i++; + + /* Skip the line break reading CRLF as one line break */ + eol = i; + if (i < len) { + if (data[i] == '\r' && i + 1 < len && + data[i+1] == '\n') + i += 2; + else + i++; + if (keepends) + eol = i; + } + SPLIT_APPEND(data, j, eol); + j = i; + } + if (j < len) { + SPLIT_APPEND(data, j, len); + } + + return list; + + onError: + Py_XDECREF(list); + return NULL; +} + +#undef SPLIT_APPEND +#undef SPLIT_ADD +#undef MAX_PREALLOC +#undef PREALLOC_SIZE + +static PyObject * +string_getnewargs(PyStringObject *v) +{ + return Py_BuildValue("(s#)", v->ob_sval, v->ob_size); +} + + +static PyMethodDef +string_methods[] = { + /* Counterparts of the obsolete stropmodule functions; except + string.maketrans(). */ + {"join", (PyCFunction)string_join, METH_O, join__doc__}, + {"split", (PyCFunction)string_split, METH_VARARGS, split__doc__}, + {"rsplit", (PyCFunction)string_rsplit, METH_VARARGS, rsplit__doc__}, + {"lower", (PyCFunction)string_lower, METH_NOARGS, lower__doc__}, + {"upper", (PyCFunction)string_upper, METH_NOARGS, upper__doc__}, + {"islower", (PyCFunction)string_islower, METH_NOARGS, islower__doc__}, + {"isupper", (PyCFunction)string_isupper, METH_NOARGS, isupper__doc__}, + {"isspace", (PyCFunction)string_isspace, METH_NOARGS, isspace__doc__}, + {"isdigit", (PyCFunction)string_isdigit, METH_NOARGS, isdigit__doc__}, + {"istitle", (PyCFunction)string_istitle, METH_NOARGS, istitle__doc__}, + {"isalpha", (PyCFunction)string_isalpha, METH_NOARGS, isalpha__doc__}, + {"isalnum", (PyCFunction)string_isalnum, METH_NOARGS, isalnum__doc__}, + {"capitalize", (PyCFunction)string_capitalize, METH_NOARGS, + capitalize__doc__}, + {"count", (PyCFunction)string_count, METH_VARARGS, count__doc__}, + {"endswith", (PyCFunction)string_endswith, METH_VARARGS, + endswith__doc__}, + {"partition", (PyCFunction)string_partition, METH_O, partition__doc__}, + {"find", (PyCFunction)string_find, METH_VARARGS, find__doc__}, + {"index", (PyCFunction)string_index, METH_VARARGS, index__doc__}, + {"lstrip", (PyCFunction)string_lstrip, METH_VARARGS, lstrip__doc__}, + {"replace", (PyCFunction)string_replace, METH_VARARGS, replace__doc__}, + {"rfind", (PyCFunction)string_rfind, METH_VARARGS, rfind__doc__}, + {"rindex", (PyCFunction)string_rindex, METH_VARARGS, rindex__doc__}, + {"rstrip", (PyCFunction)string_rstrip, METH_VARARGS, rstrip__doc__}, + {"rpartition", (PyCFunction)string_rpartition, METH_O, + rpartition__doc__}, + {"startswith", (PyCFunction)string_startswith, METH_VARARGS, + startswith__doc__}, + {"strip", (PyCFunction)string_strip, METH_VARARGS, strip__doc__}, + {"swapcase", (PyCFunction)string_swapcase, METH_NOARGS, + swapcase__doc__}, + {"translate", (PyCFunction)string_translate, METH_VARARGS, + translate__doc__}, + {"title", (PyCFunction)string_title, METH_NOARGS, title__doc__}, + {"ljust", (PyCFunction)string_ljust, METH_VARARGS, ljust__doc__}, + {"rjust", (PyCFunction)string_rjust, METH_VARARGS, rjust__doc__}, + {"center", (PyCFunction)string_center, METH_VARARGS, center__doc__}, + {"zfill", (PyCFunction)string_zfill, METH_VARARGS, zfill__doc__}, + {"encode", (PyCFunction)string_encode, METH_VARARGS, encode__doc__}, + {"decode", (PyCFunction)string_decode, METH_VARARGS, decode__doc__}, + {"expandtabs", (PyCFunction)string_expandtabs, METH_VARARGS, + expandtabs__doc__}, + {"splitlines", (PyCFunction)string_splitlines, METH_VARARGS, + splitlines__doc__}, + {"__getnewargs__", (PyCFunction)string_getnewargs, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static PyObject * +string_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *x = NULL; + static char *kwlist[] = {"object", 0}; + + if (type != &PyString_Type) + return str_subtype_new(type, args, kwds); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:str", kwlist, &x)) + return NULL; + if (x == NULL) + return PyString_FromString(""); + return PyObject_Str(x); +} + +static PyObject * +str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *tmp, *pnew; + Py_ssize_t n; + + assert(PyType_IsSubtype(type, &PyString_Type)); + tmp = string_new(&PyString_Type, args, kwds); + if (tmp == NULL) + return NULL; + assert(PyString_CheckExact(tmp)); + n = PyString_GET_SIZE(tmp); + pnew = type->tp_alloc(type, n); + if (pnew != NULL) { + Py_MEMCPY(PyString_AS_STRING(pnew), PyString_AS_STRING(tmp), n+1); + ((PyStringObject *)pnew)->ob_shash = + ((PyStringObject *)tmp)->ob_shash; + ((PyStringObject *)pnew)->ob_sstate = SSTATE_NOT_INTERNED; + } + Py_DECREF(tmp); + return pnew; +} + +static PyObject * +basestring_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_TypeError, + "The basestring type cannot be instantiated"); + return NULL; +} + +static PyObject * +string_mod(PyObject *v, PyObject *w) +{ + if (!PyString_Check(v)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyString_Format(v, w); +} + +PyDoc_STRVAR(basestring_doc, +"Type basestring cannot be instantiated; it is the base for str and unicode."); + +static PyNumberMethods string_as_number = { + 0, /*nb_add*/ + 0, /*nb_subtract*/ + 0, /*nb_multiply*/ + 0, /*nb_divide*/ + string_mod, /*nb_remainder*/ +}; + + +PyTypeObject PyBaseString_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "basestring", + 0, + 0, + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + basestring_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + basestring_new, /* tp_new */ + 0, /* tp_free */ +}; + +PyDoc_STRVAR(string_doc, +"str(object) -> string\n\ +\n\ +Return a nice string representation of the object.\n\ +If the argument is a string, the return value is the same object."); + +PyTypeObject PyString_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "str", + sizeof(PyStringObject), + sizeof(char), + string_dealloc, /* tp_dealloc */ + (printfunc)string_print, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + string_repr, /* tp_repr */ + &string_as_number, /* tp_as_number */ + &string_as_sequence, /* tp_as_sequence */ + &string_as_mapping, /* tp_as_mapping */ + (hashfunc)string_hash, /* tp_hash */ + 0, /* tp_call */ + string_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + &string_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + string_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + (richcmpfunc)string_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + string_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyBaseString_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + string_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + +void +PyString_Concat(register PyObject **pv, register PyObject *w) +{ + register PyObject *v; + if (*pv == NULL) + return; + if (w == NULL || !PyString_Check(*pv)) { + Py_DECREF(*pv); + *pv = NULL; + return; + } + v = string_concat((PyStringObject *) *pv, w); + Py_DECREF(*pv); + *pv = v; +} + +void +PyString_ConcatAndDel(register PyObject **pv, register PyObject *w) +{ + PyString_Concat(pv, w); + Py_XDECREF(w); +} + + +/* The following function breaks the notion that strings are immutable: + it changes the size of a string. We get away with this only if there + is only one module referencing the object. You can also think of it + as creating a new string object and destroying the old one, only + more efficiently. In any case, don't use this if the string may + already be known to some other part of the code... + Note that if there's not enough memory to resize the string, the original + string object at *pv is deallocated, *pv is set to NULL, an "out of + memory" exception is set, and -1 is returned. Else (on success) 0 is + returned, and the value in *pv may or may not be the same as on input. + As always, an extra byte is allocated for a trailing \0 byte (newsize + does *not* include that), and a trailing \0 byte is stored. +*/ + +int +_PyString_Resize(PyObject **pv, Py_ssize_t newsize) +{ + register PyObject *v; + register PyStringObject *sv; + v = *pv; + if (!PyString_Check(v) || v->ob_refcnt != 1 || newsize < 0 || + PyString_CHECK_INTERNED(v)) { + *pv = 0; + Py_DECREF(v); + PyErr_BadInternalCall(); + return -1; + } + /* XXX UNREF/NEWREF interface should be more symmetrical */ + _Py_DEC_REFTOTAL; + _Py_ForgetReference(v); + *pv = (PyObject *) + PyObject_REALLOC((char *)v, sizeof(PyStringObject) + newsize); + if (*pv == NULL) { + PyObject_Del(v); + PyErr_NoMemory(); + return -1; + } + _Py_NewReference(*pv); + sv = (PyStringObject *) *pv; + sv->ob_size = newsize; + sv->ob_sval[newsize] = '\0'; + sv->ob_shash = -1; /* invalidate cached hash value */ + return 0; +} + +/* Helpers for formatstring */ + +Py_LOCAL_INLINE(PyObject *) +getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) +{ + Py_ssize_t argidx = *p_argidx; + if (argidx < arglen) { + (*p_argidx)++; + if (arglen < 0) + return args; + else + return PyTuple_GetItem(args, argidx); + } + PyErr_SetString(PyExc_TypeError, + "not enough arguments for format string"); + return NULL; +} + +/* Format codes + * F_LJUST '-' + * F_SIGN '+' + * F_BLANK ' ' + * F_ALT '#' + * F_ZERO '0' + */ +#define F_LJUST (1<<0) +#define F_SIGN (1<<1) +#define F_BLANK (1<<2) +#define F_ALT (1<<3) +#define F_ZERO (1<<4) + +Py_LOCAL_INLINE(int) +formatfloat(char *buf, size_t buflen, int flags, + int prec, int type, PyObject *v) +{ + /* fmt = '%#.' + `prec` + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/ + char fmt[20]; + double x; + x = PyFloat_AsDouble(v); + if (x == -1.0 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "float argument required"); + return -1; + } + if (prec < 0) + prec = 6; + if (type == 'f' && fabs(x)/1e25 >= 1e25) + type = 'g'; + /* Worst case length calc to ensure no buffer overrun: + + 'g' formats: + fmt = %#.<prec>g + buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp + for any double rep.) + len = 1 + prec + 1 + 2 + 5 = 9 + prec + + 'f' formats: + buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) + len = 1 + 50 + 1 + prec = 52 + prec + + If prec=0 the effective precision is 1 (the leading digit is + always given), therefore increase the length by one. + + */ + if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) || + (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) { + PyErr_SetString(PyExc_OverflowError, + "formatted float is too long (precision too large?)"); + return -1; + } + PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c", + (flags&F_ALT) ? "#" : "", + prec, type); + PyOS_ascii_formatd(buf, buflen, fmt, x); + return (int)strlen(buf); +} + +/* _PyString_FormatLong emulates the format codes d, u, o, x and X, and + * the F_ALT flag, for Python's long (unbounded) ints. It's not used for + * Python's regular ints. + * Return value: a new PyString*, or NULL if error. + * . *pbuf is set to point into it, + * *plen set to the # of chars following that. + * Caller must decref it when done using pbuf. + * The string starting at *pbuf is of the form + * "-"? ("0x" | "0X")? digit+ + * "0x"/"0X" are present only for x and X conversions, with F_ALT + * set in flags. The case of hex digits will be correct, + * There will be at least prec digits, zero-filled on the left if + * necessary to get that many. + * val object to be converted + * flags bitmask of format flags; only F_ALT is looked at + * prec minimum number of digits; 0-fill on left if needed + * type a character in [duoxX]; u acts the same as d + * + * CAUTION: o, x and X conversions on regular ints can never + * produce a '-' sign, but can for Python's unbounded ints. + */ +PyObject* +_PyString_FormatLong(PyObject *val, int flags, int prec, int type, + char **pbuf, int *plen) +{ + PyObject *result = NULL; + char *buf; + Py_ssize_t i; + int sign; /* 1 if '-', else 0 */ + int len; /* number of characters */ + Py_ssize_t llen; + int numdigits; /* len == numnondigits + numdigits */ + int numnondigits = 0; + + switch (type) { + case 'd': + case 'u': + result = val->ob_type->tp_str(val); + break; + case 'o': + result = val->ob_type->tp_as_number->nb_oct(val); + break; + case 'x': + case 'X': + numnondigits = 2; + result = val->ob_type->tp_as_number->nb_hex(val); + break; + default: + assert(!"'type' not in [duoxX]"); + } + if (!result) + return NULL; + + buf = PyString_AsString(result); + if (!buf) { + Py_DECREF(result); + return NULL; + } + + /* To modify the string in-place, there can only be one reference. */ + if (result->ob_refcnt != 1) { + PyErr_BadInternalCall(); + return NULL; + } + llen = PyString_Size(result); + if (llen > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "string too large in _PyString_FormatLong"); + return NULL; + } + len = (int)llen; + if (buf[len-1] == 'L') { + --len; + buf[len] = '\0'; + } + sign = buf[0] == '-'; + numnondigits += sign; + numdigits = len - numnondigits; + assert(numdigits > 0); + + /* Get rid of base marker unless F_ALT */ + if ((flags & F_ALT) == 0) { + /* Need to skip 0x, 0X or 0. */ + int skipped = 0; + switch (type) { + case 'o': + assert(buf[sign] == '0'); + /* If 0 is only digit, leave it alone. */ + if (numdigits > 1) { + skipped = 1; + --numdigits; + } + break; + case 'x': + case 'X': + assert(buf[sign] == '0'); + assert(buf[sign + 1] == 'x'); + skipped = 2; + numnondigits -= 2; + break; + } + if (skipped) { + buf += skipped; + len -= skipped; + if (sign) + buf[0] = '-'; + } + assert(len == numnondigits + numdigits); + assert(numdigits > 0); + } + + /* Fill with leading zeroes to meet minimum width. */ + if (prec > numdigits) { + PyObject *r1 = PyString_FromStringAndSize(NULL, + numnondigits + prec); + char *b1; + if (!r1) { + Py_DECREF(result); + return NULL; + } + b1 = PyString_AS_STRING(r1); + for (i = 0; i < numnondigits; ++i) + *b1++ = *buf++; + for (i = 0; i < prec - numdigits; i++) + *b1++ = '0'; + for (i = 0; i < numdigits; i++) + *b1++ = *buf++; + *b1 = '\0'; + Py_DECREF(result); + result = r1; + buf = PyString_AS_STRING(result); + len = numnondigits + prec; + } + + /* Fix up case for hex conversions. */ + if (type == 'X') { + /* Need to convert all lower case letters to upper case. + and need to convert 0x to 0X (and -0x to -0X). */ + for (i = 0; i < len; i++) + if (buf[i] >= 'a' && buf[i] <= 'x') + buf[i] -= 'a'-'A'; + } + *pbuf = buf; + *plen = len; + return result; +} + +Py_LOCAL_INLINE(int) +formatint(char *buf, size_t buflen, int flags, + int prec, int type, PyObject *v) +{ + /* fmt = '%#.' + `prec` + 'l' + `type` + worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine) + + 1 + 1 = 24 */ + char fmt[64]; /* plenty big enough! */ + char *sign; + long x; + + x = PyInt_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "int argument required"); + return -1; + } + if (x < 0 && type == 'u') { + type = 'd'; + } + if (x < 0 && (type == 'x' || type == 'X' || type == 'o')) + sign = "-"; + else + sign = ""; + if (prec < 0) + prec = 1; + + if ((flags & F_ALT) && + (type == 'x' || type == 'X')) { + /* When converting under %#x or %#X, there are a number + * of issues that cause pain: + * - when 0 is being converted, the C standard leaves off + * the '0x' or '0X', which is inconsistent with other + * %#x/%#X conversions and inconsistent with Python's + * hex() function + * - there are platforms that violate the standard and + * convert 0 with the '0x' or '0X' + * (Metrowerks, Compaq Tru64) + * - there are platforms that give '0x' when converting + * under %#X, but convert 0 in accordance with the + * standard (OS/2 EMX) + * + * We can achieve the desired consistency by inserting our + * own '0x' or '0X' prefix, and substituting %x/%X in place + * of %#x/%#X. + * + * Note that this is the same approach as used in + * formatint() in unicodeobject.c + */ + PyOS_snprintf(fmt, sizeof(fmt), "%s0%c%%.%dl%c", + sign, type, prec, type); + } + else { + PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c", + sign, (flags&F_ALT) ? "#" : "", + prec, type); + } + + /* buf = '+'/'-'/'' + '0'/'0x'/'' + '[0-9]'*max(prec, len(x in octal)) + * worst case buf = '-0x' + [0-9]*prec, where prec >= 11 + */ + if (buflen <= 14 || buflen <= (size_t)3 + (size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted integer is too long (precision too large?)"); + return -1; + } + if (sign[0]) + PyOS_snprintf(buf, buflen, fmt, -x); + else + PyOS_snprintf(buf, buflen, fmt, x); + return (int)strlen(buf); +} + +Py_LOCAL_INLINE(int) +formatchar(char *buf, size_t buflen, PyObject *v) +{ + /* presume that the buffer is at least 2 characters long */ + if (PyString_Check(v)) { + if (!PyArg_Parse(v, "c;%c requires int or char", &buf[0])) + return -1; + } + else { + if (!PyArg_Parse(v, "b;%c requires int or char", &buf[0])) + return -1; + } + buf[1] = '\0'; + return 1; +} + +/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) + + FORMATBUFLEN is the length of the buffer in which the floats, ints, & + chars are formatted. XXX This is a magic number. Each formatting + routine does bounds checking to ensure no overflow, but a better + solution may be to malloc a buffer of appropriate size for each + format. For now, the current solution is sufficient. +*/ +#define FORMATBUFLEN (size_t)120 + +PyObject * +PyString_Format(PyObject *format, PyObject *args) +{ + char *fmt, *res; + Py_ssize_t arglen, argidx; + Py_ssize_t reslen, rescnt, fmtcnt; + int args_owned = 0; + PyObject *result, *orig_args; +#ifdef Py_USING_UNICODE + PyObject *v, *w; +#endif + PyObject *dict = NULL; + if (format == NULL || !PyString_Check(format) || args == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + orig_args = args; + fmt = PyString_AS_STRING(format); + fmtcnt = PyString_GET_SIZE(format); + reslen = rescnt = fmtcnt + 100; + result = PyString_FromStringAndSize((char *)NULL, reslen); + if (result == NULL) + return NULL; + res = PyString_AsString(result); + if (PyTuple_Check(args)) { + arglen = PyTuple_GET_SIZE(args); + argidx = 0; + } + else { + arglen = -1; + argidx = -2; + } + if (args->ob_type->tp_as_mapping && !PyTuple_Check(args) && + !PyObject_TypeCheck(args, &PyBaseString_Type)) + dict = args; + while (--fmtcnt >= 0) { + if (*fmt != '%') { + if (--rescnt < 0) { + rescnt = fmtcnt + 100; + reslen += rescnt; + if (_PyString_Resize(&result, reslen) < 0) + return NULL; + res = PyString_AS_STRING(result) + + reslen - rescnt; + --rescnt; + } + *res++ = *fmt++; + } + else { + /* Got a format specifier */ + int flags = 0; + Py_ssize_t width = -1; + int prec = -1; + int c = '\0'; + int fill; + PyObject *v = NULL; + PyObject *temp = NULL; + char *pbuf; + int sign; + Py_ssize_t len; + char formatbuf[FORMATBUFLEN]; + /* For format{float,int,char}() */ +#ifdef Py_USING_UNICODE + char *fmt_start = fmt; + Py_ssize_t argidx_start = argidx; +#endif + + fmt++; + if (*fmt == '(') { + char *keystart; + Py_ssize_t keylen; + PyObject *key; + int pcount = 1; + + if (dict == NULL) { + PyErr_SetString(PyExc_TypeError, + "format requires a mapping"); + goto error; + } + ++fmt; + --fmtcnt; + keystart = fmt; + /* Skip over balanced parentheses */ + while (pcount > 0 && --fmtcnt >= 0) { + if (*fmt == ')') + --pcount; + else if (*fmt == '(') + ++pcount; + fmt++; + } + keylen = fmt - keystart - 1; + if (fmtcnt < 0 || pcount > 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format key"); + goto error; + } + key = PyString_FromStringAndSize(keystart, + keylen); + if (key == NULL) + goto error; + if (args_owned) { + Py_DECREF(args); + args_owned = 0; + } + args = PyObject_GetItem(dict, key); + Py_DECREF(key); + if (args == NULL) { + goto error; + } + args_owned = 1; + arglen = -1; + argidx = -2; + } + while (--fmtcnt >= 0) { + switch (c = *fmt++) { + case '-': flags |= F_LJUST; continue; + case '+': flags |= F_SIGN; continue; + case ' ': flags |= F_BLANK; continue; + case '#': flags |= F_ALT; continue; + case '0': flags |= F_ZERO; continue; + } + break; + } + if (c == '*') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto error; + if (!PyInt_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "* wants int"); + goto error; + } + width = PyInt_AsLong(v); + if (width < 0) { + flags |= F_LJUST; + width = -width; + } + if (--fmtcnt >= 0) + c = *fmt++; + } + else if (c >= 0 && isdigit(c)) { + width = c - '0'; + while (--fmtcnt >= 0) { + c = Py_CHARMASK(*fmt++); + if (!isdigit(c)) + break; + if ((width*10) / 10 != width) { + PyErr_SetString( + PyExc_ValueError, + "width too big"); + goto error; + } + width = width*10 + (c - '0'); + } + } + if (c == '.') { + prec = 0; + if (--fmtcnt >= 0) + c = *fmt++; + if (c == '*') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto error; + if (!PyInt_Check(v)) { + PyErr_SetString( + PyExc_TypeError, + "* wants int"); + goto error; + } + prec = PyInt_AsLong(v); + if (prec < 0) + prec = 0; + if (--fmtcnt >= 0) + c = *fmt++; + } + else if (c >= 0 && isdigit(c)) { + prec = c - '0'; + while (--fmtcnt >= 0) { + c = Py_CHARMASK(*fmt++); + if (!isdigit(c)) + break; + if ((prec*10) / 10 != prec) { + PyErr_SetString( + PyExc_ValueError, + "prec too big"); + goto error; + } + prec = prec*10 + (c - '0'); + } + } + } /* prec */ + if (fmtcnt >= 0) { + if (c == 'h' || c == 'l' || c == 'L') { + if (--fmtcnt >= 0) + c = *fmt++; + } + } + if (fmtcnt < 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format"); + goto error; + } + if (c != '%') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto error; + } + sign = 0; + fill = ' '; + switch (c) { + case '%': + pbuf = "%"; + len = 1; + break; + case 's': +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(v)) { + fmt = fmt_start; + argidx = argidx_start; + goto unicode; + } +#endif + temp = _PyObject_Str(v); +#ifdef Py_USING_UNICODE + if (temp != NULL && PyUnicode_Check(temp)) { + Py_DECREF(temp); + fmt = fmt_start; + argidx = argidx_start; + goto unicode; + } +#endif + /* Fall through */ + case 'r': + if (c == 'r') + temp = PyObject_Repr(v); + if (temp == NULL) + goto error; + if (!PyString_Check(temp)) { + PyErr_SetString(PyExc_TypeError, + "%s argument has non-string str()"); + Py_DECREF(temp); + goto error; + } + pbuf = PyString_AS_STRING(temp); + len = PyString_GET_SIZE(temp); + if (prec >= 0 && len > prec) + len = prec; + break; + case 'i': + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (c == 'i') + c = 'd'; + if (PyLong_Check(v)) { + int ilen; + temp = _PyString_FormatLong(v, flags, + prec, c, &pbuf, &ilen); + len = ilen; + if (!temp) + goto error; + sign = 1; + } + else { + pbuf = formatbuf; + len = formatint(pbuf, + sizeof(formatbuf), + flags, prec, c, v); + if (len < 0) + goto error; + sign = 1; + } + if (flags & F_ZERO) + fill = '0'; + break; + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + if (c == 'F') + c = 'f'; + pbuf = formatbuf; + len = formatfloat(pbuf, sizeof(formatbuf), + flags, prec, c, v); + if (len < 0) + goto error; + sign = 1; + if (flags & F_ZERO) + fill = '0'; + break; + case 'c': +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(v)) { + fmt = fmt_start; + argidx = argidx_start; + goto unicode; + } +#endif + pbuf = formatbuf; + len = formatchar(pbuf, sizeof(formatbuf), v); + if (len < 0) + goto error; + break; + default: + PyErr_Format(PyExc_ValueError, + "unsupported format character '%c' (0x%x) " + "at index %zd", + c, c, + (Py_ssize_t)(fmt - 1 - + PyString_AsString(format))); + goto error; + } + if (sign) { + if (*pbuf == '-' || *pbuf == '+') { + sign = *pbuf++; + len--; + } + else if (flags & F_SIGN) + sign = '+'; + else if (flags & F_BLANK) + sign = ' '; + else + sign = 0; + } + if (width < len) + width = len; + if (rescnt - (sign != 0) < width) { + reslen -= rescnt; + rescnt = width + fmtcnt + 100; + reslen += rescnt; + if (reslen < 0) { + Py_DECREF(result); + Py_XDECREF(temp); + return PyErr_NoMemory(); + } + if (_PyString_Resize(&result, reslen) < 0) { + Py_XDECREF(temp); + return NULL; + } + res = PyString_AS_STRING(result) + + reslen - rescnt; + } + if (sign) { + if (fill != ' ') + *res++ = sign; + rescnt--; + if (width > len) + width--; + } + if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + assert(pbuf[1] == c); + if (fill != ' ') { + *res++ = *pbuf++; + *res++ = *pbuf++; + } + rescnt -= 2; + width -= 2; + if (width < 0) + width = 0; + len -= 2; + } + if (width > len && !(flags & F_LJUST)) { + do { + --rescnt; + *res++ = fill; + } while (--width > len); + } + if (fill == ' ') { + if (sign) + *res++ = sign; + if ((flags & F_ALT) && + (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + assert(pbuf[1] == c); + *res++ = *pbuf++; + *res++ = *pbuf++; + } + } + Py_MEMCPY(res, pbuf, len); + res += len; + rescnt -= len; + while (--width >= len) { + --rescnt; + *res++ = ' '; + } + if (dict && (argidx < arglen) && c != '%') { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + Py_XDECREF(temp); + goto error; + } + Py_XDECREF(temp); + } /* '%' */ + } /* until end */ + if (argidx < arglen && !dict) { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + goto error; + } + if (args_owned) { + Py_DECREF(args); + } + _PyString_Resize(&result, reslen - rescnt); + return result; + +#ifdef Py_USING_UNICODE + unicode: + if (args_owned) { + Py_DECREF(args); + args_owned = 0; + } + /* Fiddle args right (remove the first argidx arguments) */ + if (PyTuple_Check(orig_args) && argidx > 0) { + PyObject *v; + Py_ssize_t n = PyTuple_GET_SIZE(orig_args) - argidx; + v = PyTuple_New(n); + if (v == NULL) + goto error; + while (--n >= 0) { + PyObject *w = PyTuple_GET_ITEM(orig_args, n + argidx); + Py_INCREF(w); + PyTuple_SET_ITEM(v, n, w); + } + args = v; + } else { + Py_INCREF(orig_args); + args = orig_args; + } + args_owned = 1; + /* Take what we have of the result and let the Unicode formatting + function format the rest of the input. */ + rescnt = res - PyString_AS_STRING(result); + if (_PyString_Resize(&result, rescnt)) + goto error; + fmtcnt = PyString_GET_SIZE(format) - \ + (fmt - PyString_AS_STRING(format)); + format = PyUnicode_Decode(fmt, fmtcnt, NULL, NULL); + if (format == NULL) + goto error; + v = PyUnicode_Format(format, args); + Py_DECREF(format); + if (v == NULL) + goto error; + /* Paste what we have (result) to what the Unicode formatting + function returned (v) and return the result (or error) */ + w = PyUnicode_Concat(result, v); + Py_DECREF(result); + Py_DECREF(v); + Py_DECREF(args); + return w; +#endif /* Py_USING_UNICODE */ + + error: + Py_DECREF(result); + if (args_owned) { + Py_DECREF(args); + } + return NULL; +} + +void +PyString_InternInPlace(PyObject **p) +{ + register PyStringObject *s = (PyStringObject *)(*p); + PyObject *t; + if (s == NULL || !PyString_Check(s)) + Py_FatalError("PyString_InternInPlace: strings only please!"); + /* If it's a string subclass, we don't really know what putting + it in the interned dict might do. */ + if (!PyString_CheckExact(s)) + return; + if (PyString_CHECK_INTERNED(s)) + return; + if (interned == NULL) { + interned = PyDict_New(); + if (interned == NULL) { + PyErr_Clear(); /* Don't leave an exception */ + return; + } + } + t = PyDict_GetItem(interned, (PyObject *)s); + if (t) { + Py_INCREF(t); + Py_DECREF(*p); + *p = t; + return; + } + + if (PyDict_SetItem(interned, (PyObject *)s, (PyObject *)s) < 0) { + PyErr_Clear(); + return; + } + /* The two references in interned are not counted by refcnt. + The string deallocator will take care of this */ + s->ob_refcnt -= 2; + PyString_CHECK_INTERNED(s) = SSTATE_INTERNED_MORTAL; +} + +void +PyString_InternImmortal(PyObject **p) +{ + PyString_InternInPlace(p); + if (PyString_CHECK_INTERNED(*p) != SSTATE_INTERNED_IMMORTAL) { + PyString_CHECK_INTERNED(*p) = SSTATE_INTERNED_IMMORTAL; + Py_INCREF(*p); + } +} + + +PyObject * +PyString_InternFromString(const char *cp) +{ + PyObject *s = PyString_FromString(cp); + if (s == NULL) + return NULL; + PyString_InternInPlace(&s); + return s; +} + +void +PyString_Fini(void) +{ + int i; + for (i = 0; i < UCHAR_MAX + 1; i++) { + Py_XDECREF(characters[i]); + characters[i] = NULL; + } + Py_XDECREF(nullstring); + nullstring = NULL; +} + +void _Py_ReleaseInternedStrings(void) +{ + PyObject *keys; + PyStringObject *s; + Py_ssize_t i, n; + + if (interned == NULL || !PyDict_Check(interned)) + return; + keys = PyDict_Keys(interned); + if (keys == NULL || !PyList_Check(keys)) { + PyErr_Clear(); + return; + } + + /* Since _Py_ReleaseInternedStrings() is intended to help a leak + detector, interned strings are not forcibly deallocated; rather, we + give them their stolen references back, and then clear and DECREF + the interned dict. */ + + fprintf(stderr, "releasing interned strings\n"); + n = PyList_GET_SIZE(keys); + for (i = 0; i < n; i++) { + s = (PyStringObject *) PyList_GET_ITEM(keys, i); + switch (s->ob_sstate) { + case SSTATE_NOT_INTERNED: + /* XXX Shouldn't happen */ + break; + case SSTATE_INTERNED_IMMORTAL: + s->ob_refcnt += 1; + break; + case SSTATE_INTERNED_MORTAL: + s->ob_refcnt += 2; + break; + default: + Py_FatalError("Inconsistent interned string state."); + } + s->ob_sstate = SSTATE_NOT_INTERNED; + } + Py_DECREF(keys); + PyDict_Clear(interned); + Py_DECREF(interned); + interned = NULL; +} diff --git a/sys/src/cmd/python/Objects/structseq.c b/sys/src/cmd/python/Objects/structseq.c new file mode 100644 index 000000000..7ac2a1f61 --- /dev/null +++ b/sys/src/cmd/python/Objects/structseq.c @@ -0,0 +1,407 @@ +/* Implementation helper: a struct that looks like a tuple. See timemodule + and posixmodule for example uses. */ + +#include "Python.h" +#include "structmember.h" +#include "structseq.h" + +static char visible_length_key[] = "n_sequence_fields"; +static char real_length_key[] = "n_fields"; +static char unnamed_fields_key[] = "n_unnamed_fields"; + +/* Fields with this name have only a field index, not a field name. + They are only allowed for indices < n_visible_fields. */ +char *PyStructSequence_UnnamedField = "unnamed field"; + +#define VISIBLE_SIZE(op) ((op)->ob_size) +#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \ + PyDict_GetItemString((tp)->tp_dict, visible_length_key)) + +#define REAL_SIZE_TP(tp) PyInt_AsLong( \ + PyDict_GetItemString((tp)->tp_dict, real_length_key)) +#define REAL_SIZE(op) REAL_SIZE_TP((op)->ob_type) + +#define UNNAMED_FIELDS_TP(tp) PyInt_AsLong( \ + PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key)) +#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP((op)->ob_type) + + +PyObject * +PyStructSequence_New(PyTypeObject *type) +{ + PyStructSequence *obj; + + obj = PyObject_New(PyStructSequence, type); + obj->ob_size = VISIBLE_SIZE_TP(type); + + return (PyObject*) obj; +} + +static void +structseq_dealloc(PyStructSequence *obj) +{ + Py_ssize_t i, size; + + size = REAL_SIZE(obj); + for (i = 0; i < size; ++i) { + Py_XDECREF(obj->ob_item[i]); + } + PyObject_Del(obj); +} + +static Py_ssize_t +structseq_length(PyStructSequence *obj) +{ + return VISIBLE_SIZE(obj); +} + +static PyObject* +structseq_item(PyStructSequence *obj, Py_ssize_t i) +{ + if (i < 0 || i >= VISIBLE_SIZE(obj)) { + PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + return NULL; + } + Py_INCREF(obj->ob_item[i]); + return obj->ob_item[i]; +} + +static PyObject* +structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high) +{ + PyTupleObject *np; + Py_ssize_t i; + + if (low < 0) + low = 0; + if (high > VISIBLE_SIZE(obj)) + high = VISIBLE_SIZE(obj); + if (high < low) + high = low; + np = (PyTupleObject *)PyTuple_New(high-low); + if (np == NULL) + return NULL; + for(i = low; i < high; ++i) { + PyObject *v = obj->ob_item[i]; + Py_INCREF(v); + PyTuple_SET_ITEM(np, i-low, v); + } + return (PyObject *) np; +} + +static PyObject * +structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *arg = NULL; + PyObject *dict = NULL; + PyObject *ob; + PyStructSequence *res = NULL; + Py_ssize_t len, min_len, max_len, i, n_unnamed_fields; + static char *kwlist[] = {"sequence", "dict", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq", + kwlist, &arg, &dict)) + return NULL; + + arg = PySequence_Fast(arg, "constructor requires a sequence"); + + if (!arg) { + return NULL; + } + + if (dict && !PyDict_Check(dict)) { + PyErr_Format(PyExc_TypeError, + "%.500s() takes a dict as second arg, if any", + type->tp_name); + Py_DECREF(arg); + return NULL; + } + + len = PySequence_Fast_GET_SIZE(arg); + min_len = VISIBLE_SIZE_TP(type); + max_len = REAL_SIZE_TP(type); + n_unnamed_fields = UNNAMED_FIELDS_TP(type); + + if (min_len != max_len) { + if (len < min_len) { + PyErr_Format(PyExc_TypeError, + "%.500s() takes an at least %zd-sequence (%zd-sequence given)", + type->tp_name, min_len, len); + Py_DECREF(arg); + return NULL; + } + + if (len > max_len) { + PyErr_Format(PyExc_TypeError, + "%.500s() takes an at most %zd-sequence (%zd-sequence given)", + type->tp_name, max_len, len); + Py_DECREF(arg); + return NULL; + } + } + else { + if (len != min_len) { + PyErr_Format(PyExc_TypeError, + "%.500s() takes a %zd-sequence (%zd-sequence given)", + type->tp_name, min_len, len); + Py_DECREF(arg); + return NULL; + } + } + + res = (PyStructSequence*) PyStructSequence_New(type); + if (res == NULL) { + return NULL; + } + for (i = 0; i < len; ++i) { + PyObject *v = PySequence_Fast_GET_ITEM(arg, i); + Py_INCREF(v); + res->ob_item[i] = v; + } + for (; i < max_len; ++i) { + if (dict && (ob = PyDict_GetItemString( + dict, type->tp_members[i-n_unnamed_fields].name))) { + } + else { + ob = Py_None; + } + Py_INCREF(ob); + res->ob_item[i] = ob; + } + + Py_DECREF(arg); + return (PyObject*) res; +} + +static PyObject * +make_tuple(PyStructSequence *obj) +{ + return structseq_slice(obj, 0, VISIBLE_SIZE(obj)); +} + +static PyObject * +structseq_repr(PyStructSequence *obj) +{ + PyObject *tup, *str; + tup = make_tuple(obj); + str = PyObject_Repr(tup); + Py_DECREF(tup); + return str; +} + +static PyObject * +structseq_concat(PyStructSequence *obj, PyObject *b) +{ + PyObject *tup, *result; + tup = make_tuple(obj); + result = PySequence_Concat(tup, b); + Py_DECREF(tup); + return result; +} + +static PyObject * +structseq_repeat(PyStructSequence *obj, Py_ssize_t n) +{ + PyObject *tup, *result; + tup = make_tuple(obj); + result = PySequence_Repeat(tup, n); + Py_DECREF(tup); + return result; +} + +static int +structseq_contains(PyStructSequence *obj, PyObject *o) +{ + PyObject *tup; + int result; + tup = make_tuple(obj); + if (!tup) + return -1; + result = PySequence_Contains(tup, o); + Py_DECREF(tup); + return result; +} + +static long +structseq_hash(PyObject *obj) +{ + PyObject *tup; + long result; + tup = make_tuple((PyStructSequence*) obj); + if (!tup) + return -1; + result = PyObject_Hash(tup); + Py_DECREF(tup); + return result; +} + +static PyObject * +structseq_richcompare(PyObject *obj, PyObject *o2, int op) +{ + PyObject *tup, *result; + tup = make_tuple((PyStructSequence*) obj); + result = PyObject_RichCompare(tup, o2, op); + Py_DECREF(tup); + return result; +} + +static PyObject * +structseq_reduce(PyStructSequence* self) +{ + PyObject* tup; + PyObject* dict; + PyObject* result; + Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields; + int i; + + n_fields = REAL_SIZE(self); + n_visible_fields = VISIBLE_SIZE(self); + n_unnamed_fields = UNNAMED_FIELDS(self); + tup = PyTuple_New(n_visible_fields); + if (!tup) { + return NULL; + } + + dict = PyDict_New(); + if (!dict) { + Py_DECREF(tup); + return NULL; + } + + for (i = 0; i < n_visible_fields; i++) { + Py_INCREF(self->ob_item[i]); + PyTuple_SET_ITEM(tup, i, self->ob_item[i]); + } + + for (; i < n_fields; i++) { + char *n = self->ob_type->tp_members[i-n_unnamed_fields].name; + PyDict_SetItemString(dict, n, + self->ob_item[i]); + } + + result = Py_BuildValue("(O(OO))", self->ob_type, tup, dict); + + Py_DECREF(tup); + Py_DECREF(dict); + + return result; +} + +static PySequenceMethods structseq_as_sequence = { + (lenfunc)structseq_length, + (binaryfunc)structseq_concat, /* sq_concat */ + (ssizeargfunc)structseq_repeat, /* sq_repeat */ + (ssizeargfunc)structseq_item, /* sq_item */ + (ssizessizeargfunc)structseq_slice, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)structseq_contains, /* sq_contains */ +}; + +static PyMethodDef structseq_methods[] = { + {"__reduce__", (PyCFunction)structseq_reduce, + METH_NOARGS, NULL}, + {NULL, NULL} +}; + +static PyTypeObject _struct_sequence_template = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + NULL, /* tp_name */ + 0, /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)structseq_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)structseq_repr, /* tp_repr */ + 0, /* tp_as_number */ + &structseq_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + structseq_hash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + NULL, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + structseq_richcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + structseq_methods, /* tp_methods */ + NULL, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + structseq_new, /* tp_new */ +}; + +void +PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) +{ + PyObject *dict; + PyMemberDef* members; + int n_members, n_unnamed_members, i, k; + +#ifdef Py_TRACE_REFS + /* if the type object was chained, unchain it first + before overwriting its storage */ + if (type->_ob_next) { + _Py_ForgetReference((PyObject*)type); + } +#endif + + n_unnamed_members = 0; + for (i = 0; desc->fields[i].name != NULL; ++i) + if (desc->fields[i].name == PyStructSequence_UnnamedField) + n_unnamed_members++; + n_members = i; + + memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject)); + type->tp_name = desc->name; + type->tp_doc = desc->doc; + type->tp_basicsize = sizeof(PyStructSequence)+ + sizeof(PyObject*)*(n_members-1); + type->tp_itemsize = 0; + + members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1); + if (members == NULL) + return; + + for (i = k = 0; i < n_members; ++i) { + if (desc->fields[i].name == PyStructSequence_UnnamedField) + continue; + members[k].name = desc->fields[i].name; + members[k].type = T_OBJECT; + members[k].offset = offsetof(PyStructSequence, ob_item) + + i * sizeof(PyObject*); + members[k].flags = READONLY; + members[k].doc = desc->fields[i].doc; + k++; + } + members[k].name = NULL; + + type->tp_members = members; + + if (PyType_Ready(type) < 0) + return; + Py_INCREF(type); + + dict = type->tp_dict; + PyDict_SetItemString(dict, visible_length_key, + PyInt_FromLong((long) desc->n_in_sequence)); + PyDict_SetItemString(dict, real_length_key, + PyInt_FromLong((long) n_members)); + PyDict_SetItemString(dict, unnamed_fields_key, + PyInt_FromLong((long) n_unnamed_members)); +} diff --git a/sys/src/cmd/python/Objects/tupleobject.c b/sys/src/cmd/python/Objects/tupleobject.c new file mode 100644 index 000000000..6f3711f1f --- /dev/null +++ b/sys/src/cmd/python/Objects/tupleobject.c @@ -0,0 +1,890 @@ + +/* Tuple object implementation */ + +#include "Python.h" + +/* Speed optimization to avoid frequent malloc/free of small tuples */ +#ifndef MAXSAVESIZE +#define MAXSAVESIZE 20 /* Largest tuple to save on free list */ +#endif +#ifndef MAXSAVEDTUPLES +#define MAXSAVEDTUPLES 2000 /* Maximum number of tuples of each size to save */ +#endif + +#if MAXSAVESIZE > 0 +/* Entries 1 up to MAXSAVESIZE are free lists, entry 0 is the empty + tuple () of which at most one instance will be allocated. +*/ +static PyTupleObject *free_tuples[MAXSAVESIZE]; +static int num_free_tuples[MAXSAVESIZE]; +#endif +#ifdef COUNT_ALLOCS +int fast_tuple_allocs; +int tuple_zero_allocs; +#endif + +PyObject * +PyTuple_New(register Py_ssize_t size) +{ + register PyTupleObject *op; + Py_ssize_t i; + if (size < 0) { + PyErr_BadInternalCall(); + return NULL; + } +#if MAXSAVESIZE > 0 + if (size == 0 && free_tuples[0]) { + op = free_tuples[0]; + Py_INCREF(op); +#ifdef COUNT_ALLOCS + tuple_zero_allocs++; +#endif + return (PyObject *) op; + } + if (size < MAXSAVESIZE && (op = free_tuples[size]) != NULL) { + free_tuples[size] = (PyTupleObject *) op->ob_item[0]; + num_free_tuples[size]--; +#ifdef COUNT_ALLOCS + fast_tuple_allocs++; +#endif + /* Inline PyObject_InitVar */ +#ifdef Py_TRACE_REFS + op->ob_size = size; + op->ob_type = &PyTuple_Type; +#endif + _Py_NewReference((PyObject *)op); + } + else +#endif + { + Py_ssize_t nbytes = size * sizeof(PyObject *); + /* Check for overflow */ + if (nbytes / sizeof(PyObject *) != (size_t)size || + (nbytes += sizeof(PyTupleObject) - sizeof(PyObject *)) + <= 0) + { + return PyErr_NoMemory(); + } + op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); + if (op == NULL) + return NULL; + } + for (i=0; i < size; i++) + op->ob_item[i] = NULL; +#if MAXSAVESIZE > 0 + if (size == 0) { + free_tuples[0] = op; + ++num_free_tuples[0]; + Py_INCREF(op); /* extra INCREF so that this is never freed */ + } +#endif + _PyObject_GC_TRACK(op); + return (PyObject *) op; +} + +Py_ssize_t +PyTuple_Size(register PyObject *op) +{ + if (!PyTuple_Check(op)) { + PyErr_BadInternalCall(); + return -1; + } + else + return ((PyTupleObject *)op)->ob_size; +} + +PyObject * +PyTuple_GetItem(register PyObject *op, register Py_ssize_t i) +{ + if (!PyTuple_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { + PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + return NULL; + } + return ((PyTupleObject *)op) -> ob_item[i]; +} + +int +PyTuple_SetItem(register PyObject *op, register Py_ssize_t i, PyObject *newitem) +{ + register PyObject *olditem; + register PyObject **p; + if (!PyTuple_Check(op) || op->ob_refcnt != 1) { + Py_XDECREF(newitem); + PyErr_BadInternalCall(); + return -1; + } + if (i < 0 || i >= ((PyTupleObject *)op) -> ob_size) { + Py_XDECREF(newitem); + PyErr_SetString(PyExc_IndexError, + "tuple assignment index out of range"); + return -1; + } + p = ((PyTupleObject *)op) -> ob_item + i; + olditem = *p; + *p = newitem; + Py_XDECREF(olditem); + return 0; +} + +PyObject * +PyTuple_Pack(Py_ssize_t n, ...) +{ + Py_ssize_t i; + PyObject *o; + PyObject *result; + PyObject **items; + va_list vargs; + + va_start(vargs, n); + result = PyTuple_New(n); + if (result == NULL) + return NULL; + items = ((PyTupleObject *)result)->ob_item; + for (i = 0; i < n; i++) { + o = va_arg(vargs, PyObject *); + Py_INCREF(o); + items[i] = o; + } + va_end(vargs); + return result; +} + + +/* Methods */ + +static void +tupledealloc(register PyTupleObject *op) +{ + register Py_ssize_t i; + register Py_ssize_t len = op->ob_size; + PyObject_GC_UnTrack(op); + Py_TRASHCAN_SAFE_BEGIN(op) + if (len > 0) { + i = len; + while (--i >= 0) + Py_XDECREF(op->ob_item[i]); +#if MAXSAVESIZE > 0 + if (len < MAXSAVESIZE && + num_free_tuples[len] < MAXSAVEDTUPLES && + op->ob_type == &PyTuple_Type) + { + op->ob_item[0] = (PyObject *) free_tuples[len]; + num_free_tuples[len]++; + free_tuples[len] = op; + goto done; /* return */ + } +#endif + } + op->ob_type->tp_free((PyObject *)op); +done: + Py_TRASHCAN_SAFE_END(op) +} + +static int +tupleprint(PyTupleObject *op, FILE *fp, int flags) +{ + Py_ssize_t i; + fprintf(fp, "("); + for (i = 0; i < op->ob_size; i++) { + if (i > 0) + fprintf(fp, ", "); + if (PyObject_Print(op->ob_item[i], fp, 0) != 0) + return -1; + } + if (op->ob_size == 1) + fprintf(fp, ","); + fprintf(fp, ")"); + return 0; +} + +static PyObject * +tuplerepr(PyTupleObject *v) +{ + Py_ssize_t i, n; + PyObject *s, *temp; + PyObject *pieces, *result = NULL; + + n = v->ob_size; + if (n == 0) + return PyString_FromString("()"); + + pieces = PyTuple_New(n); + if (pieces == NULL) + return NULL; + + /* Do repr() on each element. */ + for (i = 0; i < n; ++i) { + s = PyObject_Repr(v->ob_item[i]); + if (s == NULL) + goto Done; + PyTuple_SET_ITEM(pieces, i, s); + } + + /* Add "()" decorations to the first and last items. */ + assert(n > 0); + s = PyString_FromString("("); + if (s == NULL) + goto Done; + temp = PyTuple_GET_ITEM(pieces, 0); + PyString_ConcatAndDel(&s, temp); + PyTuple_SET_ITEM(pieces, 0, s); + if (s == NULL) + goto Done; + + s = PyString_FromString(n == 1 ? ",)" : ")"); + if (s == NULL) + goto Done; + temp = PyTuple_GET_ITEM(pieces, n-1); + PyString_ConcatAndDel(&temp, s); + PyTuple_SET_ITEM(pieces, n-1, temp); + if (temp == NULL) + goto Done; + + /* Paste them all together with ", " between. */ + s = PyString_FromString(", "); + if (s == NULL) + goto Done; + result = _PyString_Join(s, pieces); + Py_DECREF(s); + +Done: + Py_DECREF(pieces); + return result; +} + +/* The addend 82520, was selected from the range(0, 1000000) for + generating the greatest number of prime multipliers for tuples + upto length eight: + + 1082527, 1165049, 1082531, 1165057, 1247581, 1330103, 1082533, + 1330111, 1412633, 1165069, 1247599, 1495177, 1577699 +*/ + +static long +tuplehash(PyTupleObject *v) +{ + register long x, y; + register Py_ssize_t len = v->ob_size; + register PyObject **p; + long mult = 1000003L; + x = 0x345678L; + p = v->ob_item; + while (--len >= 0) { + y = PyObject_Hash(*p++); + if (y == -1) + return -1; + x = (x ^ y) * mult; + /* the cast might truncate len; that doesn't change hash stability */ + mult += (long)(82520L + len + len); + } + x += 97531L; + if (x == -1) + x = -2; + return x; +} + +static Py_ssize_t +tuplelength(PyTupleObject *a) +{ + return a->ob_size; +} + +static int +tuplecontains(PyTupleObject *a, PyObject *el) +{ + Py_ssize_t i; + int cmp; + + for (i = 0, cmp = 0 ; cmp == 0 && i < a->ob_size; ++i) + cmp = PyObject_RichCompareBool(el, PyTuple_GET_ITEM(a, i), + Py_EQ); + return cmp; +} + +static PyObject * +tupleitem(register PyTupleObject *a, register Py_ssize_t i) +{ + if (i < 0 || i >= a->ob_size) { + PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + return NULL; + } + Py_INCREF(a->ob_item[i]); + return a->ob_item[i]; +} + +static PyObject * +tupleslice(register PyTupleObject *a, register Py_ssize_t ilow, + register Py_ssize_t ihigh) +{ + register PyTupleObject *np; + PyObject **src, **dest; + register Py_ssize_t i; + Py_ssize_t len; + if (ilow < 0) + ilow = 0; + if (ihigh > a->ob_size) + ihigh = a->ob_size; + if (ihigh < ilow) + ihigh = ilow; + if (ilow == 0 && ihigh == a->ob_size && PyTuple_CheckExact(a)) { + Py_INCREF(a); + return (PyObject *)a; + } + len = ihigh - ilow; + np = (PyTupleObject *)PyTuple_New(len); + if (np == NULL) + return NULL; + src = a->ob_item + ilow; + dest = np->ob_item; + for (i = 0; i < len; i++) { + PyObject *v = src[i]; + Py_INCREF(v); + dest[i] = v; + } + return (PyObject *)np; +} + +PyObject * +PyTuple_GetSlice(PyObject *op, Py_ssize_t i, Py_ssize_t j) +{ + if (op == NULL || !PyTuple_Check(op)) { + PyErr_BadInternalCall(); + return NULL; + } + return tupleslice((PyTupleObject *)op, i, j); +} + +static PyObject * +tupleconcat(register PyTupleObject *a, register PyObject *bb) +{ + register Py_ssize_t size; + register Py_ssize_t i; + PyObject **src, **dest; + PyTupleObject *np; + if (!PyTuple_Check(bb)) { + PyErr_Format(PyExc_TypeError, + "can only concatenate tuple (not \"%.200s\") to tuple", + bb->ob_type->tp_name); + return NULL; + } +#define b ((PyTupleObject *)bb) + size = a->ob_size + b->ob_size; + if (size < 0) + return PyErr_NoMemory(); + np = (PyTupleObject *) PyTuple_New(size); + if (np == NULL) { + return NULL; + } + src = a->ob_item; + dest = np->ob_item; + for (i = 0; i < a->ob_size; i++) { + PyObject *v = src[i]; + Py_INCREF(v); + dest[i] = v; + } + src = b->ob_item; + dest = np->ob_item + a->ob_size; + for (i = 0; i < b->ob_size; i++) { + PyObject *v = src[i]; + Py_INCREF(v); + dest[i] = v; + } + return (PyObject *)np; +#undef b +} + +static PyObject * +tuplerepeat(PyTupleObject *a, Py_ssize_t n) +{ + Py_ssize_t i, j; + Py_ssize_t size; + PyTupleObject *np; + PyObject **p, **items; + if (n < 0) + n = 0; + if (a->ob_size == 0 || n == 1) { + if (PyTuple_CheckExact(a)) { + /* Since tuples are immutable, we can return a shared + copy in this case */ + Py_INCREF(a); + return (PyObject *)a; + } + if (a->ob_size == 0) + return PyTuple_New(0); + } + size = a->ob_size * n; + if (size/a->ob_size != n) + return PyErr_NoMemory(); + np = (PyTupleObject *) PyTuple_New(size); + if (np == NULL) + return NULL; + p = np->ob_item; + items = a->ob_item; + for (i = 0; i < n; i++) { + for (j = 0; j < a->ob_size; j++) { + *p = items[j]; + Py_INCREF(*p); + p++; + } + } + return (PyObject *) np; +} + +static int +tupletraverse(PyTupleObject *o, visitproc visit, void *arg) +{ + Py_ssize_t i; + + for (i = o->ob_size; --i >= 0; ) + Py_VISIT(o->ob_item[i]); + return 0; +} + +static PyObject * +tuplerichcompare(PyObject *v, PyObject *w, int op) +{ + PyTupleObject *vt, *wt; + Py_ssize_t i; + Py_ssize_t vlen, wlen; + + if (!PyTuple_Check(v) || !PyTuple_Check(w)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + + vt = (PyTupleObject *)v; + wt = (PyTupleObject *)w; + + vlen = vt->ob_size; + wlen = wt->ob_size; + + /* Note: the corresponding code for lists has an "early out" test + * here when op is EQ or NE and the lengths differ. That pays there, + * but Tim was unable to find any real code where EQ/NE tuple + * compares don't have the same length, so testing for it here would + * have cost without benefit. + */ + + /* Search for the first index where items are different. + * Note that because tuples are immutable, it's safe to reuse + * vlen and wlen across the comparison calls. + */ + for (i = 0; i < vlen && i < wlen; i++) { + int k = PyObject_RichCompareBool(vt->ob_item[i], + wt->ob_item[i], Py_EQ); + if (k < 0) + return NULL; + if (!k) + break; + } + + if (i >= vlen || i >= wlen) { + /* No more items to compare -- compare sizes */ + int cmp; + PyObject *res; + switch (op) { + case Py_LT: cmp = vlen < wlen; break; + case Py_LE: cmp = vlen <= wlen; break; + case Py_EQ: cmp = vlen == wlen; break; + case Py_NE: cmp = vlen != wlen; break; + case Py_GT: cmp = vlen > wlen; break; + case Py_GE: cmp = vlen >= wlen; break; + default: return NULL; /* cannot happen */ + } + if (cmp) + res = Py_True; + else + res = Py_False; + Py_INCREF(res); + return res; + } + + /* We have an item that differs -- shortcuts for EQ/NE */ + if (op == Py_EQ) { + Py_INCREF(Py_False); + return Py_False; + } + if (op == Py_NE) { + Py_INCREF(Py_True); + return Py_True; + } + + /* Compare the final item again using the proper operator */ + return PyObject_RichCompare(vt->ob_item[i], wt->ob_item[i], op); +} + +static PyObject * +tuple_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static PyObject * +tuple_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *arg = NULL; + static char *kwlist[] = {"sequence", 0}; + + if (type != &PyTuple_Type) + return tuple_subtype_new(type, args, kwds); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:tuple", kwlist, &arg)) + return NULL; + + if (arg == NULL) + return PyTuple_New(0); + else + return PySequence_Tuple(arg); +} + +static PyObject * +tuple_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *tmp, *newobj, *item; + Py_ssize_t i, n; + + assert(PyType_IsSubtype(type, &PyTuple_Type)); + tmp = tuple_new(&PyTuple_Type, args, kwds); + if (tmp == NULL) + return NULL; + assert(PyTuple_Check(tmp)); + newobj = type->tp_alloc(type, n = PyTuple_GET_SIZE(tmp)); + if (newobj == NULL) + return NULL; + for (i = 0; i < n; i++) { + item = PyTuple_GET_ITEM(tmp, i); + Py_INCREF(item); + PyTuple_SET_ITEM(newobj, i, item); + } + Py_DECREF(tmp); + return newobj; +} + +PyDoc_STRVAR(tuple_doc, +"tuple() -> an empty tuple\n" +"tuple(sequence) -> tuple initialized from sequence's items\n" +"\n" +"If the argument is a tuple, the return value is the same object."); + +static PySequenceMethods tuple_as_sequence = { + (lenfunc)tuplelength, /* sq_length */ + (binaryfunc)tupleconcat, /* sq_concat */ + (ssizeargfunc)tuplerepeat, /* sq_repeat */ + (ssizeargfunc)tupleitem, /* sq_item */ + (ssizessizeargfunc)tupleslice, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)tuplecontains, /* sq_contains */ +}; + +static PyObject* +tuplesubscript(PyTupleObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyTuple_GET_SIZE(self); + return tupleitem(self, i); + } + else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, cur, i; + PyObject* result; + PyObject* it; + PyObject **src, **dest; + + if (PySlice_GetIndicesEx((PySliceObject*)item, + PyTuple_GET_SIZE(self), + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyTuple_New(0); + } + else { + result = PyTuple_New(slicelength); + if (!result) return NULL; + + src = self->ob_item; + dest = ((PyTupleObject *)result)->ob_item; + for (cur = start, i = 0; i < slicelength; + cur += step, i++) { + it = src[cur]; + Py_INCREF(it); + dest[i] = it; + } + + return result; + } + } + else { + PyErr_SetString(PyExc_TypeError, + "tuple indices must be integers"); + return NULL; + } +} + +static PyObject * +tuple_getnewargs(PyTupleObject *v) +{ + return Py_BuildValue("(N)", tupleslice(v, 0, v->ob_size)); + +} + +static PyMethodDef tuple_methods[] = { + {"__getnewargs__", (PyCFunction)tuple_getnewargs, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyMappingMethods tuple_as_mapping = { + (lenfunc)tuplelength, + (binaryfunc)tuplesubscript, + 0 +}; + +static PyObject *tuple_iter(PyObject *seq); + +PyTypeObject PyTuple_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "tuple", + sizeof(PyTupleObject) - sizeof(PyObject *), + sizeof(PyObject *), + (destructor)tupledealloc, /* tp_dealloc */ + (printfunc)tupleprint, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)tuplerepr, /* tp_repr */ + 0, /* tp_as_number */ + &tuple_as_sequence, /* tp_as_sequence */ + &tuple_as_mapping, /* tp_as_mapping */ + (hashfunc)tuplehash, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + tuple_doc, /* tp_doc */ + (traverseproc)tupletraverse, /* tp_traverse */ + 0, /* tp_clear */ + tuplerichcompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + tuple_iter, /* tp_iter */ + 0, /* tp_iternext */ + tuple_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + tuple_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + +/* The following function breaks the notion that tuples are immutable: + it changes the size of a tuple. We get away with this only if there + is only one module referencing the object. You can also think of it + as creating a new tuple object and destroying the old one, only more + efficiently. In any case, don't use this if the tuple may already be + known to some other part of the code. */ + +int +_PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) +{ + register PyTupleObject *v; + register PyTupleObject *sv; + Py_ssize_t i; + Py_ssize_t oldsize; + + v = (PyTupleObject *) *pv; + if (v == NULL || v->ob_type != &PyTuple_Type || + (v->ob_size != 0 && v->ob_refcnt != 1)) { + *pv = 0; + Py_XDECREF(v); + PyErr_BadInternalCall(); + return -1; + } + oldsize = v->ob_size; + if (oldsize == newsize) + return 0; + + if (oldsize == 0) { + /* Empty tuples are often shared, so we should never + resize them in-place even if we do own the only + (current) reference */ + Py_DECREF(v); + *pv = PyTuple_New(newsize); + return *pv == NULL ? -1 : 0; + } + + /* XXX UNREF/NEWREF interface should be more symmetrical */ + _Py_DEC_REFTOTAL; + _PyObject_GC_UNTRACK(v); + _Py_ForgetReference((PyObject *) v); + /* DECREF items deleted by shrinkage */ + for (i = newsize; i < oldsize; i++) { + Py_XDECREF(v->ob_item[i]); + v->ob_item[i] = NULL; + } + sv = PyObject_GC_Resize(PyTupleObject, v, newsize); + if (sv == NULL) { + *pv = NULL; + PyObject_GC_Del(v); + return -1; + } + _Py_NewReference((PyObject *) sv); + /* Zero out items added by growing */ + if (newsize > oldsize) + memset(&sv->ob_item[oldsize], 0, + sizeof(*sv->ob_item) * (newsize - oldsize)); + *pv = (PyObject *) sv; + _PyObject_GC_TRACK(sv); + return 0; +} + +void +PyTuple_Fini(void) +{ +#if MAXSAVESIZE > 0 + int i; + + Py_XDECREF(free_tuples[0]); + free_tuples[0] = NULL; + + for (i = 1; i < MAXSAVESIZE; i++) { + PyTupleObject *p, *q; + p = free_tuples[i]; + free_tuples[i] = NULL; + while (p) { + q = p; + p = (PyTupleObject *)(p->ob_item[0]); + PyObject_GC_Del(q); + } + } +#endif +} + +/*********************** Tuple Iterator **************************/ + +typedef struct { + PyObject_HEAD + long it_index; + PyTupleObject *it_seq; /* Set to NULL when iterator is exhausted */ +} tupleiterobject; + +static void +tupleiter_dealloc(tupleiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); +} + +static int +tupleiter_traverse(tupleiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_seq); + return 0; +} + +static PyObject * +tupleiter_next(tupleiterobject *it) +{ + PyTupleObject *seq; + PyObject *item; + + assert(it != NULL); + seq = it->it_seq; + if (seq == NULL) + return NULL; + assert(PyTuple_Check(seq)); + + if (it->it_index < PyTuple_GET_SIZE(seq)) { + item = PyTuple_GET_ITEM(seq, it->it_index); + ++it->it_index; + Py_INCREF(item); + return item; + } + + Py_DECREF(seq); + it->it_seq = NULL; + return NULL; +} + +static PyObject * +tupleiter_len(tupleiterobject *it) +{ + Py_ssize_t len = 0; + if (it->it_seq) + len = PyTuple_GET_SIZE(it->it_seq) - it->it_index; + return PyInt_FromSsize_t(len); +} + +PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); + +static PyMethodDef tupleiter_methods[] = { + {"__length_hint__", (PyCFunction)tupleiter_len, METH_NOARGS, length_hint_doc}, + {NULL, NULL} /* sentinel */ +}; + +PyTypeObject PyTupleIter_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "tupleiterator", /* tp_name */ + sizeof(tupleiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)tupleiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)tupleiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)tupleiter_next, /* tp_iternext */ + tupleiter_methods, /* tp_methods */ + 0, +}; + +static PyObject * +tuple_iter(PyObject *seq) +{ + tupleiterobject *it; + + if (!PyTuple_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + it = PyObject_GC_New(tupleiterobject, &PyTupleIter_Type); + if (it == NULL) + return NULL; + it->it_index = 0; + Py_INCREF(seq); + it->it_seq = (PyTupleObject *)seq; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} diff --git a/sys/src/cmd/python/Objects/typeobject.c b/sys/src/cmd/python/Objects/typeobject.c new file mode 100644 index 000000000..8a6f78266 --- /dev/null +++ b/sys/src/cmd/python/Objects/typeobject.c @@ -0,0 +1,5891 @@ +/* Type object implementation */ + +#include "Python.h" +#include "structmember.h" + +#include <ctype.h> + +static PyMemberDef type_members[] = { + {"__basicsize__", T_INT, offsetof(PyTypeObject,tp_basicsize),READONLY}, + {"__itemsize__", T_INT, offsetof(PyTypeObject, tp_itemsize), READONLY}, + {"__flags__", T_LONG, offsetof(PyTypeObject, tp_flags), READONLY}, + {"__weakrefoffset__", T_LONG, + offsetof(PyTypeObject, tp_weaklistoffset), READONLY}, + {"__base__", T_OBJECT, offsetof(PyTypeObject, tp_base), READONLY}, + {"__dictoffset__", T_LONG, + offsetof(PyTypeObject, tp_dictoffset), READONLY}, + {"__mro__", T_OBJECT, offsetof(PyTypeObject, tp_mro), READONLY}, + {0} +}; + +static PyObject * +type_name(PyTypeObject *type, void *context) +{ + const char *s; + + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { + PyHeapTypeObject* et = (PyHeapTypeObject*)type; + + Py_INCREF(et->ht_name); + return et->ht_name; + } + else { + s = strrchr(type->tp_name, '.'); + if (s == NULL) + s = type->tp_name; + else + s++; + return PyString_FromString(s); + } +} + +static int +type_set_name(PyTypeObject *type, PyObject *value, void *context) +{ + PyHeapTypeObject* et; + + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_TypeError, + "can't set %s.__name__", type->tp_name); + return -1; + } + if (!value) { + PyErr_Format(PyExc_TypeError, + "can't delete %s.__name__", type->tp_name); + return -1; + } + if (!PyString_Check(value)) { + PyErr_Format(PyExc_TypeError, + "can only assign string to %s.__name__, not '%s'", + type->tp_name, value->ob_type->tp_name); + return -1; + } + if (strlen(PyString_AS_STRING(value)) + != (size_t)PyString_GET_SIZE(value)) { + PyErr_Format(PyExc_ValueError, + "__name__ must not contain null bytes"); + return -1; + } + + et = (PyHeapTypeObject*)type; + + Py_INCREF(value); + + Py_DECREF(et->ht_name); + et->ht_name = value; + + type->tp_name = PyString_AS_STRING(value); + + return 0; +} + +static PyObject * +type_module(PyTypeObject *type, void *context) +{ + PyObject *mod; + char *s; + + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { + mod = PyDict_GetItemString(type->tp_dict, "__module__"); + if (!mod) { + PyErr_Format(PyExc_AttributeError, "__module__"); + return 0; + } + Py_XINCREF(mod); + return mod; + } + else { + s = strrchr(type->tp_name, '.'); + if (s != NULL) + return PyString_FromStringAndSize( + type->tp_name, (Py_ssize_t)(s - type->tp_name)); + return PyString_FromString("__builtin__"); + } +} + +static int +type_set_module(PyTypeObject *type, PyObject *value, void *context) +{ + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_TypeError, + "can't set %s.__module__", type->tp_name); + return -1; + } + if (!value) { + PyErr_Format(PyExc_TypeError, + "can't delete %s.__module__", type->tp_name); + return -1; + } + + return PyDict_SetItemString(type->tp_dict, "__module__", value); +} + +static PyObject * +type_get_bases(PyTypeObject *type, void *context) +{ + Py_INCREF(type->tp_bases); + return type->tp_bases; +} + +static PyTypeObject *best_base(PyObject *); +static int mro_internal(PyTypeObject *); +static int compatible_for_assignment(PyTypeObject *, PyTypeObject *, char *); +static int add_subclass(PyTypeObject*, PyTypeObject*); +static void remove_subclass(PyTypeObject *, PyTypeObject *); +static void update_all_slots(PyTypeObject *); + +typedef int (*update_callback)(PyTypeObject *, void *); +static int update_subclasses(PyTypeObject *type, PyObject *name, + update_callback callback, void *data); +static int recurse_down_subclasses(PyTypeObject *type, PyObject *name, + update_callback callback, void *data); + +static int +mro_subclasses(PyTypeObject *type, PyObject* temp) +{ + PyTypeObject *subclass; + PyObject *ref, *subclasses, *old_mro; + Py_ssize_t i, n; + + subclasses = type->tp_subclasses; + if (subclasses == NULL) + return 0; + assert(PyList_Check(subclasses)); + n = PyList_GET_SIZE(subclasses); + for (i = 0; i < n; i++) { + ref = PyList_GET_ITEM(subclasses, i); + assert(PyWeakref_CheckRef(ref)); + subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); + assert(subclass != NULL); + if ((PyObject *)subclass == Py_None) + continue; + assert(PyType_Check(subclass)); + old_mro = subclass->tp_mro; + if (mro_internal(subclass) < 0) { + subclass->tp_mro = old_mro; + return -1; + } + else { + PyObject* tuple; + tuple = PyTuple_Pack(2, subclass, old_mro); + Py_DECREF(old_mro); + if (!tuple) + return -1; + if (PyList_Append(temp, tuple) < 0) + return -1; + Py_DECREF(tuple); + } + if (mro_subclasses(subclass, temp) < 0) + return -1; + } + return 0; +} + +static int +type_set_bases(PyTypeObject *type, PyObject *value, void *context) +{ + Py_ssize_t i; + int r = 0; + PyObject *ob, *temp; + PyTypeObject *new_base, *old_base; + PyObject *old_bases, *old_mro; + + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_TypeError, + "can't set %s.__bases__", type->tp_name); + return -1; + } + if (!value) { + PyErr_Format(PyExc_TypeError, + "can't delete %s.__bases__", type->tp_name); + return -1; + } + if (!PyTuple_Check(value)) { + PyErr_Format(PyExc_TypeError, + "can only assign tuple to %s.__bases__, not %s", + type->tp_name, value->ob_type->tp_name); + return -1; + } + if (PyTuple_GET_SIZE(value) == 0) { + PyErr_Format(PyExc_TypeError, + "can only assign non-empty tuple to %s.__bases__, not ()", + type->tp_name); + return -1; + } + for (i = 0; i < PyTuple_GET_SIZE(value); i++) { + ob = PyTuple_GET_ITEM(value, i); + if (!PyClass_Check(ob) && !PyType_Check(ob)) { + PyErr_Format( + PyExc_TypeError, + "%s.__bases__ must be tuple of old- or new-style classes, not '%s'", + type->tp_name, ob->ob_type->tp_name); + return -1; + } + if (PyType_Check(ob)) { + if (PyType_IsSubtype((PyTypeObject*)ob, type)) { + PyErr_SetString(PyExc_TypeError, + "a __bases__ item causes an inheritance cycle"); + return -1; + } + } + } + + new_base = best_base(value); + + if (!new_base) { + return -1; + } + + if (!compatible_for_assignment(type->tp_base, new_base, "__bases__")) + return -1; + + Py_INCREF(new_base); + Py_INCREF(value); + + old_bases = type->tp_bases; + old_base = type->tp_base; + old_mro = type->tp_mro; + + type->tp_bases = value; + type->tp_base = new_base; + + if (mro_internal(type) < 0) { + goto bail; + } + + temp = PyList_New(0); + if (!temp) + goto bail; + + r = mro_subclasses(type, temp); + + if (r < 0) { + for (i = 0; i < PyList_Size(temp); i++) { + PyTypeObject* cls; + PyObject* mro; + PyArg_UnpackTuple(PyList_GET_ITEM(temp, i), + "", 2, 2, &cls, &mro); + Py_DECREF(cls->tp_mro); + cls->tp_mro = mro; + Py_INCREF(cls->tp_mro); + } + Py_DECREF(temp); + goto bail; + } + + Py_DECREF(temp); + + /* any base that was in __bases__ but now isn't, we + need to remove |type| from its tp_subclasses. + conversely, any class now in __bases__ that wasn't + needs to have |type| added to its subclasses. */ + + /* for now, sod that: just remove from all old_bases, + add to all new_bases */ + + for (i = PyTuple_GET_SIZE(old_bases) - 1; i >= 0; i--) { + ob = PyTuple_GET_ITEM(old_bases, i); + if (PyType_Check(ob)) { + remove_subclass( + (PyTypeObject*)ob, type); + } + } + + for (i = PyTuple_GET_SIZE(value) - 1; i >= 0; i--) { + ob = PyTuple_GET_ITEM(value, i); + if (PyType_Check(ob)) { + if (add_subclass((PyTypeObject*)ob, type) < 0) + r = -1; + } + } + + update_all_slots(type); + + Py_DECREF(old_bases); + Py_DECREF(old_base); + Py_DECREF(old_mro); + + return r; + + bail: + Py_DECREF(type->tp_bases); + Py_DECREF(type->tp_base); + if (type->tp_mro != old_mro) { + Py_DECREF(type->tp_mro); + } + + type->tp_bases = old_bases; + type->tp_base = old_base; + type->tp_mro = old_mro; + + return -1; +} + +static PyObject * +type_dict(PyTypeObject *type, void *context) +{ + if (type->tp_dict == NULL) { + Py_INCREF(Py_None); + return Py_None; + } + return PyDictProxy_New(type->tp_dict); +} + +static PyObject * +type_get_doc(PyTypeObject *type, void *context) +{ + PyObject *result; + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) && type->tp_doc != NULL) + return PyString_FromString(type->tp_doc); + result = PyDict_GetItemString(type->tp_dict, "__doc__"); + if (result == NULL) { + result = Py_None; + Py_INCREF(result); + } + else if (result->ob_type->tp_descr_get) { + result = result->ob_type->tp_descr_get(result, NULL, + (PyObject *)type); + } + else { + Py_INCREF(result); + } + return result; +} + +static PyGetSetDef type_getsets[] = { + {"__name__", (getter)type_name, (setter)type_set_name, NULL}, + {"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL}, + {"__module__", (getter)type_module, (setter)type_set_module, NULL}, + {"__dict__", (getter)type_dict, NULL, NULL}, + {"__doc__", (getter)type_get_doc, NULL, NULL}, + {0} +}; + +static int +type_compare(PyObject *v, PyObject *w) +{ + /* This is called with type objects only. So we + can just compare the addresses. */ + Py_uintptr_t vv = (Py_uintptr_t)v; + Py_uintptr_t ww = (Py_uintptr_t)w; + return (vv < ww) ? -1 : (vv > ww) ? 1 : 0; +} + +static PyObject * +type_repr(PyTypeObject *type) +{ + PyObject *mod, *name, *rtn; + char *kind; + + mod = type_module(type, NULL); + if (mod == NULL) + PyErr_Clear(); + else if (!PyString_Check(mod)) { + Py_DECREF(mod); + mod = NULL; + } + name = type_name(type, NULL); + if (name == NULL) + return NULL; + + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) + kind = "class"; + else + kind = "type"; + + if (mod != NULL && strcmp(PyString_AS_STRING(mod), "__builtin__")) { + rtn = PyString_FromFormat("<%s '%s.%s'>", + kind, + PyString_AS_STRING(mod), + PyString_AS_STRING(name)); + } + else + rtn = PyString_FromFormat("<%s '%s'>", kind, type->tp_name); + + Py_XDECREF(mod); + Py_DECREF(name); + return rtn; +} + +static PyObject * +type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *obj; + + if (type->tp_new == NULL) { + PyErr_Format(PyExc_TypeError, + "cannot create '%.100s' instances", + type->tp_name); + return NULL; + } + + obj = type->tp_new(type, args, kwds); + if (obj != NULL) { + /* Ugly exception: when the call was type(something), + don't call tp_init on the result. */ + if (type == &PyType_Type && + PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && + (kwds == NULL || + (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) + return obj; + /* If the returned object is not an instance of type, + it won't be initialized. */ + if (!PyType_IsSubtype(obj->ob_type, type)) + return obj; + type = obj->ob_type; + if (PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS) && + type->tp_init != NULL && + type->tp_init(obj, args, kwds) < 0) { + Py_DECREF(obj); + obj = NULL; + } + } + return obj; +} + +PyObject * +PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) +{ + PyObject *obj; + const size_t size = _PyObject_VAR_SIZE(type, nitems+1); + /* note that we need to add one, for the sentinel */ + + if (PyType_IS_GC(type)) + obj = _PyObject_GC_Malloc(size); + else + obj = (PyObject *)PyObject_MALLOC(size); + + if (obj == NULL) + return PyErr_NoMemory(); + + memset(obj, '\0', size); + + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) + Py_INCREF(type); + + if (type->tp_itemsize == 0) + PyObject_INIT(obj, type); + else + (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems); + + if (PyType_IS_GC(type)) + _PyObject_GC_TRACK(obj); + return obj; +} + +PyObject * +PyType_GenericNew(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +/* Helpers for subtyping */ + +static int +traverse_slots(PyTypeObject *type, PyObject *self, visitproc visit, void *arg) +{ + Py_ssize_t i, n; + PyMemberDef *mp; + + n = type->ob_size; + mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); + for (i = 0; i < n; i++, mp++) { + if (mp->type == T_OBJECT_EX) { + char *addr = (char *)self + mp->offset; + PyObject *obj = *(PyObject **)addr; + if (obj != NULL) { + int err = visit(obj, arg); + if (err) + return err; + } + } + } + return 0; +} + +static int +subtype_traverse(PyObject *self, visitproc visit, void *arg) +{ + PyTypeObject *type, *base; + traverseproc basetraverse; + + /* Find the nearest base with a different tp_traverse, + and traverse slots while we're at it */ + type = self->ob_type; + base = type; + while ((basetraverse = base->tp_traverse) == subtype_traverse) { + if (base->ob_size) { + int err = traverse_slots(base, self, visit, arg); + if (err) + return err; + } + base = base->tp_base; + assert(base); + } + + if (type->tp_dictoffset != base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr && *dictptr) + Py_VISIT(*dictptr); + } + + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) + /* For a heaptype, the instances count as references + to the type. Traverse the type so the collector + can find cycles involving this link. */ + Py_VISIT(type); + + if (basetraverse) + return basetraverse(self, visit, arg); + return 0; +} + +static void +clear_slots(PyTypeObject *type, PyObject *self) +{ + Py_ssize_t i, n; + PyMemberDef *mp; + + n = type->ob_size; + mp = PyHeapType_GET_MEMBERS((PyHeapTypeObject *)type); + for (i = 0; i < n; i++, mp++) { + if (mp->type == T_OBJECT_EX && !(mp->flags & READONLY)) { + char *addr = (char *)self + mp->offset; + PyObject *obj = *(PyObject **)addr; + if (obj != NULL) { + *(PyObject **)addr = NULL; + Py_DECREF(obj); + } + } + } +} + +static int +subtype_clear(PyObject *self) +{ + PyTypeObject *type, *base; + inquiry baseclear; + + /* Find the nearest base with a different tp_clear + and clear slots while we're at it */ + type = self->ob_type; + base = type; + while ((baseclear = base->tp_clear) == subtype_clear) { + if (base->ob_size) + clear_slots(base, self); + base = base->tp_base; + assert(base); + } + + /* There's no need to clear the instance dict (if any); + the collector will call its tp_clear handler. */ + + if (baseclear) + return baseclear(self); + return 0; +} + +static void +subtype_dealloc(PyObject *self) +{ + PyTypeObject *type, *base; + destructor basedealloc; + + /* Extract the type; we expect it to be a heap type */ + type = self->ob_type; + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + + /* Test whether the type has GC exactly once */ + + if (!PyType_IS_GC(type)) { + /* It's really rare to find a dynamic type that doesn't have + GC; it can only happen when deriving from 'object' and not + adding any slots or instance variables. This allows + certain simplifications: there's no need to call + clear_slots(), or DECREF the dict, or clear weakrefs. */ + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + type->tp_del(self); + if (self->ob_refcnt > 0) + return; + } + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + assert(base->ob_size == 0); + base = base->tp_base; + assert(base); + } + + /* Call the base tp_dealloc() */ + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + /* Done */ + return; + } + + /* We get here only if the type has GC */ + + /* UnTrack and re-Track around the trashcan macro, alas */ + /* See explanation at end of function for full disclosure */ + PyObject_GC_UnTrack(self); + ++_PyTrash_delete_nesting; + Py_TRASHCAN_SAFE_BEGIN(self); + --_PyTrash_delete_nesting; + /* DO NOT restore GC tracking at this point. weakref callbacks + * (if any, and whether directly here or indirectly in something we + * call) may trigger GC, and if self is tracked at that point, it + * will look like trash to GC and GC will try to delete self again. + */ + + /* Find the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + base = base->tp_base; + assert(base); + } + + /* If we added a weaklist, we clear it. Do this *before* calling + the finalizer (__del__), clearing slots, or clearing the instance + dict. */ + + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) + PyObject_ClearWeakRefs(self); + + /* Maybe call finalizer; exit early if resurrected */ + if (type->tp_del) { + _PyObject_GC_TRACK(self); + type->tp_del(self); + if (self->ob_refcnt > 0) + goto endlabel; /* resurrected */ + else + _PyObject_GC_UNTRACK(self); + /* New weakrefs could be created during the finalizer call. + If this occurs, clear them out without calling their + finalizers since they might rely on part of the object + being finalized that has already been destroyed. */ + if (type->tp_weaklistoffset && !base->tp_weaklistoffset) { + /* Modeled after GET_WEAKREFS_LISTPTR() */ + PyWeakReference **list = (PyWeakReference **) \ + PyObject_GET_WEAKREFS_LISTPTR(self); + while (*list) + _PyWeakref_ClearRef(*list); + } + } + + /* Clear slots up to the nearest base with a different tp_dealloc */ + base = type; + while ((basedealloc = base->tp_dealloc) == subtype_dealloc) { + if (base->ob_size) + clear_slots(base, self); + base = base->tp_base; + assert(base); + } + + /* If we added a dict, DECREF it */ + if (type->tp_dictoffset && !base->tp_dictoffset) { + PyObject **dictptr = _PyObject_GetDictPtr(self); + if (dictptr != NULL) { + PyObject *dict = *dictptr; + if (dict != NULL) { + Py_DECREF(dict); + *dictptr = NULL; + } + } + } + + /* Call the base tp_dealloc(); first retrack self if + * basedealloc knows about gc. + */ + if (PyType_IS_GC(base)) + _PyObject_GC_TRACK(self); + assert(basedealloc); + basedealloc(self); + + /* Can't reference self beyond this point */ + Py_DECREF(type); + + endlabel: + ++_PyTrash_delete_nesting; + Py_TRASHCAN_SAFE_END(self); + --_PyTrash_delete_nesting; + + /* Explanation of the weirdness around the trashcan macros: + + Q. What do the trashcan macros do? + + A. Read the comment titled "Trashcan mechanism" in object.h. + For one, this explains why there must be a call to GC-untrack + before the trashcan begin macro. Without understanding the + trashcan code, the answers to the following questions don't make + sense. + + Q. Why do we GC-untrack before the trashcan and then immediately + GC-track again afterward? + + A. In the case that the base class is GC-aware, the base class + probably GC-untracks the object. If it does that using the + UNTRACK macro, this will crash when the object is already + untracked. Because we don't know what the base class does, the + only safe thing is to make sure the object is tracked when we + call the base class dealloc. But... The trashcan begin macro + requires that the object is *untracked* before it is called. So + the dance becomes: + + GC untrack + trashcan begin + GC track + + Q. Why did the last question say "immediately GC-track again"? + It's nowhere near immediately. + + A. Because the code *used* to re-track immediately. Bad Idea. + self has a refcount of 0, and if gc ever gets its hands on it + (which can happen if any weakref callback gets invoked), it + looks like trash to gc too, and gc also tries to delete self + then. But we're already deleting self. Double dealloction is + a subtle disaster. + + Q. Why the bizarre (net-zero) manipulation of + _PyTrash_delete_nesting around the trashcan macros? + + A. Some base classes (e.g. list) also use the trashcan mechanism. + The following scenario used to be possible: + + - suppose the trashcan level is one below the trashcan limit + + - subtype_dealloc() is called + + - the trashcan limit is not yet reached, so the trashcan level + is incremented and the code between trashcan begin and end is + executed + + - this destroys much of the object's contents, including its + slots and __dict__ + + - basedealloc() is called; this is really list_dealloc(), or + some other type which also uses the trashcan macros + + - the trashcan limit is now reached, so the object is put on the + trashcan's to-be-deleted-later list + + - basedealloc() returns + + - subtype_dealloc() decrefs the object's type + + - subtype_dealloc() returns + + - later, the trashcan code starts deleting the objects from its + to-be-deleted-later list + + - subtype_dealloc() is called *AGAIN* for the same object + + - at the very least (if the destroyed slots and __dict__ don't + cause problems) the object's type gets decref'ed a second + time, which is *BAD*!!! + + The remedy is to make sure that if the code between trashcan + begin and end in subtype_dealloc() is called, the code between + trashcan begin and end in basedealloc() will also be called. + This is done by decrementing the level after passing into the + trashcan block, and incrementing it just before leaving the + block. + + But now it's possible that a chain of objects consisting solely + of objects whose deallocator is subtype_dealloc() will defeat + the trashcan mechanism completely: the decremented level means + that the effective level never reaches the limit. Therefore, we + *increment* the level *before* entering the trashcan block, and + matchingly decrement it after leaving. This means the trashcan + code will trigger a little early, but that's no big deal. + + Q. Are there any live examples of code in need of all this + complexity? + + A. Yes. See SF bug 668433 for code that crashed (when Python was + compiled in debug mode) before the trashcan level manipulations + were added. For more discussion, see SF patches 581742, 575073 + and bug 574207. + */ +} + +static PyTypeObject *solid_base(PyTypeObject *type); + +/* type test with subclassing support */ + +int +PyType_IsSubtype(PyTypeObject *a, PyTypeObject *b) +{ + PyObject *mro; + + if (!(a->tp_flags & Py_TPFLAGS_HAVE_CLASS)) + return b == a || b == &PyBaseObject_Type; + + mro = a->tp_mro; + if (mro != NULL) { + /* Deal with multiple inheritance without recursion + by walking the MRO tuple */ + Py_ssize_t i, n; + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + if (PyTuple_GET_ITEM(mro, i) == (PyObject *)b) + return 1; + } + return 0; + } + else { + /* a is not completely initilized yet; follow tp_base */ + do { + if (a == b) + return 1; + a = a->tp_base; + } while (a != NULL); + return b == &PyBaseObject_Type; + } +} + +/* Internal routines to do a method lookup in the type + without looking in the instance dictionary + (so we can't use PyObject_GetAttr) but still binding + it to the instance. The arguments are the object, + the method name as a C string, and the address of a + static variable used to cache the interned Python string. + + Two variants: + + - lookup_maybe() returns NULL without raising an exception + when the _PyType_Lookup() call fails; + + - lookup_method() always raises an exception upon errors. +*/ + +static PyObject * +lookup_maybe(PyObject *self, char *attrstr, PyObject **attrobj) +{ + PyObject *res; + + if (*attrobj == NULL) { + *attrobj = PyString_InternFromString(attrstr); + if (*attrobj == NULL) + return NULL; + } + res = _PyType_Lookup(self->ob_type, *attrobj); + if (res != NULL) { + descrgetfunc f; + if ((f = res->ob_type->tp_descr_get) == NULL) + Py_INCREF(res); + else + res = f(res, self, (PyObject *)(self->ob_type)); + } + return res; +} + +static PyObject * +lookup_method(PyObject *self, char *attrstr, PyObject **attrobj) +{ + PyObject *res = lookup_maybe(self, attrstr, attrobj); + if (res == NULL && !PyErr_Occurred()) + PyErr_SetObject(PyExc_AttributeError, *attrobj); + return res; +} + +/* A variation of PyObject_CallMethod that uses lookup_method() + instead of PyObject_GetAttrString(). This uses the same convention + as lookup_method to cache the interned name string object. */ + +static PyObject * +call_method(PyObject *o, char *name, PyObject **nameobj, char *format, ...) +{ + va_list va; + PyObject *args, *func = 0, *retval; + va_start(va, format); + + func = lookup_maybe(o, name, nameobj); + if (func == NULL) { + va_end(va); + if (!PyErr_Occurred()) + PyErr_SetObject(PyExc_AttributeError, *nameobj); + return NULL; + } + + if (format && *format) + args = Py_VaBuildValue(format, va); + else + args = PyTuple_New(0); + + va_end(va); + + if (args == NULL) + return NULL; + + assert(PyTuple_Check(args)); + retval = PyObject_Call(func, args, NULL); + + Py_DECREF(args); + Py_DECREF(func); + + return retval; +} + +/* Clone of call_method() that returns NotImplemented when the lookup fails. */ + +static PyObject * +call_maybe(PyObject *o, char *name, PyObject **nameobj, char *format, ...) +{ + va_list va; + PyObject *args, *func = 0, *retval; + va_start(va, format); + + func = lookup_maybe(o, name, nameobj); + if (func == NULL) { + va_end(va); + if (!PyErr_Occurred()) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return NULL; + } + + if (format && *format) + args = Py_VaBuildValue(format, va); + else + args = PyTuple_New(0); + + va_end(va); + + if (args == NULL) + return NULL; + + assert(PyTuple_Check(args)); + retval = PyObject_Call(func, args, NULL); + + Py_DECREF(args); + Py_DECREF(func); + + return retval; +} + +static int +fill_classic_mro(PyObject *mro, PyObject *cls) +{ + PyObject *bases, *base; + Py_ssize_t i, n; + + assert(PyList_Check(mro)); + assert(PyClass_Check(cls)); + i = PySequence_Contains(mro, cls); + if (i < 0) + return -1; + if (!i) { + if (PyList_Append(mro, cls) < 0) + return -1; + } + bases = ((PyClassObject *)cls)->cl_bases; + assert(bases && PyTuple_Check(bases)); + n = PyTuple_GET_SIZE(bases); + for (i = 0; i < n; i++) { + base = PyTuple_GET_ITEM(bases, i); + if (fill_classic_mro(mro, base) < 0) + return -1; + } + return 0; +} + +static PyObject * +classic_mro(PyObject *cls) +{ + PyObject *mro; + + assert(PyClass_Check(cls)); + mro = PyList_New(0); + if (mro != NULL) { + if (fill_classic_mro(mro, cls) == 0) + return mro; + Py_DECREF(mro); + } + return NULL; +} + +/* + Method resolution order algorithm C3 described in + "A Monotonic Superclass Linearization for Dylan", + by Kim Barrett, Bob Cassel, Paul Haahr, + David A. Moon, Keith Playford, and P. Tucker Withington. + (OOPSLA 1996) + + Some notes about the rules implied by C3: + + No duplicate bases. + It isn't legal to repeat a class in a list of base classes. + + The next three properties are the 3 constraints in "C3". + + Local precendece order. + If A precedes B in C's MRO, then A will precede B in the MRO of all + subclasses of C. + + Monotonicity. + The MRO of a class must be an extension without reordering of the + MRO of each of its superclasses. + + Extended Precedence Graph (EPG). + Linearization is consistent if there is a path in the EPG from + each class to all its successors in the linearization. See + the paper for definition of EPG. + */ + +static int +tail_contains(PyObject *list, int whence, PyObject *o) { + Py_ssize_t j, size; + size = PyList_GET_SIZE(list); + + for (j = whence+1; j < size; j++) { + if (PyList_GET_ITEM(list, j) == o) + return 1; + } + return 0; +} + +static PyObject * +class_name(PyObject *cls) +{ + PyObject *name = PyObject_GetAttrString(cls, "__name__"); + if (name == NULL) { + PyErr_Clear(); + Py_XDECREF(name); + name = PyObject_Repr(cls); + } + if (name == NULL) + return NULL; + if (!PyString_Check(name)) { + Py_DECREF(name); + return NULL; + } + return name; +} + +static int +check_duplicates(PyObject *list) +{ + Py_ssize_t i, j, n; + /* Let's use a quadratic time algorithm, + assuming that the bases lists is short. + */ + n = PyList_GET_SIZE(list); + for (i = 0; i < n; i++) { + PyObject *o = PyList_GET_ITEM(list, i); + for (j = i + 1; j < n; j++) { + if (PyList_GET_ITEM(list, j) == o) { + o = class_name(o); + PyErr_Format(PyExc_TypeError, + "duplicate base class %s", + o ? PyString_AS_STRING(o) : "?"); + Py_XDECREF(o); + return -1; + } + } + } + return 0; +} + +/* Raise a TypeError for an MRO order disagreement. + + It's hard to produce a good error message. In the absence of better + insight into error reporting, report the classes that were candidates + to be put next into the MRO. There is some conflict between the + order in which they should be put in the MRO, but it's hard to + diagnose what constraint can't be satisfied. +*/ + +static void +set_mro_error(PyObject *to_merge, int *remain) +{ + Py_ssize_t i, n, off, to_merge_size; + char buf[1000]; + PyObject *k, *v; + PyObject *set = PyDict_New(); + if (!set) return; + + to_merge_size = PyList_GET_SIZE(to_merge); + for (i = 0; i < to_merge_size; i++) { + PyObject *L = PyList_GET_ITEM(to_merge, i); + if (remain[i] < PyList_GET_SIZE(L)) { + PyObject *c = PyList_GET_ITEM(L, remain[i]); + if (PyDict_SetItem(set, c, Py_None) < 0) { + Py_DECREF(set); + return; + } + } + } + n = PyDict_Size(set); + + off = PyOS_snprintf(buf, sizeof(buf), "Cannot create a \ +consistent method resolution\norder (MRO) for bases"); + i = 0; + while (PyDict_Next(set, &i, &k, &v) && (size_t)off < sizeof(buf)) { + PyObject *name = class_name(k); + off += PyOS_snprintf(buf + off, sizeof(buf) - off, " %s", + name ? PyString_AS_STRING(name) : "?"); + Py_XDECREF(name); + if (--n && (size_t)(off+1) < sizeof(buf)) { + buf[off++] = ','; + buf[off] = '\0'; + } + } + PyErr_SetString(PyExc_TypeError, buf); + Py_DECREF(set); +} + +static int +pmerge(PyObject *acc, PyObject* to_merge) { + Py_ssize_t i, j, to_merge_size, empty_cnt; + int *remain; + int ok; + + to_merge_size = PyList_GET_SIZE(to_merge); + + /* remain stores an index into each sublist of to_merge. + remain[i] is the index of the next base in to_merge[i] + that is not included in acc. + */ + remain = (int *)PyMem_MALLOC(SIZEOF_INT*to_merge_size); + if (remain == NULL) + return -1; + for (i = 0; i < to_merge_size; i++) + remain[i] = 0; + + again: + empty_cnt = 0; + for (i = 0; i < to_merge_size; i++) { + PyObject *candidate; + + PyObject *cur_list = PyList_GET_ITEM(to_merge, i); + + if (remain[i] >= PyList_GET_SIZE(cur_list)) { + empty_cnt++; + continue; + } + + /* Choose next candidate for MRO. + + The input sequences alone can determine the choice. + If not, choose the class which appears in the MRO + of the earliest direct superclass of the new class. + */ + + candidate = PyList_GET_ITEM(cur_list, remain[i]); + for (j = 0; j < to_merge_size; j++) { + PyObject *j_lst = PyList_GET_ITEM(to_merge, j); + if (tail_contains(j_lst, remain[j], candidate)) { + goto skip; /* continue outer loop */ + } + } + ok = PyList_Append(acc, candidate); + if (ok < 0) { + PyMem_Free(remain); + return -1; + } + for (j = 0; j < to_merge_size; j++) { + PyObject *j_lst = PyList_GET_ITEM(to_merge, j); + if (remain[j] < PyList_GET_SIZE(j_lst) && + PyList_GET_ITEM(j_lst, remain[j]) == candidate) { + remain[j]++; + } + } + goto again; + skip: ; + } + + if (empty_cnt == to_merge_size) { + PyMem_FREE(remain); + return 0; + } + set_mro_error(to_merge, remain); + PyMem_FREE(remain); + return -1; +} + +static PyObject * +mro_implementation(PyTypeObject *type) +{ + Py_ssize_t i, n; + int ok; + PyObject *bases, *result; + PyObject *to_merge, *bases_aslist; + + if(type->tp_dict == NULL) { + if(PyType_Ready(type) < 0) + return NULL; + } + + /* Find a superclass linearization that honors the constraints + of the explicit lists of bases and the constraints implied by + each base class. + + to_merge is a list of lists, where each list is a superclass + linearization implied by a base class. The last element of + to_merge is the declared list of bases. + */ + + bases = type->tp_bases; + n = PyTuple_GET_SIZE(bases); + + to_merge = PyList_New(n+1); + if (to_merge == NULL) + return NULL; + + for (i = 0; i < n; i++) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + PyObject *parentMRO; + if (PyType_Check(base)) + parentMRO = PySequence_List( + ((PyTypeObject*)base)->tp_mro); + else + parentMRO = classic_mro(base); + if (parentMRO == NULL) { + Py_DECREF(to_merge); + return NULL; + } + + PyList_SET_ITEM(to_merge, i, parentMRO); + } + + bases_aslist = PySequence_List(bases); + if (bases_aslist == NULL) { + Py_DECREF(to_merge); + return NULL; + } + /* This is just a basic sanity check. */ + if (check_duplicates(bases_aslist) < 0) { + Py_DECREF(to_merge); + Py_DECREF(bases_aslist); + return NULL; + } + PyList_SET_ITEM(to_merge, n, bases_aslist); + + result = Py_BuildValue("[O]", (PyObject *)type); + if (result == NULL) { + Py_DECREF(to_merge); + return NULL; + } + + ok = pmerge(result, to_merge); + Py_DECREF(to_merge); + if (ok < 0) { + Py_DECREF(result); + return NULL; + } + + return result; +} + +static PyObject * +mro_external(PyObject *self) +{ + PyTypeObject *type = (PyTypeObject *)self; + + return mro_implementation(type); +} + +static int +mro_internal(PyTypeObject *type) +{ + PyObject *mro, *result, *tuple; + int checkit = 0; + + if (type->ob_type == &PyType_Type) { + result = mro_implementation(type); + } + else { + static PyObject *mro_str; + checkit = 1; + mro = lookup_method((PyObject *)type, "mro", &mro_str); + if (mro == NULL) + return -1; + result = PyObject_CallObject(mro, NULL); + Py_DECREF(mro); + } + if (result == NULL) + return -1; + tuple = PySequence_Tuple(result); + Py_DECREF(result); + if (tuple == NULL) + return -1; + if (checkit) { + Py_ssize_t i, len; + PyObject *cls; + PyTypeObject *solid; + + solid = solid_base(type); + + len = PyTuple_GET_SIZE(tuple); + + for (i = 0; i < len; i++) { + PyTypeObject *t; + cls = PyTuple_GET_ITEM(tuple, i); + if (PyClass_Check(cls)) + continue; + else if (!PyType_Check(cls)) { + PyErr_Format(PyExc_TypeError, + "mro() returned a non-class ('%.500s')", + cls->ob_type->tp_name); + Py_DECREF(tuple); + return -1; + } + t = (PyTypeObject*)cls; + if (!PyType_IsSubtype(solid, solid_base(t))) { + PyErr_Format(PyExc_TypeError, + "mro() returned base with unsuitable layout ('%.500s')", + t->tp_name); + Py_DECREF(tuple); + return -1; + } + } + } + type->tp_mro = tuple; + return 0; +} + + +/* Calculate the best base amongst multiple base classes. + This is the first one that's on the path to the "solid base". */ + +static PyTypeObject * +best_base(PyObject *bases) +{ + Py_ssize_t i, n; + PyTypeObject *base, *winner, *candidate, *base_i; + PyObject *base_proto; + + assert(PyTuple_Check(bases)); + n = PyTuple_GET_SIZE(bases); + assert(n > 0); + base = NULL; + winner = NULL; + for (i = 0; i < n; i++) { + base_proto = PyTuple_GET_ITEM(bases, i); + if (PyClass_Check(base_proto)) + continue; + if (!PyType_Check(base_proto)) { + PyErr_SetString( + PyExc_TypeError, + "bases must be types"); + return NULL; + } + base_i = (PyTypeObject *)base_proto; + if (base_i->tp_dict == NULL) { + if (PyType_Ready(base_i) < 0) + return NULL; + } + candidate = solid_base(base_i); + if (winner == NULL) { + winner = candidate; + base = base_i; + } + else if (PyType_IsSubtype(winner, candidate)) + ; + else if (PyType_IsSubtype(candidate, winner)) { + winner = candidate; + base = base_i; + } + else { + PyErr_SetString( + PyExc_TypeError, + "multiple bases have " + "instance lay-out conflict"); + return NULL; + } + } + if (base == NULL) + PyErr_SetString(PyExc_TypeError, + "a new-style class can't have only classic bases"); + return base; +} + +static int +extra_ivars(PyTypeObject *type, PyTypeObject *base) +{ + size_t t_size = type->tp_basicsize; + size_t b_size = base->tp_basicsize; + + assert(t_size >= b_size); /* Else type smaller than base! */ + if (type->tp_itemsize || base->tp_itemsize) { + /* If itemsize is involved, stricter rules */ + return t_size != b_size || + type->tp_itemsize != base->tp_itemsize; + } + if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 && + type->tp_weaklistoffset + sizeof(PyObject *) == t_size) + t_size -= sizeof(PyObject *); + if (type->tp_dictoffset && base->tp_dictoffset == 0 && + type->tp_dictoffset + sizeof(PyObject *) == t_size) + t_size -= sizeof(PyObject *); + + return t_size != b_size; +} + +static PyTypeObject * +solid_base(PyTypeObject *type) +{ + PyTypeObject *base; + + if (type->tp_base) + base = solid_base(type->tp_base); + else + base = &PyBaseObject_Type; + if (extra_ivars(type, base)) + return type; + else + return base; +} + +static void object_dealloc(PyObject *); +static int object_init(PyObject *, PyObject *, PyObject *); +static int update_slot(PyTypeObject *, PyObject *); +static void fixup_slot_dispatchers(PyTypeObject *); + +static PyObject * +subtype_dict(PyObject *obj, void *context) +{ + PyObject **dictptr = _PyObject_GetDictPtr(obj); + PyObject *dict; + + if (dictptr == NULL) { + PyErr_SetString(PyExc_AttributeError, + "This object has no __dict__"); + return NULL; + } + dict = *dictptr; + if (dict == NULL) + *dictptr = dict = PyDict_New(); + Py_XINCREF(dict); + return dict; +} + +static int +subtype_setdict(PyObject *obj, PyObject *value, void *context) +{ + PyObject **dictptr = _PyObject_GetDictPtr(obj); + PyObject *dict; + + if (dictptr == NULL) { + PyErr_SetString(PyExc_AttributeError, + "This object has no __dict__"); + return -1; + } + if (value != NULL && !PyDict_Check(value)) { + PyErr_Format(PyExc_TypeError, + "__dict__ must be set to a dictionary, " + "not a '%.200s'", value->ob_type->tp_name); + return -1; + } + dict = *dictptr; + Py_XINCREF(value); + *dictptr = value; + Py_XDECREF(dict); + return 0; +} + +static PyObject * +subtype_getweakref(PyObject *obj, void *context) +{ + PyObject **weaklistptr; + PyObject *result; + + if (obj->ob_type->tp_weaklistoffset == 0) { + PyErr_SetString(PyExc_AttributeError, + "This object has no __weakref__"); + return NULL; + } + assert(obj->ob_type->tp_weaklistoffset > 0); + assert(obj->ob_type->tp_weaklistoffset + sizeof(PyObject *) <= + (size_t)(obj->ob_type->tp_basicsize)); + weaklistptr = (PyObject **) + ((char *)obj + obj->ob_type->tp_weaklistoffset); + if (*weaklistptr == NULL) + result = Py_None; + else + result = *weaklistptr; + Py_INCREF(result); + return result; +} + +/* Three variants on the subtype_getsets list. */ + +static PyGetSetDef subtype_getsets_full[] = { + {"__dict__", subtype_dict, subtype_setdict, + PyDoc_STR("dictionary for instance variables (if defined)")}, + {"__weakref__", subtype_getweakref, NULL, + PyDoc_STR("list of weak references to the object (if defined)")}, + {0} +}; + +static PyGetSetDef subtype_getsets_dict_only[] = { + {"__dict__", subtype_dict, subtype_setdict, + PyDoc_STR("dictionary for instance variables (if defined)")}, + {0} +}; + +static PyGetSetDef subtype_getsets_weakref_only[] = { + {"__weakref__", subtype_getweakref, NULL, + PyDoc_STR("list of weak references to the object (if defined)")}, + {0} +}; + +static int +valid_identifier(PyObject *s) +{ + unsigned char *p; + Py_ssize_t i, n; + + if (!PyString_Check(s)) { + PyErr_Format(PyExc_TypeError, + "__slots__ items must be strings, not '%.200s'", + s->ob_type->tp_name); + return 0; + } + p = (unsigned char *) PyString_AS_STRING(s); + n = PyString_GET_SIZE(s); + /* We must reject an empty name. As a hack, we bump the + length to 1 so that the loop will balk on the trailing \0. */ + if (n == 0) + n = 1; + for (i = 0; i < n; i++, p++) { + if (!(i == 0 ? isalpha(*p) : isalnum(*p)) && *p != '_') { + PyErr_SetString(PyExc_TypeError, + "__slots__ must be identifiers"); + return 0; + } + } + return 1; +} + +#ifdef Py_USING_UNICODE +/* Replace Unicode objects in slots. */ + +static PyObject * +_unicode_to_string(PyObject *slots, Py_ssize_t nslots) +{ + PyObject *tmp = NULL; + PyObject *slot_name, *new_name; + Py_ssize_t i; + + for (i = 0; i < nslots; i++) { + if (PyUnicode_Check(slot_name = PyTuple_GET_ITEM(slots, i))) { + if (tmp == NULL) { + tmp = PySequence_List(slots); + if (tmp == NULL) + return NULL; + } + new_name = _PyUnicode_AsDefaultEncodedString(slot_name, + NULL); + if (new_name == NULL) { + Py_DECREF(tmp); + return NULL; + } + Py_INCREF(new_name); + PyList_SET_ITEM(tmp, i, new_name); + Py_DECREF(slot_name); + } + } + if (tmp != NULL) { + slots = PyList_AsTuple(tmp); + Py_DECREF(tmp); + } + return slots; +} +#endif + +static PyObject * +type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) +{ + PyObject *name, *bases, *dict; + static char *kwlist[] = {"name", "bases", "dict", 0}; + PyObject *slots, *tmp, *newslots; + PyTypeObject *type, *base, *tmptype, *winner; + PyHeapTypeObject *et; + PyMemberDef *mp; + Py_ssize_t i, nbases, nslots, slotoffset, add_dict, add_weak; + int j, may_add_dict, may_add_weak; + + assert(args != NULL && PyTuple_Check(args)); + assert(kwds == NULL || PyDict_Check(kwds)); + + /* Special case: type(x) should return x->ob_type */ + { + const Py_ssize_t nargs = PyTuple_GET_SIZE(args); + const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds); + + if (PyType_CheckExact(metatype) && nargs == 1 && nkwds == 0) { + PyObject *x = PyTuple_GET_ITEM(args, 0); + Py_INCREF(x->ob_type); + return (PyObject *) x->ob_type; + } + + /* SF bug 475327 -- if that didn't trigger, we need 3 + arguments. but PyArg_ParseTupleAndKeywords below may give + a msg saying type() needs exactly 3. */ + if (nargs + nkwds != 3) { + PyErr_SetString(PyExc_TypeError, + "type() takes 1 or 3 arguments"); + return NULL; + } + } + + /* Check arguments: (name, bases, dict) */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "SO!O!:type", kwlist, + &name, + &PyTuple_Type, &bases, + &PyDict_Type, &dict)) + return NULL; + + /* Determine the proper metatype to deal with this, + and check for metatype conflicts while we're at it. + Note that if some other metatype wins to contract, + it's possible that its instances are not types. */ + nbases = PyTuple_GET_SIZE(bases); + winner = metatype; + for (i = 0; i < nbases; i++) { + tmp = PyTuple_GET_ITEM(bases, i); + tmptype = tmp->ob_type; + if (tmptype == &PyClass_Type) + continue; /* Special case classic classes */ + if (PyType_IsSubtype(winner, tmptype)) + continue; + if (PyType_IsSubtype(tmptype, winner)) { + winner = tmptype; + continue; + } + PyErr_SetString(PyExc_TypeError, + "metaclass conflict: " + "the metaclass of a derived class " + "must be a (non-strict) subclass " + "of the metaclasses of all its bases"); + return NULL; + } + if (winner != metatype) { + if (winner->tp_new != type_new) /* Pass it to the winner */ + return winner->tp_new(winner, args, kwds); + metatype = winner; + } + + /* Adjust for empty tuple bases */ + if (nbases == 0) { + bases = PyTuple_Pack(1, &PyBaseObject_Type); + if (bases == NULL) + return NULL; + nbases = 1; + } + else + Py_INCREF(bases); + + /* XXX From here until type is allocated, "return NULL" leaks bases! */ + + /* Calculate best base, and check that all bases are type objects */ + base = best_base(bases); + if (base == NULL) { + Py_DECREF(bases); + return NULL; + } + if (!PyType_HasFeature(base, Py_TPFLAGS_BASETYPE)) { + PyErr_Format(PyExc_TypeError, + "type '%.100s' is not an acceptable base type", + base->tp_name); + Py_DECREF(bases); + return NULL; + } + + /* Check for a __slots__ sequence variable in dict, and count it */ + slots = PyDict_GetItemString(dict, "__slots__"); + nslots = 0; + add_dict = 0; + add_weak = 0; + may_add_dict = base->tp_dictoffset == 0; + may_add_weak = base->tp_weaklistoffset == 0 && base->tp_itemsize == 0; + if (slots == NULL) { + if (may_add_dict) { + add_dict++; + } + if (may_add_weak) { + add_weak++; + } + } + else { + /* Have slots */ + + /* Make it into a tuple */ + if (PyString_Check(slots)) + slots = PyTuple_Pack(1, slots); + else + slots = PySequence_Tuple(slots); + if (slots == NULL) { + Py_DECREF(bases); + return NULL; + } + assert(PyTuple_Check(slots)); + + /* Are slots allowed? */ + nslots = PyTuple_GET_SIZE(slots); + if (nslots > 0 && base->tp_itemsize != 0) { + PyErr_Format(PyExc_TypeError, + "nonempty __slots__ " + "not supported for subtype of '%s'", + base->tp_name); + bad_slots: + Py_DECREF(bases); + Py_DECREF(slots); + return NULL; + } + +#ifdef Py_USING_UNICODE + tmp = _unicode_to_string(slots, nslots); + if (tmp == NULL) + goto bad_slots; + if (tmp != slots) { + Py_DECREF(slots); + slots = tmp; + } +#endif + /* Check for valid slot names and two special cases */ + for (i = 0; i < nslots; i++) { + PyObject *tmp = PyTuple_GET_ITEM(slots, i); + char *s; + if (!valid_identifier(tmp)) + goto bad_slots; + assert(PyString_Check(tmp)); + s = PyString_AS_STRING(tmp); + if (strcmp(s, "__dict__") == 0) { + if (!may_add_dict || add_dict) { + PyErr_SetString(PyExc_TypeError, + "__dict__ slot disallowed: " + "we already got one"); + goto bad_slots; + } + add_dict++; + } + if (strcmp(s, "__weakref__") == 0) { + if (!may_add_weak || add_weak) { + PyErr_SetString(PyExc_TypeError, + "__weakref__ slot disallowed: " + "either we already got one, " + "or __itemsize__ != 0"); + goto bad_slots; + } + add_weak++; + } + } + + /* Copy slots into yet another tuple, demangling names */ + newslots = PyTuple_New(nslots - add_dict - add_weak); + if (newslots == NULL) + goto bad_slots; + for (i = j = 0; i < nslots; i++) { + char *s; + tmp = PyTuple_GET_ITEM(slots, i); + s = PyString_AS_STRING(tmp); + if ((add_dict && strcmp(s, "__dict__") == 0) || + (add_weak && strcmp(s, "__weakref__") == 0)) + continue; + tmp =_Py_Mangle(name, tmp); + if (!tmp) + goto bad_slots; + PyTuple_SET_ITEM(newslots, j, tmp); + j++; + } + assert(j == nslots - add_dict - add_weak); + nslots = j; + Py_DECREF(slots); + slots = newslots; + + /* Secondary bases may provide weakrefs or dict */ + if (nbases > 1 && + ((may_add_dict && !add_dict) || + (may_add_weak && !add_weak))) { + for (i = 0; i < nbases; i++) { + tmp = PyTuple_GET_ITEM(bases, i); + if (tmp == (PyObject *)base) + continue; /* Skip primary base */ + if (PyClass_Check(tmp)) { + /* Classic base class provides both */ + if (may_add_dict && !add_dict) + add_dict++; + if (may_add_weak && !add_weak) + add_weak++; + break; + } + assert(PyType_Check(tmp)); + tmptype = (PyTypeObject *)tmp; + if (may_add_dict && !add_dict && + tmptype->tp_dictoffset != 0) + add_dict++; + if (may_add_weak && !add_weak && + tmptype->tp_weaklistoffset != 0) + add_weak++; + if (may_add_dict && !add_dict) + continue; + if (may_add_weak && !add_weak) + continue; + /* Nothing more to check */ + break; + } + } + } + + /* XXX From here until type is safely allocated, + "return NULL" may leak slots! */ + + /* Allocate the type object */ + type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots); + if (type == NULL) { + Py_XDECREF(slots); + Py_DECREF(bases); + return NULL; + } + + /* Keep name and slots alive in the extended type object */ + et = (PyHeapTypeObject *)type; + Py_INCREF(name); + et->ht_name = name; + et->ht_slots = slots; + + /* Initialize tp_flags */ + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | + Py_TPFLAGS_BASETYPE; + if (base->tp_flags & Py_TPFLAGS_HAVE_GC) + type->tp_flags |= Py_TPFLAGS_HAVE_GC; + + /* It's a new-style number unless it specifically inherits any + old-style numeric behavior */ + if ((base->tp_flags & Py_TPFLAGS_CHECKTYPES) || + (base->tp_as_number == NULL)) + type->tp_flags |= Py_TPFLAGS_CHECKTYPES; + + /* Initialize essential fields */ + type->tp_as_number = &et->as_number; + type->tp_as_sequence = &et->as_sequence; + type->tp_as_mapping = &et->as_mapping; + type->tp_as_buffer = &et->as_buffer; + type->tp_name = PyString_AS_STRING(name); + + /* Set tp_base and tp_bases */ + type->tp_bases = bases; + Py_INCREF(base); + type->tp_base = base; + + /* Initialize tp_dict from passed-in dict */ + type->tp_dict = dict = PyDict_Copy(dict); + if (dict == NULL) { + Py_DECREF(type); + return NULL; + } + + /* Set __module__ in the dict */ + if (PyDict_GetItemString(dict, "__module__") == NULL) { + tmp = PyEval_GetGlobals(); + if (tmp != NULL) { + tmp = PyDict_GetItemString(tmp, "__name__"); + if (tmp != NULL) { + if (PyDict_SetItemString(dict, "__module__", + tmp) < 0) + return NULL; + } + } + } + + /* Set tp_doc to a copy of dict['__doc__'], if the latter is there + and is a string. The __doc__ accessor will first look for tp_doc; + if that fails, it will still look into __dict__. + */ + { + PyObject *doc = PyDict_GetItemString(dict, "__doc__"); + if (doc != NULL && PyString_Check(doc)) { + const size_t n = (size_t)PyString_GET_SIZE(doc); + char *tp_doc = (char *)PyObject_MALLOC(n+1); + if (tp_doc == NULL) { + Py_DECREF(type); + return NULL; + } + memcpy(tp_doc, PyString_AS_STRING(doc), n+1); + type->tp_doc = tp_doc; + } + } + + /* Special-case __new__: if it's a plain function, + make it a static function */ + tmp = PyDict_GetItemString(dict, "__new__"); + if (tmp != NULL && PyFunction_Check(tmp)) { + tmp = PyStaticMethod_New(tmp); + if (tmp == NULL) { + Py_DECREF(type); + return NULL; + } + PyDict_SetItemString(dict, "__new__", tmp); + Py_DECREF(tmp); + } + + /* Add descriptors for custom slots from __slots__, or for __dict__ */ + mp = PyHeapType_GET_MEMBERS(et); + slotoffset = base->tp_basicsize; + if (slots != NULL) { + for (i = 0; i < nslots; i++, mp++) { + mp->name = PyString_AS_STRING( + PyTuple_GET_ITEM(slots, i)); + mp->type = T_OBJECT_EX; + mp->offset = slotoffset; + + /* __dict__ and __weakref__ are already filtered out */ + assert(strcmp(mp->name, "__dict__") != 0); + assert(strcmp(mp->name, "__weakref__") != 0); + + slotoffset += sizeof(PyObject *); + } + } + if (add_dict) { + if (base->tp_itemsize) + type->tp_dictoffset = -(long)sizeof(PyObject *); + else + type->tp_dictoffset = slotoffset; + slotoffset += sizeof(PyObject *); + } + if (add_weak) { + assert(!base->tp_itemsize); + type->tp_weaklistoffset = slotoffset; + slotoffset += sizeof(PyObject *); + } + type->tp_basicsize = slotoffset; + type->tp_itemsize = base->tp_itemsize; + type->tp_members = PyHeapType_GET_MEMBERS(et); + + if (type->tp_weaklistoffset && type->tp_dictoffset) + type->tp_getset = subtype_getsets_full; + else if (type->tp_weaklistoffset && !type->tp_dictoffset) + type->tp_getset = subtype_getsets_weakref_only; + else if (!type->tp_weaklistoffset && type->tp_dictoffset) + type->tp_getset = subtype_getsets_dict_only; + else + type->tp_getset = NULL; + + /* Special case some slots */ + if (type->tp_dictoffset != 0 || nslots > 0) { + if (base->tp_getattr == NULL && base->tp_getattro == NULL) + type->tp_getattro = PyObject_GenericGetAttr; + if (base->tp_setattr == NULL && base->tp_setattro == NULL) + type->tp_setattro = PyObject_GenericSetAttr; + } + type->tp_dealloc = subtype_dealloc; + + /* Enable GC unless there are really no instance variables possible */ + if (!(type->tp_basicsize == sizeof(PyObject) && + type->tp_itemsize == 0)) + type->tp_flags |= Py_TPFLAGS_HAVE_GC; + + /* Always override allocation strategy to use regular heap */ + type->tp_alloc = PyType_GenericAlloc; + if (type->tp_flags & Py_TPFLAGS_HAVE_GC) { + type->tp_free = PyObject_GC_Del; + type->tp_traverse = subtype_traverse; + type->tp_clear = subtype_clear; + } + else + type->tp_free = PyObject_Del; + + /* Initialize the rest */ + if (PyType_Ready(type) < 0) { + Py_DECREF(type); + return NULL; + } + + /* Put the proper slots in place */ + fixup_slot_dispatchers(type); + + return (PyObject *)type; +} + +/* Internal API to look for a name through the MRO. + This returns a borrowed reference, and doesn't set an exception! */ +PyObject * +_PyType_Lookup(PyTypeObject *type, PyObject *name) +{ + Py_ssize_t i, n; + PyObject *mro, *res, *base, *dict; + + /* Look in tp_dict of types in MRO */ + mro = type->tp_mro; + + /* If mro is NULL, the type is either not yet initialized + by PyType_Ready(), or already cleared by type_clear(). + Either way the safest thing to do is to return NULL. */ + if (mro == NULL) + return NULL; + + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + for (i = 0; i < n; i++) { + base = PyTuple_GET_ITEM(mro, i); + if (PyClass_Check(base)) + dict = ((PyClassObject *)base)->cl_dict; + else { + assert(PyType_Check(base)); + dict = ((PyTypeObject *)base)->tp_dict; + } + assert(dict && PyDict_Check(dict)); + res = PyDict_GetItem(dict, name); + if (res != NULL) + return res; + } + return NULL; +} + +/* This is similar to PyObject_GenericGetAttr(), + but uses _PyType_Lookup() instead of just looking in type->tp_dict. */ +static PyObject * +type_getattro(PyTypeObject *type, PyObject *name) +{ + PyTypeObject *metatype = type->ob_type; + PyObject *meta_attribute, *attribute; + descrgetfunc meta_get; + + /* Initialize this type (we'll assume the metatype is initialized) */ + if (type->tp_dict == NULL) { + if (PyType_Ready(type) < 0) + return NULL; + } + + /* No readable descriptor found yet */ + meta_get = NULL; + + /* Look for the attribute in the metatype */ + meta_attribute = _PyType_Lookup(metatype, name); + + if (meta_attribute != NULL) { + meta_get = meta_attribute->ob_type->tp_descr_get; + + if (meta_get != NULL && PyDescr_IsData(meta_attribute)) { + /* Data descriptors implement tp_descr_set to intercept + * writes. Assume the attribute is not overridden in + * type's tp_dict (and bases): call the descriptor now. + */ + return meta_get(meta_attribute, (PyObject *)type, + (PyObject *)metatype); + } + Py_INCREF(meta_attribute); + } + + /* No data descriptor found on metatype. Look in tp_dict of this + * type and its bases */ + attribute = _PyType_Lookup(type, name); + if (attribute != NULL) { + /* Implement descriptor functionality, if any */ + descrgetfunc local_get = attribute->ob_type->tp_descr_get; + + Py_XDECREF(meta_attribute); + + if (local_get != NULL) { + /* NULL 2nd argument indicates the descriptor was + * found on the target object itself (or a base) */ + return local_get(attribute, (PyObject *)NULL, + (PyObject *)type); + } + + Py_INCREF(attribute); + return attribute; + } + + /* No attribute found in local __dict__ (or bases): use the + * descriptor from the metatype, if any */ + if (meta_get != NULL) { + PyObject *res; + res = meta_get(meta_attribute, (PyObject *)type, + (PyObject *)metatype); + Py_DECREF(meta_attribute); + return res; + } + + /* If an ordinary attribute was found on the metatype, return it now */ + if (meta_attribute != NULL) { + return meta_attribute; + } + + /* Give up */ + PyErr_Format(PyExc_AttributeError, + "type object '%.50s' has no attribute '%.400s'", + type->tp_name, PyString_AS_STRING(name)); + return NULL; +} + +static int +type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) +{ + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format( + PyExc_TypeError, + "can't set attributes of built-in/extension type '%s'", + type->tp_name); + return -1; + } + /* XXX Example of how I expect this to be used... + if (update_subclasses(type, name, invalidate_cache, NULL) < 0) + return -1; + */ + if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) + return -1; + return update_slot(type, name); +} + +static void +type_dealloc(PyTypeObject *type) +{ + PyHeapTypeObject *et; + + /* Assert this is a heap-allocated type object */ + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + _PyObject_GC_UNTRACK(type); + PyObject_ClearWeakRefs((PyObject *)type); + et = (PyHeapTypeObject *)type; + Py_XDECREF(type->tp_base); + Py_XDECREF(type->tp_dict); + Py_XDECREF(type->tp_bases); + Py_XDECREF(type->tp_mro); + Py_XDECREF(type->tp_cache); + Py_XDECREF(type->tp_subclasses); + /* A type's tp_doc is heap allocated, unlike the tp_doc slots + * of most other objects. It's okay to cast it to char *. + */ + PyObject_Free((char *)type->tp_doc); + Py_XDECREF(et->ht_name); + Py_XDECREF(et->ht_slots); + type->ob_type->tp_free((PyObject *)type); +} + +static PyObject * +type_subclasses(PyTypeObject *type, PyObject *args_ignored) +{ + PyObject *list, *raw, *ref; + Py_ssize_t i, n; + + list = PyList_New(0); + if (list == NULL) + return NULL; + raw = type->tp_subclasses; + if (raw == NULL) + return list; + assert(PyList_Check(raw)); + n = PyList_GET_SIZE(raw); + for (i = 0; i < n; i++) { + ref = PyList_GET_ITEM(raw, i); + assert(PyWeakref_CheckRef(ref)); + ref = PyWeakref_GET_OBJECT(ref); + if (ref != Py_None) { + if (PyList_Append(list, ref) < 0) { + Py_DECREF(list); + return NULL; + } + } + } + return list; +} + +static PyMethodDef type_methods[] = { + {"mro", (PyCFunction)mro_external, METH_NOARGS, + PyDoc_STR("mro() -> list\nreturn a type's method resolution order")}, + {"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS, + PyDoc_STR("__subclasses__() -> list of immediate subclasses")}, + {0} +}; + +PyDoc_STRVAR(type_doc, +"type(object) -> the object's type\n" +"type(name, bases, dict) -> a new type"); + +static int +type_traverse(PyTypeObject *type, visitproc visit, void *arg) +{ + /* Because of type_is_gc(), the collector only calls this + for heaptypes. */ + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + + Py_VISIT(type->tp_dict); + Py_VISIT(type->tp_cache); + Py_VISIT(type->tp_mro); + Py_VISIT(type->tp_bases); + Py_VISIT(type->tp_base); + + /* There's no need to visit type->tp_subclasses or + ((PyHeapTypeObject *)type)->ht_slots, because they can't be involved + in cycles; tp_subclasses is a list of weak references, + and slots is a tuple of strings. */ + + return 0; +} + +static int +type_clear(PyTypeObject *type) +{ + /* Because of type_is_gc(), the collector only calls this + for heaptypes. */ + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + + /* The only field we need to clear is tp_mro, which is part of a + hard cycle (its first element is the class itself) that won't + be broken otherwise (it's a tuple and tuples don't have a + tp_clear handler). None of the other fields need to be + cleared, and here's why: + + tp_dict: + It is a dict, so the collector will call its tp_clear. + + tp_cache: + Not used; if it were, it would be a dict. + + tp_bases, tp_base: + If these are involved in a cycle, there must be at least + one other, mutable object in the cycle, e.g. a base + class's dict; the cycle will be broken that way. + + tp_subclasses: + A list of weak references can't be part of a cycle; and + lists have their own tp_clear. + + slots (in PyHeapTypeObject): + A tuple of strings can't be part of a cycle. + */ + + Py_CLEAR(type->tp_mro); + + return 0; +} + +static int +type_is_gc(PyTypeObject *type) +{ + return type->tp_flags & Py_TPFLAGS_HEAPTYPE; +} + +PyTypeObject PyType_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "type", /* tp_name */ + sizeof(PyHeapTypeObject), /* tp_basicsize */ + sizeof(PyMemberDef), /* tp_itemsize */ + (destructor)type_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + type_compare, /* tp_compare */ + (reprfunc)type_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + (hashfunc)_Py_HashPointer, /* tp_hash */ + (ternaryfunc)type_call, /* tp_call */ + 0, /* tp_str */ + (getattrofunc)type_getattro, /* tp_getattro */ + (setattrofunc)type_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + type_doc, /* tp_doc */ + (traverseproc)type_traverse, /* tp_traverse */ + (inquiry)type_clear, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyTypeObject, tp_weaklist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + type_methods, /* tp_methods */ + type_members, /* tp_members */ + type_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + type_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + (inquiry)type_is_gc, /* tp_is_gc */ +}; + + +/* The base type of all types (eventually)... except itself. */ + +static int +object_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + return 0; +} + +/* If we don't have a tp_new for a new-style class, new will use this one. + Therefore this should take no arguments/keywords. However, this new may + also be inherited by objects that define a tp_init but no tp_new. These + objects WILL pass argumets to tp_new, because it gets the same args as + tp_init. So only allow arguments if we aren't using the default init, in + which case we expect init to handle argument parsing. */ +static PyObject * +object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + if (type->tp_init == object_init && (PyTuple_GET_SIZE(args) || + (kwds && PyDict_Check(kwds) && PyDict_Size(kwds)))) { + PyErr_SetString(PyExc_TypeError, + "default __new__ takes no parameters"); + return NULL; + } + return type->tp_alloc(type, 0); +} + +static void +object_dealloc(PyObject *self) +{ + self->ob_type->tp_free(self); +} + +static PyObject * +object_repr(PyObject *self) +{ + PyTypeObject *type; + PyObject *mod, *name, *rtn; + + type = self->ob_type; + mod = type_module(type, NULL); + if (mod == NULL) + PyErr_Clear(); + else if (!PyString_Check(mod)) { + Py_DECREF(mod); + mod = NULL; + } + name = type_name(type, NULL); + if (name == NULL) + return NULL; + if (mod != NULL && strcmp(PyString_AS_STRING(mod), "__builtin__")) + rtn = PyString_FromFormat("<%s.%s object at %p>", + PyString_AS_STRING(mod), + PyString_AS_STRING(name), + self); + else + rtn = PyString_FromFormat("<%s object at %p>", + type->tp_name, self); + Py_XDECREF(mod); + Py_DECREF(name); + return rtn; +} + +static PyObject * +object_str(PyObject *self) +{ + unaryfunc f; + + f = self->ob_type->tp_repr; + if (f == NULL) + f = object_repr; + return f(self); +} + +static long +object_hash(PyObject *self) +{ + return _Py_HashPointer(self); +} + +static PyObject * +object_get_class(PyObject *self, void *closure) +{ + Py_INCREF(self->ob_type); + return (PyObject *)(self->ob_type); +} + +static int +equiv_structs(PyTypeObject *a, PyTypeObject *b) +{ + return a == b || + (a != NULL && + b != NULL && + a->tp_basicsize == b->tp_basicsize && + a->tp_itemsize == b->tp_itemsize && + a->tp_dictoffset == b->tp_dictoffset && + a->tp_weaklistoffset == b->tp_weaklistoffset && + ((a->tp_flags & Py_TPFLAGS_HAVE_GC) == + (b->tp_flags & Py_TPFLAGS_HAVE_GC))); +} + +static int +same_slots_added(PyTypeObject *a, PyTypeObject *b) +{ + PyTypeObject *base = a->tp_base; + Py_ssize_t size; + + if (base != b->tp_base) + return 0; + if (equiv_structs(a, base) && equiv_structs(b, base)) + return 1; + size = base->tp_basicsize; + if (a->tp_dictoffset == size && b->tp_dictoffset == size) + size += sizeof(PyObject *); + if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size) + size += sizeof(PyObject *); + return size == a->tp_basicsize && size == b->tp_basicsize; +} + +static int +compatible_for_assignment(PyTypeObject* oldto, PyTypeObject* newto, char* attr) +{ + PyTypeObject *newbase, *oldbase; + + if (newto->tp_dealloc != oldto->tp_dealloc || + newto->tp_free != oldto->tp_free) + { + PyErr_Format(PyExc_TypeError, + "%s assignment: " + "'%s' deallocator differs from '%s'", + attr, + newto->tp_name, + oldto->tp_name); + return 0; + } + newbase = newto; + oldbase = oldto; + while (equiv_structs(newbase, newbase->tp_base)) + newbase = newbase->tp_base; + while (equiv_structs(oldbase, oldbase->tp_base)) + oldbase = oldbase->tp_base; + if (newbase != oldbase && + (newbase->tp_base != oldbase->tp_base || + !same_slots_added(newbase, oldbase))) { + PyErr_Format(PyExc_TypeError, + "%s assignment: " + "'%s' object layout differs from '%s'", + attr, + newto->tp_name, + oldto->tp_name); + return 0; + } + + return 1; +} + +static int +object_set_class(PyObject *self, PyObject *value, void *closure) +{ + PyTypeObject *oldto = self->ob_type; + PyTypeObject *newto; + + if (value == NULL) { + PyErr_SetString(PyExc_TypeError, + "can't delete __class__ attribute"); + return -1; + } + if (!PyType_Check(value)) { + PyErr_Format(PyExc_TypeError, + "__class__ must be set to new-style class, not '%s' object", + value->ob_type->tp_name); + return -1; + } + newto = (PyTypeObject *)value; + if (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) || + !(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE)) + { + PyErr_Format(PyExc_TypeError, + "__class__ assignment: only for heap types"); + return -1; + } + if (compatible_for_assignment(newto, oldto, "__class__")) { + Py_INCREF(newto); + self->ob_type = newto; + Py_DECREF(oldto); + return 0; + } + else { + return -1; + } +} + +static PyGetSetDef object_getsets[] = { + {"__class__", object_get_class, object_set_class, + PyDoc_STR("the object's class")}, + {0} +}; + + +/* Stuff to implement __reduce_ex__ for pickle protocols >= 2. + We fall back to helpers in copy_reg for: + - pickle protocols < 2 + - calculating the list of slot names (done only once per class) + - the __newobj__ function (which is used as a token but never called) +*/ + +static PyObject * +import_copy_reg(void) +{ + static PyObject *copy_reg_str; + + if (!copy_reg_str) { + copy_reg_str = PyString_InternFromString("copy_reg"); + if (copy_reg_str == NULL) + return NULL; + } + + return PyImport_Import(copy_reg_str); +} + +static PyObject * +slotnames(PyObject *cls) +{ + PyObject *clsdict; + PyObject *copy_reg; + PyObject *slotnames; + + if (!PyType_Check(cls)) { + Py_INCREF(Py_None); + return Py_None; + } + + clsdict = ((PyTypeObject *)cls)->tp_dict; + slotnames = PyDict_GetItemString(clsdict, "__slotnames__"); + if (slotnames != NULL && PyList_Check(slotnames)) { + Py_INCREF(slotnames); + return slotnames; + } + + copy_reg = import_copy_reg(); + if (copy_reg == NULL) + return NULL; + + slotnames = PyObject_CallMethod(copy_reg, "_slotnames", "O", cls); + Py_DECREF(copy_reg); + if (slotnames != NULL && + slotnames != Py_None && + !PyList_Check(slotnames)) + { + PyErr_SetString(PyExc_TypeError, + "copy_reg._slotnames didn't return a list or None"); + Py_DECREF(slotnames); + slotnames = NULL; + } + + return slotnames; +} + +static PyObject * +reduce_2(PyObject *obj) +{ + PyObject *cls, *getnewargs; + PyObject *args = NULL, *args2 = NULL; + PyObject *getstate = NULL, *state = NULL, *names = NULL; + PyObject *slots = NULL, *listitems = NULL, *dictitems = NULL; + PyObject *copy_reg = NULL, *newobj = NULL, *res = NULL; + Py_ssize_t i, n; + + cls = PyObject_GetAttrString(obj, "__class__"); + if (cls == NULL) + return NULL; + + getnewargs = PyObject_GetAttrString(obj, "__getnewargs__"); + if (getnewargs != NULL) { + args = PyObject_CallObject(getnewargs, NULL); + Py_DECREF(getnewargs); + if (args != NULL && !PyTuple_Check(args)) { + PyErr_Format(PyExc_TypeError, + "__getnewargs__ should return a tuple, " + "not '%.200s'", args->ob_type->tp_name); + goto end; + } + } + else { + PyErr_Clear(); + args = PyTuple_New(0); + } + if (args == NULL) + goto end; + + getstate = PyObject_GetAttrString(obj, "__getstate__"); + if (getstate != NULL) { + state = PyObject_CallObject(getstate, NULL); + Py_DECREF(getstate); + if (state == NULL) + goto end; + } + else { + PyErr_Clear(); + state = PyObject_GetAttrString(obj, "__dict__"); + if (state == NULL) { + PyErr_Clear(); + state = Py_None; + Py_INCREF(state); + } + names = slotnames(cls); + if (names == NULL) + goto end; + if (names != Py_None) { + assert(PyList_Check(names)); + slots = PyDict_New(); + if (slots == NULL) + goto end; + n = 0; + /* Can't pre-compute the list size; the list + is stored on the class so accessible to other + threads, which may be run by DECREF */ + for (i = 0; i < PyList_GET_SIZE(names); i++) { + PyObject *name, *value; + name = PyList_GET_ITEM(names, i); + value = PyObject_GetAttr(obj, name); + if (value == NULL) + PyErr_Clear(); + else { + int err = PyDict_SetItem(slots, name, + value); + Py_DECREF(value); + if (err) + goto end; + n++; + } + } + if (n) { + state = Py_BuildValue("(NO)", state, slots); + if (state == NULL) + goto end; + } + } + } + + if (!PyList_Check(obj)) { + listitems = Py_None; + Py_INCREF(listitems); + } + else { + listitems = PyObject_GetIter(obj); + if (listitems == NULL) + goto end; + } + + if (!PyDict_Check(obj)) { + dictitems = Py_None; + Py_INCREF(dictitems); + } + else { + dictitems = PyObject_CallMethod(obj, "iteritems", ""); + if (dictitems == NULL) + goto end; + } + + copy_reg = import_copy_reg(); + if (copy_reg == NULL) + goto end; + newobj = PyObject_GetAttrString(copy_reg, "__newobj__"); + if (newobj == NULL) + goto end; + + n = PyTuple_GET_SIZE(args); + args2 = PyTuple_New(n+1); + if (args2 == NULL) + goto end; + PyTuple_SET_ITEM(args2, 0, cls); + cls = NULL; + for (i = 0; i < n; i++) { + PyObject *v = PyTuple_GET_ITEM(args, i); + Py_INCREF(v); + PyTuple_SET_ITEM(args2, i+1, v); + } + + res = PyTuple_Pack(5, newobj, args2, state, listitems, dictitems); + + end: + Py_XDECREF(cls); + Py_XDECREF(args); + Py_XDECREF(args2); + Py_XDECREF(slots); + Py_XDECREF(state); + Py_XDECREF(names); + Py_XDECREF(listitems); + Py_XDECREF(dictitems); + Py_XDECREF(copy_reg); + Py_XDECREF(newobj); + return res; +} + +/* + * There were two problems when object.__reduce__ and object.__reduce_ex__ + * were implemented in the same function: + * - trying to pickle an object with a custom __reduce__ method that + * fell back to object.__reduce__ in certain circumstances led to + * infinite recursion at Python level and eventual RuntimeError. + * - Pickling objects that lied about their type by overwriting the + * __class__ descriptor could lead to infinite recursion at C level + * and eventual segfault. + * + * Because of backwards compatibility, the two methods still have to + * behave in the same way, even if this is not required by the pickle + * protocol. This common functionality was moved to the _common_reduce + * function. + */ +static PyObject * +_common_reduce(PyObject *self, int proto) +{ + PyObject *copy_reg, *res; + + if (proto >= 2) + return reduce_2(self); + + copy_reg = import_copy_reg(); + if (!copy_reg) + return NULL; + + res = PyEval_CallMethod(copy_reg, "_reduce_ex", "(Oi)", self, proto); + Py_DECREF(copy_reg); + + return res; +} + +static PyObject * +object_reduce(PyObject *self, PyObject *args) +{ + int proto = 0; + + if (!PyArg_ParseTuple(args, "|i:__reduce__", &proto)) + return NULL; + + return _common_reduce(self, proto); +} + +static PyObject * +object_reduce_ex(PyObject *self, PyObject *args) +{ + PyObject *reduce, *res; + int proto = 0; + + if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) + return NULL; + + reduce = PyObject_GetAttrString(self, "__reduce__"); + if (reduce == NULL) + PyErr_Clear(); + else { + PyObject *cls, *clsreduce, *objreduce; + int override; + cls = PyObject_GetAttrString(self, "__class__"); + if (cls == NULL) { + Py_DECREF(reduce); + return NULL; + } + clsreduce = PyObject_GetAttrString(cls, "__reduce__"); + Py_DECREF(cls); + if (clsreduce == NULL) { + Py_DECREF(reduce); + return NULL; + } + objreduce = PyDict_GetItemString(PyBaseObject_Type.tp_dict, + "__reduce__"); + override = (clsreduce != objreduce); + Py_DECREF(clsreduce); + if (override) { + res = PyObject_CallObject(reduce, NULL); + Py_DECREF(reduce); + return res; + } + else + Py_DECREF(reduce); + } + + return _common_reduce(self, proto); +} + +static PyMethodDef object_methods[] = { + {"__reduce_ex__", object_reduce_ex, METH_VARARGS, + PyDoc_STR("helper for pickle")}, + {"__reduce__", object_reduce, METH_VARARGS, + PyDoc_STR("helper for pickle")}, + {0} +}; + + +PyTypeObject PyBaseObject_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "object", /* tp_name */ + sizeof(PyObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + object_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + object_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + object_hash, /* tp_hash */ + 0, /* tp_call */ + object_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + PyObject_GenericSetAttr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + PyDoc_STR("The most base type"), /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + object_methods, /* tp_methods */ + 0, /* tp_members */ + object_getsets, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + object_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + object_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + + +/* Initialize the __dict__ in a type object */ + +static int +add_methods(PyTypeObject *type, PyMethodDef *meth) +{ + PyObject *dict = type->tp_dict; + + for (; meth->ml_name != NULL; meth++) { + PyObject *descr; + if (PyDict_GetItemString(dict, meth->ml_name) && + !(meth->ml_flags & METH_COEXIST)) + continue; + if (meth->ml_flags & METH_CLASS) { + if (meth->ml_flags & METH_STATIC) { + PyErr_SetString(PyExc_ValueError, + "method cannot be both class and static"); + return -1; + } + descr = PyDescr_NewClassMethod(type, meth); + } + else if (meth->ml_flags & METH_STATIC) { + PyObject *cfunc = PyCFunction_New(meth, NULL); + if (cfunc == NULL) + return -1; + descr = PyStaticMethod_New(cfunc); + Py_DECREF(cfunc); + } + else { + descr = PyDescr_NewMethod(type, meth); + } + if (descr == NULL) + return -1; + if (PyDict_SetItemString(dict, meth->ml_name, descr) < 0) + return -1; + Py_DECREF(descr); + } + return 0; +} + +static int +add_members(PyTypeObject *type, PyMemberDef *memb) +{ + PyObject *dict = type->tp_dict; + + for (; memb->name != NULL; memb++) { + PyObject *descr; + if (PyDict_GetItemString(dict, memb->name)) + continue; + descr = PyDescr_NewMember(type, memb); + if (descr == NULL) + return -1; + if (PyDict_SetItemString(dict, memb->name, descr) < 0) + return -1; + Py_DECREF(descr); + } + return 0; +} + +static int +add_getset(PyTypeObject *type, PyGetSetDef *gsp) +{ + PyObject *dict = type->tp_dict; + + for (; gsp->name != NULL; gsp++) { + PyObject *descr; + if (PyDict_GetItemString(dict, gsp->name)) + continue; + descr = PyDescr_NewGetSet(type, gsp); + + if (descr == NULL) + return -1; + if (PyDict_SetItemString(dict, gsp->name, descr) < 0) + return -1; + Py_DECREF(descr); + } + return 0; +} + +static void +inherit_special(PyTypeObject *type, PyTypeObject *base) +{ + Py_ssize_t oldsize, newsize; + + /* Special flag magic */ + if (!type->tp_as_buffer && base->tp_as_buffer) { + type->tp_flags &= ~Py_TPFLAGS_HAVE_GETCHARBUFFER; + type->tp_flags |= + base->tp_flags & Py_TPFLAGS_HAVE_GETCHARBUFFER; + } + if (!type->tp_as_sequence && base->tp_as_sequence) { + type->tp_flags &= ~Py_TPFLAGS_HAVE_SEQUENCE_IN; + type->tp_flags |= base->tp_flags & Py_TPFLAGS_HAVE_SEQUENCE_IN; + } + if ((type->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS) != + (base->tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS)) { + if ((!type->tp_as_number && base->tp_as_number) || + (!type->tp_as_sequence && base->tp_as_sequence)) { + type->tp_flags &= ~Py_TPFLAGS_HAVE_INPLACEOPS; + if (!type->tp_as_number && !type->tp_as_sequence) { + type->tp_flags |= base->tp_flags & + Py_TPFLAGS_HAVE_INPLACEOPS; + } + } + /* Wow */ + } + if (!type->tp_as_number && base->tp_as_number) { + type->tp_flags &= ~Py_TPFLAGS_CHECKTYPES; + type->tp_flags |= base->tp_flags & Py_TPFLAGS_CHECKTYPES; + } + + /* Copying basicsize is connected to the GC flags */ + oldsize = base->tp_basicsize; + newsize = type->tp_basicsize ? type->tp_basicsize : oldsize; + if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) && + (base->tp_flags & Py_TPFLAGS_HAVE_GC) && + (type->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE/*GC slots exist*/) && + (!type->tp_traverse && !type->tp_clear)) { + type->tp_flags |= Py_TPFLAGS_HAVE_GC; + if (type->tp_traverse == NULL) + type->tp_traverse = base->tp_traverse; + if (type->tp_clear == NULL) + type->tp_clear = base->tp_clear; + } + if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { + /* The condition below could use some explanation. + It appears that tp_new is not inherited for static types + whose base class is 'object'; this seems to be a precaution + so that old extension types don't suddenly become + callable (object.__new__ wouldn't insure the invariants + that the extension type's own factory function ensures). + Heap types, of course, are under our control, so they do + inherit tp_new; static extension types that specify some + other built-in type as the default are considered + new-style-aware so they also inherit object.__new__. */ + if (base != &PyBaseObject_Type || + (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + if (type->tp_new == NULL) + type->tp_new = base->tp_new; + } + } + type->tp_basicsize = newsize; + + /* Copy other non-function slots */ + +#undef COPYVAL +#define COPYVAL(SLOT) \ + if (type->SLOT == 0) type->SLOT = base->SLOT + + COPYVAL(tp_itemsize); + if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_WEAKREFS) { + COPYVAL(tp_weaklistoffset); + } + if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { + COPYVAL(tp_dictoffset); + } +} + +static void +inherit_slots(PyTypeObject *type, PyTypeObject *base) +{ + PyTypeObject *basebase; + +#undef SLOTDEFINED +#undef COPYSLOT +#undef COPYNUM +#undef COPYSEQ +#undef COPYMAP +#undef COPYBUF + +#define SLOTDEFINED(SLOT) \ + (base->SLOT != 0 && \ + (basebase == NULL || base->SLOT != basebase->SLOT)) + +#define COPYSLOT(SLOT) \ + if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = base->SLOT + +#define COPYNUM(SLOT) COPYSLOT(tp_as_number->SLOT) +#define COPYSEQ(SLOT) COPYSLOT(tp_as_sequence->SLOT) +#define COPYMAP(SLOT) COPYSLOT(tp_as_mapping->SLOT) +#define COPYBUF(SLOT) COPYSLOT(tp_as_buffer->SLOT) + + /* This won't inherit indirect slots (from tp_as_number etc.) + if type doesn't provide the space. */ + + if (type->tp_as_number != NULL && base->tp_as_number != NULL) { + basebase = base->tp_base; + if (basebase->tp_as_number == NULL) + basebase = NULL; + COPYNUM(nb_add); + COPYNUM(nb_subtract); + COPYNUM(nb_multiply); + COPYNUM(nb_divide); + COPYNUM(nb_remainder); + COPYNUM(nb_divmod); + COPYNUM(nb_power); + COPYNUM(nb_negative); + COPYNUM(nb_positive); + COPYNUM(nb_absolute); + COPYNUM(nb_nonzero); + COPYNUM(nb_invert); + COPYNUM(nb_lshift); + COPYNUM(nb_rshift); + COPYNUM(nb_and); + COPYNUM(nb_xor); + COPYNUM(nb_or); + COPYNUM(nb_coerce); + COPYNUM(nb_int); + COPYNUM(nb_long); + COPYNUM(nb_float); + COPYNUM(nb_oct); + COPYNUM(nb_hex); + COPYNUM(nb_inplace_add); + COPYNUM(nb_inplace_subtract); + COPYNUM(nb_inplace_multiply); + COPYNUM(nb_inplace_divide); + COPYNUM(nb_inplace_remainder); + COPYNUM(nb_inplace_power); + COPYNUM(nb_inplace_lshift); + COPYNUM(nb_inplace_rshift); + COPYNUM(nb_inplace_and); + COPYNUM(nb_inplace_xor); + COPYNUM(nb_inplace_or); + if (base->tp_flags & Py_TPFLAGS_CHECKTYPES) { + COPYNUM(nb_true_divide); + COPYNUM(nb_floor_divide); + COPYNUM(nb_inplace_true_divide); + COPYNUM(nb_inplace_floor_divide); + } + if (base->tp_flags & Py_TPFLAGS_HAVE_INDEX) { + COPYNUM(nb_index); + } + } + + if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) { + basebase = base->tp_base; + if (basebase->tp_as_sequence == NULL) + basebase = NULL; + COPYSEQ(sq_length); + COPYSEQ(sq_concat); + COPYSEQ(sq_repeat); + COPYSEQ(sq_item); + COPYSEQ(sq_slice); + COPYSEQ(sq_ass_item); + COPYSEQ(sq_ass_slice); + COPYSEQ(sq_contains); + COPYSEQ(sq_inplace_concat); + COPYSEQ(sq_inplace_repeat); + } + + if (type->tp_as_mapping != NULL && base->tp_as_mapping != NULL) { + basebase = base->tp_base; + if (basebase->tp_as_mapping == NULL) + basebase = NULL; + COPYMAP(mp_length); + COPYMAP(mp_subscript); + COPYMAP(mp_ass_subscript); + } + + if (type->tp_as_buffer != NULL && base->tp_as_buffer != NULL) { + basebase = base->tp_base; + if (basebase->tp_as_buffer == NULL) + basebase = NULL; + COPYBUF(bf_getreadbuffer); + COPYBUF(bf_getwritebuffer); + COPYBUF(bf_getsegcount); + COPYBUF(bf_getcharbuffer); + } + + basebase = base->tp_base; + + COPYSLOT(tp_dealloc); + COPYSLOT(tp_print); + if (type->tp_getattr == NULL && type->tp_getattro == NULL) { + type->tp_getattr = base->tp_getattr; + type->tp_getattro = base->tp_getattro; + } + if (type->tp_setattr == NULL && type->tp_setattro == NULL) { + type->tp_setattr = base->tp_setattr; + type->tp_setattro = base->tp_setattro; + } + /* tp_compare see tp_richcompare */ + COPYSLOT(tp_repr); + /* tp_hash see tp_richcompare */ + COPYSLOT(tp_call); + COPYSLOT(tp_str); + if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) { + if (type->tp_compare == NULL && + type->tp_richcompare == NULL && + type->tp_hash == NULL) + { + type->tp_compare = base->tp_compare; + type->tp_richcompare = base->tp_richcompare; + type->tp_hash = base->tp_hash; + } + } + else { + COPYSLOT(tp_compare); + } + if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_ITER) { + COPYSLOT(tp_iter); + COPYSLOT(tp_iternext); + } + if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_CLASS) { + COPYSLOT(tp_descr_get); + COPYSLOT(tp_descr_set); + COPYSLOT(tp_dictoffset); + COPYSLOT(tp_init); + COPYSLOT(tp_alloc); + COPYSLOT(tp_is_gc); + if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) == + (base->tp_flags & Py_TPFLAGS_HAVE_GC)) { + /* They agree about gc. */ + COPYSLOT(tp_free); + } + else if ((type->tp_flags & Py_TPFLAGS_HAVE_GC) && + type->tp_free == NULL && + base->tp_free == _PyObject_Del) { + /* A bit of magic to plug in the correct default + * tp_free function when a derived class adds gc, + * didn't define tp_free, and the base uses the + * default non-gc tp_free. + */ + type->tp_free = PyObject_GC_Del; + } + /* else they didn't agree about gc, and there isn't something + * obvious to be done -- the type is on its own. + */ + } +} + +static int add_operators(PyTypeObject *); + +int +PyType_Ready(PyTypeObject *type) +{ + PyObject *dict, *bases; + PyTypeObject *base; + Py_ssize_t i, n; + + if (type->tp_flags & Py_TPFLAGS_READY) { + assert(type->tp_dict != NULL); + return 0; + } + assert((type->tp_flags & Py_TPFLAGS_READYING) == 0); + + type->tp_flags |= Py_TPFLAGS_READYING; + +#ifdef Py_TRACE_REFS + /* PyType_Ready is the closest thing we have to a choke point + * for type objects, so is the best place I can think of to try + * to get type objects into the doubly-linked list of all objects. + * Still, not all type objects go thru PyType_Ready. + */ + _Py_AddToAllObjects((PyObject *)type, 0); +#endif + + /* Initialize tp_base (defaults to BaseObject unless that's us) */ + base = type->tp_base; + if (base == NULL && type != &PyBaseObject_Type) { + base = type->tp_base = &PyBaseObject_Type; + Py_INCREF(base); + } + + /* Now the only way base can still be NULL is if type is + * &PyBaseObject_Type. + */ + + /* Initialize the base class */ + if (base && base->tp_dict == NULL) { + if (PyType_Ready(base) < 0) + goto error; + } + + /* Initialize ob_type if NULL. This means extensions that want to be + compilable separately on Windows can call PyType_Ready() instead of + initializing the ob_type field of their type objects. */ + /* The test for base != NULL is really unnecessary, since base is only + NULL when type is &PyBaseObject_Type, and we know its ob_type is + not NULL (it's initialized to &PyType_Type). But coverity doesn't + know that. */ + if (type->ob_type == NULL && base != NULL) + type->ob_type = base->ob_type; + + /* Initialize tp_bases */ + bases = type->tp_bases; + if (bases == NULL) { + if (base == NULL) + bases = PyTuple_New(0); + else + bases = PyTuple_Pack(1, base); + if (bases == NULL) + goto error; + type->tp_bases = bases; + } + + /* Initialize tp_dict */ + dict = type->tp_dict; + if (dict == NULL) { + dict = PyDict_New(); + if (dict == NULL) + goto error; + type->tp_dict = dict; + } + + /* Add type-specific descriptors to tp_dict */ + if (add_operators(type) < 0) + goto error; + if (type->tp_methods != NULL) { + if (add_methods(type, type->tp_methods) < 0) + goto error; + } + if (type->tp_members != NULL) { + if (add_members(type, type->tp_members) < 0) + goto error; + } + if (type->tp_getset != NULL) { + if (add_getset(type, type->tp_getset) < 0) + goto error; + } + + /* Calculate method resolution order */ + if (mro_internal(type) < 0) { + goto error; + } + + /* Inherit special flags from dominant base */ + if (type->tp_base != NULL) + inherit_special(type, type->tp_base); + + /* Initialize tp_dict properly */ + bases = type->tp_mro; + assert(bases != NULL); + assert(PyTuple_Check(bases)); + n = PyTuple_GET_SIZE(bases); + for (i = 1; i < n; i++) { + PyObject *b = PyTuple_GET_ITEM(bases, i); + if (PyType_Check(b)) + inherit_slots(type, (PyTypeObject *)b); + } + + /* Sanity check for tp_free. */ + if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) && + (type->tp_free == NULL || type->tp_free == PyObject_Del)) { + /* This base class needs to call tp_free, but doesn't have + * one, or its tp_free is for non-gc'ed objects. + */ + PyErr_Format(PyExc_TypeError, "type '%.100s' participates in " + "gc and is a base type but has inappropriate " + "tp_free slot", + type->tp_name); + goto error; + } + + /* if the type dictionary doesn't contain a __doc__, set it from + the tp_doc slot. + */ + if (PyDict_GetItemString(type->tp_dict, "__doc__") == NULL) { + if (type->tp_doc != NULL) { + PyObject *doc = PyString_FromString(type->tp_doc); + if (doc == NULL) + goto error; + PyDict_SetItemString(type->tp_dict, "__doc__", doc); + Py_DECREF(doc); + } else { + PyDict_SetItemString(type->tp_dict, + "__doc__", Py_None); + } + } + + /* Some more special stuff */ + base = type->tp_base; + if (base != NULL) { + if (type->tp_as_number == NULL) + type->tp_as_number = base->tp_as_number; + if (type->tp_as_sequence == NULL) + type->tp_as_sequence = base->tp_as_sequence; + if (type->tp_as_mapping == NULL) + type->tp_as_mapping = base->tp_as_mapping; + if (type->tp_as_buffer == NULL) + type->tp_as_buffer = base->tp_as_buffer; + } + + /* Link into each base class's list of subclasses */ + bases = type->tp_bases; + n = PyTuple_GET_SIZE(bases); + for (i = 0; i < n; i++) { + PyObject *b = PyTuple_GET_ITEM(bases, i); + if (PyType_Check(b) && + add_subclass((PyTypeObject *)b, type) < 0) + goto error; + } + + /* All done -- set the ready flag */ + assert(type->tp_dict != NULL); + type->tp_flags = + (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY; + return 0; + + error: + type->tp_flags &= ~Py_TPFLAGS_READYING; + return -1; +} + +static int +add_subclass(PyTypeObject *base, PyTypeObject *type) +{ + Py_ssize_t i; + int result; + PyObject *list, *ref, *newobj; + + list = base->tp_subclasses; + if (list == NULL) { + base->tp_subclasses = list = PyList_New(0); + if (list == NULL) + return -1; + } + assert(PyList_Check(list)); + newobj = PyWeakref_NewRef((PyObject *)type, NULL); + i = PyList_GET_SIZE(list); + while (--i >= 0) { + ref = PyList_GET_ITEM(list, i); + assert(PyWeakref_CheckRef(ref)); + if (PyWeakref_GET_OBJECT(ref) == Py_None) + return PyList_SetItem(list, i, newobj); + } + result = PyList_Append(list, newobj); + Py_DECREF(newobj); + return result; +} + +static void +remove_subclass(PyTypeObject *base, PyTypeObject *type) +{ + Py_ssize_t i; + PyObject *list, *ref; + + list = base->tp_subclasses; + if (list == NULL) { + return; + } + assert(PyList_Check(list)); + i = PyList_GET_SIZE(list); + while (--i >= 0) { + ref = PyList_GET_ITEM(list, i); + assert(PyWeakref_CheckRef(ref)); + if (PyWeakref_GET_OBJECT(ref) == (PyObject*)type) { + /* this can't fail, right? */ + PySequence_DelItem(list, i); + return; + } + } +} + +static int +check_num_args(PyObject *ob, int n) +{ + if (!PyTuple_CheckExact(ob)) { + PyErr_SetString(PyExc_SystemError, + "PyArg_UnpackTuple() argument list is not a tuple"); + return 0; + } + if (n == PyTuple_GET_SIZE(ob)) + return 1; + PyErr_Format( + PyExc_TypeError, + "expected %d arguments, got %zd", n, PyTuple_GET_SIZE(ob)); + return 0; +} + +/* Generic wrappers for overloadable 'operators' such as __getitem__ */ + +/* There's a wrapper *function* for each distinct function typedef used + for type object slots (e.g. binaryfunc, ternaryfunc, etc.). There's a + wrapper *table* for each distinct operation (e.g. __len__, __add__). + Most tables have only one entry; the tables for binary operators have two + entries, one regular and one with reversed arguments. */ + +static PyObject * +wrap_lenfunc(PyObject *self, PyObject *args, void *wrapped) +{ + lenfunc func = (lenfunc)wrapped; + Py_ssize_t res; + + if (!check_num_args(args, 0)) + return NULL; + res = (*func)(self); + if (res == -1 && PyErr_Occurred()) + return NULL; + return PyInt_FromLong((long)res); +} + +static PyObject * +wrap_inquirypred(PyObject *self, PyObject *args, void *wrapped) +{ + inquiry func = (inquiry)wrapped; + int res; + + if (!check_num_args(args, 0)) + return NULL; + res = (*func)(self); + if (res == -1 && PyErr_Occurred()) + return NULL; + return PyBool_FromLong((long)res); +} + +static PyObject * +wrap_binaryfunc(PyObject *self, PyObject *args, void *wrapped) +{ + binaryfunc func = (binaryfunc)wrapped; + PyObject *other; + + if (!check_num_args(args, 1)) + return NULL; + other = PyTuple_GET_ITEM(args, 0); + return (*func)(self, other); +} + +static PyObject * +wrap_binaryfunc_l(PyObject *self, PyObject *args, void *wrapped) +{ + binaryfunc func = (binaryfunc)wrapped; + PyObject *other; + + if (!check_num_args(args, 1)) + return NULL; + other = PyTuple_GET_ITEM(args, 0); + if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) && + !PyType_IsSubtype(other->ob_type, self->ob_type)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return (*func)(self, other); +} + +static PyObject * +wrap_binaryfunc_r(PyObject *self, PyObject *args, void *wrapped) +{ + binaryfunc func = (binaryfunc)wrapped; + PyObject *other; + + if (!check_num_args(args, 1)) + return NULL; + other = PyTuple_GET_ITEM(args, 0); + if (!(self->ob_type->tp_flags & Py_TPFLAGS_CHECKTYPES) && + !PyType_IsSubtype(other->ob_type, self->ob_type)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return (*func)(other, self); +} + +static PyObject * +wrap_coercefunc(PyObject *self, PyObject *args, void *wrapped) +{ + coercion func = (coercion)wrapped; + PyObject *other, *res; + int ok; + + if (!check_num_args(args, 1)) + return NULL; + other = PyTuple_GET_ITEM(args, 0); + ok = func(&self, &other); + if (ok < 0) + return NULL; + if (ok > 0) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + res = PyTuple_New(2); + if (res == NULL) { + Py_DECREF(self); + Py_DECREF(other); + return NULL; + } + PyTuple_SET_ITEM(res, 0, self); + PyTuple_SET_ITEM(res, 1, other); + return res; +} + +static PyObject * +wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped) +{ + ternaryfunc func = (ternaryfunc)wrapped; + PyObject *other; + PyObject *third = Py_None; + + /* Note: This wrapper only works for __pow__() */ + + if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) + return NULL; + return (*func)(self, other, third); +} + +static PyObject * +wrap_ternaryfunc_r(PyObject *self, PyObject *args, void *wrapped) +{ + ternaryfunc func = (ternaryfunc)wrapped; + PyObject *other; + PyObject *third = Py_None; + + /* Note: This wrapper only works for __pow__() */ + + if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third)) + return NULL; + return (*func)(other, self, third); +} + +static PyObject * +wrap_unaryfunc(PyObject *self, PyObject *args, void *wrapped) +{ + unaryfunc func = (unaryfunc)wrapped; + + if (!check_num_args(args, 0)) + return NULL; + return (*func)(self); +} + +static PyObject * +wrap_indexargfunc(PyObject *self, PyObject *args, void *wrapped) +{ + ssizeargfunc func = (ssizeargfunc)wrapped; + PyObject* o; + Py_ssize_t i; + + if (!PyArg_UnpackTuple(args, "", 1, 1, &o)) + return NULL; + i = PyNumber_AsSsize_t(o, PyExc_OverflowError); + if (i == -1 && PyErr_Occurred()) + return NULL; + return (*func)(self, i); +} + +static Py_ssize_t +getindex(PyObject *self, PyObject *arg) +{ + Py_ssize_t i; + + i = PyNumber_AsSsize_t(arg, PyExc_OverflowError); + if (i == -1 && PyErr_Occurred()) + return -1; + if (i < 0) { + PySequenceMethods *sq = self->ob_type->tp_as_sequence; + if (sq && sq->sq_length) { + Py_ssize_t n = (*sq->sq_length)(self); + if (n < 0) + return -1; + i += n; + } + } + return i; +} + +static PyObject * +wrap_sq_item(PyObject *self, PyObject *args, void *wrapped) +{ + ssizeargfunc func = (ssizeargfunc)wrapped; + PyObject *arg; + Py_ssize_t i; + + if (PyTuple_GET_SIZE(args) == 1) { + arg = PyTuple_GET_ITEM(args, 0); + i = getindex(self, arg); + if (i == -1 && PyErr_Occurred()) + return NULL; + return (*func)(self, i); + } + check_num_args(args, 1); + assert(PyErr_Occurred()); + return NULL; +} + +static PyObject * +wrap_ssizessizeargfunc(PyObject *self, PyObject *args, void *wrapped) +{ + ssizessizeargfunc func = (ssizessizeargfunc)wrapped; + Py_ssize_t i, j; + + if (!PyArg_ParseTuple(args, "nn", &i, &j)) + return NULL; + return (*func)(self, i, j); +} + +static PyObject * +wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped) +{ + ssizeobjargproc func = (ssizeobjargproc)wrapped; + Py_ssize_t i; + int res; + PyObject *arg, *value; + + if (!PyArg_UnpackTuple(args, "", 2, 2, &arg, &value)) + return NULL; + i = getindex(self, arg); + if (i == -1 && PyErr_Occurred()) + return NULL; + res = (*func)(self, i, value); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_sq_delitem(PyObject *self, PyObject *args, void *wrapped) +{ + ssizeobjargproc func = (ssizeobjargproc)wrapped; + Py_ssize_t i; + int res; + PyObject *arg; + + if (!check_num_args(args, 1)) + return NULL; + arg = PyTuple_GET_ITEM(args, 0); + i = getindex(self, arg); + if (i == -1 && PyErr_Occurred()) + return NULL; + res = (*func)(self, i, NULL); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_ssizessizeobjargproc(PyObject *self, PyObject *args, void *wrapped) +{ + ssizessizeobjargproc func = (ssizessizeobjargproc)wrapped; + Py_ssize_t i, j; + int res; + PyObject *value; + + if (!PyArg_ParseTuple(args, "nnO", &i, &j, &value)) + return NULL; + res = (*func)(self, i, j, value); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_delslice(PyObject *self, PyObject *args, void *wrapped) +{ + ssizessizeobjargproc func = (ssizessizeobjargproc)wrapped; + Py_ssize_t i, j; + int res; + + if (!PyArg_ParseTuple(args, "nn", &i, &j)) + return NULL; + res = (*func)(self, i, j, NULL); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +/* XXX objobjproc is a misnomer; should be objargpred */ +static PyObject * +wrap_objobjproc(PyObject *self, PyObject *args, void *wrapped) +{ + objobjproc func = (objobjproc)wrapped; + int res; + PyObject *value; + + if (!check_num_args(args, 1)) + return NULL; + value = PyTuple_GET_ITEM(args, 0); + res = (*func)(self, value); + if (res == -1 && PyErr_Occurred()) + return NULL; + else + return PyBool_FromLong(res); +} + +static PyObject * +wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped) +{ + objobjargproc func = (objobjargproc)wrapped; + int res; + PyObject *key, *value; + + if (!PyArg_UnpackTuple(args, "", 2, 2, &key, &value)) + return NULL; + res = (*func)(self, key, value); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_delitem(PyObject *self, PyObject *args, void *wrapped) +{ + objobjargproc func = (objobjargproc)wrapped; + int res; + PyObject *key; + + if (!check_num_args(args, 1)) + return NULL; + key = PyTuple_GET_ITEM(args, 0); + res = (*func)(self, key, NULL); + if (res == -1 && PyErr_Occurred()) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped) +{ + cmpfunc func = (cmpfunc)wrapped; + int res; + PyObject *other; + + if (!check_num_args(args, 1)) + return NULL; + other = PyTuple_GET_ITEM(args, 0); + if (other->ob_type->tp_compare != func && + !PyType_IsSubtype(other->ob_type, self->ob_type)) { + PyErr_Format( + PyExc_TypeError, + "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'", + self->ob_type->tp_name, + self->ob_type->tp_name, + other->ob_type->tp_name); + return NULL; + } + res = (*func)(self, other); + if (PyErr_Occurred()) + return NULL; + return PyInt_FromLong((long)res); +} + +/* Helper to check for object.__setattr__ or __delattr__ applied to a type. + This is called the Carlo Verre hack after its discoverer. */ +static int +hackcheck(PyObject *self, setattrofunc func, char *what) +{ + PyTypeObject *type = self->ob_type; + while (type && type->tp_flags & Py_TPFLAGS_HEAPTYPE) + type = type->tp_base; + /* If type is NULL now, this is a really weird type. + In the same of backwards compatibility (?), just shut up. */ + if (type && type->tp_setattro != func) { + PyErr_Format(PyExc_TypeError, + "can't apply this %s to %s object", + what, + type->tp_name); + return 0; + } + return 1; +} + +static PyObject * +wrap_setattr(PyObject *self, PyObject *args, void *wrapped) +{ + setattrofunc func = (setattrofunc)wrapped; + int res; + PyObject *name, *value; + + if (!PyArg_UnpackTuple(args, "", 2, 2, &name, &value)) + return NULL; + if (!hackcheck(self, func, "__setattr__")) + return NULL; + res = (*func)(self, name, value); + if (res < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_delattr(PyObject *self, PyObject *args, void *wrapped) +{ + setattrofunc func = (setattrofunc)wrapped; + int res; + PyObject *name; + + if (!check_num_args(args, 1)) + return NULL; + name = PyTuple_GET_ITEM(args, 0); + if (!hackcheck(self, func, "__delattr__")) + return NULL; + res = (*func)(self, name, NULL); + if (res < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_hashfunc(PyObject *self, PyObject *args, void *wrapped) +{ + hashfunc func = (hashfunc)wrapped; + long res; + + if (!check_num_args(args, 0)) + return NULL; + res = (*func)(self); + if (res == -1 && PyErr_Occurred()) + return NULL; + return PyInt_FromLong(res); +} + +static PyObject * +wrap_call(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) +{ + ternaryfunc func = (ternaryfunc)wrapped; + + return (*func)(self, args, kwds); +} + +static PyObject * +wrap_richcmpfunc(PyObject *self, PyObject *args, void *wrapped, int op) +{ + richcmpfunc func = (richcmpfunc)wrapped; + PyObject *other; + + if (!check_num_args(args, 1)) + return NULL; + other = PyTuple_GET_ITEM(args, 0); + return (*func)(self, other, op); +} + +#undef RICHCMP_WRAPPER +#define RICHCMP_WRAPPER(NAME, OP) \ +static PyObject * \ +richcmp_##NAME(PyObject *self, PyObject *args, void *wrapped) \ +{ \ + return wrap_richcmpfunc(self, args, wrapped, OP); \ +} + +RICHCMP_WRAPPER(lt, Py_LT) +RICHCMP_WRAPPER(le, Py_LE) +RICHCMP_WRAPPER(eq, Py_EQ) +RICHCMP_WRAPPER(ne, Py_NE) +RICHCMP_WRAPPER(gt, Py_GT) +RICHCMP_WRAPPER(ge, Py_GE) + +static PyObject * +wrap_next(PyObject *self, PyObject *args, void *wrapped) +{ + unaryfunc func = (unaryfunc)wrapped; + PyObject *res; + + if (!check_num_args(args, 0)) + return NULL; + res = (*func)(self); + if (res == NULL && !PyErr_Occurred()) + PyErr_SetNone(PyExc_StopIteration); + return res; +} + +static PyObject * +wrap_descr_get(PyObject *self, PyObject *args, void *wrapped) +{ + descrgetfunc func = (descrgetfunc)wrapped; + PyObject *obj; + PyObject *type = NULL; + + if (!PyArg_UnpackTuple(args, "", 1, 2, &obj, &type)) + return NULL; + if (obj == Py_None) + obj = NULL; + if (type == Py_None) + type = NULL; + if (type == NULL &&obj == NULL) { + PyErr_SetString(PyExc_TypeError, + "__get__(None, None) is invalid"); + return NULL; + } + return (*func)(self, obj, type); +} + +static PyObject * +wrap_descr_set(PyObject *self, PyObject *args, void *wrapped) +{ + descrsetfunc func = (descrsetfunc)wrapped; + PyObject *obj, *value; + int ret; + + if (!PyArg_UnpackTuple(args, "", 2, 2, &obj, &value)) + return NULL; + ret = (*func)(self, obj, value); + if (ret < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped) +{ + descrsetfunc func = (descrsetfunc)wrapped; + PyObject *obj; + int ret; + + if (!check_num_args(args, 1)) + return NULL; + obj = PyTuple_GET_ITEM(args, 0); + ret = (*func)(self, obj, NULL); + if (ret < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) +{ + initproc func = (initproc)wrapped; + + if (func(self, args, kwds) < 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyTypeObject *type, *subtype, *staticbase; + PyObject *arg0, *res; + + if (self == NULL || !PyType_Check(self)) + Py_FatalError("__new__() called with non-type 'self'"); + type = (PyTypeObject *)self; + if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) { + PyErr_Format(PyExc_TypeError, + "%s.__new__(): not enough arguments", + type->tp_name); + return NULL; + } + arg0 = PyTuple_GET_ITEM(args, 0); + if (!PyType_Check(arg0)) { + PyErr_Format(PyExc_TypeError, + "%s.__new__(X): X is not a type object (%s)", + type->tp_name, + arg0->ob_type->tp_name); + return NULL; + } + subtype = (PyTypeObject *)arg0; + if (!PyType_IsSubtype(subtype, type)) { + PyErr_Format(PyExc_TypeError, + "%s.__new__(%s): %s is not a subtype of %s", + type->tp_name, + subtype->tp_name, + subtype->tp_name, + type->tp_name); + return NULL; + } + + /* Check that the use doesn't do something silly and unsafe like + object.__new__(dict). To do this, we check that the + most derived base that's not a heap type is this type. */ + staticbase = subtype; + while (staticbase && (staticbase->tp_flags & Py_TPFLAGS_HEAPTYPE)) + staticbase = staticbase->tp_base; + /* If staticbase is NULL now, it is a really weird type. + In the same of backwards compatibility (?), just shut up. */ + if (staticbase && staticbase->tp_new != type->tp_new) { + PyErr_Format(PyExc_TypeError, + "%s.__new__(%s) is not safe, use %s.__new__()", + type->tp_name, + subtype->tp_name, + staticbase == NULL ? "?" : staticbase->tp_name); + return NULL; + } + + args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); + if (args == NULL) + return NULL; + res = type->tp_new(subtype, args, kwds); + Py_DECREF(args); + return res; +} + +static struct PyMethodDef tp_new_methoddef[] = { + {"__new__", (PyCFunction)tp_new_wrapper, METH_KEYWORDS, + PyDoc_STR("T.__new__(S, ...) -> " + "a new object with type S, a subtype of T")}, + {0} +}; + +static int +add_tp_new_wrapper(PyTypeObject *type) +{ + PyObject *func; + + if (PyDict_GetItemString(type->tp_dict, "__new__") != NULL) + return 0; + func = PyCFunction_New(tp_new_methoddef, (PyObject *)type); + if (func == NULL) + return -1; + if (PyDict_SetItemString(type->tp_dict, "__new__", func)) { + Py_DECREF(func); + return -1; + } + Py_DECREF(func); + return 0; +} + +/* Slot wrappers that call the corresponding __foo__ slot. See comments + below at override_slots() for more explanation. */ + +#define SLOT0(FUNCNAME, OPSTR) \ +static PyObject * \ +FUNCNAME(PyObject *self) \ +{ \ + static PyObject *cache_str; \ + return call_method(self, OPSTR, &cache_str, "()"); \ +} + +#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \ +static PyObject * \ +FUNCNAME(PyObject *self, ARG1TYPE arg1) \ +{ \ + static PyObject *cache_str; \ + return call_method(self, OPSTR, &cache_str, "(" ARGCODES ")", arg1); \ +} + +/* Boolean helper for SLOT1BINFULL(). + right.__class__ is a nontrivial subclass of left.__class__. */ +static int +method_is_overloaded(PyObject *left, PyObject *right, char *name) +{ + PyObject *a, *b; + int ok; + + b = PyObject_GetAttrString((PyObject *)(right->ob_type), name); + if (b == NULL) { + PyErr_Clear(); + /* If right doesn't have it, it's not overloaded */ + return 0; + } + + a = PyObject_GetAttrString((PyObject *)(left->ob_type), name); + if (a == NULL) { + PyErr_Clear(); + Py_DECREF(b); + /* If right has it but left doesn't, it's overloaded */ + return 1; + } + + ok = PyObject_RichCompareBool(a, b, Py_NE); + Py_DECREF(a); + Py_DECREF(b); + if (ok < 0) { + PyErr_Clear(); + return 0; + } + + return ok; +} + + +#define SLOT1BINFULL(FUNCNAME, TESTFUNC, SLOTNAME, OPSTR, ROPSTR) \ +static PyObject * \ +FUNCNAME(PyObject *self, PyObject *other) \ +{ \ + static PyObject *cache_str, *rcache_str; \ + int do_other = self->ob_type != other->ob_type && \ + other->ob_type->tp_as_number != NULL && \ + other->ob_type->tp_as_number->SLOTNAME == TESTFUNC; \ + if (self->ob_type->tp_as_number != NULL && \ + self->ob_type->tp_as_number->SLOTNAME == TESTFUNC) { \ + PyObject *r; \ + if (do_other && \ + PyType_IsSubtype(other->ob_type, self->ob_type) && \ + method_is_overloaded(self, other, ROPSTR)) { \ + r = call_maybe( \ + other, ROPSTR, &rcache_str, "(O)", self); \ + if (r != Py_NotImplemented) \ + return r; \ + Py_DECREF(r); \ + do_other = 0; \ + } \ + r = call_maybe( \ + self, OPSTR, &cache_str, "(O)", other); \ + if (r != Py_NotImplemented || \ + other->ob_type == self->ob_type) \ + return r; \ + Py_DECREF(r); \ + } \ + if (do_other) { \ + return call_maybe( \ + other, ROPSTR, &rcache_str, "(O)", self); \ + } \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ +} + +#define SLOT1BIN(FUNCNAME, SLOTNAME, OPSTR, ROPSTR) \ + SLOT1BINFULL(FUNCNAME, FUNCNAME, SLOTNAME, OPSTR, ROPSTR) + +#define SLOT2(FUNCNAME, OPSTR, ARG1TYPE, ARG2TYPE, ARGCODES) \ +static PyObject * \ +FUNCNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \ +{ \ + static PyObject *cache_str; \ + return call_method(self, OPSTR, &cache_str, \ + "(" ARGCODES ")", arg1, arg2); \ +} + +static Py_ssize_t +slot_sq_length(PyObject *self) +{ + static PyObject *len_str; + PyObject *res = call_method(self, "__len__", &len_str, "()"); + Py_ssize_t len; + + if (res == NULL) + return -1; + len = PyInt_AsSsize_t(res); + Py_DECREF(res); + if (len < 0) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_ValueError, + "__len__() should return >= 0"); + return -1; + } + return len; +} + +/* Super-optimized version of slot_sq_item. + Other slots could do the same... */ +static PyObject * +slot_sq_item(PyObject *self, Py_ssize_t i) +{ + static PyObject *getitem_str; + PyObject *func, *args = NULL, *ival = NULL, *retval = NULL; + descrgetfunc f; + + if (getitem_str == NULL) { + getitem_str = PyString_InternFromString("__getitem__"); + if (getitem_str == NULL) + return NULL; + } + func = _PyType_Lookup(self->ob_type, getitem_str); + if (func != NULL) { + if ((f = func->ob_type->tp_descr_get) == NULL) + Py_INCREF(func); + else { + func = f(func, self, (PyObject *)(self->ob_type)); + if (func == NULL) { + return NULL; + } + } + ival = PyInt_FromSsize_t(i); + if (ival != NULL) { + args = PyTuple_New(1); + if (args != NULL) { + PyTuple_SET_ITEM(args, 0, ival); + retval = PyObject_Call(func, args, NULL); + Py_XDECREF(args); + Py_XDECREF(func); + return retval; + } + } + } + else { + PyErr_SetObject(PyExc_AttributeError, getitem_str); + } + Py_XDECREF(args); + Py_XDECREF(ival); + Py_XDECREF(func); + return NULL; +} + +SLOT2(slot_sq_slice, "__getslice__", Py_ssize_t, Py_ssize_t, "nn") + +static int +slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value) +{ + PyObject *res; + static PyObject *delitem_str, *setitem_str; + + if (value == NULL) + res = call_method(self, "__delitem__", &delitem_str, + "(n)", index); + else + res = call_method(self, "__setitem__", &setitem_str, + "(nO)", index, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static int +slot_sq_ass_slice(PyObject *self, Py_ssize_t i, Py_ssize_t j, PyObject *value) +{ + PyObject *res; + static PyObject *delslice_str, *setslice_str; + + if (value == NULL) + res = call_method(self, "__delslice__", &delslice_str, + "(nn)", i, j); + else + res = call_method(self, "__setslice__", &setslice_str, + "(nnO)", i, j, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static int +slot_sq_contains(PyObject *self, PyObject *value) +{ + PyObject *func, *res, *args; + int result = -1; + + static PyObject *contains_str; + + func = lookup_maybe(self, "__contains__", &contains_str); + if (func != NULL) { + args = PyTuple_Pack(1, value); + if (args == NULL) + res = NULL; + else { + res = PyObject_Call(func, args, NULL); + Py_DECREF(args); + } + Py_DECREF(func); + if (res != NULL) { + result = PyObject_IsTrue(res); + Py_DECREF(res); + } + } + else if (! PyErr_Occurred()) { + /* Possible results: -1 and 1 */ + result = (int)_PySequence_IterSearch(self, value, + PY_ITERSEARCH_CONTAINS); + } + return result; +} + +#define slot_mp_length slot_sq_length + +SLOT1(slot_mp_subscript, "__getitem__", PyObject *, "O") + +static int +slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) +{ + PyObject *res; + static PyObject *delitem_str, *setitem_str; + + if (value == NULL) + res = call_method(self, "__delitem__", &delitem_str, + "(O)", key); + else + res = call_method(self, "__setitem__", &setitem_str, + "(OO)", key, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +SLOT1BIN(slot_nb_add, nb_add, "__add__", "__radd__") +SLOT1BIN(slot_nb_subtract, nb_subtract, "__sub__", "__rsub__") +SLOT1BIN(slot_nb_multiply, nb_multiply, "__mul__", "__rmul__") +SLOT1BIN(slot_nb_divide, nb_divide, "__div__", "__rdiv__") +SLOT1BIN(slot_nb_remainder, nb_remainder, "__mod__", "__rmod__") +SLOT1BIN(slot_nb_divmod, nb_divmod, "__divmod__", "__rdivmod__") + +static PyObject *slot_nb_power(PyObject *, PyObject *, PyObject *); + +SLOT1BINFULL(slot_nb_power_binary, slot_nb_power, + nb_power, "__pow__", "__rpow__") + +static PyObject * +slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus) +{ + static PyObject *pow_str; + + if (modulus == Py_None) + return slot_nb_power_binary(self, other); + /* Three-arg power doesn't use __rpow__. But ternary_op + can call this when the second argument's type uses + slot_nb_power, so check before calling self.__pow__. */ + if (self->ob_type->tp_as_number != NULL && + self->ob_type->tp_as_number->nb_power == slot_nb_power) { + return call_method(self, "__pow__", &pow_str, + "(OO)", other, modulus); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +SLOT0(slot_nb_negative, "__neg__") +SLOT0(slot_nb_positive, "__pos__") +SLOT0(slot_nb_absolute, "__abs__") + +static int +slot_nb_nonzero(PyObject *self) +{ + PyObject *func, *args; + static PyObject *nonzero_str, *len_str; + int result = -1; + + func = lookup_maybe(self, "__nonzero__", &nonzero_str); + if (func == NULL) { + if (PyErr_Occurred()) + return -1; + func = lookup_maybe(self, "__len__", &len_str); + if (func == NULL) + return PyErr_Occurred() ? -1 : 1; + } + args = PyTuple_New(0); + if (args != NULL) { + PyObject *temp = PyObject_Call(func, args, NULL); + Py_DECREF(args); + if (temp != NULL) { + if (PyInt_CheckExact(temp) || PyBool_Check(temp)) + result = PyObject_IsTrue(temp); + else { + PyErr_Format(PyExc_TypeError, + "__nonzero__ should return " + "bool or int, returned %s", + temp->ob_type->tp_name); + result = -1; + } + Py_DECREF(temp); + } + } + Py_DECREF(func); + return result; +} + + +static PyObject * +slot_nb_index(PyObject *self) +{ + static PyObject *index_str; + return call_method(self, "__index__", &index_str, "()"); +} + + +SLOT0(slot_nb_invert, "__invert__") +SLOT1BIN(slot_nb_lshift, nb_lshift, "__lshift__", "__rlshift__") +SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__") +SLOT1BIN(slot_nb_and, nb_and, "__and__", "__rand__") +SLOT1BIN(slot_nb_xor, nb_xor, "__xor__", "__rxor__") +SLOT1BIN(slot_nb_or, nb_or, "__or__", "__ror__") + +static int +slot_nb_coerce(PyObject **a, PyObject **b) +{ + static PyObject *coerce_str; + PyObject *self = *a, *other = *b; + + if (self->ob_type->tp_as_number != NULL && + self->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) { + PyObject *r; + r = call_maybe( + self, "__coerce__", &coerce_str, "(O)", other); + if (r == NULL) + return -1; + if (r == Py_NotImplemented) { + Py_DECREF(r); + } + else { + if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) { + PyErr_SetString(PyExc_TypeError, + "__coerce__ didn't return a 2-tuple"); + Py_DECREF(r); + return -1; + } + *a = PyTuple_GET_ITEM(r, 0); + Py_INCREF(*a); + *b = PyTuple_GET_ITEM(r, 1); + Py_INCREF(*b); + Py_DECREF(r); + return 0; + } + } + if (other->ob_type->tp_as_number != NULL && + other->ob_type->tp_as_number->nb_coerce == slot_nb_coerce) { + PyObject *r; + r = call_maybe( + other, "__coerce__", &coerce_str, "(O)", self); + if (r == NULL) + return -1; + if (r == Py_NotImplemented) { + Py_DECREF(r); + return 1; + } + if (!PyTuple_Check(r) || PyTuple_GET_SIZE(r) != 2) { + PyErr_SetString(PyExc_TypeError, + "__coerce__ didn't return a 2-tuple"); + Py_DECREF(r); + return -1; + } + *a = PyTuple_GET_ITEM(r, 1); + Py_INCREF(*a); + *b = PyTuple_GET_ITEM(r, 0); + Py_INCREF(*b); + Py_DECREF(r); + return 0; + } + return 1; +} + +SLOT0(slot_nb_int, "__int__") +SLOT0(slot_nb_long, "__long__") +SLOT0(slot_nb_float, "__float__") +SLOT0(slot_nb_oct, "__oct__") +SLOT0(slot_nb_hex, "__hex__") +SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O") +SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O") +SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O") +SLOT1(slot_nb_inplace_divide, "__idiv__", PyObject *, "O") +SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *, "O") +/* Can't use SLOT1 here, because nb_inplace_power is ternary */ +static PyObject * +slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2) +{ + static PyObject *cache_str; + return call_method(self, "__ipow__", &cache_str, "(" "O" ")", arg1); +} +SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *, "O") +SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *, "O") +SLOT1(slot_nb_inplace_and, "__iand__", PyObject *, "O") +SLOT1(slot_nb_inplace_xor, "__ixor__", PyObject *, "O") +SLOT1(slot_nb_inplace_or, "__ior__", PyObject *, "O") +SLOT1BIN(slot_nb_floor_divide, nb_floor_divide, + "__floordiv__", "__rfloordiv__") +SLOT1BIN(slot_nb_true_divide, nb_true_divide, "__truediv__", "__rtruediv__") +SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject *, "O") +SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject *, "O") + +static int +half_compare(PyObject *self, PyObject *other) +{ + PyObject *func, *args, *res; + static PyObject *cmp_str; + Py_ssize_t c; + + func = lookup_method(self, "__cmp__", &cmp_str); + if (func == NULL) { + PyErr_Clear(); + } + else { + args = PyTuple_Pack(1, other); + if (args == NULL) + res = NULL; + else { + res = PyObject_Call(func, args, NULL); + Py_DECREF(args); + } + Py_DECREF(func); + if (res != Py_NotImplemented) { + if (res == NULL) + return -2; + c = PyInt_AsLong(res); + Py_DECREF(res); + if (c == -1 && PyErr_Occurred()) + return -2; + return (c < 0) ? -1 : (c > 0) ? 1 : 0; + } + Py_DECREF(res); + } + return 2; +} + +/* This slot is published for the benefit of try_3way_compare in object.c */ +int +_PyObject_SlotCompare(PyObject *self, PyObject *other) +{ + int c; + + if (self->ob_type->tp_compare == _PyObject_SlotCompare) { + c = half_compare(self, other); + if (c <= 1) + return c; + } + if (other->ob_type->tp_compare == _PyObject_SlotCompare) { + c = half_compare(other, self); + if (c < -1) + return -2; + if (c <= 1) + return -c; + } + return (void *)self < (void *)other ? -1 : + (void *)self > (void *)other ? 1 : 0; +} + +static PyObject * +slot_tp_repr(PyObject *self) +{ + PyObject *func, *res; + static PyObject *repr_str; + + func = lookup_method(self, "__repr__", &repr_str); + if (func != NULL) { + res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + return res; + } + PyErr_Clear(); + return PyString_FromFormat("<%s object at %p>", + self->ob_type->tp_name, self); +} + +static PyObject * +slot_tp_str(PyObject *self) +{ + PyObject *func, *res; + static PyObject *str_str; + + func = lookup_method(self, "__str__", &str_str); + if (func != NULL) { + res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + return res; + } + else { + PyErr_Clear(); + return slot_tp_repr(self); + } +} + +static long +slot_tp_hash(PyObject *self) +{ + PyObject *func; + static PyObject *hash_str, *eq_str, *cmp_str; + long h; + + func = lookup_method(self, "__hash__", &hash_str); + + if (func != NULL) { + PyObject *res = PyEval_CallObject(func, NULL); + Py_DECREF(func); + if (res == NULL) + return -1; + if (PyLong_Check(res)) + h = PyLong_Type.tp_hash(res); + else + h = PyInt_AsLong(res); + Py_DECREF(res); + } + else { + PyErr_Clear(); + func = lookup_method(self, "__eq__", &eq_str); + if (func == NULL) { + PyErr_Clear(); + func = lookup_method(self, "__cmp__", &cmp_str); + } + if (func != NULL) { + PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'", + self->ob_type->tp_name); + Py_DECREF(func); + return -1; + } + PyErr_Clear(); + h = _Py_HashPointer((void *)self); + } + if (h == -1 && !PyErr_Occurred()) + h = -2; + return h; +} + +static PyObject * +slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds) +{ + static PyObject *call_str; + PyObject *meth = lookup_method(self, "__call__", &call_str); + PyObject *res; + + if (meth == NULL) + return NULL; + + /* PyObject_Call() will end up calling slot_tp_call() again if + the object returned for __call__ has __call__ itself defined + upon it. This can be an infinite recursion if you set + __call__ in a class to an instance of it. */ + if (Py_EnterRecursiveCall(" in __call__")) { + Py_DECREF(meth); + return NULL; + } + res = PyObject_Call(meth, args, kwds); + Py_LeaveRecursiveCall(); + + Py_DECREF(meth); + return res; +} + +/* There are two slot dispatch functions for tp_getattro. + + - slot_tp_getattro() is used when __getattribute__ is overridden + but no __getattr__ hook is present; + + - slot_tp_getattr_hook() is used when a __getattr__ hook is present. + + The code in update_one_slot() always installs slot_tp_getattr_hook(); this + detects the absence of __getattr__ and then installs the simpler slot if + necessary. */ + +static PyObject * +slot_tp_getattro(PyObject *self, PyObject *name) +{ + static PyObject *getattribute_str = NULL; + return call_method(self, "__getattribute__", &getattribute_str, + "(O)", name); +} + +static PyObject * +slot_tp_getattr_hook(PyObject *self, PyObject *name) +{ + PyTypeObject *tp = self->ob_type; + PyObject *getattr, *getattribute, *res; + static PyObject *getattribute_str = NULL; + static PyObject *getattr_str = NULL; + + if (getattr_str == NULL) { + getattr_str = PyString_InternFromString("__getattr__"); + if (getattr_str == NULL) + return NULL; + } + if (getattribute_str == NULL) { + getattribute_str = + PyString_InternFromString("__getattribute__"); + if (getattribute_str == NULL) + return NULL; + } + getattr = _PyType_Lookup(tp, getattr_str); + if (getattr == NULL) { + /* No __getattr__ hook: use a simpler dispatcher */ + tp->tp_getattro = slot_tp_getattro; + return slot_tp_getattro(self, name); + } + getattribute = _PyType_Lookup(tp, getattribute_str); + if (getattribute == NULL || + (getattribute->ob_type == &PyWrapperDescr_Type && + ((PyWrapperDescrObject *)getattribute)->d_wrapped == + (void *)PyObject_GenericGetAttr)) + res = PyObject_GenericGetAttr(self, name); + else + res = PyObject_CallFunctionObjArgs(getattribute, self, name, NULL); + if (res == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + res = PyObject_CallFunctionObjArgs(getattr, self, name, NULL); + } + return res; +} + +static int +slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value) +{ + PyObject *res; + static PyObject *delattr_str, *setattr_str; + + if (value == NULL) + res = call_method(self, "__delattr__", &delattr_str, + "(O)", name); + else + res = call_method(self, "__setattr__", &setattr_str, + "(OO)", name, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +/* Map rich comparison operators to their __xx__ namesakes */ +static char *name_op[] = { + "__lt__", + "__le__", + "__eq__", + "__ne__", + "__gt__", + "__ge__", +}; + +static PyObject * +half_richcompare(PyObject *self, PyObject *other, int op) +{ + PyObject *func, *args, *res; + static PyObject *op_str[6]; + + func = lookup_method(self, name_op[op], &op_str[op]); + if (func == NULL) { + PyErr_Clear(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + args = PyTuple_Pack(1, other); + if (args == NULL) + res = NULL; + else { + res = PyObject_Call(func, args, NULL); + Py_DECREF(args); + } + Py_DECREF(func); + return res; +} + +static PyObject * +slot_tp_richcompare(PyObject *self, PyObject *other, int op) +{ + PyObject *res; + + if (self->ob_type->tp_richcompare == slot_tp_richcompare) { + res = half_richcompare(self, other, op); + if (res != Py_NotImplemented) + return res; + Py_DECREF(res); + } + if (other->ob_type->tp_richcompare == slot_tp_richcompare) { + res = half_richcompare(other, self, _Py_SwappedOp[op]); + if (res != Py_NotImplemented) { + return res; + } + Py_DECREF(res); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} + +static PyObject * +slot_tp_iter(PyObject *self) +{ + PyObject *func, *res; + static PyObject *iter_str, *getitem_str; + + func = lookup_method(self, "__iter__", &iter_str); + if (func != NULL) { + PyObject *args; + args = res = PyTuple_New(0); + if (args != NULL) { + res = PyObject_Call(func, args, NULL); + Py_DECREF(args); + } + Py_DECREF(func); + return res; + } + PyErr_Clear(); + func = lookup_method(self, "__getitem__", &getitem_str); + if (func == NULL) { + PyErr_Format(PyExc_TypeError, + "'%.200s' object is not iterable", + self->ob_type->tp_name); + return NULL; + } + Py_DECREF(func); + return PySeqIter_New(self); +} + +static PyObject * +slot_tp_iternext(PyObject *self) +{ + static PyObject *next_str; + return call_method(self, "next", &next_str, "()"); +} + +static PyObject * +slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + PyTypeObject *tp = self->ob_type; + PyObject *get; + static PyObject *get_str = NULL; + + if (get_str == NULL) { + get_str = PyString_InternFromString("__get__"); + if (get_str == NULL) + return NULL; + } + get = _PyType_Lookup(tp, get_str); + if (get == NULL) { + /* Avoid further slowdowns */ + if (tp->tp_descr_get == slot_tp_descr_get) + tp->tp_descr_get = NULL; + Py_INCREF(self); + return self; + } + if (obj == NULL) + obj = Py_None; + if (type == NULL) + type = Py_None; + return PyObject_CallFunctionObjArgs(get, self, obj, type, NULL); +} + +static int +slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value) +{ + PyObject *res; + static PyObject *del_str, *set_str; + + if (value == NULL) + res = call_method(self, "__delete__", &del_str, + "(O)", target); + else + res = call_method(self, "__set__", &set_str, + "(OO)", target, value); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; +} + +static int +slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + static PyObject *init_str; + PyObject *meth = lookup_method(self, "__init__", &init_str); + PyObject *res; + + if (meth == NULL) + return -1; + res = PyObject_Call(meth, args, kwds); + Py_DECREF(meth); + if (res == NULL) + return -1; + if (res != Py_None) { + PyErr_Format(PyExc_TypeError, + "__init__() should return None, not '%.200s'", + res->ob_type->tp_name); + Py_DECREF(res); + return -1; + } + Py_DECREF(res); + return 0; +} + +static PyObject * +slot_tp_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static PyObject *new_str; + PyObject *func; + PyObject *newargs, *x; + Py_ssize_t i, n; + + if (new_str == NULL) { + new_str = PyString_InternFromString("__new__"); + if (new_str == NULL) + return NULL; + } + func = PyObject_GetAttr((PyObject *)type, new_str); + if (func == NULL) + return NULL; + assert(PyTuple_Check(args)); + n = PyTuple_GET_SIZE(args); + newargs = PyTuple_New(n+1); + if (newargs == NULL) + return NULL; + Py_INCREF(type); + PyTuple_SET_ITEM(newargs, 0, (PyObject *)type); + for (i = 0; i < n; i++) { + x = PyTuple_GET_ITEM(args, i); + Py_INCREF(x); + PyTuple_SET_ITEM(newargs, i+1, x); + } + x = PyObject_Call(func, newargs, kwds); + Py_DECREF(newargs); + Py_DECREF(func); + return x; +} + +static void +slot_tp_del(PyObject *self) +{ + static PyObject *del_str = NULL; + PyObject *del, *res; + PyObject *error_type, *error_value, *error_traceback; + + /* Temporarily resurrect the object. */ + assert(self->ob_refcnt == 0); + self->ob_refcnt = 1; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + /* Execute __del__ method, if any. */ + del = lookup_maybe(self, "__del__", &del_str); + if (del != NULL) { + res = PyEval_CallObject(del, NULL); + if (res == NULL) + PyErr_WriteUnraisable(del); + else + Py_DECREF(res); + Py_DECREF(del); + } + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ + assert(self->ob_refcnt > 0); + if (--self->ob_refcnt == 0) + return; /* this is the normal path out */ + + /* __del__ resurrected it! Make it look like the original Py_DECREF + * never happened. + */ + { + Py_ssize_t refcnt = self->ob_refcnt; + _Py_NewReference(self); + self->ob_refcnt = refcnt; + } + assert(!PyType_IS_GC(self->ob_type) || + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so + * we need to undo that. */ + _Py_DEC_REFTOTAL; + /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object + * chain, so no more to do there. + * If COUNT_ALLOCS, the original decref bumped tp_frees, and + * _Py_NewReference bumped tp_allocs: both of those need to be + * undone. + */ +#ifdef COUNT_ALLOCS + --self->ob_type->tp_frees; + --self->ob_type->tp_allocs; +#endif +} + + +/* Table mapping __foo__ names to tp_foo offsets and slot_tp_foo wrapper + functions. The offsets here are relative to the 'PyHeapTypeObject' + structure, which incorporates the additional structures used for numbers, + sequences and mappings. + Note that multiple names may map to the same slot (e.g. __eq__, + __ne__ etc. all map to tp_richcompare) and one name may map to multiple + slots (e.g. __str__ affects tp_str as well as tp_repr). The table is + terminated with an all-zero entry. (This table is further initialized and + sorted in init_slotdefs() below.) */ + +typedef struct wrapperbase slotdef; + +#undef TPSLOT +#undef FLSLOT +#undef ETSLOT +#undef SQSLOT +#undef MPSLOT +#undef NBSLOT +#undef UNSLOT +#undef IBSLOT +#undef BINSLOT +#undef RBINSLOT + +#define TPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ + PyDoc_STR(DOC)} +#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \ + {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ + PyDoc_STR(DOC), FLAGS} +#define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \ + PyDoc_STR(DOC)} +#define SQSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + ETSLOT(NAME, as_sequence.SLOT, FUNCTION, WRAPPER, DOC) +#define MPSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + ETSLOT(NAME, as_mapping.SLOT, FUNCTION, WRAPPER, DOC) +#define NBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, DOC) +#define UNSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ + "x." NAME "() <==> " DOC) +#define IBSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \ + ETSLOT(NAME, as_number.SLOT, FUNCTION, WRAPPER, \ + "x." NAME "(y) <==> x" DOC "y") +#define BINSLOT(NAME, SLOT, FUNCTION, DOC) \ + ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ + "x." NAME "(y) <==> x" DOC "y") +#define RBINSLOT(NAME, SLOT, FUNCTION, DOC) \ + ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ + "x." NAME "(y) <==> y" DOC "x") +#define BINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ + ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_l, \ + "x." NAME "(y) <==> " DOC) +#define RBINSLOTNOTINFIX(NAME, SLOT, FUNCTION, DOC) \ + ETSLOT(NAME, as_number.SLOT, FUNCTION, wrap_binaryfunc_r, \ + "x." NAME "(y) <==> " DOC) + +static slotdef slotdefs[] = { + SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc, + "x.__len__() <==> len(x)"), + /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL. + The logic in abstract.c always falls back to nb_add/nb_multiply in + this case. Defining both the nb_* and the sq_* slots to call the + user-defined methods has unexpected side-effects, as shown by + test_descr.notimplemented() */ + SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc, + "x.__add__(y) <==> x+y"), + SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc, + "x.__mul__(n) <==> x*n"), + SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc, + "x.__rmul__(n) <==> n*x"), + SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item, + "x.__getitem__(y) <==> x[y]"), + SQSLOT("__getslice__", sq_slice, slot_sq_slice, wrap_ssizessizeargfunc, + "x.__getslice__(i, j) <==> x[i:j]\n\ + \n\ + Use of negative indices is not supported."), + SQSLOT("__setitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_setitem, + "x.__setitem__(i, y) <==> x[i]=y"), + SQSLOT("__delitem__", sq_ass_item, slot_sq_ass_item, wrap_sq_delitem, + "x.__delitem__(y) <==> del x[y]"), + SQSLOT("__setslice__", sq_ass_slice, slot_sq_ass_slice, + wrap_ssizessizeobjargproc, + "x.__setslice__(i, j, y) <==> x[i:j]=y\n\ + \n\ + Use of negative indices is not supported."), + SQSLOT("__delslice__", sq_ass_slice, slot_sq_ass_slice, wrap_delslice, + "x.__delslice__(i, j) <==> del x[i:j]\n\ + \n\ + Use of negative indices is not supported."), + SQSLOT("__contains__", sq_contains, slot_sq_contains, wrap_objobjproc, + "x.__contains__(y) <==> y in x"), + SQSLOT("__iadd__", sq_inplace_concat, NULL, + wrap_binaryfunc, "x.__iadd__(y) <==> x+=y"), + SQSLOT("__imul__", sq_inplace_repeat, NULL, + wrap_indexargfunc, "x.__imul__(y) <==> x*=y"), + + MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc, + "x.__len__() <==> len(x)"), + MPSLOT("__getitem__", mp_subscript, slot_mp_subscript, + wrap_binaryfunc, + "x.__getitem__(y) <==> x[y]"), + MPSLOT("__setitem__", mp_ass_subscript, slot_mp_ass_subscript, + wrap_objobjargproc, + "x.__setitem__(i, y) <==> x[i]=y"), + MPSLOT("__delitem__", mp_ass_subscript, slot_mp_ass_subscript, + wrap_delitem, + "x.__delitem__(y) <==> del x[y]"), + + BINSLOT("__add__", nb_add, slot_nb_add, + "+"), + RBINSLOT("__radd__", nb_add, slot_nb_add, + "+"), + BINSLOT("__sub__", nb_subtract, slot_nb_subtract, + "-"), + RBINSLOT("__rsub__", nb_subtract, slot_nb_subtract, + "-"), + BINSLOT("__mul__", nb_multiply, slot_nb_multiply, + "*"), + RBINSLOT("__rmul__", nb_multiply, slot_nb_multiply, + "*"), + BINSLOT("__div__", nb_divide, slot_nb_divide, + "/"), + RBINSLOT("__rdiv__", nb_divide, slot_nb_divide, + "/"), + BINSLOT("__mod__", nb_remainder, slot_nb_remainder, + "%"), + RBINSLOT("__rmod__", nb_remainder, slot_nb_remainder, + "%"), + BINSLOTNOTINFIX("__divmod__", nb_divmod, slot_nb_divmod, + "divmod(x, y)"), + RBINSLOTNOTINFIX("__rdivmod__", nb_divmod, slot_nb_divmod, + "divmod(y, x)"), + NBSLOT("__pow__", nb_power, slot_nb_power, wrap_ternaryfunc, + "x.__pow__(y[, z]) <==> pow(x, y[, z])"), + NBSLOT("__rpow__", nb_power, slot_nb_power, wrap_ternaryfunc_r, + "y.__rpow__(x[, z]) <==> pow(x, y[, z])"), + UNSLOT("__neg__", nb_negative, slot_nb_negative, wrap_unaryfunc, "-x"), + UNSLOT("__pos__", nb_positive, slot_nb_positive, wrap_unaryfunc, "+x"), + UNSLOT("__abs__", nb_absolute, slot_nb_absolute, wrap_unaryfunc, + "abs(x)"), + UNSLOT("__nonzero__", nb_nonzero, slot_nb_nonzero, wrap_inquirypred, + "x != 0"), + UNSLOT("__invert__", nb_invert, slot_nb_invert, wrap_unaryfunc, "~x"), + BINSLOT("__lshift__", nb_lshift, slot_nb_lshift, "<<"), + RBINSLOT("__rlshift__", nb_lshift, slot_nb_lshift, "<<"), + BINSLOT("__rshift__", nb_rshift, slot_nb_rshift, ">>"), + RBINSLOT("__rrshift__", nb_rshift, slot_nb_rshift, ">>"), + BINSLOT("__and__", nb_and, slot_nb_and, "&"), + RBINSLOT("__rand__", nb_and, slot_nb_and, "&"), + BINSLOT("__xor__", nb_xor, slot_nb_xor, "^"), + RBINSLOT("__rxor__", nb_xor, slot_nb_xor, "^"), + BINSLOT("__or__", nb_or, slot_nb_or, "|"), + RBINSLOT("__ror__", nb_or, slot_nb_or, "|"), + NBSLOT("__coerce__", nb_coerce, slot_nb_coerce, wrap_coercefunc, + "x.__coerce__(y) <==> coerce(x, y)"), + UNSLOT("__int__", nb_int, slot_nb_int, wrap_unaryfunc, + "int(x)"), + UNSLOT("__long__", nb_long, slot_nb_long, wrap_unaryfunc, + "long(x)"), + UNSLOT("__float__", nb_float, slot_nb_float, wrap_unaryfunc, + "float(x)"), + UNSLOT("__oct__", nb_oct, slot_nb_oct, wrap_unaryfunc, + "oct(x)"), + UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc, + "hex(x)"), + NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, + "x[y:z] <==> x[y.__index__():z.__index__()]"), + IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, + wrap_binaryfunc, "+"), + IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract, + wrap_binaryfunc, "-"), + IBSLOT("__imul__", nb_inplace_multiply, slot_nb_inplace_multiply, + wrap_binaryfunc, "*"), + IBSLOT("__idiv__", nb_inplace_divide, slot_nb_inplace_divide, + wrap_binaryfunc, "/"), + IBSLOT("__imod__", nb_inplace_remainder, slot_nb_inplace_remainder, + wrap_binaryfunc, "%"), + IBSLOT("__ipow__", nb_inplace_power, slot_nb_inplace_power, + wrap_binaryfunc, "**"), + IBSLOT("__ilshift__", nb_inplace_lshift, slot_nb_inplace_lshift, + wrap_binaryfunc, "<<"), + IBSLOT("__irshift__", nb_inplace_rshift, slot_nb_inplace_rshift, + wrap_binaryfunc, ">>"), + IBSLOT("__iand__", nb_inplace_and, slot_nb_inplace_and, + wrap_binaryfunc, "&"), + IBSLOT("__ixor__", nb_inplace_xor, slot_nb_inplace_xor, + wrap_binaryfunc, "^"), + IBSLOT("__ior__", nb_inplace_or, slot_nb_inplace_or, + wrap_binaryfunc, "|"), + BINSLOT("__floordiv__", nb_floor_divide, slot_nb_floor_divide, "//"), + RBINSLOT("__rfloordiv__", nb_floor_divide, slot_nb_floor_divide, "//"), + BINSLOT("__truediv__", nb_true_divide, slot_nb_true_divide, "/"), + RBINSLOT("__rtruediv__", nb_true_divide, slot_nb_true_divide, "/"), + IBSLOT("__ifloordiv__", nb_inplace_floor_divide, + slot_nb_inplace_floor_divide, wrap_binaryfunc, "//"), + IBSLOT("__itruediv__", nb_inplace_true_divide, + slot_nb_inplace_true_divide, wrap_binaryfunc, "/"), + + TPSLOT("__str__", tp_str, slot_tp_str, wrap_unaryfunc, + "x.__str__() <==> str(x)"), + TPSLOT("__str__", tp_print, NULL, NULL, ""), + TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, + "x.__repr__() <==> repr(x)"), + TPSLOT("__repr__", tp_print, NULL, NULL, ""), + TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc, + "x.__cmp__(y) <==> cmp(x,y)"), + TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, + "x.__hash__() <==> hash(x)"), + FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfunc)wrap_call, + "x.__call__(...) <==> x(...)", PyWrapperFlag_KEYWORDS), + TPSLOT("__getattribute__", tp_getattro, slot_tp_getattr_hook, + wrap_binaryfunc, "x.__getattribute__('name') <==> x.name"), + TPSLOT("__getattribute__", tp_getattr, NULL, NULL, ""), + TPSLOT("__getattr__", tp_getattro, slot_tp_getattr_hook, NULL, ""), + TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""), + TPSLOT("__setattr__", tp_setattro, slot_tp_setattro, wrap_setattr, + "x.__setattr__('name', value) <==> x.name = value"), + TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""), + TPSLOT("__delattr__", tp_setattro, slot_tp_setattro, wrap_delattr, + "x.__delattr__('name') <==> del x.name"), + TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""), + TPSLOT("__lt__", tp_richcompare, slot_tp_richcompare, richcmp_lt, + "x.__lt__(y) <==> x<y"), + TPSLOT("__le__", tp_richcompare, slot_tp_richcompare, richcmp_le, + "x.__le__(y) <==> x<=y"), + TPSLOT("__eq__", tp_richcompare, slot_tp_richcompare, richcmp_eq, + "x.__eq__(y) <==> x==y"), + TPSLOT("__ne__", tp_richcompare, slot_tp_richcompare, richcmp_ne, + "x.__ne__(y) <==> x!=y"), + TPSLOT("__gt__", tp_richcompare, slot_tp_richcompare, richcmp_gt, + "x.__gt__(y) <==> x>y"), + TPSLOT("__ge__", tp_richcompare, slot_tp_richcompare, richcmp_ge, + "x.__ge__(y) <==> x>=y"), + TPSLOT("__iter__", tp_iter, slot_tp_iter, wrap_unaryfunc, + "x.__iter__() <==> iter(x)"), + TPSLOT("next", tp_iternext, slot_tp_iternext, wrap_next, + "x.next() -> the next value, or raise StopIteration"), + TPSLOT("__get__", tp_descr_get, slot_tp_descr_get, wrap_descr_get, + "descr.__get__(obj[, type]) -> value"), + TPSLOT("__set__", tp_descr_set, slot_tp_descr_set, wrap_descr_set, + "descr.__set__(obj, value)"), + TPSLOT("__delete__", tp_descr_set, slot_tp_descr_set, + wrap_descr_delete, "descr.__delete__(obj)"), + FLSLOT("__init__", tp_init, slot_tp_init, (wrapperfunc)wrap_init, + "x.__init__(...) initializes x; " + "see x.__class__.__doc__ for signature", + PyWrapperFlag_KEYWORDS), + TPSLOT("__new__", tp_new, slot_tp_new, NULL, ""), + TPSLOT("__del__", tp_del, slot_tp_del, NULL, ""), + {NULL} +}; + +/* Given a type pointer and an offset gotten from a slotdef entry, return a + pointer to the actual slot. This is not quite the same as simply adding + the offset to the type pointer, since it takes care to indirect through the + proper indirection pointer (as_buffer, etc.); it returns NULL if the + indirection pointer is NULL. */ +static void ** +slotptr(PyTypeObject *type, int ioffset) +{ + char *ptr; + long offset = ioffset; + + /* Note: this depends on the order of the members of PyHeapTypeObject! */ + assert(offset >= 0); + assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer)); + if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) { + ptr = (char *)type->tp_as_sequence; + offset -= offsetof(PyHeapTypeObject, as_sequence); + } + else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_mapping)) { + ptr = (char *)type->tp_as_mapping; + offset -= offsetof(PyHeapTypeObject, as_mapping); + } + else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_number)) { + ptr = (char *)type->tp_as_number; + offset -= offsetof(PyHeapTypeObject, as_number); + } + else { + ptr = (char *)type; + } + if (ptr != NULL) + ptr += offset; + return (void **)ptr; +} + +/* Length of array of slotdef pointers used to store slots with the + same __name__. There should be at most MAX_EQUIV-1 slotdef entries with + the same __name__, for any __name__. Since that's a static property, it is + appropriate to declare fixed-size arrays for this. */ +#define MAX_EQUIV 10 + +/* Return a slot pointer for a given name, but ONLY if the attribute has + exactly one slot function. The name must be an interned string. */ +static void ** +resolve_slotdups(PyTypeObject *type, PyObject *name) +{ + /* XXX Maybe this could be optimized more -- but is it worth it? */ + + /* pname and ptrs act as a little cache */ + static PyObject *pname; + static slotdef *ptrs[MAX_EQUIV]; + slotdef *p, **pp; + void **res, **ptr; + + if (pname != name) { + /* Collect all slotdefs that match name into ptrs. */ + pname = name; + pp = ptrs; + for (p = slotdefs; p->name_strobj; p++) { + if (p->name_strobj == name) + *pp++ = p; + } + *pp = NULL; + } + + /* Look in all matching slots of the type; if exactly one of these has + a filled-in slot, return its value. Otherwise return NULL. */ + res = NULL; + for (pp = ptrs; *pp; pp++) { + ptr = slotptr(type, (*pp)->offset); + if (ptr == NULL || *ptr == NULL) + continue; + if (res != NULL) + return NULL; + res = ptr; + } + return res; +} + +/* Common code for update_slots_callback() and fixup_slot_dispatchers(). This + does some incredibly complex thinking and then sticks something into the + slot. (It sees if the adjacent slotdefs for the same slot have conflicting + interests, and then stores a generic wrapper or a specific function into + the slot.) Return a pointer to the next slotdef with a different offset, + because that's convenient for fixup_slot_dispatchers(). */ +static slotdef * +update_one_slot(PyTypeObject *type, slotdef *p) +{ + PyObject *descr; + PyWrapperDescrObject *d; + void *generic = NULL, *specific = NULL; + int use_generic = 0; + int offset = p->offset; + void **ptr = slotptr(type, offset); + + if (ptr == NULL) { + do { + ++p; + } while (p->offset == offset); + return p; + } + do { + descr = _PyType_Lookup(type, p->name_strobj); + if (descr == NULL) + continue; + if (descr->ob_type == &PyWrapperDescr_Type) { + void **tptr = resolve_slotdups(type, p->name_strobj); + if (tptr == NULL || tptr == ptr) + generic = p->function; + d = (PyWrapperDescrObject *)descr; + if (d->d_base->wrapper == p->wrapper && + PyType_IsSubtype(type, d->d_type)) + { + if (specific == NULL || + specific == d->d_wrapped) + specific = d->d_wrapped; + else + use_generic = 1; + } + } + else if (descr->ob_type == &PyCFunction_Type && + PyCFunction_GET_FUNCTION(descr) == + (PyCFunction)tp_new_wrapper && + strcmp(p->name, "__new__") == 0) + { + /* The __new__ wrapper is not a wrapper descriptor, + so must be special-cased differently. + If we don't do this, creating an instance will + always use slot_tp_new which will look up + __new__ in the MRO which will call tp_new_wrapper + which will look through the base classes looking + for a static base and call its tp_new (usually + PyType_GenericNew), after performing various + sanity checks and constructing a new argument + list. Cut all that nonsense short -- this speeds + up instance creation tremendously. */ + specific = (void *)type->tp_new; + /* XXX I'm not 100% sure that there isn't a hole + in this reasoning that requires additional + sanity checks. I'll buy the first person to + point out a bug in this reasoning a beer. */ + } + else { + use_generic = 1; + generic = p->function; + } + } while ((++p)->offset == offset); + if (specific && !use_generic) + *ptr = specific; + else + *ptr = generic; + return p; +} + +/* In the type, update the slots whose slotdefs are gathered in the pp array. + This is a callback for update_subclasses(). */ +static int +update_slots_callback(PyTypeObject *type, void *data) +{ + slotdef **pp = (slotdef **)data; + + for (; *pp; pp++) + update_one_slot(type, *pp); + return 0; +} + +/* Comparison function for qsort() to compare slotdefs by their offset, and + for equal offset by their address (to force a stable sort). */ +static int +slotdef_cmp(const void *aa, const void *bb) +{ + const slotdef *a = (const slotdef *)aa, *b = (const slotdef *)bb; + int c = a->offset - b->offset; + if (c != 0) + return c; + else + /* Cannot use a-b, as this gives off_t, + which may lose precision when converted to int. */ + return (a > b) ? 1 : (a < b) ? -1 : 0; +} + +/* Initialize the slotdefs table by adding interned string objects for the + names and sorting the entries. */ +static void +init_slotdefs(void) +{ + slotdef *p; + static int initialized = 0; + + if (initialized) + return; + for (p = slotdefs; p->name; p++) { + p->name_strobj = PyString_InternFromString(p->name); + if (!p->name_strobj) + Py_FatalError("Out of memory interning slotdef names"); + } + qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef), + slotdef_cmp); + initialized = 1; +} + +/* Update the slots after assignment to a class (type) attribute. */ +static int +update_slot(PyTypeObject *type, PyObject *name) +{ + slotdef *ptrs[MAX_EQUIV]; + slotdef *p; + slotdef **pp; + int offset; + + init_slotdefs(); + pp = ptrs; + for (p = slotdefs; p->name; p++) { + /* XXX assume name is interned! */ + if (p->name_strobj == name) + *pp++ = p; + } + *pp = NULL; + for (pp = ptrs; *pp; pp++) { + p = *pp; + offset = p->offset; + while (p > slotdefs && (p-1)->offset == offset) + --p; + *pp = p; + } + if (ptrs[0] == NULL) + return 0; /* Not an attribute that affects any slots */ + return update_subclasses(type, name, + update_slots_callback, (void *)ptrs); +} + +/* Store the proper functions in the slot dispatches at class (type) + definition time, based upon which operations the class overrides in its + dict. */ +static void +fixup_slot_dispatchers(PyTypeObject *type) +{ + slotdef *p; + + init_slotdefs(); + for (p = slotdefs; p->name; ) + p = update_one_slot(type, p); +} + +static void +update_all_slots(PyTypeObject* type) +{ + slotdef *p; + + init_slotdefs(); + for (p = slotdefs; p->name; p++) { + /* update_slot returns int but can't actually fail */ + update_slot(type, p->name_strobj); + } +} + +/* recurse_down_subclasses() and update_subclasses() are mutually + recursive functions to call a callback for all subclasses, + but refraining from recursing into subclasses that define 'name'. */ + +static int +update_subclasses(PyTypeObject *type, PyObject *name, + update_callback callback, void *data) +{ + if (callback(type, data) < 0) + return -1; + return recurse_down_subclasses(type, name, callback, data); +} + +static int +recurse_down_subclasses(PyTypeObject *type, PyObject *name, + update_callback callback, void *data) +{ + PyTypeObject *subclass; + PyObject *ref, *subclasses, *dict; + Py_ssize_t i, n; + + subclasses = type->tp_subclasses; + if (subclasses == NULL) + return 0; + assert(PyList_Check(subclasses)); + n = PyList_GET_SIZE(subclasses); + for (i = 0; i < n; i++) { + ref = PyList_GET_ITEM(subclasses, i); + assert(PyWeakref_CheckRef(ref)); + subclass = (PyTypeObject *)PyWeakref_GET_OBJECT(ref); + assert(subclass != NULL); + if ((PyObject *)subclass == Py_None) + continue; + assert(PyType_Check(subclass)); + /* Avoid recursing down into unaffected classes */ + dict = subclass->tp_dict; + if (dict != NULL && PyDict_Check(dict) && + PyDict_GetItem(dict, name) != NULL) + continue; + if (update_subclasses(subclass, name, callback, data) < 0) + return -1; + } + return 0; +} + +/* This function is called by PyType_Ready() to populate the type's + dictionary with method descriptors for function slots. For each + function slot (like tp_repr) that's defined in the type, one or more + corresponding descriptors are added in the type's tp_dict dictionary + under the appropriate name (like __repr__). Some function slots + cause more than one descriptor to be added (for example, the nb_add + slot adds both __add__ and __radd__ descriptors) and some function + slots compete for the same descriptor (for example both sq_item and + mp_subscript generate a __getitem__ descriptor). + + In the latter case, the first slotdef entry encoutered wins. Since + slotdef entries are sorted by the offset of the slot in the + PyHeapTypeObject, this gives us some control over disambiguating + between competing slots: the members of PyHeapTypeObject are listed + from most general to least general, so the most general slot is + preferred. In particular, because as_mapping comes before as_sequence, + for a type that defines both mp_subscript and sq_item, mp_subscript + wins. + + This only adds new descriptors and doesn't overwrite entries in + tp_dict that were previously defined. The descriptors contain a + reference to the C function they must call, so that it's safe if they + are copied into a subtype's __dict__ and the subtype has a different + C function in its slot -- calling the method defined by the + descriptor will call the C function that was used to create it, + rather than the C function present in the slot when it is called. + (This is important because a subtype may have a C function in the + slot that calls the method from the dictionary, and we want to avoid + infinite recursion here.) */ + +static int +add_operators(PyTypeObject *type) +{ + PyObject *dict = type->tp_dict; + slotdef *p; + PyObject *descr; + void **ptr; + + init_slotdefs(); + for (p = slotdefs; p->name; p++) { + if (p->wrapper == NULL) + continue; + ptr = slotptr(type, p->offset); + if (!ptr || !*ptr) + continue; + if (PyDict_GetItem(dict, p->name_strobj)) + continue; + descr = PyDescr_NewWrapper(type, p, *ptr); + if (descr == NULL) + return -1; + if (PyDict_SetItem(dict, p->name_strobj, descr) < 0) + return -1; + Py_DECREF(descr); + } + if (type->tp_new != NULL) { + if (add_tp_new_wrapper(type) < 0) + return -1; + } + return 0; +} + + +/* Cooperative 'super' */ + +typedef struct { + PyObject_HEAD + PyTypeObject *type; + PyObject *obj; + PyTypeObject *obj_type; +} superobject; + +static PyMemberDef super_members[] = { + {"__thisclass__", T_OBJECT, offsetof(superobject, type), READONLY, + "the class invoking super()"}, + {"__self__", T_OBJECT, offsetof(superobject, obj), READONLY, + "the instance invoking super(); may be None"}, + {"__self_class__", T_OBJECT, offsetof(superobject, obj_type), READONLY, + "the type of the instance invoking super(); may be None"}, + {0} +}; + +static void +super_dealloc(PyObject *self) +{ + superobject *su = (superobject *)self; + + _PyObject_GC_UNTRACK(self); + Py_XDECREF(su->obj); + Py_XDECREF(su->type); + Py_XDECREF(su->obj_type); + self->ob_type->tp_free(self); +} + +static PyObject * +super_repr(PyObject *self) +{ + superobject *su = (superobject *)self; + + if (su->obj_type) + return PyString_FromFormat( + "<super: <class '%s'>, <%s object>>", + su->type ? su->type->tp_name : "NULL", + su->obj_type->tp_name); + else + return PyString_FromFormat( + "<super: <class '%s'>, NULL>", + su->type ? su->type->tp_name : "NULL"); +} + +static PyObject * +super_getattro(PyObject *self, PyObject *name) +{ + superobject *su = (superobject *)self; + int skip = su->obj_type == NULL; + + if (!skip) { + /* We want __class__ to return the class of the super object + (i.e. super, or a subclass), not the class of su->obj. */ + skip = (PyString_Check(name) && + PyString_GET_SIZE(name) == 9 && + strcmp(PyString_AS_STRING(name), "__class__") == 0); + } + + if (!skip) { + PyObject *mro, *res, *tmp, *dict; + PyTypeObject *starttype; + descrgetfunc f; + Py_ssize_t i, n; + + starttype = su->obj_type; + mro = starttype->tp_mro; + + if (mro == NULL) + n = 0; + else { + assert(PyTuple_Check(mro)); + n = PyTuple_GET_SIZE(mro); + } + for (i = 0; i < n; i++) { + if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i)) + break; + } + i++; + res = NULL; + for (; i < n; i++) { + tmp = PyTuple_GET_ITEM(mro, i); + if (PyType_Check(tmp)) + dict = ((PyTypeObject *)tmp)->tp_dict; + else if (PyClass_Check(tmp)) + dict = ((PyClassObject *)tmp)->cl_dict; + else + continue; + res = PyDict_GetItem(dict, name); + if (res != NULL) { + Py_INCREF(res); + f = res->ob_type->tp_descr_get; + if (f != NULL) { + tmp = f(res, + /* Only pass 'obj' param if + this is instance-mode super + (See SF ID #743627) + */ + (su->obj == (PyObject *) + su->obj_type + ? (PyObject *)NULL + : su->obj), + (PyObject *)starttype); + Py_DECREF(res); + res = tmp; + } + return res; + } + } + } + return PyObject_GenericGetAttr(self, name); +} + +static PyTypeObject * +supercheck(PyTypeObject *type, PyObject *obj) +{ + /* Check that a super() call makes sense. Return a type object. + + obj can be a new-style class, or an instance of one: + + - If it is a class, it must be a subclass of 'type'. This case is + used for class methods; the return value is obj. + + - If it is an instance, it must be an instance of 'type'. This is + the normal case; the return value is obj.__class__. + + But... when obj is an instance, we want to allow for the case where + obj->ob_type is not a subclass of type, but obj.__class__ is! + This will allow using super() with a proxy for obj. + */ + + /* Check for first bullet above (special case) */ + if (PyType_Check(obj) && PyType_IsSubtype((PyTypeObject *)obj, type)) { + Py_INCREF(obj); + return (PyTypeObject *)obj; + } + + /* Normal case */ + if (PyType_IsSubtype(obj->ob_type, type)) { + Py_INCREF(obj->ob_type); + return obj->ob_type; + } + else { + /* Try the slow way */ + static PyObject *class_str = NULL; + PyObject *class_attr; + + if (class_str == NULL) { + class_str = PyString_FromString("__class__"); + if (class_str == NULL) + return NULL; + } + + class_attr = PyObject_GetAttr(obj, class_str); + + if (class_attr != NULL && + PyType_Check(class_attr) && + (PyTypeObject *)class_attr != obj->ob_type) + { + int ok = PyType_IsSubtype( + (PyTypeObject *)class_attr, type); + if (ok) + return (PyTypeObject *)class_attr; + } + + if (class_attr == NULL) + PyErr_Clear(); + else + Py_DECREF(class_attr); + } + + PyErr_SetString(PyExc_TypeError, + "super(type, obj): " + "obj must be an instance or subtype of type"); + return NULL; +} + +static PyObject * +super_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + superobject *su = (superobject *)self; + superobject *newobj; + + if (obj == NULL || obj == Py_None || su->obj != NULL) { + /* Not binding to an object, or already bound */ + Py_INCREF(self); + return self; + } + if (su->ob_type != &PySuper_Type) + /* If su is an instance of a (strict) subclass of super, + call its type */ + return PyObject_CallFunctionObjArgs((PyObject *)su->ob_type, + su->type, obj, NULL); + else { + /* Inline the common case */ + PyTypeObject *obj_type = supercheck(su->type, obj); + if (obj_type == NULL) + return NULL; + newobj = (superobject *)PySuper_Type.tp_new(&PySuper_Type, + NULL, NULL); + if (newobj == NULL) + return NULL; + Py_INCREF(su->type); + Py_INCREF(obj); + newobj->type = su->type; + newobj->obj = obj; + newobj->obj_type = obj_type; + return (PyObject *)newobj; + } +} + +static int +super_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + superobject *su = (superobject *)self; + PyTypeObject *type; + PyObject *obj = NULL; + PyTypeObject *obj_type = NULL; + + if (!_PyArg_NoKeywords("super", kwds)) + return -1; + if (!PyArg_ParseTuple(args, "O!|O:super", &PyType_Type, &type, &obj)) + return -1; + if (obj == Py_None) + obj = NULL; + if (obj != NULL) { + obj_type = supercheck(type, obj); + if (obj_type == NULL) + return -1; + Py_INCREF(obj); + } + Py_INCREF(type); + su->type = type; + su->obj = obj; + su->obj_type = obj_type; + return 0; +} + +PyDoc_STRVAR(super_doc, +"super(type) -> unbound super object\n" +"super(type, obj) -> bound super object; requires isinstance(obj, type)\n" +"super(type, type2) -> bound super object; requires issubclass(type2, type)\n" +"Typical use to call a cooperative superclass method:\n" +"class C(B):\n" +" def meth(self, arg):\n" +" super(C, self).meth(arg)"); + +static int +super_traverse(PyObject *self, visitproc visit, void *arg) +{ + superobject *su = (superobject *)self; + + Py_VISIT(su->obj); + Py_VISIT(su->type); + Py_VISIT(su->obj_type); + + return 0; +} + +PyTypeObject PySuper_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "super", /* tp_name */ + sizeof(superobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + super_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + super_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + super_getattro, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + super_doc, /* tp_doc */ + super_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + super_members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + super_descr_get, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + super_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyType_GenericNew, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; diff --git a/sys/src/cmd/python/Objects/unicodectype.c b/sys/src/cmd/python/Objects/unicodectype.c new file mode 100644 index 000000000..73def09db --- /dev/null +++ b/sys/src/cmd/python/Objects/unicodectype.c @@ -0,0 +1,789 @@ +/* + Unicode character type helpers. + + Written by Marc-Andre Lemburg (mal@lemburg.com). + Modified for Python 2.0 by Fredrik Lundh (fredrik@pythonware.com) + + Copyright (c) Corporation for National Research Initiatives. + +*/ + +#include "Python.h" +#include "unicodeobject.h" + +#define ALPHA_MASK 0x01 +#define DECIMAL_MASK 0x02 +#define DIGIT_MASK 0x04 +#define LOWER_MASK 0x08 +#define LINEBREAK_MASK 0x10 +#define SPACE_MASK 0x20 +#define TITLE_MASK 0x40 +#define UPPER_MASK 0x80 + +typedef struct { + const Py_UNICODE upper; + const Py_UNICODE lower; + const Py_UNICODE title; + const unsigned char decimal; + const unsigned char digit; + const unsigned short flags; +} _PyUnicode_TypeRecord; + +#include "unicodetype_db.h" + +static const _PyUnicode_TypeRecord * +gettyperecord(Py_UNICODE code) +{ + int index; + +#ifdef Py_UNICODE_WIDE + if (code >= 0x110000) + index = 0; + else +#endif + { + index = index1[(code>>SHIFT)]; + index = index2[(index<<SHIFT)+(code&((1<<SHIFT)-1))]; + } + + return &_PyUnicode_TypeRecords[index]; +} + +/* Returns 1 for Unicode characters having the category 'Zl', 'Zp' or + type 'B', 0 otherwise. */ + +int _PyUnicode_IsLinebreak(register const Py_UNICODE ch) +{ + switch (ch) { + case 0x000A: /* LINE FEED */ + case 0x000D: /* CARRIAGE RETURN */ + case 0x001C: /* FILE SEPARATOR */ + case 0x001D: /* GROUP SEPARATOR */ + case 0x001E: /* RECORD SEPARATOR */ + case 0x0085: /* NEXT LINE */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + return 1; + default: + return 0; + } +} + +/* Returns the titlecase Unicode characters corresponding to ch or just + ch if no titlecase mapping is known. */ + +Py_UNICODE _PyUnicode_ToTitlecase(register Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + int delta; + + if (ctype->title) + delta = ctype->title; + else + delta = ctype->upper; + + if (delta >= 32768) + delta -= 65536; + + return ch + delta; +} + +/* Returns 1 for Unicode characters having the category 'Lt', 0 + otherwise. */ + +int _PyUnicode_IsTitlecase(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + + return (ctype->flags & TITLE_MASK) != 0; +} + +/* Returns the integer decimal (0-9) for Unicode characters having + this property, -1 otherwise. */ + +int _PyUnicode_ToDecimalDigit(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + + return (ctype->flags & DECIMAL_MASK) ? ctype->decimal : -1; +} + +int _PyUnicode_IsDecimalDigit(Py_UNICODE ch) +{ + if (_PyUnicode_ToDecimalDigit(ch) < 0) + return 0; + return 1; +} + +/* Returns the integer digit (0-9) for Unicode characters having + this property, -1 otherwise. */ + +int _PyUnicode_ToDigit(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + + return (ctype->flags & DIGIT_MASK) ? ctype->digit : -1; +} + +int _PyUnicode_IsDigit(Py_UNICODE ch) +{ + if (_PyUnicode_ToDigit(ch) < 0) + return 0; + return 1; +} + +/* Returns the numeric value as double for Unicode characters having + this property, -1.0 otherwise. */ + +/* TODO: replace with unicodetype_db.h table */ + +double _PyUnicode_ToNumeric(Py_UNICODE ch) +{ + switch (ch) { + case 0x0F33: + return (double) -1 / 2; + case 0x17F0: + case 0x3007: +#ifdef Py_UNICODE_WIDE + case 0x1018A: +#endif + return (double) 0; + case 0x09F4: + case 0x17F1: + case 0x215F: + case 0x2160: + case 0x2170: + case 0x3021: + case 0x3192: + case 0x3220: + case 0x3280: +#ifdef Py_UNICODE_WIDE + case 0x10107: + case 0x10142: + case 0x10158: + case 0x10159: + case 0x1015A: + case 0x10320: + case 0x103D1: +#endif + return (double) 1; + case 0x00BD: + case 0x0F2A: + case 0x2CFD: +#ifdef Py_UNICODE_WIDE + case 0x10141: + case 0x10175: + case 0x10176: +#endif + return (double) 1 / 2; + case 0x2153: + return (double) 1 / 3; + case 0x00BC: +#ifdef Py_UNICODE_WIDE + case 0x10140: +#endif + return (double) 1 / 4; + case 0x2155: + return (double) 1 / 5; + case 0x2159: + return (double) 1 / 6; + case 0x215B: + return (double) 1 / 8; + case 0x0BF0: + case 0x1372: + case 0x2169: + case 0x2179: + case 0x2469: + case 0x247D: + case 0x2491: + case 0x24FE: + case 0x277F: + case 0x2789: + case 0x2793: + case 0x3038: + case 0x3229: + case 0x3289: +#ifdef Py_UNICODE_WIDE + case 0x10110: + case 0x10149: + case 0x10150: + case 0x10157: + case 0x10160: + case 0x10161: + case 0x10162: + case 0x10163: + case 0x10164: + case 0x10322: + case 0x103D3: + case 0x10A44: +#endif + return (double) 10; + case 0x0BF1: + case 0x137B: + case 0x216D: + case 0x217D: +#ifdef Py_UNICODE_WIDE + case 0x10119: + case 0x1014B: + case 0x10152: + case 0x1016A: + case 0x103D5: + case 0x10A46: +#endif + return (double) 100; + case 0x0BF2: + case 0x216F: + case 0x217F: + case 0x2180: +#ifdef Py_UNICODE_WIDE + case 0x10122: + case 0x1014D: + case 0x10154: + case 0x10171: + case 0x10A47: +#endif + return (double) 1000; + case 0x137C: + case 0x2182: +#ifdef Py_UNICODE_WIDE + case 0x1012B: + case 0x10155: +#endif + return (double) 10000; + case 0x216A: + case 0x217A: + case 0x246A: + case 0x247E: + case 0x2492: + case 0x24EB: + return (double) 11; + case 0x0F2F: + return (double) 11 / 2; + case 0x216B: + case 0x217B: + case 0x246B: + case 0x247F: + case 0x2493: + case 0x24EC: + return (double) 12; + case 0x246C: + case 0x2480: + case 0x2494: + case 0x24ED: + return (double) 13; + case 0x0F30: + return (double) 13 / 2; + case 0x246D: + case 0x2481: + case 0x2495: + case 0x24EE: + return (double) 14; + case 0x246E: + case 0x2482: + case 0x2496: + case 0x24EF: + return (double) 15; + case 0x0F31: + return (double) 15 / 2; + case 0x09F9: + case 0x246F: + case 0x2483: + case 0x2497: + case 0x24F0: + return (double) 16; + case 0x16EE: + case 0x2470: + case 0x2484: + case 0x2498: + case 0x24F1: + return (double) 17; + case 0x0F32: + return (double) 17 / 2; + case 0x16EF: + case 0x2471: + case 0x2485: + case 0x2499: + case 0x24F2: + return (double) 18; + case 0x16F0: + case 0x2472: + case 0x2486: + case 0x249A: + case 0x24F3: + return (double) 19; + case 0x09F5: + case 0x17F2: + case 0x2161: + case 0x2171: + case 0x3022: + case 0x3193: + case 0x3221: + case 0x3281: +#ifdef Py_UNICODE_WIDE + case 0x10108: + case 0x1015B: + case 0x1015C: + case 0x1015D: + case 0x1015E: + case 0x103D2: +#endif + return (double) 2; + case 0x2154: +#ifdef Py_UNICODE_WIDE + case 0x10177: +#endif + return (double) 2 / 3; + case 0x2156: + return (double) 2 / 5; + case 0x1373: + case 0x2473: + case 0x2487: + case 0x249B: + case 0x24F4: + case 0x3039: +#ifdef Py_UNICODE_WIDE + case 0x10111: + case 0x103D4: + case 0x10A45: +#endif + return (double) 20; +#ifdef Py_UNICODE_WIDE + case 0x1011A: + return (double) 200; + case 0x10123: + return (double) 2000; + case 0x1012C: + return (double) 20000; +#endif + case 0x3251: + return (double) 21; + case 0x3252: + return (double) 22; + case 0x3253: + return (double) 23; + case 0x3254: + return (double) 24; + case 0x3255: + return (double) 25; + case 0x3256: + return (double) 26; + case 0x3257: + return (double) 27; + case 0x3258: + return (double) 28; + case 0x3259: + return (double) 29; + case 0x09F6: + case 0x17F3: + case 0x2162: + case 0x2172: + case 0x3023: + case 0x3194: + case 0x3222: + case 0x3282: +#ifdef Py_UNICODE_WIDE + case 0x10109: +#endif + return (double) 3; + case 0x0F2B: + return (double) 3 / 2; + case 0x00BE: +#ifdef Py_UNICODE_WIDE + case 0x10178: +#endif + return (double) 3 / 4; + case 0x2157: + return (double) 3 / 5; + case 0x215C: + return (double) 3 / 8; + case 0x1374: + case 0x303A: + case 0x325A: +#ifdef Py_UNICODE_WIDE + case 0x10112: + case 0x10165: +#endif + return (double) 30; +#ifdef Py_UNICODE_WIDE + case 0x1011B: + case 0x1016B: + return (double) 300; + case 0x10124: + return (double) 3000; + case 0x1012D: + return (double) 30000; +#endif + case 0x325B: + return (double) 31; + case 0x325C: + return (double) 32; + case 0x325D: + return (double) 33; + case 0x325E: + return (double) 34; + case 0x325F: + return (double) 35; + case 0x32B1: + return (double) 36; + case 0x32B2: + return (double) 37; + case 0x32B3: + return (double) 38; + case 0x32B4: + return (double) 39; + case 0x09F7: + case 0x17F4: + case 0x2163: + case 0x2173: + case 0x3024: + case 0x3195: + case 0x3223: + case 0x3283: +#ifdef Py_UNICODE_WIDE + case 0x1010A: +#endif + return (double) 4; + case 0x2158: + return (double) 4 / 5; + case 0x1375: + case 0x32B5: +#ifdef Py_UNICODE_WIDE + case 0x10113: +#endif + return (double) 40; +#ifdef Py_UNICODE_WIDE + case 0x1011C: + return (double) 400; + case 0x10125: + return (double) 4000; + case 0x1012E: + return (double) 40000; +#endif + case 0x32B6: + return (double) 41; + case 0x32B7: + return (double) 42; + case 0x32B8: + return (double) 43; + case 0x32B9: + return (double) 44; + case 0x32BA: + return (double) 45; + case 0x32BB: + return (double) 46; + case 0x32BC: + return (double) 47; + case 0x32BD: + return (double) 48; + case 0x32BE: + return (double) 49; + case 0x17F5: + case 0x2164: + case 0x2174: + case 0x3025: + case 0x3224: + case 0x3284: +#ifdef Py_UNICODE_WIDE + case 0x1010B: + case 0x10143: + case 0x10148: + case 0x1014F: + case 0x1015F: + case 0x10173: + case 0x10321: +#endif + return (double) 5; + case 0x0F2C: + return (double) 5 / 2; + case 0x215A: + return (double) 5 / 6; + case 0x215D: + return (double) 5 / 8; + case 0x1376: + case 0x216C: + case 0x217C: + case 0x32BF: +#ifdef Py_UNICODE_WIDE + case 0x10114: + case 0x10144: + case 0x1014A: + case 0x10151: + case 0x10166: + case 0x10167: + case 0x10168: + case 0x10169: + case 0x10174: + case 0x10323: +#endif + return (double) 50; + case 0x216E: + case 0x217E: +#ifdef Py_UNICODE_WIDE + case 0x1011D: + case 0x10145: + case 0x1014C: + case 0x10153: + case 0x1016C: + case 0x1016D: + case 0x1016E: + case 0x1016F: + case 0x10170: +#endif + return (double) 500; + case 0x2181: +#ifdef Py_UNICODE_WIDE + case 0x10126: + case 0x10146: + case 0x1014E: + case 0x10172: +#endif + return (double) 5000; +#ifdef Py_UNICODE_WIDE + case 0x1012F: + case 0x10147: + case 0x10156: + return (double) 50000; +#endif + case 0x17F6: + case 0x2165: + case 0x2175: + case 0x3026: + case 0x3225: + case 0x3285: +#ifdef Py_UNICODE_WIDE + case 0x1010C: +#endif + return (double) 6; + case 0x1377: +#ifdef Py_UNICODE_WIDE + case 0x10115: +#endif + return (double) 60; +#ifdef Py_UNICODE_WIDE + case 0x1011E: + return (double) 600; + case 0x10127: + return (double) 6000; + case 0x10130: + return (double) 60000; +#endif + case 0x17F7: + case 0x2166: + case 0x2176: + case 0x3027: + case 0x3226: + case 0x3286: +#ifdef Py_UNICODE_WIDE + case 0x1010D: +#endif + return (double) 7; + case 0x0F2D: + return (double) 7 / 2; + case 0x215E: + return (double) 7 / 8; + case 0x1378: +#ifdef Py_UNICODE_WIDE + case 0x10116: +#endif + return (double) 70; +#ifdef Py_UNICODE_WIDE + case 0x1011F: + return (double) 700; + case 0x10128: + return (double) 7000; + case 0x10131: + return (double) 70000; +#endif + case 0x17F8: + case 0x2167: + case 0x2177: + case 0x3028: + case 0x3227: + case 0x3287: +#ifdef Py_UNICODE_WIDE + case 0x1010E: +#endif + return (double) 8; + case 0x1379: +#ifdef Py_UNICODE_WIDE + case 0x10117: +#endif + return (double) 80; +#ifdef Py_UNICODE_WIDE + case 0x10120: + return (double) 800; + case 0x10129: + return (double) 8000; + case 0x10132: + return (double) 80000; +#endif + case 0x17F9: + case 0x2168: + case 0x2178: + case 0x3029: + case 0x3228: + case 0x3288: +#ifdef Py_UNICODE_WIDE + case 0x1010F: +#endif + return (double) 9; + case 0x0F2E: + return (double) 9 / 2; + case 0x137A: +#ifdef Py_UNICODE_WIDE + case 0x10118: +#endif + return (double) 90; +#ifdef Py_UNICODE_WIDE + case 0x10121: + case 0x1034A: + return (double) 900; + case 0x1012A: + return (double) 9000; + case 0x10133: + return (double) 90000; +#endif + default: + return (double) _PyUnicode_ToDigit(ch); + } +} + +int _PyUnicode_IsNumeric(Py_UNICODE ch) +{ + return _PyUnicode_ToNumeric(ch) != -1.0; +} + +#ifndef WANT_WCTYPE_FUNCTIONS + +/* Returns 1 for Unicode characters having the bidirectional type + 'WS', 'B' or 'S' or the category 'Zs', 0 otherwise. */ + +int _PyUnicode_IsWhitespace(register const Py_UNICODE ch) +{ + switch (ch) { + case 0x0009: /* HORIZONTAL TABULATION */ + case 0x000A: /* LINE FEED */ + case 0x000B: /* VERTICAL TABULATION */ + case 0x000C: /* FORM FEED */ + case 0x000D: /* CARRIAGE RETURN */ + case 0x001C: /* FILE SEPARATOR */ + case 0x001D: /* GROUP SEPARATOR */ + case 0x001E: /* RECORD SEPARATOR */ + case 0x001F: /* UNIT SEPARATOR */ + case 0x0020: /* SPACE */ + case 0x0085: /* NEXT LINE */ + case 0x00A0: /* NO-BREAK SPACE */ + case 0x1680: /* OGHAM SPACE MARK */ + case 0x2000: /* EN QUAD */ + case 0x2001: /* EM QUAD */ + case 0x2002: /* EN SPACE */ + case 0x2003: /* EM SPACE */ + case 0x2004: /* THREE-PER-EM SPACE */ + case 0x2005: /* FOUR-PER-EM SPACE */ + case 0x2006: /* SIX-PER-EM SPACE */ + case 0x2007: /* FIGURE SPACE */ + case 0x2008: /* PUNCTUATION SPACE */ + case 0x2009: /* THIN SPACE */ + case 0x200A: /* HAIR SPACE */ + case 0x200B: /* ZERO WIDTH SPACE */ + case 0x2028: /* LINE SEPARATOR */ + case 0x2029: /* PARAGRAPH SEPARATOR */ + case 0x202F: /* NARROW NO-BREAK SPACE */ + case 0x205F: /* MEDIUM MATHEMATICAL SPACE */ + case 0x3000: /* IDEOGRAPHIC SPACE */ + return 1; + default: + return 0; + } +} + +/* Returns 1 for Unicode characters having the category 'Ll', 0 + otherwise. */ + +int _PyUnicode_IsLowercase(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + + return (ctype->flags & LOWER_MASK) != 0; +} + +/* Returns 1 for Unicode characters having the category 'Lu', 0 + otherwise. */ + +int _PyUnicode_IsUppercase(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + + return (ctype->flags & UPPER_MASK) != 0; +} + +/* Returns the uppercase Unicode characters corresponding to ch or just + ch if no uppercase mapping is known. */ + +Py_UNICODE _PyUnicode_ToUppercase(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + int delta = ctype->upper; + if (delta >= 32768) + delta -= 65536; + return ch + delta; +} + +/* Returns the lowercase Unicode characters corresponding to ch or just + ch if no lowercase mapping is known. */ + +Py_UNICODE _PyUnicode_ToLowercase(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + int delta = ctype->lower; + if (delta >= 32768) + delta -= 65536; + return ch + delta; +} + +/* Returns 1 for Unicode characters having the category 'Ll', 'Lu', 'Lt', + 'Lo' or 'Lm', 0 otherwise. */ + +int _PyUnicode_IsAlpha(Py_UNICODE ch) +{ + const _PyUnicode_TypeRecord *ctype = gettyperecord(ch); + + return (ctype->flags & ALPHA_MASK) != 0; +} + +#else + +/* Export the interfaces using the wchar_t type for portability + reasons: */ + +int _PyUnicode_IsWhitespace(Py_UNICODE ch) +{ + return iswspace(ch); +} + +int _PyUnicode_IsLowercase(Py_UNICODE ch) +{ + return iswlower(ch); +} + +int _PyUnicode_IsUppercase(Py_UNICODE ch) +{ + return iswupper(ch); +} + +Py_UNICODE _PyUnicode_ToLowercase(Py_UNICODE ch) +{ + return towlower(ch); +} + +Py_UNICODE _PyUnicode_ToUppercase(Py_UNICODE ch) +{ + return towupper(ch); +} + +int _PyUnicode_IsAlpha(Py_UNICODE ch) +{ + return iswalpha(ch); +} + +#endif diff --git a/sys/src/cmd/python/Objects/unicodeobject.c b/sys/src/cmd/python/Objects/unicodeobject.c new file mode 100644 index 000000000..00f2018da --- /dev/null +++ b/sys/src/cmd/python/Objects/unicodeobject.c @@ -0,0 +1,8067 @@ +/* + +Unicode implementation based on original code by Fredrik Lundh, +modified by Marc-Andre Lemburg <mal@lemburg.com> according to the +Unicode Integration Proposal (see file Misc/unicode.txt). + +Major speed upgrades to the method implementations at the Reykjavik +NeedForSpeed sprint, by Fredrik Lundh and Andrew Dalke. + +Copyright (c) Corporation for National Research Initiatives. + +-------------------------------------------------------------------- +The original string type implementation is: + + Copyright (c) 1999 by Secret Labs AB + Copyright (c) 1999 by Fredrik Lundh + +By obtaining, using, and/or copying this software and/or its +associated documentation, you agree that you have read, understood, +and will comply with the following terms and conditions: + +Permission to use, copy, modify, and distribute this software and its +associated documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies, and that both that copyright notice and this permission notice +appear in supporting documentation, and that the name of Secret Labs +AB or the author not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR +ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +-------------------------------------------------------------------- + +*/ + +#define PY_SSIZE_T_CLEAN +#include "Python.h" + +#include "unicodeobject.h" +#include "ucnhash.h" + +#ifdef MS_WINDOWS +#include <windows.h> +#endif + +/* Limit for the Unicode object free list */ + +#define MAX_UNICODE_FREELIST_SIZE 1024 + +/* Limit for the Unicode object free list stay alive optimization. + + The implementation will keep allocated Unicode memory intact for + all objects on the free list having a size less than this + limit. This reduces malloc() overhead for small Unicode objects. + + At worst this will result in MAX_UNICODE_FREELIST_SIZE * + (sizeof(PyUnicodeObject) + KEEPALIVE_SIZE_LIMIT + + malloc()-overhead) bytes of unused garbage. + + Setting the limit to 0 effectively turns the feature off. + + Note: This is an experimental feature ! If you get core dumps when + using Unicode objects, turn this feature off. + +*/ + +#define KEEPALIVE_SIZE_LIMIT 9 + +/* Endianness switches; defaults to little endian */ + +#ifdef WORDS_BIGENDIAN +# define BYTEORDER_IS_BIG_ENDIAN +#else +# define BYTEORDER_IS_LITTLE_ENDIAN +#endif + +/* --- Globals ------------------------------------------------------------ + + The globals are initialized by the _PyUnicode_Init() API and should + not be used before calling that API. + +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Free list for Unicode objects */ +static PyUnicodeObject *unicode_freelist; +static int unicode_freelist_size; + +/* The empty Unicode object is shared to improve performance. */ +static PyUnicodeObject *unicode_empty; + +/* Single character Unicode strings in the Latin-1 range are being + shared as well. */ +static PyUnicodeObject *unicode_latin1[256]; + +/* Default encoding to use and assume when NULL is passed as encoding + parameter; it is initialized by _PyUnicode_Init(). + + Always use the PyUnicode_SetDefaultEncoding() and + PyUnicode_GetDefaultEncoding() APIs to access this global. + +*/ +static char unicode_default_encoding[100]; + +Py_UNICODE +PyUnicode_GetMax(void) +{ +#ifdef Py_UNICODE_WIDE + return 0x10FFFF; +#else + /* This is actually an illegal character, so it should + not be passed to unichr. */ + return 0xFFFF; +#endif +} + +/* --- Bloom Filters ----------------------------------------------------- */ + +/* stuff to implement simple "bloom filters" for Unicode characters. + to keep things simple, we use a single bitmask, using the least 5 + bits from each unicode characters as the bit index. */ + +/* the linebreak mask is set up by Unicode_Init below */ + +#define BLOOM_MASK unsigned long + +static BLOOM_MASK bloom_linebreak; + +#define BLOOM(mask, ch) ((mask & (1 << ((ch) & 0x1F)))) + +#define BLOOM_LINEBREAK(ch)\ + (BLOOM(bloom_linebreak, (ch)) && Py_UNICODE_ISLINEBREAK((ch))) + +Py_LOCAL_INLINE(BLOOM_MASK) make_bloom_mask(Py_UNICODE* ptr, Py_ssize_t len) +{ + /* calculate simple bloom-style bitmask for a given unicode string */ + + long mask; + Py_ssize_t i; + + mask = 0; + for (i = 0; i < len; i++) + mask |= (1 << (ptr[i] & 0x1F)); + + return mask; +} + +Py_LOCAL_INLINE(int) unicode_member(Py_UNICODE chr, Py_UNICODE* set, Py_ssize_t setlen) +{ + Py_ssize_t i; + + for (i = 0; i < setlen; i++) + if (set[i] == chr) + return 1; + + return 0; +} + +#define BLOOM_MEMBER(mask, chr, set, setlen)\ + BLOOM(mask, chr) && unicode_member(chr, set, setlen) + +/* --- Unicode Object ----------------------------------------------------- */ + +static +int unicode_resize(register PyUnicodeObject *unicode, + Py_ssize_t length) +{ + void *oldstr; + + /* Shortcut if there's nothing much to do. */ + if (unicode->length == length) + goto reset; + + /* Resizing shared object (unicode_empty or single character + objects) in-place is not allowed. Use PyUnicode_Resize() + instead ! */ + + if (unicode == unicode_empty || + (unicode->length == 1 && + unicode->str[0] < 256U && + unicode_latin1[unicode->str[0]] == unicode)) { + PyErr_SetString(PyExc_SystemError, + "can't resize shared unicode objects"); + return -1; + } + + /* We allocate one more byte to make sure the string is Ux0000 terminated. + The overallocation is also used by fastsearch, which assumes that it's + safe to look at str[length] (without making any assumptions about what + it contains). */ + + oldstr = unicode->str; + PyMem_RESIZE(unicode->str, Py_UNICODE, length + 1); + if (!unicode->str) { + unicode->str = (Py_UNICODE *)oldstr; + PyErr_NoMemory(); + return -1; + } + unicode->str[length] = 0; + unicode->length = length; + + reset: + /* Reset the object caches */ + if (unicode->defenc) { + Py_DECREF(unicode->defenc); + unicode->defenc = NULL; + } + unicode->hash = -1; + + return 0; +} + +/* We allocate one more byte to make sure the string is + Ux0000 terminated -- XXX is this needed ? + + XXX This allocator could further be enhanced by assuring that the + free list never reduces its size below 1. + +*/ + +static +PyUnicodeObject *_PyUnicode_New(Py_ssize_t length) +{ + register PyUnicodeObject *unicode; + + /* Optimization for empty strings */ + if (length == 0 && unicode_empty != NULL) { + Py_INCREF(unicode_empty); + return unicode_empty; + } + + /* Unicode freelist & memory allocation */ + if (unicode_freelist) { + unicode = unicode_freelist; + unicode_freelist = *(PyUnicodeObject **)unicode; + unicode_freelist_size--; + if (unicode->str) { + /* Keep-Alive optimization: we only upsize the buffer, + never downsize it. */ + if ((unicode->length < length) && + unicode_resize(unicode, length) < 0) { + PyMem_DEL(unicode->str); + goto onError; + } + } + else { + unicode->str = PyMem_NEW(Py_UNICODE, length + 1); + } + PyObject_INIT(unicode, &PyUnicode_Type); + } + else { + unicode = PyObject_New(PyUnicodeObject, &PyUnicode_Type); + if (unicode == NULL) + return NULL; + unicode->str = PyMem_NEW(Py_UNICODE, length + 1); + } + + if (!unicode->str) { + PyErr_NoMemory(); + goto onError; + } + /* Initialize the first element to guard against cases where + * the caller fails before initializing str -- unicode_resize() + * reads str[0], and the Keep-Alive optimization can keep memory + * allocated for str alive across a call to unicode_dealloc(unicode). + * We don't want unicode_resize to read uninitialized memory in + * that case. + */ + unicode->str[0] = 0; + unicode->str[length] = 0; + unicode->length = length; + unicode->hash = -1; + unicode->defenc = NULL; + return unicode; + + onError: + _Py_ForgetReference((PyObject *)unicode); + PyObject_Del(unicode); + return NULL; +} + +static +void unicode_dealloc(register PyUnicodeObject *unicode) +{ + if (PyUnicode_CheckExact(unicode) && + unicode_freelist_size < MAX_UNICODE_FREELIST_SIZE) { + /* Keep-Alive optimization */ + if (unicode->length >= KEEPALIVE_SIZE_LIMIT) { + PyMem_DEL(unicode->str); + unicode->str = NULL; + unicode->length = 0; + } + if (unicode->defenc) { + Py_DECREF(unicode->defenc); + unicode->defenc = NULL; + } + /* Add to free list */ + *(PyUnicodeObject **)unicode = unicode_freelist; + unicode_freelist = unicode; + unicode_freelist_size++; + } + else { + PyMem_DEL(unicode->str); + Py_XDECREF(unicode->defenc); + unicode->ob_type->tp_free((PyObject *)unicode); + } +} + +int PyUnicode_Resize(PyObject **unicode, Py_ssize_t length) +{ + register PyUnicodeObject *v; + + /* Argument checks */ + if (unicode == NULL) { + PyErr_BadInternalCall(); + return -1; + } + v = (PyUnicodeObject *)*unicode; + if (v == NULL || !PyUnicode_Check(v) || v->ob_refcnt != 1 || length < 0) { + PyErr_BadInternalCall(); + return -1; + } + + /* Resizing unicode_empty and single character objects is not + possible since these are being shared. We simply return a fresh + copy with the same Unicode content. */ + if (v->length != length && + (v == unicode_empty || v->length == 1)) { + PyUnicodeObject *w = _PyUnicode_New(length); + if (w == NULL) + return -1; + Py_UNICODE_COPY(w->str, v->str, + length < v->length ? length : v->length); + Py_DECREF(*unicode); + *unicode = (PyObject *)w; + return 0; + } + + /* Note that we don't have to modify *unicode for unshared Unicode + objects, since we can modify them in-place. */ + return unicode_resize(v, length); +} + +/* Internal API for use in unicodeobject.c only ! */ +#define _PyUnicode_Resize(unicodevar, length) \ + PyUnicode_Resize(((PyObject **)(unicodevar)), length) + +PyObject *PyUnicode_FromUnicode(const Py_UNICODE *u, + Py_ssize_t size) +{ + PyUnicodeObject *unicode; + + /* If the Unicode data is known at construction time, we can apply + some optimizations which share commonly used objects. */ + if (u != NULL) { + + /* Optimization for empty strings */ + if (size == 0 && unicode_empty != NULL) { + Py_INCREF(unicode_empty); + return (PyObject *)unicode_empty; + } + + /* Single character Unicode objects in the Latin-1 range are + shared when using this constructor */ + if (size == 1 && *u < 256) { + unicode = unicode_latin1[*u]; + if (!unicode) { + unicode = _PyUnicode_New(1); + if (!unicode) + return NULL; + unicode->str[0] = *u; + unicode_latin1[*u] = unicode; + } + Py_INCREF(unicode); + return (PyObject *)unicode; + } + } + + unicode = _PyUnicode_New(size); + if (!unicode) + return NULL; + + /* Copy the Unicode data into the new object */ + if (u != NULL) + Py_UNICODE_COPY(unicode->str, u, size); + + return (PyObject *)unicode; +} + +#ifdef HAVE_WCHAR_H + +PyObject *PyUnicode_FromWideChar(register const wchar_t *w, + Py_ssize_t size) +{ + PyUnicodeObject *unicode; + + if (w == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + + unicode = _PyUnicode_New(size); + if (!unicode) + return NULL; + + /* Copy the wchar_t data into the new object */ +#ifdef HAVE_USABLE_WCHAR_T + memcpy(unicode->str, w, size * sizeof(wchar_t)); +#else + { + register Py_UNICODE *u; + register Py_ssize_t i; + u = PyUnicode_AS_UNICODE(unicode); + for (i = size; i > 0; i--) + *u++ = *w++; + } +#endif + + return (PyObject *)unicode; +} + +Py_ssize_t PyUnicode_AsWideChar(PyUnicodeObject *unicode, + wchar_t *w, + Py_ssize_t size) +{ + if (unicode == NULL) { + PyErr_BadInternalCall(); + return -1; + } + + /* If possible, try to copy the 0-termination as well */ + if (size > PyUnicode_GET_SIZE(unicode)) + size = PyUnicode_GET_SIZE(unicode) + 1; + +#ifdef HAVE_USABLE_WCHAR_T + memcpy(w, unicode->str, size * sizeof(wchar_t)); +#else + { + register Py_UNICODE *u; + register Py_ssize_t i; + u = PyUnicode_AS_UNICODE(unicode); + for (i = size; i > 0; i--) + *w++ = *u++; + } +#endif + + if (size > PyUnicode_GET_SIZE(unicode)) + return PyUnicode_GET_SIZE(unicode); + else + return size; +} + +#endif + +PyObject *PyUnicode_FromOrdinal(int ordinal) +{ + Py_UNICODE s[1]; + +#ifdef Py_UNICODE_WIDE + if (ordinal < 0 || ordinal > 0x10ffff) { + PyErr_SetString(PyExc_ValueError, + "unichr() arg not in range(0x110000) " + "(wide Python build)"); + return NULL; + } +#else + if (ordinal < 0 || ordinal > 0xffff) { + PyErr_SetString(PyExc_ValueError, + "unichr() arg not in range(0x10000) " + "(narrow Python build)"); + return NULL; + } +#endif + + s[0] = (Py_UNICODE)ordinal; + return PyUnicode_FromUnicode(s, 1); +} + +PyObject *PyUnicode_FromObject(register PyObject *obj) +{ + /* XXX Perhaps we should make this API an alias of + PyObject_Unicode() instead ?! */ + if (PyUnicode_CheckExact(obj)) { + Py_INCREF(obj); + return obj; + } + if (PyUnicode_Check(obj)) { + /* For a Unicode subtype that's not a Unicode object, + return a true Unicode object with the same data. */ + return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(obj), + PyUnicode_GET_SIZE(obj)); + } + return PyUnicode_FromEncodedObject(obj, NULL, "strict"); +} + +PyObject *PyUnicode_FromEncodedObject(register PyObject *obj, + const char *encoding, + const char *errors) +{ + const char *s = NULL; + Py_ssize_t len; + PyObject *v; + + if (obj == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + +#if 0 + /* For b/w compatibility we also accept Unicode objects provided + that no encodings is given and then redirect to + PyObject_Unicode() which then applies the additional logic for + Unicode subclasses. + + NOTE: This API should really only be used for object which + represent *encoded* Unicode ! + + */ + if (PyUnicode_Check(obj)) { + if (encoding) { + PyErr_SetString(PyExc_TypeError, + "decoding Unicode is not supported"); + return NULL; + } + return PyObject_Unicode(obj); + } +#else + if (PyUnicode_Check(obj)) { + PyErr_SetString(PyExc_TypeError, + "decoding Unicode is not supported"); + return NULL; + } +#endif + + /* Coerce object */ + if (PyString_Check(obj)) { + s = PyString_AS_STRING(obj); + len = PyString_GET_SIZE(obj); + } + else if (PyObject_AsCharBuffer(obj, &s, &len)) { + /* Overwrite the error message with something more useful in + case of a TypeError. */ + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "coercing to Unicode: need string or buffer, " + "%.80s found", + obj->ob_type->tp_name); + goto onError; + } + + /* Convert to Unicode */ + if (len == 0) { + Py_INCREF(unicode_empty); + v = (PyObject *)unicode_empty; + } + else + v = PyUnicode_Decode(s, len, encoding, errors); + + return v; + + onError: + return NULL; +} + +PyObject *PyUnicode_Decode(const char *s, + Py_ssize_t size, + const char *encoding, + const char *errors) +{ + PyObject *buffer = NULL, *unicode; + + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); + + /* Shortcuts for common default encodings */ + if (strcmp(encoding, "utf-8") == 0) + return PyUnicode_DecodeUTF8(s, size, errors); + else if (strcmp(encoding, "latin-1") == 0) + return PyUnicode_DecodeLatin1(s, size, errors); +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) + else if (strcmp(encoding, "mbcs") == 0) + return PyUnicode_DecodeMBCS(s, size, errors); +#endif + else if (strcmp(encoding, "ascii") == 0) + return PyUnicode_DecodeASCII(s, size, errors); + + /* Decode via the codec registry */ + buffer = PyBuffer_FromMemory((void *)s, size); + if (buffer == NULL) + goto onError; + unicode = PyCodec_Decode(buffer, encoding, errors); + if (unicode == NULL) + goto onError; + if (!PyUnicode_Check(unicode)) { + PyErr_Format(PyExc_TypeError, + "decoder did not return an unicode object (type=%.400s)", + unicode->ob_type->tp_name); + Py_DECREF(unicode); + goto onError; + } + Py_DECREF(buffer); + return unicode; + + onError: + Py_XDECREF(buffer); + return NULL; +} + +PyObject *PyUnicode_AsDecodedObject(PyObject *unicode, + const char *encoding, + const char *errors) +{ + PyObject *v; + + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + goto onError; + } + + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); + + /* Decode via the codec registry */ + v = PyCodec_Decode(unicode, encoding, errors); + if (v == NULL) + goto onError; + return v; + + onError: + return NULL; +} + +PyObject *PyUnicode_Encode(const Py_UNICODE *s, + Py_ssize_t size, + const char *encoding, + const char *errors) +{ + PyObject *v, *unicode; + + unicode = PyUnicode_FromUnicode(s, size); + if (unicode == NULL) + return NULL; + v = PyUnicode_AsEncodedString(unicode, encoding, errors); + Py_DECREF(unicode); + return v; +} + +PyObject *PyUnicode_AsEncodedObject(PyObject *unicode, + const char *encoding, + const char *errors) +{ + PyObject *v; + + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + goto onError; + } + + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); + + /* Encode via the codec registry */ + v = PyCodec_Encode(unicode, encoding, errors); + if (v == NULL) + goto onError; + return v; + + onError: + return NULL; +} + +PyObject *PyUnicode_AsEncodedString(PyObject *unicode, + const char *encoding, + const char *errors) +{ + PyObject *v; + + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + goto onError; + } + + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); + + /* Shortcuts for common default encodings */ + if (errors == NULL) { + if (strcmp(encoding, "utf-8") == 0) + return PyUnicode_AsUTF8String(unicode); + else if (strcmp(encoding, "latin-1") == 0) + return PyUnicode_AsLatin1String(unicode); +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) + else if (strcmp(encoding, "mbcs") == 0) + return PyUnicode_AsMBCSString(unicode); +#endif + else if (strcmp(encoding, "ascii") == 0) + return PyUnicode_AsASCIIString(unicode); + } + + /* Encode via the codec registry */ + v = PyCodec_Encode(unicode, encoding, errors); + if (v == NULL) + goto onError; + if (!PyString_Check(v)) { + PyErr_Format(PyExc_TypeError, + "encoder did not return a string object (type=%.400s)", + v->ob_type->tp_name); + Py_DECREF(v); + goto onError; + } + return v; + + onError: + return NULL; +} + +PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode, + const char *errors) +{ + PyObject *v = ((PyUnicodeObject *)unicode)->defenc; + + if (v) + return v; + v = PyUnicode_AsEncodedString(unicode, NULL, errors); + if (v && errors == NULL) + ((PyUnicodeObject *)unicode)->defenc = v; + return v; +} + +Py_UNICODE *PyUnicode_AsUnicode(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + goto onError; + } + return PyUnicode_AS_UNICODE(unicode); + + onError: + return NULL; +} + +Py_ssize_t PyUnicode_GetSize(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + goto onError; + } + return PyUnicode_GET_SIZE(unicode); + + onError: + return -1; +} + +const char *PyUnicode_GetDefaultEncoding(void) +{ + return unicode_default_encoding; +} + +int PyUnicode_SetDefaultEncoding(const char *encoding) +{ + PyObject *v; + + /* Make sure the encoding is valid. As side effect, this also + loads the encoding into the codec registry cache. */ + v = _PyCodec_Lookup(encoding); + if (v == NULL) + goto onError; + Py_DECREF(v); + strncpy(unicode_default_encoding, + encoding, + sizeof(unicode_default_encoding)); + return 0; + + onError: + return -1; +} + +/* error handling callback helper: + build arguments, call the callback and check the arguments, + if no exception occurred, copy the replacement to the output + and adjust various state variables. + return 0 on success, -1 on error +*/ + +static +int unicode_decode_call_errorhandler(const char *errors, PyObject **errorHandler, + const char *encoding, const char *reason, + const char *input, Py_ssize_t insize, Py_ssize_t *startinpos, Py_ssize_t *endinpos, PyObject **exceptionObject, const char **inptr, + PyObject **output, Py_ssize_t *outpos, Py_UNICODE **outptr) +{ + static char *argparse = "O!n;decoding error handler must return (unicode, int) tuple"; + + PyObject *restuple = NULL; + PyObject *repunicode = NULL; + Py_ssize_t outsize = PyUnicode_GET_SIZE(*output); + Py_ssize_t requiredsize; + Py_ssize_t newpos; + Py_UNICODE *repptr; + Py_ssize_t repsize; + int res = -1; + + if (*errorHandler == NULL) { + *errorHandler = PyCodec_LookupError(errors); + if (*errorHandler == NULL) + goto onError; + } + + if (*exceptionObject == NULL) { + *exceptionObject = PyUnicodeDecodeError_Create( + encoding, input, insize, *startinpos, *endinpos, reason); + if (*exceptionObject == NULL) + goto onError; + } + else { + if (PyUnicodeDecodeError_SetStart(*exceptionObject, *startinpos)) + goto onError; + if (PyUnicodeDecodeError_SetEnd(*exceptionObject, *endinpos)) + goto onError; + if (PyUnicodeDecodeError_SetReason(*exceptionObject, reason)) + goto onError; + } + + restuple = PyObject_CallFunctionObjArgs(*errorHandler, *exceptionObject, NULL); + if (restuple == NULL) + goto onError; + if (!PyTuple_Check(restuple)) { + PyErr_Format(PyExc_TypeError, &argparse[4]); + goto onError; + } + if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &repunicode, &newpos)) + goto onError; + if (newpos<0) + newpos = insize+newpos; + if (newpos<0 || newpos>insize) { + PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", newpos); + goto onError; + } + + /* need more space? (at least enough for what we + have+the replacement+the rest of the string (starting + at the new input position), so we won't have to check space + when there are no errors in the rest of the string) */ + repptr = PyUnicode_AS_UNICODE(repunicode); + repsize = PyUnicode_GET_SIZE(repunicode); + requiredsize = *outpos + repsize + insize-newpos; + if (requiredsize > outsize) { + if (requiredsize<2*outsize) + requiredsize = 2*outsize; + if (PyUnicode_Resize(output, requiredsize) < 0) + goto onError; + *outptr = PyUnicode_AS_UNICODE(*output) + *outpos; + } + *endinpos = newpos; + *inptr = input + newpos; + Py_UNICODE_COPY(*outptr, repptr, repsize); + *outptr += repsize; + *outpos += repsize; + /* we made it! */ + res = 0; + + onError: + Py_XDECREF(restuple); + return res; +} + +/* --- UTF-7 Codec -------------------------------------------------------- */ + +/* see RFC2152 for details */ + +static +char utf7_special[128] = { + /* indicate whether a UTF-7 character is special i.e. cannot be directly + encoded: + 0 - not special + 1 - special + 2 - whitespace (optional) + 3 - RFC2152 Set O (optional) */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 1, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 3, 3, 3, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 1, 1, + +}; + +/* Note: The comparison (c) <= 0 is a trick to work-around gcc + warnings about the comparison always being false; since + utf7_special[0] is 1, we can safely make that one comparison + true */ + +#define SPECIAL(c, encodeO, encodeWS) \ + ((c) > 127 || (c) <= 0 || utf7_special[(c)] == 1 || \ + (encodeWS && (utf7_special[(c)] == 2)) || \ + (encodeO && (utf7_special[(c)] == 3))) + +#define B64(n) \ + ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(n) & 0x3f]) +#define B64CHAR(c) \ + (isalnum(c) || (c) == '+' || (c) == '/') +#define UB64(c) \ + ((c) == '+' ? 62 : (c) == '/' ? 63 : (c) >= 'a' ? \ + (c) - 71 : (c) >= 'A' ? (c) - 65 : (c) + 4 ) + +#define ENCODE(out, ch, bits) \ + while (bits >= 6) { \ + *out++ = B64(ch >> (bits-6)); \ + bits -= 6; \ + } + +#define DECODE(out, ch, bits, surrogate) \ + while (bits >= 16) { \ + Py_UNICODE outCh = (Py_UNICODE) ((ch >> (bits-16)) & 0xffff); \ + bits -= 16; \ + if (surrogate) { \ + /* We have already generated an error for the high surrogate \ + so let's not bother seeing if the low surrogate is correct or not */ \ + surrogate = 0; \ + } else if (0xDC00 <= outCh && outCh <= 0xDFFF) { \ + /* This is a surrogate pair. Unfortunately we can't represent \ + it in a 16-bit character */ \ + surrogate = 1; \ + errmsg = "code pairs are not supported"; \ + goto utf7Error; \ + } else { \ + *out++ = outCh; \ + } \ + } + +PyObject *PyUnicode_DecodeUTF7(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *starts = s; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + const char *e; + PyUnicodeObject *unicode; + Py_UNICODE *p; + const char *errmsg = ""; + int inShift = 0; + unsigned int bitsleft = 0; + unsigned long charsleft = 0; + int surrogate = 0; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + unicode = _PyUnicode_New(size); + if (!unicode) + return NULL; + if (size == 0) + return (PyObject *)unicode; + + p = unicode->str; + e = s + size; + + while (s < e) { + Py_UNICODE ch; + restart: + ch = *s; + + if (inShift) { + if ((ch == '-') || !B64CHAR(ch)) { + inShift = 0; + s++; + + /* p, charsleft, bitsleft, surrogate = */ DECODE(p, charsleft, bitsleft, surrogate); + if (bitsleft >= 6) { + /* The shift sequence has a partial character in it. If + bitsleft < 6 then we could just classify it as padding + but that is not the case here */ + + errmsg = "partial character in shift sequence"; + goto utf7Error; + } + /* According to RFC2152 the remaining bits should be zero. We + choose to signal an error/insert a replacement character + here so indicate the potential of a misencoded character. */ + + /* On x86, a << b == a << (b%32) so make sure that bitsleft != 0 */ + if (bitsleft && charsleft << (sizeof(charsleft) * 8 - bitsleft)) { + errmsg = "non-zero padding bits in shift sequence"; + goto utf7Error; + } + + if (ch == '-') { + if ((s < e) && (*(s) == '-')) { + *p++ = '-'; + inShift = 1; + } + } else if (SPECIAL(ch,0,0)) { + errmsg = "unexpected special character"; + goto utf7Error; + } else { + *p++ = ch; + } + } else { + charsleft = (charsleft << 6) | UB64(ch); + bitsleft += 6; + s++; + /* p, charsleft, bitsleft, surrogate = */ DECODE(p, charsleft, bitsleft, surrogate); + } + } + else if ( ch == '+' ) { + startinpos = s-starts; + s++; + if (s < e && *s == '-') { + s++; + *p++ = '+'; + } else + { + inShift = 1; + bitsleft = 0; + } + } + else if (SPECIAL(ch,0,0)) { + errmsg = "unexpected special character"; + s++; + goto utf7Error; + } + else { + *p++ = ch; + s++; + } + continue; + utf7Error: + outpos = p-PyUnicode_AS_UNICODE(unicode); + endinpos = s-starts; + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "utf7", errmsg, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&unicode, &outpos, &p)) + goto onError; + } + + if (inShift) { + outpos = p-PyUnicode_AS_UNICODE(unicode); + endinpos = size; + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "utf7", "unterminated shift sequence", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&unicode, &outpos, &p)) + goto onError; + if (s < e) + goto restart; + } + + if (_PyUnicode_Resize(&unicode, p - PyUnicode_AS_UNICODE(unicode)) < 0) + goto onError; + + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)unicode; + +onError: + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + Py_DECREF(unicode); + return NULL; +} + + +PyObject *PyUnicode_EncodeUTF7(const Py_UNICODE *s, + Py_ssize_t size, + int encodeSetO, + int encodeWhiteSpace, + const char *errors) +{ + PyObject *v; + /* It might be possible to tighten this worst case */ + Py_ssize_t cbAllocated = 5 * size; + int inShift = 0; + Py_ssize_t i = 0; + unsigned int bitsleft = 0; + unsigned long charsleft = 0; + char * out; + char * start; + + if (size == 0) + return PyString_FromStringAndSize(NULL, 0); + + v = PyString_FromStringAndSize(NULL, cbAllocated); + if (v == NULL) + return NULL; + + start = out = PyString_AS_STRING(v); + for (;i < size; ++i) { + Py_UNICODE ch = s[i]; + + if (!inShift) { + if (ch == '+') { + *out++ = '+'; + *out++ = '-'; + } else if (SPECIAL(ch, encodeSetO, encodeWhiteSpace)) { + charsleft = ch; + bitsleft = 16; + *out++ = '+'; + /* out, charsleft, bitsleft = */ ENCODE(out, charsleft, bitsleft); + inShift = bitsleft > 0; + } else { + *out++ = (char) ch; + } + } else { + if (!SPECIAL(ch, encodeSetO, encodeWhiteSpace)) { + *out++ = B64(charsleft << (6-bitsleft)); + charsleft = 0; + bitsleft = 0; + /* Characters not in the BASE64 set implicitly unshift the sequence + so no '-' is required, except if the character is itself a '-' */ + if (B64CHAR(ch) || ch == '-') { + *out++ = '-'; + } + inShift = 0; + *out++ = (char) ch; + } else { + bitsleft += 16; + charsleft = (charsleft << 16) | ch; + /* out, charsleft, bitsleft = */ ENCODE(out, charsleft, bitsleft); + + /* If the next character is special then we dont' need to terminate + the shift sequence. If the next character is not a BASE64 character + or '-' then the shift sequence will be terminated implicitly and we + don't have to insert a '-'. */ + + if (bitsleft == 0) { + if (i + 1 < size) { + Py_UNICODE ch2 = s[i+1]; + + if (SPECIAL(ch2, encodeSetO, encodeWhiteSpace)) { + + } else if (B64CHAR(ch2) || ch2 == '-') { + *out++ = '-'; + inShift = 0; + } else { + inShift = 0; + } + + } + else { + *out++ = '-'; + inShift = 0; + } + } + } + } + } + if (bitsleft) { + *out++= B64(charsleft << (6-bitsleft) ); + *out++ = '-'; + } + + _PyString_Resize(&v, out - start); + return v; +} + +#undef SPECIAL +#undef B64 +#undef B64CHAR +#undef UB64 +#undef ENCODE +#undef DECODE + +/* --- UTF-8 Codec -------------------------------------------------------- */ + +static +char utf8_code_length[256] = { + /* Map UTF-8 encoded prefix byte to sequence length. zero means + illegal prefix. see RFC 2279 for details */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0 +}; + +PyObject *PyUnicode_DecodeUTF8(const char *s, + Py_ssize_t size, + const char *errors) +{ + return PyUnicode_DecodeUTF8Stateful(s, size, errors, NULL); +} + +PyObject *PyUnicode_DecodeUTF8Stateful(const char *s, + Py_ssize_t size, + const char *errors, + Py_ssize_t *consumed) +{ + const char *starts = s; + int n; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + const char *e; + PyUnicodeObject *unicode; + Py_UNICODE *p; + const char *errmsg = ""; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + /* Note: size will always be longer than the resulting Unicode + character count */ + unicode = _PyUnicode_New(size); + if (!unicode) + return NULL; + if (size == 0) { + if (consumed) + *consumed = 0; + return (PyObject *)unicode; + } + + /* Unpack UTF-8 encoded data */ + p = unicode->str; + e = s + size; + + while (s < e) { + Py_UCS4 ch = (unsigned char)*s; + + if (ch < 0x80) { + *p++ = (Py_UNICODE)ch; + s++; + continue; + } + + n = utf8_code_length[ch]; + + if (s + n > e) { + if (consumed) + break; + else { + errmsg = "unexpected end of data"; + startinpos = s-starts; + endinpos = size; + goto utf8Error; + } + } + + switch (n) { + + case 0: + errmsg = "unexpected code byte"; + startinpos = s-starts; + endinpos = startinpos+1; + goto utf8Error; + + case 1: + errmsg = "internal error"; + startinpos = s-starts; + endinpos = startinpos+1; + goto utf8Error; + + case 2: + if ((s[1] & 0xc0) != 0x80) { + errmsg = "invalid data"; + startinpos = s-starts; + endinpos = startinpos+2; + goto utf8Error; + } + ch = ((s[0] & 0x1f) << 6) + (s[1] & 0x3f); + if (ch < 0x80) { + startinpos = s-starts; + endinpos = startinpos+2; + errmsg = "illegal encoding"; + goto utf8Error; + } + else + *p++ = (Py_UNICODE)ch; + break; + + case 3: + if ((s[1] & 0xc0) != 0x80 || + (s[2] & 0xc0) != 0x80) { + errmsg = "invalid data"; + startinpos = s-starts; + endinpos = startinpos+3; + goto utf8Error; + } + ch = ((s[0] & 0x0f) << 12) + ((s[1] & 0x3f) << 6) + (s[2] & 0x3f); + if (ch < 0x0800) { + /* Note: UTF-8 encodings of surrogates are considered + legal UTF-8 sequences; + + XXX For wide builds (UCS-4) we should probably try + to recombine the surrogates into a single code + unit. + */ + errmsg = "illegal encoding"; + startinpos = s-starts; + endinpos = startinpos+3; + goto utf8Error; + } + else + *p++ = (Py_UNICODE)ch; + break; + + case 4: + if ((s[1] & 0xc0) != 0x80 || + (s[2] & 0xc0) != 0x80 || + (s[3] & 0xc0) != 0x80) { + errmsg = "invalid data"; + startinpos = s-starts; + endinpos = startinpos+4; + goto utf8Error; + } + ch = ((s[0] & 0x7) << 18) + ((s[1] & 0x3f) << 12) + + ((s[2] & 0x3f) << 6) + (s[3] & 0x3f); + /* validate and convert to UTF-16 */ + if ((ch < 0x10000) /* minimum value allowed for 4 + byte encoding */ + || (ch > 0x10ffff)) /* maximum value allowed for + UTF-16 */ + { + errmsg = "illegal encoding"; + startinpos = s-starts; + endinpos = startinpos+4; + goto utf8Error; + } +#ifdef Py_UNICODE_WIDE + *p++ = (Py_UNICODE)ch; +#else + /* compute and append the two surrogates: */ + + /* translate from 10000..10FFFF to 0..FFFF */ + ch -= 0x10000; + + /* high surrogate = top 10 bits added to D800 */ + *p++ = (Py_UNICODE)(0xD800 + (ch >> 10)); + + /* low surrogate = bottom 10 bits added to DC00 */ + *p++ = (Py_UNICODE)(0xDC00 + (ch & 0x03FF)); +#endif + break; + + default: + /* Other sizes are only needed for UCS-4 */ + errmsg = "unsupported Unicode code range"; + startinpos = s-starts; + endinpos = startinpos+n; + goto utf8Error; + } + s += n; + continue; + + utf8Error: + outpos = p-PyUnicode_AS_UNICODE(unicode); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "utf8", errmsg, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&unicode, &outpos, &p)) + goto onError; + } + if (consumed) + *consumed = s-starts; + + /* Adjust length */ + if (_PyUnicode_Resize(&unicode, p - unicode->str) < 0) + goto onError; + + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)unicode; + +onError: + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + Py_DECREF(unicode); + return NULL; +} + +/* Allocation strategy: if the string is short, convert into a stack buffer + and allocate exactly as much space needed at the end. Else allocate the + maximum possible needed (4 result bytes per Unicode character), and return + the excess memory at the end. +*/ +PyObject * +PyUnicode_EncodeUTF8(const Py_UNICODE *s, + Py_ssize_t size, + const char *errors) +{ +#define MAX_SHORT_UNICHARS 300 /* largest size we'll do on the stack */ + + Py_ssize_t i; /* index into s of next input byte */ + PyObject *v; /* result string object */ + char *p; /* next free byte in output buffer */ + Py_ssize_t nallocated; /* number of result bytes allocated */ + Py_ssize_t nneeded; /* number of result bytes needed */ + char stackbuf[MAX_SHORT_UNICHARS * 4]; + + assert(s != NULL); + assert(size >= 0); + + if (size <= MAX_SHORT_UNICHARS) { + /* Write into the stack buffer; nallocated can't overflow. + * At the end, we'll allocate exactly as much heap space as it + * turns out we need. + */ + nallocated = Py_SAFE_DOWNCAST(sizeof(stackbuf), size_t, int); + v = NULL; /* will allocate after we're done */ + p = stackbuf; + } + else { + /* Overallocate on the heap, and give the excess back at the end. */ + nallocated = size * 4; + if (nallocated / 4 != size) /* overflow! */ + return PyErr_NoMemory(); + v = PyString_FromStringAndSize(NULL, nallocated); + if (v == NULL) + return NULL; + p = PyString_AS_STRING(v); + } + + for (i = 0; i < size;) { + Py_UCS4 ch = s[i++]; + + if (ch < 0x80) + /* Encode ASCII */ + *p++ = (char) ch; + + else if (ch < 0x0800) { + /* Encode Latin-1 */ + *p++ = (char)(0xc0 | (ch >> 6)); + *p++ = (char)(0x80 | (ch & 0x3f)); + } + else { + /* Encode UCS2 Unicode ordinals */ + if (ch < 0x10000) { + /* Special case: check for high surrogate */ + if (0xD800 <= ch && ch <= 0xDBFF && i != size) { + Py_UCS4 ch2 = s[i]; + /* Check for low surrogate and combine the two to + form a UCS4 value */ + if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { + ch = ((ch - 0xD800) << 10 | (ch2 - 0xDC00)) + 0x10000; + i++; + goto encodeUCS4; + } + /* Fall through: handles isolated high surrogates */ + } + *p++ = (char)(0xe0 | (ch >> 12)); + *p++ = (char)(0x80 | ((ch >> 6) & 0x3f)); + *p++ = (char)(0x80 | (ch & 0x3f)); + continue; + } +encodeUCS4: + /* Encode UCS4 Unicode ordinals */ + *p++ = (char)(0xf0 | (ch >> 18)); + *p++ = (char)(0x80 | ((ch >> 12) & 0x3f)); + *p++ = (char)(0x80 | ((ch >> 6) & 0x3f)); + *p++ = (char)(0x80 | (ch & 0x3f)); + } + } + + if (v == NULL) { + /* This was stack allocated. */ + nneeded = p - stackbuf; + assert(nneeded <= nallocated); + v = PyString_FromStringAndSize(stackbuf, nneeded); + } + else { + /* Cut back to size actually needed. */ + nneeded = p - PyString_AS_STRING(v); + assert(nneeded <= nallocated); + _PyString_Resize(&v, nneeded); + } + return v; + +#undef MAX_SHORT_UNICHARS +} + +PyObject *PyUnicode_AsUTF8String(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode), + NULL); +} + +/* --- UTF-16 Codec ------------------------------------------------------- */ + +PyObject * +PyUnicode_DecodeUTF16(const char *s, + Py_ssize_t size, + const char *errors, + int *byteorder) +{ + return PyUnicode_DecodeUTF16Stateful(s, size, errors, byteorder, NULL); +} + +PyObject * +PyUnicode_DecodeUTF16Stateful(const char *s, + Py_ssize_t size, + const char *errors, + int *byteorder, + Py_ssize_t *consumed) +{ + const char *starts = s; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + PyUnicodeObject *unicode; + Py_UNICODE *p; + const unsigned char *q, *e; + int bo = 0; /* assume native ordering by default */ + const char *errmsg = ""; + /* Offsets from q for retrieving byte pairs in the right order. */ +#ifdef BYTEORDER_IS_LITTLE_ENDIAN + int ihi = 1, ilo = 0; +#else + int ihi = 0, ilo = 1; +#endif + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + /* Note: size will always be longer than the resulting Unicode + character count */ + unicode = _PyUnicode_New(size); + if (!unicode) + return NULL; + if (size == 0) + return (PyObject *)unicode; + + /* Unpack UTF-16 encoded data */ + p = unicode->str; + q = (unsigned char *)s; + e = q + size; + + if (byteorder) + bo = *byteorder; + + /* Check for BOM marks (U+FEFF) in the input and adjust current + byte order setting accordingly. In native mode, the leading BOM + mark is skipped, in all other modes, it is copied to the output + stream as-is (giving a ZWNBSP character). */ + if (bo == 0) { + if (size >= 2) { + const Py_UNICODE bom = (q[ihi] << 8) | q[ilo]; +#ifdef BYTEORDER_IS_LITTLE_ENDIAN + if (bom == 0xFEFF) { + q += 2; + bo = -1; + } + else if (bom == 0xFFFE) { + q += 2; + bo = 1; + } +#else + if (bom == 0xFEFF) { + q += 2; + bo = 1; + } + else if (bom == 0xFFFE) { + q += 2; + bo = -1; + } +#endif + } + } + + if (bo == -1) { + /* force LE */ + ihi = 1; + ilo = 0; + } + else if (bo == 1) { + /* force BE */ + ihi = 0; + ilo = 1; + } + + while (q < e) { + Py_UNICODE ch; + /* remaining bytes at the end? (size should be even) */ + if (e-q<2) { + if (consumed) + break; + errmsg = "truncated data"; + startinpos = ((const char *)q)-starts; + endinpos = ((const char *)e)-starts; + goto utf16Error; + /* The remaining input chars are ignored if the callback + chooses to skip the input */ + } + ch = (q[ihi] << 8) | q[ilo]; + + q += 2; + + if (ch < 0xD800 || ch > 0xDFFF) { + *p++ = ch; + continue; + } + + /* UTF-16 code pair: */ + if (q >= e) { + errmsg = "unexpected end of data"; + startinpos = (((const char *)q)-2)-starts; + endinpos = ((const char *)e)-starts; + goto utf16Error; + } + if (0xD800 <= ch && ch <= 0xDBFF) { + Py_UNICODE ch2 = (q[ihi] << 8) | q[ilo]; + q += 2; + if (0xDC00 <= ch2 && ch2 <= 0xDFFF) { +#ifndef Py_UNICODE_WIDE + *p++ = ch; + *p++ = ch2; +#else + *p++ = (((ch & 0x3FF)<<10) | (ch2 & 0x3FF)) + 0x10000; +#endif + continue; + } + else { + errmsg = "illegal UTF-16 surrogate"; + startinpos = (((const char *)q)-4)-starts; + endinpos = startinpos+2; + goto utf16Error; + } + + } + errmsg = "illegal encoding"; + startinpos = (((const char *)q)-2)-starts; + endinpos = startinpos+2; + /* Fall through to report the error */ + + utf16Error: + outpos = p-PyUnicode_AS_UNICODE(unicode); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "utf16", errmsg, + starts, size, &startinpos, &endinpos, &exc, (const char **)&q, + (PyObject **)&unicode, &outpos, &p)) + goto onError; + } + + if (byteorder) + *byteorder = bo; + + if (consumed) + *consumed = (const char *)q-starts; + + /* Adjust length */ + if (_PyUnicode_Resize(&unicode, p - unicode->str) < 0) + goto onError; + + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)unicode; + +onError: + Py_DECREF(unicode); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + +PyObject * +PyUnicode_EncodeUTF16(const Py_UNICODE *s, + Py_ssize_t size, + const char *errors, + int byteorder) +{ + PyObject *v; + unsigned char *p; +#ifdef Py_UNICODE_WIDE + int i, pairs; +#else + const int pairs = 0; +#endif + /* Offsets from p for storing byte pairs in the right order. */ +#ifdef BYTEORDER_IS_LITTLE_ENDIAN + int ihi = 1, ilo = 0; +#else + int ihi = 0, ilo = 1; +#endif + +#define STORECHAR(CH) \ + do { \ + p[ihi] = ((CH) >> 8) & 0xff; \ + p[ilo] = (CH) & 0xff; \ + p += 2; \ + } while(0) + +#ifdef Py_UNICODE_WIDE + for (i = pairs = 0; i < size; i++) + if (s[i] >= 0x10000) + pairs++; +#endif + v = PyString_FromStringAndSize(NULL, + 2 * (size + pairs + (byteorder == 0))); + if (v == NULL) + return NULL; + + p = (unsigned char *)PyString_AS_STRING(v); + if (byteorder == 0) + STORECHAR(0xFEFF); + if (size == 0) + return v; + + if (byteorder == -1) { + /* force LE */ + ihi = 1; + ilo = 0; + } + else if (byteorder == 1) { + /* force BE */ + ihi = 0; + ilo = 1; + } + + while (size-- > 0) { + Py_UNICODE ch = *s++; + Py_UNICODE ch2 = 0; +#ifdef Py_UNICODE_WIDE + if (ch >= 0x10000) { + ch2 = 0xDC00 | ((ch-0x10000) & 0x3FF); + ch = 0xD800 | ((ch-0x10000) >> 10); + } +#endif + STORECHAR(ch); + if (ch2) + STORECHAR(ch2); + } + return v; +#undef STORECHAR +} + +PyObject *PyUnicode_AsUTF16String(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeUTF16(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode), + NULL, + 0); +} + +/* --- Unicode Escape Codec ----------------------------------------------- */ + +static _PyUnicode_Name_CAPI *ucnhash_CAPI = NULL; + +PyObject *PyUnicode_DecodeUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *starts = s; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + int i; + PyUnicodeObject *v; + Py_UNICODE *p; + const char *end; + char* message; + Py_UCS4 chr = 0xffffffff; /* in case 'getcode' messes up */ + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + /* Escaped strings will always be longer than the resulting + Unicode string, so we start with size here and then reduce the + length after conversion to the true value. + (but if the error callback returns a long replacement string + we'll have to allocate more space) */ + v = _PyUnicode_New(size); + if (v == NULL) + goto onError; + if (size == 0) + return (PyObject *)v; + + p = PyUnicode_AS_UNICODE(v); + end = s + size; + + while (s < end) { + unsigned char c; + Py_UNICODE x; + int digits; + + /* Non-escape characters are interpreted as Unicode ordinals */ + if (*s != '\\') { + *p++ = (unsigned char) *s++; + continue; + } + + startinpos = s-starts; + /* \ - Escapes */ + s++; + switch (*s++) { + + /* \x escapes */ + case '\n': break; + case '\\': *p++ = '\\'; break; + case '\'': *p++ = '\''; break; + case '\"': *p++ = '\"'; break; + case 'b': *p++ = '\b'; break; + case 'f': *p++ = '\014'; break; /* FF */ + case 't': *p++ = '\t'; break; + case 'n': *p++ = '\n'; break; + case 'r': *p++ = '\r'; break; + case 'v': *p++ = '\013'; break; /* VT */ + case 'a': *p++ = '\007'; break; /* BEL, not classic C */ + + /* \OOO (octal) escapes */ + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + x = s[-1] - '0'; + if ('0' <= *s && *s <= '7') { + x = (x<<3) + *s++ - '0'; + if ('0' <= *s && *s <= '7') + x = (x<<3) + *s++ - '0'; + } + *p++ = x; + break; + + /* hex escapes */ + /* \xXX */ + case 'x': + digits = 2; + message = "truncated \\xXX escape"; + goto hexescape; + + /* \uXXXX */ + case 'u': + digits = 4; + message = "truncated \\uXXXX escape"; + goto hexescape; + + /* \UXXXXXXXX */ + case 'U': + digits = 8; + message = "truncated \\UXXXXXXXX escape"; + hexescape: + chr = 0; + outpos = p-PyUnicode_AS_UNICODE(v); + if (s+digits>end) { + endinpos = size; + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicodeescape", "end of string in escape sequence", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + goto nextByte; + } + for (i = 0; i < digits; ++i) { + c = (unsigned char) s[i]; + if (!isxdigit(c)) { + endinpos = (s+i+1)-starts; + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicodeescape", message, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + goto nextByte; + } + chr = (chr<<4) & ~0xF; + if (c >= '0' && c <= '9') + chr += c - '0'; + else if (c >= 'a' && c <= 'f') + chr += 10 + c - 'a'; + else + chr += 10 + c - 'A'; + } + s += i; + if (chr == 0xffffffff && PyErr_Occurred()) + /* _decoding_error will have already written into the + target buffer. */ + break; + store: + /* when we get here, chr is a 32-bit unicode character */ + if (chr <= 0xffff) + /* UCS-2 character */ + *p++ = (Py_UNICODE) chr; + else if (chr <= 0x10ffff) { + /* UCS-4 character. Either store directly, or as + surrogate pair. */ +#ifdef Py_UNICODE_WIDE + *p++ = chr; +#else + chr -= 0x10000L; + *p++ = 0xD800 + (Py_UNICODE) (chr >> 10); + *p++ = 0xDC00 + (Py_UNICODE) (chr & 0x03FF); +#endif + } else { + endinpos = s-starts; + outpos = p-PyUnicode_AS_UNICODE(v); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicodeescape", "illegal Unicode character", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + } + break; + + /* \N{name} */ + case 'N': + message = "malformed \\N character escape"; + if (ucnhash_CAPI == NULL) { + /* load the unicode data module */ + PyObject *m, *api; + m = PyImport_ImportModule("unicodedata"); + if (m == NULL) + goto ucnhashError; + api = PyObject_GetAttrString(m, "ucnhash_CAPI"); + Py_DECREF(m); + if (api == NULL) + goto ucnhashError; + ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCObject_AsVoidPtr(api); + Py_DECREF(api); + if (ucnhash_CAPI == NULL) + goto ucnhashError; + } + if (*s == '{') { + const char *start = s+1; + /* look for the closing brace */ + while (*s != '}' && s < end) + s++; + if (s > start && s < end && *s == '}') { + /* found a name. look it up in the unicode database */ + message = "unknown Unicode character name"; + s++; + if (ucnhash_CAPI->getcode(NULL, start, (int)(s-start-1), &chr)) + goto store; + } + } + endinpos = s-starts; + outpos = p-PyUnicode_AS_UNICODE(v); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicodeescape", message, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + break; + + default: + if (s > end) { + message = "\\ at end of string"; + s--; + endinpos = s-starts; + outpos = p-PyUnicode_AS_UNICODE(v); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicodeescape", message, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + } + else { + *p++ = '\\'; + *p++ = (unsigned char)s[-1]; + } + break; + } + nextByte: + ; + } + if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) + goto onError; + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)v; + +ucnhashError: + PyErr_SetString( + PyExc_UnicodeError, + "\\N escapes not supported (can't load unicodedata module)" + ); + Py_XDECREF(v); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; + +onError: + Py_XDECREF(v); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + +/* Return a Unicode-Escape string version of the Unicode object. + + If quotes is true, the string is enclosed in u"" or u'' quotes as + appropriate. + +*/ + +Py_LOCAL_INLINE(const Py_UNICODE *) findchar(const Py_UNICODE *s, + Py_ssize_t size, + Py_UNICODE ch) +{ + /* like wcschr, but doesn't stop at NULL characters */ + + while (size-- > 0) { + if (*s == ch) + return s; + s++; + } + + return NULL; +} + +static +PyObject *unicodeescape_string(const Py_UNICODE *s, + Py_ssize_t size, + int quotes) +{ + PyObject *repr; + char *p; + + static const char *hexdigit = "0123456789abcdef"; + + /* Initial allocation is based on the longest-possible unichr + escape. + + In wide (UTF-32) builds '\U00xxxxxx' is 10 chars per source + unichr, so in this case it's the longest unichr escape. In + narrow (UTF-16) builds this is five chars per source unichr + since there are two unichrs in the surrogate pair, so in narrow + (UTF-16) builds it's not the longest unichr escape. + + In wide or narrow builds '\uxxxx' is 6 chars per source unichr, + so in the narrow (UTF-16) build case it's the longest unichr + escape. + */ + + repr = PyString_FromStringAndSize(NULL, + 2 +#ifdef Py_UNICODE_WIDE + + 10*size +#else + + 6*size +#endif + + 1); + if (repr == NULL) + return NULL; + + p = PyString_AS_STRING(repr); + + if (quotes) { + *p++ = 'u'; + *p++ = (findchar(s, size, '\'') && + !findchar(s, size, '"')) ? '"' : '\''; + } + while (size-- > 0) { + Py_UNICODE ch = *s++; + + /* Escape quotes and backslashes */ + if ((quotes && + ch == (Py_UNICODE) PyString_AS_STRING(repr)[1]) || ch == '\\') { + *p++ = '\\'; + *p++ = (char) ch; + continue; + } + +#ifdef Py_UNICODE_WIDE + /* Map 21-bit characters to '\U00xxxxxx' */ + else if (ch >= 0x10000) { + *p++ = '\\'; + *p++ = 'U'; + *p++ = hexdigit[(ch >> 28) & 0x0000000F]; + *p++ = hexdigit[(ch >> 24) & 0x0000000F]; + *p++ = hexdigit[(ch >> 20) & 0x0000000F]; + *p++ = hexdigit[(ch >> 16) & 0x0000000F]; + *p++ = hexdigit[(ch >> 12) & 0x0000000F]; + *p++ = hexdigit[(ch >> 8) & 0x0000000F]; + *p++ = hexdigit[(ch >> 4) & 0x0000000F]; + *p++ = hexdigit[ch & 0x0000000F]; + continue; + } +#else + /* Map UTF-16 surrogate pairs to '\U00xxxxxx' */ + else if (ch >= 0xD800 && ch < 0xDC00) { + Py_UNICODE ch2; + Py_UCS4 ucs; + + ch2 = *s++; + size--; + if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) { + ucs = (((ch & 0x03FF) << 10) | (ch2 & 0x03FF)) + 0x00010000; + *p++ = '\\'; + *p++ = 'U'; + *p++ = hexdigit[(ucs >> 28) & 0x0000000F]; + *p++ = hexdigit[(ucs >> 24) & 0x0000000F]; + *p++ = hexdigit[(ucs >> 20) & 0x0000000F]; + *p++ = hexdigit[(ucs >> 16) & 0x0000000F]; + *p++ = hexdigit[(ucs >> 12) & 0x0000000F]; + *p++ = hexdigit[(ucs >> 8) & 0x0000000F]; + *p++ = hexdigit[(ucs >> 4) & 0x0000000F]; + *p++ = hexdigit[ucs & 0x0000000F]; + continue; + } + /* Fall through: isolated surrogates are copied as-is */ + s--; + size++; + } +#endif + + /* Map 16-bit characters to '\uxxxx' */ + if (ch >= 256) { + *p++ = '\\'; + *p++ = 'u'; + *p++ = hexdigit[(ch >> 12) & 0x000F]; + *p++ = hexdigit[(ch >> 8) & 0x000F]; + *p++ = hexdigit[(ch >> 4) & 0x000F]; + *p++ = hexdigit[ch & 0x000F]; + } + + /* Map special whitespace to '\t', \n', '\r' */ + else if (ch == '\t') { + *p++ = '\\'; + *p++ = 't'; + } + else if (ch == '\n') { + *p++ = '\\'; + *p++ = 'n'; + } + else if (ch == '\r') { + *p++ = '\\'; + *p++ = 'r'; + } + + /* Map non-printable US ASCII to '\xhh' */ + else if (ch < ' ' || ch >= 0x7F) { + *p++ = '\\'; + *p++ = 'x'; + *p++ = hexdigit[(ch >> 4) & 0x000F]; + *p++ = hexdigit[ch & 0x000F]; + } + + /* Copy everything else as-is */ + else + *p++ = (char) ch; + } + if (quotes) + *p++ = PyString_AS_STRING(repr)[1]; + + *p = '\0'; + _PyString_Resize(&repr, p - PyString_AS_STRING(repr)); + return repr; +} + +PyObject *PyUnicode_EncodeUnicodeEscape(const Py_UNICODE *s, + Py_ssize_t size) +{ + return unicodeescape_string(s, size, 0); +} + +PyObject *PyUnicode_AsUnicodeEscapeString(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeUnicodeEscape(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode)); +} + +/* --- Raw Unicode Escape Codec ------------------------------------------- */ + +PyObject *PyUnicode_DecodeRawUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *starts = s; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + PyUnicodeObject *v; + Py_UNICODE *p; + const char *end; + const char *bs; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + /* Escaped strings will always be longer than the resulting + Unicode string, so we start with size here and then reduce the + length after conversion to the true value. (But decoding error + handler might have to resize the string) */ + v = _PyUnicode_New(size); + if (v == NULL) + goto onError; + if (size == 0) + return (PyObject *)v; + p = PyUnicode_AS_UNICODE(v); + end = s + size; + while (s < end) { + unsigned char c; + Py_UCS4 x; + int i; + int count; + + /* Non-escape characters are interpreted as Unicode ordinals */ + if (*s != '\\') { + *p++ = (unsigned char)*s++; + continue; + } + startinpos = s-starts; + + /* \u-escapes are only interpreted iff the number of leading + backslashes if odd */ + bs = s; + for (;s < end;) { + if (*s != '\\') + break; + *p++ = (unsigned char)*s++; + } + if (((s - bs) & 1) == 0 || + s >= end || + (*s != 'u' && *s != 'U')) { + continue; + } + p--; + count = *s=='u' ? 4 : 8; + s++; + + /* \uXXXX with 4 hex digits, \Uxxxxxxxx with 8 */ + outpos = p-PyUnicode_AS_UNICODE(v); + for (x = 0, i = 0; i < count; ++i, ++s) { + c = (unsigned char)*s; + if (!isxdigit(c)) { + endinpos = s-starts; + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "rawunicodeescape", "truncated \\uXXXX", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + goto nextByte; + } + x = (x<<4) & ~0xF; + if (c >= '0' && c <= '9') + x += c - '0'; + else if (c >= 'a' && c <= 'f') + x += 10 + c - 'a'; + else + x += 10 + c - 'A'; + } +#ifndef Py_UNICODE_WIDE + if (x > 0x10000) { + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "rawunicodeescape", "\\Uxxxxxxxx out of range", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + } +#endif + *p++ = x; + nextByte: + ; + } + if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) + goto onError; + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)v; + + onError: + Py_XDECREF(v); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + +PyObject *PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, + Py_ssize_t size) +{ + PyObject *repr; + char *p; + char *q; + + static const char *hexdigit = "0123456789abcdef"; + +#ifdef Py_UNICODE_WIDE + repr = PyString_FromStringAndSize(NULL, 10 * size); +#else + repr = PyString_FromStringAndSize(NULL, 6 * size); +#endif + if (repr == NULL) + return NULL; + if (size == 0) + return repr; + + p = q = PyString_AS_STRING(repr); + while (size-- > 0) { + Py_UNICODE ch = *s++; +#ifdef Py_UNICODE_WIDE + /* Map 32-bit characters to '\Uxxxxxxxx' */ + if (ch >= 0x10000) { + *p++ = '\\'; + *p++ = 'U'; + *p++ = hexdigit[(ch >> 28) & 0xf]; + *p++ = hexdigit[(ch >> 24) & 0xf]; + *p++ = hexdigit[(ch >> 20) & 0xf]; + *p++ = hexdigit[(ch >> 16) & 0xf]; + *p++ = hexdigit[(ch >> 12) & 0xf]; + *p++ = hexdigit[(ch >> 8) & 0xf]; + *p++ = hexdigit[(ch >> 4) & 0xf]; + *p++ = hexdigit[ch & 15]; + } + else +#endif + /* Map 16-bit characters to '\uxxxx' */ + if (ch >= 256) { + *p++ = '\\'; + *p++ = 'u'; + *p++ = hexdigit[(ch >> 12) & 0xf]; + *p++ = hexdigit[(ch >> 8) & 0xf]; + *p++ = hexdigit[(ch >> 4) & 0xf]; + *p++ = hexdigit[ch & 15]; + } + /* Copy everything else as-is */ + else + *p++ = (char) ch; + } + *p = '\0'; + _PyString_Resize(&repr, p - q); + return repr; +} + +PyObject *PyUnicode_AsRawUnicodeEscapeString(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeRawUnicodeEscape(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode)); +} + +/* --- Unicode Internal Codec ------------------------------------------- */ + +PyObject *_PyUnicode_DecodeUnicodeInternal(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *starts = s; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + PyUnicodeObject *v; + Py_UNICODE *p; + const char *end; + const char *reason; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + +#ifdef Py_UNICODE_WIDE + Py_UNICODE unimax = PyUnicode_GetMax(); +#endif + + /* XXX overflow detection missing */ + v = _PyUnicode_New((size+Py_UNICODE_SIZE-1)/ Py_UNICODE_SIZE); + if (v == NULL) + goto onError; + if (PyUnicode_GetSize((PyObject *)v) == 0) + return (PyObject *)v; + p = PyUnicode_AS_UNICODE(v); + end = s + size; + + while (s < end) { + memcpy(p, s, sizeof(Py_UNICODE)); + /* We have to sanity check the raw data, otherwise doom looms for + some malformed UCS-4 data. */ + if ( + #ifdef Py_UNICODE_WIDE + *p > unimax || *p < 0 || + #endif + end-s < Py_UNICODE_SIZE + ) + { + startinpos = s - starts; + if (end-s < Py_UNICODE_SIZE) { + endinpos = end-starts; + reason = "truncated input"; + } + else { + endinpos = s - starts + Py_UNICODE_SIZE; + reason = "illegal code point (> 0x10FFFF)"; + } + outpos = p - PyUnicode_AS_UNICODE(v); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicode_internal", reason, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) { + goto onError; + } + } + else { + p++; + s += Py_UNICODE_SIZE; + } + } + + if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) + goto onError; + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)v; + + onError: + Py_XDECREF(v); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + +/* --- Latin-1 Codec ------------------------------------------------------ */ + +PyObject *PyUnicode_DecodeLatin1(const char *s, + Py_ssize_t size, + const char *errors) +{ + PyUnicodeObject *v; + Py_UNICODE *p; + + /* Latin-1 is equivalent to the first 256 ordinals in Unicode. */ + if (size == 1) { + Py_UNICODE r = *(unsigned char*)s; + return PyUnicode_FromUnicode(&r, 1); + } + + v = _PyUnicode_New(size); + if (v == NULL) + goto onError; + if (size == 0) + return (PyObject *)v; + p = PyUnicode_AS_UNICODE(v); + while (size-- > 0) + *p++ = (unsigned char)*s++; + return (PyObject *)v; + + onError: + Py_XDECREF(v); + return NULL; +} + +/* create or adjust a UnicodeEncodeError */ +static void make_encode_exception(PyObject **exceptionObject, + const char *encoding, + const Py_UNICODE *unicode, Py_ssize_t size, + Py_ssize_t startpos, Py_ssize_t endpos, + const char *reason) +{ + if (*exceptionObject == NULL) { + *exceptionObject = PyUnicodeEncodeError_Create( + encoding, unicode, size, startpos, endpos, reason); + } + else { + if (PyUnicodeEncodeError_SetStart(*exceptionObject, startpos)) + goto onError; + if (PyUnicodeEncodeError_SetEnd(*exceptionObject, endpos)) + goto onError; + if (PyUnicodeEncodeError_SetReason(*exceptionObject, reason)) + goto onError; + return; + onError: + Py_DECREF(*exceptionObject); + *exceptionObject = NULL; + } +} + +/* raises a UnicodeEncodeError */ +static void raise_encode_exception(PyObject **exceptionObject, + const char *encoding, + const Py_UNICODE *unicode, Py_ssize_t size, + Py_ssize_t startpos, Py_ssize_t endpos, + const char *reason) +{ + make_encode_exception(exceptionObject, + encoding, unicode, size, startpos, endpos, reason); + if (*exceptionObject != NULL) + PyCodec_StrictErrors(*exceptionObject); +} + +/* error handling callback helper: + build arguments, call the callback and check the arguments, + put the result into newpos and return the replacement string, which + has to be freed by the caller */ +static PyObject *unicode_encode_call_errorhandler(const char *errors, + PyObject **errorHandler, + const char *encoding, const char *reason, + const Py_UNICODE *unicode, Py_ssize_t size, PyObject **exceptionObject, + Py_ssize_t startpos, Py_ssize_t endpos, + Py_ssize_t *newpos) +{ + static char *argparse = "O!n;encoding error handler must return (unicode, int) tuple"; + + PyObject *restuple; + PyObject *resunicode; + + if (*errorHandler == NULL) { + *errorHandler = PyCodec_LookupError(errors); + if (*errorHandler == NULL) + return NULL; + } + + make_encode_exception(exceptionObject, + encoding, unicode, size, startpos, endpos, reason); + if (*exceptionObject == NULL) + return NULL; + + restuple = PyObject_CallFunctionObjArgs( + *errorHandler, *exceptionObject, NULL); + if (restuple == NULL) + return NULL; + if (!PyTuple_Check(restuple)) { + PyErr_Format(PyExc_TypeError, &argparse[4]); + Py_DECREF(restuple); + return NULL; + } + if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, + &resunicode, newpos)) { + Py_DECREF(restuple); + return NULL; + } + if (*newpos<0) + *newpos = size+*newpos; + if (*newpos<0 || *newpos>size) { + PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", *newpos); + Py_DECREF(restuple); + return NULL; + } + Py_INCREF(resunicode); + Py_DECREF(restuple); + return resunicode; +} + +static PyObject *unicode_encode_ucs1(const Py_UNICODE *p, + Py_ssize_t size, + const char *errors, + int limit) +{ + /* output object */ + PyObject *res; + /* pointers to the beginning and end+1 of input */ + const Py_UNICODE *startp = p; + const Py_UNICODE *endp = p + size; + /* pointer to the beginning of the unencodable characters */ + /* const Py_UNICODE *badp = NULL; */ + /* pointer into the output */ + char *str; + /* current output position */ + Py_ssize_t respos = 0; + Py_ssize_t ressize; + const char *encoding = (limit == 256) ? "latin-1" : "ascii"; + const char *reason = (limit == 256) ? "ordinal not in range(256)" : "ordinal not in range(128)"; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + /* the following variable is used for caching string comparisons + * -1=not initialized, 0=unknown, 1=strict, 2=replace, 3=ignore, 4=xmlcharrefreplace */ + int known_errorHandler = -1; + + /* allocate enough for a simple encoding without + replacements, if we need more, we'll resize */ + res = PyString_FromStringAndSize(NULL, size); + if (res == NULL) + goto onError; + if (size == 0) + return res; + str = PyString_AS_STRING(res); + ressize = size; + + while (p<endp) { + Py_UNICODE c = *p; + + /* can we encode this? */ + if (c<limit) { + /* no overflow check, because we know that the space is enough */ + *str++ = (char)c; + ++p; + } + else { + Py_ssize_t unicodepos = p-startp; + Py_ssize_t requiredsize; + PyObject *repunicode; + Py_ssize_t repsize; + Py_ssize_t newpos; + Py_ssize_t respos; + Py_UNICODE *uni2; + /* startpos for collecting unencodable chars */ + const Py_UNICODE *collstart = p; + const Py_UNICODE *collend = p; + /* find all unecodable characters */ + while ((collend < endp) && ((*collend)>=limit)) + ++collend; + /* cache callback name lookup (if not done yet, i.e. it's the first error) */ + if (known_errorHandler==-1) { + if ((errors==NULL) || (!strcmp(errors, "strict"))) + known_errorHandler = 1; + else if (!strcmp(errors, "replace")) + known_errorHandler = 2; + else if (!strcmp(errors, "ignore")) + known_errorHandler = 3; + else if (!strcmp(errors, "xmlcharrefreplace")) + known_errorHandler = 4; + else + known_errorHandler = 0; + } + switch (known_errorHandler) { + case 1: /* strict */ + raise_encode_exception(&exc, encoding, startp, size, collstart-startp, collend-startp, reason); + goto onError; + case 2: /* replace */ + while (collstart++<collend) + *str++ = '?'; /* fall through */ + case 3: /* ignore */ + p = collend; + break; + case 4: /* xmlcharrefreplace */ + respos = str-PyString_AS_STRING(res); + /* determine replacement size (temporarily (mis)uses p) */ + for (p = collstart, repsize = 0; p < collend; ++p) { + if (*p<10) + repsize += 2+1+1; + else if (*p<100) + repsize += 2+2+1; + else if (*p<1000) + repsize += 2+3+1; + else if (*p<10000) + repsize += 2+4+1; +#ifndef Py_UNICODE_WIDE + else + repsize += 2+5+1; +#else + else if (*p<100000) + repsize += 2+5+1; + else if (*p<1000000) + repsize += 2+6+1; + else + repsize += 2+7+1; +#endif + } + requiredsize = respos+repsize+(endp-collend); + if (requiredsize > ressize) { + if (requiredsize<2*ressize) + requiredsize = 2*ressize; + if (_PyString_Resize(&res, requiredsize)) + goto onError; + str = PyString_AS_STRING(res) + respos; + ressize = requiredsize; + } + /* generate replacement (temporarily (mis)uses p) */ + for (p = collstart; p < collend; ++p) { + str += sprintf(str, "&#%d;", (int)*p); + } + p = collend; + break; + default: + repunicode = unicode_encode_call_errorhandler(errors, &errorHandler, + encoding, reason, startp, size, &exc, + collstart-startp, collend-startp, &newpos); + if (repunicode == NULL) + goto onError; + /* need more space? (at least enough for what we + have+the replacement+the rest of the string, so + we won't have to check space for encodable characters) */ + respos = str-PyString_AS_STRING(res); + repsize = PyUnicode_GET_SIZE(repunicode); + requiredsize = respos+repsize+(endp-collend); + if (requiredsize > ressize) { + if (requiredsize<2*ressize) + requiredsize = 2*ressize; + if (_PyString_Resize(&res, requiredsize)) { + Py_DECREF(repunicode); + goto onError; + } + str = PyString_AS_STRING(res) + respos; + ressize = requiredsize; + } + /* check if there is anything unencodable in the replacement + and copy it to the output */ + for (uni2 = PyUnicode_AS_UNICODE(repunicode);repsize-->0; ++uni2, ++str) { + c = *uni2; + if (c >= limit) { + raise_encode_exception(&exc, encoding, startp, size, + unicodepos, unicodepos+1, reason); + Py_DECREF(repunicode); + goto onError; + } + *str = (char)c; + } + p = startp + newpos; + Py_DECREF(repunicode); + } + } + } + /* Resize if we allocated to much */ + respos = str-PyString_AS_STRING(res); + if (respos<ressize) + /* If this falls res will be NULL */ + _PyString_Resize(&res, respos); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return res; + + onError: + Py_XDECREF(res); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + +PyObject *PyUnicode_EncodeLatin1(const Py_UNICODE *p, + Py_ssize_t size, + const char *errors) +{ + return unicode_encode_ucs1(p, size, errors, 256); +} + +PyObject *PyUnicode_AsLatin1String(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeLatin1(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode), + NULL); +} + +/* --- 7-bit ASCII Codec -------------------------------------------------- */ + +PyObject *PyUnicode_DecodeASCII(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *starts = s; + PyUnicodeObject *v; + Py_UNICODE *p; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + const char *e; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + /* ASCII is equivalent to the first 128 ordinals in Unicode. */ + if (size == 1 && *(unsigned char*)s < 128) { + Py_UNICODE r = *(unsigned char*)s; + return PyUnicode_FromUnicode(&r, 1); + } + + v = _PyUnicode_New(size); + if (v == NULL) + goto onError; + if (size == 0) + return (PyObject *)v; + p = PyUnicode_AS_UNICODE(v); + e = s + size; + while (s < e) { + register unsigned char c = (unsigned char)*s; + if (c < 128) { + *p++ = c; + ++s; + } + else { + startinpos = s-starts; + endinpos = startinpos + 1; + outpos = p - (Py_UNICODE *)PyUnicode_AS_UNICODE(v); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "ascii", "ordinal not in range(128)", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) + goto onError; + } + } + if (p - PyUnicode_AS_UNICODE(v) < PyString_GET_SIZE(v)) + if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) + goto onError; + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)v; + + onError: + Py_XDECREF(v); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + +PyObject *PyUnicode_EncodeASCII(const Py_UNICODE *p, + Py_ssize_t size, + const char *errors) +{ + return unicode_encode_ucs1(p, size, errors, 128); +} + +PyObject *PyUnicode_AsASCIIString(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeASCII(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode), + NULL); +} + +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) + +/* --- MBCS codecs for Windows -------------------------------------------- */ + +#if SIZEOF_INT < SIZEOF_SSIZE_T +#define NEED_RETRY +#endif + +/* XXX This code is limited to "true" double-byte encodings, as + a) it assumes an incomplete character consists of a single byte, and + b) IsDBCSLeadByte (probably) does not work for non-DBCS multi-byte + encodings, see IsDBCSLeadByteEx documentation. */ + +static int is_dbcs_lead_byte(const char *s, int offset) +{ + const char *curr = s + offset; + + if (IsDBCSLeadByte(*curr)) { + const char *prev = CharPrev(s, curr); + return (prev == curr) || !IsDBCSLeadByte(*prev) || (curr - prev == 2); + } + return 0; +} + +/* + * Decode MBCS string into unicode object. If 'final' is set, converts + * trailing lead-byte too. Returns consumed size if succeed, -1 otherwise. + */ +static int decode_mbcs(PyUnicodeObject **v, + const char *s, /* MBCS string */ + int size, /* sizeof MBCS string */ + int final) +{ + Py_UNICODE *p; + Py_ssize_t n = 0; + int usize = 0; + + assert(size >= 0); + + /* Skip trailing lead-byte unless 'final' is set */ + if (!final && size >= 1 && is_dbcs_lead_byte(s, size - 1)) + --size; + + /* First get the size of the result */ + if (size > 0) { + usize = MultiByteToWideChar(CP_ACP, 0, s, size, NULL, 0); + if (usize == 0) { + PyErr_SetFromWindowsErrWithFilename(0, NULL); + return -1; + } + } + + if (*v == NULL) { + /* Create unicode object */ + *v = _PyUnicode_New(usize); + if (*v == NULL) + return -1; + } + else { + /* Extend unicode object */ + n = PyUnicode_GET_SIZE(*v); + if (_PyUnicode_Resize(v, n + usize) < 0) + return -1; + } + + /* Do the conversion */ + if (size > 0) { + p = PyUnicode_AS_UNICODE(*v) + n; + if (0 == MultiByteToWideChar(CP_ACP, 0, s, size, p, usize)) { + PyErr_SetFromWindowsErrWithFilename(0, NULL); + return -1; + } + } + + return size; +} + +PyObject *PyUnicode_DecodeMBCSStateful(const char *s, + Py_ssize_t size, + const char *errors, + Py_ssize_t *consumed) +{ + PyUnicodeObject *v = NULL; + int done; + + if (consumed) + *consumed = 0; + +#ifdef NEED_RETRY + retry: + if (size > INT_MAX) + done = decode_mbcs(&v, s, INT_MAX, 0); + else +#endif + done = decode_mbcs(&v, s, (int)size, !consumed); + + if (done < 0) { + Py_XDECREF(v); + return NULL; + } + + if (consumed) + *consumed += done; + +#ifdef NEED_RETRY + if (size > INT_MAX) { + s += done; + size -= done; + goto retry; + } +#endif + + return (PyObject *)v; +} + +PyObject *PyUnicode_DecodeMBCS(const char *s, + Py_ssize_t size, + const char *errors) +{ + return PyUnicode_DecodeMBCSStateful(s, size, errors, NULL); +} + +/* + * Convert unicode into string object (MBCS). + * Returns 0 if succeed, -1 otherwise. + */ +static int encode_mbcs(PyObject **repr, + const Py_UNICODE *p, /* unicode */ + int size) /* size of unicode */ +{ + int mbcssize = 0; + Py_ssize_t n = 0; + + assert(size >= 0); + + /* First get the size of the result */ + if (size > 0) { + mbcssize = WideCharToMultiByte(CP_ACP, 0, p, size, NULL, 0, NULL, NULL); + if (mbcssize == 0) { + PyErr_SetFromWindowsErrWithFilename(0, NULL); + return -1; + } + } + + if (*repr == NULL) { + /* Create string object */ + *repr = PyString_FromStringAndSize(NULL, mbcssize); + if (*repr == NULL) + return -1; + } + else { + /* Extend string object */ + n = PyString_Size(*repr); + if (_PyString_Resize(repr, n + mbcssize) < 0) + return -1; + } + + /* Do the conversion */ + if (size > 0) { + char *s = PyString_AS_STRING(*repr) + n; + if (0 == WideCharToMultiByte(CP_ACP, 0, p, size, s, mbcssize, NULL, NULL)) { + PyErr_SetFromWindowsErrWithFilename(0, NULL); + return -1; + } + } + + return 0; +} + +PyObject *PyUnicode_EncodeMBCS(const Py_UNICODE *p, + Py_ssize_t size, + const char *errors) +{ + PyObject *repr = NULL; + int ret; + +#ifdef NEED_RETRY + retry: + if (size > INT_MAX) + ret = encode_mbcs(&repr, p, INT_MAX); + else +#endif + ret = encode_mbcs(&repr, p, (int)size); + + if (ret < 0) { + Py_XDECREF(repr); + return NULL; + } + +#ifdef NEED_RETRY + if (size > INT_MAX) { + p += INT_MAX; + size -= INT_MAX; + goto retry; + } +#endif + + return repr; +} + +PyObject *PyUnicode_AsMBCSString(PyObject *unicode) +{ + if (!PyUnicode_Check(unicode)) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeMBCS(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode), + NULL); +} + +#undef NEED_RETRY + +#endif /* MS_WINDOWS */ + +/* --- Character Mapping Codec -------------------------------------------- */ + +PyObject *PyUnicode_DecodeCharmap(const char *s, + Py_ssize_t size, + PyObject *mapping, + const char *errors) +{ + const char *starts = s; + Py_ssize_t startinpos; + Py_ssize_t endinpos; + Py_ssize_t outpos; + const char *e; + PyUnicodeObject *v; + Py_UNICODE *p; + Py_ssize_t extrachars = 0; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + Py_UNICODE *mapstring = NULL; + Py_ssize_t maplen = 0; + + /* Default to Latin-1 */ + if (mapping == NULL) + return PyUnicode_DecodeLatin1(s, size, errors); + + v = _PyUnicode_New(size); + if (v == NULL) + goto onError; + if (size == 0) + return (PyObject *)v; + p = PyUnicode_AS_UNICODE(v); + e = s + size; + if (PyUnicode_CheckExact(mapping)) { + mapstring = PyUnicode_AS_UNICODE(mapping); + maplen = PyUnicode_GET_SIZE(mapping); + while (s < e) { + unsigned char ch = *s; + Py_UNICODE x = 0xfffe; /* illegal value */ + + if (ch < maplen) + x = mapstring[ch]; + + if (x == 0xfffe) { + /* undefined mapping */ + outpos = p-PyUnicode_AS_UNICODE(v); + startinpos = s-starts; + endinpos = startinpos+1; + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "charmap", "character maps to <undefined>", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) { + goto onError; + } + continue; + } + *p++ = x; + ++s; + } + } + else { + while (s < e) { + unsigned char ch = *s; + PyObject *w, *x; + + /* Get mapping (char ordinal -> integer, Unicode char or None) */ + w = PyInt_FromLong((long)ch); + if (w == NULL) + goto onError; + x = PyObject_GetItem(mapping, w); + Py_DECREF(w); + if (x == NULL) { + if (PyErr_ExceptionMatches(PyExc_LookupError)) { + /* No mapping found means: mapping is undefined. */ + PyErr_Clear(); + x = Py_None; + Py_INCREF(x); + } else + goto onError; + } + + /* Apply mapping */ + if (PyInt_Check(x)) { + long value = PyInt_AS_LONG(x); + if (value < 0 || value > 65535) { + PyErr_SetString(PyExc_TypeError, + "character mapping must be in range(65536)"); + Py_DECREF(x); + goto onError; + } + *p++ = (Py_UNICODE)value; + } + else if (x == Py_None) { + /* undefined mapping */ + outpos = p-PyUnicode_AS_UNICODE(v); + startinpos = s-starts; + endinpos = startinpos+1; + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "charmap", "character maps to <undefined>", + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) { + Py_DECREF(x); + goto onError; + } + Py_DECREF(x); + continue; + } + else if (PyUnicode_Check(x)) { + Py_ssize_t targetsize = PyUnicode_GET_SIZE(x); + + if (targetsize == 1) + /* 1-1 mapping */ + *p++ = *PyUnicode_AS_UNICODE(x); + + else if (targetsize > 1) { + /* 1-n mapping */ + if (targetsize > extrachars) { + /* resize first */ + Py_ssize_t oldpos = p - PyUnicode_AS_UNICODE(v); + Py_ssize_t needed = (targetsize - extrachars) + \ + (targetsize << 2); + extrachars += needed; + /* XXX overflow detection missing */ + if (_PyUnicode_Resize(&v, + PyUnicode_GET_SIZE(v) + needed) < 0) { + Py_DECREF(x); + goto onError; + } + p = PyUnicode_AS_UNICODE(v) + oldpos; + } + Py_UNICODE_COPY(p, + PyUnicode_AS_UNICODE(x), + targetsize); + p += targetsize; + extrachars -= targetsize; + } + /* 1-0 mapping: skip the character */ + } + else { + /* wrong return value */ + PyErr_SetString(PyExc_TypeError, + "character mapping must return integer, None or unicode"); + Py_DECREF(x); + goto onError; + } + Py_DECREF(x); + ++s; + } + } + if (p - PyUnicode_AS_UNICODE(v) < PyUnicode_GET_SIZE(v)) + if (_PyUnicode_Resize(&v, p - PyUnicode_AS_UNICODE(v)) < 0) + goto onError; + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)v; + + onError: + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + Py_XDECREF(v); + return NULL; +} + +/* Charmap encoding: the lookup table */ + +struct encoding_map{ + PyObject_HEAD + unsigned char level1[32]; + int count2, count3; + unsigned char level23[1]; +}; + +static PyObject* +encoding_map_size(PyObject *obj, PyObject* args) +{ + struct encoding_map *map = (struct encoding_map*)obj; + return PyInt_FromLong(sizeof(*map) - 1 + 16*map->count2 + + 128*map->count3); +} + +static PyMethodDef encoding_map_methods[] = { + {"size", encoding_map_size, METH_NOARGS, + PyDoc_STR("Return the size (in bytes) of this object") }, + { 0 } +}; + +static void +encoding_map_dealloc(PyObject* o) +{ + PyObject_FREE(o); +} + +static PyTypeObject EncodingMapType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "EncodingMap", /*tp_name*/ + sizeof(struct encoding_map), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + encoding_map_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + encoding_map_methods, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + 0, /*tp_init*/ + 0, /*tp_alloc*/ + 0, /*tp_new*/ + 0, /*tp_free*/ + 0, /*tp_is_gc*/ +}; + +PyObject* +PyUnicode_BuildEncodingMap(PyObject* string) +{ + Py_UNICODE *decode; + PyObject *result; + struct encoding_map *mresult; + int i; + int need_dict = 0; + unsigned char level1[32]; + unsigned char level2[512]; + unsigned char *mlevel1, *mlevel2, *mlevel3; + int count2 = 0, count3 = 0; + + if (!PyUnicode_Check(string) || PyUnicode_GetSize(string) != 256) { + PyErr_BadArgument(); + return NULL; + } + decode = PyUnicode_AS_UNICODE(string); + memset(level1, 0xFF, sizeof level1); + memset(level2, 0xFF, sizeof level2); + + /* If there isn't a one-to-one mapping of NULL to \0, + or if there are non-BMP characters, we need to use + a mapping dictionary. */ + if (decode[0] != 0) + need_dict = 1; + for (i = 1; i < 256; i++) { + int l1, l2; + if (decode[i] == 0 + #ifdef Py_UNICODE_WIDE + || decode[i] > 0xFFFF + #endif + ) { + need_dict = 1; + break; + } + if (decode[i] == 0xFFFE) + /* unmapped character */ + continue; + l1 = decode[i] >> 11; + l2 = decode[i] >> 7; + if (level1[l1] == 0xFF) + level1[l1] = count2++; + if (level2[l2] == 0xFF) + level2[l2] = count3++; + } + + if (count2 >= 0xFF || count3 >= 0xFF) + need_dict = 1; + + if (need_dict) { + PyObject *result = PyDict_New(); + PyObject *key, *value; + if (!result) + return NULL; + for (i = 0; i < 256; i++) { + key = value = NULL; + key = PyInt_FromLong(decode[i]); + value = PyInt_FromLong(i); + if (!key || !value) + goto failed1; + if (PyDict_SetItem(result, key, value) == -1) + goto failed1; + Py_DECREF(key); + Py_DECREF(value); + } + return result; + failed1: + Py_XDECREF(key); + Py_XDECREF(value); + Py_DECREF(result); + return NULL; + } + + /* Create a three-level trie */ + result = PyObject_MALLOC(sizeof(struct encoding_map) + + 16*count2 + 128*count3 - 1); + if (!result) + return PyErr_NoMemory(); + PyObject_Init(result, &EncodingMapType); + mresult = (struct encoding_map*)result; + mresult->count2 = count2; + mresult->count3 = count3; + mlevel1 = mresult->level1; + mlevel2 = mresult->level23; + mlevel3 = mresult->level23 + 16*count2; + memcpy(mlevel1, level1, 32); + memset(mlevel2, 0xFF, 16*count2); + memset(mlevel3, 0, 128*count3); + count3 = 0; + for (i = 1; i < 256; i++) { + int o1, o2, o3, i2, i3; + if (decode[i] == 0xFFFE) + /* unmapped character */ + continue; + o1 = decode[i]>>11; + o2 = (decode[i]>>7) & 0xF; + i2 = 16*mlevel1[o1] + o2; + if (mlevel2[i2] == 0xFF) + mlevel2[i2] = count3++; + o3 = decode[i] & 0x7F; + i3 = 128*mlevel2[i2] + o3; + mlevel3[i3] = i; + } + return result; +} + +static int +encoding_map_lookup(Py_UNICODE c, PyObject *mapping) +{ + struct encoding_map *map = (struct encoding_map*)mapping; + int l1 = c>>11; + int l2 = (c>>7) & 0xF; + int l3 = c & 0x7F; + int i; + +#ifdef Py_UNICODE_WIDE + if (c > 0xFFFF) { + return -1; + } +#endif + if (c == 0) + return 0; + /* level 1*/ + i = map->level1[l1]; + if (i == 0xFF) { + return -1; + } + /* level 2*/ + i = map->level23[16*i+l2]; + if (i == 0xFF) { + return -1; + } + /* level 3 */ + i = map->level23[16*map->count2 + 128*i + l3]; + if (i == 0) { + return -1; + } + return i; +} + +/* Lookup the character ch in the mapping. If the character + can't be found, Py_None is returned (or NULL, if another + error occurred). */ +static PyObject *charmapencode_lookup(Py_UNICODE c, PyObject *mapping) +{ + PyObject *w = PyInt_FromLong((long)c); + PyObject *x; + + if (w == NULL) + return NULL; + x = PyObject_GetItem(mapping, w); + Py_DECREF(w); + if (x == NULL) { + if (PyErr_ExceptionMatches(PyExc_LookupError)) { + /* No mapping found means: mapping is undefined. */ + PyErr_Clear(); + x = Py_None; + Py_INCREF(x); + return x; + } else + return NULL; + } + else if (x == Py_None) + return x; + else if (PyInt_Check(x)) { + long value = PyInt_AS_LONG(x); + if (value < 0 || value > 255) { + PyErr_SetString(PyExc_TypeError, + "character mapping must be in range(256)"); + Py_DECREF(x); + return NULL; + } + return x; + } + else if (PyString_Check(x)) + return x; + else { + /* wrong return value */ + PyErr_SetString(PyExc_TypeError, + "character mapping must return integer, None or str"); + Py_DECREF(x); + return NULL; + } +} + +static int +charmapencode_resize(PyObject **outobj, Py_ssize_t *outpos, Py_ssize_t requiredsize) +{ + Py_ssize_t outsize = PyString_GET_SIZE(*outobj); + /* exponentially overallocate to minimize reallocations */ + if (requiredsize < 2*outsize) + requiredsize = 2*outsize; + if (_PyString_Resize(outobj, requiredsize)) { + return 0; + } + return 1; +} + +typedef enum charmapencode_result { + enc_SUCCESS, enc_FAILED, enc_EXCEPTION +}charmapencode_result; +/* lookup the character, put the result in the output string and adjust + various state variables. Reallocate the output string if not enough + space is available. Return a new reference to the object that + was put in the output buffer, or Py_None, if the mapping was undefined + (in which case no character was written) or NULL, if a + reallocation error occurred. The caller must decref the result */ +static +charmapencode_result charmapencode_output(Py_UNICODE c, PyObject *mapping, + PyObject **outobj, Py_ssize_t *outpos) +{ + PyObject *rep; + char *outstart; + Py_ssize_t outsize = PyString_GET_SIZE(*outobj); + + if (mapping->ob_type == &EncodingMapType) { + int res = encoding_map_lookup(c, mapping); + Py_ssize_t requiredsize = *outpos+1; + if (res == -1) + return enc_FAILED; + if (outsize<requiredsize) + if (!charmapencode_resize(outobj, outpos, requiredsize)) + return enc_EXCEPTION; + outstart = PyString_AS_STRING(*outobj); + outstart[(*outpos)++] = (char)res; + return enc_SUCCESS; + } + + rep = charmapencode_lookup(c, mapping); + if (rep==NULL) + return enc_EXCEPTION; + else if (rep==Py_None) { + Py_DECREF(rep); + return enc_FAILED; + } else { + if (PyInt_Check(rep)) { + Py_ssize_t requiredsize = *outpos+1; + if (outsize<requiredsize) + if (!charmapencode_resize(outobj, outpos, requiredsize)) { + Py_DECREF(rep); + return enc_EXCEPTION; + } + outstart = PyString_AS_STRING(*outobj); + outstart[(*outpos)++] = (char)PyInt_AS_LONG(rep); + } + else { + const char *repchars = PyString_AS_STRING(rep); + Py_ssize_t repsize = PyString_GET_SIZE(rep); + Py_ssize_t requiredsize = *outpos+repsize; + if (outsize<requiredsize) + if (!charmapencode_resize(outobj, outpos, requiredsize)) { + Py_DECREF(rep); + return enc_EXCEPTION; + } + outstart = PyString_AS_STRING(*outobj); + memcpy(outstart + *outpos, repchars, repsize); + *outpos += repsize; + } + } + Py_DECREF(rep); + return enc_SUCCESS; +} + +/* handle an error in PyUnicode_EncodeCharmap + Return 0 on success, -1 on error */ +static +int charmap_encoding_error( + const Py_UNICODE *p, Py_ssize_t size, Py_ssize_t *inpos, PyObject *mapping, + PyObject **exceptionObject, + int *known_errorHandler, PyObject **errorHandler, const char *errors, + PyObject **res, Py_ssize_t *respos) +{ + PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ + Py_ssize_t repsize; + Py_ssize_t newpos; + Py_UNICODE *uni2; + /* startpos for collecting unencodable chars */ + Py_ssize_t collstartpos = *inpos; + Py_ssize_t collendpos = *inpos+1; + Py_ssize_t collpos; + char *encoding = "charmap"; + char *reason = "character maps to <undefined>"; + charmapencode_result x; + + /* find all unencodable characters */ + while (collendpos < size) { + PyObject *rep; + if (mapping->ob_type == &EncodingMapType) { + int res = encoding_map_lookup(p[collendpos], mapping); + if (res != -1) + break; + ++collendpos; + continue; + } + + rep = charmapencode_lookup(p[collendpos], mapping); + if (rep==NULL) + return -1; + else if (rep!=Py_None) { + Py_DECREF(rep); + break; + } + Py_DECREF(rep); + ++collendpos; + } + /* cache callback name lookup + * (if not done yet, i.e. it's the first error) */ + if (*known_errorHandler==-1) { + if ((errors==NULL) || (!strcmp(errors, "strict"))) + *known_errorHandler = 1; + else if (!strcmp(errors, "replace")) + *known_errorHandler = 2; + else if (!strcmp(errors, "ignore")) + *known_errorHandler = 3; + else if (!strcmp(errors, "xmlcharrefreplace")) + *known_errorHandler = 4; + else + *known_errorHandler = 0; + } + switch (*known_errorHandler) { + case 1: /* strict */ + raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); + return -1; + case 2: /* replace */ + for (collpos = collstartpos; collpos<collendpos; ++collpos) { + x = charmapencode_output('?', mapping, res, respos); + if (x==enc_EXCEPTION) { + return -1; + } + else if (x==enc_FAILED) { + raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); + return -1; + } + } + /* fall through */ + case 3: /* ignore */ + *inpos = collendpos; + break; + case 4: /* xmlcharrefreplace */ + /* generate replacement (temporarily (mis)uses p) */ + for (collpos = collstartpos; collpos < collendpos; ++collpos) { + char buffer[2+29+1+1]; + char *cp; + sprintf(buffer, "&#%d;", (int)p[collpos]); + for (cp = buffer; *cp; ++cp) { + x = charmapencode_output(*cp, mapping, res, respos); + if (x==enc_EXCEPTION) + return -1; + else if (x==enc_FAILED) { + raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); + return -1; + } + } + } + *inpos = collendpos; + break; + default: + repunicode = unicode_encode_call_errorhandler(errors, errorHandler, + encoding, reason, p, size, exceptionObject, + collstartpos, collendpos, &newpos); + if (repunicode == NULL) + return -1; + /* generate replacement */ + repsize = PyUnicode_GET_SIZE(repunicode); + for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) { + x = charmapencode_output(*uni2, mapping, res, respos); + if (x==enc_EXCEPTION) { + return -1; + } + else if (x==enc_FAILED) { + Py_DECREF(repunicode); + raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); + return -1; + } + } + *inpos = newpos; + Py_DECREF(repunicode); + } + return 0; +} + +PyObject *PyUnicode_EncodeCharmap(const Py_UNICODE *p, + Py_ssize_t size, + PyObject *mapping, + const char *errors) +{ + /* output object */ + PyObject *res = NULL; + /* current input position */ + Py_ssize_t inpos = 0; + /* current output position */ + Py_ssize_t respos = 0; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + /* the following variable is used for caching string comparisons + * -1=not initialized, 0=unknown, 1=strict, 2=replace, + * 3=ignore, 4=xmlcharrefreplace */ + int known_errorHandler = -1; + + /* Default to Latin-1 */ + if (mapping == NULL) + return PyUnicode_EncodeLatin1(p, size, errors); + + /* allocate enough for a simple encoding without + replacements, if we need more, we'll resize */ + res = PyString_FromStringAndSize(NULL, size); + if (res == NULL) + goto onError; + if (size == 0) + return res; + + while (inpos<size) { + /* try to encode it */ + charmapencode_result x = charmapencode_output(p[inpos], mapping, &res, &respos); + if (x==enc_EXCEPTION) /* error */ + goto onError; + if (x==enc_FAILED) { /* unencodable character */ + if (charmap_encoding_error(p, size, &inpos, mapping, + &exc, + &known_errorHandler, &errorHandler, errors, + &res, &respos)) { + goto onError; + } + } + else + /* done with this character => adjust input position */ + ++inpos; + } + + /* Resize if we allocated to much */ + if (respos<PyString_GET_SIZE(res)) { + if (_PyString_Resize(&res, respos)) + goto onError; + } + Py_XDECREF(exc); + Py_XDECREF(errorHandler); + return res; + + onError: + Py_XDECREF(res); + Py_XDECREF(exc); + Py_XDECREF(errorHandler); + return NULL; +} + +PyObject *PyUnicode_AsCharmapString(PyObject *unicode, + PyObject *mapping) +{ + if (!PyUnicode_Check(unicode) || mapping == NULL) { + PyErr_BadArgument(); + return NULL; + } + return PyUnicode_EncodeCharmap(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode), + mapping, + NULL); +} + +/* create or adjust a UnicodeTranslateError */ +static void make_translate_exception(PyObject **exceptionObject, + const Py_UNICODE *unicode, Py_ssize_t size, + Py_ssize_t startpos, Py_ssize_t endpos, + const char *reason) +{ + if (*exceptionObject == NULL) { + *exceptionObject = PyUnicodeTranslateError_Create( + unicode, size, startpos, endpos, reason); + } + else { + if (PyUnicodeTranslateError_SetStart(*exceptionObject, startpos)) + goto onError; + if (PyUnicodeTranslateError_SetEnd(*exceptionObject, endpos)) + goto onError; + if (PyUnicodeTranslateError_SetReason(*exceptionObject, reason)) + goto onError; + return; + onError: + Py_DECREF(*exceptionObject); + *exceptionObject = NULL; + } +} + +/* raises a UnicodeTranslateError */ +static void raise_translate_exception(PyObject **exceptionObject, + const Py_UNICODE *unicode, Py_ssize_t size, + Py_ssize_t startpos, Py_ssize_t endpos, + const char *reason) +{ + make_translate_exception(exceptionObject, + unicode, size, startpos, endpos, reason); + if (*exceptionObject != NULL) + PyCodec_StrictErrors(*exceptionObject); +} + +/* error handling callback helper: + build arguments, call the callback and check the arguments, + put the result into newpos and return the replacement string, which + has to be freed by the caller */ +static PyObject *unicode_translate_call_errorhandler(const char *errors, + PyObject **errorHandler, + const char *reason, + const Py_UNICODE *unicode, Py_ssize_t size, PyObject **exceptionObject, + Py_ssize_t startpos, Py_ssize_t endpos, + Py_ssize_t *newpos) +{ + static char *argparse = "O!n;translating error handler must return (unicode, int) tuple"; + + Py_ssize_t i_newpos; + PyObject *restuple; + PyObject *resunicode; + + if (*errorHandler == NULL) { + *errorHandler = PyCodec_LookupError(errors); + if (*errorHandler == NULL) + return NULL; + } + + make_translate_exception(exceptionObject, + unicode, size, startpos, endpos, reason); + if (*exceptionObject == NULL) + return NULL; + + restuple = PyObject_CallFunctionObjArgs( + *errorHandler, *exceptionObject, NULL); + if (restuple == NULL) + return NULL; + if (!PyTuple_Check(restuple)) { + PyErr_Format(PyExc_TypeError, &argparse[4]); + Py_DECREF(restuple); + return NULL; + } + if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, + &resunicode, &i_newpos)) { + Py_DECREF(restuple); + return NULL; + } + if (i_newpos<0) + *newpos = size+i_newpos; + else + *newpos = i_newpos; + if (*newpos<0 || *newpos>size) { + PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", *newpos); + Py_DECREF(restuple); + return NULL; + } + Py_INCREF(resunicode); + Py_DECREF(restuple); + return resunicode; +} + +/* Lookup the character ch in the mapping and put the result in result, + which must be decrefed by the caller. + Return 0 on success, -1 on error */ +static +int charmaptranslate_lookup(Py_UNICODE c, PyObject *mapping, PyObject **result) +{ + PyObject *w = PyInt_FromLong((long)c); + PyObject *x; + + if (w == NULL) + return -1; + x = PyObject_GetItem(mapping, w); + Py_DECREF(w); + if (x == NULL) { + if (PyErr_ExceptionMatches(PyExc_LookupError)) { + /* No mapping found means: use 1:1 mapping. */ + PyErr_Clear(); + *result = NULL; + return 0; + } else + return -1; + } + else if (x == Py_None) { + *result = x; + return 0; + } + else if (PyInt_Check(x)) { + long value = PyInt_AS_LONG(x); + long max = PyUnicode_GetMax(); + if (value < 0 || value > max) { + PyErr_Format(PyExc_TypeError, + "character mapping must be in range(0x%lx)", max+1); + Py_DECREF(x); + return -1; + } + *result = x; + return 0; + } + else if (PyUnicode_Check(x)) { + *result = x; + return 0; + } + else { + /* wrong return value */ + PyErr_SetString(PyExc_TypeError, + "character mapping must return integer, None or unicode"); + Py_DECREF(x); + return -1; + } +} +/* ensure that *outobj is at least requiredsize characters long, +if not reallocate and adjust various state variables. +Return 0 on success, -1 on error */ +static +int charmaptranslate_makespace(PyObject **outobj, Py_UNICODE **outp, + Py_ssize_t requiredsize) +{ + Py_ssize_t oldsize = PyUnicode_GET_SIZE(*outobj); + if (requiredsize > oldsize) { + /* remember old output position */ + Py_ssize_t outpos = *outp-PyUnicode_AS_UNICODE(*outobj); + /* exponentially overallocate to minimize reallocations */ + if (requiredsize < 2 * oldsize) + requiredsize = 2 * oldsize; + if (_PyUnicode_Resize(outobj, requiredsize) < 0) + return -1; + *outp = PyUnicode_AS_UNICODE(*outobj) + outpos; + } + return 0; +} +/* lookup the character, put the result in the output string and adjust + various state variables. Return a new reference to the object that + was put in the output buffer in *result, or Py_None, if the mapping was + undefined (in which case no character was written). + The called must decref result. + Return 0 on success, -1 on error. */ +static +int charmaptranslate_output(const Py_UNICODE *startinp, const Py_UNICODE *curinp, + Py_ssize_t insize, PyObject *mapping, PyObject **outobj, Py_UNICODE **outp, + PyObject **res) +{ + if (charmaptranslate_lookup(*curinp, mapping, res)) + return -1; + if (*res==NULL) { + /* not found => default to 1:1 mapping */ + *(*outp)++ = *curinp; + } + else if (*res==Py_None) + ; + else if (PyInt_Check(*res)) { + /* no overflow check, because we know that the space is enough */ + *(*outp)++ = (Py_UNICODE)PyInt_AS_LONG(*res); + } + else if (PyUnicode_Check(*res)) { + Py_ssize_t repsize = PyUnicode_GET_SIZE(*res); + if (repsize==1) { + /* no overflow check, because we know that the space is enough */ + *(*outp)++ = *PyUnicode_AS_UNICODE(*res); + } + else if (repsize!=0) { + /* more than one character */ + Py_ssize_t requiredsize = (*outp-PyUnicode_AS_UNICODE(*outobj)) + + (insize - (curinp-startinp)) + + repsize - 1; + if (charmaptranslate_makespace(outobj, outp, requiredsize)) + return -1; + memcpy(*outp, PyUnicode_AS_UNICODE(*res), sizeof(Py_UNICODE)*repsize); + *outp += repsize; + } + } + else + return -1; + return 0; +} + +PyObject *PyUnicode_TranslateCharmap(const Py_UNICODE *p, + Py_ssize_t size, + PyObject *mapping, + const char *errors) +{ + /* output object */ + PyObject *res = NULL; + /* pointers to the beginning and end+1 of input */ + const Py_UNICODE *startp = p; + const Py_UNICODE *endp = p + size; + /* pointer into the output */ + Py_UNICODE *str; + /* current output position */ + Py_ssize_t respos = 0; + char *reason = "character maps to <undefined>"; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + /* the following variable is used for caching string comparisons + * -1=not initialized, 0=unknown, 1=strict, 2=replace, + * 3=ignore, 4=xmlcharrefreplace */ + int known_errorHandler = -1; + + if (mapping == NULL) { + PyErr_BadArgument(); + return NULL; + } + + /* allocate enough for a simple 1:1 translation without + replacements, if we need more, we'll resize */ + res = PyUnicode_FromUnicode(NULL, size); + if (res == NULL) + goto onError; + if (size == 0) + return res; + str = PyUnicode_AS_UNICODE(res); + + while (p<endp) { + /* try to encode it */ + PyObject *x = NULL; + if (charmaptranslate_output(startp, p, size, mapping, &res, &str, &x)) { + Py_XDECREF(x); + goto onError; + } + Py_XDECREF(x); + if (x!=Py_None) /* it worked => adjust input pointer */ + ++p; + else { /* untranslatable character */ + PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ + Py_ssize_t repsize; + Py_ssize_t newpos; + Py_UNICODE *uni2; + /* startpos for collecting untranslatable chars */ + const Py_UNICODE *collstart = p; + const Py_UNICODE *collend = p+1; + const Py_UNICODE *coll; + + /* find all untranslatable characters */ + while (collend < endp) { + if (charmaptranslate_lookup(*collend, mapping, &x)) + goto onError; + Py_XDECREF(x); + if (x!=Py_None) + break; + ++collend; + } + /* cache callback name lookup + * (if not done yet, i.e. it's the first error) */ + if (known_errorHandler==-1) { + if ((errors==NULL) || (!strcmp(errors, "strict"))) + known_errorHandler = 1; + else if (!strcmp(errors, "replace")) + known_errorHandler = 2; + else if (!strcmp(errors, "ignore")) + known_errorHandler = 3; + else if (!strcmp(errors, "xmlcharrefreplace")) + known_errorHandler = 4; + else + known_errorHandler = 0; + } + switch (known_errorHandler) { + case 1: /* strict */ + raise_translate_exception(&exc, startp, size, collstart-startp, collend-startp, reason); + goto onError; + case 2: /* replace */ + /* No need to check for space, this is a 1:1 replacement */ + for (coll = collstart; coll<collend; ++coll) + *str++ = '?'; + /* fall through */ + case 3: /* ignore */ + p = collend; + break; + case 4: /* xmlcharrefreplace */ + /* generate replacement (temporarily (mis)uses p) */ + for (p = collstart; p < collend; ++p) { + char buffer[2+29+1+1]; + char *cp; + sprintf(buffer, "&#%d;", (int)*p); + if (charmaptranslate_makespace(&res, &str, + (str-PyUnicode_AS_UNICODE(res))+strlen(buffer)+(endp-collend))) + goto onError; + for (cp = buffer; *cp; ++cp) + *str++ = *cp; + } + p = collend; + break; + default: + repunicode = unicode_translate_call_errorhandler(errors, &errorHandler, + reason, startp, size, &exc, + collstart-startp, collend-startp, &newpos); + if (repunicode == NULL) + goto onError; + /* generate replacement */ + repsize = PyUnicode_GET_SIZE(repunicode); + if (charmaptranslate_makespace(&res, &str, + (str-PyUnicode_AS_UNICODE(res))+repsize+(endp-collend))) { + Py_DECREF(repunicode); + goto onError; + } + for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) + *str++ = *uni2; + p = startp + newpos; + Py_DECREF(repunicode); + } + } + } + /* Resize if we allocated to much */ + respos = str-PyUnicode_AS_UNICODE(res); + if (respos<PyUnicode_GET_SIZE(res)) { + if (_PyUnicode_Resize(&res, respos) < 0) + goto onError; + } + Py_XDECREF(exc); + Py_XDECREF(errorHandler); + return res; + + onError: + Py_XDECREF(res); + Py_XDECREF(exc); + Py_XDECREF(errorHandler); + return NULL; +} + +PyObject *PyUnicode_Translate(PyObject *str, + PyObject *mapping, + const char *errors) +{ + PyObject *result; + + str = PyUnicode_FromObject(str); + if (str == NULL) + goto onError; + result = PyUnicode_TranslateCharmap(PyUnicode_AS_UNICODE(str), + PyUnicode_GET_SIZE(str), + mapping, + errors); + Py_DECREF(str); + return result; + + onError: + Py_XDECREF(str); + return NULL; +} + +/* --- Decimal Encoder ---------------------------------------------------- */ + +int PyUnicode_EncodeDecimal(Py_UNICODE *s, + Py_ssize_t length, + char *output, + const char *errors) +{ + Py_UNICODE *p, *end; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + const char *encoding = "decimal"; + const char *reason = "invalid decimal Unicode string"; + /* the following variable is used for caching string comparisons + * -1=not initialized, 0=unknown, 1=strict, 2=replace, 3=ignore, 4=xmlcharrefreplace */ + int known_errorHandler = -1; + + if (output == NULL) { + PyErr_BadArgument(); + return -1; + } + + p = s; + end = s + length; + while (p < end) { + register Py_UNICODE ch = *p; + int decimal; + PyObject *repunicode; + Py_ssize_t repsize; + Py_ssize_t newpos; + Py_UNICODE *uni2; + Py_UNICODE *collstart; + Py_UNICODE *collend; + + if (Py_UNICODE_ISSPACE(ch)) { + *output++ = ' '; + ++p; + continue; + } + decimal = Py_UNICODE_TODECIMAL(ch); + if (decimal >= 0) { + *output++ = '0' + decimal; + ++p; + continue; + } + if (0 < ch && ch < 256) { + *output++ = (char)ch; + ++p; + continue; + } + /* All other characters are considered unencodable */ + collstart = p; + collend = p+1; + while (collend < end) { + if ((0 < *collend && *collend < 256) || + !Py_UNICODE_ISSPACE(*collend) || + Py_UNICODE_TODECIMAL(*collend)) + break; + } + /* cache callback name lookup + * (if not done yet, i.e. it's the first error) */ + if (known_errorHandler==-1) { + if ((errors==NULL) || (!strcmp(errors, "strict"))) + known_errorHandler = 1; + else if (!strcmp(errors, "replace")) + known_errorHandler = 2; + else if (!strcmp(errors, "ignore")) + known_errorHandler = 3; + else if (!strcmp(errors, "xmlcharrefreplace")) + known_errorHandler = 4; + else + known_errorHandler = 0; + } + switch (known_errorHandler) { + case 1: /* strict */ + raise_encode_exception(&exc, encoding, s, length, collstart-s, collend-s, reason); + goto onError; + case 2: /* replace */ + for (p = collstart; p < collend; ++p) + *output++ = '?'; + /* fall through */ + case 3: /* ignore */ + p = collend; + break; + case 4: /* xmlcharrefreplace */ + /* generate replacement (temporarily (mis)uses p) */ + for (p = collstart; p < collend; ++p) + output += sprintf(output, "&#%d;", (int)*p); + p = collend; + break; + default: + repunicode = unicode_encode_call_errorhandler(errors, &errorHandler, + encoding, reason, s, length, &exc, + collstart-s, collend-s, &newpos); + if (repunicode == NULL) + goto onError; + /* generate replacement */ + repsize = PyUnicode_GET_SIZE(repunicode); + for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) { + Py_UNICODE ch = *uni2; + if (Py_UNICODE_ISSPACE(ch)) + *output++ = ' '; + else { + decimal = Py_UNICODE_TODECIMAL(ch); + if (decimal >= 0) + *output++ = '0' + decimal; + else if (0 < ch && ch < 256) + *output++ = (char)ch; + else { + Py_DECREF(repunicode); + raise_encode_exception(&exc, encoding, + s, length, collstart-s, collend-s, reason); + goto onError; + } + } + } + p = s + newpos; + Py_DECREF(repunicode); + } + } + /* 0-terminate the output string */ + *output++ = '\0'; + Py_XDECREF(exc); + Py_XDECREF(errorHandler); + return 0; + + onError: + Py_XDECREF(exc); + Py_XDECREF(errorHandler); + return -1; +} + +/* --- Helpers ------------------------------------------------------------ */ + +#define STRINGLIB_CHAR Py_UNICODE + +#define STRINGLIB_LEN PyUnicode_GET_SIZE +#define STRINGLIB_NEW PyUnicode_FromUnicode +#define STRINGLIB_STR PyUnicode_AS_UNICODE + +Py_LOCAL_INLINE(int) +STRINGLIB_CMP(const Py_UNICODE* str, const Py_UNICODE* other, Py_ssize_t len) +{ + if (str[0] != other[0]) + return 1; + return memcmp((void*) str, (void*) other, len * sizeof(Py_UNICODE)); +} + +#define STRINGLIB_EMPTY unicode_empty + +#include "stringlib/fastsearch.h" + +#include "stringlib/count.h" +#include "stringlib/find.h" +#include "stringlib/partition.h" + +/* helper macro to fixup start/end slice values */ +#define FIX_START_END(obj) \ + if (start < 0) \ + start += (obj)->length; \ + if (start < 0) \ + start = 0; \ + if (end > (obj)->length) \ + end = (obj)->length; \ + if (end < 0) \ + end += (obj)->length; \ + if (end < 0) \ + end = 0; + +Py_ssize_t PyUnicode_Count(PyObject *str, + PyObject *substr, + Py_ssize_t start, + Py_ssize_t end) +{ + Py_ssize_t result; + PyUnicodeObject* str_obj; + PyUnicodeObject* sub_obj; + + str_obj = (PyUnicodeObject*) PyUnicode_FromObject(str); + if (!str_obj) + return -1; + sub_obj = (PyUnicodeObject*) PyUnicode_FromObject(substr); + if (!sub_obj) { + Py_DECREF(str_obj); + return -1; + } + + FIX_START_END(str_obj); + + result = stringlib_count( + str_obj->str + start, end - start, sub_obj->str, sub_obj->length + ); + + Py_DECREF(sub_obj); + Py_DECREF(str_obj); + + return result; +} + +Py_ssize_t PyUnicode_Find(PyObject *str, + PyObject *sub, + Py_ssize_t start, + Py_ssize_t end, + int direction) +{ + Py_ssize_t result; + + str = PyUnicode_FromObject(str); + if (!str) + return -2; + sub = PyUnicode_FromObject(sub); + if (!sub) { + Py_DECREF(str); + return -2; + } + + if (direction > 0) + result = stringlib_find_slice( + PyUnicode_AS_UNICODE(str), PyUnicode_GET_SIZE(str), + PyUnicode_AS_UNICODE(sub), PyUnicode_GET_SIZE(sub), + start, end + ); + else + result = stringlib_rfind_slice( + PyUnicode_AS_UNICODE(str), PyUnicode_GET_SIZE(str), + PyUnicode_AS_UNICODE(sub), PyUnicode_GET_SIZE(sub), + start, end + ); + + Py_DECREF(str); + Py_DECREF(sub); + + return result; +} + +static +int tailmatch(PyUnicodeObject *self, + PyUnicodeObject *substring, + Py_ssize_t start, + Py_ssize_t end, + int direction) +{ + if (substring->length == 0) + return 1; + + FIX_START_END(self); + + end -= substring->length; + if (end < start) + return 0; + + if (direction > 0) { + if (Py_UNICODE_MATCH(self, end, substring)) + return 1; + } else { + if (Py_UNICODE_MATCH(self, start, substring)) + return 1; + } + + return 0; +} + +Py_ssize_t PyUnicode_Tailmatch(PyObject *str, + PyObject *substr, + Py_ssize_t start, + Py_ssize_t end, + int direction) +{ + Py_ssize_t result; + + str = PyUnicode_FromObject(str); + if (str == NULL) + return -1; + substr = PyUnicode_FromObject(substr); + if (substr == NULL) { + Py_DECREF(str); + return -1; + } + + result = tailmatch((PyUnicodeObject *)str, + (PyUnicodeObject *)substr, + start, end, direction); + Py_DECREF(str); + Py_DECREF(substr); + return result; +} + +/* Apply fixfct filter to the Unicode object self and return a + reference to the modified object */ + +static +PyObject *fixup(PyUnicodeObject *self, + int (*fixfct)(PyUnicodeObject *s)) +{ + + PyUnicodeObject *u; + + u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length); + if (u == NULL) + return NULL; + + Py_UNICODE_COPY(u->str, self->str, self->length); + + if (!fixfct(u) && PyUnicode_CheckExact(self)) { + /* fixfct should return TRUE if it modified the buffer. If + FALSE, return a reference to the original buffer instead + (to save space, not time) */ + Py_INCREF(self); + Py_DECREF(u); + return (PyObject*) self; + } + return (PyObject*) u; +} + +static +int fixupper(PyUnicodeObject *self) +{ + Py_ssize_t len = self->length; + Py_UNICODE *s = self->str; + int status = 0; + + while (len-- > 0) { + register Py_UNICODE ch; + + ch = Py_UNICODE_TOUPPER(*s); + if (ch != *s) { + status = 1; + *s = ch; + } + s++; + } + + return status; +} + +static +int fixlower(PyUnicodeObject *self) +{ + Py_ssize_t len = self->length; + Py_UNICODE *s = self->str; + int status = 0; + + while (len-- > 0) { + register Py_UNICODE ch; + + ch = Py_UNICODE_TOLOWER(*s); + if (ch != *s) { + status = 1; + *s = ch; + } + s++; + } + + return status; +} + +static +int fixswapcase(PyUnicodeObject *self) +{ + Py_ssize_t len = self->length; + Py_UNICODE *s = self->str; + int status = 0; + + while (len-- > 0) { + if (Py_UNICODE_ISUPPER(*s)) { + *s = Py_UNICODE_TOLOWER(*s); + status = 1; + } else if (Py_UNICODE_ISLOWER(*s)) { + *s = Py_UNICODE_TOUPPER(*s); + status = 1; + } + s++; + } + + return status; +} + +static +int fixcapitalize(PyUnicodeObject *self) +{ + Py_ssize_t len = self->length; + Py_UNICODE *s = self->str; + int status = 0; + + if (len == 0) + return 0; + if (Py_UNICODE_ISLOWER(*s)) { + *s = Py_UNICODE_TOUPPER(*s); + status = 1; + } + s++; + while (--len > 0) { + if (Py_UNICODE_ISUPPER(*s)) { + *s = Py_UNICODE_TOLOWER(*s); + status = 1; + } + s++; + } + return status; +} + +static +int fixtitle(PyUnicodeObject *self) +{ + register Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register Py_UNICODE *e; + int previous_is_cased; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1) { + Py_UNICODE ch = Py_UNICODE_TOTITLE(*p); + if (*p != ch) { + *p = ch; + return 1; + } + else + return 0; + } + + e = p + PyUnicode_GET_SIZE(self); + previous_is_cased = 0; + for (; p < e; p++) { + register const Py_UNICODE ch = *p; + + if (previous_is_cased) + *p = Py_UNICODE_TOLOWER(ch); + else + *p = Py_UNICODE_TOTITLE(ch); + + if (Py_UNICODE_ISLOWER(ch) || + Py_UNICODE_ISUPPER(ch) || + Py_UNICODE_ISTITLE(ch)) + previous_is_cased = 1; + else + previous_is_cased = 0; + } + return 1; +} + +PyObject * +PyUnicode_Join(PyObject *separator, PyObject *seq) +{ + PyObject *internal_separator = NULL; + const Py_UNICODE blank = ' '; + const Py_UNICODE *sep = &blank; + Py_ssize_t seplen = 1; + PyUnicodeObject *res = NULL; /* the result */ + Py_ssize_t res_alloc = 100; /* # allocated bytes for string in res */ + Py_ssize_t res_used; /* # used bytes */ + Py_UNICODE *res_p; /* pointer to free byte in res's string area */ + PyObject *fseq; /* PySequence_Fast(seq) */ + Py_ssize_t seqlen; /* len(fseq) -- number of items in sequence */ + PyObject *item; + Py_ssize_t i; + + fseq = PySequence_Fast(seq, ""); + if (fseq == NULL) { + return NULL; + } + + /* Grrrr. A codec may be invoked to convert str objects to + * Unicode, and so it's possible to call back into Python code + * during PyUnicode_FromObject(), and so it's possible for a sick + * codec to change the size of fseq (if seq is a list). Therefore + * we have to keep refetching the size -- can't assume seqlen + * is invariant. + */ + seqlen = PySequence_Fast_GET_SIZE(fseq); + /* If empty sequence, return u"". */ + if (seqlen == 0) { + res = _PyUnicode_New(0); /* empty sequence; return u"" */ + goto Done; + } + /* If singleton sequence with an exact Unicode, return that. */ + if (seqlen == 1) { + item = PySequence_Fast_GET_ITEM(fseq, 0); + if (PyUnicode_CheckExact(item)) { + Py_INCREF(item); + res = (PyUnicodeObject *)item; + goto Done; + } + } + + /* At least two items to join, or one that isn't exact Unicode. */ + if (seqlen > 1) { + /* Set up sep and seplen -- they're needed. */ + if (separator == NULL) { + sep = &blank; + seplen = 1; + } + else { + internal_separator = PyUnicode_FromObject(separator); + if (internal_separator == NULL) + goto onError; + sep = PyUnicode_AS_UNICODE(internal_separator); + seplen = PyUnicode_GET_SIZE(internal_separator); + /* In case PyUnicode_FromObject() mutated seq. */ + seqlen = PySequence_Fast_GET_SIZE(fseq); + } + } + + /* Get space. */ + res = _PyUnicode_New(res_alloc); + if (res == NULL) + goto onError; + res_p = PyUnicode_AS_UNICODE(res); + res_used = 0; + + for (i = 0; i < seqlen; ++i) { + Py_ssize_t itemlen; + Py_ssize_t new_res_used; + + item = PySequence_Fast_GET_ITEM(fseq, i); + /* Convert item to Unicode. */ + if (! PyUnicode_Check(item) && ! PyString_Check(item)) { + PyErr_Format(PyExc_TypeError, + "sequence item %zd: expected string or Unicode," + " %.80s found", + i, item->ob_type->tp_name); + goto onError; + } + item = PyUnicode_FromObject(item); + if (item == NULL) + goto onError; + /* We own a reference to item from here on. */ + + /* In case PyUnicode_FromObject() mutated seq. */ + seqlen = PySequence_Fast_GET_SIZE(fseq); + + /* Make sure we have enough space for the separator and the item. */ + itemlen = PyUnicode_GET_SIZE(item); + new_res_used = res_used + itemlen; + if (new_res_used < 0) + goto Overflow; + if (i < seqlen - 1) { + new_res_used += seplen; + if (new_res_used < 0) + goto Overflow; + } + if (new_res_used > res_alloc) { + /* double allocated size until it's big enough */ + do { + res_alloc += res_alloc; + if (res_alloc <= 0) + goto Overflow; + } while (new_res_used > res_alloc); + if (_PyUnicode_Resize(&res, res_alloc) < 0) { + Py_DECREF(item); + goto onError; + } + res_p = PyUnicode_AS_UNICODE(res) + res_used; + } + + /* Copy item, and maybe the separator. */ + Py_UNICODE_COPY(res_p, PyUnicode_AS_UNICODE(item), itemlen); + res_p += itemlen; + if (i < seqlen - 1) { + Py_UNICODE_COPY(res_p, sep, seplen); + res_p += seplen; + } + Py_DECREF(item); + res_used = new_res_used; + } + + /* Shrink res to match the used area; this probably can't fail, + * but it's cheap to check. + */ + if (_PyUnicode_Resize(&res, res_used) < 0) + goto onError; + + Done: + Py_XDECREF(internal_separator); + Py_DECREF(fseq); + return (PyObject *)res; + + Overflow: + PyErr_SetString(PyExc_OverflowError, + "join() result is too long for a Python string"); + Py_DECREF(item); + /* fall through */ + + onError: + Py_XDECREF(internal_separator); + Py_DECREF(fseq); + Py_XDECREF(res); + return NULL; +} + +static +PyUnicodeObject *pad(PyUnicodeObject *self, + Py_ssize_t left, + Py_ssize_t right, + Py_UNICODE fill) +{ + PyUnicodeObject *u; + + if (left < 0) + left = 0; + if (right < 0) + right = 0; + + if (left == 0 && right == 0 && PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return self; + } + + u = _PyUnicode_New(left + self->length + right); + if (u) { + if (left) + Py_UNICODE_FILL(u->str, fill, left); + Py_UNICODE_COPY(u->str + left, self->str, self->length); + if (right) + Py_UNICODE_FILL(u->str + left + self->length, fill, right); + } + + return u; +} + +#define SPLIT_APPEND(data, left, right) \ + str = PyUnicode_FromUnicode((data) + (left), (right) - (left)); \ + if (!str) \ + goto onError; \ + if (PyList_Append(list, str)) { \ + Py_DECREF(str); \ + goto onError; \ + } \ + else \ + Py_DECREF(str); + +static +PyObject *split_whitespace(PyUnicodeObject *self, + PyObject *list, + Py_ssize_t maxcount) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len = self->length; + PyObject *str; + + for (i = j = 0; i < len; ) { + /* find a token */ + while (i < len && Py_UNICODE_ISSPACE(self->str[i])) + i++; + j = i; + while (i < len && !Py_UNICODE_ISSPACE(self->str[i])) + i++; + if (j < i) { + if (maxcount-- <= 0) + break; + SPLIT_APPEND(self->str, j, i); + while (i < len && Py_UNICODE_ISSPACE(self->str[i])) + i++; + j = i; + } + } + if (j < len) { + SPLIT_APPEND(self->str, j, len); + } + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +PyObject *PyUnicode_Splitlines(PyObject *string, + int keepends) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len; + PyObject *list; + PyObject *str; + Py_UNICODE *data; + + string = PyUnicode_FromObject(string); + if (string == NULL) + return NULL; + data = PyUnicode_AS_UNICODE(string); + len = PyUnicode_GET_SIZE(string); + + list = PyList_New(0); + if (!list) + goto onError; + + for (i = j = 0; i < len; ) { + Py_ssize_t eol; + + /* Find a line and append it */ + while (i < len && !BLOOM_LINEBREAK(data[i])) + i++; + + /* Skip the line break reading CRLF as one line break */ + eol = i; + if (i < len) { + if (data[i] == '\r' && i + 1 < len && + data[i+1] == '\n') + i += 2; + else + i++; + if (keepends) + eol = i; + } + SPLIT_APPEND(data, j, eol); + j = i; + } + if (j < len) { + SPLIT_APPEND(data, j, len); + } + + Py_DECREF(string); + return list; + + onError: + Py_XDECREF(list); + Py_DECREF(string); + return NULL; +} + +static +PyObject *split_char(PyUnicodeObject *self, + PyObject *list, + Py_UNICODE ch, + Py_ssize_t maxcount) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len = self->length; + PyObject *str; + + for (i = j = 0; i < len; ) { + if (self->str[i] == ch) { + if (maxcount-- <= 0) + break; + SPLIT_APPEND(self->str, j, i); + i = j = i + 1; + } else + i++; + } + if (j <= len) { + SPLIT_APPEND(self->str, j, len); + } + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +static +PyObject *split_substring(PyUnicodeObject *self, + PyObject *list, + PyUnicodeObject *substring, + Py_ssize_t maxcount) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len = self->length; + Py_ssize_t sublen = substring->length; + PyObject *str; + + for (i = j = 0; i <= len - sublen; ) { + if (Py_UNICODE_MATCH(self, i, substring)) { + if (maxcount-- <= 0) + break; + SPLIT_APPEND(self->str, j, i); + i = j = i + sublen; + } else + i++; + } + if (j <= len) { + SPLIT_APPEND(self->str, j, len); + } + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +static +PyObject *rsplit_whitespace(PyUnicodeObject *self, + PyObject *list, + Py_ssize_t maxcount) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len = self->length; + PyObject *str; + + for (i = j = len - 1; i >= 0; ) { + /* find a token */ + while (i >= 0 && Py_UNICODE_ISSPACE(self->str[i])) + i--; + j = i; + while (i >= 0 && !Py_UNICODE_ISSPACE(self->str[i])) + i--; + if (j > i) { + if (maxcount-- <= 0) + break; + SPLIT_APPEND(self->str, i + 1, j + 1); + while (i >= 0 && Py_UNICODE_ISSPACE(self->str[i])) + i--; + j = i; + } + } + if (j >= 0) { + SPLIT_APPEND(self->str, 0, j + 1); + } + if (PyList_Reverse(list) < 0) + goto onError; + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +static +PyObject *rsplit_char(PyUnicodeObject *self, + PyObject *list, + Py_UNICODE ch, + Py_ssize_t maxcount) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len = self->length; + PyObject *str; + + for (i = j = len - 1; i >= 0; ) { + if (self->str[i] == ch) { + if (maxcount-- <= 0) + break; + SPLIT_APPEND(self->str, i + 1, j + 1); + j = i = i - 1; + } else + i--; + } + if (j >= -1) { + SPLIT_APPEND(self->str, 0, j + 1); + } + if (PyList_Reverse(list) < 0) + goto onError; + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +static +PyObject *rsplit_substring(PyUnicodeObject *self, + PyObject *list, + PyUnicodeObject *substring, + Py_ssize_t maxcount) +{ + register Py_ssize_t i; + register Py_ssize_t j; + Py_ssize_t len = self->length; + Py_ssize_t sublen = substring->length; + PyObject *str; + + for (i = len - sublen, j = len; i >= 0; ) { + if (Py_UNICODE_MATCH(self, i, substring)) { + if (maxcount-- <= 0) + break; + SPLIT_APPEND(self->str, i + sublen, j); + j = i; + i -= sublen; + } else + i--; + } + if (j >= 0) { + SPLIT_APPEND(self->str, 0, j); + } + if (PyList_Reverse(list) < 0) + goto onError; + return list; + + onError: + Py_DECREF(list); + return NULL; +} + +#undef SPLIT_APPEND + +static +PyObject *split(PyUnicodeObject *self, + PyUnicodeObject *substring, + Py_ssize_t maxcount) +{ + PyObject *list; + + if (maxcount < 0) + maxcount = PY_SSIZE_T_MAX; + + list = PyList_New(0); + if (!list) + return NULL; + + if (substring == NULL) + return split_whitespace(self,list,maxcount); + + else if (substring->length == 1) + return split_char(self,list,substring->str[0],maxcount); + + else if (substring->length == 0) { + Py_DECREF(list); + PyErr_SetString(PyExc_ValueError, "empty separator"); + return NULL; + } + else + return split_substring(self,list,substring,maxcount); +} + +static +PyObject *rsplit(PyUnicodeObject *self, + PyUnicodeObject *substring, + Py_ssize_t maxcount) +{ + PyObject *list; + + if (maxcount < 0) + maxcount = PY_SSIZE_T_MAX; + + list = PyList_New(0); + if (!list) + return NULL; + + if (substring == NULL) + return rsplit_whitespace(self,list,maxcount); + + else if (substring->length == 1) + return rsplit_char(self,list,substring->str[0],maxcount); + + else if (substring->length == 0) { + Py_DECREF(list); + PyErr_SetString(PyExc_ValueError, "empty separator"); + return NULL; + } + else + return rsplit_substring(self,list,substring,maxcount); +} + +static +PyObject *replace(PyUnicodeObject *self, + PyUnicodeObject *str1, + PyUnicodeObject *str2, + Py_ssize_t maxcount) +{ + PyUnicodeObject *u; + + if (maxcount < 0) + maxcount = PY_SSIZE_T_MAX; + + if (str1->length == str2->length) { + /* same length */ + Py_ssize_t i; + if (str1->length == 1) { + /* replace characters */ + Py_UNICODE u1, u2; + if (!findchar(self->str, self->length, str1->str[0])) + goto nothing; + u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length); + if (!u) + return NULL; + Py_UNICODE_COPY(u->str, self->str, self->length); + u1 = str1->str[0]; + u2 = str2->str[0]; + for (i = 0; i < u->length; i++) + if (u->str[i] == u1) { + if (--maxcount < 0) + break; + u->str[i] = u2; + } + } else { + i = fastsearch( + self->str, self->length, str1->str, str1->length, FAST_SEARCH + ); + if (i < 0) + goto nothing; + u = (PyUnicodeObject*) PyUnicode_FromUnicode(NULL, self->length); + if (!u) + return NULL; + Py_UNICODE_COPY(u->str, self->str, self->length); + while (i <= self->length - str1->length) + if (Py_UNICODE_MATCH(self, i, str1)) { + if (--maxcount < 0) + break; + Py_UNICODE_COPY(u->str+i, str2->str, str2->length); + i += str1->length; + } else + i++; + } + } else { + + Py_ssize_t n, i, j, e; + Py_ssize_t product, new_size, delta; + Py_UNICODE *p; + + /* replace strings */ + n = stringlib_count(self->str, self->length, str1->str, str1->length); + if (n > maxcount) + n = maxcount; + if (n == 0) + goto nothing; + /* new_size = self->length + n * (str2->length - str1->length)); */ + delta = (str2->length - str1->length); + if (delta == 0) { + new_size = self->length; + } else { + product = n * (str2->length - str1->length); + if ((product / (str2->length - str1->length)) != n) { + PyErr_SetString(PyExc_OverflowError, + "replace string is too long"); + return NULL; + } + new_size = self->length + product; + if (new_size < 0) { + PyErr_SetString(PyExc_OverflowError, + "replace string is too long"); + return NULL; + } + } + u = _PyUnicode_New(new_size); + if (!u) + return NULL; + i = 0; + p = u->str; + e = self->length - str1->length; + if (str1->length > 0) { + while (n-- > 0) { + /* look for next match */ + j = i; + while (j <= e) { + if (Py_UNICODE_MATCH(self, j, str1)) + break; + j++; + } + if (j > i) { + if (j > e) + break; + /* copy unchanged part [i:j] */ + Py_UNICODE_COPY(p, self->str+i, j-i); + p += j - i; + } + /* copy substitution string */ + if (str2->length > 0) { + Py_UNICODE_COPY(p, str2->str, str2->length); + p += str2->length; + } + i = j + str1->length; + } + if (i < self->length) + /* copy tail [i:] */ + Py_UNICODE_COPY(p, self->str+i, self->length-i); + } else { + /* interleave */ + while (n > 0) { + Py_UNICODE_COPY(p, str2->str, str2->length); + p += str2->length; + if (--n <= 0) + break; + *p++ = self->str[i++]; + } + Py_UNICODE_COPY(p, self->str+i, self->length-i); + } + } + return (PyObject *) u; + +nothing: + /* nothing to replace; return original string (when possible) */ + if (PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return (PyObject *) self; + } + return PyUnicode_FromUnicode(self->str, self->length); +} + +/* --- Unicode Object Methods --------------------------------------------- */ + +PyDoc_STRVAR(title__doc__, +"S.title() -> unicode\n\ +\n\ +Return a titlecased version of S, i.e. words start with title case\n\ +characters, all remaining cased characters have lower case."); + +static PyObject* +unicode_title(PyUnicodeObject *self) +{ + return fixup(self, fixtitle); +} + +PyDoc_STRVAR(capitalize__doc__, +"S.capitalize() -> unicode\n\ +\n\ +Return a capitalized version of S, i.e. make the first character\n\ +have upper case."); + +static PyObject* +unicode_capitalize(PyUnicodeObject *self) +{ + return fixup(self, fixcapitalize); +} + +#if 0 +PyDoc_STRVAR(capwords__doc__, +"S.capwords() -> unicode\n\ +\n\ +Apply .capitalize() to all words in S and return the result with\n\ +normalized whitespace (all whitespace strings are replaced by ' ')."); + +static PyObject* +unicode_capwords(PyUnicodeObject *self) +{ + PyObject *list; + PyObject *item; + Py_ssize_t i; + + /* Split into words */ + list = split(self, NULL, -1); + if (!list) + return NULL; + + /* Capitalize each word */ + for (i = 0; i < PyList_GET_SIZE(list); i++) { + item = fixup((PyUnicodeObject *)PyList_GET_ITEM(list, i), + fixcapitalize); + if (item == NULL) + goto onError; + Py_DECREF(PyList_GET_ITEM(list, i)); + PyList_SET_ITEM(list, i, item); + } + + /* Join the words to form a new string */ + item = PyUnicode_Join(NULL, list); + +onError: + Py_DECREF(list); + return (PyObject *)item; +} +#endif + +/* Argument converter. Coerces to a single unicode character */ + +static int +convert_uc(PyObject *obj, void *addr) +{ + Py_UNICODE *fillcharloc = (Py_UNICODE *)addr; + PyObject *uniobj; + Py_UNICODE *unistr; + + uniobj = PyUnicode_FromObject(obj); + if (uniobj == NULL) { + PyErr_SetString(PyExc_TypeError, + "The fill character cannot be converted to Unicode"); + return 0; + } + if (PyUnicode_GET_SIZE(uniobj) != 1) { + PyErr_SetString(PyExc_TypeError, + "The fill character must be exactly one character long"); + Py_DECREF(uniobj); + return 0; + } + unistr = PyUnicode_AS_UNICODE(uniobj); + *fillcharloc = unistr[0]; + Py_DECREF(uniobj); + return 1; +} + +PyDoc_STRVAR(center__doc__, +"S.center(width[, fillchar]) -> unicode\n\ +\n\ +Return S centered in a Unicode string of length width. Padding is\n\ +done using the specified fill character (default is a space)"); + +static PyObject * +unicode_center(PyUnicodeObject *self, PyObject *args) +{ + Py_ssize_t marg, left; + Py_ssize_t width; + Py_UNICODE fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|O&:center", &width, convert_uc, &fillchar)) + return NULL; + + if (self->length >= width && PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + + marg = width - self->length; + left = marg / 2 + (marg & width & 1); + + return (PyObject*) pad(self, left, marg - left, fillchar); +} + +#if 0 + +/* This code should go into some future Unicode collation support + module. The basic comparison should compare ordinals on a naive + basis (this is what Java does and thus JPython too). */ + +/* speedy UTF-16 code point order comparison */ +/* gleaned from: */ +/* http://www-4.ibm.com/software/developer/library/utf16.html?dwzone=unicode */ + +static short utf16Fixup[32] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x2000, -0x800, -0x800, -0x800, -0x800 +}; + +static int +unicode_compare(PyUnicodeObject *str1, PyUnicodeObject *str2) +{ + Py_ssize_t len1, len2; + + Py_UNICODE *s1 = str1->str; + Py_UNICODE *s2 = str2->str; + + len1 = str1->length; + len2 = str2->length; + + while (len1 > 0 && len2 > 0) { + Py_UNICODE c1, c2; + + c1 = *s1++; + c2 = *s2++; + + if (c1 > (1<<11) * 26) + c1 += utf16Fixup[c1>>11]; + if (c2 > (1<<11) * 26) + c2 += utf16Fixup[c2>>11]; + /* now c1 and c2 are in UTF-32-compatible order */ + + if (c1 != c2) + return (c1 < c2) ? -1 : 1; + + len1--; len2--; + } + + return (len1 < len2) ? -1 : (len1 != len2); +} + +#else + +static int +unicode_compare(PyUnicodeObject *str1, PyUnicodeObject *str2) +{ + register Py_ssize_t len1, len2; + + Py_UNICODE *s1 = str1->str; + Py_UNICODE *s2 = str2->str; + + len1 = str1->length; + len2 = str2->length; + + while (len1 > 0 && len2 > 0) { + Py_UNICODE c1, c2; + + c1 = *s1++; + c2 = *s2++; + + if (c1 != c2) + return (c1 < c2) ? -1 : 1; + + len1--; len2--; + } + + return (len1 < len2) ? -1 : (len1 != len2); +} + +#endif + +int PyUnicode_Compare(PyObject *left, + PyObject *right) +{ + PyUnicodeObject *u = NULL, *v = NULL; + int result; + + /* Coerce the two arguments */ + u = (PyUnicodeObject *)PyUnicode_FromObject(left); + if (u == NULL) + goto onError; + v = (PyUnicodeObject *)PyUnicode_FromObject(right); + if (v == NULL) + goto onError; + + /* Shortcut for empty or interned objects */ + if (v == u) { + Py_DECREF(u); + Py_DECREF(v); + return 0; + } + + result = unicode_compare(u, v); + + Py_DECREF(u); + Py_DECREF(v); + return result; + +onError: + Py_XDECREF(u); + Py_XDECREF(v); + return -1; +} + +PyObject *PyUnicode_RichCompare(PyObject *left, + PyObject *right, + int op) +{ + int result; + + result = PyUnicode_Compare(left, right); + if (result == -1 && PyErr_Occurred()) + goto onError; + + /* Convert the return value to a Boolean */ + switch (op) { + case Py_EQ: + result = (result == 0); + break; + case Py_NE: + result = (result != 0); + break; + case Py_LE: + result = (result <= 0); + break; + case Py_GE: + result = (result >= 0); + break; + case Py_LT: + result = (result == -1); + break; + case Py_GT: + result = (result == 1); + break; + } + return PyBool_FromLong(result); + + onError: + + /* Standard case + + Type errors mean that PyUnicode_FromObject() could not convert + one of the arguments (usually the right hand side) to Unicode, + ie. we can't handle the comparison request. However, it is + possible that the other object knows a comparison method, which + is why we return Py_NotImplemented to give the other object a + chance. + + */ + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (op != Py_EQ && op != Py_NE) + return NULL; + + /* Equality comparison. + + This is a special case: we silence any PyExc_UnicodeDecodeError + and instead turn it into a PyErr_UnicodeWarning. + + */ + if (!PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) + return NULL; + PyErr_Clear(); + if (PyErr_Warn(PyExc_UnicodeWarning, + (op == Py_EQ) ? + "Unicode equal comparison " + "failed to convert both arguments to Unicode - " + "interpreting them as being unequal" : + "Unicode unequal comparison " + "failed to convert both arguments to Unicode - " + "interpreting them as being unequal" + ) < 0) + return NULL; + result = (op == Py_NE); + return PyBool_FromLong(result); +} + +int PyUnicode_Contains(PyObject *container, + PyObject *element) +{ + PyObject *str, *sub; + int result; + + /* Coerce the two arguments */ + sub = PyUnicode_FromObject(element); + if (!sub) { + PyErr_SetString(PyExc_TypeError, + "'in <string>' requires string as left operand"); + return -1; + } + + str = PyUnicode_FromObject(container); + if (!str) { + Py_DECREF(sub); + return -1; + } + + result = stringlib_contains_obj(str, sub); + + Py_DECREF(str); + Py_DECREF(sub); + + return result; +} + +/* Concat to string or Unicode object giving a new Unicode object. */ + +PyObject *PyUnicode_Concat(PyObject *left, + PyObject *right) +{ + PyUnicodeObject *u = NULL, *v = NULL, *w; + + /* Coerce the two arguments */ + u = (PyUnicodeObject *)PyUnicode_FromObject(left); + if (u == NULL) + goto onError; + v = (PyUnicodeObject *)PyUnicode_FromObject(right); + if (v == NULL) + goto onError; + + /* Shortcuts */ + if (v == unicode_empty) { + Py_DECREF(v); + return (PyObject *)u; + } + if (u == unicode_empty) { + Py_DECREF(u); + return (PyObject *)v; + } + + /* Concat the two Unicode strings */ + w = _PyUnicode_New(u->length + v->length); + if (w == NULL) + goto onError; + Py_UNICODE_COPY(w->str, u->str, u->length); + Py_UNICODE_COPY(w->str + u->length, v->str, v->length); + + Py_DECREF(u); + Py_DECREF(v); + return (PyObject *)w; + +onError: + Py_XDECREF(u); + Py_XDECREF(v); + return NULL; +} + +PyDoc_STRVAR(count__doc__, +"S.count(sub[, start[, end]]) -> int\n\ +\n\ +Return the number of non-overlapping occurrences of substring sub in\n\ +Unicode string S[start:end]. Optional arguments start and end are\n\ +interpreted as in slice notation."); + +static PyObject * +unicode_count(PyUnicodeObject *self, PyObject *args) +{ + PyUnicodeObject *substring; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + PyObject *result; + + if (!PyArg_ParseTuple(args, "O|O&O&:count", &substring, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + + substring = (PyUnicodeObject *)PyUnicode_FromObject( + (PyObject *)substring); + if (substring == NULL) + return NULL; + + FIX_START_END(self); + + result = PyInt_FromSsize_t( + stringlib_count(self->str + start, end - start, + substring->str, substring->length) + ); + + Py_DECREF(substring); + + return result; +} + +PyDoc_STRVAR(encode__doc__, +"S.encode([encoding[,errors]]) -> string or unicode\n\ +\n\ +Encodes S using the codec registered for encoding. encoding defaults\n\ +to the default encoding. errors may be given to set a different error\n\ +handling scheme. Default is 'strict' meaning that encoding errors raise\n\ +a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and\n\ +'xmlcharrefreplace' as well as any other name registered with\n\ +codecs.register_error that can handle UnicodeEncodeErrors."); + +static PyObject * +unicode_encode(PyUnicodeObject *self, PyObject *args) +{ + char *encoding = NULL; + char *errors = NULL; + PyObject *v; + + if (!PyArg_ParseTuple(args, "|ss:encode", &encoding, &errors)) + return NULL; + v = PyUnicode_AsEncodedObject((PyObject *)self, encoding, errors); + if (v == NULL) + goto onError; + if (!PyString_Check(v) && !PyUnicode_Check(v)) { + PyErr_Format(PyExc_TypeError, + "encoder did not return a string/unicode object " + "(type=%.400s)", + v->ob_type->tp_name); + Py_DECREF(v); + return NULL; + } + return v; + + onError: + return NULL; +} + +PyDoc_STRVAR(decode__doc__, +"S.decode([encoding[,errors]]) -> string or unicode\n\ +\n\ +Decodes S using the codec registered for encoding. encoding defaults\n\ +to the default encoding. errors may be given to set a different error\n\ +handling scheme. Default is 'strict' meaning that encoding errors raise\n\ +a UnicodeDecodeError. Other possible values are 'ignore' and 'replace'\n\ +as well as any other name registerd with codecs.register_error that is\n\ +able to handle UnicodeDecodeErrors."); + +static PyObject * +unicode_decode(PyUnicodeObject *self, PyObject *args) +{ + char *encoding = NULL; + char *errors = NULL; + PyObject *v; + + if (!PyArg_ParseTuple(args, "|ss:decode", &encoding, &errors)) + return NULL; + v = PyUnicode_AsDecodedObject((PyObject *)self, encoding, errors); + if (v == NULL) + goto onError; + if (!PyString_Check(v) && !PyUnicode_Check(v)) { + PyErr_Format(PyExc_TypeError, + "decoder did not return a string/unicode object " + "(type=%.400s)", + v->ob_type->tp_name); + Py_DECREF(v); + return NULL; + } + return v; + + onError: + return NULL; +} + +PyDoc_STRVAR(expandtabs__doc__, +"S.expandtabs([tabsize]) -> unicode\n\ +\n\ +Return a copy of S where all tab characters are expanded using spaces.\n\ +If tabsize is not given, a tab size of 8 characters is assumed."); + +static PyObject* +unicode_expandtabs(PyUnicodeObject *self, PyObject *args) +{ + Py_UNICODE *e; + Py_UNICODE *p; + Py_UNICODE *q; + Py_ssize_t i, j; + PyUnicodeObject *u; + int tabsize = 8; + + if (!PyArg_ParseTuple(args, "|i:expandtabs", &tabsize)) + return NULL; + + /* First pass: determine size of output string */ + i = j = 0; + e = self->str + self->length; + for (p = self->str; p < e; p++) + if (*p == '\t') { + if (tabsize > 0) + j += tabsize - (j % tabsize); + } + else { + j++; + if (*p == '\n' || *p == '\r') { + i += j; + j = 0; + } + } + + /* Second pass: create output string and fill it */ + u = _PyUnicode_New(i + j); + if (!u) + return NULL; + + j = 0; + q = u->str; + + for (p = self->str; p < e; p++) + if (*p == '\t') { + if (tabsize > 0) { + i = tabsize - (j % tabsize); + j += i; + while (i--) + *q++ = ' '; + } + } + else { + j++; + *q++ = *p; + if (*p == '\n' || *p == '\r') + j = 0; + } + + return (PyObject*) u; +} + +PyDoc_STRVAR(find__doc__, +"S.find(sub [,start [,end]]) -> int\n\ +\n\ +Return the lowest index in S where substring sub is found,\n\ +such that sub is contained within s[start,end]. Optional\n\ +arguments start and end are interpreted as in slice notation.\n\ +\n\ +Return -1 on failure."); + +static PyObject * +unicode_find(PyUnicodeObject *self, PyObject *args) +{ + PyObject *substring; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + Py_ssize_t result; + + if (!PyArg_ParseTuple(args, "O|O&O&:find", &substring, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + substring = PyUnicode_FromObject(substring); + if (!substring) + return NULL; + + result = stringlib_find_slice( + PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), + PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), + start, end + ); + + Py_DECREF(substring); + + return PyInt_FromSsize_t(result); +} + +static PyObject * +unicode_getitem(PyUnicodeObject *self, Py_ssize_t index) +{ + if (index < 0 || index >= self->length) { + PyErr_SetString(PyExc_IndexError, "string index out of range"); + return NULL; + } + + return (PyObject*) PyUnicode_FromUnicode(&self->str[index], 1); +} + +static long +unicode_hash(PyUnicodeObject *self) +{ + /* Since Unicode objects compare equal to their ASCII string + counterparts, they should use the individual character values + as basis for their hash value. This is needed to assure that + strings and Unicode objects behave in the same way as + dictionary keys. */ + + register Py_ssize_t len; + register Py_UNICODE *p; + register long x; + + if (self->hash != -1) + return self->hash; + len = PyUnicode_GET_SIZE(self); + p = PyUnicode_AS_UNICODE(self); + x = *p << 7; + while (--len >= 0) + x = (1000003*x) ^ *p++; + x ^= PyUnicode_GET_SIZE(self); + if (x == -1) + x = -2; + self->hash = x; + return x; +} + +PyDoc_STRVAR(index__doc__, +"S.index(sub [,start [,end]]) -> int\n\ +\n\ +Like S.find() but raise ValueError when the substring is not found."); + +static PyObject * +unicode_index(PyUnicodeObject *self, PyObject *args) +{ + Py_ssize_t result; + PyObject *substring; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + + if (!PyArg_ParseTuple(args, "O|O&O&:index", &substring, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + substring = PyUnicode_FromObject(substring); + if (!substring) + return NULL; + + result = stringlib_find_slice( + PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), + PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), + start, end + ); + + Py_DECREF(substring); + + if (result < 0) { + PyErr_SetString(PyExc_ValueError, "substring not found"); + return NULL; + } + + return PyInt_FromSsize_t(result); +} + +PyDoc_STRVAR(islower__doc__, +"S.islower() -> bool\n\ +\n\ +Return True if all cased characters in S are lowercase and there is\n\ +at least one cased character in S, False otherwise."); + +static PyObject* +unicode_islower(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + int cased; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1) + return PyBool_FromLong(Py_UNICODE_ISLOWER(*p)); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + cased = 0; + for (; p < e; p++) { + register const Py_UNICODE ch = *p; + + if (Py_UNICODE_ISUPPER(ch) || Py_UNICODE_ISTITLE(ch)) + return PyBool_FromLong(0); + else if (!cased && Py_UNICODE_ISLOWER(ch)) + cased = 1; + } + return PyBool_FromLong(cased); +} + +PyDoc_STRVAR(isupper__doc__, +"S.isupper() -> bool\n\ +\n\ +Return True if all cased characters in S are uppercase and there is\n\ +at least one cased character in S, False otherwise."); + +static PyObject* +unicode_isupper(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + int cased; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1) + return PyBool_FromLong(Py_UNICODE_ISUPPER(*p) != 0); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + cased = 0; + for (; p < e; p++) { + register const Py_UNICODE ch = *p; + + if (Py_UNICODE_ISLOWER(ch) || Py_UNICODE_ISTITLE(ch)) + return PyBool_FromLong(0); + else if (!cased && Py_UNICODE_ISUPPER(ch)) + cased = 1; + } + return PyBool_FromLong(cased); +} + +PyDoc_STRVAR(istitle__doc__, +"S.istitle() -> bool\n\ +\n\ +Return True if S is a titlecased string and there is at least one\n\ +character in S, i.e. upper- and titlecase characters may only\n\ +follow uncased characters and lowercase characters only cased ones.\n\ +Return False otherwise."); + +static PyObject* +unicode_istitle(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + int cased, previous_is_cased; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1) + return PyBool_FromLong((Py_UNICODE_ISTITLE(*p) != 0) || + (Py_UNICODE_ISUPPER(*p) != 0)); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + cased = 0; + previous_is_cased = 0; + for (; p < e; p++) { + register const Py_UNICODE ch = *p; + + if (Py_UNICODE_ISUPPER(ch) || Py_UNICODE_ISTITLE(ch)) { + if (previous_is_cased) + return PyBool_FromLong(0); + previous_is_cased = 1; + cased = 1; + } + else if (Py_UNICODE_ISLOWER(ch)) { + if (!previous_is_cased) + return PyBool_FromLong(0); + previous_is_cased = 1; + cased = 1; + } + else + previous_is_cased = 0; + } + return PyBool_FromLong(cased); +} + +PyDoc_STRVAR(isspace__doc__, +"S.isspace() -> bool\n\ +\n\ +Return True if all characters in S are whitespace\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +unicode_isspace(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1 && + Py_UNICODE_ISSPACE(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + for (; p < e; p++) { + if (!Py_UNICODE_ISSPACE(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + +PyDoc_STRVAR(isalpha__doc__, +"S.isalpha() -> bool\n\ +\n\ +Return True if all characters in S are alphabetic\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +unicode_isalpha(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1 && + Py_UNICODE_ISALPHA(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + for (; p < e; p++) { + if (!Py_UNICODE_ISALPHA(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + +PyDoc_STRVAR(isalnum__doc__, +"S.isalnum() -> bool\n\ +\n\ +Return True if all characters in S are alphanumeric\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +unicode_isalnum(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1 && + Py_UNICODE_ISALNUM(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + for (; p < e; p++) { + if (!Py_UNICODE_ISALNUM(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + +PyDoc_STRVAR(isdecimal__doc__, +"S.isdecimal() -> bool\n\ +\n\ +Return True if there are only decimal characters in S,\n\ +False otherwise."); + +static PyObject* +unicode_isdecimal(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1 && + Py_UNICODE_ISDECIMAL(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + for (; p < e; p++) { + if (!Py_UNICODE_ISDECIMAL(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + +PyDoc_STRVAR(isdigit__doc__, +"S.isdigit() -> bool\n\ +\n\ +Return True if all characters in S are digits\n\ +and there is at least one character in S, False otherwise."); + +static PyObject* +unicode_isdigit(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1 && + Py_UNICODE_ISDIGIT(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + for (; p < e; p++) { + if (!Py_UNICODE_ISDIGIT(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + +PyDoc_STRVAR(isnumeric__doc__, +"S.isnumeric() -> bool\n\ +\n\ +Return True if there are only numeric characters in S,\n\ +False otherwise."); + +static PyObject* +unicode_isnumeric(PyUnicodeObject *self) +{ + register const Py_UNICODE *p = PyUnicode_AS_UNICODE(self); + register const Py_UNICODE *e; + + /* Shortcut for single character strings */ + if (PyUnicode_GET_SIZE(self) == 1 && + Py_UNICODE_ISNUMERIC(*p)) + return PyBool_FromLong(1); + + /* Special case for empty strings */ + if (PyUnicode_GET_SIZE(self) == 0) + return PyBool_FromLong(0); + + e = p + PyUnicode_GET_SIZE(self); + for (; p < e; p++) { + if (!Py_UNICODE_ISNUMERIC(*p)) + return PyBool_FromLong(0); + } + return PyBool_FromLong(1); +} + +PyDoc_STRVAR(join__doc__, +"S.join(sequence) -> unicode\n\ +\n\ +Return a string which is the concatenation of the strings in the\n\ +sequence. The separator between elements is S."); + +static PyObject* +unicode_join(PyObject *self, PyObject *data) +{ + return PyUnicode_Join(self, data); +} + +static Py_ssize_t +unicode_length(PyUnicodeObject *self) +{ + return self->length; +} + +PyDoc_STRVAR(ljust__doc__, +"S.ljust(width[, fillchar]) -> int\n\ +\n\ +Return S left justified in a Unicode string of length width. Padding is\n\ +done using the specified fill character (default is a space)."); + +static PyObject * +unicode_ljust(PyUnicodeObject *self, PyObject *args) +{ + Py_ssize_t width; + Py_UNICODE fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|O&:ljust", &width, convert_uc, &fillchar)) + return NULL; + + if (self->length >= width && PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + + return (PyObject*) pad(self, 0, width - self->length, fillchar); +} + +PyDoc_STRVAR(lower__doc__, +"S.lower() -> unicode\n\ +\n\ +Return a copy of the string S converted to lowercase."); + +static PyObject* +unicode_lower(PyUnicodeObject *self) +{ + return fixup(self, fixlower); +} + +#define LEFTSTRIP 0 +#define RIGHTSTRIP 1 +#define BOTHSTRIP 2 + +/* Arrays indexed by above */ +static const char *stripformat[] = {"|O:lstrip", "|O:rstrip", "|O:strip"}; + +#define STRIPNAME(i) (stripformat[i]+3) + +/* externally visible for str.strip(unicode) */ +PyObject * +_PyUnicode_XStrip(PyUnicodeObject *self, int striptype, PyObject *sepobj) +{ + Py_UNICODE *s = PyUnicode_AS_UNICODE(self); + Py_ssize_t len = PyUnicode_GET_SIZE(self); + Py_UNICODE *sep = PyUnicode_AS_UNICODE(sepobj); + Py_ssize_t seplen = PyUnicode_GET_SIZE(sepobj); + Py_ssize_t i, j; + + BLOOM_MASK sepmask = make_bloom_mask(sep, seplen); + + i = 0; + if (striptype != RIGHTSTRIP) { + while (i < len && BLOOM_MEMBER(sepmask, s[i], sep, seplen)) { + i++; + } + } + + j = len; + if (striptype != LEFTSTRIP) { + do { + j--; + } while (j >= i && BLOOM_MEMBER(sepmask, s[j], sep, seplen)); + j++; + } + + if (i == 0 && j == len && PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*)self; + } + else + return PyUnicode_FromUnicode(s+i, j-i); +} + + +static PyObject * +do_strip(PyUnicodeObject *self, int striptype) +{ + Py_UNICODE *s = PyUnicode_AS_UNICODE(self); + Py_ssize_t len = PyUnicode_GET_SIZE(self), i, j; + + i = 0; + if (striptype != RIGHTSTRIP) { + while (i < len && Py_UNICODE_ISSPACE(s[i])) { + i++; + } + } + + j = len; + if (striptype != LEFTSTRIP) { + do { + j--; + } while (j >= i && Py_UNICODE_ISSPACE(s[j])); + j++; + } + + if (i == 0 && j == len && PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*)self; + } + else + return PyUnicode_FromUnicode(s+i, j-i); +} + + +static PyObject * +do_argstrip(PyUnicodeObject *self, int striptype, PyObject *args) +{ + PyObject *sep = NULL; + + if (!PyArg_ParseTuple(args, (char *)stripformat[striptype], &sep)) + return NULL; + + if (sep != NULL && sep != Py_None) { + if (PyUnicode_Check(sep)) + return _PyUnicode_XStrip(self, striptype, sep); + else if (PyString_Check(sep)) { + PyObject *res; + sep = PyUnicode_FromObject(sep); + if (sep==NULL) + return NULL; + res = _PyUnicode_XStrip(self, striptype, sep); + Py_DECREF(sep); + return res; + } + else { + PyErr_Format(PyExc_TypeError, + "%s arg must be None, unicode or str", + STRIPNAME(striptype)); + return NULL; + } + } + + return do_strip(self, striptype); +} + + +PyDoc_STRVAR(strip__doc__, +"S.strip([chars]) -> unicode\n\ +\n\ +Return a copy of the string S with leading and trailing\n\ +whitespace removed.\n\ +If chars is given and not None, remove characters in chars instead.\n\ +If chars is a str, it will be converted to unicode before stripping"); + +static PyObject * +unicode_strip(PyUnicodeObject *self, PyObject *args) +{ + if (PyTuple_GET_SIZE(args) == 0) + return do_strip(self, BOTHSTRIP); /* Common case */ + else + return do_argstrip(self, BOTHSTRIP, args); +} + + +PyDoc_STRVAR(lstrip__doc__, +"S.lstrip([chars]) -> unicode\n\ +\n\ +Return a copy of the string S with leading whitespace removed.\n\ +If chars is given and not None, remove characters in chars instead.\n\ +If chars is a str, it will be converted to unicode before stripping"); + +static PyObject * +unicode_lstrip(PyUnicodeObject *self, PyObject *args) +{ + if (PyTuple_GET_SIZE(args) == 0) + return do_strip(self, LEFTSTRIP); /* Common case */ + else + return do_argstrip(self, LEFTSTRIP, args); +} + + +PyDoc_STRVAR(rstrip__doc__, +"S.rstrip([chars]) -> unicode\n\ +\n\ +Return a copy of the string S with trailing whitespace removed.\n\ +If chars is given and not None, remove characters in chars instead.\n\ +If chars is a str, it will be converted to unicode before stripping"); + +static PyObject * +unicode_rstrip(PyUnicodeObject *self, PyObject *args) +{ + if (PyTuple_GET_SIZE(args) == 0) + return do_strip(self, RIGHTSTRIP); /* Common case */ + else + return do_argstrip(self, RIGHTSTRIP, args); +} + + +static PyObject* +unicode_repeat(PyUnicodeObject *str, Py_ssize_t len) +{ + PyUnicodeObject *u; + Py_UNICODE *p; + Py_ssize_t nchars; + size_t nbytes; + + if (len < 0) + len = 0; + + if (len == 1 && PyUnicode_CheckExact(str)) { + /* no repeat, return original string */ + Py_INCREF(str); + return (PyObject*) str; + } + + /* ensure # of chars needed doesn't overflow int and # of bytes + * needed doesn't overflow size_t + */ + nchars = len * str->length; + if (len && nchars / len != str->length) { + PyErr_SetString(PyExc_OverflowError, + "repeated string is too long"); + return NULL; + } + nbytes = (nchars + 1) * sizeof(Py_UNICODE); + if (nbytes / sizeof(Py_UNICODE) != (size_t)(nchars + 1)) { + PyErr_SetString(PyExc_OverflowError, + "repeated string is too long"); + return NULL; + } + u = _PyUnicode_New(nchars); + if (!u) + return NULL; + + p = u->str; + + if (str->length == 1 && len > 0) { + Py_UNICODE_FILL(p, str->str[0], len); + } else { + Py_ssize_t done = 0; /* number of characters copied this far */ + if (done < nchars) { + Py_UNICODE_COPY(p, str->str, str->length); + done = str->length; + } + while (done < nchars) { + int n = (done <= nchars-done) ? done : nchars-done; + Py_UNICODE_COPY(p+done, p, n); + done += n; + } + } + + return (PyObject*) u; +} + +PyObject *PyUnicode_Replace(PyObject *obj, + PyObject *subobj, + PyObject *replobj, + Py_ssize_t maxcount) +{ + PyObject *self; + PyObject *str1; + PyObject *str2; + PyObject *result; + + self = PyUnicode_FromObject(obj); + if (self == NULL) + return NULL; + str1 = PyUnicode_FromObject(subobj); + if (str1 == NULL) { + Py_DECREF(self); + return NULL; + } + str2 = PyUnicode_FromObject(replobj); + if (str2 == NULL) { + Py_DECREF(self); + Py_DECREF(str1); + return NULL; + } + result = replace((PyUnicodeObject *)self, + (PyUnicodeObject *)str1, + (PyUnicodeObject *)str2, + maxcount); + Py_DECREF(self); + Py_DECREF(str1); + Py_DECREF(str2); + return result; +} + +PyDoc_STRVAR(replace__doc__, +"S.replace (old, new[, maxsplit]) -> unicode\n\ +\n\ +Return a copy of S with all occurrences of substring\n\ +old replaced by new. If the optional argument maxsplit is\n\ +given, only the first maxsplit occurrences are replaced."); + +static PyObject* +unicode_replace(PyUnicodeObject *self, PyObject *args) +{ + PyUnicodeObject *str1; + PyUnicodeObject *str2; + Py_ssize_t maxcount = -1; + PyObject *result; + + if (!PyArg_ParseTuple(args, "OO|n:replace", &str1, &str2, &maxcount)) + return NULL; + str1 = (PyUnicodeObject *)PyUnicode_FromObject((PyObject *)str1); + if (str1 == NULL) + return NULL; + str2 = (PyUnicodeObject *)PyUnicode_FromObject((PyObject *)str2); + if (str2 == NULL) { + Py_DECREF(str1); + return NULL; + } + + result = replace(self, str1, str2, maxcount); + + Py_DECREF(str1); + Py_DECREF(str2); + return result; +} + +static +PyObject *unicode_repr(PyObject *unicode) +{ + return unicodeescape_string(PyUnicode_AS_UNICODE(unicode), + PyUnicode_GET_SIZE(unicode), + 1); +} + +PyDoc_STRVAR(rfind__doc__, +"S.rfind(sub [,start [,end]]) -> int\n\ +\n\ +Return the highest index in S where substring sub is found,\n\ +such that sub is contained within s[start,end]. Optional\n\ +arguments start and end are interpreted as in slice notation.\n\ +\n\ +Return -1 on failure."); + +static PyObject * +unicode_rfind(PyUnicodeObject *self, PyObject *args) +{ + PyObject *substring; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + Py_ssize_t result; + + if (!PyArg_ParseTuple(args, "O|O&O&:rfind", &substring, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + substring = PyUnicode_FromObject(substring); + if (!substring) + return NULL; + + result = stringlib_rfind_slice( + PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), + PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), + start, end + ); + + Py_DECREF(substring); + + return PyInt_FromSsize_t(result); +} + +PyDoc_STRVAR(rindex__doc__, +"S.rindex(sub [,start [,end]]) -> int\n\ +\n\ +Like S.rfind() but raise ValueError when the substring is not found."); + +static PyObject * +unicode_rindex(PyUnicodeObject *self, PyObject *args) +{ + PyObject *substring; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + Py_ssize_t result; + + if (!PyArg_ParseTuple(args, "O|O&O&:rindex", &substring, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + substring = PyUnicode_FromObject(substring); + if (!substring) + return NULL; + + result = stringlib_rfind_slice( + PyUnicode_AS_UNICODE(self), PyUnicode_GET_SIZE(self), + PyUnicode_AS_UNICODE(substring), PyUnicode_GET_SIZE(substring), + start, end + ); + + Py_DECREF(substring); + + if (result < 0) { + PyErr_SetString(PyExc_ValueError, "substring not found"); + return NULL; + } + return PyInt_FromSsize_t(result); +} + +PyDoc_STRVAR(rjust__doc__, +"S.rjust(width[, fillchar]) -> unicode\n\ +\n\ +Return S right justified in a Unicode string of length width. Padding is\n\ +done using the specified fill character (default is a space)."); + +static PyObject * +unicode_rjust(PyUnicodeObject *self, PyObject *args) +{ + Py_ssize_t width; + Py_UNICODE fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|O&:rjust", &width, convert_uc, &fillchar)) + return NULL; + + if (self->length >= width && PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + + return (PyObject*) pad(self, width - self->length, 0, fillchar); +} + +static PyObject* +unicode_slice(PyUnicodeObject *self, Py_ssize_t start, Py_ssize_t end) +{ + /* standard clamping */ + if (start < 0) + start = 0; + if (end < 0) + end = 0; + if (end > self->length) + end = self->length; + if (start == 0 && end == self->length && PyUnicode_CheckExact(self)) { + /* full slice, return original string */ + Py_INCREF(self); + return (PyObject*) self; + } + if (start > end) + start = end; + /* copy slice */ + return (PyObject*) PyUnicode_FromUnicode(self->str + start, + end - start); +} + +PyObject *PyUnicode_Split(PyObject *s, + PyObject *sep, + Py_ssize_t maxsplit) +{ + PyObject *result; + + s = PyUnicode_FromObject(s); + if (s == NULL) + return NULL; + if (sep != NULL) { + sep = PyUnicode_FromObject(sep); + if (sep == NULL) { + Py_DECREF(s); + return NULL; + } + } + + result = split((PyUnicodeObject *)s, (PyUnicodeObject *)sep, maxsplit); + + Py_DECREF(s); + Py_XDECREF(sep); + return result; +} + +PyDoc_STRVAR(split__doc__, +"S.split([sep [,maxsplit]]) -> list of strings\n\ +\n\ +Return a list of the words in S, using sep as the\n\ +delimiter string. If maxsplit is given, at most maxsplit\n\ +splits are done. If sep is not specified or is None,\n\ +any whitespace string is a separator."); + +static PyObject* +unicode_split(PyUnicodeObject *self, PyObject *args) +{ + PyObject *substring = Py_None; + Py_ssize_t maxcount = -1; + + if (!PyArg_ParseTuple(args, "|On:split", &substring, &maxcount)) + return NULL; + + if (substring == Py_None) + return split(self, NULL, maxcount); + else if (PyUnicode_Check(substring)) + return split(self, (PyUnicodeObject *)substring, maxcount); + else + return PyUnicode_Split((PyObject *)self, substring, maxcount); +} + +PyObject * +PyUnicode_Partition(PyObject *str_in, PyObject *sep_in) +{ + PyObject* str_obj; + PyObject* sep_obj; + PyObject* out; + + str_obj = PyUnicode_FromObject(str_in); + if (!str_obj) + return NULL; + sep_obj = PyUnicode_FromObject(sep_in); + if (!sep_obj) { + Py_DECREF(str_obj); + return NULL; + } + + out = stringlib_partition( + str_obj, PyUnicode_AS_UNICODE(str_obj), PyUnicode_GET_SIZE(str_obj), + sep_obj, PyUnicode_AS_UNICODE(sep_obj), PyUnicode_GET_SIZE(sep_obj) + ); + + Py_DECREF(sep_obj); + Py_DECREF(str_obj); + + return out; +} + + +PyObject * +PyUnicode_RPartition(PyObject *str_in, PyObject *sep_in) +{ + PyObject* str_obj; + PyObject* sep_obj; + PyObject* out; + + str_obj = PyUnicode_FromObject(str_in); + if (!str_obj) + return NULL; + sep_obj = PyUnicode_FromObject(sep_in); + if (!sep_obj) { + Py_DECREF(str_obj); + return NULL; + } + + out = stringlib_rpartition( + str_obj, PyUnicode_AS_UNICODE(str_obj), PyUnicode_GET_SIZE(str_obj), + sep_obj, PyUnicode_AS_UNICODE(sep_obj), PyUnicode_GET_SIZE(sep_obj) + ); + + Py_DECREF(sep_obj); + Py_DECREF(str_obj); + + return out; +} + +PyDoc_STRVAR(partition__doc__, +"S.partition(sep) -> (head, sep, tail)\n\ +\n\ +Searches for the separator sep in S, and returns the part before it,\n\ +the separator itself, and the part after it. If the separator is not\n\ +found, returns S and two empty strings."); + +static PyObject* +unicode_partition(PyUnicodeObject *self, PyObject *separator) +{ + return PyUnicode_Partition((PyObject *)self, separator); +} + +PyDoc_STRVAR(rpartition__doc__, +"S.rpartition(sep) -> (tail, sep, head)\n\ +\n\ +Searches for the separator sep in S, starting at the end of S, and returns\n\ +the part before it, the separator itself, and the part after it. If the\n\ +separator is not found, returns two empty strings and S."); + +static PyObject* +unicode_rpartition(PyUnicodeObject *self, PyObject *separator) +{ + return PyUnicode_RPartition((PyObject *)self, separator); +} + +PyObject *PyUnicode_RSplit(PyObject *s, + PyObject *sep, + Py_ssize_t maxsplit) +{ + PyObject *result; + + s = PyUnicode_FromObject(s); + if (s == NULL) + return NULL; + if (sep != NULL) { + sep = PyUnicode_FromObject(sep); + if (sep == NULL) { + Py_DECREF(s); + return NULL; + } + } + + result = rsplit((PyUnicodeObject *)s, (PyUnicodeObject *)sep, maxsplit); + + Py_DECREF(s); + Py_XDECREF(sep); + return result; +} + +PyDoc_STRVAR(rsplit__doc__, +"S.rsplit([sep [,maxsplit]]) -> list of strings\n\ +\n\ +Return a list of the words in S, using sep as the\n\ +delimiter string, starting at the end of the string and\n\ +working to the front. If maxsplit is given, at most maxsplit\n\ +splits are done. If sep is not specified, any whitespace string\n\ +is a separator."); + +static PyObject* +unicode_rsplit(PyUnicodeObject *self, PyObject *args) +{ + PyObject *substring = Py_None; + Py_ssize_t maxcount = -1; + + if (!PyArg_ParseTuple(args, "|On:rsplit", &substring, &maxcount)) + return NULL; + + if (substring == Py_None) + return rsplit(self, NULL, maxcount); + else if (PyUnicode_Check(substring)) + return rsplit(self, (PyUnicodeObject *)substring, maxcount); + else + return PyUnicode_RSplit((PyObject *)self, substring, maxcount); +} + +PyDoc_STRVAR(splitlines__doc__, +"S.splitlines([keepends]]) -> list of strings\n\ +\n\ +Return a list of the lines in S, breaking at line boundaries.\n\ +Line breaks are not included in the resulting list unless keepends\n\ +is given and true."); + +static PyObject* +unicode_splitlines(PyUnicodeObject *self, PyObject *args) +{ + int keepends = 0; + + if (!PyArg_ParseTuple(args, "|i:splitlines", &keepends)) + return NULL; + + return PyUnicode_Splitlines((PyObject *)self, keepends); +} + +static +PyObject *unicode_str(PyUnicodeObject *self) +{ + return PyUnicode_AsEncodedString((PyObject *)self, NULL, NULL); +} + +PyDoc_STRVAR(swapcase__doc__, +"S.swapcase() -> unicode\n\ +\n\ +Return a copy of S with uppercase characters converted to lowercase\n\ +and vice versa."); + +static PyObject* +unicode_swapcase(PyUnicodeObject *self) +{ + return fixup(self, fixswapcase); +} + +PyDoc_STRVAR(translate__doc__, +"S.translate(table) -> unicode\n\ +\n\ +Return a copy of the string S, where all characters have been mapped\n\ +through the given translation table, which must be a mapping of\n\ +Unicode ordinals to Unicode ordinals, Unicode strings or None.\n\ +Unmapped characters are left untouched. Characters mapped to None\n\ +are deleted."); + +static PyObject* +unicode_translate(PyUnicodeObject *self, PyObject *table) +{ + return PyUnicode_TranslateCharmap(self->str, + self->length, + table, + "ignore"); +} + +PyDoc_STRVAR(upper__doc__, +"S.upper() -> unicode\n\ +\n\ +Return a copy of S converted to uppercase."); + +static PyObject* +unicode_upper(PyUnicodeObject *self) +{ + return fixup(self, fixupper); +} + +PyDoc_STRVAR(zfill__doc__, +"S.zfill(width) -> unicode\n\ +\n\ +Pad a numeric string x with zeros on the left, to fill a field\n\ +of the specified width. The string x is never truncated."); + +static PyObject * +unicode_zfill(PyUnicodeObject *self, PyObject *args) +{ + Py_ssize_t fill; + PyUnicodeObject *u; + + Py_ssize_t width; + if (!PyArg_ParseTuple(args, "n:zfill", &width)) + return NULL; + + if (self->length >= width) { + if (PyUnicode_CheckExact(self)) { + Py_INCREF(self); + return (PyObject*) self; + } + else + return PyUnicode_FromUnicode( + PyUnicode_AS_UNICODE(self), + PyUnicode_GET_SIZE(self) + ); + } + + fill = width - self->length; + + u = pad(self, fill, 0, '0'); + + if (u == NULL) + return NULL; + + if (u->str[fill] == '+' || u->str[fill] == '-') { + /* move sign to beginning of string */ + u->str[0] = u->str[fill]; + u->str[fill] = '0'; + } + + return (PyObject*) u; +} + +#if 0 +static PyObject* +unicode_freelistsize(PyUnicodeObject *self) +{ + return PyInt_FromLong(unicode_freelist_size); +} +#endif + +PyDoc_STRVAR(startswith__doc__, +"S.startswith(prefix[, start[, end]]) -> bool\n\ +\n\ +Return True if S starts with the specified prefix, False otherwise.\n\ +With optional start, test S beginning at that position.\n\ +With optional end, stop comparing S at that position.\n\ +prefix can also be a tuple of strings to try."); + +static PyObject * +unicode_startswith(PyUnicodeObject *self, + PyObject *args) +{ + PyObject *subobj; + PyUnicodeObject *substring; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + int result; + + if (!PyArg_ParseTuple(args, "O|O&O&:startswith", &subobj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + if (PyTuple_Check(subobj)) { + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { + substring = (PyUnicodeObject *)PyUnicode_FromObject( + PyTuple_GET_ITEM(subobj, i)); + if (substring == NULL) + return NULL; + result = tailmatch(self, substring, start, end, -1); + Py_DECREF(substring); + if (result) { + Py_RETURN_TRUE; + } + } + /* nothing matched */ + Py_RETURN_FALSE; + } + substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); + if (substring == NULL) + return NULL; + result = tailmatch(self, substring, start, end, -1); + Py_DECREF(substring); + return PyBool_FromLong(result); +} + + +PyDoc_STRVAR(endswith__doc__, +"S.endswith(suffix[, start[, end]]) -> bool\n\ +\n\ +Return True if S ends with the specified suffix, False otherwise.\n\ +With optional start, test S beginning at that position.\n\ +With optional end, stop comparing S at that position.\n\ +suffix can also be a tuple of strings to try."); + +static PyObject * +unicode_endswith(PyUnicodeObject *self, + PyObject *args) +{ + PyObject *subobj; + PyUnicodeObject *substring; + Py_ssize_t start = 0; + Py_ssize_t end = PY_SSIZE_T_MAX; + int result; + + if (!PyArg_ParseTuple(args, "O|O&O&:endswith", &subobj, + _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) + return NULL; + if (PyTuple_Check(subobj)) { + Py_ssize_t i; + for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { + substring = (PyUnicodeObject *)PyUnicode_FromObject( + PyTuple_GET_ITEM(subobj, i)); + if (substring == NULL) + return NULL; + result = tailmatch(self, substring, start, end, +1); + Py_DECREF(substring); + if (result) { + Py_RETURN_TRUE; + } + } + Py_RETURN_FALSE; + } + substring = (PyUnicodeObject *)PyUnicode_FromObject(subobj); + if (substring == NULL) + return NULL; + + result = tailmatch(self, substring, start, end, +1); + Py_DECREF(substring); + return PyBool_FromLong(result); +} + + + +static PyObject * +unicode_getnewargs(PyUnicodeObject *v) +{ + return Py_BuildValue("(u#)", v->str, v->length); +} + + +static PyMethodDef unicode_methods[] = { + + /* Order is according to common usage: often used methods should + appear first, since lookup is done sequentially. */ + + {"encode", (PyCFunction) unicode_encode, METH_VARARGS, encode__doc__}, + {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__}, + {"split", (PyCFunction) unicode_split, METH_VARARGS, split__doc__}, + {"rsplit", (PyCFunction) unicode_rsplit, METH_VARARGS, rsplit__doc__}, + {"join", (PyCFunction) unicode_join, METH_O, join__doc__}, + {"capitalize", (PyCFunction) unicode_capitalize, METH_NOARGS, capitalize__doc__}, + {"title", (PyCFunction) unicode_title, METH_NOARGS, title__doc__}, + {"center", (PyCFunction) unicode_center, METH_VARARGS, center__doc__}, + {"count", (PyCFunction) unicode_count, METH_VARARGS, count__doc__}, + {"expandtabs", (PyCFunction) unicode_expandtabs, METH_VARARGS, expandtabs__doc__}, + {"find", (PyCFunction) unicode_find, METH_VARARGS, find__doc__}, + {"partition", (PyCFunction) unicode_partition, METH_O, partition__doc__}, + {"index", (PyCFunction) unicode_index, METH_VARARGS, index__doc__}, + {"ljust", (PyCFunction) unicode_ljust, METH_VARARGS, ljust__doc__}, + {"lower", (PyCFunction) unicode_lower, METH_NOARGS, lower__doc__}, + {"lstrip", (PyCFunction) unicode_lstrip, METH_VARARGS, lstrip__doc__}, + {"decode", (PyCFunction) unicode_decode, METH_VARARGS, decode__doc__}, +/* {"maketrans", (PyCFunction) unicode_maketrans, METH_VARARGS, maketrans__doc__}, */ + {"rfind", (PyCFunction) unicode_rfind, METH_VARARGS, rfind__doc__}, + {"rindex", (PyCFunction) unicode_rindex, METH_VARARGS, rindex__doc__}, + {"rjust", (PyCFunction) unicode_rjust, METH_VARARGS, rjust__doc__}, + {"rstrip", (PyCFunction) unicode_rstrip, METH_VARARGS, rstrip__doc__}, + {"rpartition", (PyCFunction) unicode_rpartition, METH_O, rpartition__doc__}, + {"splitlines", (PyCFunction) unicode_splitlines, METH_VARARGS, splitlines__doc__}, + {"strip", (PyCFunction) unicode_strip, METH_VARARGS, strip__doc__}, + {"swapcase", (PyCFunction) unicode_swapcase, METH_NOARGS, swapcase__doc__}, + {"translate", (PyCFunction) unicode_translate, METH_O, translate__doc__}, + {"upper", (PyCFunction) unicode_upper, METH_NOARGS, upper__doc__}, + {"startswith", (PyCFunction) unicode_startswith, METH_VARARGS, startswith__doc__}, + {"endswith", (PyCFunction) unicode_endswith, METH_VARARGS, endswith__doc__}, + {"islower", (PyCFunction) unicode_islower, METH_NOARGS, islower__doc__}, + {"isupper", (PyCFunction) unicode_isupper, METH_NOARGS, isupper__doc__}, + {"istitle", (PyCFunction) unicode_istitle, METH_NOARGS, istitle__doc__}, + {"isspace", (PyCFunction) unicode_isspace, METH_NOARGS, isspace__doc__}, + {"isdecimal", (PyCFunction) unicode_isdecimal, METH_NOARGS, isdecimal__doc__}, + {"isdigit", (PyCFunction) unicode_isdigit, METH_NOARGS, isdigit__doc__}, + {"isnumeric", (PyCFunction) unicode_isnumeric, METH_NOARGS, isnumeric__doc__}, + {"isalpha", (PyCFunction) unicode_isalpha, METH_NOARGS, isalpha__doc__}, + {"isalnum", (PyCFunction) unicode_isalnum, METH_NOARGS, isalnum__doc__}, + {"zfill", (PyCFunction) unicode_zfill, METH_VARARGS, zfill__doc__}, +#if 0 + {"capwords", (PyCFunction) unicode_capwords, METH_NOARGS, capwords__doc__}, +#endif + +#if 0 + /* This one is just used for debugging the implementation. */ + {"freelistsize", (PyCFunction) unicode_freelistsize, METH_NOARGS}, +#endif + + {"__getnewargs__", (PyCFunction)unicode_getnewargs, METH_NOARGS}, + {NULL, NULL} +}; + +static PyObject * +unicode_mod(PyObject *v, PyObject *w) +{ + if (!PyUnicode_Check(v)) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + return PyUnicode_Format(v, w); +} + +static PyNumberMethods unicode_as_number = { + 0, /*nb_add*/ + 0, /*nb_subtract*/ + 0, /*nb_multiply*/ + 0, /*nb_divide*/ + unicode_mod, /*nb_remainder*/ +}; + +static PySequenceMethods unicode_as_sequence = { + (lenfunc) unicode_length, /* sq_length */ + PyUnicode_Concat, /* sq_concat */ + (ssizeargfunc) unicode_repeat, /* sq_repeat */ + (ssizeargfunc) unicode_getitem, /* sq_item */ + (ssizessizeargfunc) unicode_slice, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + PyUnicode_Contains, /* sq_contains */ +}; + +static PyObject* +unicode_subscript(PyUnicodeObject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += PyUnicode_GET_SIZE(self); + return unicode_getitem(self, i); + } else if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, slicelength, cur, i; + Py_UNICODE* source_buf; + Py_UNICODE* result_buf; + PyObject* result; + + if (PySlice_GetIndicesEx((PySliceObject*)item, PyUnicode_GET_SIZE(self), + &start, &stop, &step, &slicelength) < 0) { + return NULL; + } + + if (slicelength <= 0) { + return PyUnicode_FromUnicode(NULL, 0); + } else { + source_buf = PyUnicode_AS_UNICODE((PyObject*)self); + result_buf = (Py_UNICODE *)PyMem_MALLOC(slicelength* + sizeof(Py_UNICODE)); + + if (result_buf == NULL) + return PyErr_NoMemory(); + + for (cur = start, i = 0; i < slicelength; cur += step, i++) { + result_buf[i] = source_buf[cur]; + } + + result = PyUnicode_FromUnicode(result_buf, slicelength); + PyMem_FREE(result_buf); + return result; + } + } else { + PyErr_SetString(PyExc_TypeError, "string indices must be integers"); + return NULL; + } +} + +static PyMappingMethods unicode_as_mapping = { + (lenfunc)unicode_length, /* mp_length */ + (binaryfunc)unicode_subscript, /* mp_subscript */ + (objobjargproc)0, /* mp_ass_subscript */ +}; + +static Py_ssize_t +unicode_buffer_getreadbuf(PyUnicodeObject *self, + Py_ssize_t index, + const void **ptr) +{ + if (index != 0) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent unicode segment"); + return -1; + } + *ptr = (void *) self->str; + return PyUnicode_GET_DATA_SIZE(self); +} + +static Py_ssize_t +unicode_buffer_getwritebuf(PyUnicodeObject *self, Py_ssize_t index, + const void **ptr) +{ + PyErr_SetString(PyExc_TypeError, + "cannot use unicode as modifiable buffer"); + return -1; +} + +static int +unicode_buffer_getsegcount(PyUnicodeObject *self, + Py_ssize_t *lenp) +{ + if (lenp) + *lenp = PyUnicode_GET_DATA_SIZE(self); + return 1; +} + +static Py_ssize_t +unicode_buffer_getcharbuf(PyUnicodeObject *self, + Py_ssize_t index, + const void **ptr) +{ + PyObject *str; + + if (index != 0) { + PyErr_SetString(PyExc_SystemError, + "accessing non-existent unicode segment"); + return -1; + } + str = _PyUnicode_AsDefaultEncodedString((PyObject *)self, NULL); + if (str == NULL) + return -1; + *ptr = (void *) PyString_AS_STRING(str); + return PyString_GET_SIZE(str); +} + +/* Helpers for PyUnicode_Format() */ + +static PyObject * +getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) +{ + Py_ssize_t argidx = *p_argidx; + if (argidx < arglen) { + (*p_argidx)++; + if (arglen < 0) + return args; + else + return PyTuple_GetItem(args, argidx); + } + PyErr_SetString(PyExc_TypeError, + "not enough arguments for format string"); + return NULL; +} + +#define F_LJUST (1<<0) +#define F_SIGN (1<<1) +#define F_BLANK (1<<2) +#define F_ALT (1<<3) +#define F_ZERO (1<<4) + +static Py_ssize_t +strtounicode(Py_UNICODE *buffer, const char *charbuffer) +{ + register Py_ssize_t i; + Py_ssize_t len = strlen(charbuffer); + for (i = len - 1; i >= 0; i--) + buffer[i] = (Py_UNICODE) charbuffer[i]; + + return len; +} + +static int +doubletounicode(Py_UNICODE *buffer, size_t len, const char *format, double x) +{ + Py_ssize_t result; + + PyOS_ascii_formatd((char *)buffer, len, format, x); + result = strtounicode(buffer, (char *)buffer); + return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); +} + +static int +longtounicode(Py_UNICODE *buffer, size_t len, const char *format, long x) +{ + Py_ssize_t result; + + PyOS_snprintf((char *)buffer, len, format, x); + result = strtounicode(buffer, (char *)buffer); + return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); +} + +/* XXX To save some code duplication, formatfloat/long/int could have been + shared with stringobject.c, converting from 8-bit to Unicode after the + formatting is done. */ + +static int +formatfloat(Py_UNICODE *buf, + size_t buflen, + int flags, + int prec, + int type, + PyObject *v) +{ + /* fmt = '%#.' + `prec` + `type` + worst case length = 3 + 10 (len of INT_MAX) + 1 = 14 (use 20)*/ + char fmt[20]; + double x; + + x = PyFloat_AsDouble(v); + if (x == -1.0 && PyErr_Occurred()) + return -1; + if (prec < 0) + prec = 6; + if (type == 'f' && (fabs(x) / 1e25) >= 1e25) + type = 'g'; + /* Worst case length calc to ensure no buffer overrun: + + 'g' formats: + fmt = %#.<prec>g + buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp + for any double rep.) + len = 1 + prec + 1 + 2 + 5 = 9 + prec + + 'f' formats: + buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) + len = 1 + 50 + 1 + prec = 52 + prec + + If prec=0 the effective precision is 1 (the leading digit is + always given), therefore increase the length by one. + + */ + if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) || + (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) { + PyErr_SetString(PyExc_OverflowError, + "formatted float is too long (precision too large?)"); + return -1; + } + PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c", + (flags&F_ALT) ? "#" : "", + prec, type); + return doubletounicode(buf, buflen, fmt, x); +} + +static PyObject* +formatlong(PyObject *val, int flags, int prec, int type) +{ + char *buf; + int i, len; + PyObject *str; /* temporary string object. */ + PyUnicodeObject *result; + + str = _PyString_FormatLong(val, flags, prec, type, &buf, &len); + if (!str) + return NULL; + result = _PyUnicode_New(len); + if (!result) { + Py_DECREF(str); + return NULL; + } + for (i = 0; i < len; i++) + result->str[i] = buf[i]; + result->str[len] = 0; + Py_DECREF(str); + return (PyObject*)result; +} + +static int +formatint(Py_UNICODE *buf, + size_t buflen, + int flags, + int prec, + int type, + PyObject *v) +{ + /* fmt = '%#.' + `prec` + 'l' + `type` + * worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine) + * + 1 + 1 + * = 24 + */ + char fmt[64]; /* plenty big enough! */ + char *sign; + long x; + + x = PyInt_AsLong(v); + if (x == -1 && PyErr_Occurred()) + return -1; + if (x < 0 && type == 'u') { + type = 'd'; + } + if (x < 0 && (type == 'x' || type == 'X' || type == 'o')) + sign = "-"; + else + sign = ""; + if (prec < 0) + prec = 1; + + /* buf = '+'/'-'/'' + '0'/'0x'/'' + '[0-9]'*max(prec, len(x in octal)) + * worst case buf = '-0x' + [0-9]*prec, where prec >= 11 + */ + if (buflen <= 14 || buflen <= (size_t)3 + (size_t)prec) { + PyErr_SetString(PyExc_OverflowError, + "formatted integer is too long (precision too large?)"); + return -1; + } + + if ((flags & F_ALT) && + (type == 'x' || type == 'X')) { + /* When converting under %#x or %#X, there are a number + * of issues that cause pain: + * - when 0 is being converted, the C standard leaves off + * the '0x' or '0X', which is inconsistent with other + * %#x/%#X conversions and inconsistent with Python's + * hex() function + * - there are platforms that violate the standard and + * convert 0 with the '0x' or '0X' + * (Metrowerks, Compaq Tru64) + * - there are platforms that give '0x' when converting + * under %#X, but convert 0 in accordance with the + * standard (OS/2 EMX) + * + * We can achieve the desired consistency by inserting our + * own '0x' or '0X' prefix, and substituting %x/%X in place + * of %#x/%#X. + * + * Note that this is the same approach as used in + * formatint() in stringobject.c + */ + PyOS_snprintf(fmt, sizeof(fmt), "%s0%c%%.%dl%c", + sign, type, prec, type); + } + else { + PyOS_snprintf(fmt, sizeof(fmt), "%s%%%s.%dl%c", + sign, (flags&F_ALT) ? "#" : "", + prec, type); + } + if (sign[0]) + return longtounicode(buf, buflen, fmt, -x); + else + return longtounicode(buf, buflen, fmt, x); +} + +static int +formatchar(Py_UNICODE *buf, + size_t buflen, + PyObject *v) +{ + /* presume that the buffer is at least 2 characters long */ + if (PyUnicode_Check(v)) { + if (PyUnicode_GET_SIZE(v) != 1) + goto onError; + buf[0] = PyUnicode_AS_UNICODE(v)[0]; + } + + else if (PyString_Check(v)) { + if (PyString_GET_SIZE(v) != 1) + goto onError; + buf[0] = (Py_UNICODE)PyString_AS_STRING(v)[0]; + } + + else { + /* Integer input truncated to a character */ + long x; + x = PyInt_AsLong(v); + if (x == -1 && PyErr_Occurred()) + goto onError; +#ifdef Py_UNICODE_WIDE + if (x < 0 || x > 0x10ffff) { + PyErr_SetString(PyExc_OverflowError, + "%c arg not in range(0x110000) " + "(wide Python build)"); + return -1; + } +#else + if (x < 0 || x > 0xffff) { + PyErr_SetString(PyExc_OverflowError, + "%c arg not in range(0x10000) " + "(narrow Python build)"); + return -1; + } +#endif + buf[0] = (Py_UNICODE) x; + } + buf[1] = '\0'; + return 1; + + onError: + PyErr_SetString(PyExc_TypeError, + "%c requires int or char"); + return -1; +} + +/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) + + FORMATBUFLEN is the length of the buffer in which the floats, ints, & + chars are formatted. XXX This is a magic number. Each formatting + routine does bounds checking to ensure no overflow, but a better + solution may be to malloc a buffer of appropriate size for each + format. For now, the current solution is sufficient. +*/ +#define FORMATBUFLEN (size_t)120 + +PyObject *PyUnicode_Format(PyObject *format, + PyObject *args) +{ + Py_UNICODE *fmt, *res; + Py_ssize_t fmtcnt, rescnt, reslen, arglen, argidx; + int args_owned = 0; + PyUnicodeObject *result = NULL; + PyObject *dict = NULL; + PyObject *uformat; + + if (format == NULL || args == NULL) { + PyErr_BadInternalCall(); + return NULL; + } + uformat = PyUnicode_FromObject(format); + if (uformat == NULL) + return NULL; + fmt = PyUnicode_AS_UNICODE(uformat); + fmtcnt = PyUnicode_GET_SIZE(uformat); + + reslen = rescnt = fmtcnt + 100; + result = _PyUnicode_New(reslen); + if (result == NULL) + goto onError; + res = PyUnicode_AS_UNICODE(result); + + if (PyTuple_Check(args)) { + arglen = PyTuple_Size(args); + argidx = 0; + } + else { + arglen = -1; + argidx = -2; + } + if (args->ob_type->tp_as_mapping && !PyTuple_Check(args) && + !PyObject_TypeCheck(args, &PyBaseString_Type)) + dict = args; + + while (--fmtcnt >= 0) { + if (*fmt != '%') { + if (--rescnt < 0) { + rescnt = fmtcnt + 100; + reslen += rescnt; + if (_PyUnicode_Resize(&result, reslen) < 0) + goto onError; + res = PyUnicode_AS_UNICODE(result) + reslen - rescnt; + --rescnt; + } + *res++ = *fmt++; + } + else { + /* Got a format specifier */ + int flags = 0; + Py_ssize_t width = -1; + int prec = -1; + Py_UNICODE c = '\0'; + Py_UNICODE fill; + PyObject *v = NULL; + PyObject *temp = NULL; + Py_UNICODE *pbuf; + Py_UNICODE sign; + Py_ssize_t len; + Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */ + + fmt++; + if (*fmt == '(') { + Py_UNICODE *keystart; + Py_ssize_t keylen; + PyObject *key; + int pcount = 1; + + if (dict == NULL) { + PyErr_SetString(PyExc_TypeError, + "format requires a mapping"); + goto onError; + } + ++fmt; + --fmtcnt; + keystart = fmt; + /* Skip over balanced parentheses */ + while (pcount > 0 && --fmtcnt >= 0) { + if (*fmt == ')') + --pcount; + else if (*fmt == '(') + ++pcount; + fmt++; + } + keylen = fmt - keystart - 1; + if (fmtcnt < 0 || pcount > 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format key"); + goto onError; + } +#if 0 + /* keys are converted to strings using UTF-8 and + then looked up since Python uses strings to hold + variables names etc. in its namespaces and we + wouldn't want to break common idioms. */ + key = PyUnicode_EncodeUTF8(keystart, + keylen, + NULL); +#else + key = PyUnicode_FromUnicode(keystart, keylen); +#endif + if (key == NULL) + goto onError; + if (args_owned) { + Py_DECREF(args); + args_owned = 0; + } + args = PyObject_GetItem(dict, key); + Py_DECREF(key); + if (args == NULL) { + goto onError; + } + args_owned = 1; + arglen = -1; + argidx = -2; + } + while (--fmtcnt >= 0) { + switch (c = *fmt++) { + case '-': flags |= F_LJUST; continue; + case '+': flags |= F_SIGN; continue; + case ' ': flags |= F_BLANK; continue; + case '#': flags |= F_ALT; continue; + case '0': flags |= F_ZERO; continue; + } + break; + } + if (c == '*') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto onError; + if (!PyInt_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "* wants int"); + goto onError; + } + width = PyInt_AsLong(v); + if (width < 0) { + flags |= F_LJUST; + width = -width; + } + if (--fmtcnt >= 0) + c = *fmt++; + } + else if (c >= '0' && c <= '9') { + width = c - '0'; + while (--fmtcnt >= 0) { + c = *fmt++; + if (c < '0' || c > '9') + break; + if ((width*10) / 10 != width) { + PyErr_SetString(PyExc_ValueError, + "width too big"); + goto onError; + } + width = width*10 + (c - '0'); + } + } + if (c == '.') { + prec = 0; + if (--fmtcnt >= 0) + c = *fmt++; + if (c == '*') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto onError; + if (!PyInt_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "* wants int"); + goto onError; + } + prec = PyInt_AsLong(v); + if (prec < 0) + prec = 0; + if (--fmtcnt >= 0) + c = *fmt++; + } + else if (c >= '0' && c <= '9') { + prec = c - '0'; + while (--fmtcnt >= 0) { + c = Py_CHARMASK(*fmt++); + if (c < '0' || c > '9') + break; + if ((prec*10) / 10 != prec) { + PyErr_SetString(PyExc_ValueError, + "prec too big"); + goto onError; + } + prec = prec*10 + (c - '0'); + } + } + } /* prec */ + if (fmtcnt >= 0) { + if (c == 'h' || c == 'l' || c == 'L') { + if (--fmtcnt >= 0) + c = *fmt++; + } + } + if (fmtcnt < 0) { + PyErr_SetString(PyExc_ValueError, + "incomplete format"); + goto onError; + } + if (c != '%') { + v = getnextarg(args, arglen, &argidx); + if (v == NULL) + goto onError; + } + sign = 0; + fill = ' '; + switch (c) { + + case '%': + pbuf = formatbuf; + /* presume that buffer length is at least 1 */ + pbuf[0] = '%'; + len = 1; + break; + + case 's': + case 'r': + if (PyUnicode_Check(v) && c == 's') { + temp = v; + Py_INCREF(temp); + } + else { + PyObject *unicode; + if (c == 's') + temp = PyObject_Unicode(v); + else + temp = PyObject_Repr(v); + if (temp == NULL) + goto onError; + if (PyUnicode_Check(temp)) + /* nothing to do */; + else if (PyString_Check(temp)) { + /* convert to string to Unicode */ + unicode = PyUnicode_Decode(PyString_AS_STRING(temp), + PyString_GET_SIZE(temp), + NULL, + "strict"); + Py_DECREF(temp); + temp = unicode; + if (temp == NULL) + goto onError; + } + else { + Py_DECREF(temp); + PyErr_SetString(PyExc_TypeError, + "%s argument has non-string str()"); + goto onError; + } + } + pbuf = PyUnicode_AS_UNICODE(temp); + len = PyUnicode_GET_SIZE(temp); + if (prec >= 0 && len > prec) + len = prec; + break; + + case 'i': + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (c == 'i') + c = 'd'; + if (PyLong_Check(v)) { + temp = formatlong(v, flags, prec, c); + if (!temp) + goto onError; + pbuf = PyUnicode_AS_UNICODE(temp); + len = PyUnicode_GET_SIZE(temp); + sign = 1; + } + else { + pbuf = formatbuf; + len = formatint(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), + flags, prec, c, v); + if (len < 0) + goto onError; + sign = 1; + } + if (flags & F_ZERO) + fill = '0'; + break; + + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + if (c == 'F') + c = 'f'; + pbuf = formatbuf; + len = formatfloat(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), + flags, prec, c, v); + if (len < 0) + goto onError; + sign = 1; + if (flags & F_ZERO) + fill = '0'; + break; + + case 'c': + pbuf = formatbuf; + len = formatchar(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), v); + if (len < 0) + goto onError; + break; + + default: + PyErr_Format(PyExc_ValueError, + "unsupported format character '%c' (0x%x) " + "at index %zd", + (31<=c && c<=126) ? (char)c : '?', + (int)c, + (Py_ssize_t)(fmt - 1 - + PyUnicode_AS_UNICODE(uformat))); + goto onError; + } + if (sign) { + if (*pbuf == '-' || *pbuf == '+') { + sign = *pbuf++; + len--; + } + else if (flags & F_SIGN) + sign = '+'; + else if (flags & F_BLANK) + sign = ' '; + else + sign = 0; + } + if (width < len) + width = len; + if (rescnt - (sign != 0) < width) { + reslen -= rescnt; + rescnt = width + fmtcnt + 100; + reslen += rescnt; + if (reslen < 0) { + Py_XDECREF(temp); + PyErr_NoMemory(); + goto onError; + } + if (_PyUnicode_Resize(&result, reslen) < 0) { + Py_XDECREF(temp); + goto onError; + } + res = PyUnicode_AS_UNICODE(result) + + reslen - rescnt; + } + if (sign) { + if (fill != ' ') + *res++ = sign; + rescnt--; + if (width > len) + width--; + } + if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + assert(pbuf[1] == c); + if (fill != ' ') { + *res++ = *pbuf++; + *res++ = *pbuf++; + } + rescnt -= 2; + width -= 2; + if (width < 0) + width = 0; + len -= 2; + } + if (width > len && !(flags & F_LJUST)) { + do { + --rescnt; + *res++ = fill; + } while (--width > len); + } + if (fill == ' ') { + if (sign) + *res++ = sign; + if ((flags & F_ALT) && (c == 'x' || c == 'X')) { + assert(pbuf[0] == '0'); + assert(pbuf[1] == c); + *res++ = *pbuf++; + *res++ = *pbuf++; + } + } + Py_UNICODE_COPY(res, pbuf, len); + res += len; + rescnt -= len; + while (--width >= len) { + --rescnt; + *res++ = ' '; + } + if (dict && (argidx < arglen) && c != '%') { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + Py_XDECREF(temp); + goto onError; + } + Py_XDECREF(temp); + } /* '%' */ + } /* until end */ + if (argidx < arglen && !dict) { + PyErr_SetString(PyExc_TypeError, + "not all arguments converted during string formatting"); + goto onError; + } + + if (_PyUnicode_Resize(&result, reslen - rescnt) < 0) + goto onError; + if (args_owned) { + Py_DECREF(args); + } + Py_DECREF(uformat); + return (PyObject *)result; + + onError: + Py_XDECREF(result); + Py_DECREF(uformat); + if (args_owned) { + Py_DECREF(args); + } + return NULL; +} + +static PyBufferProcs unicode_as_buffer = { + (readbufferproc) unicode_buffer_getreadbuf, + (writebufferproc) unicode_buffer_getwritebuf, + (segcountproc) unicode_buffer_getsegcount, + (charbufferproc) unicode_buffer_getcharbuf, +}; + +static PyObject * +unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static PyObject * +unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *x = NULL; + static char *kwlist[] = {"string", "encoding", "errors", 0}; + char *encoding = NULL; + char *errors = NULL; + + if (type != &PyUnicode_Type) + return unicode_subtype_new(type, args, kwds); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:unicode", + kwlist, &x, &encoding, &errors)) + return NULL; + if (x == NULL) + return (PyObject *)_PyUnicode_New(0); + if (encoding == NULL && errors == NULL) + return PyObject_Unicode(x); + else + return PyUnicode_FromEncodedObject(x, encoding, errors); +} + +static PyObject * +unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyUnicodeObject *tmp, *pnew; + Py_ssize_t n; + + assert(PyType_IsSubtype(type, &PyUnicode_Type)); + tmp = (PyUnicodeObject *)unicode_new(&PyUnicode_Type, args, kwds); + if (tmp == NULL) + return NULL; + assert(PyUnicode_Check(tmp)); + pnew = (PyUnicodeObject *) type->tp_alloc(type, n = tmp->length); + if (pnew == NULL) { + Py_DECREF(tmp); + return NULL; + } + pnew->str = PyMem_NEW(Py_UNICODE, n+1); + if (pnew->str == NULL) { + _Py_ForgetReference((PyObject *)pnew); + PyObject_Del(pnew); + Py_DECREF(tmp); + return PyErr_NoMemory(); + } + Py_UNICODE_COPY(pnew->str, tmp->str, n+1); + pnew->length = n; + pnew->hash = tmp->hash; + Py_DECREF(tmp); + return (PyObject *)pnew; +} + +PyDoc_STRVAR(unicode_doc, +"unicode(string [, encoding[, errors]]) -> object\n\ +\n\ +Create a new Unicode object from the given encoded string.\n\ +encoding defaults to the current default string encoding.\n\ +errors can be 'strict', 'replace' or 'ignore' and defaults to 'strict'."); + +PyTypeObject PyUnicode_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "unicode", /* tp_name */ + sizeof(PyUnicodeObject), /* tp_size */ + 0, /* tp_itemsize */ + /* Slots */ + (destructor)unicode_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + unicode_repr, /* tp_repr */ + &unicode_as_number, /* tp_as_number */ + &unicode_as_sequence, /* tp_as_sequence */ + &unicode_as_mapping, /* tp_as_mapping */ + (hashfunc) unicode_hash, /* tp_hash*/ + 0, /* tp_call*/ + (reprfunc) unicode_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + &unicode_as_buffer, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + unicode_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + PyUnicode_RichCompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + unicode_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyBaseString_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + unicode_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + +/* Initialize the Unicode implementation */ + +void _PyUnicode_Init(void) +{ + int i; + + /* XXX - move this array to unicodectype.c ? */ + Py_UNICODE linebreak[] = { + 0x000A, /* LINE FEED */ + 0x000D, /* CARRIAGE RETURN */ + 0x001C, /* FILE SEPARATOR */ + 0x001D, /* GROUP SEPARATOR */ + 0x001E, /* RECORD SEPARATOR */ + 0x0085, /* NEXT LINE */ + 0x2028, /* LINE SEPARATOR */ + 0x2029, /* PARAGRAPH SEPARATOR */ + }; + + /* Init the implementation */ + unicode_freelist = NULL; + unicode_freelist_size = 0; + unicode_empty = _PyUnicode_New(0); + if (!unicode_empty) + return; + + strcpy(unicode_default_encoding, "ascii"); + for (i = 0; i < 256; i++) + unicode_latin1[i] = NULL; + if (PyType_Ready(&PyUnicode_Type) < 0) + Py_FatalError("Can't initialize 'unicode'"); + + /* initialize the linebreak bloom filter */ + bloom_linebreak = make_bloom_mask( + linebreak, sizeof(linebreak) / sizeof(linebreak[0]) + ); + + PyType_Ready(&EncodingMapType); +} + +/* Finalize the Unicode implementation */ + +void +_PyUnicode_Fini(void) +{ + PyUnicodeObject *u; + int i; + + Py_XDECREF(unicode_empty); + unicode_empty = NULL; + + for (i = 0; i < 256; i++) { + if (unicode_latin1[i]) { + Py_DECREF(unicode_latin1[i]); + unicode_latin1[i] = NULL; + } + } + + for (u = unicode_freelist; u != NULL;) { + PyUnicodeObject *v = u; + u = *(PyUnicodeObject **)u; + if (v->str) + PyMem_DEL(v->str); + Py_XDECREF(v->defenc); + PyObject_Del(v); + } + unicode_freelist = NULL; + unicode_freelist_size = 0; +} + +#ifdef __cplusplus +} +#endif + + +/* +Local variables: +c-basic-offset: 4 +indent-tabs-mode: nil +End: +*/ diff --git a/sys/src/cmd/python/Objects/unicodetype_db.h b/sys/src/cmd/python/Objects/unicodetype_db.h new file mode 100644 index 000000000..2a49a810a --- /dev/null +++ b/sys/src/cmd/python/Objects/unicodetype_db.h @@ -0,0 +1,1269 @@ +/* this file was generated by Tools/unicode/makeunicodedata.py 2.5 */ + +/* a list of unique character type descriptors */ +const _PyUnicode_TypeRecord _PyUnicode_TypeRecords[] = { + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 32}, + {0, 0, 0, 0, 0, 48}, + {0, 0, 0, 0, 0, 6}, + {0, 0, 0, 1, 1, 6}, + {0, 0, 0, 2, 2, 6}, + {0, 0, 0, 3, 3, 6}, + {0, 0, 0, 4, 4, 6}, + {0, 0, 0, 5, 5, 6}, + {0, 0, 0, 6, 6, 6}, + {0, 0, 0, 7, 7, 6}, + {0, 0, 0, 8, 8, 6}, + {0, 0, 0, 9, 9, 6}, + {0, 32, 0, 0, 0, 129}, + {65504, 0, 65504, 0, 0, 9}, + {0, 0, 0, 0, 0, 9}, + {0, 0, 0, 0, 2, 4}, + {0, 0, 0, 0, 3, 4}, + {743, 0, 743, 0, 0, 9}, + {0, 0, 0, 0, 1, 4}, + {121, 0, 121, 0, 0, 9}, + {0, 1, 0, 0, 0, 129}, + {65535, 0, 65535, 0, 0, 9}, + {0, 65337, 0, 0, 0, 129}, + {65304, 0, 65304, 0, 0, 9}, + {0, 65415, 0, 0, 0, 129}, + {65236, 0, 65236, 0, 0, 9}, + {0, 210, 0, 0, 0, 129}, + {0, 206, 0, 0, 0, 129}, + {0, 205, 0, 0, 0, 129}, + {0, 79, 0, 0, 0, 129}, + {0, 202, 0, 0, 0, 129}, + {0, 203, 0, 0, 0, 129}, + {0, 207, 0, 0, 0, 129}, + {97, 0, 97, 0, 0, 9}, + {0, 211, 0, 0, 0, 129}, + {0, 209, 0, 0, 0, 129}, + {163, 0, 163, 0, 0, 9}, + {0, 213, 0, 0, 0, 129}, + {130, 0, 130, 0, 0, 9}, + {0, 214, 0, 0, 0, 129}, + {0, 218, 0, 0, 0, 129}, + {0, 217, 0, 0, 0, 129}, + {0, 219, 0, 0, 0, 129}, + {0, 0, 0, 0, 0, 1}, + {56, 0, 56, 0, 0, 9}, + {0, 2, 1, 0, 0, 129}, + {65535, 1, 0, 0, 0, 65}, + {65534, 0, 65535, 0, 0, 9}, + {65457, 0, 65457, 0, 0, 9}, + {0, 65439, 0, 0, 0, 129}, + {0, 65480, 0, 0, 0, 129}, + {0, 65406, 0, 0, 0, 129}, + {0, 0, 0, 0, 0, 129}, + {0, 65373, 0, 0, 0, 129}, + {0, 83, 0, 0, 0, 129}, + {65326, 0, 65326, 0, 0, 9}, + {65330, 0, 65330, 0, 0, 9}, + {65331, 0, 65331, 0, 0, 9}, + {65334, 0, 65334, 0, 0, 9}, + {65333, 0, 65333, 0, 0, 9}, + {65329, 0, 65329, 0, 0, 9}, + {65327, 0, 65327, 0, 0, 9}, + {65325, 0, 65325, 0, 0, 9}, + {65323, 0, 65323, 0, 0, 9}, + {65322, 0, 65322, 0, 0, 9}, + {65318, 0, 65318, 0, 0, 9}, + {65319, 0, 65319, 0, 0, 9}, + {65317, 0, 65317, 0, 0, 9}, + {65453, 0, 65453, 0, 0, 9}, + {84, 0, 84, 0, 0, 0}, + {0, 38, 0, 0, 0, 129}, + {0, 37, 0, 0, 0, 129}, + {0, 64, 0, 0, 0, 129}, + {0, 63, 0, 0, 0, 129}, + {65498, 0, 65498, 0, 0, 9}, + {65499, 0, 65499, 0, 0, 9}, + {65505, 0, 65505, 0, 0, 9}, + {65472, 0, 65472, 0, 0, 9}, + {65473, 0, 65473, 0, 0, 9}, + {65474, 0, 65474, 0, 0, 9}, + {65479, 0, 65479, 0, 0, 9}, + {65489, 0, 65489, 0, 0, 9}, + {65482, 0, 65482, 0, 0, 9}, + {65450, 0, 65450, 0, 0, 9}, + {65456, 0, 65456, 0, 0, 9}, + {7, 0, 7, 0, 0, 9}, + {0, 65476, 0, 0, 0, 129}, + {65440, 0, 65440, 0, 0, 9}, + {0, 65529, 0, 0, 0, 129}, + {0, 80, 0, 0, 0, 129}, + {0, 48, 0, 0, 0, 129}, + {65488, 0, 65488, 0, 0, 9}, + {0, 7264, 0, 0, 0, 129}, + {0, 0, 0, 0, 4, 4}, + {0, 0, 0, 0, 5, 4}, + {0, 0, 0, 0, 6, 4}, + {0, 0, 0, 0, 7, 4}, + {0, 0, 0, 0, 8, 4}, + {0, 0, 0, 0, 9, 4}, + {65477, 0, 65477, 0, 0, 9}, + {8, 0, 8, 0, 0, 9}, + {0, 65528, 0, 0, 0, 129}, + {74, 0, 74, 0, 0, 9}, + {86, 0, 86, 0, 0, 9}, + {100, 0, 100, 0, 0, 9}, + {128, 0, 128, 0, 0, 9}, + {112, 0, 112, 0, 0, 9}, + {126, 0, 126, 0, 0, 9}, + {0, 65528, 0, 0, 0, 65}, + {9, 0, 9, 0, 0, 9}, + {0, 65462, 0, 0, 0, 129}, + {0, 65527, 0, 0, 0, 65}, + {58331, 0, 58331, 0, 0, 9}, + {0, 65450, 0, 0, 0, 129}, + {0, 65436, 0, 0, 0, 129}, + {0, 65424, 0, 0, 0, 129}, + {0, 65408, 0, 0, 0, 129}, + {0, 65410, 0, 0, 0, 129}, + {0, 0, 0, 0, 0, 4}, + {0, 58019, 0, 0, 0, 129}, + {0, 57153, 0, 0, 0, 129}, + {0, 57274, 0, 0, 0, 129}, + {0, 16, 0, 0, 0, 0}, + {65520, 0, 65520, 0, 0, 0}, + {0, 26, 0, 0, 0, 0}, + {65510, 0, 65510, 0, 0, 0}, + {58272, 0, 58272, 0, 0, 9}, + {0, 40, 0, 0, 0, 129}, + {65496, 0, 65496, 0, 0, 9}, +}; + +/* type indexes */ +#define SHIFT 8 +static unsigned char index1[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 8, 8, 27, 28, 29, 30, 31, 32, 33, 34, 32, 35, 36, + 32, 32, 32, 37, 38, 39, 40, 41, 42, 43, 44, 32, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 45, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 46, 21, 21, 21, 21, 47, 8, 8, + 48, 49, 8, 8, 8, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 50, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 21, 51, 52, 21, 53, 54, 55, 56, 57, + 8, 58, 59, 8, 8, 8, 60, 8, 61, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 62, 63, 64, 65, 66, 67, 68, + 69, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 70, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 21, 21, 71, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 72, 73, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 74, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 74, +}; + +static unsigned char index2[] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 1, 1, 1, 1, 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 16, 1, 1, 1, + 1, 1, 1, 1, 17, 18, 1, 19, 1, 1, 1, 20, 16, 1, 1, 1, 1, 1, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 1, 14, 14, 14, 14, 14, 14, 14, 16, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 15, + 15, 15, 15, 15, 15, 15, 21, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 24, 25, 22, 23, 22, 23, 22, 23, 16, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 16, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 26, 22, 23, 22, 23, 22, 23, 27, 16, 28, 22, 23, 22, 23, 29, 22, 23, + 30, 30, 22, 23, 16, 31, 32, 33, 22, 23, 30, 34, 35, 36, 37, 22, 23, 38, + 16, 36, 39, 40, 41, 22, 23, 22, 23, 22, 23, 42, 22, 23, 42, 16, 16, 22, + 23, 42, 22, 23, 43, 43, 22, 23, 22, 23, 44, 22, 23, 16, 45, 22, 23, 16, + 46, 45, 45, 45, 45, 47, 48, 49, 47, 48, 49, 47, 48, 49, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 50, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 16, 47, 48, 49, 22, + 23, 51, 52, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 53, 16, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 16, 16, 16, 16, 16, 16, 54, 22, 23, + 55, 54, 16, 16, 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, + 57, 58, 16, 59, 59, 16, 60, 16, 61, 16, 16, 16, 16, 59, 16, 16, 62, 16, + 16, 16, 16, 63, 64, 16, 16, 16, 16, 16, 64, 16, 16, 65, 16, 16, 66, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 67, 16, 16, 67, 16, 16, 16, 16, 67, + 16, 68, 68, 16, 16, 16, 16, 16, 16, 69, 16, 70, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 71, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, + 0, 45, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 72, 1, 73, 73, 73, 0, 74, 0, 75, + 75, 16, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 76, 77, 77, 77, 16, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 78, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 79, 80, 80, 0, 81, 82, 54, 54, 54, 83, 84, + 16, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 85, 86, 87, 16, 88, 89, 1, 22, 23, 90, 22, + 23, 16, 54, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 1, 1, 1, 1, 1, 0, 1, 1, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 54, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 0, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 0, 0, 0, 0, 0, 0, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 0, 45, 1, 1, 1, 1, 1, + 1, 0, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 16, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 45, + 45, 45, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 45, 45, 1, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 45, 45, 1, 1, 1, 1, 1, 1, 1, 45, 45, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 45, 45, 45, 1, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, + 45, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 45, 1, 1, 1, 1, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, + 1, 1, 1, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, + 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 0, 0, + 0, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, + 1, 1, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 45, 45, 0, 45, 45, 45, + 1, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 45, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 0, 0, 0, + 0, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, + 0, 45, 45, 0, 45, 45, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 0, 45, 0, 0, 0, + 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 45, 45, 45, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, + 45, 0, 45, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 1, 1, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, + 45, 1, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, + 0, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, + 0, 45, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, + 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 45, 45, 0, 45, 45, + 45, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 45, 0, 45, 45, 45, 45, 45, 45, 0, 0, + 0, 45, 45, 45, 0, 45, 45, 45, 45, 0, 0, 0, 45, 45, 0, 45, 0, 45, 45, 0, + 0, 0, 45, 45, 0, 0, 0, 45, 45, 45, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, + 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, + 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 0, 0, + 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, + 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, + 45, 45, 45, 45, 45, 0, 0, 1, 45, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 45, 0, 45, 45, + 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 0, + 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, + 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 45, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 0, 0, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 1, 45, 45, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 45, 45, + 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 0, 45, 0, 0, + 45, 45, 0, 45, 0, 0, 45, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 0, 45, 45, 45, + 45, 45, 45, 45, 0, 45, 45, 45, 0, 45, 0, 45, 0, 0, 45, 45, 0, 45, 45, 45, + 45, 1, 45, 45, 1, 1, 1, 1, 1, 1, 0, 1, 1, 45, 0, 0, 45, 45, 45, 45, 45, + 0, 45, 0, 1, 1, 1, 1, 1, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, + 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 0, + 45, 45, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, + 45, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, + 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 0, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 0, + 45, 0, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 0, 0, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, + 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 0, 45, 45, 45, 45, 0, 0, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 17, 18, 95, 96, 97, + 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 45, 45, 45, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 45, 1, 1, 1, 1, 45, 1, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 45, + 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, + 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, + 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 16, 16, 16, 16, 16, 101, 0, 0, 0, 0, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 0, 0, 0, 0, 0, 0, + 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, 103, 103, + 103, 103, 102, 102, 102, 102, 102, 102, 0, 0, 103, 103, 103, 103, 103, + 103, 0, 0, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, 103, 103, + 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, + 103, 103, 103, 103, 103, 103, 102, 102, 102, 102, 102, 102, 0, 0, 103, + 103, 103, 103, 103, 103, 0, 0, 16, 102, 16, 102, 16, 102, 16, 102, 0, + 103, 0, 103, 0, 103, 0, 103, 102, 102, 102, 102, 102, 102, 102, 102, 103, + 103, 103, 103, 103, 103, 103, 103, 104, 104, 105, 105, 105, 105, 106, + 106, 107, 107, 108, 108, 109, 109, 0, 0, 102, 102, 102, 102, 102, 102, + 102, 102, 110, 110, 110, 110, 110, 110, 110, 110, 102, 102, 102, 102, + 102, 102, 102, 102, 110, 110, 110, 110, 110, 110, 110, 110, 102, 102, + 102, 102, 102, 102, 102, 102, 110, 110, 110, 110, 110, 110, 110, 110, + 102, 102, 16, 111, 16, 0, 16, 16, 103, 103, 112, 112, 113, 1, 114, 1, 1, + 1, 16, 111, 16, 0, 16, 16, 115, 115, 115, 115, 113, 1, 1, 1, 102, 102, + 16, 16, 0, 0, 16, 16, 103, 103, 116, 116, 0, 1, 1, 1, 102, 102, 16, 16, + 16, 87, 16, 16, 103, 103, 117, 117, 90, 1, 1, 1, 0, 0, 16, 111, 16, 0, + 16, 16, 118, 118, 119, 119, 113, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 120, 16, 0, 0, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, + 16, 120, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 0, 45, 45, + 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 54, 1, 1, 1, 1, 54, 1, + 1, 16, 54, 54, 54, 16, 16, 54, 54, 54, 16, 1, 54, 1, 1, 1, 54, 54, 54, + 54, 54, 1, 1, 1, 1, 1, 1, 54, 1, 121, 1, 54, 1, 122, 123, 54, 54, 1, 16, + 54, 54, 1, 54, 16, 45, 45, 45, 45, 16, 1, 1, 16, 16, 54, 54, 1, 1, 1, 1, + 1, 54, 16, 16, 16, 16, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, + 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, 125, 125, 125, 125, + 125, 125, 125, 125, 125, 125, 125, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, + 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 120, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 120, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, + 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, + 20, 17, 18, 95, 96, 97, 98, 99, 100, 1, 20, 17, 18, 95, 96, 97, 98, 99, + 100, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 0, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 22, 23, 22, 23, 22, 23, 16, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, + 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, + 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, + 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 2, 1, 1, 1, 1, 45, 45, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, + 45, 45, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 0, 1, 1, 1, 1, 45, 45, 45, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 45, 45, 45, 45, 0, 0, 0, 0, 0, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 45, 1, 45, 45, 45, 1, 45, 45, 45, 45, 1, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, + 16, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 16, 16, 16, 16, 0, 0, 0, + 0, 0, 45, 1, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 0, 45, 0, 45, + 45, 0, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 1, 1, 1, 1, 1, 1, 1, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 1, 1, 1, 1, + 1, 1, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, + 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 0, 0, 45, 45, 45, + 45, 45, 45, 0, 0, 45, 45, 45, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 1, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, + 45, 45, 45, 45, 45, 45, 45, 45, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, + 129, 129, 129, 129, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, + 130, 130, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 0, 0, + 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 45, 45, 0, 0, 0, 45, 0, 0, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 45, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 45, 45, 45, 45, 0, 45, + 45, 45, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 0, 1, 20, 17, 18, 95, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 0, 54, 54, 0, 0, 54, 0, 0, + 54, 54, 0, 0, 54, 54, 54, 54, 0, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, + 16, 16, 0, 16, 0, 16, 16, 16, 16, 16, 16, 16, 0, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 54, 54, 0, 54, 54, 54, 54, 0, 0, 54, 54, 54, 54, 54, 54, 54, + 54, 0, 54, 54, 54, 54, 54, 54, 54, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, + 54, 0, 54, 54, 54, 54, 0, 54, 54, 54, 54, 54, 0, 54, 0, 0, 0, 54, 54, 54, + 54, 54, 54, 54, 0, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 0, 0, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 1, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 1, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 1, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 1, 16, 16, 16, 16, 16, 16, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 1, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, 16, 16, 16, 16, 16, 16, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 1, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, 16, 16, 16, 16, + 16, 16, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 1, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 1, + 16, 16, 16, 16, 16, 16, 0, 0, 0, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, +}; + diff --git a/sys/src/cmd/python/Objects/weakrefobject.c b/sys/src/cmd/python/Objects/weakrefobject.c new file mode 100644 index 000000000..a404f29ad --- /dev/null +++ b/sys/src/cmd/python/Objects/weakrefobject.c @@ -0,0 +1,941 @@ +#include "Python.h" +#include "structmember.h" + + +#define GET_WEAKREFS_LISTPTR(o) \ + ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o)) + + +Py_ssize_t +_PyWeakref_GetWeakrefCount(PyWeakReference *head) +{ + Py_ssize_t count = 0; + + while (head != NULL) { + ++count; + head = head->wr_next; + } + return count; +} + + +static void +init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback) +{ + self->hash = -1; + self->wr_object = ob; + Py_XINCREF(callback); + self->wr_callback = callback; +} + +static PyWeakReference * +new_weakref(PyObject *ob, PyObject *callback) +{ + PyWeakReference *result; + + result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType); + if (result) { + init_weakref(result, ob, callback); + PyObject_GC_Track(result); + } + return result; +} + + +/* This function clears the passed-in reference and removes it from the + * list of weak references for the referent. This is the only code that + * removes an item from the doubly-linked list of weak references for an + * object; it is also responsible for clearing the callback slot. + */ +static void +clear_weakref(PyWeakReference *self) +{ + PyObject *callback = self->wr_callback; + + if (PyWeakref_GET_OBJECT(self) != Py_None) { + PyWeakReference **list = GET_WEAKREFS_LISTPTR( + PyWeakref_GET_OBJECT(self)); + + if (*list == self) + /* If 'self' is the end of the list (and thus self->wr_next == NULL) + then the weakref list itself (and thus the value of *list) will + end up being set to NULL. */ + *list = self->wr_next; + self->wr_object = Py_None; + if (self->wr_prev != NULL) + self->wr_prev->wr_next = self->wr_next; + if (self->wr_next != NULL) + self->wr_next->wr_prev = self->wr_prev; + self->wr_prev = NULL; + self->wr_next = NULL; + } + if (callback != NULL) { + Py_DECREF(callback); + self->wr_callback = NULL; + } +} + +/* Cyclic gc uses this to *just* clear the passed-in reference, leaving + * the callback intact and uncalled. It must be possible to call self's + * tp_dealloc() after calling this, so self has to be left in a sane enough + * state for that to work. We expect tp_dealloc to decref the callback + * then. The reason for not letting clear_weakref() decref the callback + * right now is that if the callback goes away, that may in turn trigger + * another callback (if a weak reference to the callback exists) -- running + * arbitrary Python code in the middle of gc is a disaster. The convolution + * here allows gc to delay triggering such callbacks until the world is in + * a sane state again. + */ +void +_PyWeakref_ClearRef(PyWeakReference *self) +{ + PyObject *callback; + + assert(self != NULL); + assert(PyWeakref_Check(self)); + /* Preserve and restore the callback around clear_weakref. */ + callback = self->wr_callback; + self->wr_callback = NULL; + clear_weakref(self); + self->wr_callback = callback; +} + +static void +weakref_dealloc(PyObject *self) +{ + PyObject_GC_UnTrack(self); + clear_weakref((PyWeakReference *) self); + self->ob_type->tp_free(self); +} + + +static int +gc_traverse(PyWeakReference *self, visitproc visit, void *arg) +{ + Py_VISIT(self->wr_callback); + return 0; +} + + +static int +gc_clear(PyWeakReference *self) +{ + clear_weakref(self); + return 0; +} + + +static PyObject * +weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw) +{ + static char *kwlist[] = {NULL}; + + if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) { + PyObject *object = PyWeakref_GET_OBJECT(self); + Py_INCREF(object); + return (object); + } + return NULL; +} + + +static long +weakref_hash(PyWeakReference *self) +{ + if (self->hash != -1) + return self->hash; + if (PyWeakref_GET_OBJECT(self) == Py_None) { + PyErr_SetString(PyExc_TypeError, "weak object has gone away"); + return -1; + } + self->hash = PyObject_Hash(PyWeakref_GET_OBJECT(self)); + return self->hash; +} + + +static PyObject * +weakref_repr(PyWeakReference *self) +{ + char buffer[256]; + if (PyWeakref_GET_OBJECT(self) == Py_None) { + PyOS_snprintf(buffer, sizeof(buffer), "<weakref at %p; dead>", self); + } + else { + char *name = NULL; + PyObject *nameobj = PyObject_GetAttrString(PyWeakref_GET_OBJECT(self), + "__name__"); + if (nameobj == NULL) + PyErr_Clear(); + else if (PyString_Check(nameobj)) + name = PyString_AS_STRING(nameobj); + PyOS_snprintf(buffer, sizeof(buffer), + name ? "<weakref at %p; to '%.50s' at %p (%s)>" + : "<weakref at %p; to '%.50s' at %p>", + self, + PyWeakref_GET_OBJECT(self)->ob_type->tp_name, + PyWeakref_GET_OBJECT(self), + name); + Py_XDECREF(nameobj); + } + return PyString_FromString(buffer); +} + +/* Weak references only support equality, not ordering. Two weak references + are equal if the underlying objects are equal. If the underlying object has + gone away, they are equal if they are identical. */ + +static PyObject * +weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) +{ + if (op != Py_EQ || self->ob_type != other->ob_type) { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + if (PyWeakref_GET_OBJECT(self) == Py_None + || PyWeakref_GET_OBJECT(other) == Py_None) { + PyObject *res = self==other ? Py_True : Py_False; + Py_INCREF(res); + return res; + } + return PyObject_RichCompare(PyWeakref_GET_OBJECT(self), + PyWeakref_GET_OBJECT(other), op); +} + +/* Given the head of an object's list of weak references, extract the + * two callback-less refs (ref and proxy). Used to determine if the + * shared references exist and to determine the back link for newly + * inserted references. + */ +static void +get_basic_refs(PyWeakReference *head, + PyWeakReference **refp, PyWeakReference **proxyp) +{ + *refp = NULL; + *proxyp = NULL; + + if (head != NULL && head->wr_callback == NULL) { + /* We need to be careful that the "basic refs" aren't + subclasses of the main types. That complicates this a + little. */ + if (PyWeakref_CheckRefExact(head)) { + *refp = head; + head = head->wr_next; + } + if (head != NULL + && head->wr_callback == NULL + && PyWeakref_CheckProxy(head)) { + *proxyp = head; + /* head = head->wr_next; */ + } + } +} + +/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */ +static void +insert_after(PyWeakReference *newref, PyWeakReference *prev) +{ + newref->wr_prev = prev; + newref->wr_next = prev->wr_next; + if (prev->wr_next != NULL) + prev->wr_next->wr_prev = newref; + prev->wr_next = newref; +} + +/* Insert 'newref' at the head of the list; 'list' points to the variable + * that stores the head. + */ +static void +insert_head(PyWeakReference *newref, PyWeakReference **list) +{ + PyWeakReference *next = *list; + + newref->wr_prev = NULL; + newref->wr_next = next; + if (next != NULL) + next->wr_prev = newref; + *list = newref; +} + +static int +parse_weakref_init_args(char *funcname, PyObject *args, PyObject *kwargs, + PyObject **obp, PyObject **callbackp) +{ + /* XXX Should check that kwargs == NULL or is empty. */ + return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp); +} + +static PyObject * +weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyWeakReference *self = NULL; + PyObject *ob, *callback = NULL; + + if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) { + PyWeakReference *ref, *proxy; + PyWeakReference **list; + + if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { + PyErr_Format(PyExc_TypeError, + "cannot create weak reference to '%s' object", + ob->ob_type->tp_name); + return NULL; + } + if (callback == Py_None) + callback = NULL; + list = GET_WEAKREFS_LISTPTR(ob); + get_basic_refs(*list, &ref, &proxy); + if (callback == NULL && type == &_PyWeakref_RefType) { + if (ref != NULL) { + /* We can re-use an existing reference. */ + Py_INCREF(ref); + return (PyObject *)ref; + } + } + /* We have to create a new reference. */ + /* Note: the tp_alloc() can trigger cyclic GC, so the weakref + list on ob can be mutated. This means that the ref and + proxy pointers we got back earlier may have been collected, + so we need to compute these values again before we use + them. */ + self = (PyWeakReference *) (type->tp_alloc(type, 0)); + if (self != NULL) { + init_weakref(self, ob, callback); + if (callback == NULL && type == &_PyWeakref_RefType) { + insert_head(self, list); + } + else { + PyWeakReference *prev; + + get_basic_refs(*list, &ref, &proxy); + prev = (proxy == NULL) ? ref : proxy; + if (prev == NULL) + insert_head(self, list); + else + insert_after(self, prev); + } + } + } + return (PyObject *)self; +} + +static int +weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *tmp; + + if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp)) + return 0; + else + return 1; +} + + +PyTypeObject +_PyWeakref_RefType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "weakref", + sizeof(PyWeakReference), + 0, + weakref_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc)weakref_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + (hashfunc)weakref_hash, /*tp_hash*/ + (ternaryfunc)weakref_call, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_RICHCOMPARE + | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + 0, /*tp_doc*/ + (traverseproc)gc_traverse, /*tp_traverse*/ + (inquiry)gc_clear, /*tp_clear*/ + (richcmpfunc)weakref_richcompare, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + 0, /*tp_methods*/ + 0, /*tp_members*/ + 0, /*tp_getset*/ + 0, /*tp_base*/ + 0, /*tp_dict*/ + 0, /*tp_descr_get*/ + 0, /*tp_descr_set*/ + 0, /*tp_dictoffset*/ + weakref___init__, /*tp_init*/ + PyType_GenericAlloc, /*tp_alloc*/ + weakref___new__, /*tp_new*/ + PyObject_GC_Del, /*tp_free*/ +}; + + +static int +proxy_checkref(PyWeakReference *proxy) +{ + if (PyWeakref_GET_OBJECT(proxy) == Py_None) { + PyErr_SetString(PyExc_ReferenceError, + "weakly-referenced object no longer exists"); + return 0; + } + return 1; +} + + +/* If a parameter is a proxy, check that it is still "live" and wrap it, + * replacing the original value with the raw object. Raises ReferenceError + * if the param is a dead proxy. + */ +#define UNWRAP(o) \ + if (PyWeakref_CheckProxy(o)) { \ + if (!proxy_checkref((PyWeakReference *)o)) \ + return NULL; \ + o = PyWeakref_GET_OBJECT(o); \ + } + +#define UNWRAP_I(o) \ + if (PyWeakref_CheckProxy(o)) { \ + if (!proxy_checkref((PyWeakReference *)o)) \ + return -1; \ + o = PyWeakref_GET_OBJECT(o); \ + } + +#define WRAP_UNARY(method, generic) \ + static PyObject * \ + method(PyObject *proxy) { \ + UNWRAP(proxy); \ + return generic(proxy); \ + } + +#define WRAP_BINARY(method, generic) \ + static PyObject * \ + method(PyObject *x, PyObject *y) { \ + UNWRAP(x); \ + UNWRAP(y); \ + return generic(x, y); \ + } + +/* Note that the third arg needs to be checked for NULL since the tp_call + * slot can receive NULL for this arg. + */ +#define WRAP_TERNARY(method, generic) \ + static PyObject * \ + method(PyObject *proxy, PyObject *v, PyObject *w) { \ + UNWRAP(proxy); \ + UNWRAP(v); \ + if (w != NULL) \ + UNWRAP(w); \ + return generic(proxy, v, w); \ + } + + +/* direct slots */ + +WRAP_BINARY(proxy_getattr, PyObject_GetAttr) +WRAP_UNARY(proxy_str, PyObject_Str) +WRAP_TERNARY(proxy_call, PyEval_CallObjectWithKeywords) + +static PyObject * +proxy_repr(PyWeakReference *proxy) +{ + char buf[160]; + PyOS_snprintf(buf, sizeof(buf), + "<weakproxy at %p to %.100s at %p>", proxy, + PyWeakref_GET_OBJECT(proxy)->ob_type->tp_name, + PyWeakref_GET_OBJECT(proxy)); + return PyString_FromString(buf); +} + + +static int +proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value) +{ + if (!proxy_checkref(proxy)) + return -1; + return PyObject_SetAttr(PyWeakref_GET_OBJECT(proxy), name, value); +} + +static int +proxy_compare(PyObject *proxy, PyObject *v) +{ + UNWRAP_I(proxy); + UNWRAP_I(v); + return PyObject_Compare(proxy, v); +} + +/* number slots */ +WRAP_BINARY(proxy_add, PyNumber_Add) +WRAP_BINARY(proxy_sub, PyNumber_Subtract) +WRAP_BINARY(proxy_mul, PyNumber_Multiply) +WRAP_BINARY(proxy_div, PyNumber_Divide) +WRAP_BINARY(proxy_mod, PyNumber_Remainder) +WRAP_BINARY(proxy_divmod, PyNumber_Divmod) +WRAP_TERNARY(proxy_pow, PyNumber_Power) +WRAP_UNARY(proxy_neg, PyNumber_Negative) +WRAP_UNARY(proxy_pos, PyNumber_Positive) +WRAP_UNARY(proxy_abs, PyNumber_Absolute) +WRAP_UNARY(proxy_invert, PyNumber_Invert) +WRAP_BINARY(proxy_lshift, PyNumber_Lshift) +WRAP_BINARY(proxy_rshift, PyNumber_Rshift) +WRAP_BINARY(proxy_and, PyNumber_And) +WRAP_BINARY(proxy_xor, PyNumber_Xor) +WRAP_BINARY(proxy_or, PyNumber_Or) +WRAP_UNARY(proxy_int, PyNumber_Int) +WRAP_UNARY(proxy_long, PyNumber_Long) +WRAP_UNARY(proxy_float, PyNumber_Float) +WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd) +WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract) +WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply) +WRAP_BINARY(proxy_idiv, PyNumber_InPlaceDivide) +WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder) +WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower) +WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift) +WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift) +WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd) +WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor) +WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr) + +static int +proxy_nonzero(PyWeakReference *proxy) +{ + PyObject *o = PyWeakref_GET_OBJECT(proxy); + if (!proxy_checkref(proxy)) + return -1; + return PyObject_IsTrue(o); +} + +static void +proxy_dealloc(PyWeakReference *self) +{ + if (self->wr_callback != NULL) + PyObject_GC_UnTrack((PyObject *)self); + clear_weakref(self); + PyObject_GC_Del(self); +} + +/* sequence slots */ + +static PyObject * +proxy_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j) +{ + if (!proxy_checkref(proxy)) + return NULL; + return PySequence_GetSlice(PyWeakref_GET_OBJECT(proxy), i, j); +} + +static int +proxy_ass_slice(PyWeakReference *proxy, Py_ssize_t i, Py_ssize_t j, PyObject *value) +{ + if (!proxy_checkref(proxy)) + return -1; + return PySequence_SetSlice(PyWeakref_GET_OBJECT(proxy), i, j, value); +} + +static int +proxy_contains(PyWeakReference *proxy, PyObject *value) +{ + if (!proxy_checkref(proxy)) + return -1; + return PySequence_Contains(PyWeakref_GET_OBJECT(proxy), value); +} + + +/* mapping slots */ + +static Py_ssize_t +proxy_length(PyWeakReference *proxy) +{ + if (!proxy_checkref(proxy)) + return -1; + return PyObject_Length(PyWeakref_GET_OBJECT(proxy)); +} + +WRAP_BINARY(proxy_getitem, PyObject_GetItem) + +static int +proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value) +{ + if (!proxy_checkref(proxy)) + return -1; + + if (value == NULL) + return PyObject_DelItem(PyWeakref_GET_OBJECT(proxy), key); + else + return PyObject_SetItem(PyWeakref_GET_OBJECT(proxy), key, value); +} + +/* iterator slots */ + +static PyObject * +proxy_iter(PyWeakReference *proxy) +{ + if (!proxy_checkref(proxy)) + return NULL; + return PyObject_GetIter(PyWeakref_GET_OBJECT(proxy)); +} + +static PyObject * +proxy_iternext(PyWeakReference *proxy) +{ + if (!proxy_checkref(proxy)) + return NULL; + return PyIter_Next(PyWeakref_GET_OBJECT(proxy)); +} + + +static PyNumberMethods proxy_as_number = { + proxy_add, /*nb_add*/ + proxy_sub, /*nb_subtract*/ + proxy_mul, /*nb_multiply*/ + proxy_div, /*nb_divide*/ + proxy_mod, /*nb_remainder*/ + proxy_divmod, /*nb_divmod*/ + proxy_pow, /*nb_power*/ + proxy_neg, /*nb_negative*/ + proxy_pos, /*nb_positive*/ + proxy_abs, /*nb_absolute*/ + (inquiry)proxy_nonzero, /*nb_nonzero*/ + proxy_invert, /*nb_invert*/ + proxy_lshift, /*nb_lshift*/ + proxy_rshift, /*nb_rshift*/ + proxy_and, /*nb_and*/ + proxy_xor, /*nb_xor*/ + proxy_or, /*nb_or*/ + 0, /*nb_coerce*/ + proxy_int, /*nb_int*/ + proxy_long, /*nb_long*/ + proxy_float, /*nb_float*/ + 0, /*nb_oct*/ + 0, /*nb_hex*/ + proxy_iadd, /*nb_inplace_add*/ + proxy_isub, /*nb_inplace_subtract*/ + proxy_imul, /*nb_inplace_multiply*/ + proxy_idiv, /*nb_inplace_divide*/ + proxy_imod, /*nb_inplace_remainder*/ + proxy_ipow, /*nb_inplace_power*/ + proxy_ilshift, /*nb_inplace_lshift*/ + proxy_irshift, /*nb_inplace_rshift*/ + proxy_iand, /*nb_inplace_and*/ + proxy_ixor, /*nb_inplace_xor*/ + proxy_ior, /*nb_inplace_or*/ +}; + +static PySequenceMethods proxy_as_sequence = { + (lenfunc)proxy_length, /*sq_length*/ + 0, /*sq_concat*/ + 0, /*sq_repeat*/ + 0, /*sq_item*/ + (ssizessizeargfunc)proxy_slice, /*sq_slice*/ + 0, /*sq_ass_item*/ + (ssizessizeobjargproc)proxy_ass_slice, /*sq_ass_slice*/ + (objobjproc)proxy_contains, /* sq_contains */ +}; + +static PyMappingMethods proxy_as_mapping = { + (lenfunc)proxy_length, /*mp_length*/ + proxy_getitem, /*mp_subscript*/ + (objobjargproc)proxy_setitem, /*mp_ass_subscript*/ +}; + + +PyTypeObject +_PyWeakref_ProxyType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "weakproxy", + sizeof(PyWeakReference), + 0, + /* methods */ + (destructor)proxy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + proxy_compare, /* tp_compare */ + (reprfunc)proxy_repr, /* tp_repr */ + &proxy_as_number, /* tp_as_number */ + &proxy_as_sequence, /* tp_as_sequence */ + &proxy_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + proxy_str, /* tp_str */ + proxy_getattr, /* tp_getattro */ + (setattrofunc)proxy_setattr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)gc_traverse, /* tp_traverse */ + (inquiry)gc_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)proxy_iter, /* tp_iter */ + (iternextfunc)proxy_iternext, /* tp_iternext */ +}; + + +PyTypeObject +_PyWeakref_CallableProxyType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "weakcallableproxy", + sizeof(PyWeakReference), + 0, + /* methods */ + (destructor)proxy_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + proxy_compare, /* tp_compare */ + (unaryfunc)proxy_repr, /* tp_repr */ + &proxy_as_number, /* tp_as_number */ + &proxy_as_sequence, /* tp_as_sequence */ + &proxy_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + proxy_call, /* tp_call */ + proxy_str, /* tp_str */ + proxy_getattr, /* tp_getattro */ + (setattrofunc)proxy_setattr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC + | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)gc_traverse, /* tp_traverse */ + (inquiry)gc_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + (getiterfunc)proxy_iter, /* tp_iter */ + (iternextfunc)proxy_iternext, /* tp_iternext */ +}; + + + +PyObject * +PyWeakref_NewRef(PyObject *ob, PyObject *callback) +{ + PyWeakReference *result = NULL; + PyWeakReference **list; + PyWeakReference *ref, *proxy; + + if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { + PyErr_Format(PyExc_TypeError, + "cannot create weak reference to '%s' object", + ob->ob_type->tp_name); + return NULL; + } + list = GET_WEAKREFS_LISTPTR(ob); + get_basic_refs(*list, &ref, &proxy); + if (callback == Py_None) + callback = NULL; + if (callback == NULL) + /* return existing weak reference if it exists */ + result = ref; + if (result != NULL) + Py_INCREF(result); + else { + /* Note: new_weakref() can trigger cyclic GC, so the weakref + list on ob can be mutated. This means that the ref and + proxy pointers we got back earlier may have been collected, + so we need to compute these values again before we use + them. */ + result = new_weakref(ob, callback); + if (result != NULL) { + get_basic_refs(*list, &ref, &proxy); + if (callback == NULL) { + if (ref == NULL) + insert_head(result, list); + else { + /* Someone else added a ref without a callback + during GC. Return that one instead of this one + to avoid violating the invariants of the list + of weakrefs for ob. */ + Py_DECREF(result); + Py_INCREF(ref); + result = ref; + } + } + else { + PyWeakReference *prev; + + prev = (proxy == NULL) ? ref : proxy; + if (prev == NULL) + insert_head(result, list); + else + insert_after(result, prev); + } + } + } + return (PyObject *) result; +} + + +PyObject * +PyWeakref_NewProxy(PyObject *ob, PyObject *callback) +{ + PyWeakReference *result = NULL; + PyWeakReference **list; + PyWeakReference *ref, *proxy; + + if (!PyType_SUPPORTS_WEAKREFS(ob->ob_type)) { + PyErr_Format(PyExc_TypeError, + "cannot create weak reference to '%s' object", + ob->ob_type->tp_name); + return NULL; + } + list = GET_WEAKREFS_LISTPTR(ob); + get_basic_refs(*list, &ref, &proxy); + if (callback == Py_None) + callback = NULL; + if (callback == NULL) + /* attempt to return an existing weak reference if it exists */ + result = proxy; + if (result != NULL) + Py_INCREF(result); + else { + /* Note: new_weakref() can trigger cyclic GC, so the weakref + list on ob can be mutated. This means that the ref and + proxy pointers we got back earlier may have been collected, + so we need to compute these values again before we use + them. */ + result = new_weakref(ob, callback); + if (result != NULL) { + PyWeakReference *prev; + + if (PyCallable_Check(ob)) + result->ob_type = &_PyWeakref_CallableProxyType; + else + result->ob_type = &_PyWeakref_ProxyType; + get_basic_refs(*list, &ref, &proxy); + if (callback == NULL) { + if (proxy != NULL) { + /* Someone else added a proxy without a callback + during GC. Return that one instead of this one + to avoid violating the invariants of the list + of weakrefs for ob. */ + Py_DECREF(result); + Py_INCREF(result = proxy); + goto skip_insert; + } + prev = ref; + } + else + prev = (proxy == NULL) ? ref : proxy; + + if (prev == NULL) + insert_head(result, list); + else + insert_after(result, prev); + skip_insert: + ; + } + } + return (PyObject *) result; +} + + +PyObject * +PyWeakref_GetObject(PyObject *ref) +{ + if (ref == NULL || !PyWeakref_Check(ref)) { + PyErr_BadInternalCall(); + return NULL; + } + return PyWeakref_GET_OBJECT(ref); +} + +/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's + * handle_weakrefs(). + */ +static void +handle_callback(PyWeakReference *ref, PyObject *callback) +{ + PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL); + + if (cbresult == NULL) + PyErr_WriteUnraisable(callback); + else + Py_DECREF(cbresult); +} + +/* This function is called by the tp_dealloc handler to clear weak references. + * + * This iterates through the weak references for 'object' and calls callbacks + * for those references which have one. It returns when all callbacks have + * been attempted. + */ +void +PyObject_ClearWeakRefs(PyObject *object) +{ + PyWeakReference **list; + + if (object == NULL + || !PyType_SUPPORTS_WEAKREFS(object->ob_type) + || object->ob_refcnt != 0) { + PyErr_BadInternalCall(); + return; + } + list = GET_WEAKREFS_LISTPTR(object); + /* Remove the callback-less basic and proxy references */ + if (*list != NULL && (*list)->wr_callback == NULL) { + clear_weakref(*list); + if (*list != NULL && (*list)->wr_callback == NULL) + clear_weakref(*list); + } + if (*list != NULL) { + PyWeakReference *current = *list; + Py_ssize_t count = _PyWeakref_GetWeakrefCount(current); + int restore_error = PyErr_Occurred() ? 1 : 0; + PyObject *err_type, *err_value, *err_tb; + + if (restore_error) + PyErr_Fetch(&err_type, &err_value, &err_tb); + if (count == 1) { + PyObject *callback = current->wr_callback; + + current->wr_callback = NULL; + clear_weakref(current); + if (callback != NULL) { + handle_callback(current, callback); + Py_DECREF(callback); + } + } + else { + PyObject *tuple; + Py_ssize_t i = 0; + + tuple = PyTuple_New(count * 2); + if (tuple == NULL) { + if (restore_error) + PyErr_Fetch(&err_type, &err_value, &err_tb); + return; + } + + for (i = 0; i < count; ++i) { + PyWeakReference *next = current->wr_next; + + Py_INCREF(current); + PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current); + PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback); + current->wr_callback = NULL; + clear_weakref(current); + current = next; + } + for (i = 0; i < count; ++i) { + PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1); + + if (callback != NULL) { + PyObject *item = PyTuple_GET_ITEM(tuple, i * 2); + handle_callback((PyWeakReference *)item, callback); + } + } + Py_DECREF(tuple); + } + if (restore_error) + PyErr_Restore(err_type, err_value, err_tb); + } +} diff --git a/sys/src/cmd/python/Parser/Python.asdl b/sys/src/cmd/python/Parser/Python.asdl new file mode 100644 index 000000000..fa4b406df --- /dev/null +++ b/sys/src/cmd/python/Parser/Python.asdl @@ -0,0 +1,115 @@ +-- ASDL's five builtin types are identifier, int, string, object, bool + +module Python version "$Revision: 43614 $" +{ + mod = Module(stmt* body) + | Interactive(stmt* body) + | Expression(expr body) + + -- not really an actual node but useful in Jython's typesystem. + | Suite(stmt* body) + + stmt = FunctionDef(identifier name, arguments args, + stmt* body, expr* decorators) + | ClassDef(identifier name, expr* bases, stmt* body) + | Return(expr? value) + + | Delete(expr* targets) + | Assign(expr* targets, expr value) + | AugAssign(expr target, operator op, expr value) + + -- not sure if bool is allowed, can always use int + | Print(expr? dest, expr* values, bool nl) + + -- use 'orelse' because else is a keyword in target languages + | For(expr target, expr iter, stmt* body, stmt* orelse) + | While(expr test, stmt* body, stmt* orelse) + | If(expr test, stmt* body, stmt* orelse) + | With(expr context_expr, expr? optional_vars, stmt* body) + + -- 'type' is a bad name + | Raise(expr? type, expr? inst, expr? tback) + | TryExcept(stmt* body, excepthandler* handlers, stmt* orelse) + | TryFinally(stmt* body, stmt* finalbody) + | Assert(expr test, expr? msg) + + | Import(alias* names) + | ImportFrom(identifier module, alias* names, int? level) + + -- Doesn't capture requirement that locals must be + -- defined if globals is + -- still supports use as a function! + | Exec(expr body, expr? globals, expr? locals) + + | Global(identifier* names) + | Expr(expr value) + | Pass | Break | Continue + + -- XXX Jython will be different + -- col_offset is the byte offset in the utf8 string the parser uses + attributes (int lineno, int col_offset) + + -- BoolOp() can use left & right? + expr = BoolOp(boolop op, expr* values) + | BinOp(expr left, operator op, expr right) + | UnaryOp(unaryop op, expr operand) + | Lambda(arguments args, expr body) + | IfExp(expr test, expr body, expr orelse) + | Dict(expr* keys, expr* values) + | ListComp(expr elt, comprehension* generators) + | GeneratorExp(expr elt, comprehension* generators) + -- the grammar constrains where yield expressions can occur + | Yield(expr? value) + -- need sequences for compare to distinguish between + -- x < 4 < 3 and (x < 4) < 3 + | Compare(expr left, cmpop* ops, expr* comparators) + | Call(expr func, expr* args, keyword* keywords, + expr? starargs, expr? kwargs) + | Repr(expr value) + | Num(object n) -- a number as a PyObject. + | Str(string s) -- need to specify raw, unicode, etc? + -- other literals? bools? + + -- the following expression can appear in assignment context + | Attribute(expr value, identifier attr, expr_context ctx) + | Subscript(expr value, slice slice, expr_context ctx) + | Name(identifier id, expr_context ctx) + | List(expr* elts, expr_context ctx) + | Tuple(expr *elts, expr_context ctx) + + -- col_offset is the byte offset in the utf8 string the parser uses + attributes (int lineno, int col_offset) + + expr_context = Load | Store | Del | AugLoad | AugStore | Param + + slice = Ellipsis | Slice(expr? lower, expr? upper, expr? step) + | ExtSlice(slice* dims) + | Index(expr value) + + boolop = And | Or + + operator = Add | Sub | Mult | Div | Mod | Pow | LShift + | RShift | BitOr | BitXor | BitAnd | FloorDiv + + unaryop = Invert | Not | UAdd | USub + + cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn + + comprehension = (expr target, expr iter, expr* ifs) + + -- not sure what to call the first argument for raise and except + -- TODO(jhylton): Figure out if there is a better way to handle + -- lineno and col_offset fields, particularly when + -- ast is exposed to Python. + excepthandler = (expr? type, expr? name, stmt* body, int lineno, + int col_offset) + + arguments = (expr* args, identifier? vararg, + identifier? kwarg, expr* defaults) + + -- keyword arguments supplied to call + keyword = (identifier arg, expr value) + + -- import name with optional 'as' alias. + alias = (identifier name, identifier? asname) +} diff --git a/sys/src/cmd/python/Parser/acceler.c b/sys/src/cmd/python/Parser/acceler.c new file mode 100644 index 000000000..b41b2654f --- /dev/null +++ b/sys/src/cmd/python/Parser/acceler.c @@ -0,0 +1,125 @@ + +/* Parser accelerator module */ + +/* The parser as originally conceived had disappointing performance. + This module does some precomputation that speeds up the selection + of a DFA based upon a token, turning a search through an array + into a simple indexing operation. The parser now cannot work + without the accelerators installed. Note that the accelerators + are installed dynamically when the parser is initialized, they + are not part of the static data structure written on graminit.[ch] + by the parser generator. */ + +#include "pgenheaders.h" +#include "grammar.h" +#include "node.h" +#include "token.h" +#include "parser.h" + +/* Forward references */ +static void fixdfa(grammar *, dfa *); +static void fixstate(grammar *, state *); + +void +PyGrammar_AddAccelerators(grammar *g) +{ + dfa *d; + int i; + d = g->g_dfa; + for (i = g->g_ndfas; --i >= 0; d++) + fixdfa(g, d); + g->g_accel = 1; +} + +void +PyGrammar_RemoveAccelerators(grammar *g) +{ + dfa *d; + int i; + g->g_accel = 0; + d = g->g_dfa; + for (i = g->g_ndfas; --i >= 0; d++) { + state *s; + int j; + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) { + if (s->s_accel) + PyObject_FREE(s->s_accel); + s->s_accel = NULL; + } + } +} + +static void +fixdfa(grammar *g, dfa *d) +{ + state *s; + int j; + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) + fixstate(g, s); +} + +static void +fixstate(grammar *g, state *s) +{ + arc *a; + int k; + int *accel; + int nl = g->g_ll.ll_nlabels; + s->s_accept = 0; + accel = (int *) PyObject_MALLOC(nl * sizeof(int)); + if (accel == NULL) { + fprintf(stderr, "no mem to build parser accelerators\n"); + exit(1); + } + for (k = 0; k < nl; k++) + accel[k] = -1; + a = s->s_arc; + for (k = s->s_narcs; --k >= 0; a++) { + int lbl = a->a_lbl; + label *l = &g->g_ll.ll_label[lbl]; + int type = l->lb_type; + if (a->a_arrow >= (1 << 7)) { + printf("XXX too many states!\n"); + continue; + } + if (ISNONTERMINAL(type)) { + dfa *d1 = PyGrammar_FindDFA(g, type); + int ibit; + if (type - NT_OFFSET >= (1 << 7)) { + printf("XXX too high nonterminal number!\n"); + continue; + } + for (ibit = 0; ibit < g->g_ll.ll_nlabels; ibit++) { + if (testbit(d1->d_first, ibit)) { + if (accel[ibit] != -1) + printf("XXX ambiguity!\n"); + accel[ibit] = a->a_arrow | (1 << 7) | + ((type - NT_OFFSET) << 8); + } + } + } + else if (lbl == EMPTY) + s->s_accept = 1; + else if (lbl >= 0 && lbl < nl) + accel[lbl] = a->a_arrow; + } + while (nl > 0 && accel[nl-1] == -1) + nl--; + for (k = 0; k < nl && accel[k] == -1;) + k++; + if (k < nl) { + int i; + s->s_accel = (int *) PyObject_MALLOC((nl-k) * sizeof(int)); + if (s->s_accel == NULL) { + fprintf(stderr, "no mem to add parser accelerators\n"); + exit(1); + } + s->s_lower = k; + s->s_upper = nl; + for (i = 0; k < nl; i++, k++) + s->s_accel[i] = accel[k]; + } + PyObject_FREE(accel); +} diff --git a/sys/src/cmd/python/Parser/asdl.py b/sys/src/cmd/python/Parser/asdl.py new file mode 100644 index 000000000..bd892b695 --- /dev/null +++ b/sys/src/cmd/python/Parser/asdl.py @@ -0,0 +1,415 @@ +"""An implementation of the Zephyr Abstract Syntax Definition Language. + +See http://asdl.sourceforge.net/ and +http://www.cs.princeton.edu/~danwang/Papers/dsl97/dsl97-abstract.html. + +Only supports top level module decl, not view. I'm guessing that view +is intended to support the browser and I'm not interested in the +browser. + +Changes for Python: Add support for module versions +""" + +#__metaclass__ = type + +import os +import traceback + +import spark + +class Token: + # spark seems to dispatch in the parser based on a token's + # type attribute + def __init__(self, type, lineno): + self.type = type + self.lineno = lineno + + def __str__(self): + return self.type + + def __repr__(self): + return str(self) + +class Id(Token): + def __init__(self, value, lineno): + self.type = 'Id' + self.value = value + self.lineno = lineno + + def __str__(self): + return self.value + +class String(Token): + def __init__(self, value, lineno): + self.type = 'String' + self.value = value + self.lineno = lineno + +class ASDLSyntaxError: + + def __init__(self, lineno, token=None, msg=None): + self.lineno = lineno + self.token = token + self.msg = msg + + def __str__(self): + if self.msg is None: + return "Error at '%s', line %d" % (self.token, self.lineno) + else: + return "%s, line %d" % (self.msg, self.lineno) + +class ASDLScanner(spark.GenericScanner, object): + + def tokenize(self, input): + self.rv = [] + self.lineno = 1 + super(ASDLScanner, self).tokenize(input) + return self.rv + + def t_id(self, s): + r"[\w\.]+" + # XXX doesn't distinguish upper vs. lower, which is + # significant for ASDL. + self.rv.append(Id(s, self.lineno)) + + def t_string(self, s): + r'"[^"]*"' + self.rv.append(String(s, self.lineno)) + + def t_xxx(self, s): # not sure what this production means + r"<=" + self.rv.append(Token(s, self.lineno)) + + def t_punctuation(self, s): + r"[\{\}\*\=\|\(\)\,\?\:]" + self.rv.append(Token(s, self.lineno)) + + def t_comment(self, s): + r"\-\-[^\n]*" + pass + + def t_newline(self, s): + r"\n" + self.lineno += 1 + + def t_whitespace(self, s): + r"[ \t]+" + pass + + def t_default(self, s): + r" . +" + raise ValueError, "unmatched input: %s" % `s` + +class ASDLParser(spark.GenericParser, object): + def __init__(self): + super(ASDLParser, self).__init__("module") + + def typestring(self, tok): + return tok.type + + def error(self, tok): + raise ASDLSyntaxError(tok.lineno, tok) + + def p_module_0(self, (module, name, version, _0, _1)): + " module ::= Id Id version { } " + if module.value != "module": + raise ASDLSyntaxError(module.lineno, + msg="expected 'module', found %s" % module) + return Module(name, None, version) + + def p_module(self, (module, name, version, _0, definitions, _1)): + " module ::= Id Id version { definitions } " + if module.value != "module": + raise ASDLSyntaxError(module.lineno, + msg="expected 'module', found %s" % module) + return Module(name, definitions, version) + + def p_version(self, (version, V)): + "version ::= Id String" + if version.value != "version": + raise ASDLSyntaxError(version.lineno, + msg="expected 'version', found %" % version) + return V + + def p_definition_0(self, (definition,)): + " definitions ::= definition " + return definition + + def p_definition_1(self, (definitions, definition)): + " definitions ::= definition definitions " + return definitions + definition + + def p_definition(self, (id, _, type)): + " definition ::= Id = type " + return [Type(id, type)] + + def p_type_0(self, (product,)): + " type ::= product " + return product + + def p_type_1(self, (sum,)): + " type ::= sum " + return Sum(sum) + + def p_type_2(self, (sum, id, _0, attributes, _1)): + " type ::= sum Id ( fields ) " + if id.value != "attributes": + raise ASDLSyntaxError(id.lineno, + msg="expected attributes, found %s" % id) + if attributes: + attributes.reverse() + return Sum(sum, attributes) + + def p_product(self, (_0, fields, _1)): + " product ::= ( fields ) " + # XXX can't I just construct things in the right order? + fields.reverse() + return Product(fields) + + def p_sum_0(self, (constructor,)): + " sum ::= constructor """ + return [constructor] + + def p_sum_1(self, (constructor, _, sum)): + " sum ::= constructor | sum " + return [constructor] + sum + + def p_sum_2(self, (constructor, _, sum)): + " sum ::= constructor | sum " + return [constructor] + sum + + def p_constructor_0(self, (id,)): + " constructor ::= Id " + return Constructor(id) + + def p_constructor_1(self, (id, _0, fields, _1)): + " constructor ::= Id ( fields ) " + # XXX can't I just construct things in the right order? + fields.reverse() + return Constructor(id, fields) + + def p_fields_0(self, (field,)): + " fields ::= field " + return [field] + + def p_fields_1(self, (field, _, fields)): + " fields ::= field , fields " + return fields + [field] + + def p_field_0(self, (type,)): + " field ::= Id " + return Field(type) + + def p_field_1(self, (type, name)): + " field ::= Id Id " + return Field(type, name) + + def p_field_2(self, (type, _, name)): + " field ::= Id * Id " + return Field(type, name, seq=1) + + def p_field_3(self, (type, _, name)): + " field ::= Id ? Id " + return Field(type, name, opt=1) + + def p_field_4(self, (type, _)): + " field ::= Id * " + return Field(type, seq=1) + + def p_field_5(self, (type, _)): + " field ::= Id ? " + return Field(type, opt=1) + +builtin_types = ("identifier", "string", "int", "bool", "object") + +# below is a collection of classes to capture the AST of an AST :-) +# not sure if any of the methods are useful yet, but I'm adding them +# piecemeal as they seem helpful + +class AST: + pass # a marker class + +class Module(AST): + def __init__(self, name, dfns, version): + self.name = name + self.dfns = dfns + self.version = version + self.types = {} # maps type name to value (from dfns) + for type in dfns: + self.types[type.name.value] = type.value + + def __repr__(self): + return "Module(%s, %s)" % (self.name, self.dfns) + +class Type(AST): + def __init__(self, name, value): + self.name = name + self.value = value + + def __repr__(self): + return "Type(%s, %s)" % (self.name, self.value) + +class Constructor(AST): + def __init__(self, name, fields=None): + self.name = name + self.fields = fields or [] + + def __repr__(self): + return "Constructor(%s, %s)" % (self.name, self.fields) + +class Field(AST): + def __init__(self, type, name=None, seq=0, opt=0): + self.type = type + self.name = name + self.seq = seq + self.opt = opt + + def __repr__(self): + if self.seq: + extra = ", seq=1" + elif self.opt: + extra = ", opt=1" + else: + extra = "" + if self.name is None: + return "Field(%s%s)" % (self.type, extra) + else: + return "Field(%s, %s%s)" % (self.type, self.name, extra) + +class Sum(AST): + def __init__(self, types, attributes=None): + self.types = types + self.attributes = attributes or [] + + def __repr__(self): + if self.attributes is None: + return "Sum(%s)" % self.types + else: + return "Sum(%s, %s)" % (self.types, self.attributes) + +class Product(AST): + def __init__(self, fields): + self.fields = fields + + def __repr__(self): + return "Product(%s)" % self.fields + +class VisitorBase(object): + + def __init__(self, skip=0): + self.cache = {} + self.skip = skip + + def visit(self, object, *args): + meth = self._dispatch(object) + if meth is None: + return + try: + meth(object, *args) + except Exception, err: + print "Error visiting", repr(object) + print err + traceback.print_exc() + # XXX hack + if hasattr(self, 'file'): + self.file.flush() + os._exit(1) + + def _dispatch(self, object): + assert isinstance(object, AST), repr(object) + klass = object.__class__ + meth = self.cache.get(klass) + if meth is None: + methname = "visit" + klass.__name__ + if self.skip: + meth = getattr(self, methname, None) + else: + meth = getattr(self, methname) + self.cache[klass] = meth + return meth + +class Check(VisitorBase): + + def __init__(self): + super(Check, self).__init__(skip=1) + self.cons = {} + self.errors = 0 + self.types = {} + + def visitModule(self, mod): + for dfn in mod.dfns: + self.visit(dfn) + + def visitType(self, type): + self.visit(type.value, str(type.name)) + + def visitSum(self, sum, name): + for t in sum.types: + self.visit(t, name) + + def visitConstructor(self, cons, name): + key = str(cons.name) + conflict = self.cons.get(key) + if conflict is None: + self.cons[key] = name + else: + print "Redefinition of constructor %s" % key + print "Defined in %s and %s" % (conflict, name) + self.errors += 1 + for f in cons.fields: + self.visit(f, key) + + def visitField(self, field, name): + key = str(field.type) + l = self.types.setdefault(key, []) + l.append(name) + + def visitProduct(self, prod, name): + for f in prod.fields: + self.visit(f, name) + +def check(mod): + v = Check() + v.visit(mod) + + for t in v.types: + if not mod.types.has_key(t) and not t in builtin_types: + v.errors += 1 + uses = ", ".join(v.types[t]) + print "Undefined type %s, used in %s" % (t, uses) + + return not v.errors + +def parse(file): + scanner = ASDLScanner() + parser = ASDLParser() + + buf = open(file).read() + tokens = scanner.tokenize(buf) + try: + return parser.parse(tokens) + except ASDLSyntaxError, err: + print err + lines = buf.split("\n") + print lines[err.lineno - 1] # lines starts at 0, files at 1 + +if __name__ == "__main__": + import glob + import sys + + if len(sys.argv) > 1: + files = sys.argv[1:] + else: + testdir = "tests" + files = glob.glob(testdir + "/*.asdl") + + for file in files: + print file + mod = parse(file) + print "module", mod.name + print len(mod.dfns), "definitions" + if not check(mod): + print "Check failed" + else: + for dfn in mod.dfns: + print dfn.type diff --git a/sys/src/cmd/python/Parser/asdl_c.py b/sys/src/cmd/python/Parser/asdl_c.py new file mode 100755 index 000000000..2974d7b15 --- /dev/null +++ b/sys/src/cmd/python/Parser/asdl_c.py @@ -0,0 +1,782 @@ +#! /usr/bin/env python +"""Generate C code from an ASDL description.""" + +# TO DO +# handle fields that have a type but no name + +import os, sys, traceback + +import asdl + +TABSIZE = 8 +MAX_COL = 80 + +def get_c_type(name): + """Return a string for the C name of the type. + + This function special cases the default types provided by asdl: + identifier, string, int, bool. + """ + # XXX ack! need to figure out where Id is useful and where string + if isinstance(name, asdl.Id): + name = name.value + if name in asdl.builtin_types: + return name + else: + return "%s_ty" % name + +def reflow_lines(s, depth): + """Reflow the line s indented depth tabs. + + Return a sequence of lines where no line extends beyond MAX_COL + when properly indented. The first line is properly indented based + exclusively on depth * TABSIZE. All following lines -- these are + the reflowed lines generated by this function -- start at the same + column as the first character beyond the opening { in the first + line. + """ + size = MAX_COL - depth * TABSIZE + if len(s) < size: + return [s] + + lines = [] + cur = s + padding = "" + while len(cur) > size: + i = cur.rfind(' ', 0, size) + # XXX this should be fixed for real + if i == -1 and 'GeneratorExp' in cur: + i = size + 3 + assert i != -1, "Impossible line %d to reflow: %s" % (size, `s`) + lines.append(padding + cur[:i]) + if len(lines) == 1: + # find new size based on brace + j = cur.find('{', 0, i) + if j >= 0: + j += 2 # account for the brace and the space after it + size -= j + padding = " " * j + else: + j = cur.find('(', 0, i) + if j >= 0: + j += 1 # account for the paren (no space after it) + size -= j + padding = " " * j + cur = cur[i+1:] + else: + lines.append(padding + cur) + return lines + +def is_simple(sum): + """Return True if a sum is a simple. + + A sum is simple if its types have no fields, e.g. + unaryop = Invert | Not | UAdd | USub + """ + + for t in sum.types: + if t.fields: + return False + return True + +class EmitVisitor(asdl.VisitorBase): + """Visit that emits lines""" + + def __init__(self, file): + self.file = file + super(EmitVisitor, self).__init__() + + def emit(self, s, depth, reflow=1): + # XXX reflow long lines? + if reflow: + lines = reflow_lines(s, depth) + else: + lines = [s] + for line in lines: + line = (" " * TABSIZE * depth) + line + "\n" + self.file.write(line) + +class TypeDefVisitor(EmitVisitor): + def visitModule(self, mod): + for dfn in mod.dfns: + self.visit(dfn) + + def visitType(self, type, depth=0): + self.visit(type.value, type.name, depth) + + def visitSum(self, sum, name, depth): + if is_simple(sum): + self.simple_sum(sum, name, depth) + else: + self.sum_with_constructors(sum, name, depth) + + def simple_sum(self, sum, name, depth): + enum = [] + for i in range(len(sum.types)): + type = sum.types[i] + enum.append("%s=%d" % (type.name, i + 1)) + enums = ", ".join(enum) + ctype = get_c_type(name) + s = "typedef enum _%s { %s } %s;" % (name, enums, ctype) + self.emit(s, depth) + self.emit("", depth) + + def sum_with_constructors(self, sum, name, depth): + ctype = get_c_type(name) + s = "typedef struct _%(name)s *%(ctype)s;" % locals() + self.emit(s, depth) + self.emit("", depth) + + def visitProduct(self, product, name, depth): + ctype = get_c_type(name) + s = "typedef struct _%(name)s *%(ctype)s;" % locals() + self.emit(s, depth) + self.emit("", depth) + +class StructVisitor(EmitVisitor): + """Visitor to generate typdefs for AST.""" + + def visitModule(self, mod): + for dfn in mod.dfns: + self.visit(dfn) + + def visitType(self, type, depth=0): + self.visit(type.value, type.name, depth) + + def visitSum(self, sum, name, depth): + if not is_simple(sum): + self.sum_with_constructors(sum, name, depth) + + def sum_with_constructors(self, sum, name, depth): + def emit(s, depth=depth): + self.emit(s % sys._getframe(1).f_locals, depth) + enum = [] + for i in range(len(sum.types)): + type = sum.types[i] + enum.append("%s_kind=%d" % (type.name, i + 1)) + + emit("enum _%(name)s_kind {" + ", ".join(enum) + "};") + + emit("struct _%(name)s {") + emit("enum _%(name)s_kind kind;", depth + 1) + emit("union {", depth + 1) + for t in sum.types: + self.visit(t, depth + 2) + emit("} v;", depth + 1) + for field in sum.attributes: + # rudimentary attribute handling + type = str(field.type) + assert type in asdl.builtin_types, type + emit("%s %s;" % (type, field.name), depth + 1); + emit("};") + emit("") + + def visitConstructor(self, cons, depth): + if cons.fields: + self.emit("struct {", depth) + for f in cons.fields: + self.visit(f, depth + 1) + self.emit("} %s;" % cons.name, depth) + self.emit("", depth) + else: + # XXX not sure what I want here, nothing is probably fine + pass + + def visitField(self, field, depth): + # XXX need to lookup field.type, because it might be something + # like a builtin... + ctype = get_c_type(field.type) + name = field.name + if field.seq: + if field.type.value in ('cmpop',): + self.emit("asdl_int_seq *%(name)s;" % locals(), depth) + else: + self.emit("asdl_seq *%(name)s;" % locals(), depth) + else: + self.emit("%(ctype)s %(name)s;" % locals(), depth) + + def visitProduct(self, product, name, depth): + self.emit("struct _%(name)s {" % locals(), depth) + for f in product.fields: + self.visit(f, depth + 1) + self.emit("};", depth) + self.emit("", depth) + +class PrototypeVisitor(EmitVisitor): + """Generate function prototypes for the .h file""" + + def visitModule(self, mod): + for dfn in mod.dfns: + self.visit(dfn) + + def visitType(self, type): + self.visit(type.value, type.name) + + def visitSum(self, sum, name): + if is_simple(sum): + pass # XXX + else: + for t in sum.types: + self.visit(t, name, sum.attributes) + + def get_args(self, fields): + """Return list of C argument into, one for each field. + + Argument info is 3-tuple of a C type, variable name, and flag + that is true if type can be NULL. + """ + args = [] + unnamed = {} + for f in fields: + if f.name is None: + name = f.type + c = unnamed[name] = unnamed.get(name, 0) + 1 + if c > 1: + name = "name%d" % (c - 1) + else: + name = f.name + # XXX should extend get_c_type() to handle this + if f.seq: + if f.type.value in ('cmpop',): + ctype = "asdl_int_seq *" + else: + ctype = "asdl_seq *" + else: + ctype = get_c_type(f.type) + args.append((ctype, name, f.opt or f.seq)) + return args + + def visitConstructor(self, cons, type, attrs): + args = self.get_args(cons.fields) + attrs = self.get_args(attrs) + ctype = get_c_type(type) + self.emit_function(cons.name, ctype, args, attrs) + + def emit_function(self, name, ctype, args, attrs, union=1): + args = args + attrs + if args: + argstr = ", ".join(["%s %s" % (atype, aname) + for atype, aname, opt in args]) + argstr += ", PyArena *arena" + else: + argstr = "PyArena *arena" + margs = "a0" + for i in range(1, len(args)+1): + margs += ", a%d" % i + self.emit("#define %s(%s) _Py_%s(%s)" % (name, margs, name, margs), 0, + reflow = 0) + self.emit("%s _Py_%s(%s);" % (ctype, name, argstr), 0) + + def visitProduct(self, prod, name): + self.emit_function(name, get_c_type(name), + self.get_args(prod.fields), [], union=0) + +class FunctionVisitor(PrototypeVisitor): + """Visitor to generate constructor functions for AST.""" + + def emit_function(self, name, ctype, args, attrs, union=1): + def emit(s, depth=0, reflow=1): + self.emit(s, depth, reflow) + argstr = ", ".join(["%s %s" % (atype, aname) + for atype, aname, opt in args + attrs]) + if argstr: + argstr += ", PyArena *arena" + else: + argstr = "PyArena *arena" + self.emit("%s" % ctype, 0) + emit("%s(%s)" % (name, argstr)) + emit("{") + emit("%s p;" % ctype, 1) + for argtype, argname, opt in args: + # XXX hack alert: false is allowed for a bool + if not opt and not (argtype == "bool" or argtype == "int"): + emit("if (!%s) {" % argname, 1) + emit("PyErr_SetString(PyExc_ValueError,", 2) + msg = "field %s is required for %s" % (argname, name) + emit(' "%s");' % msg, + 2, reflow=0) + emit('return NULL;', 2) + emit('}', 1) + + emit("p = (%s)PyArena_Malloc(arena, sizeof(*p));" % ctype, 1); + emit("if (!p) {", 1) + emit("PyErr_NoMemory();", 2) + emit("return NULL;", 2) + emit("}", 1) + if union: + self.emit_body_union(name, args, attrs) + else: + self.emit_body_struct(name, args, attrs) + emit("return p;", 1) + emit("}") + emit("") + + def emit_body_union(self, name, args, attrs): + def emit(s, depth=0, reflow=1): + self.emit(s, depth, reflow) + emit("p->kind = %s_kind;" % name, 1) + for argtype, argname, opt in args: + emit("p->v.%s.%s = %s;" % (name, argname, argname), 1) + for argtype, argname, opt in attrs: + emit("p->%s = %s;" % (argname, argname), 1) + + def emit_body_struct(self, name, args, attrs): + def emit(s, depth=0, reflow=1): + self.emit(s, depth, reflow) + for argtype, argname, opt in args: + emit("p->%s = %s;" % (argname, argname), 1) + assert not attrs + +class PickleVisitor(EmitVisitor): + + def visitModule(self, mod): + for dfn in mod.dfns: + self.visit(dfn) + + def visitType(self, type): + self.visit(type.value, type.name) + + def visitSum(self, sum, name): + pass + + def visitProduct(self, sum, name): + pass + + def visitConstructor(self, cons, name): + pass + + def visitField(self, sum): + pass + +class MarshalPrototypeVisitor(PickleVisitor): + + def prototype(self, sum, name): + ctype = get_c_type(name) + self.emit("static int marshal_write_%s(PyObject **, int *, %s);" + % (name, ctype), 0) + + visitProduct = visitSum = prototype + +class PyTypesDeclareVisitor(PickleVisitor): + + def visitProduct(self, prod, name): + self.emit("static PyTypeObject *%s_type;" % name, 0) + self.emit("static PyObject* ast2obj_%s(void*);" % name, 0) + if prod.fields: + self.emit("static char *%s_fields[]={" % name,0) + for f in prod.fields: + self.emit('"%s",' % f.name, 1) + self.emit("};", 0) + + def visitSum(self, sum, name): + self.emit("static PyTypeObject *%s_type;" % name, 0) + if sum.attributes: + self.emit("static char *%s_attributes[] = {" % name, 0) + for a in sum.attributes: + self.emit('"%s",' % a.name, 1) + self.emit("};", 0) + ptype = "void*" + if is_simple(sum): + ptype = get_c_type(name) + tnames = [] + for t in sum.types: + tnames.append(str(t.name)+"_singleton") + tnames = ", *".join(tnames) + self.emit("static PyObject *%s;" % tnames, 0) + self.emit("static PyObject* ast2obj_%s(%s);" % (name, ptype), 0) + for t in sum.types: + self.visitConstructor(t, name) + + def visitConstructor(self, cons, name): + self.emit("static PyTypeObject *%s_type;" % cons.name, 0) + if cons.fields: + self.emit("static char *%s_fields[]={" % cons.name, 0) + for t in cons.fields: + self.emit('"%s",' % t.name, 1) + self.emit("};",0) + +class PyTypesVisitor(PickleVisitor): + + def visitModule(self, mod): + self.emit(""" +static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int num_fields) +{ + PyObject *fnames, *result; + int i; + if (num_fields) { + fnames = PyTuple_New(num_fields); + if (!fnames) return NULL; + } else { + fnames = Py_None; + Py_INCREF(Py_None); + } + for(i=0; i < num_fields; i++) { + PyObject *field = PyString_FromString(fields[i]); + if (!field) { + Py_DECREF(fnames); + return NULL; + } + PyTuple_SET_ITEM(fnames, i, field); + } + result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}", + type, base, "_fields", fnames, "__module__", "_ast"); + Py_DECREF(fnames); + return (PyTypeObject*)result; +} + +static int add_attributes(PyTypeObject* type, char**attrs, int num_fields) +{ + int i, result; + PyObject *s, *l = PyList_New(num_fields); + if (!l) return 0; + for(i = 0; i < num_fields; i++) { + s = PyString_FromString(attrs[i]); + if (!s) { + Py_DECREF(l); + return 0; + } + PyList_SET_ITEM(l, i, s); + } + result = PyObject_SetAttrString((PyObject*)type, "_attributes", l) >= 0; + Py_DECREF(l); + return result; +} + +static PyObject* ast2obj_list(asdl_seq *seq, PyObject* (*func)(void*)) +{ + int i, n = asdl_seq_LEN(seq); + PyObject *result = PyList_New(n); + PyObject *value; + if (!result) + return NULL; + for (i = 0; i < n; i++) { + value = func(asdl_seq_GET(seq, i)); + if (!value) { + Py_DECREF(result); + return NULL; + } + PyList_SET_ITEM(result, i, value); + } + return result; +} + +static PyObject* ast2obj_object(void *o) +{ + if (!o) + o = Py_None; + Py_INCREF((PyObject*)o); + return (PyObject*)o; +} +#define ast2obj_identifier ast2obj_object +#define ast2obj_string ast2obj_object +static PyObject* ast2obj_bool(bool b) +{ + return PyBool_FromLong(b); +} + +static PyObject* ast2obj_int(bool b) +{ + return PyInt_FromLong(b); +} +""", 0, reflow=False) + + self.emit("static int init_types(void)",0) + self.emit("{", 0) + self.emit("static int initialized;", 1) + self.emit("if (initialized) return 1;", 1) + self.emit('AST_type = make_type("AST", &PyBaseObject_Type, NULL, 0);', 1) + for dfn in mod.dfns: + self.visit(dfn) + self.emit("initialized = 1;", 1) + self.emit("return 1;", 1); + self.emit("}", 0) + + def visitProduct(self, prod, name): + if prod.fields: + fields = name.value+"_fields" + else: + fields = "NULL" + self.emit('%s_type = make_type("%s", AST_type, %s, %d);' % + (name, name, fields, len(prod.fields)), 1) + self.emit("if (!%s_type) return 0;" % name, 1) + + def visitSum(self, sum, name): + self.emit('%s_type = make_type("%s", AST_type, NULL, 0);' % (name, name), 1) + self.emit("if (!%s_type) return 0;" % name, 1) + if sum.attributes: + self.emit("if (!add_attributes(%s_type, %s_attributes, %d)) return 0;" % + (name, name, len(sum.attributes)), 1) + else: + self.emit("if (!add_attributes(%s_type, NULL, 0)) return 0;" % name, 1) + simple = is_simple(sum) + for t in sum.types: + self.visitConstructor(t, name, simple) + + def visitConstructor(self, cons, name, simple): + if cons.fields: + fields = cons.name.value+"_fields" + else: + fields = "NULL" + self.emit('%s_type = make_type("%s", %s_type, %s, %d);' % + (cons.name, cons.name, name, fields, len(cons.fields)), 1) + self.emit("if (!%s_type) return 0;" % cons.name, 1) + if simple: + self.emit("%s_singleton = PyType_GenericNew(%s_type, NULL, NULL);" % + (cons.name, cons.name), 1) + self.emit("if (!%s_singleton) return 0;" % cons.name, 1) + +class ASTModuleVisitor(PickleVisitor): + + def visitModule(self, mod): + self.emit("PyMODINIT_FUNC", 0) + self.emit("init_ast(void)", 0) + self.emit("{", 0) + self.emit("PyObject *m, *d;", 1) + self.emit("if (!init_types()) return;", 1) + self.emit('m = Py_InitModule3("_ast", NULL, NULL);', 1) + self.emit("if (!m) return;", 1) + self.emit("d = PyModule_GetDict(m);", 1) + self.emit('if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return;', 1) + self.emit('if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0)', 1) + self.emit("return;", 2) + # Value of version: "$Revision: 53490 $" + self.emit('if (PyModule_AddStringConstant(m, "__version__", "%s") < 0)' % mod.version.value[12:-3], 1) + self.emit("return;", 2) + for dfn in mod.dfns: + self.visit(dfn) + self.emit("}", 0) + + def visitProduct(self, prod, name): + self.addObj(name) + + def visitSum(self, sum, name): + self.addObj(name) + for t in sum.types: + self.visitConstructor(t, name) + + def visitConstructor(self, cons, name): + self.addObj(cons.name) + + def addObj(self, name): + self.emit('if (PyDict_SetItemString(d, "%s", (PyObject*)%s_type) < 0) return;' % (name, name), 1) + +_SPECIALIZED_SEQUENCES = ('stmt', 'expr') + +def find_sequence(fields, doing_specialization): + """Return True if any field uses a sequence.""" + for f in fields: + if f.seq: + if not doing_specialization: + return True + if str(f.type) not in _SPECIALIZED_SEQUENCES: + return True + return False + +def has_sequence(types, doing_specialization): + for t in types: + if find_sequence(t.fields, doing_specialization): + return True + return False + + +class StaticVisitor(PickleVisitor): + CODE = '''Very simple, always emit this static code. Overide CODE''' + + def visit(self, object): + self.emit(self.CODE, 0, reflow=False) + +class ObjVisitor(PickleVisitor): + + def func_begin(self, name): + ctype = get_c_type(name) + self.emit("PyObject*", 0) + self.emit("ast2obj_%s(void* _o)" % (name), 0) + self.emit("{", 0) + self.emit("%s o = (%s)_o;" % (ctype, ctype), 1) + self.emit("PyObject *result = NULL, *value = NULL;", 1) + self.emit('if (!o) {', 1) + self.emit("Py_INCREF(Py_None);", 2) + self.emit('return Py_None;', 2) + self.emit("}", 1) + self.emit('', 0) + + def func_end(self): + self.emit("return result;", 1) + self.emit("failed:", 0) + self.emit("Py_XDECREF(value);", 1) + self.emit("Py_XDECREF(result);", 1) + self.emit("return NULL;", 1) + self.emit("}", 0) + self.emit("", 0) + + def visitSum(self, sum, name): + if is_simple(sum): + self.simpleSum(sum, name) + return + self.func_begin(name) + self.emit("switch (o->kind) {", 1) + for i in range(len(sum.types)): + t = sum.types[i] + self.visitConstructor(t, i + 1, name) + self.emit("}", 1) + for a in sum.attributes: + self.emit("value = ast2obj_%s(o->%s);" % (a.type, a.name), 1) + self.emit("if (!value) goto failed;", 1) + self.emit('if (PyObject_SetAttrString(result, "%s", value) < 0)' % a.name, 1) + self.emit('goto failed;', 2) + self.emit('Py_DECREF(value);', 1) + self.func_end() + + def simpleSum(self, sum, name): + self.emit("PyObject* ast2obj_%s(%s_ty o)" % (name, name), 0) + self.emit("{", 0) + self.emit("switch(o) {", 1) + for t in sum.types: + self.emit("case %s:" % t.name, 2) + self.emit("Py_INCREF(%s_singleton);" % t.name, 3) + self.emit("return %s_singleton;" % t.name, 3) + self.emit("}", 1) + self.emit("return NULL; /* cannot happen */", 1) + self.emit("}", 0) + + def visitProduct(self, prod, name): + self.func_begin(name) + self.emit("result = PyType_GenericNew(%s_type, NULL, NULL);" % name, 1); + self.emit("if (!result) return NULL;", 1) + for field in prod.fields: + self.visitField(field, name, 1, True) + self.func_end() + + def visitConstructor(self, cons, enum, name): + self.emit("case %s_kind:" % cons.name, 1) + self.emit("result = PyType_GenericNew(%s_type, NULL, NULL);" % cons.name, 2); + self.emit("if (!result) goto failed;", 2) + for f in cons.fields: + self.visitField(f, cons.name, 2, False) + self.emit("break;", 2) + + def visitField(self, field, name, depth, product): + def emit(s, d): + self.emit(s, depth + d) + if product: + value = "o->%s" % field.name + else: + value = "o->v.%s.%s" % (name, field.name) + self.set(field, value, depth) + emit("if (!value) goto failed;", 0) + emit('if (PyObject_SetAttrString(result, "%s", value) == -1)' % field.name, 0) + emit("goto failed;", 1) + emit("Py_DECREF(value);", 0) + + def emitSeq(self, field, value, depth, emit): + emit("seq = %s;" % value, 0) + emit("n = asdl_seq_LEN(seq);", 0) + emit("value = PyList_New(n);", 0) + emit("if (!value) goto failed;", 0) + emit("for (i = 0; i < n; i++) {", 0) + self.set("value", field, "asdl_seq_GET(seq, i)", depth + 1) + emit("if (!value1) goto failed;", 1) + emit("PyList_SET_ITEM(value, i, value1);", 1) + emit("value1 = NULL;", 1) + emit("}", 0) + + def set(self, field, value, depth): + if field.seq: + # XXX should really check for is_simple, but that requires a symbol table + if field.type.value == "cmpop": + # While the sequence elements are stored as void*, + # ast2obj_cmpop expects an enum + self.emit("{", depth) + self.emit("int i, n = asdl_seq_LEN(%s);" % value, depth+1) + self.emit("value = PyList_New(n);", depth+1) + self.emit("if (!value) goto failed;", depth+1) + self.emit("for(i = 0; i < n; i++)", depth+1) + # This cannot fail, so no need for error handling + self.emit("PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(%s, i)));" % value, + depth+2, reflow=False) + self.emit("}", depth) + else: + self.emit("value = ast2obj_list(%s, ast2obj_%s);" % (value, field.type), depth) + else: + ctype = get_c_type(field.type) + self.emit("value = ast2obj_%s(%s);" % (field.type, value), depth, reflow=False) + + +class PartingShots(StaticVisitor): + + CODE = """ +PyObject* PyAST_mod2obj(mod_ty t) +{ + init_types(); + return ast2obj_mod(t); +} +""" + +class ChainOfVisitors: + def __init__(self, *visitors): + self.visitors = visitors + + def visit(self, object): + for v in self.visitors: + v.visit(object) + v.emit("", 0) + +def main(srcfile): + argv0 = sys.argv[0] + components = argv0.split(os.sep) + argv0 = os.sep.join(components[-2:]) + auto_gen_msg = '/* File automatically generated by %s */\n' % argv0 + mod = asdl.parse(srcfile) + if not asdl.check(mod): + sys.exit(1) + if INC_DIR: + p = "%s/%s-ast.h" % (INC_DIR, mod.name) + f = open(p, "wb") + print >> f, auto_gen_msg + print >> f, '#include "asdl.h"\n' + c = ChainOfVisitors(TypeDefVisitor(f), + StructVisitor(f), + PrototypeVisitor(f), + ) + c.visit(mod) + print >>f, "PyObject* PyAST_mod2obj(mod_ty t);" + f.close() + + if SRC_DIR: + p = os.path.join(SRC_DIR, str(mod.name) + "-ast.c") + f = open(p, "wb") + print >> f, auto_gen_msg + print >> f, '#include "Python.h"' + print >> f, '#include "%s-ast.h"' % mod.name + print >> f + print >>f, "static PyTypeObject* AST_type;" + v = ChainOfVisitors( + PyTypesDeclareVisitor(f), + PyTypesVisitor(f), + FunctionVisitor(f), + ObjVisitor(f), + ASTModuleVisitor(f), + PartingShots(f), + ) + v.visit(mod) + f.close() + +if __name__ == "__main__": + import sys + import getopt + + INC_DIR = '' + SRC_DIR = '' + opts, args = getopt.getopt(sys.argv[1:], "h:c:") + if len(opts) != 1: + print "Must specify exactly one output file" + sys.exit(1) + for o, v in opts: + if o == '-h': + INC_DIR = v + if o == '-c': + SRC_DIR = v + if len(args) != 1: + print "Must specify single input file" + sys.exit(1) + main(args[0]) diff --git a/sys/src/cmd/python/Parser/bitset.c b/sys/src/cmd/python/Parser/bitset.c new file mode 100644 index 000000000..b5543b81d --- /dev/null +++ b/sys/src/cmd/python/Parser/bitset.c @@ -0,0 +1,66 @@ + +/* Bitset primitives used by the parser generator */ + +#include "pgenheaders.h" +#include "bitset.h" + +bitset +newbitset(int nbits) +{ + int nbytes = NBYTES(nbits); + bitset ss = (char *)PyObject_MALLOC(sizeof(BYTE) * nbytes); + + if (ss == NULL) + Py_FatalError("no mem for bitset"); + + ss += nbytes; + while (--nbytes >= 0) + *--ss = 0; + return ss; +} + +void +delbitset(bitset ss) +{ + PyObject_FREE(ss); +} + +int +addbit(bitset ss, int ibit) +{ + int ibyte = BIT2BYTE(ibit); + BYTE mask = BIT2MASK(ibit); + + if (ss[ibyte] & mask) + return 0; /* Bit already set */ + ss[ibyte] |= mask; + return 1; +} + +#if 0 /* Now a macro */ +int +testbit(bitset ss, int ibit) +{ + return (ss[BIT2BYTE(ibit)] & BIT2MASK(ibit)) != 0; +} +#endif + +int +samebitset(bitset ss1, bitset ss2, int nbits) +{ + int i; + + for (i = NBYTES(nbits); --i >= 0; ) + if (*ss1++ != *ss2++) + return 0; + return 1; +} + +void +mergebitset(bitset ss1, bitset ss2, int nbits) +{ + int i; + + for (i = NBYTES(nbits); --i >= 0; ) + *ss1++ |= *ss2++; +} diff --git a/sys/src/cmd/python/Parser/firstsets.c b/sys/src/cmd/python/Parser/firstsets.c new file mode 100644 index 000000000..00467b31a --- /dev/null +++ b/sys/src/cmd/python/Parser/firstsets.c @@ -0,0 +1,113 @@ + +/* Computation of FIRST stets */ + +#include "pgenheaders.h" +#include "grammar.h" +#include "token.h" + +extern int Py_DebugFlag; + +/* Forward */ +static void calcfirstset(grammar *, dfa *); + +void +addfirstsets(grammar *g) +{ + int i; + dfa *d; + + if (Py_DebugFlag) + printf("Adding FIRST sets ...\n"); + for (i = 0; i < g->g_ndfas; i++) { + d = &g->g_dfa[i]; + if (d->d_first == NULL) + calcfirstset(g, d); + } +} + +static void +calcfirstset(grammar *g, dfa *d) +{ + int i, j; + state *s; + arc *a; + int nsyms; + int *sym; + int nbits; + static bitset dummy; + bitset result; + int type; + dfa *d1; + label *l0; + + if (Py_DebugFlag) + printf("Calculate FIRST set for '%s'\n", d->d_name); + + if (dummy == NULL) + dummy = newbitset(1); + if (d->d_first == dummy) { + fprintf(stderr, "Left-recursion for '%s'\n", d->d_name); + return; + } + if (d->d_first != NULL) { + fprintf(stderr, "Re-calculating FIRST set for '%s' ???\n", + d->d_name); + } + d->d_first = dummy; + + l0 = g->g_ll.ll_label; + nbits = g->g_ll.ll_nlabels; + result = newbitset(nbits); + + sym = (int *)PyObject_MALLOC(sizeof(int)); + if (sym == NULL) + Py_FatalError("no mem for new sym in calcfirstset"); + nsyms = 1; + sym[0] = findlabel(&g->g_ll, d->d_type, (char *)NULL); + + s = &d->d_state[d->d_initial]; + for (i = 0; i < s->s_narcs; i++) { + a = &s->s_arc[i]; + for (j = 0; j < nsyms; j++) { + if (sym[j] == a->a_lbl) + break; + } + if (j >= nsyms) { /* New label */ + sym = (int *)PyObject_REALLOC(sym, + sizeof(int) * (nsyms + 1)); + if (sym == NULL) + Py_FatalError( + "no mem to resize sym in calcfirstset"); + sym[nsyms++] = a->a_lbl; + type = l0[a->a_lbl].lb_type; + if (ISNONTERMINAL(type)) { + d1 = PyGrammar_FindDFA(g, type); + if (d1->d_first == dummy) { + fprintf(stderr, + "Left-recursion below '%s'\n", + d->d_name); + } + else { + if (d1->d_first == NULL) + calcfirstset(g, d1); + mergebitset(result, + d1->d_first, nbits); + } + } + else if (ISTERMINAL(type)) { + addbit(result, a->a_lbl); + } + } + } + d->d_first = result; + if (Py_DebugFlag) { + printf("FIRST set for '%s': {", d->d_name); + for (i = 0; i < nbits; i++) { + if (testbit(result, i)) + printf(" %s", PyGrammar_LabelRepr(&l0[i])); + } + printf(" }\n"); + } + + PyObject_FREE(sym); +} diff --git a/sys/src/cmd/python/Parser/grammar.c b/sys/src/cmd/python/Parser/grammar.c new file mode 100644 index 000000000..9e7c49aab --- /dev/null +++ b/sys/src/cmd/python/Parser/grammar.c @@ -0,0 +1,254 @@ + +/* Grammar implementation */ + +#include "Python.h" +#include "pgenheaders.h" + +#include <ctype.h> + +#include "token.h" +#include "grammar.h" + +#ifdef RISCOS +#include <unixlib.h> +#endif + +extern int Py_DebugFlag; + +grammar * +newgrammar(int start) +{ + grammar *g; + + g = (grammar *)PyObject_MALLOC(sizeof(grammar)); + if (g == NULL) + Py_FatalError("no mem for new grammar"); + g->g_ndfas = 0; + g->g_dfa = NULL; + g->g_start = start; + g->g_ll.ll_nlabels = 0; + g->g_ll.ll_label = NULL; + g->g_accel = 0; + return g; +} + +dfa * +adddfa(grammar *g, int type, char *name) +{ + dfa *d; + + g->g_dfa = (dfa *)PyObject_REALLOC(g->g_dfa, + sizeof(dfa) * (g->g_ndfas + 1)); + if (g->g_dfa == NULL) + Py_FatalError("no mem to resize dfa in adddfa"); + d = &g->g_dfa[g->g_ndfas++]; + d->d_type = type; + d->d_name = strdup(name); + d->d_nstates = 0; + d->d_state = NULL; + d->d_initial = -1; + d->d_first = NULL; + return d; /* Only use while fresh! */ +} + +int +addstate(dfa *d) +{ + state *s; + + d->d_state = (state *)PyObject_REALLOC(d->d_state, + sizeof(state) * (d->d_nstates + 1)); + if (d->d_state == NULL) + Py_FatalError("no mem to resize state in addstate"); + s = &d->d_state[d->d_nstates++]; + s->s_narcs = 0; + s->s_arc = NULL; + s->s_lower = 0; + s->s_upper = 0; + s->s_accel = NULL; + s->s_accept = 0; + return s - d->d_state; +} + +void +addarc(dfa *d, int from, int to, int lbl) +{ + state *s; + arc *a; + + assert(0 <= from && from < d->d_nstates); + assert(0 <= to && to < d->d_nstates); + + s = &d->d_state[from]; + s->s_arc = (arc *)PyObject_REALLOC(s->s_arc, sizeof(arc) * (s->s_narcs + 1)); + if (s->s_arc == NULL) + Py_FatalError("no mem to resize arc list in addarc"); + a = &s->s_arc[s->s_narcs++]; + a->a_lbl = lbl; + a->a_arrow = to; +} + +int +addlabel(labellist *ll, int type, char *str) +{ + int i; + label *lb; + + for (i = 0; i < ll->ll_nlabels; i++) { + if (ll->ll_label[i].lb_type == type && + strcmp(ll->ll_label[i].lb_str, str) == 0) + return i; + } + ll->ll_label = (label *)PyObject_REALLOC(ll->ll_label, + sizeof(label) * (ll->ll_nlabels + 1)); + if (ll->ll_label == NULL) + Py_FatalError("no mem to resize labellist in addlabel"); + lb = &ll->ll_label[ll->ll_nlabels++]; + lb->lb_type = type; + lb->lb_str = strdup(str); + if (Py_DebugFlag) + printf("Label @ %8p, %d: %s\n", ll, ll->ll_nlabels, + PyGrammar_LabelRepr(lb)); + return lb - ll->ll_label; +} + +/* Same, but rather dies than adds */ + +int +findlabel(labellist *ll, int type, char *str) +{ + int i; + + for (i = 0; i < ll->ll_nlabels; i++) { + if (ll->ll_label[i].lb_type == type /*&& + strcmp(ll->ll_label[i].lb_str, str) == 0*/) + return i; + } + fprintf(stderr, "Label %d/'%s' not found\n", type, str); + Py_FatalError("grammar.c:findlabel()"); + return 0; /* Make gcc -Wall happy */ +} + +/* Forward */ +static void translabel(grammar *, label *); + +void +translatelabels(grammar *g) +{ + int i; + +#ifdef Py_DEBUG + printf("Translating labels ...\n"); +#endif + /* Don't translate EMPTY */ + for (i = EMPTY+1; i < g->g_ll.ll_nlabels; i++) + translabel(g, &g->g_ll.ll_label[i]); +} + +static void +translabel(grammar *g, label *lb) +{ + int i; + + if (Py_DebugFlag) + printf("Translating label %s ...\n", PyGrammar_LabelRepr(lb)); + + if (lb->lb_type == NAME) { + for (i = 0; i < g->g_ndfas; i++) { + if (strcmp(lb->lb_str, g->g_dfa[i].d_name) == 0) { + if (Py_DebugFlag) + printf( + "Label %s is non-terminal %d.\n", + lb->lb_str, + g->g_dfa[i].d_type); + lb->lb_type = g->g_dfa[i].d_type; + free(lb->lb_str); + lb->lb_str = NULL; + return; + } + } + for (i = 0; i < (int)N_TOKENS; i++) { + if (strcmp(lb->lb_str, _PyParser_TokenNames[i]) == 0) { + if (Py_DebugFlag) + printf("Label %s is terminal %d.\n", + lb->lb_str, i); + lb->lb_type = i; + free(lb->lb_str); + lb->lb_str = NULL; + return; + } + } + printf("Can't translate NAME label '%s'\n", lb->lb_str); + return; + } + + if (lb->lb_type == STRING) { + if (isalpha(Py_CHARMASK(lb->lb_str[1])) || + lb->lb_str[1] == '_') { + char *p; + char *src; + char *dest; + size_t name_len; + if (Py_DebugFlag) + printf("Label %s is a keyword\n", lb->lb_str); + lb->lb_type = NAME; + src = lb->lb_str + 1; + p = strchr(src, '\''); + if (p) + name_len = p - src; + else + name_len = strlen(src); + dest = (char *)malloc(name_len + 1); + if (!dest) { + printf("Can't alloc dest '%s'\n", src); + return; + } + strncpy(dest, src, name_len); + dest[name_len] = '\0'; + free(lb->lb_str); + lb->lb_str = dest; + } + else if (lb->lb_str[2] == lb->lb_str[0]) { + int type = (int) PyToken_OneChar(lb->lb_str[1]); + if (type != OP) { + lb->lb_type = type; + free(lb->lb_str); + lb->lb_str = NULL; + } + else + printf("Unknown OP label %s\n", + lb->lb_str); + } + else if (lb->lb_str[2] && lb->lb_str[3] == lb->lb_str[0]) { + int type = (int) PyToken_TwoChars(lb->lb_str[1], + lb->lb_str[2]); + if (type != OP) { + lb->lb_type = type; + free(lb->lb_str); + lb->lb_str = NULL; + } + else + printf("Unknown OP label %s\n", + lb->lb_str); + } + else if (lb->lb_str[2] && lb->lb_str[3] && lb->lb_str[4] == lb->lb_str[0]) { + int type = (int) PyToken_ThreeChars(lb->lb_str[1], + lb->lb_str[2], + lb->lb_str[3]); + if (type != OP) { + lb->lb_type = type; + free(lb->lb_str); + lb->lb_str = NULL; + } + else + printf("Unknown OP label %s\n", + lb->lb_str); + } + else + printf("Can't translate STRING label %s\n", + lb->lb_str); + } + else + printf("Can't translate label '%s'\n", + PyGrammar_LabelRepr(lb)); +} diff --git a/sys/src/cmd/python/Parser/grammar.mak b/sys/src/cmd/python/Parser/grammar.mak new file mode 100644 index 000000000..55f028ffb --- /dev/null +++ b/sys/src/cmd/python/Parser/grammar.mak @@ -0,0 +1,45 @@ +# This manages to rebuild graminit.{h, c} under MSVC 6 (Windows), via +# +# nmake /f grammar.mak +# +# You may also need to copy python23.dll into this directory, or get +# it on your search path. +# +# The intermediate files can be nuked afterwards: +# +# nmake /f grammar.mak clean +# +# I don't understand the maze of preprocessor #define's on Windows, and +# as a result this requires linking with python23.lib, so it's of no use +# for bootstrapping (the cause appears to be a useless-- in this +# particular case --pragma in PC\pyconfig.h, which demands that +# python23.lib get linked in). + +LIBS= ..\PCbuild\python25.lib + +CFLAGS= /I ..\Include /I ..\PC /D MS_NO_COREDLL /D PGEN /MD + +GRAMMAR_H= ..\Include\graminit.h +GRAMMAR_C= ..\Python\graminit.c +GRAMMAR_INPUT= ..\Grammar\Grammar + +PGEN= pgen.exe + +POBJS= acceler.obj grammar1.obj listnode.obj node.obj parser.obj \ + parsetok.obj tokenizer.obj bitset.obj metagrammar.obj + +PARSER_OBJS= $(POBJS) myreadline.obj + +PGOBJS= firstsets.obj grammar.obj pgen.obj printgrammar.obj pgenmain.obj + +PGENOBJS= $(POBJS) $(PGOBJS) + +$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT) + $(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) + +$(PGEN): $(PGENOBJS) + $(CC) $(PGENOBJS) $(LIBS) /Fe$(PGEN) + +clean: + del *.obj + del $(PGEN) diff --git a/sys/src/cmd/python/Parser/grammar1.c b/sys/src/cmd/python/Parser/grammar1.c new file mode 100644 index 000000000..b76719a1d --- /dev/null +++ b/sys/src/cmd/python/Parser/grammar1.c @@ -0,0 +1,57 @@ + +/* Grammar subroutines needed by parser */ + +#include "Python.h" +#include "pgenheaders.h" +#include "grammar.h" +#include "token.h" + +/* Return the DFA for the given type */ + +dfa * +PyGrammar_FindDFA(grammar *g, register int type) +{ + register dfa *d; +#if 1 + /* Massive speed-up */ + d = &g->g_dfa[type - NT_OFFSET]; + assert(d->d_type == type); + return d; +#else + /* Old, slow version */ + register int i; + + for (i = g->g_ndfas, d = g->g_dfa; --i >= 0; d++) { + if (d->d_type == type) + return d; + } + assert(0); + /* NOTREACHED */ +#endif +} + +char * +PyGrammar_LabelRepr(label *lb) +{ + static char buf[100]; + + if (lb->lb_type == ENDMARKER) + return "EMPTY"; + else if (ISNONTERMINAL(lb->lb_type)) { + if (lb->lb_str == NULL) { + PyOS_snprintf(buf, sizeof(buf), "NT%d", lb->lb_type); + return buf; + } + else + return lb->lb_str; + } + else { + if (lb->lb_str == NULL) + return _PyParser_TokenNames[lb->lb_type]; + else { + PyOS_snprintf(buf, sizeof(buf), "%.32s(%.32s)", + _PyParser_TokenNames[lb->lb_type], lb->lb_str); + return buf; + } + } +} diff --git a/sys/src/cmd/python/Parser/intrcheck.c b/sys/src/cmd/python/Parser/intrcheck.c new file mode 100644 index 000000000..e0f3252db --- /dev/null +++ b/sys/src/cmd/python/Parser/intrcheck.c @@ -0,0 +1,176 @@ + +/* Check for interrupts */ + +#include "Python.h" + +#ifdef QUICKWIN + +#include <io.h> + +void +PyOS_InitInterrupts(void) +{ +} + +void +PyOS_FiniInterrupts(void) +{ +} + +int +PyOS_InterruptOccurred(void) +{ + _wyield(); +} + +#define OK + +#endif /* QUICKWIN */ + +#if defined(_M_IX86) && !defined(__QNX__) +#include <io.h> +#endif + +#if defined(MSDOS) && !defined(QUICKWIN) + +#ifdef __GNUC__ + +/* This is for DJGPP's GO32 extender. I don't know how to trap + * control-C (There's no API for ctrl-C, and I don't want to mess with + * the interrupt vectors.) However, this DOES catch control-break. + * --Amrit + */ + +#include <go32.h> + +void +PyOS_InitInterrupts(void) +{ + _go32_want_ctrl_break(1 /* TRUE */); +} + +void +PyOS_FiniInterrupts(void) +{ +} + +int +PyOS_InterruptOccurred(void) +{ + return _go32_was_ctrl_break_hit(); +} + +#else /* !__GNUC__ */ + +/* This might work for MS-DOS (untested though): */ + +void +PyOS_InitInterrupts(void) +{ +} + +void +PyOS_FiniInterrupts(void) +{ +} + +int +PyOS_InterruptOccurred(void) +{ + int interrupted = 0; + while (kbhit()) { + if (getch() == '\003') + interrupted = 1; + } + return interrupted; +} + +#endif /* __GNUC__ */ + +#define OK + +#endif /* MSDOS && !QUICKWIN */ + + +#ifndef OK + +/* Default version -- for real operating systems and for Standard C */ + +#include <stdio.h> +#include <string.h> +#include <signal.h> + +static int interrupted; + +void +PyErr_SetInterrupt(void) +{ + interrupted = 1; +} + +extern int PyErr_CheckSignals(void); + +static int +checksignals_witharg(void * arg) +{ + return PyErr_CheckSignals(); +} + +static void +intcatcher(int sig) +{ + extern void Py_Exit(int); + static char message[] = +"python: to interrupt a truly hanging Python program, interrupt once more.\n"; + switch (interrupted++) { + case 0: + break; + case 1: +#ifdef RISCOS + fprintf(stderr, message); +#else + write(2, message, strlen(message)); +#endif + break; + case 2: + interrupted = 0; + Py_Exit(1); + break; + } + PyOS_setsig(SIGINT, intcatcher); + Py_AddPendingCall(checksignals_witharg, NULL); +} + +static void (*old_siginthandler)(int) = SIG_DFL; + +void +PyOS_InitInterrupts(void) +{ + if ((old_siginthandler = PyOS_setsig(SIGINT, SIG_IGN)) != SIG_IGN) + PyOS_setsig(SIGINT, intcatcher); +} + +void +PyOS_FiniInterrupts(void) +{ + PyOS_setsig(SIGINT, old_siginthandler); +} + +int +PyOS_InterruptOccurred(void) +{ + if (!interrupted) + return 0; + interrupted = 0; + return 1; +} + +#endif /* !OK */ + +void +PyOS_AfterFork(void) +{ +#ifdef WITH_THREAD + PyEval_ReInitThreads(); +#endif +} diff --git a/sys/src/cmd/python/Parser/listnode.c b/sys/src/cmd/python/Parser/listnode.c new file mode 100644 index 000000000..c0b3b666f --- /dev/null +++ b/sys/src/cmd/python/Parser/listnode.c @@ -0,0 +1,66 @@ + +/* List a node on a file */ + +#include "pgenheaders.h" +#include "token.h" +#include "node.h" + +/* Forward */ +static void list1node(FILE *, node *); +static void listnode(FILE *, node *); + +void +PyNode_ListTree(node *n) +{ + listnode(stdout, n); +} + +static int level, atbol; + +static void +listnode(FILE *fp, node *n) +{ + level = 0; + atbol = 1; + list1node(fp, n); +} + +static void +list1node(FILE *fp, node *n) +{ + if (n == 0) + return; + if (ISNONTERMINAL(TYPE(n))) { + int i; + for (i = 0; i < NCH(n); i++) + list1node(fp, CHILD(n, i)); + } + else if (ISTERMINAL(TYPE(n))) { + switch (TYPE(n)) { + case INDENT: + ++level; + break; + case DEDENT: + --level; + break; + default: + if (atbol) { + int i; + for (i = 0; i < level; ++i) + fprintf(fp, "\t"); + atbol = 0; + } + if (TYPE(n) == NEWLINE) { + if (STR(n) != NULL) + fprintf(fp, "%s", STR(n)); + fprintf(fp, "\n"); + atbol = 1; + } + else + fprintf(fp, "%s ", STR(n)); + break; + } + } + else + fprintf(fp, "? "); +} diff --git a/sys/src/cmd/python/Parser/metagrammar.c b/sys/src/cmd/python/Parser/metagrammar.c new file mode 100644 index 000000000..b61bc6d66 --- /dev/null +++ b/sys/src/cmd/python/Parser/metagrammar.c @@ -0,0 +1,159 @@ + +#include "pgenheaders.h" +#include "metagrammar.h" +#include "grammar.h" +#include "pgen.h" +static arc arcs_0_0[3] = { + {2, 0}, + {3, 0}, + {4, 1}, +}; +static arc arcs_0_1[1] = { + {0, 1}, +}; +static state states_0[2] = { + {3, arcs_0_0}, + {1, arcs_0_1}, +}; +static arc arcs_1_0[1] = { + {5, 1}, +}; +static arc arcs_1_1[1] = { + {6, 2}, +}; +static arc arcs_1_2[1] = { + {7, 3}, +}; +static arc arcs_1_3[1] = { + {3, 4}, +}; +static arc arcs_1_4[1] = { + {0, 4}, +}; +static state states_1[5] = { + {1, arcs_1_0}, + {1, arcs_1_1}, + {1, arcs_1_2}, + {1, arcs_1_3}, + {1, arcs_1_4}, +}; +static arc arcs_2_0[1] = { + {8, 1}, +}; +static arc arcs_2_1[2] = { + {9, 0}, + {0, 1}, +}; +static state states_2[2] = { + {1, arcs_2_0}, + {2, arcs_2_1}, +}; +static arc arcs_3_0[1] = { + {10, 1}, +}; +static arc arcs_3_1[2] = { + {10, 1}, + {0, 1}, +}; +static state states_3[2] = { + {1, arcs_3_0}, + {2, arcs_3_1}, +}; +static arc arcs_4_0[2] = { + {11, 1}, + {13, 2}, +}; +static arc arcs_4_1[1] = { + {7, 3}, +}; +static arc arcs_4_2[3] = { + {14, 4}, + {15, 4}, + {0, 2}, +}; +static arc arcs_4_3[1] = { + {12, 4}, +}; +static arc arcs_4_4[1] = { + {0, 4}, +}; +static state states_4[5] = { + {2, arcs_4_0}, + {1, arcs_4_1}, + {3, arcs_4_2}, + {1, arcs_4_3}, + {1, arcs_4_4}, +}; +static arc arcs_5_0[3] = { + {5, 1}, + {16, 1}, + {17, 2}, +}; +static arc arcs_5_1[1] = { + {0, 1}, +}; +static arc arcs_5_2[1] = { + {7, 3}, +}; +static arc arcs_5_3[1] = { + {18, 1}, +}; +static state states_5[4] = { + {3, arcs_5_0}, + {1, arcs_5_1}, + {1, arcs_5_2}, + {1, arcs_5_3}, +}; +static dfa dfas[6] = { + {256, "MSTART", 0, 2, states_0, + "\070\000\000"}, + {257, "RULE", 0, 5, states_1, + "\040\000\000"}, + {258, "RHS", 0, 2, states_2, + "\040\010\003"}, + {259, "ALT", 0, 2, states_3, + "\040\010\003"}, + {260, "ITEM", 0, 5, states_4, + "\040\010\003"}, + {261, "ATOM", 0, 4, states_5, + "\040\000\003"}, +}; +static label labels[19] = { + {0, "EMPTY"}, + {256, 0}, + {257, 0}, + {4, 0}, + {0, 0}, + {1, 0}, + {11, 0}, + {258, 0}, + {259, 0}, + {18, 0}, + {260, 0}, + {9, 0}, + {10, 0}, + {261, 0}, + {16, 0}, + {14, 0}, + {3, 0}, + {7, 0}, + {8, 0}, +}; +static grammar _PyParser_Grammar = { + 6, + dfas, + {19, labels}, + 256 +}; + +grammar * +meta_grammar(void) +{ + return &_PyParser_Grammar; +} + +grammar * +Py_meta_grammar(void) +{ + return meta_grammar(); +} diff --git a/sys/src/cmd/python/Parser/mkfile b/sys/src/cmd/python/Parser/mkfile new file mode 100644 index 000000000..01557576e --- /dev/null +++ b/sys/src/cmd/python/Parser/mkfile @@ -0,0 +1,44 @@ +APE=/sys/src/ape +<$APE/config + +LIB=/$objtype/lib/ape/libpython.a + +OFILES=\ + acceler.$O\ + bitset.$O\ + firstsets.$O\ + grammar1.$O\ + listnode.$O\ + metagrammar.$O\ + myreadline.$O\ + node.$O\ + parser.$O\ + parsetok.$O\ + tokenizer.$O\ + +CLEANFILES=$O.pgen + +</sys/src/cmd/mksyslib + +CFLAGS=-c -I.. -I../Include -DT$objtype -DPy_BUILD_CORE -DNDEBUG + +PGENOFILES=\ + acceler.$O\ + bitset.$O\ + firstsets.$O\ + grammar.$O\ + grammar1.$O\ + listnode.$O\ + metagrammar.$O\ + node.$O\ + parser.$O\ + parsetok.$O\ + pgen.$O\ + pgenmain.$O\ + printgrammar.$O\ + tokenizer_pgen.$O\ + ../Objects/obmalloc.$O\ + ../Python/mysnprintf.$O\ + +$O.pgen: $PGENOFILES + $LD -o $target $prereq diff --git a/sys/src/cmd/python/Parser/myreadline.c b/sys/src/cmd/python/Parser/myreadline.c new file mode 100644 index 000000000..32a1088ad --- /dev/null +++ b/sys/src/cmd/python/Parser/myreadline.c @@ -0,0 +1,219 @@ + +/* Readline interface for tokenizer.c and [raw_]input() in bltinmodule.c. + By default, or when stdin is not a tty device, we have a super + simple my_readline function using fgets. + Optionally, we can use the GNU readline library. + my_readline() has a different return value from GNU readline(): + - NULL if an interrupt occurred or if an error occurred + - a malloc'ed empty string if EOF was read + - a malloc'ed string ending in \n normally +*/ + +#include "Python.h" +#ifdef MS_WINDOWS +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#endif /* MS_WINDOWS */ + +#ifdef __VMS +extern char* vms__StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt); +#endif + + +PyThreadState* _PyOS_ReadlineTState; + +#ifdef WITH_THREAD +#include "pythread.h" +static PyThread_type_lock _PyOS_ReadlineLock = NULL; +#endif + +int (*PyOS_InputHook)(void) = NULL; + +#ifdef RISCOS +int Py_RISCOSWimpFlag; +#endif + +/* This function restarts a fgets() after an EINTR error occurred + except if PyOS_InterruptOccurred() returns true. */ + +static int +my_fgets(char *buf, int len, FILE *fp) +{ + char *p; + for (;;) { + if (PyOS_InputHook != NULL) + (void)(PyOS_InputHook)(); + errno = 0; + p = fgets(buf, len, fp); + if (p != NULL) + return 0; /* No error */ +#ifdef MS_WINDOWS + /* In the case of a Ctrl+C or some other external event + interrupting the operation: + Win2k/NT: ERROR_OPERATION_ABORTED is the most recent Win32 + error code (and feof() returns TRUE). + Win9x: Ctrl+C seems to have no effect on fgets() returning + early - the signal handler is called, but the fgets() + only returns "normally" (ie, when Enter hit or feof()) + */ + if (GetLastError()==ERROR_OPERATION_ABORTED) { + /* Signals come asynchronously, so we sleep a brief + moment before checking if the handler has been + triggered (we cant just return 1 before the + signal handler has been called, as the later + signal may be treated as a separate interrupt). + */ + Sleep(1); + if (PyOS_InterruptOccurred()) { + return 1; /* Interrupt */ + } + /* Either the sleep wasn't long enough (need a + short loop retrying?) or not interrupted at all + (in which case we should revisit the whole thing!) + Logging some warning would be nice. assert is not + viable as under the debugger, the various dialogs + mean the condition is not true. + */ + } +#endif /* MS_WINDOWS */ + if (feof(fp)) { + return -1; /* EOF */ + } +#ifdef EINTR + if (errno == EINTR) { + int s; +#ifdef WITH_THREAD + PyEval_RestoreThread(_PyOS_ReadlineTState); +#endif + s = PyErr_CheckSignals(); +#ifdef WITH_THREAD + PyEval_SaveThread(); +#endif + if (s < 0) { + return 1; + } + } +#endif + if (PyOS_InterruptOccurred()) { + return 1; /* Interrupt */ + } + return -2; /* Error */ + } + /* NOTREACHED */ +} + + +/* Readline implementation using fgets() */ + +char * +PyOS_StdioReadline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) +{ + size_t n; + char *p; + n = 100; + if ((p = (char *)PyMem_MALLOC(n)) == NULL) + return NULL; + fflush(sys_stdout); +#ifndef RISCOS + if (prompt) + fprintf(stderr, "%s", prompt); +#else + if (prompt) { + if(Py_RISCOSWimpFlag) + fprintf(stderr, "\x0cr%s\x0c", prompt); + else + fprintf(stderr, "%s", prompt); + } +#endif + fflush(stderr); + switch (my_fgets(p, (int)n, sys_stdin)) { + case 0: /* Normal case */ + break; + case 1: /* Interrupt */ + PyMem_FREE(p); + return NULL; + case -1: /* EOF */ + case -2: /* Error */ + default: /* Shouldn't happen */ + *p = '\0'; + break; + } + n = strlen(p); + while (n > 0 && p[n-1] != '\n') { + size_t incr = n+2; + p = (char *)PyMem_REALLOC(p, n + incr); + if (p == NULL) + return NULL; + if (incr > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, "input line too long"); + } + if (my_fgets(p+n, (int)incr, sys_stdin) != 0) + break; + n += strlen(p+n); + } + return (char *)PyMem_REALLOC(p, n+1); +} + + +/* By initializing this function pointer, systems embedding Python can + override the readline function. + + Note: Python expects in return a buffer allocated with PyMem_Malloc. */ + +char *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *); + + +/* Interface used by tokenizer.c and bltinmodule.c */ + +char * +PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) +{ + char *rv; + + if (_PyOS_ReadlineTState == PyThreadState_GET()) { + PyErr_SetString(PyExc_RuntimeError, + "can't re-enter readline"); + return NULL; + } + + + if (PyOS_ReadlineFunctionPointer == NULL) { +#ifdef __VMS + PyOS_ReadlineFunctionPointer = vms__StdioReadline; +#else + PyOS_ReadlineFunctionPointer = PyOS_StdioReadline; +#endif + } + +#ifdef WITH_THREAD + if (_PyOS_ReadlineLock == NULL) { + _PyOS_ReadlineLock = PyThread_allocate_lock(); + } +#endif + + _PyOS_ReadlineTState = PyThreadState_GET(); + Py_BEGIN_ALLOW_THREADS +#ifdef WITH_THREAD + PyThread_acquire_lock(_PyOS_ReadlineLock, 1); +#endif + + /* This is needed to handle the unlikely case that the + * interpreter is in interactive mode *and* stdin/out are not + * a tty. This can happen, for example if python is run like + * this: python -i < test1.py + */ + if (!isatty (fileno (sys_stdin)) || !isatty (fileno (sys_stdout))) + rv = PyOS_StdioReadline (sys_stdin, sys_stdout, prompt); + else + rv = (*PyOS_ReadlineFunctionPointer)(sys_stdin, sys_stdout, + prompt); + Py_END_ALLOW_THREADS + +#ifdef WITH_THREAD + PyThread_release_lock(_PyOS_ReadlineLock); +#endif + + _PyOS_ReadlineTState = NULL; + + return rv; +} diff --git a/sys/src/cmd/python/Parser/node.c b/sys/src/cmd/python/Parser/node.c new file mode 100644 index 000000000..d133a0d17 --- /dev/null +++ b/sys/src/cmd/python/Parser/node.c @@ -0,0 +1,135 @@ +/* Parse tree node implementation */ + +#include "Python.h" +#include "node.h" +#include "errcode.h" + +node * +PyNode_New(int type) +{ + node *n = (node *) PyObject_MALLOC(1 * sizeof(node)); + if (n == NULL) + return NULL; + n->n_type = type; + n->n_str = NULL; + n->n_lineno = 0; + n->n_nchildren = 0; + n->n_child = NULL; + return n; +} + +/* See comments at XXXROUNDUP below. Returns -1 on overflow. */ +static int +fancy_roundup(int n) +{ + /* Round up to the closest power of 2 >= n. */ + int result = 256; + assert(n > 128); + while (result < n) { + result <<= 1; + if (result <= 0) + return -1; + } + return result; +} + +/* A gimmick to make massive numbers of reallocs quicker. The result is + * a number >= the input. In PyNode_AddChild, it's used like so, when + * we're about to add child number current_size + 1: + * + * if XXXROUNDUP(current_size) < XXXROUNDUP(current_size + 1): + * allocate space for XXXROUNDUP(current_size + 1) total children + * else: + * we already have enough space + * + * Since a node starts out empty, we must have + * + * XXXROUNDUP(0) < XXXROUNDUP(1) + * + * so that we allocate space for the first child. One-child nodes are very + * common (presumably that would change if we used a more abstract form + * of syntax tree), so to avoid wasting memory it's desirable that + * XXXROUNDUP(1) == 1. That in turn forces XXXROUNDUP(0) == 0. + * + * Else for 2 <= n <= 128, we round up to the closest multiple of 4. Why 4? + * Rounding up to a multiple of an exact power of 2 is very efficient, and + * most nodes with more than one child have <= 4 kids. + * + * Else we call fancy_roundup() to grow proportionately to n. We've got an + * extreme case then (like test_longexp.py), and on many platforms doing + * anything less than proportional growth leads to exorbitant runtime + * (e.g., MacPython), or extreme fragmentation of user address space (e.g., + * Win98). + * + * In a run of compileall across the 2.3a0 Lib directory, Andrew MacIntyre + * reported that, with this scheme, 89% of PyObject_REALLOC calls in + * PyNode_AddChild passed 1 for the size, and 9% passed 4. So this usually + * wastes very little memory, but is very effective at sidestepping + * platform-realloc disasters on vulnerable platforms. + * + * Note that this would be straightforward if a node stored its current + * capacity. The code is tricky to avoid that. + */ +#define XXXROUNDUP(n) ((n) <= 1 ? (n) : \ + (n) <= 128 ? (((n) + 3) & ~3) : \ + fancy_roundup(n)) + + +int +PyNode_AddChild(register node *n1, int type, char *str, int lineno, int col_offset) +{ + const int nch = n1->n_nchildren; + int current_capacity; + int required_capacity; + node *n; + + if (nch == INT_MAX || nch < 0) + return E_OVERFLOW; + + current_capacity = XXXROUNDUP(nch); + required_capacity = XXXROUNDUP(nch + 1); + if (current_capacity < 0 || required_capacity < 0) + return E_OVERFLOW; + if (current_capacity < required_capacity) { + n = n1->n_child; + n = (node *) PyObject_REALLOC(n, + required_capacity * sizeof(node)); + if (n == NULL) + return E_NOMEM; + n1->n_child = n; + } + + n = &n1->n_child[n1->n_nchildren++]; + n->n_type = type; + n->n_str = str; + n->n_lineno = lineno; + n->n_col_offset = col_offset; + n->n_nchildren = 0; + n->n_child = NULL; + return 0; +} + +/* Forward */ +static void freechildren(node *); + + +void +PyNode_Free(node *n) +{ + if (n != NULL) { + freechildren(n); + PyObject_FREE(n); + } +} + +static void +freechildren(node *n) +{ + int i; + for (i = NCH(n); --i >= 0; ) + freechildren(CHILD(n, i)); + if (n->n_child != NULL) + PyObject_FREE(n->n_child); + if (STR(n) != NULL) + PyObject_FREE(STR(n)); +} diff --git a/sys/src/cmd/python/Parser/parser.c b/sys/src/cmd/python/Parser/parser.c new file mode 100644 index 000000000..2ce84cd32 --- /dev/null +++ b/sys/src/cmd/python/Parser/parser.c @@ -0,0 +1,433 @@ + +/* Parser implementation */ + +/* For a description, see the comments at end of this file */ + +/* XXX To do: error recovery */ + +#include "Python.h" +#include "pgenheaders.h" +#include "token.h" +#include "grammar.h" +#include "node.h" +#include "parser.h" +#include "errcode.h" + + +#ifdef Py_DEBUG +extern int Py_DebugFlag; +#define D(x) if (!Py_DebugFlag); else x +#else +#define D(x) +#endif + + +/* STACK DATA TYPE */ + +static void s_reset(stack *); + +static void +s_reset(stack *s) +{ + s->s_top = &s->s_base[MAXSTACK]; +} + +#define s_empty(s) ((s)->s_top == &(s)->s_base[MAXSTACK]) + +static int +s_push(register stack *s, dfa *d, node *parent) +{ + register stackentry *top; + if (s->s_top == s->s_base) { + fprintf(stderr, "s_push: parser stack overflow\n"); + return E_NOMEM; + } + top = --s->s_top; + top->s_dfa = d; + top->s_parent = parent; + top->s_state = 0; + return 0; +} + +#ifdef Py_DEBUG + +static void +s_pop(register stack *s) +{ + if (s_empty(s)) + Py_FatalError("s_pop: parser stack underflow -- FATAL"); + s->s_top++; +} + +#else /* !Py_DEBUG */ + +#define s_pop(s) (s)->s_top++ + +#endif + + +/* PARSER CREATION */ + +parser_state * +PyParser_New(grammar *g, int start) +{ + parser_state *ps; + + if (!g->g_accel) + PyGrammar_AddAccelerators(g); + ps = (parser_state *)PyMem_MALLOC(sizeof(parser_state)); + if (ps == NULL) + return NULL; + ps->p_grammar = g; +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD + ps->p_flags = 0; +#endif + ps->p_tree = PyNode_New(start); + if (ps->p_tree == NULL) { + PyMem_FREE(ps); + return NULL; + } + s_reset(&ps->p_stack); + (void) s_push(&ps->p_stack, PyGrammar_FindDFA(g, start), ps->p_tree); + return ps; +} + +void +PyParser_Delete(parser_state *ps) +{ + /* NB If you want to save the parse tree, + you must set p_tree to NULL before calling delparser! */ + PyNode_Free(ps->p_tree); + PyMem_FREE(ps); +} + + +/* PARSER STACK OPERATIONS */ + +static int +shift(register stack *s, int type, char *str, int newstate, int lineno, int col_offset) +{ + int err; + assert(!s_empty(s)); + err = PyNode_AddChild(s->s_top->s_parent, type, str, lineno, col_offset); + if (err) + return err; + s->s_top->s_state = newstate; + return 0; +} + +static int +push(register stack *s, int type, dfa *d, int newstate, int lineno, int col_offset) +{ + int err; + register node *n; + n = s->s_top->s_parent; + assert(!s_empty(s)); + err = PyNode_AddChild(n, type, (char *)NULL, lineno, col_offset); + if (err) + return err; + s->s_top->s_state = newstate; + return s_push(s, d, CHILD(n, NCH(n)-1)); +} + + +/* PARSER PROPER */ + +static int +classify(parser_state *ps, int type, char *str) +{ + grammar *g = ps->p_grammar; + register int n = g->g_ll.ll_nlabels; + + if (type == NAME) { + register char *s = str; + register label *l = g->g_ll.ll_label; + register int i; + for (i = n; i > 0; i--, l++) { + if (l->lb_type != NAME || l->lb_str == NULL || + l->lb_str[0] != s[0] || + strcmp(l->lb_str, s) != 0) + continue; +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD + if (!(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) { + if (s[0] == 'w' && strcmp(s, "with") == 0) + break; /* not a keyword yet */ + else if (s[0] == 'a' && strcmp(s, "as") == 0) + break; /* not a keyword yet */ + } +#endif + D(printf("It's a keyword\n")); + return n - i; + } + } + + { + register label *l = g->g_ll.ll_label; + register int i; + for (i = n; i > 0; i--, l++) { + if (l->lb_type == type && l->lb_str == NULL) { + D(printf("It's a token we know\n")); + return n - i; + } + } + } + + D(printf("Illegal token\n")); + return -1; +} + +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD +static void +future_hack(parser_state *ps) +{ + node *n = ps->p_stack.s_top->s_parent; + node *ch, *cch; + int i; + + /* from __future__ import ..., must have at least 4 children */ + n = CHILD(n, 0); + if (NCH(n) < 4) + return; + ch = CHILD(n, 0); + if (STR(ch) == NULL || strcmp(STR(ch), "from") != 0) + return; + ch = CHILD(n, 1); + if (NCH(ch) == 1 && STR(CHILD(ch, 0)) && + strcmp(STR(CHILD(ch, 0)), "__future__") != 0) + return; + ch = CHILD(n, 3); + /* ch can be a star, a parenthesis or import_as_names */ + if (TYPE(ch) == STAR) + return; + if (TYPE(ch) == LPAR) + ch = CHILD(n, 4); + + for (i = 0; i < NCH(ch); i += 2) { + cch = CHILD(ch, i); + if (NCH(cch) >= 1 && TYPE(CHILD(cch, 0)) == NAME && + strcmp(STR(CHILD(cch, 0)), "with_statement") == 0) { + ps->p_flags |= CO_FUTURE_WITH_STATEMENT; + break; + } + } +} +#endif /* future keyword */ + +int +PyParser_AddToken(register parser_state *ps, register int type, char *str, + int lineno, int col_offset, int *expected_ret) +{ + register int ilabel; + int err; + + D(printf("Token %s/'%s' ... ", _PyParser_TokenNames[type], str)); + + /* Find out which label this token is */ + ilabel = classify(ps, type, str); + if (ilabel < 0) + return E_SYNTAX; + + /* Loop until the token is shifted or an error occurred */ + for (;;) { + /* Fetch the current dfa and state */ + register dfa *d = ps->p_stack.s_top->s_dfa; + register state *s = &d->d_state[ps->p_stack.s_top->s_state]; + + D(printf(" DFA '%s', state %d:", + d->d_name, ps->p_stack.s_top->s_state)); + + /* Check accelerator */ + if (s->s_lower <= ilabel && ilabel < s->s_upper) { + register int x = s->s_accel[ilabel - s->s_lower]; + if (x != -1) { + if (x & (1<<7)) { + /* Push non-terminal */ + int nt = (x >> 8) + NT_OFFSET; + int arrow = x & ((1<<7)-1); + dfa *d1 = PyGrammar_FindDFA( + ps->p_grammar, nt); + if ((err = push(&ps->p_stack, nt, d1, + arrow, lineno, col_offset)) > 0) { + D(printf(" MemError: push\n")); + return err; + } + D(printf(" Push ...\n")); + continue; + } + + /* Shift the token */ + if ((err = shift(&ps->p_stack, type, str, + x, lineno, col_offset)) > 0) { + D(printf(" MemError: shift.\n")); + return err; + } + D(printf(" Shift.\n")); + /* Pop while we are in an accept-only state */ + while (s = &d->d_state + [ps->p_stack.s_top->s_state], + s->s_accept && s->s_narcs == 1) { + D(printf(" DFA '%s', state %d: " + "Direct pop.\n", + d->d_name, + ps->p_stack.s_top->s_state)); +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD + if (d->d_name[0] == 'i' && + strcmp(d->d_name, + "import_stmt") == 0) + future_hack(ps); +#endif + s_pop(&ps->p_stack); + if (s_empty(&ps->p_stack)) { + D(printf(" ACCEPT.\n")); + return E_DONE; + } + d = ps->p_stack.s_top->s_dfa; + } + return E_OK; + } + } + + if (s->s_accept) { +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD + if (d->d_name[0] == 'i' && + strcmp(d->d_name, "import_stmt") == 0) + future_hack(ps); +#endif + /* Pop this dfa and try again */ + s_pop(&ps->p_stack); + D(printf(" Pop ...\n")); + if (s_empty(&ps->p_stack)) { + D(printf(" Error: bottom of stack.\n")); + return E_SYNTAX; + } + continue; + } + + /* Stuck, report syntax error */ + D(printf(" Error.\n")); + if (expected_ret) { + if (s->s_lower == s->s_upper - 1) { + /* Only one possible expected token */ + *expected_ret = ps->p_grammar-> + g_ll.ll_label[s->s_lower].lb_type; + } + else + *expected_ret = -1; + } + return E_SYNTAX; + } +} + + +#ifdef Py_DEBUG + +/* DEBUG OUTPUT */ + +void +dumptree(grammar *g, node *n) +{ + int i; + + if (n == NULL) + printf("NIL"); + else { + label l; + l.lb_type = TYPE(n); + l.lb_str = STR(n); + printf("%s", PyGrammar_LabelRepr(&l)); + if (ISNONTERMINAL(TYPE(n))) { + printf("("); + for (i = 0; i < NCH(n); i++) { + if (i > 0) + printf(","); + dumptree(g, CHILD(n, i)); + } + printf(")"); + } + } +} + +void +showtree(grammar *g, node *n) +{ + int i; + + if (n == NULL) + return; + if (ISNONTERMINAL(TYPE(n))) { + for (i = 0; i < NCH(n); i++) + showtree(g, CHILD(n, i)); + } + else if (ISTERMINAL(TYPE(n))) { + printf("%s", _PyParser_TokenNames[TYPE(n)]); + if (TYPE(n) == NUMBER || TYPE(n) == NAME) + printf("(%s)", STR(n)); + printf(" "); + } + else + printf("? "); +} + +void +printtree(parser_state *ps) +{ + if (Py_DebugFlag) { + printf("Parse tree:\n"); + dumptree(ps->p_grammar, ps->p_tree); + printf("\n"); + printf("Tokens:\n"); + showtree(ps->p_grammar, ps->p_tree); + printf("\n"); + } + printf("Listing:\n"); + PyNode_ListTree(ps->p_tree); + printf("\n"); +} + +#endif /* Py_DEBUG */ + +/* + +Description +----------- + +The parser's interface is different than usual: the function addtoken() +must be called for each token in the input. This makes it possible to +turn it into an incremental parsing system later. The parsing system +constructs a parse tree as it goes. + +A parsing rule is represented as a Deterministic Finite-state Automaton +(DFA). A node in a DFA represents a state of the parser; an arc represents +a transition. Transitions are either labeled with terminal symbols or +with non-terminals. When the parser decides to follow an arc labeled +with a non-terminal, it is invoked recursively with the DFA representing +the parsing rule for that as its initial state; when that DFA accepts, +the parser that invoked it continues. The parse tree constructed by the +recursively called parser is inserted as a child in the current parse tree. + +The DFA's can be constructed automatically from a more conventional +language description. An extended LL(1) grammar (ELL(1)) is suitable. +Certain restrictions make the parser's life easier: rules that can produce +the empty string should be outlawed (there are other ways to put loops +or optional parts in the language). To avoid the need to construct +FIRST sets, we can require that all but the last alternative of a rule +(really: arc going out of a DFA's state) must begin with a terminal +symbol. + +As an example, consider this grammar: + +expr: term (OP term)* +term: CONSTANT | '(' expr ')' + +The DFA corresponding to the rule for expr is: + +------->.---term-->.-------> + ^ | + | | + \----OP----/ + +The parse tree generated for the input a+b is: + +(expr: (term: (NAME: a)), (OP: +), (term: (NAME: b))) + +*/ diff --git a/sys/src/cmd/python/Parser/parser.h b/sys/src/cmd/python/Parser/parser.h new file mode 100644 index 000000000..bdca3e944 --- /dev/null +++ b/sys/src/cmd/python/Parser/parser.h @@ -0,0 +1,42 @@ +#ifndef Py_PARSER_H +#define Py_PARSER_H +#ifdef __cplusplus +extern "C" { +#endif + + +/* Parser interface */ + +#define MAXSTACK 500 + +typedef struct { + int s_state; /* State in current DFA */ + dfa *s_dfa; /* Current DFA */ + struct _node *s_parent; /* Where to add next node */ +} stackentry; + +typedef struct { + stackentry *s_top; /* Top entry */ + stackentry s_base[MAXSTACK];/* Array of stack entries */ + /* NB The stack grows down */ +} stack; + +typedef struct { + stack p_stack; /* Stack of parser states */ + grammar *p_grammar; /* Grammar to use */ + node *p_tree; /* Top of parse tree */ +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD + unsigned long p_flags; /* see co_flags in Include/code.h */ +#endif +} parser_state; + +parser_state *PyParser_New(grammar *g, int start); +void PyParser_Delete(parser_state *ps); +int PyParser_AddToken(parser_state *ps, int type, char *str, int lineno, int col_offset, + int *expected_ret); +void PyGrammar_AddAccelerators(grammar *g); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_PARSER_H */ diff --git a/sys/src/cmd/python/Parser/parsetok.c b/sys/src/cmd/python/Parser/parsetok.c new file mode 100644 index 000000000..be53e1c59 --- /dev/null +++ b/sys/src/cmd/python/Parser/parsetok.c @@ -0,0 +1,260 @@ + +/* Parser-tokenizer link implementation */ + +#include "pgenheaders.h" +#include "tokenizer.h" +#include "node.h" +#include "grammar.h" +#include "parser.h" +#include "parsetok.h" +#include "errcode.h" +#include "graminit.h" + +int Py_TabcheckFlag; + + +/* Forward */ +static node *parsetok(struct tok_state *, grammar *, int, perrdetail *, int); +static void initerr(perrdetail *err_ret, const char* filename); + +/* Parse input coming from a string. Return error code, print some errors. */ +node * +PyParser_ParseString(const char *s, grammar *g, int start, perrdetail *err_ret) +{ + return PyParser_ParseStringFlagsFilename(s, NULL, g, start, err_ret, 0); +} + +node * +PyParser_ParseStringFlags(const char *s, grammar *g, int start, + perrdetail *err_ret, int flags) +{ + return PyParser_ParseStringFlagsFilename(s, NULL, + g, start, err_ret, flags); +} + +node * +PyParser_ParseStringFlagsFilename(const char *s, const char *filename, + grammar *g, int start, + perrdetail *err_ret, int flags) +{ + struct tok_state *tok; + + initerr(err_ret, filename); + + if ((tok = PyTokenizer_FromString(s)) == NULL) { + err_ret->error = PyErr_Occurred() ? E_DECODE : E_NOMEM; + return NULL; + } + + tok->filename = filename ? filename : "<string>"; + if (Py_TabcheckFlag || Py_VerboseFlag) { + tok->altwarning = (tok->filename != NULL); + if (Py_TabcheckFlag >= 2) + tok->alterror++; + } + + return parsetok(tok, g, start, err_ret, flags); +} + +/* Parse input coming from a file. Return error code, print some errors. */ + +node * +PyParser_ParseFile(FILE *fp, const char *filename, grammar *g, int start, + char *ps1, char *ps2, perrdetail *err_ret) +{ + return PyParser_ParseFileFlags(fp, filename, g, start, ps1, ps2, + err_ret, 0); +} + +node * +PyParser_ParseFileFlags(FILE *fp, const char *filename, grammar *g, int start, + char *ps1, char *ps2, perrdetail *err_ret, int flags) +{ + struct tok_state *tok; + + initerr(err_ret, filename); + + if ((tok = PyTokenizer_FromFile(fp, ps1, ps2)) == NULL) { + err_ret->error = E_NOMEM; + return NULL; + } + tok->filename = filename; + if (Py_TabcheckFlag || Py_VerboseFlag) { + tok->altwarning = (filename != NULL); + if (Py_TabcheckFlag >= 2) + tok->alterror++; + } + + + return parsetok(tok, g, start, err_ret, flags); +} + +/* Parse input coming from the given tokenizer structure. + Return error code. */ + +static char with_msg[] = +"%s:%d: Warning: 'with' will become a reserved keyword in Python 2.6\n"; + +static char as_msg[] = +"%s:%d: Warning: 'as' will become a reserved keyword in Python 2.6\n"; + +static void +warn(const char *msg, const char *filename, int lineno) +{ + if (filename == NULL) + filename = "<string>"; + PySys_WriteStderr(msg, filename, lineno); +} + +static node * +parsetok(struct tok_state *tok, grammar *g, int start, perrdetail *err_ret, + int flags) +{ + parser_state *ps; + node *n; + int started = 0, handling_import = 0, handling_with = 0; + + if ((ps = PyParser_New(g, start)) == NULL) { + fprintf(stderr, "no mem for new parser\n"); + err_ret->error = E_NOMEM; + PyTokenizer_Free(tok); + return NULL; + } +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD + if (flags & PyPARSE_WITH_IS_KEYWORD) + ps->p_flags |= CO_FUTURE_WITH_STATEMENT; +#endif + + for (;;) { + char *a, *b; + int type; + size_t len; + char *str; + int col_offset; + + type = PyTokenizer_Get(tok, &a, &b); + if (type == ERRORTOKEN) { + err_ret->error = tok->done; + break; + } + if (type == ENDMARKER && started) { + type = NEWLINE; /* Add an extra newline */ + handling_with = handling_import = 0; + started = 0; + /* Add the right number of dedent tokens, + except if a certain flag is given -- + codeop.py uses this. */ + if (tok->indent && + !(flags & PyPARSE_DONT_IMPLY_DEDENT)) + { + tok->pendin = -tok->indent; + tok->indent = 0; + } + } + else + started = 1; + len = b - a; /* XXX this may compute NULL - NULL */ + str = (char *) PyObject_MALLOC(len + 1); + if (str == NULL) { + fprintf(stderr, "no mem for next token\n"); + err_ret->error = E_NOMEM; + break; + } + if (len > 0) + strncpy(str, a, len); + str[len] = '\0'; + +#ifdef PY_PARSER_REQUIRES_FUTURE_KEYWORD + /* This is only necessary to support the "as" warning, but + we don't want to warn about "as" in import statements. */ + if (type == NAME && + len == 6 && str[0] == 'i' && strcmp(str, "import") == 0) + handling_import = 1; + + /* Warn about with as NAME */ + if (type == NAME && + !(ps->p_flags & CO_FUTURE_WITH_STATEMENT)) { + if (len == 4 && str[0] == 'w' && strcmp(str, "with") == 0) + warn(with_msg, err_ret->filename, tok->lineno); + else if (!(handling_import || handling_with) && + len == 2 && str[0] == 'a' && + strcmp(str, "as") == 0) + warn(as_msg, err_ret->filename, tok->lineno); + } + else if (type == NAME && + (ps->p_flags & CO_FUTURE_WITH_STATEMENT) && + len == 4 && str[0] == 'w' && strcmp(str, "with") == 0) + handling_with = 1; +#endif + if (a >= tok->line_start) + col_offset = a - tok->line_start; + else + col_offset = -1; + + if ((err_ret->error = + PyParser_AddToken(ps, (int)type, str, tok->lineno, col_offset, + &(err_ret->expected))) != E_OK) { + if (err_ret->error != E_DONE) { + PyObject_FREE(str); + err_ret->token = type; + } + break; + } + } + + if (err_ret->error == E_DONE) { + n = ps->p_tree; + ps->p_tree = NULL; + } + else + n = NULL; + + PyParser_Delete(ps); + + if (n == NULL) { + if (tok->lineno <= 1 && tok->done == E_EOF) + err_ret->error = E_EOF; + err_ret->lineno = tok->lineno; + if (tok->buf != NULL) { + size_t len; + assert(tok->cur - tok->buf < INT_MAX); + err_ret->offset = (int)(tok->cur - tok->buf); + len = tok->inp - tok->buf; + err_ret->text = (char *) PyObject_MALLOC(len + 1); + if (err_ret->text != NULL) { + if (len > 0) + strncpy(err_ret->text, tok->buf, len); + err_ret->text[len] = '\0'; + } + } + } else if (tok->encoding != NULL) { + node* r = PyNode_New(encoding_decl); + if (!r) { + err_ret->error = E_NOMEM; + n = NULL; + goto done; + } + r->n_str = tok->encoding; + r->n_nchildren = 1; + r->n_child = n; + tok->encoding = NULL; + n = r; + } + +done: + PyTokenizer_Free(tok); + + return n; +} + +static void +initerr(perrdetail *err_ret, const char *filename) +{ + err_ret->error = E_OK; + err_ret->filename = filename; + err_ret->lineno = 0; + err_ret->offset = 0; + err_ret->text = NULL; + err_ret->token = -1; + err_ret->expected = -1; +} diff --git a/sys/src/cmd/python/Parser/pgen.c b/sys/src/cmd/python/Parser/pgen.c new file mode 100644 index 000000000..dfe7cacba --- /dev/null +++ b/sys/src/cmd/python/Parser/pgen.c @@ -0,0 +1,706 @@ +/* Parser generator */ + +/* For a description, see the comments at end of this file */ + +#include "Python.h" +#include "pgenheaders.h" +#include "token.h" +#include "node.h" +#include "grammar.h" +#include "metagrammar.h" +#include "pgen.h" + +extern int Py_DebugFlag; +extern int Py_IgnoreEnvironmentFlag; /* needed by Py_GETENV */ + + +/* PART ONE -- CONSTRUCT NFA -- Cf. Algorithm 3.2 from [Aho&Ullman 77] */ + +typedef struct _nfaarc { + int ar_label; + int ar_arrow; +} nfaarc; + +typedef struct _nfastate { + int st_narcs; + nfaarc *st_arc; +} nfastate; + +typedef struct _nfa { + int nf_type; + char *nf_name; + int nf_nstates; + nfastate *nf_state; + int nf_start, nf_finish; +} nfa; + +/* Forward */ +static void compile_rhs(labellist *ll, + nfa *nf, node *n, int *pa, int *pb); +static void compile_alt(labellist *ll, + nfa *nf, node *n, int *pa, int *pb); +static void compile_item(labellist *ll, + nfa *nf, node *n, int *pa, int *pb); +static void compile_atom(labellist *ll, + nfa *nf, node *n, int *pa, int *pb); + +static int +addnfastate(nfa *nf) +{ + nfastate *st; + + nf->nf_state = (nfastate *)PyObject_REALLOC(nf->nf_state, + sizeof(nfastate) * (nf->nf_nstates + 1)); + if (nf->nf_state == NULL) + Py_FatalError("out of mem"); + st = &nf->nf_state[nf->nf_nstates++]; + st->st_narcs = 0; + st->st_arc = NULL; + return st - nf->nf_state; +} + +static void +addnfaarc(nfa *nf, int from, int to, int lbl) +{ + nfastate *st; + nfaarc *ar; + + st = &nf->nf_state[from]; + st->st_arc = (nfaarc *)PyObject_REALLOC(st->st_arc, + sizeof(nfaarc) * (st->st_narcs + 1)); + if (st->st_arc == NULL) + Py_FatalError("out of mem"); + ar = &st->st_arc[st->st_narcs++]; + ar->ar_label = lbl; + ar->ar_arrow = to; +} + +static nfa * +newnfa(char *name) +{ + nfa *nf; + static int type = NT_OFFSET; /* All types will be disjunct */ + + nf = (nfa *)PyObject_MALLOC(sizeof(nfa)); + if (nf == NULL) + Py_FatalError("no mem for new nfa"); + nf->nf_type = type++; + nf->nf_name = name; /* XXX strdup(name) ??? */ + nf->nf_nstates = 0; + nf->nf_state = NULL; + nf->nf_start = nf->nf_finish = -1; + return nf; +} + +typedef struct _nfagrammar { + int gr_nnfas; + nfa **gr_nfa; + labellist gr_ll; +} nfagrammar; + +/* Forward */ +static void compile_rule(nfagrammar *gr, node *n); + +static nfagrammar * +newnfagrammar(void) +{ + nfagrammar *gr; + + gr = (nfagrammar *)PyObject_MALLOC(sizeof(nfagrammar)); + if (gr == NULL) + Py_FatalError("no mem for new nfa grammar"); + gr->gr_nnfas = 0; + gr->gr_nfa = NULL; + gr->gr_ll.ll_nlabels = 0; + gr->gr_ll.ll_label = NULL; + addlabel(&gr->gr_ll, ENDMARKER, "EMPTY"); + return gr; +} + +static nfa * +addnfa(nfagrammar *gr, char *name) +{ + nfa *nf; + + nf = newnfa(name); + gr->gr_nfa = (nfa **)PyObject_REALLOC(gr->gr_nfa, + sizeof(nfa) * (gr->gr_nnfas + 1)); + if (gr->gr_nfa == NULL) + Py_FatalError("out of mem"); + gr->gr_nfa[gr->gr_nnfas++] = nf; + addlabel(&gr->gr_ll, NAME, nf->nf_name); + return nf; +} + +#ifdef Py_DEBUG + +static char REQNFMT[] = "metacompile: less than %d children\n"; + +#define REQN(i, count) \ + if (i < count) { \ + fprintf(stderr, REQNFMT, count); \ + Py_FatalError("REQN"); \ + } else + +#else +#define REQN(i, count) /* empty */ +#endif + +static nfagrammar * +metacompile(node *n) +{ + nfagrammar *gr; + int i; + + if (Py_DebugFlag) + printf("Compiling (meta-) parse tree into NFA grammar\n"); + gr = newnfagrammar(); + REQ(n, MSTART); + i = n->n_nchildren - 1; /* Last child is ENDMARKER */ + n = n->n_child; + for (; --i >= 0; n++) { + if (n->n_type != NEWLINE) + compile_rule(gr, n); + } + return gr; +} + +static void +compile_rule(nfagrammar *gr, node *n) +{ + nfa *nf; + + REQ(n, RULE); + REQN(n->n_nchildren, 4); + n = n->n_child; + REQ(n, NAME); + nf = addnfa(gr, n->n_str); + n++; + REQ(n, COLON); + n++; + REQ(n, RHS); + compile_rhs(&gr->gr_ll, nf, n, &nf->nf_start, &nf->nf_finish); + n++; + REQ(n, NEWLINE); +} + +static void +compile_rhs(labellist *ll, nfa *nf, node *n, int *pa, int *pb) +{ + int i; + int a, b; + + REQ(n, RHS); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + REQ(n, ALT); + compile_alt(ll, nf, n, pa, pb); + if (--i <= 0) + return; + n++; + a = *pa; + b = *pb; + *pa = addnfastate(nf); + *pb = addnfastate(nf); + addnfaarc(nf, *pa, a, EMPTY); + addnfaarc(nf, b, *pb, EMPTY); + for (; --i >= 0; n++) { + REQ(n, VBAR); + REQN(i, 1); + --i; + n++; + REQ(n, ALT); + compile_alt(ll, nf, n, &a, &b); + addnfaarc(nf, *pa, a, EMPTY); + addnfaarc(nf, b, *pb, EMPTY); + } +} + +static void +compile_alt(labellist *ll, nfa *nf, node *n, int *pa, int *pb) +{ + int i; + int a, b; + + REQ(n, ALT); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + REQ(n, ITEM); + compile_item(ll, nf, n, pa, pb); + --i; + n++; + for (; --i >= 0; n++) { + REQ(n, ITEM); + compile_item(ll, nf, n, &a, &b); + addnfaarc(nf, *pb, a, EMPTY); + *pb = b; + } +} + +static void +compile_item(labellist *ll, nfa *nf, node *n, int *pa, int *pb) +{ + int i; + int a, b; + + REQ(n, ITEM); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + if (n->n_type == LSQB) { + REQN(i, 3); + n++; + REQ(n, RHS); + *pa = addnfastate(nf); + *pb = addnfastate(nf); + addnfaarc(nf, *pa, *pb, EMPTY); + compile_rhs(ll, nf, n, &a, &b); + addnfaarc(nf, *pa, a, EMPTY); + addnfaarc(nf, b, *pb, EMPTY); + REQN(i, 1); + n++; + REQ(n, RSQB); + } + else { + compile_atom(ll, nf, n, pa, pb); + if (--i <= 0) + return; + n++; + addnfaarc(nf, *pb, *pa, EMPTY); + if (n->n_type == STAR) + *pb = *pa; + else + REQ(n, PLUS); + } +} + +static void +compile_atom(labellist *ll, nfa *nf, node *n, int *pa, int *pb) +{ + int i; + + REQ(n, ATOM); + i = n->n_nchildren; + REQN(i, 1); + n = n->n_child; + if (n->n_type == LPAR) { + REQN(i, 3); + n++; + REQ(n, RHS); + compile_rhs(ll, nf, n, pa, pb); + n++; + REQ(n, RPAR); + } + else if (n->n_type == NAME || n->n_type == STRING) { + *pa = addnfastate(nf); + *pb = addnfastate(nf); + addnfaarc(nf, *pa, *pb, addlabel(ll, n->n_type, n->n_str)); + } + else + REQ(n, NAME); +} + +static void +dumpstate(labellist *ll, nfa *nf, int istate) +{ + nfastate *st; + int i; + nfaarc *ar; + + printf("%c%2d%c", + istate == nf->nf_start ? '*' : ' ', + istate, + istate == nf->nf_finish ? '.' : ' '); + st = &nf->nf_state[istate]; + ar = st->st_arc; + for (i = 0; i < st->st_narcs; i++) { + if (i > 0) + printf("\n "); + printf("-> %2d %s", ar->ar_arrow, + PyGrammar_LabelRepr(&ll->ll_label[ar->ar_label])); + ar++; + } + printf("\n"); +} + +static void +dumpnfa(labellist *ll, nfa *nf) +{ + int i; + + printf("NFA '%s' has %d states; start %d, finish %d\n", + nf->nf_name, nf->nf_nstates, nf->nf_start, nf->nf_finish); + for (i = 0; i < nf->nf_nstates; i++) + dumpstate(ll, nf, i); +} + + +/* PART TWO -- CONSTRUCT DFA -- Algorithm 3.1 from [Aho&Ullman 77] */ + +static void +addclosure(bitset ss, nfa *nf, int istate) +{ + if (addbit(ss, istate)) { + nfastate *st = &nf->nf_state[istate]; + nfaarc *ar = st->st_arc; + int i; + + for (i = st->st_narcs; --i >= 0; ) { + if (ar->ar_label == EMPTY) + addclosure(ss, nf, ar->ar_arrow); + ar++; + } + } +} + +typedef struct _ss_arc { + bitset sa_bitset; + int sa_arrow; + int sa_label; +} ss_arc; + +typedef struct _ss_state { + bitset ss_ss; + int ss_narcs; + struct _ss_arc *ss_arc; + int ss_deleted; + int ss_finish; + int ss_rename; +} ss_state; + +typedef struct _ss_dfa { + int sd_nstates; + ss_state *sd_state; +} ss_dfa; + +/* Forward */ +static void printssdfa(int xx_nstates, ss_state *xx_state, int nbits, + labellist *ll, char *msg); +static void simplify(int xx_nstates, ss_state *xx_state); +static void convert(dfa *d, int xx_nstates, ss_state *xx_state); + +static void +makedfa(nfagrammar *gr, nfa *nf, dfa *d) +{ + int nbits = nf->nf_nstates; + bitset ss; + int xx_nstates; + ss_state *xx_state, *yy; + ss_arc *zz; + int istate, jstate, iarc, jarc, ibit; + nfastate *st; + nfaarc *ar; + + ss = newbitset(nbits); + addclosure(ss, nf, nf->nf_start); + xx_state = (ss_state *)PyObject_MALLOC(sizeof(ss_state)); + if (xx_state == NULL) + Py_FatalError("no mem for xx_state in makedfa"); + xx_nstates = 1; + yy = &xx_state[0]; + yy->ss_ss = ss; + yy->ss_narcs = 0; + yy->ss_arc = NULL; + yy->ss_deleted = 0; + yy->ss_finish = testbit(ss, nf->nf_finish); + if (yy->ss_finish) + printf("Error: nonterminal '%s' may produce empty.\n", + nf->nf_name); + + /* This algorithm is from a book written before + the invention of structured programming... */ + + /* For each unmarked state... */ + for (istate = 0; istate < xx_nstates; ++istate) { + size_t size; + yy = &xx_state[istate]; + ss = yy->ss_ss; + /* For all its states... */ + for (ibit = 0; ibit < nf->nf_nstates; ++ibit) { + if (!testbit(ss, ibit)) + continue; + st = &nf->nf_state[ibit]; + /* For all non-empty arcs from this state... */ + for (iarc = 0; iarc < st->st_narcs; iarc++) { + ar = &st->st_arc[iarc]; + if (ar->ar_label == EMPTY) + continue; + /* Look up in list of arcs from this state */ + for (jarc = 0; jarc < yy->ss_narcs; ++jarc) { + zz = &yy->ss_arc[jarc]; + if (ar->ar_label == zz->sa_label) + goto found; + } + /* Add new arc for this state */ + size = sizeof(ss_arc) * (yy->ss_narcs + 1); + yy->ss_arc = (ss_arc *)PyObject_REALLOC( + yy->ss_arc, size); + if (yy->ss_arc == NULL) + Py_FatalError("out of mem"); + zz = &yy->ss_arc[yy->ss_narcs++]; + zz->sa_label = ar->ar_label; + zz->sa_bitset = newbitset(nbits); + zz->sa_arrow = -1; + found: ; + /* Add destination */ + addclosure(zz->sa_bitset, nf, ar->ar_arrow); + } + } + /* Now look up all the arrow states */ + for (jarc = 0; jarc < xx_state[istate].ss_narcs; jarc++) { + zz = &xx_state[istate].ss_arc[jarc]; + for (jstate = 0; jstate < xx_nstates; jstate++) { + if (samebitset(zz->sa_bitset, + xx_state[jstate].ss_ss, nbits)) { + zz->sa_arrow = jstate; + goto done; + } + } + size = sizeof(ss_state) * (xx_nstates + 1); + xx_state = (ss_state *)PyObject_REALLOC(xx_state, + size); + if (xx_state == NULL) + Py_FatalError("out of mem"); + zz->sa_arrow = xx_nstates; + yy = &xx_state[xx_nstates++]; + yy->ss_ss = zz->sa_bitset; + yy->ss_narcs = 0; + yy->ss_arc = NULL; + yy->ss_deleted = 0; + yy->ss_finish = testbit(yy->ss_ss, nf->nf_finish); + done: ; + } + } + + if (Py_DebugFlag) + printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll, + "before minimizing"); + + simplify(xx_nstates, xx_state); + + if (Py_DebugFlag) + printssdfa(xx_nstates, xx_state, nbits, &gr->gr_ll, + "after minimizing"); + + convert(d, xx_nstates, xx_state); + + /* XXX cleanup */ +} + +static void +printssdfa(int xx_nstates, ss_state *xx_state, int nbits, + labellist *ll, char *msg) +{ + int i, ibit, iarc; + ss_state *yy; + ss_arc *zz; + + printf("Subset DFA %s\n", msg); + for (i = 0; i < xx_nstates; i++) { + yy = &xx_state[i]; + if (yy->ss_deleted) + continue; + printf(" Subset %d", i); + if (yy->ss_finish) + printf(" (finish)"); + printf(" { "); + for (ibit = 0; ibit < nbits; ibit++) { + if (testbit(yy->ss_ss, ibit)) + printf("%d ", ibit); + } + printf("}\n"); + for (iarc = 0; iarc < yy->ss_narcs; iarc++) { + zz = &yy->ss_arc[iarc]; + printf(" Arc to state %d, label %s\n", + zz->sa_arrow, + PyGrammar_LabelRepr( + &ll->ll_label[zz->sa_label])); + } + } +} + + +/* PART THREE -- SIMPLIFY DFA */ + +/* Simplify the DFA by repeatedly eliminating states that are + equivalent to another oner. This is NOT Algorithm 3.3 from + [Aho&Ullman 77]. It does not always finds the minimal DFA, + but it does usually make a much smaller one... (For an example + of sub-optimal behavior, try S: x a b+ | y a b+.) +*/ + +static int +samestate(ss_state *s1, ss_state *s2) +{ + int i; + + if (s1->ss_narcs != s2->ss_narcs || s1->ss_finish != s2->ss_finish) + return 0; + for (i = 0; i < s1->ss_narcs; i++) { + if (s1->ss_arc[i].sa_arrow != s2->ss_arc[i].sa_arrow || + s1->ss_arc[i].sa_label != s2->ss_arc[i].sa_label) + return 0; + } + return 1; +} + +static void +renamestates(int xx_nstates, ss_state *xx_state, int from, int to) +{ + int i, j; + + if (Py_DebugFlag) + printf("Rename state %d to %d.\n", from, to); + for (i = 0; i < xx_nstates; i++) { + if (xx_state[i].ss_deleted) + continue; + for (j = 0; j < xx_state[i].ss_narcs; j++) { + if (xx_state[i].ss_arc[j].sa_arrow == from) + xx_state[i].ss_arc[j].sa_arrow = to; + } + } +} + +static void +simplify(int xx_nstates, ss_state *xx_state) +{ + int changes; + int i, j; + + do { + changes = 0; + for (i = 1; i < xx_nstates; i++) { + if (xx_state[i].ss_deleted) + continue; + for (j = 0; j < i; j++) { + if (xx_state[j].ss_deleted) + continue; + if (samestate(&xx_state[i], &xx_state[j])) { + xx_state[i].ss_deleted++; + renamestates(xx_nstates, xx_state, + i, j); + changes++; + break; + } + } + } + } while (changes); +} + + +/* PART FOUR -- GENERATE PARSING TABLES */ + +/* Convert the DFA into a grammar that can be used by our parser */ + +static void +convert(dfa *d, int xx_nstates, ss_state *xx_state) +{ + int i, j; + ss_state *yy; + ss_arc *zz; + + for (i = 0; i < xx_nstates; i++) { + yy = &xx_state[i]; + if (yy->ss_deleted) + continue; + yy->ss_rename = addstate(d); + } + + for (i = 0; i < xx_nstates; i++) { + yy = &xx_state[i]; + if (yy->ss_deleted) + continue; + for (j = 0; j < yy->ss_narcs; j++) { + zz = &yy->ss_arc[j]; + addarc(d, yy->ss_rename, + xx_state[zz->sa_arrow].ss_rename, + zz->sa_label); + } + if (yy->ss_finish) + addarc(d, yy->ss_rename, yy->ss_rename, 0); + } + + d->d_initial = 0; +} + + +/* PART FIVE -- GLUE IT ALL TOGETHER */ + +static grammar * +maketables(nfagrammar *gr) +{ + int i; + nfa *nf; + dfa *d; + grammar *g; + + if (gr->gr_nnfas == 0) + return NULL; + g = newgrammar(gr->gr_nfa[0]->nf_type); + /* XXX first rule must be start rule */ + g->g_ll = gr->gr_ll; + + for (i = 0; i < gr->gr_nnfas; i++) { + nf = gr->gr_nfa[i]; + if (Py_DebugFlag) { + printf("Dump of NFA for '%s' ...\n", nf->nf_name); + dumpnfa(&gr->gr_ll, nf); + printf("Making DFA for '%s' ...\n", nf->nf_name); + } + d = adddfa(g, nf->nf_type, nf->nf_name); + makedfa(gr, gr->gr_nfa[i], d); + } + + return g; +} + +grammar * +pgen(node *n) +{ + nfagrammar *gr; + grammar *g; + + gr = metacompile(n); + g = maketables(gr); + translatelabels(g); + addfirstsets(g); + return g; +} + +grammar * +Py_pgen(node *n) +{ + return pgen(n); +} + +/* + +Description +----------- + +Input is a grammar in extended BNF (using * for repetition, + for +at-least-once repetition, [] for optional parts, | for alternatives and +() for grouping). This has already been parsed and turned into a parse +tree. + +Each rule is considered as a regular expression in its own right. +It is turned into a Non-deterministic Finite Automaton (NFA), which +is then turned into a Deterministic Finite Automaton (DFA), which is then +optimized to reduce the number of states. See [Aho&Ullman 77] chapter 3, +or similar compiler books (this technique is more often used for lexical +analyzers). + +The DFA's are used by the parser as parsing tables in a special way +that's probably unique. Before they are usable, the FIRST sets of all +non-terminals are computed. + +Reference +--------- + +[Aho&Ullman 77] + Aho&Ullman, Principles of Compiler Design, Addison-Wesley 1977 + (first edition) + +*/ diff --git a/sys/src/cmd/python/Parser/pgenmain.c b/sys/src/cmd/python/Parser/pgenmain.c new file mode 100644 index 000000000..fc27a2cd1 --- /dev/null +++ b/sys/src/cmd/python/Parser/pgenmain.c @@ -0,0 +1,173 @@ + +/* Parser generator main program */ + +/* This expects a filename containing the grammar as argv[1] (UNIX) + or asks the console for such a file name (THINK C). + It writes its output on two files in the current directory: + - "graminit.c" gets the grammar as a bunch of initialized data + - "graminit.h" gets the grammar's non-terminals as #defines. + Error messages and status info during the generation process are + written to stdout, or sometimes to stderr. */ + +/* XXX TO DO: + - check for duplicate definitions of names (instead of fatal err) +*/ + +#include "Python.h" +#include "pgenheaders.h" +#include "grammar.h" +#include "node.h" +#include "parsetok.h" +#include "pgen.h" + +int Py_DebugFlag; +int Py_VerboseFlag; +int Py_IgnoreEnvironmentFlag; + +/* Forward */ +grammar *getgrammar(char *filename); + +void +Py_Exit(int sts) +{ + exit(sts); +} + +int +main(int argc, char **argv) +{ + grammar *g; + FILE *fp; + char *filename, *graminit_h, *graminit_c; + + if (argc != 4) { + fprintf(stderr, + "usage: %s grammar graminit.h graminit.c\n", argv[0]); + Py_Exit(2); + } + filename = argv[1]; + graminit_h = argv[2]; + graminit_c = argv[3]; + g = getgrammar(filename); + fp = fopen(graminit_c, "w"); + if (fp == NULL) { + perror(graminit_c); + Py_Exit(1); + } + if (Py_DebugFlag) + printf("Writing %s ...\n", graminit_c); + printgrammar(g, fp); + fclose(fp); + fp = fopen(graminit_h, "w"); + if (fp == NULL) { + perror(graminit_h); + Py_Exit(1); + } + if (Py_DebugFlag) + printf("Writing %s ...\n", graminit_h); + printnonterminals(g, fp); + fclose(fp); + Py_Exit(0); + return 0; /* Make gcc -Wall happy */ +} + +grammar * +getgrammar(char *filename) +{ + FILE *fp; + node *n; + grammar *g0, *g; + perrdetail err; + + fp = fopen(filename, "r"); + if (fp == NULL) { + perror(filename); + Py_Exit(1); + } + g0 = meta_grammar(); + n = PyParser_ParseFile(fp, filename, g0, g0->g_start, + (char *)NULL, (char *)NULL, &err); + fclose(fp); + if (n == NULL) { + fprintf(stderr, "Parsing error %d, line %d.\n", + err.error, err.lineno); + if (err.text != NULL) { + size_t i; + fprintf(stderr, "%s", err.text); + i = strlen(err.text); + if (i == 0 || err.text[i-1] != '\n') + fprintf(stderr, "\n"); + for (i = 0; i < err.offset; i++) { + if (err.text[i] == '\t') + putc('\t', stderr); + else + putc(' ', stderr); + } + fprintf(stderr, "^\n"); + PyObject_FREE(err.text); + } + Py_Exit(1); + } + g = pgen(n); + if (g == NULL) { + printf("Bad grammar.\n"); + Py_Exit(1); + } + return g; +} + +/* Can't happen in pgen */ +PyObject* +PyErr_Occurred() +{ + return 0; +} + +void +Py_FatalError(const char *msg) +{ + fprintf(stderr, "pgen: FATAL ERROR: %s\n", msg); + Py_Exit(1); +} + +/* No-nonsense my_readline() for tokenizer.c */ + +char * +PyOS_Readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) +{ + size_t n = 1000; + char *p = (char *)PyMem_MALLOC(n); + char *q; + if (p == NULL) + return NULL; + fprintf(stderr, "%s", prompt); + q = fgets(p, n, sys_stdin); + if (q == NULL) { + *p = '\0'; + return p; + } + n = strlen(p); + if (n > 0 && p[n-1] != '\n') + p[n-1] = '\n'; + return (char *)PyMem_REALLOC(p, n+1); +} + +/* No-nonsense fgets */ +char * +Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj) +{ + return fgets(buf, n, stream); +} + + +#include <stdarg.h> + +void +PySys_WriteStderr(const char *format, ...) +{ + va_list va; + + va_start(va, format); + vfprintf(stderr, format, va); + va_end(va); +} diff --git a/sys/src/cmd/python/Parser/printgrammar.c b/sys/src/cmd/python/Parser/printgrammar.c new file mode 100644 index 000000000..554069814 --- /dev/null +++ b/sys/src/cmd/python/Parser/printgrammar.c @@ -0,0 +1,113 @@ + +/* Print a bunch of C initializers that represent a grammar */ + +#include "pgenheaders.h" +#include "grammar.h" + +/* Forward */ +static void printarcs(int, dfa *, FILE *); +static void printstates(grammar *, FILE *); +static void printdfas(grammar *, FILE *); +static void printlabels(grammar *, FILE *); + +void +printgrammar(grammar *g, FILE *fp) +{ + fprintf(fp, "#include \"pgenheaders.h\"\n"); + fprintf(fp, "#include \"grammar.h\"\n"); + printdfas(g, fp); + printlabels(g, fp); + fprintf(fp, "grammar _PyParser_Grammar = {\n"); + fprintf(fp, "\t%d,\n", g->g_ndfas); + fprintf(fp, "\tdfas,\n"); + fprintf(fp, "\t{%d, labels},\n", g->g_ll.ll_nlabels); + fprintf(fp, "\t%d\n", g->g_start); + fprintf(fp, "};\n"); +} + +void +printnonterminals(grammar *g, FILE *fp) +{ + dfa *d; + int i; + + d = g->g_dfa; + for (i = g->g_ndfas; --i >= 0; d++) + fprintf(fp, "#define %s %d\n", d->d_name, d->d_type); +} + +static void +printarcs(int i, dfa *d, FILE *fp) +{ + arc *a; + state *s; + int j, k; + + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) { + fprintf(fp, "static arc arcs_%d_%d[%d] = {\n", + i, j, s->s_narcs); + a = s->s_arc; + for (k = 0; k < s->s_narcs; k++, a++) + fprintf(fp, "\t{%d, %d},\n", a->a_lbl, a->a_arrow); + fprintf(fp, "};\n"); + } +} + +static void +printstates(grammar *g, FILE *fp) +{ + state *s; + dfa *d; + int i, j; + + d = g->g_dfa; + for (i = 0; i < g->g_ndfas; i++, d++) { + printarcs(i, d, fp); + fprintf(fp, "static state states_%d[%d] = {\n", + i, d->d_nstates); + s = d->d_state; + for (j = 0; j < d->d_nstates; j++, s++) + fprintf(fp, "\t{%d, arcs_%d_%d},\n", + s->s_narcs, i, j); + fprintf(fp, "};\n"); + } +} + +static void +printdfas(grammar *g, FILE *fp) +{ + dfa *d; + int i, j; + + printstates(g, fp); + fprintf(fp, "static dfa dfas[%d] = {\n", g->g_ndfas); + d = g->g_dfa; + for (i = 0; i < g->g_ndfas; i++, d++) { + fprintf(fp, "\t{%d, \"%s\", %d, %d, states_%d,\n", + d->d_type, d->d_name, d->d_initial, d->d_nstates, i); + fprintf(fp, "\t \""); + for (j = 0; j < NBYTES(g->g_ll.ll_nlabels); j++) + fprintf(fp, "\\%03o", d->d_first[j] & 0xff); + fprintf(fp, "\"},\n"); + } + fprintf(fp, "};\n"); +} + +static void +printlabels(grammar *g, FILE *fp) +{ + label *l; + int i; + + fprintf(fp, "static label labels[%d] = {\n", g->g_ll.ll_nlabels); + l = g->g_ll.ll_label; + for (i = g->g_ll.ll_nlabels; --i >= 0; l++) { + if (l->lb_str == NULL) + fprintf(fp, "\t{%d, 0},\n", l->lb_type); + else + fprintf(fp, "\t{%d, \"%s\"},\n", + l->lb_type, l->lb_str); + } + fprintf(fp, "};\n"); +} diff --git a/sys/src/cmd/python/Parser/spark.py b/sys/src/cmd/python/Parser/spark.py new file mode 100644 index 000000000..2c18623a0 --- /dev/null +++ b/sys/src/cmd/python/Parser/spark.py @@ -0,0 +1,840 @@ +# Copyright (c) 1998-2002 John Aycock +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +__version__ = 'SPARK-0.7 (pre-alpha-5)' + +import re +import sys +import string + +def _namelist(instance): + namelist, namedict, classlist = [], {}, [instance.__class__] + for c in classlist: + for b in c.__bases__: + classlist.append(b) + for name in c.__dict__.keys(): + if not namedict.has_key(name): + namelist.append(name) + namedict[name] = 1 + return namelist + +class GenericScanner: + def __init__(self, flags=0): + pattern = self.reflect() + self.re = re.compile(pattern, re.VERBOSE|flags) + + self.index2func = {} + for name, number in self.re.groupindex.items(): + self.index2func[number-1] = getattr(self, 't_' + name) + + def makeRE(self, name): + doc = getattr(self, name).__doc__ + rv = '(?P<%s>%s)' % (name[2:], doc) + return rv + + def reflect(self): + rv = [] + for name in _namelist(self): + if name[:2] == 't_' and name != 't_default': + rv.append(self.makeRE(name)) + + rv.append(self.makeRE('t_default')) + return string.join(rv, '|') + + def error(self, s, pos): + print "Lexical error at position %s" % pos + raise SystemExit + + def tokenize(self, s): + pos = 0 + n = len(s) + while pos < n: + m = self.re.match(s, pos) + if m is None: + self.error(s, pos) + + groups = m.groups() + for i in range(len(groups)): + if groups[i] and self.index2func.has_key(i): + self.index2func[i](groups[i]) + pos = m.end() + + def t_default(self, s): + r'( . | \n )+' + print "Specification error: unmatched input" + raise SystemExit + +# +# Extracted from GenericParser and made global so that [un]picking works. +# +class _State: + def __init__(self, stateno, items): + self.T, self.complete, self.items = [], [], items + self.stateno = stateno + +class GenericParser: + # + # An Earley parser, as per J. Earley, "An Efficient Context-Free + # Parsing Algorithm", CACM 13(2), pp. 94-102. Also J. C. Earley, + # "An Efficient Context-Free Parsing Algorithm", Ph.D. thesis, + # Carnegie-Mellon University, August 1968. New formulation of + # the parser according to J. Aycock, "Practical Earley Parsing + # and the SPARK Toolkit", Ph.D. thesis, University of Victoria, + # 2001, and J. Aycock and R. N. Horspool, "Practical Earley + # Parsing", unpublished paper, 2001. + # + + def __init__(self, start): + self.rules = {} + self.rule2func = {} + self.rule2name = {} + self.collectRules() + self.augment(start) + self.ruleschanged = 1 + + _NULLABLE = '\e_' + _START = 'START' + _BOF = '|-' + + # + # When pickling, take the time to generate the full state machine; + # some information is then extraneous, too. Unfortunately we + # can't save the rule2func map. + # + def __getstate__(self): + if self.ruleschanged: + # + # XXX - duplicated from parse() + # + self.computeNull() + self.newrules = {} + self.new2old = {} + self.makeNewRules() + self.ruleschanged = 0 + self.edges, self.cores = {}, {} + self.states = { 0: self.makeState0() } + self.makeState(0, self._BOF) + # + # XXX - should find a better way to do this.. + # + changes = 1 + while changes: + changes = 0 + for k, v in self.edges.items(): + if v is None: + state, sym = k + if self.states.has_key(state): + self.goto(state, sym) + changes = 1 + rv = self.__dict__.copy() + for s in self.states.values(): + del s.items + del rv['rule2func'] + del rv['nullable'] + del rv['cores'] + return rv + + def __setstate__(self, D): + self.rules = {} + self.rule2func = {} + self.rule2name = {} + self.collectRules() + start = D['rules'][self._START][0][1][1] # Blech. + self.augment(start) + D['rule2func'] = self.rule2func + D['makeSet'] = self.makeSet_fast + self.__dict__ = D + + # + # A hook for GenericASTBuilder and GenericASTMatcher. Mess + # thee not with this; nor shall thee toucheth the _preprocess + # argument to addRule. + # + def preprocess(self, rule, func): return rule, func + + def addRule(self, doc, func, _preprocess=1): + fn = func + rules = string.split(doc) + + index = [] + for i in range(len(rules)): + if rules[i] == '::=': + index.append(i-1) + index.append(len(rules)) + + for i in range(len(index)-1): + lhs = rules[index[i]] + rhs = rules[index[i]+2:index[i+1]] + rule = (lhs, tuple(rhs)) + + if _preprocess: + rule, fn = self.preprocess(rule, func) + + if self.rules.has_key(lhs): + self.rules[lhs].append(rule) + else: + self.rules[lhs] = [ rule ] + self.rule2func[rule] = fn + self.rule2name[rule] = func.__name__[2:] + self.ruleschanged = 1 + + def collectRules(self): + for name in _namelist(self): + if name[:2] == 'p_': + func = getattr(self, name) + doc = func.__doc__ + self.addRule(doc, func) + + def augment(self, start): + rule = '%s ::= %s %s' % (self._START, self._BOF, start) + self.addRule(rule, lambda args: args[1], 0) + + def computeNull(self): + self.nullable = {} + tbd = [] + + for rulelist in self.rules.values(): + lhs = rulelist[0][0] + self.nullable[lhs] = 0 + for rule in rulelist: + rhs = rule[1] + if len(rhs) == 0: + self.nullable[lhs] = 1 + continue + # + # We only need to consider rules which + # consist entirely of nonterminal symbols. + # This should be a savings on typical + # grammars. + # + for sym in rhs: + if not self.rules.has_key(sym): + break + else: + tbd.append(rule) + changes = 1 + while changes: + changes = 0 + for lhs, rhs in tbd: + if self.nullable[lhs]: + continue + for sym in rhs: + if not self.nullable[sym]: + break + else: + self.nullable[lhs] = 1 + changes = 1 + + def makeState0(self): + s0 = _State(0, []) + for rule in self.newrules[self._START]: + s0.items.append((rule, 0)) + return s0 + + def finalState(self, tokens): + # + # Yuck. + # + if len(self.newrules[self._START]) == 2 and len(tokens) == 0: + return 1 + start = self.rules[self._START][0][1][1] + return self.goto(1, start) + + def makeNewRules(self): + worklist = [] + for rulelist in self.rules.values(): + for rule in rulelist: + worklist.append((rule, 0, 1, rule)) + + for rule, i, candidate, oldrule in worklist: + lhs, rhs = rule + n = len(rhs) + while i < n: + sym = rhs[i] + if not self.rules.has_key(sym) or \ + not self.nullable[sym]: + candidate = 0 + i = i + 1 + continue + + newrhs = list(rhs) + newrhs[i] = self._NULLABLE+sym + newrule = (lhs, tuple(newrhs)) + worklist.append((newrule, i+1, + candidate, oldrule)) + candidate = 0 + i = i + 1 + else: + if candidate: + lhs = self._NULLABLE+lhs + rule = (lhs, rhs) + if self.newrules.has_key(lhs): + self.newrules[lhs].append(rule) + else: + self.newrules[lhs] = [ rule ] + self.new2old[rule] = oldrule + + def typestring(self, token): + return None + + def error(self, token): + print "Syntax error at or near `%s' token" % token + raise SystemExit + + def parse(self, tokens): + sets = [ [(1,0), (2,0)] ] + self.links = {} + + if self.ruleschanged: + self.computeNull() + self.newrules = {} + self.new2old = {} + self.makeNewRules() + self.ruleschanged = 0 + self.edges, self.cores = {}, {} + self.states = { 0: self.makeState0() } + self.makeState(0, self._BOF) + + for i in xrange(len(tokens)): + sets.append([]) + + if sets[i] == []: + break + self.makeSet(tokens[i], sets, i) + else: + sets.append([]) + self.makeSet(None, sets, len(tokens)) + + #_dump(tokens, sets, self.states) + + finalitem = (self.finalState(tokens), 0) + if finalitem not in sets[-2]: + if len(tokens) > 0: + self.error(tokens[i-1]) + else: + self.error(None) + + return self.buildTree(self._START, finalitem, + tokens, len(sets)-2) + + def isnullable(self, sym): + # + # For symbols in G_e only. If we weren't supporting 1.5, + # could just use sym.startswith(). + # + return self._NULLABLE == sym[0:len(self._NULLABLE)] + + def skip(self, (lhs, rhs), pos=0): + n = len(rhs) + while pos < n: + if not self.isnullable(rhs[pos]): + break + pos = pos + 1 + return pos + + def makeState(self, state, sym): + assert sym is not None + # + # Compute \epsilon-kernel state's core and see if + # it exists already. + # + kitems = [] + for rule, pos in self.states[state].items: + lhs, rhs = rule + if rhs[pos:pos+1] == (sym,): + kitems.append((rule, self.skip(rule, pos+1))) + core = kitems + + core.sort() + tcore = tuple(core) + if self.cores.has_key(tcore): + return self.cores[tcore] + # + # Nope, doesn't exist. Compute it and the associated + # \epsilon-nonkernel state together; we'll need it right away. + # + k = self.cores[tcore] = len(self.states) + K, NK = _State(k, kitems), _State(k+1, []) + self.states[k] = K + predicted = {} + + edges = self.edges + rules = self.newrules + for X in K, NK: + worklist = X.items + for item in worklist: + rule, pos = item + lhs, rhs = rule + if pos == len(rhs): + X.complete.append(rule) + continue + + nextSym = rhs[pos] + key = (X.stateno, nextSym) + if not rules.has_key(nextSym): + if not edges.has_key(key): + edges[key] = None + X.T.append(nextSym) + else: + edges[key] = None + if not predicted.has_key(nextSym): + predicted[nextSym] = 1 + for prule in rules[nextSym]: + ppos = self.skip(prule) + new = (prule, ppos) + NK.items.append(new) + # + # Problem: we know K needs generating, but we + # don't yet know about NK. Can't commit anything + # regarding NK to self.edges until we're sure. Should + # we delay committing on both K and NK to avoid this + # hacky code? This creates other problems.. + # + if X is K: + edges = {} + + if NK.items == []: + return k + + # + # Check for \epsilon-nonkernel's core. Unfortunately we + # need to know the entire set of predicted nonterminals + # to do this without accidentally duplicating states. + # + core = predicted.keys() + core.sort() + tcore = tuple(core) + if self.cores.has_key(tcore): + self.edges[(k, None)] = self.cores[tcore] + return k + + nk = self.cores[tcore] = self.edges[(k, None)] = NK.stateno + self.edges.update(edges) + self.states[nk] = NK + return k + + def goto(self, state, sym): + key = (state, sym) + if not self.edges.has_key(key): + # + # No transitions from state on sym. + # + return None + + rv = self.edges[key] + if rv is None: + # + # Target state isn't generated yet. Remedy this. + # + rv = self.makeState(state, sym) + self.edges[key] = rv + return rv + + def gotoT(self, state, t): + return [self.goto(state, t)] + + def gotoST(self, state, st): + rv = [] + for t in self.states[state].T: + if st == t: + rv.append(self.goto(state, t)) + return rv + + def add(self, set, item, i=None, predecessor=None, causal=None): + if predecessor is None: + if item not in set: + set.append(item) + else: + key = (item, i) + if item not in set: + self.links[key] = [] + set.append(item) + self.links[key].append((predecessor, causal)) + + def makeSet(self, token, sets, i): + cur, next = sets[i], sets[i+1] + + ttype = token is not None and self.typestring(token) or None + if ttype is not None: + fn, arg = self.gotoT, ttype + else: + fn, arg = self.gotoST, token + + for item in cur: + ptr = (item, i) + state, parent = item + add = fn(state, arg) + for k in add: + if k is not None: + self.add(next, (k, parent), i+1, ptr) + nk = self.goto(k, None) + if nk is not None: + self.add(next, (nk, i+1)) + + if parent == i: + continue + + for rule in self.states[state].complete: + lhs, rhs = rule + for pitem in sets[parent]: + pstate, pparent = pitem + k = self.goto(pstate, lhs) + if k is not None: + why = (item, i, rule) + pptr = (pitem, parent) + self.add(cur, (k, pparent), + i, pptr, why) + nk = self.goto(k, None) + if nk is not None: + self.add(cur, (nk, i)) + + def makeSet_fast(self, token, sets, i): + # + # Call *only* when the entire state machine has been built! + # It relies on self.edges being filled in completely, and + # then duplicates and inlines code to boost speed at the + # cost of extreme ugliness. + # + cur, next = sets[i], sets[i+1] + ttype = token is not None and self.typestring(token) or None + + for item in cur: + ptr = (item, i) + state, parent = item + if ttype is not None: + k = self.edges.get((state, ttype), None) + if k is not None: + #self.add(next, (k, parent), i+1, ptr) + #INLINED --v + new = (k, parent) + key = (new, i+1) + if new not in next: + self.links[key] = [] + next.append(new) + self.links[key].append((ptr, None)) + #INLINED --^ + #nk = self.goto(k, None) + nk = self.edges.get((k, None), None) + if nk is not None: + #self.add(next, (nk, i+1)) + #INLINED --v + new = (nk, i+1) + if new not in next: + next.append(new) + #INLINED --^ + else: + add = self.gotoST(state, token) + for k in add: + if k is not None: + self.add(next, (k, parent), i+1, ptr) + #nk = self.goto(k, None) + nk = self.edges.get((k, None), None) + if nk is not None: + self.add(next, (nk, i+1)) + + if parent == i: + continue + + for rule in self.states[state].complete: + lhs, rhs = rule + for pitem in sets[parent]: + pstate, pparent = pitem + #k = self.goto(pstate, lhs) + k = self.edges.get((pstate, lhs), None) + if k is not None: + why = (item, i, rule) + pptr = (pitem, parent) + #self.add(cur, (k, pparent), + # i, pptr, why) + #INLINED --v + new = (k, pparent) + key = (new, i) + if new not in cur: + self.links[key] = [] + cur.append(new) + self.links[key].append((pptr, why)) + #INLINED --^ + #nk = self.goto(k, None) + nk = self.edges.get((k, None), None) + if nk is not None: + #self.add(cur, (nk, i)) + #INLINED --v + new = (nk, i) + if new not in cur: + cur.append(new) + #INLINED --^ + + def predecessor(self, key, causal): + for p, c in self.links[key]: + if c == causal: + return p + assert 0 + + def causal(self, key): + links = self.links[key] + if len(links) == 1: + return links[0][1] + choices = [] + rule2cause = {} + for p, c in links: + rule = c[2] + choices.append(rule) + rule2cause[rule] = c + return rule2cause[self.ambiguity(choices)] + + def deriveEpsilon(self, nt): + if len(self.newrules[nt]) > 1: + rule = self.ambiguity(self.newrules[nt]) + else: + rule = self.newrules[nt][0] + #print rule + + rhs = rule[1] + attr = [None] * len(rhs) + + for i in range(len(rhs)-1, -1, -1): + attr[i] = self.deriveEpsilon(rhs[i]) + return self.rule2func[self.new2old[rule]](attr) + + def buildTree(self, nt, item, tokens, k): + state, parent = item + + choices = [] + for rule in self.states[state].complete: + if rule[0] == nt: + choices.append(rule) + rule = choices[0] + if len(choices) > 1: + rule = self.ambiguity(choices) + #print rule + + rhs = rule[1] + attr = [None] * len(rhs) + + for i in range(len(rhs)-1, -1, -1): + sym = rhs[i] + if not self.newrules.has_key(sym): + if sym != self._BOF: + attr[i] = tokens[k-1] + key = (item, k) + item, k = self.predecessor(key, None) + #elif self.isnullable(sym): + elif self._NULLABLE == sym[0:len(self._NULLABLE)]: + attr[i] = self.deriveEpsilon(sym) + else: + key = (item, k) + why = self.causal(key) + attr[i] = self.buildTree(sym, why[0], + tokens, why[1]) + item, k = self.predecessor(key, why) + return self.rule2func[self.new2old[rule]](attr) + + def ambiguity(self, rules): + # + # XXX - problem here and in collectRules() if the same rule + # appears in >1 method. Also undefined results if rules + # causing the ambiguity appear in the same method. + # + sortlist = [] + name2index = {} + for i in range(len(rules)): + lhs, rhs = rule = rules[i] + name = self.rule2name[self.new2old[rule]] + sortlist.append((len(rhs), name)) + name2index[name] = i + sortlist.sort() + list = map(lambda (a,b): b, sortlist) + return rules[name2index[self.resolve(list)]] + + def resolve(self, list): + # + # Resolve ambiguity in favor of the shortest RHS. + # Since we walk the tree from the top down, this + # should effectively resolve in favor of a "shift". + # + return list[0] + +# +# GenericASTBuilder automagically constructs a concrete/abstract syntax tree +# for a given input. The extra argument is a class (not an instance!) +# which supports the "__setslice__" and "__len__" methods. +# +# XXX - silently overrides any user code in methods. +# + +class GenericASTBuilder(GenericParser): + def __init__(self, AST, start): + GenericParser.__init__(self, start) + self.AST = AST + + def preprocess(self, rule, func): + rebind = lambda lhs, self=self: \ + lambda args, lhs=lhs, self=self: \ + self.buildASTNode(args, lhs) + lhs, rhs = rule + return rule, rebind(lhs) + + def buildASTNode(self, args, lhs): + children = [] + for arg in args: + if isinstance(arg, self.AST): + children.append(arg) + else: + children.append(self.terminal(arg)) + return self.nonterminal(lhs, children) + + def terminal(self, token): return token + + def nonterminal(self, type, args): + rv = self.AST(type) + rv[:len(args)] = args + return rv + +# +# GenericASTTraversal is a Visitor pattern according to Design Patterns. For +# each node it attempts to invoke the method n_<node type>, falling +# back onto the default() method if the n_* can't be found. The preorder +# traversal also looks for an exit hook named n_<node type>_exit (no default +# routine is called if it's not found). To prematurely halt traversal +# of a subtree, call the prune() method -- this only makes sense for a +# preorder traversal. Node type is determined via the typestring() method. +# + +class GenericASTTraversalPruningException: + pass + +class GenericASTTraversal: + def __init__(self, ast): + self.ast = ast + + def typestring(self, node): + return node.type + + def prune(self): + raise GenericASTTraversalPruningException + + def preorder(self, node=None): + if node is None: + node = self.ast + + try: + name = 'n_' + self.typestring(node) + if hasattr(self, name): + func = getattr(self, name) + func(node) + else: + self.default(node) + except GenericASTTraversalPruningException: + return + + for kid in node: + self.preorder(kid) + + name = name + '_exit' + if hasattr(self, name): + func = getattr(self, name) + func(node) + + def postorder(self, node=None): + if node is None: + node = self.ast + + for kid in node: + self.postorder(kid) + + name = 'n_' + self.typestring(node) + if hasattr(self, name): + func = getattr(self, name) + func(node) + else: + self.default(node) + + + def default(self, node): + pass + +# +# GenericASTMatcher. AST nodes must have "__getitem__" and "__cmp__" +# implemented. +# +# XXX - makes assumptions about how GenericParser walks the parse tree. +# + +class GenericASTMatcher(GenericParser): + def __init__(self, start, ast): + GenericParser.__init__(self, start) + self.ast = ast + + def preprocess(self, rule, func): + rebind = lambda func, self=self: \ + lambda args, func=func, self=self: \ + self.foundMatch(args, func) + lhs, rhs = rule + rhslist = list(rhs) + rhslist.reverse() + + return (lhs, tuple(rhslist)), rebind(func) + + def foundMatch(self, args, func): + func(args[-1]) + return args[-1] + + def match_r(self, node): + self.input.insert(0, node) + children = 0 + + for child in node: + if children == 0: + self.input.insert(0, '(') + children = children + 1 + self.match_r(child) + + if children > 0: + self.input.insert(0, ')') + + def match(self, ast=None): + if ast is None: + ast = self.ast + self.input = [] + + self.match_r(ast) + self.parse(self.input) + + def resolve(self, list): + # + # Resolve ambiguity in favor of the longest RHS. + # + return list[-1] + +def _dump(tokens, sets, states): + for i in range(len(sets)): + print 'set', i + for item in sets[i]: + print '\t', item + for (lhs, rhs), pos in states[item[0]].items: + print '\t\t', lhs, '::=', + print string.join(rhs[:pos]), + print '.', + print string.join(rhs[pos:]) + if i < len(tokens): + print + print 'token', str(tokens[i]) + print diff --git a/sys/src/cmd/python/Parser/tokenizer.c b/sys/src/cmd/python/Parser/tokenizer.c new file mode 100644 index 000000000..c58b6899b --- /dev/null +++ b/sys/src/cmd/python/Parser/tokenizer.c @@ -0,0 +1,1535 @@ + +/* Tokenizer implementation */ + +#include "Python.h" +#include "pgenheaders.h" + +#include <ctype.h> +#include <assert.h> + +#include "tokenizer.h" +#include "errcode.h" + +#ifndef PGEN +#include "unicodeobject.h" +#include "stringobject.h" +#include "fileobject.h" +#include "codecs.h" +#include "abstract.h" +#endif /* PGEN */ + +extern char *PyOS_Readline(FILE *, FILE *, char *); +/* Return malloc'ed string including trailing \n; + empty malloc'ed string for EOF; + NULL if interrupted */ + +/* Don't ever change this -- it would break the portability of Python code */ +#define TABSIZE 8 + +/* Convert a possibly signed character to a nonnegative int */ +/* XXX This assumes characters are 8 bits wide */ +#ifdef __CHAR_UNSIGNED__ +#define Py_CHARMASK(c) (c) +#else +#define Py_CHARMASK(c) ((c) & 0xff) +#endif + +/* Forward */ +static struct tok_state *tok_new(void); +static int tok_nextc(struct tok_state *tok); +static void tok_backup(struct tok_state *tok, int c); + +/* Token names */ + +char *_PyParser_TokenNames[] = { + "ENDMARKER", + "NAME", + "NUMBER", + "STRING", + "NEWLINE", + "INDENT", + "DEDENT", + "LPAR", + "RPAR", + "LSQB", + "RSQB", + "COLON", + "COMMA", + "SEMI", + "PLUS", + "MINUS", + "STAR", + "SLASH", + "VBAR", + "AMPER", + "LESS", + "GREATER", + "EQUAL", + "DOT", + "PERCENT", + "BACKQUOTE", + "LBRACE", + "RBRACE", + "EQEQUAL", + "NOTEQUAL", + "LESSEQUAL", + "GREATEREQUAL", + "TILDE", + "CIRCUMFLEX", + "LEFTSHIFT", + "RIGHTSHIFT", + "DOUBLESTAR", + "PLUSEQUAL", + "MINEQUAL", + "STAREQUAL", + "SLASHEQUAL", + "PERCENTEQUAL", + "AMPEREQUAL", + "VBAREQUAL", + "CIRCUMFLEXEQUAL", + "LEFTSHIFTEQUAL", + "RIGHTSHIFTEQUAL", + "DOUBLESTAREQUAL", + "DOUBLESLASH", + "DOUBLESLASHEQUAL", + "AT", + /* This table must match the #defines in token.h! */ + "OP", + "<ERRORTOKEN>", + "<N_TOKENS>" +}; + + +/* Create and initialize a new tok_state structure */ + +static struct tok_state * +tok_new(void) +{ + struct tok_state *tok = (struct tok_state *)PyMem_MALLOC( + sizeof(struct tok_state)); + if (tok == NULL) + return NULL; + tok->buf = tok->cur = tok->end = tok->inp = tok->start = NULL; + tok->done = E_OK; + tok->fp = NULL; + tok->tabsize = TABSIZE; + tok->indent = 0; + tok->indstack[0] = 0; + tok->atbol = 1; + tok->pendin = 0; + tok->prompt = tok->nextprompt = NULL; + tok->lineno = 0; + tok->level = 0; + tok->filename = NULL; + tok->altwarning = 0; + tok->alterror = 0; + tok->alttabsize = 1; + tok->altindstack[0] = 0; + tok->decoding_state = 0; + tok->decoding_erred = 0; + tok->read_coding_spec = 0; + tok->encoding = NULL; + tok->cont_line = 0; +#ifndef PGEN + tok->decoding_readline = NULL; + tok->decoding_buffer = NULL; +#endif + return tok; +} + +#ifdef PGEN + +static char * +decoding_fgets(char *s, int size, struct tok_state *tok) +{ + return fgets(s, size, tok->fp); +} + +static int +decoding_feof(struct tok_state *tok) +{ + return feof(tok->fp); +} + +static const char * +decode_str(const char *str, struct tok_state *tok) +{ + return str; +} + +#else /* PGEN */ + +static char * +error_ret(struct tok_state *tok) /* XXX */ +{ + tok->decoding_erred = 1; + if (tok->fp != NULL && tok->buf != NULL) /* see PyTokenizer_Free */ + PyMem_FREE(tok->buf); + tok->buf = NULL; + return NULL; /* as if it were EOF */ +} + +static char * +new_string(const char *s, Py_ssize_t len) +{ + char* result = (char *)PyMem_MALLOC(len + 1); + if (result != NULL) { + memcpy(result, s, len); + result[len] = '\0'; + } + return result; +} + +static char * +get_normal_name(char *s) /* for utf-8 and latin-1 */ +{ + char buf[13]; + int i; + for (i = 0; i < 12; i++) { + int c = s[i]; + if (c == '\0') break; + else if (c == '_') buf[i] = '-'; + else buf[i] = tolower(c); + } + buf[i] = '\0'; + if (strcmp(buf, "utf-8") == 0 || + strncmp(buf, "utf-8-", 6) == 0) return "utf-8"; + else if (strcmp(buf, "latin-1") == 0 || + strcmp(buf, "iso-8859-1") == 0 || + strcmp(buf, "iso-latin-1") == 0 || + strncmp(buf, "latin-1-", 8) == 0 || + strncmp(buf, "iso-8859-1-", 11) == 0 || + strncmp(buf, "iso-latin-1-", 12) == 0) return "iso-8859-1"; + else return s; +} + +/* Return the coding spec in S, or NULL if none is found. */ + +static char * +get_coding_spec(const char *s, Py_ssize_t size) +{ + Py_ssize_t i; + /* Coding spec must be in a comment, and that comment must be + * the only statement on the source code line. */ + for (i = 0; i < size - 6; i++) { + if (s[i] == '#') + break; + if (s[i] != ' ' && s[i] != '\t' && s[i] != '\014') + return NULL; + } + for (; i < size - 6; i++) { /* XXX inefficient search */ + const char* t = s + i; + if (strncmp(t, "coding", 6) == 0) { + const char* begin = NULL; + t += 6; + if (t[0] != ':' && t[0] != '=') + continue; + do { + t++; + } while (t[0] == '\x20' || t[0] == '\t'); + + begin = t; + while (isalnum(Py_CHARMASK(t[0])) || + t[0] == '-' || t[0] == '_' || t[0] == '.') + t++; + + if (begin < t) { + char* r = new_string(begin, t - begin); + char* q = get_normal_name(r); + if (r != q) { + PyMem_FREE(r); + r = new_string(q, strlen(q)); + } + return r; + } + } + } + return NULL; +} + +/* Check whether the line contains a coding spec. If it does, + invoke the set_readline function for the new encoding. + This function receives the tok_state and the new encoding. + Return 1 on success, 0 on failure. */ + +static int +check_coding_spec(const char* line, Py_ssize_t size, struct tok_state *tok, + int set_readline(struct tok_state *, const char *)) +{ + char * cs; + int r = 1; + + if (tok->cont_line) + /* It's a continuation line, so it can't be a coding spec. */ + return 1; + cs = get_coding_spec(line, size); + if (cs != NULL) { + tok->read_coding_spec = 1; + if (tok->encoding == NULL) { + assert(tok->decoding_state == 1); /* raw */ + if (strcmp(cs, "utf-8") == 0 || + strcmp(cs, "iso-8859-1") == 0) { + tok->encoding = cs; + } else { +#ifdef Py_USING_UNICODE + r = set_readline(tok, cs); + if (r) { + tok->encoding = cs; + tok->decoding_state = -1; + } + else + PyMem_FREE(cs); +#else + /* Without Unicode support, we cannot + process the coding spec. Since there + won't be any Unicode literals, that + won't matter. */ + PyMem_FREE(cs); +#endif + } + } else { /* then, compare cs with BOM */ + r = (strcmp(tok->encoding, cs) == 0); + PyMem_FREE(cs); + } + } + if (!r) { + cs = tok->encoding; + if (!cs) + cs = "with BOM"; + PyErr_Format(PyExc_SyntaxError, "encoding problem: %s", cs); + } + return r; +} + +/* See whether the file starts with a BOM. If it does, + invoke the set_readline function with the new encoding. + Return 1 on success, 0 on failure. */ + +static int +check_bom(int get_char(struct tok_state *), + void unget_char(int, struct tok_state *), + int set_readline(struct tok_state *, const char *), + struct tok_state *tok) +{ + int ch = get_char(tok); + tok->decoding_state = 1; + if (ch == EOF) { + return 1; + } else if (ch == 0xEF) { + ch = get_char(tok); if (ch != 0xBB) goto NON_BOM; + ch = get_char(tok); if (ch != 0xBF) goto NON_BOM; +#if 0 + /* Disable support for UTF-16 BOMs until a decision + is made whether this needs to be supported. */ + } else if (ch == 0xFE) { + ch = get_char(tok); if (ch != 0xFF) goto NON_BOM; + if (!set_readline(tok, "utf-16-be")) return 0; + tok->decoding_state = -1; + } else if (ch == 0xFF) { + ch = get_char(tok); if (ch != 0xFE) goto NON_BOM; + if (!set_readline(tok, "utf-16-le")) return 0; + tok->decoding_state = -1; +#endif + } else { + unget_char(ch, tok); + return 1; + } + if (tok->encoding != NULL) + PyMem_FREE(tok->encoding); + tok->encoding = new_string("utf-8", 5); /* resulting is in utf-8 */ + return 1; + NON_BOM: + /* any token beginning with '\xEF', '\xFE', '\xFF' is a bad token */ + unget_char(0xFF, tok); /* XXX this will cause a syntax error */ + return 1; +} + +/* Read a line of text from TOK into S, using the stream in TOK. + Return NULL on failure, else S. + + On entry, tok->decoding_buffer will be one of: + 1) NULL: need to call tok->decoding_readline to get a new line + 2) PyUnicodeObject *: decoding_feof has called tok->decoding_readline and + stored the result in tok->decoding_buffer + 3) PyStringObject *: previous call to fp_readl did not have enough room + (in the s buffer) to copy entire contents of the line read + by tok->decoding_readline. tok->decoding_buffer has the overflow. + In this case, fp_readl is called in a loop (with an expanded buffer) + until the buffer ends with a '\n' (or until the end of the file is + reached): see tok_nextc and its calls to decoding_fgets. +*/ + +static char * +fp_readl(char *s, int size, struct tok_state *tok) +{ +#ifndef Py_USING_UNICODE + /* In a non-Unicode built, this should never be called. */ + Py_FatalError("fp_readl should not be called in this build."); + return NULL; /* Keep compiler happy (not reachable) */ +#else + PyObject* utf8 = NULL; + PyObject* buf = tok->decoding_buffer; + char *str; + Py_ssize_t utf8len; + + /* Ask for one less byte so we can terminate it */ + assert(size > 0); + size--; + + if (buf == NULL) { + buf = PyObject_CallObject(tok->decoding_readline, NULL); + if (buf == NULL) + return error_ret(tok); + } else { + tok->decoding_buffer = NULL; + if (PyString_CheckExact(buf)) + utf8 = buf; + } + if (utf8 == NULL) { + utf8 = PyUnicode_AsUTF8String(buf); + Py_DECREF(buf); + if (utf8 == NULL) + return error_ret(tok); + } + str = PyString_AsString(utf8); + utf8len = PyString_GET_SIZE(utf8); + if (utf8len > size) { + tok->decoding_buffer = PyString_FromStringAndSize(str+size, utf8len-size); + if (tok->decoding_buffer == NULL) { + Py_DECREF(utf8); + return error_ret(tok); + } + utf8len = size; + } + memcpy(s, str, utf8len); + s[utf8len] = '\0'; + Py_DECREF(utf8); + if (utf8len == 0) return NULL; /* EOF */ + return s; +#endif +} + +/* Set the readline function for TOK to a StreamReader's + readline function. The StreamReader is named ENC. + + This function is called from check_bom and check_coding_spec. + + ENC is usually identical to the future value of tok->encoding, + except for the (currently unsupported) case of UTF-16. + + Return 1 on success, 0 on failure. */ + +static int +fp_setreadl(struct tok_state *tok, const char* enc) +{ + PyObject *reader, *stream, *readline; + + /* XXX: constify filename argument. */ + stream = PyFile_FromFile(tok->fp, (char*)tok->filename, "rb", NULL); + if (stream == NULL) + return 0; + + reader = PyCodec_StreamReader(enc, stream, NULL); + Py_DECREF(stream); + if (reader == NULL) + return 0; + + readline = PyObject_GetAttrString(reader, "readline"); + Py_DECREF(reader); + if (readline == NULL) + return 0; + + tok->decoding_readline = readline; + return 1; +} + +/* Fetch the next byte from TOK. */ + +static int fp_getc(struct tok_state *tok) { + return getc(tok->fp); +} + +/* Unfetch the last byte back into TOK. */ + +static void fp_ungetc(int c, struct tok_state *tok) { + ungetc(c, tok->fp); +} + +/* Read a line of input from TOK. Determine encoding + if necessary. */ + +static char * +decoding_fgets(char *s, int size, struct tok_state *tok) +{ + char *line = NULL; + int badchar = 0; + for (;;) { + if (tok->decoding_state < 0) { + /* We already have a codec associated with + this input. */ + line = fp_readl(s, size, tok); + break; + } else if (tok->decoding_state > 0) { + /* We want a 'raw' read. */ + line = Py_UniversalNewlineFgets(s, size, + tok->fp, NULL); + break; + } else { + /* We have not yet determined the encoding. + If an encoding is found, use the file-pointer + reader functions from now on. */ + if (!check_bom(fp_getc, fp_ungetc, fp_setreadl, tok)) + return error_ret(tok); + assert(tok->decoding_state != 0); + } + } + if (line != NULL && tok->lineno < 2 && !tok->read_coding_spec) { + if (!check_coding_spec(line, strlen(line), tok, fp_setreadl)) { + return error_ret(tok); + } + } +#ifndef PGEN + /* The default encoding is ASCII, so make sure we don't have any + non-ASCII bytes in it. */ + if (line && !tok->encoding) { + unsigned char *c; + for (c = (unsigned char *)line; *c; c++) + if (*c > 127) { + badchar = *c; + break; + } + } + if (badchar) { + char buf[500]; + /* Need to add 1 to the line number, since this line + has not been counted, yet. */ + sprintf(buf, + "Non-ASCII character '\\x%.2x' " + "in file %.200s on line %i, " + "but no encoding declared; " + "see http://www.python.org/peps/pep-0263.html for details", + badchar, tok->filename, tok->lineno + 1); + PyErr_SetString(PyExc_SyntaxError, buf); + return error_ret(tok); + } +#endif + return line; +} + +static int +decoding_feof(struct tok_state *tok) +{ + if (tok->decoding_state >= 0) { + return feof(tok->fp); + } else { + PyObject* buf = tok->decoding_buffer; + if (buf == NULL) { + buf = PyObject_CallObject(tok->decoding_readline, NULL); + if (buf == NULL) { + error_ret(tok); + return 1; + } else { + tok->decoding_buffer = buf; + } + } + return PyObject_Length(buf) == 0; + } +} + +/* Fetch a byte from TOK, using the string buffer. */ + +static int +buf_getc(struct tok_state *tok) { + return Py_CHARMASK(*tok->str++); +} + +/* Unfetch a byte from TOK, using the string buffer. */ + +static void +buf_ungetc(int c, struct tok_state *tok) { + tok->str--; + assert(Py_CHARMASK(*tok->str) == c); /* tok->cur may point to read-only segment */ +} + +/* Set the readline function for TOK to ENC. For the string-based + tokenizer, this means to just record the encoding. */ + +static int +buf_setreadl(struct tok_state *tok, const char* enc) { + tok->enc = enc; + return 1; +} + +/* Return a UTF-8 encoding Python string object from the + C byte string STR, which is encoded with ENC. */ + +#ifdef Py_USING_UNICODE +static PyObject * +translate_into_utf8(const char* str, const char* enc) { + PyObject *utf8; + PyObject* buf = PyUnicode_Decode(str, strlen(str), enc, NULL); + if (buf == NULL) + return NULL; + utf8 = PyUnicode_AsUTF8String(buf); + Py_DECREF(buf); + return utf8; +} +#endif + +/* Decode a byte string STR for use as the buffer of TOK. + Look for encoding declarations inside STR, and record them + inside TOK. */ + +static const char * +decode_str(const char *str, struct tok_state *tok) +{ + PyObject* utf8 = NULL; + const char *s; + int lineno = 0; + tok->enc = NULL; + tok->str = str; + if (!check_bom(buf_getc, buf_ungetc, buf_setreadl, tok)) + return error_ret(tok); + str = tok->str; /* string after BOM if any */ + assert(str); +#ifdef Py_USING_UNICODE + if (tok->enc != NULL) { + utf8 = translate_into_utf8(str, tok->enc); + if (utf8 == NULL) + return error_ret(tok); + str = PyString_AsString(utf8); + } +#endif + for (s = str;; s++) { + if (*s == '\0') break; + else if (*s == '\n') { + lineno++; + if (lineno == 2) break; + } + } + tok->enc = NULL; + if (!check_coding_spec(str, s - str, tok, buf_setreadl)) + return error_ret(tok); +#ifdef Py_USING_UNICODE + if (tok->enc != NULL) { + assert(utf8 == NULL); + utf8 = translate_into_utf8(str, tok->enc); + if (utf8 == NULL) { + PyErr_Format(PyExc_SyntaxError, + "unknown encoding: %s", tok->enc); + return error_ret(tok); + } + str = PyString_AsString(utf8); + } +#endif + assert(tok->decoding_buffer == NULL); + tok->decoding_buffer = utf8; /* CAUTION */ + return str; +} + +#endif /* PGEN */ + +/* Set up tokenizer for string */ + +struct tok_state * +PyTokenizer_FromString(const char *str) +{ + struct tok_state *tok = tok_new(); + if (tok == NULL) + return NULL; + str = (char *)decode_str(str, tok); + if (str == NULL) { + PyTokenizer_Free(tok); + return NULL; + } + + /* XXX: constify members. */ + tok->buf = tok->cur = tok->end = tok->inp = (char*)str; + return tok; +} + + +/* Set up tokenizer for file */ + +struct tok_state * +PyTokenizer_FromFile(FILE *fp, char *ps1, char *ps2) +{ + struct tok_state *tok = tok_new(); + if (tok == NULL) + return NULL; + if ((tok->buf = (char *)PyMem_MALLOC(BUFSIZ)) == NULL) { + PyTokenizer_Free(tok); + return NULL; + } + tok->cur = tok->inp = tok->buf; + tok->end = tok->buf + BUFSIZ; + tok->fp = fp; + tok->prompt = ps1; + tok->nextprompt = ps2; + return tok; +} + + +/* Free a tok_state structure */ + +void +PyTokenizer_Free(struct tok_state *tok) +{ + if (tok->encoding != NULL) + PyMem_FREE(tok->encoding); +#ifndef PGEN + Py_XDECREF(tok->decoding_readline); + Py_XDECREF(tok->decoding_buffer); +#endif + if (tok->fp != NULL && tok->buf != NULL) + PyMem_FREE(tok->buf); + PyMem_FREE(tok); +} + +#if !defined(PGEN) && defined(Py_USING_UNICODE) +static int +tok_stdin_decode(struct tok_state *tok, char **inp) +{ + PyObject *enc, *sysstdin, *decoded, *utf8; + const char *encoding; + char *converted; + + if (PySys_GetFile((char *)"stdin", NULL) != stdin) + return 0; + sysstdin = PySys_GetObject("stdin"); + if (sysstdin == NULL || !PyFile_Check(sysstdin)) + return 0; + + enc = ((PyFileObject *)sysstdin)->f_encoding; + if (enc == NULL || !PyString_Check(enc)) + return 0; + Py_INCREF(enc); + + encoding = PyString_AsString(enc); + decoded = PyUnicode_Decode(*inp, strlen(*inp), encoding, NULL); + if (decoded == NULL) + goto error_clear; + + utf8 = PyUnicode_AsEncodedString(decoded, "utf-8", NULL); + Py_DECREF(decoded); + if (utf8 == NULL) + goto error_clear; + + assert(PyString_Check(utf8)); + converted = new_string(PyString_AS_STRING(utf8), + PyString_GET_SIZE(utf8)); + Py_DECREF(utf8); + if (converted == NULL) + goto error_nomem; + + PyMem_FREE(*inp); + *inp = converted; + if (tok->encoding != NULL) + PyMem_FREE(tok->encoding); + tok->encoding = new_string(encoding, strlen(encoding)); + if (tok->encoding == NULL) + goto error_nomem; + + Py_DECREF(enc); + return 0; + +error_nomem: + Py_DECREF(enc); + tok->done = E_NOMEM; + return -1; + +error_clear: + /* Fallback to iso-8859-1: for backward compatibility */ + Py_DECREF(enc); + PyErr_Clear(); + return 0; +} +#endif + +/* Get next char, updating state; error code goes into tok->done */ + +static int +tok_nextc(register struct tok_state *tok) +{ + for (;;) { + if (tok->cur != tok->inp) { + return Py_CHARMASK(*tok->cur++); /* Fast path */ + } + if (tok->done != E_OK) + return EOF; + if (tok->fp == NULL) { + char *end = strchr(tok->inp, '\n'); + if (end != NULL) + end++; + else { + end = strchr(tok->inp, '\0'); + if (end == tok->inp) { + tok->done = E_EOF; + return EOF; + } + } + if (tok->start == NULL) + tok->buf = tok->cur; + tok->line_start = tok->cur; + tok->lineno++; + tok->inp = end; + return Py_CHARMASK(*tok->cur++); + } + if (tok->prompt != NULL) { + char *newtok = PyOS_Readline(stdin, stdout, tok->prompt); + if (tok->nextprompt != NULL) + tok->prompt = tok->nextprompt; + if (newtok == NULL) + tok->done = E_INTR; + else if (*newtok == '\0') { + PyMem_FREE(newtok); + tok->done = E_EOF; + } +#if !defined(PGEN) && defined(Py_USING_UNICODE) + else if (tok_stdin_decode(tok, &newtok) != 0) + PyMem_FREE(newtok); +#endif + else if (tok->start != NULL) { + size_t start = tok->start - tok->buf; + size_t oldlen = tok->cur - tok->buf; + size_t newlen = oldlen + strlen(newtok); + char *buf = tok->buf; + buf = (char *)PyMem_REALLOC(buf, newlen+1); + tok->lineno++; + if (buf == NULL) { + PyMem_FREE(tok->buf); + tok->buf = NULL; + PyMem_FREE(newtok); + tok->done = E_NOMEM; + return EOF; + } + tok->buf = buf; + tok->cur = tok->buf + oldlen; + tok->line_start = tok->cur; + strcpy(tok->buf + oldlen, newtok); + PyMem_FREE(newtok); + tok->inp = tok->buf + newlen; + tok->end = tok->inp + 1; + tok->start = tok->buf + start; + } + else { + tok->lineno++; + if (tok->buf != NULL) + PyMem_FREE(tok->buf); + tok->buf = newtok; + tok->line_start = tok->buf; + tok->cur = tok->buf; + tok->line_start = tok->buf; + tok->inp = strchr(tok->buf, '\0'); + tok->end = tok->inp + 1; + } + } + else { + int done = 0; + Py_ssize_t cur = 0; + char *pt; + if (tok->start == NULL) { + if (tok->buf == NULL) { + tok->buf = (char *) + PyMem_MALLOC(BUFSIZ); + if (tok->buf == NULL) { + tok->done = E_NOMEM; + return EOF; + } + tok->end = tok->buf + BUFSIZ; + } + if (decoding_fgets(tok->buf, (int)(tok->end - tok->buf), + tok) == NULL) { + tok->done = E_EOF; + done = 1; + } + else { + tok->done = E_OK; + tok->inp = strchr(tok->buf, '\0'); + done = tok->inp[-1] == '\n'; + } + } + else { + cur = tok->cur - tok->buf; + if (decoding_feof(tok)) { + tok->done = E_EOF; + done = 1; + } + else + tok->done = E_OK; + } + tok->lineno++; + /* Read until '\n' or EOF */ + while (!done) { + Py_ssize_t curstart = tok->start == NULL ? -1 : + tok->start - tok->buf; + Py_ssize_t curvalid = tok->inp - tok->buf; + Py_ssize_t newsize = curvalid + BUFSIZ; + char *newbuf = tok->buf; + newbuf = (char *)PyMem_REALLOC(newbuf, + newsize); + if (newbuf == NULL) { + tok->done = E_NOMEM; + tok->cur = tok->inp; + return EOF; + } + tok->buf = newbuf; + tok->inp = tok->buf + curvalid; + tok->end = tok->buf + newsize; + tok->start = curstart < 0 ? NULL : + tok->buf + curstart; + if (decoding_fgets(tok->inp, + (int)(tok->end - tok->inp), + tok) == NULL) { + /* Break out early on decoding + errors, as tok->buf will be NULL + */ + if (tok->decoding_erred) + return EOF; + /* Last line does not end in \n, + fake one */ + strcpy(tok->inp, "\n"); + } + tok->inp = strchr(tok->inp, '\0'); + done = tok->inp[-1] == '\n'; + } + if (tok->buf != NULL) { + tok->cur = tok->buf + cur; + tok->line_start = tok->cur; + /* replace "\r\n" with "\n" */ + /* For Mac leave the \r, giving syntax error */ + pt = tok->inp - 2; + if (pt >= tok->buf && *pt == '\r') { + *pt++ = '\n'; + *pt = '\0'; + tok->inp = pt; + } + } + } + if (tok->done != E_OK) { + if (tok->prompt != NULL) + PySys_WriteStderr("\n"); + tok->cur = tok->inp; + return EOF; + } + } + /*NOTREACHED*/ +} + + +/* Back-up one character */ + +static void +tok_backup(register struct tok_state *tok, register int c) +{ + if (c != EOF) { + if (--tok->cur < tok->buf) + Py_FatalError("tok_backup: begin of buffer"); + if (*tok->cur != c) + *tok->cur = c; + } +} + + +/* Return the token corresponding to a single character */ + +int +PyToken_OneChar(int c) +{ + switch (c) { + case '(': return LPAR; + case ')': return RPAR; + case '[': return LSQB; + case ']': return RSQB; + case ':': return COLON; + case ',': return COMMA; + case ';': return SEMI; + case '+': return PLUS; + case '-': return MINUS; + case '*': return STAR; + case '/': return SLASH; + case '|': return VBAR; + case '&': return AMPER; + case '<': return LESS; + case '>': return GREATER; + case '=': return EQUAL; + case '.': return DOT; + case '%': return PERCENT; + case '`': return BACKQUOTE; + case '{': return LBRACE; + case '}': return RBRACE; + case '^': return CIRCUMFLEX; + case '~': return TILDE; + case '@': return AT; + default: return OP; + } +} + + +int +PyToken_TwoChars(int c1, int c2) +{ + switch (c1) { + case '=': + switch (c2) { + case '=': return EQEQUAL; + } + break; + case '!': + switch (c2) { + case '=': return NOTEQUAL; + } + break; + case '<': + switch (c2) { + case '>': return NOTEQUAL; + case '=': return LESSEQUAL; + case '<': return LEFTSHIFT; + } + break; + case '>': + switch (c2) { + case '=': return GREATEREQUAL; + case '>': return RIGHTSHIFT; + } + break; + case '+': + switch (c2) { + case '=': return PLUSEQUAL; + } + break; + case '-': + switch (c2) { + case '=': return MINEQUAL; + } + break; + case '*': + switch (c2) { + case '*': return DOUBLESTAR; + case '=': return STAREQUAL; + } + break; + case '/': + switch (c2) { + case '/': return DOUBLESLASH; + case '=': return SLASHEQUAL; + } + break; + case '|': + switch (c2) { + case '=': return VBAREQUAL; + } + break; + case '%': + switch (c2) { + case '=': return PERCENTEQUAL; + } + break; + case '&': + switch (c2) { + case '=': return AMPEREQUAL; + } + break; + case '^': + switch (c2) { + case '=': return CIRCUMFLEXEQUAL; + } + break; + } + return OP; +} + +int +PyToken_ThreeChars(int c1, int c2, int c3) +{ + switch (c1) { + case '<': + switch (c2) { + case '<': + switch (c3) { + case '=': + return LEFTSHIFTEQUAL; + } + break; + } + break; + case '>': + switch (c2) { + case '>': + switch (c3) { + case '=': + return RIGHTSHIFTEQUAL; + } + break; + } + break; + case '*': + switch (c2) { + case '*': + switch (c3) { + case '=': + return DOUBLESTAREQUAL; + } + break; + } + break; + case '/': + switch (c2) { + case '/': + switch (c3) { + case '=': + return DOUBLESLASHEQUAL; + } + break; + } + break; + } + return OP; +} + +static int +indenterror(struct tok_state *tok) +{ + if (tok->alterror) { + tok->done = E_TABSPACE; + tok->cur = tok->inp; + return 1; + } + if (tok->altwarning) { + PySys_WriteStderr("%s: inconsistent use of tabs and spaces " + "in indentation\n", tok->filename); + tok->altwarning = 0; + } + return 0; +} + + +/* Get next token, after space stripping etc. */ + +static int +tok_get(register struct tok_state *tok, char **p_start, char **p_end) +{ + register int c; + int blankline; + + *p_start = *p_end = NULL; + nextline: + tok->start = NULL; + blankline = 0; + + /* Get indentation level */ + if (tok->atbol) { + register int col = 0; + register int altcol = 0; + tok->atbol = 0; + for (;;) { + c = tok_nextc(tok); + if (c == ' ') + col++, altcol++; + else if (c == '\t') { + col = (col/tok->tabsize + 1) * tok->tabsize; + altcol = (altcol/tok->alttabsize + 1) + * tok->alttabsize; + } + else if (c == '\014') /* Control-L (formfeed) */ + col = altcol = 0; /* For Emacs users */ + else + break; + } + tok_backup(tok, c); + if (c == '#' || c == '\n') { + /* Lines with only whitespace and/or comments + shouldn't affect the indentation and are + not passed to the parser as NEWLINE tokens, + except *totally* empty lines in interactive + mode, which signal the end of a command group. */ + if (col == 0 && c == '\n' && tok->prompt != NULL) + blankline = 0; /* Let it through */ + else + blankline = 1; /* Ignore completely */ + /* We can't jump back right here since we still + may need to skip to the end of a comment */ + } + if (!blankline && tok->level == 0) { + if (col == tok->indstack[tok->indent]) { + /* No change */ + if (altcol != tok->altindstack[tok->indent]) { + if (indenterror(tok)) + return ERRORTOKEN; + } + } + else if (col > tok->indstack[tok->indent]) { + /* Indent -- always one */ + if (tok->indent+1 >= MAXINDENT) { + tok->done = E_TOODEEP; + tok->cur = tok->inp; + return ERRORTOKEN; + } + if (altcol <= tok->altindstack[tok->indent]) { + if (indenterror(tok)) + return ERRORTOKEN; + } + tok->pendin++; + tok->indstack[++tok->indent] = col; + tok->altindstack[tok->indent] = altcol; + } + else /* col < tok->indstack[tok->indent] */ { + /* Dedent -- any number, must be consistent */ + while (tok->indent > 0 && + col < tok->indstack[tok->indent]) { + tok->pendin--; + tok->indent--; + } + if (col != tok->indstack[tok->indent]) { + tok->done = E_DEDENT; + tok->cur = tok->inp; + return ERRORTOKEN; + } + if (altcol != tok->altindstack[tok->indent]) { + if (indenterror(tok)) + return ERRORTOKEN; + } + } + } + } + + tok->start = tok->cur; + + /* Return pending indents/dedents */ + if (tok->pendin != 0) { + if (tok->pendin < 0) { + tok->pendin++; + return DEDENT; + } + else { + tok->pendin--; + return INDENT; + } + } + + again: + tok->start = NULL; + /* Skip spaces */ + do { + c = tok_nextc(tok); + } while (c == ' ' || c == '\t' || c == '\014'); + + /* Set start of current token */ + tok->start = tok->cur - 1; + + /* Skip comment, while looking for tab-setting magic */ + if (c == '#') { + static char *tabforms[] = { + "tab-width:", /* Emacs */ + ":tabstop=", /* vim, full form */ + ":ts=", /* vim, abbreviated form */ + "set tabsize=", /* will vi never die? */ + /* more templates can be added here to support other editors */ + }; + char cbuf[80]; + char *tp, **cp; + tp = cbuf; + do { + *tp++ = c = tok_nextc(tok); + } while (c != EOF && c != '\n' && + (size_t)(tp - cbuf + 1) < sizeof(cbuf)); + *tp = '\0'; + for (cp = tabforms; + cp < tabforms + sizeof(tabforms)/sizeof(tabforms[0]); + cp++) { + if ((tp = strstr(cbuf, *cp))) { + int newsize = atoi(tp + strlen(*cp)); + + if (newsize >= 1 && newsize <= 40) { + tok->tabsize = newsize; + if (Py_VerboseFlag) + PySys_WriteStderr( + "Tab size set to %d\n", + newsize); + } + } + } + while (c != EOF && c != '\n') + c = tok_nextc(tok); + } + + /* Check for EOF and errors now */ + if (c == EOF) { + return tok->done == E_EOF ? ENDMARKER : ERRORTOKEN; + } + + /* Identifier (most frequent token!) */ + if (isalpha(c) || c == '_') { + /* Process r"", u"" and ur"" */ + switch (c) { + case 'r': + case 'R': + c = tok_nextc(tok); + if (c == '"' || c == '\'') + goto letter_quote; + break; + case 'u': + case 'U': + c = tok_nextc(tok); + if (c == 'r' || c == 'R') + c = tok_nextc(tok); + if (c == '"' || c == '\'') + goto letter_quote; + break; + } + while (isalnum(c) || c == '_') { + c = tok_nextc(tok); + } + tok_backup(tok, c); + *p_start = tok->start; + *p_end = tok->cur; + return NAME; + } + + /* Newline */ + if (c == '\n') { + tok->atbol = 1; + if (blankline || tok->level > 0) + goto nextline; + *p_start = tok->start; + *p_end = tok->cur - 1; /* Leave '\n' out of the string */ + tok->cont_line = 0; + return NEWLINE; + } + + /* Period or number starting with period? */ + if (c == '.') { + c = tok_nextc(tok); + if (isdigit(c)) { + goto fraction; + } + else { + tok_backup(tok, c); + *p_start = tok->start; + *p_end = tok->cur; + return DOT; + } + } + + /* Number */ + if (isdigit(c)) { + if (c == '0') { + /* Hex or octal -- maybe. */ + c = tok_nextc(tok); + if (c == '.') + goto fraction; +#ifndef WITHOUT_COMPLEX + if (c == 'j' || c == 'J') + goto imaginary; +#endif + if (c == 'x' || c == 'X') { + /* Hex */ + do { + c = tok_nextc(tok); + } while (isxdigit(c)); + } + else { + int found_decimal = 0; + /* Octal; c is first char of it */ + /* There's no 'isoctdigit' macro, sigh */ + while ('0' <= c && c < '8') { + c = tok_nextc(tok); + } + if (isdigit(c)) { + found_decimal = 1; + do { + c = tok_nextc(tok); + } while (isdigit(c)); + } + if (c == '.') + goto fraction; + else if (c == 'e' || c == 'E') + goto exponent; +#ifndef WITHOUT_COMPLEX + else if (c == 'j' || c == 'J') + goto imaginary; +#endif + else if (found_decimal) { + tok->done = E_TOKEN; + tok_backup(tok, c); + return ERRORTOKEN; + } + } + if (c == 'l' || c == 'L') + c = tok_nextc(tok); + } + else { + /* Decimal */ + do { + c = tok_nextc(tok); + } while (isdigit(c)); + if (c == 'l' || c == 'L') + c = tok_nextc(tok); + else { + /* Accept floating point numbers. */ + if (c == '.') { + fraction: + /* Fraction */ + do { + c = tok_nextc(tok); + } while (isdigit(c)); + } + if (c == 'e' || c == 'E') { + exponent: + /* Exponent part */ + c = tok_nextc(tok); + if (c == '+' || c == '-') + c = tok_nextc(tok); + if (!isdigit(c)) { + tok->done = E_TOKEN; + tok_backup(tok, c); + return ERRORTOKEN; + } + do { + c = tok_nextc(tok); + } while (isdigit(c)); + } +#ifndef WITHOUT_COMPLEX + if (c == 'j' || c == 'J') + /* Imaginary part */ + imaginary: + c = tok_nextc(tok); +#endif + } + } + tok_backup(tok, c); + *p_start = tok->start; + *p_end = tok->cur; + return NUMBER; + } + + letter_quote: + /* String */ + if (c == '\'' || c == '"') { + Py_ssize_t quote2 = tok->cur - tok->start + 1; + int quote = c; + int triple = 0; + int tripcount = 0; + for (;;) { + c = tok_nextc(tok); + if (c == '\n') { + if (!triple) { + tok->done = E_EOLS; + tok_backup(tok, c); + return ERRORTOKEN; + } + tripcount = 0; + tok->cont_line = 1; /* multiline string. */ + } + else if (c == EOF) { + if (triple) + tok->done = E_EOFS; + else + tok->done = E_EOLS; + tok->cur = tok->inp; + return ERRORTOKEN; + } + else if (c == quote) { + tripcount++; + if (tok->cur - tok->start == quote2) { + c = tok_nextc(tok); + if (c == quote) { + triple = 1; + tripcount = 0; + continue; + } + tok_backup(tok, c); + } + if (!triple || tripcount == 3) + break; + } + else if (c == '\\') { + tripcount = 0; + c = tok_nextc(tok); + if (c == EOF) { + tok->done = E_EOLS; + tok->cur = tok->inp; + return ERRORTOKEN; + } + } + else + tripcount = 0; + } + *p_start = tok->start; + *p_end = tok->cur; + return STRING; + } + + /* Line continuation */ + if (c == '\\') { + c = tok_nextc(tok); + if (c != '\n') { + tok->done = E_LINECONT; + tok->cur = tok->inp; + return ERRORTOKEN; + } + tok->cont_line = 1; + goto again; /* Read next line */ + } + + /* Check for two-character token */ + { + int c2 = tok_nextc(tok); + int token = PyToken_TwoChars(c, c2); + if (token != OP) { + int c3 = tok_nextc(tok); + int token3 = PyToken_ThreeChars(c, c2, c3); + if (token3 != OP) { + token = token3; + } else { + tok_backup(tok, c3); + } + *p_start = tok->start; + *p_end = tok->cur; + return token; + } + tok_backup(tok, c2); + } + + /* Keep track of parentheses nesting level */ + switch (c) { + case '(': + case '[': + case '{': + tok->level++; + break; + case ')': + case ']': + case '}': + tok->level--; + break; + } + + /* Punctuation character */ + *p_start = tok->start; + *p_end = tok->cur; + return PyToken_OneChar(c); +} + +int +PyTokenizer_Get(struct tok_state *tok, char **p_start, char **p_end) +{ + int result = tok_get(tok, p_start, p_end); + if (tok->decoding_erred) { + result = ERRORTOKEN; + tok->done = E_DECODE; + } + return result; +} + +#ifdef Py_DEBUG + +void +tok_dump(int type, char *start, char *end) +{ + printf("%s", _PyParser_TokenNames[type]); + if (type == NAME || type == NUMBER || type == STRING || type == OP) + printf("(%.*s)", (int)(end - start), start); +} + +#endif diff --git a/sys/src/cmd/python/Parser/tokenizer.h b/sys/src/cmd/python/Parser/tokenizer.h new file mode 100644 index 000000000..5e7ebf74f --- /dev/null +++ b/sys/src/cmd/python/Parser/tokenizer.h @@ -0,0 +1,65 @@ +#ifndef Py_TOKENIZER_H +#define Py_TOKENIZER_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "object.h" + +/* Tokenizer interface */ + +#include "token.h" /* For token types */ + +#define MAXINDENT 100 /* Max indentation level */ + +/* Tokenizer state */ +struct tok_state { + /* Input state; buf <= cur <= inp <= end */ + /* NB an entire line is held in the buffer */ + char *buf; /* Input buffer, or NULL; malloc'ed if fp != NULL */ + char *cur; /* Next character in buffer */ + char *inp; /* End of data in buffer */ + char *end; /* End of input buffer if buf != NULL */ + char *start; /* Start of current token if not NULL */ + int done; /* E_OK normally, E_EOF at EOF, otherwise error code */ + /* NB If done != E_OK, cur must be == inp!!! */ + FILE *fp; /* Rest of input; NULL if tokenizing a string */ + int tabsize; /* Tab spacing */ + int indent; /* Current indentation index */ + int indstack[MAXINDENT]; /* Stack of indents */ + int atbol; /* Nonzero if at begin of new line */ + int pendin; /* Pending indents (if > 0) or dedents (if < 0) */ + char *prompt, *nextprompt; /* For interactive prompting */ + int lineno; /* Current line number */ + int level; /* () [] {} Parentheses nesting level */ + /* Used to allow free continuations inside them */ + /* Stuff for checking on different tab sizes */ + const char *filename; /* For error messages */ + int altwarning; /* Issue warning if alternate tabs don't match */ + int alterror; /* Issue error if alternate tabs don't match */ + int alttabsize; /* Alternate tab spacing */ + int altindstack[MAXINDENT]; /* Stack of alternate indents */ + /* Stuff for PEP 0263 */ + int decoding_state; /* -1:decoding, 0:init, 1:raw */ + int decoding_erred; /* whether erred in decoding */ + int read_coding_spec; /* whether 'coding:...' has been read */ + char *encoding; + int cont_line; /* whether we are in a continuation line. */ + const char* line_start; /* pointer to start of current line */ +#ifndef PGEN + PyObject *decoding_readline; /* codecs.open(...).readline */ + PyObject *decoding_buffer; +#endif + const char* enc; + const char* str; +}; + +extern struct tok_state *PyTokenizer_FromString(const char *); +extern struct tok_state *PyTokenizer_FromFile(FILE *, char *, char *); +extern void PyTokenizer_Free(struct tok_state *); +extern int PyTokenizer_Get(struct tok_state *, char **, char **); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_TOKENIZER_H */ diff --git a/sys/src/cmd/python/Parser/tokenizer_pgen.c b/sys/src/cmd/python/Parser/tokenizer_pgen.c new file mode 100644 index 000000000..9cb8492d6 --- /dev/null +++ b/sys/src/cmd/python/Parser/tokenizer_pgen.c @@ -0,0 +1,2 @@ +#define PGEN +#include "tokenizer.c" diff --git a/sys/src/cmd/python/Python/Python-ast.c b/sys/src/cmd/python/Python/Python-ast.c new file mode 100644 index 000000000..7a0f52825 --- /dev/null +++ b/sys/src/cmd/python/Python/Python-ast.c @@ -0,0 +1,3202 @@ +/* File automatically generated by Parser/asdl_c.py */ + +#include "Python.h" +#include "Python-ast.h" + +static PyTypeObject* AST_type; +static PyTypeObject *mod_type; +static PyObject* ast2obj_mod(void*); +static PyTypeObject *Module_type; +static char *Module_fields[]={ + "body", +}; +static PyTypeObject *Interactive_type; +static char *Interactive_fields[]={ + "body", +}; +static PyTypeObject *Expression_type; +static char *Expression_fields[]={ + "body", +}; +static PyTypeObject *Suite_type; +static char *Suite_fields[]={ + "body", +}; +static PyTypeObject *stmt_type; +static char *stmt_attributes[] = { + "lineno", + "col_offset", +}; +static PyObject* ast2obj_stmt(void*); +static PyTypeObject *FunctionDef_type; +static char *FunctionDef_fields[]={ + "name", + "args", + "body", + "decorators", +}; +static PyTypeObject *ClassDef_type; +static char *ClassDef_fields[]={ + "name", + "bases", + "body", +}; +static PyTypeObject *Return_type; +static char *Return_fields[]={ + "value", +}; +static PyTypeObject *Delete_type; +static char *Delete_fields[]={ + "targets", +}; +static PyTypeObject *Assign_type; +static char *Assign_fields[]={ + "targets", + "value", +}; +static PyTypeObject *AugAssign_type; +static char *AugAssign_fields[]={ + "target", + "op", + "value", +}; +static PyTypeObject *Print_type; +static char *Print_fields[]={ + "dest", + "values", + "nl", +}; +static PyTypeObject *For_type; +static char *For_fields[]={ + "target", + "iter", + "body", + "orelse", +}; +static PyTypeObject *While_type; +static char *While_fields[]={ + "test", + "body", + "orelse", +}; +static PyTypeObject *If_type; +static char *If_fields[]={ + "test", + "body", + "orelse", +}; +static PyTypeObject *With_type; +static char *With_fields[]={ + "context_expr", + "optional_vars", + "body", +}; +static PyTypeObject *Raise_type; +static char *Raise_fields[]={ + "type", + "inst", + "tback", +}; +static PyTypeObject *TryExcept_type; +static char *TryExcept_fields[]={ + "body", + "handlers", + "orelse", +}; +static PyTypeObject *TryFinally_type; +static char *TryFinally_fields[]={ + "body", + "finalbody", +}; +static PyTypeObject *Assert_type; +static char *Assert_fields[]={ + "test", + "msg", +}; +static PyTypeObject *Import_type; +static char *Import_fields[]={ + "names", +}; +static PyTypeObject *ImportFrom_type; +static char *ImportFrom_fields[]={ + "module", + "names", + "level", +}; +static PyTypeObject *Exec_type; +static char *Exec_fields[]={ + "body", + "globals", + "locals", +}; +static PyTypeObject *Global_type; +static char *Global_fields[]={ + "names", +}; +static PyTypeObject *Expr_type; +static char *Expr_fields[]={ + "value", +}; +static PyTypeObject *Pass_type; +static PyTypeObject *Break_type; +static PyTypeObject *Continue_type; +static PyTypeObject *expr_type; +static char *expr_attributes[] = { + "lineno", + "col_offset", +}; +static PyObject* ast2obj_expr(void*); +static PyTypeObject *BoolOp_type; +static char *BoolOp_fields[]={ + "op", + "values", +}; +static PyTypeObject *BinOp_type; +static char *BinOp_fields[]={ + "left", + "op", + "right", +}; +static PyTypeObject *UnaryOp_type; +static char *UnaryOp_fields[]={ + "op", + "operand", +}; +static PyTypeObject *Lambda_type; +static char *Lambda_fields[]={ + "args", + "body", +}; +static PyTypeObject *IfExp_type; +static char *IfExp_fields[]={ + "test", + "body", + "orelse", +}; +static PyTypeObject *Dict_type; +static char *Dict_fields[]={ + "keys", + "values", +}; +static PyTypeObject *ListComp_type; +static char *ListComp_fields[]={ + "elt", + "generators", +}; +static PyTypeObject *GeneratorExp_type; +static char *GeneratorExp_fields[]={ + "elt", + "generators", +}; +static PyTypeObject *Yield_type; +static char *Yield_fields[]={ + "value", +}; +static PyTypeObject *Compare_type; +static char *Compare_fields[]={ + "left", + "ops", + "comparators", +}; +static PyTypeObject *Call_type; +static char *Call_fields[]={ + "func", + "args", + "keywords", + "starargs", + "kwargs", +}; +static PyTypeObject *Repr_type; +static char *Repr_fields[]={ + "value", +}; +static PyTypeObject *Num_type; +static char *Num_fields[]={ + "n", +}; +static PyTypeObject *Str_type; +static char *Str_fields[]={ + "s", +}; +static PyTypeObject *Attribute_type; +static char *Attribute_fields[]={ + "value", + "attr", + "ctx", +}; +static PyTypeObject *Subscript_type; +static char *Subscript_fields[]={ + "value", + "slice", + "ctx", +}; +static PyTypeObject *Name_type; +static char *Name_fields[]={ + "id", + "ctx", +}; +static PyTypeObject *List_type; +static char *List_fields[]={ + "elts", + "ctx", +}; +static PyTypeObject *Tuple_type; +static char *Tuple_fields[]={ + "elts", + "ctx", +}; +static PyTypeObject *expr_context_type; +static PyObject *Load_singleton, *Store_singleton, *Del_singleton, +*AugLoad_singleton, *AugStore_singleton, *Param_singleton; +static PyObject* ast2obj_expr_context(expr_context_ty); +static PyTypeObject *Load_type; +static PyTypeObject *Store_type; +static PyTypeObject *Del_type; +static PyTypeObject *AugLoad_type; +static PyTypeObject *AugStore_type; +static PyTypeObject *Param_type; +static PyTypeObject *slice_type; +static PyObject* ast2obj_slice(void*); +static PyTypeObject *Ellipsis_type; +static PyTypeObject *Slice_type; +static char *Slice_fields[]={ + "lower", + "upper", + "step", +}; +static PyTypeObject *ExtSlice_type; +static char *ExtSlice_fields[]={ + "dims", +}; +static PyTypeObject *Index_type; +static char *Index_fields[]={ + "value", +}; +static PyTypeObject *boolop_type; +static PyObject *And_singleton, *Or_singleton; +static PyObject* ast2obj_boolop(boolop_ty); +static PyTypeObject *And_type; +static PyTypeObject *Or_type; +static PyTypeObject *operator_type; +static PyObject *Add_singleton, *Sub_singleton, *Mult_singleton, +*Div_singleton, *Mod_singleton, *Pow_singleton, *LShift_singleton, +*RShift_singleton, *BitOr_singleton, *BitXor_singleton, *BitAnd_singleton, +*FloorDiv_singleton; +static PyObject* ast2obj_operator(operator_ty); +static PyTypeObject *Add_type; +static PyTypeObject *Sub_type; +static PyTypeObject *Mult_type; +static PyTypeObject *Div_type; +static PyTypeObject *Mod_type; +static PyTypeObject *Pow_type; +static PyTypeObject *LShift_type; +static PyTypeObject *RShift_type; +static PyTypeObject *BitOr_type; +static PyTypeObject *BitXor_type; +static PyTypeObject *BitAnd_type; +static PyTypeObject *FloorDiv_type; +static PyTypeObject *unaryop_type; +static PyObject *Invert_singleton, *Not_singleton, *UAdd_singleton, +*USub_singleton; +static PyObject* ast2obj_unaryop(unaryop_ty); +static PyTypeObject *Invert_type; +static PyTypeObject *Not_type; +static PyTypeObject *UAdd_type; +static PyTypeObject *USub_type; +static PyTypeObject *cmpop_type; +static PyObject *Eq_singleton, *NotEq_singleton, *Lt_singleton, *LtE_singleton, +*Gt_singleton, *GtE_singleton, *Is_singleton, *IsNot_singleton, *In_singleton, +*NotIn_singleton; +static PyObject* ast2obj_cmpop(cmpop_ty); +static PyTypeObject *Eq_type; +static PyTypeObject *NotEq_type; +static PyTypeObject *Lt_type; +static PyTypeObject *LtE_type; +static PyTypeObject *Gt_type; +static PyTypeObject *GtE_type; +static PyTypeObject *Is_type; +static PyTypeObject *IsNot_type; +static PyTypeObject *In_type; +static PyTypeObject *NotIn_type; +static PyTypeObject *comprehension_type; +static PyObject* ast2obj_comprehension(void*); +static char *comprehension_fields[]={ + "target", + "iter", + "ifs", +}; +static PyTypeObject *excepthandler_type; +static PyObject* ast2obj_excepthandler(void*); +static char *excepthandler_fields[]={ + "type", + "name", + "body", + "lineno", + "col_offset", +}; +static PyTypeObject *arguments_type; +static PyObject* ast2obj_arguments(void*); +static char *arguments_fields[]={ + "args", + "vararg", + "kwarg", + "defaults", +}; +static PyTypeObject *keyword_type; +static PyObject* ast2obj_keyword(void*); +static char *keyword_fields[]={ + "arg", + "value", +}; +static PyTypeObject *alias_type; +static PyObject* ast2obj_alias(void*); +static char *alias_fields[]={ + "name", + "asname", +}; + + +static PyTypeObject* make_type(char *type, PyTypeObject* base, char**fields, int num_fields) +{ + PyObject *fnames, *result; + int i; + if (num_fields) { + fnames = PyTuple_New(num_fields); + if (!fnames) return NULL; + } else { + fnames = Py_None; + Py_INCREF(Py_None); + } + for(i=0; i < num_fields; i++) { + PyObject *field = PyString_FromString(fields[i]); + if (!field) { + Py_DECREF(fnames); + return NULL; + } + PyTuple_SET_ITEM(fnames, i, field); + } + result = PyObject_CallFunction((PyObject*)&PyType_Type, "s(O){sOss}", + type, base, "_fields", fnames, "__module__", "_ast"); + Py_DECREF(fnames); + return (PyTypeObject*)result; +} + +static int add_attributes(PyTypeObject* type, char**attrs, int num_fields) +{ + int i, result; + PyObject *s, *l = PyList_New(num_fields); + if (!l) return 0; + for(i = 0; i < num_fields; i++) { + s = PyString_FromString(attrs[i]); + if (!s) { + Py_DECREF(l); + return 0; + } + PyList_SET_ITEM(l, i, s); + } + result = PyObject_SetAttrString((PyObject*)type, "_attributes", l) >= 0; + Py_DECREF(l); + return result; +} + +static PyObject* ast2obj_list(asdl_seq *seq, PyObject* (*func)(void*)) +{ + int i, n = asdl_seq_LEN(seq); + PyObject *result = PyList_New(n); + PyObject *value; + if (!result) + return NULL; + for (i = 0; i < n; i++) { + value = func(asdl_seq_GET(seq, i)); + if (!value) { + Py_DECREF(result); + return NULL; + } + PyList_SET_ITEM(result, i, value); + } + return result; +} + +static PyObject* ast2obj_object(void *o) +{ + if (!o) + o = Py_None; + Py_INCREF((PyObject*)o); + return (PyObject*)o; +} +#define ast2obj_identifier ast2obj_object +#define ast2obj_string ast2obj_object +static PyObject* ast2obj_bool(bool b) +{ + return PyBool_FromLong(b); +} + +static PyObject* ast2obj_int(bool b) +{ + return PyInt_FromLong(b); +} + +static int init_types(void) +{ + static int initialized; + if (initialized) return 1; + AST_type = make_type("AST", &PyBaseObject_Type, NULL, 0); + mod_type = make_type("mod", AST_type, NULL, 0); + if (!mod_type) return 0; + if (!add_attributes(mod_type, NULL, 0)) return 0; + Module_type = make_type("Module", mod_type, Module_fields, 1); + if (!Module_type) return 0; + Interactive_type = make_type("Interactive", mod_type, + Interactive_fields, 1); + if (!Interactive_type) return 0; + Expression_type = make_type("Expression", mod_type, Expression_fields, + 1); + if (!Expression_type) return 0; + Suite_type = make_type("Suite", mod_type, Suite_fields, 1); + if (!Suite_type) return 0; + stmt_type = make_type("stmt", AST_type, NULL, 0); + if (!stmt_type) return 0; + if (!add_attributes(stmt_type, stmt_attributes, 2)) return 0; + FunctionDef_type = make_type("FunctionDef", stmt_type, + FunctionDef_fields, 4); + if (!FunctionDef_type) return 0; + ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 3); + if (!ClassDef_type) return 0; + Return_type = make_type("Return", stmt_type, Return_fields, 1); + if (!Return_type) return 0; + Delete_type = make_type("Delete", stmt_type, Delete_fields, 1); + if (!Delete_type) return 0; + Assign_type = make_type("Assign", stmt_type, Assign_fields, 2); + if (!Assign_type) return 0; + AugAssign_type = make_type("AugAssign", stmt_type, AugAssign_fields, 3); + if (!AugAssign_type) return 0; + Print_type = make_type("Print", stmt_type, Print_fields, 3); + if (!Print_type) return 0; + For_type = make_type("For", stmt_type, For_fields, 4); + if (!For_type) return 0; + While_type = make_type("While", stmt_type, While_fields, 3); + if (!While_type) return 0; + If_type = make_type("If", stmt_type, If_fields, 3); + if (!If_type) return 0; + With_type = make_type("With", stmt_type, With_fields, 3); + if (!With_type) return 0; + Raise_type = make_type("Raise", stmt_type, Raise_fields, 3); + if (!Raise_type) return 0; + TryExcept_type = make_type("TryExcept", stmt_type, TryExcept_fields, 3); + if (!TryExcept_type) return 0; + TryFinally_type = make_type("TryFinally", stmt_type, TryFinally_fields, + 2); + if (!TryFinally_type) return 0; + Assert_type = make_type("Assert", stmt_type, Assert_fields, 2); + if (!Assert_type) return 0; + Import_type = make_type("Import", stmt_type, Import_fields, 1); + if (!Import_type) return 0; + ImportFrom_type = make_type("ImportFrom", stmt_type, ImportFrom_fields, + 3); + if (!ImportFrom_type) return 0; + Exec_type = make_type("Exec", stmt_type, Exec_fields, 3); + if (!Exec_type) return 0; + Global_type = make_type("Global", stmt_type, Global_fields, 1); + if (!Global_type) return 0; + Expr_type = make_type("Expr", stmt_type, Expr_fields, 1); + if (!Expr_type) return 0; + Pass_type = make_type("Pass", stmt_type, NULL, 0); + if (!Pass_type) return 0; + Break_type = make_type("Break", stmt_type, NULL, 0); + if (!Break_type) return 0; + Continue_type = make_type("Continue", stmt_type, NULL, 0); + if (!Continue_type) return 0; + expr_type = make_type("expr", AST_type, NULL, 0); + if (!expr_type) return 0; + if (!add_attributes(expr_type, expr_attributes, 2)) return 0; + BoolOp_type = make_type("BoolOp", expr_type, BoolOp_fields, 2); + if (!BoolOp_type) return 0; + BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3); + if (!BinOp_type) return 0; + UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2); + if (!UnaryOp_type) return 0; + Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2); + if (!Lambda_type) return 0; + IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3); + if (!IfExp_type) return 0; + Dict_type = make_type("Dict", expr_type, Dict_fields, 2); + if (!Dict_type) return 0; + ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2); + if (!ListComp_type) return 0; + GeneratorExp_type = make_type("GeneratorExp", expr_type, + GeneratorExp_fields, 2); + if (!GeneratorExp_type) return 0; + Yield_type = make_type("Yield", expr_type, Yield_fields, 1); + if (!Yield_type) return 0; + Compare_type = make_type("Compare", expr_type, Compare_fields, 3); + if (!Compare_type) return 0; + Call_type = make_type("Call", expr_type, Call_fields, 5); + if (!Call_type) return 0; + Repr_type = make_type("Repr", expr_type, Repr_fields, 1); + if (!Repr_type) return 0; + Num_type = make_type("Num", expr_type, Num_fields, 1); + if (!Num_type) return 0; + Str_type = make_type("Str", expr_type, Str_fields, 1); + if (!Str_type) return 0; + Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3); + if (!Attribute_type) return 0; + Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3); + if (!Subscript_type) return 0; + Name_type = make_type("Name", expr_type, Name_fields, 2); + if (!Name_type) return 0; + List_type = make_type("List", expr_type, List_fields, 2); + if (!List_type) return 0; + Tuple_type = make_type("Tuple", expr_type, Tuple_fields, 2); + if (!Tuple_type) return 0; + expr_context_type = make_type("expr_context", AST_type, NULL, 0); + if (!expr_context_type) return 0; + if (!add_attributes(expr_context_type, NULL, 0)) return 0; + Load_type = make_type("Load", expr_context_type, NULL, 0); + if (!Load_type) return 0; + Load_singleton = PyType_GenericNew(Load_type, NULL, NULL); + if (!Load_singleton) return 0; + Store_type = make_type("Store", expr_context_type, NULL, 0); + if (!Store_type) return 0; + Store_singleton = PyType_GenericNew(Store_type, NULL, NULL); + if (!Store_singleton) return 0; + Del_type = make_type("Del", expr_context_type, NULL, 0); + if (!Del_type) return 0; + Del_singleton = PyType_GenericNew(Del_type, NULL, NULL); + if (!Del_singleton) return 0; + AugLoad_type = make_type("AugLoad", expr_context_type, NULL, 0); + if (!AugLoad_type) return 0; + AugLoad_singleton = PyType_GenericNew(AugLoad_type, NULL, NULL); + if (!AugLoad_singleton) return 0; + AugStore_type = make_type("AugStore", expr_context_type, NULL, 0); + if (!AugStore_type) return 0; + AugStore_singleton = PyType_GenericNew(AugStore_type, NULL, NULL); + if (!AugStore_singleton) return 0; + Param_type = make_type("Param", expr_context_type, NULL, 0); + if (!Param_type) return 0; + Param_singleton = PyType_GenericNew(Param_type, NULL, NULL); + if (!Param_singleton) return 0; + slice_type = make_type("slice", AST_type, NULL, 0); + if (!slice_type) return 0; + if (!add_attributes(slice_type, NULL, 0)) return 0; + Ellipsis_type = make_type("Ellipsis", slice_type, NULL, 0); + if (!Ellipsis_type) return 0; + Slice_type = make_type("Slice", slice_type, Slice_fields, 3); + if (!Slice_type) return 0; + ExtSlice_type = make_type("ExtSlice", slice_type, ExtSlice_fields, 1); + if (!ExtSlice_type) return 0; + Index_type = make_type("Index", slice_type, Index_fields, 1); + if (!Index_type) return 0; + boolop_type = make_type("boolop", AST_type, NULL, 0); + if (!boolop_type) return 0; + if (!add_attributes(boolop_type, NULL, 0)) return 0; + And_type = make_type("And", boolop_type, NULL, 0); + if (!And_type) return 0; + And_singleton = PyType_GenericNew(And_type, NULL, NULL); + if (!And_singleton) return 0; + Or_type = make_type("Or", boolop_type, NULL, 0); + if (!Or_type) return 0; + Or_singleton = PyType_GenericNew(Or_type, NULL, NULL); + if (!Or_singleton) return 0; + operator_type = make_type("operator", AST_type, NULL, 0); + if (!operator_type) return 0; + if (!add_attributes(operator_type, NULL, 0)) return 0; + Add_type = make_type("Add", operator_type, NULL, 0); + if (!Add_type) return 0; + Add_singleton = PyType_GenericNew(Add_type, NULL, NULL); + if (!Add_singleton) return 0; + Sub_type = make_type("Sub", operator_type, NULL, 0); + if (!Sub_type) return 0; + Sub_singleton = PyType_GenericNew(Sub_type, NULL, NULL); + if (!Sub_singleton) return 0; + Mult_type = make_type("Mult", operator_type, NULL, 0); + if (!Mult_type) return 0; + Mult_singleton = PyType_GenericNew(Mult_type, NULL, NULL); + if (!Mult_singleton) return 0; + Div_type = make_type("Div", operator_type, NULL, 0); + if (!Div_type) return 0; + Div_singleton = PyType_GenericNew(Div_type, NULL, NULL); + if (!Div_singleton) return 0; + Mod_type = make_type("Mod", operator_type, NULL, 0); + if (!Mod_type) return 0; + Mod_singleton = PyType_GenericNew(Mod_type, NULL, NULL); + if (!Mod_singleton) return 0; + Pow_type = make_type("Pow", operator_type, NULL, 0); + if (!Pow_type) return 0; + Pow_singleton = PyType_GenericNew(Pow_type, NULL, NULL); + if (!Pow_singleton) return 0; + LShift_type = make_type("LShift", operator_type, NULL, 0); + if (!LShift_type) return 0; + LShift_singleton = PyType_GenericNew(LShift_type, NULL, NULL); + if (!LShift_singleton) return 0; + RShift_type = make_type("RShift", operator_type, NULL, 0); + if (!RShift_type) return 0; + RShift_singleton = PyType_GenericNew(RShift_type, NULL, NULL); + if (!RShift_singleton) return 0; + BitOr_type = make_type("BitOr", operator_type, NULL, 0); + if (!BitOr_type) return 0; + BitOr_singleton = PyType_GenericNew(BitOr_type, NULL, NULL); + if (!BitOr_singleton) return 0; + BitXor_type = make_type("BitXor", operator_type, NULL, 0); + if (!BitXor_type) return 0; + BitXor_singleton = PyType_GenericNew(BitXor_type, NULL, NULL); + if (!BitXor_singleton) return 0; + BitAnd_type = make_type("BitAnd", operator_type, NULL, 0); + if (!BitAnd_type) return 0; + BitAnd_singleton = PyType_GenericNew(BitAnd_type, NULL, NULL); + if (!BitAnd_singleton) return 0; + FloorDiv_type = make_type("FloorDiv", operator_type, NULL, 0); + if (!FloorDiv_type) return 0; + FloorDiv_singleton = PyType_GenericNew(FloorDiv_type, NULL, NULL); + if (!FloorDiv_singleton) return 0; + unaryop_type = make_type("unaryop", AST_type, NULL, 0); + if (!unaryop_type) return 0; + if (!add_attributes(unaryop_type, NULL, 0)) return 0; + Invert_type = make_type("Invert", unaryop_type, NULL, 0); + if (!Invert_type) return 0; + Invert_singleton = PyType_GenericNew(Invert_type, NULL, NULL); + if (!Invert_singleton) return 0; + Not_type = make_type("Not", unaryop_type, NULL, 0); + if (!Not_type) return 0; + Not_singleton = PyType_GenericNew(Not_type, NULL, NULL); + if (!Not_singleton) return 0; + UAdd_type = make_type("UAdd", unaryop_type, NULL, 0); + if (!UAdd_type) return 0; + UAdd_singleton = PyType_GenericNew(UAdd_type, NULL, NULL); + if (!UAdd_singleton) return 0; + USub_type = make_type("USub", unaryop_type, NULL, 0); + if (!USub_type) return 0; + USub_singleton = PyType_GenericNew(USub_type, NULL, NULL); + if (!USub_singleton) return 0; + cmpop_type = make_type("cmpop", AST_type, NULL, 0); + if (!cmpop_type) return 0; + if (!add_attributes(cmpop_type, NULL, 0)) return 0; + Eq_type = make_type("Eq", cmpop_type, NULL, 0); + if (!Eq_type) return 0; + Eq_singleton = PyType_GenericNew(Eq_type, NULL, NULL); + if (!Eq_singleton) return 0; + NotEq_type = make_type("NotEq", cmpop_type, NULL, 0); + if (!NotEq_type) return 0; + NotEq_singleton = PyType_GenericNew(NotEq_type, NULL, NULL); + if (!NotEq_singleton) return 0; + Lt_type = make_type("Lt", cmpop_type, NULL, 0); + if (!Lt_type) return 0; + Lt_singleton = PyType_GenericNew(Lt_type, NULL, NULL); + if (!Lt_singleton) return 0; + LtE_type = make_type("LtE", cmpop_type, NULL, 0); + if (!LtE_type) return 0; + LtE_singleton = PyType_GenericNew(LtE_type, NULL, NULL); + if (!LtE_singleton) return 0; + Gt_type = make_type("Gt", cmpop_type, NULL, 0); + if (!Gt_type) return 0; + Gt_singleton = PyType_GenericNew(Gt_type, NULL, NULL); + if (!Gt_singleton) return 0; + GtE_type = make_type("GtE", cmpop_type, NULL, 0); + if (!GtE_type) return 0; + GtE_singleton = PyType_GenericNew(GtE_type, NULL, NULL); + if (!GtE_singleton) return 0; + Is_type = make_type("Is", cmpop_type, NULL, 0); + if (!Is_type) return 0; + Is_singleton = PyType_GenericNew(Is_type, NULL, NULL); + if (!Is_singleton) return 0; + IsNot_type = make_type("IsNot", cmpop_type, NULL, 0); + if (!IsNot_type) return 0; + IsNot_singleton = PyType_GenericNew(IsNot_type, NULL, NULL); + if (!IsNot_singleton) return 0; + In_type = make_type("In", cmpop_type, NULL, 0); + if (!In_type) return 0; + In_singleton = PyType_GenericNew(In_type, NULL, NULL); + if (!In_singleton) return 0; + NotIn_type = make_type("NotIn", cmpop_type, NULL, 0); + if (!NotIn_type) return 0; + NotIn_singleton = PyType_GenericNew(NotIn_type, NULL, NULL); + if (!NotIn_singleton) return 0; + comprehension_type = make_type("comprehension", AST_type, + comprehension_fields, 3); + if (!comprehension_type) return 0; + excepthandler_type = make_type("excepthandler", AST_type, + excepthandler_fields, 5); + if (!excepthandler_type) return 0; + arguments_type = make_type("arguments", AST_type, arguments_fields, 4); + if (!arguments_type) return 0; + keyword_type = make_type("keyword", AST_type, keyword_fields, 2); + if (!keyword_type) return 0; + alias_type = make_type("alias", AST_type, alias_fields, 2); + if (!alias_type) return 0; + initialized = 1; + return 1; +} + +mod_ty +Module(asdl_seq * body, PyArena *arena) +{ + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Module_kind; + p->v.Module.body = body; + return p; +} + +mod_ty +Interactive(asdl_seq * body, PyArena *arena) +{ + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Interactive_kind; + p->v.Interactive.body = body; + return p; +} + +mod_ty +Expression(expr_ty body, PyArena *arena) +{ + mod_ty p; + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for Expression"); + return NULL; + } + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Expression_kind; + p->v.Expression.body = body; + return p; +} + +mod_ty +Suite(asdl_seq * body, PyArena *arena) +{ + mod_ty p; + p = (mod_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Suite_kind; + p->v.Suite.body = body; + return p; +} + +stmt_ty +FunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq * + decorators, int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for FunctionDef"); + return NULL; + } + if (!args) { + PyErr_SetString(PyExc_ValueError, + "field args is required for FunctionDef"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = FunctionDef_kind; + p->v.FunctionDef.name = name; + p->v.FunctionDef.args = args; + p->v.FunctionDef.body = body; + p->v.FunctionDef.decorators = decorators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int lineno, int + col_offset, PyArena *arena) +{ + stmt_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for ClassDef"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = ClassDef_kind; + p->v.ClassDef.name = name; + p->v.ClassDef.bases = bases; + p->v.ClassDef.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Return(expr_ty value, int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Return_kind; + p->v.Return.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Delete(asdl_seq * targets, int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Delete_kind; + p->v.Delete.targets = targets; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Assign(asdl_seq * targets, expr_ty value, int lineno, int col_offset, PyArena + *arena) +{ + stmt_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Assign"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Assign_kind; + p->v.Assign.targets = targets; + p->v.Assign.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +AugAssign(expr_ty target, operator_ty op, expr_ty value, int lineno, int + col_offset, PyArena *arena) +{ + stmt_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for AugAssign"); + return NULL; + } + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for AugAssign"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for AugAssign"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = AugAssign_kind; + p->v.AugAssign.target = target; + p->v.AugAssign.op = op; + p->v.AugAssign.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Print(expr_ty dest, asdl_seq * values, bool nl, int lineno, int col_offset, + PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Print_kind; + p->v.Print.dest = dest; + p->v.Print.values = values; + p->v.Print.nl = nl; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +For(expr_ty target, expr_ty iter, asdl_seq * body, asdl_seq * orelse, int + lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for For"); + return NULL; + } + if (!iter) { + PyErr_SetString(PyExc_ValueError, + "field iter is required for For"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = For_kind; + p->v.For.target = target; + p->v.For.iter = iter; + p->v.For.body = body; + p->v.For.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +While(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int + col_offset, PyArena *arena) +{ + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for While"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = While_kind; + p->v.While.test = test; + p->v.While.body = body; + p->v.While.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +If(expr_ty test, asdl_seq * body, asdl_seq * orelse, int lineno, int + col_offset, PyArena *arena) +{ + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for If"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = If_kind; + p->v.If.test = test; + p->v.If.body = body; + p->v.If.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +With(expr_ty context_expr, expr_ty optional_vars, asdl_seq * body, int lineno, + int col_offset, PyArena *arena) +{ + stmt_ty p; + if (!context_expr) { + PyErr_SetString(PyExc_ValueError, + "field context_expr is required for With"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = With_kind; + p->v.With.context_expr = context_expr; + p->v.With.optional_vars = optional_vars; + p->v.With.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Raise(expr_ty type, expr_ty inst, expr_ty tback, int lineno, int col_offset, + PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Raise_kind; + p->v.Raise.type = type; + p->v.Raise.inst = inst; + p->v.Raise.tback = tback; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +TryExcept(asdl_seq * body, asdl_seq * handlers, asdl_seq * orelse, int lineno, + int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = TryExcept_kind; + p->v.TryExcept.body = body; + p->v.TryExcept.handlers = handlers; + p->v.TryExcept.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +TryFinally(asdl_seq * body, asdl_seq * finalbody, int lineno, int col_offset, + PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = TryFinally_kind; + p->v.TryFinally.body = body; + p->v.TryFinally.finalbody = finalbody; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Assert(expr_ty test, expr_ty msg, int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for Assert"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Assert_kind; + p->v.Assert.test = test; + p->v.Assert.msg = msg; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Import(asdl_seq * names, int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Import_kind; + p->v.Import.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +ImportFrom(identifier module, asdl_seq * names, int level, int lineno, int + col_offset, PyArena *arena) +{ + stmt_ty p; + if (!module) { + PyErr_SetString(PyExc_ValueError, + "field module is required for ImportFrom"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = ImportFrom_kind; + p->v.ImportFrom.module = module; + p->v.ImportFrom.names = names; + p->v.ImportFrom.level = level; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Exec(expr_ty body, expr_ty globals, expr_ty locals, int lineno, int col_offset, + PyArena *arena) +{ + stmt_ty p; + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for Exec"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Exec_kind; + p->v.Exec.body = body; + p->v.Exec.globals = globals; + p->v.Exec.locals = locals; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Global(asdl_seq * names, int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Global_kind; + p->v.Global.names = names; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Expr(expr_ty value, int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Expr"); + return NULL; + } + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Expr_kind; + p->v.Expr.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Pass(int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Pass_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Break(int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Break_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +stmt_ty +Continue(int lineno, int col_offset, PyArena *arena) +{ + stmt_ty p; + p = (stmt_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Continue_kind; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +BoolOp(boolop_ty op, asdl_seq * values, int lineno, int col_offset, PyArena + *arena) +{ + expr_ty p; + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for BoolOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = BoolOp_kind; + p->v.BoolOp.op = op; + p->v.BoolOp.values = values; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +BinOp(expr_ty left, operator_ty op, expr_ty right, int lineno, int col_offset, + PyArena *arena) +{ + expr_ty p; + if (!left) { + PyErr_SetString(PyExc_ValueError, + "field left is required for BinOp"); + return NULL; + } + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for BinOp"); + return NULL; + } + if (!right) { + PyErr_SetString(PyExc_ValueError, + "field right is required for BinOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = BinOp_kind; + p->v.BinOp.left = left; + p->v.BinOp.op = op; + p->v.BinOp.right = right; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +UnaryOp(unaryop_ty op, expr_ty operand, int lineno, int col_offset, PyArena + *arena) +{ + expr_ty p; + if (!op) { + PyErr_SetString(PyExc_ValueError, + "field op is required for UnaryOp"); + return NULL; + } + if (!operand) { + PyErr_SetString(PyExc_ValueError, + "field operand is required for UnaryOp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = UnaryOp_kind; + p->v.UnaryOp.op = op; + p->v.UnaryOp.operand = operand; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Lambda(arguments_ty args, expr_ty body, int lineno, int col_offset, PyArena + *arena) +{ + expr_ty p; + if (!args) { + PyErr_SetString(PyExc_ValueError, + "field args is required for Lambda"); + return NULL; + } + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for Lambda"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Lambda_kind; + p->v.Lambda.args = args; + p->v.Lambda.body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, int col_offset, + PyArena *arena) +{ + expr_ty p; + if (!test) { + PyErr_SetString(PyExc_ValueError, + "field test is required for IfExp"); + return NULL; + } + if (!body) { + PyErr_SetString(PyExc_ValueError, + "field body is required for IfExp"); + return NULL; + } + if (!orelse) { + PyErr_SetString(PyExc_ValueError, + "field orelse is required for IfExp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = IfExp_kind; + p->v.IfExp.test = test; + p->v.IfExp.body = body; + p->v.IfExp.orelse = orelse; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Dict(asdl_seq * keys, asdl_seq * values, int lineno, int col_offset, PyArena + *arena) +{ + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Dict_kind; + p->v.Dict.keys = keys; + p->v.Dict.values = values; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +ListComp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, + PyArena *arena) +{ + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for ListComp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = ListComp_kind; + p->v.ListComp.elt = elt; + p->v.ListComp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +GeneratorExp(expr_ty elt, asdl_seq * generators, int lineno, int col_offset, + PyArena *arena) +{ + expr_ty p; + if (!elt) { + PyErr_SetString(PyExc_ValueError, + "field elt is required for GeneratorExp"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = GeneratorExp_kind; + p->v.GeneratorExp.elt = elt; + p->v.GeneratorExp.generators = generators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Yield(expr_ty value, int lineno, int col_offset, PyArena *arena) +{ + expr_ty p; + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Yield_kind; + p->v.Yield.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Compare(expr_ty left, asdl_int_seq * ops, asdl_seq * comparators, int lineno, + int col_offset, PyArena *arena) +{ + expr_ty p; + if (!left) { + PyErr_SetString(PyExc_ValueError, + "field left is required for Compare"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Compare_kind; + p->v.Compare.left = left; + p->v.Compare.ops = ops; + p->v.Compare.comparators = comparators; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Call(expr_ty func, asdl_seq * args, asdl_seq * keywords, expr_ty starargs, + expr_ty kwargs, int lineno, int col_offset, PyArena *arena) +{ + expr_ty p; + if (!func) { + PyErr_SetString(PyExc_ValueError, + "field func is required for Call"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Call_kind; + p->v.Call.func = func; + p->v.Call.args = args; + p->v.Call.keywords = keywords; + p->v.Call.starargs = starargs; + p->v.Call.kwargs = kwargs; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Repr(expr_ty value, int lineno, int col_offset, PyArena *arena) +{ + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Repr"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Repr_kind; + p->v.Repr.value = value; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Num(object n, int lineno, int col_offset, PyArena *arena) +{ + expr_ty p; + if (!n) { + PyErr_SetString(PyExc_ValueError, + "field n is required for Num"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Num_kind; + p->v.Num.n = n; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Str(string s, int lineno, int col_offset, PyArena *arena) +{ + expr_ty p; + if (!s) { + PyErr_SetString(PyExc_ValueError, + "field s is required for Str"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Str_kind; + p->v.Str.s = s; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena) +{ + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Attribute"); + return NULL; + } + if (!attr) { + PyErr_SetString(PyExc_ValueError, + "field attr is required for Attribute"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Attribute"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Attribute_kind; + p->v.Attribute.value = value; + p->v.Attribute.attr = attr; + p->v.Attribute.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Subscript(expr_ty value, slice_ty slice, expr_context_ty ctx, int lineno, int + col_offset, PyArena *arena) +{ + expr_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Subscript"); + return NULL; + } + if (!slice) { + PyErr_SetString(PyExc_ValueError, + "field slice is required for Subscript"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Subscript"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Subscript_kind; + p->v.Subscript.value = value; + p->v.Subscript.slice = slice; + p->v.Subscript.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Name(identifier id, expr_context_ty ctx, int lineno, int col_offset, PyArena + *arena) +{ + expr_ty p; + if (!id) { + PyErr_SetString(PyExc_ValueError, + "field id is required for Name"); + return NULL; + } + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Name"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Name_kind; + p->v.Name.id = id; + p->v.Name.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +List(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena + *arena) +{ + expr_ty p; + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for List"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = List_kind; + p->v.List.elts = elts; + p->v.List.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +expr_ty +Tuple(asdl_seq * elts, expr_context_ty ctx, int lineno, int col_offset, PyArena + *arena) +{ + expr_ty p; + if (!ctx) { + PyErr_SetString(PyExc_ValueError, + "field ctx is required for Tuple"); + return NULL; + } + p = (expr_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Tuple_kind; + p->v.Tuple.elts = elts; + p->v.Tuple.ctx = ctx; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +slice_ty +Ellipsis(PyArena *arena) +{ + slice_ty p; + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Ellipsis_kind; + return p; +} + +slice_ty +Slice(expr_ty lower, expr_ty upper, expr_ty step, PyArena *arena) +{ + slice_ty p; + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Slice_kind; + p->v.Slice.lower = lower; + p->v.Slice.upper = upper; + p->v.Slice.step = step; + return p; +} + +slice_ty +ExtSlice(asdl_seq * dims, PyArena *arena) +{ + slice_ty p; + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = ExtSlice_kind; + p->v.ExtSlice.dims = dims; + return p; +} + +slice_ty +Index(expr_ty value, PyArena *arena) +{ + slice_ty p; + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for Index"); + return NULL; + } + p = (slice_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->kind = Index_kind; + p->v.Index.value = value; + return p; +} + +comprehension_ty +comprehension(expr_ty target, expr_ty iter, asdl_seq * ifs, PyArena *arena) +{ + comprehension_ty p; + if (!target) { + PyErr_SetString(PyExc_ValueError, + "field target is required for comprehension"); + return NULL; + } + if (!iter) { + PyErr_SetString(PyExc_ValueError, + "field iter is required for comprehension"); + return NULL; + } + p = (comprehension_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->target = target; + p->iter = iter; + p->ifs = ifs; + return p; +} + +excepthandler_ty +excepthandler(expr_ty type, expr_ty name, asdl_seq * body, int lineno, int + col_offset, PyArena *arena) +{ + excepthandler_ty p; + p = (excepthandler_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->type = type; + p->name = name; + p->body = body; + p->lineno = lineno; + p->col_offset = col_offset; + return p; +} + +arguments_ty +arguments(asdl_seq * args, identifier vararg, identifier kwarg, asdl_seq * + defaults, PyArena *arena) +{ + arguments_ty p; + p = (arguments_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->args = args; + p->vararg = vararg; + p->kwarg = kwarg; + p->defaults = defaults; + return p; +} + +keyword_ty +keyword(identifier arg, expr_ty value, PyArena *arena) +{ + keyword_ty p; + if (!arg) { + PyErr_SetString(PyExc_ValueError, + "field arg is required for keyword"); + return NULL; + } + if (!value) { + PyErr_SetString(PyExc_ValueError, + "field value is required for keyword"); + return NULL; + } + p = (keyword_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->arg = arg; + p->value = value; + return p; +} + +alias_ty +alias(identifier name, identifier asname, PyArena *arena) +{ + alias_ty p; + if (!name) { + PyErr_SetString(PyExc_ValueError, + "field name is required for alias"); + return NULL; + } + p = (alias_ty)PyArena_Malloc(arena, sizeof(*p)); + if (!p) { + PyErr_NoMemory(); + return NULL; + } + p->name = name; + p->asname = asname; + return p; +} + + +PyObject* +ast2obj_mod(void* _o) +{ + mod_ty o = (mod_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case Module_kind: + result = PyType_GenericNew(Module_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Module.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Interactive_kind: + result = PyType_GenericNew(Interactive_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Interactive.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Expression_kind: + result = PyType_GenericNew(Expression_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Expression.body); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Suite_kind: + result = PyType_GenericNew(Suite_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Suite.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + break; + } + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* +ast2obj_stmt(void* _o) +{ + stmt_ty o = (stmt_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case FunctionDef_kind: + result = PyType_GenericNew(FunctionDef_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.FunctionDef.name); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "name", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_arguments(o->v.FunctionDef.args); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "args", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.FunctionDef.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.FunctionDef.decorators, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "decorators", value) == -1) + goto failed; + Py_DECREF(value); + break; + case ClassDef_kind: + result = PyType_GenericNew(ClassDef_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.ClassDef.name); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "name", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.bases, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "bases", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Return_kind: + result = PyType_GenericNew(Return_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Return.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Delete_kind: + result = PyType_GenericNew(Delete_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Delete.targets, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "targets", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Assign_kind: + result = PyType_GenericNew(Assign_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Assign.targets, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "targets", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Assign.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + break; + case AugAssign_kind: + result = PyType_GenericNew(AugAssign_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.AugAssign.target); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "target", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_operator(o->v.AugAssign.op); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "op", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.AugAssign.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Print_kind: + result = PyType_GenericNew(Print_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Print.dest); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "dest", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Print.values, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "values", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_bool(o->v.Print.nl); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "nl", value) == -1) + goto failed; + Py_DECREF(value); + break; + case For_kind: + result = PyType_GenericNew(For_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.For.target); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "target", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.For.iter); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "iter", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.For.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.For.orelse, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "orelse", value) == -1) + goto failed; + Py_DECREF(value); + break; + case While_kind: + result = PyType_GenericNew(While_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.While.test); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "test", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.While.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.While.orelse, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "orelse", value) == -1) + goto failed; + Py_DECREF(value); + break; + case If_kind: + result = PyType_GenericNew(If_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.If.test); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "test", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.If.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.If.orelse, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "orelse", value) == -1) + goto failed; + Py_DECREF(value); + break; + case With_kind: + result = PyType_GenericNew(With_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.With.context_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "context_expr", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.With.optional_vars); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "optional_vars", value) == + -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.With.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Raise_kind: + result = PyType_GenericNew(Raise_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Raise.type); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "type", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Raise.inst); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "inst", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Raise.tback); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "tback", value) == -1) + goto failed; + Py_DECREF(value); + break; + case TryExcept_kind: + result = PyType_GenericNew(TryExcept_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.TryExcept.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.TryExcept.handlers, + ast2obj_excepthandler); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "handlers", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.TryExcept.orelse, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "orelse", value) == -1) + goto failed; + Py_DECREF(value); + break; + case TryFinally_kind: + result = PyType_GenericNew(TryFinally_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.TryFinally.body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.TryFinally.finalbody, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "finalbody", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Assert_kind: + result = PyType_GenericNew(Assert_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Assert.test); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "test", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Assert.msg); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "msg", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Import_kind: + result = PyType_GenericNew(Import_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Import.names, ast2obj_alias); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "names", value) == -1) + goto failed; + Py_DECREF(value); + break; + case ImportFrom_kind: + result = PyType_GenericNew(ImportFrom_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.ImportFrom.module); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "module", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ImportFrom.names, ast2obj_alias); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "names", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->v.ImportFrom.level); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "level", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Exec_kind: + result = PyType_GenericNew(Exec_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Exec.body); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Exec.globals); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "globals", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Exec.locals); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "locals", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Global_kind: + result = PyType_GenericNew(Global_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Global.names, ast2obj_identifier); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "names", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Expr_kind: + result = PyType_GenericNew(Expr_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Expr.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Pass_kind: + result = PyType_GenericNew(Pass_type, NULL, NULL); + if (!result) goto failed; + break; + case Break_kind: + result = PyType_GenericNew(Break_type, NULL, NULL); + if (!result) goto failed; + break; + case Continue_kind: + result = PyType_GenericNew(Continue_type, NULL, NULL); + if (!result) goto failed; + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "lineno", value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "col_offset", value) < 0) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* +ast2obj_expr(void* _o) +{ + expr_ty o = (expr_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case BoolOp_kind: + result = PyType_GenericNew(BoolOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_boolop(o->v.BoolOp.op); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "op", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.BoolOp.values, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "values", value) == -1) + goto failed; + Py_DECREF(value); + break; + case BinOp_kind: + result = PyType_GenericNew(BinOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.BinOp.left); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "left", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_operator(o->v.BinOp.op); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "op", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.BinOp.right); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "right", value) == -1) + goto failed; + Py_DECREF(value); + break; + case UnaryOp_kind: + result = PyType_GenericNew(UnaryOp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_unaryop(o->v.UnaryOp.op); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "op", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.UnaryOp.operand); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "operand", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Lambda_kind: + result = PyType_GenericNew(Lambda_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_arguments(o->v.Lambda.args); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "args", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Lambda.body); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + break; + case IfExp_kind: + result = PyType_GenericNew(IfExp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.IfExp.test); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "test", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.IfExp.body); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.IfExp.orelse); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "orelse", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Dict_kind: + result = PyType_GenericNew(Dict_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Dict.keys, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "keys", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Dict.values, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "values", value) == -1) + goto failed; + Py_DECREF(value); + break; + case ListComp_kind: + result = PyType_GenericNew(ListComp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.ListComp.elt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "elt", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.ListComp.generators, + ast2obj_comprehension); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "generators", value) == -1) + goto failed; + Py_DECREF(value); + break; + case GeneratorExp_kind: + result = PyType_GenericNew(GeneratorExp_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.GeneratorExp.elt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "elt", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.GeneratorExp.generators, + ast2obj_comprehension); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "generators", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Yield_kind: + result = PyType_GenericNew(Yield_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Yield.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Compare_kind: + result = PyType_GenericNew(Compare_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Compare.left); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "left", value) == -1) + goto failed; + Py_DECREF(value); + { + int i, n = asdl_seq_LEN(o->v.Compare.ops); + value = PyList_New(n); + if (!value) goto failed; + for(i = 0; i < n; i++) + PyList_SET_ITEM(value, i, ast2obj_cmpop((cmpop_ty)asdl_seq_GET(o->v.Compare.ops, i))); + } + if (!value) goto failed; + if (PyObject_SetAttrString(result, "ops", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Compare.comparators, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "comparators", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Call_kind: + result = PyType_GenericNew(Call_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Call.func); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "func", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Call.args, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "args", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->v.Call.keywords, ast2obj_keyword); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "keywords", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Call.starargs); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "starargs", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Call.kwargs); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "kwargs", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Repr_kind: + result = PyType_GenericNew(Repr_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Repr.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Num_kind: + result = PyType_GenericNew(Num_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_object(o->v.Num.n); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "n", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Str_kind: + result = PyType_GenericNew(Str_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_string(o->v.Str.s); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "s", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Attribute_kind: + result = PyType_GenericNew(Attribute_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Attribute.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->v.Attribute.attr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "attr", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Attribute.ctx); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "ctx", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Subscript_kind: + result = PyType_GenericNew(Subscript_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Subscript.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_slice(o->v.Subscript.slice); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "slice", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Subscript.ctx); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "ctx", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Name_kind: + result = PyType_GenericNew(Name_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_identifier(o->v.Name.id); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "id", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Name.ctx); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "ctx", value) == -1) + goto failed; + Py_DECREF(value); + break; + case List_kind: + result = PyType_GenericNew(List_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.List.elts, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "elts", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.List.ctx); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "ctx", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Tuple_kind: + result = PyType_GenericNew(Tuple_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.Tuple.elts, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "elts", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr_context(o->v.Tuple.ctx); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "ctx", value) == -1) + goto failed; + Py_DECREF(value); + break; + } + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "lineno", value) < 0) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "col_offset", value) < 0) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* ast2obj_expr_context(expr_context_ty o) +{ + switch(o) { + case Load: + Py_INCREF(Load_singleton); + return Load_singleton; + case Store: + Py_INCREF(Store_singleton); + return Store_singleton; + case Del: + Py_INCREF(Del_singleton); + return Del_singleton; + case AugLoad: + Py_INCREF(AugLoad_singleton); + return AugLoad_singleton; + case AugStore: + Py_INCREF(AugStore_singleton); + return AugStore_singleton; + case Param: + Py_INCREF(Param_singleton); + return Param_singleton; + } + return NULL; /* cannot happen */ +} +PyObject* +ast2obj_slice(void* _o) +{ + slice_ty o = (slice_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + switch (o->kind) { + case Ellipsis_kind: + result = PyType_GenericNew(Ellipsis_type, NULL, NULL); + if (!result) goto failed; + break; + case Slice_kind: + result = PyType_GenericNew(Slice_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Slice.lower); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "lower", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Slice.upper); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "upper", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.Slice.step); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "step", value) == -1) + goto failed; + Py_DECREF(value); + break; + case ExtSlice_kind: + result = PyType_GenericNew(ExtSlice_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_list(o->v.ExtSlice.dims, ast2obj_slice); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "dims", value) == -1) + goto failed; + Py_DECREF(value); + break; + case Index_kind: + result = PyType_GenericNew(Index_type, NULL, NULL); + if (!result) goto failed; + value = ast2obj_expr(o->v.Index.value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + break; + } + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* ast2obj_boolop(boolop_ty o) +{ + switch(o) { + case And: + Py_INCREF(And_singleton); + return And_singleton; + case Or: + Py_INCREF(Or_singleton); + return Or_singleton; + } + return NULL; /* cannot happen */ +} +PyObject* ast2obj_operator(operator_ty o) +{ + switch(o) { + case Add: + Py_INCREF(Add_singleton); + return Add_singleton; + case Sub: + Py_INCREF(Sub_singleton); + return Sub_singleton; + case Mult: + Py_INCREF(Mult_singleton); + return Mult_singleton; + case Div: + Py_INCREF(Div_singleton); + return Div_singleton; + case Mod: + Py_INCREF(Mod_singleton); + return Mod_singleton; + case Pow: + Py_INCREF(Pow_singleton); + return Pow_singleton; + case LShift: + Py_INCREF(LShift_singleton); + return LShift_singleton; + case RShift: + Py_INCREF(RShift_singleton); + return RShift_singleton; + case BitOr: + Py_INCREF(BitOr_singleton); + return BitOr_singleton; + case BitXor: + Py_INCREF(BitXor_singleton); + return BitXor_singleton; + case BitAnd: + Py_INCREF(BitAnd_singleton); + return BitAnd_singleton; + case FloorDiv: + Py_INCREF(FloorDiv_singleton); + return FloorDiv_singleton; + } + return NULL; /* cannot happen */ +} +PyObject* ast2obj_unaryop(unaryop_ty o) +{ + switch(o) { + case Invert: + Py_INCREF(Invert_singleton); + return Invert_singleton; + case Not: + Py_INCREF(Not_singleton); + return Not_singleton; + case UAdd: + Py_INCREF(UAdd_singleton); + return UAdd_singleton; + case USub: + Py_INCREF(USub_singleton); + return USub_singleton; + } + return NULL; /* cannot happen */ +} +PyObject* ast2obj_cmpop(cmpop_ty o) +{ + switch(o) { + case Eq: + Py_INCREF(Eq_singleton); + return Eq_singleton; + case NotEq: + Py_INCREF(NotEq_singleton); + return NotEq_singleton; + case Lt: + Py_INCREF(Lt_singleton); + return Lt_singleton; + case LtE: + Py_INCREF(LtE_singleton); + return LtE_singleton; + case Gt: + Py_INCREF(Gt_singleton); + return Gt_singleton; + case GtE: + Py_INCREF(GtE_singleton); + return GtE_singleton; + case Is: + Py_INCREF(Is_singleton); + return Is_singleton; + case IsNot: + Py_INCREF(IsNot_singleton); + return IsNot_singleton; + case In: + Py_INCREF(In_singleton); + return In_singleton; + case NotIn: + Py_INCREF(NotIn_singleton); + return NotIn_singleton; + } + return NULL; /* cannot happen */ +} +PyObject* +ast2obj_comprehension(void* _o) +{ + comprehension_ty o = (comprehension_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(comprehension_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_expr(o->target); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "target", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->iter); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "iter", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->ifs, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "ifs", value) == -1) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* +ast2obj_excepthandler(void* _o) +{ + excepthandler_ty o = (excepthandler_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(excepthandler_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_expr(o->type); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "type", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->name); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "name", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->body, ast2obj_stmt); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "body", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->lineno); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "lineno", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_int(o->col_offset); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "col_offset", value) == -1) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* +ast2obj_arguments(void* _o) +{ + arguments_ty o = (arguments_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(arguments_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_list(o->args, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "args", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->vararg); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "vararg", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->kwarg); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "kwarg", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_list(o->defaults, ast2obj_expr); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "defaults", value) == -1) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* +ast2obj_keyword(void* _o) +{ + keyword_ty o = (keyword_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(keyword_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->arg); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "arg", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->value); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "value", value) == -1) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + +PyObject* +ast2obj_alias(void* _o) +{ + alias_ty o = (alias_ty)_o; + PyObject *result = NULL, *value = NULL; + if (!o) { + Py_INCREF(Py_None); + return Py_None; + } + + result = PyType_GenericNew(alias_type, NULL, NULL); + if (!result) return NULL; + value = ast2obj_identifier(o->name); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "name", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_identifier(o->asname); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "asname", value) == -1) + goto failed; + Py_DECREF(value); + return result; +failed: + Py_XDECREF(value); + Py_XDECREF(result); + return NULL; +} + + +PyMODINIT_FUNC +init_ast(void) +{ + PyObject *m, *d; + if (!init_types()) return; + m = Py_InitModule3("_ast", NULL, NULL); + if (!m) return; + d = PyModule_GetDict(m); + if (PyDict_SetItemString(d, "AST", (PyObject*)AST_type) < 0) return; + if (PyModule_AddIntConstant(m, "PyCF_ONLY_AST", PyCF_ONLY_AST) < 0) + return; + if (PyModule_AddStringConstant(m, "__version__", "43614") < 0) + return; + if (PyDict_SetItemString(d, "mod", (PyObject*)mod_type) < 0) return; + if (PyDict_SetItemString(d, "Module", (PyObject*)Module_type) < 0) + return; + if (PyDict_SetItemString(d, "Interactive", (PyObject*)Interactive_type) + < 0) return; + if (PyDict_SetItemString(d, "Expression", (PyObject*)Expression_type) < + 0) return; + if (PyDict_SetItemString(d, "Suite", (PyObject*)Suite_type) < 0) return; + if (PyDict_SetItemString(d, "stmt", (PyObject*)stmt_type) < 0) return; + if (PyDict_SetItemString(d, "FunctionDef", (PyObject*)FunctionDef_type) + < 0) return; + if (PyDict_SetItemString(d, "ClassDef", (PyObject*)ClassDef_type) < 0) + return; + if (PyDict_SetItemString(d, "Return", (PyObject*)Return_type) < 0) + return; + if (PyDict_SetItemString(d, "Delete", (PyObject*)Delete_type) < 0) + return; + if (PyDict_SetItemString(d, "Assign", (PyObject*)Assign_type) < 0) + return; + if (PyDict_SetItemString(d, "AugAssign", (PyObject*)AugAssign_type) < + 0) return; + if (PyDict_SetItemString(d, "Print", (PyObject*)Print_type) < 0) return; + if (PyDict_SetItemString(d, "For", (PyObject*)For_type) < 0) return; + if (PyDict_SetItemString(d, "While", (PyObject*)While_type) < 0) return; + if (PyDict_SetItemString(d, "If", (PyObject*)If_type) < 0) return; + if (PyDict_SetItemString(d, "With", (PyObject*)With_type) < 0) return; + if (PyDict_SetItemString(d, "Raise", (PyObject*)Raise_type) < 0) return; + if (PyDict_SetItemString(d, "TryExcept", (PyObject*)TryExcept_type) < + 0) return; + if (PyDict_SetItemString(d, "TryFinally", (PyObject*)TryFinally_type) < + 0) return; + if (PyDict_SetItemString(d, "Assert", (PyObject*)Assert_type) < 0) + return; + if (PyDict_SetItemString(d, "Import", (PyObject*)Import_type) < 0) + return; + if (PyDict_SetItemString(d, "ImportFrom", (PyObject*)ImportFrom_type) < + 0) return; + if (PyDict_SetItemString(d, "Exec", (PyObject*)Exec_type) < 0) return; + if (PyDict_SetItemString(d, "Global", (PyObject*)Global_type) < 0) + return; + if (PyDict_SetItemString(d, "Expr", (PyObject*)Expr_type) < 0) return; + if (PyDict_SetItemString(d, "Pass", (PyObject*)Pass_type) < 0) return; + if (PyDict_SetItemString(d, "Break", (PyObject*)Break_type) < 0) return; + if (PyDict_SetItemString(d, "Continue", (PyObject*)Continue_type) < 0) + return; + if (PyDict_SetItemString(d, "expr", (PyObject*)expr_type) < 0) return; + if (PyDict_SetItemString(d, "BoolOp", (PyObject*)BoolOp_type) < 0) + return; + if (PyDict_SetItemString(d, "BinOp", (PyObject*)BinOp_type) < 0) return; + if (PyDict_SetItemString(d, "UnaryOp", (PyObject*)UnaryOp_type) < 0) + return; + if (PyDict_SetItemString(d, "Lambda", (PyObject*)Lambda_type) < 0) + return; + if (PyDict_SetItemString(d, "IfExp", (PyObject*)IfExp_type) < 0) return; + if (PyDict_SetItemString(d, "Dict", (PyObject*)Dict_type) < 0) return; + if (PyDict_SetItemString(d, "ListComp", (PyObject*)ListComp_type) < 0) + return; + if (PyDict_SetItemString(d, "GeneratorExp", + (PyObject*)GeneratorExp_type) < 0) return; + if (PyDict_SetItemString(d, "Yield", (PyObject*)Yield_type) < 0) return; + if (PyDict_SetItemString(d, "Compare", (PyObject*)Compare_type) < 0) + return; + if (PyDict_SetItemString(d, "Call", (PyObject*)Call_type) < 0) return; + if (PyDict_SetItemString(d, "Repr", (PyObject*)Repr_type) < 0) return; + if (PyDict_SetItemString(d, "Num", (PyObject*)Num_type) < 0) return; + if (PyDict_SetItemString(d, "Str", (PyObject*)Str_type) < 0) return; + if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) < + 0) return; + if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) < + 0) return; + if (PyDict_SetItemString(d, "Name", (PyObject*)Name_type) < 0) return; + if (PyDict_SetItemString(d, "List", (PyObject*)List_type) < 0) return; + if (PyDict_SetItemString(d, "Tuple", (PyObject*)Tuple_type) < 0) return; + if (PyDict_SetItemString(d, "expr_context", + (PyObject*)expr_context_type) < 0) return; + if (PyDict_SetItemString(d, "Load", (PyObject*)Load_type) < 0) return; + if (PyDict_SetItemString(d, "Store", (PyObject*)Store_type) < 0) return; + if (PyDict_SetItemString(d, "Del", (PyObject*)Del_type) < 0) return; + if (PyDict_SetItemString(d, "AugLoad", (PyObject*)AugLoad_type) < 0) + return; + if (PyDict_SetItemString(d, "AugStore", (PyObject*)AugStore_type) < 0) + return; + if (PyDict_SetItemString(d, "Param", (PyObject*)Param_type) < 0) return; + if (PyDict_SetItemString(d, "slice", (PyObject*)slice_type) < 0) return; + if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) + return; + if (PyDict_SetItemString(d, "Slice", (PyObject*)Slice_type) < 0) return; + if (PyDict_SetItemString(d, "ExtSlice", (PyObject*)ExtSlice_type) < 0) + return; + if (PyDict_SetItemString(d, "Index", (PyObject*)Index_type) < 0) return; + if (PyDict_SetItemString(d, "boolop", (PyObject*)boolop_type) < 0) + return; + if (PyDict_SetItemString(d, "And", (PyObject*)And_type) < 0) return; + if (PyDict_SetItemString(d, "Or", (PyObject*)Or_type) < 0) return; + if (PyDict_SetItemString(d, "operator", (PyObject*)operator_type) < 0) + return; + if (PyDict_SetItemString(d, "Add", (PyObject*)Add_type) < 0) return; + if (PyDict_SetItemString(d, "Sub", (PyObject*)Sub_type) < 0) return; + if (PyDict_SetItemString(d, "Mult", (PyObject*)Mult_type) < 0) return; + if (PyDict_SetItemString(d, "Div", (PyObject*)Div_type) < 0) return; + if (PyDict_SetItemString(d, "Mod", (PyObject*)Mod_type) < 0) return; + if (PyDict_SetItemString(d, "Pow", (PyObject*)Pow_type) < 0) return; + if (PyDict_SetItemString(d, "LShift", (PyObject*)LShift_type) < 0) + return; + if (PyDict_SetItemString(d, "RShift", (PyObject*)RShift_type) < 0) + return; + if (PyDict_SetItemString(d, "BitOr", (PyObject*)BitOr_type) < 0) return; + if (PyDict_SetItemString(d, "BitXor", (PyObject*)BitXor_type) < 0) + return; + if (PyDict_SetItemString(d, "BitAnd", (PyObject*)BitAnd_type) < 0) + return; + if (PyDict_SetItemString(d, "FloorDiv", (PyObject*)FloorDiv_type) < 0) + return; + if (PyDict_SetItemString(d, "unaryop", (PyObject*)unaryop_type) < 0) + return; + if (PyDict_SetItemString(d, "Invert", (PyObject*)Invert_type) < 0) + return; + if (PyDict_SetItemString(d, "Not", (PyObject*)Not_type) < 0) return; + if (PyDict_SetItemString(d, "UAdd", (PyObject*)UAdd_type) < 0) return; + if (PyDict_SetItemString(d, "USub", (PyObject*)USub_type) < 0) return; + if (PyDict_SetItemString(d, "cmpop", (PyObject*)cmpop_type) < 0) return; + if (PyDict_SetItemString(d, "Eq", (PyObject*)Eq_type) < 0) return; + if (PyDict_SetItemString(d, "NotEq", (PyObject*)NotEq_type) < 0) return; + if (PyDict_SetItemString(d, "Lt", (PyObject*)Lt_type) < 0) return; + if (PyDict_SetItemString(d, "LtE", (PyObject*)LtE_type) < 0) return; + if (PyDict_SetItemString(d, "Gt", (PyObject*)Gt_type) < 0) return; + if (PyDict_SetItemString(d, "GtE", (PyObject*)GtE_type) < 0) return; + if (PyDict_SetItemString(d, "Is", (PyObject*)Is_type) < 0) return; + if (PyDict_SetItemString(d, "IsNot", (PyObject*)IsNot_type) < 0) return; + if (PyDict_SetItemString(d, "In", (PyObject*)In_type) < 0) return; + if (PyDict_SetItemString(d, "NotIn", (PyObject*)NotIn_type) < 0) return; + if (PyDict_SetItemString(d, "comprehension", + (PyObject*)comprehension_type) < 0) return; + if (PyDict_SetItemString(d, "excepthandler", + (PyObject*)excepthandler_type) < 0) return; + if (PyDict_SetItemString(d, "arguments", (PyObject*)arguments_type) < + 0) return; + if (PyDict_SetItemString(d, "keyword", (PyObject*)keyword_type) < 0) + return; + if (PyDict_SetItemString(d, "alias", (PyObject*)alias_type) < 0) return; +} + + +PyObject* PyAST_mod2obj(mod_ty t) +{ + init_types(); + return ast2obj_mod(t); +} + + diff --git a/sys/src/cmd/python/Python/asdl.c b/sys/src/cmd/python/Python/asdl.c new file mode 100644 index 000000000..72329b9d2 --- /dev/null +++ b/sys/src/cmd/python/Python/asdl.c @@ -0,0 +1,36 @@ +#include "Python.h" +#include "asdl.h" + +asdl_seq * +asdl_seq_new(int size, PyArena *arena) +{ + asdl_seq *seq = NULL; + size_t n = sizeof(asdl_seq) + + (size ? (sizeof(void *) * (size - 1)) : 0); + + seq = (asdl_seq *)PyArena_Malloc(arena, n); + if (!seq) { + PyErr_NoMemory(); + return NULL; + } + memset(seq, 0, n); + seq->size = size; + return seq; +} + +asdl_int_seq * +asdl_int_seq_new(int size, PyArena *arena) +{ + asdl_int_seq *seq = NULL; + size_t n = sizeof(asdl_seq) + + (size ? (sizeof(int) * (size - 1)) : 0); + + seq = (asdl_int_seq *)PyArena_Malloc(arena, n); + if (!seq) { + PyErr_NoMemory(); + return NULL; + } + memset(seq, 0, n); + seq->size = size; + return seq; +} diff --git a/sys/src/cmd/python/Python/ast.c b/sys/src/cmd/python/Python/ast.c new file mode 100644 index 000000000..67f45ed06 --- /dev/null +++ b/sys/src/cmd/python/Python/ast.c @@ -0,0 +1,3292 @@ +/* + * This file includes functions to transform a concrete syntax tree (CST) to + * an abstract syntax tree (AST). The main function is PyAST_FromNode(). + * + */ +#include "Python.h" +#include "Python-ast.h" +#include "grammar.h" +#include "node.h" +#include "pyarena.h" +#include "ast.h" +#include "token.h" +#include "parsetok.h" +#include "graminit.h" + +#include <assert.h> + +/* XXX TO DO + - re-indent this file (should be done) + - internal error checking (freeing memory, etc.) + - syntax errors +*/ + +/* Data structure used internally */ +struct compiling { + char *c_encoding; /* source encoding */ + PyArena *c_arena; /* arena for allocating memeory */ +}; + +static asdl_seq *seq_for_testlist(struct compiling *, const node *); +static expr_ty ast_for_expr(struct compiling *, const node *); +static stmt_ty ast_for_stmt(struct compiling *, const node *); +static asdl_seq *ast_for_suite(struct compiling *, const node *); +static asdl_seq *ast_for_exprlist(struct compiling *, const node *, expr_context_ty); +static expr_ty ast_for_testlist(struct compiling *, const node *); +static expr_ty ast_for_testlist_gexp(struct compiling *, const node *); + +/* Note different signature for ast_for_call */ +static expr_ty ast_for_call(struct compiling *, const node *, expr_ty); + +static PyObject *parsenumber(const char *); +static PyObject *parsestr(const char *s, const char *encoding); +static PyObject *parsestrplus(struct compiling *, const node *n); + +#ifndef LINENO +#define LINENO(n) ((n)->n_lineno) +#endif + +static identifier +new_identifier(const char* n, PyArena *arena) { + PyObject* id = PyString_InternFromString(n); + PyArena_AddPyObject(arena, id); + return id; +} + +#define NEW_IDENTIFIER(n) new_identifier(STR(n), c->c_arena) + +/* This routine provides an invalid object for the syntax error. + The outermost routine must unpack this error and create the + proper object. We do this so that we don't have to pass + the filename to everything function. + + XXX Maybe we should just pass the filename... +*/ + +static int +ast_error(const node *n, const char *errstr) +{ + PyObject *u = Py_BuildValue("zi", errstr, LINENO(n)); + if (!u) + return 0; + PyErr_SetObject(PyExc_SyntaxError, u); + Py_DECREF(u); + return 0; +} + +static void +ast_error_finish(const char *filename) +{ + PyObject *type, *value, *tback, *errstr, *loc, *tmp; + long lineno; + + assert(PyErr_Occurred()); + if (!PyErr_ExceptionMatches(PyExc_SyntaxError)) + return; + + PyErr_Fetch(&type, &value, &tback); + errstr = PyTuple_GetItem(value, 0); + if (!errstr) + return; + Py_INCREF(errstr); + lineno = PyInt_AsLong(PyTuple_GetItem(value, 1)); + if (lineno == -1) { + Py_DECREF(errstr); + return; + } + Py_DECREF(value); + + loc = PyErr_ProgramText(filename, lineno); + if (!loc) { + Py_INCREF(Py_None); + loc = Py_None; + } + tmp = Py_BuildValue("(zlOO)", filename, lineno, Py_None, loc); + Py_DECREF(loc); + if (!tmp) { + Py_DECREF(errstr); + return; + } + value = PyTuple_Pack(2, errstr, tmp); + Py_DECREF(errstr); + Py_DECREF(tmp); + if (!value) + return; + PyErr_Restore(type, value, tback); +} + +/* num_stmts() returns number of contained statements. + + Use this routine to determine how big a sequence is needed for + the statements in a parse tree. Its raison d'etre is this bit of + grammar: + + stmt: simple_stmt | compound_stmt + simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE + + A simple_stmt can contain multiple small_stmt elements joined + by semicolons. If the arg is a simple_stmt, the number of + small_stmt elements is returned. +*/ + +static int +num_stmts(const node *n) +{ + int i, l; + node *ch; + + switch (TYPE(n)) { + case single_input: + if (TYPE(CHILD(n, 0)) == NEWLINE) + return 0; + else + return num_stmts(CHILD(n, 0)); + case file_input: + l = 0; + for (i = 0; i < NCH(n); i++) { + ch = CHILD(n, i); + if (TYPE(ch) == stmt) + l += num_stmts(ch); + } + return l; + case stmt: + return num_stmts(CHILD(n, 0)); + case compound_stmt: + return 1; + case simple_stmt: + return NCH(n) / 2; /* Divide by 2 to remove count of semi-colons */ + case suite: + if (NCH(n) == 1) + return num_stmts(CHILD(n, 0)); + else { + l = 0; + for (i = 2; i < (NCH(n) - 1); i++) + l += num_stmts(CHILD(n, i)); + return l; + } + default: { + char buf[128]; + + sprintf(buf, "Non-statement found: %d %d\n", + TYPE(n), NCH(n)); + Py_FatalError(buf); + } + } + assert(0); + return 0; +} + +/* Transform the CST rooted at node * to the appropriate AST +*/ + +mod_ty +PyAST_FromNode(const node *n, PyCompilerFlags *flags, const char *filename, + PyArena *arena) +{ + int i, j, k, num; + asdl_seq *stmts = NULL; + stmt_ty s; + node *ch; + struct compiling c; + + if (flags && flags->cf_flags & PyCF_SOURCE_IS_UTF8) { + c.c_encoding = "utf-8"; + if (TYPE(n) == encoding_decl) { + ast_error(n, "encoding declaration in Unicode string"); + goto error; + } + } else if (TYPE(n) == encoding_decl) { + c.c_encoding = STR(n); + n = CHILD(n, 0); + } else { + c.c_encoding = NULL; + } + c.c_arena = arena; + + k = 0; + switch (TYPE(n)) { + case file_input: + stmts = asdl_seq_new(num_stmts(n), arena); + if (!stmts) + return NULL; + for (i = 0; i < NCH(n) - 1; i++) { + ch = CHILD(n, i); + if (TYPE(ch) == NEWLINE) + continue; + REQ(ch, stmt); + num = num_stmts(ch); + if (num == 1) { + s = ast_for_stmt(&c, ch); + if (!s) + goto error; + asdl_seq_SET(stmts, k++, s); + } + else { + ch = CHILD(ch, 0); + REQ(ch, simple_stmt); + for (j = 0; j < num; j++) { + s = ast_for_stmt(&c, CHILD(ch, j * 2)); + if (!s) + goto error; + asdl_seq_SET(stmts, k++, s); + } + } + } + return Module(stmts, arena); + case eval_input: { + expr_ty testlist_ast; + + /* XXX Why not gen_for here? */ + testlist_ast = ast_for_testlist(&c, CHILD(n, 0)); + if (!testlist_ast) + goto error; + return Expression(testlist_ast, arena); + } + case single_input: + if (TYPE(CHILD(n, 0)) == NEWLINE) { + stmts = asdl_seq_new(1, arena); + if (!stmts) + goto error; + asdl_seq_SET(stmts, 0, Pass(n->n_lineno, n->n_col_offset, + arena)); + return Interactive(stmts, arena); + } + else { + n = CHILD(n, 0); + num = num_stmts(n); + stmts = asdl_seq_new(num, arena); + if (!stmts) + goto error; + if (num == 1) { + s = ast_for_stmt(&c, n); + if (!s) + goto error; + asdl_seq_SET(stmts, 0, s); + } + else { + /* Only a simple_stmt can contain multiple statements. */ + REQ(n, simple_stmt); + for (i = 0; i < NCH(n); i += 2) { + if (TYPE(CHILD(n, i)) == NEWLINE) + break; + s = ast_for_stmt(&c, CHILD(n, i)); + if (!s) + goto error; + asdl_seq_SET(stmts, i / 2, s); + } + } + + return Interactive(stmts, arena); + } + default: + goto error; + } + error: + ast_error_finish(filename); + return NULL; +} + +/* Return the AST repr. of the operator represented as syntax (|, ^, etc.) +*/ + +static operator_ty +get_operator(const node *n) +{ + switch (TYPE(n)) { + case VBAR: + return BitOr; + case CIRCUMFLEX: + return BitXor; + case AMPER: + return BitAnd; + case LEFTSHIFT: + return LShift; + case RIGHTSHIFT: + return RShift; + case PLUS: + return Add; + case MINUS: + return Sub; + case STAR: + return Mult; + case SLASH: + return Div; + case DOUBLESLASH: + return FloorDiv; + case PERCENT: + return Mod; + default: + return (operator_ty)0; + } +} + +/* Set the context ctx for expr_ty e, recursively traversing e. + + Only sets context for expr kinds that "can appear in assignment context" + (according to ../Parser/Python.asdl). For other expr kinds, it sets + an appropriate syntax error and returns false. +*/ + +static int +set_context(expr_ty e, expr_context_ty ctx, const node *n) +{ + asdl_seq *s = NULL; + /* If a particular expression type can't be used for assign / delete, + set expr_name to its name and an error message will be generated. + */ + const char* expr_name = NULL; + + /* The ast defines augmented store and load contexts, but the + implementation here doesn't actually use them. The code may be + a little more complex than necessary as a result. It also means + that expressions in an augmented assignment have a Store context. + Consider restructuring so that augmented assignment uses + set_context(), too. + */ + assert(ctx != AugStore && ctx != AugLoad); + + switch (e->kind) { + case Attribute_kind: + if (ctx == Store && + !strcmp(PyString_AS_STRING(e->v.Attribute.attr), "None")) { + return ast_error(n, "assignment to None"); + } + e->v.Attribute.ctx = ctx; + break; + case Subscript_kind: + e->v.Subscript.ctx = ctx; + break; + case Name_kind: + if (ctx == Store && + !strcmp(PyString_AS_STRING(e->v.Name.id), "None")) { + return ast_error(n, "assignment to None"); + } + e->v.Name.ctx = ctx; + break; + case List_kind: + e->v.List.ctx = ctx; + s = e->v.List.elts; + break; + case Tuple_kind: + if (asdl_seq_LEN(e->v.Tuple.elts) == 0) + return ast_error(n, "can't assign to ()"); + e->v.Tuple.ctx = ctx; + s = e->v.Tuple.elts; + break; + case Lambda_kind: + expr_name = "lambda"; + break; + case Call_kind: + expr_name = "function call"; + break; + case BoolOp_kind: + case BinOp_kind: + case UnaryOp_kind: + expr_name = "operator"; + break; + case GeneratorExp_kind: + expr_name = "generator expression"; + break; + case Yield_kind: + expr_name = "yield expression"; + break; + case ListComp_kind: + expr_name = "list comprehension"; + break; + case Dict_kind: + case Num_kind: + case Str_kind: + expr_name = "literal"; + break; + case Compare_kind: + expr_name = "comparison"; + break; + case Repr_kind: + expr_name = "repr"; + break; + case IfExp_kind: + expr_name = "conditional expression"; + break; + default: + PyErr_Format(PyExc_SystemError, + "unexpected expression in assignment %d (line %d)", + e->kind, e->lineno); + return 0; + } + /* Check for error string set by switch */ + if (expr_name) { + char buf[300]; + PyOS_snprintf(buf, sizeof(buf), + "can't %s %s", + ctx == Store ? "assign to" : "delete", + expr_name); + return ast_error(n, buf); + } + + /* If the LHS is a list or tuple, we need to set the assignment + context for all the contained elements. + */ + if (s) { + int i; + + for (i = 0; i < asdl_seq_LEN(s); i++) { + if (!set_context((expr_ty)asdl_seq_GET(s, i), ctx, n)) + return 0; + } + } + return 1; +} + +static operator_ty +ast_for_augassign(const node *n) +{ + REQ(n, augassign); + n = CHILD(n, 0); + switch (STR(n)[0]) { + case '+': + return Add; + case '-': + return Sub; + case '/': + if (STR(n)[1] == '/') + return FloorDiv; + else + return Div; + case '%': + return Mod; + case '<': + return LShift; + case '>': + return RShift; + case '&': + return BitAnd; + case '^': + return BitXor; + case '|': + return BitOr; + case '*': + if (STR(n)[1] == '*') + return Pow; + else + return Mult; + default: + PyErr_Format(PyExc_SystemError, "invalid augassign: %s", STR(n)); + return (operator_ty)0; + } +} + +static cmpop_ty +ast_for_comp_op(const node *n) +{ + /* comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is' + |'is' 'not' + */ + REQ(n, comp_op); + if (NCH(n) == 1) { + n = CHILD(n, 0); + switch (TYPE(n)) { + case LESS: + return Lt; + case GREATER: + return Gt; + case EQEQUAL: /* == */ + return Eq; + case LESSEQUAL: + return LtE; + case GREATEREQUAL: + return GtE; + case NOTEQUAL: + return NotEq; + case NAME: + if (strcmp(STR(n), "in") == 0) + return In; + if (strcmp(STR(n), "is") == 0) + return Is; + default: + PyErr_Format(PyExc_SystemError, "invalid comp_op: %s", + STR(n)); + return (cmpop_ty)0; + } + } + else if (NCH(n) == 2) { + /* handle "not in" and "is not" */ + switch (TYPE(CHILD(n, 0))) { + case NAME: + if (strcmp(STR(CHILD(n, 1)), "in") == 0) + return NotIn; + if (strcmp(STR(CHILD(n, 0)), "is") == 0) + return IsNot; + default: + PyErr_Format(PyExc_SystemError, "invalid comp_op: %s %s", + STR(CHILD(n, 0)), STR(CHILD(n, 1))); + return (cmpop_ty)0; + } + } + PyErr_Format(PyExc_SystemError, "invalid comp_op: has %d children", + NCH(n)); + return (cmpop_ty)0; +} + +static asdl_seq * +seq_for_testlist(struct compiling *c, const node *n) +{ + /* testlist: test (',' test)* [','] */ + asdl_seq *seq; + expr_ty expression; + int i; + assert(TYPE(n) == testlist + || TYPE(n) == listmaker + || TYPE(n) == testlist_gexp + || TYPE(n) == testlist_safe + || TYPE(n) == testlist1 + ); + + seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!seq) + return NULL; + + for (i = 0; i < NCH(n); i += 2) { + assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == old_test); + + expression = ast_for_expr(c, CHILD(n, i)); + if (!expression) + return NULL; + + assert(i / 2 < seq->size); + asdl_seq_SET(seq, i / 2, expression); + } + return seq; +} + +static expr_ty +compiler_complex_args(struct compiling *c, const node *n) +{ + int i, len = (NCH(n) + 1) / 2; + expr_ty result; + asdl_seq *args = asdl_seq_new(len, c->c_arena); + if (!args) + return NULL; + + /* fpdef: NAME | '(' fplist ')' + fplist: fpdef (',' fpdef)* [','] + */ + REQ(n, fplist); + for (i = 0; i < len; i++) { + const node *fpdef_node = CHILD(n, 2*i); + const node *child; + expr_ty arg; +set_name: + /* fpdef_node is either a NAME or an fplist */ + child = CHILD(fpdef_node, 0); + if (TYPE(child) == NAME) { + if (!strcmp(STR(child), "None")) { + ast_error(child, "assignment to None"); + return NULL; + } + arg = Name(NEW_IDENTIFIER(child), Store, LINENO(child), + child->n_col_offset, c->c_arena); + } + else { + assert(TYPE(fpdef_node) == fpdef); + /* fpdef_node[0] is not a name, so it must be a '(', get CHILD[1] */ + child = CHILD(fpdef_node, 1); + assert(TYPE(child) == fplist); + /* NCH == 1 means we have (x), we need to elide the extra parens */ + if (NCH(child) == 1) { + fpdef_node = CHILD(child, 0); + assert(TYPE(fpdef_node) == fpdef); + goto set_name; + } + arg = compiler_complex_args(c, child); + } + asdl_seq_SET(args, i, arg); + } + + result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); + if (!set_context(result, Store, n)) + return NULL; + return result; +} + + +/* Create AST for argument list. */ + +static arguments_ty +ast_for_arguments(struct compiling *c, const node *n) +{ + /* parameters: '(' [varargslist] ')' + varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] + | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] + */ + int i, j, k, n_args = 0, n_defaults = 0, found_default = 0; + asdl_seq *args, *defaults; + identifier vararg = NULL, kwarg = NULL; + node *ch; + + if (TYPE(n) == parameters) { + if (NCH(n) == 2) /* () as argument list */ + return arguments(NULL, NULL, NULL, NULL, c->c_arena); + n = CHILD(n, 1); + } + REQ(n, varargslist); + + /* first count the number of normal args & defaults */ + for (i = 0; i < NCH(n); i++) { + ch = CHILD(n, i); + if (TYPE(ch) == fpdef) + n_args++; + if (TYPE(ch) == EQUAL) + n_defaults++; + } + args = (n_args ? asdl_seq_new(n_args, c->c_arena) : NULL); + if (!args && n_args) + return NULL; /* Don't need to goto error; no objects allocated */ + defaults = (n_defaults ? asdl_seq_new(n_defaults, c->c_arena) : NULL); + if (!defaults && n_defaults) + return NULL; /* Don't need to goto error; no objects allocated */ + + /* fpdef: NAME | '(' fplist ')' + fplist: fpdef (',' fpdef)* [','] + */ + i = 0; + j = 0; /* index for defaults */ + k = 0; /* index for args */ + while (i < NCH(n)) { + ch = CHILD(n, i); + switch (TYPE(ch)) { + case fpdef: + handle_fpdef: + /* XXX Need to worry about checking if TYPE(CHILD(n, i+1)) is + anything other than EQUAL or a comma? */ + /* XXX Should NCH(n) check be made a separate check? */ + if (i + 1 < NCH(n) && TYPE(CHILD(n, i + 1)) == EQUAL) { + expr_ty expression = ast_for_expr(c, CHILD(n, i + 2)); + if (!expression) + goto error; + assert(defaults != NULL); + asdl_seq_SET(defaults, j++, expression); + i += 2; + found_default = 1; + } + else if (found_default) { + ast_error(n, + "non-default argument follows default argument"); + goto error; + } + if (NCH(ch) == 3) { + ch = CHILD(ch, 1); + /* def foo((x)): is not complex, special case. */ + if (NCH(ch) != 1) { + /* We have complex arguments, setup for unpacking. */ + asdl_seq_SET(args, k++, compiler_complex_args(c, ch)); + } else { + /* def foo((x)): setup for checking NAME below. */ + /* Loop because there can be many parens and tuple + upacking mixed in. */ + ch = CHILD(ch, 0); + assert(TYPE(ch) == fpdef); + goto handle_fpdef; + } + } + if (TYPE(CHILD(ch, 0)) == NAME) { + expr_ty name; + if (!strcmp(STR(CHILD(ch, 0)), "None")) { + ast_error(CHILD(ch, 0), "assignment to None"); + goto error; + } + name = Name(NEW_IDENTIFIER(CHILD(ch, 0)), + Param, LINENO(ch), ch->n_col_offset, + c->c_arena); + if (!name) + goto error; + asdl_seq_SET(args, k++, name); + + } + i += 2; /* the name and the comma */ + break; + case STAR: + if (!strcmp(STR(CHILD(n, i+1)), "None")) { + ast_error(CHILD(n, i+1), "assignment to None"); + goto error; + } + vararg = NEW_IDENTIFIER(CHILD(n, i+1)); + i += 3; + break; + case DOUBLESTAR: + if (!strcmp(STR(CHILD(n, i+1)), "None")) { + ast_error(CHILD(n, i+1), "assignment to None"); + goto error; + } + kwarg = NEW_IDENTIFIER(CHILD(n, i+1)); + i += 3; + break; + default: + PyErr_Format(PyExc_SystemError, + "unexpected node in varargslist: %d @ %d", + TYPE(ch), i); + goto error; + } + } + + return arguments(args, vararg, kwarg, defaults, c->c_arena); + + error: + Py_XDECREF(vararg); + Py_XDECREF(kwarg); + return NULL; +} + +static expr_ty +ast_for_dotted_name(struct compiling *c, const node *n) +{ + expr_ty e; + identifier id; + int lineno, col_offset; + int i; + + REQ(n, dotted_name); + + lineno = LINENO(n); + col_offset = n->n_col_offset; + + id = NEW_IDENTIFIER(CHILD(n, 0)); + if (!id) + return NULL; + e = Name(id, Load, lineno, col_offset, c->c_arena); + if (!e) + return NULL; + + for (i = 2; i < NCH(n); i+=2) { + id = NEW_IDENTIFIER(CHILD(n, i)); + if (!id) + return NULL; + e = Attribute(e, id, Load, lineno, col_offset, c->c_arena); + if (!e) + return NULL; + } + + return e; +} + +static expr_ty +ast_for_decorator(struct compiling *c, const node *n) +{ + /* decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE */ + expr_ty d = NULL; + expr_ty name_expr; + + REQ(n, decorator); + REQ(CHILD(n, 0), AT); + REQ(RCHILD(n, -1), NEWLINE); + + name_expr = ast_for_dotted_name(c, CHILD(n, 1)); + if (!name_expr) + return NULL; + + if (NCH(n) == 3) { /* No arguments */ + d = name_expr; + name_expr = NULL; + } + else if (NCH(n) == 5) { /* Call with no arguments */ + d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n), + n->n_col_offset, c->c_arena); + if (!d) + return NULL; + name_expr = NULL; + } + else { + d = ast_for_call(c, CHILD(n, 3), name_expr); + if (!d) + return NULL; + name_expr = NULL; + } + + return d; +} + +static asdl_seq* +ast_for_decorators(struct compiling *c, const node *n) +{ + asdl_seq* decorator_seq; + expr_ty d; + int i; + + REQ(n, decorators); + decorator_seq = asdl_seq_new(NCH(n), c->c_arena); + if (!decorator_seq) + return NULL; + + for (i = 0; i < NCH(n); i++) { + d = ast_for_decorator(c, CHILD(n, i)); + if (!d) + return NULL; + asdl_seq_SET(decorator_seq, i, d); + } + return decorator_seq; +} + +static stmt_ty +ast_for_funcdef(struct compiling *c, const node *n) +{ + /* funcdef: 'def' [decorators] NAME parameters ':' suite */ + identifier name; + arguments_ty args; + asdl_seq *body; + asdl_seq *decorator_seq = NULL; + int name_i; + + REQ(n, funcdef); + + if (NCH(n) == 6) { /* decorators are present */ + decorator_seq = ast_for_decorators(c, CHILD(n, 0)); + if (!decorator_seq) + return NULL; + name_i = 2; + } + else { + name_i = 1; + } + + name = NEW_IDENTIFIER(CHILD(n, name_i)); + if (!name) + return NULL; + else if (!strcmp(STR(CHILD(n, name_i)), "None")) { + ast_error(CHILD(n, name_i), "assignment to None"); + return NULL; + } + args = ast_for_arguments(c, CHILD(n, name_i + 1)); + if (!args) + return NULL; + body = ast_for_suite(c, CHILD(n, name_i + 3)); + if (!body) + return NULL; + + return FunctionDef(name, args, body, decorator_seq, LINENO(n), + n->n_col_offset, c->c_arena); +} + +static expr_ty +ast_for_lambdef(struct compiling *c, const node *n) +{ + /* lambdef: 'lambda' [varargslist] ':' test */ + arguments_ty args; + expr_ty expression; + + if (NCH(n) == 3) { + args = arguments(NULL, NULL, NULL, NULL, c->c_arena); + if (!args) + return NULL; + expression = ast_for_expr(c, CHILD(n, 2)); + if (!expression) + return NULL; + } + else { + args = ast_for_arguments(c, CHILD(n, 1)); + if (!args) + return NULL; + expression = ast_for_expr(c, CHILD(n, 3)); + if (!expression) + return NULL; + } + + return Lambda(args, expression, LINENO(n), n->n_col_offset, c->c_arena); +} + +static expr_ty +ast_for_ifexpr(struct compiling *c, const node *n) +{ + /* test: or_test 'if' or_test 'else' test */ + expr_ty expression, body, orelse; + + assert(NCH(n) == 5); + body = ast_for_expr(c, CHILD(n, 0)); + if (!body) + return NULL; + expression = ast_for_expr(c, CHILD(n, 2)); + if (!expression) + return NULL; + orelse = ast_for_expr(c, CHILD(n, 4)); + if (!orelse) + return NULL; + return IfExp(expression, body, orelse, LINENO(n), n->n_col_offset, + c->c_arena); +} + +/* Count the number of 'for' loop in a list comprehension. + + Helper for ast_for_listcomp(). +*/ + +static int +count_list_fors(const node *n) +{ + int n_fors = 0; + node *ch = CHILD(n, 1); + + count_list_for: + n_fors++; + REQ(ch, list_for); + if (NCH(ch) == 5) + ch = CHILD(ch, 4); + else + return n_fors; + count_list_iter: + REQ(ch, list_iter); + ch = CHILD(ch, 0); + if (TYPE(ch) == list_for) + goto count_list_for; + else if (TYPE(ch) == list_if) { + if (NCH(ch) == 3) { + ch = CHILD(ch, 2); + goto count_list_iter; + } + else + return n_fors; + } + + /* Should never be reached */ + PyErr_SetString(PyExc_SystemError, "logic error in count_list_fors"); + return -1; +} + +/* Count the number of 'if' statements in a list comprehension. + + Helper for ast_for_listcomp(). +*/ + +static int +count_list_ifs(const node *n) +{ + int n_ifs = 0; + + count_list_iter: + REQ(n, list_iter); + if (TYPE(CHILD(n, 0)) == list_for) + return n_ifs; + n = CHILD(n, 0); + REQ(n, list_if); + n_ifs++; + if (NCH(n) == 2) + return n_ifs; + n = CHILD(n, 2); + goto count_list_iter; +} + +static expr_ty +ast_for_listcomp(struct compiling *c, const node *n) +{ + /* listmaker: test ( list_for | (',' test)* [','] ) + list_for: 'for' exprlist 'in' testlist_safe [list_iter] + list_iter: list_for | list_if + list_if: 'if' test [list_iter] + testlist_safe: test [(',' test)+ [',']] + */ + expr_ty elt; + asdl_seq *listcomps; + int i, n_fors; + node *ch; + + REQ(n, listmaker); + assert(NCH(n) > 1); + + elt = ast_for_expr(c, CHILD(n, 0)); + if (!elt) + return NULL; + + n_fors = count_list_fors(n); + if (n_fors == -1) + return NULL; + + listcomps = asdl_seq_new(n_fors, c->c_arena); + if (!listcomps) + return NULL; + + ch = CHILD(n, 1); + for (i = 0; i < n_fors; i++) { + comprehension_ty lc; + asdl_seq *t; + expr_ty expression; + node *for_ch; + + REQ(ch, list_for); + + for_ch = CHILD(ch, 1); + t = ast_for_exprlist(c, for_ch, Store); + if (!t) + return NULL; + expression = ast_for_testlist(c, CHILD(ch, 3)); + if (!expression) + return NULL; + + /* Check the # of children rather than the length of t, since + [x for x, in ... ] has 1 element in t, but still requires a Tuple. */ + if (NCH(for_ch) == 1) + lc = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL, + c->c_arena); + else + lc = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, + c->c_arena), + expression, NULL, c->c_arena); + if (!lc) + return NULL; + + if (NCH(ch) == 5) { + int j, n_ifs; + asdl_seq *ifs; + expr_ty list_for_expr; + + ch = CHILD(ch, 4); + n_ifs = count_list_ifs(ch); + if (n_ifs == -1) + return NULL; + + ifs = asdl_seq_new(n_ifs, c->c_arena); + if (!ifs) + return NULL; + + for (j = 0; j < n_ifs; j++) { + REQ(ch, list_iter); + ch = CHILD(ch, 0); + REQ(ch, list_if); + + list_for_expr = ast_for_expr(c, CHILD(ch, 1)); + if (!list_for_expr) + return NULL; + + asdl_seq_SET(ifs, j, list_for_expr); + if (NCH(ch) == 3) + ch = CHILD(ch, 2); + } + /* on exit, must guarantee that ch is a list_for */ + if (TYPE(ch) == list_iter) + ch = CHILD(ch, 0); + lc->ifs = ifs; + } + asdl_seq_SET(listcomps, i, lc); + } + + return ListComp(elt, listcomps, LINENO(n), n->n_col_offset, c->c_arena); +} + +/* + Count the number of 'for' loops in a generator expression. + + Helper for ast_for_genexp(). +*/ + +static int +count_gen_fors(const node *n) +{ + int n_fors = 0; + node *ch = CHILD(n, 1); + + count_gen_for: + n_fors++; + REQ(ch, gen_for); + if (NCH(ch) == 5) + ch = CHILD(ch, 4); + else + return n_fors; + count_gen_iter: + REQ(ch, gen_iter); + ch = CHILD(ch, 0); + if (TYPE(ch) == gen_for) + goto count_gen_for; + else if (TYPE(ch) == gen_if) { + if (NCH(ch) == 3) { + ch = CHILD(ch, 2); + goto count_gen_iter; + } + else + return n_fors; + } + + /* Should never be reached */ + PyErr_SetString(PyExc_SystemError, + "logic error in count_gen_fors"); + return -1; +} + +/* Count the number of 'if' statements in a generator expression. + + Helper for ast_for_genexp(). +*/ + +static int +count_gen_ifs(const node *n) +{ + int n_ifs = 0; + + while (1) { + REQ(n, gen_iter); + if (TYPE(CHILD(n, 0)) == gen_for) + return n_ifs; + n = CHILD(n, 0); + REQ(n, gen_if); + n_ifs++; + if (NCH(n) == 2) + return n_ifs; + n = CHILD(n, 2); + } +} + +/* TODO(jhylton): Combine with list comprehension code? */ +static expr_ty +ast_for_genexp(struct compiling *c, const node *n) +{ + /* testlist_gexp: test ( gen_for | (',' test)* [','] ) + argument: [test '='] test [gen_for] # Really [keyword '='] test */ + expr_ty elt; + asdl_seq *genexps; + int i, n_fors; + node *ch; + + assert(TYPE(n) == (testlist_gexp) || TYPE(n) == (argument)); + assert(NCH(n) > 1); + + elt = ast_for_expr(c, CHILD(n, 0)); + if (!elt) + return NULL; + + n_fors = count_gen_fors(n); + if (n_fors == -1) + return NULL; + + genexps = asdl_seq_new(n_fors, c->c_arena); + if (!genexps) + return NULL; + + ch = CHILD(n, 1); + for (i = 0; i < n_fors; i++) { + comprehension_ty ge; + asdl_seq *t; + expr_ty expression; + node *for_ch; + + REQ(ch, gen_for); + + for_ch = CHILD(ch, 1); + t = ast_for_exprlist(c, for_ch, Store); + if (!t) + return NULL; + expression = ast_for_expr(c, CHILD(ch, 3)); + if (!expression) + return NULL; + + /* Check the # of children rather than the length of t, since + (x for x, in ...) has 1 element in t, but still requires a Tuple. */ + if (NCH(for_ch) == 1) + ge = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, + NULL, c->c_arena); + else + ge = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, + c->c_arena), + expression, NULL, c->c_arena); + + if (!ge) + return NULL; + + if (NCH(ch) == 5) { + int j, n_ifs; + asdl_seq *ifs; + + ch = CHILD(ch, 4); + n_ifs = count_gen_ifs(ch); + if (n_ifs == -1) + return NULL; + + ifs = asdl_seq_new(n_ifs, c->c_arena); + if (!ifs) + return NULL; + + for (j = 0; j < n_ifs; j++) { + REQ(ch, gen_iter); + ch = CHILD(ch, 0); + REQ(ch, gen_if); + + expression = ast_for_expr(c, CHILD(ch, 1)); + if (!expression) + return NULL; + asdl_seq_SET(ifs, j, expression); + if (NCH(ch) == 3) + ch = CHILD(ch, 2); + } + /* on exit, must guarantee that ch is a gen_for */ + if (TYPE(ch) == gen_iter) + ch = CHILD(ch, 0); + ge->ifs = ifs; + } + asdl_seq_SET(genexps, i, ge); + } + + return GeneratorExp(elt, genexps, LINENO(n), n->n_col_offset, c->c_arena); +} + +static expr_ty +ast_for_atom(struct compiling *c, const node *n) +{ + /* atom: '(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']' + | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+ + */ + node *ch = CHILD(n, 0); + + switch (TYPE(ch)) { + case NAME: + /* All names start in Load context, but may later be + changed. */ + return Name(NEW_IDENTIFIER(ch), Load, LINENO(n), n->n_col_offset, c->c_arena); + case STRING: { + PyObject *str = parsestrplus(c, n); + if (!str) + return NULL; + + PyArena_AddPyObject(c->c_arena, str); + return Str(str, LINENO(n), n->n_col_offset, c->c_arena); + } + case NUMBER: { + PyObject *pynum = parsenumber(STR(ch)); + if (!pynum) + return NULL; + + PyArena_AddPyObject(c->c_arena, pynum); + return Num(pynum, LINENO(n), n->n_col_offset, c->c_arena); + } + case LPAR: /* some parenthesized expressions */ + ch = CHILD(n, 1); + + if (TYPE(ch) == RPAR) + return Tuple(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena); + + if (TYPE(ch) == yield_expr) + return ast_for_expr(c, ch); + + if ((NCH(ch) > 1) && (TYPE(CHILD(ch, 1)) == gen_for)) + return ast_for_genexp(c, ch); + + return ast_for_testlist_gexp(c, ch); + case LSQB: /* list (or list comprehension) */ + ch = CHILD(n, 1); + + if (TYPE(ch) == RSQB) + return List(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena); + + REQ(ch, listmaker); + if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) { + asdl_seq *elts = seq_for_testlist(c, ch); + if (!elts) + return NULL; + + return List(elts, Load, LINENO(n), n->n_col_offset, c->c_arena); + } + else + return ast_for_listcomp(c, ch); + case LBRACE: { + /* dictmaker: test ':' test (',' test ':' test)* [','] */ + int i, size; + asdl_seq *keys, *values; + + ch = CHILD(n, 1); + size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ + keys = asdl_seq_new(size, c->c_arena); + if (!keys) + return NULL; + + values = asdl_seq_new(size, c->c_arena); + if (!values) + return NULL; + + for (i = 0; i < NCH(ch); i += 4) { + expr_ty expression; + + expression = ast_for_expr(c, CHILD(ch, i)); + if (!expression) + return NULL; + + asdl_seq_SET(keys, i / 4, expression); + + expression = ast_for_expr(c, CHILD(ch, i + 2)); + if (!expression) + return NULL; + + asdl_seq_SET(values, i / 4, expression); + } + return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena); + } + case BACKQUOTE: { /* repr */ + expr_ty expression = ast_for_testlist(c, CHILD(n, 1)); + if (!expression) + return NULL; + + return Repr(expression, LINENO(n), n->n_col_offset, c->c_arena); + } + default: + PyErr_Format(PyExc_SystemError, "unhandled atom %d", TYPE(ch)); + return NULL; + } +} + +static slice_ty +ast_for_slice(struct compiling *c, const node *n) +{ + node *ch; + expr_ty lower = NULL, upper = NULL, step = NULL; + + REQ(n, subscript); + + /* + subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] + sliceop: ':' [test] + */ + ch = CHILD(n, 0); + if (TYPE(ch) == DOT) + return Ellipsis(c->c_arena); + + if (NCH(n) == 1 && TYPE(ch) == test) { + /* 'step' variable hold no significance in terms of being used over + other vars */ + step = ast_for_expr(c, ch); + if (!step) + return NULL; + + return Index(step, c->c_arena); + } + + if (TYPE(ch) == test) { + lower = ast_for_expr(c, ch); + if (!lower) + return NULL; + } + + /* If there's an upper bound it's in the second or third position. */ + if (TYPE(ch) == COLON) { + if (NCH(n) > 1) { + node *n2 = CHILD(n, 1); + + if (TYPE(n2) == test) { + upper = ast_for_expr(c, n2); + if (!upper) + return NULL; + } + } + } else if (NCH(n) > 2) { + node *n2 = CHILD(n, 2); + + if (TYPE(n2) == test) { + upper = ast_for_expr(c, n2); + if (!upper) + return NULL; + } + } + + ch = CHILD(n, NCH(n) - 1); + if (TYPE(ch) == sliceop) { + if (NCH(ch) == 1) { + /* No expression, so step is None */ + ch = CHILD(ch, 0); + step = Name(new_identifier("None", c->c_arena), Load, + LINENO(ch), ch->n_col_offset, c->c_arena); + if (!step) + return NULL; + } else { + ch = CHILD(ch, 1); + if (TYPE(ch) == test) { + step = ast_for_expr(c, ch); + if (!step) + return NULL; + } + } + } + + return Slice(lower, upper, step, c->c_arena); +} + +static expr_ty +ast_for_binop(struct compiling *c, const node *n) +{ + /* Must account for a sequence of expressions. + How should A op B op C by represented? + BinOp(BinOp(A, op, B), op, C). + */ + + int i, nops; + expr_ty expr1, expr2, result; + operator_ty newoperator; + + expr1 = ast_for_expr(c, CHILD(n, 0)); + if (!expr1) + return NULL; + + expr2 = ast_for_expr(c, CHILD(n, 2)); + if (!expr2) + return NULL; + + newoperator = get_operator(CHILD(n, 1)); + if (!newoperator) + return NULL; + + result = BinOp(expr1, newoperator, expr2, LINENO(n), n->n_col_offset, + c->c_arena); + if (!result) + return NULL; + + nops = (NCH(n) - 1) / 2; + for (i = 1; i < nops; i++) { + expr_ty tmp_result, tmp; + const node* next_oper = CHILD(n, i * 2 + 1); + + newoperator = get_operator(next_oper); + if (!newoperator) + return NULL; + + tmp = ast_for_expr(c, CHILD(n, i * 2 + 2)); + if (!tmp) + return NULL; + + tmp_result = BinOp(result, newoperator, tmp, + LINENO(next_oper), next_oper->n_col_offset, + c->c_arena); + if (!tmp) + return NULL; + result = tmp_result; + } + return result; +} + +static expr_ty +ast_for_trailer(struct compiling *c, const node *n, expr_ty left_expr) +{ + /* trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME + subscriptlist: subscript (',' subscript)* [','] + subscript: '.' '.' '.' | test | [test] ':' [test] [sliceop] + */ + REQ(n, trailer); + if (TYPE(CHILD(n, 0)) == LPAR) { + if (NCH(n) == 2) + return Call(left_expr, NULL, NULL, NULL, NULL, LINENO(n), + n->n_col_offset, c->c_arena); + else + return ast_for_call(c, CHILD(n, 1), left_expr); + } + else if (TYPE(CHILD(n, 0)) == DOT ) { + return Attribute(left_expr, NEW_IDENTIFIER(CHILD(n, 1)), Load, + LINENO(n), n->n_col_offset, c->c_arena); + } + else { + REQ(CHILD(n, 0), LSQB); + REQ(CHILD(n, 2), RSQB); + n = CHILD(n, 1); + if (NCH(n) == 1) { + slice_ty slc = ast_for_slice(c, CHILD(n, 0)); + if (!slc) + return NULL; + return Subscript(left_expr, slc, Load, LINENO(n), n->n_col_offset, + c->c_arena); + } + else { + /* The grammar is ambiguous here. The ambiguity is resolved + by treating the sequence as a tuple literal if there are + no slice features. + */ + int j; + slice_ty slc; + expr_ty e; + bool simple = true; + asdl_seq *slices, *elts; + slices = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!slices) + return NULL; + for (j = 0; j < NCH(n); j += 2) { + slc = ast_for_slice(c, CHILD(n, j)); + if (!slc) + return NULL; + if (slc->kind != Index_kind) + simple = false; + asdl_seq_SET(slices, j / 2, slc); + } + if (!simple) { + return Subscript(left_expr, ExtSlice(slices, c->c_arena), + Load, LINENO(n), n->n_col_offset, c->c_arena); + } + /* extract Index values and put them in a Tuple */ + elts = asdl_seq_new(asdl_seq_LEN(slices), c->c_arena); + if (!elts) + return NULL; + for (j = 0; j < asdl_seq_LEN(slices); ++j) { + slc = (slice_ty)asdl_seq_GET(slices, j); + assert(slc->kind == Index_kind && slc->v.Index.value); + asdl_seq_SET(elts, j, slc->v.Index.value); + } + e = Tuple(elts, Load, LINENO(n), n->n_col_offset, c->c_arena); + if (!e) + return NULL; + return Subscript(left_expr, Index(e, c->c_arena), + Load, LINENO(n), n->n_col_offset, c->c_arena); + } + } +} + +static expr_ty +ast_for_factor(struct compiling *c, const node *n) +{ + node *pfactor, *ppower, *patom, *pnum; + expr_ty expression; + + /* If the unary - operator is applied to a constant, don't generate + a UNARY_NEGATIVE opcode. Just store the approriate value as a + constant. The peephole optimizer already does something like + this but it doesn't handle the case where the constant is + (sys.maxint - 1). In that case, we want a PyIntObject, not a + PyLongObject. + */ + if (TYPE(CHILD(n, 0)) == MINUS + && NCH(n) == 2 + && TYPE((pfactor = CHILD(n, 1))) == factor + && NCH(pfactor) == 1 + && TYPE((ppower = CHILD(pfactor, 0))) == power + && NCH(ppower) == 1 + && TYPE((patom = CHILD(ppower, 0))) == atom + && TYPE((pnum = CHILD(patom, 0))) == NUMBER) { + char *s = PyObject_MALLOC(strlen(STR(pnum)) + 2); + if (s == NULL) + return NULL; + s[0] = '-'; + strcpy(s + 1, STR(pnum)); + PyObject_FREE(STR(pnum)); + STR(pnum) = s; + return ast_for_atom(c, patom); + } + + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + + switch (TYPE(CHILD(n, 0))) { + case PLUS: + return UnaryOp(UAdd, expression, LINENO(n), n->n_col_offset, + c->c_arena); + case MINUS: + return UnaryOp(USub, expression, LINENO(n), n->n_col_offset, + c->c_arena); + case TILDE: + return UnaryOp(Invert, expression, LINENO(n), + n->n_col_offset, c->c_arena); + } + PyErr_Format(PyExc_SystemError, "unhandled factor: %d", + TYPE(CHILD(n, 0))); + return NULL; +} + +static expr_ty +ast_for_power(struct compiling *c, const node *n) +{ + /* power: atom trailer* ('**' factor)* + */ + int i; + expr_ty e, tmp; + REQ(n, power); + e = ast_for_atom(c, CHILD(n, 0)); + if (!e) + return NULL; + if (NCH(n) == 1) + return e; + for (i = 1; i < NCH(n); i++) { + node *ch = CHILD(n, i); + if (TYPE(ch) != trailer) + break; + tmp = ast_for_trailer(c, ch, e); + if (!tmp) + return NULL; + tmp->lineno = e->lineno; + tmp->col_offset = e->col_offset; + e = tmp; + } + if (TYPE(CHILD(n, NCH(n) - 1)) == factor) { + expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1)); + if (!f) + return NULL; + tmp = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena); + if (!tmp) + return NULL; + e = tmp; + } + return e; +} + +/* Do not name a variable 'expr'! Will cause a compile error. +*/ + +static expr_ty +ast_for_expr(struct compiling *c, const node *n) +{ + /* handle the full range of simple expressions + test: or_test ['if' or_test 'else' test] | lambdef + or_test: and_test ('or' and_test)* + and_test: not_test ('and' not_test)* + not_test: 'not' not_test | comparison + comparison: expr (comp_op expr)* + expr: xor_expr ('|' xor_expr)* + xor_expr: and_expr ('^' and_expr)* + and_expr: shift_expr ('&' shift_expr)* + shift_expr: arith_expr (('<<'|'>>') arith_expr)* + arith_expr: term (('+'|'-') term)* + term: factor (('*'|'/'|'%'|'//') factor)* + factor: ('+'|'-'|'~') factor | power + power: atom trailer* ('**' factor)* + + As well as modified versions that exist for backward compatibility, + to explicitly allow: + [ x for x in lambda: 0, lambda: 1 ] + (which would be ambiguous without these extra rules) + + old_test: or_test | old_lambdef + old_lambdef: 'lambda' [vararglist] ':' old_test + + */ + + asdl_seq *seq; + int i; + + loop: + switch (TYPE(n)) { + case test: + case old_test: + if (TYPE(CHILD(n, 0)) == lambdef || + TYPE(CHILD(n, 0)) == old_lambdef) + return ast_for_lambdef(c, CHILD(n, 0)); + else if (NCH(n) > 1) + return ast_for_ifexpr(c, n); + /* Fallthrough */ + case or_test: + case and_test: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!seq) + return NULL; + for (i = 0; i < NCH(n); i += 2) { + expr_ty e = ast_for_expr(c, CHILD(n, i)); + if (!e) + return NULL; + asdl_seq_SET(seq, i / 2, e); + } + if (!strcmp(STR(CHILD(n, 1)), "and")) + return BoolOp(And, seq, LINENO(n), n->n_col_offset, + c->c_arena); + assert(!strcmp(STR(CHILD(n, 1)), "or")); + return BoolOp(Or, seq, LINENO(n), n->n_col_offset, c->c_arena); + case not_test: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + else { + expr_ty expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + + return UnaryOp(Not, expression, LINENO(n), n->n_col_offset, + c->c_arena); + } + case comparison: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + else { + expr_ty expression; + asdl_int_seq *ops; + asdl_seq *cmps; + ops = asdl_int_seq_new(NCH(n) / 2, c->c_arena); + if (!ops) + return NULL; + cmps = asdl_seq_new(NCH(n) / 2, c->c_arena); + if (!cmps) { + return NULL; + } + for (i = 1; i < NCH(n); i += 2) { + cmpop_ty newoperator; + + newoperator = ast_for_comp_op(CHILD(n, i)); + if (!newoperator) { + return NULL; + } + + expression = ast_for_expr(c, CHILD(n, i + 1)); + if (!expression) { + return NULL; + } + + asdl_seq_SET(ops, i / 2, newoperator); + asdl_seq_SET(cmps, i / 2, expression); + } + expression = ast_for_expr(c, CHILD(n, 0)); + if (!expression) { + return NULL; + } + + return Compare(expression, ops, cmps, LINENO(n), + n->n_col_offset, c->c_arena); + } + break; + + /* The next five cases all handle BinOps. The main body of code + is the same in each case, but the switch turned inside out to + reuse the code for each type of operator. + */ + case expr: + case xor_expr: + case and_expr: + case shift_expr: + case arith_expr: + case term: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + return ast_for_binop(c, n); + case yield_expr: { + expr_ty exp = NULL; + if (NCH(n) == 2) { + exp = ast_for_testlist(c, CHILD(n, 1)); + if (!exp) + return NULL; + } + return Yield(exp, LINENO(n), n->n_col_offset, c->c_arena); + } + case factor: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + return ast_for_factor(c, n); + case power: + return ast_for_power(c, n); + default: + PyErr_Format(PyExc_SystemError, "unhandled expr: %d", TYPE(n)); + return NULL; + } + /* should never get here unless if error is set */ + return NULL; +} + +static expr_ty +ast_for_call(struct compiling *c, const node *n, expr_ty func) +{ + /* + arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] + | '**' test) + argument: [test '='] test [gen_for] # Really [keyword '='] test + */ + + int i, nargs, nkeywords, ngens; + asdl_seq *args; + asdl_seq *keywords; + expr_ty vararg = NULL, kwarg = NULL; + + REQ(n, arglist); + + nargs = 0; + nkeywords = 0; + ngens = 0; + for (i = 0; i < NCH(n); i++) { + node *ch = CHILD(n, i); + if (TYPE(ch) == argument) { + if (NCH(ch) == 1) + nargs++; + else if (TYPE(CHILD(ch, 1)) == gen_for) + ngens++; + else + nkeywords++; + } + } + if (ngens > 1 || (ngens && (nargs || nkeywords))) { + ast_error(n, "Generator expression must be parenthesized " + "if not sole argument"); + return NULL; + } + + if (nargs + nkeywords + ngens > 255) { + ast_error(n, "more than 255 arguments"); + return NULL; + } + + args = asdl_seq_new(nargs + ngens, c->c_arena); + if (!args) + return NULL; + keywords = asdl_seq_new(nkeywords, c->c_arena); + if (!keywords) + return NULL; + nargs = 0; + nkeywords = 0; + for (i = 0; i < NCH(n); i++) { + node *ch = CHILD(n, i); + if (TYPE(ch) == argument) { + expr_ty e; + if (NCH(ch) == 1) { + if (nkeywords) { + ast_error(CHILD(ch, 0), + "non-keyword arg after keyword arg"); + return NULL; + } + e = ast_for_expr(c, CHILD(ch, 0)); + if (!e) + return NULL; + asdl_seq_SET(args, nargs++, e); + } + else if (TYPE(CHILD(ch, 1)) == gen_for) { + e = ast_for_genexp(c, ch); + if (!e) + return NULL; + asdl_seq_SET(args, nargs++, e); + } + else { + keyword_ty kw; + identifier key; + + /* CHILD(ch, 0) is test, but must be an identifier? */ + e = ast_for_expr(c, CHILD(ch, 0)); + if (!e) + return NULL; + /* f(lambda x: x[0] = 3) ends up getting parsed with + * LHS test = lambda x: x[0], and RHS test = 3. + * SF bug 132313 points out that complaining about a keyword + * then is very confusing. + */ + if (e->kind == Lambda_kind) { + ast_error(CHILD(ch, 0), "lambda cannot contain assignment"); + return NULL; + } else if (e->kind != Name_kind) { + ast_error(CHILD(ch, 0), "keyword can't be an expression"); + return NULL; + } + key = e->v.Name.id; + e = ast_for_expr(c, CHILD(ch, 2)); + if (!e) + return NULL; + kw = keyword(key, e, c->c_arena); + if (!kw) + return NULL; + asdl_seq_SET(keywords, nkeywords++, kw); + } + } + else if (TYPE(ch) == STAR) { + vararg = ast_for_expr(c, CHILD(n, i+1)); + i++; + } + else if (TYPE(ch) == DOUBLESTAR) { + kwarg = ast_for_expr(c, CHILD(n, i+1)); + i++; + } + } + + return Call(func, args, keywords, vararg, kwarg, func->lineno, func->col_offset, c->c_arena); +} + +static expr_ty +ast_for_testlist(struct compiling *c, const node* n) +{ + /* testlist_gexp: test (',' test)* [','] */ + /* testlist: test (',' test)* [','] */ + /* testlist_safe: test (',' test)+ [','] */ + /* testlist1: test (',' test)* */ + assert(NCH(n) > 0); + if (TYPE(n) == testlist_gexp) { + if (NCH(n) > 1) + assert(TYPE(CHILD(n, 1)) != gen_for); + } + else { + assert(TYPE(n) == testlist || + TYPE(n) == testlist_safe || + TYPE(n) == testlist1); + } + if (NCH(n) == 1) + return ast_for_expr(c, CHILD(n, 0)); + else { + asdl_seq *tmp = seq_for_testlist(c, n); + if (!tmp) + return NULL; + return Tuple(tmp, Load, LINENO(n), n->n_col_offset, c->c_arena); + } +} + +static expr_ty +ast_for_testlist_gexp(struct compiling *c, const node* n) +{ + /* testlist_gexp: test ( gen_for | (',' test)* [','] ) */ + /* argument: test [ gen_for ] */ + assert(TYPE(n) == testlist_gexp || TYPE(n) == argument); + if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) + return ast_for_genexp(c, n); + return ast_for_testlist(c, n); +} + +/* like ast_for_testlist() but returns a sequence */ +static asdl_seq* +ast_for_class_bases(struct compiling *c, const node* n) +{ + /* testlist: test (',' test)* [','] */ + assert(NCH(n) > 0); + REQ(n, testlist); + if (NCH(n) == 1) { + expr_ty base; + asdl_seq *bases = asdl_seq_new(1, c->c_arena); + if (!bases) + return NULL; + base = ast_for_expr(c, CHILD(n, 0)); + if (!base) + return NULL; + asdl_seq_SET(bases, 0, base); + return bases; + } + + return seq_for_testlist(c, n); +} + +static stmt_ty +ast_for_expr_stmt(struct compiling *c, const node *n) +{ + REQ(n, expr_stmt); + /* expr_stmt: testlist (augassign (yield_expr|testlist) + | ('=' (yield_expr|testlist))*) + testlist: test (',' test)* [','] + augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' + | '<<=' | '>>=' | '**=' | '//=' + test: ... here starts the operator precendence dance + */ + + if (NCH(n) == 1) { + expr_ty e = ast_for_testlist(c, CHILD(n, 0)); + if (!e) + return NULL; + + return Expr(e, LINENO(n), n->n_col_offset, c->c_arena); + } + else if (TYPE(CHILD(n, 1)) == augassign) { + expr_ty expr1, expr2; + operator_ty newoperator; + node *ch = CHILD(n, 0); + + expr1 = ast_for_testlist(c, ch); + if (!expr1) + return NULL; + /* TODO(nas): Remove duplicated error checks (set_context does it) */ + switch (expr1->kind) { + case GeneratorExp_kind: + ast_error(ch, "augmented assignment to generator " + "expression not possible"); + return NULL; + case Yield_kind: + ast_error(ch, "augmented assignment to yield " + "expression not possible"); + return NULL; + case Name_kind: { + const char *var_name = PyString_AS_STRING(expr1->v.Name.id); + if (var_name[0] == 'N' && !strcmp(var_name, "None")) { + ast_error(ch, "assignment to None"); + return NULL; + } + break; + } + case Attribute_kind: + case Subscript_kind: + break; + default: + ast_error(ch, "illegal expression for augmented " + "assignment"); + return NULL; + } + if (!set_context(expr1, Store, ch)) + return NULL; + + ch = CHILD(n, 2); + if (TYPE(ch) == testlist) + expr2 = ast_for_testlist(c, ch); + else + expr2 = ast_for_expr(c, ch); + if (!expr2) + return NULL; + + newoperator = ast_for_augassign(CHILD(n, 1)); + if (!newoperator) + return NULL; + + return AugAssign(expr1, newoperator, expr2, LINENO(n), n->n_col_offset, c->c_arena); + } + else { + int i; + asdl_seq *targets; + node *value; + expr_ty expression; + + /* a normal assignment */ + REQ(CHILD(n, 1), EQUAL); + targets = asdl_seq_new(NCH(n) / 2, c->c_arena); + if (!targets) + return NULL; + for (i = 0; i < NCH(n) - 2; i += 2) { + expr_ty e; + node *ch = CHILD(n, i); + if (TYPE(ch) == yield_expr) { + ast_error(ch, "assignment to yield expression not possible"); + return NULL; + } + e = ast_for_testlist(c, ch); + + /* set context to assign */ + if (!e) + return NULL; + + if (!set_context(e, Store, CHILD(n, i))) + return NULL; + + asdl_seq_SET(targets, i / 2, e); + } + value = CHILD(n, NCH(n) - 1); + if (TYPE(value) == testlist) + expression = ast_for_testlist(c, value); + else + expression = ast_for_expr(c, value); + if (!expression) + return NULL; + return Assign(targets, expression, LINENO(n), n->n_col_offset, c->c_arena); + } +} + +static stmt_ty +ast_for_print_stmt(struct compiling *c, const node *n) +{ + /* print_stmt: 'print' ( [ test (',' test)* [','] ] + | '>>' test [ (',' test)+ [','] ] ) + */ + expr_ty dest = NULL, expression; + asdl_seq *seq; + bool nl; + int i, j, start = 1; + + REQ(n, print_stmt); + if (NCH(n) >= 2 && TYPE(CHILD(n, 1)) == RIGHTSHIFT) { + dest = ast_for_expr(c, CHILD(n, 2)); + if (!dest) + return NULL; + start = 4; + } + seq = asdl_seq_new((NCH(n) + 1 - start) / 2, c->c_arena); + if (!seq) + return NULL; + for (i = start, j = 0; i < NCH(n); i += 2, ++j) { + expression = ast_for_expr(c, CHILD(n, i)); + if (!expression) + return NULL; + asdl_seq_SET(seq, j, expression); + } + nl = (TYPE(CHILD(n, NCH(n) - 1)) == COMMA) ? false : true; + return Print(dest, seq, nl, LINENO(n), n->n_col_offset, c->c_arena); +} + +static asdl_seq * +ast_for_exprlist(struct compiling *c, const node *n, expr_context_ty context) +{ + asdl_seq *seq; + int i; + expr_ty e; + + REQ(n, exprlist); + + seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!seq) + return NULL; + for (i = 0; i < NCH(n); i += 2) { + e = ast_for_expr(c, CHILD(n, i)); + if (!e) + return NULL; + asdl_seq_SET(seq, i / 2, e); + if (context && !set_context(e, context, CHILD(n, i))) + return NULL; + } + return seq; +} + +static stmt_ty +ast_for_del_stmt(struct compiling *c, const node *n) +{ + asdl_seq *expr_list; + + /* del_stmt: 'del' exprlist */ + REQ(n, del_stmt); + + expr_list = ast_for_exprlist(c, CHILD(n, 1), Del); + if (!expr_list) + return NULL; + return Delete(expr_list, LINENO(n), n->n_col_offset, c->c_arena); +} + +static stmt_ty +ast_for_flow_stmt(struct compiling *c, const node *n) +{ + /* + flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt + | yield_stmt + break_stmt: 'break' + continue_stmt: 'continue' + return_stmt: 'return' [testlist] + yield_stmt: yield_expr + yield_expr: 'yield' testlist + raise_stmt: 'raise' [test [',' test [',' test]]] + */ + node *ch; + + REQ(n, flow_stmt); + ch = CHILD(n, 0); + switch (TYPE(ch)) { + case break_stmt: + return Break(LINENO(n), n->n_col_offset, c->c_arena); + case continue_stmt: + return Continue(LINENO(n), n->n_col_offset, c->c_arena); + case yield_stmt: { /* will reduce to yield_expr */ + expr_ty exp = ast_for_expr(c, CHILD(ch, 0)); + if (!exp) + return NULL; + return Expr(exp, LINENO(n), n->n_col_offset, c->c_arena); + } + case return_stmt: + if (NCH(ch) == 1) + return Return(NULL, LINENO(n), n->n_col_offset, c->c_arena); + else { + expr_ty expression = ast_for_testlist(c, CHILD(ch, 1)); + if (!expression) + return NULL; + return Return(expression, LINENO(n), n->n_col_offset, c->c_arena); + } + case raise_stmt: + if (NCH(ch) == 1) + return Raise(NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); + else if (NCH(ch) == 2) { + expr_ty expression = ast_for_expr(c, CHILD(ch, 1)); + if (!expression) + return NULL; + return Raise(expression, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); + } + else if (NCH(ch) == 4) { + expr_ty expr1, expr2; + + expr1 = ast_for_expr(c, CHILD(ch, 1)); + if (!expr1) + return NULL; + expr2 = ast_for_expr(c, CHILD(ch, 3)); + if (!expr2) + return NULL; + + return Raise(expr1, expr2, NULL, LINENO(n), n->n_col_offset, c->c_arena); + } + else if (NCH(ch) == 6) { + expr_ty expr1, expr2, expr3; + + expr1 = ast_for_expr(c, CHILD(ch, 1)); + if (!expr1) + return NULL; + expr2 = ast_for_expr(c, CHILD(ch, 3)); + if (!expr2) + return NULL; + expr3 = ast_for_expr(c, CHILD(ch, 5)); + if (!expr3) + return NULL; + + return Raise(expr1, expr2, expr3, LINENO(n), n->n_col_offset, c->c_arena); + } + default: + PyErr_Format(PyExc_SystemError, + "unexpected flow_stmt: %d", TYPE(ch)); + return NULL; + } + + PyErr_SetString(PyExc_SystemError, "unhandled flow statement"); + return NULL; +} + +static alias_ty +alias_for_import_name(struct compiling *c, const node *n) +{ + /* + import_as_name: NAME ['as' NAME] + dotted_as_name: dotted_name ['as' NAME] + dotted_name: NAME ('.' NAME)* + */ + PyObject *str; + + loop: + switch (TYPE(n)) { + case import_as_name: + str = NULL; + if (NCH(n) == 3) { + if (strcmp(STR(CHILD(n, 1)), "as") != 0) { + ast_error(n, "must use 'as' in import"); + return NULL; + } + str = NEW_IDENTIFIER(CHILD(n, 2)); + } + return alias(NEW_IDENTIFIER(CHILD(n, 0)), str, c->c_arena); + case dotted_as_name: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + else { + alias_ty a = alias_for_import_name(c, CHILD(n, 0)); + if (!a) + return NULL; + if (strcmp(STR(CHILD(n, 1)), "as") != 0) { + ast_error(n, "must use 'as' in import"); + return NULL; + } + assert(!a->asname); + a->asname = NEW_IDENTIFIER(CHILD(n, 2)); + return a; + } + break; + case dotted_name: + if (NCH(n) == 1) + return alias(NEW_IDENTIFIER(CHILD(n, 0)), NULL, c->c_arena); + else { + /* Create a string of the form "a.b.c" */ + int i; + size_t len; + char *s; + + len = 0; + for (i = 0; i < NCH(n); i += 2) + /* length of string plus one for the dot */ + len += strlen(STR(CHILD(n, i))) + 1; + len--; /* the last name doesn't have a dot */ + str = PyString_FromStringAndSize(NULL, len); + if (!str) + return NULL; + s = PyString_AS_STRING(str); + if (!s) + return NULL; + for (i = 0; i < NCH(n); i += 2) { + char *sch = STR(CHILD(n, i)); + strcpy(s, STR(CHILD(n, i))); + s += strlen(sch); + *s++ = '.'; + } + --s; + *s = '\0'; + PyString_InternInPlace(&str); + PyArena_AddPyObject(c->c_arena, str); + return alias(str, NULL, c->c_arena); + } + break; + case STAR: + str = PyString_InternFromString("*"); + PyArena_AddPyObject(c->c_arena, str); + return alias(str, NULL, c->c_arena); + default: + PyErr_Format(PyExc_SystemError, + "unexpected import name: %d", TYPE(n)); + return NULL; + } + + PyErr_SetString(PyExc_SystemError, "unhandled import name condition"); + return NULL; +} + +static stmt_ty +ast_for_import_stmt(struct compiling *c, const node *n) +{ + /* + import_stmt: import_name | import_from + import_name: 'import' dotted_as_names + import_from: 'from' ('.'* dotted_name | '.') 'import' + ('*' | '(' import_as_names ')' | import_as_names) + */ + int lineno; + int col_offset; + int i; + asdl_seq *aliases; + + REQ(n, import_stmt); + lineno = LINENO(n); + col_offset = n->n_col_offset; + n = CHILD(n, 0); + if (TYPE(n) == import_name) { + n = CHILD(n, 1); + REQ(n, dotted_as_names); + aliases = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!aliases) + return NULL; + for (i = 0; i < NCH(n); i += 2) { + alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); + if (!import_alias) + return NULL; + asdl_seq_SET(aliases, i / 2, import_alias); + } + return Import(aliases, lineno, col_offset, c->c_arena); + } + else if (TYPE(n) == import_from) { + int n_children; + int idx, ndots = 0; + alias_ty mod = NULL; + identifier modname; + + /* Count the number of dots (for relative imports) and check for the + optional module name */ + for (idx = 1; idx < NCH(n); idx++) { + if (TYPE(CHILD(n, idx)) == dotted_name) { + mod = alias_for_import_name(c, CHILD(n, idx)); + idx++; + break; + } else if (TYPE(CHILD(n, idx)) != DOT) { + break; + } + ndots++; + } + idx++; /* skip over the 'import' keyword */ + switch (TYPE(CHILD(n, idx))) { + case STAR: + /* from ... import * */ + n = CHILD(n, idx); + n_children = 1; + if (ndots) { + ast_error(n, "'import *' not allowed with 'from .'"); + return NULL; + } + break; + case LPAR: + /* from ... import (x, y, z) */ + n = CHILD(n, idx + 1); + n_children = NCH(n); + break; + case import_as_names: + /* from ... import x, y, z */ + n = CHILD(n, idx); + n_children = NCH(n); + if (n_children % 2 == 0) { + ast_error(n, "trailing comma not allowed without" + " surrounding parentheses"); + return NULL; + } + break; + default: + ast_error(n, "Unexpected node-type in from-import"); + return NULL; + } + + aliases = asdl_seq_new((n_children + 1) / 2, c->c_arena); + if (!aliases) + return NULL; + + /* handle "from ... import *" special b/c there's no children */ + if (TYPE(n) == STAR) { + alias_ty import_alias = alias_for_import_name(c, n); + if (!import_alias) + return NULL; + asdl_seq_SET(aliases, 0, import_alias); + } + else { + for (i = 0; i < NCH(n); i += 2) { + alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); + if (!import_alias) + return NULL; + asdl_seq_SET(aliases, i / 2, import_alias); + } + } + if (mod != NULL) + modname = mod->name; + else + modname = new_identifier("", c->c_arena); + return ImportFrom(modname, aliases, ndots, lineno, col_offset, + c->c_arena); + } + PyErr_Format(PyExc_SystemError, + "unknown import statement: starts with command '%s'", + STR(CHILD(n, 0))); + return NULL; +} + +static stmt_ty +ast_for_global_stmt(struct compiling *c, const node *n) +{ + /* global_stmt: 'global' NAME (',' NAME)* */ + identifier name; + asdl_seq *s; + int i; + + REQ(n, global_stmt); + s = asdl_seq_new(NCH(n) / 2, c->c_arena); + if (!s) + return NULL; + for (i = 1; i < NCH(n); i += 2) { + name = NEW_IDENTIFIER(CHILD(n, i)); + if (!name) + return NULL; + asdl_seq_SET(s, i / 2, name); + } + return Global(s, LINENO(n), n->n_col_offset, c->c_arena); +} + +static stmt_ty +ast_for_exec_stmt(struct compiling *c, const node *n) +{ + expr_ty expr1, globals = NULL, locals = NULL; + int n_children = NCH(n); + if (n_children != 2 && n_children != 4 && n_children != 6) { + PyErr_Format(PyExc_SystemError, + "poorly formed 'exec' statement: %d parts to statement", + n_children); + return NULL; + } + + /* exec_stmt: 'exec' expr ['in' test [',' test]] */ + REQ(n, exec_stmt); + expr1 = ast_for_expr(c, CHILD(n, 1)); + if (!expr1) + return NULL; + if (n_children >= 4) { + globals = ast_for_expr(c, CHILD(n, 3)); + if (!globals) + return NULL; + } + if (n_children == 6) { + locals = ast_for_expr(c, CHILD(n, 5)); + if (!locals) + return NULL; + } + + return Exec(expr1, globals, locals, LINENO(n), n->n_col_offset, c->c_arena); +} + +static stmt_ty +ast_for_assert_stmt(struct compiling *c, const node *n) +{ + /* assert_stmt: 'assert' test [',' test] */ + REQ(n, assert_stmt); + if (NCH(n) == 2) { + expr_ty expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + return Assert(expression, NULL, LINENO(n), n->n_col_offset, c->c_arena); + } + else if (NCH(n) == 4) { + expr_ty expr1, expr2; + + expr1 = ast_for_expr(c, CHILD(n, 1)); + if (!expr1) + return NULL; + expr2 = ast_for_expr(c, CHILD(n, 3)); + if (!expr2) + return NULL; + + return Assert(expr1, expr2, LINENO(n), n->n_col_offset, c->c_arena); + } + PyErr_Format(PyExc_SystemError, + "improper number of parts to 'assert' statement: %d", + NCH(n)); + return NULL; +} + +static asdl_seq * +ast_for_suite(struct compiling *c, const node *n) +{ + /* suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT */ + asdl_seq *seq; + stmt_ty s; + int i, total, num, end, pos = 0; + node *ch; + + REQ(n, suite); + + total = num_stmts(n); + seq = asdl_seq_new(total, c->c_arena); + if (!seq) + return NULL; + if (TYPE(CHILD(n, 0)) == simple_stmt) { + n = CHILD(n, 0); + /* simple_stmt always ends with a NEWLINE, + and may have a trailing SEMI + */ + end = NCH(n) - 1; + if (TYPE(CHILD(n, end - 1)) == SEMI) + end--; + /* loop by 2 to skip semi-colons */ + for (i = 0; i < end; i += 2) { + ch = CHILD(n, i); + s = ast_for_stmt(c, ch); + if (!s) + return NULL; + asdl_seq_SET(seq, pos++, s); + } + } + else { + for (i = 2; i < (NCH(n) - 1); i++) { + ch = CHILD(n, i); + REQ(ch, stmt); + num = num_stmts(ch); + if (num == 1) { + /* small_stmt or compound_stmt with only one child */ + s = ast_for_stmt(c, ch); + if (!s) + return NULL; + asdl_seq_SET(seq, pos++, s); + } + else { + int j; + ch = CHILD(ch, 0); + REQ(ch, simple_stmt); + for (j = 0; j < NCH(ch); j += 2) { + /* statement terminates with a semi-colon ';' */ + if (NCH(CHILD(ch, j)) == 0) { + assert((j + 1) == NCH(ch)); + break; + } + s = ast_for_stmt(c, CHILD(ch, j)); + if (!s) + return NULL; + asdl_seq_SET(seq, pos++, s); + } + } + } + } + assert(pos == seq->size); + return seq; +} + +static stmt_ty +ast_for_if_stmt(struct compiling *c, const node *n) +{ + /* if_stmt: 'if' test ':' suite ('elif' test ':' suite)* + ['else' ':' suite] + */ + char *s; + + REQ(n, if_stmt); + + if (NCH(n) == 4) { + expr_ty expression; + asdl_seq *suite_seq; + + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + + return If(expression, suite_seq, NULL, LINENO(n), n->n_col_offset, c->c_arena); + } + + s = STR(CHILD(n, 4)); + /* s[2], the third character in the string, will be + 's' for el_s_e, or + 'i' for el_i_f + */ + if (s[2] == 's') { + expr_ty expression; + asdl_seq *seq1, *seq2; + + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + seq1 = ast_for_suite(c, CHILD(n, 3)); + if (!seq1) + return NULL; + seq2 = ast_for_suite(c, CHILD(n, 6)); + if (!seq2) + return NULL; + + return If(expression, seq1, seq2, LINENO(n), n->n_col_offset, c->c_arena); + } + else if (s[2] == 'i') { + int i, n_elif, has_else = 0; + expr_ty expression; + asdl_seq *suite_seq; + asdl_seq *orelse = NULL; + n_elif = NCH(n) - 4; + /* must reference the child n_elif+1 since 'else' token is third, + not fourth, child from the end. */ + if (TYPE(CHILD(n, (n_elif + 1))) == NAME + && STR(CHILD(n, (n_elif + 1)))[2] == 's') { + has_else = 1; + n_elif -= 3; + } + n_elif /= 4; + + if (has_else) { + asdl_seq *suite_seq2; + + orelse = asdl_seq_new(1, c->c_arena); + if (!orelse) + return NULL; + expression = ast_for_expr(c, CHILD(n, NCH(n) - 6)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, NCH(n) - 4)); + if (!suite_seq) + return NULL; + suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1)); + if (!suite_seq2) + return NULL; + + asdl_seq_SET(orelse, 0, If(expression, suite_seq, suite_seq2, + LINENO(CHILD(n, NCH(n) - 6)), CHILD(n, NCH(n) - 6)->n_col_offset, + c->c_arena)); + /* the just-created orelse handled the last elif */ + n_elif--; + } + + for (i = 0; i < n_elif; i++) { + int off = 5 + (n_elif - i - 1) * 4; + asdl_seq *newobj = asdl_seq_new(1, c->c_arena); + if (!newobj) + return NULL; + expression = ast_for_expr(c, CHILD(n, off)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, off + 2)); + if (!suite_seq) + return NULL; + + asdl_seq_SET(newobj, 0, + If(expression, suite_seq, orelse, + LINENO(CHILD(n, off)), CHILD(n, off)->n_col_offset, c->c_arena)); + orelse = newobj; + } + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + return If(expression, suite_seq, orelse, + LINENO(n), n->n_col_offset, c->c_arena); + } + + PyErr_Format(PyExc_SystemError, + "unexpected token in 'if' statement: %s", s); + return NULL; +} + +static stmt_ty +ast_for_while_stmt(struct compiling *c, const node *n) +{ + /* while_stmt: 'while' test ':' suite ['else' ':' suite] */ + REQ(n, while_stmt); + + if (NCH(n) == 4) { + expr_ty expression; + asdl_seq *suite_seq; + + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + return While(expression, suite_seq, NULL, LINENO(n), n->n_col_offset, c->c_arena); + } + else if (NCH(n) == 7) { + expr_ty expression; + asdl_seq *seq1, *seq2; + + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + seq1 = ast_for_suite(c, CHILD(n, 3)); + if (!seq1) + return NULL; + seq2 = ast_for_suite(c, CHILD(n, 6)); + if (!seq2) + return NULL; + + return While(expression, seq1, seq2, LINENO(n), n->n_col_offset, c->c_arena); + } + + PyErr_Format(PyExc_SystemError, + "wrong number of tokens for 'while' statement: %d", + NCH(n)); + return NULL; +} + +static stmt_ty +ast_for_for_stmt(struct compiling *c, const node *n) +{ + asdl_seq *_target, *seq = NULL, *suite_seq; + expr_ty expression; + expr_ty target; + const node *node_target; + /* for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite] */ + REQ(n, for_stmt); + + if (NCH(n) == 9) { + seq = ast_for_suite(c, CHILD(n, 8)); + if (!seq) + return NULL; + } + + node_target = CHILD(n, 1); + _target = ast_for_exprlist(c, node_target, Store); + if (!_target) + return NULL; + /* Check the # of children rather than the length of _target, since + for x, in ... has 1 element in _target, but still requires a Tuple. */ + if (NCH(node_target) == 1) + target = (expr_ty)asdl_seq_GET(_target, 0); + else + target = Tuple(_target, Store, LINENO(n), n->n_col_offset, c->c_arena); + + expression = ast_for_testlist(c, CHILD(n, 3)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 5)); + if (!suite_seq) + return NULL; + + return For(target, expression, suite_seq, seq, LINENO(n), n->n_col_offset, + c->c_arena); +} + +static excepthandler_ty +ast_for_except_clause(struct compiling *c, const node *exc, node *body) +{ + /* except_clause: 'except' [test [',' test]] */ + REQ(exc, except_clause); + REQ(body, suite); + + if (NCH(exc) == 1) { + asdl_seq *suite_seq = ast_for_suite(c, body); + if (!suite_seq) + return NULL; + + return excepthandler(NULL, NULL, suite_seq, LINENO(exc), + exc->n_col_offset, c->c_arena); + } + else if (NCH(exc) == 2) { + expr_ty expression; + asdl_seq *suite_seq; + + expression = ast_for_expr(c, CHILD(exc, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, body); + if (!suite_seq) + return NULL; + + return excepthandler(expression, NULL, suite_seq, LINENO(exc), + exc->n_col_offset, c->c_arena); + } + else if (NCH(exc) == 4) { + asdl_seq *suite_seq; + expr_ty expression; + expr_ty e = ast_for_expr(c, CHILD(exc, 3)); + if (!e) + return NULL; + if (!set_context(e, Store, CHILD(exc, 3))) + return NULL; + expression = ast_for_expr(c, CHILD(exc, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, body); + if (!suite_seq) + return NULL; + + return excepthandler(expression, e, suite_seq, LINENO(exc), + exc->n_col_offset, c->c_arena); + } + + PyErr_Format(PyExc_SystemError, + "wrong number of children for 'except' clause: %d", + NCH(exc)); + return NULL; +} + +static stmt_ty +ast_for_try_stmt(struct compiling *c, const node *n) +{ + const int nch = NCH(n); + int n_except = (nch - 3)/3; + asdl_seq *body, *orelse = NULL, *finally = NULL; + + REQ(n, try_stmt); + + body = ast_for_suite(c, CHILD(n, 2)); + if (body == NULL) + return NULL; + + if (TYPE(CHILD(n, nch - 3)) == NAME) { + if (strcmp(STR(CHILD(n, nch - 3)), "finally") == 0) { + if (nch >= 9 && TYPE(CHILD(n, nch - 6)) == NAME) { + /* we can assume it's an "else", + because nch >= 9 for try-else-finally and + it would otherwise have a type of except_clause */ + orelse = ast_for_suite(c, CHILD(n, nch - 4)); + if (orelse == NULL) + return NULL; + n_except--; + } + + finally = ast_for_suite(c, CHILD(n, nch - 1)); + if (finally == NULL) + return NULL; + n_except--; + } + else { + /* we can assume it's an "else", + otherwise it would have a type of except_clause */ + orelse = ast_for_suite(c, CHILD(n, nch - 1)); + if (orelse == NULL) + return NULL; + n_except--; + } + } + else if (TYPE(CHILD(n, nch - 3)) != except_clause) { + ast_error(n, "malformed 'try' statement"); + return NULL; + } + + if (n_except > 0) { + int i; + stmt_ty except_st; + /* process except statements to create a try ... except */ + asdl_seq *handlers = asdl_seq_new(n_except, c->c_arena); + if (handlers == NULL) + return NULL; + + for (i = 0; i < n_except; i++) { + excepthandler_ty e = ast_for_except_clause(c, CHILD(n, 3 + i * 3), + CHILD(n, 5 + i * 3)); + if (!e) + return NULL; + asdl_seq_SET(handlers, i, e); + } + + except_st = TryExcept(body, handlers, orelse, LINENO(n), + n->n_col_offset, c->c_arena); + if (!finally) + return except_st; + + /* if a 'finally' is present too, we nest the TryExcept within a + TryFinally to emulate try ... except ... finally */ + body = asdl_seq_new(1, c->c_arena); + if (body == NULL) + return NULL; + asdl_seq_SET(body, 0, except_st); + } + + /* must be a try ... finally (except clauses are in body, if any exist) */ + assert(finally != NULL); + return TryFinally(body, finally, LINENO(n), n->n_col_offset, c->c_arena); +} + +static expr_ty +ast_for_with_var(struct compiling *c, const node *n) +{ + REQ(n, with_var); + if (strcmp(STR(CHILD(n, 0)), "as") != 0) { + ast_error(n, "expected \"with [expr] as [var]\""); + return NULL; + } + return ast_for_expr(c, CHILD(n, 1)); +} + +/* with_stmt: 'with' test [ with_var ] ':' suite */ +static stmt_ty +ast_for_with_stmt(struct compiling *c, const node *n) +{ + expr_ty context_expr, optional_vars = NULL; + int suite_index = 3; /* skip 'with', test, and ':' */ + asdl_seq *suite_seq; + + assert(TYPE(n) == with_stmt); + context_expr = ast_for_expr(c, CHILD(n, 1)); + if (!context_expr) + return NULL; + if (TYPE(CHILD(n, 2)) == with_var) { + optional_vars = ast_for_with_var(c, CHILD(n, 2)); + + if (!optional_vars) { + return NULL; + } + if (!set_context(optional_vars, Store, n)) { + return NULL; + } + suite_index = 4; + } + + suite_seq = ast_for_suite(c, CHILD(n, suite_index)); + if (!suite_seq) { + return NULL; + } + return With(context_expr, optional_vars, suite_seq, LINENO(n), + n->n_col_offset, c->c_arena); +} + +static stmt_ty +ast_for_classdef(struct compiling *c, const node *n) +{ + /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */ + asdl_seq *bases, *s; + + REQ(n, classdef); + + if (!strcmp(STR(CHILD(n, 1)), "None")) { + ast_error(n, "assignment to None"); + return NULL; + } + + if (NCH(n) == 4) { + s = ast_for_suite(c, CHILD(n, 3)); + if (!s) + return NULL; + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), + n->n_col_offset, c->c_arena); + } + /* check for empty base list */ + if (TYPE(CHILD(n,3)) == RPAR) { + s = ast_for_suite(c, CHILD(n,5)); + if (!s) + return NULL; + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), + n->n_col_offset, c->c_arena); + } + + /* else handle the base class list */ + bases = ast_for_class_bases(c, CHILD(n, 3)); + if (!bases) + return NULL; + + s = ast_for_suite(c, CHILD(n, 6)); + if (!s) + return NULL; + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), bases, s, LINENO(n), + n->n_col_offset, c->c_arena); +} + +static stmt_ty +ast_for_stmt(struct compiling *c, const node *n) +{ + if (TYPE(n) == stmt) { + assert(NCH(n) == 1); + n = CHILD(n, 0); + } + if (TYPE(n) == simple_stmt) { + assert(num_stmts(n) == 1); + n = CHILD(n, 0); + } + if (TYPE(n) == small_stmt) { + REQ(n, small_stmt); + n = CHILD(n, 0); + /* small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt + | flow_stmt | import_stmt | global_stmt | exec_stmt + | assert_stmt + */ + switch (TYPE(n)) { + case expr_stmt: + return ast_for_expr_stmt(c, n); + case print_stmt: + return ast_for_print_stmt(c, n); + case del_stmt: + return ast_for_del_stmt(c, n); + case pass_stmt: + return Pass(LINENO(n), n->n_col_offset, c->c_arena); + case flow_stmt: + return ast_for_flow_stmt(c, n); + case import_stmt: + return ast_for_import_stmt(c, n); + case global_stmt: + return ast_for_global_stmt(c, n); + case exec_stmt: + return ast_for_exec_stmt(c, n); + case assert_stmt: + return ast_for_assert_stmt(c, n); + default: + PyErr_Format(PyExc_SystemError, + "unhandled small_stmt: TYPE=%d NCH=%d\n", + TYPE(n), NCH(n)); + return NULL; + } + } + else { + /* compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt + | funcdef | classdef + */ + node *ch = CHILD(n, 0); + REQ(n, compound_stmt); + switch (TYPE(ch)) { + case if_stmt: + return ast_for_if_stmt(c, ch); + case while_stmt: + return ast_for_while_stmt(c, ch); + case for_stmt: + return ast_for_for_stmt(c, ch); + case try_stmt: + return ast_for_try_stmt(c, ch); + case with_stmt: + return ast_for_with_stmt(c, ch); + case funcdef: + return ast_for_funcdef(c, ch); + case classdef: + return ast_for_classdef(c, ch); + default: + PyErr_Format(PyExc_SystemError, + "unhandled small_stmt: TYPE=%d NCH=%d\n", + TYPE(n), NCH(n)); + return NULL; + } + } +} + +static PyObject * +parsenumber(const char *s) +{ + const char *end; + long x; + double dx; +#ifndef WITHOUT_COMPLEX + Py_complex c; + int imflag; +#endif + + errno = 0; + end = s + strlen(s) - 1; +#ifndef WITHOUT_COMPLEX + imflag = *end == 'j' || *end == 'J'; +#endif + if (*end == 'l' || *end == 'L') + return PyLong_FromString((char *)s, (char **)0, 0); + if (s[0] == '0') { + x = (long) PyOS_strtoul((char *)s, (char **)&end, 0); + if (x < 0 && errno == 0) { + return PyLong_FromString((char *)s, + (char **)0, + 0); + } + } + else + x = PyOS_strtol((char *)s, (char **)&end, 0); + if (*end == '\0') { + if (errno != 0) + return PyLong_FromString((char *)s, (char **)0, 0); + return PyInt_FromLong(x); + } + /* XXX Huge floats may silently fail */ +#ifndef WITHOUT_COMPLEX + if (imflag) { + c.real = 0.; + PyFPE_START_PROTECT("atof", return 0) + c.imag = PyOS_ascii_atof(s); + PyFPE_END_PROTECT(c) + return PyComplex_FromCComplex(c); + } + else +#endif + { + PyFPE_START_PROTECT("atof", return 0) + dx = PyOS_ascii_atof(s); + PyFPE_END_PROTECT(dx) + return PyFloat_FromDouble(dx); + } +} + +static PyObject * +decode_utf8(const char **sPtr, const char *end, char* encoding) +{ +#ifndef Py_USING_UNICODE + Py_FatalError("decode_utf8 should not be called in this build."); + return NULL; +#else + PyObject *u, *v; + char *s, *t; + t = s = (char *)*sPtr; + /* while (s < end && *s != '\\') s++; */ /* inefficient for u".." */ + while (s < end && (*s & 0x80)) s++; + *sPtr = s; + u = PyUnicode_DecodeUTF8(t, s - t, NULL); + if (u == NULL) + return NULL; + v = PyUnicode_AsEncodedString(u, encoding, NULL); + Py_DECREF(u); + return v; +#endif +} + +static PyObject * +decode_unicode(const char *s, size_t len, int rawmode, const char *encoding) +{ + PyObject *v, *u; + char *buf; + char *p; + const char *end; + if (encoding == NULL) { + buf = (char *)s; + u = NULL; + } else if (strcmp(encoding, "iso-8859-1") == 0) { + buf = (char *)s; + u = NULL; + } else { + /* "\XX" may become "\u005c\uHHLL" (12 bytes) */ + u = PyString_FromStringAndSize((char *)NULL, len * 4); + if (u == NULL) + return NULL; + p = buf = PyString_AsString(u); + end = s + len; + while (s < end) { + if (*s == '\\') { + *p++ = *s++; + if (*s & 0x80) { + strcpy(p, "u005c"); + p += 5; + } + } + if (*s & 0x80) { /* XXX inefficient */ + PyObject *w; + char *r; + Py_ssize_t rn, i; + w = decode_utf8(&s, end, "utf-16-be"); + if (w == NULL) { + Py_DECREF(u); + return NULL; + } + r = PyString_AsString(w); + rn = PyString_Size(w); + assert(rn % 2 == 0); + for (i = 0; i < rn; i += 2) { + sprintf(p, "\\u%02x%02x", + r[i + 0] & 0xFF, + r[i + 1] & 0xFF); + p += 6; + } + Py_DECREF(w); + } else { + *p++ = *s++; + } + } + len = p - buf; + s = buf; + } + if (rawmode) + v = PyUnicode_DecodeRawUnicodeEscape(s, len, NULL); + else + v = PyUnicode_DecodeUnicodeEscape(s, len, NULL); + Py_XDECREF(u); + return v; +} + +/* s is a Python string literal, including the bracketing quote characters, + * and r &/or u prefixes (if any), and embedded escape sequences (if any). + * parsestr parses it, and returns the decoded Python string object. + */ +static PyObject * +parsestr(const char *s, const char *encoding) +{ + size_t len; + int quote = Py_CHARMASK(*s); + int rawmode = 0; + int need_encoding; + int unicode = 0; + + if (isalpha(quote) || quote == '_') { + if (quote == 'u' || quote == 'U') { + quote = *++s; + unicode = 1; + } + if (quote == 'r' || quote == 'R') { + quote = *++s; + rawmode = 1; + } + } + if (quote != '\'' && quote != '\"') { + PyErr_BadInternalCall(); + return NULL; + } + s++; + len = strlen(s); + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "string to parse is too long"); + return NULL; + } + if (s[--len] != quote) { + PyErr_BadInternalCall(); + return NULL; + } + if (len >= 4 && s[0] == quote && s[1] == quote) { + s += 2; + len -= 2; + if (s[--len] != quote || s[--len] != quote) { + PyErr_BadInternalCall(); + return NULL; + } + } +#ifdef Py_USING_UNICODE + if (unicode || Py_UnicodeFlag) { + return decode_unicode(s, len, rawmode, encoding); + } +#endif + need_encoding = (encoding != NULL && + strcmp(encoding, "utf-8") != 0 && + strcmp(encoding, "iso-8859-1") != 0); + if (rawmode || strchr(s, '\\') == NULL) { + if (need_encoding) { +#ifndef Py_USING_UNICODE + /* This should not happen - we never see any other + encoding. */ + Py_FatalError( + "cannot deal with encodings in this build."); +#else + PyObject *v, *u = PyUnicode_DecodeUTF8(s, len, NULL); + if (u == NULL) + return NULL; + v = PyUnicode_AsEncodedString(u, encoding, NULL); + Py_DECREF(u); + return v; +#endif + } else { + return PyString_FromStringAndSize(s, len); + } + } + + return PyString_DecodeEscape(s, len, NULL, unicode, + need_encoding ? encoding : NULL); +} + +/* Build a Python string object out of a STRING atom. This takes care of + * compile-time literal catenation, calling parsestr() on each piece, and + * pasting the intermediate results together. + */ +static PyObject * +parsestrplus(struct compiling *c, const node *n) +{ + PyObject *v; + int i; + REQ(CHILD(n, 0), STRING); + if ((v = parsestr(STR(CHILD(n, 0)), c->c_encoding)) != NULL) { + /* String literal concatenation */ + for (i = 1; i < NCH(n); i++) { + PyObject *s; + s = parsestr(STR(CHILD(n, i)), c->c_encoding); + if (s == NULL) + goto onError; + if (PyString_Check(v) && PyString_Check(s)) { + PyString_ConcatAndDel(&v, s); + if (v == NULL) + goto onError; + } +#ifdef Py_USING_UNICODE + else { + PyObject *temp = PyUnicode_Concat(v, s); + Py_DECREF(s); + Py_DECREF(v); + v = temp; + if (v == NULL) + goto onError; + } +#endif + } + } + return v; + + onError: + Py_XDECREF(v); + return NULL; +} diff --git a/sys/src/cmd/python/Python/atof.c b/sys/src/cmd/python/Python/atof.c new file mode 100644 index 000000000..8fbde3847 --- /dev/null +++ b/sys/src/cmd/python/Python/atof.c @@ -0,0 +1,50 @@ + +/* Just in case you haven't got an atof() around... + This one doesn't check for bad syntax or overflow, + and is slow and inaccurate. + But it's good enough for the occasional string literal... */ + +#include "pyconfig.h" + +#include <ctype.h> + +double atof(char *s) +{ + double a = 0.0; + int e = 0; + int c; + while ((c = *s++) != '\0' && isdigit(c)) { + a = a*10.0 + (c - '0'); + } + if (c == '.') { + while ((c = *s++) != '\0' && isdigit(c)) { + a = a*10.0 + (c - '0'); + e = e-1; + } + } + if (c == 'e' || c == 'E') { + int sign = 1; + int i = 0; + c = *s++; + if (c == '+') + c = *s++; + else if (c == '-') { + c = *s++; + sign = -1; + } + while (isdigit(c)) { + i = i*10 + (c - '0'); + c = *s++; + } + e += i*sign; + } + while (e > 0) { + a *= 10.0; + e--; + } + while (e < 0) { + a *= 0.1; + e++; + } + return a; +} diff --git a/sys/src/cmd/python/Python/bltinmodule.c b/sys/src/cmd/python/Python/bltinmodule.c new file mode 100644 index 000000000..ceb2fc77f --- /dev/null +++ b/sys/src/cmd/python/Python/bltinmodule.c @@ -0,0 +1,2620 @@ +/* Built-in functions */ + +#include "Python.h" + +#include "node.h" +#include "code.h" +#include "eval.h" + +#include <ctype.h> + +#ifdef RISCOS +#include "unixstuff.h" +#endif + +/* The default encoding used by the platform file system APIs + Can remain NULL for all platforms that don't have such a concept +*/ +#if defined(MS_WINDOWS) && defined(HAVE_USABLE_WCHAR_T) +const char *Py_FileSystemDefaultEncoding = "mbcs"; +#elif defined(__APPLE__) +const char *Py_FileSystemDefaultEncoding = "utf-8"; +#else +const char *Py_FileSystemDefaultEncoding = NULL; /* use default */ +#endif + +/* Forward */ +static PyObject *filterstring(PyObject *, PyObject *); +#ifdef Py_USING_UNICODE +static PyObject *filterunicode(PyObject *, PyObject *); +#endif +static PyObject *filtertuple (PyObject *, PyObject *); + +static PyObject * +builtin___import__(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"name", "globals", "locals", "fromlist", + "level", 0}; + char *name; + PyObject *globals = NULL; + PyObject *locals = NULL; + PyObject *fromlist = NULL; + int level = -1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|OOOi:__import__", + kwlist, &name, &globals, &locals, &fromlist, &level)) + return NULL; + return PyImport_ImportModuleLevel(name, globals, locals, + fromlist, level); +} + +PyDoc_STRVAR(import_doc, +"__import__(name, globals={}, locals={}, fromlist=[], level=-1) -> module\n\ +\n\ +Import a module. The globals are only used to determine the context;\n\ +they are not modified. The locals are currently unused. The fromlist\n\ +should be a list of names to emulate ``from name import ...'', or an\n\ +empty list to emulate ``import name''.\n\ +When importing a module from a package, note that __import__('A.B', ...)\n\ +returns package A when fromlist is empty, but its submodule B when\n\ +fromlist is not empty. Level is used to determine whether to perform \n\ +absolute or relative imports. -1 is the original strategy of attempting\n\ +both absolute and relative imports, 0 is absolute, a positive number\n\ +is the number of parent directories to search relative to the current module."); + + +static PyObject * +builtin_abs(PyObject *self, PyObject *v) +{ + return PyNumber_Absolute(v); +} + +PyDoc_STRVAR(abs_doc, +"abs(number) -> number\n\ +\n\ +Return the absolute value of the argument."); + +static PyObject * +builtin_all(PyObject *self, PyObject *v) +{ + PyObject *it, *item; + + it = PyObject_GetIter(v); + if (it == NULL) + return NULL; + + while ((item = PyIter_Next(it)) != NULL) { + int cmp = PyObject_IsTrue(item); + Py_DECREF(item); + if (cmp < 0) { + Py_DECREF(it); + return NULL; + } + if (cmp == 0) { + Py_DECREF(it); + Py_RETURN_FALSE; + } + } + Py_DECREF(it); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_TRUE; +} + +PyDoc_STRVAR(all_doc, +"all(iterable) -> bool\n\ +\n\ +Return True if bool(x) is True for all values x in the iterable."); + +static PyObject * +builtin_any(PyObject *self, PyObject *v) +{ + PyObject *it, *item; + + it = PyObject_GetIter(v); + if (it == NULL) + return NULL; + + while ((item = PyIter_Next(it)) != NULL) { + int cmp = PyObject_IsTrue(item); + Py_DECREF(item); + if (cmp < 0) { + Py_DECREF(it); + return NULL; + } + if (cmp == 1) { + Py_DECREF(it); + Py_RETURN_TRUE; + } + } + Py_DECREF(it); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(any_doc, +"any(iterable) -> bool\n\ +\n\ +Return True if bool(x) is True for any x in the iterable."); + +static PyObject * +builtin_apply(PyObject *self, PyObject *args) +{ + PyObject *func, *alist = NULL, *kwdict = NULL; + PyObject *t = NULL, *retval = NULL; + + if (!PyArg_UnpackTuple(args, "apply", 1, 3, &func, &alist, &kwdict)) + return NULL; + if (alist != NULL) { + if (!PyTuple_Check(alist)) { + if (!PySequence_Check(alist)) { + PyErr_Format(PyExc_TypeError, + "apply() arg 2 expected sequence, found %s", + alist->ob_type->tp_name); + return NULL; + } + t = PySequence_Tuple(alist); + if (t == NULL) + return NULL; + alist = t; + } + } + if (kwdict != NULL && !PyDict_Check(kwdict)) { + PyErr_Format(PyExc_TypeError, + "apply() arg 3 expected dictionary, found %s", + kwdict->ob_type->tp_name); + goto finally; + } + retval = PyEval_CallObjectWithKeywords(func, alist, kwdict); + finally: + Py_XDECREF(t); + return retval; +} + +PyDoc_STRVAR(apply_doc, +"apply(object[, args[, kwargs]]) -> value\n\ +\n\ +Call a callable object with positional arguments taken from the tuple args,\n\ +and keyword arguments taken from the optional dictionary kwargs.\n\ +Note that classes are callable, as are instances with a __call__() method.\n\ +\n\ +Deprecated since release 2.3. Instead, use the extended call syntax:\n\ + function(*args, **keywords)."); + + +static PyObject * +builtin_callable(PyObject *self, PyObject *v) +{ + return PyBool_FromLong((long)PyCallable_Check(v)); +} + +PyDoc_STRVAR(callable_doc, +"callable(object) -> bool\n\ +\n\ +Return whether the object is callable (i.e., some kind of function).\n\ +Note that classes are callable, as are instances with a __call__() method."); + + +static PyObject * +builtin_filter(PyObject *self, PyObject *args) +{ + PyObject *func, *seq, *result, *it, *arg; + Py_ssize_t len; /* guess for result list size */ + register Py_ssize_t j; + + if (!PyArg_UnpackTuple(args, "filter", 2, 2, &func, &seq)) + return NULL; + + /* Strings and tuples return a result of the same type. */ + if (PyString_Check(seq)) + return filterstring(func, seq); +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(seq)) + return filterunicode(func, seq); +#endif + if (PyTuple_Check(seq)) + return filtertuple(func, seq); + + /* Pre-allocate argument list tuple. */ + arg = PyTuple_New(1); + if (arg == NULL) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(seq); + if (it == NULL) + goto Fail_arg; + + /* Guess a result list size. */ + len = _PyObject_LengthHint(seq); + if (len < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + goto Fail_it; + } + PyErr_Clear(); + len = 8; /* arbitrary */ + } + + /* Get a result list. */ + if (PyList_Check(seq) && seq->ob_refcnt == 1) { + /* Eww - can modify the list in-place. */ + Py_INCREF(seq); + result = seq; + } + else { + result = PyList_New(len); + if (result == NULL) + goto Fail_it; + } + + /* Build the result list. */ + j = 0; + for (;;) { + PyObject *item; + int ok; + + item = PyIter_Next(it); + if (item == NULL) { + if (PyErr_Occurred()) + goto Fail_result_it; + break; + } + + if (func == (PyObject *)&PyBool_Type || func == Py_None) { + ok = PyObject_IsTrue(item); + } + else { + PyObject *good; + PyTuple_SET_ITEM(arg, 0, item); + good = PyObject_Call(func, arg, NULL); + PyTuple_SET_ITEM(arg, 0, NULL); + if (good == NULL) { + Py_DECREF(item); + goto Fail_result_it; + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + } + if (ok) { + if (j < len) + PyList_SET_ITEM(result, j, item); + else { + int status = PyList_Append(result, item); + Py_DECREF(item); + if (status < 0) + goto Fail_result_it; + } + ++j; + } + else + Py_DECREF(item); + } + + + /* Cut back result list if len is too big. */ + if (j < len && PyList_SetSlice(result, j, len, NULL) < 0) + goto Fail_result_it; + + Py_DECREF(it); + Py_DECREF(arg); + return result; + +Fail_result_it: + Py_DECREF(result); +Fail_it: + Py_DECREF(it); +Fail_arg: + Py_DECREF(arg); + return NULL; +} + +PyDoc_STRVAR(filter_doc, +"filter(function or None, sequence) -> list, tuple, or string\n" +"\n" +"Return those items of sequence for which function(item) is true. If\n" +"function is None, return the items that are true. If sequence is a tuple\n" +"or string, return the same type, else return a list."); + +static PyObject * +builtin_chr(PyObject *self, PyObject *args) +{ + long x; + char s[1]; + + if (!PyArg_ParseTuple(args, "l:chr", &x)) + return NULL; + if (x < 0 || x >= 256) { + PyErr_SetString(PyExc_ValueError, + "chr() arg not in range(256)"); + return NULL; + } + s[0] = (char)x; + return PyString_FromStringAndSize(s, 1); +} + +PyDoc_STRVAR(chr_doc, +"chr(i) -> character\n\ +\n\ +Return a string of one character with ordinal i; 0 <= i < 256."); + + +#ifdef Py_USING_UNICODE +static PyObject * +builtin_unichr(PyObject *self, PyObject *args) +{ + long x; + + if (!PyArg_ParseTuple(args, "l:unichr", &x)) + return NULL; + + return PyUnicode_FromOrdinal(x); +} + +PyDoc_STRVAR(unichr_doc, +"unichr(i) -> Unicode character\n\ +\n\ +Return a Unicode string of one character with ordinal i; 0 <= i <= 0x10ffff."); +#endif + + +static PyObject * +builtin_cmp(PyObject *self, PyObject *args) +{ + PyObject *a, *b; + int c; + + if (!PyArg_UnpackTuple(args, "cmp", 2, 2, &a, &b)) + return NULL; + if (PyObject_Cmp(a, b, &c) < 0) + return NULL; + return PyInt_FromLong((long)c); +} + +PyDoc_STRVAR(cmp_doc, +"cmp(x, y) -> integer\n\ +\n\ +Return negative if x<y, zero if x==y, positive if x>y."); + + +static PyObject * +builtin_coerce(PyObject *self, PyObject *args) +{ + PyObject *v, *w; + PyObject *res; + + if (!PyArg_UnpackTuple(args, "coerce", 2, 2, &v, &w)) + return NULL; + if (PyNumber_Coerce(&v, &w) < 0) + return NULL; + res = PyTuple_Pack(2, v, w); + Py_DECREF(v); + Py_DECREF(w); + return res; +} + +PyDoc_STRVAR(coerce_doc, +"coerce(x, y) -> (x1, y1)\n\ +\n\ +Return a tuple consisting of the two numeric arguments converted to\n\ +a common type, using the same rules as used by arithmetic operations.\n\ +If coercion is not possible, raise TypeError."); + +static PyObject * +builtin_compile(PyObject *self, PyObject *args) +{ + char *str; + char *filename; + char *startstr; + int start; + int dont_inherit = 0; + int supplied_flags = 0; + PyCompilerFlags cf; + PyObject *result = NULL, *cmd, *tmp = NULL; + Py_ssize_t length; + + if (!PyArg_ParseTuple(args, "Oss|ii:compile", &cmd, &filename, + &startstr, &supplied_flags, &dont_inherit)) + return NULL; + + cf.cf_flags = supplied_flags; + +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(cmd)) { + tmp = PyUnicode_AsUTF8String(cmd); + if (tmp == NULL) + return NULL; + cmd = tmp; + cf.cf_flags |= PyCF_SOURCE_IS_UTF8; + } +#endif + if (PyObject_AsReadBuffer(cmd, (const void **)&str, &length)) + return NULL; + if ((size_t)length != strlen(str)) { + PyErr_SetString(PyExc_TypeError, + "compile() expected string without null bytes"); + goto cleanup; + } + + if (strcmp(startstr, "exec") == 0) + start = Py_file_input; + else if (strcmp(startstr, "eval") == 0) + start = Py_eval_input; + else if (strcmp(startstr, "single") == 0) + start = Py_single_input; + else { + PyErr_SetString(PyExc_ValueError, + "compile() arg 3 must be 'exec' or 'eval' or 'single'"); + goto cleanup; + } + + if (supplied_flags & + ~(PyCF_MASK | PyCF_MASK_OBSOLETE | PyCF_DONT_IMPLY_DEDENT | PyCF_ONLY_AST)) + { + PyErr_SetString(PyExc_ValueError, + "compile(): unrecognised flags"); + goto cleanup; + } + /* XXX Warn if (supplied_flags & PyCF_MASK_OBSOLETE) != 0? */ + + if (!dont_inherit) { + PyEval_MergeCompilerFlags(&cf); + } + result = Py_CompileStringFlags(str, filename, start, &cf); +cleanup: + Py_XDECREF(tmp); + return result; +} + +PyDoc_STRVAR(compile_doc, +"compile(source, filename, mode[, flags[, dont_inherit]]) -> code object\n\ +\n\ +Compile the source string (a Python module, statement or expression)\n\ +into a code object that can be executed by the exec statement or eval().\n\ +The filename will be used for run-time error messages.\n\ +The mode must be 'exec' to compile a module, 'single' to compile a\n\ +single (interactive) statement, or 'eval' to compile an expression.\n\ +The flags argument, if present, controls which future statements influence\n\ +the compilation of the code.\n\ +The dont_inherit argument, if non-zero, stops the compilation inheriting\n\ +the effects of any future statements in effect in the code calling\n\ +compile; if absent or zero these statements do influence the compilation,\n\ +in addition to any features explicitly specified."); + +static PyObject * +builtin_dir(PyObject *self, PyObject *args) +{ + PyObject *arg = NULL; + + if (!PyArg_UnpackTuple(args, "dir", 0, 1, &arg)) + return NULL; + return PyObject_Dir(arg); +} + +PyDoc_STRVAR(dir_doc, +"dir([object]) -> list of strings\n" +"\n" +"Return an alphabetized list of names comprising (some of) the attributes\n" +"of the given object, and of attributes reachable from it:\n" +"\n" +"No argument: the names in the current scope.\n" +"Module object: the module attributes.\n" +"Type or class object: its attributes, and recursively the attributes of\n" +" its bases.\n" +"Otherwise: its attributes, its class's attributes, and recursively the\n" +" attributes of its class's base classes."); + +static PyObject * +builtin_divmod(PyObject *self, PyObject *args) +{ + PyObject *v, *w; + + if (!PyArg_UnpackTuple(args, "divmod", 2, 2, &v, &w)) + return NULL; + return PyNumber_Divmod(v, w); +} + +PyDoc_STRVAR(divmod_doc, +"divmod(x, y) -> (div, mod)\n\ +\n\ +Return the tuple ((x-x%y)/y, x%y). Invariant: div*y + mod == x."); + + +static PyObject * +builtin_eval(PyObject *self, PyObject *args) +{ + PyObject *cmd, *result, *tmp = NULL; + PyObject *globals = Py_None, *locals = Py_None; + char *str; + PyCompilerFlags cf; + + if (!PyArg_UnpackTuple(args, "eval", 1, 3, &cmd, &globals, &locals)) + return NULL; + if (locals != Py_None && !PyMapping_Check(locals)) { + PyErr_SetString(PyExc_TypeError, "locals must be a mapping"); + return NULL; + } + if (globals != Py_None && !PyDict_Check(globals)) { + PyErr_SetString(PyExc_TypeError, PyMapping_Check(globals) ? + "globals must be a real dict; try eval(expr, {}, mapping)" + : "globals must be a dict"); + return NULL; + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) + locals = PyEval_GetLocals(); + } + else if (locals == Py_None) + locals = globals; + + if (globals == NULL || locals == NULL) { + PyErr_SetString(PyExc_TypeError, + "eval must be given globals and locals " + "when called without a frame"); + return NULL; + } + + if (PyDict_GetItemString(globals, "__builtins__") == NULL) { + if (PyDict_SetItemString(globals, "__builtins__", + PyEval_GetBuiltins()) != 0) + return NULL; + } + + if (PyCode_Check(cmd)) { + if (PyCode_GetNumFree((PyCodeObject *)cmd) > 0) { + PyErr_SetString(PyExc_TypeError, + "code object passed to eval() may not contain free variables"); + return NULL; + } + return PyEval_EvalCode((PyCodeObject *) cmd, globals, locals); + } + + if (!PyString_Check(cmd) && + !PyUnicode_Check(cmd)) { + PyErr_SetString(PyExc_TypeError, + "eval() arg 1 must be a string or code object"); + return NULL; + } + cf.cf_flags = 0; + +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(cmd)) { + tmp = PyUnicode_AsUTF8String(cmd); + if (tmp == NULL) + return NULL; + cmd = tmp; + cf.cf_flags |= PyCF_SOURCE_IS_UTF8; + } +#endif + if (PyString_AsStringAndSize(cmd, &str, NULL)) { + Py_XDECREF(tmp); + return NULL; + } + while (*str == ' ' || *str == '\t') + str++; + + (void)PyEval_MergeCompilerFlags(&cf); + result = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); + Py_XDECREF(tmp); + return result; +} + +PyDoc_STRVAR(eval_doc, +"eval(source[, globals[, locals]]) -> value\n\ +\n\ +Evaluate the source in the context of globals and locals.\n\ +The source may be a string representing a Python expression\n\ +or a code object as returned by compile().\n\ +The globals must be a dictionary and locals can be any mapping,\n\ +defaulting to the current globals and locals.\n\ +If only globals is given, locals defaults to it.\n"); + + +static PyObject * +builtin_execfile(PyObject *self, PyObject *args) +{ + char *filename; + PyObject *globals = Py_None, *locals = Py_None; + PyObject *res; + FILE* fp = NULL; + PyCompilerFlags cf; + int exists; + + if (!PyArg_ParseTuple(args, "s|O!O:execfile", + &filename, + &PyDict_Type, &globals, + &locals)) + return NULL; + if (locals != Py_None && !PyMapping_Check(locals)) { + PyErr_SetString(PyExc_TypeError, "locals must be a mapping"); + return NULL; + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) + locals = PyEval_GetLocals(); + } + else if (locals == Py_None) + locals = globals; + if (PyDict_GetItemString(globals, "__builtins__") == NULL) { + if (PyDict_SetItemString(globals, "__builtins__", + PyEval_GetBuiltins()) != 0) + return NULL; + } + + exists = 0; + /* Test for existence or directory. */ +#if defined(PLAN9) + { + Dir *d; + + if ((d = dirstat(filename))!=nil) { + if(d->mode & DMDIR) + werrstr("is a directory"); + else + exists = 1; + free(d); + } + } +#elif defined(RISCOS) + if (object_exists(filename)) { + if (isdir(filename)) + errno = EISDIR; + else + exists = 1; + } +#else /* standard Posix */ + { + struct stat s; + if (stat(filename, &s) == 0) { + if (S_ISDIR(s.st_mode)) +# if defined(PYOS_OS2) && defined(PYCC_VACPP) + errno = EOS2ERR; +# else + errno = EISDIR; +# endif + else + exists = 1; + } + } +#endif + + if (exists) { + Py_BEGIN_ALLOW_THREADS + fp = fopen(filename, "r" PY_STDIOTEXTMODE); + Py_END_ALLOW_THREADS + + if (fp == NULL) { + exists = 0; + } + } + + if (!exists) { + PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); + return NULL; + } + cf.cf_flags = 0; + if (PyEval_MergeCompilerFlags(&cf)) + res = PyRun_FileExFlags(fp, filename, Py_file_input, globals, + locals, 1, &cf); + else + res = PyRun_FileEx(fp, filename, Py_file_input, globals, + locals, 1); + return res; +} + +PyDoc_STRVAR(execfile_doc, +"execfile(filename[, globals[, locals]])\n\ +\n\ +Read and execute a Python script from a file.\n\ +The globals and locals are dictionaries, defaulting to the current\n\ +globals and locals. If only globals is given, locals defaults to it."); + + +static PyObject * +builtin_getattr(PyObject *self, PyObject *args) +{ + PyObject *v, *result, *dflt = NULL; + PyObject *name; + + if (!PyArg_UnpackTuple(args, "getattr", 2, 3, &v, &name, &dflt)) + return NULL; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(name)) { + name = _PyUnicode_AsDefaultEncodedString(name, NULL); + if (name == NULL) + return NULL; + } +#endif + + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "getattr(): attribute name must be string"); + return NULL; + } + result = PyObject_GetAttr(v, name); + if (result == NULL && dflt != NULL && + PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + Py_INCREF(dflt); + result = dflt; + } + return result; +} + +PyDoc_STRVAR(getattr_doc, +"getattr(object, name[, default]) -> value\n\ +\n\ +Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.\n\ +When a default argument is given, it is returned when the attribute doesn't\n\ +exist; without it, an exception is raised in that case."); + + +static PyObject * +builtin_globals(PyObject *self) +{ + PyObject *d; + + d = PyEval_GetGlobals(); + Py_XINCREF(d); + return d; +} + +PyDoc_STRVAR(globals_doc, +"globals() -> dictionary\n\ +\n\ +Return the dictionary containing the current scope's global variables."); + + +static PyObject * +builtin_hasattr(PyObject *self, PyObject *args) +{ + PyObject *v; + PyObject *name; + + if (!PyArg_UnpackTuple(args, "hasattr", 2, 2, &v, &name)) + return NULL; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(name)) { + name = _PyUnicode_AsDefaultEncodedString(name, NULL); + if (name == NULL) + return NULL; + } +#endif + + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "hasattr(): attribute name must be string"); + return NULL; + } + v = PyObject_GetAttr(v, name); + if (v == NULL) { + PyErr_Clear(); + Py_INCREF(Py_False); + return Py_False; + } + Py_DECREF(v); + Py_INCREF(Py_True); + return Py_True; +} + +PyDoc_STRVAR(hasattr_doc, +"hasattr(object, name) -> bool\n\ +\n\ +Return whether the object has an attribute with the given name.\n\ +(This is done by calling getattr(object, name) and catching exceptions.)"); + + +static PyObject * +builtin_id(PyObject *self, PyObject *v) +{ + return PyLong_FromVoidPtr(v); +} + +PyDoc_STRVAR(id_doc, +"id(object) -> integer\n\ +\n\ +Return the identity of an object. This is guaranteed to be unique among\n\ +simultaneously existing objects. (Hint: it's the object's memory address.)"); + + +static PyObject * +builtin_map(PyObject *self, PyObject *args) +{ + typedef struct { + PyObject *it; /* the iterator object */ + int saw_StopIteration; /* bool: did the iterator end? */ + } sequence; + + PyObject *func, *result; + sequence *seqs = NULL, *sqp; + Py_ssize_t n, len; + register int i, j; + + n = PyTuple_Size(args); + if (n < 2) { + PyErr_SetString(PyExc_TypeError, + "map() requires at least two args"); + return NULL; + } + + func = PyTuple_GetItem(args, 0); + n--; + + if (func == Py_None && n == 1) { + /* map(None, S) is the same as list(S). */ + return PySequence_List(PyTuple_GetItem(args, 1)); + } + + /* Get space for sequence descriptors. Must NULL out the iterator + * pointers so that jumping to Fail_2 later doesn't see trash. + */ + if ((seqs = PyMem_NEW(sequence, n)) == NULL) { + PyErr_NoMemory(); + return NULL; + } + for (i = 0; i < n; ++i) { + seqs[i].it = (PyObject*)NULL; + seqs[i].saw_StopIteration = 0; + } + + /* Do a first pass to obtain iterators for the arguments, and set len + * to the largest of their lengths. + */ + len = 0; + for (i = 0, sqp = seqs; i < n; ++i, ++sqp) { + PyObject *curseq; + Py_ssize_t curlen; + + /* Get iterator. */ + curseq = PyTuple_GetItem(args, i+1); + sqp->it = PyObject_GetIter(curseq); + if (sqp->it == NULL) { + static char errmsg[] = + "argument %d to map() must support iteration"; + char errbuf[sizeof(errmsg) + 25]; + PyOS_snprintf(errbuf, sizeof(errbuf), errmsg, i+2); + PyErr_SetString(PyExc_TypeError, errbuf); + goto Fail_2; + } + + /* Update len. */ + curlen = _PyObject_LengthHint(curseq); + if (curlen < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + goto Fail_2; + } + PyErr_Clear(); + curlen = 8; /* arbitrary */ + } + if (curlen > len) + len = curlen; + } + + /* Get space for the result list. */ + if ((result = (PyObject *) PyList_New(len)) == NULL) + goto Fail_2; + + /* Iterate over the sequences until all have stopped. */ + for (i = 0; ; ++i) { + PyObject *alist, *item=NULL, *value; + int numactive = 0; + + if (func == Py_None && n == 1) + alist = NULL; + else if ((alist = PyTuple_New(n)) == NULL) + goto Fail_1; + + for (j = 0, sqp = seqs; j < n; ++j, ++sqp) { + if (sqp->saw_StopIteration) { + Py_INCREF(Py_None); + item = Py_None; + } + else { + item = PyIter_Next(sqp->it); + if (item) + ++numactive; + else { + if (PyErr_Occurred()) { + Py_XDECREF(alist); + goto Fail_1; + } + Py_INCREF(Py_None); + item = Py_None; + sqp->saw_StopIteration = 1; + } + } + if (alist) + PyTuple_SET_ITEM(alist, j, item); + else + break; + } + + if (!alist) + alist = item; + + if (numactive == 0) { + Py_DECREF(alist); + break; + } + + if (func == Py_None) + value = alist; + else { + value = PyEval_CallObject(func, alist); + Py_DECREF(alist); + if (value == NULL) + goto Fail_1; + } + if (i >= len) { + int status = PyList_Append(result, value); + Py_DECREF(value); + if (status < 0) + goto Fail_1; + } + else if (PyList_SetItem(result, i, value) < 0) + goto Fail_1; + } + + if (i < len && PyList_SetSlice(result, i, len, NULL) < 0) + goto Fail_1; + + goto Succeed; + +Fail_1: + Py_DECREF(result); +Fail_2: + result = NULL; +Succeed: + assert(seqs); + for (i = 0; i < n; ++i) + Py_XDECREF(seqs[i].it); + PyMem_DEL(seqs); + return result; +} + +PyDoc_STRVAR(map_doc, +"map(function, sequence[, sequence, ...]) -> list\n\ +\n\ +Return a list of the results of applying the function to the items of\n\ +the argument sequence(s). If more than one sequence is given, the\n\ +function is called with an argument list consisting of the corresponding\n\ +item of each sequence, substituting None for missing values when not all\n\ +sequences have the same length. If the function is None, return a list of\n\ +the items of the sequence (or a list of tuples if more than one sequence)."); + + +static PyObject * +builtin_setattr(PyObject *self, PyObject *args) +{ + PyObject *v; + PyObject *name; + PyObject *value; + + if (!PyArg_UnpackTuple(args, "setattr", 3, 3, &v, &name, &value)) + return NULL; + if (PyObject_SetAttr(v, name, value) != 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setattr_doc, +"setattr(object, name, value)\n\ +\n\ +Set a named attribute on an object; setattr(x, 'y', v) is equivalent to\n\ +``x.y = v''."); + + +static PyObject * +builtin_delattr(PyObject *self, PyObject *args) +{ + PyObject *v; + PyObject *name; + + if (!PyArg_UnpackTuple(args, "delattr", 2, 2, &v, &name)) + return NULL; + if (PyObject_SetAttr(v, name, (PyObject *)NULL) != 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(delattr_doc, +"delattr(object, name)\n\ +\n\ +Delete a named attribute on an object; delattr(x, 'y') is equivalent to\n\ +``del x.y''."); + + +static PyObject * +builtin_hash(PyObject *self, PyObject *v) +{ + long x; + + x = PyObject_Hash(v); + if (x == -1) + return NULL; + return PyInt_FromLong(x); +} + +PyDoc_STRVAR(hash_doc, +"hash(object) -> integer\n\ +\n\ +Return a hash value for the object. Two objects with the same value have\n\ +the same hash value. The reverse is not necessarily true, but likely."); + + +static PyObject * +builtin_hex(PyObject *self, PyObject *v) +{ + PyNumberMethods *nb; + PyObject *res; + + if ((nb = v->ob_type->tp_as_number) == NULL || + nb->nb_hex == NULL) { + PyErr_SetString(PyExc_TypeError, + "hex() argument can't be converted to hex"); + return NULL; + } + res = (*nb->nb_hex)(v); + if (res && !PyString_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__hex__ returned non-string (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; +} + +PyDoc_STRVAR(hex_doc, +"hex(number) -> string\n\ +\n\ +Return the hexadecimal representation of an integer or long integer."); + + +static PyObject *builtin_raw_input(PyObject *, PyObject *); + +static PyObject * +builtin_input(PyObject *self, PyObject *args) +{ + PyObject *line; + char *str; + PyObject *res; + PyObject *globals, *locals; + PyCompilerFlags cf; + + line = builtin_raw_input(self, args); + if (line == NULL) + return line; + if (!PyArg_Parse(line, "s;embedded '\\0' in input line", &str)) + return NULL; + while (*str == ' ' || *str == '\t') + str++; + globals = PyEval_GetGlobals(); + locals = PyEval_GetLocals(); + if (PyDict_GetItemString(globals, "__builtins__") == NULL) { + if (PyDict_SetItemString(globals, "__builtins__", + PyEval_GetBuiltins()) != 0) + return NULL; + } + cf.cf_flags = 0; + PyEval_MergeCompilerFlags(&cf); + res = PyRun_StringFlags(str, Py_eval_input, globals, locals, &cf); + Py_DECREF(line); + return res; +} + +PyDoc_STRVAR(input_doc, +"input([prompt]) -> value\n\ +\n\ +Equivalent to eval(raw_input(prompt))."); + + +static PyObject * +builtin_intern(PyObject *self, PyObject *args) +{ + PyObject *s; + if (!PyArg_ParseTuple(args, "S:intern", &s)) + return NULL; + if (!PyString_CheckExact(s)) { + PyErr_SetString(PyExc_TypeError, + "can't intern subclass of string"); + return NULL; + } + Py_INCREF(s); + PyString_InternInPlace(&s); + return s; +} + +PyDoc_STRVAR(intern_doc, +"intern(string) -> string\n\ +\n\ +``Intern'' the given string. This enters the string in the (global)\n\ +table of interned strings whose purpose is to speed up dictionary lookups.\n\ +Return the string itself or the previously interned string object with the\n\ +same value."); + + +static PyObject * +builtin_iter(PyObject *self, PyObject *args) +{ + PyObject *v, *w = NULL; + + if (!PyArg_UnpackTuple(args, "iter", 1, 2, &v, &w)) + return NULL; + if (w == NULL) + return PyObject_GetIter(v); + if (!PyCallable_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "iter(v, w): v must be callable"); + return NULL; + } + return PyCallIter_New(v, w); +} + +PyDoc_STRVAR(iter_doc, +"iter(collection) -> iterator\n\ +iter(callable, sentinel) -> iterator\n\ +\n\ +Get an iterator from an object. In the first form, the argument must\n\ +supply its own iterator, or be a sequence.\n\ +In the second form, the callable is called until it returns the sentinel."); + + +static PyObject * +builtin_len(PyObject *self, PyObject *v) +{ + Py_ssize_t res; + + res = PyObject_Size(v); + if (res < 0 && PyErr_Occurred()) + return NULL; + return PyInt_FromSsize_t(res); +} + +PyDoc_STRVAR(len_doc, +"len(object) -> integer\n\ +\n\ +Return the number of items of a sequence or mapping."); + + +static PyObject * +builtin_locals(PyObject *self) +{ + PyObject *d; + + d = PyEval_GetLocals(); + Py_XINCREF(d); + return d; +} + +PyDoc_STRVAR(locals_doc, +"locals() -> dictionary\n\ +\n\ +Update and return a dictionary containing the current scope's local variables."); + + +static PyObject * +min_max(PyObject *args, PyObject *kwds, int op) +{ + PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL; + const char *name = op == Py_LT ? "min" : "max"; + + if (PyTuple_Size(args) > 1) + v = args; + else if (!PyArg_UnpackTuple(args, (char *)name, 1, 1, &v)) + return NULL; + + if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds)) { + keyfunc = PyDict_GetItemString(kwds, "key"); + if (PyDict_Size(kwds)!=1 || keyfunc == NULL) { + PyErr_Format(PyExc_TypeError, + "%s() got an unexpected keyword argument", name); + return NULL; + } + } + + it = PyObject_GetIter(v); + if (it == NULL) + return NULL; + + maxitem = NULL; /* the result */ + maxval = NULL; /* the value associated with the result */ + while (( item = PyIter_Next(it) )) { + /* get the value from the key function */ + if (keyfunc != NULL) { + val = PyObject_CallFunctionObjArgs(keyfunc, item, NULL); + if (val == NULL) + goto Fail_it_item; + } + /* no key function; the value is the item */ + else { + val = item; + Py_INCREF(val); + } + + /* maximum value and item are unset; set them */ + if (maxval == NULL) { + maxitem = item; + maxval = val; + } + /* maximum value and item are set; update them as necessary */ + else { + int cmp = PyObject_RichCompareBool(val, maxval, op); + if (cmp < 0) + goto Fail_it_item_and_val; + else if (cmp > 0) { + Py_DECREF(maxval); + Py_DECREF(maxitem); + maxval = val; + maxitem = item; + } + else { + Py_DECREF(item); + Py_DECREF(val); + } + } + } + if (PyErr_Occurred()) + goto Fail_it; + if (maxval == NULL) { + PyErr_Format(PyExc_ValueError, + "%s() arg is an empty sequence", name); + assert(maxitem == NULL); + } + else + Py_DECREF(maxval); + Py_DECREF(it); + return maxitem; + +Fail_it_item_and_val: + Py_DECREF(val); +Fail_it_item: + Py_DECREF(item); +Fail_it: + Py_XDECREF(maxval); + Py_XDECREF(maxitem); + Py_DECREF(it); + return NULL; +} + +static PyObject * +builtin_min(PyObject *self, PyObject *args, PyObject *kwds) +{ + return min_max(args, kwds, Py_LT); +} + +PyDoc_STRVAR(min_doc, +"min(iterable[, key=func]) -> value\n\ +min(a, b, c, ...[, key=func]) -> value\n\ +\n\ +With a single iterable argument, return its smallest item.\n\ +With two or more arguments, return the smallest argument."); + + +static PyObject * +builtin_max(PyObject *self, PyObject *args, PyObject *kwds) +{ + return min_max(args, kwds, Py_GT); +} + +PyDoc_STRVAR(max_doc, +"max(iterable[, key=func]) -> value\n\ +max(a, b, c, ...[, key=func]) -> value\n\ +\n\ +With a single iterable argument, return its largest item.\n\ +With two or more arguments, return the largest argument."); + + +static PyObject * +builtin_oct(PyObject *self, PyObject *v) +{ + PyNumberMethods *nb; + PyObject *res; + + if (v == NULL || (nb = v->ob_type->tp_as_number) == NULL || + nb->nb_oct == NULL) { + PyErr_SetString(PyExc_TypeError, + "oct() argument can't be converted to oct"); + return NULL; + } + res = (*nb->nb_oct)(v); + if (res && !PyString_Check(res)) { + PyErr_Format(PyExc_TypeError, + "__oct__ returned non-string (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; +} + +PyDoc_STRVAR(oct_doc, +"oct(number) -> string\n\ +\n\ +Return the octal representation of an integer or long integer."); + + +static PyObject * +builtin_open(PyObject *self, PyObject *args, PyObject *kwds) +{ + return PyObject_Call((PyObject*)&PyFile_Type, args, kwds); +} + +PyDoc_STRVAR(open_doc, +"open(name[, mode[, buffering]]) -> file object\n\ +\n\ +Open a file using the file() type, returns a file object."); + + +static PyObject * +builtin_ord(PyObject *self, PyObject* obj) +{ + long ord; + Py_ssize_t size; + + if (PyString_Check(obj)) { + size = PyString_GET_SIZE(obj); + if (size == 1) { + ord = (long)((unsigned char)*PyString_AS_STRING(obj)); + return PyInt_FromLong(ord); + } +#ifdef Py_USING_UNICODE + } else if (PyUnicode_Check(obj)) { + size = PyUnicode_GET_SIZE(obj); + if (size == 1) { + ord = (long)*PyUnicode_AS_UNICODE(obj); + return PyInt_FromLong(ord); + } +#endif + } else { + PyErr_Format(PyExc_TypeError, + "ord() expected string of length 1, but " \ + "%.200s found", obj->ob_type->tp_name); + return NULL; + } + + PyErr_Format(PyExc_TypeError, + "ord() expected a character, " + "but string of length %zd found", + size); + return NULL; +} + +PyDoc_STRVAR(ord_doc, +"ord(c) -> integer\n\ +\n\ +Return the integer ordinal of a one-character string."); + + +static PyObject * +builtin_pow(PyObject *self, PyObject *args) +{ + PyObject *v, *w, *z = Py_None; + + if (!PyArg_UnpackTuple(args, "pow", 2, 3, &v, &w, &z)) + return NULL; + return PyNumber_Power(v, w, z); +} + +PyDoc_STRVAR(pow_doc, +"pow(x, y[, z]) -> number\n\ +\n\ +With two arguments, equivalent to x**y. With three arguments,\n\ +equivalent to (x**y) % z, but may be more efficient (e.g. for longs)."); + + + +/* Return number of items in range (lo, hi, step), when arguments are + * PyInt or PyLong objects. step > 0 required. Return a value < 0 if + * & only if the true value is too large to fit in a signed long. + * Arguments MUST return 1 with either PyInt_Check() or + * PyLong_Check(). Return -1 when there is an error. + */ +static long +get_len_of_range_longs(PyObject *lo, PyObject *hi, PyObject *step) +{ + /* ------------------------------------------------------------- + Algorithm is equal to that of get_len_of_range(), but it operates + on PyObjects (which are assumed to be PyLong or PyInt objects). + ---------------------------------------------------------------*/ + long n; + PyObject *diff = NULL; + PyObject *one = NULL; + PyObject *tmp1 = NULL, *tmp2 = NULL, *tmp3 = NULL; + /* holds sub-expression evaluations */ + + /* if (lo >= hi), return length of 0. */ + if (PyObject_Compare(lo, hi) >= 0) + return 0; + + if ((one = PyLong_FromLong(1L)) == NULL) + goto Fail; + + if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL) + goto Fail; + + if ((diff = PyNumber_Subtract(tmp1, one)) == NULL) + goto Fail; + + if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL) + goto Fail; + + if ((tmp3 = PyNumber_Add(tmp2, one)) == NULL) + goto Fail; + + n = PyLong_AsLong(tmp3); + if (PyErr_Occurred()) { /* Check for Overflow */ + PyErr_Clear(); + goto Fail; + } + + Py_DECREF(tmp3); + Py_DECREF(tmp2); + Py_DECREF(diff); + Py_DECREF(tmp1); + Py_DECREF(one); + return n; + + Fail: + Py_XDECREF(tmp3); + Py_XDECREF(tmp2); + Py_XDECREF(diff); + Py_XDECREF(tmp1); + Py_XDECREF(one); + return -1; +} + +/* An extension of builtin_range() that handles the case when PyLong + * arguments are given. */ +static PyObject * +handle_range_longs(PyObject *self, PyObject *args) +{ + PyObject *ilow; + PyObject *ihigh = NULL; + PyObject *istep = NULL; + + PyObject *curnum = NULL; + PyObject *v = NULL; + long bign; + int i, n; + int cmp_result; + + PyObject *zero = PyLong_FromLong(0); + + if (zero == NULL) + return NULL; + + if (!PyArg_UnpackTuple(args, "range", 1, 3, &ilow, &ihigh, &istep)) { + Py_DECREF(zero); + return NULL; + } + + /* Figure out which way we were called, supply defaults, and be + * sure to incref everything so that the decrefs at the end + * are correct. + */ + assert(ilow != NULL); + if (ihigh == NULL) { + /* only 1 arg -- it's the upper limit */ + ihigh = ilow; + ilow = NULL; + } + assert(ihigh != NULL); + Py_INCREF(ihigh); + + /* ihigh correct now; do ilow */ + if (ilow == NULL) + ilow = zero; + Py_INCREF(ilow); + + /* ilow and ihigh correct now; do istep */ + if (istep == NULL) { + istep = PyLong_FromLong(1L); + if (istep == NULL) + goto Fail; + } + else { + Py_INCREF(istep); + } + + if (!PyInt_Check(ilow) && !PyLong_Check(ilow)) { + PyErr_Format(PyExc_TypeError, + "range() integer start argument expected, got %s.", + ilow->ob_type->tp_name); + goto Fail; + } + + if (!PyInt_Check(ihigh) && !PyLong_Check(ihigh)) { + PyErr_Format(PyExc_TypeError, + "range() integer end argument expected, got %s.", + ihigh->ob_type->tp_name); + goto Fail; + } + + if (!PyInt_Check(istep) && !PyLong_Check(istep)) { + PyErr_Format(PyExc_TypeError, + "range() integer step argument expected, got %s.", + istep->ob_type->tp_name); + goto Fail; + } + + if (PyObject_Cmp(istep, zero, &cmp_result) == -1) + goto Fail; + if (cmp_result == 0) { + PyErr_SetString(PyExc_ValueError, + "range() step argument must not be zero"); + goto Fail; + } + + if (cmp_result > 0) + bign = get_len_of_range_longs(ilow, ihigh, istep); + else { + PyObject *neg_istep = PyNumber_Negative(istep); + if (neg_istep == NULL) + goto Fail; + bign = get_len_of_range_longs(ihigh, ilow, neg_istep); + Py_DECREF(neg_istep); + } + + n = (int)bign; + if (bign < 0 || (long)n != bign) { + PyErr_SetString(PyExc_OverflowError, + "range() result has too many items"); + goto Fail; + } + + v = PyList_New(n); + if (v == NULL) + goto Fail; + + curnum = ilow; + Py_INCREF(curnum); + + for (i = 0; i < n; i++) { + PyObject *w = PyNumber_Long(curnum); + PyObject *tmp_num; + if (w == NULL) + goto Fail; + + PyList_SET_ITEM(v, i, w); + + tmp_num = PyNumber_Add(curnum, istep); + if (tmp_num == NULL) + goto Fail; + + Py_DECREF(curnum); + curnum = tmp_num; + } + Py_DECREF(ilow); + Py_DECREF(ihigh); + Py_DECREF(istep); + Py_DECREF(zero); + Py_DECREF(curnum); + return v; + + Fail: + Py_DECREF(ilow); + Py_DECREF(ihigh); + Py_XDECREF(istep); + Py_DECREF(zero); + Py_XDECREF(curnum); + Py_XDECREF(v); + return NULL; +} + +/* Return number of items in range/xrange (lo, hi, step). step > 0 + * required. Return a value < 0 if & only if the true value is too + * large to fit in a signed long. + */ +static long +get_len_of_range(long lo, long hi, long step) +{ + /* ------------------------------------------------------------- + If lo >= hi, the range is empty. + Else if n values are in the range, the last one is + lo + (n-1)*step, which must be <= hi-1. Rearranging, + n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives + the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so + the RHS is non-negative and so truncation is the same as the + floor. Letting M be the largest positive long, the worst case + for the RHS numerator is hi=M, lo=-M-1, and then + hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough + precision to compute the RHS exactly. + ---------------------------------------------------------------*/ + long n = 0; + if (lo < hi) { + unsigned long uhi = (unsigned long)hi; + unsigned long ulo = (unsigned long)lo; + unsigned long diff = uhi - ulo - 1; + n = (long)(diff / (unsigned long)step + 1); + } + return n; +} + +static PyObject * +builtin_range(PyObject *self, PyObject *args) +{ + long ilow = 0, ihigh = 0, istep = 1; + long bign; + int i, n; + + PyObject *v; + + if (PyTuple_Size(args) <= 1) { + if (!PyArg_ParseTuple(args, + "l;range() requires 1-3 int arguments", + &ihigh)) { + PyErr_Clear(); + return handle_range_longs(self, args); + } + } + else { + if (!PyArg_ParseTuple(args, + "ll|l;range() requires 1-3 int arguments", + &ilow, &ihigh, &istep)) { + PyErr_Clear(); + return handle_range_longs(self, args); + } + } + if (istep == 0) { + PyErr_SetString(PyExc_ValueError, + "range() step argument must not be zero"); + return NULL; + } + if (istep > 0) + bign = get_len_of_range(ilow, ihigh, istep); + else + bign = get_len_of_range(ihigh, ilow, -istep); + n = (int)bign; + if (bign < 0 || (long)n != bign) { + PyErr_SetString(PyExc_OverflowError, + "range() result has too many items"); + return NULL; + } + v = PyList_New(n); + if (v == NULL) + return NULL; + for (i = 0; i < n; i++) { + PyObject *w = PyInt_FromLong(ilow); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SET_ITEM(v, i, w); + ilow += istep; + } + return v; +} + +PyDoc_STRVAR(range_doc, +"range([start,] stop[, step]) -> list of integers\n\ +\n\ +Return a list containing an arithmetic progression of integers.\n\ +range(i, j) returns [i, i+1, i+2, ..., j-1]; start (!) defaults to 0.\n\ +When step is given, it specifies the increment (or decrement).\n\ +For example, range(4) returns [0, 1, 2, 3]. The end point is omitted!\n\ +These are exactly the valid indices for a list of 4 elements."); + + +static PyObject * +builtin_raw_input(PyObject *self, PyObject *args) +{ + PyObject *v = NULL; + PyObject *fin = PySys_GetObject("stdin"); + PyObject *fout = PySys_GetObject("stdout"); + + if (!PyArg_UnpackTuple(args, "[raw_]input", 0, 1, &v)) + return NULL; + + if (fin == NULL) { + PyErr_SetString(PyExc_RuntimeError, "[raw_]input: lost sys.stdin"); + return NULL; + } + if (fout == NULL) { + PyErr_SetString(PyExc_RuntimeError, "[raw_]input: lost sys.stdout"); + return NULL; + } + if (PyFile_SoftSpace(fout, 0)) { + if (PyFile_WriteString(" ", fout) != 0) + return NULL; + } + if (PyFile_AsFile(fin) && PyFile_AsFile(fout) + && isatty(fileno(PyFile_AsFile(fin))) + && isatty(fileno(PyFile_AsFile(fout)))) { + PyObject *po; + char *prompt; + char *s; + PyObject *result; + if (v != NULL) { + po = PyObject_Str(v); + if (po == NULL) + return NULL; + prompt = PyString_AsString(po); + if (prompt == NULL) + return NULL; + } + else { + po = NULL; + prompt = ""; + } + s = PyOS_Readline(PyFile_AsFile(fin), PyFile_AsFile(fout), + prompt); + Py_XDECREF(po); + if (s == NULL) { + if (!PyErr_Occurred()) + PyErr_SetNone(PyExc_KeyboardInterrupt); + return NULL; + } + if (*s == '\0') { + PyErr_SetNone(PyExc_EOFError); + result = NULL; + } + else { /* strip trailing '\n' */ + size_t len = strlen(s); + if (len > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "[raw_]input: input too long"); + result = NULL; + } + else { + result = PyString_FromStringAndSize(s, len-1); + } + } + PyMem_FREE(s); + return result; + } + if (v != NULL) { + if (PyFile_WriteObject(v, fout, Py_PRINT_RAW) != 0) + return NULL; + } + return PyFile_GetLine(fin, -1); +} + +PyDoc_STRVAR(raw_input_doc, +"raw_input([prompt]) -> string\n\ +\n\ +Read a string from standard input. The trailing newline is stripped.\n\ +If the user hits EOF (Unix: Ctl-D, Windows: Ctl-Z+Return), raise EOFError.\n\ +On Unix, GNU readline is used if enabled. The prompt string, if given,\n\ +is printed without a trailing newline before reading."); + + +static PyObject * +builtin_reduce(PyObject *self, PyObject *args) +{ + PyObject *seq, *func, *result = NULL, *it; + + if (!PyArg_UnpackTuple(args, "reduce", 2, 3, &func, &seq, &result)) + return NULL; + if (result != NULL) + Py_INCREF(result); + + it = PyObject_GetIter(seq); + if (it == NULL) { + PyErr_SetString(PyExc_TypeError, + "reduce() arg 2 must support iteration"); + Py_XDECREF(result); + return NULL; + } + + if ((args = PyTuple_New(2)) == NULL) + goto Fail; + + for (;;) { + PyObject *op2; + + if (args->ob_refcnt > 1) { + Py_DECREF(args); + if ((args = PyTuple_New(2)) == NULL) + goto Fail; + } + + op2 = PyIter_Next(it); + if (op2 == NULL) { + if (PyErr_Occurred()) + goto Fail; + break; + } + + if (result == NULL) + result = op2; + else { + PyTuple_SetItem(args, 0, result); + PyTuple_SetItem(args, 1, op2); + if ((result = PyEval_CallObject(func, args)) == NULL) + goto Fail; + } + } + + Py_DECREF(args); + + if (result == NULL) + PyErr_SetString(PyExc_TypeError, + "reduce() of empty sequence with no initial value"); + + Py_DECREF(it); + return result; + +Fail: + Py_XDECREF(args); + Py_XDECREF(result); + Py_DECREF(it); + return NULL; +} + +PyDoc_STRVAR(reduce_doc, +"reduce(function, sequence[, initial]) -> value\n\ +\n\ +Apply a function of two arguments cumulatively to the items of a sequence,\n\ +from left to right, so as to reduce the sequence to a single value.\n\ +For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates\n\ +((((1+2)+3)+4)+5). If initial is present, it is placed before the items\n\ +of the sequence in the calculation, and serves as a default when the\n\ +sequence is empty."); + + +static PyObject * +builtin_reload(PyObject *self, PyObject *v) +{ + return PyImport_ReloadModule(v); +} + +PyDoc_STRVAR(reload_doc, +"reload(module) -> module\n\ +\n\ +Reload the module. The module must have been successfully imported before."); + + +static PyObject * +builtin_repr(PyObject *self, PyObject *v) +{ + return PyObject_Repr(v); +} + +PyDoc_STRVAR(repr_doc, +"repr(object) -> string\n\ +\n\ +Return the canonical string representation of the object.\n\ +For most object types, eval(repr(object)) == object."); + + +static PyObject * +builtin_round(PyObject *self, PyObject *args, PyObject *kwds) +{ + double number; + double f; + int ndigits = 0; + int i; + static char *kwlist[] = {"number", "ndigits", 0}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "d|i:round", + kwlist, &number, &ndigits)) + return NULL; + f = 1.0; + i = abs(ndigits); + while (--i >= 0) + f = f*10.0; + if (ndigits < 0) + number /= f; + else + number *= f; + if (number >= 0.0) + number = floor(number + 0.5); + else + number = ceil(number - 0.5); + if (ndigits < 0) + number *= f; + else + number /= f; + return PyFloat_FromDouble(number); +} + +PyDoc_STRVAR(round_doc, +"round(number[, ndigits]) -> floating point number\n\ +\n\ +Round a number to a given precision in decimal digits (default 0 digits).\n\ +This always returns a floating point number. Precision may be negative."); + +static PyObject * +builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *newlist, *v, *seq, *compare=NULL, *keyfunc=NULL, *newargs; + PyObject *callable; + static char *kwlist[] = {"iterable", "cmp", "key", "reverse", 0}; + int reverse; + + /* args 1-4 should match listsort in Objects/listobject.c */ + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOi:sorted", + kwlist, &seq, &compare, &keyfunc, &reverse)) + return NULL; + + newlist = PySequence_List(seq); + if (newlist == NULL) + return NULL; + + callable = PyObject_GetAttrString(newlist, "sort"); + if (callable == NULL) { + Py_DECREF(newlist); + return NULL; + } + + newargs = PyTuple_GetSlice(args, 1, 4); + if (newargs == NULL) { + Py_DECREF(newlist); + Py_DECREF(callable); + return NULL; + } + + v = PyObject_Call(callable, newargs, kwds); + Py_DECREF(newargs); + Py_DECREF(callable); + if (v == NULL) { + Py_DECREF(newlist); + return NULL; + } + Py_DECREF(v); + return newlist; +} + +PyDoc_STRVAR(sorted_doc, +"sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list"); + +static PyObject * +builtin_vars(PyObject *self, PyObject *args) +{ + PyObject *v = NULL; + PyObject *d; + + if (!PyArg_UnpackTuple(args, "vars", 0, 1, &v)) + return NULL; + if (v == NULL) { + d = PyEval_GetLocals(); + if (d == NULL) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, + "vars(): no locals!?"); + } + else + Py_INCREF(d); + } + else { + d = PyObject_GetAttrString(v, "__dict__"); + if (d == NULL) { + PyErr_SetString(PyExc_TypeError, + "vars() argument must have __dict__ attribute"); + return NULL; + } + } + return d; +} + +PyDoc_STRVAR(vars_doc, +"vars([object]) -> dictionary\n\ +\n\ +Without arguments, equivalent to locals().\n\ +With an argument, equivalent to object.__dict__."); + + +static PyObject* +builtin_sum(PyObject *self, PyObject *args) +{ + PyObject *seq; + PyObject *result = NULL; + PyObject *temp, *item, *iter; + + if (!PyArg_UnpackTuple(args, "sum", 1, 2, &seq, &result)) + return NULL; + + iter = PyObject_GetIter(seq); + if (iter == NULL) + return NULL; + + if (result == NULL) { + result = PyInt_FromLong(0); + if (result == NULL) { + Py_DECREF(iter); + return NULL; + } + } else { + /* reject string values for 'start' parameter */ + if (PyObject_TypeCheck(result, &PyBaseString_Type)) { + PyErr_SetString(PyExc_TypeError, + "sum() can't sum strings [use ''.join(seq) instead]"); + Py_DECREF(iter); + return NULL; + } + Py_INCREF(result); + } + + for(;;) { + item = PyIter_Next(iter); + if (item == NULL) { + /* error, or end-of-sequence */ + if (PyErr_Occurred()) { + Py_DECREF(result); + result = NULL; + } + break; + } + temp = PyNumber_Add(result, item); + Py_DECREF(result); + Py_DECREF(item); + result = temp; + if (result == NULL) + break; + } + Py_DECREF(iter); + return result; +} + +PyDoc_STRVAR(sum_doc, +"sum(sequence, start=0) -> value\n\ +\n\ +Returns the sum of a sequence of numbers (NOT strings) plus the value\n\ +of parameter 'start'. When the sequence is empty, returns start."); + + +static PyObject * +builtin_isinstance(PyObject *self, PyObject *args) +{ + PyObject *inst; + PyObject *cls; + int retval; + + if (!PyArg_UnpackTuple(args, "isinstance", 2, 2, &inst, &cls)) + return NULL; + + retval = PyObject_IsInstance(inst, cls); + if (retval < 0) + return NULL; + return PyBool_FromLong(retval); +} + +PyDoc_STRVAR(isinstance_doc, +"isinstance(object, class-or-type-or-tuple) -> bool\n\ +\n\ +Return whether an object is an instance of a class or of a subclass thereof.\n\ +With a type as second argument, return whether that is the object's type.\n\ +The form using a tuple, isinstance(x, (A, B, ...)), is a shortcut for\n\ +isinstance(x, A) or isinstance(x, B) or ... (etc.)."); + + +static PyObject * +builtin_issubclass(PyObject *self, PyObject *args) +{ + PyObject *derived; + PyObject *cls; + int retval; + + if (!PyArg_UnpackTuple(args, "issubclass", 2, 2, &derived, &cls)) + return NULL; + + retval = PyObject_IsSubclass(derived, cls); + if (retval < 0) + return NULL; + return PyBool_FromLong(retval); +} + +PyDoc_STRVAR(issubclass_doc, +"issubclass(C, B) -> bool\n\ +\n\ +Return whether class C is a subclass (i.e., a derived class) of class B.\n\ +When using a tuple as the second argument issubclass(X, (A, B, ...)),\n\ +is a shortcut for issubclass(X, A) or issubclass(X, B) or ... (etc.)."); + + +static PyObject* +builtin_zip(PyObject *self, PyObject *args) +{ + PyObject *ret; + const Py_ssize_t itemsize = PySequence_Length(args); + Py_ssize_t i; + PyObject *itlist; /* tuple of iterators */ + Py_ssize_t len; /* guess at result length */ + + if (itemsize == 0) + return PyList_New(0); + + /* args must be a tuple */ + assert(PyTuple_Check(args)); + + /* Guess at result length: the shortest of the input lengths. + If some argument refuses to say, we refuse to guess too, lest + an argument like xrange(sys.maxint) lead us astray.*/ + len = -1; /* unknown */ + for (i = 0; i < itemsize; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + Py_ssize_t thislen = _PyObject_LengthHint(item); + if (thislen < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + return NULL; + } + PyErr_Clear(); + len = -1; + break; + } + else if (len < 0 || thislen < len) + len = thislen; + } + + /* allocate result list */ + if (len < 0) + len = 10; /* arbitrary */ + if ((ret = PyList_New(len)) == NULL) + return NULL; + + /* obtain iterators */ + itlist = PyTuple_New(itemsize); + if (itlist == NULL) + goto Fail_ret; + for (i = 0; i < itemsize; ++i) { + PyObject *item = PyTuple_GET_ITEM(args, i); + PyObject *it = PyObject_GetIter(item); + if (it == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + PyErr_Format(PyExc_TypeError, + "zip argument #%zd must support iteration", + i+1); + goto Fail_ret_itlist; + } + PyTuple_SET_ITEM(itlist, i, it); + } + + /* build result into ret list */ + for (i = 0; ; ++i) { + int j; + PyObject *next = PyTuple_New(itemsize); + if (!next) + goto Fail_ret_itlist; + + for (j = 0; j < itemsize; j++) { + PyObject *it = PyTuple_GET_ITEM(itlist, j); + PyObject *item = PyIter_Next(it); + if (!item) { + if (PyErr_Occurred()) { + Py_DECREF(ret); + ret = NULL; + } + Py_DECREF(next); + Py_DECREF(itlist); + goto Done; + } + PyTuple_SET_ITEM(next, j, item); + } + + if (i < len) + PyList_SET_ITEM(ret, i, next); + else { + int status = PyList_Append(ret, next); + Py_DECREF(next); + ++len; + if (status < 0) + goto Fail_ret_itlist; + } + } + +Done: + if (ret != NULL && i < len) { + /* The list is too big. */ + if (PyList_SetSlice(ret, i, len, NULL) < 0) + return NULL; + } + return ret; + +Fail_ret_itlist: + Py_DECREF(itlist); +Fail_ret: + Py_DECREF(ret); + return NULL; +} + + +PyDoc_STRVAR(zip_doc, +"zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]\n\ +\n\ +Return a list of tuples, where each tuple contains the i-th element\n\ +from each of the argument sequences. The returned list is truncated\n\ +in length to the length of the shortest argument sequence."); + + +static PyMethodDef builtin_methods[] = { + {"__import__", (PyCFunction)builtin___import__, METH_VARARGS | METH_KEYWORDS, import_doc}, + {"abs", builtin_abs, METH_O, abs_doc}, + {"all", builtin_all, METH_O, all_doc}, + {"any", builtin_any, METH_O, any_doc}, + {"apply", builtin_apply, METH_VARARGS, apply_doc}, + {"callable", builtin_callable, METH_O, callable_doc}, + {"chr", builtin_chr, METH_VARARGS, chr_doc}, + {"cmp", builtin_cmp, METH_VARARGS, cmp_doc}, + {"coerce", builtin_coerce, METH_VARARGS, coerce_doc}, + {"compile", builtin_compile, METH_VARARGS, compile_doc}, + {"delattr", builtin_delattr, METH_VARARGS, delattr_doc}, + {"dir", builtin_dir, METH_VARARGS, dir_doc}, + {"divmod", builtin_divmod, METH_VARARGS, divmod_doc}, + {"eval", builtin_eval, METH_VARARGS, eval_doc}, + {"execfile", builtin_execfile, METH_VARARGS, execfile_doc}, + {"filter", builtin_filter, METH_VARARGS, filter_doc}, + {"getattr", builtin_getattr, METH_VARARGS, getattr_doc}, + {"globals", (PyCFunction)builtin_globals, METH_NOARGS, globals_doc}, + {"hasattr", builtin_hasattr, METH_VARARGS, hasattr_doc}, + {"hash", builtin_hash, METH_O, hash_doc}, + {"hex", builtin_hex, METH_O, hex_doc}, + {"id", builtin_id, METH_O, id_doc}, + {"input", builtin_input, METH_VARARGS, input_doc}, + {"intern", builtin_intern, METH_VARARGS, intern_doc}, + {"isinstance", builtin_isinstance, METH_VARARGS, isinstance_doc}, + {"issubclass", builtin_issubclass, METH_VARARGS, issubclass_doc}, + {"iter", builtin_iter, METH_VARARGS, iter_doc}, + {"len", builtin_len, METH_O, len_doc}, + {"locals", (PyCFunction)builtin_locals, METH_NOARGS, locals_doc}, + {"map", builtin_map, METH_VARARGS, map_doc}, + {"max", (PyCFunction)builtin_max, METH_VARARGS | METH_KEYWORDS, max_doc}, + {"min", (PyCFunction)builtin_min, METH_VARARGS | METH_KEYWORDS, min_doc}, + {"oct", builtin_oct, METH_O, oct_doc}, + {"open", (PyCFunction)builtin_open, METH_VARARGS | METH_KEYWORDS, open_doc}, + {"ord", builtin_ord, METH_O, ord_doc}, + {"pow", builtin_pow, METH_VARARGS, pow_doc}, + {"range", builtin_range, METH_VARARGS, range_doc}, + {"raw_input", builtin_raw_input, METH_VARARGS, raw_input_doc}, + {"reduce", builtin_reduce, METH_VARARGS, reduce_doc}, + {"reload", builtin_reload, METH_O, reload_doc}, + {"repr", builtin_repr, METH_O, repr_doc}, + {"round", (PyCFunction)builtin_round, METH_VARARGS | METH_KEYWORDS, round_doc}, + {"setattr", builtin_setattr, METH_VARARGS, setattr_doc}, + {"sorted", (PyCFunction)builtin_sorted, METH_VARARGS | METH_KEYWORDS, sorted_doc}, + {"sum", builtin_sum, METH_VARARGS, sum_doc}, +#ifdef Py_USING_UNICODE + {"unichr", builtin_unichr, METH_VARARGS, unichr_doc}, +#endif + {"vars", builtin_vars, METH_VARARGS, vars_doc}, + {"zip", builtin_zip, METH_VARARGS, zip_doc}, + {NULL, NULL}, +}; + +PyDoc_STRVAR(builtin_doc, +"Built-in functions, exceptions, and other objects.\n\ +\n\ +Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices."); + +PyObject * +_PyBuiltin_Init(void) +{ + PyObject *mod, *dict, *debug; + mod = Py_InitModule4("__builtin__", builtin_methods, + builtin_doc, (PyObject *)NULL, + PYTHON_API_VERSION); + if (mod == NULL) + return NULL; + dict = PyModule_GetDict(mod); + +#ifdef Py_TRACE_REFS + /* __builtin__ exposes a number of statically allocated objects + * that, before this code was added in 2.3, never showed up in + * the list of "all objects" maintained by Py_TRACE_REFS. As a + * result, programs leaking references to None and False (etc) + * couldn't be diagnosed by examining sys.getobjects(0). + */ +#define ADD_TO_ALL(OBJECT) _Py_AddToAllObjects((PyObject *)(OBJECT), 0) +#else +#define ADD_TO_ALL(OBJECT) (void)0 +#endif + +#define SETBUILTIN(NAME, OBJECT) \ + if (PyDict_SetItemString(dict, NAME, (PyObject *)OBJECT) < 0) \ + return NULL; \ + ADD_TO_ALL(OBJECT) + + SETBUILTIN("None", Py_None); + SETBUILTIN("Ellipsis", Py_Ellipsis); + SETBUILTIN("NotImplemented", Py_NotImplemented); + SETBUILTIN("False", Py_False); + SETBUILTIN("True", Py_True); + SETBUILTIN("basestring", &PyBaseString_Type); + SETBUILTIN("bool", &PyBool_Type); + SETBUILTIN("buffer", &PyBuffer_Type); + SETBUILTIN("classmethod", &PyClassMethod_Type); +#ifndef WITHOUT_COMPLEX + SETBUILTIN("complex", &PyComplex_Type); +#endif + SETBUILTIN("dict", &PyDict_Type); + SETBUILTIN("enumerate", &PyEnum_Type); + SETBUILTIN("file", &PyFile_Type); + SETBUILTIN("float", &PyFloat_Type); + SETBUILTIN("frozenset", &PyFrozenSet_Type); + SETBUILTIN("property", &PyProperty_Type); + SETBUILTIN("int", &PyInt_Type); + SETBUILTIN("list", &PyList_Type); + SETBUILTIN("long", &PyLong_Type); + SETBUILTIN("object", &PyBaseObject_Type); + SETBUILTIN("reversed", &PyReversed_Type); + SETBUILTIN("set", &PySet_Type); + SETBUILTIN("slice", &PySlice_Type); + SETBUILTIN("staticmethod", &PyStaticMethod_Type); + SETBUILTIN("str", &PyString_Type); + SETBUILTIN("super", &PySuper_Type); + SETBUILTIN("tuple", &PyTuple_Type); + SETBUILTIN("type", &PyType_Type); + SETBUILTIN("xrange", &PyRange_Type); +#ifdef Py_USING_UNICODE + SETBUILTIN("unicode", &PyUnicode_Type); +#endif + debug = PyBool_FromLong(Py_OptimizeFlag == 0); + if (PyDict_SetItemString(dict, "__debug__", debug) < 0) { + Py_XDECREF(debug); + return NULL; + } + Py_XDECREF(debug); + + return mod; +#undef ADD_TO_ALL +#undef SETBUILTIN +} + +/* Helper for filter(): filter a tuple through a function */ + +static PyObject * +filtertuple(PyObject *func, PyObject *tuple) +{ + PyObject *result; + Py_ssize_t i, j; + Py_ssize_t len = PyTuple_Size(tuple); + + if (len == 0) { + if (PyTuple_CheckExact(tuple)) + Py_INCREF(tuple); + else + tuple = PyTuple_New(0); + return tuple; + } + + if ((result = PyTuple_New(len)) == NULL) + return NULL; + + for (i = j = 0; i < len; ++i) { + PyObject *item, *good; + int ok; + + if (tuple->ob_type->tp_as_sequence && + tuple->ob_type->tp_as_sequence->sq_item) { + item = tuple->ob_type->tp_as_sequence->sq_item(tuple, i); + if (item == NULL) + goto Fail_1; + } else { + PyErr_SetString(PyExc_TypeError, "filter(): unsubscriptable tuple"); + goto Fail_1; + } + if (func == Py_None) { + Py_INCREF(item); + good = item; + } + else { + PyObject *arg = PyTuple_Pack(1, item); + if (arg == NULL) { + Py_DECREF(item); + goto Fail_1; + } + good = PyEval_CallObject(func, arg); + Py_DECREF(arg); + if (good == NULL) { + Py_DECREF(item); + goto Fail_1; + } + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + if (ok) { + if (PyTuple_SetItem(result, j++, item) < 0) + goto Fail_1; + } + else + Py_DECREF(item); + } + + if (_PyTuple_Resize(&result, j) < 0) + return NULL; + + return result; + +Fail_1: + Py_DECREF(result); + return NULL; +} + + +/* Helper for filter(): filter a string through a function */ + +static PyObject * +filterstring(PyObject *func, PyObject *strobj) +{ + PyObject *result; + Py_ssize_t i, j; + Py_ssize_t len = PyString_Size(strobj); + Py_ssize_t outlen = len; + + if (func == Py_None) { + /* If it's a real string we can return the original, + * as no character is ever false and __getitem__ + * does return this character. If it's a subclass + * we must go through the __getitem__ loop */ + if (PyString_CheckExact(strobj)) { + Py_INCREF(strobj); + return strobj; + } + } + if ((result = PyString_FromStringAndSize(NULL, len)) == NULL) + return NULL; + + for (i = j = 0; i < len; ++i) { + PyObject *item; + int ok; + + item = (*strobj->ob_type->tp_as_sequence->sq_item)(strobj, i); + if (item == NULL) + goto Fail_1; + if (func==Py_None) { + ok = 1; + } else { + PyObject *arg, *good; + arg = PyTuple_Pack(1, item); + if (arg == NULL) { + Py_DECREF(item); + goto Fail_1; + } + good = PyEval_CallObject(func, arg); + Py_DECREF(arg); + if (good == NULL) { + Py_DECREF(item); + goto Fail_1; + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + } + if (ok) { + Py_ssize_t reslen; + if (!PyString_Check(item)) { + PyErr_SetString(PyExc_TypeError, "can't filter str to str:" + " __getitem__ returned different type"); + Py_DECREF(item); + goto Fail_1; + } + reslen = PyString_GET_SIZE(item); + if (reslen == 1) { + PyString_AS_STRING(result)[j++] = + PyString_AS_STRING(item)[0]; + } else { + /* do we need more space? */ + Py_ssize_t need = j + reslen + len-i-1; + if (need > outlen) { + /* overallocate, to avoid reallocations */ + if (need<2*outlen) + need = 2*outlen; + if (_PyString_Resize(&result, need)) { + Py_DECREF(item); + return NULL; + } + outlen = need; + } + memcpy( + PyString_AS_STRING(result) + j, + PyString_AS_STRING(item), + reslen + ); + j += reslen; + } + } + Py_DECREF(item); + } + + if (j < outlen) + _PyString_Resize(&result, j); + + return result; + +Fail_1: + Py_DECREF(result); + return NULL; +} + +#ifdef Py_USING_UNICODE +/* Helper for filter(): filter a Unicode object through a function */ + +static PyObject * +filterunicode(PyObject *func, PyObject *strobj) +{ + PyObject *result; + register Py_ssize_t i, j; + Py_ssize_t len = PyUnicode_GetSize(strobj); + Py_ssize_t outlen = len; + + if (func == Py_None) { + /* If it's a real string we can return the original, + * as no character is ever false and __getitem__ + * does return this character. If it's a subclass + * we must go through the __getitem__ loop */ + if (PyUnicode_CheckExact(strobj)) { + Py_INCREF(strobj); + return strobj; + } + } + if ((result = PyUnicode_FromUnicode(NULL, len)) == NULL) + return NULL; + + for (i = j = 0; i < len; ++i) { + PyObject *item, *arg, *good; + int ok; + + item = (*strobj->ob_type->tp_as_sequence->sq_item)(strobj, i); + if (item == NULL) + goto Fail_1; + if (func == Py_None) { + ok = 1; + } else { + arg = PyTuple_Pack(1, item); + if (arg == NULL) { + Py_DECREF(item); + goto Fail_1; + } + good = PyEval_CallObject(func, arg); + Py_DECREF(arg); + if (good == NULL) { + Py_DECREF(item); + goto Fail_1; + } + ok = PyObject_IsTrue(good); + Py_DECREF(good); + } + if (ok) { + Py_ssize_t reslen; + if (!PyUnicode_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "can't filter unicode to unicode:" + " __getitem__ returned different type"); + Py_DECREF(item); + goto Fail_1; + } + reslen = PyUnicode_GET_SIZE(item); + if (reslen == 1) + PyUnicode_AS_UNICODE(result)[j++] = + PyUnicode_AS_UNICODE(item)[0]; + else { + /* do we need more space? */ + Py_ssize_t need = j + reslen + len - i - 1; + if (need > outlen) { + /* overallocate, + to avoid reallocations */ + if (need < 2 * outlen) + need = 2 * outlen; + if (PyUnicode_Resize( + &result, need) < 0) { + Py_DECREF(item); + goto Fail_1; + } + outlen = need; + } + memcpy(PyUnicode_AS_UNICODE(result) + j, + PyUnicode_AS_UNICODE(item), + reslen*sizeof(Py_UNICODE)); + j += reslen; + } + } + Py_DECREF(item); + } + + if (j < outlen) + PyUnicode_Resize(&result, j); + + return result; + +Fail_1: + Py_DECREF(result); + return NULL; +} +#endif diff --git a/sys/src/cmd/python/Python/ceval.c b/sys/src/cmd/python/Python/ceval.c new file mode 100644 index 000000000..597ae481f --- /dev/null +++ b/sys/src/cmd/python/Python/ceval.c @@ -0,0 +1,4351 @@ + +/* Execute compiled code */ + +/* XXX TO DO: + XXX speed up searching for keywords by using a dictionary + XXX document it! + */ + +/* enable more aggressive intra-module optimizations, where available */ +#define PY_LOCAL_AGGRESSIVE + +#include "Python.h" + +#include "code.h" +#include "frameobject.h" +#include "eval.h" +#include "opcode.h" +#include "structmember.h" + +#include <ctype.h> + +#ifndef WITH_TSC + +#define READ_TIMESTAMP(var) + +#else + +typedef unsigned long long uint64; + +#if defined(__ppc__) /* <- Don't know if this is the correct symbol; this + section should work for GCC on any PowerPC platform, + irrespective of OS. POWER? Who knows :-) */ + +#define READ_TIMESTAMP(var) ppc_getcounter(&var) + +static void +ppc_getcounter(uint64 *v) +{ + register unsigned long tbu, tb, tbu2; + + loop: + asm volatile ("mftbu %0" : "=r" (tbu) ); + asm volatile ("mftb %0" : "=r" (tb) ); + asm volatile ("mftbu %0" : "=r" (tbu2)); + if (__builtin_expect(tbu != tbu2, 0)) goto loop; + + /* The slightly peculiar way of writing the next lines is + compiled better by GCC than any other way I tried. */ + ((long*)(v))[0] = tbu; + ((long*)(v))[1] = tb; +} + +#else /* this is for linux/x86 (and probably any other GCC/x86 combo) */ + +#define READ_TIMESTAMP(val) \ + __asm__ __volatile__("rdtsc" : "=A" (val)) + +#endif + +void dump_tsc(int opcode, int ticked, uint64 inst0, uint64 inst1, + uint64 loop0, uint64 loop1, uint64 intr0, uint64 intr1) +{ + uint64 intr, inst, loop; + PyThreadState *tstate = PyThreadState_Get(); + if (!tstate->interp->tscdump) + return; + intr = intr1 - intr0; + inst = inst1 - inst0 - intr; + loop = loop1 - loop0 - intr; + fprintf(stderr, "opcode=%03d t=%d inst=%06lld loop=%06lld\n", + opcode, ticked, inst, loop); +} + +#endif + +/* Turn this on if your compiler chokes on the big switch: */ +/* #define CASE_TOO_BIG 1 */ + +#ifdef Py_DEBUG +/* For debugging the interpreter: */ +#define LLTRACE 1 /* Low-level trace feature */ +#define CHECKEXC 1 /* Double-check exception checking */ +#endif + +typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *); + +/* Forward declarations */ +#ifdef WITH_TSC +static PyObject * call_function(PyObject ***, int, uint64*, uint64*); +#else +static PyObject * call_function(PyObject ***, int); +#endif +static PyObject * fast_function(PyObject *, PyObject ***, int, int, int); +static PyObject * do_call(PyObject *, PyObject ***, int, int); +static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int); +static PyObject * update_keyword_args(PyObject *, int, PyObject ***,PyObject *); +static PyObject * update_star_args(int, int, PyObject *, PyObject ***); +static PyObject * load_args(PyObject ***, int); +#define CALL_FLAG_VAR 1 +#define CALL_FLAG_KW 2 + +#ifdef LLTRACE +static int lltrace; +static int prtrace(PyObject *, char *); +#endif +static int call_trace(Py_tracefunc, PyObject *, PyFrameObject *, + int, PyObject *); +static void call_trace_protected(Py_tracefunc, PyObject *, + PyFrameObject *, int, PyObject *); +static void call_exc_trace(Py_tracefunc, PyObject *, PyFrameObject *); +static int maybe_call_line_trace(Py_tracefunc, PyObject *, + PyFrameObject *, int *, int *, int *); + +static PyObject * apply_slice(PyObject *, PyObject *, PyObject *); +static int assign_slice(PyObject *, PyObject *, + PyObject *, PyObject *); +static PyObject * cmp_outcome(int, PyObject *, PyObject *); +static PyObject * import_from(PyObject *, PyObject *); +static int import_all_from(PyObject *, PyObject *); +static PyObject * build_class(PyObject *, PyObject *, PyObject *); +static int exec_statement(PyFrameObject *, + PyObject *, PyObject *, PyObject *); +static void set_exc_info(PyThreadState *, PyObject *, PyObject *, PyObject *); +static void reset_exc_info(PyThreadState *); +static void format_exc_check_arg(PyObject *, char *, PyObject *); +static PyObject * string_concatenate(PyObject *, PyObject *, + PyFrameObject *, unsigned char *); + +#define NAME_ERROR_MSG \ + "name '%.200s' is not defined" +#define GLOBAL_NAME_ERROR_MSG \ + "global name '%.200s' is not defined" +#define UNBOUNDLOCAL_ERROR_MSG \ + "local variable '%.200s' referenced before assignment" +#define UNBOUNDFREE_ERROR_MSG \ + "free variable '%.200s' referenced before assignment" \ + " in enclosing scope" + +/* Dynamic execution profile */ +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS +static long dxpairs[257][256]; +#define dxp dxpairs[256] +#else +static long dxp[256]; +#endif +#endif + +/* Function call profile */ +#ifdef CALL_PROFILE +#define PCALL_NUM 11 +static int pcall[PCALL_NUM]; + +#define PCALL_ALL 0 +#define PCALL_FUNCTION 1 +#define PCALL_FAST_FUNCTION 2 +#define PCALL_FASTER_FUNCTION 3 +#define PCALL_METHOD 4 +#define PCALL_BOUND_METHOD 5 +#define PCALL_CFUNCTION 6 +#define PCALL_TYPE 7 +#define PCALL_GENERATOR 8 +#define PCALL_OTHER 9 +#define PCALL_POP 10 + +/* Notes about the statistics + + PCALL_FAST stats + + FAST_FUNCTION means no argument tuple needs to be created. + FASTER_FUNCTION means that the fast-path frame setup code is used. + + If there is a method call where the call can be optimized by changing + the argument tuple and calling the function directly, it gets recorded + twice. + + As a result, the relationship among the statistics appears to be + PCALL_ALL == PCALL_FUNCTION + PCALL_METHOD - PCALL_BOUND_METHOD + + PCALL_CFUNCTION + PCALL_TYPE + PCALL_GENERATOR + PCALL_OTHER + PCALL_FUNCTION > PCALL_FAST_FUNCTION > PCALL_FASTER_FUNCTION + PCALL_METHOD > PCALL_BOUND_METHOD +*/ + +#define PCALL(POS) pcall[POS]++ + +PyObject * +PyEval_GetCallStats(PyObject *self) +{ + return Py_BuildValue("iiiiiiiiiii", + pcall[0], pcall[1], pcall[2], pcall[3], + pcall[4], pcall[5], pcall[6], pcall[7], + pcall[8], pcall[9], pcall[10]); +} +#else +#define PCALL(O) + +PyObject * +PyEval_GetCallStats(PyObject *self) +{ + Py_INCREF(Py_None); + return Py_None; +} +#endif + + +#ifdef WITH_THREAD + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#include "pythread.h" + +static PyThread_type_lock interpreter_lock = 0; /* This is the GIL */ +static long main_thread = 0; + +int +PyEval_ThreadsInitialized(void) +{ + return interpreter_lock != 0; +} + +void +PyEval_InitThreads(void) +{ + if (interpreter_lock) + return; + interpreter_lock = PyThread_allocate_lock(); + PyThread_acquire_lock(interpreter_lock, 1); + main_thread = PyThread_get_thread_ident(); +} + +void +PyEval_AcquireLock(void) +{ + PyThread_acquire_lock(interpreter_lock, 1); +} + +void +PyEval_ReleaseLock(void) +{ + PyThread_release_lock(interpreter_lock); +} + +void +PyEval_AcquireThread(PyThreadState *tstate) +{ + if (tstate == NULL) + Py_FatalError("PyEval_AcquireThread: NULL new thread state"); + /* Check someone has called PyEval_InitThreads() to create the lock */ + assert(interpreter_lock); + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError( + "PyEval_AcquireThread: non-NULL old thread state"); +} + +void +PyEval_ReleaseThread(PyThreadState *tstate) +{ + if (tstate == NULL) + Py_FatalError("PyEval_ReleaseThread: NULL thread state"); + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("PyEval_ReleaseThread: wrong thread state"); + PyThread_release_lock(interpreter_lock); +} + +/* This function is called from PyOS_AfterFork to ensure that newly + created child processes don't hold locks referring to threads which + are not running in the child process. (This could also be done using + pthread_atfork mechanism, at least for the pthreads implementation.) */ + +void +PyEval_ReInitThreads(void) +{ + if (!interpreter_lock) + return; + /*XXX Can't use PyThread_free_lock here because it does too + much error-checking. Doing this cleanly would require + adding a new function to each thread_*.h. Instead, just + create a new lock and waste a little bit of memory */ + interpreter_lock = PyThread_allocate_lock(); + PyThread_acquire_lock(interpreter_lock, 1); + main_thread = PyThread_get_thread_ident(); +} +#endif + +/* Functions save_thread and restore_thread are always defined so + dynamically loaded modules needn't be compiled separately for use + with and without threads: */ + +PyThreadState * +PyEval_SaveThread(void) +{ + PyThreadState *tstate = PyThreadState_Swap(NULL); + if (tstate == NULL) + Py_FatalError("PyEval_SaveThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) + PyThread_release_lock(interpreter_lock); +#endif + return tstate; +} + +void +PyEval_RestoreThread(PyThreadState *tstate) +{ + if (tstate == NULL) + Py_FatalError("PyEval_RestoreThread: NULL tstate"); +#ifdef WITH_THREAD + if (interpreter_lock) { + int err = errno; + PyThread_acquire_lock(interpreter_lock, 1); + errno = err; + } +#endif + PyThreadState_Swap(tstate); +} + + +/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX + signal handlers or Mac I/O completion routines) can schedule calls + to a function to be called synchronously. + The synchronous function is called with one void* argument. + It should return 0 for success or -1 for failure -- failure should + be accompanied by an exception. + + If registry succeeds, the registry function returns 0; if it fails + (e.g. due to too many pending calls) it returns -1 (without setting + an exception condition). + + Note that because registry may occur from within signal handlers, + or other asynchronous events, calling malloc() is unsafe! + +#ifdef WITH_THREAD + Any thread can schedule pending calls, but only the main thread + will execute them. +#endif + + XXX WARNING! ASYNCHRONOUSLY EXECUTING CODE! + There are two possible race conditions: + (1) nested asynchronous registry calls; + (2) registry calls made while pending calls are being processed. + While (1) is very unlikely, (2) is a real possibility. + The current code is safe against (2), but not against (1). + The safety against (2) is derived from the fact that only one + thread (the main thread) ever takes things out of the queue. + + XXX Darn! With the advent of thread state, we should have an array + of pending calls per thread in the thread state! Later... +*/ + +#define NPENDINGCALLS 32 +static struct { + int (*func)(void *); + void *arg; +} pendingcalls[NPENDINGCALLS]; +static volatile int pendingfirst = 0; +static volatile int pendinglast = 0; +static volatile int things_to_do = 0; + +int +Py_AddPendingCall(int (*func)(void *), void *arg) +{ + static int busy = 0; + int i, j; + /* XXX Begin critical section */ + /* XXX If you want this to be safe against nested + XXX asynchronous calls, you'll have to work harder! */ + if (busy) + return -1; + busy = 1; + i = pendinglast; + j = (i + 1) % NPENDINGCALLS; + if (j == pendingfirst) { + busy = 0; + return -1; /* Queue full */ + } + pendingcalls[i].func = func; + pendingcalls[i].arg = arg; + pendinglast = j; + + _Py_Ticker = 0; + things_to_do = 1; /* Signal main loop */ + busy = 0; + /* XXX End critical section */ + return 0; +} + +int +Py_MakePendingCalls(void) +{ + static int busy = 0; +#ifdef WITH_THREAD + if (main_thread && PyThread_get_thread_ident() != main_thread) + return 0; +#endif + if (busy) + return 0; + busy = 1; + things_to_do = 0; + for (;;) { + int i; + int (*func)(void *); + void *arg; + i = pendingfirst; + if (i == pendinglast) + break; /* Queue empty */ + func = pendingcalls[i].func; + arg = pendingcalls[i].arg; + pendingfirst = (i + 1) % NPENDINGCALLS; + if (func(arg) < 0) { + busy = 0; + things_to_do = 1; /* We're not done yet */ + return -1; + } + } + busy = 0; + return 0; +} + + +/* The interpreter's recursion limit */ + +#ifndef Py_DEFAULT_RECURSION_LIMIT +#define Py_DEFAULT_RECURSION_LIMIT 1000 +#endif +static int recursion_limit = Py_DEFAULT_RECURSION_LIMIT; +int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT; + +int +Py_GetRecursionLimit(void) +{ + return recursion_limit; +} + +void +Py_SetRecursionLimit(int new_limit) +{ + recursion_limit = new_limit; + _Py_CheckRecursionLimit = recursion_limit; +} + +/* the macro Py_EnterRecursiveCall() only calls _Py_CheckRecursiveCall() + if the recursion_depth reaches _Py_CheckRecursionLimit. + If USE_STACKCHECK, the macro decrements _Py_CheckRecursionLimit + to guarantee that _Py_CheckRecursiveCall() is regularly called. + Without USE_STACKCHECK, there is no need for this. */ +int +_Py_CheckRecursiveCall(char *where) +{ + PyThreadState *tstate = PyThreadState_GET(); + +#ifdef USE_STACKCHECK + if (PyOS_CheckStack()) { + --tstate->recursion_depth; + PyErr_SetString(PyExc_MemoryError, "Stack overflow"); + return -1; + } +#endif + if (tstate->recursion_depth > recursion_limit) { + --tstate->recursion_depth; + PyErr_Format(PyExc_RuntimeError, + "maximum recursion depth exceeded%s", + where); + return -1; + } + _Py_CheckRecursionLimit = recursion_limit; + return 0; +} + +/* Status code for main loop (reason for stack unwind) */ +enum why_code { + WHY_NOT = 0x0001, /* No error */ + WHY_EXCEPTION = 0x0002, /* Exception occurred */ + WHY_RERAISE = 0x0004, /* Exception re-raised by 'finally' */ + WHY_RETURN = 0x0008, /* 'return' statement */ + WHY_BREAK = 0x0010, /* 'break' statement */ + WHY_CONTINUE = 0x0020, /* 'continue' statement */ + WHY_YIELD = 0x0040 /* 'yield' operator */ +}; + +static enum why_code do_raise(PyObject *, PyObject *, PyObject *); +static int unpack_iterable(PyObject *, int, PyObject **); + +/* for manipulating the thread switch and periodic "stuff" - used to be + per thread, now just a pair o' globals */ +int _Py_CheckInterval = 100; +volatile int _Py_Ticker = 100; + +PyObject * +PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals) +{ + /* XXX raise SystemError if globals is NULL */ + return PyEval_EvalCodeEx(co, + globals, locals, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + (PyObject **)NULL, 0, + NULL); +} + + +/* Interpreter main loop */ + +PyObject * +PyEval_EvalFrame(PyFrameObject *f) { + /* This is for backward compatibility with extension modules that + used this API; core interpreter code should call PyEval_EvalFrameEx() */ + return PyEval_EvalFrameEx(f, 0); +} + +PyObject * +PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) +{ +#ifdef DXPAIRS + int lastopcode = 0; +#endif + register PyObject **stack_pointer; /* Next free slot in value stack */ + register unsigned char *next_instr; + register int opcode; /* Current opcode */ + register int oparg; /* Current opcode argument, if any */ + register enum why_code why; /* Reason for block stack unwind */ + register int err; /* Error status -- nonzero if error */ + register PyObject *x; /* Result object -- NULL if error */ + register PyObject *v; /* Temporary objects popped off stack */ + register PyObject *w; + register PyObject *u; + register PyObject *t; + register PyObject *stream = NULL; /* for PRINT opcodes */ + register PyObject **fastlocals, **freevars; + PyObject *retval = NULL; /* Return value */ + PyThreadState *tstate = PyThreadState_GET(); + PyCodeObject *co; + + /* when tracing we set things up so that + + not (instr_lb <= current_bytecode_offset < instr_ub) + + is true when the line being executed has changed. The + initial values are such as to make this false the first + time it is tested. */ + int instr_ub = -1, instr_lb = 0, instr_prev = -1; + + unsigned char *first_instr; + PyObject *names; + PyObject *consts; +#if defined(Py_DEBUG) || defined(LLTRACE) + /* Make it easier to find out where we are with a debugger */ + char *filename; +#endif + +/* Tuple access macros */ + +#ifndef Py_DEBUG +#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i)) +#else +#define GETITEM(v, i) PyTuple_GetItem((v), (i)) +#endif + +#ifdef WITH_TSC +/* Use Pentium timestamp counter to mark certain events: + inst0 -- beginning of switch statement for opcode dispatch + inst1 -- end of switch statement (may be skipped) + loop0 -- the top of the mainloop + loop1 -- place where control returns again to top of mainloop + (may be skipped) + intr1 -- beginning of long interruption + intr2 -- end of long interruption + + Many opcodes call out to helper C functions. In some cases, the + time in those functions should be counted towards the time for the + opcode, but not in all cases. For example, a CALL_FUNCTION opcode + calls another Python function; there's no point in charge all the + bytecode executed by the called function to the caller. + + It's hard to make a useful judgement statically. In the presence + of operator overloading, it's impossible to tell if a call will + execute new Python code or not. + + It's a case-by-case judgement. I'll use intr1 for the following + cases: + + EXEC_STMT + IMPORT_STAR + IMPORT_FROM + CALL_FUNCTION (and friends) + + */ + uint64 inst0, inst1, loop0, loop1, intr0 = 0, intr1 = 0; + int ticked = 0; + + READ_TIMESTAMP(inst0); + READ_TIMESTAMP(inst1); + READ_TIMESTAMP(loop0); + READ_TIMESTAMP(loop1); + + /* shut up the compiler */ + opcode = 0; +#endif + +/* Code access macros */ + +#define INSTR_OFFSET() ((int)(next_instr - first_instr)) +#define NEXTOP() (*next_instr++) +#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2]) +#define PEEKARG() ((next_instr[2]<<8) + next_instr[1]) +#define JUMPTO(x) (next_instr = first_instr + (x)) +#define JUMPBY(x) (next_instr += (x)) + +/* OpCode prediction macros + Some opcodes tend to come in pairs thus making it possible to predict + the second code when the first is run. For example, COMPARE_OP is often + followed by JUMP_IF_FALSE or JUMP_IF_TRUE. And, those opcodes are often + followed by a POP_TOP. + + Verifying the prediction costs a single high-speed test of register + variable against a constant. If the pairing was good, then the + processor has a high likelihood of making its own successful branch + prediction which results in a nearly zero overhead transition to the + next opcode. + + A successful prediction saves a trip through the eval-loop including + its two unpredictable branches, the HASARG test and the switch-case. + + If collecting opcode statistics, turn off prediction so that + statistics are accurately maintained (the predictions bypass + the opcode frequency counter updates). +*/ + +#ifdef DYNAMIC_EXECUTION_PROFILE +#define PREDICT(op) if (0) goto PRED_##op +#else +#define PREDICT(op) if (*next_instr == op) goto PRED_##op +#endif + +#define PREDICTED(op) PRED_##op: next_instr++ +#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3 + +/* Stack manipulation macros */ + +/* The stack can grow at most MAXINT deep, as co_nlocals and + co_stacksize are ints. */ +#define STACK_LEVEL() ((int)(stack_pointer - f->f_valuestack)) +#define EMPTY() (STACK_LEVEL() == 0) +#define TOP() (stack_pointer[-1]) +#define SECOND() (stack_pointer[-2]) +#define THIRD() (stack_pointer[-3]) +#define FOURTH() (stack_pointer[-4]) +#define SET_TOP(v) (stack_pointer[-1] = (v)) +#define SET_SECOND(v) (stack_pointer[-2] = (v)) +#define SET_THIRD(v) (stack_pointer[-3] = (v)) +#define SET_FOURTH(v) (stack_pointer[-4] = (v)) +#define BASIC_STACKADJ(n) (stack_pointer += n) +#define BASIC_PUSH(v) (*stack_pointer++ = (v)) +#define BASIC_POP() (*--stack_pointer) + +#ifdef LLTRACE +#define PUSH(v) { (void)(BASIC_PUSH(v), \ + lltrace && prtrace(TOP(), "push")); \ + assert(STACK_LEVEL() <= co->co_stacksize); } +#define POP() ((void)(lltrace && prtrace(TOP(), "pop")), BASIC_POP()) +#define STACKADJ(n) { (void)(BASIC_STACKADJ(n), \ + lltrace && prtrace(TOP(), "stackadj")); \ + assert(STACK_LEVEL() <= co->co_stacksize); } +#define EXT_POP(STACK_POINTER) (lltrace && prtrace(*(STACK_POINTER), "ext_pop"), *--(STACK_POINTER)) +#else +#define PUSH(v) BASIC_PUSH(v) +#define POP() BASIC_POP() +#define STACKADJ(n) BASIC_STACKADJ(n) +#define EXT_POP(STACK_POINTER) (*--(STACK_POINTER)) +#endif + +/* Local variable macros */ + +#define GETLOCAL(i) (fastlocals[i]) + +/* The SETLOCAL() macro must not DECREF the local variable in-place and + then store the new value; it must copy the old value to a temporary + value, then store the new value, and then DECREF the temporary value. + This is because it is possible that during the DECREF the frame is + accessed by other code (e.g. a __del__ method or gc.collect()) and the + variable would be pointing to already-freed memory. */ +#define SETLOCAL(i, value) do { PyObject *tmp = GETLOCAL(i); \ + GETLOCAL(i) = value; \ + Py_XDECREF(tmp); } while (0) + +/* Start of code */ + + if (f == NULL) + return NULL; + + /* push frame */ + if (Py_EnterRecursiveCall("")) + return NULL; + + tstate->frame = f; + + if (tstate->use_tracing) { + if (tstate->c_tracefunc != NULL) { + /* tstate->c_tracefunc, if defined, is a + function that will be called on *every* entry + to a code block. Its return value, if not + None, is a function that will be called at + the start of each executed line of code. + (Actually, the function must return itself + in order to continue tracing.) The trace + functions are called with three arguments: + a pointer to the current frame, a string + indicating why the function is called, and + an argument which depends on the situation. + The global trace function is also called + whenever an exception is detected. */ + if (call_trace(tstate->c_tracefunc, tstate->c_traceobj, + f, PyTrace_CALL, Py_None)) { + /* Trace function raised an error */ + goto exit_eval_frame; + } + } + if (tstate->c_profilefunc != NULL) { + /* Similar for c_profilefunc, except it needn't + return itself and isn't called for "line" events */ + if (call_trace(tstate->c_profilefunc, + tstate->c_profileobj, + f, PyTrace_CALL, Py_None)) { + /* Profile function raised an error */ + goto exit_eval_frame; + } + } + } + + co = f->f_code; + names = co->co_names; + consts = co->co_consts; + fastlocals = f->f_localsplus; + freevars = f->f_localsplus + co->co_nlocals; + first_instr = (unsigned char*) PyString_AS_STRING(co->co_code); + /* An explanation is in order for the next line. + + f->f_lasti now refers to the index of the last instruction + executed. You might think this was obvious from the name, but + this wasn't always true before 2.3! PyFrame_New now sets + f->f_lasti to -1 (i.e. the index *before* the first instruction) + and YIELD_VALUE doesn't fiddle with f_lasti any more. So this + does work. Promise. */ + next_instr = first_instr + f->f_lasti + 1; + stack_pointer = f->f_stacktop; + assert(stack_pointer != NULL); + f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */ + +#ifdef LLTRACE + lltrace = PyDict_GetItemString(f->f_globals, "__lltrace__") != NULL; +#endif +#if defined(Py_DEBUG) || defined(LLTRACE) + filename = PyString_AsString(co->co_filename); +#endif + + why = WHY_NOT; + err = 0; + x = Py_None; /* Not a reference, just anything non-NULL */ + w = NULL; + + if (throwflag) { /* support for generator.throw() */ + why = WHY_EXCEPTION; + goto on_error; + } + + for (;;) { +#ifdef WITH_TSC + if (inst1 == 0) { + /* Almost surely, the opcode executed a break + or a continue, preventing inst1 from being set + on the way out of the loop. + */ + READ_TIMESTAMP(inst1); + loop1 = inst1; + } + dump_tsc(opcode, ticked, inst0, inst1, loop0, loop1, + intr0, intr1); + ticked = 0; + inst1 = 0; + intr0 = 0; + intr1 = 0; + READ_TIMESTAMP(loop0); +#endif + assert(stack_pointer >= f->f_valuestack); /* else underflow */ + assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */ + + /* Do periodic things. Doing this every time through + the loop would add too much overhead, so we do it + only every Nth instruction. We also do it if + ``things_to_do'' is set, i.e. when an asynchronous + event needs attention (e.g. a signal handler or + async I/O handler); see Py_AddPendingCall() and + Py_MakePendingCalls() above. */ + + if (--_Py_Ticker < 0) { + if (*next_instr == SETUP_FINALLY) { + /* Make the last opcode before + a try: finally: block uninterruptable. */ + goto fast_next_opcode; + } + _Py_Ticker = _Py_CheckInterval; + tstate->tick_counter++; +#ifdef WITH_TSC + ticked = 1; +#endif + if (things_to_do) { + if (Py_MakePendingCalls() < 0) { + why = WHY_EXCEPTION; + goto on_error; + } + if (things_to_do) + /* MakePendingCalls() didn't succeed. + Force early re-execution of this + "periodic" code, possibly after + a thread switch */ + _Py_Ticker = 0; + } +#ifdef WITH_THREAD + if (interpreter_lock) { + /* Give another thread a chance */ + + if (PyThreadState_Swap(NULL) != tstate) + Py_FatalError("ceval: tstate mix-up"); + PyThread_release_lock(interpreter_lock); + + /* Other threads may run now */ + + PyThread_acquire_lock(interpreter_lock, 1); + if (PyThreadState_Swap(tstate) != NULL) + Py_FatalError("ceval: orphan tstate"); + + /* Check for thread interrupts */ + + if (tstate->async_exc != NULL) { + x = tstate->async_exc; + tstate->async_exc = NULL; + PyErr_SetNone(x); + Py_DECREF(x); + why = WHY_EXCEPTION; + goto on_error; + } + } +#endif + } + + fast_next_opcode: + f->f_lasti = INSTR_OFFSET(); + + /* line-by-line tracing support */ + + if (tstate->c_tracefunc != NULL && !tstate->tracing) { + /* see maybe_call_line_trace + for expository comments */ + f->f_stacktop = stack_pointer; + + err = maybe_call_line_trace(tstate->c_tracefunc, + tstate->c_traceobj, + f, &instr_lb, &instr_ub, + &instr_prev); + /* Reload possibly changed frame fields */ + JUMPTO(f->f_lasti); + if (f->f_stacktop != NULL) { + stack_pointer = f->f_stacktop; + f->f_stacktop = NULL; + } + if (err) { + /* trace function raised an exception */ + goto on_error; + } + } + + /* Extract opcode and argument */ + + opcode = NEXTOP(); + oparg = 0; /* allows oparg to be stored in a register because + it doesn't have to be remembered across a full loop */ + if (HAS_ARG(opcode)) + oparg = NEXTARG(); + dispatch_opcode: +#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef DXPAIRS + dxpairs[lastopcode][opcode]++; + lastopcode = opcode; +#endif + dxp[opcode]++; +#endif + +#ifdef LLTRACE + /* Instruction tracing */ + + if (lltrace) { + if (HAS_ARG(opcode)) { + printf("%d: %d, %d\n", + f->f_lasti, opcode, oparg); + } + else { + printf("%d: %d\n", + f->f_lasti, opcode); + } + } +#endif + + /* Main switch on opcode */ + READ_TIMESTAMP(inst0); + + switch (opcode) { + + /* BEWARE! + It is essential that any operation that fails sets either + x to NULL, err to nonzero, or why to anything but WHY_NOT, + and that no operation that succeeds does this! */ + + /* case STOP_CODE: this is an error! */ + + case NOP: + goto fast_next_opcode; + + case LOAD_FAST: + x = GETLOCAL(oparg); + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + goto fast_next_opcode; + } + format_exc_check_arg(PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(co->co_varnames, oparg)); + break; + + case LOAD_CONST: + x = GETITEM(consts, oparg); + Py_INCREF(x); + PUSH(x); + goto fast_next_opcode; + + PREDICTED_WITH_ARG(STORE_FAST); + case STORE_FAST: + v = POP(); + SETLOCAL(oparg, v); + goto fast_next_opcode; + + PREDICTED(POP_TOP); + case POP_TOP: + v = POP(); + Py_DECREF(v); + goto fast_next_opcode; + + case ROT_TWO: + v = TOP(); + w = SECOND(); + SET_TOP(w); + SET_SECOND(v); + goto fast_next_opcode; + + case ROT_THREE: + v = TOP(); + w = SECOND(); + x = THIRD(); + SET_TOP(w); + SET_SECOND(x); + SET_THIRD(v); + goto fast_next_opcode; + + case ROT_FOUR: + u = TOP(); + v = SECOND(); + w = THIRD(); + x = FOURTH(); + SET_TOP(v); + SET_SECOND(w); + SET_THIRD(x); + SET_FOURTH(u); + goto fast_next_opcode; + + case DUP_TOP: + v = TOP(); + Py_INCREF(v); + PUSH(v); + goto fast_next_opcode; + + case DUP_TOPX: + if (oparg == 2) { + x = TOP(); + Py_INCREF(x); + w = SECOND(); + Py_INCREF(w); + STACKADJ(2); + SET_TOP(x); + SET_SECOND(w); + goto fast_next_opcode; + } else if (oparg == 3) { + x = TOP(); + Py_INCREF(x); + w = SECOND(); + Py_INCREF(w); + v = THIRD(); + Py_INCREF(v); + STACKADJ(3); + SET_TOP(x); + SET_SECOND(w); + SET_THIRD(v); + goto fast_next_opcode; + } + Py_FatalError("invalid argument to DUP_TOPX" + " (bytecode corruption?)"); + break; + + case UNARY_POSITIVE: + v = TOP(); + x = PyNumber_Positive(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case UNARY_NEGATIVE: + v = TOP(); + x = PyNumber_Negative(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case UNARY_NOT: + v = TOP(); + err = PyObject_IsTrue(v); + Py_DECREF(v); + if (err == 0) { + Py_INCREF(Py_True); + SET_TOP(Py_True); + continue; + } + else if (err > 0) { + Py_INCREF(Py_False); + SET_TOP(Py_False); + err = 0; + continue; + } + STACKADJ(-1); + break; + + case UNARY_CONVERT: + v = TOP(); + x = PyObject_Repr(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case UNARY_INVERT: + v = TOP(); + x = PyNumber_Invert(v); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_POWER: + w = POP(); + v = TOP(); + x = PyNumber_Power(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_MULTIPLY: + w = POP(); + v = TOP(); + x = PyNumber_Multiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_DIVIDE: + if (!_Py_QnewFlag) { + w = POP(); + v = TOP(); + x = PyNumber_Divide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + } + /* -Qnew is in effect: fall through to + BINARY_TRUE_DIVIDE */ + case BINARY_TRUE_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_TrueDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_FLOOR_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_FloorDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_MODULO: + w = POP(); + v = TOP(); + x = PyNumber_Remainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_ADD: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int + int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a + b; + if ((i^a) < 0 && (i^b) < 0) + goto slow_add; + x = PyInt_FromLong(i); + } + else if (PyString_CheckExact(v) && + PyString_CheckExact(w)) { + x = string_concatenate(v, w, f, next_instr); + /* string_concatenate consumed the ref to v */ + goto skip_decref_vx; + } + else { + slow_add: + x = PyNumber_Add(v, w); + } + Py_DECREF(v); + skip_decref_vx: + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_SUBTRACT: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int - int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a - b; + if ((i^a) < 0 && (i^~b) < 0) + goto slow_sub; + x = PyInt_FromLong(i); + } + else { + slow_sub: + x = PyNumber_Subtract(v, w); + } + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_SUBSCR: + w = POP(); + v = TOP(); + if (PyList_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: list[int] */ + Py_ssize_t i = PyInt_AsSsize_t(w); + if (i < 0) + i += PyList_GET_SIZE(v); + if (i >= 0 && i < PyList_GET_SIZE(v)) { + x = PyList_GET_ITEM(v, i); + Py_INCREF(x); + } + else + goto slow_get; + } + else + slow_get: + x = PyObject_GetItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_LSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_Lshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_RSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_Rshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_AND: + w = POP(); + v = TOP(); + x = PyNumber_And(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_XOR: + w = POP(); + v = TOP(); + x = PyNumber_Xor(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case BINARY_OR: + w = POP(); + v = TOP(); + x = PyNumber_Or(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case LIST_APPEND: + w = POP(); + v = POP(); + err = PyList_Append(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) { + PREDICT(JUMP_ABSOLUTE); + continue; + } + break; + + case INPLACE_POWER: + w = POP(); + v = TOP(); + x = PyNumber_InPlacePower(v, w, Py_None); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_MULTIPLY: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceMultiply(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_DIVIDE: + if (!_Py_QnewFlag) { + w = POP(); + v = TOP(); + x = PyNumber_InPlaceDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + } + /* -Qnew is in effect: fall through to + INPLACE_TRUE_DIVIDE */ + case INPLACE_TRUE_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceTrueDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_FLOOR_DIVIDE: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceFloorDivide(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_MODULO: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceRemainder(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_ADD: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int + int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a + b; + if ((i^a) < 0 && (i^b) < 0) + goto slow_iadd; + x = PyInt_FromLong(i); + } + else if (PyString_CheckExact(v) && + PyString_CheckExact(w)) { + x = string_concatenate(v, w, f, next_instr); + /* string_concatenate consumed the ref to v */ + goto skip_decref_v; + } + else { + slow_iadd: + x = PyNumber_InPlaceAdd(v, w); + } + Py_DECREF(v); + skip_decref_v: + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_SUBTRACT: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(v) && PyInt_CheckExact(w)) { + /* INLINE: int - int */ + register long a, b, i; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + i = a - b; + if ((i^a) < 0 && (i^~b) < 0) + goto slow_isub; + x = PyInt_FromLong(i); + } + else { + slow_isub: + x = PyNumber_InPlaceSubtract(v, w); + } + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_LSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceLshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_RSHIFT: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceRshift(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_AND: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceAnd(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_XOR: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceXor(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case INPLACE_OR: + w = POP(); + v = TOP(); + x = PyNumber_InPlaceOr(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case SLICE+0: + case SLICE+1: + case SLICE+2: + case SLICE+3: + if ((opcode-SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-SLICE) & 1) + v = POP(); + else + v = NULL; + u = TOP(); + x = apply_slice(u, v, w); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case STORE_SLICE+0: + case STORE_SLICE+1: + case STORE_SLICE+2: + case STORE_SLICE+3: + if ((opcode-STORE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-STORE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + t = POP(); + err = assign_slice(u, v, w, t); /* u[v:w] = t */ + Py_DECREF(t); + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case DELETE_SLICE+0: + case DELETE_SLICE+1: + case DELETE_SLICE+2: + case DELETE_SLICE+3: + if ((opcode-DELETE_SLICE) & 2) + w = POP(); + else + w = NULL; + if ((opcode-DELETE_SLICE) & 1) + v = POP(); + else + v = NULL; + u = POP(); + err = assign_slice(u, v, w, (PyObject *)NULL); + /* del u[v:w] */ + Py_DECREF(u); + Py_XDECREF(v); + Py_XDECREF(w); + if (err == 0) continue; + break; + + case STORE_SUBSCR: + w = TOP(); + v = SECOND(); + u = THIRD(); + STACKADJ(-3); + /* v[w] = u */ + err = PyObject_SetItem(v, w, u); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case DELETE_SUBSCR: + w = TOP(); + v = SECOND(); + STACKADJ(-2); + /* del v[w] */ + err = PyObject_DelItem(v, w); + Py_DECREF(v); + Py_DECREF(w); + if (err == 0) continue; + break; + + case PRINT_EXPR: + v = POP(); + w = PySys_GetObject("displayhook"); + if (w == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "lost sys.displayhook"); + err = -1; + x = NULL; + } + if (err == 0) { + x = PyTuple_Pack(1, v); + if (x == NULL) + err = -1; + } + if (err == 0) { + w = PyEval_CallObject(w, x); + Py_XDECREF(w); + if (w == NULL) + err = -1; + } + Py_DECREF(v); + Py_XDECREF(x); + break; + + case PRINT_ITEM_TO: + w = stream = POP(); + /* fall through to PRINT_ITEM */ + + case PRINT_ITEM: + v = POP(); + if (stream == NULL || stream == Py_None) { + w = PySys_GetObject("stdout"); + if (w == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + err = -1; + } + } + /* PyFile_SoftSpace() can exececute arbitrary code + if sys.stdout is an instance with a __getattr__. + If __getattr__ raises an exception, w will + be freed, so we need to prevent that temporarily. */ + Py_XINCREF(w); + if (w != NULL && PyFile_SoftSpace(w, 0)) + err = PyFile_WriteString(" ", w); + if (err == 0) + err = PyFile_WriteObject(v, w, Py_PRINT_RAW); + if (err == 0) { + /* XXX move into writeobject() ? */ + if (PyString_Check(v)) { + char *s = PyString_AS_STRING(v); + Py_ssize_t len = PyString_GET_SIZE(v); + if (len == 0 || + !isspace(Py_CHARMASK(s[len-1])) || + s[len-1] == ' ') + PyFile_SoftSpace(w, 1); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(v)) { + Py_UNICODE *s = PyUnicode_AS_UNICODE(v); + Py_ssize_t len = PyUnicode_GET_SIZE(v); + if (len == 0 || + !Py_UNICODE_ISSPACE(s[len-1]) || + s[len-1] == ' ') + PyFile_SoftSpace(w, 1); + } +#endif + else + PyFile_SoftSpace(w, 1); + } + Py_XDECREF(w); + Py_DECREF(v); + Py_XDECREF(stream); + stream = NULL; + if (err == 0) + continue; + break; + + case PRINT_NEWLINE_TO: + w = stream = POP(); + /* fall through to PRINT_NEWLINE */ + + case PRINT_NEWLINE: + if (stream == NULL || stream == Py_None) { + w = PySys_GetObject("stdout"); + if (w == NULL) + PyErr_SetString(PyExc_RuntimeError, + "lost sys.stdout"); + } + if (w != NULL) { + err = PyFile_WriteString("\n", w); + if (err == 0) + PyFile_SoftSpace(w, 0); + } + Py_XDECREF(stream); + stream = NULL; + break; + + +#ifdef CASE_TOO_BIG + default: switch (opcode) { +#endif + case RAISE_VARARGS: + u = v = w = NULL; + switch (oparg) { + case 3: + u = POP(); /* traceback */ + /* Fallthrough */ + case 2: + v = POP(); /* value */ + /* Fallthrough */ + case 1: + w = POP(); /* exc */ + case 0: /* Fallthrough */ + why = do_raise(w, v, u); + break; + default: + PyErr_SetString(PyExc_SystemError, + "bad RAISE_VARARGS oparg"); + why = WHY_EXCEPTION; + break; + } + break; + + case LOAD_LOCALS: + if ((x = f->f_locals) != NULL) { + Py_INCREF(x); + PUSH(x); + continue; + } + PyErr_SetString(PyExc_SystemError, "no locals"); + break; + + case RETURN_VALUE: + retval = POP(); + why = WHY_RETURN; + goto fast_block_end; + + case YIELD_VALUE: + retval = POP(); + f->f_stacktop = stack_pointer; + why = WHY_YIELD; + goto fast_yield; + + case EXEC_STMT: + w = TOP(); + v = SECOND(); + u = THIRD(); + STACKADJ(-3); + READ_TIMESTAMP(intr0); + err = exec_statement(f, u, v, w); + READ_TIMESTAMP(intr1); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case POP_BLOCK: + { + PyTryBlock *b = PyFrame_BlockPop(f); + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_DECREF(v); + } + } + continue; + + case END_FINALLY: + v = POP(); + if (PyInt_Check(v)) { + why = (enum why_code) PyInt_AS_LONG(v); + assert(why != WHY_YIELD); + if (why == WHY_RETURN || + why == WHY_CONTINUE) + retval = POP(); + } + else if (PyExceptionClass_Check(v) || PyString_Check(v)) { + w = POP(); + u = POP(); + PyErr_Restore(v, w, u); + why = WHY_RERAISE; + break; + } + else if (v != Py_None) { + PyErr_SetString(PyExc_SystemError, + "'finally' pops bad exception"); + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case BUILD_CLASS: + u = TOP(); + v = SECOND(); + w = THIRD(); + STACKADJ(-2); + x = build_class(u, v, w); + SET_TOP(x); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + break; + + case STORE_NAME: + w = GETITEM(names, oparg); + v = POP(); + if ((x = f->f_locals) != NULL) { + if (PyDict_CheckExact(x)) + err = PyDict_SetItem(x, w, v); + else + err = PyObject_SetItem(x, w, v); + Py_DECREF(v); + if (err == 0) continue; + break; + } + PyErr_Format(PyExc_SystemError, + "no locals found when storing %s", + PyObject_REPR(w)); + break; + + case DELETE_NAME: + w = GETITEM(names, oparg); + if ((x = f->f_locals) != NULL) { + if ((err = PyObject_DelItem(x, w)) != 0) + format_exc_check_arg(PyExc_NameError, + NAME_ERROR_MSG ,w); + break; + } + PyErr_Format(PyExc_SystemError, + "no locals when deleting %s", + PyObject_REPR(w)); + break; + + PREDICTED_WITH_ARG(UNPACK_SEQUENCE); + case UNPACK_SEQUENCE: + v = POP(); + if (PyTuple_CheckExact(v) && PyTuple_GET_SIZE(v) == oparg) { + PyObject **items = ((PyTupleObject *)v)->ob_item; + while (oparg--) { + w = items[oparg]; + Py_INCREF(w); + PUSH(w); + } + Py_DECREF(v); + continue; + } else if (PyList_CheckExact(v) && PyList_GET_SIZE(v) == oparg) { + PyObject **items = ((PyListObject *)v)->ob_item; + while (oparg--) { + w = items[oparg]; + Py_INCREF(w); + PUSH(w); + } + } else if (unpack_iterable(v, oparg, + stack_pointer + oparg)) { + stack_pointer += oparg; + } else { + /* unpack_iterable() raised an exception */ + why = WHY_EXCEPTION; + } + Py_DECREF(v); + break; + + case STORE_ATTR: + w = GETITEM(names, oparg); + v = TOP(); + u = SECOND(); + STACKADJ(-2); + err = PyObject_SetAttr(v, w, u); /* v.w = u */ + Py_DECREF(v); + Py_DECREF(u); + if (err == 0) continue; + break; + + case DELETE_ATTR: + w = GETITEM(names, oparg); + v = POP(); + err = PyObject_SetAttr(v, w, (PyObject *)NULL); + /* del v.w */ + Py_DECREF(v); + break; + + case STORE_GLOBAL: + w = GETITEM(names, oparg); + v = POP(); + err = PyDict_SetItem(f->f_globals, w, v); + Py_DECREF(v); + if (err == 0) continue; + break; + + case DELETE_GLOBAL: + w = GETITEM(names, oparg); + if ((err = PyDict_DelItem(f->f_globals, w)) != 0) + format_exc_check_arg( + PyExc_NameError, GLOBAL_NAME_ERROR_MSG, w); + break; + + case LOAD_NAME: + w = GETITEM(names, oparg); + if ((v = f->f_locals) == NULL) { + PyErr_Format(PyExc_SystemError, + "no locals when loading %s", + PyObject_REPR(w)); + break; + } + if (PyDict_CheckExact(v)) { + x = PyDict_GetItem(v, w); + Py_XINCREF(x); + } + else { + x = PyObject_GetItem(v, w); + if (x == NULL && PyErr_Occurred()) { + if (!PyErr_ExceptionMatches(PyExc_KeyError)) + break; + PyErr_Clear(); + } + } + if (x == NULL) { + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + format_exc_check_arg( + PyExc_NameError, + NAME_ERROR_MSG ,w); + break; + } + } + Py_INCREF(x); + } + PUSH(x); + continue; + + case LOAD_GLOBAL: + w = GETITEM(names, oparg); + if (PyString_CheckExact(w)) { + /* Inline the PyDict_GetItem() calls. + WARNING: this is an extreme speed hack. + Do not try this at home. */ + long hash = ((PyStringObject *)w)->ob_shash; + if (hash != -1) { + PyDictObject *d; + PyDictEntry *e; + d = (PyDictObject *)(f->f_globals); + e = d->ma_lookup(d, w, hash); + if (e == NULL) { + x = NULL; + break; + } + x = e->me_value; + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + continue; + } + d = (PyDictObject *)(f->f_builtins); + e = d->ma_lookup(d, w, hash); + if (e == NULL) { + x = NULL; + break; + } + x = e->me_value; + if (x != NULL) { + Py_INCREF(x); + PUSH(x); + continue; + } + goto load_global_error; + } + } + /* This is the un-inlined version of the code above */ + x = PyDict_GetItem(f->f_globals, w); + if (x == NULL) { + x = PyDict_GetItem(f->f_builtins, w); + if (x == NULL) { + load_global_error: + format_exc_check_arg( + PyExc_NameError, + GLOBAL_NAME_ERROR_MSG, w); + break; + } + } + Py_INCREF(x); + PUSH(x); + continue; + + case DELETE_FAST: + x = GETLOCAL(oparg); + if (x != NULL) { + SETLOCAL(oparg, NULL); + continue; + } + format_exc_check_arg( + PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + PyTuple_GetItem(co->co_varnames, oparg) + ); + break; + + case LOAD_CLOSURE: + x = freevars[oparg]; + Py_INCREF(x); + PUSH(x); + if (x != NULL) continue; + break; + + case LOAD_DEREF: + x = freevars[oparg]; + w = PyCell_Get(x); + if (w != NULL) { + PUSH(w); + continue; + } + err = -1; + /* Don't stomp existing exception */ + if (PyErr_Occurred()) + break; + if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) { + v = PyTuple_GET_ITEM(co->co_cellvars, + oparg); + format_exc_check_arg( + PyExc_UnboundLocalError, + UNBOUNDLOCAL_ERROR_MSG, + v); + } else { + v = PyTuple_GET_ITEM( + co->co_freevars, + oparg - PyTuple_GET_SIZE(co->co_cellvars)); + format_exc_check_arg( + PyExc_NameError, + UNBOUNDFREE_ERROR_MSG, + v); + } + break; + + case STORE_DEREF: + w = POP(); + x = freevars[oparg]; + PyCell_Set(x, w); + Py_DECREF(w); + continue; + + case BUILD_TUPLE: + x = PyTuple_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyTuple_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_LIST: + x = PyList_New(oparg); + if (x != NULL) { + for (; --oparg >= 0;) { + w = POP(); + PyList_SET_ITEM(x, oparg, w); + } + PUSH(x); + continue; + } + break; + + case BUILD_MAP: + x = PyDict_New(); + PUSH(x); + if (x != NULL) continue; + break; + + case LOAD_ATTR: + w = GETITEM(names, oparg); + v = TOP(); + x = PyObject_GetAttr(v, w); + Py_DECREF(v); + SET_TOP(x); + if (x != NULL) continue; + break; + + case COMPARE_OP: + w = POP(); + v = TOP(); + if (PyInt_CheckExact(w) && PyInt_CheckExact(v)) { + /* INLINE: cmp(int, int) */ + register long a, b; + register int res; + a = PyInt_AS_LONG(v); + b = PyInt_AS_LONG(w); + switch (oparg) { + case PyCmp_LT: res = a < b; break; + case PyCmp_LE: res = a <= b; break; + case PyCmp_EQ: res = a == b; break; + case PyCmp_NE: res = a != b; break; + case PyCmp_GT: res = a > b; break; + case PyCmp_GE: res = a >= b; break; + case PyCmp_IS: res = v == w; break; + case PyCmp_IS_NOT: res = v != w; break; + default: goto slow_compare; + } + x = res ? Py_True : Py_False; + Py_INCREF(x); + } + else { + slow_compare: + x = cmp_outcome(oparg, v, w); + } + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x == NULL) break; + PREDICT(JUMP_IF_FALSE); + PREDICT(JUMP_IF_TRUE); + continue; + + case IMPORT_NAME: + w = GETITEM(names, oparg); + x = PyDict_GetItemString(f->f_builtins, "__import__"); + if (x == NULL) { + PyErr_SetString(PyExc_ImportError, + "__import__ not found"); + break; + } + v = POP(); + u = TOP(); + if (PyInt_AsLong(u) != -1 || PyErr_Occurred()) + w = PyTuple_Pack(5, + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + v, + u); + else + w = PyTuple_Pack(4, + w, + f->f_globals, + f->f_locals == NULL ? + Py_None : f->f_locals, + v); + Py_DECREF(v); + Py_DECREF(u); + if (w == NULL) { + u = POP(); + x = NULL; + break; + } + READ_TIMESTAMP(intr0); + x = PyEval_CallObject(x, w); + READ_TIMESTAMP(intr1); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case IMPORT_STAR: + v = POP(); + PyFrame_FastToLocals(f); + if ((x = f->f_locals) == NULL) { + PyErr_SetString(PyExc_SystemError, + "no locals found during 'import *'"); + break; + } + READ_TIMESTAMP(intr0); + err = import_all_from(x, v); + READ_TIMESTAMP(intr1); + PyFrame_LocalsToFast(f, 0); + Py_DECREF(v); + if (err == 0) continue; + break; + + case IMPORT_FROM: + w = GETITEM(names, oparg); + v = TOP(); + READ_TIMESTAMP(intr0); + x = import_from(v, w); + READ_TIMESTAMP(intr1); + PUSH(x); + if (x != NULL) continue; + break; + + case JUMP_FORWARD: + JUMPBY(oparg); + goto fast_next_opcode; + + PREDICTED_WITH_ARG(JUMP_IF_FALSE); + case JUMP_IF_FALSE: + w = TOP(); + if (w == Py_True) { + PREDICT(POP_TOP); + goto fast_next_opcode; + } + if (w == Py_False) { + JUMPBY(oparg); + goto fast_next_opcode; + } + err = PyObject_IsTrue(w); + if (err > 0) + err = 0; + else if (err == 0) + JUMPBY(oparg); + else + break; + continue; + + PREDICTED_WITH_ARG(JUMP_IF_TRUE); + case JUMP_IF_TRUE: + w = TOP(); + if (w == Py_False) { + PREDICT(POP_TOP); + goto fast_next_opcode; + } + if (w == Py_True) { + JUMPBY(oparg); + goto fast_next_opcode; + } + err = PyObject_IsTrue(w); + if (err > 0) { + err = 0; + JUMPBY(oparg); + } + else if (err == 0) + ; + else + break; + continue; + + PREDICTED_WITH_ARG(JUMP_ABSOLUTE); + case JUMP_ABSOLUTE: + JUMPTO(oparg); + continue; + + case GET_ITER: + /* before: [obj]; after [getiter(obj)] */ + v = TOP(); + x = PyObject_GetIter(v); + Py_DECREF(v); + if (x != NULL) { + SET_TOP(x); + PREDICT(FOR_ITER); + continue; + } + STACKADJ(-1); + break; + + PREDICTED_WITH_ARG(FOR_ITER); + case FOR_ITER: + /* before: [iter]; after: [iter, iter()] *or* [] */ + v = TOP(); + x = (*v->ob_type->tp_iternext)(v); + if (x != NULL) { + PUSH(x); + PREDICT(STORE_FAST); + PREDICT(UNPACK_SEQUENCE); + continue; + } + if (PyErr_Occurred()) { + if (!PyErr_ExceptionMatches(PyExc_StopIteration)) + break; + PyErr_Clear(); + } + /* iterator ended normally */ + x = v = POP(); + Py_DECREF(v); + JUMPBY(oparg); + continue; + + case BREAK_LOOP: + why = WHY_BREAK; + goto fast_block_end; + + case CONTINUE_LOOP: + retval = PyInt_FromLong(oparg); + if (!retval) { + x = NULL; + break; + } + why = WHY_CONTINUE; + goto fast_block_end; + + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + /* NOTE: If you add any new block-setup opcodes that are not try/except/finally + handlers, you may need to update the PyGen_NeedsFinalizing() function. */ + + PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, + STACK_LEVEL()); + continue; + + case WITH_CLEANUP: + { + /* TOP is the context.__exit__ bound method. + Below that are 1-3 values indicating how/why + we entered the finally clause: + - SECOND = None + - (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval + - SECOND = WHY_*; no retval below it + - (SECOND, THIRD, FOURTH) = exc_info() + In the last case, we must call + TOP(SECOND, THIRD, FOURTH) + otherwise we must call + TOP(None, None, None) + + In addition, if the stack represents an exception, + *and* the function call returns a 'true' value, we + "zap" this information, to prevent END_FINALLY from + re-raising the exception. (But non-local gotos + should still be resumed.) + */ + + x = TOP(); + u = SECOND(); + if (PyInt_Check(u) || u == Py_None) { + u = v = w = Py_None; + } + else { + v = THIRD(); + w = FOURTH(); + } + /* XXX Not the fastest way to call it... */ + x = PyObject_CallFunctionObjArgs(x, u, v, w, NULL); + if (x == NULL) + break; /* Go to error exit */ + if (u != Py_None && PyObject_IsTrue(x)) { + /* There was an exception and a true return */ + Py_DECREF(x); + x = TOP(); /* Again */ + STACKADJ(-3); + Py_INCREF(Py_None); + SET_TOP(Py_None); + Py_DECREF(x); + Py_DECREF(u); + Py_DECREF(v); + Py_DECREF(w); + } else { + /* Let END_FINALLY do its thing */ + Py_DECREF(x); + x = POP(); + Py_DECREF(x); + } + break; + } + + case CALL_FUNCTION: + { + PyObject **sp; + PCALL(PCALL_ALL); + sp = stack_pointer; +#ifdef WITH_TSC + x = call_function(&sp, oparg, &intr0, &intr1); +#else + x = call_function(&sp, oparg); +#endif + stack_pointer = sp; + PUSH(x); + if (x != NULL) + continue; + break; + } + + case CALL_FUNCTION_VAR: + case CALL_FUNCTION_KW: + case CALL_FUNCTION_VAR_KW: + { + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int flags = (opcode - CALL_FUNCTION) & 3; + int n = na + 2 * nk; + PyObject **pfunc, *func, **sp; + PCALL(PCALL_ALL); + if (flags & CALL_FLAG_VAR) + n++; + if (flags & CALL_FLAG_KW) + n++; + pfunc = stack_pointer - n - 1; + func = *pfunc; + + if (PyMethod_Check(func) + && PyMethod_GET_SELF(func) != NULL) { + PyObject *self = PyMethod_GET_SELF(func); + Py_INCREF(self); + func = PyMethod_GET_FUNCTION(func); + Py_INCREF(func); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } else + Py_INCREF(func); + sp = stack_pointer; + READ_TIMESTAMP(intr0); + x = ext_do_call(func, &sp, flags, na, nk); + READ_TIMESTAMP(intr1); + stack_pointer = sp; + Py_DECREF(func); + + while (stack_pointer > pfunc) { + w = POP(); + Py_DECREF(w); + } + PUSH(x); + if (x != NULL) + continue; + break; + } + + case MAKE_FUNCTION: + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + /* XXX Maybe this should be a separate opcode? */ + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + + case MAKE_CLOSURE: + { + v = POP(); /* code object */ + x = PyFunction_New(v, f->f_globals); + Py_DECREF(v); + if (x != NULL) { + v = POP(); + err = PyFunction_SetClosure(x, v); + Py_DECREF(v); + } + if (x != NULL && oparg > 0) { + v = PyTuple_New(oparg); + if (v == NULL) { + Py_DECREF(x); + x = NULL; + break; + } + while (--oparg >= 0) { + w = POP(); + PyTuple_SET_ITEM(v, oparg, w); + } + err = PyFunction_SetDefaults(x, v); + Py_DECREF(v); + } + PUSH(x); + break; + } + + case BUILD_SLICE: + if (oparg == 3) + w = POP(); + else + w = NULL; + v = POP(); + u = TOP(); + x = PySlice_New(u, v, w); + Py_DECREF(u); + Py_DECREF(v); + Py_XDECREF(w); + SET_TOP(x); + if (x != NULL) continue; + break; + + case EXTENDED_ARG: + opcode = NEXTOP(); + oparg = oparg<<16 | NEXTARG(); + goto dispatch_opcode; + + default: + fprintf(stderr, + "XXX lineno: %d, opcode: %d\n", + PyCode_Addr2Line(f->f_code, f->f_lasti), + opcode); + PyErr_SetString(PyExc_SystemError, "unknown opcode"); + why = WHY_EXCEPTION; + break; + +#ifdef CASE_TOO_BIG + } +#endif + + } /* switch */ + + on_error: + + READ_TIMESTAMP(inst1); + + /* Quickly continue if no error occurred */ + + if (why == WHY_NOT) { + if (err == 0 && x != NULL) { +#ifdef CHECKEXC + /* This check is expensive! */ + if (PyErr_Occurred()) + fprintf(stderr, + "XXX undetected error\n"); + else { +#endif + READ_TIMESTAMP(loop1); + continue; /* Normal, fast path */ +#ifdef CHECKEXC + } +#endif + } + why = WHY_EXCEPTION; + x = Py_None; + err = 0; + } + + /* Double-check exception status */ + + if (why == WHY_EXCEPTION || why == WHY_RERAISE) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, + "error return without exception set"); + why = WHY_EXCEPTION; + } + } +#ifdef CHECKEXC + else { + /* This check is expensive! */ + if (PyErr_Occurred()) { + char buf[1024]; + sprintf(buf, "Stack unwind with exception " + "set and why=%d", why); + Py_FatalError(buf); + } + } +#endif + + /* Log traceback info if this is a real exception */ + + if (why == WHY_EXCEPTION) { + PyTraceBack_Here(f); + + if (tstate->c_tracefunc != NULL) + call_exc_trace(tstate->c_tracefunc, + tstate->c_traceobj, f); + } + + /* For the rest, treat WHY_RERAISE as WHY_EXCEPTION */ + + if (why == WHY_RERAISE) + why = WHY_EXCEPTION; + + /* Unwind stacks if a (pseudo) exception occurred */ + +fast_block_end: + while (why != WHY_NOT && f->f_iblock > 0) { + PyTryBlock *b = PyFrame_BlockPop(f); + + assert(why != WHY_YIELD); + if (b->b_type == SETUP_LOOP && why == WHY_CONTINUE) { + /* For a continue inside a try block, + don't pop the block for the loop. */ + PyFrame_BlockSetup(f, b->b_type, b->b_handler, + b->b_level); + why = WHY_NOT; + JUMPTO(PyInt_AS_LONG(retval)); + Py_DECREF(retval); + break; + } + + while (STACK_LEVEL() > b->b_level) { + v = POP(); + Py_XDECREF(v); + } + if (b->b_type == SETUP_LOOP && why == WHY_BREAK) { + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + if (b->b_type == SETUP_FINALLY || + (b->b_type == SETUP_EXCEPT && + why == WHY_EXCEPTION)) { + if (why == WHY_EXCEPTION) { + PyObject *exc, *val, *tb; + PyErr_Fetch(&exc, &val, &tb); + if (val == NULL) { + val = Py_None; + Py_INCREF(val); + } + /* Make the raw exception data + available to the handler, + so a program can emulate the + Python main loop. Don't do + this for 'finally'. */ + if (b->b_type == SETUP_EXCEPT) { + PyErr_NormalizeException( + &exc, &val, &tb); + set_exc_info(tstate, + exc, val, tb); + } + if (tb == NULL) { + Py_INCREF(Py_None); + PUSH(Py_None); + } else + PUSH(tb); + PUSH(val); + PUSH(exc); + } + else { + if (why & (WHY_RETURN | WHY_CONTINUE)) + PUSH(retval); + v = PyInt_FromLong((long)why); + PUSH(v); + } + why = WHY_NOT; + JUMPTO(b->b_handler); + break; + } + } /* unwind stack */ + + /* End the loop if we still have an error (or return) */ + + if (why != WHY_NOT) + break; + READ_TIMESTAMP(loop1); + + } /* main loop */ + + assert(why != WHY_YIELD); + /* Pop remaining stack entries. */ + while (!EMPTY()) { + v = POP(); + Py_XDECREF(v); + } + + if (why != WHY_RETURN) + retval = NULL; + +fast_yield: + if (tstate->use_tracing) { + if (tstate->c_tracefunc) { + if (why == WHY_RETURN || why == WHY_YIELD) { + if (call_trace(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN, retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + else if (why == WHY_EXCEPTION) { + call_trace_protected(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN, NULL); + } + } + if (tstate->c_profilefunc) { + if (why == WHY_EXCEPTION) + call_trace_protected(tstate->c_profilefunc, + tstate->c_profileobj, f, + PyTrace_RETURN, NULL); + else if (call_trace(tstate->c_profilefunc, + tstate->c_profileobj, f, + PyTrace_RETURN, retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + } + + if (tstate->frame->f_exc_type != NULL) + reset_exc_info(tstate); + else { + assert(tstate->frame->f_exc_value == NULL); + assert(tstate->frame->f_exc_traceback == NULL); + } + + /* pop frame */ + exit_eval_frame: + Py_LeaveRecursiveCall(); + tstate->frame = f->f_back; + + return retval; +} + +/* This is gonna seem *real weird*, but if you put some other code between + PyEval_EvalFrame() and PyEval_EvalCodeEx() you will need to adjust + the test in the if statements in Misc/gdbinit (pystack and pystackv). */ + +PyObject * +PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, + PyObject **args, int argcount, PyObject **kws, int kwcount, + PyObject **defs, int defcount, PyObject *closure) +{ + register PyFrameObject *f; + register PyObject *retval = NULL; + register PyObject **fastlocals, **freevars; + PyThreadState *tstate = PyThreadState_GET(); + PyObject *x, *u; + + if (globals == NULL) { + PyErr_SetString(PyExc_SystemError, + "PyEval_EvalCodeEx: NULL globals"); + return NULL; + } + + assert(tstate != NULL); + assert(globals != NULL); + f = PyFrame_New(tstate, co, globals, locals); + if (f == NULL) + return NULL; + + fastlocals = f->f_localsplus; + freevars = f->f_localsplus + co->co_nlocals; + + if (co->co_argcount > 0 || + co->co_flags & (CO_VARARGS | CO_VARKEYWORDS)) { + int i; + int n = argcount; + PyObject *kwdict = NULL; + if (co->co_flags & CO_VARKEYWORDS) { + kwdict = PyDict_New(); + if (kwdict == NULL) + goto fail; + i = co->co_argcount; + if (co->co_flags & CO_VARARGS) + i++; + SETLOCAL(i, kwdict); + } + if (argcount > co->co_argcount) { + if (!(co->co_flags & CO_VARARGS)) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes %s %d " + "%sargument%s (%d given)", + PyString_AsString(co->co_name), + defcount ? "at most" : "exactly", + co->co_argcount, + kwcount ? "non-keyword " : "", + co->co_argcount == 1 ? "" : "s", + argcount); + goto fail; + } + n = co->co_argcount; + } + for (i = 0; i < n; i++) { + x = args[i]; + Py_INCREF(x); + SETLOCAL(i, x); + } + if (co->co_flags & CO_VARARGS) { + u = PyTuple_New(argcount - n); + if (u == NULL) + goto fail; + SETLOCAL(co->co_argcount, u); + for (i = n; i < argcount; i++) { + x = args[i]; + Py_INCREF(x); + PyTuple_SET_ITEM(u, i-n, x); + } + } + for (i = 0; i < kwcount; i++) { + PyObject *keyword = kws[2*i]; + PyObject *value = kws[2*i + 1]; + int j; + if (keyword == NULL || !PyString_Check(keyword)) { + PyErr_Format(PyExc_TypeError, + "%.200s() keywords must be strings", + PyString_AsString(co->co_name)); + goto fail; + } + /* XXX slow -- speed up using dictionary? */ + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = PyTuple_GET_ITEM( + co->co_varnames, j); + int cmp = PyObject_RichCompareBool( + keyword, nm, Py_EQ); + if (cmp > 0) + break; + else if (cmp < 0) + goto fail; + } + /* Check errors from Compare */ + if (PyErr_Occurred()) + goto fail; + if (j >= co->co_argcount) { + if (kwdict == NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s() got an unexpected " + "keyword argument '%.400s'", + PyString_AsString(co->co_name), + PyString_AsString(keyword)); + goto fail; + } + PyDict_SetItem(kwdict, keyword, value); + } + else { + if (GETLOCAL(j) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s() got multiple " + "values for keyword " + "argument '%.400s'", + PyString_AsString(co->co_name), + PyString_AsString(keyword)); + goto fail; + } + Py_INCREF(value); + SETLOCAL(j, value); + } + } + if (argcount < co->co_argcount) { + int m = co->co_argcount - defcount; + for (i = argcount; i < m; i++) { + if (GETLOCAL(i) == NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes %s %d " + "%sargument%s (%d given)", + PyString_AsString(co->co_name), + ((co->co_flags & CO_VARARGS) || + defcount) ? "at least" + : "exactly", + m, kwcount ? "non-keyword " : "", + m == 1 ? "" : "s", i); + goto fail; + } + } + if (n > m) + i = n - m; + else + i = 0; + for (; i < defcount; i++) { + if (GETLOCAL(m+i) == NULL) { + PyObject *def = defs[i]; + Py_INCREF(def); + SETLOCAL(m+i, def); + } + } + } + } + else { + if (argcount > 0 || kwcount > 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%d given)", + PyString_AsString(co->co_name), + argcount + kwcount); + goto fail; + } + } + /* Allocate and initialize storage for cell vars, and copy free + vars into frame. This isn't too efficient right now. */ + if (PyTuple_GET_SIZE(co->co_cellvars)) { + int i, j, nargs, found; + char *cellname, *argname; + PyObject *c; + + nargs = co->co_argcount; + if (co->co_flags & CO_VARARGS) + nargs++; + if (co->co_flags & CO_VARKEYWORDS) + nargs++; + + /* Initialize each cell var, taking into account + cell vars that are initialized from arguments. + + Should arrange for the compiler to put cellvars + that are arguments at the beginning of the cellvars + list so that we can march over it more efficiently? + */ + for (i = 0; i < PyTuple_GET_SIZE(co->co_cellvars); ++i) { + cellname = PyString_AS_STRING( + PyTuple_GET_ITEM(co->co_cellvars, i)); + found = 0; + for (j = 0; j < nargs; j++) { + argname = PyString_AS_STRING( + PyTuple_GET_ITEM(co->co_varnames, j)); + if (strcmp(cellname, argname) == 0) { + c = PyCell_New(GETLOCAL(j)); + if (c == NULL) + goto fail; + GETLOCAL(co->co_nlocals + i) = c; + found = 1; + break; + } + } + if (found == 0) { + c = PyCell_New(NULL); + if (c == NULL) + goto fail; + SETLOCAL(co->co_nlocals + i, c); + } + } + } + if (PyTuple_GET_SIZE(co->co_freevars)) { + int i; + for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) { + PyObject *o = PyTuple_GET_ITEM(closure, i); + Py_INCREF(o); + freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o; + } + } + + if (co->co_flags & CO_GENERATOR) { + /* Don't need to keep the reference to f_back, it will be set + * when the generator is resumed. */ + Py_XDECREF(f->f_back); + f->f_back = NULL; + + PCALL(PCALL_GENERATOR); + + /* Create a new generator that owns the ready to run frame + * and return that as the value. */ + return PyGen_New(f); + } + + retval = PyEval_EvalFrameEx(f,0); + + fail: /* Jump here from prelude on failure */ + + /* decref'ing the frame can cause __del__ methods to get invoked, + which can call back into Python. While we're done with the + current Python frame (f), the associated C stack is still in use, + so recursion_depth must be boosted for the duration. + */ + assert(tstate != NULL); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return retval; +} + + +/* Implementation notes for set_exc_info() and reset_exc_info(): + +- Below, 'exc_ZZZ' stands for 'exc_type', 'exc_value' and + 'exc_traceback'. These always travel together. + +- tstate->curexc_ZZZ is the "hot" exception that is set by + PyErr_SetString(), cleared by PyErr_Clear(), and so on. + +- Once an exception is caught by an except clause, it is transferred + from tstate->curexc_ZZZ to tstate->exc_ZZZ, from which sys.exc_info() + can pick it up. This is the primary task of set_exc_info(). + XXX That can't be right: set_exc_info() doesn't look at tstate->curexc_ZZZ. + +- Now let me explain the complicated dance with frame->f_exc_ZZZ. + + Long ago, when none of this existed, there were just a few globals: + one set corresponding to the "hot" exception, and one set + corresponding to sys.exc_ZZZ. (Actually, the latter weren't C + globals; they were simply stored as sys.exc_ZZZ. For backwards + compatibility, they still are!) The problem was that in code like + this: + + try: + "something that may fail" + except "some exception": + "do something else first" + "print the exception from sys.exc_ZZZ." + + if "do something else first" invoked something that raised and caught + an exception, sys.exc_ZZZ were overwritten. That was a frequent + cause of subtle bugs. I fixed this by changing the semantics as + follows: + + - Within one frame, sys.exc_ZZZ will hold the last exception caught + *in that frame*. + + - But initially, and as long as no exception is caught in a given + frame, sys.exc_ZZZ will hold the last exception caught in the + previous frame (or the frame before that, etc.). + + The first bullet fixed the bug in the above example. The second + bullet was for backwards compatibility: it was (and is) common to + have a function that is called when an exception is caught, and to + have that function access the caught exception via sys.exc_ZZZ. + (Example: traceback.print_exc()). + + At the same time I fixed the problem that sys.exc_ZZZ weren't + thread-safe, by introducing sys.exc_info() which gets it from tstate; + but that's really a separate improvement. + + The reset_exc_info() function in ceval.c restores the tstate->exc_ZZZ + variables to what they were before the current frame was called. The + set_exc_info() function saves them on the frame so that + reset_exc_info() can restore them. The invariant is that + frame->f_exc_ZZZ is NULL iff the current frame never caught an + exception (where "catching" an exception applies only to successful + except clauses); and if the current frame ever caught an exception, + frame->f_exc_ZZZ is the exception that was stored in tstate->exc_ZZZ + at the start of the current frame. + +*/ + +static void +set_exc_info(PyThreadState *tstate, + PyObject *type, PyObject *value, PyObject *tb) +{ + PyFrameObject *frame = tstate->frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + + assert(type != NULL); + assert(frame != NULL); + if (frame->f_exc_type == NULL) { + assert(frame->f_exc_value == NULL); + assert(frame->f_exc_traceback == NULL); + /* This frame didn't catch an exception before. */ + /* Save previous exception of this thread in this frame. */ + if (tstate->exc_type == NULL) { + /* XXX Why is this set to Py_None? */ + Py_INCREF(Py_None); + tstate->exc_type = Py_None; + } + Py_INCREF(tstate->exc_type); + Py_XINCREF(tstate->exc_value); + Py_XINCREF(tstate->exc_traceback); + frame->f_exc_type = tstate->exc_type; + frame->f_exc_value = tstate->exc_value; + frame->f_exc_traceback = tstate->exc_traceback; + } + /* Set new exception for this thread. */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_INCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + tstate->exc_type = type; + tstate->exc_value = value; + tstate->exc_traceback = tb; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + /* For b/w compatibility */ + PySys_SetObject("exc_type", type); + PySys_SetObject("exc_value", value); + PySys_SetObject("exc_traceback", tb); +} + +static void +reset_exc_info(PyThreadState *tstate) +{ + PyFrameObject *frame; + PyObject *tmp_type, *tmp_value, *tmp_tb; + + /* It's a precondition that the thread state's frame caught an + * exception -- verify in a debug build. + */ + assert(tstate != NULL); + frame = tstate->frame; + assert(frame != NULL); + assert(frame->f_exc_type != NULL); + + /* Copy the frame's exception info back to the thread state. */ + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + Py_INCREF(frame->f_exc_type); + Py_XINCREF(frame->f_exc_value); + Py_XINCREF(frame->f_exc_traceback); + tstate->exc_type = frame->f_exc_type; + tstate->exc_value = frame->f_exc_value; + tstate->exc_traceback = frame->f_exc_traceback; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + + /* For b/w compatibility */ + PySys_SetObject("exc_type", frame->f_exc_type); + PySys_SetObject("exc_value", frame->f_exc_value); + PySys_SetObject("exc_traceback", frame->f_exc_traceback); + + /* Clear the frame's exception info. */ + tmp_type = frame->f_exc_type; + tmp_value = frame->f_exc_value; + tmp_tb = frame->f_exc_traceback; + frame->f_exc_type = NULL; + frame->f_exc_value = NULL; + frame->f_exc_traceback = NULL; + Py_DECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); +} + +/* Logic for the raise statement (too complicated for inlining). + This *consumes* a reference count to each of its arguments. */ +static enum why_code +do_raise(PyObject *type, PyObject *value, PyObject *tb) +{ + if (type == NULL) { + /* Reraise */ + PyThreadState *tstate = PyThreadState_GET(); + type = tstate->exc_type == NULL ? Py_None : tstate->exc_type; + value = tstate->exc_value; + tb = tstate->exc_traceback; + Py_XINCREF(type); + Py_XINCREF(value); + Py_XINCREF(tb); + } + + /* We support the following forms of raise: + raise <class>, <classinstance> + raise <class>, <argument tuple> + raise <class>, None + raise <class>, <argument> + raise <classinstance>, None + raise <string>, <object> + raise <string>, None + + An omitted second argument is the same as None. + + In addition, raise <tuple>, <anything> is the same as + raising the tuple's first item (and it better have one!); + this rule is applied recursively. + + Finally, an optional third argument can be supplied, which + gives the traceback to be substituted (useful when + re-raising an exception after examining it). */ + + /* First, check the traceback argument, replacing None with + NULL. */ + if (tb == Py_None) { + Py_DECREF(tb); + tb = NULL; + } + else if (tb != NULL && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "raise: arg 3 must be a traceback or None"); + goto raise_error; + } + + /* Next, replace a missing value with None */ + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + + /* Next, repeatedly, replace a tuple exception with its first item */ + while (PyTuple_Check(type) && PyTuple_Size(type) > 0) { + PyObject *tmp = type; + type = PyTuple_GET_ITEM(type, 0); + Py_INCREF(type); + Py_DECREF(tmp); + } + + if (PyString_CheckExact(type)) { + /* Raising builtin string is deprecated but still allowed -- + * do nothing. Raising an instance of a new-style str + * subclass is right out. */ + if (PyErr_Warn(PyExc_DeprecationWarning, + "raising a string exception is deprecated")) + goto raise_error; + } + else if (PyExceptionClass_Check(type)) + PyErr_NormalizeException(&type, &value, &tb); + + else if (PyExceptionInstance_Check(type)) { + /* Raising an instance. The value should be a dummy. */ + if (value != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto raise_error; + } + else { + /* Normalize to raise <class>, <instance> */ + Py_DECREF(value); + value = type; + type = PyExceptionInstance_Class(type); + Py_INCREF(type); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes, instances, or " + "strings (deprecated), not %s", + type->ob_type->tp_name); + goto raise_error; + } + PyErr_Restore(type, value, tb); + if (tb == NULL) + return WHY_EXCEPTION; + else + return WHY_RERAISE; + raise_error: + Py_XDECREF(value); + Py_XDECREF(type); + Py_XDECREF(tb); + return WHY_EXCEPTION; +} + +/* Iterate v argcnt times and store the results on the stack (via decreasing + sp). Return 1 for success, 0 if error. */ + +static int +unpack_iterable(PyObject *v, int argcnt, PyObject **sp) +{ + int i = 0; + PyObject *it; /* iter(v) */ + PyObject *w; + + assert(v != NULL); + + it = PyObject_GetIter(v); + if (it == NULL) + goto Error; + + for (; i < argcnt; i++) { + w = PyIter_Next(it); + if (w == NULL) { + /* Iterator done, via error or exhaustion. */ + if (!PyErr_Occurred()) { + PyErr_Format(PyExc_ValueError, + "need more than %d value%s to unpack", + i, i == 1 ? "" : "s"); + } + goto Error; + } + *--sp = w; + } + + /* We better have exhausted the iterator now. */ + w = PyIter_Next(it); + if (w == NULL) { + if (PyErr_Occurred()) + goto Error; + Py_DECREF(it); + return 1; + } + Py_DECREF(w); + PyErr_SetString(PyExc_ValueError, "too many values to unpack"); + /* fall through */ +Error: + for (; i > 0; i--, sp++) + Py_DECREF(*sp); + Py_XDECREF(it); + return 0; +} + + +#ifdef LLTRACE +static int +prtrace(PyObject *v, char *str) +{ + printf("%s ", str); + if (PyObject_Print(v, stdout, 0) != 0) + PyErr_Clear(); /* Don't know what else to do */ + printf("\n"); + return 1; +} +#endif + +static void +call_exc_trace(Py_tracefunc func, PyObject *self, PyFrameObject *f) +{ + PyObject *type, *value, *traceback, *arg; + int err; + PyErr_Fetch(&type, &value, &traceback); + if (value == NULL) { + value = Py_None; + Py_INCREF(value); + } + arg = PyTuple_Pack(3, type, value, traceback); + if (arg == NULL) { + PyErr_Restore(type, value, traceback); + return; + } + err = call_trace(func, self, f, PyTrace_EXCEPTION, arg); + Py_DECREF(arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } +} + +static void +call_trace_protected(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, + int what, PyObject *arg) +{ + PyObject *type, *value, *traceback; + int err; + PyErr_Fetch(&type, &value, &traceback); + err = call_trace(func, obj, frame, what, arg); + if (err == 0) + PyErr_Restore(type, value, traceback); + else { + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(traceback); + } +} + +static int +call_trace(Py_tracefunc func, PyObject *obj, PyFrameObject *frame, + int what, PyObject *arg) +{ + register PyThreadState *tstate = frame->f_tstate; + int result; + if (tstate->tracing) + return 0; + tstate->tracing++; + tstate->use_tracing = 0; + result = func(obj, frame, what, arg); + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + tstate->tracing--; + return result; +} + +PyObject * +_PyEval_CallTracing(PyObject *func, PyObject *args) +{ + PyFrameObject *frame = PyEval_GetFrame(); + PyThreadState *tstate = frame->f_tstate; + int save_tracing = tstate->tracing; + int save_use_tracing = tstate->use_tracing; + PyObject *result; + + tstate->tracing = 0; + tstate->use_tracing = ((tstate->c_tracefunc != NULL) + || (tstate->c_profilefunc != NULL)); + result = PyObject_Call(func, args, NULL); + tstate->tracing = save_tracing; + tstate->use_tracing = save_use_tracing; + return result; +} + +static int +maybe_call_line_trace(Py_tracefunc func, PyObject *obj, + PyFrameObject *frame, int *instr_lb, int *instr_ub, + int *instr_prev) +{ + int result = 0; + + /* If the last instruction executed isn't in the current + instruction window, reset the window. If the last + instruction happens to fall at the start of a line or if it + represents a jump backwards, call the trace function. + */ + if ((frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub)) { + int line; + PyAddrPair bounds; + + line = PyCode_CheckLineNumber(frame->f_code, frame->f_lasti, + &bounds); + if (line >= 0) { + frame->f_lineno = line; + result = call_trace(func, obj, frame, + PyTrace_LINE, Py_None); + } + *instr_lb = bounds.ap_lower; + *instr_ub = bounds.ap_upper; + } + else if (frame->f_lasti <= *instr_prev) { + result = call_trace(func, obj, frame, PyTrace_LINE, Py_None); + } + *instr_prev = frame->f_lasti; + return result; +} + +void +PyEval_SetProfile(Py_tracefunc func, PyObject *arg) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *temp = tstate->c_profileobj; + Py_XINCREF(arg); + tstate->c_profilefunc = NULL; + tstate->c_profileobj = NULL; + /* Must make sure that tracing is not ignored if 'temp' is freed */ + tstate->use_tracing = tstate->c_tracefunc != NULL; + Py_XDECREF(temp); + tstate->c_profilefunc = func; + tstate->c_profileobj = arg; + /* Flag that tracing or profiling is turned on */ + tstate->use_tracing = (func != NULL) || (tstate->c_tracefunc != NULL); +} + +void +PyEval_SetTrace(Py_tracefunc func, PyObject *arg) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *temp = tstate->c_traceobj; + Py_XINCREF(arg); + tstate->c_tracefunc = NULL; + tstate->c_traceobj = NULL; + /* Must make sure that profiling is not ignored if 'temp' is freed */ + tstate->use_tracing = tstate->c_profilefunc != NULL; + Py_XDECREF(temp); + tstate->c_tracefunc = func; + tstate->c_traceobj = arg; + /* Flag that tracing or profiling is turned on */ + tstate->use_tracing = ((func != NULL) + || (tstate->c_profilefunc != NULL)); +} + +PyObject * +PyEval_GetBuiltins(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + if (current_frame == NULL) + return PyThreadState_GET()->interp->builtins; + else + return current_frame->f_builtins; +} + +PyObject * +PyEval_GetLocals(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + if (current_frame == NULL) + return NULL; + PyFrame_FastToLocals(current_frame); + return current_frame->f_locals; +} + +PyObject * +PyEval_GetGlobals(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + if (current_frame == NULL) + return NULL; + else + return current_frame->f_globals; +} + +PyFrameObject * +PyEval_GetFrame(void) +{ + PyThreadState *tstate = PyThreadState_GET(); + return _PyThreadState_GetFrame(tstate); +} + +int +PyEval_GetRestricted(void) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + return current_frame == NULL ? 0 : PyFrame_IsRestricted(current_frame); +} + +int +PyEval_MergeCompilerFlags(PyCompilerFlags *cf) +{ + PyFrameObject *current_frame = PyEval_GetFrame(); + int result = cf->cf_flags != 0; + + if (current_frame != NULL) { + const int codeflags = current_frame->f_code->co_flags; + const int compilerflags = codeflags & PyCF_MASK; + if (compilerflags) { + result = 1; + cf->cf_flags |= compilerflags; + } +#if 0 /* future keyword */ + if (codeflags & CO_GENERATOR_ALLOWED) { + result = 1; + cf->cf_flags |= CO_GENERATOR_ALLOWED; + } +#endif + } + return result; +} + +int +Py_FlushLine(void) +{ + PyObject *f = PySys_GetObject("stdout"); + if (f == NULL) + return 0; + if (!PyFile_SoftSpace(f, 0)) + return 0; + return PyFile_WriteString("\n", f); +} + + +/* External interface to call any callable object. + The arg must be a tuple or NULL. */ + +#undef PyEval_CallObject +/* for backward compatibility: export this interface */ + +PyObject * +PyEval_CallObject(PyObject *func, PyObject *arg) +{ + return PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL); +} +#define PyEval_CallObject(func,arg) \ + PyEval_CallObjectWithKeywords(func, arg, (PyObject *)NULL) + +PyObject * +PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw) +{ + PyObject *result; + + if (arg == NULL) { + arg = PyTuple_New(0); + if (arg == NULL) + return NULL; + } + else if (!PyTuple_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "argument list must be a tuple"); + return NULL; + } + else + Py_INCREF(arg); + + if (kw != NULL && !PyDict_Check(kw)) { + PyErr_SetString(PyExc_TypeError, + "keyword list must be a dictionary"); + Py_DECREF(arg); + return NULL; + } + + result = PyObject_Call(func, arg, kw); + Py_DECREF(arg); + return result; +} + +const char * +PyEval_GetFuncName(PyObject *func) +{ + if (PyMethod_Check(func)) + return PyEval_GetFuncName(PyMethod_GET_FUNCTION(func)); + else if (PyFunction_Check(func)) + return PyString_AsString(((PyFunctionObject*)func)->func_name); + else if (PyCFunction_Check(func)) + return ((PyCFunctionObject*)func)->m_ml->ml_name; + else if (PyClass_Check(func)) + return PyString_AsString(((PyClassObject*)func)->cl_name); + else if (PyInstance_Check(func)) { + return PyString_AsString( + ((PyInstanceObject*)func)->in_class->cl_name); + } else { + return func->ob_type->tp_name; + } +} + +const char * +PyEval_GetFuncDesc(PyObject *func) +{ + if (PyMethod_Check(func)) + return "()"; + else if (PyFunction_Check(func)) + return "()"; + else if (PyCFunction_Check(func)) + return "()"; + else if (PyClass_Check(func)) + return " constructor"; + else if (PyInstance_Check(func)) { + return " instance"; + } else { + return " object"; + } +} + +static void +err_args(PyObject *func, int flags, int nargs) +{ + if (flags & METH_NOARGS) + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%d given)", + ((PyCFunctionObject *)func)->m_ml->ml_name, + nargs); + else + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%d given)", + ((PyCFunctionObject *)func)->m_ml->ml_name, + nargs); +} + +#define C_TRACE(x, call) \ +if (tstate->use_tracing && tstate->c_profilefunc) { \ + if (call_trace(tstate->c_profilefunc, \ + tstate->c_profileobj, \ + tstate->frame, PyTrace_C_CALL, \ + func)) { \ + x = NULL; \ + } \ + else { \ + x = call; \ + if (tstate->c_profilefunc != NULL) { \ + if (x == NULL) { \ + call_trace_protected(tstate->c_profilefunc, \ + tstate->c_profileobj, \ + tstate->frame, PyTrace_C_EXCEPTION, \ + func); \ + /* XXX should pass (type, value, tb) */ \ + } else { \ + if (call_trace(tstate->c_profilefunc, \ + tstate->c_profileobj, \ + tstate->frame, PyTrace_C_RETURN, \ + func)) { \ + Py_DECREF(x); \ + x = NULL; \ + } \ + } \ + } \ + } \ +} else { \ + x = call; \ + } + +static PyObject * +call_function(PyObject ***pp_stack, int oparg +#ifdef WITH_TSC + , uint64* pintr0, uint64* pintr1 +#endif + ) +{ + int na = oparg & 0xff; + int nk = (oparg>>8) & 0xff; + int n = na + 2 * nk; + PyObject **pfunc = (*pp_stack) - n - 1; + PyObject *func = *pfunc; + PyObject *x, *w; + + /* Always dispatch PyCFunction first, because these are + presumed to be the most frequent callable object. + */ + if (PyCFunction_Check(func) && nk == 0) { + int flags = PyCFunction_GET_FLAGS(func); + PyThreadState *tstate = PyThreadState_GET(); + + PCALL(PCALL_CFUNCTION); + if (flags & (METH_NOARGS | METH_O)) { + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + if (flags & METH_NOARGS && na == 0) { + C_TRACE(x, (*meth)(self,NULL)); + } + else if (flags & METH_O && na == 1) { + PyObject *arg = EXT_POP(*pp_stack); + C_TRACE(x, (*meth)(self,arg)); + Py_DECREF(arg); + } + else { + err_args(func, flags, na); + x = NULL; + } + } + else { + PyObject *callargs; + callargs = load_args(pp_stack, na); + READ_TIMESTAMP(*pintr0); + C_TRACE(x, PyCFunction_Call(func,callargs,NULL)); + READ_TIMESTAMP(*pintr1); + Py_XDECREF(callargs); + } + } else { + if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) { + /* optimize access to bound methods */ + PyObject *self = PyMethod_GET_SELF(func); + PCALL(PCALL_METHOD); + PCALL(PCALL_BOUND_METHOD); + Py_INCREF(self); + func = PyMethod_GET_FUNCTION(func); + Py_INCREF(func); + Py_DECREF(*pfunc); + *pfunc = self; + na++; + n++; + } else + Py_INCREF(func); + READ_TIMESTAMP(*pintr0); + if (PyFunction_Check(func)) + x = fast_function(func, pp_stack, n, na, nk); + else + x = do_call(func, pp_stack, na, nk); + READ_TIMESTAMP(*pintr1); + Py_DECREF(func); + } + + /* Clear the stack of the function object. Also removes + the arguments in case they weren't consumed already + (fast_function() and err_args() leave them on the stack). + */ + while ((*pp_stack) > pfunc) { + w = EXT_POP(*pp_stack); + Py_DECREF(w); + PCALL(PCALL_POP); + } + return x; +} + +/* The fast_function() function optimize calls for which no argument + tuple is necessary; the objects are passed directly from the stack. + For the simplest case -- a function that takes only positional + arguments and is called with only positional arguments -- it + inlines the most primitive frame setup code from + PyEval_EvalCodeEx(), which vastly reduces the checks that must be + done before evaluating the frame. +*/ + +static PyObject * +fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk) +{ + PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); + PyObject *globals = PyFunction_GET_GLOBALS(func); + PyObject *argdefs = PyFunction_GET_DEFAULTS(func); + PyObject **d = NULL; + int nd = 0; + + PCALL(PCALL_FUNCTION); + PCALL(PCALL_FAST_FUNCTION); + if (argdefs == NULL && co->co_argcount == n && nk==0 && + co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) { + PyFrameObject *f; + PyObject *retval = NULL; + PyThreadState *tstate = PyThreadState_GET(); + PyObject **fastlocals, **stack; + int i; + + PCALL(PCALL_FASTER_FUNCTION); + assert(globals != NULL); + /* XXX Perhaps we should create a specialized + PyFrame_New() that doesn't take locals, but does + take builtins without sanity checking them. + */ + assert(tstate != NULL); + f = PyFrame_New(tstate, co, globals, NULL); + if (f == NULL) + return NULL; + + fastlocals = f->f_localsplus; + stack = (*pp_stack) - n; + + for (i = 0; i < n; i++) { + Py_INCREF(*stack); + fastlocals[i] = *stack++; + } + retval = PyEval_EvalFrameEx(f,0); + ++tstate->recursion_depth; + Py_DECREF(f); + --tstate->recursion_depth; + return retval; + } + if (argdefs != NULL) { + d = &PyTuple_GET_ITEM(argdefs, 0); + nd = ((PyTupleObject *)argdefs)->ob_size; + } + return PyEval_EvalCodeEx(co, globals, + (PyObject *)NULL, (*pp_stack)-n, na, + (*pp_stack)-2*nk, nk, d, nd, + PyFunction_GET_CLOSURE(func)); +} + +static PyObject * +update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack, + PyObject *func) +{ + PyObject *kwdict = NULL; + if (orig_kwdict == NULL) + kwdict = PyDict_New(); + else { + kwdict = PyDict_Copy(orig_kwdict); + Py_DECREF(orig_kwdict); + } + if (kwdict == NULL) + return NULL; + while (--nk >= 0) { + int err; + PyObject *value = EXT_POP(*pp_stack); + PyObject *key = EXT_POP(*pp_stack); + if (PyDict_GetItem(kwdict, key) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s%s got multiple values " + "for keyword argument '%.200s'", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func), + PyString_AsString(key)); + Py_DECREF(key); + Py_DECREF(value); + Py_DECREF(kwdict); + return NULL; + } + err = PyDict_SetItem(kwdict, key, value); + Py_DECREF(key); + Py_DECREF(value); + if (err) { + Py_DECREF(kwdict); + return NULL; + } + } + return kwdict; +} + +static PyObject * +update_star_args(int nstack, int nstar, PyObject *stararg, + PyObject ***pp_stack) +{ + PyObject *callargs, *w; + + callargs = PyTuple_New(nstack + nstar); + if (callargs == NULL) { + return NULL; + } + if (nstar) { + int i; + for (i = 0; i < nstar; i++) { + PyObject *a = PyTuple_GET_ITEM(stararg, i); + Py_INCREF(a); + PyTuple_SET_ITEM(callargs, nstack + i, a); + } + } + while (--nstack >= 0) { + w = EXT_POP(*pp_stack); + PyTuple_SET_ITEM(callargs, nstack, w); + } + return callargs; +} + +static PyObject * +load_args(PyObject ***pp_stack, int na) +{ + PyObject *args = PyTuple_New(na); + PyObject *w; + + if (args == NULL) + return NULL; + while (--na >= 0) { + w = EXT_POP(*pp_stack); + PyTuple_SET_ITEM(args, na, w); + } + return args; +} + +static PyObject * +do_call(PyObject *func, PyObject ***pp_stack, int na, int nk) +{ + PyObject *callargs = NULL; + PyObject *kwdict = NULL; + PyObject *result = NULL; + + if (nk > 0) { + kwdict = update_keyword_args(NULL, nk, pp_stack, func); + if (kwdict == NULL) + goto call_fail; + } + callargs = load_args(pp_stack, na); + if (callargs == NULL) + goto call_fail; +#ifdef CALL_PROFILE + /* At this point, we have to look at the type of func to + update the call stats properly. Do it here so as to avoid + exposing the call stats machinery outside ceval.c + */ + if (PyFunction_Check(func)) + PCALL(PCALL_FUNCTION); + else if (PyMethod_Check(func)) + PCALL(PCALL_METHOD); + else if (PyType_Check(func)) + PCALL(PCALL_TYPE); + else + PCALL(PCALL_OTHER); +#endif + result = PyObject_Call(func, callargs, kwdict); + call_fail: + Py_XDECREF(callargs); + Py_XDECREF(kwdict); + return result; +} + +static PyObject * +ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk) +{ + int nstar = 0; + PyObject *callargs = NULL; + PyObject *stararg = NULL; + PyObject *kwdict = NULL; + PyObject *result = NULL; + + if (flags & CALL_FLAG_KW) { + kwdict = EXT_POP(*pp_stack); + if (!(kwdict && PyDict_Check(kwdict))) { + PyErr_Format(PyExc_TypeError, + "%s%s argument after ** " + "must be a dictionary", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func)); + goto ext_call_fail; + } + } + if (flags & CALL_FLAG_VAR) { + stararg = EXT_POP(*pp_stack); + if (!PyTuple_Check(stararg)) { + PyObject *t = NULL; + t = PySequence_Tuple(stararg); + if (t == NULL) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Format(PyExc_TypeError, + "%s%s argument after * " + "must be a sequence", + PyEval_GetFuncName(func), + PyEval_GetFuncDesc(func)); + } + goto ext_call_fail; + } + Py_DECREF(stararg); + stararg = t; + } + nstar = PyTuple_GET_SIZE(stararg); + } + if (nk > 0) { + kwdict = update_keyword_args(kwdict, nk, pp_stack, func); + if (kwdict == NULL) + goto ext_call_fail; + } + callargs = update_star_args(na, nstar, stararg, pp_stack); + if (callargs == NULL) + goto ext_call_fail; +#ifdef CALL_PROFILE + /* At this point, we have to look at the type of func to + update the call stats properly. Do it here so as to avoid + exposing the call stats machinery outside ceval.c + */ + if (PyFunction_Check(func)) + PCALL(PCALL_FUNCTION); + else if (PyMethod_Check(func)) + PCALL(PCALL_METHOD); + else if (PyType_Check(func)) + PCALL(PCALL_TYPE); + else + PCALL(PCALL_OTHER); +#endif + result = PyObject_Call(func, callargs, kwdict); + ext_call_fail: + Py_XDECREF(callargs); + Py_XDECREF(kwdict); + Py_XDECREF(stararg); + return result; +} + +/* Extract a slice index from a PyInt or PyLong or an object with the + nb_index slot defined, and store in *pi. + Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, + and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1. + Return 0 on error, 1 on success. +*/ +/* Note: If v is NULL, return success without storing into *pi. This + is because_PyEval_SliceIndex() is called by apply_slice(), which can be + called by the SLICE opcode with v and/or w equal to NULL. +*/ +int +_PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi) +{ + if (v != NULL) { + Py_ssize_t x; + if (PyInt_Check(v)) { + /* XXX(nnorwitz): I think PyInt_AS_LONG is correct, + however, it looks like it should be AsSsize_t. + There should be a comment here explaining why. + */ + x = PyInt_AS_LONG(v); + } + else if (PyIndex_Check(v)) { + x = PyNumber_AsSsize_t(v, NULL); + if (x == -1 && PyErr_Occurred()) + return 0; + } + else { + PyErr_SetString(PyExc_TypeError, + "slice indices must be integers or " + "None or have an __index__ method"); + return 0; + } + *pi = x; + } + return 1; +} + +#undef ISINDEX +#define ISINDEX(x) ((x) == NULL || \ + PyInt_Check(x) || PyLong_Check(x) || PyIndex_Check(x)) + +static PyObject * +apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ +{ + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { + Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; + if (!_PyEval_SliceIndex(v, &ilow)) + return NULL; + if (!_PyEval_SliceIndex(w, &ihigh)) + return NULL; + return PySequence_GetSlice(u, ilow, ihigh); + } + else { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + PyObject *res = PyObject_GetItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return NULL; + } +} + +static int +assign_slice(PyObject *u, PyObject *v, PyObject *w, PyObject *x) + /* u[v:w] = x */ +{ + PyTypeObject *tp = u->ob_type; + PySequenceMethods *sq = tp->tp_as_sequence; + + if (sq && sq->sq_ass_slice && ISINDEX(v) && ISINDEX(w)) { + Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; + if (!_PyEval_SliceIndex(v, &ilow)) + return -1; + if (!_PyEval_SliceIndex(w, &ihigh)) + return -1; + if (x == NULL) + return PySequence_DelSlice(u, ilow, ihigh); + else + return PySequence_SetSlice(u, ilow, ihigh, x); + } + else { + PyObject *slice = PySlice_New(v, w, NULL); + if (slice != NULL) { + int res; + if (x != NULL) + res = PyObject_SetItem(u, slice, x); + else + res = PyObject_DelItem(u, slice); + Py_DECREF(slice); + return res; + } + else + return -1; + } +} + +static PyObject * +cmp_outcome(int op, register PyObject *v, register PyObject *w) +{ + int res = 0; + switch (op) { + case PyCmp_IS: + res = (v == w); + break; + case PyCmp_IS_NOT: + res = (v != w); + break; + case PyCmp_IN: + res = PySequence_Contains(w, v); + if (res < 0) + return NULL; + break; + case PyCmp_NOT_IN: + res = PySequence_Contains(w, v); + if (res < 0) + return NULL; + res = !res; + break; + case PyCmp_EXC_MATCH: + res = PyErr_GivenExceptionMatches(v, w); + break; + default: + return PyObject_RichCompare(v, w, op); + } + v = res ? Py_True : Py_False; + Py_INCREF(v); + return v; +} + +static PyObject * +import_from(PyObject *v, PyObject *name) +{ + PyObject *x; + + x = PyObject_GetAttr(v, name); + if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Format(PyExc_ImportError, + "cannot import name %.230s", + PyString_AsString(name)); + } + return x; +} + +static int +import_all_from(PyObject *locals, PyObject *v) +{ + PyObject *all = PyObject_GetAttrString(v, "__all__"); + PyObject *dict, *name, *value; + int skip_leading_underscores = 0; + int pos, err; + + if (all == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; /* Unexpected error */ + PyErr_Clear(); + dict = PyObject_GetAttrString(v, "__dict__"); + if (dict == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_SetString(PyExc_ImportError, + "from-import-* object has no __dict__ and no __all__"); + return -1; + } + all = PyMapping_Keys(dict); + Py_DECREF(dict); + if (all == NULL) + return -1; + skip_leading_underscores = 1; + } + + for (pos = 0, err = 0; ; pos++) { + name = PySequence_GetItem(all, pos); + if (name == NULL) { + if (!PyErr_ExceptionMatches(PyExc_IndexError)) + err = -1; + else + PyErr_Clear(); + break; + } + if (skip_leading_underscores && + PyString_Check(name) && + PyString_AS_STRING(name)[0] == '_') + { + Py_DECREF(name); + continue; + } + value = PyObject_GetAttr(v, name); + if (value == NULL) + err = -1; + else if (PyDict_CheckExact(locals)) + err = PyDict_SetItem(locals, name, value); + else + err = PyObject_SetItem(locals, name, value); + Py_DECREF(name); + Py_XDECREF(value); + if (err != 0) + break; + } + Py_DECREF(all); + return err; +} + +static PyObject * +build_class(PyObject *methods, PyObject *bases, PyObject *name) +{ + PyObject *metaclass = NULL, *result, *base; + + if (PyDict_Check(methods)) + metaclass = PyDict_GetItemString(methods, "__metaclass__"); + if (metaclass != NULL) + Py_INCREF(metaclass); + else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) { + base = PyTuple_GET_ITEM(bases, 0); + metaclass = PyObject_GetAttrString(base, "__class__"); + if (metaclass == NULL) { + PyErr_Clear(); + metaclass = (PyObject *)base->ob_type; + Py_INCREF(metaclass); + } + } + else { + PyObject *g = PyEval_GetGlobals(); + if (g != NULL && PyDict_Check(g)) + metaclass = PyDict_GetItemString(g, "__metaclass__"); + if (metaclass == NULL) + metaclass = (PyObject *) &PyClass_Type; + Py_INCREF(metaclass); + } + result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, NULL); + Py_DECREF(metaclass); + if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + /* A type error here likely means that the user passed + in a base that was not a class (such the random module + instead of the random.random type). Help them out with + by augmenting the error message with more information.*/ + + PyObject *ptype, *pvalue, *ptraceback; + + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + if (PyString_Check(pvalue)) { + PyObject *newmsg; + newmsg = PyString_FromFormat( + "Error when calling the metaclass bases\n %s", + PyString_AS_STRING(pvalue)); + if (newmsg != NULL) { + Py_DECREF(pvalue); + pvalue = newmsg; + } + } + PyErr_Restore(ptype, pvalue, ptraceback); + } + return result; +} + +static int +exec_statement(PyFrameObject *f, PyObject *prog, PyObject *globals, + PyObject *locals) +{ + int n; + PyObject *v; + int plain = 0; + + if (PyTuple_Check(prog) && globals == Py_None && locals == Py_None && + ((n = PyTuple_Size(prog)) == 2 || n == 3)) { + /* Backward compatibility hack */ + globals = PyTuple_GetItem(prog, 1); + if (n == 3) + locals = PyTuple_GetItem(prog, 2); + prog = PyTuple_GetItem(prog, 0); + } + if (globals == Py_None) { + globals = PyEval_GetGlobals(); + if (locals == Py_None) { + locals = PyEval_GetLocals(); + plain = 1; + } + if (!globals || !locals) { + PyErr_SetString(PyExc_SystemError, + "globals and locals cannot be NULL"); + return -1; + } + } + else if (locals == Py_None) + locals = globals; + if (!PyString_Check(prog) && + !PyUnicode_Check(prog) && + !PyCode_Check(prog) && + !PyFile_Check(prog)) { + PyErr_SetString(PyExc_TypeError, + "exec: arg 1 must be a string, file, or code object"); + return -1; + } + if (!PyDict_Check(globals)) { + PyErr_SetString(PyExc_TypeError, + "exec: arg 2 must be a dictionary or None"); + return -1; + } + if (!PyMapping_Check(locals)) { + PyErr_SetString(PyExc_TypeError, + "exec: arg 3 must be a mapping or None"); + return -1; + } + if (PyDict_GetItemString(globals, "__builtins__") == NULL) + PyDict_SetItemString(globals, "__builtins__", f->f_builtins); + if (PyCode_Check(prog)) { + if (PyCode_GetNumFree((PyCodeObject *)prog) > 0) { + PyErr_SetString(PyExc_TypeError, + "code object passed to exec may not contain free variables"); + return -1; + } + v = PyEval_EvalCode((PyCodeObject *) prog, globals, locals); + } + else if (PyFile_Check(prog)) { + FILE *fp = PyFile_AsFile(prog); + char *name = PyString_AsString(PyFile_Name(prog)); + PyCompilerFlags cf; + if (name == NULL) + return -1; + cf.cf_flags = 0; + if (PyEval_MergeCompilerFlags(&cf)) + v = PyRun_FileFlags(fp, name, Py_file_input, globals, + locals, &cf); + else + v = PyRun_File(fp, name, Py_file_input, globals, + locals); + } + else { + PyObject *tmp = NULL; + char *str; + PyCompilerFlags cf; + cf.cf_flags = 0; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(prog)) { + tmp = PyUnicode_AsUTF8String(prog); + if (tmp == NULL) + return -1; + prog = tmp; + cf.cf_flags |= PyCF_SOURCE_IS_UTF8; + } +#endif + if (PyString_AsStringAndSize(prog, &str, NULL)) + return -1; + if (PyEval_MergeCompilerFlags(&cf)) + v = PyRun_StringFlags(str, Py_file_input, globals, + locals, &cf); + else + v = PyRun_String(str, Py_file_input, globals, locals); + Py_XDECREF(tmp); + } + if (plain) + PyFrame_LocalsToFast(f, 0); + if (v == NULL) + return -1; + Py_DECREF(v); + return 0; +} + +static void +format_exc_check_arg(PyObject *exc, char *format_str, PyObject *obj) +{ + char *obj_str; + + if (!obj) + return; + + obj_str = PyString_AsString(obj); + if (!obj_str) + return; + + PyErr_Format(exc, format_str, obj_str); +} + +static PyObject * +string_concatenate(PyObject *v, PyObject *w, + PyFrameObject *f, unsigned char *next_instr) +{ + /* This function implements 'variable += expr' when both arguments + are strings. */ + Py_ssize_t v_len = PyString_GET_SIZE(v); + Py_ssize_t w_len = PyString_GET_SIZE(w); + Py_ssize_t new_len = v_len + w_len; + if (new_len < 0) { + PyErr_SetString(PyExc_OverflowError, + "strings are too large to concat"); + return NULL; + } + + if (v->ob_refcnt == 2) { + /* In the common case, there are 2 references to the value + * stored in 'variable' when the += is performed: one on the + * value stack (in 'v') and one still stored in the 'variable'. + * We try to delete the variable now to reduce the refcnt to 1. + */ + switch (*next_instr) { + case STORE_FAST: + { + int oparg = PEEKARG(); + PyObject **fastlocals = f->f_localsplus; + if (GETLOCAL(oparg) == v) + SETLOCAL(oparg, NULL); + break; + } + case STORE_DEREF: + { + PyObject **freevars = f->f_localsplus + f->f_code->co_nlocals; + PyObject *c = freevars[PEEKARG()]; + if (PyCell_GET(c) == v) + PyCell_Set(c, NULL); + break; + } + case STORE_NAME: + { + PyObject *names = f->f_code->co_names; + PyObject *name = GETITEM(names, PEEKARG()); + PyObject *locals = f->f_locals; + if (PyDict_CheckExact(locals) && + PyDict_GetItem(locals, name) == v) { + if (PyDict_DelItem(locals, name) != 0) { + PyErr_Clear(); + } + } + break; + } + } + } + + if (v->ob_refcnt == 1 && !PyString_CHECK_INTERNED(v)) { + /* Now we own the last reference to 'v', so we can resize it + * in-place. + */ + if (_PyString_Resize(&v, new_len) != 0) { + /* XXX if _PyString_Resize() fails, 'v' has been + * deallocated so it cannot be put back into 'variable'. + * The MemoryError is raised when there is no value in + * 'variable', which might (very remotely) be a cause + * of incompatibilities. + */ + return NULL; + } + /* copy 'w' into the newly allocated area of 'v' */ + memcpy(PyString_AS_STRING(v) + v_len, + PyString_AS_STRING(w), w_len); + return v; + } + else { + /* When in-place resizing is not an option. */ + PyString_Concat(&v, w); + return v; + } +} + +#ifdef DYNAMIC_EXECUTION_PROFILE + +static PyObject * +getarray(long a[256]) +{ + int i; + PyObject *l = PyList_New(256); + if (l == NULL) return NULL; + for (i = 0; i < 256; i++) { + PyObject *x = PyInt_FromLong(a[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + for (i = 0; i < 256; i++) + a[i] = 0; + return l; +} + +PyObject * +_Py_GetDXProfile(PyObject *self, PyObject *args) +{ +#ifndef DXPAIRS + return getarray(dxp); +#else + int i; + PyObject *l = PyList_New(257); + if (l == NULL) return NULL; + for (i = 0; i < 257; i++) { + PyObject *x = getarray(dxpairs[i]); + if (x == NULL) { + Py_DECREF(l); + return NULL; + } + PyList_SetItem(l, i, x); + } + return l; +#endif +} + +#endif diff --git a/sys/src/cmd/python/Python/codecs.c b/sys/src/cmd/python/Python/codecs.c new file mode 100644 index 000000000..4b0f4cb0d --- /dev/null +++ b/sys/src/cmd/python/Python/codecs.c @@ -0,0 +1,860 @@ +/* ------------------------------------------------------------------------ + + Python Codec Registry and support functions + +Written by Marc-Andre Lemburg (mal@lemburg.com). + +Copyright (c) Corporation for National Research Initiatives. + + ------------------------------------------------------------------------ */ + +#include "Python.h" +#include <ctype.h> + +/* --- Codec Registry ----------------------------------------------------- */ + +/* Import the standard encodings package which will register the first + codec search function. + + This is done in a lazy way so that the Unicode implementation does + not downgrade startup time of scripts not needing it. + + ImportErrors are silently ignored by this function. Only one try is + made. + +*/ + +static int _PyCodecRegistry_Init(void); /* Forward */ + +int PyCodec_Register(PyObject *search_function) +{ + PyInterpreterState *interp = PyThreadState_GET()->interp; + if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) + goto onError; + if (search_function == NULL) { + PyErr_BadArgument(); + goto onError; + } + if (!PyCallable_Check(search_function)) { + PyErr_SetString(PyExc_TypeError, "argument must be callable"); + goto onError; + } + return PyList_Append(interp->codec_search_path, search_function); + + onError: + return -1; +} + +/* Convert a string to a normalized Python string: all characters are + converted to lower case, spaces are replaced with underscores. */ + +static +PyObject *normalizestring(const char *string) +{ + register size_t i; + size_t len = strlen(string); + char *p; + PyObject *v; + + if (len > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, "string is too large"); + return NULL; + } + + v = PyString_FromStringAndSize(NULL, len); + if (v == NULL) + return NULL; + p = PyString_AS_STRING(v); + for (i = 0; i < len; i++) { + register char ch = string[i]; + if (ch == ' ') + ch = '-'; + else + ch = tolower(Py_CHARMASK(ch)); + p[i] = ch; + } + return v; +} + +/* Lookup the given encoding and return a tuple providing the codec + facilities. + + The encoding string is looked up converted to all lower-case + characters. This makes encodings looked up through this mechanism + effectively case-insensitive. + + If no codec is found, a LookupError is set and NULL returned. + + As side effect, this tries to load the encodings package, if not + yet done. This is part of the lazy load strategy for the encodings + package. + +*/ + +PyObject *_PyCodec_Lookup(const char *encoding) +{ + PyInterpreterState *interp; + PyObject *result, *args = NULL, *v; + Py_ssize_t i, len; + + if (encoding == NULL) { + PyErr_BadArgument(); + goto onError; + } + + interp = PyThreadState_GET()->interp; + if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) + goto onError; + + /* Convert the encoding to a normalized Python string: all + characters are converted to lower case, spaces and hyphens are + replaced with underscores. */ + v = normalizestring(encoding); + if (v == NULL) + goto onError; + PyString_InternInPlace(&v); + + /* First, try to lookup the name in the registry dictionary */ + result = PyDict_GetItem(interp->codec_search_cache, v); + if (result != NULL) { + Py_INCREF(result); + Py_DECREF(v); + return result; + } + + /* Next, scan the search functions in order of registration */ + args = PyTuple_New(1); + if (args == NULL) + goto onError; + PyTuple_SET_ITEM(args,0,v); + + len = PyList_Size(interp->codec_search_path); + if (len < 0) + goto onError; + if (len == 0) { + PyErr_SetString(PyExc_LookupError, + "no codec search functions registered: " + "can't find encoding"); + goto onError; + } + + for (i = 0; i < len; i++) { + PyObject *func; + + func = PyList_GetItem(interp->codec_search_path, i); + if (func == NULL) + goto onError; + result = PyEval_CallObject(func, args); + if (result == NULL) + goto onError; + if (result == Py_None) { + Py_DECREF(result); + continue; + } + if (!PyTuple_Check(result) || PyTuple_GET_SIZE(result) != 4) { + PyErr_SetString(PyExc_TypeError, + "codec search functions must return 4-tuples"); + Py_DECREF(result); + goto onError; + } + break; + } + if (i == len) { + /* XXX Perhaps we should cache misses too ? */ + PyErr_Format(PyExc_LookupError, + "unknown encoding: %s", encoding); + goto onError; + } + + /* Cache and return the result */ + PyDict_SetItem(interp->codec_search_cache, v, result); + Py_DECREF(args); + return result; + + onError: + Py_XDECREF(args); + return NULL; +} + +static +PyObject *args_tuple(PyObject *object, + const char *errors) +{ + PyObject *args; + + args = PyTuple_New(1 + (errors != NULL)); + if (args == NULL) + return NULL; + Py_INCREF(object); + PyTuple_SET_ITEM(args,0,object); + if (errors) { + PyObject *v; + + v = PyString_FromString(errors); + if (v == NULL) { + Py_DECREF(args); + return NULL; + } + PyTuple_SET_ITEM(args, 1, v); + } + return args; +} + +/* Helper function to get a codec item */ + +static +PyObject *codec_getitem(const char *encoding, int index) +{ + PyObject *codecs; + PyObject *v; + + codecs = _PyCodec_Lookup(encoding); + if (codecs == NULL) + return NULL; + v = PyTuple_GET_ITEM(codecs, index); + Py_DECREF(codecs); + Py_INCREF(v); + return v; +} + +/* Helper function to create an incremental codec. */ + +static +PyObject *codec_getincrementalcodec(const char *encoding, + const char *errors, + const char *attrname) +{ + PyObject *codecs, *ret, *inccodec; + + codecs = _PyCodec_Lookup(encoding); + if (codecs == NULL) + return NULL; + inccodec = PyObject_GetAttrString(codecs, attrname); + Py_DECREF(codecs); + if (inccodec == NULL) + return NULL; + if (errors) + ret = PyObject_CallFunction(inccodec, "s", errors); + else + ret = PyObject_CallFunction(inccodec, NULL); + Py_DECREF(inccodec); + return ret; +} + +/* Helper function to create a stream codec. */ + +static +PyObject *codec_getstreamcodec(const char *encoding, + PyObject *stream, + const char *errors, + const int index) +{ + PyObject *codecs, *streamcodec, *codeccls; + + codecs = _PyCodec_Lookup(encoding); + if (codecs == NULL) + return NULL; + + codeccls = PyTuple_GET_ITEM(codecs, index); + if (errors != NULL) + streamcodec = PyObject_CallFunction(codeccls, "Os", stream, errors); + else + streamcodec = PyObject_CallFunction(codeccls, "O", stream); + Py_DECREF(codecs); + return streamcodec; +} + +/* Convenience APIs to query the Codec registry. + + All APIs return a codec object with incremented refcount. + + */ + +PyObject *PyCodec_Encoder(const char *encoding) +{ + return codec_getitem(encoding, 0); +} + +PyObject *PyCodec_Decoder(const char *encoding) +{ + return codec_getitem(encoding, 1); +} + +PyObject *PyCodec_IncrementalEncoder(const char *encoding, + const char *errors) +{ + return codec_getincrementalcodec(encoding, errors, "incrementalencoder"); +} + +PyObject *PyCodec_IncrementalDecoder(const char *encoding, + const char *errors) +{ + return codec_getincrementalcodec(encoding, errors, "incrementaldecoder"); +} + +PyObject *PyCodec_StreamReader(const char *encoding, + PyObject *stream, + const char *errors) +{ + return codec_getstreamcodec(encoding, stream, errors, 2); +} + +PyObject *PyCodec_StreamWriter(const char *encoding, + PyObject *stream, + const char *errors) +{ + return codec_getstreamcodec(encoding, stream, errors, 3); +} + +/* Encode an object (e.g. an Unicode object) using the given encoding + and return the resulting encoded object (usually a Python string). + + errors is passed to the encoder factory as argument if non-NULL. */ + +PyObject *PyCodec_Encode(PyObject *object, + const char *encoding, + const char *errors) +{ + PyObject *encoder = NULL; + PyObject *args = NULL, *result = NULL; + PyObject *v; + + encoder = PyCodec_Encoder(encoding); + if (encoder == NULL) + goto onError; + + args = args_tuple(object, errors); + if (args == NULL) + goto onError; + + result = PyEval_CallObject(encoder,args); + if (result == NULL) + goto onError; + + if (!PyTuple_Check(result) || + PyTuple_GET_SIZE(result) != 2) { + PyErr_SetString(PyExc_TypeError, + "encoder must return a tuple (object,integer)"); + goto onError; + } + v = PyTuple_GET_ITEM(result,0); + Py_INCREF(v); + /* We don't check or use the second (integer) entry. */ + + Py_DECREF(args); + Py_DECREF(encoder); + Py_DECREF(result); + return v; + + onError: + Py_XDECREF(result); + Py_XDECREF(args); + Py_XDECREF(encoder); + return NULL; +} + +/* Decode an object (usually a Python string) using the given encoding + and return an equivalent object (e.g. an Unicode object). + + errors is passed to the decoder factory as argument if non-NULL. */ + +PyObject *PyCodec_Decode(PyObject *object, + const char *encoding, + const char *errors) +{ + PyObject *decoder = NULL; + PyObject *args = NULL, *result = NULL; + PyObject *v; + + decoder = PyCodec_Decoder(encoding); + if (decoder == NULL) + goto onError; + + args = args_tuple(object, errors); + if (args == NULL) + goto onError; + + result = PyEval_CallObject(decoder,args); + if (result == NULL) + goto onError; + if (!PyTuple_Check(result) || + PyTuple_GET_SIZE(result) != 2) { + PyErr_SetString(PyExc_TypeError, + "decoder must return a tuple (object,integer)"); + goto onError; + } + v = PyTuple_GET_ITEM(result,0); + Py_INCREF(v); + /* We don't check or use the second (integer) entry. */ + + Py_DECREF(args); + Py_DECREF(decoder); + Py_DECREF(result); + return v; + + onError: + Py_XDECREF(args); + Py_XDECREF(decoder); + Py_XDECREF(result); + return NULL; +} + +/* Register the error handling callback function error under the name + name. This function will be called by the codec when it encounters + an unencodable characters/undecodable bytes and doesn't know the + callback name, when name is specified as the error parameter + in the call to the encode/decode function. + Return 0 on success, -1 on error */ +int PyCodec_RegisterError(const char *name, PyObject *error) +{ + PyInterpreterState *interp = PyThreadState_GET()->interp; + if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) + return -1; + if (!PyCallable_Check(error)) { + PyErr_SetString(PyExc_TypeError, "handler must be callable"); + return -1; + } + return PyDict_SetItemString(interp->codec_error_registry, + (char *)name, error); +} + +/* Lookup the error handling callback function registered under the + name error. As a special case NULL can be passed, in which case + the error handling callback for strict encoding will be returned. */ +PyObject *PyCodec_LookupError(const char *name) +{ + PyObject *handler = NULL; + + PyInterpreterState *interp = PyThreadState_GET()->interp; + if (interp->codec_search_path == NULL && _PyCodecRegistry_Init()) + return NULL; + + if (name==NULL) + name = "strict"; + handler = PyDict_GetItemString(interp->codec_error_registry, (char *)name); + if (!handler) + PyErr_Format(PyExc_LookupError, "unknown error handler name '%.400s'", name); + else + Py_INCREF(handler); + return handler; +} + +static void wrong_exception_type(PyObject *exc) +{ + PyObject *type = PyObject_GetAttrString(exc, "__class__"); + if (type != NULL) { + PyObject *name = PyObject_GetAttrString(type, "__name__"); + Py_DECREF(type); + if (name != NULL) { + PyObject *string = PyObject_Str(name); + Py_DECREF(name); + if (string != NULL) { + PyErr_Format(PyExc_TypeError, + "don't know how to handle %.400s in error callback", + PyString_AS_STRING(string)); + Py_DECREF(string); + } + } + } +} + +PyObject *PyCodec_StrictErrors(PyObject *exc) +{ + if (PyExceptionInstance_Check(exc)) + PyErr_SetObject(PyExceptionInstance_Class(exc), exc); + else + PyErr_SetString(PyExc_TypeError, "codec must pass exception instance"); + return NULL; +} + + +#ifdef Py_USING_UNICODE +PyObject *PyCodec_IgnoreErrors(PyObject *exc) +{ + Py_ssize_t end; + if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) { + if (PyUnicodeEncodeError_GetEnd(exc, &end)) + return NULL; + } + else if (PyObject_IsInstance(exc, PyExc_UnicodeDecodeError)) { + if (PyUnicodeDecodeError_GetEnd(exc, &end)) + return NULL; + } + else if (PyObject_IsInstance(exc, PyExc_UnicodeTranslateError)) { + if (PyUnicodeTranslateError_GetEnd(exc, &end)) + return NULL; + } + else { + wrong_exception_type(exc); + return NULL; + } + /* ouch: passing NULL, 0, pos gives None instead of u'' */ + return Py_BuildValue("(u#n)", &end, 0, end); +} + + +PyObject *PyCodec_ReplaceErrors(PyObject *exc) +{ + PyObject *restuple; + Py_ssize_t start; + Py_ssize_t end; + Py_ssize_t i; + + if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) { + PyObject *res; + Py_UNICODE *p; + if (PyUnicodeEncodeError_GetStart(exc, &start)) + return NULL; + if (PyUnicodeEncodeError_GetEnd(exc, &end)) + return NULL; + res = PyUnicode_FromUnicode(NULL, end-start); + if (res == NULL) + return NULL; + for (p = PyUnicode_AS_UNICODE(res), i = start; + i<end; ++p, ++i) + *p = '?'; + restuple = Py_BuildValue("(On)", res, end); + Py_DECREF(res); + return restuple; + } + else if (PyObject_IsInstance(exc, PyExc_UnicodeDecodeError)) { + Py_UNICODE res = Py_UNICODE_REPLACEMENT_CHARACTER; + if (PyUnicodeDecodeError_GetEnd(exc, &end)) + return NULL; + return Py_BuildValue("(u#n)", &res, 1, end); + } + else if (PyObject_IsInstance(exc, PyExc_UnicodeTranslateError)) { + PyObject *res; + Py_UNICODE *p; + if (PyUnicodeTranslateError_GetStart(exc, &start)) + return NULL; + if (PyUnicodeTranslateError_GetEnd(exc, &end)) + return NULL; + res = PyUnicode_FromUnicode(NULL, end-start); + if (res == NULL) + return NULL; + for (p = PyUnicode_AS_UNICODE(res), i = start; + i<end; ++p, ++i) + *p = Py_UNICODE_REPLACEMENT_CHARACTER; + restuple = Py_BuildValue("(On)", res, end); + Py_DECREF(res); + return restuple; + } + else { + wrong_exception_type(exc); + return NULL; + } +} + +PyObject *PyCodec_XMLCharRefReplaceErrors(PyObject *exc) +{ + if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) { + PyObject *restuple; + PyObject *object; + Py_ssize_t start; + Py_ssize_t end; + PyObject *res; + Py_UNICODE *p; + Py_UNICODE *startp; + Py_UNICODE *outp; + int ressize; + if (PyUnicodeEncodeError_GetStart(exc, &start)) + return NULL; + if (PyUnicodeEncodeError_GetEnd(exc, &end)) + return NULL; + if (!(object = PyUnicodeEncodeError_GetObject(exc))) + return NULL; + startp = PyUnicode_AS_UNICODE(object); + for (p = startp+start, ressize = 0; p < startp+end; ++p) { + if (*p<10) + ressize += 2+1+1; + else if (*p<100) + ressize += 2+2+1; + else if (*p<1000) + ressize += 2+3+1; + else if (*p<10000) + ressize += 2+4+1; +#ifndef Py_UNICODE_WIDE + else + ressize += 2+5+1; +#else + else if (*p<100000) + ressize += 2+5+1; + else if (*p<1000000) + ressize += 2+6+1; + else + ressize += 2+7+1; +#endif + } + /* allocate replacement */ + res = PyUnicode_FromUnicode(NULL, ressize); + if (res == NULL) { + Py_DECREF(object); + return NULL; + } + /* generate replacement */ + for (p = startp+start, outp = PyUnicode_AS_UNICODE(res); + p < startp+end; ++p) { + Py_UNICODE c = *p; + int digits; + int base; + *outp++ = '&'; + *outp++ = '#'; + if (*p<10) { + digits = 1; + base = 1; + } + else if (*p<100) { + digits = 2; + base = 10; + } + else if (*p<1000) { + digits = 3; + base = 100; + } + else if (*p<10000) { + digits = 4; + base = 1000; + } +#ifndef Py_UNICODE_WIDE + else { + digits = 5; + base = 10000; + } +#else + else if (*p<100000) { + digits = 5; + base = 10000; + } + else if (*p<1000000) { + digits = 6; + base = 100000; + } + else { + digits = 7; + base = 1000000; + } +#endif + while (digits-->0) { + *outp++ = '0' + c/base; + c %= base; + base /= 10; + } + *outp++ = ';'; + } + restuple = Py_BuildValue("(On)", res, end); + Py_DECREF(res); + Py_DECREF(object); + return restuple; + } + else { + wrong_exception_type(exc); + return NULL; + } +} + +static Py_UNICODE hexdigits[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' +}; + +PyObject *PyCodec_BackslashReplaceErrors(PyObject *exc) +{ + if (PyObject_IsInstance(exc, PyExc_UnicodeEncodeError)) { + PyObject *restuple; + PyObject *object; + Py_ssize_t start; + Py_ssize_t end; + PyObject *res; + Py_UNICODE *p; + Py_UNICODE *startp; + Py_UNICODE *outp; + int ressize; + if (PyUnicodeEncodeError_GetStart(exc, &start)) + return NULL; + if (PyUnicodeEncodeError_GetEnd(exc, &end)) + return NULL; + if (!(object = PyUnicodeEncodeError_GetObject(exc))) + return NULL; + startp = PyUnicode_AS_UNICODE(object); + for (p = startp+start, ressize = 0; p < startp+end; ++p) { +#ifdef Py_UNICODE_WIDE + if (*p >= 0x00010000) + ressize += 1+1+8; + else +#endif + if (*p >= 0x100) { + ressize += 1+1+4; + } + else + ressize += 1+1+2; + } + res = PyUnicode_FromUnicode(NULL, ressize); + if (res==NULL) + return NULL; + for (p = startp+start, outp = PyUnicode_AS_UNICODE(res); + p < startp+end; ++p) { + Py_UNICODE c = *p; + *outp++ = '\\'; +#ifdef Py_UNICODE_WIDE + if (c >= 0x00010000) { + *outp++ = 'U'; + *outp++ = hexdigits[(c>>28)&0xf]; + *outp++ = hexdigits[(c>>24)&0xf]; + *outp++ = hexdigits[(c>>20)&0xf]; + *outp++ = hexdigits[(c>>16)&0xf]; + *outp++ = hexdigits[(c>>12)&0xf]; + *outp++ = hexdigits[(c>>8)&0xf]; + } + else +#endif + if (c >= 0x100) { + *outp++ = 'u'; + *outp++ = hexdigits[(c>>12)&0xf]; + *outp++ = hexdigits[(c>>8)&0xf]; + } + else + *outp++ = 'x'; + *outp++ = hexdigits[(c>>4)&0xf]; + *outp++ = hexdigits[c&0xf]; + } + + restuple = Py_BuildValue("(On)", res, end); + Py_DECREF(res); + Py_DECREF(object); + return restuple; + } + else { + wrong_exception_type(exc); + return NULL; + } +} +#endif + +static PyObject *strict_errors(PyObject *self, PyObject *exc) +{ + return PyCodec_StrictErrors(exc); +} + + +#ifdef Py_USING_UNICODE +static PyObject *ignore_errors(PyObject *self, PyObject *exc) +{ + return PyCodec_IgnoreErrors(exc); +} + + +static PyObject *replace_errors(PyObject *self, PyObject *exc) +{ + return PyCodec_ReplaceErrors(exc); +} + + +static PyObject *xmlcharrefreplace_errors(PyObject *self, PyObject *exc) +{ + return PyCodec_XMLCharRefReplaceErrors(exc); +} + + +static PyObject *backslashreplace_errors(PyObject *self, PyObject *exc) +{ + return PyCodec_BackslashReplaceErrors(exc); +} +#endif + +static int _PyCodecRegistry_Init(void) +{ + static struct { + char *name; + PyMethodDef def; + } methods[] = + { + { + "strict", + { + "strict_errors", + strict_errors, + METH_O + } + }, +#ifdef Py_USING_UNICODE + { + "ignore", + { + "ignore_errors", + ignore_errors, + METH_O + } + }, + { + "replace", + { + "replace_errors", + replace_errors, + METH_O + } + }, + { + "xmlcharrefreplace", + { + "xmlcharrefreplace_errors", + xmlcharrefreplace_errors, + METH_O + } + }, + { + "backslashreplace", + { + "backslashreplace_errors", + backslashreplace_errors, + METH_O + } + } +#endif + }; + + PyInterpreterState *interp = PyThreadState_GET()->interp; + PyObject *mod; + unsigned i; + + if (interp->codec_search_path != NULL) + return 0; + + interp->codec_search_path = PyList_New(0); + interp->codec_search_cache = PyDict_New(); + interp->codec_error_registry = PyDict_New(); + + if (interp->codec_error_registry) { + for (i = 0; i < sizeof(methods)/sizeof(methods[0]); ++i) { + PyObject *func = PyCFunction_New(&methods[i].def, NULL); + int res; + if (!func) + Py_FatalError("can't initialize codec error registry"); + res = PyCodec_RegisterError(methods[i].name, func); + Py_DECREF(func); + if (res) + Py_FatalError("can't initialize codec error registry"); + } + } + + if (interp->codec_search_path == NULL || + interp->codec_search_cache == NULL || + interp->codec_error_registry == NULL) + Py_FatalError("can't initialize codec registry"); + + mod = PyImport_ImportModuleLevel("encodings", NULL, NULL, NULL, 0); + if (mod == NULL) { + if (PyErr_ExceptionMatches(PyExc_ImportError)) { + /* Ignore ImportErrors... this is done so that + distributions can disable the encodings package. Note + that other errors are not masked, e.g. SystemErrors + raised to inform the user of an error in the Python + configuration are still reported back to the user. */ + PyErr_Clear(); + return 0; + } + return -1; + } + Py_DECREF(mod); + return 0; +} diff --git a/sys/src/cmd/python/Python/compile.c b/sys/src/cmd/python/Python/compile.c new file mode 100644 index 000000000..e493beb6c --- /dev/null +++ b/sys/src/cmd/python/Python/compile.c @@ -0,0 +1,4570 @@ +/* + * This file compiles an abstract syntax tree (AST) into Python bytecode. + * + * The primary entry point is PyAST_Compile(), which returns a + * PyCodeObject. The compiler makes several passes to build the code + * object: + * 1. Checks for future statements. See future.c + * 2. Builds a symbol table. See symtable.c. + * 3. Generate code for basic blocks. See compiler_mod() in this file. + * 4. Assemble the basic blocks into final code. See assemble() in + * this file. + * + * Note that compiler_mod() suggests module, but the module ast type + * (mod_ty) has cases for expressions and interactive statements. + * + * CAUTION: The VISIT_* macros abort the current function when they + * encounter a problem. So don't invoke them when there is memory + * which needs to be released. Code blocks are OK, as the compiler + * structure takes care of releasing those. + */ + +#include "Python.h" + +#include "Python-ast.h" +#include "node.h" +#include "pyarena.h" +#include "ast.h" +#include "code.h" +#include "compile.h" +#include "symtable.h" +#include "opcode.h" + +int Py_OptimizeFlag = 0; + +/* + ISSUES: + + opcode_stack_effect() function should be reviewed since stack depth bugs + could be really hard to find later. + + Dead code is being generated (i.e. after unconditional jumps). + XXX(nnorwitz): not sure this is still true +*/ + +#define DEFAULT_BLOCK_SIZE 16 +#define DEFAULT_BLOCKS 8 +#define DEFAULT_CODE_SIZE 128 +#define DEFAULT_LNOTAB_SIZE 16 + +struct instr { + unsigned i_jabs : 1; + unsigned i_jrel : 1; + unsigned i_hasarg : 1; + unsigned char i_opcode; + int i_oparg; + struct basicblock_ *i_target; /* target block (if jump instruction) */ + int i_lineno; +}; + +typedef struct basicblock_ { + /* Each basicblock in a compilation unit is linked via b_list in the + reverse order that the block are allocated. b_list points to the next + block, not to be confused with b_next, which is next by control flow. */ + struct basicblock_ *b_list; + /* number of instructions used */ + int b_iused; + /* length of instruction array (b_instr) */ + int b_ialloc; + /* pointer to an array of instructions, initially NULL */ + struct instr *b_instr; + /* If b_next is non-NULL, it is a pointer to the next + block reached by normal control flow. */ + struct basicblock_ *b_next; + /* b_seen is used to perform a DFS of basicblocks. */ + unsigned b_seen : 1; + /* b_return is true if a RETURN_VALUE opcode is inserted. */ + unsigned b_return : 1; + /* depth of stack upon entry of block, computed by stackdepth() */ + int b_startdepth; + /* instruction offset for block, computed by assemble_jump_offsets() */ + int b_offset; +} basicblock; + +/* fblockinfo tracks the current frame block. + +A frame block is used to handle loops, try/except, and try/finally. +It's called a frame block to distinguish it from a basic block in the +compiler IR. +*/ + +enum fblocktype { LOOP, EXCEPT, FINALLY_TRY, FINALLY_END }; + +struct fblockinfo { + enum fblocktype fb_type; + basicblock *fb_block; +}; + +/* The following items change on entry and exit of code blocks. + They must be saved and restored when returning to a block. +*/ +struct compiler_unit { + PySTEntryObject *u_ste; + + PyObject *u_name; + /* The following fields are dicts that map objects to + the index of them in co_XXX. The index is used as + the argument for opcodes that refer to those collections. + */ + PyObject *u_consts; /* all constants */ + PyObject *u_names; /* all names */ + PyObject *u_varnames; /* local variables */ + PyObject *u_cellvars; /* cell variables */ + PyObject *u_freevars; /* free variables */ + + PyObject *u_private; /* for private name mangling */ + + int u_argcount; /* number of arguments for block */ + /* Pointer to the most recently allocated block. By following b_list + members, you can reach all early allocated blocks. */ + basicblock *u_blocks; + basicblock *u_curblock; /* pointer to current block */ + int u_tmpname; /* temporary variables for list comps */ + + int u_nfblocks; + struct fblockinfo u_fblock[CO_MAXBLOCKS]; + + int u_firstlineno; /* the first lineno of the block */ + int u_lineno; /* the lineno for the current stmt */ + bool u_lineno_set; /* boolean to indicate whether instr + has been generated with current lineno */ +}; + +/* This struct captures the global state of a compilation. + +The u pointer points to the current compilation unit, while units +for enclosing blocks are stored in c_stack. The u and c_stack are +managed by compiler_enter_scope() and compiler_exit_scope(). +*/ + +struct compiler { + const char *c_filename; + struct symtable *c_st; + PyFutureFeatures *c_future; /* pointer to module's __future__ */ + PyCompilerFlags *c_flags; + + int c_interactive; /* true if in interactive mode */ + int c_nestlevel; + + struct compiler_unit *u; /* compiler state for current block */ + PyObject *c_stack; /* Python list holding compiler_unit ptrs */ + char *c_encoding; /* source encoding (a borrowed reference) */ + PyArena *c_arena; /* pointer to memory allocation arena */ +}; + +struct assembler { + PyObject *a_bytecode; /* string containing bytecode */ + int a_offset; /* offset into bytecode */ + int a_nblocks; /* number of reachable blocks */ + basicblock **a_postorder; /* list of blocks in dfs postorder */ + PyObject *a_lnotab; /* string containing lnotab */ + int a_lnotab_off; /* offset into lnotab */ + int a_lineno; /* last lineno of emitted instruction */ + int a_lineno_off; /* bytecode offset of last lineno */ +}; + +static int compiler_enter_scope(struct compiler *, identifier, void *, int); +static void compiler_free(struct compiler *); +static basicblock *compiler_new_block(struct compiler *); +static int compiler_next_instr(struct compiler *, basicblock *); +static int compiler_addop(struct compiler *, int); +static int compiler_addop_o(struct compiler *, int, PyObject *, PyObject *); +static int compiler_addop_i(struct compiler *, int, int); +static int compiler_addop_j(struct compiler *, int, basicblock *, int); +static basicblock *compiler_use_new_block(struct compiler *); +static int compiler_error(struct compiler *, const char *); +static int compiler_nameop(struct compiler *, identifier, expr_context_ty); + +static PyCodeObject *compiler_mod(struct compiler *, mod_ty); +static int compiler_visit_stmt(struct compiler *, stmt_ty); +static int compiler_visit_keyword(struct compiler *, keyword_ty); +static int compiler_visit_expr(struct compiler *, expr_ty); +static int compiler_augassign(struct compiler *, stmt_ty); +static int compiler_visit_slice(struct compiler *, slice_ty, + expr_context_ty); + +static int compiler_push_fblock(struct compiler *, enum fblocktype, + basicblock *); +static void compiler_pop_fblock(struct compiler *, enum fblocktype, + basicblock *); +/* Returns true if there is a loop on the fblock stack. */ +static int compiler_in_loop(struct compiler *); + +static int inplace_binop(struct compiler *, operator_ty); +static int expr_constant(expr_ty e); + +static int compiler_with(struct compiler *, stmt_ty); + +static PyCodeObject *assemble(struct compiler *, int addNone); +static PyObject *__doc__; + +PyObject * +_Py_Mangle(PyObject *privateobj, PyObject *ident) +{ + /* Name mangling: __private becomes _classname__private. + This is independent from how the name is used. */ + const char *p, *name = PyString_AsString(ident); + char *buffer; + size_t nlen, plen; + if (privateobj == NULL || !PyString_Check(privateobj) || + name == NULL || name[0] != '_' || name[1] != '_') { + Py_INCREF(ident); + return ident; + } + p = PyString_AsString(privateobj); + nlen = strlen(name); + if (name[nlen-1] == '_' && name[nlen-2] == '_') { + Py_INCREF(ident); + return ident; /* Don't mangle __whatever__ */ + } + /* Strip leading underscores from class name */ + while (*p == '_') + p++; + if (*p == '\0') { + Py_INCREF(ident); + return ident; /* Don't mangle if class is just underscores */ + } + plen = strlen(p); + ident = PyString_FromStringAndSize(NULL, 1 + nlen + plen); + if (!ident) + return 0; + /* ident = "_" + p[:plen] + name # i.e. 1+plen+nlen bytes */ + buffer = PyString_AS_STRING(ident); + buffer[0] = '_'; + strncpy(buffer+1, p, plen); + strcpy(buffer+1+plen, name); + return ident; +} + +static int +compiler_init(struct compiler *c) +{ + memset(c, 0, sizeof(struct compiler)); + + c->c_stack = PyList_New(0); + if (!c->c_stack) + return 0; + + return 1; +} + +PyCodeObject * +PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, + PyArena *arena) +{ + struct compiler c; + PyCodeObject *co = NULL; + PyCompilerFlags local_flags; + int merged; + + if (!__doc__) { + __doc__ = PyString_InternFromString("__doc__"); + if (!__doc__) + return NULL; + } + + if (!compiler_init(&c)) + return NULL; + c.c_filename = filename; + c.c_arena = arena; + c.c_future = PyFuture_FromAST(mod, filename); + if (c.c_future == NULL) + goto finally; + if (!flags) { + local_flags.cf_flags = 0; + flags = &local_flags; + } + merged = c.c_future->ff_features | flags->cf_flags; + c.c_future->ff_features = merged; + flags->cf_flags = merged; + c.c_flags = flags; + c.c_nestlevel = 0; + + c.c_st = PySymtable_Build(mod, filename, c.c_future); + if (c.c_st == NULL) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_SystemError, "no symtable"); + goto finally; + } + + /* XXX initialize to NULL for now, need to handle */ + c.c_encoding = NULL; + + co = compiler_mod(&c, mod); + + finally: + compiler_free(&c); + assert(co || PyErr_Occurred()); + return co; +} + +PyCodeObject * +PyNode_Compile(struct _node *n, const char *filename) +{ + PyCodeObject *co = NULL; + mod_ty mod; + PyArena *arena = PyArena_New(); + if (!arena) + return NULL; + mod = PyAST_FromNode(n, NULL, filename, arena); + if (mod) + co = PyAST_Compile(mod, filename, NULL, arena); + PyArena_Free(arena); + return co; +} + +static void +compiler_free(struct compiler *c) +{ + if (c->c_st) + PySymtable_Free(c->c_st); + if (c->c_future) + PyObject_Free(c->c_future); + Py_DECREF(c->c_stack); +} + +static PyObject * +list2dict(PyObject *list) +{ + Py_ssize_t i, n; + PyObject *v, *k; + PyObject *dict = PyDict_New(); + if (!dict) return NULL; + + n = PyList_Size(list); + for (i = 0; i < n; i++) { + v = PyInt_FromLong(i); + if (!v) { + Py_DECREF(dict); + return NULL; + } + k = PyList_GET_ITEM(list, i); + k = PyTuple_Pack(2, k, k->ob_type); + if (k == NULL || PyDict_SetItem(dict, k, v) < 0) { + Py_XDECREF(k); + Py_DECREF(v); + Py_DECREF(dict); + return NULL; + } + Py_DECREF(k); + Py_DECREF(v); + } + return dict; +} + +/* Return new dict containing names from src that match scope(s). + +src is a symbol table dictionary. If the scope of a name matches +either scope_type or flag is set, insert it into the new dict. The +values are integers, starting at offset and increasing by one for +each key. +*/ + +static PyObject * +dictbytype(PyObject *src, int scope_type, int flag, int offset) +{ + Py_ssize_t pos = 0, i = offset, scope; + PyObject *k, *v, *dest = PyDict_New(); + + assert(offset >= 0); + if (dest == NULL) + return NULL; + + while (PyDict_Next(src, &pos, &k, &v)) { + /* XXX this should probably be a macro in symtable.h */ + assert(PyInt_Check(v)); + scope = (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK; + + if (scope == scope_type || PyInt_AS_LONG(v) & flag) { + PyObject *tuple, *item = PyInt_FromLong(i); + if (item == NULL) { + Py_DECREF(dest); + return NULL; + } + i++; + tuple = PyTuple_Pack(2, k, k->ob_type); + if (!tuple || PyDict_SetItem(dest, tuple, item) < 0) { + Py_DECREF(item); + Py_DECREF(dest); + Py_XDECREF(tuple); + return NULL; + } + Py_DECREF(item); + Py_DECREF(tuple); + } + } + return dest; +} + +/* Begin: Peephole optimizations ----------------------------------------- */ + +#define GETARG(arr, i) ((int)((arr[i+2]<<8) + arr[i+1])) +#define UNCONDITIONAL_JUMP(op) (op==JUMP_ABSOLUTE || op==JUMP_FORWARD) +#define ABSOLUTE_JUMP(op) (op==JUMP_ABSOLUTE || op==CONTINUE_LOOP) +#define GETJUMPTGT(arr, i) (GETARG(arr,i) + (ABSOLUTE_JUMP(arr[i]) ? 0 : i+3)) +#define SETARG(arr, i, val) arr[i+2] = val>>8; arr[i+1] = val & 255 +#define CODESIZE(op) (HAS_ARG(op) ? 3 : 1) +#define ISBASICBLOCK(blocks, start, bytes) \ + (blocks[start]==blocks[start+bytes-1]) + +/* Replace LOAD_CONST c1. LOAD_CONST c2 ... LOAD_CONST cn BUILD_TUPLE n + with LOAD_CONST (c1, c2, ... cn). + The consts table must still be in list form so that the + new constant (c1, c2, ... cn) can be appended. + Called with codestr pointing to the first LOAD_CONST. + Bails out with no change if one or more of the LOAD_CONSTs is missing. + Also works for BUILD_LIST when followed by an "in" or "not in" test. +*/ +static int +tuple_of_constants(unsigned char *codestr, int n, PyObject *consts) +{ + PyObject *newconst, *constant; + Py_ssize_t i, arg, len_consts; + + /* Pre-conditions */ + assert(PyList_CheckExact(consts)); + assert(codestr[n*3] == BUILD_TUPLE || codestr[n*3] == BUILD_LIST); + assert(GETARG(codestr, (n*3)) == n); + for (i=0 ; i<n ; i++) + assert(codestr[i*3] == LOAD_CONST); + + /* Buildup new tuple of constants */ + newconst = PyTuple_New(n); + if (newconst == NULL) + return 0; + len_consts = PyList_GET_SIZE(consts); + for (i=0 ; i<n ; i++) { + arg = GETARG(codestr, (i*3)); + assert(arg < len_consts); + constant = PyList_GET_ITEM(consts, arg); + Py_INCREF(constant); + PyTuple_SET_ITEM(newconst, i, constant); + } + + /* Append folded constant onto consts */ + if (PyList_Append(consts, newconst)) { + Py_DECREF(newconst); + return 0; + } + Py_DECREF(newconst); + + /* Write NOPs over old LOAD_CONSTS and + add a new LOAD_CONST newconst on top of the BUILD_TUPLE n */ + memset(codestr, NOP, n*3); + codestr[n*3] = LOAD_CONST; + SETARG(codestr, (n*3), len_consts); + return 1; +} + +/* Replace LOAD_CONST c1. LOAD_CONST c2 BINOP + with LOAD_CONST binop(c1,c2) + The consts table must still be in list form so that the + new constant can be appended. + Called with codestr pointing to the first LOAD_CONST. + Abandons the transformation if the folding fails (i.e. 1+'a'). + If the new constant is a sequence, only folds when the size + is below a threshold value. That keeps pyc files from + becoming large in the presence of code like: (None,)*1000. +*/ +static int +fold_binops_on_constants(unsigned char *codestr, PyObject *consts) +{ + PyObject *newconst, *v, *w; + Py_ssize_t len_consts, size; + int opcode; + + /* Pre-conditions */ + assert(PyList_CheckExact(consts)); + assert(codestr[0] == LOAD_CONST); + assert(codestr[3] == LOAD_CONST); + + /* Create new constant */ + v = PyList_GET_ITEM(consts, GETARG(codestr, 0)); + w = PyList_GET_ITEM(consts, GETARG(codestr, 3)); + opcode = codestr[6]; + switch (opcode) { + case BINARY_POWER: + newconst = PyNumber_Power(v, w, Py_None); + break; + case BINARY_MULTIPLY: + newconst = PyNumber_Multiply(v, w); + break; + case BINARY_DIVIDE: + /* Cannot fold this operation statically since + the result can depend on the run-time presence + of the -Qnew flag */ + return 0; + case BINARY_TRUE_DIVIDE: + newconst = PyNumber_TrueDivide(v, w); + break; + case BINARY_FLOOR_DIVIDE: + newconst = PyNumber_FloorDivide(v, w); + break; + case BINARY_MODULO: + newconst = PyNumber_Remainder(v, w); + break; + case BINARY_ADD: + newconst = PyNumber_Add(v, w); + break; + case BINARY_SUBTRACT: + newconst = PyNumber_Subtract(v, w); + break; + case BINARY_SUBSCR: + newconst = PyObject_GetItem(v, w); + break; + case BINARY_LSHIFT: + newconst = PyNumber_Lshift(v, w); + break; + case BINARY_RSHIFT: + newconst = PyNumber_Rshift(v, w); + break; + case BINARY_AND: + newconst = PyNumber_And(v, w); + break; + case BINARY_XOR: + newconst = PyNumber_Xor(v, w); + break; + case BINARY_OR: + newconst = PyNumber_Or(v, w); + break; + default: + /* Called with an unknown opcode */ + PyErr_Format(PyExc_SystemError, + "unexpected binary operation %d on a constant", + opcode); + return 0; + } + if (newconst == NULL) { + PyErr_Clear(); + return 0; + } + size = PyObject_Size(newconst); + if (size == -1) + PyErr_Clear(); + else if (size > 20) { + Py_DECREF(newconst); + return 0; + } + + /* Append folded constant into consts table */ + len_consts = PyList_GET_SIZE(consts); + if (PyList_Append(consts, newconst)) { + Py_DECREF(newconst); + return 0; + } + Py_DECREF(newconst); + + /* Write NOP NOP NOP NOP LOAD_CONST newconst */ + memset(codestr, NOP, 4); + codestr[4] = LOAD_CONST; + SETARG(codestr, 4, len_consts); + return 1; +} + +static int +fold_unaryops_on_constants(unsigned char *codestr, PyObject *consts) +{ + PyObject *newconst=NULL, *v; + Py_ssize_t len_consts; + int opcode; + + /* Pre-conditions */ + assert(PyList_CheckExact(consts)); + assert(codestr[0] == LOAD_CONST); + + /* Create new constant */ + v = PyList_GET_ITEM(consts, GETARG(codestr, 0)); + opcode = codestr[3]; + switch (opcode) { + case UNARY_NEGATIVE: + /* Preserve the sign of -0.0 */ + if (PyObject_IsTrue(v) == 1) + newconst = PyNumber_Negative(v); + break; + case UNARY_CONVERT: + newconst = PyObject_Repr(v); + break; + case UNARY_INVERT: + newconst = PyNumber_Invert(v); + break; + default: + /* Called with an unknown opcode */ + PyErr_Format(PyExc_SystemError, + "unexpected unary operation %d on a constant", + opcode); + return 0; + } + if (newconst == NULL) { + PyErr_Clear(); + return 0; + } + + /* Append folded constant into consts table */ + len_consts = PyList_GET_SIZE(consts); + if (PyList_Append(consts, newconst)) { + Py_DECREF(newconst); + return 0; + } + Py_DECREF(newconst); + + /* Write NOP LOAD_CONST newconst */ + codestr[0] = NOP; + codestr[1] = LOAD_CONST; + SETARG(codestr, 1, len_consts); + return 1; +} + +static unsigned int * +markblocks(unsigned char *code, int len) +{ + unsigned int *blocks = (unsigned int *)PyMem_Malloc(len*sizeof(int)); + int i,j, opcode, blockcnt = 0; + + if (blocks == NULL) { + PyErr_NoMemory(); + return NULL; + } + memset(blocks, 0, len*sizeof(int)); + + /* Mark labels in the first pass */ + for (i=0 ; i<len ; i+=CODESIZE(opcode)) { + opcode = code[i]; + switch (opcode) { + case FOR_ITER: + case JUMP_FORWARD: + case JUMP_IF_FALSE: + case JUMP_IF_TRUE: + case JUMP_ABSOLUTE: + case CONTINUE_LOOP: + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + j = GETJUMPTGT(code, i); + blocks[j] = 1; + break; + } + } + /* Build block numbers in the second pass */ + for (i=0 ; i<len ; i++) { + blockcnt += blocks[i]; /* increment blockcnt over labels */ + blocks[i] = blockcnt; + } + return blocks; +} + +/* Perform basic peephole optimizations to components of a code object. + The consts object should still be in list form to allow new constants + to be appended. + + To keep the optimizer simple, it bails out (does nothing) for code + containing extended arguments or that has a length over 32,700. That + allows us to avoid overflow and sign issues. Likewise, it bails when + the lineno table has complex encoding for gaps >= 255. + + Optimizations are restricted to simple transformations occuring within a + single basic block. All transformations keep the code size the same or + smaller. For those that reduce size, the gaps are initially filled with + NOPs. Later those NOPs are removed and the jump addresses retargeted in + a single pass. Line numbering is adjusted accordingly. */ + +static PyObject * +optimize_code(PyObject *code, PyObject* consts, PyObject *names, + PyObject *lineno_obj) +{ + Py_ssize_t i, j, codelen; + int nops, h, adj; + int tgt, tgttgt, opcode; + unsigned char *codestr = NULL; + unsigned char *lineno; + int *addrmap = NULL; + int new_line, cum_orig_line, last_line, tabsiz; + int cumlc=0, lastlc=0; /* Count runs of consecutive LOAD_CONSTs */ + unsigned int *blocks = NULL; + char *name; + + /* Bail out if an exception is set */ + if (PyErr_Occurred()) + goto exitUnchanged; + + /* Bypass optimization when the lineno table is too complex */ + assert(PyString_Check(lineno_obj)); + lineno = (unsigned char*)PyString_AS_STRING(lineno_obj); + tabsiz = PyString_GET_SIZE(lineno_obj); + if (memchr(lineno, 255, tabsiz) != NULL) + goto exitUnchanged; + + /* Avoid situations where jump retargeting could overflow */ + assert(PyString_Check(code)); + codelen = PyString_Size(code); + if (codelen > 32700) + goto exitUnchanged; + + /* Make a modifiable copy of the code string */ + codestr = (unsigned char *)PyMem_Malloc(codelen); + if (codestr == NULL) + goto exitUnchanged; + codestr = (unsigned char *)memcpy(codestr, + PyString_AS_STRING(code), codelen); + + /* Verify that RETURN_VALUE terminates the codestring. This allows + the various transformation patterns to look ahead several + instructions without additional checks to make sure they are not + looking beyond the end of the code string. + */ + if (codestr[codelen-1] != RETURN_VALUE) + goto exitUnchanged; + + /* Mapping to new jump targets after NOPs are removed */ + addrmap = (int *)PyMem_Malloc(codelen * sizeof(int)); + if (addrmap == NULL) + goto exitUnchanged; + + blocks = markblocks(codestr, codelen); + if (blocks == NULL) + goto exitUnchanged; + assert(PyList_Check(consts)); + + for (i=0 ; i<codelen ; i += CODESIZE(codestr[i])) { + opcode = codestr[i]; + + lastlc = cumlc; + cumlc = 0; + + switch (opcode) { + + /* Replace UNARY_NOT JUMP_IF_FALSE POP_TOP with + with JUMP_IF_TRUE POP_TOP */ + case UNARY_NOT: + if (codestr[i+1] != JUMP_IF_FALSE || + codestr[i+4] != POP_TOP || + !ISBASICBLOCK(blocks,i,5)) + continue; + tgt = GETJUMPTGT(codestr, (i+1)); + if (codestr[tgt] != POP_TOP) + continue; + j = GETARG(codestr, i+1) + 1; + codestr[i] = JUMP_IF_TRUE; + SETARG(codestr, i, j); + codestr[i+3] = POP_TOP; + codestr[i+4] = NOP; + break; + + /* not a is b --> a is not b + not a in b --> a not in b + not a is not b --> a is b + not a not in b --> a in b + */ + case COMPARE_OP: + j = GETARG(codestr, i); + if (j < 6 || j > 9 || + codestr[i+3] != UNARY_NOT || + !ISBASICBLOCK(blocks,i,4)) + continue; + SETARG(codestr, i, (j^1)); + codestr[i+3] = NOP; + break; + + /* Replace LOAD_GLOBAL/LOAD_NAME None + with LOAD_CONST None */ + case LOAD_NAME: + case LOAD_GLOBAL: + j = GETARG(codestr, i); + name = PyString_AsString(PyTuple_GET_ITEM(names, j)); + if (name == NULL || strcmp(name, "None") != 0) + continue; + for (j=0 ; j < PyList_GET_SIZE(consts) ; j++) { + if (PyList_GET_ITEM(consts, j) == Py_None) + break; + } + if (j == PyList_GET_SIZE(consts)) { + if (PyList_Append(consts, Py_None) == -1) + goto exitUnchanged; + } + assert(PyList_GET_ITEM(consts, j) == Py_None); + codestr[i] = LOAD_CONST; + SETARG(codestr, i, j); + cumlc = lastlc + 1; + break; + + /* Skip over LOAD_CONST trueconst + JUMP_IF_FALSE xx POP_TOP */ + case LOAD_CONST: + cumlc = lastlc + 1; + j = GETARG(codestr, i); + if (codestr[i+3] != JUMP_IF_FALSE || + codestr[i+6] != POP_TOP || + !ISBASICBLOCK(blocks,i,7) || + !PyObject_IsTrue(PyList_GET_ITEM(consts, j))) + continue; + memset(codestr+i, NOP, 7); + cumlc = 0; + break; + + /* Try to fold tuples of constants (includes a case for lists + which are only used for "in" and "not in" tests). + Skip over BUILD_SEQN 1 UNPACK_SEQN 1. + Replace BUILD_SEQN 2 UNPACK_SEQN 2 with ROT2. + Replace BUILD_SEQN 3 UNPACK_SEQN 3 with ROT3 ROT2. */ + case BUILD_TUPLE: + case BUILD_LIST: + j = GETARG(codestr, i); + h = i - 3 * j; + if (h >= 0 && + j <= lastlc && + ((opcode == BUILD_TUPLE && + ISBASICBLOCK(blocks, h, 3*(j+1))) || + (opcode == BUILD_LIST && + codestr[i+3]==COMPARE_OP && + ISBASICBLOCK(blocks, h, 3*(j+2)) && + (GETARG(codestr,i+3)==6 || + GETARG(codestr,i+3)==7))) && + tuple_of_constants(&codestr[h], j, consts)) { + assert(codestr[i] == LOAD_CONST); + cumlc = 1; + break; + } + if (codestr[i+3] != UNPACK_SEQUENCE || + !ISBASICBLOCK(blocks,i,6) || + j != GETARG(codestr, i+3)) + continue; + if (j == 1) { + memset(codestr+i, NOP, 6); + } else if (j == 2) { + codestr[i] = ROT_TWO; + memset(codestr+i+1, NOP, 5); + } else if (j == 3) { + codestr[i] = ROT_THREE; + codestr[i+1] = ROT_TWO; + memset(codestr+i+2, NOP, 4); + } + break; + + /* Fold binary ops on constants. + LOAD_CONST c1 LOAD_CONST c2 BINOP --> LOAD_CONST binop(c1,c2) */ + case BINARY_POWER: + case BINARY_MULTIPLY: + case BINARY_TRUE_DIVIDE: + case BINARY_FLOOR_DIVIDE: + case BINARY_MODULO: + case BINARY_ADD: + case BINARY_SUBTRACT: + case BINARY_SUBSCR: + case BINARY_LSHIFT: + case BINARY_RSHIFT: + case BINARY_AND: + case BINARY_XOR: + case BINARY_OR: + if (lastlc >= 2 && + ISBASICBLOCK(blocks, i-6, 7) && + fold_binops_on_constants(&codestr[i-6], consts)) { + i -= 2; + assert(codestr[i] == LOAD_CONST); + cumlc = 1; + } + break; + + /* Fold unary ops on constants. + LOAD_CONST c1 UNARY_OP --> LOAD_CONST unary_op(c) */ + case UNARY_NEGATIVE: + case UNARY_CONVERT: + case UNARY_INVERT: + if (lastlc >= 1 && + ISBASICBLOCK(blocks, i-3, 4) && + fold_unaryops_on_constants(&codestr[i-3], consts)) { + i -= 2; + assert(codestr[i] == LOAD_CONST); + cumlc = 1; + } + break; + + /* Simplify conditional jump to conditional jump where the + result of the first test implies the success of a similar + test or the failure of the opposite test. + Arises in code like: + "if a and b:" + "if a or b:" + "a and b or c" + "(a and b) and c" + x:JUMP_IF_FALSE y y:JUMP_IF_FALSE z --> x:JUMP_IF_FALSE z + x:JUMP_IF_FALSE y y:JUMP_IF_TRUE z --> x:JUMP_IF_FALSE y+3 + where y+3 is the instruction following the second test. + */ + case JUMP_IF_FALSE: + case JUMP_IF_TRUE: + tgt = GETJUMPTGT(codestr, i); + j = codestr[tgt]; + if (j == JUMP_IF_FALSE || j == JUMP_IF_TRUE) { + if (j == opcode) { + tgttgt = GETJUMPTGT(codestr, tgt) - i - 3; + SETARG(codestr, i, tgttgt); + } else { + tgt -= i; + SETARG(codestr, i, tgt); + } + break; + } + /* Intentional fallthrough */ + + /* Replace jumps to unconditional jumps */ + case FOR_ITER: + case JUMP_FORWARD: + case JUMP_ABSOLUTE: + case CONTINUE_LOOP: + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + tgt = GETJUMPTGT(codestr, i); + if (!UNCONDITIONAL_JUMP(codestr[tgt])) + continue; + tgttgt = GETJUMPTGT(codestr, tgt); + if (opcode == JUMP_FORWARD) /* JMP_ABS can go backwards */ + opcode = JUMP_ABSOLUTE; + if (!ABSOLUTE_JUMP(opcode)) + tgttgt -= i + 3; /* Calc relative jump addr */ + if (tgttgt < 0) /* No backward relative jumps */ + continue; + codestr[i] = opcode; + SETARG(codestr, i, tgttgt); + break; + + case EXTENDED_ARG: + goto exitUnchanged; + + /* Replace RETURN LOAD_CONST None RETURN with just RETURN */ + case RETURN_VALUE: + if (i+4 >= codelen || + codestr[i+4] != RETURN_VALUE || + !ISBASICBLOCK(blocks,i,5)) + continue; + memset(codestr+i+1, NOP, 4); + break; + } + } + + /* Fixup linenotab */ + for (i=0, nops=0 ; i<codelen ; i += CODESIZE(codestr[i])) { + addrmap[i] = i - nops; + if (codestr[i] == NOP) + nops++; + } + cum_orig_line = 0; + last_line = 0; + for (i=0 ; i < tabsiz ; i+=2) { + cum_orig_line += lineno[i]; + new_line = addrmap[cum_orig_line]; + assert (new_line - last_line < 255); + lineno[i] =((unsigned char)(new_line - last_line)); + last_line = new_line; + } + + /* Remove NOPs and fixup jump targets */ + for (i=0, h=0 ; i<codelen ; ) { + opcode = codestr[i]; + switch (opcode) { + case NOP: + i++; + continue; + + case JUMP_ABSOLUTE: + case CONTINUE_LOOP: + j = addrmap[GETARG(codestr, i)]; + SETARG(codestr, i, j); + break; + + case FOR_ITER: + case JUMP_FORWARD: + case JUMP_IF_FALSE: + case JUMP_IF_TRUE: + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: + j = addrmap[GETARG(codestr, i) + i + 3] - addrmap[i] - 3; + SETARG(codestr, i, j); + break; + } + adj = CODESIZE(opcode); + while (adj--) + codestr[h++] = codestr[i++]; + } + assert(h + nops == codelen); + + code = PyString_FromStringAndSize((char *)codestr, h); + PyMem_Free(addrmap); + PyMem_Free(codestr); + PyMem_Free(blocks); + return code; + + exitUnchanged: + if (blocks != NULL) + PyMem_Free(blocks); + if (addrmap != NULL) + PyMem_Free(addrmap); + if (codestr != NULL) + PyMem_Free(codestr); + Py_INCREF(code); + return code; +} + +/* End: Peephole optimizations ----------------------------------------- */ + +/* + +Leave this debugging code for just a little longer. + +static void +compiler_display_symbols(PyObject *name, PyObject *symbols) +{ +PyObject *key, *value; +int flags; +Py_ssize_t pos = 0; + +fprintf(stderr, "block %s\n", PyString_AS_STRING(name)); +while (PyDict_Next(symbols, &pos, &key, &value)) { +flags = PyInt_AsLong(value); +fprintf(stderr, "var %s:", PyString_AS_STRING(key)); +if (flags & DEF_GLOBAL) +fprintf(stderr, " declared_global"); +if (flags & DEF_LOCAL) +fprintf(stderr, " local"); +if (flags & DEF_PARAM) +fprintf(stderr, " param"); +if (flags & DEF_STAR) +fprintf(stderr, " stararg"); +if (flags & DEF_DOUBLESTAR) +fprintf(stderr, " starstar"); +if (flags & DEF_INTUPLE) +fprintf(stderr, " tuple"); +if (flags & DEF_FREE) +fprintf(stderr, " free"); +if (flags & DEF_FREE_GLOBAL) +fprintf(stderr, " global"); +if (flags & DEF_FREE_CLASS) +fprintf(stderr, " free/class"); +if (flags & DEF_IMPORT) +fprintf(stderr, " import"); +fprintf(stderr, "\n"); +} + fprintf(stderr, "\n"); +} +*/ + +static void +compiler_unit_check(struct compiler_unit *u) +{ + basicblock *block; + for (block = u->u_blocks; block != NULL; block = block->b_list) { + assert(block != (void *)0xcbcbcbcb); + assert(block != (void *)0xfbfbfbfb); + assert(block != (void *)0xdbdbdbdb); + if (block->b_instr != NULL) { + assert(block->b_ialloc > 0); + assert(block->b_iused > 0); + assert(block->b_ialloc >= block->b_iused); + } + else { + assert (block->b_iused == 0); + assert (block->b_ialloc == 0); + } + } +} + +static void +compiler_unit_free(struct compiler_unit *u) +{ + basicblock *b, *next; + + compiler_unit_check(u); + b = u->u_blocks; + while (b != NULL) { + if (b->b_instr) + PyObject_Free((void *)b->b_instr); + next = b->b_list; + PyObject_Free((void *)b); + b = next; + } + Py_CLEAR(u->u_ste); + Py_CLEAR(u->u_name); + Py_CLEAR(u->u_consts); + Py_CLEAR(u->u_names); + Py_CLEAR(u->u_varnames); + Py_CLEAR(u->u_freevars); + Py_CLEAR(u->u_cellvars); + Py_CLEAR(u->u_private); + PyObject_Free(u); +} + +static int +compiler_enter_scope(struct compiler *c, identifier name, void *key, + int lineno) +{ + struct compiler_unit *u; + + u = (struct compiler_unit *)PyObject_Malloc(sizeof( + struct compiler_unit)); + if (!u) { + PyErr_NoMemory(); + return 0; + } + memset(u, 0, sizeof(struct compiler_unit)); + u->u_argcount = 0; + u->u_ste = PySymtable_Lookup(c->c_st, key); + if (!u->u_ste) { + compiler_unit_free(u); + return 0; + } + Py_INCREF(name); + u->u_name = name; + u->u_varnames = list2dict(u->u_ste->ste_varnames); + u->u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0); + if (!u->u_varnames || !u->u_cellvars) { + compiler_unit_free(u); + return 0; + } + + u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS, + PyDict_Size(u->u_cellvars)); + if (!u->u_freevars) { + compiler_unit_free(u); + return 0; + } + + u->u_blocks = NULL; + u->u_tmpname = 0; + u->u_nfblocks = 0; + u->u_firstlineno = lineno; + u->u_lineno = 0; + u->u_lineno_set = false; + u->u_consts = PyDict_New(); + if (!u->u_consts) { + compiler_unit_free(u); + return 0; + } + u->u_names = PyDict_New(); + if (!u->u_names) { + compiler_unit_free(u); + return 0; + } + + u->u_private = NULL; + + /* Push the old compiler_unit on the stack. */ + if (c->u) { + PyObject *wrapper = PyCObject_FromVoidPtr(c->u, NULL); + if (!wrapper || PyList_Append(c->c_stack, wrapper) < 0) { + Py_XDECREF(wrapper); + compiler_unit_free(u); + return 0; + } + Py_DECREF(wrapper); + u->u_private = c->u->u_private; + Py_XINCREF(u->u_private); + } + c->u = u; + + c->c_nestlevel++; + if (compiler_use_new_block(c) == NULL) + return 0; + + return 1; +} + +static void +compiler_exit_scope(struct compiler *c) +{ + int n; + PyObject *wrapper; + + c->c_nestlevel--; + compiler_unit_free(c->u); + /* Restore c->u to the parent unit. */ + n = PyList_GET_SIZE(c->c_stack) - 1; + if (n >= 0) { + wrapper = PyList_GET_ITEM(c->c_stack, n); + c->u = (struct compiler_unit *)PyCObject_AsVoidPtr(wrapper); + /* we are deleting from a list so this really shouldn't fail */ + if (PySequence_DelItem(c->c_stack, n) < 0) + Py_FatalError("compiler_exit_scope()"); + compiler_unit_check(c->u); + } + else + c->u = NULL; + +} + +/* Allocate a new "anonymous" local variable. + Used by list comprehensions and with statements. +*/ + +static PyObject * +compiler_new_tmpname(struct compiler *c) +{ + char tmpname[256]; + PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", ++c->u->u_tmpname); + return PyString_FromString(tmpname); +} + +/* Allocate a new block and return a pointer to it. + Returns NULL on error. +*/ + +static basicblock * +compiler_new_block(struct compiler *c) +{ + basicblock *b; + struct compiler_unit *u; + + u = c->u; + b = (basicblock *)PyObject_Malloc(sizeof(basicblock)); + if (b == NULL) { + PyErr_NoMemory(); + return NULL; + } + memset((void *)b, 0, sizeof(basicblock)); + /* Extend the singly linked list of blocks with new block. */ + b->b_list = u->u_blocks; + u->u_blocks = b; + return b; +} + +static basicblock * +compiler_use_new_block(struct compiler *c) +{ + basicblock *block = compiler_new_block(c); + if (block == NULL) + return NULL; + c->u->u_curblock = block; + return block; +} + +static basicblock * +compiler_next_block(struct compiler *c) +{ + basicblock *block = compiler_new_block(c); + if (block == NULL) + return NULL; + c->u->u_curblock->b_next = block; + c->u->u_curblock = block; + return block; +} + +static basicblock * +compiler_use_next_block(struct compiler *c, basicblock *block) +{ + assert(block != NULL); + c->u->u_curblock->b_next = block; + c->u->u_curblock = block; + return block; +} + +/* Returns the offset of the next instruction in the current block's + b_instr array. Resizes the b_instr as necessary. + Returns -1 on failure. + */ + +static int +compiler_next_instr(struct compiler *c, basicblock *b) +{ + assert(b != NULL); + if (b->b_instr == NULL) { + b->b_instr = (struct instr *)PyObject_Malloc( + sizeof(struct instr) * DEFAULT_BLOCK_SIZE); + if (b->b_instr == NULL) { + PyErr_NoMemory(); + return -1; + } + b->b_ialloc = DEFAULT_BLOCK_SIZE; + memset((char *)b->b_instr, 0, + sizeof(struct instr) * DEFAULT_BLOCK_SIZE); + } + else if (b->b_iused == b->b_ialloc) { + struct instr *tmp; + size_t oldsize, newsize; + oldsize = b->b_ialloc * sizeof(struct instr); + newsize = oldsize << 1; + if (newsize == 0) { + PyErr_NoMemory(); + return -1; + } + b->b_ialloc <<= 1; + tmp = (struct instr *)PyObject_Realloc( + (void *)b->b_instr, newsize); + if (tmp == NULL) { + PyErr_NoMemory(); + return -1; + } + b->b_instr = tmp; + memset((char *)b->b_instr + oldsize, 0, newsize - oldsize); + } + return b->b_iused++; +} + +/* Set the i_lineno member of the instruction at offse off if the + line number for the current expression/statement (?) has not + already been set. If it has been set, the call has no effect. + + Every time a new node is b + */ + +static void +compiler_set_lineno(struct compiler *c, int off) +{ + basicblock *b; + if (c->u->u_lineno_set) + return; + c->u->u_lineno_set = true; + b = c->u->u_curblock; + b->b_instr[off].i_lineno = c->u->u_lineno; +} + +static int +opcode_stack_effect(int opcode, int oparg) +{ + switch (opcode) { + case POP_TOP: + return -1; + case ROT_TWO: + case ROT_THREE: + return 0; + case DUP_TOP: + return 1; + case ROT_FOUR: + return 0; + + case UNARY_POSITIVE: + case UNARY_NEGATIVE: + case UNARY_NOT: + case UNARY_CONVERT: + case UNARY_INVERT: + return 0; + + case LIST_APPEND: + return -2; + + case BINARY_POWER: + case BINARY_MULTIPLY: + case BINARY_DIVIDE: + case BINARY_MODULO: + case BINARY_ADD: + case BINARY_SUBTRACT: + case BINARY_SUBSCR: + case BINARY_FLOOR_DIVIDE: + case BINARY_TRUE_DIVIDE: + return -1; + case INPLACE_FLOOR_DIVIDE: + case INPLACE_TRUE_DIVIDE: + return -1; + + case SLICE+0: + return 1; + case SLICE+1: + return 0; + case SLICE+2: + return 0; + case SLICE+3: + return -1; + + case STORE_SLICE+0: + return -2; + case STORE_SLICE+1: + return -3; + case STORE_SLICE+2: + return -3; + case STORE_SLICE+3: + return -4; + + case DELETE_SLICE+0: + return -1; + case DELETE_SLICE+1: + return -2; + case DELETE_SLICE+2: + return -2; + case DELETE_SLICE+3: + return -3; + + case INPLACE_ADD: + case INPLACE_SUBTRACT: + case INPLACE_MULTIPLY: + case INPLACE_DIVIDE: + case INPLACE_MODULO: + return -1; + case STORE_SUBSCR: + return -3; + case DELETE_SUBSCR: + return -2; + + case BINARY_LSHIFT: + case BINARY_RSHIFT: + case BINARY_AND: + case BINARY_XOR: + case BINARY_OR: + return -1; + case INPLACE_POWER: + return -1; + case GET_ITER: + return 0; + + case PRINT_EXPR: + return -1; + case PRINT_ITEM: + return -1; + case PRINT_NEWLINE: + return 0; + case PRINT_ITEM_TO: + return -2; + case PRINT_NEWLINE_TO: + return -1; + case INPLACE_LSHIFT: + case INPLACE_RSHIFT: + case INPLACE_AND: + case INPLACE_XOR: + case INPLACE_OR: + return -1; + case BREAK_LOOP: + return 0; + case WITH_CLEANUP: + return -1; /* XXX Sometimes more */ + case LOAD_LOCALS: + return 1; + case RETURN_VALUE: + return -1; + case IMPORT_STAR: + return -1; + case EXEC_STMT: + return -3; + case YIELD_VALUE: + return 0; + + case POP_BLOCK: + return 0; + case END_FINALLY: + return -1; /* or -2 or -3 if exception occurred */ + case BUILD_CLASS: + return -2; + + case STORE_NAME: + return -1; + case DELETE_NAME: + return 0; + case UNPACK_SEQUENCE: + return oparg-1; + case FOR_ITER: + return 1; + + case STORE_ATTR: + return -2; + case DELETE_ATTR: + return -1; + case STORE_GLOBAL: + return -1; + case DELETE_GLOBAL: + return 0; + case DUP_TOPX: + return oparg; + case LOAD_CONST: + return 1; + case LOAD_NAME: + return 1; + case BUILD_TUPLE: + case BUILD_LIST: + return 1-oparg; + case BUILD_MAP: + return 1; + case LOAD_ATTR: + return 0; + case COMPARE_OP: + return -1; + case IMPORT_NAME: + return 0; + case IMPORT_FROM: + return 1; + + case JUMP_FORWARD: + case JUMP_IF_FALSE: + case JUMP_IF_TRUE: + case JUMP_ABSOLUTE: + return 0; + + case LOAD_GLOBAL: + return 1; + + case CONTINUE_LOOP: + return 0; + case SETUP_LOOP: + return 0; + case SETUP_EXCEPT: + case SETUP_FINALLY: + return 3; /* actually pushed by an exception */ + + case LOAD_FAST: + return 1; + case STORE_FAST: + return -1; + case DELETE_FAST: + return 0; + + case RAISE_VARARGS: + return -oparg; +#define NARGS(o) (((o) % 256) + 2*((o) / 256)) + case CALL_FUNCTION: + return -NARGS(oparg); + case CALL_FUNCTION_VAR: + case CALL_FUNCTION_KW: + return -NARGS(oparg)-1; + case CALL_FUNCTION_VAR_KW: + return -NARGS(oparg)-2; +#undef NARGS + case MAKE_FUNCTION: + return -oparg; + case BUILD_SLICE: + if (oparg == 3) + return -2; + else + return -1; + + case MAKE_CLOSURE: + return -oparg; + case LOAD_CLOSURE: + return 1; + case LOAD_DEREF: + return 1; + case STORE_DEREF: + return -1; + default: + fprintf(stderr, "opcode = %d\n", opcode); + Py_FatalError("opcode_stack_effect()"); + + } + return 0; /* not reachable */ +} + +/* Add an opcode with no argument. + Returns 0 on failure, 1 on success. +*/ + +static int +compiler_addop(struct compiler *c, int opcode) +{ + basicblock *b; + struct instr *i; + int off; + off = compiler_next_instr(c, c->u->u_curblock); + if (off < 0) + return 0; + b = c->u->u_curblock; + i = &b->b_instr[off]; + i->i_opcode = opcode; + i->i_hasarg = 0; + if (opcode == RETURN_VALUE) + b->b_return = 1; + compiler_set_lineno(c, off); + return 1; +} + +static int +compiler_add_o(struct compiler *c, PyObject *dict, PyObject *o) +{ + PyObject *t, *v; + Py_ssize_t arg; + + /* necessary to make sure types aren't coerced (e.g., int and long) */ + t = PyTuple_Pack(2, o, o->ob_type); + if (t == NULL) + return -1; + + v = PyDict_GetItem(dict, t); + if (!v) { + arg = PyDict_Size(dict); + v = PyInt_FromLong(arg); + if (!v) { + Py_DECREF(t); + return -1; + } + if (PyDict_SetItem(dict, t, v) < 0) { + Py_DECREF(t); + Py_DECREF(v); + return -1; + } + Py_DECREF(v); + } + else + arg = PyInt_AsLong(v); + Py_DECREF(t); + return arg; +} + +static int +compiler_addop_o(struct compiler *c, int opcode, PyObject *dict, + PyObject *o) +{ + int arg = compiler_add_o(c, dict, o); + if (arg < 0) + return 0; + return compiler_addop_i(c, opcode, arg); +} + +static int +compiler_addop_name(struct compiler *c, int opcode, PyObject *dict, + PyObject *o) +{ + int arg; + PyObject *mangled = _Py_Mangle(c->u->u_private, o); + if (!mangled) + return 0; + arg = compiler_add_o(c, dict, mangled); + Py_DECREF(mangled); + if (arg < 0) + return 0; + return compiler_addop_i(c, opcode, arg); +} + +/* Add an opcode with an integer argument. + Returns 0 on failure, 1 on success. +*/ + +static int +compiler_addop_i(struct compiler *c, int opcode, int oparg) +{ + struct instr *i; + int off; + off = compiler_next_instr(c, c->u->u_curblock); + if (off < 0) + return 0; + i = &c->u->u_curblock->b_instr[off]; + i->i_opcode = opcode; + i->i_oparg = oparg; + i->i_hasarg = 1; + compiler_set_lineno(c, off); + return 1; +} + +static int +compiler_addop_j(struct compiler *c, int opcode, basicblock *b, int absolute) +{ + struct instr *i; + int off; + + assert(b != NULL); + off = compiler_next_instr(c, c->u->u_curblock); + if (off < 0) + return 0; + i = &c->u->u_curblock->b_instr[off]; + i->i_opcode = opcode; + i->i_target = b; + i->i_hasarg = 1; + if (absolute) + i->i_jabs = 1; + else + i->i_jrel = 1; + compiler_set_lineno(c, off); + return 1; +} + +/* The distinction between NEW_BLOCK and NEXT_BLOCK is subtle. (I'd + like to find better names.) NEW_BLOCK() creates a new block and sets + it as the current block. NEXT_BLOCK() also creates an implicit jump + from the current block to the new block. +*/ + +/* XXX The returns inside these macros make it impossible to decref + objects created in the local function. +*/ + + +#define NEW_BLOCK(C) { \ + if (compiler_use_new_block((C)) == NULL) \ + return 0; \ +} + +#define NEXT_BLOCK(C) { \ + if (compiler_next_block((C)) == NULL) \ + return 0; \ +} + +#define ADDOP(C, OP) { \ + if (!compiler_addop((C), (OP))) \ + return 0; \ +} + +#define ADDOP_IN_SCOPE(C, OP) { \ + if (!compiler_addop((C), (OP))) { \ + compiler_exit_scope(c); \ + return 0; \ + } \ +} + +#define ADDOP_O(C, OP, O, TYPE) { \ + if (!compiler_addop_o((C), (OP), (C)->u->u_ ## TYPE, (O))) \ + return 0; \ +} + +#define ADDOP_NAME(C, OP, O, TYPE) { \ + if (!compiler_addop_name((C), (OP), (C)->u->u_ ## TYPE, (O))) \ + return 0; \ +} + +#define ADDOP_I(C, OP, O) { \ + if (!compiler_addop_i((C), (OP), (O))) \ + return 0; \ +} + +#define ADDOP_JABS(C, OP, O) { \ + if (!compiler_addop_j((C), (OP), (O), 1)) \ + return 0; \ +} + +#define ADDOP_JREL(C, OP, O) { \ + if (!compiler_addop_j((C), (OP), (O), 0)) \ + return 0; \ +} + +/* VISIT and VISIT_SEQ takes an ASDL type as their second argument. They use + the ASDL name to synthesize the name of the C type and the visit function. +*/ + +#define VISIT(C, TYPE, V) {\ + if (!compiler_visit_ ## TYPE((C), (V))) \ + return 0; \ +} + +#define VISIT_IN_SCOPE(C, TYPE, V) {\ + if (!compiler_visit_ ## TYPE((C), (V))) { \ + compiler_exit_scope(c); \ + return 0; \ + } \ +} + +#define VISIT_SLICE(C, V, CTX) {\ + if (!compiler_visit_slice((C), (V), (CTX))) \ + return 0; \ +} + +#define VISIT_SEQ(C, TYPE, SEQ) { \ + int _i; \ + asdl_seq *seq = (SEQ); /* avoid variable capture */ \ + for (_i = 0; _i < asdl_seq_LEN(seq); _i++) { \ + TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, _i); \ + if (!compiler_visit_ ## TYPE((C), elt)) \ + return 0; \ + } \ +} + +#define VISIT_SEQ_IN_SCOPE(C, TYPE, SEQ) { \ + int _i; \ + asdl_seq *seq = (SEQ); /* avoid variable capture */ \ + for (_i = 0; _i < asdl_seq_LEN(seq); _i++) { \ + TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, _i); \ + if (!compiler_visit_ ## TYPE((C), elt)) { \ + compiler_exit_scope(c); \ + return 0; \ + } \ + } \ +} + +static int +compiler_isdocstring(stmt_ty s) +{ + if (s->kind != Expr_kind) + return 0; + return s->v.Expr.value->kind == Str_kind; +} + +/* Compile a sequence of statements, checking for a docstring. */ + +static int +compiler_body(struct compiler *c, asdl_seq *stmts) +{ + int i = 0; + stmt_ty st; + + if (!asdl_seq_LEN(stmts)) + return 1; + st = (stmt_ty)asdl_seq_GET(stmts, 0); + if (compiler_isdocstring(st)) { + i = 1; + VISIT(c, expr, st->v.Expr.value); + if (!compiler_nameop(c, __doc__, Store)) + return 0; + } + for (; i < asdl_seq_LEN(stmts); i++) + VISIT(c, stmt, (stmt_ty)asdl_seq_GET(stmts, i)); + return 1; +} + +static PyCodeObject * +compiler_mod(struct compiler *c, mod_ty mod) +{ + PyCodeObject *co; + int addNone = 1; + static PyObject *module; + if (!module) { + module = PyString_FromString("<module>"); + if (!module) + return NULL; + } + /* Use 0 for firstlineno initially, will fixup in assemble(). */ + if (!compiler_enter_scope(c, module, mod, 0)) + return NULL; + switch (mod->kind) { + case Module_kind: + if (!compiler_body(c, mod->v.Module.body)) { + compiler_exit_scope(c); + return 0; + } + break; + case Interactive_kind: + c->c_interactive = 1; + VISIT_SEQ_IN_SCOPE(c, stmt, + mod->v.Interactive.body); + break; + case Expression_kind: + VISIT_IN_SCOPE(c, expr, mod->v.Expression.body); + addNone = 0; + break; + case Suite_kind: + PyErr_SetString(PyExc_SystemError, + "suite should not be possible"); + return 0; + default: + PyErr_Format(PyExc_SystemError, + "module kind %d should not be possible", + mod->kind); + return 0; + } + co = assemble(c, addNone); + compiler_exit_scope(c); + return co; +} + +/* The test for LOCAL must come before the test for FREE in order to + handle classes where name is both local and free. The local var is + a method and the free var is a free var referenced within a method. +*/ + +static int +get_ref_type(struct compiler *c, PyObject *name) +{ + int scope = PyST_GetScope(c->u->u_ste, name); + if (scope == 0) { + char buf[350]; + PyOS_snprintf(buf, sizeof(buf), + "unknown scope for %.100s in %.100s(%s) in %s\n" + "symbols: %s\nlocals: %s\nglobals: %s\n", + PyString_AS_STRING(name), + PyString_AS_STRING(c->u->u_name), + PyObject_REPR(c->u->u_ste->ste_id), + c->c_filename, + PyObject_REPR(c->u->u_ste->ste_symbols), + PyObject_REPR(c->u->u_varnames), + PyObject_REPR(c->u->u_names) + ); + Py_FatalError(buf); + } + + return scope; +} + +static int +compiler_lookup_arg(PyObject *dict, PyObject *name) +{ + PyObject *k, *v; + k = PyTuple_Pack(2, name, name->ob_type); + if (k == NULL) + return -1; + v = PyDict_GetItem(dict, k); + Py_DECREF(k); + if (v == NULL) + return -1; + return PyInt_AS_LONG(v); +} + +static int +compiler_make_closure(struct compiler *c, PyCodeObject *co, int args) +{ + int i, free = PyCode_GetNumFree(co); + if (free == 0) { + ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); + ADDOP_I(c, MAKE_FUNCTION, args); + return 1; + } + for (i = 0; i < free; ++i) { + /* Bypass com_addop_varname because it will generate + LOAD_DEREF but LOAD_CLOSURE is needed. + */ + PyObject *name = PyTuple_GET_ITEM(co->co_freevars, i); + int arg, reftype; + + /* Special case: If a class contains a method with a + free variable that has the same name as a method, + the name will be considered free *and* local in the + class. It should be handled by the closure, as + well as by the normal name loookup logic. + */ + reftype = get_ref_type(c, name); + if (reftype == CELL) + arg = compiler_lookup_arg(c->u->u_cellvars, name); + else /* (reftype == FREE) */ + arg = compiler_lookup_arg(c->u->u_freevars, name); + if (arg == -1) { + printf("lookup %s in %s %d %d\n" + "freevars of %s: %s\n", + PyObject_REPR(name), + PyString_AS_STRING(c->u->u_name), + reftype, arg, + PyString_AS_STRING(co->co_name), + PyObject_REPR(co->co_freevars)); + Py_FatalError("compiler_make_closure()"); + } + ADDOP_I(c, LOAD_CLOSURE, arg); + } + ADDOP_I(c, BUILD_TUPLE, free); + ADDOP_O(c, LOAD_CONST, (PyObject*)co, consts); + ADDOP_I(c, MAKE_CLOSURE, args); + return 1; +} + +static int +compiler_decorators(struct compiler *c, asdl_seq* decos) +{ + int i; + + if (!decos) + return 1; + + for (i = 0; i < asdl_seq_LEN(decos); i++) { + VISIT(c, expr, (expr_ty)asdl_seq_GET(decos, i)); + } + return 1; +} + +static int +compiler_arguments(struct compiler *c, arguments_ty args) +{ + int i; + int n = asdl_seq_LEN(args->args); + /* Correctly handle nested argument lists */ + for (i = 0; i < n; i++) { + expr_ty arg = (expr_ty)asdl_seq_GET(args->args, i); + if (arg->kind == Tuple_kind) { + PyObject *id = PyString_FromFormat(".%d", i); + if (id == NULL) { + return 0; + } + if (!compiler_nameop(c, id, Load)) { + Py_DECREF(id); + return 0; + } + Py_DECREF(id); + VISIT(c, expr, arg); + } + } + return 1; +} + +static int +compiler_function(struct compiler *c, stmt_ty s) +{ + PyCodeObject *co; + PyObject *first_const = Py_None; + arguments_ty args = s->v.FunctionDef.args; + asdl_seq* decos = s->v.FunctionDef.decorators; + stmt_ty st; + int i, n, docstring; + + assert(s->kind == FunctionDef_kind); + + if (!compiler_decorators(c, decos)) + return 0; + if (args->defaults) + VISIT_SEQ(c, expr, args->defaults); + if (!compiler_enter_scope(c, s->v.FunctionDef.name, (void *)s, + s->lineno)) + return 0; + + st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, 0); + docstring = compiler_isdocstring(st); + if (docstring) + first_const = st->v.Expr.value->v.Str.s; + if (compiler_add_o(c, c->u->u_consts, first_const) < 0) { + compiler_exit_scope(c); + return 0; + } + + /* unpack nested arguments */ + compiler_arguments(c, args); + + c->u->u_argcount = asdl_seq_LEN(args->args); + n = asdl_seq_LEN(s->v.FunctionDef.body); + /* if there was a docstring, we need to skip the first statement */ + for (i = docstring; i < n; i++) { + st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, i); + VISIT_IN_SCOPE(c, stmt, st); + } + co = assemble(c, 1); + compiler_exit_scope(c); + if (co == NULL) + return 0; + + compiler_make_closure(c, co, asdl_seq_LEN(args->defaults)); + Py_DECREF(co); + + for (i = 0; i < asdl_seq_LEN(decos); i++) { + ADDOP_I(c, CALL_FUNCTION, 1); + } + + return compiler_nameop(c, s->v.FunctionDef.name, Store); +} + +static int +compiler_class(struct compiler *c, stmt_ty s) +{ + int n; + PyCodeObject *co; + PyObject *str; + /* push class name on stack, needed by BUILD_CLASS */ + ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts); + /* push the tuple of base classes on the stack */ + n = asdl_seq_LEN(s->v.ClassDef.bases); + if (n > 0) + VISIT_SEQ(c, expr, s->v.ClassDef.bases); + ADDOP_I(c, BUILD_TUPLE, n); + if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, + s->lineno)) + return 0; + c->u->u_private = s->v.ClassDef.name; + Py_INCREF(c->u->u_private); + str = PyString_InternFromString("__name__"); + if (!str || !compiler_nameop(c, str, Load)) { + Py_XDECREF(str); + compiler_exit_scope(c); + return 0; + } + + Py_DECREF(str); + str = PyString_InternFromString("__module__"); + if (!str || !compiler_nameop(c, str, Store)) { + Py_XDECREF(str); + compiler_exit_scope(c); + return 0; + } + Py_DECREF(str); + + if (!compiler_body(c, s->v.ClassDef.body)) { + compiler_exit_scope(c); + return 0; + } + + ADDOP_IN_SCOPE(c, LOAD_LOCALS); + ADDOP_IN_SCOPE(c, RETURN_VALUE); + co = assemble(c, 1); + compiler_exit_scope(c); + if (co == NULL) + return 0; + + compiler_make_closure(c, co, 0); + Py_DECREF(co); + + ADDOP_I(c, CALL_FUNCTION, 0); + ADDOP(c, BUILD_CLASS); + if (!compiler_nameop(c, s->v.ClassDef.name, Store)) + return 0; + return 1; +} + +static int +compiler_ifexp(struct compiler *c, expr_ty e) +{ + basicblock *end, *next; + + assert(e->kind == IfExp_kind); + end = compiler_new_block(c); + if (end == NULL) + return 0; + next = compiler_new_block(c); + if (next == NULL) + return 0; + VISIT(c, expr, e->v.IfExp.test); + ADDOP_JREL(c, JUMP_IF_FALSE, next); + ADDOP(c, POP_TOP); + VISIT(c, expr, e->v.IfExp.body); + ADDOP_JREL(c, JUMP_FORWARD, end); + compiler_use_next_block(c, next); + ADDOP(c, POP_TOP); + VISIT(c, expr, e->v.IfExp.orelse); + compiler_use_next_block(c, end); + return 1; +} + +static int +compiler_lambda(struct compiler *c, expr_ty e) +{ + PyCodeObject *co; + static identifier name; + arguments_ty args = e->v.Lambda.args; + assert(e->kind == Lambda_kind); + + if (!name) { + name = PyString_InternFromString("<lambda>"); + if (!name) + return 0; + } + + if (args->defaults) + VISIT_SEQ(c, expr, args->defaults); + if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) + return 0; + + /* unpack nested arguments */ + compiler_arguments(c, args); + + c->u->u_argcount = asdl_seq_LEN(args->args); + VISIT_IN_SCOPE(c, expr, e->v.Lambda.body); + ADDOP_IN_SCOPE(c, RETURN_VALUE); + co = assemble(c, 1); + compiler_exit_scope(c); + if (co == NULL) + return 0; + + compiler_make_closure(c, co, asdl_seq_LEN(args->defaults)); + Py_DECREF(co); + + return 1; +} + +static int +compiler_print(struct compiler *c, stmt_ty s) +{ + int i, n; + bool dest; + + assert(s->kind == Print_kind); + n = asdl_seq_LEN(s->v.Print.values); + dest = false; + if (s->v.Print.dest) { + VISIT(c, expr, s->v.Print.dest); + dest = true; + } + for (i = 0; i < n; i++) { + expr_ty e = (expr_ty)asdl_seq_GET(s->v.Print.values, i); + if (dest) { + ADDOP(c, DUP_TOP); + VISIT(c, expr, e); + ADDOP(c, ROT_TWO); + ADDOP(c, PRINT_ITEM_TO); + } + else { + VISIT(c, expr, e); + ADDOP(c, PRINT_ITEM); + } + } + if (s->v.Print.nl) { + if (dest) + ADDOP(c, PRINT_NEWLINE_TO) + else + ADDOP(c, PRINT_NEWLINE) + } + else if (dest) + ADDOP(c, POP_TOP); + return 1; +} + +static int +compiler_if(struct compiler *c, stmt_ty s) +{ + basicblock *end, *next; + int constant; + assert(s->kind == If_kind); + end = compiler_new_block(c); + if (end == NULL) + return 0; + next = compiler_new_block(c); + if (next == NULL) + return 0; + + constant = expr_constant(s->v.If.test); + /* constant = 0: "if 0" + * constant = 1: "if 1", "if 2", ... + * constant = -1: rest */ + if (constant == 0) { + if (s->v.If.orelse) + VISIT_SEQ(c, stmt, s->v.If.orelse); + } else if (constant == 1) { + VISIT_SEQ(c, stmt, s->v.If.body); + } else { + VISIT(c, expr, s->v.If.test); + ADDOP_JREL(c, JUMP_IF_FALSE, next); + ADDOP(c, POP_TOP); + VISIT_SEQ(c, stmt, s->v.If.body); + ADDOP_JREL(c, JUMP_FORWARD, end); + compiler_use_next_block(c, next); + ADDOP(c, POP_TOP); + if (s->v.If.orelse) + VISIT_SEQ(c, stmt, s->v.If.orelse); + } + compiler_use_next_block(c, end); + return 1; +} + +static int +compiler_for(struct compiler *c, stmt_ty s) +{ + basicblock *start, *cleanup, *end; + + start = compiler_new_block(c); + cleanup = compiler_new_block(c); + end = compiler_new_block(c); + if (start == NULL || end == NULL || cleanup == NULL) + return 0; + ADDOP_JREL(c, SETUP_LOOP, end); + if (!compiler_push_fblock(c, LOOP, start)) + return 0; + VISIT(c, expr, s->v.For.iter); + ADDOP(c, GET_ITER); + compiler_use_next_block(c, start); + /* XXX(nnorwitz): is there a better way to handle this? + for loops are special, we want to be able to trace them + each time around, so we need to set an extra line number. */ + c->u->u_lineno_set = false; + ADDOP_JREL(c, FOR_ITER, cleanup); + VISIT(c, expr, s->v.For.target); + VISIT_SEQ(c, stmt, s->v.For.body); + ADDOP_JABS(c, JUMP_ABSOLUTE, start); + compiler_use_next_block(c, cleanup); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, LOOP, start); + VISIT_SEQ(c, stmt, s->v.For.orelse); + compiler_use_next_block(c, end); + return 1; +} + +static int +compiler_while(struct compiler *c, stmt_ty s) +{ + basicblock *loop, *orelse, *end, *anchor = NULL; + int constant = expr_constant(s->v.While.test); + + if (constant == 0) + return 1; + loop = compiler_new_block(c); + end = compiler_new_block(c); + if (constant == -1) { + anchor = compiler_new_block(c); + if (anchor == NULL) + return 0; + } + if (loop == NULL || end == NULL) + return 0; + if (s->v.While.orelse) { + orelse = compiler_new_block(c); + if (orelse == NULL) + return 0; + } + else + orelse = NULL; + + ADDOP_JREL(c, SETUP_LOOP, end); + compiler_use_next_block(c, loop); + if (!compiler_push_fblock(c, LOOP, loop)) + return 0; + if (constant == -1) { + VISIT(c, expr, s->v.While.test); + ADDOP_JREL(c, JUMP_IF_FALSE, anchor); + ADDOP(c, POP_TOP); + } + VISIT_SEQ(c, stmt, s->v.While.body); + ADDOP_JABS(c, JUMP_ABSOLUTE, loop); + + /* XXX should the two POP instructions be in a separate block + if there is no else clause ? + */ + + if (constant == -1) { + compiler_use_next_block(c, anchor); + ADDOP(c, POP_TOP); + ADDOP(c, POP_BLOCK); + } + compiler_pop_fblock(c, LOOP, loop); + if (orelse != NULL) /* what if orelse is just pass? */ + VISIT_SEQ(c, stmt, s->v.While.orelse); + compiler_use_next_block(c, end); + + return 1; +} + +static int +compiler_continue(struct compiler *c) +{ + static const char LOOP_ERROR_MSG[] = "'continue' not properly in loop"; + static const char IN_FINALLY_ERROR_MSG[] = + "'continue' not supported inside 'finally' clause"; + int i; + + if (!c->u->u_nfblocks) + return compiler_error(c, LOOP_ERROR_MSG); + i = c->u->u_nfblocks - 1; + switch (c->u->u_fblock[i].fb_type) { + case LOOP: + ADDOP_JABS(c, JUMP_ABSOLUTE, c->u->u_fblock[i].fb_block); + break; + case EXCEPT: + case FINALLY_TRY: + while (--i >= 0 && c->u->u_fblock[i].fb_type != LOOP) { + /* Prevent try: ... finally: + try: continue ... or + try: ... except: continue */ + if (c->u->u_fblock[i].fb_type == FINALLY_END) + return compiler_error(c, IN_FINALLY_ERROR_MSG); + } + if (i == -1) + return compiler_error(c, LOOP_ERROR_MSG); + ADDOP_JABS(c, CONTINUE_LOOP, c->u->u_fblock[i].fb_block); + break; + case FINALLY_END: + return compiler_error(c, IN_FINALLY_ERROR_MSG); + } + + return 1; +} + +/* Code generated for "try: <body> finally: <finalbody>" is as follows: + + SETUP_FINALLY L + <code for body> + POP_BLOCK + LOAD_CONST <None> + L: <code for finalbody> + END_FINALLY + + The special instructions use the block stack. Each block + stack entry contains the instruction that created it (here + SETUP_FINALLY), the level of the value stack at the time the + block stack entry was created, and a label (here L). + + SETUP_FINALLY: + Pushes the current value stack level and the label + onto the block stack. + POP_BLOCK: + Pops en entry from the block stack, and pops the value + stack until its level is the same as indicated on the + block stack. (The label is ignored.) + END_FINALLY: + Pops a variable number of entries from the *value* stack + and re-raises the exception they specify. The number of + entries popped depends on the (pseudo) exception type. + + The block stack is unwound when an exception is raised: + when a SETUP_FINALLY entry is found, the exception is pushed + onto the value stack (and the exception condition is cleared), + and the interpreter jumps to the label gotten from the block + stack. +*/ + +static int +compiler_try_finally(struct compiler *c, stmt_ty s) +{ + basicblock *body, *end; + body = compiler_new_block(c); + end = compiler_new_block(c); + if (body == NULL || end == NULL) + return 0; + + ADDOP_JREL(c, SETUP_FINALLY, end); + compiler_use_next_block(c, body); + if (!compiler_push_fblock(c, FINALLY_TRY, body)) + return 0; + VISIT_SEQ(c, stmt, s->v.TryFinally.body); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, FINALLY_TRY, body); + + ADDOP_O(c, LOAD_CONST, Py_None, consts); + compiler_use_next_block(c, end); + if (!compiler_push_fblock(c, FINALLY_END, end)) + return 0; + VISIT_SEQ(c, stmt, s->v.TryFinally.finalbody); + ADDOP(c, END_FINALLY); + compiler_pop_fblock(c, FINALLY_END, end); + + return 1; +} + +/* + Code generated for "try: S except E1, V1: S1 except E2, V2: S2 ...": + (The contents of the value stack is shown in [], with the top + at the right; 'tb' is trace-back info, 'val' the exception's + associated value, and 'exc' the exception.) + + Value stack Label Instruction Argument + [] SETUP_EXCEPT L1 + [] <code for S> + [] POP_BLOCK + [] JUMP_FORWARD L0 + + [tb, val, exc] L1: DUP ) + [tb, val, exc, exc] <evaluate E1> ) + [tb, val, exc, exc, E1] COMPARE_OP EXC_MATCH ) only if E1 + [tb, val, exc, 1-or-0] JUMP_IF_FALSE L2 ) + [tb, val, exc, 1] POP ) + [tb, val, exc] POP + [tb, val] <assign to V1> (or POP if no V1) + [tb] POP + [] <code for S1> + JUMP_FORWARD L0 + + [tb, val, exc, 0] L2: POP + [tb, val, exc] DUP + .............................etc....................... + + [tb, val, exc, 0] Ln+1: POP + [tb, val, exc] END_FINALLY # re-raise exception + + [] L0: <next statement> + + Of course, parts are not generated if Vi or Ei is not present. +*/ +static int +compiler_try_except(struct compiler *c, stmt_ty s) +{ + basicblock *body, *orelse, *except, *end; + int i, n; + + body = compiler_new_block(c); + except = compiler_new_block(c); + orelse = compiler_new_block(c); + end = compiler_new_block(c); + if (body == NULL || except == NULL || orelse == NULL || end == NULL) + return 0; + ADDOP_JREL(c, SETUP_EXCEPT, except); + compiler_use_next_block(c, body); + if (!compiler_push_fblock(c, EXCEPT, body)) + return 0; + VISIT_SEQ(c, stmt, s->v.TryExcept.body); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, EXCEPT, body); + ADDOP_JREL(c, JUMP_FORWARD, orelse); + n = asdl_seq_LEN(s->v.TryExcept.handlers); + compiler_use_next_block(c, except); + for (i = 0; i < n; i++) { + excepthandler_ty handler = (excepthandler_ty)asdl_seq_GET( + s->v.TryExcept.handlers, i); + if (!handler->type && i < n-1) + return compiler_error(c, "default 'except:' must be last"); + c->u->u_lineno_set = false; + c->u->u_lineno = handler->lineno; + except = compiler_new_block(c); + if (except == NULL) + return 0; + if (handler->type) { + ADDOP(c, DUP_TOP); + VISIT(c, expr, handler->type); + ADDOP_I(c, COMPARE_OP, PyCmp_EXC_MATCH); + ADDOP_JREL(c, JUMP_IF_FALSE, except); + ADDOP(c, POP_TOP); + } + ADDOP(c, POP_TOP); + if (handler->name) { + VISIT(c, expr, handler->name); + } + else { + ADDOP(c, POP_TOP); + } + ADDOP(c, POP_TOP); + VISIT_SEQ(c, stmt, handler->body); + ADDOP_JREL(c, JUMP_FORWARD, end); + compiler_use_next_block(c, except); + if (handler->type) + ADDOP(c, POP_TOP); + } + ADDOP(c, END_FINALLY); + compiler_use_next_block(c, orelse); + VISIT_SEQ(c, stmt, s->v.TryExcept.orelse); + compiler_use_next_block(c, end); + return 1; +} + +static int +compiler_import_as(struct compiler *c, identifier name, identifier asname) +{ + /* The IMPORT_NAME opcode was already generated. This function + merely needs to bind the result to a name. + + If there is a dot in name, we need to split it and emit a + LOAD_ATTR for each name. + */ + const char *src = PyString_AS_STRING(name); + const char *dot = strchr(src, '.'); + if (dot) { + /* Consume the base module name to get the first attribute */ + src = dot + 1; + while (dot) { + /* NB src is only defined when dot != NULL */ + PyObject *attr; + dot = strchr(src, '.'); + attr = PyString_FromStringAndSize(src, + dot ? dot - src : strlen(src)); + if (!attr) + return -1; + ADDOP_O(c, LOAD_ATTR, attr, names); + Py_DECREF(attr); + src = dot + 1; + } + } + return compiler_nameop(c, asname, Store); +} + +static int +compiler_import(struct compiler *c, stmt_ty s) +{ + /* The Import node stores a module name like a.b.c as a single + string. This is convenient for all cases except + import a.b.c as d + where we need to parse that string to extract the individual + module names. + XXX Perhaps change the representation to make this case simpler? + */ + int i, n = asdl_seq_LEN(s->v.Import.names); + + for (i = 0; i < n; i++) { + alias_ty alias = (alias_ty)asdl_seq_GET(s->v.Import.names, i); + int r; + PyObject *level; + + if (c->c_flags && (c->c_flags->cf_flags & CO_FUTURE_ABSOLUTE_IMPORT)) + level = PyInt_FromLong(0); + else + level = PyInt_FromLong(-1); + + if (level == NULL) + return 0; + + ADDOP_O(c, LOAD_CONST, level, consts); + Py_DECREF(level); + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP_NAME(c, IMPORT_NAME, alias->name, names); + + if (alias->asname) { + r = compiler_import_as(c, alias->name, alias->asname); + if (!r) + return r; + } + else { + identifier tmp = alias->name; + const char *base = PyString_AS_STRING(alias->name); + char *dot = strchr(base, '.'); + if (dot) + tmp = PyString_FromStringAndSize(base, + dot - base); + r = compiler_nameop(c, tmp, Store); + if (dot) { + Py_DECREF(tmp); + } + if (!r) + return r; + } + } + return 1; +} + +static int +compiler_from_import(struct compiler *c, stmt_ty s) +{ + int i, n = asdl_seq_LEN(s->v.ImportFrom.names); + + PyObject *names = PyTuple_New(n); + PyObject *level; + + if (!names) + return 0; + + if (s->v.ImportFrom.level == 0 && c->c_flags && + !(c->c_flags->cf_flags & CO_FUTURE_ABSOLUTE_IMPORT)) + level = PyInt_FromLong(-1); + else + level = PyInt_FromLong(s->v.ImportFrom.level); + + if (!level) { + Py_DECREF(names); + return 0; + } + + /* build up the names */ + for (i = 0; i < n; i++) { + alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); + Py_INCREF(alias->name); + PyTuple_SET_ITEM(names, i, alias->name); + } + + if (s->lineno > c->c_future->ff_lineno) { + if (!strcmp(PyString_AS_STRING(s->v.ImportFrom.module), + "__future__")) { + Py_DECREF(level); + Py_DECREF(names); + return compiler_error(c, + "from __future__ imports must occur " + "at the beginning of the file"); + + } + } + + ADDOP_O(c, LOAD_CONST, level, consts); + Py_DECREF(level); + ADDOP_O(c, LOAD_CONST, names, consts); + Py_DECREF(names); + ADDOP_NAME(c, IMPORT_NAME, s->v.ImportFrom.module, names); + for (i = 0; i < n; i++) { + alias_ty alias = (alias_ty)asdl_seq_GET(s->v.ImportFrom.names, i); + identifier store_name; + + if (i == 0 && *PyString_AS_STRING(alias->name) == '*') { + assert(n == 1); + ADDOP(c, IMPORT_STAR); + return 1; + } + + ADDOP_NAME(c, IMPORT_FROM, alias->name, names); + store_name = alias->name; + if (alias->asname) + store_name = alias->asname; + + if (!compiler_nameop(c, store_name, Store)) { + Py_DECREF(names); + return 0; + } + } + /* remove imported module */ + ADDOP(c, POP_TOP); + return 1; +} + +static int +compiler_assert(struct compiler *c, stmt_ty s) +{ + static PyObject *assertion_error = NULL; + basicblock *end; + + if (Py_OptimizeFlag) + return 1; + if (assertion_error == NULL) { + assertion_error = PyString_FromString("AssertionError"); + if (assertion_error == NULL) + return 0; + } + VISIT(c, expr, s->v.Assert.test); + end = compiler_new_block(c); + if (end == NULL) + return 0; + ADDOP_JREL(c, JUMP_IF_TRUE, end); + ADDOP(c, POP_TOP); + ADDOP_O(c, LOAD_GLOBAL, assertion_error, names); + if (s->v.Assert.msg) { + VISIT(c, expr, s->v.Assert.msg); + ADDOP_I(c, RAISE_VARARGS, 2); + } + else { + ADDOP_I(c, RAISE_VARARGS, 1); + } + compiler_use_next_block(c, end); + ADDOP(c, POP_TOP); + return 1; +} + +static int +compiler_visit_stmt(struct compiler *c, stmt_ty s) +{ + int i, n; + + /* Always assign a lineno to the next instruction for a stmt. */ + c->u->u_lineno = s->lineno; + c->u->u_lineno_set = false; + + switch (s->kind) { + case FunctionDef_kind: + return compiler_function(c, s); + case ClassDef_kind: + return compiler_class(c, s); + case Return_kind: + if (c->u->u_ste->ste_type != FunctionBlock) + return compiler_error(c, "'return' outside function"); + if (s->v.Return.value) { + VISIT(c, expr, s->v.Return.value); + } + else + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP(c, RETURN_VALUE); + break; + case Delete_kind: + VISIT_SEQ(c, expr, s->v.Delete.targets) + break; + case Assign_kind: + n = asdl_seq_LEN(s->v.Assign.targets); + VISIT(c, expr, s->v.Assign.value); + for (i = 0; i < n; i++) { + if (i < n - 1) + ADDOP(c, DUP_TOP); + VISIT(c, expr, + (expr_ty)asdl_seq_GET(s->v.Assign.targets, i)); + } + break; + case AugAssign_kind: + return compiler_augassign(c, s); + case Print_kind: + return compiler_print(c, s); + case For_kind: + return compiler_for(c, s); + case While_kind: + return compiler_while(c, s); + case If_kind: + return compiler_if(c, s); + case Raise_kind: + n = 0; + if (s->v.Raise.type) { + VISIT(c, expr, s->v.Raise.type); + n++; + if (s->v.Raise.inst) { + VISIT(c, expr, s->v.Raise.inst); + n++; + if (s->v.Raise.tback) { + VISIT(c, expr, s->v.Raise.tback); + n++; + } + } + } + ADDOP_I(c, RAISE_VARARGS, n); + break; + case TryExcept_kind: + return compiler_try_except(c, s); + case TryFinally_kind: + return compiler_try_finally(c, s); + case Assert_kind: + return compiler_assert(c, s); + case Import_kind: + return compiler_import(c, s); + case ImportFrom_kind: + return compiler_from_import(c, s); + case Exec_kind: + VISIT(c, expr, s->v.Exec.body); + if (s->v.Exec.globals) { + VISIT(c, expr, s->v.Exec.globals); + if (s->v.Exec.locals) { + VISIT(c, expr, s->v.Exec.locals); + } else { + ADDOP(c, DUP_TOP); + } + } else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP(c, DUP_TOP); + } + ADDOP(c, EXEC_STMT); + break; + case Global_kind: + break; + case Expr_kind: + if (c->c_interactive && c->c_nestlevel <= 1) { + VISIT(c, expr, s->v.Expr.value); + ADDOP(c, PRINT_EXPR); + } + else if (s->v.Expr.value->kind != Str_kind && + s->v.Expr.value->kind != Num_kind) { + VISIT(c, expr, s->v.Expr.value); + ADDOP(c, POP_TOP); + } + break; + case Pass_kind: + break; + case Break_kind: + if (!compiler_in_loop(c)) + return compiler_error(c, "'break' outside loop"); + ADDOP(c, BREAK_LOOP); + break; + case Continue_kind: + return compiler_continue(c); + case With_kind: + return compiler_with(c, s); + } + return 1; +} + +static int +unaryop(unaryop_ty op) +{ + switch (op) { + case Invert: + return UNARY_INVERT; + case Not: + return UNARY_NOT; + case UAdd: + return UNARY_POSITIVE; + case USub: + return UNARY_NEGATIVE; + } + return 0; +} + +static int +binop(struct compiler *c, operator_ty op) +{ + switch (op) { + case Add: + return BINARY_ADD; + case Sub: + return BINARY_SUBTRACT; + case Mult: + return BINARY_MULTIPLY; + case Div: + if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION) + return BINARY_TRUE_DIVIDE; + else + return BINARY_DIVIDE; + case Mod: + return BINARY_MODULO; + case Pow: + return BINARY_POWER; + case LShift: + return BINARY_LSHIFT; + case RShift: + return BINARY_RSHIFT; + case BitOr: + return BINARY_OR; + case BitXor: + return BINARY_XOR; + case BitAnd: + return BINARY_AND; + case FloorDiv: + return BINARY_FLOOR_DIVIDE; + } + return 0; +} + +static int +cmpop(cmpop_ty op) +{ + switch (op) { + case Eq: + return PyCmp_EQ; + case NotEq: + return PyCmp_NE; + case Lt: + return PyCmp_LT; + case LtE: + return PyCmp_LE; + case Gt: + return PyCmp_GT; + case GtE: + return PyCmp_GE; + case Is: + return PyCmp_IS; + case IsNot: + return PyCmp_IS_NOT; + case In: + return PyCmp_IN; + case NotIn: + return PyCmp_NOT_IN; + } + return PyCmp_BAD; +} + +static int +inplace_binop(struct compiler *c, operator_ty op) +{ + switch (op) { + case Add: + return INPLACE_ADD; + case Sub: + return INPLACE_SUBTRACT; + case Mult: + return INPLACE_MULTIPLY; + case Div: + if (c->c_flags && c->c_flags->cf_flags & CO_FUTURE_DIVISION) + return INPLACE_TRUE_DIVIDE; + else + return INPLACE_DIVIDE; + case Mod: + return INPLACE_MODULO; + case Pow: + return INPLACE_POWER; + case LShift: + return INPLACE_LSHIFT; + case RShift: + return INPLACE_RSHIFT; + case BitOr: + return INPLACE_OR; + case BitXor: + return INPLACE_XOR; + case BitAnd: + return INPLACE_AND; + case FloorDiv: + return INPLACE_FLOOR_DIVIDE; + } + PyErr_Format(PyExc_SystemError, + "inplace binary op %d should not be possible", op); + return 0; +} + +static int +compiler_nameop(struct compiler *c, identifier name, expr_context_ty ctx) +{ + int op, scope, arg; + enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype; + + PyObject *dict = c->u->u_names; + PyObject *mangled; + /* XXX AugStore isn't used anywhere! */ + + /* First check for assignment to __debug__. Param? */ + if ((ctx == Store || ctx == AugStore || ctx == Del) + && !strcmp(PyString_AS_STRING(name), "__debug__")) { + return compiler_error(c, "can not assign to __debug__"); + } + + mangled = _Py_Mangle(c->u->u_private, name); + if (!mangled) + return 0; + + op = 0; + optype = OP_NAME; + scope = PyST_GetScope(c->u->u_ste, mangled); + switch (scope) { + case FREE: + dict = c->u->u_freevars; + optype = OP_DEREF; + break; + case CELL: + dict = c->u->u_cellvars; + optype = OP_DEREF; + break; + case LOCAL: + if (c->u->u_ste->ste_type == FunctionBlock) + optype = OP_FAST; + break; + case GLOBAL_IMPLICIT: + if (c->u->u_ste->ste_type == FunctionBlock && + !c->u->u_ste->ste_unoptimized) + optype = OP_GLOBAL; + break; + case GLOBAL_EXPLICIT: + optype = OP_GLOBAL; + break; + default: + /* scope can be 0 */ + break; + } + + /* XXX Leave assert here, but handle __doc__ and the like better */ + assert(scope || PyString_AS_STRING(name)[0] == '_'); + + switch (optype) { + case OP_DEREF: + switch (ctx) { + case Load: op = LOAD_DEREF; break; + case Store: op = STORE_DEREF; break; + case AugLoad: + case AugStore: + break; + case Del: + PyErr_Format(PyExc_SyntaxError, + "can not delete variable '%s' referenced " + "in nested scope", + PyString_AS_STRING(name)); + Py_DECREF(mangled); + return 0; + case Param: + default: + PyErr_SetString(PyExc_SystemError, + "param invalid for deref variable"); + return 0; + } + break; + case OP_FAST: + switch (ctx) { + case Load: op = LOAD_FAST; break; + case Store: op = STORE_FAST; break; + case Del: op = DELETE_FAST; break; + case AugLoad: + case AugStore: + break; + case Param: + default: + PyErr_SetString(PyExc_SystemError, + "param invalid for local variable"); + return 0; + } + ADDOP_O(c, op, mangled, varnames); + Py_DECREF(mangled); + return 1; + case OP_GLOBAL: + switch (ctx) { + case Load: op = LOAD_GLOBAL; break; + case Store: op = STORE_GLOBAL; break; + case Del: op = DELETE_GLOBAL; break; + case AugLoad: + case AugStore: + break; + case Param: + default: + PyErr_SetString(PyExc_SystemError, + "param invalid for global variable"); + return 0; + } + break; + case OP_NAME: + switch (ctx) { + case Load: op = LOAD_NAME; break; + case Store: op = STORE_NAME; break; + case Del: op = DELETE_NAME; break; + case AugLoad: + case AugStore: + break; + case Param: + default: + PyErr_SetString(PyExc_SystemError, + "param invalid for name variable"); + return 0; + } + break; + } + + assert(op); + arg = compiler_add_o(c, dict, mangled); + Py_DECREF(mangled); + if (arg < 0) + return 0; + return compiler_addop_i(c, op, arg); +} + +static int +compiler_boolop(struct compiler *c, expr_ty e) +{ + basicblock *end; + int jumpi, i, n; + asdl_seq *s; + + assert(e->kind == BoolOp_kind); + if (e->v.BoolOp.op == And) + jumpi = JUMP_IF_FALSE; + else + jumpi = JUMP_IF_TRUE; + end = compiler_new_block(c); + if (end == NULL) + return 0; + s = e->v.BoolOp.values; + n = asdl_seq_LEN(s) - 1; + assert(n >= 0); + for (i = 0; i < n; ++i) { + VISIT(c, expr, (expr_ty)asdl_seq_GET(s, i)); + ADDOP_JREL(c, jumpi, end); + ADDOP(c, POP_TOP) + } + VISIT(c, expr, (expr_ty)asdl_seq_GET(s, n)); + compiler_use_next_block(c, end); + return 1; +} + +static int +compiler_list(struct compiler *c, expr_ty e) +{ + int n = asdl_seq_LEN(e->v.List.elts); + if (e->v.List.ctx == Store) { + ADDOP_I(c, UNPACK_SEQUENCE, n); + } + VISIT_SEQ(c, expr, e->v.List.elts); + if (e->v.List.ctx == Load) { + ADDOP_I(c, BUILD_LIST, n); + } + return 1; +} + +static int +compiler_tuple(struct compiler *c, expr_ty e) +{ + int n = asdl_seq_LEN(e->v.Tuple.elts); + if (e->v.Tuple.ctx == Store) { + ADDOP_I(c, UNPACK_SEQUENCE, n); + } + VISIT_SEQ(c, expr, e->v.Tuple.elts); + if (e->v.Tuple.ctx == Load) { + ADDOP_I(c, BUILD_TUPLE, n); + } + return 1; +} + +static int +compiler_compare(struct compiler *c, expr_ty e) +{ + int i, n; + basicblock *cleanup = NULL; + + /* XXX the logic can be cleaned up for 1 or multiple comparisons */ + VISIT(c, expr, e->v.Compare.left); + n = asdl_seq_LEN(e->v.Compare.ops); + assert(n > 0); + if (n > 1) { + cleanup = compiler_new_block(c); + if (cleanup == NULL) + return 0; + VISIT(c, expr, + (expr_ty)asdl_seq_GET(e->v.Compare.comparators, 0)); + } + for (i = 1; i < n; i++) { + ADDOP(c, DUP_TOP); + ADDOP(c, ROT_THREE); + ADDOP_I(c, COMPARE_OP, + cmpop((cmpop_ty)(asdl_seq_GET( + e->v.Compare.ops, i - 1)))); + ADDOP_JREL(c, JUMP_IF_FALSE, cleanup); + NEXT_BLOCK(c); + ADDOP(c, POP_TOP); + if (i < (n - 1)) + VISIT(c, expr, + (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); + } + VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, n - 1)); + ADDOP_I(c, COMPARE_OP, + cmpop((cmpop_ty)(asdl_seq_GET(e->v.Compare.ops, n - 1)))); + if (n > 1) { + basicblock *end = compiler_new_block(c); + if (end == NULL) + return 0; + ADDOP_JREL(c, JUMP_FORWARD, end); + compiler_use_next_block(c, cleanup); + ADDOP(c, ROT_TWO); + ADDOP(c, POP_TOP); + compiler_use_next_block(c, end); + } + return 1; +} +#undef CMPCAST + +static int +compiler_call(struct compiler *c, expr_ty e) +{ + int n, code = 0; + + VISIT(c, expr, e->v.Call.func); + n = asdl_seq_LEN(e->v.Call.args); + VISIT_SEQ(c, expr, e->v.Call.args); + if (e->v.Call.keywords) { + VISIT_SEQ(c, keyword, e->v.Call.keywords); + n |= asdl_seq_LEN(e->v.Call.keywords) << 8; + } + if (e->v.Call.starargs) { + VISIT(c, expr, e->v.Call.starargs); + code |= 1; + } + if (e->v.Call.kwargs) { + VISIT(c, expr, e->v.Call.kwargs); + code |= 2; + } + switch (code) { + case 0: + ADDOP_I(c, CALL_FUNCTION, n); + break; + case 1: + ADDOP_I(c, CALL_FUNCTION_VAR, n); + break; + case 2: + ADDOP_I(c, CALL_FUNCTION_KW, n); + break; + case 3: + ADDOP_I(c, CALL_FUNCTION_VAR_KW, n); + break; + } + return 1; +} + +static int +compiler_listcomp_generator(struct compiler *c, PyObject *tmpname, + asdl_seq *generators, int gen_index, + expr_ty elt) +{ + /* generate code for the iterator, then each of the ifs, + and then write to the element */ + + comprehension_ty l; + basicblock *start, *anchor, *skip, *if_cleanup; + int i, n; + + start = compiler_new_block(c); + skip = compiler_new_block(c); + if_cleanup = compiler_new_block(c); + anchor = compiler_new_block(c); + + if (start == NULL || skip == NULL || if_cleanup == NULL || + anchor == NULL) + return 0; + + l = (comprehension_ty)asdl_seq_GET(generators, gen_index); + VISIT(c, expr, l->iter); + ADDOP(c, GET_ITER); + compiler_use_next_block(c, start); + ADDOP_JREL(c, FOR_ITER, anchor); + NEXT_BLOCK(c); + VISIT(c, expr, l->target); + + /* XXX this needs to be cleaned up...a lot! */ + n = asdl_seq_LEN(l->ifs); + for (i = 0; i < n; i++) { + expr_ty e = (expr_ty)asdl_seq_GET(l->ifs, i); + VISIT(c, expr, e); + ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); + NEXT_BLOCK(c); + ADDOP(c, POP_TOP); + } + + if (++gen_index < asdl_seq_LEN(generators)) + if (!compiler_listcomp_generator(c, tmpname, + generators, gen_index, elt)) + return 0; + + /* only append after the last for generator */ + if (gen_index >= asdl_seq_LEN(generators)) { + if (!compiler_nameop(c, tmpname, Load)) + return 0; + VISIT(c, expr, elt); + ADDOP(c, LIST_APPEND); + + compiler_use_next_block(c, skip); + } + for (i = 0; i < n; i++) { + ADDOP_I(c, JUMP_FORWARD, 1); + if (i == 0) + compiler_use_next_block(c, if_cleanup); + ADDOP(c, POP_TOP); + } + ADDOP_JABS(c, JUMP_ABSOLUTE, start); + compiler_use_next_block(c, anchor); + /* delete the append method added to locals */ + if (gen_index == 1) + if (!compiler_nameop(c, tmpname, Del)) + return 0; + + return 1; +} + +static int +compiler_listcomp(struct compiler *c, expr_ty e) +{ + identifier tmp; + int rc = 0; + static identifier append; + asdl_seq *generators = e->v.ListComp.generators; + + assert(e->kind == ListComp_kind); + if (!append) { + append = PyString_InternFromString("append"); + if (!append) + return 0; + } + tmp = compiler_new_tmpname(c); + if (!tmp) + return 0; + ADDOP_I(c, BUILD_LIST, 0); + ADDOP(c, DUP_TOP); + if (compiler_nameop(c, tmp, Store)) + rc = compiler_listcomp_generator(c, tmp, generators, 0, + e->v.ListComp.elt); + Py_DECREF(tmp); + return rc; +} + +static int +compiler_genexp_generator(struct compiler *c, + asdl_seq *generators, int gen_index, + expr_ty elt) +{ + /* generate code for the iterator, then each of the ifs, + and then write to the element */ + + comprehension_ty ge; + basicblock *start, *anchor, *skip, *if_cleanup, *end; + int i, n; + + start = compiler_new_block(c); + skip = compiler_new_block(c); + if_cleanup = compiler_new_block(c); + anchor = compiler_new_block(c); + end = compiler_new_block(c); + + if (start == NULL || skip == NULL || if_cleanup == NULL || + anchor == NULL || end == NULL) + return 0; + + ge = (comprehension_ty)asdl_seq_GET(generators, gen_index); + ADDOP_JREL(c, SETUP_LOOP, end); + if (!compiler_push_fblock(c, LOOP, start)) + return 0; + + if (gen_index == 0) { + /* Receive outermost iter as an implicit argument */ + c->u->u_argcount = 1; + ADDOP_I(c, LOAD_FAST, 0); + } + else { + /* Sub-iter - calculate on the fly */ + VISIT(c, expr, ge->iter); + ADDOP(c, GET_ITER); + } + compiler_use_next_block(c, start); + ADDOP_JREL(c, FOR_ITER, anchor); + NEXT_BLOCK(c); + VISIT(c, expr, ge->target); + + /* XXX this needs to be cleaned up...a lot! */ + n = asdl_seq_LEN(ge->ifs); + for (i = 0; i < n; i++) { + expr_ty e = (expr_ty)asdl_seq_GET(ge->ifs, i); + VISIT(c, expr, e); + ADDOP_JREL(c, JUMP_IF_FALSE, if_cleanup); + NEXT_BLOCK(c); + ADDOP(c, POP_TOP); + } + + if (++gen_index < asdl_seq_LEN(generators)) + if (!compiler_genexp_generator(c, generators, gen_index, elt)) + return 0; + + /* only append after the last 'for' generator */ + if (gen_index >= asdl_seq_LEN(generators)) { + VISIT(c, expr, elt); + ADDOP(c, YIELD_VALUE); + ADDOP(c, POP_TOP); + + compiler_use_next_block(c, skip); + } + for (i = 0; i < n; i++) { + ADDOP_I(c, JUMP_FORWARD, 1); + if (i == 0) + compiler_use_next_block(c, if_cleanup); + + ADDOP(c, POP_TOP); + } + ADDOP_JABS(c, JUMP_ABSOLUTE, start); + compiler_use_next_block(c, anchor); + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, LOOP, start); + compiler_use_next_block(c, end); + + return 1; +} + +static int +compiler_genexp(struct compiler *c, expr_ty e) +{ + static identifier name; + PyCodeObject *co; + expr_ty outermost_iter = ((comprehension_ty) + (asdl_seq_GET(e->v.GeneratorExp.generators, + 0)))->iter; + + if (!name) { + name = PyString_FromString("<genexpr>"); + if (!name) + return 0; + } + + if (!compiler_enter_scope(c, name, (void *)e, e->lineno)) + return 0; + compiler_genexp_generator(c, e->v.GeneratorExp.generators, 0, + e->v.GeneratorExp.elt); + co = assemble(c, 1); + compiler_exit_scope(c); + if (co == NULL) + return 0; + + compiler_make_closure(c, co, 0); + Py_DECREF(co); + + VISIT(c, expr, outermost_iter); + ADDOP(c, GET_ITER); + ADDOP_I(c, CALL_FUNCTION, 1); + + return 1; +} + +static int +compiler_visit_keyword(struct compiler *c, keyword_ty k) +{ + ADDOP_O(c, LOAD_CONST, k->arg, consts); + VISIT(c, expr, k->value); + return 1; +} + +/* Test whether expression is constant. For constants, report + whether they are true or false. + + Return values: 1 for true, 0 for false, -1 for non-constant. + */ + +static int +expr_constant(expr_ty e) +{ + switch (e->kind) { + case Num_kind: + return PyObject_IsTrue(e->v.Num.n); + case Str_kind: + return PyObject_IsTrue(e->v.Str.s); + case Name_kind: + /* __debug__ is not assignable, so we can optimize + * it away in if and while statements */ + if (strcmp(PyString_AS_STRING(e->v.Name.id), + "__debug__") == 0) + return ! Py_OptimizeFlag; + /* fall through */ + default: + return -1; + } +} + +/* + Implements the with statement from PEP 343. + + The semantics outlined in that PEP are as follows: + + with EXPR as VAR: + BLOCK + + It is implemented roughly as: + + context = EXPR + exit = context.__exit__ # not calling it + value = context.__enter__() + try: + VAR = value # if VAR present in the syntax + BLOCK + finally: + if an exception was raised: + exc = copy of (exception, instance, traceback) + else: + exc = (None, None, None) + exit(*exc) + */ +static int +compiler_with(struct compiler *c, stmt_ty s) +{ + static identifier enter_attr, exit_attr; + basicblock *block, *finally; + identifier tmpexit, tmpvalue = NULL; + + assert(s->kind == With_kind); + + if (!enter_attr) { + enter_attr = PyString_InternFromString("__enter__"); + if (!enter_attr) + return 0; + } + if (!exit_attr) { + exit_attr = PyString_InternFromString("__exit__"); + if (!exit_attr) + return 0; + } + + block = compiler_new_block(c); + finally = compiler_new_block(c); + if (!block || !finally) + return 0; + + /* Create a temporary variable to hold context.__exit__ */ + tmpexit = compiler_new_tmpname(c); + if (tmpexit == NULL) + return 0; + PyArena_AddPyObject(c->c_arena, tmpexit); + + if (s->v.With.optional_vars) { + /* Create a temporary variable to hold context.__enter__(). + We need to do this rather than preserving it on the stack + because SETUP_FINALLY remembers the stack level. + We need to do the assignment *inside* the try/finally + so that context.__exit__() is called when the assignment + fails. But we need to call context.__enter__() *before* + the try/finally so that if it fails we won't call + context.__exit__(). + */ + tmpvalue = compiler_new_tmpname(c); + if (tmpvalue == NULL) + return 0; + PyArena_AddPyObject(c->c_arena, tmpvalue); + } + + /* Evaluate EXPR */ + VISIT(c, expr, s->v.With.context_expr); + + /* Squirrel away context.__exit__ */ + ADDOP(c, DUP_TOP); + ADDOP_O(c, LOAD_ATTR, exit_attr, names); + if (!compiler_nameop(c, tmpexit, Store)) + return 0; + + /* Call context.__enter__() */ + ADDOP_O(c, LOAD_ATTR, enter_attr, names); + ADDOP_I(c, CALL_FUNCTION, 0); + + if (s->v.With.optional_vars) { + /* Store it in tmpvalue */ + if (!compiler_nameop(c, tmpvalue, Store)) + return 0; + } + else { + /* Discard result from context.__enter__() */ + ADDOP(c, POP_TOP); + } + + /* Start the try block */ + ADDOP_JREL(c, SETUP_FINALLY, finally); + + compiler_use_next_block(c, block); + if (!compiler_push_fblock(c, FINALLY_TRY, block)) { + return 0; + } + + if (s->v.With.optional_vars) { + /* Bind saved result of context.__enter__() to VAR */ + if (!compiler_nameop(c, tmpvalue, Load) || + !compiler_nameop(c, tmpvalue, Del)) + return 0; + VISIT(c, expr, s->v.With.optional_vars); + } + + /* BLOCK code */ + VISIT_SEQ(c, stmt, s->v.With.body); + + /* End of try block; start the finally block */ + ADDOP(c, POP_BLOCK); + compiler_pop_fblock(c, FINALLY_TRY, block); + + ADDOP_O(c, LOAD_CONST, Py_None, consts); + compiler_use_next_block(c, finally); + if (!compiler_push_fblock(c, FINALLY_END, finally)) + return 0; + + /* Finally block starts; push tmpexit and issue our magic opcode. */ + if (!compiler_nameop(c, tmpexit, Load) || + !compiler_nameop(c, tmpexit, Del)) + return 0; + ADDOP(c, WITH_CLEANUP); + + /* Finally block ends. */ + ADDOP(c, END_FINALLY); + compiler_pop_fblock(c, FINALLY_END, finally); + return 1; +} + +static int +compiler_visit_expr(struct compiler *c, expr_ty e) +{ + int i, n; + + /* If expr e has a different line number than the last expr/stmt, + set a new line number for the next instruction. + */ + if (e->lineno > c->u->u_lineno) { + c->u->u_lineno = e->lineno; + c->u->u_lineno_set = false; + } + switch (e->kind) { + case BoolOp_kind: + return compiler_boolop(c, e); + case BinOp_kind: + VISIT(c, expr, e->v.BinOp.left); + VISIT(c, expr, e->v.BinOp.right); + ADDOP(c, binop(c, e->v.BinOp.op)); + break; + case UnaryOp_kind: + VISIT(c, expr, e->v.UnaryOp.operand); + ADDOP(c, unaryop(e->v.UnaryOp.op)); + break; + case Lambda_kind: + return compiler_lambda(c, e); + case IfExp_kind: + return compiler_ifexp(c, e); + case Dict_kind: + /* XXX get rid of arg? */ + ADDOP_I(c, BUILD_MAP, 0); + n = asdl_seq_LEN(e->v.Dict.values); + /* We must arrange things just right for STORE_SUBSCR. + It wants the stack to look like (value) (dict) (key) */ + for (i = 0; i < n; i++) { + ADDOP(c, DUP_TOP); + VISIT(c, expr, + (expr_ty)asdl_seq_GET(e->v.Dict.values, i)); + ADDOP(c, ROT_TWO); + VISIT(c, expr, + (expr_ty)asdl_seq_GET(e->v.Dict.keys, i)); + ADDOP(c, STORE_SUBSCR); + } + break; + case ListComp_kind: + return compiler_listcomp(c, e); + case GeneratorExp_kind: + return compiler_genexp(c, e); + case Yield_kind: + if (c->u->u_ste->ste_type != FunctionBlock) + return compiler_error(c, "'yield' outside function"); + /* + for (i = 0; i < c->u->u_nfblocks; i++) { + if (c->u->u_fblock[i].fb_type == FINALLY_TRY) + return compiler_error( + c, "'yield' not allowed in a 'try' " + "block with a 'finally' clause"); + } + */ + if (e->v.Yield.value) { + VISIT(c, expr, e->v.Yield.value); + } + else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + } + ADDOP(c, YIELD_VALUE); + break; + case Compare_kind: + return compiler_compare(c, e); + case Call_kind: + return compiler_call(c, e); + case Repr_kind: + VISIT(c, expr, e->v.Repr.value); + ADDOP(c, UNARY_CONVERT); + break; + case Num_kind: + ADDOP_O(c, LOAD_CONST, e->v.Num.n, consts); + break; + case Str_kind: + ADDOP_O(c, LOAD_CONST, e->v.Str.s, consts); + break; + /* The following exprs can be assignment targets. */ + case Attribute_kind: + if (e->v.Attribute.ctx != AugStore) + VISIT(c, expr, e->v.Attribute.value); + switch (e->v.Attribute.ctx) { + case AugLoad: + ADDOP(c, DUP_TOP); + /* Fall through to load */ + case Load: + ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names); + break; + case AugStore: + ADDOP(c, ROT_TWO); + /* Fall through to save */ + case Store: + ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); + break; + case Del: + ADDOP_NAME(c, DELETE_ATTR, e->v.Attribute.attr, names); + break; + case Param: + default: + PyErr_SetString(PyExc_SystemError, + "param invalid in attribute expression"); + return 0; + } + break; + case Subscript_kind: + switch (e->v.Subscript.ctx) { + case AugLoad: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, AugLoad); + break; + case Load: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, Load); + break; + case AugStore: + VISIT_SLICE(c, e->v.Subscript.slice, AugStore); + break; + case Store: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, Store); + break; + case Del: + VISIT(c, expr, e->v.Subscript.value); + VISIT_SLICE(c, e->v.Subscript.slice, Del); + break; + case Param: + default: + PyErr_SetString(PyExc_SystemError, + "param invalid in subscript expression"); + return 0; + } + break; + case Name_kind: + return compiler_nameop(c, e->v.Name.id, e->v.Name.ctx); + /* child nodes of List and Tuple will have expr_context set */ + case List_kind: + return compiler_list(c, e); + case Tuple_kind: + return compiler_tuple(c, e); + } + return 1; +} + +static int +compiler_augassign(struct compiler *c, stmt_ty s) +{ + expr_ty e = s->v.AugAssign.target; + expr_ty auge; + + assert(s->kind == AugAssign_kind); + + switch (e->kind) { + case Attribute_kind: + auge = Attribute(e->v.Attribute.value, e->v.Attribute.attr, + AugLoad, e->lineno, e->col_offset, c->c_arena); + if (auge == NULL) + return 0; + VISIT(c, expr, auge); + VISIT(c, expr, s->v.AugAssign.value); + ADDOP(c, inplace_binop(c, s->v.AugAssign.op)); + auge->v.Attribute.ctx = AugStore; + VISIT(c, expr, auge); + break; + case Subscript_kind: + auge = Subscript(e->v.Subscript.value, e->v.Subscript.slice, + AugLoad, e->lineno, e->col_offset, c->c_arena); + if (auge == NULL) + return 0; + VISIT(c, expr, auge); + VISIT(c, expr, s->v.AugAssign.value); + ADDOP(c, inplace_binop(c, s->v.AugAssign.op)); + auge->v.Subscript.ctx = AugStore; + VISIT(c, expr, auge); + break; + case Name_kind: + if (!compiler_nameop(c, e->v.Name.id, Load)) + return 0; + VISIT(c, expr, s->v.AugAssign.value); + ADDOP(c, inplace_binop(c, s->v.AugAssign.op)); + return compiler_nameop(c, e->v.Name.id, Store); + default: + PyErr_Format(PyExc_SystemError, + "invalid node type (%d) for augmented assignment", + e->kind); + return 0; + } + return 1; +} + +static int +compiler_push_fblock(struct compiler *c, enum fblocktype t, basicblock *b) +{ + struct fblockinfo *f; + if (c->u->u_nfblocks >= CO_MAXBLOCKS) { + PyErr_SetString(PyExc_SystemError, + "too many statically nested blocks"); + return 0; + } + f = &c->u->u_fblock[c->u->u_nfblocks++]; + f->fb_type = t; + f->fb_block = b; + return 1; +} + +static void +compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b) +{ + struct compiler_unit *u = c->u; + assert(u->u_nfblocks > 0); + u->u_nfblocks--; + assert(u->u_fblock[u->u_nfblocks].fb_type == t); + assert(u->u_fblock[u->u_nfblocks].fb_block == b); +} + +static int +compiler_in_loop(struct compiler *c) { + int i; + struct compiler_unit *u = c->u; + for (i = 0; i < u->u_nfblocks; ++i) { + if (u->u_fblock[i].fb_type == LOOP) + return 1; + } + return 0; +} +/* Raises a SyntaxError and returns 0. + If something goes wrong, a different exception may be raised. +*/ + +static int +compiler_error(struct compiler *c, const char *errstr) +{ + PyObject *loc; + PyObject *u = NULL, *v = NULL; + + loc = PyErr_ProgramText(c->c_filename, c->u->u_lineno); + if (!loc) { + Py_INCREF(Py_None); + loc = Py_None; + } + u = Py_BuildValue("(ziOO)", c->c_filename, c->u->u_lineno, + Py_None, loc); + if (!u) + goto exit; + v = Py_BuildValue("(zO)", errstr, u); + if (!v) + goto exit; + PyErr_SetObject(PyExc_SyntaxError, v); + exit: + Py_DECREF(loc); + Py_XDECREF(u); + Py_XDECREF(v); + return 0; +} + +static int +compiler_handle_subscr(struct compiler *c, const char *kind, + expr_context_ty ctx) +{ + int op = 0; + + /* XXX this code is duplicated */ + switch (ctx) { + case AugLoad: /* fall through to Load */ + case Load: op = BINARY_SUBSCR; break; + case AugStore:/* fall through to Store */ + case Store: op = STORE_SUBSCR; break; + case Del: op = DELETE_SUBSCR; break; + case Param: + PyErr_Format(PyExc_SystemError, + "invalid %s kind %d in subscript\n", + kind, ctx); + return 0; + } + if (ctx == AugLoad) { + ADDOP_I(c, DUP_TOPX, 2); + } + else if (ctx == AugStore) { + ADDOP(c, ROT_THREE); + } + ADDOP(c, op); + return 1; +} + +static int +compiler_slice(struct compiler *c, slice_ty s, expr_context_ty ctx) +{ + int n = 2; + assert(s->kind == Slice_kind); + + /* only handles the cases where BUILD_SLICE is emitted */ + if (s->v.Slice.lower) { + VISIT(c, expr, s->v.Slice.lower); + } + else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + } + + if (s->v.Slice.upper) { + VISIT(c, expr, s->v.Slice.upper); + } + else { + ADDOP_O(c, LOAD_CONST, Py_None, consts); + } + + if (s->v.Slice.step) { + n++; + VISIT(c, expr, s->v.Slice.step); + } + ADDOP_I(c, BUILD_SLICE, n); + return 1; +} + +static int +compiler_simple_slice(struct compiler *c, slice_ty s, expr_context_ty ctx) +{ + int op = 0, slice_offset = 0, stack_count = 0; + + assert(s->v.Slice.step == NULL); + if (s->v.Slice.lower) { + slice_offset++; + stack_count++; + if (ctx != AugStore) + VISIT(c, expr, s->v.Slice.lower); + } + if (s->v.Slice.upper) { + slice_offset += 2; + stack_count++; + if (ctx != AugStore) + VISIT(c, expr, s->v.Slice.upper); + } + + if (ctx == AugLoad) { + switch (stack_count) { + case 0: ADDOP(c, DUP_TOP); break; + case 1: ADDOP_I(c, DUP_TOPX, 2); break; + case 2: ADDOP_I(c, DUP_TOPX, 3); break; + } + } + else if (ctx == AugStore) { + switch (stack_count) { + case 0: ADDOP(c, ROT_TWO); break; + case 1: ADDOP(c, ROT_THREE); break; + case 2: ADDOP(c, ROT_FOUR); break; + } + } + + switch (ctx) { + case AugLoad: /* fall through to Load */ + case Load: op = SLICE; break; + case AugStore:/* fall through to Store */ + case Store: op = STORE_SLICE; break; + case Del: op = DELETE_SLICE; break; + case Param: + default: + PyErr_SetString(PyExc_SystemError, + "param invalid in simple slice"); + return 0; + } + + ADDOP(c, op + slice_offset); + return 1; +} + +static int +compiler_visit_nested_slice(struct compiler *c, slice_ty s, + expr_context_ty ctx) +{ + switch (s->kind) { + case Ellipsis_kind: + ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts); + break; + case Slice_kind: + return compiler_slice(c, s, ctx); + case Index_kind: + VISIT(c, expr, s->v.Index.value); + break; + case ExtSlice_kind: + default: + PyErr_SetString(PyExc_SystemError, + "extended slice invalid in nested slice"); + return 0; + } + return 1; +} + + +static int +compiler_visit_slice(struct compiler *c, slice_ty s, expr_context_ty ctx) +{ + char * kindname = NULL; + switch (s->kind) { + case Index_kind: + kindname = "index"; + if (ctx != AugStore) { + VISIT(c, expr, s->v.Index.value); + } + break; + case Ellipsis_kind: + kindname = "ellipsis"; + if (ctx != AugStore) { + ADDOP_O(c, LOAD_CONST, Py_Ellipsis, consts); + } + break; + case Slice_kind: + kindname = "slice"; + if (!s->v.Slice.step) + return compiler_simple_slice(c, s, ctx); + if (ctx != AugStore) { + if (!compiler_slice(c, s, ctx)) + return 0; + } + break; + case ExtSlice_kind: + kindname = "extended slice"; + if (ctx != AugStore) { + int i, n = asdl_seq_LEN(s->v.ExtSlice.dims); + for (i = 0; i < n; i++) { + slice_ty sub = (slice_ty)asdl_seq_GET( + s->v.ExtSlice.dims, i); + if (!compiler_visit_nested_slice(c, sub, ctx)) + return 0; + } + ADDOP_I(c, BUILD_TUPLE, n); + } + break; + default: + PyErr_Format(PyExc_SystemError, + "invalid subscript kind %d", s->kind); + return 0; + } + return compiler_handle_subscr(c, kindname, ctx); +} + +/* do depth-first search of basic block graph, starting with block. + post records the block indices in post-order. + + XXX must handle implicit jumps from one block to next +*/ + +static void +dfs(struct compiler *c, basicblock *b, struct assembler *a) +{ + int i; + struct instr *instr = NULL; + + if (b->b_seen) + return; + b->b_seen = 1; + if (b->b_next != NULL) + dfs(c, b->b_next, a); + for (i = 0; i < b->b_iused; i++) { + instr = &b->b_instr[i]; + if (instr->i_jrel || instr->i_jabs) + dfs(c, instr->i_target, a); + } + a->a_postorder[a->a_nblocks++] = b; +} + +static int +stackdepth_walk(struct compiler *c, basicblock *b, int depth, int maxdepth) +{ + int i; + struct instr *instr; + if (b->b_seen || b->b_startdepth >= depth) + return maxdepth; + b->b_seen = 1; + b->b_startdepth = depth; + for (i = 0; i < b->b_iused; i++) { + instr = &b->b_instr[i]; + depth += opcode_stack_effect(instr->i_opcode, instr->i_oparg); + if (depth > maxdepth) + maxdepth = depth; + assert(depth >= 0); /* invalid code or bug in stackdepth() */ + if (instr->i_jrel || instr->i_jabs) { + maxdepth = stackdepth_walk(c, instr->i_target, + depth, maxdepth); + if (instr->i_opcode == JUMP_ABSOLUTE || + instr->i_opcode == JUMP_FORWARD) { + goto out; /* remaining code is dead */ + } + } + } + if (b->b_next) + maxdepth = stackdepth_walk(c, b->b_next, depth, maxdepth); +out: + b->b_seen = 0; + return maxdepth; +} + +/* Find the flow path that needs the largest stack. We assume that + * cycles in the flow graph have no net effect on the stack depth. + */ +static int +stackdepth(struct compiler *c) +{ + basicblock *b, *entryblock; + entryblock = NULL; + for (b = c->u->u_blocks; b != NULL; b = b->b_list) { + b->b_seen = 0; + b->b_startdepth = INT_MIN; + entryblock = b; + } + if (!entryblock) + return 0; + return stackdepth_walk(c, entryblock, 0, 0); +} + +static int +assemble_init(struct assembler *a, int nblocks, int firstlineno) +{ + memset(a, 0, sizeof(struct assembler)); + a->a_lineno = firstlineno; + a->a_bytecode = PyString_FromStringAndSize(NULL, DEFAULT_CODE_SIZE); + if (!a->a_bytecode) + return 0; + a->a_lnotab = PyString_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE); + if (!a->a_lnotab) + return 0; + a->a_postorder = (basicblock **)PyObject_Malloc( + sizeof(basicblock *) * nblocks); + if (!a->a_postorder) { + PyErr_NoMemory(); + return 0; + } + return 1; +} + +static void +assemble_free(struct assembler *a) +{ + Py_XDECREF(a->a_bytecode); + Py_XDECREF(a->a_lnotab); + if (a->a_postorder) + PyObject_Free(a->a_postorder); +} + +/* Return the size of a basic block in bytes. */ + +static int +instrsize(struct instr *instr) +{ + if (!instr->i_hasarg) + return 1; + if (instr->i_oparg > 0xffff) + return 6; + return 3; +} + +static int +blocksize(basicblock *b) +{ + int i; + int size = 0; + + for (i = 0; i < b->b_iused; i++) + size += instrsize(&b->b_instr[i]); + return size; +} + +/* All about a_lnotab. + +c_lnotab is an array of unsigned bytes disguised as a Python string. +It is used to map bytecode offsets to source code line #s (when needed +for tracebacks). + +The array is conceptually a list of + (bytecode offset increment, line number increment) +pairs. The details are important and delicate, best illustrated by example: + + byte code offset source code line number + 0 1 + 6 2 + 50 7 + 350 307 + 361 308 + +The first trick is that these numbers aren't stored, only the increments +from one row to the next (this doesn't really work, but it's a start): + + 0, 1, 6, 1, 44, 5, 300, 300, 11, 1 + +The second trick is that an unsigned byte can't hold negative values, or +values larger than 255, so (a) there's a deep assumption that byte code +offsets and their corresponding line #s both increase monotonically, and (b) +if at least one column jumps by more than 255 from one row to the next, more +than one pair is written to the table. In case #b, there's no way to know +from looking at the table later how many were written. That's the delicate +part. A user of c_lnotab desiring to find the source line number +corresponding to a bytecode address A should do something like this + + lineno = addr = 0 + for addr_incr, line_incr in c_lnotab: + addr += addr_incr + if addr > A: + return lineno + lineno += line_incr + +In order for this to work, when the addr field increments by more than 255, +the line # increment in each pair generated must be 0 until the remaining addr +increment is < 256. So, in the example above, assemble_lnotab (it used +to be called com_set_lineno) should not (as was actually done until 2.2) +expand 300, 300 to 255, 255, 45, 45, + but to 255, 0, 45, 255, 0, 45. +*/ + +static int +assemble_lnotab(struct assembler *a, struct instr *i) +{ + int d_bytecode, d_lineno; + int len; + unsigned char *lnotab; + + d_bytecode = a->a_offset - a->a_lineno_off; + d_lineno = i->i_lineno - a->a_lineno; + + assert(d_bytecode >= 0); + assert(d_lineno >= 0); + + /* XXX(nnorwitz): is there a better way to handle this? + for loops are special, we want to be able to trace them + each time around, so we need to set an extra line number. */ + if (d_lineno == 0 && i->i_opcode != FOR_ITER) + return 1; + + if (d_bytecode > 255) { + int j, nbytes, ncodes = d_bytecode / 255; + nbytes = a->a_lnotab_off + 2 * ncodes; + len = PyString_GET_SIZE(a->a_lnotab); + if (nbytes >= len) { + if (len * 2 < nbytes) + len = nbytes; + else + len *= 2; + if (_PyString_Resize(&a->a_lnotab, len) < 0) + return 0; + } + lnotab = (unsigned char *) + PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + for (j = 0; j < ncodes; j++) { + *lnotab++ = 255; + *lnotab++ = 0; + } + d_bytecode -= ncodes * 255; + a->a_lnotab_off += ncodes * 2; + } + assert(d_bytecode <= 255); + if (d_lineno > 255) { + int j, nbytes, ncodes = d_lineno / 255; + nbytes = a->a_lnotab_off + 2 * ncodes; + len = PyString_GET_SIZE(a->a_lnotab); + if (nbytes >= len) { + if (len * 2 < nbytes) + len = nbytes; + else + len *= 2; + if (_PyString_Resize(&a->a_lnotab, len) < 0) + return 0; + } + lnotab = (unsigned char *) + PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + *lnotab++ = d_bytecode; + *lnotab++ = 255; + d_bytecode = 0; + for (j = 1; j < ncodes; j++) { + *lnotab++ = 0; + *lnotab++ = 255; + } + d_lineno -= ncodes * 255; + a->a_lnotab_off += ncodes * 2; + } + + len = PyString_GET_SIZE(a->a_lnotab); + if (a->a_lnotab_off + 2 >= len) { + if (_PyString_Resize(&a->a_lnotab, len * 2) < 0) + return 0; + } + lnotab = (unsigned char *) + PyString_AS_STRING(a->a_lnotab) + a->a_lnotab_off; + + a->a_lnotab_off += 2; + if (d_bytecode) { + *lnotab++ = d_bytecode; + *lnotab++ = d_lineno; + } + else { /* First line of a block; def stmt, etc. */ + *lnotab++ = 0; + *lnotab++ = d_lineno; + } + a->a_lineno = i->i_lineno; + a->a_lineno_off = a->a_offset; + return 1; +} + +/* assemble_emit() + Extend the bytecode with a new instruction. + Update lnotab if necessary. +*/ + +static int +assemble_emit(struct assembler *a, struct instr *i) +{ + int size, arg = 0, ext = 0; + Py_ssize_t len = PyString_GET_SIZE(a->a_bytecode); + char *code; + + size = instrsize(i); + if (i->i_hasarg) { + arg = i->i_oparg; + ext = arg >> 16; + } + if (i->i_lineno && !assemble_lnotab(a, i)) + return 0; + if (a->a_offset + size >= len) { + if (_PyString_Resize(&a->a_bytecode, len * 2) < 0) + return 0; + } + code = PyString_AS_STRING(a->a_bytecode) + a->a_offset; + a->a_offset += size; + if (size == 6) { + assert(i->i_hasarg); + *code++ = (char)EXTENDED_ARG; + *code++ = ext & 0xff; + *code++ = ext >> 8; + arg &= 0xffff; + } + *code++ = i->i_opcode; + if (i->i_hasarg) { + assert(size == 3 || size == 6); + *code++ = arg & 0xff; + *code++ = arg >> 8; + } + return 1; +} + +static void +assemble_jump_offsets(struct assembler *a, struct compiler *c) +{ + basicblock *b; + int bsize, totsize, extended_arg_count, last_extended_arg_count = 0; + int i; + + /* Compute the size of each block and fixup jump args. + Replace block pointer with position in bytecode. */ +start: + totsize = 0; + for (i = a->a_nblocks - 1; i >= 0; i--) { + b = a->a_postorder[i]; + bsize = blocksize(b); + b->b_offset = totsize; + totsize += bsize; + } + extended_arg_count = 0; + for (b = c->u->u_blocks; b != NULL; b = b->b_list) { + bsize = b->b_offset; + for (i = 0; i < b->b_iused; i++) { + struct instr *instr = &b->b_instr[i]; + /* Relative jumps are computed relative to + the instruction pointer after fetching + the jump instruction. + */ + bsize += instrsize(instr); + if (instr->i_jabs) + instr->i_oparg = instr->i_target->b_offset; + else if (instr->i_jrel) { + int delta = instr->i_target->b_offset - bsize; + instr->i_oparg = delta; + } + else + continue; + if (instr->i_oparg > 0xffff) + extended_arg_count++; + } + } + + /* XXX: This is an awful hack that could hurt performance, but + on the bright side it should work until we come up + with a better solution. + + In the meantime, should the goto be dropped in favor + of a loop? + + The issue is that in the first loop blocksize() is called + which calls instrsize() which requires i_oparg be set + appropriately. There is a bootstrap problem because + i_oparg is calculated in the second loop above. + + So we loop until we stop seeing new EXTENDED_ARGs. + The only EXTENDED_ARGs that could be popping up are + ones in jump instructions. So this should converge + fairly quickly. + */ + if (last_extended_arg_count != extended_arg_count) { + last_extended_arg_count = extended_arg_count; + goto start; + } +} + +static PyObject * +dict_keys_inorder(PyObject *dict, int offset) +{ + PyObject *tuple, *k, *v; + Py_ssize_t i, pos = 0, size = PyDict_Size(dict); + + tuple = PyTuple_New(size); + if (tuple == NULL) + return NULL; + while (PyDict_Next(dict, &pos, &k, &v)) { + i = PyInt_AS_LONG(v); + k = PyTuple_GET_ITEM(k, 0); + Py_INCREF(k); + assert((i - offset) < size); + assert((i - offset) >= 0); + PyTuple_SET_ITEM(tuple, i - offset, k); + } + return tuple; +} + +static int +compute_code_flags(struct compiler *c) +{ + PySTEntryObject *ste = c->u->u_ste; + int flags = 0, n; + if (ste->ste_type != ModuleBlock) + flags |= CO_NEWLOCALS; + if (ste->ste_type == FunctionBlock) { + if (!ste->ste_unoptimized) + flags |= CO_OPTIMIZED; + if (ste->ste_nested) + flags |= CO_NESTED; + if (ste->ste_generator) + flags |= CO_GENERATOR; + } + if (ste->ste_varargs) + flags |= CO_VARARGS; + if (ste->ste_varkeywords) + flags |= CO_VARKEYWORDS; + if (ste->ste_generator) + flags |= CO_GENERATOR; + + /* (Only) inherit compilerflags in PyCF_MASK */ + flags |= (c->c_flags->cf_flags & PyCF_MASK); + + n = PyDict_Size(c->u->u_freevars); + if (n < 0) + return -1; + if (n == 0) { + n = PyDict_Size(c->u->u_cellvars); + if (n < 0) + return -1; + if (n == 0) { + flags |= CO_NOFREE; + } + } + + return flags; +} + +static PyCodeObject * +makecode(struct compiler *c, struct assembler *a) +{ + PyObject *tmp; + PyCodeObject *co = NULL; + PyObject *consts = NULL; + PyObject *names = NULL; + PyObject *varnames = NULL; + PyObject *filename = NULL; + PyObject *name = NULL; + PyObject *freevars = NULL; + PyObject *cellvars = NULL; + PyObject *bytecode = NULL; + int nlocals, flags; + + tmp = dict_keys_inorder(c->u->u_consts, 0); + if (!tmp) + goto error; + consts = PySequence_List(tmp); /* optimize_code requires a list */ + Py_DECREF(tmp); + + names = dict_keys_inorder(c->u->u_names, 0); + varnames = dict_keys_inorder(c->u->u_varnames, 0); + if (!consts || !names || !varnames) + goto error; + + cellvars = dict_keys_inorder(c->u->u_cellvars, 0); + if (!cellvars) + goto error; + freevars = dict_keys_inorder(c->u->u_freevars, PyTuple_Size(cellvars)); + if (!freevars) + goto error; + filename = PyString_FromString(c->c_filename); + if (!filename) + goto error; + + nlocals = PyDict_Size(c->u->u_varnames); + flags = compute_code_flags(c); + if (flags < 0) + goto error; + + bytecode = optimize_code(a->a_bytecode, consts, names, a->a_lnotab); + if (!bytecode) + goto error; + + tmp = PyList_AsTuple(consts); /* PyCode_New requires a tuple */ + if (!tmp) + goto error; + Py_DECREF(consts); + consts = tmp; + + co = PyCode_New(c->u->u_argcount, nlocals, stackdepth(c), flags, + bytecode, consts, names, varnames, + freevars, cellvars, + filename, c->u->u_name, + c->u->u_firstlineno, + a->a_lnotab); + error: + Py_XDECREF(consts); + Py_XDECREF(names); + Py_XDECREF(varnames); + Py_XDECREF(filename); + Py_XDECREF(name); + Py_XDECREF(freevars); + Py_XDECREF(cellvars); + Py_XDECREF(bytecode); + return co; +} + + +/* For debugging purposes only */ +#if 0 +static void +dump_instr(const struct instr *i) +{ + const char *jrel = i->i_jrel ? "jrel " : ""; + const char *jabs = i->i_jabs ? "jabs " : ""; + char arg[128]; + + *arg = '\0'; + if (i->i_hasarg) + sprintf(arg, "arg: %d ", i->i_oparg); + + fprintf(stderr, "line: %d, opcode: %d %s%s%s\n", + i->i_lineno, i->i_opcode, arg, jabs, jrel); +} + +static void +dump_basicblock(const basicblock *b) +{ + const char *seen = b->b_seen ? "seen " : ""; + const char *b_return = b->b_return ? "return " : ""; + fprintf(stderr, "used: %d, depth: %d, offset: %d %s%s\n", + b->b_iused, b->b_startdepth, b->b_offset, seen, b_return); + if (b->b_instr) { + int i; + for (i = 0; i < b->b_iused; i++) { + fprintf(stderr, " [%02d] ", i); + dump_instr(b->b_instr + i); + } + } +} +#endif + +static PyCodeObject * +assemble(struct compiler *c, int addNone) +{ + basicblock *b, *entryblock; + struct assembler a; + int i, j, nblocks; + PyCodeObject *co = NULL; + + /* Make sure every block that falls off the end returns None. + XXX NEXT_BLOCK() isn't quite right, because if the last + block ends with a jump or return b_next shouldn't set. + */ + if (!c->u->u_curblock->b_return) { + NEXT_BLOCK(c); + if (addNone) + ADDOP_O(c, LOAD_CONST, Py_None, consts); + ADDOP(c, RETURN_VALUE); + } + + nblocks = 0; + entryblock = NULL; + for (b = c->u->u_blocks; b != NULL; b = b->b_list) { + nblocks++; + entryblock = b; + } + + /* Set firstlineno if it wasn't explicitly set. */ + if (!c->u->u_firstlineno) { + if (entryblock && entryblock->b_instr) + c->u->u_firstlineno = entryblock->b_instr->i_lineno; + else + c->u->u_firstlineno = 1; + } + if (!assemble_init(&a, nblocks, c->u->u_firstlineno)) + goto error; + dfs(c, entryblock, &a); + + /* Can't modify the bytecode after computing jump offsets. */ + assemble_jump_offsets(&a, c); + + /* Emit code in reverse postorder from dfs. */ + for (i = a.a_nblocks - 1; i >= 0; i--) { + b = a.a_postorder[i]; + for (j = 0; j < b->b_iused; j++) + if (!assemble_emit(&a, &b->b_instr[j])) + goto error; + } + + if (_PyString_Resize(&a.a_lnotab, a.a_lnotab_off) < 0) + goto error; + if (_PyString_Resize(&a.a_bytecode, a.a_offset) < 0) + goto error; + + co = makecode(c, &a); + error: + assemble_free(&a); + return co; +} diff --git a/sys/src/cmd/python/Python/dup2.c b/sys/src/cmd/python/Python/dup2.c new file mode 100644 index 000000000..ba7413a0c --- /dev/null +++ b/sys/src/cmd/python/Python/dup2.c @@ -0,0 +1,30 @@ +/* + * Public domain dup2() lookalike + * by Curtis Jackson @ AT&T Technologies, Burlington, NC + * electronic address: burl!rcj + * + * dup2 performs the following functions: + * + * Check to make sure that fd1 is a valid open file descriptor. + * Check to see if fd2 is already open; if so, close it. + * Duplicate fd1 onto fd2; checking to make sure fd2 is a valid fd. + * Return fd2 if all went well; return BADEXIT otherwise. + */ + +#include <fcntl.h> + +#define BADEXIT -1 + +int +dup2(int fd1, int fd2) +{ + if (fd1 != fd2) { + if (fcntl(fd1, F_GETFL) < 0) + return BADEXIT; + if (fcntl(fd2, F_GETFL) >= 0) + close(fd2); + if (fcntl(fd1, F_DUPFD, fd2) < 0) + return BADEXIT; + } + return fd2; +} diff --git a/sys/src/cmd/python/Python/dynload_aix.c b/sys/src/cmd/python/Python/dynload_aix.c new file mode 100644 index 000000000..7a604f223 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_aix.c @@ -0,0 +1,183 @@ + +/* Support for dynamic loading of extension modules */ + +#include "Python.h" +#include "importdl.h" + +#include <ctype.h> /* for isdigit() */ +#include <errno.h> /* for global errno */ +#include <string.h> /* for strerror() */ +#include <stdlib.h> /* for malloc(), free() */ +#include <sys/ldr.h> + + +#ifdef AIX_GENUINE_CPLUSPLUS +#include "/usr/lpp/xlC/include/load.h" +#define aix_load loadAndInit +#else +#define aix_load load +#endif + + +extern char *Py_GetProgramName(void); + +typedef struct Module { + struct Module *next; + void *entry; +} Module, *ModulePtr; + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {".so", "rb", C_EXTENSION}, + {"module.so", "rb", C_EXTENSION}, + {0, 0} +}; + +static int +aix_getoldmodules(void **modlistptr) +{ + register ModulePtr modptr, prevmodptr; + register struct ld_info *ldiptr; + register char *ldibuf; + register int errflag, bufsize = 1024; + register unsigned int offset; + char *progname = Py_GetProgramName(); + + /* + -- Get the list of loaded modules into ld_info structures. + */ + if ((ldibuf = malloc(bufsize)) == NULL) { + PyErr_SetString(PyExc_ImportError, strerror(errno)); + return -1; + } + while ((errflag = loadquery(L_GETINFO, ldibuf, bufsize)) == -1 + && errno == ENOMEM) { + free(ldibuf); + bufsize += 1024; + if ((ldibuf = malloc(bufsize)) == NULL) { + PyErr_SetString(PyExc_ImportError, strerror(errno)); + return -1; + } + } + if (errflag == -1) { + PyErr_SetString(PyExc_ImportError, strerror(errno)); + return -1; + } + /* + -- Make the modules list from the ld_info structures. + */ + ldiptr = (struct ld_info *)ldibuf; + prevmodptr = NULL; + do { + if (strstr(progname, ldiptr->ldinfo_filename) == NULL && + strstr(ldiptr->ldinfo_filename, "python") == NULL) { + /* + -- Extract only the modules belonging to the main + -- executable + those containing "python" as a + -- substring (like the "python[version]" binary or + -- "libpython[version].a" in case it's a shared lib). + */ + offset = (unsigned int)ldiptr->ldinfo_next; + ldiptr = (struct ld_info *)((char*)ldiptr + offset); + continue; + } + if ((modptr = (ModulePtr)malloc(sizeof(Module))) == NULL) { + PyErr_SetString(PyExc_ImportError, strerror(errno)); + while (*modlistptr) { + modptr = (ModulePtr)*modlistptr; + *modlistptr = (void *)modptr->next; + free(modptr); + } + return -1; + } + modptr->entry = ldiptr->ldinfo_dataorg; + modptr->next = NULL; + if (prevmodptr == NULL) + *modlistptr = (void *)modptr; + else + prevmodptr->next = modptr; + prevmodptr = modptr; + offset = (unsigned int)ldiptr->ldinfo_next; + ldiptr = (struct ld_info *)((char*)ldiptr + offset); + } while (offset); + free(ldibuf); + return 0; +} + + +static void +aix_loaderror(const char *pathname) +{ + + char *message[1024], errbuf[1024]; + register int i,j; + + struct errtab { + int errNo; + char *errstr; + } load_errtab[] = { + {L_ERROR_TOOMANY, "too many errors, rest skipped."}, + {L_ERROR_NOLIB, "can't load library:"}, + {L_ERROR_UNDEF, "can't find symbol in library:"}, + {L_ERROR_RLDBAD, + "RLD index out of range or bad relocation type:"}, + {L_ERROR_FORMAT, "not a valid, executable xcoff file:"}, + {L_ERROR_MEMBER, + "file not an archive or does not contain requested member:"}, + {L_ERROR_TYPE, "symbol table mismatch:"}, + {L_ERROR_ALIGN, "text alignment in file is wrong."}, + {L_ERROR_SYSTEM, "System error:"}, + {L_ERROR_ERRNO, NULL} + }; + +#define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0])) +#define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1) + + PyOS_snprintf(errbuf, sizeof(errbuf), "from module %.200s ", pathname); + + if (!loadquery(L_GETMESSAGES, &message[0], sizeof(message))) { + ERRBUF_APPEND(strerror(errno)); + ERRBUF_APPEND("\n"); + } + for(i = 0; message[i] && *message[i]; i++) { + int nerr = atoi(message[i]); + for (j=0; j<LOAD_ERRTAB_LEN ; j++) { + if (nerr == load_errtab[j].errNo && load_errtab[j].errstr) + ERRBUF_APPEND(load_errtab[j].errstr); + } + while (isdigit(Py_CHARMASK(*message[i]))) message[i]++ ; + ERRBUF_APPEND(message[i]); + ERRBUF_APPEND("\n"); + } + errbuf[strlen(errbuf)-1] = '\0'; /* trim off last newline */ + PyErr_SetString(PyExc_ImportError, errbuf); + return; +} + + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + dl_funcptr p; + + /* + -- Invoke load() with L_NOAUTODEFER leaving the imported symbols + -- of the shared module unresolved. Thus we have to resolve them + -- explicitly with loadbind. The new module is loaded, then we + -- resolve its symbols using the list of already loaded modules + -- (only those that belong to the python executable). Get these + -- with loadquery(L_GETINFO). + */ + + static void *staticmodlistptr = NULL; + + if (!staticmodlistptr) + if (aix_getoldmodules(&staticmodlistptr) == -1) + return NULL; + p = (dl_funcptr) aix_load((char *)pathname, L_NOAUTODEFER, 0); + if (p == NULL) { + aix_loaderror(pathname); + return NULL; + } + + return p; +} diff --git a/sys/src/cmd/python/Python/dynload_atheos.c b/sys/src/cmd/python/Python/dynload_atheos.c new file mode 100644 index 000000000..6f4df73c3 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_atheos.c @@ -0,0 +1,47 @@ + +/* Support for dynamic loading of extension modules */ + +#include <atheos/image.h> +#include <errno.h> + +#include "Python.h" +#include "importdl.h" + + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {".so", "rb", C_EXTENSION}, + {"module.so", "rb", C_EXTENSION}, + {0, 0} +}; + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + void *p; + int lib; + char funcname[258]; + + if (Py_VerboseFlag) + printf("load_library %s\n", pathname); + + lib = load_library(pathname, 0); + if (lib < 0) { + char buf[512]; + if (Py_VerboseFlag) + perror(pathname); + PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s: %.200s", + pathname, strerror(errno)); + PyErr_SetString(PyExc_ImportError, buf); + return NULL; + } + PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname); + if (Py_VerboseFlag) + printf("get_symbol_address %s\n", funcname); + if (get_symbol_address(lib, funcname, -1, &p) < 0) { + p = NULL; + if (Py_VerboseFlag) + perror(funcname); + } + + return (dl_funcptr) p; +} diff --git a/sys/src/cmd/python/Python/dynload_beos.c b/sys/src/cmd/python/Python/dynload_beos.c new file mode 100644 index 000000000..5b05d6b73 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_beos.c @@ -0,0 +1,254 @@ + +/* Support for dynamic loading of extension modules */ + +#include <kernel/image.h> +#include <kernel/OS.h> +#include <stdlib.h> + +#include "Python.h" +#include "importdl.h" + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {".so", "rb", C_EXTENSION}, + {"module.so", "rb", C_EXTENSION}, + {0, 0} +}; + +#if defined(MAXPATHLEN) && !defined(_SYS_PARAM_H) +#undef MAXPATHLEN +#endif + +#ifdef WITH_THREAD +#include "pythread.h" +static PyThread_type_lock beos_dyn_lock; +#endif + +static PyObject *beos_dyn_images = NULL; + +/* ---------------------------------------------------------------------- + * BeOS dynamic loading support + * + * This uses shared libraries, but BeOS has its own way of doing things + * (much easier than dlfnc.h, from the look of things). We'll use a + * Python Dictionary object to store the images_ids so we can be very + * nice and unload them when we exit. + * + * Note that this is thread-safe. Probably irrelevent, because of losing + * systems... Python probably disables threads while loading modules. + * Note the use of "probably"! Better to be safe than sorry. [chrish] + * + * As of 1.5.1 this should also work properly when you've configured + * Python without thread support; the 1.5 version required it, which wasn't + * very friendly. Note that I haven't tested it without threading... why + * would you want to avoid threads on BeOS? [chrish] + * + * As of 1.5.2, the PyImport_BeImageID() function has been removed; Donn + * tells me it's not necessary anymore because of PyCObject_Import(). + * [chrish] + */ + +/* Whack an item; the item is an image_id in disguise, so we'll call + * unload_add_on() for it. + */ +static void beos_nuke_dyn( PyObject *item ) +{ + status_t retval; + + if( item ) { + image_id id = (image_id)PyInt_AsLong( item ); + + retval = unload_add_on( id ); + } +} + +/* atexit() handler that'll call unload_add_on() for every item in the + * dictionary. + */ +static void beos_cleanup_dyn( void ) +{ + if( beos_dyn_images ) { + int idx; + int list_size; + PyObject *id_list; + +#ifdef WITH_THREAD + PyThread_acquire_lock( beos_dyn_lock, 1 ); +#endif + + id_list = PyDict_Values( beos_dyn_images ); + + list_size = PyList_Size( id_list ); + for( idx = 0; idx < list_size; idx++ ) { + PyObject *the_item; + + the_item = PyList_GetItem( id_list, idx ); + beos_nuke_dyn( the_item ); + } + + PyDict_Clear( beos_dyn_images ); + +#ifdef WITH_THREAD + PyThread_free_lock( beos_dyn_lock ); +#endif + } +} + +/* + * Initialize our dictionary, and the dictionary mutex. + */ +static void beos_init_dyn( void ) +{ + /* We're protected from a race condition here by the atomic init_count + * variable. + */ + static int32 init_count = 0; + int32 val; + + val = atomic_add( &init_count, 1 ); + if( beos_dyn_images == NULL && val == 0 ) { + beos_dyn_images = PyDict_New(); +#ifdef WITH_THREAD + beos_dyn_lock = PyThread_allocate_lock(); +#endif + atexit( beos_cleanup_dyn ); + } +} + +/* + * Add an image_id to the dictionary; the module name of the loaded image + * is the key. Note that if the key is already in the dict, we unload + * that image; this should allow reload() to work on dynamically loaded + * modules (super-keen!). + */ +static void beos_add_dyn( char *name, image_id id ) +{ + int retval; + PyObject *py_id; + + if( beos_dyn_images == NULL ) { + beos_init_dyn(); + } + +#ifdef WITH_THREAD + retval = PyThread_acquire_lock( beos_dyn_lock, 1 ); +#endif + + /* If there's already an object with this key in the dictionary, + * we're doing a reload(), so let's nuke it. + */ + py_id = PyDict_GetItemString( beos_dyn_images, name ); + if( py_id ) { + beos_nuke_dyn( py_id ); + retval = PyDict_DelItemString( beos_dyn_images, name ); + } + + py_id = PyInt_FromLong( (long)id ); + if( py_id ) { + retval = PyDict_SetItemString( beos_dyn_images, name, py_id ); + } + +#ifdef WITH_THREAD + PyThread_release_lock( beos_dyn_lock ); +#endif +} + + + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + dl_funcptr p; + image_id the_id; + status_t retval; + char fullpath[PATH_MAX]; + char funcname[258]; + + if( Py_VerboseFlag ) { + printf( "load_add_on( %s )\n", pathname ); + } + + /* Hmm, this old bug appears to have regenerated itself; if the + * path isn't absolute, load_add_on() will fail. Reported to Be + * April 21, 1998. + */ + if( pathname[0] != '/' ) { + (void)getcwd( fullpath, PATH_MAX ); + (void)strncat( fullpath, "/", PATH_MAX ); + (void)strncat( fullpath, pathname, PATH_MAX ); + + if( Py_VerboseFlag ) { + printf( "load_add_on( %s )\n", fullpath ); + } + } else { + (void)strcpy( fullpath, pathname ); + } + + the_id = load_add_on( fullpath ); + if( the_id < B_NO_ERROR ) { + /* It's too bad load_add_on() doesn't set errno or something... + */ + char buff[256]; /* hate hard-coded string sizes... */ + + if( Py_VerboseFlag ) { + printf( "load_add_on( %s ) failed", fullpath ); + } + + if( the_id == B_ERROR ) + PyOS_snprintf( buff, sizeof(buff), + "BeOS: Failed to load %.200s", + fullpath ); + else + PyOS_snprintf( buff, sizeof(buff), + "Unknown error loading %.200s", + fullpath ); + + PyErr_SetString( PyExc_ImportError, buff ); + return NULL; + } + + PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname); + if( Py_VerboseFlag ) { + printf( "get_image_symbol( %s )\n", funcname ); + } + + retval = get_image_symbol( the_id, funcname, B_SYMBOL_TYPE_TEXT, &p ); + if( retval != B_NO_ERROR || p == NULL ) { + /* That's bad, we can't find that symbol in the module... + */ + char buff[256]; /* hate hard-coded string sizes... */ + + if( Py_VerboseFlag ) { + printf( "get_image_symbol( %s ) failed", funcname ); + } + + switch( retval ) { + case B_BAD_IMAGE_ID: + PyOS_snprintf( buff, sizeof(buff), + "can't load init function for dynamic module: " + "Invalid image ID for %.180s", fullpath ); + break; + case B_BAD_INDEX: + PyOS_snprintf( buff, sizeof(buff), + "can't load init function for dynamic module: " + "Bad index for %.180s", funcname ); + break; + default: + PyOS_snprintf( buff, sizeof(buff), + "can't load init function for dynamic module: " + "Unknown error looking up %.180s", funcname ); + break; + } + + retval = unload_add_on( the_id ); + + PyErr_SetString( PyExc_ImportError, buff ); + return NULL; + } + + /* Save the module name and image ID for later so we can clean up + * gracefully. + */ + beos_add_dyn( fqname, the_id ); + + return p; +} diff --git a/sys/src/cmd/python/Python/dynload_dl.c b/sys/src/cmd/python/Python/dynload_dl.c new file mode 100644 index 000000000..4675a6722 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_dl.c @@ -0,0 +1,26 @@ + +/* Support for dynamic loading of extension modules */ + +#include "dl.h" + +#include "Python.h" +#include "importdl.h" + + +extern char *Py_GetProgramName(void); + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {".o", "rb", C_EXTENSION}, + {"module.o", "rb", C_EXTENSION}, + {0, 0} +}; + + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + char funcname[258]; + + PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname); + return dl_loadmod(Py_GetProgramName(), pathname, funcname); +} diff --git a/sys/src/cmd/python/Python/dynload_hpux.c b/sys/src/cmd/python/Python/dynload_hpux.c new file mode 100644 index 000000000..fec0826ca --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_hpux.c @@ -0,0 +1,58 @@ + +/* Support for dynamic loading of extension modules */ + +#include "dl.h" +#include <errno.h> + +#include "Python.h" +#include "importdl.h" + +#if defined(__hp9000s300) +#define FUNCNAME_PATTERN "_init%.200s" +#else +#define FUNCNAME_PATTERN "init%.200s" +#endif + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {SHLIB_EXT, "rb", C_EXTENSION}, + {"module"SHLIB_EXT, "rb", C_EXTENSION}, + {0, 0} +}; + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + dl_funcptr p; + shl_t lib; + int flags; + char funcname[258]; + + flags = BIND_FIRST | BIND_DEFERRED; + if (Py_VerboseFlag) { + flags = BIND_FIRST | BIND_IMMEDIATE | + BIND_NONFATAL | BIND_VERBOSE; + printf("shl_load %s\n",pathname); + } + lib = shl_load(pathname, flags, 0); + /* XXX Chuck Blake once wrote that 0 should be BIND_NOSTART? */ + if (lib == NULL) { + char buf[256]; + if (Py_VerboseFlag) + perror(pathname); + PyOS_snprintf(buf, sizeof(buf), "Failed to load %.200s", + pathname); + PyErr_SetString(PyExc_ImportError, buf); + return NULL; + } + PyOS_snprintf(funcname, sizeof(funcname), FUNCNAME_PATTERN, shortname); + if (Py_VerboseFlag) + printf("shl_findsym %s\n", funcname); + if (shl_findsym(&lib, funcname, TYPE_UNDEFINED, (void *) &p) == -1) { + shl_unload(lib); + p = NULL; + } + if (p == NULL && Py_VerboseFlag) + perror(funcname); + + return p; +} diff --git a/sys/src/cmd/python/Python/dynload_next.c b/sys/src/cmd/python/Python/dynload_next.c new file mode 100644 index 000000000..27df35696 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_next.c @@ -0,0 +1,114 @@ + +/* Support for dynamic loading of extension modules on Mac OS X +** All references to "NeXT" are for historical reasons. +*/ + +#include "Python.h" +#include "importdl.h" + +#include <mach-o/dyld.h> + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {".so", "rb", C_EXTENSION}, + {"module.so", "rb", C_EXTENSION}, + {0, 0} +}; + +/* +** Python modules are Mach-O MH_BUNDLE files. The best way to load these +** is each in a private namespace, so you can load, say, a module bar and a +** module foo.bar. If we load everything in the global namespace the two +** initbar() symbols will conflict. +** However, it seems some extension packages depend upon being able to access +** each others' global symbols. There seems to be no way to eat our cake and +** have it, so the USE_DYLD_GLOBAL_NAMESPACE define determines which behaviour +** you get. +*/ + +#ifdef USE_DYLD_GLOBAL_NAMESPACE +#define LINKOPTIONS NSLINKMODULE_OPTION_BINDNOW|NSLINKMODULE_OPTION_RETURN_ON_ERROR +#else +#define LINKOPTIONS NSLINKMODULE_OPTION_BINDNOW| \ + NSLINKMODULE_OPTION_RETURN_ON_ERROR|NSLINKMODULE_OPTION_PRIVATE +#endif +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + dl_funcptr p = NULL; + char funcname[258]; + NSObjectFileImageReturnCode rc; + NSObjectFileImage image; + NSModule newModule; + NSSymbol theSym; + const char *errString; + char errBuf[512]; + + PyOS_snprintf(funcname, sizeof(funcname), "_init%.200s", shortname); + +#ifdef USE_DYLD_GLOBAL_NAMESPACE + if (NSIsSymbolNameDefined(funcname)) { + theSym = NSLookupAndBindSymbol(funcname); + p = (dl_funcptr)NSAddressOfSymbol(theSym); + return p; + } +#endif + rc = NSCreateObjectFileImageFromFile(pathname, &image); + switch(rc) { + default: + case NSObjectFileImageFailure: + case NSObjectFileImageFormat: + /* for these a message is printed on stderr by dyld */ + errString = "Can't create object file image"; + break; + case NSObjectFileImageSuccess: + errString = NULL; + break; + case NSObjectFileImageInappropriateFile: + errString = "Inappropriate file type for dynamic loading"; + break; + case NSObjectFileImageArch: + errString = "Wrong CPU type in object file"; + break; + case NSObjectFileImageAccess: + errString = "Can't read object file (no access)"; + break; + } + if (errString == NULL) { + newModule = NSLinkModule(image, pathname, LINKOPTIONS); + if (newModule == NULL) { + int errNo; + const char *fileName, *moreErrorStr; + NSLinkEditErrors c; + NSLinkEditError( &c, &errNo, &fileName, &moreErrorStr ); + PyOS_snprintf(errBuf, 512, "Failure linking new module: %s: %s", + fileName, moreErrorStr); + errString = errBuf; + } + } + if (errString != NULL) { + PyErr_SetString(PyExc_ImportError, errString); + return NULL; + } +#ifdef USE_DYLD_GLOBAL_NAMESPACE + if (!NSIsSymbolNameDefined(funcname)) { + /* UnlinkModule() isn't implemented in current versions, but calling it does no harm */ + /* NSUnLinkModule(newModule, FALSE); removed: causes problems for ObjC code */ + PyErr_Format(PyExc_ImportError, + "Loaded module does not contain symbol %.200s", + funcname); + return NULL; + } + theSym = NSLookupAndBindSymbol(funcname); +#else + theSym = NSLookupSymbolInModule(newModule, funcname); + if ( theSym == NULL ) { + /* NSUnLinkModule(newModule, FALSE); removed: causes problems for ObjC code */ + PyErr_Format(PyExc_ImportError, + "Loaded module does not contain symbol %.200s", + funcname); + return NULL; + } +#endif + p = (dl_funcptr)NSAddressOfSymbol(theSym); + return p; +} diff --git a/sys/src/cmd/python/Python/dynload_os2.c b/sys/src/cmd/python/Python/dynload_os2.c new file mode 100644 index 000000000..d660e2750 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_os2.c @@ -0,0 +1,46 @@ + +/* Support for dynamic loading of extension modules */ + +#define INCL_DOSERRORS +#define INCL_DOSMODULEMGR +#include <os2.h> + +#include "Python.h" +#include "importdl.h" + + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {".pyd", "rb", C_EXTENSION}, + {".dll", "rb", C_EXTENSION}, + {0, 0} +}; + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + dl_funcptr p; + APIRET rc; + HMODULE hDLL; + char failreason[256]; + char funcname[258]; + + rc = DosLoadModule(failreason, + sizeof(failreason), + pathname, + &hDLL); + + if (rc != NO_ERROR) { + char errBuf[256]; + PyOS_snprintf(errBuf, sizeof(errBuf), + "DLL load failed, rc = %d: %.200s", + rc, failreason); + PyErr_SetString(PyExc_ImportError, errBuf); + return NULL; + } + + PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname); + rc = DosQueryProcAddr(hDLL, 0L, funcname, &p); + if (rc != NO_ERROR) + p = NULL; /* Signify Failure to Acquire Entrypoint */ + return p; +} diff --git a/sys/src/cmd/python/Python/dynload_shlib.c b/sys/src/cmd/python/Python/dynload_shlib.c new file mode 100644 index 000000000..f12a93cb5 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_shlib.c @@ -0,0 +1,143 @@ + +/* Support for dynamic loading of extension modules */ + +#include "Python.h" +#include "importdl.h" + +#include <sys/types.h> +#include <sys/stat.h> + +#if defined(__NetBSD__) +#include <sys/param.h> +#if (NetBSD < 199712) +#include <nlist.h> +#include <link.h> +#define dlerror() "error in dynamic linking" +#endif +#endif /* NetBSD */ + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#else +#if defined(PYOS_OS2) && defined(PYCC_GCC) +#include "dlfcn.h" +#endif +#endif + +#if (defined(__OpenBSD__) || defined(__NetBSD__)) && !defined(__ELF__) +#define LEAD_UNDERSCORE "_" +#else +#define LEAD_UNDERSCORE "" +#endif + + +const struct filedescr _PyImport_DynLoadFiletab[] = { +#ifdef __CYGWIN__ + {".dll", "rb", C_EXTENSION}, + {"module.dll", "rb", C_EXTENSION}, +#else +#if defined(PYOS_OS2) && defined(PYCC_GCC) + {".pyd", "rb", C_EXTENSION}, + {".dll", "rb", C_EXTENSION}, +#else +#ifdef __VMS + {".exe", "rb", C_EXTENSION}, + {".EXE", "rb", C_EXTENSION}, + {"module.exe", "rb", C_EXTENSION}, + {"MODULE.EXE", "rb", C_EXTENSION}, +#else + {".so", "rb", C_EXTENSION}, + {"module.so", "rb", C_EXTENSION}, +#endif +#endif +#endif + {0, 0} +}; + +static struct { + dev_t dev; +#ifdef __VMS + ino_t ino[3]; +#else + ino_t ino; +#endif + void *handle; +} handles[128]; +static int nhandles = 0; + + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + dl_funcptr p; + void *handle; + char funcname[258]; + char pathbuf[260]; + int dlopenflags=0; + + if (strchr(pathname, '/') == NULL) { + /* Prefix bare filename with "./" */ + PyOS_snprintf(pathbuf, sizeof(pathbuf), "./%-.255s", pathname); + pathname = pathbuf; + } + + PyOS_snprintf(funcname, sizeof(funcname), + LEAD_UNDERSCORE "init%.200s", shortname); + + if (fp != NULL) { + int i; + struct stat statb; + fstat(fileno(fp), &statb); + for (i = 0; i < nhandles; i++) { + if (statb.st_dev == handles[i].dev && + statb.st_ino == handles[i].ino) { + p = (dl_funcptr) dlsym(handles[i].handle, + funcname); + return p; + } + } + if (nhandles < 128) { + handles[nhandles].dev = statb.st_dev; +#ifdef __VMS + handles[nhandles].ino[0] = statb.st_ino[0]; + handles[nhandles].ino[1] = statb.st_ino[1]; + handles[nhandles].ino[2] = statb.st_ino[2]; +#else + handles[nhandles].ino = statb.st_ino; +#endif + } + } + +#if !(defined(PYOS_OS2) && defined(PYCC_GCC)) + dlopenflags = PyThreadState_GET()->interp->dlopenflags; +#endif + + if (Py_VerboseFlag) + PySys_WriteStderr("dlopen(\"%s\", %x);\n", pathname, + dlopenflags); + +#ifdef __VMS + /* VMS currently don't allow a pathname, use a logical name instead */ + /* Concatenate 'python_module_' and shortname */ + /* so "import vms.bar" will use the logical python_module_bar */ + /* As C module use only one name space this is probably not a */ + /* important limitation */ + PyOS_snprintf(pathbuf, sizeof(pathbuf), "python_module_%-.200s", + shortname); + pathname = pathbuf; +#endif + + handle = dlopen(pathname, dlopenflags); + + if (handle == NULL) { + const char *error = dlerror(); + if (error == NULL) + error = "unknown dlopen() error"; + PyErr_SetString(PyExc_ImportError, error); + return NULL; + } + if (fp != NULL && nhandles < 128) + handles[nhandles++].handle = handle; + p = (dl_funcptr) dlsym(handle, funcname); + return p; +} diff --git a/sys/src/cmd/python/Python/dynload_stub.c b/sys/src/cmd/python/Python/dynload_stub.c new file mode 100644 index 000000000..69f8b450b --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_stub.c @@ -0,0 +1,11 @@ + +/* This module provides the necessary stubs for when dynamic loading is + not present. */ + +#include "Python.h" +#include "importdl.h" + + +const struct filedescr _PyImport_DynLoadFiletab[] = { + {0, 0} +}; diff --git a/sys/src/cmd/python/Python/dynload_win.c b/sys/src/cmd/python/Python/dynload_win.c new file mode 100644 index 000000000..37d6d2ee3 --- /dev/null +++ b/sys/src/cmd/python/Python/dynload_win.c @@ -0,0 +1,263 @@ + +/* Support for dynamic loading of extension modules */ + +#include <windows.h> +#ifdef HAVE_DIRECT_H +#include <direct.h> +#endif +#include <ctype.h> + +#include "Python.h" +#include "importdl.h" + +const struct filedescr _PyImport_DynLoadFiletab[] = { +#ifdef _DEBUG + {"_d.pyd", "rb", C_EXTENSION}, + /* Temporarily disable .dll, to avoid conflicts between sqlite3.dll + and the sqlite3 package. If this needs to be reverted for 2.5, + some other solution for the naming conflict must be found. + {"_d.dll", "rb", C_EXTENSION}, + */ +#else + {".pyd", "rb", C_EXTENSION}, + /* Likewise + {".dll", "rb", C_EXTENSION}, + */ +#endif + {0, 0} +}; + + +/* Case insensitive string compare, to avoid any dependencies on particular + C RTL implementations */ + +static int strcasecmp (char *string1, char *string2) +{ + int first, second; + + do { + first = tolower(*string1); + second = tolower(*string2); + string1++; + string2++; + } while (first && first == second); + + return (first - second); +} + + +/* Function to return the name of the "python" DLL that the supplied module + directly imports. Looks through the list of imported modules and + returns the first entry that starts with "python" (case sensitive) and + is followed by nothing but numbers until the separator (period). + + Returns a pointer to the import name, or NULL if no matching name was + located. + + This function parses through the PE header for the module as loaded in + memory by the system loader. The PE header is accessed as documented by + Microsoft in the MSDN PE and COFF specification (2/99), and handles + both PE32 and PE32+. It only worries about the direct import table and + not the delay load import table since it's unlikely an extension is + going to be delay loading Python (after all, it's already loaded). + + If any magic values are not found (e.g., the PE header or optional + header magic), then this function simply returns NULL. */ + +#define DWORD_AT(mem) (*(DWORD *)(mem)) +#define WORD_AT(mem) (*(WORD *)(mem)) + +static char *GetPythonImport (HINSTANCE hModule) +{ + unsigned char *dllbase, *import_data, *import_name; + DWORD pe_offset, opt_offset; + WORD opt_magic; + int num_dict_off, import_off; + + /* Safety check input */ + if (hModule == NULL) { + return NULL; + } + + /* Module instance is also the base load address. First portion of + memory is the MS-DOS loader, which holds the offset to the PE + header (from the load base) at 0x3C */ + dllbase = (unsigned char *)hModule; + pe_offset = DWORD_AT(dllbase + 0x3C); + + /* The PE signature must be "PE\0\0" */ + if (memcmp(dllbase+pe_offset,"PE\0\0",4)) { + return NULL; + } + + /* Following the PE signature is the standard COFF header (20 + bytes) and then the optional header. The optional header starts + with a magic value of 0x10B for PE32 or 0x20B for PE32+ (PE32+ + uses 64-bits for some fields). It might also be 0x107 for a ROM + image, but we don't process that here. + + The optional header ends with a data dictionary that directly + points to certain types of data, among them the import entries + (in the second table entry). Based on the header type, we + determine offsets for the data dictionary count and the entry + within the dictionary pointing to the imports. */ + + opt_offset = pe_offset + 4 + 20; + opt_magic = WORD_AT(dllbase+opt_offset); + if (opt_magic == 0x10B) { + /* PE32 */ + num_dict_off = 92; + import_off = 104; + } else if (opt_magic == 0x20B) { + /* PE32+ */ + num_dict_off = 108; + import_off = 120; + } else { + /* Unsupported */ + return NULL; + } + + /* Now if an import table exists, offset to it and walk the list of + imports. The import table is an array (ending when an entry has + empty values) of structures (20 bytes each), which contains (at + offset 12) a relative address (to the module base) at which a + string constant holding the import name is located. */ + + if (DWORD_AT(dllbase + opt_offset + num_dict_off) >= 2) { + /* We have at least 2 tables - the import table is the second + one. But still it may be that the table size is zero */ + if (0 == DWORD_AT(dllbase + opt_offset + import_off + sizeof(DWORD))) + return NULL; + import_data = dllbase + DWORD_AT(dllbase + + opt_offset + + import_off); + while (DWORD_AT(import_data)) { + import_name = dllbase + DWORD_AT(import_data+12); + if (strlen(import_name) >= 6 && + !strncmp(import_name,"python",6)) { + char *pch; + + /* Ensure python prefix is followed only + by numbers to the end of the basename */ + pch = import_name + 6; +#ifdef _DEBUG + while (*pch && pch[0] != '_' && pch[1] != 'd' && pch[2] != '.') { +#else + while (*pch && *pch != '.') { +#endif + if (*pch >= '0' && *pch <= '9') { + pch++; + } else { + pch = NULL; + break; + } + } + + if (pch) { + /* Found it - return the name */ + return import_name; + } + } + import_data += 20; + } + } + + return NULL; +} + + +dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, + const char *pathname, FILE *fp) +{ + dl_funcptr p; + char funcname[258], *import_python; + + PyOS_snprintf(funcname, sizeof(funcname), "init%.200s", shortname); + + { + HINSTANCE hDLL = NULL; + char pathbuf[260]; + LPTSTR dummy; + /* We use LoadLibraryEx so Windows looks for dependent DLLs + in directory of pathname first. However, Windows95 + can sometimes not work correctly unless the absolute + path is used. If GetFullPathName() fails, the LoadLibrary + will certainly fail too, so use its error code */ + if (GetFullPathName(pathname, + sizeof(pathbuf), + pathbuf, + &dummy)) + /* XXX This call doesn't exist in Windows CE */ + hDLL = LoadLibraryEx(pathname, NULL, + LOAD_WITH_ALTERED_SEARCH_PATH); + if (hDLL==NULL){ + char errBuf[256]; + unsigned int errorCode; + + /* Get an error string from Win32 error code */ + char theInfo[256]; /* Pointer to error text + from system */ + int theLength; /* Length of error text */ + + errorCode = GetLastError(); + + theLength = FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM, /* flags */ + NULL, /* message source */ + errorCode, /* the message (error) ID */ + 0, /* default language environment */ + (LPTSTR) theInfo, /* the buffer */ + sizeof(theInfo), /* the buffer size */ + NULL); /* no additional format args. */ + + /* Problem: could not get the error message. + This should not happen if called correctly. */ + if (theLength == 0) { + PyOS_snprintf(errBuf, sizeof(errBuf), + "DLL load failed with error code %d", + errorCode); + } else { + size_t len; + /* For some reason a \r\n + is appended to the text */ + if (theLength >= 2 && + theInfo[theLength-2] == '\r' && + theInfo[theLength-1] == '\n') { + theLength -= 2; + theInfo[theLength] = '\0'; + } + strcpy(errBuf, "DLL load failed: "); + len = strlen(errBuf); + strncpy(errBuf+len, theInfo, + sizeof(errBuf)-len); + errBuf[sizeof(errBuf)-1] = '\0'; + } + PyErr_SetString(PyExc_ImportError, errBuf); + return NULL; + } else { + char buffer[256]; + +#ifdef _DEBUG + PyOS_snprintf(buffer, sizeof(buffer), "python%d%d_d.dll", +#else + PyOS_snprintf(buffer, sizeof(buffer), "python%d%d.dll", +#endif + PY_MAJOR_VERSION,PY_MINOR_VERSION); + import_python = GetPythonImport(hDLL); + + if (import_python && + strcasecmp(buffer,import_python)) { + PyOS_snprintf(buffer, sizeof(buffer), + "Module use of %.150s conflicts " + "with this version of Python.", + import_python); + PyErr_SetString(PyExc_ImportError,buffer); + FreeLibrary(hDLL); + return NULL; + } + } + p = GetProcAddress(hDLL, funcname); + } + + return p; +} diff --git a/sys/src/cmd/python/Python/errors.c b/sys/src/cmd/python/Python/errors.c new file mode 100644 index 000000000..bc77c3c1b --- /dev/null +++ b/sys/src/cmd/python/Python/errors.c @@ -0,0 +1,822 @@ + +/* Error handling */ + +#include "Python.h" + +#ifndef __STDC__ +#ifndef MS_WINDOWS +extern char *strerror(int); +#endif +#endif + +#ifdef MS_WINDOWS +#include "windows.h" +#include "winbase.h" +#endif + +#include <ctype.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +void +PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *oldtype, *oldvalue, *oldtraceback; + + if (traceback != NULL && !PyTraceBack_Check(traceback)) { + /* XXX Should never happen -- fatal error instead? */ + /* Well, it could be None. */ + Py_DECREF(traceback); + traceback = NULL; + } + + /* Save these in locals to safeguard against recursive + invocation through Py_XDECREF */ + oldtype = tstate->curexc_type; + oldvalue = tstate->curexc_value; + oldtraceback = tstate->curexc_traceback; + + tstate->curexc_type = type; + tstate->curexc_value = value; + tstate->curexc_traceback = traceback; + + Py_XDECREF(oldtype); + Py_XDECREF(oldvalue); + Py_XDECREF(oldtraceback); +} + +void +PyErr_SetObject(PyObject *exception, PyObject *value) +{ + Py_XINCREF(exception); + Py_XINCREF(value); + PyErr_Restore(exception, value, (PyObject *)NULL); +} + +void +PyErr_SetNone(PyObject *exception) +{ + PyErr_SetObject(exception, (PyObject *)NULL); +} + +void +PyErr_SetString(PyObject *exception, const char *string) +{ + PyObject *value = PyString_FromString(string); + PyErr_SetObject(exception, value); + Py_XDECREF(value); +} + + +PyObject * +PyErr_Occurred(void) +{ + PyThreadState *tstate = PyThreadState_GET(); + + return tstate->curexc_type; +} + + +int +PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc) +{ + if (err == NULL || exc == NULL) { + /* maybe caused by "import exceptions" that failed early on */ + return 0; + } + if (PyTuple_Check(exc)) { + Py_ssize_t i, n; + n = PyTuple_Size(exc); + for (i = 0; i < n; i++) { + /* Test recursively */ + if (PyErr_GivenExceptionMatches( + err, PyTuple_GET_ITEM(exc, i))) + { + return 1; + } + } + return 0; + } + /* err might be an instance, so check its class. */ + if (PyExceptionInstance_Check(err)) + err = PyExceptionInstance_Class(err); + + if (PyExceptionClass_Check(err) && PyExceptionClass_Check(exc)) { + /* problems here!? not sure PyObject_IsSubclass expects to + be called with an exception pending... */ + return PyObject_IsSubclass(err, exc); + } + + return err == exc; +} + + +int +PyErr_ExceptionMatches(PyObject *exc) +{ + return PyErr_GivenExceptionMatches(PyErr_Occurred(), exc); +} + + +/* Used in many places to normalize a raised exception, including in + eval_code2(), do_raise(), and PyErr_Print() +*/ +void +PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb) +{ + PyObject *type = *exc; + PyObject *value = *val; + PyObject *inclass = NULL; + PyObject *initial_tb = NULL; + + if (type == NULL) { + /* There was no exception, so nothing to do. */ + return; + } + + /* If PyErr_SetNone() was used, the value will have been actually + set to NULL. + */ + if (!value) { + value = Py_None; + Py_INCREF(value); + } + + if (PyExceptionInstance_Check(value)) + inclass = PyExceptionInstance_Class(value); + + /* Normalize the exception so that if the type is a class, the + value will be an instance. + */ + if (PyExceptionClass_Check(type)) { + /* if the value was not an instance, or is not an instance + whose class is (or is derived from) type, then use the + value as an argument to instantiation of the type + class. + */ + if (!inclass || !PyObject_IsSubclass(inclass, type)) { + PyObject *args, *res; + + if (value == Py_None) + args = PyTuple_New(0); + else if (PyTuple_Check(value)) { + Py_INCREF(value); + args = value; + } + else + args = PyTuple_Pack(1, value); + + if (args == NULL) + goto finally; + res = PyEval_CallObject(type, args); + Py_DECREF(args); + if (res == NULL) + goto finally; + Py_DECREF(value); + value = res; + } + /* if the class of the instance doesn't exactly match the + class of the type, believe the instance + */ + else if (inclass != type) { + Py_DECREF(type); + type = inclass; + Py_INCREF(type); + } + } + *exc = type; + *val = value; + return; +finally: + Py_DECREF(type); + Py_DECREF(value); + /* If the new exception doesn't set a traceback and the old + exception had a traceback, use the old traceback for the + new exception. It's better than nothing. + */ + initial_tb = *tb; + PyErr_Fetch(exc, val, tb); + if (initial_tb != NULL) { + if (*tb == NULL) + *tb = initial_tb; + else + Py_DECREF(initial_tb); + } + /* normalize recursively */ + PyErr_NormalizeException(exc, val, tb); +} + + +void +PyErr_Fetch(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) +{ + PyThreadState *tstate = PyThreadState_GET(); + + *p_type = tstate->curexc_type; + *p_value = tstate->curexc_value; + *p_traceback = tstate->curexc_traceback; + + tstate->curexc_type = NULL; + tstate->curexc_value = NULL; + tstate->curexc_traceback = NULL; +} + +void +PyErr_Clear(void) +{ + PyErr_Restore(NULL, NULL, NULL); +} + +/* Convenience functions to set a type error exception and return 0 */ + +int +PyErr_BadArgument(void) +{ + PyErr_SetString(PyExc_TypeError, + "bad argument type for built-in operation"); + return 0; +} + +PyObject * +PyErr_NoMemory(void) +{ + if (PyErr_ExceptionMatches(PyExc_MemoryError)) + /* already current */ + return NULL; + + /* raise the pre-allocated instance if it still exists */ + if (PyExc_MemoryErrorInst) + PyErr_SetObject(PyExc_MemoryError, PyExc_MemoryErrorInst); + else + /* this will probably fail since there's no memory and hee, + hee, we have to instantiate this class + */ + PyErr_SetNone(PyExc_MemoryError); + + return NULL; +} + +PyObject * +PyErr_SetFromErrnoWithFilenameObject(PyObject *exc, PyObject *filenameObject) +{ + PyObject *v; + char *s; + int i = errno; +#ifdef PLAN9 + char errbuf[ERRMAX]; +#endif +#ifdef MS_WINDOWS + char *s_buf = NULL; + char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */ +#endif +#ifdef EINTR + if (i == EINTR && PyErr_CheckSignals()) + return NULL; +#endif +#ifdef PLAN9 + rerrstr(errbuf, sizeof errbuf); + s = errbuf; +#else + if (i == 0) + s = "Error"; /* Sometimes errno didn't get set */ + else +#ifndef MS_WINDOWS + s = strerror(i); +#else + { + /* Note that the Win32 errors do not lineup with the + errno error. So if the error is in the MSVC error + table, we use it, otherwise we assume it really _is_ + a Win32 error code + */ + if (i > 0 && i < _sys_nerr) { + s = _sys_errlist[i]; + } + else { + int len = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, /* no message source */ + i, + MAKELANGID(LANG_NEUTRAL, + SUBLANG_DEFAULT), + /* Default language */ + (LPTSTR) &s_buf, + 0, /* size not used */ + NULL); /* no args */ + if (len==0) { + /* Only ever seen this in out-of-mem + situations */ + sprintf(s_small_buf, "Windows Error 0x%X", i); + s = s_small_buf; + s_buf = NULL; + } else { + s = s_buf; + /* remove trailing cr/lf and dots */ + while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.')) + s[--len] = '\0'; + } + } + } +#endif /* Unix/Windows */ +#endif /* PLAN 9*/ + if (filenameObject != NULL) + v = Py_BuildValue("(isO)", i, s, filenameObject); + else + v = Py_BuildValue("(is)", i, s); + if (v != NULL) { + PyErr_SetObject(exc, v); + Py_DECREF(v); + } +#ifdef MS_WINDOWS + LocalFree(s_buf); +#endif + return NULL; +} + + +PyObject * +PyErr_SetFromErrnoWithFilename(PyObject *exc, char *filename) +{ + PyObject *name = filename ? PyString_FromString(filename) : NULL; + PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name); + Py_XDECREF(name); + return result; +} + +#ifdef Py_WIN_WIDE_FILENAMES +PyObject * +PyErr_SetFromErrnoWithUnicodeFilename(PyObject *exc, Py_UNICODE *filename) +{ + PyObject *name = filename ? + PyUnicode_FromUnicode(filename, wcslen(filename)) : + NULL; + PyObject *result = PyErr_SetFromErrnoWithFilenameObject(exc, name); + Py_XDECREF(name); + return result; +} +#endif /* Py_WIN_WIDE_FILENAMES */ + +PyObject * +PyErr_SetFromErrno(PyObject *exc) +{ + return PyErr_SetFromErrnoWithFilenameObject(exc, NULL); +} + +#ifdef MS_WINDOWS +/* Windows specific error code handling */ +PyObject *PyErr_SetExcFromWindowsErrWithFilenameObject( + PyObject *exc, + int ierr, + PyObject *filenameObject) +{ + int len; + char *s; + char *s_buf = NULL; /* Free via LocalFree */ + char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */ + PyObject *v; + DWORD err = (DWORD)ierr; + if (err==0) err = GetLastError(); + len = FormatMessage( + /* Error API error */ + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, /* no message source */ + err, + MAKELANGID(LANG_NEUTRAL, + SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) &s_buf, + 0, /* size not used */ + NULL); /* no args */ + if (len==0) { + /* Only seen this in out of mem situations */ + sprintf(s_small_buf, "Windows Error 0x%X", err); + s = s_small_buf; + s_buf = NULL; + } else { + s = s_buf; + /* remove trailing cr/lf and dots */ + while (len > 0 && (s[len-1] <= ' ' || s[len-1] == '.')) + s[--len] = '\0'; + } + if (filenameObject != NULL) + v = Py_BuildValue("(isO)", err, s, filenameObject); + else + v = Py_BuildValue("(is)", err, s); + if (v != NULL) { + PyErr_SetObject(exc, v); + Py_DECREF(v); + } + LocalFree(s_buf); + return NULL; +} + +PyObject *PyErr_SetExcFromWindowsErrWithFilename( + PyObject *exc, + int ierr, + const char *filename) +{ + PyObject *name = filename ? PyString_FromString(filename) : NULL; + PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc, + ierr, + name); + Py_XDECREF(name); + return ret; +} + +#ifdef Py_WIN_WIDE_FILENAMES +PyObject *PyErr_SetExcFromWindowsErrWithUnicodeFilename( + PyObject *exc, + int ierr, + const Py_UNICODE *filename) +{ + PyObject *name = filename ? + PyUnicode_FromUnicode(filename, wcslen(filename)) : + NULL; + PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc, + ierr, + name); + Py_XDECREF(name); + return ret; +} +#endif /* Py_WIN_WIDE_FILENAMES */ + +PyObject *PyErr_SetExcFromWindowsErr(PyObject *exc, int ierr) +{ + return PyErr_SetExcFromWindowsErrWithFilename(exc, ierr, NULL); +} + +PyObject *PyErr_SetFromWindowsErr(int ierr) +{ + return PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError, + ierr, NULL); +} +PyObject *PyErr_SetFromWindowsErrWithFilename( + int ierr, + const char *filename) +{ + PyObject *name = filename ? PyString_FromString(filename) : NULL; + PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject( + PyExc_WindowsError, + ierr, name); + Py_XDECREF(name); + return result; +} + +#ifdef Py_WIN_WIDE_FILENAMES +PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename( + int ierr, + const Py_UNICODE *filename) +{ + PyObject *name = filename ? + PyUnicode_FromUnicode(filename, wcslen(filename)) : + NULL; + PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject( + PyExc_WindowsError, + ierr, name); + Py_XDECREF(name); + return result; +} +#endif /* Py_WIN_WIDE_FILENAMES */ +#endif /* MS_WINDOWS */ + +void +_PyErr_BadInternalCall(char *filename, int lineno) +{ + PyErr_Format(PyExc_SystemError, + "%s:%d: bad argument to internal function", + filename, lineno); +} + +/* Remove the preprocessor macro for PyErr_BadInternalCall() so that we can + export the entry point for existing object code: */ +#undef PyErr_BadInternalCall +void +PyErr_BadInternalCall(void) +{ + PyErr_Format(PyExc_SystemError, + "bad argument to internal function"); +} +#define PyErr_BadInternalCall() _PyErr_BadInternalCall(__FILE__, __LINE__) + + + +PyObject * +PyErr_Format(PyObject *exception, const char *format, ...) +{ + va_list vargs; + PyObject* string; + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + + string = PyString_FromFormatV(format, vargs); + PyErr_SetObject(exception, string); + Py_XDECREF(string); + va_end(vargs); + return NULL; +} + + + +PyObject * +PyErr_NewException(char *name, PyObject *base, PyObject *dict) +{ + char *dot; + PyObject *modulename = NULL; + PyObject *classname = NULL; + PyObject *mydict = NULL; + PyObject *bases = NULL; + PyObject *result = NULL; + dot = strrchr(name, '.'); + if (dot == NULL) { + PyErr_SetString(PyExc_SystemError, + "PyErr_NewException: name must be module.class"); + return NULL; + } + if (base == NULL) + base = PyExc_Exception; + if (dict == NULL) { + dict = mydict = PyDict_New(); + if (dict == NULL) + goto failure; + } + if (PyDict_GetItemString(dict, "__module__") == NULL) { + modulename = PyString_FromStringAndSize(name, + (Py_ssize_t)(dot-name)); + if (modulename == NULL) + goto failure; + if (PyDict_SetItemString(dict, "__module__", modulename) != 0) + goto failure; + } + if (PyTuple_Check(base)) { + bases = base; + /* INCREF as we create a new ref in the else branch */ + Py_INCREF(bases); + } else { + bases = PyTuple_Pack(1, base); + if (bases == NULL) + goto failure; + } + /* Create a real new-style class. */ + result = PyObject_CallFunction((PyObject *)&PyType_Type, "sOO", + dot+1, bases, dict); + failure: + Py_XDECREF(bases); + Py_XDECREF(mydict); + Py_XDECREF(classname); + Py_XDECREF(modulename); + return result; +} + +/* Call when an exception has occurred but there is no way for Python + to handle it. Examples: exception in __del__ or during GC. */ +void +PyErr_WriteUnraisable(PyObject *obj) +{ + PyObject *f, *t, *v, *tb; + PyErr_Fetch(&t, &v, &tb); + f = PySys_GetObject("stderr"); + if (f != NULL) { + PyFile_WriteString("Exception ", f); + if (t) { + PyObject* moduleName; + char* className = NULL; + if (PyExceptionClass_Check(t)) + className = PyExceptionClass_Name(t); + else if (PyString_Check(t)) + className = PyString_AS_STRING(t); + + if (className != NULL) { + char *dot = strrchr(className, '.'); + if (dot != NULL) + className = dot+1; + } + + moduleName = PyObject_GetAttrString(t, "__module__"); + if (moduleName == NULL) + PyFile_WriteString("<unknown>", f); + else { + char* modstr = PyString_AsString(moduleName); + if (modstr) + { + PyFile_WriteString(modstr, f); + PyFile_WriteString(".", f); + } + } + if (className == NULL) + PyFile_WriteString("<unknown>", f); + else + PyFile_WriteString(className, f); + if (v && v != Py_None) { + PyFile_WriteString(": ", f); + PyFile_WriteObject(v, f, 0); + } + Py_XDECREF(moduleName); + } + PyFile_WriteString(" in ", f); + PyFile_WriteObject(obj, f, 0); + PyFile_WriteString(" ignored\n", f); + PyErr_Clear(); /* Just in case */ + } + Py_XDECREF(t); + Py_XDECREF(v); + Py_XDECREF(tb); +} + +extern PyObject *PyModule_GetWarningsModule(void); + +/* Function to issue a warning message; may raise an exception. */ +int +PyErr_WarnEx(PyObject *category, const char *message, Py_ssize_t stack_level) +{ + PyObject *dict, *func = NULL; + PyObject *warnings_module = PyModule_GetWarningsModule(); + + if (warnings_module != NULL) { + dict = PyModule_GetDict(warnings_module); + if (dict != NULL) + func = PyDict_GetItemString(dict, "warn"); + } + if (func == NULL) { + PySys_WriteStderr("warning: %s\n", message); + return 0; + } + else { + PyObject *res; + + if (category == NULL) + category = PyExc_RuntimeWarning; + res = PyObject_CallFunction(func, "sOn", + message, category, stack_level); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; + } +} + +/* PyErr_Warn is only for backwards compatability and will be removed. + Use PyErr_WarnEx instead. */ + +#undef PyErr_Warn + +PyAPI_FUNC(int) +PyErr_Warn(PyObject *category, char *message) +{ + return PyErr_WarnEx(category, message, 1); +} + +/* Warning with explicit origin */ +int +PyErr_WarnExplicit(PyObject *category, const char *message, + const char *filename, int lineno, + const char *module, PyObject *registry) +{ + PyObject *mod, *dict, *func = NULL; + + mod = PyImport_ImportModule("warnings"); + if (mod != NULL) { + dict = PyModule_GetDict(mod); + func = PyDict_GetItemString(dict, "warn_explicit"); + Py_DECREF(mod); + } + if (func == NULL) { + PySys_WriteStderr("warning: %s\n", message); + return 0; + } + else { + PyObject *res; + + if (category == NULL) + category = PyExc_RuntimeWarning; + if (registry == NULL) + registry = Py_None; + res = PyObject_CallFunction(func, "sOsizO", message, category, + filename, lineno, module, registry); + if (res == NULL) + return -1; + Py_DECREF(res); + return 0; + } +} + + +/* Set file and line information for the current exception. + If the exception is not a SyntaxError, also sets additional attributes + to make printing of exceptions believe it is a syntax error. */ + +void +PyErr_SyntaxLocation(const char *filename, int lineno) +{ + PyObject *exc, *v, *tb, *tmp; + + /* add attributes for the line number and filename for the error */ + PyErr_Fetch(&exc, &v, &tb); + PyErr_NormalizeException(&exc, &v, &tb); + /* XXX check that it is, indeed, a syntax error. It might not + * be, though. */ + tmp = PyInt_FromLong(lineno); + if (tmp == NULL) + PyErr_Clear(); + else { + if (PyObject_SetAttrString(v, "lineno", tmp)) + PyErr_Clear(); + Py_DECREF(tmp); + } + if (filename != NULL) { + tmp = PyString_FromString(filename); + if (tmp == NULL) + PyErr_Clear(); + else { + if (PyObject_SetAttrString(v, "filename", tmp)) + PyErr_Clear(); + Py_DECREF(tmp); + } + + tmp = PyErr_ProgramText(filename, lineno); + if (tmp) { + if (PyObject_SetAttrString(v, "text", tmp)) + PyErr_Clear(); + Py_DECREF(tmp); + } + } + if (PyObject_SetAttrString(v, "offset", Py_None)) { + PyErr_Clear(); + } + if (exc != PyExc_SyntaxError) { + if (!PyObject_HasAttrString(v, "msg")) { + tmp = PyObject_Str(v); + if (tmp) { + if (PyObject_SetAttrString(v, "msg", tmp)) + PyErr_Clear(); + Py_DECREF(tmp); + } else { + PyErr_Clear(); + } + } + if (!PyObject_HasAttrString(v, "print_file_and_line")) { + if (PyObject_SetAttrString(v, "print_file_and_line", + Py_None)) + PyErr_Clear(); + } + } + PyErr_Restore(exc, v, tb); +} + +/* com_fetch_program_text will attempt to load the line of text that + the exception refers to. If it fails, it will return NULL but will + not set an exception. + + XXX The functionality of this function is quite similar to the + functionality in tb_displayline() in traceback.c. +*/ + +PyObject * +PyErr_ProgramText(const char *filename, int lineno) +{ + FILE *fp; + int i; + char linebuf[1000]; + + if (filename == NULL || *filename == '\0' || lineno <= 0) + return NULL; + fp = fopen(filename, "r" PY_STDIOTEXTMODE); + if (fp == NULL) + return NULL; + for (i = 0; i < lineno; i++) { + char *pLastChar = &linebuf[sizeof(linebuf) - 2]; + do { + *pLastChar = '\0'; + if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, fp, NULL) == NULL) + break; + /* fgets read *something*; if it didn't get as + far as pLastChar, it must have found a newline + or hit the end of the file; if pLastChar is \n, + it obviously found a newline; else we haven't + yet seen a newline, so must continue */ + } while (*pLastChar != '\0' && *pLastChar != '\n'); + } + fclose(fp); + if (i == lineno) { + char *p = linebuf; + while (*p == ' ' || *p == '\t' || *p == '\014') + p++; + return PyString_FromString(p); + } + return NULL; +} + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Python/fmod.c b/sys/src/cmd/python/Python/fmod.c new file mode 100644 index 000000000..919c6cc74 --- /dev/null +++ b/sys/src/cmd/python/Python/fmod.c @@ -0,0 +1,27 @@ + +/* Portable fmod(x, y) implementation for systems that don't have it */ + +#include "pyconfig.h" + +#include "pyport.h" +#include <errno.h> + +double +fmod(double x, double y) +{ + double i, f; + + if (y == 0.0) { + errno = EDOM; + return 0.0; + } + + /* return f such that x = i*y + f for some integer i + such that |f| < |y| and f has the same sign as x */ + + i = floor(x/y); + f = x - i*y; + if ((x < 0.0) != (y < 0.0)) + f = f-y; + return f; +} diff --git a/sys/src/cmd/python/Python/frozen.c b/sys/src/cmd/python/Python/frozen.c new file mode 100644 index 000000000..946d626bd --- /dev/null +++ b/sys/src/cmd/python/Python/frozen.c @@ -0,0 +1,38 @@ + +/* Dummy frozen modules initializer */ + +#include "Python.h" + +/* In order to test the support for frozen modules, by default we + define a single frozen module, __hello__. Loading it will print + some famous words... */ + +/* To regenerate this data after the bytecode or marshal format has changed, + go to ../Tools/freeze/ and freeze the hello.py file; then copy and paste + the appropriate bytes from M___main__.c. */ + +static unsigned char M___hello__[] = { + 99,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, + 0,115,9,0,0,0,100,0,0,71,72,100,1,0,83,40, + 2,0,0,0,115,14,0,0,0,72,101,108,108,111,32,119, + 111,114,108,100,46,46,46,78,40,0,0,0,0,40,0,0, + 0,0,40,0,0,0,0,40,0,0,0,0,115,8,0,0, + 0,104,101,108,108,111,46,112,121,115,1,0,0,0,63,1, + 0,0,0,115,0,0,0,0, +}; + +#define SIZE (int)sizeof(M___hello__) + +static struct _frozen _PyImport_FrozenModules[] = { + /* Test module */ + {"__hello__", M___hello__, SIZE}, + /* Test package (negative size indicates package-ness) */ + {"__phello__", M___hello__, -SIZE}, + {"__phello__.spam", M___hello__, SIZE}, + {0, 0, 0} /* sentinel */ +}; + +/* Embedding apps may change this pointer to point to their favorite + collection of frozen modules: */ + +struct _frozen *PyImport_FrozenModules = _PyImport_FrozenModules; diff --git a/sys/src/cmd/python/Python/frozenmain.c b/sys/src/cmd/python/Python/frozenmain.c new file mode 100644 index 000000000..397f0465c --- /dev/null +++ b/sys/src/cmd/python/Python/frozenmain.c @@ -0,0 +1,68 @@ + +/* Python interpreter main program for frozen scripts */ + +#include "Python.h" + +#ifdef MS_WINDOWS +extern void PyWinFreeze_ExeInit(void); +extern void PyWinFreeze_ExeTerm(void); +extern int PyInitFrozenExtensions(void); +#endif + +/* Main program */ + +int +Py_FrozenMain(int argc, char **argv) +{ + char *p; + int n, sts; + int inspect = 0; + int unbuffered = 0; + + Py_FrozenFlag = 1; /* Suppress errors from getpath.c */ + + if ((p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') + inspect = 1; + if ((p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') + unbuffered = 1; + + if (unbuffered) { + setbuf(stdin, (char *)NULL); + setbuf(stdout, (char *)NULL); + setbuf(stderr, (char *)NULL); + } + +#ifdef MS_WINDOWS + PyInitFrozenExtensions(); +#endif /* MS_WINDOWS */ + Py_SetProgramName(argv[0]); + Py_Initialize(); +#ifdef MS_WINDOWS + PyWinFreeze_ExeInit(); +#endif + + if (Py_VerboseFlag) + fprintf(stderr, "Python %s\n%s\n", + Py_GetVersion(), Py_GetCopyright()); + + PySys_SetArgv(argc, argv); + + n = PyImport_ImportFrozenModule("__main__"); + if (n == 0) + Py_FatalError("__main__ not frozen"); + if (n < 0) { + PyErr_Print(); + sts = 1; + } + else + sts = 0; + + if (inspect && isatty((int)fileno(stdin))) + sts = PyRun_AnyFile(stdin, "<stdin>") != 0; + +#ifdef MS_WINDOWS + PyWinFreeze_ExeTerm(); +#endif + Py_Finalize(); + return sts; +} diff --git a/sys/src/cmd/python/Python/future.c b/sys/src/cmd/python/Python/future.c new file mode 100644 index 000000000..3b3ca1d7b --- /dev/null +++ b/sys/src/cmd/python/Python/future.c @@ -0,0 +1,136 @@ +#include "Python.h" +#include "Python-ast.h" +#include "node.h" +#include "token.h" +#include "graminit.h" +#include "code.h" +#include "compile.h" +#include "symtable.h" + +#define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" + +static int +future_check_features(PyFutureFeatures *ff, stmt_ty s, const char *filename) +{ + int i; + asdl_seq *names; + + assert(s->kind == ImportFrom_kind); + + names = s->v.ImportFrom.names; + for (i = 0; i < asdl_seq_LEN(names); i++) { + alias_ty name = (alias_ty)asdl_seq_GET(names, i); + const char *feature = PyString_AsString(name->name); + if (!feature) + return 0; + if (strcmp(feature, FUTURE_NESTED_SCOPES) == 0) { + continue; + } else if (strcmp(feature, FUTURE_GENERATORS) == 0) { + continue; + } else if (strcmp(feature, FUTURE_DIVISION) == 0) { + ff->ff_features |= CO_FUTURE_DIVISION; + } else if (strcmp(feature, FUTURE_ABSOLUTE_IMPORT) == 0) { + ff->ff_features |= CO_FUTURE_ABSOLUTE_IMPORT; + } else if (strcmp(feature, FUTURE_WITH_STATEMENT) == 0) { + ff->ff_features |= CO_FUTURE_WITH_STATEMENT; + } else if (strcmp(feature, "braces") == 0) { + PyErr_SetString(PyExc_SyntaxError, + "not a chance"); + PyErr_SyntaxLocation(filename, s->lineno); + return 0; + } else { + PyErr_Format(PyExc_SyntaxError, + UNDEFINED_FUTURE_FEATURE, feature); + PyErr_SyntaxLocation(filename, s->lineno); + return 0; + } + } + return 1; +} + +static int +future_parse(PyFutureFeatures *ff, mod_ty mod, const char *filename) +{ + int i, found_docstring = 0, done = 0, prev_line = 0; + + static PyObject *future; + if (!future) { + future = PyString_InternFromString("__future__"); + if (!future) + return 0; + } + + if (!(mod->kind == Module_kind || mod->kind == Interactive_kind)) + return 1; + + /* A subsequent pass will detect future imports that don't + appear at the beginning of the file. There's one case, + however, that is easier to handl here: A series of imports + joined by semi-colons, where the first import is a future + statement but some subsequent import has the future form + but is preceded by a regular import. + */ + + + for (i = 0; i < asdl_seq_LEN(mod->v.Module.body); i++) { + stmt_ty s = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i); + + if (done && s->lineno > prev_line) + return 1; + prev_line = s->lineno; + + /* The tests below will return from this function unless it is + still possible to find a future statement. The only things + that can precede a future statement are another future + statement and a doc string. + */ + + if (s->kind == ImportFrom_kind) { + if (s->v.ImportFrom.module == future) { + if (done) { + PyErr_SetString(PyExc_SyntaxError, + ERR_LATE_FUTURE); + PyErr_SyntaxLocation(filename, + s->lineno); + return 0; + } + if (!future_check_features(ff, s, filename)) + return 0; + ff->ff_lineno = s->lineno; + } + else + done = 1; + } + else if (s->kind == Expr_kind && !found_docstring) { + expr_ty e = s->v.Expr.value; + if (e->kind != Str_kind) + done = 1; + else + found_docstring = 1; + } + else + done = 1; + } + return 1; +} + + +PyFutureFeatures * +PyFuture_FromAST(mod_ty mod, const char *filename) +{ + PyFutureFeatures *ff; + + ff = (PyFutureFeatures *)PyObject_Malloc(sizeof(PyFutureFeatures)); + if (ff == NULL) { + PyErr_NoMemory(); + return NULL; + } + ff->ff_features = 0; + ff->ff_lineno = -1; + + if (!future_parse(ff, mod, filename)) { + PyObject_Free(ff); + return NULL; + } + return ff; +} diff --git a/sys/src/cmd/python/Python/getargs.c b/sys/src/cmd/python/Python/getargs.c new file mode 100644 index 000000000..d62559863 --- /dev/null +++ b/sys/src/cmd/python/Python/getargs.c @@ -0,0 +1,1771 @@ + +/* New getargs implementation */ + +#include "Python.h" + +#include <ctype.h> + + +#ifdef __cplusplus +extern "C" { +#endif +int PyArg_Parse(PyObject *, const char *, ...); +int PyArg_ParseTuple(PyObject *, const char *, ...); +int PyArg_VaParse(PyObject *, const char *, va_list); + +int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, + const char *, char **, ...); +int PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, + const char *, char **, va_list); + +#ifdef HAVE_DECLSPEC_DLL +/* Export functions */ +PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, char *, ...); +PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, char *, ...); +PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *, + const char *, char **, ...); +PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...); +PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, char *, va_list); +PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *, + const char *, char **, va_list); +#endif + +#define FLAG_COMPAT 1 +#define FLAG_SIZE_T 2 + + +/* Forward */ +static int vgetargs1(PyObject *, const char *, va_list *, int); +static void seterror(int, const char *, int *, const char *, const char *); +static char *convertitem(PyObject *, const char **, va_list *, int, int *, + char *, size_t, PyObject **); +static char *converttuple(PyObject *, const char **, va_list *, int, + int *, char *, size_t, int, PyObject **); +static char *convertsimple(PyObject *, const char **, va_list *, int, char *, + size_t, PyObject **); +static Py_ssize_t convertbuffer(PyObject *, void **p, char **); + +static int vgetargskeywords(PyObject *, PyObject *, + const char *, char **, va_list *, int); +static char *skipitem(const char **, va_list *, int); + +int +PyArg_Parse(PyObject *args, const char *format, ...) +{ + int retval; + va_list va; + + va_start(va, format); + retval = vgetargs1(args, format, &va, FLAG_COMPAT); + va_end(va); + return retval; +} + +int +_PyArg_Parse_SizeT(PyObject *args, char *format, ...) +{ + int retval; + va_list va; + + va_start(va, format); + retval = vgetargs1(args, format, &va, FLAG_COMPAT|FLAG_SIZE_T); + va_end(va); + return retval; +} + + +int +PyArg_ParseTuple(PyObject *args, const char *format, ...) +{ + int retval; + va_list va; + + va_start(va, format); + retval = vgetargs1(args, format, &va, 0); + va_end(va); + return retval; +} + +int +_PyArg_ParseTuple_SizeT(PyObject *args, char *format, ...) +{ + int retval; + va_list va; + + va_start(va, format); + retval = vgetargs1(args, format, &va, FLAG_SIZE_T); + va_end(va); + return retval; +} + + +int +PyArg_VaParse(PyObject *args, const char *format, va_list va) +{ + va_list lva; + +#ifdef VA_LIST_IS_ARRAY + memcpy(lva, va, sizeof(va_list)); +#else +#ifdef __va_copy + __va_copy(lva, va); +#else + lva = va; +#endif +#endif + + return vgetargs1(args, format, &lva, 0); +} + +int +_PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va) +{ + va_list lva; + +#ifdef VA_LIST_IS_ARRAY + memcpy(lva, va, sizeof(va_list)); +#else +#ifdef __va_copy + __va_copy(lva, va); +#else + lva = va; +#endif +#endif + + return vgetargs1(args, format, &lva, FLAG_SIZE_T); +} + + +/* Handle cleanup of allocated memory in case of exception */ + +static int +addcleanup(void *ptr, PyObject **freelist) +{ + PyObject *cobj; + if (!*freelist) { + *freelist = PyList_New(0); + if (!*freelist) { + PyMem_FREE(ptr); + return -1; + } + } + cobj = PyCObject_FromVoidPtr(ptr, NULL); + if (!cobj) { + PyMem_FREE(ptr); + return -1; + } + if(PyList_Append(*freelist, cobj)) { + PyMem_FREE(ptr); + Py_DECREF(cobj); + return -1; + } + Py_DECREF(cobj); + return 0; +} + +static int +cleanreturn(int retval, PyObject *freelist) +{ + if(freelist) { + if((retval) == 0) { + Py_ssize_t len = PyList_GET_SIZE(freelist), i; + for (i = 0; i < len; i++) + PyMem_FREE(PyCObject_AsVoidPtr( + PyList_GET_ITEM(freelist, i))); + } + Py_DECREF(freelist); + } + return retval; +} + + +static int +vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) +{ + char msgbuf[256]; + int levels[32]; + const char *fname = NULL; + const char *message = NULL; + int min = -1; + int max = 0; + int level = 0; + int endfmt = 0; + const char *formatsave = format; + Py_ssize_t i, len; + char *msg; + PyObject *freelist = NULL; + int compat = flags & FLAG_COMPAT; + + assert(compat || (args != (PyObject*)NULL)); + flags = flags & ~FLAG_COMPAT; + + while (endfmt == 0) { + int c = *format++; + switch (c) { + case '(': + if (level == 0) + max++; + level++; + if (level >= 30) + Py_FatalError("too many tuple nesting levels " + "in argument format string"); + break; + case ')': + if (level == 0) + Py_FatalError("excess ')' in getargs format"); + else + level--; + break; + case '\0': + endfmt = 1; + break; + case ':': + fname = format; + endfmt = 1; + break; + case ';': + message = format; + endfmt = 1; + break; + default: + if (level == 0) { + if (c == 'O') + max++; + else if (isalpha(Py_CHARMASK(c))) { + if (c != 'e') /* skip encoded */ + max++; + } else if (c == '|') + min = max; + } + break; + } + } + + if (level != 0) + Py_FatalError(/* '(' */ "missing ')' in getargs format"); + + if (min < 0) + min = max; + + format = formatsave; + + if (compat) { + if (max == 0) { + if (args == NULL) + return 1; + PyOS_snprintf(msgbuf, sizeof(msgbuf), + "%.200s%s takes no arguments", + fname==NULL ? "function" : fname, + fname==NULL ? "" : "()"); + PyErr_SetString(PyExc_TypeError, msgbuf); + return 0; + } + else if (min == 1 && max == 1) { + if (args == NULL) { + PyOS_snprintf(msgbuf, sizeof(msgbuf), + "%.200s%s takes at least one argument", + fname==NULL ? "function" : fname, + fname==NULL ? "" : "()"); + PyErr_SetString(PyExc_TypeError, msgbuf); + return 0; + } + msg = convertitem(args, &format, p_va, flags, levels, + msgbuf, sizeof(msgbuf), &freelist); + if (msg == NULL) + return cleanreturn(1, freelist); + seterror(levels[0], msg, levels+1, fname, message); + return cleanreturn(0, freelist); + } + else { + PyErr_SetString(PyExc_SystemError, + "old style getargs format uses new features"); + return 0; + } + } + + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, + "new style getargs format but argument is not a tuple"); + return 0; + } + + len = PyTuple_GET_SIZE(args); + + if (len < min || max < len) { + if (message == NULL) { + PyOS_snprintf(msgbuf, sizeof(msgbuf), + "%.150s%s takes %s %d argument%s " + "(%ld given)", + fname==NULL ? "function" : fname, + fname==NULL ? "" : "()", + min==max ? "exactly" + : len < min ? "at least" : "at most", + len < min ? min : max, + (len < min ? min : max) == 1 ? "" : "s", + Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); + message = msgbuf; + } + PyErr_SetString(PyExc_TypeError, message); + return 0; + } + + for (i = 0; i < len; i++) { + if (*format == '|') + format++; + msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va, + flags, levels, msgbuf, + sizeof(msgbuf), &freelist); + if (msg) { + seterror(i+1, msg, levels, fname, message); + return cleanreturn(0, freelist); + } + } + + if (*format != '\0' && !isalpha(Py_CHARMASK(*format)) && + *format != '(' && + *format != '|' && *format != ':' && *format != ';') { + PyErr_Format(PyExc_SystemError, + "bad format string: %.200s", formatsave); + return cleanreturn(0, freelist); + } + + return cleanreturn(1, freelist); +} + + + +static void +seterror(int iarg, const char *msg, int *levels, const char *fname, + const char *message) +{ + char buf[512]; + int i; + char *p = buf; + + if (PyErr_Occurred()) + return; + else if (message == NULL) { + if (fname != NULL) { + PyOS_snprintf(p, sizeof(buf), "%.200s() ", fname); + p += strlen(p); + } + if (iarg != 0) { + PyOS_snprintf(p, sizeof(buf) - (p - buf), + "argument %d", iarg); + i = 0; + p += strlen(p); + while (levels[i] > 0 && i < 32 && (int)(p-buf) < 220) { + PyOS_snprintf(p, sizeof(buf) - (p - buf), + ", item %d", levels[i]-1); + p += strlen(p); + i++; + } + } + else { + PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument"); + p += strlen(p); + } + PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg); + message = buf; + } + PyErr_SetString(PyExc_TypeError, message); +} + + +/* Convert a tuple argument. + On entry, *p_format points to the character _after_ the opening '('. + On successful exit, *p_format points to the closing ')'. + If successful: + *p_format and *p_va are updated, + *levels and *msgbuf are untouched, + and NULL is returned. + If the argument is invalid: + *p_format is unchanged, + *p_va is undefined, + *levels is a 0-terminated list of item numbers, + *msgbuf contains an error message, whose format is: + "must be <typename1>, not <typename2>", where: + <typename1> is the name of the expected type, and + <typename2> is the name of the actual type, + and msgbuf is returned. +*/ + +static char * +converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags, + int *levels, char *msgbuf, size_t bufsize, int toplevel, + PyObject **freelist) +{ + int level = 0; + int n = 0; + const char *format = *p_format; + int i; + + for (;;) { + int c = *format++; + if (c == '(') { + if (level == 0) + n++; + level++; + } + else if (c == ')') { + if (level == 0) + break; + level--; + } + else if (c == ':' || c == ';' || c == '\0') + break; + else if (level == 0 && isalpha(Py_CHARMASK(c))) + n++; + } + + if (!PySequence_Check(arg) || PyString_Check(arg)) { + levels[0] = 0; + PyOS_snprintf(msgbuf, bufsize, + toplevel ? "expected %d arguments, not %.50s" : + "must be %d-item sequence, not %.50s", + n, + arg == Py_None ? "None" : arg->ob_type->tp_name); + return msgbuf; + } + + if ((i = PySequence_Size(arg)) != n) { + levels[0] = 0; + PyOS_snprintf(msgbuf, bufsize, + toplevel ? "expected %d arguments, not %d" : + "must be sequence of length %d, not %d", + n, i); + return msgbuf; + } + + format = *p_format; + for (i = 0; i < n; i++) { + char *msg; + PyObject *item; + item = PySequence_GetItem(arg, i); + if (item == NULL) { + PyErr_Clear(); + levels[0] = i+1; + levels[1] = 0; + strncpy(msgbuf, "is not retrievable", bufsize); + return msgbuf; + } + msg = convertitem(item, &format, p_va, flags, levels+1, + msgbuf, bufsize, freelist); + /* PySequence_GetItem calls tp->sq_item, which INCREFs */ + Py_XDECREF(item); + if (msg != NULL) { + levels[0] = i+1; + return msg; + } + } + + *p_format = format; + return NULL; +} + + +/* Convert a single item. */ + +static char * +convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags, + int *levels, char *msgbuf, size_t bufsize, PyObject **freelist) +{ + char *msg; + const char *format = *p_format; + + if (*format == '(' /* ')' */) { + format++; + msg = converttuple(arg, &format, p_va, flags, levels, msgbuf, + bufsize, 0, freelist); + if (msg == NULL) + format++; + } + else { + msg = convertsimple(arg, &format, p_va, flags, + msgbuf, bufsize, freelist); + if (msg != NULL) + levels[0] = 0; + } + if (msg == NULL) + *p_format = format; + return msg; +} + + + +#define UNICODE_DEFAULT_ENCODING(arg) \ + _PyUnicode_AsDefaultEncodedString(arg, NULL) + +/* Format an error message generated by convertsimple(). */ + +static char * +converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize) +{ + assert(expected != NULL); + assert(arg != NULL); + PyOS_snprintf(msgbuf, bufsize, + "must be %.50s, not %.50s", expected, + arg == Py_None ? "None" : arg->ob_type->tp_name); + return msgbuf; +} + +#define CONV_UNICODE "(unicode conversion error)" + +/* explicitly check for float arguments when integers are expected. For now + * signal a warning. Returns true if an exception was raised. */ +static int +float_argument_error(PyObject *arg) +{ + if (PyFloat_Check(arg) && + PyErr_Warn(PyExc_DeprecationWarning, + "integer argument expected, got float" )) + return 1; + else + return 0; +} + +/* Convert a non-tuple argument. Return NULL if conversion went OK, + or a string with a message describing the failure. The message is + formatted as "must be <desired type>, not <actual type>". + When failing, an exception may or may not have been raised. + Don't call if a tuple is expected. + + When you add new format codes, please don't forget poor skipitem() below. +*/ + +static char * +convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, + char *msgbuf, size_t bufsize, PyObject **freelist) +{ + /* For # codes */ +#define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\ + if (flags & FLAG_SIZE_T) q2=va_arg(*p_va, Py_ssize_t*); \ + else q=va_arg(*p_va, int*); +#define STORE_SIZE(s) if (flags & FLAG_SIZE_T) *q2=s; else *q=s; +#define BUFFER_LEN ((flags & FLAG_SIZE_T) ? *q2:*q) + + const char *format = *p_format; + char c = *format++; +#ifdef Py_USING_UNICODE + PyObject *uarg; +#endif + + switch (c) { + + case 'b': { /* unsigned byte -- very short int */ + char *p = va_arg(*p_va, char *); + long ival; + if (float_argument_error(arg)) + return converterr("integer<b>", arg, msgbuf, bufsize); + ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<b>", arg, msgbuf, bufsize); + else if (ival < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is less than minimum"); + return converterr("integer<b>", arg, msgbuf, bufsize); + } + else if (ival > UCHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is greater than maximum"); + return converterr("integer<b>", arg, msgbuf, bufsize); + } + else + *p = (unsigned char) ival; + break; + } + + case 'B': {/* byte sized bitfield - both signed and unsigned + values allowed */ + char *p = va_arg(*p_va, char *); + long ival; + if (float_argument_error(arg)) + return converterr("integer<B>", arg, msgbuf, bufsize); + ival = PyInt_AsUnsignedLongMask(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<B>", arg, msgbuf, bufsize); + else + *p = (unsigned char) ival; + break; + } + + case 'h': {/* signed short int */ + short *p = va_arg(*p_va, short *); + long ival; + if (float_argument_error(arg)) + return converterr("integer<h>", arg, msgbuf, bufsize); + ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<h>", arg, msgbuf, bufsize); + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + return converterr("integer<h>", arg, msgbuf, bufsize); + } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + return converterr("integer<h>", arg, msgbuf, bufsize); + } + else + *p = (short) ival; + break; + } + + case 'H': { /* short int sized bitfield, both signed and + unsigned allowed */ + unsigned short *p = va_arg(*p_va, unsigned short *); + long ival; + if (float_argument_error(arg)) + return converterr("integer<H>", arg, msgbuf, bufsize); + ival = PyInt_AsUnsignedLongMask(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<H>", arg, msgbuf, bufsize); + else + *p = (unsigned short) ival; + break; + } + + case 'i': {/* signed int */ + int *p = va_arg(*p_va, int *); + long ival; + if (float_argument_error(arg)) + return converterr("integer<i>", arg, msgbuf, bufsize); + ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<i>", arg, msgbuf, bufsize); + else if (ival > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed integer is greater than maximum"); + return converterr("integer<i>", arg, msgbuf, bufsize); + } + else if (ival < INT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed integer is less than minimum"); + return converterr("integer<i>", arg, msgbuf, bufsize); + } + else + *p = ival; + break; + } + + case 'I': { /* int sized bitfield, both signed and + unsigned allowed */ + unsigned int *p = va_arg(*p_va, unsigned int *); + unsigned int ival; + if (float_argument_error(arg)) + return converterr("integer<I>", arg, msgbuf, bufsize); + ival = (unsigned int)PyInt_AsUnsignedLongMask(arg); + if (ival == (unsigned int)-1 && PyErr_Occurred()) + return converterr("integer<I>", arg, msgbuf, bufsize); + else + *p = ival; + break; + } + + case 'n': /* Py_ssize_t */ +#if SIZEOF_SIZE_T != SIZEOF_LONG + { + Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *); + Py_ssize_t ival; + if (float_argument_error(arg)) + return converterr("integer<n>", arg, msgbuf, bufsize); + ival = PyInt_AsSsize_t(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<n>", arg, msgbuf, bufsize); + *p = ival; + break; + } +#endif + /* Fall through from 'n' to 'l' if Py_ssize_t is int */ + case 'l': {/* long int */ + long *p = va_arg(*p_va, long *); + long ival; + if (float_argument_error(arg)) + return converterr("integer<l>", arg, msgbuf, bufsize); + ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer<l>", arg, msgbuf, bufsize); + else + *p = ival; + break; + } + + case 'k': { /* long sized bitfield */ + unsigned long *p = va_arg(*p_va, unsigned long *); + unsigned long ival; + if (PyInt_Check(arg)) + ival = PyInt_AsUnsignedLongMask(arg); + else if (PyLong_Check(arg)) + ival = PyLong_AsUnsignedLongMask(arg); + else + return converterr("integer<k>", arg, msgbuf, bufsize); + *p = ival; + break; + } + +#ifdef HAVE_LONG_LONG + case 'L': {/* PY_LONG_LONG */ + PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * ); + PY_LONG_LONG ival = PyLong_AsLongLong( arg ); + if( ival == (PY_LONG_LONG)-1 && PyErr_Occurred() ) { + return converterr("long<L>", arg, msgbuf, bufsize); + } else { + *p = ival; + } + break; + } + + case 'K': { /* long long sized bitfield */ + unsigned PY_LONG_LONG *p = va_arg(*p_va, unsigned PY_LONG_LONG *); + unsigned PY_LONG_LONG ival; + if (PyInt_Check(arg)) + ival = PyInt_AsUnsignedLongMask(arg); + else if (PyLong_Check(arg)) + ival = PyLong_AsUnsignedLongLongMask(arg); + else + return converterr("integer<K>", arg, msgbuf, bufsize); + *p = ival; + break; + } +#endif + + case 'f': {/* float */ + float *p = va_arg(*p_va, float *); + double dval = PyFloat_AsDouble(arg); + if (PyErr_Occurred()) + return converterr("float<f>", arg, msgbuf, bufsize); + else + *p = (float) dval; + break; + } + + case 'd': {/* double */ + double *p = va_arg(*p_va, double *); + double dval = PyFloat_AsDouble(arg); + if (PyErr_Occurred()) + return converterr("float<d>", arg, msgbuf, bufsize); + else + *p = dval; + break; + } + +#ifndef WITHOUT_COMPLEX + case 'D': {/* complex double */ + Py_complex *p = va_arg(*p_va, Py_complex *); + Py_complex cval; + cval = PyComplex_AsCComplex(arg); + if (PyErr_Occurred()) + return converterr("complex<D>", arg, msgbuf, bufsize); + else + *p = cval; + break; + } +#endif /* WITHOUT_COMPLEX */ + + case 'c': {/* char */ + char *p = va_arg(*p_va, char *); + if (PyString_Check(arg) && PyString_Size(arg) == 1) + *p = PyString_AS_STRING(arg)[0]; + else + return converterr("char", arg, msgbuf, bufsize); + break; + } + + case 's': {/* string */ + if (*format == '#') { + void **p = (void **)va_arg(*p_va, char **); + FETCH_SIZE; + + if (PyString_Check(arg)) { + *p = PyString_AS_STRING(arg); + STORE_SIZE(PyString_GET_SIZE(arg)); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(arg)) { + uarg = UNICODE_DEFAULT_ENCODING(arg); + if (uarg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf, bufsize); + *p = PyString_AS_STRING(uarg); + STORE_SIZE(PyString_GET_SIZE(uarg)); + } +#endif + else { /* any buffer-like object */ + char *buf; + Py_ssize_t count = convertbuffer(arg, p, &buf); + if (count < 0) + return converterr(buf, arg, msgbuf, bufsize); + STORE_SIZE(count); + } + format++; + } else { + char **p = va_arg(*p_va, char **); + + if (PyString_Check(arg)) + *p = PyString_AS_STRING(arg); +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(arg)) { + uarg = UNICODE_DEFAULT_ENCODING(arg); + if (uarg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf, bufsize); + *p = PyString_AS_STRING(uarg); + } +#endif + else + return converterr("string", arg, msgbuf, bufsize); + if ((Py_ssize_t)strlen(*p) != PyString_Size(arg)) + return converterr("string without null bytes", + arg, msgbuf, bufsize); + } + break; + } + + case 'z': {/* string, may be NULL (None) */ + if (*format == '#') { /* any buffer-like object */ + void **p = (void **)va_arg(*p_va, char **); + FETCH_SIZE; + + if (arg == Py_None) { + *p = 0; + STORE_SIZE(0); + } + else if (PyString_Check(arg)) { + *p = PyString_AS_STRING(arg); + STORE_SIZE(PyString_GET_SIZE(arg)); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(arg)) { + uarg = UNICODE_DEFAULT_ENCODING(arg); + if (uarg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf, bufsize); + *p = PyString_AS_STRING(uarg); + STORE_SIZE(PyString_GET_SIZE(uarg)); + } +#endif + else { /* any buffer-like object */ + char *buf; + Py_ssize_t count = convertbuffer(arg, p, &buf); + if (count < 0) + return converterr(buf, arg, msgbuf, bufsize); + STORE_SIZE(count); + } + format++; + } else { + char **p = va_arg(*p_va, char **); + + if (arg == Py_None) + *p = 0; + else if (PyString_Check(arg)) + *p = PyString_AS_STRING(arg); +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(arg)) { + uarg = UNICODE_DEFAULT_ENCODING(arg); + if (uarg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf, bufsize); + *p = PyString_AS_STRING(uarg); + } +#endif + else + return converterr("string or None", + arg, msgbuf, bufsize); + if (*format == '#') { + FETCH_SIZE; + assert(0); /* XXX redundant with if-case */ + if (arg == Py_None) + *q = 0; + else + *q = PyString_Size(arg); + format++; + } + else if (*p != NULL && + (Py_ssize_t)strlen(*p) != PyString_Size(arg)) + return converterr( + "string without null bytes or None", + arg, msgbuf, bufsize); + } + break; + } + + case 'e': {/* encoded string */ + char **buffer; + const char *encoding; + PyObject *s; + int size, recode_strings; + + /* Get 'e' parameter: the encoding name */ + encoding = (const char *)va_arg(*p_va, const char *); +#ifdef Py_USING_UNICODE + if (encoding == NULL) + encoding = PyUnicode_GetDefaultEncoding(); +#endif + + /* Get output buffer parameter: + 's' (recode all objects via Unicode) or + 't' (only recode non-string objects) + */ + if (*format == 's') + recode_strings = 1; + else if (*format == 't') + recode_strings = 0; + else + return converterr( + "(unknown parser marker combination)", + arg, msgbuf, bufsize); + buffer = (char **)va_arg(*p_va, char **); + format++; + if (buffer == NULL) + return converterr("(buffer is NULL)", + arg, msgbuf, bufsize); + + /* Encode object */ + if (!recode_strings && PyString_Check(arg)) { + s = arg; + Py_INCREF(s); + } + else { +#ifdef Py_USING_UNICODE + PyObject *u; + + /* Convert object to Unicode */ + u = PyUnicode_FromObject(arg); + if (u == NULL) + return converterr( + "string or unicode or text buffer", + arg, msgbuf, bufsize); + + /* Encode object; use default error handling */ + s = PyUnicode_AsEncodedString(u, + encoding, + NULL); + Py_DECREF(u); + if (s == NULL) + return converterr("(encoding failed)", + arg, msgbuf, bufsize); + if (!PyString_Check(s)) { + Py_DECREF(s); + return converterr( + "(encoder failed to return a string)", + arg, msgbuf, bufsize); + } +#else + return converterr("string<e>", arg, msgbuf, bufsize); +#endif + } + size = PyString_GET_SIZE(s); + + /* Write output; output is guaranteed to be 0-terminated */ + if (*format == '#') { + /* Using buffer length parameter '#': + + - if *buffer is NULL, a new buffer of the + needed size is allocated and the data + copied into it; *buffer is updated to point + to the new buffer; the caller is + responsible for PyMem_Free()ing it after + usage + + - if *buffer is not NULL, the data is + copied to *buffer; *buffer_len has to be + set to the size of the buffer on input; + buffer overflow is signalled with an error; + buffer has to provide enough room for the + encoded string plus the trailing 0-byte + + - in both cases, *buffer_len is updated to + the size of the buffer /excluding/ the + trailing 0-byte + + */ + FETCH_SIZE; + + format++; + if (q == NULL && q2 == NULL) { + Py_DECREF(s); + return converterr( + "(buffer_len is NULL)", + arg, msgbuf, bufsize); + } + if (*buffer == NULL) { + *buffer = PyMem_NEW(char, size + 1); + if (*buffer == NULL) { + Py_DECREF(s); + return converterr( + "(memory error)", + arg, msgbuf, bufsize); + } + if(addcleanup(*buffer, freelist)) { + Py_DECREF(s); + return converterr( + "(cleanup problem)", + arg, msgbuf, bufsize); + } + } else { + if (size + 1 > BUFFER_LEN) { + Py_DECREF(s); + return converterr( + "(buffer overflow)", + arg, msgbuf, bufsize); + } + } + memcpy(*buffer, + PyString_AS_STRING(s), + size + 1); + STORE_SIZE(size); + } else { + /* Using a 0-terminated buffer: + + - the encoded string has to be 0-terminated + for this variant to work; if it is not, an + error raised + + - a new buffer of the needed size is + allocated and the data copied into it; + *buffer is updated to point to the new + buffer; the caller is responsible for + PyMem_Free()ing it after usage + + */ + if ((Py_ssize_t)strlen(PyString_AS_STRING(s)) + != size) { + Py_DECREF(s); + return converterr( + "(encoded string without NULL bytes)", + arg, msgbuf, bufsize); + } + *buffer = PyMem_NEW(char, size + 1); + if (*buffer == NULL) { + Py_DECREF(s); + return converterr("(memory error)", + arg, msgbuf, bufsize); + } + if(addcleanup(*buffer, freelist)) { + Py_DECREF(s); + return converterr("(cleanup problem)", + arg, msgbuf, bufsize); + } + memcpy(*buffer, + PyString_AS_STRING(s), + size + 1); + } + Py_DECREF(s); + break; + } + +#ifdef Py_USING_UNICODE + case 'u': {/* raw unicode buffer (Py_UNICODE *) */ + if (*format == '#') { /* any buffer-like object */ + void **p = (void **)va_arg(*p_va, char **); + FETCH_SIZE; + if (PyUnicode_Check(arg)) { + *p = PyUnicode_AS_UNICODE(arg); + STORE_SIZE(PyUnicode_GET_SIZE(arg)); + } + else { + return converterr("cannot convert raw buffers", + arg, msgbuf, bufsize); + } + format++; + } else { + Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); + if (PyUnicode_Check(arg)) + *p = PyUnicode_AS_UNICODE(arg); + else + return converterr("unicode", arg, msgbuf, bufsize); + } + break; + } +#endif + + case 'S': { /* string object */ + PyObject **p = va_arg(*p_va, PyObject **); + if (PyString_Check(arg)) + *p = arg; + else + return converterr("string", arg, msgbuf, bufsize); + break; + } + +#ifdef Py_USING_UNICODE + case 'U': { /* Unicode object */ + PyObject **p = va_arg(*p_va, PyObject **); + if (PyUnicode_Check(arg)) + *p = arg; + else + return converterr("unicode", arg, msgbuf, bufsize); + break; + } +#endif + + case 'O': { /* object */ + PyTypeObject *type; + PyObject **p; + if (*format == '!') { + type = va_arg(*p_va, PyTypeObject*); + p = va_arg(*p_va, PyObject **); + format++; + if (PyType_IsSubtype(arg->ob_type, type)) + *p = arg; + else + return converterr(type->tp_name, arg, msgbuf, bufsize); + + } + else if (*format == '?') { + inquiry pred = va_arg(*p_va, inquiry); + p = va_arg(*p_va, PyObject **); + format++; + if ((*pred)(arg)) + *p = arg; + else + return converterr("(unspecified)", + arg, msgbuf, bufsize); + + } + else if (*format == '&') { + typedef int (*converter)(PyObject *, void *); + converter convert = va_arg(*p_va, converter); + void *addr = va_arg(*p_va, void *); + format++; + if (! (*convert)(arg, addr)) + return converterr("(unspecified)", + arg, msgbuf, bufsize); + } + else { + p = va_arg(*p_va, PyObject **); + *p = arg; + } + break; + } + + + case 'w': { /* memory buffer, read-write access */ + void **p = va_arg(*p_va, void **); + PyBufferProcs *pb = arg->ob_type->tp_as_buffer; + int count; + + if (pb == NULL || + pb->bf_getwritebuffer == NULL || + pb->bf_getsegcount == NULL) + return converterr("read-write buffer", arg, msgbuf, bufsize); + if ((*pb->bf_getsegcount)(arg, NULL) != 1) + return converterr("single-segment read-write buffer", + arg, msgbuf, bufsize); + if ((count = pb->bf_getwritebuffer(arg, 0, p)) < 0) + return converterr("(unspecified)", arg, msgbuf, bufsize); + if (*format == '#') { + FETCH_SIZE; + STORE_SIZE(count); + format++; + } + break; + } + + case 't': { /* 8-bit character buffer, read-only access */ + char **p = va_arg(*p_va, char **); + PyBufferProcs *pb = arg->ob_type->tp_as_buffer; + int count; + + if (*format++ != '#') + return converterr( + "invalid use of 't' format character", + arg, msgbuf, bufsize); + if (!PyType_HasFeature(arg->ob_type, + Py_TPFLAGS_HAVE_GETCHARBUFFER) || + pb == NULL || pb->bf_getcharbuffer == NULL || + pb->bf_getsegcount == NULL) + return converterr( + "string or read-only character buffer", + arg, msgbuf, bufsize); + + if (pb->bf_getsegcount(arg, NULL) != 1) + return converterr( + "string or single-segment read-only buffer", + arg, msgbuf, bufsize); + + count = pb->bf_getcharbuffer(arg, 0, p); + if (count < 0) + return converterr("(unspecified)", arg, msgbuf, bufsize); + { + FETCH_SIZE; + STORE_SIZE(count); + } + break; + } + + default: + return converterr("impossible<bad format char>", arg, msgbuf, bufsize); + + } + + *p_format = format; + return NULL; +} + +static Py_ssize_t +convertbuffer(PyObject *arg, void **p, char **errmsg) +{ + PyBufferProcs *pb = arg->ob_type->tp_as_buffer; + Py_ssize_t count; + if (pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL) { + *errmsg = "string or read-only buffer"; + return -1; + } + if ((*pb->bf_getsegcount)(arg, NULL) != 1) { + *errmsg = "string or single-segment read-only buffer"; + return -1; + } + if ((count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0) { + *errmsg = "(unspecified)"; + } + return count; +} + +/* Support for keyword arguments donated by + Geoff Philbrick <philbric@delphi.hks.com> */ + +/* Return false (0) for error, else true. */ +int +PyArg_ParseTupleAndKeywords(PyObject *args, + PyObject *keywords, + const char *format, + char **kwlist, ...) +{ + int retval; + va_list va; + + if ((args == NULL || !PyTuple_Check(args)) || + (keywords != NULL && !PyDict_Check(keywords)) || + format == NULL || + kwlist == NULL) + { + PyErr_BadInternalCall(); + return 0; + } + + va_start(va, kwlist); + retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0); + va_end(va); + return retval; +} + +int +_PyArg_ParseTupleAndKeywords_SizeT(PyObject *args, + PyObject *keywords, + const char *format, + char **kwlist, ...) +{ + int retval; + va_list va; + + if ((args == NULL || !PyTuple_Check(args)) || + (keywords != NULL && !PyDict_Check(keywords)) || + format == NULL || + kwlist == NULL) + { + PyErr_BadInternalCall(); + return 0; + } + + va_start(va, kwlist); + retval = vgetargskeywords(args, keywords, format, + kwlist, &va, FLAG_SIZE_T); + va_end(va); + return retval; +} + + +int +PyArg_VaParseTupleAndKeywords(PyObject *args, + PyObject *keywords, + const char *format, + char **kwlist, va_list va) +{ + int retval; + va_list lva; + + if ((args == NULL || !PyTuple_Check(args)) || + (keywords != NULL && !PyDict_Check(keywords)) || + format == NULL || + kwlist == NULL) + { + PyErr_BadInternalCall(); + return 0; + } + +#ifdef VA_LIST_IS_ARRAY + memcpy(lva, va, sizeof(va_list)); +#else +#ifdef __va_copy + __va_copy(lva, va); +#else + lva = va; +#endif +#endif + + retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0); + return retval; +} + +int +_PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args, + PyObject *keywords, + const char *format, + char **kwlist, va_list va) +{ + int retval; + va_list lva; + + if ((args == NULL || !PyTuple_Check(args)) || + (keywords != NULL && !PyDict_Check(keywords)) || + format == NULL || + kwlist == NULL) + { + PyErr_BadInternalCall(); + return 0; + } + +#ifdef VA_LIST_IS_ARRAY + memcpy(lva, va, sizeof(va_list)); +#else +#ifdef __va_copy + __va_copy(lva, va); +#else + lva = va; +#endif +#endif + + retval = vgetargskeywords(args, keywords, format, + kwlist, &lva, FLAG_SIZE_T); + return retval; +} + + +static int +vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, + char **kwlist, va_list *p_va, int flags) +{ + char msgbuf[512]; + int levels[32]; + const char *fname, *message; + int min, max; + const char *formatsave; + int i, len, nargs, nkeywords; + const char *msg; + char **p; + PyObject *freelist = NULL; + + assert(args != NULL && PyTuple_Check(args)); + assert(keywords == NULL || PyDict_Check(keywords)); + assert(format != NULL); + assert(kwlist != NULL); + assert(p_va != NULL); + + /* Search the format: + message <- error msg, if any (else NULL). + fname <- routine name, if any (else NULL). + min <- # of required arguments, or -1 if all are required. + max <- most arguments (required + optional). + Check that kwlist has a non-NULL entry for each arg. + Raise error if a tuple arg spec is found. + */ + fname = message = NULL; + formatsave = format; + p = kwlist; + min = -1; + max = 0; + while ((i = *format++) != '\0') { + if (isalpha(Py_CHARMASK(i)) && i != 'e') { + max++; + if (*p == NULL) { + PyErr_SetString(PyExc_RuntimeError, + "more argument specifiers than " + "keyword list entries"); + return 0; + } + p++; + } + else if (i == '|') + min = max; + else if (i == ':') { + fname = format; + break; + } + else if (i == ';') { + message = format; + break; + } + else if (i == '(') { + PyErr_SetString(PyExc_RuntimeError, + "tuple found in format when using keyword " + "arguments"); + return 0; + } + } + format = formatsave; + if (*p != NULL) { + PyErr_SetString(PyExc_RuntimeError, + "more keyword list entries than " + "argument specifiers"); + return 0; + } + if (min < 0) { + /* All arguments are required. */ + min = max; + } + + nargs = PyTuple_GET_SIZE(args); + nkeywords = keywords == NULL ? 0 : PyDict_Size(keywords); + + /* make sure there are no duplicate values for an argument; + its not clear when to use the term "keyword argument vs. + keyword parameter in messages */ + if (nkeywords > 0) { + for (i = 0; i < nargs; i++) { + const char *thiskw = kwlist[i]; + if (thiskw == NULL) + break; + if (PyDict_GetItemString(keywords, thiskw)) { + PyErr_Format(PyExc_TypeError, + "keyword parameter '%s' was given " + "by position and by name", + thiskw); + return 0; + } + else if (PyErr_Occurred()) + return 0; + } + } + + /* required arguments missing from args can be supplied by keyword + arguments; set len to the number of positional arguments, and, + if that's less than the minimum required, add in the number of + required arguments that are supplied by keywords */ + len = nargs; + if (nkeywords > 0 && nargs < min) { + for (i = nargs; i < min; i++) { + if (PyDict_GetItemString(keywords, kwlist[i])) + len++; + else if (PyErr_Occurred()) + return 0; + } + } + + /* make sure we got an acceptable number of arguments; the message + is a little confusing with keywords since keyword arguments + which are supplied, but don't match the required arguments + are not included in the "%d given" part of the message + XXX and this isn't a bug!? */ + if (len < min || max < len) { + if (message == NULL) { + PyOS_snprintf(msgbuf, sizeof(msgbuf), + "%.200s%s takes %s %d argument%s " + "(%d given)", + fname==NULL ? "function" : fname, + fname==NULL ? "" : "()", + min==max ? "exactly" + : len < min ? "at least" : "at most", + len < min ? min : max, + (len < min ? min : max) == 1 ? "" : "s", + len); + message = msgbuf; + } + PyErr_SetString(PyExc_TypeError, message); + return 0; + } + + /* convert the positional arguments */ + for (i = 0; i < nargs; i++) { + if (*format == '|') + format++; + msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va, + flags, levels, msgbuf, sizeof(msgbuf), + &freelist); + if (msg) { + seterror(i+1, msg, levels, fname, message); + return cleanreturn(0, freelist); + } + } + + /* handle no keyword parameters in call */ + if (nkeywords == 0) + return cleanreturn(1, freelist); + + /* convert the keyword arguments; this uses the format + string where it was left after processing args */ + for (i = nargs; i < max; i++) { + PyObject *item; + if (*format == '|') + format++; + item = PyDict_GetItemString(keywords, kwlist[i]); + if (item != NULL) { + Py_INCREF(item); + msg = convertitem(item, &format, p_va, flags, levels, + msgbuf, sizeof(msgbuf), &freelist); + Py_DECREF(item); + if (msg) { + seterror(i+1, msg, levels, fname, message); + return cleanreturn(0, freelist); + } + --nkeywords; + if (nkeywords == 0) + break; + } + else if (PyErr_Occurred()) + return cleanreturn(0, freelist); + else { + msg = skipitem(&format, p_va, flags); + if (msg) { + levels[0] = 0; + seterror(i+1, msg, levels, fname, message); + return cleanreturn(0, freelist); + } + } + } + + /* make sure there are no extraneous keyword arguments */ + if (nkeywords > 0) { + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(keywords, &pos, &key, &value)) { + int match = 0; + char *ks; + if (!PyString_Check(key)) { + PyErr_SetString(PyExc_TypeError, + "keywords must be strings"); + return cleanreturn(0, freelist); + } + ks = PyString_AsString(key); + for (i = 0; i < max; i++) { + if (!strcmp(ks, kwlist[i])) { + match = 1; + break; + } + } + if (!match) { + PyErr_Format(PyExc_TypeError, + "'%s' is an invalid keyword " + "argument for this function", + ks); + return cleanreturn(0, freelist); + } + } + } + + return cleanreturn(1, freelist); +} + + +static char * +skipitem(const char **p_format, va_list *p_va, int flags) +{ + const char *format = *p_format; + char c = *format++; + + switch (c) { + + /* simple codes + * The individual types (second arg of va_arg) are irrelevant */ + + case 'b': /* byte -- very short int */ + case 'B': /* byte as bitfield */ + case 'h': /* short int */ + case 'H': /* short int as bitfield */ + case 'i': /* int */ + case 'I': /* int sized bitfield */ + case 'l': /* long int */ + case 'k': /* long int sized bitfield */ +#ifdef HAVE_LONG_LONG + case 'L': /* PY_LONG_LONG */ + case 'K': /* PY_LONG_LONG sized bitfield */ +#endif + case 'f': /* float */ + case 'd': /* double */ +#ifndef WITHOUT_COMPLEX + case 'D': /* complex double */ +#endif + case 'c': /* char */ + { + (void) va_arg(*p_va, void *); + break; + } + + case 'n': /* Py_ssize_t */ + { + (void) va_arg(*p_va, Py_ssize_t *); + break; + } + + /* string codes */ + + case 'e': /* string with encoding */ + { + (void) va_arg(*p_va, const char *); + if (!(*format == 's' || *format == 't')) + /* after 'e', only 's' and 't' is allowed */ + goto err; + format++; + /* explicit fallthrough to string cases */ + } + + case 's': /* string */ + case 'z': /* string or None */ +#ifdef Py_USING_UNICODE + case 'u': /* unicode string */ +#endif + case 't': /* buffer, read-only */ + case 'w': /* buffer, read-write */ + { + (void) va_arg(*p_va, char **); + if (*format == '#') { + if (flags & FLAG_SIZE_T) + (void) va_arg(*p_va, Py_ssize_t *); + else + (void) va_arg(*p_va, int *); + format++; + } + break; + } + + /* object codes */ + + case 'S': /* string object */ +#ifdef Py_USING_UNICODE + case 'U': /* unicode string object */ +#endif + { + (void) va_arg(*p_va, PyObject **); + break; + } + + case 'O': /* object */ + { + if (*format == '!') { + format++; + (void) va_arg(*p_va, PyTypeObject*); + (void) va_arg(*p_va, PyObject **); + } +#if 0 +/* I don't know what this is for */ + else if (*format == '?') { + inquiry pred = va_arg(*p_va, inquiry); + format++; + if ((*pred)(arg)) { + (void) va_arg(*p_va, PyObject **); + } + } +#endif + else if (*format == '&') { + typedef int (*converter)(PyObject *, void *); + (void) va_arg(*p_va, converter); + (void) va_arg(*p_va, void *); + format++; + } + else { + (void) va_arg(*p_va, PyObject **); + } + break; + } + + default: +err: + return "impossible<bad format char>"; + + } + + /* The "(...)" format code for tuples is not handled here because + * it is not allowed with keyword args. */ + + *p_format = format; + return NULL; +} + + +int +PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...) +{ + Py_ssize_t i, l; + PyObject **o; + va_list vargs; + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, max); +#else + va_start(vargs); +#endif + + assert(min >= 0); + assert(min <= max); + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, + "PyArg_UnpackTuple() argument list is not a tuple"); + return 0; + } + l = PyTuple_GET_SIZE(args); + if (l < min) { + if (name != NULL) + PyErr_Format( + PyExc_TypeError, + "%s expected %s%zd arguments, got %zd", + name, (min == max ? "" : "at least "), min, l); + else + PyErr_Format( + PyExc_TypeError, + "unpacked tuple should have %s%zd elements," + " but has %zd", + (min == max ? "" : "at least "), min, l); + va_end(vargs); + return 0; + } + if (l > max) { + if (name != NULL) + PyErr_Format( + PyExc_TypeError, + "%s expected %s%zd arguments, got %zd", + name, (min == max ? "" : "at most "), max, l); + else + PyErr_Format( + PyExc_TypeError, + "unpacked tuple should have %s%zd elements," + " but has %zd", + (min == max ? "" : "at most "), max, l); + va_end(vargs); + return 0; + } + for (i = 0; i < l; i++) { + o = va_arg(vargs, PyObject **); + *o = PyTuple_GET_ITEM(args, i); + } + va_end(vargs); + return 1; +} + + +/* For type constructors that don't take keyword args + * + * Sets a TypeError and returns 0 if the kwds dict is + * not emtpy, returns 1 otherwise + */ +int +_PyArg_NoKeywords(const char *funcname, PyObject *kw) +{ + if (kw == NULL) + return 1; + if (!PyDict_CheckExact(kw)) { + PyErr_BadInternalCall(); + return 0; + } + if (PyDict_Size(kw) == 0) + return 1; + + PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments", + funcname); + return 0; +} +#ifdef __cplusplus +}; +#endif diff --git a/sys/src/cmd/python/Python/getcompiler.c b/sys/src/cmd/python/Python/getcompiler.c new file mode 100644 index 000000000..0f441deb8 --- /dev/null +++ b/sys/src/cmd/python/Python/getcompiler.c @@ -0,0 +1,28 @@ + +/* Return the compiler identification, if possible. */ + +#include "Python.h" + +#ifndef COMPILER + +#ifdef __GNUC__ +#define COMPILER "\n[GCC " __VERSION__ "]" +#endif + +#endif /* !COMPILER */ + +#ifndef COMPILER + +#ifdef __cplusplus +#define COMPILER "[C++]" +#else +#define COMPILER "[C]" +#endif + +#endif /* !COMPILER */ + +const char * +Py_GetCompiler(void) +{ + return COMPILER; +} diff --git a/sys/src/cmd/python/Python/getcopyright.c b/sys/src/cmd/python/Python/getcopyright.c new file mode 100644 index 000000000..c10aea452 --- /dev/null +++ b/sys/src/cmd/python/Python/getcopyright.c @@ -0,0 +1,23 @@ +/* Return the copyright string. This is updated manually. */ + +#include "Python.h" + +static char cprt[] = +"\ +Copyright (c) 2001-2007 Python Software Foundation.\n\ +All Rights Reserved.\n\ +\n\ +Copyright (c) 2000 BeOpen.com.\n\ +All Rights Reserved.\n\ +\n\ +Copyright (c) 1995-2001 Corporation for National Research Initiatives.\n\ +All Rights Reserved.\n\ +\n\ +Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n\ +All Rights Reserved."; + +const char * +Py_GetCopyright(void) +{ + return cprt; +} diff --git a/sys/src/cmd/python/Python/getcwd.c b/sys/src/cmd/python/Python/getcwd.c new file mode 100644 index 000000000..967d484b3 --- /dev/null +++ b/sys/src/cmd/python/Python/getcwd.c @@ -0,0 +1,83 @@ + +/* Two PD getcwd() implementations. + Author: Guido van Rossum, CWI Amsterdam, Jan 1991, <guido@cwi.nl>. */ + +#include <stdio.h> +#include <errno.h> + +#ifdef HAVE_GETWD + +/* Version for BSD systems -- use getwd() */ + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifndef MAXPATHLEN +#if defined(PATH_MAX) && PATH_MAX > 1024 +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 1024 +#endif +#endif + +extern char *getwd(char *); + +char * +getcwd(char *buf, int size) +{ + char localbuf[MAXPATHLEN+1]; + char *ret; + + if (size <= 0) { + errno = EINVAL; + return NULL; + } + ret = getwd(localbuf); + if (ret != NULL && strlen(localbuf) >= (size_t)size) { + errno = ERANGE; + return NULL; + } + if (ret == NULL) { + errno = EACCES; /* Most likely error */ + return NULL; + } + strncpy(buf, localbuf, size); + return buf; +} + +#else /* !HAVE_GETWD */ + +/* Version for really old UNIX systems -- use pipe from pwd */ + +#ifndef PWD_CMD +#define PWD_CMD "/bin/pwd" +#endif + +char * +getcwd(char *buf, int size) +{ + FILE *fp; + char *p; + int sts; + if (size <= 0) { + errno = EINVAL; + return NULL; + } + if ((fp = popen(PWD_CMD, "r")) == NULL) + return NULL; + if (fgets(buf, size, fp) == NULL || (sts = pclose(fp)) != 0) { + errno = EACCES; /* Most likely error */ + return NULL; + } + for (p = buf; *p != '\n'; p++) { + if (*p == '\0') { + errno = ERANGE; + return NULL; + } + } + *p = '\0'; + return buf; +} + +#endif /* !HAVE_GETWD */ diff --git a/sys/src/cmd/python/Python/getmtime.c b/sys/src/cmd/python/Python/getmtime.c new file mode 100644 index 000000000..54edb531d --- /dev/null +++ b/sys/src/cmd/python/Python/getmtime.c @@ -0,0 +1,26 @@ + +/* Subroutine to get the last modification time of a file */ + +/* (A separate file because this may be OS dependent) */ + +#include "Python.h" +#include "pyconfig.h" + +#ifdef __cplusplus +extern "C" { +#endif + +time_t +PyOS_GetLastModificationTime(char *path, FILE *fp) +{ + struct stat st; + if (fstat(fileno(fp), &st) != 0) + return -1; + else + return st.st_mtime; +} + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Python/getopt.c b/sys/src/cmd/python/Python/getopt.c new file mode 100644 index 000000000..659efcfff --- /dev/null +++ b/sys/src/cmd/python/Python/getopt.c @@ -0,0 +1,115 @@ +/*---------------------------------------------------------------------------* + * <RCS keywords> + * + * C++ Library + * + * Copyright 1992-1994, David Gottner + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice, this permission notice and + * the following disclaimer notice appear unmodified in all copies. + * + * I DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL I + * BE LIABLE FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY + * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Nevertheless, I would like to know about bugs in this library or + * suggestions for improvment. Send bug reports and feedback to + * davegottner@delphi.com. + *---------------------------------------------------------------------------*/ + +/* Modified to support --help and --version, as well as /? on Windows + * by Georg Brandl. */ + +#include <stdio.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +int _PyOS_opterr = 1; /* generate error messages */ +int _PyOS_optind = 1; /* index into argv array */ +char *_PyOS_optarg = NULL; /* optional argument */ + +int _PyOS_GetOpt(int argc, char **argv, char *optstring) +{ + static char *opt_ptr = ""; + char *ptr; + int option; + + if (*opt_ptr == '\0') { + + if (_PyOS_optind >= argc) + return -1; +#ifdef MS_WINDOWS + else if (strcmp(argv[_PyOS_optind], "/?") == 0) { + ++_PyOS_optind; + return 'h'; + } +#endif + + else if (argv[_PyOS_optind][0] != '-' || + argv[_PyOS_optind][1] == '\0' /* lone dash */ ) + return -1; + + else if (strcmp(argv[_PyOS_optind], "--") == 0) { + ++_PyOS_optind; + return -1; + } + + else if (strcmp(argv[_PyOS_optind], "--help") == 0) { + ++_PyOS_optind; + return 'h'; + } + + else if (strcmp(argv[_PyOS_optind], "--version") == 0) { + ++_PyOS_optind; + return 'V'; + } + + + opt_ptr = &argv[_PyOS_optind++][1]; + } + + if ( (option = *opt_ptr++) == '\0') + return -1; + + if ((ptr = strchr(optstring, option)) == NULL) { + if (_PyOS_opterr) + fprintf(stderr, "Unknown option: -%c\n", option); + + return '_'; + } + + if (*(ptr + 1) == ':') { + if (*opt_ptr != '\0') { + _PyOS_optarg = opt_ptr; + opt_ptr = ""; + } + + else { + if (_PyOS_optind >= argc) { + if (_PyOS_opterr) + fprintf(stderr, + "Argument expected for the -%c option\n", option); + return '_'; + } + + _PyOS_optarg = argv[_PyOS_optind++]; + } + } + + return option; +} + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Python/getplatform.c b/sys/src/cmd/python/Python/getplatform.c new file mode 100644 index 000000000..7a3c8b534 --- /dev/null +++ b/sys/src/cmd/python/Python/getplatform.c @@ -0,0 +1,12 @@ + +#include "Python.h" + +#ifndef PLATFORM +#define PLATFORM "plan9" +#endif + +const char * +Py_GetPlatform(void) +{ + return PLATFORM; +} diff --git a/sys/src/cmd/python/Python/getversion.c b/sys/src/cmd/python/Python/getversion.c new file mode 100644 index 000000000..7af16fc81 --- /dev/null +++ b/sys/src/cmd/python/Python/getversion.c @@ -0,0 +1,15 @@ + +/* Return the full version string. */ + +#include "Python.h" + +#include "patchlevel.h" + +const char * +Py_GetVersion(void) +{ + static char version[250]; + PyOS_snprintf(version, sizeof(version), "%.80s (%.80s) %.80s", + PY_VERSION, Py_GetBuildInfo(), Py_GetCompiler()); + return version; +} diff --git a/sys/src/cmd/python/Python/graminit.c b/sys/src/cmd/python/Python/graminit.c new file mode 100644 index 000000000..8f20502b1 --- /dev/null +++ b/sys/src/cmd/python/Python/graminit.c @@ -0,0 +1,2129 @@ +#include "pgenheaders.h" +#include "grammar.h" +static arc arcs_0_0[3] = { + {2, 1}, + {3, 1}, + {4, 2}, +}; +static arc arcs_0_1[1] = { + {0, 1}, +}; +static arc arcs_0_2[1] = { + {2, 1}, +}; +static state states_0[3] = { + {3, arcs_0_0}, + {1, arcs_0_1}, + {1, arcs_0_2}, +}; +static arc arcs_1_0[3] = { + {2, 0}, + {6, 0}, + {7, 1}, +}; +static arc arcs_1_1[1] = { + {0, 1}, +}; +static state states_1[2] = { + {3, arcs_1_0}, + {1, arcs_1_1}, +}; +static arc arcs_2_0[1] = { + {9, 1}, +}; +static arc arcs_2_1[2] = { + {2, 1}, + {7, 2}, +}; +static arc arcs_2_2[1] = { + {0, 2}, +}; +static state states_2[3] = { + {1, arcs_2_0}, + {2, arcs_2_1}, + {1, arcs_2_2}, +}; +static arc arcs_3_0[1] = { + {11, 1}, +}; +static arc arcs_3_1[1] = { + {12, 2}, +}; +static arc arcs_3_2[2] = { + {13, 3}, + {2, 4}, +}; +static arc arcs_3_3[2] = { + {14, 5}, + {15, 6}, +}; +static arc arcs_3_4[1] = { + {0, 4}, +}; +static arc arcs_3_5[1] = { + {15, 6}, +}; +static arc arcs_3_6[1] = { + {2, 4}, +}; +static state states_3[7] = { + {1, arcs_3_0}, + {1, arcs_3_1}, + {2, arcs_3_2}, + {2, arcs_3_3}, + {1, arcs_3_4}, + {1, arcs_3_5}, + {1, arcs_3_6}, +}; +static arc arcs_4_0[1] = { + {10, 1}, +}; +static arc arcs_4_1[2] = { + {10, 1}, + {0, 1}, +}; +static state states_4[2] = { + {1, arcs_4_0}, + {2, arcs_4_1}, +}; +static arc arcs_5_0[2] = { + {16, 1}, + {18, 2}, +}; +static arc arcs_5_1[1] = { + {18, 2}, +}; +static arc arcs_5_2[1] = { + {19, 3}, +}; +static arc arcs_5_3[1] = { + {20, 4}, +}; +static arc arcs_5_4[1] = { + {21, 5}, +}; +static arc arcs_5_5[1] = { + {22, 6}, +}; +static arc arcs_5_6[1] = { + {0, 6}, +}; +static state states_5[7] = { + {2, arcs_5_0}, + {1, arcs_5_1}, + {1, arcs_5_2}, + {1, arcs_5_3}, + {1, arcs_5_4}, + {1, arcs_5_5}, + {1, arcs_5_6}, +}; +static arc arcs_6_0[1] = { + {13, 1}, +}; +static arc arcs_6_1[2] = { + {23, 2}, + {15, 3}, +}; +static arc arcs_6_2[1] = { + {15, 3}, +}; +static arc arcs_6_3[1] = { + {0, 3}, +}; +static state states_6[4] = { + {1, arcs_6_0}, + {2, arcs_6_1}, + {1, arcs_6_2}, + {1, arcs_6_3}, +}; +static arc arcs_7_0[3] = { + {24, 1}, + {28, 2}, + {29, 3}, +}; +static arc arcs_7_1[3] = { + {25, 4}, + {27, 5}, + {0, 1}, +}; +static arc arcs_7_2[1] = { + {19, 6}, +}; +static arc arcs_7_3[1] = { + {19, 7}, +}; +static arc arcs_7_4[1] = { + {26, 8}, +}; +static arc arcs_7_5[4] = { + {24, 1}, + {28, 2}, + {29, 3}, + {0, 5}, +}; +static arc arcs_7_6[2] = { + {27, 9}, + {0, 6}, +}; +static arc arcs_7_7[1] = { + {0, 7}, +}; +static arc arcs_7_8[2] = { + {27, 5}, + {0, 8}, +}; +static arc arcs_7_9[1] = { + {29, 3}, +}; +static state states_7[10] = { + {3, arcs_7_0}, + {3, arcs_7_1}, + {1, arcs_7_2}, + {1, arcs_7_3}, + {1, arcs_7_4}, + {4, arcs_7_5}, + {2, arcs_7_6}, + {1, arcs_7_7}, + {2, arcs_7_8}, + {1, arcs_7_9}, +}; +static arc arcs_8_0[2] = { + {19, 1}, + {13, 2}, +}; +static arc arcs_8_1[1] = { + {0, 1}, +}; +static arc arcs_8_2[1] = { + {30, 3}, +}; +static arc arcs_8_3[1] = { + {15, 1}, +}; +static state states_8[4] = { + {2, arcs_8_0}, + {1, arcs_8_1}, + {1, arcs_8_2}, + {1, arcs_8_3}, +}; +static arc arcs_9_0[1] = { + {24, 1}, +}; +static arc arcs_9_1[2] = { + {27, 2}, + {0, 1}, +}; +static arc arcs_9_2[2] = { + {24, 1}, + {0, 2}, +}; +static state states_9[3] = { + {1, arcs_9_0}, + {2, arcs_9_1}, + {2, arcs_9_2}, +}; +static arc arcs_10_0[2] = { + {3, 1}, + {4, 1}, +}; +static arc arcs_10_1[1] = { + {0, 1}, +}; +static state states_10[2] = { + {2, arcs_10_0}, + {1, arcs_10_1}, +}; +static arc arcs_11_0[1] = { + {31, 1}, +}; +static arc arcs_11_1[2] = { + {32, 2}, + {2, 3}, +}; +static arc arcs_11_2[2] = { + {31, 1}, + {2, 3}, +}; +static arc arcs_11_3[1] = { + {0, 3}, +}; +static state states_11[4] = { + {1, arcs_11_0}, + {2, arcs_11_1}, + {2, arcs_11_2}, + {1, arcs_11_3}, +}; +static arc arcs_12_0[9] = { + {33, 1}, + {34, 1}, + {35, 1}, + {36, 1}, + {37, 1}, + {38, 1}, + {39, 1}, + {40, 1}, + {41, 1}, +}; +static arc arcs_12_1[1] = { + {0, 1}, +}; +static state states_12[2] = { + {9, arcs_12_0}, + {1, arcs_12_1}, +}; +static arc arcs_13_0[1] = { + {9, 1}, +}; +static arc arcs_13_1[3] = { + {42, 2}, + {25, 3}, + {0, 1}, +}; +static arc arcs_13_2[2] = { + {43, 4}, + {9, 4}, +}; +static arc arcs_13_3[2] = { + {43, 5}, + {9, 5}, +}; +static arc arcs_13_4[1] = { + {0, 4}, +}; +static arc arcs_13_5[2] = { + {25, 3}, + {0, 5}, +}; +static state states_13[6] = { + {1, arcs_13_0}, + {3, arcs_13_1}, + {2, arcs_13_2}, + {2, arcs_13_3}, + {1, arcs_13_4}, + {2, arcs_13_5}, +}; +static arc arcs_14_0[12] = { + {44, 1}, + {45, 1}, + {46, 1}, + {47, 1}, + {48, 1}, + {49, 1}, + {50, 1}, + {51, 1}, + {52, 1}, + {53, 1}, + {54, 1}, + {55, 1}, +}; +static arc arcs_14_1[1] = { + {0, 1}, +}; +static state states_14[2] = { + {12, arcs_14_0}, + {1, arcs_14_1}, +}; +static arc arcs_15_0[1] = { + {56, 1}, +}; +static arc arcs_15_1[3] = { + {26, 2}, + {57, 3}, + {0, 1}, +}; +static arc arcs_15_2[2] = { + {27, 4}, + {0, 2}, +}; +static arc arcs_15_3[1] = { + {26, 5}, +}; +static arc arcs_15_4[2] = { + {26, 2}, + {0, 4}, +}; +static arc arcs_15_5[2] = { + {27, 6}, + {0, 5}, +}; +static arc arcs_15_6[1] = { + {26, 7}, +}; +static arc arcs_15_7[2] = { + {27, 8}, + {0, 7}, +}; +static arc arcs_15_8[2] = { + {26, 7}, + {0, 8}, +}; +static state states_15[9] = { + {1, arcs_15_0}, + {3, arcs_15_1}, + {2, arcs_15_2}, + {1, arcs_15_3}, + {2, arcs_15_4}, + {2, arcs_15_5}, + {1, arcs_15_6}, + {2, arcs_15_7}, + {2, arcs_15_8}, +}; +static arc arcs_16_0[1] = { + {58, 1}, +}; +static arc arcs_16_1[1] = { + {59, 2}, +}; +static arc arcs_16_2[1] = { + {0, 2}, +}; +static state states_16[3] = { + {1, arcs_16_0}, + {1, arcs_16_1}, + {1, arcs_16_2}, +}; +static arc arcs_17_0[1] = { + {60, 1}, +}; +static arc arcs_17_1[1] = { + {0, 1}, +}; +static state states_17[2] = { + {1, arcs_17_0}, + {1, arcs_17_1}, +}; +static arc arcs_18_0[5] = { + {61, 1}, + {62, 1}, + {63, 1}, + {64, 1}, + {65, 1}, +}; +static arc arcs_18_1[1] = { + {0, 1}, +}; +static state states_18[2] = { + {5, arcs_18_0}, + {1, arcs_18_1}, +}; +static arc arcs_19_0[1] = { + {66, 1}, +}; +static arc arcs_19_1[1] = { + {0, 1}, +}; +static state states_19[2] = { + {1, arcs_19_0}, + {1, arcs_19_1}, +}; +static arc arcs_20_0[1] = { + {67, 1}, +}; +static arc arcs_20_1[1] = { + {0, 1}, +}; +static state states_20[2] = { + {1, arcs_20_0}, + {1, arcs_20_1}, +}; +static arc arcs_21_0[1] = { + {68, 1}, +}; +static arc arcs_21_1[2] = { + {9, 2}, + {0, 1}, +}; +static arc arcs_21_2[1] = { + {0, 2}, +}; +static state states_21[3] = { + {1, arcs_21_0}, + {2, arcs_21_1}, + {1, arcs_21_2}, +}; +static arc arcs_22_0[1] = { + {43, 1}, +}; +static arc arcs_22_1[1] = { + {0, 1}, +}; +static state states_22[2] = { + {1, arcs_22_0}, + {1, arcs_22_1}, +}; +static arc arcs_23_0[1] = { + {69, 1}, +}; +static arc arcs_23_1[2] = { + {26, 2}, + {0, 1}, +}; +static arc arcs_23_2[2] = { + {27, 3}, + {0, 2}, +}; +static arc arcs_23_3[1] = { + {26, 4}, +}; +static arc arcs_23_4[2] = { + {27, 5}, + {0, 4}, +}; +static arc arcs_23_5[1] = { + {26, 6}, +}; +static arc arcs_23_6[1] = { + {0, 6}, +}; +static state states_23[7] = { + {1, arcs_23_0}, + {2, arcs_23_1}, + {2, arcs_23_2}, + {1, arcs_23_3}, + {2, arcs_23_4}, + {1, arcs_23_5}, + {1, arcs_23_6}, +}; +static arc arcs_24_0[2] = { + {70, 1}, + {71, 1}, +}; +static arc arcs_24_1[1] = { + {0, 1}, +}; +static state states_24[2] = { + {2, arcs_24_0}, + {1, arcs_24_1}, +}; +static arc arcs_25_0[1] = { + {72, 1}, +}; +static arc arcs_25_1[1] = { + {73, 2}, +}; +static arc arcs_25_2[1] = { + {0, 2}, +}; +static state states_25[3] = { + {1, arcs_25_0}, + {1, arcs_25_1}, + {1, arcs_25_2}, +}; +static arc arcs_26_0[1] = { + {74, 1}, +}; +static arc arcs_26_1[2] = { + {75, 2}, + {12, 3}, +}; +static arc arcs_26_2[3] = { + {75, 2}, + {12, 3}, + {72, 4}, +}; +static arc arcs_26_3[1] = { + {72, 4}, +}; +static arc arcs_26_4[3] = { + {28, 5}, + {13, 6}, + {76, 5}, +}; +static arc arcs_26_5[1] = { + {0, 5}, +}; +static arc arcs_26_6[1] = { + {76, 7}, +}; +static arc arcs_26_7[1] = { + {15, 5}, +}; +static state states_26[8] = { + {1, arcs_26_0}, + {2, arcs_26_1}, + {3, arcs_26_2}, + {1, arcs_26_3}, + {3, arcs_26_4}, + {1, arcs_26_5}, + {1, arcs_26_6}, + {1, arcs_26_7}, +}; +static arc arcs_27_0[1] = { + {19, 1}, +}; +static arc arcs_27_1[3] = { + {78, 2}, + {19, 2}, + {0, 1}, +}; +static arc arcs_27_2[1] = { + {19, 3}, +}; +static arc arcs_27_3[1] = { + {0, 3}, +}; +static state states_27[4] = { + {1, arcs_27_0}, + {3, arcs_27_1}, + {1, arcs_27_2}, + {1, arcs_27_3}, +}; +static arc arcs_28_0[1] = { + {12, 1}, +}; +static arc arcs_28_1[3] = { + {78, 2}, + {19, 2}, + {0, 1}, +}; +static arc arcs_28_2[1] = { + {19, 3}, +}; +static arc arcs_28_3[1] = { + {0, 3}, +}; +static state states_28[4] = { + {1, arcs_28_0}, + {3, arcs_28_1}, + {1, arcs_28_2}, + {1, arcs_28_3}, +}; +static arc arcs_29_0[1] = { + {77, 1}, +}; +static arc arcs_29_1[2] = { + {27, 2}, + {0, 1}, +}; +static arc arcs_29_2[2] = { + {77, 1}, + {0, 2}, +}; +static state states_29[3] = { + {1, arcs_29_0}, + {2, arcs_29_1}, + {2, arcs_29_2}, +}; +static arc arcs_30_0[1] = { + {79, 1}, +}; +static arc arcs_30_1[2] = { + {27, 0}, + {0, 1}, +}; +static state states_30[2] = { + {1, arcs_30_0}, + {2, arcs_30_1}, +}; +static arc arcs_31_0[1] = { + {19, 1}, +}; +static arc arcs_31_1[2] = { + {75, 0}, + {0, 1}, +}; +static state states_31[2] = { + {1, arcs_31_0}, + {2, arcs_31_1}, +}; +static arc arcs_32_0[1] = { + {80, 1}, +}; +static arc arcs_32_1[1] = { + {19, 2}, +}; +static arc arcs_32_2[2] = { + {27, 1}, + {0, 2}, +}; +static state states_32[3] = { + {1, arcs_32_0}, + {1, arcs_32_1}, + {2, arcs_32_2}, +}; +static arc arcs_33_0[1] = { + {81, 1}, +}; +static arc arcs_33_1[1] = { + {82, 2}, +}; +static arc arcs_33_2[2] = { + {83, 3}, + {0, 2}, +}; +static arc arcs_33_3[1] = { + {26, 4}, +}; +static arc arcs_33_4[2] = { + {27, 5}, + {0, 4}, +}; +static arc arcs_33_5[1] = { + {26, 6}, +}; +static arc arcs_33_6[1] = { + {0, 6}, +}; +static state states_33[7] = { + {1, arcs_33_0}, + {1, arcs_33_1}, + {2, arcs_33_2}, + {1, arcs_33_3}, + {2, arcs_33_4}, + {1, arcs_33_5}, + {1, arcs_33_6}, +}; +static arc arcs_34_0[1] = { + {84, 1}, +}; +static arc arcs_34_1[1] = { + {26, 2}, +}; +static arc arcs_34_2[2] = { + {27, 3}, + {0, 2}, +}; +static arc arcs_34_3[1] = { + {26, 4}, +}; +static arc arcs_34_4[1] = { + {0, 4}, +}; +static state states_34[5] = { + {1, arcs_34_0}, + {1, arcs_34_1}, + {2, arcs_34_2}, + {1, arcs_34_3}, + {1, arcs_34_4}, +}; +static arc arcs_35_0[7] = { + {85, 1}, + {86, 1}, + {87, 1}, + {88, 1}, + {89, 1}, + {17, 1}, + {90, 1}, +}; +static arc arcs_35_1[1] = { + {0, 1}, +}; +static state states_35[2] = { + {7, arcs_35_0}, + {1, arcs_35_1}, +}; +static arc arcs_36_0[1] = { + {91, 1}, +}; +static arc arcs_36_1[1] = { + {26, 2}, +}; +static arc arcs_36_2[1] = { + {21, 3}, +}; +static arc arcs_36_3[1] = { + {22, 4}, +}; +static arc arcs_36_4[3] = { + {92, 1}, + {93, 5}, + {0, 4}, +}; +static arc arcs_36_5[1] = { + {21, 6}, +}; +static arc arcs_36_6[1] = { + {22, 7}, +}; +static arc arcs_36_7[1] = { + {0, 7}, +}; +static state states_36[8] = { + {1, arcs_36_0}, + {1, arcs_36_1}, + {1, arcs_36_2}, + {1, arcs_36_3}, + {3, arcs_36_4}, + {1, arcs_36_5}, + {1, arcs_36_6}, + {1, arcs_36_7}, +}; +static arc arcs_37_0[1] = { + {94, 1}, +}; +static arc arcs_37_1[1] = { + {26, 2}, +}; +static arc arcs_37_2[1] = { + {21, 3}, +}; +static arc arcs_37_3[1] = { + {22, 4}, +}; +static arc arcs_37_4[2] = { + {93, 5}, + {0, 4}, +}; +static arc arcs_37_5[1] = { + {21, 6}, +}; +static arc arcs_37_6[1] = { + {22, 7}, +}; +static arc arcs_37_7[1] = { + {0, 7}, +}; +static state states_37[8] = { + {1, arcs_37_0}, + {1, arcs_37_1}, + {1, arcs_37_2}, + {1, arcs_37_3}, + {2, arcs_37_4}, + {1, arcs_37_5}, + {1, arcs_37_6}, + {1, arcs_37_7}, +}; +static arc arcs_38_0[1] = { + {95, 1}, +}; +static arc arcs_38_1[1] = { + {59, 2}, +}; +static arc arcs_38_2[1] = { + {83, 3}, +}; +static arc arcs_38_3[1] = { + {9, 4}, +}; +static arc arcs_38_4[1] = { + {21, 5}, +}; +static arc arcs_38_5[1] = { + {22, 6}, +}; +static arc arcs_38_6[2] = { + {93, 7}, + {0, 6}, +}; +static arc arcs_38_7[1] = { + {21, 8}, +}; +static arc arcs_38_8[1] = { + {22, 9}, +}; +static arc arcs_38_9[1] = { + {0, 9}, +}; +static state states_38[10] = { + {1, arcs_38_0}, + {1, arcs_38_1}, + {1, arcs_38_2}, + {1, arcs_38_3}, + {1, arcs_38_4}, + {1, arcs_38_5}, + {2, arcs_38_6}, + {1, arcs_38_7}, + {1, arcs_38_8}, + {1, arcs_38_9}, +}; +static arc arcs_39_0[1] = { + {96, 1}, +}; +static arc arcs_39_1[1] = { + {21, 2}, +}; +static arc arcs_39_2[1] = { + {22, 3}, +}; +static arc arcs_39_3[2] = { + {97, 4}, + {98, 5}, +}; +static arc arcs_39_4[1] = { + {21, 6}, +}; +static arc arcs_39_5[1] = { + {21, 7}, +}; +static arc arcs_39_6[1] = { + {22, 8}, +}; +static arc arcs_39_7[1] = { + {22, 9}, +}; +static arc arcs_39_8[4] = { + {97, 4}, + {93, 10}, + {98, 5}, + {0, 8}, +}; +static arc arcs_39_9[1] = { + {0, 9}, +}; +static arc arcs_39_10[1] = { + {21, 11}, +}; +static arc arcs_39_11[1] = { + {22, 12}, +}; +static arc arcs_39_12[2] = { + {98, 5}, + {0, 12}, +}; +static state states_39[13] = { + {1, arcs_39_0}, + {1, arcs_39_1}, + {1, arcs_39_2}, + {2, arcs_39_3}, + {1, arcs_39_4}, + {1, arcs_39_5}, + {1, arcs_39_6}, + {1, arcs_39_7}, + {4, arcs_39_8}, + {1, arcs_39_9}, + {1, arcs_39_10}, + {1, arcs_39_11}, + {2, arcs_39_12}, +}; +static arc arcs_40_0[1] = { + {99, 1}, +}; +static arc arcs_40_1[1] = { + {26, 2}, +}; +static arc arcs_40_2[2] = { + {100, 3}, + {21, 4}, +}; +static arc arcs_40_3[1] = { + {21, 4}, +}; +static arc arcs_40_4[1] = { + {22, 5}, +}; +static arc arcs_40_5[1] = { + {0, 5}, +}; +static state states_40[6] = { + {1, arcs_40_0}, + {1, arcs_40_1}, + {2, arcs_40_2}, + {1, arcs_40_3}, + {1, arcs_40_4}, + {1, arcs_40_5}, +}; +static arc arcs_41_0[2] = { + {78, 1}, + {19, 1}, +}; +static arc arcs_41_1[1] = { + {82, 2}, +}; +static arc arcs_41_2[1] = { + {0, 2}, +}; +static state states_41[3] = { + {2, arcs_41_0}, + {1, arcs_41_1}, + {1, arcs_41_2}, +}; +static arc arcs_42_0[1] = { + {101, 1}, +}; +static arc arcs_42_1[2] = { + {26, 2}, + {0, 1}, +}; +static arc arcs_42_2[2] = { + {27, 3}, + {0, 2}, +}; +static arc arcs_42_3[1] = { + {26, 4}, +}; +static arc arcs_42_4[1] = { + {0, 4}, +}; +static state states_42[5] = { + {1, arcs_42_0}, + {2, arcs_42_1}, + {2, arcs_42_2}, + {1, arcs_42_3}, + {1, arcs_42_4}, +}; +static arc arcs_43_0[2] = { + {3, 1}, + {2, 2}, +}; +static arc arcs_43_1[1] = { + {0, 1}, +}; +static arc arcs_43_2[1] = { + {102, 3}, +}; +static arc arcs_43_3[1] = { + {6, 4}, +}; +static arc arcs_43_4[2] = { + {6, 4}, + {103, 1}, +}; +static state states_43[5] = { + {2, arcs_43_0}, + {1, arcs_43_1}, + {1, arcs_43_2}, + {1, arcs_43_3}, + {2, arcs_43_4}, +}; +static arc arcs_44_0[1] = { + {105, 1}, +}; +static arc arcs_44_1[2] = { + {27, 2}, + {0, 1}, +}; +static arc arcs_44_2[1] = { + {105, 3}, +}; +static arc arcs_44_3[2] = { + {27, 4}, + {0, 3}, +}; +static arc arcs_44_4[2] = { + {105, 3}, + {0, 4}, +}; +static state states_44[5] = { + {1, arcs_44_0}, + {2, arcs_44_1}, + {1, arcs_44_2}, + {2, arcs_44_3}, + {2, arcs_44_4}, +}; +static arc arcs_45_0[2] = { + {106, 1}, + {107, 1}, +}; +static arc arcs_45_1[1] = { + {0, 1}, +}; +static state states_45[2] = { + {2, arcs_45_0}, + {1, arcs_45_1}, +}; +static arc arcs_46_0[1] = { + {108, 1}, +}; +static arc arcs_46_1[2] = { + {23, 2}, + {21, 3}, +}; +static arc arcs_46_2[1] = { + {21, 3}, +}; +static arc arcs_46_3[1] = { + {105, 4}, +}; +static arc arcs_46_4[1] = { + {0, 4}, +}; +static state states_46[5] = { + {1, arcs_46_0}, + {2, arcs_46_1}, + {1, arcs_46_2}, + {1, arcs_46_3}, + {1, arcs_46_4}, +}; +static arc arcs_47_0[2] = { + {106, 1}, + {109, 2}, +}; +static arc arcs_47_1[2] = { + {91, 3}, + {0, 1}, +}; +static arc arcs_47_2[1] = { + {0, 2}, +}; +static arc arcs_47_3[1] = { + {106, 4}, +}; +static arc arcs_47_4[1] = { + {93, 5}, +}; +static arc arcs_47_5[1] = { + {26, 2}, +}; +static state states_47[6] = { + {2, arcs_47_0}, + {2, arcs_47_1}, + {1, arcs_47_2}, + {1, arcs_47_3}, + {1, arcs_47_4}, + {1, arcs_47_5}, +}; +static arc arcs_48_0[1] = { + {110, 1}, +}; +static arc arcs_48_1[2] = { + {111, 0}, + {0, 1}, +}; +static state states_48[2] = { + {1, arcs_48_0}, + {2, arcs_48_1}, +}; +static arc arcs_49_0[1] = { + {112, 1}, +}; +static arc arcs_49_1[2] = { + {113, 0}, + {0, 1}, +}; +static state states_49[2] = { + {1, arcs_49_0}, + {2, arcs_49_1}, +}; +static arc arcs_50_0[2] = { + {114, 1}, + {115, 2}, +}; +static arc arcs_50_1[1] = { + {112, 2}, +}; +static arc arcs_50_2[1] = { + {0, 2}, +}; +static state states_50[3] = { + {2, arcs_50_0}, + {1, arcs_50_1}, + {1, arcs_50_2}, +}; +static arc arcs_51_0[1] = { + {82, 1}, +}; +static arc arcs_51_1[2] = { + {116, 0}, + {0, 1}, +}; +static state states_51[2] = { + {1, arcs_51_0}, + {2, arcs_51_1}, +}; +static arc arcs_52_0[10] = { + {117, 1}, + {118, 1}, + {119, 1}, + {120, 1}, + {121, 1}, + {122, 1}, + {123, 1}, + {83, 1}, + {114, 2}, + {124, 3}, +}; +static arc arcs_52_1[1] = { + {0, 1}, +}; +static arc arcs_52_2[1] = { + {83, 1}, +}; +static arc arcs_52_3[2] = { + {114, 1}, + {0, 3}, +}; +static state states_52[4] = { + {10, arcs_52_0}, + {1, arcs_52_1}, + {1, arcs_52_2}, + {2, arcs_52_3}, +}; +static arc arcs_53_0[1] = { + {125, 1}, +}; +static arc arcs_53_1[2] = { + {126, 0}, + {0, 1}, +}; +static state states_53[2] = { + {1, arcs_53_0}, + {2, arcs_53_1}, +}; +static arc arcs_54_0[1] = { + {127, 1}, +}; +static arc arcs_54_1[2] = { + {128, 0}, + {0, 1}, +}; +static state states_54[2] = { + {1, arcs_54_0}, + {2, arcs_54_1}, +}; +static arc arcs_55_0[1] = { + {129, 1}, +}; +static arc arcs_55_1[2] = { + {130, 0}, + {0, 1}, +}; +static state states_55[2] = { + {1, arcs_55_0}, + {2, arcs_55_1}, +}; +static arc arcs_56_0[1] = { + {131, 1}, +}; +static arc arcs_56_1[3] = { + {132, 0}, + {57, 0}, + {0, 1}, +}; +static state states_56[2] = { + {1, arcs_56_0}, + {3, arcs_56_1}, +}; +static arc arcs_57_0[1] = { + {133, 1}, +}; +static arc arcs_57_1[3] = { + {134, 0}, + {135, 0}, + {0, 1}, +}; +static state states_57[2] = { + {1, arcs_57_0}, + {3, arcs_57_1}, +}; +static arc arcs_58_0[1] = { + {136, 1}, +}; +static arc arcs_58_1[5] = { + {28, 0}, + {137, 0}, + {138, 0}, + {139, 0}, + {0, 1}, +}; +static state states_58[2] = { + {1, arcs_58_0}, + {5, arcs_58_1}, +}; +static arc arcs_59_0[4] = { + {134, 1}, + {135, 1}, + {140, 1}, + {141, 2}, +}; +static arc arcs_59_1[1] = { + {136, 2}, +}; +static arc arcs_59_2[1] = { + {0, 2}, +}; +static state states_59[3] = { + {4, arcs_59_0}, + {1, arcs_59_1}, + {1, arcs_59_2}, +}; +static arc arcs_60_0[1] = { + {142, 1}, +}; +static arc arcs_60_1[3] = { + {143, 1}, + {29, 2}, + {0, 1}, +}; +static arc arcs_60_2[1] = { + {136, 3}, +}; +static arc arcs_60_3[1] = { + {0, 3}, +}; +static state states_60[4] = { + {1, arcs_60_0}, + {3, arcs_60_1}, + {1, arcs_60_2}, + {1, arcs_60_3}, +}; +static arc arcs_61_0[7] = { + {13, 1}, + {145, 2}, + {148, 3}, + {151, 4}, + {19, 5}, + {153, 5}, + {154, 6}, +}; +static arc arcs_61_1[3] = { + {43, 7}, + {144, 7}, + {15, 5}, +}; +static arc arcs_61_2[2] = { + {146, 8}, + {147, 5}, +}; +static arc arcs_61_3[2] = { + {149, 9}, + {150, 5}, +}; +static arc arcs_61_4[1] = { + {152, 10}, +}; +static arc arcs_61_5[1] = { + {0, 5}, +}; +static arc arcs_61_6[2] = { + {154, 6}, + {0, 6}, +}; +static arc arcs_61_7[1] = { + {15, 5}, +}; +static arc arcs_61_8[1] = { + {147, 5}, +}; +static arc arcs_61_9[1] = { + {150, 5}, +}; +static arc arcs_61_10[1] = { + {151, 5}, +}; +static state states_61[11] = { + {7, arcs_61_0}, + {3, arcs_61_1}, + {2, arcs_61_2}, + {2, arcs_61_3}, + {1, arcs_61_4}, + {1, arcs_61_5}, + {2, arcs_61_6}, + {1, arcs_61_7}, + {1, arcs_61_8}, + {1, arcs_61_9}, + {1, arcs_61_10}, +}; +static arc arcs_62_0[1] = { + {26, 1}, +}; +static arc arcs_62_1[3] = { + {155, 2}, + {27, 3}, + {0, 1}, +}; +static arc arcs_62_2[1] = { + {0, 2}, +}; +static arc arcs_62_3[2] = { + {26, 4}, + {0, 3}, +}; +static arc arcs_62_4[2] = { + {27, 3}, + {0, 4}, +}; +static state states_62[5] = { + {1, arcs_62_0}, + {3, arcs_62_1}, + {1, arcs_62_2}, + {2, arcs_62_3}, + {2, arcs_62_4}, +}; +static arc arcs_63_0[1] = { + {26, 1}, +}; +static arc arcs_63_1[3] = { + {156, 2}, + {27, 3}, + {0, 1}, +}; +static arc arcs_63_2[1] = { + {0, 2}, +}; +static arc arcs_63_3[2] = { + {26, 4}, + {0, 3}, +}; +static arc arcs_63_4[2] = { + {27, 3}, + {0, 4}, +}; +static state states_63[5] = { + {1, arcs_63_0}, + {3, arcs_63_1}, + {1, arcs_63_2}, + {2, arcs_63_3}, + {2, arcs_63_4}, +}; +static arc arcs_64_0[1] = { + {108, 1}, +}; +static arc arcs_64_1[2] = { + {23, 2}, + {21, 3}, +}; +static arc arcs_64_2[1] = { + {21, 3}, +}; +static arc arcs_64_3[1] = { + {26, 4}, +}; +static arc arcs_64_4[1] = { + {0, 4}, +}; +static state states_64[5] = { + {1, arcs_64_0}, + {2, arcs_64_1}, + {1, arcs_64_2}, + {1, arcs_64_3}, + {1, arcs_64_4}, +}; +static arc arcs_65_0[3] = { + {13, 1}, + {145, 2}, + {75, 3}, +}; +static arc arcs_65_1[2] = { + {14, 4}, + {15, 5}, +}; +static arc arcs_65_2[1] = { + {157, 6}, +}; +static arc arcs_65_3[1] = { + {19, 5}, +}; +static arc arcs_65_4[1] = { + {15, 5}, +}; +static arc arcs_65_5[1] = { + {0, 5}, +}; +static arc arcs_65_6[1] = { + {147, 5}, +}; +static state states_65[7] = { + {3, arcs_65_0}, + {2, arcs_65_1}, + {1, arcs_65_2}, + {1, arcs_65_3}, + {1, arcs_65_4}, + {1, arcs_65_5}, + {1, arcs_65_6}, +}; +static arc arcs_66_0[1] = { + {158, 1}, +}; +static arc arcs_66_1[2] = { + {27, 2}, + {0, 1}, +}; +static arc arcs_66_2[2] = { + {158, 1}, + {0, 2}, +}; +static state states_66[3] = { + {1, arcs_66_0}, + {2, arcs_66_1}, + {2, arcs_66_2}, +}; +static arc arcs_67_0[3] = { + {75, 1}, + {26, 2}, + {21, 3}, +}; +static arc arcs_67_1[1] = { + {75, 4}, +}; +static arc arcs_67_2[2] = { + {21, 3}, + {0, 2}, +}; +static arc arcs_67_3[3] = { + {26, 5}, + {159, 6}, + {0, 3}, +}; +static arc arcs_67_4[1] = { + {75, 6}, +}; +static arc arcs_67_5[2] = { + {159, 6}, + {0, 5}, +}; +static arc arcs_67_6[1] = { + {0, 6}, +}; +static state states_67[7] = { + {3, arcs_67_0}, + {1, arcs_67_1}, + {2, arcs_67_2}, + {3, arcs_67_3}, + {1, arcs_67_4}, + {2, arcs_67_5}, + {1, arcs_67_6}, +}; +static arc arcs_68_0[1] = { + {21, 1}, +}; +static arc arcs_68_1[2] = { + {26, 2}, + {0, 1}, +}; +static arc arcs_68_2[1] = { + {0, 2}, +}; +static state states_68[3] = { + {1, arcs_68_0}, + {2, arcs_68_1}, + {1, arcs_68_2}, +}; +static arc arcs_69_0[1] = { + {82, 1}, +}; +static arc arcs_69_1[2] = { + {27, 2}, + {0, 1}, +}; +static arc arcs_69_2[2] = { + {82, 1}, + {0, 2}, +}; +static state states_69[3] = { + {1, arcs_69_0}, + {2, arcs_69_1}, + {2, arcs_69_2}, +}; +static arc arcs_70_0[1] = { + {26, 1}, +}; +static arc arcs_70_1[2] = { + {27, 2}, + {0, 1}, +}; +static arc arcs_70_2[2] = { + {26, 1}, + {0, 2}, +}; +static state states_70[3] = { + {1, arcs_70_0}, + {2, arcs_70_1}, + {2, arcs_70_2}, +}; +static arc arcs_71_0[1] = { + {26, 1}, +}; +static arc arcs_71_1[1] = { + {21, 2}, +}; +static arc arcs_71_2[1] = { + {26, 3}, +}; +static arc arcs_71_3[2] = { + {27, 4}, + {0, 3}, +}; +static arc arcs_71_4[2] = { + {26, 1}, + {0, 4}, +}; +static state states_71[5] = { + {1, arcs_71_0}, + {1, arcs_71_1}, + {1, arcs_71_2}, + {2, arcs_71_3}, + {2, arcs_71_4}, +}; +static arc arcs_72_0[1] = { + {160, 1}, +}; +static arc arcs_72_1[1] = { + {19, 2}, +}; +static arc arcs_72_2[2] = { + {13, 3}, + {21, 4}, +}; +static arc arcs_72_3[2] = { + {9, 5}, + {15, 6}, +}; +static arc arcs_72_4[1] = { + {22, 7}, +}; +static arc arcs_72_5[1] = { + {15, 6}, +}; +static arc arcs_72_6[1] = { + {21, 4}, +}; +static arc arcs_72_7[1] = { + {0, 7}, +}; +static state states_72[8] = { + {1, arcs_72_0}, + {1, arcs_72_1}, + {2, arcs_72_2}, + {2, arcs_72_3}, + {1, arcs_72_4}, + {1, arcs_72_5}, + {1, arcs_72_6}, + {1, arcs_72_7}, +}; +static arc arcs_73_0[3] = { + {161, 1}, + {28, 2}, + {29, 3}, +}; +static arc arcs_73_1[2] = { + {27, 4}, + {0, 1}, +}; +static arc arcs_73_2[1] = { + {26, 5}, +}; +static arc arcs_73_3[1] = { + {26, 6}, +}; +static arc arcs_73_4[4] = { + {161, 1}, + {28, 2}, + {29, 3}, + {0, 4}, +}; +static arc arcs_73_5[2] = { + {27, 7}, + {0, 5}, +}; +static arc arcs_73_6[1] = { + {0, 6}, +}; +static arc arcs_73_7[1] = { + {29, 3}, +}; +static state states_73[8] = { + {3, arcs_73_0}, + {2, arcs_73_1}, + {1, arcs_73_2}, + {1, arcs_73_3}, + {4, arcs_73_4}, + {2, arcs_73_5}, + {1, arcs_73_6}, + {1, arcs_73_7}, +}; +static arc arcs_74_0[1] = { + {26, 1}, +}; +static arc arcs_74_1[3] = { + {156, 2}, + {25, 3}, + {0, 1}, +}; +static arc arcs_74_2[1] = { + {0, 2}, +}; +static arc arcs_74_3[1] = { + {26, 2}, +}; +static state states_74[4] = { + {1, arcs_74_0}, + {3, arcs_74_1}, + {1, arcs_74_2}, + {1, arcs_74_3}, +}; +static arc arcs_75_0[2] = { + {155, 1}, + {163, 1}, +}; +static arc arcs_75_1[1] = { + {0, 1}, +}; +static state states_75[2] = { + {2, arcs_75_0}, + {1, arcs_75_1}, +}; +static arc arcs_76_0[1] = { + {95, 1}, +}; +static arc arcs_76_1[1] = { + {59, 2}, +}; +static arc arcs_76_2[1] = { + {83, 3}, +}; +static arc arcs_76_3[1] = { + {104, 4}, +}; +static arc arcs_76_4[2] = { + {162, 5}, + {0, 4}, +}; +static arc arcs_76_5[1] = { + {0, 5}, +}; +static state states_76[6] = { + {1, arcs_76_0}, + {1, arcs_76_1}, + {1, arcs_76_2}, + {1, arcs_76_3}, + {2, arcs_76_4}, + {1, arcs_76_5}, +}; +static arc arcs_77_0[1] = { + {91, 1}, +}; +static arc arcs_77_1[1] = { + {105, 2}, +}; +static arc arcs_77_2[2] = { + {162, 3}, + {0, 2}, +}; +static arc arcs_77_3[1] = { + {0, 3}, +}; +static state states_77[4] = { + {1, arcs_77_0}, + {1, arcs_77_1}, + {2, arcs_77_2}, + {1, arcs_77_3}, +}; +static arc arcs_78_0[2] = { + {156, 1}, + {165, 1}, +}; +static arc arcs_78_1[1] = { + {0, 1}, +}; +static state states_78[2] = { + {2, arcs_78_0}, + {1, arcs_78_1}, +}; +static arc arcs_79_0[1] = { + {95, 1}, +}; +static arc arcs_79_1[1] = { + {59, 2}, +}; +static arc arcs_79_2[1] = { + {83, 3}, +}; +static arc arcs_79_3[1] = { + {106, 4}, +}; +static arc arcs_79_4[2] = { + {164, 5}, + {0, 4}, +}; +static arc arcs_79_5[1] = { + {0, 5}, +}; +static state states_79[6] = { + {1, arcs_79_0}, + {1, arcs_79_1}, + {1, arcs_79_2}, + {1, arcs_79_3}, + {2, arcs_79_4}, + {1, arcs_79_5}, +}; +static arc arcs_80_0[1] = { + {91, 1}, +}; +static arc arcs_80_1[1] = { + {105, 2}, +}; +static arc arcs_80_2[2] = { + {164, 3}, + {0, 2}, +}; +static arc arcs_80_3[1] = { + {0, 3}, +}; +static state states_80[4] = { + {1, arcs_80_0}, + {1, arcs_80_1}, + {2, arcs_80_2}, + {1, arcs_80_3}, +}; +static arc arcs_81_0[1] = { + {26, 1}, +}; +static arc arcs_81_1[2] = { + {27, 0}, + {0, 1}, +}; +static state states_81[2] = { + {1, arcs_81_0}, + {2, arcs_81_1}, +}; +static arc arcs_82_0[1] = { + {19, 1}, +}; +static arc arcs_82_1[1] = { + {0, 1}, +}; +static state states_82[2] = { + {1, arcs_82_0}, + {1, arcs_82_1}, +}; +static arc arcs_83_0[1] = { + {167, 1}, +}; +static arc arcs_83_1[2] = { + {9, 2}, + {0, 1}, +}; +static arc arcs_83_2[1] = { + {0, 2}, +}; +static state states_83[3] = { + {1, arcs_83_0}, + {2, arcs_83_1}, + {1, arcs_83_2}, +}; +static dfa dfas[84] = { + {256, "single_input", 0, 3, states_0, + "\004\050\014\000\000\000\000\025\074\005\023\310\011\020\004\000\300\020\222\006\201"}, + {257, "file_input", 0, 2, states_1, + "\204\050\014\000\000\000\000\025\074\005\023\310\011\020\004\000\300\020\222\006\201"}, + {258, "eval_input", 0, 3, states_2, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {259, "decorator", 0, 7, states_3, + "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {260, "decorators", 0, 2, states_4, + "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {261, "funcdef", 0, 7, states_5, + "\000\010\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {262, "parameters", 0, 4, states_6, + "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {263, "varargslist", 0, 10, states_7, + "\000\040\010\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {264, "fpdef", 0, 4, states_8, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {265, "fplist", 0, 3, states_9, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {266, "stmt", 0, 2, states_10, + "\000\050\014\000\000\000\000\025\074\005\023\310\011\020\004\000\300\020\222\006\201"}, + {267, "simple_stmt", 0, 4, states_11, + "\000\040\010\000\000\000\000\025\074\005\023\000\000\020\004\000\300\020\222\006\200"}, + {268, "small_stmt", 0, 2, states_12, + "\000\040\010\000\000\000\000\025\074\005\023\000\000\020\004\000\300\020\222\006\200"}, + {269, "expr_stmt", 0, 6, states_13, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {270, "augassign", 0, 2, states_14, + "\000\000\000\000\000\360\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {271, "print_stmt", 0, 9, states_15, + "\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {272, "del_stmt", 0, 3, states_16, + "\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {273, "pass_stmt", 0, 2, states_17, + "\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {274, "flow_stmt", 0, 2, states_18, + "\000\000\000\000\000\000\000\000\074\000\000\000\000\000\000\000\000\000\000\000\200"}, + {275, "break_stmt", 0, 2, states_19, + "\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000"}, + {276, "continue_stmt", 0, 2, states_20, + "\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000"}, + {277, "return_stmt", 0, 3, states_21, + "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000"}, + {278, "yield_stmt", 0, 2, states_22, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200"}, + {279, "raise_stmt", 0, 7, states_23, + "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000"}, + {280, "import_stmt", 0, 2, states_24, + "\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000"}, + {281, "import_name", 0, 3, states_25, + "\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000"}, + {282, "import_from", 0, 8, states_26, + "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"}, + {283, "import_as_name", 0, 4, states_27, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {284, "dotted_as_name", 0, 4, states_28, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {285, "import_as_names", 0, 3, states_29, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {286, "dotted_as_names", 0, 2, states_30, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {287, "dotted_name", 0, 2, states_31, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {288, "global_stmt", 0, 3, states_32, + "\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000"}, + {289, "exec_stmt", 0, 7, states_33, + "\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000"}, + {290, "assert_stmt", 0, 5, states_34, + "\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000"}, + {291, "compound_stmt", 0, 2, states_35, + "\000\010\004\000\000\000\000\000\000\000\000\310\011\000\000\000\000\000\000\000\001"}, + {292, "if_stmt", 0, 8, states_36, + "\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000"}, + {293, "while_stmt", 0, 8, states_37, + "\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000"}, + {294, "for_stmt", 0, 10, states_38, + "\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000"}, + {295, "try_stmt", 0, 13, states_39, + "\000\000\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000"}, + {296, "with_stmt", 0, 6, states_40, + "\000\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000"}, + {297, "with_var", 0, 3, states_41, + "\000\000\010\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000\000\000"}, + {298, "except_clause", 0, 5, states_42, + "\000\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"}, + {299, "suite", 0, 5, states_43, + "\004\040\010\000\000\000\000\025\074\005\023\000\000\020\004\000\300\020\222\006\200"}, + {300, "testlist_safe", 0, 5, states_44, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {301, "old_test", 0, 2, states_45, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {302, "old_lambdef", 0, 5, states_46, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000"}, + {303, "test", 0, 6, states_47, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {304, "or_test", 0, 2, states_48, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\004\000\300\020\222\006\000"}, + {305, "and_test", 0, 2, states_49, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\004\000\300\020\222\006\000"}, + {306, "not_test", 0, 3, states_50, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\004\000\300\020\222\006\000"}, + {307, "comparison", 0, 2, states_51, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {308, "comp_op", 0, 4, states_52, + "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\344\037\000\000\000\000\000"}, + {309, "expr", 0, 2, states_53, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {310, "xor_expr", 0, 2, states_54, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {311, "and_expr", 0, 2, states_55, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {312, "shift_expr", 0, 2, states_56, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {313, "arith_expr", 0, 2, states_57, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {314, "term", 0, 2, states_58, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {315, "factor", 0, 3, states_59, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {316, "power", 0, 4, states_60, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\222\006\000"}, + {317, "atom", 0, 11, states_61, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\222\006\000"}, + {318, "listmaker", 0, 5, states_62, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {319, "testlist_gexp", 0, 5, states_63, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {320, "lambdef", 0, 5, states_64, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000"}, + {321, "trailer", 0, 7, states_65, + "\000\040\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\002\000\000"}, + {322, "subscriptlist", 0, 3, states_66, + "\000\040\050\000\000\000\000\000\000\010\000\000\000\020\004\000\300\020\222\006\000"}, + {323, "subscript", 0, 7, states_67, + "\000\040\050\000\000\000\000\000\000\010\000\000\000\020\004\000\300\020\222\006\000"}, + {324, "sliceop", 0, 3, states_68, + "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {325, "exprlist", 0, 3, states_69, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\300\020\222\006\000"}, + {326, "testlist", 0, 3, states_70, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {327, "dictmaker", 0, 5, states_71, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {328, "classdef", 0, 8, states_72, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"}, + {329, "arglist", 0, 8, states_73, + "\000\040\010\060\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {330, "argument", 0, 4, states_74, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {331, "list_iter", 0, 2, states_75, + "\000\000\000\000\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\000\000"}, + {332, "list_for", 0, 6, states_76, + "\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000"}, + {333, "list_if", 0, 4, states_77, + "\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000"}, + {334, "gen_iter", 0, 2, states_78, + "\000\000\000\000\000\000\000\000\000\000\000\210\000\000\000\000\000\000\000\000\000"}, + {335, "gen_for", 0, 6, states_79, + "\000\000\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000"}, + {336, "gen_if", 0, 4, states_80, + "\000\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000"}, + {337, "testlist1", 0, 2, states_81, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\020\004\000\300\020\222\006\000"}, + {338, "encoding_decl", 0, 2, states_82, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {339, "yield_expr", 0, 3, states_83, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\200"}, +}; +static label labels[168] = { + {0, "EMPTY"}, + {256, 0}, + {4, 0}, + {267, 0}, + {291, 0}, + {257, 0}, + {266, 0}, + {0, 0}, + {258, 0}, + {326, 0}, + {259, 0}, + {50, 0}, + {287, 0}, + {7, 0}, + {329, 0}, + {8, 0}, + {260, 0}, + {261, 0}, + {1, "def"}, + {1, 0}, + {262, 0}, + {11, 0}, + {299, 0}, + {263, 0}, + {264, 0}, + {22, 0}, + {303, 0}, + {12, 0}, + {16, 0}, + {36, 0}, + {265, 0}, + {268, 0}, + {13, 0}, + {269, 0}, + {271, 0}, + {272, 0}, + {273, 0}, + {274, 0}, + {280, 0}, + {288, 0}, + {289, 0}, + {290, 0}, + {270, 0}, + {339, 0}, + {37, 0}, + {38, 0}, + {39, 0}, + {40, 0}, + {41, 0}, + {42, 0}, + {43, 0}, + {44, 0}, + {45, 0}, + {46, 0}, + {47, 0}, + {49, 0}, + {1, "print"}, + {35, 0}, + {1, "del"}, + {325, 0}, + {1, "pass"}, + {275, 0}, + {276, 0}, + {277, 0}, + {279, 0}, + {278, 0}, + {1, "break"}, + {1, "continue"}, + {1, "return"}, + {1, "raise"}, + {281, 0}, + {282, 0}, + {1, "import"}, + {286, 0}, + {1, "from"}, + {23, 0}, + {285, 0}, + {283, 0}, + {1, "as"}, + {284, 0}, + {1, "global"}, + {1, "exec"}, + {309, 0}, + {1, "in"}, + {1, "assert"}, + {292, 0}, + {293, 0}, + {294, 0}, + {295, 0}, + {296, 0}, + {328, 0}, + {1, "if"}, + {1, "elif"}, + {1, "else"}, + {1, "while"}, + {1, "for"}, + {1, "try"}, + {298, 0}, + {1, "finally"}, + {1, "with"}, + {297, 0}, + {1, "except"}, + {5, 0}, + {6, 0}, + {300, 0}, + {301, 0}, + {304, 0}, + {302, 0}, + {1, "lambda"}, + {320, 0}, + {305, 0}, + {1, "or"}, + {306, 0}, + {1, "and"}, + {1, "not"}, + {307, 0}, + {308, 0}, + {20, 0}, + {21, 0}, + {28, 0}, + {31, 0}, + {30, 0}, + {29, 0}, + {29, 0}, + {1, "is"}, + {310, 0}, + {18, 0}, + {311, 0}, + {33, 0}, + {312, 0}, + {19, 0}, + {313, 0}, + {34, 0}, + {314, 0}, + {14, 0}, + {15, 0}, + {315, 0}, + {17, 0}, + {24, 0}, + {48, 0}, + {32, 0}, + {316, 0}, + {317, 0}, + {321, 0}, + {319, 0}, + {9, 0}, + {318, 0}, + {10, 0}, + {26, 0}, + {327, 0}, + {27, 0}, + {25, 0}, + {337, 0}, + {2, 0}, + {3, 0}, + {332, 0}, + {335, 0}, + {322, 0}, + {323, 0}, + {324, 0}, + {1, "class"}, + {330, 0}, + {331, 0}, + {333, 0}, + {334, 0}, + {336, 0}, + {338, 0}, + {1, "yield"}, +}; +grammar _PyParser_Grammar = { + 84, + dfas, + {168, labels}, + 256 +}; diff --git a/sys/src/cmd/python/Python/hypot.c b/sys/src/cmd/python/Python/hypot.c new file mode 100644 index 000000000..755d0c31c --- /dev/null +++ b/sys/src/cmd/python/Python/hypot.c @@ -0,0 +1,23 @@ +/* hypot() replacement */ + +#include "pyconfig.h" +#include "pyport.h" + +double hypot(double x, double y) +{ + double yx; + + x = fabs(x); + y = fabs(y); + if (x < y) { + double temp = x; + x = y; + y = temp; + } + if (x == 0.) + return 0.; + else { + yx = y/x; + return x*sqrt(1.+yx*yx); + } +} diff --git a/sys/src/cmd/python/Python/import.c b/sys/src/cmd/python/Python/import.c new file mode 100644 index 000000000..291e63dc7 --- /dev/null +++ b/sys/src/cmd/python/Python/import.c @@ -0,0 +1,3160 @@ + +/* Module definition and import implementation */ + +#include "Python.h" + +#include "Python-ast.h" +#include "pyarena.h" +#include "pythonrun.h" +#include "errcode.h" +#include "marshal.h" +#include "code.h" +#include "compile.h" +#include "eval.h" +#include "osdefs.h" +#include "importdl.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef __cplusplus +extern "C" { +#endif + +extern time_t PyOS_GetLastModificationTime(char *, FILE *); + /* In getmtime.c */ + +/* Magic word to reject .pyc files generated by other Python versions. + It should change for each incompatible change to the bytecode. + + The value of CR and LF is incorporated so if you ever read or write + a .pyc file in text mode the magic number will be wrong; also, the + Apple MPW compiler swaps their values, botching string constants. + + The magic numbers must be spaced apart atleast 2 values, as the + -U interpeter flag will cause MAGIC+1 being used. They have been + odd numbers for some time now. + + There were a variety of old schemes for setting the magic number. + The current working scheme is to increment the previous value by + 10. + + Known values: + Python 1.5: 20121 + Python 1.5.1: 20121 + Python 1.5.2: 20121 + Python 1.6: 50428 + Python 2.0: 50823 + Python 2.0.1: 50823 + Python 2.1: 60202 + Python 2.1.1: 60202 + Python 2.1.2: 60202 + Python 2.2: 60717 + Python 2.3a0: 62011 + Python 2.3a0: 62021 + Python 2.3a0: 62011 (!) + Python 2.4a0: 62041 + Python 2.4a3: 62051 + Python 2.4b1: 62061 + Python 2.5a0: 62071 + Python 2.5a0: 62081 (ast-branch) + Python 2.5a0: 62091 (with) + Python 2.5a0: 62092 (changed WITH_CLEANUP opcode) + Python 2.5b3: 62101 (fix wrong code: for x, in ...) + Python 2.5b3: 62111 (fix wrong code: x += yield) + Python 2.5c1: 62121 (fix wrong lnotab with for loops and + storing constants that should have been removed) + Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp) +. +*/ +#define MAGIC (62131 | ((long)'\r'<<16) | ((long)'\n'<<24)) + +/* Magic word as global; note that _PyImport_Init() can change the + value of this global to accommodate for alterations of how the + compiler works which are enabled by command line switches. */ +static long pyc_magic = MAGIC; + +/* See _PyImport_FixupExtension() below */ +static PyObject *extensions = NULL; + +/* This table is defined in config.c: */ +extern struct _inittab _PyImport_Inittab[]; + +struct _inittab *PyImport_Inittab = _PyImport_Inittab; + +/* these tables define the module suffixes that Python recognizes */ +struct filedescr * _PyImport_Filetab = NULL; + +#ifdef RISCOS +static const struct filedescr _PyImport_StandardFiletab[] = { + {"/py", "U", PY_SOURCE}, + {"/pyc", "rb", PY_COMPILED}, + {0, 0} +}; +#else +static const struct filedescr _PyImport_StandardFiletab[] = { + {".py", "U", PY_SOURCE}, +#ifdef MS_WINDOWS + {".pyw", "U", PY_SOURCE}, +#endif + {".pyc", "rb", PY_COMPILED}, + {0, 0} +}; +#endif + +static PyTypeObject NullImporterType; /* Forward reference */ + +/* Initialize things */ + +void +_PyImport_Init(void) +{ + const struct filedescr *scan; + struct filedescr *filetab; + int countD = 0; + int countS = 0; + + /* prepare _PyImport_Filetab: copy entries from + _PyImport_DynLoadFiletab and _PyImport_StandardFiletab. + */ + for (scan = _PyImport_DynLoadFiletab; scan->suffix != NULL; ++scan) + ++countD; + for (scan = _PyImport_StandardFiletab; scan->suffix != NULL; ++scan) + ++countS; + filetab = PyMem_NEW(struct filedescr, countD + countS + 1); + if (filetab == NULL) + Py_FatalError("Can't initialize import file table."); + memcpy(filetab, _PyImport_DynLoadFiletab, + countD * sizeof(struct filedescr)); + memcpy(filetab + countD, _PyImport_StandardFiletab, + countS * sizeof(struct filedescr)); + filetab[countD + countS].suffix = NULL; + + _PyImport_Filetab = filetab; + + if (Py_OptimizeFlag) { + /* Replace ".pyc" with ".pyo" in _PyImport_Filetab */ + for (; filetab->suffix != NULL; filetab++) { +#ifndef RISCOS + if (strcmp(filetab->suffix, ".pyc") == 0) + filetab->suffix = ".pyo"; +#else + if (strcmp(filetab->suffix, "/pyc") == 0) + filetab->suffix = "/pyo"; +#endif + } + } + + if (Py_UnicodeFlag) { + /* Fix the pyc_magic so that byte compiled code created + using the all-Unicode method doesn't interfere with + code created in normal operation mode. */ + pyc_magic = MAGIC + 1; + } +} + +void +_PyImportHooks_Init(void) +{ + PyObject *v, *path_hooks = NULL, *zimpimport; + int err = 0; + + /* adding sys.path_hooks and sys.path_importer_cache, setting up + zipimport */ + if (PyType_Ready(&NullImporterType) < 0) + goto error; + + if (Py_VerboseFlag) + PySys_WriteStderr("# installing zipimport hook\n"); + + v = PyList_New(0); + if (v == NULL) + goto error; + err = PySys_SetObject("meta_path", v); + Py_DECREF(v); + if (err) + goto error; + v = PyDict_New(); + if (v == NULL) + goto error; + err = PySys_SetObject("path_importer_cache", v); + Py_DECREF(v); + if (err) + goto error; + path_hooks = PyList_New(0); + if (path_hooks == NULL) + goto error; + err = PySys_SetObject("path_hooks", path_hooks); + if (err) { + error: + PyErr_Print(); + Py_FatalError("initializing sys.meta_path, sys.path_hooks, " + "path_importer_cache, or NullImporter failed" + ); + } + + zimpimport = PyImport_ImportModule("zipimport"); + if (zimpimport == NULL) { + PyErr_Clear(); /* No zip import module -- okay */ + if (Py_VerboseFlag) + PySys_WriteStderr("# can't import zipimport\n"); + } + else { + PyObject *zipimporter = PyObject_GetAttrString(zimpimport, + "zipimporter"); + Py_DECREF(zimpimport); + if (zipimporter == NULL) { + PyErr_Clear(); /* No zipimporter object -- okay */ + if (Py_VerboseFlag) + PySys_WriteStderr( + "# can't import zipimport.zipimporter\n"); + } + else { + /* sys.path_hooks.append(zipimporter) */ + err = PyList_Append(path_hooks, zipimporter); + Py_DECREF(zipimporter); + if (err) + goto error; + if (Py_VerboseFlag) + PySys_WriteStderr( + "# installed zipimport hook\n"); + } + } + Py_DECREF(path_hooks); +} + +void +_PyImport_Fini(void) +{ + Py_XDECREF(extensions); + extensions = NULL; + PyMem_DEL(_PyImport_Filetab); + _PyImport_Filetab = NULL; +} + + +/* Locking primitives to prevent parallel imports of the same module + in different threads to return with a partially loaded module. + These calls are serialized by the global interpreter lock. */ + +#ifdef WITH_THREAD + +#include "pythread.h" + +static PyThread_type_lock import_lock = 0; +static long import_lock_thread = -1; +static int import_lock_level = 0; + +static void +lock_import(void) +{ + long me = PyThread_get_thread_ident(); + if (me == -1) + return; /* Too bad */ + if (import_lock == NULL) { + import_lock = PyThread_allocate_lock(); + if (import_lock == NULL) + return; /* Nothing much we can do. */ + } + if (import_lock_thread == me) { + import_lock_level++; + return; + } + if (import_lock_thread != -1 || !PyThread_acquire_lock(import_lock, 0)) + { + PyThreadState *tstate = PyEval_SaveThread(); + PyThread_acquire_lock(import_lock, 1); + PyEval_RestoreThread(tstate); + } + import_lock_thread = me; + import_lock_level = 1; +} + +static int +unlock_import(void) +{ + long me = PyThread_get_thread_ident(); + if (me == -1 || import_lock == NULL) + return 0; /* Too bad */ + if (import_lock_thread != me) + return -1; + import_lock_level--; + if (import_lock_level == 0) { + import_lock_thread = -1; + PyThread_release_lock(import_lock); + } + return 1; +} + +/* This function is called from PyOS_AfterFork to ensure that newly + created child processes do not share locks with the parent. */ + +void +_PyImport_ReInitLock(void) +{ +#ifdef _AIX + if (import_lock != NULL) + import_lock = PyThread_allocate_lock(); +#endif +} + +#else + +#define lock_import() +#define unlock_import() 0 + +#endif + +static PyObject * +imp_lock_held(PyObject *self, PyObject *noargs) +{ +#ifdef WITH_THREAD + return PyBool_FromLong(import_lock_thread != -1); +#else + return PyBool_FromLong(0); +#endif +} + +static PyObject * +imp_acquire_lock(PyObject *self, PyObject *noargs) +{ +#ifdef WITH_THREAD + lock_import(); +#endif + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +imp_release_lock(PyObject *self, PyObject *noargs) +{ +#ifdef WITH_THREAD + if (unlock_import() < 0) { + PyErr_SetString(PyExc_RuntimeError, + "not holding the import lock"); + return NULL; + } +#endif + Py_INCREF(Py_None); + return Py_None; +} + +static void +imp_modules_reloading_clear (void) +{ + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules_reloading == NULL) + return; + PyDict_Clear(interp->modules_reloading); + return; +} + +/* Helper for sys */ + +PyObject * +PyImport_GetModuleDict(void) +{ + PyInterpreterState *interp = PyThreadState_GET()->interp; + if (interp->modules == NULL) + Py_FatalError("PyImport_GetModuleDict: no module dictionary!"); + return interp->modules; +} + + +/* List of names to clear in sys */ +static char* sys_deletes[] = { + "path", "argv", "ps1", "ps2", "exitfunc", + "exc_type", "exc_value", "exc_traceback", + "last_type", "last_value", "last_traceback", + "path_hooks", "path_importer_cache", "meta_path", + NULL +}; + +static char* sys_files[] = { + "stdin", "__stdin__", + "stdout", "__stdout__", + "stderr", "__stderr__", + NULL +}; + + +/* Un-initialize things, as good as we can */ + +void +PyImport_Cleanup(void) +{ + Py_ssize_t pos, ndone; + char *name; + PyObject *key, *value, *dict; + PyInterpreterState *interp = PyThreadState_GET()->interp; + PyObject *modules = interp->modules; + + if (modules == NULL) + return; /* Already done */ + + /* Delete some special variables first. These are common + places where user values hide and people complain when their + destructors fail. Since the modules containing them are + deleted *last* of all, they would come too late in the normal + destruction order. Sigh. */ + + value = PyDict_GetItemString(modules, "__builtin__"); + if (value != NULL && PyModule_Check(value)) { + dict = PyModule_GetDict(value); + if (Py_VerboseFlag) + PySys_WriteStderr("# clear __builtin__._\n"); + PyDict_SetItemString(dict, "_", Py_None); + } + value = PyDict_GetItemString(modules, "sys"); + if (value != NULL && PyModule_Check(value)) { + char **p; + PyObject *v; + dict = PyModule_GetDict(value); + for (p = sys_deletes; *p != NULL; p++) { + if (Py_VerboseFlag) + PySys_WriteStderr("# clear sys.%s\n", *p); + PyDict_SetItemString(dict, *p, Py_None); + } + for (p = sys_files; *p != NULL; p+=2) { + if (Py_VerboseFlag) + PySys_WriteStderr("# restore sys.%s\n", *p); + v = PyDict_GetItemString(dict, *(p+1)); + if (v == NULL) + v = Py_None; + PyDict_SetItemString(dict, *p, v); + } + } + + /* First, delete __main__ */ + value = PyDict_GetItemString(modules, "__main__"); + if (value != NULL && PyModule_Check(value)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup __main__\n"); + _PyModule_Clear(value); + PyDict_SetItemString(modules, "__main__", Py_None); + } + + /* The special treatment of __builtin__ here is because even + when it's not referenced as a module, its dictionary is + referenced by almost every module's __builtins__. Since + deleting a module clears its dictionary (even if there are + references left to it), we need to delete the __builtin__ + module last. Likewise, we don't delete sys until the very + end because it is implicitly referenced (e.g. by print). + + Also note that we 'delete' modules by replacing their entry + in the modules dict with None, rather than really deleting + them; this avoids a rehash of the modules dictionary and + also marks them as "non existent" so they won't be + re-imported. */ + + /* Next, repeatedly delete modules with a reference count of + one (skipping __builtin__ and sys) and delete them */ + do { + ndone = 0; + pos = 0; + while (PyDict_Next(modules, &pos, &key, &value)) { + if (value->ob_refcnt != 1) + continue; + if (PyString_Check(key) && PyModule_Check(value)) { + name = PyString_AS_STRING(key); + if (strcmp(name, "__builtin__") == 0) + continue; + if (strcmp(name, "sys") == 0) + continue; + if (Py_VerboseFlag) + PySys_WriteStderr( + "# cleanup[1] %s\n", name); + _PyModule_Clear(value); + PyDict_SetItem(modules, key, Py_None); + ndone++; + } + } + } while (ndone > 0); + + /* Next, delete all modules (still skipping __builtin__ and sys) */ + pos = 0; + while (PyDict_Next(modules, &pos, &key, &value)) { + if (PyString_Check(key) && PyModule_Check(value)) { + name = PyString_AS_STRING(key); + if (strcmp(name, "__builtin__") == 0) + continue; + if (strcmp(name, "sys") == 0) + continue; + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup[2] %s\n", name); + _PyModule_Clear(value); + PyDict_SetItem(modules, key, Py_None); + } + } + + /* Next, delete sys and __builtin__ (in that order) */ + value = PyDict_GetItemString(modules, "sys"); + if (value != NULL && PyModule_Check(value)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup sys\n"); + _PyModule_Clear(value); + PyDict_SetItemString(modules, "sys", Py_None); + } + value = PyDict_GetItemString(modules, "__builtin__"); + if (value != NULL && PyModule_Check(value)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# cleanup __builtin__\n"); + _PyModule_Clear(value); + PyDict_SetItemString(modules, "__builtin__", Py_None); + } + + /* Finally, clear and delete the modules directory */ + PyDict_Clear(modules); + interp->modules = NULL; + Py_DECREF(modules); + Py_CLEAR(interp->modules_reloading); +} + + +/* Helper for pythonrun.c -- return magic number */ + +long +PyImport_GetMagicNumber(void) +{ + return pyc_magic; +} + + +/* Magic for extension modules (built-in as well as dynamically + loaded). To prevent initializing an extension module more than + once, we keep a static dictionary 'extensions' keyed by module name + (for built-in modules) or by filename (for dynamically loaded + modules), containing these modules. A copy of the module's + dictionary is stored by calling _PyImport_FixupExtension() + immediately after the module initialization function succeeds. A + copy can be retrieved from there by calling + _PyImport_FindExtension(). */ + +PyObject * +_PyImport_FixupExtension(char *name, char *filename) +{ + PyObject *modules, *mod, *dict, *copy; + if (extensions == NULL) { + extensions = PyDict_New(); + if (extensions == NULL) + return NULL; + } + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, name); + if (mod == NULL || !PyModule_Check(mod)) { + PyErr_Format(PyExc_SystemError, + "_PyImport_FixupExtension: module %.200s not loaded", name); + return NULL; + } + dict = PyModule_GetDict(mod); + if (dict == NULL) + return NULL; + copy = PyDict_Copy(dict); + if (copy == NULL) + return NULL; + PyDict_SetItemString(extensions, filename, copy); + Py_DECREF(copy); + return copy; +} + +PyObject * +_PyImport_FindExtension(char *name, char *filename) +{ + PyObject *dict, *mod, *mdict; + if (extensions == NULL) + return NULL; + dict = PyDict_GetItemString(extensions, filename); + if (dict == NULL) + return NULL; + mod = PyImport_AddModule(name); + if (mod == NULL) + return NULL; + mdict = PyModule_GetDict(mod); + if (mdict == NULL) + return NULL; + if (PyDict_Update(mdict, dict)) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # previously loaded (%s)\n", + name, filename); + return mod; +} + + +/* Get the module object corresponding to a module name. + First check the modules dictionary if there's one there, + if not, create a new one and insert it in the modules dictionary. + Because the former action is most common, THIS DOES NOT RETURN A + 'NEW' REFERENCE! */ + +PyObject * +PyImport_AddModule(const char *name) +{ + PyObject *modules = PyImport_GetModuleDict(); + PyObject *m; + + if ((m = PyDict_GetItemString(modules, name)) != NULL && + PyModule_Check(m)) + return m; + m = PyModule_New(name); + if (m == NULL) + return NULL; + if (PyDict_SetItemString(modules, name, m) != 0) { + Py_DECREF(m); + return NULL; + } + Py_DECREF(m); /* Yes, it still exists, in modules! */ + + return m; +} + +/* Remove name from sys.modules, if it's there. */ +static void +_RemoveModule(const char *name) +{ + PyObject *modules = PyImport_GetModuleDict(); + if (PyDict_GetItemString(modules, name) == NULL) + return; + if (PyDict_DelItemString(modules, name) < 0) + Py_FatalError("import: deleting existing key in" + "sys.modules failed"); +} + +/* Execute a code object in a module and return the module object + * WITH INCREMENTED REFERENCE COUNT. If an error occurs, name is + * removed from sys.modules, to avoid leaving damaged module objects + * in sys.modules. The caller may wish to restore the original + * module object (if any) in this case; PyImport_ReloadModule is an + * example. + */ +PyObject * +PyImport_ExecCodeModule(char *name, PyObject *co) +{ + return PyImport_ExecCodeModuleEx(name, co, (char *)NULL); +} + +PyObject * +PyImport_ExecCodeModuleEx(char *name, PyObject *co, char *pathname) +{ + PyObject *modules = PyImport_GetModuleDict(); + PyObject *m, *d, *v; + + m = PyImport_AddModule(name); + if (m == NULL) + return NULL; + /* If the module is being reloaded, we get the old module back + and re-use its dict to exec the new code. */ + d = PyModule_GetDict(m); + if (PyDict_GetItemString(d, "__builtins__") == NULL) { + if (PyDict_SetItemString(d, "__builtins__", + PyEval_GetBuiltins()) != 0) + goto error; + } + /* Remember the filename as the __file__ attribute */ + v = NULL; + if (pathname != NULL) { + v = PyString_FromString(pathname); + if (v == NULL) + PyErr_Clear(); + } + if (v == NULL) { + v = ((PyCodeObject *)co)->co_filename; + Py_INCREF(v); + } + if (PyDict_SetItemString(d, "__file__", v) != 0) + PyErr_Clear(); /* Not important enough to report */ + Py_DECREF(v); + + v = PyEval_EvalCode((PyCodeObject *)co, d, d); + if (v == NULL) + goto error; + Py_DECREF(v); + + if ((m = PyDict_GetItemString(modules, name)) == NULL) { + PyErr_Format(PyExc_ImportError, + "Loaded module %.200s not found in sys.modules", + name); + return NULL; + } + + Py_INCREF(m); + + return m; + + error: + _RemoveModule(name); + return NULL; +} + + +/* Given a pathname for a Python source file, fill a buffer with the + pathname for the corresponding compiled file. Return the pathname + for the compiled file, or NULL if there's no space in the buffer. + Doesn't set an exception. */ + +static char * +make_compiled_pathname(char *pathname, char *buf, size_t buflen) +{ + size_t len = strlen(pathname); + if (len+2 > buflen) + return NULL; + +#ifdef MS_WINDOWS + /* Treat .pyw as if it were .py. The case of ".pyw" must match + that used in _PyImport_StandardFiletab. */ + if (len >= 4 && strcmp(&pathname[len-4], ".pyw") == 0) + --len; /* pretend 'w' isn't there */ +#endif + memcpy(buf, pathname, len); + buf[len] = Py_OptimizeFlag ? 'o' : 'c'; + buf[len+1] = '\0'; + + return buf; +} + + +/* Given a pathname for a Python source file, its time of last + modification, and a pathname for a compiled file, check whether the + compiled file represents the same version of the source. If so, + return a FILE pointer for the compiled file, positioned just after + the header; if not, return NULL. + Doesn't set an exception. */ + +static FILE * +check_compiled_module(char *pathname, time_t mtime, char *cpathname) +{ + FILE *fp; + long magic; + long pyc_mtime; + + fp = fopen(cpathname, "rb"); + if (fp == NULL) + return NULL; + magic = PyMarshal_ReadLongFromFile(fp); + if (magic != pyc_magic) { + if (Py_VerboseFlag) + PySys_WriteStderr("# %s has bad magic\n", cpathname); + fclose(fp); + return NULL; + } + pyc_mtime = PyMarshal_ReadLongFromFile(fp); + if (pyc_mtime != mtime) { + if (Py_VerboseFlag) + PySys_WriteStderr("# %s has bad mtime\n", cpathname); + fclose(fp); + return NULL; + } + if (Py_VerboseFlag) + PySys_WriteStderr("# %s matches %s\n", cpathname, pathname); + return fp; +} + + +/* Read a code object from a file and check it for validity */ + +static PyCodeObject * +read_compiled_module(char *cpathname, FILE *fp) +{ + PyObject *co; + + co = PyMarshal_ReadLastObjectFromFile(fp); + if (co == NULL) + return NULL; + if (!PyCode_Check(co)) { + PyErr_Format(PyExc_ImportError, + "Non-code object in %.200s", cpathname); + Py_DECREF(co); + return NULL; + } + return (PyCodeObject *)co; +} + + +/* Load a module from a compiled file, execute it, and return its + module object WITH INCREMENTED REFERENCE COUNT */ + +static PyObject * +load_compiled_module(char *name, char *cpathname, FILE *fp) +{ + long magic; + PyCodeObject *co; + PyObject *m; + + magic = PyMarshal_ReadLongFromFile(fp); + if (magic != pyc_magic) { + PyErr_Format(PyExc_ImportError, + "Bad magic number in %.200s", cpathname); + return NULL; + } + (void) PyMarshal_ReadLongFromFile(fp); + co = read_compiled_module(cpathname, fp); + if (co == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # precompiled from %s\n", + name, cpathname); + m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, cpathname); + Py_DECREF(co); + + return m; +} + +/* Parse a source file and return the corresponding code object */ + +static PyCodeObject * +parse_source_module(const char *pathname, FILE *fp) +{ + PyCodeObject *co = NULL; + mod_ty mod; + PyArena *arena = PyArena_New(); + if (arena == NULL) + return NULL; + + mod = PyParser_ASTFromFile(fp, pathname, Py_file_input, 0, 0, 0, + NULL, arena); + if (mod) { + co = PyAST_Compile(mod, pathname, NULL, arena); + } + PyArena_Free(arena); + return co; +} + + +/* Helper to open a bytecode file for writing in exclusive mode */ + +static FILE * +open_exclusive(char *filename) +{ +#if defined(O_EXCL)&&defined(O_CREAT)&&defined(O_WRONLY)&&defined(O_TRUNC) + /* Use O_EXCL to avoid a race condition when another process tries to + write the same file. When that happens, our open() call fails, + which is just fine (since it's only a cache). + XXX If the file exists and is writable but the directory is not + writable, the file will never be written. Oh well. + */ + int fd; + (void) unlink(filename); + fd = open(filename, O_EXCL|O_CREAT|O_WRONLY|O_TRUNC +#ifdef O_BINARY + |O_BINARY /* necessary for Windows */ +#endif +#ifdef __VMS + , 0666, "ctxt=bin", "shr=nil" +#else + , 0666 +#endif + ); + if (fd < 0) + return NULL; + return fdopen(fd, "wb"); +#else + /* Best we can do -- on Windows this can't happen anyway */ + return fopen(filename, "wb"); +#endif +} + + +/* Write a compiled module to a file, placing the time of last + modification of its source into the header. + Errors are ignored, if a write error occurs an attempt is made to + remove the file. */ + +static void +write_compiled_module(PyCodeObject *co, char *cpathname, time_t mtime) +{ + FILE *fp; + + fp = open_exclusive(cpathname); + if (fp == NULL) { + if (Py_VerboseFlag) + PySys_WriteStderr( + "# can't create %s\n", cpathname); + return; + } + PyMarshal_WriteLongToFile(pyc_magic, fp, Py_MARSHAL_VERSION); + /* First write a 0 for mtime */ + PyMarshal_WriteLongToFile(0L, fp, Py_MARSHAL_VERSION); + PyMarshal_WriteObjectToFile((PyObject *)co, fp, Py_MARSHAL_VERSION); + if (fflush(fp) != 0 || ferror(fp)) { + if (Py_VerboseFlag) + PySys_WriteStderr("# can't write %s\n", cpathname); + /* Don't keep partial file */ + fclose(fp); + (void) unlink(cpathname); + return; + } + /* Now write the true mtime */ + fseek(fp, 4L, 0); + assert(mtime < LONG_MAX); + PyMarshal_WriteLongToFile((long)mtime, fp, Py_MARSHAL_VERSION); + fflush(fp); + fclose(fp); + if (Py_VerboseFlag) + PySys_WriteStderr("# wrote %s\n", cpathname); +} + + +/* Load a source module from a given file and return its module + object WITH INCREMENTED REFERENCE COUNT. If there's a matching + byte-compiled file, use that instead. */ + +static PyObject * +load_source_module(char *name, char *pathname, FILE *fp) +{ + time_t mtime; + FILE *fpc; + char buf[MAXPATHLEN+1]; + char *cpathname; + PyCodeObject *co; + PyObject *m; + + mtime = PyOS_GetLastModificationTime(pathname, fp); + if (mtime == (time_t)(-1)) { + PyErr_Format(PyExc_RuntimeError, + "unable to get modification time from '%s'", + pathname); + return NULL; + } +#if SIZEOF_TIME_T > 4 + /* Python's .pyc timestamp handling presumes that the timestamp fits + in 4 bytes. This will be fine until sometime in the year 2038, + when a 4-byte signed time_t will overflow. + */ + if (mtime >> 32) { + PyErr_SetString(PyExc_OverflowError, + "modification time overflows a 4 byte field"); + return NULL; + } +#endif + cpathname = make_compiled_pathname(pathname, buf, + (size_t)MAXPATHLEN + 1); + if (cpathname != NULL && + (fpc = check_compiled_module(pathname, mtime, cpathname))) { + co = read_compiled_module(cpathname, fpc); + fclose(fpc); + if (co == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # precompiled from %s\n", + name, cpathname); + pathname = cpathname; + } + else { + co = parse_source_module(pathname, fp); + if (co == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # from %s\n", + name, pathname); + if (cpathname) + write_compiled_module(co, cpathname, mtime); + } + m = PyImport_ExecCodeModuleEx(name, (PyObject *)co, pathname); + Py_DECREF(co); + + return m; +} + + +/* Forward */ +static PyObject *load_module(char *, FILE *, char *, int, PyObject *); +static struct filedescr *find_module(char *, char *, PyObject *, + char *, size_t, FILE **, PyObject **); +static struct _frozen *find_frozen(char *name); + +/* Load a package and return its module object WITH INCREMENTED + REFERENCE COUNT */ + +static PyObject * +load_package(char *name, char *pathname) +{ + PyObject *m, *d; + PyObject *file = NULL; + PyObject *path = NULL; + int err; + char buf[MAXPATHLEN+1]; + FILE *fp = NULL; + struct filedescr *fdp; + + m = PyImport_AddModule(name); + if (m == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # directory %s\n", + name, pathname); + d = PyModule_GetDict(m); + file = PyString_FromString(pathname); + if (file == NULL) + goto error; + path = Py_BuildValue("[O]", file); + if (path == NULL) + goto error; + err = PyDict_SetItemString(d, "__file__", file); + if (err == 0) + err = PyDict_SetItemString(d, "__path__", path); + if (err != 0) + goto error; + buf[0] = '\0'; + fdp = find_module(name, "__init__", path, buf, sizeof(buf), &fp, NULL); + if (fdp == NULL) { + if (PyErr_ExceptionMatches(PyExc_ImportError)) { + PyErr_Clear(); + Py_INCREF(m); + } + else + m = NULL; + goto cleanup; + } + m = load_module(name, fp, buf, fdp->type, NULL); + if (fp != NULL) + fclose(fp); + goto cleanup; + + error: + m = NULL; + cleanup: + Py_XDECREF(path); + Py_XDECREF(file); + return m; +} + + +/* Helper to test for built-in module */ + +static int +is_builtin(char *name) +{ + int i; + for (i = 0; PyImport_Inittab[i].name != NULL; i++) { + if (strcmp(name, PyImport_Inittab[i].name) == 0) { + if (PyImport_Inittab[i].initfunc == NULL) + return -1; + else + return 1; + } + } + return 0; +} + + +/* Return an importer object for a sys.path/pkg.__path__ item 'p', + possibly by fetching it from the path_importer_cache dict. If it + wasn't yet cached, traverse path_hooks until it a hook is found + that can handle the path item. Return None if no hook could; + this tells our caller it should fall back to the builtin + import mechanism. Cache the result in path_importer_cache. + Returns a borrowed reference. */ + +static PyObject * +get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks, + PyObject *p) +{ + PyObject *importer; + Py_ssize_t j, nhooks; + + /* These conditions are the caller's responsibility: */ + assert(PyList_Check(path_hooks)); + assert(PyDict_Check(path_importer_cache)); + + nhooks = PyList_Size(path_hooks); + if (nhooks < 0) + return NULL; /* Shouldn't happen */ + + importer = PyDict_GetItem(path_importer_cache, p); + if (importer != NULL) + return importer; + + /* set path_importer_cache[p] to None to avoid recursion */ + if (PyDict_SetItem(path_importer_cache, p, Py_None) != 0) + return NULL; + + for (j = 0; j < nhooks; j++) { + PyObject *hook = PyList_GetItem(path_hooks, j); + if (hook == NULL) + return NULL; + importer = PyObject_CallFunctionObjArgs(hook, p, NULL); + if (importer != NULL) + break; + + if (!PyErr_ExceptionMatches(PyExc_ImportError)) { + return NULL; + } + PyErr_Clear(); + } + if (importer == NULL) { + importer = PyObject_CallFunctionObjArgs( + (PyObject *)&NullImporterType, p, NULL + ); + if (importer == NULL) { + if (PyErr_ExceptionMatches(PyExc_ImportError)) { + PyErr_Clear(); + return Py_None; + } + } + } + if (importer != NULL) { + int err = PyDict_SetItem(path_importer_cache, p, importer); + Py_DECREF(importer); + if (err != 0) + return NULL; + } + return importer; +} + +/* Search the path (default sys.path) for a module. Return the + corresponding filedescr struct, and (via return arguments) the + pathname and an open file. Return NULL if the module is not found. */ + +#ifdef MS_COREDLL +extern FILE *PyWin_FindRegisteredModule(const char *, struct filedescr **, + char *, Py_ssize_t); +#endif + +static int case_ok(char *, Py_ssize_t, Py_ssize_t, char *); +static int find_init_module(char *); /* Forward */ +static struct filedescr importhookdescr = {"", "", IMP_HOOK}; + +static struct filedescr * +find_module(char *fullname, char *subname, PyObject *path, char *buf, + size_t buflen, FILE **p_fp, PyObject **p_loader) +{ + Py_ssize_t i, npath; + size_t len, namelen; + struct filedescr *fdp = NULL; + char *filemode; + FILE *fp = NULL; + PyObject *path_hooks, *path_importer_cache; +#ifndef RISCOS + struct stat statbuf; +#endif + static struct filedescr fd_frozen = {"", "", PY_FROZEN}; + static struct filedescr fd_builtin = {"", "", C_BUILTIN}; + static struct filedescr fd_package = {"", "", PKG_DIRECTORY}; + char name[MAXPATHLEN+1]; +#if defined(PYOS_OS2) + size_t saved_len; + size_t saved_namelen; + char *saved_buf = NULL; +#endif + if (p_loader != NULL) + *p_loader = NULL; + + if (strlen(subname) > MAXPATHLEN) { + PyErr_SetString(PyExc_OverflowError, + "module name is too long"); + return NULL; + } + strcpy(name, subname); + + /* sys.meta_path import hook */ + if (p_loader != NULL) { + PyObject *meta_path; + + meta_path = PySys_GetObject("meta_path"); + if (meta_path == NULL || !PyList_Check(meta_path)) { + PyErr_SetString(PyExc_ImportError, + "sys.meta_path must be a list of " + "import hooks"); + return NULL; + } + Py_INCREF(meta_path); /* zap guard */ + npath = PyList_Size(meta_path); + for (i = 0; i < npath; i++) { + PyObject *loader; + PyObject *hook = PyList_GetItem(meta_path, i); + loader = PyObject_CallMethod(hook, "find_module", + "sO", fullname, + path != NULL ? + path : Py_None); + if (loader == NULL) { + Py_DECREF(meta_path); + return NULL; /* true error */ + } + if (loader != Py_None) { + /* a loader was found */ + *p_loader = loader; + Py_DECREF(meta_path); + return &importhookdescr; + } + Py_DECREF(loader); + } + Py_DECREF(meta_path); + } + + if (path != NULL && PyString_Check(path)) { + /* The only type of submodule allowed inside a "frozen" + package are other frozen modules or packages. */ + if (PyString_Size(path) + 1 + strlen(name) >= (size_t)buflen) { + PyErr_SetString(PyExc_ImportError, + "full frozen module name too long"); + return NULL; + } + strcpy(buf, PyString_AsString(path)); + strcat(buf, "."); + strcat(buf, name); + strcpy(name, buf); + if (find_frozen(name) != NULL) { + strcpy(buf, name); + return &fd_frozen; + } + PyErr_Format(PyExc_ImportError, + "No frozen submodule named %.200s", name); + return NULL; + } + if (path == NULL) { + if (is_builtin(name)) { + strcpy(buf, name); + return &fd_builtin; + } + if ((find_frozen(name)) != NULL) { + strcpy(buf, name); + return &fd_frozen; + } + +#ifdef MS_COREDLL + fp = PyWin_FindRegisteredModule(name, &fdp, buf, buflen); + if (fp != NULL) { + *p_fp = fp; + return fdp; + } +#endif + path = PySys_GetObject("path"); + } + if (path == NULL || !PyList_Check(path)) { + PyErr_SetString(PyExc_ImportError, + "sys.path must be a list of directory names"); + return NULL; + } + + path_hooks = PySys_GetObject("path_hooks"); + if (path_hooks == NULL || !PyList_Check(path_hooks)) { + PyErr_SetString(PyExc_ImportError, + "sys.path_hooks must be a list of " + "import hooks"); + return NULL; + } + path_importer_cache = PySys_GetObject("path_importer_cache"); + if (path_importer_cache == NULL || + !PyDict_Check(path_importer_cache)) { + PyErr_SetString(PyExc_ImportError, + "sys.path_importer_cache must be a dict"); + return NULL; + } + + npath = PyList_Size(path); + namelen = strlen(name); + for (i = 0; i < npath; i++) { + PyObject *copy = NULL; + PyObject *v = PyList_GetItem(path, i); + if (!v) + return NULL; +#ifdef Py_USING_UNICODE + if (PyUnicode_Check(v)) { + copy = PyUnicode_Encode(PyUnicode_AS_UNICODE(v), + PyUnicode_GET_SIZE(v), Py_FileSystemDefaultEncoding, NULL); + if (copy == NULL) + return NULL; + v = copy; + } + else +#endif + if (!PyString_Check(v)) + continue; + len = PyString_GET_SIZE(v); + if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen) { + Py_XDECREF(copy); + continue; /* Too long */ + } + strcpy(buf, PyString_AS_STRING(v)); + if (strlen(buf) != len) { + Py_XDECREF(copy); + continue; /* v contains '\0' */ + } + + /* sys.path_hooks import hook */ + if (p_loader != NULL) { + PyObject *importer; + + importer = get_path_importer(path_importer_cache, + path_hooks, v); + if (importer == NULL) { + Py_XDECREF(copy); + return NULL; + } + /* Note: importer is a borrowed reference */ + if (importer != Py_None) { + PyObject *loader; + loader = PyObject_CallMethod(importer, + "find_module", + "s", fullname); + Py_XDECREF(copy); + if (loader == NULL) + return NULL; /* error */ + if (loader != Py_None) { + /* a loader was found */ + *p_loader = loader; + return &importhookdescr; + } + Py_DECREF(loader); + continue; + } + } + /* no hook was found, use builtin import */ + + if (len > 0 && buf[len-1] != SEP +#ifdef ALTSEP + && buf[len-1] != ALTSEP +#endif + ) + buf[len++] = SEP; + strcpy(buf+len, name); + len += namelen; + + /* Check for package import (buf holds a directory name, + and there's an __init__ module in that directory */ +#ifdef HAVE_STAT + if (stat(buf, &statbuf) == 0 && /* it exists */ + S_ISDIR(statbuf.st_mode) && /* it's a directory */ + case_ok(buf, len, namelen, name)) { /* case matches */ + if (find_init_module(buf)) { /* and has __init__.py */ + Py_XDECREF(copy); + return &fd_package; + } + else { + char warnstr[MAXPATHLEN+80]; + sprintf(warnstr, "Not importing directory " + "'%.*s': missing __init__.py", + MAXPATHLEN, buf); + if (PyErr_Warn(PyExc_ImportWarning, + warnstr)) { + Py_XDECREF(copy); + return NULL; + } + } + } +#else + /* XXX How are you going to test for directories? */ +#ifdef RISCOS + if (isdir(buf) && + case_ok(buf, len, namelen, name)) { + if (find_init_module(buf)) { + Py_XDECREF(copy); + return &fd_package; + } + else { + char warnstr[MAXPATHLEN+80]; + sprintf(warnstr, "Not importing directory " + "'%.*s': missing __init__.py", + MAXPATHLEN, buf); + if (PyErr_Warn(PyExc_ImportWarning, + warnstr)) { + Py_XDECREF(copy); + return NULL; + } + } +#endif +#endif +#if defined(PYOS_OS2) + /* take a snapshot of the module spec for restoration + * after the 8 character DLL hackery + */ + saved_buf = strdup(buf); + saved_len = len; + saved_namelen = namelen; +#endif /* PYOS_OS2 */ + for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { +#if defined(PYOS_OS2) + /* OS/2 limits DLLs to 8 character names (w/o + extension) + * so if the name is longer than that and its a + * dynamically loaded module we're going to try, + * truncate the name before trying + */ + if (strlen(subname) > 8) { + /* is this an attempt to load a C extension? */ + const struct filedescr *scan; + scan = _PyImport_DynLoadFiletab; + while (scan->suffix != NULL) { + if (!strcmp(scan->suffix, fdp->suffix)) + break; + else + scan++; + } + if (scan->suffix != NULL) { + /* yes, so truncate the name */ + namelen = 8; + len -= strlen(subname) - namelen; + buf[len] = '\0'; + } + } +#endif /* PYOS_OS2 */ + strcpy(buf+len, fdp->suffix); + if (Py_VerboseFlag > 1) + PySys_WriteStderr("# trying %s\n", buf); + filemode = fdp->mode; + if (filemode[0] == 'U') + filemode = "r" PY_STDIOTEXTMODE; + fp = fopen(buf, filemode); + if (fp != NULL) { + if (case_ok(buf, len, namelen, name)) + break; + else { /* continue search */ + fclose(fp); + fp = NULL; + } + } +#if defined(PYOS_OS2) + /* restore the saved snapshot */ + strcpy(buf, saved_buf); + len = saved_len; + namelen = saved_namelen; +#endif + } +#if defined(PYOS_OS2) + /* don't need/want the module name snapshot anymore */ + if (saved_buf) + { + free(saved_buf); + saved_buf = NULL; + } +#endif + Py_XDECREF(copy); + if (fp != NULL) + break; + } + if (fp == NULL) { + PyErr_Format(PyExc_ImportError, + "No module named %.200s", name); + return NULL; + } + *p_fp = fp; + return fdp; +} + +/* Helpers for main.c + * Find the source file corresponding to a named module + */ +struct filedescr * +_PyImport_FindModule(const char *name, PyObject *path, char *buf, + size_t buflen, FILE **p_fp, PyObject **p_loader) +{ + return find_module((char *) name, (char *) name, path, + buf, buflen, p_fp, p_loader); +} + +PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr * fd) +{ + return fd->type == PY_SOURCE || fd->type == PY_COMPILED; +} + +/* case_ok(char* buf, Py_ssize_t len, Py_ssize_t namelen, char* name) + * The arguments here are tricky, best shown by example: + * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0 + * ^ ^ ^ ^ + * |--------------------- buf ---------------------| + * |------------------- len ------------------| + * |------ name -------| + * |----- namelen -----| + * buf is the full path, but len only counts up to (& exclusive of) the + * extension. name is the module name, also exclusive of extension. + * + * We've already done a successful stat() or fopen() on buf, so know that + * there's some match, possibly case-insensitive. + * + * case_ok() is to return 1 if there's a case-sensitive match for + * name, else 0. case_ok() is also to return 1 if envar PYTHONCASEOK + * exists. + * + * case_ok() is used to implement case-sensitive import semantics even + * on platforms with case-insensitive filesystems. It's trivial to implement + * for case-sensitive filesystems. It's pretty much a cross-platform + * nightmare for systems with case-insensitive filesystems. + */ + +/* First we may need a pile of platform-specific header files; the sequence + * of #if's here should match the sequence in the body of case_ok(). + */ +#if defined(MS_WINDOWS) +#include <windows.h> + +#elif defined(DJGPP) +#include <dir.h> + +#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) +#include <sys/types.h> +#include <dirent.h> + +#elif defined(PYOS_OS2) +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_NOPMAPI +#include <os2.h> + +#elif defined(RISCOS) +#include "oslib/osfscontrol.h" +#endif + +static int +case_ok(char *buf, Py_ssize_t len, Py_ssize_t namelen, char *name) +{ +/* Pick a platform-specific implementation; the sequence of #if's here should + * match the sequence just above. + */ + +/* MS_WINDOWS */ +#if defined(MS_WINDOWS) + WIN32_FIND_DATA data; + HANDLE h; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + h = FindFirstFile(buf, &data); + if (h == INVALID_HANDLE_VALUE) { + PyErr_Format(PyExc_NameError, + "Can't find file for module %.100s\n(filename %.300s)", + name, buf); + return 0; + } + FindClose(h); + return strncmp(data.cFileName, name, namelen) == 0; + +/* DJGPP */ +#elif defined(DJGPP) + struct ffblk ffblk; + int done; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + done = findfirst(buf, &ffblk, FA_ARCH|FA_RDONLY|FA_HIDDEN|FA_DIREC); + if (done) { + PyErr_Format(PyExc_NameError, + "Can't find file for module %.100s\n(filename %.300s)", + name, buf); + return 0; + } + return strncmp(ffblk.ff_name, name, namelen) == 0; + +/* new-fangled macintosh (macosx) or Cygwin */ +#elif (defined(__MACH__) && defined(__APPLE__) || defined(__CYGWIN__)) && defined(HAVE_DIRENT_H) + DIR *dirp; + struct dirent *dp; + char dirname[MAXPATHLEN + 1]; + const int dirlen = len - namelen - 1; /* don't want trailing SEP */ + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + /* Copy the dir component into dirname; substitute "." if empty */ + if (dirlen <= 0) { + dirname[0] = '.'; + dirname[1] = '\0'; + } + else { + assert(dirlen <= MAXPATHLEN); + memcpy(dirname, buf, dirlen); + dirname[dirlen] = '\0'; + } + /* Open the directory and search the entries for an exact match. */ + dirp = opendir(dirname); + if (dirp) { + char *nameWithExt = buf + len - namelen; + while ((dp = readdir(dirp)) != NULL) { + const int thislen = +#ifdef _DIRENT_HAVE_D_NAMELEN + dp->d_namlen; +#else + strlen(dp->d_name); +#endif + if (thislen >= namelen && + strcmp(dp->d_name, nameWithExt) == 0) { + (void)closedir(dirp); + return 1; /* Found */ + } + } + (void)closedir(dirp); + } + return 0 ; /* Not found */ + +/* RISC OS */ +#elif defined(RISCOS) + char canon[MAXPATHLEN+1]; /* buffer for the canonical form of the path */ + char buf2[MAXPATHLEN+2]; + char *nameWithExt = buf+len-namelen; + int canonlen; + os_error *e; + + if (Py_GETENV("PYTHONCASEOK") != NULL) + return 1; + + /* workaround: + append wildcard, otherwise case of filename wouldn't be touched */ + strcpy(buf2, buf); + strcat(buf2, "*"); + + e = xosfscontrol_canonicalise_path(buf2,canon,0,0,MAXPATHLEN+1,&canonlen); + canonlen = MAXPATHLEN+1-canonlen; + if (e || canonlen<=0 || canonlen>(MAXPATHLEN+1) ) + return 0; + if (strcmp(nameWithExt, canon+canonlen-strlen(nameWithExt))==0) + return 1; /* match */ + + return 0; + +/* OS/2 */ +#elif defined(PYOS_OS2) + HDIR hdir = 1; + ULONG srchcnt = 1; + FILEFINDBUF3 ffbuf; + APIRET rc; + + if (getenv("PYTHONCASEOK") != NULL) + return 1; + + rc = DosFindFirst(buf, + &hdir, + FILE_READONLY | FILE_HIDDEN | FILE_SYSTEM | FILE_DIRECTORY, + &ffbuf, sizeof(ffbuf), + &srchcnt, + FIL_STANDARD); + if (rc != NO_ERROR) + return 0; + return strncmp(ffbuf.achName, name, namelen) == 0; + +/* assuming it's a case-sensitive filesystem, so there's nothing to do! */ +#else + return 1; + +#endif +} + + +#ifdef HAVE_STAT +/* Helper to look for __init__.py or __init__.py[co] in potential package */ +static int +find_init_module(char *buf) +{ + const size_t save_len = strlen(buf); + size_t i = save_len; + char *pname; /* pointer to start of __init__ */ + struct stat statbuf; + +/* For calling case_ok(buf, len, namelen, name): + * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0 + * ^ ^ ^ ^ + * |--------------------- buf ---------------------| + * |------------------- len ------------------| + * |------ name -------| + * |----- namelen -----| + */ + if (save_len + 13 >= MAXPATHLEN) + return 0; + buf[i++] = SEP; + pname = buf + i; + strcpy(pname, "__init__.py"); + if (stat(buf, &statbuf) == 0) { + if (case_ok(buf, + save_len + 9, /* len("/__init__") */ + 8, /* len("__init__") */ + pname)) { + buf[save_len] = '\0'; + return 1; + } + } + i += strlen(pname); + strcpy(buf+i, Py_OptimizeFlag ? "o" : "c"); + if (stat(buf, &statbuf) == 0) { + if (case_ok(buf, + save_len + 9, /* len("/__init__") */ + 8, /* len("__init__") */ + pname)) { + buf[save_len] = '\0'; + return 1; + } + } + buf[save_len] = '\0'; + return 0; +} + +#else + +#ifdef RISCOS +static int +find_init_module(buf) + char *buf; +{ + int save_len = strlen(buf); + int i = save_len; + + if (save_len + 13 >= MAXPATHLEN) + return 0; + buf[i++] = SEP; + strcpy(buf+i, "__init__/py"); + if (isfile(buf)) { + buf[save_len] = '\0'; + return 1; + } + + if (Py_OptimizeFlag) + strcpy(buf+i, "o"); + else + strcpy(buf+i, "c"); + if (isfile(buf)) { + buf[save_len] = '\0'; + return 1; + } + buf[save_len] = '\0'; + return 0; +} +#endif /*RISCOS*/ + +#endif /* HAVE_STAT */ + + +static int init_builtin(char *); /* Forward */ + +/* Load an external module using the default search path and return + its module object WITH INCREMENTED REFERENCE COUNT */ + +static PyObject * +load_module(char *name, FILE *fp, char *buf, int type, PyObject *loader) +{ + PyObject *modules; + PyObject *m; + int err; + + /* First check that there's an open file (if we need one) */ + switch (type) { + case PY_SOURCE: + case PY_COMPILED: + if (fp == NULL) { + PyErr_Format(PyExc_ValueError, + "file object required for import (type code %d)", + type); + return NULL; + } + } + + switch (type) { + + case PY_SOURCE: + m = load_source_module(name, buf, fp); + break; + + case PY_COMPILED: + m = load_compiled_module(name, buf, fp); + break; + +#ifdef HAVE_DYNAMIC_LOADING + case C_EXTENSION: + m = _PyImport_LoadDynamicModule(name, buf, fp); + break; +#endif + + case PKG_DIRECTORY: + m = load_package(name, buf); + break; + + case C_BUILTIN: + case PY_FROZEN: + if (buf != NULL && buf[0] != '\0') + name = buf; + if (type == C_BUILTIN) + err = init_builtin(name); + else + err = PyImport_ImportFrozenModule(name); + if (err < 0) + return NULL; + if (err == 0) { + PyErr_Format(PyExc_ImportError, + "Purported %s module %.200s not found", + type == C_BUILTIN ? + "builtin" : "frozen", + name); + return NULL; + } + modules = PyImport_GetModuleDict(); + m = PyDict_GetItemString(modules, name); + if (m == NULL) { + PyErr_Format( + PyExc_ImportError, + "%s module %.200s not properly initialized", + type == C_BUILTIN ? + "builtin" : "frozen", + name); + return NULL; + } + Py_INCREF(m); + break; + + case IMP_HOOK: { + if (loader == NULL) { + PyErr_SetString(PyExc_ImportError, + "import hook without loader"); + return NULL; + } + m = PyObject_CallMethod(loader, "load_module", "s", name); + break; + } + + default: + PyErr_Format(PyExc_ImportError, + "Don't know how to import %.200s (type code %d)", + name, type); + m = NULL; + + } + + return m; +} + + +/* Initialize a built-in module. + Return 1 for succes, 0 if the module is not found, and -1 with + an exception set if the initialization failed. */ + +static int +init_builtin(char *name) +{ + struct _inittab *p; + + if (_PyImport_FindExtension(name, name) != NULL) + return 1; + + for (p = PyImport_Inittab; p->name != NULL; p++) { + if (strcmp(name, p->name) == 0) { + if (p->initfunc == NULL) { + PyErr_Format(PyExc_ImportError, + "Cannot re-init internal module %.200s", + name); + return -1; + } + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # builtin\n", name); + (*p->initfunc)(); + if (PyErr_Occurred()) + return -1; + if (_PyImport_FixupExtension(name, name) == NULL) + return -1; + return 1; + } + } + return 0; +} + + +/* Frozen modules */ + +static struct _frozen * +find_frozen(char *name) +{ + struct _frozen *p; + + for (p = PyImport_FrozenModules; ; p++) { + if (p->name == NULL) + return NULL; + if (strcmp(p->name, name) == 0) + break; + } + return p; +} + +static PyObject * +get_frozen_object(char *name) +{ + struct _frozen *p = find_frozen(name); + int size; + + if (p == NULL) { + PyErr_Format(PyExc_ImportError, + "No such frozen object named %.200s", + name); + return NULL; + } + if (p->code == NULL) { + PyErr_Format(PyExc_ImportError, + "Excluded frozen object named %.200s", + name); + return NULL; + } + size = p->size; + if (size < 0) + size = -size; + return PyMarshal_ReadObjectFromString((char *)p->code, size); +} + +/* Initialize a frozen module. + Return 1 for succes, 0 if the module is not found, and -1 with + an exception set if the initialization failed. + This function is also used from frozenmain.c */ + +int +PyImport_ImportFrozenModule(char *name) +{ + struct _frozen *p = find_frozen(name); + PyObject *co; + PyObject *m; + int ispackage; + int size; + + if (p == NULL) + return 0; + if (p->code == NULL) { + PyErr_Format(PyExc_ImportError, + "Excluded frozen object named %.200s", + name); + return -1; + } + size = p->size; + ispackage = (size < 0); + if (ispackage) + size = -size; + if (Py_VerboseFlag) + PySys_WriteStderr("import %s # frozen%s\n", + name, ispackage ? " package" : ""); + co = PyMarshal_ReadObjectFromString((char *)p->code, size); + if (co == NULL) + return -1; + if (!PyCode_Check(co)) { + PyErr_Format(PyExc_TypeError, + "frozen object %.200s is not a code object", + name); + goto err_return; + } + if (ispackage) { + /* Set __path__ to the package name */ + PyObject *d, *s; + int err; + m = PyImport_AddModule(name); + if (m == NULL) + goto err_return; + d = PyModule_GetDict(m); + s = PyString_InternFromString(name); + if (s == NULL) + goto err_return; + err = PyDict_SetItemString(d, "__path__", s); + Py_DECREF(s); + if (err != 0) + goto err_return; + } + m = PyImport_ExecCodeModuleEx(name, co, "<frozen>"); + if (m == NULL) + goto err_return; + Py_DECREF(co); + Py_DECREF(m); + return 1; +err_return: + Py_DECREF(co); + return -1; +} + + +/* Import a module, either built-in, frozen, or external, and return + its module object WITH INCREMENTED REFERENCE COUNT */ + +PyObject * +PyImport_ImportModule(const char *name) +{ + PyObject *pname; + PyObject *result; + + pname = PyString_FromString(name); + if (pname == NULL) + return NULL; + result = PyImport_Import(pname); + Py_DECREF(pname); + return result; +} + +/* Forward declarations for helper routines */ +static PyObject *get_parent(PyObject *globals, char *buf, + Py_ssize_t *p_buflen, int level); +static PyObject *load_next(PyObject *mod, PyObject *altmod, + char **p_name, char *buf, Py_ssize_t *p_buflen); +static int mark_miss(char *name); +static int ensure_fromlist(PyObject *mod, PyObject *fromlist, + char *buf, Py_ssize_t buflen, int recursive); +static PyObject * import_submodule(PyObject *mod, char *name, char *fullname); + +/* The Magnum Opus of dotted-name import :-) */ + +static PyObject * +import_module_level(char *name, PyObject *globals, PyObject *locals, + PyObject *fromlist, int level) +{ + char buf[MAXPATHLEN+1]; + Py_ssize_t buflen = 0; + PyObject *parent, *head, *next, *tail; + + parent = get_parent(globals, buf, &buflen, level); + if (parent == NULL) + return NULL; + + head = load_next(parent, Py_None, &name, buf, &buflen); + if (head == NULL) + return NULL; + + tail = head; + Py_INCREF(tail); + while (name) { + next = load_next(tail, tail, &name, buf, &buflen); + Py_DECREF(tail); + if (next == NULL) { + Py_DECREF(head); + return NULL; + } + tail = next; + } + if (tail == Py_None) { + /* If tail is Py_None, both get_parent and load_next found + an empty module name: someone called __import__("") or + doctored faulty bytecode */ + Py_DECREF(tail); + Py_DECREF(head); + PyErr_SetString(PyExc_ValueError, + "Empty module name"); + return NULL; + } + + if (fromlist != NULL) { + if (fromlist == Py_None || !PyObject_IsTrue(fromlist)) + fromlist = NULL; + } + + if (fromlist == NULL) { + Py_DECREF(tail); + return head; + } + + Py_DECREF(head); + if (!ensure_fromlist(tail, fromlist, buf, buflen, 0)) { + Py_DECREF(tail); + return NULL; + } + + return tail; +} + +/* For DLL compatibility */ +#undef PyImport_ImportModuleEx +PyObject * +PyImport_ImportModuleEx(char *name, PyObject *globals, PyObject *locals, + PyObject *fromlist) +{ + PyObject *result; + lock_import(); + result = import_module_level(name, globals, locals, fromlist, -1); + if (unlock_import() < 0) { + Py_XDECREF(result); + PyErr_SetString(PyExc_RuntimeError, + "not holding the import lock"); + return NULL; + } + return result; +} +#define PyImport_ImportModuleEx(n, g, l, f) \ + PyImport_ImportModuleLevel(n, g, l, f, -1); + +PyObject * +PyImport_ImportModuleLevel(char *name, PyObject *globals, PyObject *locals, + PyObject *fromlist, int level) +{ + PyObject *result; + lock_import(); + result = import_module_level(name, globals, locals, fromlist, level); + if (unlock_import() < 0) { + Py_XDECREF(result); + PyErr_SetString(PyExc_RuntimeError, + "not holding the import lock"); + return NULL; + } + return result; +} + +/* Return the package that an import is being performed in. If globals comes + from the module foo.bar.bat (not itself a package), this returns the + sys.modules entry for foo.bar. If globals is from a package's __init__.py, + the package's entry in sys.modules is returned, as a borrowed reference. + + The *name* of the returned package is returned in buf, with the length of + the name in *p_buflen. + + If globals doesn't come from a package or a module in a package, or a + corresponding entry is not found in sys.modules, Py_None is returned. +*/ +static PyObject * +get_parent(PyObject *globals, char *buf, Py_ssize_t *p_buflen, int level) +{ + static PyObject *namestr = NULL; + static PyObject *pathstr = NULL; + PyObject *modname, *modpath, *modules, *parent; + + if (globals == NULL || !PyDict_Check(globals) || !level) + return Py_None; + + if (namestr == NULL) { + namestr = PyString_InternFromString("__name__"); + if (namestr == NULL) + return NULL; + } + if (pathstr == NULL) { + pathstr = PyString_InternFromString("__path__"); + if (pathstr == NULL) + return NULL; + } + + *buf = '\0'; + *p_buflen = 0; + modname = PyDict_GetItem(globals, namestr); + if (modname == NULL || !PyString_Check(modname)) + return Py_None; + + modpath = PyDict_GetItem(globals, pathstr); + if (modpath != NULL) { + Py_ssize_t len = PyString_GET_SIZE(modname); + if (len > MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + strcpy(buf, PyString_AS_STRING(modname)); + } + else { + char *start = PyString_AS_STRING(modname); + char *lastdot = strrchr(start, '.'); + size_t len; + if (lastdot == NULL && level > 0) { + PyErr_SetString(PyExc_ValueError, + "Attempted relative import in non-package"); + return NULL; + } + if (lastdot == NULL) + return Py_None; + len = lastdot - start; + if (len >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + strncpy(buf, start, len); + buf[len] = '\0'; + } + + while (--level > 0) { + char *dot = strrchr(buf, '.'); + if (dot == NULL) { + PyErr_SetString(PyExc_ValueError, + "Attempted relative import beyond " + "toplevel package"); + return NULL; + } + *dot = '\0'; + } + *p_buflen = strlen(buf); + + modules = PyImport_GetModuleDict(); + parent = PyDict_GetItemString(modules, buf); + if (parent == NULL) + PyErr_Format(PyExc_SystemError, + "Parent module '%.200s' not loaded", buf); + return parent; + /* We expect, but can't guarantee, if parent != None, that: + - parent.__name__ == buf + - parent.__dict__ is globals + If this is violated... Who cares? */ +} + +/* altmod is either None or same as mod */ +static PyObject * +load_next(PyObject *mod, PyObject *altmod, char **p_name, char *buf, + Py_ssize_t *p_buflen) +{ + char *name = *p_name; + char *dot = strchr(name, '.'); + size_t len; + char *p; + PyObject *result; + + if (strlen(name) == 0) { + /* completely empty module name should only happen in + 'from . import' (or '__import__("")')*/ + Py_INCREF(mod); + *p_name = NULL; + return mod; + } + + if (dot == NULL) { + *p_name = NULL; + len = strlen(name); + } + else { + *p_name = dot+1; + len = dot-name; + } + if (len == 0) { + PyErr_SetString(PyExc_ValueError, + "Empty module name"); + return NULL; + } + + p = buf + *p_buflen; + if (p != buf) + *p++ = '.'; + if (p+len-buf >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + return NULL; + } + strncpy(p, name, len); + p[len] = '\0'; + *p_buflen = p+len-buf; + + result = import_submodule(mod, p, buf); + if (result == Py_None && altmod != mod) { + Py_DECREF(result); + /* Here, altmod must be None and mod must not be None */ + result = import_submodule(altmod, p, p); + if (result != NULL && result != Py_None) { + if (mark_miss(buf) != 0) { + Py_DECREF(result); + return NULL; + } + strncpy(buf, name, len); + buf[len] = '\0'; + *p_buflen = len; + } + } + if (result == NULL) + return NULL; + + if (result == Py_None) { + Py_DECREF(result); + PyErr_Format(PyExc_ImportError, + "No module named %.200s", name); + return NULL; + } + + return result; +} + +static int +mark_miss(char *name) +{ + PyObject *modules = PyImport_GetModuleDict(); + return PyDict_SetItemString(modules, name, Py_None); +} + +static int +ensure_fromlist(PyObject *mod, PyObject *fromlist, char *buf, Py_ssize_t buflen, + int recursive) +{ + int i; + + if (!PyObject_HasAttrString(mod, "__path__")) + return 1; + + for (i = 0; ; i++) { + PyObject *item = PySequence_GetItem(fromlist, i); + int hasit; + if (item == NULL) { + if (PyErr_ExceptionMatches(PyExc_IndexError)) { + PyErr_Clear(); + return 1; + } + return 0; + } + if (!PyString_Check(item)) { + PyErr_SetString(PyExc_TypeError, + "Item in ``from list'' not a string"); + Py_DECREF(item); + return 0; + } + if (PyString_AS_STRING(item)[0] == '*') { + PyObject *all; + Py_DECREF(item); + /* See if the package defines __all__ */ + if (recursive) + continue; /* Avoid endless recursion */ + all = PyObject_GetAttrString(mod, "__all__"); + if (all == NULL) + PyErr_Clear(); + else { + int ret = ensure_fromlist(mod, all, buf, buflen, 1); + Py_DECREF(all); + if (!ret) + return 0; + } + continue; + } + hasit = PyObject_HasAttr(mod, item); + if (!hasit) { + char *subname = PyString_AS_STRING(item); + PyObject *submod; + char *p; + if (buflen + strlen(subname) >= MAXPATHLEN) { + PyErr_SetString(PyExc_ValueError, + "Module name too long"); + Py_DECREF(item); + return 0; + } + p = buf + buflen; + *p++ = '.'; + strcpy(p, subname); + submod = import_submodule(mod, subname, buf); + Py_XDECREF(submod); + if (submod == NULL) { + Py_DECREF(item); + return 0; + } + } + Py_DECREF(item); + } + + /* NOTREACHED */ +} + +static int +add_submodule(PyObject *mod, PyObject *submod, char *fullname, char *subname, + PyObject *modules) +{ + if (mod == Py_None) + return 1; + /* Irrespective of the success of this load, make a + reference to it in the parent package module. A copy gets + saved in the modules dictionary under the full name, so get a + reference from there, if need be. (The exception is when the + load failed with a SyntaxError -- then there's no trace in + sys.modules. In that case, of course, do nothing extra.) */ + if (submod == NULL) { + submod = PyDict_GetItemString(modules, fullname); + if (submod == NULL) + return 1; + } + if (PyModule_Check(mod)) { + /* We can't use setattr here since it can give a + * spurious warning if the submodule name shadows a + * builtin name */ + PyObject *dict = PyModule_GetDict(mod); + if (!dict) + return 0; + if (PyDict_SetItemString(dict, subname, submod) < 0) + return 0; + } + else { + if (PyObject_SetAttrString(mod, subname, submod) < 0) + return 0; + } + return 1; +} + +static PyObject * +import_submodule(PyObject *mod, char *subname, char *fullname) +{ + PyObject *modules = PyImport_GetModuleDict(); + PyObject *m = NULL; + + /* Require: + if mod == None: subname == fullname + else: mod.__name__ + "." + subname == fullname + */ + + if ((m = PyDict_GetItemString(modules, fullname)) != NULL) { + Py_INCREF(m); + } + else { + PyObject *path, *loader = NULL; + char buf[MAXPATHLEN+1]; + struct filedescr *fdp; + FILE *fp = NULL; + + if (mod == Py_None) + path = NULL; + else { + path = PyObject_GetAttrString(mod, "__path__"); + if (path == NULL) { + PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + } + + buf[0] = '\0'; + fdp = find_module(fullname, subname, path, buf, MAXPATHLEN+1, + &fp, &loader); + Py_XDECREF(path); + if (fdp == NULL) { + if (!PyErr_ExceptionMatches(PyExc_ImportError)) + return NULL; + PyErr_Clear(); + Py_INCREF(Py_None); + return Py_None; + } + m = load_module(fullname, fp, buf, fdp->type, loader); + Py_XDECREF(loader); + if (fp) + fclose(fp); + if (!add_submodule(mod, m, fullname, subname, modules)) { + Py_XDECREF(m); + m = NULL; + } + } + + return m; +} + + +/* Re-import a module of any kind and return its module object, WITH + INCREMENTED REFERENCE COUNT */ + +PyObject * +PyImport_ReloadModule(PyObject *m) +{ + PyInterpreterState *interp = PyThreadState_Get()->interp; + PyObject *modules_reloading = interp->modules_reloading; + PyObject *modules = PyImport_GetModuleDict(); + PyObject *path = NULL, *loader = NULL, *existing_m = NULL; + char *name, *subname; + char buf[MAXPATHLEN+1]; + struct filedescr *fdp; + FILE *fp = NULL; + PyObject *newm; + + if (modules_reloading == NULL) { + Py_FatalError("PyImport_ReloadModule: " + "no modules_reloading dictionary!"); + return NULL; + } + + if (m == NULL || !PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "reload() argument must be module"); + return NULL; + } + name = PyModule_GetName(m); + if (name == NULL) + return NULL; + if (m != PyDict_GetItemString(modules, name)) { + PyErr_Format(PyExc_ImportError, + "reload(): module %.200s not in sys.modules", + name); + return NULL; + } + if ((existing_m = PyDict_GetItemString(modules_reloading, name)) != NULL) { + /* Due to a recursive reload, this module is already being reloaded. */ + Py_INCREF(existing_m); + return existing_m; + } + PyDict_SetItemString(modules_reloading, name, m); + + subname = strrchr(name, '.'); + if (subname == NULL) + subname = name; + else { + PyObject *parentname, *parent; + parentname = PyString_FromStringAndSize(name, (subname-name)); + if (parentname == NULL) { + imp_modules_reloading_clear(); + return NULL; + } + parent = PyDict_GetItem(modules, parentname); + if (parent == NULL) { + PyErr_Format(PyExc_ImportError, + "reload(): parent %.200s not in sys.modules", + PyString_AS_STRING(parentname)); + Py_DECREF(parentname); + imp_modules_reloading_clear(); + return NULL; + } + Py_DECREF(parentname); + subname++; + path = PyObject_GetAttrString(parent, "__path__"); + if (path == NULL) + PyErr_Clear(); + } + buf[0] = '\0'; + fdp = find_module(name, subname, path, buf, MAXPATHLEN+1, &fp, &loader); + Py_XDECREF(path); + + if (fdp == NULL) { + Py_XDECREF(loader); + imp_modules_reloading_clear(); + return NULL; + } + + newm = load_module(name, fp, buf, fdp->type, loader); + Py_XDECREF(loader); + + if (fp) + fclose(fp); + if (newm == NULL) { + /* load_module probably removed name from modules because of + * the error. Put back the original module object. We're + * going to return NULL in this case regardless of whether + * replacing name succeeds, so the return value is ignored. + */ + PyDict_SetItemString(modules, name, m); + } + imp_modules_reloading_clear(); + return newm; +} + + +/* Higher-level import emulator which emulates the "import" statement + more accurately -- it invokes the __import__() function from the + builtins of the current globals. This means that the import is + done using whatever import hooks are installed in the current + environment, e.g. by "rexec". + A dummy list ["__doc__"] is passed as the 4th argument so that + e.g. PyImport_Import(PyString_FromString("win32com.client.gencache")) + will return <module "gencache"> instead of <module "win32com">. */ + +PyObject * +PyImport_Import(PyObject *module_name) +{ + static PyObject *silly_list = NULL; + static PyObject *builtins_str = NULL; + static PyObject *import_str = NULL; + PyObject *globals = NULL; + PyObject *import = NULL; + PyObject *builtins = NULL; + PyObject *r = NULL; + + /* Initialize constant string objects */ + if (silly_list == NULL) { + import_str = PyString_InternFromString("__import__"); + if (import_str == NULL) + return NULL; + builtins_str = PyString_InternFromString("__builtins__"); + if (builtins_str == NULL) + return NULL; + silly_list = Py_BuildValue("[s]", "__doc__"); + if (silly_list == NULL) + return NULL; + } + + /* Get the builtins from current globals */ + globals = PyEval_GetGlobals(); + if (globals != NULL) { + Py_INCREF(globals); + builtins = PyObject_GetItem(globals, builtins_str); + if (builtins == NULL) + goto err; + } + else { + /* No globals -- use standard builtins, and fake globals */ + PyErr_Clear(); + + builtins = PyImport_ImportModuleLevel("__builtin__", + NULL, NULL, NULL, 0); + if (builtins == NULL) + return NULL; + globals = Py_BuildValue("{OO}", builtins_str, builtins); + if (globals == NULL) + goto err; + } + + /* Get the __import__ function from the builtins */ + if (PyDict_Check(builtins)) { + import = PyObject_GetItem(builtins, import_str); + if (import == NULL) + PyErr_SetObject(PyExc_KeyError, import_str); + } + else + import = PyObject_GetAttr(builtins, import_str); + if (import == NULL) + goto err; + + /* Call the _import__ function with the proper argument list */ + r = PyObject_CallFunctionObjArgs(import, module_name, globals, + globals, silly_list, NULL); + + err: + Py_XDECREF(globals); + Py_XDECREF(builtins); + Py_XDECREF(import); + + return r; +} + + +/* Module 'imp' provides Python access to the primitives used for + importing modules. +*/ + +static PyObject * +imp_get_magic(PyObject *self, PyObject *noargs) +{ + char buf[4]; + + buf[0] = (char) ((pyc_magic >> 0) & 0xff); + buf[1] = (char) ((pyc_magic >> 8) & 0xff); + buf[2] = (char) ((pyc_magic >> 16) & 0xff); + buf[3] = (char) ((pyc_magic >> 24) & 0xff); + + return PyString_FromStringAndSize(buf, 4); +} + +static PyObject * +imp_get_suffixes(PyObject *self, PyObject *noargs) +{ + PyObject *list; + struct filedescr *fdp; + + list = PyList_New(0); + if (list == NULL) + return NULL; + for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) { + PyObject *item = Py_BuildValue("ssi", + fdp->suffix, fdp->mode, fdp->type); + if (item == NULL) { + Py_DECREF(list); + return NULL; + } + if (PyList_Append(list, item) < 0) { + Py_DECREF(list); + Py_DECREF(item); + return NULL; + } + Py_DECREF(item); + } + return list; +} + +static PyObject * +call_find_module(char *name, PyObject *path) +{ + extern int fclose(FILE *); + PyObject *fob, *ret; + struct filedescr *fdp; + char pathname[MAXPATHLEN+1]; + FILE *fp = NULL; + + pathname[0] = '\0'; + if (path == Py_None) + path = NULL; + fdp = find_module(NULL, name, path, pathname, MAXPATHLEN+1, &fp, NULL); + if (fdp == NULL) + return NULL; + if (fp != NULL) { + fob = PyFile_FromFile(fp, pathname, fdp->mode, fclose); + if (fob == NULL) { + fclose(fp); + return NULL; + } + } + else { + fob = Py_None; + Py_INCREF(fob); + } + ret = Py_BuildValue("Os(ssi)", + fob, pathname, fdp->suffix, fdp->mode, fdp->type); + Py_DECREF(fob); + return ret; +} + +static PyObject * +imp_find_module(PyObject *self, PyObject *args) +{ + char *name; + PyObject *path = NULL; + if (!PyArg_ParseTuple(args, "s|O:find_module", &name, &path)) + return NULL; + return call_find_module(name, path); +} + +static PyObject * +imp_init_builtin(PyObject *self, PyObject *args) +{ + char *name; + int ret; + PyObject *m; + if (!PyArg_ParseTuple(args, "s:init_builtin", &name)) + return NULL; + ret = init_builtin(name); + if (ret < 0) + return NULL; + if (ret == 0) { + Py_INCREF(Py_None); + return Py_None; + } + m = PyImport_AddModule(name); + Py_XINCREF(m); + return m; +} + +static PyObject * +imp_init_frozen(PyObject *self, PyObject *args) +{ + char *name; + int ret; + PyObject *m; + if (!PyArg_ParseTuple(args, "s:init_frozen", &name)) + return NULL; + ret = PyImport_ImportFrozenModule(name); + if (ret < 0) + return NULL; + if (ret == 0) { + Py_INCREF(Py_None); + return Py_None; + } + m = PyImport_AddModule(name); + Py_XINCREF(m); + return m; +} + +static PyObject * +imp_get_frozen_object(PyObject *self, PyObject *args) +{ + char *name; + + if (!PyArg_ParseTuple(args, "s:get_frozen_object", &name)) + return NULL; + return get_frozen_object(name); +} + +static PyObject * +imp_is_builtin(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s:is_builtin", &name)) + return NULL; + return PyInt_FromLong(is_builtin(name)); +} + +static PyObject * +imp_is_frozen(PyObject *self, PyObject *args) +{ + char *name; + struct _frozen *p; + if (!PyArg_ParseTuple(args, "s:is_frozen", &name)) + return NULL; + p = find_frozen(name); + return PyBool_FromLong((long) (p == NULL ? 0 : p->size)); +} + +static FILE * +get_file(char *pathname, PyObject *fob, char *mode) +{ + FILE *fp; + if (fob == NULL) { + if (mode[0] == 'U') + mode = "r" PY_STDIOTEXTMODE; + fp = fopen(pathname, mode); + if (fp == NULL) + PyErr_SetFromErrno(PyExc_IOError); + } + else { + fp = PyFile_AsFile(fob); + if (fp == NULL) + PyErr_SetString(PyExc_ValueError, + "bad/closed file object"); + } + return fp; +} + +static PyObject * +imp_load_compiled(PyObject *self, PyObject *args) +{ + char *name; + char *pathname; + PyObject *fob = NULL; + PyObject *m; + FILE *fp; + if (!PyArg_ParseTuple(args, "ss|O!:load_compiled", &name, &pathname, + &PyFile_Type, &fob)) + return NULL; + fp = get_file(pathname, fob, "rb"); + if (fp == NULL) + return NULL; + m = load_compiled_module(name, pathname, fp); + if (fob == NULL) + fclose(fp); + return m; +} + +#ifdef HAVE_DYNAMIC_LOADING + +static PyObject * +imp_load_dynamic(PyObject *self, PyObject *args) +{ + char *name; + char *pathname; + PyObject *fob = NULL; + PyObject *m; + FILE *fp = NULL; + if (!PyArg_ParseTuple(args, "ss|O!:load_dynamic", &name, &pathname, + &PyFile_Type, &fob)) + return NULL; + if (fob) { + fp = get_file(pathname, fob, "r"); + if (fp == NULL) + return NULL; + } + m = _PyImport_LoadDynamicModule(name, pathname, fp); + return m; +} + +#endif /* HAVE_DYNAMIC_LOADING */ + +static PyObject * +imp_load_source(PyObject *self, PyObject *args) +{ + char *name; + char *pathname; + PyObject *fob = NULL; + PyObject *m; + FILE *fp; + if (!PyArg_ParseTuple(args, "ss|O!:load_source", &name, &pathname, + &PyFile_Type, &fob)) + return NULL; + fp = get_file(pathname, fob, "r"); + if (fp == NULL) + return NULL; + m = load_source_module(name, pathname, fp); + if (fob == NULL) + fclose(fp); + return m; +} + +static PyObject * +imp_load_module(PyObject *self, PyObject *args) +{ + char *name; + PyObject *fob; + char *pathname; + char *suffix; /* Unused */ + char *mode; + int type; + FILE *fp; + + if (!PyArg_ParseTuple(args, "sOs(ssi):load_module", + &name, &fob, &pathname, + &suffix, &mode, &type)) + return NULL; + if (*mode) { + /* Mode must start with 'r' or 'U' and must not contain '+'. + Implicit in this test is the assumption that the mode + may contain other modifiers like 'b' or 't'. */ + + if (!(*mode == 'r' || *mode == 'U') || strchr(mode, '+')) { + PyErr_Format(PyExc_ValueError, + "invalid file open mode %.200s", mode); + return NULL; + } + } + if (fob == Py_None) + fp = NULL; + else { + if (!PyFile_Check(fob)) { + PyErr_SetString(PyExc_ValueError, + "load_module arg#2 should be a file or None"); + return NULL; + } + fp = get_file(pathname, fob, mode); + if (fp == NULL) + return NULL; + } + return load_module(name, fp, pathname, type, NULL); +} + +static PyObject * +imp_load_package(PyObject *self, PyObject *args) +{ + char *name; + char *pathname; + if (!PyArg_ParseTuple(args, "ss:load_package", &name, &pathname)) + return NULL; + return load_package(name, pathname); +} + +static PyObject * +imp_new_module(PyObject *self, PyObject *args) +{ + char *name; + if (!PyArg_ParseTuple(args, "s:new_module", &name)) + return NULL; + return PyModule_New(name); +} + +/* Doc strings */ + +PyDoc_STRVAR(doc_imp, +"This module provides the components needed to build your own\n\ +__import__ function. Undocumented functions are obsolete."); + +PyDoc_STRVAR(doc_find_module, +"find_module(name, [path]) -> (file, filename, (suffix, mode, type))\n\ +Search for a module. If path is omitted or None, search for a\n\ +built-in, frozen or special module and continue search in sys.path.\n\ +The module name cannot contain '.'; to search for a submodule of a\n\ +package, pass the submodule name and the package's __path__."); + +PyDoc_STRVAR(doc_load_module, +"load_module(name, file, filename, (suffix, mode, type)) -> module\n\ +Load a module, given information returned by find_module().\n\ +The module name must include the full package name, if any."); + +PyDoc_STRVAR(doc_get_magic, +"get_magic() -> string\n\ +Return the magic number for .pyc or .pyo files."); + +PyDoc_STRVAR(doc_get_suffixes, +"get_suffixes() -> [(suffix, mode, type), ...]\n\ +Return a list of (suffix, mode, type) tuples describing the files\n\ +that find_module() looks for."); + +PyDoc_STRVAR(doc_new_module, +"new_module(name) -> module\n\ +Create a new module. Do not enter it in sys.modules.\n\ +The module name must include the full package name, if any."); + +PyDoc_STRVAR(doc_lock_held, +"lock_held() -> boolean\n\ +Return True if the import lock is currently held, else False.\n\ +On platforms without threads, return False."); + +PyDoc_STRVAR(doc_acquire_lock, +"acquire_lock() -> None\n\ +Acquires the interpreter's import lock for the current thread.\n\ +This lock should be used by import hooks to ensure thread-safety\n\ +when importing modules.\n\ +On platforms without threads, this function does nothing."); + +PyDoc_STRVAR(doc_release_lock, +"release_lock() -> None\n\ +Release the interpreter's import lock.\n\ +On platforms without threads, this function does nothing."); + +static PyMethodDef imp_methods[] = { + {"find_module", imp_find_module, METH_VARARGS, doc_find_module}, + {"get_magic", imp_get_magic, METH_NOARGS, doc_get_magic}, + {"get_suffixes", imp_get_suffixes, METH_NOARGS, doc_get_suffixes}, + {"load_module", imp_load_module, METH_VARARGS, doc_load_module}, + {"new_module", imp_new_module, METH_VARARGS, doc_new_module}, + {"lock_held", imp_lock_held, METH_NOARGS, doc_lock_held}, + {"acquire_lock", imp_acquire_lock, METH_NOARGS, doc_acquire_lock}, + {"release_lock", imp_release_lock, METH_NOARGS, doc_release_lock}, + /* The rest are obsolete */ + {"get_frozen_object", imp_get_frozen_object, METH_VARARGS}, + {"init_builtin", imp_init_builtin, METH_VARARGS}, + {"init_frozen", imp_init_frozen, METH_VARARGS}, + {"is_builtin", imp_is_builtin, METH_VARARGS}, + {"is_frozen", imp_is_frozen, METH_VARARGS}, + {"load_compiled", imp_load_compiled, METH_VARARGS}, +#ifdef HAVE_DYNAMIC_LOADING + {"load_dynamic", imp_load_dynamic, METH_VARARGS}, +#endif + {"load_package", imp_load_package, METH_VARARGS}, + {"load_source", imp_load_source, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +static int +setint(PyObject *d, char *name, int value) +{ + PyObject *v; + int err; + + v = PyInt_FromLong((long)value); + err = PyDict_SetItemString(d, name, v); + Py_XDECREF(v); + return err; +} + +typedef struct { + PyObject_HEAD +} NullImporter; + +static int +NullImporter_init(NullImporter *self, PyObject *args, PyObject *kwds) +{ + char *path; + + if (!_PyArg_NoKeywords("NullImporter()", kwds)) + return -1; + + if (!PyArg_ParseTuple(args, "s:NullImporter", + &path)) + return -1; + + if (strlen(path) == 0) { + PyErr_SetString(PyExc_ImportError, "empty pathname"); + return -1; + } else { +#ifndef RISCOS + struct stat statbuf; + int rv; + + rv = stat(path, &statbuf); + if (rv == 0) { + /* it exists */ + if (S_ISDIR(statbuf.st_mode)) { + /* it's a directory */ + PyErr_SetString(PyExc_ImportError, + "existing directory"); + return -1; + } + } +#else + if (object_exists(path)) { + /* it exists */ + if (isdir(path)) { + /* it's a directory */ + PyErr_SetString(PyExc_ImportError, + "existing directory"); + return -1; + } + } +#endif + } + return 0; +} + +static PyObject * +NullImporter_find_module(NullImporter *self, PyObject *args) +{ + Py_RETURN_NONE; +} + +static PyMethodDef NullImporter_methods[] = { + {"find_module", (PyCFunction)NullImporter_find_module, METH_VARARGS, + "Always return None" + }, + {NULL} /* Sentinel */ +}; + + +static PyTypeObject NullImporterType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "imp.NullImporter", /*tp_name*/ + sizeof(NullImporter), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + 0, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + "Null importer object", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + NullImporter_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)NullImporter_init, /* tp_init */ + 0, /* tp_alloc */ + PyType_GenericNew /* tp_new */ +}; + + +PyMODINIT_FUNC +initimp(void) +{ + PyObject *m, *d; + + if (PyType_Ready(&NullImporterType) < 0) + goto failure; + + m = Py_InitModule4("imp", imp_methods, doc_imp, + NULL, PYTHON_API_VERSION); + if (m == NULL) + goto failure; + d = PyModule_GetDict(m); + if (d == NULL) + goto failure; + + if (setint(d, "SEARCH_ERROR", SEARCH_ERROR) < 0) goto failure; + if (setint(d, "PY_SOURCE", PY_SOURCE) < 0) goto failure; + if (setint(d, "PY_COMPILED", PY_COMPILED) < 0) goto failure; + if (setint(d, "C_EXTENSION", C_EXTENSION) < 0) goto failure; + if (setint(d, "PY_RESOURCE", PY_RESOURCE) < 0) goto failure; + if (setint(d, "PKG_DIRECTORY", PKG_DIRECTORY) < 0) goto failure; + if (setint(d, "C_BUILTIN", C_BUILTIN) < 0) goto failure; + if (setint(d, "PY_FROZEN", PY_FROZEN) < 0) goto failure; + if (setint(d, "PY_CODERESOURCE", PY_CODERESOURCE) < 0) goto failure; + if (setint(d, "IMP_HOOK", IMP_HOOK) < 0) goto failure; + + Py_INCREF(&NullImporterType); + PyModule_AddObject(m, "NullImporter", (PyObject *)&NullImporterType); + failure: + ; +} + + +/* API for embedding applications that want to add their own entries + to the table of built-in modules. This should normally be called + *before* Py_Initialize(). When the table resize fails, -1 is + returned and the existing table is unchanged. + + After a similar function by Just van Rossum. */ + +int +PyImport_ExtendInittab(struct _inittab *newtab) +{ + static struct _inittab *our_copy = NULL; + struct _inittab *p; + int i, n; + + /* Count the number of entries in both tables */ + for (n = 0; newtab[n].name != NULL; n++) + ; + if (n == 0) + return 0; /* Nothing to do */ + for (i = 0; PyImport_Inittab[i].name != NULL; i++) + ; + + /* Allocate new memory for the combined table */ + p = our_copy; + PyMem_RESIZE(p, struct _inittab, i+n+1); + if (p == NULL) + return -1; + + /* Copy the tables into the new memory */ + if (our_copy != PyImport_Inittab) + memcpy(p, PyImport_Inittab, (i+1) * sizeof(struct _inittab)); + PyImport_Inittab = our_copy = p; + memcpy(p+i, newtab, (n+1) * sizeof(struct _inittab)); + + return 0; +} + +/* Shorthand to add a single entry given a name and a function */ + +int +PyImport_AppendInittab(char *name, void (*initfunc)(void)) +{ + struct _inittab newtab[2]; + + memset(newtab, '\0', sizeof newtab); + + newtab[0].name = name; + newtab[0].initfunc = initfunc; + + return PyImport_ExtendInittab(newtab); +} + +#ifdef __cplusplus +} +#endif diff --git a/sys/src/cmd/python/Python/importdl.c b/sys/src/cmd/python/Python/importdl.c new file mode 100644 index 000000000..9c325e447 --- /dev/null +++ b/sys/src/cmd/python/Python/importdl.c @@ -0,0 +1,78 @@ + +/* Support for dynamic loading of extension modules */ + +#include "Python.h" + +/* ./configure sets HAVE_DYNAMIC_LOADING if dynamic loading of modules is + supported on this platform. configure will then compile and link in one + of the dynload_*.c files, as appropriate. We will call a function in + those modules to get a function pointer to the module's init function. +*/ +#ifdef HAVE_DYNAMIC_LOADING + +#include "importdl.h" + +extern dl_funcptr _PyImport_GetDynLoadFunc(const char *name, + const char *shortname, + const char *pathname, FILE *fp); + + + +PyObject * +_PyImport_LoadDynamicModule(char *name, char *pathname, FILE *fp) +{ + PyObject *m; + char *lastdot, *shortname, *packagecontext, *oldcontext; + dl_funcptr p; + + if ((m = _PyImport_FindExtension(name, pathname)) != NULL) { + Py_INCREF(m); + return m; + } + lastdot = strrchr(name, '.'); + if (lastdot == NULL) { + packagecontext = NULL; + shortname = name; + } + else { + packagecontext = name; + shortname = lastdot+1; + } + + p = _PyImport_GetDynLoadFunc(name, shortname, pathname, fp); + if (PyErr_Occurred()) + return NULL; + if (p == NULL) { + PyErr_Format(PyExc_ImportError, + "dynamic module does not define init function (init%.200s)", + shortname); + return NULL; + } + oldcontext = _Py_PackageContext; + _Py_PackageContext = packagecontext; + (*p)(); + _Py_PackageContext = oldcontext; + if (PyErr_Occurred()) + return NULL; + + m = PyDict_GetItemString(PyImport_GetModuleDict(), name); + if (m == NULL) { + PyErr_SetString(PyExc_SystemError, + "dynamic module not initialized properly"); + return NULL; + } + /* Remember the filename as the __file__ attribute */ + if (PyModule_AddStringConstant(m, "__file__", pathname) < 0) + PyErr_Clear(); /* Not important enough to report */ + + if (_PyImport_FixupExtension(name, pathname) == NULL) + return NULL; + if (Py_VerboseFlag) + PySys_WriteStderr( + "import %s # dynamically loaded from %s\n", + name, pathname); + Py_INCREF(m); + return m; +} + +#endif /* HAVE_DYNAMIC_LOADING */ diff --git a/sys/src/cmd/python/Python/importdl.h b/sys/src/cmd/python/Python/importdl.h new file mode 100644 index 000000000..5a2d45c46 --- /dev/null +++ b/sys/src/cmd/python/Python/importdl.h @@ -0,0 +1,53 @@ +#ifndef Py_IMPORTDL_H +#define Py_IMPORTDL_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Definitions for dynamic loading of extension modules */ +enum filetype { + SEARCH_ERROR, + PY_SOURCE, + PY_COMPILED, + C_EXTENSION, + PY_RESOURCE, /* Mac only */ + PKG_DIRECTORY, + C_BUILTIN, + PY_FROZEN, + PY_CODERESOURCE, /* Mac only */ + IMP_HOOK +}; + +struct filedescr { + char *suffix; + char *mode; + enum filetype type; +}; +extern struct filedescr * _PyImport_Filetab; +extern const struct filedescr _PyImport_DynLoadFiletab[]; + +extern PyObject *_PyImport_LoadDynamicModule(char *name, char *pathname, + FILE *); + +/* Max length of module suffix searched for -- accommodates "module.slb" */ +#define MAXSUFFIXSIZE 12 + +#ifdef MS_WINDOWS +#include <windows.h> +typedef FARPROC dl_funcptr; +#else +#if defined(PYOS_OS2) && !defined(PYCC_GCC) +#include <os2def.h> +typedef int (* APIENTRY dl_funcptr)(); +#else +typedef void (*dl_funcptr)(void); +#endif +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* !Py_IMPORTDL_H */ diff --git a/sys/src/cmd/python/Python/mactoolboxglue.c b/sys/src/cmd/python/Python/mactoolboxglue.c new file mode 100644 index 000000000..26a13083f --- /dev/null +++ b/sys/src/cmd/python/Python/mactoolboxglue.c @@ -0,0 +1,470 @@ +/*********************************************************** +Copyright 1991-1997 by Stichting Mathematisch Centrum, Amsterdam, +The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + + +#include "Python.h" +#include "pymactoolbox.h" +#include <arpa/inet.h> /* for ntohl, htonl */ + + +/* Like strerror() but for Mac OS error numbers */ +char * +PyMac_StrError(int err) +{ + static char buf[256]; + PyObject *m; + PyObject *rv; + + m = PyImport_ImportModule("MacOS"); + if (!m) { + if (Py_VerboseFlag) + PyErr_Print(); + PyErr_Clear(); + rv = NULL; + } + else { + rv = PyObject_CallMethod(m, "GetErrorString", "i", err); + if (!rv) + PyErr_Clear(); + } + if (!rv) { + buf[0] = '\0'; + } + else { + char *input = PyString_AsString(rv); + if (!input) { + PyErr_Clear(); + buf[0] = '\0'; + } else { + strncpy(buf, input, sizeof(buf) - 1); + buf[sizeof(buf) - 1] = '\0'; + } + Py_DECREF(rv); + } + Py_XDECREF(m); + return buf; +} + +/* Exception object shared by all Mac specific modules for Mac OS errors */ +PyObject *PyMac_OSErrException; + +/* Initialize and return PyMac_OSErrException */ +PyObject * +PyMac_GetOSErrException(void) +{ + if (PyMac_OSErrException == NULL) + PyMac_OSErrException = PyErr_NewException("MacOS.Error", NULL, NULL); + return PyMac_OSErrException; +} + +/* Set a MAC-specific error from errno, and return NULL; return None if no error */ +PyObject * +PyErr_Mac(PyObject *eobj, int err) +{ + char *msg; + PyObject *v; + + if (err == 0 && !PyErr_Occurred()) { + Py_INCREF(Py_None); + return Py_None; + } + if (err == -1 && PyErr_Occurred()) + return NULL; + msg = PyMac_StrError(err); + v = Py_BuildValue("(is)", err, msg); + PyErr_SetObject(eobj, v); + Py_DECREF(v); + return NULL; +} + +/* Call PyErr_Mac with PyMac_OSErrException */ +PyObject * +PyMac_Error(OSErr err) +{ + return PyErr_Mac(PyMac_GetOSErrException(), err); +} + + +OSErr +PyMac_GetFullPathname(FSSpec *fss, char *path, int len) +{ + PyObject *fs, *exc; + PyObject *rv = NULL; + char *input; + OSErr err = noErr; + + *path = '\0'; + + fs = PyMac_BuildFSSpec(fss); + if (!fs) + goto error; + + rv = PyObject_CallMethod(fs, "as_pathname", ""); + if (!rv) + goto error; + + input = PyString_AsString(rv); + if (!input) + goto error; + + strncpy(path, input, len - 1); + path[len - 1] = '\0'; + + Py_XDECREF(rv); + Py_XDECREF(fs); + return err; + + error: + exc = PyErr_Occurred(); + if (exc && PyErr_GivenExceptionMatches(exc, + PyMac_GetOSErrException())) { + PyObject *args = PyObject_GetAttrString(exc, "args"); + if (args) { + char *ignore; + PyArg_ParseTuple(args, "is", &err, &ignore); + Py_XDECREF(args); + } + } + if (err == noErr) + err = -1; + PyErr_Clear(); + Py_XDECREF(rv); + Py_XDECREF(fs); + return err; +} + +/* Convert a 4-char string object argument to an OSType value */ +int +PyMac_GetOSType(PyObject *v, OSType *pr) +{ + uint32_t tmp; + if (!PyString_Check(v) || PyString_Size(v) != 4) { + PyErr_SetString(PyExc_TypeError, + "OSType arg must be string of 4 chars"); + return 0; + } + memcpy((char *)&tmp, PyString_AsString(v), 4); + *pr = (OSType)ntohl(tmp); + return 1; +} + +/* Convert an OSType value to a 4-char string object */ +PyObject * +PyMac_BuildOSType(OSType t) +{ + uint32_t tmp = htonl((uint32_t)t); + return PyString_FromStringAndSize((char *)&tmp, 4); +} + +/* Convert an NumVersion value to a 4-element tuple */ +PyObject * +PyMac_BuildNumVersion(NumVersion t) +{ + return Py_BuildValue("(hhhh)", t.majorRev, t.minorAndBugRev, t.stage, t.nonRelRev); +} + + +/* Convert a Python string object to a Str255 */ +int +PyMac_GetStr255(PyObject *v, Str255 pbuf) +{ + int len; + if (!PyString_Check(v) || (len = PyString_Size(v)) > 255) { + PyErr_SetString(PyExc_TypeError, + "Str255 arg must be string of at most 255 chars"); + return 0; + } + pbuf[0] = len; + memcpy((char *)(pbuf+1), PyString_AsString(v), len); + return 1; +} + +/* Convert a Str255 to a Python string object */ +PyObject * +PyMac_BuildStr255(Str255 s) +{ + if ( s == NULL ) { + PyErr_SetString(PyExc_SystemError, "Str255 pointer is NULL"); + return NULL; + } + return PyString_FromStringAndSize((char *)&s[1], (int)s[0]); +} + +PyObject * +PyMac_BuildOptStr255(Str255 s) +{ + if ( s == NULL ) { + Py_INCREF(Py_None); + return Py_None; + } + return PyString_FromStringAndSize((char *)&s[1], (int)s[0]); +} + + + +/* Convert a Python object to a Rect. + The object must be a (left, top, right, bottom) tuple. + (This differs from the order in the struct but is consistent with + the arguments to SetRect(), and also with STDWIN). */ +int +PyMac_GetRect(PyObject *v, Rect *r) +{ + return PyArg_Parse(v, "(hhhh)", &r->left, &r->top, &r->right, &r->bottom); +} + +/* Convert a Rect to a Python object */ +PyObject * +PyMac_BuildRect(Rect *r) +{ + return Py_BuildValue("(hhhh)", r->left, r->top, r->right, r->bottom); +} + + +/* Convert a Python object to a Point. + The object must be a (h, v) tuple. + (This differs from the order in the struct but is consistent with + the arguments to SetPoint(), and also with STDWIN). */ +int +PyMac_GetPoint(PyObject *v, Point *p) +{ + return PyArg_Parse(v, "(hh)", &p->h, &p->v); +} + +/* Convert a Point to a Python object */ +PyObject * +PyMac_BuildPoint(Point p) +{ + return Py_BuildValue("(hh)", p.h, p.v); +} + + +/* Convert a Python object to an EventRecord. + The object must be a (what, message, when, (v, h), modifiers) tuple. */ +int +PyMac_GetEventRecord(PyObject *v, EventRecord *e) +{ + return PyArg_Parse(v, "(Hkk(hh)H)", + &e->what, + &e->message, + &e->when, + &e->where.h, + &e->where.v, + &e->modifiers); +} + +/* Convert a Rect to an EventRecord object */ +PyObject * +PyMac_BuildEventRecord(EventRecord *e) +{ + return Py_BuildValue("(hll(hh)h)", + e->what, + e->message, + e->when, + e->where.h, + e->where.v, + e->modifiers); +} + +/* Convert Python object to Fixed */ +int +PyMac_GetFixed(PyObject *v, Fixed *f) +{ + double d; + + if( !PyArg_Parse(v, "d", &d)) + return 0; + *f = (Fixed)(d * 0x10000); + return 1; +} + +/* Convert a Fixed to a Python object */ +PyObject * +PyMac_BuildFixed(Fixed f) +{ + double d; + + d = f; + d = d / 0x10000; + return Py_BuildValue("d", d); +} + +/* Convert wide to/from Python int or (hi, lo) tuple. XXXX Should use Python longs */ +int +PyMac_Getwide(PyObject *v, wide *rv) +{ + if (PyInt_Check(v)) { + rv->hi = 0; + rv->lo = PyInt_AsLong(v); + if( rv->lo & 0x80000000 ) + rv->hi = -1; + return 1; + } + return PyArg_Parse(v, "(kk)", &rv->hi, &rv->lo); +} + + +PyObject * +PyMac_Buildwide(wide *w) +{ + if ( (w->hi == 0 && (w->lo & 0x80000000) == 0) || + (w->hi == -1 && (w->lo & 0x80000000) ) ) + return PyInt_FromLong(w->lo); + return Py_BuildValue("(ll)", w->hi, w->lo); +} + +#ifdef USE_TOOLBOX_OBJECT_GLUE +/* +** Glue together the toolbox objects. +** +** Because toolbox modules interdepend on each other, they use each others +** object types, on MacOSX/MachO this leads to the situation that they +** cannot be dynamically loaded (or they would all have to be lumped into +** a single .so, but this would be bad for extensibility). +** +** This file defines wrappers for all the _New and _Convert functions, +** which are the Py_BuildValue and PyArg_ParseTuple helpers. The wrappers +** check an indirection function pointer, and if it isn't filled in yet +** they import the appropriate module, whose init routine should fill in +** the pointer. +*/ + +#define GLUE_NEW(object, routinename, module) \ +PyObject *(*PyMacGluePtr_##routinename)(object); \ +\ +PyObject *routinename(object cobj) { \ + if (!PyMacGluePtr_##routinename) { \ + if (!PyImport_ImportModule(module)) return NULL; \ + if (!PyMacGluePtr_##routinename) { \ + PyErr_SetString(PyExc_ImportError, "Module did not provide routine: " module ": " #routinename); \ + return NULL; \ + } \ + } \ + return (*PyMacGluePtr_##routinename)(cobj); \ +} + +#define GLUE_CONVERT(object, routinename, module) \ +int (*PyMacGluePtr_##routinename)(PyObject *, object *); \ +\ +int routinename(PyObject *pyobj, object *cobj) { \ + if (!PyMacGluePtr_##routinename) { \ + if (!PyImport_ImportModule(module)) return 0; \ + if (!PyMacGluePtr_##routinename) { \ + PyErr_SetString(PyExc_ImportError, "Module did not provide routine: " module ": " #routinename); \ + return 0; \ + } \ + } \ + return (*PyMacGluePtr_##routinename)(pyobj, cobj); \ +} + +GLUE_NEW(FSSpec *, PyMac_BuildFSSpec, "Carbon.File") +GLUE_CONVERT(FSSpec, PyMac_GetFSSpec, "Carbon.File") +GLUE_NEW(FSRef *, PyMac_BuildFSRef, "Carbon.File") +GLUE_CONVERT(FSRef, PyMac_GetFSRef, "Carbon.File") + +GLUE_NEW(AppleEvent *, AEDesc_New, "Carbon.AE") /* XXXX Why by address? */ +GLUE_NEW(AppleEvent *, AEDesc_NewBorrowed, "Carbon.AE") +GLUE_CONVERT(AppleEvent, AEDesc_Convert, "Carbon.AE") + +GLUE_NEW(Component, CmpObj_New, "Carbon.Cm") +GLUE_CONVERT(Component, CmpObj_Convert, "Carbon.Cm") +GLUE_NEW(ComponentInstance, CmpInstObj_New, "Carbon.Cm") +GLUE_CONVERT(ComponentInstance, CmpInstObj_Convert, "Carbon.Cm") + +GLUE_NEW(ControlHandle, CtlObj_New, "Carbon.Ctl") +GLUE_CONVERT(ControlHandle, CtlObj_Convert, "Carbon.Ctl") + +GLUE_NEW(DialogPtr, DlgObj_New, "Carbon.Dlg") +GLUE_CONVERT(DialogPtr, DlgObj_Convert, "Carbon.Dlg") +GLUE_NEW(DialogPtr, DlgObj_WhichDialog, "Carbon.Dlg") + +GLUE_NEW(DragReference, DragObj_New, "Carbon.Drag") +GLUE_CONVERT(DragReference, DragObj_Convert, "Carbon.Drag") + +GLUE_NEW(ListHandle, ListObj_New, "Carbon.List") +GLUE_CONVERT(ListHandle, ListObj_Convert, "Carbon.List") + +GLUE_NEW(MenuHandle, MenuObj_New, "Carbon.Menu") +GLUE_CONVERT(MenuHandle, MenuObj_Convert, "Carbon.Menu") + +GLUE_NEW(GrafPtr, GrafObj_New, "Carbon.Qd") +GLUE_CONVERT(GrafPtr, GrafObj_Convert, "Carbon.Qd") +GLUE_NEW(BitMapPtr, BMObj_New, "Carbon.Qd") +GLUE_CONVERT(BitMapPtr, BMObj_Convert, "Carbon.Qd") +GLUE_NEW(RGBColor *, QdRGB_New, "Carbon.Qd") /* XXXX Why? */ +GLUE_CONVERT(RGBColor, QdRGB_Convert, "Carbon.Qd") + +GLUE_NEW(GWorldPtr, GWorldObj_New, "Carbon.Qdoffs") +GLUE_CONVERT(GWorldPtr, GWorldObj_Convert, "Carbon.Qdoffs") + +GLUE_NEW(Track, TrackObj_New, "Carbon.Qt") +GLUE_CONVERT(Track, TrackObj_Convert, "Carbon.Qt") +GLUE_NEW(Movie, MovieObj_New, "Carbon.Qt") +GLUE_CONVERT(Movie, MovieObj_Convert, "Carbon.Qt") +GLUE_NEW(MovieController, MovieCtlObj_New, "Carbon.Qt") +GLUE_CONVERT(MovieController, MovieCtlObj_Convert, "Carbon.Qt") +GLUE_NEW(TimeBase, TimeBaseObj_New, "Carbon.Qt") +GLUE_CONVERT(TimeBase, TimeBaseObj_Convert, "Carbon.Qt") +GLUE_NEW(UserData, UserDataObj_New, "Carbon.Qt") +GLUE_CONVERT(UserData, UserDataObj_Convert, "Carbon.Qt") +GLUE_NEW(Media, MediaObj_New, "Carbon.Qt") +GLUE_CONVERT(Media, MediaObj_Convert, "Carbon.Qt") + +GLUE_NEW(Handle, ResObj_New, "Carbon.Res") +GLUE_CONVERT(Handle, ResObj_Convert, "Carbon.Res") +GLUE_NEW(Handle, OptResObj_New, "Carbon.Res") +GLUE_CONVERT(Handle, OptResObj_Convert, "Carbon.Res") + +GLUE_NEW(TEHandle, TEObj_New, "Carbon.TE") +GLUE_CONVERT(TEHandle, TEObj_Convert, "Carbon.TE") + +GLUE_NEW(WindowPtr, WinObj_New, "Carbon.Win") +GLUE_CONVERT(WindowPtr, WinObj_Convert, "Carbon.Win") +GLUE_NEW(WindowPtr, WinObj_WhichWindow, "Carbon.Win") + +GLUE_CONVERT(CFTypeRef, CFObj_Convert, "Carbon.CF") +GLUE_NEW(CFTypeRef, CFObj_New, "Carbon.CF") + +GLUE_CONVERT(CFTypeRef, CFTypeRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFTypeRef, CFTypeRefObj_New, "Carbon.CF") + +GLUE_CONVERT(CFStringRef, CFStringRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFStringRef, CFStringRefObj_New, "Carbon.CF") +GLUE_CONVERT(CFMutableStringRef, CFMutableStringRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFMutableStringRef, CFMutableStringRefObj_New, "Carbon.CF") + +GLUE_CONVERT(CFArrayRef, CFArrayRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFArrayRef, CFArrayRefObj_New, "Carbon.CF") +GLUE_CONVERT(CFMutableArrayRef, CFMutableArrayRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFMutableArrayRef, CFMutableArrayRefObj_New, "Carbon.CF") + +GLUE_CONVERT(CFDictionaryRef, CFDictionaryRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFDictionaryRef, CFDictionaryRefObj_New, "Carbon.CF") +GLUE_CONVERT(CFMutableDictionaryRef, CFMutableDictionaryRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFMutableDictionaryRef, CFMutableDictionaryRefObj_New, "Carbon.CF") + +GLUE_CONVERT(CFURLRef, CFURLRefObj_Convert, "Carbon.CF") +GLUE_CONVERT(CFURLRef, OptionalCFURLRefObj_Convert, "Carbon.CF") +GLUE_NEW(CFURLRef, CFURLRefObj_New, "Carbon.CF") + +#endif /* USE_TOOLBOX_OBJECT_GLUE */ diff --git a/sys/src/cmd/python/Python/marshal.c b/sys/src/cmd/python/Python/marshal.c new file mode 100644 index 000000000..776836e55 --- /dev/null +++ b/sys/src/cmd/python/Python/marshal.c @@ -0,0 +1,1155 @@ + +/* Write Python objects to files and read them back. + This is intended for writing and reading compiled Python code only; + a true persistent storage facility would be much harder, since + it would have to take circular links and sharing into account. */ + +#define PY_SSIZE_T_CLEAN + +#include "Python.h" +#include "longintrepr.h" +#include "code.h" +#include "marshal.h" + +/* High water mark to determine when the marshalled object is dangerously deep + * and risks coring the interpreter. When the object stack gets this deep, + * raise an exception instead of continuing. + */ +#define MAX_MARSHAL_STACK_DEPTH 5000 + +#define TYPE_NULL '0' +#define TYPE_NONE 'N' +#define TYPE_FALSE 'F' +#define TYPE_TRUE 'T' +#define TYPE_STOPITER 'S' +#define TYPE_ELLIPSIS '.' +#define TYPE_INT 'i' +#define TYPE_INT64 'I' +#define TYPE_FLOAT 'f' +#define TYPE_BINARY_FLOAT 'g' +#define TYPE_COMPLEX 'x' +#define TYPE_BINARY_COMPLEX 'y' +#define TYPE_LONG 'l' +#define TYPE_STRING 's' +#define TYPE_INTERNED 't' +#define TYPE_STRINGREF 'R' +#define TYPE_TUPLE '(' +#define TYPE_LIST '[' +#define TYPE_DICT '{' +#define TYPE_CODE 'c' +#define TYPE_UNICODE 'u' +#define TYPE_UNKNOWN '?' +#define TYPE_SET '<' +#define TYPE_FROZENSET '>' + +typedef struct { + FILE *fp; + int error; + int depth; + /* If fp == NULL, the following are valid: */ + PyObject *str; + char *ptr; + char *end; + PyObject *strings; /* dict on marshal, list on unmarshal */ + int version; +} WFILE; + +#define w_byte(c, p) if (((p)->fp)) putc((c), (p)->fp); \ + else if ((p)->ptr != (p)->end) *(p)->ptr++ = (c); \ + else w_more(c, p) + +static void +w_more(int c, WFILE *p) +{ + Py_ssize_t size, newsize; + if (p->str == NULL) + return; /* An error already occurred */ + size = PyString_Size(p->str); + newsize = size + 1024; + if (_PyString_Resize(&p->str, newsize) != 0) { + p->ptr = p->end = NULL; + } + else { + p->ptr = PyString_AS_STRING((PyStringObject *)p->str) + size; + p->end = + PyString_AS_STRING((PyStringObject *)p->str) + newsize; + *p->ptr++ = Py_SAFE_DOWNCAST(c, int, char); + } +} + +static void +w_string(char *s, int n, WFILE *p) +{ + if (p->fp != NULL) { + fwrite(s, 1, n, p->fp); + } + else { + while (--n >= 0) { + w_byte(*s, p); + s++; + } + } +} + +static void +w_short(int x, WFILE *p) +{ + w_byte((char)( x & 0xff), p); + w_byte((char)((x>> 8) & 0xff), p); +} + +static void +w_long(long x, WFILE *p) +{ + w_byte((char)( x & 0xff), p); + w_byte((char)((x>> 8) & 0xff), p); + w_byte((char)((x>>16) & 0xff), p); + w_byte((char)((x>>24) & 0xff), p); +} + +#if SIZEOF_LONG > 4 +static void +w_long64(long x, WFILE *p) +{ + w_long(x, p); + w_long(x>>32, p); +} +#endif + +static void +w_object(PyObject *v, WFILE *p) +{ + Py_ssize_t i, n; + + p->depth++; + + if (p->depth > MAX_MARSHAL_STACK_DEPTH) { + p->error = 2; + } + else if (v == NULL) { + w_byte(TYPE_NULL, p); + } + else if (v == Py_None) { + w_byte(TYPE_NONE, p); + } + else if (v == PyExc_StopIteration) { + w_byte(TYPE_STOPITER, p); + } + else if (v == Py_Ellipsis) { + w_byte(TYPE_ELLIPSIS, p); + } + else if (v == Py_False) { + w_byte(TYPE_FALSE, p); + } + else if (v == Py_True) { + w_byte(TYPE_TRUE, p); + } + else if (PyInt_Check(v)) { + long x = PyInt_AS_LONG((PyIntObject *)v); +#if SIZEOF_LONG > 4 + long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31); + if (y && y != -1) { + w_byte(TYPE_INT64, p); + w_long64(x, p); + } + else +#endif + { + w_byte(TYPE_INT, p); + w_long(x, p); + } + } + else if (PyLong_Check(v)) { + PyLongObject *ob = (PyLongObject *)v; + w_byte(TYPE_LONG, p); + n = ob->ob_size; + w_long((long)n, p); + if (n < 0) + n = -n; + for (i = 0; i < n; i++) + w_short(ob->ob_digit[i], p); + } + else if (PyFloat_Check(v)) { + if (p->version > 1) { + unsigned char buf[8]; + if (_PyFloat_Pack8(PyFloat_AsDouble(v), + buf, 1) < 0) { + p->error = 1; + return; + } + w_byte(TYPE_BINARY_FLOAT, p); + w_string((char*)buf, 8, p); + } + else { + char buf[256]; /* Plenty to format any double */ + PyFloat_AsReprString(buf, (PyFloatObject *)v); + n = strlen(buf); + w_byte(TYPE_FLOAT, p); + w_byte((int)n, p); + w_string(buf, (int)n, p); + } + } +#ifndef WITHOUT_COMPLEX + else if (PyComplex_Check(v)) { + if (p->version > 1) { + unsigned char buf[8]; + if (_PyFloat_Pack8(PyComplex_RealAsDouble(v), + buf, 1) < 0) { + p->error = 1; + return; + } + w_byte(TYPE_BINARY_COMPLEX, p); + w_string((char*)buf, 8, p); + if (_PyFloat_Pack8(PyComplex_ImagAsDouble(v), + buf, 1) < 0) { + p->error = 1; + return; + } + w_string((char*)buf, 8, p); + } + else { + char buf[256]; /* Plenty to format any double */ + PyFloatObject *temp; + w_byte(TYPE_COMPLEX, p); + temp = (PyFloatObject*)PyFloat_FromDouble( + PyComplex_RealAsDouble(v)); + if (!temp) { + p->error = 1; + return; + } + PyFloat_AsReprString(buf, temp); + Py_DECREF(temp); + n = strlen(buf); + w_byte((int)n, p); + w_string(buf, (int)n, p); + temp = (PyFloatObject*)PyFloat_FromDouble( + PyComplex_ImagAsDouble(v)); + if (!temp) { + p->error = 1; + return; + } + PyFloat_AsReprString(buf, temp); + Py_DECREF(temp); + n = strlen(buf); + w_byte((int)n, p); + w_string(buf, (int)n, p); + } + } +#endif + else if (PyString_Check(v)) { + if (p->strings && PyString_CHECK_INTERNED(v)) { + PyObject *o = PyDict_GetItem(p->strings, v); + if (o) { + long w = PyInt_AsLong(o); + w_byte(TYPE_STRINGREF, p); + w_long(w, p); + goto exit; + } + else { + o = PyInt_FromSsize_t(PyDict_Size(p->strings)); + PyDict_SetItem(p->strings, v, o); + Py_DECREF(o); + w_byte(TYPE_INTERNED, p); + } + } + else { + w_byte(TYPE_STRING, p); + } + n = PyString_GET_SIZE(v); + if (n > INT_MAX) { + /* huge strings are not supported */ + p->depth--; + p->error = 1; + return; + } + w_long((long)n, p); + w_string(PyString_AS_STRING(v), (int)n, p); + } +#ifdef Py_USING_UNICODE + else if (PyUnicode_Check(v)) { + PyObject *utf8; + utf8 = PyUnicode_AsUTF8String(v); + if (utf8 == NULL) { + p->depth--; + p->error = 1; + return; + } + w_byte(TYPE_UNICODE, p); + n = PyString_GET_SIZE(utf8); + if (n > INT_MAX) { + p->depth--; + p->error = 1; + return; + } + w_long((long)n, p); + w_string(PyString_AS_STRING(utf8), (int)n, p); + Py_DECREF(utf8); + } +#endif + else if (PyTuple_Check(v)) { + w_byte(TYPE_TUPLE, p); + n = PyTuple_Size(v); + w_long((long)n, p); + for (i = 0; i < n; i++) { + w_object(PyTuple_GET_ITEM(v, i), p); + } + } + else if (PyList_Check(v)) { + w_byte(TYPE_LIST, p); + n = PyList_GET_SIZE(v); + w_long((long)n, p); + for (i = 0; i < n; i++) { + w_object(PyList_GET_ITEM(v, i), p); + } + } + else if (PyDict_Check(v)) { + Py_ssize_t pos; + PyObject *key, *value; + w_byte(TYPE_DICT, p); + /* This one is NULL object terminated! */ + pos = 0; + while (PyDict_Next(v, &pos, &key, &value)) { + w_object(key, p); + w_object(value, p); + } + w_object((PyObject *)NULL, p); + } + else if (PyAnySet_Check(v)) { + PyObject *value, *it; + + if (PyObject_TypeCheck(v, &PySet_Type)) + w_byte(TYPE_SET, p); + else + w_byte(TYPE_FROZENSET, p); + n = PyObject_Size(v); + if (n == -1) { + p->depth--; + p->error = 1; + return; + } + w_long((long)n, p); + it = PyObject_GetIter(v); + if (it == NULL) { + p->depth--; + p->error = 1; + return; + } + while ((value = PyIter_Next(it)) != NULL) { + w_object(value, p); + Py_DECREF(value); + } + Py_DECREF(it); + if (PyErr_Occurred()) { + p->depth--; + p->error = 1; + return; + } + } + else if (PyCode_Check(v)) { + PyCodeObject *co = (PyCodeObject *)v; + w_byte(TYPE_CODE, p); + w_long(co->co_argcount, p); + w_long(co->co_nlocals, p); + w_long(co->co_stacksize, p); + w_long(co->co_flags, p); + w_object(co->co_code, p); + w_object(co->co_consts, p); + w_object(co->co_names, p); + w_object(co->co_varnames, p); + w_object(co->co_freevars, p); + w_object(co->co_cellvars, p); + w_object(co->co_filename, p); + w_object(co->co_name, p); + w_long(co->co_firstlineno, p); + w_object(co->co_lnotab, p); + } + else if (PyObject_CheckReadBuffer(v)) { + /* Write unknown buffer-style objects as a string */ + char *s; + PyBufferProcs *pb = v->ob_type->tp_as_buffer; + w_byte(TYPE_STRING, p); + n = (*pb->bf_getreadbuffer)(v, 0, (void **)&s); + if (n > INT_MAX) { + p->depth--; + p->error = 1; + return; + } + w_long((long)n, p); + w_string(s, (int)n, p); + } + else { + w_byte(TYPE_UNKNOWN, p); + p->error = 1; + } + exit: + p->depth--; +} + +/* version currently has no effect for writing longs. */ +void +PyMarshal_WriteLongToFile(long x, FILE *fp, int version) +{ + WFILE wf; + wf.fp = fp; + wf.error = 0; + wf.depth = 0; + wf.strings = NULL; + wf.version = version; + w_long(x, &wf); +} + +void +PyMarshal_WriteObjectToFile(PyObject *x, FILE *fp, int version) +{ + WFILE wf; + wf.fp = fp; + wf.error = 0; + wf.depth = 0; + wf.strings = (version > 0) ? PyDict_New() : NULL; + wf.version = version; + w_object(x, &wf); + Py_XDECREF(wf.strings); +} + +typedef WFILE RFILE; /* Same struct with different invariants */ + +#define rs_byte(p) (((p)->ptr != (p)->end) ? (unsigned char)*(p)->ptr++ : EOF) + +#define r_byte(p) ((p)->fp ? getc((p)->fp) : rs_byte(p)) + +static int +r_string(char *s, int n, RFILE *p) +{ + if (p->fp != NULL) + /* The result fits into int because it must be <=n. */ + return (int)fread(s, 1, n, p->fp); + if (p->end - p->ptr < n) + n = (int)(p->end - p->ptr); + memcpy(s, p->ptr, n); + p->ptr += n; + return n; +} + +static int +r_short(RFILE *p) +{ + register short x; + x = r_byte(p); + x |= r_byte(p) << 8; + /* Sign-extension, in case short greater than 16 bits */ + x |= -(x & 0x8000); + return x; +} + +static long +r_long(RFILE *p) +{ + register long x; + register FILE *fp = p->fp; + if (fp) { + x = getc(fp); + x |= (long)getc(fp) << 8; + x |= (long)getc(fp) << 16; + x |= (long)getc(fp) << 24; + } + else { + x = rs_byte(p); + x |= (long)rs_byte(p) << 8; + x |= (long)rs_byte(p) << 16; + x |= (long)rs_byte(p) << 24; + } +#if SIZEOF_LONG > 4 + /* Sign extension for 64-bit machines */ + x |= -(x & 0x80000000L); +#endif + return x; +} + +/* r_long64 deals with the TYPE_INT64 code. On a machine with + sizeof(long) > 4, it returns a Python int object, else a Python long + object. Note that w_long64 writes out TYPE_INT if 32 bits is enough, + so there's no inefficiency here in returning a PyLong on 32-bit boxes + for everything written via TYPE_INT64 (i.e., if an int is written via + TYPE_INT64, it *needs* more than 32 bits). +*/ +static PyObject * +r_long64(RFILE *p) +{ + long lo4 = r_long(p); + long hi4 = r_long(p); +#if SIZEOF_LONG > 4 + long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); + return PyInt_FromLong(x); +#else + unsigned char buf[8]; + int one = 1; + int is_little_endian = (int)*(char*)&one; + if (is_little_endian) { + memcpy(buf, &lo4, 4); + memcpy(buf+4, &hi4, 4); + } + else { + memcpy(buf, &hi4, 4); + memcpy(buf+4, &lo4, 4); + } + return _PyLong_FromByteArray(buf, 8, is_little_endian, 1); +#endif +} + +static PyObject * +r_object(RFILE *p) +{ + /* NULL is a valid return value, it does not necessarily means that + an exception is set. */ + PyObject *v, *v2, *v3; + long i, n; + int type = r_byte(p); + + switch (type) { + + case EOF: + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + + case TYPE_NULL: + return NULL; + + case TYPE_NONE: + Py_INCREF(Py_None); + return Py_None; + + case TYPE_STOPITER: + Py_INCREF(PyExc_StopIteration); + return PyExc_StopIteration; + + case TYPE_ELLIPSIS: + Py_INCREF(Py_Ellipsis); + return Py_Ellipsis; + + case TYPE_FALSE: + Py_INCREF(Py_False); + return Py_False; + + case TYPE_TRUE: + Py_INCREF(Py_True); + return Py_True; + + case TYPE_INT: + return PyInt_FromLong(r_long(p)); + + case TYPE_INT64: + return r_long64(p); + + case TYPE_LONG: + { + int size; + PyLongObject *ob; + n = r_long(p); + if (n < -INT_MAX || n > INT_MAX) { + PyErr_SetString(PyExc_ValueError, + "bad marshal data"); + return NULL; + } + size = n<0 ? -n : n; + ob = _PyLong_New(size); + if (ob == NULL) + return NULL; + ob->ob_size = n; + for (i = 0; i < size; i++) { + int digit = r_short(p); + if (digit < 0) { + Py_DECREF(ob); + PyErr_SetString(PyExc_ValueError, + "bad marshal data"); + return NULL; + } + ob->ob_digit[i] = digit; + } + return (PyObject *)ob; + } + + case TYPE_FLOAT: + { + char buf[256]; + double dx; + n = r_byte(p); + if (n == EOF || r_string(buf, (int)n, p) != n) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + buf[n] = '\0'; + PyFPE_START_PROTECT("atof", return 0) + dx = PyOS_ascii_atof(buf); + PyFPE_END_PROTECT(dx) + return PyFloat_FromDouble(dx); + } + + case TYPE_BINARY_FLOAT: + { + unsigned char buf[8]; + double x; + if (r_string((char*)buf, 8, p) != 8) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + x = _PyFloat_Unpack8(buf, 1); + if (x == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyFloat_FromDouble(x); + } + +#ifndef WITHOUT_COMPLEX + case TYPE_COMPLEX: + { + char buf[256]; + Py_complex c; + n = r_byte(p); + if (n == EOF || r_string(buf, (int)n, p) != n) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + buf[n] = '\0'; + PyFPE_START_PROTECT("atof", return 0) + c.real = PyOS_ascii_atof(buf); + PyFPE_END_PROTECT(c) + n = r_byte(p); + if (n == EOF || r_string(buf, (int)n, p) != n) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + buf[n] = '\0'; + PyFPE_START_PROTECT("atof", return 0) + c.imag = PyOS_ascii_atof(buf); + PyFPE_END_PROTECT(c) + return PyComplex_FromCComplex(c); + } + + case TYPE_BINARY_COMPLEX: + { + unsigned char buf[8]; + Py_complex c; + if (r_string((char*)buf, 8, p) != 8) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + c.real = _PyFloat_Unpack8(buf, 1); + if (c.real == -1.0 && PyErr_Occurred()) { + return NULL; + } + if (r_string((char*)buf, 8, p) != 8) { + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + c.imag = _PyFloat_Unpack8(buf, 1); + if (c.imag == -1.0 && PyErr_Occurred()) { + return NULL; + } + return PyComplex_FromCComplex(c); + } +#endif + + case TYPE_INTERNED: + case TYPE_STRING: + n = r_long(p); + if (n < 0 || n > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; + } + v = PyString_FromStringAndSize((char *)NULL, n); + if (v == NULL) + return v; + if (r_string(PyString_AS_STRING(v), (int)n, p) != n) { + Py_DECREF(v); + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + if (type == TYPE_INTERNED) { + PyString_InternInPlace(&v); + PyList_Append(p->strings, v); + } + return v; + + case TYPE_STRINGREF: + n = r_long(p); + if (n < 0 || n >= PyList_GET_SIZE(p->strings)) { + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; + } + v = PyList_GET_ITEM(p->strings, n); + Py_INCREF(v); + return v; + +#ifdef Py_USING_UNICODE + case TYPE_UNICODE: + { + char *buffer; + + n = r_long(p); + if (n < 0 || n > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; + } + buffer = PyMem_NEW(char, n); + if (buffer == NULL) + return PyErr_NoMemory(); + if (r_string(buffer, (int)n, p) != n) { + PyMem_DEL(buffer); + PyErr_SetString(PyExc_EOFError, + "EOF read where object expected"); + return NULL; + } + v = PyUnicode_DecodeUTF8(buffer, n, NULL); + PyMem_DEL(buffer); + return v; + } +#endif + + case TYPE_TUPLE: + n = r_long(p); + if (n < 0 || n > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; + } + v = PyTuple_New((int)n); + if (v == NULL) + return v; + for (i = 0; i < n; i++) { + v2 = r_object(p); + if ( v2 == NULL ) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, + "NULL object in marshal data"); + Py_DECREF(v); + v = NULL; + break; + } + PyTuple_SET_ITEM(v, (int)i, v2); + } + return v; + + case TYPE_LIST: + n = r_long(p); + if (n < 0 || n > INT_MAX) { + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; + } + v = PyList_New((int)n); + if (v == NULL) + return v; + for (i = 0; i < n; i++) { + v2 = r_object(p); + if ( v2 == NULL ) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, + "NULL object in marshal data"); + Py_DECREF(v); + v = NULL; + break; + } + PyList_SetItem(v, (int)i, v2); + } + return v; + + case TYPE_DICT: + v = PyDict_New(); + if (v == NULL) + return NULL; + for (;;) { + PyObject *key, *val; + key = r_object(p); + if (key == NULL) + break; + val = r_object(p); + if (val != NULL) + PyDict_SetItem(v, key, val); + Py_DECREF(key); + Py_XDECREF(val); + } + if (PyErr_Occurred()) { + Py_DECREF(v); + v = NULL; + } + return v; + + case TYPE_SET: + case TYPE_FROZENSET: + n = r_long(p); + if (n < 0) { + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; + } + v = PyTuple_New((int)n); + if (v == NULL) + return v; + for (i = 0; i < n; i++) { + v2 = r_object(p); + if ( v2 == NULL ) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, + "NULL object in marshal data"); + Py_DECREF(v); + v = NULL; + break; + } + PyTuple_SET_ITEM(v, (int)i, v2); + } + if (v == NULL) + return v; + if (type == TYPE_SET) + v3 = PySet_New(v); + else + v3 = PyFrozenSet_New(v); + Py_DECREF(v); + return v3; + + case TYPE_CODE: + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "cannot unmarshal code objects in " + "restricted execution mode"); + return NULL; + } + else { + int argcount; + int nlocals; + int stacksize; + int flags; + PyObject *code = NULL; + PyObject *consts = NULL; + PyObject *names = NULL; + PyObject *varnames = NULL; + PyObject *freevars = NULL; + PyObject *cellvars = NULL; + PyObject *filename = NULL; + PyObject *name = NULL; + int firstlineno; + PyObject *lnotab = NULL; + + v = NULL; + + /* XXX ignore long->int overflows for now */ + argcount = (int)r_long(p); + nlocals = (int)r_long(p); + stacksize = (int)r_long(p); + flags = (int)r_long(p); + code = r_object(p); + if (code == NULL) + goto code_error; + consts = r_object(p); + if (consts == NULL) + goto code_error; + names = r_object(p); + if (names == NULL) + goto code_error; + varnames = r_object(p); + if (varnames == NULL) + goto code_error; + freevars = r_object(p); + if (freevars == NULL) + goto code_error; + cellvars = r_object(p); + if (cellvars == NULL) + goto code_error; + filename = r_object(p); + if (filename == NULL) + goto code_error; + name = r_object(p); + if (name == NULL) + goto code_error; + firstlineno = (int)r_long(p); + lnotab = r_object(p); + if (lnotab == NULL) + goto code_error; + + v = (PyObject *) PyCode_New( + argcount, nlocals, stacksize, flags, + code, consts, names, varnames, + freevars, cellvars, filename, name, + firstlineno, lnotab); + + code_error: + Py_XDECREF(code); + Py_XDECREF(consts); + Py_XDECREF(names); + Py_XDECREF(varnames); + Py_XDECREF(freevars); + Py_XDECREF(cellvars); + Py_XDECREF(filename); + Py_XDECREF(name); + Py_XDECREF(lnotab); + + } + return v; + + default: + /* Bogus data got written, which isn't ideal. + This will let you keep working and recover. */ + PyErr_SetString(PyExc_ValueError, "bad marshal data"); + return NULL; + + } +} + +static PyObject * +read_object(RFILE *p) +{ + PyObject *v; + if (PyErr_Occurred()) { + fprintf(stderr, "XXX readobject called with exception set\n"); + return NULL; + } + v = r_object(p); + if (v == NULL && !PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, "NULL object in marshal data"); + return v; +} + +int +PyMarshal_ReadShortFromFile(FILE *fp) +{ + RFILE rf; + assert(fp); + rf.fp = fp; + rf.strings = NULL; + rf.end = rf.ptr = NULL; + return r_short(&rf); +} + +long +PyMarshal_ReadLongFromFile(FILE *fp) +{ + RFILE rf; + rf.fp = fp; + rf.strings = NULL; + return r_long(&rf); +} + +#ifdef HAVE_FSTAT +/* Return size of file in bytes; < 0 if unknown. */ +static off_t +getfilesize(FILE *fp) +{ + struct stat st; + if (fstat(fileno(fp), &st) != 0) + return -1; + else + return st.st_size; +} +#endif + +/* If we can get the size of the file up-front, and it's reasonably small, + * read it in one gulp and delegate to ...FromString() instead. Much quicker + * than reading a byte at a time from file; speeds .pyc imports. + * CAUTION: since this may read the entire remainder of the file, don't + * call it unless you know you're done with the file. + */ +PyObject * +PyMarshal_ReadLastObjectFromFile(FILE *fp) +{ +/* 75% of 2.1's .pyc files can exploit SMALL_FILE_LIMIT. + * REASONABLE_FILE_LIMIT is by defn something big enough for Tkinter.pyc. + */ +#define SMALL_FILE_LIMIT (1L << 14) +#define REASONABLE_FILE_LIMIT (1L << 18) +#ifdef HAVE_FSTAT + off_t filesize; +#endif +#ifdef HAVE_FSTAT + filesize = getfilesize(fp); + if (filesize > 0) { + char buf[SMALL_FILE_LIMIT]; + char* pBuf = NULL; + if (filesize <= SMALL_FILE_LIMIT) + pBuf = buf; + else if (filesize <= REASONABLE_FILE_LIMIT) + pBuf = (char *)PyMem_MALLOC(filesize); + if (pBuf != NULL) { + PyObject* v; + size_t n; + /* filesize must fit into an int, because it + is smaller than REASONABLE_FILE_LIMIT */ + n = fread(pBuf, 1, (int)filesize, fp); + v = PyMarshal_ReadObjectFromString(pBuf, n); + if (pBuf != buf) + PyMem_FREE(pBuf); + return v; + } + + } +#endif + /* We don't have fstat, or we do but the file is larger than + * REASONABLE_FILE_LIMIT or malloc failed -- read a byte at a time. + */ + return PyMarshal_ReadObjectFromFile(fp); + +#undef SMALL_FILE_LIMIT +#undef REASONABLE_FILE_LIMIT +} + +PyObject * +PyMarshal_ReadObjectFromFile(FILE *fp) +{ + RFILE rf; + PyObject *result; + rf.fp = fp; + rf.strings = PyList_New(0); + result = r_object(&rf); + Py_DECREF(rf.strings); + return result; +} + +PyObject * +PyMarshal_ReadObjectFromString(char *str, Py_ssize_t len) +{ + RFILE rf; + PyObject *result; + rf.fp = NULL; + rf.ptr = str; + rf.end = str + len; + rf.strings = PyList_New(0); + result = r_object(&rf); + Py_DECREF(rf.strings); + return result; +} + +PyObject * +PyMarshal_WriteObjectToString(PyObject *x, int version) +{ + WFILE wf; + wf.fp = NULL; + wf.str = PyString_FromStringAndSize((char *)NULL, 50); + if (wf.str == NULL) + return NULL; + wf.ptr = PyString_AS_STRING((PyStringObject *)wf.str); + wf.end = wf.ptr + PyString_Size(wf.str); + wf.error = 0; + wf.depth = 0; + wf.version = version; + wf.strings = (version > 0) ? PyDict_New() : NULL; + w_object(x, &wf); + Py_XDECREF(wf.strings); + if (wf.str != NULL) { + char *base = PyString_AS_STRING((PyStringObject *)wf.str); + if (wf.ptr - base > PY_SSIZE_T_MAX) { + Py_DECREF(wf.str); + PyErr_SetString(PyExc_OverflowError, + "too much marshall data for a string"); + return NULL; + } + _PyString_Resize(&wf.str, (Py_ssize_t)(wf.ptr - base)); + } + if (wf.error) { + Py_XDECREF(wf.str); + PyErr_SetString(PyExc_ValueError, + (wf.error==1)?"unmarshallable object" + :"object too deeply nested to marshal"); + return NULL; + } + return wf.str; +} + +/* And an interface for Python programs... */ + +static PyObject * +marshal_dump(PyObject *self, PyObject *args) +{ + WFILE wf; + PyObject *x; + PyObject *f; + int version = Py_MARSHAL_VERSION; + if (!PyArg_ParseTuple(args, "OO|i:dump", &x, &f, &version)) + return NULL; + if (!PyFile_Check(f)) { + PyErr_SetString(PyExc_TypeError, + "marshal.dump() 2nd arg must be file"); + return NULL; + } + wf.fp = PyFile_AsFile(f); + wf.str = NULL; + wf.ptr = wf.end = NULL; + wf.error = 0; + wf.depth = 0; + wf.strings = (version > 0) ? PyDict_New() : 0; + wf.version = version; + w_object(x, &wf); + Py_XDECREF(wf.strings); + if (wf.error) { + PyErr_SetString(PyExc_ValueError, + (wf.error==1)?"unmarshallable object" + :"object too deeply nested to marshal"); + return NULL; + } + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +marshal_load(PyObject *self, PyObject *f) +{ + RFILE rf; + PyObject *result; + if (!PyFile_Check(f)) { + PyErr_SetString(PyExc_TypeError, + "marshal.load() arg must be file"); + return NULL; + } + rf.fp = PyFile_AsFile(f); + rf.strings = PyList_New(0); + result = read_object(&rf); + Py_DECREF(rf.strings); + return result; +} + +static PyObject * +marshal_dumps(PyObject *self, PyObject *args) +{ + PyObject *x; + int version = Py_MARSHAL_VERSION; + if (!PyArg_ParseTuple(args, "O|i:dumps", &x, &version)) + return NULL; + return PyMarshal_WriteObjectToString(x, version); +} + +static PyObject * +marshal_loads(PyObject *self, PyObject *args) +{ + RFILE rf; + char *s; + Py_ssize_t n; + PyObject* result; + if (!PyArg_ParseTuple(args, "s#:loads", &s, &n)) + return NULL; + rf.fp = NULL; + rf.ptr = s; + rf.end = s + n; + rf.strings = PyList_New(0); + result = read_object(&rf); + Py_DECREF(rf.strings); + return result; +} + +static PyMethodDef marshal_methods[] = { + {"dump", marshal_dump, METH_VARARGS}, + {"load", marshal_load, METH_O}, + {"dumps", marshal_dumps, METH_VARARGS}, + {"loads", marshal_loads, METH_VARARGS}, + {NULL, NULL} /* sentinel */ +}; + +PyMODINIT_FUNC +PyMarshal_Init(void) +{ + PyObject *mod = Py_InitModule("marshal", marshal_methods); + if (mod == NULL) + return; + PyModule_AddIntConstant(mod, "version", Py_MARSHAL_VERSION); +} diff --git a/sys/src/cmd/python/Python/memmove.c b/sys/src/cmd/python/Python/memmove.c new file mode 100644 index 000000000..6fb0dad93 --- /dev/null +++ b/sys/src/cmd/python/Python/memmove.c @@ -0,0 +1,25 @@ + +/* A perhaps slow but I hope correct implementation of memmove */ + +extern char *memcpy(char *, char *, int); + +char * +memmove(char *dst, char *src, int n) +{ + char *realdst = dst; + if (n <= 0) + return dst; + if (src >= dst+n || dst >= src+n) + return memcpy(dst, src, n); + if (src > dst) { + while (--n >= 0) + *dst++ = *src++; + } + else if (src < dst) { + src += n; + dst += n; + while (--n >= 0) + *--dst = *--src; + } + return realdst; +} diff --git a/sys/src/cmd/python/Python/mkfile b/sys/src/cmd/python/Python/mkfile new file mode 100644 index 000000000..bab94765b --- /dev/null +++ b/sys/src/cmd/python/Python/mkfile @@ -0,0 +1,64 @@ +</$cputype/mkfile +cpuO=$O +APE=/sys/src/ape +<$APE/config + +LIB=/$objtype/lib/ape/libpython.a + +OFILES=\ + Python-ast.$O\ + asdl.$O\ + ast.$O\ + bltinmodule.$O\ + ceval.$O\ + codecs.$O\ + compile.$O\ + dynload_stub.$O\ + errors.$O\ +# fmod.$O\ + frozen.$O\ + frozenmain.$O\ + future.$O\ + getargs.$O\ + getcompiler.$O\ + getcopyright.$O\ + getmtime.$O\ + getopt.$O\ + getplatform.$O\ + getversion.$O\ + import.$O\ + importdl.$O\ + marshal.$O\ + modsupport.$O\ + mysnprintf.$O\ + mystrtoul.$O\ + pyarena.$O\ + pyfpe.$O\ + pystate.$O\ + pystrtod.$O\ + pythonrun.$O\ +# sigcheck.$O\ + structmember.$O\ + symtable.$O\ + sysmodule.$O\ + thread.$O\ + traceback.$O\ + graminit.$O\ + +</sys/src/cmd/mksyslib + +CFLAGS=-c -I.. -I../Include -DT$objtype -DPy_BUILD_CORE -DNDEBUG + +graminit.c ../Include/graminit.h:V: ../Parser/$cpuO.pgen + ../Parser/$cpuO.pgen ../Grammar/Grammar graminit.h graminit.c + mv graminit.h ../Include + + +# when cputype!=objtype, $PGENO causes unnecessary object files to be created. +# but when cputype==objtype, it keeps this mkfile from fighting with mkfile.pgen +# over creating some of these. +../Parser/$cpuO.pgen:V: $PGENO + @{ + cd ../Parser + objtype=$cputype mk $cpuO.pgen + } diff --git a/sys/src/cmd/python/Python/modsupport.c b/sys/src/cmd/python/Python/modsupport.c new file mode 100644 index 000000000..1aa3df285 --- /dev/null +++ b/sys/src/cmd/python/Python/modsupport.c @@ -0,0 +1,631 @@ + +/* Module support implementation */ + +#include "Python.h" + +#define FLAG_SIZE_T 1 +typedef double va_double; + +static PyObject *va_build_value(const char *, va_list, int); + +/* Package context -- the full module name for package imports */ +char *_Py_PackageContext = NULL; + +/* Py_InitModule4() parameters: + - name is the module name + - methods is the list of top-level functions + - doc is the documentation string + - passthrough is passed as self to functions defined in the module + - api_version is the value of PYTHON_API_VERSION at the time the + module was compiled + + Return value is a borrowed reference to the module object; or NULL + if an error occurred (in Python 1.4 and before, errors were fatal). + Errors may still leak memory. +*/ + +static char api_version_warning[] = +"Python C API version mismatch for module %.100s:\ + This Python has API version %d, module %.100s has version %d."; + +PyObject * +Py_InitModule4(const char *name, PyMethodDef *methods, const char *doc, + PyObject *passthrough, int module_api_version) +{ + PyObject *m, *d, *v, *n; + PyMethodDef *ml; + if (!Py_IsInitialized()) + Py_FatalError("Interpreter not initialized (version mismatch?)"); + if (module_api_version != PYTHON_API_VERSION) { + char message[512]; + PyOS_snprintf(message, sizeof(message), + api_version_warning, name, + PYTHON_API_VERSION, name, + module_api_version); + if (PyErr_Warn(PyExc_RuntimeWarning, message)) + return NULL; + } + /* Make sure name is fully qualified. + + This is a bit of a hack: when the shared library is loaded, + the module name is "package.module", but the module calls + Py_InitModule*() with just "module" for the name. The shared + library loader squirrels away the true name of the module in + _Py_PackageContext, and Py_InitModule*() will substitute this + (if the name actually matches). + */ + if (_Py_PackageContext != NULL) { + char *p = strrchr(_Py_PackageContext, '.'); + if (p != NULL && strcmp(name, p+1) == 0) { + name = _Py_PackageContext; + _Py_PackageContext = NULL; + } + } + if ((m = PyImport_AddModule(name)) == NULL) + return NULL; + d = PyModule_GetDict(m); + if (methods != NULL) { + n = PyString_FromString(name); + if (n == NULL) + return NULL; + for (ml = methods; ml->ml_name != NULL; ml++) { + if ((ml->ml_flags & METH_CLASS) || + (ml->ml_flags & METH_STATIC)) { + PyErr_SetString(PyExc_ValueError, + "module functions cannot set" + " METH_CLASS or METH_STATIC"); + Py_DECREF(n); + return NULL; + } + v = PyCFunction_NewEx(ml, passthrough, n); + if (v == NULL) { + Py_DECREF(n); + return NULL; + } + if (PyDict_SetItemString(d, ml->ml_name, v) != 0) { + Py_DECREF(v); + Py_DECREF(n); + return NULL; + } + Py_DECREF(v); + } + Py_DECREF(n); + } + if (doc != NULL) { + v = PyString_FromString(doc); + if (v == NULL || PyDict_SetItemString(d, "__doc__", v) != 0) { + Py_XDECREF(v); + return NULL; + } + Py_DECREF(v); + } + return m; +} + + +/* Helper for mkvalue() to scan the length of a format */ + +static int +countformat(const char *format, int endchar) +{ + int count = 0; + int level = 0; + while (level > 0 || *format != endchar) { + switch (*format) { + case '\0': + /* Premature end */ + PyErr_SetString(PyExc_SystemError, + "unmatched paren in format"); + return -1; + case '(': + case '[': + case '{': + if (level == 0) + count++; + level++; + break; + case ')': + case ']': + case '}': + level--; + break; + case '#': + case '&': + case ',': + case ':': + case ' ': + case '\t': + break; + default: + if (level == 0) + count++; + } + format++; + } + return count; +} + + +/* Generic function to create a value -- the inverse of getargs() */ +/* After an original idea and first implementation by Steven Miale */ + +static PyObject *do_mktuple(const char**, va_list *, int, int, int); +static PyObject *do_mklist(const char**, va_list *, int, int, int); +static PyObject *do_mkdict(const char**, va_list *, int, int, int); +static PyObject *do_mkvalue(const char**, va_list *, int); + + +static PyObject * +do_mkdict(const char **p_format, va_list *p_va, int endchar, int n, int flags) +{ + PyObject *d; + int i; + int itemfailed = 0; + if (n < 0) + return NULL; + if ((d = PyDict_New()) == NULL) + return NULL; + /* Note that we can't bail immediately on error as this will leak + refcounts on any 'N' arguments. */ + for (i = 0; i < n; i+= 2) { + PyObject *k, *v; + int err; + k = do_mkvalue(p_format, p_va, flags); + if (k == NULL) { + itemfailed = 1; + Py_INCREF(Py_None); + k = Py_None; + } + v = do_mkvalue(p_format, p_va, flags); + if (v == NULL) { + itemfailed = 1; + Py_INCREF(Py_None); + v = Py_None; + } + err = PyDict_SetItem(d, k, v); + Py_DECREF(k); + Py_DECREF(v); + if (err < 0 || itemfailed) { + Py_DECREF(d); + return NULL; + } + } + if (d != NULL && **p_format != endchar) { + Py_DECREF(d); + d = NULL; + PyErr_SetString(PyExc_SystemError, + "Unmatched paren in format"); + } + else if (endchar) + ++*p_format; + return d; +} + +static PyObject * +do_mklist(const char **p_format, va_list *p_va, int endchar, int n, int flags) +{ + PyObject *v; + int i; + int itemfailed = 0; + if (n < 0) + return NULL; + v = PyList_New(n); + if (v == NULL) + return NULL; + /* Note that we can't bail immediately on error as this will leak + refcounts on any 'N' arguments. */ + for (i = 0; i < n; i++) { + PyObject *w = do_mkvalue(p_format, p_va, flags); + if (w == NULL) { + itemfailed = 1; + Py_INCREF(Py_None); + w = Py_None; + } + PyList_SET_ITEM(v, i, w); + } + + if (itemfailed) { + /* do_mkvalue() should have already set an error */ + Py_DECREF(v); + return NULL; + } + if (**p_format != endchar) { + Py_DECREF(v); + PyErr_SetString(PyExc_SystemError, + "Unmatched paren in format"); + return NULL; + } + if (endchar) + ++*p_format; + return v; +} + +#ifdef Py_USING_UNICODE +static int +_ustrlen(Py_UNICODE *u) +{ + int i = 0; + Py_UNICODE *v = u; + while (*v != 0) { i++; v++; } + return i; +} +#endif + +static PyObject * +do_mktuple(const char **p_format, va_list *p_va, int endchar, int n, int flags) +{ + PyObject *v; + int i; + int itemfailed = 0; + if (n < 0) + return NULL; + if ((v = PyTuple_New(n)) == NULL) + return NULL; + /* Note that we can't bail immediately on error as this will leak + refcounts on any 'N' arguments. */ + for (i = 0; i < n; i++) { + PyObject *w = do_mkvalue(p_format, p_va, flags); + if (w == NULL) { + itemfailed = 1; + Py_INCREF(Py_None); + w = Py_None; + } + PyTuple_SET_ITEM(v, i, w); + } + if (itemfailed) { + /* do_mkvalue() should have already set an error */ + Py_DECREF(v); + return NULL; + } + if (**p_format != endchar) { + Py_DECREF(v); + PyErr_SetString(PyExc_SystemError, + "Unmatched paren in format"); + return NULL; + } + if (endchar) + ++*p_format; + return v; +} + +static PyObject * +do_mkvalue(const char **p_format, va_list *p_va, int flags) +{ + for (;;) { + switch (*(*p_format)++) { + case '(': + return do_mktuple(p_format, p_va, ')', + countformat(*p_format, ')'), flags); + + case '[': + return do_mklist(p_format, p_va, ']', + countformat(*p_format, ']'), flags); + + case '{': + return do_mkdict(p_format, p_va, '}', + countformat(*p_format, '}'), flags); + + case 'b': + case 'B': + case 'h': + case 'i': + return PyInt_FromLong((long)va_arg(*p_va, int)); + + case 'H': + return PyInt_FromLong((long)va_arg(*p_va, unsigned int)); + + case 'I': + { + unsigned int n; + n = va_arg(*p_va, unsigned int); + if (n > (unsigned long)PyInt_GetMax()) + return PyLong_FromUnsignedLong((unsigned long)n); + else + return PyInt_FromLong(n); + } + + case 'n': +#if SIZEOF_SIZE_T!=SIZEOF_LONG + return PyInt_FromSsize_t(va_arg(*p_va, Py_ssize_t)); +#endif + /* Fall through from 'n' to 'l' if Py_ssize_t is long */ + case 'l': + return PyInt_FromLong(va_arg(*p_va, long)); + + case 'k': + { + unsigned long n; + n = va_arg(*p_va, unsigned long); + if (n > (unsigned long)PyInt_GetMax()) + return PyLong_FromUnsignedLong(n); + else + return PyInt_FromLong(n); + } + +#ifdef HAVE_LONG_LONG + case 'L': + return PyLong_FromLongLong((PY_LONG_LONG)va_arg(*p_va, PY_LONG_LONG)); + + case 'K': + return PyLong_FromUnsignedLongLong((PY_LONG_LONG)va_arg(*p_va, unsigned PY_LONG_LONG)); +#endif +#ifdef Py_USING_UNICODE + case 'u': + { + PyObject *v; + Py_UNICODE *u = va_arg(*p_va, Py_UNICODE *); + Py_ssize_t n; + if (**p_format == '#') { + ++*p_format; + if (flags & FLAG_SIZE_T) + n = va_arg(*p_va, Py_ssize_t); + else + n = va_arg(*p_va, int); + } + else + n = -1; + if (u == NULL) { + v = Py_None; + Py_INCREF(v); + } + else { + if (n < 0) + n = _ustrlen(u); + v = PyUnicode_FromUnicode(u, n); + } + return v; + } +#endif + case 'f': + case 'd': + return PyFloat_FromDouble( + (double)va_arg(*p_va, va_double)); + +#ifndef WITHOUT_COMPLEX + case 'D': + return PyComplex_FromCComplex( + *((Py_complex *)va_arg(*p_va, Py_complex *))); +#endif /* WITHOUT_COMPLEX */ + + case 'c': + { + char p[1]; + p[0] = (char)va_arg(*p_va, int); + return PyString_FromStringAndSize(p, 1); + } + + case 's': + case 'z': + { + PyObject *v; + char *str = va_arg(*p_va, char *); + Py_ssize_t n; + if (**p_format == '#') { + ++*p_format; + if (flags & FLAG_SIZE_T) + n = va_arg(*p_va, Py_ssize_t); + else + n = va_arg(*p_va, int); + } + else + n = -1; + if (str == NULL) { + v = Py_None; + Py_INCREF(v); + } + else { + if (n < 0) { + size_t m = strlen(str); + if (m > PY_SSIZE_T_MAX) { + PyErr_SetString(PyExc_OverflowError, + "string too long for Python string"); + return NULL; + } + n = (Py_ssize_t)m; + } + v = PyString_FromStringAndSize(str, n); + } + return v; + } + + case 'N': + case 'S': + case 'O': + if (**p_format == '&') { + typedef PyObject *(*converter)(void *); + converter func = va_arg(*p_va, converter); + void *arg = va_arg(*p_va, void *); + ++*p_format; + return (*func)(arg); + } + else { + PyObject *v; + v = va_arg(*p_va, PyObject *); + if (v != NULL) { + if (*(*p_format - 1) != 'N') + Py_INCREF(v); + } + else if (!PyErr_Occurred()) + /* If a NULL was passed + * because a call that should + * have constructed a value + * failed, that's OK, and we + * pass the error on; but if + * no error occurred it's not + * clear that the caller knew + * what she was doing. */ + PyErr_SetString(PyExc_SystemError, + "NULL object passed to Py_BuildValue"); + return v; + } + + case ':': + case ',': + case ' ': + case '\t': + break; + + default: + PyErr_SetString(PyExc_SystemError, + "bad format char passed to Py_BuildValue"); + return NULL; + + } + } +} + + +PyObject * +Py_BuildValue(const char *format, ...) +{ + va_list va; + PyObject* retval; + va_start(va, format); + retval = va_build_value(format, va, 0); + va_end(va); + return retval; +} + +PyObject * +_Py_BuildValue_SizeT(const char *format, ...) +{ + va_list va; + PyObject* retval; + va_start(va, format); + retval = va_build_value(format, va, FLAG_SIZE_T); + va_end(va); + return retval; +} + +PyObject * +Py_VaBuildValue(const char *format, va_list va) +{ + return va_build_value(format, va, 0); +} + +PyObject * +_Py_VaBuildValue_SizeT(const char *format, va_list va) +{ + return va_build_value(format, va, FLAG_SIZE_T); +} + +static PyObject * +va_build_value(const char *format, va_list va, int flags) +{ + const char *f = format; + int n = countformat(f, '\0'); + va_list lva; + +#ifdef VA_LIST_IS_ARRAY + memcpy(lva, va, sizeof(va_list)); +#else +#ifdef __va_copy + __va_copy(lva, va); +#else + lva = va; +#endif +#endif + + if (n < 0) + return NULL; + if (n == 0) { + Py_INCREF(Py_None); + return Py_None; + } + if (n == 1) + return do_mkvalue(&f, &lva, flags); + return do_mktuple(&f, &lva, '\0', n, flags); +} + + +PyObject * +PyEval_CallFunction(PyObject *obj, const char *format, ...) +{ + va_list vargs; + PyObject *args; + PyObject *res; + + va_start(vargs, format); + + args = Py_VaBuildValue(format, vargs); + va_end(vargs); + + if (args == NULL) + return NULL; + + res = PyEval_CallObject(obj, args); + Py_DECREF(args); + + return res; +} + + +PyObject * +PyEval_CallMethod(PyObject *obj, const char *methodname, const char *format, ...) +{ + va_list vargs; + PyObject *meth; + PyObject *args; + PyObject *res; + + meth = PyObject_GetAttrString(obj, methodname); + if (meth == NULL) + return NULL; + + va_start(vargs, format); + + args = Py_VaBuildValue(format, vargs); + va_end(vargs); + + if (args == NULL) { + Py_DECREF(meth); + return NULL; + } + + res = PyEval_CallObject(meth, args); + Py_DECREF(meth); + Py_DECREF(args); + + return res; +} + +int +PyModule_AddObject(PyObject *m, const char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m)) { + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs module as first arg"); + return -1; + } + if (!o) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_TypeError, + "PyModule_AddObject() needs non-NULL value"); + return -1; + } + + dict = PyModule_GetDict(m); + if (dict == NULL) { + /* Internal error -- modules must have a dict! */ + PyErr_Format(PyExc_SystemError, "module '%s' has no __dict__", + PyModule_GetName(m)); + return -1; + } + if (PyDict_SetItemString(dict, name, o)) + return -1; + Py_DECREF(o); + return 0; +} + +int +PyModule_AddIntConstant(PyObject *m, const char *name, long value) +{ + return PyModule_AddObject(m, name, PyInt_FromLong(value)); +} + +int +PyModule_AddStringConstant(PyObject *m, const char *name, const char *value) +{ + return PyModule_AddObject(m, name, PyString_FromString(value)); +} diff --git a/sys/src/cmd/python/Python/mysnprintf.c b/sys/src/cmd/python/Python/mysnprintf.c new file mode 100644 index 000000000..4d3770d89 --- /dev/null +++ b/sys/src/cmd/python/Python/mysnprintf.c @@ -0,0 +1,93 @@ +#include "Python.h" +#include <ctype.h> + +/* snprintf() wrappers. If the platform has vsnprintf, we use it, else we + emulate it in a half-hearted way. Even if the platform has it, we wrap + it because platforms differ in what vsnprintf does in case the buffer + is too small: C99 behavior is to return the number of characters that + would have been written had the buffer not been too small, and to set + the last byte of the buffer to \0. At least MS _vsnprintf returns a + negative value instead, and fills the entire buffer with non-\0 data. + + The wrappers ensure that str[size-1] is always \0 upon return. + + PyOS_snprintf and PyOS_vsnprintf never write more than size bytes + (including the trailing '\0') into str. + + If the platform doesn't have vsnprintf, and the buffer size needed to + avoid truncation exceeds size by more than 512, Python aborts with a + Py_FatalError. + + Return value (rv): + + When 0 <= rv < size, the output conversion was unexceptional, and + rv characters were written to str (excluding a trailing \0 byte at + str[rv]). + + When rv >= size, output conversion was truncated, and a buffer of + size rv+1 would have been needed to avoid truncation. str[size-1] + is \0 in this case. + + When rv < 0, "something bad happened". str[size-1] is \0 in this + case too, but the rest of str is unreliable. It could be that + an error in format codes was detected by libc, or on platforms + with a non-C99 vsnprintf simply that the buffer wasn't big enough + to avoid truncation, or on platforms without any vsnprintf that + PyMem_Malloc couldn't obtain space for a temp buffer. + + CAUTION: Unlike C99, str != NULL and size > 0 are required. +*/ + +int +PyOS_snprintf(char *str, size_t size, const char *format, ...) +{ + int rc; + va_list va; + + va_start(va, format); + rc = PyOS_vsnprintf(str, size, format, va); + va_end(va); + return rc; +} + +int +PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va) +{ + int len; /* # bytes written, excluding \0 */ +#ifndef HAVE_SNPRINTF + char *buffer; +#endif + assert(str != NULL); + assert(size > 0); + assert(format != NULL); + +#ifdef HAVE_SNPRINTF + len = vsnprintf(str, size, format, va); +#else + /* Emulate it. */ + buffer = PyMem_MALLOC(size + 512); + if (buffer == NULL) { + len = -666; + goto Done; + } + + len = vsprintf(buffer, format, va); + if (len < 0) + /* ignore the error */; + + else if ((size_t)len >= size + 512) + Py_FatalError("Buffer overflow in PyOS_snprintf/PyOS_vsnprintf"); + + else { + const size_t to_copy = (size_t)len < size ? + (size_t)len : size - 1; + assert(to_copy < size); + memcpy(str, buffer, to_copy); + str[to_copy] = '\0'; + } + PyMem_FREE(buffer); +Done: +#endif + str[size-1] = '\0'; + return len; +} diff --git a/sys/src/cmd/python/Python/mystrtoul.c b/sys/src/cmd/python/Python/mystrtoul.c new file mode 100644 index 000000000..f0070575d --- /dev/null +++ b/sys/src/cmd/python/Python/mystrtoul.c @@ -0,0 +1,232 @@ + +#include "Python.h" + +#if defined(__sgi) && defined(WITH_THREAD) && !defined(_SGI_MP_SOURCE) +#define _SGI_MP_SOURCE +#endif + +/* Convert a possibly signed character to a nonnegative int */ +/* XXX This assumes characters are 8 bits wide */ +#ifdef __CHAR_UNSIGNED__ +#define Py_CHARMASK(c) (c) +#else +#define Py_CHARMASK(c) ((c) & 0xff) +#endif + +/* strtol and strtoul, renamed to avoid conflicts */ + + +#include <ctype.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + +/* Static overflow check values for bases 2 through 36. + * smallmax[base] is the largest unsigned long i such that + * i * base doesn't overflow unsigned long. + */ +static unsigned long smallmax[] = { + 0, /* bases 0 and 1 are invalid */ + 0, + ULONG_MAX / 2, + ULONG_MAX / 3, + ULONG_MAX / 4, + ULONG_MAX / 5, + ULONG_MAX / 6, + ULONG_MAX / 7, + ULONG_MAX / 8, + ULONG_MAX / 9, + ULONG_MAX / 10, + ULONG_MAX / 11, + ULONG_MAX / 12, + ULONG_MAX / 13, + ULONG_MAX / 14, + ULONG_MAX / 15, + ULONG_MAX / 16, + ULONG_MAX / 17, + ULONG_MAX / 18, + ULONG_MAX / 19, + ULONG_MAX / 20, + ULONG_MAX / 21, + ULONG_MAX / 22, + ULONG_MAX / 23, + ULONG_MAX / 24, + ULONG_MAX / 25, + ULONG_MAX / 26, + ULONG_MAX / 27, + ULONG_MAX / 28, + ULONG_MAX / 29, + ULONG_MAX / 30, + ULONG_MAX / 31, + ULONG_MAX / 32, + ULONG_MAX / 33, + ULONG_MAX / 34, + ULONG_MAX / 35, + ULONG_MAX / 36, +}; + +/* maximum digits that can't ever overflow for bases 2 through 36, + * calculated by [int(math.floor(math.log(2**32, i))) for i in range(2, 37)]. + * Note that this is pessimistic if sizeof(long) > 4. + */ +#if SIZEOF_LONG == 4 +static int digitlimit[] = { + 0, 0, 32, 20, 16, 13, 12, 11, 10, 10, /* 0 - 9 */ + 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, /* 10 - 19 */ + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, /* 20 - 29 */ + 6, 6, 6, 6, 6, 6, 6}; /* 30 - 36 */ +#elif SIZEOF_LONG == 8 +/* [int(math.floor(math.log(2**64, i))) for i in range(2, 37)] */ +static int digitlimit[] = { + 0, 0, 64, 40, 32, 27, 24, 22, 21, 20, /* 0 - 9 */ + 19, 18, 17, 17, 16, 16, 16, 15, 15, 15, /* 10 - 19 */ + 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, /* 20 - 29 */ + 13, 12, 12, 12, 12, 12, 12}; /* 30 - 36 */ +#else +#error "Need table for SIZEOF_LONG" +#endif + +/* +** strtoul +** This is a general purpose routine for converting +** an ascii string to an integer in an arbitrary base. +** Leading white space is ignored. If 'base' is zero +** it looks for a leading 0, 0x or 0X to tell which +** base. If these are absent it defaults to 10. +** Base must be 0 or between 2 and 36 (inclusive). +** If 'ptr' is non-NULL it will contain a pointer to +** the end of the scan. +** Errors due to bad pointers will probably result in +** exceptions - we don't check for them. +*/ +unsigned long +PyOS_strtoul(register char *str, char **ptr, int base) +{ + register unsigned long result = 0; /* return value of the function */ + register int c; /* current input character */ + register int ovlimit; /* required digits to overflow */ + + /* skip leading white space */ + while (*str && isspace(Py_CHARMASK(*str))) + ++str; + + /* check for leading 0 or 0x for auto-base or base 16 */ + switch (base) { + case 0: /* look for leading 0, 0x or 0X */ + if (*str == '0') { + ++str; + if (*str == 'x' || *str == 'X') { + ++str; + base = 16; + } + else + base = 8; + } + else + base = 10; + break; + + case 16: /* skip leading 0x or 0X */ + if (*str == '0') { + ++str; + if (*str == 'x' || *str == 'X') + ++str; + } + break; + } + + /* catch silly bases */ + if (base < 2 || base > 36) { + if (ptr) + *ptr = str; + return 0; + } + + /* skip leading zeroes */ + while (*str == '0') + ++str; + + /* base is guaranteed to be in [2, 36] at this point */ + ovlimit = digitlimit[base]; + + /* do the conversion until non-digit character encountered */ + while ((c = _PyLong_DigitValue[Py_CHARMASK(*str)]) < base) { + if (ovlimit > 0) /* no overflow check required */ + result = result * base + c; + else { /* requires overflow check */ + register unsigned long temp_result; + + if (ovlimit < 0) /* guaranteed overflow */ + goto overflowed; + + /* there could be an overflow */ + /* check overflow just from shifting */ + if (result > smallmax[base]) + goto overflowed; + + result *= base; + + /* check overflow from the digit's value */ + temp_result = result + c; + if (temp_result < result) + goto overflowed; + + result = temp_result; + } + + ++str; + --ovlimit; + } + + /* set pointer to point to the last character scanned */ + if (ptr) + *ptr = str; + + return result; + +overflowed: + if (ptr) { + /* spool through remaining digit characters */ + while (_PyLong_DigitValue[Py_CHARMASK(*str)] < base) + ++str; + *ptr = str; + } + errno = ERANGE; + return (unsigned long)-1; +} + +/* Checking for overflow in PyOS_strtol is a PITA; see comments + * about PY_ABS_LONG_MIN in longobject.c. + */ +#define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) + +long +PyOS_strtol(char *str, char **ptr, int base) +{ + long result; + unsigned long uresult; + char sign; + + while (*str && isspace(Py_CHARMASK(*str))) + str++; + + sign = *str; + if (sign == '+' || sign == '-') + str++; + + uresult = PyOS_strtoul(str, ptr, base); + + if (uresult <= (unsigned long)LONG_MAX) { + result = (long)uresult; + if (sign == '-') + result = -result; + } + else if (sign == '-' && uresult == PY_ABS_LONG_MIN) { + result = LONG_MIN; + } + else { + errno = ERANGE; + result = LONG_MAX; + } + return result; +} diff --git a/sys/src/cmd/python/Python/pyarena.c b/sys/src/cmd/python/Python/pyarena.c new file mode 100644 index 000000000..f4cc474f4 --- /dev/null +++ b/sys/src/cmd/python/Python/pyarena.c @@ -0,0 +1,220 @@ +#include "Python.h" +#include "pyarena.h" + +/* A simple arena block structure. + + Measurements with standard library modules suggest the average + allocation is about 20 bytes and that most compiles use a single + block. + + TODO(jhylton): Think about a realloc API, maybe just for the last + allocation? +*/ + +#define DEFAULT_BLOCK_SIZE 8192 +#define ALIGNMENT 8 +#define ALIGNMENT_MASK (ALIGNMENT - 1) +#define ROUNDUP(x) (((x) + ALIGNMENT_MASK) & ~ALIGNMENT_MASK) + +typedef struct _block { + /* Total number of bytes owned by this block available to pass out. + * Read-only after initialization. The first such byte starts at + * ab_mem. + */ + size_t ab_size; + + /* Total number of bytes already passed out. The next byte available + * to pass out starts at ab_mem + ab_offset. + */ + size_t ab_offset; + + /* An arena maintains a singly-linked, NULL-terminated list of + * all blocks owned by the arena. These are linked via the + * ab_next member. + */ + struct _block *ab_next; + + /* Pointer to the first allocatable byte owned by this block. Read- + * only after initialization. + */ + void *ab_mem; +} block; + +/* The arena manages two kinds of memory, blocks of raw memory + and a list of PyObject* pointers. PyObjects are decrefed + when the arena is freed. +*/ + +struct _arena { + /* Pointer to the first block allocated for the arena, never NULL. + It is used only to find the first block when the arena is + being freed. + */ + block *a_head; + + /* Pointer to the block currently used for allocation. It's + ab_next field should be NULL. If it is not-null after a + call to block_alloc(), it means a new block has been allocated + and a_cur should be reset to point it. + */ + block *a_cur; + + /* A Python list object containing references to all the PyObject + pointers associated with this area. They will be DECREFed + when the arena is freed. + */ + PyObject *a_objects; + +#if defined(Py_DEBUG) + /* Debug output */ + size_t total_allocs; + size_t total_size; + size_t total_blocks; + size_t total_block_size; + size_t total_big_blocks; +#endif +}; + +static block * +block_new(size_t size) +{ + /* Allocate header and block as one unit. + ab_mem points just past header. */ + block *b = (block *)malloc(sizeof(block) + size); + if (!b) + return NULL; + b->ab_size = size; + b->ab_mem = (void *)(b + 1); + b->ab_next = NULL; + b->ab_offset = ROUNDUP((Py_uintptr_t)(b->ab_mem)) - + (Py_uintptr_t)(b->ab_mem); + return b; +} + +static void +block_free(block *b) { + while (b) { + block *next = b->ab_next; + free(b); + b = next; + } +} + +static void * +block_alloc(block *b, size_t size) +{ + void *p; + assert(b); + size = ROUNDUP(size); + if (b->ab_offset + size > b->ab_size) { + /* If we need to allocate more memory than will fit in + the default block, allocate a one-off block that is + exactly the right size. */ + /* TODO(jhylton): Think about space waste at end of block */ + block *newbl = block_new( + size < DEFAULT_BLOCK_SIZE ? + DEFAULT_BLOCK_SIZE : size); + if (!newbl) + return NULL; + assert(!b->ab_next); + b->ab_next = newbl; + b = newbl; + } + + assert(b->ab_offset + size <= b->ab_size); + p = (void *)(((char *)b->ab_mem) + b->ab_offset); + b->ab_offset += size; + return p; +} + +PyArena * +PyArena_New() +{ + PyArena* arena = (PyArena *)malloc(sizeof(PyArena)); + if (!arena) + return (PyArena*)PyErr_NoMemory(); + + arena->a_head = block_new(DEFAULT_BLOCK_SIZE); + arena->a_cur = arena->a_head; + if (!arena->a_head) { + free((void *)arena); + return (PyArena*)PyErr_NoMemory(); + } + arena->a_objects = PyList_New(0); + if (!arena->a_objects) { + block_free(arena->a_head); + free((void *)arena); + return (PyArena*)PyErr_NoMemory(); + } +#if defined(Py_DEBUG) + arena->total_allocs = 0; + arena->total_size = 0; + arena->total_blocks = 1; + arena->total_block_size = DEFAULT_BLOCK_SIZE; + arena->total_big_blocks = 0; +#endif + return arena; +} + +void +PyArena_Free(PyArena *arena) +{ + int r; + assert(arena); +#if defined(Py_DEBUG) + /* + fprintf(stderr, + "alloc=%d size=%d blocks=%d block_size=%d big=%d objects=%d\n", + arena->total_allocs, arena->total_size, arena->total_blocks, + arena->total_block_size, arena->total_big_blocks, + PyList_Size(arena->a_objects)); + */ +#endif + block_free(arena->a_head); + /* This property normally holds, except when the code being compiled + is sys.getobjects(0), in which case there will be two references. + assert(arena->a_objects->ob_refcnt == 1); + */ + + /* Clear all the elements from the list. This is necessary + to guarantee that they will be DECREFed. */ + r = PyList_SetSlice(arena->a_objects, + 0, PyList_GET_SIZE(arena->a_objects), NULL); + assert(r == 0); + assert(PyList_GET_SIZE(arena->a_objects) == 0); + Py_DECREF(arena->a_objects); + free(arena); +} + +void * +PyArena_Malloc(PyArena *arena, size_t size) +{ + void *p = block_alloc(arena->a_cur, size); + if (!p) + return PyErr_NoMemory(); +#if defined(Py_DEBUG) + arena->total_allocs++; + arena->total_size += size; +#endif + /* Reset cur if we allocated a new block. */ + if (arena->a_cur->ab_next) { + arena->a_cur = arena->a_cur->ab_next; +#if defined(Py_DEBUG) + arena->total_blocks++; + arena->total_block_size += arena->a_cur->ab_size; + if (arena->a_cur->ab_size > DEFAULT_BLOCK_SIZE) + ++arena->total_big_blocks; +#endif + } + return p; +} + +int +PyArena_AddPyObject(PyArena *arena, PyObject *obj) +{ + int r = PyList_Append(arena->a_objects, obj); + if (r >= 0) { + Py_DECREF(obj); + } + return r; +} diff --git a/sys/src/cmd/python/Python/pyfpe.c b/sys/src/cmd/python/Python/pyfpe.c new file mode 100644 index 000000000..4b7f5bae1 --- /dev/null +++ b/sys/src/cmd/python/Python/pyfpe.c @@ -0,0 +1,23 @@ +#include "pyconfig.h" +#include "pyfpe.h" +/* + * The signal handler for SIGFPE is actually declared in an external + * module fpectl, or as preferred by the user. These variable + * definitions are required in order to compile Python without + * getting missing externals, but to actually handle SIGFPE requires + * defining a handler and enabling generation of SIGFPE. + */ + +#ifdef WANT_SIGFPE_HANDLER +jmp_buf PyFPE_jbuf; +int PyFPE_counter = 0; +#endif + +/* Have this outside the above #ifdef, since some picky ANSI compilers issue a + warning when compiling an empty file. */ + +double +PyFPE_dummy(void *dummy) +{ + return 1.0; +} diff --git a/sys/src/cmd/python/Python/pystate.c b/sys/src/cmd/python/Python/pystate.c new file mode 100644 index 000000000..086789d35 --- /dev/null +++ b/sys/src/cmd/python/Python/pystate.c @@ -0,0 +1,632 @@ + +/* Thread and interpreter state structures and their interfaces */ + +#include "Python.h" + +/* -------------------------------------------------------------------------- +CAUTION + +Always use malloc() and free() directly in this file. A number of these +functions are advertised as safe to call when the GIL isn't held, and in +a debug build Python redirects (e.g.) PyMem_NEW (etc) to Python's debugging +obmalloc functions. Those aren't thread-safe (they rely on the GIL to avoid +the expense of doing their own locking). +-------------------------------------------------------------------------- */ + +#ifdef HAVE_DLOPEN +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif +#ifndef RTLD_LAZY +#define RTLD_LAZY 1 +#endif +#endif + + +#ifdef WITH_THREAD +#include "pythread.h" +static PyThread_type_lock head_mutex = NULL; /* Protects interp->tstate_head */ +#define HEAD_INIT() (void)(head_mutex || (head_mutex = PyThread_allocate_lock())) +#define HEAD_LOCK() PyThread_acquire_lock(head_mutex, WAIT_LOCK) +#define HEAD_UNLOCK() PyThread_release_lock(head_mutex) + +#ifdef __cplusplus +extern "C" { +#endif + +/* The single PyInterpreterState used by this process' + GILState implementation +*/ +static PyInterpreterState *autoInterpreterState = NULL; +static int autoTLSkey = 0; +#else +#define HEAD_INIT() /* Nothing */ +#define HEAD_LOCK() /* Nothing */ +#define HEAD_UNLOCK() /* Nothing */ +#endif + +static PyInterpreterState *interp_head = NULL; + +PyThreadState *_PyThreadState_Current = NULL; +PyThreadFrameGetter _PyThreadState_GetFrame = NULL; + +#ifdef WITH_THREAD +static void _PyGILState_NoteThreadState(PyThreadState* tstate); +#endif + + +PyInterpreterState * +PyInterpreterState_New(void) +{ + PyInterpreterState *interp = (PyInterpreterState *) + malloc(sizeof(PyInterpreterState)); + + if (interp != NULL) { + HEAD_INIT(); +#ifdef WITH_THREAD + if (head_mutex == NULL) + Py_FatalError("Can't initialize threads for interpreter"); +#endif + interp->modules = NULL; + interp->modules_reloading = NULL; + interp->sysdict = NULL; + interp->builtins = NULL; + interp->tstate_head = NULL; + interp->codec_search_path = NULL; + interp->codec_search_cache = NULL; + interp->codec_error_registry = NULL; +#ifdef HAVE_DLOPEN +#ifdef RTLD_NOW + interp->dlopenflags = RTLD_NOW; +#else + interp->dlopenflags = RTLD_LAZY; +#endif +#endif +#ifdef WITH_TSC + interp->tscdump = 0; +#endif + + HEAD_LOCK(); + interp->next = interp_head; + interp_head = interp; + HEAD_UNLOCK(); + } + + return interp; +} + + +void +PyInterpreterState_Clear(PyInterpreterState *interp) +{ + PyThreadState *p; + HEAD_LOCK(); + for (p = interp->tstate_head; p != NULL; p = p->next) + PyThreadState_Clear(p); + HEAD_UNLOCK(); + Py_CLEAR(interp->codec_search_path); + Py_CLEAR(interp->codec_search_cache); + Py_CLEAR(interp->codec_error_registry); + Py_CLEAR(interp->modules); + Py_CLEAR(interp->modules_reloading); + Py_CLEAR(interp->sysdict); + Py_CLEAR(interp->builtins); +} + + +static void +zapthreads(PyInterpreterState *interp) +{ + PyThreadState *p; + /* No need to lock the mutex here because this should only happen + when the threads are all really dead (XXX famous last words). */ + while ((p = interp->tstate_head) != NULL) { + PyThreadState_Delete(p); + } +} + + +void +PyInterpreterState_Delete(PyInterpreterState *interp) +{ + PyInterpreterState **p; + zapthreads(interp); + HEAD_LOCK(); + for (p = &interp_head; ; p = &(*p)->next) { + if (*p == NULL) + Py_FatalError( + "PyInterpreterState_Delete: invalid interp"); + if (*p == interp) + break; + } + if (interp->tstate_head != NULL) + Py_FatalError("PyInterpreterState_Delete: remaining threads"); + *p = interp->next; + HEAD_UNLOCK(); + free(interp); +} + + +/* Default implementation for _PyThreadState_GetFrame */ +static struct _frame * +threadstate_getframe(PyThreadState *self) +{ + return self->frame; +} + +PyThreadState * +PyThreadState_New(PyInterpreterState *interp) +{ + PyThreadState *tstate = (PyThreadState *)malloc(sizeof(PyThreadState)); + + if (_PyThreadState_GetFrame == NULL) + _PyThreadState_GetFrame = threadstate_getframe; + + if (tstate != NULL) { + tstate->interp = interp; + + tstate->frame = NULL; + tstate->recursion_depth = 0; + tstate->tracing = 0; + tstate->use_tracing = 0; + tstate->tick_counter = 0; + tstate->gilstate_counter = 0; + tstate->async_exc = NULL; +#ifdef WITH_THREAD + tstate->thread_id = PyThread_get_thread_ident(); +#else + tstate->thread_id = 0; +#endif + + tstate->dict = NULL; + + tstate->curexc_type = NULL; + tstate->curexc_value = NULL; + tstate->curexc_traceback = NULL; + + tstate->exc_type = NULL; + tstate->exc_value = NULL; + tstate->exc_traceback = NULL; + + tstate->c_profilefunc = NULL; + tstate->c_tracefunc = NULL; + tstate->c_profileobj = NULL; + tstate->c_traceobj = NULL; + +#ifdef WITH_THREAD + _PyGILState_NoteThreadState(tstate); +#endif + + HEAD_LOCK(); + tstate->next = interp->tstate_head; + interp->tstate_head = tstate; + HEAD_UNLOCK(); + } + + return tstate; +} + + +void +PyThreadState_Clear(PyThreadState *tstate) +{ + if (Py_VerboseFlag && tstate->frame != NULL) + fprintf(stderr, + "PyThreadState_Clear: warning: thread still has a frame\n"); + + Py_CLEAR(tstate->frame); + + Py_CLEAR(tstate->dict); + Py_CLEAR(tstate->async_exc); + + Py_CLEAR(tstate->curexc_type); + Py_CLEAR(tstate->curexc_value); + Py_CLEAR(tstate->curexc_traceback); + + Py_CLEAR(tstate->exc_type); + Py_CLEAR(tstate->exc_value); + Py_CLEAR(tstate->exc_traceback); + + tstate->c_profilefunc = NULL; + tstate->c_tracefunc = NULL; + Py_CLEAR(tstate->c_profileobj); + Py_CLEAR(tstate->c_traceobj); +} + + +/* Common code for PyThreadState_Delete() and PyThreadState_DeleteCurrent() */ +static void +tstate_delete_common(PyThreadState *tstate) +{ + PyInterpreterState *interp; + PyThreadState **p; + if (tstate == NULL) + Py_FatalError("PyThreadState_Delete: NULL tstate"); + interp = tstate->interp; + if (interp == NULL) + Py_FatalError("PyThreadState_Delete: NULL interp"); + HEAD_LOCK(); + for (p = &interp->tstate_head; ; p = &(*p)->next) { + if (*p == NULL) + Py_FatalError( + "PyThreadState_Delete: invalid tstate"); + if (*p == tstate) + break; + } + *p = tstate->next; + HEAD_UNLOCK(); + free(tstate); +} + + +void +PyThreadState_Delete(PyThreadState *tstate) +{ + if (tstate == _PyThreadState_Current) + Py_FatalError("PyThreadState_Delete: tstate is still current"); + tstate_delete_common(tstate); +#ifdef WITH_THREAD + if (autoTLSkey && PyThread_get_key_value(autoTLSkey) == tstate) + PyThread_delete_key_value(autoTLSkey); +#endif /* WITH_THREAD */ +} + + +#ifdef WITH_THREAD +void +PyThreadState_DeleteCurrent() +{ + PyThreadState *tstate = _PyThreadState_Current; + if (tstate == NULL) + Py_FatalError( + "PyThreadState_DeleteCurrent: no current tstate"); + _PyThreadState_Current = NULL; + tstate_delete_common(tstate); + if (autoTLSkey && PyThread_get_key_value(autoTLSkey) == tstate) + PyThread_delete_key_value(autoTLSkey); + PyEval_ReleaseLock(); +} +#endif /* WITH_THREAD */ + + +PyThreadState * +PyThreadState_Get(void) +{ + if (_PyThreadState_Current == NULL) + Py_FatalError("PyThreadState_Get: no current thread"); + + return _PyThreadState_Current; +} + + +PyThreadState * +PyThreadState_Swap(PyThreadState *newts) +{ + PyThreadState *oldts = _PyThreadState_Current; + + _PyThreadState_Current = newts; + /* It should not be possible for more than one thread state + to be used for a thread. Check this the best we can in debug + builds. + */ +#if defined(Py_DEBUG) && defined(WITH_THREAD) + if (newts) { + /* This can be called from PyEval_RestoreThread(). Similar + to it, we need to ensure errno doesn't change. + */ + int err = errno; + PyThreadState *check = PyGILState_GetThisThreadState(); + if (check && check->interp == newts->interp && check != newts) + Py_FatalError("Invalid thread state for this thread"); + errno = err; + } +#endif + return oldts; +} + +/* An extension mechanism to store arbitrary additional per-thread state. + PyThreadState_GetDict() returns a dictionary that can be used to hold such + state; the caller should pick a unique key and store its state there. If + PyThreadState_GetDict() returns NULL, an exception has *not* been raised + and the caller should assume no per-thread state is available. */ + +PyObject * +PyThreadState_GetDict(void) +{ + if (_PyThreadState_Current == NULL) + return NULL; + + if (_PyThreadState_Current->dict == NULL) { + PyObject *d; + _PyThreadState_Current->dict = d = PyDict_New(); + if (d == NULL) + PyErr_Clear(); + } + return _PyThreadState_Current->dict; +} + + +/* Asynchronously raise an exception in a thread. + Requested by Just van Rossum and Alex Martelli. + To prevent naive misuse, you must write your own extension + to call this, or use ctypes. Must be called with the GIL held. + Returns the number of tstates modified (normally 1, but 0 if `id` didn't + match any known thread id). Can be called with exc=NULL to clear an + existing async exception. This raises no exceptions. */ + +int +PyThreadState_SetAsyncExc(long id, PyObject *exc) { + PyThreadState *tstate = PyThreadState_GET(); + PyInterpreterState *interp = tstate->interp; + PyThreadState *p; + + /* Although the GIL is held, a few C API functions can be called + * without the GIL held, and in particular some that create and + * destroy thread and interpreter states. Those can mutate the + * list of thread states we're traversing, so to prevent that we lock + * head_mutex for the duration. + */ + HEAD_LOCK(); + for (p = interp->tstate_head; p != NULL; p = p->next) { + if (p->thread_id == id) { + /* Tricky: we need to decref the current value + * (if any) in p->async_exc, but that can in turn + * allow arbitrary Python code to run, including + * perhaps calls to this function. To prevent + * deadlock, we need to release head_mutex before + * the decref. + */ + PyObject *old_exc = p->async_exc; + Py_XINCREF(exc); + p->async_exc = exc; + HEAD_UNLOCK(); + Py_XDECREF(old_exc); + return 1; + } + } + HEAD_UNLOCK(); + return 0; +} + + +/* Routines for advanced debuggers, requested by David Beazley. + Don't use unless you know what you are doing! */ + +PyInterpreterState * +PyInterpreterState_Head(void) +{ + return interp_head; +} + +PyInterpreterState * +PyInterpreterState_Next(PyInterpreterState *interp) { + return interp->next; +} + +PyThreadState * +PyInterpreterState_ThreadHead(PyInterpreterState *interp) { + return interp->tstate_head; +} + +PyThreadState * +PyThreadState_Next(PyThreadState *tstate) { + return tstate->next; +} + +/* The implementation of sys._current_frames(). This is intended to be + called with the GIL held, as it will be when called via + sys._current_frames(). It's possible it would work fine even without + the GIL held, but haven't thought enough about that. +*/ +PyObject * +_PyThread_CurrentFrames(void) +{ + PyObject *result; + PyInterpreterState *i; + + result = PyDict_New(); + if (result == NULL) + return NULL; + + /* for i in all interpreters: + * for t in all of i's thread states: + * if t's frame isn't NULL, map t's id to its frame + * Because these lists can mutute even when the GIL is held, we + * need to grab head_mutex for the duration. + */ + HEAD_LOCK(); + for (i = interp_head; i != NULL; i = i->next) { + PyThreadState *t; + for (t = i->tstate_head; t != NULL; t = t->next) { + PyObject *id; + int stat; + struct _frame *frame = t->frame; + if (frame == NULL) + continue; + id = PyInt_FromLong(t->thread_id); + if (id == NULL) + goto Fail; + stat = PyDict_SetItem(result, id, (PyObject *)frame); + Py_DECREF(id); + if (stat < 0) + goto Fail; + } + } + HEAD_UNLOCK(); + return result; + + Fail: + HEAD_UNLOCK(); + Py_DECREF(result); + return NULL; +} + +/* Python "auto thread state" API. */ +#ifdef WITH_THREAD + +/* Keep this as a static, as it is not reliable! It can only + ever be compared to the state for the *current* thread. + * If not equal, then it doesn't matter that the actual + value may change immediately after comparison, as it can't + possibly change to the current thread's state. + * If equal, then the current thread holds the lock, so the value can't + change until we yield the lock. +*/ +static int +PyThreadState_IsCurrent(PyThreadState *tstate) +{ + /* Must be the tstate for this thread */ + assert(PyGILState_GetThisThreadState()==tstate); + /* On Windows at least, simple reads and writes to 32 bit values + are atomic. + */ + return tstate == _PyThreadState_Current; +} + +/* Internal initialization/finalization functions called by + Py_Initialize/Py_Finalize +*/ +void +_PyGILState_Init(PyInterpreterState *i, PyThreadState *t) +{ + assert(i && t); /* must init with valid states */ + autoTLSkey = PyThread_create_key(); + autoInterpreterState = i; + assert(PyThread_get_key_value(autoTLSkey) == NULL); + assert(t->gilstate_counter == 0); + + _PyGILState_NoteThreadState(t); +} + +void +_PyGILState_Fini(void) +{ + PyThread_delete_key(autoTLSkey); + autoTLSkey = 0; + autoInterpreterState = NULL; +} + +/* When a thread state is created for a thread by some mechanism other than + PyGILState_Ensure, it's important that the GILState machinery knows about + it so it doesn't try to create another thread state for the thread (this is + a better fix for SF bug #1010677 than the first one attempted). +*/ +static void +_PyGILState_NoteThreadState(PyThreadState* tstate) +{ + /* If autoTLSkey is 0, this must be the very first threadstate created + in Py_Initialize(). Don't do anything for now (we'll be back here + when _PyGILState_Init is called). */ + if (!autoTLSkey) + return; + + /* Stick the thread state for this thread in thread local storage. + + The only situation where you can legitimately have more than one + thread state for an OS level thread is when there are multiple + interpreters, when: + + a) You shouldn't really be using the PyGILState_ APIs anyway, + and: + + b) The slightly odd way PyThread_set_key_value works (see + comments by its implementation) means that the first thread + state created for that given OS level thread will "win", + which seems reasonable behaviour. + */ + if (PyThread_set_key_value(autoTLSkey, (void *)tstate) < 0) + Py_FatalError("Couldn't create autoTLSkey mapping"); + + /* PyGILState_Release must not try to delete this thread state. */ + tstate->gilstate_counter = 1; +} + +/* The public functions */ +PyThreadState * +PyGILState_GetThisThreadState(void) +{ + if (autoInterpreterState == NULL || autoTLSkey == 0) + return NULL; + return (PyThreadState *)PyThread_get_key_value(autoTLSkey); +} + +PyGILState_STATE +PyGILState_Ensure(void) +{ + int current; + PyThreadState *tcur; + /* Note that we do not auto-init Python here - apart from + potential races with 2 threads auto-initializing, pep-311 + spells out other issues. Embedders are expected to have + called Py_Initialize() and usually PyEval_InitThreads(). + */ + assert(autoInterpreterState); /* Py_Initialize() hasn't been called! */ + tcur = (PyThreadState *)PyThread_get_key_value(autoTLSkey); + if (tcur == NULL) { + /* Create a new thread state for this thread */ + tcur = PyThreadState_New(autoInterpreterState); + if (tcur == NULL) + Py_FatalError("Couldn't create thread-state for new thread"); + /* This is our thread state! We'll need to delete it in the + matching call to PyGILState_Release(). */ + tcur->gilstate_counter = 0; + current = 0; /* new thread state is never current */ + } + else + current = PyThreadState_IsCurrent(tcur); + if (current == 0) + PyEval_RestoreThread(tcur); + /* Update our counter in the thread-state - no need for locks: + - tcur will remain valid as we hold the GIL. + - the counter is safe as we are the only thread "allowed" + to modify this value + */ + ++tcur->gilstate_counter; + return current ? PyGILState_LOCKED : PyGILState_UNLOCKED; +} + +void +PyGILState_Release(PyGILState_STATE oldstate) +{ + PyThreadState *tcur = (PyThreadState *)PyThread_get_key_value( + autoTLSkey); + if (tcur == NULL) + Py_FatalError("auto-releasing thread-state, " + "but no thread-state for this thread"); + /* We must hold the GIL and have our thread state current */ + /* XXX - remove the check - the assert should be fine, + but while this is very new (April 2003), the extra check + by release-only users can't hurt. + */ + if (! PyThreadState_IsCurrent(tcur)) + Py_FatalError("This thread state must be current when releasing"); + assert(PyThreadState_IsCurrent(tcur)); + --tcur->gilstate_counter; + assert(tcur->gilstate_counter >= 0); /* illegal counter value */ + + /* If we're going to destroy this thread-state, we must + * clear it while the GIL is held, as destructors may run. + */ + if (tcur->gilstate_counter == 0) { + /* can't have been locked when we created it */ + assert(oldstate == PyGILState_UNLOCKED); + PyThreadState_Clear(tcur); + /* Delete the thread-state. Note this releases the GIL too! + * It's vital that the GIL be held here, to avoid shutdown + * races; see bugs 225673 and 1061968 (that nasty bug has a + * habit of coming back). + */ + PyThreadState_DeleteCurrent(); + } + /* Release the lock if necessary */ + else if (oldstate == PyGILState_UNLOCKED) + PyEval_SaveThread(); +} + +#ifdef __cplusplus +} +#endif + +#endif /* WITH_THREAD */ + + diff --git a/sys/src/cmd/python/Python/pystrtod.c b/sys/src/cmd/python/Python/pystrtod.c new file mode 100644 index 000000000..6c19b45fd --- /dev/null +++ b/sys/src/cmd/python/Python/pystrtod.c @@ -0,0 +1,248 @@ +/* -*- Mode: C; c-file-style: "python" -*- */ + +#include <Python.h> +#include <locale.h> + +/* ascii character tests (as opposed to locale tests) */ +#define ISSPACE(c) ((c) == ' ' || (c) == '\f' || (c) == '\n' || \ + (c) == '\r' || (c) == '\t' || (c) == '\v') +#define ISDIGIT(c) ((c) >= '0' && (c) <= '9') +#define ISXDIGIT(c) (ISDIGIT(c) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F')) + + +/** + * PyOS_ascii_strtod: + * @nptr: the string to convert to a numeric value. + * @endptr: if non-%NULL, it returns the character after + * the last character used in the conversion. + * + * Converts a string to a #gdouble value. + * This function behaves like the standard strtod() function + * does in the C locale. It does this without actually + * changing the current locale, since that would not be + * thread-safe. + * + * This function is typically used when reading configuration + * files or other non-user input that should be locale independent. + * To handle input from the user you should normally use the + * locale-sensitive system strtod() function. + * + * If the correct value would cause overflow, plus or minus %HUGE_VAL + * is returned (according to the sign of the value), and %ERANGE is + * stored in %errno. If the correct value would cause underflow, + * zero is returned and %ERANGE is stored in %errno. + * If memory allocation fails, %ENOMEM is stored in %errno. + * + * This function resets %errno before calling strtod() so that + * you can reliably detect overflow and underflow. + * + * Return value: the #gdouble value. + **/ +double +PyOS_ascii_strtod(const char *nptr, char **endptr) +{ + char *fail_pos; + double val = -1.0; + struct lconv *locale_data; + const char *decimal_point; + size_t decimal_point_len; + const char *p, *decimal_point_pos; + const char *end = NULL; /* Silence gcc */ + + assert(nptr != NULL); + + fail_pos = NULL; + + locale_data = localeconv(); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen(decimal_point); + + assert(decimal_point_len != 0); + + decimal_point_pos = NULL; + if (decimal_point[0] != '.' || + decimal_point[1] != 0) + { + p = nptr; + /* Skip leading space */ + while (ISSPACE(*p)) + p++; + + /* Skip leading optional sign */ + if (*p == '+' || *p == '-') + p++; + + while (ISDIGIT(*p)) + p++; + + if (*p == '.') + { + decimal_point_pos = p++; + + while (ISDIGIT(*p)) + p++; + + if (*p == 'e' || *p == 'E') + p++; + if (*p == '+' || *p == '-') + p++; + while (ISDIGIT(*p)) + p++; + end = p; + } + else if (strncmp(p, decimal_point, decimal_point_len) == 0) + { + /* Python bug #1417699 */ + *endptr = (char*)nptr; + errno = EINVAL; + return val; + } + /* For the other cases, we need not convert the decimal point */ + } + + /* Set errno to zero, so that we can distinguish zero results + and underflows */ + errno = 0; + + if (decimal_point_pos) + { + char *copy, *c; + + /* We need to convert the '.' to the locale specific decimal point */ + copy = (char *)PyMem_MALLOC(end - nptr + 1 + decimal_point_len); + if (copy == NULL) { + if (endptr) + *endptr = (char *)nptr; + errno = ENOMEM; + return val; + } + + c = copy; + memcpy(c, nptr, decimal_point_pos - nptr); + c += decimal_point_pos - nptr; + memcpy(c, decimal_point, decimal_point_len); + c += decimal_point_len; + memcpy(c, decimal_point_pos + 1, end - (decimal_point_pos + 1)); + c += end - (decimal_point_pos + 1); + *c = 0; + + val = strtod(copy, &fail_pos); + + if (fail_pos) + { + if (fail_pos > decimal_point_pos) + fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1); + else + fail_pos = (char *)nptr + (fail_pos - copy); + } + + PyMem_FREE(copy); + + } + else { + unsigned i = 0; + if (nptr[i] == '-') + i++; + if (nptr[i] == '0' && (nptr[i+1] == 'x' || nptr[i+1] == 'X')) + fail_pos = (char*)nptr; + else + val = strtod(nptr, &fail_pos); + } + + if (endptr) + *endptr = fail_pos; + + return val; +} + + +/** + * PyOS_ascii_formatd: + * @buffer: A buffer to place the resulting string in + * @buf_len: The length of the buffer. + * @format: The printf()-style format to use for the + * code to use for converting. + * @d: The #gdouble to convert + * + * Converts a #gdouble to a string, using the '.' as + * decimal point. To format the number you pass in + * a printf()-style format string. Allowed conversion + * specifiers are 'e', 'E', 'f', 'F', 'g' and 'G'. + * + * Return value: The pointer to the buffer with the converted string. + **/ +char * +PyOS_ascii_formatd(char *buffer, + size_t buf_len, + const char *format, + double d) +{ + struct lconv *locale_data; + const char *decimal_point; + size_t decimal_point_len, rest_len; + char *p; + char format_char; + +/* g_return_val_if_fail (buffer != NULL, NULL); */ +/* g_return_val_if_fail (format[0] == '%', NULL); */ +/* g_return_val_if_fail (strpbrk (format + 1, "'l%") == NULL, NULL); */ + + format_char = format[strlen(format) - 1]; + +/* g_return_val_if_fail (format_char == 'e' || format_char == 'E' || */ +/* format_char == 'f' || format_char == 'F' || */ +/* format_char == 'g' || format_char == 'G', */ +/* NULL); */ + + if (format[0] != '%') + return NULL; + + if (strpbrk(format + 1, "'l%")) + return NULL; + + if (!(format_char == 'e' || format_char == 'E' || + format_char == 'f' || format_char == 'F' || + format_char == 'g' || format_char == 'G')) + return NULL; + + + PyOS_snprintf(buffer, buf_len, format, d); + + locale_data = localeconv(); + decimal_point = locale_data->decimal_point; + decimal_point_len = strlen(decimal_point); + + assert(decimal_point_len != 0); + + if (decimal_point[0] != '.' || + decimal_point[1] != 0) + { + p = buffer; + + if (*p == '+' || *p == '-') + p++; + + while (isdigit((unsigned char)*p)) + p++; + + if (strncmp(p, decimal_point, decimal_point_len) == 0) + { + *p = '.'; + p++; + if (decimal_point_len > 1) { + rest_len = strlen(p + (decimal_point_len - 1)); + memmove(p, p + (decimal_point_len - 1), + rest_len); + p[rest_len] = 0; + } + } + } + + return buffer; +} + +double +PyOS_ascii_atof(const char *nptr) +{ + return PyOS_ascii_strtod(nptr, NULL); +} diff --git a/sys/src/cmd/python/Python/pythonrun.c b/sys/src/cmd/python/Python/pythonrun.c new file mode 100644 index 000000000..75241fe91 --- /dev/null +++ b/sys/src/cmd/python/Python/pythonrun.c @@ -0,0 +1,1857 @@ + +/* Python interpreter top-level routines, including init/exit */ + +#include "Python.h" + +#include "Python-ast.h" +#include "grammar.h" +#include "node.h" +#include "token.h" +#include "parsetok.h" +#include "errcode.h" +#include "code.h" +#include "compile.h" +#include "symtable.h" +#include "pyarena.h" +#include "ast.h" +#include "eval.h" +#include "marshal.h" + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#ifdef HAVE_LANGINFO_H +#include <locale.h> +#include <langinfo.h> +#endif + +#ifdef MS_WINDOWS +#undef BYTE +#include "windows.h" +#endif + +#ifndef Py_REF_DEBUG +#define PRINT_TOTAL_REFS() +#else /* Py_REF_DEBUG */ +#define PRINT_TOTAL_REFS() fprintf(stderr, \ + "[%" PY_FORMAT_SIZE_T "d refs]\n", \ + _Py_GetRefTotal()) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *Py_GetPath(void); + +extern grammar _PyParser_Grammar; /* From graminit.c */ + +/* Forward */ +static void initmain(void); +static void initsite(void); +static PyObject *run_mod(mod_ty, const char *, PyObject *, PyObject *, + PyCompilerFlags *, PyArena *); +static PyObject *run_pyc_file(FILE *, const char *, PyObject *, PyObject *, + PyCompilerFlags *); +static void err_input(perrdetail *); +static void initsigs(void); +static void call_sys_exitfunc(void); +static void call_ll_exitfuncs(void); +extern void _PyUnicode_Init(void); +extern void _PyUnicode_Fini(void); + +#ifdef WITH_THREAD +extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *); +extern void _PyGILState_Fini(void); +#endif /* WITH_THREAD */ + +int Py_DebugFlag; /* Needed by parser.c */ +int Py_VerboseFlag; /* Needed by import.c */ +int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ +int Py_NoSiteFlag; /* Suppress 'import site' */ +int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */ +int Py_FrozenFlag; /* Needed by getpath.c */ +int Py_UnicodeFlag = 0; /* Needed by compile.c */ +int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */ +/* _XXX Py_QnewFlag should go away in 2.3. It's true iff -Qnew is passed, + on the command line, and is used in 2.2 by ceval.c to make all "/" divisions + true divisions (which they will be in 2.3). */ +int _Py_QnewFlag = 0; + +/* Reference to 'warnings' module, to avoid importing it + on the fly when the import lock may be held. See 683658/771097 +*/ +static PyObject *warnings_module = NULL; + +/* Returns a borrowed reference to the 'warnings' module, or NULL. + If the module is returned, it is guaranteed to have been obtained + without acquiring the import lock +*/ +PyObject *PyModule_GetWarningsModule(void) +{ + PyObject *typ, *val, *tb; + PyObject *all_modules; + /* If we managed to get the module at init time, just use it */ + if (warnings_module) + return warnings_module; + /* If it wasn't available at init time, it may be available + now in sys.modules (common scenario is frozen apps: import + at init time fails, but the frozen init code sets up sys.path + correctly, then does an implicit import of warnings for us + */ + /* Save and restore any exceptions */ + PyErr_Fetch(&typ, &val, &tb); + + all_modules = PySys_GetObject("modules"); + if (all_modules) { + warnings_module = PyDict_GetItemString(all_modules, "warnings"); + /* We keep a ref in the global */ + Py_XINCREF(warnings_module); + } + PyErr_Restore(typ, val, tb); + return warnings_module; +} + +static int initialized = 0; + +/* API to access the initialized flag -- useful for esoteric use */ + +int +Py_IsInitialized(void) +{ + return initialized; +} + +/* Global initializations. Can be undone by Py_Finalize(). Don't + call this twice without an intervening Py_Finalize() call. When + initializations fail, a fatal error is issued and the function does + not return. On return, the first thread and interpreter state have + been created. + + Locking: you must hold the interpreter lock while calling this. + (If the lock has not yet been initialized, that's equivalent to + having the lock, but you cannot use multiple threads.) + +*/ + +static int +add_flag(int flag, const char *envs) +{ + int env = atoi(envs); + if (flag < env) + flag = env; + if (flag < 1) + flag = 1; + return flag; +} + +void +Py_InitializeEx(int install_sigs) +{ + PyInterpreterState *interp; + PyThreadState *tstate; + PyObject *bimod, *sysmod; + char *p; +#if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET) + char *codeset; + char *saved_locale; + PyObject *sys_stream, *sys_isatty; +#endif + extern void _Py_ReadyTypes(void); + + if (initialized) + return; + initialized = 1; + + if ((p = Py_GETENV("PYTHONDEBUG")) && *p != '\0') + Py_DebugFlag = add_flag(Py_DebugFlag, p); + if ((p = Py_GETENV("PYTHONVERBOSE")) && *p != '\0') + Py_VerboseFlag = add_flag(Py_VerboseFlag, p); + if ((p = Py_GETENV("PYTHONOPTIMIZE")) && *p != '\0') + Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); + + interp = PyInterpreterState_New(); + if (interp == NULL) + Py_FatalError("Py_Initialize: can't make first interpreter"); + + tstate = PyThreadState_New(interp); + if (tstate == NULL) + Py_FatalError("Py_Initialize: can't make first thread"); + (void) PyThreadState_Swap(tstate); + + _Py_ReadyTypes(); + + if (!_PyFrame_Init()) + Py_FatalError("Py_Initialize: can't init frames"); + + if (!_PyInt_Init()) + Py_FatalError("Py_Initialize: can't init ints"); + + _PyFloat_Init(); + + interp->modules = PyDict_New(); + if (interp->modules == NULL) + Py_FatalError("Py_Initialize: can't make modules dictionary"); + interp->modules_reloading = PyDict_New(); + if (interp->modules_reloading == NULL) + Py_FatalError("Py_Initialize: can't make modules_reloading dictionary"); + +#ifdef Py_USING_UNICODE + /* Init Unicode implementation; relies on the codec registry */ + _PyUnicode_Init(); +#endif + + bimod = _PyBuiltin_Init(); + if (bimod == NULL) + Py_FatalError("Py_Initialize: can't initialize __builtin__"); + interp->builtins = PyModule_GetDict(bimod); + if (interp->builtins == NULL) + Py_FatalError("Py_Initialize: can't initialize builtins dict"); + Py_INCREF(interp->builtins); + + sysmod = _PySys_Init(); + if (sysmod == NULL) + Py_FatalError("Py_Initialize: can't initialize sys"); + interp->sysdict = PyModule_GetDict(sysmod); + if (interp->sysdict == NULL) + Py_FatalError("Py_Initialize: can't initialize sys dict"); + Py_INCREF(interp->sysdict); + _PyImport_FixupExtension("sys", "sys"); + PySys_SetPath(Py_GetPath()); + PyDict_SetItemString(interp->sysdict, "modules", + interp->modules); + + _PyImport_Init(); + + /* initialize builtin exceptions */ + _PyExc_Init(); + _PyImport_FixupExtension("exceptions", "exceptions"); + + /* phase 2 of builtins */ + _PyImport_FixupExtension("__builtin__", "__builtin__"); + + _PyImportHooks_Init(); + + if (install_sigs) + initsigs(); /* Signal handling stuff, including initintr() */ + + initmain(); /* Module __main__ */ + if (!Py_NoSiteFlag) + initsite(); /* Module site */ + + /* auto-thread-state API, if available */ +#ifdef WITH_THREAD + _PyGILState_Init(interp, tstate); +#endif /* WITH_THREAD */ + + warnings_module = PyImport_ImportModule("warnings"); + if (!warnings_module) + PyErr_Clear(); + +#if defined(Py_USING_UNICODE) && defined(HAVE_LANGINFO_H) && defined(CODESET) + /* On Unix, set the file system encoding according to the + user's preference, if the CODESET names a well-known + Python codec, and Py_FileSystemDefaultEncoding isn't + initialized by other means. Also set the encoding of + stdin and stdout if these are terminals. */ + + saved_locale = strdup(setlocale(LC_CTYPE, NULL)); + setlocale(LC_CTYPE, ""); + codeset = nl_langinfo(CODESET); + if (codeset && *codeset) { + PyObject *enc = PyCodec_Encoder(codeset); + if (enc) { + codeset = strdup(codeset); + Py_DECREF(enc); + } else { + codeset = NULL; + PyErr_Clear(); + } + } else + codeset = NULL; + setlocale(LC_CTYPE, saved_locale); + free(saved_locale); + + if (codeset) { + sys_stream = PySys_GetObject("stdin"); + sys_isatty = PyObject_CallMethod(sys_stream, "isatty", ""); + if (!sys_isatty) + PyErr_Clear(); + if(sys_isatty && PyObject_IsTrue(sys_isatty) && + PyFile_Check(sys_stream)) { + if (!PyFile_SetEncoding(sys_stream, codeset)) + Py_FatalError("Cannot set codeset of stdin"); + } + Py_XDECREF(sys_isatty); + + sys_stream = PySys_GetObject("stdout"); + sys_isatty = PyObject_CallMethod(sys_stream, "isatty", ""); + if (!sys_isatty) + PyErr_Clear(); + if(sys_isatty && PyObject_IsTrue(sys_isatty) && + PyFile_Check(sys_stream)) { + if (!PyFile_SetEncoding(sys_stream, codeset)) + Py_FatalError("Cannot set codeset of stdout"); + } + Py_XDECREF(sys_isatty); + + sys_stream = PySys_GetObject("stderr"); + sys_isatty = PyObject_CallMethod(sys_stream, "isatty", ""); + if (!sys_isatty) + PyErr_Clear(); + if(sys_isatty && PyObject_IsTrue(sys_isatty) && + PyFile_Check(sys_stream)) { + if (!PyFile_SetEncoding(sys_stream, codeset)) + Py_FatalError("Cannot set codeset of stderr"); + } + Py_XDECREF(sys_isatty); + + if (!Py_FileSystemDefaultEncoding) + Py_FileSystemDefaultEncoding = codeset; + else + free(codeset); + } +#endif +} + +void +Py_Initialize(void) +{ + Py_InitializeEx(1); +} + + +#ifdef COUNT_ALLOCS +extern void dump_counts(FILE*); +#endif + +/* Undo the effect of Py_Initialize(). + + Beware: if multiple interpreter and/or thread states exist, these + are not wiped out; only the current thread and interpreter state + are deleted. But since everything else is deleted, those other + interpreter and thread states should no longer be used. + + (XXX We should do better, e.g. wipe out all interpreters and + threads.) + + Locking: as above. + +*/ + +void +Py_Finalize(void) +{ + PyInterpreterState *interp; + PyThreadState *tstate; + + if (!initialized) + return; + + /* The interpreter is still entirely intact at this point, and the + * exit funcs may be relying on that. In particular, if some thread + * or exit func is still waiting to do an import, the import machinery + * expects Py_IsInitialized() to return true. So don't say the + * interpreter is uninitialized until after the exit funcs have run. + * Note that Threading.py uses an exit func to do a join on all the + * threads created thru it, so this also protects pending imports in + * the threads created via Threading. + */ + call_sys_exitfunc(); + initialized = 0; + + /* Get current thread state and interpreter pointer */ + tstate = PyThreadState_GET(); + interp = tstate->interp; + + /* Disable signal handling */ + PyOS_FiniInterrupts(); + + /* drop module references we saved */ + Py_XDECREF(warnings_module); + warnings_module = NULL; + + /* Collect garbage. This may call finalizers; it's nice to call these + * before all modules are destroyed. + * XXX If a __del__ or weakref callback is triggered here, and tries to + * XXX import a module, bad things can happen, because Python no + * XXX longer believes it's initialized. + * XXX Fatal Python error: Interpreter not initialized (version mismatch?) + * XXX is easy to provoke that way. I've also seen, e.g., + * XXX Exception exceptions.ImportError: 'No module named sha' + * XXX in <function callback at 0x008F5718> ignored + * XXX but I'm unclear on exactly how that one happens. In any case, + * XXX I haven't seen a real-life report of either of these. + */ + PyGC_Collect(); +#ifdef COUNT_ALLOCS + /* With COUNT_ALLOCS, it helps to run GC multiple times: + each collection might release some types from the type + list, so they become garbage. */ + while (PyGC_Collect() > 0) + /* nothing */; +#endif + + /* Destroy all modules */ + PyImport_Cleanup(); + + /* Collect final garbage. This disposes of cycles created by + * new-style class definitions, for example. + * XXX This is disabled because it caused too many problems. If + * XXX a __del__ or weakref callback triggers here, Python code has + * XXX a hard time running, because even the sys module has been + * XXX cleared out (sys.stdout is gone, sys.excepthook is gone, etc). + * XXX One symptom is a sequence of information-free messages + * XXX coming from threads (if a __del__ or callback is invoked, + * XXX other threads can execute too, and any exception they encounter + * XXX triggers a comedy of errors as subsystem after subsystem + * XXX fails to find what it *expects* to find in sys to help report + * XXX the exception and consequent unexpected failures). I've also + * XXX seen segfaults then, after adding print statements to the + * XXX Python code getting called. + */ +#if 0 + PyGC_Collect(); +#endif + + /* Destroy the database used by _PyImport_{Fixup,Find}Extension */ + _PyImport_Fini(); + + /* Debugging stuff */ +#ifdef COUNT_ALLOCS + dump_counts(stdout); +#endif + + PRINT_TOTAL_REFS(); + +#ifdef Py_TRACE_REFS + /* Display all objects still alive -- this can invoke arbitrary + * __repr__ overrides, so requires a mostly-intact interpreter. + * Alas, a lot of stuff may still be alive now that will be cleaned + * up later. + */ + if (Py_GETENV("PYTHONDUMPREFS")) + _Py_PrintReferences(stderr); +#endif /* Py_TRACE_REFS */ + + /* Cleanup auto-thread-state */ +#ifdef WITH_THREAD + _PyGILState_Fini(); +#endif /* WITH_THREAD */ + + /* Clear interpreter state */ + PyInterpreterState_Clear(interp); + + /* Now we decref the exception classes. After this point nothing + can raise an exception. That's okay, because each Fini() method + below has been checked to make sure no exceptions are ever + raised. + */ + + _PyExc_Fini(); + + /* Delete current thread */ + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); + + /* Sundry finalizers */ + PyMethod_Fini(); + PyFrame_Fini(); + PyCFunction_Fini(); + PyTuple_Fini(); + PyList_Fini(); + PySet_Fini(); + PyString_Fini(); + PyInt_Fini(); + PyFloat_Fini(); + +#ifdef Py_USING_UNICODE + /* Cleanup Unicode implementation */ + _PyUnicode_Fini(); +#endif + + /* XXX Still allocated: + - various static ad-hoc pointers to interned strings + - int and float free list blocks + - whatever various modules and libraries allocate + */ + + PyGrammar_RemoveAccelerators(&_PyParser_Grammar); + +#ifdef Py_TRACE_REFS + /* Display addresses (& refcnts) of all objects still alive. + * An address can be used to find the repr of the object, printed + * above by _Py_PrintReferences. + */ + if (Py_GETENV("PYTHONDUMPREFS")) + _Py_PrintReferenceAddresses(stderr); +#endif /* Py_TRACE_REFS */ +#ifdef PYMALLOC_DEBUG + if (Py_GETENV("PYTHONMALLOCSTATS")) + _PyObject_DebugMallocStats(); +#endif + + call_ll_exitfuncs(); +} + +/* Create and initialize a new interpreter and thread, and return the + new thread. This requires that Py_Initialize() has been called + first. + + Unsuccessful initialization yields a NULL pointer. Note that *no* + exception information is available even in this case -- the + exception information is held in the thread, and there is no + thread. + + Locking: as above. + +*/ + +PyThreadState * +Py_NewInterpreter(void) +{ + PyInterpreterState *interp; + PyThreadState *tstate, *save_tstate; + PyObject *bimod, *sysmod; + + if (!initialized) + Py_FatalError("Py_NewInterpreter: call Py_Initialize first"); + + interp = PyInterpreterState_New(); + if (interp == NULL) + return NULL; + + tstate = PyThreadState_New(interp); + if (tstate == NULL) { + PyInterpreterState_Delete(interp); + return NULL; + } + + save_tstate = PyThreadState_Swap(tstate); + + /* XXX The following is lax in error checking */ + + interp->modules = PyDict_New(); + interp->modules_reloading = PyDict_New(); + + bimod = _PyImport_FindExtension("__builtin__", "__builtin__"); + if (bimod != NULL) { + interp->builtins = PyModule_GetDict(bimod); + if (interp->builtins == NULL) + goto handle_error; + Py_INCREF(interp->builtins); + } + sysmod = _PyImport_FindExtension("sys", "sys"); + if (bimod != NULL && sysmod != NULL) { + interp->sysdict = PyModule_GetDict(sysmod); + if (interp->sysdict == NULL) + goto handle_error; + Py_INCREF(interp->sysdict); + PySys_SetPath(Py_GetPath()); + PyDict_SetItemString(interp->sysdict, "modules", + interp->modules); + _PyImportHooks_Init(); + initmain(); + if (!Py_NoSiteFlag) + initsite(); + } + + if (!PyErr_Occurred()) + return tstate; + +handle_error: + /* Oops, it didn't work. Undo it all. */ + + PyErr_Print(); + PyThreadState_Clear(tstate); + PyThreadState_Swap(save_tstate); + PyThreadState_Delete(tstate); + PyInterpreterState_Delete(interp); + + return NULL; +} + +/* Delete an interpreter and its last thread. This requires that the + given thread state is current, that the thread has no remaining + frames, and that it is its interpreter's only remaining thread. + It is a fatal error to violate these constraints. + + (Py_Finalize() doesn't have these constraints -- it zaps + everything, regardless.) + + Locking: as above. + +*/ + +void +Py_EndInterpreter(PyThreadState *tstate) +{ + PyInterpreterState *interp = tstate->interp; + + if (tstate != PyThreadState_GET()) + Py_FatalError("Py_EndInterpreter: thread is not current"); + if (tstate->frame != NULL) + Py_FatalError("Py_EndInterpreter: thread still has a frame"); + if (tstate != interp->tstate_head || tstate->next != NULL) + Py_FatalError("Py_EndInterpreter: not the last thread"); + + PyImport_Cleanup(); + PyInterpreterState_Clear(interp); + PyThreadState_Swap(NULL); + PyInterpreterState_Delete(interp); +} + +static char *progname = "python"; + +void +Py_SetProgramName(char *pn) +{ + if (pn && *pn) + progname = pn; +} + +char * +Py_GetProgramName(void) +{ + return progname; +} + +static char *default_home = NULL; + +void +Py_SetPythonHome(char *home) +{ + default_home = home; +} + +char * +Py_GetPythonHome(void) +{ + char *home = default_home; + if (home == NULL && !Py_IgnoreEnvironmentFlag) + home = Py_GETENV("PYTHONHOME"); + return home; +} + +/* Create __main__ module */ + +static void +initmain(void) +{ + PyObject *m, *d; + m = PyImport_AddModule("__main__"); + if (m == NULL) + Py_FatalError("can't create __main__ module"); + d = PyModule_GetDict(m); + if (PyDict_GetItemString(d, "__builtins__") == NULL) { + PyObject *bimod = PyImport_ImportModule("__builtin__"); + if (bimod == NULL || + PyDict_SetItemString(d, "__builtins__", bimod) != 0) + Py_FatalError("can't add __builtins__ to __main__"); + Py_DECREF(bimod); + } +} + +/* Import the site module (not into __main__ though) */ + +static void +initsite(void) +{ + PyObject *m, *f; + m = PyImport_ImportModule("site"); + if (m == NULL) { + f = PySys_GetObject("stderr"); + if (Py_VerboseFlag) { + PyFile_WriteString( + "'import site' failed; traceback:\n", f); + PyErr_Print(); + } + else { + PyFile_WriteString( + "'import site' failed; use -v for traceback\n", f); + PyErr_Clear(); + } + } + else { + Py_DECREF(m); + } +} + +/* Parse input from a file and execute it */ + +int +PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit, + PyCompilerFlags *flags) +{ + if (filename == NULL) + filename = "???"; + if (Py_FdIsInteractive(fp, filename)) { + int err = PyRun_InteractiveLoopFlags(fp, filename, flags); + if (closeit) + fclose(fp); + return err; + } + else + return PyRun_SimpleFileExFlags(fp, filename, closeit, flags); +} + +int +PyRun_InteractiveLoopFlags(FILE *fp, const char *filename, PyCompilerFlags *flags) +{ + PyObject *v; + int ret; + PyCompilerFlags local_flags; + + if (flags == NULL) { + flags = &local_flags; + local_flags.cf_flags = 0; + } + v = PySys_GetObject("ps1"); + if (v == NULL) { + PySys_SetObject("ps1", v = PyString_FromString(">>> ")); + Py_XDECREF(v); + } + v = PySys_GetObject("ps2"); + if (v == NULL) { + PySys_SetObject("ps2", v = PyString_FromString("... ")); + Py_XDECREF(v); + } + for (;;) { + ret = PyRun_InteractiveOneFlags(fp, filename, flags); + PRINT_TOTAL_REFS(); + if (ret == E_EOF) + return 0; + /* + if (ret == E_NOMEM) + return -1; + */ + } +} + +/* compute parser flags based on compiler flags */ +#define PARSER_FLAGS(flags) \ + ((flags) ? ((((flags)->cf_flags & PyCF_DONT_IMPLY_DEDENT) ? \ + PyPARSE_DONT_IMPLY_DEDENT : 0) \ + | ((flags)->cf_flags & CO_FUTURE_WITH_STATEMENT ? \ + PyPARSE_WITH_IS_KEYWORD : 0)) : 0) + +int +PyRun_InteractiveOneFlags(FILE *fp, const char *filename, PyCompilerFlags *flags) +{ + PyObject *m, *d, *v, *w; + mod_ty mod; + PyArena *arena; + char *ps1 = "", *ps2 = ""; + int errcode = 0; + + v = PySys_GetObject("ps1"); + if (v != NULL) { + v = PyObject_Str(v); + if (v == NULL) + PyErr_Clear(); + else if (PyString_Check(v)) + ps1 = PyString_AsString(v); + } + w = PySys_GetObject("ps2"); + if (w != NULL) { + w = PyObject_Str(w); + if (w == NULL) + PyErr_Clear(); + else if (PyString_Check(w)) + ps2 = PyString_AsString(w); + } + arena = PyArena_New(); + if (arena == NULL) { + Py_XDECREF(v); + Py_XDECREF(w); + return -1; + } + mod = PyParser_ASTFromFile(fp, filename, + Py_single_input, ps1, ps2, + flags, &errcode, arena); + Py_XDECREF(v); + Py_XDECREF(w); + if (mod == NULL) { + PyArena_Free(arena); + if (errcode == E_EOF) { + PyErr_Clear(); + return E_EOF; + } + PyErr_Print(); + return -1; + } + m = PyImport_AddModule("__main__"); + if (m == NULL) { + PyArena_Free(arena); + return -1; + } + d = PyModule_GetDict(m); + v = run_mod(mod, filename, d, d, flags, arena); + PyArena_Free(arena); + if (v == NULL) { + PyErr_Print(); + return -1; + } + Py_DECREF(v); + if (Py_FlushLine()) + PyErr_Clear(); + return 0; +} + +/* Check whether a file maybe a pyc file: Look at the extension, + the file type, and, if we may close it, at the first few bytes. */ + +static int +maybe_pyc_file(FILE *fp, const char* filename, const char* ext, int closeit) +{ + if (strcmp(ext, ".pyc") == 0 || strcmp(ext, ".pyo") == 0) + return 1; + + /* Only look into the file if we are allowed to close it, since + it then should also be seekable. */ + if (closeit) { + /* Read only two bytes of the magic. If the file was opened in + text mode, the bytes 3 and 4 of the magic (\r\n) might not + be read as they are on disk. */ + unsigned int halfmagic = PyImport_GetMagicNumber() & 0xFFFF; + unsigned char buf[2]; + /* Mess: In case of -x, the stream is NOT at its start now, + and ungetc() was used to push back the first newline, + which makes the current stream position formally undefined, + and a x-platform nightmare. + Unfortunately, we have no direct way to know whether -x + was specified. So we use a terrible hack: if the current + stream position is not 0, we assume -x was specified, and + give up. Bug 132850 on SourceForge spells out the + hopelessness of trying anything else (fseek and ftell + don't work predictably x-platform for text-mode files). + */ + int ispyc = 0; + if (ftell(fp) == 0) { + if (fread(buf, 1, 2, fp) == 2 && + ((unsigned int)buf[1]<<8 | buf[0]) == halfmagic) + ispyc = 1; + rewind(fp); + } + return ispyc; + } + return 0; +} + +int +PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, + PyCompilerFlags *flags) +{ + PyObject *m, *d, *v; + const char *ext; + + m = PyImport_AddModule("__main__"); + if (m == NULL) + return -1; + d = PyModule_GetDict(m); + if (PyDict_GetItemString(d, "__file__") == NULL) { + PyObject *f = PyString_FromString(filename); + if (f == NULL) + return -1; + if (PyDict_SetItemString(d, "__file__", f) < 0) { + Py_DECREF(f); + return -1; + } + Py_DECREF(f); + } + ext = filename + strlen(filename) - 4; + if (maybe_pyc_file(fp, filename, ext, closeit)) { + /* Try to run a pyc file. First, re-open in binary */ + if (closeit) + fclose(fp); + if ((fp = fopen(filename, "rb")) == NULL) { + fprintf(stderr, "python: Can't reopen .pyc file\n"); + return -1; + } + /* Turn on optimization if a .pyo file is given */ + if (strcmp(ext, ".pyo") == 0) + Py_OptimizeFlag = 1; + v = run_pyc_file(fp, filename, d, d, flags); + } else { + v = PyRun_FileExFlags(fp, filename, Py_file_input, d, d, + closeit, flags); + } + if (v == NULL) { + PyErr_Print(); + return -1; + } + Py_DECREF(v); + if (Py_FlushLine()) + PyErr_Clear(); + return 0; +} + +int +PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) +{ + PyObject *m, *d, *v; + m = PyImport_AddModule("__main__"); + if (m == NULL) + return -1; + d = PyModule_GetDict(m); + v = PyRun_StringFlags(command, Py_file_input, d, d, flags); + if (v == NULL) { + PyErr_Print(); + return -1; + } + Py_DECREF(v); + if (Py_FlushLine()) + PyErr_Clear(); + return 0; +} + +static int +parse_syntax_error(PyObject *err, PyObject **message, const char **filename, + int *lineno, int *offset, const char **text) +{ + long hold; + PyObject *v; + + /* old style errors */ + if (PyTuple_Check(err)) + return PyArg_ParseTuple(err, "O(ziiz)", message, filename, + lineno, offset, text); + + /* new style errors. `err' is an instance */ + + if (! (v = PyObject_GetAttrString(err, "msg"))) + goto finally; + *message = v; + + if (!(v = PyObject_GetAttrString(err, "filename"))) + goto finally; + if (v == Py_None) + *filename = NULL; + else if (! (*filename = PyString_AsString(v))) + goto finally; + + Py_DECREF(v); + if (!(v = PyObject_GetAttrString(err, "lineno"))) + goto finally; + hold = PyInt_AsLong(v); + Py_DECREF(v); + v = NULL; + if (hold < 0 && PyErr_Occurred()) + goto finally; + *lineno = (int)hold; + + if (!(v = PyObject_GetAttrString(err, "offset"))) + goto finally; + if (v == Py_None) { + *offset = -1; + Py_DECREF(v); + v = NULL; + } else { + hold = PyInt_AsLong(v); + Py_DECREF(v); + v = NULL; + if (hold < 0 && PyErr_Occurred()) + goto finally; + *offset = (int)hold; + } + + if (!(v = PyObject_GetAttrString(err, "text"))) + goto finally; + if (v == Py_None) + *text = NULL; + else if (! (*text = PyString_AsString(v))) + goto finally; + Py_DECREF(v); + return 1; + +finally: + Py_XDECREF(v); + return 0; +} + +void +PyErr_Print(void) +{ + PyErr_PrintEx(1); +} + +static void +print_error_text(PyObject *f, int offset, const char *text) +{ + char *nl; + if (offset >= 0) { + if (offset > 0 && offset == (int)strlen(text)) + offset--; + for (;;) { + nl = strchr(text, '\n'); + if (nl == NULL || nl-text >= offset) + break; + offset -= (int)(nl+1-text); + text = nl+1; + } + while (*text == ' ' || *text == '\t') { + text++; + offset--; + } + } + PyFile_WriteString(" ", f); + PyFile_WriteString(text, f); + if (*text == '\0' || text[strlen(text)-1] != '\n') + PyFile_WriteString("\n", f); + if (offset == -1) + return; + PyFile_WriteString(" ", f); + offset--; + while (offset > 0) { + PyFile_WriteString(" ", f); + offset--; + } + PyFile_WriteString("^\n", f); +} + +static void +handle_system_exit(void) +{ + PyObject *exception, *value, *tb; + int exitcode = 0; + + PyErr_Fetch(&exception, &value, &tb); + if (Py_FlushLine()) + PyErr_Clear(); + fflush(stdout); + if (value == NULL || value == Py_None) + goto done; + if (PyExceptionInstance_Check(value)) { + /* The error code should be in the `code' attribute. */ + PyObject *code = PyObject_GetAttrString(value, "code"); + if (code) { + Py_DECREF(value); + value = code; + if (value == Py_None) + goto done; + } + /* If we failed to dig out the 'code' attribute, + just let the else clause below print the error. */ + } + if (PyInt_Check(value)) + exitcode = (int)PyInt_AsLong(value); + else { + PyObject_Print(value, stderr, Py_PRINT_RAW); + PySys_WriteStderr("\n"); + exitcode = 1; + } + done: + /* Restore and clear the exception info, in order to properly decref + * the exception, value, and traceback. If we just exit instead, + * these leak, which confuses PYTHONDUMPREFS output, and may prevent + * some finalizers from running. + */ + PyErr_Restore(exception, value, tb); + PyErr_Clear(); + Py_Exit(exitcode); + /* NOTREACHED */ +} + +void +PyErr_PrintEx(int set_sys_last_vars) +{ + PyObject *exception, *v, *tb, *hook; + + if (PyErr_ExceptionMatches(PyExc_SystemExit)) { + handle_system_exit(); + } + PyErr_Fetch(&exception, &v, &tb); + if (exception == NULL) + return; + PyErr_NormalizeException(&exception, &v, &tb); + if (exception == NULL) + return; + /* Now we know v != NULL too */ + if (set_sys_last_vars) { + PySys_SetObject("last_type", exception); + PySys_SetObject("last_value", v); + PySys_SetObject("last_traceback", tb); + } + hook = PySys_GetObject("excepthook"); + if (hook) { + PyObject *args = PyTuple_Pack(3, + exception, v, tb ? tb : Py_None); + PyObject *result = PyEval_CallObject(hook, args); + if (result == NULL) { + PyObject *exception2, *v2, *tb2; + if (PyErr_ExceptionMatches(PyExc_SystemExit)) { + handle_system_exit(); + } + PyErr_Fetch(&exception2, &v2, &tb2); + PyErr_NormalizeException(&exception2, &v2, &tb2); + /* It should not be possible for exception2 or v2 + to be NULL. However PyErr_Display() can't + tolerate NULLs, so just be safe. */ + if (exception2 == NULL) { + exception2 = Py_None; + Py_INCREF(exception2); + } + if (v2 == NULL) { + v2 = Py_None; + Py_INCREF(v2); + } + if (Py_FlushLine()) + PyErr_Clear(); + fflush(stdout); + PySys_WriteStderr("Error in sys.excepthook:\n"); + PyErr_Display(exception2, v2, tb2); + PySys_WriteStderr("\nOriginal exception was:\n"); + PyErr_Display(exception, v, tb); + Py_DECREF(exception2); + Py_DECREF(v2); + Py_XDECREF(tb2); + } + Py_XDECREF(result); + Py_XDECREF(args); + } else { + PySys_WriteStderr("sys.excepthook is missing\n"); + PyErr_Display(exception, v, tb); + } + Py_XDECREF(exception); + Py_XDECREF(v); + Py_XDECREF(tb); +} + +void +PyErr_Display(PyObject *exception, PyObject *value, PyObject *tb) +{ + int err = 0; + PyObject *f = PySys_GetObject("stderr"); + Py_INCREF(value); + if (f == NULL) + fprintf(stderr, "lost sys.stderr\n"); + else { + if (Py_FlushLine()) + PyErr_Clear(); + fflush(stdout); + if (tb && tb != Py_None) + err = PyTraceBack_Print(tb, f); + if (err == 0 && + PyObject_HasAttrString(value, "print_file_and_line")) + { + PyObject *message; + const char *filename, *text; + int lineno, offset; + if (!parse_syntax_error(value, &message, &filename, + &lineno, &offset, &text)) + PyErr_Clear(); + else { + char buf[10]; + PyFile_WriteString(" File \"", f); + if (filename == NULL) + PyFile_WriteString("<string>", f); + else + PyFile_WriteString(filename, f); + PyFile_WriteString("\", line ", f); + PyOS_snprintf(buf, sizeof(buf), "%d", lineno); + PyFile_WriteString(buf, f); + PyFile_WriteString("\n", f); + if (text != NULL) + print_error_text(f, offset, text); + Py_DECREF(value); + value = message; + /* Can't be bothered to check all those + PyFile_WriteString() calls */ + if (PyErr_Occurred()) + err = -1; + } + } + if (err) { + /* Don't do anything else */ + } + else if (PyExceptionClass_Check(exception)) { + PyObject* moduleName; + char* className = PyExceptionClass_Name(exception); + if (className != NULL) { + char *dot = strrchr(className, '.'); + if (dot != NULL) + className = dot+1; + } + + moduleName = PyObject_GetAttrString(exception, "__module__"); + if (moduleName == NULL) + err = PyFile_WriteString("<unknown>", f); + else { + char* modstr = PyString_AsString(moduleName); + if (modstr && strcmp(modstr, "exceptions")) + { + err = PyFile_WriteString(modstr, f); + err += PyFile_WriteString(".", f); + } + Py_DECREF(moduleName); + } + if (err == 0) { + if (className == NULL) + err = PyFile_WriteString("<unknown>", f); + else + err = PyFile_WriteString(className, f); + } + } + else + err = PyFile_WriteObject(exception, f, Py_PRINT_RAW); + if (err == 0 && (value != Py_None)) { + PyObject *s = PyObject_Str(value); + /* only print colon if the str() of the + object is not the empty string + */ + if (s == NULL) + err = -1; + else if (!PyString_Check(s) || + PyString_GET_SIZE(s) != 0) + err = PyFile_WriteString(": ", f); + if (err == 0) + err = PyFile_WriteObject(s, f, Py_PRINT_RAW); + Py_XDECREF(s); + } + if (err == 0) + err = PyFile_WriteString("\n", f); + } + Py_DECREF(value); + /* If an error happened here, don't show it. + XXX This is wrong, but too many callers rely on this behavior. */ + if (err != 0) + PyErr_Clear(); +} + +PyObject * +PyRun_StringFlags(const char *str, int start, PyObject *globals, + PyObject *locals, PyCompilerFlags *flags) +{ + PyObject *ret = NULL; + mod_ty mod; + PyArena *arena = PyArena_New(); + if (arena == NULL) + return NULL; + + mod = PyParser_ASTFromString(str, "<string>", start, flags, arena); + if (mod != NULL) + ret = run_mod(mod, "<string>", globals, locals, flags, arena); + PyArena_Free(arena); + return ret; +} + +PyObject * +PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, + PyObject *locals, int closeit, PyCompilerFlags *flags) +{ + PyObject *ret; + mod_ty mod; + PyArena *arena = PyArena_New(); + if (arena == NULL) + return NULL; + + mod = PyParser_ASTFromFile(fp, filename, start, 0, 0, + flags, NULL, arena); + if (closeit) + fclose(fp); + if (mod == NULL) { + PyArena_Free(arena); + return NULL; + } + ret = run_mod(mod, filename, globals, locals, flags, arena); + PyArena_Free(arena); + return ret; +} + +static PyObject * +run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals, + PyCompilerFlags *flags, PyArena *arena) +{ + PyCodeObject *co; + PyObject *v; + co = PyAST_Compile(mod, filename, flags, arena); + if (co == NULL) + return NULL; + v = PyEval_EvalCode(co, globals, locals); + Py_DECREF(co); + return v; +} + +static PyObject * +run_pyc_file(FILE *fp, const char *filename, PyObject *globals, + PyObject *locals, PyCompilerFlags *flags) +{ + PyCodeObject *co; + PyObject *v; + long magic; + long PyImport_GetMagicNumber(void); + + magic = PyMarshal_ReadLongFromFile(fp); + if (magic != PyImport_GetMagicNumber()) { + PyErr_SetString(PyExc_RuntimeError, + "Bad magic number in .pyc file"); + return NULL; + } + (void) PyMarshal_ReadLongFromFile(fp); + v = PyMarshal_ReadLastObjectFromFile(fp); + fclose(fp); + if (v == NULL || !PyCode_Check(v)) { + Py_XDECREF(v); + PyErr_SetString(PyExc_RuntimeError, + "Bad code object in .pyc file"); + return NULL; + } + co = (PyCodeObject *)v; + v = PyEval_EvalCode(co, globals, locals); + if (v && flags) + flags->cf_flags |= (co->co_flags & PyCF_MASK); + Py_DECREF(co); + return v; +} + +PyObject * +Py_CompileStringFlags(const char *str, const char *filename, int start, + PyCompilerFlags *flags) +{ + PyCodeObject *co; + mod_ty mod; + PyArena *arena = PyArena_New(); + if (arena == NULL) + return NULL; + + mod = PyParser_ASTFromString(str, filename, start, flags, arena); + if (mod == NULL) { + PyArena_Free(arena); + return NULL; + } + if (flags && (flags->cf_flags & PyCF_ONLY_AST)) { + PyObject *result = PyAST_mod2obj(mod); + PyArena_Free(arena); + return result; + } + co = PyAST_Compile(mod, filename, flags, arena); + PyArena_Free(arena); + return (PyObject *)co; +} + +struct symtable * +Py_SymtableString(const char *str, const char *filename, int start) +{ + struct symtable *st; + mod_ty mod; + PyArena *arena = PyArena_New(); + if (arena == NULL) + return NULL; + + mod = PyParser_ASTFromString(str, filename, start, NULL, arena); + if (mod == NULL) { + PyArena_Free(arena); + return NULL; + } + st = PySymtable_Build(mod, filename, 0); + PyArena_Free(arena); + return st; +} + +/* Preferred access to parser is through AST. */ +mod_ty +PyParser_ASTFromString(const char *s, const char *filename, int start, + PyCompilerFlags *flags, PyArena *arena) +{ + mod_ty mod; + perrdetail err; + node *n = PyParser_ParseStringFlagsFilename(s, filename, + &_PyParser_Grammar, start, &err, + PARSER_FLAGS(flags)); + if (n) { + mod = PyAST_FromNode(n, flags, filename, arena); + PyNode_Free(n); + return mod; + } + else { + err_input(&err); + return NULL; + } +} + +mod_ty +PyParser_ASTFromFile(FILE *fp, const char *filename, int start, char *ps1, + char *ps2, PyCompilerFlags *flags, int *errcode, + PyArena *arena) +{ + mod_ty mod; + perrdetail err; + node *n = PyParser_ParseFileFlags(fp, filename, &_PyParser_Grammar, + start, ps1, ps2, &err, PARSER_FLAGS(flags)); + if (n) { + mod = PyAST_FromNode(n, flags, filename, arena); + PyNode_Free(n); + return mod; + } + else { + err_input(&err); + if (errcode) + *errcode = err.error; + return NULL; + } +} + +/* Simplified interface to parsefile -- return node or set exception */ + +node * +PyParser_SimpleParseFileFlags(FILE *fp, const char *filename, int start, int flags) +{ + perrdetail err; + node *n = PyParser_ParseFileFlags(fp, filename, &_PyParser_Grammar, + start, NULL, NULL, &err, flags); + if (n == NULL) + err_input(&err); + + return n; +} + +/* Simplified interface to parsestring -- return node or set exception */ + +node * +PyParser_SimpleParseStringFlags(const char *str, int start, int flags) +{ + perrdetail err; + node *n = PyParser_ParseStringFlags(str, &_PyParser_Grammar, + start, &err, flags); + if (n == NULL) + err_input(&err); + return n; +} + +node * +PyParser_SimpleParseStringFlagsFilename(const char *str, const char *filename, + int start, int flags) +{ + perrdetail err; + node *n = PyParser_ParseStringFlagsFilename(str, filename, + &_PyParser_Grammar, start, &err, flags); + if (n == NULL) + err_input(&err); + return n; +} + +node * +PyParser_SimpleParseStringFilename(const char *str, const char *filename, int start) +{ + return PyParser_SimpleParseStringFlagsFilename(str, filename, start, 0); +} + +/* May want to move a more generalized form of this to parsetok.c or + even parser modules. */ + +void +PyParser_SetError(perrdetail *err) +{ + err_input(err); +} + +/* Set the error appropriate to the given input error code (see errcode.h) */ + +static void +err_input(perrdetail *err) +{ + PyObject *v, *w, *errtype; + PyObject* u = NULL; + char *msg = NULL; + errtype = PyExc_SyntaxError; + switch (err->error) { + case E_SYNTAX: + errtype = PyExc_IndentationError; + if (err->expected == INDENT) + msg = "expected an indented block"; + else if (err->token == INDENT) + msg = "unexpected indent"; + else if (err->token == DEDENT) + msg = "unexpected unindent"; + else { + errtype = PyExc_SyntaxError; + msg = "invalid syntax"; + } + break; + case E_TOKEN: + msg = "invalid token"; + break; + case E_EOFS: + msg = "EOF while scanning triple-quoted string"; + break; + case E_EOLS: + msg = "EOL while scanning single-quoted string"; + break; + case E_INTR: + if (!PyErr_Occurred()) + PyErr_SetNone(PyExc_KeyboardInterrupt); + return; + case E_NOMEM: + PyErr_NoMemory(); + return; + case E_EOF: + msg = "unexpected EOF while parsing"; + break; + case E_TABSPACE: + errtype = PyExc_TabError; + msg = "inconsistent use of tabs and spaces in indentation"; + break; + case E_OVERFLOW: + msg = "expression too long"; + break; + case E_DEDENT: + errtype = PyExc_IndentationError; + msg = "unindent does not match any outer indentation level"; + break; + case E_TOODEEP: + errtype = PyExc_IndentationError; + msg = "too many levels of indentation"; + break; + case E_DECODE: { + PyObject *type, *value, *tb; + PyErr_Fetch(&type, &value, &tb); + if (value != NULL) { + u = PyObject_Str(value); + if (u != NULL) { + msg = PyString_AsString(u); + } + } + if (msg == NULL) + msg = "unknown decode error"; + Py_XDECREF(type); + Py_XDECREF(value); + Py_XDECREF(tb); + break; + } + case E_LINECONT: + msg = "unexpected character after line continuation character"; + break; + default: + fprintf(stderr, "error=%d\n", err->error); + msg = "unknown parsing error"; + break; + } + v = Py_BuildValue("(ziiz)", err->filename, + err->lineno, err->offset, err->text); + if (err->text != NULL) { + PyObject_FREE(err->text); + err->text = NULL; + } + w = NULL; + if (v != NULL) + w = Py_BuildValue("(sO)", msg, v); + Py_XDECREF(u); + Py_XDECREF(v); + PyErr_SetObject(errtype, w); + Py_XDECREF(w); +} + +/* Print fatal error message and abort */ + +void +Py_FatalError(const char *msg) +{ + fprintf(stderr, "Fatal Python error: %s\n", msg); +#ifdef MS_WINDOWS + OutputDebugString("Fatal Python error: "); + OutputDebugString(msg); + OutputDebugString("\n"); +#ifdef _DEBUG + DebugBreak(); +#endif +#endif /* MS_WINDOWS */ + abort(); +} + +/* Clean up and exit */ + +#ifdef WITH_THREAD +#include "pythread.h" +#endif + +#define NEXITFUNCS 32 +static void (*exitfuncs[NEXITFUNCS])(void); +static int nexitfuncs = 0; + +int Py_AtExit(void (*func)(void)) +{ + if (nexitfuncs >= NEXITFUNCS) + return -1; + exitfuncs[nexitfuncs++] = func; + return 0; +} + +static void +call_sys_exitfunc(void) +{ + PyObject *exitfunc = PySys_GetObject("exitfunc"); + + if (exitfunc) { + PyObject *res; + Py_INCREF(exitfunc); + PySys_SetObject("exitfunc", (PyObject *)NULL); + res = PyEval_CallObject(exitfunc, (PyObject *)NULL); + if (res == NULL) { + if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { + PySys_WriteStderr("Error in sys.exitfunc:\n"); + } + PyErr_Print(); + } + Py_DECREF(exitfunc); + } + + if (Py_FlushLine()) + PyErr_Clear(); +} + +static void +call_ll_exitfuncs(void) +{ + while (nexitfuncs > 0) + (*exitfuncs[--nexitfuncs])(); + + fflush(stdout); + fflush(stderr); +} + +void +Py_Exit(int sts) +{ + Py_Finalize(); + + exit(sts); +} + +static void +initsigs(void) +{ +#ifdef SIGPIPE + PyOS_setsig(SIGPIPE, SIG_IGN); +#endif +#ifdef SIGXFZ + PyOS_setsig(SIGXFZ, SIG_IGN); +#endif +#ifdef SIGXFSZ + PyOS_setsig(SIGXFSZ, SIG_IGN); +#endif + PyOS_InitInterrupts(); /* May imply initsignal() */ +} + + +/* + * The file descriptor fd is considered ``interactive'' if either + * a) isatty(fd) is TRUE, or + * b) the -i flag was given, and the filename associated with + * the descriptor is NULL or "<stdin>" or "???". + */ +int +Py_FdIsInteractive(FILE *fp, const char *filename) +{ + if (isatty((int)fileno(fp))) + return 1; + if (!Py_InteractiveFlag) + return 0; + return (filename == NULL) || + (strcmp(filename, "<stdin>") == 0) || + (strcmp(filename, "???") == 0); +} + + +#if defined(USE_STACKCHECK) +#if defined(WIN32) && defined(_MSC_VER) + +/* Stack checking for Microsoft C */ + +#include <malloc.h> +#include <excpt.h> + +/* + * Return non-zero when we run out of memory on the stack; zero otherwise. + */ +int +PyOS_CheckStack(void) +{ + __try { + /* alloca throws a stack overflow exception if there's + not enough space left on the stack */ + alloca(PYOS_STACK_MARGIN * sizeof(void*)); + return 0; + } __except (EXCEPTION_EXECUTE_HANDLER) { + /* just ignore all errors */ + } + return 1; +} + +#endif /* WIN32 && _MSC_VER */ + +/* Alternate implementations can be added here... */ + +#endif /* USE_STACKCHECK */ + + +/* Wrappers around sigaction() or signal(). */ + +PyOS_sighandler_t +PyOS_getsig(int sig) +{ +#ifdef HAVE_SIGACTION + struct sigaction context; + if (sigaction(sig, NULL, &context) == -1) + return SIG_ERR; + return context.sa_handler; +#else + PyOS_sighandler_t handler; +/* Special signal handling for the secure CRT in Visual Studio 2005 */ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + switch (sig) { + /* Only these signals are valid */ + case SIGINT: + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGTERM: + case SIGBREAK: + case SIGABRT: + break; + /* Don't call signal() with other values or it will assert */ + default: + return SIG_ERR; + } +#endif /* _MSC_VER && _MSC_VER >= 1400 */ + handler = signal(sig, SIG_IGN); + if (handler != SIG_ERR) + signal(sig, handler); + return handler; +#endif +} + +PyOS_sighandler_t +PyOS_setsig(int sig, PyOS_sighandler_t handler) +{ +#ifdef HAVE_SIGACTION + struct sigaction context, ocontext; + context.sa_handler = handler; + sigemptyset(&context.sa_mask); + context.sa_flags = 0; + if (sigaction(sig, &context, &ocontext) == -1) + return SIG_ERR; + return ocontext.sa_handler; +#else + PyOS_sighandler_t oldhandler; + oldhandler = signal(sig, handler); +#ifdef HAVE_SIGINTERRUPT + siginterrupt(sig, 1); +#endif + return oldhandler; +#endif +} + +/* Deprecated C API functions still provided for binary compatiblity */ + +#undef PyParser_SimpleParseFile +PyAPI_FUNC(node *) +PyParser_SimpleParseFile(FILE *fp, const char *filename, int start) +{ + return PyParser_SimpleParseFileFlags(fp, filename, start, 0); +} + +#undef PyParser_SimpleParseString +PyAPI_FUNC(node *) +PyParser_SimpleParseString(const char *str, int start) +{ + return PyParser_SimpleParseStringFlags(str, start, 0); +} + +#undef PyRun_AnyFile +PyAPI_FUNC(int) +PyRun_AnyFile(FILE *fp, const char *name) +{ + return PyRun_AnyFileExFlags(fp, name, 0, NULL); +} + +#undef PyRun_AnyFileEx +PyAPI_FUNC(int) +PyRun_AnyFileEx(FILE *fp, const char *name, int closeit) +{ + return PyRun_AnyFileExFlags(fp, name, closeit, NULL); +} + +#undef PyRun_AnyFileFlags +PyAPI_FUNC(int) +PyRun_AnyFileFlags(FILE *fp, const char *name, PyCompilerFlags *flags) +{ + return PyRun_AnyFileExFlags(fp, name, 0, flags); +} + +#undef PyRun_File +PyAPI_FUNC(PyObject *) +PyRun_File(FILE *fp, const char *p, int s, PyObject *g, PyObject *l) +{ + return PyRun_FileExFlags(fp, p, s, g, l, 0, NULL); +} + +#undef PyRun_FileEx +PyAPI_FUNC(PyObject *) +PyRun_FileEx(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, int c) +{ + return PyRun_FileExFlags(fp, p, s, g, l, c, NULL); +} + +#undef PyRun_FileFlags +PyAPI_FUNC(PyObject *) +PyRun_FileFlags(FILE *fp, const char *p, int s, PyObject *g, PyObject *l, + PyCompilerFlags *flags) +{ + return PyRun_FileExFlags(fp, p, s, g, l, 0, flags); +} + +#undef PyRun_SimpleFile +PyAPI_FUNC(int) +PyRun_SimpleFile(FILE *f, const char *p) +{ + return PyRun_SimpleFileExFlags(f, p, 0, NULL); +} + +#undef PyRun_SimpleFileEx +PyAPI_FUNC(int) +PyRun_SimpleFileEx(FILE *f, const char *p, int c) +{ + return PyRun_SimpleFileExFlags(f, p, c, NULL); +} + + +#undef PyRun_String +PyAPI_FUNC(PyObject *) +PyRun_String(const char *str, int s, PyObject *g, PyObject *l) +{ + return PyRun_StringFlags(str, s, g, l, NULL); +} + +#undef PyRun_SimpleString +PyAPI_FUNC(int) +PyRun_SimpleString(const char *s) +{ + return PyRun_SimpleStringFlags(s, NULL); +} + +#undef Py_CompileString +PyAPI_FUNC(PyObject *) +Py_CompileString(const char *str, const char *p, int s) +{ + return Py_CompileStringFlags(str, p, s, NULL); +} + +#undef PyRun_InteractiveOne +PyAPI_FUNC(int) +PyRun_InteractiveOne(FILE *f, const char *p) +{ + return PyRun_InteractiveOneFlags(f, p, NULL); +} + +#undef PyRun_InteractiveLoop +PyAPI_FUNC(int) +PyRun_InteractiveLoop(FILE *f, const char *p) +{ + return PyRun_InteractiveLoopFlags(f, p, NULL); +} + +#ifdef __cplusplus +} +#endif + diff --git a/sys/src/cmd/python/Python/sigcheck.c b/sys/src/cmd/python/Python/sigcheck.c new file mode 100644 index 000000000..022d0e8ac --- /dev/null +++ b/sys/src/cmd/python/Python/sigcheck.c @@ -0,0 +1,19 @@ + +/* Sigcheck is similar to intrcheck() but sets an exception when an + interrupt occurs. It can't be in the intrcheck.c file since that + file (and the whole directory it is in) doesn't know about objects + or exceptions. It can't be in errors.c because it can be + overridden (at link time) by a more powerful version implemented in + signalmodule.c. */ + +#include "Python.h" + +/* ARGSUSED */ +int +PyErr_CheckSignals(void) +{ + if (!PyOS_InterruptOccurred()) + return 0; + PyErr_SetNone(PyExc_KeyboardInterrupt); + return -1; +} diff --git a/sys/src/cmd/python/Python/strdup.c b/sys/src/cmd/python/Python/strdup.c new file mode 100644 index 000000000..20187e0f0 --- /dev/null +++ b/sys/src/cmd/python/Python/strdup.c @@ -0,0 +1,14 @@ +/* strdup() replacement (from stdwin, if you must know) */ + +#include "pgenheaders.h" + +char * +strdup(const char *str) +{ + if (str != NULL) { + register char *copy = malloc(strlen(str) + 1); + if (copy != NULL) + return strcpy(copy, str); + } + return NULL; +} diff --git a/sys/src/cmd/python/Python/strerror.c b/sys/src/cmd/python/Python/strerror.c new file mode 100644 index 000000000..55f8342ec --- /dev/null +++ b/sys/src/cmd/python/Python/strerror.c @@ -0,0 +1,19 @@ + +/* PD implementation of strerror() for systems that don't have it. + Author: Guido van Rossum, CWI Amsterdam, Oct. 1990, <guido@cwi.nl>. */ + +#include <stdio.h> +#include "Python.h" + +extern int sys_nerr; +extern char *sys_errlist[]; + +char * +strerror(int err) +{ + static char buf[20]; + if (err >= 0 && err < sys_nerr) + return sys_errlist[err]; + PyOS_snprintf(buf, sizeof(buf), "Unknown errno %d", err); + return buf; +} diff --git a/sys/src/cmd/python/Python/strtod.c b/sys/src/cmd/python/Python/strtod.c new file mode 100644 index 000000000..5c084a4de --- /dev/null +++ b/sys/src/cmd/python/Python/strtod.c @@ -0,0 +1,156 @@ +#include "pyconfig.h" + +/* comp.sources.misc strtod(), as posted in comp.lang.tcl, + with bugfix for "123000.0" and acceptance of space after 'e' sign nuked. + + ************************************************************ + * YOU MUST EDIT THE MACHINE-DEPENDENT DEFINITIONS BELOW!!! * + ************************************************************ +*/ + +/* File : stdtod.c (Modified version of str2dbl.c) + Author : Richard A. O'Keefe @ Quintus Computer Systems, Inc. + Updated: Tuesday August 2nd, 1988 + Defines: double strtod (char *str, char**ptr) +*/ + +/* This is an implementation of the strtod() function described in the + System V manuals, with a different name to avoid linker problems. + All that str2dbl() does itself is check that the argument is well-formed + and is in range. It leaves the work of conversion to atof(), which is + assumed to exist and deliver correct results (if they can be represented). + + There are two reasons why this should be provided to the net: + (a) some UNIX systems do not yet have strtod(), or do not have it + available in the BSD "universe" (but they do have atof()). + (b) some of the UNIX systems that *do* have it get it wrong. + (some crash with large arguments, some assign the wrong *ptr value). + There is a reason why *we* are providing it: we need a correct version + of strtod(), and if we give this one away maybe someone will look for + mistakes in it and fix them for us (:-). +*/ + +/* The following constants are machine-specific. MD{MIN,MAX}EXPT are + integers and MD{MIN,MAX}FRAC are strings such that + 0.${MDMAXFRAC}e${MDMAXEXPT} is the largest representable double, + 0.${MDMINFRAC}e${MDMINEXPT} is the smallest representable +ve double + MD{MIN,MAX}FRAC must not have any trailing zeros. + The values here are for IEEE-754 64-bit floats. + It is not perfectly clear to me whether an IEEE infinity should be + returned for overflow, nor what a portable way of writing one is, + so HUGE is just 0.MAXFRAC*10**MAXEXPT (this seems still to be the + UNIX convention). + + I do know about <values.h>, but the whole point of this file is that + we can't always trust that stuff to be there or to be correct. +*/ +static int MDMINEXPT = {-323}; +static char MDMINFRAC[] = "494065645841246544"; +static double ZERO = 0.0; + +static int MDMAXEXPT = { 309}; +static char MDMAXFRAC[] = "17976931348623157"; +static double HUGE = 1.7976931348623157e308; + +extern double atof(const char *); /* Only called when result known to be ok */ + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +extern int errno; + +double strtod(char *str, char **ptr) +{ + int sign, scale, dotseen; + int esign, expt; + char *save; + register char *sp, *dp; + register int c; + char *buforg, *buflim; + char buffer[64]; /* 45-digit significant + */ + /* 13-digit exponent */ + sp = str; + while (*sp == ' ') sp++; + sign = 1; + if (*sp == '-') sign -= 2, sp++; + dotseen = 0, scale = 0; + dp = buffer; + *dp++ = '0'; *dp++ = '.'; + buforg = dp, buflim = buffer+48; + for (save = sp; c = *sp; sp++) + if (c == '.') { + if (dotseen) break; + dotseen++; + } else + if ((unsigned)(c-'0') > (unsigned)('9'-'0')) { + break; + } else + if (c == '0') { + if (dp != buforg) { + /* This is not the first digit, so we want to keep it */ + if (dp < buflim) *dp++ = c; + if (!dotseen) scale++; + } else { + /* No non-zero digits seen yet */ + /* If a . has been seen, scale must be adjusted */ + if (dotseen) scale--; + } + } else { + /* This is a nonzero digit, so we want to keep it */ + if (dp < buflim) *dp++ = c; + /* If it precedes a ., scale must be adjusted */ + if (!dotseen) scale++; + } + if (sp == save) { + if (ptr) *ptr = str; + errno = EDOM; /* what should this be? */ + return ZERO; + } + + while (dp > buforg && dp[-1] == '0') --dp; + if (dp == buforg) *dp++ = '0'; + *dp = '\0'; + /* Now the contents of buffer are + +--+--------+-+--------+ + |0.|fraction|\|leftover| + +--+--------+-+--------+ + ^dp points here + where fraction begins with 0 iff it is "0", and has at most + 45 digits in it, and leftover is at least 16 characters. + */ + save = sp, expt = 0, esign = 1; + do { + c = *sp++; + if (c != 'e' && c != 'E') break; + c = *sp++; + if (c == '-') esign -= 2, c = *sp++; else + if (c == '+' /* || c == ' ' */ ) c = *sp++; + if ((unsigned)(c-'0') > (unsigned)('9'-'0')) break; + while (c == '0') c = *sp++; + for (; (unsigned)(c-'0') <= (unsigned)('9'-'0'); c = *sp++) + expt = expt*10 + c-'0'; + if (esign < 0) expt = -expt; + save = sp-1; + } while (0); + if (ptr) *ptr = save; + expt += scale; + /* Now the number is sign*0.fraction*10**expt */ + errno = ERANGE; + if (expt > MDMAXEXPT) { + return HUGE*sign; + } else + if (expt == MDMAXEXPT) { + if (strcmp(buforg, MDMAXFRAC) > 0) return HUGE*sign; + } else + if (expt < MDMINEXPT) { + return ZERO*sign; + } else + if (expt == MDMINEXPT) { + if (strcmp(buforg, MDMINFRAC) < 0) return ZERO*sign; + } + /* We have now established that the number can be */ + /* represented without overflow or underflow */ + (void) sprintf(dp, "E%d", expt); + errno = 0; + return atof(buffer)*sign; +} diff --git a/sys/src/cmd/python/Python/structmember.c b/sys/src/cmd/python/Python/structmember.c new file mode 100644 index 000000000..03934c0c8 --- /dev/null +++ b/sys/src/cmd/python/Python/structmember.c @@ -0,0 +1,312 @@ + +/* Map C struct members to Python object attributes */ + +#include "Python.h" + +#include "structmember.h" + +static PyObject * +listmembers(struct memberlist *mlist) +{ + int i, n; + PyObject *v; + for (n = 0; mlist[n].name != NULL; n++) + ; + v = PyList_New(n); + if (v != NULL) { + for (i = 0; i < n; i++) + PyList_SetItem(v, i, + PyString_FromString(mlist[i].name)); + if (PyErr_Occurred()) { + Py_DECREF(v); + v = NULL; + } + else { + PyList_Sort(v); + } + } + return v; +} + +PyObject * +PyMember_Get(const char *addr, struct memberlist *mlist, const char *name) +{ + struct memberlist *l; + + if (strcmp(name, "__members__") == 0) + return listmembers(mlist); + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + PyMemberDef copy; + copy.name = l->name; + copy.type = l->type; + copy.offset = l->offset; + copy.flags = l->flags; + copy.doc = NULL; + return PyMember_GetOne(addr, &copy); + } + } + PyErr_SetString(PyExc_AttributeError, name); + return NULL; +} + +PyObject * +PyMember_GetOne(const char *addr, PyMemberDef *l) +{ + PyObject *v; + if ((l->flags & READ_RESTRICTED) && + PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); + return NULL; + } + addr += l->offset; + switch (l->type) { + case T_BYTE: + v = PyInt_FromLong(*(char*)addr); + break; + case T_UBYTE: + v = PyLong_FromUnsignedLong(*(unsigned char*)addr); + break; + case T_SHORT: + v = PyInt_FromLong(*(short*)addr); + break; + case T_USHORT: + v = PyLong_FromUnsignedLong(*(unsigned short*)addr); + break; + case T_INT: + v = PyInt_FromLong(*(int*)addr); + break; + case T_UINT: + v = PyLong_FromUnsignedLong(*(unsigned int*)addr); + break; + case T_LONG: + v = PyInt_FromLong(*(long*)addr); + break; + case T_ULONG: + v = PyLong_FromUnsignedLong(*(unsigned long*)addr); + break; + case T_FLOAT: + v = PyFloat_FromDouble((double)*(float*)addr); + break; + case T_DOUBLE: + v = PyFloat_FromDouble(*(double*)addr); + break; + case T_STRING: + if (*(char**)addr == NULL) { + Py_INCREF(Py_None); + v = Py_None; + } + else + v = PyString_FromString(*(char**)addr); + break; + case T_STRING_INPLACE: + v = PyString_FromString((char*)addr); + break; + case T_CHAR: + v = PyString_FromStringAndSize((char*)addr, 1); + break; + case T_OBJECT: + v = *(PyObject **)addr; + if (v == NULL) + v = Py_None; + Py_INCREF(v); + break; + case T_OBJECT_EX: + v = *(PyObject **)addr; + if (v == NULL) + PyErr_SetString(PyExc_AttributeError, l->name); + Py_XINCREF(v); + break; +#ifdef HAVE_LONG_LONG + case T_LONGLONG: + v = PyLong_FromLongLong(*(PY_LONG_LONG *)addr); + break; + case T_ULONGLONG: + v = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)addr); + break; +#endif /* HAVE_LONG_LONG */ + default: + PyErr_SetString(PyExc_SystemError, "bad memberdescr type"); + v = NULL; + } + return v; +} + +int +PyMember_Set(char *addr, struct memberlist *mlist, const char *name, PyObject *v) +{ + struct memberlist *l; + + for (l = mlist; l->name != NULL; l++) { + if (strcmp(l->name, name) == 0) { + PyMemberDef copy; + copy.name = l->name; + copy.type = l->type; + copy.offset = l->offset; + copy.flags = l->flags; + copy.doc = NULL; + return PyMember_SetOne(addr, &copy, v); + } + } + + PyErr_SetString(PyExc_AttributeError, name); + return -1; +} + +int +PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v) +{ + PyObject *oldv; + + if ((l->flags & READONLY) || l->type == T_STRING) + { + PyErr_SetString(PyExc_TypeError, "readonly attribute"); + return -1; + } + if ((l->flags & WRITE_RESTRICTED) && PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, "restricted attribute"); + return -1; + } + if (v == NULL && l->type != T_OBJECT_EX && l->type != T_OBJECT) { + PyErr_SetString(PyExc_TypeError, + "can't delete numeric/char attribute"); + return -1; + } + addr += l->offset; + switch (l->type) { + case T_BYTE:{ + long long_val; + long_val = PyInt_AsLong(v); + if ((long_val == -1) && PyErr_Occurred()) + return -1; + *(char*)addr = (char)long_val; + break; + } + case T_UBYTE:{ + long long_val; + long_val = PyInt_AsLong(v); + if ((long_val == -1) && PyErr_Occurred()) + return -1; + *(unsigned char*)addr = (unsigned char)long_val; + break; + } + case T_SHORT:{ + long long_val; + long_val = PyInt_AsLong(v); + if ((long_val == -1) && PyErr_Occurred()) + return -1; + *(short*)addr = (short)long_val; + break; + } + case T_USHORT:{ + long long_val; + long_val = PyInt_AsLong(v); + if ((long_val == -1) && PyErr_Occurred()) + return -1; + *(unsigned short*)addr = (unsigned short)long_val; + break; + } + case T_INT:{ + long long_val; + long_val = PyInt_AsLong(v); + if ((long_val == -1) && PyErr_Occurred()) + return -1; + *(int *)addr = (int)long_val; + break; + } + case T_UINT:{ + unsigned long ulong_val; + ulong_val = PyLong_AsUnsignedLong(v); + if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) { + /* XXX: For compatibility, accept negative int values + as well. */ + PyErr_Clear(); + ulong_val = PyLong_AsLong(v); + if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) + return -1; + } + *(unsigned int *)addr = (unsigned int)ulong_val; + break; + } + case T_LONG:{ + *(long*)addr = PyLong_AsLong(v); + if ((*(long*)addr == -1) && PyErr_Occurred()) + return -1; + break; + } + case T_ULONG:{ + *(unsigned long*)addr = PyLong_AsUnsignedLong(v); + if ((*(unsigned long*)addr == (unsigned long)-1) + && PyErr_Occurred()) { + /* XXX: For compatibility, accept negative int values + as well. */ + PyErr_Clear(); + *(unsigned long*)addr = PyLong_AsLong(v); + if ((*(unsigned long*)addr == (unsigned int)-1) && PyErr_Occurred()) + return -1; + } + break; + } + case T_FLOAT:{ + double double_val; + double_val = PyFloat_AsDouble(v); + if ((double_val == -1) && PyErr_Occurred()) + return -1; + *(float*)addr = (float)double_val; + break; + } + case T_DOUBLE: + *(double*)addr = PyFloat_AsDouble(v); + if ((*(double*)addr == -1) && PyErr_Occurred()) + return -1; + break; + case T_OBJECT: + case T_OBJECT_EX: + Py_XINCREF(v); + oldv = *(PyObject **)addr; + *(PyObject **)addr = v; + Py_XDECREF(oldv); + break; + case T_CHAR: + if (PyString_Check(v) && PyString_Size(v) == 1) { + *(char*)addr = PyString_AsString(v)[0]; + } + else { + PyErr_BadArgument(); + return -1; + } + break; +#ifdef HAVE_LONG_LONG + case T_LONGLONG: + if (!PyLong_Check(v)) { + PyErr_BadArgument(); + return -1; + } else { + PY_LONG_LONG value; + *(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v); + if ((value == -1) && PyErr_Occurred()) { + return -1; + } + } + break; + case T_ULONGLONG: + if (!PyLong_Check(v)) { + PyErr_BadArgument(); + return -1; + } else { + unsigned PY_LONG_LONG value; + *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v); + if ((value == (unsigned PY_LONG_LONG)-1) && + PyErr_Occurred()) { + return -1; + } + } + break; +#endif /* HAVE_LONG_LONG */ + default: + PyErr_Format(PyExc_SystemError, + "bad memberdescr type for %s", l->name); + return -1; + } + return 0; +} diff --git a/sys/src/cmd/python/Python/symtable.c b/sys/src/cmd/python/Python/symtable.c new file mode 100644 index 000000000..3e58b5034 --- /dev/null +++ b/sys/src/cmd/python/Python/symtable.c @@ -0,0 +1,1425 @@ +#include "Python.h" +#include "Python-ast.h" +#include "code.h" +#include "symtable.h" +#include "structmember.h" + +/* error strings used for warnings */ +#define GLOBAL_AFTER_ASSIGN \ +"name '%.400s' is assigned to before global declaration" + +#define GLOBAL_AFTER_USE \ +"name '%.400s' is used prior to global declaration" + +#define IMPORT_STAR_WARNING "import * only allowed at module level" + +#define RETURN_VAL_IN_GENERATOR \ + "'return' with argument inside generator" + +/* XXX(nnorwitz): change name since static? */ +static PySTEntryObject * +PySTEntry_New(struct symtable *st, identifier name, _Py_block_ty block, + void *key, int lineno) +{ + PySTEntryObject *ste = NULL; + PyObject *k; + + k = PyLong_FromVoidPtr(key); + if (k == NULL) + goto fail; + ste = (PySTEntryObject *)PyObject_New(PySTEntryObject, + &PySTEntry_Type); + ste->ste_table = st; + ste->ste_id = k; + ste->ste_tmpname = 0; + + ste->ste_name = name; + Py_INCREF(name); + + ste->ste_symbols = NULL; + ste->ste_varnames = NULL; + ste->ste_children = NULL; + + ste->ste_symbols = PyDict_New(); + if (ste->ste_symbols == NULL) + goto fail; + + ste->ste_varnames = PyList_New(0); + if (ste->ste_varnames == NULL) + goto fail; + + ste->ste_children = PyList_New(0); + if (ste->ste_children == NULL) + goto fail; + + ste->ste_type = block; + ste->ste_unoptimized = 0; + ste->ste_nested = 0; + ste->ste_free = 0; + ste->ste_varargs = 0; + ste->ste_varkeywords = 0; + ste->ste_opt_lineno = 0; + ste->ste_tmpname = 0; + ste->ste_lineno = lineno; + + if (st->st_cur != NULL && + (st->st_cur->ste_nested || + st->st_cur->ste_type == FunctionBlock)) + ste->ste_nested = 1; + ste->ste_child_free = 0; + ste->ste_generator = 0; + ste->ste_returns_value = 0; + + if (PyDict_SetItem(st->st_symbols, ste->ste_id, (PyObject *)ste) < 0) + goto fail; + + return ste; + fail: + Py_XDECREF(ste); + return NULL; +} + +static PyObject * +ste_repr(PySTEntryObject *ste) +{ + char buf[256]; + + PyOS_snprintf(buf, sizeof(buf), + "<symtable entry %.100s(%ld), line %d>", + PyString_AS_STRING(ste->ste_name), + PyInt_AS_LONG(ste->ste_id), ste->ste_lineno); + return PyString_FromString(buf); +} + +static void +ste_dealloc(PySTEntryObject *ste) +{ + ste->ste_table = NULL; + Py_XDECREF(ste->ste_id); + Py_XDECREF(ste->ste_name); + Py_XDECREF(ste->ste_symbols); + Py_XDECREF(ste->ste_varnames); + Py_XDECREF(ste->ste_children); + PyObject_Del(ste); +} + +#define OFF(x) offsetof(PySTEntryObject, x) + +static PyMemberDef ste_memberlist[] = { + {"id", T_OBJECT, OFF(ste_id), READONLY}, + {"name", T_OBJECT, OFF(ste_name), READONLY}, + {"symbols", T_OBJECT, OFF(ste_symbols), READONLY}, + {"varnames", T_OBJECT, OFF(ste_varnames), READONLY}, + {"children", T_OBJECT, OFF(ste_children), READONLY}, + {"type", T_INT, OFF(ste_type), READONLY}, + {"lineno", T_INT, OFF(ste_lineno), READONLY}, + {NULL} +}; + +PyTypeObject PySTEntry_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "symtable entry", + sizeof(PySTEntryObject), + 0, + (destructor)ste_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)ste_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + ste_memberlist, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +static int symtable_analyze(struct symtable *st); +static int symtable_warn(struct symtable *st, char *msg, int lineno); +static int symtable_enter_block(struct symtable *st, identifier name, + _Py_block_ty block, void *ast, int lineno); +static int symtable_exit_block(struct symtable *st, void *ast); +static int symtable_visit_stmt(struct symtable *st, stmt_ty s); +static int symtable_visit_expr(struct symtable *st, expr_ty s); +static int symtable_visit_genexp(struct symtable *st, expr_ty s); +static int symtable_visit_arguments(struct symtable *st, arguments_ty); +static int symtable_visit_excepthandler(struct symtable *st, excepthandler_ty); +static int symtable_visit_alias(struct symtable *st, alias_ty); +static int symtable_visit_comprehension(struct symtable *st, comprehension_ty); +static int symtable_visit_keyword(struct symtable *st, keyword_ty); +static int symtable_visit_slice(struct symtable *st, slice_ty); +static int symtable_visit_params(struct symtable *st, asdl_seq *args, int top); +static int symtable_visit_params_nested(struct symtable *st, asdl_seq *args); +static int symtable_implicit_arg(struct symtable *st, int pos); + + +static identifier top = NULL, lambda = NULL, genexpr = NULL; + +#define GET_IDENTIFIER(VAR) \ + ((VAR) ? (VAR) : ((VAR) = PyString_InternFromString(# VAR))) + +#define DUPLICATE_ARGUMENT \ +"duplicate argument '%s' in function definition" + +static struct symtable * +symtable_new(void) +{ + struct symtable *st; + + st = (struct symtable *)PyMem_Malloc(sizeof(struct symtable)); + if (st == NULL) + return NULL; + + st->st_filename = NULL; + st->st_symbols = NULL; + + if ((st->st_stack = PyList_New(0)) == NULL) + goto fail; + if ((st->st_symbols = PyDict_New()) == NULL) + goto fail; + st->st_cur = NULL; + st->st_tmpname = 0; + st->st_private = NULL; + return st; + fail: + PySymtable_Free(st); + return NULL; +} + +struct symtable * +PySymtable_Build(mod_ty mod, const char *filename, PyFutureFeatures *future) +{ + struct symtable *st = symtable_new(); + asdl_seq *seq; + int i; + + if (st == NULL) + return st; + st->st_filename = filename; + st->st_future = future; + if (!symtable_enter_block(st, GET_IDENTIFIER(top), ModuleBlock, + (void *)mod, 0)) { + PySymtable_Free(st); + return NULL; + } + + st->st_top = st->st_cur; + st->st_cur->ste_unoptimized = OPT_TOPLEVEL; + /* Any other top-level initialization? */ + switch (mod->kind) { + case Module_kind: + seq = mod->v.Module.body; + for (i = 0; i < asdl_seq_LEN(seq); i++) + if (!symtable_visit_stmt(st, + (stmt_ty)asdl_seq_GET(seq, i))) + goto error; + break; + case Expression_kind: + if (!symtable_visit_expr(st, mod->v.Expression.body)) + goto error; + break; + case Interactive_kind: + seq = mod->v.Interactive.body; + for (i = 0; i < asdl_seq_LEN(seq); i++) + if (!symtable_visit_stmt(st, + (stmt_ty)asdl_seq_GET(seq, i))) + goto error; + break; + case Suite_kind: + PyErr_SetString(PyExc_RuntimeError, + "this compiler does not handle Suites"); + goto error; + } + if (!symtable_exit_block(st, (void *)mod)) { + PySymtable_Free(st); + return NULL; + } + if (symtable_analyze(st)) + return st; + PySymtable_Free(st); + return NULL; + error: + (void) symtable_exit_block(st, (void *)mod); + PySymtable_Free(st); + return NULL; +} + +void +PySymtable_Free(struct symtable *st) +{ + Py_XDECREF(st->st_symbols); + Py_XDECREF(st->st_stack); + PyMem_Free((void *)st); +} + +PySTEntryObject * +PySymtable_Lookup(struct symtable *st, void *key) +{ + PyObject *k, *v; + + k = PyLong_FromVoidPtr(key); + if (k == NULL) + return NULL; + v = PyDict_GetItem(st->st_symbols, k); + if (v) { + assert(PySTEntry_Check(v)); + Py_INCREF(v); + } + else { + PyErr_SetString(PyExc_KeyError, + "unknown symbol table entry"); + } + + Py_DECREF(k); + return (PySTEntryObject *)v; +} + +int +PyST_GetScope(PySTEntryObject *ste, PyObject *name) +{ + PyObject *v = PyDict_GetItem(ste->ste_symbols, name); + if (!v) + return 0; + assert(PyInt_Check(v)); + return (PyInt_AS_LONG(v) >> SCOPE_OFF) & SCOPE_MASK; +} + + +/* Analyze raw symbol information to determine scope of each name. + + The next several functions are helpers for PySymtable_Analyze(), + which determines whether a name is local, global, or free. In addition, + it determines which local variables are cell variables; they provide + bindings that are used for free variables in enclosed blocks. + + There are also two kinds of free variables, implicit and explicit. An + explicit global is declared with the global statement. An implicit + global is a free variable for which the compiler has found no binding + in an enclosing function scope. The implicit global is either a global + or a builtin. Python's module and class blocks use the xxx_NAME opcodes + to handle these names to implement slightly odd semantics. In such a + block, the name is treated as global until it is assigned to; then it + is treated as a local. + + The symbol table requires two passes to determine the scope of each name. + The first pass collects raw facts from the AST: the name is a parameter + here, the name is used by not defined here, etc. The second pass analyzes + these facts during a pass over the PySTEntryObjects created during pass 1. + + When a function is entered during the second pass, the parent passes + the set of all name bindings visible to its children. These bindings + are used to determine if the variable is free or an implicit global. + After doing the local analysis, it analyzes each of its child blocks + using an updated set of name bindings. + + The children update the free variable set. If a local variable is free + in a child, the variable is marked as a cell. The current function must + provide runtime storage for the variable that may outlive the function's + frame. Cell variables are removed from the free set before the analyze + function returns to its parent. + + The sets of bound and free variables are implemented as dictionaries + mapping strings to None. +*/ + +#define SET_SCOPE(DICT, NAME, I) { \ + PyObject *o = PyInt_FromLong(I); \ + if (!o) \ + return 0; \ + if (PyDict_SetItem((DICT), (NAME), o) < 0) { \ + Py_DECREF(o); \ + return 0; \ + } \ + Py_DECREF(o); \ +} + +/* Decide on scope of name, given flags. + + The dicts passed in as arguments are modified as necessary. + ste is passed so that flags can be updated. +*/ + +static int +analyze_name(PySTEntryObject *ste, PyObject *dict, PyObject *name, long flags, + PyObject *bound, PyObject *local, PyObject *free, + PyObject *global) +{ + if (flags & DEF_GLOBAL) { + if (flags & DEF_PARAM) { + PyErr_Format(PyExc_SyntaxError, + "name '%s' is local and global", + PyString_AS_STRING(name)); + return 0; + } + SET_SCOPE(dict, name, GLOBAL_EXPLICIT); + if (PyDict_SetItem(global, name, Py_None) < 0) + return 0; + if (bound && PyDict_GetItem(bound, name)) { + if (PyDict_DelItem(bound, name) < 0) + return 0; + } + return 1; + } + if (flags & DEF_BOUND) { + SET_SCOPE(dict, name, LOCAL); + if (PyDict_SetItem(local, name, Py_None) < 0) + return 0; + if (PyDict_GetItem(global, name)) { + if (PyDict_DelItem(global, name) < 0) + return 0; + } + return 1; + } + /* If an enclosing block has a binding for this name, it + is a free variable rather than a global variable. + Note that having a non-NULL bound implies that the block + is nested. + */ + if (bound && PyDict_GetItem(bound, name)) { + SET_SCOPE(dict, name, FREE); + ste->ste_free = 1; + if (PyDict_SetItem(free, name, Py_None) < 0) + return 0; + return 1; + } + /* If a parent has a global statement, then call it global + explicit? It could also be global implicit. + */ + else if (global && PyDict_GetItem(global, name)) { + SET_SCOPE(dict, name, GLOBAL_EXPLICIT); + return 1; + } + else { + if (ste->ste_nested) + ste->ste_free = 1; + SET_SCOPE(dict, name, GLOBAL_IMPLICIT); + return 1; + } + return 0; /* Can't get here */ +} + +#undef SET_SCOPE + +/* If a name is defined in free and also in locals, then this block + provides the binding for the free variable. The name should be + marked CELL in this block and removed from the free list. + + Note that the current block's free variables are included in free. + That's safe because no name can be free and local in the same scope. +*/ + +static int +analyze_cells(PyObject *scope, PyObject *free) +{ + PyObject *name, *v, *w; + int success = 0; + Py_ssize_t pos = 0; + + w = PyInt_FromLong(CELL); + if (!w) + return 0; + while (PyDict_Next(scope, &pos, &name, &v)) { + long flags; + assert(PyInt_Check(v)); + flags = PyInt_AS_LONG(v); + if (flags != LOCAL) + continue; + if (!PyDict_GetItem(free, name)) + continue; + /* Replace LOCAL with CELL for this name, and remove + from free. It is safe to replace the value of name + in the dict, because it will not cause a resize. + */ + if (PyDict_SetItem(scope, name, w) < 0) + goto error; + if (!PyDict_DelItem(free, name) < 0) + goto error; + } + success = 1; + error: + Py_DECREF(w); + return success; +} + +/* Check for illegal statements in unoptimized namespaces */ +static int +check_unoptimized(const PySTEntryObject* ste) { + char buf[300]; + const char* trailer; + + if (ste->ste_type != FunctionBlock || !ste->ste_unoptimized + || !(ste->ste_free || ste->ste_child_free)) + return 1; + + trailer = (ste->ste_child_free ? + "contains a nested function with free variables" : + "is a nested function"); + + switch (ste->ste_unoptimized) { + case OPT_TOPLEVEL: /* exec / import * at top-level is fine */ + case OPT_EXEC: /* qualified exec is fine */ + return 1; + case OPT_IMPORT_STAR: + PyOS_snprintf(buf, sizeof(buf), + "import * is not allowed in function '%.100s' " + "because it is %s", + PyString_AS_STRING(ste->ste_name), trailer); + break; + case OPT_BARE_EXEC: + PyOS_snprintf(buf, sizeof(buf), + "unqualified exec is not allowed in function " + "'%.100s' it %s", + PyString_AS_STRING(ste->ste_name), trailer); + break; + default: + PyOS_snprintf(buf, sizeof(buf), + "function '%.100s' uses import * and bare exec, " + "which are illegal because it %s", + PyString_AS_STRING(ste->ste_name), trailer); + break; + } + + PyErr_SetString(PyExc_SyntaxError, buf); + PyErr_SyntaxLocation(ste->ste_table->st_filename, + ste->ste_opt_lineno); + return 0; +} + +/* Enter the final scope information into the st_symbols dict. + * + * All arguments are dicts. Modifies symbols, others are read-only. +*/ +static int +update_symbols(PyObject *symbols, PyObject *scope, + PyObject *bound, PyObject *free, int classflag) +{ + PyObject *name, *v, *u, *w, *free_value = NULL; + Py_ssize_t pos = 0; + + while (PyDict_Next(symbols, &pos, &name, &v)) { + long i, flags; + assert(PyInt_Check(v)); + flags = PyInt_AS_LONG(v); + w = PyDict_GetItem(scope, name); + assert(w && PyInt_Check(w)); + i = PyInt_AS_LONG(w); + flags |= (i << SCOPE_OFF); + u = PyInt_FromLong(flags); + if (!u) + return 0; + if (PyDict_SetItem(symbols, name, u) < 0) { + Py_DECREF(u); + return 0; + } + Py_DECREF(u); + } + + free_value = PyInt_FromLong(FREE << SCOPE_OFF); + if (!free_value) + return 0; + + /* add a free variable when it's only use is for creating a closure */ + pos = 0; + while (PyDict_Next(free, &pos, &name, &v)) { + PyObject *o = PyDict_GetItem(symbols, name); + + if (o) { + /* It could be a free variable in a method of + the class that has the same name as a local + or global in the class scope. + */ + if (classflag && + PyInt_AS_LONG(o) & (DEF_BOUND | DEF_GLOBAL)) { + long i = PyInt_AS_LONG(o) | DEF_FREE_CLASS; + o = PyInt_FromLong(i); + if (!o) { + Py_DECREF(free_value); + return 0; + } + if (PyDict_SetItem(symbols, name, o) < 0) { + Py_DECREF(o); + Py_DECREF(free_value); + return 0; + } + Py_DECREF(o); + } + /* else it's not free, probably a cell */ + continue; + } + if (!PyDict_GetItem(bound, name)) + continue; /* it's a global */ + + if (PyDict_SetItem(symbols, name, free_value) < 0) { + Py_DECREF(free_value); + return 0; + } + } + Py_DECREF(free_value); + return 1; +} + +/* Make final symbol table decisions for block of ste. + Arguments: + ste -- current symtable entry (input/output) + bound -- set of variables bound in enclosing scopes (input) + free -- set of free variables in enclosed scopes (output) + globals -- set of declared global variables in enclosing scopes (input) +*/ + +static int +analyze_block(PySTEntryObject *ste, PyObject *bound, PyObject *free, + PyObject *global) +{ + PyObject *name, *v, *local = NULL, *scope = NULL, *newbound = NULL; + PyObject *newglobal = NULL, *newfree = NULL; + int i, success = 0; + Py_ssize_t pos = 0; + + local = PyDict_New(); + if (!local) + goto error; + scope = PyDict_New(); + if (!scope) + goto error; + newglobal = PyDict_New(); + if (!newglobal) + goto error; + newfree = PyDict_New(); + if (!newfree) + goto error; + newbound = PyDict_New(); + if (!newbound) + goto error; + + if (ste->ste_type == ClassBlock) { + /* make a copy of globals before calling analyze_name(), + because global statements in the class have no effect + on nested functions. + */ + if (PyDict_Update(newglobal, global) < 0) + goto error; + if (bound) + if (PyDict_Update(newbound, bound) < 0) + goto error; + } + + assert(PySTEntry_Check(ste)); + assert(PyDict_Check(ste->ste_symbols)); + while (PyDict_Next(ste->ste_symbols, &pos, &name, &v)) { + long flags = PyInt_AS_LONG(v); + if (!analyze_name(ste, scope, name, flags, bound, local, free, + global)) + goto error; + } + + if (ste->ste_type != ClassBlock) { + if (ste->ste_type == FunctionBlock) { + if (PyDict_Update(newbound, local) < 0) + goto error; + } + if (bound) { + if (PyDict_Update(newbound, bound) < 0) + goto error; + } + if (PyDict_Update(newglobal, global) < 0) + goto error; + } + + /* Recursively call analyze_block() on each child block */ + for (i = 0; i < PyList_GET_SIZE(ste->ste_children); ++i) { + PyObject *c = PyList_GET_ITEM(ste->ste_children, i); + PySTEntryObject* entry; + assert(c && PySTEntry_Check(c)); + entry = (PySTEntryObject*)c; + if (!analyze_block(entry, newbound, newfree, newglobal)) + goto error; + if (entry->ste_free || entry->ste_child_free) + ste->ste_child_free = 1; + } + + if (ste->ste_type == FunctionBlock && !analyze_cells(scope, newfree)) + goto error; + if (!update_symbols(ste->ste_symbols, scope, bound, newfree, + ste->ste_type == ClassBlock)) + goto error; + if (!check_unoptimized(ste)) + goto error; + + if (PyDict_Update(free, newfree) < 0) + goto error; + success = 1; + error: + Py_XDECREF(local); + Py_XDECREF(scope); + Py_XDECREF(newbound); + Py_XDECREF(newglobal); + Py_XDECREF(newfree); + if (!success) + assert(PyErr_Occurred()); + return success; +} + +static int +symtable_analyze(struct symtable *st) +{ + PyObject *free, *global; + int r; + + free = PyDict_New(); + if (!free) + return 0; + global = PyDict_New(); + if (!global) { + Py_DECREF(free); + return 0; + } + r = analyze_block(st->st_top, NULL, free, global); + Py_DECREF(free); + Py_DECREF(global); + return r; +} + + +static int +symtable_warn(struct symtable *st, char *msg, int lineno) +{ + if (PyErr_WarnExplicit(PyExc_SyntaxWarning, msg, st->st_filename, + lineno, NULL, NULL) < 0) { + if (PyErr_ExceptionMatches(PyExc_SyntaxWarning)) { + PyErr_SetString(PyExc_SyntaxError, msg); + PyErr_SyntaxLocation(st->st_filename, + st->st_cur->ste_lineno); + } + return 0; + } + return 1; +} + +/* symtable_enter_block() gets a reference via PySTEntry_New(). + This reference is released when the block is exited, via the DECREF + in symtable_exit_block(). +*/ + +static int +symtable_exit_block(struct symtable *st, void *ast) +{ + Py_ssize_t end; + + Py_CLEAR(st->st_cur); + end = PyList_GET_SIZE(st->st_stack) - 1; + if (end >= 0) { + st->st_cur = (PySTEntryObject *)PyList_GET_ITEM(st->st_stack, + end); + if (st->st_cur == NULL) + return 0; + Py_INCREF(st->st_cur); + if (PySequence_DelItem(st->st_stack, end) < 0) + return 0; + } + return 1; +} + +static int +symtable_enter_block(struct symtable *st, identifier name, _Py_block_ty block, + void *ast, int lineno) +{ + PySTEntryObject *prev = NULL; + + if (st->st_cur) { + prev = st->st_cur; + if (PyList_Append(st->st_stack, (PyObject *)st->st_cur) < 0) { + return 0; + } + Py_DECREF(st->st_cur); + } + st->st_cur = PySTEntry_New(st, name, block, ast, lineno); + if (st->st_cur == NULL) + return 0; + if (name == GET_IDENTIFIER(top)) + st->st_global = st->st_cur->ste_symbols; + if (prev) { + if (PyList_Append(prev->ste_children, + (PyObject *)st->st_cur) < 0) { + return 0; + } + } + return 1; +} + +static long +symtable_lookup(struct symtable *st, PyObject *name) +{ + PyObject *o; + PyObject *mangled = _Py_Mangle(st->st_private, name); + if (!mangled) + return 0; + o = PyDict_GetItem(st->st_cur->ste_symbols, mangled); + Py_DECREF(mangled); + if (!o) + return 0; + return PyInt_AsLong(o); +} + +static int +symtable_add_def(struct symtable *st, PyObject *name, int flag) +{ + PyObject *o; + PyObject *dict; + long val; + PyObject *mangled = _Py_Mangle(st->st_private, name); + + if (!mangled) + return 0; + dict = st->st_cur->ste_symbols; + if ((o = PyDict_GetItem(dict, mangled))) { + val = PyInt_AS_LONG(o); + if ((flag & DEF_PARAM) && (val & DEF_PARAM)) { + /* Is it better to use 'mangled' or 'name' here? */ + PyErr_Format(PyExc_SyntaxError, DUPLICATE_ARGUMENT, + PyString_AsString(name)); + PyErr_SyntaxLocation(st->st_filename, + st->st_cur->ste_lineno); + goto error; + } + val |= flag; + } else + val = flag; + o = PyInt_FromLong(val); + if (o == NULL) + goto error; + if (PyDict_SetItem(dict, mangled, o) < 0) { + Py_DECREF(o); + goto error; + } + Py_DECREF(o); + + if (flag & DEF_PARAM) { + if (PyList_Append(st->st_cur->ste_varnames, mangled) < 0) + goto error; + } else if (flag & DEF_GLOBAL) { + /* XXX need to update DEF_GLOBAL for other flags too; + perhaps only DEF_FREE_GLOBAL */ + val = flag; + if ((o = PyDict_GetItem(st->st_global, mangled))) { + val |= PyInt_AS_LONG(o); + } + o = PyInt_FromLong(val); + if (o == NULL) + goto error; + if (PyDict_SetItem(st->st_global, mangled, o) < 0) { + Py_DECREF(o); + goto error; + } + Py_DECREF(o); + } + Py_DECREF(mangled); + return 1; + +error: + Py_DECREF(mangled); + return 0; +} + +/* VISIT, VISIT_SEQ and VIST_SEQ_TAIL take an ASDL type as their second argument. + They use the ASDL name to synthesize the name of the C type and the visit + function. + + VISIT_SEQ_TAIL permits the start of an ASDL sequence to be skipped, which is + useful if the first node in the sequence requires special treatment. +*/ + +#define VISIT(ST, TYPE, V) \ + if (!symtable_visit_ ## TYPE((ST), (V))) \ + return 0; + +#define VISIT_IN_BLOCK(ST, TYPE, V, S) \ + if (!symtable_visit_ ## TYPE((ST), (V))) { \ + symtable_exit_block((ST), (S)); \ + return 0; \ + } + +#define VISIT_SEQ(ST, TYPE, SEQ) { \ + int i; \ + asdl_seq *seq = (SEQ); /* avoid variable capture */ \ + for (i = 0; i < asdl_seq_LEN(seq); i++) { \ + TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ + if (!symtable_visit_ ## TYPE((ST), elt)) \ + return 0; \ + } \ +} + +#define VISIT_SEQ_IN_BLOCK(ST, TYPE, SEQ, S) { \ + int i; \ + asdl_seq *seq = (SEQ); /* avoid variable capture */ \ + for (i = 0; i < asdl_seq_LEN(seq); i++) { \ + TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ + if (!symtable_visit_ ## TYPE((ST), elt)) { \ + symtable_exit_block((ST), (S)); \ + return 0; \ + } \ + } \ +} + +#define VISIT_SEQ_TAIL(ST, TYPE, SEQ, START) { \ + int i; \ + asdl_seq *seq = (SEQ); /* avoid variable capture */ \ + for (i = (START); i < asdl_seq_LEN(seq); i++) { \ + TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ + if (!symtable_visit_ ## TYPE((ST), elt)) \ + return 0; \ + } \ +} + +#define VISIT_SEQ_TAIL_IN_BLOCK(ST, TYPE, SEQ, START, S) { \ + int i; \ + asdl_seq *seq = (SEQ); /* avoid variable capture */ \ + for (i = (START); i < asdl_seq_LEN(seq); i++) { \ + TYPE ## _ty elt = (TYPE ## _ty)asdl_seq_GET(seq, i); \ + if (!symtable_visit_ ## TYPE((ST), elt)) { \ + symtable_exit_block((ST), (S)); \ + return 0; \ + } \ + } \ +} + +static int +symtable_new_tmpname(struct symtable *st) +{ + char tmpname[256]; + identifier tmp; + + PyOS_snprintf(tmpname, sizeof(tmpname), "_[%d]", + ++st->st_cur->ste_tmpname); + tmp = PyString_InternFromString(tmpname); + if (!tmp) + return 0; + if (!symtable_add_def(st, tmp, DEF_LOCAL)) + return 0; + Py_DECREF(tmp); + return 1; +} + +static int +symtable_visit_stmt(struct symtable *st, stmt_ty s) +{ + switch (s->kind) { + case FunctionDef_kind: + if (!symtable_add_def(st, s->v.FunctionDef.name, DEF_LOCAL)) + return 0; + if (s->v.FunctionDef.args->defaults) + VISIT_SEQ(st, expr, s->v.FunctionDef.args->defaults); + if (s->v.FunctionDef.decorators) + VISIT_SEQ(st, expr, s->v.FunctionDef.decorators); + if (!symtable_enter_block(st, s->v.FunctionDef.name, + FunctionBlock, (void *)s, s->lineno)) + return 0; + VISIT_IN_BLOCK(st, arguments, s->v.FunctionDef.args, s); + VISIT_SEQ_IN_BLOCK(st, stmt, s->v.FunctionDef.body, s); + if (!symtable_exit_block(st, s)) + return 0; + break; + case ClassDef_kind: { + PyObject *tmp; + if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL)) + return 0; + VISIT_SEQ(st, expr, s->v.ClassDef.bases); + if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, + (void *)s, s->lineno)) + return 0; + tmp = st->st_private; + st->st_private = s->v.ClassDef.name; + VISIT_SEQ_IN_BLOCK(st, stmt, s->v.ClassDef.body, s); + st->st_private = tmp; + if (!symtable_exit_block(st, s)) + return 0; + break; + } + case Return_kind: + if (s->v.Return.value) { + VISIT(st, expr, s->v.Return.value); + st->st_cur->ste_returns_value = 1; + if (st->st_cur->ste_generator) { + PyErr_SetString(PyExc_SyntaxError, + RETURN_VAL_IN_GENERATOR); + PyErr_SyntaxLocation(st->st_filename, + s->lineno); + return 0; + } + } + break; + case Delete_kind: + VISIT_SEQ(st, expr, s->v.Delete.targets); + break; + case Assign_kind: + VISIT_SEQ(st, expr, s->v.Assign.targets); + VISIT(st, expr, s->v.Assign.value); + break; + case AugAssign_kind: + VISIT(st, expr, s->v.AugAssign.target); + VISIT(st, expr, s->v.AugAssign.value); + break; + case Print_kind: + if (s->v.Print.dest) + VISIT(st, expr, s->v.Print.dest); + VISIT_SEQ(st, expr, s->v.Print.values); + break; + case For_kind: + VISIT(st, expr, s->v.For.target); + VISIT(st, expr, s->v.For.iter); + VISIT_SEQ(st, stmt, s->v.For.body); + if (s->v.For.orelse) + VISIT_SEQ(st, stmt, s->v.For.orelse); + break; + case While_kind: + VISIT(st, expr, s->v.While.test); + VISIT_SEQ(st, stmt, s->v.While.body); + if (s->v.While.orelse) + VISIT_SEQ(st, stmt, s->v.While.orelse); + break; + case If_kind: + /* XXX if 0: and lookup_yield() hacks */ + VISIT(st, expr, s->v.If.test); + VISIT_SEQ(st, stmt, s->v.If.body); + if (s->v.If.orelse) + VISIT_SEQ(st, stmt, s->v.If.orelse); + break; + case Raise_kind: + if (s->v.Raise.type) { + VISIT(st, expr, s->v.Raise.type); + if (s->v.Raise.inst) { + VISIT(st, expr, s->v.Raise.inst); + if (s->v.Raise.tback) + VISIT(st, expr, s->v.Raise.tback); + } + } + break; + case TryExcept_kind: + VISIT_SEQ(st, stmt, s->v.TryExcept.body); + VISIT_SEQ(st, stmt, s->v.TryExcept.orelse); + VISIT_SEQ(st, excepthandler, s->v.TryExcept.handlers); + break; + case TryFinally_kind: + VISIT_SEQ(st, stmt, s->v.TryFinally.body); + VISIT_SEQ(st, stmt, s->v.TryFinally.finalbody); + break; + case Assert_kind: + VISIT(st, expr, s->v.Assert.test); + if (s->v.Assert.msg) + VISIT(st, expr, s->v.Assert.msg); + break; + case Import_kind: + VISIT_SEQ(st, alias, s->v.Import.names); + /* XXX Don't have the lineno available inside + visit_alias */ + if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) + st->st_cur->ste_opt_lineno = s->lineno; + break; + case ImportFrom_kind: + VISIT_SEQ(st, alias, s->v.ImportFrom.names); + /* XXX Don't have the lineno available inside + visit_alias */ + if (st->st_cur->ste_unoptimized && !st->st_cur->ste_opt_lineno) + st->st_cur->ste_opt_lineno = s->lineno; + break; + case Exec_kind: + VISIT(st, expr, s->v.Exec.body); + if (!st->st_cur->ste_opt_lineno) + st->st_cur->ste_opt_lineno = s->lineno; + if (s->v.Exec.globals) { + st->st_cur->ste_unoptimized |= OPT_EXEC; + VISIT(st, expr, s->v.Exec.globals); + if (s->v.Exec.locals) + VISIT(st, expr, s->v.Exec.locals); + } else { + st->st_cur->ste_unoptimized |= OPT_BARE_EXEC; + } + break; + case Global_kind: { + int i; + asdl_seq *seq = s->v.Global.names; + for (i = 0; i < asdl_seq_LEN(seq); i++) { + identifier name = (identifier)asdl_seq_GET(seq, i); + char *c_name = PyString_AS_STRING(name); + long cur = symtable_lookup(st, name); + if (cur < 0) + return 0; + if (cur & (DEF_LOCAL | USE)) { + char buf[256]; + if (cur & DEF_LOCAL) + PyOS_snprintf(buf, sizeof(buf), + GLOBAL_AFTER_ASSIGN, + c_name); + else + PyOS_snprintf(buf, sizeof(buf), + GLOBAL_AFTER_USE, + c_name); + if (!symtable_warn(st, buf, s->lineno)) + return 0; + } + if (!symtable_add_def(st, name, DEF_GLOBAL)) + return 0; + } + break; + } + case Expr_kind: + VISIT(st, expr, s->v.Expr.value); + break; + case Pass_kind: + case Break_kind: + case Continue_kind: + /* nothing to do here */ + break; + case With_kind: + if (!symtable_new_tmpname(st)) + return 0; + VISIT(st, expr, s->v.With.context_expr); + if (s->v.With.optional_vars) { + if (!symtable_new_tmpname(st)) + return 0; + VISIT(st, expr, s->v.With.optional_vars); + } + VISIT_SEQ(st, stmt, s->v.With.body); + break; + } + return 1; +} + +static int +symtable_visit_expr(struct symtable *st, expr_ty e) +{ + switch (e->kind) { + case BoolOp_kind: + VISIT_SEQ(st, expr, e->v.BoolOp.values); + break; + case BinOp_kind: + VISIT(st, expr, e->v.BinOp.left); + VISIT(st, expr, e->v.BinOp.right); + break; + case UnaryOp_kind: + VISIT(st, expr, e->v.UnaryOp.operand); + break; + case Lambda_kind: { + if (!symtable_add_def(st, GET_IDENTIFIER(lambda), DEF_LOCAL)) + return 0; + if (e->v.Lambda.args->defaults) + VISIT_SEQ(st, expr, e->v.Lambda.args->defaults); + /* XXX how to get line numbers for expressions */ + if (!symtable_enter_block(st, GET_IDENTIFIER(lambda), + FunctionBlock, (void *)e, 0)) + return 0; + VISIT_IN_BLOCK(st, arguments, e->v.Lambda.args, (void*)e); + VISIT_IN_BLOCK(st, expr, e->v.Lambda.body, (void*)e); + if (!symtable_exit_block(st, (void *)e)) + return 0; + break; + } + case IfExp_kind: + VISIT(st, expr, e->v.IfExp.test); + VISIT(st, expr, e->v.IfExp.body); + VISIT(st, expr, e->v.IfExp.orelse); + break; + case Dict_kind: + VISIT_SEQ(st, expr, e->v.Dict.keys); + VISIT_SEQ(st, expr, e->v.Dict.values); + break; + case ListComp_kind: + if (!symtable_new_tmpname(st)) + return 0; + VISIT(st, expr, e->v.ListComp.elt); + VISIT_SEQ(st, comprehension, e->v.ListComp.generators); + break; + case GeneratorExp_kind: + if (!symtable_visit_genexp(st, e)) + return 0; + break; + case Yield_kind: + if (e->v.Yield.value) + VISIT(st, expr, e->v.Yield.value); + st->st_cur->ste_generator = 1; + if (st->st_cur->ste_returns_value) { + PyErr_SetString(PyExc_SyntaxError, + RETURN_VAL_IN_GENERATOR); + PyErr_SyntaxLocation(st->st_filename, + e->lineno); + return 0; + } + break; + case Compare_kind: + VISIT(st, expr, e->v.Compare.left); + VISIT_SEQ(st, expr, e->v.Compare.comparators); + break; + case Call_kind: + VISIT(st, expr, e->v.Call.func); + VISIT_SEQ(st, expr, e->v.Call.args); + VISIT_SEQ(st, keyword, e->v.Call.keywords); + if (e->v.Call.starargs) + VISIT(st, expr, e->v.Call.starargs); + if (e->v.Call.kwargs) + VISIT(st, expr, e->v.Call.kwargs); + break; + case Repr_kind: + VISIT(st, expr, e->v.Repr.value); + break; + case Num_kind: + case Str_kind: + /* Nothing to do here. */ + break; + /* The following exprs can be assignment targets. */ + case Attribute_kind: + VISIT(st, expr, e->v.Attribute.value); + break; + case Subscript_kind: + VISIT(st, expr, e->v.Subscript.value); + VISIT(st, slice, e->v.Subscript.slice); + break; + case Name_kind: + if (!symtable_add_def(st, e->v.Name.id, + e->v.Name.ctx == Load ? USE : DEF_LOCAL)) + return 0; + break; + /* child nodes of List and Tuple will have expr_context set */ + case List_kind: + VISIT_SEQ(st, expr, e->v.List.elts); + break; + case Tuple_kind: + VISIT_SEQ(st, expr, e->v.Tuple.elts); + break; + } + return 1; +} + +static int +symtable_implicit_arg(struct symtable *st, int pos) +{ + PyObject *id = PyString_FromFormat(".%d", pos); + if (id == NULL) + return 0; + if (!symtable_add_def(st, id, DEF_PARAM)) { + Py_DECREF(id); + return 0; + } + Py_DECREF(id); + return 1; +} + +static int +symtable_visit_params(struct symtable *st, asdl_seq *args, int toplevel) +{ + int i; + + /* go through all the toplevel arguments first */ + for (i = 0; i < asdl_seq_LEN(args); i++) { + expr_ty arg = (expr_ty)asdl_seq_GET(args, i); + if (arg->kind == Name_kind) { + assert(arg->v.Name.ctx == Param || + (arg->v.Name.ctx == Store && !toplevel)); + if (!symtable_add_def(st, arg->v.Name.id, DEF_PARAM)) + return 0; + } + else if (arg->kind == Tuple_kind) { + assert(arg->v.Tuple.ctx == Store); + if (toplevel) { + if (!symtable_implicit_arg(st, i)) + return 0; + } + } + else { + PyErr_SetString(PyExc_SyntaxError, + "invalid expression in parameter list"); + PyErr_SyntaxLocation(st->st_filename, + st->st_cur->ste_lineno); + return 0; + } + } + + if (!toplevel) { + if (!symtable_visit_params_nested(st, args)) + return 0; + } + + return 1; +} + +static int +symtable_visit_params_nested(struct symtable *st, asdl_seq *args) +{ + int i; + for (i = 0; i < asdl_seq_LEN(args); i++) { + expr_ty arg = (expr_ty)asdl_seq_GET(args, i); + if (arg->kind == Tuple_kind && + !symtable_visit_params(st, arg->v.Tuple.elts, 0)) + return 0; + } + + return 1; +} + +static int +symtable_visit_arguments(struct symtable *st, arguments_ty a) +{ + /* skip default arguments inside function block + XXX should ast be different? + */ + if (a->args && !symtable_visit_params(st, a->args, 1)) + return 0; + if (a->vararg) { + if (!symtable_add_def(st, a->vararg, DEF_PARAM)) + return 0; + st->st_cur->ste_varargs = 1; + } + if (a->kwarg) { + if (!symtable_add_def(st, a->kwarg, DEF_PARAM)) + return 0; + st->st_cur->ste_varkeywords = 1; + } + if (a->args && !symtable_visit_params_nested(st, a->args)) + return 0; + return 1; +} + + +static int +symtable_visit_excepthandler(struct symtable *st, excepthandler_ty eh) +{ + if (eh->type) + VISIT(st, expr, eh->type); + if (eh->name) + VISIT(st, expr, eh->name); + VISIT_SEQ(st, stmt, eh->body); + return 1; +} + + +static int +symtable_visit_alias(struct symtable *st, alias_ty a) +{ + /* Compute store_name, the name actually bound by the import + operation. It is diferent than a->name when a->name is a + dotted package name (e.g. spam.eggs) + */ + PyObject *store_name; + PyObject *name = (a->asname == NULL) ? a->name : a->asname; + const char *base = PyString_AS_STRING(name); + char *dot = strchr(base, '.'); + if (dot) { + store_name = PyString_FromStringAndSize(base, dot - base); + if (!store_name) + return 0; + } + else { + store_name = name; + Py_INCREF(store_name); + } + if (strcmp(PyString_AS_STRING(name), "*")) { + int r = symtable_add_def(st, store_name, DEF_IMPORT); + Py_DECREF(store_name); + return r; + } + else { + if (st->st_cur->ste_type != ModuleBlock) { + int lineno = st->st_cur->ste_lineno; + if (!symtable_warn(st, IMPORT_STAR_WARNING, lineno)) { + Py_DECREF(store_name); + return 0; + } + } + st->st_cur->ste_unoptimized |= OPT_IMPORT_STAR; + Py_DECREF(store_name); + return 1; + } +} + + +static int +symtable_visit_comprehension(struct symtable *st, comprehension_ty lc) +{ + VISIT(st, expr, lc->target); + VISIT(st, expr, lc->iter); + VISIT_SEQ(st, expr, lc->ifs); + return 1; +} + + +static int +symtable_visit_keyword(struct symtable *st, keyword_ty k) +{ + VISIT(st, expr, k->value); + return 1; +} + + +static int +symtable_visit_slice(struct symtable *st, slice_ty s) +{ + switch (s->kind) { + case Slice_kind: + if (s->v.Slice.lower) + VISIT(st, expr, s->v.Slice.lower) + if (s->v.Slice.upper) + VISIT(st, expr, s->v.Slice.upper) + if (s->v.Slice.step) + VISIT(st, expr, s->v.Slice.step) + break; + case ExtSlice_kind: + VISIT_SEQ(st, slice, s->v.ExtSlice.dims) + break; + case Index_kind: + VISIT(st, expr, s->v.Index.value) + break; + case Ellipsis_kind: + break; + } + return 1; +} + +static int +symtable_visit_genexp(struct symtable *st, expr_ty e) +{ + comprehension_ty outermost = ((comprehension_ty) + (asdl_seq_GET(e->v.GeneratorExp.generators, 0))); + /* Outermost iterator is evaluated in current scope */ + VISIT(st, expr, outermost->iter); + /* Create generator scope for the rest */ + if (!symtable_enter_block(st, GET_IDENTIFIER(genexpr), + FunctionBlock, (void *)e, 0)) { + return 0; + } + st->st_cur->ste_generator = 1; + /* Outermost iter is received as an argument */ + if (!symtable_implicit_arg(st, 0)) { + symtable_exit_block(st, (void *)e); + return 0; + } + VISIT_IN_BLOCK(st, expr, outermost->target, (void*)e); + VISIT_SEQ_IN_BLOCK(st, expr, outermost->ifs, (void*)e); + VISIT_SEQ_TAIL_IN_BLOCK(st, comprehension, + e->v.GeneratorExp.generators, 1, (void*)e); + VISIT_IN_BLOCK(st, expr, e->v.GeneratorExp.elt, (void*)e); + if (!symtable_exit_block(st, (void *)e)) + return 0; + return 1; +} diff --git a/sys/src/cmd/python/Python/sysmodule.c b/sys/src/cmd/python/Python/sysmodule.c new file mode 100644 index 000000000..f2c42b962 --- /dev/null +++ b/sys/src/cmd/python/Python/sysmodule.c @@ -0,0 +1,1468 @@ + +/* System module */ + +/* +Various bits of information used by the interpreter are collected in +module 'sys'. +Function member: +- exit(sts): raise SystemExit +Data members: +- stdin, stdout, stderr: standard file objects +- modules: the table of modules (dictionary) +- path: module search path (list of strings) +- argv: script arguments (list of strings) +- ps1, ps2: optional primary and secondary prompts (strings) +*/ + +#include "Python.h" +#include "code.h" +#include "frameobject.h" +#include "eval.h" + +#include "osdefs.h" + +#ifdef MS_WINDOWS +#define WIN32_LEAN_AND_MEAN +#include "windows.h" +#endif /* MS_WINDOWS */ + +#ifdef MS_COREDLL +extern void *PyWin_DLLhModule; +/* A string loaded from the DLL at startup: */ +extern const char *PyWin_DLLVersionString; +#endif + +#ifdef __VMS +#include <unixlib.h> +#endif + +#ifdef MS_WINDOWS +#include <windows.h> +#endif + +#ifdef HAVE_LANGINFO_H +#include <locale.h> +#include <langinfo.h> +#endif + +PyObject * +PySys_GetObject(char *name) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *sd = tstate->interp->sysdict; + if (sd == NULL) + return NULL; + return PyDict_GetItemString(sd, name); +} + +FILE * +PySys_GetFile(char *name, FILE *def) +{ + FILE *fp = NULL; + PyObject *v = PySys_GetObject(name); + if (v != NULL && PyFile_Check(v)) + fp = PyFile_AsFile(v); + if (fp == NULL) + fp = def; + return fp; +} + +int +PySys_SetObject(char *name, PyObject *v) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *sd = tstate->interp->sysdict; + if (v == NULL) { + if (PyDict_GetItemString(sd, name) == NULL) + return 0; + else + return PyDict_DelItemString(sd, name); + } + else + return PyDict_SetItemString(sd, name, v); +} + +static PyObject * +sys_displayhook(PyObject *self, PyObject *o) +{ + PyObject *outf; + PyInterpreterState *interp = PyThreadState_GET()->interp; + PyObject *modules = interp->modules; + PyObject *builtins = PyDict_GetItemString(modules, "__builtin__"); + + if (builtins == NULL) { + PyErr_SetString(PyExc_RuntimeError, "lost __builtin__"); + return NULL; + } + + /* Print value except if None */ + /* After printing, also assign to '_' */ + /* Before, set '_' to None to avoid recursion */ + if (o == Py_None) { + Py_INCREF(Py_None); + return Py_None; + } + if (PyObject_SetAttrString(builtins, "_", Py_None) != 0) + return NULL; + if (Py_FlushLine() != 0) + return NULL; + outf = PySys_GetObject("stdout"); + if (outf == NULL) { + PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); + return NULL; + } + if (PyFile_WriteObject(o, outf, 0) != 0) + return NULL; + PyFile_SoftSpace(outf, 1); + if (Py_FlushLine() != 0) + return NULL; + if (PyObject_SetAttrString(builtins, "_", o) != 0) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(displayhook_doc, +"displayhook(object) -> None\n" +"\n" +"Print an object to sys.stdout and also save it in __builtin__.\n" +); + +static PyObject * +sys_excepthook(PyObject* self, PyObject* args) +{ + PyObject *exc, *value, *tb; + if (!PyArg_UnpackTuple(args, "excepthook", 3, 3, &exc, &value, &tb)) + return NULL; + PyErr_Display(exc, value, tb); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(excepthook_doc, +"excepthook(exctype, value, traceback) -> None\n" +"\n" +"Handle an exception by displaying it with a traceback on sys.stderr.\n" +); + +static PyObject * +sys_exc_info(PyObject *self, PyObject *noargs) +{ + PyThreadState *tstate; + tstate = PyThreadState_GET(); + return Py_BuildValue( + "(OOO)", + tstate->exc_type != NULL ? tstate->exc_type : Py_None, + tstate->exc_value != NULL ? tstate->exc_value : Py_None, + tstate->exc_traceback != NULL ? + tstate->exc_traceback : Py_None); +} + +PyDoc_STRVAR(exc_info_doc, +"exc_info() -> (type, value, traceback)\n\ +\n\ +Return information about the most recent exception caught by an except\n\ +clause in the current stack frame or in an older stack frame." +); + +static PyObject * +sys_exc_clear(PyObject *self, PyObject *noargs) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyObject *tmp_type, *tmp_value, *tmp_tb; + tmp_type = tstate->exc_type; + tmp_value = tstate->exc_value; + tmp_tb = tstate->exc_traceback; + tstate->exc_type = NULL; + tstate->exc_value = NULL; + tstate->exc_traceback = NULL; + Py_XDECREF(tmp_type); + Py_XDECREF(tmp_value); + Py_XDECREF(tmp_tb); + /* For b/w compatibility */ + PySys_SetObject("exc_type", Py_None); + PySys_SetObject("exc_value", Py_None); + PySys_SetObject("exc_traceback", Py_None); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(exc_clear_doc, +"exc_clear() -> None\n\ +\n\ +Clear global information on the current exception. Subsequent calls to\n\ +exc_info() will return (None,None,None) until another exception is raised\n\ +in the current thread or the execution stack returns to a frame where\n\ +another exception is being handled." +); + +static PyObject * +sys_exit(PyObject *self, PyObject *args) +{ + PyObject *exit_code = 0; + if (!PyArg_UnpackTuple(args, "exit", 0, 1, &exit_code)) + return NULL; + /* Raise SystemExit so callers may catch it or clean up. */ + PyErr_SetObject(PyExc_SystemExit, exit_code); + return NULL; +} + +PyDoc_STRVAR(exit_doc, +"exit([status])\n\ +\n\ +Exit the interpreter by raising SystemExit(status).\n\ +If the status is omitted or None, it defaults to zero (i.e., success).\n\ +If the status is numeric, it will be used as the system exit status.\n\ +If it is another kind of object, it will be printed and the system\n\ +exit status will be one (i.e., failure)." +); + +#ifdef Py_USING_UNICODE + +static PyObject * +sys_getdefaultencoding(PyObject *self) +{ + return PyString_FromString(PyUnicode_GetDefaultEncoding()); +} + +PyDoc_STRVAR(getdefaultencoding_doc, +"getdefaultencoding() -> string\n\ +\n\ +Return the current default string encoding used by the Unicode \n\ +implementation." +); + +static PyObject * +sys_setdefaultencoding(PyObject *self, PyObject *args) +{ + char *encoding; + if (!PyArg_ParseTuple(args, "s:setdefaultencoding", &encoding)) + return NULL; + if (PyUnicode_SetDefaultEncoding(encoding)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setdefaultencoding_doc, +"setdefaultencoding(encoding)\n\ +\n\ +Set the current default string encoding used by the Unicode implementation." +); + +static PyObject * +sys_getfilesystemencoding(PyObject *self) +{ + if (Py_FileSystemDefaultEncoding) + return PyString_FromString(Py_FileSystemDefaultEncoding); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(getfilesystemencoding_doc, +"getfilesystemencoding() -> string\n\ +\n\ +Return the encoding used to convert Unicode filenames in\n\ +operating system filenames." +); + +#endif + +/* + * Cached interned string objects used for calling the profile and + * trace functions. Initialized by trace_init(). + */ +static PyObject *whatstrings[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL}; + +static int +trace_init(void) +{ + static char *whatnames[7] = {"call", "exception", "line", "return", + "c_call", "c_exception", "c_return"}; + PyObject *name; + int i; + for (i = 0; i < 7; ++i) { + if (whatstrings[i] == NULL) { + name = PyString_InternFromString(whatnames[i]); + if (name == NULL) + return -1; + whatstrings[i] = name; + } + } + return 0; +} + + +static PyObject * +call_trampoline(PyThreadState *tstate, PyObject* callback, + PyFrameObject *frame, int what, PyObject *arg) +{ + PyObject *args = PyTuple_New(3); + PyObject *whatstr; + PyObject *result; + + if (args == NULL) + return NULL; + Py_INCREF(frame); + whatstr = whatstrings[what]; + Py_INCREF(whatstr); + if (arg == NULL) + arg = Py_None; + Py_INCREF(arg); + PyTuple_SET_ITEM(args, 0, (PyObject *)frame); + PyTuple_SET_ITEM(args, 1, whatstr); + PyTuple_SET_ITEM(args, 2, arg); + + /* call the Python-level function */ + PyFrame_FastToLocals(frame); + result = PyEval_CallObject(callback, args); + PyFrame_LocalsToFast(frame, 1); + if (result == NULL) + PyTraceBack_Here(frame); + + /* cleanup */ + Py_DECREF(args); + return result; +} + +static int +profile_trampoline(PyObject *self, PyFrameObject *frame, + int what, PyObject *arg) +{ + PyThreadState *tstate = frame->f_tstate; + PyObject *result; + + if (arg == NULL) + arg = Py_None; + result = call_trampoline(tstate, self, frame, what, arg); + if (result == NULL) { + PyEval_SetProfile(NULL, NULL); + return -1; + } + Py_DECREF(result); + return 0; +} + +static int +trace_trampoline(PyObject *self, PyFrameObject *frame, + int what, PyObject *arg) +{ + PyThreadState *tstate = frame->f_tstate; + PyObject *callback; + PyObject *result; + + if (what == PyTrace_CALL) + callback = self; + else + callback = frame->f_trace; + if (callback == NULL) + return 0; + result = call_trampoline(tstate, callback, frame, what, arg); + if (result == NULL) { + PyEval_SetTrace(NULL, NULL); + Py_XDECREF(frame->f_trace); + frame->f_trace = NULL; + return -1; + } + if (result != Py_None) { + PyObject *temp = frame->f_trace; + frame->f_trace = NULL; + Py_XDECREF(temp); + frame->f_trace = result; + } + else { + Py_DECREF(result); + } + return 0; +} + +static PyObject * +sys_settrace(PyObject *self, PyObject *args) +{ + if (trace_init() == -1) + return NULL; + if (args == Py_None) + PyEval_SetTrace(NULL, NULL); + else + PyEval_SetTrace(trace_trampoline, args); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(settrace_doc, +"settrace(function)\n\ +\n\ +Set the global debug tracing function. It will be called on each\n\ +function call. See the debugger chapter in the library manual." +); + +static PyObject * +sys_setprofile(PyObject *self, PyObject *args) +{ + if (trace_init() == -1) + return NULL; + if (args == Py_None) + PyEval_SetProfile(NULL, NULL); + else + PyEval_SetProfile(profile_trampoline, args); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setprofile_doc, +"setprofile(function)\n\ +\n\ +Set the profiling function. It will be called on each function call\n\ +and return. See the profiler chapter in the library manual." +); + +static PyObject * +sys_setcheckinterval(PyObject *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "i:setcheckinterval", &_Py_CheckInterval)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setcheckinterval_doc, +"setcheckinterval(n)\n\ +\n\ +Tell the Python interpreter to check for asynchronous events every\n\ +n instructions. This also affects how often thread switches occur." +); + +static PyObject * +sys_getcheckinterval(PyObject *self, PyObject *args) +{ + return PyInt_FromLong(_Py_CheckInterval); +} + +PyDoc_STRVAR(getcheckinterval_doc, +"getcheckinterval() -> current check interval; see setcheckinterval()." +); + +#ifdef WITH_TSC +static PyObject * +sys_settscdump(PyObject *self, PyObject *args) +{ + int bool; + PyThreadState *tstate = PyThreadState_Get(); + + if (!PyArg_ParseTuple(args, "i:settscdump", &bool)) + return NULL; + if (bool) + tstate->interp->tscdump = 1; + else + tstate->interp->tscdump = 0; + Py_INCREF(Py_None); + return Py_None; + +} + +PyDoc_STRVAR(settscdump_doc, +"settscdump(bool)\n\ +\n\ +If true, tell the Python interpreter to dump VM measurements to\n\ +stderr. If false, turn off dump. The measurements are based on the\n\ +processor's time-stamp counter." +); +#endif /* TSC */ + +static PyObject * +sys_setrecursionlimit(PyObject *self, PyObject *args) +{ + int new_limit; + if (!PyArg_ParseTuple(args, "i:setrecursionlimit", &new_limit)) + return NULL; + if (new_limit <= 0) { + PyErr_SetString(PyExc_ValueError, + "recursion limit must be positive"); + return NULL; + } + Py_SetRecursionLimit(new_limit); + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setrecursionlimit_doc, +"setrecursionlimit(n)\n\ +\n\ +Set the maximum depth of the Python interpreter stack to n. This\n\ +limit prevents infinite recursion from causing an overflow of the C\n\ +stack and crashing Python. The highest possible limit is platform-\n\ +dependent." +); + +static PyObject * +sys_getrecursionlimit(PyObject *self) +{ + return PyInt_FromLong(Py_GetRecursionLimit()); +} + +PyDoc_STRVAR(getrecursionlimit_doc, +"getrecursionlimit()\n\ +\n\ +Return the current value of the recursion limit, the maximum depth\n\ +of the Python interpreter stack. This limit prevents infinite\n\ +recursion from causing an overflow of the C stack and crashing Python." +); + +#ifdef MS_WINDOWS +PyDoc_STRVAR(getwindowsversion_doc, +"getwindowsversion()\n\ +\n\ +Return information about the running version of Windows.\n\ +The result is a tuple of (major, minor, build, platform, text)\n\ +All elements are numbers, except text which is a string.\n\ +Platform may be 0 for win32s, 1 for Windows 9x/ME, 2 for Windows NT/2000/XP\n\ +" +); + +static PyObject * +sys_getwindowsversion(PyObject *self) +{ + OSVERSIONINFO ver; + ver.dwOSVersionInfoSize = sizeof(ver); + if (!GetVersionEx(&ver)) + return PyErr_SetFromWindowsErr(0); + return Py_BuildValue("HHHHs", + ver.dwMajorVersion, + ver.dwMinorVersion, + ver.dwBuildNumber, + ver.dwPlatformId, + ver.szCSDVersion); +} + +#endif /* MS_WINDOWS */ + +#ifdef HAVE_DLOPEN +static PyObject * +sys_setdlopenflags(PyObject *self, PyObject *args) +{ + int new_val; + PyThreadState *tstate = PyThreadState_GET(); + if (!PyArg_ParseTuple(args, "i:setdlopenflags", &new_val)) + return NULL; + if (!tstate) + return NULL; + tstate->interp->dlopenflags = new_val; + Py_INCREF(Py_None); + return Py_None; +} + +PyDoc_STRVAR(setdlopenflags_doc, +"setdlopenflags(n) -> None\n\ +\n\ +Set the flags that will be used for dlopen() calls. Among other\n\ +things, this will enable a lazy resolving of symbols when importing\n\ +a module, if called as sys.setdlopenflags(0)\n\ +To share symbols across extension modules, call as\n\ +sys.setdlopenflags(dl.RTLD_NOW|dl.RTLD_GLOBAL)" +); + +static PyObject * +sys_getdlopenflags(PyObject *self, PyObject *args) +{ + PyThreadState *tstate = PyThreadState_GET(); + if (!tstate) + return NULL; + return PyInt_FromLong(tstate->interp->dlopenflags); +} + +PyDoc_STRVAR(getdlopenflags_doc, +"getdlopenflags() -> int\n\ +\n\ +Return the current value of the flags that are used for dlopen()\n\ +calls. The flag constants are defined in the dl module." +); +#endif + +#ifdef USE_MALLOPT +/* Link with -lmalloc (or -lmpc) on an SGI */ +#include <malloc.h> + +static PyObject * +sys_mdebug(PyObject *self, PyObject *args) +{ + int flag; + if (!PyArg_ParseTuple(args, "i:mdebug", &flag)) + return NULL; + mallopt(M_DEBUG, flag); + Py_INCREF(Py_None); + return Py_None; +} +#endif /* USE_MALLOPT */ + +static PyObject * +sys_getrefcount(PyObject *self, PyObject *arg) +{ + return PyInt_FromSsize_t(arg->ob_refcnt); +} + +#ifdef Py_REF_DEBUG +static PyObject * +sys_gettotalrefcount(PyObject *self) +{ + return PyInt_FromSsize_t(_Py_GetRefTotal()); +} +#endif /* Py_REF_DEBUG */ + +PyDoc_STRVAR(getrefcount_doc, +"getrefcount(object) -> integer\n\ +\n\ +Return the reference count of object. The count returned is generally\n\ +one higher than you might expect, because it includes the (temporary)\n\ +reference as an argument to getrefcount()." +); + +#ifdef COUNT_ALLOCS +static PyObject * +sys_getcounts(PyObject *self) +{ + extern PyObject *get_counts(void); + + return get_counts(); +} +#endif + +PyDoc_STRVAR(getframe_doc, +"_getframe([depth]) -> frameobject\n\ +\n\ +Return a frame object from the call stack. If optional integer depth is\n\ +given, return the frame object that many calls below the top of the stack.\n\ +If that is deeper than the call stack, ValueError is raised. The default\n\ +for depth is zero, returning the frame at the top of the call stack.\n\ +\n\ +This function should be used for internal and specialized\n\ +purposes only." +); + +static PyObject * +sys_getframe(PyObject *self, PyObject *args) +{ + PyFrameObject *f = PyThreadState_GET()->frame; + int depth = -1; + + if (!PyArg_ParseTuple(args, "|i:_getframe", &depth)) + return NULL; + + while (depth > 0 && f != NULL) { + f = f->f_back; + --depth; + } + if (f == NULL) { + PyErr_SetString(PyExc_ValueError, + "call stack is not deep enough"); + return NULL; + } + Py_INCREF(f); + return (PyObject*)f; +} + +PyDoc_STRVAR(current_frames_doc, +"_current_frames() -> dictionary\n\ +\n\ +Return a dictionary mapping each current thread T's thread id to T's\n\ +current stack frame.\n\ +\n\ +This function should be used for specialized purposes only." +); + +static PyObject * +sys_current_frames(PyObject *self, PyObject *noargs) +{ + return _PyThread_CurrentFrames(); +} + +PyDoc_STRVAR(call_tracing_doc, +"call_tracing(func, args) -> object\n\ +\n\ +Call func(*args), while tracing is enabled. The tracing state is\n\ +saved, and restored afterwards. This is intended to be called from\n\ +a debugger from a checkpoint, to recursively debug some other code." +); + +static PyObject * +sys_call_tracing(PyObject *self, PyObject *args) +{ + PyObject *func, *funcargs; + if (!PyArg_UnpackTuple(args, "call_tracing", 2, 2, &func, &funcargs)) + return NULL; + return _PyEval_CallTracing(func, funcargs); +} + +PyDoc_STRVAR(callstats_doc, +"callstats() -> tuple of integers\n\ +\n\ +Return a tuple of function call statistics, if CALL_PROFILE was defined\n\ +when Python was built. Otherwise, return None.\n\ +\n\ +When enabled, this function returns detailed, implementation-specific\n\ +details about the number of function calls executed. The return value is\n\ +a 11-tuple where the entries in the tuple are counts of:\n\ +0. all function calls\n\ +1. calls to PyFunction_Type objects\n\ +2. PyFunction calls that do not create an argument tuple\n\ +3. PyFunction calls that do not create an argument tuple\n\ + and bypass PyEval_EvalCodeEx()\n\ +4. PyMethod calls\n\ +5. PyMethod calls on bound methods\n\ +6. PyType calls\n\ +7. PyCFunction calls\n\ +8. generator calls\n\ +9. All other calls\n\ +10. Number of stack pops performed by call_function()" +); + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef Py_TRACE_REFS +/* Defined in objects.c because it uses static globals if that file */ +extern PyObject *_Py_GetObjects(PyObject *, PyObject *); +#endif + +#ifdef DYNAMIC_EXECUTION_PROFILE +/* Defined in ceval.c because it uses static globals if that file */ +extern PyObject *_Py_GetDXProfile(PyObject *, PyObject *); +#endif + +#ifdef __cplusplus +} +#endif + +static PyMethodDef sys_methods[] = { + /* Might as well keep this in alphabetic order */ + {"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS, + callstats_doc}, + {"_current_frames", sys_current_frames, METH_NOARGS, + current_frames_doc}, + {"displayhook", sys_displayhook, METH_O, displayhook_doc}, + {"exc_info", sys_exc_info, METH_NOARGS, exc_info_doc}, + {"exc_clear", sys_exc_clear, METH_NOARGS, exc_clear_doc}, + {"excepthook", sys_excepthook, METH_VARARGS, excepthook_doc}, + {"exit", sys_exit, METH_VARARGS, exit_doc}, +#ifdef Py_USING_UNICODE + {"getdefaultencoding", (PyCFunction)sys_getdefaultencoding, + METH_NOARGS, getdefaultencoding_doc}, +#endif +#ifdef HAVE_DLOPEN + {"getdlopenflags", (PyCFunction)sys_getdlopenflags, METH_NOARGS, + getdlopenflags_doc}, +#endif +#ifdef COUNT_ALLOCS + {"getcounts", (PyCFunction)sys_getcounts, METH_NOARGS}, +#endif +#ifdef DYNAMIC_EXECUTION_PROFILE + {"getdxp", _Py_GetDXProfile, METH_VARARGS}, +#endif +#ifdef Py_USING_UNICODE + {"getfilesystemencoding", (PyCFunction)sys_getfilesystemencoding, + METH_NOARGS, getfilesystemencoding_doc}, +#endif +#ifdef Py_TRACE_REFS + {"getobjects", _Py_GetObjects, METH_VARARGS}, +#endif +#ifdef Py_REF_DEBUG + {"gettotalrefcount", (PyCFunction)sys_gettotalrefcount, METH_NOARGS}, +#endif + {"getrefcount", (PyCFunction)sys_getrefcount, METH_O, getrefcount_doc}, + {"getrecursionlimit", (PyCFunction)sys_getrecursionlimit, METH_NOARGS, + getrecursionlimit_doc}, + {"_getframe", sys_getframe, METH_VARARGS, getframe_doc}, +#ifdef MS_WINDOWS + {"getwindowsversion", (PyCFunction)sys_getwindowsversion, METH_NOARGS, + getwindowsversion_doc}, +#endif /* MS_WINDOWS */ +#ifdef USE_MALLOPT + {"mdebug", sys_mdebug, METH_VARARGS}, +#endif +#ifdef Py_USING_UNICODE + {"setdefaultencoding", sys_setdefaultencoding, METH_VARARGS, + setdefaultencoding_doc}, +#endif + {"setcheckinterval", sys_setcheckinterval, METH_VARARGS, + setcheckinterval_doc}, + {"getcheckinterval", sys_getcheckinterval, METH_NOARGS, + getcheckinterval_doc}, +#ifdef HAVE_DLOPEN + {"setdlopenflags", sys_setdlopenflags, METH_VARARGS, + setdlopenflags_doc}, +#endif + {"setprofile", sys_setprofile, METH_O, setprofile_doc}, + {"setrecursionlimit", sys_setrecursionlimit, METH_VARARGS, + setrecursionlimit_doc}, +#ifdef WITH_TSC + {"settscdump", sys_settscdump, METH_VARARGS, settscdump_doc}, +#endif + {"settrace", sys_settrace, METH_O, settrace_doc}, + {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject * +list_builtin_module_names(void) +{ + PyObject *list = PyList_New(0); + int i; + if (list == NULL) + return NULL; + for (i = 0; PyImport_Inittab[i].name != NULL; i++) { + PyObject *name = PyString_FromString( + PyImport_Inittab[i].name); + if (name == NULL) + break; + PyList_Append(list, name); + Py_DECREF(name); + } + if (PyList_Sort(list) != 0) { + Py_DECREF(list); + list = NULL; + } + if (list) { + PyObject *v = PyList_AsTuple(list); + Py_DECREF(list); + list = v; + } + return list; +} + +static PyObject *warnoptions = NULL; + +void +PySys_ResetWarnOptions(void) +{ + if (warnoptions == NULL || !PyList_Check(warnoptions)) + return; + PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL); +} + +void +PySys_AddWarnOption(char *s) +{ + PyObject *str; + + if (warnoptions == NULL || !PyList_Check(warnoptions)) { + Py_XDECREF(warnoptions); + warnoptions = PyList_New(0); + if (warnoptions == NULL) + return; + } + str = PyString_FromString(s); + if (str != NULL) { + PyList_Append(warnoptions, str); + Py_DECREF(str); + } +} + +/* XXX This doc string is too long to be a single string literal in VC++ 5.0. + Two literals concatenated works just fine. If you have a K&R compiler + or other abomination that however *does* understand longer strings, + get rid of the !!! comment in the middle and the quotes that surround it. */ +PyDoc_VAR(sys_doc) = +PyDoc_STR( +"This module provides access to some objects used or maintained by the\n\ +interpreter and to functions that interact strongly with the interpreter.\n\ +\n\ +Dynamic objects:\n\ +\n\ +argv -- command line arguments; argv[0] is the script pathname if known\n\ +path -- module search path; path[0] is the script directory, else ''\n\ +modules -- dictionary of loaded modules\n\ +\n\ +displayhook -- called to show results in an interactive session\n\ +excepthook -- called to handle any uncaught exception other than SystemExit\n\ + To customize printing in an interactive session or to install a custom\n\ + top-level exception handler, assign other functions to replace these.\n\ +\n\ +exitfunc -- if sys.exitfunc exists, this routine is called when Python exits\n\ + Assigning to sys.exitfunc is deprecated; use the atexit module instead.\n\ +\n\ +stdin -- standard input file object; used by raw_input() and input()\n\ +stdout -- standard output file object; used by the print statement\n\ +stderr -- standard error object; used for error messages\n\ + By assigning other file objects (or objects that behave like files)\n\ + to these, it is possible to redirect all of the interpreter's I/O.\n\ +\n\ +last_type -- type of last uncaught exception\n\ +last_value -- value of last uncaught exception\n\ +last_traceback -- traceback of last uncaught exception\n\ + These three are only available in an interactive session after a\n\ + traceback has been printed.\n\ +\n\ +exc_type -- type of exception currently being handled\n\ +exc_value -- value of exception currently being handled\n\ +exc_traceback -- traceback of exception currently being handled\n\ + The function exc_info() should be used instead of these three,\n\ + because it is thread-safe.\n\ +" +) +/* concatenating string here */ +PyDoc_STR( +"\n\ +Static objects:\n\ +\n\ +maxint -- the largest supported integer (the smallest is -maxint-1)\n\ +maxunicode -- the largest supported character\n\ +builtin_module_names -- tuple of module names built into this interpreter\n\ +version -- the version of this interpreter as a string\n\ +version_info -- version information as a tuple\n\ +hexversion -- version information encoded as a single integer\n\ +copyright -- copyright notice pertaining to this interpreter\n\ +platform -- platform identifier\n\ +executable -- pathname of this Python interpreter\n\ +prefix -- prefix used to find the Python library\n\ +exec_prefix -- prefix used to find the machine-specific Python library\n\ +" +) +#ifdef MS_WINDOWS +/* concatenating string here */ +PyDoc_STR( +"dllhandle -- [Windows only] integer handle of the Python DLL\n\ +winver -- [Windows only] version number of the Python DLL\n\ +" +) +#endif /* MS_WINDOWS */ +PyDoc_STR( +"__stdin__ -- the original stdin; don't touch!\n\ +__stdout__ -- the original stdout; don't touch!\n\ +__stderr__ -- the original stderr; don't touch!\n\ +__displayhook__ -- the original displayhook; don't touch!\n\ +__excepthook__ -- the original excepthook; don't touch!\n\ +\n\ +Functions:\n\ +\n\ +displayhook() -- print an object to the screen, and save it in __builtin__._\n\ +excepthook() -- print an exception and its traceback to sys.stderr\n\ +exc_info() -- return thread-safe information about the current exception\n\ +exc_clear() -- clear the exception state for the current thread\n\ +exit() -- exit the interpreter by raising SystemExit\n\ +getdlopenflags() -- returns flags to be used for dlopen() calls\n\ +getrefcount() -- return the reference count for an object (plus one :-)\n\ +getrecursionlimit() -- return the max recursion depth for the interpreter\n\ +setcheckinterval() -- control how often the interpreter checks for events\n\ +setdlopenflags() -- set the flags to be used for dlopen() calls\n\ +setprofile() -- set the global profiling function\n\ +setrecursionlimit() -- set the max recursion depth for the interpreter\n\ +settrace() -- set the global debug tracing function\n\ +" +) +/* end of sys_doc */ ; + +static int +_check_and_flush (FILE *stream) +{ + int prev_fail = ferror (stream); + return fflush (stream) || prev_fail ? EOF : 0; +} + +/* Subversion branch and revision management */ +static const char _patchlevel_revision[] = PY_PATCHLEVEL_REVISION; +static const char headurl[] = "$HeadURL: svn+ssh://pythondev@svn.python.org/python/tags/r251/Python/sysmodule.c $"; +static int svn_initialized; +static char patchlevel_revision[50]; /* Just the number */ +static char branch[50]; +static char shortbranch[50]; +static const char *svn_revision; + +static void +svnversion_init(void) +{ + const char *python, *br_start, *br_end, *br_end2, *svnversion; + Py_ssize_t len; + int istag; + + if (svn_initialized) + return; + + python = strstr(headurl, "/python/"); + if (!python) + Py_FatalError("subversion keywords missing"); + + br_start = python + 8; + br_end = strchr(br_start, '/'); + assert(br_end); + + /* Works even for trunk, + as we are in trunk/Python/sysmodule.c */ + br_end2 = strchr(br_end+1, '/'); + + istag = strncmp(br_start, "tags", 4) == 0; + if (strncmp(br_start, "trunk", 5) == 0) { + strcpy(branch, "trunk"); + strcpy(shortbranch, "trunk"); + + } + else if (istag || strncmp(br_start, "branches", 8) == 0) { + len = br_end2 - br_start; + strncpy(branch, br_start, len); + branch[len] = '\0'; + + len = br_end2 - (br_end + 1); + strncpy(shortbranch, br_end + 1, len); + shortbranch[len] = '\0'; + } + else { + Py_FatalError("bad HeadURL"); + return; + } + + + svnversion = _Py_svnversion(); + if (strcmp(svnversion, "exported") != 0) + svn_revision = svnversion; + else if (istag) { + len = strlen(_patchlevel_revision); + strncpy(patchlevel_revision, _patchlevel_revision + 11, + len - 13); + patchlevel_revision[len - 13] = '\0'; + svn_revision = patchlevel_revision; + } + else + svn_revision = ""; + + svn_initialized = 1; +} + +/* Return svnversion output if available. + Else return Revision of patchlevel.h if on branch. + Else return empty string */ +const char* +Py_SubversionRevision() +{ + svnversion_init(); + return svn_revision; +} + +const char* +Py_SubversionShortBranch() +{ + svnversion_init(); + return shortbranch; +} + +PyObject * +_PySys_Init(void) +{ + PyObject *m, *v, *sysdict; + PyObject *sysin, *sysout, *syserr; + char *s; +#ifdef MS_WINDOWS + char buf[128]; +#endif + + m = Py_InitModule3("sys", sys_methods, sys_doc); + if (m == NULL) + return NULL; + sysdict = PyModule_GetDict(m); + + { + /* XXX: does this work on Win/Win64? (see posix_fstat) */ + struct stat sb; + if (fstat(fileno(stdin), &sb) == 0 && + S_ISDIR(sb.st_mode)) { + /* There's nothing more we can do. */ + /* Py_FatalError() will core dump, so just exit. */ + PySys_WriteStderr("Python error: <stdin> is a directory, cannot continue\n"); + exit(EXIT_FAILURE); + } + } + + /* Closing the standard FILE* if sys.std* goes aways causes problems + * for embedded Python usages. Closing them when somebody explicitly + * invokes .close() might be possible, but the FAQ promises they get + * never closed. However, we still need to get write errors when + * writing fails (e.g. because stdout is redirected), so we flush the + * streams and check for errors before the file objects are deleted. + * On OS X, fflush()ing stdin causes an error, so we exempt stdin + * from that procedure. + */ + sysin = PyFile_FromFile(stdin, "<stdin>", "r", NULL); + sysout = PyFile_FromFile(stdout, "<stdout>", "w", _check_and_flush); + syserr = PyFile_FromFile(stderr, "<stderr>", "w", _check_and_flush); + if (PyErr_Occurred()) + return NULL; +#ifdef MS_WINDOWS + if(isatty(_fileno(stdin)) && PyFile_Check(sysin)) { + sprintf(buf, "cp%d", GetConsoleCP()); + if (!PyFile_SetEncoding(sysin, buf)) + return NULL; + } + if(isatty(_fileno(stdout)) && PyFile_Check(sysout)) { + sprintf(buf, "cp%d", GetConsoleOutputCP()); + if (!PyFile_SetEncoding(sysout, buf)) + return NULL; + } + if(isatty(_fileno(stderr)) && PyFile_Check(syserr)) { + sprintf(buf, "cp%d", GetConsoleOutputCP()); + if (!PyFile_SetEncoding(syserr, buf)) + return NULL; + } +#endif + + PyDict_SetItemString(sysdict, "stdin", sysin); + PyDict_SetItemString(sysdict, "stdout", sysout); + PyDict_SetItemString(sysdict, "stderr", syserr); + /* Make backup copies for cleanup */ + PyDict_SetItemString(sysdict, "__stdin__", sysin); + PyDict_SetItemString(sysdict, "__stdout__", sysout); + PyDict_SetItemString(sysdict, "__stderr__", syserr); + PyDict_SetItemString(sysdict, "__displayhook__", + PyDict_GetItemString(sysdict, "displayhook")); + PyDict_SetItemString(sysdict, "__excepthook__", + PyDict_GetItemString(sysdict, "excepthook")); + Py_XDECREF(sysin); + Py_XDECREF(sysout); + Py_XDECREF(syserr); + PyDict_SetItemString(sysdict, "version", + v = PyString_FromString(Py_GetVersion())); + Py_XDECREF(v); + PyDict_SetItemString(sysdict, "hexversion", + v = PyInt_FromLong(PY_VERSION_HEX)); + Py_XDECREF(v); + svnversion_init(); + v = Py_BuildValue("(ssz)", "CPython", branch, svn_revision); + PyDict_SetItemString(sysdict, "subversion", v); + Py_XDECREF(v); + /* + * These release level checks are mutually exclusive and cover + * the field, so don't get too fancy with the pre-processor! + */ +#if PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_ALPHA + s = "alpha"; +#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_BETA + s = "beta"; +#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_GAMMA + s = "candidate"; +#elif PY_RELEASE_LEVEL == PY_RELEASE_LEVEL_FINAL + s = "final"; +#endif + +#define SET_SYS_FROM_STRING(key, value) \ + v = value; \ + if (v != NULL) \ + PyDict_SetItemString(sysdict, key, v); \ + Py_XDECREF(v) + + SET_SYS_FROM_STRING("version_info", + Py_BuildValue("iiisi", PY_MAJOR_VERSION, + PY_MINOR_VERSION, + PY_MICRO_VERSION, s, + PY_RELEASE_SERIAL)); + SET_SYS_FROM_STRING("api_version", + PyInt_FromLong(PYTHON_API_VERSION)); + SET_SYS_FROM_STRING("copyright", + PyString_FromString(Py_GetCopyright())); + SET_SYS_FROM_STRING("platform", + PyString_FromString(Py_GetPlatform())); + SET_SYS_FROM_STRING("executable", + PyString_FromString(Py_GetProgramFullPath())); + SET_SYS_FROM_STRING("prefix", + PyString_FromString(Py_GetPrefix())); + SET_SYS_FROM_STRING("exec_prefix", + PyString_FromString(Py_GetExecPrefix())); + SET_SYS_FROM_STRING("maxint", + PyInt_FromLong(PyInt_GetMax())); +#ifdef Py_USING_UNICODE + SET_SYS_FROM_STRING("maxunicode", + PyInt_FromLong(PyUnicode_GetMax())); +#endif + SET_SYS_FROM_STRING("builtin_module_names", + list_builtin_module_names()); + { + /* Assumes that longs are at least 2 bytes long. + Should be safe! */ + unsigned long number = 1; + char *value; + + s = (char *) &number; + if (s[0] == 0) + value = "big"; + else + value = "little"; + SET_SYS_FROM_STRING("byteorder", + PyString_FromString(value)); + } +#ifdef MS_COREDLL + SET_SYS_FROM_STRING("dllhandle", + PyLong_FromVoidPtr(PyWin_DLLhModule)); + SET_SYS_FROM_STRING("winver", + PyString_FromString(PyWin_DLLVersionString)); +#endif +#undef SET_SYS_FROM_STRING + if (warnoptions == NULL) { + warnoptions = PyList_New(0); + } + else { + Py_INCREF(warnoptions); + } + if (warnoptions != NULL) { + PyDict_SetItemString(sysdict, "warnoptions", warnoptions); + } + + if (PyErr_Occurred()) + return NULL; + return m; +} + +static PyObject * +makepathobject(char *path, int delim) +{ + int i, n; + char *p; + PyObject *v, *w; + + n = 1; + p = path; + while ((p = strchr(p, delim)) != NULL) { + n++; + p++; + } + v = PyList_New(n); + if (v == NULL) + return NULL; + for (i = 0; ; i++) { + p = strchr(path, delim); + if (p == NULL) + p = strchr(path, '\0'); /* End of string */ + w = PyString_FromStringAndSize(path, (Py_ssize_t) (p - path)); + if (w == NULL) { + Py_DECREF(v); + return NULL; + } + PyList_SetItem(v, i, w); + if (*p == '\0') + break; + path = p+1; + } + return v; +} + +void +PySys_SetPath(char *path) +{ + PyObject *v; + if ((v = makepathobject(path, DELIM)) == NULL) + Py_FatalError("can't create sys.path"); + if (PySys_SetObject("path", v) != 0) + Py_FatalError("can't assign sys.path"); + Py_DECREF(v); +} + +static PyObject * +makeargvobject(int argc, char **argv) +{ + PyObject *av; + if (argc <= 0 || argv == NULL) { + /* Ensure at least one (empty) argument is seen */ + static char *empty_argv[1] = {""}; + argv = empty_argv; + argc = 1; + } + av = PyList_New(argc); + if (av != NULL) { + int i; + for (i = 0; i < argc; i++) { +#ifdef __VMS + PyObject *v; + + /* argv[0] is the script pathname if known */ + if (i == 0) { + char* fn = decc$translate_vms(argv[0]); + if ((fn == (char *)0) || fn == (char *)-1) + v = PyString_FromString(argv[0]); + else + v = PyString_FromString( + decc$translate_vms(argv[0])); + } else + v = PyString_FromString(argv[i]); +#else + PyObject *v = PyString_FromString(argv[i]); +#endif + if (v == NULL) { + Py_DECREF(av); + av = NULL; + break; + } + PyList_SetItem(av, i, v); + } + } + return av; +} + +void +PySys_SetArgv(int argc, char **argv) +{ +#if defined(HAVE_REALPATH) + char fullpath[MAXPATHLEN]; +#elif defined(MS_WINDOWS) + char fullpath[MAX_PATH]; +#endif + PyObject *av = makeargvobject(argc, argv); + PyObject *path = PySys_GetObject("path"); + if (av == NULL) + Py_FatalError("no mem for sys.argv"); + if (PySys_SetObject("argv", av) != 0) + Py_FatalError("can't assign sys.argv"); + if (path != NULL) { + char *argv0 = argv[0]; + char *p = NULL; + Py_ssize_t n = 0; + PyObject *a; +#ifdef HAVE_READLINK + char link[MAXPATHLEN+1]; + char argv0copy[2*MAXPATHLEN+1]; + int nr = 0; + if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) + nr = readlink(argv0, link, MAXPATHLEN); + if (nr > 0) { + /* It's a symlink */ + link[nr] = '\0'; + if (link[0] == SEP) + argv0 = link; /* Link to absolute path */ + else if (strchr(link, SEP) == NULL) + ; /* Link without path */ + else { + /* Must join(dirname(argv0), link) */ + char *q = strrchr(argv0, SEP); + if (q == NULL) + argv0 = link; /* argv0 without path */ + else { + /* Must make a copy */ + strcpy(argv0copy, argv0); + q = strrchr(argv0copy, SEP); + strcpy(q+1, link); + argv0 = argv0copy; + } + } + } +#endif /* HAVE_READLINK */ +#if SEP == '\\' /* Special case for MS filename syntax */ + if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) { + char *q; +#ifdef MS_WINDOWS + char *ptemp; + if (GetFullPathName(argv0, + sizeof(fullpath), + fullpath, + &ptemp)) { + argv0 = fullpath; + } +#endif + p = strrchr(argv0, SEP); + /* Test for alternate separator */ + q = strrchr(p ? p : argv0, '/'); + if (q != NULL) + p = q; + if (p != NULL) { + n = p + 1 - argv0; + if (n > 1 && p[-1] != ':') + n--; /* Drop trailing separator */ + } + } +#else /* All other filename syntaxes */ + if (argc > 0 && argv0 != NULL && strcmp(argv0, "-c") != 0) { +#if defined(HAVE_REALPATH) + if (realpath(argv0, fullpath)) { + argv0 = fullpath; + } +#endif + p = strrchr(argv0, SEP); + } + if (p != NULL) { +#ifndef RISCOS + n = p + 1 - argv0; +#else /* don't include trailing separator */ + n = p - argv0; +#endif /* RISCOS */ +#if SEP == '/' /* Special case for Unix filename syntax */ + if (n > 1) + n--; /* Drop trailing separator */ +#endif /* Unix */ + } +#endif /* All others */ + a = PyString_FromStringAndSize(argv0, n); + if (a == NULL) + Py_FatalError("no mem for sys.path insertion"); + if (PyList_Insert(path, 0, a) < 0) + Py_FatalError("sys.path.insert(0) failed"); + Py_DECREF(a); + } + Py_DECREF(av); +} + + +/* APIs to write to sys.stdout or sys.stderr using a printf-like interface. + Adapted from code submitted by Just van Rossum. + + PySys_WriteStdout(format, ...) + PySys_WriteStderr(format, ...) + + The first function writes to sys.stdout; the second to sys.stderr. When + there is a problem, they write to the real (C level) stdout or stderr; + no exceptions are raised. + + Both take a printf-style format string as their first argument followed + by a variable length argument list determined by the format string. + + *** WARNING *** + + The format should limit the total size of the formatted output string to + 1000 bytes. In particular, this means that no unrestricted "%s" formats + should occur; these should be limited using "%.<N>s where <N> is a + decimal number calculated so that <N> plus the maximum size of other + formatted text does not exceed 1000 bytes. Also watch out for "%f", + which can print hundreds of digits for very large numbers. + + */ + +static void +mywrite(char *name, FILE *fp, const char *format, va_list va) +{ + PyObject *file; + PyObject *error_type, *error_value, *error_traceback; + + PyErr_Fetch(&error_type, &error_value, &error_traceback); + file = PySys_GetObject(name); + if (file == NULL || PyFile_AsFile(file) == fp) + vfprintf(fp, format, va); + else { + char buffer[1001]; + const int written = PyOS_vsnprintf(buffer, sizeof(buffer), + format, va); + if (PyFile_WriteString(buffer, file) != 0) { + PyErr_Clear(); + fputs(buffer, fp); + } + if (written < 0 || (size_t)written >= sizeof(buffer)) { + const char *truncated = "... truncated"; + if (PyFile_WriteString(truncated, file) != 0) { + PyErr_Clear(); + fputs(truncated, fp); + } + } + } + PyErr_Restore(error_type, error_value, error_traceback); +} + +void +PySys_WriteStdout(const char *format, ...) +{ + va_list va; + + va_start(va, format); + mywrite("stdout", stdout, format, va); + va_end(va); +} + +void +PySys_WriteStderr(const char *format, ...) +{ + va_list va; + + va_start(va, format); + mywrite("stderr", stderr, format, va); + va_end(va); +} diff --git a/sys/src/cmd/python/Python/thread.c b/sys/src/cmd/python/Python/thread.c new file mode 100644 index 000000000..3a2c7af6f --- /dev/null +++ b/sys/src/cmd/python/Python/thread.c @@ -0,0 +1,384 @@ + +/* Thread package. + This is intended to be usable independently from Python. + The implementation for system foobar is in a file thread_foobar.h + which is included by this file dependent on config settings. + Stuff shared by all thread_*.h files is collected here. */ + +#include "Python.h" + + +#ifndef _POSIX_THREADS +/* This means pthreads are not implemented in libc headers, hence the macro + not present in unistd.h. But they still can be implemented as an external + library (e.g. gnu pth in pthread emulation) */ +# ifdef HAVE_PTHREAD_H +# include <pthread.h> /* _POSIX_THREADS */ +# endif +#endif + +#ifndef DONT_HAVE_STDIO_H +#include <stdio.h> +#endif + +#include <stdlib.h> + +#ifdef __sgi +#ifndef HAVE_PTHREAD_H /* XXX Need to check in configure.in */ +#undef _POSIX_THREADS +#endif +#endif + +#include "pythread.h" + +#ifndef _POSIX_THREADS + +#ifdef __sgi +#define SGI_THREADS +#endif + +#ifdef HAVE_THREAD_H +#define SOLARIS_THREADS +#endif + +#if defined(sun) && !defined(SOLARIS_THREADS) +#define SUN_LWP +#endif + +/* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then + enough of the Posix threads package is implimented to support python + threads. + + This is valid for HP-UX 11.23 running on an ia64 system. If needed, add + a check of __ia64 to verify that we're running on a ia64 system instead + of a pa-risc system. +*/ +#ifdef __hpux +#ifdef _SC_THREADS +#define _POSIX_THREADS +#endif +#endif + +#endif /* _POSIX_THREADS */ + + +#ifdef Py_DEBUG +static int thread_debug = 0; +#define dprintf(args) (void)((thread_debug & 1) && printf args) +#define d2printf(args) ((thread_debug & 8) && printf args) +#else +#define dprintf(args) +#define d2printf(args) +#endif + +static int initialized; + +static void PyThread__init_thread(void); /* Forward */ + +void +PyThread_init_thread(void) +{ +#ifdef Py_DEBUG + char *p = getenv("THREADDEBUG"); + + if (p) { + if (*p) + thread_debug = atoi(p); + else + thread_debug = 1; + } +#endif /* Py_DEBUG */ + if (initialized) + return; + initialized = 1; + dprintf(("PyThread_init_thread called\n")); + PyThread__init_thread(); +} + +/* Support for runtime thread stack size tuning. + A value of 0 means using the platform's default stack size + or the size specified by the THREAD_STACK_SIZE macro. */ +static size_t _pythread_stacksize = 0; + +#ifdef SGI_THREADS +#include "thread_sgi.h" +#endif + +#ifdef SOLARIS_THREADS +#include "thread_solaris.h" +#endif + +#ifdef SUN_LWP +#include "thread_lwp.h" +#endif + +#ifdef HAVE_PTH +#include "thread_pth.h" +#undef _POSIX_THREADS +#endif + +#ifdef _POSIX_THREADS +#include "thread_pthread.h" +#endif + +#ifdef C_THREADS +#include "thread_cthread.h" +#endif + +#ifdef NT_THREADS +#include "thread_nt.h" +#endif + +#ifdef OS2_THREADS +#include "thread_os2.h" +#endif + +#ifdef BEOS_THREADS +#include "thread_beos.h" +#endif + +#ifdef WINCE_THREADS +#include "thread_wince.h" +#endif + +#ifdef PLAN9_THREADS +#include "thread_plan9.h" +#endif + +#ifdef ATHEOS_THREADS +#include "thread_atheos.h" +#endif + +/* +#ifdef FOOBAR_THREADS +#include "thread_foobar.h" +#endif +*/ + +/* return the current thread stack size */ +size_t +PyThread_get_stacksize(void) +{ + return _pythread_stacksize; +} + +/* Only platforms defining a THREAD_SET_STACKSIZE() macro + in thread_<platform>.h support changing the stack size. + Return 0 if stack size is valid, + -1 if stack size value is invalid, + -2 if setting stack size is not supported. */ +int +PyThread_set_stacksize(size_t size) +{ +#if defined(THREAD_SET_STACKSIZE) + return THREAD_SET_STACKSIZE(size); +#else + return -2; +#endif +} + +#ifndef Py_HAVE_NATIVE_TLS +/* If the platform has not supplied a platform specific + TLS implementation, provide our own. + + This code stolen from "thread_sgi.h", where it was the only + implementation of an existing Python TLS API. +*/ +/* ------------------------------------------------------------------------ +Per-thread data ("key") support. + +Use PyThread_create_key() to create a new key. This is typically shared +across threads. + +Use PyThread_set_key_value(thekey, value) to associate void* value with +thekey in the current thread. Each thread has a distinct mapping of thekey +to a void* value. Caution: if the current thread already has a mapping +for thekey, value is ignored. + +Use PyThread_get_key_value(thekey) to retrieve the void* value associated +with thekey in the current thread. This returns NULL if no value is +associated with thekey in the current thread. + +Use PyThread_delete_key_value(thekey) to forget the current thread's associated +value for thekey. PyThread_delete_key(thekey) forgets the values associated +with thekey across *all* threads. + +While some of these functions have error-return values, none set any +Python exception. + +None of the functions does memory management on behalf of the void* values. +You need to allocate and deallocate them yourself. If the void* values +happen to be PyObject*, these functions don't do refcount operations on +them either. + +The GIL does not need to be held when calling these functions; they supply +their own locking. This isn't true of PyThread_create_key(), though (see +next paragraph). + +There's a hidden assumption that PyThread_create_key() will be called before +any of the other functions are called. There's also a hidden assumption +that calls to PyThread_create_key() are serialized externally. +------------------------------------------------------------------------ */ + +/* A singly-linked list of struct key objects remembers all the key->value + * associations. File static keyhead heads the list. keymutex is used + * to enforce exclusion internally. + */ +struct key { + /* Next record in the list, or NULL if this is the last record. */ + struct key *next; + + /* The thread id, according to PyThread_get_thread_ident(). */ + long id; + + /* The key and its associated value. */ + int key; + void *value; +}; + +static struct key *keyhead = NULL; +static PyThread_type_lock keymutex = NULL; +static int nkeys = 0; /* PyThread_create_key() hands out nkeys+1 next */ + +/* Internal helper. + * If the current thread has a mapping for key, the appropriate struct key* + * is returned. NB: value is ignored in this case! + * If there is no mapping for key in the current thread, then: + * If value is NULL, NULL is returned. + * Else a mapping of key to value is created for the current thread, + * and a pointer to a new struct key* is returned; except that if + * malloc() can't find room for a new struct key*, NULL is returned. + * So when value==NULL, this acts like a pure lookup routine, and when + * value!=NULL, this acts like dict.setdefault(), returning an existing + * mapping if one exists, else creating a new mapping. + * + * Caution: this used to be too clever, trying to hold keymutex only + * around the "p->next = keyhead; keyhead = p" pair. That allowed + * another thread to mutate the list, via key deletion, concurrent with + * find_key() crawling over the list. Hilarity ensued. For example, when + * the for-loop here does "p = p->next", p could end up pointing at a + * record that PyThread_delete_key_value() was concurrently free()'ing. + * That could lead to anything, from failing to find a key that exists, to + * segfaults. Now we lock the whole routine. + */ +static struct key * +find_key(int key, void *value) +{ + struct key *p; + long id = PyThread_get_thread_ident(); + + if (!keymutex) + return NULL; + PyThread_acquire_lock(keymutex, 1); + for (p = keyhead; p != NULL; p = p->next) { + if (p->id == id && p->key == key) + goto Done; + } + if (value == NULL) { + assert(p == NULL); + goto Done; + } + p = (struct key *)malloc(sizeof(struct key)); + if (p != NULL) { + p->id = id; + p->key = key; + p->value = value; + p->next = keyhead; + keyhead = p; + } + Done: + PyThread_release_lock(keymutex); + return p; +} + +/* Return a new key. This must be called before any other functions in + * this family, and callers must arrange to serialize calls to this + * function. No violations are detected. + */ +int +PyThread_create_key(void) +{ + /* All parts of this function are wrong if it's called by multiple + * threads simultaneously. + */ + if (keymutex == NULL) + keymutex = PyThread_allocate_lock(); + return ++nkeys; +} + +/* Forget the associations for key across *all* threads. */ +void +PyThread_delete_key(int key) +{ + struct key *p, **q; + + PyThread_acquire_lock(keymutex, 1); + q = &keyhead; + while ((p = *q) != NULL) { + if (p->key == key) { + *q = p->next; + free((void *)p); + /* NB This does *not* free p->value! */ + } + else + q = &p->next; + } + PyThread_release_lock(keymutex); +} + +/* Confusing: If the current thread has an association for key, + * value is ignored, and 0 is returned. Else an attempt is made to create + * an association of key to value for the current thread. 0 is returned + * if that succeeds, but -1 is returned if there's not enough memory + * to create the association. value must not be NULL. + */ +int +PyThread_set_key_value(int key, void *value) +{ + struct key *p; + + assert(value != NULL); + p = find_key(key, value); + if (p == NULL) + return -1; + else + return 0; +} + +/* Retrieve the value associated with key in the current thread, or NULL + * if the current thread doesn't have an association for key. + */ +void * +PyThread_get_key_value(int key) +{ + struct key *p = find_key(key, NULL); + + if (p == NULL) + return NULL; + else + return p->value; +} + +/* Forget the current thread's association for key, if any. */ +void +PyThread_delete_key_value(int key) +{ + long id = PyThread_get_thread_ident(); + struct key *p, **q; + + PyThread_acquire_lock(keymutex, 1); + q = &keyhead; + while ((p = *q) != NULL) { + if (p->key == key && p->id == id) { + *q = p->next; + free((void *)p); + /* NB This does *not* free p->value! */ + break; + } + else + q = &p->next; + } + PyThread_release_lock(keymutex); +} + +#endif /* Py_HAVE_NATIVE_TLS */ diff --git a/sys/src/cmd/python/Python/thread_atheos.h b/sys/src/cmd/python/Python/thread_atheos.h new file mode 100644 index 000000000..c9f5e2318 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_atheos.h @@ -0,0 +1,300 @@ +/* Threading for AtheOS. + Based on thread_beos.h. */ + +#include <atheos/threads.h> +#include <atheos/semaphore.h> +#include <atheos/atomic.h> +#include <errno.h> +#include <string.h> + +/* Missing decl from threads.h */ +extern int exit_thread(int); + + +/* Undefine FASTLOCK to play with simple semaphores. */ +#define FASTLOCK + + +#ifdef FASTLOCK + +/* Use an atomic counter and a semaphore for maximum speed. */ +typedef struct fastmutex { + sem_id sem; + atomic_t count; +} fastmutex_t; + + +static int fastmutex_create(const char *name, fastmutex_t * mutex); +static int fastmutex_destroy(fastmutex_t * mutex); +static int fastmutex_lock(fastmutex_t * mutex); +static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout); +static int fastmutex_unlock(fastmutex_t * mutex); + + +static int fastmutex_create(const char *name, fastmutex_t * mutex) +{ + mutex->count = 0; + mutex->sem = create_semaphore(name, 0, 0); + return (mutex->sem < 0) ? -1 : 0; +} + + +static int fastmutex_destroy(fastmutex_t * mutex) +{ + if (fastmutex_timedlock(mutex, 0) == 0 || errno == EWOULDBLOCK) { + return delete_semaphore(mutex->sem); + } + return 0; +} + + +static int fastmutex_lock(fastmutex_t * mutex) +{ + atomic_t prev = atomic_add(&mutex->count, 1); + if (prev > 0) + return lock_semaphore(mutex->sem); + return 0; +} + + +static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout) +{ + atomic_t prev = atomic_add(&mutex->count, 1); + if (prev > 0) + return lock_semaphore_x(mutex->sem, 1, 0, timeout); + return 0; +} + + +static int fastmutex_unlock(fastmutex_t * mutex) +{ + atomic_t prev = atomic_add(&mutex->count, -1); + if (prev > 1) + return unlock_semaphore(mutex->sem); + return 0; +} + + +#endif /* FASTLOCK */ + + +/* + * Initialization. + * + */ +static void PyThread__init_thread(void) +{ + /* Do nothing. */ + return; +} + + +/* + * Thread support. + * + */ + +static atomic_t thread_count = 0; + +long PyThread_start_new_thread(void (*func) (void *), void *arg) +{ + status_t success = -1; + thread_id tid; + char name[OS_NAME_LENGTH]; + atomic_t this_thread; + + dprintf(("PyThread_start_new_thread called\n")); + + this_thread = atomic_add(&thread_count, 1); + PyOS_snprintf(name, sizeof(name), "python thread (%d)", this_thread); + + tid = spawn_thread(name, func, NORMAL_PRIORITY, 0, arg); + if (tid < 0) { + dprintf(("PyThread_start_new_thread spawn_thread failed: %s\n", strerror(errno))); + } else { + success = resume_thread(tid); + if (success < 0) { + dprintf(("PyThread_start_new_thread resume_thread failed: %s\n", strerror(errno))); + } + } + + return (success < 0 ? -1 : tid); +} + + +long PyThread_get_thread_ident(void) +{ + return get_thread_id(NULL); +} + + +static void do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + + /* Thread-safe way to read a variable without a mutex: */ + if (atomic_add(&thread_count, 0) == 0) { + /* No threads around, so exit main(). */ + if (no_cleanup) + _exit(0); + else + exit(0); + } else { + /* We're a thread */ + exit_thread(0); + } +} + + +void PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + + +void PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + + +#ifndef NO_EXIT_PROG +static void do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + + /* No need to do anything, the threads get torn down if main()exits. */ + if (no_cleanup) + _exit(status); + else + exit(status); +} + + +void PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + + +void PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + + +/* + * Lock support. + * + */ + +static atomic_t lock_count = 0; + +PyThread_type_lock PyThread_allocate_lock(void) +{ +#ifdef FASTLOCK + fastmutex_t *lock; +#else + sem_id sema; +#endif + char name[OS_NAME_LENGTH]; + atomic_t this_lock; + + dprintf(("PyThread_allocate_lock called\n")); + +#ifdef FASTLOCK + lock = (fastmutex_t *) malloc(sizeof(fastmutex_t)); + if (lock == NULL) { + dprintf(("PyThread_allocate_lock failed: out of memory\n")); + return (PyThread_type_lock) NULL; + } +#endif + this_lock = atomic_add(&lock_count, 1); + PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock); + +#ifdef FASTLOCK + if (fastmutex_create(name, lock) < 0) { + dprintf(("PyThread_allocate_lock failed: %s\n", + strerror(errno))); + free(lock); + lock = NULL; + } + dprintf(("PyThread_allocate_lock()-> %p\n", lock)); + return (PyThread_type_lock) lock; +#else + sema = create_semaphore(name, 1, 0); + if (sema < 0) { + dprintf(("PyThread_allocate_lock failed: %s\n", + strerror(errno))); + sema = 0; + } + dprintf(("PyThread_allocate_lock()-> %p\n", sema)); + return (PyThread_type_lock) sema; +#endif +} + + +void PyThread_free_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_free_lock(%p) called\n", lock)); + +#ifdef FASTLOCK + if (fastmutex_destroy((fastmutex_t *) lock) < 0) { + dprintf(("PyThread_free_lock(%p) failed: %s\n", lock, + strerror(errno))); + } + free(lock); +#else + if (delete_semaphore((sem_id) lock) < 0) { + dprintf(("PyThread_free_lock(%p) failed: %s\n", lock, + strerror(errno))); + } +#endif +} + + +int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int retval; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, + waitflag)); + +#ifdef FASTLOCK + if (waitflag) + retval = fastmutex_lock((fastmutex_t *) lock); + else + retval = fastmutex_timedlock((fastmutex_t *) lock, 0); +#else + if (waitflag) + retval = lock_semaphore((sem_id) lock); + else + retval = lock_semaphore_x((sem_id) lock, 1, 0, 0); +#endif + if (retval < 0) { + dprintf(("PyThread_acquire_lock(%p, %d) failed: %s\n", + lock, waitflag, strerror(errno))); + } + dprintf(("PyThread_acquire_lock(%p, %d)-> %d\n", lock, waitflag, + retval)); + return retval < 0 ? 0 : 1; +} + + +void PyThread_release_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_release_lock(%p) called\n", lock)); + +#ifdef FASTLOCK + if (fastmutex_unlock((fastmutex_t *) lock) < 0) { + dprintf(("PyThread_release_lock(%p) failed: %s\n", lock, + strerror(errno))); + } +#else + if (unlock_semaphore((sem_id) lock) < 0) { + dprintf(("PyThread_release_lock(%p) failed: %s\n", lock, + strerror(errno))); + } +#endif +} diff --git a/sys/src/cmd/python/Python/thread_beos.h b/sys/src/cmd/python/Python/thread_beos.h new file mode 100644 index 000000000..82f99ded3 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_beos.h @@ -0,0 +1,287 @@ +#include <kernel/OS.h> +#include <support/SupportDefs.h> +#include <errno.h> + +/* ---------------------------------------------------------------------- + * Fast locking mechanism described by Benoit Schillings (benoit@be.com) + * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/). + */ +typedef struct benaphore { + sem_id _sem; + int32 _atom; +} benaphore_t; + +static status_t benaphore_create( const char *name, benaphore_t *ben ); +static status_t benaphore_destroy( benaphore_t *ben ); +static status_t benaphore_lock( benaphore_t *ben ); +static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros ); +static status_t benaphore_unlock( benaphore_t *ben ); + +static status_t benaphore_create( const char *name, benaphore_t *ben ) +{ + if( ben != NULL ) { + ben->_atom = 0; + ben->_sem = create_sem( 0, name ); + + if( ben->_sem < B_NO_ERROR ) { + return B_BAD_SEM_ID; + } + } else { + return EFAULT; + } + + return EOK; +} + +static status_t benaphore_destroy( benaphore_t *ben ) +{ + if( ben->_sem >= B_NO_ERROR ) { + status_t retval = benaphore_timedlock( ben, 0 ); + + if( retval == EOK || retval == EWOULDBLOCK ) { + status_t del_retval = delete_sem( ben->_sem ); + + return del_retval; + } + } + + return B_BAD_SEM_ID; +} + +static status_t benaphore_lock( benaphore_t *ben ) +{ + int32 prev = atomic_add( &(ben->_atom), 1 ); + + if( prev > 0 ) { + return acquire_sem( ben->_sem ); + } + + return EOK; +} + +static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros ) +{ + int32 prev = atomic_add( &(ben->_atom), 1 ); + + if( prev > 0 ) { + status_t retval = acquire_sem_etc( ben->_sem, 1, B_TIMEOUT, micros ); + + switch( retval ) { + case B_WOULD_BLOCK: /* Fall through... */ + case B_TIMED_OUT: + return EWOULDBLOCK; + break; + case B_OK: + return EOK; + break; + default: + return retval; + break; + } + } + + return EOK; +} + +static status_t benaphore_unlock( benaphore_t *ben ) +{ + int32 prev = atomic_add( &(ben->_atom), -1 ); + + if( prev > 1 ) { + return release_sem( ben->_sem ); + } + + return EOK; +} + +/* ---------------------------------------------------------------------- + * Initialization. + */ +static void PyThread__init_thread( void ) +{ + /* Do nothing. */ + return; +} + +/* ---------------------------------------------------------------------- + * Thread support. + * + * Only ANSI C, renamed functions here; you can't use K&R on BeOS, + * and there's no legacy thread module to support. + */ + +static int32 thread_count = 0; + +long PyThread_start_new_thread( void (*func)(void *), void *arg ) +{ + status_t success = 0; + thread_id tid; + char name[B_OS_NAME_LENGTH]; + int32 this_thread; + + dprintf(("PyThread_start_new_thread called\n")); + + /* We are so very thread-safe... */ + this_thread = atomic_add( &thread_count, 1 ); + PyOS_snprintf(name, sizeof(name), + "python thread (%d)", this_thread ); + + tid = spawn_thread( (thread_func)func, name, + B_NORMAL_PRIORITY, arg ); + if( tid > B_NO_ERROR ) { + success = resume_thread( tid ); + } + + return ( success == B_NO_ERROR ? tid : -1 ); +} + +long PyThread_get_thread_ident( void ) +{ + /* Presumed to return the current thread's ID... */ + thread_id tid; + tid = find_thread( NULL ); + + return ( tid != B_NAME_NOT_FOUND ? tid : -1 ); +} + +static void do_PyThread_exit_thread( int no_cleanup ) +{ + int32 threads; + + dprintf(("PyThread_exit_thread called\n")); + + /* Thread-safe way to read a variable without a mutex: */ + threads = atomic_add( &thread_count, 0 ); + + if( threads == 0 ) { + /* No threads around, so exit main(). */ + if( no_cleanup ) { + _exit(0); + } else { + exit(0); + } + } else { + /* Oh, we're a thread, let's try to exit gracefully... */ + exit_thread( B_NO_ERROR ); + } +} + +void PyThread_exit_thread( void ) +{ + do_PyThread_exit_thread(0); +} + +void PyThread__exit_thread( void ) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void do_PyThread_exit_prog( int status, int no_cleanup ) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + + /* No need to do anything, the threads get torn down if main() exits. */ + + if (no_cleanup) { + _exit(status); + } else { + exit(status); + } +} + +void PyThread_exit_prog( int status ) +{ + do_PyThread_exit_prog(status, 0); +} + +void PyThread__exit_prog( int status ) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* ---------------------------------------------------------------------- + * Lock support. + */ + +static int32 lock_count = 0; + +PyThread_type_lock PyThread_allocate_lock( void ) +{ + benaphore_t *lock; + status_t retval; + char name[B_OS_NAME_LENGTH]; + int32 this_lock; + + dprintf(("PyThread_allocate_lock called\n")); + + lock = (benaphore_t *)malloc( sizeof( benaphore_t ) ); + if( lock == NULL ) { + /* TODO: that's bad, raise MemoryError */ + return (PyThread_type_lock)NULL; + } + + this_lock = atomic_add( &lock_count, 1 ); + PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock); + + retval = benaphore_create( name, lock ); + if( retval != EOK ) { + /* TODO: that's bad, raise an exception */ + return (PyThread_type_lock)NULL; + } + + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void PyThread_free_lock( PyThread_type_lock lock ) +{ + status_t retval; + + dprintf(("PyThread_free_lock(%p) called\n", lock)); + + retval = benaphore_destroy( (benaphore_t *)lock ); + if( retval != EOK ) { + /* TODO: that's bad, raise an exception */ + return; + } +} + +int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag ) +{ + int success; + status_t retval; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + + if( waitflag ) { + retval = benaphore_lock( (benaphore_t *)lock ); + } else { + retval = benaphore_timedlock( (benaphore_t *)lock, 0 ); + } + + if( retval == EOK ) { + success = 1; + } else { + success = 0; + + /* TODO: that's bad, raise an exception */ + } + + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void PyThread_release_lock( PyThread_type_lock lock ) +{ + status_t retval; + + dprintf(("PyThread_release_lock(%p) called\n", lock)); + + retval = benaphore_unlock( (benaphore_t *)lock ); + if( retval != EOK ) { + /* TODO: that's bad, raise an exception */ + return; + } +} diff --git a/sys/src/cmd/python/Python/thread_cthread.h b/sys/src/cmd/python/Python/thread_cthread.h new file mode 100644 index 000000000..ca776c636 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_cthread.h @@ -0,0 +1,156 @@ + +#ifdef MACH_C_THREADS +#include <mach/cthreads.h> +#endif + +#ifdef HURD_C_THREADS +#include <cthreads.h> +#endif + +/* + * Initialization. + */ +static void +PyThread__init_thread(void) +{ +#ifndef HURD_C_THREADS + /* Roland McGrath said this should not be used since this is + done while linking to threads */ + cthread_init(); +#else +/* do nothing */ + ; +#endif +} + +/* + * Thread support. + */ +long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + int success = 0; /* init not needed when SOLARIS_THREADS and */ + /* C_THREADS implemented properly */ + + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + /* looks like solaris detaches the thread to never rejoin + * so well do it here + */ + cthread_detach(cthread_fork((cthread_fn_t) func, arg)); + return success < 0 ? -1 : 0; +} + +long +PyThread_get_thread_ident(void) +{ + if (!initialized) + PyThread_init_thread(); + return (long) cthread_self(); +} + +static void +do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) + if (no_cleanup) + _exit(0); + else + exit(0); + cthread_exit(0); +} + +void +PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void +PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static +void do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void +PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void +PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. + */ +PyThread_type_lock +PyThread_allocate_lock(void) +{ + mutex_t lock; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lock = mutex_alloc(); + if (mutex_init(lock)) { + perror("mutex_init"); + free((void *) lock); + lock = 0; + } + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void +PyThread_free_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_free_lock(%p) called\n", lock)); + mutex_free(lock); +} + +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success = FALSE; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + if (waitflag) { /* blocking */ + mutex_lock((mutex_t)lock); + success = TRUE; + } else { /* non blocking */ + success = mutex_try_lock((mutex_t)lock); + } + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void +PyThread_release_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_release_lock(%p) called\n", lock)); + mutex_unlock((mutex_t )lock); +} diff --git a/sys/src/cmd/python/Python/thread_foobar.h b/sys/src/cmd/python/Python/thread_foobar.h new file mode 100644 index 000000000..67491a167 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_foobar.h @@ -0,0 +1,115 @@ + +/* + * Initialization. + */ +static void +PyThread__init_thread(void) +{ +} + +/* + * Thread support. + */ +long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + int success = 0; /* init not needed when SOLARIS_THREADS and */ + /* C_THREADS implemented properly */ + + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + return success < 0 ? -1 : 0; +} + +long +PyThread_get_thread_ident(void) +{ + if (!initialized) + PyThread_init_thread(); +} + +static +void do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) + if (no_cleanup) + _exit(0); + else + exit(0); +} + +void +PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void +PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static +void do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void +PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void +PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. + */ +PyThread_type_lock +PyThread_allocate_lock(void) +{ + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void +PyThread_free_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_free_lock(%p) called\n", lock)); +} + +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void +PyThread_release_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_release_lock(%p) called\n", lock)); +} diff --git a/sys/src/cmd/python/Python/thread_lwp.h b/sys/src/cmd/python/Python/thread_lwp.h new file mode 100644 index 000000000..e93d65aa3 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_lwp.h @@ -0,0 +1,149 @@ + +#include <stdlib.h> +#include <lwp/lwp.h> +#include <lwp/stackdep.h> + +#define STACKSIZE 1000 /* stacksize for a thread */ +#define NSTACKS 2 /* # stacks to be put in cache initially */ + +struct lock { + int lock_locked; + cv_t lock_condvar; + mon_t lock_monitor; +}; + + +/* + * Initialization. + */ +static void PyThread__init_thread(void) +{ + lwp_setstkcache(STACKSIZE, NSTACKS); +} + +/* + * Thread support. + */ + + +long PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + thread_t tid; + int success; + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg); + return success < 0 ? -1 : 0; +} + +long PyThread_get_thread_ident(void) +{ + thread_t tid; + if (!initialized) + PyThread_init_thread(); + if (lwp_self(&tid) < 0) + return -1; + return tid.thread_id; +} + +static void do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) + if (no_cleanup) + _exit(0); + else + exit(0); + lwp_destroy(SELF); +} + +void PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); + pod_exit(status); +} + +void PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. + */ +PyThread_type_lock PyThread_allocate_lock(void) +{ + struct lock *lock; + extern char *malloc(size_t); + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lock = (struct lock *) malloc(sizeof(struct lock)); + lock->lock_locked = 0; + (void) mon_create(&lock->lock_monitor); + (void) cv_create(&lock->lock_condvar, lock->lock_monitor); + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void PyThread_free_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_free_lock(%p) called\n", lock)); + mon_destroy(((struct lock *) lock)->lock_monitor); + free((char *) lock); +} + +int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + success = 0; + + (void) mon_enter(((struct lock *) lock)->lock_monitor); + if (waitflag) + while (((struct lock *) lock)->lock_locked) + cv_wait(((struct lock *) lock)->lock_condvar); + if (!((struct lock *) lock)->lock_locked) { + success = 1; + ((struct lock *) lock)->lock_locked = 1; + } + cv_broadcast(((struct lock *) lock)->lock_condvar); + mon_exit(((struct lock *) lock)->lock_monitor); + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void PyThread_release_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_release_lock(%p) called\n", lock)); + (void) mon_enter(((struct lock *) lock)->lock_monitor); + ((struct lock *) lock)->lock_locked = 0; + cv_broadcast(((struct lock *) lock)->lock_condvar); + mon_exit(((struct lock *) lock)->lock_monitor); +} diff --git a/sys/src/cmd/python/Python/thread_nt.h b/sys/src/cmd/python/Python/thread_nt.h new file mode 100644 index 000000000..67f5ed517 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_nt.h @@ -0,0 +1,364 @@ + +/* This code implemented by Dag.Gruneau@elsa.preseco.comm.se */ +/* Fast NonRecursiveMutex support by Yakov Markovitch, markovitch@iso.ru */ +/* Eliminated some memory leaks, gsw@agere.com */ + +#include <windows.h> +#include <limits.h> +#ifdef HAVE_PROCESS_H +#include <process.h> +#endif + +typedef struct NRMUTEX { + LONG owned ; + DWORD thread_id ; + HANDLE hevent ; +} NRMUTEX, *PNRMUTEX ; + +typedef PVOID WINAPI interlocked_cmp_xchg_t(PVOID *dest, PVOID exc, PVOID comperand) ; + +/* Sorry mate, but we haven't got InterlockedCompareExchange in Win95! */ +static PVOID WINAPI +interlocked_cmp_xchg(PVOID *dest, PVOID exc, PVOID comperand) +{ + static LONG spinlock = 0 ; + PVOID result ; + DWORD dwSleep = 0; + + /* Acqire spinlock (yielding control to other threads if cant aquire for the moment) */ + while(InterlockedExchange(&spinlock, 1)) + { + // Using Sleep(0) can cause a priority inversion. + // Sleep(0) only yields the processor if there's + // another thread of the same priority that's + // ready to run. If a high-priority thread is + // trying to acquire the lock, which is held by + // a low-priority thread, then the low-priority + // thread may never get scheduled and hence never + // free the lock. NT attempts to avoid priority + // inversions by temporarily boosting the priority + // of low-priority runnable threads, but the problem + // can still occur if there's a medium-priority + // thread that's always runnable. If Sleep(1) is used, + // then the thread unconditionally yields the CPU. We + // only do this for the second and subsequent even + // iterations, since a millisecond is a long time to wait + // if the thread can be scheduled in again sooner + // (~100,000 instructions). + // Avoid priority inversion: 0, 1, 0, 1,... + Sleep(dwSleep); + dwSleep = !dwSleep; + } + result = *dest ; + if (result == comperand) + *dest = exc ; + /* Release spinlock */ + spinlock = 0 ; + return result ; +} ; + +static interlocked_cmp_xchg_t *ixchg; + +BOOL +InitializeNonRecursiveMutex(PNRMUTEX mutex) +{ + if (!ixchg) + { + /* Sorely, Win95 has no InterlockedCompareExchange API (Win98 has), so we have to use emulation */ + HANDLE kernel = GetModuleHandle("kernel32.dll") ; + if (!kernel || (ixchg = (interlocked_cmp_xchg_t *)GetProcAddress(kernel, "InterlockedCompareExchange")) == NULL) + ixchg = interlocked_cmp_xchg ; + } + + mutex->owned = -1 ; /* No threads have entered NonRecursiveMutex */ + mutex->thread_id = 0 ; + mutex->hevent = CreateEvent(NULL, FALSE, FALSE, NULL) ; + return mutex->hevent != NULL ; /* TRUE if the mutex is created */ +} + +#ifdef InterlockedCompareExchange +#undef InterlockedCompareExchange +#endif +#define InterlockedCompareExchange(dest,exchange,comperand) (ixchg((dest), (exchange), (comperand))) + +VOID +DeleteNonRecursiveMutex(PNRMUTEX mutex) +{ + /* No in-use check */ + CloseHandle(mutex->hevent) ; + mutex->hevent = NULL ; /* Just in case */ +} + +DWORD +EnterNonRecursiveMutex(PNRMUTEX mutex, BOOL wait) +{ + /* Assume that the thread waits successfully */ + DWORD ret ; + + /* InterlockedIncrement(&mutex->owned) == 0 means that no thread currently owns the mutex */ + if (!wait) + { + if (InterlockedCompareExchange((PVOID *)&mutex->owned, (PVOID)0, (PVOID)-1) != (PVOID)-1) + return WAIT_TIMEOUT ; + ret = WAIT_OBJECT_0 ; + } + else + ret = InterlockedIncrement(&mutex->owned) ? + /* Some thread owns the mutex, let's wait... */ + WaitForSingleObject(mutex->hevent, INFINITE) : WAIT_OBJECT_0 ; + + mutex->thread_id = GetCurrentThreadId() ; /* We own it */ + return ret ; +} + +BOOL +LeaveNonRecursiveMutex(PNRMUTEX mutex) +{ + /* We don't own the mutex */ + mutex->thread_id = 0 ; + return + InterlockedDecrement(&mutex->owned) < 0 || + SetEvent(mutex->hevent) ; /* Other threads are waiting, wake one on them up */ +} + +PNRMUTEX +AllocNonRecursiveMutex(void) +{ + PNRMUTEX mutex = (PNRMUTEX)malloc(sizeof(NRMUTEX)) ; + if (mutex && !InitializeNonRecursiveMutex(mutex)) + { + free(mutex) ; + mutex = NULL ; + } + return mutex ; +} + +void +FreeNonRecursiveMutex(PNRMUTEX mutex) +{ + if (mutex) + { + DeleteNonRecursiveMutex(mutex) ; + free(mutex) ; + } +} + +long PyThread_get_thread_ident(void); + +/* + * Initialization of the C package, should not be needed. + */ +static void +PyThread__init_thread(void) +{ +} + +/* + * Thread support. + */ + +typedef struct { + void (*func)(void*); + void *arg; + long id; + HANDLE done; +} callobj; + +static int +bootstrap(void *call) +{ + callobj *obj = (callobj*)call; + /* copy callobj since other thread might free it before we're done */ + void (*func)(void*) = obj->func; + void *arg = obj->arg; + + obj->id = PyThread_get_thread_ident(); + ReleaseSemaphore(obj->done, 1, NULL); + func(arg); + return 0; +} + +long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + Py_uintptr_t rv; + callobj obj; + + dprintf(("%ld: PyThread_start_new_thread called\n", + PyThread_get_thread_ident())); + if (!initialized) + PyThread_init_thread(); + + obj.id = -1; /* guilty until proved innocent */ + obj.func = func; + obj.arg = arg; + obj.done = CreateSemaphore(NULL, 0, 1, NULL); + if (obj.done == NULL) + return -1; + + rv = _beginthread(bootstrap, _pythread_stacksize, &obj); + if (rv == (Py_uintptr_t)-1) { + /* I've seen errno == EAGAIN here, which means "there are + * too many threads". + */ + dprintf(("%ld: PyThread_start_new_thread failed: %p errno %d\n", + PyThread_get_thread_ident(), rv, errno)); + obj.id = -1; + } + else { + dprintf(("%ld: PyThread_start_new_thread succeeded: %p\n", + PyThread_get_thread_ident(), rv)); + /* wait for thread to initialize, so we can get its id */ + WaitForSingleObject(obj.done, INFINITE); + assert(obj.id != -1); + } + CloseHandle((HANDLE)obj.done); + return obj.id; +} + +/* + * Return the thread Id instead of an handle. The Id is said to uniquely identify the + * thread in the system + */ +long +PyThread_get_thread_ident(void) +{ + if (!initialized) + PyThread_init_thread(); + + return GetCurrentThreadId(); +} + +static void +do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("%ld: PyThread_exit_thread called\n", PyThread_get_thread_ident())); + if (!initialized) + if (no_cleanup) + _exit(0); + else + exit(0); + _endthread(); +} + +void +PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void +PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void +do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void +PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void +PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. It has too be implemented as semaphores. + * I [Dag] tried to implement it with mutex but I could find a way to + * tell whether a thread already own the lock or not. + */ +PyThread_type_lock +PyThread_allocate_lock(void) +{ + PNRMUTEX aLock; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + aLock = AllocNonRecursiveMutex() ; + + dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); + + return (PyThread_type_lock) aLock; +} + +void +PyThread_free_lock(PyThread_type_lock aLock) +{ + dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); + + FreeNonRecursiveMutex(aLock) ; +} + +/* + * Return 1 on success if the lock was acquired + * + * and 0 if the lock was not acquired. This means a 0 is returned + * if the lock has already been acquired by this thread! + */ +int +PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) +{ + int success ; + + dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag)); + + success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (waitflag ? INFINITE : 0)) == WAIT_OBJECT_0 ; + + dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success)); + + return success; +} + +void +PyThread_release_lock(PyThread_type_lock aLock) +{ + dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); + + if (!(aLock && LeaveNonRecursiveMutex((PNRMUTEX) aLock))) + dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError())); +} + +/* minimum/maximum thread stack sizes supported */ +#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ +#define THREAD_MAX_STACKSIZE 0x10000000 /* 256MB */ + +/* set the thread stack size. + * Return 0 if size is valid, -1 otherwise. + */ +static int +_pythread_nt_set_stacksize(size_t size) +{ + /* set to default */ + if (size == 0) { + _pythread_stacksize = 0; + return 0; + } + + /* valid range? */ + if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) { + _pythread_stacksize = size; + return 0; + } + + return -1; +} + +#define THREAD_SET_STACKSIZE(x) _pythread_nt_set_stacksize(x) diff --git a/sys/src/cmd/python/Python/thread_os2.h b/sys/src/cmd/python/Python/thread_os2.h new file mode 100644 index 000000000..12eeed51c --- /dev/null +++ b/sys/src/cmd/python/Python/thread_os2.h @@ -0,0 +1,307 @@ +/* This code implemented by cvale@netcom.com */ + +#define INCL_DOSPROCESS +#define INCL_DOSSEMAPHORES +#include "os2.h" +#include "limits.h" + +#include "process.h" + +#if defined(PYCC_GCC) +#include <sys/builtin.h> +#include <sys/fmutex.h> +#else +long PyThread_get_thread_ident(void); +#endif + +/* default thread stack size of 64kB */ +#if !defined(THREAD_STACK_SIZE) +#define THREAD_STACK_SIZE 0x10000 +#endif + +#define OS2_STACKSIZE(x) (x ? x : THREAD_STACK_SIZE) + +/* + * Initialization of the C package, should not be needed. + */ +static void +PyThread__init_thread(void) +{ +} + +/* + * Thread support. + */ +long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + int thread_id; + + thread_id = _beginthread(func, + NULL, + OS2_STACKSIZE(_pythread_stacksize), + arg); + + if (thread_id == -1) { + dprintf(("_beginthread failed. return %ld\n", errno)); + } + + return thread_id; +} + +long +PyThread_get_thread_ident(void) +{ +#if !defined(PYCC_GCC) + PPIB pib; + PTIB tib; +#endif + + if (!initialized) + PyThread_init_thread(); + +#if defined(PYCC_GCC) + return _gettid(); +#else + DosGetInfoBlocks(&tib, &pib); + return tib->tib_ptib2->tib2_ultid; +#endif +} + +static void +do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("%ld: PyThread_exit_thread called\n", + PyThread_get_thread_ident())); + if (!initialized) + if (no_cleanup) + _exit(0); + else + exit(0); + _endthread(); +} + +void +PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void +PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void +do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void +PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void +PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. This is implemented with an event semaphore and critical + * sections to make it behave more like a posix mutex than its OS/2 + * counterparts. + */ + +typedef struct os2_lock_t { + int is_set; + HEV changed; +} *type_os2_lock; + +PyThread_type_lock +PyThread_allocate_lock(void) +{ +#if defined(PYCC_GCC) + _fmutex *sem = malloc(sizeof(_fmutex)); + if (!initialized) + PyThread_init_thread(); + dprintf(("%ld: PyThread_allocate_lock() -> %lx\n", + PyThread_get_thread_ident(), + (long)sem)); + if (_fmutex_create(sem, 0)) { + free(sem); + sem = NULL; + } + return (PyThread_type_lock)sem; +#else + APIRET rc; + type_os2_lock lock = (type_os2_lock)malloc(sizeof(struct os2_lock_t)); + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lock->is_set = 0; + + DosCreateEventSem(NULL, &lock->changed, 0, 0); + + dprintf(("%ld: PyThread_allocate_lock() -> %p\n", + PyThread_get_thread_ident(), + lock->changed)); + + return (PyThread_type_lock)lock; +#endif +} + +void +PyThread_free_lock(PyThread_type_lock aLock) +{ +#if !defined(PYCC_GCC) + type_os2_lock lock = (type_os2_lock)aLock; +#endif + + dprintf(("%ld: PyThread_free_lock(%p) called\n", + PyThread_get_thread_ident(),aLock)); + +#if defined(PYCC_GCC) + if (aLock) { + _fmutex_close((_fmutex *)aLock); + free((_fmutex *)aLock); + } +#else + DosCloseEventSem(lock->changed); + free(aLock); +#endif +} + +/* + * Return 1 on success if the lock was acquired + * + * and 0 if the lock was not acquired. + */ +int +PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) +{ +#if !defined(PYCC_GCC) + int done = 0; + ULONG count; + PID pid = 0; + TID tid = 0; + type_os2_lock lock = (type_os2_lock)aLock; +#endif + + dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", + PyThread_get_thread_ident(), + aLock, + waitflag)); + +#if defined(PYCC_GCC) + /* always successful if the lock doesn't exist */ + if (aLock && + _fmutex_request((_fmutex *)aLock, waitflag ? 0 : _FMR_NOWAIT)) + return 0; +#else + while (!done) { + /* if the lock is currently set, we have to wait for + * the state to change + */ + if (lock->is_set) { + if (!waitflag) + return 0; + DosWaitEventSem(lock->changed, SEM_INDEFINITE_WAIT); + } + + /* enter a critical section and try to get the semaphore. If + * it is still locked, we will try again. + */ + if (DosEnterCritSec()) + return 0; + + if (!lock->is_set) { + lock->is_set = 1; + DosResetEventSem(lock->changed, &count); + done = 1; + } + + DosExitCritSec(); + } +#endif + + return 1; +} + +void +PyThread_release_lock(PyThread_type_lock aLock) +{ +#if !defined(PYCC_GCC) + type_os2_lock lock = (type_os2_lock)aLock; +#endif + + dprintf(("%ld: PyThread_release_lock(%p) called\n", + PyThread_get_thread_ident(), + aLock)); + +#if defined(PYCC_GCC) + if (aLock) + _fmutex_release((_fmutex *)aLock); +#else + if (!lock->is_set) { + dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", + PyThread_get_thread_ident(), + aLock, + GetLastError())); + return; + } + + if (DosEnterCritSec()) { + dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", + PyThread_get_thread_ident(), + aLock, + GetLastError())); + return; + } + + lock->is_set = 0; + DosPostEventSem(lock->changed); + + DosExitCritSec(); +#endif +} + +/* minimum/maximum thread stack sizes supported */ +#define THREAD_MIN_STACKSIZE 0x8000 /* 32kB */ +#define THREAD_MAX_STACKSIZE 0x2000000 /* 32MB */ + +/* set the thread stack size. + * Return 0 if size is valid, -1 otherwise. + */ +static int +_pythread_os2_set_stacksize(size_t size) +{ + /* set to default */ + if (size == 0) { + _pythread_stacksize = 0; + return 0; + } + + /* valid range? */ + if (size >= THREAD_MIN_STACKSIZE && size < THREAD_MAX_STACKSIZE) { + _pythread_stacksize = size; + return 0; + } + + return -1; +} + +#define THREAD_SET_STACKSIZE(x) _pythread_os2_set_stacksize(x) diff --git a/sys/src/cmd/python/Python/thread_plan9.h b/sys/src/cmd/python/Python/thread_plan9.h new file mode 100644 index 000000000..d0504806e --- /dev/null +++ b/sys/src/cmd/python/Python/thread_plan9.h @@ -0,0 +1,135 @@ +#define _PLAN9_SOURCE +#include <u.h> +#include <lib9.h> +#include <qlock.h> + +/* + * Initialization. + */ +static void +PyThread__init_thread(void) +{ +} + +/* + * Thread support. + */ +long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + switch(rfork(RFPROC|RFMEM)){ + case -1: + printf("rfork: %r\n"); + return -1; + case 0: + _threadarg->fn = func; + _threadarg->arg = arg; + longjmp(_threadarg->jb, 1); + default: + return 0; + } +} + +long +PyThread_get_thread_ident(void) +{ + if (!initialized) + PyThread_init_thread(); + return getpid(); +} + +void +PyThread_exit_thread(void) +{ + if(initialized) + _exit(0); + exit(0); +} + +void +PyThread__exit_thread(void) +{ + _exit(0); +} + +#ifndef NO_EXIT_PROG +static +void do_PyThread_exit_prog(int status, int no_cleanup) +{ + /* + * BUG BUG BUG + */ + + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void +PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void +PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. + */ +PyThread_type_lock +PyThread_allocate_lock(void) +{ + QLock *lk; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lk = malloc(sizeof(*lk)); + memset(lk, 0, sizeof(*lk)); + dprintf(("PyThread_allocate_lock() -> %p\n", lk)); + return lk; +} + +void +PyThread_free_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_free_lock(%p) called\n", lock)); + free(lock); +} + +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + if(lock == nil) + success = 0; + else if(waitflag){ + qlock(lock); + success = 1; + }else + success = canqlock(lock); + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void +PyThread_release_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_release_lock(%p) called\n", lock)); + qunlock(lock); +} + diff --git a/sys/src/cmd/python/Python/thread_pth.h b/sys/src/cmd/python/Python/thread_pth.h new file mode 100644 index 000000000..8c7dbe925 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_pth.h @@ -0,0 +1,213 @@ + +/* GNU pth threads interface + http://www.gnu.org/software/pth + 2000-05-03 Andy Dustman <andy@dustman.net> + + Adapted from Posix threads interface + 12 May 1997 -- david arnold <davida@pobox.com> + */ + +#include <stdlib.h> +#include <string.h> +#include <pth.h> + +/* A pth mutex isn't sufficient to model the Python lock type + * because pth mutexes can be acquired multiple times by the + * same thread. + * + * The pth_lock struct implements a Python lock as a "locked?" bit + * and a <condition, mutex> pair. In general, if the bit can be acquired + * instantly, it is, else the pair is used to block the thread until the + * bit is cleared. + */ + +typedef struct { + char locked; /* 0=unlocked, 1=locked */ + /* a <cond, mutex> pair to handle an acquire of a locked lock */ + pth_cond_t lock_released; + pth_mutex_t mut; +} pth_lock; + +#define CHECK_STATUS(name) if (status == -1) { printf("%d ", status); perror(name); error = 1; } + +pth_attr_t PyThread_attr; + +/* + * Initialization. + */ + +static void PyThread__init_thread(void) +{ + pth_init(); + PyThread_attr = pth_attr_new(); + pth_attr_set(PyThread_attr, PTH_ATTR_STACK_SIZE, 1<<18); + pth_attr_set(PyThread_attr, PTH_ATTR_JOINABLE, FALSE); +} + +/* + * Thread support. + */ + + +long PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + pth_t th; + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + + th = pth_spawn(PyThread_attr, + (void* (*)(void *))func, + (void *)arg + ); + + return th; +} + +long PyThread_get_thread_ident(void) +{ + volatile pth_t threadid; + if (!initialized) + PyThread_init_thread(); + /* Jump through some hoops for Alpha OSF/1 */ + threadid = pth_self(); + return (long) *(long *) &threadid; +} + +static void do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) { + if (no_cleanup) + _exit(0); + else + exit(0); + } +} + +void PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. + */ +PyThread_type_lock PyThread_allocate_lock(void) +{ + pth_lock *lock; + int status, error = 0; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lock = (pth_lock *) malloc(sizeof(pth_lock)); + memset((void *)lock, '\0', sizeof(pth_lock)); + if (lock) { + lock->locked = 0; + status = pth_mutex_init(&lock->mut); + CHECK_STATUS("pth_mutex_init"); + status = pth_cond_init(&lock->lock_released); + CHECK_STATUS("pth_cond_init"); + if (error) { + free((void *)lock); + lock = NULL; + } + } + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void PyThread_free_lock(PyThread_type_lock lock) +{ + pth_lock *thelock = (pth_lock *)lock; + + dprintf(("PyThread_free_lock(%p) called\n", lock)); + + free((void *)thelock); +} + +int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + pth_lock *thelock = (pth_lock *)lock; + int status, error = 0; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + + status = pth_mutex_acquire(&thelock->mut, !waitflag, NULL); + CHECK_STATUS("pth_mutex_acquire[1]"); + success = thelock->locked == 0; + if (success) thelock->locked = 1; + status = pth_mutex_release( &thelock->mut ); + CHECK_STATUS("pth_mutex_release[1]"); + + if ( !success && waitflag ) { + /* continue trying until we get the lock */ + + /* mut must be locked by me -- part of the condition + * protocol */ + status = pth_mutex_acquire( &thelock->mut, !waitflag, NULL ); + CHECK_STATUS("pth_mutex_acquire[2]"); + while ( thelock->locked ) { + status = pth_cond_await(&thelock->lock_released, + &thelock->mut, NULL); + CHECK_STATUS("pth_cond_await"); + } + thelock->locked = 1; + status = pth_mutex_release( &thelock->mut ); + CHECK_STATUS("pth_mutex_release[2]"); + success = 1; + } + if (error) success = 0; + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void PyThread_release_lock(PyThread_type_lock lock) +{ + pth_lock *thelock = (pth_lock *)lock; + int status, error = 0; + + dprintf(("PyThread_release_lock(%p) called\n", lock)); + + status = pth_mutex_acquire( &thelock->mut, 0, NULL ); + CHECK_STATUS("pth_mutex_acquire[3]"); + + thelock->locked = 0; + + status = pth_mutex_release( &thelock->mut ); + CHECK_STATUS("pth_mutex_release[3]"); + + /* wake up someone (anyone, if any) waiting on the lock */ + status = pth_cond_notify( &thelock->lock_released, 0 ); + CHECK_STATUS("pth_cond_notify"); +} diff --git a/sys/src/cmd/python/Python/thread_pthread.h b/sys/src/cmd/python/Python/thread_pthread.h new file mode 100644 index 000000000..60d2fb216 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_pthread.h @@ -0,0 +1,533 @@ + +/* Posix threads interface */ + +#include <stdlib.h> +#include <string.h> +#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR) +#define destructor xxdestructor +#endif +#include <pthread.h> +#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR) +#undef destructor +#endif +#include <signal.h> + +/* The POSIX spec requires that use of pthread_attr_setstacksize + be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */ +#ifdef _POSIX_THREAD_ATTR_STACKSIZE +#ifndef THREAD_STACK_SIZE +#define THREAD_STACK_SIZE 0 /* use default stack size */ +#endif +/* for safety, ensure a viable minimum stacksize */ +#define THREAD_STACK_MIN 0x8000 /* 32kB */ +#else /* !_POSIX_THREAD_ATTR_STACKSIZE */ +#ifdef THREAD_STACK_SIZE +#error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined" +#endif +#endif + +/* The POSIX spec says that implementations supporting the sem_* + family of functions must indicate this by defining + _POSIX_SEMAPHORES. */ +#ifdef _POSIX_SEMAPHORES +/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so + we need to add 0 to make it work there as well. */ +#if (_POSIX_SEMAPHORES+0) == -1 +#define HAVE_BROKEN_POSIX_SEMAPHORES +#else +#include <semaphore.h> +#include <errno.h> +#endif +#endif + +/* Before FreeBSD 5.4, system scope threads was very limited resource + in default setting. So the process scope is preferred to get + enough number of threads to work. */ +#ifdef __FreeBSD__ +#include <osreldate.h> +#if __FreeBSD_version >= 500000 && __FreeBSD_version < 504101 +#undef PTHREAD_SYSTEM_SCHED_SUPPORTED +#endif +#endif + +#if !defined(pthread_attr_default) +# define pthread_attr_default ((pthread_attr_t *)NULL) +#endif +#if !defined(pthread_mutexattr_default) +# define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL) +#endif +#if !defined(pthread_condattr_default) +# define pthread_condattr_default ((pthread_condattr_t *)NULL) +#endif + + +/* Whether or not to use semaphores directly rather than emulating them with + * mutexes and condition variables: + */ +#if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) +# define USE_SEMAPHORES +#else +# undef USE_SEMAPHORES +#endif + + +/* On platforms that don't use standard POSIX threads pthread_sigmask() + * isn't present. DEC threads uses sigprocmask() instead as do most + * other UNIX International compliant systems that don't have the full + * pthread implementation. + */ +#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) +# define SET_THREAD_SIGMASK pthread_sigmask +#else +# define SET_THREAD_SIGMASK sigprocmask +#endif + + +/* A pthread mutex isn't sufficient to model the Python lock type + * because, according to Draft 5 of the docs (P1003.4a/D5), both of the + * following are undefined: + * -> a thread tries to lock a mutex it already has locked + * -> a thread tries to unlock a mutex locked by a different thread + * pthread mutexes are designed for serializing threads over short pieces + * of code anyway, so wouldn't be an appropriate implementation of + * Python's locks regardless. + * + * The pthread_lock struct implements a Python lock as a "locked?" bit + * and a <condition, mutex> pair. In general, if the bit can be acquired + * instantly, it is, else the pair is used to block the thread until the + * bit is cleared. 9 May 1994 tim@ksr.com + */ + +typedef struct { + char locked; /* 0=unlocked, 1=locked */ + /* a <cond, mutex> pair to handle an acquire of a locked lock */ + pthread_cond_t lock_released; + pthread_mutex_t mut; +} pthread_lock; + +#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; } + +/* + * Initialization. + */ + +#ifdef _HAVE_BSDI +static +void _noop(void) +{ +} + +static void +PyThread__init_thread(void) +{ + /* DO AN INIT BY STARTING THE THREAD */ + static int dummy = 0; + pthread_t thread1; + pthread_create(&thread1, NULL, (void *) _noop, &dummy); + pthread_join(thread1, NULL); +} + +#else /* !_HAVE_BSDI */ + +static void +PyThread__init_thread(void) +{ +#if defined(_AIX) && defined(__GNUC__) + pthread_init(); +#endif +} + +#endif /* !_HAVE_BSDI */ + +/* + * Thread support. + */ + + +long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + pthread_t th; + int status; +#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) + pthread_attr_t attrs; +#endif +#if defined(THREAD_STACK_SIZE) + size_t tss; +#endif + + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + +#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) + if (pthread_attr_init(&attrs) != 0) + return -1; +#endif +#if defined(THREAD_STACK_SIZE) + tss = (_pythread_stacksize != 0) ? _pythread_stacksize + : THREAD_STACK_SIZE; + if (tss != 0) { + if (pthread_attr_setstacksize(&attrs, tss) != 0) { + pthread_attr_destroy(&attrs); + return -1; + } + } +#endif +#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) + pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); +#endif + + status = pthread_create(&th, +#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) + &attrs, +#else + (pthread_attr_t*)NULL, +#endif + (void* (*)(void *))func, + (void *)arg + ); + +#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) + pthread_attr_destroy(&attrs); +#endif + if (status != 0) + return -1; + + pthread_detach(th); + +#if SIZEOF_PTHREAD_T <= SIZEOF_LONG + return (long) th; +#else + return (long) *(long *) &th; +#endif +} + +/* XXX This implementation is considered (to quote Tim Peters) "inherently + hosed" because: + - It does not guarantee the promise that a non-zero integer is returned. + - The cast to long is inherently unsafe. + - It is not clear that the 'volatile' (for AIX?) and ugly casting in the + latter return statement (for Alpha OSF/1) are any longer necessary. +*/ +long +PyThread_get_thread_ident(void) +{ + volatile pthread_t threadid; + if (!initialized) + PyThread_init_thread(); + /* Jump through some hoops for Alpha OSF/1 */ + threadid = pthread_self(); +#if SIZEOF_PTHREAD_T <= SIZEOF_LONG + return (long) threadid; +#else + return (long) *(long *) &threadid; +#endif +} + +static void +do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) { + if (no_cleanup) + _exit(0); + else + exit(0); + } +} + +void +PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void +PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void +do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void +PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void +PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +#ifdef USE_SEMAPHORES + +/* + * Lock support. + */ + +PyThread_type_lock +PyThread_allocate_lock(void) +{ + sem_t *lock; + int status, error = 0; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lock = (sem_t *)malloc(sizeof(sem_t)); + + if (lock) { + status = sem_init(lock,0,1); + CHECK_STATUS("sem_init"); + + if (error) { + free((void *)lock); + lock = NULL; + } + } + + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock)lock; +} + +void +PyThread_free_lock(PyThread_type_lock lock) +{ + sem_t *thelock = (sem_t *)lock; + int status, error = 0; + + dprintf(("PyThread_free_lock(%p) called\n", lock)); + + if (!thelock) + return; + + status = sem_destroy(thelock); + CHECK_STATUS("sem_destroy"); + + free((void *)thelock); +} + +/* + * As of February 2002, Cygwin thread implementations mistakenly report error + * codes in the return value of the sem_ calls (like the pthread_ functions). + * Correct implementations return -1 and put the code in errno. This supports + * either. + */ +static int +fix_status(int status) +{ + return (status == -1) ? errno : status; +} + +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + sem_t *thelock = (sem_t *)lock; + int status, error = 0; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + + do { + if (waitflag) + status = fix_status(sem_wait(thelock)); + else + status = fix_status(sem_trywait(thelock)); + } while (status == EINTR); /* Retry if interrupted by a signal */ + + if (waitflag) { + CHECK_STATUS("sem_wait"); + } else if (status != EAGAIN) { + CHECK_STATUS("sem_trywait"); + } + + success = (status == 0) ? 1 : 0; + + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void +PyThread_release_lock(PyThread_type_lock lock) +{ + sem_t *thelock = (sem_t *)lock; + int status, error = 0; + + dprintf(("PyThread_release_lock(%p) called\n", lock)); + + status = sem_post(thelock); + CHECK_STATUS("sem_post"); +} + +#else /* USE_SEMAPHORES */ + +/* + * Lock support. + */ +PyThread_type_lock +PyThread_allocate_lock(void) +{ + pthread_lock *lock; + int status, error = 0; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lock = (pthread_lock *) malloc(sizeof(pthread_lock)); + if (lock) { + memset((void *)lock, '\0', sizeof(pthread_lock)); + lock->locked = 0; + + status = pthread_mutex_init(&lock->mut, + pthread_mutexattr_default); + CHECK_STATUS("pthread_mutex_init"); + + status = pthread_cond_init(&lock->lock_released, + pthread_condattr_default); + CHECK_STATUS("pthread_cond_init"); + + if (error) { + free((void *)lock); + lock = 0; + } + } + + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void +PyThread_free_lock(PyThread_type_lock lock) +{ + pthread_lock *thelock = (pthread_lock *)lock; + int status, error = 0; + + dprintf(("PyThread_free_lock(%p) called\n", lock)); + + status = pthread_mutex_destroy( &thelock->mut ); + CHECK_STATUS("pthread_mutex_destroy"); + + status = pthread_cond_destroy( &thelock->lock_released ); + CHECK_STATUS("pthread_cond_destroy"); + + free((void *)thelock); +} + +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + pthread_lock *thelock = (pthread_lock *)lock; + int status, error = 0; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + + status = pthread_mutex_lock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_lock[1]"); + success = thelock->locked == 0; + + if ( !success && waitflag ) { + /* continue trying until we get the lock */ + + /* mut must be locked by me -- part of the condition + * protocol */ + while ( thelock->locked ) { + status = pthread_cond_wait(&thelock->lock_released, + &thelock->mut); + CHECK_STATUS("pthread_cond_wait"); + } + success = 1; + } + if (success) thelock->locked = 1; + status = pthread_mutex_unlock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_unlock[1]"); + + if (error) success = 0; + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void +PyThread_release_lock(PyThread_type_lock lock) +{ + pthread_lock *thelock = (pthread_lock *)lock; + int status, error = 0; + + dprintf(("PyThread_release_lock(%p) called\n", lock)); + + status = pthread_mutex_lock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_lock[3]"); + + thelock->locked = 0; + + status = pthread_mutex_unlock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_unlock[3]"); + + /* wake up someone (anyone, if any) waiting on the lock */ + status = pthread_cond_signal( &thelock->lock_released ); + CHECK_STATUS("pthread_cond_signal"); +} + +#endif /* USE_SEMAPHORES */ + +/* set the thread stack size. + * Return 0 if size is valid, -1 if size is invalid, + * -2 if setting stack size is not supported. + */ +static int +_pythread_pthread_set_stacksize(size_t size) +{ +#if defined(THREAD_STACK_SIZE) + pthread_attr_t attrs; + size_t tss_min; + int rc = 0; +#endif + + /* set to default */ + if (size == 0) { + _pythread_stacksize = 0; + return 0; + } + +#if defined(THREAD_STACK_SIZE) +#if defined(PTHREAD_STACK_MIN) + tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN + : THREAD_STACK_MIN; +#else + tss_min = THREAD_STACK_MIN; +#endif + if (size >= tss_min) { + /* validate stack size by setting thread attribute */ + if (pthread_attr_init(&attrs) == 0) { + rc = pthread_attr_setstacksize(&attrs, size); + pthread_attr_destroy(&attrs); + if (rc == 0) { + _pythread_stacksize = size; + return 0; + } + } + } + return -1; +#else + return -2; +#endif +} + +#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) diff --git a/sys/src/cmd/python/Python/thread_sgi.h b/sys/src/cmd/python/Python/thread_sgi.h new file mode 100644 index 000000000..234665848 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_sgi.h @@ -0,0 +1,375 @@ + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/prctl.h> +#include <ulocks.h> +#include <errno.h> + +#define HDR_SIZE 2680 /* sizeof(ushdr_t) */ +#define MAXPROC 100 /* max # of threads that can be started */ + +static usptr_t *shared_arena; +static ulock_t count_lock; /* protection for some variables */ +static ulock_t wait_lock; /* lock used to wait for other threads */ +static int waiting_for_threads; /* protected by count_lock */ +static int nthreads; /* protected by count_lock */ +static int exit_status; +#ifndef NO_EXIT_PROG +static int do_exit; /* indicates that the program is to exit */ +#endif +static int exiting; /* we're already exiting (for maybe_exit) */ +static pid_t my_pid; /* PID of main thread */ +static struct pidlist { + pid_t parent; + pid_t child; +} pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */ +static int maxpidindex; /* # of PIDs in pidlist */ + +#ifndef NO_EXIT_PROG +/* + * This routine is called as a signal handler when another thread + * exits. When that happens, we must see whether we have to exit as + * well (because of an PyThread_exit_prog()) or whether we should continue on. + */ +static void exit_sig(void) +{ + d2printf(("exit_sig called\n")); + if (exiting && getpid() == my_pid) { + d2printf(("already exiting\n")); + return; + } + if (do_exit) { + d2printf(("exiting in exit_sig\n")); +#ifdef Py_DEBUG + if ((thread_debug & 8) == 0) + thread_debug &= ~1; /* don't produce debug messages */ +#endif + PyThread_exit_thread(); + } +} + +/* + * This routine is called when a process calls exit(). If that wasn't + * done from the library, we do as if an PyThread_exit_prog() was intended. + */ +static void maybe_exit(void) +{ + dprintf(("maybe_exit called\n")); + if (exiting) { + dprintf(("already exiting\n")); + return; + } + PyThread_exit_prog(0); +} +#endif /* NO_EXIT_PROG */ + +/* + * Initialization. + */ +static void PyThread__init_thread(void) +{ +#ifndef NO_EXIT_PROG + struct sigaction s; +#endif /* NO_EXIT_PROG */ +#ifdef USE_DL + long addr, size; +#endif /* USE_DL */ + + +#ifdef USE_DL + if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) + perror("usconfig - CONF_INITSIZE (check)"); + if (usconfig(CONF_INITSIZE, size) < 0) + perror("usconfig - CONF_INITSIZE (reset)"); + addr = (long) dl_getrange(size + HDR_SIZE); + dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size)); + errno = 0; + if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0) + perror("usconfig - CONF_ATTACHADDR (set)"); +#endif /* USE_DL */ + if (usconfig(CONF_INITUSERS, 16) < 0) + perror("usconfig - CONF_INITUSERS"); + my_pid = getpid(); /* so that we know which is the main thread */ +#ifndef NO_EXIT_PROG + atexit(maybe_exit); + s.sa_handler = exit_sig; + sigemptyset(&s.sa_mask); + /*sigaddset(&s.sa_mask, SIGUSR1);*/ + s.sa_flags = 0; + sigaction(SIGUSR1, &s, 0); + if (prctl(PR_SETEXITSIG, SIGUSR1) < 0) + perror("prctl - PR_SETEXITSIG"); +#endif /* NO_EXIT_PROG */ + if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) + perror("usconfig - CONF_ARENATYPE"); + usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */ +#ifdef Py_DEBUG + if (thread_debug & 4) + usconfig(CONF_LOCKTYPE, US_DEBUGPLUS); + else if (thread_debug & 2) + usconfig(CONF_LOCKTYPE, US_DEBUG); +#endif /* Py_DEBUG */ + if ((shared_arena = usinit(tmpnam(0))) == 0) + perror("usinit"); +#ifdef USE_DL + if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */ + perror("usconfig - CONF_ATTACHADDR (reset)"); +#endif /* USE_DL */ + if ((count_lock = usnewlock(shared_arena)) == NULL) + perror("usnewlock (count_lock)"); + (void) usinitlock(count_lock); + if ((wait_lock = usnewlock(shared_arena)) == NULL) + perror("usnewlock (wait_lock)"); + dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena))); +} + +/* + * Thread support. + */ + +static void clean_threads(void) +{ + int i, j; + pid_t mypid, pid; + + /* clean up any exited threads */ + mypid = getpid(); + i = 0; + while (i < maxpidindex) { + if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) { + pid = waitpid(pid, 0, WNOHANG); + if (pid > 0) { + /* a thread has exited */ + pidlist[i] = pidlist[--maxpidindex]; + /* remove references to children of dead proc */ + for (j = 0; j < maxpidindex; j++) + if (pidlist[j].parent == pid) + pidlist[j].child = -1; + continue; /* don't increment i */ + } + } + i++; + } + /* clean up the list */ + i = 0; + while (i < maxpidindex) { + if (pidlist[i].child == -1) { + pidlist[i] = pidlist[--maxpidindex]; + continue; /* don't increment i */ + } + i++; + } +} + +long PyThread_start_new_thread(void (*func)(void *), void *arg) +{ +#ifdef USE_DL + long addr, size; + static int local_initialized = 0; +#endif /* USE_DL */ + int success = 0; /* init not needed when SOLARIS_THREADS and */ + /* C_THREADS implemented properly */ + + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + switch (ussetlock(count_lock)) { + case 0: return 0; + case -1: perror("ussetlock (count_lock)"); + } + if (maxpidindex >= MAXPROC) + success = -1; + else { +#ifdef USE_DL + if (!local_initialized) { + if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) + perror("usconfig - CONF_INITSIZE (check)"); + if (usconfig(CONF_INITSIZE, size) < 0) + perror("usconfig - CONF_INITSIZE (reset)"); + addr = (long) dl_getrange(size + HDR_SIZE); + dprintf(("trying to use addr %p-%p for sproc\n", + addr, addr+size)); + errno = 0; + if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && + errno != 0) + perror("usconfig - CONF_ATTACHADDR (set)"); + } +#endif /* USE_DL */ + clean_threads(); + if ((success = sproc(func, PR_SALL, arg)) < 0) + perror("sproc"); +#ifdef USE_DL + if (!local_initialized) { + if (usconfig(CONF_ATTACHADDR, addr) < 0) + /* reset address */ + perror("usconfig - CONF_ATTACHADDR (reset)"); + local_initialized = 1; + } +#endif /* USE_DL */ + if (success >= 0) { + nthreads++; + pidlist[maxpidindex].parent = getpid(); + pidlist[maxpidindex++].child = success; + dprintf(("pidlist[%d] = %d\n", + maxpidindex-1, success)); + } + } + if (usunsetlock(count_lock) < 0) + perror("usunsetlock (count_lock)"); + return success; +} + +long PyThread_get_thread_ident(void) +{ + return getpid(); +} + +static void do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) + if (no_cleanup) + _exit(0); + else + exit(0); + if (ussetlock(count_lock) < 0) + perror("ussetlock (count_lock)"); + nthreads--; + if (getpid() == my_pid) { + /* main thread; wait for other threads to exit */ + exiting = 1; +#ifndef NO_EXIT_PROG + if (do_exit) { + int i; + + /* notify other threads */ + clean_threads(); + if (nthreads >= 0) { + dprintf(("kill other threads\n")); + for (i = 0; i < maxpidindex; i++) + if (pidlist[i].child > 0) + (void) kill(pidlist[i].child, + SIGKILL); + _exit(exit_status); + } + } +#endif /* NO_EXIT_PROG */ + waiting_for_threads = 1; + if (ussetlock(wait_lock) < 0) + perror("ussetlock (wait_lock)"); + for (;;) { + if (nthreads < 0) { + dprintf(("really exit (%d)\n", exit_status)); + if (no_cleanup) + _exit(exit_status); + else + exit(exit_status); + } + if (usunsetlock(count_lock) < 0) + perror("usunsetlock (count_lock)"); + dprintf(("waiting for other threads (%d)\n", nthreads)); + if (ussetlock(wait_lock) < 0) + perror("ussetlock (wait_lock)"); + if (ussetlock(count_lock) < 0) + perror("ussetlock (count_lock)"); + } + } + /* not the main thread */ + if (waiting_for_threads) { + dprintf(("main thread is waiting\n")); + if (usunsetlock(wait_lock) < 0) + perror("usunsetlock (wait_lock)"); + } +#ifndef NO_EXIT_PROG + else if (do_exit) + (void) kill(my_pid, SIGUSR1); +#endif /* NO_EXIT_PROG */ + if (usunsetlock(count_lock) < 0) + perror("usunsetlock (count_lock)"); + _exit(0); +} + +void PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); + do_exit = 1; + exit_status = status; + do_PyThread_exit_thread(no_cleanup); +} + +void PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. + */ +PyThread_type_lock PyThread_allocate_lock(void) +{ + ulock_t lock; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + if ((lock = usnewlock(shared_arena)) == NULL) + perror("usnewlock"); + (void) usinitlock(lock); + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void PyThread_free_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_free_lock(%p) called\n", lock)); + usfreelock((ulock_t) lock, shared_arena); +} + +int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + errno = 0; /* clear it just in case */ + if (waitflag) + success = ussetlock((ulock_t) lock); + else + success = uscsetlock((ulock_t) lock, 1); /* Try it once */ + if (success < 0) + perror(waitflag ? "ussetlock" : "uscsetlock"); + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void PyThread_release_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_release_lock(%p) called\n", lock)); + if (usunsetlock((ulock_t) lock) < 0) + perror("usunsetlock"); +} diff --git a/sys/src/cmd/python/Python/thread_solaris.h b/sys/src/cmd/python/Python/thread_solaris.h new file mode 100644 index 000000000..ff3e6f359 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_solaris.h @@ -0,0 +1,174 @@ + +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include </usr/include/thread.h> +#undef _POSIX_THREADS + + +/* + * Initialization. + */ +static void PyThread__init_thread(void) +{ +} + +/* + * Thread support. + */ +struct func_arg { + void (*func)(void *); + void *arg; +}; + +static void * +new_func(void *funcarg) +{ + void (*func)(void *); + void *arg; + + func = ((struct func_arg *) funcarg)->func; + arg = ((struct func_arg *) funcarg)->arg; + free(funcarg); + (*func)(arg); + return 0; +} + + +long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + thread_t tid; + struct func_arg *funcarg; + + dprintf(("PyThread_start_new_thread called\n")); + if (!initialized) + PyThread_init_thread(); + funcarg = (struct func_arg *) malloc(sizeof(struct func_arg)); + funcarg->func = func; + funcarg->arg = arg; + if (thr_create(0, 0, new_func, funcarg, + THR_DETACHED | THR_NEW_LWP, &tid)) { + perror("thr_create"); + free((void *) funcarg); + return -1; + } + return tid; +} + +long +PyThread_get_thread_ident(void) +{ + if (!initialized) + PyThread_init_thread(); + return thr_self(); +} + +static void +do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("PyThread_exit_thread called\n")); + if (!initialized) + if (no_cleanup) + _exit(0); + else + exit(0); + thr_exit(0); +} + +void +PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void +PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void +do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void +PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void +PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. + */ +PyThread_type_lock +PyThread_allocate_lock(void) +{ + mutex_t *lock; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + lock = (mutex_t *) malloc(sizeof(mutex_t)); + if (mutex_init(lock, USYNC_THREAD, 0)) { + perror("mutex_init"); + free((void *) lock); + lock = 0; + } + dprintf(("PyThread_allocate_lock() -> %p\n", lock)); + return (PyThread_type_lock) lock; +} + +void +PyThread_free_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_free_lock(%p) called\n", lock)); + mutex_destroy((mutex_t *) lock); + free((void *) lock); +} + +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + int success; + + dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); + if (waitflag) + success = mutex_lock((mutex_t *) lock); + else + success = mutex_trylock((mutex_t *) lock); + if (success < 0) + perror(waitflag ? "mutex_lock" : "mutex_trylock"); + else + success = !success; /* solaris does it the other way round */ + dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); + return success; +} + +void +PyThread_release_lock(PyThread_type_lock lock) +{ + dprintf(("PyThread_release_lock(%p) called\n", lock)); + if (mutex_unlock((mutex_t *) lock)) + perror("mutex_unlock"); +} diff --git a/sys/src/cmd/python/Python/thread_wince.h b/sys/src/cmd/python/Python/thread_wince.h new file mode 100644 index 000000000..e16f5d141 --- /dev/null +++ b/sys/src/cmd/python/Python/thread_wince.h @@ -0,0 +1,171 @@ + +/* This code implemented by Mark Hammond (MHammond@skippinet.com.au) */ + +#include <windows.h> +#include <limits.h> +#include <pydebug.h> + +long PyThread_get_thread_ident(void); + +/* + * Change all headers to pure ANSI as no one will use K&R style on an + * NT + */ + +/* + * Initialization of the C package, should not be needed. + */ +static void PyThread__init_thread(void) +{ +} + +/* + * Thread support. + */ +long PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + long rv; + int success = -1; + + dprintf(("%ld: PyThread_start_new_thread called\n", PyThread_get_thread_ident())); + if (!initialized) + PyThread_init_thread(); + + rv = _beginthread(func, 0, arg); /* use default stack size */ + + if (rv != -1) { + success = 0; + dprintf(("%ld: PyThread_start_new_thread succeeded:\n", PyThread_get_thread_ident())); + } + + return success; +} + +/* + * Return the thread Id instead of an handle. The Id is said to uniquely identify the + * thread in the system + */ +long PyThread_get_thread_ident(void) +{ + if (!initialized) + PyThread_init_thread(); + + return GetCurrentThreadId(); +} + +static void do_PyThread_exit_thread(int no_cleanup) +{ + dprintf(("%ld: do_PyThread_exit_thread called\n", PyThread_get_thread_ident())); + if (!initialized) + if (no_cleanup) + exit(0); /* XXX - was _exit()!! */ + else + exit(0); + _endthread(); +} + +void PyThread_exit_thread(void) +{ + do_PyThread_exit_thread(0); +} + +void PyThread__exit_thread(void) +{ + do_PyThread_exit_thread(1); +} + +#ifndef NO_EXIT_PROG +static void do_PyThread_exit_prog(int status, int no_cleanup) +{ + dprintf(("PyThread_exit_prog(%d) called\n", status)); + if (!initialized) + if (no_cleanup) + _exit(status); + else + exit(status); +} + +void PyThread_exit_prog(int status) +{ + do_PyThread_exit_prog(status, 0); +} + +void PyThread__exit_prog(int status) +{ + do_PyThread_exit_prog(status, 1); +} +#endif /* NO_EXIT_PROG */ + +/* + * Lock support. It has to be implemented using Mutexes, as + * CE doesnt support semaphores. Therefore we use some hacks to + * simulate the non reentrant requirements of Python locks + */ +PyThread_type_lock PyThread_allocate_lock(void) +{ + HANDLE aLock; + + dprintf(("PyThread_allocate_lock called\n")); + if (!initialized) + PyThread_init_thread(); + + aLock = CreateEvent(NULL, /* Security attributes */ + 0, /* Manual-Reset */ + 1, /* Is initially signalled */ + NULL); /* Name of event */ + + dprintf(("%ld: PyThread_allocate_lock() -> %p\n", PyThread_get_thread_ident(), aLock)); + + return (PyThread_type_lock) aLock; +} + +void PyThread_free_lock(PyThread_type_lock aLock) +{ + dprintf(("%ld: PyThread_free_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); + + CloseHandle(aLock); +} + +/* + * Return 1 on success if the lock was acquired + * + * and 0 if the lock was not acquired. This means a 0 is returned + * if the lock has already been acquired by this thread! + */ +int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) +{ + int success = 1; + DWORD waitResult; + + dprintf(("%ld: PyThread_acquire_lock(%p, %d) called\n", PyThread_get_thread_ident(),aLock, waitflag)); + +#ifndef DEBUG + waitResult = WaitForSingleObject(aLock, (waitflag ? INFINITE : 0)); +#else + /* To aid in debugging, we regularly wake up. This allows us to + break into the debugger */ + while (TRUE) { + waitResult = WaitForSingleObject(aLock, waitflag ? 3000 : 0); + if (waitflag==0 || (waitflag && waitResult == WAIT_OBJECT_0)) + break; + } +#endif + + if (waitResult != WAIT_OBJECT_0) { + success = 0; /* We failed */ + } + + dprintf(("%ld: PyThread_acquire_lock(%p, %d) -> %d\n", PyThread_get_thread_ident(),aLock, waitflag, success)); + + return success; +} + +void PyThread_release_lock(PyThread_type_lock aLock) +{ + dprintf(("%ld: PyThread_release_lock(%p) called\n", PyThread_get_thread_ident(),aLock)); + + if (!SetEvent(aLock)) + dprintf(("%ld: Could not PyThread_release_lock(%p) error: %l\n", PyThread_get_thread_ident(), aLock, GetLastError())); +} + + diff --git a/sys/src/cmd/python/Python/traceback.c b/sys/src/cmd/python/Python/traceback.c new file mode 100644 index 000000000..4ddee2c73 --- /dev/null +++ b/sys/src/cmd/python/Python/traceback.c @@ -0,0 +1,262 @@ + +/* Traceback implementation */ + +#include "Python.h" + +#include "code.h" +#include "frameobject.h" +#include "structmember.h" +#include "osdefs.h" +#include "traceback.h" + +#define OFF(x) offsetof(PyTracebackObject, x) + +static struct memberlist tb_memberlist[] = { + {"tb_next", T_OBJECT, OFF(tb_next)}, + {"tb_frame", T_OBJECT, OFF(tb_frame)}, + {"tb_lasti", T_INT, OFF(tb_lasti)}, + {"tb_lineno", T_INT, OFF(tb_lineno)}, + {NULL} /* Sentinel */ +}; + +static PyObject * +tb_getattr(PyTracebackObject *tb, char *name) +{ + return PyMember_Get((char *)tb, tb_memberlist, name); +} + +static void +tb_dealloc(PyTracebackObject *tb) +{ + PyObject_GC_UnTrack(tb); + Py_TRASHCAN_SAFE_BEGIN(tb) + Py_XDECREF(tb->tb_next); + Py_XDECREF(tb->tb_frame); + PyObject_GC_Del(tb); + Py_TRASHCAN_SAFE_END(tb) +} + +static int +tb_traverse(PyTracebackObject *tb, visitproc visit, void *arg) +{ + Py_VISIT(tb->tb_next); + Py_VISIT(tb->tb_frame); + return 0; +} + +static void +tb_clear(PyTracebackObject *tb) +{ + Py_CLEAR(tb->tb_next); + Py_CLEAR(tb->tb_frame); +} + +PyTypeObject PyTraceBack_Type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "traceback", + sizeof(PyTracebackObject), + 0, + (destructor)tb_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)tb_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)tb_traverse, /* tp_traverse */ + (inquiry)tb_clear, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ +}; + +static PyTracebackObject * +newtracebackobject(PyTracebackObject *next, PyFrameObject *frame) +{ + PyTracebackObject *tb; + if ((next != NULL && !PyTraceBack_Check(next)) || + frame == NULL || !PyFrame_Check(frame)) { + PyErr_BadInternalCall(); + return NULL; + } + tb = PyObject_GC_New(PyTracebackObject, &PyTraceBack_Type); + if (tb != NULL) { + Py_XINCREF(next); + tb->tb_next = next; + Py_XINCREF(frame); + tb->tb_frame = frame; + tb->tb_lasti = frame->f_lasti; + tb->tb_lineno = PyCode_Addr2Line(frame->f_code, + frame->f_lasti); + PyObject_GC_Track(tb); + } + return tb; +} + +int +PyTraceBack_Here(PyFrameObject *frame) +{ + PyThreadState *tstate = PyThreadState_GET(); + PyTracebackObject *oldtb = (PyTracebackObject *) tstate->curexc_traceback; + PyTracebackObject *tb = newtracebackobject(oldtb, frame); + if (tb == NULL) + return -1; + tstate->curexc_traceback = (PyObject *)tb; + Py_XDECREF(oldtb); + return 0; +} + +static int +tb_displayline(PyObject *f, char *filename, int lineno, char *name) +{ + int err = 0; + FILE *xfp; + char linebuf[2000]; + int i; + if (filename == NULL || name == NULL) + return -1; + /* This is needed by Emacs' compile command */ +#define FMT " File \"%.500s\", line %d, in %.500s\n" + xfp = fopen(filename, "r" PY_STDIOTEXTMODE); + if (xfp == NULL) { + /* Search tail of filename in sys.path before giving up */ + PyObject *path; + char *tail = strrchr(filename, SEP); + if (tail == NULL) + tail = filename; + else + tail++; + path = PySys_GetObject("path"); + if (path != NULL && PyList_Check(path)) { + Py_ssize_t _npath = PyList_Size(path); + int npath = Py_SAFE_DOWNCAST(_npath, Py_ssize_t, int); + size_t taillen = strlen(tail); + char namebuf[MAXPATHLEN+1]; + for (i = 0; i < npath; i++) { + PyObject *v = PyList_GetItem(path, i); + if (v == NULL) { + PyErr_Clear(); + break; + } + if (PyString_Check(v)) { + size_t len; + len = PyString_GET_SIZE(v); + if (len + 1 + taillen >= MAXPATHLEN) + continue; /* Too long */ + strcpy(namebuf, PyString_AsString(v)); + if (strlen(namebuf) != len) + continue; /* v contains '\0' */ + if (len > 0 && namebuf[len-1] != SEP) + namebuf[len++] = SEP; + strcpy(namebuf+len, tail); + xfp = fopen(namebuf, "r" PY_STDIOTEXTMODE); + if (xfp != NULL) { + filename = namebuf; + break; + } + } + } + } + } + PyOS_snprintf(linebuf, sizeof(linebuf), FMT, filename, lineno, name); + err = PyFile_WriteString(linebuf, f); + if (xfp == NULL) + return err; + else if (err != 0) { + fclose(xfp); + return err; + } + for (i = 0; i < lineno; i++) { + char* pLastChar = &linebuf[sizeof(linebuf)-2]; + do { + *pLastChar = '\0'; + if (Py_UniversalNewlineFgets(linebuf, sizeof linebuf, xfp, NULL) == NULL) + break; + /* fgets read *something*; if it didn't get as + far as pLastChar, it must have found a newline + or hit the end of the file; if pLastChar is \n, + it obviously found a newline; else we haven't + yet seen a newline, so must continue */ + } while (*pLastChar != '\0' && *pLastChar != '\n'); + } + if (i == lineno) { + char *p = linebuf; + while (*p == ' ' || *p == '\t' || *p == '\014') + p++; + err = PyFile_WriteString(" ", f); + if (err == 0) { + err = PyFile_WriteString(p, f); + if (err == 0 && strchr(p, '\n') == NULL) + err = PyFile_WriteString("\n", f); + } + } + fclose(xfp); + return err; +} + +static int +tb_printinternal(PyTracebackObject *tb, PyObject *f, int limit) +{ + int err = 0; + int depth = 0; + PyTracebackObject *tb1 = tb; + while (tb1 != NULL) { + depth++; + tb1 = tb1->tb_next; + } + while (tb != NULL && err == 0) { + if (depth <= limit) { + err = tb_displayline(f, + PyString_AsString( + tb->tb_frame->f_code->co_filename), + tb->tb_lineno, + PyString_AsString(tb->tb_frame->f_code->co_name)); + } + depth--; + tb = tb->tb_next; + if (err == 0) + err = PyErr_CheckSignals(); + } + return err; +} + +int +PyTraceBack_Print(PyObject *v, PyObject *f) +{ + int err; + PyObject *limitv; + int limit = 1000; + if (v == NULL) + return 0; + if (!PyTraceBack_Check(v)) { + PyErr_BadInternalCall(); + return -1; + } + limitv = PySys_GetObject("tracebacklimit"); + if (limitv && PyInt_Check(limitv)) { + limit = PyInt_AsLong(limitv); + if (limit <= 0) + return 0; + } + err = PyFile_WriteString("Traceback (most recent call last):\n", f); + if (!err) + err = tb_printinternal((PyTracebackObject *)v, f, limit); + return err; +} diff --git a/sys/src/cmd/python/README b/sys/src/cmd/python/README new file mode 100644 index 000000000..de09bb1b6 --- /dev/null +++ b/sys/src/cmd/python/README @@ -0,0 +1,1297 @@ +This is Python version 2.5.1 +============================ + +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software +Foundation. +All rights reserved. + +Copyright (c) 2000 BeOpen.com. +All rights reserved. + +Copyright (c) 1995-2001 Corporation for National Research Initiatives. +All rights reserved. + +Copyright (c) 1991-1995 Stichting Mathematisch Centrum. +All rights reserved. + + +License information +------------------- + +See the file "LICENSE" for information on the history of this +software, terms & conditions for usage, and a DISCLAIMER OF ALL +WARRANTIES. + +This Python distribution contains no GNU General Public Licensed +(GPLed) code so it may be used in proprietary projects just like prior +Python distributions. There are interfaces to some GNU code but these +are entirely optional. + +All trademarks referenced herein are property of their respective +holders. + + +What's new in this release? +--------------------------- + +See the file "Misc/NEWS". + + +If you don't read instructions +------------------------------ + +Congratulations on getting this far. :-) + +To start building right away (on UNIX): type "./configure" in the +current directory and when it finishes, type "make". This creates an +executable "./python"; to install in /usr/local, first do "su root" +and then "make install". + +The section `Build instructions' below is still recommended reading. + + +What is Python anyway? +---------------------- + +Python is an interpreted, interactive object-oriented programming +language suitable (amongst other uses) for distributed application +development, scripting, numeric computing and system testing. Python +is often compared to Tcl, Perl, Java, JavaScript, Visual Basic or +Scheme. To find out more about what Python can do for you, point your +browser to http://www.python.org/. + + +How do I learn Python? +---------------------- + +The official tutorial is still a good place to start; see +http://docs.python.org/ for online and downloadable versions, as well +as a list of other introductions, and reference documentation. + +There's a quickly growing set of books on Python. See +http://wiki.python.org/moin/PythonBooks for a list. + + +Documentation +------------- + +All documentation is provided online in a variety of formats. In +order of importance for new users: Tutorial, Library Reference, +Language Reference, Extending & Embedding, and the Python/C API. The +Library Reference is especially of immense value since much of +Python's power is described there, including the built-in data types +and functions! + +All documentation is also available online at the Python web site +(http://docs.python.org/, see below). It is available online for +occasional reference, or can be downloaded in many formats for faster +access. The documentation is available in HTML, PostScript, PDF, and +LaTeX formats; the LaTeX version is primarily for documentation +authors, translators, and people with special formatting requirements. + +Unfortunately, new-style classes (new in Python 2.2) have not yet been +integrated into Python's standard documentation. A collection of +pointers to what has been written is at: + + http://www.python.org/doc/newstyle.html + + +Web sites +--------- + +New Python releases and related technologies are published at +http://www.python.org/. Come visit us! + +There's also a Python community web site at +http://starship.python.net/. + + +Newsgroups and Mailing Lists +---------------------------- + +Read comp.lang.python, a high-volume discussion newsgroup about +Python, or comp.lang.python.announce, a low-volume moderated newsgroup +for Python-related announcements. These are also accessible as +mailing lists: see http://www.python.org/community/lists.html for an +overview of these and many other Python-related mailing lists. + +Archives are accessible via the Google Groups Usenet archive; see +http://groups.google.com/. The mailing lists are also archived, see +http://www.python.org/community/lists.html for details. + + +Bug reports +----------- + +To report or search for bugs, please use the Python Bug +Tracker at http://sourceforge.net/bugs/?group_id=5470. + + +Patches and contributions +------------------------- + +To submit a patch or other contribution, please use the Python Patch +Manager at http://sourceforge.net/patch/?group_id=5470. Guidelines +for patch submission may be found at http://www.python.org/patches/. + +If you have a proposal to change Python, it's best to submit a Python +Enhancement Proposal (PEP) first. All current PEPs, as well as +guidelines for submitting a new PEP, are listed at +http://www.python.org/peps/. + + +Questions +--------- + +For help, if you can't find it in the manuals or on the web site, it's +best to post to the comp.lang.python or the Python mailing list (see +above). If you specifically don't want to involve the newsgroup or +mailing list, send questions to help@python.org (a group of volunteers +who answer questions as they can). The newsgroup is the most +efficient way to ask public questions. + + +Build instructions +================== + +Before you can build Python, you must first configure it. +Fortunately, the configuration and build process has been automated +for Unix and Linux installations, so all you usually have to do is +type a few commands and sit back. There are some platforms where +things are not quite as smooth; see the platform specific notes below. +If you want to build for multiple platforms sharing the same source +tree, see the section on VPATH below. + +Start by running the script "./configure", which determines your +system configuration and creates the Makefile. (It takes a minute or +two -- please be patient!) You may want to pass options to the +configure script -- see the section below on configuration options and +variables. When it's done, you are ready to run make. + +To build Python, you normally type "make" in the toplevel directory. +If you have changed the configuration, the Makefile may have to be +rebuilt. In this case you may have to run make again to correctly +build your desired target. The interpreter executable is built in the +top level directory. + +Once you have built a Python interpreter, see the subsections below on +testing and installation. If you run into trouble, see the next +section. + +Previous versions of Python used a manual configuration process that +involved editing the file Modules/Setup. While this file still exists +and manual configuration is still supported, it is rarely needed any +more: almost all modules are automatically built as appropriate under +guidance of the setup.py script, which is run by Make after the +interpreter has been built. + + +Troubleshooting +--------------- + +See also the platform specific notes in the next section. + +If you run into other trouble, see the FAQ +(http://www.python.org/doc/faq) for hints on what can go wrong, and +how to fix it. + +If you rerun the configure script with different options, remove all +object files by running "make clean" before rebuilding. Believe it or +not, "make clean" sometimes helps to clean up other inexplicable +problems as well. Try it before sending in a bug report! + +If the configure script fails or doesn't seem to find things that +should be there, inspect the config.log file. + +If you get a warning for every file about the -Olimit option being no +longer supported, you can ignore it. There's no foolproof way to know +whether this option is needed; all we can do is test whether it is +accepted without error. On some systems, e.g. older SGI compilers, it +is essential for performance (specifically when compiling ceval.c, +which has more basic blocks than the default limit of 1000). If the +warning bothers you, edit the Makefile to remove "-Olimit 1500" from +the OPT variable. + +If you get failures in test_long, or sys.maxint gets set to -1, you +are probably experiencing compiler bugs, usually related to +optimization. This is a common problem with some versions of gcc, and +some vendor-supplied compilers, which can sometimes be worked around +by turning off optimization. Consider switching to stable versions +(gcc 2.95.2, gcc 3.x, or contact your vendor.) + +From Python 2.0 onward, all Python C code is ANSI C. Compiling using +old K&R-C-only compilers is no longer possible. ANSI C compilers are +available for all modern systems, either in the form of updated +compilers from the vendor, or one of the free compilers (gcc). + +If "make install" fails mysteriously during the "compiling the library" +step, make sure that you don't have any of the PYTHONPATH or PYTHONHOME +environment variables set, as they may interfere with the newly built +executable which is compiling the library. + +Unsupported systems +------------------- + +A number of features are not supported in Python 2.5 anymore. Some +support code is still present, but will be removed in Python 2.6. +If you still need to use current Python versions on these systems, +please send a message to python-dev@python.org indicating that you +volunteer to support this system. For a more detailed discussion +regarding no-longer-supported and resupporting platforms, as well +as a list of platforms that became or will be unsupported, see PEP 11. + +More specifically, the following systems are not supported any +longer: +- SunOS 4 +- DYNIX +- dgux +- Minix +- NeXT +- Irix 4 and --with-sgi-dl +- Linux 1 +- Systems defining __d6_pthread_create (configure.in) +- Systems defining PY_PTHREAD_D4, PY_PTHREAD_D6, + or PY_PTHREAD_D7 in thread_pthread.h +- Systems using --with-dl-dld +- Systems using --without-universal-newlines +- MacOS 9 + +The following systems are still supported in Python 2.5, but +support will be dropped in 2.6: +- Systems using --with-wctype-functions +- Win9x, WinME + +Warning on install in Windows 98 and Windows Me +----------------------------------------------- + +Following Microsoft's closing of Extended Support for +Windows 98/ME (July 11, 2006), Python 2.6 will stop +supporting these platforms. Python development and +maintainability becomes easier (and more reliable) when +platform specific code targeting OSes with few users +and no dedicated expert developers is taken out. The +vendor also warns that the OS versions listed above +"can expose customers to security risks" and recommends +upgrade. + +Platform specific notes +----------------------- + +(Some of these may no longer apply. If you find you can build Python +on these platforms without the special directions mentioned here, +submit a documentation bug report to SourceForge (see Bug Reports +above) so we can remove them!) + +GCC 4.1, +GCC 4.2: There is a known incompatibility between Python and GCC, + where GCC 4.1 and later uses an interpretation of C + different to earlier GCC releases in an area where the C + specification has undefined behaviour (namely, integer arithmetic + involving -sys.maxint-1). + + As a consequence, compiling Python with GCC 4.1/4.2 is not + recommended. It is likely that this problem will be resolved + in future Python releases. As a work-around, it seems that + adding -fwrapv to the compiler options restores the earlier + GCC behaviour. + +Unix platforms: If your vendor still ships (and you still use) Berkeley DB + 1.85 you will need to edit Modules/Setup to build the bsddb185 + module and add a line to sitecustomize.py which makes it the + default. In Modules/Setup a line like + + bsddb185 bsddbmodule.c + + should work. (You may need to add -I, -L or -l flags to direct the + compiler and linker to your include files and libraries.) + +XXX I think this next bit is out of date: + +64-bit platforms: The modules audioop, imageop and rgbimg don't work. + The setup.py script disables them on 64-bit installations. + Don't try to enable them in the Modules/Setup file. They + contain code that is quite wordsize sensitive. (If you have a + fix, let us know!) + +Solaris: When using Sun's C compiler with threads, at least on Solaris + 2.5.1, you need to add the "-mt" compiler option (the simplest + way is probably to specify the compiler with this option as + the "CC" environment variable when running the configure + script). + + When using GCC on Solaris, beware of binutils 2.13 or GCC + versions built using it. This mistakenly enables the + -zcombreloc option which creates broken shared libraries on + Solaris. binutils 2.12 works, and the binutils maintainers + are aware of the problem. Binutils 2.13.1 only partially + fixed things. It appears that 2.13.2 solves the problem + completely. This problem is known to occur with Solaris 2.7 + and 2.8, but may also affect earlier and later versions of the + OS. + + When the dynamic loader complains about errors finding shared + libraries, such as + + ld.so.1: ./python: fatal: libstdc++.so.5: open failed: + No such file or directory + + you need to first make sure that the library is available on + your system. Then, you need to instruct the dynamic loader how + to find it. You can choose any of the following strategies: + + 1. When compiling Python, set LD_RUN_PATH to the directories + containing missing libraries. + 2. When running Python, set LD_LIBRARY_PATH to these directories. + 3. Use crle(8) to extend the search path of the loader. + 4. Modify the installed GCC specs file, adding -R options into the + *link: section. + + The complex object fails to compile on Solaris 10 with gcc 3.4 (at + least up to 3.4.3). To work around it, define Py_HUGE_VAL as + HUGE_VAL(), e.g.: + + make CPPFLAGS='-D"Py_HUGE_VAL=HUGE_VAL()" -I. -I$(srcdir)/Include' + ./python setup.py CPPFLAGS='-D"Py_HUGE_VAL=HUGE_VAL()"' + +Linux: A problem with threads and fork() was tracked down to a bug in + the pthreads code in glibc version 2.0.5; glibc version 2.0.7 + solves the problem. This causes the popen2 test to fail; + problem and solution reported by Pablo Bleyer. + +Red Hat Linux: Red Hat 9 built Python2.2 in UCS-4 mode and hacked + Tcl to support it. To compile Python2.3 with Tkinter, you will + need to pass --enable-unicode=ucs4 flag to ./configure. + + There's an executable /usr/bin/python which is Python + 1.5.2 on most older Red Hat installations; several key Red Hat tools + require this version. Python 2.1.x may be installed as + /usr/bin/python2. The Makefile installs Python as + /usr/local/bin/python, which may or may not take precedence + over /usr/bin/python, depending on how you have set up $PATH. + +FreeBSD 3.x and probably platforms with NCurses that use libmytinfo or + similar: When using cursesmodule, the linking is not done in + the correct order with the defaults. Remove "-ltermcap" from + the readline entry in Setup, and use as curses entry: "curses + cursesmodule.c -lmytinfo -lncurses -ltermcap" - "mytinfo" (so + called on FreeBSD) should be the name of the auxiliary library + required on your platform. Normally, it would be linked + automatically, but not necessarily in the correct order. + +BSDI: BSDI versions before 4.1 have known problems with threads, + which can cause strange errors in a number of modules (for + instance, the 'test_signal' test script will hang forever.) + Turning off threads (with --with-threads=no) or upgrading to + BSDI 4.1 solves this problem. + +DEC Unix: Run configure with --with-dec-threads, or with + --with-threads=no if no threads are desired (threads are on by + default). When using GCC, it is possible to get an internal + compiler error if optimization is used. This was reported for + GCC 2.7.2.3 on selectmodule.c. Manually compile the affected + file without optimization to solve the problem. + +DEC Ultrix: compile with GCC to avoid bugs in the native compiler, + and pass SHELL=/bin/sh5 to Make when installing. + +AIX: A complete overhaul of the shared library support is now in + place. See Misc/AIX-NOTES for some notes on how it's done. + (The optimizer bug reported at this place in previous releases + has been worked around by a minimal code change.) If you get + errors about pthread_* functions, during compile or during + testing, try setting CC to a thread-safe (reentrant) compiler, + like "cc_r". For full C++ module support, set CC="xlC_r" (or + CC="xlC" without thread support). + +AIX 5.3: To build a 64-bit version with IBM's compiler, I used the + following: + + export PATH=/usr/bin:/usr/vacpp/bin + ./configure --with-gcc="xlc_r -q64" --with-cxx="xlC_r -q64" \ + --disable-ipv6 AR="ar -X64" + make + +HP-UX: When using threading, you may have to add -D_REENTRANT to the + OPT variable in the top-level Makefile; reported by Pat Knight, + this seems to make a difference (at least for HP-UX 10.20) + even though pyconfig.h defines it. This seems unnecessary when + using HP/UX 11 and later - threading seems to work "out of the + box". + +HP-UX ia64: When building on the ia64 (Itanium) platform using HP's + compiler, some experience has shown that the compiler's + optimiser produces a completely broken version of python + (see http://www.python.org/sf/814976). To work around this, + edit the Makefile and remove -O from the OPT line. + + To build a 64-bit executable on an Itanium 2 system using HP's + compiler, use these environment variables: + + CC=cc + CXX=aCC + BASECFLAGS="+DD64" + LDFLAGS="+DD64 -lxnet" + + and call configure as: + + ./configure --without-gcc + + then *unset* the environment variables again before running + make. (At least one of these flags causes the build to fail + if it remains set.) You still have to edit the Makefile and + remove -O from the OPT line. + +HP PA-RISC 2.0: A recent bug report (http://www.python.org/sf/546117) + suggests that the C compiler in this 64-bit system has bugs + in the optimizer that break Python. Compiling without + optimization solves the problems. + +SCO: The following apply to SCO 3 only; Python builds out of the box + on SCO 5 (or so we've heard). + + 1) Everything works much better if you add -U__STDC__ to the + defs. This is because all the SCO header files are broken. + Anything that isn't mentioned in the C standard is + conditionally excluded when __STDC__ is defined. + + 2) Due to the U.S. export restrictions, SCO broke the crypt + stuff out into a separate library, libcrypt_i.a so the LIBS + needed be set to: + + LIBS=' -lsocket -lcrypt_i' + +UnixWare: There are known bugs in the math library of the system, as well as + problems in the handling of threads (calling fork in one + thread may interrupt system calls in others). Therefore, test_math and + tests involving threads will fail until those problems are fixed. + +QNX: Chris Herborth (chrish@qnx.com) writes: + configure works best if you use GNU bash; a port is available on + ftp.qnx.com in /usr/free. I used the following process to build, + test and install Python 1.5.x under QNX: + + 1) CONFIG_SHELL=/usr/local/bin/bash CC=cc RANLIB=: \ + ./configure --verbose --without-gcc --with-libm="" + + 2) edit Modules/Setup to activate everything that makes sense for + your system... tested here at QNX with the following modules: + + array, audioop, binascii, cPickle, cStringIO, cmath, + crypt, curses, errno, fcntl, gdbm, grp, imageop, + _locale, math, md5, new, operator, parser, pcre, + posix, pwd, readline, regex, reop, rgbimg, rotor, + select, signal, socket, soundex, strop, struct, + syslog, termios, time, timing, zlib, audioop, imageop, rgbimg + + 3) make SHELL=/usr/local/bin/bash + + or, if you feel the need for speed: + + make SHELL=/usr/local/bin/bash OPT="-5 -Oil+nrt" + + 4) make SHELL=/usr/local/bin/bash test + + Using GNU readline 2.2 seems to behave strangely, but I + think that's a problem with my readline 2.2 port. :-\ + + 5) make SHELL=/usr/local/bin/bash install + + If you get SIGSEGVs while running Python (I haven't yet, but + I've only run small programs and the test cases), you're + probably running out of stack; the default 32k could be a + little tight. To increase the stack size, edit the Makefile + to read: LDFLAGS = -N 48k + +BeOS: See Misc/BeOS-NOTES for notes about compiling/installing + Python on BeOS R3 or later. Note that only the PowerPC + platform is supported for R3; both PowerPC and x86 are + supported for R4. + +Cray T3E: Mark Hadfield (m.hadfield@niwa.co.nz) writes: + Python can be built satisfactorily on a Cray T3E but based on + my experience with the NIWA T3E (2002-05-22, version 2.2.1) + there are a few bugs and gotchas. For more information see a + thread on comp.lang.python in May 2002 entitled "Building + Python on Cray T3E". + + 1) Use Cray's cc and not gcc. The latter was reported not to + work by Konrad Hinsen. It may work now, but it may not. + + 2) To set sys.platform to something sensible, pass the + following environment variable to the configure script: + + MACHDEP=unicosmk + + 2) Run configure with option "--enable-unicode=ucs4". + + 3) The Cray T3E does not support dynamic linking, so extension + modules have to be built by adding (or uncommenting) lines + in Modules/Setup. The minimum set of modules is + + posix, new, _sre, unicodedata + + On NIWA's vanilla T3E system the following have also been + included successfully: + + _codecs, _locale, _socket, _symtable, _testcapi, _weakref + array, binascii, cmath, cPickle, crypt, cStringIO, dbm + errno, fcntl, grp, math, md5, operator, parser, pcre, pwd + regex, rotor, select, struct, strop, syslog, termios + time, timing, xreadlines + + 4) Once the python executable and library have been built, make + will execute setup.py, which will attempt to build remaining + extensions and link them dynamically. Each of these attempts + will fail but should not halt the make process. This is + normal. + + 5) Running "make test" uses a lot of resources and causes + problems on our system. You might want to try running tests + singly or in small groups. + +SGI: SGI's standard "make" utility (/bin/make or /usr/bin/make) + does not check whether a command actually changed the file it + is supposed to build. This means that whenever you say "make" + it will redo the link step. The remedy is to use SGI's much + smarter "smake" utility (/usr/sbin/smake), or GNU make. If + you set the first line of the Makefile to #!/usr/sbin/smake + smake will be invoked by make (likewise for GNU make). + + WARNING: There are bugs in the optimizer of some versions of + SGI's compilers that can cause bus errors or other strange + behavior, especially on numerical operations. To avoid this, + try building with "make OPT=". + +OS/2: If you are running Warp3 or Warp4 and have IBM's VisualAge C/C++ + compiler installed, just change into the pc\os2vacpp directory + and type NMAKE. Threading and sockets are supported by default + in the resulting binaries of PYTHON15.DLL and PYTHON.EXE. + +Monterey (64-bit AIX): The current Monterey C compiler (Visual Age) + uses the OBJECT_MODE={32|64} environment variable to set the + compilation mode to either 32-bit or 64-bit (32-bit mode is + the default). Presumably you want 64-bit compilation mode for + this 64-bit OS. As a result you must first set OBJECT_MODE=64 + in your environment before configuring (./configure) or + building (make) Python on Monterey. + +Reliant UNIX: The thread support does not compile on Reliant UNIX, and + there is a (minor) problem in the configure script for that + platform as well. This should be resolved in time for a + future release. + +MacOSX: The tests will crash on both 10.1 and 10.2 with SEGV in + test_re and test_sre due to the small default stack size. If + you set the stack size to 2048 before doing a "make test" the + failure can be avoided. If you're using the tcsh or csh shells, + use "limit stacksize 2048" and for the bash shell (the default + as of OSX 10.3), use "ulimit -s 2048". + + On naked Darwin you may want to add the configure option + "--disable-toolbox-glue" to disable the glue code for the Carbon + interface modules. The modules themselves are currently only built + if you add the --enable-framework option, see below. + + On a clean OSX /usr/local does not exist. Do a + "sudo mkdir -m 775 /usr/local" + before you do a make install. It is probably not a good idea to + do "sudo make install" which installs everything as superuser, + as this may later cause problems when installing distutils-based + additions. + + Some people have reported problems building Python after using "fink" + to install additional unix software. Disabling fink (remove all + references to /sw from your .profile or .login) should solve this. + + You may want to try the configure option "--enable-framework" + which installs Python as a framework. The location can be set + as argument to the --enable-framework option (default + /Library/Frameworks). A framework install is probably needed if you + want to use any Aqua-based GUI toolkit (whether Tkinter, wxPython, + Carbon, Cocoa or anything else). + + You may also want to try the configure option "--enable-universalsdk" + which builds Python as a universal binary with support for the + i386 and PPC architectures. This requires Xcode 2.1 or later to build. + + See Mac/OSX/README for more information on framework and + universal builds. + +Cygwin: With recent (relative to the time of writing, 2001-12-19) + Cygwin installations, there are problems with the interaction + of dynamic linking and fork(). This manifests itself in build + failures during the execution of setup.py. + + There are two workarounds that both enable Python (albeit + without threading support) to build and pass all tests on + NT/2000 (and most likely XP as well, though reports of testing + on XP would be appreciated). + + The workarounds: + + (a) the band-aid fix is to link the _socket module statically + rather than dynamically (which is the default). + + To do this, run "./configure --with-threads=no" including any + other options you need (--prefix, etc.). Then in Modules/Setup + uncomment the lines: + + #SSL=/usr/local/ssl + #_socket socketmodule.c \ + # -DUSE_SSL -I$(SSL)/include -I$(SSL)/include/openssl \ + # -L$(SSL)/lib -lssl -lcrypto + + and remove "local/" from the SSL variable. Finally, just run + "make"! + + (b) The "proper" fix is to rebase the Cygwin DLLs to prevent + base address conflicts. Details on how to do this can be + found in the following mail: + + http://sources.redhat.com/ml/cygwin/2001-12/msg00894.html + + It is hoped that a version of this solution will be + incorporated into the Cygwin distribution fairly soon. + + Two additional problems: + + (1) Threading support should still be disabled due to a known + bug in Cygwin pthreads that causes test_threadedtempfile to + hang. + + (2) The _curses module does not build. This is a known + Cygwin ncurses problem that should be resolved the next time + that this package is released. + + On older versions of Cygwin, test_poll may hang and test_strftime + may fail. + + The situation on 9X/Me is not accurately known at present. + Some time ago, there were reports that the following + regression tests failed: + + test_pwd + test_select (hang) + test_socket + + Due to the test_select hang on 9X/Me, one should run the + regression test using the following: + + make TESTOPTS='-l -x test_select' test + + News regarding these platforms with more recent Cygwin + versions would be appreciated! + +AtheOS: From Octavian Cerna <tavy at ylabs.com>: + + Before building: + + Make sure you have shared versions of the libraries you + want to use with Python. You will have to compile them + yourself, or download precompiled packages. + + Recommended libraries: + + ncurses-4.2 + readline-4.2a + zlib-1.1.4 + + Build: + + $ ./configure --prefix=/usr/python + $ make + + Python is always built as a shared library, otherwise + dynamic loading would not work. + + Testing: + + $ make test + + Install: + + # make install + # pkgmanager -a /usr/python + + + AtheOS issues: + + - large file support: due to a stdio bug in glibc/libio, + access to large files may not work correctly. fseeko() + tries to seek to a negative offset. ftello() returns a + negative offset, it looks like a 32->64bit + sign-extension issue. The lowlevel functions (open, + lseek, etc) are OK. + - sockets: AF_UNIX is defined in the C library and in + Python, but not implemented in the system. + - select: poll is available in the C library, but does not + work (It does not return POLLNVAL for bad fds and + hangs). + - posix: statvfs and fstatvfs always return ENOSYS. + - disabled modules: + - mmap: not yet implemented in AtheOS + - nis: broken (on an unconfigured system + yp_get_default_domain() returns junk instead of + error) + - dl: dynamic loading doesn't work via dlopen() + - resource: getrimit and setrlimit are not yet + implemented + + - if you are getting segmentation faults, you probably are + low on memory. AtheOS doesn't handle very well an + out-of-memory condition and simply SEGVs the process. + + Tested on: + + AtheOS-0.3.7 + gcc-2.95 + binutils-2.10 + make-3.78 + + +Configuring the bsddb and dbm modules +------------------------------------- + +Beginning with Python version 2.3, the PyBsddb package +<http://pybsddb.sf.net/> was adopted into Python as the bsddb package, +exposing a set of package-level functions which provide +backwards-compatible behavior. Only versions 3.3 through 4.4 of +Sleepycat's libraries provide the necessary API, so older versions +aren't supported through this interface. The old bsddb module has +been retained as bsddb185, though it is not built by default. Users +wishing to use it will have to tweak Modules/Setup to build it. The +dbm module will still be built against the Sleepycat libraries if +other preferred alternatives (ndbm, gdbm) are not found. + +Building the sqlite3 module +--------------------------- + +To build the sqlite3 module, you'll need the sqlite3 or libsqlite3 +packages installed, including the header files. Many modern operating +systems distribute the headers in a separate package to the library - +often it will be the same name as the main package, but with a -dev or +-devel suffix. + +The version of pysqlite2 that's including in Python needs sqlite3 3.0.8 +or later. setup.py attempts to check that it can find a correct version. + +Configuring threads +------------------- + +As of Python 2.0, threads are enabled by default. If you wish to +compile without threads, or if your thread support is broken, pass the +--with-threads=no switch to configure. Unfortunately, on some +platforms, additional compiler and/or linker options are required for +threads to work properly. Below is a table of those options, +collected by Bill Janssen. We would love to automate this process +more, but the information below is not enough to write a patch for the +configure.in file, so manual intervention is required. If you patch +the configure.in file and are confident that the patch works, please +send in the patch. (Don't bother patching the configure script itself +-- it is regenerated each time the configure.in file changes.) + +Compiler switches for threads +............................. + +The definition of _REENTRANT should be configured automatically, if +that does not work on your system, or if _REENTRANT is defined +incorrectly, please report that as a bug. + + OS/Compiler/threads Switches for use with threads + (POSIX is draft 10, DCE is draft 4) compile & link + + SunOS 5.{1-5}/{gcc,SunPro cc}/solaris -mt + SunOS 5.5/{gcc,SunPro cc}/POSIX (nothing) + DEC OSF/1 3.x/cc/DCE -threads + (butenhof@zko.dec.com) + Digital UNIX 4.x/cc/DCE -threads + (butenhof@zko.dec.com) + Digital UNIX 4.x/cc/POSIX -pthread + (butenhof@zko.dec.com) + AIX 4.1.4/cc_r/d7 (nothing) + (buhrt@iquest.net) + AIX 4.1.4/cc_r4/DCE (nothing) + (buhrt@iquest.net) + IRIX 6.2/cc/POSIX (nothing) + (robertl@cwi.nl) + + +Linker (ld) libraries and flags for threads +........................................... + + OS/threads Libraries/switches for use with threads + + SunOS 5.{1-5}/solaris -lthread + SunOS 5.5/POSIX -lpthread + DEC OSF/1 3.x/DCE -lpthreads -lmach -lc_r -lc + (butenhof@zko.dec.com) + Digital UNIX 4.x/DCE -lpthreads -lpthread -lmach -lexc -lc + (butenhof@zko.dec.com) + Digital UNIX 4.x/POSIX -lpthread -lmach -lexc -lc + (butenhof@zko.dec.com) + AIX 4.1.4/{draft7,DCE} (nothing) + (buhrt@iquest.net) + IRIX 6.2/POSIX -lpthread + (jph@emilia.engr.sgi.com) + + +Building a shared libpython +--------------------------- + +Starting with Python 2.3, the majority of the interpreter can be built +into a shared library, which can then be used by the interpreter +executable, and by applications embedding Python. To enable this feature, +configure with --enable-shared. + +If you enable this feature, the same object files will be used to create +a static library. In particular, the static library will contain object +files using position-independent code (PIC) on platforms where PIC flags +are needed for the shared library. + + +Configuring additional built-in modules +--------------------------------------- + +Starting with Python 2.1, the setup.py script at the top of the source +distribution attempts to detect which modules can be built and +automatically compiles them. Autodetection doesn't always work, so +you can still customize the configuration by editing the Modules/Setup +file; but this should be considered a last resort. The rest of this +section only applies if you decide to edit the Modules/Setup file. +You also need this to enable static linking of certain modules (which +is needed to enable profiling on some systems). + +This file is initially copied from Setup.dist by the configure script; +if it does not exist yet, create it by copying Modules/Setup.dist +yourself (configure will never overwrite it). Never edit Setup.dist +-- always edit Setup or Setup.local (see below). Read the comments in +the file for information on what kind of edits are allowed. When you +have edited Setup in the Modules directory, the interpreter will +automatically be rebuilt the next time you run make (in the toplevel +directory). + +Many useful modules can be built on any Unix system, but some optional +modules can't be reliably autodetected. Often the quickest way to +determine whether a particular module works or not is to see if it +will build: enable it in Setup, then if you get compilation or link +errors, disable it -- you're either missing support or need to adjust +the compilation and linking parameters for that module. + +On SGI IRIX, there are modules that interface to many SGI specific +system libraries, e.g. the GL library and the audio hardware. These +modules will not be built by the setup.py script. + +In addition to the file Setup, you can also edit the file Setup.local. +(the makesetup script processes both). You may find it more +convenient to edit Setup.local and leave Setup alone. Then, when +installing a new Python version, you can copy your old Setup.local +file. + + +Setting the optimization/debugging options +------------------------------------------ + +If you want or need to change the optimization/debugging options for +the C compiler, assign to the OPT variable on the toplevel make +command; e.g. "make OPT=-g" will build a debugging version of Python +on most platforms. The default is OPT=-O; a value for OPT in the +environment when the configure script is run overrides this default +(likewise for CC; and the initial value for LIBS is used as the base +set of libraries to link with). + +When compiling with GCC, the default value of OPT will also include +the -Wall and -Wstrict-prototypes options. + +Additional debugging code to help debug memory management problems can +be enabled by using the --with-pydebug option to the configure script. + +For flags that change binary compatibility, use the EXTRA_CFLAGS +variable. + + +Profiling +--------- + +If you want C profiling turned on, the easiest way is to run configure +with the CC environment variable to the necessary compiler +invocation. For example, on Linux, this works for profiling using +gprof(1): + + CC="gcc -pg" ./configure + +Note that on Linux, gprof apparently does not work for shared +libraries. The Makefile/Setup mechanism can be used to compile and +link most extension modules statically. + + +Testing +------- + +To test the interpreter, type "make test" in the top-level directory. +This runs the test set twice (once with no compiled files, once with +the compiled files left by the previous test run). The test set +produces some output. You can generally ignore the messages about +skipped tests due to optional features which can't be imported. +If a message is printed about a failed test or a traceback or core +dump is produced, something is wrong. On some Linux systems (those +that are not yet using glibc 6), test_strftime fails due to a +non-standard implementation of strftime() in the C library. Please +ignore this, or upgrade to glibc version 6. + +IMPORTANT: If the tests fail and you decide to mail a bug report, +*don't* include the output of "make test". It is useless. Run the +failing test manually, as follows: + + ./python ./Lib/test/test_whatever.py + +(substituting the top of the source tree for '.' if you built in a +different directory). This runs the test in verbose mode. + + +Installing +---------- + +To install the Python binary, library modules, shared library modules +(see below), include files, configuration files, and the manual page, +just type + + make install + +This will install all platform-independent files in subdirectories of +the directory given with the --prefix option to configure or to the +`prefix' Make variable (default /usr/local). All binary and other +platform-specific files will be installed in subdirectories if the +directory given by --exec-prefix or the `exec_prefix' Make variable +(defaults to the --prefix directory) is given. + +If DESTDIR is set, it will be taken as the root directory of the +installation, and files will be installed into $(DESTDIR)$(prefix), +$(DESTDIR)$(exec_prefix), etc. + +All subdirectories created will have Python's version number in their +name, e.g. the library modules are installed in +"/usr/local/lib/python<version>/" by default, where <version> is the +<major>.<minor> release number (e.g. "2.1"). The Python binary is +installed as "python<version>" and a hard link named "python" is +created. The only file not installed with a version number in its +name is the manual page, installed as "/usr/local/man/man1/python.1" +by default. + +If you have a previous installation of Python that you don't +want to replace yet, use + + make altinstall + +This installs the same set of files as "make install" except it +doesn't create the hard link to "python<version>" named "python" and +it doesn't install the manual page at all. + +The only thing you may have to install manually is the Python mode for +Emacs found in Misc/python-mode.el. (But then again, more recent +versions of Emacs may already have it.) Follow the instructions that +came with Emacs for installation of site-specific files. + +On Mac OS X, if you have configured Python with --enable-framework, you +should use "make frameworkinstall" to do the installation. Note that this +installs the Python executable in a place that is not normally on your +PATH, you may want to set up a symlink in /usr/local/bin. + + +Configuration options and variables +----------------------------------- + +Some special cases are handled by passing options to the configure +script. + +WARNING: if you rerun the configure script with different options, you +must run "make clean" before rebuilding. Exceptions to this rule: +after changing --prefix or --exec-prefix, all you need to do is remove +Modules/getpath.o. + +--with(out)-gcc: The configure script uses gcc (the GNU C compiler) if + it finds it. If you don't want this, or if this compiler is + installed but broken on your platform, pass the option + --without-gcc. You can also pass "CC=cc" (or whatever the + name of the proper C compiler is) in the environment, but the + advantage of using --without-gcc is that this option is + remembered by the config.status script for its --recheck + option. + +--prefix, --exec-prefix: If you want to install the binaries and the + Python library somewhere else than in /usr/local/{bin,lib}, + you can pass the option --prefix=DIRECTORY; the interpreter + binary will be installed as DIRECTORY/bin/python and the + library files as DIRECTORY/lib/python/*. If you pass + --exec-prefix=DIRECTORY (as well) this overrides the + installation prefix for architecture-dependent files (like the + interpreter binary). Note that --prefix=DIRECTORY also + affects the default module search path (sys.path), when + Modules/config.c is compiled. Passing make the option + prefix=DIRECTORY (and/or exec_prefix=DIRECTORY) overrides the + prefix set at configuration time; this may be more convenient + than re-running the configure script if you change your mind + about the install prefix. + +--with-readline: This option is no longer supported. GNU + readline is automatically enabled by setup.py when present. + +--with-threads: On most Unix systems, you can now use multiple + threads, and support for this is enabled by default. To + disable this, pass --with-threads=no. If the library required + for threads lives in a peculiar place, you can use + --with-thread=DIRECTORY. IMPORTANT: run "make clean" after + changing (either enabling or disabling) this option, or you + will get link errors! Note: for DEC Unix use + --with-dec-threads instead. + +--with-sgi-dl: On SGI IRIX 4, dynamic loading of extension modules is + supported by the "dl" library by Jack Jansen, which is + ftp'able from ftp://ftp.cwi.nl/pub/dynload/dl-1.6.tar.Z. + This is enabled (after you've ftp'ed and compiled the dl + library) by passing --with-sgi-dl=DIRECTORY where DIRECTORY + is the absolute pathname of the dl library. (Don't bother on + IRIX 5, it already has dynamic linking using SunOS style + shared libraries.) THIS OPTION IS UNSUPPORTED. + +--with-dl-dld: Dynamic loading of modules is rumored to be supported + on some other systems: VAX (Ultrix), Sun3 (SunOS 3.4), Sequent + Symmetry (Dynix), and Atari ST. This is done using a + combination of the GNU dynamic loading package + (ftp://ftp.cwi.nl/pub/dynload/dl-dld-1.1.tar.Z) and an + emulation of the SGI dl library mentioned above (the emulation + can be found at + ftp://ftp.cwi.nl/pub/dynload/dld-3.2.3.tar.Z). To + enable this, ftp and compile both libraries, then call + configure, passing it the option + --with-dl-dld=DL_DIRECTORY,DLD_DIRECTORY where DL_DIRECTORY is + the absolute pathname of the dl emulation library and + DLD_DIRECTORY is the absolute pathname of the GNU dld library. + (Don't bother on SunOS 4 or 5, they already have dynamic + linking using shared libraries.) THIS OPTION IS UNSUPPORTED. + +--with-libm, --with-libc: It is possible to specify alternative + versions for the Math library (default -lm) and the C library + (default the empty string) using the options + --with-libm=STRING and --with-libc=STRING, respectively. For + example, if your system requires that you pass -lc_s to the C + compiler to use the shared C library, you can pass + --with-libc=-lc_s. These libraries are passed after all other + libraries, the C library last. + +--with-libs='libs': Add 'libs' to the LIBS that the python interpreter + is linked against. + +--with-cxx-main=<compiler>: If you plan to use C++ extension modules, + then -- on some platforms -- you need to compile python's main() + function with the C++ compiler. With this option, make will use + <compiler> to compile main() *and* to link the python executable. + It is likely that the resulting executable depends on the C++ + runtime library of <compiler>. (The default is --without-cxx-main.) + + There are platforms that do not require you to build Python + with a C++ compiler in order to use C++ extension modules. + E.g., x86 Linux with ELF shared binaries and GCC 3.x, 4.x is such + a platform. We recommend that you configure Python + --without-cxx-main on those platforms because a mismatch + between the C++ compiler version used to build Python and to + build a C++ extension module is likely to cause a crash at + runtime. + + The Python installation also stores the variable CXX that + determines, e.g., the C++ compiler distutils calls by default + to build C++ extensions. If you set CXX on the configure command + line to any string of non-zero length, then configure won't + change CXX. If you do not preset CXX but pass + --with-cxx-main=<compiler>, then configure sets CXX=<compiler>. + In all other cases, configure looks for a C++ compiler by + some common names (c++, g++, gcc, CC, cxx, cc++, cl) and sets + CXX to the first compiler it finds. If it does not find any + C++ compiler, then it sets CXX="". + + Similarly, if you want to change the command used to link the + python executable, then set LINKCC on the configure command line. + + +--with-pydebug: Enable additional debugging code to help track down + memory management problems. This allows printing a list of all + live objects when the interpreter terminates. + +--with(out)-universal-newlines: enable reading of text files with + foreign newline convention (default: enabled). In other words, + any of \r, \n or \r\n is acceptable as end-of-line character. + If enabled import and execfile will automatically accept any newline + in files. Python code can open a file with open(file, 'U') to + read it in universal newline mode. THIS OPTION IS UNSUPPORTED. + +--with-tsc: Profile using the Pentium timestamping counter (TSC). + +--with-system-ffi: Build the _ctypes extension module using an ffi + library installed on the system. + + +Building for multiple architectures (using the VPATH feature) +------------------------------------------------------------- + +If your file system is shared between multiple architectures, it +usually is not necessary to make copies of the sources for each +architecture you want to support. If the make program supports the +VPATH feature, you can create an empty build directory for each +architecture, and in each directory run the configure script (on the +appropriate machine with the appropriate options). This creates the +necessary subdirectories and the Makefiles therein. The Makefiles +contain a line VPATH=... which points to a directory containing the +actual sources. (On SGI systems, use "smake -J1" instead of "make" if +you use VPATH -- don't try gnumake.) + +For example, the following is all you need to build a minimal Python +in /usr/tmp/python (assuming ~guido/src/python is the toplevel +directory and you want to build in /usr/tmp/python): + + $ mkdir /usr/tmp/python + $ cd /usr/tmp/python + $ ~guido/src/python/configure + [...] + $ make + [...] + $ + +Note that configure copies the original Setup file to the build +directory if it finds no Setup file there. This means that you can +edit the Setup file for each architecture independently. For this +reason, subsequent changes to the original Setup file are not tracked +automatically, as they might overwrite local changes. To force a copy +of a changed original Setup file, delete the target Setup file. (The +makesetup script supports multiple input files, so if you want to be +fancy you can change the rules to create an empty Setup.local if it +doesn't exist and run it with arguments $(srcdir)/Setup Setup.local; +however this assumes that you only need to add modules.) + + +Building on non-UNIX systems +---------------------------- + +For Windows (2000/NT/ME/98/95), assuming you have MS VC++ 7.1, the +project files are in PCbuild, the workspace is pcbuild.dsw. See +PCbuild\readme.txt for detailed instructions. + +For other non-Unix Windows compilers, in particular MS VC++ 6.0 and +for OS/2, enter the directory "PC" and read the file "readme.txt". + +For the Mac, a separate source distribution will be made available, +for use with the CodeWarrior compiler. If you are interested in Mac +development, join the PythonMac Special Interest Group +(http://www.python.org/sigs/pythonmac-sig/, or send email to +pythonmac-sig-request@python.org). + +Of course, there are also binary distributions available for these +platforms -- see http://www.python.org/. + +To port Python to a new non-UNIX system, you will have to fake the +effect of running the configure script manually (for Mac and PC, this +has already been done for you). A good start is to copy the file +pyconfig.h.in to pyconfig.h and edit the latter to reflect the actual +configuration of your system. Most symbols must simply be defined as +1 only if the corresponding feature is present and can be left alone +otherwise; however the *_t type symbols must be defined as some +variant of int if they need to be defined at all. + +For all platforms, it's important that the build arrange to define the +preprocessor symbol NDEBUG on the compiler command line in a release +build of Python (else assert() calls remain in the code, hurting +release-build performance). The Unix, Windows and Mac builds already +do this. + + +Miscellaneous issues +==================== + +Emacs mode +---------- + +There's an excellent Emacs editing mode for Python code; see the file +Misc/python-mode.el. Originally written by the famous Tim Peters, it +is now maintained by the equally famous Barry Warsaw (it's no +coincidence that they now both work on the same team). The latest +version, along with various other contributed Python-related Emacs +goodies, is online at http://www.python.org/emacs/python-mode. And +if you are planning to edit the Python C code, please pick up the +latest version of CC Mode http://www.python.org/emacs/cc-mode; it +contains a "python" style used throughout most of the Python C source +files. (Newer versions of Emacs or XEmacs may already come with the +latest version of python-mode.) + + +Tkinter +------- + +The setup.py script automatically configures this when it detects a +usable Tcl/Tk installation. This requires Tcl/Tk version 8.0 or +higher. + +For more Tkinter information, see the Tkinter Resource page: +http://www.python.org/topics/tkinter/ + +There are demos in the Demo/tkinter directory. + +Note that there's a Python module called "Tkinter" (capital T) which +lives in Lib/lib-tk/Tkinter.py, and a C module called "_tkinter" +(lower case t and leading underscore) which lives in +Modules/_tkinter.c. Demos and normal Tk applications import only the +Python Tkinter module -- only the latter imports the C _tkinter +module. In order to find the C _tkinter module, it must be compiled +and linked into the Python interpreter -- the setup.py script does +this. In order to find the Python Tkinter module, sys.path must be +set correctly -- normal installation takes care of this. + + +Distribution structure +---------------------- + +Most subdirectories have their own README files. Most files have +comments. + +BeOS/ Files specific to the BeOS port +Demo/ Demonstration scripts, modules and programs +Doc/ Documentation sources (LaTeX) +Grammar/ Input for the parser generator +Include/ Public header files +LICENSE Licensing information +Lib/ Python library modules +Mac/ Macintosh specific resources +Makefile.pre.in Source from which config.status creates the Makefile.pre +Misc/ Miscellaneous useful files +Modules/ Implementation of most built-in modules +Objects/ Implementation of most built-in object types +PC/ Files specific to PC ports (DOS, Windows, OS/2) +PCbuild/ Build directory for Microsoft Visual C++ +Parser/ The parser and tokenizer and their input handling +Python/ The byte-compiler and interpreter +README The file you're reading now +Tools/ Some useful programs written in Python +pyconfig.h.in Source from which pyconfig.h is created (GNU autoheader output) +configure Configuration shell script (GNU autoconf output) +configure.in Configuration specification (input for GNU autoconf) +install-sh Shell script used to install files +setup.py Python script used to build extension modules + +The following files will (may) be created in the toplevel directory by +the configuration and build processes: + +Makefile Build rules +Makefile.pre Build rules before running Modules/makesetup +buildno Keeps track of the build number +config.cache Cache of configuration variables +pyconfig.h Configuration header +config.log Log from last configure run +config.status Status from last run of the configure script +getbuildinfo.o Object file from Modules/getbuildinfo.c +libpython<version>.a The library archive +python The executable interpreter +tags, TAGS Tags files for vi and Emacs + + +That's all, folks! +------------------ + + +--Guido van Rossum (home page: http://www.python.org/~guido/) diff --git a/sys/src/cmd/python/README.Plan9 b/sys/src/cmd/python/README.Plan9 new file mode 100644 index 000000000..20301b269 --- /dev/null +++ b/sys/src/cmd/python/README.Plan9 @@ -0,0 +1,12 @@ +Python 2.5.1 for APE. + +Requires: +- /n/sources/patch/ape-chmod-dirbit + +Federico G. Benavento +November 2009 +benavento@gmail.com + +Some fixes by Felipe Bichued +October 2008 +bichued@gmail.com diff --git a/sys/src/cmd/python/Tools/README b/sys/src/cmd/python/Tools/README new file mode 100644 index 000000000..404ba4dbf --- /dev/null +++ b/sys/src/cmd/python/Tools/README @@ -0,0 +1,47 @@ +This directory contains a number of Python programs that are useful +while building or extending Python. + +audiopy Audiopy is a program to control the Solaris audio + device, allowing you to choose both the input and + output devices, and to set the output volume, that can + be run either as a command-line script, or as a + Tkinter application. + +bgen Generate complete extension modules from a + description. Still under development! + +compiler Tools used to maintain the compiler package in the + standard library. + +faqwiz FAQ Wizard. + See http://www.python.org/cgi-bin/faqw.py + for a live example. + +freeze Create a stand-alone executable from a Python program. + +i18n Tools for internationalization. pygettext.py + parses Python source code and generates .pot files, + and msgfmt.py generates a binary message catalog + from a catalog in text format. + +modulator Interactively generate boiler plate for an extension + module. Works easiest if you have Tk. + +pynche A Tkinter-based color editor. + +scripts A number of useful single-file programs, e.g. tabnanny.py + (by Tim Peters), which checks for inconsistent mixing + of tabs and spaces. + +unicode Tools used to generate unicode database files for + Python 2.0 (by Fredrik Lundh). + +versioncheck A tool to automate checking whether you have the latest + version of a package (by Jack Jansen). + +webchecker A link checker for web sites. + +world Script to take a list of Internet addresses and print + out where in the world those addresses originate from, + based on the top-level domain country code found in + the address. diff --git a/sys/src/cmd/python/Tools/audiopy/README b/sys/src/cmd/python/Tools/audiopy/README new file mode 100644 index 000000000..45bf7736f --- /dev/null +++ b/sys/src/cmd/python/Tools/audiopy/README @@ -0,0 +1,112 @@ +audiopy - a program to control the Solaris audio device. + +Contact: Barry Warsaw +Email: bwarsaw@python.org +Version: 1.1 + +Introduction + + Audiopy is a program to control the Solaris audio device, allowing + you to choose both the input and output devices, and to set the + output volume. It can be run either as a standalone command-line + script, or as a Tkinter based GUI application. + + Note that your version of Python must have been built with the + sunaudiodev module enabled. It is not enabled by default however! + You will need to edit your Modules/Setup file, uncomment the + sunaudiodev module spec line and rebuild Python. + + Using audiopy, you can select one of three possible input devices: + the microphone, the line-in jack, or the CD in. These choices are + mutually exclusive; you can only have one active input device at + any one time (this is enforced by the underlying device). Some + input devices may not be supported on all Solaris machines. + + You can also choose to enable any of the three possible output + devices: the headphone jack, the speakers, or the line-out jack. + You can enable any combination of these three devices. + + You can also set the output gain (volume) level. + +Running as a GUI + + Simply start audiopy with no arguments to start it as a Tkinter + based GUI application. It will pop up a window with two sections: + the top portion contains three radio buttons indicating your + selected input device; the middle portion contains three + checkboxes indicating your selected output devices; the bottom + portion contains a slider that changes the output gain. + + Note the underlined characters in the button labels. These + indicate keyboard accelerators so that pressing Alt+character you + can select that device. For example, Alt-s toggles the Speaker + device. The Alt accelerators are the same as those you'd use in + as the short-form command line switches (see below). + + Alt-q is also an accelerator for selecting Quit from the File + menu. + + Unsupported devices will appear dimmed out in the GUI. When run + as a GUI, audiopy monitors the audio device and automatically + updates its display if the state of the device is changed by some + other means. With Python versions before 1.5.2 this is done by + occasionally polling the device, but in Python 1.5.2 no polling is + necessary (you don't really need to know this, but I thought I'd + plug 1.5.2 :-). + +Running as a Command Line Program + + You can run audiopy from the command line to select any + combination of input or output device, by using the command line + options. Actually, any option forces audiopy to run as a command + line program and not display its GUI. + + Options have the general form + + --device[={0,1}] + -d[-{0,1}] + + meaning there is both a long-form and short-form of the switch, + where `device' or `d' is one of the following: + + (input) + microphone -- m + linein -- i + cd -- c + + (output) + headphones -- p + speaker -- s + lineout -- o + + When no value is given, the switch just toggles the specified + device. With a value, 0 turns the device off and 1 turns the + device on. Any other value is an error. + + For example, to turn the speakers off, turn the headphones on, and + toggle the cd input device, run audiopy from the command line like + so: + + % ./audiopy -s=0 -p=1 -c + + Audiopy understands these other command line options: + + --gain volume + -g volume + Sets the output volume to the specified gain level. This must + be an integer between MIN_GAIN and MAX_GAIN (usually [0..255], + but use the -h option to find the exact values). + + --version + -v + Print the version number and exit + + --help + -h + Print a help message and exit + + + +Local Variables: +indent-tabs-mode: nil +End: diff --git a/sys/src/cmd/python/Tools/audiopy/audiopy b/sys/src/cmd/python/Tools/audiopy/audiopy new file mode 100755 index 000000000..b817c5cc0 --- /dev/null +++ b/sys/src/cmd/python/Tools/audiopy/audiopy @@ -0,0 +1,507 @@ +#! /usr/bin/env python + +"""audiopy -- a program to control the Solaris audio device. + +Contact: Barry Warsaw +Email: bwarsaw@python.org +Version: %(__version__)s + +When no arguments are given, this pops up a graphical window which lets you +choose the audio input and output devices, and set the output volume. + +This program can be driven via the command line, and when done so, no window +pops up. Most options have the general form: + + --device[={0,1}] + -d[={0,1}] + Set the I/O device. With no value, it toggles the specified device. + With a value, 0 turns the device off and 1 turns the device on. + +The list of devices and their short options are: + + (input) + microphone -- m + linein -- i + cd -- c + + (output) + headphones -- p + speaker -- s + lineout -- o + +Other options are: + + --gain volume + -g volume + Sets the output gain to the specified volume, which must be an integer + in the range [%(MIN_GAIN)s..%(MAX_GAIN)s] + + --version + -v + Print the version number and exit. + + --help + -h + Print this message and exit. +""" + +import sys +import os +import errno +import sunaudiodev +from SUNAUDIODEV import * + +# Milliseconds between interrupt checks +KEEPALIVE_TIMER = 500 + +__version__ = '1.1' + + + +class MainWindow: + def __init__(self, device): + from Tkinter import * + self.__helpwin = None + self.__devctl = device + info = device.getinfo() + # + self.__tkroot = tkroot = Tk(className='Audiopy') + tkroot.withdraw() + # create the menubar + menubar = Menu(tkroot) + filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Quit', + command=self.__quit, + accelerator='Alt-Q', + underline=0) + helpmenu = Menu(menubar, name='help', tearoff=0) + helpmenu.add_command(label='About Audiopy...', + command=self.__popup_about, + underline=0) + helpmenu.add_command(label='Help...', + command=self.__popup_using, + underline=0) + menubar.add_cascade(label='File', + menu=filemenu, + underline=0) + menubar.add_cascade(label='Help', + menu=helpmenu, + underline=0) + # now create the top level window + root = self.__root = Toplevel(tkroot, class_='Audiopy', menu=menubar) + root.protocol('WM_DELETE_WINDOW', self.__quit) + root.title('audiopy ' + __version__) + root.iconname('audiopy ' + __version__) + root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive) + # + buttons = [] + # + # where does input come from? + frame = Frame(root, bd=1, relief=RAISED) + frame.grid(row=1, column=0, sticky='NSEW') + label = Label(frame, text='Input From:') + label.grid(row=0, column=0, sticky=E) + self.__inputvar = IntVar() + ## + btn = Radiobutton(frame, + text='None', + variable=self.__inputvar, + value=0, + command=self.__pushtodev, + underline=0) + btn.grid(row=0, column=1, sticky=W) + root.bind('<Alt-n>', self.__none) + root.bind('<Alt-N>', self.__none) + if not info.i_avail_ports & MICROPHONE: + btn.configure(state=DISABLED) + buttons.append(btn) + ## + btn = Radiobutton(frame, + text='Microphone', + variable=self.__inputvar, + value=MICROPHONE, + command=self.__pushtodev, + underline=0) + btn.grid(row=1, column=1, sticky=W) + root.bind('<Alt-m>', self.__mic) + root.bind('<Alt-M>', self.__mic) + if not info.i_avail_ports & MICROPHONE: + btn.configure(state=DISABLED) + buttons.append(btn) + ## + btn = Radiobutton(frame, + text='Line In', + variable=self.__inputvar, + value=LINE_IN, + command=self.__pushtodev, + underline=5) + btn.grid(row=2, column=1, sticky=W) + root.bind('<Alt-i>', self.__linein) + root.bind('<Alt-I>', self.__linein) + if not info.i_avail_ports & LINE_IN: + btn.configure(state=DISABLED) + buttons.append(btn) + ## if SUNAUDIODEV was built on an older version of Solaris, the CD + ## input device won't exist + try: + btn = Radiobutton(frame, + text='CD', + variable=self.__inputvar, + value=CD, + command=self.__pushtodev, + underline=0) + btn.grid(row=3, column=1, sticky=W) + root.bind('<Alt-c>', self.__cd) + root.bind('<Alt-C>', self.__cd) + if not info.i_avail_ports & CD: + btn.configure(state=DISABLED) + buttons.append(btn) + except NameError: + pass + # + # where does output go to? + frame = Frame(root, bd=1, relief=RAISED) + frame.grid(row=2, column=0, sticky='NSEW') + label = Label(frame, text='Output To:') + label.grid(row=0, column=0, sticky=E) + self.__spkvar = IntVar() + btn = Checkbutton(frame, + text='Speaker', + variable=self.__spkvar, + onvalue=SPEAKER, + command=self.__pushtodev, + underline=0) + btn.grid(row=0, column=1, sticky=W) + root.bind('<Alt-s>', self.__speaker) + root.bind('<Alt-S>', self.__speaker) + if not info.o_avail_ports & SPEAKER: + btn.configure(state=DISABLED) + buttons.append(btn) + ## + self.__headvar = IntVar() + btn = Checkbutton(frame, + text='Headphones', + variable=self.__headvar, + onvalue=HEADPHONE, + command=self.__pushtodev, + underline=4) + btn.grid(row=1, column=1, sticky=W) + root.bind('<Alt-p>', self.__headphones) + root.bind('<Alt-P>', self.__headphones) + if not info.o_avail_ports & HEADPHONE: + btn.configure(state=DISABLED) + buttons.append(btn) + ## + self.__linevar = IntVar() + btn = Checkbutton(frame, + variable=self.__linevar, + onvalue=LINE_OUT, + text='Line Out', + command=self.__pushtodev, + underline=0) + btn.grid(row=2, column=1, sticky=W) + root.bind('<Alt-l>', self.__lineout) + root.bind('<Alt-L>', self.__lineout) + if not info.o_avail_ports & LINE_OUT: + btn.configure(state=DISABLED) + buttons.append(btn) + # + # Fix up widths + widest = 0 + for b in buttons: + width = b['width'] + if width > widest: + widest = width + for b in buttons: + b.configure(width=widest) + # root bindings + root.bind('<Alt-q>', self.__quit) + root.bind('<Alt-Q>', self.__quit) + # + # Volume + frame = Frame(root, bd=1, relief=RAISED) + frame.grid(row=3, column=0, sticky='NSEW') + label = Label(frame, text='Output Volume:') + label.grid(row=0, column=0, sticky=W) + self.__scalevar = IntVar() + self.__scale = Scale(frame, + orient=HORIZONTAL, + from_=MIN_GAIN, + to=MAX_GAIN, + length=200, + variable=self.__scalevar, + command=self.__volume) + self.__scale.grid(row=1, column=0, sticky=EW) + # + # do we need to poll for changes? + self.__needtopoll = 1 + try: + fd = self.__devctl.fileno() + self.__needtopoll = 0 + except AttributeError: + pass + else: + import fcntl + import signal + import STROPTS + # set up the signal handler + signal.signal(signal.SIGPOLL, self.__update) + fcntl.ioctl(fd, STROPTS.I_SETSIG, STROPTS.S_MSG) + self.__update() + + def __quit(self, event=None): + self.__devctl.close() + self.__root.quit() + + def __popup_about(self, event=None): + import tkMessageBox + tkMessageBox.showinfo('About Audiopy ' + __version__, + '''\ +Audiopy %s +Control the Solaris audio device + +For information +Contact: Barry A. Warsaw +Email: bwarsaw@python.org''' % __version__) + + def __popup_using(self, event=None): + if not self.__helpwin: + self.__helpwin = Helpwin(self.__tkroot, self.__quit) + self.__helpwin.deiconify() + + + def __keepalive(self): + # Exercise the Python interpreter regularly so keyboard interrupts get + # through. + self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive) + if self.__needtopoll: + self.__update() + + def __update(self, num=None, frame=None): + # It's possible (although I have never seen it) to get an interrupted + # system call during the getinfo() call. If so, and we're polling, + # don't sweat it because we'll come around again later. Otherwise, + # we'll give it a couple of tries and then give up until next time. + tries = 0 + while 1: + try: + info = self.__devctl.getinfo() + break + except sunaudiodev.error: + if self.__needtopoll or tries > 3: + return + tries = tries + 1 + # input + self.__inputvar.set(info.i_port) + # output + self.__spkvar.set(info.o_port & SPEAKER) + self.__headvar.set(info.o_port & HEADPHONE) + self.__linevar.set(info.o_port & LINE_OUT) + # volume + self.__scalevar.set(info.o_gain) + + def __pushtodev(self, event=None): + info = self.__devctl.getinfo() + info.o_port = self.__spkvar.get() + \ + self.__headvar.get() + \ + self.__linevar.get() + info.i_port = self.__inputvar.get() + info.o_gain = self.__scalevar.get() + try: + self.__devctl.setinfo(info) + except sunaudiodev.error, msg: + # TBD: what to do? it's probably temporary. + pass + + def __getset(self, var, onvalue): + if var.get() == onvalue: + var.set(0) + else: + var.set(onvalue) + self.__pushtodev() + + def __none(self, event=None): + self.__inputvar.set(0) + self.__pushtodev() + + def __mic(self, event=None): + self.__getset(self.__inputvar, MICROPHONE) + + def __linein(self, event=None): + self.__getset(self.__inputvar, LINE_IN) + + def __cd(self, event=None): + self.__getset(self.__inputvar, CD) + + def __speaker(self, event=None): + self.__getset(self.__spkvar, SPEAKER) + + def __headphones(self, event=None): + self.__getset(self.__headvar, HEADPHONE) + + def __lineout(self, event=None): + self.__getset(self.__linevar, LINE_OUT) + + def __volume(self, event=None): + self.__pushtodev() + + def start(self): + self.__keepalive() + self.__tkroot.mainloop() + + + +class Helpwin: + def __init__(self, master, quitfunc): + from Tkinter import * + self.__root = root = Toplevel(master, class_='Audiopy') + root.protocol('WM_DELETE_WINDOW', self.__withdraw) + root.title('Audiopy Help Window') + root.iconname('Audiopy Help Window') + root.bind('<Alt-q>', quitfunc) + root.bind('<Alt-Q>', quitfunc) + root.bind('<Alt-w>', self.__withdraw) + root.bind('<Alt-W>', self.__withdraw) + + # more elaborate help is available in the README file + readmefile = os.path.join(sys.path[0], 'README') + try: + fp = None + try: + fp = open(readmefile) + contents = fp.read() + # wax the last page, it contains Emacs cruft + i = contents.rfind('\f') + if i > 0: + contents = contents[:i].rstrip() + finally: + if fp: + fp.close() + except IOError: + sys.stderr.write("Couldn't open audiopy's README, " + 'using docstring instead.\n') + contents = __doc__ % globals() + + self.__text = text = Text(root, relief=SUNKEN, + width=80, height=24) + text.insert(0.0, contents) + scrollbar = Scrollbar(root) + scrollbar.pack(fill=Y, side=RIGHT) + text.pack(fill=BOTH, expand=YES) + text.configure(yscrollcommand=(scrollbar, 'set')) + scrollbar.configure(command=(text, 'yview')) + + def __withdraw(self, event=None): + self.__root.withdraw() + + def deiconify(self): + self.__root.deiconify() + + + + +def usage(code, msg=''): + print __doc__ % globals() + if msg: + print msg + sys.exit(code) + + +def main(): + # + # Open up the audio control device and query for the current output + # device + device = sunaudiodev.open('control') + + if len(sys.argv) == 1: + # GUI + w = MainWindow(device) + try: + w.start() + except KeyboardInterrupt: + pass + return + + # spec: LONG OPT, SHORT OPT, 0=input,1=output, MASK + options = [('--microphone', '-m', 0, MICROPHONE), + ('--linein', '-i', 0, LINE_IN), + ('--headphones', '-p', 1, HEADPHONE), + ('--speaker', '-s', 1, SPEAKER), + ('--lineout', '-o', 1, LINE_OUT), + ] + # See the comment above about `CD' + try: + options.append(('--cd', '-c', 0, CD)) + except NameError: + pass + + info = device.getinfo() + # first get the existing values + i = 0 + while i < len(sys.argv)-1: + i = i + 1 + arg = sys.argv[i] + if arg in ('-h', '--help'): + usage(0) + # does not return + elif arg in ('-g', '--gain'): + gainspec = '<missing>' + try: + gainspec = sys.argv[i+1] + gain = int(gainspec) + except (ValueError, IndexError): + usage(1, 'Bad gain specification: ' + gainspec) + info.o_gain = gain + i = i + 1 + continue + elif arg in ('-v', '--version'): + print '''\ +audiopy -- a program to control the Solaris audio device. +Contact: Barry Warsaw +Email: bwarsaw@python.org +Version: %s''' % __version__ + sys.exit(0) + for long, short, io, mask in options: + if arg in (long, short): + # toggle the option + if io == 0: + info.i_port = info.i_port ^ mask + else: + info.o_port = info.o_port ^ mask + break + val = None + try: + if arg[:len(long)+1] == long+'=': + val = int(arg[len(long)+1:]) + elif arg[:len(short)+1] == short+'=': + val = int(arg[len(short)+1:]) + except ValueError: + usage(1, msg='Invalid option: ' + arg) + # does not return + if val == 0: + if io == 0: + info.i_port = info.i_port & ~mask + else: + info.o_port = info.o_port & ~mask + break + elif val == 1: + if io == 0: + info.i_port = info.i_port | mask + else: + info.o_port = info.o_port | mask + break + # else keep trying next option + else: + usage(1, msg='Invalid option: ' + arg) + # now set the values + try: + device.setinfo(info) + except sunaudiodev.error, (code, msg): + if code <> errno.EINVAL: + raise + device.close() + + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/bgen/README b/sys/src/cmd/python/Tools/bgen/README new file mode 100644 index 000000000..70700c652 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/README @@ -0,0 +1,7 @@ +BGEN -- Automatic Generation of Extension Modules +================================================= + +This directory contains BGEN -- a package that helps in generating +complete source code for Python extension module. For examples of its +use, see the Mac Python source distribution (available separately +from the Python ftp archives). Note that BGEN is not Mac specific! diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgen.py b/sys/src/cmd/python/Tools/bgen/bgen/bgen.py new file mode 100644 index 000000000..db28b0a87 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgen.py @@ -0,0 +1,12 @@ +"Export everything in the various bgen submodules." + +from bgenType import * +from bgenVariable import * +from bgenBuffer import * +from bgenStackBuffer import * +from bgenHeapBuffer import * +from bgenStringBuffer import * +from bgenOutput import * +from bgenGenerator import * +from bgenModule import * +from bgenObjectDefinition import * diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenBuffer.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenBuffer.py new file mode 100644 index 000000000..94ab95003 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenBuffer.py @@ -0,0 +1,301 @@ +"""Buffers are character arrays that may contain null bytes. + +There are a number of variants depending on: +- how the buffer is allocated (for output buffers), and +- whether and how the size is passed into and/or out of the called function. +""" + + +from bgenType import Type, InputOnlyMixIn, OutputOnlyMixIn, InputOnlyType, OutputOnlyType +from bgenOutput import * + + +# Map common types to their format characters +type2format = { + 'long': 'l', + 'int': 'i', + 'short': 'h', + 'char': 'b', + 'unsigned long': 'l', + 'unsigned int': 'i', + 'unsigned short': 'h', + 'unsigned char': 'b', +} + + +# ----- PART 1: Fixed character buffers ----- + + +class FixedInputOutputBufferType(InputOnlyType): + + """Fixed buffer -- passed as (inbuffer, outbuffer).""" + + def __init__(self, size, datatype = 'char', sizetype = 'int', sizeformat = None): + self.typeName = "Buffer" + self.size = str(size) + self.datatype = datatype + self.sizetype = sizetype + self.sizeformat = sizeformat or type2format[sizetype] + self.label_needed = 0 + + def getArgDeclarations(self, name, reference=False, constmode=False, outmode=False): + if reference: + raise RuntimeError, "Cannot pass buffer types by reference" + return (self.getBufferDeclarations(name, constmode, outmode) + + self.getSizeDeclarations(name, outmode)) + + def getBufferDeclarations(self, name, constmode=False, outmode=False): + return self.getInputBufferDeclarations(name, constmode) + \ + self.getOutputBufferDeclarations(name, constmode, outmode) + + def getInputBufferDeclarations(self, name, constmode=False): + if constmode: + const = "const " + else: + const = "" + return ["%s%s *%s__in__" % (const, self.datatype, name)] + + def getOutputBufferDeclarations(self, name, constmode=False, outmode=False): + if constmode: + raise RuntimeError, "Cannot use const output buffer" + if outmode: + out = "*" + else: + out = "" + return ["%s%s %s__out__[%s]" % (self.datatype, out, name, self.size)] + + def getSizeDeclarations(self, name, outmode=False): + if outmode: + out = "*" + else: + out = "" + return ["%s%s %s__len__" %(self.sizetype, out, name)] + + def getAuxDeclarations(self, name): + return ["int %s__in_len__" %(name)] + + def getargsFormat(self): + return "s#" + + def getargsArgs(self, name): + return "&%s__in__, &%s__in_len__" % (name, name) + + def getargsCheck(self, name): + Output("if (%s__in_len__ != %s)", name, self.size) + OutLbrace() + Output('PyErr_SetString(PyExc_TypeError, "buffer length should be %s");', + self.size) + Output("goto %s__error__;", name) + self.label_needed = 1 + OutRbrace() + self.transferSize(name) + + def transferSize(self, name): + Output("%s__len__ = %s__in_len__;", name, name) + + def passOutput(self, name): + return "%s__in__, %s__out__" % (name, name) + + def mkvalueFormat(self): + return "s#" + + def mkvalueArgs(self, name): + return "%s__out__, (int)%s" % (name, self.size) + + def cleanup(self, name): + if self.label_needed: + DedentLevel() + Output(" %s__error__: ;", name) + IndentLevel() + + +class FixedCombinedInputOutputBufferType(FixedInputOutputBufferType): + + """Like fixed buffer -- but same parameter is input and output.""" + + def passOutput(self, name): + return "(%s *)memcpy(%s__out__, %s__in__, %s)" % \ + (self.datatype, name, name, self.size) + + +class InputOnlyBufferMixIn(InputOnlyMixIn): + + def getOutputBufferDeclarations(self, name, constmode=False, outmode=False): + return [] + + +class OutputOnlyBufferMixIn(OutputOnlyMixIn): + + def getInputBufferDeclarations(self, name, constmode=False): + return [] + +class OptionalInputBufferMixIn: + + """Add to input buffers if the buffer may be omitted: pass None in Python + and the C code will get a NULL pointer and zero size""" + + def getargsFormat(self): + return "z#" + + +class FixedInputBufferType(InputOnlyBufferMixIn, FixedInputOutputBufferType): + + """Fixed size input buffer -- passed without size information. + + Instantiate with the size as parameter. + """ + + def passInput(self, name): + return "%s__in__" % name + +class OptionalFixedInputBufferType(OptionalInputBufferMixIn, FixedInputBufferType): + pass + +class FixedOutputBufferType(OutputOnlyBufferMixIn, FixedInputOutputBufferType): + + """Fixed size output buffer -- passed without size information. + + Instantiate with the size as parameter. + """ + + def passOutput(self, name): + return "%s__out__" % name + + +class VarInputBufferType(FixedInputBufferType): + + """Variable size input buffer -- passed as (buffer, size). + + Instantiate without size parameter. + """ + + def __init__(self, datatype = 'char', sizetype = 'int', sizeformat = None): + FixedInputBufferType.__init__(self, "0", datatype, sizetype, sizeformat) + + def getargsCheck(self, name): + Output("%s__len__ = %s__in_len__;", name, name) + + def passInput(self, name): + return "%s__in__, %s__len__" % (name, name) + +class ReverseInputBufferMixin: + """ Mixin for input buffers that are passed as (size, buffer) """ + + def passInput(self, name): + return "%s__len__, %s__in__" % (name, name) + +class OptionalVarInputBufferType(OptionalInputBufferMixIn, VarInputBufferType): + pass + +# ----- PART 2: Structure buffers ----- + + +class StructInputOutputBufferType(FixedInputOutputBufferType): + + """Structure buffer -- passed as a structure pointer. + + Instantiate with the struct type as parameter. + """ + + def __init__(self, type): + FixedInputOutputBufferType.__init__(self, "sizeof(%s)" % type) + self.typeName = self.type = type + + def getInputBufferDeclarations(self, name, constmode=False): + if constmode: + const = "const " + else: + const = "" + return ["%s%s *%s__in__" % (const, self.type, name)] + + def getSizeDeclarations(self, name, outmode=False): + return [] + + def getAuxDeclarations(self, name): + return ["int %s__in_len__" % (name)] + + def getOutputBufferDeclarations(self, name, constmode=False, outmode=False): + if constmode: + raise RuntimeError, "Cannot use const output buffer" + if outmode: + out = "*" + else: + out = "" + return ["%s%s %s__out__" % (self.type, out, name)] + + def getargsArgs(self, name): + return "(char **)&%s__in__, &%s__in_len__" % (name, name) + + def transferSize(self, name): + pass + + def passInput(self, name): + return "%s__in__" % name + + def passOutput(self, name): + return "%s__in__, &%s__out__" % (name, name) + + def mkvalueArgs(self, name): + return "(char *)&%s__out__, (int)%s" % (name, self.size) + + +class StructCombinedInputOutputBufferType(StructInputOutputBufferType): + + """Like structure buffer -- but same parameter is input and output.""" + + def passOutput(self, name): + return "(%s *)memcpy((char *)%s__out__, (char *)%s__in__, %s)" % \ + (self.type, name, name, self.size) + + +class StructInputBufferType(InputOnlyBufferMixIn, StructInputOutputBufferType): + + """Fixed size input buffer -- passed as a pointer to a structure. + + Instantiate with the struct type as parameter. + """ + + +class StructByValueBufferType(StructInputBufferType): + + """Fixed size input buffer -- passed as a structure BY VALUE. + + Instantiate with the struct type as parameter. + """ + + def passInput(self, name): + return "*%s__in__" % name + + +class StructOutputBufferType(OutputOnlyBufferMixIn, StructInputOutputBufferType): + + """Fixed size output buffer -- passed as a pointer to a structure. + + Instantiate with the struct type as parameter. + """ + + def getSizeDeclarations(self, name, outmode=False): + return [] + + def getAuxDeclarations(self, name): + return [] + + def passOutput(self, name): + return "&%s__out__" % name + + +class ArrayOutputBufferType(OutputOnlyBufferMixIn, StructInputOutputBufferType): + + """Fixed size output buffer -- declared as a typedef, passed as an array. + + Instantiate with the struct type as parameter. + """ + + def getSizeDeclarations(self, name, outmode=False): + return [] + + def getAuxDeclarations(self, name): + return [] + + def passOutput(self, name): + return "%s__out__" % name diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenGenerator.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenGenerator.py new file mode 100644 index 000000000..3da39589a --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenGenerator.py @@ -0,0 +1,302 @@ +from bgenOutput import * +from bgenType import * +from bgenVariable import * + + +Error = "bgenGenerator.Error" + +DEBUG=0 + +# Strings to specify argument transfer modes in generator calls +IN = "in" +OUT = "out" +INOUT = IN_OUT = "in-out" + + +class BaseFunctionGenerator: + + def __init__(self, name, condition=None, callname=None, modifiers=None): + if DEBUG: print "<--", name + self.name = name + if callname: + self.callname = callname + else: + self.callname = name + self.prefix = name + self.objecttype = "PyObject" # Type of _self argument to function + self.condition = condition + self.modifiers = modifiers + + def setprefix(self, prefix): + self.prefix = prefix + + def checkgenerate(self): + return True + + def generate(self): + if not self.checkgenerate(): + return + if DEBUG: print "-->", self.name + if self.condition: + Output() + Output(self.condition) + self.functionheader() + self.functionbody() + self.functiontrailer() + if self.condition: + Output("#endif") + + def functionheader(self): + Output() + Output("static PyObject *%s_%s(%s *_self, PyObject *_args)", + self.prefix, self.name, self.objecttype) + OutLbrace() + Output("PyObject *_res = NULL;") + + def functionbody(self): + Output("/* XXX To be provided */") + + def functiontrailer(self): + OutRbrace() + + def reference(self, name = None): + if not self.checkgenerate(): + return + if name is None: + name = self.name + docstring = self.docstring() + if self.condition: + Output() + Output(self.condition) + Output("{\"%s\", (PyCFunction)%s_%s, 1,", name, self.prefix, self.name) + Output(" PyDoc_STR(%s)},", stringify(docstring)) + if self.condition: + Output("#endif") + + def docstring(self): + return None + + def __cmp__(self, other): + if not hasattr(other, 'name'): + return cmp(id(self), id(other)) + return cmp(self.name, other.name) + +_stringify_map = {'\n': '\\n', '\t': '\\t', '\r': '\\r', '\b': '\\b', + '\e': '\\e', '\a': '\\a', '\f': '\\f', '"': '\\"'} +def stringify(str): + if str is None: return "NULL" + res = '"' + map = _stringify_map + for c in str: + if map.has_key(c): res = res + map[c] + elif ' ' <= c <= '~': res = res + c + else: res = res + '\\%03o' % ord(c) + res = res + '"' + return res + + +class ManualGenerator(BaseFunctionGenerator): + + def __init__(self, name, body, condition=None): + BaseFunctionGenerator.__init__(self, name, condition=condition) + self.body = body + + def functionbody(self): + Output("%s", self.body) + + def setselftype(self, selftype, itselftype): + self.objecttype = selftype + self.itselftype = itselftype + + +class FunctionGenerator(BaseFunctionGenerator): + + def __init__(self, returntype, name, *argumentList, **conditionlist): + BaseFunctionGenerator.__init__(self, name, **conditionlist) + self.returntype = returntype + self.argumentList = [] + self.setreturnvar() + self.parseArgumentList(argumentList) + self.prefix = "XXX" # Will be changed by setprefix() call + self.itselftype = None # Type of _self->ob_itself, if defined + + def setreturnvar(self): + if self.returntype: + self.rv = self.makereturnvar() + self.argumentList.append(self.rv) + else: + self.rv = None + + def makereturnvar(self): + return Variable(self.returntype, "_rv", OutMode) + + def setselftype(self, selftype, itselftype): + self.objecttype = selftype + self.itselftype = itselftype + + def parseArgumentList(self, argumentList): + iarg = 0 + for type, name, mode in argumentList: + iarg = iarg + 1 + if name is None: name = "_arg%d" % iarg + arg = Variable(type, name, mode) + self.argumentList.append(arg) + + def docstring(self): + input = [] + output = [] + for arg in self.argumentList: + if arg.flags == ErrorMode or arg.flags == SelfMode: + continue + if arg.type == None: + str = 'void' + else: + if hasattr(arg.type, 'typeName'): + typeName = arg.type.typeName + if typeName is None: # Suppressed type + continue + else: + typeName = "?" + print "Nameless type", arg.type + + str = typeName + ' ' + arg.name + if arg.mode in (InMode, InOutMode): + input.append(str) + if arg.mode in (InOutMode, OutMode): + output.append(str) + if not input: + instr = "()" + else: + instr = "(%s)" % ", ".join(input) + if not output or output == ["void"]: + outstr = "None" + else: + outstr = "(%s)" % ", ".join(output) + return instr + " -> " + outstr + + def functionbody(self): + self.declarations() + self.precheck() + self.getargs() + self.callit() + self.checkit() + self.returnvalue() + + def declarations(self): + for arg in self.argumentList: + arg.declare() + + def getargs(self): + sep = ",\n" + ' '*len("if (!PyArg_ParseTuple(") + fmt, lst = self.getargsFormatArgs(sep) + Output("if (!PyArg_ParseTuple(_args, \"%s\"%s))", fmt, lst) + IndentLevel() + Output("return NULL;") + DedentLevel() + for arg in self.argumentList: + if arg.flags == SelfMode: + continue + if arg.mode in (InMode, InOutMode): + arg.getargsCheck() + + def getargsFormatArgs(self, sep): + fmt = "" + lst = "" + for arg in self.argumentList: + if arg.flags == SelfMode: + continue + if arg.mode in (InMode, InOutMode): + arg.getargsPreCheck() + fmt = fmt + arg.getargsFormat() + args = arg.getargsArgs() + if args: + lst = lst + sep + args + return fmt, lst + + def precheck(self): + pass + + def beginallowthreads(self): + pass + + def endallowthreads(self): + pass + + def callit(self): + args = "" + s = "%s%s(" % (self.getrvforcallit(), self.callname) + sep = ",\n" + ' '*len(s) + for arg in self.argumentList: + if arg is self.rv: + continue + s = arg.passArgument() + if args: s = sep + s + args = args + s + self.beginallowthreads() + Output("%s%s(%s);", + self.getrvforcallit(), self.callname, args) + self.endallowthreads() + + def getrvforcallit(self): + if self.rv: + return "%s = " % self.rv.name + else: + return "" + + def checkit(self): + for arg in self.argumentList: + arg.errorCheck() + + def returnvalue(self): + sep = ",\n" + ' '*len("return Py_BuildValue(") + fmt, lst = self.mkvalueFormatArgs(sep) + if fmt == "": + Output("Py_INCREF(Py_None);") + Output("_res = Py_None;"); + else: + Output("_res = Py_BuildValue(\"%s\"%s);", fmt, lst) + tmp = self.argumentList[:] + tmp.reverse() + for arg in tmp: + if not arg: continue + arg.cleanup() + Output("return _res;") + + def mkvalueFormatArgs(self, sep): + fmt = "" + lst = "" + for arg in self.argumentList: + if not arg: continue + if arg.flags == ErrorMode: continue + if arg.mode in (OutMode, InOutMode): + arg.mkvaluePreCheck() + fmt = fmt + arg.mkvalueFormat() + lst = lst + sep + arg.mkvalueArgs() + return fmt, lst + +class MethodGenerator(FunctionGenerator): + + def parseArgumentList(self, args): + a0, args = args[0], args[1:] + t0, n0, m0 = a0 + if m0 != InMode: + raise ValueError, "method's 'self' must be 'InMode'" + self.itself = Variable(t0, "_self->ob_itself", SelfMode) + self.argumentList.append(self.itself) + FunctionGenerator.parseArgumentList(self, args) + +def _test(): + void = None + eggs = FunctionGenerator(void, "eggs", + (stringptr, 'cmd', InMode), + (int, 'x', InMode), + (double, 'y', InOutMode), + (int, 'status', ErrorMode), + ) + eggs.setprefix("spam") + print "/* START */" + eggs.generate() + + +if __name__ == "__main__": + _test() diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenGeneratorGroup.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenGeneratorGroup.py new file mode 100644 index 000000000..d82ab53b6 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenGeneratorGroup.py @@ -0,0 +1,40 @@ +from bgenOutput import * + +class GeneratorGroup: + + def __init__(self, prefix): + self.prefix = prefix + self.generators = [] + + def add(self, g, dupcheck=0): + if dupcheck: + if g in self.generators: + print 'DUP', g.name + return + g.setprefix(self.prefix) + self.generators.append(g) + + def generate(self): + for g in self.generators: + g.generate() + Output() + Output("static PyMethodDef %s_methods[] = {", self.prefix) + IndentLevel() + for g in self.generators: + g.reference() + Output("{NULL, NULL, 0}") + DedentLevel() + Output("};") + + +def _test(): + void = None + from bgenGenerator import FunctionGenerator + group = GeneratorGroup("spam") + eggs = FunctionGenerator(void, "eggs") + group.add(eggs) + print "/* START */" + group.generate() + +if __name__ == "__main__": + _test() diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenHeapBuffer.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenHeapBuffer.py new file mode 100644 index 000000000..930bb7e5f --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenHeapBuffer.py @@ -0,0 +1,145 @@ +# Buffers allocated on the heap + +from bgenOutput import * +from bgenType import OutputOnlyMixIn +from bgenBuffer import FixedInputOutputBufferType + + +class HeapInputOutputBufferType(FixedInputOutputBufferType): + + """Input-output buffer allocated on the heap -- passed as (inbuffer, outbuffer, size). + + Instantiate without parameters. + Call from Python with input buffer. + """ + + def __init__(self, datatype = 'char', sizetype = 'int', sizeformat = None): + FixedInputOutputBufferType.__init__(self, "0", datatype, sizetype, sizeformat) + + def getOutputBufferDeclarations(self, name, constmode=False, outmode=False): + if constmode: + raise RuntimeError, "Cannot use const output buffer" + if outmode: + out = "*" + else: + out = "" + return ["%s%s *%s__out__" % (self.datatype, out, name)] + + def getargsCheck(self, name): + Output("if ((%s__out__ = malloc(%s__in_len__)) == NULL)", name, name) + OutLbrace() + Output('PyErr_NoMemory();') + Output("goto %s__error__;", name) + self.label_needed = 1 + OutRbrace() + Output("%s__len__ = %s__in_len__;", name, name) + + def passOutput(self, name): + return "%s__in__, %s__out__, (%s)%s__len__" % \ + (name, name, self.sizetype, name) + + def mkvalueArgs(self, name): + return "%s__out__, (int)%s__len__" % (name, name) + + def cleanup(self, name): + Output("free(%s__out__);", name) + FixedInputOutputBufferType.cleanup(self, name) + + +class VarHeapInputOutputBufferType(HeapInputOutputBufferType): + + """same as base class, but passed as (inbuffer, outbuffer, &size)""" + + def passOutput(self, name): + return "%s__in__, %s__out__, &%s__len__" % (name, name, name) + + +class HeapCombinedInputOutputBufferType(HeapInputOutputBufferType): + + """same as base class, but passed as (inoutbuffer, size)""" + + def passOutput(self, name): + return "(%s *)memcpy(%s__out__, %s__in__, %s__len__)" % \ + (self.datatype, name, name, name) + + +class VarHeapCombinedInputOutputBufferType(HeapInputOutputBufferType): + + """same as base class, but passed as (inoutbuffer, &size)""" + + def passOutput(self, name): + return "(%s *)memcpy(%s__out__, %s__in__, &%s__len__)" % \ + (self.datatype, name, name, name) + + +class HeapOutputBufferType(OutputOnlyMixIn, HeapInputOutputBufferType): + + """Output buffer allocated on the heap -- passed as (buffer, size). + + Instantiate without parameters. + Call from Python with buffer size. + """ + + def getInputBufferDeclarations(self, name, constmode=False): + return [] + + def getargsFormat(self): + return "i" + + def getargsArgs(self, name): + return "&%s__in_len__" % name + + def passOutput(self, name): + return "%s__out__, %s__len__" % (name, name) + + +class VarHeapOutputBufferType(HeapOutputBufferType): + + """Output buffer allocated on the heap -- passed as (buffer, &size). + + Instantiate without parameters. + Call from Python with buffer size. + """ + + def passOutput(self, name): + return "%s__out__, &%s__len__" % (name, name) + + +class VarVarHeapOutputBufferType(VarHeapOutputBufferType): + + """Output buffer allocated on the heap -- passed as (buffer, size, &size). + + Instantiate without parameters. + Call from Python with buffer size. + """ + + def passOutput(self, name): + return "%s__out__, %s__len__, &%s__len__" % (name, name, name) + +class MallocHeapOutputBufferType(HeapOutputBufferType): + """Output buffer allocated by the called function -- passed as (&buffer, &size). + + Instantiate without parameters. + Call from Python without parameters. + """ + + def getargsCheck(self, name): + Output("%s__out__ = NULL;", name) + + def getAuxDeclarations(self, name): + return [] + + def passOutput(self, name): + return "&%s__out__, &%s__len__" % (name, name) + + def getargsFormat(self): + return "" + + def getargsArgs(self, name): + return None + + def mkvalueFormat(self): + return "z#" + + def cleanup(self, name): + Output("if( %s__out__ ) free(%s__out__);", name, name) diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenModule.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenModule.py new file mode 100644 index 000000000..d41aa05c5 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenModule.py @@ -0,0 +1,94 @@ +from bgenOutput import * +from bgenGeneratorGroup import GeneratorGroup + +class Module(GeneratorGroup): + + def __init__(self, name, prefix = None, + includestuff = None, + finalstuff = None, + initstuff = None, + variablestuff = None, + longname = None): + GeneratorGroup.__init__(self, prefix or name) + self.name = name + if longname: + self.longname = longname + else: + self.longname = name + self.includestuff = includestuff + self.initstuff = initstuff + self.finalstuff = finalstuff + self.variablestuff = variablestuff + self.typeobjects = [] + + def addobject(self, od): + self.generators.append(od) + self.typeobjects.append(od) + od.setmodulename(self.longname) + + def generate(self): + OutHeader1("Module " + self.name) + Output("#include \"Python.h\"") + Output() + + if self.includestuff: + Output() + Output("%s", self.includestuff) + + self.declareModuleVariables() + + GeneratorGroup.generate(self) + + if self.finalstuff: + Output() + Output("%s", self.finalstuff) + + Output() + Output("void init%s(void)", self.name) + OutLbrace() + Output("PyObject *m;") + Output("PyObject *d;") + Output() + + if self.initstuff: + Output("%s", self.initstuff) + Output() + + Output("m = Py_InitModule(\"%s\", %s_methods);", + self.name, self.prefix) + Output("d = PyModule_GetDict(m);") + self.createModuleVariables() + OutRbrace() + OutHeader1("End module " + self.name) + + def declareModuleVariables(self): + self.errorname = self.prefix + "_Error" + Output("static PyObject *%s;", self.errorname) + + def createModuleVariables(self): + Output("""%s = %s;""", self.errorname, self.exceptionInitializer()) + Output("""if (%s == NULL ||""", self.errorname) + Output(""" PyDict_SetItemString(d, "Error", %s) != 0)""", + self.errorname) + IndentLevel() + Output("""return;""") + DedentLevel() + for tp in self.typeobjects: + tp.outputTypeObjectInitializer() + if self.variablestuff: + Output("%s", self.variablestuff) + Output() + + def exceptionInitializer(self): + return """PyErr_NewException("%s.Error", NULL, NULL)""" % self.name + + +def _test(): + from bgenGenerator import FunctionGenerator + m = Module("spam", "", "#include <stdio.h>") + g = FunctionGenerator(None, "bacon") + m.add(g) + m.generate() + +if __name__ == "__main__": + _test() diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenObjectDefinition.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenObjectDefinition.py new file mode 100644 index 000000000..6f9bd5300 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenObjectDefinition.py @@ -0,0 +1,512 @@ +from bgenOutput import * +from bgenGeneratorGroup import GeneratorGroup + +class ObjectDefinition(GeneratorGroup): + "Spit out code that together defines a new Python object type" + basechain = "NULL" + tp_flags = "Py_TPFLAGS_DEFAULT" + basetype = None + argref = "" # set to "*" if arg to <type>_New should be pointer + argconst = "" # set to "const " if arg to <type>_New should be const + + def __init__(self, name, prefix, itselftype): + """ObjectDefinition constructor. May be extended, but do not override. + + - name: the object's official name, e.g. 'SndChannel'. + - prefix: the prefix used for the object's functions and data, e.g. 'SndCh'. + - itselftype: the C type actually contained in the object, e.g. 'SndChannelPtr'. + + XXX For official Python data types, rules for the 'Py' prefix are a problem. + """ + + GeneratorGroup.__init__(self, prefix or name) + self.name = name + self.itselftype = itselftype + self.objecttype = name + 'Object' + self.typename = name + '_Type' + self.static = "static " # set to "" to make <type>_New and <type>_Convert public + self.modulename = None + if hasattr(self, "assertions"): + self.assertions() + + def add(self, g, dupcheck=0): + g.setselftype(self.objecttype, self.itselftype) + GeneratorGroup.add(self, g, dupcheck) + + def reference(self): + # In case we are referenced from a module + pass + + def setmodulename(self, name): + self.modulename = name + + def generate(self): + # XXX This should use long strings and %(varname)s substitution! + + OutHeader2("Object type " + self.name) + + self.outputCheck() + + Output("typedef struct %s {", self.objecttype) + IndentLevel() + Output("PyObject_HEAD") + self.outputStructMembers() + DedentLevel() + Output("} %s;", self.objecttype) + + self.outputNew() + + self.outputConvert() + + self.outputDealloc() + + GeneratorGroup.generate(self) + + Output() + self.outputMethodChain() + + self.outputGetattr() + + self.outputSetattr() + + self.outputCompare() + + self.outputRepr() + + self.outputHash() + + self.outputPEP253Hooks() + + self.outputTypeObject() + + OutHeader2("End object type " + self.name) + + def outputCheck(self): + sf = self.static and "static " + Output("%sPyTypeObject %s;", sf, self.typename) + Output() + Output("#define %s_Check(x) ((x)->ob_type == &%s || PyObject_TypeCheck((x), &%s))", + self.prefix, self.typename, self.typename) + Output() + + def outputMethodChain(self): + Output("%sPyMethodChain %s_chain = { %s_methods, %s };", + self.static, self.prefix, self.prefix, self.basechain) + + def outputStructMembers(self): + Output("%s ob_itself;", self.itselftype) + + def outputNew(self): + Output() + Output("%sPyObject *%s_New(%s%s %sitself)", self.static, self.prefix, + self.argconst, self.itselftype, self.argref) + OutLbrace() + Output("%s *it;", self.objecttype) + self.outputCheckNewArg() + Output("it = PyObject_NEW(%s, &%s);", self.objecttype, self.typename) + Output("if (it == NULL) return NULL;") + if self.basetype: + Output("/* XXXX Should we tp_init or tp_new our basetype? */") + self.outputInitStructMembers() + Output("return (PyObject *)it;") + OutRbrace() + + def outputInitStructMembers(self): + Output("it->ob_itself = %sitself;", self.argref) + + def outputCheckNewArg(self): + "Override this method to apply additional checks/conversions" + + def outputConvert(self): + Output() + Output("%sint %s_Convert(PyObject *v, %s *p_itself)", self.static, self.prefix, + self.itselftype) + OutLbrace() + self.outputCheckConvertArg() + Output("if (!%s_Check(v))", self.prefix) + OutLbrace() + Output('PyErr_SetString(PyExc_TypeError, "%s required");', self.name) + Output("return 0;") + OutRbrace() + Output("*p_itself = ((%s *)v)->ob_itself;", self.objecttype) + Output("return 1;") + OutRbrace() + + def outputCheckConvertArg(self): + "Override this method to apply additional conversions" + + def outputDealloc(self): + Output() + Output("static void %s_dealloc(%s *self)", self.prefix, self.objecttype) + OutLbrace() + self.outputCleanupStructMembers() + if self.basetype: + Output("%s.tp_dealloc((PyObject *)self);", self.basetype) + elif hasattr(self, 'output_tp_free'): + # This is a new-style object with tp_free slot + Output("self->ob_type->tp_free((PyObject *)self);") + else: + Output("PyObject_Free((PyObject *)self);") + OutRbrace() + + def outputCleanupStructMembers(self): + self.outputFreeIt("self->ob_itself") + + def outputFreeIt(self, name): + Output("/* Cleanup of %s goes here */", name) + + def outputGetattr(self): + Output() + Output("static PyObject *%s_getattr(%s *self, char *name)", self.prefix, self.objecttype) + OutLbrace() + self.outputGetattrBody() + OutRbrace() + + def outputGetattrBody(self): + self.outputGetattrHook() + Output("return Py_FindMethodInChain(&%s_chain, (PyObject *)self, name);", + self.prefix) + + def outputGetattrHook(self): + pass + + def outputSetattr(self): + Output() + Output("#define %s_setattr NULL", self.prefix) + + def outputCompare(self): + Output() + Output("#define %s_compare NULL", self.prefix) + + def outputRepr(self): + Output() + Output("#define %s_repr NULL", self.prefix) + + def outputHash(self): + Output() + Output("#define %s_hash NULL", self.prefix) + + def outputTypeObject(self): + sf = self.static and "static " + Output() + Output("%sPyTypeObject %s = {", sf, self.typename) + IndentLevel() + Output("PyObject_HEAD_INIT(NULL)") + Output("0, /*ob_size*/") + if self.modulename: + Output("\"%s.%s\", /*tp_name*/", self.modulename, self.name) + else: + Output("\"%s\", /*tp_name*/", self.name) + Output("sizeof(%s), /*tp_basicsize*/", self.objecttype) + Output("0, /*tp_itemsize*/") + Output("/* methods */") + Output("(destructor) %s_dealloc, /*tp_dealloc*/", self.prefix) + Output("0, /*tp_print*/") + Output("(getattrfunc) %s_getattr, /*tp_getattr*/", self.prefix) + Output("(setattrfunc) %s_setattr, /*tp_setattr*/", self.prefix) + Output("(cmpfunc) %s_compare, /*tp_compare*/", self.prefix) + Output("(reprfunc) %s_repr, /*tp_repr*/", self.prefix) + Output("(PyNumberMethods *)0, /* tp_as_number */") + Output("(PySequenceMethods *)0, /* tp_as_sequence */") + Output("(PyMappingMethods *)0, /* tp_as_mapping */") + Output("(hashfunc) %s_hash, /*tp_hash*/", self.prefix) + DedentLevel() + Output("};") + + def outputTypeObjectInitializer(self): + Output("""%s.ob_type = &PyType_Type;""", self.typename) + if self.basetype: + Output("%s.tp_base = &%s;", self.typename, self.basetype) + Output("if (PyType_Ready(&%s) < 0) return;", self.typename) + Output("""Py_INCREF(&%s);""", self.typename) + Output("PyModule_AddObject(m, \"%s\", (PyObject *)&%s);", self.name, self.typename); + self.outputTypeObjectInitializerCompat() + + def outputTypeObjectInitializerCompat(self): + Output("/* Backward-compatible name */") + Output("""Py_INCREF(&%s);""", self.typename); + Output("PyModule_AddObject(m, \"%sType\", (PyObject *)&%s);", self.name, self.typename); + + def outputPEP253Hooks(self): + pass + +class PEP252Mixin: + getsetlist = [] + + def assertions(self): + # Check that various things aren't overridden. If they are it could + # signify a bgen-client that has been partially converted to PEP252. + assert self.outputGetattr.im_func == PEP252Mixin.outputGetattr.im_func + assert self.outputSetattr.im_func == PEP252Mixin.outputSetattr.im_func + assert self.outputGetattrBody == None + assert self.outputGetattrHook == None + assert self.basechain == "NULL" + + def outputGetattr(self): + pass + + outputGetattrBody = None + + outputGetattrHook = None + + def outputSetattr(self): + pass + + def outputMethodChain(self): + # This is a good place to output the getters and setters + self.outputGetSetList() + + def outputHook(self, name): + methodname = "outputHook_" + name + if hasattr(self, methodname): + func = getattr(self, methodname) + func() + else: + Output("0, /*%s*/", name) + + def outputTypeObject(self): + sf = self.static and "static " + Output() + Output("%sPyTypeObject %s = {", sf, self.typename) + IndentLevel() + Output("PyObject_HEAD_INIT(NULL)") + Output("0, /*ob_size*/") + if self.modulename: + Output("\"%s.%s\", /*tp_name*/", self.modulename, self.name) + else: + Output("\"%s\", /*tp_name*/", self.name) + Output("sizeof(%s), /*tp_basicsize*/", self.objecttype) + Output("0, /*tp_itemsize*/") + + Output("/* methods */") + Output("(destructor) %s_dealloc, /*tp_dealloc*/", self.prefix) + Output("0, /*tp_print*/") + Output("(getattrfunc)0, /*tp_getattr*/") + Output("(setattrfunc)0, /*tp_setattr*/") + Output("(cmpfunc) %s_compare, /*tp_compare*/", self.prefix) + Output("(reprfunc) %s_repr, /*tp_repr*/", self.prefix) + + Output("(PyNumberMethods *)0, /* tp_as_number */") + Output("(PySequenceMethods *)0, /* tp_as_sequence */") + Output("(PyMappingMethods *)0, /* tp_as_mapping */") + + Output("(hashfunc) %s_hash, /*tp_hash*/", self.prefix) + self.outputHook("tp_call") + Output("0, /*tp_str*/") + Output("PyObject_GenericGetAttr, /*tp_getattro*/") + Output("PyObject_GenericSetAttr, /*tp_setattro */") + + self.outputHook("tp_as_buffer") + Output("%s, /* tp_flags */", self.tp_flags) + self.outputHook("tp_doc") + self.outputHook("tp_traverse") + self.outputHook("tp_clear") + self.outputHook("tp_richcompare") + self.outputHook("tp_weaklistoffset") + self.outputHook("tp_iter") + self.outputHook("tp_iternext") + Output("%s_methods, /* tp_methods */", self.prefix) + self.outputHook("tp_members") + Output("%s_getsetlist, /*tp_getset*/", self.prefix) + self.outputHook("tp_base") + self.outputHook("tp_dict") + self.outputHook("tp_descr_get") + self.outputHook("tp_descr_set") + self.outputHook("tp_dictoffset") + self.outputHook("tp_init") + self.outputHook("tp_alloc") + self.outputHook("tp_new") + self.outputHook("tp_free") + DedentLevel() + Output("};") + + def outputGetSetList(self): + if self.getsetlist: + for name, get, set, doc in self.getsetlist: + if get: + self.outputGetter(name, get) + else: + Output("#define %s_get_%s NULL", self.prefix, name) + Output() + if set: + self.outputSetter(name, set) + else: + Output("#define %s_set_%s NULL", self.prefix, name) + Output() + + Output("static PyGetSetDef %s_getsetlist[] = {", self.prefix) + IndentLevel() + for name, get, set, doc in self.getsetlist: + if doc: + doc = '"' + doc + '"' + else: + doc = "NULL" + Output("{\"%s\", (getter)%s_get_%s, (setter)%s_set_%s, %s},", + name, self.prefix, name, self.prefix, name, doc) + Output("{NULL, NULL, NULL, NULL},") + DedentLevel() + Output("};") + else: + Output("#define %s_getsetlist NULL", self.prefix) + Output() + + def outputGetter(self, name, code): + Output("static PyObject *%s_get_%s(%s *self, void *closure)", + self.prefix, name, self.objecttype) + OutLbrace() + Output(code) + OutRbrace() + Output() + + def outputSetter(self, name, code): + Output("static int %s_set_%s(%s *self, PyObject *v, void *closure)", + self.prefix, name, self.objecttype) + OutLbrace() + Output(code) + Output("return 0;") + OutRbrace() + Output() + +class PEP253Mixin(PEP252Mixin): + tp_flags = "Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE" + + def outputHook_tp_init(self): + Output("%s_tp_init, /* tp_init */", self.prefix) + + def outputHook_tp_alloc(self): + Output("%s_tp_alloc, /* tp_alloc */", self.prefix) + + def outputHook_tp_new(self): + Output("%s_tp_new, /* tp_new */", self.prefix) + + def outputHook_tp_free(self): + Output("%s_tp_free, /* tp_free */", self.prefix) + + def output_tp_initBody_basecall(self): + """If a type shares its init call with its base type set output_tp_initBody + to output_tp_initBody_basecall""" + if self.basetype: + Output("if (%s.tp_init)", self.basetype) + OutLbrace() + Output("if ( (*%s.tp_init)(_self, _args, _kwds) < 0) return -1;", self.basetype) + OutRbrace() + + output_tp_initBody = None + + def output_tp_init(self): + if self.output_tp_initBody: + Output("static int %s_tp_init(PyObject *_self, PyObject *_args, PyObject *_kwds)", self.prefix) + OutLbrace() + self.output_tp_initBody() + OutRbrace() + else: + Output("#define %s_tp_init 0", self.prefix) + Output() + + output_tp_allocBody = None + + def output_tp_alloc(self): + if self.output_tp_allocBody: + Output("static PyObject *%s_tp_alloc(PyTypeObject *type, int nitems)", + self.prefix) + OutLbrace() + self.output_tp_allocBody() + OutRbrace() + else: + Output("#define %s_tp_alloc PyType_GenericAlloc", self.prefix) + Output() + + def output_tp_newBody(self): + Output("PyObject *_self;"); + Output("%s itself;", self.itselftype); + Output("char *kw[] = {\"itself\", 0};") + Output() + Output("if (!PyArg_ParseTupleAndKeywords(_args, _kwds, \"O&\", kw, %s_Convert, &itself)) return NULL;", + self.prefix); + if self.basetype: + Output("if (%s.tp_new)", self.basetype) + OutLbrace() + Output("if ( (*%s.tp_new)(type, _args, _kwds) == NULL) return NULL;", self.basetype) + Dedent() + Output("} else {") + Indent() + Output("if ((_self = type->tp_alloc(type, 0)) == NULL) return NULL;") + OutRbrace() + else: + Output("if ((_self = type->tp_alloc(type, 0)) == NULL) return NULL;") + Output("((%s *)_self)->ob_itself = itself;", self.objecttype) + Output("return _self;") + + def output_tp_new(self): + if self.output_tp_newBody: + Output("static PyObject *%s_tp_new(PyTypeObject *type, PyObject *_args, PyObject *_kwds)", self.prefix) + OutLbrace() + self.output_tp_newBody() + OutRbrace() + else: + Output("#define %s_tp_new PyType_GenericNew", self.prefix) + Output() + + output_tp_freeBody = None + + def output_tp_free(self): + if self.output_tp_freeBody: + Output("static void %s_tp_free(PyObject *self)", self.prefix) + OutLbrace() + self.output_tp_freeBody() + OutRbrace() + else: + Output("#define %s_tp_free PyObject_Del", self.prefix) + Output() + + def outputPEP253Hooks(self): + self.output_tp_init() + self.output_tp_alloc() + self.output_tp_new() + self.output_tp_free() + +class GlobalObjectDefinition(ObjectDefinition): + """Like ObjectDefinition but exports some parts. + + XXX Should also somehow generate a .h file for them. + """ + + def __init__(self, name, prefix = None, itselftype = None): + ObjectDefinition.__init__(self, name, prefix or name, itselftype or name) + self.static = "" + +class ObjectIdentityMixin: + """A mixin class for objects that makes the identity of ob_itself + govern comparisons and dictionary lookups. Useful if the C object can + be returned by library calls and it is difficult (or impossible) to find + the corresponding Python objects. With this you can create Python object + wrappers on the fly""" + + def outputCompare(self): + Output() + Output("static int %s_compare(%s *self, %s *other)", self.prefix, self.objecttype, + self.objecttype) + OutLbrace() + Output("unsigned long v, w;") + Output() + Output("if (!%s_Check((PyObject *)other))", self.prefix) + OutLbrace() + Output("v=(unsigned long)self;") + Output("w=(unsigned long)other;") + OutRbrace() + Output("else") + OutLbrace() + Output("v=(unsigned long)self->ob_itself;") + Output("w=(unsigned long)other->ob_itself;") + OutRbrace() + Output("if( v < w ) return -1;") + Output("if( v > w ) return 1;") + Output("return 0;") + OutRbrace() + + def outputHash(self): + Output() + Output("static long %s_hash(%s *self)", self.prefix, self.objecttype) + OutLbrace() + Output("return (long)self->ob_itself;") + OutRbrace() diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenOutput.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenOutput.py new file mode 100644 index 000000000..53d4f55f1 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenOutput.py @@ -0,0 +1,219 @@ +"""Output primitives for the binding generator classes. + +This should really be a class, but then everybody would be passing +the output object to each other. I chose for the simpler approach +of a module with a global variable. Use SetOutputFile() or +SetOutputFileName() to change the output file. +""" + +_NeedClose = 0 + +def SetOutputFile(file = None, needclose = 0): + """Call this with an open file object to make it the output file. + + Call it without arguments to close the current file (if necessary) + and reset it to sys.stdout. + If the second argument is true, the new file will be explicitly closed + on a subsequence call. + """ + global _File, _NeedClose + if _NeedClose: + tmp = _File + _NeedClose = 0 + _File = None + tmp.close() + if file is None: + import sys + file = sys.stdout + _File = file + _NeedClose = file and needclose + +def SetOutputFileName(filename = None): + """Call this with a filename to make it the output file. + + Call it without arguments to close the current file (if necessary) + and reset it to sys.stdout. + """ + SetOutputFile() + if filename: + SetOutputFile(open(filename, 'w'), 1) + +SetOutputFile() # Initialize _File + +_Level = 0 # Indentation level + +def GetLevel(): + """Return the current indentation level.""" + return _Level + +def SetLevel(level): + """Set the current indentation level. + + This does no type or range checking -- use at own risk. + """ + global _Level + _Level = level + +def Output(format = "", *args): + VaOutput(format, args) + +def VaOutput(format, args): + """Call this with a format string and argument tuple for the format. + + A newline is always added. Each line in the output is indented + to the proper indentation level -- even if the result of the + format expansion contains embedded newlines. Exception: lines + beginning with '#' are not indented -- these are assumed to be + C preprprocessor lines. + """ + text = format % args + if _Level > 0: + indent = '\t' * _Level + lines = text.split('\n') + for i in range(len(lines)): + if lines[i] and lines[i][0] != '#': + lines[i] = indent + lines[i] + text = '\n'.join(lines) + _File.write(text + '\n') + +def IndentLevel(by = 1): + """Increment the indentation level by one. + + When called with an argument, adds it to the indentation level. + """ + global _Level + if _Level+by < 0: + raise Error, "indentation underflow (internal error)" + _Level = _Level + by + +def DedentLevel(by = 1): + """Decrement the indentation level by one. + + When called with an argument, subtracts it from the indentation level. + """ + IndentLevel(-by) + +def OutIndent(format = "", *args): + """Combine Output() followed by IndentLevel(). + + If no text is given, acts like lone IndentLevel(). + """ + if format: VaOutput(format, args) + IndentLevel() + +def OutDedent(format = "", *args): + """Combine Output() followed by DedentLevel(). + + If no text is given, acts like loneDedentLevel(). + """ + if format: VaOutput(format, args) + DedentLevel() + +def OutLbrace(format = "", *args): + """Like Output, but add a '{' and increase the indentation level. + + If no text is given a lone '{' is output. + """ + if format: + format = format + " {" + else: + format = "{" + VaOutput(format, args) + IndentLevel() + +def OutRbrace(): + """Decrease the indentation level and output a '}' on a line by itself.""" + DedentLevel() + Output("}") + +def OutHeader(text, dash): + """Output a header comment using a given dash character.""" + n = 64 - len(text) + Output() + Output("/* %s %s %s */", dash * (n/2), text, dash * (n - n/2)) + Output() + +def OutHeader1(text): + """Output a level 1 header comment (uses '=' dashes).""" + OutHeader(text, "=") + +def OutHeader2(text): + """Output a level 2 header comment (uses '-' dashes).""" + OutHeader(text, "-") + +def Out(text): + """Output multiline text that's internally indented. + + Pass this a multiline character string. The whitespace before the + first nonblank line of the string will be subtracted from all lines. + The lines are then output using Output(), but without interpretation + of formatting (if you need formatting you can do it before the call). + Recommended use: + + Out(''' + int main(argc, argv) + int argc; + char *argv; + { + printf("Hello, world\\n"); + exit(0); + } + ''') + + Caveat: the indentation must be consistent -- if you use three tabs + in the first line, (up to) three tabs are removed from following lines, + but a line beginning with 24 spaces is not trimmed at all. Don't use + this as a feature. + """ + # (Don't you love using triple quotes *inside* triple quotes? :-) + + lines = text.split('\n') + indent = "" + for line in lines: + if line.strip(): + for c in line: + if not c.isspace(): + break + indent = indent + c + break + n = len(indent) + for line in lines: + if line[:n] == indent: + line = line[n:] + else: + for c in indent: + if line[:1] <> c: break + line = line[1:] + VaOutput("%s", line) + + +def _test(): + """Test program. Run when the module is run as a script.""" + OutHeader1("test bgenOutput") + Out(""" + #include <Python.h> + #include <stdio.h> + + main(argc, argv) + int argc; + char **argv; + { + int i; + """) + IndentLevel() + Output("""\ +/* Here are a few comment lines. + Just to test indenting multiple lines. + + End of the comment lines. */ +""") + Output("for (i = 0; i < argc; i++)") + OutLbrace() + Output('printf("argv[%%d] = %%s\\n", i, argv[i]);') + OutRbrace() + Output("exit(0)") + OutRbrace() + OutHeader2("end test") + +if __name__ == '__main__': + _test() diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenStackBuffer.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenStackBuffer.py new file mode 100644 index 000000000..431bb73be --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenStackBuffer.py @@ -0,0 +1,62 @@ +"""Buffers allocated on the stack.""" + + +from bgenBuffer import FixedInputBufferType, FixedOutputBufferType + + +class StackOutputBufferType(FixedOutputBufferType): + + """Fixed output buffer allocated on the stack -- passed as (buffer, size). + + Instantiate with the buffer size as parameter. + """ + + def passOutput(self, name): + return "%s__out__, %s" % (name, self.size) + + +class VarStackOutputBufferType(StackOutputBufferType): + + """Output buffer allocated on the stack -- passed as (buffer, &size). + + Instantiate with the buffer size as parameter. + """ + + def getSizeDeclarations(self, name): + return [] + + def getAuxDeclarations(self, name): + return ["int %s__len__ = %s" % (name, self.size)] + + def passOutput(self, name): + return "%s__out__, &%s__len__" % (name, name) + + def mkvalueArgs(self, name): + return "%s__out__, (int)%s__len__" % (name, name) + + +class VarVarStackOutputBufferType(VarStackOutputBufferType): + + """Output buffer allocated on the stack -- passed as (buffer, size, &size). + + Instantiate with the buffer size as parameter. + """ + + def passOutput(self, name): + return "%s__out__, %s__len__, &%s__len__" % (name, name, name) + + +class ReturnVarStackOutputBufferType(VarStackOutputBufferType): + + """Output buffer allocated on the stack -- passed as (buffer, size) -> size. + + Instantiate with the buffer size as parameter. + The function's return value is the size. + (XXX Should have a way to suppress returning it separately, too.) + """ + + def passOutput(self, name): + return "%s__out__, %s__len__" % (name, name) + + def mkvalueArgs(self, name): + return "%s__out__, (int)_rv" % name diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenStringBuffer.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenStringBuffer.py new file mode 100644 index 000000000..a232f83d2 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenStringBuffer.py @@ -0,0 +1,67 @@ +"""Buffers used to hold null-terminated strings.""" + + +from bgenBuffer import FixedOutputBufferType +from bgenStackBuffer import StackOutputBufferType +from bgenHeapBuffer import HeapOutputBufferType + + +class StringBufferMixIn: + + """Mix-in class to create various string buffer types. + + Strings are character arrays terminated by a null byte. + (For input, this is also covered by stringptr.) + For output, there are again three variants: + - Fixed: size is a constant given in the documentation; or + - Stack: size is passed to the C function but we decide on a size at + code generation time so we can still allocate on the heap); or + - Heap: size is passed to the C function and we let the Python caller + pass a size. + (Note that this doesn't cover output parameters in which a string + pointer is returned. These are actually easier (no allocation) but far + less common. I'll write the classes when there is demand.) + """ + + def getSizeDeclarations(self, name): + return [] + + def getAuxDeclarations(self, name): + return [] + + def getargsFormat(self): + return "s" + + def getargsArgs(self, name): + return "&%s__in__" % name + + def mkvalueFormat(self): + return "s" + + def mkvalueArgs(self, name): + return "%s__out__" % name + + +class FixedOutputStringType(StringBufferMixIn, FixedOutputBufferType): + + """Null-terminated output string -- passed without size. + + Instantiate with buffer size as parameter. + """ + + +class StackOutputStringType(StringBufferMixIn, StackOutputBufferType): + + """Null-terminated output string -- passed as (buffer, size). + + Instantiate with buffer size as parameter. + """ + + +class HeapOutputStringType(StringBufferMixIn, HeapOutputBufferType): + + """Null-terminated output string -- passed as (buffer, size). + + Instantiate without parameters. + Call from Python with buffer size. + """ diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenType.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenType.py new file mode 100644 index 000000000..c988700cb --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenType.py @@ -0,0 +1,328 @@ +"""Type classes and a modest collection of standard types.""" + + +from bgenOutput import * + + +class Type: + + """Define the various things you can do with a C type. + + Most methods are intended to be extended or overridden. + """ + + def __init__(self, typeName, fmt): + """Call with the C name and getargs format for the type. + + Example: int = Type("int", "i") + """ + self.typeName = typeName + self.fmt = fmt + + def declare(self, name, reference=False): + """Declare a variable of the type with a given name. + + Example: int.declare('spam') prints "int spam;" + """ + for decl in self.getArgDeclarations(name, reference): + Output("%s;", decl) + for decl in self.getAuxDeclarations(name): + Output("%s;", decl) + + def getArgDeclarations(self, name, reference=False, constmode=False, outmode=False): + """Return the main part of the declarations for this type: the items + that will be passed as arguments in the C/C++ function call.""" + if reference: + ref = "&" + else: + ref = "" + if constmode: + const = "const " + else: + const = "" + if outmode: + out = "*" + else: + out = "" + return ["%s%s%s%s %s" % (const, self.typeName, ref, out, name)] + + def getAuxDeclarations(self, name): + """Return any auxiliary declarations needed for implementing this + type, such as helper variables used to hold sizes, etc. These declarations + are not part of the C/C++ function call interface.""" + return [] + + def getargs(self): + return self.getargsFormat(), self.getargsArgs() + + def getargsFormat(self): + """Return the format for this type for use with PyArg_Parse(). + + Example: int.getargsFormat() returns the string "i". + (getargs is a very old name for PyArg_Parse, hence the name of this method). + """ + return self.fmt + + def getargsArgs(self, name): + """Return an argument for use with PyArg_Parse(). + + Example: int.getargsArgs("spam") returns the string "&spam". + """ + return "&" + name + + def getargsPreCheck(self, name): + """Perform any actions needed before calling getargs(). + + This could include declaring temporary variables and such. + """ + + def getargsCheck(self, name): + """Perform any needed post-[new]getargs() checks. + + This is type-dependent; the default does not check for errors. + An example would be a check for a maximum string length, or it + could do post-getargs() copying or conversion.""" + + def passInput(self, name): + """Return an argument for passing a variable into a call. + + Example: int.passInput("spam") returns the string "spam". + """ + return name + + def passOutput(self, name): + """Return an argument for returning a variable out of a call. + + Example: int.passOutput("spam") returns the string "&spam". + """ + return "&" + name + + def passReference(self, name): + """Return an argument for C++ pass-by-reference. + Default is to call passInput(). + """ + return self.passInput(name) + + def errorCheck(self, name): + """Check for an error returned in the variable. + + This is type-dependent; the default does not check for errors. + An example would be a check for a NULL pointer. + If an error is found, the generated routine should + raise an exception and return NULL. + + XXX There should be a way to add error clean-up code. + """ + Output("/* XXX no err check for %s %s */", self.typeName, name) + + def mkvalue(self): + return self.mkvalueFormat(), self.mkvalueArgs() + + def mkvalueFormat(self): + """Return the format for this type for use with Py_BuildValue(). + + This is normally the same as getargsFormat() but it is + a separate function to allow future divergence. + (mkvalue is a very old name for Py_BuildValue, hence the name of this + method). + """ + return self.getargsFormat() + + def mkvalueArgs(self, name): + """Return an argument for use with Py_BuildValue(). + + Example: int.mkvalueArgs("spam") returns the string "spam". + """ + return name + + def mkvaluePreCheck(self, name): + """Perform any actions needed before calling mkvalue(). + + This could include declaring temporary variables and such. + """ + + def cleanup(self, name): + """Clean up if necessary. + + This is normally empty; it may deallocate buffers etc. + """ + pass + +class ByAddressType(Type): + "Simple type that is also passed by address for input" + + def passInput(self, name): + return "&%s" % name + + + +# Sometimes it's useful to define a type that's only usable as input or output parameter + +class InputOnlyMixIn: + + "Mix-in class to boobytrap passOutput" + + def passOutput(self, name): + raise RuntimeError, "Type '%s' can only be used for input parameters" % self.typeName + +class InputOnlyType(InputOnlyMixIn, Type): + + "Same as Type, but only usable for input parameters -- passOutput is boobytrapped" + +class OutputOnlyMixIn: + + "Mix-in class to boobytrap passInput" + + def passInput(self, name): + raise RuntimeError, "Type '%s' can only be used for output parameters" % self.typeName + +class OutputOnlyType(OutputOnlyMixIn, Type): + + "Same as Type, but only usable for output parameters -- passInput is boobytrapped" + + +# A modest collection of standard C types. +void = None +char = Type("char", "c") +short = Type("short", "h") +unsigned_short = Type("unsigned short", "H") +int = Type("int", "i") +long = Type("long", "l") +unsigned_long = Type("unsigned long", "l") +float = Type("float", "f") +double = Type("double", "d") + + +# The most common use of character pointers is a null-terminated string. +# For input, this is easy. For output, and for other uses of char *, +# see the module bgenBuffer. +stringptr = InputOnlyType("char*", "s") +unicodestringptr = InputOnlyType("wchar_t *", "u") + + +# Some Python related types. +objectptr = Type("PyObject*", "O") +stringobjectptr = Type("PyStringObject*", "S") +# Etc. + + +class FakeType(InputOnlyType): + + """A type that is not represented in the Python version of the interface. + + Instantiate with a value to pass in the call. + """ + + def __init__(self, substitute): + self.substitute = substitute + self.typeName = None # Don't show this argument in __doc__ string + + def getArgDeclarations(self, name, reference=False, constmode=False, outmode=False): + return [] + + def getAuxDeclarations(self, name, reference=False): + return [] + + def getargsFormat(self): + return "" + + def getargsArgs(self, name): + return None + + def passInput(self, name): + return self.substitute + + +class OpaqueType(Type): + + """A type represented by an opaque object type, always passed by address. + + Instantiate with the type name and the names of the new and convert procs. + If fewer than three arguments are passed, the second argument is used + to derive the new and convert procs by appending _New and _Convert; it + defaults to the first argument. + """ + + def __init__(self, name, arg = None, extra = None): + self.typeName = name + if extra is None: + # Two arguments (name, usetype) or one (name) + arg = arg or name + self.new = arg + '_New' + self.convert = arg + '_Convert' + else: + # Three arguments (name, new, convert) + self.new = arg + self.convert = extra + + def getargsFormat(self): + return "O&" + + def getargsArgs(self, name): + return "%s, &%s" % (self.convert, name) + + def passInput(self, name): + return "&%s" % name + + def mkvalueFormat(self): + return "O&" + + def mkvalueArgs(self, name): + return "%s, &%s" % (self.new, name) + + +class OpaqueByValueType(OpaqueType): + + """A type represented by an opaque object type, on input passed BY VALUE. + + Instantiate with the type name, and optionally an object type name whose + New/Convert functions will be used. + """ + + def passInput(self, name): + return name + + def mkvalueArgs(self, name): + return "%s, %s" % (self.new, name) + +class OpaqueByRefType(OpaqueType): + """An opaque object type, passed by reference. + + Instantiate with the type name, and optionally an object type name whose + New/Convert functions will be used. + """ + + def passInput(self, name): + return name + +# def passOutput(self, name): +# return name + + def mkvalueFormat(self): + return "O" + + def mkvalueArgs(self, name): + return "%s(%s)" % (self.new, name) + +class OpaqueByValueStructType(OpaqueByValueType): + """Similar to OpaqueByValueType, but we also pass this to mkvalue by + address, in stead of by value. + """ + + def mkvalueArgs(self, name): + return "%s, &%s" % (self.new, name) + + +class OpaqueArrayType(OpaqueByValueType): + + """A type represented by an opaque object type, with ARRAY passing semantics. + + Instantiate with the type name, and optional an object type name whose + New/Convert functions will be used. + """ + + def getargsArgs(self, name): + return "%s, %s" % (self.convert, name) + + def passOutput(self, name): + return name diff --git a/sys/src/cmd/python/Tools/bgen/bgen/bgenVariable.py b/sys/src/cmd/python/Tools/bgen/bgen/bgenVariable.py new file mode 100644 index 000000000..0ad24b346 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/bgenVariable.py @@ -0,0 +1,112 @@ +"""Variables, arguments and argument transfer modes etc.""" + + +# Values to represent argument transfer modes +InMode = 1 # input-only argument +OutMode = 2 # output-only argument +InOutMode = 3 # input-output argument +ModeMask = 3 # bits to keep for mode + + +# Special cases for mode/flags argument +# XXX This is still a mess! +SelfMode = 4+InMode # this is 'self' -- don't declare it +ReturnMode = 8+OutMode # this is the function return value +ErrorMode = 16+OutMode # this is an error status -- turn it into an exception +RefMode = 32 +ConstMode = 64 + +class Variable: + + """A Variable holds a type, a name, a transfer mode and flags. + + Most of its methods call the correponding type method with the + variable name. + """ + + def __init__(self, type, name = None, flags = InMode): + """Call with a type, a name and flags. + + If name is None, it muse be set later. + flags defaults to InMode. + """ + self.type = type + self.name = name + self.flags = flags + self.mode = flags & ModeMask + + def declare(self): + """Declare the variable if necessary. + + If it is "self", it is not declared. + """ + if self.flags == ReturnMode+RefMode: + self.type.declare(self.name, reference=True) + elif self.flags != SelfMode: + self.type.declare(self.name) + + def getArgDeclarations(self, fullmodes=False): + refmode = (self.flags & RefMode) + constmode = False + outmode = False + if fullmodes: + constmode = (self.flags & ConstMode) + outmode = (self.flags & OutMode) + return self.type.getArgDeclarations(self.name, + reference=refmode, constmode=constmode, outmode=outmode) + + def getAuxDeclarations(self): + return self.type.getAuxDeclarations(self.name) + + def getargsFormat(self): + """Call the type's getargsFormatmethod.""" + return self.type.getargsFormat() + + def getargsArgs(self): + """Call the type's getargsArgsmethod.""" + return self.type.getargsArgs(self.name) + + def getargsCheck(self): + return self.type.getargsCheck(self.name) + + def getargsPreCheck(self): + return self.type.getargsPreCheck(self.name) + + def passArgument(self): + """Return the string required to pass the variable as argument. + + For "in" arguments, return the variable name. + For "out" and "in out" arguments, + return its name prefixed with "&". + """ + if self.mode == InMode: + return self.type.passInput(self.name) + if self.mode & RefMode: + return self.type.passReference(self.name) + if self.mode in (OutMode, InOutMode): + return self.type.passOutput(self.name) + # XXX Shouldn't get here + return "/*mode?*/" + self.type.passInput(self.name) + + def errorCheck(self): + """Check for an error if necessary. + + This only generates code if the variable's mode is ErrorMode. + """ + if self.flags == ErrorMode: + self.type.errorCheck(self.name) + + def mkvalueFormat (self): + """Call the type's mkvalueFormat method.""" + return self.type.mkvalueFormat() + + def mkvalueArgs(self): + """Call the type's mkvalueArgs method.""" + return self.type.mkvalueArgs(self.name) + + def mkvaluePreCheck(self): + return self.type.mkvaluePreCheck(self.name) + + def cleanup(self): + """Call the type's cleanup method.""" + return self.type.cleanup(self.name) diff --git a/sys/src/cmd/python/Tools/bgen/bgen/macsupport.py b/sys/src/cmd/python/Tools/bgen/bgen/macsupport.py new file mode 100644 index 000000000..7cd2b81da --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/macsupport.py @@ -0,0 +1,197 @@ +"""\ +Augment the "bgen" package with definitions that are useful on the Apple Macintosh. + +Intended usage is "from macsupport import *" -- this implies all bgen's goodies. +""" + + +# Import everything from bgen (for ourselves as well as for re-export) +from bgen import * + + +# Simple types +Boolean = Type("Boolean", "b") +SignedByte = Type("SignedByte", "b") +Size = Type("Size", "l") +Style = Type("Style", "b") +StyleParameter = Type("StyleParameter", "h") +CharParameter = Type("CharParameter", "h") +TextEncoding = Type("TextEncoding", "l") +ByteCount = Type("ByteCount", "l") +Duration = Type("Duration", "l") +ByteOffset = Type("ByteOffset", "l") +OptionBits = Type("OptionBits", "l") +ItemCount = Type("ItemCount", "l") +PBVersion = Type("PBVersion", "l") +ScriptCode = Type("ScriptCode", "h") +LangCode = Type("LangCode", "h") +RegionCode = Type("RegionCode", "h") + +UInt8 = Type("UInt8", "b") +SInt8 = Type("SInt8", "b") +UInt16 = Type("UInt16", "H") +SInt16 = Type("SInt16", "h") +UInt32 = Type("UInt32", "l") +SInt32 = Type("SInt32", "l") +Float32 = Type("Float32", "f") + +wide = OpaqueByValueType("wide", "PyMac_Buildwide", "PyMac_Getwide") +wide_ptr = OpaqueType("wide", "PyMac_Buildwide", "PyMac_Getwide") + +# Pascal strings +ConstStr255Param = OpaqueArrayType("Str255", "PyMac_BuildStr255", "PyMac_GetStr255") +Str255 = OpaqueArrayType("Str255", "PyMac_BuildStr255", "PyMac_GetStr255") +StringPtr = OpaqueByValueType("StringPtr", "PyMac_BuildStr255", "PyMac_GetStr255") +ConstStringPtr = StringPtr + +# File System Specifications +FSSpec_ptr = OpaqueType("FSSpec", "PyMac_BuildFSSpec", "PyMac_GetFSSpec") +FSSpec = OpaqueByValueStructType("FSSpec", "PyMac_BuildFSSpec", "PyMac_GetFSSpec") +FSRef_ptr = OpaqueType("FSRef", "PyMac_BuildFSRef", "PyMac_GetFSRef") +FSRef = OpaqueByValueStructType("FSRef", "PyMac_BuildFSRef", "PyMac_GetFSRef") + +# OSType and ResType: 4-byte character strings +def OSTypeType(typename): + return OpaqueByValueType(typename, "PyMac_BuildOSType", "PyMac_GetOSType") +OSType = OSTypeType("OSType") +ResType = OSTypeType("ResType") +FourCharCode = OSTypeType("FourCharCode") + +# Version numbers +NumVersion = OpaqueByValueType("NumVersion", "PyMac_BuildNumVersion", "BUG") + +# Handles (always resources in our case) +Handle = OpaqueByValueType("Handle", "ResObj") +MenuHandle = OpaqueByValueType("MenuHandle", "MenuObj") +MenuRef = MenuHandle +ControlHandle = OpaqueByValueType("ControlHandle", "CtlObj") +ControlRef = ControlHandle + +# Windows and Dialogs +WindowPtr = OpaqueByValueType("WindowPtr", "WinObj") +WindowRef = WindowPtr +DialogPtr = OpaqueByValueType("DialogPtr", "DlgObj") +DialogRef = DialogPtr +ExistingWindowPtr = OpaqueByValueType("WindowPtr", "WinObj_WhichWindow", "BUG") +ExistingDialogPtr = OpaqueByValueType("DialogPtr", "DlgObj_WhichDialog", "BUG") + +# NULL pointer passed in as optional storage -- not present in Python version +NullStorage = FakeType("(void *)0") + +# More standard datatypes +Fixed = OpaqueByValueType("Fixed", "PyMac_BuildFixed", "PyMac_GetFixed") + +# Quickdraw data types +Rect = Rect_ptr = OpaqueType("Rect", "PyMac_BuildRect", "PyMac_GetRect") +Point = OpaqueByValueType("Point", "PyMac_BuildPoint", "PyMac_GetPoint") +Point_ptr = OpaqueType("Point", "PyMac_BuildPoint", "PyMac_GetPoint") + +# Event records +EventRecord = OpaqueType("EventRecord", "PyMac_BuildEventRecord", "PyMac_GetEventRecord") +EventRecord_ptr = EventRecord + +# CoreFoundation datatypes +CFTypeRef = OpaqueByValueType("CFTypeRef", "CFTypeRefObj") +CFStringRef = OpaqueByValueType("CFStringRef", "CFStringRefObj") +CFMutableStringRef = OpaqueByValueType("CFMutableStringRef", "CFMutableStringRefObj") +CFArrayRef = OpaqueByValueType("CFArrayRef", "CFArrayRefObj") +CFMutableArrayRef = OpaqueByValueType("CFMutableArrayRef", "CFMutableArrayRefObj") +CFDictionaryRef = OpaqueByValueType("CFDictionaryRef", "CFDictionaryRefObj") +CFMutableDictionaryRef = OpaqueByValueType("CFMutableDictionaryRef", "CFMutableDictionaryRefObj") +CFURLRef = OpaqueByValueType("CFURLRef", "CFURLRefObj") +OptionalCFURLRef = OpaqueByValueType("CFURLRef", "OptionalCFURLRefObj") + +# OSErr is special because it is turned into an exception +# (Could do this with less code using a variant of mkvalue("O&")?) +class OSErrType(Type): + def errorCheck(self, name): + Output("if (%s != noErr) return PyMac_Error(%s);", name, name) + self.used = 1 +OSErr = OSErrType("OSErr", 'h') +OSStatus = OSErrType("OSStatus", 'l') + + +# Various buffer types + +InBuffer = VarInputBufferType('char', 'long', 'l') # (buf, len) +UcharInBuffer = VarInputBufferType('unsigned char', 'long', 'l') # (buf, len) +OptionalInBuffer = OptionalVarInputBufferType('char', 'long', 'l') # (buf, len) + +InOutBuffer = HeapInputOutputBufferType('char', 'long', 'l') # (inbuf, outbuf, len) +VarInOutBuffer = VarHeapInputOutputBufferType('char', 'long', 'l') # (inbuf, outbuf, &len) + +OutBuffer = HeapOutputBufferType('char', 'long', 'l') # (buf, len) +VarOutBuffer = VarHeapOutputBufferType('char', 'long', 'l') # (buf, &len) +VarVarOutBuffer = VarVarHeapOutputBufferType('char', 'long', 'l') # (buf, len, &len) + +# Unicode arguments sometimes have reversed len, buffer (don't understand why Apple did this...) +class VarUnicodeInputBufferType(VarInputBufferType): + + def getargsFormat(self): + return "u#" + +class VarUnicodeReverseInputBufferType(ReverseInputBufferMixin, VarUnicodeInputBufferType): + pass + +UnicodeInBuffer = VarUnicodeInputBufferType('UniChar', 'UniCharCount', 'l') +UnicodeReverseInBuffer = VarUnicodeReverseInputBufferType('UniChar', 'UniCharCount', 'l') +UniChar_ptr = InputOnlyType("UniCharPtr", "u") + + +# Predefine various pieces of program text to be passed to Module() later: + +# Stuff added immediately after the system include files +includestuff = """ +#include "pymactoolbox.h" + +/* Macro to test whether a weak-loaded CFM function exists */ +#define PyMac_PRECHECK(rtn) do { if ( &rtn == NULL ) {\\ + PyErr_SetString(PyExc_NotImplementedError, \\ + "Not available in this shared library/OS version"); \\ + return NULL; \\ + }} while(0) + +""" + +# Stuff added just before the module's init function +finalstuff = """ +""" + +# Stuff added inside the module's init function +initstuff = """ +""" + + +# Generator classes with a twist -- if the function returns OSErr, +# its mode is manipulated so that it turns into an exception or disappears +# (and its name is changed to _err, for documentation purposes). +# This requires that the OSErr type (defined above) has a non-trivial +# errorCheck method. +class OSErrMixIn: + "Mix-in class to treat OSErr/OSStatus return values special" + def makereturnvar(self): + if self.returntype.__class__ == OSErrType: + return Variable(self.returntype, "_err", ErrorMode) + else: + return Variable(self.returntype, "_rv", OutMode) + +class OSErrFunctionGenerator(OSErrMixIn, FunctionGenerator): pass +class OSErrMethodGenerator(OSErrMixIn, MethodGenerator): pass + +class WeakLinkMixIn: + "Mix-in to test the function actually exists (!= NULL) before calling" + + def precheck(self): + Output('#ifndef %s', self.name) + Output('PyMac_PRECHECK(%s);', self.name) + Output('#endif') + +class WeakLinkFunctionGenerator(WeakLinkMixIn, FunctionGenerator): pass +class WeakLinkMethodGenerator(WeakLinkMixIn, MethodGenerator): pass +class OSErrWeakLinkFunctionGenerator(OSErrMixIn, WeakLinkMixIn, FunctionGenerator): pass +class OSErrWeakLinkMethodGenerator(OSErrMixIn, WeakLinkMixIn, MethodGenerator): pass + +class MacModule(Module): + "Subclass which gets the exception initializer from macglue.c" + def exceptionInitializer(self): + return "PyMac_GetOSErrException()" diff --git a/sys/src/cmd/python/Tools/bgen/bgen/scantools.py b/sys/src/cmd/python/Tools/bgen/bgen/scantools.py new file mode 100644 index 000000000..d809a65f2 --- /dev/null +++ b/sys/src/cmd/python/Tools/bgen/bgen/scantools.py @@ -0,0 +1,849 @@ +"""\ + +Tools for scanning header files in search of function prototypes. + +Often, the function prototypes in header files contain enough information +to automatically generate (or reverse-engineer) interface specifications +from them. The conventions used are very vendor specific, but once you've +figured out what they are they are often a great help, and it sure beats +manually entering the interface specifications. (These are needed to generate +the glue used to access the functions from Python.) + +In order to make this class useful, almost every component can be overridden. +The defaults are (currently) tuned to scanning Apple Macintosh header files, +although most Mac specific details are contained in header-specific subclasses. +""" + +import re +import sys +import os +import fnmatch +from types import * +try: + import MacOS +except ImportError: + MacOS = None + +try: + from bgenlocations import CREATOR, INCLUDEDIR +except ImportError: + CREATOR = None + INCLUDEDIR = os.curdir + +Error = "scantools.Error" + +BEGINHTMLREPORT="""<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<style type="text/css"> +.unmatched { } +.commentstripping { color: grey; text-decoration: line-through } +.comment { text-decoration: line-through } +.notcomment { color: black } +.incomplete { color: maroon } +.constant { color: green } +.pyconstant { background-color: yellow } +.blconstant { background-color: yellow; color: red } +.declaration { color: blue } +.pydeclaration { background-color: yellow } +.type { font-style: italic } +.name { font-weight: bold } +.value { font-style: italic } +.arglist { text-decoration: underline } +.blacklisted { background-color: yellow; color: red } +</style> +<title>Bgen scan report</title> +</head> +<body> +<h1>Bgen scan report</h1> +<h2>Legend</h2> +<p>This scan report is intended to help you debug the regular expressions +used by the bgen scanner. It consists of the original ".h" header file(s) +marked up to show you what the regular expressions in the bgen parser matched +for each line. NOTE: comments in the original source files may or may not be +shown.</p> +<p>The typographic conventions of this file are as follows:</p> +<dl> +<dt>comment stripping</dt> +<dd><pre><span class="commentstripping"><span class="notcomment">comment stripping is </span><span class="comment">/* marked up */</span><span class="notcomment"> and the line is repeated if needed</span></span></pre> +<p>If anything here does not appear to happen correctly look at +<tt>comment1_pat</tt> and <tt>comment2_pat</tt>.</p> +</dd> +<dt>constant definitions</dt> +<dd><pre><span class="constant">#define <span class="name">name</span> <span class="value">value</span></pre> +<p>Highlights name and value of the constant. Governed by <tt>sym_pat</tt>.</p> +</dd> +<dt>function declaration</dt> +<dd><pre><span class="declaration"><span class="type">char *</span><span class="name">rindex</span><span class="arglist">(<span class="type">const char *</span><span class="name">s</span>, <span class="type">int </span><span class="name">c</span>)</span>;</span></pre> +<p>Highlights type, name and argument list. <tt>type_pat</tt>, +<tt>name_pat</tt> and <tt>args_pat</tt> are combined into <tt>whole_pat</tt>, which +is what is used here.</p></dd> +</dd> +<dt>incomplete match for function declaration</dt> +<dd><pre><span class="incomplete"><span class="type">char *</span>foo;</span></pre> +<p>The beginning of this looked promising, but it did not match a function declaration. +In other words, it matched <tt>head_pat</tt> but not <tt>whole_pat</tt>. If the next +declaration has also been gobbled up you need to look at <tt>end_pat</tt>.</p> +</dd> +<dt>unrecognized input</dt> +<dd><pre><span class="unmatched">#include "type.h"</span></pre> +<p>If there are function declarations the scanner has missed (i.e. things +are in this class but you want them to be declarations) you need to adapt +<tt>head_pat</tt>. +</dd> +</dl> +<h2>Output</h2> +<pre> +<span class="unmatched"> +""" +ENDHTMLREPORT="""</span> +</pre> +</body> +</html> +""" + +class Scanner: + + # Set to 1 in subclass to debug your scanner patterns. + debug = 0 + + def __init__(self, input = None, output = None, defsoutput = None): + self.initsilent() + self.initblacklists() + self.initrepairinstructions() + self.initpaths() + self.initfiles() + self.initpatterns() + self.compilepatterns() + self.initosspecifics() + self.initusedtypes() + if output: + self.setoutput(output, defsoutput) + if input: + self.setinput(input) + + def initusedtypes(self): + self.usedtypes = {} + + def typeused(self, type, mode): + if not self.usedtypes.has_key(type): + self.usedtypes[type] = {} + self.usedtypes[type][mode] = None + + def reportusedtypes(self): + types = self.usedtypes.keys() + types.sort() + for type in types: + modes = self.usedtypes[type].keys() + modes.sort() + self.report("%s %s", type, " ".join(modes)) + + def gentypetest(self, file): + fp = open(file, "w") + fp.write("types=[\n") + types = self.usedtypes.keys() + types.sort() + for type in types: + fp.write("\t'%s',\n"%type) + fp.write("]\n") + fp.write("""missing=0 +for t in types: + try: + tt = eval(t) + except NameError: + print "** Missing type:", t + missing = 1 +if missing: raise "Missing Types" +""") + fp.close() + + def initsilent(self): + self.silent = 1 + + def error(self, format, *args): + if self.silent >= 0: + print format%args + + def report(self, format, *args): + if not self.silent: + print format%args + + def writeinitialdefs(self): + pass + + def initblacklists(self): + self.blacklistnames = self.makeblacklistnames() + self.blacklisttypes = ["unknown", "-"] + self.makeblacklisttypes() + self.greydictnames = self.greylist2dict(self.makegreylist()) + + def greylist2dict(self, list): + rv = {} + for define, namelist in list: + for name in namelist: + rv[name] = define + return rv + + def makeblacklistnames(self): + return [] + + def makeblacklisttypes(self): + return [] + + def makegreylist(self): + return [] + + def initrepairinstructions(self): + self.repairinstructions = self.makerepairinstructions() + self.inherentpointertypes = self.makeinherentpointertypes() + + def makerepairinstructions(self): + """Parse the repair file into repair instructions. + + The file format is simple: + 1) use \ to split a long logical line in multiple physical lines + 2) everything after the first # on a line is ignored (as comment) + 3) empty lines are ignored + 4) remaining lines must have exactly 3 colon-separated fields: + functionpattern : argumentspattern : argumentsreplacement + 5) all patterns use shell style pattern matching + 6) an empty functionpattern means the same as * + 7) the other two fields are each comma-separated lists of triples + 8) a triple is a space-separated list of 1-3 words + 9) a triple with less than 3 words is padded at the end with "*" words + 10) when used as a pattern, a triple matches the type, name, and mode + of an argument, respectively + 11) when used as a replacement, the words of a triple specify + replacements for the corresponding words of the argument, + with "*" as a word by itself meaning leave the original word + (no other uses of "*" is allowed) + 12) the replacement need not have the same number of triples + as the pattern + """ + f = self.openrepairfile() + if not f: return [] + print "Reading repair file", repr(f.name), "..." + list = [] + lineno = 0 + while 1: + line = f.readline() + if not line: break + lineno = lineno + 1 + startlineno = lineno + while line[-2:] == '\\\n': + line = line[:-2] + ' ' + f.readline() + lineno = lineno + 1 + i = line.find('#') + if i >= 0: line = line[:i] + words = [s.strip() for s in line.split(':')] + if words == ['']: continue + if len(words) <> 3: + print "Line", startlineno, + print ": bad line (not 3 colon-separated fields)" + print repr(line) + continue + [fpat, pat, rep] = words + if not fpat: fpat = "*" + if not pat: + print "Line", startlineno, + print "Empty pattern" + print repr(line) + continue + patparts = [s.strip() for s in pat.split(',')] + repparts = [s.strip() for s in rep.split(',')] + patterns = [] + for p in patparts: + if not p: + print "Line", startlineno, + print "Empty pattern part" + print repr(line) + continue + pattern = p.split() + if len(pattern) > 3: + print "Line", startlineno, + print "Pattern part has > 3 words" + print repr(line) + pattern = pattern[:3] + else: + while len(pattern) < 3: + pattern.append("*") + patterns.append(pattern) + replacements = [] + for p in repparts: + if not p: + print "Line", startlineno, + print "Empty replacement part" + print repr(line) + continue + replacement = p.split() + if len(replacement) > 3: + print "Line", startlineno, + print "Pattern part has > 3 words" + print repr(line) + replacement = replacement[:3] + else: + while len(replacement) < 3: + replacement.append("*") + replacements.append(replacement) + list.append((fpat, patterns, replacements)) + return list + + def makeinherentpointertypes(self): + return [] + + def openrepairfile(self, filename = "REPAIR"): + try: + return open(filename, "rU") + except IOError, msg: + print repr(filename), ":", msg + print "Cannot open repair file -- assume no repair needed" + return None + + def initfiles(self): + self.specmine = 0 + self.defsmine = 0 + self.scanmine = 0 + self.htmlmine = 0 + self.specfile = sys.stdout + self.defsfile = None + self.scanfile = sys.stdin + self.htmlfile = None + self.lineno = 0 + self.line = "" + + def initpaths(self): + self.includepath = [os.curdir, INCLUDEDIR] + + def initpatterns(self): + self.head_pat = r"^EXTERN_API[^_]" + self.tail_pat = r"[;={}]" + self.type_pat = r"EXTERN_API" + \ + r"[ \t\n]*\([ \t\n]*" + \ + r"(?P<type>[a-zA-Z0-9_* \t]*[a-zA-Z0-9_*])" + \ + r"[ \t\n]*\)[ \t\n]*" + self.name_pat = r"(?P<name>[a-zA-Z0-9_]+)[ \t\n]*" + self.args_pat = r"\((?P<args>([^\(;=\)]+|\([^\(;=\)]*\))*)\)" + self.whole_pat = self.type_pat + self.name_pat + self.args_pat + self.sym_pat = r"^[ \t]*(?P<name>[a-zA-Z0-9_]+)[ \t]*=" + \ + r"[ \t]*(?P<defn>[-0-9_a-zA-Z'\"\(][^\t\n,;}]*),?" + self.asplit_pat = r"^(?P<type>.*[^a-zA-Z0-9_])(?P<name>[a-zA-Z0-9_]+)(?P<array>\[\])?$" + self.comment1_pat = r"(?P<rest>.*)//.*" + # note that the next pattern only removes comments that are wholly within one line + self.comment2_pat = r"(?P<rest1>.*)/\*.*\*/(?P<rest2>.*)" + + def compilepatterns(self): + for name in dir(self): + if name[-4:] == "_pat": + pat = getattr(self, name) + prog = re.compile(pat) + setattr(self, name[:-4], prog) + + def initosspecifics(self): + if MacOS and CREATOR: + self.filetype = 'TEXT' + self.filecreator = CREATOR + else: + self.filetype = self.filecreator = None + + def setfiletype(self, filename): + if MacOS and (self.filecreator or self.filetype): + creator, type = MacOS.GetCreatorAndType(filename) + if self.filecreator: creator = self.filecreator + if self.filetype: type = self.filetype + MacOS.SetCreatorAndType(filename, creator, type) + + def close(self): + self.closefiles() + + def closefiles(self): + self.closespec() + self.closedefs() + self.closescan() + self.closehtml() + + def closespec(self): + tmp = self.specmine and self.specfile + self.specfile = None + if tmp: tmp.close() + + def closedefs(self): + tmp = self.defsmine and self.defsfile + self.defsfile = None + if tmp: tmp.close() + + def closescan(self): + tmp = self.scanmine and self.scanfile + self.scanfile = None + if tmp: tmp.close() + + def closehtml(self): + if self.htmlfile: self.htmlfile.write(ENDHTMLREPORT) + tmp = self.htmlmine and self.htmlfile + self.htmlfile = None + if tmp: tmp.close() + + def setoutput(self, spec, defs = None): + self.closespec() + self.closedefs() + if spec: + if type(spec) == StringType: + file = self.openoutput(spec) + mine = 1 + else: + file = spec + mine = 0 + self.specfile = file + self.specmine = mine + if defs: + if type(defs) == StringType: + file = self.openoutput(defs) + mine = 1 + else: + file = defs + mine = 0 + self.defsfile = file + self.defsmine = mine + + def sethtmloutput(self, htmlfile): + self.closehtml() + if htmlfile: + if type(htmlfile) == StringType: + file = self.openoutput(htmlfile) + mine = 1 + else: + file = htmlfile + mine = 0 + self.htmlfile = file + self.htmlmine = mine + self.htmlfile.write(BEGINHTMLREPORT) + + def openoutput(self, filename): + try: + file = open(filename, 'w') + except IOError, arg: + raise IOError, (filename, arg) + self.setfiletype(filename) + return file + + def setinput(self, scan = sys.stdin): + if not type(scan) in (TupleType, ListType): + scan = [scan] + self.allscaninputs = scan + self._nextinput() + + def _nextinput(self): + if not self.allscaninputs: + return 0 + scan = self.allscaninputs[0] + self.allscaninputs = self.allscaninputs[1:] + self.closescan() + if scan: + if type(scan) == StringType: + file = self.openinput(scan) + mine = 1 + else: + file = scan + mine = 0 + self.scanfile = file + self.scanmine = mine + self.lineno = 0 + return 1 + + def openinput(self, filename): + if not os.path.isabs(filename): + for dir in self.includepath: + fullname = os.path.join(dir, filename) + #self.report("trying full name %r", fullname) + try: + return open(fullname, 'rU') + except IOError: + pass + # If not on the path, or absolute, try default open() + try: + return open(filename, 'rU') + except IOError, arg: + raise IOError, (arg, filename) + + def getline(self): + if not self.scanfile: + raise Error, "input file not set" + self.line = self.scanfile.readline() + if not self.line: + if self._nextinput(): + return self.getline() + raise EOFError + self.lineno = self.lineno + 1 + return self.line + + def scan(self): + if not self.scanfile: + self.error("No input file has been specified") + return + inputname = self.scanfile.name + self.report("scanfile = %r", inputname) + if not self.specfile: + self.report("(No interface specifications will be written)") + else: + self.report("specfile = %r", self.specfile.name) + self.specfile.write("# Generated from %r\n\n" % (inputname,)) + if not self.defsfile: + self.report("(No symbol definitions will be written)") + else: + self.report("defsfile = %r", (self.defsfile.name,)) + self.defsfile.write("# Generated from %r\n\n" % (os.path.split(inputname)[1],)) + self.writeinitialdefs() + self.alreadydone = [] + try: + while 1: + try: line = self.getline() + except EOFError: break + if self.debug: + self.report("LINE: %r" % (line,)) + match = self.comment1.match(line) + if match: + self.htmlreport(line, klass='commentstripping', ranges=[( + match.start('rest'), match.end('rest'), 'notcomment')]) + line = match.group('rest') + if self.debug: + self.report("\tafter comment1: %r" % (line,)) + match = self.comment2.match(line) + while match: + if match: + self.htmlreport(line, klass='commentstripping', ranges=[ + (match.start('rest1'), match.end('rest1'), 'notcomment'), + (match.start('rest2'), match.end('rest2'), 'notcomment')]) + line = match.group('rest1')+match.group('rest2') + if self.debug: + self.report("\tafter comment2: %r" % (line,)) + match = self.comment2.match(line) + if self.defsfile: + match = self.sym.match(line) + if match: + if self.debug: + self.report("\tmatches sym.") + self.dosymdef(match, line) + continue + match = self.head.match(line) + if match: + if self.debug: + self.report("\tmatches head.") + self.dofuncspec() + continue + self.htmlreport(line, klass='unmatched') + except EOFError: + self.error("Uncaught EOF error") + self.reportusedtypes() + + def dosymdef(self, match, line): + name, defn = match.group('name', 'defn') + self.htmlreport(line, klass='constant', ranges=[ + (match.start('name'), match.end('name'), 'name'), + (match.start('defn'), match.end('defn'), 'value')]) + defn = escape8bit(defn) + if self.debug: + self.report("\tsym: name=%r, defn=%r" % (name, defn)) + if not name in self.blacklistnames: + oline = "%s = %s\n" % (name, defn) + self.defsfile.write(oline) + self.htmlreport(oline, klass="pyconstant") + else: + self.defsfile.write("# %s = %s\n" % (name, defn)) + self.htmlreport("** no output: name is blacklisted", klass="blconstant") + # XXXX No way to handle greylisted names + + def dofuncspec(self): + raw = self.line + while not self.tail.search(raw): + line = self.getline() + if self.debug: + self.report("* CONTINUATION LINE: %r" % (line,)) + match = self.comment1.match(line) + if match: + line = match.group('rest') + if self.debug: + self.report("\tafter comment1: %r" % (line,)) + match = self.comment2.match(line) + while match: + line = match.group('rest1')+match.group('rest2') + if self.debug: + self.report("\tafter comment1: %r" % (line,)) + match = self.comment2.match(line) + raw = raw + line + if self.debug: + self.report("* WHOLE LINE: %r" % (raw,)) + self.processrawspec(raw) + return raw + + def processrawspec(self, raw): + match = self.whole.search(raw) + if not match: + self.report("Bad raw spec: %r", raw) + if self.debug: + match = self.type.search(raw) + if not match: + self.report("(Type already doesn't match)") + self.htmlreport(raw, klass='incomplete', ranges=[( + match.start('type'), match.end('type'), 'type')]) + else: + self.report("(but type matched)") + self.htmlreport(raw, klass='incomplete') + return + type, name, args = match.group('type', 'name', 'args') + ranges=[ + (match.start('type'), match.end('type'), 'type'), + (match.start('name'), match.end('name'), 'name'), + (match.start('args'), match.end('args'), 'arglist')] + self.htmlreport(raw, klass='declaration', ranges=ranges) + modifiers = self.getmodifiers(match) + type = self.pythonizename(type) + name = self.pythonizename(name) + if self.checkduplicate(name): + self.htmlreport("*** no output generated: duplicate name", klass="blacklisted") + return + self.report("==> %s %s <==", type, name) + if self.blacklisted(type, name): + self.htmlreport("*** no output generated: function name or return type blacklisted", klass="blacklisted") + self.report("*** %s %s blacklisted", type, name) + return + returnlist = [(type, name, 'ReturnMode')] + returnlist = self.repairarglist(name, returnlist) + [(type, name, returnmode)] = returnlist + arglist = self.extractarglist(args) + arglist = self.repairarglist(name, arglist) + if self.unmanageable(type, name, arglist): + self.htmlreport("*** no output generated: some argument blacklisted", klass="blacklisted") + ##for arg in arglist: + ## self.report(" %r", arg) + self.report("*** %s %s unmanageable", type, name) + return + if modifiers: + self.generate(type, name, arglist, modifiers) + else: + self.generate(type, name, arglist) + + def getmodifiers(self, match): + return [] + + def checkduplicate(self, name): + if name in self.alreadydone: + self.report("Name has already been defined: %r", name) + return True + self.alreadydone.append(name) + return False + + def pythonizename(self, name): + name = re.sub("\*", " ptr", name) + name = name.strip() + name = re.sub("[ \t]+", "_", name) + return name + + def extractarglist(self, args): + args = args.strip() + if not args or args == "void": + return [] + parts = [s.strip() for s in args.split(",")] + arglist = [] + for part in parts: + arg = self.extractarg(part) + arglist.append(arg) + return arglist + + def extractarg(self, part): + mode = "InMode" + part = part.strip() + match = self.asplit.match(part) + if not match: + self.error("Indecipherable argument: %r", part) + return ("unknown", part, mode) + type, name, array = match.group('type', 'name', 'array') + if array: + # array matches an optional [] after the argument name + type = type + " ptr " + type = self.pythonizename(type) + return self.modifyarg(type, name, mode) + + def modifyarg(self, type, name, mode): + if type[:6] == "const_": + type = type[6:] + elif type[-4:] == "_ptr": + type = type[:-4] + mode = "OutMode" + elif type in self.inherentpointertypes: + mode = "OutMode" + if type[-4:] == "_far": + type = type[:-4] + return type, name, mode + + def repairarglist(self, functionname, arglist): + arglist = arglist[:] + i = 0 + while i < len(arglist): + for item in self.repairinstructions: + if len(item) == 2: + pattern, replacement = item + functionpat = "*" + else: + functionpat, pattern, replacement = item + if not fnmatch.fnmatchcase(functionname, functionpat): + continue + n = len(pattern) + if i+n > len(arglist): continue + current = arglist[i:i+n] + for j in range(n): + if not self.matcharg(pattern[j], current[j]): + break + else: # All items of the pattern match + new = self.substituteargs( + pattern, replacement, current) + if new is not None: + arglist[i:i+n] = new + i = i+len(new) # No recursive substitutions + break + else: # No patterns match + i = i+1 + return arglist + + def matcharg(self, patarg, arg): + return len(filter(None, map(fnmatch.fnmatchcase, arg, patarg))) == 3 + + def substituteargs(self, pattern, replacement, old): + new = [] + for k in range(len(replacement)): + item = replacement[k] + newitem = [item[0], item[1], item[2]] + for i in range(3): + if item[i] == '*': + newitem[i] = old[k][i] + elif item[i][:1] == '$': + index = int(item[i][1:]) - 1 + newitem[i] = old[index][i] + new.append(tuple(newitem)) + ##self.report("old: %r", old) + ##self.report("new: %r", new) + return new + + def generate(self, tp, name, arglist, modifiers=[]): + + self.typeused(tp, 'return') + if modifiers: + classname, listname = self.destination(tp, name, arglist, modifiers) + else: + classname, listname = self.destination(tp, name, arglist) + if not classname or not listname: + self.htmlreport("*** no output generated: self.destination() returned None", klass="blacklisted") + return + if not self.specfile: + self.htmlreport("*** no output generated: no output file specified", klass="blacklisted") + return + self.specfile.write("f = %s(%s, %r,\n" % (classname, tp, name)) + for atype, aname, amode in arglist: + self.typeused(atype, amode) + self.specfile.write(" (%s, %r, %s),\n" % + (atype, aname, amode)) + if self.greydictnames.has_key(name): + self.specfile.write(" condition=%r,\n"%(self.greydictnames[name],)) + self.generatemodifiers(classname, name, modifiers) + self.specfile.write(")\n") + self.specfile.write("%s.append(f)\n\n" % listname) + if self.htmlfile: + oline = "Adding to %s:\n%s(returntype=%s, name=%r" % (listname, classname, tp, name) + for atype, aname, amode in arglist: + oline += ",\n (%s, %r, %s)" % (atype, aname, amode) + oline += ")\n" + self.htmlreport(oline, klass="pydeclaration") + + def destination(self, type, name, arglist): + return "FunctionGenerator", "functions" + + def generatemodifiers(self, classname, name, modifiers): + pass + + def blacklisted(self, type, name): + if type in self.blacklisttypes: + ##self.report("return type %s is blacklisted", type) + return 1 + if name in self.blacklistnames: + ##self.report("function name %s is blacklisted", name) + return 1 + return 0 + + def unmanageable(self, type, name, arglist): + for atype, aname, amode in arglist: + if atype in self.blacklisttypes: + self.report("argument type %s is blacklisted", atype) + return 1 + return 0 + + def htmlreport(self, line, klass=None, ranges=None): + if not self.htmlfile: return + if ranges is None: + ranges = [] + if klass: + ranges.insert(0, (0, len(line), klass)) + oline = '' + i = 0 + for c in line: + for b, e, name in ranges: + if b == i: + oline += '<span class="%s">' % name + if e == i: + oline += '</span>' + i += 1 + + if c == '<': oline += '&lt;' + elif c == '>': oline += '&gt;' + else: oline += c + for b, e, name in ranges: + if b >= i: + oline += '<span class="%s">' % name + if e >= i: + oline += '</span>' + if not line or line[-1] != '\n': + oline += '\n' + self.htmlfile.write(oline) + +class Scanner_PreUH3(Scanner): + """Scanner for Universal Headers before release 3""" + def initpatterns(self): + Scanner.initpatterns(self) + self.head_pat = "^extern pascal[ \t]+" # XXX Mac specific! + self.type_pat = "pascal[ \t\n]+(?P<type>[a-zA-Z0-9_ \t]*[a-zA-Z0-9_])[ \t\n]+" + self.whole_pat = self.type_pat + self.name_pat + self.args_pat + self.sym_pat = "^[ \t]*(?P<name>[a-zA-Z0-9_]+)[ \t]*=" + \ + "[ \t]*(?P<defn>[-0-9'\"][^\t\n,;}]*),?" + +class Scanner_OSX(Scanner): + """Scanner for modern (post UH3.3) Universal Headers """ + def initpatterns(self): + Scanner.initpatterns(self) + self.head_pat = "^EXTERN_API(_C)?" + self.type_pat = "EXTERN_API(_C)?" + \ + "[ \t\n]*\([ \t\n]*" + \ + "(?P<type>[a-zA-Z0-9_* \t]*[a-zA-Z0-9_*])" + \ + "[ \t\n]*\)[ \t\n]*" + self.whole_pat = self.type_pat + self.name_pat + self.args_pat + self.sym_pat = "^[ \t]*(?P<name>[a-zA-Z0-9_]+)[ \t]*=" + \ + "[ \t]*(?P<defn>[-0-9_a-zA-Z'\"\(][^\t\n,;}]*),?" + +_8bit = re.compile(r"[\200-\377]") + +def escape8bit(s): + if _8bit.search(s) is not None: + out = [] + for c in s: + o = ord(c) + if o >= 128: + out.append("\\" + hex(o)[1:]) + else: + out.append(c) + s = "".join(out) + return s + +def test(): + input = "D:Development:THINK C:Mac #includes:Apple #includes:AppleEvents.h" + output = "@aespecs.py" + defsoutput = "@aedefs.py" + s = Scanner(input, output, defsoutput) + s.scan() + +if __name__ == '__main__': + test() diff --git a/sys/src/cmd/python/Tools/buildbot/Makefile b/sys/src/cmd/python/Tools/buildbot/Makefile new file mode 100644 index 000000000..166023184 --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/Makefile @@ -0,0 +1,6 @@ +all: kill_python.exe + ./kill_python.exe + +kill_python.exe: kill_python.c + gcc -o kill_python.exe kill_python.c -lpsapi + diff --git a/sys/src/cmd/python/Tools/buildbot/build.bat b/sys/src/cmd/python/Tools/buildbot/build.bat new file mode 100644 index 000000000..e96323c5b --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/build.bat @@ -0,0 +1,5 @@ +@rem Used by the buildbot "compile" step. +cmd /c Tools\buildbot\external.bat +call "%VS71COMNTOOLS%vsvars32.bat" +cmd /q/c Tools\buildbot\kill_python.bat +devenv.com /useenv /build Debug PCbuild\pcbuild.sln diff --git a/sys/src/cmd/python/Tools/buildbot/clean.bat b/sys/src/cmd/python/Tools/buildbot/clean.bat new file mode 100644 index 000000000..4b949225d --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/clean.bat @@ -0,0 +1,6 @@ +@rem Used by the buildbot "clean" step. +call "%VS71COMNTOOLS%vsvars32.bat" +cd PCbuild +@echo Deleting .pyc/.pyo files ... +python_d.exe rmpyc.py +devenv.com /clean Debug pcbuild.sln diff --git a/sys/src/cmd/python/Tools/buildbot/external.bat b/sys/src/cmd/python/Tools/buildbot/external.bat new file mode 100644 index 000000000..463285fa4 --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/external.bat @@ -0,0 +1,36 @@ +@rem Fetches (and builds if necessary) external dependencies + +@rem Assume we start inside the Python source directory +cd .. +call "%VS71COMNTOOLS%vsvars32.bat" + +@rem bzip +if not exist bzip2-1.0.3 svn export http://svn.python.org/projects/external/bzip2-1.0.3 + +@rem Sleepycat db +if not exist db-4.4.20 svn export http://svn.python.org/projects/external/db-4.4.20 +if not exist db-4.4.20\build_win32\debug\libdb44sd.lib ( + devenv db-4.4.20\build_win32\Berkeley_DB.sln /build Debug /project db_static +) + +@rem OpenSSL +if not exist openssl-0.9.8a svn export http://svn.python.org/projects/external/openssl-0.9.8a + +@rem tcltk +if not exist tcl8.4.12 ( + if exist tcltk rd /s/q tcltk + svn export http://svn.python.org/projects/external/tcl8.4.12 + svn export http://svn.python.org/projects/external/tk8.4.12 + cd tcl8.4.12\win + nmake -f makefile.vc + nmake -f makefile.vc INSTALLDIR=..\..\tcltk install + cd ..\.. + cd tk8.4.12\win + nmake -f makefile.vc TCLDIR=..\..\tcl8.4.12 + nmake -f makefile.vc TCLDIR=..\..\tcl8.4.12 INSTALLDIR=..\..\tcltk install + cd ..\.. +) + +@rem sqlite +if not exist sqlite-source-3.3.4 svn export http://svn.python.org/projects/external/sqlite-source-3.3.4 +if not exist build\PCbuild\sqlite3.dll copy sqlite-source-3.3.4\sqlite3.dll build\PCbuild diff --git a/sys/src/cmd/python/Tools/buildbot/kill_python.bat b/sys/src/cmd/python/Tools/buildbot/kill_python.bat new file mode 100644 index 000000000..d78b6d4c4 --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/kill_python.bat @@ -0,0 +1,3 @@ +cd Tools\buildbot +nmake /C /S /f kill_python.mak +kill_python.exe diff --git a/sys/src/cmd/python/Tools/buildbot/kill_python.c b/sys/src/cmd/python/Tools/buildbot/kill_python.c new file mode 100644 index 000000000..023ff2def --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/kill_python.c @@ -0,0 +1,68 @@ +/* This program looks for processes which have build\PCbuild\python.exe + in their path and terminates them. */ +#include <windows.h> +#include <psapi.h> +#include <stdio.h> + +int main() +{ + DWORD pids[1024], cbNeeded; + int i, num_processes; + if (!EnumProcesses(pids, sizeof(pids), &cbNeeded)) { + printf("EnumProcesses failed\n"); + return 1; + } + num_processes = cbNeeded/sizeof(pids[0]); + for (i = 0; i < num_processes; i++) { + HANDLE hProcess; + char path[MAX_PATH]; + HMODULE mods[1024]; + int k, num_mods; + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION + | PROCESS_VM_READ + | PROCESS_TERMINATE , + FALSE, pids[i]); + if (!hProcess) + /* process not accessible */ + continue; + if (!EnumProcessModules(hProcess, mods, sizeof(mods), &cbNeeded)) { + /* For unknown reasons, this sometimes returns ERROR_PARTIAL_COPY; + this apparently means we are not supposed to read the process. */ + if (GetLastError() == ERROR_PARTIAL_COPY) { + CloseHandle(hProcess); + continue; + } + printf("EnumProcessModules failed: %d\n", GetLastError()); + return 1; + } + if (!GetModuleFileNameEx(hProcess, NULL, path, sizeof(path))) { + printf("GetProcessImageFileName failed\n"); + return 1; + } + + _strlwr(path); + /* printf("%s\n", path); */ + + /* Check if we are running a buildbot version of Python. + + On Windows, this will always be a debug build from the + PCbuild directory. build\\PCbuild\\python_d.exe + + On Cygwin, the pathname is similar to other Unixes. + Use \\build\\python.exe to ensure we don't match + PCbuild\\python.exe which could be a normal instance + of Python running on vanilla Windows. + */ + if ((strstr(path, "build\\pcbuild\\python_d.exe") != NULL) || + (strstr(path, "\\build\\python.exe") != NULL)) { + printf("Terminating %s (pid %d)\n", path, pids[i]); + if (!TerminateProcess(hProcess, 1)) { + printf("Termination failed: %d\n", GetLastError()); + return 1; + } + return 0; + } + + CloseHandle(hProcess); + } +} diff --git a/sys/src/cmd/python/Tools/buildbot/kill_python.mak b/sys/src/cmd/python/Tools/buildbot/kill_python.mak new file mode 100644 index 000000000..6027d3f9b --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/kill_python.mak @@ -0,0 +1,2 @@ +kill_python.exe: kill_python.c + cl -nologo -o kill_python.exe kill_python.c psapi.lib diff --git a/sys/src/cmd/python/Tools/buildbot/test.bat b/sys/src/cmd/python/Tools/buildbot/test.bat new file mode 100644 index 000000000..c8b1937ca --- /dev/null +++ b/sys/src/cmd/python/Tools/buildbot/test.bat @@ -0,0 +1,3 @@ +@rem Used by the buildbot "test" step. +cd PCbuild +call rt.bat -d -q -uall -rw diff --git a/sys/src/cmd/python/Tools/compiler/ACKS b/sys/src/cmd/python/Tools/compiler/ACKS new file mode 100644 index 000000000..5f97b1554 --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/ACKS @@ -0,0 +1,8 @@ +Fred L. Drake, Jr. +Mark Hammond +Shane Hathaway +Neil Schemenauer +Evan Simpson +Greg Stein +Bill Tutt +Moshe Zadka diff --git a/sys/src/cmd/python/Tools/compiler/README b/sys/src/cmd/python/Tools/compiler/README new file mode 100644 index 000000000..1885dd946 --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/README @@ -0,0 +1,18 @@ +This directory contains support tools for the Python compiler package, +which is now part of the standard library. + +compile.py Demo that compiles a Python module into a .pyc file + using the pure-Python compiler code. + +demo.py Prints the names of all the methods defined in a module, + as a demonstration of walking through the abstract syntax + tree produced by the parser. + +dumppyc.py Dumps the contents of a .pyc file, printing + the attributes of the code object followed by a + code disassembly. + +regrtest.py Runs the Python test suite using bytecode generated + by the pure-Python compiler code instead of the + builtin compiler. + diff --git a/sys/src/cmd/python/Tools/compiler/ast.txt b/sys/src/cmd/python/Tools/compiler/ast.txt new file mode 100644 index 000000000..7968a5222 --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/ast.txt @@ -0,0 +1,104 @@ +# This file describes the nodes of the AST in ast.py. The module is +# generated by astgen.py. +# The descriptions use the following special notation to describe +# properties of the children: +# * this child is not a node +# ! this child is a sequence that contains nodes in it +# & this child may be set to None +# = ... a default value for the node constructor (optional args) +# +# If you add node types here, please be sure to update the list of +# Node types in Doc/lib/asttable.tex. +Module: doc*, node +Stmt: nodes! +Decorators: nodes! +Function: decorators&, name*, argnames*, defaults!, flags*, doc*, code +Lambda: argnames*, defaults!, flags*, code +Class: name*, bases!, doc*, code +Pass: +Break: +Continue: +For: assign, list, body, else_& +While: test, body, else_& +With: expr, vars&, body +If: tests!, else_& +IfExp: test, then, else_ +Exec: expr, locals&, globals& +From: modname*, names*, level* +Import: names* +Raise: expr1&, expr2&, expr3& +TryFinally: body, final +TryExcept: body, handlers!, else_& +Return: value +Yield: value +Const: value* +Print: nodes!, dest& +Printnl: nodes!, dest& +Discard: expr +AugAssign: node, op*, expr +Assign: nodes!, expr +AssTuple: nodes! +AssList: nodes! +AssName: name*, flags* +AssAttr: expr, attrname*, flags* +ListComp: expr, quals! +ListCompFor: assign, list, ifs! +ListCompIf: test +GenExpr: code +GenExprInner: expr, quals! +GenExprFor: assign, iter, ifs! +GenExprIf: test +List: nodes! +Dict: items! +Not: expr +Compare: expr, ops! +Name: name* +Global: names* +Backquote: expr +Getattr: expr, attrname* +CallFunc: node, args!, star_args& = None, dstar_args& = None +Keyword: name*, expr +Subscript: expr, flags*, subs! +Ellipsis: +Sliceobj: nodes! +Slice: expr, flags*, lower&, upper& +Assert: test, fail& +Tuple: nodes! +Or: nodes! +And: nodes! +Bitor: nodes! +Bitxor: nodes! +Bitand: nodes! +LeftShift: (left, right) +RightShift: (left, right) +Add: (left, right) +Sub: (left, right) +Mul: (left, right) +Div: (left, right) +Mod: (left, right) +Power: (left, right) +FloorDiv: (left, right) +UnaryAdd: expr +UnarySub: expr +Invert: expr + +init(Function): + self.varargs = self.kwargs = None + if flags & CO_VARARGS: + self.varargs = 1 + if flags & CO_VARKEYWORDS: + self.kwargs = 1 + +init(Lambda): + self.varargs = self.kwargs = None + if flags & CO_VARARGS: + self.varargs = 1 + if flags & CO_VARKEYWORDS: + self.kwargs = 1 + +init(GenExpr): + self.argnames = ['[outmost-iterable]'] + self.varargs = self.kwargs = None + +init(GenExprFor): + self.is_outmost = False diff --git a/sys/src/cmd/python/Tools/compiler/astgen.py b/sys/src/cmd/python/Tools/compiler/astgen.py new file mode 100644 index 000000000..59b98f2b0 --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/astgen.py @@ -0,0 +1,289 @@ +"""Generate ast module from specification + +This script generates the ast module from a simple specification, +which makes it easy to accomodate changes in the grammar. This +approach would be quite reasonable if the grammar changed often. +Instead, it is rather complex to generate the appropriate code. And +the Node interface has changed more often than the grammar. +""" + +import fileinput +import getopt +import re +import sys +from StringIO import StringIO + +SPEC = "ast.txt" +COMMA = ", " + +def load_boilerplate(file): + f = open(file) + buf = f.read() + f.close() + i = buf.find('### ''PROLOGUE') + j = buf.find('### ''EPILOGUE') + pro = buf[i+12:j].strip() + epi = buf[j+12:].strip() + return pro, epi + +def strip_default(arg): + """Return the argname from an 'arg = default' string""" + i = arg.find('=') + if i == -1: + return arg + t = arg[:i].strip() + return t + +P_NODE = 1 +P_OTHER = 2 +P_NESTED = 3 +P_NONE = 4 + +class NodeInfo: + """Each instance describes a specific AST node""" + def __init__(self, name, args): + self.name = name + self.args = args.strip() + self.argnames = self.get_argnames() + self.argprops = self.get_argprops() + self.nargs = len(self.argnames) + self.init = [] + + def get_argnames(self): + if '(' in self.args: + i = self.args.find('(') + j = self.args.rfind(')') + args = self.args[i+1:j] + else: + args = self.args + return [strip_default(arg.strip()) + for arg in args.split(',') if arg] + + def get_argprops(self): + """Each argument can have a property like '*' or '!' + + XXX This method modifies the argnames in place! + """ + d = {} + hardest_arg = P_NODE + for i in range(len(self.argnames)): + arg = self.argnames[i] + if arg.endswith('*'): + arg = self.argnames[i] = arg[:-1] + d[arg] = P_OTHER + hardest_arg = max(hardest_arg, P_OTHER) + elif arg.endswith('!'): + arg = self.argnames[i] = arg[:-1] + d[arg] = P_NESTED + hardest_arg = max(hardest_arg, P_NESTED) + elif arg.endswith('&'): + arg = self.argnames[i] = arg[:-1] + d[arg] = P_NONE + hardest_arg = max(hardest_arg, P_NONE) + else: + d[arg] = P_NODE + self.hardest_arg = hardest_arg + + if hardest_arg > P_NODE: + self.args = self.args.replace('*', '') + self.args = self.args.replace('!', '') + self.args = self.args.replace('&', '') + + return d + + def gen_source(self): + buf = StringIO() + print >> buf, "class %s(Node):" % self.name + self._gen_init(buf) + print >> buf + self._gen_getChildren(buf) + print >> buf + self._gen_getChildNodes(buf) + print >> buf + self._gen_repr(buf) + buf.seek(0, 0) + return buf.read() + + def _gen_init(self, buf): + if self.args: + print >> buf, " def __init__(self, %s, lineno=None):" % self.args + else: + print >> buf, " def __init__(self, lineno=None):" + if self.argnames: + for name in self.argnames: + print >> buf, " self.%s = %s" % (name, name) + print >> buf, " self.lineno = lineno" + # Copy the lines in self.init, indented four spaces. The rstrip() + # business is to get rid of the four spaces if line happens to be + # empty, so that reindent.py is happy with the output. + for line in self.init: + print >> buf, (" " + line).rstrip() + + def _gen_getChildren(self, buf): + print >> buf, " def getChildren(self):" + if len(self.argnames) == 0: + print >> buf, " return ()" + else: + if self.hardest_arg < P_NESTED: + clist = COMMA.join(["self.%s" % c + for c in self.argnames]) + if self.nargs == 1: + print >> buf, " return %s," % clist + else: + print >> buf, " return %s" % clist + else: + if len(self.argnames) == 1: + print >> buf, " return tuple(flatten(self.%s))" % self.argnames[0] + else: + print >> buf, " children = []" + template = " children.%s(%sself.%s%s)" + for name in self.argnames: + if self.argprops[name] == P_NESTED: + print >> buf, template % ("extend", "flatten(", + name, ")") + else: + print >> buf, template % ("append", "", name, "") + print >> buf, " return tuple(children)" + + def _gen_getChildNodes(self, buf): + print >> buf, " def getChildNodes(self):" + if len(self.argnames) == 0: + print >> buf, " return ()" + else: + if self.hardest_arg < P_NESTED: + clist = ["self.%s" % c + for c in self.argnames + if self.argprops[c] == P_NODE] + if len(clist) == 0: + print >> buf, " return ()" + elif len(clist) == 1: + print >> buf, " return %s," % clist[0] + else: + print >> buf, " return %s" % COMMA.join(clist) + else: + print >> buf, " nodelist = []" + template = " nodelist.%s(%sself.%s%s)" + for name in self.argnames: + if self.argprops[name] == P_NONE: + tmp = (" if self.%s is not None:\n" + " nodelist.append(self.%s)") + print >> buf, tmp % (name, name) + elif self.argprops[name] == P_NESTED: + print >> buf, template % ("extend", "flatten_nodes(", + name, ")") + elif self.argprops[name] == P_NODE: + print >> buf, template % ("append", "", name, "") + print >> buf, " return tuple(nodelist)" + + def _gen_repr(self, buf): + print >> buf, " def __repr__(self):" + if self.argnames: + fmt = COMMA.join(["%s"] * self.nargs) + if '(' in self.args: + fmt = '(%s)' % fmt + vals = ["repr(self.%s)" % name for name in self.argnames] + vals = COMMA.join(vals) + if self.nargs == 1: + vals = vals + "," + print >> buf, ' return "%s(%s)" %% (%s)' % \ + (self.name, fmt, vals) + else: + print >> buf, ' return "%s()"' % self.name + +rx_init = re.compile('init\((.*)\):') + +def parse_spec(file): + classes = {} + cur = None + for line in fileinput.input(file): + if line.strip().startswith('#'): + continue + mo = rx_init.search(line) + if mo is None: + if cur is None: + # a normal entry + try: + name, args = line.split(':') + except ValueError: + continue + classes[name] = NodeInfo(name, args) + cur = None + else: + # some code for the __init__ method + cur.init.append(line) + else: + # some extra code for a Node's __init__ method + name = mo.group(1) + cur = classes[name] + return sorted(classes.values(), key=lambda n: n.name) + +def main(): + prologue, epilogue = load_boilerplate(sys.argv[-1]) + print prologue + print + classes = parse_spec(SPEC) + for info in classes: + print info.gen_source() + print epilogue + +if __name__ == "__main__": + main() + sys.exit(0) + +### PROLOGUE +"""Python abstract syntax node definitions + +This file is automatically generated by Tools/compiler/astgen.py +""" +from consts import CO_VARARGS, CO_VARKEYWORDS + +def flatten(seq): + l = [] + for elt in seq: + t = type(elt) + if t is tuple or t is list: + for elt2 in flatten(elt): + l.append(elt2) + else: + l.append(elt) + return l + +def flatten_nodes(seq): + return [n for n in flatten(seq) if isinstance(n, Node)] + +nodes = {} + +class Node: + """Abstract base class for ast nodes.""" + def getChildren(self): + pass # implemented by subclasses + def __iter__(self): + for n in self.getChildren(): + yield n + def asList(self): # for backwards compatibility + return self.getChildren() + def getChildNodes(self): + pass # implemented by subclasses + +class EmptyNode(Node): + pass + +class Expression(Node): + # Expression is an artificial node class to support "eval" + nodes["expression"] = "Expression" + def __init__(self, node): + self.node = node + + def getChildren(self): + return self.node, + + def getChildNodes(self): + return self.node, + + def __repr__(self): + return "Expression(%s)" % (repr(self.node)) + +### EPILOGUE +for name, obj in globals().items(): + if isinstance(obj, type) and issubclass(obj, Node): + nodes[name.lower()] = obj diff --git a/sys/src/cmd/python/Tools/compiler/compile.py b/sys/src/cmd/python/Tools/compiler/compile.py new file mode 100644 index 000000000..9d50425d3 --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/compile.py @@ -0,0 +1,51 @@ +import sys +import getopt + +from compiler import compileFile, visitor + +import profile + +def main(): + VERBOSE = 0 + DISPLAY = 0 + PROFILE = 0 + CONTINUE = 0 + opts, args = getopt.getopt(sys.argv[1:], 'vqdcp') + for k, v in opts: + if k == '-v': + VERBOSE = 1 + visitor.ASTVisitor.VERBOSE = visitor.ASTVisitor.VERBOSE + 1 + if k == '-q': + if sys.platform[:3]=="win": + f = open('nul', 'wb') # /dev/null fails on Windows... + else: + f = open('/dev/null', 'wb') + sys.stdout = f + if k == '-d': + DISPLAY = 1 + if k == '-c': + CONTINUE = 1 + if k == '-p': + PROFILE = 1 + if not args: + print "no files to compile" + else: + for filename in args: + if VERBOSE: + print filename + try: + if PROFILE: + profile.run('compileFile(%r, %r)' % (filename, DISPLAY), + filename + ".prof") + else: + compileFile(filename, DISPLAY) + + except SyntaxError, err: + print err + if err.lineno is not None: + print err.lineno + if not CONTINUE: + sys.exit(-1) + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Tools/compiler/demo.py b/sys/src/cmd/python/Tools/compiler/demo.py new file mode 100755 index 000000000..61c54ee29 --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/demo.py @@ -0,0 +1,38 @@ +#! /usr/bin/env python + +"""Print names of all methods defined in module + +This script demonstrates use of the visitor interface of the compiler +package. +""" + +import compiler + +class MethodFinder: + """Print the names of all the methods + + Each visit method takes two arguments, the node and its current + scope. The scope is the name of the current class or None. + """ + + def visitClass(self, node, scope=None): + self.visit(node.code, node.name) + + def visitFunction(self, node, scope=None): + if scope is not None: + print "%s.%s" % (scope, node.name) + self.visit(node.code, None) + +def main(files): + mf = MethodFinder() + for file in files: + f = open(file) + buf = f.read() + f.close() + ast = compiler.parse(buf) + compiler.walk(ast, mf) + +if __name__ == "__main__": + import sys + + main(sys.argv[1:]) diff --git a/sys/src/cmd/python/Tools/compiler/dumppyc.py b/sys/src/cmd/python/Tools/compiler/dumppyc.py new file mode 100755 index 000000000..1258cce81 --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/dumppyc.py @@ -0,0 +1,47 @@ +#! /usr/bin/env python + +import marshal +import os +import dis +import types + +def dump(obj): + print obj + for attr in dir(obj): + if attr.startswith('co_'): + val = getattr(obj, attr) + print "\t", attr, repr(val) + +def loadCode(path): + f = open(path) + f.read(8) + co = marshal.load(f) + f.close() + return co + +def walk(co, match=None): + if match is None or co.co_name == match: + dump(co) + print + dis.dis(co) + for obj in co.co_consts: + if type(obj) == types.CodeType: + walk(obj, match) + +def load(filename, codename=None): + co = loadCode(filename) + walk(co, codename) + +if __name__ == "__main__": + import sys + if len(sys.argv) == 3: + filename, codename = sys.argv[1:] + else: + filename = sys.argv[1] + codename = None + if filename.endswith('.py'): + buf = open(filename).read() + co = compile(buf, filename, "exec") + walk(co) + else: + load(filename, codename) diff --git a/sys/src/cmd/python/Tools/compiler/regrtest.py b/sys/src/cmd/python/Tools/compiler/regrtest.py new file mode 100644 index 000000000..50d06e71f --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/regrtest.py @@ -0,0 +1,78 @@ +"""Run the Python regression test using the compiler + +This test runs the standard Python test suite using bytecode generated +by this compiler instead of by the builtin compiler. + +The regression test is run with the interpreter in verbose mode so +that import problems can be observed easily. +""" + +from compiler import compileFile + +import os +import sys +import test +import tempfile + +def copy_test_suite(): + dest = tempfile.mkdtemp() + os.system("cp -r %s/* %s" % (test.__path__[0], dest)) + print "Creating copy of test suite in", dest + return dest + +def copy_library(): + dest = tempfile.mkdtemp() + libdir = os.path.split(test.__path__[0])[0] + print "Found standard library in", libdir + print "Creating copy of standard library in", dest + os.system("cp -r %s/* %s" % (libdir, dest)) + return dest + +def compile_files(dir): + print "Compiling", dir, "\n\t", + line_len = 10 + for file in os.listdir(dir): + base, ext = os.path.splitext(file) + if ext == '.py': + source = os.path.join(dir, file) + line_len = line_len + len(file) + 1 + if line_len > 75: + print "\n\t", + line_len = len(source) + 9 + print file, + try: + compileFile(source) + except SyntaxError, err: + print err + continue + # make sure the .pyc file is not over-written + os.chmod(source + "c", 444) + elif file == 'CVS': + pass + else: + path = os.path.join(dir, file) + if os.path.isdir(path): + print + print + compile_files(path) + print "\t", + line_len = 10 + print + +def run_regrtest(lib_dir): + test_dir = os.path.join(lib_dir, "test") + os.chdir(test_dir) + os.system("PYTHONPATH=%s %s -v regrtest.py" % (lib_dir, sys.executable)) + +def cleanup(dir): + os.system("rm -rf %s" % dir) + +def main(): + lib_dir = copy_library() + compile_files(lib_dir) + run_regrtest(lib_dir) + raw_input("Cleanup?") + cleanup(lib_dir) + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Tools/compiler/stacktest.py b/sys/src/cmd/python/Tools/compiler/stacktest.py new file mode 100644 index 000000000..4f4b1611c --- /dev/null +++ b/sys/src/cmd/python/Tools/compiler/stacktest.py @@ -0,0 +1,43 @@ +import compiler +import dis +import types + +def extract_code_objects(co): + l = [co] + for const in co.co_consts: + if type(const) == types.CodeType: + l.append(const) + return l + +def compare(a, b): + if not (a.co_name == "?" or a.co_name.startswith('<lambda')): + assert a.co_name == b.co_name, (a, b) + if a.co_stacksize != b.co_stacksize: + print "stack mismatch %s: %d vs. %d" % (a.co_name, + a.co_stacksize, + b.co_stacksize) + if a.co_stacksize > b.co_stacksize: + print "good code" + dis.dis(a) + print "bad code" + dis.dis(b) + assert 0 + +def main(files): + for file in files: + print file + buf = open(file).read() + try: + co1 = compile(buf, file, "exec") + except SyntaxError: + print "skipped" + continue + co2 = compiler.compile(buf, file, "exec") + co1l = extract_code_objects(co1) + co2l = extract_code_objects(co2) + for a, b in zip(co1l, co2l): + compare(a, b) + +if __name__ == "__main__": + import sys + main(sys.argv[1:]) diff --git a/sys/src/cmd/python/Tools/faqwiz/README b/sys/src/cmd/python/Tools/faqwiz/README new file mode 100644 index 000000000..a1e4d4404 --- /dev/null +++ b/sys/src/cmd/python/Tools/faqwiz/README @@ -0,0 +1,114 @@ +FAQ Wizard +---------- + +Author: Guido van Rossum <guido@python.org> +Version: 1.0 +Date: 6 April 1998 + + +This is a CGI program that maintains a user-editable FAQ. It uses RCS +to keep track of changes to individual FAQ entries. It is fully +configurable; everything you might want to change when using this +program to maintain some other FAQ than the Python FAQ is contained in +the configuration module, faqconf.py. + +Note that the bulk of the code is not an executable script; it's an +importable module. The actual script in cgi-bin is minimal. + +Files: + +faqw.py executable script to be edited and installed in cgi-bin +faqwiz.py main module, lives in same directory as FAQ entry files +faqconf.py main configuration module +faqcust.py additional local customization module (optional) +move-faqwiz.sh Script to move faqwiz entries. + + +What's New? +----------- + +Version 1.0 corrects some minor bugs and uses tab-agnostic +indentation; it is otherwise unchanged from version 0.9.0. + +Version 0.9.0 uses the re module (Perl style regular expressions) for +all its regular expression needs, instead of the regex and regsub +modules (Emacs style). This affects the syntax for regular +expressions entered by the user as search strings (with "regular +expression" checked), hence the version number jump. + + +Setup Information +----------------- + +This assumes you are familiar with Python, with your http server, and +with running CGI scripts under your http server. You need Python 1.5 +or better. + +Select a place where the Python modules that constitute the FAQ wizard +will live (the directory where you unpacked it is an obvious choice). +This will be called the SRCDIR. This directory should not be writable +by other users of your system (since they would be able to execute +arbitrary code by invoking the FAQ wizard's CGI script). + +Create a dedicated working directory, preferably one that's not +directly reachable from your http server. This will be called the +FAQDIR. Create a subdirectory named RCS. Make both the working +directory and the RCS subdirectory wrld-writable. (This is essential, +since the FAQ wizard runs as use nobody, and needs to create +additional files here!) + +Edit faqconf.py to reflect your setup. You only need to edit the top +part, up till the line of all dashes. The comments should guide you +in your edits. (Actually, you can also choose to add your changes to +faqcust.py and leave faqconf.py alone. This is essential if you are +maintaining multiple FAQs; see below.) + +Don't forget to edit the SECTION_TITLES variables to reflect the set +of section titles for your FAQ! + +Next, edit faqw.py to reflect the pathname of your Python interpreter +and the values for SRCDIR and FAQDIR that you just chose. Then +install faqw.py in your cgi-bin directory. Make sure that it is +world-executable. You should now be able to connect to the FAQ wizard +by entering the following URL in your web client (subsituting the +appropriate host and port for "your.web.server", and perhaps +specifying a different directory for "cgi-bin" if local conventions so +dictate): + + http://your.web.server/cgi-bin/faqw.py + +If you are unable to get this working, check your server's error_log +file. The documentation for Python's cgi module in the Python Library +Reference Manual gives plentyu additional information about installing +and debugging CGI scripts, including setup debugging. This +documentation is repeated in the doc string in the cgi module; try +``import cgi; print cgi.__doc__''. + +Assuming this works, you should now be able to add the first entry to +your FAQ using the FAQ wizard interface. This creates a file +faq01.001.htp in your working directory and an RCS revision history +file faq01.001.htp,v in the RCS subdirectory. You can now exercise +the other FAQ wizard features (search, index, whole FAQ, what's new, +roulette, and so on). + + +Maintaining Multiple FAQs +------------------------- + +If you have multiple FAQs, you need a separate FAQDIR per FAQ, and a +different customization file per FAQ. The easiest thing to do would +be to have the faqcust.py for each FAQ live in the FAQDIR for that +FAQ, but that creates some security concerns, since the FAQDIR must be +world writable: *if* someone who breaks into your system (or a +legitimate user) manages to edit the faqcust.py file they can get +arbitrary code to execute through the FAQ wizard. Therefore, you will +need a more complex setup. + +The best way is probably to have a directory that is only writable by +you for each FAQ, where you place the copy of faqcust.py for that FAQ, +and have a world-writable subdirectory DATA for the data. You then +set FAQDIR to point to the DATA directory and change the faqw.py +bootstrap script to add FAQDIR/.. to sys.path (in front of SRCDIR, so +the dummy faqcust.py from SRCDIR is ignored). + +--Guido van Rossum (home page: http://www.python.org/~guido/) diff --git a/sys/src/cmd/python/Tools/faqwiz/faqconf.py b/sys/src/cmd/python/Tools/faqwiz/faqconf.py new file mode 100644 index 000000000..d1acd80c0 --- /dev/null +++ b/sys/src/cmd/python/Tools/faqwiz/faqconf.py @@ -0,0 +1,577 @@ +"""FAQ Wizard customization module. + +Edit this file to customize the FAQ Wizard. For normal purposes, you +should only have to change the FAQ section titles and the small group +of parameters below it. + +""" + +# Titles of FAQ sections + +SECTION_TITLES = { + # SectionNumber : SectionTitle; need at least one entry + 1: "General information and availability", +} + +# Parameters you definitely want to change + +SHORTNAME = "Generic" # FAQ name with "FAQ" omitted +PASSWORD = "" # Password for editing +OWNERNAME = "FAQ owner" # Name for feedback +OWNEREMAIL = "nobody@anywhere.org" # Email for feedback +HOMEURL = "http://www.python.org" # Related home page +HOMENAME = "Python home" # Name of related home page +RCSBINDIR = "/usr/local/bin/" # Directory containing RCS commands + # (must end in a slash) + +# Parameters you can normally leave alone + +MAXHITS = 10 # Max #hits to be shown directly +COOKIE_LIFETIME = 28*24*3600 # Cookie expiration in seconds + # (28*24*3600 = 28 days = 4 weeks) +PROCESS_PREFORMAT = 1 # toggle whether preformatted text + # will replace urls and emails with + # HTML links + +# Markers appended to title to indicate recently change +# (may contain HTML, e.g. <IMG>); and corresponding + +MARK_VERY_RECENT = " **" # Changed very recently +MARK_RECENT = " *" # Changed recently +DT_VERY_RECENT = 24*3600 # 24 hours +DT_RECENT = 7*24*3600 # 7 days + +EXPLAIN_MARKS = """ +<P>(Entries marked with ** were changed within the last 24 hours; +entries marked with * were changed within the last 7 days.) +<P> +""" + +# Version -- don't change unless you edit faqwiz.py + +WIZVERSION = "1.0.4" # FAQ Wizard version + +import os, sys +if os.name in ['nt',]: + # On NT we'll probably be running python from a batch file, + # so sys.argv[0] is not helpful + FAQCGI = 'faq.bat' # Relative URL of the FAQ cgi script + # LOGNAME is not typically set on NT + os.environ[ 'LOGNAME' ] = "FAQWizard" +else: + # This parameter is normally overwritten with a dynamic value + FAQCGI = 'faqw.py' # Relative URL of the FAQ cgi script + FAQCGI = os.path.basename(sys.argv[0]) or FAQCGI +del os, sys + +# Perl (re module) style regular expression to recognize FAQ entry +# files: group(1) should be the section number, group(2) should be the +# question number. Both should be fixed width so simple-minded +# sorting yields the right order. + +OKFILENAME = r"^faq(\d\d)\.(\d\d\d)\.htp$" + +# Format to construct a FAQ entry file name + +NEWFILENAME = "faq%02d.%03d.htp" + +# Load local customizations on top of the previous parameters + +try: + from faqcust import * +except ImportError: + pass + +# Calculated parameter names + +COOKIE_NAME = SHORTNAME + "-FAQ-Wizard" # Name used for Netscape cookie +FAQNAME = SHORTNAME + " FAQ" # Name of the FAQ + +# ---------------------------------------------------------------------- + +# Anything below this point normally needn't be changed; you would +# change this if you were to create e.g. a French translation or if +# you just aren't happy with the text generated by the FAQ Wizard. + +# Most strings here are subject to substitution (string%dictionary) + +# RCS commands + +import os +if os.name in ['nt', ]: + SH_RLOG = RCSBINDIR + "rlog %(file)s < NUL" + SH_RLOG_H = RCSBINDIR + "rlog -h %(file)s < NUL" + SH_RDIFF = RCSBINDIR + "rcsdiff -r%(prev)s -r%(rev)s %(file)s < NUL" + SH_REVISION = RCSBINDIR + "co -p%(rev)s %(file)s < NUL" + ### Have to use co -l, or the file is not marked rw on NT + SH_LOCK = RCSBINDIR + "co -l %(file)s < NUL" + SH_CHECKIN = RCSBINDIR + "ci -u %(file)s < %(tfn)s" +else: + SH_RLOG = RCSBINDIR + "rlog %(file)s </dev/null 2>&1" + SH_RLOG_H = RCSBINDIR + "rlog -h %(file)s </dev/null 2>&1" + SH_RDIFF = RCSBINDIR + "rcsdiff -r%(prev)s -r%(rev)s %(file)s </dev/null 2>&1" + SH_REVISION = RCSBINDIR + "co -p%(rev)s %(file)s </dev/null 2>&1" + SH_LOCK = RCSBINDIR + "rcs -l %(file)s </dev/null 2>&1" + SH_CHECKIN = RCSBINDIR + "ci -u %(file)s <%(tfn)s 2>&1" +del os + +# Titles for various output pages (not subject to substitution) + +T_HOME = FAQNAME + " Wizard " + WIZVERSION +T_ERROR = "Sorry, an error occurred" +T_ROULETTE = FAQNAME + " Roulette" +T_ALL = "The Whole " + FAQNAME +T_INDEX = FAQNAME + " Index" +T_SEARCH = FAQNAME + " Search Results" +T_RECENT = "What's New in the " + FAQNAME +T_SHOW = FAQNAME + " Entry" +T_LOG = "RCS log for %s entry" % FAQNAME +T_REVISION = "RCS revision for %s entry" % FAQNAME +T_DIFF = "RCS diff for %s entry" % FAQNAME +T_ADD = "Add an entry to the " + FAQNAME +T_DELETE = "Deleting an entry from the " + FAQNAME +T_EDIT = FAQNAME + " Edit Wizard" +T_REVIEW = T_EDIT + " - Review Changes" +T_COMMITTED = T_EDIT + " - Changes Committed" +T_COMMITFAILED = T_EDIT + " - Commit Failed" +T_CANTCOMMIT = T_EDIT + " - Commit Rejected" +T_HELP = T_EDIT + " - Help" + +# Generic prologue and epilogue + +PROLOGUE = ''' +<HTML> +<HEAD> +<TITLE>%(title)s</TITLE> +</HEAD> + +<BODY + BGCOLOR="#FFFFFF" + TEXT="#000000" + LINK="#AA0000" + VLINK="#906A6A"> +<H1>%(title)s</H1> +''' + +EPILOGUE = ''' +<HR> +<A HREF="%(HOMEURL)s">%(HOMENAME)s</A> / +<A HREF="%(FAQCGI)s?req=home">%(FAQNAME)s Wizard %(WIZVERSION)s</A> / +Feedback to <A HREF="mailto:%(OWNEREMAIL)s">%(OWNERNAME)s</A> + +</BODY> +</HTML> +''' + +# Home page + +HOME = """ +<H2>Search the %(FAQNAME)s:</H2> + +<BLOCKQUOTE> + +<FORM ACTION="%(FAQCGI)s"> + <INPUT TYPE=text NAME=query> + <INPUT TYPE=submit VALUE="Search"><BR> + <INPUT TYPE=radio NAME=querytype VALUE=simple CHECKED> + Simple string + / + <INPUT TYPE=radio NAME=querytype VALUE=regex> + Regular expression + /<BR> + <INPUT TYPE=radio NAME=querytype VALUE=anykeywords> + Keywords (any) + / + <INPUT TYPE=radio NAME=querytype VALUE=allkeywords> + Keywords (all) + <BR> + <INPUT TYPE=radio NAME=casefold VALUE=yes CHECKED> + Fold case + / + <INPUT TYPE=radio NAME=casefold VALUE=no> + Case sensitive + <BR> + <INPUT TYPE=hidden NAME=req VALUE=search> +</FORM> + +</BLOCKQUOTE> + +<HR> + +<H2>Other forms of %(FAQNAME)s access:</H2> + +<UL> +<LI><A HREF="%(FAQCGI)s?req=index">FAQ index</A> +<LI><A HREF="%(FAQCGI)s?req=all">The whole FAQ</A> +<LI><A HREF="%(FAQCGI)s?req=recent">What's new in the FAQ?</A> +<LI><A HREF="%(FAQCGI)s?req=roulette">FAQ roulette</A> +<LI><A HREF="%(FAQCGI)s?req=add">Add a FAQ entry</A> +<LI><A HREF="%(FAQCGI)s?req=delete">Delete a FAQ entry</A> +</UL> +""" + +# Index formatting + +INDEX_SECTION = """ +<P> +<HR> +<H2>%(sec)s. %(title)s</H2> +<UL> +""" + +INDEX_ADDSECTION = """ +<P> +<LI><A HREF="%(FAQCGI)s?req=new&amp;section=%(sec)s">Add new entry</A> +(at this point) +""" + +INDEX_ENDSECTION = """ +</UL> +""" + +INDEX_ENTRY = """\ +<LI><A HREF="%(FAQCGI)s?req=show&amp;file=%(file)s">%(title)s</A> +""" + +LOCAL_ENTRY = """\ +<LI><A HREF="#%(sec)s.%(num)s">%(title)s</A> +""" + +# Entry formatting + +ENTRY_HEADER1 = """ +<HR> +<H2><A NAME="%(sec)s.%(num)s">%(title)s</A>\ +""" + +ENTRY_HEADER2 = """\ +</H2> +""" + +ENTRY_FOOTER = """ +<A HREF="%(FAQCGI)s?req=edit&amp;file=%(file)s">Edit this entry</A> / +<A HREF="%(FAQCGI)s?req=log&amp;file=%(file)s">Log info</A> +""" + +ENTRY_LOGINFO = """ +/ Last changed on %(last_changed_date)s by +<A HREF="mailto:%(last_changed_email)s">%(last_changed_author)s</A> +""" + +# Search + +NO_HITS = """ +No hits. +""" + +ONE_HIT = """ +Your search matched the following entry: +""" + +FEW_HITS = """ +Your search matched the following %(count)s entries: +""" + +MANY_HITS = """ +Your search matched more than %(MAXHITS)s entries. +The %(count)s matching entries are presented here ordered by section: +""" + +# RCS log and diff + +LOG = """ +Click on a revision line to see the diff between that revision and the +previous one. +""" + +REVISIONLINK = """\ +<A HREF="%(FAQCGI)s?req=revision&amp;file=%(file)s&amp;rev=%(rev)s" +>%(line)s</A>\ +""" +DIFFLINK = """\ + (<A HREF="%(FAQCGI)s?req=diff&amp;file=%(file)s&amp;\ +prev=%(prev)s&amp;rev=%(rev)s" +>diff -r%(prev)s -r%(rev)s</A>)\ +""" + +# Recently changed entries + +NO_RECENT = """ +<HR> +No %(FAQNAME)s entries were changed in the last %(period)s. +""" + +VIEW_MENU = """ +<HR> +View entries changed in the last... +<UL> +<LI><A HREF="%(FAQCGI)s?req=recent&amp;days=1">24 hours</A> +<LI><A HREF="%(FAQCGI)s?req=recent&amp;days=2">2 days</A> +<LI><A HREF="%(FAQCGI)s?req=recent&amp;days=3">3 days</A> +<LI><A HREF="%(FAQCGI)s?req=recent&amp;days=7">week</A> +<LI><A HREF="%(FAQCGI)s?req=recent&amp;days=28">4 weeks</A> +<LI><A HREF="%(FAQCGI)s?req=recent&amp;days=365250">millennium</A> +</UL> +""" + +ONE_RECENT = VIEW_MENU + """ +The following %(FAQNAME)s entry was changed in the last %(period)s: +""" + +SOME_RECENT = VIEW_MENU + """ +The following %(count)s %(FAQNAME)s entries were changed +in the last %(period)s, most recently changed shown first: +""" + +TAIL_RECENT = VIEW_MENU + +# Last changed banner on "all" (strftime format) +LAST_CHANGED = "Last changed on %c %Z" + +# "Compat" command prologue (this has no <BODY> tag) +COMPAT = """ +<H1>The whole %(FAQNAME)s</H1> +See also the <A HREF="%(FAQCGI)s?req=home">%(FAQNAME)s Wizard</A>. +<P> +""" + +# Editing + +EDITHEAD = """ +<A HREF="%(FAQCGI)s?req=help">Click for Help</A> +""" + +REVIEWHEAD = EDITHEAD + + +EDITFORM1 = """ +<FORM ACTION="%(FAQCGI)s" METHOD=POST> +<INPUT TYPE=hidden NAME=req VALUE=review> +<INPUT TYPE=hidden NAME=file VALUE=%(file)s> +<INPUT TYPE=hidden NAME=editversion VALUE=%(editversion)s> +<HR> +""" + +EDITFORM2 = """ +Title: <INPUT TYPE=text SIZE=70 NAME=title VALUE="%(title)s"><BR> +<TEXTAREA COLS=72 ROWS=20 NAME=body>%(body)s +</TEXTAREA><BR> +Log message (reason for the change):<BR> +<TEXTAREA COLS=72 ROWS=5 NAME=log>%(log)s +</TEXTAREA><BR> +Please provide the following information for logging purposes: +<TABLE FRAME=none COLS=2> + <TR> + <TD>Name: + <TD><INPUT TYPE=text SIZE=40 NAME=author VALUE="%(author)s"> + <TR> + <TD>Email: + <TD><INPUT TYPE=text SIZE=40 NAME=email VALUE="%(email)s"> + <TR> + <TD>Password: + <TD><INPUT TYPE=password SIZE=20 NAME=password VALUE="%(password)s"> +</TABLE> + +<INPUT TYPE=submit NAME=review VALUE="Preview Edit"> +Click this button to preview your changes. +""" + +EDITFORM3 = """ +</FORM> +""" + +COMMIT = """ +<INPUT TYPE=submit NAME=commit VALUE="Commit"> +Click this button to commit your changes. +<HR> +""" + +NOCOMMIT_HEAD = """ +To commit your changes, please correct the following errors in the +form below and click the Preview Edit button. +<UL> +""" +NOCOMMIT_TAIL = """ +</UL> +<HR> +""" + +CANTCOMMIT_HEAD = """ +Some required information is missing: +<UL> +""" +NEED_PASSWD = "<LI>You must provide the correct password.\n" +NEED_AUTHOR = "<LI>You must enter your name.\n" +NEED_EMAIL = "<LI>You must enter your email address.\n" +NEED_LOG = "<LI>You must enter a log message.\n" +CANTCOMMIT_TAIL = """ +</UL> +Please use your browser's Back command to correct the form and commit +again. +""" + +NEWCONFLICT = """ +<P> +You are creating a new entry, but the entry number specified is not +correct. +<P> +The two most common causes of this problem are: +<UL> +<LI>After creating the entry yourself, you went back in your browser, + edited the entry some more, and clicked Commit again. +<LI>Someone else started creating a new entry in the same section and + committed before you did. +</UL> +(It is also possible that the last entry in the section was physically +deleted, but this should not happen except through manual intervention +by the FAQ maintainer.) +<P> +<A HREF="%(FAQCGI)s?req=new&amp;section=%(sec)s">Click here to try +again.</A> +<P> +""" + +VERSIONCONFLICT = """ +<P> +You edited version %(editversion)s but the current version is %(version)s. +<P> +The two most common causes of this problem are: +<UL> +<LI>After committing a change, you went back in your browser, + edited the entry some more, and clicked Commit again. +<LI>Someone else started editing the same entry and committed + before you did. +</UL> +<P> +<A HREF="%(FAQCGI)s?req=show&amp;file=%(file)s">Click here to reload +the entry and try again.</A> +<P> +""" + +CANTWRITE = """ +Can't write file %(file)s (%(why)s). +""" + +FILEHEADER = """\ +Title: %(title)s +Last-Changed-Date: %(date)s +Last-Changed-Author: %(author)s +Last-Changed-Email: %(email)s +Last-Changed-Remote-Host: %(REMOTE_HOST)s +Last-Changed-Remote-Address: %(REMOTE_ADDR)s +""" + +LOGHEADER = """\ +Last-Changed-Date: %(date)s +Last-Changed-Author: %(author)s +Last-Changed-Email: %(email)s +Last-Changed-Remote-Host: %(REMOTE_HOST)s +Last-Changed-Remote-Address: %(REMOTE_ADDR)s + +%(log)s +""" + +COMMITTED = """ +Your changes have been committed. +""" + +COMMITFAILED = """ +Exit status %(sts)s. +""" + +# Add/Delete + +ADD_HEAD = """ +At the moment, new entries can only be added at the end of a section. +This is because the entry numbers are also their +unique identifiers -- it's a bad idea to renumber entries. +<P> +Click on the section to which you want to add a new entry: +<UL> +""" + +ADD_SECTION = """\ +<LI><A HREF="%(FAQCGI)s?req=new&amp;section=%(section)s">%(section)s. %(title)s</A> +""" + +ADD_TAIL = """ +</UL> +""" + +ROULETTE = """ +<P>Hit your browser's Reload button to play again.<P> +""" + +DELETE = """ +At the moment, there's no direct way to delete entries. +This is because the entry numbers are also their +unique identifiers -- it's a bad idea to renumber entries. +<P> +If you really think an entry needs to be deleted, +change the title to "(deleted)" and make the body +empty (keep the entry number in the title though). +""" + +# Help file for the FAQ Edit Wizard + +HELP = """ +Using the %(FAQNAME)s Edit Wizard speaks mostly for itself. Here are +some answers to questions you are likely to ask: + +<P><HR> + +<H2>I can review an entry but I can't commit it.</H2> + +The commit button only appears if the following conditions are met: + +<UL> + +<LI>The Name field is not empty. + +<LI>The Email field contains at least an @ character. + +<LI>The Log message box is not empty. + +<LI>The Password field contains the proper password. + +</UL> + +<P><HR> + +<H2>What is the password?</H2> + +At the moment, only PSA members will be told the password. This is a +good time to join the PSA! See <A +HREF="http://www.python.org/psa/">the PSA home page</A>. + +<P><HR> + +<H2>Can I use HTML in the FAQ entry?</H2> + +Yes, if you include it in &lt;HTML&rt; and &lt;/HTML&gt; tags. +<P> +Also, if you include a URL or an email address in the text it will +automatigally become an anchor of the right type. Also, *word* +is made italic (but only for single alphabetic words). + +<P><HR> + +<H2>How do I delineate paragraphs?</H2> + +Use blank lines to separate paragraphs. + +<P><HR> + +<H2>How do I enter example text?</H2> + +Any line that begins with a space or tab is assumed to be part of +literal text. Blocks of literal text delineated by blank lines are +placed inside &lt;PRE&gt;...&lt;/PRE&gt;. +""" + +# Load local customizations again, in case they set some other variables + +try: + from faqcust import * +except ImportError: + pass diff --git a/sys/src/cmd/python/Tools/faqwiz/faqcust.py b/sys/src/cmd/python/Tools/faqwiz/faqcust.py new file mode 100644 index 000000000..8f1678188 --- /dev/null +++ b/sys/src/cmd/python/Tools/faqwiz/faqcust.py @@ -0,0 +1 @@ +# Add your customizations here -- modified copies of what's in faqconf.py. diff --git a/sys/src/cmd/python/Tools/faqwiz/faqw.py b/sys/src/cmd/python/Tools/faqwiz/faqw.py new file mode 100755 index 000000000..a26e0d60e --- /dev/null +++ b/sys/src/cmd/python/Tools/faqwiz/faqw.py @@ -0,0 +1,33 @@ +#! /usr/local/bin/python + +"""FAQ wizard bootstrap.""" + +# This is a longer version of the bootstrap script given at the end of +# faqwin.py; it prints timing statistics at the end of the regular CGI +# script's output (so you can monitor how it is doing). + +# This script should be placed in your cgi-bin directory and made +# executable. + +# You need to edit the first line and the lines that define FAQDIR and +# SRCDIR, below: change /usr/local/bin/python to where your Python +# interpreter lives, change the value for FAQDIR to where your FAQ +# lives, and change the value for SRCDIR to where your faqwiz.py +# module lives. The faqconf.py and faqcust.py files live there, too. + +import os +t1 = os.times() # If this doesn't work, just get rid of the timing code! +try: + FAQDIR = "/usr/people/guido/python/FAQ" + SRCDIR = "/usr/people/guido/python/src/Tools/faqwiz" + import os, sys, time, operator + os.chdir(FAQDIR) + sys.path.insert(0, SRCDIR) + import faqwiz +except SystemExit, n: + sys.exit(n) +except: + t, v, tb = sys.exc_info() + print + import cgi + cgi.print_exception(t, v, tb) diff --git a/sys/src/cmd/python/Tools/faqwiz/faqwiz.py b/sys/src/cmd/python/Tools/faqwiz/faqwiz.py new file mode 100644 index 000000000..bdd270c38 --- /dev/null +++ b/sys/src/cmd/python/Tools/faqwiz/faqwiz.py @@ -0,0 +1,841 @@ +"""Generic FAQ Wizard. + +This is a CGI program that maintains a user-editable FAQ. It uses RCS +to keep track of changes to individual FAQ entries. It is fully +configurable; everything you might want to change when using this +program to maintain some other FAQ than the Python FAQ is contained in +the configuration module, faqconf.py. + +Note that this is not an executable script; it's an importable module. +The actual script to place in cgi-bin is faqw.py. + +""" + +import sys, time, os, stat, re, cgi, faqconf +from faqconf import * # This imports all uppercase names +now = time.time() + +class FileError: + def __init__(self, file): + self.file = file + +class InvalidFile(FileError): + pass + +class NoSuchSection(FileError): + def __init__(self, section): + FileError.__init__(self, NEWFILENAME %(section, 1)) + self.section = section + +class NoSuchFile(FileError): + def __init__(self, file, why=None): + FileError.__init__(self, file) + self.why = why + +def escape(s): + s = s.replace('&', '&amp;') + s = s.replace('<', '&lt;') + s = s.replace('>', '&gt;') + return s + +def escapeq(s): + s = escape(s) + s = s.replace('"', '&quot;') + return s + +def _interpolate(format, args, kw): + try: + quote = kw['_quote'] + except KeyError: + quote = 1 + d = (kw,) + args + (faqconf.__dict__,) + m = MagicDict(d, quote) + return format % m + +def interpolate(format, *args, **kw): + return _interpolate(format, args, kw) + +def emit(format, *args, **kw): + try: + f = kw['_file'] + except KeyError: + f = sys.stdout + f.write(_interpolate(format, args, kw)) + +translate_prog = None + +def translate(text, pre=0): + global translate_prog + if not translate_prog: + translate_prog = prog = re.compile( + r'\b(http|ftp|https)://\S+(\b|/)|\b[-.\w]+@[-.\w]+') + else: + prog = translate_prog + i = 0 + list = [] + while 1: + m = prog.search(text, i) + if not m: + break + j = m.start() + list.append(escape(text[i:j])) + i = j + url = m.group(0) + while url[-1] in '();:,.?\'"<>': + url = url[:-1] + i = i + len(url) + url = escape(url) + if not pre or (pre and PROCESS_PREFORMAT): + if ':' in url: + repl = '<A HREF="%s">%s</A>' % (url, url) + else: + repl = '<A HREF="mailto:%s">%s</A>' % (url, url) + else: + repl = url + list.append(repl) + j = len(text) + list.append(escape(text[i:j])) + return ''.join(list) + +def emphasize(line): + return re.sub(r'\*([a-zA-Z]+)\*', r'<I>\1</I>', line) + +revparse_prog = None + +def revparse(rev): + global revparse_prog + if not revparse_prog: + revparse_prog = re.compile(r'^(\d{1,3})\.(\d{1,4})$') + m = revparse_prog.match(rev) + if not m: + return None + [major, minor] = map(int, m.group(1, 2)) + return major, minor + +logon = 0 +def log(text): + if logon: + logfile = open("logfile", "a") + logfile.write(text + "\n") + logfile.close() + +def load_cookies(): + if not os.environ.has_key('HTTP_COOKIE'): + return {} + raw = os.environ['HTTP_COOKIE'] + words = [s.strip() for s in raw.split(';')] + cookies = {} + for word in words: + i = word.find('=') + if i >= 0: + key, value = word[:i], word[i+1:] + cookies[key] = value + return cookies + +def load_my_cookie(): + cookies = load_cookies() + try: + value = cookies[COOKIE_NAME] + except KeyError: + return {} + import urllib + value = urllib.unquote(value) + words = value.split('/') + while len(words) < 3: + words.append('') + author = '/'.join(words[:-2]) + email = words[-2] + password = words[-1] + return {'author': author, + 'email': email, + 'password': password} + +def send_my_cookie(ui): + name = COOKIE_NAME + value = "%s/%s/%s" % (ui.author, ui.email, ui.password) + import urllib + value = urllib.quote(value) + then = now + COOKIE_LIFETIME + gmt = time.gmtime(then) + path = os.environ.get('SCRIPT_NAME', '/cgi-bin/') + print "Set-Cookie: %s=%s; path=%s;" % (name, value, path), + print time.strftime("expires=%a, %d-%b-%y %X GMT", gmt) + +class MagicDict: + + def __init__(self, d, quote): + self.__d = d + self.__quote = quote + + def __getitem__(self, key): + for d in self.__d: + try: + value = d[key] + if value: + value = str(value) + if self.__quote: + value = escapeq(value) + return value + except KeyError: + pass + return '' + +class UserInput: + + def __init__(self): + self.__form = cgi.FieldStorage() + #log("\n\nbody: " + self.body) + + def __getattr__(self, name): + if name[0] == '_': + raise AttributeError + try: + value = self.__form[name].value + except (TypeError, KeyError): + value = '' + else: + value = value.strip() + setattr(self, name, value) + return value + + def __getitem__(self, key): + return getattr(self, key) + +class FaqEntry: + + def __init__(self, fp, file, sec_num): + self.file = file + self.sec, self.num = sec_num + if fp: + import rfc822 + self.__headers = rfc822.Message(fp) + self.body = fp.read().strip() + else: + self.__headers = {'title': "%d.%d. " % sec_num} + self.body = '' + + def __getattr__(self, name): + if name[0] == '_': + raise AttributeError + key = '-'.join(name.split('_')) + try: + value = self.__headers[key] + except KeyError: + value = '' + setattr(self, name, value) + return value + + def __getitem__(self, key): + return getattr(self, key) + + def load_version(self): + command = interpolate(SH_RLOG_H, self) + p = os.popen(command) + version = '' + while 1: + line = p.readline() + if not line: + break + if line[:5] == 'head:': + version = line[5:].strip() + p.close() + self.version = version + + def getmtime(self): + if not self.last_changed_date: + return 0 + try: + return os.stat(self.file)[stat.ST_MTIME] + except os.error: + return 0 + + def emit_marks(self): + mtime = self.getmtime() + if mtime >= now - DT_VERY_RECENT: + emit(MARK_VERY_RECENT, self) + elif mtime >= now - DT_RECENT: + emit(MARK_RECENT, self) + + def show(self, edit=1): + emit(ENTRY_HEADER1, self) + self.emit_marks() + emit(ENTRY_HEADER2, self) + pre = 0 + raw = 0 + for line in self.body.split('\n'): + # Allow the user to insert raw html into a FAQ answer + # (Skip Montanaro, with changes by Guido) + tag = line.rstrip().lower() + if tag == '<html>': + raw = 1 + continue + if tag == '</html>': + raw = 0 + continue + if raw: + print line + continue + if not line.strip(): + if pre: + print '</PRE>' + pre = 0 + else: + print '<P>' + else: + if not line[0].isspace(): + if pre: + print '</PRE>' + pre = 0 + else: + if not pre: + print '<PRE>' + pre = 1 + if '/' in line or '@' in line: + line = translate(line, pre) + elif '<' in line or '&' in line: + line = escape(line) + if not pre and '*' in line: + line = emphasize(line) + print line + if pre: + print '</PRE>' + pre = 0 + if edit: + print '<P>' + emit(ENTRY_FOOTER, self) + if self.last_changed_date: + emit(ENTRY_LOGINFO, self) + print '<P>' + +class FaqDir: + + entryclass = FaqEntry + + __okprog = re.compile(OKFILENAME) + + def __init__(self, dir=os.curdir): + self.__dir = dir + self.__files = None + + def __fill(self): + if self.__files is not None: + return + self.__files = files = [] + okprog = self.__okprog + for file in os.listdir(self.__dir): + if self.__okprog.match(file): + files.append(file) + files.sort() + + def good(self, file): + return self.__okprog.match(file) + + def parse(self, file): + m = self.good(file) + if not m: + return None + sec, num = m.group(1, 2) + return int(sec), int(num) + + def list(self): + # XXX Caller shouldn't modify result + self.__fill() + return self.__files + + def open(self, file): + sec_num = self.parse(file) + if not sec_num: + raise InvalidFile(file) + try: + fp = open(file) + except IOError, msg: + raise NoSuchFile(file, msg) + try: + return self.entryclass(fp, file, sec_num) + finally: + fp.close() + + def show(self, file, edit=1): + self.open(file).show(edit=edit) + + def new(self, section): + if not SECTION_TITLES.has_key(section): + raise NoSuchSection(section) + maxnum = 0 + for file in self.list(): + sec, num = self.parse(file) + if sec == section: + maxnum = max(maxnum, num) + sec_num = (section, maxnum+1) + file = NEWFILENAME % sec_num + return self.entryclass(None, file, sec_num) + +class FaqWizard: + + def __init__(self): + self.ui = UserInput() + self.dir = FaqDir() + + def go(self): + print 'Content-type: text/html' + req = self.ui.req or 'home' + mname = 'do_%s' % req + try: + meth = getattr(self, mname) + except AttributeError: + self.error("Bad request type %r." % (req,)) + else: + try: + meth() + except InvalidFile, exc: + self.error("Invalid entry file name %s" % exc.file) + except NoSuchFile, exc: + self.error("No entry with file name %s" % exc.file) + except NoSuchSection, exc: + self.error("No section number %s" % exc.section) + self.epilogue() + + def error(self, message, **kw): + self.prologue(T_ERROR) + emit(message, kw) + + def prologue(self, title, entry=None, **kw): + emit(PROLOGUE, entry, kwdict=kw, title=escape(title)) + + def epilogue(self): + emit(EPILOGUE) + + def do_home(self): + self.prologue(T_HOME) + emit(HOME) + + def do_debug(self): + self.prologue("FAQ Wizard Debugging") + form = cgi.FieldStorage() + cgi.print_form(form) + cgi.print_environ(os.environ) + cgi.print_directory() + cgi.print_arguments() + + def do_search(self): + query = self.ui.query + if not query: + self.error("Empty query string!") + return + if self.ui.querytype == 'simple': + query = re.escape(query) + queries = [query] + elif self.ui.querytype in ('anykeywords', 'allkeywords'): + words = filter(None, re.split('\W+', query)) + if not words: + self.error("No keywords specified!") + return + words = map(lambda w: r'\b%s\b' % w, words) + if self.ui.querytype[:3] == 'any': + queries = ['|'.join(words)] + else: + # Each of the individual queries must match + queries = words + else: + # Default to regular expression + queries = [query] + self.prologue(T_SEARCH) + progs = [] + for query in queries: + if self.ui.casefold == 'no': + p = re.compile(query) + else: + p = re.compile(query, re.IGNORECASE) + progs.append(p) + hits = [] + for file in self.dir.list(): + try: + entry = self.dir.open(file) + except FileError: + constants + for p in progs: + if not p.search(entry.title) and not p.search(entry.body): + break + else: + hits.append(file) + if not hits: + emit(NO_HITS, self.ui, count=0) + elif len(hits) <= MAXHITS: + if len(hits) == 1: + emit(ONE_HIT, count=1) + else: + emit(FEW_HITS, count=len(hits)) + self.format_all(hits, headers=0) + else: + emit(MANY_HITS, count=len(hits)) + self.format_index(hits) + + def do_all(self): + self.prologue(T_ALL) + files = self.dir.list() + self.last_changed(files) + self.format_index(files, localrefs=1) + self.format_all(files) + + def do_compat(self): + files = self.dir.list() + emit(COMPAT) + self.last_changed(files) + self.format_index(files, localrefs=1) + self.format_all(files, edit=0) + sys.exit(0) # XXX Hack to suppress epilogue + + def last_changed(self, files): + latest = 0 + for file in files: + entry = self.dir.open(file) + if entry: + mtime = mtime = entry.getmtime() + if mtime > latest: + latest = mtime + print time.strftime(LAST_CHANGED, time.localtime(latest)) + emit(EXPLAIN_MARKS) + + def format_all(self, files, edit=1, headers=1): + sec = 0 + for file in files: + try: + entry = self.dir.open(file) + except NoSuchFile: + continue + if headers and entry.sec != sec: + sec = entry.sec + try: + title = SECTION_TITLES[sec] + except KeyError: + title = "Untitled" + emit("\n<HR>\n<H1>%(sec)s. %(title)s</H1>\n", + sec=sec, title=title) + entry.show(edit=edit) + + def do_index(self): + self.prologue(T_INDEX) + files = self.dir.list() + self.last_changed(files) + self.format_index(files, add=1) + + def format_index(self, files, add=0, localrefs=0): + sec = 0 + for file in files: + try: + entry = self.dir.open(file) + except NoSuchFile: + continue + if entry.sec != sec: + if sec: + if add: + emit(INDEX_ADDSECTION, sec=sec) + emit(INDEX_ENDSECTION, sec=sec) + sec = entry.sec + try: + title = SECTION_TITLES[sec] + except KeyError: + title = "Untitled" + emit(INDEX_SECTION, sec=sec, title=title) + if localrefs: + emit(LOCAL_ENTRY, entry) + else: + emit(INDEX_ENTRY, entry) + entry.emit_marks() + if sec: + if add: + emit(INDEX_ADDSECTION, sec=sec) + emit(INDEX_ENDSECTION, sec=sec) + + def do_recent(self): + if not self.ui.days: + days = 1 + else: + days = float(self.ui.days) + try: + cutoff = now - days * 24 * 3600 + except OverflowError: + cutoff = 0 + list = [] + for file in self.dir.list(): + entry = self.dir.open(file) + if not entry: + continue + mtime = entry.getmtime() + if mtime >= cutoff: + list.append((mtime, file)) + list.sort() + list.reverse() + self.prologue(T_RECENT) + if days <= 1: + period = "%.2g hours" % (days*24) + else: + period = "%.6g days" % days + if not list: + emit(NO_RECENT, period=period) + elif len(list) == 1: + emit(ONE_RECENT, period=period) + else: + emit(SOME_RECENT, period=period, count=len(list)) + self.format_all(map(lambda (mtime, file): file, list), headers=0) + emit(TAIL_RECENT) + + def do_roulette(self): + import random + files = self.dir.list() + if not files: + self.error("No entries.") + return + file = random.choice(files) + self.prologue(T_ROULETTE) + emit(ROULETTE) + self.dir.show(file) + + def do_help(self): + self.prologue(T_HELP) + emit(HELP) + + def do_show(self): + entry = self.dir.open(self.ui.file) + self.prologue(T_SHOW) + entry.show() + + def do_add(self): + self.prologue(T_ADD) + emit(ADD_HEAD) + sections = SECTION_TITLES.items() + sections.sort() + for section, title in sections: + emit(ADD_SECTION, section=section, title=title) + emit(ADD_TAIL) + + def do_delete(self): + self.prologue(T_DELETE) + emit(DELETE) + + def do_log(self): + entry = self.dir.open(self.ui.file) + self.prologue(T_LOG, entry) + emit(LOG, entry) + self.rlog(interpolate(SH_RLOG, entry), entry) + + def rlog(self, command, entry=None): + output = os.popen(command).read() + sys.stdout.write('<PRE>') + athead = 0 + lines = output.split('\n') + while lines and not lines[-1]: + del lines[-1] + if lines: + line = lines[-1] + if line[:1] == '=' and len(line) >= 40 and \ + line == line[0]*len(line): + del lines[-1] + headrev = None + for line in lines: + if entry and athead and line[:9] == 'revision ': + rev = line[9:].split() + mami = revparse(rev) + if not mami: + print line + else: + emit(REVISIONLINK, entry, rev=rev, line=line) + if mami[1] > 1: + prev = "%d.%d" % (mami[0], mami[1]-1) + emit(DIFFLINK, entry, prev=prev, rev=rev) + if headrev: + emit(DIFFLINK, entry, prev=rev, rev=headrev) + else: + headrev = rev + print + athead = 0 + else: + athead = 0 + if line[:1] == '-' and len(line) >= 20 and \ + line == len(line) * line[0]: + athead = 1 + sys.stdout.write('<HR>') + else: + print line + print '</PRE>' + + def do_revision(self): + entry = self.dir.open(self.ui.file) + rev = self.ui.rev + mami = revparse(rev) + if not mami: + self.error("Invalid revision number: %r." % (rev,)) + self.prologue(T_REVISION, entry) + self.shell(interpolate(SH_REVISION, entry, rev=rev)) + + def do_diff(self): + entry = self.dir.open(self.ui.file) + prev = self.ui.prev + rev = self.ui.rev + mami = revparse(rev) + if not mami: + self.error("Invalid revision number: %r." % (rev,)) + if prev: + if not revparse(prev): + self.error("Invalid previous revision number: %r." % (prev,)) + else: + prev = '%d.%d' % (mami[0], mami[1]) + self.prologue(T_DIFF, entry) + self.shell(interpolate(SH_RDIFF, entry, rev=rev, prev=prev)) + + def shell(self, command): + output = os.popen(command).read() + sys.stdout.write('<PRE>') + print escape(output) + print '</PRE>' + + def do_new(self): + entry = self.dir.new(section=int(self.ui.section)) + entry.version = '*new*' + self.prologue(T_EDIT) + emit(EDITHEAD) + emit(EDITFORM1, entry, editversion=entry.version) + emit(EDITFORM2, entry, load_my_cookie()) + emit(EDITFORM3) + entry.show(edit=0) + + def do_edit(self): + entry = self.dir.open(self.ui.file) + entry.load_version() + self.prologue(T_EDIT) + emit(EDITHEAD) + emit(EDITFORM1, entry, editversion=entry.version) + emit(EDITFORM2, entry, load_my_cookie()) + emit(EDITFORM3) + entry.show(edit=0) + + def do_review(self): + send_my_cookie(self.ui) + if self.ui.editversion == '*new*': + sec, num = self.dir.parse(self.ui.file) + entry = self.dir.new(section=sec) + entry.version = "*new*" + if entry.file != self.ui.file: + self.error("Commit version conflict!") + emit(NEWCONFLICT, self.ui, sec=sec, num=num) + return + else: + entry = self.dir.open(self.ui.file) + entry.load_version() + # Check that the FAQ entry number didn't change + if self.ui.title.split()[:1] != entry.title.split()[:1]: + self.error("Don't change the entry number please!") + return + # Check that the edited version is the current version + if entry.version != self.ui.editversion: + self.error("Commit version conflict!") + emit(VERSIONCONFLICT, entry, self.ui) + return + commit_ok = ((not PASSWORD + or self.ui.password == PASSWORD) + and self.ui.author + and '@' in self.ui.email + and self.ui.log) + if self.ui.commit: + if not commit_ok: + self.cantcommit() + else: + self.commit(entry) + return + self.prologue(T_REVIEW) + emit(REVIEWHEAD) + entry.body = self.ui.body + entry.title = self.ui.title + entry.show(edit=0) + emit(EDITFORM1, self.ui, entry) + if commit_ok: + emit(COMMIT) + else: + emit(NOCOMMIT_HEAD) + self.errordetail() + emit(NOCOMMIT_TAIL) + emit(EDITFORM2, self.ui, entry, load_my_cookie()) + emit(EDITFORM3) + + def cantcommit(self): + self.prologue(T_CANTCOMMIT) + print CANTCOMMIT_HEAD + self.errordetail() + print CANTCOMMIT_TAIL + + def errordetail(self): + if PASSWORD and self.ui.password != PASSWORD: + emit(NEED_PASSWD) + if not self.ui.log: + emit(NEED_LOG) + if not self.ui.author: + emit(NEED_AUTHOR) + if not self.ui.email: + emit(NEED_EMAIL) + + def commit(self, entry): + file = entry.file + # Normalize line endings in body + if '\r' in self.ui.body: + self.ui.body = re.sub('\r\n?', '\n', self.ui.body) + # Normalize whitespace in title + self.ui.title = ' '.join(self.ui.title.split()) + # Check that there were any changes + if self.ui.body == entry.body and self.ui.title == entry.title: + self.error("You didn't make any changes!") + return + + # need to lock here because otherwise the file exists and is not writable (on NT) + command = interpolate(SH_LOCK, file=file) + p = os.popen(command) + output = p.read() + + try: + os.unlink(file) + except os.error: + pass + try: + f = open(file, 'w') + except IOError, why: + self.error(CANTWRITE, file=file, why=why) + return + date = time.ctime(now) + emit(FILEHEADER, self.ui, os.environ, date=date, _file=f, _quote=0) + f.write('\n') + f.write(self.ui.body) + f.write('\n') + f.close() + + import tempfile + tf = tempfile.NamedTemporaryFile() + emit(LOGHEADER, self.ui, os.environ, date=date, _file=tf) + tf.flush() + tf.seek(0) + + command = interpolate(SH_CHECKIN, file=file, tfn=tf.name) + log("\n\n" + command) + p = os.popen(command) + output = p.read() + sts = p.close() + log("output: " + output) + log("done: " + str(sts)) + log("TempFile:\n" + tf.read() + "end") + + if not sts: + self.prologue(T_COMMITTED) + emit(COMMITTED) + else: + self.error(T_COMMITFAILED) + emit(COMMITFAILED, sts=sts) + print '<PRE>%s</PRE>' % escape(output) + + try: + os.unlink(tf.name) + except os.error: + pass + + entry = self.dir.open(file) + entry.show() + +wiz = FaqWizard() +wiz.go() diff --git a/sys/src/cmd/python/Tools/faqwiz/move-faqwiz.sh b/sys/src/cmd/python/Tools/faqwiz/move-faqwiz.sh new file mode 100755 index 000000000..6a708aa25 --- /dev/null +++ b/sys/src/cmd/python/Tools/faqwiz/move-faqwiz.sh @@ -0,0 +1,49 @@ +#!/bin/sh +# +# Christian Reis <kiko@async.com.br> +# +# Moves +# +# Example: +# +# blackjesus:~> ./move-faqwiz.sh 2\.1 3\.2 +# Moving FAQ question 02.001 to 03.002 + +if [ x$2 == x ]; then + echo "Need 2 args: original_version final_version." + exit 2 +fi + +if [ ! -d data -o ! -d data/RCS ]; then + echo "Run this inside the faqwiz data/ directory's parent dir." + exit 2 +fi + +function cut_n_pad() { + t=`echo $1 | cut -d. -f $2` + export $3=`echo $t | awk "{ tmp = \\$0; l = length(tmp); for (i = 0; i < $2-l+1; i++) { tmp = "0".tmp } print tmp }"` +} + +cut_n_pad $1 1 prefix1 +cut_n_pad $1 2 suffix1 +cut_n_pad $2 1 prefix2 +cut_n_pad $2 2 suffix2 +tmpfile=tmp$RANDOM.tmp +file1=faq$prefix1.$suffix1.htp +file2=faq$prefix2.$suffix2.htp + +echo "Moving FAQ question $prefix1.$suffix1 to $prefix2.$suffix2" + +sed -e "s/$1\./$2\./g" data/$file1 > ${tmpfile}1 +sed -e "s/$1\./$2\./g" data/RCS/$file1,v > ${tmpfile}2 + +if [ -f data/$file2 ]; then + echo "Target FAQ exists. Won't clobber." + exit 2 +fi + +mv ${tmpfile}1 data/$file2 +mv ${tmpfile}2 data/RCS/$file2,v +mv data/$file1 data/$file1.orig +mv data/RCS/$file1,v data/RCS/$file1,v.orig + diff --git a/sys/src/cmd/python/Tools/framer/README.txt b/sys/src/cmd/python/Tools/framer/README.txt new file mode 100644 index 000000000..4a93a4da9 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/README.txt @@ -0,0 +1,8 @@ +framer is a tool to generate boilerplate code for C extension types. + +The boilerplate is generated from a specification object written in +Python. The specification uses the class statement to describe the +extension module and any extension types it contains. From the +specification, framer can generate all the boilerplate C code, +including function definitions, argument handling code, and type +objects. diff --git a/sys/src/cmd/python/Tools/framer/TODO.txt b/sys/src/cmd/python/Tools/framer/TODO.txt new file mode 100644 index 000000000..8586c8e66 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/TODO.txt @@ -0,0 +1,6 @@ +Add spec for getsets. +Generate a distutils setup script. +Handle operator overloading. +Generate traverse and clear methods for GC. +Handle mapping, sequence, buffer protocols. +Finish the todo list. diff --git a/sys/src/cmd/python/Tools/framer/example.py b/sys/src/cmd/python/Tools/framer/example.py new file mode 100644 index 000000000..96f627858 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/example.py @@ -0,0 +1,126 @@ +"""Generate the skeleton for cStringIO as an example of framer.""" + +from framer.bases import Module, Type +from framer.member import member + +class cStringIO(Module): + """A simple fast partial StringIO replacement. + + This module provides a simple useful replacement for the StringIO + module that is written in C. It does not provide the full + generality of StringIO, but it provides enough for most + applications and is especially useful in conjunction with the + pickle module. + + Usage: + + from cStringIO import StringIO + + an_output_stream = StringIO() + an_output_stream.write(some_stuff) + ... + value = an_output_stream.getvalue() + + an_input_stream = StringIO(a_string) + spam = an_input_stream.readline() + spam = an_input_stream.read(5) + an_input_stream.seek(0) # OK, start over + spam = an_input_stream.read() # and read it all + """ + + __file__ = "cStringIO.c" + + def StringIO(o): + """Return a StringIO-like stream for reading or writing""" + StringIO.pyarg = "|O" + + class InputType(Type): + "Simple type for treating strings as input file streams" + + abbrev = "input" + + struct = """\ + typedef struct { + PyObject_HEAD + char *buf; + int pos; + int size; + PyObject *pbuf; + } InputObject; + """ + + def flush(self): + """Does nothing""" + + def getvalue(self): + """Get the string value. + + If use_pos is specified and is a true value, then the + string returned will include only the text up to the + current file position. + """ + + def isatty(self): + """Always returns False""" + + def read(self, s): + """Return s characters or the rest of the string.""" + read.pyarg = "|i" + + def readline(self): + """Read one line.""" + + def readlines(self, hint): + """Read all lines.""" + readlines.pyarg = "|i" + + def reset(self): + """Reset the file position to the beginning.""" + + def tell(self): + """Get the current position.""" + + def truncate(self, pos): + """Truncate the file at the current position.""" + truncate.pyarg = "|i" + + def seek(self, position, mode=0): + """Set the current position. + + The optional mode argument can be 0 for absolute, 1 for relative, + and 2 for relative to EOF. The default is absolute. + """ + seek.pyarg = "i|i" + + def close(self): + pass + + class OutputType(InputType): + "Simple type for output strings." + + abbrev = "output" + + struct = """\ + typedef struct { + PyObject_HEAD + char *buf; + int pos; + int size; + int softspace; + } OutputObject; + """ + + softspace = member() + + def close(self): + """Explicitly release resources.""" + + def write(self, s): + """Write a string to the file.""" + # XXX Hack: writing None resets the buffer + + def writelines(self, lines): + """Write each string in lines.""" + + +cStringIO.gen() diff --git a/sys/src/cmd/python/Tools/framer/framer/__init__.py b/sys/src/cmd/python/Tools/framer/framer/__init__.py new file mode 100644 index 000000000..d8f905898 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/__init__.py @@ -0,0 +1,6 @@ +"""A tool to generate basic framework for C extension types. + +The basic ideas is the same as modulator, but the code generates code +using many of the new features introduced in Python 2.2. It also +takes a more declarative approach to generating code. +""" diff --git a/sys/src/cmd/python/Tools/framer/framer/bases.py b/sys/src/cmd/python/Tools/framer/framer/bases.py new file mode 100644 index 000000000..fb3cb036e --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/bases.py @@ -0,0 +1,220 @@ +"""Provides the Module and Type base classes that user code inherits from.""" + +__all__ = ["Module", "Type", "member"] + +from framer import struct, template +from framer.function import Function, Method +from framer.member import member +from framer.slots import * +from framer.util import cstring, unindent + +from types import FunctionType + +def sortitems(dict): + L = dict.items() + L.sort() + return L + +# The Module and Type classes are implemented using metaclasses, +# because most of the methods are class methods. It is easier to use +# metaclasses than the cumbersome classmethod() builtin. They have +# class methods because they are exposed to user code as base classes. + +class BaseMetaclass(type): + """Shared infrastructure for generating modules and types.""" + + # just methoddef so far + + def dump_methoddef(self, f, functions, vars): + def p(templ, vars=vars): # helper function to generate output + print >> f, templ % vars + + if not functions: + return + p(template.methoddef_start) + for name, func in sortitems(functions): + if func.__doc__: + p(template.methoddef_def_doc, func.vars) + else: + p(template.methoddef_def, func.vars) + p(template.methoddef_end) + +class ModuleMetaclass(BaseMetaclass): + """Provides methods for Module class.""" + + def gen(self): + self.analyze() + self.initvars() + f = open(self.__filename, "w") + self.dump(f) + f.close() + + def analyze(self): + self.name = getattr(self, "abbrev", self.__name__) + self.__functions = {} + self.__types = {} + self.__members = False + + for name, obj in self.__dict__.iteritems(): + if isinstance(obj, FunctionType): + self.__functions[name] = Function(obj, self) + elif isinstance(obj, TypeMetaclass): + obj._TypeMetaclass__module = self.name + obj.analyze() + self.__types[name] = obj + if obj.has_members(): + self.__members = True + + def initvars(self): + v = self.__vars = {} + filename = getattr(self, "__file__", None) + if filename is None: + filename = self.__name__ + "module.c" + self.__filename = v["FileName"] = filename + name = v["ModuleName"] = self.__name__ + v["MethodDefName"] = "%s_methods" % name + v["ModuleDocstring"] = cstring(unindent(self.__doc__)) + + def dump(self, f): + def p(templ, vars=self.__vars): # helper function to generate output + print >> f, templ % vars + + p(template.module_start) + if self.__members: + p(template.member_include) + print >> f + + if self.__doc__: + p(template.module_doc) + + for name, type in sortitems(self.__types): + type.dump(f) + + for name, func in sortitems(self.__functions): + func.dump(f) + + self.dump_methoddef(f, self.__functions, self.__vars) + + p(template.module_init_start) + for name, type in sortitems(self.__types): + type.dump_init(f) + + p("}") + +class Module: + __metaclass__ = ModuleMetaclass + +class TypeMetaclass(BaseMetaclass): + + def dump(self, f): + self.initvars() + + # defined after initvars() so that __vars is defined + def p(templ, vars=self.__vars): + print >> f, templ % vars + + if self.struct is not None: + print >> f, unindent(self.struct, False) + + if self.__doc__: + p(template.docstring) + + for name, func in sortitems(self.__methods): + func.dump(f) + + self.dump_methoddef(f, self.__methods, self.__vars) + self.dump_memberdef(f) + self.dump_slots(f) + + def has_members(self): + if self.__members: + return True + else: + return False + + def analyze(self): + # called by ModuleMetaclass analyze() + self.name = getattr(self, "abbrev", self.__name__) + src = getattr(self, "struct", None) + if src is not None: + self.__struct = struct.parse(src) + else: + self.__struct = None + self.__methods = {} + self.__members = {} + for cls in self.__mro__: + for k, v in cls.__dict__.iteritems(): + if isinstance(v, FunctionType): + self.__methods[k] = Method(v, self) + if isinstance(v, member): + self.__members[k] = v + assert self.__struct is not None + v.register(k, self.__struct) + self.analyze_slots() + + def analyze_slots(self): + self.__slots = {} + for s in Slots: + if s.special is not None: + meth = self.__methods.get(s.special) + if meth is not None: + self.__slots[s] = meth + self.__slots[TP_NAME] = '"%s.%s"' % (self.__module, self.__name__) + if self.__doc__: + self.__slots[TP_DOC] = "%s_doc" % self.name + if self.__struct is not None: + self.__slots[TP_BASICSIZE] = "sizeof(%s)" % self.__struct.name + self.__slots[TP_DEALLOC] = "%s_dealloc" % self.name + if self.__methods: + self.__slots[TP_METHODS] = "%s_methods" % self.name + if self.__members: + self.__slots[TP_MEMBERS] = "%s_members" % self.name + + def initvars(self): + v = self.__vars = {} + v["TypeName"] = self.__name__ + v["CTypeName"] = "Py%s_Type" % self.__name__ + v["MethodDefName"] = self.__slots[TP_METHODS] + if self.__doc__: + v["DocstringVar"] = self.__slots[TP_DOC] + v["Docstring"] = cstring(unindent(self.__doc__)) + if self.__struct is not None: + v["StructName"] = self.__struct.name + if self.__members: + v["MemberDefName"] = self.__slots[TP_MEMBERS] + + def dump_memberdef(self, f): + def p(templ, vars=self.__vars): + print >> f, templ % vars + + if not self.__members: + return + p(template.memberdef_start) + for name, slot in sortitems(self.__members): + slot.dump(f) + p(template.memberdef_end) + + def dump_slots(self, f): + def p(templ, vars=self.__vars): + print >> f, templ % vars + + if self.struct: + p(template.dealloc_func, {"name" : self.__slots[TP_DEALLOC]}) + + p(template.type_struct_start) + for s in Slots[:-5]: # XXX + val = self.__slots.get(s, s.default) + ntabs = 4 - (4 + len(val)) / 8 + line = " %s,%s/* %s */" % (val, "\t" * ntabs, s.name) + print >> f, line + p(template.type_struct_end) + + def dump_init(self, f): + def p(templ): + print >> f, templ % self.__vars + + p(template.type_init_type) + p(template.module_add_type) + +class Type: + __metaclass__ = TypeMetaclass diff --git a/sys/src/cmd/python/Tools/framer/framer/function.py b/sys/src/cmd/python/Tools/framer/framer/function.py new file mode 100644 index 000000000..306f7e986 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/function.py @@ -0,0 +1,173 @@ +"""Functions.""" + +from framer import template +from framer.util import cstring, unindent + +METH_O = "METH_O" +METH_NOARGS = "METH_NOARGS" +METH_VARARGS = "METH_VARARGS" + +def parsefmt(fmt): + for c in fmt: + if c == '|': + continue + yield c + +class Argument: + + def __init__(self, name): + self.name = name + self.ctype = "PyObject *" + self.default = None + + def __str__(self): + return "%s%s" % (self.ctype, self.name) + + def setfmt(self, code): + self.ctype = self._codes[code] + if self.ctype[-1] != "*": + self.ctype += " " + + _codes = {"O": "PyObject *", + "i": "int", + } + + def decl(self): + if self.default is None: + return str(self) + ";" + else: + return "%s = %s;" % (self, self.default) + +class _ArgumentList(object): + + # these instance variables should be initialized by subclasses + ml_meth = None + fmt = None + + def __init__(self, args): + self.args = map(Argument, args) + + def __len__(self): + return len(self.args) + + def __getitem__(self, i): + return self.args[i] + + def dump_decls(self, f): + pass + +class NoArgs(_ArgumentList): + + def __init__(self, args): + assert len(args) == 0 + super(NoArgs, self).__init__(args) + self.ml_meth = METH_NOARGS + + def c_args(self): + return "PyObject *self" + +class OneArg(_ArgumentList): + + def __init__(self, args): + assert len(args) == 1 + super(OneArg, self).__init__(args) + self.ml_meth = METH_O + + def c_args(self): + return "PyObject *self, %s" % self.args[0] + +class VarArgs(_ArgumentList): + + def __init__(self, args, fmt=None): + super(VarArgs, self).__init__(args) + self.ml_meth = METH_VARARGS + if fmt is not None: + self.fmt = fmt + i = 0 + for code in parsefmt(fmt): + self.args[i].setfmt(code) + i += 1 + + def c_args(self): + return "PyObject *self, PyObject *args" + + def targets(self): + return ", ".join(["&%s" % a.name for a in self.args]) + + def dump_decls(self, f): + for a in self.args: + print >> f, " %s" % a.decl() + +def ArgumentList(func, method): + code = func.func_code + args = code.co_varnames[:code.co_argcount] + if method: + args = args[1:] + pyarg = getattr(func, "pyarg", None) + if pyarg is not None: + args = VarArgs(args, pyarg) + if func.func_defaults: + L = list(func.func_defaults) + ndefault = len(L) + i = len(args) - ndefault + while L: + args[i].default = L.pop(0) + return args + else: + if len(args) == 0: + return NoArgs(args) + elif len(args) == 1: + return OneArg(args) + else: + return VarArgs(args) + +class Function: + + method = False + + def __init__(self, func, parent): + self._func = func + self._parent = parent + self.analyze() + self.initvars() + + def dump(self, f): + def p(templ, vars=None): # helper function to generate output + if vars is None: + vars = self.vars + print >> f, templ % vars + + if self.__doc__: + p(template.docstring) + + d = {"name" : self.vars["CName"], + "args" : self.args.c_args(), + } + p(template.funcdef_start, d) + + self.args.dump_decls(f) + + if self.args.ml_meth == METH_VARARGS: + p(template.varargs) + + p(template.funcdef_end) + + def analyze(self): + self.__doc__ = self._func.__doc__ + self.args = ArgumentList(self._func, self.method) + + def initvars(self): + v = self.vars = {} + v["PythonName"] = self._func.__name__ + s = v["CName"] = "%s_%s" % (self._parent.name, self._func.__name__) + v["DocstringVar"] = s + "_doc" + v["MethType"] = self.args.ml_meth + if self.__doc__: + v["Docstring"] = cstring(unindent(self.__doc__)) + if self.args.fmt is not None: + v["ArgParse"] = self.args.fmt + v["ArgTargets"] = self.args.targets() + +class Method(Function): + + method = True diff --git a/sys/src/cmd/python/Tools/framer/framer/member.py b/sys/src/cmd/python/Tools/framer/framer/member.py new file mode 100644 index 000000000..5faf46227 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/member.py @@ -0,0 +1,73 @@ +from framer import template +from framer.util import cstring, unindent + +T_SHORT = "T_SHORT" +T_INT = "T_INT" +T_LONG = "T_LONG" +T_FLOAT = "T_FLOAT" +T_DOUBLE = "T_DOUBLE" +T_STRING = "T_STRING" +T_OBJECT = "T_OBJECT" +T_CHAR = "T_CHAR" +T_BYTE = "T_BYTE" +T_UBYTE = "T_UBYTE" +T_UINT = "T_UINT" +T_ULONG = "T_ULONG" +T_STRING_INPLACE = "T_STRING_INPLACE" +T_OBJECT_EX = "T_OBJECT_EX" + +RO = READONLY = "READONLY" +READ_RESTRICTED = "READ_RESTRICTED" +WRITE_RESTRICTED = "WRITE_RESTRICTED" +RESTRICT = "RESTRICTED" + +c2t = {"int" : T_INT, + "unsigned int" : T_UINT, + "long" : T_LONG, + "unsigned long" : T_LONG, + "float" : T_FLOAT, + "double" : T_DOUBLE, + "char *" : T_CHAR, + "PyObject *" : T_OBJECT, + } + +class member(object): + + def __init__(self, cname=None, type=None, flags=None, doc=None): + self.type = type + self.flags = flags + self.cname = cname + self.doc = doc + self.name = None + self.struct = None + + def register(self, name, struct): + self.name = name + self.struct = struct + self.initvars() + + def initvars(self): + v = self.vars = {} + v["PythonName"] = self.name + if self.cname is not None: + v["CName"] = self.cname + else: + v["CName"] = self.name + v["Flags"] = self.flags or "0" + v["Type"] = self.get_type() + if self.doc is not None: + v["Docstring"] = cstring(unindent(self.doc)) + v["StructName"] = self.struct.name + + def get_type(self): + """Deduce type code from struct specification if not defined""" + if self.type is not None: + return self.type + ctype = self.struct.get_type(self.name) + return c2t[ctype] + + def dump(self, f): + if self.doc is None: + print >> f, template.memberdef_def % self.vars + else: + print >> f, template.memberdef_def_doc % self.vars diff --git a/sys/src/cmd/python/Tools/framer/framer/slots.py b/sys/src/cmd/python/Tools/framer/framer/slots.py new file mode 100644 index 000000000..d369c9ad0 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/slots.py @@ -0,0 +1,64 @@ +"""Descriptions of all the slots in Python's type objects.""" + +class Slot(object): + def __init__(self, name, cast=None, special=None, default="0"): + self.name = name + self.cast = cast + self.special = special + self.default = default + +Slots = (Slot("ob_size"), + Slot("tp_name"), + Slot("tp_basicsize"), + Slot("tp_itemsize"), + Slot("tp_dealloc", "destructor"), + Slot("tp_print", "printfunc"), + Slot("tp_getattr", "getattrfunc"), + Slot("tp_setattr", "setattrfunc"), + Slot("tp_compare", "cmpfunc", "__cmp__"), + Slot("tp_repr", "reprfunc", "__repr__"), + Slot("tp_as_number"), + Slot("tp_as_sequence"), + Slot("tp_as_mapping"), + Slot("tp_hash", "hashfunc", "__hash__"), + Slot("tp_call", "ternaryfunc", "__call__"), + Slot("tp_str", "reprfunc", "__str__"), + Slot("tp_getattro", "getattrofunc", "__getattr__", # XXX + "PyObject_GenericGetAttr"), + Slot("tp_setattro", "setattrofunc", "__setattr__"), + Slot("tp_as_buffer"), + Slot("tp_flags", default="Py_TPFLAGS_DEFAULT"), + Slot("tp_doc"), + Slot("tp_traverse", "traverseprox"), + Slot("tp_clear", "inquiry"), + Slot("tp_richcompare", "richcmpfunc"), + Slot("tp_weaklistoffset"), + Slot("tp_iter", "getiterfunc", "__iter__"), + Slot("tp_iternext", "iternextfunc", "__next__"), # XXX + Slot("tp_methods"), + Slot("tp_members"), + Slot("tp_getset"), + Slot("tp_base"), + Slot("tp_dict"), + Slot("tp_descr_get", "descrgetfunc"), + Slot("tp_descr_set", "descrsetfunc"), + Slot("tp_dictoffset"), + Slot("tp_init", "initproc", "__init__"), + Slot("tp_alloc", "allocfunc"), + Slot("tp_new", "newfunc"), + Slot("tp_free", "freefunc"), + Slot("tp_is_gc", "inquiry"), + Slot("tp_bases"), + Slot("tp_mro"), + Slot("tp_cache"), + Slot("tp_subclasses"), + Slot("tp_weaklist"), + ) + +# give some slots symbolic names +TP_NAME = Slots[1] +TP_BASICSIZE = Slots[2] +TP_DEALLOC = Slots[4] +TP_DOC = Slots[20] +TP_METHODS = Slots[27] +TP_MEMBERS = Slots[28] diff --git a/sys/src/cmd/python/Tools/framer/framer/struct.py b/sys/src/cmd/python/Tools/framer/framer/struct.py new file mode 100644 index 000000000..12ea8d7c4 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/struct.py @@ -0,0 +1,52 @@ +"""Rudimentary parser for C struct definitions.""" + +import re + +PyObject_HEAD = "PyObject_HEAD" +PyObject_VAR_HEAD = "PyObject_VAR_HEAD" + +rx_name = re.compile("} (\w+);") + +class Struct: + def __init__(self, name, head, members): + self.name = name + self.head = head + self.members = members + + def get_type(self, name): + for _name, type in self.members: + if name == _name: + return type + raise ValueError, "no member named %s" % name + +def parse(s): + """Parse a C struct definition. + + The parser is very restricted in what it will accept. + """ + + lines = filter(None, s.split("\n")) # get non-empty lines + assert lines[0].strip() == "typedef struct {" + pyhead = lines[1].strip() + assert (pyhead.startswith("PyObject") and + pyhead.endswith("HEAD")) + members = [] + for line in lines[2:]: + line = line.strip() + if line.startswith("}"): + break + + assert line.endswith(";") + line = line[:-1] + words = line.split() + name = words[-1] + type = " ".join(words[:-1]) + if name[0] == "*": + name = name[1:] + type += " *" + members.append((name, type)) + name = None + mo = rx_name.search(line) + assert mo is not None + name = mo.group(1) + return Struct(name, pyhead, members) diff --git a/sys/src/cmd/python/Tools/framer/framer/structparse.py b/sys/src/cmd/python/Tools/framer/framer/structparse.py new file mode 100644 index 000000000..f24c0da09 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/structparse.py @@ -0,0 +1,46 @@ +"""Rudimentary parser for C struct definitions.""" + +import re + +PyObject_HEAD = "PyObject_HEAD" +PyObject_VAR_HEAD = "PyObject_VAR_HEAD" + +rx_name = re.compile("} (\w+);") + +class Struct: + def __init__(self, name, head, members): + self.name = name + self.head = head + self.members = members + +def parse(s): + """Parse a C struct definition. + + The parser is very restricted in what it will accept. + """ + + lines = filter(None, s.split("\n")) # get non-empty lines + assert lines[0].strip() == "typedef struct {" + pyhead = lines[1].strip() + assert (pyhead.startswith("PyObject") and + pyhead.endswith("HEAD")) + members = [] + for line in lines[2:]: + line = line.strip() + if line.startswith("}"): + break + + assert line.endswith(";") + line = line[:-1] + words = line.split() + name = words[-1] + type = " ".join(words[:-1]) + if name[0] == "*": + name = name[1:] + type += " *" + members.append((name, type)) + name = None + mo = rx_name.search(line) + assert mo is not None + name = mo.group(1) + return Struct(name, pyhead, members) diff --git a/sys/src/cmd/python/Tools/framer/framer/template.py b/sys/src/cmd/python/Tools/framer/framer/template.py new file mode 100644 index 000000000..41f95371b --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/template.py @@ -0,0 +1,102 @@ +"""framer's C code templates. + +Templates use the following variables: + +FileName: name of the file that contains the C source code +ModuleName: name of the module, as in "import ModuleName" +ModuleDocstring: C string containing the module doc string +""" + +module_start = '#include "Python.h"' +member_include = '#include "structmember.h"' + +module_doc = """\ +PyDoc_STRVAR(%(ModuleName)s_doc, +%(ModuleDocstring)s); +""" + +methoddef_start = """\ +static struct PyMethodDef %(MethodDefName)s[] = {""" + +methoddef_def = """\ + {"%(PythonName)s", (PyCFunction)%(CName)s, %(MethType)s},""" + +methoddef_def_doc = """\ + {"%(PythonName)s", (PyCFunction)%(CName)s, %(MethType)s, + %(DocstringVar)s},""" + +methoddef_end = """\ + {NULL, NULL} +}; +""" + +memberdef_start = """\ +#define OFF(X) offsetof(%(StructName)s, X) + +static struct PyMemberDef %(MemberDefName)s[] = {""" + +memberdef_def_doc = """\ + {"%(PythonName)s", %(Type)s, OFF(%(CName)s), %(Flags)s, + %(Docstring)s},""" + +memberdef_def = """\ + {"%(PythonName)s", %(Type)s, OFF(%(CName)s), %(Flags)s},""" + +memberdef_end = """\ + {NULL} +}; + +#undef OFF +""" + +dealloc_func = """static void +%(name)s(PyObject *ob) +{ +} +""" + +docstring = """\ +PyDoc_STRVAR(%(DocstringVar)s, +%(Docstring)s); +""" + +funcdef_start = """\ +static PyObject * +%(name)s(%(args)s) +{""" + +funcdef_end = """\ +} +""" + +varargs = """\ + if (!PyArg_ParseTuple(args, \"%(ArgParse)s:%(PythonName)s\", + %(ArgTargets)s)) + return NULL;""" + +module_init_start = """\ +PyMODINIT_FUNC +init%(ModuleName)s(void) +{ + PyObject *mod; + + mod = Py_InitModule3("%(ModuleName)s", %(MethodDefName)s, + %(ModuleName)s_doc); + if (mod == NULL) + return; +""" + +type_init_type = " %(CTypeName)s.ob_type = &PyType_Type;" +module_add_type = """\ + if (!PyObject_SetAttrString(mod, "%(TypeName)s", + (PyObject *)&%(CTypeName)s)) + return; +""" + +type_struct_start = """\ +static PyTypeObject %(CTypeName)s = { + PyObject_HEAD_INIT(0)""" + +type_struct_end = """\ +}; +""" diff --git a/sys/src/cmd/python/Tools/framer/framer/util.py b/sys/src/cmd/python/Tools/framer/framer/util.py new file mode 100644 index 000000000..73f330964 --- /dev/null +++ b/sys/src/cmd/python/Tools/framer/framer/util.py @@ -0,0 +1,35 @@ +def cstring(s, width=70): + """Return C string representation of a Python string. + + width specifies the maximum width of any line of the C string. + """ + L = [] + for l in s.split("\n"): + if len(l) < width: + L.append(r'"%s\n"' % l) + + return "\n".join(L) + +def unindent(s, skipfirst=True): + """Return an unindented version of a docstring. + + Removes indentation on lines following the first one, using the + leading whitespace of the first indented line that is not blank + to determine the indentation. + """ + + lines = s.split("\n") + if skipfirst: + first = lines.pop(0) + L = [first] + else: + L = [] + indent = None + for l in lines: + ls = l.strip() + if ls: + indent = len(l) - len(ls) + break + L += [l[indent:] for l in lines] + + return "\n".join(L) diff --git a/sys/src/cmd/python/Tools/freeze/README b/sys/src/cmd/python/Tools/freeze/README new file mode 100644 index 000000000..81be2c843 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/README @@ -0,0 +1,296 @@ +THE FREEZE SCRIPT +================= + +(Directions for Windows are at the end of this file.) + + +What is Freeze? +--------------- + +Freeze make it possible to ship arbitrary Python programs to people +who don't have Python. The shipped file (called a "frozen" version of +your Python program) is an executable, so this only works if your +platform is compatible with that on the receiving end (this is usually +a matter of having the same major operating system revision and CPU +type). + +The shipped file contains a Python interpreter and large portions of +the Python run-time. Some measures have been taken to avoid linking +unneeded modules, but the resulting binary is usually not small. + +The Python source code of your program (and of the library modules +written in Python that it uses) is not included in the binary -- +instead, the compiled byte-code (the instruction stream used +internally by the interpreter) is incorporated. This gives some +protection of your Python source code, though not much -- a +disassembler for Python byte-code is available in the standard Python +library. At least someone running "strings" on your binary won't see +the source. + + +How does Freeze know which modules to include? +---------------------------------------------- + +Previous versions of Freeze used a pretty simple-minded algorithm to +find the modules that your program uses, essentially searching for +lines starting with the word "import". It was pretty easy to trick it +into making mistakes, either missing valid import statements, or +mistaking string literals (e.g. doc strings) for import statements. + +This has been remedied: Freeze now uses the regular Python parser to +parse the program (and all its modules) and scans the generated byte +code for IMPORT instructions. It may still be confused -- it will not +know about calls to the __import__ built-in function, or about import +statements constructed on the fly and executed using the 'exec' +statement, and it will consider import statements even when they are +unreachable (e.g. "if 0: import foobar"). + +This new version of Freeze also knows about Python's new package +import mechanism, and uses exactly the same rules to find imported +modules and packages. One exception: if you write 'from package +import *', Python will look into the __all__ variable of the package +to determine which modules are to be imported, while Freeze will do a +directory listing. + +One tricky issue: Freeze assumes that the Python interpreter and +environment you're using to run Freeze is the same one that would be +used to run your program, which should also be the same whose sources +and installed files you will learn about in the next section. In +particular, your PYTHONPATH setting should be the same as for running +your program locally. (Tip: if the program doesn't run when you type +"python hello.py" there's little chance of getting the frozen version +to run.) + + +How do I use Freeze? +-------------------- + +Normally, you should be able to use it as follows: + + python freeze.py hello.py + +where hello.py is your program and freeze.py is the main file of +Freeze (in actuality, you'll probably specify an absolute pathname +such as /usr/joe/python/Tools/freeze/freeze.py). + + +What do I do next? +------------------ + +Freeze creates a number of files: frozen.c, config.c and Makefile, +plus one file for each Python module that gets included named +M_<module>.c. To produce the frozen version of your program, you can +simply type "make". This should produce a binary file. If the +filename argument to Freeze was "hello.py", the binary will be called +"hello". + +Note: you can use the -o option to freeze to specify an alternative +directory where these files are created. This makes it easier to +clean up after you've shipped the frozen binary. You should invoke +"make" in the given directory. + + +Freezing Tkinter programs +------------------------- + +Unfortunately, it is currently not possible to freeze programs that +use Tkinter without a Tcl/Tk installation. The best way to ship a +frozen Tkinter program is to decide in advance where you are going +to place the Tcl and Tk library files in the distributed setup, and +then declare these directories in your frozen Python program using +the TCL_LIBRARY, TK_LIBRARY and TIX_LIBRARY environment variables. + +For example, assume you will ship your frozen program in the directory +<root>/bin/windows-x86 and will place your Tcl library files +in <root>/lib/tcl8.2 and your Tk library files in <root>/lib/tk8.2. Then +placing the following lines in your frozen Python script before importing +Tkinter or Tix would set the environment correctly for Tcl/Tk/Tix: + +import os +import os.path +RootDir = os.path.dirname(os.path.dirname(os.getcwd())) + +import sys +if sys.platform == "win32": + sys.path = ['', '..\\..\\lib\\python-2.0'] + os.environ['TCL_LIBRARY'] = RootDir + '\\lib\\tcl8.2' + os.environ['TK_LIBRARY'] = RootDir + '\\lib\\tk8.2' + os.environ['TIX_LIBRARY'] = RootDir + '\\lib\\tix8.1' +elif sys.platform == "linux2": + sys.path = ['', '../../lib/python-2.0'] + os.environ['TCL_LIBRARY'] = RootDir + '/lib/tcl8.2' + os.environ['TK_LIBRARY'] = RootDir + '/lib/tk8.2' + os.environ['TIX_LIBRARY'] = RootDir + '/lib/tix8.1' +elif sys.platform == "solaris": + sys.path = ['', '../../lib/python-2.0'] + os.environ['TCL_LIBRARY'] = RootDir + '/lib/tcl8.2' + os.environ['TK_LIBRARY'] = RootDir + '/lib/tk8.2' + os.environ['TIX_LIBRARY'] = RootDir + '/lib/tix8.1' + +This also adds <root>/lib/python-2.0 to your Python path +for any Python files such as _tkinter.pyd you may need. + +Note that the dynamic libraries (such as tcl82.dll tk82.dll python20.dll +under Windows, or libtcl8.2.so and libtcl8.2.so under Unix) are required +at program load time, and are searched by the operating system loader +before Python can be started. Under Windows, the environment +variable PATH is consulted, and under Unix, it may be the +environment variable LD_LIBRARY_PATH and/or the system +shared library cache (ld.so). An additional preferred directory for +finding the dynamic libraries is built into the .dll or .so files at +compile time - see the LIB_RUNTIME_DIR variable in the Tcl makefile. +The OS must find the dynamic libraries or your frozen program won't start. +Usually I make sure that the .so or .dll files are in the same directory +as the executable, but this may not be foolproof. + +A workaround to installing your Tcl library files with your frozen +executable would be possible, in which the Tcl/Tk library files are +incorporated in a frozen Python module as string literals and written +to a temporary location when the program runs; this is currently left +as an exercise for the reader. An easier approach is to freeze the +Tcl/Tk/Tix code into the dynamic libraries using the Tcl ET code, +or the Tix Stand-Alone-Module code. Of course, you can also simply +require that Tcl/Tk is required on the target installation, but be +careful that the version corresponds. + +There are some caveats using frozen Tkinter applications: + Under Windows if you use the -s windows option, writing +to stdout or stderr is an error. + The Tcl [info nameofexecutable] will be set to where the +program was frozen, not where it is run from. + The global variables argc and argv do not exist. + + +A warning about shared library modules +-------------------------------------- + +When your Python installation uses shared library modules such as +_tkinter.pyd, these will not be incorporated in the frozen program. + Again, the frozen program will work when you test it, but it won't + work when you ship it to a site without a Python installation. + +Freeze prints a warning when this is the case at the end of the +freezing process: + + Warning: unknown modules remain: ... + +When this occurs, the best thing to do is usually to rebuild Python +using static linking only. Or use the approach described in the previous +section to declare a library path using sys.path, and place the modules +such as _tkinter.pyd there. + + +Troubleshooting +--------------- + +If you have trouble using Freeze for a large program, it's probably +best to start playing with a really simple program first (like the file +hello.py). If you can't get that to work there's something +fundamentally wrong -- perhaps you haven't installed Python. To do a +proper install, you should do "make install" in the Python root +directory. + + +Usage under Windows 95 or NT +---------------------------- + +Under Windows 95 or NT, you *must* use the -p option and point it to +the top of the Python source tree. + +WARNING: the resulting executable is not self-contained; it requires +the Python DLL, currently PYTHON20.DLL (it does not require the +standard library of .py files though). It may also require one or +more extension modules loaded from .DLL or .PYD files; the module +names are printed in the warning message about remaining unknown +modules. + +The driver script generates a Makefile that works with the Microsoft +command line C compiler (CL). To compile, run "nmake"; this will +build a target "hello.exe" if the source was "hello.py". Only the +files frozenmain.c and frozen.c are used; no config.c is generated or +used, since the standard DLL is used. + +In order for this to work, you must have built Python using the VC++ +(Developer Studio) 5.0 compiler. The provided project builds +python20.lib in the subdirectory pcbuild\Release of thje Python source +tree, and this is where the generated Makefile expects it to be. If +this is not the case, you can edit the Makefile or (probably better) +winmakemakefile.py (e.g., if you are using the 4.2 compiler, the +python20.lib file is generated in the subdirectory vc40 of the Python +source tree). + +It is possible to create frozen programs that don't have a console +window, by specifying the option '-s windows'. See the Usage below. + +Usage +----- + +Here is a list of all of the options (taken from freeze.__doc__): + +usage: freeze [options...] script [module]... + +Options: +-p prefix: This is the prefix used when you ran ``make install'' + in the Python build directory. + (If you never ran this, freeze won't work.) + The default is whatever sys.prefix evaluates to. + It can also be the top directory of the Python source + tree; then -P must point to the build tree. + +-P exec_prefix: Like -p but this is the 'exec_prefix', used to + install objects etc. The default is whatever sys.exec_prefix + evaluates to, or the -p argument if given. + If -p points to the Python source tree, -P must point + to the build tree, if different. + +-e extension: A directory containing additional .o files that + may be used to resolve modules. This directory + should also have a Setup file describing the .o files. + On Windows, the name of a .INI file describing one + or more extensions is passed. + More than one -e option may be given. + +-o dir: Directory where the output files are created; default '.'. + +-m: Additional arguments are module names instead of filenames. + +-a package=dir: Additional directories to be added to the package's + __path__. Used to simulate directories added by the + package at runtime (eg, by OpenGL and win32com). + More than one -a option may be given for each package. + +-l file: Pass the file to the linker (windows only) + +-d: Debugging mode for the module finder. + +-q: Make the module finder totally quiet. + +-h: Print this help message. + +-x module Exclude the specified module. + +-i filename: Include a file with additional command line options. Used + to prevent command lines growing beyond the capabilities of + the shell/OS. All arguments specified in filename + are read and the -i option replaced with the parsed + params (note - quoting args in this file is NOT supported) + +-s subsystem: Specify the subsystem (For Windows only.); + 'console' (default), 'windows', 'service' or 'com_dll' + +-w: Toggle Windows (NT or 95) behavior. + (For debugging only -- on a win32 platform, win32 behavior + is automatic.) + +Arguments: + +script: The Python script to be executed by the resulting binary. + +module ...: Additional Python modules (referenced by pathname) + that will be included in the resulting binary. These + may be .py or .pyc files. If -m is specified, these are + module names that are search in the path instead. + + + +--Guido van Rossum (home page: http://www.python.org/~guido/) diff --git a/sys/src/cmd/python/Tools/freeze/bkfile.py b/sys/src/cmd/python/Tools/freeze/bkfile.py new file mode 100644 index 000000000..54af2fac8 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/bkfile.py @@ -0,0 +1,47 @@ +_orig_open = open + +class _BkFile: + def __init__(self, file, mode, bufsize): + import os + self.__filename = file + self.__backup = file + '~' + try: + os.unlink(self.__backup) + except os.error: + pass + try: + os.rename(file, self.__backup) + except os.error: + self.__backup = None + self.__file = _orig_open(file, mode, bufsize) + self.closed = self.__file.closed + self.fileno = self.__file.fileno + self.flush = self.__file.flush + self.isatty = self.__file.isatty + self.mode = self.__file.mode + self.name = self.__file.name + self.read = self.__file.read + self.readinto = self.__file.readinto + self.readline = self.__file.readline + self.readlines = self.__file.readlines + self.seek = self.__file.seek + self.softspace = self.__file.softspace + self.tell = self.__file.tell + self.truncate = self.__file.truncate + self.write = self.__file.write + self.writelines = self.__file.writelines + + def close(self): + self.__file.close() + if self.__backup is None: + return + import filecmp + if filecmp.cmp(self.__backup, self.__filename, shallow = 0): + import os + os.unlink(self.__filename) + os.rename(self.__backup, self.__filename) + +def open(file, mode = 'r', bufsize = -1): + if 'w' not in mode: + return _orig_open(file, mode, bufsize) + return _BkFile(file, mode, bufsize) diff --git a/sys/src/cmd/python/Tools/freeze/checkextensions.py b/sys/src/cmd/python/Tools/freeze/checkextensions.py new file mode 100644 index 000000000..334521f55 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/checkextensions.py @@ -0,0 +1,90 @@ +# Check for a module in a set of extension directories. +# An extension directory should contain a Setup file +# and one or more .o files or a lib.a file. + +import os +import parsesetup + +def checkextensions(unknown, extensions): + files = [] + modules = [] + edict = {} + for e in extensions: + setup = os.path.join(e, 'Setup') + liba = os.path.join(e, 'lib.a') + if not os.path.isfile(liba): + liba = None + edict[e] = parsesetup.getsetupinfo(setup), liba + for mod in unknown: + for e in extensions: + (mods, vars), liba = edict[e] + if not mods.has_key(mod): + continue + modules.append(mod) + if liba: + # If we find a lib.a, use it, ignore the + # .o files, and use *all* libraries for + # *all* modules in the Setup file + if liba in files: + break + files.append(liba) + for m in mods.keys(): + files = files + select(e, mods, vars, + m, 1) + break + files = files + select(e, mods, vars, mod, 0) + break + return files, modules + +def select(e, mods, vars, mod, skipofiles): + files = [] + for w in mods[mod]: + w = treatword(w) + if not w: + continue + w = expandvars(w, vars) + for w in w.split(): + if skipofiles and w[-2:] == '.o': + continue + # Assume $var expands to absolute pathname + if w[0] not in ('-', '$') and w[-2:] in ('.o', '.a'): + w = os.path.join(e, w) + if w[:2] in ('-L', '-R') and w[2:3] != '$': + w = w[:2] + os.path.join(e, w[2:]) + files.append(w) + return files + +cc_flags = ['-I', '-D', '-U'] +cc_exts = ['.c', '.C', '.cc', '.c++'] + +def treatword(w): + if w[:2] in cc_flags: + return None + if w[:1] == '-': + return w # Assume loader flag + head, tail = os.path.split(w) + base, ext = os.path.splitext(tail) + if ext in cc_exts: + tail = base + '.o' + w = os.path.join(head, tail) + return w + +def expandvars(str, vars): + i = 0 + while i < len(str): + i = k = str.find('$', i) + if i < 0: + break + i = i+1 + var = str[i:i+1] + i = i+1 + if var == '(': + j = str.find(')', i) + if j < 0: + break + var = str[i:j] + i = j+1 + if vars.has_key(var): + str = str[:k] + vars[var] + str[i:] + i = k + return str diff --git a/sys/src/cmd/python/Tools/freeze/checkextensions_win32.py b/sys/src/cmd/python/Tools/freeze/checkextensions_win32.py new file mode 100644 index 000000000..a198ecf39 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/checkextensions_win32.py @@ -0,0 +1,188 @@ +"""Extension management for Windows. + +Under Windows it is unlikely the .obj files are of use, as special compiler options +are needed (primarily to toggle the behavior of "public" symbols. + +I dont consider it worth parsing the MSVC makefiles for compiler options. Even if +we get it just right, a specific freeze application may have specific compiler +options anyway (eg, to enable or disable specific functionality) + +So my basic stragtegy is: + +* Have some Windows INI files which "describe" one or more extension modules. + (Freeze comes with a default one for all known modules - but you can specify + your own). +* This description can include: + - The MSVC .dsp file for the extension. The .c source file names + are extraced from there. + - Specific compiler/linker options + - Flag to indicate if Unicode compilation is expected. + +At the moment the name and location of this INI file is hardcoded, +but an obvious enhancement would be to provide command line options. +""" + +import os, sys +try: + import win32api +except ImportError: + win32api = None # User has already been warned + +class CExtension: + """An abstraction of an extension implemented in C/C++ + """ + def __init__(self, name, sourceFiles): + self.name = name + # A list of strings defining additional compiler options. + self.sourceFiles = sourceFiles + # A list of special compiler options to be applied to + # all source modules in this extension. + self.compilerOptions = [] + # A list of .lib files the final .EXE will need. + self.linkerLibs = [] + + def GetSourceFiles(self): + return self.sourceFiles + + def AddCompilerOption(self, option): + self.compilerOptions.append(option) + def GetCompilerOptions(self): + return self.compilerOptions + + def AddLinkerLib(self, lib): + self.linkerLibs.append(lib) + def GetLinkerLibs(self): + return self.linkerLibs + +def checkextensions(unknown, extra_inis, prefix): + # Create a table of frozen extensions + + defaultMapName = os.path.join( os.path.split(sys.argv[0])[0], "extensions_win32.ini") + if not os.path.isfile(defaultMapName): + sys.stderr.write("WARNING: %s can not be found - standard extensions may not be found\n" % defaultMapName) + else: + # must go on end, so other inis can override. + extra_inis.append(defaultMapName) + + ret = [] + for mod in unknown: + for ini in extra_inis: +# print "Looking for", mod, "in", win32api.GetFullPathName(ini),"...", + defn = get_extension_defn( mod, ini, prefix ) + if defn is not None: +# print "Yay - found it!" + ret.append( defn ) + break +# print "Nope!" + else: # For not broken! + sys.stderr.write("No definition of module %s in any specified map file.\n" % (mod)) + + return ret + +def get_extension_defn(moduleName, mapFileName, prefix): + if win32api is None: return None + os.environ['PYTHONPREFIX'] = prefix + dsp = win32api.GetProfileVal(moduleName, "dsp", "", mapFileName) + if dsp=="": + return None + + # We allow environment variables in the file name + dsp = win32api.ExpandEnvironmentStrings(dsp) + # If the path to the .DSP file is not absolute, assume it is relative + # to the description file. + if not os.path.isabs(dsp): + dsp = os.path.join( os.path.split(mapFileName)[0], dsp) + # Parse it to extract the source files. + sourceFiles = parse_dsp(dsp) + if sourceFiles is None: + return None + + module = CExtension(moduleName, sourceFiles) + # Put the path to the DSP into the environment so entries can reference it. + os.environ['dsp_path'] = os.path.split(dsp)[0] + os.environ['ini_path'] = os.path.split(mapFileName)[0] + + cl_options = win32api.GetProfileVal(moduleName, "cl", "", mapFileName) + if cl_options: + module.AddCompilerOption(win32api.ExpandEnvironmentStrings(cl_options)) + + exclude = win32api.GetProfileVal(moduleName, "exclude", "", mapFileName) + exclude = exclude.split() + + if win32api.GetProfileVal(moduleName, "Unicode", 0, mapFileName): + module.AddCompilerOption('/D UNICODE /D _UNICODE') + + libs = win32api.GetProfileVal(moduleName, "libs", "", mapFileName).split() + for lib in libs: + module.AddLinkerLib(win32api.ExpandEnvironmentStrings(lib)) + + for exc in exclude: + if exc in module.sourceFiles: + modules.sourceFiles.remove(exc) + + return module + +# Given an MSVC DSP file, locate C source files it uses +# returns a list of source files. +def parse_dsp(dsp): +# print "Processing", dsp + # For now, only support + ret = [] + dsp_path, dsp_name = os.path.split(dsp) + try: + lines = open(dsp, "r").readlines() + except IOError, msg: + sys.stderr.write("%s: %s\n" % (dsp, msg)) + return None + for line in lines: + fields = line.strip().split("=", 2) + if fields[0]=="SOURCE": + if os.path.splitext(fields[1])[1].lower() in ['.cpp', '.c']: + ret.append( win32api.GetFullPathName(os.path.join(dsp_path, fields[1] ) ) ) + return ret + +def write_extension_table(fname, modules): + fp = open(fname, "w") + try: + fp.write (ext_src_header) + # Write fn protos + for module in modules: + # bit of a hack for .pyd's as part of packages. + name = module.name.split('.')[-1] + fp.write('extern void init%s(void);\n' % (name) ) + # Write the table + fp.write (ext_tab_header) + for module in modules: + name = module.name.split('.')[-1] + fp.write('\t{"%s", init%s},\n' % (name, name) ) + + fp.write (ext_tab_footer) + fp.write(ext_src_footer) + finally: + fp.close() + + +ext_src_header = """\ +#include "Python.h" +""" + +ext_tab_header = """\ + +static struct _inittab extensions[] = { +""" + +ext_tab_footer = """\ + /* Sentinel */ + {0, 0} +}; +""" + +ext_src_footer = """\ +extern DL_IMPORT(int) PyImport_ExtendInittab(struct _inittab *newtab); + +int PyInitFrozenExtensions() +{ + return PyImport_ExtendInittab(extensions); +} + +""" diff --git a/sys/src/cmd/python/Tools/freeze/extensions_win32.ini b/sys/src/cmd/python/Tools/freeze/extensions_win32.ini new file mode 100644 index 000000000..efc5e35a4 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/extensions_win32.ini @@ -0,0 +1,171 @@ +; This is a list of modules generally build as .pyd files. +; +; Each section contains enough information about a module for +; freeze to include the module as a static, built-in module +; in a frozen .EXE/.DLL. + +; This is all setup for all the win32 extension modules +; released by Mark Hammond. +; You must ensure that the environment variable PYTHONEX is set +; to point to the root win32 extensions directory + +; PYTHONPREFIX must point to the Python build root directory +; (the *parent* of PCbuild); normally the freeze script takes +; care of this. + + + + + +;-------------------------------------------------------------- +; +; Standard Python extension modules +; + +; Here are some of the standard Python extensions modules. +; If you need others, add them here + +[_socket] +dsp=%PYTHONPREFIX%\PCBuild\_socket.dsp + +[_sre] +dsp=%PYTHONPREFIX%\PCBuild\_sre.dsp + +[unicodedata] +dsp=%PYTHONPREFIX%\PCBuild\unicodedata.dsp + +[mmap] +dsp=%PYTHONPREFIX%\PCBuild\mmap.dsp + +[winsound] +dsp=%PYTHONPREFIX%\PCBuild\winsound.dsp +libs=winmm.lib + +[parser] +dsp=%PYTHONPREFIX%\PCBuild\parser.dsp + +[select] +dsp=%PYTHONPREFIX%\PCBuild\select.dsp + +[zlib] +dsp=%PYTHONPREFIX%\PCBuild\zlib.dsp +cl=/I %PYTHONPREFIX%\..\zlib-1.1.4 /D _WINDOWS /D WIN32 +libs=%PYTHONPREFIX%\..\zlib-1.1.4\zlib.lib /nodefaultlib:libc + +[_winreg] +dsp=%PYTHONPREFIX%\PCBuild\winreg.dsp +libs=advapi32.lib + + +;-------------------------------------------------------------- +; +; Win32 Projects. +; +[perfmon] +dsp=%PYTHONEX%\win32\perfmon.dsp +cl=/I %PYTHONEX%\win32\src +Unicode=1 + +[pywintypes] +dsp=%PYTHONEX%\win32\pywintypes.dsp +cl=/I %PYTHONEX%\win32\src +libs=ole32.lib oleaut32.lib + +[win32api] +dsp=%PYTHONEX%\win32\win32api.dsp +cl=/I %PYTHONEX%\win32\src +libs=kernel32.lib user32.lib shell32.lib advapi32.lib + +[win32service] +dsp=%PYTHONEX%\win32\win32service.dsp +cl=/I %PYTHONEX%\win32\src +Unicode=1 +libs=advapi32.lib + +[win32evtlog] +dsp=%PYTHONEX%\win32\win32evtlog.dsp +cl=/I %PYTHONEX%\win32\src + +[win32process] +dsp=%PYTHONEX%\win32\win32process.dsp +cl=/I %PYTHONEX%\win32\src + +[win32event] +dsp=%PYTHONEX%\win32\win32event.dsp +cl=/I %PYTHONEX%\win32\src + +[win32file] +dsp=%PYTHONEX%\win32\win32file.dsp +cl=/I %PYTHONEX%\win32\src + +[win32net] +dsp=%PYTHONEX%\win32\win32net.dsp +cl=/I %PYTHONEX%\win32\src +libs=netapi32.lib + +[win32pdh] +dsp=%PYTHONEX%\win32\win32pdh.dsp +cl=/I %PYTHONEX%\win32\src + +[win32pipe] +dsp=%PYTHONEX%\win32\win32pipe.dsp +cl=/I %PYTHONEX%\win32\src + +[win32security] +dsp=%PYTHONEX%\win32\win32security.dsp +cl=/I %PYTHONEX%\win32\src + +[win32service] +dsp=%PYTHONEX%\win32\win32service.dsp +cl=/I %PYTHONEX%\win32\src + +[win32trace] +dsp=%PYTHONEX%\win32\win32trace.dsp +cl=/I %PYTHONEX%\win32\src + +;-------------------------------------------------------------- +; +; COM Projects. +; + +[pythoncom] +dsp=%PYTHONEX%\com\win32com.dsp +cl=/I %PYTHONEX%\com\win32com\src\include /I %PYTHONEX%\win32\src +libs=uuid.lib + +[win32com.axcontrol.axcontrol] +dsp=%PYTHONEX%\com\axcontrol.dsp +cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include + +[win32com.axscript.axscript] +dsp=%PYTHONEX%\com\Active Scripting.dsp +cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include + +[win32com.axdebug.axdebug] +dsp=%PYTHONEX%\com\Active Debugging.dsp +cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include + +[win32com.mapi.mapi] +dsp=%PYTHONEX%\com\mapi.dsp +cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include +libs=MBLOGON.lib ADDRLKUP.LIB mapi32.lib version.lib + +[win32com.mapi.exchange] +dsp=%PYTHONEX%\com\exchange.dsp +cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include +libs=MBLOGON.lib ADDRLKUP.LIB exchinst.lib EDKCFG.LIB EDKUTILS.LIB EDKMAPI.LIB mapi32.lib version.lib + +[win32com.mapi.exchdapi] +dsp=%PYTHONEX%\com\exchdapi.dsp +cl=/I %PYTHONEX%\win32\src /I %PYTHONEX%\com\win32com\src\include +libs=DAPI.LIB + +[servicemanager] +dsp=%PYTHONEX%\win32\PythonService EXE.dsp +Unicode = 1 + +; Pythonwin +[win32ui] +dsp=%PYTHONEX%\Pythonwin\win32ui.dsp +cl=/D _AFXDLL /D FREEZE_WIN32UI /GX /I %PYTHONEX%\win32\src +libs=mfc42.lib diff --git a/sys/src/cmd/python/Tools/freeze/freeze.py b/sys/src/cmd/python/Tools/freeze/freeze.py new file mode 100755 index 000000000..836f53261 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/freeze.py @@ -0,0 +1,497 @@ +#! /usr/bin/env python + +"""Freeze a Python script into a binary. + +usage: freeze [options...] script [module]... + +Options: +-p prefix: This is the prefix used when you ran ``make install'' + in the Python build directory. + (If you never ran this, freeze won't work.) + The default is whatever sys.prefix evaluates to. + It can also be the top directory of the Python source + tree; then -P must point to the build tree. + +-P exec_prefix: Like -p but this is the 'exec_prefix', used to + install objects etc. The default is whatever sys.exec_prefix + evaluates to, or the -p argument if given. + If -p points to the Python source tree, -P must point + to the build tree, if different. + +-e extension: A directory containing additional .o files that + may be used to resolve modules. This directory + should also have a Setup file describing the .o files. + On Windows, the name of a .INI file describing one + or more extensions is passed. + More than one -e option may be given. + +-o dir: Directory where the output files are created; default '.'. + +-m: Additional arguments are module names instead of filenames. + +-a package=dir: Additional directories to be added to the package's + __path__. Used to simulate directories added by the + package at runtime (eg, by OpenGL and win32com). + More than one -a option may be given for each package. + +-l file: Pass the file to the linker (windows only) + +-d: Debugging mode for the module finder. + +-q: Make the module finder totally quiet. + +-h: Print this help message. + +-x module Exclude the specified module. It will still be imported + by the frozen binary if it exists on the host system. + +-X module Like -x, except the module can never be imported by + the frozen binary. + +-E: Freeze will fail if any modules can't be found (that + were not excluded using -x or -X). + +-i filename: Include a file with additional command line options. Used + to prevent command lines growing beyond the capabilities of + the shell/OS. All arguments specified in filename + are read and the -i option replaced with the parsed + params (note - quoting args in this file is NOT supported) + +-s subsystem: Specify the subsystem (For Windows only.); + 'console' (default), 'windows', 'service' or 'com_dll' + +-w: Toggle Windows (NT or 95) behavior. + (For debugging only -- on a win32 platform, win32 behavior + is automatic.) + +-r prefix=f: Replace path prefix. + Replace prefix with f in the source path references + contained in the resulting binary. + +Arguments: + +script: The Python script to be executed by the resulting binary. + +module ...: Additional Python modules (referenced by pathname) + that will be included in the resulting binary. These + may be .py or .pyc files. If -m is specified, these are + module names that are search in the path instead. + +NOTES: + +In order to use freeze successfully, you must have built Python and +installed it ("make install"). + +The script should not use modules provided only as shared libraries; +if it does, the resulting binary is not self-contained. +""" + + +# Import standard modules + +import modulefinder +import getopt +import os +import sys + + +# Import the freeze-private modules + +import checkextensions +import makeconfig +import makefreeze +import makemakefile +import parsesetup +import bkfile + + +# Main program + +def main(): + # overridable context + prefix = None # settable with -p option + exec_prefix = None # settable with -P option + extensions = [] + exclude = [] # settable with -x option + addn_link = [] # settable with -l, but only honored under Windows. + path = sys.path[:] + modargs = 0 + debug = 1 + odir = '' + win = sys.platform[:3] == 'win' + replace_paths = [] # settable with -r option + error_if_any_missing = 0 + + # default the exclude list for each platform + if win: exclude = exclude + [ + 'dos', 'dospath', 'mac', 'macpath', 'macfs', 'MACFS', 'posix', + 'os2', 'ce', 'riscos', 'riscosenviron', 'riscospath', + ] + + fail_import = exclude[:] + + # output files + frozen_c = 'frozen.c' + config_c = 'config.c' + target = 'a.out' # normally derived from script name + makefile = 'Makefile' + subsystem = 'console' + + # parse command line by first replacing any "-i" options with the + # file contents. + pos = 1 + while pos < len(sys.argv)-1: + # last option can not be "-i", so this ensures "pos+1" is in range! + if sys.argv[pos] == '-i': + try: + options = open(sys.argv[pos+1]).read().split() + except IOError, why: + usage("File name '%s' specified with the -i option " + "can not be read - %s" % (sys.argv[pos+1], why) ) + # Replace the '-i' and the filename with the read params. + sys.argv[pos:pos+2] = options + pos = pos + len(options) - 1 # Skip the name and the included args. + pos = pos + 1 + + # Now parse the command line with the extras inserted. + try: + opts, args = getopt.getopt(sys.argv[1:], 'r:a:dEe:hmo:p:P:qs:wX:x:l:') + except getopt.error, msg: + usage('getopt error: ' + str(msg)) + + # proces option arguments + for o, a in opts: + if o == '-h': + print __doc__ + return + if o == '-d': + debug = debug + 1 + if o == '-e': + extensions.append(a) + if o == '-m': + modargs = 1 + if o == '-o': + odir = a + if o == '-p': + prefix = a + if o == '-P': + exec_prefix = a + if o == '-q': + debug = 0 + if o == '-w': + win = not win + if o == '-s': + if not win: + usage("-s subsystem option only on Windows") + subsystem = a + if o == '-x': + exclude.append(a) + if o == '-X': + exclude.append(a) + fail_import.append(a) + if o == '-E': + error_if_any_missing = 1 + if o == '-l': + addn_link.append(a) + if o == '-a': + apply(modulefinder.AddPackagePath, tuple(a.split("=", 2))) + if o == '-r': + f,r = a.split("=", 2) + replace_paths.append( (f,r) ) + + # modules that are imported by the Python runtime + implicits = [] + for module in ('site', 'warnings',): + if module not in exclude: + implicits.append(module) + + # default prefix and exec_prefix + if not exec_prefix: + if prefix: + exec_prefix = prefix + else: + exec_prefix = sys.exec_prefix + if not prefix: + prefix = sys.prefix + + # determine whether -p points to the Python source tree + ishome = os.path.exists(os.path.join(prefix, 'Python', 'ceval.c')) + + # locations derived from options + version = sys.version[:3] + if win: + extensions_c = 'frozen_extensions.c' + if ishome: + print "(Using Python source directory)" + binlib = exec_prefix + incldir = os.path.join(prefix, 'Include') + config_h_dir = exec_prefix + config_c_in = os.path.join(prefix, 'Modules', 'config.c.in') + frozenmain_c = os.path.join(prefix, 'Python', 'frozenmain.c') + makefile_in = os.path.join(exec_prefix, 'Makefile') + if win: + frozendllmain_c = os.path.join(exec_prefix, 'Pc\\frozen_dllmain.c') + else: + binlib = os.path.join(exec_prefix, + 'lib', 'python%s' % version, 'config') + incldir = os.path.join(prefix, 'include', 'python%s' % version) + config_h_dir = os.path.join(exec_prefix, 'include', + 'python%s' % version) + config_c_in = os.path.join(binlib, 'config.c.in') + frozenmain_c = os.path.join(binlib, 'frozenmain.c') + makefile_in = os.path.join(binlib, 'Makefile') + frozendllmain_c = os.path.join(binlib, 'frozen_dllmain.c') + supp_sources = [] + defines = [] + includes = ['-I' + incldir, '-I' + config_h_dir] + + # sanity check of directories and files + check_dirs = [prefix, exec_prefix, binlib, incldir] + if not win: + # These are not directories on Windows. + check_dirs = check_dirs + extensions + for dir in check_dirs: + if not os.path.exists(dir): + usage('needed directory %s not found' % dir) + if not os.path.isdir(dir): + usage('%s: not a directory' % dir) + if win: + files = supp_sources + extensions # extensions are files on Windows. + else: + files = [config_c_in, makefile_in] + supp_sources + for file in supp_sources: + if not os.path.exists(file): + usage('needed file %s not found' % file) + if not os.path.isfile(file): + usage('%s: not a plain file' % file) + if not win: + for dir in extensions: + setup = os.path.join(dir, 'Setup') + if not os.path.exists(setup): + usage('needed file %s not found' % setup) + if not os.path.isfile(setup): + usage('%s: not a plain file' % setup) + + # check that enough arguments are passed + if not args: + usage('at least one filename argument required') + + # check that file arguments exist + for arg in args: + if arg == '-m': + break + # if user specified -m on the command line before _any_ + # file names, then nothing should be checked (as the + # very first file should be a module name) + if modargs: + break + if not os.path.exists(arg): + usage('argument %s not found' % arg) + if not os.path.isfile(arg): + usage('%s: not a plain file' % arg) + + # process non-option arguments + scriptfile = args[0] + modules = args[1:] + + # derive target name from script name + base = os.path.basename(scriptfile) + base, ext = os.path.splitext(base) + if base: + if base != scriptfile: + target = base + else: + target = base + '.bin' + + # handle -o option + base_frozen_c = frozen_c + base_config_c = config_c + base_target = target + if odir and not os.path.isdir(odir): + try: + os.mkdir(odir) + print "Created output directory", odir + except os.error, msg: + usage('%s: mkdir failed (%s)' % (odir, str(msg))) + base = '' + if odir: + base = os.path.join(odir, '') + frozen_c = os.path.join(odir, frozen_c) + config_c = os.path.join(odir, config_c) + target = os.path.join(odir, target) + makefile = os.path.join(odir, makefile) + if win: extensions_c = os.path.join(odir, extensions_c) + + # Handle special entry point requirements + # (on Windows, some frozen programs do not use __main__, but + # import the module directly. Eg, DLLs, Services, etc + custom_entry_point = None # Currently only used on Windows + python_entry_is_main = 1 # Is the entry point called __main__? + # handle -s option on Windows + if win: + import winmakemakefile + try: + custom_entry_point, python_entry_is_main = \ + winmakemakefile.get_custom_entry_point(subsystem) + except ValueError, why: + usage(why) + + + # Actual work starts here... + + # collect all modules of the program + dir = os.path.dirname(scriptfile) + path[0] = dir + mf = modulefinder.ModuleFinder(path, debug, exclude, replace_paths) + + if win and subsystem=='service': + # If a Windows service, then add the "built-in" module. + mod = mf.add_module("servicemanager") + mod.__file__="dummy.pyd" # really built-in to the resulting EXE + + for mod in implicits: + mf.import_hook(mod) + for mod in modules: + if mod == '-m': + modargs = 1 + continue + if modargs: + if mod[-2:] == '.*': + mf.import_hook(mod[:-2], None, ["*"]) + else: + mf.import_hook(mod) + else: + mf.load_file(mod) + + # Add the main script as either __main__, or the actual module name. + if python_entry_is_main: + mf.run_script(scriptfile) + else: + mf.load_file(scriptfile) + + if debug > 0: + mf.report() + print + dict = mf.modules + + if error_if_any_missing: + missing = mf.any_missing() + if missing: + sys.exit("There are some missing modules: %r" % missing) + + # generate output for frozen modules + files = makefreeze.makefreeze(base, dict, debug, custom_entry_point, + fail_import) + + # look for unfrozen modules (builtin and of unknown origin) + builtins = [] + unknown = [] + mods = dict.keys() + mods.sort() + for mod in mods: + if dict[mod].__code__: + continue + if not dict[mod].__file__: + builtins.append(mod) + else: + unknown.append(mod) + + # search for unknown modules in extensions directories (not on Windows) + addfiles = [] + frozen_extensions = [] # Windows list of modules. + if unknown or (not win and builtins): + if not win: + addfiles, addmods = \ + checkextensions.checkextensions(unknown+builtins, + extensions) + for mod in addmods: + if mod in unknown: + unknown.remove(mod) + builtins.append(mod) + else: + # Do the windows thang... + import checkextensions_win32 + # Get a list of CExtension instances, each describing a module + # (including its source files) + frozen_extensions = checkextensions_win32.checkextensions( + unknown, extensions, prefix) + for mod in frozen_extensions: + unknown.remove(mod.name) + + # report unknown modules + if unknown: + sys.stderr.write('Warning: unknown modules remain: %s\n' % + ' '.join(unknown)) + + # windows gets different treatment + if win: + # Taking a shortcut here... + import winmakemakefile, checkextensions_win32 + checkextensions_win32.write_extension_table(extensions_c, + frozen_extensions) + # Create a module definition for the bootstrap C code. + xtras = [frozenmain_c, os.path.basename(frozen_c), + frozendllmain_c, os.path.basename(extensions_c)] + files + maindefn = checkextensions_win32.CExtension( '__main__', xtras ) + frozen_extensions.append( maindefn ) + outfp = open(makefile, 'w') + try: + winmakemakefile.makemakefile(outfp, + locals(), + frozen_extensions, + os.path.basename(target)) + finally: + outfp.close() + return + + # generate config.c and Makefile + builtins.sort() + infp = open(config_c_in) + outfp = bkfile.open(config_c, 'w') + try: + makeconfig.makeconfig(infp, outfp, builtins) + finally: + outfp.close() + infp.close() + + cflags = ['$(OPT)'] + cppflags = defines + includes + libs = [os.path.join(binlib, 'libpython$(VERSION).a')] + + somevars = {} + if os.path.exists(makefile_in): + makevars = parsesetup.getmakevars(makefile_in) + for key in makevars.keys(): + somevars[key] = makevars[key] + + somevars['CFLAGS'] = ' '.join(cflags) # override + somevars['CPPFLAGS'] = ' '.join(cppflags) # override + files = [base_config_c, base_frozen_c] + \ + files + supp_sources + addfiles + libs + \ + ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)'] + + outfp = bkfile.open(makefile, 'w') + try: + makemakefile.makemakefile(outfp, somevars, files, base_target) + finally: + outfp.close() + + # Done! + + if odir: + print 'Now run "make" in', odir, + print 'to build the target:', base_target + else: + print 'Now run "make" to build the target:', base_target + + +# Print usage message and exit + +def usage(msg): + sys.stdout = sys.stderr + print "Error:", msg + print "Use ``%s -h'' for help" % sys.argv[0] + sys.exit(2) + + +main() diff --git a/sys/src/cmd/python/Tools/freeze/hello.py b/sys/src/cmd/python/Tools/freeze/hello.py new file mode 100644 index 000000000..f978acc88 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/hello.py @@ -0,0 +1 @@ +print 'Hello world...' diff --git a/sys/src/cmd/python/Tools/freeze/makeconfig.py b/sys/src/cmd/python/Tools/freeze/makeconfig.py new file mode 100644 index 000000000..7cd9b7847 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/makeconfig.py @@ -0,0 +1,61 @@ +import re + + +# Write the config.c file + +never = ['marshal', '__main__', '__builtin__', 'sys', 'exceptions'] + +def makeconfig(infp, outfp, modules, with_ifdef=0): + m1 = re.compile('-- ADDMODULE MARKER 1 --') + m2 = re.compile('-- ADDMODULE MARKER 2 --') + while 1: + line = infp.readline() + if not line: break + outfp.write(line) + if m1 and m1.search(line): + m1 = None + for mod in modules: + if mod in never: + continue + if with_ifdef: + outfp.write("#ifndef init%s\n"%mod) + outfp.write('extern void init%s(void);\n' % mod) + if with_ifdef: + outfp.write("#endif\n") + elif m2 and m2.search(line): + m2 = None + for mod in modules: + if mod in never: + continue + outfp.write('\t{"%s", init%s},\n' % + (mod, mod)) + if m1: + sys.stderr.write('MARKER 1 never found\n') + elif m2: + sys.stderr.write('MARKER 2 never found\n') + + +# Test program. + +def test(): + import sys + if not sys.argv[3:]: + print 'usage: python makeconfig.py config.c.in outputfile', + print 'modulename ...' + sys.exit(2) + if sys.argv[1] == '-': + infp = sys.stdin + else: + infp = open(sys.argv[1]) + if sys.argv[2] == '-': + outfp = sys.stdout + else: + outfp = open(sys.argv[2], 'w') + makeconfig(infp, outfp, sys.argv[3:]) + if outfp != sys.stdout: + outfp.close() + if infp != sys.stdin: + infp.close() + +if __name__ == '__main__': + test() diff --git a/sys/src/cmd/python/Tools/freeze/makefreeze.py b/sys/src/cmd/python/Tools/freeze/makefreeze.py new file mode 100644 index 000000000..1208b67fe --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/makefreeze.py @@ -0,0 +1,90 @@ +import marshal +import bkfile + + +# Write a file containing frozen code for the modules in the dictionary. + +header = """ +#include "Python.h" + +static struct _frozen _PyImport_FrozenModules[] = { +""" +trailer = """\ + {0, 0, 0} /* sentinel */ +}; +""" + +# if __debug__ == 0 (i.e. -O option given), set Py_OptimizeFlag in frozen app. +default_entry_point = """ +int +main(int argc, char **argv) +{ + extern int Py_FrozenMain(int, char **); +""" + ((not __debug__ and """ + Py_OptimizeFlag++; +""") or "") + """ + PyImport_FrozenModules = _PyImport_FrozenModules; + return Py_FrozenMain(argc, argv); +} + +""" + +def makefreeze(base, dict, debug=0, entry_point=None, fail_import=()): + if entry_point is None: entry_point = default_entry_point + done = [] + files = [] + mods = dict.keys() + mods.sort() + for mod in mods: + m = dict[mod] + mangled = "__".join(mod.split(".")) + if m.__code__: + file = 'M_' + mangled + '.c' + outfp = bkfile.open(base + file, 'w') + files.append(file) + if debug: + print "freezing", mod, "..." + str = marshal.dumps(m.__code__) + size = len(str) + if m.__path__: + # Indicate package by negative size + size = -size + done.append((mod, mangled, size)) + writecode(outfp, mangled, str) + outfp.close() + if debug: + print "generating table of frozen modules" + outfp = bkfile.open(base + 'frozen.c', 'w') + for mod, mangled, size in done: + outfp.write('extern unsigned char M_%s[];\n' % mangled) + outfp.write(header) + for mod, mangled, size in done: + outfp.write('\t{"%s", M_%s, %d},\n' % (mod, mangled, size)) + outfp.write('\n') + # The following modules have a NULL code pointer, indicating + # that the prozen program should not search for them on the host + # system. Importing them will *always* raise an ImportError. + # The zero value size is never used. + for mod in fail_import: + outfp.write('\t{"%s", NULL, 0},\n' % (mod,)) + outfp.write(trailer) + outfp.write(entry_point) + outfp.close() + return files + + + +# Write a C initializer for a module containing the frozen python code. +# The array is called M_<mod>. + +def writecode(outfp, mod, str): + outfp.write('unsigned char M_%s[] = {' % mod) + for i in range(0, len(str), 16): + outfp.write('\n\t') + for c in str[i:i+16]: + outfp.write('%d,' % ord(c)) + outfp.write('\n};\n') + +## def writecode(outfp, mod, str): +## outfp.write('unsigned char M_%s[%d] = "%s";\n' % (mod, len(str), +## '\\"'.join(map(lambda s: repr(s)[1:-1], str.split('"'))))) diff --git a/sys/src/cmd/python/Tools/freeze/makemakefile.py b/sys/src/cmd/python/Tools/freeze/makemakefile.py new file mode 100644 index 000000000..ff8b15a19 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/makemakefile.py @@ -0,0 +1,29 @@ +# Write the actual Makefile. + +import os + +def makemakefile(outfp, makevars, files, target): + outfp.write("# Makefile generated by freeze.py script\n\n") + + keys = makevars.keys() + keys.sort() + for key in keys: + outfp.write("%s=%s\n" % (key, makevars[key])) + outfp.write("\nall: %s\n\n" % target) + + deps = [] + for i in range(len(files)): + file = files[i] + if file[-2:] == '.c': + base = os.path.basename(file) + dest = base[:-2] + '.o' + outfp.write("%s: %s\n" % (dest, file)) + outfp.write("\t$(CC) $(CFLAGS) $(CPPFLAGS) -c %s\n" % file) + files[i] = dest + deps.append(dest) + + outfp.write("\n%s: %s\n" % (target, ' '.join(deps))) + outfp.write("\t$(LINKCC) $(LDFLAGS) $(LINKFORSHARED) %s -o %s $(LDLAST)\n" % + (' '.join(files), target)) + + outfp.write("\nclean:\n\t-rm -f *.o %s\n" % target) diff --git a/sys/src/cmd/python/Tools/freeze/parsesetup.py b/sys/src/cmd/python/Tools/freeze/parsesetup.py new file mode 100644 index 000000000..856234d44 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/parsesetup.py @@ -0,0 +1,112 @@ +# Parse Makefiles and Python Setup(.in) files. + +import re + + +# Extract variable definitions from a Makefile. +# Return a dictionary mapping names to values. +# May raise IOError. + +makevardef = re.compile('^([a-zA-Z0-9_]+)[ \t]*=(.*)') + +def getmakevars(filename): + variables = {} + fp = open(filename) + pendingline = "" + try: + while 1: + line = fp.readline() + if pendingline: + line = pendingline + line + pendingline = "" + if not line: + break + if line.endswith('\\\n'): + pendingline = line[:-2] + matchobj = makevardef.match(line) + if not matchobj: + continue + (name, value) = matchobj.group(1, 2) + # Strip trailing comment + i = value.find('#') + if i >= 0: + value = value[:i] + value = value.strip() + variables[name] = value + finally: + fp.close() + return variables + + +# Parse a Python Setup(.in) file. +# Return two dictionaries, the first mapping modules to their +# definitions, the second mapping variable names to their values. +# May raise IOError. + +setupvardef = re.compile('^([a-zA-Z0-9_]+)=(.*)') + +def getsetupinfo(filename): + modules = {} + variables = {} + fp = open(filename) + pendingline = "" + try: + while 1: + line = fp.readline() + if pendingline: + line = pendingline + line + pendingline = "" + if not line: + break + # Strip comments + i = line.find('#') + if i >= 0: + line = line[:i] + if line.endswith('\\\n'): + pendingline = line[:-2] + continue + matchobj = setupvardef.match(line) + if matchobj: + (name, value) = matchobj.group(1, 2) + variables[name] = value.strip() + else: + words = line.split() + if words: + modules[words[0]] = words[1:] + finally: + fp.close() + return modules, variables + + +# Test the above functions. + +def test(): + import sys + import os + if not sys.argv[1:]: + print 'usage: python parsesetup.py Makefile*|Setup* ...' + sys.exit(2) + for arg in sys.argv[1:]: + base = os.path.basename(arg) + if base[:8] == 'Makefile': + print 'Make style parsing:', arg + v = getmakevars(arg) + prdict(v) + elif base[:5] == 'Setup': + print 'Setup style parsing:', arg + m, v = getsetupinfo(arg) + prdict(m) + prdict(v) + else: + print arg, 'is neither a Makefile nor a Setup file' + print '(name must begin with "Makefile" or "Setup")' + +def prdict(d): + keys = d.keys() + keys.sort() + for key in keys: + value = d[key] + print "%-15s" % key, str(value) + +if __name__ == '__main__': + test() diff --git a/sys/src/cmd/python/Tools/freeze/win32.html b/sys/src/cmd/python/Tools/freeze/win32.html new file mode 100644 index 000000000..7e1d32d49 --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/win32.html @@ -0,0 +1,119 @@ +<HTML> +<HEAD> +<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252"> +<META NAME="Generator" CONTENT="Microsoft Word 97"> +<TITLE>win32</TITLE> +<META NAME="Version" CONTENT="8.0.3410"> +<META NAME="Date" CONTENT="10/11/96"> +<META NAME="Template" CONTENT="D:\Program Files\Microsoft Office\Office\HTML.DOT"> +</HEAD> +<BODY TEXT="#000000" BGCOLOR="#ffffff"> + +<H1>Freeze for Win32</H1> +<P>This document describes how to use Freeze for the Win32 platform. </P> +<P>Freeze itself is a Python tool for creating stand-alone executables from Python source code. This document does not attempt to document freeze itself - only the win32 specific changes.</P> +<H2>Frozen programs under Win32</H2> +<P>Frozen programs under Win32 can (theoretically) freeze any type of program supported by Python on Win32 - At the moment, Console .EXE and NT Service .EXE programs are supported. GUI Python programs and COM .EXE programs are very nearly all ready to go.</P> +<H3>Program Dependencies</H3> +<P>The person freezing the program has control over what external DLLs are required by a frozen program. The following dependencies are supported:</P> +<H4>Minimal frozen programs</H4> +<P>These programs freeze only .py files in your program. All external DLLs are required at run-time. This includes all .pyd/.dll modules used by your program, Python20.dll, and msvcrt.dll. </P> +<P>A small Python program would typically create a .EXE around 300kb.</P> +<H4>Frozen Extension programs</H4> +<B><I><P>Note:</B></I> For Python1.5.1, you must get a patch from Guido to import.c for this to work.</P> +<P>These programs also freeze in the sources from all .pyd and .dll files used at runtime. This means the resulting .EXE is only dependent on Python20.dll and msvcrt.dll.</P> +<P>A small Python program using win32api, win32con and one or 2 other win32 extensions would typically create a .EXE around 400kb.</P> +<H4>Completely frozen programs</H4> +<P>Completely stand-alone programs, as is the default on Unix systems. These are currently not supported, mainly as the size of a decent Python program gets very large. However, by tweaking the existing Unix support, this would not be difficult to do.</P> +<H2>Freezing Extension Modules</H2> +<P>By default, a file in the main "freeze" directory called "extensions_win32.ini" is used to obtain information about frozen extensions. A typical entry is:</P> +<CODE><P>[win32api]</P> +<P>dsp=%PYTHONEX%\win32\win32api.dsp</P> +<P>cl=/I %PYTHONEX%\win32\src</P> +<P>libs=kernel32.lib user32.lib shell32.lib advapi32.lib</P> +</CODE><P>&nbsp;</P> +<P>This entry indicates that the win32api extension module is defined in the MSVC project file "<CODE>%PYTHONEX%\win32\win32api.dsp</CODE>". Note the use of<CODE> </CODE>"<CODE>%PYTHONEX%" </CODE>- most strings are substituted with environment variables. In this case, it is assumed variable PYTHONEX points to the main "Python Extensions" source directory (which is assumed to be in the same structure as the release of the extension sources).</P> +<P>An entry in a .INI file can also control specific compiler options, and also the .lib files necessary to be linked with the application.</P> +<H3>Freezing Extension Module Considerations</H3> +<P>To prevent freezing extension modules, simply exclude that module using the freeze "-x" switch.</P> +<P>Occasionally, it will be necessary to explicitly include dependent modules. For example, many win32 modules are dependent on the "pywintypes" module - for example, the win32api module. In this case, the module may be explicitly included using the freeze "-m" option.</P> +<H3>Freezing win32com and PythonCOM</H3> +<P>PythonCOM.dll can be frozen as long as you are not implementing COM Servers. Ie, you can freeze programs which control other applications, but can not implement programs that are themselves controlled by other applications.</P> +<P>If you use any of the win32com .pyd extensions (ex, axscript, mapi, internet, axcontrol), then you will need to specify an additional "-a" option to point to the win32comext directory. There is an example below.</P> +<P>The use of the "win32com.client.gencache" module is not supported (although could be quite easily??)</P> +<H2>Examples</H2> +<P>Before we start, we must:</P> +<CODE><P>D:\temp\delme&gt;set PYTHONEX=d:\src\pythonex</P> +</CODE><H3>Helloworld.py</H3> +<H4>Source Code</H4><DIR> +<DIR> + +<CODE><P>import sys</P> +<P>&nbsp;</P> +<P>print " ".join( ["Hello", "world"] + sys.argv[1:] )</P></DIR> +</DIR> + +</CODE><H4>Command Line used</H4><DIR> +<DIR> + +<FONT FACE="Courier New" SIZE=2><P>\src\python-1.5.1\tools\freeze\freeze.py helloworld.py</P> +<P>nmake</P></DIR> +</DIR> + +</FONT><P>Resulting helloworld.exe: 114,688 bytes.</P> +<H3>Helloworld2.py</H3> +<P>Uses win32api. Demonstrates requirement for pywintypes, and difference between freezing extensions and not.</P> +<H4>Source Code</H4><DIR> +<DIR> + +<P>import win32api</P> +<P>print "Hello from", win32api.GetComputerName()</P></DIR> +</DIR> + +<H4>Command Line used</H4> +<P>By default, win32api will be frozen in with the .EXE. If you do not provide the "pywintypes" inclusion, then the link step will fail looking for all the pywintypes modules.</P><DIR> +<DIR> + +<FONT FACE="Courier New" SIZE=2><P>\src\python-1.5.1\tools\freeze\freeze.py helloworld2.py -m pywintypes</P> +<P>nmake</P></DIR> +</DIR> + +</FONT><P>Resulting helloworld2.exe: 167,936 bytes</P> +<P>Simply adding win32con to the mix gives an EXE of size: 352,768 bytes.</P> +<H4>Command Line used</H4> +<P>Using this build, we are dependent at runtime on the win32api.pyd and pywintypes15.dll files.</P><DIR> +<DIR> + +<P>\src\python-1.5.1\tools\freeze\freeze.py -x win32api helloworld.py</P></DIR> +</DIR> + +<P>Resulting helloworld2.exe: 114,688</P> +<P>Adding win32con to this build results in a size of: 252,928</P> +<H3>Testmapi.py</H3> +<P>Uses MAPI, a PythonCOM extension, and win32api.</P> +<H4>Source Code</H4> +<P>from win32com.mapi import mapi</P> +<P>import win32api</P> +<P>mapi.MAPIInitialize( (mapi.MAPI_INIT_VERSION, 0) )</P> +<P>print "Hello from", win32api.GetComputerName()</P> +<P>mapi.MAPIUninitialize()</P> +<H4>Command Line used</H4> +<P>As it does not import pythoncom or pywintypes itself, they must be specified. As it uses the win32comext directory, -a must be used. If you have built the win32com extensions from sources, then the second -a is required.</P><DIR> +<DIR> + +<CODE><P>\src\python-1.5.1\tools\freeze\freeze.py -a win32com=%PYTHONEX%\com\win32comext -a win32com.mapi=%PYTHONEX%\com\build\release testmapi.py -m pywintypes -m pythoncom</P></DIR> +</DIR> + +</CODE><P>Resulting testmapi.exe: 352,768 bytes</P> +<H3>PipeTestService.py</H3> +<P>This is a standard Python demo in the Win32 extensions. It can be found in the "win32\demos\service" directory.</P> +<H4>Command Line used</H4> +<P>This will create a native NT Service EXE, dependent only on the main Python20.dll. All other modules are built-in to the final .EXE</P><DIR> +<DIR> + +<CODE><P>\src\python-1.5.1\tools\freeze\freeze.py -s service %PYTHONEX%\win32\demos\service\pipeTestService.py</P></DIR> +</DIR> + +<P>Resulting pipeTestService.exe: </CODE><FONT FACE="Courier New" SIZE=2>533,504 bytes.</P></FONT></BODY> +</HTML> + diff --git a/sys/src/cmd/python/Tools/freeze/winmakemakefile.py b/sys/src/cmd/python/Tools/freeze/winmakemakefile.py new file mode 100644 index 000000000..8570f3d5c --- /dev/null +++ b/sys/src/cmd/python/Tools/freeze/winmakemakefile.py @@ -0,0 +1,146 @@ +import sys, os + +# Template used then the program is a GUI program +WINMAINTEMPLATE = """ +#include <windows.h> + +int WINAPI WinMain( + HINSTANCE hInstance, // handle to current instance + HINSTANCE hPrevInstance, // handle to previous instance + LPSTR lpCmdLine, // pointer to command line + int nCmdShow // show state of window + ) +{ + extern int Py_FrozenMain(int, char **); + PyImport_FrozenModules = _PyImport_FrozenModules; + return Py_FrozenMain(__argc, __argv); +} +""" + +SERVICETEMPLATE = """ +extern int PythonService_main(int, char **); + +int main( int argc, char **argv) +{ + PyImport_FrozenModules = _PyImport_FrozenModules; + return PythonService_main(argc, argv); +} +""" + +subsystem_details = { + # -s flag : (C entry point template), (is it __main__?), (is it a DLL?) + 'console' : (None, 1, 0), + 'windows' : (WINMAINTEMPLATE, 1, 0), + 'service' : (SERVICETEMPLATE, 0, 0), + 'com_dll' : ("", 0, 1), +} + +def get_custom_entry_point(subsystem): + try: + return subsystem_details[subsystem][:2] + except KeyError: + raise ValueError, "The subsystem %s is not known" % subsystem + + +def makemakefile(outfp, vars, files, target): + save = sys.stdout + try: + sys.stdout = outfp + realwork(vars, files, target) + finally: + sys.stdout = save + +def realwork(vars, moddefns, target): + version_suffix = "%r%r" % sys.version_info[:2] + print "# Makefile for Microsoft Visual C++ generated by freeze.py script" + print + print 'target = %s' % target + print 'pythonhome = %s' % vars['prefix'] + print + print 'DEBUG=0 # Set to 1 to use the _d versions of Python.' + print '!IF $(DEBUG)' + print 'debug_suffix=_d' + print 'c_debug=/Zi /Od /DDEBUG /D_DEBUG' + print 'l_debug=/DEBUG' + print 'temp_dir=Build\\Debug' + print '!ELSE' + print 'debug_suffix=' + print 'c_debug=/Ox' + print 'l_debug=' + print 'temp_dir=Build\\Release' + print '!ENDIF' + print + + print '# The following line assumes you have built Python using the standard instructions' + print '# Otherwise fix the following line to point to the library.' + print 'pythonlib = "$(pythonhome)/pcbuild/python%s$(debug_suffix).lib"' % version_suffix + print + + # We only ever write one "entry point" symbol - either + # "main" or "WinMain". Therefore, there is no need to + # pass a subsystem switch to the linker as it works it + # out all by itself. However, the subsystem _does_ determine + # the file extension and additional linker flags. + target_link_flags = "" + target_ext = ".exe" + if subsystem_details[vars['subsystem']][2]: + target_link_flags = "-dll" + target_ext = ".dll" + + + print "# As the target uses Python%s.dll, we must use this compiler option!" % version_suffix + print "cdl = /MD" + print + print "all: $(target)$(debug_suffix)%s" % (target_ext) + print + + print '$(temp_dir):' + print ' if not exist $(temp_dir)\. mkdir $(temp_dir)' + print + + objects = [] + libs = ["shell32.lib", "comdlg32.lib", "wsock32.lib", "user32.lib", "oleaut32.lib"] + for moddefn in moddefns: + print "# Module", moddefn.name + for file in moddefn.sourceFiles: + base = os.path.basename(file) + base, ext = os.path.splitext(base) + objects.append(base + ".obj") + print '$(temp_dir)\%s.obj: "%s"' % (base, file) + print "\t@$(CC) -c -nologo /Fo$* $(cdl) $(c_debug) /D BUILD_FREEZE", + print '"-I$(pythonhome)/Include" "-I$(pythonhome)/PC" \\' + print "\t\t$(cflags) $(cdebug) $(cinclude) \\" + extra = moddefn.GetCompilerOptions() + if extra: + print "\t\t%s \\" % (' '.join(extra),) + print '\t\t"%s"' % file + print + + # Add .lib files this module needs + for modlib in moddefn.GetLinkerLibs(): + if modlib not in libs: + libs.append(modlib) + + print "ADDN_LINK_FILES=", + for addn in vars['addn_link']: print '"%s"' % (addn), + print ; print + + print "OBJS=", + for obj in objects: print '"$(temp_dir)\%s"' % (obj), + print ; print + + print "LIBS=", + for lib in libs: print '"%s"' % (lib), + print ; print + + print "$(target)$(debug_suffix)%s: $(temp_dir) $(OBJS)" % (target_ext) + print "\tlink -out:$(target)$(debug_suffix)%s %s" % (target_ext, target_link_flags), + print "\t$(OBJS) \\" + print "\t$(LIBS) \\" + print "\t$(ADDN_LINK_FILES) \\" + print "\t$(pythonlib) $(lcustom) $(l_debug)\\" + print "\t$(resources)" + print + print "clean:" + print "\t-rm -f *.obj" + print "\t-rm -f $(target).exe" diff --git a/sys/src/cmd/python/Tools/i18n/makelocalealias.py b/sys/src/cmd/python/Tools/i18n/makelocalealias.py new file mode 100644 index 000000000..43df35a0a --- /dev/null +++ b/sys/src/cmd/python/Tools/i18n/makelocalealias.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +""" + Convert the X11 locale.alias file into a mapping dictionary suitable + for locale.py. + + Written by Marc-Andre Lemburg <mal@genix.com>, 2004-12-10. + +""" +import locale + +# Location of the alias file +LOCALE_ALIAS = '/usr/lib/X11/locale/locale.alias' + +def parse(filename): + + f = open(filename) + lines = f.read().splitlines() + data = {} + for line in lines: + line = line.strip() + if not line: + continue + if line[:1] == '#': + continue + locale, alias = line.split() + # Strip ':' + if locale[-1] == ':': + locale = locale[:-1] + # Lower-case locale + locale = locale.lower() + # Ignore one letter locale mappings (except for 'c') + if len(locale) == 1 and locale != 'c': + continue + # Normalize encoding, if given + if '.' in locale: + lang, encoding = locale.split('.')[:2] + encoding = encoding.replace('-', '') + encoding = encoding.replace('_', '') + locale = lang + '.' + encoding + if encoding.lower() == 'utf8': + # Ignore UTF-8 mappings - this encoding should be + # available for all locales + continue + data[locale] = alias + return data + +def pprint(data): + + items = data.items() + items.sort() + for k,v in items: + print ' %-40s%r,' % ('%r:' % k, v) + +def print_differences(data, olddata): + + items = olddata.items() + items.sort() + for k, v in items: + if not data.has_key(k): + print '# removed %r' % k + elif olddata[k] != data[k]: + print '# updated %r -> %r to %r' % \ + (k, olddata[k], data[k]) + # Additions are not mentioned + +if __name__ == '__main__': + data = locale.locale_alias.copy() + data.update(parse(LOCALE_ALIAS)) + print_differences(data, locale.locale_alias) + print + print 'locale_alias = {' + pprint(data) + print '}' diff --git a/sys/src/cmd/python/Tools/i18n/msgfmt.py b/sys/src/cmd/python/Tools/i18n/msgfmt.py new file mode 100755 index 000000000..64331313c --- /dev/null +++ b/sys/src/cmd/python/Tools/i18n/msgfmt.py @@ -0,0 +1,203 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-1 -*- +# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de> + +"""Generate binary message catalog from textual translation description. + +This program converts a textual Uniforum-style message catalog (.po file) into +a binary GNU catalog (.mo file). This is essentially the same function as the +GNU msgfmt program, however, it is a simpler implementation. + +Usage: msgfmt.py [OPTIONS] filename.po + +Options: + -o file + --output-file=file + Specify the output file to write to. If omitted, output will go to a + file named filename.mo (based off the input file name). + + -h + --help + Print this message and exit. + + -V + --version + Display version information and exit. +""" + +import sys +import os +import getopt +import struct +import array + +__version__ = "1.1" + +MESSAGES = {} + + + +def usage(code, msg=''): + print >> sys.stderr, __doc__ + if msg: + print >> sys.stderr, msg + sys.exit(code) + + + +def add(id, str, fuzzy): + "Add a non-fuzzy translation to the dictionary." + global MESSAGES + if not fuzzy and str: + MESSAGES[id] = str + + + +def generate(): + "Return the generated output." + global MESSAGES + keys = MESSAGES.keys() + # the keys are sorted in the .mo file + keys.sort() + offsets = [] + ids = strs = '' + for id in keys: + # For each string, we need size and file offset. Each string is NUL + # terminated; the NUL does not count into the size. + offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id]))) + ids += id + '\0' + strs += MESSAGES[id] + '\0' + output = '' + # The header is 7 32-bit unsigned integers. We don't use hash tables, so + # the keys start right after the index tables. + # translated string. + keystart = 7*4+16*len(keys) + # and the values start after the keys + valuestart = keystart + len(ids) + koffsets = [] + voffsets = [] + # The string table first has the list of keys, then the list of values. + # Each entry has first the size of the string, then the file offset. + for o1, l1, o2, l2 in offsets: + koffsets += [l1, o1+keystart] + voffsets += [l2, o2+valuestart] + offsets = koffsets + voffsets + output = struct.pack("Iiiiiii", + 0x950412deL, # Magic + 0, # Version + len(keys), # # of entries + 7*4, # start of key index + 7*4+len(keys)*8, # start of value index + 0, 0) # size and offset of hash table + output += array.array("i", offsets).tostring() + output += ids + output += strs + return output + + + +def make(filename, outfile): + ID = 1 + STR = 2 + + # Compute .mo name from .po name and arguments + if filename.endswith('.po'): + infile = filename + else: + infile = filename + '.po' + if outfile is None: + outfile = os.path.splitext(infile)[0] + '.mo' + + try: + lines = open(infile).readlines() + except IOError, msg: + print >> sys.stderr, msg + sys.exit(1) + + section = None + fuzzy = 0 + + # Parse the catalog + lno = 0 + for l in lines: + lno += 1 + # If we get a comment line after a msgstr, this is a new entry + if l[0] == '#' and section == STR: + add(msgid, msgstr, fuzzy) + section = None + fuzzy = 0 + # Record a fuzzy mark + if l[:2] == '#,' and 'fuzzy' in l: + fuzzy = 1 + # Skip comments + if l[0] == '#': + continue + # Now we are in a msgid section, output previous section + if l.startswith('msgid'): + if section == STR: + add(msgid, msgstr, fuzzy) + section = ID + l = l[5:] + msgid = msgstr = '' + # Now we are in a msgstr section + elif l.startswith('msgstr'): + section = STR + l = l[6:] + # Skip empty lines + l = l.strip() + if not l: + continue + # XXX: Does this always follow Python escape semantics? + l = eval(l) + if section == ID: + msgid += l + elif section == STR: + msgstr += l + else: + print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \ + 'before:' + print >> sys.stderr, l + sys.exit(1) + # Add last entry + if section == STR: + add(msgid, msgstr, fuzzy) + + # Compute output + output = generate() + + try: + open(outfile,"wb").write(output) + except IOError,msg: + print >> sys.stderr, msg + + + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], 'hVo:', + ['help', 'version', 'output-file=']) + except getopt.error, msg: + usage(1, msg) + + outfile = None + # parse options + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-V', '--version'): + print >> sys.stderr, "msgfmt.py", __version__ + sys.exit(0) + elif opt in ('-o', '--output-file'): + outfile = arg + # do it + if not args: + print >> sys.stderr, 'No input file given' + print >> sys.stderr, "Try `msgfmt --help' for more information." + return + + for filename in args: + make(filename, outfile) + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/i18n/pygettext.py b/sys/src/cmd/python/Tools/i18n/pygettext.py new file mode 100755 index 000000000..bb0dd35da --- /dev/null +++ b/sys/src/cmd/python/Tools/i18n/pygettext.py @@ -0,0 +1,669 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-1 -*- +# Originally written by Barry Warsaw <barry@zope.com> +# +# Minimally patched to make it even more xgettext compatible +# by Peter Funk <pf@artcom-gmbh.de> +# +# 2002-11-22 Jürgen Hermann <jh@web.de> +# Added checks that _() only contains string literals, and +# command line args are resolved to module lists, i.e. you +# can now pass a filename, a module or package name, or a +# directory (including globbing chars, important for Win32). +# Made docstring fit in 80 chars wide displays using pydoc. +# + +# for selftesting +try: + import fintl + _ = fintl.gettext +except ImportError: + _ = lambda s: s + +__doc__ = _("""pygettext -- Python equivalent of xgettext(1) + +Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the +internationalization of C programs. Most of these tools are independent of +the programming language and can be used from within Python programs. +Martin von Loewis' work[1] helps considerably in this regard. + +There's one problem though; xgettext is the program that scans source code +looking for message strings, but it groks only C (or C++). Python +introduces a few wrinkles, such as dual quoting characters, triple quoted +strings, and raw strings. xgettext understands none of this. + +Enter pygettext, which uses Python's standard tokenize module to scan +Python source code, generating .pot files identical to what GNU xgettext[2] +generates for C and C++ code. From there, the standard GNU tools can be +used. + +A word about marking Python strings as candidates for translation. GNU +xgettext recognizes the following keywords: gettext, dgettext, dcgettext, +and gettext_noop. But those can be a lot of text to include all over your +code. C and C++ have a trick: they use the C preprocessor. Most +internationalized C source includes a #define for gettext() to _() so that +what has to be written in the source is much less. Thus these are both +translatable strings: + + gettext("Translatable String") + _("Translatable String") + +Python of course has no preprocessor so this doesn't work so well. Thus, +pygettext searches only for _() by default, but see the -k/--keyword flag +below for how to augment this. + + [1] http://www.python.org/workshops/1997-10/proceedings/loewis.html + [2] http://www.gnu.org/software/gettext/gettext.html + +NOTE: pygettext attempts to be option and feature compatible with GNU +xgettext where ever possible. However some options are still missing or are +not fully implemented. Also, xgettext's use of command line switches with +option arguments is broken, and in these cases, pygettext just defines +additional switches. + +Usage: pygettext [options] inputfile ... + +Options: + + -a + --extract-all + Extract all strings. + + -d name + --default-domain=name + Rename the default output file from messages.pot to name.pot. + + -E + --escape + Replace non-ASCII characters with octal escape sequences. + + -D + --docstrings + Extract module, class, method, and function docstrings. These do + not need to be wrapped in _() markers, and in fact cannot be for + Python to consider them docstrings. (See also the -X option). + + -h + --help + Print this help message and exit. + + -k word + --keyword=word + Keywords to look for in addition to the default set, which are: + %(DEFAULTKEYWORDS)s + + You can have multiple -k flags on the command line. + + -K + --no-default-keywords + Disable the default set of keywords (see above). Any keywords + explicitly added with the -k/--keyword option are still recognized. + + --no-location + Do not write filename/lineno location comments. + + -n + --add-location + Write filename/lineno location comments indicating where each + extracted string is found in the source. These lines appear before + each msgid. The style of comments is controlled by the -S/--style + option. This is the default. + + -o filename + --output=filename + Rename the default output file from messages.pot to filename. If + filename is `-' then the output is sent to standard out. + + -p dir + --output-dir=dir + Output files will be placed in directory dir. + + -S stylename + --style stylename + Specify which style to use for location comments. Two styles are + supported: + + Solaris # File: filename, line: line-number + GNU #: filename:line + + The style name is case insensitive. GNU style is the default. + + -v + --verbose + Print the names of the files being processed. + + -V + --version + Print the version of pygettext and exit. + + -w columns + --width=columns + Set width of output to columns. + + -x filename + --exclude-file=filename + Specify a file that contains a list of strings that are not be + extracted from the input files. Each string to be excluded must + appear on a line by itself in the file. + + -X filename + --no-docstrings=filename + Specify a file that contains a list of files (one per line) that + should not have their docstrings extracted. This is only useful in + conjunction with the -D option above. + +If `inputfile' is -, standard input is read. +""") + +import os +import imp +import sys +import glob +import time +import getopt +import token +import tokenize +import operator + +__version__ = '1.5' + +default_keywords = ['_'] +DEFAULTKEYWORDS = ', '.join(default_keywords) + +EMPTYSTRING = '' + + + +# The normal pot-file header. msgmerge and Emacs's po-mode work better if it's +# there. +pot_header = _('''\ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\\n" +"POT-Creation-Date: %(time)s\\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n" +"Language-Team: LANGUAGE <LL@li.org>\\n" +"MIME-Version: 1.0\\n" +"Content-Type: text/plain; charset=CHARSET\\n" +"Content-Transfer-Encoding: ENCODING\\n" +"Generated-By: pygettext.py %(version)s\\n" + +''') + + +def usage(code, msg=''): + print >> sys.stderr, __doc__ % globals() + if msg: + print >> sys.stderr, msg + sys.exit(code) + + + +escapes = [] + +def make_escapes(pass_iso8859): + global escapes + if pass_iso8859: + # Allow iso-8859 characters to pass through so that e.g. 'msgid + # "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we + # escape any character outside the 32..126 range. + mod = 128 + else: + mod = 256 + for i in range(256): + if 32 <= (i % mod) <= 126: + escapes.append(chr(i)) + else: + escapes.append("\\%03o" % i) + escapes[ord('\\')] = '\\\\' + escapes[ord('\t')] = '\\t' + escapes[ord('\r')] = '\\r' + escapes[ord('\n')] = '\\n' + escapes[ord('\"')] = '\\"' + + +def escape(s): + global escapes + s = list(s) + for i in range(len(s)): + s[i] = escapes[ord(s[i])] + return EMPTYSTRING.join(s) + + +def safe_eval(s): + # unwrap quotes, safely + return eval(s, {'__builtins__':{}}, {}) + + +def normalize(s): + # This converts the various Python string types into a format that is + # appropriate for .po files, namely much closer to C style. + lines = s.split('\n') + if len(lines) == 1: + s = '"' + escape(s) + '"' + else: + if not lines[-1]: + del lines[-1] + lines[-1] = lines[-1] + '\n' + for i in range(len(lines)): + lines[i] = escape(lines[i]) + lineterm = '\\n"\n"' + s = '""\n"' + lineterm.join(lines) + '"' + return s + + +def containsAny(str, set): + """Check whether 'str' contains ANY of the chars in 'set'""" + return 1 in [c in str for c in set] + + +def _visit_pyfiles(list, dirname, names): + """Helper for getFilesForName().""" + # get extension for python source files + if not globals().has_key('_py_ext'): + global _py_ext + _py_ext = [triple[0] for triple in imp.get_suffixes() + if triple[2] == imp.PY_SOURCE][0] + + # don't recurse into CVS directories + if 'CVS' in names: + names.remove('CVS') + + # add all *.py files to list + list.extend( + [os.path.join(dirname, file) for file in names + if os.path.splitext(file)[1] == _py_ext] + ) + + +def _get_modpkg_path(dotted_name, pathlist=None): + """Get the filesystem path for a module or a package. + + Return the file system path to a file for a module, and to a directory for + a package. Return None if the name is not found, or is a builtin or + extension module. + """ + # split off top-most name + parts = dotted_name.split('.', 1) + + if len(parts) > 1: + # we have a dotted path, import top-level package + try: + file, pathname, description = imp.find_module(parts[0], pathlist) + if file: file.close() + except ImportError: + return None + + # check if it's indeed a package + if description[2] == imp.PKG_DIRECTORY: + # recursively handle the remaining name parts + pathname = _get_modpkg_path(parts[1], [pathname]) + else: + pathname = None + else: + # plain name + try: + file, pathname, description = imp.find_module( + dotted_name, pathlist) + if file: + file.close() + if description[2] not in [imp.PY_SOURCE, imp.PKG_DIRECTORY]: + pathname = None + except ImportError: + pathname = None + + return pathname + + +def getFilesForName(name): + """Get a list of module files for a filename, a module or package name, + or a directory. + """ + if not os.path.exists(name): + # check for glob chars + if containsAny(name, "*?[]"): + files = glob.glob(name) + list = [] + for file in files: + list.extend(getFilesForName(file)) + return list + + # try to find module or package + name = _get_modpkg_path(name) + if not name: + return [] + + if os.path.isdir(name): + # find all python files in directory + list = [] + os.path.walk(name, _visit_pyfiles, list) + return list + elif os.path.exists(name): + # a single file + return [name] + + return [] + + +class TokenEater: + def __init__(self, options): + self.__options = options + self.__messages = {} + self.__state = self.__waiting + self.__data = [] + self.__lineno = -1 + self.__freshmodule = 1 + self.__curfile = None + + def __call__(self, ttype, tstring, stup, etup, line): + # dispatch +## import token +## print >> sys.stderr, 'ttype:', token.tok_name[ttype], \ +## 'tstring:', tstring + self.__state(ttype, tstring, stup[0]) + + def __waiting(self, ttype, tstring, lineno): + opts = self.__options + # Do docstring extractions, if enabled + if opts.docstrings and not opts.nodocstrings.get(self.__curfile): + # module docstring? + if self.__freshmodule: + if ttype == tokenize.STRING: + self.__addentry(safe_eval(tstring), lineno, isdocstring=1) + self.__freshmodule = 0 + elif ttype not in (tokenize.COMMENT, tokenize.NL): + self.__freshmodule = 0 + return + # class docstring? + if ttype == tokenize.NAME and tstring in ('class', 'def'): + self.__state = self.__suiteseen + return + if ttype == tokenize.NAME and tstring in opts.keywords: + self.__state = self.__keywordseen + + def __suiteseen(self, ttype, tstring, lineno): + # ignore anything until we see the colon + if ttype == tokenize.OP and tstring == ':': + self.__state = self.__suitedocstring + + def __suitedocstring(self, ttype, tstring, lineno): + # ignore any intervening noise + if ttype == tokenize.STRING: + self.__addentry(safe_eval(tstring), lineno, isdocstring=1) + self.__state = self.__waiting + elif ttype not in (tokenize.NEWLINE, tokenize.INDENT, + tokenize.COMMENT): + # there was no class docstring + self.__state = self.__waiting + + def __keywordseen(self, ttype, tstring, lineno): + if ttype == tokenize.OP and tstring == '(': + self.__data = [] + self.__lineno = lineno + self.__state = self.__openseen + else: + self.__state = self.__waiting + + def __openseen(self, ttype, tstring, lineno): + if ttype == tokenize.OP and tstring == ')': + # We've seen the last of the translatable strings. Record the + # line number of the first line of the strings and update the list + # of messages seen. Reset state for the next batch. If there + # were no strings inside _(), then just ignore this entry. + if self.__data: + self.__addentry(EMPTYSTRING.join(self.__data)) + self.__state = self.__waiting + elif ttype == tokenize.STRING: + self.__data.append(safe_eval(tstring)) + elif ttype not in [tokenize.COMMENT, token.INDENT, token.DEDENT, + token.NEWLINE, tokenize.NL]: + # warn if we see anything else than STRING or whitespace + print >> sys.stderr, _( + '*** %(file)s:%(lineno)s: Seen unexpected token "%(token)s"' + ) % { + 'token': tstring, + 'file': self.__curfile, + 'lineno': self.__lineno + } + self.__state = self.__waiting + + def __addentry(self, msg, lineno=None, isdocstring=0): + if lineno is None: + lineno = self.__lineno + if not msg in self.__options.toexclude: + entry = (self.__curfile, lineno) + self.__messages.setdefault(msg, {})[entry] = isdocstring + + def set_filename(self, filename): + self.__curfile = filename + self.__freshmodule = 1 + + def write(self, fp): + options = self.__options + timestamp = time.strftime('%Y-%m-%d %H:%M+%Z') + # The time stamp in the header doesn't have the same format as that + # generated by xgettext... + print >> fp, pot_header % {'time': timestamp, 'version': __version__} + # Sort the entries. First sort each particular entry's keys, then + # sort all the entries by their first item. + reverse = {} + for k, v in self.__messages.items(): + keys = v.keys() + keys.sort() + reverse.setdefault(tuple(keys), []).append((k, v)) + rkeys = reverse.keys() + rkeys.sort() + for rkey in rkeys: + rentries = reverse[rkey] + rentries.sort() + for k, v in rentries: + isdocstring = 0 + # If the entry was gleaned out of a docstring, then add a + # comment stating so. This is to aid translators who may wish + # to skip translating some unimportant docstrings. + if reduce(operator.__add__, v.values()): + isdocstring = 1 + # k is the message string, v is a dictionary-set of (filename, + # lineno) tuples. We want to sort the entries in v first by + # file name and then by line number. + v = v.keys() + v.sort() + if not options.writelocations: + pass + # location comments are different b/w Solaris and GNU: + elif options.locationstyle == options.SOLARIS: + for filename, lineno in v: + d = {'filename': filename, 'lineno': lineno} + print >>fp, _( + '# File: %(filename)s, line: %(lineno)d') % d + elif options.locationstyle == options.GNU: + # fit as many locations on one line, as long as the + # resulting line length doesn't exceeds 'options.width' + locline = '#:' + for filename, lineno in v: + d = {'filename': filename, 'lineno': lineno} + s = _(' %(filename)s:%(lineno)d') % d + if len(locline) + len(s) <= options.width: + locline = locline + s + else: + print >> fp, locline + locline = "#:" + s + if len(locline) > 2: + print >> fp, locline + if isdocstring: + print >> fp, '#, docstring' + print >> fp, 'msgid', normalize(k) + print >> fp, 'msgstr ""\n' + + + +def main(): + global default_keywords + try: + opts, args = getopt.getopt( + sys.argv[1:], + 'ad:DEhk:Kno:p:S:Vvw:x:X:', + ['extract-all', 'default-domain=', 'escape', 'help', + 'keyword=', 'no-default-keywords', + 'add-location', 'no-location', 'output=', 'output-dir=', + 'style=', 'verbose', 'version', 'width=', 'exclude-file=', + 'docstrings', 'no-docstrings', + ]) + except getopt.error, msg: + usage(1, msg) + + # for holding option values + class Options: + # constants + GNU = 1 + SOLARIS = 2 + # defaults + extractall = 0 # FIXME: currently this option has no effect at all. + escape = 0 + keywords = [] + outpath = '' + outfile = 'messages.pot' + writelocations = 1 + locationstyle = GNU + verbose = 0 + width = 78 + excludefilename = '' + docstrings = 0 + nodocstrings = {} + + options = Options() + locations = {'gnu' : options.GNU, + 'solaris' : options.SOLARIS, + } + + # parse options + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-a', '--extract-all'): + options.extractall = 1 + elif opt in ('-d', '--default-domain'): + options.outfile = arg + '.pot' + elif opt in ('-E', '--escape'): + options.escape = 1 + elif opt in ('-D', '--docstrings'): + options.docstrings = 1 + elif opt in ('-k', '--keyword'): + options.keywords.append(arg) + elif opt in ('-K', '--no-default-keywords'): + default_keywords = [] + elif opt in ('-n', '--add-location'): + options.writelocations = 1 + elif opt in ('--no-location',): + options.writelocations = 0 + elif opt in ('-S', '--style'): + options.locationstyle = locations.get(arg.lower()) + if options.locationstyle is None: + usage(1, _('Invalid value for --style: %s') % arg) + elif opt in ('-o', '--output'): + options.outfile = arg + elif opt in ('-p', '--output-dir'): + options.outpath = arg + elif opt in ('-v', '--verbose'): + options.verbose = 1 + elif opt in ('-V', '--version'): + print _('pygettext.py (xgettext for Python) %s') % __version__ + sys.exit(0) + elif opt in ('-w', '--width'): + try: + options.width = int(arg) + except ValueError: + usage(1, _('--width argument must be an integer: %s') % arg) + elif opt in ('-x', '--exclude-file'): + options.excludefilename = arg + elif opt in ('-X', '--no-docstrings'): + fp = open(arg) + try: + while 1: + line = fp.readline() + if not line: + break + options.nodocstrings[line[:-1]] = 1 + finally: + fp.close() + + # calculate escapes + make_escapes(options.escape) + + # calculate all keywords + options.keywords.extend(default_keywords) + + # initialize list of strings to exclude + if options.excludefilename: + try: + fp = open(options.excludefilename) + options.toexclude = fp.readlines() + fp.close() + except IOError: + print >> sys.stderr, _( + "Can't read --exclude-file: %s") % options.excludefilename + sys.exit(1) + else: + options.toexclude = [] + + # resolve args to module lists + expanded = [] + for arg in args: + if arg == '-': + expanded.append(arg) + else: + expanded.extend(getFilesForName(arg)) + args = expanded + + # slurp through all the files + eater = TokenEater(options) + for filename in args: + if filename == '-': + if options.verbose: + print _('Reading standard input') + fp = sys.stdin + closep = 0 + else: + if options.verbose: + print _('Working on %s') % filename + fp = open(filename) + closep = 1 + try: + eater.set_filename(filename) + try: + tokenize.tokenize(fp.readline, eater) + except tokenize.TokenError, e: + print >> sys.stderr, '%s: %s, line %d, column %d' % ( + e[0], filename, e[1][0], e[1][1]) + finally: + if closep: + fp.close() + + # write the output + if options.outfile == '-': + fp = sys.stdout + closep = 0 + else: + if options.outpath: + options.outfile = os.path.join(options.outpath, options.outfile) + fp = open(options.outfile, 'w') + closep = 1 + try: + eater.write(fp) + finally: + if closep: + fp.close() + + +if __name__ == '__main__': + main() + # some more test strings + _(u'a unicode string') + # this one creates a warning + _('*** Seen unexpected token "%(token)s"') % {'token': 'test'} + _('more' 'than' 'one' 'string') diff --git a/sys/src/cmd/python/Tools/modulator/EXAMPLE.py b/sys/src/cmd/python/Tools/modulator/EXAMPLE.py new file mode 100644 index 000000000..b36a5a761 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/EXAMPLE.py @@ -0,0 +1,53 @@ +# +# Example input file for modulator if you don't have tk. +# +# You may also have to strip some imports out of modulator to make +# it work. + +import genmodule + +# +# Generate code for a simple object with a method called sample + +o = genmodule.object() +o.name = 'simple object' +o.abbrev = 'simp' +o.methodlist = ['sample'] +o.funclist = ['new'] + +# +# Generate code for an object that looks numberish +# +o2 = genmodule.object() +o2.name = 'number-like object' +o2.abbrev = 'nl' +o2.typelist = ['tp_as_number'] +o2.funclist = ['new', 'tp_repr', 'tp_compare'] + +# +# Generate code for a method with a full complement of functions, +# some methods, accessible as sequence and allowing structmember.c type +# structure access as well. +# +o3 = genmodule.object() +o3.name = 'over-the-top object' +o3.abbrev = 'ot' +o3.methodlist = ['method1', 'method2'] +o3.funclist = ['new', 'tp_dealloc', 'tp_print', 'tp_getattr', 'tp_setattr', + 'tp_compare', 'tp_repr', 'tp_hash'] +o3.typelist = ['tp_as_sequence', 'structure'] + +# +# Now generate code for a module that incorporates these object types. +# Also add the boilerplates for functions to create instances of each +# type. +# +m = genmodule.module() +m.name = 'sample' +m.abbrev = 'sample' +m.methodlist = ['newsimple', 'newnumberish', 'newott'] +m.objects = [o, o2, o3] + +fp = open('EXAMPLEmodule.c', 'w') +genmodule.write(fp, m) +fp.close() diff --git a/sys/src/cmd/python/Tools/modulator/README b/sys/src/cmd/python/Tools/modulator/README new file mode 100644 index 000000000..aae86b4a7 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/README @@ -0,0 +1,25 @@ +This is release 1.2 of modulator, a generator of boilerplate code for +modules to be written in C. + +Difference between 1.2 and 1.1: __doc__ templates are now generated +(thanks to Jim Fulton). + +Difference between 1.1 and 1.0: the templates now use "new-style" +naming conventions. Many thanks to Chak Tan <tan@ee.rochester.edu> for +supplying them. + +Usage when you have tk is *really* simple: start modulator, fill out +the forms specifying all the objects and methods, tell modulator +whether objects should also be accessible as sequences, etc and press +'generate code'. It will write a complete skeleton module for you. + +Usage when you don't have tk is slightly more difficult. Look at +EXAMPLE.py for some details (to run, use "python EXAMPLE.py"). Don't +bother with EXAMPLE.py if you have Tkinter!!! + +Oh yeah: you'll probably want to change Templates/copyright, or all +your code ends up as being copyrighted to CWI:-) + +Let me know what you think, + Jack Jansen, jack@cwi.nl + diff --git a/sys/src/cmd/python/Tools/modulator/ScrolledListbox.py b/sys/src/cmd/python/Tools/modulator/ScrolledListbox.py new file mode 100644 index 000000000..8bb5738f1 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/ScrolledListbox.py @@ -0,0 +1,37 @@ +# A ScrolledList widget feels like a list widget but also has a +# vertical scroll bar on its right. (Later, options may be added to +# add a horizontal bar as well, to make the bars disappear +# automatically when not needed, to move them to the other side of the +# window, etc.) +# +# Configuration options are passed to the List widget. +# A Frame widget is inserted between the master and the list, to hold +# the Scrollbar widget. +# Most methods calls are inherited from the List widget; Pack methods +# are redirected to the Frame widget however. + +from Tkinter import * +from Tkinter import _cnfmerge + +class ScrolledListbox(Listbox): + def __init__(self, master=None, cnf={}): + cnf = _cnfmerge(cnf) + fcnf = {} + vcnf = {'name': 'vbar', + Pack: {'side': 'right', 'fill': 'y'},} + for k in cnf.keys(): + if type(k) == ClassType or k == 'name': + fcnf[k] = cnf[k] + del cnf[k] + self.frame = Frame(master, fcnf) + self.vbar = Scrollbar(self.frame, vcnf) + cnf[Pack] = {'side': 'left', 'fill': 'both', 'expand': 'yes'} + cnf['name'] = 'list' + Listbox.__init__(self, self.frame, cnf) + self['yscrollcommand'] = (self.vbar, 'set') + self.vbar['command'] = (self, 'yview') + + # Copy Pack methods of self.frame -- hack! + for m in Pack.__dict__.keys(): + if m[0] != '_' and m != 'config': + setattr(self, m, getattr(self.frame, m)) diff --git a/sys/src/cmd/python/Tools/modulator/Templates/copyright b/sys/src/cmd/python/Tools/modulator/Templates/copyright new file mode 100644 index 000000000..e69de29bb diff --git a/sys/src/cmd/python/Tools/modulator/Templates/module_head b/sys/src/cmd/python/Tools/modulator/Templates/module_head new file mode 100644 index 000000000..be001090b --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/module_head @@ -0,0 +1,6 @@ + +#include "Python.h" + +static PyObject *ErrorObject; + +/* ----------------------------------------------------- */ diff --git a/sys/src/cmd/python/Tools/modulator/Templates/module_method b/sys/src/cmd/python/Tools/modulator/Templates/module_method new file mode 100644 index 000000000..3048b1fc4 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/module_method @@ -0,0 +1,14 @@ + +static char $abbrev$_$method$__doc__[] = +"" +; + +static PyObject * +$abbrev$_$method$(PyObject *self /* Not used */, PyObject *args) +{ + + if (!PyArg_ParseTuple(args, "")) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/module_tail b/sys/src/cmd/python/Tools/modulator/Templates/module_tail new file mode 100644 index 000000000..59cc50b6c --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/module_tail @@ -0,0 +1,37 @@ + +/* List of methods defined in the module */ + +static struct PyMethodDef $abbrev$_methods[] = { + $methodlist$ + {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ +}; + + +/* Initialization function for the module (*must* be called init$name$) */ + +static char $name$_module_documentation[] = +"" +; + +void +init$name$() +{ + PyObject *m, *d; + + /* Create the module and add the functions */ + m = Py_InitModule4("$name$", $abbrev$_methods, + $name$_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); + + /* Add some symbolic constants to the module */ + d = PyModule_GetDict(m); + ErrorObject = PyString_FromString("$name$.error"); + PyDict_SetItemString(d, "error", ErrorObject); + + /* XXXX Add constants here */ + + /* Check for errors */ + if (PyErr_Occurred()) + Py_FatalError("can't initialize module $name$"); +} + diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_head b/sys/src/cmd/python/Tools/modulator/Templates/object_head new file mode 100644 index 000000000..07d1f6a9f --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_head @@ -0,0 +1,13 @@ + +/* Declarations for objects of type $name$ */ + +typedef struct { + PyObject_HEAD + /* XXXX Add your own stuff here */ +} $abbrev$object; + +static PyTypeObject $Abbrev$type; + + + +/* ---------------------------------------------------------------- */ diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_method b/sys/src/cmd/python/Tools/modulator/Templates/object_method new file mode 100644 index 000000000..b15162c31 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_method @@ -0,0 +1,14 @@ + +static char $abbrev$_$method$__doc__[] = +"" +; + +static PyObject * +$abbrev$_$method$($abbrev$object *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, "")) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_mlist b/sys/src/cmd/python/Tools/modulator/Templates/object_mlist new file mode 100644 index 000000000..a12a9e1be --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_mlist @@ -0,0 +1,8 @@ + +static struct PyMethodDef $abbrev$_methods[] = { + $methodlist$ + {NULL, NULL} /* sentinel */ +}; + +/* ---------- */ + diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_new b/sys/src/cmd/python/Tools/modulator/Templates/object_new new file mode 100644 index 000000000..30c5e363e --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_new @@ -0,0 +1,13 @@ + +static $abbrev$object * +new$abbrev$object() +{ + $abbrev$object *self; + + self = PyObject_NEW($abbrev$object, &$Abbrev$type); + if (self == NULL) + return NULL; + /* XXXX Add your own initializers here */ + return self; +} + diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_structure b/sys/src/cmd/python/Tools/modulator/Templates/object_structure new file mode 100644 index 000000000..573ac8db9 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_structure @@ -0,0 +1,37 @@ + +/* Code to access structure members by accessing attributes */ + +#include "structmember.h" + +#define OFF(x) offsetof(XXXXobject, x) + +static struct memberlist $abbrev$_memberlist[] = { + /* XXXX Add lines like { "foo", T_INT, OFF(foo), RO } */ + + {NULL} /* Sentinel */ +}; + +static PyObject * +$abbrev$_getattr($abbrev$object *self, char *name) +{ + PyObject *rv; + + /* XXXX Add your own getattr code here */ + rv = PyMember_Get((char *)/*XXXX*/0, $abbrev$_memberlist, name); + if (rv) + return rv; + PyErr_Clear(); + return Py_FindMethod($abbrev$_methods, (PyObject *)self, name); +} + + +static int +$abbrev$_setattr($abbrev$object *self, char *name, PyObject *v) +{ + /* XXXX Add your own setattr code here */ + if ( v == NULL ) { + PyErr_SetString(PyExc_AttributeError, "Cannot delete attribute"); + return -1; + } + return PyMember_Set((char *)/*XXXX*/0, $abbrev$_memberlist, name, v); +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tail b/sys/src/cmd/python/Tools/modulator/Templates/object_tail new file mode 100644 index 000000000..1d1334c9f --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tail @@ -0,0 +1,33 @@ + +static char $Abbrev$type__doc__[] = +"" +; + +static PyTypeObject $Abbrev$type = { + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "$name$", /*tp_name*/ + sizeof($abbrev$object), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)$tp_dealloc$, /*tp_dealloc*/ + (printfunc)$tp_print$, /*tp_print*/ + (getattrfunc)$tp_getattr$, /*tp_getattr*/ + (setattrfunc)$tp_setattr$, /*tp_setattr*/ + (cmpfunc)$tp_compare$, /*tp_compare*/ + (reprfunc)$tp_repr$, /*tp_repr*/ + $tp_as_number$, /*tp_as_number*/ + $tp_as_sequence$, /*tp_as_sequence*/ + $tp_as_mapping$, /*tp_as_mapping*/ + (hashfunc)$tp_hash$, /*tp_hash*/ + (ternaryfunc)$tp_call$, /*tp_call*/ + (reprfunc)$tp_str$, /*tp_str*/ + + /* Space for future expansion */ + 0L,0L,0L,0L, + $Abbrev$type__doc__ /* Documentation string */ +}; + +/* End of code for $name$ objects */ +/* -------------------------------------------------------- */ + diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_mapping b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_mapping new file mode 100644 index 000000000..f9213b70e --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_mapping @@ -0,0 +1,29 @@ + +/* Code to access $name$ objects as mappings */ + +static int +$abbrev$_length($abbrev$object *self) +{ + /* XXXX Return the size of the mapping */ +} + +static PyObject * +$abbrev$_subscript($abbrev$object *self, PyObject *key) +{ + /* XXXX Return the item of self indexed by key */ +} + +static int +$abbrev$_ass_sub($abbrev$object *self, PyObject *v, PyObject *w) +{ + /* XXXX Put w in self under key v */ + return 0; +} + +static PyMappingMethods $abbrev$_as_mapping = { + (inquiry)$abbrev$_length, /*mp_length*/ + (binaryfunc)$abbrev$_subscript, /*mp_subscript*/ + (objobjargproc)$abbrev$_ass_sub, /*mp_ass_subscript*/ +}; + +/* -------------------------------------------------------- */ diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_number b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_number new file mode 100644 index 000000000..e69aa9a55 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_number @@ -0,0 +1,169 @@ + +/* Code to access $name$ objects as numbers */ + +static PyObject * +$abbrev$_add($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX Add them */ +} + +static PyObject * +$abbrev$_sub($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX Subtract them */ +} + +static PyObject * +$abbrev$_mul($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX Multiply them */ +} + +static PyObject * +$abbrev$_div($abbrev$object *x, $abbrev$object *y) +{ + /* XXXX Divide them */ +} + +static PyObject * +$abbrev$_mod($abbrev$object *x, $abbrev$object *y) +{ + /* XXXX Modulo them */ +} + +static PyObject * +$abbrev$_divmod($abbrev$object *x, $abbrev$object *y) +{ + /* XXXX Return 2-tuple with div and mod */ +} + +static PyObject * +$abbrev$_pow($abbrev$object *v, $abbrev$object *w, $abbrev$object *z) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_neg($abbrev$object *v) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_pos($abbrev$object *v) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_abs($abbrev$object *v) +{ + /* XXXX */ +} + +static int +$abbrev$_nonzero($abbrev$object *v) +{ + /* XXXX Return 1 if non-zero */ +} + +static PyObject * +$abbrev$_invert($abbrev$object *v) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_lshift($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_rshift($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_and($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_xor($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_or($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX */ +} + +static int +$abbrev$_coerce(PyObject **pv, PyObject **pw) +{ + /* XXXX I haven't a clue... */ + return 1; +} + +static PyObject * +$abbrev$_int($abbrev$object *v) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_long($abbrev$object *v) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_float($abbrev$object *v) +{ + /* XXXX */ +} + +static PyObject * +$abbrev$_oct($abbrev$object *v) +{ + /* XXXX Return object as octal stringobject */ +} + +static PyObject * +$abbrev$_hex($abbrev$object *v) +{ + /* XXXX Return object as hex stringobject */ +} + +static PyNumberMethods $abbrev$_as_number = { + (binaryfunc)$abbrev$_add, /*nb_add*/ + (binaryfunc)$abbrev$_sub, /*nb_subtract*/ + (binaryfunc)$abbrev$_mul, /*nb_multiply*/ + (binaryfunc)$abbrev$_div, /*nb_divide*/ + (binaryfunc)$abbrev$_mod, /*nb_remainder*/ + (binaryfunc)$abbrev$_divmod, /*nb_divmod*/ + (ternaryfunc)$abbrev$_pow, /*nb_power*/ + (unaryfunc)$abbrev$_neg, /*nb_negative*/ + (unaryfunc)$abbrev$_pos, /*nb_positive*/ + (unaryfunc)$abbrev$_abs, /*nb_absolute*/ + (inquiry)$abbrev$_nonzero, /*nb_nonzero*/ + (unaryfunc)$abbrev$_invert, /*nb_invert*/ + (binaryfunc)$abbrev$_lshift, /*nb_lshift*/ + (binaryfunc)$abbrev$_rshift, /*nb_rshift*/ + (binaryfunc)$abbrev$_and, /*nb_and*/ + (binaryfunc)$abbrev$_xor, /*nb_xor*/ + (binaryfunc)$abbrev$_or, /*nb_or*/ + (coercion)$abbrev$_coerce, /*nb_coerce*/ + (unaryfunc)$abbrev$_int, /*nb_int*/ + (unaryfunc)$abbrev$_long, /*nb_long*/ + (unaryfunc)$abbrev$_float, /*nb_float*/ + (unaryfunc)$abbrev$_oct, /*nb_oct*/ + (unaryfunc)$abbrev$_hex, /*nb_hex*/ +}; + +/* ------------------------------------------------------- */ diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_sequence b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_sequence new file mode 100644 index 000000000..54c0b9290 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_as_sequence @@ -0,0 +1,58 @@ + +/* Code to handle accessing $name$ objects as sequence objects */ + +static int +$abbrev$_length($abbrev$object *self) +{ + /* XXXX Return the size of the object */ +} + +static PyObject * +$abbrev$_concat($abbrev$object *self, PyObject *bb) +{ + /* XXXX Return the concatenation of self and bb */ +} + +static PyObject * +$abbrev$_repeat($abbrev$object *self, int n) +{ + /* XXXX Return a new object that is n times self */ +} + +static PyObject * +$abbrev$_item($abbrev$object *self, int i) +{ + /* XXXX Return the i-th object of self */ +} + +static PyObject * +$abbrev$_slice($abbrev$object *self, int ilow, int ihigh) +{ + /* XXXX Return the ilow..ihigh slice of self in a new object */ +} + +static int +$abbrev$_ass_item($abbrev$object *self, int i, PyObject *v) +{ + /* XXXX Assign to the i-th element of self */ + return 0; +} + +static int +$abbrev$_ass_slice(PyListObject *self, int ilow, int ihigh, PyObject *v) +{ + /* XXXX Replace ilow..ihigh slice of self with v */ + return 0; +} + +static PySequenceMethods $abbrev$_as_sequence = { + (inquiry)$abbrev$_length, /*sq_length*/ + (binaryfunc)$abbrev$_concat, /*sq_concat*/ + (intargfunc)$abbrev$_repeat, /*sq_repeat*/ + (intargfunc)$abbrev$_item, /*sq_item*/ + (intintargfunc)$abbrev$_slice, /*sq_slice*/ + (intobjargproc)$abbrev$_ass_item, /*sq_ass_item*/ + (intintobjargproc)$abbrev$_ass_slice, /*sq_ass_slice*/ +}; + +/* -------------------------------------------------------------- */ diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_call b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_call new file mode 100644 index 000000000..a93f17fd6 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_call @@ -0,0 +1,7 @@ + +static PyObject * +$abbrev$_call($abbrev$object *self, PyObject *args, PyObject *kwargs) +{ + /* XXXX Return the result of calling self with argument args */ +} + diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_compare b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_compare new file mode 100644 index 000000000..153bae0bd --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_compare @@ -0,0 +1,6 @@ + +static int +$abbrev$_compare($abbrev$object *v, $abbrev$object *w) +{ + /* XXXX Compare objects and return -1, 0 or 1 */ +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_dealloc b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_dealloc new file mode 100644 index 000000000..440419a52 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_dealloc @@ -0,0 +1,7 @@ + +static void +$abbrev$_dealloc($abbrev$object *self) +{ + /* XXXX Add your own cleanup code here */ + PyMem_DEL(self); +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_getattr b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_getattr new file mode 100644 index 000000000..6a1b2e866 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_getattr @@ -0,0 +1,7 @@ + +static PyObject * +$abbrev$_getattr($abbrev$object *self, char *name) +{ + /* XXXX Add your own getattr code here */ + return Py_FindMethod($abbrev$_methods, (PyObject *)self, name); +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_hash b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_hash new file mode 100644 index 000000000..2d63f6a8a --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_hash @@ -0,0 +1,6 @@ + +static long +$abbrev$_hash($abbrev$object *self) +{ + /* XXXX Return a hash of self (or -1) */ +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_print b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_print new file mode 100644 index 000000000..76408d234 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_print @@ -0,0 +1,7 @@ + +static int +$abbrev$_print($abbrev$object *self, FILE *fp, int flags) +{ + /* XXXX Add code here to print self to fp */ + return 0; +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_repr b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_repr new file mode 100644 index 000000000..f12222508 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_repr @@ -0,0 +1,9 @@ + +static PyObject * +$abbrev$_repr($abbrev$object *self) +{ + PyObject *s; + + /* XXXX Add code here to put self into s */ + return s; +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_setattr b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_setattr new file mode 100644 index 000000000..dfe4bc8c7 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_setattr @@ -0,0 +1,9 @@ + +static int +$abbrev$_setattr($abbrev$object *self, char *name, PyObject *v) +{ + /* Set attribute 'name' to value 'v'. v==NULL means delete */ + + /* XXXX Add your own setattr code here */ + return -1; +} diff --git a/sys/src/cmd/python/Tools/modulator/Templates/object_tp_str b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_str new file mode 100644 index 000000000..2e3648e83 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Templates/object_tp_str @@ -0,0 +1,10 @@ + +static PyObject * +$abbrev$_str($abbrev$object *self) +{ + PyObject *s; + + /* XXXX Add code here to put self into s */ + return s; +} + diff --git a/sys/src/cmd/python/Tools/modulator/Tkextra.py b/sys/src/cmd/python/Tools/modulator/Tkextra.py new file mode 100755 index 000000000..8f557286f --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/Tkextra.py @@ -0,0 +1,235 @@ +#! /usr/bin/env python + +# A Python function that generates dialog boxes with a text message, +# optional bitmap, and any number of buttons. +# Cf. Ousterhout, Tcl and the Tk Toolkit, Figs. 27.2-3, pp. 269-270. + +from Tkinter import * + +mainWidget = None + +def dialog(master, title, text, bitmap, default, *args): + + # 1. Create the top-level window and divide it into top + # and bottom parts. + + w = Toplevel(master, {'class': 'Dialog'}) + w.title(title) + w.iconname('Dialog') + + top = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'top', 'fill': 'both'}}) + bot = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'bottom', 'fill': 'both'}}) + + # 2. Fill the top part with the bitmap and message. + + msg = Message(top, + {'width': '3i', + 'text': text, + 'font': '-Adobe-Times-Medium-R-Normal-*-180-*', + Pack: {'side': 'right', 'expand': 1, + 'fill': 'both', + 'padx': '3m', 'pady': '3m'}}) + if bitmap: + bm = Label(top, {'bitmap': bitmap, + Pack: {'side': 'left', + 'padx': '3m', 'pady': '3m'}}) + + # 3. Create a row of buttons at the bottom of the dialog. + + buttons = [] + i = 0 + for but in args: + b = Button(bot, {'text': but, + 'command': ('set', 'button', i)}) + buttons.append(b) + if i == default: + bd = Frame(bot, {'relief': 'sunken', 'bd': 1, + Pack: {'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '2m'}}) + b.lift() + b.pack ({'in': bd, 'side': 'left', + 'padx': '2m', 'pady': '2m', + 'ipadx': '2m', 'ipady': '1m'}) + else: + b.pack ({'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '3m', + 'ipady': '2m', 'ipady': '1m'}) + i = i+1 + + # 4. Set up a binding for <Return>, if there's a default, + # set a grab, and claim the focus too. + + if default >= 0: + w.bind('<Return>', + lambda e, b=buttons[default], i=default: + (b.flash(), + b.setvar('button', i))) + + oldFocus = w.tk.call('focus') # XXX + w.grab_set() + w.focus() + + # 5. Wait for the user to respond, then restore the focus + # and return the index of the selected button. + + w.waitvar('button') + w.destroy() + w.tk.call('focus', oldFocus) # XXX + return w.getint(w.getvar('button')) + +def strdialog(master, title, text, bitmap, default, *args): + + # 1. Create the top-level window and divide it into top + # and bottom parts. + + w = Toplevel(master, {'class': 'Dialog'}) + w.title(title) + w.iconname('Dialog') + + top = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'top', 'fill': 'both'}}) + if args: + bot = Frame(w, {'relief': 'raised', 'bd': 1, + Pack: {'side': 'bottom', 'fill': 'both'}}) + + # 2. Fill the top part with the bitmap, message and input field. + + if bitmap: + bm = Label(top, {'bitmap': bitmap, + Pack: {'side': 'left', + 'padx': '3m', 'pady': '3m'}}) + + msg = Message(top, + {'width': '3i', + 'text': text, + 'font': '-Adobe-Times-Medium-R-Normal-*-180-*', + Pack: {'side': 'left', + 'fill': 'both', + 'padx': '3m', 'pady': '3m'}}) + + field = Entry(top, + {'relief':'sunken', + Pack:{'side':'left', + 'fill':'x', + 'expand':1, + 'padx':'3m', 'pady':'3m'}}) + # 3. Create a row of buttons at the bottom of the dialog. + + buttons = [] + i = 0 + for but in args: + b = Button(bot, {'text': but, + 'command': ('set', 'button', i)}) + buttons.append(b) + if i == default: + bd = Frame(bot, {'relief': 'sunken', 'bd': 1, + Pack: {'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '2m'}}) + b.lift() + b.pack ({'in': bd, 'side': 'left', + 'padx': '2m', 'pady': '2m', + 'ipadx': '2m', 'ipady': '1m'}) + else: + b.pack ({'side': 'left', 'expand': 1, + 'padx': '3m', 'pady': '3m', + 'ipady': '2m', 'ipady': '1m'}) + i = i+1 + + # 4. Set up a binding for <Return>, if there's a default, + # set a grab, and claim the focus too. + + if not args: + w.bind('<Return>', lambda arg, top=top: top.setvar('button', 0)) + field.bind('<Return>', lambda arg, top=top: top.setvar('button', 0)) + elif default >= 0: + w.bind('<Return>', + lambda e, b=buttons[default], i=default: + (b.flash(), + b.setvar('button', i))) + field.bind('<Return>', + lambda e, b=buttons[default], i=default: + (b.flash(), + b.setvar('button', i))) + + oldFocus = w.tk.call('focus') # XXX + w.grab_set() + field.focus() + + # 5. Wait for the user to respond, then restore the focus + # and return the index of the selected button. + + w.waitvar('button') + v = field.get() + w.destroy() + w.tk.call('focus', oldFocus) # XXX + if args: + return v, w.getint(w.getvar('button')) + else: + return v + +def message(str): + i = dialog(mainWidget, 'Message', str, '', 0, 'OK') + +def askyn(str): + i = dialog(mainWidget, 'Question', str, '', 0, 'No', 'Yes') + return i + +def askync(str): + i = dialog(mainWidget, 'Question', str, '', 0, 'Cancel', 'No', 'Yes') + return i-1 + +def askstr(str): + i = strdialog(mainWidget, 'Question', str, '', 0) + return i + +def askfile(str): # XXXX For now... + i = strdialog(mainWidget, 'Question', str, '', 0) + return i + +# The rest is the test program. + +def _go(): + i = dialog(mainWidget, + 'Not Responding', + "The file server isn't responding right now; " + "I'll keep trying.", + '', + -1, + 'OK') + print 'pressed button', i + i = dialog(mainWidget, + 'File Modified', + 'File "tcl.h" has been modified since ' + 'the last time it was saved. ' + 'Do you want to save it before exiting the application?', + 'warning', + 0, + 'Save File', + 'Discard Changes', + 'Return To Editor') + print 'pressed button', i + print message('Test of message') + print askyn('Test of yes/no') + print askync('Test of yes/no/cancel') + print askstr('Type a string:') + print strdialog(mainWidget, 'Question', 'Another string:', '', + 0, 'Save', 'Save as text') + +def _test(): + import sys + global mainWidget + mainWidget = Frame() + Pack.config(mainWidget) + start = Button(mainWidget, + {'text': 'Press Here To Start', 'command': _go}) + start.pack() + endit = Button(mainWidget, + {'text': 'Exit', + 'command': 'exit', + Pack: {'fill' : 'both'}}) + mainWidget.mainloop() + +if __name__ == '__main__': + _test() diff --git a/sys/src/cmd/python/Tools/modulator/genmodule.py b/sys/src/cmd/python/Tools/modulator/genmodule.py new file mode 100755 index 000000000..da3068472 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/genmodule.py @@ -0,0 +1,160 @@ +# +# Genmodule - A python program to help you build (template) modules. +# +# Usage: +# +# o = genmodule.object() +# o.name = 'dwarve object' +# o.abbrev = 'dw' +# o.funclist = ['new', 'dealloc', 'getattr', 'setattr'] +# o.methodlist = ['dig'] +# +# m = genmodule.module() +# m.name = 'beings' +# m.abbrev = 'be' +# m.methodlist = ['newdwarve'] +# m.objects = [o] +# +# genmodule.write(sys.stdout, m) +# +import sys +import os +import varsubst + +error = 'genmodule.error' + +# +# Names of functions in the object-description struct. +# +FUNCLIST = ['new', 'tp_dealloc', 'tp_print', 'tp_getattr', 'tp_setattr', + 'tp_compare', 'tp_repr', 'tp_hash', 'tp_call', 'tp_str'] +TYPELIST = ['tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'structure'] + +# +# writer is a base class for the object and module classes +# it contains code common to both. +# +class writer: + def __init__(self): + self._subst = None + + def makesubst(self): + if not self._subst: + if not self.__dict__.has_key('abbrev'): + self.abbrev = self.name + self.Abbrev = self.abbrev[0].upper()+self.abbrev[1:] + subst = varsubst.Varsubst(self.__dict__) + subst.useindent(1) + self._subst = subst.subst + + def addcode(self, name, fp): + ifp = self.opentemplate(name) + self.makesubst() + d = ifp.read() + d = self._subst(d) + fp.write(d) + + def opentemplate(self, name): + for p in sys.path: + fn = os.path.join(p, name) + if os.path.exists(fn): + return open(fn, 'r') + fn = os.path.join(p, 'Templates') + fn = os.path.join(fn, name) + if os.path.exists(fn): + return open(fn, 'r') + raise error, 'Template '+name+' not found for '+self._type+' '+ \ + self.name + +class module(writer): + _type = 'module' + + def writecode(self, fp): + self.addcode('copyright', fp) + self.addcode('module_head', fp) + for o in self.objects: + o.writehead(fp) + for o in self.objects: + o.writebody(fp) + new_ml = '' + for fn in self.methodlist: + self.method = fn + self.addcode('module_method', fp) + new_ml = new_ml + ( + '{"%s",\t(PyCFunction)%s_%s,\tMETH_VARARGS,\t%s_%s__doc__},\n' + %(fn, self.abbrev, fn, self.abbrev, fn)) + self.methodlist = new_ml + self.addcode('module_tail', fp) + +class object(writer): + _type = 'object' + def __init__(self): + self.typelist = [] + self.methodlist = [] + self.funclist = ['new'] + writer.__init__(self) + + def writecode(self, fp): + self.addcode('copyright', fp) + self.writehead(fp) + self.writebody(fp) + + def writehead(self, fp): + self.addcode('object_head', fp) + + def writebody(self, fp): + new_ml = '' + for fn in self.methodlist: + self.method = fn + self.addcode('object_method', fp) + new_ml = new_ml + ( + '{"%s",\t(PyCFunction)%s_%s,\tMETH_VARARGS,\t%s_%s__doc__},\n' + %(fn, self.abbrev, fn, self.abbrev, fn)) + self.methodlist = new_ml + self.addcode('object_mlist', fp) + + # Add getattr if we have methods + if self.methodlist and not 'tp_getattr' in self.funclist: + self.funclist.insert(0, 'tp_getattr') + + for fn in FUNCLIST: + setattr(self, fn, '0') + + # + # Special case for structure-access objects: put getattr in the + # list of functions but don't generate code for it directly, + # the code is obtained from the object_structure template. + # The same goes for setattr. + # + if 'structure' in self.typelist: + if 'tp_getattr' in self.funclist: + self.funclist.remove('tp_getattr') + if 'tp_setattr' in self.funclist: + self.funclist.remove('tp_setattr') + self.tp_getattr = self.abbrev + '_getattr' + self.tp_setattr = self.abbrev + '_setattr' + for fn in self.funclist: + self.addcode('object_'+fn, fp) + setattr(self, fn, '%s_%s'%(self.abbrev, fn[3:])) + for tn in TYPELIST: + setattr(self, tn, '0') + for tn in self.typelist: + self.addcode('object_'+tn, fp) + setattr(self, tn, '&%s_%s'%(self.abbrev, tn[3:])) + self.addcode('object_tail', fp) + +def write(fp, obj): + obj.writecode(fp) + +if __name__ == '__main__': + o = object() + o.name = 'dwarve object' + o.abbrev = 'dw' + o.funclist = ['new', 'tp_dealloc'] + o.methodlist = ['dig'] + m = module() + m.name = 'beings' + m.abbrev = 'be' + m.methodlist = ['newdwarve'] + m.objects = [o] + write(sys.stdout, m) diff --git a/sys/src/cmd/python/Tools/modulator/modulator.py b/sys/src/cmd/python/Tools/modulator/modulator.py new file mode 100755 index 000000000..3e06bc237 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/modulator.py @@ -0,0 +1,383 @@ +#! /usr/bin/env python +# +# Modulator - Generate skeleton modules. +# +# The user fills out some forms with information about what the module +# should support (methods, objects), names of these things, prefixes to +# use for C code, whether the objects should also support access as numbers, +# etc etc etc. +# When the user presses 'Generate code' we generate a complete skeleton +# module in C. +# +# Alternatively, the selections made can be save to a python sourcefile and +# this sourcefile can be passed on the command line (resulting in the same +# skeleton C code). +# +# Jack Jansen, CWI, October 1994. +# + +import sys, os +if os.name <> 'mac': + sys.path.append(os.path.join(os.environ['HOME'], + 'src/python/Tools/modulator')) + +from Tkinter import * +from Tkextra import * +from ScrolledListbox import ScrolledListbox +import sys +import genmodule +import string + +oops = 'oops' + +IDENTSTARTCHARS = string.letters + '_' +IDENTCHARS = string.letters + string.digits + '_' + +# Check that string is a legal C identifier +def checkid(str): + if not str: return 0 + if not str[0] in IDENTSTARTCHARS: + return 0 + for c in str[1:]: + if not c in IDENTCHARS: + return 0 + return 1 + +def getlistlist(list): + rv = [] + n = list.size() + for i in range(n): + rv.append(list.get(i)) + return rv + +class UI: + def __init__(self): + self.main = Frame() + self.main.pack() + self.main.master.title('Modulator: Module view') + self.cmdframe = Frame(self.main, {'relief':'raised', 'bd':'0.5m', + Pack:{'side':'top', + 'fill':'x'}}) + self.objframe = Frame(self.main, {Pack:{'side':'top', 'fill':'x', + 'expand':1}}) + + + self.check_button = Button(self.cmdframe, + {'text':'Check', 'command':self.cb_check, + Pack:{'side':'left', 'padx':'0.5m'}}) + self.save_button = Button(self.cmdframe, + {'text':'Save...', 'command':self.cb_save, + Pack:{'side':'left', 'padx':'0.5m'}}) + self.code_button = Button(self.cmdframe, + {'text':'Generate code...', + 'command':self.cb_gencode, + Pack:{'side':'left', 'padx':'0.5m'}}) + self.quit_button = Button(self.cmdframe, + {'text':'Quit', + 'command':self.cb_quit, + Pack:{'side':'right', 'padx':'0.5m'}}) + + self.module = UI_module(self) + self.objects = [] + self.modified = 0 + + def run(self): + self.main.mainloop() + + def cb_quit(self, *args): + if self.modified: + if not askyn('You have not saved\nAre you sure you want to quit?'): + return + sys.exit(0) + + def cb_check(self, *args): + try: + self.module.synchronize() + for o in self.objects: + o.synchronize() + except oops: + pass + + def cb_save(self, *args): + try: + pycode = self.module.gencode('m', self.objects) + except oops: + return + + fn = askfile('Python file name: ') + if not fn: + return + + fp = open(fn, 'w') + + fp.write(pycode) + fp.close() + + def cb_gencode(self, *args): + try: + pycode = self.module.gencode('m', self.objects) + except oops: + pass + + fn = askfile('C file name: ') + if not fn: + return + + fp = open(fn, 'w') + + try: + exec pycode + except: + message('An error occurred:-)') + return + genmodule.write(fp, m) + fp.close() + +class UI_module: + def __init__(self, parent): + self.parent = parent + self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', + Pack:{'side':'top', + 'fill':'x'}}) + self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + + self.l1 = Label(self.f1, {'text':'Module:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.name_entry = Entry(self.f1, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, + Pack:{'side':'left', 'padx':'0.5m'}}) + + self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, + Pack:{'side':'left', 'expand':1, + 'padx':'0.5m', 'fill':'both'}}) + + self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_entry = Entry(self.f3, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.method_entry.bind('<Return>', self.cb_method) + self.delete_button = Button(self.f3, {'text':'Delete method', + 'command':self.cb_delmethod, + Pack:{'side':'left', + 'padx':'0.5m'}}) + + self.newobj_button = Button(self.f4, {'text':'new object', + 'command':self.cb_newobj, + Pack:{'side':'left', + 'padx':'0.5m'}}) + + def cb_delmethod(self, *args): + list = self.method_list.curselection() + for i in list: + self.method_list.delete(i) + + def cb_newobj(self, *arg): + self.parent.objects.append(UI_object(self.parent)) + + def cb_method(self, *arg): + name = self.method_entry.get() + if not name: + return + self.method_entry.delete('0', 'end') + self.method_list.insert('end', name) + + def synchronize(self): + n = self.name_entry.get() + if not n: + message('Module name not set') + raise oops + if not checkid(n): + message('Module name not an identifier:\n'+n) + raise oops + if not self.abbrev_entry.get(): + self.abbrev_entry.insert('end', n) + m = getlistlist(self.method_list) + for n in m: + if not checkid(n): + message('Method name not an identifier:\n'+n) + raise oops + + def gencode(self, name, objects): + rv = '' + self.synchronize() + for o in objects: + o.synchronize() + onames = [] + for i in range(len(objects)): + oname = 'o%d' % (i+1) + rv = rv + objects[i].gencode(oname) + onames.append(oname) + rv = rv + '%s = genmodule.module()\n' % (name,) + rv = rv + '%s.name = %r\n' % (name, self.name_entry.get()) + rv = rv + '%s.abbrev = %r\n' % (name, self.abbrev_entry.get()) + rv = rv + '%s.methodlist = %r\n' % (name, getlistlist(self.method_list)) + rv = rv + '%s.objects = [%s]\n' % (name, ','.join(onames)) + rv = rv + '\n' + return rv + +object_number = 0 + +class UI_object: + def __init__(self, parent): + global object_number + + object_number = object_number + 1 + self.num = object_number + self.vpref = 'o%r_' % self.num + self.frame = Toplevel(parent.objframe) +# self.frame.pack() + self.frame.title('Modulator: object view') +# self.frame = Frame(parent.objframe, {'relief':'raised', 'bd':'0.2m', +# Pack:{'side':'top', +# 'fill':'x'}}) + self.f1 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f2 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f3 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + self.f4 = Frame(self.frame, {Pack:{'side':'top', 'pady':'0.5m', + 'fill':'x'}}) + + + self.l1 = Label(self.f1, {'text':'Object:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.name_entry = Entry(self.f1, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.l2 = Label(self.f1, {'text':'Abbrev:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.abbrev_entry = Entry(self.f1, {'relief':'sunken', 'width':5, + Pack:{'side':'left', 'padx':'0.5m'}}) + + self.l3 = Label(self.f2, {'text':'Methods:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_list = ScrolledListbox(self.f2, {'relief':'sunken','bd':2, + Pack:{'side':'left', 'expand':1, + 'padx':'0.5m', 'fill':'both'}}) + + self.l4 = Label(self.f3, {'text':'Add method:', Pack:{'side':'left', + 'padx':'0.5m'}}) + self.method_entry = Entry(self.f3, {'relief':'sunken', + Pack:{'side':'left', 'padx':'0.5m', 'expand':1}}) + self.method_entry.bind('<Return>', self.cb_method) + self.delete_button = Button(self.f3, {'text':'Delete method', + 'command':self.cb_delmethod, + Pack:{'side':'left', + 'padx':'0.5m'}}) + + + self.l5 = Label(self.f4, {'text':'functions:', + Pack:{'side':'left', + 'padx':'0.5m'}}) + self.f5 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', + 'fill':'both'}}) + self.l6 = Label(self.f4, {'text':'Types:', + Pack:{'side':'left', 'padx':'0.5m'}}) + self.f6 = Frame(self.f4, {Pack:{'side':'left', 'pady':'0.5m', + 'fill':'x'}}) + self.funcs = {} + for i in genmodule.FUNCLIST: + vname = self.vpref+i + self.f5.setvar(vname, 0) + b = Checkbutton(self.f5, {'variable':vname, 'text':i, + Pack:{'side':'top', 'pady':'0.5m', + 'anchor':'w','expand':1}}) + self.funcs[i] = b + self.f5.setvar(self.vpref+'new', 1) + + self.types = {} + for i in genmodule.TYPELIST: + vname = self.vpref + i + self.f6.setvar(vname, 0) + b = Checkbutton(self.f6, {'variable':vname, 'text':i, + Pack:{'side':'top', 'pady':'0.5m', + 'anchor':'w'}}) + self.types[i] = b + + def cb_method(self, *arg): + name = self.method_entry.get() + if not name: + return + self.method_entry.delete('0', 'end') + self.method_list.insert('end', name) + + def cb_delmethod(self, *args): + list = self.method_list.curselection() + for i in list: + self.method_list.delete(i) + + def synchronize(self): + n = self.name_entry.get() + if not n: + message('Object name not set') + raise oops + if not self.abbrev_entry.get(): + self.abbrev_entry.insert('end', n) + n = self.abbrev_entry.get() + if not checkid(n): + message('Abbreviation not an identifier:\n'+n) + raise oops + m = getlistlist(self.method_list) + for n in m: + if not checkid(n): + message('Method name not an identifier:\n'+n) + raise oops + if m: + self.f5.setvar(self.vpref+'tp_getattr', 1) + pass + + def gencode(self, name): + rv = '' + rv = rv + '%s = genmodule.object()\n' % (name,) + rv = rv + '%s.name = %r\n' % (name, self.name_entry.get()) + rv = rv + '%s.abbrev = %r\n' % (name, self.abbrev_entry.get()) + rv = rv + '%s.methodlist = %r\n' % (name, getlistlist(self.method_list)) + fl = [] + for fn in genmodule.FUNCLIST: + vname = self.vpref + fn + if self.f5.getvar(vname) == '1': + fl.append(fn) + rv = rv + '%s.funclist = %r\n' % (name, fl) + + fl = [] + for fn in genmodule.TYPELIST: + vname = self.vpref + fn + if self.f5.getvar(vname) == '1': + fl.append(fn) + + rv = rv + '%s.typelist = %r\n' % (name, fl) + + rv = rv + '\n' + return rv + + +def main(): + if len(sys.argv) < 2: + ui = UI() + ui.run() + elif len(sys.argv) == 2: + fp = open(sys.argv[1]) + pycode = fp.read() + try: + exec pycode + except: + sys.stderr.write('An error occurred:-)\n') + sys.exit(1) + ##genmodule.write(sys.stdout, m) + else: + sys.stderr.write('Usage: modulator [file]\n') + sys.exit(1) + +main() diff --git a/sys/src/cmd/python/Tools/modulator/varsubst.py b/sys/src/cmd/python/Tools/modulator/varsubst.py new file mode 100644 index 000000000..3b3395065 --- /dev/null +++ b/sys/src/cmd/python/Tools/modulator/varsubst.py @@ -0,0 +1,56 @@ +# +# Variable substitution. Variables are $delimited$ +# +import re + +error = 'varsubst.error' + +class Varsubst: + def __init__(self, dict): + self.dict = dict + self.prog = re.compile('\$([a-zA-Z0-9_]*)\$') + self.do_useindent = 0 + + def useindent(self, onoff): + self.do_useindent = onoff + + def subst(self, s): + rv = '' + while 1: + m = self.prog.search(s) + if not m: + return rv + s + rv = rv + s[:m.start()] + s = s[m.end():] + if m.end() - m.start() == 2: + # Escaped dollar + rv = rv + '$' + s = s[2:] + continue + name = m.group(1) + if not self.dict.has_key(name): + raise error, 'No such variable: '+name + value = self.dict[name] + if self.do_useindent and '\n' in value: + value = self._modindent(value, rv) + rv = rv + value + + def _modindent(self, value, old): + lastnl = old.rfind('\n', 0) + 1 + lastnl = len(old) - lastnl + sub = '\n' + (' '*lastnl) + return re.sub('\n', sub, value) + +def _test(): + import sys + import os + + sys.stderr.write('-- Copying stdin to stdout with environment map --\n') + c = Varsubst(os.environ) + c.useindent(1) + d = sys.stdin.read() + sys.stdout.write(c.subst(d)) + sys.exit(1) + +if __name__ == '__main__': + _test() diff --git a/sys/src/cmd/python/Tools/msi/README.txt b/sys/src/cmd/python/Tools/msi/README.txt new file mode 100644 index 000000000..dc4ae90cf --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/README.txt @@ -0,0 +1,25 @@ +Packaging Python as a Microsoft Installer Package (MSI) +======================================================= + +Using this library, Python can be packaged as a MS-Windows +MSI file. To generate an installer package, you need +a build tree. By default, the build tree root directory +is assumed to be in "../..". This location can be changed +by adding a file config.py; see the beginning of msi.py +for additional customization options. + +The packaging process assumes that binaries have been +generated according to the instructions in PCBuild/README.txt, +and that you have either Visual Studio or the Platform SDK +installed. In addition, you need the Python COM extensions, +either from PythonWin, or from ActivePython. + +To invoke the script, open a cmd.exe window which has +cabarc.exe in its PATH (e.g. "Visual Studio .NET 2003 +Command Prompt"). Then invoke + +<path-to-python.exe> msi.py + +If everything succeeds, pythonX.Y.Z.msi is generated +in the current directory. + diff --git a/sys/src/cmd/python/Tools/msi/msi.py b/sys/src/cmd/python/Tools/msi/msi.py new file mode 100644 index 000000000..0229fb7bc --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/msi.py @@ -0,0 +1,1203 @@ +# Python MSI Generator +# (C) 2003 Martin v. Loewis +# See "FOO" in comments refers to MSDN sections with the title FOO. +import msilib, schema, sequence, os, glob, time, re +from msilib import Feature, CAB, Directory, Dialog, Binary, add_data +import uisample +from win32com.client import constants +from distutils.spawn import find_executable +from uuids import product_codes + +# Settings can be overridden in config.py below +# 0 for official python.org releases +# 1 for intermediate releases by anybody, with +# a new product code for every package. +snapshot = 1 +# 1 means that file extension is px, not py, +# and binaries start with x +testpackage = 0 +# Location of build tree +srcdir = os.path.abspath("../..") +# Text to be displayed as the version in dialogs etc. +# goes into file name and ProductCode. Defaults to +# current_version.day for Snapshot, current_version otherwise +full_current_version = None +# Is Tcl available at all? +have_tcl = True +# Where is sqlite3.dll located, relative to srcdir? +sqlite_dir = "../sqlite-source-3.3.4" + +try: + from config import * +except ImportError: + pass + +# Extract current version from Include/patchlevel.h +lines = open(srcdir + "/Include/patchlevel.h").readlines() +major = minor = micro = level = serial = None +levels = { + 'PY_RELEASE_LEVEL_ALPHA':0xA, + 'PY_RELEASE_LEVEL_BETA': 0xB, + 'PY_RELEASE_LEVEL_GAMMA':0xC, + 'PY_RELEASE_LEVEL_FINAL':0xF + } +for l in lines: + if not l.startswith("#define"): + continue + l = l.split() + if len(l) != 3: + continue + _, name, value = l + if name == 'PY_MAJOR_VERSION': major = value + if name == 'PY_MINOR_VERSION': minor = value + if name == 'PY_MICRO_VERSION': micro = value + if name == 'PY_RELEASE_LEVEL': level = levels[value] + if name == 'PY_RELEASE_SERIAL': serial = value + +short_version = major+"."+minor +# See PC/make_versioninfo.c +FIELD3 = 1000*int(micro) + 10*level + int(serial) +current_version = "%s.%d" % (short_version, FIELD3) + +# This should never change. The UpgradeCode of this package can be +# used in the Upgrade table of future packages to make the future +# package replace this one. See "UpgradeCode Property". +upgrade_code_snapshot='{92A24481-3ECB-40FC-8836-04B7966EC0D5}' +upgrade_code='{65E6DE48-A358-434D-AA4F-4AF72DB4718F}' + +if snapshot: + current_version = "%s.%s.%s" % (major, minor, int(time.time()/3600/24)) + product_code = msilib.gen_uuid() +else: + product_code = product_codes[current_version] + +if full_current_version is None: + full_current_version = current_version + +extensions = [ + 'bz2.pyd', + 'pyexpat.pyd', + 'select.pyd', + 'unicodedata.pyd', + 'winsound.pyd', + '_elementtree.pyd', + '_bsddb.pyd', + '_socket.pyd', + '_ssl.pyd', + '_testcapi.pyd', + '_tkinter.pyd', + '_msi.pyd', + '_ctypes.pyd', + '_ctypes_test.pyd', + '_sqlite3.pyd', + '_hashlib.pyd' +] + +# Well-known component UUIDs +# These are needed for SharedDLLs reference counter; if +# a different UUID was used for each incarnation of, say, +# python24.dll, an upgrade would set the reference counter +# from 1 to 2 (due to what I consider a bug in MSI) +# Using the same UUID is fine since these files are versioned, +# so Installer will always keep the newest version. +msvcr71_uuid = "{8666C8DD-D0B4-4B42-928E-A69E32FA5D4D}" +pythondll_uuid = { + "24":"{9B81E618-2301-4035-AC77-75D9ABEB7301}", + "25":"{2e41b118-38bd-4c1b-a840-6977efd1b911}" + } [major+minor] + +# Build the mingw import library, libpythonXY.a +# This requires 'nm' and 'dlltool' executables on your PATH +def build_mingw_lib(lib_file, def_file, dll_file, mingw_lib): + warning = "WARNING: %s - libpythonXX.a not built" + nm = find_executable('nm') + dlltool = find_executable('dlltool') + + if not nm or not dlltool: + print warning % "nm and/or dlltool were not found" + return False + + nm_command = '%s -Cs %s' % (nm, lib_file) + dlltool_command = "%s --dllname %s --def %s --output-lib %s" % \ + (dlltool, dll_file, def_file, mingw_lib) + export_match = re.compile(r"^_imp__(.*) in python\d+\.dll").match + + f = open(def_file,'w') + print >>f, "LIBRARY %s" % dll_file + print >>f, "EXPORTS" + + nm_pipe = os.popen(nm_command) + for line in nm_pipe.readlines(): + m = export_match(line) + if m: + print >>f, m.group(1) + f.close() + exit = nm_pipe.close() + + if exit: + print warning % "nm did not run successfully" + return False + + if os.system(dlltool_command) != 0: + print warning % "dlltool did not run successfully" + return False + + return True + +# Target files (.def and .a) go in PCBuild directory +lib_file = os.path.join(srcdir, "PCBuild", "python%s%s.lib" % (major, minor)) +def_file = os.path.join(srcdir, "PCBuild", "python%s%s.def" % (major, minor)) +dll_file = "python%s%s.dll" % (major, minor) +mingw_lib = os.path.join(srcdir, "PCBuild", "libpython%s%s.a" % (major, minor)) + +have_mingw = build_mingw_lib(lib_file, def_file, dll_file, mingw_lib) + +# Determine the target architechture +dll_path = os.path.join(srcdir, "PCBuild", dll_file) +msilib.set_arch_from_file(dll_path) +if msilib.pe_type(dll_path) != msilib.pe_type("msisupport.dll"): + raise SystemError, "msisupport.dll for incorrect architecture" + +if testpackage: + ext = 'px' + testprefix = 'x' +else: + ext = 'py' + testprefix = '' + +if msilib.Win64: + SystemFolderName = "[SystemFolder64]" +else: + SystemFolderName = "[SystemFolder]" + +msilib.reset() + +# condition in which to install pythonxy.dll in system32: +# a) it is Windows 9x or +# b) it is NT, the user is privileged, and has chosen per-machine installation +sys32cond = "(Windows9x or (Privileged and ALLUSERS))" + +def build_database(): + """Generate an empty database, with just the schema and the + Summary information stream.""" + if snapshot: + uc = upgrade_code_snapshot + else: + uc = upgrade_code + # schema represents the installer 2.0 database schema. + # sequence is the set of standard sequences + # (ui/execute, admin/advt/install) + db = msilib.init_database("python-%s%s.msi" % (full_current_version, msilib.arch_ext), + schema, ProductName="Python "+full_current_version, + ProductCode=product_code, + ProductVersion=current_version, + Manufacturer=u"Martin v. L\xf6wis") + # The default sequencing of the RemoveExistingProducts action causes + # removal of files that got just installed. Place it after + # InstallInitialize, so we first uninstall everything, but still roll + # back in case the installation is interrupted + msilib.change_sequence(sequence.InstallExecuteSequence, + "RemoveExistingProducts", 1510) + msilib.add_tables(db, sequence) + # We cannot set ALLUSERS in the property table, as this cannot be + # reset if the user choses a per-user installation. Instead, we + # maintain WhichUsers, which can be "ALL" or "JUSTME". The UI manages + # this property, and when the execution starts, ALLUSERS is set + # accordingly. + add_data(db, "Property", [("UpgradeCode", uc), + ("WhichUsers", "ALL"), + ("ProductLine", "Python%s%s" % (major, minor)), + ]) + db.Commit() + return db + +def remove_old_versions(db): + "Fill the upgrade table." + start = "%s.%s.0" % (major, minor) + # This requests that feature selection states of an older + # installation should be forwarded into this one. Upgrading + # requires that both the old and the new installation are + # either both per-machine or per-user. + migrate_features = 1 + # See "Upgrade Table". We remove releases with the same major and + # minor version. For an snapshot, we remove all earlier snapshots. For + # a release, we remove all snapshots, and all earlier releases. + if snapshot: + add_data(db, "Upgrade", + [(upgrade_code_snapshot, start, + current_version, + None, # Ignore language + migrate_features, + None, # Migrate ALL features + "REMOVEOLDSNAPSHOT")]) + props = "REMOVEOLDSNAPSHOT" + else: + add_data(db, "Upgrade", + [(upgrade_code, start, current_version, + None, migrate_features, None, "REMOVEOLDVERSION"), + (upgrade_code_snapshot, start, "%s.%d.0" % (major, int(minor)+1), + None, migrate_features, None, "REMOVEOLDSNAPSHOT")]) + props = "REMOVEOLDSNAPSHOT;REMOVEOLDVERSION" + # Installer collects the product codes of the earlier releases in + # these properties. In order to allow modification of the properties, + # they must be declared as secure. See "SecureCustomProperties Property" + add_data(db, "Property", [("SecureCustomProperties", props)]) + +class PyDialog(Dialog): + """Dialog class with a fixed layout: controls at the top, then a ruler, + then a list of buttons: back, next, cancel. Optionally a bitmap at the + left.""" + def __init__(self, *args, **kw): + """Dialog(database, name, x, y, w, h, attributes, title, first, + default, cancel, bitmap=true)""" + Dialog.__init__(self, *args) + ruler = self.h - 36 + bmwidth = 152*ruler/328 + if kw.get("bitmap", True): + self.bitmap("Bitmap", 0, 0, bmwidth, ruler, "PythonWin") + self.line("BottomLine", 0, ruler, self.w, 0) + + def title(self, title): + "Set the title text of the dialog at the top." + # name, x, y, w, h, flags=Visible|Enabled|Transparent|NoPrefix, + # text, in VerdanaBold10 + self.text("Title", 135, 10, 220, 60, 0x30003, + r"{\VerdanaBold10}%s" % title) + + def back(self, title, next, name = "Back", active = 1): + """Add a back button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 180, self.h-27 , 56, 17, flags, title, next) + + def cancel(self, title, next, name = "Cancel", active = 1): + """Add a cancel button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 304, self.h-27, 56, 17, flags, title, next) + + def next(self, title, next, name = "Next", active = 1): + """Add a Next button with a given title, the tab-next button, + its name in the Control table, possibly initially disabled. + + Return the button, so that events can be associated""" + if active: + flags = 3 # Visible|Enabled + else: + flags = 1 # Visible + return self.pushbutton(name, 236, self.h-27, 56, 17, flags, title, next) + + def xbutton(self, name, title, next, xpos): + """Add a button with a given title, the tab-next button, + its name in the Control table, giving its x position; the + y-position is aligned with the other buttons. + + Return the button, so that events can be associated""" + return self.pushbutton(name, int(self.w*xpos - 28), self.h-27, 56, 17, 3, title, next) + +def add_ui(db): + x = y = 50 + w = 370 + h = 300 + title = "[ProductName] Setup" + + # see "Dialog Style Bits" + modal = 3 # visible | modal + modeless = 1 # visible + track_disk_space = 32 + + add_data(db, 'ActionText', uisample.ActionText) + add_data(db, 'UIText', uisample.UIText) + + # Bitmaps + if not os.path.exists(srcdir+r"\PC\python_icon.exe"): + raise "Run icons.mak in PC directory" + add_data(db, "Binary", + [("PythonWin", msilib.Binary(srcdir+r"\PCbuild\installer.bmp")), # 152x328 pixels + ("py.ico",msilib.Binary(srcdir+r"\PC\py.ico")), + ]) + add_data(db, "Icon", + [("python_icon.exe", msilib.Binary(srcdir+r"\PC\python_icon.exe"))]) + + # Scripts + # CheckDir sets TargetExists if TARGETDIR exists. + # UpdateEditIDLE sets the REGISTRY.tcl component into + # the installed/uninstalled state according to both the + # Extensions and TclTk features. + if os.system("nmake /nologo /c /f msisupport.mak") != 0: + raise "'nmake /f msisupport.mak' failed" + add_data(db, "Binary", [("Script", msilib.Binary("msisupport.dll"))]) + # See "Custom Action Type 1" + if msilib.Win64: + CheckDir = "CheckDir" + UpdateEditIDLE = "UpdateEditIDLE" + else: + CheckDir = "_CheckDir@4" + UpdateEditIDLE = "_UpdateEditIDLE@4" + add_data(db, "CustomAction", + [("CheckDir", 1, "Script", CheckDir)]) + if have_tcl: + add_data(db, "CustomAction", + [("UpdateEditIDLE", 1, "Script", UpdateEditIDLE)]) + + # UI customization properties + add_data(db, "Property", + # See "DefaultUIFont Property" + [("DefaultUIFont", "DlgFont8"), + # See "ErrorDialog Style Bit" + ("ErrorDialog", "ErrorDlg"), + ("Progress1", "Install"), # modified in maintenance type dlg + ("Progress2", "installs"), + ("MaintenanceForm_Action", "Repair")]) + + # Fonts, see "TextStyle Table" + add_data(db, "TextStyle", + [("DlgFont8", "Tahoma", 9, None, 0), + ("DlgFontBold8", "Tahoma", 8, None, 1), #bold + ("VerdanaBold10", "Verdana", 10, None, 1), + ("VerdanaRed9", "Verdana", 9, 255, 0), + ]) + + compileargs = r'-Wi "[TARGETDIR]Lib\compileall.py" -f -x bad_coding|badsyntax|site-packages "[TARGETDIR]Lib"' + # See "CustomAction Table" + add_data(db, "CustomAction", [ + # msidbCustomActionTypeFirstSequence + msidbCustomActionTypeTextData + msidbCustomActionTypeProperty + # See "Custom Action Type 51", + # "Custom Action Execution Scheduling Options" + ("InitialTargetDir", 307, "TARGETDIR", + "[WindowsVolume]Python%s%s" % (major, minor)), + ("SetDLLDirToTarget", 307, "DLLDIR", "[TARGETDIR]"), + ("SetDLLDirToSystem32", 307, "DLLDIR", SystemFolderName), + # msidbCustomActionTypeExe + msidbCustomActionTypeSourceFile + # See "Custom Action Type 18" + ("CompilePyc", 18, "python.exe", compileargs), + ("CompilePyo", 18, "python.exe", "-O "+compileargs), + ]) + + # UI Sequences, see "InstallUISequence Table", "Using a Sequence Table" + # Numbers indicate sequence; see sequence.py for how these action integrate + add_data(db, "InstallUISequence", + [("PrepareDlg", "Not Privileged or Windows9x or Installed", 140), + ("WhichUsersDlg", "Privileged and not Windows9x and not Installed", 141), + ("InitialTargetDir", 'TARGETDIR=""', 750), + # In the user interface, assume all-users installation if privileged. + ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), + ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), + ("SelectDirectoryDlg", "Not Installed", 1230), + # XXX no support for resume installations yet + #("ResumeDlg", "Installed AND (RESUME OR Preselected)", 1240), + ("MaintenanceTypeDlg", "Installed AND NOT RESUME AND NOT Preselected", 1250), + ("ProgressDlg", None, 1280)]) + add_data(db, "AdminUISequence", + [("InitialTargetDir", 'TARGETDIR=""', 750), + ("SetDLLDirToTarget", 'DLLDIR=""', 751), + ]) + + # Execute Sequences + add_data(db, "InstallExecuteSequence", + [("InitialTargetDir", 'TARGETDIR=""', 750), + ("SetDLLDirToSystem32", 'DLLDIR="" and ' + sys32cond, 751), + ("SetDLLDirToTarget", 'DLLDIR="" and not ' + sys32cond, 752), + ("UpdateEditIDLE", None, 1050), + ("CompilePyc", "COMPILEALL", 6800), + ("CompilePyo", "COMPILEALL", 6801), + ]) + add_data(db, "AdminExecuteSequence", + [("InitialTargetDir", 'TARGETDIR=""', 750), + ("SetDLLDirToTarget", 'DLLDIR=""', 751), + ("CompilePyc", "COMPILEALL", 6800), + ("CompilePyo", "COMPILEALL", 6801), + ]) + + ##################################################################### + # Standard dialogs: FatalError, UserExit, ExitDialog + fatal=PyDialog(db, "FatalError", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + fatal.title("[ProductName] Installer ended prematurely") + fatal.back("< Back", "Finish", active = 0) + fatal.cancel("Cancel", "Back", active = 0) + fatal.text("Description1", 135, 70, 220, 80, 0x30003, + "[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.") + fatal.text("Description2", 135, 155, 220, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c=fatal.next("Finish", "Cancel", name="Finish") + # See "ControlEvent Table". Parameters are the event, the parameter + # to the action, and optionally the condition for the event, and the order + # of events. + c.event("EndDialog", "Exit") + + user_exit=PyDialog(db, "UserExit", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + user_exit.title("[ProductName] Installer was interrupted") + user_exit.back("< Back", "Finish", active = 0) + user_exit.cancel("Cancel", "Back", active = 0) + user_exit.text("Description1", 135, 70, 220, 80, 0x30003, + "[ProductName] setup was interrupted. Your system has not been modified. " + "To install this program at a later time, please run the installation again.") + user_exit.text("Description2", 135, 155, 220, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c = user_exit.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Exit") + + exit_dialog = PyDialog(db, "ExitDialog", x, y, w, h, modal, title, + "Finish", "Finish", "Finish") + exit_dialog.title("Completing the [ProductName] Installer") + exit_dialog.back("< Back", "Finish", active = 0) + exit_dialog.cancel("Cancel", "Back", active = 0) + exit_dialog.text("Acknowledgements", 135, 95, 220, 120, 0x30003, + "Special Windows thanks to:\n" + " Mark Hammond, without whose years of freely \n" + " shared Windows expertise, Python for Windows \n" + " would still be Python for DOS.") + + c = exit_dialog.text("warning", 135, 200, 220, 40, 0x30003, + "{\\VerdanaRed9}Warning: Python 2.5.x is the last " + "Python release for Windows 9x.") + c.condition("Hide", "NOT Version9X") + + exit_dialog.text("Description", 135, 235, 220, 20, 0x30003, + "Click the Finish button to exit the Installer.") + c = exit_dialog.next("Finish", "Cancel", name="Finish") + c.event("EndDialog", "Return") + + ##################################################################### + # Required dialog: FilesInUse, ErrorDlg + inuse = PyDialog(db, "FilesInUse", + x, y, w, h, + 19, # KeepModeless|Modal|Visible + title, + "Retry", "Retry", "Retry", bitmap=False) + inuse.text("Title", 15, 6, 200, 15, 0x30003, + r"{\DlgFontBold8}Files in Use") + inuse.text("Description", 20, 23, 280, 20, 0x30003, + "Some files that need to be updated are currently in use.") + inuse.text("Text", 20, 55, 330, 50, 3, + "The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.") + inuse.control("List", "ListBox", 20, 107, 330, 130, 7, "FileInUseProcess", + None, None, None) + c=inuse.back("Exit", "Ignore", name="Exit") + c.event("EndDialog", "Exit") + c=inuse.next("Ignore", "Retry", name="Ignore") + c.event("EndDialog", "Ignore") + c=inuse.cancel("Retry", "Exit", name="Retry") + c.event("EndDialog","Retry") + + + # See "Error Dialog". See "ICE20" for the required names of the controls. + error = Dialog(db, "ErrorDlg", + 50, 10, 330, 101, + 65543, # Error|Minimize|Modal|Visible + title, + "ErrorText", None, None) + error.text("ErrorText", 50,9,280,48,3, "") + error.control("ErrorIcon", "Icon", 15, 9, 24, 24, 5242881, None, "py.ico", None, None) + error.pushbutton("N",120,72,81,21,3,"No",None).event("EndDialog","ErrorNo") + error.pushbutton("Y",240,72,81,21,3,"Yes",None).event("EndDialog","ErrorYes") + error.pushbutton("A",0,72,81,21,3,"Abort",None).event("EndDialog","ErrorAbort") + error.pushbutton("C",42,72,81,21,3,"Cancel",None).event("EndDialog","ErrorCancel") + error.pushbutton("I",81,72,81,21,3,"Ignore",None).event("EndDialog","ErrorIgnore") + error.pushbutton("O",159,72,81,21,3,"Ok",None).event("EndDialog","ErrorOk") + error.pushbutton("R",198,72,81,21,3,"Retry",None).event("EndDialog","ErrorRetry") + + ##################################################################### + # Global "Query Cancel" dialog + cancel = Dialog(db, "CancelDlg", 50, 10, 260, 85, 3, title, + "No", "No", "No") + cancel.text("Text", 48, 15, 194, 30, 3, + "Are you sure you want to cancel [ProductName] installation?") + cancel.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, + "py.ico", None, None) + c=cancel.pushbutton("Yes", 72, 57, 56, 17, 3, "Yes", "No") + c.event("EndDialog", "Exit") + + c=cancel.pushbutton("No", 132, 57, 56, 17, 3, "No", "Yes") + c.event("EndDialog", "Return") + + ##################################################################### + # Global "Wait for costing" dialog + costing = Dialog(db, "WaitForCostingDlg", 50, 10, 260, 85, modal, title, + "Return", "Return", "Return") + costing.text("Text", 48, 15, 194, 30, 3, + "Please wait while the installer finishes determining your disk space requirements.") + costing.control("Icon", "Icon", 15, 15, 24, 24, 5242881, None, + "py.ico", None, None) + c = costing.pushbutton("Return", 102, 57, 56, 17, 3, "Return", None) + c.event("EndDialog", "Exit") + + ##################################################################### + # Preparation dialog: no user input except cancellation + prep = PyDialog(db, "PrepareDlg", x, y, w, h, modeless, title, + "Cancel", "Cancel", "Cancel") + prep.text("Description", 135, 70, 220, 40, 0x30003, + "Please wait while the Installer prepares to guide you through the installation.") + prep.title("Welcome to the [ProductName] Installer") + c=prep.text("ActionText", 135, 110, 220, 20, 0x30003, "Pondering...") + c.mapping("ActionText", "Text") + c=prep.text("ActionData", 135, 135, 220, 30, 0x30003, None) + c.mapping("ActionData", "Text") + prep.back("Back", None, active=0) + prep.next("Next", None, active=0) + c=prep.cancel("Cancel", None) + c.event("SpawnDialog", "CancelDlg") + + ##################################################################### + # Target directory selection + seldlg = PyDialog(db, "SelectDirectoryDlg", x, y, w, h, modal, title, + "Next", "Next", "Cancel") + seldlg.title("Select Destination Directory") + c = seldlg.text("Existing", 135, 25, 235, 30, 0x30003, + "{\VerdanaRed9}This update will replace your existing [ProductLine] installation.") + c.condition("Hide", 'REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""') + seldlg.text("Description", 135, 50, 220, 40, 0x30003, + "Please select a directory for the [ProductName] files.") + + seldlg.back("< Back", None, active=0) + c = seldlg.next("Next >", "Cancel") + c.event("DoAction", "CheckDir", "TargetExistsOk<>1", order=1) + # If the target exists, but we found that we are going to remove old versions, don't bother + # confirming that the target directory exists. Strictly speaking, we should determine that + # the target directory is indeed the target of the product that we are going to remove, but + # I don't know how to do that. + c.event("SpawnDialog", "ExistingDirectoryDlg", 'TargetExists=1 and REMOVEOLDVERSION="" and REMOVEOLDSNAPSHOT=""', 2) + c.event("SetTargetPath", "TARGETDIR", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 3) + c.event("SpawnWaitDialog", "WaitForCostingDlg", "CostingComplete=1", 4) + c.event("NewDialog", "SelectFeaturesDlg", 'TargetExists=0 or REMOVEOLDVERSION<>"" or REMOVEOLDSNAPSHOT<>""', 5) + + c = seldlg.cancel("Cancel", "DirectoryCombo") + c.event("SpawnDialog", "CancelDlg") + + seldlg.control("DirectoryCombo", "DirectoryCombo", 135, 70, 172, 80, 393219, + "TARGETDIR", None, "DirectoryList", None) + seldlg.control("DirectoryList", "DirectoryList", 135, 90, 208, 136, 3, "TARGETDIR", + None, "PathEdit", None) + seldlg.control("PathEdit", "PathEdit", 135, 230, 206, 16, 3, "TARGETDIR", None, "Next", None) + c = seldlg.pushbutton("Up", 306, 70, 18, 18, 3, "Up", None) + c.event("DirectoryListUp", "0") + c = seldlg.pushbutton("NewDir", 324, 70, 30, 18, 3, "New", None) + c.event("DirectoryListNew", "0") + + ##################################################################### + # SelectFeaturesDlg + features = PyDialog(db, "SelectFeaturesDlg", x, y, w, h, modal|track_disk_space, + title, "Tree", "Next", "Cancel") + features.title("Customize [ProductName]") + features.text("Description", 135, 35, 220, 15, 0x30003, + "Select the way you want features to be installed.") + features.text("Text", 135,45,220,30, 3, + "Click on the icons in the tree below to change the way features will be installed.") + + c=features.back("< Back", "Next") + c.event("NewDialog", "SelectDirectoryDlg") + + c=features.next("Next >", "Cancel") + c.mapping("SelectionNoItems", "Enabled") + c.event("SpawnDialog", "DiskCostDlg", "OutOfDiskSpace=1", order=1) + c.event("EndDialog", "Return", "OutOfDiskSpace<>1", order=2) + + c=features.cancel("Cancel", "Tree") + c.event("SpawnDialog", "CancelDlg") + + # The browse property is not used, since we have only a single target path (selected already) + features.control("Tree", "SelectionTree", 135, 75, 220, 95, 7, "_BrowseProperty", + "Tree of selections", "Back", None) + + #c=features.pushbutton("Reset", 42, 243, 56, 17, 3, "Reset", "DiskCost") + #c.mapping("SelectionNoItems", "Enabled") + #c.event("Reset", "0") + + features.control("Box", "GroupBox", 135, 170, 225, 90, 1, None, None, None, None) + + c=features.xbutton("DiskCost", "Disk &Usage", None, 0.10) + c.mapping("SelectionNoItems","Enabled") + c.event("SpawnDialog", "DiskCostDlg") + + c=features.xbutton("Advanced", "Advanced", None, 0.30) + c.event("SpawnDialog", "AdvancedDlg") + + c=features.text("ItemDescription", 140, 180, 210, 30, 3, + "Multiline description of the currently selected item.") + c.mapping("SelectionDescription","Text") + + c=features.text("ItemSize", 140, 210, 210, 45, 3, + "The size of the currently selected item.") + c.mapping("SelectionSize", "Text") + + ##################################################################### + # Disk cost + cost = PyDialog(db, "DiskCostDlg", x, y, w, h, modal, title, + "OK", "OK", "OK", bitmap=False) + cost.text("Title", 15, 6, 200, 15, 0x30003, + "{\DlgFontBold8}Disk Space Requirements") + cost.text("Description", 20, 20, 280, 20, 0x30003, + "The disk space required for the installation of the selected features.") + cost.text("Text", 20, 53, 330, 60, 3, + "The highlighted volumes (if any) do not have enough disk space " + "available for the currently selected features. You can either " + "remove some files from the highlighted volumes, or choose to " + "install less features onto local drive(s), or select different " + "destination drive(s).") + cost.control("VolumeList", "VolumeCostList", 20, 100, 330, 150, 393223, + None, "{120}{70}{70}{70}{70}", None, None) + cost.xbutton("OK", "Ok", None, 0.5).event("EndDialog", "Return") + + ##################################################################### + # WhichUsers Dialog. Only available on NT, and for privileged users. + # This must be run before FindRelatedProducts, because that will + # take into account whether the previous installation was per-user + # or per-machine. We currently don't support going back to this + # dialog after "Next" was selected; to support this, we would need to + # find how to reset the ALLUSERS property, and how to re-run + # FindRelatedProducts. + # On Windows9x, the ALLUSERS property is ignored on the command line + # and in the Property table, but installer fails according to the documentation + # if a dialog attempts to set ALLUSERS. + whichusers = PyDialog(db, "WhichUsersDlg", x, y, w, h, modal, title, + "AdminInstall", "Next", "Cancel") + whichusers.title("Select whether to install [ProductName] for all users of this computer.") + # A radio group with two options: allusers, justme + g = whichusers.radiogroup("AdminInstall", 135, 60, 160, 50, 3, + "WhichUsers", "", "Next") + g.add("ALL", 0, 5, 150, 20, "Install for all users") + g.add("JUSTME", 0, 25, 150, 20, "Install just for me") + + whichusers.back("Back", None, active=0) + + c = whichusers.next("Next >", "Cancel") + c.event("[ALLUSERS]", "1", 'WhichUsers="ALL"', 1) + c.event("EndDialog", "Return", order = 2) + + c = whichusers.cancel("Cancel", "AdminInstall") + c.event("SpawnDialog", "CancelDlg") + + ##################################################################### + # Advanced Dialog. + advanced = PyDialog(db, "AdvancedDlg", x, y, w, h, modal, title, + "CompilePyc", "Next", "Cancel") + advanced.title("Advanced Options for [ProductName]") + # A radio group with two options: allusers, justme + advanced.checkbox("CompilePyc", 135, 60, 230, 50, 3, + "COMPILEALL", "Compile .py files to byte code after installation", "Next") + + c = advanced.next("Finish", "Cancel") + c.event("EndDialog", "Return") + + c = advanced.cancel("Cancel", "CompilePyc") + c.event("SpawnDialog", "CancelDlg") + + ##################################################################### + # Existing Directory dialog + dlg = Dialog(db, "ExistingDirectoryDlg", 50, 30, 200, 80, modal, title, + "No", "No", "No") + dlg.text("Title", 10, 20, 180, 40, 3, + "[TARGETDIR] exists. Are you sure you want to overwrite existing files?") + c=dlg.pushbutton("Yes", 30, 60, 55, 17, 3, "Yes", "No") + c.event("[TargetExists]", "0", order=1) + c.event("[TargetExistsOk]", "1", order=2) + c.event("EndDialog", "Return", order=3) + c=dlg.pushbutton("No", 115, 60, 55, 17, 3, "No", "Yes") + c.event("EndDialog", "Return") + + ##################################################################### + # Installation Progress dialog (modeless) + progress = PyDialog(db, "ProgressDlg", x, y, w, h, modeless, title, + "Cancel", "Cancel", "Cancel", bitmap=False) + progress.text("Title", 20, 15, 200, 15, 0x30003, + "{\DlgFontBold8}[Progress1] [ProductName]") + progress.text("Text", 35, 65, 300, 30, 3, + "Please wait while the Installer [Progress2] [ProductName]. " + "This may take several minutes.") + progress.text("StatusLabel", 35, 100, 35, 20, 3, "Status:") + + c=progress.text("ActionText", 70, 100, w-70, 20, 3, "Pondering...") + c.mapping("ActionText", "Text") + + #c=progress.text("ActionData", 35, 140, 300, 20, 3, None) + #c.mapping("ActionData", "Text") + + c=progress.control("ProgressBar", "ProgressBar", 35, 120, 300, 10, 65537, + None, "Progress done", None, None) + c.mapping("SetProgress", "Progress") + + progress.back("< Back", "Next", active=False) + progress.next("Next >", "Cancel", active=False) + progress.cancel("Cancel", "Back").event("SpawnDialog", "CancelDlg") + + # Maintenance type: repair/uninstall + maint = PyDialog(db, "MaintenanceTypeDlg", x, y, w, h, modal, title, + "Next", "Next", "Cancel") + maint.title("Welcome to the [ProductName] Setup Wizard") + maint.text("BodyText", 135, 63, 230, 42, 3, + "Select whether you want to repair or remove [ProductName].") + g=maint.radiogroup("RepairRadioGroup", 135, 108, 230, 60, 3, + "MaintenanceForm_Action", "", "Next") + g.add("Change", 0, 0, 200, 17, "&Change [ProductName]") + g.add("Repair", 0, 18, 200, 17, "&Repair [ProductName]") + g.add("Remove", 0, 36, 200, 17, "Re&move [ProductName]") + + maint.back("< Back", None, active=False) + c=maint.next("Finish", "Cancel") + # Change installation: Change progress dialog to "Change", then ask + # for feature selection + c.event("[Progress1]", "Change", 'MaintenanceForm_Action="Change"', 1) + c.event("[Progress2]", "changes", 'MaintenanceForm_Action="Change"', 2) + + # Reinstall: Change progress dialog to "Repair", then invoke reinstall + # Also set list of reinstalled features to "ALL" + c.event("[REINSTALL]", "ALL", 'MaintenanceForm_Action="Repair"', 5) + c.event("[Progress1]", "Repairing", 'MaintenanceForm_Action="Repair"', 6) + c.event("[Progress2]", "repairs", 'MaintenanceForm_Action="Repair"', 7) + c.event("Reinstall", "ALL", 'MaintenanceForm_Action="Repair"', 8) + + # Uninstall: Change progress to "Remove", then invoke uninstall + # Also set list of removed features to "ALL" + c.event("[REMOVE]", "ALL", 'MaintenanceForm_Action="Remove"', 11) + c.event("[Progress1]", "Removing", 'MaintenanceForm_Action="Remove"', 12) + c.event("[Progress2]", "removes", 'MaintenanceForm_Action="Remove"', 13) + c.event("Remove", "ALL", 'MaintenanceForm_Action="Remove"', 14) + + # Close dialog when maintenance action scheduled + c.event("EndDialog", "Return", 'MaintenanceForm_Action<>"Change"', 20) + c.event("NewDialog", "SelectFeaturesDlg", 'MaintenanceForm_Action="Change"', 21) + + maint.cancel("Cancel", "RepairRadioGroup").event("SpawnDialog", "CancelDlg") + + +# See "Feature Table". The feature level is 1 for all features, +# and the feature attributes are 0 for the DefaultFeature, and +# FollowParent for all other features. The numbers are the Display +# column. +def add_features(db): + # feature attributes: + # msidbFeatureAttributesFollowParent == 2 + # msidbFeatureAttributesDisallowAdvertise == 8 + # Features that need to be installed with together with the main feature + # (i.e. additional Python libraries) need to follow the parent feature. + # Features that have no advertisement trigger (e.g. the test suite) + # must not support advertisement + global default_feature, tcltk, htmlfiles, tools, testsuite, ext_feature + default_feature = Feature(db, "DefaultFeature", "Python", + "Python Interpreter and Libraries", + 1, directory = "TARGETDIR") + # We don't support advertisement of extensions + ext_feature = Feature(db, "Extensions", "Register Extensions", + "Make this Python installation the default Python installation", 3, + parent = default_feature, attributes=2|8) + if have_tcl: + tcltk = Feature(db, "TclTk", "Tcl/Tk", "Tkinter, IDLE, pydoc", 5, + parent = default_feature, attributes=2) + htmlfiles = Feature(db, "Documentation", "Documentation", + "Python HTMLHelp File", 7, parent = default_feature) + tools = Feature(db, "Tools", "Utility Scripts", + "Python utility scripts (Tools/", 9, + parent = default_feature, attributes=2) + testsuite = Feature(db, "Testsuite", "Test suite", + "Python test suite (Lib/test/)", 11, + parent = default_feature, attributes=2|8) + +def extract_msvcr71(): + import _winreg + # Find the location of the merge modules + k = _winreg.OpenKey( + _winreg.HKEY_LOCAL_MACHINE, + r"Software\Microsoft\VisualStudio\7.1\Setup\VS") + dir = _winreg.QueryValueEx(k, "MSMDir")[0] + _winreg.CloseKey(k) + files = glob.glob1(dir, "*CRT71*") + assert len(files) == 1 + file = os.path.join(dir, files[0]) + # Extract msvcr71.dll + m = msilib.MakeMerge2() + m.OpenModule(file, 0) + m.ExtractFiles(".") + m.CloseModule() + # Find the version/language of msvcr71.dll + installer = msilib.MakeInstaller() + return installer.FileVersion("msvcr71.dll", 0), \ + installer.FileVersion("msvcr71.dll", 1) + +class PyDirectory(Directory): + """By default, all components in the Python installer + can run from source.""" + def __init__(self, *args, **kw): + if not kw.has_key("componentflags"): + kw['componentflags'] = 2 #msidbComponentAttributesOptional + Directory.__init__(self, *args, **kw) + +# See "File Table", "Component Table", "Directory Table", +# "FeatureComponents Table" +def add_files(db): + cab = CAB("python") + tmpfiles = [] + # Add all executables, icons, text files into the TARGETDIR component + root = PyDirectory(db, cab, None, srcdir, "TARGETDIR", "SourceDir") + default_feature.set_current() + if not msilib.Win64: + root.add_file("PCBuild/w9xpopen.exe") + root.add_file("README.txt", src="README") + root.add_file("NEWS.txt", src="Misc/NEWS") + root.add_file("LICENSE.txt", src="LICENSE") + root.start_component("python.exe", keyfile="python.exe") + root.add_file("PCBuild/python.exe") + root.start_component("pythonw.exe", keyfile="pythonw.exe") + root.add_file("PCBuild/pythonw.exe") + + # msidbComponentAttributesSharedDllRefCount = 8, see "Component Table" + dlldir = PyDirectory(db, cab, root, srcdir, "DLLDIR", ".") + pydll = "python%s%s.dll" % (major, minor) + pydllsrc = srcdir + "/PCBuild/" + pydll + dlldir.start_component("DLLDIR", flags = 8, keyfile = pydll, uuid = pythondll_uuid) + installer = msilib.MakeInstaller() + pyversion = installer.FileVersion(pydllsrc, 0) + if not snapshot: + # For releases, the Python DLL has the same version as the + # installer package. + assert pyversion.split(".")[:3] == current_version.split(".") + dlldir.add_file("PCBuild/python%s%s.dll" % (major, minor), + version=pyversion, + language=installer.FileVersion(pydllsrc, 1)) + # XXX determine dependencies + version, lang = extract_msvcr71() + dlldir.start_component("msvcr71", flags=8, keyfile="msvcr71.dll", uuid=msvcr71_uuid) + dlldir.add_file("msvcr71.dll", src=os.path.abspath("msvcr71.dll"), + version=version, language=lang) + tmpfiles.append("msvcr71.dll") + + # Check if _ctypes.pyd exists + have_ctypes = os.path.exists(srcdir+"/PCBuild/_ctypes.pyd") + if not have_ctypes: + print "WARNING: _ctypes.pyd not found, ctypes will not be included" + extensions.remove("_ctypes.pyd") + + # Add all .py files in Lib, except lib-tk, test + dirs={} + pydirs = [(root,"Lib")] + while pydirs: + parent, dir = pydirs.pop() + if dir == ".svn" or dir.startswith("plat-"): + continue + elif dir in ["lib-tk", "idlelib", "Icons"]: + if not have_tcl: + continue + tcltk.set_current() + elif dir in ['test', 'tests', 'data', 'output']: + # test: Lib, Lib/email, Lib/bsddb, Lib/ctypes, Lib/sqlite3 + # tests: Lib/distutils + # data: Lib/email/test + # output: Lib/test + testsuite.set_current() + elif not have_ctypes and dir == "ctypes": + continue + else: + default_feature.set_current() + lib = PyDirectory(db, cab, parent, dir, dir, "%s|%s" % (parent.make_short(dir), dir)) + # Add additional files + dirs[dir]=lib + lib.glob("*.txt") + if dir=='site-packages': + lib.add_file("README.txt", src="README") + continue + files = lib.glob("*.py") + files += lib.glob("*.pyw") + if files: + # Add an entry to the RemoveFile table to remove bytecode files. + lib.remove_pyc() + if dir.endswith('.egg-info'): + lib.add_file('entry_points.txt') + lib.add_file('PKG-INFO') + lib.add_file('top_level.txt') + lib.add_file('zip-safe') + continue + if dir=='test' and parent.physical=='Lib': + lib.add_file("185test.db") + lib.add_file("audiotest.au") + lib.add_file("cfgparser.1") + lib.add_file("sgml_input.html") + lib.add_file("test.xml") + lib.add_file("test.xml.out") + lib.add_file("testtar.tar") + lib.add_file("test_difflib_expect.html") + lib.add_file("check_soundcard.vbs") + lib.add_file("empty.vbs") + lib.glob("*.uue") + lib.add_file("readme.txt", src="README") + if dir=='decimaltestdata': + lib.glob("*.decTest") + if dir=='output': + lib.glob("test_*") + if dir=='idlelib': + lib.glob("*.def") + lib.add_file("idle.bat") + if dir=="Icons": + lib.glob("*.gif") + lib.add_file("idle.icns") + if dir=="command" and parent.physical=="distutils": + lib.add_file("wininst-6.exe") + lib.add_file("wininst-7.1.exe") + if dir=="setuptools": + lib.add_file("cli.exe") + lib.add_file("gui.exe") + if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email": + # This should contain all non-.svn files listed in subversion + for f in os.listdir(lib.absolute): + if f.endswith(".txt") or f==".svn":continue + if f.endswith(".au") or f.endswith(".gif"): + lib.add_file(f) + else: + print "WARNING: New file %s in email/test/data" % f + for f in os.listdir(lib.absolute): + if os.path.isdir(os.path.join(lib.absolute, f)): + pydirs.append((lib, f)) + # Add DLLs + default_feature.set_current() + lib = PyDirectory(db, cab, root, srcdir+"/PCBuild", "DLLs", "DLLS|DLLs") + lib.add_file("py.ico", src="../PC/py.ico") + lib.add_file("pyc.ico", src="../PC/pyc.ico") + dlls = [] + tclfiles = [] + for f in extensions: + if f=="_tkinter.pyd": + continue + if not os.path.exists(srcdir+"/PCBuild/"+f): + print "WARNING: Missing extension", f + continue + dlls.append(f) + lib.add_file(f) + # Add sqlite + if msilib.msi_type=="Intel64;1033": + sqlite_arch = "/ia64" + elif msilib.msi_type=="x64;1033": + sqlite_arch = "/amd64" + else: + sqlite_arch = "" + lib.add_file(srcdir+"/"+sqlite_dir+sqlite_arch+"/sqlite3.dll") + if have_tcl: + if not os.path.exists(srcdir+"/PCBuild/_tkinter.pyd"): + print "WARNING: Missing _tkinter.pyd" + else: + lib.start_component("TkDLLs", tcltk) + lib.add_file("_tkinter.pyd") + dlls.append("_tkinter.pyd") + tcldir = os.path.normpath(srcdir+"/../tcltk/bin") + for f in glob.glob1(tcldir, "*.dll"): + lib.add_file(f, src=os.path.join(tcldir, f)) + # check whether there are any unknown extensions + for f in glob.glob1(srcdir+"/PCBuild", "*.pyd"): + if f.endswith("_d.pyd"): continue # debug version + if f in dlls: continue + print "WARNING: Unknown extension", f + + # Add headers + default_feature.set_current() + lib = PyDirectory(db, cab, root, "include", "include", "INCLUDE|include") + lib.glob("*.h") + lib.add_file("pyconfig.h", src="../PC/pyconfig.h") + # Add import libraries + lib = PyDirectory(db, cab, root, "PCBuild", "libs", "LIBS|libs") + for f in dlls: + lib.add_file(f.replace('pyd','lib')) + lib.add_file('python%s%s.lib' % (major, minor)) + # Add the mingw-format library + if have_mingw: + lib.add_file('libpython%s%s.a' % (major, minor)) + if have_tcl: + # Add Tcl/Tk + tcldirs = [(root, '../tcltk/lib', 'tcl')] + tcltk.set_current() + while tcldirs: + parent, phys, dir = tcldirs.pop() + lib = PyDirectory(db, cab, parent, phys, dir, "%s|%s" % (parent.make_short(dir), dir)) + if not os.path.exists(lib.absolute): + continue + for f in os.listdir(lib.absolute): + if os.path.isdir(os.path.join(lib.absolute, f)): + tcldirs.append((lib, f, f)) + else: + lib.add_file(f) + # Add tools + tools.set_current() + tooldir = PyDirectory(db, cab, root, "Tools", "Tools", "TOOLS|Tools") + for f in ['i18n', 'pynche', 'Scripts', 'versioncheck', 'webchecker']: + lib = PyDirectory(db, cab, tooldir, f, f, "%s|%s" % (tooldir.make_short(f), f)) + lib.glob("*.py") + lib.glob("*.pyw", exclude=['pydocgui.pyw']) + lib.remove_pyc() + lib.glob("*.txt") + if f == "pynche": + x = PyDirectory(db, cab, lib, "X", "X", "X|X") + x.glob("*.txt") + if os.path.exists(os.path.join(lib.absolute, "README")): + lib.add_file("README.txt", src="README") + if f == 'Scripts': + if have_tcl: + lib.start_component("pydocgui.pyw", tcltk, keyfile="pydocgui.pyw") + lib.add_file("pydocgui.pyw") + # Add documentation + htmlfiles.set_current() + lib = PyDirectory(db, cab, root, "Doc", "Doc", "DOC|Doc") + lib.start_component("documentation", keyfile="Python%s%s.chm" % (major,minor)) + lib.add_file("Python%s%s.chm" % (major, minor)) + + cab.commit(db) + + for f in tmpfiles: + os.unlink(f) + +# See "Registry Table", "Component Table" +def add_registry(db): + # File extensions, associated with the REGISTRY.def component + # IDLE verbs depend on the tcltk feature. + # msidbComponentAttributesRegistryKeyPath = 4 + # -1 for Root specifies "dependent on ALLUSERS property" + tcldata = [] + if have_tcl: + tcldata = [ + ("REGISTRY.tcl", msilib.gen_uuid(), "TARGETDIR", 4, None, + "py.IDLE")] + add_data(db, "Component", + # msidbComponentAttributesRegistryKeyPath = 4 + [("REGISTRY", msilib.gen_uuid(), "TARGETDIR", 4, None, + "InstallPath"), + ("REGISTRY.doc", msilib.gen_uuid(), "TARGETDIR", 4, None, + "Documentation"), + ("REGISTRY.def", msilib.gen_uuid(), "TARGETDIR", 4, + None, None)] + tcldata) + # See "FeatureComponents Table". + # The association between TclTk and pythonw.exe is necessary to make ICE59 + # happy, because the installer otherwise believes that the IDLE and PyDoc + # shortcuts might get installed without pythonw.exe being install. This + # is not true, since installing TclTk will install the default feature, which + # will cause pythonw.exe to be installed. + # REGISTRY.tcl is not associated with any feature, as it will be requested + # through a custom action + tcldata = [] + if have_tcl: + tcldata = [(tcltk.id, "pythonw.exe")] + add_data(db, "FeatureComponents", + [(default_feature.id, "REGISTRY"), + (htmlfiles.id, "REGISTRY.doc"), + (ext_feature.id, "REGISTRY.def")] + + tcldata + ) + # Extensions are not advertised. For advertised extensions, + # we would need separate binaries that install along with the + # extension. + pat = r"Software\Classes\%sPython.%sFile\shell\%s\command" + ewi = "Edit with IDLE" + pat2 = r"Software\Classes\%sPython.%sFile\DefaultIcon" + pat3 = r"Software\Classes\%sPython.%sFile" + tcl_verbs = [] + if have_tcl: + tcl_verbs=[ + ("py.IDLE", -1, pat % (testprefix, "", ewi), "", + r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"', + "REGISTRY.tcl"), + ("pyw.IDLE", -1, pat % (testprefix, "NoCon", ewi), "", + r'"[TARGETDIR]pythonw.exe" "[TARGETDIR]Lib\idlelib\idle.pyw" -n -e "%1"', + "REGISTRY.tcl"), + ] + add_data(db, "Registry", + [# Extensions + ("py.ext", -1, r"Software\Classes\."+ext, "", + "Python.File", "REGISTRY.def"), + ("pyw.ext", -1, r"Software\Classes\."+ext+'w', "", + "Python.NoConFile", "REGISTRY.def"), + ("pyc.ext", -1, r"Software\Classes\."+ext+'c', "", + "Python.CompiledFile", "REGISTRY.def"), + ("pyo.ext", -1, r"Software\Classes\."+ext+'o', "", + "Python.CompiledFile", "REGISTRY.def"), + # MIME types + ("py.mime", -1, r"Software\Classes\."+ext, "Content Type", + "text/plain", "REGISTRY.def"), + ("pyw.mime", -1, r"Software\Classes\."+ext+'w', "Content Type", + "text/plain", "REGISTRY.def"), + #Verbs + ("py.open", -1, pat % (testprefix, "", "open"), "", + r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"), + ("pyw.open", -1, pat % (testprefix, "NoCon", "open"), "", + r'"[TARGETDIR]pythonw.exe" "%1" %*', "REGISTRY.def"), + ("pyc.open", -1, pat % (testprefix, "Compiled", "open"), "", + r'"[TARGETDIR]python.exe" "%1" %*', "REGISTRY.def"), + ] + tcl_verbs + [ + #Icons + ("py.icon", -1, pat2 % (testprefix, ""), "", + r'[DLLs]py.ico', "REGISTRY.def"), + ("pyw.icon", -1, pat2 % (testprefix, "NoCon"), "", + r'[DLLs]py.ico', "REGISTRY.def"), + ("pyc.icon", -1, pat2 % (testprefix, "Compiled"), "", + r'[DLLs]pyc.ico', "REGISTRY.def"), + # Descriptions + ("py.txt", -1, pat3 % (testprefix, ""), "", + "Python File", "REGISTRY.def"), + ("pyw.txt", -1, pat3 % (testprefix, "NoCon"), "", + "Python File (no console)", "REGISTRY.def"), + ("pyc.txt", -1, pat3 % (testprefix, "Compiled"), "", + "Compiled Python File", "REGISTRY.def"), + ]) + + # Registry keys + prefix = r"Software\%sPython\PythonCore\%s" % (testprefix, short_version) + add_data(db, "Registry", + [("InstallPath", -1, prefix+r"\InstallPath", "", "[TARGETDIR]", "REGISTRY"), + ("InstallGroup", -1, prefix+r"\InstallPath\InstallGroup", "", + "Python %s" % short_version, "REGISTRY"), + ("PythonPath", -1, prefix+r"\PythonPath", "", + r"[TARGETDIR]Lib;[TARGETDIR]DLLs;[TARGETDIR]Lib\lib-tk", "REGISTRY"), + ("Documentation", -1, prefix+r"\Help\Main Python Documentation", "", + r"[TARGETDIR]Doc\Python%s%s.chm" % (major, minor), "REGISTRY.doc"), + ("Modules", -1, prefix+r"\Modules", "+", None, "REGISTRY"), + ("AppPaths", -1, r"Software\Microsoft\Windows\CurrentVersion\App Paths\Python.exe", + "", r"[TARGETDIR]Python.exe", "REGISTRY.def") + ]) + # Shortcuts, see "Shortcut Table" + add_data(db, "Directory", + [("ProgramMenuFolder", "TARGETDIR", "."), + ("MenuDir", "ProgramMenuFolder", "PY%s%s|%sPython %s.%s" % (major,minor,testprefix,major,minor))]) + add_data(db, "RemoveFile", + [("MenuDir", "TARGETDIR", None, "MenuDir", 2)]) + tcltkshortcuts = [] + if have_tcl: + tcltkshortcuts = [ + ("IDLE", "MenuDir", "IDLE|IDLE (Python GUI)", "pythonw.exe", + tcltk.id, r'"[TARGETDIR]Lib\idlelib\idle.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"), + ("PyDoc", "MenuDir", "MODDOCS|Module Docs", "pythonw.exe", + tcltk.id, r'"[TARGETDIR]Tools\scripts\pydocgui.pyw"', None, None, "python_icon.exe", 0, None, "TARGETDIR"), + ] + add_data(db, "Shortcut", + tcltkshortcuts + + [# Advertised shortcuts: targets are features, not files + ("Python", "MenuDir", "PYTHON|Python (command line)", "python.exe", + default_feature.id, None, None, None, "python_icon.exe", 2, None, "TARGETDIR"), + # Advertising the Manual breaks on (some?) Win98, and the shortcut lacks an + # icon first. + #("Manual", "MenuDir", "MANUAL|Python Manuals", "documentation", + # htmlfiles.id, None, None, None, None, None, None, None), + ## Non-advertised shortcuts: must be associated with a registry component + ("Manual", "MenuDir", "MANUAL|Python Manuals", "REGISTRY.doc", + "[#Python%s%s.chm]" % (major,minor), None, + None, None, None, None, None, None), + ("Uninstall", "MenuDir", "UNINST|Uninstall Python", "REGISTRY", + SystemFolderName+"msiexec", "/x%s" % product_code, + None, None, None, None, None, None), + ]) + db.Commit() + +db = build_database() +try: + add_features(db) + add_ui(db) + add_files(db) + add_registry(db) + remove_old_versions(db) + db.Commit() +finally: + del db diff --git a/sys/src/cmd/python/Tools/msi/msilib.py b/sys/src/cmd/python/Tools/msi/msilib.py new file mode 100644 index 000000000..d7b86ccb0 --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/msilib.py @@ -0,0 +1,674 @@ +# Microsoft Installer Library +# (C) 2003 Martin v. Loewis + +import win32com.client.gencache +import win32com.client +import pythoncom, pywintypes +from win32com.client import constants +import re, string, os, sets, glob, popen2, sys, _winreg, struct + +try: + basestring +except NameError: + basestring = (str, unicode) + +# Partially taken from Wine +datasizemask= 0x00ff +type_valid= 0x0100 +type_localizable= 0x0200 + +typemask= 0x0c00 +type_long= 0x0000 +type_short= 0x0400 +type_string= 0x0c00 +type_binary= 0x0800 + +type_nullable= 0x1000 +type_key= 0x2000 +# XXX temporary, localizable? +knownbits = datasizemask | type_valid | type_localizable | \ + typemask | type_nullable | type_key + +# Summary Info Property IDs +PID_CODEPAGE=1 +PID_TITLE=2 +PID_SUBJECT=3 +PID_AUTHOR=4 +PID_KEYWORDS=5 +PID_COMMENTS=6 +PID_TEMPLATE=7 +PID_LASTAUTHOR=8 +PID_REVNUMBER=9 +PID_LASTPRINTED=11 +PID_CREATE_DTM=12 +PID_LASTSAVE_DTM=13 +PID_PAGECOUNT=14 +PID_WORDCOUNT=15 +PID_CHARCOUNT=16 +PID_APPNAME=18 +PID_SECURITY=19 + +def reset(): + global _directories + _directories = sets.Set() + +def EnsureMSI(): + win32com.client.gencache.EnsureModule('{000C1092-0000-0000-C000-000000000046}', 1033, 1, 0) + +def EnsureMSM(): + try: + win32com.client.gencache.EnsureModule('{0ADDA82F-2C26-11D2-AD65-00A0C9AF11A6}', 0, 1, 0) + except pywintypes.com_error: + win32com.client.gencache.EnsureModule('{0ADDA82F-2C26-11D2-AD65-00A0C9AF11A6}', 0, 2, 0) + +_Installer=None +def MakeInstaller(): + global _Installer + if _Installer is None: + EnsureMSI() + _Installer = win32com.client.Dispatch('WindowsInstaller.Installer', + resultCLSID='{000C1090-0000-0000-C000-000000000046}') + return _Installer + +_Merge=None +def MakeMerge2(): + global _Merge + if _Merge is None: + EnsureMSM() + _Merge = win32com.client.Dispatch("Msm.Merge2.1") + return _Merge + +class Table: + def __init__(self, name): + self.name = name + self.fields = [] + + def add_field(self, index, name, type): + self.fields.append((index,name,type)) + + def sql(self): + fields = [] + keys = [] + self.fields.sort() + fields = [None]*len(self.fields) + for index, name, type in self.fields: + index -= 1 + unk = type & ~knownbits + if unk: + print "%s.%s unknown bits %x" % (self.name, name, unk) + size = type & datasizemask + dtype = type & typemask + if dtype == type_string: + if size: + tname="CHAR(%d)" % size + else: + tname="CHAR" + elif dtype == type_short: + assert size==2 + tname = "SHORT" + elif dtype == type_long: + assert size==4 + tname="LONG" + elif dtype == type_binary: + assert size==0 + tname="OBJECT" + else: + tname="unknown" + print "%s.%sunknown integer type %d" % (self.name, name, size) + if type & type_nullable: + flags = "" + else: + flags = " NOT NULL" + if type & type_localizable: + flags += " LOCALIZABLE" + fields[index] = "`%s` %s%s" % (name, tname, flags) + if type & type_key: + keys.append("`%s`" % name) + fields = ", ".join(fields) + keys = ", ".join(keys) + return "CREATE TABLE %s (%s PRIMARY KEY %s)" % (self.name, fields, keys) + + def create(self, db): + v = db.OpenView(self.sql()) + v.Execute(None) + v.Close() + +class Binary: + def __init__(self, fname): + self.name = fname + def __repr__(self): + return 'msilib.Binary(os.path.join(dirname,"%s"))' % self.name + +def gen_schema(destpath, schemapath): + d = MakeInstaller() + schema = d.OpenDatabase(schemapath, + win32com.client.constants.msiOpenDatabaseModeReadOnly) + + # XXX ORBER BY + v=schema.OpenView("SELECT * FROM _Columns") + curtable=None + tables = [] + v.Execute(None) + f = open(destpath, "wt") + f.write("from msilib import Table\n") + while 1: + r=v.Fetch() + if not r:break + name=r.StringData(1) + if curtable != name: + f.write("\n%s = Table('%s')\n" % (name,name)) + curtable = name + tables.append(name) + f.write("%s.add_field(%d,'%s',%d)\n" % + (name, r.IntegerData(2), r.StringData(3), r.IntegerData(4))) + v.Close() + + f.write("\ntables=[%s]\n\n" % (", ".join(tables))) + + # Fill the _Validation table + f.write("_Validation_records = [\n") + v = schema.OpenView("SELECT * FROM _Validation") + v.Execute(None) + while 1: + r = v.Fetch() + if not r:break + # Table, Column, Nullable + f.write("(%s,%s,%s," % + (`r.StringData(1)`, `r.StringData(2)`, `r.StringData(3)`)) + def put_int(i): + if r.IsNull(i):f.write("None, ") + else:f.write("%d," % r.IntegerData(i)) + def put_str(i): + if r.IsNull(i):f.write("None, ") + else:f.write("%s," % `r.StringData(i)`) + put_int(4) # MinValue + put_int(5) # MaxValue + put_str(6) # KeyTable + put_int(7) # KeyColumn + put_str(8) # Category + put_str(9) # Set + put_str(10)# Description + f.write("),\n") + f.write("]\n\n") + + f.close() + +def gen_sequence(destpath, msipath): + dir = os.path.dirname(destpath) + d = MakeInstaller() + seqmsi = d.OpenDatabase(msipath, + win32com.client.constants.msiOpenDatabaseModeReadOnly) + + v = seqmsi.OpenView("SELECT * FROM _Tables"); + v.Execute(None) + f = open(destpath, "w") + print >>f, "import msilib,os;dirname=os.path.dirname(__file__)" + tables = [] + while 1: + r = v.Fetch() + if not r:break + table = r.StringData(1) + tables.append(table) + f.write("%s = [\n" % table) + v1 = seqmsi.OpenView("SELECT * FROM `%s`" % table) + v1.Execute(None) + info = v1.ColumnInfo(constants.msiColumnInfoTypes) + while 1: + r = v1.Fetch() + if not r:break + rec = [] + for i in range(1,r.FieldCount+1): + if r.IsNull(i): + rec.append(None) + elif info.StringData(i)[0] in "iI": + rec.append(r.IntegerData(i)) + elif info.StringData(i)[0] in "slSL": + rec.append(r.StringData(i)) + elif info.StringData(i)[0]=="v": + size = r.DataSize(i) + bytes = r.ReadStream(i, size, constants.msiReadStreamBytes) + bytes = bytes.encode("latin-1") # binary data represented "as-is" + if table == "Binary": + fname = rec[0]+".bin" + open(os.path.join(dir,fname),"wb").write(bytes) + rec.append(Binary(fname)) + else: + rec.append(bytes) + else: + raise "Unsupported column type", info.StringData(i) + f.write(repr(tuple(rec))+",\n") + v1.Close() + f.write("]\n\n") + v.Close() + f.write("tables=%s\n" % repr(map(str,tables))) + f.close() + +class _Unspecified:pass +def change_sequence(seq, action, seqno=_Unspecified, cond = _Unspecified): + "Change the sequence number of an action in a sequence list" + for i in range(len(seq)): + if seq[i][0] == action: + if cond is _Unspecified: + cond = seq[i][1] + if seqno is _Unspecified: + seqno = seq[i][2] + seq[i] = (action, cond, seqno) + return + raise ValueError, "Action not found in sequence" + +def add_data(db, table, values): + d = MakeInstaller() + v = db.OpenView("SELECT * FROM `%s`" % table) + count = v.ColumnInfo(0).FieldCount + r = d.CreateRecord(count) + for value in values: + assert len(value) == count, value + for i in range(count): + field = value[i] + if isinstance(field, (int, long)): + r.SetIntegerData(i+1,field) + elif isinstance(field, basestring): + r.SetStringData(i+1,field) + elif field is None: + pass + elif isinstance(field, Binary): + r.SetStream(i+1, field.name) + else: + raise TypeError, "Unsupported type %s" % field.__class__.__name__ + v.Modify(win32com.client.constants.msiViewModifyInsert, r) + r.ClearData() + v.Close() + +def add_stream(db, name, path): + d = MakeInstaller() + v = db.OpenView("INSERT INTO _Streams (Name, Data) VALUES ('%s', ?)" % name) + r = d.CreateRecord(1) + r.SetStream(1, path) + v.Execute(r) + v.Close() + +def init_database(name, schema, + ProductName, ProductCode, ProductVersion, + Manufacturer): + try: + os.unlink(name) + except OSError: + pass + ProductCode = ProductCode.upper() + d = MakeInstaller() + # Create the database + db = d.OpenDatabase(name, + win32com.client.constants.msiOpenDatabaseModeCreate) + # Create the tables + for t in schema.tables: + t.create(db) + # Fill the validation table + add_data(db, "_Validation", schema._Validation_records) + # Initialize the summary information, allowing atmost 20 properties + si = db.GetSummaryInformation(20) + si.SetProperty(PID_TITLE, "Installation Database") + si.SetProperty(PID_SUBJECT, ProductName) + si.SetProperty(PID_AUTHOR, Manufacturer) + si.SetProperty(PID_TEMPLATE, msi_type) + si.SetProperty(PID_REVNUMBER, gen_uuid()) + si.SetProperty(PID_WORDCOUNT, 2) # long file names, compressed, original media + si.SetProperty(PID_PAGECOUNT, 200) + si.SetProperty(PID_APPNAME, "Python MSI Library") + # XXX more properties + si.Persist() + add_data(db, "Property", [ + ("ProductName", ProductName), + ("ProductCode", ProductCode), + ("ProductVersion", ProductVersion), + ("Manufacturer", Manufacturer), + ("ProductLanguage", "1033")]) + db.Commit() + return db + +def add_tables(db, module): + for table in module.tables: + add_data(db, table, getattr(module, table)) + +def make_id(str): + #str = str.replace(".", "_") # colons are allowed + str = str.replace(" ", "_") + str = str.replace("-", "_") + if str[0] in string.digits: + str = "_"+str + assert re.match("^[A-Za-z_][A-Za-z0-9_.]*$", str), "FILE"+str + return str + +def gen_uuid(): + return str(pythoncom.CreateGuid()) + +class CAB: + def __init__(self, name): + self.name = name + self.file = open(name+".txt", "wt") + self.filenames = sets.Set() + self.index = 0 + + def gen_id(self, dir, file): + logical = _logical = make_id(file) + pos = 1 + while logical in self.filenames: + logical = "%s.%d" % (_logical, pos) + pos += 1 + self.filenames.add(logical) + return logical + + def append(self, full, file, logical = None): + if os.path.isdir(full): + return + if not logical: + logical = self.gen_id(dir, file) + self.index += 1 + if full.find(" ")!=-1: + print >>self.file, '"%s" %s' % (full, logical) + else: + print >>self.file, '%s %s' % (full, logical) + return self.index, logical + + def commit(self, db): + self.file.close() + try: + os.unlink(self.name+".cab") + except OSError: + pass + for k, v in [(r"Software\Microsoft\VisualStudio\7.1\Setup\VS", "VS7CommonBinDir"), + (r"Software\Microsoft\Win32SDK\Directories", "Install Dir")]: + try: + key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, k) + except WindowsError: + continue + cabarc = os.path.join(_winreg.QueryValueEx(key, v)[0], r"Bin", "cabarc.exe") + _winreg.CloseKey(key) + if not os.path.exists(cabarc):continue + break + else: + print "WARNING: cabarc.exe not found in registry" + cabarc = "cabarc.exe" + f = popen2.popen4(r'"%s" -m lzx:21 n %s.cab @%s.txt' % (cabarc, self.name, self.name))[0] + for line in f: + if line.startswith(" -- adding "): + sys.stdout.write(".") + else: + sys.stdout.write(line) + sys.stdout.flush() + if not os.path.exists(self.name+".cab"): + raise IOError, "cabarc failed" + add_data(db, "Media", + [(1, self.index, None, "#"+self.name, None, None)]) + add_stream(db, self.name, self.name+".cab") + os.unlink(self.name+".txt") + os.unlink(self.name+".cab") + db.Commit() + +_directories = sets.Set() +class Directory: + def __init__(self, db, cab, basedir, physical, _logical, default, componentflags=None): + """Create a new directory in the Directory table. There is a current component + at each point in time for the directory, which is either explicitly created + through start_component, or implicitly when files are added for the first + time. Files are added into the current component, and into the cab file. + To create a directory, a base directory object needs to be specified (can be + None), the path to the physical directory, and a logical directory name. + Default specifies the DefaultDir slot in the directory table. componentflags + specifies the default flags that new components get.""" + index = 1 + _logical = make_id(_logical) + logical = _logical + while logical in _directories: + logical = "%s%d" % (_logical, index) + index += 1 + _directories.add(logical) + self.db = db + self.cab = cab + self.basedir = basedir + self.physical = physical + self.logical = logical + self.component = None + self.short_names = sets.Set() + self.ids = sets.Set() + self.keyfiles = {} + self.componentflags = componentflags + if basedir: + self.absolute = os.path.join(basedir.absolute, physical) + blogical = basedir.logical + else: + self.absolute = physical + blogical = None + add_data(db, "Directory", [(logical, blogical, default)]) + + def start_component(self, component = None, feature = None, flags = None, keyfile = None, uuid=None): + """Add an entry to the Component table, and make this component the current for this + directory. If no component name is given, the directory name is used. If no feature + is given, the current feature is used. If no flags are given, the directory's default + flags are used. If no keyfile is given, the KeyPath is left null in the Component + table.""" + if flags is None: + flags = self.componentflags + if uuid is None: + uuid = gen_uuid() + else: + uuid = uuid.upper() + if component is None: + component = self.logical + self.component = component + if Win64: + flags |= 256 + if keyfile: + keyid = self.cab.gen_id(self.absolute, keyfile) + self.keyfiles[keyfile] = keyid + else: + keyid = None + add_data(self.db, "Component", + [(component, uuid, self.logical, flags, None, keyid)]) + if feature is None: + feature = current_feature + add_data(self.db, "FeatureComponents", + [(feature.id, component)]) + + def make_short(self, file): + parts = file.split(".") + if len(parts)>1: + suffix = parts[-1].upper() + else: + suffix = None + prefix = parts[0].upper() + if len(prefix) <= 8 and (not suffix or len(suffix)<=3): + if suffix: + file = prefix+"."+suffix + else: + file = prefix + assert file not in self.short_names + else: + prefix = prefix[:6] + if suffix: + suffix = suffix[:3] + pos = 1 + while 1: + if suffix: + file = "%s~%d.%s" % (prefix, pos, suffix) + else: + file = "%s~%d" % (prefix, pos) + if file not in self.short_names: break + pos += 1 + assert pos < 10000 + if pos in (10, 100, 1000): + prefix = prefix[:-1] + self.short_names.add(file) + assert not re.search(r'[\?|><:/*"+,;=\[\]]', file) # restrictions on short names + return file + + def add_file(self, file, src=None, version=None, language=None): + """Add a file to the current component of the directory, starting a new one + one if there is no current component. By default, the file name in the source + and the file table will be identical. If the src file is specified, it is + interpreted relative to the current directory. Optionally, a version and a + language can be specified for the entry in the File table.""" + if not self.component: + self.start_component(self.logical, current_feature) + if not src: + # Allow relative paths for file if src is not specified + src = file + file = os.path.basename(file) + absolute = os.path.join(self.absolute, src) + assert not re.search(r'[\?|><:/*]"', file) # restrictions on long names + if self.keyfiles.has_key(file): + logical = self.keyfiles[file] + else: + logical = None + sequence, logical = self.cab.append(absolute, file, logical) + assert logical not in self.ids + self.ids.add(logical) + short = self.make_short(file) + full = "%s|%s" % (short, file) + filesize = os.stat(absolute).st_size + # constants.msidbFileAttributesVital + # Compressed omitted, since it is the database default + # could add r/o, system, hidden + attributes = 512 + add_data(self.db, "File", + [(logical, self.component, full, filesize, version, + language, attributes, sequence)]) + if not version: + # Add hash if the file is not versioned + filehash = MakeInstaller().FileHash(absolute, 0) + add_data(self.db, "MsiFileHash", + [(logical, 0, filehash.IntegerData(1), + filehash.IntegerData(2), filehash.IntegerData(3), + filehash.IntegerData(4))]) + # Automatically remove .pyc/.pyo files on uninstall (2) + # XXX: adding so many RemoveFile entries makes installer unbelievably + # slow. So instead, we have to use wildcard remove entries + # if file.endswith(".py"): + # add_data(self.db, "RemoveFile", + # [(logical+"c", self.component, "%sC|%sc" % (short, file), + # self.logical, 2), + # (logical+"o", self.component, "%sO|%so" % (short, file), + # self.logical, 2)]) + + def glob(self, pattern, exclude = None): + """Add a list of files to the current component as specified in the + glob pattern. Individual files can be excluded in the exclude list.""" + files = glob.glob1(self.absolute, pattern) + for f in files: + if exclude and f in exclude: continue + self.add_file(f) + return files + + def remove_pyc(self): + "Remove .pyc/.pyo files on uninstall" + add_data(self.db, "RemoveFile", + [(self.component+"c", self.component, "*.pyc", self.logical, 2), + (self.component+"o", self.component, "*.pyo", self.logical, 2)]) + +class Feature: + def __init__(self, db, id, title, desc, display, level = 1, + parent=None, directory = None, attributes=0): + self.id = id + if parent: + parent = parent.id + add_data(db, "Feature", + [(id, parent, title, desc, display, + level, directory, attributes)]) + def set_current(self): + global current_feature + current_feature = self + +class Control: + def __init__(self, dlg, name): + self.dlg = dlg + self.name = name + + def event(self, ev, arg, cond = "1", order = None): + add_data(self.dlg.db, "ControlEvent", + [(self.dlg.name, self.name, ev, arg, cond, order)]) + + def mapping(self, ev, attr): + add_data(self.dlg.db, "EventMapping", + [(self.dlg.name, self.name, ev, attr)]) + + def condition(self, action, condition): + add_data(self.dlg.db, "ControlCondition", + [(self.dlg.name, self.name, action, condition)]) + +class RadioButtonGroup(Control): + def __init__(self, dlg, name, property): + self.dlg = dlg + self.name = name + self.property = property + self.index = 1 + + def add(self, name, x, y, w, h, text, value = None): + if value is None: + value = name + add_data(self.dlg.db, "RadioButton", + [(self.property, self.index, value, + x, y, w, h, text, None)]) + self.index += 1 + +class Dialog: + def __init__(self, db, name, x, y, w, h, attr, title, first, default, cancel): + self.db = db + self.name = name + self.x, self.y, self.w, self.h = x,y,w,h + add_data(db, "Dialog", [(name, x,y,w,h,attr,title,first,default,cancel)]) + + def control(self, name, type, x, y, w, h, attr, prop, text, next, help): + add_data(self.db, "Control", + [(self.name, name, type, x, y, w, h, attr, prop, text, next, help)]) + return Control(self, name) + + def text(self, name, x, y, w, h, attr, text): + return self.control(name, "Text", x, y, w, h, attr, None, + text, None, None) + + def bitmap(self, name, x, y, w, h, text): + return self.control(name, "Bitmap", x, y, w, h, 1, None, text, None, None) + + def line(self, name, x, y, w, h): + return self.control(name, "Line", x, y, w, h, 1, None, None, None, None) + + def pushbutton(self, name, x, y, w, h, attr, text, next): + return self.control(name, "PushButton", x, y, w, h, attr, None, text, next, None) + + def radiogroup(self, name, x, y, w, h, attr, prop, text, next): + add_data(self.db, "Control", + [(self.name, name, "RadioButtonGroup", + x, y, w, h, attr, prop, text, next, None)]) + return RadioButtonGroup(self, name, prop) + + def checkbox(self, name, x, y, w, h, attr, prop, text, next): + return self.control(name, "CheckBox", x, y, w, h, attr, prop, text, next, None) + +def pe_type(path): + header = open(path, "rb").read(1000) + # offset of PE header is at offset 0x3c + pe_offset = struct.unpack("<i", header[0x3c:0x40])[0] + assert header[pe_offset:pe_offset+4] == "PE\0\0" + machine = struct.unpack("<H", header[pe_offset+4:pe_offset+6])[0] + return machine + +def set_arch_from_file(path): + global msi_type, Win64, arch_ext + machine = pe_type(path) + if machine == 0x14c: + # i386 + msi_type = "Intel" + Win64 = 0 + arch_ext = '' + elif machine == 0x200: + # Itanium + msi_type = "Intel64" + Win64 = 1 + arch_ext = '.ia64' + elif machine == 0x8664: + # AMD64 + msi_type = "x64" + Win64 = 1 + arch_ext = '.amd64' + else: + raise ValueError, "Unsupported architecture" + msi_type += ";1033" diff --git a/sys/src/cmd/python/Tools/msi/msisupport.c b/sys/src/cmd/python/Tools/msi/msisupport.c new file mode 100644 index 000000000..b293bfc19 --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/msisupport.c @@ -0,0 +1,102 @@ +#include "windows.h" +#include "msiquery.h" + +int isWinNT; + +/* Print a debug message to the installer log file. + * To see the debug messages, install with + * msiexec /i pythonxy.msi /l*v python.log + */ +static UINT debug(MSIHANDLE hInstall, LPCSTR msg) +{ + MSIHANDLE hRec = MsiCreateRecord(1); + if (!hRec || MsiRecordSetStringA(hRec, 1, msg) != ERROR_SUCCESS) { + return ERROR_INSTALL_FAILURE; + } + MsiProcessMessage(hInstall, INSTALLMESSAGE_INFO, hRec); + MsiCloseHandle(hRec); + return ERROR_SUCCESS; +} + +/* Check whether the TARGETDIR exists and is a directory. + * Set TargetExists appropriately. + */ +UINT __declspec(dllexport) __stdcall CheckDir(MSIHANDLE hInstall) +{ +#define PSIZE 1024 + WCHAR wpath[PSIZE]; + char path[PSIZE]; + UINT result; + DWORD size = PSIZE; + DWORD attributes; + + isWinNT = (GetVersion() < 0x80000000) ? 1 : 0; + + if (isWinNT) + result = MsiGetPropertyW(hInstall, L"TARGETDIR", wpath, &size); + else + result = MsiGetPropertyA(hInstall, "TARGETDIR", path, &size); + if (result != ERROR_SUCCESS) + return result; + wpath[size] = L'\0'; + path[size] = L'\0'; + + if (isWinNT) + attributes = GetFileAttributesW(wpath); + else + attributes = GetFileAttributesA(path); + if (attributes == INVALID_FILE_ATTRIBUTES || + !(attributes & FILE_ATTRIBUTE_DIRECTORY)) + { + return MsiSetPropertyA(hInstall, "TargetExists", "0"); + } else { + return MsiSetPropertyA(hInstall, "TargetExists", "1"); + } +} + +/* Update the state of the REGISTRY.tcl component according to the + * Extension and TclTk features. REGISTRY.tcl must be installed + * if both features are installed, and must be absent otherwise. + */ +UINT __declspec(dllexport) __stdcall UpdateEditIDLE(MSIHANDLE hInstall) +{ + INSTALLSTATE ext_old, ext_new, tcl_old, tcl_new, reg_new; + UINT result; + + result = MsiGetFeatureStateA(hInstall, "Extensions", &ext_old, &ext_new); + if (result != ERROR_SUCCESS) + return result; + result = MsiGetFeatureStateA(hInstall, "TclTk", &tcl_old, &tcl_new); + if (result != ERROR_SUCCESS) + return result; + + /* If the current state is Absent, and the user did not select + the feature in the UI, Installer apparently sets the "selected" + state to unknown. Update it to the current value, then. */ + if (ext_new == INSTALLSTATE_UNKNOWN) + ext_new = ext_old; + if (tcl_new == INSTALLSTATE_UNKNOWN) + tcl_new = tcl_old; + + // XXX consider current state of REGISTRY.tcl? + if (((tcl_new == INSTALLSTATE_LOCAL) || + (tcl_new == INSTALLSTATE_SOURCE) || + (tcl_new == INSTALLSTATE_DEFAULT)) && + ((ext_new == INSTALLSTATE_LOCAL) || + (ext_new == INSTALLSTATE_SOURCE) || + (ext_new == INSTALLSTATE_DEFAULT))) { + reg_new = INSTALLSTATE_SOURCE; + } else { + reg_new = INSTALLSTATE_ABSENT; + } + result = MsiSetComponentStateA(hInstall, "REGISTRY.tcl", reg_new); + return result; +} + +BOOL APIENTRY DllMain(HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved) +{ + return TRUE; +} + diff --git a/sys/src/cmd/python/Tools/msi/msisupport.mak b/sys/src/cmd/python/Tools/msi/msisupport.mak new file mode 100644 index 000000000..fb960c281 --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/msisupport.mak @@ -0,0 +1,25 @@ +!IF "$(CPU)" == "" +# VS environment + +# /OPT: REF and ICF are added by VS.NET by default +# NOWIN98 saves 7k of executable size, at the expense of some +# slowdown on Win98 +msisupport.dll: msisupport.obj + link.exe /OUT:msisupport.dll /INCREMENTAL:NO /NOLOGO /DLL /MACHINE:X86 /SUBSYSTEM:WINDOWS /OPT:REF /OPT:ICF /OPT:NOWIN98 msisupport.obj msi.lib kernel32.lib + +# We request a static CRT, so that there will be no CRT dependencies +# for the target system. We cannot do without a CRT, since it provides +# the DLL entry point. +msisupport.obj: msisupport.c + cl /O2 /D WIN32 /D NDEBUG /D _WINDOWS /MT /W3 /c msisupport.c + +!ELSE +# SDK environment: assume all options are already correct + +msisupport.dll: msisupport.obj + link.exe /OUT:msisupport.dll /INCREMENTAL:NO /NOLOGO /DLL msisupport.obj msi.lib kernel32.lib + +msisupport.obj: msisupport.c + cl /O2 /D WIN32 /D NDEBUG /D _WINDOWS /MD /W3 /GS- /c msisupport.c +!ENDIF + diff --git a/sys/src/cmd/python/Tools/msi/schema.py b/sys/src/cmd/python/Tools/msi/schema.py new file mode 100644 index 000000000..7a3e7975b --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/schema.py @@ -0,0 +1,1007 @@ +from msilib import Table + +_Validation = Table('_Validation') +_Validation.add_field(1,'Table',11552) +_Validation.add_field(2,'Column',11552) +_Validation.add_field(3,'Nullable',3332) +_Validation.add_field(4,'MinValue',4356) +_Validation.add_field(5,'MaxValue',4356) +_Validation.add_field(6,'KeyTable',7679) +_Validation.add_field(7,'KeyColumn',5378) +_Validation.add_field(8,'Category',7456) +_Validation.add_field(9,'Set',7679) +_Validation.add_field(10,'Description',7679) + +ActionText = Table('ActionText') +ActionText.add_field(1,'Action',11592) +ActionText.add_field(2,'Description',7936) +ActionText.add_field(3,'Template',7936) + +AdminExecuteSequence = Table('AdminExecuteSequence') +AdminExecuteSequence.add_field(1,'Action',11592) +AdminExecuteSequence.add_field(2,'Condition',7679) +AdminExecuteSequence.add_field(3,'Sequence',5378) + +Condition = Table('Condition') +Condition.add_field(1,'Feature_',11558) +Condition.add_field(2,'Level',9474) +Condition.add_field(3,'Condition',7679) + +AdminUISequence = Table('AdminUISequence') +AdminUISequence.add_field(1,'Action',11592) +AdminUISequence.add_field(2,'Condition',7679) +AdminUISequence.add_field(3,'Sequence',5378) + +AdvtExecuteSequence = Table('AdvtExecuteSequence') +AdvtExecuteSequence.add_field(1,'Action',11592) +AdvtExecuteSequence.add_field(2,'Condition',7679) +AdvtExecuteSequence.add_field(3,'Sequence',5378) + +AdvtUISequence = Table('AdvtUISequence') +AdvtUISequence.add_field(1,'Action',11592) +AdvtUISequence.add_field(2,'Condition',7679) +AdvtUISequence.add_field(3,'Sequence',5378) + +AppId = Table('AppId') +AppId.add_field(1,'AppId',11558) +AppId.add_field(2,'RemoteServerName',7679) +AppId.add_field(3,'LocalService',7679) +AppId.add_field(4,'ServiceParameters',7679) +AppId.add_field(5,'DllSurrogate',7679) +AppId.add_field(6,'ActivateAtStorage',5378) +AppId.add_field(7,'RunAsInteractiveUser',5378) + +AppSearch = Table('AppSearch') +AppSearch.add_field(1,'Property',11592) +AppSearch.add_field(2,'Signature_',11592) + +Property = Table('Property') +Property.add_field(1,'Property',11592) +Property.add_field(2,'Value',3840) + +BBControl = Table('BBControl') +BBControl.add_field(1,'Billboard_',11570) +BBControl.add_field(2,'BBControl',11570) +BBControl.add_field(3,'Type',3378) +BBControl.add_field(4,'X',1282) +BBControl.add_field(5,'Y',1282) +BBControl.add_field(6,'Width',1282) +BBControl.add_field(7,'Height',1282) +BBControl.add_field(8,'Attributes',4356) +BBControl.add_field(9,'Text',7986) + +Billboard = Table('Billboard') +Billboard.add_field(1,'Billboard',11570) +Billboard.add_field(2,'Feature_',3366) +Billboard.add_field(3,'Action',7474) +Billboard.add_field(4,'Ordering',5378) + +Feature = Table('Feature') +Feature.add_field(1,'Feature',11558) +Feature.add_field(2,'Feature_Parent',7462) +Feature.add_field(3,'Title',8000) +Feature.add_field(4,'Description',8191) +Feature.add_field(5,'Display',5378) +Feature.add_field(6,'Level',1282) +Feature.add_field(7,'Directory_',7496) +Feature.add_field(8,'Attributes',1282) + +Binary = Table('Binary') +Binary.add_field(1,'Name',11592) +Binary.add_field(2,'Data',2304) + +BindImage = Table('BindImage') +BindImage.add_field(1,'File_',11592) +BindImage.add_field(2,'Path',7679) + +File = Table('File') +File.add_field(1,'File',11592) +File.add_field(2,'Component_',3400) +File.add_field(3,'FileName',4095) +File.add_field(4,'FileSize',260) +File.add_field(5,'Version',7496) +File.add_field(6,'Language',7444) +File.add_field(7,'Attributes',5378) +File.add_field(8,'Sequence',1282) + +CCPSearch = Table('CCPSearch') +CCPSearch.add_field(1,'Signature_',11592) + +CheckBox = Table('CheckBox') +CheckBox.add_field(1,'Property',11592) +CheckBox.add_field(2,'Value',7488) + +Class = Table('Class') +Class.add_field(1,'CLSID',11558) +Class.add_field(2,'Context',11552) +Class.add_field(3,'Component_',11592) +Class.add_field(4,'ProgId_Default',7679) +Class.add_field(5,'Description',8191) +Class.add_field(6,'AppId_',7462) +Class.add_field(7,'FileTypeMask',7679) +Class.add_field(8,'Icon_',7496) +Class.add_field(9,'IconIndex',5378) +Class.add_field(10,'DefInprocHandler',7456) +Class.add_field(11,'Argument',7679) +Class.add_field(12,'Feature_',3366) +Class.add_field(13,'Attributes',5378) + +Component = Table('Component') +Component.add_field(1,'Component',11592) +Component.add_field(2,'ComponentId',7462) +Component.add_field(3,'Directory_',3400) +Component.add_field(4,'Attributes',1282) +Component.add_field(5,'Condition',7679) +Component.add_field(6,'KeyPath',7496) + +Icon = Table('Icon') +Icon.add_field(1,'Name',11592) +Icon.add_field(2,'Data',2304) + +ProgId = Table('ProgId') +ProgId.add_field(1,'ProgId',11775) +ProgId.add_field(2,'ProgId_Parent',7679) +ProgId.add_field(3,'Class_',7462) +ProgId.add_field(4,'Description',8191) +ProgId.add_field(5,'Icon_',7496) +ProgId.add_field(6,'IconIndex',5378) + +ComboBox = Table('ComboBox') +ComboBox.add_field(1,'Property',11592) +ComboBox.add_field(2,'Order',9474) +ComboBox.add_field(3,'Value',3392) +ComboBox.add_field(4,'Text',8000) + +CompLocator = Table('CompLocator') +CompLocator.add_field(1,'Signature_',11592) +CompLocator.add_field(2,'ComponentId',3366) +CompLocator.add_field(3,'Type',5378) + +Complus = Table('Complus') +Complus.add_field(1,'Component_',11592) +Complus.add_field(2,'ExpType',13570) + +Directory = Table('Directory') +Directory.add_field(1,'Directory',11592) +Directory.add_field(2,'Directory_Parent',7496) +Directory.add_field(3,'DefaultDir',4095) + +Control = Table('Control') +Control.add_field(1,'Dialog_',11592) +Control.add_field(2,'Control',11570) +Control.add_field(3,'Type',3348) +Control.add_field(4,'X',1282) +Control.add_field(5,'Y',1282) +Control.add_field(6,'Width',1282) +Control.add_field(7,'Height',1282) +Control.add_field(8,'Attributes',4356) +Control.add_field(9,'Property',7474) +Control.add_field(10,'Text',7936) +Control.add_field(11,'Control_Next',7474) +Control.add_field(12,'Help',7986) + +Dialog = Table('Dialog') +Dialog.add_field(1,'Dialog',11592) +Dialog.add_field(2,'HCentering',1282) +Dialog.add_field(3,'VCentering',1282) +Dialog.add_field(4,'Width',1282) +Dialog.add_field(5,'Height',1282) +Dialog.add_field(6,'Attributes',4356) +Dialog.add_field(7,'Title',8064) +Dialog.add_field(8,'Control_First',3378) +Dialog.add_field(9,'Control_Default',7474) +Dialog.add_field(10,'Control_Cancel',7474) + +ControlCondition = Table('ControlCondition') +ControlCondition.add_field(1,'Dialog_',11592) +ControlCondition.add_field(2,'Control_',11570) +ControlCondition.add_field(3,'Action',11570) +ControlCondition.add_field(4,'Condition',11775) + +ControlEvent = Table('ControlEvent') +ControlEvent.add_field(1,'Dialog_',11592) +ControlEvent.add_field(2,'Control_',11570) +ControlEvent.add_field(3,'Event',11570) +ControlEvent.add_field(4,'Argument',11775) +ControlEvent.add_field(5,'Condition',15871) +ControlEvent.add_field(6,'Ordering',5378) + +CreateFolder = Table('CreateFolder') +CreateFolder.add_field(1,'Directory_',11592) +CreateFolder.add_field(2,'Component_',11592) + +CustomAction = Table('CustomAction') +CustomAction.add_field(1,'Action',11592) +CustomAction.add_field(2,'Type',1282) +CustomAction.add_field(3,'Source',7496) +CustomAction.add_field(4,'Target',7679) + +DrLocator = Table('DrLocator') +DrLocator.add_field(1,'Signature_',11592) +DrLocator.add_field(2,'Parent',15688) +DrLocator.add_field(3,'Path',15871) +DrLocator.add_field(4,'Depth',5378) + +DuplicateFile = Table('DuplicateFile') +DuplicateFile.add_field(1,'FileKey',11592) +DuplicateFile.add_field(2,'Component_',3400) +DuplicateFile.add_field(3,'File_',3400) +DuplicateFile.add_field(4,'DestName',8191) +DuplicateFile.add_field(5,'DestFolder',7496) + +Environment = Table('Environment') +Environment.add_field(1,'Environment',11592) +Environment.add_field(2,'Name',4095) +Environment.add_field(3,'Value',8191) +Environment.add_field(4,'Component_',3400) + +Error = Table('Error') +Error.add_field(1,'Error',9474) +Error.add_field(2,'Message',7936) + +EventMapping = Table('EventMapping') +EventMapping.add_field(1,'Dialog_',11592) +EventMapping.add_field(2,'Control_',11570) +EventMapping.add_field(3,'Event',11570) +EventMapping.add_field(4,'Attribute',3378) + +Extension = Table('Extension') +Extension.add_field(1,'Extension',11775) +Extension.add_field(2,'Component_',11592) +Extension.add_field(3,'ProgId_',7679) +Extension.add_field(4,'MIME_',7488) +Extension.add_field(5,'Feature_',3366) + +MIME = Table('MIME') +MIME.add_field(1,'ContentType',11584) +MIME.add_field(2,'Extension_',3583) +MIME.add_field(3,'CLSID',7462) + +FeatureComponents = Table('FeatureComponents') +FeatureComponents.add_field(1,'Feature_',11558) +FeatureComponents.add_field(2,'Component_',11592) + +FileSFPCatalog = Table('FileSFPCatalog') +FileSFPCatalog.add_field(1,'File_',11592) +FileSFPCatalog.add_field(2,'SFPCatalog_',11775) + +SFPCatalog = Table('SFPCatalog') +SFPCatalog.add_field(1,'SFPCatalog',11775) +SFPCatalog.add_field(2,'Catalog',2304) +SFPCatalog.add_field(3,'Dependency',7424) + +Font = Table('Font') +Font.add_field(1,'File_',11592) +Font.add_field(2,'FontTitle',7552) + +IniFile = Table('IniFile') +IniFile.add_field(1,'IniFile',11592) +IniFile.add_field(2,'FileName',4095) +IniFile.add_field(3,'DirProperty',7496) +IniFile.add_field(4,'Section',3936) +IniFile.add_field(5,'Key',3968) +IniFile.add_field(6,'Value',4095) +IniFile.add_field(7,'Action',1282) +IniFile.add_field(8,'Component_',3400) + +IniLocator = Table('IniLocator') +IniLocator.add_field(1,'Signature_',11592) +IniLocator.add_field(2,'FileName',3583) +IniLocator.add_field(3,'Section',3424) +IniLocator.add_field(4,'Key',3456) +IniLocator.add_field(5,'Field',5378) +IniLocator.add_field(6,'Type',5378) + +InstallExecuteSequence = Table('InstallExecuteSequence') +InstallExecuteSequence.add_field(1,'Action',11592) +InstallExecuteSequence.add_field(2,'Condition',7679) +InstallExecuteSequence.add_field(3,'Sequence',5378) + +InstallUISequence = Table('InstallUISequence') +InstallUISequence.add_field(1,'Action',11592) +InstallUISequence.add_field(2,'Condition',7679) +InstallUISequence.add_field(3,'Sequence',5378) + +IsolatedComponent = Table('IsolatedComponent') +IsolatedComponent.add_field(1,'Component_Shared',11592) +IsolatedComponent.add_field(2,'Component_Application',11592) + +LaunchCondition = Table('LaunchCondition') +LaunchCondition.add_field(1,'Condition',11775) +LaunchCondition.add_field(2,'Description',4095) + +ListBox = Table('ListBox') +ListBox.add_field(1,'Property',11592) +ListBox.add_field(2,'Order',9474) +ListBox.add_field(3,'Value',3392) +ListBox.add_field(4,'Text',8000) + +ListView = Table('ListView') +ListView.add_field(1,'Property',11592) +ListView.add_field(2,'Order',9474) +ListView.add_field(3,'Value',3392) +ListView.add_field(4,'Text',8000) +ListView.add_field(5,'Binary_',7496) + +LockPermissions = Table('LockPermissions') +LockPermissions.add_field(1,'LockObject',11592) +LockPermissions.add_field(2,'Table',11552) +LockPermissions.add_field(3,'Domain',15871) +LockPermissions.add_field(4,'User',11775) +LockPermissions.add_field(5,'Permission',4356) + +Media = Table('Media') +Media.add_field(1,'DiskId',9474) +Media.add_field(2,'LastSequence',1282) +Media.add_field(3,'DiskPrompt',8000) +Media.add_field(4,'Cabinet',7679) +Media.add_field(5,'VolumeLabel',7456) +Media.add_field(6,'Source',7496) + +MoveFile = Table('MoveFile') +MoveFile.add_field(1,'FileKey',11592) +MoveFile.add_field(2,'Component_',3400) +MoveFile.add_field(3,'SourceName',8191) +MoveFile.add_field(4,'DestName',8191) +MoveFile.add_field(5,'SourceFolder',7496) +MoveFile.add_field(6,'DestFolder',3400) +MoveFile.add_field(7,'Options',1282) + +MsiAssembly = Table('MsiAssembly') +MsiAssembly.add_field(1,'Component_',11592) +MsiAssembly.add_field(2,'Feature_',3366) +MsiAssembly.add_field(3,'File_Manifest',7496) +MsiAssembly.add_field(4,'File_Application',7496) +MsiAssembly.add_field(5,'Attributes',5378) + +MsiAssemblyName = Table('MsiAssemblyName') +MsiAssemblyName.add_field(1,'Component_',11592) +MsiAssemblyName.add_field(2,'Name',11775) +MsiAssemblyName.add_field(3,'Value',3583) + +MsiDigitalCertificate = Table('MsiDigitalCertificate') +MsiDigitalCertificate.add_field(1,'DigitalCertificate',11592) +MsiDigitalCertificate.add_field(2,'CertData',2304) + +MsiDigitalSignature = Table('MsiDigitalSignature') +MsiDigitalSignature.add_field(1,'Table',11552) +MsiDigitalSignature.add_field(2,'SignObject',11592) +MsiDigitalSignature.add_field(3,'DigitalCertificate_',3400) +MsiDigitalSignature.add_field(4,'Hash',6400) + +MsiFileHash = Table('MsiFileHash') +MsiFileHash.add_field(1,'File_',11592) +MsiFileHash.add_field(2,'Options',1282) +MsiFileHash.add_field(3,'HashPart1',260) +MsiFileHash.add_field(4,'HashPart2',260) +MsiFileHash.add_field(5,'HashPart3',260) +MsiFileHash.add_field(6,'HashPart4',260) + +MsiPatchHeaders = Table('MsiPatchHeaders') +MsiPatchHeaders.add_field(1,'StreamRef',11558) +MsiPatchHeaders.add_field(2,'Header',2304) + +ODBCAttribute = Table('ODBCAttribute') +ODBCAttribute.add_field(1,'Driver_',11592) +ODBCAttribute.add_field(2,'Attribute',11560) +ODBCAttribute.add_field(3,'Value',8191) + +ODBCDriver = Table('ODBCDriver') +ODBCDriver.add_field(1,'Driver',11592) +ODBCDriver.add_field(2,'Component_',3400) +ODBCDriver.add_field(3,'Description',3583) +ODBCDriver.add_field(4,'File_',3400) +ODBCDriver.add_field(5,'File_Setup',7496) + +ODBCDataSource = Table('ODBCDataSource') +ODBCDataSource.add_field(1,'DataSource',11592) +ODBCDataSource.add_field(2,'Component_',3400) +ODBCDataSource.add_field(3,'Description',3583) +ODBCDataSource.add_field(4,'DriverDescription',3583) +ODBCDataSource.add_field(5,'Registration',1282) + +ODBCSourceAttribute = Table('ODBCSourceAttribute') +ODBCSourceAttribute.add_field(1,'DataSource_',11592) +ODBCSourceAttribute.add_field(2,'Attribute',11552) +ODBCSourceAttribute.add_field(3,'Value',8191) + +ODBCTranslator = Table('ODBCTranslator') +ODBCTranslator.add_field(1,'Translator',11592) +ODBCTranslator.add_field(2,'Component_',3400) +ODBCTranslator.add_field(3,'Description',3583) +ODBCTranslator.add_field(4,'File_',3400) +ODBCTranslator.add_field(5,'File_Setup',7496) + +Patch = Table('Patch') +Patch.add_field(1,'File_',11592) +Patch.add_field(2,'Sequence',9474) +Patch.add_field(3,'PatchSize',260) +Patch.add_field(4,'Attributes',1282) +Patch.add_field(5,'Header',6400) +Patch.add_field(6,'StreamRef_',7462) + +PatchPackage = Table('PatchPackage') +PatchPackage.add_field(1,'PatchId',11558) +PatchPackage.add_field(2,'Media_',1282) + +PublishComponent = Table('PublishComponent') +PublishComponent.add_field(1,'ComponentId',11558) +PublishComponent.add_field(2,'Qualifier',11775) +PublishComponent.add_field(3,'Component_',11592) +PublishComponent.add_field(4,'AppData',8191) +PublishComponent.add_field(5,'Feature_',3366) + +RadioButton = Table('RadioButton') +RadioButton.add_field(1,'Property',11592) +RadioButton.add_field(2,'Order',9474) +RadioButton.add_field(3,'Value',3392) +RadioButton.add_field(4,'X',1282) +RadioButton.add_field(5,'Y',1282) +RadioButton.add_field(6,'Width',1282) +RadioButton.add_field(7,'Height',1282) +RadioButton.add_field(8,'Text',8000) +RadioButton.add_field(9,'Help',7986) + +Registry = Table('Registry') +Registry.add_field(1,'Registry',11592) +Registry.add_field(2,'Root',1282) +Registry.add_field(3,'Key',4095) +Registry.add_field(4,'Name',8191) +Registry.add_field(5,'Value',7936) +Registry.add_field(6,'Component_',3400) + +RegLocator = Table('RegLocator') +RegLocator.add_field(1,'Signature_',11592) +RegLocator.add_field(2,'Root',1282) +RegLocator.add_field(3,'Key',3583) +RegLocator.add_field(4,'Name',7679) +RegLocator.add_field(5,'Type',5378) + +RemoveFile = Table('RemoveFile') +RemoveFile.add_field(1,'FileKey',11592) +RemoveFile.add_field(2,'Component_',3400) +RemoveFile.add_field(3,'FileName',8191) +RemoveFile.add_field(4,'DirProperty',3400) +RemoveFile.add_field(5,'InstallMode',1282) + +RemoveIniFile = Table('RemoveIniFile') +RemoveIniFile.add_field(1,'RemoveIniFile',11592) +RemoveIniFile.add_field(2,'FileName',4095) +RemoveIniFile.add_field(3,'DirProperty',7496) +RemoveIniFile.add_field(4,'Section',3936) +RemoveIniFile.add_field(5,'Key',3968) +RemoveIniFile.add_field(6,'Value',8191) +RemoveIniFile.add_field(7,'Action',1282) +RemoveIniFile.add_field(8,'Component_',3400) + +RemoveRegistry = Table('RemoveRegistry') +RemoveRegistry.add_field(1,'RemoveRegistry',11592) +RemoveRegistry.add_field(2,'Root',1282) +RemoveRegistry.add_field(3,'Key',4095) +RemoveRegistry.add_field(4,'Name',8191) +RemoveRegistry.add_field(5,'Component_',3400) + +ReserveCost = Table('ReserveCost') +ReserveCost.add_field(1,'ReserveKey',11592) +ReserveCost.add_field(2,'Component_',3400) +ReserveCost.add_field(3,'ReserveFolder',7496) +ReserveCost.add_field(4,'ReserveLocal',260) +ReserveCost.add_field(5,'ReserveSource',260) + +SelfReg = Table('SelfReg') +SelfReg.add_field(1,'File_',11592) +SelfReg.add_field(2,'Cost',5378) + +ServiceControl = Table('ServiceControl') +ServiceControl.add_field(1,'ServiceControl',11592) +ServiceControl.add_field(2,'Name',4095) +ServiceControl.add_field(3,'Event',1282) +ServiceControl.add_field(4,'Arguments',8191) +ServiceControl.add_field(5,'Wait',5378) +ServiceControl.add_field(6,'Component_',3400) + +ServiceInstall = Table('ServiceInstall') +ServiceInstall.add_field(1,'ServiceInstall',11592) +ServiceInstall.add_field(2,'Name',3583) +ServiceInstall.add_field(3,'DisplayName',8191) +ServiceInstall.add_field(4,'ServiceType',260) +ServiceInstall.add_field(5,'StartType',260) +ServiceInstall.add_field(6,'ErrorControl',260) +ServiceInstall.add_field(7,'LoadOrderGroup',7679) +ServiceInstall.add_field(8,'Dependencies',7679) +ServiceInstall.add_field(9,'StartName',7679) +ServiceInstall.add_field(10,'Password',7679) +ServiceInstall.add_field(11,'Arguments',7679) +ServiceInstall.add_field(12,'Component_',3400) +ServiceInstall.add_field(13,'Description',8191) + +Shortcut = Table('Shortcut') +Shortcut.add_field(1,'Shortcut',11592) +Shortcut.add_field(2,'Directory_',3400) +Shortcut.add_field(3,'Name',3968) +Shortcut.add_field(4,'Component_',3400) +Shortcut.add_field(5,'Target',3400) +Shortcut.add_field(6,'Arguments',7679) +Shortcut.add_field(7,'Description',8191) +Shortcut.add_field(8,'Hotkey',5378) +Shortcut.add_field(9,'Icon_',7496) +Shortcut.add_field(10,'IconIndex',5378) +Shortcut.add_field(11,'ShowCmd',5378) +Shortcut.add_field(12,'WkDir',7496) + +Signature = Table('Signature') +Signature.add_field(1,'Signature',11592) +Signature.add_field(2,'FileName',3583) +Signature.add_field(3,'MinVersion',7444) +Signature.add_field(4,'MaxVersion',7444) +Signature.add_field(5,'MinSize',4356) +Signature.add_field(6,'MaxSize',4356) +Signature.add_field(7,'MinDate',4356) +Signature.add_field(8,'MaxDate',4356) +Signature.add_field(9,'Languages',7679) + +TextStyle = Table('TextStyle') +TextStyle.add_field(1,'TextStyle',11592) +TextStyle.add_field(2,'FaceName',3360) +TextStyle.add_field(3,'Size',1282) +TextStyle.add_field(4,'Color',4356) +TextStyle.add_field(5,'StyleBits',5378) + +TypeLib = Table('TypeLib') +TypeLib.add_field(1,'LibID',11558) +TypeLib.add_field(2,'Language',9474) +TypeLib.add_field(3,'Component_',11592) +TypeLib.add_field(4,'Version',4356) +TypeLib.add_field(5,'Description',8064) +TypeLib.add_field(6,'Directory_',7496) +TypeLib.add_field(7,'Feature_',3366) +TypeLib.add_field(8,'Cost',4356) + +UIText = Table('UIText') +UIText.add_field(1,'Key',11592) +UIText.add_field(2,'Text',8191) + +Upgrade = Table('Upgrade') +Upgrade.add_field(1,'UpgradeCode',11558) +Upgrade.add_field(2,'VersionMin',15636) +Upgrade.add_field(3,'VersionMax',15636) +Upgrade.add_field(4,'Language',15871) +Upgrade.add_field(5,'Attributes',8452) +Upgrade.add_field(6,'Remove',7679) +Upgrade.add_field(7,'ActionProperty',3400) + +Verb = Table('Verb') +Verb.add_field(1,'Extension_',11775) +Verb.add_field(2,'Verb',11552) +Verb.add_field(3,'Sequence',5378) +Verb.add_field(4,'Command',8191) +Verb.add_field(5,'Argument',8191) + +tables=[_Validation, ActionText, AdminExecuteSequence, Condition, AdminUISequence, AdvtExecuteSequence, AdvtUISequence, AppId, AppSearch, Property, BBControl, Billboard, Feature, Binary, BindImage, File, CCPSearch, CheckBox, Class, Component, Icon, ProgId, ComboBox, CompLocator, Complus, Directory, Control, Dialog, ControlCondition, ControlEvent, CreateFolder, CustomAction, DrLocator, DuplicateFile, Environment, Error, EventMapping, Extension, MIME, FeatureComponents, FileSFPCatalog, SFPCatalog, Font, IniFile, IniLocator, InstallExecuteSequence, InstallUISequence, IsolatedComponent, LaunchCondition, ListBox, ListView, LockPermissions, Media, MoveFile, MsiAssembly, MsiAssemblyName, MsiDigitalCertificate, MsiDigitalSignature, MsiFileHash, MsiPatchHeaders, ODBCAttribute, ODBCDriver, ODBCDataSource, ODBCSourceAttribute, ODBCTranslator, Patch, PatchPackage, PublishComponent, RadioButton, Registry, RegLocator, RemoveFile, RemoveIniFile, RemoveRegistry, ReserveCost, SelfReg, ServiceControl, ServiceInstall, Shortcut, Signature, TextStyle, TypeLib, UIText, Upgrade, Verb] + +_Validation_records = [ +(u'_Validation',u'Table',u'N',None, None, None, None, u'Identifier',None, u'Name of table',), +(u'_Validation',u'Column',u'N',None, None, None, None, u'Identifier',None, u'Name of column',), +(u'_Validation',u'Description',u'Y',None, None, None, None, u'Text',None, u'Description of column',), +(u'_Validation',u'Set',u'Y',None, None, None, None, u'Text',None, u'Set of values that are permitted',), +(u'_Validation',u'Category',u'Y',None, None, None, None, None, u'Text;Formatted;Template;Condition;Guid;Path;Version;Language;Identifier;Binary;UpperCase;LowerCase;Filename;Paths;AnyPath;WildCardFilename;RegPath;KeyFormatted;CustomSource;Property;Cabinet;Shortcut;URL',u'String category',), +(u'_Validation',u'KeyColumn',u'Y',1,32,None, None, None, None, u'Column to which foreign key connects',), +(u'_Validation',u'KeyTable',u'Y',None, None, None, None, u'Identifier',None, u'For foreign key, Name of table to which data must link',), +(u'_Validation',u'MaxValue',u'Y',-2147483647,2147483647,None, None, None, None, u'Maximum value allowed',), +(u'_Validation',u'MinValue',u'Y',-2147483647,2147483647,None, None, None, None, u'Minimum value allowed',), +(u'_Validation',u'Nullable',u'N',None, None, None, None, None, u'Y;N;@',u'Whether the column is nullable',), +(u'ActionText',u'Description',u'Y',None, None, None, None, u'Text',None, u'Localized description displayed in progress dialog and log when action is executing.',), +(u'ActionText',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to be described.',), +(u'ActionText',u'Template',u'Y',None, None, None, None, u'Template',None, u'Optional localized format template used to format action data records for display during action execution.',), +(u'AdminExecuteSequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), +(u'AdminExecuteSequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), +(u'AdminExecuteSequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), +(u'Condition',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Expression evaluated to determine if Level in the Feature table is to change.',), +(u'Condition',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Reference to a Feature entry in Feature table.',), +(u'Condition',u'Level',u'N',0,32767,None, None, None, None, u'New selection Level to set in Feature table if Condition evaluates to TRUE.',), +(u'AdminUISequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), +(u'AdminUISequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), +(u'AdminUISequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), +(u'AdvtExecuteSequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), +(u'AdvtExecuteSequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), +(u'AdvtExecuteSequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), +(u'AdvtUISequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), +(u'AdvtUISequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), +(u'AdvtUISequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), +(u'AppId',u'AppId',u'N',None, None, None, None, u'Guid',None, None, ), +(u'AppId',u'ActivateAtStorage',u'Y',0,1,None, None, None, None, None, ), +(u'AppId',u'DllSurrogate',u'Y',None, None, None, None, u'Text',None, None, ), +(u'AppId',u'LocalService',u'Y',None, None, None, None, u'Text',None, None, ), +(u'AppId',u'RemoteServerName',u'Y',None, None, None, None, u'Formatted',None, None, ), +(u'AppId',u'RunAsInteractiveUser',u'Y',0,1,None, None, None, None, None, ), +(u'AppId',u'ServiceParameters',u'Y',None, None, None, None, u'Text',None, None, ), +(u'AppSearch',u'Property',u'N',None, None, None, None, u'Identifier',None, u'The property associated with a Signature',), +(u'AppSearch',u'Signature_',u'N',None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator',1,u'Identifier',None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.',), +(u'Property',u'Property',u'N',None, None, None, None, u'Identifier',None, u'Name of property, uppercase if settable by launcher or loader.',), +(u'Property',u'Value',u'N',None, None, None, None, u'Text',None, u'String value for property. Never null or empty.',), +(u'BBControl',u'Type',u'N',None, None, None, None, u'Identifier',None, u'The type of the control.',), +(u'BBControl',u'Y',u'N',0,32767,None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.',), +(u'BBControl',u'Text',u'Y',None, None, None, None, u'Text',None, u'A string used to set the initial text contained within a control (if appropriate).',), +(u'BBControl',u'BBControl',u'N',None, None, None, None, u'Identifier',None, u'Name of the control. This name must be unique within a billboard, but can repeat on different billboard.',), +(u'BBControl',u'Attributes',u'Y',0,2147483647,None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.',), +(u'BBControl',u'Billboard_',u'N',None, None, u'Billboard',1,u'Identifier',None, u'External key to the Billboard table, name of the billboard.',), +(u'BBControl',u'Height',u'N',0,32767,None, None, None, None, u'Height of the bounding rectangle of the control.',), +(u'BBControl',u'Width',u'N',0,32767,None, None, None, None, u'Width of the bounding rectangle of the control.',), +(u'BBControl',u'X',u'N',0,32767,None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.',), +(u'Billboard',u'Action',u'Y',None, None, None, None, u'Identifier',None, u'The name of an action. The billboard is displayed during the progress messages received from this action.',), +(u'Billboard',u'Billboard',u'N',None, None, None, None, u'Identifier',None, u'Name of the billboard.',), +(u'Billboard',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'An external key to the Feature Table. The billboard is shown only if this feature is being installed.',), +(u'Billboard',u'Ordering',u'Y',0,32767,None, None, None, None, u'A positive integer. If there is more than one billboard corresponding to an action they will be shown in the order defined by this column.',), +(u'Feature',u'Description',u'Y',None, None, None, None, u'Text',None, u'Longer descriptive text describing a visible feature item.',), +(u'Feature',u'Attributes',u'N',None, None, None, None, None, u'0;1;2;4;5;6;8;9;10;16;17;18;20;21;22;24;25;26;32;33;34;36;37;38;48;49;50;52;53;54',u'Feature attributes',), +(u'Feature',u'Feature',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular feature record.',), +(u'Feature',u'Directory_',u'Y',None, None, u'Directory',1,u'UpperCase',None, u'The name of the Directory that can be configured by the UI. A non-null value will enable the browse button.',), +(u'Feature',u'Level',u'N',0,32767,None, None, None, None, u'The install level at which record will be initially selected. An install level of 0 will disable an item and prevent its display.',), +(u'Feature',u'Title',u'Y',None, None, None, None, u'Text',None, u'Short text identifying a visible feature item.',), +(u'Feature',u'Display',u'Y',0,32767,None, None, None, None, u'Numeric sort order, used to force a specific display ordering.',), +(u'Feature',u'Feature_Parent',u'Y',None, None, u'Feature',1,u'Identifier',None, u'Optional key of a parent record in the same table. If the parent is not selected, then the record will not be installed. Null indicates a root item.',), +(u'Binary',u'Name',u'N',None, None, None, None, u'Identifier',None, u'Unique key identifying the binary data.',), +(u'Binary',u'Data',u'N',None, None, None, None, u'Binary',None, u'The unformatted binary data.',), +(u'BindImage',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'The index into the File table. This must be an executable file.',), +(u'BindImage',u'Path',u'Y',None, None, None, None, u'Paths',None, u'A list of ; delimited paths that represent the paths to be searched for the import DLLS. The list is usually a list of properties each enclosed within square brackets [] .',), +(u'File',u'Sequence',u'N',1,32767,None, None, None, None, u'Sequence with respect to the media images; order must track cabinet order.',), +(u'File',u'Attributes',u'Y',0,32767,None, None, None, None, u'Integer containing bit flags representing file attributes (with the decimal value of each bit position in parentheses)',), +(u'File',u'File',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token, must match identifier in cabinet. For uncompressed files, this field is ignored.',), +(u'File',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the file.',), +(u'File',u'FileName',u'N',None, None, None, None, u'Filename',None, u'File name used for installation, may be localized. This may contain a "short name|long name" pair.',), +(u'File',u'FileSize',u'N',0,2147483647,None, None, None, None, u'Size of file in bytes (long integer).',), +(u'File',u'Language',u'Y',None, None, None, None, u'Language',None, u'List of decimal language Ids, comma-separated if more than one.',), +(u'File',u'Version',u'Y',None, None, u'File',1,u'Version',None, u'Version string for versioned files; Blank for unversioned files.',), +(u'CCPSearch',u'Signature_',u'N',None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator',1,u'Identifier',None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.',), +(u'CheckBox',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to the item.',), +(u'CheckBox',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The value string associated with the item.',), +(u'Class',u'Description',u'Y',None, None, None, None, u'Text',None, u'Localized description for the Class.',), +(u'Class',u'Attributes',u'Y',None, 32767,None, None, None, None, u'Class registration attributes.',), +(u'Class',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.',), +(u'Class',u'AppId_',u'Y',None, None, u'AppId',1,u'Guid',None, u'Optional AppID containing DCOM information for associated application (string GUID).',), +(u'Class',u'Argument',u'Y',None, None, None, None, u'Formatted',None, u'optional argument for LocalServers.',), +(u'Class',u'CLSID',u'N',None, None, None, None, u'Guid',None, u'The CLSID of an OLE factory.',), +(u'Class',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.',), +(u'Class',u'Context',u'N',None, None, None, None, u'Identifier',None, u'The numeric server context for this server. CLSCTX_xxxx',), +(u'Class',u'DefInprocHandler',u'Y',None, None, None, None, u'Filename',u'1;2;3',u'Optional default inproc handler. Only optionally provided if Context=CLSCTX_LOCAL_SERVER. Typically "ole32.dll" or "mapi32.dll"',), +(u'Class',u'FileTypeMask',u'Y',None, None, None, None, u'Text',None, u'Optional string containing information for the HKCRthis CLSID) key. If multiple patterns exist, they must be delimited by a semicolon, and numeric subkeys will be generated: 0,1,2...',), +(u'Class',u'Icon_',u'Y',None, None, u'Icon',1,u'Identifier',None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this CLSID. Will be written under the DefaultIcon key.',), +(u'Class',u'IconIndex',u'Y',-32767,32767,None, None, None, None, u'Optional icon index.',), +(u'Class',u'ProgId_Default',u'Y',None, None, u'ProgId',1,u'Text',None, u'Optional ProgId associated with this CLSID.',), +(u'Component',u'Condition',u'Y',None, None, None, None, u'Condition',None, u"A conditional statement that will disable this component if the specified condition evaluates to the 'True' state. If a component is disabled, it will not be installed, regardless of the 'Action' state associated with the component.",), +(u'Component',u'Attributes',u'N',None, None, None, None, None, None, u'Remote execution option, one of irsEnum',), +(u'Component',u'Component',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular component record.',), +(u'Component',u'ComponentId',u'Y',None, None, None, None, u'Guid',None, u'A string GUID unique to this component, version, and language.',), +(u'Component',u'Directory_',u'N',None, None, u'Directory',1,u'Identifier',None, u'Required key of a Directory table record. This is actually a property name whose value contains the actual path, set either by the AppSearch action or with the default setting obtained from the Directory table.',), +(u'Component',u'KeyPath',u'Y',None, None, u'File;Registry;ODBCDataSource',1,u'Identifier',None, u'Either the primary key into the File table, Registry table, or ODBCDataSource table. This extract path is stored when the component is installed, and is used to detect the presence of the component and to return the path to it.',), +(u'Icon',u'Name',u'N',None, None, None, None, u'Identifier',None, u'Primary key. Name of the icon file.',), +(u'Icon',u'Data',u'N',None, None, None, None, u'Binary',None, u'Binary stream. The binary icon data in PE (.DLL or .EXE) or icon (.ICO) format.',), +(u'ProgId',u'Description',u'Y',None, None, None, None, u'Text',None, u'Localized description for the Program identifier.',), +(u'ProgId',u'Icon_',u'Y',None, None, u'Icon',1,u'Identifier',None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this ProgId. Will be written under the DefaultIcon key.',), +(u'ProgId',u'IconIndex',u'Y',-32767,32767,None, None, None, None, u'Optional icon index.',), +(u'ProgId',u'ProgId',u'N',None, None, None, None, u'Text',None, u'The Program Identifier. Primary key.',), +(u'ProgId',u'Class_',u'Y',None, None, u'Class',1,u'Guid',None, u'The CLSID of an OLE factory corresponding to the ProgId.',), +(u'ProgId',u'ProgId_Parent',u'Y',None, None, u'ProgId',1,u'Text',None, u'The Parent Program Identifier. If specified, the ProgId column becomes a version independent prog id.',), +(u'ComboBox',u'Text',u'Y',None, None, None, None, u'Formatted',None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.',), +(u'ComboBox',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this item. All the items tied to the same property become part of the same combobox.',), +(u'ComboBox',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value string associated with this item. Selecting the line will set the associated property to this value.',), +(u'ComboBox',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list.\tThe integers do not have to be consecutive.',), +(u'CompLocator',u'Type',u'Y',0,1,None, None, None, None, u'A boolean value that determines if the registry value is a filename or a directory location.',), +(u'CompLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.',), +(u'CompLocator',u'ComponentId',u'N',None, None, None, None, u'Guid',None, u'A string GUID unique to this component, version, and language.',), +(u'Complus',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the ComPlus component.',), +(u'Complus',u'ExpType',u'Y',0,32767,None, None, None, None, u'ComPlus component attributes.',), +(u'Directory',u'Directory',u'N',None, None, None, None, u'Identifier',None, u'Unique identifier for directory entry, primary key. If a property by this name is defined, it contains the full path to the directory.',), +(u'Directory',u'DefaultDir',u'N',None, None, None, None, u'DefaultDir',None, u"The default sub-path under parent's path.",), +(u'Directory',u'Directory_Parent',u'Y',None, None, u'Directory',1,u'Identifier',None, u'Reference to the entry in this table specifying the default parent directory. A record parented to itself or with a Null parent represents a root of the install tree.',), +(u'Control',u'Type',u'N',None, None, None, None, u'Identifier',None, u'The type of the control.',), +(u'Control',u'Y',u'N',0,32767,None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.',), +(u'Control',u'Text',u'Y',None, None, None, None, u'Formatted',None, u'A string used to set the initial text contained within a control (if appropriate).',), +(u'Control',u'Property',u'Y',None, None, None, None, u'Identifier',None, u'The name of a defined property to be linked to this control. ',), +(u'Control',u'Attributes',u'Y',0,2147483647,None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.',), +(u'Control',u'Height',u'N',0,32767,None, None, None, None, u'Height of the bounding rectangle of the control.',), +(u'Control',u'Width',u'N',0,32767,None, None, None, None, u'Width of the bounding rectangle of the control.',), +(u'Control',u'X',u'N',0,32767,None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.',), +(u'Control',u'Control',u'N',None, None, None, None, u'Identifier',None, u'Name of the control. This name must be unique within a dialog, but can repeat on different dialogs. ',), +(u'Control',u'Control_Next',u'Y',None, None, u'Control',2,u'Identifier',None, u'The name of an other control on the same dialog. This link defines the tab order of the controls. The links have to form one or more cycles!',), +(u'Control',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'External key to the Dialog table, name of the dialog.',), +(u'Control',u'Help',u'Y',None, None, None, None, u'Text',None, u'The help strings used with the button. The text is optional. ',), +(u'Dialog',u'Attributes',u'Y',0,2147483647,None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this dialog.',), +(u'Dialog',u'Height',u'N',0,32767,None, None, None, None, u'Height of the bounding rectangle of the dialog.',), +(u'Dialog',u'Width',u'N',0,32767,None, None, None, None, u'Width of the bounding rectangle of the dialog.',), +(u'Dialog',u'Dialog',u'N',None, None, None, None, u'Identifier',None, u'Name of the dialog.',), +(u'Dialog',u'Control_Cancel',u'Y',None, None, u'Control',2,u'Identifier',None, u'Defines the cancel control. Hitting escape or clicking on the close icon on the dialog is equivalent to pushing this button.',), +(u'Dialog',u'Control_Default',u'Y',None, None, u'Control',2,u'Identifier',None, u'Defines the default control. Hitting return is equivalent to pushing this button.',), +(u'Dialog',u'Control_First',u'N',None, None, u'Control',2,u'Identifier',None, u'Defines the control that has the focus when the dialog is created.',), +(u'Dialog',u'HCentering',u'N',0,100,None, None, None, None, u'Horizontal position of the dialog on a 0-100 scale. 0 means left end, 100 means right end of the screen, 50 center.',), +(u'Dialog',u'Title',u'Y',None, None, None, None, u'Formatted',None, u"A text string specifying the title to be displayed in the title bar of the dialog's window.",), +(u'Dialog',u'VCentering',u'N',0,100,None, None, None, None, u'Vertical position of the dialog on a 0-100 scale. 0 means top end, 100 means bottom end of the screen, 50 center.',), +(u'ControlCondition',u'Action',u'N',None, None, None, None, None, u'Default;Disable;Enable;Hide;Show',u'The desired action to be taken on the specified control.',), +(u'ControlCondition',u'Condition',u'N',None, None, None, None, u'Condition',None, u'A standard conditional statement that specifies under which conditions the action should be triggered.',), +(u'ControlCondition',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'A foreign key to the Dialog table, name of the dialog.',), +(u'ControlCondition',u'Control_',u'N',None, None, u'Control',2,u'Identifier',None, u'A foreign key to the Control table, name of the control.',), +(u'ControlEvent',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'A standard conditional statement that specifies under which conditions an event should be triggered.',), +(u'ControlEvent',u'Ordering',u'Y',0,2147483647,None, None, None, None, u'An integer used to order several events tied to the same control. Can be left blank.',), +(u'ControlEvent',u'Argument',u'N',None, None, None, None, u'Formatted',None, u'A value to be used as a modifier when triggering a particular event.',), +(u'ControlEvent',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'A foreign key to the Dialog table, name of the dialog.',), +(u'ControlEvent',u'Control_',u'N',None, None, u'Control',2,u'Identifier',None, u'A foreign key to the Control table, name of the control',), +(u'ControlEvent',u'Event',u'N',None, None, None, None, u'Formatted',None, u'An identifier that specifies the type of the event that should take place when the user interacts with control specified by the first two entries.',), +(u'CreateFolder',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table.',), +(u'CreateFolder',u'Directory_',u'N',None, None, u'Directory',1,u'Identifier',None, u'Primary key, could be foreign key into the Directory table.',), +(u'CustomAction',u'Type',u'N',1,16383,None, None, None, None, u'The numeric custom action type, consisting of source location, code type, entry, option flags.',), +(u'CustomAction',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Primary key, name of action, normally appears in sequence table unless private use.',), +(u'CustomAction',u'Source',u'Y',None, None, None, None, u'CustomSource',None, u'The table reference of the source of the code.',), +(u'CustomAction',u'Target',u'Y',None, None, None, None, u'Formatted',None, u'Excecution parameter, depends on the type of custom action',), +(u'DrLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature table.',), +(u'DrLocator',u'Path',u'Y',None, None, None, None, u'AnyPath',None, u'The path on the user system. This is a either a subpath below the value of the Parent or a full path. The path may contain properties enclosed within [ ] that will be expanded.',), +(u'DrLocator',u'Depth',u'Y',0,32767,None, None, None, None, u'The depth below the path to which the Signature_ is recursively searched. If absent, the depth is assumed to be 0.',), +(u'DrLocator',u'Parent',u'Y',None, None, None, None, u'Identifier',None, u'The parent file signature. It is also a foreign key in the Signature table. If null and the Path column does not expand to a full path, then all the fixed drives of the user system are searched using the Path.',), +(u'DuplicateFile',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Foreign key referencing the source file to be duplicated.',), +(u'DuplicateFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the duplicate file.',), +(u'DuplicateFile',u'DestFolder',u'Y',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full pathname to a destination folder.',), +(u'DuplicateFile',u'DestName',u'Y',None, None, None, None, u'Filename',None, u'Filename to be given to the duplicate file.',), +(u'DuplicateFile',u'FileKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular file entry',), +(u'Environment',u'Name',u'N',None, None, None, None, u'Text',None, u'The name of the environmental value.',), +(u'Environment',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The value to set in the environmental settings.',), +(u'Environment',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the installing of the environmental value.',), +(u'Environment',u'Environment',u'N',None, None, None, None, u'Identifier',None, u'Unique identifier for the environmental variable setting',), +(u'Error',u'Error',u'N',0,32767,None, None, None, None, u'Integer error number, obtained from header file IError(...) macros.',), +(u'Error',u'Message',u'Y',None, None, None, None, u'Template',None, u'Error formatting template, obtained from user ed. or localizers.',), +(u'EventMapping',u'Dialog_',u'N',None, None, u'Dialog',1,u'Identifier',None, u'A foreign key to the Dialog table, name of the Dialog.',), +(u'EventMapping',u'Control_',u'N',None, None, u'Control',2,u'Identifier',None, u'A foreign key to the Control table, name of the control.',), +(u'EventMapping',u'Event',u'N',None, None, None, None, u'Identifier',None, u'An identifier that specifies the type of the event that the control subscribes to.',), +(u'EventMapping',u'Attribute',u'N',None, None, None, None, u'Identifier',None, u'The name of the control attribute, that is set when this event is received.',), +(u'Extension',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.',), +(u'Extension',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.',), +(u'Extension',u'Extension',u'N',None, None, None, None, u'Text',None, u'The extension associated with the table row.',), +(u'Extension',u'MIME_',u'Y',None, None, u'MIME',1,u'Text',None, u'Optional Context identifier, typically "type/format" associated with the extension',), +(u'Extension',u'ProgId_',u'Y',None, None, u'ProgId',1,u'Text',None, u'Optional ProgId associated with this extension.',), +(u'MIME',u'CLSID',u'Y',None, None, None, None, u'Guid',None, u'Optional associated CLSID.',), +(u'MIME',u'ContentType',u'N',None, None, None, None, u'Text',None, u'Primary key. Context identifier, typically "type/format".',), +(u'MIME',u'Extension_',u'N',None, None, u'Extension',1,u'Text',None, u'Optional associated extension (without dot)',), +(u'FeatureComponents',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Foreign key into Feature table.',), +(u'FeatureComponents',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into Component table.',), +(u'FileSFPCatalog',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'File associated with the catalog',), +(u'FileSFPCatalog',u'SFPCatalog_',u'N',None, None, u'SFPCatalog',1,u'Filename',None, u'Catalog associated with the file',), +(u'SFPCatalog',u'SFPCatalog',u'N',None, None, None, None, u'Filename',None, u'File name for the catalog.',), +(u'SFPCatalog',u'Catalog',u'N',None, None, None, None, u'Binary',None, u'SFP Catalog',), +(u'SFPCatalog',u'Dependency',u'Y',None, None, None, None, u'Formatted',None, u'Parent catalog - only used by SFP',), +(u'Font',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Primary key, foreign key into File table referencing font file.',), +(u'Font',u'FontTitle',u'Y',None, None, None, None, u'Text',None, u'Font name.',), +(u'IniFile',u'Action',u'N',None, None, None, None, None, u'0;1;3',u'The type of modification to be made, one of iifEnum',), +(u'IniFile',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value to be written.',), +(u'IniFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the installing of the .INI value.',), +(u'IniFile',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The .INI file name in which to write the information',), +(u'IniFile',u'IniFile',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), +(u'IniFile',u'DirProperty',u'Y',None, None, None, None, u'Identifier',None, u'Foreign key into the Directory table denoting the directory where the .INI file is.',), +(u'IniFile',u'Key',u'N',None, None, None, None, u'Formatted',None, u'The .INI file key below Section.',), +(u'IniFile',u'Section',u'N',None, None, None, None, u'Formatted',None, u'The .INI file Section.',), +(u'IniLocator',u'Type',u'Y',0,2,None, None, None, None, u'An integer value that determines if the .INI value read is a filename or a directory location or to be used as is w/o interpretation.',), +(u'IniLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.',), +(u'IniLocator',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The .INI file name.',), +(u'IniLocator',u'Key',u'N',None, None, None, None, u'Text',None, u'Key value (followed by an equals sign in INI file).',), +(u'IniLocator',u'Section',u'N',None, None, None, None, u'Text',None, u'Section name within in file (within square brackets in INI file).',), +(u'IniLocator',u'Field',u'Y',0,32767,None, None, None, None, u'The field in the .INI line. If Field is null or 0 the entire line is read.',), +(u'InstallExecuteSequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), +(u'InstallExecuteSequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), +(u'InstallExecuteSequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), +(u'InstallUISequence',u'Action',u'N',None, None, None, None, u'Identifier',None, u'Name of action to invoke, either in the engine or the handler DLL.',), +(u'InstallUISequence',u'Condition',u'Y',None, None, None, None, u'Condition',None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.',), +(u'InstallUISequence',u'Sequence',u'Y',-4,32767,None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.',), +(u'IsolatedComponent',u'Component_Application',u'N',None, None, u'Component',1,u'Identifier',None, u'Key to Component table item for application',), +(u'IsolatedComponent',u'Component_Shared',u'N',None, None, u'Component',1,u'Identifier',None, u'Key to Component table item to be isolated',), +(u'LaunchCondition',u'Description',u'N',None, None, None, None, u'Formatted',None, u'Localizable text to display when condition fails and install must abort.',), +(u'LaunchCondition',u'Condition',u'N',None, None, None, None, u'Condition',None, u'Expression which must evaluate to TRUE in order for install to commence.',), +(u'ListBox',u'Text',u'Y',None, None, None, None, u'Text',None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.',), +(u'ListBox',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listbox.',), +(u'ListBox',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value string associated with this item. Selecting the line will set the associated property to this value.',), +(u'ListBox',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.',), +(u'ListView',u'Text',u'Y',None, None, None, None, u'Text',None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.',), +(u'ListView',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listview.',), +(u'ListView',u'Value',u'N',None, None, None, None, u'Identifier',None, u'The value string associated with this item. Selecting the line will set the associated property to this value.',), +(u'ListView',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.',), +(u'ListView',u'Binary_',u'Y',None, None, u'Binary',1,u'Identifier',None, u'The name of the icon to be displayed with the icon. The binary information is looked up from the Binary Table.',), +(u'LockPermissions',u'Table',u'N',None, None, None, None, u'Identifier',u'Directory;File;Registry',u'Reference to another table name',), +(u'LockPermissions',u'Domain',u'Y',None, None, None, None, u'Formatted',None, u'Domain name for user whose permissions are being set. (usually a property)',), +(u'LockPermissions',u'LockObject',u'N',None, None, None, None, u'Identifier',None, u'Foreign key into Registry or File table',), +(u'LockPermissions',u'Permission',u'Y',-2147483647,2147483647,None, None, None, None, u'Permission Access mask. Full Control = 268435456 (GENERIC_ALL = 0x10000000)',), +(u'LockPermissions',u'User',u'N',None, None, None, None, u'Formatted',None, u'User for permissions to be set. (usually a property)',), +(u'Media',u'Source',u'Y',None, None, None, None, u'Property',None, u'The property defining the location of the cabinet file.',), +(u'Media',u'Cabinet',u'Y',None, None, None, None, u'Cabinet',None, u'If some or all of the files stored on the media are compressed in a cabinet, the name of that cabinet.',), +(u'Media',u'DiskId',u'N',1,32767,None, None, None, None, u'Primary key, integer to determine sort order for table.',), +(u'Media',u'DiskPrompt',u'Y',None, None, None, None, u'Text',None, u'Disk name: the visible text actually printed on the disk. This will be used to prompt the user when this disk needs to be inserted.',), +(u'Media',u'LastSequence',u'N',0,32767,None, None, None, None, u'File sequence number for the last file for this media.',), +(u'Media',u'VolumeLabel',u'Y',None, None, None, None, u'Text',None, u'The label attributed to the volume.',), +(u'ModuleComponents',u'Component',u'N',None, None, u'Component',1,u'Identifier',None, u'Component contained in the module.',), +(u'ModuleComponents',u'Language',u'N',None, None, u'ModuleSignature',2,None, None, u'Default language ID for module (may be changed by transform).',), +(u'ModuleComponents',u'ModuleID',u'N',None, None, u'ModuleSignature',1,u'Identifier',None, u'Module containing the component.',), +(u'ModuleSignature',u'Language',u'N',None, None, None, None, None, None, u'Default decimal language of module.',), +(u'ModuleSignature',u'Version',u'N',None, None, None, None, u'Version',None, u'Version of the module.',), +(u'ModuleSignature',u'ModuleID',u'N',None, None, None, None, u'Identifier',None, u'Module identifier (String.GUID).',), +(u'ModuleDependency',u'ModuleID',u'N',None, None, u'ModuleSignature',1,u'Identifier',None, u'Module requiring the dependency.',), +(u'ModuleDependency',u'ModuleLanguage',u'N',None, None, u'ModuleSignature',2,None, None, u'Language of module requiring the dependency.',), +(u'ModuleDependency',u'RequiredID',u'N',None, None, None, None, None, None, u'String.GUID of required module.',), +(u'ModuleDependency',u'RequiredLanguage',u'N',None, None, None, None, None, None, u'LanguageID of the required module.',), +(u'ModuleDependency',u'RequiredVersion',u'Y',None, None, None, None, u'Version',None, u'Version of the required version.',), +(u'ModuleExclusion',u'ModuleID',u'N',None, None, u'ModuleSignature',1,u'Identifier',None, u'String.GUID of module with exclusion requirement.',), +(u'ModuleExclusion',u'ModuleLanguage',u'N',None, None, u'ModuleSignature',2,None, None, u'LanguageID of module with exclusion requirement.',), +(u'ModuleExclusion',u'ExcludedID',u'N',None, None, None, None, None, None, u'String.GUID of excluded module.',), +(u'ModuleExclusion',u'ExcludedLanguage',u'N',None, None, None, None, None, None, u'Language of excluded module.',), +(u'ModuleExclusion',u'ExcludedMaxVersion',u'Y',None, None, None, None, u'Version',None, u'Maximum version of excluded module.',), +(u'ModuleExclusion',u'ExcludedMinVersion',u'Y',None, None, None, None, u'Version',None, u'Minimum version of excluded module.',), +(u'MoveFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'If this component is not "selected" for installation or removal, no action will be taken on the associated MoveFile entry',), +(u'MoveFile',u'DestFolder',u'N',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory',), +(u'MoveFile',u'DestName',u'Y',None, None, None, None, u'Filename',None, u'Name to be given to the original file after it is moved or copied. If blank, the destination file will be given the same name as the source file',), +(u'MoveFile',u'FileKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key that uniquely identifies a particular MoveFile record',), +(u'MoveFile',u'Options',u'N',0,1,None, None, None, None, u'Integer value specifying the MoveFile operating mode, one of imfoEnum',), +(u'MoveFile',u'SourceFolder',u'Y',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full path to the source directory',), +(u'MoveFile',u'SourceName',u'Y',None, None, None, None, u'Text',None, u"Name of the source file(s) to be moved or copied. Can contain the '*' or '?' wildcards.",), +(u'MsiAssembly',u'Attributes',u'Y',None, None, None, None, None, None, u'Assembly attributes',), +(u'MsiAssembly',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Foreign key into Feature table.',), +(u'MsiAssembly',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into Component table.',), +(u'MsiAssembly',u'File_Application',u'Y',None, None, u'File',1,u'Identifier',None, u'Foreign key into File table, denoting the application context for private assemblies. Null for global assemblies.',), +(u'MsiAssembly',u'File_Manifest',u'Y',None, None, u'File',1,u'Identifier',None, u'Foreign key into the File table denoting the manifest file for the assembly.',), +(u'MsiAssemblyName',u'Name',u'N',None, None, None, None, u'Text',None, u'The name part of the name-value pairs for the assembly name.',), +(u'MsiAssemblyName',u'Value',u'N',None, None, None, None, u'Text',None, u'The value part of the name-value pairs for the assembly name.',), +(u'MsiAssemblyName',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into Component table.',), +(u'MsiDigitalCertificate',u'CertData',u'N',None, None, None, None, u'Binary',None, u'A certificate context blob for a signer certificate',), +(u'MsiDigitalCertificate',u'DigitalCertificate',u'N',None, None, None, None, u'Identifier',None, u'A unique identifier for the row',), +(u'MsiDigitalSignature',u'Table',u'N',None, None, None, None, None, u'Media',u'Reference to another table name (only Media table is supported)',), +(u'MsiDigitalSignature',u'DigitalCertificate_',u'N',None, None, u'MsiDigitalCertificate',1,u'Identifier',None, u'Foreign key to MsiDigitalCertificate table identifying the signer certificate',), +(u'MsiDigitalSignature',u'Hash',u'Y',None, None, None, None, u'Binary',None, u'The encoded hash blob from the digital signature',), +(u'MsiDigitalSignature',u'SignObject',u'N',None, None, None, None, u'Text',None, u'Foreign key to Media table',), +(u'MsiFileHash',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Primary key, foreign key into File table referencing file with this hash',), +(u'MsiFileHash',u'Options',u'N',0,32767,None, None, None, None, u'Various options and attributes for this hash.',), +(u'MsiFileHash',u'HashPart1',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), +(u'MsiFileHash',u'HashPart2',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), +(u'MsiFileHash',u'HashPart3',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), +(u'MsiFileHash',u'HashPart4',u'N',None, None, None, None, None, None, u'Size of file in bytes (long integer).',), +(u'MsiPatchHeaders',u'StreamRef',u'N',None, None, None, None, u'Identifier',None, u'Primary key. A unique identifier for the row.',), +(u'MsiPatchHeaders',u'Header',u'N',None, None, None, None, u'Binary',None, u'Binary stream. The patch header, used for patch validation.',), +(u'ODBCAttribute',u'Value',u'Y',None, None, None, None, u'Text',None, u'Value for ODBC driver attribute',), +(u'ODBCAttribute',u'Attribute',u'N',None, None, None, None, u'Text',None, u'Name of ODBC driver attribute',), +(u'ODBCAttribute',u'Driver_',u'N',None, None, u'ODBCDriver',1,u'Identifier',None, u'Reference to ODBC driver in ODBCDriver table',), +(u'ODBCDriver',u'Description',u'N',None, None, None, None, u'Text',None, u'Text used as registered name for driver, non-localized',), +(u'ODBCDriver',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Reference to key driver file',), +(u'ODBCDriver',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reference to associated component',), +(u'ODBCDriver',u'Driver',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized.internal token for driver',), +(u'ODBCDriver',u'File_Setup',u'Y',None, None, u'File',1,u'Identifier',None, u'Optional reference to key driver setup DLL',), +(u'ODBCDataSource',u'Description',u'N',None, None, None, None, u'Text',None, u'Text used as registered name for data source',), +(u'ODBCDataSource',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reference to associated component',), +(u'ODBCDataSource',u'DataSource',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized.internal token for data source',), +(u'ODBCDataSource',u'DriverDescription',u'N',None, None, None, None, u'Text',None, u'Reference to driver description, may be existing driver',), +(u'ODBCDataSource',u'Registration',u'N',0,1,None, None, None, None, u'Registration option: 0=machine, 1=user, others t.b.d.',), +(u'ODBCSourceAttribute',u'Value',u'Y',None, None, None, None, u'Text',None, u'Value for ODBC data source attribute',), +(u'ODBCSourceAttribute',u'Attribute',u'N',None, None, None, None, u'Text',None, u'Name of ODBC data source attribute',), +(u'ODBCSourceAttribute',u'DataSource_',u'N',None, None, u'ODBCDataSource',1,u'Identifier',None, u'Reference to ODBC data source in ODBCDataSource table',), +(u'ODBCTranslator',u'Description',u'N',None, None, None, None, u'Text',None, u'Text used as registered name for translator',), +(u'ODBCTranslator',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Reference to key translator file',), +(u'ODBCTranslator',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reference to associated component',), +(u'ODBCTranslator',u'File_Setup',u'Y',None, None, u'File',1,u'Identifier',None, u'Optional reference to key translator setup DLL',), +(u'ODBCTranslator',u'Translator',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized.internal token for translator',), +(u'Patch',u'Sequence',u'N',0,32767,None, None, None, None, u'Primary key, sequence with respect to the media images; order must track cabinet order.',), +(u'Patch',u'Attributes',u'N',0,32767,None, None, None, None, u'Integer containing bit flags representing patch attributes',), +(u'Patch',u'File_',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token, foreign key to File table, must match identifier in cabinet.',), +(u'Patch',u'Header',u'Y',None, None, None, None, u'Binary',None, u'Binary stream. The patch header, used for patch validation.',), +(u'Patch',u'PatchSize',u'N',0,2147483647,None, None, None, None, u'Size of patch in bytes (long integer).',), +(u'Patch',u'StreamRef_',u'Y',None, None, None, None, u'Identifier',None, u'Identifier. Foreign key to the StreamRef column of the MsiPatchHeaders table.',), +(u'PatchPackage',u'Media_',u'N',0,32767,None, None, None, None, u'Foreign key to DiskId column of Media table. Indicates the disk containing the patch package.',), +(u'PatchPackage',u'PatchId',u'N',None, None, None, None, u'Guid',None, u'A unique string GUID representing this patch.',), +(u'PublishComponent',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Foreign key into the Feature table.',), +(u'PublishComponent',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table.',), +(u'PublishComponent',u'ComponentId',u'N',None, None, None, None, u'Guid',None, u'A string GUID that represents the component id that will be requested by the alien product.',), +(u'PublishComponent',u'AppData',u'Y',None, None, None, None, u'Text',None, u'This is localisable Application specific data that can be associated with a Qualified Component.',), +(u'PublishComponent',u'Qualifier',u'N',None, None, None, None, u'Text',None, u'This is defined only when the ComponentId column is an Qualified Component Id. This is the Qualifier for ProvideComponentIndirect.',), +(u'RadioButton',u'Y',u'N',0,32767,None, None, None, None, u'The vertical coordinate of the upper left corner of the bounding rectangle of the radio button.',), +(u'RadioButton',u'Text',u'Y',None, None, None, None, u'Text',None, u'The visible title to be assigned to the radio button.',), +(u'RadioButton',u'Property',u'N',None, None, None, None, u'Identifier',None, u'A named property to be tied to this radio button. All the buttons tied to the same property become part of the same group.',), +(u'RadioButton',u'Height',u'N',0,32767,None, None, None, None, u'The height of the button.',), +(u'RadioButton',u'Width',u'N',0,32767,None, None, None, None, u'The width of the button.',), +(u'RadioButton',u'X',u'N',0,32767,None, None, None, None, u'The horizontal coordinate of the upper left corner of the bounding rectangle of the radio button.',), +(u'RadioButton',u'Value',u'N',None, None, None, None, u'Formatted',None, u'The value string associated with this button. Selecting the button will set the associated property to this value.',), +(u'RadioButton',u'Order',u'N',1,32767,None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.',), +(u'RadioButton',u'Help',u'Y',None, None, None, None, u'Text',None, u'The help strings used with the button. The text is optional.',), +(u'Registry',u'Name',u'Y',None, None, None, None, u'Formatted',None, u'The registry value name.',), +(u'Registry',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The registry value.',), +(u'Registry',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the installing of the registry value.',), +(u'Registry',u'Key',u'N',None, None, None, None, u'RegPath',None, u'The key for the registry value.',), +(u'Registry',u'Registry',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), +(u'Registry',u'Root',u'N',-1,3,None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.',), +(u'RegLocator',u'Name',u'Y',None, None, None, None, u'Formatted',None, u'The registry value name.',), +(u'RegLocator',u'Type',u'Y',0,18,None, None, None, None, u'An integer value that determines if the registry value is a filename or a directory location or to be used as is w/o interpretation.',), +(u'RegLocator',u'Signature_',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table. If the type is 0, the registry values refers a directory, and _Signature is not a foreign key.',), +(u'RegLocator',u'Key',u'N',None, None, None, None, u'RegPath',None, u'The key for the registry value.',), +(u'RegLocator',u'Root',u'N',0,3,None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.',), +(u'RemoveFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key referencing Component that controls the file to be removed.',), +(u'RemoveFile',u'FileKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key used to identify a particular file entry',), +(u'RemoveFile',u'FileName',u'Y',None, None, None, None, u'WildCardFilename',None, u'Name of the file to be removed.',), +(u'RemoveFile',u'DirProperty',u'N',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full pathname to the folder of the file to be removed.',), +(u'RemoveFile',u'InstallMode',u'N',None, None, None, None, None, u'1;2;3',u'Installation option, one of iimEnum.',), +(u'RemoveIniFile',u'Action',u'N',None, None, None, None, None, u'2;4',u'The type of modification to be made, one of iifEnum.',), +(u'RemoveIniFile',u'Value',u'Y',None, None, None, None, u'Formatted',None, u'The value to be deleted. The value is required when Action is iifIniRemoveTag',), +(u'RemoveIniFile',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the deletion of the .INI value.',), +(u'RemoveIniFile',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The .INI file name in which to delete the information',), +(u'RemoveIniFile',u'DirProperty',u'Y',None, None, None, None, u'Identifier',None, u'Foreign key into the Directory table denoting the directory where the .INI file is.',), +(u'RemoveIniFile',u'Key',u'N',None, None, None, None, u'Formatted',None, u'The .INI file key below Section.',), +(u'RemoveIniFile',u'Section',u'N',None, None, None, None, u'Formatted',None, u'The .INI file Section.',), +(u'RemoveIniFile',u'RemoveIniFile',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), +(u'RemoveRegistry',u'Name',u'Y',None, None, None, None, u'Formatted',None, u'The registry value name.',), +(u'RemoveRegistry',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table referencing component that controls the deletion of the registry value.',), +(u'RemoveRegistry',u'Key',u'N',None, None, None, None, u'RegPath',None, u'The key for the registry value.',), +(u'RemoveRegistry',u'Root',u'N',-1,3,None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum',), +(u'RemoveRegistry',u'RemoveRegistry',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), +(u'ReserveCost',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Reserve a specified amount of space if this component is to be installed.',), +(u'ReserveCost',u'ReserveFolder',u'Y',None, None, None, None, u'Identifier',None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory',), +(u'ReserveCost',u'ReserveKey',u'N',None, None, None, None, u'Identifier',None, u'Primary key that uniquely identifies a particular ReserveCost record',), +(u'ReserveCost',u'ReserveLocal',u'N',0,2147483647,None, None, None, None, u'Disk space to reserve if linked component is installed locally.',), +(u'ReserveCost',u'ReserveSource',u'N',0,2147483647,None, None, None, None, u'Disk space to reserve if linked component is installed to run from the source location.',), +(u'SelfReg',u'File_',u'N',None, None, u'File',1,u'Identifier',None, u'Foreign key into the File table denoting the module that needs to be registered.',), +(u'SelfReg',u'Cost',u'Y',0,32767,None, None, None, None, u'The cost of registering the module.',), +(u'ServiceControl',u'Name',u'N',None, None, None, None, u'Formatted',None, u'Name of a service. /, \\, comma and space are invalid',), +(u'ServiceControl',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table that controls the startup of the service',), +(u'ServiceControl',u'Event',u'N',0,187,None, None, None, None, u'Bit field: Install: 0x1 = Start, 0x2 = Stop, 0x8 = Delete, Uninstall: 0x10 = Start, 0x20 = Stop, 0x80 = Delete',), +(u'ServiceControl',u'ServiceControl',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), +(u'ServiceControl',u'Arguments',u'Y',None, None, None, None, u'Formatted',None, u'Arguments for the service. Separate by [~].',), +(u'ServiceControl',u'Wait',u'Y',0,1,None, None, None, None, u'Boolean for whether to wait for the service to fully start',), +(u'ServiceInstall',u'Name',u'N',None, None, None, None, u'Formatted',None, u'Internal Name of the Service',), +(u'ServiceInstall',u'Description',u'Y',None, None, None, None, u'Text',None, u'Description of service.',), +(u'ServiceInstall',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table that controls the startup of the service',), +(u'ServiceInstall',u'Arguments',u'Y',None, None, None, None, u'Formatted',None, u'Arguments to include in every start of the service, passed to WinMain',), +(u'ServiceInstall',u'ServiceInstall',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), +(u'ServiceInstall',u'Dependencies',u'Y',None, None, None, None, u'Formatted',None, u'Other services this depends on to start. Separate by [~], and end with [~][~]',), +(u'ServiceInstall',u'DisplayName',u'Y',None, None, None, None, u'Formatted',None, u'External Name of the Service',), +(u'ServiceInstall',u'ErrorControl',u'N',-2147483647,2147483647,None, None, None, None, u'Severity of error if service fails to start',), +(u'ServiceInstall',u'LoadOrderGroup',u'Y',None, None, None, None, u'Formatted',None, u'LoadOrderGroup',), +(u'ServiceInstall',u'Password',u'Y',None, None, None, None, u'Formatted',None, u'password to run service with. (with StartName)',), +(u'ServiceInstall',u'ServiceType',u'N',-2147483647,2147483647,None, None, None, None, u'Type of the service',), +(u'ServiceInstall',u'StartName',u'Y',None, None, None, None, u'Formatted',None, u'User or object name to run service as',), +(u'ServiceInstall',u'StartType',u'N',0,4,None, None, None, None, u'Type of the service',), +(u'Shortcut',u'Name',u'N',None, None, None, None, u'Filename',None, u'The name of the shortcut to be created.',), +(u'Shortcut',u'Description',u'Y',None, None, None, None, u'Text',None, u'The description for the shortcut.',), +(u'Shortcut',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Foreign key into the Component table denoting the component whose selection gates the the shortcut creation/deletion.',), +(u'Shortcut',u'Icon_',u'Y',None, None, u'Icon',1,u'Identifier',None, u'Foreign key into the File table denoting the external icon file for the shortcut.',), +(u'Shortcut',u'IconIndex',u'Y',-32767,32767,None, None, None, None, u'The icon index for the shortcut.',), +(u'Shortcut',u'Directory_',u'N',None, None, u'Directory',1,u'Identifier',None, u'Foreign key into the Directory table denoting the directory where the shortcut file is created.',), +(u'Shortcut',u'Target',u'N',None, None, None, None, u'Shortcut',None, u'The shortcut target. This is usually a property that is expanded to a file or a folder that the shortcut points to.',), +(u'Shortcut',u'Arguments',u'Y',None, None, None, None, u'Formatted',None, u'The command-line arguments for the shortcut.',), +(u'Shortcut',u'Shortcut',u'N',None, None, None, None, u'Identifier',None, u'Primary key, non-localized token.',), +(u'Shortcut',u'Hotkey',u'Y',0,32767,None, None, None, None, u'The hotkey for the shortcut. It has the virtual-key code for the key in the low-order byte, and the modifier flags in the high-order byte. ',), +(u'Shortcut',u'ShowCmd',u'Y',None, None, None, None, None, u'1;3;7',u'The show command for the application window.The following values may be used.',), +(u'Shortcut',u'WkDir',u'Y',None, None, None, None, u'Identifier',None, u'Name of property defining location of working directory.',), +(u'Signature',u'FileName',u'N',None, None, None, None, u'Filename',None, u'The name of the file. This may contain a "short name|long name" pair.',), +(u'Signature',u'Signature',u'N',None, None, None, None, u'Identifier',None, u'The table key. The Signature represents a unique file signature.',), +(u'Signature',u'Languages',u'Y',None, None, None, None, u'Language',None, u'The languages supported by the file.',), +(u'Signature',u'MaxDate',u'Y',0,2147483647,None, None, None, None, u'The maximum creation date of the file.',), +(u'Signature',u'MaxSize',u'Y',0,2147483647,None, None, None, None, u'The maximum size of the file. ',), +(u'Signature',u'MaxVersion',u'Y',None, None, None, None, u'Text',None, u'The maximum version of the file.',), +(u'Signature',u'MinDate',u'Y',0,2147483647,None, None, None, None, u'The minimum creation date of the file.',), +(u'Signature',u'MinSize',u'Y',0,2147483647,None, None, None, None, u'The minimum size of the file.',), +(u'Signature',u'MinVersion',u'Y',None, None, None, None, u'Text',None, u'The minimum version of the file.',), +(u'TextStyle',u'TextStyle',u'N',None, None, None, None, u'Identifier',None, u'Name of the style. The primary key of this table. This name is embedded in the texts to indicate a style change.',), +(u'TextStyle',u'Color',u'Y',0,16777215,None, None, None, None, u'A long integer indicating the color of the string in the RGB format (Red, Green, Blue each 0-255, RGB = R + 256*G + 256^2*B).',), +(u'TextStyle',u'FaceName',u'N',None, None, None, None, u'Text',None, u'A string indicating the name of the font used. Required. The string must be at most 31 characters long.',), +(u'TextStyle',u'Size',u'N',0,32767,None, None, None, None, u'The size of the font used. This size is given in our units (1/12 of the system font height). Assuming that the system font is set to 12 point size, this is equivalent to the point size.',), +(u'TextStyle',u'StyleBits',u'Y',0,15,None, None, None, None, u'A combination of style bits.',), +(u'TypeLib',u'Description',u'Y',None, None, None, None, u'Text',None, None, ), +(u'TypeLib',u'Feature_',u'N',None, None, u'Feature',1,u'Identifier',None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the type library to be operational.',), +(u'TypeLib',u'Component_',u'N',None, None, u'Component',1,u'Identifier',None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.',), +(u'TypeLib',u'Directory_',u'Y',None, None, u'Directory',1,u'Identifier',None, u'Optional. The foreign key into the Directory table denoting the path to the help file for the type library.',), +(u'TypeLib',u'Language',u'N',0,32767,None, None, None, None, u'The language of the library.',), +(u'TypeLib',u'Version',u'Y',0,16777215,None, None, None, None, u'The version of the library. The minor version is in the lower 8 bits of the integer. The major version is in the next 16 bits. ',), +(u'TypeLib',u'Cost',u'Y',0,2147483647,None, None, None, None, u'The cost associated with the registration of the typelib. This column is currently optional.',), +(u'TypeLib',u'LibID',u'N',None, None, None, None, u'Guid',None, u'The GUID that represents the library.',), +(u'UIText',u'Text',u'Y',None, None, None, None, u'Text',None, u'The localized version of the string.',), +(u'UIText',u'Key',u'N',None, None, None, None, u'Identifier',None, u'A unique key that identifies the particular string.',), +(u'Upgrade',u'Attributes',u'N',0,2147483647,None, None, None, None, u'The attributes of this product set.',), +(u'Upgrade',u'Language',u'Y',None, None, None, None, u'Language',None, u'A comma-separated list of languages for either products in this set or products not in this set.',), +(u'Upgrade',u'ActionProperty',u'N',None, None, None, None, u'UpperCase',None, u'The property to set when a product in this set is found.',), +(u'Upgrade',u'Remove',u'Y',None, None, None, None, u'Formatted',None, u'The list of features to remove when uninstalling a product from this set. The default is "ALL".',), +(u'Upgrade',u'UpgradeCode',u'N',None, None, None, None, u'Guid',None, u'The UpgradeCode GUID belonging to the products in this set.',), +(u'Upgrade',u'VersionMax',u'Y',None, None, None, None, u'Text',None, u'The maximum ProductVersion of the products in this set. The set may or may not include products with this particular version.',), +(u'Upgrade',u'VersionMin',u'Y',None, None, None, None, u'Text',None, u'The minimum ProductVersion of the products in this set. The set may or may not include products with this particular version.',), +(u'Verb',u'Sequence',u'Y',0,32767,None, None, None, None, u'Order within the verbs for a particular extension. Also used simply to specify the default verb.',), +(u'Verb',u'Argument',u'Y',None, None, None, None, u'Formatted',None, u'Optional value for the command arguments.',), +(u'Verb',u'Extension_',u'N',None, None, u'Extension',1,u'Text',None, u'The extension associated with the table row.',), +(u'Verb',u'Verb',u'N',None, None, None, None, u'Text',None, u'The verb for the command.',), +(u'Verb',u'Command',u'Y',None, None, None, None, u'Formatted',None, u'The command text.',), +] diff --git a/sys/src/cmd/python/Tools/msi/sequence.py b/sys/src/cmd/python/Tools/msi/sequence.py new file mode 100644 index 000000000..1138f7a23 --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/sequence.py @@ -0,0 +1,126 @@ +AdminExecuteSequence = [ +(u'InstallInitialize', None, 1500), +(u'InstallFinalize', None, 6600), +(u'InstallFiles', None, 4000), +(u'InstallAdminPackage', None, 3900), +(u'FileCost', None, 900), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'InstallValidate', None, 1400), +] + +AdminUISequence = [ +(u'FileCost', None, 900), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'ExecuteAction', None, 1300), +(u'ExitDialog', None, -1), +(u'FatalError', None, -3), +(u'UserExit', None, -2), +] + +AdvtExecuteSequence = [ +(u'InstallInitialize', None, 1500), +(u'InstallFinalize', None, 6600), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'InstallValidate', None, 1400), +(u'CreateShortcuts', None, 4500), +(u'MsiPublishAssemblies', None, 6250), +(u'PublishComponents', None, 6200), +(u'PublishFeatures', None, 6300), +(u'PublishProduct', None, 6400), +(u'RegisterClassInfo', None, 4600), +(u'RegisterExtensionInfo', None, 4700), +(u'RegisterMIMEInfo', None, 4900), +(u'RegisterProgIdInfo', None, 4800), +] + +InstallExecuteSequence = [ +(u'InstallInitialize', None, 1500), +(u'InstallFinalize', None, 6600), +(u'InstallFiles', None, 4000), +(u'FileCost', None, 900), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'InstallValidate', None, 1400), +(u'CreateShortcuts', None, 4500), +(u'MsiPublishAssemblies', None, 6250), +(u'PublishComponents', None, 6200), +(u'PublishFeatures', None, 6300), +(u'PublishProduct', None, 6400), +(u'RegisterClassInfo', None, 4600), +(u'RegisterExtensionInfo', None, 4700), +(u'RegisterMIMEInfo', None, 4900), +(u'RegisterProgIdInfo', None, 4800), +(u'AllocateRegistrySpace', u'NOT Installed', 1550), +(u'AppSearch', None, 400), +(u'BindImage', None, 4300), +(u'CCPSearch', u'NOT Installed', 500), +(u'CreateFolders', None, 3700), +(u'DeleteServices', u'VersionNT', 2000), +(u'DuplicateFiles', None, 4210), +(u'FindRelatedProducts', None, 200), +(u'InstallODBC', None, 5400), +(u'InstallServices', u'VersionNT', 5800), +(u'IsolateComponents', None, 950), +(u'LaunchConditions', None, 100), +(u'MigrateFeatureStates', None, 1200), +(u'MoveFiles', None, 3800), +(u'PatchFiles', None, 4090), +(u'ProcessComponents', None, 1600), +(u'RegisterComPlus', None, 5700), +(u'RegisterFonts', None, 5300), +(u'RegisterProduct', None, 6100), +(u'RegisterTypeLibraries', None, 5500), +(u'RegisterUser', None, 6000), +(u'RemoveDuplicateFiles', None, 3400), +(u'RemoveEnvironmentStrings', None, 3300), +(u'RemoveExistingProducts', None, 6700), +(u'RemoveFiles', None, 3500), +(u'RemoveFolders', None, 3600), +(u'RemoveIniValues', None, 3100), +(u'RemoveODBC', None, 2400), +(u'RemoveRegistryValues', None, 2600), +(u'RemoveShortcuts', None, 3200), +(u'RMCCPSearch', u'NOT Installed', 600), +(u'SelfRegModules', None, 5600), +(u'SelfUnregModules', None, 2200), +(u'SetODBCFolders', None, 1100), +(u'StartServices', u'VersionNT', 5900), +(u'StopServices', u'VersionNT', 1900), +(u'MsiUnpublishAssemblies', None, 1750), +(u'UnpublishComponents', None, 1700), +(u'UnpublishFeatures', None, 1800), +(u'UnregisterClassInfo', None, 2700), +(u'UnregisterComPlus', None, 2100), +(u'UnregisterExtensionInfo', None, 2800), +(u'UnregisterFonts', None, 2500), +(u'UnregisterMIMEInfo', None, 3000), +(u'UnregisterProgIdInfo', None, 2900), +(u'UnregisterTypeLibraries', None, 2300), +(u'ValidateProductID', None, 700), +(u'WriteEnvironmentStrings', None, 5200), +(u'WriteIniValues', None, 5100), +(u'WriteRegistryValues', None, 5000), +] + +InstallUISequence = [ +(u'FileCost', None, 900), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'ExecuteAction', None, 1300), +(u'ExitDialog', None, -1), +(u'FatalError', None, -3), +(u'UserExit', None, -2), +(u'AppSearch', None, 400), +(u'CCPSearch', u'NOT Installed', 500), +(u'FindRelatedProducts', None, 200), +(u'IsolateComponents', None, 950), +(u'LaunchConditions', None, 100), +(u'MigrateFeatureStates', None, 1200), +(u'RMCCPSearch', u'NOT Installed', 600), +(u'ValidateProductID', None, 700), +] + +tables=['AdminExecuteSequence', 'AdminUISequence', 'AdvtExecuteSequence', 'InstallExecuteSequence', 'InstallUISequence'] diff --git a/sys/src/cmd/python/Tools/msi/uisample.py b/sys/src/cmd/python/Tools/msi/uisample.py new file mode 100644 index 000000000..2bdf59e10 --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/uisample.py @@ -0,0 +1,1400 @@ + +import msilib,os;dirname=os.path.dirname(__file__) +AdminExecuteSequence = [ +(u'InstallValidate', None, 1400), +(u'InstallInitialize', None, 1500), +(u'InstallFinalize', None, 6600), +(u'InstallFiles', None, 4000), +(u'InstallAdminPackage', None, 3900), +(u'FileCost', None, 900), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +] + +AdminUISequence = [ +(u'AdminWelcomeDlg', None, 1230), +(u'FileCost', None, 900), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'ExecuteAction', None, 1300), +(u'ExitDialog', None, -1), +(u'FatalError', None, -3), +(u'PrepareDlg', None, 140), +(u'ProgressDlg', None, 1280), +(u'UserExit', None, -2), +] + +AdvtExecuteSequence = [ +(u'InstallValidate', None, 1400), +(u'InstallInitialize', None, 1500), +(u'InstallFinalize', None, 6600), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'CreateShortcuts', None, 4500), +(u'PublishComponents', None, 6200), +(u'PublishFeatures', None, 6300), +(u'PublishProduct', None, 6400), +(u'RegisterClassInfo', None, 4600), +(u'RegisterExtensionInfo', None, 4700), +(u'RegisterMIMEInfo', None, 4900), +(u'RegisterProgIdInfo', None, 4800), +] + +BBControl = [ +] + +Billboard = [ +] + +Binary = [ +(u'bannrbmp', msilib.Binary(os.path.join(dirname,"bannrbmp.bin"))), +(u'completi', msilib.Binary(os.path.join(dirname,"completi.bin"))), +(u'custicon', msilib.Binary(os.path.join(dirname,"custicon.bin"))), +(u'dlgbmp', msilib.Binary(os.path.join(dirname,"dlgbmp.bin"))), +(u'exclamic', msilib.Binary(os.path.join(dirname,"exclamic.bin"))), +(u'info', msilib.Binary(os.path.join(dirname,"info.bin"))), +(u'insticon', msilib.Binary(os.path.join(dirname,"insticon.bin"))), +(u'New', msilib.Binary(os.path.join(dirname,"New.bin"))), +(u'removico', msilib.Binary(os.path.join(dirname,"removico.bin"))), +(u'repairic', msilib.Binary(os.path.join(dirname,"repairic.bin"))), +(u'Up', msilib.Binary(os.path.join(dirname,"Up.bin"))), +] + +CheckBox = [ +] + +Property = [ +(u'BannerBitmap', u'bannrbmp'), +(u'IAgree', u'No'), +(u'ProductID', u'none'), +(u'ARPHELPLINK', u'http://www.microsoft.com/management'), +(u'ButtonText_Back', u'< &Back'), +(u'ButtonText_Browse', u'Br&owse'), +(u'ButtonText_Cancel', u'Cancel'), +(u'ButtonText_Exit', u'&Exit'), +(u'ButtonText_Finish', u'&Finish'), +(u'ButtonText_Ignore', u'&Ignore'), +(u'ButtonText_Install', u'&Install'), +(u'ButtonText_Next', u'&Next >'), +(u'ButtonText_No', u'&No'), +(u'ButtonText_OK', u'OK'), +(u'ButtonText_Remove', u'&Remove'), +(u'ButtonText_Repair', u'&Repair'), +(u'ButtonText_Reset', u'&Reset'), +(u'ButtonText_Resume', u'&Resume'), +(u'ButtonText_Retry', u'&Retry'), +(u'ButtonText_Return', u'&Return'), +(u'ButtonText_Yes', u'&Yes'), +(u'CompleteSetupIcon', u'completi'), +(u'ComponentDownload', u'ftp://anonymous@microsoft.com/components/'), +(u'CustomSetupIcon', u'custicon'), +(u'DefaultUIFont', u'DlgFont8'), +(u'DialogBitmap', u'dlgbmp'), +(u'DlgTitleFont', u'{&DlgFontBold8}'), +(u'ErrorDialog', u'ErrorDlg'), +(u'ExclamationIcon', u'exclamic'), +(u'InfoIcon', u'info'), +(u'InstallerIcon', u'insticon'), +(u'INSTALLLEVEL', u'3'), +(u'InstallMode', u'Typical'), +(u'PIDTemplate', u'12345<###-%%%%%%%>@@@@@'), +#(u'ProductLanguage', u'1033'), +(u'Progress1', u'Installing'), +(u'Progress2', u'installs'), +(u'PROMPTROLLBACKCOST', u'P'), +(u'RemoveIcon', u'removico'), +(u'RepairIcon', u'repairic'), +(u'Setup', u'Setup'), +(u'ShowUserRegistrationDlg', u'1'), +(u'Wizard', u'Setup Wizard'), +] + +ComboBox = [ +] + +Control = [ +(u'AdminWelcomeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), +(u'AdminWelcomeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'AdminWelcomeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'AdminWelcomeDlg', u'Description', u'Text', 135, 70, 220, 30, 196611, None, u'The [Wizard] will create a server image of [ProductName], at a specified network location. Click Next to continue or Cancel to exit the [Wizard].', None, None), +(u'AdminWelcomeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), +(u'AdminWelcomeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), +(u'AdminWelcomeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +(u'ExitDialog', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), +(u'ExitDialog', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'ExitDialog', u'Cancel', u'PushButton', 304, 243, 56, 17, 1, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'ExitDialog', u'Description', u'Text', 135, 70, 220, 20, 196611, None, u'Click the Finish button to exit the [Wizard].', None, None), +(u'ExitDialog', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Completing the [ProductName] [Wizard]', None, None), +(u'ExitDialog', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Finish', None), +(u'ExitDialog', u'Finish', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Finish]', u'Cancel', None), +(u'FatalError', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), +(u'FatalError', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'FatalError', u'Cancel', u'PushButton', 304, 243, 56, 17, 1, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'FatalError', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}[ProductName] [Wizard] ended prematurely', None, None), +(u'FatalError', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Finish', None), +(u'FatalError', u'Finish', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Finish]', u'Cancel', None), +(u'FatalError', u'Description1', u'Text', 135, 70, 220, 40, 196611, None, u'[ProductName] setup ended prematurely because of an error. Your system has not been modified. To install this program at a later time, please run the installation again.', None, None), +(u'FatalError', u'Description2', u'Text', 135, 115, 220, 20, 196611, None, u'Click the Finish button to exit the [Wizard].', None, None), +(u'PrepareDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Cancel', None), +(u'PrepareDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'PrepareDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'PrepareDlg', u'Description', u'Text', 135, 70, 220, 20, 196611, None, u'Please wait while the [Wizard] prepares to guide you through the installation.', None, None), +(u'PrepareDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), +(u'PrepareDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', None, None), +(u'PrepareDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', None, None), +(u'PrepareDlg', u'ActionData', u'Text', 135, 125, 220, 30, 196611, None, None, None, None), +(u'PrepareDlg', u'ActionText', u'Text', 135, 100, 220, 20, 196611, None, None, None, None), +(u'ProgressDlg', u'Text', u'Text', 35, 65, 300, 20, 3, None, u'Please wait while the [Wizard] [Progress2] [ProductName]. This may take several minutes.', None, None), +(u'ProgressDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), +(u'ProgressDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'ProgressDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'ProgressDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'ProgressDlg', u'Title', u'Text', 20, 15, 200, 15, 196611, None, u'[DlgTitleFont][Progress1] [ProductName]', None, None), +(u'ProgressDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), +(u'ProgressDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', u'Cancel', None), +(u'ProgressDlg', u'ActionText', u'Text', 70, 100, 265, 10, 3, None, None, None, None), +(u'ProgressDlg', u'ProgressBar', u'ProgressBar', 35, 115, 300, 10, 65537, None, u'Progress done', None, None), +(u'ProgressDlg', u'StatusLabel', u'Text', 35, 100, 35, 10, 3, None, u'Status:', None, None), +(u'UserExit', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), +(u'UserExit', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'UserExit', u'Cancel', u'PushButton', 304, 243, 56, 17, 1, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'UserExit', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}[ProductName] [Wizard] was interrupted', None, None), +(u'UserExit', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Finish', None), +(u'UserExit', u'Finish', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Finish]', u'Cancel', None), +(u'UserExit', u'Description1', u'Text', 135, 70, 220, 40, 196611, None, u'[ProductName] setup was interrupted. Your system has not been modified. To install this program at a later time, please run the installation again.', None, None), +(u'UserExit', u'Description2', u'Text', 135, 115, 220, 20, 196611, None, u'Click the Finish button to exit the [Wizard].', None, None), +(u'AdminBrowseDlg', u'Up', u'PushButton', 298, 55, 19, 19, 3670019, None, u'Up', u'NewFolder', u'Up One Level|'), +(u'AdminBrowseDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'PathEdit', None), +(u'AdminBrowseDlg', u'PathEdit', u'PathEdit', 84, 202, 261, 17, 3, u'TARGETDIR', None, u'OK', None), +(u'AdminBrowseDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'AdminBrowseDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'AdminBrowseDlg', u'Cancel', u'PushButton', 240, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'ComboLabel', None), +(u'AdminBrowseDlg', u'ComboLabel', u'Text', 25, 58, 44, 10, 3, None, u'&Look in:', u'DirectoryCombo', None), +(u'AdminBrowseDlg', u'DirectoryCombo', u'DirectoryCombo', 70, 55, 220, 80, 458755, u'TARGETDIR', None, u'Up', None), +(u'AdminBrowseDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Browse to the destination folder', None, None), +(u'AdminBrowseDlg', u'DirectoryList', u'DirectoryList', 25, 83, 320, 110, 7, u'TARGETDIR', None, u'PathLabel', None), +(u'AdminBrowseDlg', u'PathLabel', u'Text', 25, 205, 59, 10, 3, None, u'&Folder name:', u'BannerBitmap', None), +(u'AdminBrowseDlg', u'NewFolder', u'PushButton', 325, 55, 19, 19, 3670019, None, u'New', u'DirectoryList', u'Create A New Folder|'), +(u'AdminBrowseDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'Cancel', None), +(u'AdminBrowseDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Change current destination folder', None, None), +(u'AdminInstallPointDlg', u'Text', u'Text', 25, 80, 320, 10, 3, None, u'&Enter a new network location or click Browse to browse to one.', u'PathEdit', None), +(u'AdminInstallPointDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Text', None), +(u'AdminInstallPointDlg', u'PathEdit', u'PathEdit', 25, 93, 320, 18, 3, u'TARGETDIR', None, u'Browse', None), +(u'AdminInstallPointDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'AdminInstallPointDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'AdminInstallPointDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'AdminInstallPointDlg', u'Description', u'Text', 25, 20, 280, 20, 196611, None, u'Please specify a network location for the server image of [ProductName] product', None, None), +(u'AdminInstallPointDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Network Location', None, None), +(u'AdminInstallPointDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), +(u'AdminInstallPointDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +(u'AdminInstallPointDlg', u'Browse', u'PushButton', 289, 119, 56, 17, 3, None, u'[ButtonText_Browse]', u'Back', None), +(u'AdminRegistrationDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'OrganizationLabel', None), +(u'AdminRegistrationDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'AdminRegistrationDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'AdminRegistrationDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'AdminRegistrationDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Please enter your company information', None, None), +(u'AdminRegistrationDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Company Information', None, None), +(u'AdminRegistrationDlg', u'Back', u'PushButton', 180, 243, 56, 17, 65539, None, u'[ButtonText_Back]', u'Next', None), +(u'AdminRegistrationDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +(u'AdminRegistrationDlg', u'OrganizationLabel', u'Text', 45, 71, 285, 30, 3, None, u'&Please enter the name of your organization in the box below. This will be used as default company name for subsequent installations of [ProductName]:', u'OrganizationEdit', None), +(u'AdminRegistrationDlg', u'CDKeyEdit', u'MaskedEdit', 45, 143, 250, 16, 3, u'PIDKEY', u'[PIDTemplate]', u'Back', None), +(u'AdminRegistrationDlg', u'CDKeyLabel', u'Text', 45, 130, 50, 10, 3, None, u'CD &Key:', u'CDKeyEdit', None), +(u'AdminRegistrationDlg', u'OrganizationEdit', u'Edit', 45, 105, 220, 18, 3, u'COMPANYNAME', u'{80}', u'CDKeyLabel', None), +(u'BrowseDlg', u'Up', u'PushButton', 298, 55, 19, 19, 3670019, None, u'Up', u'NewFolder', u'Up One Level|'), +(u'BrowseDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'PathEdit', None), +(u'BrowseDlg', u'PathEdit', u'PathEdit', 84, 202, 261, 18, 11, u'_BrowseProperty', None, u'OK', None), +(u'BrowseDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'BrowseDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'BrowseDlg', u'Cancel', u'PushButton', 240, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'ComboLabel', None), +(u'BrowseDlg', u'ComboLabel', u'Text', 25, 58, 44, 10, 3, None, u'&Look in:', u'DirectoryCombo', None), +(u'BrowseDlg', u'DirectoryCombo', u'DirectoryCombo', 70, 55, 220, 80, 393227, u'_BrowseProperty', None, u'Up', None), +(u'BrowseDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Browse to the destination folder', None, None), +(u'BrowseDlg', u'DirectoryList', u'DirectoryList', 25, 83, 320, 110, 15, u'_BrowseProperty', None, u'PathLabel', None), +(u'BrowseDlg', u'PathLabel', u'Text', 25, 205, 59, 10, 3, None, u'&Folder name:', u'BannerBitmap', None), +(u'BrowseDlg', u'NewFolder', u'PushButton', 325, 55, 19, 19, 3670019, None, u'New', u'DirectoryList', u'Create A New Folder|'), +(u'BrowseDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'Cancel', None), +(u'BrowseDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Change current destination folder', None, None), +(u'CancelDlg', u'Text', u'Text', 48, 15, 194, 30, 3, None, u'Are you sure you want to cancel [ProductName] installation?', None, None), +(u'CancelDlg', u'Icon', u'Icon', 15, 15, 24, 24, 5242881, None, u'[InfoIcon]', None, u'Information icon|'), +(u'CancelDlg', u'No', u'PushButton', 132, 57, 56, 17, 3, None, u'[ButtonText_No]', u'Yes', None), +(u'CancelDlg', u'Yes', u'PushButton', 72, 57, 56, 17, 3, None, u'[ButtonText_Yes]', u'No', None), +(u'CustomizeDlg', u'Text', u'Text', 25, 55, 320, 20, 3, None, u'Click on the icons in the tree below to change the way features will be installed.', None, None), +(u'CustomizeDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Tree', None), +(u'CustomizeDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'CustomizeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'CustomizeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'CustomizeDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Select the way you want features to be installed.', None, None), +(u'CustomizeDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Custom Setup', None, None), +(u'CustomizeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), +(u'CustomizeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +(u'CustomizeDlg', u'Browse', u'PushButton', 304, 200, 56, 17, 3, None, u'[ButtonText_Browse]', u'Reset', None), +(u'CustomizeDlg', u'Tree', u'SelectionTree', 25, 85, 175, 95, 7, u'_BrowseProperty', u'Tree of selections', u'Browse', None), +(u'CustomizeDlg', u'Box', u'GroupBox', 210, 81, 140, 98, 1, None, None, None, None), +(u'CustomizeDlg', u'Reset', u'PushButton', 42, 243, 56, 17, 3, None, u'[ButtonText_Reset]', u'DiskCost', None), +(u'CustomizeDlg', u'DiskCost', u'PushButton', 111, 243, 56, 17, 3, None, u'Disk &Usage', u'Back', None), +(u'CustomizeDlg', u'ItemDescription', u'Text', 215, 90, 131, 30, 3, None, u'Multiline description of the currently selected item.', None, None), +(u'CustomizeDlg', u'ItemSize', u'Text', 215, 130, 131, 45, 3, None, u'The size of the currently selected item.', None, None), +(u'CustomizeDlg', u'Location', u'Text', 75, 200, 215, 20, 3, None, u"<The selection's path>", None, None), +(u'CustomizeDlg', u'LocationLabel', u'Text', 25, 200, 50, 10, 3, None, u'Location:', None, None), +(u'DiskCostDlg', u'Text', u'Text', 20, 53, 330, 40, 3, None, u'The highlighted volumes (if any) do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).', None, None), +(u'DiskCostDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'OK', None), +(u'DiskCostDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'DiskCostDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'DiskCostDlg', u'Description', u'Text', 20, 20, 280, 20, 196611, None, u'The disk space required for the installation of the selected features.', None, None), +(u'DiskCostDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'BannerBitmap', None), +(u'DiskCostDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Disk Space Requirements', None, None), +(u'DiskCostDlg', u'VolumeList', u'VolumeCostList', 20, 100, 330, 120, 393223, None, u'{120}{70}{70}{70}{70}', None, None), +(u'ErrorDlg', u'Y', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Yes]', None, None), +(u'ErrorDlg', u'A', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Cancel]', None, None), +(u'ErrorDlg', u'C', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Cancel]', None, None), +(u'ErrorDlg', u'ErrorIcon', u'Icon', 15, 15, 24, 24, 5242881, None, u'[InfoIcon]', None, u'Information icon|'), +(u'ErrorDlg', u'ErrorText', u'Text', 48, 15, 205, 60, 3, None, u'Information text', None, None), +(u'ErrorDlg', u'I', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Ignore]', None, None), +(u'ErrorDlg', u'N', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_No]', None, None), +(u'ErrorDlg', u'O', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_OK]', None, None), +(u'ErrorDlg', u'R', u'PushButton', 100, 80, 56, 17, 3, None, u'[ButtonText_Retry]', None, None), +(u'FilesInUse', u'Text', u'Text', 20, 55, 330, 30, 3, None, u'The following applications are using files that need to be updated by this setup. Close these applications and then click Retry to continue the installation or Cancel to exit it.', None, None), +(u'FilesInUse', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Retry', None), +(u'FilesInUse', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'FilesInUse', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'FilesInUse', u'Description', u'Text', 20, 23, 280, 20, 196611, None, u'Some files that need to be updated are currently in use.', None, None), +(u'FilesInUse', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Files in Use', None, None), +(u'FilesInUse', u'Retry', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Retry]', u'Ignore', None), +(u'FilesInUse', u'Exit', u'PushButton', 166, 243, 56, 17, 3, None, u'[ButtonText_Exit]', u'BannerBitmap', None), +(u'FilesInUse', u'Ignore', u'PushButton', 235, 243, 56, 17, 3, None, u'[ButtonText_Ignore]', u'Exit', None), +(u'FilesInUse', u'List', u'ListBox', 20, 87, 330, 130, 7, u'FileInUseProcess', None, None, None), +(u'LicenseAgreementDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'AgreementText', None), +(u'LicenseAgreementDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'LicenseAgreementDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'LicenseAgreementDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'LicenseAgreementDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Please read the following license agreement carefully', None, None), +(u'LicenseAgreementDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]End-User License Agreement', None, None), +(u'LicenseAgreementDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), +(u'LicenseAgreementDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +(u'LicenseAgreementDlg', u'AgreementText', u'ScrollableText', 20, 60, 330, 120, 7, None, u'{\\rtf1\\ansi\\ansicpg1252\\deff0\\deftab720{\\fonttbl{\\f0\\froman\\fprq2 Times New Roman;}}{\\colortbl\\red0\\green0\\blue0;} \\deflang1033\\horzdoc{\\*\\fchars }{\\*\\lchars }\\pard\\plain\\f0\\fs20 <Your license agreement should go here.>\\par }', u'Buttons', None), +(u'LicenseAgreementDlg', u'Buttons', u'RadioButtonGroup', 20, 187, 330, 40, 3, u'IAgree', None, u'Back', None), +(u'MaintenanceTypeDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'ChangeLabel', None), +(u'MaintenanceTypeDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'MaintenanceTypeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'MaintenanceTypeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'MaintenanceTypeDlg', u'Description', u'Text', 25, 23, 280, 20, 196611, None, u'Select the operation you wish to perform.', None, None), +(u'MaintenanceTypeDlg', u'Title', u'Text', 15, 6, 240, 15, 196611, None, u'[DlgTitleFont]Modify, Repair or Remove installation', None, None), +(u'MaintenanceTypeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), +(u'MaintenanceTypeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', u'Cancel', None), +(u'MaintenanceTypeDlg', u'ChangeLabel', u'Text', 105, 65, 100, 10, 3, None, u'[DlgTitleFont]&Modify', u'ChangeButton', None), +(u'MaintenanceTypeDlg', u'ChangeButton', u'PushButton', 50, 65, 38, 38, 5767171, None, u'[CustomSetupIcon]', u'RepairLabel', u'Modify Installation|'), +(u'MaintenanceTypeDlg', u'RepairLabel', u'Text', 105, 114, 100, 10, 3, None, u'[DlgTitleFont]Re&pair', u'RepairButton', None), +(u'MaintenanceTypeDlg', u'ChangeText', u'Text', 105, 78, 230, 20, 3, None, u'Allows users to change the way features are installed.', None, None), +(u'MaintenanceTypeDlg', u'RemoveButton', u'PushButton', 50, 163, 38, 38, 5767171, None, u'[RemoveIcon]', u'Back', u'Remove Installation|'), +(u'MaintenanceTypeDlg', u'RemoveLabel', u'Text', 105, 163, 100, 10, 3, None, u'[DlgTitleFont]&Remove', u'RemoveButton', None), +(u'MaintenanceTypeDlg', u'RemoveText', u'Text', 105, 176, 230, 20, 3, None, u'Removes [ProductName] from your computer.', None, None), +(u'MaintenanceTypeDlg', u'RepairButton', u'PushButton', 50, 114, 38, 38, 5767171, None, u'[RepairIcon]', u'RemoveLabel', u'Repair Installation|'), +(u'MaintenanceTypeDlg', u'RepairText', u'Text', 105, 127, 230, 30, 3, None, u'Repairs errors in the most recent installation state - fixes missing or corrupt files, shortcuts and registry entries.', None, None), +(u'MaintenanceWelcomeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), +(u'MaintenanceWelcomeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'MaintenanceWelcomeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'MaintenanceWelcomeDlg', u'Description', u'Text', 135, 70, 220, 60, 196611, None, u'The [Wizard] will allow you to change the way [ProductName] features are installed on your computer or even to remove [ProductName] from your computer. Click Next to continue or Cancel to exit the [Wizard].', None, None), +(u'MaintenanceWelcomeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), +(u'MaintenanceWelcomeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), +(u'MaintenanceWelcomeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +(u'OutOfDiskDlg', u'Text', u'Text', 20, 53, 330, 40, 3, None, u'The highlighted volumes do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).', None, None), +(u'OutOfDiskDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'OK', None), +(u'OutOfDiskDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'OutOfDiskDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'OutOfDiskDlg', u'Description', u'Text', 20, 20, 280, 20, 196611, None, u'Disk space required for the installation exceeds available disk space.', None, None), +(u'OutOfDiskDlg', u'OK', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_OK]', u'BannerBitmap', None), +(u'OutOfDiskDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Out of Disk Space', None, None), +(u'OutOfDiskDlg', u'VolumeList', u'VolumeCostList', 20, 100, 330, 120, 393223, None, u'{120}{70}{70}{70}{70}', None, None), +(u'OutOfRbDiskDlg', u'Text', u'Text', 20, 53, 330, 40, 3, None, u'The highlighted volumes do not have enough disk space available for the currently selected features. You can either remove some files from the highlighted volumes, or choose to install less features onto local drive(s), or select different destination drive(s).', None, None), +(u'OutOfRbDiskDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'No', None), +(u'OutOfRbDiskDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'OutOfRbDiskDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'OutOfRbDiskDlg', u'Description', u'Text', 20, 20, 280, 20, 196611, None, u'Disk space required for the installation exceeds available disk space.', None, None), +(u'OutOfRbDiskDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Out of Disk Space', None, None), +(u'OutOfRbDiskDlg', u'No', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_No]', u'Yes', None), +(u'OutOfRbDiskDlg', u'Yes', u'PushButton', 240, 243, 56, 17, 3, None, u'[ButtonText_Yes]', u'BannerBitmap', None), +(u'OutOfRbDiskDlg', u'VolumeList', u'VolumeCostList', 20, 140, 330, 80, 4587527, None, u'{120}{70}{70}{70}{70}', None, None), +(u'OutOfRbDiskDlg', u'Text2', u'Text', 20, 94, 330, 40, 3, None, u"Alternatively, you may choose to disable the installer's rollback functionality. This allows the installer to restore your computer's original state should the installation be interrupted in any way. Click Yes if you wish to take the risk to disable rollback.", None, None), +(u'ResumeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), +(u'ResumeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'ResumeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'ResumeDlg', u'Description', u'Text', 135, 70, 220, 30, 196611, None, u'The [Wizard] will complete the installation of [ProductName] on your computer. Click Install to continue or Cancel to exit the [Wizard].', None, None), +(u'ResumeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Resuming the [ProductName] [Wizard]', None, None), +(u'ResumeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Install', None), +(u'ResumeDlg', u'Install', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Install]', u'Cancel', None), +(u'SetupTypeDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'TypicalLabel', None), +(u'SetupTypeDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'SetupTypeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'SetupTypeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'SetupTypeDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Choose the setup type that best suits your needs', None, None), +(u'SetupTypeDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Choose Setup Type', None, None), +(u'SetupTypeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), +(u'SetupTypeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 1, None, u'[ButtonText_Next]', u'Cancel', None), +(u'SetupTypeDlg', u'TypicalLabel', u'Text', 105, 65, 100, 10, 3, None, u'[DlgTitleFont]&Typical', u'TypicalButton', None), +(u'SetupTypeDlg', u'CompleteButton', u'PushButton', 50, 171, 38, 38, 5767171, None, u'[CompleteSetupIcon]', u'Back', u'Complete Installation|'), +(u'SetupTypeDlg', u'CompleteLabel', u'Text', 105, 171, 100, 10, 3, None, u'[DlgTitleFont]C&omplete', u'CompleteButton', None), +(u'SetupTypeDlg', u'CompleteText', u'Text', 105, 184, 230, 20, 3, None, u'All program features will be installed. (Requires most disk space)', None, None), +(u'SetupTypeDlg', u'CustomButton', u'PushButton', 50, 118, 38, 38, 5767171, None, u'[CustomSetupIcon]', u'CompleteLabel', u'Custom Installation|'), +(u'SetupTypeDlg', u'CustomLabel', u'Text', 105, 118, 100, 10, 3, None, u'[DlgTitleFont]C&ustom', u'CustomButton', None), +(u'SetupTypeDlg', u'CustomText', u'Text', 105, 131, 230, 30, 3, None, u'Allows users to choose which program features will be installed and where they will be installed. Recommended for advanced users.', None, None), +(u'SetupTypeDlg', u'TypicalButton', u'PushButton', 50, 65, 38, 38, 5767171, None, u'[InstallerIcon]', u'CustomLabel', u'Typical Installation|'), +(u'SetupTypeDlg', u'TypicalText', u'Text', 105, 78, 230, 20, 3, None, u'Installs the most common program features. Recommended for most users.', None, None), +(u'UserRegistrationDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'NameLabel', None), +(u'UserRegistrationDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'UserRegistrationDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'UserRegistrationDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'UserRegistrationDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'Please enter your customer information', None, None), +(u'UserRegistrationDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Customer Information', None, None), +(u'UserRegistrationDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Next', None), +(u'UserRegistrationDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +(u'UserRegistrationDlg', u'OrganizationLabel', u'Text', 45, 110, 100, 15, 3, None, u'&Organization:', u'OrganizationEdit', None), +(u'UserRegistrationDlg', u'CDKeyEdit', u'MaskedEdit', 45, 159, 250, 16, 3, u'PIDKEY', u'[PIDTemplate]', u'Back', None), +(u'UserRegistrationDlg', u'CDKeyLabel', u'Text', 45, 147, 50, 10, 3, None, u'CD &Key:', u'CDKeyEdit', None), +(u'UserRegistrationDlg', u'OrganizationEdit', u'Edit', 45, 122, 220, 18, 3, u'COMPANYNAME', u'{80}', u'CDKeyLabel', None), +(u'UserRegistrationDlg', u'NameLabel', u'Text', 45, 73, 100, 15, 3, None, u'&User Name:', u'NameEdit', None), +(u'UserRegistrationDlg', u'NameEdit', u'Edit', 45, 85, 220, 18, 3, u'USERNAME', u'{80}', u'OrganizationLabel', None), +(u'VerifyReadyDlg', u'Text', u'Text', 25, 70, 320, 20, 3, None, u'Click Install to begin the installation. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.', None, None), +(u'VerifyReadyDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), +(u'VerifyReadyDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'VerifyReadyDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'VerifyReadyDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'VerifyReadyDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'The [Wizard] is ready to begin the [InstallMode] installation', None, None), +(u'VerifyReadyDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Ready to Install', None, None), +(u'VerifyReadyDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Install', None), +(u'VerifyReadyDlg', u'Install', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Install]', u'Cancel', None), +(u'VerifyRemoveDlg', u'Text', u'Text', 25, 70, 320, 30, 3, None, u'Click Remove to remove [ProductName] from your computer. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.', None, None), +(u'VerifyRemoveDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), +(u'VerifyRemoveDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'VerifyRemoveDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'VerifyRemoveDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'VerifyRemoveDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'You have chosen to remove the program from your computer.', None, None), +(u'VerifyRemoveDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Remove [ProductName]', None, None), +(u'VerifyRemoveDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Remove', None), +(u'VerifyRemoveDlg', u'Remove', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Remove]', u'Cancel', None), +(u'VerifyRepairDlg', u'Text', u'Text', 25, 70, 320, 30, 3, None, u'Click Repair to repair the installation of [ProductName]. If you want to review or change any of your installation settings, click Back. Click Cancel to exit the wizard.', None, None), +(u'VerifyRepairDlg', u'BannerBitmap', u'Bitmap', 0, 0, 374, 44, 1, None, u'[BannerBitmap]', u'Back', None), +(u'VerifyRepairDlg', u'BannerLine', u'Line', 0, 44, 374, 0, 1, None, None, None, None), +(u'VerifyRepairDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'VerifyRepairDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'BannerBitmap', None), +(u'VerifyRepairDlg', u'Description', u'Text', 25, 23, 280, 15, 196611, None, u'The [Wizard] is ready to begin the repair of [ProductName].', None, None), +(u'VerifyRepairDlg', u'Title', u'Text', 15, 6, 200, 15, 196611, None, u'[DlgTitleFont]Repair [ProductName]', None, None), +(u'VerifyRepairDlg', u'Back', u'PushButton', 180, 243, 56, 17, 3, None, u'[ButtonText_Back]', u'Repair', None), +(u'VerifyRepairDlg', u'Repair', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Repair]', u'Cancel', None), +(u'WaitForCostingDlg', u'Text', u'Text', 48, 15, 194, 30, 3, None, u'Please wait while the installer finishes determining your disk space requirements.', None, None), +(u'WaitForCostingDlg', u'Icon', u'Icon', 15, 15, 24, 24, 5242881, None, u'[ExclamationIcon]', None, u'Exclamation icon|'), +(u'WaitForCostingDlg', u'Return', u'PushButton', 102, 57, 56, 17, 3, None, u'[ButtonText_Return]', None, None), +(u'WelcomeDlg', u'Bitmap', u'Bitmap', 0, 0, 370, 234, 1, None, u'[DialogBitmap]', u'Back', None), +(u'WelcomeDlg', u'BottomLine', u'Line', 0, 234, 374, 0, 1, None, None, None, None), +(u'WelcomeDlg', u'Cancel', u'PushButton', 304, 243, 56, 17, 3, None, u'[ButtonText_Cancel]', u'Bitmap', None), +(u'WelcomeDlg', u'Description', u'Text', 135, 70, 220, 30, 196611, None, u'The [Wizard] will install [ProductName] on your computer. Click Next to continue or Cancel to exit the [Wizard].', None, None), +(u'WelcomeDlg', u'Title', u'Text', 135, 20, 220, 60, 196611, None, u'{\\VerdanaBold13}Welcome to the [ProductName] [Wizard]', None, None), +(u'WelcomeDlg', u'Back', u'PushButton', 180, 243, 56, 17, 1, None, u'[ButtonText_Back]', u'Next', None), +(u'WelcomeDlg', u'Next', u'PushButton', 236, 243, 56, 17, 3, None, u'[ButtonText_Next]', u'Cancel', None), +] + +ListBox = [ +] + +ActionText = [ +(u'InstallValidate', u'Validating install', None), +(u'InstallFiles', u'Copying new files', u'File: [1], Directory: [9], Size: [6]'), +(u'InstallAdminPackage', u'Copying network install files', u'File: [1], Directory: [9], Size: [6]'), +(u'FileCost', u'Computing space requirements', None), +(u'CostInitialize', u'Computing space requirements', None), +(u'CostFinalize', u'Computing space requirements', None), +(u'CreateShortcuts', u'Creating shortcuts', u'Shortcut: [1]'), +(u'PublishComponents', u'Publishing Qualified Components', u'Component ID: [1], Qualifier: [2]'), +(u'PublishFeatures', u'Publishing Product Features', u'Feature: [1]'), +(u'PublishProduct', u'Publishing product information', None), +(u'RegisterClassInfo', u'Registering Class servers', u'Class Id: [1]'), +(u'RegisterExtensionInfo', u'Registering extension servers', u'Extension: [1]'), +(u'RegisterMIMEInfo', u'Registering MIME info', u'MIME Content Type: [1], Extension: [2]'), +(u'RegisterProgIdInfo', u'Registering program identifiers', u'ProgId: [1]'), +(u'AllocateRegistrySpace', u'Allocating registry space', u'Free space: [1]'), +(u'AppSearch', u'Searching for installed applications', u'Property: [1], Signature: [2]'), +(u'BindImage', u'Binding executables', u'File: [1]'), +(u'CCPSearch', u'Searching for qualifying products', None), +(u'CreateFolders', u'Creating folders', u'Folder: [1]'), +(u'DeleteServices', u'Deleting services', u'Service: [1]'), +(u'DuplicateFiles', u'Creating duplicate files', u'File: [1], Directory: [9], Size: [6]'), +(u'FindRelatedProducts', u'Searching for related applications', u'Found application: [1]'), +(u'InstallODBC', u'Installing ODBC components', None), +(u'InstallServices', u'Installing new services', u'Service: [2]'), +(u'LaunchConditions', u'Evaluating launch conditions', None), +(u'MigrateFeatureStates', u'Migrating feature states from related applications', u'Application: [1]'), +(u'MoveFiles', u'Moving files', u'File: [1], Directory: [9], Size: [6]'), +(u'PatchFiles', u'Patching files', u'File: [1], Directory: [2], Size: [3]'), +(u'ProcessComponents', u'Updating component registration', None), +(u'RegisterComPlus', u'Registering COM+ Applications and Components', u'AppId: [1]{{, AppType: [2], Users: [3], RSN: [4]}}'), +(u'RegisterFonts', u'Registering fonts', u'Font: [1]'), +(u'RegisterProduct', u'Registering product', u'[1]'), +(u'RegisterTypeLibraries', u'Registering type libraries', u'LibID: [1]'), +(u'RegisterUser', u'Registering user', u'[1]'), +(u'RemoveDuplicateFiles', u'Removing duplicated files', u'File: [1], Directory: [9]'), +(u'RemoveEnvironmentStrings', u'Updating environment strings', u'Name: [1], Value: [2], Action [3]'), +(u'RemoveExistingProducts', u'Removing applications', u'Application: [1], Command line: [2]'), +(u'RemoveFiles', u'Removing files', u'File: [1], Directory: [9]'), +(u'RemoveFolders', u'Removing folders', u'Folder: [1]'), +(u'RemoveIniValues', u'Removing INI files entries', u'File: [1], Section: [2], Key: [3], Value: [4]'), +(u'RemoveODBC', u'Removing ODBC components', None), +(u'RemoveRegistryValues', u'Removing system registry values', u'Key: [1], Name: [2]'), +(u'RemoveShortcuts', u'Removing shortcuts', u'Shortcut: [1]'), +(u'RMCCPSearch', u'Searching for qualifying products', None), +(u'SelfRegModules', u'Registering modules', u'File: [1], Folder: [2]'), +(u'SelfUnregModules', u'Unregistering modules', u'File: [1], Folder: [2]'), +(u'SetODBCFolders', u'Initializing ODBC directories', None), +(u'StartServices', u'Starting services', u'Service: [1]'), +(u'StopServices', u'Stopping services', u'Service: [1]'), +(u'UnpublishComponents', u'Unpublishing Qualified Components', u'Component ID: [1], Qualifier: [2]'), +(u'UnpublishFeatures', u'Unpublishing Product Features', u'Feature: [1]'), +(u'UnregisterClassInfo', u'Unregister Class servers', u'Class Id: [1]'), +(u'UnregisterComPlus', u'Unregistering COM+ Applications and Components', u'AppId: [1]{{, AppType: [2]}}'), +(u'UnregisterExtensionInfo', u'Unregistering extension servers', u'Extension: [1]'), +(u'UnregisterFonts', u'Unregistering fonts', u'Font: [1]'), +(u'UnregisterMIMEInfo', u'Unregistering MIME info', u'MIME Content Type: [1], Extension: [2]'), +(u'UnregisterProgIdInfo', u'Unregistering program identifiers', u'ProgId: [1]'), +(u'UnregisterTypeLibraries', u'Unregistering type libraries', u'LibID: [1]'), +(u'WriteEnvironmentStrings', u'Updating environment strings', u'Name: [1], Value: [2], Action [3]'), +(u'WriteIniValues', u'Writing INI files values', u'File: [1], Section: [2], Key: [3], Value: [4]'), +(u'WriteRegistryValues', u'Writing system registry values', u'Key: [1], Name: [2], Value: [3]'), +(u'Advertise', u'Advertising application', None), +(u'GenerateScript', u'Generating script operations for action:', u'[1]'), +(u'InstallSFPCatalogFile', u'Installing system catalog', u'File: [1], Dependencies: [2]'), +(u'MsiPublishAssemblies', u'Publishing assembly information', u'Application Context:[1], Assembly Name:[2]'), +(u'MsiUnpublishAssemblies', u'Unpublishing assembly information', u'Application Context:[1], Assembly Name:[2]'), +(u'Rollback', u'Rolling back action:', u'[1]'), +(u'RollbackCleanup', u'Removing backup files', u'File: [1]'), +(u'UnmoveFiles', u'Removing moved files', u'File: [1], Directory: [9]'), +(u'UnpublishProduct', u'Unpublishing product information', None), +] + +ControlCondition = [ +(u'CustomizeDlg', u'Browse', u'Hide', u'Installed'), +(u'CustomizeDlg', u'Location', u'Hide', u'Installed'), +(u'CustomizeDlg', u'LocationLabel', u'Hide', u'Installed'), +(u'LicenseAgreementDlg', u'Next', u'Disable', u'IAgree <> "Yes"'), +(u'LicenseAgreementDlg', u'Next', u'Enable', u'IAgree = "Yes"'), +] + +ControlEvent = [ +(u'AdminWelcomeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'AdminWelcomeDlg', u'Next', u'NewDialog', u'AdminRegistrationDlg', u'1', 2), +(u'AdminWelcomeDlg', u'Next', u'[InstallMode]', u'Server Image', u'1', 1), +(u'ExitDialog', u'Finish', u'EndDialog', u'Return', u'1', None), +(u'FatalError', u'Finish', u'EndDialog', u'Exit', u'1', None), +(u'PrepareDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'ProgressDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'UserExit', u'Finish', u'EndDialog', u'Exit', u'1', None), +(u'AdminBrowseDlg', u'Up', u'DirectoryListUp', u'0', u'1', None), +(u'AdminBrowseDlg', u'Cancel', u'Reset', u'0', u'1', 1), +(u'AdminBrowseDlg', u'Cancel', u'EndDialog', u'Return', u'1', 2), +(u'AdminBrowseDlg', u'NewFolder', u'DirectoryListNew', u'0', u'1', None), +(u'AdminBrowseDlg', u'OK', u'EndDialog', u'Return', u'1', 2), +(u'AdminBrowseDlg', u'OK', u'SetTargetPath', u'TARGETDIR', u'1', 1), +(u'AdminInstallPointDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'AdminInstallPointDlg', u'Back', u'NewDialog', u'AdminRegistrationDlg', u'1', None), +(u'AdminInstallPointDlg', u'Next', u'SetTargetPath', u'TARGETDIR', u'1', 1), +(u'AdminInstallPointDlg', u'Next', u'NewDialog', u'VerifyReadyDlg', u'1', 2), +(u'AdminInstallPointDlg', u'Browse', u'SpawnDialog', u'AdminBrowseDlg', u'1', None), +(u'AdminRegistrationDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'AdminRegistrationDlg', u'Back', u'NewDialog', u'AdminWelcomeDlg', u'1', None), +(u'AdminRegistrationDlg', u'Next', u'NewDialog', u'AdminInstallPointDlg', u'ProductID', 2), +(u'AdminRegistrationDlg', u'Next', u'ValidateProductID', u'0', u'0', 1), +(u'BrowseDlg', u'Up', u'DirectoryListUp', u'0', u'1', None), +(u'BrowseDlg', u'Cancel', u'Reset', u'0', u'1', 1), +(u'BrowseDlg', u'Cancel', u'EndDialog', u'Return', u'1', 2), +(u'BrowseDlg', u'NewFolder', u'DirectoryListNew', u'0', u'1', None), +(u'BrowseDlg', u'OK', u'EndDialog', u'Return', u'1', 2), +(u'BrowseDlg', u'OK', u'SetTargetPath', u'[_BrowseProperty]', u'1', 1), +(u'CancelDlg', u'No', u'EndDialog', u'Return', u'1', None), +(u'CancelDlg', u'Yes', u'EndDialog', u'Exit', u'1', None), +(u'CustomizeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'CustomizeDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'InstallMode = "Change"', None), +(u'CustomizeDlg', u'Back', u'NewDialog', u'SetupTypeDlg', u'InstallMode = "Custom"', None), +(u'CustomizeDlg', u'Next', u'NewDialog', u'VerifyReadyDlg', u'1', None), +(u'CustomizeDlg', u'Browse', u'SelectionBrowse', u'BrowseDlg', u'1', None), +(u'CustomizeDlg', u'Reset', u'Reset', u'0', u'1', None), +(u'CustomizeDlg', u'DiskCost', u'SpawnDialog', u'DiskCostDlg', u'1', 2), +(u'DiskCostDlg', u'OK', u'EndDialog', u'Return', u'1', None), +(u'ErrorDlg', u'Y', u'EndDialog', u'ErrorYes', u'1', None), +(u'ErrorDlg', u'A', u'EndDialog', u'ErrorAbort', u'1', None), +(u'ErrorDlg', u'C', u'EndDialog', u'ErrorCancel', u'1', None), +(u'ErrorDlg', u'I', u'EndDialog', u'ErrorIgnore', u'1', None), +(u'ErrorDlg', u'N', u'EndDialog', u'ErrorNo', u'1', None), +(u'ErrorDlg', u'O', u'EndDialog', u'ErrorOk', u'1', None), +(u'ErrorDlg', u'R', u'EndDialog', u'ErrorRetry', u'1', None), +(u'FilesInUse', u'Retry', u'EndDialog', u'Retry', u'1', None), +(u'FilesInUse', u'Exit', u'EndDialog', u'Exit', u'1', None), +(u'FilesInUse', u'Ignore', u'EndDialog', u'Ignore', u'1', None), +(u'LicenseAgreementDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'LicenseAgreementDlg', u'Back', u'NewDialog', u'WelcomeDlg', u'1', None), +(u'LicenseAgreementDlg', u'Next', u'NewDialog', u'SetupTypeDlg', u'IAgree = "Yes" AND ShowUserRegistrationDlg <> 1', 3), +(u'LicenseAgreementDlg', u'Next', u'NewDialog', u'UserRegistrationDlg', u'IAgree = "Yes" AND ShowUserRegistrationDlg = 1', 1), +(u'LicenseAgreementDlg', u'Next', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 2), +(u'MaintenanceTypeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'MaintenanceTypeDlg', u'Back', u'NewDialog', u'MaintenanceWelcomeDlg', u'1', None), +(u'MaintenanceTypeDlg', u'ChangeButton', u'NewDialog', u'CustomizeDlg', u'1', 4), +(u'MaintenanceTypeDlg', u'ChangeButton', u'[InstallMode]', u'Change', u'1', 1), +(u'MaintenanceTypeDlg', u'ChangeButton', u'[Progress1]', u'Changing', u'1', 2), +(u'MaintenanceTypeDlg', u'ChangeButton', u'[Progress2]', u'changes', u'1', 3), +(u'MaintenanceTypeDlg', u'RemoveButton', u'NewDialog', u'VerifyRemoveDlg', u'1', 4), +(u'MaintenanceTypeDlg', u'RemoveButton', u'[InstallMode]', u'Remove', u'1', 1), +(u'MaintenanceTypeDlg', u'RemoveButton', u'[Progress1]', u'Removing', u'1', 2), +(u'MaintenanceTypeDlg', u'RemoveButton', u'[Progress2]', u'removes', u'1', 3), +(u'MaintenanceTypeDlg', u'RepairButton', u'NewDialog', u'VerifyRepairDlg', u'1', 4), +(u'MaintenanceTypeDlg', u'RepairButton', u'[InstallMode]', u'Repair', u'1', 1), +(u'MaintenanceTypeDlg', u'RepairButton', u'[Progress1]', u'Repairing', u'1', 2), +(u'MaintenanceTypeDlg', u'RepairButton', u'[Progress2]', u'repairs', u'1', 3), +(u'MaintenanceWelcomeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'MaintenanceWelcomeDlg', u'Next', u'NewDialog', u'MaintenanceTypeDlg', u'1', 2), +(u'MaintenanceWelcomeDlg', u'Next', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 1), +(u'OutOfDiskDlg', u'OK', u'EndDialog', u'Return', u'1', None), +(u'OutOfRbDiskDlg', u'No', u'EndDialog', u'Return', u'1', None), +(u'OutOfRbDiskDlg', u'Yes', u'EndDialog', u'Return', u'1', 2), +(u'OutOfRbDiskDlg', u'Yes', u'EnableRollback', u'False', u'1', 1), +(u'ResumeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'ResumeDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 4), +(u'ResumeDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 2), +(u'ResumeDlg', u'Install', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 6), +(u'ResumeDlg', u'Install', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 3), +(u'ResumeDlg', u'Install', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 1), +(u'ResumeDlg', u'Install', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 5), +(u'SetupTypeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'SetupTypeDlg', u'Back', u'NewDialog', u'LicenseAgreementDlg', u'ShowUserRegistrationDlg <> 1', None), +(u'SetupTypeDlg', u'Back', u'NewDialog', u'UserRegistrationDlg', u'ShowUserRegistrationDlg = 1', None), +(u'SetupTypeDlg', u'CompleteButton', u'NewDialog', u'VerifyReadyDlg', u'1', 3), +(u'SetupTypeDlg', u'CompleteButton', u'[InstallMode]', u'Complete', u'1', 1), +(u'SetupTypeDlg', u'CompleteButton', u'SetInstallLevel', u'1000', u'1', 2), +(u'SetupTypeDlg', u'CustomButton', u'NewDialog', u'CustomizeDlg', u'1', 2), +(u'SetupTypeDlg', u'CustomButton', u'[InstallMode]', u'Custom', u'1', 1), +(u'SetupTypeDlg', u'TypicalButton', u'NewDialog', u'VerifyReadyDlg', u'1', 3), +(u'SetupTypeDlg', u'TypicalButton', u'[InstallMode]', u'Typical', u'1', 1), +(u'SetupTypeDlg', u'TypicalButton', u'SetInstallLevel', u'3', u'1', 2), +(u'UserRegistrationDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'UserRegistrationDlg', u'Back', u'NewDialog', u'LicenseAgreementDlg', u'1', None), +(u'UserRegistrationDlg', u'Next', u'NewDialog', u'SetupTypeDlg', u'ProductID', 3), +(u'UserRegistrationDlg', u'Next', u'ValidateProductID', u'0', u'0', 1), +(u'UserRegistrationDlg', u'Next', u'SpawnWaitDialog', u'WaitForCostingDlg', u'CostingComplete = 1', 2), +(u'VerifyReadyDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'VerifyReadyDlg', u'Back', u'NewDialog', u'AdminInstallPointDlg', u'InstallMode = "Server Image"', None), +(u'VerifyReadyDlg', u'Back', u'NewDialog', u'CustomizeDlg', u'InstallMode = "Custom" OR InstallMode = "Change"', None), +(u'VerifyReadyDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'InstallMode = "Repair"', None), +(u'VerifyReadyDlg', u'Back', u'NewDialog', u'SetupTypeDlg', u'InstallMode = "Typical" OR InstallMode = "Complete"', None), +(u'VerifyReadyDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 3), +(u'VerifyReadyDlg', u'Install', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 1), +(u'VerifyReadyDlg', u'Install', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 5), +(u'VerifyReadyDlg', u'Install', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 2), +(u'VerifyReadyDlg', u'Install', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 4), +(u'VerifyRemoveDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'VerifyRemoveDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'1', None), +(u'VerifyRemoveDlg', u'Remove', u'Remove', u'All', u'OutOfDiskSpace <> 1', 1), +(u'VerifyRemoveDlg', u'Remove', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 4), +(u'VerifyRemoveDlg', u'Remove', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 2), +(u'VerifyRemoveDlg', u'Remove', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 6), +(u'VerifyRemoveDlg', u'Remove', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 3), +(u'VerifyRemoveDlg', u'Remove', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 5), +(u'VerifyRepairDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'VerifyRepairDlg', u'Back', u'NewDialog', u'MaintenanceTypeDlg', u'1', None), +(u'VerifyRepairDlg', u'Repair', u'EndDialog', u'Return', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 5), +(u'VerifyRepairDlg', u'Repair', u'EndDialog', u'Return', u'OutOfDiskSpace <> 1', 3), +(u'VerifyRepairDlg', u'Repair', u'SpawnDialog', u'OutOfDiskDlg', u'(OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST="F")', 7), +(u'VerifyRepairDlg', u'Repair', u'SpawnDialog', u'OutOfRbDiskDlg', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST="P" OR NOT PROMPTROLLBACKCOST)', 4), +(u'VerifyRepairDlg', u'Repair', u'EnableRollback', u'False', u'OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST="D"', 6), +(u'VerifyRepairDlg', u'Repair', u'Reinstall', u'All', u'OutOfDiskSpace <> 1', 2), +(u'VerifyRepairDlg', u'Repair', u'ReinstallMode', u'ecmus', u'OutOfDiskSpace <> 1', 1), +(u'WaitForCostingDlg', u'Return', u'EndDialog', u'Exit', u'1', None), +(u'WelcomeDlg', u'Cancel', u'SpawnDialog', u'CancelDlg', u'1', None), +(u'WelcomeDlg', u'Next', u'NewDialog', u'LicenseAgreementDlg', u'1', None), +] + +Dialog = [ +(u'AdminWelcomeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Next', u'Next', u'Cancel'), +(u'ExitDialog', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Finish', u'Finish', u'Finish'), +(u'FatalError', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Finish', u'Finish', u'Finish'), +(u'PrepareDlg', 50, 50, 370, 270, 1, u'[ProductName] [Setup]', u'Cancel', u'Cancel', u'Cancel'), +(u'ProgressDlg', 50, 50, 370, 270, 1, u'[ProductName] [Setup]', u'Cancel', u'Cancel', u'Cancel'), +(u'UserExit', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Finish', u'Finish', u'Finish'), +(u'AdminBrowseDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'PathEdit', u'OK', u'Cancel'), +(u'AdminInstallPointDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Text', u'Next', u'Cancel'), +(u'AdminRegistrationDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'OrganizationLabel', u'Next', u'Cancel'), +(u'BrowseDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'PathEdit', u'OK', u'Cancel'), +(u'CancelDlg', 50, 10, 260, 85, 3, u'[ProductName] [Setup]', u'No', u'No', u'No'), +(u'CustomizeDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Tree', u'Next', u'Cancel'), +(u'DiskCostDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'OK', u'OK', u'OK'), +(u'ErrorDlg', 50, 10, 270, 105, 65539, u'Installer Information', u'ErrorText', None, None), +(u'FilesInUse', 50, 50, 370, 270, 19, u'[ProductName] [Setup]', u'Retry', u'Retry', u'Retry'), +(u'LicenseAgreementDlg', 50, 50, 370, 270, 3, u'[ProductName] License Agreement', u'Buttons', u'Next', u'Cancel'), +(u'MaintenanceTypeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'ChangeLabel', u'ChangeButton', u'Cancel'), +(u'MaintenanceWelcomeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Next', u'Next', u'Cancel'), +(u'OutOfDiskDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'OK', u'OK', u'OK'), +(u'OutOfRbDiskDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'No', u'No', u'No'), +(u'ResumeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Install', u'Install', u'Cancel'), +(u'SetupTypeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'TypicalLabel', u'TypicalButton', u'Cancel'), +(u'UserRegistrationDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'NameLabel', u'Next', u'Cancel'), +(u'VerifyReadyDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Install', u'Install', u'Cancel'), +(u'VerifyRemoveDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Back', u'Back', u'Cancel'), +(u'VerifyRepairDlg', 50, 50, 370, 270, 35, u'[ProductName] [Setup]', u'Repair', u'Repair', u'Cancel'), +(u'WaitForCostingDlg', 50, 10, 260, 85, 3, u'[ProductName] [Setup]', u'Return', u'Return', u'Return'), +(u'WelcomeDlg', 50, 50, 370, 270, 3, u'[ProductName] [Setup]', u'Next', u'Next', u'Cancel'), +] + +EventMapping = [ +(u'PrepareDlg', u'ActionData', u'ActionData', u'Text'), +(u'PrepareDlg', u'ActionText', u'ActionText', u'Text'), +(u'ProgressDlg', u'ActionText', u'ActionText', u'Text'), +(u'ProgressDlg', u'ProgressBar', u'SetProgress', u'Progress'), +(u'AdminBrowseDlg', u'DirectoryCombo', u'IgnoreChange', u'IgnoreChange'), +(u'BrowseDlg', u'DirectoryCombo', u'IgnoreChange', u'IgnoreChange'), +(u'CustomizeDlg', u'Next', u'SelectionNoItems', u'Enabled'), +(u'CustomizeDlg', u'Reset', u'SelectionNoItems', u'Enabled'), +(u'CustomizeDlg', u'DiskCost', u'SelectionNoItems', u'Enabled'), +(u'CustomizeDlg', u'ItemDescription', u'SelectionDescription', u'Text'), +(u'CustomizeDlg', u'ItemSize', u'SelectionSize', u'Text'), +(u'CustomizeDlg', u'Location', u'SelectionPath', u'Text'), +(u'CustomizeDlg', u'Location', u'SelectionPathOn', u'Visible'), +(u'CustomizeDlg', u'LocationLabel', u'SelectionPathOn', u'Visible'), +] + +InstallExecuteSequence = [ +(u'InstallValidate', None, 1400), +(u'InstallInitialize', None, 1500), +(u'InstallFinalize', None, 6600), +(u'InstallFiles', None, 4000), +(u'FileCost', None, 900), +(u'CostInitialize', None, 800), +(u'CostFinalize', None, 1000), +(u'CreateShortcuts', None, 4500), +(u'PublishComponents', None, 6200), +(u'PublishFeatures', None, 6300), +(u'PublishProduct', None, 6400), +(u'RegisterClassInfo', None, 4600), +(u'RegisterExtensionInfo', None, 4700), +(u'RegisterMIMEInfo', None, 4900), +(u'RegisterProgIdInfo', None, 4800), +(u'ValidateProductID', None, 700), +(u'AllocateRegistrySpace', u'NOT Installed', 1550), +(u'AppSearch', None, 400), +(u'BindImage', None, 4300), +(u'CCPSearch', u'NOT Installed', 500), +(u'CreateFolders', None, 3700), +(u'DeleteServices', u'VersionNT', 2000), +(u'DuplicateFiles', None, 4210), +(u'FindRelatedProducts', None, 200), +(u'InstallODBC', None, 5400), +(u'InstallServices', u'VersionNT', 5800), +(u'LaunchConditions', None, 100), +(u'MigrateFeatureStates', None, 1200), +(u'MoveFiles', None, 3800), +(u'PatchFiles', None, 4090), +(u'ProcessComponents', None, 1600), +(u'RegisterComPlus', None, 5700), +(u'RegisterFonts', None, 5300), +(u'RegisterProduct', None, 6100), +(u'RegisterTypeLibraries', None, 5500), +(u'RegisterUser', None, 6000), +(u'RemoveDuplicateFiles', None, 3400), +(u'RemoveEnvironmentStrings', None, 3300), +(u'RemoveExistingProducts', None, 6700), +(u'RemoveFiles', None, 3500), +(u'RemoveFolders', None, 3600), +(u'RemoveIniValues', None, 3100), +(u'RemoveODBC', None, 2400), +(u'RemoveRegistryValues', None, 2600), +(u'RemoveShortcuts', None, 3200), +(u'RMCCPSearch', u'NOT Installed', 600), +(u'SelfRegModules', None, 5600), +(u'SelfUnregModules', None, 2200), +(u'SetODBCFolders', None, 1100), +(u'StartServices', u'VersionNT', 5900), +(u'StopServices', u'VersionNT', 1900), +(u'UnpublishComponents', None, 1700), +(u'UnpublishFeatures', None, 1800), +(u'UnregisterClassInfo', None, 2700), +(u'UnregisterComPlus', None, 2100), +(u'UnregisterExtensionInfo', None, 2800), +(u'UnregisterFonts', None, 2500), +(u'UnregisterMIMEInfo', None, 3000), +(u'UnregisterProgIdInfo', None, 2900), +(u'UnregisterTypeLibraries', None, 2300), +(u'WriteEnvironmentStrings', None, 5200), +(u'WriteIniValues', None, 5100), +(u'WriteRegistryValues', None, 5000), +] + +InstallUISequence = [ +#(u'FileCost', None, 900), +#(u'CostInitialize', None, 800), +#(u'CostFinalize', None, 1000), +#(u'ExecuteAction', None, 1300), +#(u'ExitDialog', None, -1), +#(u'FatalError', None, -3), +(u'PrepareDlg', None, 140), +(u'ProgressDlg', None, 1280), +#(u'UserExit', None, -2), +(u'MaintenanceWelcomeDlg', u'Installed AND NOT RESUME AND NOT Preselected', 1250), +(u'ResumeDlg', u'Installed AND (RESUME OR Preselected)', 1240), +(u'WelcomeDlg', u'NOT Installed', 1230), +#(u'AppSearch', None, 400), +#(u'CCPSearch', u'NOT Installed', 500), +#(u'FindRelatedProducts', None, 200), +#(u'LaunchConditions', None, 100), +#(u'MigrateFeatureStates', None, 1200), +#(u'RMCCPSearch', u'NOT Installed', 600), +] + +ListView = [ +] + +RadioButton = [ +(u'IAgree', 1, u'Yes', 5, 0, 250, 15, u'{\\DlgFont8}I &accept the terms in the License Agreement', None), +(u'IAgree', 2, u'No', 5, 20, 250, 15, u'{\\DlgFont8}I &do not accept the terms in the License Agreement', None), +] + +TextStyle = [ +(u'DlgFont8', u'Tahoma', 8, None, 0), +(u'DlgFontBold8', u'Tahoma', 8, None, 1), +(u'VerdanaBold13', u'Verdana', 13, None, 1), +] + +UIText = [ +(u'AbsentPath', None), +(u'bytes', u'bytes'), +(u'GB', u'GB'), +(u'KB', u'KB'), +(u'MB', u'MB'), +(u'MenuAbsent', u'Entire feature will be unavailable'), +(u'MenuAdvertise', u'Feature will be installed when required'), +(u'MenuAllCD', u'Entire feature will be installed to run from CD'), +(u'MenuAllLocal', u'Entire feature will be installed on local hard drive'), +(u'MenuAllNetwork', u'Entire feature will be installed to run from network'), +(u'MenuCD', u'Will be installed to run from CD'), +(u'MenuLocal', u'Will be installed on local hard drive'), +(u'MenuNetwork', u'Will be installed to run from network'), +(u'ScriptInProgress', u'Gathering required information...'), +(u'SelAbsentAbsent', u'This feature will remain uninstalled'), +(u'SelAbsentAdvertise', u'This feature will be set to be installed when required'), +(u'SelAbsentCD', u'This feature will be installed to run from CD'), +(u'SelAbsentLocal', u'This feature will be installed on the local hard drive'), +(u'SelAbsentNetwork', u'This feature will be installed to run from the network'), +(u'SelAdvertiseAbsent', u'This feature will become unavailable'), +(u'SelAdvertiseAdvertise', u'Will be installed when required'), +(u'SelAdvertiseCD', u'This feature will be available to run from CD'), +(u'SelAdvertiseLocal', u'This feature will be installed on your local hard drive'), +(u'SelAdvertiseNetwork', u'This feature will be available to run from the network'), +(u'SelCDAbsent', u"This feature will be uninstalled completely, you won't be able to run it from CD"), +(u'SelCDAdvertise', u'This feature will change from run from CD state to set to be installed when required'), +(u'SelCDCD', u'This feature will remain to be run from CD'), +(u'SelCDLocal', u'This feature will change from run from CD state to be installed on the local hard drive'), +(u'SelChildCostNeg', u'This feature frees up [1] on your hard drive.'), +(u'SelChildCostPos', u'This feature requires [1] on your hard drive.'), +(u'SelCostPending', u'Compiling cost for this feature...'), +(u'SelLocalAbsent', u'This feature will be completely removed'), +(u'SelLocalAdvertise', u'This feature will be removed from your local hard drive, but will be set to be installed when required'), +(u'SelLocalCD', u'This feature will be removed from your local hard drive, but will be still available to run from CD'), +(u'SelLocalLocal', u'This feature will remain on you local hard drive'), +(u'SelLocalNetwork', u'This feature will be removed from your local hard drive, but will be still available to run from the network'), +(u'SelNetworkAbsent', u"This feature will be uninstalled completely, you won't be able to run it from the network"), +(u'SelNetworkAdvertise', u'This feature will change from run from network state to set to be installed when required'), +(u'SelNetworkLocal', u'This feature will change from run from network state to be installed on the local hard drive'), +(u'SelNetworkNetwork', u'This feature will remain to be run from the network'), +(u'SelParentCostNegNeg', u'This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.'), +(u'SelParentCostNegPos', u'This feature frees up [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.'), +(u'SelParentCostPosNeg', u'This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures free up [4] on your hard drive.'), +(u'SelParentCostPosPos', u'This feature requires [1] on your hard drive. It has [2] of [3] subfeatures selected. The subfeatures require [4] on your hard drive.'), +(u'TimeRemaining', u'Time remaining: {[1] minutes }{[2] seconds}'), +(u'VolumeCostAvailable', u'Available'), +(u'VolumeCostDifference', u'Difference'), +(u'VolumeCostRequired', u'Required'), +(u'VolumeCostSize', u'Disk Size'), +(u'VolumeCostVolume', u'Volume'), +] + +_Validation = [ +(u'AdminExecuteSequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), +(u'AdminExecuteSequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), +(u'AdminExecuteSequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), +(u'AdminUISequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), +(u'AdminUISequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), +(u'AdminUISequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), +(u'Condition', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Expression evaluated to determine if Level in the Feature table is to change.'), +(u'Condition', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Reference to a Feature entry in Feature table.'), +(u'Condition', u'Level', u'N', 0, 32767, None, None, None, None, u'New selection Level to set in Feature table if Condition evaluates to TRUE.'), +(u'AdvtExecuteSequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), +(u'AdvtExecuteSequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), +(u'AdvtExecuteSequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), +(u'BBControl', u'Type', u'N', None, None, None, None, u'Identifier', None, u'The type of the control.'), +(u'BBControl', u'BBControl', u'N', None, None, None, None, u'Identifier', None, u'Name of the control. This name must be unique within a billboard, but can repeat on different billboard.'), +(u'BBControl', u'Billboard_', u'N', None, None, u'Billboard', 1, u'Identifier', None, u'External key to the Billboard table, name of the billboard.'), +(u'BBControl', u'X', u'N', 0, 32767, None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.'), +(u'BBControl', u'Y', u'N', 0, 32767, None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.'), +(u'BBControl', u'Width', u'N', 0, 32767, None, None, None, None, u'Width of the bounding rectangle of the control.'), +(u'BBControl', u'Height', u'N', 0, 32767, None, None, None, None, u'Height of the bounding rectangle of the control.'), +(u'BBControl', u'Attributes', u'Y', 0, 2147483647, None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.'), +(u'BBControl', u'Text', u'Y', None, None, None, None, u'Text', None, u'A string used to set the initial text contained within a control (if appropriate).'), +(u'Billboard', u'Action', u'Y', None, None, None, None, u'Identifier', None, u'The name of an action. The billboard is displayed during the progress messages received from this action.'), +(u'Billboard', u'Billboard', u'N', None, None, None, None, u'Identifier', None, u'Name of the billboard.'), +(u'Billboard', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'An external key to the Feature Table. The billboard is shown only if this feature is being installed.'), +(u'Billboard', u'Ordering', u'Y', 0, 32767, None, None, None, None, u'A positive integer. If there is more than one billboard corresponding to an action they will be shown in the order defined by this column.'), +(u'Binary', u'Name', u'N', None, None, None, None, u'Identifier', None, u'Unique key identifying the binary data.'), +(u'Binary', u'Data', u'N', None, None, None, None, u'Binary', None, u'The unformatted binary data.'), +(u'CheckBox', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to the item.'), +(u'CheckBox', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The value string associated with the item.'), +(u'Property', u'Property', u'N', None, None, None, None, u'Identifier', None, u'Name of property, uppercase if settable by launcher or loader.'), +(u'Property', u'Value', u'N', None, None, None, None, u'Text', None, u'String value for property. Never null or empty.'), +(u'ComboBox', u'Text', u'Y', None, None, None, None, u'Formatted', None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.'), +(u'ComboBox', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this item. All the items tied to the same property become part of the same combobox.'), +(u'ComboBox', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value string associated with this item. Selecting the line will set the associated property to this value.'), +(u'ComboBox', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list.\tThe integers do not have to be consecutive.'), +(u'Control', u'Type', u'N', None, None, None, None, u'Identifier', None, u'The type of the control.'), +(u'Control', u'X', u'N', 0, 32767, None, None, None, None, u'Horizontal coordinate of the upper left corner of the bounding rectangle of the control.'), +(u'Control', u'Y', u'N', 0, 32767, None, None, None, None, u'Vertical coordinate of the upper left corner of the bounding rectangle of the control.'), +(u'Control', u'Width', u'N', 0, 32767, None, None, None, None, u'Width of the bounding rectangle of the control.'), +(u'Control', u'Height', u'N', 0, 32767, None, None, None, None, u'Height of the bounding rectangle of the control.'), +(u'Control', u'Attributes', u'Y', 0, 2147483647, None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this control.'), +(u'Control', u'Text', u'Y', None, None, None, None, u'Formatted', None, u'A string used to set the initial text contained within a control (if appropriate).'), +(u'Control', u'Property', u'Y', None, None, None, None, u'Identifier', None, u'The name of a defined property to be linked to this control. '), +(u'Control', u'Control', u'N', None, None, None, None, u'Identifier', None, u'Name of the control. This name must be unique within a dialog, but can repeat on different dialogs. '), +(u'Control', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'External key to the Dialog table, name of the dialog.'), +(u'Control', u'Control_Next', u'Y', None, None, u'Control', 2, u'Identifier', None, u'The name of an other control on the same dialog. This link defines the tab order of the controls. The links have to form one or more cycles!'), +(u'Control', u'Help', u'Y', None, None, None, None, u'Text', None, u'The help strings used with the button. The text is optional. '), +(u'Icon', u'Name', u'N', None, None, None, None, u'Identifier', None, u'Primary key. Name of the icon file.'), +(u'Icon', u'Data', u'N', None, None, None, None, u'Binary', None, u'Binary stream. The binary icon data in PE (.DLL or .EXE) or icon (.ICO) format.'), +(u'ListBox', u'Text', u'Y', None, None, None, None, u'Text', None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.'), +(u'ListBox', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listbox.'), +(u'ListBox', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value string associated with this item. Selecting the line will set the associated property to this value.'), +(u'ListBox', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.'), +(u'ActionText', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to be described.'), +(u'ActionText', u'Description', u'Y', None, None, None, None, u'Text', None, u'Localized description displayed in progress dialog and log when action is executing.'), +(u'ActionText', u'Template', u'Y', None, None, None, None, u'Template', None, u'Optional localized format template used to format action data records for display during action execution.'), +(u'ControlCondition', u'Action', u'N', None, None, None, None, None, u'Default;Disable;Enable;Hide;Show', u'The desired action to be taken on the specified control.'), +(u'ControlCondition', u'Condition', u'N', None, None, None, None, u'Condition', None, u'A standard conditional statement that specifies under which conditions the action should be triggered.'), +(u'ControlCondition', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'A foreign key to the Dialog table, name of the dialog.'), +(u'ControlCondition', u'Control_', u'N', None, None, u'Control', 2, u'Identifier', None, u'A foreign key to the Control table, name of the control.'), +(u'ControlEvent', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'A standard conditional statement that specifies under which conditions an event should be triggered.'), +(u'ControlEvent', u'Ordering', u'Y', 0, 2147483647, None, None, None, None, u'An integer used to order several events tied to the same control. Can be left blank.'), +(u'ControlEvent', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'A foreign key to the Dialog table, name of the dialog.'), +(u'ControlEvent', u'Control_', u'N', None, None, u'Control', 2, u'Identifier', None, u'A foreign key to the Control table, name of the control'), +(u'ControlEvent', u'Event', u'N', None, None, None, None, u'Formatted', None, u'An identifier that specifies the type of the event that should take place when the user interacts with control specified by the first two entries.'), +(u'ControlEvent', u'Argument', u'N', None, None, None, None, u'Formatted', None, u'A value to be used as a modifier when triggering a particular event.'), +(u'Dialog', u'Width', u'N', 0, 32767, None, None, None, None, u'Width of the bounding rectangle of the dialog.'), +(u'Dialog', u'Height', u'N', 0, 32767, None, None, None, None, u'Height of the bounding rectangle of the dialog.'), +(u'Dialog', u'Attributes', u'Y', 0, 2147483647, None, None, None, None, u'A 32-bit word that specifies the attribute flags to be applied to this dialog.'), +(u'Dialog', u'Title', u'Y', None, None, None, None, u'Formatted', None, u"A text string specifying the title to be displayed in the title bar of the dialog's window."), +(u'Dialog', u'Dialog', u'N', None, None, None, None, u'Identifier', None, u'Name of the dialog.'), +(u'Dialog', u'HCentering', u'N', 0, 100, None, None, None, None, u'Horizontal position of the dialog on a 0-100 scale. 0 means left end, 100 means right end of the screen, 50 center.'), +(u'Dialog', u'VCentering', u'N', 0, 100, None, None, None, None, u'Vertical position of the dialog on a 0-100 scale. 0 means top end, 100 means bottom end of the screen, 50 center.'), +(u'Dialog', u'Control_First', u'N', None, None, u'Control', 2, u'Identifier', None, u'Defines the control that has the focus when the dialog is created.'), +(u'Dialog', u'Control_Default', u'Y', None, None, u'Control', 2, u'Identifier', None, u'Defines the default control. Hitting return is equivalent to pushing this button.'), +(u'Dialog', u'Control_Cancel', u'Y', None, None, u'Control', 2, u'Identifier', None, u'Defines the cancel control. Hitting escape or clicking on the close icon on the dialog is equivalent to pushing this button.'), +(u'EventMapping', u'Dialog_', u'N', None, None, u'Dialog', 1, u'Identifier', None, u'A foreign key to the Dialog table, name of the Dialog.'), +(u'EventMapping', u'Control_', u'N', None, None, u'Control', 2, u'Identifier', None, u'A foreign key to the Control table, name of the control.'), +(u'EventMapping', u'Event', u'N', None, None, None, None, u'Identifier', None, u'An identifier that specifies the type of the event that the control subscribes to.'), +(u'EventMapping', u'Attribute', u'N', None, None, None, None, u'Identifier', None, u'The name of the control attribute, that is set when this event is received.'), +(u'InstallExecuteSequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), +(u'InstallExecuteSequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), +(u'InstallExecuteSequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), +(u'AppSearch', u'Property', u'N', None, None, None, None, u'Identifier', None, u'The property associated with a Signature'), +(u'AppSearch', u'Signature_', u'N', None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator', 1, u'Identifier', None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.'), +(u'BindImage', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'The index into the File table. This must be an executable file.'), +(u'BindImage', u'Path', u'Y', None, None, None, None, u'Paths', None, u'A list of ; delimited paths that represent the paths to be searched for the import DLLS. The list is usually a list of properties each enclosed within square brackets [] .'), +(u'CCPSearch', u'Signature_', u'N', None, None, u'Signature;RegLocator;IniLocator;DrLocator;CompLocator', 1, u'Identifier', None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature, RegLocator, IniLocator, CompLocator and the DrLocator tables.'), +(u'InstallUISequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), +(u'InstallUISequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), +(u'InstallUISequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), +(u'ListView', u'Text', u'Y', None, None, None, None, u'Text', None, u'The visible text to be assigned to the item. Optional. If this entry or the entire column is missing, the text is the same as the value.'), +(u'ListView', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this item. All the items tied to the same property become part of the same listview.'), +(u'ListView', u'Value', u'N', None, None, None, None, u'Identifier', None, u'The value string associated with this item. Selecting the line will set the associated property to this value.'), +(u'ListView', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.'), +(u'ListView', u'Binary_', u'Y', None, None, u'Binary', 1, u'Identifier', None, u'The name of the icon to be displayed with the icon. The binary information is looked up from the Binary Table.'), +(u'RadioButton', u'X', u'N', 0, 32767, None, None, None, None, u'The horizontal coordinate of the upper left corner of the bounding rectangle of the radio button.'), +(u'RadioButton', u'Y', u'N', 0, 32767, None, None, None, None, u'The vertical coordinate of the upper left corner of the bounding rectangle of the radio button.'), +(u'RadioButton', u'Width', u'N', 0, 32767, None, None, None, None, u'The width of the button.'), +(u'RadioButton', u'Height', u'N', 0, 32767, None, None, None, None, u'The height of the button.'), +(u'RadioButton', u'Text', u'Y', None, None, None, None, u'Text', None, u'The visible title to be assigned to the radio button.'), +(u'RadioButton', u'Property', u'N', None, None, None, None, u'Identifier', None, u'A named property to be tied to this radio button. All the buttons tied to the same property become part of the same group.'), +(u'RadioButton', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value string associated with this button. Selecting the button will set the associated property to this value.'), +(u'RadioButton', u'Order', u'N', 1, 32767, None, None, None, None, u'A positive integer used to determine the ordering of the items within one list..The integers do not have to be consecutive.'), +(u'RadioButton', u'Help', u'Y', None, None, None, None, u'Text', None, u'The help strings used with the button. The text is optional.'), +(u'TextStyle', u'TextStyle', u'N', None, None, None, None, u'Identifier', None, u'Name of the style. The primary key of this table. This name is embedded in the texts to indicate a style change.'), +(u'TextStyle', u'FaceName', u'N', None, None, None, None, u'Text', None, u'A string indicating the name of the font used. Required. The string must be at most 31 characters long.'), +(u'TextStyle', u'Size', u'N', 0, 32767, None, None, None, None, u'The size of the font used. This size is given in our units (1/12 of the system font height). Assuming that the system font is set to 12 point size, this is equivalent to the point size.'), +(u'TextStyle', u'Color', u'Y', 0, 16777215, None, None, None, None, u'A long integer indicating the color of the string in the RGB format (Red, Green, Blue each 0-255, RGB = R + 256*G + 256^2*B).'), +(u'TextStyle', u'StyleBits', u'Y', 0, 15, None, None, None, None, u'A combination of style bits.'), +(u'UIText', u'Text', u'Y', None, None, None, None, u'Text', None, u'The localized version of the string.'), +(u'UIText', u'Key', u'N', None, None, None, None, u'Identifier', None, u'A unique key that identifies the particular string.'), +(u'_Validation', u'Table', u'N', None, None, None, None, u'Identifier', None, u'Name of table'), +(u'_Validation', u'Description', u'Y', None, None, None, None, u'Text', None, u'Description of column'), +(u'_Validation', u'Column', u'N', None, None, None, None, u'Identifier', None, u'Name of column'), +(u'_Validation', u'Nullable', u'N', None, None, None, None, None, u'Y;N;@', u'Whether the column is nullable'), +(u'_Validation', u'MinValue', u'Y', -2147483647, 2147483647, None, None, None, None, u'Minimum value allowed'), +(u'_Validation', u'MaxValue', u'Y', -2147483647, 2147483647, None, None, None, None, u'Maximum value allowed'), +(u'_Validation', u'KeyTable', u'Y', None, None, None, None, u'Identifier', None, u'For foreign key, Name of table to which data must link'), +(u'_Validation', u'KeyColumn', u'Y', 1, 32, None, None, None, None, u'Column to which foreign key connects'), +(u'_Validation', u'Category', u'Y', None, None, None, None, None, u'Text;Formatted;Template;Condition;Guid;Path;Version;Language;Identifier;Binary;UpperCase;LowerCase;Filename;Paths;AnyPath;WildCardFilename;RegPath;KeyFormatted;CustomSource;Property;Cabinet;Shortcut;URL', u'String category'), +(u'_Validation', u'Set', u'Y', None, None, None, None, u'Text', None, u'Set of values that are permitted'), +(u'AdvtUISequence', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Name of action to invoke, either in the engine or the handler DLL.'), +(u'AdvtUISequence', u'Sequence', u'Y', -4, 32767, None, None, None, None, u'Number that determines the sort order in which the actions are to be executed. Leave blank to suppress action.'), +(u'AdvtUISequence', u'Condition', u'Y', None, None, None, None, u'Condition', None, u'Optional expression which skips the action if evaluates to expFalse.If the expression syntax is invalid, the engine will terminate, returning iesBadActionData.'), +(u'AppId', u'AppId', u'N', None, None, None, None, u'Guid', None, None), +(u'AppId', u'ActivateAtStorage', u'Y', 0, 1, None, None, None, None, None), +(u'AppId', u'DllSurrogate', u'Y', None, None, None, None, u'Text', None, None), +(u'AppId', u'LocalService', u'Y', None, None, None, None, u'Text', None, None), +(u'AppId', u'RemoteServerName', u'Y', None, None, None, None, u'Formatted', None, None), +(u'AppId', u'RunAsInteractiveUser', u'Y', 0, 1, None, None, None, None, None), +(u'AppId', u'ServiceParameters', u'Y', None, None, None, None, u'Text', None, None), +(u'Feature', u'Attributes', u'N', None, None, None, None, None, u'0;1;2;4;5;6;8;9;10;16;17;18;20;21;22;24;25;26;32;33;34;36;37;38;48;49;50;52;53;54', u'Feature attributes'), +(u'Feature', u'Description', u'Y', None, None, None, None, u'Text', None, u'Longer descriptive text describing a visible feature item.'), +(u'Feature', u'Title', u'Y', None, None, None, None, u'Text', None, u'Short text identifying a visible feature item.'), +(u'Feature', u'Feature', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular feature record.'), +(u'Feature', u'Directory_', u'Y', None, None, u'Directory', 1, u'UpperCase', None, u'The name of the Directory that can be configured by the UI. A non-null value will enable the browse button.'), +(u'Feature', u'Level', u'N', 0, 32767, None, None, None, None, u'The install level at which record will be initially selected. An install level of 0 will disable an item and prevent its display.'), +(u'Feature', u'Display', u'Y', 0, 32767, None, None, None, None, u'Numeric sort order, used to force a specific display ordering.'), +(u'Feature', u'Feature_Parent', u'Y', None, None, u'Feature', 1, u'Identifier', None, u'Optional key of a parent record in the same table. If the parent is not selected, then the record will not be installed. Null indicates a root item.'), +(u'File', u'Sequence', u'N', 1, 32767, None, None, None, None, u'Sequence with respect to the media images; order must track cabinet order.'), +(u'File', u'Attributes', u'Y', 0, 32767, None, None, None, None, u'Integer containing bit flags representing file attributes (with the decimal value of each bit position in parentheses)'), +(u'File', u'File', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token, must match identifier in cabinet. For uncompressed files, this field is ignored.'), +(u'File', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the file.'), +(u'File', u'FileName', u'N', None, None, None, None, u'Filename', None, u'File name used for installation, may be localized. This may contain a "short name|long name" pair.'), +(u'File', u'FileSize', u'N', 0, 2147483647, None, None, None, None, u'Size of file in bytes (long integer).'), +(u'File', u'Language', u'Y', None, None, None, None, u'Language', None, u'List of decimal language Ids, comma-separated if more than one.'), +(u'File', u'Version', u'Y', None, None, u'File', 1, u'Version', None, u'Version string for versioned files; Blank for unversioned files.'), +(u'Class', u'Attributes', u'Y', None, 32767, None, None, None, None, u'Class registration attributes.'), +(u'Class', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.'), +(u'Class', u'Description', u'Y', None, None, None, None, u'Text', None, u'Localized description for the Class.'), +(u'Class', u'Argument', u'Y', None, None, None, None, u'Formatted', None, u'optional argument for LocalServers.'), +(u'Class', u'AppId_', u'Y', None, None, u'AppId', 1, u'Guid', None, u'Optional AppID containing DCOM information for associated application (string GUID).'), +(u'Class', u'CLSID', u'N', None, None, None, None, u'Guid', None, u'The CLSID of an OLE factory.'), +(u'Class', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.'), +(u'Class', u'Context', u'N', None, None, None, None, u'Identifier', None, u'The numeric server context for this server. CLSCTX_xxxx'), +(u'Class', u'DefInprocHandler', u'Y', None, None, None, None, u'Filename', u'1;2;3', u'Optional default inproc handler. Only optionally provided if Context=CLSCTX_LOCAL_SERVER. Typically "ole32.dll" or "mapi32.dll"'), +(u'Class', u'FileTypeMask', u'Y', None, None, None, None, u'Text', None, u'Optional string containing information for the HKCRthis CLSID) key. If multiple patterns exist, they must be delimited by a semicolon, and numeric subkeys will be generated: 0,1,2...'), +(u'Class', u'Icon_', u'Y', None, None, u'Icon', 1, u'Identifier', None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this CLSID. Will be written under the DefaultIcon key.'), +(u'Class', u'IconIndex', u'Y', -32767, 32767, None, None, None, None, u'Optional icon index.'), +(u'Class', u'ProgId_Default', u'Y', None, None, u'ProgId', 1, u'Text', None, u'Optional ProgId associated with this CLSID.'), +(u'Component', u'Condition', u'Y', None, None, None, None, u'Condition', None, u"A conditional statement that will disable this component if the specified condition evaluates to the 'True' state. If a component is disabled, it will not be installed, regardless of the 'Action' state associated with the component."), +(u'Component', u'Attributes', u'N', None, None, None, None, None, None, u'Remote execution option, one of irsEnum'), +(u'Component', u'Component', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular component record.'), +(u'Component', u'ComponentId', u'Y', None, None, None, None, u'Guid', None, u'A string GUID unique to this component, version, and language.'), +(u'Component', u'Directory_', u'N', None, None, u'Directory', 1, u'Identifier', None, u'Required key of a Directory table record. This is actually a property name whose value contains the actual path, set either by the AppSearch action or with the default setting obtained from the Directory table.'), +(u'Component', u'KeyPath', u'Y', None, None, u'File;Registry;ODBCDataSource', 1, u'Identifier', None, u'Either the primary key into the File table, Registry table, or ODBCDataSource table. This extract path is stored when the component is installed, and is used to detect the presence of the component and to return the path to it.'), +(u'ProgId', u'Description', u'Y', None, None, None, None, u'Text', None, u'Localized description for the Program identifier.'), +(u'ProgId', u'Icon_', u'Y', None, None, u'Icon', 1, u'Identifier', None, u'Optional foreign key into the Icon Table, specifying the icon file associated with this ProgId. Will be written under the DefaultIcon key.'), +(u'ProgId', u'IconIndex', u'Y', -32767, 32767, None, None, None, None, u'Optional icon index.'), +(u'ProgId', u'ProgId', u'N', None, None, None, None, u'Text', None, u'The Program Identifier. Primary key.'), +(u'ProgId', u'Class_', u'Y', None, None, u'Class', 1, u'Guid', None, u'The CLSID of an OLE factory corresponding to the ProgId.'), +(u'ProgId', u'ProgId_Parent', u'Y', None, None, u'ProgId', 1, u'Text', None, u'The Parent Program Identifier. If specified, the ProgId column becomes a version independent prog id.'), +(u'CompLocator', u'Type', u'Y', 0, 1, None, None, None, None, u'A boolean value that determines if the registry value is a filename or a directory location.'), +(u'CompLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.'), +(u'CompLocator', u'ComponentId', u'N', None, None, None, None, u'Guid', None, u'A string GUID unique to this component, version, and language.'), +(u'Complus', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the ComPlus component.'), +(u'Complus', u'ExpType', u'Y', 0, 32767, None, None, None, None, u'ComPlus component attributes.'), +(u'Directory', u'Directory', u'N', None, None, None, None, u'Identifier', None, u'Unique identifier for directory entry, primary key. If a property by this name is defined, it contains the full path to the directory.'), +(u'Directory', u'DefaultDir', u'N', None, None, None, None, u'DefaultDir', None, u"The default sub-path under parent's path."), +(u'Directory', u'Directory_Parent', u'Y', None, None, u'Directory', 1, u'Identifier', None, u'Reference to the entry in this table specifying the default parent directory. A record parented to itself or with a Null parent represents a root of the install tree.'), +(u'CreateFolder', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table.'), +(u'CreateFolder', u'Directory_', u'N', None, None, u'Directory', 1, u'Identifier', None, u'Primary key, could be foreign key into the Directory table.'), +(u'CustomAction', u'Type', u'N', 1, 16383, None, None, None, None, u'The numeric custom action type, consisting of source location, code type, entry, option flags.'), +(u'CustomAction', u'Action', u'N', None, None, None, None, u'Identifier', None, u'Primary key, name of action, normally appears in sequence table unless private use.'), +(u'CustomAction', u'Source', u'Y', None, None, None, None, u'CustomSource', None, u'The table reference of the source of the code.'), +(u'CustomAction', u'Target', u'Y', None, None, None, None, u'Formatted', None, u'Excecution parameter, depends on the type of custom action'), +(u'DrLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The Signature_ represents a unique file signature and is also the foreign key in the Signature table.'), +(u'DrLocator', u'Path', u'Y', None, None, None, None, u'AnyPath', None, u'The path on the user system. This is a either a subpath below the value of the Parent or a full path. The path may contain properties enclosed within [ ] that will be expanded.'), +(u'DrLocator', u'Depth', u'Y', 0, 32767, None, None, None, None, u'The depth below the path to which the Signature_ is recursively searched. If absent, the depth is assumed to be 0.'), +(u'DrLocator', u'Parent', u'Y', None, None, None, None, u'Identifier', None, u'The parent file signature. It is also a foreign key in the Signature table. If null and the Path column does not expand to a full path, then all the fixed drives of the user system are searched using the Path.'), +(u'DuplicateFile', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Foreign key referencing the source file to be duplicated.'), +(u'DuplicateFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the duplicate file.'), +(u'DuplicateFile', u'DestFolder', u'Y', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full pathname to a destination folder.'), +(u'DuplicateFile', u'DestName', u'Y', None, None, None, None, u'Filename', None, u'Filename to be given to the duplicate file.'), +(u'DuplicateFile', u'FileKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular file entry'), +(u'Environment', u'Name', u'N', None, None, None, None, u'Text', None, u'The name of the environmental value.'), +(u'Environment', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The value to set in the environmental settings.'), +(u'Environment', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the installing of the environmental value.'), +(u'Environment', u'Environment', u'N', None, None, None, None, u'Identifier', None, u'Unique identifier for the environmental variable setting'), +(u'Error', u'Error', u'N', 0, 32767, None, None, None, None, u'Integer error number, obtained from header file IError(...) macros.'), +(u'Error', u'Message', u'Y', None, None, None, None, u'Template', None, u'Error formatting template, obtained from user ed. or localizers.'), +(u'Extension', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the CLSID factory to be operational.'), +(u'Extension', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.'), +(u'Extension', u'Extension', u'N', None, None, None, None, u'Text', None, u'The extension associated with the table row.'), +(u'Extension', u'MIME_', u'Y', None, None, u'MIME', 1, u'Text', None, u'Optional Context identifier, typically "type/format" associated with the extension'), +(u'Extension', u'ProgId_', u'Y', None, None, u'ProgId', 1, u'Text', None, u'Optional ProgId associated with this extension.'), +(u'MIME', u'CLSID', u'Y', None, None, None, None, u'Guid', None, u'Optional associated CLSID.'), +(u'MIME', u'ContentType', u'N', None, None, None, None, u'Text', None, u'Primary key. Context identifier, typically "type/format".'), +(u'MIME', u'Extension_', u'N', None, None, u'Extension', 1, u'Text', None, u'Optional associated extension (without dot)'), +(u'FeatureComponents', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Foreign key into Feature table.'), +(u'FeatureComponents', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into Component table.'), +(u'FileSFPCatalog', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'File associated with the catalog'), +(u'FileSFPCatalog', u'SFPCatalog_', u'N', None, None, u'SFPCatalog', 1, u'Filename', None, u'Catalog associated with the file'), +(u'SFPCatalog', u'SFPCatalog', u'N', None, None, None, None, u'Filename', None, u'File name for the catalog.'), +(u'SFPCatalog', u'Catalog', u'N', None, None, None, None, u'Binary', None, u'SFP Catalog'), +(u'SFPCatalog', u'Dependency', u'Y', None, None, None, None, u'Formatted', None, u'Parent catalog - only used by SFP'), +(u'Font', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Primary key, foreign key into File table referencing font file.'), +(u'Font', u'FontTitle', u'Y', None, None, None, None, u'Text', None, u'Font name.'), +(u'IniFile', u'Action', u'N', None, None, None, None, None, u'0;1;3', u'The type of modification to be made, one of iifEnum'), +(u'IniFile', u'Value', u'N', None, None, None, None, u'Formatted', None, u'The value to be written.'), +(u'IniFile', u'Key', u'N', None, None, None, None, u'Formatted', None, u'The .INI file key below Section.'), +(u'IniFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the installing of the .INI value.'), +(u'IniFile', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The .INI file name in which to write the information'), +(u'IniFile', u'IniFile', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), +(u'IniFile', u'DirProperty', u'Y', None, None, None, None, u'Identifier', None, u'Foreign key into the Directory table denoting the directory where the .INI file is.'), +(u'IniFile', u'Section', u'N', None, None, None, None, u'Formatted', None, u'The .INI file Section.'), +(u'IniLocator', u'Type', u'Y', 0, 2, None, None, None, None, u'An integer value that determines if the .INI value read is a filename or a directory location or to be used as is w/o interpretation.'), +(u'IniLocator', u'Key', u'N', None, None, None, None, u'Text', None, u'Key value (followed by an equals sign in INI file).'), +(u'IniLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table.'), +(u'IniLocator', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The .INI file name.'), +(u'IniLocator', u'Section', u'N', None, None, None, None, u'Text', None, u'Section name within in file (within square brackets in INI file).'), +(u'IniLocator', u'Field', u'Y', 0, 32767, None, None, None, None, u'The field in the .INI line. If Field is null or 0 the entire line is read.'), +(u'IsolatedComponent', u'Component_Application', u'N', None, None, u'Component', 1, u'Identifier', None, u'Key to Component table item for application'), +(u'IsolatedComponent', u'Component_Shared', u'N', None, None, u'Component', 1, u'Identifier', None, u'Key to Component table item to be isolated'), +(u'LaunchCondition', u'Condition', u'N', None, None, None, None, u'Condition', None, u'Expression which must evaluate to TRUE in order for install to commence.'), +(u'LaunchCondition', u'Description', u'N', None, None, None, None, u'Formatted', None, u'Localizable text to display when condition fails and install must abort.'), +(u'LockPermissions', u'Table', u'N', None, None, None, None, u'Identifier', u'Directory;File;Registry', u'Reference to another table name'), +(u'LockPermissions', u'Domain', u'Y', None, None, None, None, u'Formatted', None, u'Domain name for user whose permissions are being set. (usually a property)'), +(u'LockPermissions', u'LockObject', u'N', None, None, None, None, u'Identifier', None, u'Foreign key into Registry or File table'), +(u'LockPermissions', u'Permission', u'Y', -2147483647, 2147483647, None, None, None, None, u'Permission Access mask. Full Control = 268435456 (GENERIC_ALL = 0x10000000)'), +(u'LockPermissions', u'User', u'N', None, None, None, None, u'Formatted', None, u'User for permissions to be set. (usually a property)'), +(u'Media', u'Source', u'Y', None, None, None, None, u'Property', None, u'The property defining the location of the cabinet file.'), +(u'Media', u'Cabinet', u'Y', None, None, None, None, u'Cabinet', None, u'If some or all of the files stored on the media are compressed in a cabinet, the name of that cabinet.'), +(u'Media', u'DiskId', u'N', 1, 32767, None, None, None, None, u'Primary key, integer to determine sort order for table.'), +(u'Media', u'DiskPrompt', u'Y', None, None, None, None, u'Text', None, u'Disk name: the visible text actually printed on the disk. This will be used to prompt the user when this disk needs to be inserted.'), +(u'Media', u'LastSequence', u'N', 0, 32767, None, None, None, None, u'File sequence number for the last file for this media.'), +(u'Media', u'VolumeLabel', u'Y', None, None, None, None, u'Text', None, u'The label attributed to the volume.'), +(u'ModuleComponents', u'Component', u'N', None, None, u'Component', 1, u'Identifier', None, u'Component contained in the module.'), +(u'ModuleComponents', u'Language', u'N', None, None, u'ModuleSignature', 2, None, None, u'Default language ID for module (may be changed by transform).'), +(u'ModuleComponents', u'ModuleID', u'N', None, None, u'ModuleSignature', 1, u'Identifier', None, u'Module containing the component.'), +(u'ModuleSignature', u'Language', u'N', None, None, None, None, None, None, u'Default decimal language of module.'), +(u'ModuleSignature', u'Version', u'N', None, None, None, None, u'Version', None, u'Version of the module.'), +(u'ModuleSignature', u'ModuleID', u'N', None, None, None, None, u'Identifier', None, u'Module identifier (String.GUID).'), +(u'ModuleDependency', u'ModuleID', u'N', None, None, u'ModuleSignature', 1, u'Identifier', None, u'Module requiring the dependency.'), +(u'ModuleDependency', u'ModuleLanguage', u'N', None, None, u'ModuleSignature', 2, None, None, u'Language of module requiring the dependency.'), +(u'ModuleDependency', u'RequiredID', u'N', None, None, None, None, None, None, u'String.GUID of required module.'), +(u'ModuleDependency', u'RequiredLanguage', u'N', None, None, None, None, None, None, u'LanguageID of the required module.'), +(u'ModuleDependency', u'RequiredVersion', u'Y', None, None, None, None, u'Version', None, u'Version of the required version.'), +(u'ModuleExclusion', u'ModuleID', u'N', None, None, u'ModuleSignature', 1, u'Identifier', None, u'String.GUID of module with exclusion requirement.'), +(u'ModuleExclusion', u'ModuleLanguage', u'N', None, None, u'ModuleSignature', 2, None, None, u'LanguageID of module with exclusion requirement.'), +(u'ModuleExclusion', u'ExcludedID', u'N', None, None, None, None, None, None, u'String.GUID of excluded module.'), +(u'ModuleExclusion', u'ExcludedLanguage', u'N', None, None, None, None, None, None, u'Language of excluded module.'), +(u'ModuleExclusion', u'ExcludedMaxVersion', u'Y', None, None, None, None, u'Version', None, u'Maximum version of excluded module.'), +(u'ModuleExclusion', u'ExcludedMinVersion', u'Y', None, None, None, None, u'Version', None, u'Minimum version of excluded module.'), +(u'MoveFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'If this component is not "selected" for installation or removal, no action will be taken on the associated MoveFile entry'), +(u'MoveFile', u'DestFolder', u'N', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory'), +(u'MoveFile', u'DestName', u'Y', None, None, None, None, u'Filename', None, u'Name to be given to the original file after it is moved or copied. If blank, the destination file will be given the same name as the source file'), +(u'MoveFile', u'FileKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key that uniquely identifies a particular MoveFile record'), +(u'MoveFile', u'Options', u'N', 0, 1, None, None, None, None, u'Integer value specifying the MoveFile operating mode, one of imfoEnum'), +(u'MoveFile', u'SourceFolder', u'Y', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full path to the source directory'), +(u'MoveFile', u'SourceName', u'Y', None, None, None, None, u'Text', None, u"Name of the source file(s) to be moved or copied. Can contain the '*' or '?' wildcards."), +(u'MsiAssembly', u'Attributes', u'Y', None, None, None, None, None, None, u'Assembly attributes'), +(u'MsiAssembly', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Foreign key into Feature table.'), +(u'MsiAssembly', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into Component table.'), +(u'MsiAssembly', u'File_Application', u'Y', None, None, u'File', 1, u'Identifier', None, u'Foreign key into File table, denoting the application context for private assemblies. Null for global assemblies.'), +(u'MsiAssembly', u'File_Manifest', u'Y', None, None, u'File', 1, u'Identifier', None, u'Foreign key into the File table denoting the manifest file for the assembly.'), +(u'MsiAssemblyName', u'Name', u'N', None, None, None, None, u'Text', None, u'The name part of the name-value pairs for the assembly name.'), +(u'MsiAssemblyName', u'Value', u'N', None, None, None, None, u'Text', None, u'The value part of the name-value pairs for the assembly name.'), +(u'MsiAssemblyName', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into Component table.'), +(u'MsiDigitalCertificate', u'CertData', u'N', None, None, None, None, u'Binary', None, u'A certificate context blob for a signer certificate'), +(u'MsiDigitalCertificate', u'DigitalCertificate', u'N', None, None, None, None, u'Identifier', None, u'A unique identifier for the row'), +(u'MsiDigitalSignature', u'Table', u'N', None, None, None, None, None, u'Media', u'Reference to another table name (only Media table is supported)'), +(u'MsiDigitalSignature', u'DigitalCertificate_', u'N', None, None, u'MsiDigitalCertificate', 1, u'Identifier', None, u'Foreign key to MsiDigitalCertificate table identifying the signer certificate'), +(u'MsiDigitalSignature', u'Hash', u'Y', None, None, None, None, u'Binary', None, u'The encoded hash blob from the digital signature'), +(u'MsiDigitalSignature', u'SignObject', u'N', None, None, None, None, u'Text', None, u'Foreign key to Media table'), +(u'MsiFileHash', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Primary key, foreign key into File table referencing file with this hash'), +(u'MsiFileHash', u'Options', u'N', 0, 32767, None, None, None, None, u'Various options and attributes for this hash.'), +(u'MsiFileHash', u'HashPart1', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), +(u'MsiFileHash', u'HashPart2', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), +(u'MsiFileHash', u'HashPart3', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), +(u'MsiFileHash', u'HashPart4', u'N', None, None, None, None, None, None, u'Size of file in bytes (long integer).'), +(u'MsiPatchHeaders', u'StreamRef', u'N', None, None, None, None, u'Identifier', None, u'Primary key. A unique identifier for the row.'), +(u'MsiPatchHeaders', u'Header', u'N', None, None, None, None, u'Binary', None, u'Binary stream. The patch header, used for patch validation.'), +(u'ODBCAttribute', u'Value', u'Y', None, None, None, None, u'Text', None, u'Value for ODBC driver attribute'), +(u'ODBCAttribute', u'Attribute', u'N', None, None, None, None, u'Text', None, u'Name of ODBC driver attribute'), +(u'ODBCAttribute', u'Driver_', u'N', None, None, u'ODBCDriver', 1, u'Identifier', None, u'Reference to ODBC driver in ODBCDriver table'), +(u'ODBCDriver', u'Description', u'N', None, None, None, None, u'Text', None, u'Text used as registered name for driver, non-localized'), +(u'ODBCDriver', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Reference to key driver file'), +(u'ODBCDriver', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reference to associated component'), +(u'ODBCDriver', u'Driver', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized.internal token for driver'), +(u'ODBCDriver', u'File_Setup', u'Y', None, None, u'File', 1, u'Identifier', None, u'Optional reference to key driver setup DLL'), +(u'ODBCDataSource', u'Description', u'N', None, None, None, None, u'Text', None, u'Text used as registered name for data source'), +(u'ODBCDataSource', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reference to associated component'), +(u'ODBCDataSource', u'DataSource', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized.internal token for data source'), +(u'ODBCDataSource', u'DriverDescription', u'N', None, None, None, None, u'Text', None, u'Reference to driver description, may be existing driver'), +(u'ODBCDataSource', u'Registration', u'N', 0, 1, None, None, None, None, u'Registration option: 0=machine, 1=user, others t.b.d.'), +(u'ODBCSourceAttribute', u'Value', u'Y', None, None, None, None, u'Text', None, u'Value for ODBC data source attribute'), +(u'ODBCSourceAttribute', u'Attribute', u'N', None, None, None, None, u'Text', None, u'Name of ODBC data source attribute'), +(u'ODBCSourceAttribute', u'DataSource_', u'N', None, None, u'ODBCDataSource', 1, u'Identifier', None, u'Reference to ODBC data source in ODBCDataSource table'), +(u'ODBCTranslator', u'Description', u'N', None, None, None, None, u'Text', None, u'Text used as registered name for translator'), +(u'ODBCTranslator', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Reference to key translator file'), +(u'ODBCTranslator', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reference to associated component'), +(u'ODBCTranslator', u'File_Setup', u'Y', None, None, u'File', 1, u'Identifier', None, u'Optional reference to key translator setup DLL'), +(u'ODBCTranslator', u'Translator', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized.internal token for translator'), +(u'Patch', u'Sequence', u'N', 0, 32767, None, None, None, None, u'Primary key, sequence with respect to the media images; order must track cabinet order.'), +(u'Patch', u'Attributes', u'N', 0, 32767, None, None, None, None, u'Integer containing bit flags representing patch attributes'), +(u'Patch', u'File_', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token, foreign key to File table, must match identifier in cabinet.'), +(u'Patch', u'Header', u'Y', None, None, None, None, u'Binary', None, u'Binary stream. The patch header, used for patch validation.'), +(u'Patch', u'PatchSize', u'N', 0, 2147483647, None, None, None, None, u'Size of patch in bytes (long integer).'), +(u'Patch', u'StreamRef_', u'Y', None, None, None, None, u'Identifier', None, u'Identifier. Foreign key to the StreamRef column of the MsiPatchHeaders table.'), +(u'PatchPackage', u'Media_', u'N', 0, 32767, None, None, None, None, u'Foreign key to DiskId column of Media table. Indicates the disk containing the patch package.'), +(u'PatchPackage', u'PatchId', u'N', None, None, None, None, u'Guid', None, u'A unique string GUID representing this patch.'), +(u'PublishComponent', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Foreign key into the Feature table.'), +(u'PublishComponent', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table.'), +(u'PublishComponent', u'ComponentId', u'N', None, None, None, None, u'Guid', None, u'A string GUID that represents the component id that will be requested by the alien product.'), +(u'PublishComponent', u'AppData', u'Y', None, None, None, None, u'Text', None, u'This is localisable Application specific data that can be associated with a Qualified Component.'), +(u'PublishComponent', u'Qualifier', u'N', None, None, None, None, u'Text', None, u'This is defined only when the ComponentId column is an Qualified Component Id. This is the Qualifier for ProvideComponentIndirect.'), +(u'Registry', u'Name', u'Y', None, None, None, None, u'Formatted', None, u'The registry value name.'), +(u'Registry', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The registry value.'), +(u'Registry', u'Key', u'N', None, None, None, None, u'RegPath', None, u'The key for the registry value.'), +(u'Registry', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the installing of the registry value.'), +(u'Registry', u'Registry', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), +(u'Registry', u'Root', u'N', -1, 3, None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.'), +(u'RegLocator', u'Name', u'Y', None, None, None, None, u'Formatted', None, u'The registry value name.'), +(u'RegLocator', u'Type', u'Y', 0, 18, None, None, None, None, u'An integer value that determines if the registry value is a filename or a directory location or to be used as is w/o interpretation.'), +(u'RegLocator', u'Key', u'N', None, None, None, None, u'RegPath', None, u'The key for the registry value.'), +(u'RegLocator', u'Signature_', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature_ represents a unique file signature and is also the foreign key in the Signature table. If the type is 0, the registry values refers a directory, and _Signature is not a foreign key.'), +(u'RegLocator', u'Root', u'N', 0, 3, None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum.'), +(u'RemoveFile', u'InstallMode', u'N', None, None, None, None, None, u'1;2;3', u'Installation option, one of iimEnum.'), +(u'RemoveFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key referencing Component that controls the file to be removed.'), +(u'RemoveFile', u'FileKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key used to identify a particular file entry'), +(u'RemoveFile', u'FileName', u'Y', None, None, None, None, u'WildCardFilename', None, u'Name of the file to be removed.'), +(u'RemoveFile', u'DirProperty', u'N', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full pathname to the folder of the file to be removed.'), +(u'RemoveIniFile', u'Action', u'N', None, None, None, None, None, u'2;4', u'The type of modification to be made, one of iifEnum.'), +(u'RemoveIniFile', u'Value', u'Y', None, None, None, None, u'Formatted', None, u'The value to be deleted. The value is required when Action is iifIniRemoveTag'), +(u'RemoveIniFile', u'Key', u'N', None, None, None, None, u'Formatted', None, u'The .INI file key below Section.'), +(u'RemoveIniFile', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the deletion of the .INI value.'), +(u'RemoveIniFile', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The .INI file name in which to delete the information'), +(u'RemoveIniFile', u'DirProperty', u'Y', None, None, None, None, u'Identifier', None, u'Foreign key into the Directory table denoting the directory where the .INI file is.'), +(u'RemoveIniFile', u'Section', u'N', None, None, None, None, u'Formatted', None, u'The .INI file Section.'), +(u'RemoveIniFile', u'RemoveIniFile', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), +(u'RemoveRegistry', u'Name', u'Y', None, None, None, None, u'Formatted', None, u'The registry value name.'), +(u'RemoveRegistry', u'Key', u'N', None, None, None, None, u'RegPath', None, u'The key for the registry value.'), +(u'RemoveRegistry', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table referencing component that controls the deletion of the registry value.'), +(u'RemoveRegistry', u'Root', u'N', -1, 3, None, None, None, None, u'The predefined root key for the registry value, one of rrkEnum'), +(u'RemoveRegistry', u'RemoveRegistry', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), +(u'ReserveCost', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Reserve a specified amount of space if this component is to be installed.'), +(u'ReserveCost', u'ReserveFolder', u'Y', None, None, None, None, u'Identifier', None, u'Name of a property whose value is assumed to resolve to the full path to the destination directory'), +(u'ReserveCost', u'ReserveKey', u'N', None, None, None, None, u'Identifier', None, u'Primary key that uniquely identifies a particular ReserveCost record'), +(u'ReserveCost', u'ReserveLocal', u'N', 0, 2147483647, None, None, None, None, u'Disk space to reserve if linked component is installed locally.'), +(u'ReserveCost', u'ReserveSource', u'N', 0, 2147483647, None, None, None, None, u'Disk space to reserve if linked component is installed to run from the source location.'), +(u'SelfReg', u'File_', u'N', None, None, u'File', 1, u'Identifier', None, u'Foreign key into the File table denoting the module that needs to be registered.'), +(u'SelfReg', u'Cost', u'Y', 0, 32767, None, None, None, None, u'The cost of registering the module.'), +(u'ServiceControl', u'Name', u'N', None, None, None, None, u'Formatted', None, u'Name of a service. /, \\, comma and space are invalid'), +(u'ServiceControl', u'Event', u'N', 0, 187, None, None, None, None, u'Bit field: Install: 0x1 = Start, 0x2 = Stop, 0x8 = Delete, Uninstall: 0x10 = Start, 0x20 = Stop, 0x80 = Delete'), +(u'ServiceControl', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table that controls the startup of the service'), +(u'ServiceControl', u'ServiceControl', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), +(u'ServiceControl', u'Arguments', u'Y', None, None, None, None, u'Formatted', None, u'Arguments for the service. Separate by [~].'), +(u'ServiceControl', u'Wait', u'Y', 0, 1, None, None, None, None, u'Boolean for whether to wait for the service to fully start'), +(u'ServiceInstall', u'Name', u'N', None, None, None, None, u'Formatted', None, u'Internal Name of the Service'), +(u'ServiceInstall', u'Description', u'Y', None, None, None, None, u'Text', None, u'Description of service.'), +(u'ServiceInstall', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table that controls the startup of the service'), +(u'ServiceInstall', u'Arguments', u'Y', None, None, None, None, u'Formatted', None, u'Arguments to include in every start of the service, passed to WinMain'), +(u'ServiceInstall', u'ServiceInstall', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), +(u'ServiceInstall', u'Dependencies', u'Y', None, None, None, None, u'Formatted', None, u'Other services this depends on to start. Separate by [~], and end with [~][~]'), +(u'ServiceInstall', u'DisplayName', u'Y', None, None, None, None, u'Formatted', None, u'External Name of the Service'), +(u'ServiceInstall', u'ErrorControl', u'N', -2147483647, 2147483647, None, None, None, None, u'Severity of error if service fails to start'), +(u'ServiceInstall', u'LoadOrderGroup', u'Y', None, None, None, None, u'Formatted', None, u'LoadOrderGroup'), +(u'ServiceInstall', u'Password', u'Y', None, None, None, None, u'Formatted', None, u'password to run service with. (with StartName)'), +(u'ServiceInstall', u'ServiceType', u'N', -2147483647, 2147483647, None, None, None, None, u'Type of the service'), +(u'ServiceInstall', u'StartName', u'Y', None, None, None, None, u'Formatted', None, u'User or object name to run service as'), +(u'ServiceInstall', u'StartType', u'N', 0, 4, None, None, None, None, u'Type of the service'), +(u'Shortcut', u'Name', u'N', None, None, None, None, u'Filename', None, u'The name of the shortcut to be created.'), +(u'Shortcut', u'Description', u'Y', None, None, None, None, u'Text', None, u'The description for the shortcut.'), +(u'Shortcut', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Foreign key into the Component table denoting the component whose selection gates the the shortcut creation/deletion.'), +(u'Shortcut', u'Icon_', u'Y', None, None, u'Icon', 1, u'Identifier', None, u'Foreign key into the File table denoting the external icon file for the shortcut.'), +(u'Shortcut', u'IconIndex', u'Y', -32767, 32767, None, None, None, None, u'The icon index for the shortcut.'), +(u'Shortcut', u'Directory_', u'N', None, None, u'Directory', 1, u'Identifier', None, u'Foreign key into the Directory table denoting the directory where the shortcut file is created.'), +(u'Shortcut', u'Target', u'N', None, None, None, None, u'Shortcut', None, u'The shortcut target. This is usually a property that is expanded to a file or a folder that the shortcut points to.'), +(u'Shortcut', u'Arguments', u'Y', None, None, None, None, u'Formatted', None, u'The command-line arguments for the shortcut.'), +(u'Shortcut', u'Shortcut', u'N', None, None, None, None, u'Identifier', None, u'Primary key, non-localized token.'), +(u'Shortcut', u'Hotkey', u'Y', 0, 32767, None, None, None, None, u'The hotkey for the shortcut. It has the virtual-key code for the key in the low-order byte, and the modifier flags in the high-order byte. '), +(u'Shortcut', u'ShowCmd', u'Y', None, None, None, None, None, u'1;3;7', u'The show command for the application window.The following values may be used.'), +(u'Shortcut', u'WkDir', u'Y', None, None, None, None, u'Identifier', None, u'Name of property defining location of working directory.'), +(u'Signature', u'FileName', u'N', None, None, None, None, u'Filename', None, u'The name of the file. This may contain a "short name|long name" pair.'), +(u'Signature', u'Signature', u'N', None, None, None, None, u'Identifier', None, u'The table key. The Signature represents a unique file signature.'), +(u'Signature', u'Languages', u'Y', None, None, None, None, u'Language', None, u'The languages supported by the file.'), +(u'Signature', u'MaxDate', u'Y', 0, 2147483647, None, None, None, None, u'The maximum creation date of the file.'), +(u'Signature', u'MaxSize', u'Y', 0, 2147483647, None, None, None, None, u'The maximum size of the file. '), +(u'Signature', u'MaxVersion', u'Y', None, None, None, None, u'Text', None, u'The maximum version of the file.'), +(u'Signature', u'MinDate', u'Y', 0, 2147483647, None, None, None, None, u'The minimum creation date of the file.'), +(u'Signature', u'MinSize', u'Y', 0, 2147483647, None, None, None, None, u'The minimum size of the file.'), +(u'Signature', u'MinVersion', u'Y', None, None, None, None, u'Text', None, u'The minimum version of the file.'), +(u'TypeLib', u'Feature_', u'N', None, None, u'Feature', 1, u'Identifier', None, u'Required foreign key into the Feature Table, specifying the feature to validate or install in order for the type library to be operational.'), +(u'TypeLib', u'Description', u'Y', None, None, None, None, u'Text', None, None), +(u'TypeLib', u'Component_', u'N', None, None, u'Component', 1, u'Identifier', None, u'Required foreign key into the Component Table, specifying the component for which to return a path when called through LocateComponent.'), +(u'TypeLib', u'Directory_', u'Y', None, None, u'Directory', 1, u'Identifier', None, u'Optional. The foreign key into the Directory table denoting the path to the help file for the type library.'), +(u'TypeLib', u'Language', u'N', 0, 32767, None, None, None, None, u'The language of the library.'), +(u'TypeLib', u'Version', u'Y', 0, 16777215, None, None, None, None, u'The version of the library. The minor version is in the lower 8 bits of the integer. The major version is in the next 16 bits. '), +(u'TypeLib', u'Cost', u'Y', 0, 2147483647, None, None, None, None, u'The cost associated with the registration of the typelib. This column is currently optional.'), +(u'TypeLib', u'LibID', u'N', None, None, None, None, u'Guid', None, u'The GUID that represents the library.'), +(u'Upgrade', u'Attributes', u'N', 0, 2147483647, None, None, None, None, u'The attributes of this product set.'), +(u'Upgrade', u'Remove', u'Y', None, None, None, None, u'Formatted', None, u'The list of features to remove when uninstalling a product from this set. The default is "ALL".'), +(u'Upgrade', u'Language', u'Y', None, None, None, None, u'Language', None, u'A comma-separated list of languages for either products in this set or products not in this set.'), +(u'Upgrade', u'ActionProperty', u'N', None, None, None, None, u'UpperCase', None, u'The property to set when a product in this set is found.'), +(u'Upgrade', u'UpgradeCode', u'N', None, None, None, None, u'Guid', None, u'The UpgradeCode GUID belonging to the products in this set.'), +(u'Upgrade', u'VersionMax', u'Y', None, None, None, None, u'Text', None, u'The maximum ProductVersion of the products in this set. The set may or may not include products with this particular version.'), +(u'Upgrade', u'VersionMin', u'Y', None, None, None, None, u'Text', None, u'The minimum ProductVersion of the products in this set. The set may or may not include products with this particular version.'), +(u'Verb', u'Sequence', u'Y', 0, 32767, None, None, None, None, u'Order within the verbs for a particular extension. Also used simply to specify the default verb.'), +(u'Verb', u'Argument', u'Y', None, None, None, None, u'Formatted', None, u'Optional value for the command arguments.'), +(u'Verb', u'Extension_', u'N', None, None, u'Extension', 1, u'Text', None, u'The extension associated with the table row.'), +(u'Verb', u'Verb', u'N', None, None, None, None, u'Text', None, u'The verb for the command.'), +(u'Verb', u'Command', u'Y', None, None, None, None, u'Formatted', None, u'The command text.'), +] + +Error = [ +(0, u'{{Fatal error: }}'), +(1, u'{{Error [1]. }}'), +(2, u'Warning [1]. '), +(3, None), +(4, u'Info [1]. '), +(5, u'The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is [1]. {{The arguments are: [2], [3], [4]}}'), +(6, None), +(7, u'{{Disk full: }}'), +(8, u'Action [Time]: [1]. [2]'), +(9, u'[ProductName]'), +(10, u'{[2]}{, [3]}{, [4]}'), +(11, u'Message type: [1], Argument: [2]'), +(12, u'=== Logging started: [Date] [Time] ==='), +(13, u'=== Logging stopped: [Date] [Time] ==='), +(14, u'Action start [Time]: [1].'), +(15, u'Action ended [Time]: [1]. Return value [2].'), +(16, u'Time remaining: {[1] minutes }{[2] seconds}'), +(17, u'Out of memory. Shut down other applications before retrying.'), +(18, u'Installer is no longer responding.'), +(19, u'Installer stopped prematurely.'), +(20, u'Please wait while Windows configures [ProductName]'), +(21, u'Gathering required information...'), +(22, u'Removing older versions of this application...'), +(23, u'Preparing to remove older versions of this application...'), +(32, u'{[ProductName] }Setup completed successfully.'), +(33, u'{[ProductName] }Setup failed.'), +(1101, u'Error reading from file: [2]. {{ System error [3].}} Verify that the file exists and that you can access it.'), +(1301, u"Cannot create the file '[2]'. A directory with this name already exists. Cancel the install and try installing to a different location."), +(1302, u'Please insert the disk: [2]'), +(1303, u'The installer has insufficient privileges to access this directory: [2]. The installation cannot continue. Log on as administrator or contact your system administrator.'), +(1304, u'Error writing to file: [2]. Verify that you have access to that directory.'), +(1305, u'Error reading from file [2]. {{ System error [3].}} Verify that the file exists and that you can access it.'), +(1306, u"Another application has exclusive access to the file '[2]'. Please shut down all other applications, then click Retry."), +(1307, u'There is not enough disk space to install this file: [2]. Free some disk space and click Retry, or click Cancel to exit.'), +(1308, u'Source file not found: [2]. Verify that the file exists and that you can access it.'), +(1309, u'Error reading from file: [3]. {{ System error [2].}} Verify that the file exists and that you can access it.'), +(1310, u'Error writing to file: [3]. {{ System error [2].}} Verify that you have access to that directory.'), +(1311, u'Source file not found{{(cabinet)}}: [2]. Verify that the file exists and that you can access it.'), +(1312, u"Cannot create the directory '[2]'. A file with this name already exists. Please rename or remove the file and click retry, or click Cancel to exit."), +(1313, u'The volume [2] is currently unavailable. Please select another.'), +(1314, u"The specified path '[2]' is unavailable."), +(1315, u'Unable to write to the specified folder: [2].'), +(1316, u'A network error occurred while attempting to read from the file: [2]'), +(1317, u'An error occurred while attempting to create the directory: [2]'), +(1318, u'A network error occurred while attempting to create the directory: [2]'), +(1319, u'A network error occurred while attempting to open the source file cabinet: [2]'), +(1320, u'The specified path is too long: [2]'), +(1321, u'The Installer has insufficient privileges to modify this file: [2].'), +(1322, u"A portion of the folder path '[2]' is invalid. It is either empty or exceeds the length allowed by the system."), +(1323, u"The folder path '[2]' contains words that are not valid in folder paths."), +(1324, u"The folder path '[2]' contains an invalid character."), +(1325, u"'[2]' is not a valid short file name."), +(1326, u'Error getting file security: [3] GetLastError: [2]'), +(1327, u'Invalid Drive: [2]'), +(1328, u'Error applying patch to file [2]. It has probably been updated by other means, and can no longer be modified by this patch. For more information contact your patch vendor. {{System Error: [3]}}'), +(1329, u'A file that is required cannot be installed because the cabinet file [2] is not digitally signed. This may indicate that the cabinet file is corrupt.'), +(1330, u'A file that is required cannot be installed because the cabinet file [2] has an invalid digital signature. This may indicate that the cabinet file is corrupt.{{ Error [3] was returned by WinVerifyTrust.}}'), +(1331, u'Failed to correctly copy [2] file: CRC error.'), +(1332, u'Failed to correctly move [2] file: CRC error.'), +(1333, u'Failed to correctly patch [2] file: CRC error.'), +(1334, u"The file '[2]' cannot be installed because the file cannot be found in cabinet file '[3]'. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package."), +(1335, u"The cabinet file '[2]' required for this installation is corrupt and cannot be used. This could indicate a network error, an error reading from the CD-ROM, or a problem with this package."), +(1336, u'There was an error creating a temporary file that is needed to complete this installation.{{ Folder: [3]. System error code: [2]}}'), +(1401, u'Could not create key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. '), +(1402, u'Could not open key: [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. '), +(1403, u'Could not delete value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. '), +(1404, u'Could not delete key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel. '), +(1405, u'Could not read value [2] from key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel. '), +(1406, u'Could not write value [2] to key [3]. {{ System error [4].}} Verify that you have sufficient access to that key, or contact your support personnel.'), +(1407, u'Could not get value names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.'), +(1408, u'Could not get sub key names for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.'), +(1409, u'Could not read security information for key [2]. {{ System error [3].}} Verify that you have sufficient access to that key, or contact your support personnel.'), +(1410, u'Could not increase the available registry space. [2] KB of free registry space is required for the installation of this application.'), +(1500, u'Another installation is in progress. You must complete that installation before continuing this one.'), +(1501, u'Error accessing secured data. Please make sure the Windows Installer is configured properly and try the install again.'), +(1502, u"User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product. Your current install will now continue."), +(1503, u"User '[2]' has previously initiated an install for product '[3]'. That user will need to run that install again before they can use that product."), +(1601, u"Out of disk space -- Volume: '[2]'; required space: [3] KB; available space: [4] KB. Free some disk space and retry."), +(1602, u'Are you sure you want to cancel?'), +(1603, u"The file [2][3] is being held in use{ by the following process: Name: [4], Id: [5], Window Title: '[6]'}. Close that application and retry."), +(1604, u"The product '[2]' is already installed, preventing the installation of this product. The two products are incompatible."), +(1605, u"There is not enough disk space on the volume '[2]' to continue the install with recovery enabled. [3] KB are required, but only [4] KB are available. Click Ignore to continue the install without saving recovery information, click Retry to check for available space again, or click Cancel to quit the installation."), +(1606, u'Could not access network location [2].'), +(1607, u'The following applications should be closed before continuing the install:'), +(1608, u'Could not find any previously installed compliant products on the machine for installing this product.'), +(1609, u"An error occurred while applying security settings. [2] is not a valid user or group. This could be a problem with the package, or a problem connecting to a domain controller on the network. Check your network connection and click Retry, or Cancel to end the install. {{Unable to locate the user's SID, system error [3]}}"), +(1701, u'The key [2] is not valid. Verify that you entered the correct key.'), +(1702, u'The installer must restart your system before configuration of [2] can continue. Click Yes to restart now or No if you plan to manually restart later.'), +(1703, u'You must restart your system for the configuration changes made to [2] to take effect. Click Yes to restart now or No if you plan to manually restart later.'), +(1704, u'An installation for [2] is currently suspended. You must undo the changes made by that installation to continue. Do you want to undo those changes?'), +(1705, u'A previous installation for this product is in progress. You must undo the changes made by that installation to continue. Do you want to undo those changes?'), +(1706, u"An installation package for the product [2] cannot be found. Try the installation again using a valid copy of the installation package '[3]'."), +(1707, u'Installation completed successfully.'), +(1708, u'Installation failed.'), +(1709, u'Product: [2] -- [3]'), +(1710, u'You may either restore your computer to its previous state or continue the install later. Would you like to restore?'), +(1711, u'An error occurred while writing installation information to disk. Check to make sure enough disk space is available, and click Retry, or Cancel to end the install.'), +(1712, u'One or more of the files required to restore your computer to its previous state could not be found. Restoration will not be possible.'), +(1713, u'[2] cannot install one of its required products. Contact your technical support group. {{System Error: [3].}}'), +(1714, u'The older version of [2] cannot be removed. Contact your technical support group. {{System Error [3].}}'), +(1715, u'Installed [2]'), +(1716, u'Configured [2]'), +(1717, u'Removed [2]'), +(1718, u'File [2] was rejected by digital signature policy.'), +(1719, u'The Windows Installer Service could not be accessed. This can occur if you are running Windows in safe mode, or if the Windows Installer is not correctly installed. Contact your support personnel for assistance.'), +(1720, u'There is a problem with this Windows Installer package. A script required for this install to complete could not be run. Contact your support personnel or package vendor. {{Custom action [2] script error [3], [4]: [5] Line [6], Column [7], [8] }}'), +(1721, u'There is a problem with this Windows Installer package. A program required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action: [2], location: [3], command: [4] }}'), +(1722, u'There is a problem with this Windows Installer package. A program run as part of the setup did not finish as expected. Contact your support personnel or package vendor. {{Action [2], location: [3], command: [4] }}'), +(1723, u'There is a problem with this Windows Installer package. A DLL required for this install to complete could not be run. Contact your support personnel or package vendor. {{Action [2], entry: [3], library: [4] }}'), +(1724, u'Removal completed successfully.'), +(1725, u'Removal failed.'), +(1726, u'Advertisement completed successfully.'), +(1727, u'Advertisement failed.'), +(1728, u'Configuration completed successfully.'), +(1729, u'Configuration failed.'), +(1730, u'You must be an Administrator to remove this application. To remove this application, you can log on as an Administrator, or contact your technical support group for assistance.'), +(1801, u'The path [2] is not valid. Please specify a valid path.'), +(1802, u'Out of memory. Shut down other applications before retrying.'), +(1803, u'There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to go back to the previously selected volume.'), +(1804, u'There is no disk in drive [2]. Please insert one and click Retry, or click Cancel to return to the browse dialog and select a different volume.'), +(1805, u'The folder [2] does not exist. Please enter a path to an existing folder.'), +(1806, u'You have insufficient privileges to read this folder.'), +(1807, u'A valid destination folder for the install could not be determined.'), +(1901, u'Error attempting to read from the source install database: [2].'), +(1902, u'Scheduling reboot operation: Renaming file [2] to [3]. Must reboot to complete operation.'), +(1903, u'Scheduling reboot operation: Deleting file [2]. Must reboot to complete operation.'), +(1904, u'Module [2] failed to register. HRESULT [3]. Contact your support personnel.'), +(1905, u'Module [2] failed to unregister. HRESULT [3]. Contact your support personnel.'), +(1906, u'Failed to cache package [2]. Error: [3]. Contact your support personnel.'), +(1907, u'Could not register font [2]. Verify that you have sufficient permissions to install fonts, and that the system supports this font.'), +(1908, u'Could not unregister font [2]. Verify that you that you have sufficient permissions to remove fonts.'), +(1909, u'Could not create Shortcut [2]. Verify that the destination folder exists and that you can access it.'), +(1910, u'Could not remove Shortcut [2]. Verify that the shortcut file exists and that you can access it.'), +(1911, u'Could not register type library for file [2]. Contact your support personnel.'), +(1912, u'Could not unregister type library for file [2]. Contact your support personnel.'), +(1913, u'Could not update the ini file [2][3]. Verify that the file exists and that you can access it.'), +(1914, u'Could not schedule file [2] to replace file [3] on reboot. Verify that you have write permissions to file [3].'), +(1915, u'Error removing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.'), +(1916, u'Error installing ODBC driver manager, ODBC error [2]: [3]. Contact your support personnel.'), +(1917, u'Error removing ODBC driver: [4], ODBC error [2]: [3]. Verify that you have sufficient privileges to remove ODBC drivers.'), +(1918, u'Error installing ODBC driver: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.'), +(1919, u'Error configuring ODBC data source: [4], ODBC error [2]: [3]. Verify that the file [4] exists and that you can access it.'), +(1920, u"Service '[2]' ([3]) failed to start. Verify that you have sufficient privileges to start system services."), +(1921, u"Service '[2]' ([3]) could not be stopped. Verify that you have sufficient privileges to stop system services."), +(1922, u"Service '[2]' ([3]) could not be deleted. Verify that you have sufficient privileges to remove system services."), +(1923, u"Service '[2]' ([3]) could not be installed. Verify that you have sufficient privileges to install system services."), +(1924, u"Could not update environment variable '[2]'. Verify that you have sufficient privileges to modify environment variables."), +(1925, u'You do not have sufficient privileges to complete this installation for all users of the machine. Log on as administrator and then retry this installation.'), +(1926, u"Could not set file security for file '[3]'. Error: [2]. Verify that you have sufficient privileges to modify the security permissions for this file."), +(1927, u'Component Services (COM+ 1.0) are not installed on this computer. This installation requires Component Services in order to complete successfully. Component Services are available on Windows 2000.'), +(1928, u'Error registering COM+ Application. Contact your support personnel for more information.'), +(1929, u'Error unregistering COM+ Application. Contact your support personnel for more information.'), +(1930, u"The description for service '[2]' ([3]) could not be changed."), +(1931, u'The Windows Installer service cannot update the system file [2] because the file is protected by Windows. You may need to update your operating system for this program to work correctly. {{Package version: [3], OS Protected version: [4]}}'), +(1932, u'The Windows Installer service cannot update the protected Windows file [2]. {{Package version: [3], OS Protected version: [4], SFP Error: [5]}}'), +(1933, u'The Windows Installer service cannot update one or more protected Windows files. {{SFP Error: [2]. List of protected files:\\r\\n[3]}}'), +(1934, u'User installations are disabled via policy on the machine.'), +(1935, u'An error occurred during the installation of assembly component [2]. HRESULT: [3]. {{assembly interface: [4], function: [5], assembly name: [6]}}'), +] + +tables=['AdminExecuteSequence', 'AdminUISequence', 'AdvtExecuteSequence', 'BBControl', 'Billboard', 'Binary', 'CheckBox', 'Property', 'ComboBox', 'Control', 'ListBox', 'ActionText', 'ControlCondition', 'ControlEvent', 'Dialog', 'EventMapping', 'InstallExecuteSequence', 'InstallUISequence', 'ListView', 'RadioButton', 'TextStyle', 'UIText', '_Validation', 'Error'] diff --git a/sys/src/cmd/python/Tools/msi/uuids.py b/sys/src/cmd/python/Tools/msi/uuids.py new file mode 100644 index 000000000..b8adac69e --- /dev/null +++ b/sys/src/cmd/python/Tools/msi/uuids.py @@ -0,0 +1,38 @@ +# This should be extended for each Python release. +# The product code must change whenever the name of the MSI file +# changes, and when new component codes are issued for existing +# components. See "Changing the Product Code". As we change the +# component codes with every build, we need a new product code +# each time. For intermediate (snapshot) releases, they are automatically +# generated. For official releases, we record the product codes, +# so people can refer to them. +product_codes = { + '2.4.101': '{0e9b4d8e-6cda-446e-a208-7b92f3ddffa0}', # 2.4a1, released as a snapshot + '2.4.102': '{1b998745-4901-4edb-bc52-213689e1b922}', # 2.4a2 + '2.4.103': '{33fc8bd2-1e8f-4add-a40a-ade2728d5942}', # 2.4a3 + '2.4.111': '{51a7e2a8-2025-4ef0-86ff-e6aab742d1fa}', # 2.4b1 + '2.4.112': '{4a5e7c1d-c659-4fe3-b8c9-7c65bd9c95a5}', # 2.4b2 + '2.4.121': '{75508821-a8e9-40a8-95bd-dbe6033ddbea}', # 2.4c1 + '2.4.122': '{83a9118b-4bdd-473b-afc3-bcb142feca9e}', # 2.4c2 + '2.4.150': '{82d9302e-f209-4805-b548-52087047483a}', # 2.4.0 + '2.4.1121':'{be027411-8e6b-4440-a29b-b07df0690230}', # 2.4.1c1 + '2.4.1122':'{02818752-48bf-4074-a281-7a4114c4f1b1}', # 2.4.1c2 + '2.4.1150':'{4d4f5346-7e4a-40b5-9387-fdb6181357fc}', # 2.4.1 + '2.4.2121':'{5ef9d6b6-df78-45d2-ab09-14786a3c5a99}', # 2.4.2c1 + '2.4.2150':'{b191e49c-ea23-43b2-b28a-14e0784069b8}', # 2.4.2 + '2.4.3121':'{f669ed4d-1dce-41c4-9617-d985397187a1}', # 2.4.3c1 + '2.4.3150':'{75e71add-042c-4f30-bfac-a9ec42351313}', # 2.4.3 + '2.5.101': '{bc14ce3e-5e72-4a64-ac1f-bf59a571898c}', # 2.5a1 + '2.5.102': '{5eed51c1-8e9d-4071-94c5-b40de5d49ba5}', # 2.5a2 + '2.5.103': '{73dcd966-ffec-415f-bb39-8342c1f47017}', # 2.5a3 + '2.5.111': '{c797ecf8-a8e6-4fec-bb99-526b65f28626}', # 2.5b1 + '2.5.112': '{32beb774-f625-439d-b587-7187487baf15}', # 2.5b2 + '2.5.113': '{89f23918-11cf-4f08-be13-b9b2e6463fd9}', # 2.5b3 + '2.5.121': '{8e9321bc-6b24-48a3-8fd4-c95f8e531e5f}', # 2.5c1 + '2.5.122': '{a6cd508d-9599-45da-a441-cbffa9f7e070}', # 2.5c2 + '2.5.150': '{0a2c5854-557e-48c8-835a-3b9f074bdcaa}', # 2.5.0 + '2.5.1121':'{0378b43e-6184-4c2f-be1a-4a367781cd54}', # 2.5.1c1 + '2.5.1150':'{31800004-6386-4999-a519-518f2d78d8f0}', # 2.5.1 + '2.5.2150':'{6304a7da-1132-4e91-a343-a296269eab8a}', # 2.5.2c1 + '2.5.2150':'{6b976adf-8ae8-434e-b282-a06c7f624d2f}', # 2.5.2 +} diff --git a/sys/src/cmd/python/Tools/pybench/Arithmetic.py b/sys/src/cmd/python/Tools/pybench/Arithmetic.py new file mode 100644 index 000000000..6923b4b49 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Arithmetic.py @@ -0,0 +1,777 @@ +from pybench import Test + +class SimpleIntegerArithmetic(Test): + + version = 2.0 + operations = 5 * (3 + 5 + 5 + 3 + 3 + 3) + rounds = 120000 + + def test(self): + + for i in xrange(self.rounds): + + a = 2 + b = 3 + c = 3 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + def calibrate(self): + + for i in xrange(self.rounds): + pass + +class SimpleFloatArithmetic(Test): + + version = 2.0 + operations = 5 * (3 + 5 + 5 + 3 + 3 + 3) + rounds = 120000 + + def test(self): + + for i in xrange(self.rounds): + + a = 2.1 + b = 3.3332 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2.1 + b = 3.3332 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2.1 + b = 3.3332 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2.1 + b = 3.3332 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2.1 + b = 3.3332 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + def calibrate(self): + + for i in xrange(self.rounds): + pass + +class SimpleIntFloatArithmetic(Test): + + version = 2.0 + operations = 5 * (3 + 5 + 5 + 3 + 3 + 3) + rounds = 120000 + + def test(self): + + for i in xrange(self.rounds): + + a = 2 + b = 3 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + b = 3 + c = 3.14159 + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + def calibrate(self): + + for i in xrange(self.rounds): + pass + + +class SimpleLongArithmetic(Test): + + version = 2.0 + operations = 5 * (3 + 5 + 5 + 3 + 3 + 3) + rounds = 60000 + + def test(self): + + for i in xrange(self.rounds): + + a = 2220001L + b = 100001L + c = 30005L + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2220001L + b = 100001L + c = 30005L + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2220001L + b = 100001L + c = 30005L + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2220001L + b = 100001L + c = 30005L + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2220001L + b = 100001L + c = 30005L + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + def calibrate(self): + + for i in xrange(self.rounds): + pass + +class SimpleComplexArithmetic(Test): + + version = 2.0 + operations = 5 * (3 + 5 + 5 + 3 + 3 + 3) + rounds = 80000 + + def test(self): + + for i in xrange(self.rounds): + + a = 2 + 3j + b = 2.5 + 4.5j + c = 1.2 + 6.2j + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + 3j + b = 2.5 + 4.5j + c = 1.2 + 6.2j + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + 3j + b = 2.5 + 4.5j + c = 1.2 + 6.2j + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + 3j + b = 2.5 + 4.5j + c = 1.2 + 6.2j + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + a = 2 + 3j + b = 2.5 + 4.5j + c = 1.2 + 6.2j + + c = a + b + c = b + c + c = c + a + c = a + b + c = b + c + + c = c - a + c = a - b + c = b - c + c = c - a + c = b - c + + c = a / b + c = b / a + c = c / b + + c = a * b + c = b * a + c = c * b + + c = a / b + c = b / a + c = c / b + + def calibrate(self): + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Calls.py b/sys/src/cmd/python/Tools/pybench/Calls.py new file mode 100644 index 000000000..72ccd0eaa --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Calls.py @@ -0,0 +1,502 @@ +from pybench import Test + +class PythonFunctionCalls(Test): + + version = 2.0 + operations = 5*(1+4+4+2) + rounds = 60000 + + def test(self): + + global f,f1,g,h + + # define functions + def f(): + pass + + def f1(x): + pass + + def g(a,b,c): + return a,b,c + + def h(a,b,c,d=1,e=2,f=3): + return d,e,f + + # do calls + for i in xrange(self.rounds): + + f() + f1(i) + f1(i) + f1(i) + f1(i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + h(i,i,3,i,i) + h(i,i,i,2,i,3) + + f() + f1(i) + f1(i) + f1(i) + f1(i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + h(i,i,3,i,i) + h(i,i,i,2,i,3) + + f() + f1(i) + f1(i) + f1(i) + f1(i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + h(i,i,3,i,i) + h(i,i,i,2,i,3) + + f() + f1(i) + f1(i) + f1(i) + f1(i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + h(i,i,3,i,i) + h(i,i,i,2,i,3) + + f() + f1(i) + f1(i) + f1(i) + f1(i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + g(i,i,i) + h(i,i,3,i,i) + h(i,i,i,2,i,3) + + def calibrate(self): + + global f,f1,g,h + + # define functions + def f(): + pass + + def f1(x): + pass + + def g(a,b,c): + return a,b,c + + def h(a,b,c,d=1,e=2,f=3): + return d,e,f + + # do calls + for i in xrange(self.rounds): + pass + +### + +class BuiltinFunctionCalls(Test): + + version = 2.0 + operations = 5*(2+5+5+5) + rounds = 60000 + + def test(self): + + # localize functions + f0 = globals + f1 = hash + f2 = cmp + f3 = range + + # do calls + for i in xrange(self.rounds): + + f0() + f0() + f1(i) + f1(i) + f1(i) + f1(i) + f1(i) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + + f0() + f0() + f1(i) + f1(i) + f1(i) + f1(i) + f1(i) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + + f0() + f0() + f1(i) + f1(i) + f1(i) + f1(i) + f1(i) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + + f0() + f0() + f1(i) + f1(i) + f1(i) + f1(i) + f1(i) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + + f0() + f0() + f1(i) + f1(i) + f1(i) + f1(i) + f1(i) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f2(1,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + f3(1,3,2) + + def calibrate(self): + + # localize functions + f0 = dir + f1 = hash + f2 = range + f3 = range + + # do calls + for i in xrange(self.rounds): + pass + +### + +class PythonMethodCalls(Test): + + version = 2.0 + operations = 5*(6 + 5 + 4) + rounds = 30000 + + def test(self): + + class c: + + x = 2 + s = 'string' + + def f(self): + + return self.x + + def j(self,a,b): + + self.y = a + self.t = b + return self.y + + def k(self,a,b,c=3): + + self.y = a + self.s = b + self.t = c + + o = c() + + for i in xrange(self.rounds): + + o.f() + o.f() + o.f() + o.f() + o.f() + o.f() + o.j(i,i) + o.j(i,i) + o.j(i,2) + o.j(i,2) + o.j(2,2) + o.k(i,i) + o.k(i,2) + o.k(i,2,3) + o.k(i,i,c=4) + + o.f() + o.f() + o.f() + o.f() + o.f() + o.f() + o.j(i,i) + o.j(i,i) + o.j(i,2) + o.j(i,2) + o.j(2,2) + o.k(i,i) + o.k(i,2) + o.k(i,2,3) + o.k(i,i,c=4) + + o.f() + o.f() + o.f() + o.f() + o.f() + o.f() + o.j(i,i) + o.j(i,i) + o.j(i,2) + o.j(i,2) + o.j(2,2) + o.k(i,i) + o.k(i,2) + o.k(i,2,3) + o.k(i,i,c=4) + + o.f() + o.f() + o.f() + o.f() + o.f() + o.f() + o.j(i,i) + o.j(i,i) + o.j(i,2) + o.j(i,2) + o.j(2,2) + o.k(i,i) + o.k(i,2) + o.k(i,2,3) + o.k(i,i,c=4) + + o.f() + o.f() + o.f() + o.f() + o.f() + o.f() + o.j(i,i) + o.j(i,i) + o.j(i,2) + o.j(i,2) + o.j(2,2) + o.k(i,i) + o.k(i,2) + o.k(i,2,3) + o.k(i,i,c=4) + + def calibrate(self): + + class c: + + x = 2 + s = 'string' + + def f(self): + + return self.x + + def j(self,a,b): + + self.y = a + self.t = b + + def k(self,a,b,c=3): + + self.y = a + self.s = b + self.t = c + + o = c + + for i in xrange(self.rounds): + pass + +### + +class Recursion(Test): + + version = 2.0 + operations = 5 + rounds = 100000 + + def test(self): + + global f + + def f(x): + + if x > 1: + return f(x-1) + return 1 + + for i in xrange(self.rounds): + f(10) + f(10) + f(10) + f(10) + f(10) + + def calibrate(self): + + global f + + def f(x): + + if x > 0: + return f(x-1) + return 1 + + for i in xrange(self.rounds): + pass + + +### Test to make Fredrik happy... + +if __name__ == '__main__': + import timeit + if 0: + timeit.TestClass = PythonFunctionCalls + timeit.main(['-s', 'test = TestClass(); test.rounds = 1000', + 'test.test()']) + else: + setup = """\ +global f,f1,g,h + +# define functions +def f(): + pass + +def f1(x): + pass + +def g(a,b,c): + return a,b,c + +def h(a,b,c,d=1,e=2,f=3): + return d,e,f + +i = 1 +""" + test = """\ +f() +f1(i) +f1(i) +f1(i) +f1(i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +h(i,i,3,i,i) +h(i,i,i,2,i,3) + +f() +f1(i) +f1(i) +f1(i) +f1(i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +h(i,i,3,i,i) +h(i,i,i,2,i,3) + +f() +f1(i) +f1(i) +f1(i) +f1(i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +h(i,i,3,i,i) +h(i,i,i,2,i,3) + +f() +f1(i) +f1(i) +f1(i) +f1(i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +h(i,i,3,i,i) +h(i,i,i,2,i,3) + +f() +f1(i) +f1(i) +f1(i) +f1(i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +g(i,i,i) +h(i,i,3,i,i) +h(i,i,i,2,i,3) +""" + + timeit.main(['-s', setup, + test]) diff --git a/sys/src/cmd/python/Tools/pybench/CommandLine.py b/sys/src/cmd/python/Tools/pybench/CommandLine.py new file mode 100644 index 000000000..6601be5fb --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/CommandLine.py @@ -0,0 +1,634 @@ +""" CommandLine - Get and parse command line options + + NOTE: This still is very much work in progress !!! + + Different version are likely to be incompatible. + + TODO: + + * Incorporate the changes made by (see Inbox) + * Add number range option using srange() + +""" + +__copyright__ = """\ +Copyright (c), 1997-2006, Marc-Andre Lemburg (mal@lemburg.com) +Copyright (c), 2000-2006, eGenix.com Software GmbH (info@egenix.com) +See the documentation for further information on copyrights, +or contact the author. All Rights Reserved. +""" + +__version__ = '1.2' + +import sys, getopt, string, glob, os, re, exceptions, traceback + +### Helpers + +def _getopt_flags(options): + + """ Convert the option list to a getopt flag string and long opt + list + + """ + s = [] + l = [] + for o in options: + if o.prefix == '-': + # short option + s.append(o.name) + if o.takes_argument: + s.append(':') + else: + # long option + if o.takes_argument: + l.append(o.name+'=') + else: + l.append(o.name) + return string.join(s,''),l + +def invisible_input(prompt='>>> '): + + """ Get raw input from a terminal without echoing the characters to + the terminal, e.g. for password queries. + + """ + import getpass + entry = getpass.getpass(prompt) + if entry is None: + raise KeyboardInterrupt + return entry + +def fileopen(name, mode='wb', encoding=None): + + """ Open a file using mode. + + Default mode is 'wb' meaning to open the file for writing in + binary mode. If encoding is given, I/O to and from the file is + transparently encoded using the given encoding. + + Files opened for writing are chmod()ed to 0600. + + """ + if name == 'stdout': + return sys.stdout + elif name == 'stderr': + return sys.stderr + elif name == 'stdin': + return sys.stdin + else: + if encoding is not None: + import codecs + f = codecs.open(name, mode, encoding) + else: + f = open(name, mode) + if 'w' in mode: + os.chmod(name, 0600) + return f + +def option_dict(options): + + """ Return a dictionary mapping option names to Option instances. + """ + d = {} + for option in options: + d[option.name] = option + return d + +# Alias +getpasswd = invisible_input + +_integerRE = re.compile('\s*(-?\d+)\s*$') +_integerRangeRE = re.compile('\s*(-?\d+)\s*-\s*(-?\d+)\s*$') + +def srange(s, + + split=string.split,integer=_integerRE, + integerRange=_integerRangeRE): + + """ Converts a textual representation of integer numbers and ranges + to a Python list. + + Supported formats: 2,3,4,2-10,-1 - -3, 5 - -2 + + Values are appended to the created list in the order specified + in the string. + + """ + l = [] + append = l.append + for entry in split(s,','): + m = integer.match(entry) + if m: + append(int(m.groups()[0])) + continue + m = integerRange.match(entry) + if m: + start,end = map(int,m.groups()) + l[len(l):] = range(start,end+1) + return l + +def abspath(path, + + expandvars=os.path.expandvars,expanduser=os.path.expanduser, + join=os.path.join,getcwd=os.getcwd): + + """ Return the corresponding absolute path for path. + + path is expanded in the usual shell ways before + joining it with the current working directory. + + """ + try: + path = expandvars(path) + except AttributeError: + pass + try: + path = expanduser(path) + except AttributeError: + pass + return join(getcwd(), path) + +### Option classes + +class Option: + + """ Option base class. Takes no argument. + + """ + default = None + helptext = '' + prefix = '-' + takes_argument = 0 + has_default = 0 + tab = 15 + + def __init__(self,name,help=None): + + if not name[:1] == '-': + raise TypeError,'option names must start with "-"' + if name[1:2] == '-': + self.prefix = '--' + self.name = name[2:] + else: + self.name = name[1:] + if help: + self.help = help + + def __str__(self): + + o = self + name = o.prefix + o.name + if o.takes_argument: + name = name + ' arg' + if len(name) > self.tab: + name = name + '\n' + ' ' * (self.tab + 1 + len(o.prefix)) + else: + name = '%-*s ' % (self.tab, name) + description = o.help + if o.has_default: + description = description + ' (%s)' % o.default + return '%s %s' % (name, description) + +class ArgumentOption(Option): + + """ Option that takes an argument. + + An optional default argument can be given. + + """ + def __init__(self,name,help=None,default=None): + + # Basemethod + Option.__init__(self,name,help) + + if default is not None: + self.default = default + self.has_default = 1 + self.takes_argument = 1 + +class SwitchOption(Option): + + """ Options that can be on or off. Has an optional default value. + + """ + def __init__(self,name,help=None,default=None): + + # Basemethod + Option.__init__(self,name,help) + + if default is not None: + self.default = default + self.has_default = 1 + +### Application baseclass + +class Application: + + """ Command line application interface with builtin argument + parsing. + + """ + # Options the program accepts (Option instances) + options = [] + + # Standard settings; these are appended to options in __init__ + preset_options = [SwitchOption('-v', + 'generate verbose output'), + SwitchOption('-h', + 'show this help text'), + SwitchOption('--help', + 'show this help text'), + SwitchOption('--debug', + 'enable debugging'), + SwitchOption('--copyright', + 'show copyright'), + SwitchOption('--examples', + 'show examples of usage')] + + # The help layout looks like this: + # [header] - defaults to '' + # + # [synopsis] - formatted as '<self.name> %s' % self.synopsis + # + # options: + # [options] - formatted from self.options + # + # [version] - formatted as 'Version:\n %s' % self.version, if given + # + # [about] - defaults to '' + # + # Note: all fields that do not behave as template are formatted + # using the instances dictionary as substitution namespace, + # e.g. %(name)s will be replaced by the applications name. + # + + # Header (default to program name) + header = '' + + # Name (defaults to program name) + name = '' + + # Synopsis (%(name)s is replaced by the program name) + synopsis = '%(name)s [option] files...' + + # Version (optional) + version = '' + + # General information printed after the possible options (optional) + about = '' + + # Examples of usage to show when the --examples option is given (optional) + examples = '' + + # Copyright to show + copyright = __copyright__ + + # Apply file globbing ? + globbing = 1 + + # Generate debug output ? + debug = 0 + + # Generate verbose output ? + verbose = 0 + + # Internal errors to catch + InternalError = exceptions.Exception + + # Instance variables: + values = None # Dictionary of passed options (or default values) + # indexed by the options name, e.g. '-h' + files = None # List of passed filenames + optionlist = None # List of passed options + + def __init__(self,argv=None): + + # Setup application specs + if argv is None: + argv = sys.argv + self.filename = os.path.split(argv[0])[1] + if not self.name: + self.name = os.path.split(self.filename)[1] + else: + self.name = self.name + if not self.header: + self.header = self.name + else: + self.header = self.header + + # Init .arguments list + self.arguments = argv[1:] + + # Setup Option mapping + self.option_map = option_dict(self.options) + + # Append preset options + for option in self.preset_options: + if not self.option_map.has_key(option.name): + self.add_option(option) + + # Init .files list + self.files = [] + + # Start Application + try: + # Process startup + rc = self.startup() + if rc is not None: + raise SystemExit,rc + + # Parse command line + rc = self.parse() + if rc is not None: + raise SystemExit,rc + + # Start application + rc = self.main() + if rc is None: + rc = 0 + + except SystemExit,rc: + pass + + except KeyboardInterrupt: + print + print '* User Break' + print + rc = 1 + + except self.InternalError: + print + print '* Internal Error (use --debug to display the traceback)' + if self.debug: + print + traceback.print_exc(20, sys.stdout) + elif self.verbose: + print ' %s: %s' % sys.exc_info()[:2] + print + rc = 1 + + raise SystemExit,rc + + def add_option(self, option): + + """ Add a new Option instance to the Application dynamically. + + Note that this has to be done *before* .parse() is being + executed. + + """ + self.options.append(option) + self.option_map[option.name] = option + + def startup(self): + + """ Set user defined instance variables. + + If this method returns anything other than None, the + process is terminated with the return value as exit code. + + """ + return None + + def exit(self, rc=0): + + """ Exit the program. + + rc is used as exit code and passed back to the calling + program. It defaults to 0 which usually means: OK. + + """ + raise SystemExit, rc + + def parse(self): + + """ Parse the command line and fill in self.values and self.files. + + After having parsed the options, the remaining command line + arguments are interpreted as files and passed to .handle_files() + for processing. + + As final step the option handlers are called in the order + of the options given on the command line. + + """ + # Parse arguments + self.values = values = {} + for o in self.options: + if o.has_default: + values[o.prefix+o.name] = o.default + else: + values[o.prefix+o.name] = 0 + flags,lflags = _getopt_flags(self.options) + try: + optlist,files = getopt.getopt(self.arguments,flags,lflags) + if self.globbing: + l = [] + for f in files: + gf = glob.glob(f) + if not gf: + l.append(f) + else: + l[len(l):] = gf + files = l + self.optionlist = optlist + self.files = files + self.files + except getopt.error,why: + self.help(why) + sys.exit(1) + + # Call file handler + rc = self.handle_files(self.files) + if rc is not None: + sys.exit(rc) + + # Call option handlers + for optionname, value in optlist: + + # Try to convert value to integer + try: + value = string.atoi(value) + except ValueError: + pass + + # Find handler and call it (or count the number of option + # instances on the command line) + handlername = 'handle' + string.replace(optionname, '-', '_') + try: + handler = getattr(self, handlername) + except AttributeError: + if value == '': + # count the number of occurances + if values.has_key(optionname): + values[optionname] = values[optionname] + 1 + else: + values[optionname] = 1 + else: + values[optionname] = value + else: + rc = handler(value) + if rc is not None: + raise SystemExit, rc + + # Apply final file check (for backward compatibility) + rc = self.check_files(self.files) + if rc is not None: + sys.exit(rc) + + def check_files(self,filelist): + + """ Apply some user defined checks on the files given in filelist. + + This may modify filelist in place. A typical application + is checking that at least n files are given. + + If this method returns anything other than None, the + process is terminated with the return value as exit code. + + """ + return None + + def help(self,note=''): + + self.print_header() + if self.synopsis: + print 'Synopsis:' + # To remain backward compatible: + try: + synopsis = self.synopsis % self.name + except (NameError, KeyError, TypeError): + synopsis = self.synopsis % self.__dict__ + print ' ' + synopsis + print + self.print_options() + if self.version: + print 'Version:' + print ' %s' % self.version + print + if self.about: + print string.strip(self.about % self.__dict__) + print + if note: + print '-'*72 + print 'Note:',note + print + + def notice(self,note): + + print '-'*72 + print 'Note:',note + print '-'*72 + print + + def print_header(self): + + print '-'*72 + print self.header % self.__dict__ + print '-'*72 + print + + def print_options(self): + + options = self.options + print 'Options and default settings:' + if not options: + print ' None' + return + long = filter(lambda x: x.prefix == '--', options) + short = filter(lambda x: x.prefix == '-', options) + items = short + long + for o in options: + print ' ',o + print + + # + # Example handlers: + # + # If a handler returns anything other than None, processing stops + # and the return value is passed to sys.exit() as argument. + # + + # File handler + def handle_files(self,files): + + """ This may process the files list in place. + """ + return None + + # Short option handler + def handle_h(self,arg): + + self.help() + return 0 + + def handle_v(self, value): + + """ Turn on verbose output. + """ + self.verbose = 1 + + # Handlers for long options have two underscores in their name + def handle__help(self,arg): + + self.help() + return 0 + + def handle__debug(self,arg): + + self.debug = 1 + # We don't want to catch internal errors: + self.InternalError = None + + def handle__copyright(self,arg): + + self.print_header() + print string.strip(self.copyright % self.__dict__) + print + return 0 + + def handle__examples(self,arg): + + self.print_header() + if self.examples: + print 'Examples:' + print + print string.strip(self.examples % self.__dict__) + print + else: + print 'No examples available.' + print + return 0 + + def main(self): + + """ Override this method as program entry point. + + The return value is passed to sys.exit() as argument. If + it is None, 0 is assumed (meaning OK). Unhandled + exceptions are reported with exit status code 1 (see + __init__ for further details). + + """ + return None + +# Alias +CommandLine = Application + +def _test(): + + class MyApplication(Application): + header = 'Test Application' + version = __version__ + options = [Option('-v','verbose')] + + def handle_v(self,arg): + print 'VERBOSE, Yeah !' + + cmd = MyApplication() + if not cmd.values['-h']: + cmd.help() + print 'files:',cmd.files + print 'Bye...' + +if __name__ == '__main__': + _test() diff --git a/sys/src/cmd/python/Tools/pybench/Constructs.py b/sys/src/cmd/python/Tools/pybench/Constructs.py new file mode 100644 index 000000000..510546196 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Constructs.py @@ -0,0 +1,564 @@ +from pybench import Test + +class IfThenElse(Test): + + version = 2.0 + operations = 30*3 # hard to say... + rounds = 150000 + + def test(self): + + a,b,c = 1,2,3 + for i in xrange(self.rounds): + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + if a == 1: + if b == 2: + if c != 3: + c = 3 + b = 3 + else: + c = 2 + elif b == 3: + b = 2 + a = 2 + elif a == 2: + a = 3 + else: + a = 1 + + def calibrate(self): + + a,b,c = 1,2,3 + for i in xrange(self.rounds): + pass + +class NestedForLoops(Test): + + version = 2.0 + operations = 1000*10*5 + rounds = 300 + + def test(self): + + l1 = range(1000) + l2 = range(10) + l3 = range(5) + for i in xrange(self.rounds): + for i in l1: + for j in l2: + for k in l3: + pass + + def calibrate(self): + + l1 = range(1000) + l2 = range(10) + l3 = range(5) + for i in xrange(self.rounds): + pass + +class ForLoops(Test): + + version = 2.0 + operations = 5 * 5 + rounds = 10000 + + def test(self): + + l1 = range(100) + for i in xrange(self.rounds): + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + for i in l1: + pass + + def calibrate(self): + + l1 = range(1000) + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Dict.py b/sys/src/cmd/python/Tools/pybench/Dict.py new file mode 100644 index 000000000..9cdd68264 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Dict.py @@ -0,0 +1,504 @@ +from pybench import Test + +class DictCreation(Test): + + version = 2.0 + operations = 5*(5 + 5) + rounds = 80000 + + def test(self): + + for i in xrange(self.rounds): + + d1 = {} + d2 = {} + d3 = {} + d4 = {} + d5 = {} + + d1 = {1:2,3:4,5:6} + d2 = {2:3,4:5,6:7} + d3 = {3:4,5:6,7:8} + d4 = {4:5,6:7,8:9} + d5 = {6:7,8:9,10:11} + + d1 = {} + d2 = {} + d3 = {} + d4 = {} + d5 = {} + + d1 = {1:2,3:4,5:6} + d2 = {2:3,4:5,6:7} + d3 = {3:4,5:6,7:8} + d4 = {4:5,6:7,8:9} + d5 = {6:7,8:9,10:11} + + d1 = {} + d2 = {} + d3 = {} + d4 = {} + d5 = {} + + d1 = {1:2,3:4,5:6} + d2 = {2:3,4:5,6:7} + d3 = {3:4,5:6,7:8} + d4 = {4:5,6:7,8:9} + d5 = {6:7,8:9,10:11} + + d1 = {} + d2 = {} + d3 = {} + d4 = {} + d5 = {} + + d1 = {1:2,3:4,5:6} + d2 = {2:3,4:5,6:7} + d3 = {3:4,5:6,7:8} + d4 = {4:5,6:7,8:9} + d5 = {6:7,8:9,10:11} + + d1 = {} + d2 = {} + d3 = {} + d4 = {} + d5 = {} + + d1 = {1:2,3:4,5:6} + d2 = {2:3,4:5,6:7} + d3 = {3:4,5:6,7:8} + d4 = {4:5,6:7,8:9} + d5 = {6:7,8:9,10:11} + + def calibrate(self): + + for i in xrange(self.rounds): + pass + +class DictWithStringKeys(Test): + + version = 2.0 + operations = 5*(6 + 6) + rounds = 200000 + + def test(self): + + d = {} + + for i in xrange(self.rounds): + + d['abc'] = 1 + d['def'] = 2 + d['ghi'] = 3 + d['jkl'] = 4 + d['mno'] = 5 + d['pqr'] = 6 + + d['abc'] + d['def'] + d['ghi'] + d['jkl'] + d['mno'] + d['pqr'] + + d['abc'] = 1 + d['def'] = 2 + d['ghi'] = 3 + d['jkl'] = 4 + d['mno'] = 5 + d['pqr'] = 6 + + d['abc'] + d['def'] + d['ghi'] + d['jkl'] + d['mno'] + d['pqr'] + + d['abc'] = 1 + d['def'] = 2 + d['ghi'] = 3 + d['jkl'] = 4 + d['mno'] = 5 + d['pqr'] = 6 + + d['abc'] + d['def'] + d['ghi'] + d['jkl'] + d['mno'] + d['pqr'] + + d['abc'] = 1 + d['def'] = 2 + d['ghi'] = 3 + d['jkl'] = 4 + d['mno'] = 5 + d['pqr'] = 6 + + d['abc'] + d['def'] + d['ghi'] + d['jkl'] + d['mno'] + d['pqr'] + + d['abc'] = 1 + d['def'] = 2 + d['ghi'] = 3 + d['jkl'] = 4 + d['mno'] = 5 + d['pqr'] = 6 + + d['abc'] + d['def'] + d['ghi'] + d['jkl'] + d['mno'] + d['pqr'] + + def calibrate(self): + + d = {} + + for i in xrange(self.rounds): + pass + +class DictWithFloatKeys(Test): + + version = 2.0 + operations = 5*(6 + 6) + rounds = 150000 + + def test(self): + + d = {} + + for i in xrange(self.rounds): + + d[1.234] = 1 + d[2.345] = 2 + d[3.456] = 3 + d[4.567] = 4 + d[5.678] = 5 + d[6.789] = 6 + + d[1.234] + d[2.345] + d[3.456] + d[4.567] + d[5.678] + d[6.789] + + d[1.234] = 1 + d[2.345] = 2 + d[3.456] = 3 + d[4.567] = 4 + d[5.678] = 5 + d[6.789] = 6 + + d[1.234] + d[2.345] + d[3.456] + d[4.567] + d[5.678] + d[6.789] + + d[1.234] = 1 + d[2.345] = 2 + d[3.456] = 3 + d[4.567] = 4 + d[5.678] = 5 + d[6.789] = 6 + + d[1.234] + d[2.345] + d[3.456] + d[4.567] + d[5.678] + d[6.789] + + d[1.234] = 1 + d[2.345] = 2 + d[3.456] = 3 + d[4.567] = 4 + d[5.678] = 5 + d[6.789] = 6 + + d[1.234] + d[2.345] + d[3.456] + d[4.567] + d[5.678] + d[6.789] + + d[1.234] = 1 + d[2.345] = 2 + d[3.456] = 3 + d[4.567] = 4 + d[5.678] = 5 + d[6.789] = 6 + + d[1.234] + d[2.345] + d[3.456] + d[4.567] + d[5.678] + d[6.789] + + def calibrate(self): + + d = {} + + for i in xrange(self.rounds): + pass + +class DictWithIntegerKeys(Test): + + version = 2.0 + operations = 5*(6 + 6) + rounds = 200000 + + def test(self): + + d = {} + + for i in xrange(self.rounds): + + d[1] = 1 + d[2] = 2 + d[3] = 3 + d[4] = 4 + d[5] = 5 + d[6] = 6 + + d[1] + d[2] + d[3] + d[4] + d[5] + d[6] + + d[1] = 1 + d[2] = 2 + d[3] = 3 + d[4] = 4 + d[5] = 5 + d[6] = 6 + + d[1] + d[2] + d[3] + d[4] + d[5] + d[6] + + d[1] = 1 + d[2] = 2 + d[3] = 3 + d[4] = 4 + d[5] = 5 + d[6] = 6 + + d[1] + d[2] + d[3] + d[4] + d[5] + d[6] + + d[1] = 1 + d[2] = 2 + d[3] = 3 + d[4] = 4 + d[5] = 5 + d[6] = 6 + + d[1] + d[2] + d[3] + d[4] + d[5] + d[6] + + d[1] = 1 + d[2] = 2 + d[3] = 3 + d[4] = 4 + d[5] = 5 + d[6] = 6 + + d[1] + d[2] + d[3] + d[4] + d[5] + d[6] + + def calibrate(self): + + d = {} + + for i in xrange(self.rounds): + pass + +class SimpleDictManipulation(Test): + + version = 2.0 + operations = 5*(6 + 6 + 6 + 6) + rounds = 100000 + + def test(self): + + d = {} + has_key = d.has_key + + for i in xrange(self.rounds): + + d[0] = 3 + d[1] = 4 + d[2] = 5 + d[3] = 3 + d[4] = 4 + d[5] = 5 + + x = d[0] + x = d[1] + x = d[2] + x = d[3] + x = d[4] + x = d[5] + + has_key(0) + has_key(2) + has_key(4) + has_key(6) + has_key(8) + has_key(10) + + del d[0] + del d[1] + del d[2] + del d[3] + del d[4] + del d[5] + + d[0] = 3 + d[1] = 4 + d[2] = 5 + d[3] = 3 + d[4] = 4 + d[5] = 5 + + x = d[0] + x = d[1] + x = d[2] + x = d[3] + x = d[4] + x = d[5] + + has_key(0) + has_key(2) + has_key(4) + has_key(6) + has_key(8) + has_key(10) + + del d[0] + del d[1] + del d[2] + del d[3] + del d[4] + del d[5] + + d[0] = 3 + d[1] = 4 + d[2] = 5 + d[3] = 3 + d[4] = 4 + d[5] = 5 + + x = d[0] + x = d[1] + x = d[2] + x = d[3] + x = d[4] + x = d[5] + + has_key(0) + has_key(2) + has_key(4) + has_key(6) + has_key(8) + has_key(10) + + del d[0] + del d[1] + del d[2] + del d[3] + del d[4] + del d[5] + + d[0] = 3 + d[1] = 4 + d[2] = 5 + d[3] = 3 + d[4] = 4 + d[5] = 5 + + x = d[0] + x = d[1] + x = d[2] + x = d[3] + x = d[4] + x = d[5] + + has_key(0) + has_key(2) + has_key(4) + has_key(6) + has_key(8) + has_key(10) + + del d[0] + del d[1] + del d[2] + del d[3] + del d[4] + del d[5] + + d[0] = 3 + d[1] = 4 + d[2] = 5 + d[3] = 3 + d[4] = 4 + d[5] = 5 + + x = d[0] + x = d[1] + x = d[2] + x = d[3] + x = d[4] + x = d[5] + + has_key(0) + has_key(2) + has_key(4) + has_key(6) + has_key(8) + has_key(10) + + del d[0] + del d[1] + del d[2] + del d[3] + del d[4] + del d[5] + + def calibrate(self): + + d = {} + has_key = d.has_key + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Exceptions.py b/sys/src/cmd/python/Tools/pybench/Exceptions.py new file mode 100644 index 000000000..eff69c717 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Exceptions.py @@ -0,0 +1,699 @@ +from pybench import Test + +class TryRaiseExcept(Test): + + version = 2.0 + operations = 2 + 3 + 3 + rounds = 80000 + + def test(self): + + error = ValueError + + for i in xrange(self.rounds): + try: + raise error + except: + pass + try: + raise error + except: + pass + try: + raise error,"something" + except: + pass + try: + raise error,"something" + except: + pass + try: + raise error,"something" + except: + pass + try: + raise error("something") + except: + pass + try: + raise error("something") + except: + pass + try: + raise error("something") + except: + pass + + def calibrate(self): + + error = ValueError + + for i in xrange(self.rounds): + pass + + +class TryExcept(Test): + + version = 2.0 + operations = 15 * 10 + rounds = 150000 + + def test(self): + + for i in xrange(self.rounds): + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + try: + pass + except: + pass + + def calibrate(self): + + for i in xrange(self.rounds): + pass + +### Test to make Fredrik happy... + +if __name__ == '__main__': + import timeit + timeit.TestClass = TryRaiseExcept + timeit.main(['-s', 'test = TestClass(); test.rounds = 1000', + 'test.test()']) diff --git a/sys/src/cmd/python/Tools/pybench/Imports.py b/sys/src/cmd/python/Tools/pybench/Imports.py new file mode 100644 index 000000000..afc728b94 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Imports.py @@ -0,0 +1,138 @@ +from pybench import Test + +# First imports: +import os +import package.submodule + +class SecondImport(Test): + + version = 2.0 + operations = 5 * 5 + rounds = 40000 + + def test(self): + + for i in xrange(self.rounds): + import os + import os + import os + import os + import os + + import os + import os + import os + import os + import os + + import os + import os + import os + import os + import os + + import os + import os + import os + import os + import os + + import os + import os + import os + import os + import os + + def calibrate(self): + + for i in xrange(self.rounds): + pass + + +class SecondPackageImport(Test): + + version = 2.0 + operations = 5 * 5 + rounds = 40000 + + def test(self): + + for i in xrange(self.rounds): + import package + import package + import package + import package + import package + + import package + import package + import package + import package + import package + + import package + import package + import package + import package + import package + + import package + import package + import package + import package + import package + + import package + import package + import package + import package + import package + + def calibrate(self): + + for i in xrange(self.rounds): + pass + +class SecondSubmoduleImport(Test): + + version = 2.0 + operations = 5 * 5 + rounds = 40000 + + def test(self): + + for i in xrange(self.rounds): + import package.submodule + import package.submodule + import package.submodule + import package.submodule + import package.submodule + + import package.submodule + import package.submodule + import package.submodule + import package.submodule + import package.submodule + + import package.submodule + import package.submodule + import package.submodule + import package.submodule + import package.submodule + + import package.submodule + import package.submodule + import package.submodule + import package.submodule + import package.submodule + + import package.submodule + import package.submodule + import package.submodule + import package.submodule + import package.submodule + + def calibrate(self): + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Instances.py b/sys/src/cmd/python/Tools/pybench/Instances.py new file mode 100644 index 000000000..1dfc82f32 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Instances.py @@ -0,0 +1,66 @@ +from pybench import Test + +class CreateInstances(Test): + + version = 2.0 + operations = 3 + 7 + 4 + rounds = 80000 + + def test(self): + + class c: + pass + + class d: + def __init__(self,a,b,c): + self.a = a + self.b = b + self.c = c + + class e: + def __init__(self,a,b,c=4): + self.a = a + self.b = b + self.c = c + self.d = a + self.e = b + self.f = c + + for i in xrange(self.rounds): + o = c() + o1 = c() + o2 = c() + p = d(i,i,3) + p1 = d(i,i,3) + p2 = d(i,3,3) + p3 = d(3,i,3) + p4 = d(i,i,i) + p5 = d(3,i,3) + p6 = d(i,i,i) + q = e(i,i,3) + q1 = e(i,i,3) + q2 = e(i,i,3) + q3 = e(i,i) + + def calibrate(self): + + class c: + pass + + class d: + def __init__(self,a,b,c): + self.a = a + self.b = b + self.c = c + + class e: + def __init__(self,a,b,c=4): + self.a = a + self.b = b + self.c = c + self.d = a + self.e = b + self.f = c + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/LICENSE b/sys/src/cmd/python/Tools/pybench/LICENSE new file mode 100644 index 000000000..17c6a6bdf --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/LICENSE @@ -0,0 +1,25 @@ +pybench License +--------------- + +This copyright notice and license applies to all files in the pybench +directory of the pybench distribution. + +Copyright (c), 1997-2006, Marc-Andre Lemburg (mal@lemburg.com) +Copyright (c), 2000-2006, eGenix.com Software GmbH (info@egenix.com) + + All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee or royalty is hereby +granted, provided that the above copyright notice appear in all copies +and that both that copyright notice and this permission notice appear +in supporting documentation or portions thereof, including +modifications, that you make. + +THE AUTHOR MARC-ANDRE LEMBURG DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! diff --git a/sys/src/cmd/python/Tools/pybench/Lists.py b/sys/src/cmd/python/Tools/pybench/Lists.py new file mode 100644 index 000000000..67760db35 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Lists.py @@ -0,0 +1,295 @@ +from pybench import Test + +class SimpleListManipulation(Test): + + version = 2.0 + operations = 5* (6 + 6 + 6) + rounds = 130000 + + def test(self): + + l = [] + append = l.append + + for i in xrange(self.rounds): + + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + x = l[0] + x = l[1] + x = l[2] + x = l[3] + x = l[4] + x = l[5] + + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + x = l[0] + x = l[1] + x = l[2] + x = l[3] + x = l[4] + x = l[5] + + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + x = l[0] + x = l[1] + x = l[2] + x = l[3] + x = l[4] + x = l[5] + + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + x = l[0] + x = l[1] + x = l[2] + x = l[3] + x = l[4] + x = l[5] + + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + x = l[0] + x = l[1] + x = l[2] + x = l[3] + x = l[4] + x = l[5] + + if len(l) > 10000: + # cut down the size + del l[:] + + def calibrate(self): + + l = [] + append = l.append + + for i in xrange(self.rounds): + pass + +class ListSlicing(Test): + + version = 2.0 + operations = 25*(3+1+2+1) + rounds = 800 + + def test(self): + + n = range(100) + r = range(25) + + for i in xrange(self.rounds): + + l = n[:] + + for j in r: + + m = l[50:] + m = l[:25] + m = l[50:55] + l[:3] = n + m = l[:-1] + m = l[1:] + l[-1:] = n + + def calibrate(self): + + n = range(100) + r = range(25) + + for i in xrange(self.rounds): + for j in r: + pass + +class SmallLists(Test): + + version = 2.0 + operations = 5*(1+ 6 + 6 + 3 + 1) + rounds = 80000 + + def test(self): + + for i in xrange(self.rounds): + + l = [] + + append = l.append + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + l[:3] = [1,2,3] + m = l[:-1] + m = l[1:] + + l[-1:] = [4,5,6] + + l = [] + + append = l.append + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + l[:3] = [1,2,3] + m = l[:-1] + m = l[1:] + + l[-1:] = [4,5,6] + + l = [] + + append = l.append + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + l[:3] = [1,2,3] + m = l[:-1] + m = l[1:] + + l[-1:] = [4,5,6] + + l = [] + + append = l.append + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + l[:3] = [1,2,3] + m = l[:-1] + m = l[1:] + + l[-1:] = [4,5,6] + + l = [] + + append = l.append + append(2) + append(3) + append(4) + append(2) + append(3) + append(4) + + l[0] = 3 + l[1] = 4 + l[2] = 5 + l[3] = 3 + l[4] = 4 + l[5] = 5 + + l[:3] = [1,2,3] + m = l[:-1] + m = l[1:] + + l[-1:] = [4,5,6] + + def calibrate(self): + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Lookups.py b/sys/src/cmd/python/Tools/pybench/Lookups.py new file mode 100644 index 000000000..f20e7da49 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Lookups.py @@ -0,0 +1,945 @@ +from pybench import Test + +class SpecialClassAttribute(Test): + + version = 2.0 + operations = 5*(12 + 12) + rounds = 100000 + + def test(self): + + class c: + pass + + for i in xrange(self.rounds): + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + c.__a = 2 + c.__b = 3 + c.__c = 4 + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + x = c.__a + x = c.__b + x = c.__c + + def calibrate(self): + + class c: + pass + + for i in xrange(self.rounds): + pass + +class NormalClassAttribute(Test): + + version = 2.0 + operations = 5*(12 + 12) + rounds = 100000 + + def test(self): + + class c: + pass + + for i in xrange(self.rounds): + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + c.a = 2 + c.b = 3 + c.c = 4 + + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + x = c.a + x = c.b + x = c.c + + def calibrate(self): + + class c: + pass + + for i in xrange(self.rounds): + pass + +class SpecialInstanceAttribute(Test): + + version = 2.0 + operations = 5*(12 + 12) + rounds = 100000 + + def test(self): + + class c: + pass + o = c() + + for i in xrange(self.rounds): + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + o.__a__ = 2 + o.__b__ = 3 + o.__c__ = 4 + + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + x = o.__a__ + x = o.__b__ + x = o.__c__ + + def calibrate(self): + + class c: + pass + o = c() + + for i in xrange(self.rounds): + pass + +class NormalInstanceAttribute(Test): + + version = 2.0 + operations = 5*(12 + 12) + rounds = 100000 + + def test(self): + + class c: + pass + o = c() + + for i in xrange(self.rounds): + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + o.a = 2 + o.b = 3 + o.c = 4 + + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + x = o.a + x = o.b + x = o.c + + def calibrate(self): + + class c: + pass + o = c() + + for i in xrange(self.rounds): + pass + +class BuiltinMethodLookup(Test): + + version = 2.0 + operations = 5*(3*5 + 3*5) + rounds = 70000 + + def test(self): + + l = [] + d = {} + + for i in xrange(self.rounds): + + l.append + l.append + l.append + l.append + l.append + + l.insert + l.insert + l.insert + l.insert + l.insert + + l.sort + l.sort + l.sort + l.sort + l.sort + + d.has_key + d.has_key + d.has_key + d.has_key + d.has_key + + d.items + d.items + d.items + d.items + d.items + + d.get + d.get + d.get + d.get + d.get + + l.append + l.append + l.append + l.append + l.append + + l.insert + l.insert + l.insert + l.insert + l.insert + + l.sort + l.sort + l.sort + l.sort + l.sort + + d.has_key + d.has_key + d.has_key + d.has_key + d.has_key + + d.items + d.items + d.items + d.items + d.items + + d.get + d.get + d.get + d.get + d.get + + l.append + l.append + l.append + l.append + l.append + + l.insert + l.insert + l.insert + l.insert + l.insert + + l.sort + l.sort + l.sort + l.sort + l.sort + + d.has_key + d.has_key + d.has_key + d.has_key + d.has_key + + d.items + d.items + d.items + d.items + d.items + + d.get + d.get + d.get + d.get + d.get + + l.append + l.append + l.append + l.append + l.append + + l.insert + l.insert + l.insert + l.insert + l.insert + + l.sort + l.sort + l.sort + l.sort + l.sort + + d.has_key + d.has_key + d.has_key + d.has_key + d.has_key + + d.items + d.items + d.items + d.items + d.items + + d.get + d.get + d.get + d.get + d.get + + l.append + l.append + l.append + l.append + l.append + + l.insert + l.insert + l.insert + l.insert + l.insert + + l.sort + l.sort + l.sort + l.sort + l.sort + + d.has_key + d.has_key + d.has_key + d.has_key + d.has_key + + d.items + d.items + d.items + d.items + d.items + + d.get + d.get + d.get + d.get + d.get + + def calibrate(self): + + l = [] + d = {} + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/NewInstances.py b/sys/src/cmd/python/Tools/pybench/NewInstances.py new file mode 100644 index 000000000..258beba61 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/NewInstances.py @@ -0,0 +1,75 @@ +from pybench import Test + +# Check for new-style class support: +try: + class c(object): + pass +except NameError: + raise ImportError + +### + +class CreateNewInstances(Test): + + version = 2.0 + operations = 3 + 7 + 4 + rounds = 60000 + + def test(self): + + class c(object): + pass + + class d(object): + def __init__(self,a,b,c): + self.a = a + self.b = b + self.c = c + + class e(object): + def __init__(self,a,b,c=4): + self.a = a + self.b = b + self.c = c + self.d = a + self.e = b + self.f = c + + for i in xrange(self.rounds): + o = c() + o1 = c() + o2 = c() + p = d(i,i,3) + p1 = d(i,i,3) + p2 = d(i,3,3) + p3 = d(3,i,3) + p4 = d(i,i,i) + p5 = d(3,i,3) + p6 = d(i,i,i) + q = e(i,i,3) + q1 = e(i,i,3) + q2 = e(i,i,3) + q3 = e(i,i) + + def calibrate(self): + + class c(object): + pass + + class d(object): + def __init__(self,a,b,c): + self.a = a + self.b = b + self.c = c + + class e(object): + def __init__(self,a,b,c=4): + self.a = a + self.b = b + self.c = c + self.d = a + self.e = b + self.f = c + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Numbers.py b/sys/src/cmd/python/Tools/pybench/Numbers.py new file mode 100644 index 000000000..10c8940a2 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Numbers.py @@ -0,0 +1,784 @@ +from pybench import Test + +class CompareIntegers(Test): + + version = 2.0 + operations = 30 * 5 + rounds = 120000 + + def test(self): + + for i in xrange(self.rounds): + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + 2 < 3 + 2 > 3 + 2 == 3 + 2 > 3 + 2 < 3 + + def calibrate(self): + + for i in xrange(self.rounds): + pass + + +class CompareFloats(Test): + + version = 2.0 + operations = 30 * 5 + rounds = 80000 + + def test(self): + + for i in xrange(self.rounds): + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + 2.1 < 3.31 + 2.1 > 3.31 + 2.1 == 3.31 + 2.1 > 3.31 + 2.1 < 3.31 + + def calibrate(self): + + for i in xrange(self.rounds): + pass + + +class CompareFloatsIntegers(Test): + + version = 2.0 + operations = 30 * 5 + rounds = 60000 + + def test(self): + + for i in xrange(self.rounds): + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + 2.1 < 4 + 2.1 > 4 + 2.1 == 4 + 2.1 > 4 + 2.1 < 4 + + def calibrate(self): + + for i in xrange(self.rounds): + pass + + +class CompareLongs(Test): + + version = 2.0 + operations = 30 * 5 + rounds = 70000 + + def test(self): + + for i in xrange(self.rounds): + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + 1234567890L < 3456789012345L + 1234567890L > 3456789012345L + 1234567890L == 3456789012345L + 1234567890L > 3456789012345L + 1234567890L < 3456789012345L + + def calibrate(self): + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/README b/sys/src/cmd/python/Tools/pybench/README new file mode 100644 index 000000000..022c8dea9 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/README @@ -0,0 +1,368 @@ +________________________________________________________________________ + +PYBENCH - A Python Benchmark Suite +________________________________________________________________________ + + Extendable suite of of low-level benchmarks for measuring + the performance of the Python implementation + (interpreter, compiler or VM). + +pybench is a collection of tests that provides a standardized way to +measure the performance of Python implementations. It takes a very +close look at different aspects of Python programs and let's you +decide which factors are more important to you than others, rather +than wrapping everything up in one number, like the other performance +tests do (e.g. pystone which is included in the Python Standard +Library). + +pybench has been used in the past by several Python developers to +track down performance bottlenecks or to demonstrate the impact of +optimizations and new features in Python. + +The command line interface for pybench is the file pybench.py. Run +this script with option '--help' to get a listing of the possible +options. Without options, pybench will simply execute the benchmark +and then print out a report to stdout. + + +Micro-Manual +------------ + +Run 'pybench.py -h' to see the help screen. Run 'pybench.py' to run +the benchmark suite using default settings and 'pybench.py -f <file>' +to have it store the results in a file too. + +It is usually a good idea to run pybench.py multiple times to see +whether the environment, timers and benchmark run-times are suitable +for doing benchmark tests. + +You can use the comparison feature of pybench.py ('pybench.py -c +<file>') to check how well the system behaves in comparison to a +reference run. + +If the differences are well below 10% for each test, then you have a +system that is good for doing benchmark testings. Of you get random +differences of more than 10% or significant differences between the +values for minimum and average time, then you likely have some +background processes running which cause the readings to become +inconsistent. Examples include: web-browsers, email clients, RSS +readers, music players, backup programs, etc. + +If you are only interested in a few tests of the whole suite, you can +use the filtering option, e.g. 'pybench.py -t string' will only +run/show the tests that have 'string' in their name. + +This is the current output of pybench.py --help: + +""" +------------------------------------------------------------------------ +PYBENCH - a benchmark test suite for Python interpreters/compilers. +------------------------------------------------------------------------ + +Synopsis: + pybench.py [option] files... + +Options and default settings: + -n arg number of rounds (10) + -f arg save benchmark to file arg () + -c arg compare benchmark with the one in file arg () + -s arg show benchmark in file arg, then exit () + -w arg set warp factor to arg (10) + -t arg run only tests with names matching arg () + -C arg set the number of calibration runs to arg (20) + -d hide noise in comparisons (0) + -v verbose output (not recommended) (0) + --with-gc enable garbage collection (0) + --with-syscheck use default sys check interval (0) + --timer arg use given timer (time.time) + -h show this help text + --help show this help text + --debug enable debugging + --copyright show copyright + --examples show examples of usage + +Version: + 2.0 + +The normal operation is to run the suite and display the +results. Use -f to save them for later reuse or comparisons. + +Available timers: + + time.time + time.clock + systimes.processtime + +Examples: + +python2.1 pybench.py -f p21.pybench +python2.5 pybench.py -f p25.pybench +python pybench.py -s p25.pybench -c p21.pybench +""" + +License +------- + +See LICENSE file. + + +Sample output +------------- + +""" +------------------------------------------------------------------------------- +PYBENCH 2.0 +------------------------------------------------------------------------------- +* using Python 2.4.2 +* disabled garbage collection +* system check interval set to maximum: 2147483647 +* using timer: time.time + +Calibrating tests. Please wait... + +Running 10 round(s) of the suite at warp factor 10: + +* Round 1 done in 6.388 seconds. +* Round 2 done in 6.485 seconds. +* Round 3 done in 6.786 seconds. +... +* Round 10 done in 6.546 seconds. + +------------------------------------------------------------------------------- +Benchmark: 2006-06-12 12:09:25 +------------------------------------------------------------------------------- + + Rounds: 10 + Warp: 10 + Timer: time.time + + Machine Details: + Platform ID: Linux-2.6.8-24.19-default-x86_64-with-SuSE-9.2-x86-64 + Processor: x86_64 + + Python: + Executable: /usr/local/bin/python + Version: 2.4.2 + Compiler: GCC 3.3.4 (pre 3.3.5 20040809) + Bits: 64bit + Build: Oct 1 2005 15:24:35 (#1) + Unicode: UCS2 + + +Test minimum average operation overhead +------------------------------------------------------------------------------- + BuiltinFunctionCalls: 126ms 145ms 0.28us 0.274ms + BuiltinMethodLookup: 124ms 130ms 0.12us 0.316ms + CompareFloats: 109ms 110ms 0.09us 0.361ms + CompareFloatsIntegers: 100ms 104ms 0.12us 0.271ms + CompareIntegers: 137ms 138ms 0.08us 0.542ms + CompareInternedStrings: 124ms 127ms 0.08us 1.367ms + CompareLongs: 100ms 104ms 0.10us 0.316ms + CompareStrings: 111ms 115ms 0.12us 0.929ms + CompareUnicode: 108ms 128ms 0.17us 0.693ms + ConcatStrings: 142ms 155ms 0.31us 0.562ms + ConcatUnicode: 119ms 127ms 0.42us 0.384ms + CreateInstances: 123ms 128ms 1.14us 0.367ms + CreateNewInstances: 121ms 126ms 1.49us 0.335ms + CreateStringsWithConcat: 130ms 135ms 0.14us 0.916ms + CreateUnicodeWithConcat: 130ms 135ms 0.34us 0.361ms + DictCreation: 108ms 109ms 0.27us 0.361ms + DictWithFloatKeys: 149ms 153ms 0.17us 0.678ms + DictWithIntegerKeys: 124ms 126ms 0.11us 0.915ms + DictWithStringKeys: 114ms 117ms 0.10us 0.905ms + ForLoops: 110ms 111ms 4.46us 0.063ms + IfThenElse: 118ms 119ms 0.09us 0.685ms + ListSlicing: 116ms 120ms 8.59us 0.103ms + NestedForLoops: 125ms 137ms 0.09us 0.019ms + NormalClassAttribute: 124ms 136ms 0.11us 0.457ms + NormalInstanceAttribute: 110ms 117ms 0.10us 0.454ms + PythonFunctionCalls: 107ms 113ms 0.34us 0.271ms + PythonMethodCalls: 140ms 149ms 0.66us 0.141ms + Recursion: 156ms 166ms 3.32us 0.452ms + SecondImport: 112ms 118ms 1.18us 0.180ms + SecondPackageImport: 118ms 127ms 1.27us 0.180ms + SecondSubmoduleImport: 140ms 151ms 1.51us 0.180ms + SimpleComplexArithmetic: 128ms 139ms 0.16us 0.361ms + SimpleDictManipulation: 134ms 136ms 0.11us 0.452ms + SimpleFloatArithmetic: 110ms 113ms 0.09us 0.571ms + SimpleIntFloatArithmetic: 106ms 111ms 0.08us 0.548ms + SimpleIntegerArithmetic: 106ms 109ms 0.08us 0.544ms + SimpleListManipulation: 103ms 113ms 0.10us 0.587ms + SimpleLongArithmetic: 112ms 118ms 0.18us 0.271ms + SmallLists: 105ms 116ms 0.17us 0.366ms + SmallTuples: 108ms 128ms 0.24us 0.406ms + SpecialClassAttribute: 119ms 136ms 0.11us 0.453ms + SpecialInstanceAttribute: 143ms 155ms 0.13us 0.454ms + StringMappings: 115ms 121ms 0.48us 0.405ms + StringPredicates: 120ms 129ms 0.18us 2.064ms + StringSlicing: 111ms 127ms 0.23us 0.781ms + TryExcept: 125ms 126ms 0.06us 0.681ms + TryRaiseExcept: 133ms 137ms 2.14us 0.361ms + TupleSlicing: 117ms 120ms 0.46us 0.066ms + UnicodeMappings: 156ms 160ms 4.44us 0.429ms + UnicodePredicates: 117ms 121ms 0.22us 2.487ms + UnicodeProperties: 115ms 153ms 0.38us 2.070ms + UnicodeSlicing: 126ms 129ms 0.26us 0.689ms +------------------------------------------------------------------------------- +Totals: 6283ms 6673ms +""" +________________________________________________________________________ + +Writing New Tests +________________________________________________________________________ + +pybench tests are simple modules defining one or more pybench.Test +subclasses. + +Writing a test essentially boils down to providing two methods: +.test() which runs .rounds number of .operations test operations each +and .calibrate() which does the same except that it doesn't actually +execute the operations. + + +Here's an example: +------------------ + +from pybench import Test + +class IntegerCounting(Test): + + # Version number of the test as float (x.yy); this is important + # for comparisons of benchmark runs - tests with unequal version + # number will not get compared. + version = 1.0 + + # The number of abstract operations done in each round of the + # test. An operation is the basic unit of what you want to + # measure. The benchmark will output the amount of run-time per + # operation. Note that in order to raise the measured timings + # significantly above noise level, it is often required to repeat + # sets of operations more than once per test round. The measured + # overhead per test round should be less than 1 second. + operations = 20 + + # Number of rounds to execute per test run. This should be + # adjusted to a figure that results in a test run-time of between + # 1-2 seconds (at warp 1). + rounds = 100000 + + def test(self): + + """ Run the test. + + The test needs to run self.rounds executing + self.operations number of operations each. + + """ + # Init the test + a = 1 + + # Run test rounds + # + # NOTE: Use xrange() for all test loops unless you want to face + # a 20MB process ! + # + for i in xrange(self.rounds): + + # Repeat the operations per round to raise the run-time + # per operation significantly above the noise level of the + # for-loop overhead. + + # Execute 20 operations (a += 1): + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + a += 1 + + def calibrate(self): + + """ Calibrate the test. + + This method should execute everything that is needed to + setup and run the test - except for the actual operations + that you intend to measure. pybench uses this method to + measure the test implementation overhead. + + """ + # Init the test + a = 1 + + # Run test rounds (without actually doing any operation) + for i in xrange(self.rounds): + + # Skip the actual execution of the operations, since we + # only want to measure the test's administration overhead. + pass + +Registering a new test module +----------------------------- + +To register a test module with pybench, the classes need to be +imported into the pybench.Setup module. pybench will then scan all the +symbols defined in that module for subclasses of pybench.Test and +automatically add them to the benchmark suite. + + +Breaking Comparability +---------------------- + +If a change is made to any individual test that means it is no +longer strictly comparable with previous runs, the '.version' class +variable should be updated. Therefafter, comparisons with previous +versions of the test will list as "n/a" to reflect the change. + + +Version History +--------------- + + 2.0: rewrote parts of pybench which resulted in more repeatable + timings: + - made timer a parameter + - changed the platform default timer to use high-resolution + timers rather than process timers (which have a much lower + resolution) + - added option to select timer + - added process time timer (using systimes.py) + - changed to use min() as timing estimator (average + is still taken as well to provide an idea of the difference) + - garbage collection is turned off per default + - sys check interval is set to the highest possible value + - calibration is now a separate step and done using + a different strategy that allows measuring the test + overhead more accurately + - modified the tests to each give a run-time of between + 100-200ms using warp 10 + - changed default warp factor to 10 (from 20) + - compared results with timeit.py and confirmed measurements + - bumped all test versions to 2.0 + - updated platform.py to the latest version + - changed the output format a bit to make it look + nicer + - refactored the APIs somewhat + 1.3+: Steve Holden added the NewInstances test and the filtering + option during the NeedForSpeed sprint; this also triggered a long + discussion on how to improve benchmark timing and finally + resulted in the release of 2.0 + 1.3: initial checkin into the Python SVN repository + + +Have fun, +-- +Marc-Andre Lemburg +mal@lemburg.com diff --git a/sys/src/cmd/python/Tools/pybench/Setup.py b/sys/src/cmd/python/Tools/pybench/Setup.py new file mode 100644 index 000000000..f1417e6c3 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Setup.py @@ -0,0 +1,39 @@ +#!python + +# Setup file for pybench +# +# This file has to import all tests to be run; it is executed as +# Python source file, so you can do all kinds of manipulations here +# rather than having to edit the tests themselves. +# +# Note: Please keep this module compatible to Python 1.5.2. +# +# Tests may include features in later Python versions, but these +# should then be embedded in try-except clauses in this configuration +# module. + +# Defaults +Number_of_rounds = 10 +Warp_factor = 10 + +# Import tests +from Arithmetic import * +from Calls import * +from Constructs import * +from Lookups import * +from Instances import * +try: + from NewInstances import * +except ImportError: + pass +from Lists import * +from Tuples import * +from Dict import * +from Exceptions import * +from Imports import * +from Strings import * +from Numbers import * +try: + from Unicode import * +except (ImportError, SyntaxError): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Strings.py b/sys/src/cmd/python/Tools/pybench/Strings.py new file mode 100644 index 000000000..3be8b35e9 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Strings.py @@ -0,0 +1,562 @@ +from pybench import Test +from string import join + +class ConcatStrings(Test): + + version = 2.0 + operations = 10 * 5 + rounds = 100000 + + def test(self): + + # Make sure the strings are *not* interned + s = join(map(str,range(100))) + t = join(map(str,range(1,101))) + + for i in xrange(self.rounds): + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + def calibrate(self): + + s = join(map(str,range(100))) + t = join(map(str,range(1,101))) + + for i in xrange(self.rounds): + pass + + +class CompareStrings(Test): + + version = 2.0 + operations = 10 * 5 + rounds = 200000 + + def test(self): + + # Make sure the strings are *not* interned + s = join(map(str,range(10))) + t = join(map(str,range(10))) + "abc" + + for i in xrange(self.rounds): + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + def calibrate(self): + + s = join(map(str,range(10))) + t = join(map(str,range(10))) + "abc" + + for i in xrange(self.rounds): + pass + + +class CompareInternedStrings(Test): + + version = 2.0 + operations = 10 * 5 + rounds = 300000 + + def test(self): + + # Make sure the strings *are* interned + s = intern(join(map(str,range(10)))) + t = s + + for i in xrange(self.rounds): + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + t == s + t == s + t >= s + t > s + t < s + + def calibrate(self): + + s = intern(join(map(str,range(10)))) + t = s + + for i in xrange(self.rounds): + pass + + +class CreateStringsWithConcat(Test): + + version = 2.0 + operations = 10 * 5 + rounds = 200000 + + def test(self): + + for i in xrange(self.rounds): + s = 'om' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + s = s + 'xax' + s = s + 'xbx' + s = s + 'xcx' + s = s + 'xdx' + s = s + 'xex' + + def calibrate(self): + + for i in xrange(self.rounds): + pass + + +class StringSlicing(Test): + + version = 2.0 + operations = 5 * 7 + rounds = 160000 + + def test(self): + + s = join(map(str,range(100))) + + for i in xrange(self.rounds): + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + def calibrate(self): + + s = join(map(str,range(100))) + + for i in xrange(self.rounds): + pass + +### String methods + +if hasattr('', 'lower'): + + class StringMappings(Test): + + version = 2.0 + operations = 3 * (5 + 4 + 2 + 1) + rounds = 70000 + + def test(self): + + s = join(map(chr,range(20)),'') + t = join(map(chr,range(50)),'') + u = join(map(chr,range(100)),'') + v = join(map(chr,range(256)),'') + + for i in xrange(self.rounds): + + s.lower() + s.lower() + s.lower() + s.lower() + s.lower() + + s.upper() + s.upper() + s.upper() + s.upper() + s.upper() + + s.title() + s.title() + s.title() + s.title() + s.title() + + t.lower() + t.lower() + t.lower() + t.lower() + + t.upper() + t.upper() + t.upper() + t.upper() + + t.title() + t.title() + t.title() + t.title() + + u.lower() + u.lower() + + u.upper() + u.upper() + + u.title() + u.title() + + v.lower() + + v.upper() + + v.title() + + def calibrate(self): + + s = join(map(chr,range(20)),'') + t = join(map(chr,range(50)),'') + u = join(map(chr,range(100)),'') + v = join(map(chr,range(256)),'') + + for i in xrange(self.rounds): + pass + + class StringPredicates(Test): + + version = 2.0 + operations = 10 * 7 + rounds = 100000 + + def test(self): + + data = ('abc', '123', ' ', '\xe4\xf6\xfc', '\xdf'*10) + len_data = len(data) + + for i in xrange(self.rounds): + s = data[i % len_data] + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdigit() + s.islower() + s.isspace() + s.istitle() + s.isupper() + + def calibrate(self): + + data = ('abc', '123', ' ', '\u1234\u2345\u3456', '\uFFFF'*10) + data = ('abc', '123', ' ', '\xe4\xf6\xfc', '\xdf'*10) + len_data = len(data) + + for i in xrange(self.rounds): + s = data[i % len_data] diff --git a/sys/src/cmd/python/Tools/pybench/Tuples.py b/sys/src/cmd/python/Tools/pybench/Tuples.py new file mode 100644 index 000000000..8e4698959 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Tuples.py @@ -0,0 +1,360 @@ +from pybench import Test + +class TupleSlicing(Test): + + version = 2.0 + operations = 3 * 25 * 10 * 7 + rounds = 500 + + def test(self): + + r = range(25) + t = tuple(range(100)) + + for i in xrange(self.rounds): + + for j in r: + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + m = t[50:] + m = t[:25] + m = t[50:55] + m = t[:-1] + m = t[1:] + m = t[-10:] + m = t[:10] + + def calibrate(self): + + r = range(25) + t = tuple(range(100)) + + for i in xrange(self.rounds): + for j in r: + pass + +class SmallTuples(Test): + + version = 2.0 + operations = 5*(1 + 3 + 6 + 2) + rounds = 90000 + + def test(self): + + for i in xrange(self.rounds): + + t = (1,2,3,4,5,6) + + a,b,c,d,e,f = t + a,b,c,d,e,f = t + a,b,c,d,e,f = t + + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + + l = list(t) + t = tuple(l) + + t = (1,2,3,4,5,6) + + a,b,c,d,e,f = t + a,b,c,d,e,f = t + a,b,c,d,e,f = t + + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + + l = list(t) + t = tuple(l) + + t = (1,2,3,4,5,6) + + a,b,c,d,e,f = t + a,b,c,d,e,f = t + a,b,c,d,e,f = t + + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + + l = list(t) + t = tuple(l) + + t = (1,2,3,4,5,6) + + a,b,c,d,e,f = t + a,b,c,d,e,f = t + a,b,c,d,e,f = t + + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + + l = list(t) + t = tuple(l) + + t = (1,2,3,4,5,6) + + a,b,c,d,e,f = t + a,b,c,d,e,f = t + a,b,c,d,e,f = t + + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + a,b,c = t[:3] + + l = list(t) + t = tuple(l) + + def calibrate(self): + + for i in xrange(self.rounds): + pass diff --git a/sys/src/cmd/python/Tools/pybench/Unicode.py b/sys/src/cmd/python/Tools/pybench/Unicode.py new file mode 100644 index 000000000..153a91e66 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/Unicode.py @@ -0,0 +1,542 @@ +try: + unicode +except NameError: + raise ImportError + +from pybench import Test +from string import join + +class ConcatUnicode(Test): + + version = 2.0 + operations = 10 * 5 + rounds = 60000 + + def test(self): + + # Make sure the strings are *not* interned + s = unicode(join(map(str,range(100)))) + t = unicode(join(map(str,range(1,101)))) + + for i in xrange(self.rounds): + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + t + s + t + s + t + s + t + s + t + s + + def calibrate(self): + + s = unicode(join(map(str,range(100)))) + t = unicode(join(map(str,range(1,101)))) + + for i in xrange(self.rounds): + pass + + +class CompareUnicode(Test): + + version = 2.0 + operations = 10 * 5 + rounds = 150000 + + def test(self): + + # Make sure the strings are *not* interned + s = unicode(join(map(str,range(10)))) + t = unicode(join(map(str,range(10))) + "abc") + + for i in xrange(self.rounds): + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + t < s + t > s + t == s + t > s + t < s + + def calibrate(self): + + s = unicode(join(map(str,range(10)))) + t = unicode(join(map(str,range(10))) + "abc") + + for i in xrange(self.rounds): + pass + + +class CreateUnicodeWithConcat(Test): + + version = 2.0 + operations = 10 * 5 + rounds = 80000 + + def test(self): + + for i in xrange(self.rounds): + s = u'om' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + s = s + u'xax' + s = s + u'xbx' + s = s + u'xcx' + s = s + u'xdx' + s = s + u'xex' + + def calibrate(self): + + for i in xrange(self.rounds): + pass + + +class UnicodeSlicing(Test): + + version = 2.0 + operations = 5 * 7 + rounds = 140000 + + def test(self): + + s = unicode(join(map(str,range(100)))) + + for i in xrange(self.rounds): + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + s[50:] + s[:25] + s[50:55] + s[-1:] + s[:1] + s[2:] + s[11:-11] + + def calibrate(self): + + s = unicode(join(map(str,range(100)))) + + for i in xrange(self.rounds): + pass + +### String methods + +class UnicodeMappings(Test): + + version = 2.0 + operations = 3 * (5 + 4 + 2 + 1) + rounds = 10000 + + def test(self): + + s = join(map(unichr,range(20)),'') + t = join(map(unichr,range(100)),'') + u = join(map(unichr,range(500)),'') + v = join(map(unichr,range(1000)),'') + + for i in xrange(self.rounds): + + s.lower() + s.lower() + s.lower() + s.lower() + s.lower() + + s.upper() + s.upper() + s.upper() + s.upper() + s.upper() + + s.title() + s.title() + s.title() + s.title() + s.title() + + t.lower() + t.lower() + t.lower() + t.lower() + + t.upper() + t.upper() + t.upper() + t.upper() + + t.title() + t.title() + t.title() + t.title() + + u.lower() + u.lower() + + u.upper() + u.upper() + + u.title() + u.title() + + v.lower() + + v.upper() + + v.title() + + def calibrate(self): + + s = join(map(unichr,range(20)),'') + t = join(map(unichr,range(100)),'') + u = join(map(unichr,range(500)),'') + v = join(map(unichr,range(1000)),'') + + for i in xrange(self.rounds): + pass + +class UnicodePredicates(Test): + + version = 2.0 + operations = 5 * 9 + rounds = 120000 + + def test(self): + + data = (u'abc', u'123', u' ', u'\u1234\u2345\u3456', u'\uFFFF'*10) + len_data = len(data) + + for i in xrange(self.rounds): + s = data[i % len_data] + + s.isalnum() + s.isalpha() + s.isdecimal() + s.isdigit() + s.islower() + s.isnumeric() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdecimal() + s.isdigit() + s.islower() + s.isnumeric() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdecimal() + s.isdigit() + s.islower() + s.isnumeric() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdecimal() + s.isdigit() + s.islower() + s.isnumeric() + s.isspace() + s.istitle() + s.isupper() + + s.isalnum() + s.isalpha() + s.isdecimal() + s.isdigit() + s.islower() + s.isnumeric() + s.isspace() + s.istitle() + s.isupper() + + def calibrate(self): + + data = (u'abc', u'123', u' ', u'\u1234\u2345\u3456', u'\uFFFF'*10) + len_data = len(data) + + for i in xrange(self.rounds): + s = data[i % len_data] + +try: + import unicodedata +except ImportError: + pass +else: + class UnicodeProperties(Test): + + version = 2.0 + operations = 5 * 8 + rounds = 100000 + + def test(self): + + data = (u'a', u'1', u' ', u'\u1234', u'\uFFFF') + len_data = len(data) + digit = unicodedata.digit + numeric = unicodedata.numeric + decimal = unicodedata.decimal + category = unicodedata.category + bidirectional = unicodedata.bidirectional + decomposition = unicodedata.decomposition + mirrored = unicodedata.mirrored + combining = unicodedata.combining + + for i in xrange(self.rounds): + + c = data[i % len_data] + + digit(c, None) + numeric(c, None) + decimal(c, None) + category(c) + bidirectional(c) + decomposition(c) + mirrored(c) + combining(c) + + digit(c, None) + numeric(c, None) + decimal(c, None) + category(c) + bidirectional(c) + decomposition(c) + mirrored(c) + combining(c) + + digit(c, None) + numeric(c, None) + decimal(c, None) + category(c) + bidirectional(c) + decomposition(c) + mirrored(c) + combining(c) + + digit(c, None) + numeric(c, None) + decimal(c, None) + category(c) + bidirectional(c) + decomposition(c) + mirrored(c) + combining(c) + + digit(c, None) + numeric(c, None) + decimal(c, None) + category(c) + bidirectional(c) + decomposition(c) + mirrored(c) + combining(c) + + def calibrate(self): + + data = (u'a', u'1', u' ', u'\u1234', u'\uFFFF') + len_data = len(data) + digit = unicodedata.digit + numeric = unicodedata.numeric + decimal = unicodedata.decimal + category = unicodedata.category + bidirectional = unicodedata.bidirectional + decomposition = unicodedata.decomposition + mirrored = unicodedata.mirrored + combining = unicodedata.combining + + for i in xrange(self.rounds): + + c = data[i % len_data] diff --git a/sys/src/cmd/python/Tools/pybench/clockres.py b/sys/src/cmd/python/Tools/pybench/clockres.py new file mode 100644 index 000000000..64095b3a5 --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/clockres.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +""" clockres - calculates the resolution in seconds of a given timer. + + Copyright (c) 2006, Marc-Andre Lemburg (mal@egenix.com). See the + documentation for further information on copyrights, or contact + the author. All Rights Reserved. + +""" +import time + +TEST_TIME = 1.0 + +def clockres(timer): + d = {} + wallclock = time.time + start = wallclock() + stop = wallclock() + TEST_TIME + spin_loops = range(1000) + while 1: + now = wallclock() + if now >= stop: + break + for i in spin_loops: + d[timer()] = 1 + values = d.keys() + values.sort() + min_diff = TEST_TIME + for i in range(len(values) - 1): + diff = values[i+1] - values[i] + if diff < min_diff: + min_diff = diff + return min_diff + +if __name__ == '__main__': + print 'Clock resolution of various timer implementations:' + print 'time.clock: %10.3fus' % (clockres(time.clock) * 1e6) + print 'time.time: %10.3fus' % (clockres(time.time) * 1e6) + try: + import systimes + print 'systimes.processtime: %10.3fus' % (clockres(systimes.processtime) * 1e6) + except ImportError: + pass diff --git a/sys/src/cmd/python/Tools/pybench/package/__init__.py b/sys/src/cmd/python/Tools/pybench/package/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sys/src/cmd/python/Tools/pybench/package/submodule.py b/sys/src/cmd/python/Tools/pybench/package/submodule.py new file mode 100644 index 000000000..e69de29bb diff --git a/sys/src/cmd/python/Tools/pybench/pybench.py b/sys/src/cmd/python/Tools/pybench/pybench.py new file mode 100755 index 000000000..242f0399b --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/pybench.py @@ -0,0 +1,943 @@ +#!/usr/local/bin/python -O + +""" A Python Benchmark Suite + +""" +# +# Note: Please keep this module compatible to Python 1.5.2. +# +# Tests may include features in later Python versions, but these +# should then be embedded in try-except clauses in the configuration +# module Setup.py. +# + +# pybench Copyright +__copyright__ = """\ +Copyright (c), 1997-2006, Marc-Andre Lemburg (mal@lemburg.com) +Copyright (c), 2000-2006, eGenix.com Software GmbH (info@egenix.com) + + All Rights Reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee or royalty is hereby +granted, provided that the above copyright notice appear in all copies +and that both that copyright notice and this permission notice appear +in supporting documentation or portions thereof, including +modifications, that you make. + +THE AUTHOR MARC-ANDRE LEMBURG DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! +""" + +import sys, time, operator, string +from CommandLine import * + +try: + import cPickle + pickle = cPickle +except ImportError: + import pickle + +# Version number; version history: see README file ! +__version__ = '2.0' + +### Constants + +# Second fractions +MILLI_SECONDS = 1e3 +MICRO_SECONDS = 1e6 + +# Percent unit +PERCENT = 100 + +# Horizontal line length +LINE = 79 + +# Minimum test run-time +MIN_TEST_RUNTIME = 1e-3 + +# Number of calibration runs to use for calibrating the tests +CALIBRATION_RUNS = 20 + +# Number of calibration loops to run for each calibration run +CALIBRATION_LOOPS = 20 + +# Allow skipping calibration ? +ALLOW_SKIPPING_CALIBRATION = 1 + +# Timer types +TIMER_TIME_TIME = 'time.time' +TIMER_TIME_CLOCK = 'time.clock' +TIMER_SYSTIMES_PROCESSTIME = 'systimes.processtime' + +# Choose platform default timer +if sys.platform[:3] == 'win': + # On WinXP this has 2.5ms resolution + TIMER_PLATFORM_DEFAULT = TIMER_TIME_CLOCK +else: + # On Linux this has 1ms resolution + TIMER_PLATFORM_DEFAULT = TIMER_TIME_TIME + +# Print debug information ? +_debug = 0 + +### Helpers + +def get_timer(timertype): + + if timertype == TIMER_TIME_TIME: + return time.time + elif timertype == TIMER_TIME_CLOCK: + return time.clock + elif timertype == TIMER_SYSTIMES_PROCESSTIME: + import systimes + return systimes.processtime + else: + raise TypeError('unknown timer type: %s' % timertype) + +def get_machine_details(): + + import platform + if _debug: + print 'Getting machine details...' + buildno, builddate = platform.python_build() + python = platform.python_version() + if python > '2.0': + try: + unichr(100000) + except ValueError: + # UCS2 build (standard) + unicode = 'UCS2' + else: + # UCS4 build (most recent Linux distros) + unicode = 'UCS4' + else: + unicode = None + bits, linkage = platform.architecture() + return { + 'platform': platform.platform(), + 'processor': platform.processor(), + 'executable': sys.executable, + 'python': platform.python_version(), + 'compiler': platform.python_compiler(), + 'buildno': buildno, + 'builddate': builddate, + 'unicode': unicode, + 'bits': bits, + } + +def print_machine_details(d, indent=''): + + l = ['Machine Details:', + ' Platform ID: %s' % d.get('platform', 'n/a'), + ' Processor: %s' % d.get('processor', 'n/a'), + '', + 'Python:', + ' Executable: %s' % d.get('executable', 'n/a'), + ' Version: %s' % d.get('python', 'n/a'), + ' Compiler: %s' % d.get('compiler', 'n/a'), + ' Bits: %s' % d.get('bits', 'n/a'), + ' Build: %s (#%s)' % (d.get('builddate', 'n/a'), + d.get('buildno', 'n/a')), + ' Unicode: %s' % d.get('unicode', 'n/a'), + ] + print indent + string.join(l, '\n' + indent) + '\n' + +### Test baseclass + +class Test: + + """ All test must have this class as baseclass. It provides + the necessary interface to the benchmark machinery. + + The tests must set .rounds to a value high enough to let the + test run between 20-50 seconds. This is needed because + clock()-timing only gives rather inaccurate values (on Linux, + for example, it is accurate to a few hundreths of a + second). If you don't want to wait that long, use a warp + factor larger than 1. + + It is also important to set the .operations variable to a + value representing the number of "virtual operations" done per + call of .run(). + + If you change a test in some way, don't forget to increase + it's version number. + + """ + + ### Instance variables that each test should override + + # Version number of the test as float (x.yy); this is important + # for comparisons of benchmark runs - tests with unequal version + # number will not get compared. + version = 2.0 + + # The number of abstract operations done in each round of the + # test. An operation is the basic unit of what you want to + # measure. The benchmark will output the amount of run-time per + # operation. Note that in order to raise the measured timings + # significantly above noise level, it is often required to repeat + # sets of operations more than once per test round. The measured + # overhead per test round should be less than 1 second. + operations = 1 + + # Number of rounds to execute per test run. This should be + # adjusted to a figure that results in a test run-time of between + # 1-2 seconds. + rounds = 100000 + + ### Internal variables + + # Mark this class as implementing a test + is_a_test = 1 + + # Last timing: (real, run, overhead) + last_timing = (0.0, 0.0, 0.0) + + # Warp factor to use for this test + warp = 1 + + # Number of calibration runs to use + calibration_runs = CALIBRATION_RUNS + + # List of calibration timings + overhead_times = None + + # List of test run timings + times = [] + + # Timer used for the benchmark + timer = TIMER_PLATFORM_DEFAULT + + def __init__(self, warp=None, calibration_runs=None, timer=None): + + # Set parameters + if warp is not None: + self.rounds = int(self.rounds / warp) + if self.rounds == 0: + raise ValueError('warp factor set too high') + self.warp = warp + if calibration_runs is not None: + if (not ALLOW_SKIPPING_CALIBRATION and + calibration_runs < 1): + raise ValueError('at least one calibration run is required') + self.calibration_runs = calibration_runs + if timer is not None: + timer = timer + + # Init variables + self.times = [] + self.overhead_times = [] + + # We want these to be in the instance dict, so that pickle + # saves them + self.version = self.version + self.operations = self.operations + self.rounds = self.rounds + + def get_timer(self): + + """ Return the timer function to use for the test. + + """ + return get_timer(self.timer) + + def compatible(self, other): + + """ Return 1/0 depending on whether the test is compatible + with the other Test instance or not. + + """ + if self.version != other.version: + return 0 + if self.rounds != other.rounds: + return 0 + return 1 + + def calibrate_test(self): + + if self.calibration_runs == 0: + self.overhead_times = [0.0] + return + + calibrate = self.calibrate + timer = self.get_timer() + calibration_loops = range(CALIBRATION_LOOPS) + + # Time the calibration loop overhead + prep_times = [] + for i in range(self.calibration_runs): + t = timer() + for i in calibration_loops: + pass + t = timer() - t + prep_times.append(t) + min_prep_time = min(prep_times) + if _debug: + print + print 'Calib. prep time = %.6fms' % ( + min_prep_time * MILLI_SECONDS) + + # Time the calibration runs (doing CALIBRATION_LOOPS loops of + # .calibrate() method calls each) + for i in range(self.calibration_runs): + t = timer() + for i in calibration_loops: + calibrate() + t = timer() - t + self.overhead_times.append(t / CALIBRATION_LOOPS + - min_prep_time) + + # Check the measured times + min_overhead = min(self.overhead_times) + max_overhead = max(self.overhead_times) + if _debug: + print 'Calib. overhead time = %.6fms' % ( + min_overhead * MILLI_SECONDS) + if min_overhead < 0.0: + raise ValueError('calibration setup did not work') + if max_overhead - min_overhead > 0.1: + raise ValueError( + 'overhead calibration timing range too inaccurate: ' + '%r - %r' % (min_overhead, max_overhead)) + + def run(self): + + """ Run the test in two phases: first calibrate, then + do the actual test. Be careful to keep the calibration + timing low w/r to the test timing. + + """ + test = self.test + timer = self.get_timer() + + # Get calibration + min_overhead = min(self.overhead_times) + + # Test run + t = timer() + test() + t = timer() - t + if t < MIN_TEST_RUNTIME: + raise ValueError('warp factor too high: ' + 'test times are < 10ms') + eff_time = t - min_overhead + if eff_time < 0: + raise ValueError('wrong calibration') + self.last_timing = (eff_time, t, min_overhead) + self.times.append(eff_time) + + def calibrate(self): + + """ Calibrate the test. + + This method should execute everything that is needed to + setup and run the test - except for the actual operations + that you intend to measure. pybench uses this method to + measure the test implementation overhead. + + """ + return + + def test(self): + + """ Run the test. + + The test needs to run self.rounds executing + self.operations number of operations each. + + """ + return + + def stat(self): + + """ Return test run statistics as tuple: + + (minimum run time, + average run time, + total run time, + average time per operation, + minimum overhead time) + + """ + runs = len(self.times) + if runs == 0: + return 0.0, 0.0, 0.0, 0.0 + min_time = min(self.times) + total_time = reduce(operator.add, self.times, 0.0) + avg_time = total_time / float(runs) + operation_avg = total_time / float(runs + * self.rounds + * self.operations) + if self.overhead_times: + min_overhead = min(self.overhead_times) + else: + min_overhead = self.last_timing[2] + return min_time, avg_time, total_time, operation_avg, min_overhead + +### Load Setup + +# This has to be done after the definition of the Test class, since +# the Setup module will import subclasses using this class. + +import Setup + +### Benchmark base class + +class Benchmark: + + # Name of the benchmark + name = '' + + # Number of benchmark rounds to run + rounds = 1 + + # Warp factor use to run the tests + warp = 1 # Warp factor + + # Average benchmark round time + roundtime = 0 + + # Benchmark version number as float x.yy + version = 2.0 + + # Produce verbose output ? + verbose = 0 + + # Dictionary with the machine details + machine_details = None + + # Timer used for the benchmark + timer = TIMER_PLATFORM_DEFAULT + + def __init__(self, name, verbose=None, timer=None, warp=None, + calibration_runs=None): + + if name: + self.name = name + else: + self.name = '%04i-%02i-%02i %02i:%02i:%02i' % \ + (time.localtime(time.time())[:6]) + if verbose is not None: + self.verbose = verbose + if timer is not None: + self.timer = timer + if warp is not None: + self.warp = warp + if calibration_runs is not None: + self.calibration_runs = calibration_runs + + # Init vars + self.tests = {} + if _debug: + print 'Getting machine details...' + self.machine_details = get_machine_details() + + # Make .version an instance attribute to have it saved in the + # Benchmark pickle + self.version = self.version + + def get_timer(self): + + """ Return the timer function to use for the test. + + """ + return get_timer(self.timer) + + def compatible(self, other): + + """ Return 1/0 depending on whether the benchmark is + compatible with the other Benchmark instance or not. + + """ + if self.version != other.version: + return 0 + if (self.machine_details == other.machine_details and + self.timer != other.timer): + return 0 + if (self.calibration_runs == 0 and + other.calibration_runs != 0): + return 0 + if (self.calibration_runs != 0 and + other.calibration_runs == 0): + return 0 + return 1 + + def load_tests(self, setupmod, limitnames=None): + + # Add tests + if self.verbose: + print 'Searching for tests ...' + print '--------------------------------------' + for testclass in setupmod.__dict__.values(): + if not hasattr(testclass, 'is_a_test'): + continue + name = testclass.__name__ + if name == 'Test': + continue + if (limitnames is not None and + limitnames.search(name) is None): + continue + self.tests[name] = testclass( + warp=self.warp, + calibration_runs=self.calibration_runs, + timer=self.timer) + l = self.tests.keys() + l.sort() + if self.verbose: + for name in l: + print ' %s' % name + print '--------------------------------------' + print ' %i tests found' % len(l) + print + + def calibrate(self): + + print 'Calibrating tests. Please wait...' + if self.verbose: + print + print 'Test min max' + print '-' * LINE + tests = self.tests.items() + tests.sort() + for i in range(len(tests)): + name, test = tests[i] + test.calibrate_test() + if self.verbose: + print '%30s: %6.3fms %6.3fms' % \ + (name, + min(test.overhead_times) * MILLI_SECONDS, + max(test.overhead_times) * MILLI_SECONDS) + print + + def run(self): + + tests = self.tests.items() + tests.sort() + timer = self.get_timer() + print 'Running %i round(s) of the suite at warp factor %i:' % \ + (self.rounds, self.warp) + print + self.roundtimes = [] + for i in range(self.rounds): + if self.verbose: + print ' Round %-25i effective absolute overhead' % (i+1) + total_eff_time = 0.0 + for j in range(len(tests)): + name, test = tests[j] + if self.verbose: + print '%30s:' % name, + test.run() + (eff_time, abs_time, min_overhead) = test.last_timing + total_eff_time = total_eff_time + eff_time + if self.verbose: + print ' %5.0fms %5.0fms %7.3fms' % \ + (eff_time * MILLI_SECONDS, + abs_time * MILLI_SECONDS, + min_overhead * MILLI_SECONDS) + self.roundtimes.append(total_eff_time) + if self.verbose: + print (' ' + ' ------------------------------') + print (' ' + ' Totals: %6.0fms' % + (total_eff_time * MILLI_SECONDS)) + print + else: + print '* Round %i done in %.3f seconds.' % (i+1, + total_eff_time) + print + + def stat(self): + + """ Return benchmark run statistics as tuple: + + (minimum round time, + average round time, + maximum round time) + + XXX Currently not used, since the benchmark does test + statistics across all rounds. + + """ + runs = len(self.roundtimes) + if runs == 0: + return 0.0, 0.0 + min_time = min(self.roundtimes) + total_time = reduce(operator.add, self.roundtimes, 0.0) + avg_time = total_time / float(runs) + max_time = max(self.roundtimes) + return (min_time, avg_time, max_time) + + def print_header(self, title='Benchmark'): + + print '-' * LINE + print '%s: %s' % (title, self.name) + print '-' * LINE + print + print ' Rounds: %s' % self.rounds + print ' Warp: %s' % self.warp + print ' Timer: %s' % self.timer + print + if self.machine_details: + print_machine_details(self.machine_details, indent=' ') + print + + def print_benchmark(self, hidenoise=0, limitnames=None): + + print ('Test ' + ' minimum average operation overhead') + print '-' * LINE + tests = self.tests.items() + tests.sort() + total_min_time = 0.0 + total_avg_time = 0.0 + for name, test in tests: + if (limitnames is not None and + limitnames.search(name) is None): + continue + (min_time, + avg_time, + total_time, + op_avg, + min_overhead) = test.stat() + total_min_time = total_min_time + min_time + total_avg_time = total_avg_time + avg_time + print '%30s: %5.0fms %5.0fms %6.2fus %7.3fms' % \ + (name, + min_time * MILLI_SECONDS, + avg_time * MILLI_SECONDS, + op_avg * MICRO_SECONDS, + min_overhead *MILLI_SECONDS) + print '-' * LINE + print ('Totals: ' + ' %6.0fms %6.0fms' % + (total_min_time * MILLI_SECONDS, + total_avg_time * MILLI_SECONDS, + )) + print + + def print_comparison(self, compare_to, hidenoise=0, limitnames=None): + + # Check benchmark versions + if compare_to.version != self.version: + print ('* Benchmark versions differ: ' + 'cannot compare this benchmark to "%s" !' % + compare_to.name) + print + self.print_benchmark(hidenoise=hidenoise, + limitnames=limitnames) + return + + # Print header + compare_to.print_header('Comparing with') + print ('Test ' + ' minimum run-time average run-time') + print (' ' + ' this other diff this other diff') + print '-' * LINE + + # Print test comparisons + tests = self.tests.items() + tests.sort() + total_min_time = other_total_min_time = 0.0 + total_avg_time = other_total_avg_time = 0.0 + benchmarks_compatible = self.compatible(compare_to) + tests_compatible = 1 + for name, test in tests: + if (limitnames is not None and + limitnames.search(name) is None): + continue + (min_time, + avg_time, + total_time, + op_avg, + min_overhead) = test.stat() + total_min_time = total_min_time + min_time + total_avg_time = total_avg_time + avg_time + try: + other = compare_to.tests[name] + except KeyError: + other = None + if other is None: + # Other benchmark doesn't include the given test + min_diff, avg_diff = 'n/a', 'n/a' + other_min_time = 0.0 + other_avg_time = 0.0 + tests_compatible = 0 + else: + (other_min_time, + other_avg_time, + other_total_time, + other_op_avg, + other_min_overhead) = other.stat() + other_total_min_time = other_total_min_time + other_min_time + other_total_avg_time = other_total_avg_time + other_avg_time + if (benchmarks_compatible and + test.compatible(other)): + # Both benchmark and tests are comparible + min_diff = ((min_time * self.warp) / + (other_min_time * other.warp) - 1.0) + avg_diff = ((avg_time * self.warp) / + (other_avg_time * other.warp) - 1.0) + if hidenoise and abs(min_diff) < 10.0: + min_diff = '' + else: + min_diff = '%+5.1f%%' % (min_diff * PERCENT) + if hidenoise and abs(avg_diff) < 10.0: + avg_diff = '' + else: + avg_diff = '%+5.1f%%' % (avg_diff * PERCENT) + else: + # Benchmark or tests are not comparible + min_diff, avg_diff = 'n/a', 'n/a' + tests_compatible = 0 + print '%30s: %5.0fms %5.0fms %7s %5.0fms %5.0fms %7s' % \ + (name, + min_time * MILLI_SECONDS, + other_min_time * MILLI_SECONDS * compare_to.warp / self.warp, + min_diff, + avg_time * MILLI_SECONDS, + other_avg_time * MILLI_SECONDS * compare_to.warp / self.warp, + avg_diff) + print '-' * LINE + + # Summarise test results + if not benchmarks_compatible or not tests_compatible: + min_diff, avg_diff = 'n/a', 'n/a' + else: + if other_total_min_time != 0.0: + min_diff = '%+5.1f%%' % ( + ((total_min_time * self.warp) / + (other_total_min_time * compare_to.warp) - 1.0) * PERCENT) + else: + min_diff = 'n/a' + if other_total_avg_time != 0.0: + avg_diff = '%+5.1f%%' % ( + ((total_avg_time * self.warp) / + (other_total_avg_time * compare_to.warp) - 1.0) * PERCENT) + else: + avg_diff = 'n/a' + print ('Totals: ' + ' %5.0fms %5.0fms %7s %5.0fms %5.0fms %7s' % + (total_min_time * MILLI_SECONDS, + (other_total_min_time * compare_to.warp/self.warp + * MILLI_SECONDS), + min_diff, + total_avg_time * MILLI_SECONDS, + (other_total_avg_time * compare_to.warp/self.warp + * MILLI_SECONDS), + avg_diff + )) + print + print '(this=%s, other=%s)' % (self.name, + compare_to.name) + print + +class PyBenchCmdline(Application): + + header = ("PYBENCH - a benchmark test suite for Python " + "interpreters/compilers.") + + version = __version__ + + debug = _debug + + options = [ArgumentOption('-n', + 'number of rounds', + Setup.Number_of_rounds), + ArgumentOption('-f', + 'save benchmark to file arg', + ''), + ArgumentOption('-c', + 'compare benchmark with the one in file arg', + ''), + ArgumentOption('-s', + 'show benchmark in file arg, then exit', + ''), + ArgumentOption('-w', + 'set warp factor to arg', + Setup.Warp_factor), + ArgumentOption('-t', + 'run only tests with names matching arg', + ''), + ArgumentOption('-C', + 'set the number of calibration runs to arg', + CALIBRATION_RUNS), + SwitchOption('-d', + 'hide noise in comparisons', + 0), + SwitchOption('-v', + 'verbose output (not recommended)', + 0), + SwitchOption('--with-gc', + 'enable garbage collection', + 0), + SwitchOption('--with-syscheck', + 'use default sys check interval', + 0), + ArgumentOption('--timer', + 'use given timer', + TIMER_PLATFORM_DEFAULT), + ] + + about = """\ +The normal operation is to run the suite and display the +results. Use -f to save them for later reuse or comparisons. + +Available timers: + + time.time + time.clock + systimes.processtime + +Examples: + +python2.1 pybench.py -f p21.pybench +python2.5 pybench.py -f p25.pybench +python pybench.py -s p25.pybench -c p21.pybench +""" + copyright = __copyright__ + + def main(self): + + rounds = self.values['-n'] + reportfile = self.values['-f'] + show_bench = self.values['-s'] + compare_to = self.values['-c'] + hidenoise = self.values['-d'] + warp = int(self.values['-w']) + withgc = self.values['--with-gc'] + limitnames = self.values['-t'] + if limitnames: + if _debug: + print '* limiting test names to one with substring "%s"' % \ + limitnames + limitnames = re.compile(limitnames, re.I) + else: + limitnames = None + verbose = self.verbose + withsyscheck = self.values['--with-syscheck'] + calibration_runs = self.values['-C'] + timer = self.values['--timer'] + + print '-' * LINE + print 'PYBENCH %s' % __version__ + print '-' * LINE + print '* using Python %s' % (string.split(sys.version)[0]) + + # Switch off garbage collection + if not withgc: + try: + import gc + except ImportError: + print '* Python version doesn\'t support garbage collection' + else: + gc.disable() + print '* disabled garbage collection' + + # "Disable" sys check interval + if not withsyscheck: + # Too bad the check interval uses an int instead of a long... + value = 2147483647 + sys.setcheckinterval(value) + print '* system check interval set to maximum: %s' % value + + if timer == TIMER_SYSTIMES_PROCESSTIME: + import systimes + print '* using timer: systimes.processtime (%s)' % \ + systimes.SYSTIMES_IMPLEMENTATION + else: + print '* using timer: %s' % timer + + print + + if compare_to: + try: + f = open(compare_to,'rb') + bench = pickle.load(f) + bench.name = compare_to + f.close() + compare_to = bench + except IOError, reason: + print '* Error opening/reading file %s: %s' % ( + repr(compare_to), + reason) + compare_to = None + + if show_bench: + try: + f = open(show_bench,'rb') + bench = pickle.load(f) + bench.name = show_bench + f.close() + bench.print_header() + if compare_to: + bench.print_comparison(compare_to, + hidenoise=hidenoise, + limitnames=limitnames) + else: + bench.print_benchmark(hidenoise=hidenoise, + limitnames=limitnames) + except IOError, reason: + print '* Error opening/reading file %s: %s' % ( + repr(show_bench), + reason) + print + return + + if reportfile: + print 'Creating benchmark: %s (rounds=%i, warp=%i)' % \ + (reportfile, rounds, warp) + print + + # Create benchmark object + bench = Benchmark(reportfile, + verbose=verbose, + timer=timer, + warp=warp, + calibration_runs=calibration_runs) + bench.rounds = rounds + bench.load_tests(Setup, limitnames=limitnames) + try: + bench.calibrate() + bench.run() + except KeyboardInterrupt: + print + print '*** KeyboardInterrupt -- Aborting' + print + return + bench.print_header() + if compare_to: + bench.print_comparison(compare_to, + hidenoise=hidenoise, + limitnames=limitnames) + else: + bench.print_benchmark(hidenoise=hidenoise, + limitnames=limitnames) + + # Ring bell + sys.stderr.write('\007') + + if reportfile: + try: + f = open(reportfile,'wb') + bench.name = reportfile + pickle.dump(bench,f) + f.close() + except IOError, reason: + print '* Error opening/writing reportfile' + except IOError, reason: + print '* Error opening/writing reportfile %s: %s' % ( + reportfile, + reason) + print + +if __name__ == '__main__': + PyBenchCmdline() diff --git a/sys/src/cmd/python/Tools/pybench/systimes.py b/sys/src/cmd/python/Tools/pybench/systimes.py new file mode 100644 index 000000000..bf07e36dd --- /dev/null +++ b/sys/src/cmd/python/Tools/pybench/systimes.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python + +""" systimes() user and system timer implementations for use by + pybench. + + This module implements various different strategies for measuring + performance timings. It tries to choose the best available method + based on the platforma and available tools. + + On Windows, it is recommended to have the Mark Hammond win32 + package installed. Alternatively, the Thomas Heller ctypes + packages can also be used. + + On Unix systems, the standard resource module provides the highest + resolution timings. Unfortunately, it is not available on all Unix + platforms. + + If no supported timing methods based on process time can be found, + the module reverts to the highest resolution wall-clock timer + instead. The system time part will then always be 0.0. + + The module exports one public API: + + def systimes(): + + Return the current timer values for measuring user and system + time as tuple of seconds (user_time, system_time). + + Copyright (c) 2006, Marc-Andre Lemburg (mal@egenix.com). See the + documentation for further information on copyrights, or contact + the author. All Rights Reserved. + +""" +import time, sys, struct + +# +# Note: Please keep this module compatible to Python 1.5.2. +# +# TODOs: +# +# * Add ctypes wrapper for new clock_gettime() real-time POSIX APIs; +# these will then provide nano-second resolution where available. +# +# * Add a function that returns the resolution of systimes() +# values, ie. systimesres(). +# + +### Choose an implementation + +SYSTIMES_IMPLEMENTATION = None +USE_CTYPES_GETPROCESSTIMES = 'cytpes GetProcessTimes() wrapper' +USE_WIN32PROCESS_GETPROCESSTIMES = 'win32process.GetProcessTimes()' +USE_RESOURCE_GETRUSAGE = 'resource.getrusage()' +USE_PROCESS_TIME_CLOCK = 'time.clock() (process time)' +USE_WALL_TIME_CLOCK = 'time.clock() (wall-clock)' +USE_WALL_TIME_TIME = 'time.time() (wall-clock)' + +if sys.platform[:3] == 'win': + # Windows platform + try: + import win32process + except ImportError: + try: + import ctypes + except ImportError: + # Use the wall-clock implementation time.clock(), since this + # is the highest resolution clock available on Windows + SYSTIMES_IMPLEMENTATION = USE_WALL_TIME_CLOCK + else: + SYSTIMES_IMPLEMENTATION = USE_CTYPES_GETPROCESSTIMES + else: + SYSTIMES_IMPLEMENTATION = USE_WIN32PROCESS_GETPROCESSTIMES +else: + # All other platforms + try: + import resource + except ImportError: + pass + else: + SYSTIMES_IMPLEMENTATION = USE_RESOURCE_GETRUSAGE + +# Fall-back solution +if SYSTIMES_IMPLEMENTATION is None: + # Check whether we can use time.clock() as approximation + # for systimes() + start = time.clock() + time.sleep(0.1) + stop = time.clock() + if stop - start < 0.001: + # Looks like time.clock() is usable (and measures process + # time) + SYSTIMES_IMPLEMENTATION = USE_PROCESS_TIME_CLOCK + else: + # Use wall-clock implementation time.time() since this provides + # the highest resolution clock on most systems + SYSTIMES_IMPLEMENTATION = USE_WALL_TIME_TIME + +### Implementations + +def getrusage_systimes(): + return resource.getrusage(resource.RUSAGE_SELF)[:2] + +def process_time_clock_systimes(): + return (time.clock(), 0.0) + +def wall_clock_clock_systimes(): + return (time.clock(), 0.0) + +def wall_clock_time_systimes(): + return (time.time(), 0.0) + +# Number of clock ticks per second for the values returned +# by GetProcessTimes() on Windows. +# +# Note: Ticks returned by GetProcessTimes() are 100ns intervals on +# Windows XP. However, the process times are only updated with every +# clock tick and the frequency of these is somewhat lower: depending +# on the OS version between 10ms and 15ms. Even worse, the process +# time seems to be allocated to process currently running when the +# clock interrupt arrives, ie. it is possible that the current time +# slice gets accounted to a different process. + +WIN32_PROCESS_TIMES_TICKS_PER_SECOND = 1e7 + +def win32process_getprocesstimes_systimes(): + d = win32process.GetProcessTimes(win32process.GetCurrentProcess()) + return (d['UserTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND, + d['KernelTime'] / WIN32_PROCESS_TIMES_TICKS_PER_SECOND) + +def ctypes_getprocesstimes_systimes(): + creationtime = ctypes.c_ulonglong() + exittime = ctypes.c_ulonglong() + kerneltime = ctypes.c_ulonglong() + usertime = ctypes.c_ulonglong() + rc = ctypes.windll.kernel32.GetProcessTimes( + ctypes.windll.kernel32.GetCurrentProcess(), + ctypes.byref(creationtime), + ctypes.byref(exittime), + ctypes.byref(kerneltime), + ctypes.byref(usertime)) + if not rc: + raise TypeError('GetProcessTimes() returned an error') + return (usertime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND, + kerneltime.value / WIN32_PROCESS_TIMES_TICKS_PER_SECOND) + +# Select the default for the systimes() function + +if SYSTIMES_IMPLEMENTATION is USE_RESOURCE_GETRUSAGE: + systimes = getrusage_systimes + +elif SYSTIMES_IMPLEMENTATION is USE_PROCESS_TIME_CLOCK: + systimes = process_time_clock_systimes + +elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_CLOCK: + systimes = wall_clock_clock_systimes + +elif SYSTIMES_IMPLEMENTATION is USE_WALL_TIME_TIME: + systimes = wall_clock_time_systimes + +elif SYSTIMES_IMPLEMENTATION is USE_WIN32PROCESS_GETPROCESSTIMES: + systimes = win32process_getprocesstimes_systimes + +elif SYSTIMES_IMPLEMENTATION is USE_CTYPES_GETPROCESSTIMES: + systimes = ctypes_getprocesstimes_systimes + +else: + raise TypeError('no suitable systimes() implementation found') + +def processtime(): + + """ Return the total time spent on the process. + + This is the sum of user and system time as returned by + systimes(). + + """ + user, system = systimes() + return user + system + +### Testing + +def some_workload(): + x = 0L + for i in xrange(10000000L): + x = x + 1L + +def test_workload(): + print 'Testing systimes() under load conditions' + t0 = systimes() + some_workload() + t1 = systimes() + print 'before:', t0 + print 'after:', t1 + print 'differences:', (t1[0] - t0[0], t1[1] - t0[1]) + print + +def test_idle(): + print 'Testing systimes() under idle conditions' + t0 = systimes() + time.sleep(1) + t1 = systimes() + print 'before:', t0 + print 'after:', t1 + print 'differences:', (t1[0] - t0[0], t1[1] - t0[1]) + print + +if __name__ == '__main__': + print 'Using %s as timer' % SYSTIMES_IMPLEMENTATION + print + test_workload() + test_idle() diff --git a/sys/src/cmd/python/Tools/pynche/ChipViewer.py b/sys/src/cmd/python/Tools/pynche/ChipViewer.py new file mode 100644 index 000000000..05412cec4 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/ChipViewer.py @@ -0,0 +1,131 @@ +"""Chip viewer and widget. + +In the lower left corner of the main Pynche window, you will see two +ChipWidgets, one for the selected color and one for the nearest color. The +selected color is the actual RGB value expressed as an X11 #COLOR name. The +nearest color is the named color from the X11 database that is closest to the +selected color in 3D space. There may be other colors equally close, but the +nearest one is the first one found. + +Clicking on the nearest color chip selects that named color. + +The ChipViewer class includes the entire lower left quandrant; i.e. both the +selected and nearest ChipWidgets. +""" + +from types import StringType +from Tkinter import * +import ColorDB + + +class ChipWidget: + _WIDTH = 150 + _HEIGHT = 80 + + def __init__(self, + master = None, + width = _WIDTH, + height = _HEIGHT, + text = 'Color', + initialcolor = 'blue', + presscmd = None, + releasecmd = None): + # create the text label + self.__label = Label(master, text=text) + self.__label.grid(row=0, column=0) + # create the color chip, implemented as a frame + self.__chip = Frame(master, relief=RAISED, borderwidth=2, + width=width, + height=height, + background=initialcolor) + self.__chip.grid(row=1, column=0) + # create the color name + self.__namevar = StringVar() + self.__namevar.set(initialcolor) + self.__name = Entry(master, textvariable=self.__namevar, + relief=FLAT, justify=CENTER, state=DISABLED, + font=self.__label['font']) + self.__name.grid(row=2, column=0) + # create the message area + self.__msgvar = StringVar() + self.__name = Entry(master, textvariable=self.__msgvar, + relief=FLAT, justify=CENTER, state=DISABLED, + font=self.__label['font']) + self.__name.grid(row=3, column=0) + # set bindings + if presscmd: + self.__chip.bind('<ButtonPress-1>', presscmd) + if releasecmd: + self.__chip.bind('<ButtonRelease-1>', releasecmd) + + def set_color(self, color): + self.__chip.config(background=color) + + def get_color(self): + return self.__chip['background'] + + def set_name(self, colorname): + self.__namevar.set(colorname) + + def set_message(self, message): + self.__msgvar.set(message) + + def press(self): + self.__chip.configure(relief=SUNKEN) + + def release(self): + self.__chip.configure(relief=RAISED) + + + +class ChipViewer: + def __init__(self, switchboard, master=None): + self.__sb = switchboard + self.__frame = Frame(master, relief=RAISED, borderwidth=1) + self.__frame.grid(row=3, column=0, ipadx=5, sticky='NSEW') + # create the chip that will display the currently selected color + # exactly + self.__sframe = Frame(self.__frame) + self.__sframe.grid(row=0, column=0) + self.__selected = ChipWidget(self.__sframe, text='Selected') + # create the chip that will display the nearest real X11 color + # database color name + self.__nframe = Frame(self.__frame) + self.__nframe.grid(row=0, column=1) + self.__nearest = ChipWidget(self.__nframe, text='Nearest', + presscmd = self.__buttonpress, + releasecmd = self.__buttonrelease) + + def update_yourself(self, red, green, blue): + # Selected always shows the #rrggbb name of the color, nearest always + # shows the name of the nearest color in the database. BAW: should + # an exact match be indicated in some way? + # + # Always use the #rrggbb style to actually set the color, since we may + # not be using X color names (e.g. "web-safe" names) + colordb = self.__sb.colordb() + rgbtuple = (red, green, blue) + rrggbb = ColorDB.triplet_to_rrggbb(rgbtuple) + # find the nearest + nearest = colordb.nearest(red, green, blue) + nearest_tuple = colordb.find_byname(nearest) + nearest_rrggbb = ColorDB.triplet_to_rrggbb(nearest_tuple) + self.__selected.set_color(rrggbb) + self.__nearest.set_color(nearest_rrggbb) + # set the name and messages areas + self.__selected.set_name(rrggbb) + if rrggbb == nearest_rrggbb: + self.__selected.set_message(nearest) + else: + self.__selected.set_message('') + self.__nearest.set_name(nearest_rrggbb) + self.__nearest.set_message(nearest) + + def __buttonpress(self, event=None): + self.__nearest.press() + + def __buttonrelease(self, event=None): + self.__nearest.release() + rrggbb = self.__nearest.get_color() + red, green, blue = ColorDB.rrggbb_to_triplet(rrggbb) + self.__sb.update_views(red, green, blue) diff --git a/sys/src/cmd/python/Tools/pynche/ColorDB.py b/sys/src/cmd/python/Tools/pynche/ColorDB.py new file mode 100644 index 000000000..96b6ce67c --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/ColorDB.py @@ -0,0 +1,279 @@ +"""Color Database. + +This file contains one class, called ColorDB, and several utility functions. +The class must be instantiated by the get_colordb() function in this file, +passing it a filename to read a database out of. + +The get_colordb() function will try to examine the file to figure out what the +format of the file is. If it can't figure out the file format, or it has +trouble reading the file, None is returned. You can pass get_colordb() an +optional filetype argument. + +Supporte file types are: + + X_RGB_TXT -- X Consortium rgb.txt format files. Three columns of numbers + from 0 .. 255 separated by whitespace. Arbitrary trailing + columns used as the color name. + +The utility functions are useful for converting between the various expected +color formats, and for calculating other color values. + +""" + +import sys +import re +from types import * +import operator + +class BadColor(Exception): + pass + +DEFAULT_DB = None +SPACE = ' ' +COMMASPACE = ', ' + + + +# generic class +class ColorDB: + def __init__(self, fp): + lineno = 2 + self.__name = fp.name + # Maintain several dictionaries for indexing into the color database. + # Note that while Tk supports RGB intensities of 4, 8, 12, or 16 bits, + # for now we only support 8 bit intensities. At least on OpenWindows, + # all intensities in the /usr/openwin/lib/rgb.txt file are 8-bit + # + # key is (red, green, blue) tuple, value is (name, [aliases]) + self.__byrgb = {} + # key is name, value is (red, green, blue) + self.__byname = {} + # all unique names (non-aliases). built-on demand + self.__allnames = None + while 1: + line = fp.readline() + if not line: + break + # get this compiled regular expression from derived class + mo = self._re.match(line) + if not mo: + print >> sys.stderr, 'Error in', fp.name, ' line', lineno + lineno += 1 + continue + # extract the red, green, blue, and name + red, green, blue = self._extractrgb(mo) + name = self._extractname(mo) + keyname = name.lower() + # BAW: for now the `name' is just the first named color with the + # rgb values we find. Later, we might want to make the two word + # version the `name', or the CapitalizedVersion, etc. + key = (red, green, blue) + foundname, aliases = self.__byrgb.get(key, (name, [])) + if foundname <> name and foundname not in aliases: + aliases.append(name) + self.__byrgb[key] = (foundname, aliases) + # add to byname lookup + self.__byname[keyname] = key + lineno = lineno + 1 + + # override in derived classes + def _extractrgb(self, mo): + return [int(x) for x in mo.group('red', 'green', 'blue')] + + def _extractname(self, mo): + return mo.group('name') + + def filename(self): + return self.__name + + def find_byrgb(self, rgbtuple): + """Return name for rgbtuple""" + try: + return self.__byrgb[rgbtuple] + except KeyError: + raise BadColor(rgbtuple) + + def find_byname(self, name): + """Return (red, green, blue) for name""" + name = name.lower() + try: + return self.__byname[name] + except KeyError: + raise BadColor(name) + + def nearest(self, red, green, blue): + """Return the name of color nearest (red, green, blue)""" + # BAW: should we use Voronoi diagrams, Delaunay triangulation, or + # octree for speeding up the locating of nearest point? Exhaustive + # search is inefficient, but seems fast enough. + nearest = -1 + nearest_name = '' + for name, aliases in self.__byrgb.values(): + r, g, b = self.__byname[name.lower()] + rdelta = red - r + gdelta = green - g + bdelta = blue - b + distance = rdelta * rdelta + gdelta * gdelta + bdelta * bdelta + if nearest == -1 or distance < nearest: + nearest = distance + nearest_name = name + return nearest_name + + def unique_names(self): + # sorted + if not self.__allnames: + self.__allnames = [] + for name, aliases in self.__byrgb.values(): + self.__allnames.append(name) + # sort irregardless of case + def nocase_cmp(n1, n2): + return cmp(n1.lower(), n2.lower()) + self.__allnames.sort(nocase_cmp) + return self.__allnames + + def aliases_of(self, red, green, blue): + try: + name, aliases = self.__byrgb[(red, green, blue)] + except KeyError: + raise BadColor((red, green, blue)) + return [name] + aliases + + +class RGBColorDB(ColorDB): + _re = re.compile( + '\s*(?P<red>\d+)\s+(?P<green>\d+)\s+(?P<blue>\d+)\s+(?P<name>.*)') + + +class HTML40DB(ColorDB): + _re = re.compile('(?P<name>\S+)\s+(?P<hexrgb>#[0-9a-fA-F]{6})') + + def _extractrgb(self, mo): + return rrggbb_to_triplet(mo.group('hexrgb')) + +class LightlinkDB(HTML40DB): + _re = re.compile('(?P<name>(.+))\s+(?P<hexrgb>#[0-9a-fA-F]{6})') + + def _extractname(self, mo): + return mo.group('name').strip() + +class WebsafeDB(ColorDB): + _re = re.compile('(?P<hexrgb>#[0-9a-fA-F]{6})') + + def _extractrgb(self, mo): + return rrggbb_to_triplet(mo.group('hexrgb')) + + def _extractname(self, mo): + return mo.group('hexrgb').upper() + + + +# format is a tuple (RE, SCANLINES, CLASS) where RE is a compiled regular +# expression, SCANLINES is the number of header lines to scan, and CLASS is +# the class to instantiate if a match is found + +FILETYPES = [ + (re.compile('Xorg'), RGBColorDB), + (re.compile('XConsortium'), RGBColorDB), + (re.compile('HTML'), HTML40DB), + (re.compile('lightlink'), LightlinkDB), + (re.compile('Websafe'), WebsafeDB), + ] + +def get_colordb(file, filetype=None): + colordb = None + fp = open(file) + try: + line = fp.readline() + if not line: + return None + # try to determine the type of RGB file it is + if filetype is None: + filetypes = FILETYPES + else: + filetypes = [filetype] + for typere, class_ in filetypes: + mo = typere.search(line) + if mo: + break + else: + # no matching type + return None + # we know the type and the class to grok the type, so suck it in + colordb = class_(fp) + finally: + fp.close() + # save a global copy + global DEFAULT_DB + DEFAULT_DB = colordb + return colordb + + + +_namedict = {} + +def rrggbb_to_triplet(color): + """Converts a #rrggbb color to the tuple (red, green, blue).""" + rgbtuple = _namedict.get(color) + if rgbtuple is None: + if color[0] <> '#': + raise BadColor(color) + red = color[1:3] + green = color[3:5] + blue = color[5:7] + rgbtuple = int(red, 16), int(green, 16), int(blue, 16) + _namedict[color] = rgbtuple + return rgbtuple + + +_tripdict = {} +def triplet_to_rrggbb(rgbtuple): + """Converts a (red, green, blue) tuple to #rrggbb.""" + global _tripdict + hexname = _tripdict.get(rgbtuple) + if hexname is None: + hexname = '#%02x%02x%02x' % rgbtuple + _tripdict[rgbtuple] = hexname + return hexname + + +_maxtuple = (256.0,) * 3 +def triplet_to_fractional_rgb(rgbtuple): + return map(operator.__div__, rgbtuple, _maxtuple) + + +def triplet_to_brightness(rgbtuple): + # return the brightness (grey level) along the scale 0.0==black to + # 1.0==white + r = 0.299 + g = 0.587 + b = 0.114 + return r*rgbtuple[0] + g*rgbtuple[1] + b*rgbtuple[2] + + + +if __name__ == '__main__': + colordb = get_colordb('/usr/openwin/lib/rgb.txt') + if not colordb: + print 'No parseable color database found' + sys.exit(1) + # on my system, this color matches exactly + target = 'navy' + red, green, blue = rgbtuple = colordb.find_byname(target) + print target, ':', red, green, blue, triplet_to_rrggbb(rgbtuple) + name, aliases = colordb.find_byrgb(rgbtuple) + print 'name:', name, 'aliases:', COMMASPACE.join(aliases) + r, g, b = (1, 1, 128) # nearest to navy + r, g, b = (145, 238, 144) # nearest to lightgreen + r, g, b = (255, 251, 250) # snow + print 'finding nearest to', target, '...' + import time + t0 = time.time() + nearest = colordb.nearest(r, g, b) + t1 = time.time() + print 'found nearest color', nearest, 'in', t1-t0, 'seconds' + # dump the database + for n in colordb.unique_names(): + r, g, b = colordb.find_byname(n) + aliases = colordb.aliases_of(r, g, b) + print '%20s: (%3d/%3d/%3d) == %s' % (n, r, g, b, + SPACE.join(aliases[1:])) diff --git a/sys/src/cmd/python/Tools/pynche/DetailsViewer.py b/sys/src/cmd/python/Tools/pynche/DetailsViewer.py new file mode 100644 index 000000000..11a99a6af --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/DetailsViewer.py @@ -0,0 +1,273 @@ +"""DetailsViewer class. + +This class implements a pure input window which allows you to meticulously +edit the current color. You have both mouse control of the color (via the +buttons along the bottom row), and there are keyboard bindings for each of the +increment/decrement buttons. + +The top three check buttons allow you to specify which of the three color +variations are tied together when incrementing and decrementing. Red, green, +and blue are self evident. By tying together red and green, you can modify +the yellow level of the color. By tying together red and blue, you can modify +the magenta level of the color. By tying together green and blue, you can +modify the cyan level, and by tying all three together, you can modify the +grey level. + +The behavior at the boundaries (0 and 255) are defined by the `At boundary' +option menu: + + Stop + When the increment or decrement would send any of the tied variations + out of bounds, the entire delta is discarded. + + Wrap Around + When the increment or decrement would send any of the tied variations + out of bounds, the out of bounds variation is wrapped around to the + other side. Thus if red were at 238 and 25 were added to it, red + would have the value 7. + + Preseve Distance + When the increment or decrement would send any of the tied variations + out of bounds, all tied variations are wrapped as one, so as to + preserve the distance between them. Thus if green and blue were tied, + and green was at 238 while blue was at 223, and an increment of 25 + were applied, green would be at 15 and blue would be at 0. + + Squash + When the increment or decrement would send any of the tied variations + out of bounds, the out of bounds variation is set to the ceiling of + 255 or floor of 0, as appropriate. In this way, all tied variations + are squashed to one edge or the other. + +The following key bindings can be used as accelerators. Note that Pynche can +fall behind if you hold the key down as a key repeat: + +Left arrow == -1 +Right arrow == +1 + +Control + Left == -10 +Control + Right == 10 + +Shift + Left == -25 +Shift + Right == +25 +""" + +from Tkinter import * + +STOP = 'Stop' +WRAP = 'Wrap Around' +RATIO = 'Preserve Distance' +GRAV = 'Squash' + +ADDTOVIEW = 'Details Window...' + + +class DetailsViewer: + def __init__(self, switchboard, master=None): + self.__sb = switchboard + optiondb = switchboard.optiondb() + self.__red, self.__green, self.__blue = switchboard.current_rgb() + # GUI + root = self.__root = Toplevel(master, class_='Pynche') + root.protocol('WM_DELETE_WINDOW', self.withdraw) + root.title('Pynche Details Window') + root.iconname('Pynche Details Window') + root.bind('<Alt-q>', self.__quit) + root.bind('<Alt-Q>', self.__quit) + root.bind('<Alt-w>', self.withdraw) + root.bind('<Alt-W>', self.withdraw) + # accelerators + root.bind('<KeyPress-Left>', self.__minus1) + root.bind('<KeyPress-Right>', self.__plus1) + root.bind('<Control-KeyPress-Left>', self.__minus10) + root.bind('<Control-KeyPress-Right>', self.__plus10) + root.bind('<Shift-KeyPress-Left>', self.__minus25) + root.bind('<Shift-KeyPress-Right>', self.__plus25) + # + # color ties + frame = self.__frame = Frame(root) + frame.pack(expand=YES, fill=X) + self.__l1 = Label(frame, text='Move Sliders:') + self.__l1.grid(row=1, column=0, sticky=E) + self.__rvar = IntVar() + self.__rvar.set(optiondb.get('RSLIDER', 4)) + self.__radio1 = Checkbutton(frame, text='Red', + variable=self.__rvar, + command=self.__effect, + onvalue=4, offvalue=0) + self.__radio1.grid(row=1, column=1, sticky=W) + self.__gvar = IntVar() + self.__gvar.set(optiondb.get('GSLIDER', 2)) + self.__radio2 = Checkbutton(frame, text='Green', + variable=self.__gvar, + command=self.__effect, + onvalue=2, offvalue=0) + self.__radio2.grid(row=2, column=1, sticky=W) + self.__bvar = IntVar() + self.__bvar.set(optiondb.get('BSLIDER', 1)) + self.__radio3 = Checkbutton(frame, text='Blue', + variable=self.__bvar, + command=self.__effect, + onvalue=1, offvalue=0) + self.__radio3.grid(row=3, column=1, sticky=W) + self.__l2 = Label(frame) + self.__l2.grid(row=4, column=1, sticky=W) + self.__effect() + # + # Boundary behavior + self.__l3 = Label(frame, text='At boundary:') + self.__l3.grid(row=5, column=0, sticky=E) + self.__boundvar = StringVar() + self.__boundvar.set(optiondb.get('ATBOUND', STOP)) + self.__omenu = OptionMenu(frame, self.__boundvar, + STOP, WRAP, RATIO, GRAV) + self.__omenu.grid(row=5, column=1, sticky=W) + self.__omenu.configure(width=17) + # + # Buttons + frame = self.__btnframe = Frame(frame) + frame.grid(row=0, column=0, columnspan=2, sticky='EW') + self.__down25 = Button(frame, text='-25', + command=self.__minus25) + self.__down10 = Button(frame, text='-10', + command=self.__minus10) + self.__down1 = Button(frame, text='-1', + command=self.__minus1) + self.__up1 = Button(frame, text='+1', + command=self.__plus1) + self.__up10 = Button(frame, text='+10', + command=self.__plus10) + self.__up25 = Button(frame, text='+25', + command=self.__plus25) + self.__down25.pack(expand=YES, fill=X, side=LEFT) + self.__down10.pack(expand=YES, fill=X, side=LEFT) + self.__down1.pack(expand=YES, fill=X, side=LEFT) + self.__up1.pack(expand=YES, fill=X, side=LEFT) + self.__up10.pack(expand=YES, fill=X, side=LEFT) + self.__up25.pack(expand=YES, fill=X, side=LEFT) + + def __effect(self, event=None): + tie = self.__rvar.get() + self.__gvar.get() + self.__bvar.get() + if tie in (0, 1, 2, 4): + text = '' + else: + text = '(= %s Level)' % {3: 'Cyan', + 5: 'Magenta', + 6: 'Yellow', + 7: 'Grey'}[tie] + self.__l2.configure(text=text) + + def __quit(self, event=None): + self.__root.quit() + + def withdraw(self, event=None): + self.__root.withdraw() + + def deiconify(self, event=None): + self.__root.deiconify() + + def __minus25(self, event=None): + self.__delta(-25) + + def __minus10(self, event=None): + self.__delta(-10) + + def __minus1(self, event=None): + self.__delta(-1) + + def __plus1(self, event=None): + self.__delta(1) + + def __plus10(self, event=None): + self.__delta(10) + + def __plus25(self, event=None): + self.__delta(25) + + def __delta(self, delta): + tie = [] + if self.__rvar.get(): + red = self.__red + delta + tie.append(red) + else: + red = self.__red + if self.__gvar.get(): + green = self.__green + delta + tie.append(green) + else: + green = self.__green + if self.__bvar.get(): + blue = self.__blue + delta + tie.append(blue) + else: + blue = self.__blue + # now apply at boundary behavior + atbound = self.__boundvar.get() + if atbound == STOP: + if red < 0 or green < 0 or blue < 0 or \ + red > 255 or green > 255 or blue > 255: + # then + red, green, blue = self.__red, self.__green, self.__blue + elif atbound == WRAP or (atbound == RATIO and len(tie) < 2): + if red < 0: + red += 256 + if green < 0: + green += 256 + if blue < 0: + blue += 256 + if red > 255: + red -= 256 + if green > 255: + green -= 256 + if blue > 255: + blue -= 256 + elif atbound == RATIO: + # for when 2 or 3 colors are tied together + dir = 0 + for c in tie: + if c < 0: + dir = -1 + elif c > 255: + dir = 1 + if dir == -1: + delta = max(tie) + if self.__rvar.get(): + red = red + 255 - delta + if self.__gvar.get(): + green = green + 255 - delta + if self.__bvar.get(): + blue = blue + 255 - delta + elif dir == 1: + delta = min(tie) + if self.__rvar.get(): + red = red - delta + if self.__gvar.get(): + green = green - delta + if self.__bvar.get(): + blue = blue - delta + elif atbound == GRAV: + if red < 0: + red = 0 + if green < 0: + green = 0 + if blue < 0: + blue = 0 + if red > 255: + red = 255 + if green > 255: + green = 255 + if blue > 255: + blue = 255 + self.__sb.update_views(red, green, blue) + self.__root.update_idletasks() + + def update_yourself(self, red, green, blue): + self.__red = red + self.__green = green + self.__blue = blue + + def save_options(self, optiondb): + optiondb['RSLIDER'] = self.__rvar.get() + optiondb['GSLIDER'] = self.__gvar.get() + optiondb['BSLIDER'] = self.__bvar.get() + optiondb['ATBOUND'] = self.__boundvar.get() diff --git a/sys/src/cmd/python/Tools/pynche/ListViewer.py b/sys/src/cmd/python/Tools/pynche/ListViewer.py new file mode 100644 index 000000000..213cd08ba --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/ListViewer.py @@ -0,0 +1,175 @@ +"""ListViewer class. + +This class implements an input/output view on the color model. It lists every +unique color (e.g. unique r/g/b value) found in the color database. Each +color is shown by small swatch and primary color name. Some colors have +aliases -- more than one name for the same r/g/b value. These aliases are +displayed in the small listbox at the bottom of the screen. + +Clicking on a color name or swatch selects that color and updates all other +windows. When a color is selected in a different viewer, the color list is +scrolled to the selected color and it is highlighted. If the selected color +is an r/g/b value without a name, no scrolling occurs. + +You can turn off Update On Click if all you want to see is the alias for a +given name, without selecting the color. +""" + +from Tkinter import * +import ColorDB + +ADDTOVIEW = 'Color %List Window...' + +class ListViewer: + def __init__(self, switchboard, master=None): + self.__sb = switchboard + optiondb = switchboard.optiondb() + self.__lastbox = None + self.__dontcenter = 0 + # GUI + root = self.__root = Toplevel(master, class_='Pynche') + root.protocol('WM_DELETE_WINDOW', self.withdraw) + root.title('Pynche Color List') + root.iconname('Pynche Color List') + root.bind('<Alt-q>', self.__quit) + root.bind('<Alt-Q>', self.__quit) + root.bind('<Alt-w>', self.withdraw) + root.bind('<Alt-W>', self.withdraw) + # + # create the canvas which holds everything, and its scrollbar + # + frame = self.__frame = Frame(root) + frame.pack() + canvas = self.__canvas = Canvas(frame, width=160, height=300, + borderwidth=2, relief=SUNKEN) + self.__scrollbar = Scrollbar(frame) + self.__scrollbar.pack(fill=Y, side=RIGHT) + canvas.pack(fill=BOTH, expand=1) + canvas.configure(yscrollcommand=(self.__scrollbar, 'set')) + self.__scrollbar.configure(command=(canvas, 'yview')) + self.__populate() + # + # Update on click + self.__uoc = BooleanVar() + self.__uoc.set(optiondb.get('UPONCLICK', 1)) + self.__uocbtn = Checkbutton(root, + text='Update on Click', + variable=self.__uoc, + command=self.__toggleupdate) + self.__uocbtn.pack(expand=1, fill=BOTH) + # + # alias list + self.__alabel = Label(root, text='Aliases:') + self.__alabel.pack() + self.__aliases = Listbox(root, height=5, + selectmode=BROWSE) + self.__aliases.pack(expand=1, fill=BOTH) + + def __populate(self): + # + # create all the buttons + colordb = self.__sb.colordb() + canvas = self.__canvas + row = 0 + widest = 0 + bboxes = self.__bboxes = [] + for name in colordb.unique_names(): + exactcolor = ColorDB.triplet_to_rrggbb(colordb.find_byname(name)) + canvas.create_rectangle(5, row*20 + 5, + 20, row*20 + 20, + fill=exactcolor) + textid = canvas.create_text(25, row*20 + 13, + text=name, + anchor=W) + x1, y1, textend, y2 = canvas.bbox(textid) + boxid = canvas.create_rectangle(3, row*20+3, + textend+3, row*20 + 23, + outline='', + tags=(exactcolor, 'all')) + canvas.bind('<ButtonRelease>', self.__onrelease) + bboxes.append(boxid) + if textend+3 > widest: + widest = textend+3 + row += 1 + canvheight = (row-1)*20 + 25 + canvas.config(scrollregion=(0, 0, 150, canvheight)) + for box in bboxes: + x1, y1, x2, y2 = canvas.coords(box) + canvas.coords(box, x1, y1, widest, y2) + + def __onrelease(self, event=None): + canvas = self.__canvas + # find the current box + x = canvas.canvasx(event.x) + y = canvas.canvasy(event.y) + ids = canvas.find_overlapping(x, y, x, y) + for boxid in ids: + if boxid in self.__bboxes: + break + else: +## print 'No box found!' + return + tags = self.__canvas.gettags(boxid) + for t in tags: + if t[0] == '#': + break + else: +## print 'No color tag found!' + return + red, green, blue = ColorDB.rrggbb_to_triplet(t) + self.__dontcenter = 1 + if self.__uoc.get(): + self.__sb.update_views(red, green, blue) + else: + self.update_yourself(red, green, blue) + self.__red, self.__green, self.__blue = red, green, blue + + def __toggleupdate(self, event=None): + if self.__uoc.get(): + self.__sb.update_views(self.__red, self.__green, self.__blue) + + def __quit(self, event=None): + self.__root.quit() + + def withdraw(self, event=None): + self.__root.withdraw() + + def deiconify(self, event=None): + self.__root.deiconify() + + def update_yourself(self, red, green, blue): + canvas = self.__canvas + # turn off the last box + if self.__lastbox: + canvas.itemconfigure(self.__lastbox, outline='') + # turn on the current box + colortag = ColorDB.triplet_to_rrggbb((red, green, blue)) + canvas.itemconfigure(colortag, outline='black') + self.__lastbox = colortag + # fill the aliases + self.__aliases.delete(0, END) + try: + aliases = self.__sb.colordb().aliases_of(red, green, blue)[1:] + except ColorDB.BadColor: + self.__aliases.insert(END, '<no matching color>') + return + if not aliases: + self.__aliases.insert(END, '<no aliases>') + else: + for name in aliases: + self.__aliases.insert(END, name) + # maybe scroll the canvas so that the item is visible + if self.__dontcenter: + self.__dontcenter = 0 + else: + ig, ig, ig, y1 = canvas.coords(colortag) + ig, ig, ig, y2 = canvas.coords(self.__bboxes[-1]) + h = int(canvas['height']) * 0.5 + canvas.yview('moveto', (y1-h) / y2) + + def save_options(self, optiondb): + optiondb['UPONCLICK'] = self.__uoc.get() + + def colordb_changed(self, colordb): + self.__canvas.delete('all') + self.__populate() diff --git a/sys/src/cmd/python/Tools/pynche/Main.py b/sys/src/cmd/python/Tools/pynche/Main.py new file mode 100644 index 000000000..1fa3f175c --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/Main.py @@ -0,0 +1,229 @@ +"""Pynche -- The PYthon Natural Color and Hue Editor. + +Contact: %(AUTHNAME)s +Email: %(AUTHEMAIL)s +Version: %(__version__)s + +Pynche is based largely on a similar color editor I wrote years ago for the +SunView window system. That editor was called ICE: the Interactive Color +Editor. I'd always wanted to port the editor to X but didn't feel like +hacking X and C code to do it. Fast forward many years, to where Python + +Tkinter provides such a nice programming environment, with enough power, that +I finally buckled down and implemented it. I changed the name because these +days, too many other systems have the acronym `ICE'. + +This program currently requires Python 2.2 with Tkinter. + +Usage: %(PROGRAM)s [-d file] [-i file] [-X] [-v] [-h] [initialcolor] + +Where: + --database file + -d file + Alternate location of a color database file + + --initfile file + -i file + Alternate location of the initialization file. This file contains a + persistent database of the current Pynche options and color. This + means that Pynche restores its option settings and current color when + it restarts, using this file (unless the -X option is used). The + default is ~/.pynche + + --ignore + -X + Ignore the initialization file when starting up. Pynche will still + write the current option settings to this file when it quits. + + --version + -v + print the version number and exit + + --help + -h + print this message + + initialcolor + initial color, as a color name or #RRGGBB format +""" + +__version__ = '1.4.1' + +import sys +import os +import getopt +import ColorDB + +from PyncheWidget import PyncheWidget +from Switchboard import Switchboard +from StripViewer import StripViewer +from ChipViewer import ChipViewer +from TypeinViewer import TypeinViewer + + + +PROGRAM = sys.argv[0] +AUTHNAME = 'Barry Warsaw' +AUTHEMAIL = 'barry@python.org' + +# Default locations of rgb.txt or other textual color database +RGB_TXT = [ + # Solaris OpenWindows + '/usr/openwin/lib/rgb.txt', + # Linux + '/usr/lib/X11/rgb.txt', + # The X11R6.4 rgb.txt file + os.path.join(sys.path[0], 'X/rgb.txt'), + # add more here + ] + + + +# Do this because PyncheWidget.py wants to get at the interpolated docstring +# too, for its Help menu. +def docstring(): + return __doc__ % globals() + + +def usage(code, msg=''): + print docstring() + if msg: + print msg + sys.exit(code) + + + +def initial_color(s, colordb): + # function called on every color + def scan_color(s, colordb=colordb): + try: + r, g, b = colordb.find_byname(s) + except ColorDB.BadColor: + try: + r, g, b = ColorDB.rrggbb_to_triplet(s) + except ColorDB.BadColor: + return None, None, None + return r, g, b + # + # First try the passed in color + r, g, b = scan_color(s) + if r is None: + # try the same color with '#' prepended, since some shells require + # this to be escaped, which is a pain + r, g, b = scan_color('#' + s) + if r is None: + print 'Bad initial color, using gray50:', s + r, g, b = scan_color('gray50') + if r is None: + usage(1, 'Cannot find an initial color to use') + # does not return + return r, g, b + + + +def build(master=None, initialcolor=None, initfile=None, ignore=None, + dbfile=None): + # create all output widgets + s = Switchboard(not ignore and initfile) + # defer to the command line chosen color database, falling back to the one + # in the .pynche file. + if dbfile is None: + dbfile = s.optiondb().get('DBFILE') + # find a parseable color database + colordb = None + files = RGB_TXT[:] + if dbfile is None: + dbfile = files.pop() + while colordb is None: + try: + colordb = ColorDB.get_colordb(dbfile) + except (KeyError, IOError): + pass + if colordb is None: + if not files: + break + dbfile = files.pop(0) + if not colordb: + usage(1, 'No color database file found, see the -d option.') + s.set_colordb(colordb) + + # create the application window decorations + app = PyncheWidget(__version__, s, master=master) + w = app.window() + + # these built-in viewers live inside the main Pynche window + s.add_view(StripViewer(s, w)) + s.add_view(ChipViewer(s, w)) + s.add_view(TypeinViewer(s, w)) + + # get the initial color as components and set the color on all views. if + # there was no initial color given on the command line, use the one that's + # stored in the option database + if initialcolor is None: + optiondb = s.optiondb() + red = optiondb.get('RED') + green = optiondb.get('GREEN') + blue = optiondb.get('BLUE') + # but if there wasn't any stored in the database, use grey50 + if red is None or blue is None or green is None: + red, green, blue = initial_color('grey50', colordb) + else: + red, green, blue = initial_color(initialcolor, colordb) + s.update_views(red, green, blue) + return app, s + + +def run(app, s): + try: + app.start() + except KeyboardInterrupt: + pass + + + +def main(): + try: + opts, args = getopt.getopt( + sys.argv[1:], + 'hd:i:Xv', + ['database=', 'initfile=', 'ignore', 'help', 'version']) + except getopt.error, msg: + usage(1, msg) + + if len(args) == 0: + initialcolor = None + elif len(args) == 1: + initialcolor = args[0] + else: + usage(1) + + ignore = False + dbfile = None + initfile = os.path.expanduser('~/.pynche') + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-v', '--version'): + print """\ +Pynche -- The PYthon Natural Color and Hue Editor. +Contact: %(AUTHNAME)s +Email: %(AUTHEMAIL)s +Version: %(__version__)s""" % globals() + sys.exit(0) + elif opt in ('-d', '--database'): + dbfile = arg + elif opt in ('-X', '--ignore'): + ignore = True + elif opt in ('-i', '--initfile'): + initfile = arg + + app, sb = build(initialcolor=initialcolor, + initfile=initfile, + ignore=ignore, + dbfile=dbfile) + run(app, sb) + sb.save_views() + + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/pynche/PyncheWidget.py b/sys/src/cmd/python/Tools/pynche/PyncheWidget.py new file mode 100644 index 000000000..fcfe7ce6c --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/PyncheWidget.py @@ -0,0 +1,309 @@ +"""Main Pynche (Pythonically Natural Color and Hue Editor) widget. + +This window provides the basic decorations, primarily including the menubar. +It is used to bring up other windows. +""" + +import sys +import os +from Tkinter import * +import tkMessageBox +import tkFileDialog +import ColorDB + +# Milliseconds between interrupt checks +KEEPALIVE_TIMER = 500 + + + +class PyncheWidget: + def __init__(self, version, switchboard, master=None, extrapath=[]): + self.__sb = switchboard + self.__version = version + self.__textwin = None + self.__listwin = None + self.__detailswin = None + self.__helpwin = None + self.__dialogstate = {} + modal = self.__modal = not not master + # If a master was given, we are running as a modal dialog servant to + # some other application. We rearrange our UI in this case (there's + # no File menu and we get `Okay' and `Cancel' buttons), and we do a + # grab_set() to make ourselves modal + if modal: + self.__tkroot = tkroot = Toplevel(master, class_='Pynche') + tkroot.grab_set() + tkroot.withdraw() + else: + # Is there already a default root for Tk, say because we're + # running under Guido's IDE? :-) Two conditions say no, either the + # import fails or _default_root is None. + tkroot = None + try: + from Tkinter import _default_root + tkroot = self.__tkroot = _default_root + except ImportError: + pass + if not tkroot: + tkroot = self.__tkroot = Tk(className='Pynche') + # but this isn't our top level widget, so make it invisible + tkroot.withdraw() + # create the menubar + menubar = self.__menubar = Menu(tkroot) + # + # File menu + # + filemenu = self.__filemenu = Menu(menubar, tearoff=0) + filemenu.add_command(label='Load palette...', + command=self.__load, + underline=0) + if not modal: + filemenu.add_command(label='Quit', + command=self.__quit, + accelerator='Alt-Q', + underline=0) + # + # View menu + # + views = make_view_popups(self.__sb, self.__tkroot, extrapath) + viewmenu = Menu(menubar, tearoff=0) + for v in views: + viewmenu.add_command(label=v.menutext(), + command=v.popup, + underline=v.underline()) + # + # Help menu + # + helpmenu = Menu(menubar, name='help', tearoff=0) + helpmenu.add_command(label='About Pynche...', + command=self.__popup_about, + underline=0) + helpmenu.add_command(label='Help...', + command=self.__popup_usage, + underline=0) + # + # Tie them all together + # + menubar.add_cascade(label='File', + menu=filemenu, + underline=0) + menubar.add_cascade(label='View', + menu=viewmenu, + underline=0) + menubar.add_cascade(label='Help', + menu=helpmenu, + underline=0) + + # now create the top level window + root = self.__root = Toplevel(tkroot, class_='Pynche', menu=menubar) + root.protocol('WM_DELETE_WINDOW', + modal and self.__bell or self.__quit) + root.title('Pynche %s' % version) + root.iconname('Pynche') + # Only bind accelerators for the File->Quit menu item if running as a + # standalone app + if not modal: + root.bind('<Alt-q>', self.__quit) + root.bind('<Alt-Q>', self.__quit) + else: + # We're a modal dialog so we have a new row of buttons + bframe = Frame(root, borderwidth=1, relief=RAISED) + bframe.grid(row=4, column=0, columnspan=2, + sticky='EW', + ipady=5) + okay = Button(bframe, + text='Okay', + command=self.__okay) + okay.pack(side=LEFT, expand=1) + cancel = Button(bframe, + text='Cancel', + command=self.__cancel) + cancel.pack(side=LEFT, expand=1) + + def __quit(self, event=None): + self.__tkroot.quit() + + def __bell(self, event=None): + self.__tkroot.bell() + + def __okay(self, event=None): + self.__sb.withdraw_views() + self.__tkroot.grab_release() + self.__quit() + + def __cancel(self, event=None): + self.__sb.canceled() + self.__okay() + + def __keepalive(self): + # Exercise the Python interpreter regularly so keyboard interrupts get + # through. + self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive) + + def start(self): + if not self.__modal: + self.__keepalive() + self.__tkroot.mainloop() + + def window(self): + return self.__root + + def __popup_about(self, event=None): + from Main import __version__ + tkMessageBox.showinfo('About Pynche ' + __version__, + '''\ +Pynche %s +The PYthonically Natural +Color and Hue Editor + +For information +contact: Barry A. Warsaw +email: bwarsaw@python.org''' % __version__) + + def __popup_usage(self, event=None): + if not self.__helpwin: + self.__helpwin = Helpwin(self.__root, self.__quit) + self.__helpwin.deiconify() + + def __load(self, event=None): + while 1: + idir, ifile = os.path.split(self.__sb.colordb().filename()) + file = tkFileDialog.askopenfilename( + filetypes=[('Text files', '*.txt'), + ('All files', '*'), + ], + initialdir=idir, + initialfile=ifile) + if not file: + # cancel button + return + try: + colordb = ColorDB.get_colordb(file) + except IOError: + tkMessageBox.showerror('Read error', '''\ +Could not open file for reading: +%s''' % file) + continue + if colordb is None: + tkMessageBox.showerror('Unrecognized color file type', '''\ +Unrecognized color file type in file: +%s''' % file) + continue + break + self.__sb.set_colordb(colordb) + + def withdraw(self): + self.__root.withdraw() + + def deiconify(self): + self.__root.deiconify() + + + +class Helpwin: + def __init__(self, master, quitfunc): + from Main import docstring + self.__root = root = Toplevel(master, class_='Pynche') + root.protocol('WM_DELETE_WINDOW', self.__withdraw) + root.title('Pynche Help Window') + root.iconname('Pynche Help Window') + root.bind('<Alt-q>', quitfunc) + root.bind('<Alt-Q>', quitfunc) + root.bind('<Alt-w>', self.__withdraw) + root.bind('<Alt-W>', self.__withdraw) + + # more elaborate help is available in the README file + readmefile = os.path.join(sys.path[0], 'README') + try: + fp = None + try: + fp = open(readmefile) + contents = fp.read() + # wax the last page, it contains Emacs cruft + i = contents.rfind('\f') + if i > 0: + contents = contents[:i].rstrip() + finally: + if fp: + fp.close() + except IOError: + sys.stderr.write("Couldn't open Pynche's README, " + 'using docstring instead.\n') + contents = docstring() + + self.__text = text = Text(root, relief=SUNKEN, + width=80, height=24) + self.__text.focus_set() + text.insert(0.0, contents) + scrollbar = Scrollbar(root) + scrollbar.pack(fill=Y, side=RIGHT) + text.pack(fill=BOTH, expand=YES) + text.configure(yscrollcommand=(scrollbar, 'set')) + scrollbar.configure(command=(text, 'yview')) + + def __withdraw(self, event=None): + self.__root.withdraw() + + def deiconify(self): + self.__root.deiconify() + + + +class PopupViewer: + def __init__(self, module, name, switchboard, root): + self.__m = module + self.__name = name + self.__sb = switchboard + self.__root = root + self.__menutext = module.ADDTOVIEW + # find the underline character + underline = module.ADDTOVIEW.find('%') + if underline == -1: + underline = 0 + else: + self.__menutext = module.ADDTOVIEW.replace('%', '', 1) + self.__underline = underline + self.__window = None + + def menutext(self): + return self.__menutext + + def underline(self): + return self.__underline + + def popup(self, event=None): + if not self.__window: + # class and module must have the same name + class_ = getattr(self.__m, self.__name) + self.__window = class_(self.__sb, self.__root) + self.__sb.add_view(self.__window) + self.__window.deiconify() + + def __cmp__(self, other): + return cmp(self.__menutext, other.__menutext) + + +def make_view_popups(switchboard, root, extrapath): + viewers = [] + # where we are in the file system + dirs = [os.path.dirname(__file__)] + extrapath + for dir in dirs: + if dir == '': + dir = '.' + for file in os.listdir(dir): + if file[-9:] == 'Viewer.py': + name = file[:-3] + try: + module = __import__(name) + except ImportError: + # Pynche is running from inside a package, so get the + # module using the explicit path. + pkg = __import__('pynche.'+name) + module = getattr(pkg, name) + if hasattr(module, 'ADDTOVIEW') and module.ADDTOVIEW: + # this is an external viewer + v = PopupViewer(module, name, switchboard, root) + viewers.append(v) + # sort alphabetically + viewers.sort() + return viewers diff --git a/sys/src/cmd/python/Tools/pynche/README b/sys/src/cmd/python/Tools/pynche/README new file mode 100644 index 000000000..d20efc316 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/README @@ -0,0 +1,398 @@ +Pynche - The PYthonically Natural Color and Hue Editor + +Contact: Barry A. Warsaw +Email: bwarsaw@python.org +Version: 1.3 + +Introduction + + Pynche is a color editor based largely on a similar program that I + originally wrote back in 1987 for the Sunview window system. That + editor was called ICE, the Interactive Color Editor. I'd always + wanted to port this program to X but didn't feel like hacking X + and C code to do it. Fast forward many years, to where Python + + Tkinter provides such a nice programming environment, with enough + power, that I finally buckled down and re-implemented it. I + changed the name because these days, too many other systems have + the acronym `ICE'. + + Pynche should work with any variant of Python after 1.5.2 + (e.g. 2.0.1 and 2.1.1), using Tk 8.0.x. It's been tested on + Solaris 2.6, Windows NT 4, and various Linux distros. You'll want + to be sure to have at least Tk 8.0.3 for Windows. Also, Pynche is + very colormap intensive, so it doesn't work very well on 8-bit + graphics cards; 24bit+ graphics cards are so cheap these days, + I'll probably never "fix" that. + + Pynche must find a text database of colors names in order to + provide `nearest' color matching. Pynche is distributed with an + rgb.txt file from the X11R6.4 distribution for this reason, along + with other "Web related" database (see below). You can use a + different file with the -d option. The file xlicense.txt contains + the license only for rgb.txt and both files are in the X/ + subdirectory. + + Pynche is pronounced: Pin'-chee + + +Running Standalone + + On Unix, start it by running the `pynche' script. On Windows, run + pynche.pyw to inhibit the console window. When run from the + command line, the following options are recognized: + + --database file + -d file + Alternate location of the color database file. Without this + option, the first valid file found will be used (see below). + + --initfile file + -i file + Alternate location of the persistent initialization file. See + the section on Persistency below. + + --ignore + -X + Ignore the persistent initialization file when starting up. + Pynche will still write the current option settings to the + persistent init file when it quits. + + --help + -h + Print the help message. + + initialcolor + a Tk color name or #rrggbb color spec to be used as the + initially selected color. This overrides any color saved in + the persistent init file. Since `#' needs to be escaped in + many shells, it is optional in the spec (e.g. #45dd1f is the + same as 45dd1f). + + +Running as a Modal Dialog + + Pynche can be run as a modal dialog, inside another application, + say as a general color chooser. In fact, Grail 0.6 uses Pynche + and a future version of IDLE may as well. Pynche supports the API + implemented by the Tkinter standard tkColorChooser module, with a + few changes as described below. By importing pyColorChooser from + the Pynche package, you can run + + pyColorChooser.askcolor() + + which will popup Pynche as a modal dialog, and return the selected + color. + + There are some UI differences when running as a modal + vs. standalone. When running as a modal, there is no "Quit" menu + item under the "File" menu. Instead there are "Okay" and "Cancel" + buttons. + + When "Okay" is hit, askcolor() returns the tuple + + ((r, g, b), "name") + + where r, g, and b are red, green, and blue color values + respectively (in the range 0 to 255). "name" will be a color name + from the color database if there is an exact match, otherwise it + will be an X11 color spec of the form "#rrggbb". Note that this + is different than tkColorChooser, which doesn't know anything + about color names. + + askcolor() supports the following optional keyword arguments: + + color + the color to set as the initial selected color + + master[*] + the master window to use as the parent of the modal + dialog. Without this argument, pyColorChooser will create + its own Tkinter.Tk instance as the master. This may not + be what you want. + + databasefile + similar to the --database option, the value must be a + file name + + initfile[*] + similar to the --initfile option, the value must be a + file name + + ignore[*] + similar to the --ignore flag, the value is a boolean + + wantspec + When this is true, the "name" field in the return tuple + will always be a color spec of the form "#rrggbb". It + will not return a color name even if there is a match; + this is so pyColorChooser can exactly match the API of + tkColorChooser. + + [*] these arguments must be specified the first time + askcolor() is used and cannot be changed on subsequent calls. + + +The Colorstrip Window + + The top part of the main Pynche window contains the "variation + strips". Each strip contains a number of "color chips". The + strips always indicate the currently selected color by a highlight + rectangle around the selected color chip, with an arrow pointing + to the chip. Each arrow has an associated number giving you the + color value along the variation's axis. Each variation strip + shows you the colors that are reachable from the selected color by + varying just one axis of the color solid. + + For example, when the selected color is (in Red/Green/Blue + notation) 127/127/127, the Red Variations strip shows you every + color in the range 0/127/127 to 255/127/127. Similarly for the + green and blue axes. You can select any color by clicking on its + chip. This will update the highlight rectangle and the arrow, as + well as other displays in Pynche. + + Click on "Update while dragging" if you want Pynche to update the + selected color while you drag along any variation strip (this will + be a bit slower). Click on "Hexadecimal" to display the arrow + numbers in hex. + + There are also two shortcut buttons in this window, which + auto-select Black (0/0/0) and White (255/255/255). + + +The Proof Window + + In the lower left corner of the main window you see two larger + color chips. The Selected chip shows you a larger version of the + color selected in the variation strips, along with its X11 color + specification. The Nearest chip shows you the closest color in + the X11 database to the selected color, giving its X11 color + specification, and below that, its X11 color name. When the + Selected chip color exactly matches the Nearest chip color, you + will see the color name appear below the color specification for + the Selected chip. + + Clicking on the Nearest color chip selects that color. Color + distance is calculated in the 3D space of the RGB color solid and + if more than one color name is the same distance from the selected + color, the first one found will be chosen. + + Note that there may be more than one X11 color name for the same + RGB value. In that case, the first one found in the text database + is designated the "primary" name, and this is shown under the + Nearest chip. The other names are "aliases" and they are visible + in the Color List Window (see below). + + Both the color specifications and color names are selectable for + copying and pasting into another window. + + +The Type-in Window + + At the lower right of the main window are three entry fields. + Here you can type numeric values for any of the three color axes. + Legal values are between 0 and 255, and these fields do not allow + you to enter illegal values. You must hit Enter or Tab to select + the new color. + + Click on "Update while typing" if you want Pynche to select the + color on every keystroke (well, every one that produces a legal + value!) Click on "Hexadecimal" to display and enter color values + in hex. + + +Other Views + + There are three secondary windows which are not displayed by + default. You can bring these up via the "View" menu on the main + Pynche window. + + +The Text Window + + The "Text Window" allows you to see what effects various colors + have on the standard Tk text widget elements. In the upper part + of the window is a plain Tk text widget and here you can edit the + text, select a region of text, etc. Below this is a button "Track + color changes". When this is turned on, any colors selected in + the other windows will change the text widget element specified in + the radio buttons below. When this is turned off, text widget + elements are not affected by color selection. + + You can choose which element gets changed by color selection by + clicking on one of the radio buttons in the bottom part of this + window. Text foreground and background affect the text in the + upper part of the window. Selection foreground and background + affect the colors of the primary selection which is what you see + when you click the middle button (depending on window system) and + drag it through some text. + + The Insertion is the insertion cursor in the text window, where + new text will be inserted as you type. The insertion cursor only + has a background. + + +The Color List Window + + The "Color List" window shows every named color in the color name + database (this window may take a while to come up). In the upper + part of the window you see a scrolling list of all the color names + in the database, in alphabetical order. Click on any color to + select it. In the bottom part of the window is displayed any + aliases for the selected color (those color names that have the + same RGB value, but were found later in the text database). For + example, find the color "Black" and you'll see that its aliases + are "gray0" and "grey0". + + If the color has no aliases you'll see "<no aliases>" here. If you + just want to see if a color has an alias, and do not want to select a + color when you click on it, turn off "Update on Click". + + Note that the color list is always updated when a color is selected + from the main window. There's no way to turn this feature off. If + the selected color has no matching color name you'll see + "<no matching color>" in the Aliases window. + + +The Details Window + + The "Details" window gives you more control over color selection + than just clicking on a color chip in the main window. The row of + buttons along the top apply the specified increment and decrement + amounts to the selected color. These delta amounts are applied to + the variation strips specified by the check boxes labeled "Move + Sliders". Thus if just Red and Green are selected, hitting -10 + will subtract 10 from the color value along the red and green + variation only. Note the message under the checkboxes; this + indicates the primary color level being changed when more than one + slider is tied together. For example, if Red and Green are + selected, you will be changing the Yellow level of the selected + color. + + The "At Boundary" behavior determines what happens when any color + variation hits either the lower or upper boundaries (0 or 255) as + a result of clicking on the top row buttons: + + Stop + When the increment or decrement would send any of the tied + variations out of bounds, the entire delta is discarded. + + Wrap Around + When the increment or decrement would send any of the tied + variations out of bounds, the out of bounds value is wrapped + around to the other side. Thus if red were at 238 and +25 + were clicked, red would have the value 7. + + Preserve Distance + When the increment or decrement would send any of the tied + variations out of bounds, all tied variations are wrapped as + one, so as to preserve the distance between them. Thus if + green and blue were tied, and green was at 238 while blue was + at 223, and +25 were clicked, green would be at 15 and blue + would be at 0. + + Squash + When the increment or decrement would send any of the tied + variations out of bounds, the out of bounds variation is set + to the ceiling of 255 or floor of 0, as appropriate. In this + way, all tied variations are squashed to one edge or the + other. + + The top row buttons have the following keyboard accelerators: + + -25 == Shift Left Arrow + -10 == Control Left Arrow + -1 == Left Arrow + +1 == Right Arrow + +10 == Control Right Arrow + +25 == Shift Right Arrow + + +Keyboard Accelerators + + Alt-w in any secondary window dismisses the window. In the main + window it exits Pynche (except when running as a modal). + + Alt-q in any window exits Pynche (except when running as a modal). + + +Persistency + + Pynche remembers various settings of options and colors between + invocations, storing these values in a `persistent initialization + file'. The actual location of this file is specified by the + --initfile option (see above), and defaults to ~/.pynche. + + When Pynche exits, it saves these values in the init file, and + re-reads them when it starts up. There is no locking on this + file, so if you run multiple instances of Pynche at a time, you + may clobber the init file. + + The actual options stored include + + - the currently selected color + + - all settings of checkbox and radio button options in all windows + + - the contents of the text window, the current text selection and + insertion point, and all current text widget element color + settings. + + - the name of the color database file (but not its contents) + + You can inhibit Pynche from reading the init file by supplying the + --ignore option on the command line. However, you cannot suppress + the storing of the settings in the init file on Pynche exit. If + you really want to do this, use /dev/null as the init file, using + --initfile. + + +Color Name Database Files + + Pynche uses a color name database file to calculate the nearest + color to the selected color, and to display in the Color List + view. Several files are distributed with Pynche, described + below. By default, the X11 color name database file is selected. + Other files: + + html40colors.txt -- the HTML 4.0 guaranteed color names + + websafe.txt -- the 216 "Web-safe" colors that Netscape and MSIE + guarantee will not be dithered. These are specified in #rrggbb + format for both values and names + + webcolors.txt -- The 140 color names that Tim Peters and his + sister say NS and MSIE both understand (with some controversy over + AliceBlue). + + namedcolors.txt -- an alternative set of Netscape colors. + + You can switch between files by choosing "Load palette..." from + the "File" menu. This brings up a standard Tk file dialog. + Choose the file you want and then click "Ok". If Pynche + understands the format in this file, it will load the database and + update the appropriate windows. If not, it will bring up an error + dialog. + + +To Do + + Here's a brief list of things I want to do (some mythical day): + + - Better support for resizing the top level windows + + - More output views, e.g. color solids + + - Have the notion of a `last color selected'; this may require a + new output view + + - Support setting the font in the text view + + - Support distutils setup.py for installation + + I'm open to suggestions! + + + +Local Variables: +indent-tabs-mode: nil +End: diff --git a/sys/src/cmd/python/Tools/pynche/StripViewer.py b/sys/src/cmd/python/Tools/pynche/StripViewer.py new file mode 100644 index 000000000..01bcbf6d0 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/StripViewer.py @@ -0,0 +1,433 @@ +"""Strip viewer and related widgets. + +The classes in this file implement the StripViewer shown in the top two thirds +of the main Pynche window. It consists of three StripWidgets which display +the variations in red, green, and blue respectively of the currently selected +r/g/b color value. + +Each StripWidget shows the color variations that are reachable by varying an +axis of the currently selected color. So for example, if the color is + + (R,G,B)=(127,163,196) + +then the Red variations show colors from (0,163,196) to (255,163,196), the +Green variations show colors from (127,0,196) to (127,255,196), and the Blue +variations show colors from (127,163,0) to (127,163,255). + +The selected color is always visible in all three StripWidgets, and in fact +each StripWidget highlights the selected color, and has an arrow pointing to +the selected chip, which includes the value along that particular axis. + +Clicking on any chip in any StripWidget selects that color, and updates all +arrows and other windows. By toggling on Update while dragging, Pynche will +select the color under the cursor while you drag it, but be forewarned that +this can be slow. +""" + +from Tkinter import * +import ColorDB + +# Load this script into the Tcl interpreter and call it in +# StripWidget.set_color(). This is about as fast as it can be with the +# current _tkinter.c interface, which doesn't support Tcl Objects. +TCLPROC = '''\ +proc setcolor {canv colors} { + set i 1 + foreach c $colors { + $canv itemconfigure $i -fill $c -outline $c + incr i + } +} +''' + +# Tcl event types +BTNDOWN = 4 +BTNUP = 5 +BTNDRAG = 6 + +SPACE = ' ' + + + +def constant(numchips): + step = 255.0 / (numchips - 1) + start = 0.0 + seq = [] + while numchips > 0: + seq.append(int(start)) + start = start + step + numchips = numchips - 1 + return seq + +# red variations, green+blue = cyan constant +def constant_red_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, [red] * numchips, seq, seq) + +# green variations, red+blue = magenta constant +def constant_green_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, seq, [green] * numchips, seq) + +# blue variations, red+green = yellow constant +def constant_blue_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, seq, seq, [blue] * numchips) + +# red variations, green+blue = cyan constant +def constant_cyan_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, seq, [green] * numchips, [blue] * numchips) + +# green variations, red+blue = magenta constant +def constant_magenta_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, [red] * numchips, seq, [blue] * numchips) + +# blue variations, red+green = yellow constant +def constant_yellow_generator(numchips, red, green, blue): + seq = constant(numchips) + return map(None, [red] * numchips, [green] * numchips, seq) + + + +class LeftArrow: + _ARROWWIDTH = 30 + _ARROWHEIGHT = 15 + _YOFFSET = 13 + _TEXTYOFFSET = 1 + _TAG = ('leftarrow',) + + def __init__(self, canvas, x): + self._canvas = canvas + self.__arrow, self.__text = self._create(x) + self.move_to(x) + + def _create(self, x): + arrow = self._canvas.create_line( + x, self._ARROWHEIGHT + self._YOFFSET, + x, self._YOFFSET, + x + self._ARROWWIDTH, self._YOFFSET, + arrow='first', + width=3.0, + tags=self._TAG) + text = self._canvas.create_text( + x + self._ARROWWIDTH + 13, + self._ARROWHEIGHT - self._TEXTYOFFSET, + tags=self._TAG, + text='128') + return arrow, text + + def _x(self): + coords = self._canvas.coords(self._TAG) + assert coords + return coords[0] + + def move_to(self, x): + deltax = x - self._x() + self._canvas.move(self._TAG, deltax, 0) + + def set_text(self, text): + self._canvas.itemconfigure(self.__text, text=text) + + +class RightArrow(LeftArrow): + _TAG = ('rightarrow',) + + def _create(self, x): + arrow = self._canvas.create_line( + x, self._YOFFSET, + x + self._ARROWWIDTH, self._YOFFSET, + x + self._ARROWWIDTH, self._ARROWHEIGHT + self._YOFFSET, + arrow='last', + width=3.0, + tags=self._TAG) + text = self._canvas.create_text( + x - self._ARROWWIDTH + 15, # BAW: kludge + self._ARROWHEIGHT - self._TEXTYOFFSET, + justify=RIGHT, + text='128', + tags=self._TAG) + return arrow, text + + def _x(self): + coords = self._canvas.coords(self._TAG) + assert coords + return coords[0] + self._ARROWWIDTH + + + +class StripWidget: + _CHIPHEIGHT = 50 + _CHIPWIDTH = 10 + _NUMCHIPS = 40 + + def __init__(self, switchboard, + master = None, + chipwidth = _CHIPWIDTH, + chipheight = _CHIPHEIGHT, + numchips = _NUMCHIPS, + generator = None, + axis = None, + label = '', + uwdvar = None, + hexvar = None): + # instance variables + self.__generator = generator + self.__axis = axis + self.__numchips = numchips + assert self.__axis in (0, 1, 2) + self.__uwd = uwdvar + self.__hexp = hexvar + # the last chip selected + self.__lastchip = None + self.__sb = switchboard + + canvaswidth = numchips * (chipwidth + 1) + canvasheight = chipheight + 43 # BAW: Kludge + + # create the canvas and pack it + canvas = self.__canvas = Canvas(master, + width=canvaswidth, + height=canvasheight, +## borderwidth=2, +## relief=GROOVE + ) + + canvas.pack() + canvas.bind('<ButtonPress-1>', self.__select_chip) + canvas.bind('<ButtonRelease-1>', self.__select_chip) + canvas.bind('<B1-Motion>', self.__select_chip) + + # Load a proc into the Tcl interpreter. This is used in the + # set_color() method to speed up setting the chip colors. + canvas.tk.eval(TCLPROC) + + # create the color strip + chips = self.__chips = [] + x = 1 + y = 30 + tags = ('chip',) + for c in range(self.__numchips): + color = 'grey' + canvas.create_rectangle( + x, y, x+chipwidth, y+chipheight, + fill=color, outline=color, + tags=tags) + x = x + chipwidth + 1 # for outline + chips.append(color) + + # create the strip label + self.__label = canvas.create_text( + 3, y + chipheight + 8, + text=label, + anchor=W) + + # create the arrow and text item + chipx = self.__arrow_x(0) + self.__leftarrow = LeftArrow(canvas, chipx) + + chipx = self.__arrow_x(len(chips) - 1) + self.__rightarrow = RightArrow(canvas, chipx) + + def __arrow_x(self, chipnum): + coords = self.__canvas.coords(chipnum+1) + assert coords + x0, y0, x1, y1 = coords + return (x1 + x0) / 2.0 + + # Invoked when one of the chips is clicked. This should just tell the + # switchboard to set the color on all the output components + def __select_chip(self, event=None): + x = event.x + y = event.y + canvas = self.__canvas + chip = canvas.find_overlapping(x, y, x, y) + if chip and (1 <= chip[0] <= self.__numchips): + color = self.__chips[chip[0]-1] + red, green, blue = ColorDB.rrggbb_to_triplet(color) + etype = int(event.type) + if (etype == BTNUP or self.__uwd.get()): + # update everyone + self.__sb.update_views(red, green, blue) + else: + # just track the arrows + self.__trackarrow(chip[0], (red, green, blue)) + + def __trackarrow(self, chip, rgbtuple): + # invert the last chip + if self.__lastchip is not None: + color = self.__canvas.itemcget(self.__lastchip, 'fill') + self.__canvas.itemconfigure(self.__lastchip, outline=color) + self.__lastchip = chip + # get the arrow's text + coloraxis = rgbtuple[self.__axis] + if self.__hexp.get(): + # hex + text = hex(coloraxis) + else: + # decimal + text = repr(coloraxis) + # move the arrow, and set its text + if coloraxis <= 128: + # use the left arrow + self.__leftarrow.set_text(text) + self.__leftarrow.move_to(self.__arrow_x(chip-1)) + self.__rightarrow.move_to(-100) + else: + # use the right arrow + self.__rightarrow.set_text(text) + self.__rightarrow.move_to(self.__arrow_x(chip-1)) + self.__leftarrow.move_to(-100) + # and set the chip's outline + brightness = ColorDB.triplet_to_brightness(rgbtuple) + if brightness <= 128: + outline = 'white' + else: + outline = 'black' + self.__canvas.itemconfigure(chip, outline=outline) + + + def update_yourself(self, red, green, blue): + assert self.__generator + i = 1 + chip = 0 + chips = self.__chips = [] + tk = self.__canvas.tk + # get the red, green, and blue components for all chips + for t in self.__generator(self.__numchips, red, green, blue): + rrggbb = ColorDB.triplet_to_rrggbb(t) + chips.append(rrggbb) + tred, tgreen, tblue = t + if tred <= red and tgreen <= green and tblue <= blue: + chip = i + i = i + 1 + # call the raw tcl script + colors = SPACE.join(chips) + tk.eval('setcolor %s {%s}' % (self.__canvas._w, colors)) + # move the arrows around + self.__trackarrow(chip, (red, green, blue)) + + def set(self, label, generator): + self.__canvas.itemconfigure(self.__label, text=label) + self.__generator = generator + + +class StripViewer: + def __init__(self, switchboard, master=None): + self.__sb = switchboard + optiondb = switchboard.optiondb() + # create a frame inside the master. + frame = Frame(master, relief=RAISED, borderwidth=1) + frame.grid(row=1, column=0, columnspan=2, sticky='NSEW') + # create the options to be used later + uwd = self.__uwdvar = BooleanVar() + uwd.set(optiondb.get('UPWHILEDRAG', 0)) + hexp = self.__hexpvar = BooleanVar() + hexp.set(optiondb.get('HEXSTRIP', 0)) + # create the red, green, blue strips inside their own frame + frame1 = Frame(frame) + frame1.pack(expand=YES, fill=BOTH) + self.__reds = StripWidget(switchboard, frame1, + generator=constant_cyan_generator, + axis=0, + label='Red Variations', + uwdvar=uwd, hexvar=hexp) + + self.__greens = StripWidget(switchboard, frame1, + generator=constant_magenta_generator, + axis=1, + label='Green Variations', + uwdvar=uwd, hexvar=hexp) + + self.__blues = StripWidget(switchboard, frame1, + generator=constant_yellow_generator, + axis=2, + label='Blue Variations', + uwdvar=uwd, hexvar=hexp) + + # create a frame to contain the controls + frame2 = Frame(frame) + frame2.pack(expand=YES, fill=BOTH) + frame2.columnconfigure(0, weight=20) + frame2.columnconfigure(2, weight=20) + + padx = 8 + + # create the black button + blackbtn = Button(frame2, + text='Black', + command=self.__toblack) + blackbtn.grid(row=0, column=0, rowspan=2, sticky=W, padx=padx) + + # create the controls + uwdbtn = Checkbutton(frame2, + text='Update while dragging', + variable=uwd) + uwdbtn.grid(row=0, column=1, sticky=W) + hexbtn = Checkbutton(frame2, + text='Hexadecimal', + variable=hexp, + command=self.__togglehex) + hexbtn.grid(row=1, column=1, sticky=W) + + # XXX: ignore this feature for now; it doesn't work quite right yet + +## gentypevar = self.__gentypevar = IntVar() +## self.__variations = Radiobutton(frame, +## text='Variations', +## variable=gentypevar, +## value=0, +## command=self.__togglegentype) +## self.__variations.grid(row=0, column=1, sticky=W) +## self.__constants = Radiobutton(frame, +## text='Constants', +## variable=gentypevar, +## value=1, +## command=self.__togglegentype) +## self.__constants.grid(row=1, column=1, sticky=W) + + # create the white button + whitebtn = Button(frame2, + text='White', + command=self.__towhite) + whitebtn.grid(row=0, column=2, rowspan=2, sticky=E, padx=padx) + + def update_yourself(self, red, green, blue): + self.__reds.update_yourself(red, green, blue) + self.__greens.update_yourself(red, green, blue) + self.__blues.update_yourself(red, green, blue) + + def __togglehex(self, event=None): + red, green, blue = self.__sb.current_rgb() + self.update_yourself(red, green, blue) + +## def __togglegentype(self, event=None): +## which = self.__gentypevar.get() +## if which == 0: +## self.__reds.set(label='Red Variations', +## generator=constant_cyan_generator) +## self.__greens.set(label='Green Variations', +## generator=constant_magenta_generator) +## self.__blues.set(label='Blue Variations', +## generator=constant_yellow_generator) +## elif which == 1: +## self.__reds.set(label='Red Constant', +## generator=constant_red_generator) +## self.__greens.set(label='Green Constant', +## generator=constant_green_generator) +## self.__blues.set(label='Blue Constant', +## generator=constant_blue_generator) +## else: +## assert 0 +## self.__sb.update_views_current() + + def __toblack(self, event=None): + self.__sb.update_views(0, 0, 0) + + def __towhite(self, event=None): + self.__sb.update_views(255, 255, 255) + + def save_options(self, optiondb): + optiondb['UPWHILEDRAG'] = self.__uwdvar.get() + optiondb['HEXSTRIP'] = self.__hexpvar.get() diff --git a/sys/src/cmd/python/Tools/pynche/Switchboard.py b/sys/src/cmd/python/Tools/pynche/Switchboard.py new file mode 100644 index 000000000..ee83d4766 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/Switchboard.py @@ -0,0 +1,139 @@ +"""Switchboard class. + +This class is used to coordinate updates among all Viewers. Every Viewer must +conform to the following interface: + + - it must include a method called update_yourself() which takes three + arguments; the red, green, and blue values of the selected color. + + - When a Viewer selects a color and wishes to update all other Views, it + should call update_views() on the Switchboard object. Note that the + Viewer typically does *not* update itself before calling update_views(), + since this would cause it to get updated twice. + +Optionally, Viewers can also implement: + + - save_options() which takes an optiondb (a dictionary). Store into this + dictionary any values the Viewer wants to save in the persistent + ~/.pynche file. This dictionary is saved using marshal. The namespace + for the keys is ad-hoc; make sure you don't clobber some other Viewer's + keys! + + - withdraw() which takes no arguments. This is called when Pynche is + unmapped. All Viewers should implement this. + + - colordb_changed() which takes a single argument, an instance of + ColorDB. This is called whenever the color name database is changed and + gives a chance for the Viewers to do something on those events. See + ListViewer for details. + +External Viewers are found dynamically. Viewer modules should have names such +as FooViewer.py. If such a named module has a module global variable called +ADDTOVIEW and this variable is true, the Viewer will be added dynamically to +the `View' menu. ADDTOVIEW contains a string which is used as the menu item +to display the Viewer (one kludge: if the string contains a `%', this is used +to indicate that the next character will get an underline in the menu, +otherwise the first character is underlined). + +FooViewer.py should contain a class called FooViewer, and its constructor +should take two arguments, an instance of Switchboard, and optionally a Tk +master window. + +""" + +import sys +from types import DictType +import marshal + + + +class Switchboard: + def __init__(self, initfile): + self.__initfile = initfile + self.__colordb = None + self.__optiondb = {} + self.__views = [] + self.__red = 0 + self.__green = 0 + self.__blue = 0 + self.__canceled = 0 + # read the initialization file + fp = None + if initfile: + try: + try: + fp = open(initfile) + self.__optiondb = marshal.load(fp) + if not isinstance(self.__optiondb, DictType): + print >> sys.stderr, \ + 'Problem reading options from file:', initfile + self.__optiondb = {} + except (IOError, EOFError, ValueError): + pass + finally: + if fp: + fp.close() + + def add_view(self, view): + self.__views.append(view) + + def update_views(self, red, green, blue): + self.__red = red + self.__green = green + self.__blue = blue + for v in self.__views: + v.update_yourself(red, green, blue) + + def update_views_current(self): + self.update_views(self.__red, self.__green, self.__blue) + + def current_rgb(self): + return self.__red, self.__green, self.__blue + + def colordb(self): + return self.__colordb + + def set_colordb(self, colordb): + self.__colordb = colordb + for v in self.__views: + if hasattr(v, 'colordb_changed'): + v.colordb_changed(colordb) + self.update_views_current() + + def optiondb(self): + return self.__optiondb + + def save_views(self): + # save the current color + self.__optiondb['RED'] = self.__red + self.__optiondb['GREEN'] = self.__green + self.__optiondb['BLUE'] = self.__blue + for v in self.__views: + if hasattr(v, 'save_options'): + v.save_options(self.__optiondb) + # save the name of the file used for the color database. we'll try to + # load this first. + self.__optiondb['DBFILE'] = self.__colordb.filename() + fp = None + try: + try: + fp = open(self.__initfile, 'w') + except IOError: + print >> sys.stderr, 'Cannot write options to file:', \ + self.__initfile + else: + marshal.dump(self.__optiondb, fp) + finally: + if fp: + fp.close() + + def withdraw_views(self): + for v in self.__views: + if hasattr(v, 'withdraw'): + v.withdraw() + + def canceled(self, flag=1): + self.__canceled = flag + + def canceled_p(self): + return self.__canceled diff --git a/sys/src/cmd/python/Tools/pynche/TextViewer.py b/sys/src/cmd/python/Tools/pynche/TextViewer.py new file mode 100644 index 000000000..456bd96e3 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/TextViewer.py @@ -0,0 +1,188 @@ +"""TextViewer class. + +The TextViewer allows you to see how the selected color would affect various +characteristics of a Tk text widget. This is an output viewer only. + +In the top part of the window is a standard text widget with some sample text +in it. You are free to edit this text in any way you want (BAW: allow you to +change font characteristics). If you want changes in other viewers to update +text characteristics, turn on Track color changes. + +To select which characteristic tracks the change, select one of the radio +buttons in the window below. Text foreground and background affect the text +in the window above. The Selection is what you see when you click the middle +button and drag it through some text. The Insertion is the insertion cursor +in the text window (which only has a background). +""" + +from Tkinter import * +import ColorDB + +ADDTOVIEW = 'Text Window...' + + + +class TextViewer: + def __init__(self, switchboard, master=None): + self.__sb = switchboard + optiondb = switchboard.optiondb() + root = self.__root = Toplevel(master, class_='Pynche') + root.protocol('WM_DELETE_WINDOW', self.withdraw) + root.title('Pynche Text Window') + root.iconname('Pynche Text Window') + root.bind('<Alt-q>', self.__quit) + root.bind('<Alt-Q>', self.__quit) + root.bind('<Alt-w>', self.withdraw) + root.bind('<Alt-W>', self.withdraw) + # + # create the text widget + # + self.__text = Text(root, relief=SUNKEN, + background=optiondb.get('TEXTBG', 'black'), + foreground=optiondb.get('TEXTFG', 'white'), + width=35, height=15) + sfg = optiondb.get('TEXT_SFG') + if sfg: + self.__text.configure(selectforeground=sfg) + sbg = optiondb.get('TEXT_SBG') + if sbg: + self.__text.configure(selectbackground=sbg) + ibg = optiondb.get('TEXT_IBG') + if ibg: + self.__text.configure(insertbackground=ibg) + self.__text.pack() + self.__text.insert(0.0, optiondb.get('TEXT', '''\ +Insert some stuff here and play +with the buttons below to see +how the colors interact in +textual displays. + +See how the selection can also +be affected by tickling the buttons +and choosing a color.''')) + insert = optiondb.get('TEXTINS') + if insert: + self.__text.mark_set(INSERT, insert) + try: + start, end = optiondb.get('TEXTSEL', (6.0, END)) + self.__text.tag_add(SEL, start, end) + except ValueError: + # selection wasn't set + pass + self.__text.focus_set() + # + # variables + self.__trackp = BooleanVar() + self.__trackp.set(optiondb.get('TRACKP', 0)) + self.__which = IntVar() + self.__which.set(optiondb.get('WHICH', 0)) + # + # track toggle + self.__t = Checkbutton(root, text='Track color changes', + variable=self.__trackp, + relief=GROOVE, + command=self.__toggletrack) + self.__t.pack(fill=X, expand=YES) + frame = self.__frame = Frame(root) + frame.pack() + # + # labels + self.__labels = [] + row = 2 + for text in ('Text:', 'Selection:', 'Insertion:'): + l = Label(frame, text=text) + l.grid(row=row, column=0, sticky=E) + self.__labels.append(l) + row += 1 + col = 1 + for text in ('Foreground', 'Background'): + l = Label(frame, text=text) + l.grid(row=1, column=col) + self.__labels.append(l) + col += 1 + # + # radios + self.__radios = [] + for col in (1, 2): + for row in (2, 3, 4): + # there is no insertforeground option + if row==4 and col==1: + continue + r = Radiobutton(frame, variable=self.__which, + value=(row-2)*2 + col-1, + command=self.__set_color) + r.grid(row=row, column=col) + self.__radios.append(r) + self.__toggletrack() + + def __quit(self, event=None): + self.__root.quit() + + def withdraw(self, event=None): + self.__root.withdraw() + + def deiconify(self, event=None): + self.__root.deiconify() + + def __forceupdate(self, event=None): + self.__sb.update_views_current() + + def __toggletrack(self, event=None): + if self.__trackp.get(): + state = NORMAL + fg = self.__radios[0]['foreground'] + else: + state = DISABLED + fg = self.__radios[0]['disabledforeground'] + for r in self.__radios: + r.configure(state=state) + for l in self.__labels: + l.configure(foreground=fg) + + def __set_color(self, event=None): + which = self.__which.get() + text = self.__text + if which == 0: + color = text['foreground'] + elif which == 1: + color = text['background'] + elif which == 2: + color = text['selectforeground'] + elif which == 3: + color = text['selectbackground'] + elif which == 5: + color = text['insertbackground'] + try: + red, green, blue = ColorDB.rrggbb_to_triplet(color) + except ColorDB.BadColor: + # must have been a color name + red, green, blue = self.__sb.colordb().find_byname(color) + self.__sb.update_views(red, green, blue) + + def update_yourself(self, red, green, blue): + if self.__trackp.get(): + colorname = ColorDB.triplet_to_rrggbb((red, green, blue)) + which = self.__which.get() + text = self.__text + if which == 0: + text.configure(foreground=colorname) + elif which == 1: + text.configure(background=colorname) + elif which == 2: + text.configure(selectforeground=colorname) + elif which == 3: + text.configure(selectbackground=colorname) + elif which == 5: + text.configure(insertbackground=colorname) + + def save_options(self, optiondb): + optiondb['TRACKP'] = self.__trackp.get() + optiondb['WHICH'] = self.__which.get() + optiondb['TEXT'] = self.__text.get(0.0, 'end - 1c') + optiondb['TEXTSEL'] = self.__text.tag_ranges(SEL)[0:2] + optiondb['TEXTINS'] = self.__text.index(INSERT) + optiondb['TEXTFG'] = self.__text['foreground'] + optiondb['TEXTBG'] = self.__text['background'] + optiondb['TEXT_SFG'] = self.__text['selectforeground'] + optiondb['TEXT_SBG'] = self.__text['selectbackground'] + optiondb['TEXT_IBG'] = self.__text['insertbackground'] diff --git a/sys/src/cmd/python/Tools/pynche/TypeinViewer.py b/sys/src/cmd/python/Tools/pynche/TypeinViewer.py new file mode 100644 index 000000000..bcc3cda86 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/TypeinViewer.py @@ -0,0 +1,163 @@ +"""TypeinViewer class. + +The TypeinViewer is what you see at the lower right of the main Pynche +widget. It contains three text entry fields, one each for red, green, blue. +Input into these windows is highly constrained; it only allows you to enter +values that are legal for a color axis. This usually means 0-255 for decimal +input and 0x0 - 0xff for hex input. + +You can toggle whether you want to view and input the values in either decimal +or hex by clicking on Hexadecimal. By clicking on Update while typing, the +color selection will be made on every change to the text field. Otherwise, +you must hit Return or Tab to select the color. +""" + +import sys +import re +from Tkinter import * + + + +class TypeinViewer: + def __init__(self, switchboard, master=None): + # non-gui ivars + self.__sb = switchboard + optiondb = switchboard.optiondb() + self.__hexp = BooleanVar() + self.__hexp.set(optiondb.get('HEXTYPE', 0)) + self.__uwtyping = BooleanVar() + self.__uwtyping.set(optiondb.get('UPWHILETYPE', 0)) + # create the gui + self.__frame = Frame(master, relief=RAISED, borderwidth=1) + self.__frame.grid(row=3, column=1, sticky='NSEW') + # Red + self.__xl = Label(self.__frame, text='Red:') + self.__xl.grid(row=0, column=0, sticky=E) + subframe = Frame(self.__frame) + subframe.grid(row=0, column=1) + self.__xox = Label(subframe, text='0x') + self.__xox.grid(row=0, column=0, sticky=E) + self.__xox['font'] = 'courier' + self.__x = Entry(subframe, width=3) + self.__x.grid(row=0, column=1) + self.__x.bindtags(self.__x.bindtags() + ('Normalize', 'Update')) + self.__x.bind_class('Normalize', '<Key>', self.__normalize) + self.__x.bind_class('Update' , '<Key>', self.__maybeupdate) + # Green + self.__yl = Label(self.__frame, text='Green:') + self.__yl.grid(row=1, column=0, sticky=E) + subframe = Frame(self.__frame) + subframe.grid(row=1, column=1) + self.__yox = Label(subframe, text='0x') + self.__yox.grid(row=0, column=0, sticky=E) + self.__yox['font'] = 'courier' + self.__y = Entry(subframe, width=3) + self.__y.grid(row=0, column=1) + self.__y.bindtags(self.__y.bindtags() + ('Normalize', 'Update')) + # Blue + self.__zl = Label(self.__frame, text='Blue:') + self.__zl.grid(row=2, column=0, sticky=E) + subframe = Frame(self.__frame) + subframe.grid(row=2, column=1) + self.__zox = Label(subframe, text='0x') + self.__zox.grid(row=0, column=0, sticky=E) + self.__zox['font'] = 'courier' + self.__z = Entry(subframe, width=3) + self.__z.grid(row=0, column=1) + self.__z.bindtags(self.__z.bindtags() + ('Normalize', 'Update')) + # Update while typing? + self.__uwt = Checkbutton(self.__frame, + text='Update while typing', + variable=self.__uwtyping) + self.__uwt.grid(row=3, column=0, columnspan=2, sticky=W) + # Hex/Dec + self.__hex = Checkbutton(self.__frame, + text='Hexadecimal', + variable=self.__hexp, + command=self.__togglehex) + self.__hex.grid(row=4, column=0, columnspan=2, sticky=W) + + def __togglehex(self, event=None): + red, green, blue = self.__sb.current_rgb() + if self.__hexp.get(): + label = '0x' + else: + label = ' ' + self.__xox['text'] = label + self.__yox['text'] = label + self.__zox['text'] = label + self.update_yourself(red, green, blue) + + def __normalize(self, event=None): + ew = event.widget + contents = ew.get() + icursor = ew.index(INSERT) + if contents and contents[0] in 'xX' and self.__hexp.get(): + contents = '0' + contents + # Figure out the contents in the current base. + try: + if self.__hexp.get(): + v = int(contents, 16) + else: + v = int(contents) + except ValueError: + v = None + # If value is not legal, or empty, delete the last character inserted + # and ring the bell. Don't ring the bell if the field is empty (it'll + # just equal zero. + if v is None: + pass + elif v < 0 or v > 255: + i = ew.index(INSERT) + if event.char: + contents = contents[:i-1] + contents[i:] + icursor -= 1 + ew.bell() + elif self.__hexp.get(): + contents = hex(v)[2:] + else: + contents = int(v) + ew.delete(0, END) + ew.insert(0, contents) + ew.icursor(icursor) + + def __maybeupdate(self, event=None): + if self.__uwtyping.get() or event.keysym in ('Return', 'Tab'): + self.__update(event) + + def __update(self, event=None): + redstr = self.__x.get() or '0' + greenstr = self.__y.get() or '0' + bluestr = self.__z.get() or '0' + if self.__hexp.get(): + base = 16 + else: + base = 10 + red, green, blue = [int(x, base) for x in (redstr, greenstr, bluestr)] + self.__sb.update_views(red, green, blue) + + def update_yourself(self, red, green, blue): + if self.__hexp.get(): + sred, sgreen, sblue = [hex(x)[2:] for x in (red, green, blue)] + else: + sred, sgreen, sblue = red, green, blue + x, y, z = self.__x, self.__y, self.__z + xicursor = x.index(INSERT) + yicursor = y.index(INSERT) + zicursor = z.index(INSERT) + x.delete(0, END) + y.delete(0, END) + z.delete(0, END) + x.insert(0, sred) + y.insert(0, sgreen) + z.insert(0, sblue) + x.icursor(xicursor) + y.icursor(yicursor) + z.icursor(zicursor) + + def hexp_var(self): + return self.__hexp + + def save_options(self, optiondb): + optiondb['HEXTYPE'] = self.__hexp.get() + optiondb['UPWHILETYPE'] = self.__uwtyping.get() diff --git a/sys/src/cmd/python/Tools/pynche/X/rgb.txt b/sys/src/cmd/python/Tools/pynche/X/rgb.txt new file mode 100644 index 000000000..b11ffd058 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/X/rgb.txt @@ -0,0 +1,753 @@ +! $XConsortium: rgb.txt,v 10.41 94/02/20 18:39:36 rws Exp $ +255 250 250 snow +248 248 255 ghost white +248 248 255 GhostWhite +245 245 245 white smoke +245 245 245 WhiteSmoke +220 220 220 gainsboro +255 250 240 floral white +255 250 240 FloralWhite +253 245 230 old lace +253 245 230 OldLace +250 240 230 linen +250 235 215 antique white +250 235 215 AntiqueWhite +255 239 213 papaya whip +255 239 213 PapayaWhip +255 235 205 blanched almond +255 235 205 BlanchedAlmond +255 228 196 bisque +255 218 185 peach puff +255 218 185 PeachPuff +255 222 173 navajo white +255 222 173 NavajoWhite +255 228 181 moccasin +255 248 220 cornsilk +255 255 240 ivory +255 250 205 lemon chiffon +255 250 205 LemonChiffon +255 245 238 seashell +240 255 240 honeydew +245 255 250 mint cream +245 255 250 MintCream +240 255 255 azure +240 248 255 alice blue +240 248 255 AliceBlue +230 230 250 lavender +255 240 245 lavender blush +255 240 245 LavenderBlush +255 228 225 misty rose +255 228 225 MistyRose +255 255 255 white + 0 0 0 black + 47 79 79 dark slate gray + 47 79 79 DarkSlateGray + 47 79 79 dark slate grey + 47 79 79 DarkSlateGrey +105 105 105 dim gray +105 105 105 DimGray +105 105 105 dim grey +105 105 105 DimGrey +112 128 144 slate gray +112 128 144 SlateGray +112 128 144 slate grey +112 128 144 SlateGrey +119 136 153 light slate gray +119 136 153 LightSlateGray +119 136 153 light slate grey +119 136 153 LightSlateGrey +190 190 190 gray +190 190 190 grey +211 211 211 light grey +211 211 211 LightGrey +211 211 211 light gray +211 211 211 LightGray + 25 25 112 midnight blue + 25 25 112 MidnightBlue + 0 0 128 navy + 0 0 128 navy blue + 0 0 128 NavyBlue +100 149 237 cornflower blue +100 149 237 CornflowerBlue + 72 61 139 dark slate blue + 72 61 139 DarkSlateBlue +106 90 205 slate blue +106 90 205 SlateBlue +123 104 238 medium slate blue +123 104 238 MediumSlateBlue +132 112 255 light slate blue +132 112 255 LightSlateBlue + 0 0 205 medium blue + 0 0 205 MediumBlue + 65 105 225 royal blue + 65 105 225 RoyalBlue + 0 0 255 blue + 30 144 255 dodger blue + 30 144 255 DodgerBlue + 0 191 255 deep sky blue + 0 191 255 DeepSkyBlue +135 206 235 sky blue +135 206 235 SkyBlue +135 206 250 light sky blue +135 206 250 LightSkyBlue + 70 130 180 steel blue + 70 130 180 SteelBlue +176 196 222 light steel blue +176 196 222 LightSteelBlue +173 216 230 light blue +173 216 230 LightBlue +176 224 230 powder blue +176 224 230 PowderBlue +175 238 238 pale turquoise +175 238 238 PaleTurquoise + 0 206 209 dark turquoise + 0 206 209 DarkTurquoise + 72 209 204 medium turquoise + 72 209 204 MediumTurquoise + 64 224 208 turquoise + 0 255 255 cyan +224 255 255 light cyan +224 255 255 LightCyan + 95 158 160 cadet blue + 95 158 160 CadetBlue +102 205 170 medium aquamarine +102 205 170 MediumAquamarine +127 255 212 aquamarine + 0 100 0 dark green + 0 100 0 DarkGreen + 85 107 47 dark olive green + 85 107 47 DarkOliveGreen +143 188 143 dark sea green +143 188 143 DarkSeaGreen + 46 139 87 sea green + 46 139 87 SeaGreen + 60 179 113 medium sea green + 60 179 113 MediumSeaGreen + 32 178 170 light sea green + 32 178 170 LightSeaGreen +152 251 152 pale green +152 251 152 PaleGreen + 0 255 127 spring green + 0 255 127 SpringGreen +124 252 0 lawn green +124 252 0 LawnGreen + 0 255 0 green +127 255 0 chartreuse + 0 250 154 medium spring green + 0 250 154 MediumSpringGreen +173 255 47 green yellow +173 255 47 GreenYellow + 50 205 50 lime green + 50 205 50 LimeGreen +154 205 50 yellow green +154 205 50 YellowGreen + 34 139 34 forest green + 34 139 34 ForestGreen +107 142 35 olive drab +107 142 35 OliveDrab +189 183 107 dark khaki +189 183 107 DarkKhaki +240 230 140 khaki +238 232 170 pale goldenrod +238 232 170 PaleGoldenrod +250 250 210 light goldenrod yellow +250 250 210 LightGoldenrodYellow +255 255 224 light yellow +255 255 224 LightYellow +255 255 0 yellow +255 215 0 gold +238 221 130 light goldenrod +238 221 130 LightGoldenrod +218 165 32 goldenrod +184 134 11 dark goldenrod +184 134 11 DarkGoldenrod +188 143 143 rosy brown +188 143 143 RosyBrown +205 92 92 indian red +205 92 92 IndianRed +139 69 19 saddle brown +139 69 19 SaddleBrown +160 82 45 sienna +205 133 63 peru +222 184 135 burlywood +245 245 220 beige +245 222 179 wheat +244 164 96 sandy brown +244 164 96 SandyBrown +210 180 140 tan +210 105 30 chocolate +178 34 34 firebrick +165 42 42 brown +233 150 122 dark salmon +233 150 122 DarkSalmon +250 128 114 salmon +255 160 122 light salmon +255 160 122 LightSalmon +255 165 0 orange +255 140 0 dark orange +255 140 0 DarkOrange +255 127 80 coral +240 128 128 light coral +240 128 128 LightCoral +255 99 71 tomato +255 69 0 orange red +255 69 0 OrangeRed +255 0 0 red +255 105 180 hot pink +255 105 180 HotPink +255 20 147 deep pink +255 20 147 DeepPink +255 192 203 pink +255 182 193 light pink +255 182 193 LightPink +219 112 147 pale violet red +219 112 147 PaleVioletRed +176 48 96 maroon +199 21 133 medium violet red +199 21 133 MediumVioletRed +208 32 144 violet red +208 32 144 VioletRed +255 0 255 magenta +238 130 238 violet +221 160 221 plum +218 112 214 orchid +186 85 211 medium orchid +186 85 211 MediumOrchid +153 50 204 dark orchid +153 50 204 DarkOrchid +148 0 211 dark violet +148 0 211 DarkViolet +138 43 226 blue violet +138 43 226 BlueViolet +160 32 240 purple +147 112 219 medium purple +147 112 219 MediumPurple +216 191 216 thistle +255 250 250 snow1 +238 233 233 snow2 +205 201 201 snow3 +139 137 137 snow4 +255 245 238 seashell1 +238 229 222 seashell2 +205 197 191 seashell3 +139 134 130 seashell4 +255 239 219 AntiqueWhite1 +238 223 204 AntiqueWhite2 +205 192 176 AntiqueWhite3 +139 131 120 AntiqueWhite4 +255 228 196 bisque1 +238 213 183 bisque2 +205 183 158 bisque3 +139 125 107 bisque4 +255 218 185 PeachPuff1 +238 203 173 PeachPuff2 +205 175 149 PeachPuff3 +139 119 101 PeachPuff4 +255 222 173 NavajoWhite1 +238 207 161 NavajoWhite2 +205 179 139 NavajoWhite3 +139 121 94 NavajoWhite4 +255 250 205 LemonChiffon1 +238 233 191 LemonChiffon2 +205 201 165 LemonChiffon3 +139 137 112 LemonChiffon4 +255 248 220 cornsilk1 +238 232 205 cornsilk2 +205 200 177 cornsilk3 +139 136 120 cornsilk4 +255 255 240 ivory1 +238 238 224 ivory2 +205 205 193 ivory3 +139 139 131 ivory4 +240 255 240 honeydew1 +224 238 224 honeydew2 +193 205 193 honeydew3 +131 139 131 honeydew4 +255 240 245 LavenderBlush1 +238 224 229 LavenderBlush2 +205 193 197 LavenderBlush3 +139 131 134 LavenderBlush4 +255 228 225 MistyRose1 +238 213 210 MistyRose2 +205 183 181 MistyRose3 +139 125 123 MistyRose4 +240 255 255 azure1 +224 238 238 azure2 +193 205 205 azure3 +131 139 139 azure4 +131 111 255 SlateBlue1 +122 103 238 SlateBlue2 +105 89 205 SlateBlue3 + 71 60 139 SlateBlue4 + 72 118 255 RoyalBlue1 + 67 110 238 RoyalBlue2 + 58 95 205 RoyalBlue3 + 39 64 139 RoyalBlue4 + 0 0 255 blue1 + 0 0 238 blue2 + 0 0 205 blue3 + 0 0 139 blue4 + 30 144 255 DodgerBlue1 + 28 134 238 DodgerBlue2 + 24 116 205 DodgerBlue3 + 16 78 139 DodgerBlue4 + 99 184 255 SteelBlue1 + 92 172 238 SteelBlue2 + 79 148 205 SteelBlue3 + 54 100 139 SteelBlue4 + 0 191 255 DeepSkyBlue1 + 0 178 238 DeepSkyBlue2 + 0 154 205 DeepSkyBlue3 + 0 104 139 DeepSkyBlue4 +135 206 255 SkyBlue1 +126 192 238 SkyBlue2 +108 166 205 SkyBlue3 + 74 112 139 SkyBlue4 +176 226 255 LightSkyBlue1 +164 211 238 LightSkyBlue2 +141 182 205 LightSkyBlue3 + 96 123 139 LightSkyBlue4 +198 226 255 SlateGray1 +185 211 238 SlateGray2 +159 182 205 SlateGray3 +108 123 139 SlateGray4 +202 225 255 LightSteelBlue1 +188 210 238 LightSteelBlue2 +162 181 205 LightSteelBlue3 +110 123 139 LightSteelBlue4 +191 239 255 LightBlue1 +178 223 238 LightBlue2 +154 192 205 LightBlue3 +104 131 139 LightBlue4 +224 255 255 LightCyan1 +209 238 238 LightCyan2 +180 205 205 LightCyan3 +122 139 139 LightCyan4 +187 255 255 PaleTurquoise1 +174 238 238 PaleTurquoise2 +150 205 205 PaleTurquoise3 +102 139 139 PaleTurquoise4 +152 245 255 CadetBlue1 +142 229 238 CadetBlue2 +122 197 205 CadetBlue3 + 83 134 139 CadetBlue4 + 0 245 255 turquoise1 + 0 229 238 turquoise2 + 0 197 205 turquoise3 + 0 134 139 turquoise4 + 0 255 255 cyan1 + 0 238 238 cyan2 + 0 205 205 cyan3 + 0 139 139 cyan4 +151 255 255 DarkSlateGray1 +141 238 238 DarkSlateGray2 +121 205 205 DarkSlateGray3 + 82 139 139 DarkSlateGray4 +127 255 212 aquamarine1 +118 238 198 aquamarine2 +102 205 170 aquamarine3 + 69 139 116 aquamarine4 +193 255 193 DarkSeaGreen1 +180 238 180 DarkSeaGreen2 +155 205 155 DarkSeaGreen3 +105 139 105 DarkSeaGreen4 + 84 255 159 SeaGreen1 + 78 238 148 SeaGreen2 + 67 205 128 SeaGreen3 + 46 139 87 SeaGreen4 +154 255 154 PaleGreen1 +144 238 144 PaleGreen2 +124 205 124 PaleGreen3 + 84 139 84 PaleGreen4 + 0 255 127 SpringGreen1 + 0 238 118 SpringGreen2 + 0 205 102 SpringGreen3 + 0 139 69 SpringGreen4 + 0 255 0 green1 + 0 238 0 green2 + 0 205 0 green3 + 0 139 0 green4 +127 255 0 chartreuse1 +118 238 0 chartreuse2 +102 205 0 chartreuse3 + 69 139 0 chartreuse4 +192 255 62 OliveDrab1 +179 238 58 OliveDrab2 +154 205 50 OliveDrab3 +105 139 34 OliveDrab4 +202 255 112 DarkOliveGreen1 +188 238 104 DarkOliveGreen2 +162 205 90 DarkOliveGreen3 +110 139 61 DarkOliveGreen4 +255 246 143 khaki1 +238 230 133 khaki2 +205 198 115 khaki3 +139 134 78 khaki4 +255 236 139 LightGoldenrod1 +238 220 130 LightGoldenrod2 +205 190 112 LightGoldenrod3 +139 129 76 LightGoldenrod4 +255 255 224 LightYellow1 +238 238 209 LightYellow2 +205 205 180 LightYellow3 +139 139 122 LightYellow4 +255 255 0 yellow1 +238 238 0 yellow2 +205 205 0 yellow3 +139 139 0 yellow4 +255 215 0 gold1 +238 201 0 gold2 +205 173 0 gold3 +139 117 0 gold4 +255 193 37 goldenrod1 +238 180 34 goldenrod2 +205 155 29 goldenrod3 +139 105 20 goldenrod4 +255 185 15 DarkGoldenrod1 +238 173 14 DarkGoldenrod2 +205 149 12 DarkGoldenrod3 +139 101 8 DarkGoldenrod4 +255 193 193 RosyBrown1 +238 180 180 RosyBrown2 +205 155 155 RosyBrown3 +139 105 105 RosyBrown4 +255 106 106 IndianRed1 +238 99 99 IndianRed2 +205 85 85 IndianRed3 +139 58 58 IndianRed4 +255 130 71 sienna1 +238 121 66 sienna2 +205 104 57 sienna3 +139 71 38 sienna4 +255 211 155 burlywood1 +238 197 145 burlywood2 +205 170 125 burlywood3 +139 115 85 burlywood4 +255 231 186 wheat1 +238 216 174 wheat2 +205 186 150 wheat3 +139 126 102 wheat4 +255 165 79 tan1 +238 154 73 tan2 +205 133 63 tan3 +139 90 43 tan4 +255 127 36 chocolate1 +238 118 33 chocolate2 +205 102 29 chocolate3 +139 69 19 chocolate4 +255 48 48 firebrick1 +238 44 44 firebrick2 +205 38 38 firebrick3 +139 26 26 firebrick4 +255 64 64 brown1 +238 59 59 brown2 +205 51 51 brown3 +139 35 35 brown4 +255 140 105 salmon1 +238 130 98 salmon2 +205 112 84 salmon3 +139 76 57 salmon4 +255 160 122 LightSalmon1 +238 149 114 LightSalmon2 +205 129 98 LightSalmon3 +139 87 66 LightSalmon4 +255 165 0 orange1 +238 154 0 orange2 +205 133 0 orange3 +139 90 0 orange4 +255 127 0 DarkOrange1 +238 118 0 DarkOrange2 +205 102 0 DarkOrange3 +139 69 0 DarkOrange4 +255 114 86 coral1 +238 106 80 coral2 +205 91 69 coral3 +139 62 47 coral4 +255 99 71 tomato1 +238 92 66 tomato2 +205 79 57 tomato3 +139 54 38 tomato4 +255 69 0 OrangeRed1 +238 64 0 OrangeRed2 +205 55 0 OrangeRed3 +139 37 0 OrangeRed4 +255 0 0 red1 +238 0 0 red2 +205 0 0 red3 +139 0 0 red4 +255 20 147 DeepPink1 +238 18 137 DeepPink2 +205 16 118 DeepPink3 +139 10 80 DeepPink4 +255 110 180 HotPink1 +238 106 167 HotPink2 +205 96 144 HotPink3 +139 58 98 HotPink4 +255 181 197 pink1 +238 169 184 pink2 +205 145 158 pink3 +139 99 108 pink4 +255 174 185 LightPink1 +238 162 173 LightPink2 +205 140 149 LightPink3 +139 95 101 LightPink4 +255 130 171 PaleVioletRed1 +238 121 159 PaleVioletRed2 +205 104 137 PaleVioletRed3 +139 71 93 PaleVioletRed4 +255 52 179 maroon1 +238 48 167 maroon2 +205 41 144 maroon3 +139 28 98 maroon4 +255 62 150 VioletRed1 +238 58 140 VioletRed2 +205 50 120 VioletRed3 +139 34 82 VioletRed4 +255 0 255 magenta1 +238 0 238 magenta2 +205 0 205 magenta3 +139 0 139 magenta4 +255 131 250 orchid1 +238 122 233 orchid2 +205 105 201 orchid3 +139 71 137 orchid4 +255 187 255 plum1 +238 174 238 plum2 +205 150 205 plum3 +139 102 139 plum4 +224 102 255 MediumOrchid1 +209 95 238 MediumOrchid2 +180 82 205 MediumOrchid3 +122 55 139 MediumOrchid4 +191 62 255 DarkOrchid1 +178 58 238 DarkOrchid2 +154 50 205 DarkOrchid3 +104 34 139 DarkOrchid4 +155 48 255 purple1 +145 44 238 purple2 +125 38 205 purple3 + 85 26 139 purple4 +171 130 255 MediumPurple1 +159 121 238 MediumPurple2 +137 104 205 MediumPurple3 + 93 71 139 MediumPurple4 +255 225 255 thistle1 +238 210 238 thistle2 +205 181 205 thistle3 +139 123 139 thistle4 + 0 0 0 gray0 + 0 0 0 grey0 + 3 3 3 gray1 + 3 3 3 grey1 + 5 5 5 gray2 + 5 5 5 grey2 + 8 8 8 gray3 + 8 8 8 grey3 + 10 10 10 gray4 + 10 10 10 grey4 + 13 13 13 gray5 + 13 13 13 grey5 + 15 15 15 gray6 + 15 15 15 grey6 + 18 18 18 gray7 + 18 18 18 grey7 + 20 20 20 gray8 + 20 20 20 grey8 + 23 23 23 gray9 + 23 23 23 grey9 + 26 26 26 gray10 + 26 26 26 grey10 + 28 28 28 gray11 + 28 28 28 grey11 + 31 31 31 gray12 + 31 31 31 grey12 + 33 33 33 gray13 + 33 33 33 grey13 + 36 36 36 gray14 + 36 36 36 grey14 + 38 38 38 gray15 + 38 38 38 grey15 + 41 41 41 gray16 + 41 41 41 grey16 + 43 43 43 gray17 + 43 43 43 grey17 + 46 46 46 gray18 + 46 46 46 grey18 + 48 48 48 gray19 + 48 48 48 grey19 + 51 51 51 gray20 + 51 51 51 grey20 + 54 54 54 gray21 + 54 54 54 grey21 + 56 56 56 gray22 + 56 56 56 grey22 + 59 59 59 gray23 + 59 59 59 grey23 + 61 61 61 gray24 + 61 61 61 grey24 + 64 64 64 gray25 + 64 64 64 grey25 + 66 66 66 gray26 + 66 66 66 grey26 + 69 69 69 gray27 + 69 69 69 grey27 + 71 71 71 gray28 + 71 71 71 grey28 + 74 74 74 gray29 + 74 74 74 grey29 + 77 77 77 gray30 + 77 77 77 grey30 + 79 79 79 gray31 + 79 79 79 grey31 + 82 82 82 gray32 + 82 82 82 grey32 + 84 84 84 gray33 + 84 84 84 grey33 + 87 87 87 gray34 + 87 87 87 grey34 + 89 89 89 gray35 + 89 89 89 grey35 + 92 92 92 gray36 + 92 92 92 grey36 + 94 94 94 gray37 + 94 94 94 grey37 + 97 97 97 gray38 + 97 97 97 grey38 + 99 99 99 gray39 + 99 99 99 grey39 +102 102 102 gray40 +102 102 102 grey40 +105 105 105 gray41 +105 105 105 grey41 +107 107 107 gray42 +107 107 107 grey42 +110 110 110 gray43 +110 110 110 grey43 +112 112 112 gray44 +112 112 112 grey44 +115 115 115 gray45 +115 115 115 grey45 +117 117 117 gray46 +117 117 117 grey46 +120 120 120 gray47 +120 120 120 grey47 +122 122 122 gray48 +122 122 122 grey48 +125 125 125 gray49 +125 125 125 grey49 +127 127 127 gray50 +127 127 127 grey50 +130 130 130 gray51 +130 130 130 grey51 +133 133 133 gray52 +133 133 133 grey52 +135 135 135 gray53 +135 135 135 grey53 +138 138 138 gray54 +138 138 138 grey54 +140 140 140 gray55 +140 140 140 grey55 +143 143 143 gray56 +143 143 143 grey56 +145 145 145 gray57 +145 145 145 grey57 +148 148 148 gray58 +148 148 148 grey58 +150 150 150 gray59 +150 150 150 grey59 +153 153 153 gray60 +153 153 153 grey60 +156 156 156 gray61 +156 156 156 grey61 +158 158 158 gray62 +158 158 158 grey62 +161 161 161 gray63 +161 161 161 grey63 +163 163 163 gray64 +163 163 163 grey64 +166 166 166 gray65 +166 166 166 grey65 +168 168 168 gray66 +168 168 168 grey66 +171 171 171 gray67 +171 171 171 grey67 +173 173 173 gray68 +173 173 173 grey68 +176 176 176 gray69 +176 176 176 grey69 +179 179 179 gray70 +179 179 179 grey70 +181 181 181 gray71 +181 181 181 grey71 +184 184 184 gray72 +184 184 184 grey72 +186 186 186 gray73 +186 186 186 grey73 +189 189 189 gray74 +189 189 189 grey74 +191 191 191 gray75 +191 191 191 grey75 +194 194 194 gray76 +194 194 194 grey76 +196 196 196 gray77 +196 196 196 grey77 +199 199 199 gray78 +199 199 199 grey78 +201 201 201 gray79 +201 201 201 grey79 +204 204 204 gray80 +204 204 204 grey80 +207 207 207 gray81 +207 207 207 grey81 +209 209 209 gray82 +209 209 209 grey82 +212 212 212 gray83 +212 212 212 grey83 +214 214 214 gray84 +214 214 214 grey84 +217 217 217 gray85 +217 217 217 grey85 +219 219 219 gray86 +219 219 219 grey86 +222 222 222 gray87 +222 222 222 grey87 +224 224 224 gray88 +224 224 224 grey88 +227 227 227 gray89 +227 227 227 grey89 +229 229 229 gray90 +229 229 229 grey90 +232 232 232 gray91 +232 232 232 grey91 +235 235 235 gray92 +235 235 235 grey92 +237 237 237 gray93 +237 237 237 grey93 +240 240 240 gray94 +240 240 240 grey94 +242 242 242 gray95 +242 242 242 grey95 +245 245 245 gray96 +245 245 245 grey96 +247 247 247 gray97 +247 247 247 grey97 +250 250 250 gray98 +250 250 250 grey98 +252 252 252 gray99 +252 252 252 grey99 +255 255 255 gray100 +255 255 255 grey100 +169 169 169 dark grey +169 169 169 DarkGrey +169 169 169 dark gray +169 169 169 DarkGray +0 0 139 dark blue +0 0 139 DarkBlue +0 139 139 dark cyan +0 139 139 DarkCyan +139 0 139 dark magenta +139 0 139 DarkMagenta +139 0 0 dark red +139 0 0 DarkRed +144 238 144 light green +144 238 144 LightGreen diff --git a/sys/src/cmd/python/Tools/pynche/X/xlicense.txt b/sys/src/cmd/python/Tools/pynche/X/xlicense.txt new file mode 100644 index 000000000..b4471db67 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/X/xlicense.txt @@ -0,0 +1,29 @@ +X Window System License - X11R6.4 + +Copyright (c) 1998 The Open Group + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + +X Window System is a trademark of The Open Group diff --git a/sys/src/cmd/python/Tools/pynche/__init__.py b/sys/src/cmd/python/Tools/pynche/__init__.py new file mode 100644 index 000000000..b93054b3e --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/__init__.py @@ -0,0 +1 @@ +# Dummy file to make this directory a package. diff --git a/sys/src/cmd/python/Tools/pynche/html40colors.txt b/sys/src/cmd/python/Tools/pynche/html40colors.txt new file mode 100644 index 000000000..3eeb0a10a --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/html40colors.txt @@ -0,0 +1,17 @@ +# HTML 4.0 color names +Black #000000 +Silver #c0c0c0 +Gray #808080 +White #ffffff +Maroon #800000 +Red #ff0000 +Purple #800080 +Fuchsia #ff00ff +Green #008000 +Lime #00ff00 +Olive #808000 +Yellow #ffff00 +Navy #000080 +Blue #0000ff +Teal #008080 +Aqua #00ffff diff --git a/sys/src/cmd/python/Tools/pynche/namedcolors.txt b/sys/src/cmd/python/Tools/pynche/namedcolors.txt new file mode 100644 index 000000000..3658e85f2 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/namedcolors.txt @@ -0,0 +1,100 @@ +# named colors from http://www.lightlink.com/xine/bells/namedcolors.html +White #FFFFFF +Red #FF0000 +Green #00FF00 +Blue #0000FF +Magenta #FF00FF +Cyan #00FFFF +Yellow #FFFF00 +Black #000000 +Aquamarine #70DB93 +Baker's Chocolate #5C3317 +Blue Violet #9F5F9F +Brass #B5A642 +Bright Gold #D9D919 +Brown #A62A2A +Bronze #8C7853 +Bronze II #A67D3D +Cadet Blue #5F9F9F +Cool Copper #D98719 +Copper #B87333 +Coral #FF7F00 +Corn Flower Blue #42426F +Dark Brown #5C4033 +Dark Green #2F4F2F +Dark Green Copper #4A766E +Dark Olive Green #4F4F2F +Dark Orchid #9932CD +Dark Purple #871F78 +Dark Slate Blue #6B238E +Dark Slate Grey #2F4F4F +Dark Tan #97694F +Dark Turquoise #7093DB +Dark Wood #855E42 +Dim Grey #545454 +Dusty Rose #856363 +Feldspar #D19275 +Firebrick #8E2323 +Forest Green #238E23 +Gold #CD7F32 +Goldenrod #DBDB70 +Grey #C0C0C0 +Green Copper #527F76 +Green Yellow #93DB70 +Hunter Green #215E21 +Indian Red #4E2F2F +Khaki #9F9F5F +Light Blue #C0D9D9 +Light Grey #A8A8A8 +Light Steel Blue #8F8FBD +Light Wood #E9C2A6 +Lime Green #32CD32 +Mandarian Orange #E47833 +Maroon #8E236B +Medium Aquamarine #32CD99 +Medium Blue #3232CD +Medium Forest Green #6B8E23 +Medium Goldenrod #EAEAAE +Medium Orchid #9370DB +Medium Sea Green #426F42 +Medium Slate Blue #7F00FF +Medium Spring Green #7FFF00 +Medium Turquoise #70DBDB +Medium Violet Red #DB7093 +Medium Wood #A68064 +Midnight Blue #2F2F4F +Navy Blue #23238E +Neon Blue #4D4DFF +Neon Pink #FF6EC7 +New Midnight Blue #00009C +New Tan #EBC79E +Old Gold #CFB53B +Orange #FF7F00 +Orange Red #FF2400 +Orchid #DB70DB +Pale Green #8FBC8F +Pink #BC8F8F +Plum #EAADEA +Quartz #D9D9F3 +Rich Blue #5959AB +Salmon #6F4242 +Scarlet #8C1717 +Sea Green #238E68 +Semi-Sweet Chocolate #6B4226 +Sienna #8E6B23 +Silver #E6E8FA +Sky Blue #3299CC +Slate Blue #007FFF +Spicy Pink #FF1CAE +Spring Green #00FF7F +Steel Blue #236B8E +Summer Sky #38B0DE +Tan #DB9370 +Thistle #D8BFD8 +Turquoise #ADEAEA +Very Dark Brown #5C4033 +Very Light Grey #CDCDCD +Violet #4F2F4F +Violet Red #CC3299 +Wheat #D8D8BF +Yellow Green #99CC32 diff --git a/sys/src/cmd/python/Tools/pynche/pyColorChooser.py b/sys/src/cmd/python/Tools/pynche/pyColorChooser.py new file mode 100644 index 000000000..56f694062 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/pyColorChooser.py @@ -0,0 +1,125 @@ +"""Color chooser implementing (almost) the tkColorColor interface +""" + +import os +import Main +import ColorDB + + + +class Chooser: + """Ask for a color""" + def __init__(self, + master = None, + databasefile = None, + initfile = None, + ignore = None, + wantspec = None): + self.__master = master + self.__databasefile = databasefile + self.__initfile = initfile or os.path.expanduser('~/.pynche') + self.__ignore = ignore + self.__pw = None + self.__wantspec = wantspec + + def show(self, color, options): + # scan for options that can override the ctor options + self.__wantspec = options.get('wantspec', self.__wantspec) + dbfile = options.get('databasefile', self.__databasefile) + # load the database file + colordb = None + if dbfile <> self.__databasefile: + colordb = ColorDB.get_colordb(dbfile) + if not self.__master: + from Tkinter import Tk + self.__master = Tk() + if not self.__pw: + self.__pw, self.__sb = \ + Main.build(master = self.__master, + initfile = self.__initfile, + ignore = self.__ignore) + else: + self.__pw.deiconify() + # convert color + if colordb: + self.__sb.set_colordb(colordb) + else: + colordb = self.__sb.colordb() + if color: + r, g, b = Main.initial_color(color, colordb) + self.__sb.update_views(r, g, b) + # reset the canceled flag and run it + self.__sb.canceled(0) + Main.run(self.__pw, self.__sb) + rgbtuple = self.__sb.current_rgb() + self.__pw.withdraw() + # check to see if the cancel button was pushed + if self.__sb.canceled_p(): + return None, None + # Try to return the color name from the database if there is an exact + # match, otherwise use the "#rrggbb" spec. BAW: Forget about color + # aliases for now, maybe later we should return these too. + name = None + if not self.__wantspec: + try: + name = colordb.find_byrgb(rgbtuple)[0] + except ColorDB.BadColor: + pass + if name is None: + name = ColorDB.triplet_to_rrggbb(rgbtuple) + return rgbtuple, name + + def save(self): + if self.__sb: + self.__sb.save_views() + + +# convenience stuff +_chooser = None + +def askcolor(color = None, **options): + """Ask for a color""" + global _chooser + if not _chooser: + _chooser = apply(Chooser, (), options) + return _chooser.show(color, options) + +def save(): + global _chooser + if _chooser: + _chooser.save() + + +# test stuff +if __name__ == '__main__': + from Tkinter import * + + class Tester: + def __init__(self): + self.__root = tk = Tk() + b = Button(tk, text='Choose Color...', command=self.__choose) + b.pack() + self.__l = Label(tk) + self.__l.pack() + q = Button(tk, text='Quit', command=self.__quit) + q.pack() + + def __choose(self, event=None): + rgb, name = askcolor(master=self.__root) + if rgb is None: + text = 'You hit CANCEL!' + else: + r, g, b = rgb + text = 'You picked %s (%3d/%3d/%3d)' % (name, r, g, b) + self.__l.configure(text=text) + + def __quit(self, event=None): + self.__root.quit() + + def run(self): + self.__root.mainloop() + t = Tester() + t.run() + # simpler +## print 'color:', askcolor() +## print 'color:', askcolor() diff --git a/sys/src/cmd/python/Tools/pynche/pynche b/sys/src/cmd/python/Tools/pynche/pynche new file mode 100755 index 000000000..64bf70335 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/pynche @@ -0,0 +1,7 @@ +#! /usr/bin/env python + +"""Run this file under Unix, or when debugging under Windows. +Run the file pynche.pyw under Windows to inhibit the console window. +""" +import Main +Main.main() diff --git a/sys/src/cmd/python/Tools/pynche/pynche.pyw b/sys/src/cmd/python/Tools/pynche/pynche.pyw new file mode 100755 index 000000000..6dfc8fed7 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/pynche.pyw @@ -0,0 +1,7 @@ +#! /usr/bin/env python + +"""Run this file under Windows to inhibit the console window. +Run the file pynche.py under Unix or when debugging under Windows. +""" +import Main +Main.main() diff --git a/sys/src/cmd/python/Tools/pynche/webcolors.txt b/sys/src/cmd/python/Tools/pynche/webcolors.txt new file mode 100644 index 000000000..f645c1e61 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/webcolors.txt @@ -0,0 +1,141 @@ +# De-facto NS & MSIE recognized HTML color names +AliceBlue #f0f8ff +AntiqueWhite #faebd7 +Aqua #00ffff +Aquamarine #7fffd4 +Azure #f0ffff +Beige #f5f5dc +Bisque #ffe4c4 +Black #000000 +BlanchedAlmond #ffebcd +Blue #0000ff +BlueViolet #8a2be2 +Brown #a52a2a +BurlyWood #deb887 +CadetBlue #5f9ea0 +Chartreuse #7fff00 +Chocolate #d2691e +Coral #ff7f50 +CornflowerBlue #6495ed +Cornsilk #fff8dc +Crimson #dc143c +Cyan #00ffff +DarkBlue #00008b +DarkCyan #008b8b +DarkGoldenrod #b8860b +DarkGray #a9a9a9 +DarkGreen #006400 +DarkKhaki #bdb76b +DarkMagenta #8b008b +DarkOliveGreen #556b2f +DarkOrange #ff8c00 +DarkOrchid #9932cc +DarkRed #8b0000 +DarkSalmon #e9967a +DarkSeaGreen #8fbc8f +DarkSlateBlue #483d8b +DarkSlateGray #2f4f4f +DarkTurquoise #00ced1 +DarkViolet #9400d3 +DeepPink #ff1493 +DeepSkyBlue #00bfff +DimGray #696969 +DodgerBlue #1e90ff +FireBrick #b22222 +FloralWhite #fffaf0 +ForestGreen #228b22 +Fuchsia #ff00ff +Gainsboro #dcdcdc +GhostWhite #f8f8ff +Gold #ffd700 +Goldenrod #daa520 +Gray #808080 +Green #008000 +GreenYellow #adff2f +Honeydew #f0fff0 +HotPink #ff69b4 +IndianRed #cd5c5c +Indigo #4b0082 +Ivory #fffff0 +Khaki #f0e68c +Lavender #e6e6fa +LavenderBlush #fff0f5 +LawnGreen #7cfc00 +LemonChiffon #fffacd +LightBlue #add8e6 +LightCoral #f08080 +LightCyan #e0ffff +LightGoldenrodYellow #fafad2 +LightGreen #90ee90 +LightGrey #d3d3d3 +LightPink #ffb6c1 +LightSalmon #ffa07a +LightSeaGreen #20b2aa +LightSkyBlue #87cefa +LightSlateGray #778899 +LightSteelBlue #b0c4de +LightYellow #ffffe0 +Lime #00ff00 +LimeGreen #32cd32 +Linen #faf0e6 +Magenta #ff00ff +Maroon #800000 +MediumAquamarine #66cdaa +MediumBlue #0000cd +MediumOrchid #ba55d3 +MediumPurple #9370db +MediumSeaGreen #3cb371 +MediumSlateBlue #7b68ee +MediumSpringGreen #00fa9a +MediumTurquoise #48d1cc +MediumVioletRed #c71585 +MidnightBlue #191970 +MintCream #f5fffa +MistyRose #ffe4e1 +Moccasin #ffe4b5 +NavajoWhite #ffdead +Navy #000080 +OldLace #fdf5e6 +Olive #808000 +OliveDrab #6b8e23 +Orange #ffa500 +OrangeRed #ff4500 +Orchid #da70d6 +PaleGoldenrod #eee8aa +PaleGreen #98fb98 +PaleTurquoise #afeeee +PaleVioletRed #db7093 +PapayaWhip #ffefd5 +PeachPuff #ffdab9 +Peru #cd853f +Pink #ffc0cb +Plum #dda0dd +PowderBlue #b0e0e6 +Purple #800080 +Red #ff0000 +RosyBrown #bc8f8f +RoyalBlue #4169e1 +SaddleBrown #8b4513 +Salmon #fa8072 +SandyBrown #f4a460 +SeaGreen #2e8b57 +Seashell #fff5ee +Sienna #a0522d +Silver #c0c0c0 +SkyBlue #87ceeb +SlateBlue #6a5acd +SlateGray #708090 +Snow #fffafa +SpringGreen #00ff7f +SteelBlue #4682b4 +Tan #d2b48c +Teal #008080 +Thistle #d8bfd8 +Tomato #ff6347 +Turquoise #40e0d0 +Violet #ee82ee +Wheat #f5deb3 +White #ffffff +WhiteSmoke #f5f5f5 +Yellow #ffff00 +YellowGreen #9acd32 diff --git a/sys/src/cmd/python/Tools/pynche/websafe.txt b/sys/src/cmd/python/Tools/pynche/websafe.txt new file mode 100644 index 000000000..70ed51e68 --- /dev/null +++ b/sys/src/cmd/python/Tools/pynche/websafe.txt @@ -0,0 +1,217 @@ +# Websafe RGB values +#000000 +#000033 +#000066 +#000099 +#0000cc +#0000ff +#003300 +#003333 +#003366 +#003399 +#0033cc +#0033ff +#006600 +#006633 +#006666 +#006699 +#0066cc +#0066ff +#009900 +#009933 +#009966 +#009999 +#0099cc +#0099ff +#00cc00 +#00cc33 +#00cc66 +#00cc99 +#00cccc +#00ccff +#00ff00 +#00ff33 +#00ff66 +#00ff99 +#00ffcc +#00ffff +#330000 +#330033 +#330066 +#330099 +#3300cc +#3300ff +#333300 +#333333 +#333366 +#333399 +#3333cc +#3333ff +#336600 +#336633 +#336666 +#336699 +#3366cc +#3366ff +#339900 +#339933 +#339966 +#339999 +#3399cc +#3399ff +#33cc00 +#33cc33 +#33cc66 +#33cc99 +#33cccc +#33ccff +#33ff00 +#33ff33 +#33ff66 +#33ff99 +#33ffcc +#33ffff +#660000 +#660033 +#660066 +#660099 +#6600cc +#6600ff +#663300 +#663333 +#663366 +#663399 +#6633cc +#6633ff +#666600 +#666633 +#666666 +#666699 +#6666cc +#6666ff +#669900 +#669933 +#669966 +#669999 +#6699cc +#6699ff +#66cc00 +#66cc33 +#66cc66 +#66cc99 +#66cccc +#66ccff +#66ff00 +#66ff33 +#66ff66 +#66ff99 +#66ffcc +#66ffff +#990000 +#990033 +#990066 +#990099 +#9900cc +#9900ff +#993300 +#993333 +#993366 +#993399 +#9933cc +#9933ff +#996600 +#996633 +#996666 +#996699 +#9966cc +#9966ff +#999900 +#999933 +#999966 +#999999 +#9999cc +#9999ff +#99cc00 +#99cc33 +#99cc66 +#99cc99 +#99cccc +#99ccff +#99ff00 +#99ff33 +#99ff66 +#99ff99 +#99ffcc +#99ffff +#cc0000 +#cc0033 +#cc0066 +#cc0099 +#cc00cc +#cc00ff +#cc3300 +#cc3333 +#cc3366 +#cc3399 +#cc33cc +#cc33ff +#cc6600 +#cc6633 +#cc6666 +#cc6699 +#cc66cc +#cc66ff +#cc9900 +#cc9933 +#cc9966 +#cc9999 +#cc99cc +#cc99ff +#cccc00 +#cccc33 +#cccc66 +#cccc99 +#cccccc +#ccccff +#ccff00 +#ccff33 +#ccff66 +#ccff99 +#ccffcc +#ccffff +#ff0000 +#ff0033 +#ff0066 +#ff0099 +#ff00cc +#ff00ff +#ff3300 +#ff3333 +#ff3366 +#ff3399 +#ff33cc +#ff33ff +#ff6600 +#ff6633 +#ff6666 +#ff6699 +#ff66cc +#ff66ff +#ff9900 +#ff9933 +#ff9966 +#ff9999 +#ff99cc +#ff99ff +#ffcc00 +#ffcc33 +#ffcc66 +#ffcc99 +#ffcccc +#ffccff +#ffff00 +#ffff33 +#ffff66 +#ffff99 +#ffffcc +#ffffff diff --git a/sys/src/cmd/python/Tools/scripts/README b/sys/src/cmd/python/Tools/scripts/README new file mode 100644 index 000000000..9c7b40e58 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/README @@ -0,0 +1,66 @@ +This directory contains a collection of executable Python scripts that +are useful while building, extending or managing Python. Some (e.g., +dutree or lll) are also generally useful UNIX tools. + +See also the Demo/scripts directory! + +byext.py Print lines/words/chars stats of files by extension +byteyears.py Print product of a file's size and age +checkappend.py Search for multi-argument .append() calls +checkpyc.py Check presence and validity of ".pyc" files +classfix.py Convert old class syntax to new +cleanfuture.py Fix reduntant Python __future__ statements +combinerefs.py A helper for analyzing PYTHONDUMPREFS output. +copytime.py Copy one file's atime and mtime to another +crlf.py Change CRLF line endings to LF (Windows to Unix) +cvsfiles.py Print a list of files that are under CVS +db2pickle.py Dump a database file to a pickle +diff.py Print file diffs in context, unified, or ndiff formats +dutree.py Format du(1) output as a tree sorted by size +eptags.py Create Emacs TAGS file for Python modules +finddiv.py A grep-like tool that looks for division operators. +findlinksto.py Recursively find symbolic links to a given path prefix +findnocoding.py Find source files which need an encoding declaration +fixcid.py Massive identifier substitution on C source files +fixdiv.py Tool to fix division operators. +fixheader.py Add some cpp magic to a C include file +fixnotice.py Fix the copyright notice in source files +fixps.py Fix Python scripts' first line (if #!) +ftpmirror.py FTP mirror script +google.py Open a webbrowser with Google. +gprof2html.py Transform gprof(1) output into useful HTML. +h2py.py Translate #define's into Python assignments +hotshotmain.py Main program to run script under control of hotshot +idle Main program to start IDLE +ifdef.py Remove #if(n)def groups from C sources +lfcr.py Change LF line endings to CRLF (Unix to Windows) +linktree.py Make a copy of a tree with links to original files +lll.py Find and list symbolic links in current directory +logmerge.py Consolidate CVS/RCS logs read from stdin +mailerdaemon.py parse error messages from mailer daemons (Sjoerd&Jack) +md5sum.py Print MD5 checksums of argument files. +methfix.py Fix old method syntax def f(self, (a1, ..., aN)): +mkreal.py Turn a symbolic link into a real file or directory +ndiff.py Intelligent diff between text files (Tim Peters) +nm2def.py Create a template for PC/python_nt.def (Marc Lemburg) +objgraph.py Print object graph from nm output on a library +parseentities.py Utility for parsing HTML entity definitions +pathfix.py Change #!/usr/local/bin/python into something else +pdeps.py Print dependencies between Python modules +pickle2db.py Load a pickle generated by db2pickle.py to a database +pindent.py Indent Python code, giving block-closing comments +ptags.py Create vi tags file for Python modules +pydoc Python documentation browser. +pysource.py Find Python source files +redemo.py Basic regular expression demonstration facility +reindent.py Change .py files to use 4-space indents. +rgrep.py Reverse grep through a file (useful for big logfiles) +setup.py Install all scripts listed here. +suff.py Sort a list of files by suffix +svneol.py Sets svn:eol-style on all files in directory. +texcheck.py Validate Python LaTeX formatting (Raymond Hettinger) +texi2html.py Convert GNU texinfo files into HTML +treesync.py Synchronize source trees (very ideosyncratic) +untabify.py Replace tabs with spaces in argument files +which.py Find a program in $PATH +xxci.py Wrapper for rcsdiff and ci diff --git a/sys/src/cmd/python/Tools/scripts/byext.py b/sys/src/cmd/python/Tools/scripts/byext.py new file mode 100644 index 000000000..09610b00b --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/byext.py @@ -0,0 +1,131 @@ +#! /usr/bin/env python + +"""Show file statistics by extension.""" + +import os +import sys + +class Stats: + + def __init__(self): + self.stats = {} + + def statargs(self, args): + for arg in args: + if os.path.isdir(arg): + self.statdir(arg) + elif os.path.isfile(arg): + self.statfile(arg) + else: + sys.stderr.write("Can't find %s\n" % arg) + self.addstats("<???>", "unknown", 1) + + def statdir(self, dir): + self.addstats("<dir>", "dirs", 1) + try: + names = os.listdir(dir) + except os.error, err: + sys.stderr.write("Can't list %s: %s\n" % (dir, err)) + self.addstats("<dir>", "unlistable", 1) + return + names.sort() + for name in names: + if name.startswith(".#"): + continue # Skip CVS temp files + if name.endswith("~"): + continue# Skip Emacs backup files + full = os.path.join(dir, name) + if os.path.islink(full): + self.addstats("<lnk>", "links", 1) + elif os.path.isdir(full): + self.statdir(full) + else: + self.statfile(full) + + def statfile(self, filename): + head, ext = os.path.splitext(filename) + head, base = os.path.split(filename) + if ext == base: + ext = "" # E.g. .cvsignore is deemed not to have an extension + ext = os.path.normcase(ext) + if not ext: + ext = "<none>" + self.addstats(ext, "files", 1) + try: + f = open(filename, "rb") + except IOError, err: + sys.stderr.write("Can't open %s: %s\n" % (filename, err)) + self.addstats(ext, "unopenable", 1) + return + data = f.read() + f.close() + self.addstats(ext, "bytes", len(data)) + if '\0' in data: + self.addstats(ext, "binary", 1) + return + if not data: + self.addstats(ext, "empty", 1) + #self.addstats(ext, "chars", len(data)) + lines = data.splitlines() + self.addstats(ext, "lines", len(lines)) + del lines + words = data.split() + self.addstats(ext, "words", len(words)) + + def addstats(self, ext, key, n): + d = self.stats.setdefault(ext, {}) + d[key] = d.get(key, 0) + n + + def report(self): + exts = self.stats.keys() + exts.sort() + # Get the column keys + columns = {} + for ext in exts: + columns.update(self.stats[ext]) + cols = columns.keys() + cols.sort() + colwidth = {} + colwidth["ext"] = max([len(ext) for ext in exts]) + minwidth = 6 + self.stats["TOTAL"] = {} + for col in cols: + total = 0 + cw = max(minwidth, len(col)) + for ext in exts: + value = self.stats[ext].get(col) + if value is None: + w = 0 + else: + w = len("%d" % value) + total += value + cw = max(cw, w) + cw = max(cw, len(str(total))) + colwidth[col] = cw + self.stats["TOTAL"][col] = total + exts.append("TOTAL") + for ext in exts: + self.stats[ext]["ext"] = ext + cols.insert(0, "ext") + def printheader(): + for col in cols: + print "%*s" % (colwidth[col], col), + print + printheader() + for ext in exts: + for col in cols: + value = self.stats[ext].get(col, "") + print "%*s" % (colwidth[col], value), + print + printheader() # Another header at the bottom + +def main(): + args = sys.argv[1:] + if not args: + args = [os.curdir] + s = Stats() + s.statargs(args) + s.report() + +if __name__ == "__main__": + main() diff --git a/sys/src/cmd/python/Tools/scripts/byteyears.py b/sys/src/cmd/python/Tools/scripts/byteyears.py new file mode 100755 index 000000000..ba38cafd1 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/byteyears.py @@ -0,0 +1,61 @@ +#! /usr/bin/env python + +# Print the product of age and size of each file, in suitable units. +# +# Usage: byteyears [ -a | -m | -c ] file ... +# +# Options -[amc] select atime, mtime (default) or ctime as age. + +import sys, os, time +from stat import * + +def main(): + + # Use lstat() to stat files if it exists, else stat() + try: + statfunc = os.lstat + except AttributeError: + statfunc = os.stat + + # Parse options + if sys.argv[1] == '-m': + itime = ST_MTIME + del sys.argv[1] + elif sys.argv[1] == '-c': + itime = ST_CTIME + del sys.argv[1] + elif sys.argv[1] == '-a': + itime = ST_CTIME + del sys.argv[1] + else: + itime = ST_MTIME + + secs_per_year = 365.0 * 24.0 * 3600.0 # Scale factor + now = time.time() # Current time, for age computations + status = 0 # Exit status, set to 1 on errors + + # Compute max file name length + maxlen = 1 + for filename in sys.argv[1:]: + maxlen = max(maxlen, len(filename)) + + # Process each argument in turn + for filename in sys.argv[1:]: + try: + st = statfunc(filename) + except os.error, msg: + sys.stderr.write("can't stat %r: %r\n" % (filename, msg)) + status = 1 + st = () + if st: + anytime = st[itime] + size = st[ST_SIZE] + age = now - anytime + byteyears = float(size) * float(age) / secs_per_year + print filename.ljust(maxlen), + print repr(int(byteyears)).rjust(8) + + sys.exit(status) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/checkappend.py b/sys/src/cmd/python/Tools/scripts/checkappend.py new file mode 100755 index 000000000..a8714d936 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/checkappend.py @@ -0,0 +1,167 @@ +#! /usr/bin/env python + +# Released to the public domain, by Tim Peters, 28 February 2000. + +"""checkappend.py -- search for multi-argument .append() calls. + +Usage: specify one or more file or directory paths: + checkappend [-v] file_or_dir [file_or_dir] ... + +Each file_or_dir is checked for multi-argument .append() calls. When +a directory, all .py files in the directory, and recursively in its +subdirectories, are checked. + +Use -v for status msgs. Use -vv for more status msgs. + +In the absence of -v, the only output is pairs of the form + + filename(linenumber): + line containing the suspicious append + +Note that this finds multi-argument append calls regardless of whether +they're attached to list objects. If a module defines a class with an +append method that takes more than one argument, calls to that method +will be listed. + +Note that this will not find multi-argument list.append calls made via a +bound method object. For example, this is not caught: + + somelist = [] + push = somelist.append + push(1, 2, 3) +""" + +__version__ = 1, 0, 0 + +import os +import sys +import getopt +import tokenize + +verbose = 0 + +def errprint(*args): + msg = ' '.join(args) + sys.stderr.write(msg) + sys.stderr.write("\n") + +def main(): + args = sys.argv[1:] + global verbose + try: + opts, args = getopt.getopt(sys.argv[1:], "v") + except getopt.error, msg: + errprint(str(msg) + "\n\n" + __doc__) + return + for opt, optarg in opts: + if opt == '-v': + verbose = verbose + 1 + if not args: + errprint(__doc__) + return + for arg in args: + check(arg) + +def check(file): + if os.path.isdir(file) and not os.path.islink(file): + if verbose: + print "%r: listing directory" % (file,) + names = os.listdir(file) + for name in names: + fullname = os.path.join(file, name) + if ((os.path.isdir(fullname) and + not os.path.islink(fullname)) + or os.path.normcase(name[-3:]) == ".py"): + check(fullname) + return + + try: + f = open(file) + except IOError, msg: + errprint("%r: I/O Error: %s" % (file, msg)) + return + + if verbose > 1: + print "checking %r ..." % (file,) + + ok = AppendChecker(file, f).run() + if verbose and ok: + print "%r: Clean bill of health." % (file,) + +[FIND_DOT, + FIND_APPEND, + FIND_LPAREN, + FIND_COMMA, + FIND_STMT] = range(5) + +class AppendChecker: + def __init__(self, fname, file): + self.fname = fname + self.file = file + self.state = FIND_DOT + self.nerrors = 0 + + def run(self): + try: + tokenize.tokenize(self.file.readline, self.tokeneater) + except tokenize.TokenError, msg: + errprint("%r: Token Error: %s" % (self.fname, msg)) + self.nerrors = self.nerrors + 1 + return self.nerrors == 0 + + def tokeneater(self, type, token, start, end, line, + NEWLINE=tokenize.NEWLINE, + JUNK=(tokenize.COMMENT, tokenize.NL), + OP=tokenize.OP, + NAME=tokenize.NAME): + + state = self.state + + if type in JUNK: + pass + + elif state is FIND_DOT: + if type is OP and token == ".": + state = FIND_APPEND + + elif state is FIND_APPEND: + if type is NAME and token == "append": + self.line = line + self.lineno = start[0] + state = FIND_LPAREN + else: + state = FIND_DOT + + elif state is FIND_LPAREN: + if type is OP and token == "(": + self.level = 1 + state = FIND_COMMA + else: + state = FIND_DOT + + elif state is FIND_COMMA: + if type is OP: + if token in ("(", "{", "["): + self.level = self.level + 1 + elif token in (")", "}", "]"): + self.level = self.level - 1 + if self.level == 0: + state = FIND_DOT + elif token == "," and self.level == 1: + self.nerrors = self.nerrors + 1 + print "%s(%d):\n%s" % (self.fname, self.lineno, + self.line) + # don't gripe about this stmt again + state = FIND_STMT + + elif state is FIND_STMT: + if type is NEWLINE: + state = FIND_DOT + + else: + raise SystemError("unknown internal state '%r'" % (state,)) + + self.state = state + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/checkpyc.py b/sys/src/cmd/python/Tools/scripts/checkpyc.py new file mode 100755 index 000000000..8af76726a --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/checkpyc.py @@ -0,0 +1,66 @@ +#! /usr/bin/env python +# Check that all ".pyc" files exist and are up-to-date +# Uses module 'os' + +import sys +import os +from stat import ST_MTIME +import imp + +def main(): + silent = 0 + verbose = 0 + if sys.argv[1:]: + if sys.argv[1] == '-v': + verbose = 1 + elif sys.argv[1] == '-s': + silent = 1 + MAGIC = imp.get_magic() + if not silent: + print 'Using MAGIC word', repr(MAGIC) + for dirname in sys.path: + try: + names = os.listdir(dirname) + except os.error: + print 'Cannot list directory', repr(dirname) + continue + if not silent: + print 'Checking ', repr(dirname), '...' + names.sort() + for name in names: + if name[-3:] == '.py': + name = os.path.join(dirname, name) + try: + st = os.stat(name) + except os.error: + print 'Cannot stat', repr(name) + continue + if verbose: + print 'Check', repr(name), '...' + name_c = name + 'c' + try: + f = open(name_c, 'r') + except IOError: + print 'Cannot open', repr(name_c) + continue + magic_str = f.read(4) + mtime_str = f.read(4) + f.close() + if magic_str <> MAGIC: + print 'Bad MAGIC word in ".pyc" file', + print repr(name_c) + continue + mtime = get_long(mtime_str) + if mtime == 0 or mtime == -1: + print 'Bad ".pyc" file', repr(name_c) + elif mtime <> st[ST_MTIME]: + print 'Out-of-date ".pyc" file', + print repr(name_c) + +def get_long(s): + if len(s) <> 4: + return -1 + return ord(s[0]) + (ord(s[1])<<8) + (ord(s[2])<<16) + (ord(s[3])<<24) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/classfix.py b/sys/src/cmd/python/Tools/scripts/classfix.py new file mode 100755 index 000000000..d30700fbf --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/classfix.py @@ -0,0 +1,190 @@ +#! /usr/bin/env python + +# This script is obsolete -- it is kept for historical purposes only. +# +# Fix Python source files to use the new class definition syntax, i.e., +# the syntax used in Python versions before 0.9.8: +# class C() = base(), base(), ...: ... +# is changed to the current syntax: +# class C(base, base, ...): ... +# +# The script uses heuristics to find class definitions that usually +# work but occasionally can fail; carefully check the output! +# +# Command line arguments are files or directories to be processed. +# Directories are searched recursively for files whose name looks +# like a python module. +# Symbolic links are always ignored (except as explicit directory +# arguments). Of course, the original file is kept as a back-up +# (with a "~" attached to its name). +# +# Changes made are reported to stdout in a diff-like format. +# +# Undoubtedly you can do this using find and sed or perl, but this is +# a nice example of Python code that recurses down a directory tree +# and uses regular expressions. Also note several subtleties like +# preserving the file's mode and avoiding to even write a temp file +# when no changes are needed for a file. +# +# NB: by changing only the function fixline() you can turn this +# into a program for a different change to Python programs... + +import sys +import re +import os +from stat import * + +err = sys.stderr.write +dbg = err +rep = sys.stdout.write + +def main(): + bad = 0 + if not sys.argv[1:]: # No arguments + err('usage: ' + sys.argv[0] + ' file-or-directory ...\n') + sys.exit(2) + for arg in sys.argv[1:]: + if os.path.isdir(arg): + if recursedown(arg): bad = 1 + elif os.path.islink(arg): + err(arg + ': will not process symbolic links\n') + bad = 1 + else: + if fix(arg): bad = 1 + sys.exit(bad) + +ispythonprog = re.compile('^[a-zA-Z0-9_]+\.py$') +def ispython(name): + return ispythonprog.match(name) >= 0 + +def recursedown(dirname): + dbg('recursedown(%r)\n' % (dirname,)) + bad = 0 + try: + names = os.listdir(dirname) + except os.error, msg: + err('%s: cannot list directory: %r\n' % (dirname, msg)) + return 1 + names.sort() + subdirs = [] + for name in names: + if name in (os.curdir, os.pardir): continue + fullname = os.path.join(dirname, name) + if os.path.islink(fullname): pass + elif os.path.isdir(fullname): + subdirs.append(fullname) + elif ispython(name): + if fix(fullname): bad = 1 + for fullname in subdirs: + if recursedown(fullname): bad = 1 + return bad + +def fix(filename): +## dbg('fix(%r)\n' % (filename,)) + try: + f = open(filename, 'r') + except IOError, msg: + err('%s: cannot open: %r\n' % (filename, msg)) + return 1 + head, tail = os.path.split(filename) + tempname = os.path.join(head, '@' + tail) + g = None + # If we find a match, we rewind the file and start over but + # now copy everything to a temp file. + lineno = 0 + while 1: + line = f.readline() + if not line: break + lineno = lineno + 1 + while line[-2:] == '\\\n': + nextline = f.readline() + if not nextline: break + line = line + nextline + lineno = lineno + 1 + newline = fixline(line) + if newline != line: + if g is None: + try: + g = open(tempname, 'w') + except IOError, msg: + f.close() + err('%s: cannot create: %r\n' % (tempname, msg)) + return 1 + f.seek(0) + lineno = 0 + rep(filename + ':\n') + continue # restart from the beginning + rep(repr(lineno) + '\n') + rep('< ' + line) + rep('> ' + newline) + if g is not None: + g.write(newline) + + # End of file + f.close() + if not g: return 0 # No changes + + # Finishing touch -- move files + + # First copy the file's mode to the temp file + try: + statbuf = os.stat(filename) + os.chmod(tempname, statbuf[ST_MODE] & 07777) + except os.error, msg: + err('%s: warning: chmod failed (%r)\n' % (tempname, msg)) + # Then make a backup of the original file as filename~ + try: + os.rename(filename, filename + '~') + except os.error, msg: + err('%s: warning: backup failed (%r)\n' % (filename, msg)) + # Now move the temp file to the original file + try: + os.rename(tempname, filename) + except os.error, msg: + err('%s: rename failed (%r)\n' % (filename, msg)) + return 1 + # Return succes + return 0 + +# This expression doesn't catch *all* class definition headers, +# but it's pretty darn close. +classexpr = '^([ \t]*class +[a-zA-Z0-9_]+) *( *) *((=.*)?):' +classprog = re.compile(classexpr) + +# Expressions for finding base class expressions. +baseexpr = '^ *(.*) *( *) *$' +baseprog = re.compile(baseexpr) + +def fixline(line): + if classprog.match(line) < 0: # No 'class' keyword -- no change + return line + + (a0, b0), (a1, b1), (a2, b2) = classprog.regs[:3] + # a0, b0 = Whole match (up to ':') + # a1, b1 = First subexpression (up to classname) + # a2, b2 = Second subexpression (=.*) + head = line[:b1] + tail = line[b0:] # Unmatched rest of line + + if a2 == b2: # No base classes -- easy case + return head + ':' + tail + + # Get rid of leading '=' + basepart = line[a2+1:b2] + + # Extract list of base expressions + bases = basepart.split(',') + + # Strip trailing '()' from each base expression + for i in range(len(bases)): + if baseprog.match(bases[i]) >= 0: + x1, y1 = baseprog.regs[1] + bases[i] = bases[i][x1:y1] + + # Join the bases back again and build the new line + basepart = ', '.join(bases) + + return head + '(' + basepart + '):' + tail + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/cleanfuture.py b/sys/src/cmd/python/Tools/scripts/cleanfuture.py new file mode 100644 index 000000000..3f2da3a98 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/cleanfuture.py @@ -0,0 +1,276 @@ +#! /usr/bin/env python + +"""cleanfuture [-d][-r][-v] path ... + +-d Dry run. Analyze, but don't make any changes to, files. +-r Recurse. Search for all .py files in subdirectories too. +-v Verbose. Print informative msgs. + +Search Python (.py) files for future statements, and remove the features +from such statements that are already mandatory in the version of Python +you're using. + +Pass one or more file and/or directory paths. When a directory path, all +.py files within the directory will be examined, and, if the -r option is +given, likewise recursively for subdirectories. + +Overwrites files in place, renaming the originals with a .bak extension. If +cleanfuture finds nothing to change, the file is left alone. If cleanfuture +does change a file, the changed file is a fixed-point (i.e., running +cleanfuture on the resulting .py file won't change it again, at least not +until you try it again with a later Python release). + +Limitations: You can do these things, but this tool won't help you then: + ++ A future statement cannot be mixed with any other statement on the same + physical line (separated by semicolon). + ++ A future statement cannot contain an "as" clause. + +Example: Assuming you're using Python 2.2, if a file containing + +from __future__ import nested_scopes, generators + +is analyzed by cleanfuture, the line is rewritten to + +from __future__ import generators + +because nested_scopes is no longer optional in 2.2 but generators is. +""" + +import __future__ +import tokenize +import os +import sys + +dryrun = 0 +recurse = 0 +verbose = 0 + +def errprint(*args): + strings = map(str, args) + msg = ' '.join(strings) + if msg[-1:] != '\n': + msg += '\n' + sys.stderr.write(msg) + +def main(): + import getopt + global verbose, recurse, dryrun + try: + opts, args = getopt.getopt(sys.argv[1:], "drv") + except getopt.error, msg: + errprint(msg) + return + for o, a in opts: + if o == '-d': + dryrun += 1 + elif o == '-r': + recurse += 1 + elif o == '-v': + verbose += 1 + if not args: + errprint("Usage:", __doc__) + return + for arg in args: + check(arg) + +def check(file): + if os.path.isdir(file) and not os.path.islink(file): + if verbose: + print "listing directory", file + names = os.listdir(file) + for name in names: + fullname = os.path.join(file, name) + if ((recurse and os.path.isdir(fullname) and + not os.path.islink(fullname)) + or name.lower().endswith(".py")): + check(fullname) + return + + if verbose: + print "checking", file, "...", + try: + f = open(file) + except IOError, msg: + errprint("%r: I/O Error: %s" % (file, str(msg))) + return + + ff = FutureFinder(f, file) + changed = ff.run() + if changed: + ff.gettherest() + f.close() + if changed: + if verbose: + print "changed." + if dryrun: + print "But this is a dry run, so leaving it alone." + for s, e, line in changed: + print "%r lines %d-%d" % (file, s+1, e+1) + for i in range(s, e+1): + print ff.lines[i], + if line is None: + print "-- deleted" + else: + print "-- change to:" + print line, + if not dryrun: + bak = file + ".bak" + if os.path.exists(bak): + os.remove(bak) + os.rename(file, bak) + if verbose: + print "renamed", file, "to", bak + g = open(file, "w") + ff.write(g) + g.close() + if verbose: + print "wrote new", file + else: + if verbose: + print "unchanged." + +class FutureFinder: + + def __init__(self, f, fname): + self.f = f + self.fname = fname + self.ateof = 0 + self.lines = [] # raw file lines + + # List of (start_index, end_index, new_line) triples. + self.changed = [] + + # Line-getter for tokenize. + def getline(self): + if self.ateof: + return "" + line = self.f.readline() + if line == "": + self.ateof = 1 + else: + self.lines.append(line) + return line + + def run(self): + STRING = tokenize.STRING + NL = tokenize.NL + NEWLINE = tokenize.NEWLINE + COMMENT = tokenize.COMMENT + NAME = tokenize.NAME + OP = tokenize.OP + + changed = self.changed + get = tokenize.generate_tokens(self.getline).next + type, token, (srow, scol), (erow, ecol), line = get() + + # Chew up initial comments and blank lines (if any). + while type in (COMMENT, NL, NEWLINE): + type, token, (srow, scol), (erow, ecol), line = get() + + # Chew up docstring (if any -- and it may be implicitly catenated!). + while type is STRING: + type, token, (srow, scol), (erow, ecol), line = get() + + # Analyze the future stmts. + while 1: + # Chew up comments and blank lines (if any). + while type in (COMMENT, NL, NEWLINE): + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is NAME and token == "from"): + break + startline = srow - 1 # tokenize is one-based + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is NAME and token == "__future__"): + break + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is NAME and token == "import"): + break + type, token, (srow, scol), (erow, ecol), line = get() + + # Get the list of features. + features = [] + while type is NAME: + features.append(token) + type, token, (srow, scol), (erow, ecol), line = get() + + if not (type is OP and token == ','): + break + type, token, (srow, scol), (erow, ecol), line = get() + + # A trailing comment? + comment = None + if type is COMMENT: + comment = token + type, token, (srow, scol), (erow, ecol), line = get() + + if type is not NEWLINE: + errprint("Skipping file %r; can't parse line %d:\n%s" % + (self.fname, srow, line)) + return [] + + endline = srow - 1 + + # Check for obsolete features. + okfeatures = [] + for f in features: + object = getattr(__future__, f, None) + if object is None: + # A feature we don't know about yet -- leave it in. + # They'll get a compile-time error when they compile + # this program, but that's not our job to sort out. + okfeatures.append(f) + else: + released = object.getMandatoryRelease() + if released is None or released <= sys.version_info: + # Withdrawn or obsolete. + pass + else: + okfeatures.append(f) + + # Rewrite the line if at least one future-feature is obsolete. + if len(okfeatures) < len(features): + if len(okfeatures) == 0: + line = None + else: + line = "from __future__ import " + line += ', '.join(okfeatures) + if comment is not None: + line += ' ' + comment + line += '\n' + changed.append((startline, endline, line)) + + # Loop back for more future statements. + + return changed + + def gettherest(self): + if self.ateof: + self.therest = '' + else: + self.therest = self.f.read() + + def write(self, f): + changed = self.changed + assert changed + # Prevent calling this again. + self.changed = [] + # Apply changes in reverse order. + changed.reverse() + for s, e, line in changed: + if line is None: + # pure deletion + del self.lines[s:e+1] + else: + self.lines[s:e+1] = [line] + f.writelines(self.lines) + # Copy over the remainder of the file. + if self.therest: + f.write(self.therest) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/combinerefs.py b/sys/src/cmd/python/Tools/scripts/combinerefs.py new file mode 100644 index 000000000..f04b29f0a --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/combinerefs.py @@ -0,0 +1,127 @@ +#! /usr/bin/env python + +""" +combinerefs path + +A helper for analyzing PYTHONDUMPREFS output. + +When the PYTHONDUMPREFS envar is set in a debug build, at Python shutdown +time Py_Finalize() prints the list of all live objects twice: first it +prints the repr() of each object while the interpreter is still fully intact. +After cleaning up everything it can, it prints all remaining live objects +again, but the second time just prints their addresses, refcounts, and type +names (because the interpreter has been torn down, calling repr methods at +this point can get into infinite loops or blow up). + +Save all this output into a file, then run this script passing the path to +that file. The script finds both output chunks, combines them, then prints +a line of output for each object still alive at the end: + + address refcnt typename repr + +address is the address of the object, in whatever format the platform C +produces for a %p format code. + +refcnt is of the form + + "[" ref "]" + +when the object's refcount is the same in both PYTHONDUMPREFS output blocks, +or + + "[" ref_before "->" ref_after "]" + +if the refcount changed. + +typename is object->ob_type->tp_name, extracted from the second PYTHONDUMPREFS +output block. + +repr is repr(object), extracted from the first PYTHONDUMPREFS output block. +CAUTION: If object is a container type, it may not actually contain all the +objects shown in the repr: the repr was captured from the first output block, +and some of the containees may have been released since then. For example, +it's common for the line showing the dict of interned strings to display +strings that no longer exist at the end of Py_Finalize; this can be recognized +(albeit painfully) because such containees don't have a line of their own. + +The objects are listed in allocation order, with most-recently allocated +printed first, and the first object allocated printed last. + + +Simple examples: + + 00857060 [14] str '__len__' + +The str object '__len__' is alive at shutdown time, and both PYTHONDUMPREFS +output blocks said there were 14 references to it. This is probably due to +C modules that intern the string "__len__" and keep a reference to it in a +file static. + + 00857038 [46->5] tuple () + +46-5 = 41 references to the empty tuple were removed by the cleanup actions +between the times PYTHONDUMPREFS produced output. + + 00858028 [1025->1456] str '<dummy key>' + +The string '<dummy key>', which is used in dictobject.c to overwrite a real +key that gets deleted, grew several hundred references during cleanup. It +suggests that stuff did get removed from dicts by cleanup, but that the dicts +themselves are staying alive for some reason. """ + +import re +import sys + +# Generate lines from fileiter. If whilematch is true, continue reading +# while the regexp object pat matches line. If whilematch is false, lines +# are read so long as pat doesn't match them. In any case, the first line +# that doesn't match pat (when whilematch is true), or that does match pat +# (when whilematch is false), is lost, and fileiter will resume at the line +# following it. +def read(fileiter, pat, whilematch): + for line in fileiter: + if bool(pat.match(line)) == whilematch: + yield line + else: + break + +def combine(fname): + f = file(fname) + fi = iter(f) + + for line in read(fi, re.compile(r'^Remaining objects:$'), False): + pass + + crack = re.compile(r'([a-zA-Z\d]+) \[(\d+)\] (.*)') + addr2rc = {} + addr2guts = {} + before = 0 + for line in read(fi, re.compile(r'^Remaining object addresses:$'), False): + m = crack.match(line) + if m: + addr, addr2rc[addr], addr2guts[addr] = m.groups() + before += 1 + else: + print '??? skipped:', line + + after = 0 + for line in read(fi, crack, True): + after += 1 + m = crack.match(line) + assert m + addr, rc, guts = m.groups() # guts is type name here + if addr not in addr2rc: + print '??? new object created while tearing down:', line.rstrip() + continue + print addr, + if rc == addr2rc[addr]: + print '[%s]' % rc, + else: + print '[%s->%s]' % (addr2rc[addr], rc), + print guts, addr2guts[addr] + + f.close() + print "%d objects before, %d after" % (before, after) + +if __name__ == '__main__': + combine(sys.argv[1]) diff --git a/sys/src/cmd/python/Tools/scripts/copytime.py b/sys/src/cmd/python/Tools/scripts/copytime.py new file mode 100755 index 000000000..209c4924d --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/copytime.py @@ -0,0 +1,26 @@ +#! /usr/bin/env python + +# Copy one file's atime and mtime to another + +import sys +import os +from stat import ST_ATIME, ST_MTIME # Really constants 7 and 8 + +def main(): + if len(sys.argv) <> 3: + sys.stderr.write('usage: copytime source destination\n') + sys.exit(2) + file1, file2 = sys.argv[1], sys.argv[2] + try: + stat1 = os.stat(file1) + except os.error: + sys.stderr.write(file1 + ': cannot stat\n') + sys.exit(1) + try: + os.utime(file2, (stat1[ST_ATIME], stat1[ST_MTIME])) + except os.error: + sys.stderr.write(file2 + ': cannot change time\n') + sys.exit(2) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/crlf.py b/sys/src/cmd/python/Tools/scripts/crlf.py new file mode 100755 index 000000000..a975cb292 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/crlf.py @@ -0,0 +1,23 @@ +#! /usr/bin/env python +"Replace CRLF with LF in argument files. Print names of changed files." + +import sys, os + +def main(): + for filename in sys.argv[1:]: + if os.path.isdir(filename): + print filename, "Directory!" + continue + data = open(filename, "rb").read() + if '\0' in data: + print filename, "Binary!" + continue + newdata = data.replace("\r\n", "\n") + if newdata != data: + print filename + f = open(filename, "wb") + f.write(newdata) + f.close() + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/cvsfiles.py b/sys/src/cmd/python/Tools/scripts/cvsfiles.py new file mode 100755 index 000000000..53b42943c --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/cvsfiles.py @@ -0,0 +1,72 @@ +#! /usr/bin/env python + +"""Print a list of files that are mentioned in CVS directories. + +Usage: cvsfiles.py [-n file] [directory] ... + +If the '-n file' option is given, only files under CVS that are newer +than the given file are printed; by default, all files under CVS are +printed. As a special case, if a file does not exist, it is always +printed. +""" + +import os +import sys +import stat +import getopt + +cutofftime = 0 + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "n:") + except getopt.error, msg: + print msg + print __doc__, + return 1 + global cutofftime + newerfile = None + for o, a in opts: + if o == '-n': + cutofftime = getmtime(a) + if args: + for arg in args: + process(arg) + else: + process(".") + +def process(dir): + cvsdir = 0 + subdirs = [] + names = os.listdir(dir) + for name in names: + fullname = os.path.join(dir, name) + if name == "CVS": + cvsdir = fullname + else: + if os.path.isdir(fullname): + if not os.path.islink(fullname): + subdirs.append(fullname) + if cvsdir: + entries = os.path.join(cvsdir, "Entries") + for e in open(entries).readlines(): + words = e.split('/') + if words[0] == '' and words[1:]: + name = words[1] + fullname = os.path.join(dir, name) + if cutofftime and getmtime(fullname) <= cutofftime: + pass + else: + print fullname + for sub in subdirs: + process(sub) + +def getmtime(filename): + try: + st = os.stat(filename) + except os.error: + return 0 + return st[stat.ST_MTIME] + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/db2pickle.py b/sys/src/cmd/python/Tools/scripts/db2pickle.py new file mode 100644 index 000000000..795011b62 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/db2pickle.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python + +""" +Synopsis: %(prog)s [-h|-g|-b|-r|-a] dbfile [ picklefile ] + +Convert the database file given on the command line to a pickle +representation. The optional flags indicate the type of the database: + + -a - open using anydbm + -b - open as bsddb btree file + -d - open as dbm file + -g - open as gdbm file + -h - open as bsddb hash file + -r - open as bsddb recno file + +The default is hash. If a pickle file is named it is opened for write +access (deleting any existing data). If no pickle file is named, the pickle +output is written to standard output. + +""" + +import getopt +try: + import bsddb +except ImportError: + bsddb = None +try: + import dbm +except ImportError: + dbm = None +try: + import gdbm +except ImportError: + gdbm = None +try: + import anydbm +except ImportError: + anydbm = None +import sys +try: + import cPickle as pickle +except ImportError: + import pickle + +prog = sys.argv[0] + +def usage(): + sys.stderr.write(__doc__ % globals()) + +def main(args): + try: + opts, args = getopt.getopt(args, "hbrdag", + ["hash", "btree", "recno", "dbm", + "gdbm", "anydbm"]) + except getopt.error: + usage() + return 1 + + if len(args) == 0 or len(args) > 2: + usage() + return 1 + elif len(args) == 1: + dbfile = args[0] + pfile = sys.stdout + else: + dbfile = args[0] + try: + pfile = open(args[1], 'wb') + except IOError: + sys.stderr.write("Unable to open %s\n" % args[1]) + return 1 + + dbopen = None + for opt, arg in opts: + if opt in ("-h", "--hash"): + try: + dbopen = bsddb.hashopen + except AttributeError: + sys.stderr.write("bsddb module unavailable.\n") + return 1 + elif opt in ("-b", "--btree"): + try: + dbopen = bsddb.btopen + except AttributeError: + sys.stderr.write("bsddb module unavailable.\n") + return 1 + elif opt in ("-r", "--recno"): + try: + dbopen = bsddb.rnopen + except AttributeError: + sys.stderr.write("bsddb module unavailable.\n") + return 1 + elif opt in ("-a", "--anydbm"): + try: + dbopen = anydbm.open + except AttributeError: + sys.stderr.write("anydbm module unavailable.\n") + return 1 + elif opt in ("-g", "--gdbm"): + try: + dbopen = gdbm.open + except AttributeError: + sys.stderr.write("gdbm module unavailable.\n") + return 1 + elif opt in ("-d", "--dbm"): + try: + dbopen = dbm.open + except AttributeError: + sys.stderr.write("dbm module unavailable.\n") + return 1 + if dbopen is None: + if bsddb is None: + sys.stderr.write("bsddb module unavailable - ") + sys.stderr.write("must specify dbtype.\n") + return 1 + else: + dbopen = bsddb.hashopen + + try: + db = dbopen(dbfile, 'r') + except bsddb.error: + sys.stderr.write("Unable to open %s. " % dbfile) + sys.stderr.write("Check for format or version mismatch.\n") + return 1 + + for k in db.keys(): + pickle.dump((k, db[k]), pfile, 1==1) + + db.close() + pfile.close() + + return 0 + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/sys/src/cmd/python/Tools/scripts/diff.py b/sys/src/cmd/python/Tools/scripts/diff.py new file mode 100644 index 000000000..52dcab1ff --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/diff.py @@ -0,0 +1,49 @@ +""" Command line interface to difflib.py providing diffs in four formats: + +* ndiff: lists every line and highlights interline changes. +* context: highlights clusters of changes in a before/after format. +* unified: highlights clusters of changes in an inline format. +* html: generates side by side comparison with change highlights. + +""" + +import sys, os, time, difflib, optparse + +def main(): + + usage = "usage: %prog [options] fromfile tofile" + parser = optparse.OptionParser(usage) + parser.add_option("-c", action="store_true", default=False, help='Produce a context format diff (default)') + parser.add_option("-u", action="store_true", default=False, help='Produce a unified format diff') + parser.add_option("-m", action="store_true", default=False, help='Produce HTML side by side diff (can use -c and -l in conjunction)') + parser.add_option("-n", action="store_true", default=False, help='Produce a ndiff format diff') + parser.add_option("-l", "--lines", type="int", default=3, help='Set number of context lines (default 3)') + (options, args) = parser.parse_args() + + if len(args) == 0: + parser.print_help() + sys.exit(1) + if len(args) != 2: + parser.error("need to specify both a fromfile and tofile") + + n = options.lines + fromfile, tofile = args + + fromdate = time.ctime(os.stat(fromfile).st_mtime) + todate = time.ctime(os.stat(tofile).st_mtime) + fromlines = open(fromfile, 'U').readlines() + tolines = open(tofile, 'U').readlines() + + if options.u: + diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n) + elif options.n: + diff = difflib.ndiff(fromlines, tolines) + elif options.m: + diff = difflib.HtmlDiff().make_file(fromlines,tolines,fromfile,tofile,context=options.c,numlines=n) + else: + diff = difflib.context_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n) + + sys.stdout.writelines(diff) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/dutree.doc b/sys/src/cmd/python/Tools/scripts/dutree.doc new file mode 100644 index 000000000..2a094261b --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/dutree.doc @@ -0,0 +1,54 @@ +Path: cwi.nl!sun4nl!mcsun!uunet!cs.utexas.edu!convex!usenet +From: tchrist@convex.COM (Tom Christiansen) +Newsgroups: comp.lang.perl +Subject: Re: The problems of Perl (Re: Question (silly?)) +Message-ID: <1992Jan17.053115.4220@convex.com> +Date: 17 Jan 92 05:31:15 GMT +References: <17458@ector.cs.purdue.edu> <1992Jan16.165347.25583@cherokee.uswest.com> <=#Hues+4@cs.psu.edu> +Sender: usenet@convex.com (news access account) +Reply-To: tchrist@convex.COM (Tom Christiansen) +Organization: CONVEX Realtime Development, Colorado Springs, CO +Lines: 83 +Nntp-Posting-Host: pixel.convex.com + +From the keyboard of flee@cs.psu.edu (Felix Lee): +:And Perl is definitely awkward with data types. I haven't yet found a +:pleasant way of shoving non-trivial data types into Perl's grammar. + +Yes, it's pretty aweful at that, alright. Sometimes I write perl programs +that need them, and sometimes it just takes a little creativity. But +sometimes it's not worth it. I actually wrote a C program the other day +(gasp) because I didn't want to deal with a game matrix with six links per node. + +:Here's a very simple problem that's tricky to express in Perl: process +:the output of "du" to produce output that's indented to reflect the +:tree structure, and with each subtree sorted by size. Something like: +: 434 /etc +: | 344 . +: | 50 install +: | 35 uucp +: | 3 nserve +: | | 2 . +: | | 1 auth.info +: | 1 sm +: | 1 sm.bak + +At first I thought I could just keep one local list around +at once, but this seems inherently recursive. Which means +I need an real recursive data structure. Maybe you could +do it with one of the %assoc arrays Larry uses in the begat +programs, but I broke down and got dirty. I think the hardest +part was matching Felix's desired output exactly. It's not +blazingly fast: I should probably inline the &childof routine, +but it *was* faster to write than I could have written the +equivalent C program. + + +--tom + +-- +"GUIs normally make it simple to accomplish simple actions and impossible +to accomplish complex actions." --Doug Gwyn (22/Jun/91 in comp.unix.wizards) + + Tom Christiansen tchrist@convex.com convex!tchrist + diff --git a/sys/src/cmd/python/Tools/scripts/dutree.py b/sys/src/cmd/python/Tools/scripts/dutree.py new file mode 100755 index 000000000..d938ae153 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/dutree.py @@ -0,0 +1,60 @@ +#! /usr/bin/env python +# Format du output in a tree shape + +import os, sys, errno + +def main(): + p = os.popen('du ' + ' '.join(sys.argv[1:]), 'r') + total, d = None, {} + for line in p.readlines(): + i = 0 + while line[i] in '0123456789': i = i+1 + size = eval(line[:i]) + while line[i] in ' \t': i = i+1 + filename = line[i:-1] + comps = filename.split('/') + if comps[0] == '': comps[0] = '/' + if comps[len(comps)-1] == '': del comps[len(comps)-1] + total, d = store(size, comps, total, d) + try: + display(total, d) + except IOError, e: + if e.errno != errno.EPIPE: + raise + +def store(size, comps, total, d): + if comps == []: + return size, d + if not d.has_key(comps[0]): + d[comps[0]] = None, {} + t1, d1 = d[comps[0]] + d[comps[0]] = store(size, comps[1:], t1, d1) + return total, d + +def display(total, d): + show(total, d, '') + +def show(total, d, prefix): + if not d: return + list = [] + sum = 0 + for key in d.keys(): + tsub, dsub = d[key] + list.append((tsub, key)) + if tsub is not None: sum = sum + tsub +## if sum < total: +## list.append((total - sum, os.curdir)) + list.sort() + list.reverse() + width = len(repr(list[0][0])) + for tsub, key in list: + if tsub is None: + psub = prefix + else: + print prefix + repr(tsub).rjust(width) + ' ' + key + psub = prefix + ' '*(width-1) + '|' + ' '*(len(key)+1) + if d.has_key(key): + show(tsub, d[key][1], psub) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/eptags.py b/sys/src/cmd/python/Tools/scripts/eptags.py new file mode 100755 index 000000000..8d35dfb31 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/eptags.py @@ -0,0 +1,56 @@ +#! /usr/bin/env python +"""Create a TAGS file for Python programs, usable with GNU Emacs. + +usage: eptags pyfiles... + +The output TAGS file is usable with Emacs version 18, 19, 20. +Tagged are: + - functions (even inside other defs or classes) + - classes + +eptags warns about files it cannot open. +eptags will not give warnings about duplicate tags. + +BUGS: + Because of tag duplication (methods with the same name in different + classes), TAGS files are not very useful for most object-oriented + python projects. +""" +import sys,re + +expr = r'^[ \t]*(def|class)[ \t]+([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*[:\(]' +matcher = re.compile(expr) + +def treat_file(filename, outfp): + """Append tags found in file named 'filename' to the open file 'outfp'""" + try: + fp = open(filename, 'r') + except: + sys.stderr.write('Cannot open %s\n'%filename) + return + charno = 0 + lineno = 0 + tags = [] + size = 0 + while 1: + line = fp.readline() + if not line: + break + lineno = lineno + 1 + m = matcher.search(line) + if m: + tag = m.group(0) + '\177%d,%d\n' % (lineno, charno) + tags.append(tag) + size = size + len(tag) + charno = charno + len(line) + outfp.write('\f\n%s,%d\n' % (filename,size)) + for tag in tags: + outfp.write(tag) + +def main(): + outfp = open('TAGS', 'w') + for filename in sys.argv[1:]: + treat_file(filename, outfp) + +if __name__=="__main__": + main() diff --git a/sys/src/cmd/python/Tools/scripts/finddiv.py b/sys/src/cmd/python/Tools/scripts/finddiv.py new file mode 100755 index 000000000..97f63316c --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/finddiv.py @@ -0,0 +1,89 @@ +#! /usr/bin/env python + +"""finddiv - a grep-like tool that looks for division operators. + +Usage: finddiv [-l] file_or_directory ... + +For directory arguments, all files in the directory whose name ends in +.py are processed, and subdirectories are processed recursively. + +This actually tokenizes the files to avoid false hits in comments or +strings literals. + +By default, this prints all lines containing a / or /= operator, in +grep -n style. With the -l option specified, it prints the filename +of files that contain at least one / or /= operator. +""" + +import os +import sys +import getopt +import tokenize + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "lh") + except getopt.error, msg: + usage(msg) + return 2 + if not args: + usage("at least one file argument is required") + return 2 + listnames = 0 + for o, a in opts: + if o == "-h": + print __doc__ + return + if o == "-l": + listnames = 1 + exit = None + for filename in args: + x = process(filename, listnames) + exit = exit or x + return exit + +def usage(msg): + sys.stderr.write("%s: %s\n" % (sys.argv[0], msg)) + sys.stderr.write("Usage: %s [-l] file ...\n" % sys.argv[0]) + sys.stderr.write("Try `%s -h' for more information.\n" % sys.argv[0]) + +def process(filename, listnames): + if os.path.isdir(filename): + return processdir(filename, listnames) + try: + fp = open(filename) + except IOError, msg: + sys.stderr.write("Can't open: %s\n" % msg) + return 1 + g = tokenize.generate_tokens(fp.readline) + lastrow = None + for type, token, (row, col), end, line in g: + if token in ("/", "/="): + if listnames: + print filename + break + if row != lastrow: + lastrow = row + print "%s:%d:%s" % (filename, row, line), + fp.close() + +def processdir(dir, listnames): + try: + names = os.listdir(dir) + except os.error, msg: + sys.stderr.write("Can't list directory: %s\n" % dir) + return 1 + files = [] + for name in names: + fn = os.path.join(dir, name) + if os.path.normcase(fn).endswith(".py") or os.path.isdir(fn): + files.append(fn) + files.sort(lambda a, b: cmp(os.path.normcase(a), os.path.normcase(b))) + exit = None + for fn in files: + x = process(fn, listnames) + exit = exit or x + return exit + +if __name__ == "__main__": + sys.exit(main()) diff --git a/sys/src/cmd/python/Tools/scripts/findlinksto.py b/sys/src/cmd/python/Tools/scripts/findlinksto.py new file mode 100755 index 000000000..8dd4bfb3c --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/findlinksto.py @@ -0,0 +1,43 @@ +#! /usr/bin/env python + +# findlinksto +# +# find symbolic links to a path matching a regular expression + +import os +import sys +import re +import getopt + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], '') + if len(args) < 2: + raise getopt.GetoptError('not enough arguments', None) + except getopt.GetoptError, msg: + sys.stdout = sys.stderr + print msg + print 'usage: findlinksto pattern directory ...' + sys.exit(2) + pat, dirs = args[0], args[1:] + prog = re.compile(pat) + for dirname in dirs: + os.path.walk(dirname, visit, prog) + +def visit(prog, dirname, names): + if os.path.islink(dirname): + names[:] = [] + return + if os.path.ismount(dirname): + print 'descend into', dirname + for name in names: + name = os.path.join(dirname, name) + try: + linkto = os.readlink(name) + if prog.search(linkto) is not None: + print name, '->', linkto + except os.error: + pass + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/findnocoding.py b/sys/src/cmd/python/Tools/scripts/findnocoding.py new file mode 100755 index 000000000..537f0a185 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/findnocoding.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python + +"""List all those Python files that require a coding directive + +Usage: nocoding.py dir1 [dir2...] +""" + +__author__ = "Oleg Broytmann, Georg Brandl" + +import sys, os, re, getopt + +# our pysource module finds Python source files +try: + import pysource +except: + # emulate the module with a simple os.walk + class pysource: + has_python_ext = looks_like_python = can_be_compiled = None + def walk_python_files(self, paths, *args, **kwargs): + for path in paths: + if os.path.isfile(path): + yield path.endswith(".py") + elif os.path.isdir(path): + for root, dirs, files in os.walk(path): + for filename in files: + if filename.endswith(".py"): + yield os.path.join(root, filename) + pysource = pysource() + + + print >>sys.stderr, ("The pysource module is not available; " + "no sophisticated Python source file search will be done.") + + +decl_re = re.compile(r"coding[=:]\s*([-\w.]+)") + +def get_declaration(line): + match = decl_re.search(line) + if match: + return match.group(1) + return '' + +def has_correct_encoding(text, codec): + try: + unicode(text, codec) + except UnicodeDecodeError: + return False + else: + return True + +def needs_declaration(fullpath): + try: + infile = open(fullpath, 'rU') + except IOError: # Oops, the file was removed - ignore it + return None + + line1 = infile.readline() + line2 = infile.readline() + + if get_declaration(line1) or get_declaration(line2): + # the file does have an encoding declaration, so trust it + infile.close() + return False + + # check the whole file for non-ASCII characters + rest = infile.read() + infile.close() + + if has_correct_encoding(line1+line2+rest, "ascii"): + return False + + return True + + +usage = """Usage: %s [-cd] paths... + -c: recognize Python source files trying to compile them + -d: debug output""" % sys.argv[0] + +try: + opts, args = getopt.getopt(sys.argv[1:], 'cd') +except getopt.error, msg: + print >>sys.stderr, msg + print >>sys.stderr, usage + sys.exit(1) + +is_python = pysource.looks_like_python +debug = False + +for o, a in opts: + if o == '-c': + is_python = pysource.can_be_compiled + elif o == '-d': + debug = True + +if not args: + print >>sys.stderr, usage + sys.exit(1) + +for fullpath in pysource.walk_python_files(args, is_python): + if debug: + print "Testing for coding: %s" % fullpath + result = needs_declaration(fullpath) + if result: + print fullpath diff --git a/sys/src/cmd/python/Tools/scripts/fixcid.py b/sys/src/cmd/python/Tools/scripts/fixcid.py new file mode 100755 index 000000000..433a4254e --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/fixcid.py @@ -0,0 +1,314 @@ +#! /usr/bin/env python + +# Perform massive identifier substitution on C source files. +# This actually tokenizes the files (to some extent) so it can +# avoid making substitutions inside strings or comments. +# Inside strings, substitutions are never made; inside comments, +# it is a user option (off by default). +# +# The substitutions are read from one or more files whose lines, +# when not empty, after stripping comments starting with #, +# must contain exactly two words separated by whitespace: the +# old identifier and its replacement. +# +# The option -r reverses the sense of the substitutions (this may be +# useful to undo a particular substitution). +# +# If the old identifier is prefixed with a '*' (with no intervening +# whitespace), then it will not be substituted inside comments. +# +# Command line arguments are files or directories to be processed. +# Directories are searched recursively for files whose name looks +# like a C file (ends in .h or .c). The special filename '-' means +# operate in filter mode: read stdin, write stdout. +# +# Symbolic links are always ignored (except as explicit directory +# arguments). +# +# The original files are kept as back-up with a "~" suffix. +# +# Changes made are reported to stdout in a diff-like format. +# +# NB: by changing only the function fixline() you can turn this +# into a program for different changes to C source files; by +# changing the function wanted() you can make a different selection of +# files. + +import sys +import re +import os +from stat import * +import getopt + +err = sys.stderr.write +dbg = err +rep = sys.stdout.write + +def usage(): + progname = sys.argv[0] + err('Usage: ' + progname + + ' [-c] [-r] [-s file] ... file-or-directory ...\n') + err('\n') + err('-c : substitute inside comments\n') + err('-r : reverse direction for following -s options\n') + err('-s substfile : add a file of substitutions\n') + err('\n') + err('Each non-empty non-comment line in a substitution file must\n') + err('contain exactly two words: an identifier and its replacement.\n') + err('Comments start with a # character and end at end of line.\n') + err('If an identifier is preceded with a *, it is not substituted\n') + err('inside a comment even when -c is specified.\n') + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], 'crs:') + except getopt.error, msg: + err('Options error: ' + str(msg) + '\n') + usage() + sys.exit(2) + bad = 0 + if not args: # No arguments + usage() + sys.exit(2) + for opt, arg in opts: + if opt == '-c': + setdocomments() + if opt == '-r': + setreverse() + if opt == '-s': + addsubst(arg) + for arg in args: + if os.path.isdir(arg): + if recursedown(arg): bad = 1 + elif os.path.islink(arg): + err(arg + ': will not process symbolic links\n') + bad = 1 + else: + if fix(arg): bad = 1 + sys.exit(bad) + +# Change this regular expression to select a different set of files +Wanted = '^[a-zA-Z0-9_]+\.[ch]$' +def wanted(name): + return re.match(Wanted, name) >= 0 + +def recursedown(dirname): + dbg('recursedown(%r)\n' % (dirname,)) + bad = 0 + try: + names = os.listdir(dirname) + except os.error, msg: + err(dirname + ': cannot list directory: ' + str(msg) + '\n') + return 1 + names.sort() + subdirs = [] + for name in names: + if name in (os.curdir, os.pardir): continue + fullname = os.path.join(dirname, name) + if os.path.islink(fullname): pass + elif os.path.isdir(fullname): + subdirs.append(fullname) + elif wanted(name): + if fix(fullname): bad = 1 + for fullname in subdirs: + if recursedown(fullname): bad = 1 + return bad + +def fix(filename): +## dbg('fix(%r)\n' % (filename,)) + if filename == '-': + # Filter mode + f = sys.stdin + g = sys.stdout + else: + # File replacement mode + try: + f = open(filename, 'r') + except IOError, msg: + err(filename + ': cannot open: ' + str(msg) + '\n') + return 1 + head, tail = os.path.split(filename) + tempname = os.path.join(head, '@' + tail) + g = None + # If we find a match, we rewind the file and start over but + # now copy everything to a temp file. + lineno = 0 + initfixline() + while 1: + line = f.readline() + if not line: break + lineno = lineno + 1 + while line[-2:] == '\\\n': + nextline = f.readline() + if not nextline: break + line = line + nextline + lineno = lineno + 1 + newline = fixline(line) + if newline != line: + if g is None: + try: + g = open(tempname, 'w') + except IOError, msg: + f.close() + err(tempname+': cannot create: '+ + str(msg)+'\n') + return 1 + f.seek(0) + lineno = 0 + initfixline() + rep(filename + ':\n') + continue # restart from the beginning + rep(repr(lineno) + '\n') + rep('< ' + line) + rep('> ' + newline) + if g is not None: + g.write(newline) + + # End of file + if filename == '-': return 0 # Done in filter mode + f.close() + if not g: return 0 # No changes + + # Finishing touch -- move files + + # First copy the file's mode to the temp file + try: + statbuf = os.stat(filename) + os.chmod(tempname, statbuf[ST_MODE] & 07777) + except os.error, msg: + err(tempname + ': warning: chmod failed (' + str(msg) + ')\n') + # Then make a backup of the original file as filename~ + try: + os.rename(filename, filename + '~') + except os.error, msg: + err(filename + ': warning: backup failed (' + str(msg) + ')\n') + # Now move the temp file to the original file + try: + os.rename(tempname, filename) + except os.error, msg: + err(filename + ': rename failed (' + str(msg) + ')\n') + return 1 + # Return succes + return 0 + +# Tokenizing ANSI C (partly) + +Identifier = '\(struct \)?[a-zA-Z_][a-zA-Z0-9_]+' +String = '"\([^\n\\"]\|\\\\.\)*"' +Char = '\'\([^\n\\\']\|\\\\.\)*\'' +CommentStart = '/\*' +CommentEnd = '\*/' + +Hexnumber = '0[xX][0-9a-fA-F]*[uUlL]*' +Octnumber = '0[0-7]*[uUlL]*' +Decnumber = '[1-9][0-9]*[uUlL]*' +Intnumber = Hexnumber + '\|' + Octnumber + '\|' + Decnumber +Exponent = '[eE][-+]?[0-9]+' +Pointfloat = '\([0-9]+\.[0-9]*\|\.[0-9]+\)\(' + Exponent + '\)?' +Expfloat = '[0-9]+' + Exponent +Floatnumber = Pointfloat + '\|' + Expfloat +Number = Floatnumber + '\|' + Intnumber + +# Anything else is an operator -- don't list this explicitly because of '/*' + +OutsideComment = (Identifier, Number, String, Char, CommentStart) +OutsideCommentPattern = '(' + '|'.join(OutsideComment) + ')' +OutsideCommentProgram = re.compile(OutsideCommentPattern) + +InsideComment = (Identifier, Number, CommentEnd) +InsideCommentPattern = '(' + '|'.join(InsideComment) + ')' +InsideCommentProgram = re.compile(InsideCommentPattern) + +def initfixline(): + global Program + Program = OutsideCommentProgram + +def fixline(line): + global Program +## print '-->', repr(line) + i = 0 + while i < len(line): + i = Program.search(line, i) + if i < 0: break + found = Program.group(0) +## if Program is InsideCommentProgram: print '...', +## else: print ' ', +## print found + if len(found) == 2: + if found == '/*': + Program = InsideCommentProgram + elif found == '*/': + Program = OutsideCommentProgram + n = len(found) + if Dict.has_key(found): + subst = Dict[found] + if Program is InsideCommentProgram: + if not Docomments: + print 'Found in comment:', found + i = i + n + continue + if NotInComment.has_key(found): +## print 'Ignored in comment:', +## print found, '-->', subst +## print 'Line:', line, + subst = found +## else: +## print 'Substituting in comment:', +## print found, '-->', subst +## print 'Line:', line, + line = line[:i] + subst + line[i+n:] + n = len(subst) + i = i + n + return line + +Docomments = 0 +def setdocomments(): + global Docomments + Docomments = 1 + +Reverse = 0 +def setreverse(): + global Reverse + Reverse = (not Reverse) + +Dict = {} +NotInComment = {} +def addsubst(substfile): + try: + fp = open(substfile, 'r') + except IOError, msg: + err(substfile + ': cannot read substfile: ' + str(msg) + '\n') + sys.exit(1) + lineno = 0 + while 1: + line = fp.readline() + if not line: break + lineno = lineno + 1 + try: + i = line.index('#') + except ValueError: + i = -1 # Happens to delete trailing \n + words = line[:i].split() + if not words: continue + if len(words) == 3 and words[0] == 'struct': + words[:2] = [words[0] + ' ' + words[1]] + elif len(words) <> 2: + err(substfile + '%s:%r: warning: bad line: %r' % (substfile, lineno, line)) + continue + if Reverse: + [value, key] = words + else: + [key, value] = words + if value[0] == '*': + value = value[1:] + if key[0] == '*': + key = key[1:] + NotInComment[key] = value + if Dict.has_key(key): + err('%s:%r: warning: overriding: %r %r\n' % (substfile, lineno, key, value)) + err('%s:%r: warning: previous: %r\n' % (substfile, lineno, Dict[key])) + Dict[key] = value + fp.close() + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/fixdiv.py b/sys/src/cmd/python/Tools/scripts/fixdiv.py new file mode 100755 index 000000000..2bbd3d52c --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/fixdiv.py @@ -0,0 +1,380 @@ +#! /usr/bin/env python + +"""fixdiv - tool to fix division operators. + +To use this tool, first run `python -Qwarnall yourscript.py 2>warnings'. +This runs the script `yourscript.py' while writing warning messages +about all uses of the classic division operator to the file +`warnings'. The warnings look like this: + + <file>:<line>: DeprecationWarning: classic <type> division + +The warnings are written to stderr, so you must use `2>' for the I/O +redirect. I know of no way to redirect stderr on Windows in a DOS +box, so you will have to modify the script to set sys.stderr to some +kind of log file if you want to do this on Windows. + +The warnings are not limited to the script; modules imported by the +script may also trigger warnings. In fact a useful technique is to +write a test script specifically intended to exercise all code in a +particular module or set of modules. + +Then run `python fixdiv.py warnings'. This first reads the warnings, +looking for classic division warnings, and sorts them by file name and +line number. Then, for each file that received at least one warning, +it parses the file and tries to match the warnings up to the division +operators found in the source code. If it is successful, it writes +its findings to stdout, preceded by a line of dashes and a line of the +form: + + Index: <file> + +If the only findings found are suggestions to change a / operator into +a // operator, the output is acceptable input for the Unix 'patch' +program. + +Here are the possible messages on stdout (N stands for a line number): + +- A plain-diff-style change ('NcN', a line marked by '<', a line + containing '---', and a line marked by '>'): + + A / operator was found that should be changed to //. This is the + recommendation when only int and/or long arguments were seen. + +- 'True division / operator at line N' and a line marked by '=': + + A / operator was found that can remain unchanged. This is the + recommendation when only float and/or complex arguments were seen. + +- 'Ambiguous / operator (..., ...) at line N', line marked by '?': + + A / operator was found for which int or long as well as float or + complex arguments were seen. This is highly unlikely; if it occurs, + you may have to restructure the code to keep the classic semantics, + or maybe you don't care about the classic semantics. + +- 'No conclusive evidence on line N', line marked by '*': + + A / operator was found for which no warnings were seen. This could + be code that was never executed, or code that was only executed + with user-defined objects as arguments. You will have to + investigate further. Note that // can be overloaded separately from + /, using __floordiv__. True division can also be separately + overloaded, using __truediv__. Classic division should be the same + as either of those. (XXX should I add a warning for division on + user-defined objects, to disambiguate this case from code that was + never executed?) + +- 'Phantom ... warnings for line N', line marked by '*': + + A warning was seen for a line not containing a / operator. The most + likely cause is a warning about code executed by 'exec' or eval() + (see note below), or an indirect invocation of the / operator, for + example via the div() function in the operator module. It could + also be caused by a change to the file between the time the test + script was run to collect warnings and the time fixdiv was run. + +- 'More than one / operator in line N'; or + 'More than one / operator per statement in lines N-N': + + The scanner found more than one / operator on a single line, or in a + statement split across multiple lines. Because the warnings + framework doesn't (and can't) show the offset within the line, and + the code generator doesn't always give the correct line number for + operations in a multi-line statement, we can't be sure whether all + operators in the statement were executed. To be on the safe side, + by default a warning is issued about this case. In practice, these + cases are usually safe, and the -m option suppresses these warning. + +- 'Can't find the / operator in line N', line marked by '*': + + This really shouldn't happen. It means that the tokenize module + reported a '/' operator but the line it returns didn't contain a '/' + character at the indicated position. + +- 'Bad warning for line N: XYZ', line marked by '*': + + This really shouldn't happen. It means that a 'classic XYZ + division' warning was read with XYZ being something other than + 'int', 'long', 'float', or 'complex'. + +Notes: + +- The augmented assignment operator /= is handled the same way as the + / operator. + +- This tool never looks at the // operator; no warnings are ever + generated for use of this operator. + +- This tool never looks at the / operator when a future division + statement is in effect; no warnings are generated in this case, and + because the tool only looks at files for which at least one classic + division warning was seen, it will never look at files containing a + future division statement. + +- Warnings may be issued for code not read from a file, but executed + using an exec statement or the eval() function. These may have + <string> in the filename position, in which case the fixdiv script + will attempt and fail to open a file named '<string>' and issue a + warning about this failure; or these may be reported as 'Phantom' + warnings (see above). You're on your own to deal with these. You + could make all recommended changes and add a future division + statement to all affected files, and then re-run the test script; it + should not issue any warnings. If there are any, and you have a + hard time tracking down where they are generated, you can use the + -Werror option to force an error instead of a first warning, + generating a traceback. + +- The tool should be run from the same directory as that from which + the original script was run, otherwise it won't be able to open + files given by relative pathnames. +""" + +import sys +import getopt +import re +import tokenize + +multi_ok = 0 + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "hm") + except getopt.error, msg: + usage(msg) + return 2 + for o, a in opts: + if o == "-h": + print __doc__ + return + if o == "-m": + global multi_ok + multi_ok = 1 + if not args: + usage("at least one file argument is required") + return 2 + if args[1:]: + sys.stderr.write("%s: extra file arguments ignored\n", sys.argv[0]) + warnings = readwarnings(args[0]) + if warnings is None: + return 1 + files = warnings.keys() + if not files: + print "No classic division warnings read from", args[0] + return + files.sort() + exit = None + for filename in files: + x = process(filename, warnings[filename]) + exit = exit or x + return exit + +def usage(msg): + sys.stderr.write("%s: %s\n" % (sys.argv[0], msg)) + sys.stderr.write("Usage: %s [-m] warnings\n" % sys.argv[0]) + sys.stderr.write("Try `%s -h' for more information.\n" % sys.argv[0]) + +PATTERN = ("^(.+?):(\d+): DeprecationWarning: " + "classic (int|long|float|complex) division$") + +def readwarnings(warningsfile): + prog = re.compile(PATTERN) + try: + f = open(warningsfile) + except IOError, msg: + sys.stderr.write("can't open: %s\n" % msg) + return + warnings = {} + while 1: + line = f.readline() + if not line: + break + m = prog.match(line) + if not m: + if line.find("division") >= 0: + sys.stderr.write("Warning: ignored input " + line) + continue + filename, lineno, what = m.groups() + list = warnings.get(filename) + if list is None: + warnings[filename] = list = [] + list.append((int(lineno), intern(what))) + f.close() + return warnings + +def process(filename, list): + print "-"*70 + assert list # if this fails, readwarnings() is broken + try: + fp = open(filename) + except IOError, msg: + sys.stderr.write("can't open: %s\n" % msg) + return 1 + print "Index:", filename + f = FileContext(fp) + list.sort() + index = 0 # list[:index] has been processed, list[index:] is still to do + g = tokenize.generate_tokens(f.readline) + while 1: + startlineno, endlineno, slashes = lineinfo = scanline(g) + if startlineno is None: + break + assert startlineno <= endlineno is not None + orphans = [] + while index < len(list) and list[index][0] < startlineno: + orphans.append(list[index]) + index += 1 + if orphans: + reportphantomwarnings(orphans, f) + warnings = [] + while index < len(list) and list[index][0] <= endlineno: + warnings.append(list[index]) + index += 1 + if not slashes and not warnings: + pass + elif slashes and not warnings: + report(slashes, "No conclusive evidence") + elif warnings and not slashes: + reportphantomwarnings(warnings, f) + else: + if len(slashes) > 1: + if not multi_ok: + rows = [] + lastrow = None + for (row, col), line in slashes: + if row == lastrow: + continue + rows.append(row) + lastrow = row + assert rows + if len(rows) == 1: + print "*** More than one / operator in line", rows[0] + else: + print "*** More than one / operator per statement", + print "in lines %d-%d" % (rows[0], rows[-1]) + intlong = [] + floatcomplex = [] + bad = [] + for lineno, what in warnings: + if what in ("int", "long"): + intlong.append(what) + elif what in ("float", "complex"): + floatcomplex.append(what) + else: + bad.append(what) + lastrow = None + for (row, col), line in slashes: + if row == lastrow: + continue + lastrow = row + line = chop(line) + if line[col:col+1] != "/": + print "*** Can't find the / operator in line %d:" % row + print "*", line + continue + if bad: + print "*** Bad warning for line %d:" % row, bad + print "*", line + elif intlong and not floatcomplex: + print "%dc%d" % (row, row) + print "<", line + print "---" + print ">", line[:col] + "/" + line[col:] + elif floatcomplex and not intlong: + print "True division / operator at line %d:" % row + print "=", line + elif intlong and floatcomplex: + print "*** Ambiguous / operator (%s, %s) at line %d:" % ( + "|".join(intlong), "|".join(floatcomplex), row) + print "?", line + fp.close() + +def reportphantomwarnings(warnings, f): + blocks = [] + lastrow = None + lastblock = None + for row, what in warnings: + if row != lastrow: + lastblock = [row] + blocks.append(lastblock) + lastblock.append(what) + for block in blocks: + row = block[0] + whats = "/".join(block[1:]) + print "*** Phantom %s warnings for line %d:" % (whats, row) + f.report(row, mark="*") + +def report(slashes, message): + lastrow = None + for (row, col), line in slashes: + if row != lastrow: + print "*** %s on line %d:" % (message, row) + print "*", chop(line) + lastrow = row + +class FileContext: + def __init__(self, fp, window=5, lineno=1): + self.fp = fp + self.window = 5 + self.lineno = 1 + self.eoflookahead = 0 + self.lookahead = [] + self.buffer = [] + def fill(self): + while len(self.lookahead) < self.window and not self.eoflookahead: + line = self.fp.readline() + if not line: + self.eoflookahead = 1 + break + self.lookahead.append(line) + def readline(self): + self.fill() + if not self.lookahead: + return "" + line = self.lookahead.pop(0) + self.buffer.append(line) + self.lineno += 1 + return line + def truncate(self): + del self.buffer[-window:] + def __getitem__(self, index): + self.fill() + bufstart = self.lineno - len(self.buffer) + lookend = self.lineno + len(self.lookahead) + if bufstart <= index < self.lineno: + return self.buffer[index - bufstart] + if self.lineno <= index < lookend: + return self.lookahead[index - self.lineno] + raise KeyError + def report(self, first, last=None, mark="*"): + if last is None: + last = first + for i in range(first, last+1): + try: + line = self[first] + except KeyError: + line = "<missing line>" + print mark, chop(line) + +def scanline(g): + slashes = [] + startlineno = None + endlineno = None + for type, token, start, end, line in g: + endlineno = end[0] + if startlineno is None: + startlineno = endlineno + if token in ("/", "/="): + slashes.append((start, line)) + if type == tokenize.NEWLINE: + break + return startlineno, endlineno, slashes + +def chop(line): + if line.endswith("\n"): + return line[:-1] + else: + return line + +if __name__ == "__main__": + sys.exit(main()) diff --git a/sys/src/cmd/python/Tools/scripts/fixheader.py b/sys/src/cmd/python/Tools/scripts/fixheader.py new file mode 100755 index 000000000..1bf5c526b --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/fixheader.py @@ -0,0 +1,49 @@ +#! /usr/bin/env python + +# Add some standard cpp magic to a header file + +import sys + +def main(): + args = sys.argv[1:] + for filename in args: + process(filename) + +def process(filename): + try: + f = open(filename, 'r') + except IOError, msg: + sys.stderr.write('%s: can\'t open: %s\n' % (filename, str(msg))) + return + data = f.read() + f.close() + if data[:2] <> '/*': + sys.stderr.write('%s does not begin with C comment\n' % filename) + return + try: + f = open(filename, 'w') + except IOError, msg: + sys.stderr.write('%s: can\'t write: %s\n' % (filename, str(msg))) + return + sys.stderr.write('Processing %s ...\n' % filename) + magic = 'Py_' + for c in filename: + if ord(c)<=0x80 and c.isalnum(): + magic = magic + c.upper() + else: magic = magic + '_' + sys.stdout = f + print '#ifndef', magic + print '#define', magic + print '#ifdef __cplusplus' + print 'extern "C" {' + print '#endif' + print + f.write(data) + print + print '#ifdef __cplusplus' + print '}' + print '#endif' + print '#endif /*', '!'+magic, '*/' + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/fixnotice.py b/sys/src/cmd/python/Tools/scripts/fixnotice.py new file mode 100755 index 000000000..0ae487200 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/fixnotice.py @@ -0,0 +1,113 @@ +#! /usr/bin/env python + +"""(Ostensibly) fix copyright notices in files. + +Actually, this sript will simply replace a block of text in a file from one +string to another. It will only do this once though, i.e. not globally +throughout the file. It writes a backup file and then does an os.rename() +dance for atomicity. + +Usage: fixnotices.py [options] [filenames] +Options: + -h / --help + Print this message and exit + + --oldnotice=file + Use the notice in the file as the old (to be replaced) string, instead + of the hard coded value in the script. + + --newnotice=file + Use the notice in the file as the new (replacement) string, instead of + the hard coded value in the script. + + --dry-run + Don't actually make the changes, but print out the list of files that + would change. When used with -v, a status will be printed for every + file. + + -v / --verbose + Print a message for every file looked at, indicating whether the file + is changed or not. +""" + +OLD_NOTICE = """/*********************************************************** +Copyright (c) 2000, BeOpen.com. +Copyright (c) 1995-2000, Corporation for National Research Initiatives. +Copyright (c) 1990-1995, Stichting Mathematisch Centrum. +All rights reserved. + +See the file "Misc/COPYRIGHT" for information on usage and +redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. +******************************************************************/ +""" +import os +import sys +import getopt + +NEW_NOTICE = "" +DRYRUN = 0 +VERBOSE = 0 + + +def usage(code, msg=''): + print __doc__ % globals() + if msg: + print msg + sys.exit(code) + + +def main(): + global DRYRUN, OLD_NOTICE, NEW_NOTICE, VERBOSE + try: + opts, args = getopt.getopt(sys.argv[1:], 'hv', + ['help', 'oldnotice=', 'newnotice=', + 'dry-run', 'verbose']) + except getopt.error, msg: + usage(1, msg) + + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-v', '--verbose'): + VERBOSE = 1 + elif opt == '--dry-run': + DRYRUN = 1 + elif opt == '--oldnotice': + fp = open(arg) + OLD_NOTICE = fp.read() + fp.close() + elif opt == '--newnotice': + fp = open(arg) + NEW_NOTICE = fp.read() + fp.close() + + for arg in args: + process(arg) + + +def process(file): + f = open(file) + data = f.read() + f.close() + i = data.find(OLD_NOTICE) + if i < 0: + if VERBOSE: + print 'no change:', file + return + elif DRYRUN or VERBOSE: + print ' change:', file + if DRYRUN: + # Don't actually change the file + return + data = data[:i] + NEW_NOTICE + data[i+len(OLD_NOTICE):] + new = file + ".new" + backup = file + ".bak" + f = open(new, "w") + f.write(data) + f.close() + os.rename(file, backup) + os.rename(new, file) + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/fixps.py b/sys/src/cmd/python/Tools/scripts/fixps.py new file mode 100755 index 000000000..2ff15f41e --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/fixps.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +# Fix Python script(s) to reference the interpreter via /usr/bin/env python. +# Warning: this overwrites the file without making a backup. + +import sys +import re + + +def main(): + for filename in sys.argv[1:]: + try: + f = open(filename, 'r') + except IOError, msg: + print filename, ': can\'t open :', msg + continue + line = f.readline() + if not re.match('^#! */usr/local/bin/python', line): + print filename, ': not a /usr/local/bin/python script' + f.close() + continue + rest = f.read() + f.close() + line = re.sub('/usr/local/bin/python', + '/usr/bin/env python', line) + print filename, ':', repr(line) + f = open(filename, "w") + f.write(line) + f.write(rest) + f.close() + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/ftpmirror.py b/sys/src/cmd/python/Tools/scripts/ftpmirror.py new file mode 100755 index 000000000..0f918b884 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/ftpmirror.py @@ -0,0 +1,400 @@ +#! /usr/bin/env python + +"""Mirror a remote ftp subtree into a local directory tree. + +usage: ftpmirror [-v] [-q] [-i] [-m] [-n] [-r] [-s pat] + [-l username [-p passwd [-a account]]] + hostname[:port] [remotedir [localdir]] +-v: verbose +-q: quiet +-i: interactive mode +-m: macintosh server (NCSA telnet 2.4) (implies -n -s '*.o') +-n: don't log in +-r: remove local files/directories no longer pertinent +-l username [-p passwd [-a account]]: login info (default .netrc or anonymous) +-s pat: skip files matching pattern +hostname: remote host w/ optional port separated by ':' +remotedir: remote directory (default initial) +localdir: local directory (default current) +""" + +import os +import sys +import time +import getopt +import ftplib +import netrc +from fnmatch import fnmatch + +# Print usage message and exit +def usage(*args): + sys.stdout = sys.stderr + for msg in args: print msg + print __doc__ + sys.exit(2) + +verbose = 1 # 0 for -q, 2 for -v +interactive = 0 +mac = 0 +rmok = 0 +nologin = 0 +skippats = ['.', '..', '.mirrorinfo'] + +# Main program: parse command line and start processing +def main(): + global verbose, interactive, mac, rmok, nologin + try: + opts, args = getopt.getopt(sys.argv[1:], 'a:bil:mnp:qrs:v') + except getopt.error, msg: + usage(msg) + login = '' + passwd = '' + account = '' + if not args: usage('hostname missing') + host = args[0] + port = 0 + if ':' in host: + host, port = host.split(':', 1) + port = int(port) + try: + auth = netrc.netrc().authenticators(host) + if auth is not None: + login, account, passwd = auth + except (netrc.NetrcParseError, IOError): + pass + for o, a in opts: + if o == '-l': login = a + if o == '-p': passwd = a + if o == '-a': account = a + if o == '-v': verbose = verbose + 1 + if o == '-q': verbose = 0 + if o == '-i': interactive = 1 + if o == '-m': mac = 1; nologin = 1; skippats.append('*.o') + if o == '-n': nologin = 1 + if o == '-r': rmok = 1 + if o == '-s': skippats.append(a) + remotedir = '' + localdir = '' + if args[1:]: + remotedir = args[1] + if args[2:]: + localdir = args[2] + if args[3:]: usage('too many arguments') + # + f = ftplib.FTP() + if verbose: print "Connecting to '%s%s'..." % (host, + (port and ":%d"%port or "")) + f.connect(host,port) + if not nologin: + if verbose: + print 'Logging in as %r...' % (login or 'anonymous') + f.login(login, passwd, account) + if verbose: print 'OK.' + pwd = f.pwd() + if verbose > 1: print 'PWD =', repr(pwd) + if remotedir: + if verbose > 1: print 'cwd(%s)' % repr(remotedir) + f.cwd(remotedir) + if verbose > 1: print 'OK.' + pwd = f.pwd() + if verbose > 1: print 'PWD =', repr(pwd) + # + mirrorsubdir(f, localdir) + +# Core logic: mirror one subdirectory (recursively) +def mirrorsubdir(f, localdir): + pwd = f.pwd() + if localdir and not os.path.isdir(localdir): + if verbose: print 'Creating local directory', repr(localdir) + try: + makedir(localdir) + except os.error, msg: + print "Failed to establish local directory", repr(localdir) + return + infofilename = os.path.join(localdir, '.mirrorinfo') + try: + text = open(infofilename, 'r').read() + except IOError, msg: + text = '{}' + try: + info = eval(text) + except (SyntaxError, NameError): + print 'Bad mirror info in', repr(infofilename) + info = {} + subdirs = [] + listing = [] + if verbose: print 'Listing remote directory %r...' % (pwd,) + f.retrlines('LIST', listing.append) + filesfound = [] + for line in listing: + if verbose > 1: print '-->', repr(line) + if mac: + # Mac listing has just filenames; + # trailing / means subdirectory + filename = line.strip() + mode = '-' + if filename[-1:] == '/': + filename = filename[:-1] + mode = 'd' + infostuff = '' + else: + # Parse, assuming a UNIX listing + words = line.split(None, 8) + if len(words) < 6: + if verbose > 1: print 'Skipping short line' + continue + filename = words[-1].lstrip() + i = filename.find(" -> ") + if i >= 0: + # words[0] had better start with 'l'... + if verbose > 1: + print 'Found symbolic link %r' % (filename,) + linkto = filename[i+4:] + filename = filename[:i] + infostuff = words[-5:-1] + mode = words[0] + skip = 0 + for pat in skippats: + if fnmatch(filename, pat): + if verbose > 1: + print 'Skip pattern', repr(pat), + print 'matches', repr(filename) + skip = 1 + break + if skip: + continue + if mode[0] == 'd': + if verbose > 1: + print 'Remembering subdirectory', repr(filename) + subdirs.append(filename) + continue + filesfound.append(filename) + if info.has_key(filename) and info[filename] == infostuff: + if verbose > 1: + print 'Already have this version of',repr(filename) + continue + fullname = os.path.join(localdir, filename) + tempname = os.path.join(localdir, '@'+filename) + if interactive: + doit = askabout('file', filename, pwd) + if not doit: + if not info.has_key(filename): + info[filename] = 'Not retrieved' + continue + try: + os.unlink(tempname) + except os.error: + pass + if mode[0] == 'l': + if verbose: + print "Creating symlink %r -> %r" % (filename, linkto) + try: + os.symlink(linkto, tempname) + except IOError, msg: + print "Can't create %r: %s" % (tempname, msg) + continue + else: + try: + fp = open(tempname, 'wb') + except IOError, msg: + print "Can't create %r: %s" % (tempname, msg) + continue + if verbose: + print 'Retrieving %r from %r as %r...' % (filename, pwd, fullname) + if verbose: + fp1 = LoggingFile(fp, 1024, sys.stdout) + else: + fp1 = fp + t0 = time.time() + try: + f.retrbinary('RETR ' + filename, + fp1.write, 8*1024) + except ftplib.error_perm, msg: + print msg + t1 = time.time() + bytes = fp.tell() + fp.close() + if fp1 != fp: + fp1.close() + try: + os.unlink(fullname) + except os.error: + pass # Ignore the error + try: + os.rename(tempname, fullname) + except os.error, msg: + print "Can't rename %r to %r: %s" % (tempname, fullname, msg) + continue + info[filename] = infostuff + writedict(info, infofilename) + if verbose and mode[0] != 'l': + dt = t1 - t0 + kbytes = bytes / 1024.0 + print int(round(kbytes)), + print 'Kbytes in', + print int(round(dt)), + print 'seconds', + if t1 > t0: + print '(~%d Kbytes/sec)' % \ + int(round(kbytes/dt),) + print + # + # Remove files from info that are no longer remote + deletions = 0 + for filename in info.keys(): + if filename not in filesfound: + if verbose: + print "Removing obsolete info entry for", + print repr(filename), "in", repr(localdir or ".") + del info[filename] + deletions = deletions + 1 + if deletions: + writedict(info, infofilename) + # + # Remove local files that are no longer in the remote directory + try: + if not localdir: names = os.listdir(os.curdir) + else: names = os.listdir(localdir) + except os.error: + names = [] + for name in names: + if name[0] == '.' or info.has_key(name) or name in subdirs: + continue + skip = 0 + for pat in skippats: + if fnmatch(name, pat): + if verbose > 1: + print 'Skip pattern', repr(pat), + print 'matches', repr(name) + skip = 1 + break + if skip: + continue + fullname = os.path.join(localdir, name) + if not rmok: + if verbose: + print 'Local file', repr(fullname), + print 'is no longer pertinent' + continue + if verbose: print 'Removing local file/dir', repr(fullname) + remove(fullname) + # + # Recursively mirror subdirectories + for subdir in subdirs: + if interactive: + doit = askabout('subdirectory', subdir, pwd) + if not doit: continue + if verbose: print 'Processing subdirectory', repr(subdir) + localsubdir = os.path.join(localdir, subdir) + pwd = f.pwd() + if verbose > 1: + print 'Remote directory now:', repr(pwd) + print 'Remote cwd', repr(subdir) + try: + f.cwd(subdir) + except ftplib.error_perm, msg: + print "Can't chdir to", repr(subdir), ":", repr(msg) + else: + if verbose: print 'Mirroring as', repr(localsubdir) + mirrorsubdir(f, localsubdir) + if verbose > 1: print 'Remote cwd ..' + f.cwd('..') + newpwd = f.pwd() + if newpwd != pwd: + print 'Ended up in wrong directory after cd + cd ..' + print 'Giving up now.' + break + else: + if verbose > 1: print 'OK.' + +# Helper to remove a file or directory tree +def remove(fullname): + if os.path.isdir(fullname) and not os.path.islink(fullname): + try: + names = os.listdir(fullname) + except os.error: + names = [] + ok = 1 + for name in names: + if not remove(os.path.join(fullname, name)): + ok = 0 + if not ok: + return 0 + try: + os.rmdir(fullname) + except os.error, msg: + print "Can't remove local directory %r: %s" % (fullname, msg) + return 0 + else: + try: + os.unlink(fullname) + except os.error, msg: + print "Can't remove local file %r: %s" % (fullname, msg) + return 0 + return 1 + +# Wrapper around a file for writing to write a hash sign every block. +class LoggingFile: + def __init__(self, fp, blocksize, outfp): + self.fp = fp + self.bytes = 0 + self.hashes = 0 + self.blocksize = blocksize + self.outfp = outfp + def write(self, data): + self.bytes = self.bytes + len(data) + hashes = int(self.bytes) / self.blocksize + while hashes > self.hashes: + self.outfp.write('#') + self.outfp.flush() + self.hashes = self.hashes + 1 + self.fp.write(data) + def close(self): + self.outfp.write('\n') + +# Ask permission to download a file. +def askabout(filetype, filename, pwd): + prompt = 'Retrieve %s %s from %s ? [ny] ' % (filetype, filename, pwd) + while 1: + reply = raw_input(prompt).strip().lower() + if reply in ['y', 'ye', 'yes']: + return 1 + if reply in ['', 'n', 'no', 'nop', 'nope']: + return 0 + print 'Please answer yes or no.' + +# Create a directory if it doesn't exist. Recursively create the +# parent directory as well if needed. +def makedir(pathname): + if os.path.isdir(pathname): + return + dirname = os.path.dirname(pathname) + if dirname: makedir(dirname) + os.mkdir(pathname, 0777) + +# Write a dictionary to a file in a way that can be read back using +# rval() but is still somewhat readable (i.e. not a single long line). +# Also creates a backup file. +def writedict(dict, filename): + dir, fname = os.path.split(filename) + tempname = os.path.join(dir, '@' + fname) + backup = os.path.join(dir, fname + '~') + try: + os.unlink(backup) + except os.error: + pass + fp = open(tempname, 'w') + fp.write('{\n') + for key, value in dict.items(): + fp.write('%r: %r,\n' % (key, value)) + fp.write('}\n') + fp.close() + try: + os.rename(filename, backup) + except os.error: + pass + os.rename(tempname, filename) + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/google.py b/sys/src/cmd/python/Tools/scripts/google.py new file mode 100755 index 000000000..b2ab1a43a --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/google.py @@ -0,0 +1,23 @@ +#! /usr/bin/env python + +import sys, webbrowser + +def main(): + args = sys.argv[1:] + if not args: + print "Usage: %s querystring" % sys.argv[0] + return + list = [] + for arg in args: + if '+' in arg: + arg = arg.replace('+', '%2B') + if ' ' in arg: + arg = '"%s"' % arg + arg = arg.replace(' ', '+') + list.append(arg) + s = '+'.join(list) + url = "http://www.google.com/search?q=%s" % s + webbrowser.open(url) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/gprof2html.py b/sys/src/cmd/python/Tools/scripts/gprof2html.py new file mode 100755 index 000000000..cb01c2ce6 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/gprof2html.py @@ -0,0 +1,79 @@ +#! /usr/bin/env python2.3 + +"""Transform gprof(1) output into useful HTML.""" + +import re, os, sys, cgi, webbrowser + +header = """\ +<html> +<head> + <title>gprof output (%s)</title> +</head> +<body> +<pre> +""" + +trailer = """\ +</pre> +</body> +</html> +""" + +def add_escapes(input): + for line in input: + yield cgi.escape(line) + +def main(): + filename = "gprof.out" + if sys.argv[1:]: + filename = sys.argv[1] + outputfilename = filename + ".html" + input = add_escapes(file(filename)) + output = file(outputfilename, "w") + output.write(header % filename) + for line in input: + output.write(line) + if line.startswith(" time"): + break + labels = {} + for line in input: + m = re.match(r"(.* )(\w+)\n", line) + if not m: + output.write(line) + break + stuff, fname = m.group(1, 2) + labels[fname] = fname + output.write('%s<a name="flat:%s" href="#call:%s">%s</a>\n' % + (stuff, fname, fname, fname)) + for line in input: + output.write(line) + if line.startswith("index % time"): + break + for line in input: + m = re.match(r"(.* )(\w+)(( &lt;cycle.*&gt;)? \[\d+\])\n", line) + if not m: + output.write(line) + if line.startswith("Index by function name"): + break + continue + prefix, fname, suffix = m.group(1, 2, 3) + if fname not in labels: + output.write(line) + continue + if line.startswith("["): + output.write('%s<a name="call:%s" href="#flat:%s">%s</a>%s\n' % + (prefix, fname, fname, fname, suffix)) + else: + output.write('%s<a href="#call:%s">%s</a>%s\n' % + (prefix, fname, fname, suffix)) + for line in input: + for part in re.findall(r"(\w+(?:\.c)?|\W+)", line): + if part in labels: + part = '<a href="#call:%s">%s</a>' % (part, part) + output.write(part) + output.write(trailer) + output.close() + webbrowser.open("file:" + os.path.abspath(outputfilename)) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/h2py.py b/sys/src/cmd/python/Tools/scripts/h2py.py new file mode 100755 index 000000000..63e7336f9 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/h2py.py @@ -0,0 +1,175 @@ +#! /usr/bin/env python + +# Read #define's and translate to Python code. +# Handle #include statements. +# Handle #define macros with one argument. +# Anything that isn't recognized or doesn't translate into valid +# Python is ignored. + +# Without filename arguments, acts as a filter. +# If one or more filenames are given, output is written to corresponding +# filenames in the local directory, translated to all uppercase, with +# the extension replaced by ".py". + +# By passing one or more options of the form "-i regular_expression" +# you can specify additional strings to be ignored. This is useful +# e.g. to ignore casts to u_long: simply specify "-i '(u_long)'". + +# XXX To do: +# - turn trailing C comments into Python comments +# - turn C Boolean operators "&& || !" into Python "and or not" +# - what to do about #if(def)? +# - what to do about macros with multiple parameters? + +import sys, re, getopt, os + +p_define = re.compile('^[\t ]*#[\t ]*define[\t ]+([a-zA-Z0-9_]+)[\t ]+') + +p_macro = re.compile( + '^[\t ]*#[\t ]*define[\t ]+' + '([a-zA-Z0-9_]+)\(([_a-zA-Z][_a-zA-Z0-9]*)\)[\t ]+') + +p_include = re.compile('^[\t ]*#[\t ]*include[\t ]+<([a-zA-Z0-9_/\.]+)') + +p_comment = re.compile(r'/\*([^*]+|\*+[^/])*(\*+/)?') +p_cpp_comment = re.compile('//.*') + +ignores = [p_comment, p_cpp_comment] + +p_char = re.compile(r"'(\\.[^\\]*|[^\\])'") + +p_hex = re.compile(r"0x([0-9a-fA-F]+)L?") + +filedict = {} +importable = {} + +try: + searchdirs=os.environ['include'].split(';') +except KeyError: + try: + searchdirs=os.environ['INCLUDE'].split(';') + except KeyError: + try: + if sys.platform.find("beos") == 0: + searchdirs=os.environ['BEINCLUDES'].split(';') + elif sys.platform.startswith("atheos"): + searchdirs=os.environ['C_INCLUDE_PATH'].split(':') + else: + raise KeyError + except KeyError: + searchdirs=['/usr/include'] + +def main(): + global filedict + opts, args = getopt.getopt(sys.argv[1:], 'i:') + for o, a in opts: + if o == '-i': + ignores.append(re.compile(a)) + if not args: + args = ['-'] + for filename in args: + if filename == '-': + sys.stdout.write('# Generated by h2py from stdin\n') + process(sys.stdin, sys.stdout) + else: + fp = open(filename, 'r') + outfile = os.path.basename(filename) + i = outfile.rfind('.') + if i > 0: outfile = outfile[:i] + modname = outfile.upper() + outfile = modname + '.py' + outfp = open(outfile, 'w') + outfp.write('# Generated by h2py from %s\n' % filename) + filedict = {} + for dir in searchdirs: + if filename[:len(dir)] == dir: + filedict[filename[len(dir)+1:]] = None # no '/' trailing + importable[filename[len(dir)+1:]] = modname + break + process(fp, outfp) + outfp.close() + fp.close() + +def pytify(body): + # replace ignored patterns by spaces + for p in ignores: + body = p.sub(' ', body) + # replace char literals by ord(...) + body = p_char.sub('ord(\\0)', body) + # Compute negative hexadecimal constants + start = 0 + UMAX = 2*(sys.maxint+1) + while 1: + m = p_hex.search(body, start) + if not m: break + s,e = m.span() + val = long(body[slice(*m.span(1))], 16) + if val > sys.maxint: + val -= UMAX + body = body[:s] + "(" + str(val) + ")" + body[e:] + start = s + 1 + return body + +def process(fp, outfp, env = {}): + lineno = 0 + while 1: + line = fp.readline() + if not line: break + lineno = lineno + 1 + match = p_define.match(line) + if match: + # gobble up continuation lines + while line[-2:] == '\\\n': + nextline = fp.readline() + if not nextline: break + lineno = lineno + 1 + line = line + nextline + name = match.group(1) + body = line[match.end():] + body = pytify(body) + ok = 0 + stmt = '%s = %s\n' % (name, body.strip()) + try: + exec stmt in env + except: + sys.stderr.write('Skipping: %s' % stmt) + else: + outfp.write(stmt) + match = p_macro.match(line) + if match: + macro, arg = match.group(1, 2) + body = line[match.end():] + body = pytify(body) + stmt = 'def %s(%s): return %s\n' % (macro, arg, body) + try: + exec stmt in env + except: + sys.stderr.write('Skipping: %s' % stmt) + else: + outfp.write(stmt) + match = p_include.match(line) + if match: + regs = match.regs + a, b = regs[1] + filename = line[a:b] + if importable.has_key(filename): + outfp.write('from %s import *\n' % importable[filename]) + elif not filedict.has_key(filename): + filedict[filename] = None + inclfp = None + for dir in searchdirs: + try: + inclfp = open(dir + '/' + filename) + break + except IOError: + pass + if inclfp: + outfp.write( + '\n# Included from %s\n' % filename) + process(inclfp, outfp, env) + else: + sys.stderr.write('Warning - could not find file %s\n' % + filename) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/hotshotmain.py b/sys/src/cmd/python/Tools/scripts/hotshotmain.py new file mode 100644 index 000000000..4f406284b --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/hotshotmain.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: iso-8859-1 -*- + +""" +Run a Python script under hotshot's control. + +Adapted from a posting on python-dev by Walter Dörwald + +usage %prog [ %prog args ] filename [ filename args ] + +Any arguments after the filename are used as sys.argv for the filename. +""" + +import sys +import optparse +import os +import hotshot +import hotshot.stats + +PROFILE = "hotshot.prof" + +def run_hotshot(filename, profile, args): + prof = hotshot.Profile(profile) + sys.path.insert(0, os.path.dirname(filename)) + sys.argv = [filename] + args + prof.run("execfile(%r)" % filename) + prof.close() + stats = hotshot.stats.load(profile) + stats.sort_stats("time", "calls") + + # print_stats uses unadorned print statements, so the only way + # to force output to stderr is to reassign sys.stdout temporarily + save_stdout = sys.stdout + sys.stdout = sys.stderr + stats.print_stats() + sys.stdout = save_stdout + + return 0 + +def main(args): + parser = optparse.OptionParser(__doc__) + parser.disable_interspersed_args() + parser.add_option("-p", "--profile", action="store", default=PROFILE, + dest="profile", help='Specify profile file to use') + (options, args) = parser.parse_args(args) + + if len(args) == 0: + parser.print_help("missing script to execute") + return 1 + + filename = args[0] + return run_hotshot(filename, options.profile, args[1:]) + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/sys/src/cmd/python/Tools/scripts/idle b/sys/src/cmd/python/Tools/scripts/idle new file mode 100644 index 000000000..1ba2a2c59 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/idle @@ -0,0 +1,5 @@ +#! /usr/bin/env python + +from idlelib.PyShell import main +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/ifdef.py b/sys/src/cmd/python/Tools/scripts/ifdef.py new file mode 100755 index 000000000..2ed7a6667 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/ifdef.py @@ -0,0 +1,112 @@ +#! /usr/bin/env python + +# Selectively preprocess #ifdef / #ifndef statements. +# Usage: +# ifdef [-Dname] ... [-Uname] ... [file] ... +# +# This scans the file(s), looking for #ifdef and #ifndef preprocessor +# commands that test for one of the names mentioned in the -D and -U +# options. On standard output it writes a copy of the input file(s) +# minus those code sections that are suppressed by the selected +# combination of defined/undefined symbols. The #if(n)def/#else/#else +# lines themselfs (if the #if(n)def tests for one of the mentioned +# names) are removed as well. + +# Features: Arbitrary nesting of recognized and unrecognized +# preprocesor statements works correctly. Unrecognized #if* commands +# are left in place, so it will never remove too much, only too +# little. It does accept whitespace around the '#' character. + +# Restrictions: There should be no comments or other symbols on the +# #if(n)def lines. The effect of #define/#undef commands in the input +# file or in included files is not taken into account. Tests using +# #if and the defined() pseudo function are not recognized. The #elif +# command is not recognized. Improperly nesting is not detected. +# Lines that look like preprocessor commands but which are actually +# part of comments or string literals will be mistaken for +# preprocessor commands. + +import sys +import getopt + +defs = [] +undefs = [] + +def main(): + opts, args = getopt.getopt(sys.argv[1:], 'D:U:') + for o, a in opts: + if o == '-D': + defs.append(a) + if o == '-U': + undefs.append(a) + if not args: + args = ['-'] + for filename in args: + if filename == '-': + process(sys.stdin, sys.stdout) + else: + f = open(filename, 'r') + process(f, sys.stdout) + f.close() + +def process(fpi, fpo): + keywords = ('if', 'ifdef', 'ifndef', 'else', 'endif') + ok = 1 + stack = [] + while 1: + line = fpi.readline() + if not line: break + while line[-2:] == '\\\n': + nextline = fpi.readline() + if not nextline: break + line = line + nextline + tmp = line.strip() + if tmp[:1] != '#': + if ok: fpo.write(line) + continue + tmp = tmp[1:].strip() + words = tmp.split() + keyword = words[0] + if keyword not in keywords: + if ok: fpo.write(line) + continue + if keyword in ('ifdef', 'ifndef') and len(words) == 2: + if keyword == 'ifdef': + ko = 1 + else: + ko = 0 + word = words[1] + if word in defs: + stack.append((ok, ko, word)) + if not ko: ok = 0 + elif word in undefs: + stack.append((ok, not ko, word)) + if ko: ok = 0 + else: + stack.append((ok, -1, word)) + if ok: fpo.write(line) + elif keyword == 'if': + stack.append((ok, -1, '')) + if ok: fpo.write(line) + elif keyword == 'else' and stack: + s_ok, s_ko, s_word = stack[-1] + if s_ko < 0: + if ok: fpo.write(line) + else: + s_ko = not s_ko + ok = s_ok + if not s_ko: ok = 0 + stack[-1] = s_ok, s_ko, s_word + elif keyword == 'endif' and stack: + s_ok, s_ko, s_word = stack[-1] + if s_ko < 0: + if ok: fpo.write(line) + del stack[-1] + ok = s_ok + else: + sys.stderr.write('Unknown keyword %s\n' % keyword) + if stack: + sys.stderr.write('stack: %s\n' % stack) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/lfcr.py b/sys/src/cmd/python/Tools/scripts/lfcr.py new file mode 100755 index 000000000..babafae32 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/lfcr.py @@ -0,0 +1,24 @@ +#! /usr/bin/env python + +"Replace LF with CRLF in argument files. Print names of changed files." + +import sys, re, os + +def main(): + for filename in sys.argv[1:]: + if os.path.isdir(filename): + print filename, "Directory!" + continue + data = open(filename, "rb").read() + if '\0' in data: + print filename, "Binary!" + continue + newdata = re.sub("\r?\n", "\r\n", data) + if newdata != data: + print filename + f = open(filename, "wb") + f.write(newdata) + f.close() + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/linktree.py b/sys/src/cmd/python/Tools/scripts/linktree.py new file mode 100755 index 000000000..995f2efa9 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/linktree.py @@ -0,0 +1,80 @@ +#! /usr/bin/env python + +# linktree +# +# Make a copy of a directory tree with symbolic links to all files in the +# original tree. +# All symbolic links go to a special symbolic link at the top, so you +# can easily fix things if the original source tree moves. +# See also "mkreal". +# +# usage: mklinks oldtree newtree + +import sys, os + +LINK = '.LINK' # Name of special symlink at the top. + +debug = 0 + +def main(): + if not 3 <= len(sys.argv) <= 4: + print 'usage:', sys.argv[0], 'oldtree newtree [linkto]' + return 2 + oldtree, newtree = sys.argv[1], sys.argv[2] + if len(sys.argv) > 3: + link = sys.argv[3] + link_may_fail = 1 + else: + link = LINK + link_may_fail = 0 + if not os.path.isdir(oldtree): + print oldtree + ': not a directory' + return 1 + try: + os.mkdir(newtree, 0777) + except os.error, msg: + print newtree + ': cannot mkdir:', msg + return 1 + linkname = os.path.join(newtree, link) + try: + os.symlink(os.path.join(os.pardir, oldtree), linkname) + except os.error, msg: + if not link_may_fail: + print linkname + ': cannot symlink:', msg + return 1 + else: + print linkname + ': warning: cannot symlink:', msg + linknames(oldtree, newtree, link) + return 0 + +def linknames(old, new, link): + if debug: print 'linknames', (old, new, link) + try: + names = os.listdir(old) + except os.error, msg: + print old + ': warning: cannot listdir:', msg + return + for name in names: + if name not in (os.curdir, os.pardir): + oldname = os.path.join(old, name) + linkname = os.path.join(link, name) + newname = os.path.join(new, name) + if debug > 1: print oldname, newname, linkname + if os.path.isdir(oldname) and \ + not os.path.islink(oldname): + try: + os.mkdir(newname, 0777) + ok = 1 + except: + print newname + \ + ': warning: cannot mkdir:', msg + ok = 0 + if ok: + linkname = os.path.join(os.pardir, + linkname) + linknames(oldname, newname, linkname) + else: + os.symlink(linkname, newname) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/sys/src/cmd/python/Tools/scripts/lll.py b/sys/src/cmd/python/Tools/scripts/lll.py new file mode 100755 index 000000000..9902d9d39 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/lll.py @@ -0,0 +1,28 @@ +#! /usr/bin/env python + +# Find symbolic links and show where they point to. +# Arguments are directories to search; default is current directory. +# No recursion. +# (This is a totally different program from "findsymlinks.py"!) + +import sys, os + +def lll(dirname): + for name in os.listdir(dirname): + if name not in (os.curdir, os.pardir): + full = os.path.join(dirname, name) + if os.path.islink(full): + print name, '->', os.readlink(full) +def main(): + args = sys.argv[1:] + if not args: args = [os.curdir] + first = 1 + for arg in args: + if len(args) > 1: + if not first: print + first = 0 + print arg + ':' + lll(arg) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/logmerge.py b/sys/src/cmd/python/Tools/scripts/logmerge.py new file mode 100755 index 000000000..edfec2c45 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/logmerge.py @@ -0,0 +1,185 @@ +#! /usr/bin/env python + +"""Consolidate a bunch of CVS or RCS logs read from stdin. + +Input should be the output of a CVS or RCS logging command, e.g. + + cvs log -rrelease14: + +which dumps all log messages from release1.4 upwards (assuming that +release 1.4 was tagged with tag 'release14'). Note the trailing +colon! + +This collects all the revision records and outputs them sorted by date +rather than by file, collapsing duplicate revision record, i.e., +records with the same message for different files. + +The -t option causes it to truncate (discard) the last revision log +entry; this is useful when using something like the above cvs log +command, which shows the revisions including the given tag, while you +probably want everything *since* that tag. + +The -r option reverses the output (oldest first; the default is oldest +last). + +The -b tag option restricts the output to *only* checkin messages +belonging to the given branch tag. The form -b HEAD restricts the +output to checkin messages belonging to the CVS head (trunk). (It +produces some output if tag is a non-branch tag, but this output is +not very useful.) + +-h prints this message and exits. + +XXX This code was created by reverse engineering CVS 1.9 and RCS 5.7 +from their output. +""" + +import os, sys, errno, getopt, re + +sep1 = '='*77 + '\n' # file separator +sep2 = '-'*28 + '\n' # revision separator + +def main(): + """Main program""" + truncate_last = 0 + reverse = 0 + branch = None + opts, args = getopt.getopt(sys.argv[1:], "trb:h") + for o, a in opts: + if o == '-t': + truncate_last = 1 + elif o == '-r': + reverse = 1 + elif o == '-b': + branch = a + elif o == '-h': + print __doc__ + sys.exit(0) + database = [] + while 1: + chunk = read_chunk(sys.stdin) + if not chunk: + break + records = digest_chunk(chunk, branch) + if truncate_last: + del records[-1] + database[len(database):] = records + database.sort() + if not reverse: + database.reverse() + format_output(database) + +def read_chunk(fp): + """Read a chunk -- data for one file, ending with sep1. + + Split the chunk in parts separated by sep2. + + """ + chunk = [] + lines = [] + while 1: + line = fp.readline() + if not line: + break + if line == sep1: + if lines: + chunk.append(lines) + break + if line == sep2: + if lines: + chunk.append(lines) + lines = [] + else: + lines.append(line) + return chunk + +def digest_chunk(chunk, branch=None): + """Digest a chunk -- extract working file name and revisions""" + lines = chunk[0] + key = 'Working file:' + keylen = len(key) + for line in lines: + if line[:keylen] == key: + working_file = line[keylen:].strip() + break + else: + working_file = None + if branch is None: + pass + elif branch == "HEAD": + branch = re.compile(r"^\d+\.\d+$") + else: + revisions = {} + key = 'symbolic names:\n' + found = 0 + for line in lines: + if line == key: + found = 1 + elif found: + if line[0] in '\t ': + tag, rev = line.split() + if tag[-1] == ':': + tag = tag[:-1] + revisions[tag] = rev + else: + found = 0 + rev = revisions.get(branch) + branch = re.compile(r"^<>$") # <> to force a mismatch by default + if rev: + if rev.find('.0.') >= 0: + rev = rev.replace('.0.', '.') + branch = re.compile(r"^" + re.escape(rev) + r"\.\d+$") + records = [] + for lines in chunk[1:]: + revline = lines[0] + dateline = lines[1] + text = lines[2:] + words = dateline.split() + author = None + if len(words) >= 3 and words[0] == 'date:': + dateword = words[1] + timeword = words[2] + if timeword[-1:] == ';': + timeword = timeword[:-1] + date = dateword + ' ' + timeword + if len(words) >= 5 and words[3] == 'author:': + author = words[4] + if author[-1:] == ';': + author = author[:-1] + else: + date = None + text.insert(0, revline) + words = revline.split() + if len(words) >= 2 and words[0] == 'revision': + rev = words[1] + else: + # No 'revision' line -- weird... + rev = None + text.insert(0, revline) + if branch: + if rev is None or not branch.match(rev): + continue + records.append((date, working_file, rev, author, text)) + return records + +def format_output(database): + prevtext = None + prev = [] + database.append((None, None, None, None, None)) # Sentinel + for (date, working_file, rev, author, text) in database: + if text != prevtext: + if prev: + print sep2, + for (p_date, p_working_file, p_rev, p_author) in prev: + print p_date, p_author, p_working_file, p_rev + sys.stdout.writelines(prevtext) + prev = [] + prev.append((date, working_file, rev, author)) + prevtext = text + +if __name__ == '__main__': + try: + main() + except IOError, e: + if e.errno != errno.EPIPE: + raise diff --git a/sys/src/cmd/python/Tools/scripts/mailerdaemon.py b/sys/src/cmd/python/Tools/scripts/mailerdaemon.py new file mode 100755 index 000000000..85f90aa61 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/mailerdaemon.py @@ -0,0 +1,237 @@ +"""mailerdaemon - classes to parse mailer-daemon messages""" + +import rfc822 +import calendar +import re +import os +import sys + +Unparseable = 'mailerdaemon.Unparseable' + +class ErrorMessage(rfc822.Message): + def __init__(self, fp): + rfc822.Message.__init__(self, fp) + self.sub = '' + + def is_warning(self): + sub = self.getheader('Subject') + if not sub: + return 0 + sub = sub.lower() + if sub.startswith('waiting mail'): return 1 + if 'warning' in sub: return 1 + self.sub = sub + return 0 + + def get_errors(self): + for p in EMPARSERS: + self.rewindbody() + try: + return p(self.fp, self.sub) + except Unparseable: + pass + raise Unparseable + +# List of re's or tuples of re's. +# If a re, it should contain at least a group (?P<email>...) which +# should refer to the email address. The re can also contain a group +# (?P<reason>...) which should refer to the reason (error message). +# If no reason is present, the emparse_list_reason list is used to +# find a reason. +# If a tuple, the tuple should contain 2 re's. The first re finds a +# location, the second re is repeated one or more times to find +# multiple email addresses. The second re is matched (not searched) +# where the previous match ended. +# The re's are compiled using the re module. +emparse_list_list = [ + 'error: (?P<reason>unresolvable): (?P<email>.+)', + ('----- The following addresses had permanent fatal errors -----\n', + '(?P<email>[^ \n].*)\n( .*\n)?'), + 'remote execution.*\n.*rmail (?P<email>.+)', + ('The following recipients did not receive your message:\n\n', + ' +(?P<email>.*)\n(The following recipients did not receive your message:\n\n)?'), + '------- Failure Reasons --------\n\n(?P<reason>.*)\n(?P<email>.*)', + '^<(?P<email>.*)>:\n(?P<reason>.*)', + '^(?P<reason>User mailbox exceeds allowed size): (?P<email>.+)', + '^5\\d{2} <(?P<email>[^\n>]+)>\\.\\.\\. (?P<reason>.+)', + '^Original-Recipient: rfc822;(?P<email>.*)', + '^did not reach the following recipient\\(s\\):\n\n(?P<email>.*) on .*\n +(?P<reason>.*)', + '^ <(?P<email>[^\n>]+)> \\.\\.\\. (?P<reason>.*)', + '^Report on your message to: (?P<email>.*)\nReason: (?P<reason>.*)', + '^Your message was not delivered to +(?P<email>.*)\n +for the following reason:\n +(?P<reason>.*)', + '^ was not +(?P<email>[^ \n].*?) *\n.*\n.*\n.*\n because:.*\n +(?P<reason>[^ \n].*?) *\n', + ] +# compile the re's in the list and store them in-place. +for i in range(len(emparse_list_list)): + x = emparse_list_list[i] + if type(x) is type(''): + x = re.compile(x, re.MULTILINE) + else: + xl = [] + for x in x: + xl.append(re.compile(x, re.MULTILINE)) + x = tuple(xl) + del xl + emparse_list_list[i] = x + del x +del i + +# list of re's used to find reasons (error messages). +# if a string, "<>" is replaced by a copy of the email address. +# The expressions are searched for in order. After the first match, +# no more expressions are searched for. So, order is important. +emparse_list_reason = [ + r'^5\d{2} <>\.\.\. (?P<reason>.*)', + '<>\.\.\. (?P<reason>.*)', + re.compile(r'^<<< 5\d{2} (?P<reason>.*)', re.MULTILINE), + re.compile('===== stderr was =====\nrmail: (?P<reason>.*)'), + re.compile('^Diagnostic-Code: (?P<reason>.*)', re.MULTILINE), + ] +emparse_list_from = re.compile('^From:', re.IGNORECASE|re.MULTILINE) +def emparse_list(fp, sub): + data = fp.read() + res = emparse_list_from.search(data) + if res is None: + from_index = len(data) + else: + from_index = res.start(0) + errors = [] + emails = [] + reason = None + for regexp in emparse_list_list: + if type(regexp) is type(()): + res = regexp[0].search(data, 0, from_index) + if res is not None: + try: + reason = res.group('reason') + except IndexError: + pass + while 1: + res = regexp[1].match(data, res.end(0), from_index) + if res is None: + break + emails.append(res.group('email')) + break + else: + res = regexp.search(data, 0, from_index) + if res is not None: + emails.append(res.group('email')) + try: + reason = res.group('reason') + except IndexError: + pass + break + if not emails: + raise Unparseable + if not reason: + reason = sub + if reason[:15] == 'returned mail: ': + reason = reason[15:] + for regexp in emparse_list_reason: + if type(regexp) is type(''): + for i in range(len(emails)-1,-1,-1): + email = emails[i] + exp = re.compile(re.escape(email).join(regexp.split('<>')), re.MULTILINE) + res = exp.search(data) + if res is not None: + errors.append(' '.join((email.strip()+': '+res.group('reason')).split())) + del emails[i] + continue + res = regexp.search(data) + if res is not None: + reason = res.group('reason') + break + for email in emails: + errors.append(' '.join((email.strip()+': '+reason).split())) + return errors + +EMPARSERS = [emparse_list, ] + +def sort_numeric(a, b): + a = int(a) + b = int(b) + if a < b: return -1 + elif a > b: return 1 + else: return 0 + +def parsedir(dir, modify): + os.chdir(dir) + pat = re.compile('^[0-9]*$') + errordict = {} + errorfirst = {} + errorlast = {} + nok = nwarn = nbad = 0 + + # find all numeric file names and sort them + files = filter(lambda fn, pat=pat: pat.match(fn) is not None, os.listdir('.')) + files.sort(sort_numeric) + + for fn in files: + # Lets try to parse the file. + fp = open(fn) + m = ErrorMessage(fp) + sender = m.getaddr('From') + print '%s\t%-40s\t'%(fn, sender[1]), + + if m.is_warning(): + fp.close() + print 'warning only' + nwarn = nwarn + 1 + if modify: + os.rename(fn, ','+fn) +## os.unlink(fn) + continue + + try: + errors = m.get_errors() + except Unparseable: + print '** Not parseable' + nbad = nbad + 1 + fp.close() + continue + print len(errors), 'errors' + + # Remember them + for e in errors: + try: + mm, dd = m.getdate('date')[1:1+2] + date = '%s %02d' % (calendar.month_abbr[mm], dd) + except: + date = '??????' + if not errordict.has_key(e): + errordict[e] = 1 + errorfirst[e] = '%s (%s)' % (fn, date) + else: + errordict[e] = errordict[e] + 1 + errorlast[e] = '%s (%s)' % (fn, date) + + fp.close() + nok = nok + 1 + if modify: + os.rename(fn, ','+fn) +## os.unlink(fn) + + print '--------------' + print nok, 'files parsed,',nwarn,'files warning-only,', + print nbad,'files unparseable' + print '--------------' + list = [] + for e in errordict.keys(): + list.append((errordict[e], errorfirst[e], errorlast[e], e)) + list.sort() + for num, first, last, e in list: + print '%d %s - %s\t%s' % (num, first, last, e) + +def main(): + modify = 0 + if len(sys.argv) > 1 and sys.argv[1] == '-d': + modify = 1 + del sys.argv[1] + if len(sys.argv) > 1: + for folder in sys.argv[1:]: + parsedir(folder, modify) + else: + parsedir('/ufs/jack/Mail/errorsinbox', modify) + +if __name__ == '__main__' or sys.argv[0] == __name__: + main() diff --git a/sys/src/cmd/python/Tools/scripts/md5sum.py b/sys/src/cmd/python/Tools/scripts/md5sum.py new file mode 100644 index 000000000..e045f1a71 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/md5sum.py @@ -0,0 +1,90 @@ +#! /usr/bin/env python + +"""Python utility to print MD5 checksums of argument files. +""" + + +bufsize = 8096 +fnfilter = None +rmode = 'rb' + +usage = """ +usage: sum5 [-b] [-t] [-l] [-s bufsize] [file ...] +-b : read files in binary mode (default) +-t : read files in text mode (you almost certainly don't want this!) +-l : print last pathname component only +-s bufsize: read buffer size (default %d) +file ... : files to sum; '-' or no files means stdin +""" % bufsize + +import sys +import os +import getopt +import md5 + +def sum(*files): + sts = 0 + if files and isinstance(files[-1], file): + out, files = files[-1], files[:-1] + else: + out = sys.stdout + if len(files) == 1 and not isinstance(files[0], str): + files = files[0] + for f in files: + if isinstance(f, str): + if f == '-': + sts = printsumfp(sys.stdin, '<stdin>', out) or sts + else: + sts = printsum(f, out) or sts + else: + sts = sum(f, out) or sts + return sts + +def printsum(filename, out=sys.stdout): + try: + fp = open(filename, rmode) + except IOError, msg: + sys.stderr.write('%s: Can\'t open: %s\n' % (filename, msg)) + return 1 + if fnfilter: + filename = fnfilter(filename) + sts = printsumfp(fp, filename, out) + fp.close() + return sts + +def printsumfp(fp, filename, out=sys.stdout): + m = md5.new() + try: + while 1: + data = fp.read(bufsize) + if not data: + break + m.update(data) + except IOError, msg: + sys.stderr.write('%s: I/O error: %s\n' % (filename, msg)) + return 1 + out.write('%s %s\n' % (m.hexdigest(), filename)) + return 0 + +def main(args = sys.argv[1:], out=sys.stdout): + global fnfilter, rmode, bufsize + try: + opts, args = getopt.getopt(args, 'blts:') + except getopt.error, msg: + sys.stderr.write('%s: %s\n%s' % (sys.argv[0], msg, usage)) + return 2 + for o, a in opts: + if o == '-l': + fnfilter = os.path.basename + elif o == '-b': + rmode = 'rb' + elif o == '-t': + rmode = 'r' + elif o == '-s': + bufsize = int(a) + if not args: + args = ['-'] + return sum(args, out) + +if __name__ == '__main__' or __name__ == sys.argv[0]: + sys.exit(main(sys.argv[1:], sys.stdout)) diff --git a/sys/src/cmd/python/Tools/scripts/methfix.py b/sys/src/cmd/python/Tools/scripts/methfix.py new file mode 100755 index 000000000..b81871ff6 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/methfix.py @@ -0,0 +1,171 @@ +#! /usr/bin/env python + +# Fix Python source files to avoid using +# def method(self, (arg1, ..., argn)): +# instead of the more rational +# def method(self, arg1, ..., argn): +# +# Command line arguments are files or directories to be processed. +# Directories are searched recursively for files whose name looks +# like a python module. +# Symbolic links are always ignored (except as explicit directory +# arguments). Of course, the original file is kept as a back-up +# (with a "~" attached to its name). +# It complains about binaries (files containing null bytes) +# and about files that are ostensibly not Python files: if the first +# line starts with '#!' and does not contain the string 'python'. +# +# Changes made are reported to stdout in a diff-like format. +# +# Undoubtedly you can do this using find and sed or perl, but this is +# a nice example of Python code that recurses down a directory tree +# and uses regular expressions. Also note several subtleties like +# preserving the file's mode and avoiding to even write a temp file +# when no changes are needed for a file. +# +# NB: by changing only the function fixline() you can turn this +# into a program for a different change to Python programs... + +import sys +import re +import os +from stat import * + +err = sys.stderr.write +dbg = err +rep = sys.stdout.write + +def main(): + bad = 0 + if not sys.argv[1:]: # No arguments + err('usage: ' + sys.argv[0] + ' file-or-directory ...\n') + sys.exit(2) + for arg in sys.argv[1:]: + if os.path.isdir(arg): + if recursedown(arg): bad = 1 + elif os.path.islink(arg): + err(arg + ': will not process symbolic links\n') + bad = 1 + else: + if fix(arg): bad = 1 + sys.exit(bad) + +ispythonprog = re.compile('^[a-zA-Z0-9_]+\.py$') +def ispython(name): + return ispythonprog.match(name) >= 0 + +def recursedown(dirname): + dbg('recursedown(%r)\n' % (dirname,)) + bad = 0 + try: + names = os.listdir(dirname) + except os.error, msg: + err('%s: cannot list directory: %r\n' % (dirname, msg)) + return 1 + names.sort() + subdirs = [] + for name in names: + if name in (os.curdir, os.pardir): continue + fullname = os.path.join(dirname, name) + if os.path.islink(fullname): pass + elif os.path.isdir(fullname): + subdirs.append(fullname) + elif ispython(name): + if fix(fullname): bad = 1 + for fullname in subdirs: + if recursedown(fullname): bad = 1 + return bad + +def fix(filename): +## dbg('fix(%r)\n' % (filename,)) + try: + f = open(filename, 'r') + except IOError, msg: + err('%s: cannot open: %r\n' % (filename, msg)) + return 1 + head, tail = os.path.split(filename) + tempname = os.path.join(head, '@' + tail) + g = None + # If we find a match, we rewind the file and start over but + # now copy everything to a temp file. + lineno = 0 + while 1: + line = f.readline() + if not line: break + lineno = lineno + 1 + if g is None and '\0' in line: + # Check for binary files + err(filename + ': contains null bytes; not fixed\n') + f.close() + return 1 + if lineno == 1 and g is None and line[:2] == '#!': + # Check for non-Python scripts + words = line[2:].split() + if words and re.search('[pP]ython', words[0]) < 0: + msg = filename + ': ' + words[0] + msg = msg + ' script; not fixed\n' + err(msg) + f.close() + return 1 + while line[-2:] == '\\\n': + nextline = f.readline() + if not nextline: break + line = line + nextline + lineno = lineno + 1 + newline = fixline(line) + if newline != line: + if g is None: + try: + g = open(tempname, 'w') + except IOError, msg: + f.close() + err('%s: cannot create: %r\n' % (tempname, msg)) + return 1 + f.seek(0) + lineno = 0 + rep(filename + ':\n') + continue # restart from the beginning + rep(repr(lineno) + '\n') + rep('< ' + line) + rep('> ' + newline) + if g is not None: + g.write(newline) + + # End of file + f.close() + if not g: return 0 # No changes + + # Finishing touch -- move files + + # First copy the file's mode to the temp file + try: + statbuf = os.stat(filename) + os.chmod(tempname, statbuf[ST_MODE] & 07777) + except os.error, msg: + err('%s: warning: chmod failed (%r)\n' % (tempname, msg)) + # Then make a backup of the original file as filename~ + try: + os.rename(filename, filename + '~') + except os.error, msg: + err('%s: warning: backup failed (%r)\n' % (filename, msg)) + # Now move the temp file to the original file + try: + os.rename(tempname, filename) + except os.error, msg: + err('%s: rename failed (%r)\n' % (filename, msg)) + return 1 + # Return succes + return 0 + + +fixpat = '^[ \t]+def +[a-zA-Z0-9_]+ *( *self *, *(( *(.*) *)) *) *:' +fixprog = re.compile(fixpat) + +def fixline(line): + if fixprog.match(line) >= 0: + (a, b), (c, d) = fixprog.regs[1:3] + line = line[:a] + line[c:d] + line[b:] + return line + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/mkreal.py b/sys/src/cmd/python/Tools/scripts/mkreal.py new file mode 100755 index 000000000..fb9e9a58b --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/mkreal.py @@ -0,0 +1,66 @@ +#! /usr/bin/env python + +# mkreal +# +# turn a symlink to a directory into a real directory + +import sys +import os +from stat import * + +join = os.path.join + +error = 'mkreal error' + +BUFSIZE = 32*1024 + +def mkrealfile(name): + st = os.stat(name) # Get the mode + mode = S_IMODE(st[ST_MODE]) + linkto = os.readlink(name) # Make sure again it's a symlink + f_in = open(name, 'r') # This ensures it's a file + os.unlink(name) + f_out = open(name, 'w') + while 1: + buf = f_in.read(BUFSIZE) + if not buf: break + f_out.write(buf) + del f_out # Flush data to disk before changing mode + os.chmod(name, mode) + +def mkrealdir(name): + st = os.stat(name) # Get the mode + mode = S_IMODE(st[ST_MODE]) + linkto = os.readlink(name) + files = os.listdir(name) + os.unlink(name) + os.mkdir(name, mode) + os.chmod(name, mode) + linkto = join(os.pardir, linkto) + # + for filename in files: + if filename not in (os.curdir, os.pardir): + os.symlink(join(linkto, filename), join(name, filename)) + +def main(): + sys.stdout = sys.stderr + progname = os.path.basename(sys.argv[0]) + if progname == '-c': progname = 'mkreal' + args = sys.argv[1:] + if not args: + print 'usage:', progname, 'path ...' + sys.exit(2) + status = 0 + for name in args: + if not os.path.islink(name): + print progname+':', name+':', 'not a symlink' + status = 1 + else: + if os.path.isdir(name): + mkrealdir(name) + else: + mkrealfile(name) + sys.exit(status) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/ndiff.py b/sys/src/cmd/python/Tools/scripts/ndiff.py new file mode 100755 index 000000000..88712b814 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/ndiff.py @@ -0,0 +1,133 @@ +#! /usr/bin/env python + +# Module ndiff version 1.7.0 +# Released to the public domain 08-Dec-2000, +# by Tim Peters (tim.one@home.com). + +# Provided as-is; use at your own risk; no warranty; no promises; enjoy! + +# ndiff.py is now simply a front-end to the difflib.ndiff() function. +# Originally, it contained the difflib.SequenceMatcher class as well. +# This completes the raiding of reusable code from this formerly +# self-contained script. + +"""ndiff [-q] file1 file2 + or +ndiff (-r1 | -r2) < ndiff_output > file1_or_file2 + +Print a human-friendly file difference report to stdout. Both inter- +and intra-line differences are noted. In the second form, recreate file1 +(-r1) or file2 (-r2) on stdout, from an ndiff report on stdin. + +In the first form, if -q ("quiet") is not specified, the first two lines +of output are + +-: file1 ++: file2 + +Each remaining line begins with a two-letter code: + + "- " line unique to file1 + "+ " line unique to file2 + " " line common to both files + "? " line not present in either input file + +Lines beginning with "? " attempt to guide the eye to intraline +differences, and were not present in either input file. These lines can be +confusing if the source files contain tab characters. + +The first file can be recovered by retaining only lines that begin with +" " or "- ", and deleting those 2-character prefixes; use ndiff with -r1. + +The second file can be recovered similarly, but by retaining only " " and +"+ " lines; use ndiff with -r2; or, on Unix, the second file can be +recovered by piping the output through + + sed -n '/^[+ ] /s/^..//p' +""" + +__version__ = 1, 7, 0 + +import difflib, sys + +def fail(msg): + out = sys.stderr.write + out(msg + "\n\n") + out(__doc__) + return 0 + +# open a file & return the file object; gripe and return 0 if it +# couldn't be opened +def fopen(fname): + try: + return open(fname, 'U') + except IOError, detail: + return fail("couldn't open " + fname + ": " + str(detail)) + +# open two files & spray the diff to stdout; return false iff a problem +def fcompare(f1name, f2name): + f1 = fopen(f1name) + f2 = fopen(f2name) + if not f1 or not f2: + return 0 + + a = f1.readlines(); f1.close() + b = f2.readlines(); f2.close() + for line in difflib.ndiff(a, b): + print line, + + return 1 + +# crack args (sys.argv[1:] is normal) & compare; +# return false iff a problem + +def main(args): + import getopt + try: + opts, args = getopt.getopt(args, "qr:") + except getopt.error, detail: + return fail(str(detail)) + noisy = 1 + qseen = rseen = 0 + for opt, val in opts: + if opt == "-q": + qseen = 1 + noisy = 0 + elif opt == "-r": + rseen = 1 + whichfile = val + if qseen and rseen: + return fail("can't specify both -q and -r") + if rseen: + if args: + return fail("no args allowed with -r option") + if whichfile in ("1", "2"): + restore(whichfile) + return 1 + return fail("-r value must be 1 or 2") + if len(args) != 2: + return fail("need 2 filename args") + f1name, f2name = args + if noisy: + print '-:', f1name + print '+:', f2name + return fcompare(f1name, f2name) + +# read ndiff output from stdin, and print file1 (which=='1') or +# file2 (which=='2') to stdout + +def restore(which): + restored = difflib.restore(sys.stdin.readlines(), which) + sys.stdout.writelines(restored) + +if __name__ == '__main__': + args = sys.argv[1:] + if "-profile" in args: + import profile, pstats + args.remove("-profile") + statf = "ndiff.pro" + profile.run("main(args)", statf) + stats = pstats.Stats(statf) + stats.strip_dirs().sort_stats('time').print_stats() + else: + main(args) diff --git a/sys/src/cmd/python/Tools/scripts/nm2def.py b/sys/src/cmd/python/Tools/scripts/nm2def.py new file mode 100755 index 000000000..6887ee282 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/nm2def.py @@ -0,0 +1,103 @@ +#! /usr/bin/env python +"""nm2def.py + +Helpers to extract symbols from Unix libs and auto-generate +Windows definition files from them. Depends on nm(1). Tested +on Linux and Solaris only (-p option to nm is for Solaris only). + +By Marc-Andre Lemburg, Aug 1998. + +Additional notes: the output of nm is supposed to look like this: + +acceler.o: +000001fd T PyGrammar_AddAccelerators + U PyGrammar_FindDFA +00000237 T PyGrammar_RemoveAccelerators + U _IO_stderr_ + U exit + U fprintf + U free + U malloc + U printf + +grammar1.o: +00000000 T PyGrammar_FindDFA +00000034 T PyGrammar_LabelRepr + U _PyParser_TokenNames + U abort + U printf + U sprintf + +... + +Even if this isn't the default output of your nm, there is generally an +option to produce this format (since it is the original v7 Unix format). + +""" +import os,re,sys + +PYTHONLIB = 'libpython'+sys.version[:3]+'.a' +PC_PYTHONLIB = 'Python'+sys.version[0]+sys.version[2]+'.dll' +NM = 'nm -p -g %s' # For Linux, use "nm -g %s" + +def symbols(lib=PYTHONLIB,types=('T','C','D')): + + lines = os.popen(NM % lib).readlines() + lines = [s.strip() for s in lines] + symbols = {} + for line in lines: + if len(line) == 0 or ':' in line: + continue + items = line.split() + if len(items) != 3: + continue + address, type, name = items + if type not in types: + continue + symbols[name] = address,type + return symbols + +def export_list(symbols): + + data = [] + code = [] + for name,(addr,type) in symbols.items(): + if type in ('C','D'): + data.append('\t'+name) + else: + code.append('\t'+name) + data.sort() + data.append('') + code.sort() + return ' DATA\n'.join(data)+'\n'+'\n'.join(code) + +# Definition file template +DEF_TEMPLATE = """\ +EXPORTS +%s +""" + +# Special symbols that have to be included even though they don't +# pass the filter +SPECIALS = ( + ) + +def filter_Python(symbols,specials=SPECIALS): + + for name in symbols.keys(): + if name[:2] == 'Py' or name[:3] == '_Py': + pass + elif name not in specials: + del symbols[name] + +def main(): + + s = symbols(PYTHONLIB) + filter_Python(s) + exports = export_list(s) + f = sys.stdout # open('PC/python_nt.def','w') + f.write(DEF_TEMPLATE % (exports)) + f.close() + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/objgraph.py b/sys/src/cmd/python/Tools/scripts/objgraph.py new file mode 100755 index 000000000..f74c2b670 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/objgraph.py @@ -0,0 +1,215 @@ +#! /usr/bin/env python + +# objgraph +# +# Read "nm -o" input (on IRIX: "nm -Bo") of a set of libraries or modules +# and print various interesting listings, such as: +# +# - which names are used but not defined in the set (and used where), +# - which names are defined in the set (and where), +# - which modules use which other modules, +# - which modules are used by which other modules. +# +# Usage: objgraph [-cdu] [file] ... +# -c: print callers per objectfile +# -d: print callees per objectfile +# -u: print usage of undefined symbols +# If none of -cdu is specified, all are assumed. +# Use "nm -o" to generate the input (on IRIX: "nm -Bo"), +# e.g.: nm -o /lib/libc.a | objgraph + + +import sys +import os +import getopt +import re + +# Types of symbols. +# +definitions = 'TRGDSBAEC' +externals = 'UV' +ignore = 'Nntrgdsbavuc' + +# Regular expression to parse "nm -o" output. +# +matcher = re.compile('(.*):\t?........ (.) (.*)$') + +# Store "item" in "dict" under "key". +# The dictionary maps keys to lists of items. +# If there is no list for the key yet, it is created. +# +def store(dict, key, item): + if dict.has_key(key): + dict[key].append(item) + else: + dict[key] = [item] + +# Return a flattened version of a list of strings: the concatenation +# of its elements with intervening spaces. +# +def flat(list): + s = '' + for item in list: + s = s + ' ' + item + return s[1:] + +# Global variables mapping defined/undefined names to files and back. +# +file2undef = {} +def2file = {} +file2def = {} +undef2file = {} + +# Read one input file and merge the data into the tables. +# Argument is an open file. +# +def readinput(fp): + while 1: + s = fp.readline() + if not s: + break + # If you get any output from this line, + # it is probably caused by an unexpected input line: + if matcher.search(s) < 0: s; continue # Shouldn't happen + (ra, rb), (r1a, r1b), (r2a, r2b), (r3a, r3b) = matcher.regs[:4] + fn, name, type = s[r1a:r1b], s[r3a:r3b], s[r2a:r2b] + if type in definitions: + store(def2file, name, fn) + store(file2def, fn, name) + elif type in externals: + store(file2undef, fn, name) + store(undef2file, name, fn) + elif not type in ignore: + print fn + ':' + name + ': unknown type ' + type + +# Print all names that were undefined in some module and where they are +# defined. +# +def printcallee(): + flist = file2undef.keys() + flist.sort() + for filename in flist: + print filename + ':' + elist = file2undef[filename] + elist.sort() + for ext in elist: + if len(ext) >= 8: + tabs = '\t' + else: + tabs = '\t\t' + if not def2file.has_key(ext): + print '\t' + ext + tabs + ' *undefined' + else: + print '\t' + ext + tabs + flat(def2file[ext]) + +# Print for each module the names of the other modules that use it. +# +def printcaller(): + files = file2def.keys() + files.sort() + for filename in files: + callers = [] + for label in file2def[filename]: + if undef2file.has_key(label): + callers = callers + undef2file[label] + if callers: + callers.sort() + print filename + ':' + lastfn = '' + for fn in callers: + if fn <> lastfn: + print '\t' + fn + lastfn = fn + else: + print filename + ': unused' + +# Print undefined names and where they are used. +# +def printundef(): + undefs = {} + for filename in file2undef.keys(): + for ext in file2undef[filename]: + if not def2file.has_key(ext): + store(undefs, ext, filename) + elist = undefs.keys() + elist.sort() + for ext in elist: + print ext + ':' + flist = undefs[ext] + flist.sort() + for filename in flist: + print '\t' + filename + +# Print warning messages about names defined in more than one file. +# +def warndups(): + savestdout = sys.stdout + sys.stdout = sys.stderr + names = def2file.keys() + names.sort() + for name in names: + if len(def2file[name]) > 1: + print 'warning:', name, 'multiply defined:', + print flat(def2file[name]) + sys.stdout = savestdout + +# Main program +# +def main(): + try: + optlist, args = getopt.getopt(sys.argv[1:], 'cdu') + except getopt.error: + sys.stdout = sys.stderr + print 'Usage:', os.path.basename(sys.argv[0]), + print '[-cdu] [file] ...' + print '-c: print callers per objectfile' + print '-d: print callees per objectfile' + print '-u: print usage of undefined symbols' + print 'If none of -cdu is specified, all are assumed.' + print 'Use "nm -o" to generate the input (on IRIX: "nm -Bo"),' + print 'e.g.: nm -o /lib/libc.a | objgraph' + return 1 + optu = optc = optd = 0 + for opt, void in optlist: + if opt == '-u': + optu = 1 + elif opt == '-c': + optc = 1 + elif opt == '-d': + optd = 1 + if optu == optc == optd == 0: + optu = optc = optd = 1 + if not args: + args = ['-'] + for filename in args: + if filename == '-': + readinput(sys.stdin) + else: + readinput(open(filename, 'r')) + # + warndups() + # + more = (optu + optc + optd > 1) + if optd: + if more: + print '---------------All callees------------------' + printcallee() + if optu: + if more: + print '---------------Undefined callees------------' + printundef() + if optc: + if more: + print '---------------All Callers------------------' + printcaller() + return 0 + +# Call the main program. +# Use its return value as exit status. +# Catch interrupts to avoid stack trace. +# +if __name__ == '__main__': + try: + sys.exit(main()) + except KeyboardInterrupt: + sys.exit(1) diff --git a/sys/src/cmd/python/Tools/scripts/parseentities.py b/sys/src/cmd/python/Tools/scripts/parseentities.py new file mode 100755 index 000000000..cf4e17c1f --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/parseentities.py @@ -0,0 +1,64 @@ +#!/usr/local/bin/python +""" Utility for parsing HTML entity definitions available from: + + http://www.w3.org/ as e.g. + http://www.w3.org/TR/REC-html40/HTMLlat1.ent + + Input is read from stdin, output is written to stdout in form of a + Python snippet defining a dictionary "entitydefs" mapping literal + entity name to character or numeric entity. + + Marc-Andre Lemburg, mal@lemburg.com, 1999. + Use as you like. NO WARRANTIES. + +""" +import re,sys +import TextTools + +entityRE = re.compile('<!ENTITY +(\w+) +CDATA +"([^"]+)" +-- +((?:.|\n)+?) *-->') + +def parse(text,pos=0,endpos=None): + + pos = 0 + if endpos is None: + endpos = len(text) + d = {} + while 1: + m = entityRE.search(text,pos,endpos) + if not m: + break + name,charcode,comment = m.groups() + d[name] = charcode,comment + pos = m.end() + return d + +def writefile(f,defs): + + f.write("entitydefs = {\n") + items = defs.items() + items.sort() + for name,(charcode,comment) in items: + if charcode[:2] == '&#': + code = int(charcode[2:-1]) + if code < 256: + charcode = "'\%o'" % code + else: + charcode = repr(charcode) + else: + charcode = repr(charcode) + comment = TextTools.collapse(comment) + f.write(" '%s':\t%s, \t# %s\n" % (name,charcode,comment)) + f.write('\n}\n') + +if __name__ == '__main__': + if len(sys.argv) > 1: + infile = open(sys.argv[1]) + else: + infile = sys.stdin + if len(sys.argv) > 2: + outfile = open(sys.argv[2],'w') + else: + outfile = sys.stdout + text = infile.read() + defs = parse(text) + writefile(outfile,defs) diff --git a/sys/src/cmd/python/Tools/scripts/pathfix.py b/sys/src/cmd/python/Tools/scripts/pathfix.py new file mode 100755 index 000000000..7f6f191bb --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/pathfix.py @@ -0,0 +1,149 @@ +#! /usr/bin/env python + +# Change the #! line occurring in Python scripts. The new interpreter +# pathname must be given with a -i option. +# +# Command line arguments are files or directories to be processed. +# Directories are searched recursively for files whose name looks +# like a python module. +# Symbolic links are always ignored (except as explicit directory +# arguments). Of course, the original file is kept as a back-up +# (with a "~" attached to its name). +# +# Undoubtedly you can do this using find and sed or perl, but this is +# a nice example of Python code that recurses down a directory tree +# and uses regular expressions. Also note several subtleties like +# preserving the file's mode and avoiding to even write a temp file +# when no changes are needed for a file. +# +# NB: by changing only the function fixfile() you can turn this +# into a program for a different change to Python programs... + +import sys +import re +import os +from stat import * +import getopt + +err = sys.stderr.write +dbg = err +rep = sys.stdout.write + +new_interpreter = None + +def main(): + global new_interpreter + usage = ('usage: %s -i /interpreter file-or-directory ...\n' % + sys.argv[0]) + try: + opts, args = getopt.getopt(sys.argv[1:], 'i:') + except getopt.error, msg: + err(msg + '\n') + err(usage) + sys.exit(2) + for o, a in opts: + if o == '-i': + new_interpreter = a + if not new_interpreter or new_interpreter[0] != '/' or not args: + err('-i option or file-or-directory missing\n') + err(usage) + sys.exit(2) + bad = 0 + for arg in args: + if os.path.isdir(arg): + if recursedown(arg): bad = 1 + elif os.path.islink(arg): + err(arg + ': will not process symbolic links\n') + bad = 1 + else: + if fix(arg): bad = 1 + sys.exit(bad) + +ispythonprog = re.compile('^[a-zA-Z0-9_]+\.py$') +def ispython(name): + return ispythonprog.match(name) >= 0 + +def recursedown(dirname): + dbg('recursedown(%r)\n' % (dirname,)) + bad = 0 + try: + names = os.listdir(dirname) + except os.error, msg: + err('%s: cannot list directory: %r\n' % (dirname, msg)) + return 1 + names.sort() + subdirs = [] + for name in names: + if name in (os.curdir, os.pardir): continue + fullname = os.path.join(dirname, name) + if os.path.islink(fullname): pass + elif os.path.isdir(fullname): + subdirs.append(fullname) + elif ispython(name): + if fix(fullname): bad = 1 + for fullname in subdirs: + if recursedown(fullname): bad = 1 + return bad + +def fix(filename): +## dbg('fix(%r)\n' % (filename,)) + try: + f = open(filename, 'r') + except IOError, msg: + err('%s: cannot open: %r\n' % (filename, msg)) + return 1 + line = f.readline() + fixed = fixline(line) + if line == fixed: + rep(filename+': no change\n') + f.close() + return + head, tail = os.path.split(filename) + tempname = os.path.join(head, '@' + tail) + try: + g = open(tempname, 'w') + except IOError, msg: + f.close() + err('%s: cannot create: %r\n' % (tempname, msg)) + return 1 + rep(filename + ': updating\n') + g.write(fixed) + BUFSIZE = 8*1024 + while 1: + buf = f.read(BUFSIZE) + if not buf: break + g.write(buf) + g.close() + f.close() + + # Finishing touch -- move files + + # First copy the file's mode to the temp file + try: + statbuf = os.stat(filename) + os.chmod(tempname, statbuf[ST_MODE] & 07777) + except os.error, msg: + err('%s: warning: chmod failed (%r)\n' % (tempname, msg)) + # Then make a backup of the original file as filename~ + try: + os.rename(filename, filename + '~') + except os.error, msg: + err('%s: warning: backup failed (%r)\n' % (filename, msg)) + # Now move the temp file to the original file + try: + os.rename(tempname, filename) + except os.error, msg: + err('%s: rename failed (%r)\n' % (filename, msg)) + return 1 + # Return succes + return 0 + +def fixline(line): + if not line.startswith('#!'): + return line + if "python" not in line: + return line + return '#! %s\n' % new_interpreter + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/pdeps.py b/sys/src/cmd/python/Tools/scripts/pdeps.py new file mode 100755 index 000000000..da63e357d --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/pdeps.py @@ -0,0 +1,167 @@ +#! /usr/bin/env python + +# pdeps +# +# Find dependencies between a bunch of Python modules. +# +# Usage: +# pdeps file1.py file2.py ... +# +# Output: +# Four tables separated by lines like '--- Closure ---': +# 1) Direct dependencies, listing which module imports which other modules +# 2) The inverse of (1) +# 3) Indirect dependencies, or the closure of the above +# 4) The inverse of (3) +# +# To do: +# - command line options to select output type +# - option to automatically scan the Python library for referenced modules +# - option to limit output to particular modules + + +import sys +import re +import os + + +# Main program +# +def main(): + args = sys.argv[1:] + if not args: + print 'usage: pdeps file.py file.py ...' + return 2 + # + table = {} + for arg in args: + process(arg, table) + # + print '--- Uses ---' + printresults(table) + # + print '--- Used By ---' + inv = inverse(table) + printresults(inv) + # + print '--- Closure of Uses ---' + reach = closure(table) + printresults(reach) + # + print '--- Closure of Used By ---' + invreach = inverse(reach) + printresults(invreach) + # + return 0 + + +# Compiled regular expressions to search for import statements +# +m_import = re.compile('^[ \t]*from[ \t]+([^ \t]+)[ \t]+') +m_from = re.compile('^[ \t]*import[ \t]+([^#]+)') + + +# Collect data from one file +# +def process(filename, table): + fp = open(filename, 'r') + mod = os.path.basename(filename) + if mod[-3:] == '.py': + mod = mod[:-3] + table[mod] = list = [] + while 1: + line = fp.readline() + if not line: break + while line[-1:] == '\\': + nextline = fp.readline() + if not nextline: break + line = line[:-1] + nextline + if m_import.match(line) >= 0: + (a, b), (a1, b1) = m_import.regs[:2] + elif m_from.match(line) >= 0: + (a, b), (a1, b1) = m_from.regs[:2] + else: continue + words = line[a1:b1].split(',') + # print '#', line, words + for word in words: + word = word.strip() + if word not in list: + list.append(word) + + +# Compute closure (this is in fact totally general) +# +def closure(table): + modules = table.keys() + # + # Initialize reach with a copy of table + # + reach = {} + for mod in modules: + reach[mod] = table[mod][:] + # + # Iterate until no more change + # + change = 1 + while change: + change = 0 + for mod in modules: + for mo in reach[mod]: + if mo in modules: + for m in reach[mo]: + if m not in reach[mod]: + reach[mod].append(m) + change = 1 + # + return reach + + +# Invert a table (this is again totally general). +# All keys of the original table are made keys of the inverse, +# so there may be empty lists in the inverse. +# +def inverse(table): + inv = {} + for key in table.keys(): + if not inv.has_key(key): + inv[key] = [] + for item in table[key]: + store(inv, item, key) + return inv + + +# Store "item" in "dict" under "key". +# The dictionary maps keys to lists of items. +# If there is no list for the key yet, it is created. +# +def store(dict, key, item): + if dict.has_key(key): + dict[key].append(item) + else: + dict[key] = [item] + + +# Tabulate results neatly +# +def printresults(table): + modules = table.keys() + maxlen = 0 + for mod in modules: maxlen = max(maxlen, len(mod)) + modules.sort() + for mod in modules: + list = table[mod] + list.sort() + print mod.ljust(maxlen), ':', + if mod in list: + print '(*)', + for ref in list: + print ref, + print + + +# Call main and honor exit status +if __name__ == '__main__': + try: + sys.exit(main()) + except KeyboardInterrupt: + sys.exit(1) diff --git a/sys/src/cmd/python/Tools/scripts/pickle2db.py b/sys/src/cmd/python/Tools/scripts/pickle2db.py new file mode 100644 index 000000000..86545ccac --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/pickle2db.py @@ -0,0 +1,147 @@ +#!/usr/bin/env python + +""" +Synopsis: %(prog)s [-h|-b|-g|-r|-a|-d] [ picklefile ] dbfile + +Read the given picklefile as a series of key/value pairs and write to a new +database. If the database already exists, any contents are deleted. The +optional flags indicate the type of the output database: + + -a - open using anydbm + -b - open as bsddb btree file + -d - open as dbm file + -g - open as gdbm file + -h - open as bsddb hash file + -r - open as bsddb recno file + +The default is hash. If a pickle file is named it is opened for read +access. If no pickle file is named, the pickle input is read from standard +input. + +Note that recno databases can only contain integer keys, so you can't dump a +hash or btree database using db2pickle.py and reconstitute it to a recno +database with %(prog)s unless your keys are integers. + +""" + +import getopt +try: + import bsddb +except ImportError: + bsddb = None +try: + import dbm +except ImportError: + dbm = None +try: + import gdbm +except ImportError: + gdbm = None +try: + import anydbm +except ImportError: + anydbm = None +import sys +try: + import cPickle as pickle +except ImportError: + import pickle + +prog = sys.argv[0] + +def usage(): + sys.stderr.write(__doc__ % globals()) + +def main(args): + try: + opts, args = getopt.getopt(args, "hbrdag", + ["hash", "btree", "recno", "dbm", "anydbm", + "gdbm"]) + except getopt.error: + usage() + return 1 + + if len(args) == 0 or len(args) > 2: + usage() + return 1 + elif len(args) == 1: + pfile = sys.stdin + dbfile = args[0] + else: + try: + pfile = open(args[0], 'rb') + except IOError: + sys.stderr.write("Unable to open %s\n" % args[0]) + return 1 + dbfile = args[1] + + dbopen = None + for opt, arg in opts: + if opt in ("-h", "--hash"): + try: + dbopen = bsddb.hashopen + except AttributeError: + sys.stderr.write("bsddb module unavailable.\n") + return 1 + elif opt in ("-b", "--btree"): + try: + dbopen = bsddb.btopen + except AttributeError: + sys.stderr.write("bsddb module unavailable.\n") + return 1 + elif opt in ("-r", "--recno"): + try: + dbopen = bsddb.rnopen + except AttributeError: + sys.stderr.write("bsddb module unavailable.\n") + return 1 + elif opt in ("-a", "--anydbm"): + try: + dbopen = anydbm.open + except AttributeError: + sys.stderr.write("anydbm module unavailable.\n") + return 1 + elif opt in ("-g", "--gdbm"): + try: + dbopen = gdbm.open + except AttributeError: + sys.stderr.write("gdbm module unavailable.\n") + return 1 + elif opt in ("-d", "--dbm"): + try: + dbopen = dbm.open + except AttributeError: + sys.stderr.write("dbm module unavailable.\n") + return 1 + if dbopen is None: + if bsddb is None: + sys.stderr.write("bsddb module unavailable - ") + sys.stderr.write("must specify dbtype.\n") + return 1 + else: + dbopen = bsddb.hashopen + + try: + db = dbopen(dbfile, 'c') + except bsddb.error: + sys.stderr.write("Unable to open %s. " % dbfile) + sys.stderr.write("Check for format or version mismatch.\n") + return 1 + else: + for k in db.keys(): + del db[k] + + while 1: + try: + (key, val) = pickle.load(pfile) + except EOFError: + break + db[key] = val + + db.close() + pfile.close() + + return 0 + +if __name__ == "__main__": + sys.exit(main(sys.argv[1:])) diff --git a/sys/src/cmd/python/Tools/scripts/pindent.py b/sys/src/cmd/python/Tools/scripts/pindent.py new file mode 100755 index 000000000..89ed9e699 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/pindent.py @@ -0,0 +1,543 @@ +#! /usr/bin/env python + +# This file contains a class and a main program that perform three +# related (though complimentary) formatting operations on Python +# programs. When called as "pindent -c", it takes a valid Python +# program as input and outputs a version augmented with block-closing +# comments. When called as "pindent -d", it assumes its input is a +# Python program with block-closing comments and outputs a commentless +# version. When called as "pindent -r" it assumes its input is a +# Python program with block-closing comments but with its indentation +# messed up, and outputs a properly indented version. + +# A "block-closing comment" is a comment of the form '# end <keyword>' +# where <keyword> is the keyword that opened the block. If the +# opening keyword is 'def' or 'class', the function or class name may +# be repeated in the block-closing comment as well. Here is an +# example of a program fully augmented with block-closing comments: + +# def foobar(a, b): +# if a == b: +# a = a+1 +# elif a < b: +# b = b-1 +# if b > a: a = a-1 +# # end if +# else: +# print 'oops!' +# # end if +# # end def foobar + +# Note that only the last part of an if...elif...else... block needs a +# block-closing comment; the same is true for other compound +# statements (e.g. try...except). Also note that "short-form" blocks +# like the second 'if' in the example must be closed as well; +# otherwise the 'else' in the example would be ambiguous (remember +# that indentation is not significant when interpreting block-closing +# comments). + +# The operations are idempotent (i.e. applied to their own output +# they yield an identical result). Running first "pindent -c" and +# then "pindent -r" on a valid Python program produces a program that +# is semantically identical to the input (though its indentation may +# be different). Running "pindent -e" on that output produces a +# program that only differs from the original in indentation. + +# Other options: +# -s stepsize: set the indentation step size (default 8) +# -t tabsize : set the number of spaces a tab character is worth (default 8) +# -e : expand TABs into spaces +# file ... : input file(s) (default standard input) +# The results always go to standard output + +# Caveats: +# - comments ending in a backslash will be mistaken for continued lines +# - continuations using backslash are always left unchanged +# - continuations inside parentheses are not extra indented by -r +# but must be indented for -c to work correctly (this breaks +# idempotency!) +# - continued lines inside triple-quoted strings are totally garbled + +# Secret feature: +# - On input, a block may also be closed with an "end statement" -- +# this is a block-closing comment without the '#' sign. + +# Possible improvements: +# - check syntax based on transitions in 'next' table +# - better error reporting +# - better error recovery +# - check identifier after class/def + +# The following wishes need a more complete tokenization of the source: +# - Don't get fooled by comments ending in backslash +# - reindent continuation lines indicated by backslash +# - handle continuation lines inside parentheses/braces/brackets +# - handle triple quoted strings spanning lines +# - realign comments +# - optionally do much more thorough reformatting, a la C indent + +# Defaults +STEPSIZE = 8 +TABSIZE = 8 +EXPANDTABS = 0 + +import os +import re +import sys + +next = {} +next['if'] = next['elif'] = 'elif', 'else', 'end' +next['while'] = next['for'] = 'else', 'end' +next['try'] = 'except', 'finally' +next['except'] = 'except', 'else', 'end' +next['else'] = next['finally'] = next['def'] = next['class'] = 'end' +next['end'] = () +start = 'if', 'while', 'for', 'try', 'def', 'class' + +class PythonIndenter: + + def __init__(self, fpi = sys.stdin, fpo = sys.stdout, + indentsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + self.fpi = fpi + self.fpo = fpo + self.indentsize = indentsize + self.tabsize = tabsize + self.lineno = 0 + self.expandtabs = expandtabs + self._write = fpo.write + self.kwprog = re.compile( + r'^\s*(?P<kw>[a-z]+)' + r'(\s+(?P<id>[a-zA-Z_]\w*))?' + r'[^\w]') + self.endprog = re.compile( + r'^\s*#?\s*end\s+(?P<kw>[a-z]+)' + r'(\s+(?P<id>[a-zA-Z_]\w*))?' + r'[^\w]') + self.wsprog = re.compile(r'^[ \t]*') + # end def __init__ + + def write(self, line): + if self.expandtabs: + self._write(line.expandtabs(self.tabsize)) + else: + self._write(line) + # end if + # end def write + + def readline(self): + line = self.fpi.readline() + if line: self.lineno = self.lineno + 1 + # end if + return line + # end def readline + + def error(self, fmt, *args): + if args: fmt = fmt % args + # end if + sys.stderr.write('Error at line %d: %s\n' % (self.lineno, fmt)) + self.write('### %s ###\n' % fmt) + # end def error + + def getline(self): + line = self.readline() + while line[-2:] == '\\\n': + line2 = self.readline() + if not line2: break + # end if + line = line + line2 + # end while + return line + # end def getline + + def putline(self, line, indent = None): + if indent is None: + self.write(line) + return + # end if + tabs, spaces = divmod(indent*self.indentsize, self.tabsize) + i = 0 + m = self.wsprog.match(line) + if m: i = m.end() + # end if + self.write('\t'*tabs + ' '*spaces + line[i:]) + # end def putline + + def reformat(self): + stack = [] + while 1: + line = self.getline() + if not line: break # EOF + # end if + m = self.endprog.match(line) + if m: + kw = 'end' + kw2 = m.group('kw') + if not stack: + self.error('unexpected end') + elif stack[-1][0] != kw2: + self.error('unmatched end') + # end if + del stack[-1:] + self.putline(line, len(stack)) + continue + # end if + m = self.kwprog.match(line) + if m: + kw = m.group('kw') + if kw in start: + self.putline(line, len(stack)) + stack.append((kw, kw)) + continue + # end if + if next.has_key(kw) and stack: + self.putline(line, len(stack)-1) + kwa, kwb = stack[-1] + stack[-1] = kwa, kw + continue + # end if + # end if + self.putline(line, len(stack)) + # end while + if stack: + self.error('unterminated keywords') + for kwa, kwb in stack: + self.write('\t%s\n' % kwa) + # end for + # end if + # end def reformat + + def delete(self): + begin_counter = 0 + end_counter = 0 + while 1: + line = self.getline() + if not line: break # EOF + # end if + m = self.endprog.match(line) + if m: + end_counter = end_counter + 1 + continue + # end if + m = self.kwprog.match(line) + if m: + kw = m.group('kw') + if kw in start: + begin_counter = begin_counter + 1 + # end if + # end if + self.putline(line) + # end while + if begin_counter - end_counter < 0: + sys.stderr.write('Warning: input contained more end tags than expected\n') + elif begin_counter - end_counter > 0: + sys.stderr.write('Warning: input contained less end tags than expected\n') + # end if + # end def delete + + def complete(self): + self.indentsize = 1 + stack = [] + todo = [] + thisid = '' + current, firstkw, lastkw, topid = 0, '', '', '' + while 1: + line = self.getline() + i = 0 + m = self.wsprog.match(line) + if m: i = m.end() + # end if + m = self.endprog.match(line) + if m: + thiskw = 'end' + endkw = m.group('kw') + thisid = m.group('id') + else: + m = self.kwprog.match(line) + if m: + thiskw = m.group('kw') + if not next.has_key(thiskw): + thiskw = '' + # end if + if thiskw in ('def', 'class'): + thisid = m.group('id') + else: + thisid = '' + # end if + elif line[i:i+1] in ('\n', '#'): + todo.append(line) + continue + else: + thiskw = '' + # end if + # end if + indent = len(line[:i].expandtabs(self.tabsize)) + while indent < current: + if firstkw: + if topid: + s = '# end %s %s\n' % ( + firstkw, topid) + else: + s = '# end %s\n' % firstkw + # end if + self.putline(s, current) + firstkw = lastkw = '' + # end if + current, firstkw, lastkw, topid = stack[-1] + del stack[-1] + # end while + if indent == current and firstkw: + if thiskw == 'end': + if endkw != firstkw: + self.error('mismatched end') + # end if + firstkw = lastkw = '' + elif not thiskw or thiskw in start: + if topid: + s = '# end %s %s\n' % ( + firstkw, topid) + else: + s = '# end %s\n' % firstkw + # end if + self.putline(s, current) + firstkw = lastkw = topid = '' + # end if + # end if + if indent > current: + stack.append((current, firstkw, lastkw, topid)) + if thiskw and thiskw not in start: + # error + thiskw = '' + # end if + current, firstkw, lastkw, topid = \ + indent, thiskw, thiskw, thisid + # end if + if thiskw: + if thiskw in start: + firstkw = lastkw = thiskw + topid = thisid + else: + lastkw = thiskw + # end if + # end if + for l in todo: self.write(l) + # end for + todo = [] + if not line: break + # end if + self.write(line) + # end while + # end def complete + +# end class PythonIndenter + +# Simplified user interface +# - xxx_filter(input, output): read and write file objects +# - xxx_string(s): take and return string object +# - xxx_file(filename): process file in place, return true iff changed + +def complete_filter(input = sys.stdin, output = sys.stdout, + stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) + pi.complete() +# end def complete_filter + +def delete_filter(input= sys.stdin, output = sys.stdout, + stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) + pi.delete() +# end def delete_filter + +def reformat_filter(input = sys.stdin, output = sys.stdout, + stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) + pi.reformat() +# end def reformat_filter + +class StringReader: + def __init__(self, buf): + self.buf = buf + self.pos = 0 + self.len = len(self.buf) + # end def __init__ + def read(self, n = 0): + if n <= 0: + n = self.len - self.pos + else: + n = min(n, self.len - self.pos) + # end if + r = self.buf[self.pos : self.pos + n] + self.pos = self.pos + n + return r + # end def read + def readline(self): + i = self.buf.find('\n', self.pos) + return self.read(i + 1 - self.pos) + # end def readline + def readlines(self): + lines = [] + line = self.readline() + while line: + lines.append(line) + line = self.readline() + # end while + return lines + # end def readlines + # seek/tell etc. are left as an exercise for the reader +# end class StringReader + +class StringWriter: + def __init__(self): + self.buf = '' + # end def __init__ + def write(self, s): + self.buf = self.buf + s + # end def write + def getvalue(self): + return self.buf + # end def getvalue +# end class StringWriter + +def complete_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + input = StringReader(source) + output = StringWriter() + pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) + pi.complete() + return output.getvalue() +# end def complete_string + +def delete_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + input = StringReader(source) + output = StringWriter() + pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) + pi.delete() + return output.getvalue() +# end def delete_string + +def reformat_string(source, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + input = StringReader(source) + output = StringWriter() + pi = PythonIndenter(input, output, stepsize, tabsize, expandtabs) + pi.reformat() + return output.getvalue() +# end def reformat_string + +def complete_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + source = open(filename, 'r').read() + result = complete_string(source, stepsize, tabsize, expandtabs) + if source == result: return 0 + # end if + import os + try: os.rename(filename, filename + '~') + except os.error: pass + # end try + f = open(filename, 'w') + f.write(result) + f.close() + return 1 +# end def complete_file + +def delete_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + source = open(filename, 'r').read() + result = delete_string(source, stepsize, tabsize, expandtabs) + if source == result: return 0 + # end if + import os + try: os.rename(filename, filename + '~') + except os.error: pass + # end try + f = open(filename, 'w') + f.write(result) + f.close() + return 1 +# end def delete_file + +def reformat_file(filename, stepsize = STEPSIZE, tabsize = TABSIZE, expandtabs = EXPANDTABS): + source = open(filename, 'r').read() + result = reformat_string(source, stepsize, tabsize, expandtabs) + if source == result: return 0 + # end if + import os + try: os.rename(filename, filename + '~') + except os.error: pass + # end try + f = open(filename, 'w') + f.write(result) + f.close() + return 1 +# end def reformat_file + +# Test program when called as a script + +usage = """ +usage: pindent (-c|-d|-r) [-s stepsize] [-t tabsize] [-e] [file] ... +-c : complete a correctly indented program (add #end directives) +-d : delete #end directives +-r : reformat a completed program (use #end directives) +-s stepsize: indentation step (default %(STEPSIZE)d) +-t tabsize : the worth in spaces of a tab (default %(TABSIZE)d) +-e : expand TABs into spaces (defailt OFF) +[file] ... : files are changed in place, with backups in file~ +If no files are specified or a single - is given, +the program acts as a filter (reads stdin, writes stdout). +""" % vars() + +def error_both(op1, op2): + sys.stderr.write('Error: You can not specify both '+op1+' and -'+op2[0]+' at the same time\n') + sys.stderr.write(usage) + sys.exit(2) +# end def error_both + +def test(): + import getopt + try: + opts, args = getopt.getopt(sys.argv[1:], 'cdrs:t:e') + except getopt.error, msg: + sys.stderr.write('Error: %s\n' % msg) + sys.stderr.write(usage) + sys.exit(2) + # end try + action = None + stepsize = STEPSIZE + tabsize = TABSIZE + expandtabs = EXPANDTABS + for o, a in opts: + if o == '-c': + if action: error_both(o, action) + # end if + action = 'complete' + elif o == '-d': + if action: error_both(o, action) + # end if + action = 'delete' + elif o == '-r': + if action: error_both(o, action) + # end if + action = 'reformat' + elif o == '-s': + stepsize = int(a) + elif o == '-t': + tabsize = int(a) + elif o == '-e': + expandtabs = 1 + # end if + # end for + if not action: + sys.stderr.write( + 'You must specify -c(omplete), -d(elete) or -r(eformat)\n') + sys.stderr.write(usage) + sys.exit(2) + # end if + if not args or args == ['-']: + action = eval(action + '_filter') + action(sys.stdin, sys.stdout, stepsize, tabsize, expandtabs) + else: + action = eval(action + '_file') + for filename in args: + action(filename, stepsize, tabsize, expandtabs) + # end for + # end if +# end def test + +if __name__ == '__main__': + test() +# end if diff --git a/sys/src/cmd/python/Tools/scripts/ptags.py b/sys/src/cmd/python/Tools/scripts/ptags.py new file mode 100755 index 000000000..ac0135607 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/ptags.py @@ -0,0 +1,53 @@ +#! /usr/bin/env python + +# ptags +# +# Create a tags file for Python programs, usable with vi. +# Tagged are: +# - functions (even inside other defs or classes) +# - classes +# - filenames +# Warns about files it cannot open. +# No warnings about duplicate tags. + +import sys, re, os + +tags = [] # Modified global variable! + +def main(): + args = sys.argv[1:] + for filename in args: + treat_file(filename) + if tags: + fp = open('tags', 'w') + tags.sort() + for s in tags: fp.write(s) + + +expr = '^[ \t]*(def|class)[ \t]+([a-zA-Z0-9_]+)[ \t]*[:\(]' +matcher = re.compile(expr) + +def treat_file(filename): + try: + fp = open(filename, 'r') + except: + sys.stderr.write('Cannot open %s\n' % filename) + return + base = os.path.basename(filename) + if base[-3:] == '.py': + base = base[:-3] + s = base + '\t' + filename + '\t' + '1\n' + tags.append(s) + while 1: + line = fp.readline() + if not line: + break + m = matcher.match(line) + if m: + content = m.group(0) + name = m.group(2) + s = name + '\t' + filename + '\t/^' + content + '/\n' + tags.append(s) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/pydoc b/sys/src/cmd/python/Tools/scripts/pydoc new file mode 100755 index 000000000..0879a4258 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/pydoc @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +import pydoc +if __name__ == '__main__': + pydoc.cli() diff --git a/sys/src/cmd/python/Tools/scripts/pydocgui.pyw b/sys/src/cmd/python/Tools/scripts/pydocgui.pyw new file mode 100644 index 000000000..8e9a3d682 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/pydocgui.pyw @@ -0,0 +1,7 @@ +# Note: this file must not be named pydoc.pyw, lest it just end up +# importing itself (Python began allowing import of .pyw files +# between 2.2a1 and 2.2a2). +import pydoc + +if __name__ == '__main__': + pydoc.gui() diff --git a/sys/src/cmd/python/Tools/scripts/pysource.py b/sys/src/cmd/python/Tools/scripts/pysource.py new file mode 100644 index 000000000..71e0ded9c --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/pysource.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python + +"""\ +List python source files. + +There are three functions to check whether a file is a Python source, listed +here with increasing complexity: + +- has_python_ext() checks whether a file name ends in '.py[w]'. +- look_like_python() checks whether the file is not binary and either has + the '.py[w]' extension or the first line contains the word 'python'. +- can_be_compiled() checks whether the file can be compiled by compile(). + +The file also must be of appropriate size - not bigger than a megabyte. + +walk_python_files() recursively lists all Python files under the given directories. +""" +__author__ = "Oleg Broytmann, Georg Brandl" + +__all__ = ["has_python_ext", "looks_like_python", "can_be_compiled", "walk_python_files"] + + +import sys, os, re + +binary_re = re.compile('[\x00-\x08\x0E-\x1F\x7F]') + +debug = False + +def print_debug(msg): + if debug: print msg + + +def _open(fullpath): + try: + size = os.stat(fullpath).st_size + except OSError, err: # Permission denied - ignore the file + print_debug("%s: permission denied: %s" % (fullpath, err)) + return None + + if size > 1024*1024: # too big + print_debug("%s: the file is too big: %d bytes" % (fullpath, size)) + return None + + try: + return open(fullpath, 'rU') + except IOError, err: # Access denied, or a special file - ignore it + print_debug("%s: access denied: %s" % (fullpath, err)) + return None + +def has_python_ext(fullpath): + return fullpath.endswith(".py") or fullpath.endswith(".pyw") + +def looks_like_python(fullpath): + infile = _open(fullpath) + if infile is None: + return False + + line = infile.readline() + infile.close() + + if binary_re.search(line): + # file appears to be binary + print_debug("%s: appears to be binary" % fullpath) + return False + + if fullpath.endswith(".py") or fullpath.endswith(".pyw"): + return True + elif "python" in line: + # disguised Python script (e.g. CGI) + return True + + return False + +def can_be_compiled(fullpath): + infile = _open(fullpath) + if infile is None: + return False + + code = infile.read() + infile.close() + + try: + compile(code, fullpath, "exec") + except Exception, err: + print_debug("%s: cannot compile: %s" % (fullpath, err)) + return False + + return True + + +def walk_python_files(paths, is_python=looks_like_python, exclude_dirs=None): + """\ + Recursively yield all Python source files below the given paths. + + paths: a list of files and/or directories to be checked. + is_python: a function that takes a file name and checks whether it is a + Python source file + exclude_dirs: a list of directory base names that should be excluded in + the search + """ + if exclude_dirs is None: + exclude_dirs=[] + + for path in paths: + print_debug("testing: %s" % path) + if os.path.isfile(path): + if is_python(path): + yield path + elif os.path.isdir(path): + print_debug(" it is a directory") + for dirpath, dirnames, filenames in os.walk(path): + for exclude in exclude_dirs: + if exclude in dirnames: + dirnames.remove(exclude) + for filename in filenames: + fullpath = os.path.join(dirpath, filename) + print_debug("testing: %s" % fullpath) + if is_python(fullpath): + yield fullpath + else: + print_debug(" unknown type") + + +if __name__ == "__main__": + # Two simple examples/tests + for fullpath in walk_python_files(['.']): + print fullpath + print "----------" + for fullpath in walk_python_files(['.'], is_python=can_be_compiled): + print fullpath diff --git a/sys/src/cmd/python/Tools/scripts/redemo.py b/sys/src/cmd/python/Tools/scripts/redemo.py new file mode 100644 index 000000000..de7f3c4a2 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/redemo.py @@ -0,0 +1,171 @@ +"""Basic regular expression demostration facility (Perl style syntax).""" + +from Tkinter import * +import re + +class ReDemo: + + def __init__(self, master): + self.master = master + + self.promptdisplay = Label(self.master, anchor=W, + text="Enter a Perl-style regular expression:") + self.promptdisplay.pack(side=TOP, fill=X) + + self.regexdisplay = Entry(self.master) + self.regexdisplay.pack(fill=X) + self.regexdisplay.focus_set() + + self.addoptions() + + self.statusdisplay = Label(self.master, text="", anchor=W) + self.statusdisplay.pack(side=TOP, fill=X) + + self.labeldisplay = Label(self.master, anchor=W, + text="Enter a string to search:") + self.labeldisplay.pack(fill=X) + self.labeldisplay.pack(fill=X) + + self.showframe = Frame(master) + self.showframe.pack(fill=X, anchor=W) + + self.showvar = StringVar(master) + self.showvar.set("first") + + self.showfirstradio = Radiobutton(self.showframe, + text="Highlight first match", + variable=self.showvar, + value="first", + command=self.recompile) + self.showfirstradio.pack(side=LEFT) + + self.showallradio = Radiobutton(self.showframe, + text="Highlight all matches", + variable=self.showvar, + value="all", + command=self.recompile) + self.showallradio.pack(side=LEFT) + + self.stringdisplay = Text(self.master, width=60, height=4) + self.stringdisplay.pack(fill=BOTH, expand=1) + self.stringdisplay.tag_configure("hit", background="yellow") + + self.grouplabel = Label(self.master, text="Groups:", anchor=W) + self.grouplabel.pack(fill=X) + + self.grouplist = Listbox(self.master) + self.grouplist.pack(expand=1, fill=BOTH) + + self.regexdisplay.bind('<Key>', self.recompile) + self.stringdisplay.bind('<Key>', self.reevaluate) + + self.compiled = None + self.recompile() + + btags = self.regexdisplay.bindtags() + self.regexdisplay.bindtags(btags[1:] + btags[:1]) + + btags = self.stringdisplay.bindtags() + self.stringdisplay.bindtags(btags[1:] + btags[:1]) + + def addoptions(self): + self.frames = [] + self.boxes = [] + self.vars = [] + for name in ('IGNORECASE', + 'LOCALE', + 'MULTILINE', + 'DOTALL', + 'VERBOSE'): + if len(self.boxes) % 3 == 0: + frame = Frame(self.master) + frame.pack(fill=X) + self.frames.append(frame) + val = getattr(re, name) + var = IntVar() + box = Checkbutton(frame, + variable=var, text=name, + offvalue=0, onvalue=val, + command=self.recompile) + box.pack(side=LEFT) + self.boxes.append(box) + self.vars.append(var) + + def getflags(self): + flags = 0 + for var in self.vars: + flags = flags | var.get() + flags = flags + return flags + + def recompile(self, event=None): + try: + self.compiled = re.compile(self.regexdisplay.get(), + self.getflags()) + bg = self.promptdisplay['background'] + self.statusdisplay.config(text="", background=bg) + except re.error, msg: + self.compiled = None + self.statusdisplay.config( + text="re.error: %s" % str(msg), + background="red") + self.reevaluate() + + def reevaluate(self, event=None): + try: + self.stringdisplay.tag_remove("hit", "1.0", END) + except TclError: + pass + try: + self.stringdisplay.tag_remove("hit0", "1.0", END) + except TclError: + pass + self.grouplist.delete(0, END) + if not self.compiled: + return + self.stringdisplay.tag_configure("hit", background="yellow") + self.stringdisplay.tag_configure("hit0", background="orange") + text = self.stringdisplay.get("1.0", END) + last = 0 + nmatches = 0 + while last <= len(text): + m = self.compiled.search(text, last) + if m is None: + break + first, last = m.span() + if last == first: + last = first+1 + tag = "hit0" + else: + tag = "hit" + pfirst = "1.0 + %d chars" % first + plast = "1.0 + %d chars" % last + self.stringdisplay.tag_add(tag, pfirst, plast) + if nmatches == 0: + self.stringdisplay.yview_pickplace(pfirst) + groups = list(m.groups()) + groups.insert(0, m.group()) + for i in range(len(groups)): + g = "%2d: %r" % (i, groups[i]) + self.grouplist.insert(END, g) + nmatches = nmatches + 1 + if self.showvar.get() == "first": + break + + if nmatches == 0: + self.statusdisplay.config(text="(no match)", + background="yellow") + else: + self.statusdisplay.config(text="") + + +# Main function, run when invoked as a stand-alone Python program. + +def main(): + root = Tk() + demo = ReDemo(root) + root.protocol('WM_DELETE_WINDOW', root.quit) + root.mainloop() + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/reindent.py b/sys/src/cmd/python/Tools/scripts/reindent.py new file mode 100644 index 000000000..5ac98c7f7 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/reindent.py @@ -0,0 +1,293 @@ +#! /usr/bin/env python + +# Released to the public domain, by Tim Peters, 03 October 2000. + +"""reindent [-d][-r][-v] [ path ... ] + +-d (--dryrun) Dry run. Analyze, but don't make any changes to, files. +-r (--recurse) Recurse. Search for all .py files in subdirectories too. +-v (--verbose) Verbose. Print informative msgs; else no output. +-h (--help) Help. Print this usage information and exit. + +Change Python (.py) files to use 4-space indents and no hard tab characters. +Also trim excess spaces and tabs from ends of lines, and remove empty lines +at the end of files. Also ensure the last line ends with a newline. + +If no paths are given on the command line, reindent operates as a filter, +reading a single source file from standard input and writing the transformed +source to standard output. In this case, the -d, -r and -v flags are +ignored. + +You can pass one or more file and/or directory paths. When a directory +path, all .py files within the directory will be examined, and, if the -r +option is given, likewise recursively for subdirectories. + +If output is not to standard output, reindent overwrites files in place, +renaming the originals with a .bak extension. If it finds nothing to +change, the file is left alone. If reindent does change a file, the changed +file is a fixed-point for future runs (i.e., running reindent on the +resulting .py file won't change it again). + +The hard part of reindenting is figuring out what to do with comment +lines. So long as the input files get a clean bill of health from +tabnanny.py, reindent should do a good job. +""" + +__version__ = "1" + +import tokenize +import os +import sys + +verbose = 0 +recurse = 0 +dryrun = 0 + +def usage(msg=None): + if msg is not None: + print >> sys.stderr, msg + print >> sys.stderr, __doc__ + +def errprint(*args): + sep = "" + for arg in args: + sys.stderr.write(sep + str(arg)) + sep = " " + sys.stderr.write("\n") + +def main(): + import getopt + global verbose, recurse, dryrun + try: + opts, args = getopt.getopt(sys.argv[1:], "drvh", + ["dryrun", "recurse", "verbose", "help"]) + except getopt.error, msg: + usage(msg) + return + for o, a in opts: + if o in ('-d', '--dryrun'): + dryrun += 1 + elif o in ('-r', '--recurse'): + recurse += 1 + elif o in ('-v', '--verbose'): + verbose += 1 + elif o in ('-h', '--help'): + usage() + return + if not args: + r = Reindenter(sys.stdin) + r.run() + r.write(sys.stdout) + return + for arg in args: + check(arg) + +def check(file): + if os.path.isdir(file) and not os.path.islink(file): + if verbose: + print "listing directory", file + names = os.listdir(file) + for name in names: + fullname = os.path.join(file, name) + if ((recurse and os.path.isdir(fullname) and + not os.path.islink(fullname)) + or name.lower().endswith(".py")): + check(fullname) + return + + if verbose: + print "checking", file, "...", + try: + f = open(file) + except IOError, msg: + errprint("%s: I/O Error: %s" % (file, str(msg))) + return + + r = Reindenter(f) + f.close() + if r.run(): + if verbose: + print "changed." + if dryrun: + print "But this is a dry run, so leaving it alone." + if not dryrun: + bak = file + ".bak" + if os.path.exists(bak): + os.remove(bak) + os.rename(file, bak) + if verbose: + print "renamed", file, "to", bak + f = open(file, "w") + r.write(f) + f.close() + if verbose: + print "wrote new", file + else: + if verbose: + print "unchanged." + +def _rstrip(line, JUNK='\n \t'): + """Return line stripped of trailing spaces, tabs, newlines. + + Note that line.rstrip() instead also strips sundry control characters, + but at least one known Emacs user expects to keep junk like that, not + mentioning Barry by name or anything <wink>. + """ + + i = len(line) + while i > 0 and line[i-1] in JUNK: + i -= 1 + return line[:i] + +class Reindenter: + + def __init__(self, f): + self.find_stmt = 1 # next token begins a fresh stmt? + self.level = 0 # current indent level + + # Raw file lines. + self.raw = f.readlines() + + # File lines, rstripped & tab-expanded. Dummy at start is so + # that we can use tokenize's 1-based line numbering easily. + # Note that a line is all-blank iff it's "\n". + self.lines = [_rstrip(line).expandtabs() + "\n" + for line in self.raw] + self.lines.insert(0, None) + self.index = 1 # index into self.lines of next line + + # List of (lineno, indentlevel) pairs, one for each stmt and + # comment line. indentlevel is -1 for comment lines, as a + # signal that tokenize doesn't know what to do about them; + # indeed, they're our headache! + self.stats = [] + + def run(self): + tokenize.tokenize(self.getline, self.tokeneater) + # Remove trailing empty lines. + lines = self.lines + while lines and lines[-1] == "\n": + lines.pop() + # Sentinel. + stats = self.stats + stats.append((len(lines), 0)) + # Map count of leading spaces to # we want. + have2want = {} + # Program after transformation. + after = self.after = [] + # Copy over initial empty lines -- there's nothing to do until + # we see a line with *something* on it. + i = stats[0][0] + after.extend(lines[1:i]) + for i in range(len(stats)-1): + thisstmt, thislevel = stats[i] + nextstmt = stats[i+1][0] + have = getlspace(lines[thisstmt]) + want = thislevel * 4 + if want < 0: + # A comment line. + if have: + # An indented comment line. If we saw the same + # indentation before, reuse what it most recently + # mapped to. + want = have2want.get(have, -1) + if want < 0: + # Then it probably belongs to the next real stmt. + for j in xrange(i+1, len(stats)-1): + jline, jlevel = stats[j] + if jlevel >= 0: + if have == getlspace(lines[jline]): + want = jlevel * 4 + break + if want < 0: # Maybe it's a hanging + # comment like this one, + # in which case we should shift it like its base + # line got shifted. + for j in xrange(i-1, -1, -1): + jline, jlevel = stats[j] + if jlevel >= 0: + want = have + getlspace(after[jline-1]) - \ + getlspace(lines[jline]) + break + if want < 0: + # Still no luck -- leave it alone. + want = have + else: + want = 0 + assert want >= 0 + have2want[have] = want + diff = want - have + if diff == 0 or have == 0: + after.extend(lines[thisstmt:nextstmt]) + else: + for line in lines[thisstmt:nextstmt]: + if diff > 0: + if line == "\n": + after.append(line) + else: + after.append(" " * diff + line) + else: + remove = min(getlspace(line), -diff) + after.append(line[remove:]) + return self.raw != self.after + + def write(self, f): + f.writelines(self.after) + + # Line-getter for tokenize. + def getline(self): + if self.index >= len(self.lines): + line = "" + else: + line = self.lines[self.index] + self.index += 1 + return line + + # Line-eater for tokenize. + def tokeneater(self, type, token, (sline, scol), end, line, + INDENT=tokenize.INDENT, + DEDENT=tokenize.DEDENT, + NEWLINE=tokenize.NEWLINE, + COMMENT=tokenize.COMMENT, + NL=tokenize.NL): + + if type == NEWLINE: + # A program statement, or ENDMARKER, will eventually follow, + # after some (possibly empty) run of tokens of the form + # (NL | COMMENT)* (INDENT | DEDENT+)? + self.find_stmt = 1 + + elif type == INDENT: + self.find_stmt = 1 + self.level += 1 + + elif type == DEDENT: + self.find_stmt = 1 + self.level -= 1 + + elif type == COMMENT: + if self.find_stmt: + self.stats.append((sline, -1)) + # but we're still looking for a new stmt, so leave + # find_stmt alone + + elif type == NL: + pass + + elif self.find_stmt: + # This is the first "real token" following a NEWLINE, so it + # must be the first token of the next program statement, or an + # ENDMARKER. + self.find_stmt = 0 + if line: # not endmarker + self.stats.append((sline, self.level)) + +# Count number of leading blanks. +def getlspace(line): + i, n = 0, len(line) + while i < n and line[i] == " ": + i += 1 + return i + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/rgrep.py b/sys/src/cmd/python/Tools/scripts/rgrep.py new file mode 100755 index 000000000..b64420645 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/rgrep.py @@ -0,0 +1,64 @@ +#! /usr/bin/env python + +"""Reverse grep. + +Usage: rgrep [-i] pattern file +""" + +import sys +import re +import getopt + +def main(): + bufsize = 64*1024 + reflags = 0 + opts, args = getopt.getopt(sys.argv[1:], "i") + for o, a in opts: + if o == '-i': + reflags = reflags | re.IGNORECASE + if len(args) < 2: + usage("not enough arguments") + if len(args) > 2: + usage("exactly one file argument required") + pattern, filename = args + try: + prog = re.compile(pattern, reflags) + except re.error, msg: + usage("error in regular expression: %s" % str(msg)) + try: + f = open(filename) + except IOError, msg: + usage("can't open %s: %s" % (repr(filename), str(msg)), 1) + f.seek(0, 2) + pos = f.tell() + leftover = None + while pos > 0: + size = min(pos, bufsize) + pos = pos - size + f.seek(pos) + buffer = f.read(size) + lines = buffer.split("\n") + del buffer + if leftover is None: + if not lines[-1]: + del lines[-1] + else: + lines[-1] = lines[-1] + leftover + if pos > 0: + leftover = lines[0] + del lines[0] + else: + leftover = None + lines.reverse() + for line in lines: + if prog.search(line): + print line + +def usage(msg, code=2): + sys.stdout = sys.stderr + print msg + print __doc__ + sys.exit(code) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/setup.py b/sys/src/cmd/python/Tools/scripts/setup.py new file mode 100644 index 000000000..23bf247ef --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/setup.py @@ -0,0 +1,19 @@ +from distutils.core import setup + +if __name__ == '__main__': + setup( + scripts=[ + 'byteyears.py', + 'checkpyc.py', + 'copytime.py', + 'crlf.py', + 'dutree.py', + 'ftpmirror.py', + 'h2py.py', + 'lfcr.py', + 'logmerge.py', + '../../Lib/tabnanny.py', + '../../Lib/timeit.py', + 'untabify.py', + ], + ) diff --git a/sys/src/cmd/python/Tools/scripts/suff.py b/sys/src/cmd/python/Tools/scripts/suff.py new file mode 100755 index 000000000..c026201c5 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/suff.py @@ -0,0 +1,30 @@ +#! /usr/bin/env python + +# suff +# +# show different suffixes amongst arguments + +import sys + +def main(): + files = sys.argv[1:] + suffixes = {} + for filename in files: + suff = getsuffix(filename) + if not suffixes.has_key(suff): + suffixes[suff] = [] + suffixes[suff].append(filename) + keys = suffixes.keys() + keys.sort() + for suff in keys: + print repr(suff), len(suffixes[suff]) + +def getsuffix(filename): + suff = '' + for i in range(len(filename)): + if filename[i] == '.': + suff = filename[i:] + return suff + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/svneol.py b/sys/src/cmd/python/Tools/scripts/svneol.py new file mode 100644 index 000000000..a5e562c1e --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/svneol.py @@ -0,0 +1,77 @@ +#! /usr/bin/env python + +""" +SVN helper script. + +Try to set the svn:eol-style property to "native" on every .py, .txt, .c and +.h file in the directory tree rooted at the current directory. + +Files with the svn:eol-style property already set (to anything) are skipped. + +svn will itself refuse to set this property on a file that's not under SVN +control, or that has a binary mime-type property set. This script inherits +that behavior, and passes on whatever warning message the failing "svn +propset" command produces. + +In the Python project, it's safe to invoke this script from the root of +a checkout. + +No output is produced for files that are ignored. For a file that gets +svn:eol-style set, output looks like: + + property 'svn:eol-style' set on 'Lib\ctypes\__init__.py' + +For a file not under version control: + + svn: warning: 'patch-finalizer.txt' is not under version control + +and for a file with a binary mime-type property: + + svn: File 'Lib\test\test_pep263.py' has binary mime type property +""" + +import re +import os + +def proplist(root, fn): + "Return a list of property names for file fn in directory root" + path = os.path.join(root, ".svn", "props", fn+".svn-work") + try: + f = open(path) + except IOError: + # no properties file: not under version control + return [] + result = [] + while 1: + # key-value pairs, of the form + # K <length> + # <keyname>NL + # V length + # <value>NL + # END + line = f.readline() + if line.startswith("END"): + break + assert line.startswith("K ") + L = int(line.split()[1]) + key = f.read(L) + result.append(key) + f.readline() + line = f.readline() + assert line.startswith("V ") + L = int(line.split()[1]) + value = f.read(L) + f.readline() + f.close() + return result + +possible_text_file = re.compile(r"\.([hc]|py|txt|sln|vcproj)$").search + +for root, dirs, files in os.walk('.'): + if '.svn' in dirs: + dirs.remove('.svn') + for fn in files: + if possible_text_file(fn): + if 'svn:eol-style' not in proplist(root, fn): + path = os.path.join(root, fn) + os.system('svn propset svn:eol-style native "%s"' % path) diff --git a/sys/src/cmd/python/Tools/scripts/texcheck.py b/sys/src/cmd/python/Tools/scripts/texcheck.py new file mode 100644 index 000000000..4a5663584 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/texcheck.py @@ -0,0 +1,233 @@ +""" TeXcheck.py -- rough syntax checking on Python style LaTeX documents. + + Written by Raymond D. Hettinger <python at rcn.com> + Copyright (c) 2003 Python Software Foundation. All rights reserved. + +Designed to catch common markup errors including: +* Unbalanced or mismatched parenthesis, brackets, and braces. +* Unbalanced or mismatched \\begin and \\end blocks. +* Misspelled or invalid LaTeX commands. +* Use of forward slashes instead of backslashes for commands. +* Table line size mismatches. + +Sample command line usage: + python texcheck.py -k chapterheading -m lib/librandomtex *.tex + +Options: + -m Munge parenthesis and brackets. [0,n) would normally mismatch. + -k keyword: Keyword is a valid LaTeX command. Do not include the backslash. + -d: Delimiter check only (useful for non-LaTeX files). + -h: Help + -s lineno: Start at lineno (useful for skipping complex sections). + -v: Verbose. Trace the matching of //begin and //end blocks. +""" + +import re +import sys +import getopt +from itertools import izip, count, islice +import glob + +cmdstr = r""" + \section \module \declaremodule \modulesynopsis \moduleauthor + \sectionauthor \versionadded \code \class \method \begin + \optional \var \ref \end \subsection \lineiii \hline \label + \indexii \textrm \ldots \keyword \stindex \index \item \note + \withsubitem \ttindex \footnote \citetitle \samp \opindex + \noindent \exception \strong \dfn \ctype \obindex \character + \indexiii \function \bifuncindex \refmodule \refbimodindex + \subsubsection \nodename \member \chapter \emph \ASCII \UNIX + \regexp \program \production \token \productioncont \term + \grammartoken \lineii \seemodule \file \EOF \documentclass + \usepackage \title \input \maketitle \ifhtml \fi \url \Cpp + \tableofcontents \kbd \programopt \envvar \refstmodindex + \cfunction \constant \NULL \moreargs \cfuncline \cdata + \textasciicircum \n \ABC \setindexsubitem \versionchanged + \deprecated \seetext \newcommand \POSIX \pep \warning \rfc + \verbatiminput \methodline \textgreater \seetitle \lineiv + \funclineni \ulink \manpage \funcline \dataline \unspecified + \textbackslash \mimetype \mailheader \seepep \textunderscore + \longprogramopt \infinity \plusminus \shortversion \version + \refmodindex \seerfc \makeindex \makemodindex \renewcommand + \indexname \appendix \protect \indexiv \mbox \textasciitilde + \platform \seeurl \leftmargin \labelwidth \localmoduletable + \LaTeX \copyright \memberline \backslash \pi \centerline + \caption \vspace \textwidth \menuselection \textless + \makevar \csimplemacro \menuselection \bfcode \sub \release + \email \kwindex \refexmodindex \filenq \e \menuselection + \exindex \linev \newsgroup \verbatim \setshortversion + \author \authoraddress \paragraph \subparagraph \cmemberline + \textbar \C \seelink +""" + +def matchclose(c_lineno, c_symbol, openers, pairmap): + "Verify that closing delimiter matches most recent opening delimiter" + try: + o_lineno, o_symbol = openers.pop() + except IndexError: + print "\nDelimiter mismatch. On line %d, encountered closing '%s' without corresponding open" % (c_lineno, c_symbol) + return + if o_symbol in pairmap.get(c_symbol, [c_symbol]): return + print "\nOpener '%s' on line %d was not closed before encountering '%s' on line %d" % (o_symbol, o_lineno, c_symbol, c_lineno) + return + +def checkit(source, opts, morecmds=[]): + """Check the LaTeX formatting in a sequence of lines. + + Opts is a mapping of options to option values if any: + -m munge parenthesis and brackets + -d delimiters only checking + -v verbose trace of delimiter matching + -s lineno: linenumber to start scan (default is 1). + + Morecmds is a sequence of LaTeX commands (without backslashes) that + are to be considered valid in the scan. + """ + + texcmd = re.compile(r'\\[A-Za-z]+') + falsetexcmd = re.compile(r'\/([A-Za-z]+)') # Mismarked with forward slash + + validcmds = set(cmdstr.split()) + for cmd in morecmds: + validcmds.add('\\' + cmd) + + if '-m' in opts: + pairmap = {']':'[(', ')':'(['} # Munged openers + else: + pairmap = {']':'[', ')':'('} # Normal opener for a given closer + openpunct = set('([') # Set of valid openers + + delimiters = re.compile(r'\\(begin|end){([_a-zA-Z]+)}|([()\[\]])') + braces = re.compile(r'({)|(})') + doubledwords = re.compile(r'(\b[A-za-z]+\b) \b\1\b') + spacingmarkup = re.compile(r'\\(ABC|ASCII|C|Cpp|EOF|infinity|NULL|plusminus|POSIX|UNIX)\s') + + openers = [] # Stack of pending open delimiters + bracestack = [] # Stack of pending open braces + + tablestart = re.compile(r'\\begin{(?:long)?table([iv]+)}') + tableline = re.compile(r'\\line([iv]+){') + tableend = re.compile(r'\\end{(?:long)?table([iv]+)}') + tablelevel = '' + tablestartline = 0 + + startline = int(opts.get('-s', '1')) + lineno = 0 + + for lineno, line in izip(count(startline), islice(source, startline-1, None)): + line = line.rstrip() + + # Check balancing of open/close parenthesis, brackets, and begin/end blocks + for begend, name, punct in delimiters.findall(line): + if '-v' in opts: + print lineno, '|', begend, name, punct, + if begend == 'begin' and '-d' not in opts: + openers.append((lineno, name)) + elif punct in openpunct: + openers.append((lineno, punct)) + elif begend == 'end' and '-d' not in opts: + matchclose(lineno, name, openers, pairmap) + elif punct in pairmap: + matchclose(lineno, punct, openers, pairmap) + if '-v' in opts: + print ' --> ', openers + + # Balance opening and closing braces + for open, close in braces.findall(line): + if open == '{': + bracestack.append(lineno) + if close == '}': + try: + bracestack.pop() + except IndexError: + print r'Warning, unmatched } on line %s.' % (lineno,) + + # Optionally, skip LaTeX specific checks + if '-d' in opts: + continue + + # Warn whenever forward slashes encountered with a LaTeX command + for cmd in falsetexcmd.findall(line): + if '822' in line or '.html' in line: + continue # Ignore false positives for urls and for /rfc822 + if '\\' + cmd in validcmds: + print 'Warning, forward slash used on line %d with cmd: /%s' % (lineno, cmd) + + # Check for markup requiring {} for correct spacing + for cmd in spacingmarkup.findall(line): + print r'Warning, \%s should be written as \%s{} on line %d' % (cmd, cmd, lineno) + + # Validate commands + nc = line.find(r'\newcommand') + if nc != -1: + start = line.find('{', nc) + end = line.find('}', start) + validcmds.add(line[start+1:end]) + for cmd in texcmd.findall(line): + if cmd not in validcmds: + print r'Warning, unknown tex cmd on line %d: \%s' % (lineno, cmd) + + # Check table levels (make sure lineii only inside tableii) + m = tablestart.search(line) + if m: + tablelevel = m.group(1) + tablestartline = lineno + m = tableline.search(line) + if m and m.group(1) != tablelevel: + print r'Warning, \line%s on line %d does not match \table%s on line %d' % (m.group(1), lineno, tablelevel, tablestartline) + if tableend.search(line): + tablelevel = '' + + # Style guide warnings + if 'e.g.' in line or 'i.e.' in line: + print r'Style warning, avoid use of i.e or e.g. on line %d' % (lineno,) + + for dw in doubledwords.findall(line): + print r'Doubled word warning. "%s" on line %d' % (dw, lineno) + + lastline = lineno + for lineno, symbol in openers: + print "Unmatched open delimiter '%s' on line %d" % (symbol, lineno) + for lineno in bracestack: + print "Unmatched { on line %d" % (lineno,) + print 'Done checking %d lines.' % (lastline,) + return 0 + +def main(args=None): + if args is None: + args = sys.argv[1:] + optitems, arglist = getopt.getopt(args, "k:mdhs:v") + opts = dict(optitems) + if '-h' in opts or args==[]: + print __doc__ + return 0 + + if len(arglist) < 1: + print 'Please specify a file to be checked' + return 1 + + for i, filespec in enumerate(arglist): + if '*' in filespec or '?' in filespec: + arglist[i:i+1] = glob.glob(filespec) + + morecmds = [v for k,v in optitems if k=='-k'] + err = [] + + for filename in arglist: + print '=' * 30 + print "Checking", filename + try: + f = open(filename) + except IOError: + print 'Cannot open file %s.' % arglist[0] + return 2 + + try: + err.append(checkit(f, opts, morecmds)) + finally: + f.close() + + return max(err) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/sys/src/cmd/python/Tools/scripts/texi2html.py b/sys/src/cmd/python/Tools/scripts/texi2html.py new file mode 100755 index 000000000..3ecaee68f --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/texi2html.py @@ -0,0 +1,2078 @@ +#! /usr/bin/env python + +# Convert GNU texinfo files into HTML, one file per node. +# Based on Texinfo 2.14. +# Usage: texi2html [-d] [-d] [-c] inputfile outputdirectory +# The input file must be a complete texinfo file, e.g. emacs.texi. +# This creates many files (one per info node) in the output directory, +# overwriting existing files of the same name. All files created have +# ".html" as their extension. + + +# XXX To do: +# - handle @comment*** correctly +# - handle @xref {some words} correctly +# - handle @ftable correctly (items aren't indexed?) +# - handle @itemx properly +# - handle @exdent properly +# - add links directly to the proper line from indices +# - check against the definitive list of @-cmds; we still miss (among others): +# - @defindex (hard) +# - @c(omment) in the middle of a line (rarely used) +# - @this* (not really needed, only used in headers anyway) +# - @today{} (ever used outside title page?) + +# More consistent handling of chapters/sections/etc. +# Lots of documentation +# Many more options: +# -top designate top node +# -links customize which types of links are included +# -split split at chapters or sections instead of nodes +# -name Allow different types of filename handling. Non unix systems +# will have problems with long node names +# ... +# Support the most recent texinfo version and take a good look at HTML 3.0 +# More debugging output (customizable) and more flexible error handling +# How about icons ? + +# rpyron 2002-05-07 +# Robert Pyron <rpyron@alum.mit.edu> +# 1. BUGFIX: In function makefile(), strip blanks from the nodename. +# This is necesary to match the behavior of parser.makeref() and +# parser.do_node(). +# 2. BUGFIX fixed KeyError in end_ifset (well, I may have just made +# it go away, rather than fix it) +# 3. BUGFIX allow @menu and menu items inside @ifset or @ifclear +# 4. Support added for: +# @uref URL reference +# @image image file reference (see note below) +# @multitable output an HTML table +# @vtable +# 5. Partial support for accents, to match MAKEINFO output +# 6. I added a new command-line option, '-H basename', to specify +# HTML Help output. This will cause three files to be created +# in the current directory: +# `basename`.hhp HTML Help Workshop project file +# `basename`.hhc Contents file for the project +# `basename`.hhk Index file for the project +# When fed into HTML Help Workshop, the resulting file will be +# named `basename`.chm. +# 7. A new class, HTMLHelp, to accomplish item 6. +# 8. Various calls to HTMLHelp functions. +# A NOTE ON IMAGES: Just as 'outputdirectory' must exist before +# running this program, all referenced images must already exist +# in outputdirectory. + +import os +import sys +import string +import re + +MAGIC = '\\input texinfo' + +cmprog = re.compile('^@([a-z]+)([ \t]|$)') # Command (line-oriented) +blprog = re.compile('^[ \t]*$') # Blank line +kwprog = re.compile('@[a-z]+') # Keyword (embedded, usually + # with {} args) +spprog = re.compile('[\n@{}&<>]') # Special characters in + # running text + # + # menu item (Yuck!) +miprog = re.compile('^\* ([^:]*):(:|[ \t]*([^\t,\n.]+)([^ \t\n]*))[ \t\n]*') +# 0 1 1 2 3 34 42 0 +# ----- ---------- --------- +# -|----------------------------- +# ----------------------------------------------------- + + + + +class HTMLNode: + """Some of the parser's functionality is separated into this class. + + A Node accumulates its contents, takes care of links to other Nodes + and saves itself when it is finished and all links are resolved. + """ + + DOCTYPE = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">' + + type = 0 + cont = '' + epilogue = '</BODY></HTML>\n' + + def __init__(self, dir, name, topname, title, next, prev, up): + self.dirname = dir + self.name = name + if topname: + self.topname = topname + else: + self.topname = name + self.title = title + self.next = next + self.prev = prev + self.up = up + self.lines = [] + + def write(self, *lines): + map(self.lines.append, lines) + + def flush(self): + fp = open(self.dirname + '/' + makefile(self.name), 'w') + fp.write(self.prologue) + fp.write(self.text) + fp.write(self.epilogue) + fp.close() + + def link(self, label, nodename, rel=None, rev=None): + if nodename: + if nodename.lower() == '(dir)': + addr = '../dir.html' + title = '' + else: + addr = makefile(nodename) + title = ' TITLE="%s"' % nodename + self.write(label, ': <A HREF="', addr, '"', \ + rel and (' REL=' + rel) or "", \ + rev and (' REV=' + rev) or "", \ + title, '>', nodename, '</A> \n') + + def finalize(self): + length = len(self.lines) + self.text = ''.join(self.lines) + self.lines = [] + self.open_links() + self.output_links() + self.close_links() + links = ''.join(self.lines) + self.lines = [] + self.prologue = ( + self.DOCTYPE + + '\n<HTML><HEAD>\n' + ' <!-- Converted with texi2html and Python -->\n' + ' <TITLE>' + self.title + '</TITLE>\n' + ' <LINK REL=Next HREF="' + + makefile(self.next) + '" TITLE="' + self.next + '">\n' + ' <LINK REL=Previous HREF="' + + makefile(self.prev) + '" TITLE="' + self.prev + '">\n' + ' <LINK REL=Up HREF="' + + makefile(self.up) + '" TITLE="' + self.up + '">\n' + '</HEAD><BODY>\n' + + links) + if length > 20: + self.epilogue = '<P>\n%s</BODY></HTML>\n' % links + + def open_links(self): + self.write('<HR>\n') + + def close_links(self): + self.write('<HR>\n') + + def output_links(self): + if self.cont != self.next: + self.link(' Cont', self.cont) + self.link(' Next', self.next, rel='Next') + self.link(' Prev', self.prev, rel='Previous') + self.link(' Up', self.up, rel='Up') + if self.name <> self.topname: + self.link(' Top', self.topname) + + +class HTML3Node(HTMLNode): + + DOCTYPE = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML Level 3//EN//3.0">' + + def open_links(self): + self.write('<DIV CLASS=Navigation>\n <HR>\n') + + def close_links(self): + self.write(' <HR>\n</DIV>\n') + + +class TexinfoParser: + + COPYRIGHT_SYMBOL = "&copy;" + FN_ID_PATTERN = "(%(id)s)" + FN_SOURCE_PATTERN = '<A NAME=footnoteref%(id)s' \ + ' HREF="#footnotetext%(id)s">' \ + + FN_ID_PATTERN + '</A>' + FN_TARGET_PATTERN = '<A NAME=footnotetext%(id)s' \ + ' HREF="#footnoteref%(id)s">' \ + + FN_ID_PATTERN + '</A>\n%(text)s<P>\n' + FN_HEADER = '\n<P>\n<HR NOSHADE SIZE=1 WIDTH=200>\n' \ + '<STRONG><EM>Footnotes</EM></STRONG>\n<P>' + + + Node = HTMLNode + + # Initialize an instance + def __init__(self): + self.unknown = {} # statistics about unknown @-commands + self.filenames = {} # Check for identical filenames + self.debugging = 0 # larger values produce more output + self.print_headers = 0 # always print headers? + self.nodefp = None # open file we're writing to + self.nodelineno = 0 # Linenumber relative to node + self.links = None # Links from current node + self.savetext = None # If not None, save text head instead + self.savestack = [] # If not None, save text head instead + self.htmlhelp = None # html help data + self.dirname = 'tmp' # directory where files are created + self.includedir = '.' # directory to search @include files + self.nodename = '' # name of current node + self.topname = '' # name of top node (first node seen) + self.title = '' # title of this whole Texinfo tree + self.resetindex() # Reset all indices + self.contents = [] # Reset table of contents + self.numbering = [] # Reset section numbering counters + self.nofill = 0 # Normal operation: fill paragraphs + self.values={'html': 1} # Names that should be parsed in ifset + self.stackinfo={} # Keep track of state in the stack + # XXX The following should be reset per node?! + self.footnotes = [] # Reset list of footnotes + self.itemarg = None # Reset command used by @item + self.itemnumber = None # Reset number for @item in @enumerate + self.itemindex = None # Reset item index name + self.node = None + self.nodestack = [] + self.cont = 0 + self.includedepth = 0 + + # Set htmlhelp helper class + def sethtmlhelp(self, htmlhelp): + self.htmlhelp = htmlhelp + + # Set (output) directory name + def setdirname(self, dirname): + self.dirname = dirname + + # Set include directory name + def setincludedir(self, includedir): + self.includedir = includedir + + # Parse the contents of an entire file + def parse(self, fp): + line = fp.readline() + lineno = 1 + while line and (line[0] == '%' or blprog.match(line)): + line = fp.readline() + lineno = lineno + 1 + if line[:len(MAGIC)] <> MAGIC: + raise SyntaxError, 'file does not begin with %r' % (MAGIC,) + self.parserest(fp, lineno) + + # Parse the contents of a file, not expecting a MAGIC header + def parserest(self, fp, initial_lineno): + lineno = initial_lineno + self.done = 0 + self.skip = 0 + self.stack = [] + accu = [] + while not self.done: + line = fp.readline() + self.nodelineno = self.nodelineno + 1 + if not line: + if accu: + if not self.skip: self.process(accu) + accu = [] + if initial_lineno > 0: + print '*** EOF before @bye' + break + lineno = lineno + 1 + mo = cmprog.match(line) + if mo: + a, b = mo.span(1) + cmd = line[a:b] + if cmd in ('noindent', 'refill'): + accu.append(line) + else: + if accu: + if not self.skip: + self.process(accu) + accu = [] + self.command(line, mo) + elif blprog.match(line) and \ + 'format' not in self.stack and \ + 'example' not in self.stack: + if accu: + if not self.skip: + self.process(accu) + if self.nofill: + self.write('\n') + else: + self.write('<P>\n') + accu = [] + else: + # Append the line including trailing \n! + accu.append(line) + # + if self.skip: + print '*** Still skipping at the end' + if self.stack: + print '*** Stack not empty at the end' + print '***', self.stack + if self.includedepth == 0: + while self.nodestack: + self.nodestack[-1].finalize() + self.nodestack[-1].flush() + del self.nodestack[-1] + + # Start saving text in a buffer instead of writing it to a file + def startsaving(self): + if self.savetext <> None: + self.savestack.append(self.savetext) + # print '*** Recursively saving text, expect trouble' + self.savetext = '' + + # Return the text saved so far and start writing to file again + def collectsavings(self): + savetext = self.savetext + if len(self.savestack) > 0: + self.savetext = self.savestack[-1] + del self.savestack[-1] + else: + self.savetext = None + return savetext or '' + + # Write text to file, or save it in a buffer, or ignore it + def write(self, *args): + try: + text = ''.join(args) + except: + print args + raise TypeError + if self.savetext <> None: + self.savetext = self.savetext + text + elif self.nodefp: + self.nodefp.write(text) + elif self.node: + self.node.write(text) + + # Complete the current node -- write footnotes and close file + def endnode(self): + if self.savetext <> None: + print '*** Still saving text at end of node' + dummy = self.collectsavings() + if self.footnotes: + self.writefootnotes() + if self.nodefp: + if self.nodelineno > 20: + self.write('<HR>\n') + [name, next, prev, up] = self.nodelinks[:4] + self.link('Next', next) + self.link('Prev', prev) + self.link('Up', up) + if self.nodename <> self.topname: + self.link('Top', self.topname) + self.write('<HR>\n') + self.write('</BODY>\n') + self.nodefp.close() + self.nodefp = None + elif self.node: + if not self.cont and \ + (not self.node.type or \ + (self.node.next and self.node.prev and self.node.up)): + self.node.finalize() + self.node.flush() + else: + self.nodestack.append(self.node) + self.node = None + self.nodename = '' + + # Process a list of lines, expanding embedded @-commands + # This mostly distinguishes between menus and normal text + def process(self, accu): + if self.debugging > 1: + print '!'*self.debugging, 'process:', self.skip, self.stack, + if accu: print accu[0][:30], + if accu[0][30:] or accu[1:]: print '...', + print + if self.inmenu(): + # XXX should be done differently + for line in accu: + mo = miprog.match(line) + if not mo: + line = line.strip() + '\n' + self.expand(line) + continue + bgn, end = mo.span(0) + a, b = mo.span(1) + c, d = mo.span(2) + e, f = mo.span(3) + g, h = mo.span(4) + label = line[a:b] + nodename = line[c:d] + if nodename[0] == ':': nodename = label + else: nodename = line[e:f] + punct = line[g:h] + self.write(' <LI><A HREF="', + makefile(nodename), + '">', nodename, + '</A>', punct, '\n') + self.htmlhelp.menuitem(nodename) + self.expand(line[end:]) + else: + text = ''.join(accu) + self.expand(text) + + # find 'menu' (we might be inside 'ifset' or 'ifclear') + def inmenu(self): + #if 'menu' in self.stack: + # print 'inmenu :', self.skip, self.stack, self.stackinfo + stack = self.stack + while stack and stack[-1] in ('ifset','ifclear'): + try: + if self.stackinfo[len(stack)]: + return 0 + except KeyError: + pass + stack = stack[:-1] + return (stack and stack[-1] == 'menu') + + # Write a string, expanding embedded @-commands + def expand(self, text): + stack = [] + i = 0 + n = len(text) + while i < n: + start = i + mo = spprog.search(text, i) + if mo: + i = mo.start() + else: + self.write(text[start:]) + break + self.write(text[start:i]) + c = text[i] + i = i+1 + if c == '\n': + self.write('\n') + continue + if c == '<': + self.write('&lt;') + continue + if c == '>': + self.write('&gt;') + continue + if c == '&': + self.write('&amp;') + continue + if c == '{': + stack.append('') + continue + if c == '}': + if not stack: + print '*** Unmatched }' + self.write('}') + continue + cmd = stack[-1] + del stack[-1] + try: + method = getattr(self, 'close_' + cmd) + except AttributeError: + self.unknown_close(cmd) + continue + method() + continue + if c <> '@': + # Cannot happen unless spprog is changed + raise RuntimeError, 'unexpected funny %r' % c + start = i + while i < n and text[i] in string.ascii_letters: i = i+1 + if i == start: + # @ plus non-letter: literal next character + i = i+1 + c = text[start:i] + if c == ':': + # `@:' means no extra space after + # preceding `.', `?', `!' or `:' + pass + else: + # `@.' means a sentence-ending period; + # `@@', `@{', `@}' quote `@', `{', `}' + self.write(c) + continue + cmd = text[start:i] + if i < n and text[i] == '{': + i = i+1 + stack.append(cmd) + try: + method = getattr(self, 'open_' + cmd) + except AttributeError: + self.unknown_open(cmd) + continue + method() + continue + try: + method = getattr(self, 'handle_' + cmd) + except AttributeError: + self.unknown_handle(cmd) + continue + method() + if stack: + print '*** Stack not empty at para:', stack + + # --- Handle unknown embedded @-commands --- + + def unknown_open(self, cmd): + print '*** No open func for @' + cmd + '{...}' + cmd = cmd + '{' + self.write('@', cmd) + if not self.unknown.has_key(cmd): + self.unknown[cmd] = 1 + else: + self.unknown[cmd] = self.unknown[cmd] + 1 + + def unknown_close(self, cmd): + print '*** No close func for @' + cmd + '{...}' + cmd = '}' + cmd + self.write('}') + if not self.unknown.has_key(cmd): + self.unknown[cmd] = 1 + else: + self.unknown[cmd] = self.unknown[cmd] + 1 + + def unknown_handle(self, cmd): + print '*** No handler for @' + cmd + self.write('@', cmd) + if not self.unknown.has_key(cmd): + self.unknown[cmd] = 1 + else: + self.unknown[cmd] = self.unknown[cmd] + 1 + + # XXX The following sections should be ordered as the texinfo docs + + # --- Embedded @-commands without {} argument list -- + + def handle_noindent(self): pass + + def handle_refill(self): pass + + # --- Include file handling --- + + def do_include(self, args): + file = args + file = os.path.join(self.includedir, file) + try: + fp = open(file, 'r') + except IOError, msg: + print '*** Can\'t open include file', repr(file) + return + print '!'*self.debugging, '--> file', repr(file) + save_done = self.done + save_skip = self.skip + save_stack = self.stack + self.includedepth = self.includedepth + 1 + self.parserest(fp, 0) + self.includedepth = self.includedepth - 1 + fp.close() + self.done = save_done + self.skip = save_skip + self.stack = save_stack + print '!'*self.debugging, '<-- file', repr(file) + + # --- Special Insertions --- + + def open_dmn(self): pass + def close_dmn(self): pass + + def open_dots(self): self.write('...') + def close_dots(self): pass + + def open_bullet(self): pass + def close_bullet(self): pass + + def open_TeX(self): self.write('TeX') + def close_TeX(self): pass + + def handle_copyright(self): self.write(self.COPYRIGHT_SYMBOL) + def open_copyright(self): self.write(self.COPYRIGHT_SYMBOL) + def close_copyright(self): pass + + def open_minus(self): self.write('-') + def close_minus(self): pass + + # --- Accents --- + + # rpyron 2002-05-07 + # I would like to do at least as well as makeinfo when + # it is producing HTML output: + # + # input output + # @"o @"o umlaut accent + # @'o 'o acute accent + # @,{c} @,{c} cedilla accent + # @=o @=o macron/overbar accent + # @^o @^o circumflex accent + # @`o `o grave accent + # @~o @~o tilde accent + # @dotaccent{o} @dotaccent{o} overdot accent + # @H{o} @H{o} long Hungarian umlaut + # @ringaccent{o} @ringaccent{o} ring accent + # @tieaccent{oo} @tieaccent{oo} tie-after accent + # @u{o} @u{o} breve accent + # @ubaraccent{o} @ubaraccent{o} underbar accent + # @udotaccent{o} @udotaccent{o} underdot accent + # @v{o} @v{o} hacek or check accent + # @exclamdown{} &#161; upside-down ! + # @questiondown{} &#191; upside-down ? + # @aa{},@AA{} &#229;,&#197; a,A with circle + # @ae{},@AE{} &#230;,&#198; ae,AE ligatures + # @dotless{i} @dotless{i} dotless i + # @dotless{j} @dotless{j} dotless j + # @l{},@L{} l/,L/ suppressed-L,l + # @o{},@O{} &#248;,&#216; O,o with slash + # @oe{},@OE{} oe,OE oe,OE ligatures + # @ss{} &#223; es-zet or sharp S + # + # The following character codes and approximations have been + # copied from makeinfo's HTML output. + + def open_exclamdown(self): self.write('&#161;') # upside-down ! + def close_exclamdown(self): pass + def open_questiondown(self): self.write('&#191;') # upside-down ? + def close_questiondown(self): pass + def open_aa(self): self.write('&#229;') # a with circle + def close_aa(self): pass + def open_AA(self): self.write('&#197;') # A with circle + def close_AA(self): pass + def open_ae(self): self.write('&#230;') # ae ligatures + def close_ae(self): pass + def open_AE(self): self.write('&#198;') # AE ligatures + def close_AE(self): pass + def open_o(self): self.write('&#248;') # o with slash + def close_o(self): pass + def open_O(self): self.write('&#216;') # O with slash + def close_O(self): pass + def open_ss(self): self.write('&#223;') # es-zet or sharp S + def close_ss(self): pass + def open_oe(self): self.write('oe') # oe ligatures + def close_oe(self): pass + def open_OE(self): self.write('OE') # OE ligatures + def close_OE(self): pass + def open_l(self): self.write('l/') # suppressed-l + def close_l(self): pass + def open_L(self): self.write('L/') # suppressed-L + def close_L(self): pass + + # --- Special Glyphs for Examples --- + + def open_result(self): self.write('=&gt;') + def close_result(self): pass + + def open_expansion(self): self.write('==&gt;') + def close_expansion(self): pass + + def open_print(self): self.write('-|') + def close_print(self): pass + + def open_error(self): self.write('error--&gt;') + def close_error(self): pass + + def open_equiv(self): self.write('==') + def close_equiv(self): pass + + def open_point(self): self.write('-!-') + def close_point(self): pass + + # --- Cross References --- + + def open_pxref(self): + self.write('see ') + self.startsaving() + def close_pxref(self): + self.makeref() + + def open_xref(self): + self.write('See ') + self.startsaving() + def close_xref(self): + self.makeref() + + def open_ref(self): + self.startsaving() + def close_ref(self): + self.makeref() + + def open_inforef(self): + self.write('See info file ') + self.startsaving() + def close_inforef(self): + text = self.collectsavings() + args = [s.strip() for s in text.split(',')] + while len(args) < 3: args.append('') + node = args[0] + file = args[2] + self.write('`', file, '\', node `', node, '\'') + + def makeref(self): + text = self.collectsavings() + args = [s.strip() for s in text.split(',')] + while len(args) < 5: args.append('') + nodename = label = args[0] + if args[2]: label = args[2] + file = args[3] + title = args[4] + href = makefile(nodename) + if file: + href = '../' + file + '/' + href + self.write('<A HREF="', href, '">', label, '</A>') + + # rpyron 2002-05-07 uref support + def open_uref(self): + self.startsaving() + def close_uref(self): + text = self.collectsavings() + args = [s.strip() for s in text.split(',')] + while len(args) < 2: args.append('') + href = args[0] + label = args[1] + if not label: label = href + self.write('<A HREF="', href, '">', label, '</A>') + + # rpyron 2002-05-07 image support + # GNU makeinfo producing HTML output tries `filename.png'; if + # that does not exist, it tries `filename.jpg'. If that does + # not exist either, it complains. GNU makeinfo does not handle + # GIF files; however, I include GIF support here because + # MySQL documentation uses GIF files. + + def open_image(self): + self.startsaving() + def close_image(self): + self.makeimage() + def makeimage(self): + text = self.collectsavings() + args = [s.strip() for s in text.split(',')] + while len(args) < 5: args.append('') + filename = args[0] + width = args[1] + height = args[2] + alt = args[3] + ext = args[4] + + # The HTML output will have a reference to the image + # that is relative to the HTML output directory, + # which is what 'filename' gives us. However, we need + # to find it relative to our own current directory, + # so we construct 'imagename'. + imagelocation = self.dirname + '/' + filename + + if os.path.exists(imagelocation+'.png'): + filename += '.png' + elif os.path.exists(imagelocation+'.jpg'): + filename += '.jpg' + elif os.path.exists(imagelocation+'.gif'): # MySQL uses GIF files + filename += '.gif' + else: + print "*** Cannot find image " + imagelocation + #TODO: what is 'ext'? + self.write('<IMG SRC="', filename, '"', \ + width and (' WIDTH="' + width + '"') or "", \ + height and (' HEIGHT="' + height + '"') or "", \ + alt and (' ALT="' + alt + '"') or "", \ + '/>' ) + self.htmlhelp.addimage(imagelocation) + + + # --- Marking Words and Phrases --- + + # --- Other @xxx{...} commands --- + + def open_(self): pass # Used by {text enclosed in braces} + def close_(self): pass + + open_asis = open_ + close_asis = close_ + + def open_cite(self): self.write('<CITE>') + def close_cite(self): self.write('</CITE>') + + def open_code(self): self.write('<CODE>') + def close_code(self): self.write('</CODE>') + + def open_t(self): self.write('<TT>') + def close_t(self): self.write('</TT>') + + def open_dfn(self): self.write('<DFN>') + def close_dfn(self): self.write('</DFN>') + + def open_emph(self): self.write('<EM>') + def close_emph(self): self.write('</EM>') + + def open_i(self): self.write('<I>') + def close_i(self): self.write('</I>') + + def open_footnote(self): + # if self.savetext <> None: + # print '*** Recursive footnote -- expect weirdness' + id = len(self.footnotes) + 1 + self.write(self.FN_SOURCE_PATTERN % {'id': repr(id)}) + self.startsaving() + + def close_footnote(self): + id = len(self.footnotes) + 1 + self.footnotes.append((id, self.collectsavings())) + + def writefootnotes(self): + self.write(self.FN_HEADER) + for id, text in self.footnotes: + self.write(self.FN_TARGET_PATTERN + % {'id': repr(id), 'text': text}) + self.footnotes = [] + + def open_file(self): self.write('<CODE>') + def close_file(self): self.write('</CODE>') + + def open_kbd(self): self.write('<KBD>') + def close_kbd(self): self.write('</KBD>') + + def open_key(self): self.write('<KEY>') + def close_key(self): self.write('</KEY>') + + def open_r(self): self.write('<R>') + def close_r(self): self.write('</R>') + + def open_samp(self): self.write('`<SAMP>') + def close_samp(self): self.write('</SAMP>\'') + + def open_sc(self): self.write('<SMALLCAPS>') + def close_sc(self): self.write('</SMALLCAPS>') + + def open_strong(self): self.write('<STRONG>') + def close_strong(self): self.write('</STRONG>') + + def open_b(self): self.write('<B>') + def close_b(self): self.write('</B>') + + def open_var(self): self.write('<VAR>') + def close_var(self): self.write('</VAR>') + + def open_w(self): self.write('<NOBREAK>') + def close_w(self): self.write('</NOBREAK>') + + def open_url(self): self.startsaving() + def close_url(self): + text = self.collectsavings() + self.write('<A HREF="', text, '">', text, '</A>') + + def open_email(self): self.startsaving() + def close_email(self): + text = self.collectsavings() + self.write('<A HREF="mailto:', text, '">', text, '</A>') + + open_titlefont = open_ + close_titlefont = close_ + + def open_small(self): pass + def close_small(self): pass + + def command(self, line, mo): + a, b = mo.span(1) + cmd = line[a:b] + args = line[b:].strip() + if self.debugging > 1: + print '!'*self.debugging, 'command:', self.skip, self.stack, \ + '@' + cmd, args + try: + func = getattr(self, 'do_' + cmd) + except AttributeError: + try: + func = getattr(self, 'bgn_' + cmd) + except AttributeError: + # don't complain if we are skipping anyway + if not self.skip: + self.unknown_cmd(cmd, args) + return + self.stack.append(cmd) + func(args) + return + if not self.skip or cmd == 'end': + func(args) + + def unknown_cmd(self, cmd, args): + print '*** unknown', '@' + cmd, args + if not self.unknown.has_key(cmd): + self.unknown[cmd] = 1 + else: + self.unknown[cmd] = self.unknown[cmd] + 1 + + def do_end(self, args): + words = args.split() + if not words: + print '*** @end w/o args' + else: + cmd = words[0] + if not self.stack or self.stack[-1] <> cmd: + print '*** @end', cmd, 'unexpected' + else: + del self.stack[-1] + try: + func = getattr(self, 'end_' + cmd) + except AttributeError: + self.unknown_end(cmd) + return + func() + + def unknown_end(self, cmd): + cmd = 'end ' + cmd + print '*** unknown', '@' + cmd + if not self.unknown.has_key(cmd): + self.unknown[cmd] = 1 + else: + self.unknown[cmd] = self.unknown[cmd] + 1 + + # --- Comments --- + + def do_comment(self, args): pass + do_c = do_comment + + # --- Conditional processing --- + + def bgn_ifinfo(self, args): pass + def end_ifinfo(self): pass + + def bgn_iftex(self, args): self.skip = self.skip + 1 + def end_iftex(self): self.skip = self.skip - 1 + + def bgn_ignore(self, args): self.skip = self.skip + 1 + def end_ignore(self): self.skip = self.skip - 1 + + def bgn_tex(self, args): self.skip = self.skip + 1 + def end_tex(self): self.skip = self.skip - 1 + + def do_set(self, args): + fields = args.split(' ') + key = fields[0] + if len(fields) == 1: + value = 1 + else: + value = ' '.join(fields[1:]) + self.values[key] = value + + def do_clear(self, args): + self.values[args] = None + + def bgn_ifset(self, args): + if args not in self.values.keys() \ + or self.values[args] is None: + self.skip = self.skip + 1 + self.stackinfo[len(self.stack)] = 1 + else: + self.stackinfo[len(self.stack)] = 0 + def end_ifset(self): + try: + if self.stackinfo[len(self.stack) + 1]: + self.skip = self.skip - 1 + del self.stackinfo[len(self.stack) + 1] + except KeyError: + print '*** end_ifset: KeyError :', len(self.stack) + 1 + + def bgn_ifclear(self, args): + if args in self.values.keys() \ + and self.values[args] is not None: + self.skip = self.skip + 1 + self.stackinfo[len(self.stack)] = 1 + else: + self.stackinfo[len(self.stack)] = 0 + def end_ifclear(self): + try: + if self.stackinfo[len(self.stack) + 1]: + self.skip = self.skip - 1 + del self.stackinfo[len(self.stack) + 1] + except KeyError: + print '*** end_ifclear: KeyError :', len(self.stack) + 1 + + def open_value(self): + self.startsaving() + + def close_value(self): + key = self.collectsavings() + if key in self.values.keys(): + self.write(self.values[key]) + else: + print '*** Undefined value: ', key + + # --- Beginning a file --- + + do_finalout = do_comment + do_setchapternewpage = do_comment + do_setfilename = do_comment + + def do_settitle(self, args): + self.startsaving() + self.expand(args) + self.title = self.collectsavings() + def do_parskip(self, args): pass + + # --- Ending a file --- + + def do_bye(self, args): + self.endnode() + self.done = 1 + + # --- Title page --- + + def bgn_titlepage(self, args): self.skip = self.skip + 1 + def end_titlepage(self): self.skip = self.skip - 1 + def do_shorttitlepage(self, args): pass + + def do_center(self, args): + # Actually not used outside title page... + self.write('<H1>') + self.expand(args) + self.write('</H1>\n') + do_title = do_center + do_subtitle = do_center + do_author = do_center + + do_vskip = do_comment + do_vfill = do_comment + do_smallbook = do_comment + + do_paragraphindent = do_comment + do_setchapternewpage = do_comment + do_headings = do_comment + do_footnotestyle = do_comment + + do_evenheading = do_comment + do_evenfooting = do_comment + do_oddheading = do_comment + do_oddfooting = do_comment + do_everyheading = do_comment + do_everyfooting = do_comment + + # --- Nodes --- + + def do_node(self, args): + self.endnode() + self.nodelineno = 0 + parts = [s.strip() for s in args.split(',')] + while len(parts) < 4: parts.append('') + self.nodelinks = parts + [name, next, prev, up] = parts[:4] + file = self.dirname + '/' + makefile(name) + if self.filenames.has_key(file): + print '*** Filename already in use: ', file + else: + if self.debugging: print '!'*self.debugging, '--- writing', file + self.filenames[file] = 1 + # self.nodefp = open(file, 'w') + self.nodename = name + if self.cont and self.nodestack: + self.nodestack[-1].cont = self.nodename + if not self.topname: self.topname = name + title = name + if self.title: title = title + ' -- ' + self.title + self.node = self.Node(self.dirname, self.nodename, self.topname, + title, next, prev, up) + self.htmlhelp.addnode(self.nodename,next,prev,up,file) + + def link(self, label, nodename): + if nodename: + if nodename.lower() == '(dir)': + addr = '../dir.html' + else: + addr = makefile(nodename) + self.write(label, ': <A HREF="', addr, '" TYPE="', + label, '">', nodename, '</A> \n') + + # --- Sectioning commands --- + + def popstack(self, type): + if (self.node): + self.node.type = type + while self.nodestack: + if self.nodestack[-1].type > type: + self.nodestack[-1].finalize() + self.nodestack[-1].flush() + del self.nodestack[-1] + elif self.nodestack[-1].type == type: + if not self.nodestack[-1].next: + self.nodestack[-1].next = self.node.name + if not self.node.prev: + self.node.prev = self.nodestack[-1].name + self.nodestack[-1].finalize() + self.nodestack[-1].flush() + del self.nodestack[-1] + else: + if type > 1 and not self.node.up: + self.node.up = self.nodestack[-1].name + break + + def do_chapter(self, args): + self.heading('H1', args, 0) + self.popstack(1) + + def do_unnumbered(self, args): + self.heading('H1', args, -1) + self.popstack(1) + def do_appendix(self, args): + self.heading('H1', args, -1) + self.popstack(1) + def do_top(self, args): + self.heading('H1', args, -1) + def do_chapheading(self, args): + self.heading('H1', args, -1) + def do_majorheading(self, args): + self.heading('H1', args, -1) + + def do_section(self, args): + self.heading('H1', args, 1) + self.popstack(2) + + def do_unnumberedsec(self, args): + self.heading('H1', args, -1) + self.popstack(2) + def do_appendixsec(self, args): + self.heading('H1', args, -1) + self.popstack(2) + do_appendixsection = do_appendixsec + def do_heading(self, args): + self.heading('H1', args, -1) + + def do_subsection(self, args): + self.heading('H2', args, 2) + self.popstack(3) + def do_unnumberedsubsec(self, args): + self.heading('H2', args, -1) + self.popstack(3) + def do_appendixsubsec(self, args): + self.heading('H2', args, -1) + self.popstack(3) + def do_subheading(self, args): + self.heading('H2', args, -1) + + def do_subsubsection(self, args): + self.heading('H3', args, 3) + self.popstack(4) + def do_unnumberedsubsubsec(self, args): + self.heading('H3', args, -1) + self.popstack(4) + def do_appendixsubsubsec(self, args): + self.heading('H3', args, -1) + self.popstack(4) + def do_subsubheading(self, args): + self.heading('H3', args, -1) + + def heading(self, type, args, level): + if level >= 0: + while len(self.numbering) <= level: + self.numbering.append(0) + del self.numbering[level+1:] + self.numbering[level] = self.numbering[level] + 1 + x = '' + for i in self.numbering: + x = x + repr(i) + '.' + args = x + ' ' + args + self.contents.append((level, args, self.nodename)) + self.write('<', type, '>') + self.expand(args) + self.write('</', type, '>\n') + if self.debugging or self.print_headers: + print '---', args + + def do_contents(self, args): + # pass + self.listcontents('Table of Contents', 999) + + def do_shortcontents(self, args): + pass + # self.listcontents('Short Contents', 0) + do_summarycontents = do_shortcontents + + def listcontents(self, title, maxlevel): + self.write('<H1>', title, '</H1>\n<UL COMPACT PLAIN>\n') + prevlevels = [0] + for level, title, node in self.contents: + if level > maxlevel: + continue + if level > prevlevels[-1]: + # can only advance one level at a time + self.write(' '*prevlevels[-1], '<UL PLAIN>\n') + prevlevels.append(level) + elif level < prevlevels[-1]: + # might drop back multiple levels + while level < prevlevels[-1]: + del prevlevels[-1] + self.write(' '*prevlevels[-1], + '</UL>\n') + self.write(' '*level, '<LI> <A HREF="', + makefile(node), '">') + self.expand(title) + self.write('</A>\n') + self.write('</UL>\n' * len(prevlevels)) + + # --- Page lay-out --- + + # These commands are only meaningful in printed text + + def do_page(self, args): pass + + def do_need(self, args): pass + + def bgn_group(self, args): pass + def end_group(self): pass + + # --- Line lay-out --- + + def do_sp(self, args): + if self.nofill: + self.write('\n') + else: + self.write('<P>\n') + + def do_hline(self, args): + self.write('<HR>') + + # --- Function and variable definitions --- + + def bgn_deffn(self, args): + self.write('<DL>') + self.do_deffnx(args) + + def end_deffn(self): + self.write('</DL>\n') + + def do_deffnx(self, args): + self.write('<DT>') + words = splitwords(args, 2) + [category, name], rest = words[:2], words[2:] + self.expand('@b{%s}' % name) + for word in rest: self.expand(' ' + makevar(word)) + #self.expand(' -- ' + category) + self.write('\n<DD>') + self.index('fn', name) + + def bgn_defun(self, args): self.bgn_deffn('Function ' + args) + end_defun = end_deffn + def do_defunx(self, args): self.do_deffnx('Function ' + args) + + def bgn_defmac(self, args): self.bgn_deffn('Macro ' + args) + end_defmac = end_deffn + def do_defmacx(self, args): self.do_deffnx('Macro ' + args) + + def bgn_defspec(self, args): self.bgn_deffn('{Special Form} ' + args) + end_defspec = end_deffn + def do_defspecx(self, args): self.do_deffnx('{Special Form} ' + args) + + def bgn_defvr(self, args): + self.write('<DL>') + self.do_defvrx(args) + + end_defvr = end_deffn + + def do_defvrx(self, args): + self.write('<DT>') + words = splitwords(args, 2) + [category, name], rest = words[:2], words[2:] + self.expand('@code{%s}' % name) + # If there are too many arguments, show them + for word in rest: self.expand(' ' + word) + #self.expand(' -- ' + category) + self.write('\n<DD>') + self.index('vr', name) + + def bgn_defvar(self, args): self.bgn_defvr('Variable ' + args) + end_defvar = end_defvr + def do_defvarx(self, args): self.do_defvrx('Variable ' + args) + + def bgn_defopt(self, args): self.bgn_defvr('{User Option} ' + args) + end_defopt = end_defvr + def do_defoptx(self, args): self.do_defvrx('{User Option} ' + args) + + # --- Ditto for typed languages --- + + def bgn_deftypefn(self, args): + self.write('<DL>') + self.do_deftypefnx(args) + + end_deftypefn = end_deffn + + def do_deftypefnx(self, args): + self.write('<DT>') + words = splitwords(args, 3) + [category, datatype, name], rest = words[:3], words[3:] + self.expand('@code{%s} @b{%s}' % (datatype, name)) + for word in rest: self.expand(' ' + makevar(word)) + #self.expand(' -- ' + category) + self.write('\n<DD>') + self.index('fn', name) + + + def bgn_deftypefun(self, args): self.bgn_deftypefn('Function ' + args) + end_deftypefun = end_deftypefn + def do_deftypefunx(self, args): self.do_deftypefnx('Function ' + args) + + def bgn_deftypevr(self, args): + self.write('<DL>') + self.do_deftypevrx(args) + + end_deftypevr = end_deftypefn + + def do_deftypevrx(self, args): + self.write('<DT>') + words = splitwords(args, 3) + [category, datatype, name], rest = words[:3], words[3:] + self.expand('@code{%s} @b{%s}' % (datatype, name)) + # If there are too many arguments, show them + for word in rest: self.expand(' ' + word) + #self.expand(' -- ' + category) + self.write('\n<DD>') + self.index('fn', name) + + def bgn_deftypevar(self, args): + self.bgn_deftypevr('Variable ' + args) + end_deftypevar = end_deftypevr + def do_deftypevarx(self, args): + self.do_deftypevrx('Variable ' + args) + + # --- Ditto for object-oriented languages --- + + def bgn_defcv(self, args): + self.write('<DL>') + self.do_defcvx(args) + + end_defcv = end_deftypevr + + def do_defcvx(self, args): + self.write('<DT>') + words = splitwords(args, 3) + [category, classname, name], rest = words[:3], words[3:] + self.expand('@b{%s}' % name) + # If there are too many arguments, show them + for word in rest: self.expand(' ' + word) + #self.expand(' -- %s of @code{%s}' % (category, classname)) + self.write('\n<DD>') + self.index('vr', '%s @r{on %s}' % (name, classname)) + + def bgn_defivar(self, args): + self.bgn_defcv('{Instance Variable} ' + args) + end_defivar = end_defcv + def do_defivarx(self, args): + self.do_defcvx('{Instance Variable} ' + args) + + def bgn_defop(self, args): + self.write('<DL>') + self.do_defopx(args) + + end_defop = end_defcv + + def do_defopx(self, args): + self.write('<DT>') + words = splitwords(args, 3) + [category, classname, name], rest = words[:3], words[3:] + self.expand('@b{%s}' % name) + for word in rest: self.expand(' ' + makevar(word)) + #self.expand(' -- %s of @code{%s}' % (category, classname)) + self.write('\n<DD>') + self.index('fn', '%s @r{on %s}' % (name, classname)) + + def bgn_defmethod(self, args): + self.bgn_defop('Method ' + args) + end_defmethod = end_defop + def do_defmethodx(self, args): + self.do_defopx('Method ' + args) + + # --- Ditto for data types --- + + def bgn_deftp(self, args): + self.write('<DL>') + self.do_deftpx(args) + + end_deftp = end_defcv + + def do_deftpx(self, args): + self.write('<DT>') + words = splitwords(args, 2) + [category, name], rest = words[:2], words[2:] + self.expand('@b{%s}' % name) + for word in rest: self.expand(' ' + word) + #self.expand(' -- ' + category) + self.write('\n<DD>') + self.index('tp', name) + + # --- Making Lists and Tables + + def bgn_enumerate(self, args): + if not args: + self.write('<OL>\n') + self.stackinfo[len(self.stack)] = '</OL>\n' + else: + self.itemnumber = args + self.write('<UL>\n') + self.stackinfo[len(self.stack)] = '</UL>\n' + def end_enumerate(self): + self.itemnumber = None + self.write(self.stackinfo[len(self.stack) + 1]) + del self.stackinfo[len(self.stack) + 1] + + def bgn_itemize(self, args): + self.itemarg = args + self.write('<UL>\n') + def end_itemize(self): + self.itemarg = None + self.write('</UL>\n') + + def bgn_table(self, args): + self.itemarg = args + self.write('<DL>\n') + def end_table(self): + self.itemarg = None + self.write('</DL>\n') + + def bgn_ftable(self, args): + self.itemindex = 'fn' + self.bgn_table(args) + def end_ftable(self): + self.itemindex = None + self.end_table() + + def bgn_vtable(self, args): + self.itemindex = 'vr' + self.bgn_table(args) + def end_vtable(self): + self.itemindex = None + self.end_table() + + def do_item(self, args): + if self.itemindex: self.index(self.itemindex, args) + if self.itemarg: + if self.itemarg[0] == '@' and self.itemarg[1] and \ + self.itemarg[1] in string.ascii_letters: + args = self.itemarg + '{' + args + '}' + else: + # some other character, e.g. '-' + args = self.itemarg + ' ' + args + if self.itemnumber <> None: + args = self.itemnumber + '. ' + args + self.itemnumber = increment(self.itemnumber) + if self.stack and self.stack[-1] == 'table': + self.write('<DT>') + self.expand(args) + self.write('\n<DD>') + elif self.stack and self.stack[-1] == 'multitable': + self.write('<TR><TD>') + self.expand(args) + self.write('</TD>\n</TR>\n') + else: + self.write('<LI>') + self.expand(args) + self.write(' ') + do_itemx = do_item # XXX Should suppress leading blank line + + # rpyron 2002-05-07 multitable support + def bgn_multitable(self, args): + self.itemarg = None # should be handled by columnfractions + self.write('<TABLE BORDER="">\n') + def end_multitable(self): + self.itemarg = None + self.write('</TABLE>\n<BR>\n') + def handle_columnfractions(self): + # It would be better to handle this, but for now it's in the way... + self.itemarg = None + def handle_tab(self): + self.write('</TD>\n <TD>') + + # --- Enumerations, displays, quotations --- + # XXX Most of these should increase the indentation somehow + + def bgn_quotation(self, args): self.write('<BLOCKQUOTE>') + def end_quotation(self): self.write('</BLOCKQUOTE>\n') + + def bgn_example(self, args): + self.nofill = self.nofill + 1 + self.write('<PRE>') + def end_example(self): + self.write('</PRE>\n') + self.nofill = self.nofill - 1 + + bgn_lisp = bgn_example # Synonym when contents are executable lisp code + end_lisp = end_example + + bgn_smallexample = bgn_example # XXX Should use smaller font + end_smallexample = end_example + + bgn_smalllisp = bgn_lisp # Ditto + end_smalllisp = end_lisp + + bgn_display = bgn_example + end_display = end_example + + bgn_format = bgn_display + end_format = end_display + + def do_exdent(self, args): self.expand(args + '\n') + # XXX Should really mess with indentation + + def bgn_flushleft(self, args): + self.nofill = self.nofill + 1 + self.write('<PRE>\n') + def end_flushleft(self): + self.write('</PRE>\n') + self.nofill = self.nofill - 1 + + def bgn_flushright(self, args): + self.nofill = self.nofill + 1 + self.write('<ADDRESS COMPACT>\n') + def end_flushright(self): + self.write('</ADDRESS>\n') + self.nofill = self.nofill - 1 + + def bgn_menu(self, args): + self.write('<DIR>\n') + self.write(' <STRONG><EM>Menu</EM></STRONG><P>\n') + self.htmlhelp.beginmenu() + def end_menu(self): + self.write('</DIR>\n') + self.htmlhelp.endmenu() + + def bgn_cartouche(self, args): pass + def end_cartouche(self): pass + + # --- Indices --- + + def resetindex(self): + self.noncodeindices = ['cp'] + self.indextitle = {} + self.indextitle['cp'] = 'Concept' + self.indextitle['fn'] = 'Function' + self.indextitle['ky'] = 'Keyword' + self.indextitle['pg'] = 'Program' + self.indextitle['tp'] = 'Type' + self.indextitle['vr'] = 'Variable' + # + self.whichindex = {} + for name in self.indextitle.keys(): + self.whichindex[name] = [] + + def user_index(self, name, args): + if self.whichindex.has_key(name): + self.index(name, args) + else: + print '*** No index named', repr(name) + + def do_cindex(self, args): self.index('cp', args) + def do_findex(self, args): self.index('fn', args) + def do_kindex(self, args): self.index('ky', args) + def do_pindex(self, args): self.index('pg', args) + def do_tindex(self, args): self.index('tp', args) + def do_vindex(self, args): self.index('vr', args) + + def index(self, name, args): + self.whichindex[name].append((args, self.nodename)) + self.htmlhelp.index(args, self.nodename) + + def do_synindex(self, args): + words = args.split() + if len(words) <> 2: + print '*** bad @synindex', args + return + [old, new] = words + if not self.whichindex.has_key(old) or \ + not self.whichindex.has_key(new): + print '*** bad key(s) in @synindex', args + return + if old <> new and \ + self.whichindex[old] is not self.whichindex[new]: + inew = self.whichindex[new] + inew[len(inew):] = self.whichindex[old] + self.whichindex[old] = inew + do_syncodeindex = do_synindex # XXX Should use code font + + def do_printindex(self, args): + words = args.split() + for name in words: + if self.whichindex.has_key(name): + self.prindex(name) + else: + print '*** No index named', repr(name) + + def prindex(self, name): + iscodeindex = (name not in self.noncodeindices) + index = self.whichindex[name] + if not index: return + if self.debugging: + print '!'*self.debugging, '--- Generating', \ + self.indextitle[name], 'index' + # The node already provides a title + index1 = [] + junkprog = re.compile('^(@[a-z]+)?{') + for key, node in index: + sortkey = key.lower() + # Remove leading `@cmd{' from sort key + # -- don't bother about the matching `}' + oldsortkey = sortkey + while 1: + mo = junkprog.match(sortkey) + if not mo: + break + i = mo.end() + sortkey = sortkey[i:] + index1.append((sortkey, key, node)) + del index[:] + index1.sort() + self.write('<DL COMPACT>\n') + prevkey = prevnode = None + for sortkey, key, node in index1: + if (key, node) == (prevkey, prevnode): + continue + if self.debugging > 1: print '!'*self.debugging, key, ':', node + self.write('<DT>') + if iscodeindex: key = '@code{' + key + '}' + if key != prevkey: + self.expand(key) + self.write('\n<DD><A HREF="%s">%s</A>\n' % (makefile(node), node)) + prevkey, prevnode = key, node + self.write('</DL>\n') + + # --- Final error reports --- + + def report(self): + if self.unknown: + print '--- Unrecognized commands ---' + cmds = self.unknown.keys() + cmds.sort() + for cmd in cmds: + print cmd.ljust(20), self.unknown[cmd] + + +class TexinfoParserHTML3(TexinfoParser): + + COPYRIGHT_SYMBOL = "&copy;" + FN_ID_PATTERN = "[%(id)s]" + FN_SOURCE_PATTERN = '<A ID=footnoteref%(id)s ' \ + 'HREF="#footnotetext%(id)s">' + FN_ID_PATTERN + '</A>' + FN_TARGET_PATTERN = '<FN ID=footnotetext%(id)s>\n' \ + '<P><A HREF="#footnoteref%(id)s">' + FN_ID_PATTERN \ + + '</A>\n%(text)s</P></FN>\n' + FN_HEADER = '<DIV CLASS=footnotes>\n <HR NOSHADE WIDTH=200>\n' \ + ' <STRONG><EM>Footnotes</EM></STRONG>\n <P>\n' + + Node = HTML3Node + + def bgn_quotation(self, args): self.write('<BQ>') + def end_quotation(self): self.write('</BQ>\n') + + def bgn_example(self, args): + # this use of <CODE> would not be legal in HTML 2.0, + # but is in more recent DTDs. + self.nofill = self.nofill + 1 + self.write('<PRE CLASS=example><CODE>') + def end_example(self): + self.write("</CODE></PRE>\n") + self.nofill = self.nofill - 1 + + def bgn_flushleft(self, args): + self.nofill = self.nofill + 1 + self.write('<PRE CLASS=flushleft>\n') + + def bgn_flushright(self, args): + self.nofill = self.nofill + 1 + self.write('<DIV ALIGN=right CLASS=flushright><ADDRESS COMPACT>\n') + def end_flushright(self): + self.write('</ADDRESS></DIV>\n') + self.nofill = self.nofill - 1 + + def bgn_menu(self, args): + self.write('<UL PLAIN CLASS=menu>\n') + self.write(' <LH>Menu</LH>\n') + def end_menu(self): + self.write('</UL>\n') + + +# rpyron 2002-05-07 +class HTMLHelp: + """ + This class encapsulates support for HTML Help. Node names, + file names, menu items, index items, and image file names are + accumulated until a call to finalize(). At that time, three + output files are created in the current directory: + + `helpbase`.hhp is a HTML Help Workshop project file. + It contains various information, some of + which I do not understand; I just copied + the default project info from a fresh + installation. + `helpbase`.hhc is the Contents file for the project. + `helpbase`.hhk is the Index file for the project. + + When these files are used as input to HTML Help Workshop, + the resulting file will be named: + + `helpbase`.chm + + If none of the defaults in `helpbase`.hhp are changed, + the .CHM file will have Contents, Index, Search, and + Favorites tabs. + """ + + codeprog = re.compile('@code{(.*?)}') + + def __init__(self,helpbase,dirname): + self.helpbase = helpbase + self.dirname = dirname + self.projectfile = None + self.contentfile = None + self.indexfile = None + self.nodelist = [] + self.nodenames = {} # nodename : index + self.nodeindex = {} + self.filenames = {} # filename : filename + self.indexlist = [] # (args,nodename) == (key,location) + self.current = '' + self.menudict = {} + self.dumped = {} + + + def addnode(self,name,next,prev,up,filename): + node = (name,next,prev,up,filename) + # add this file to dict + # retrieve list with self.filenames.values() + self.filenames[filename] = filename + # add this node to nodelist + self.nodeindex[name] = len(self.nodelist) + self.nodelist.append(node) + # set 'current' for menu items + self.current = name + self.menudict[self.current] = [] + + def menuitem(self,nodename): + menu = self.menudict[self.current] + menu.append(nodename) + + + def addimage(self,imagename): + self.filenames[imagename] = imagename + + def index(self, args, nodename): + self.indexlist.append((args,nodename)) + + def beginmenu(self): + pass + + def endmenu(self): + pass + + def finalize(self): + if not self.helpbase: + return + + # generate interesting filenames + resultfile = self.helpbase + '.chm' + projectfile = self.helpbase + '.hhp' + contentfile = self.helpbase + '.hhc' + indexfile = self.helpbase + '.hhk' + + # generate a reasonable title + title = self.helpbase + + # get the default topic file + (topname,topnext,topprev,topup,topfile) = self.nodelist[0] + defaulttopic = topfile + + # PROJECT FILE + try: + fp = open(projectfile,'w') + print>>fp, '[OPTIONS]' + print>>fp, 'Auto Index=Yes' + print>>fp, 'Binary TOC=No' + print>>fp, 'Binary Index=Yes' + print>>fp, 'Compatibility=1.1' + print>>fp, 'Compiled file=' + resultfile + '' + print>>fp, 'Contents file=' + contentfile + '' + print>>fp, 'Default topic=' + defaulttopic + '' + print>>fp, 'Error log file=ErrorLog.log' + print>>fp, 'Index file=' + indexfile + '' + print>>fp, 'Title=' + title + '' + print>>fp, 'Display compile progress=Yes' + print>>fp, 'Full-text search=Yes' + print>>fp, 'Default window=main' + print>>fp, '' + print>>fp, '[WINDOWS]' + print>>fp, ('main=,"' + contentfile + '","' + indexfile + + '","","",,,,,0x23520,222,0x1046,[10,10,780,560],' + '0xB0000,,,,,,0') + print>>fp, '' + print>>fp, '[FILES]' + print>>fp, '' + self.dumpfiles(fp) + fp.close() + except IOError, msg: + print projectfile, ':', msg + sys.exit(1) + + # CONTENT FILE + try: + fp = open(contentfile,'w') + print>>fp, '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">' + print>>fp, '<!-- This file defines the table of contents -->' + print>>fp, '<HTML>' + print>>fp, '<HEAD>' + print>>fp, ('<meta name="GENERATOR"' + 'content="Microsoft&reg; HTML Help Workshop 4.1">') + print>>fp, '<!-- Sitemap 1.0 -->' + print>>fp, '</HEAD>' + print>>fp, '<BODY>' + print>>fp, ' <OBJECT type="text/site properties">' + print>>fp, ' <param name="Window Styles" value="0x800025">' + print>>fp, ' <param name="comment" value="title:">' + print>>fp, ' <param name="comment" value="base:">' + print>>fp, ' </OBJECT>' + self.dumpnodes(fp) + print>>fp, '</BODY>' + print>>fp, '</HTML>' + fp.close() + except IOError, msg: + print contentfile, ':', msg + sys.exit(1) + + # INDEX FILE + try: + fp = open(indexfile ,'w') + print>>fp, '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">' + print>>fp, '<!-- This file defines the index -->' + print>>fp, '<HTML>' + print>>fp, '<HEAD>' + print>>fp, ('<meta name="GENERATOR"' + 'content="Microsoft&reg; HTML Help Workshop 4.1">') + print>>fp, '<!-- Sitemap 1.0 -->' + print>>fp, '</HEAD>' + print>>fp, '<BODY>' + print>>fp, '<OBJECT type="text/site properties">' + print>>fp, '</OBJECT>' + self.dumpindex(fp) + print>>fp, '</BODY>' + print>>fp, '</HTML>' + fp.close() + except IOError, msg: + print indexfile , ':', msg + sys.exit(1) + + def dumpfiles(self, outfile=sys.stdout): + filelist = self.filenames.values() + filelist.sort() + for filename in filelist: + print>>outfile, filename + + def dumpnodes(self, outfile=sys.stdout): + self.dumped = {} + if self.nodelist: + nodename, dummy, dummy, dummy, dummy = self.nodelist[0] + self.topnode = nodename + + print>>outfile, '<UL>' + for node in self.nodelist: + self.dumpnode(node,0,outfile) + print>>outfile, '</UL>' + + def dumpnode(self, node, indent=0, outfile=sys.stdout): + if node: + # Retrieve info for this node + (nodename,next,prev,up,filename) = node + self.current = nodename + + # Have we been dumped already? + if self.dumped.has_key(nodename): + return + self.dumped[nodename] = 1 + + # Print info for this node + print>>outfile, ' '*indent, + print>>outfile, '<LI><OBJECT type="text/sitemap">', + print>>outfile, '<param name="Name" value="' + nodename +'">', + print>>outfile, '<param name="Local" value="'+ filename +'">', + print>>outfile, '</OBJECT>' + + # Does this node have menu items? + try: + menu = self.menudict[nodename] + self.dumpmenu(menu,indent+2,outfile) + except KeyError: + pass + + def dumpmenu(self, menu, indent=0, outfile=sys.stdout): + if menu: + currentnode = self.current + if currentnode != self.topnode: # XXX this is a hack + print>>outfile, ' '*indent + '<UL>' + indent += 2 + for item in menu: + menunode = self.getnode(item) + self.dumpnode(menunode,indent,outfile) + if currentnode != self.topnode: # XXX this is a hack + print>>outfile, ' '*indent + '</UL>' + indent -= 2 + + def getnode(self, nodename): + try: + index = self.nodeindex[nodename] + return self.nodelist[index] + except KeyError: + return None + except IndexError: + return None + + # (args,nodename) == (key,location) + def dumpindex(self, outfile=sys.stdout): + print>>outfile, '<UL>' + for (key,location) in self.indexlist: + key = self.codeexpand(key) + location = makefile(location) + location = self.dirname + '/' + location + print>>outfile, '<LI><OBJECT type="text/sitemap">', + print>>outfile, '<param name="Name" value="' + key + '">', + print>>outfile, '<param name="Local" value="' + location + '">', + print>>outfile, '</OBJECT>' + print>>outfile, '</UL>' + + def codeexpand(self, line): + co = self.codeprog.match(line) + if not co: + return line + bgn, end = co.span(0) + a, b = co.span(1) + line = line[:bgn] + line[a:b] + line[end:] + return line + + +# Put @var{} around alphabetic substrings +def makevar(str): + return '@var{'+str+'}' + + +# Split a string in "words" according to findwordend +def splitwords(str, minlength): + words = [] + i = 0 + n = len(str) + while i < n: + while i < n and str[i] in ' \t\n': i = i+1 + if i >= n: break + start = i + i = findwordend(str, i, n) + words.append(str[start:i]) + while len(words) < minlength: words.append('') + return words + + +# Find the end of a "word", matching braces and interpreting @@ @{ @} +fwprog = re.compile('[@{} ]') +def findwordend(str, i, n): + level = 0 + while i < n: + mo = fwprog.search(str, i) + if not mo: + break + i = mo.start() + c = str[i]; i = i+1 + if c == '@': i = i+1 # Next character is not special + elif c == '{': level = level+1 + elif c == '}': level = level-1 + elif c == ' ' and level <= 0: return i-1 + return n + + +# Convert a node name into a file name +def makefile(nodename): + nodename = nodename.strip() + return fixfunnychars(nodename) + '.html' + + +# Characters that are perfectly safe in filenames and hyperlinks +goodchars = string.ascii_letters + string.digits + '!@-=+.' + +# Replace characters that aren't perfectly safe by dashes +# Underscores are bad since Cern HTTPD treats them as delimiters for +# encoding times, so you get mismatches if you compress your files: +# a.html.gz will map to a_b.html.gz +def fixfunnychars(addr): + i = 0 + while i < len(addr): + c = addr[i] + if c not in goodchars: + c = '-' + addr = addr[:i] + c + addr[i+1:] + i = i + len(c) + return addr + + +# Increment a string used as an enumeration +def increment(s): + if not s: + return '1' + for sequence in string.digits, string.lowercase, string.uppercase: + lastc = s[-1] + if lastc in sequence: + i = sequence.index(lastc) + 1 + if i >= len(sequence): + if len(s) == 1: + s = sequence[0]*2 + if s == '00': + s = '10' + else: + s = increment(s[:-1]) + sequence[0] + else: + s = s[:-1] + sequence[i] + return s + return s # Don't increment + + +def test(): + import sys + debugging = 0 + print_headers = 0 + cont = 0 + html3 = 0 + htmlhelp = '' + + while sys.argv[1] == ['-d']: + debugging = debugging + 1 + del sys.argv[1] + if sys.argv[1] == '-p': + print_headers = 1 + del sys.argv[1] + if sys.argv[1] == '-c': + cont = 1 + del sys.argv[1] + if sys.argv[1] == '-3': + html3 = 1 + del sys.argv[1] + if sys.argv[1] == '-H': + helpbase = sys.argv[2] + del sys.argv[1:3] + if len(sys.argv) <> 3: + print 'usage: texi2hh [-d [-d]] [-p] [-c] [-3] [-H htmlhelp]', \ + 'inputfile outputdirectory' + sys.exit(2) + + if html3: + parser = TexinfoParserHTML3() + else: + parser = TexinfoParser() + parser.cont = cont + parser.debugging = debugging + parser.print_headers = print_headers + + file = sys.argv[1] + dirname = sys.argv[2] + parser.setdirname(dirname) + parser.setincludedir(os.path.dirname(file)) + + htmlhelp = HTMLHelp(helpbase, dirname) + parser.sethtmlhelp(htmlhelp) + + try: + fp = open(file, 'r') + except IOError, msg: + print file, ':', msg + sys.exit(1) + + parser.parse(fp) + fp.close() + parser.report() + + htmlhelp.finalize() + + +if __name__ == "__main__": + test() diff --git a/sys/src/cmd/python/Tools/scripts/treesync.py b/sys/src/cmd/python/Tools/scripts/treesync.py new file mode 100755 index 000000000..ab9324bae --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/treesync.py @@ -0,0 +1,205 @@ +#! /usr/bin/env python + +"""Script to synchronize two source trees. + +Invoke with two arguments: + +python treesync.py slave master + +The assumption is that "master" contains CVS administration while +slave doesn't. All files in the slave tree that have a CVS/Entries +entry in the master tree are synchronized. This means: + + If the files differ: + if the slave file is newer: + normalize the slave file + if the files still differ: + copy the slave to the master + else (the master is newer): + copy the master to the slave + + normalizing the slave means replacing CRLF with LF when the master + doesn't use CRLF + +""" + +import os, sys, stat, getopt + +# Interactivity options +default_answer = "ask" +create_files = "yes" +create_directories = "no" +write_slave = "ask" +write_master = "ask" + +def main(): + global always_no, always_yes + global create_directories, write_master, write_slave + opts, args = getopt.getopt(sys.argv[1:], "nym:s:d:f:a:") + for o, a in opts: + if o == '-y': + default_answer = "yes" + if o == '-n': + default_answer = "no" + if o == '-s': + write_slave = a + if o == '-m': + write_master = a + if o == '-d': + create_directories = a + if o == '-f': + create_files = a + if o == '-a': + create_files = create_directories = write_slave = write_master = a + try: + [slave, master] = args + except ValueError: + print "usage: python", sys.argv[0] or "treesync.py", + print "[-n] [-y] [-m y|n|a] [-s y|n|a] [-d y|n|a] [-f n|y|a]", + print "slavedir masterdir" + return + process(slave, master) + +def process(slave, master): + cvsdir = os.path.join(master, "CVS") + if not os.path.isdir(cvsdir): + print "skipping master subdirectory", master + print "-- not under CVS" + return + print "-"*40 + print "slave ", slave + print "master", master + if not os.path.isdir(slave): + if not okay("create slave directory %s?" % slave, + answer=create_directories): + print "skipping master subdirectory", master + print "-- no corresponding slave", slave + return + print "creating slave directory", slave + try: + os.mkdir(slave) + except os.error, msg: + print "can't make slave directory", slave, ":", msg + return + else: + print "made slave directory", slave + cvsdir = None + subdirs = [] + names = os.listdir(master) + for name in names: + mastername = os.path.join(master, name) + slavename = os.path.join(slave, name) + if name == "CVS": + cvsdir = mastername + else: + if os.path.isdir(mastername) and not os.path.islink(mastername): + subdirs.append((slavename, mastername)) + if cvsdir: + entries = os.path.join(cvsdir, "Entries") + for e in open(entries).readlines(): + words = e.split('/') + if words[0] == '' and words[1:]: + name = words[1] + s = os.path.join(slave, name) + m = os.path.join(master, name) + compare(s, m) + for (s, m) in subdirs: + process(s, m) + +def compare(slave, master): + try: + sf = open(slave, 'r') + except IOError: + sf = None + try: + mf = open(master, 'rb') + except IOError: + mf = None + if not sf: + if not mf: + print "Neither master nor slave exists", master + return + print "Creating missing slave", slave + copy(master, slave, answer=create_files) + return + if not mf: + print "Not updating missing master", master + return + if sf and mf: + if identical(sf, mf): + return + sft = mtime(sf) + mft = mtime(mf) + if mft > sft: + # Master is newer -- copy master to slave + sf.close() + mf.close() + print "Master ", master + print "is newer than slave", slave + copy(master, slave, answer=write_slave) + return + # Slave is newer -- copy slave to master + print "Slave is", sft-mft, "seconds newer than master" + # But first check what to do about CRLF + mf.seek(0) + fun = funnychars(mf) + mf.close() + sf.close() + if fun: + print "***UPDATING MASTER (BINARY COPY)***" + copy(slave, master, "rb", answer=write_master) + else: + print "***UPDATING MASTER***" + copy(slave, master, "r", answer=write_master) + +BUFSIZE = 16*1024 + +def identical(sf, mf): + while 1: + sd = sf.read(BUFSIZE) + md = mf.read(BUFSIZE) + if sd != md: return 0 + if not sd: break + return 1 + +def mtime(f): + st = os.fstat(f.fileno()) + return st[stat.ST_MTIME] + +def funnychars(f): + while 1: + buf = f.read(BUFSIZE) + if not buf: break + if '\r' in buf or '\0' in buf: return 1 + return 0 + +def copy(src, dst, rmode="rb", wmode="wb", answer='ask'): + print "copying", src + print " to", dst + if not okay("okay to copy? ", answer): + return + f = open(src, rmode) + g = open(dst, wmode) + while 1: + buf = f.read(BUFSIZE) + if not buf: break + g.write(buf) + f.close() + g.close() + +def okay(prompt, answer='ask'): + answer = answer.strip().lower() + if not answer or answer[0] not in 'ny': + answer = raw_input(prompt) + answer = answer.strip().lower() + if not answer: + answer = default_answer + if answer[:1] == 'y': + return 1 + if answer[:1] == 'n': + return 0 + print "Yes or No please -- try again:" + return okay(prompt) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/untabify.py b/sys/src/cmd/python/Tools/scripts/untabify.py new file mode 100755 index 000000000..9bdf235b6 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/untabify.py @@ -0,0 +1,52 @@ +#! /usr/bin/env python + +"Replace tabs with spaces in argument files. Print names of changed files." + +import os +import sys +import getopt + +def main(): + tabsize = 8 + try: + opts, args = getopt.getopt(sys.argv[1:], "t:") + if not args: + raise getopt.error, "At least one file argument required" + except getopt.error, msg: + print msg + print "usage:", sys.argv[0], "[-t tabwidth] file ..." + return + for optname, optvalue in opts: + if optname == '-t': + tabsize = int(optvalue) + + for filename in args: + process(filename, tabsize) + +def process(filename, tabsize): + try: + f = open(filename) + text = f.read() + f.close() + except IOError, msg: + print "%r: I/O error: %s" % (filename, msg) + return + newtext = text.expandtabs(tabsize) + if newtext == text: + return + backup = filename + "~" + try: + os.unlink(backup) + except os.error: + pass + try: + os.rename(filename, backup) + except os.error: + pass + f = open(filename, "w") + f.write(newtext) + f.close() + print filename + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/which.py b/sys/src/cmd/python/Tools/scripts/which.py new file mode 100755 index 000000000..49b69acf8 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/which.py @@ -0,0 +1,60 @@ +#! /usr/bin/env python + +# Variant of "which". +# On stderr, near and total misses are reported. +# '-l<flags>' argument adds ls -l<flags> of each file found. + +import sys +if sys.path[0] in (".", ""): del sys.path[0] + +import sys, os +from stat import * + +def msg(str): + sys.stderr.write(str + '\n') + +def main(): + pathlist = os.environ['PATH'].split(os.pathsep) + + sts = 0 + longlist = '' + + if sys.argv[1:] and sys.argv[1][:2] == '-l': + longlist = sys.argv[1] + del sys.argv[1] + + for prog in sys.argv[1:]: + ident = () + for dir in pathlist: + filename = os.path.join(dir, prog) + try: + st = os.stat(filename) + except os.error: + continue + if not S_ISREG(st[ST_MODE]): + msg(filename + ': not a disk file') + else: + mode = S_IMODE(st[ST_MODE]) + if mode & 0111: + if not ident: + print filename + ident = st[:3] + else: + if st[:3] == ident: + s = 'same as: ' + else: + s = 'also: ' + msg(s + filename) + else: + msg(filename + ': not executable') + if longlist: + sts = os.system('ls ' + longlist + ' ' + filename) + if sts: msg('"ls -l" exit status: ' + repr(sts)) + if not ident: + msg(prog + ': not found') + sts = 1 + + sys.exit(sts) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/scripts/xxci.py b/sys/src/cmd/python/Tools/scripts/xxci.py new file mode 100755 index 000000000..c6a7d0872 --- /dev/null +++ b/sys/src/cmd/python/Tools/scripts/xxci.py @@ -0,0 +1,117 @@ +#! /usr/bin/env python + +# xxci +# +# check in files for which rcsdiff returns nonzero exit status + +import sys +import os +from stat import * +import commands +import fnmatch + +EXECMAGIC = '\001\140\000\010' + +MAXSIZE = 200*1024 # Files this big must be binaries and are skipped. + +def getargs(): + args = sys.argv[1:] + if args: + return args + print 'No arguments, checking almost *, in "ls -t" order' + list = [] + for file in os.listdir(os.curdir): + if not skipfile(file): + list.append((getmtime(file), file)) + list.sort() + if not list: + print 'Nothing to do -- exit 1' + sys.exit(1) + list.sort() + list.reverse() + for mtime, file in list: args.append(file) + return args + +def getmtime(file): + try: + st = os.stat(file) + return st[ST_MTIME] + except os.error: + return -1 + +badnames = ['tags', 'TAGS', 'xyzzy', 'nohup.out', 'core'] +badprefixes = ['.', ',', '@', '#', 'o.'] +badsuffixes = \ + ['~', '.a', '.o', '.old', '.bak', '.orig', '.new', '.prev', '.not', \ + '.pyc', '.fdc', '.rgb', '.elc', ',v'] +ignore = [] + +def setup(): + ignore[:] = badnames + for p in badprefixes: + ignore.append(p + '*') + for p in badsuffixes: + ignore.append('*' + p) + try: + f = open('.xxcign', 'r') + except IOError: + return + ignore[:] = ignore + f.read().split() + +def skipfile(file): + for p in ignore: + if fnmatch.fnmatch(file, p): return 1 + try: + st = os.lstat(file) + except os.error: + return 1 # Doesn't exist -- skip it + # Skip non-plain files. + if not S_ISREG(st[ST_MODE]): return 1 + # Skip huge files -- probably binaries. + if st[ST_SIZE] >= MAXSIZE: return 1 + # Skip executables + try: + data = open(file, 'r').read(len(EXECMAGIC)) + if data == EXECMAGIC: return 1 + except: + pass + return 0 + +def badprefix(file): + for bad in badprefixes: + if file[:len(bad)] == bad: return 1 + return 0 + +def badsuffix(file): + for bad in badsuffixes: + if file[-len(bad):] == bad: return 1 + return 0 + +def go(args): + for file in args: + print file + ':' + if differing(file): + showdiffs(file) + if askyesno('Check in ' + file + ' ? '): + sts = os.system('rcs -l ' + file) # ignored + sts = os.system('ci -l ' + file) + +def differing(file): + cmd = 'co -p ' + file + ' 2>/dev/null | cmp -s - ' + file + sts = os.system(cmd) + return sts != 0 + +def showdiffs(file): + cmd = 'rcsdiff ' + file + ' 2>&1 | ${PAGER-more}' + sts = os.system(cmd) + +def askyesno(prompt): + s = raw_input(prompt) + return s in ['y', 'yes'] + +if __name__ == '__main__': + try: + setup() + go(getargs()) + except KeyboardInterrupt: + print '[Intr]' diff --git a/sys/src/cmd/python/Tools/unicode/Makefile b/sys/src/cmd/python/Tools/unicode/Makefile new file mode 100644 index 000000000..35744ad0d --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/Makefile @@ -0,0 +1,84 @@ +# +# Recreate the Python charmap codecs from the Unicode mapping +# files available at ftp://ftp.unicode.org/ +# +#(c) Copyright Marc-Andre Lemburg, 2005. +# Licensed to PSF under a Contributor Agreement. + +# Python binary to use +PYTHON = python + +# Remove tool to use +RM = /bin/rm + +### Generic targets + +all: distclean mappings codecs + +codecs: misc windows iso apple ebcdic custom-mappings cjk + +### Mappings + +mappings: + ncftpget -R ftp.unicode.org . Public/MAPPINGS + +### Codecs + +build/: + mkdir build + +misc: build/ + $(PYTHON) gencodec.py MAPPINGS/VENDORS/MISC/ build/ + $(RM) build/atarist.* + $(RM) build/us_ascii_quotes.* + $(RM) build/ibmgraph.* + $(RM) build/sgml.* + $(RM) -f build/readme.* + +custom-mappings: build/ + $(PYTHON) gencodec.py python-mappings/ build/ + +windows: build/ + $(PYTHON) gencodec.py MAPPINGS/VENDORS/MICSFT/WINDOWS/ build/ + $(RM) build/cp9* + $(RM) -f build/readme.* + +iso: build/ + $(PYTHON) gencodec.py MAPPINGS/ISO8859/ build/ iso + $(RM) -f build/isoreadme.* + +apple: build/ + $(PYTHON) gencodec.py MAPPINGS/VENDORS/APPLE/ build/ mac_ + $(RM) build/mac_dingbats.* + $(RM) build/mac_japanese.* + $(RM) build/mac_chin* + $(RM) build/mac_korean.* + $(RM) build/mac_symbol.* + $(RM) build/mac_corpchar.* + $(RM) build/mac_devanaga.* + $(RM) build/mac_gaelic.* + $(RM) build/mac_gurmukhi.* + $(RM) build/mac_hebrew.* + $(RM) build/mac_inuit.* + $(RM) build/mac_thai.* + $(RM) build/mac_ukraine.* + $(RM) build/mac_arabic.py + $(RM) build/mac_celtic.* + $(RM) build/mac_gujarati.* + $(RM) build/mac_keyboard.* + $(RM) -f build/mac_readme.* + +ebcdic: build/ + $(PYTHON) gencodec.py MAPPINGS/VENDORS/MICSFT/EBCDIC/ build/ + $(RM) -f build/readme.* + +cjk: build/ + $(PYTHON) gencjkcodecs.py build/ + +### Cleanup + +clean: + $(RM) -f build/* + +distclean: clean + $(RM) -rf MAPPINGS/ diff --git a/sys/src/cmd/python/Tools/unicode/comparecodecs.py b/sys/src/cmd/python/Tools/unicode/comparecodecs.py new file mode 100644 index 000000000..cd417a48b --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/comparecodecs.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +""" Compare the output of two codecs. + +(c) Copyright 2005, Marc-Andre Lemburg (mal@lemburg.com). + + Licensed to PSF under a Contributor Agreement. + +""" +import sys + +def compare_codecs(encoding1, encoding2): + + print 'Comparing encoding/decoding of %r and %r' % (encoding1, encoding2) + mismatch = 0 + # Check encoding + for i in range(sys.maxunicode): + u = unichr(i) + try: + c1 = u.encode(encoding1) + except UnicodeError, reason: + c1 = '<undefined>' + try: + c2 = u.encode(encoding2) + except UnicodeError, reason: + c2 = '<undefined>' + if c1 != c2: + print ' * encoding mismatch for 0x%04X: %-14r != %r' % \ + (i, c1, c2) + mismatch += 1 + # Check decoding + for i in range(256): + c = chr(i) + try: + u1 = c.decode(encoding1) + except UnicodeError: + u1 = u'<undefined>' + try: + u2 = c.decode(encoding2) + except UnicodeError: + u2 = u'<undefined>' + if u1 != u2: + print ' * decoding mismatch for 0x%04X: %-14r != %r' % \ + (i, u1, u2) + mismatch += 1 + if mismatch: + print + print 'Found %i mismatches' % mismatch + else: + print '-> Codecs are identical.' + +if __name__ == '__main__': + compare_codecs(sys.argv[1], sys.argv[2]) diff --git a/sys/src/cmd/python/Tools/unicode/gencjkcodecs.py b/sys/src/cmd/python/Tools/unicode/gencjkcodecs.py new file mode 100644 index 000000000..975c19cb8 --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/gencjkcodecs.py @@ -0,0 +1,68 @@ +import os, string + +codecs = { + 'cn': ('gb2312', 'gbk', 'gb18030', 'hz'), + 'tw': ('big5', 'cp950'), + 'hk': ('big5hkscs',), + 'jp': ('cp932', 'shift_jis', 'euc_jp', 'euc_jisx0213', 'shift_jisx0213', + 'euc_jis_2004', 'shift_jis_2004'), + 'kr': ('cp949', 'euc_kr', 'johab'), + 'iso2022': ('iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', + 'iso2022_jp_2004', 'iso2022_jp_3', 'iso2022_jp_ext', + 'iso2022_kr'), +} + +TEMPLATE = string.Template("""\ +# +# $encoding.py: Python Unicode Codec for $ENCODING +# +# Written by Hye-Shik Chang <perky@FreeBSD.org> +# + +import _codecs_$owner, codecs +import _multibytecodec as mbc + +codec = _codecs_$owner.getcodec('$encoding') + +class Codec(codecs.Codec): + encode = codec.encode + decode = codec.decode + +class IncrementalEncoder(mbc.MultibyteIncrementalEncoder, + codecs.IncrementalEncoder): + codec = codec + +class IncrementalDecoder(mbc.MultibyteIncrementalDecoder, + codecs.IncrementalDecoder): + codec = codec + +class StreamReader(Codec, mbc.MultibyteStreamReader, codecs.StreamReader): + codec = codec + +class StreamWriter(Codec, mbc.MultibyteStreamWriter, codecs.StreamWriter): + codec = codec + +def getregentry(): + return codecs.CodecInfo( + name='$encoding', + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamreader=StreamReader, + streamwriter=StreamWriter, + ) +""") + +def gencodecs(prefix): + for loc, encodings in codecs.iteritems(): + for enc in encodings: + code = TEMPLATE.substitute(ENCODING=enc.upper(), + encoding=enc.lower(), + owner=loc) + codecpath = os.path.join(prefix, enc + '.py') + open(codecpath, 'w').write(code) + +if __name__ == '__main__': + import sys + gencodecs(sys.argv[1]) diff --git a/sys/src/cmd/python/Tools/unicode/gencodec.py b/sys/src/cmd/python/Tools/unicode/gencodec.py new file mode 100644 index 000000000..8a2ca6447 --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/gencodec.py @@ -0,0 +1,426 @@ +""" Unicode Mapping Parser and Codec Generator. + +This script parses Unicode mapping files as available from the Unicode +site (ftp://ftp.unicode.org/Public/MAPPINGS/) and creates Python codec +modules from them. The codecs use the standard character mapping codec +to actually apply the mapping. + +Synopsis: gencodec.py dir codec_prefix + +All files in dir are scanned and those producing non-empty mappings +will be written to <codec_prefix><mapname>.py with <mapname> being the +first part of the map's filename ('a' in a.b.c.txt) converted to +lowercase with hyphens replaced by underscores. + +The tool also writes marshalled versions of the mapping tables to the +same location (with .mapping extension). + +Written by Marc-Andre Lemburg (mal@lemburg.com). + +(c) Copyright CNRI, All Rights Reserved. NO WARRANTY. +(c) Copyright Guido van Rossum, 2000. + +Table generation: +(c) Copyright Marc-Andre Lemburg, 2005. + Licensed to PSF under a Contributor Agreement. + +"""#" + +import re, os, time, marshal, codecs + +# Maximum allowed size of charmap tables +MAX_TABLE_SIZE = 8192 + +# Standard undefined Unicode code point +UNI_UNDEFINED = unichr(0xFFFE) + +mapRE = re.compile('((?:0x[0-9a-fA-F]+\+?)+)' + '\s+' + '((?:(?:0x[0-9a-fA-Z]+|<[A-Za-z]+>)\+?)*)' + '\s*' + '(#.+)?') + +def parsecodes(codes, + len=len, filter=filter,range=range): + + """ Converts code combinations to either a single code integer + or a tuple of integers. + + meta-codes (in angular brackets, e.g. <LR> and <RL>) are + ignored. + + Empty codes or illegal ones are returned as None. + + """ + if not codes: + return None + l = codes.split('+') + if len(l) == 1: + return int(l[0],16) + for i in range(len(l)): + try: + l[i] = int(l[i],16) + except ValueError: + l[i] = None + l = filter(lambda x: x is not None, l) + if len(l) == 1: + return l[0] + else: + return tuple(l) + +def readmap(filename): + + f = open(filename,'r') + lines = f.readlines() + f.close() + enc2uni = {} + identity = [] + unmapped = range(256) + + # UTC mapping tables per convention don't include the identity + # mappings for code points 0x00 - 0x1F and 0x7F, unless these are + # explicitly mapped to different characters or undefined + for i in range(32) + [127]: + identity.append(i) + unmapped.remove(i) + enc2uni[i] = (i, 'CONTROL CHARACTER') + + for line in lines: + line = line.strip() + if not line or line[0] == '#': + continue + m = mapRE.match(line) + if not m: + #print '* not matched: %s' % repr(line) + continue + enc,uni,comment = m.groups() + enc = parsecodes(enc) + uni = parsecodes(uni) + if comment is None: + comment = '' + else: + comment = comment[1:].strip() + if enc < 256: + if enc in unmapped: + unmapped.remove(enc) + if enc == uni: + identity.append(enc) + enc2uni[enc] = (uni,comment) + else: + enc2uni[enc] = (uni,comment) + + # If there are more identity-mapped entries than unmapped entries, + # it pays to generate an identity dictionary first, and add explicit + # mappings to None for the rest + if len(identity) >= len(unmapped): + for enc in unmapped: + enc2uni[enc] = (None, "") + enc2uni['IDENTITY'] = 256 + + return enc2uni + +def hexrepr(t, precision=4): + + if t is None: + return 'None' + try: + len(t) + except: + return '0x%0*X' % (precision, t) + try: + return '(' + ', '.join(['0x%0*X' % (precision, item) + for item in t]) + ')' + except TypeError, why: + print '* failed to convert %r: %s' % (t, why) + raise + +def python_mapdef_code(varname, map, comments=1, precisions=(2, 4)): + + l = [] + append = l.append + if map.has_key("IDENTITY"): + append("%s = codecs.make_identity_dict(range(%d))" % + (varname, map["IDENTITY"])) + append("%s.update({" % varname) + splits = 1 + del map["IDENTITY"] + identity = 1 + else: + append("%s = {" % varname) + splits = 0 + identity = 0 + + mappings = map.items() + mappings.sort() + i = 0 + key_precision, value_precision = precisions + for mapkey, mapvalue in mappings: + mapcomment = '' + if isinstance(mapkey, tuple): + (mapkey, mapcomment) = mapkey + if isinstance(mapvalue, tuple): + (mapvalue, mapcomment) = mapvalue + if mapkey is None: + continue + if (identity and + mapkey == mapvalue and + mapkey < 256): + # No need to include identity mappings, since these + # are already set for the first 256 code points. + continue + key = hexrepr(mapkey, key_precision) + value = hexrepr(mapvalue, value_precision) + if mapcomment and comments: + append(' %s: %s,\t# %s' % (key, value, mapcomment)) + else: + append(' %s: %s,' % (key, value)) + i += 1 + if i == 4096: + # Split the definition into parts to that the Python + # parser doesn't dump core + if splits == 0: + append('}') + else: + append('})') + append('%s.update({' % varname) + i = 0 + splits = splits + 1 + if splits == 0: + append('}') + else: + append('})') + + return l + +def python_tabledef_code(varname, map, comments=1, key_precision=2): + + l = [] + append = l.append + append('%s = (' % varname) + + # Analyze map and create table dict + mappings = map.items() + mappings.sort() + table = {} + maxkey = 0 + if map.has_key('IDENTITY'): + for key in range(256): + table[key] = (key, '') + maxkey = 255 + del map['IDENTITY'] + for mapkey, mapvalue in mappings: + mapcomment = '' + if isinstance(mapkey, tuple): + (mapkey, mapcomment) = mapkey + if isinstance(mapvalue, tuple): + (mapvalue, mapcomment) = mapvalue + if mapkey is None: + continue + table[mapkey] = (mapvalue, mapcomment) + if mapkey > maxkey: + maxkey = mapkey + if maxkey > MAX_TABLE_SIZE: + # Table too large + return None + + # Create table code + for key in range(maxkey + 1): + if key not in table: + mapvalue = None + mapcomment = 'UNDEFINED' + else: + mapvalue, mapcomment = table[key] + if mapvalue is None: + mapchar = UNI_UNDEFINED + else: + if isinstance(mapvalue, tuple): + # 1-n mappings not supported + return None + else: + mapchar = unichr(mapvalue) + if mapcomment and comments: + append(' %r\t# %s -> %s' % (mapchar, + hexrepr(key, key_precision), + mapcomment)) + else: + append(' %r' % mapchar) + + append(')') + return l + +def codegen(name, map, encodingname, comments=1): + + """ Returns Python source for the given map. + + Comments are included in the source, if comments is true (default). + + """ + # Generate code + decoding_map_code = python_mapdef_code( + 'decoding_map', + map, + comments=comments) + decoding_table_code = python_tabledef_code( + 'decoding_table', + map, + comments=comments) + encoding_map_code = python_mapdef_code( + 'encoding_map', + codecs.make_encoding_map(map), + comments=comments, + precisions=(4, 2)) + + if decoding_table_code: + suffix = 'table' + else: + suffix = 'map' + + l = [ + '''\ +""" Python Character Mapping Codec %s generated from '%s' with gencodec.py. + +"""#" + +import codecs + +### Codec APIs + +class Codec(codecs.Codec): + + def encode(self,input,errors='strict'): + return codecs.charmap_encode(input,errors,encoding_%s) + + def decode(self,input,errors='strict'): + return codecs.charmap_decode(input,errors,decoding_%s) +''' % (encodingname, name, suffix, suffix)] + l.append('''\ +class IncrementalEncoder(codecs.IncrementalEncoder): + def encode(self, input, final=False): + return codecs.charmap_encode(input,self.errors,encoding_%s)[0] + +class IncrementalDecoder(codecs.IncrementalDecoder): + def decode(self, input, final=False): + return codecs.charmap_decode(input,self.errors,decoding_%s)[0]''' % + (suffix, suffix)) + + l.append(''' +class StreamWriter(Codec,codecs.StreamWriter): + pass + +class StreamReader(Codec,codecs.StreamReader): + pass + +### encodings module API + +def getregentry(): + return codecs.CodecInfo( + name=%r, + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamreader=StreamReader, + streamwriter=StreamWriter, + ) +''' % encodingname.replace('_', '-')) + + # Add decoding table or map (with preference to the table) + if not decoding_table_code: + l.append(''' +### Decoding Map +''') + l.extend(decoding_map_code) + else: + l.append(''' +### Decoding Table +''') + l.extend(decoding_table_code) + + # Add encoding map + if decoding_table_code: + l.append(''' +### Encoding table +encoding_table=codecs.charmap_build(decoding_table) +''') + else: + l.append(''' +### Encoding Map +''') + l.extend(encoding_map_code) + + # Final new-line + l.append('') + + return '\n'.join(l).expandtabs() + +def pymap(name,map,pyfile,encodingname,comments=1): + + code = codegen(name,map,encodingname,comments) + f = open(pyfile,'w') + f.write(code) + f.close() + +def marshalmap(name,map,marshalfile): + + d = {} + for e,(u,c) in map.items(): + d[e] = (u,c) + f = open(marshalfile,'wb') + marshal.dump(d,f) + f.close() + +def convertdir(dir, dirprefix='', nameprefix='', comments=1): + + mapnames = os.listdir(dir) + for mapname in mapnames: + mappathname = os.path.join(dir, mapname) + if not os.path.isfile(mappathname): + continue + name = os.path.split(mapname)[1] + name = name.replace('-','_') + name = name.split('.')[0] + name = name.lower() + name = nameprefix + name + codefile = name + '.py' + marshalfile = name + '.mapping' + print 'converting %s to %s and %s' % (mapname, + dirprefix + codefile, + dirprefix + marshalfile) + try: + map = readmap(os.path.join(dir,mapname)) + if not map: + print '* map is empty; skipping' + else: + pymap(mappathname, map, dirprefix + codefile,name,comments) + marshalmap(mappathname, map, dirprefix + marshalfile) + except ValueError, why: + print '* conversion failed: %s' % why + raise + +def rewritepythondir(dir, dirprefix='', comments=1): + + mapnames = os.listdir(dir) + for mapname in mapnames: + if not mapname.endswith('.mapping'): + continue + name = mapname[:-len('.mapping')] + codefile = name + '.py' + print 'converting %s to %s' % (mapname, + dirprefix + codefile) + try: + map = marshal.load(open(os.path.join(dir,mapname), + 'rb')) + if not map: + print '* map is empty; skipping' + else: + pymap(mapname, map, dirprefix + codefile,name,comments) + except ValueError, why: + print '* conversion failed: %s' % why + +if __name__ == '__main__': + + import sys + if 1: + apply(convertdir,tuple(sys.argv[1:])) + else: + apply(rewritepythondir,tuple(sys.argv[1:])) diff --git a/sys/src/cmd/python/Tools/unicode/listcodecs.py b/sys/src/cmd/python/Tools/unicode/listcodecs.py new file mode 100644 index 000000000..19d21e187 --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/listcodecs.py @@ -0,0 +1,41 @@ +""" List all available codec modules. + +(c) Copyright 2005, Marc-Andre Lemburg (mal@lemburg.com). + + Licensed to PSF under a Contributor Agreement. + +""" + +import os, codecs, encodings + +_debug = 0 + +def listcodecs(dir): + names = [] + for filename in os.listdir(dir): + if filename[-3:] != '.py': + continue + name = filename[:-3] + # Check whether we've found a true codec + try: + codecs.lookup(name) + except LookupError: + # Codec not found + continue + except Exception, reason: + # Probably an error from importing the codec; still it's + # a valid code name + if _debug: + print '* problem importing codec %r: %s' % \ + (name, reason) + names.append(name) + return names + + +if __name__ == '__main__': + names = listcodecs(encodings.__path__[0]) + names.sort() + print 'all_codecs = [' + for name in names: + print ' %r,' % name + print ']' diff --git a/sys/src/cmd/python/Tools/unicode/makeunicodedata.py b/sys/src/cmd/python/Tools/unicode/makeunicodedata.py new file mode 100644 index 000000000..9de69048e --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/makeunicodedata.py @@ -0,0 +1,943 @@ +# +# (re)generate unicode property and type databases +# +# this script converts a unicode 3.2 database file to +# Modules/unicodedata_db.h, Modules/unicodename_db.h, +# and Objects/unicodetype_db.h +# +# history: +# 2000-09-24 fl created (based on bits and pieces from unidb) +# 2000-09-25 fl merged tim's splitbin fixes, separate decomposition table +# 2000-09-25 fl added character type table +# 2000-09-26 fl added LINEBREAK, DECIMAL, and DIGIT flags/fields (2.0) +# 2000-11-03 fl expand first/last ranges +# 2001-01-19 fl added character name tables (2.1) +# 2001-01-21 fl added decomp compression; dynamic phrasebook threshold +# 2002-09-11 wd use string methods +# 2002-10-18 mvl update to Unicode 3.2 +# 2002-10-22 mvl generate NFC tables +# 2002-11-24 mvl expand all ranges, sort names version-independently +# 2002-11-25 mvl add UNIDATA_VERSION +# 2004-05-29 perky add east asian width information +# 2006-03-10 mvl update to Unicode 4.1; add UCD 3.2 delta +# +# written by Fredrik Lundh (fredrik@pythonware.com) +# + +import sys + +SCRIPT = sys.argv[0] +VERSION = "2.5" + +# The Unicode Database +UNIDATA_VERSION = "4.1.0" +UNICODE_DATA = "UnicodeData%s.txt" +COMPOSITION_EXCLUSIONS = "CompositionExclusions%s.txt" +EASTASIAN_WIDTH = "EastAsianWidth%s.txt" + +old_versions = ["3.2.0"] + +CATEGORY_NAMES = [ "Cn", "Lu", "Ll", "Lt", "Mn", "Mc", "Me", "Nd", + "Nl", "No", "Zs", "Zl", "Zp", "Cc", "Cf", "Cs", "Co", "Cn", "Lm", + "Lo", "Pc", "Pd", "Ps", "Pe", "Pi", "Pf", "Po", "Sm", "Sc", "Sk", + "So" ] + +BIDIRECTIONAL_NAMES = [ "", "L", "LRE", "LRO", "R", "AL", "RLE", "RLO", + "PDF", "EN", "ES", "ET", "AN", "CS", "NSM", "BN", "B", "S", "WS", + "ON" ] + +EASTASIANWIDTH_NAMES = [ "F", "H", "W", "Na", "A", "N" ] + +# note: should match definitions in Objects/unicodectype.c +ALPHA_MASK = 0x01 +DECIMAL_MASK = 0x02 +DIGIT_MASK = 0x04 +LOWER_MASK = 0x08 +LINEBREAK_MASK = 0x10 +SPACE_MASK = 0x20 +TITLE_MASK = 0x40 +UPPER_MASK = 0x80 + +def maketables(trace=0): + + print "--- Reading", UNICODE_DATA % "", "..." + + version = "" + unicode = UnicodeData(UNICODE_DATA % version, + COMPOSITION_EXCLUSIONS % version, + EASTASIAN_WIDTH % version) + + print len(filter(None, unicode.table)), "characters" + + for version in old_versions: + print "--- Reading", UNICODE_DATA % ("-"+version), "..." + old_unicode = UnicodeData(UNICODE_DATA % ("-"+version), + COMPOSITION_EXCLUSIONS % ("-"+version), + EASTASIAN_WIDTH % ("-"+version)) + print len(filter(None, old_unicode.table)), "characters" + merge_old_version(version, unicode, old_unicode) + + makeunicodename(unicode, trace) + makeunicodedata(unicode, trace) + makeunicodetype(unicode, trace) + +# -------------------------------------------------------------------- +# unicode character properties + +def makeunicodedata(unicode, trace): + + dummy = (0, 0, 0, 0, 0) + table = [dummy] + cache = {0: dummy} + index = [0] * len(unicode.chars) + + FILE = "Modules/unicodedata_db.h" + + print "--- Preparing", FILE, "..." + + # 1) database properties + + for char in unicode.chars: + record = unicode.table[char] + if record: + # extract database properties + category = CATEGORY_NAMES.index(record[2]) + combining = int(record[3]) + bidirectional = BIDIRECTIONAL_NAMES.index(record[4]) + mirrored = record[9] == "Y" + eastasianwidth = EASTASIANWIDTH_NAMES.index(record[15]) + item = ( + category, combining, bidirectional, mirrored, eastasianwidth + ) + # add entry to index and item tables + i = cache.get(item) + if i is None: + cache[item] = i = len(table) + table.append(item) + index[char] = i + + # 2) decomposition data + + decomp_data = [0] + decomp_prefix = [""] + decomp_index = [0] * len(unicode.chars) + decomp_size = 0 + + comp_pairs = [] + comp_first = [None] * len(unicode.chars) + comp_last = [None] * len(unicode.chars) + + for char in unicode.chars: + record = unicode.table[char] + if record: + if record[5]: + decomp = record[5].split() + if len(decomp) > 19: + raise Exception, "character %x has a decomposition too large for nfd_nfkd" % char + # prefix + if decomp[0][0] == "<": + prefix = decomp.pop(0) + else: + prefix = "" + try: + i = decomp_prefix.index(prefix) + except ValueError: + i = len(decomp_prefix) + decomp_prefix.append(prefix) + prefix = i + assert prefix < 256 + # content + decomp = [prefix + (len(decomp)<<8)] +\ + map(lambda s: int(s, 16), decomp) + # Collect NFC pairs + if not prefix and len(decomp) == 3 and \ + char not in unicode.exclusions and \ + unicode.table[decomp[1]][3] == "0": + p, l, r = decomp + comp_first[l] = 1 + comp_last[r] = 1 + comp_pairs.append((l,r,char)) + try: + i = decomp_data.index(decomp) + except ValueError: + i = len(decomp_data) + decomp_data.extend(decomp) + decomp_size = decomp_size + len(decomp) * 2 + else: + i = 0 + decomp_index[char] = i + + f = l = 0 + comp_first_ranges = [] + comp_last_ranges = [] + prev_f = prev_l = None + for i in unicode.chars: + if comp_first[i] is not None: + comp_first[i] = f + f += 1 + if prev_f is None: + prev_f = (i,i) + elif prev_f[1]+1 == i: + prev_f = prev_f[0],i + else: + comp_first_ranges.append(prev_f) + prev_f = (i,i) + if comp_last[i] is not None: + comp_last[i] = l + l += 1 + if prev_l is None: + prev_l = (i,i) + elif prev_l[1]+1 == i: + prev_l = prev_l[0],i + else: + comp_last_ranges.append(prev_l) + prev_l = (i,i) + comp_first_ranges.append(prev_f) + comp_last_ranges.append(prev_l) + total_first = f + total_last = l + + comp_data = [0]*(total_first*total_last) + for f,l,char in comp_pairs: + f = comp_first[f] + l = comp_last[l] + comp_data[f*total_last+l] = char + + print len(table), "unique properties" + print len(decomp_prefix), "unique decomposition prefixes" + print len(decomp_data), "unique decomposition entries:", + print decomp_size, "bytes" + print total_first, "first characters in NFC" + print total_last, "last characters in NFC" + print len(comp_pairs), "NFC pairs" + + print "--- Writing", FILE, "..." + + fp = open(FILE, "w") + print >>fp, "/* this file was generated by %s %s */" % (SCRIPT, VERSION) + print >>fp + print >>fp, '#define UNIDATA_VERSION "%s"' % UNIDATA_VERSION + print >>fp, "/* a list of unique database records */" + print >>fp, \ + "const _PyUnicode_DatabaseRecord _PyUnicode_Database_Records[] = {" + for item in table: + print >>fp, " {%d, %d, %d, %d, %d}," % item + print >>fp, "};" + print >>fp + + print >>fp, "/* Reindexing of NFC first characters. */" + print >>fp, "#define TOTAL_FIRST",total_first + print >>fp, "#define TOTAL_LAST",total_last + print >>fp, "struct reindex{int start;short count,index;};" + print >>fp, "struct reindex nfc_first[] = {" + for start,end in comp_first_ranges: + print >>fp," { %d, %d, %d}," % (start,end-start,comp_first[start]) + print >>fp," {0,0,0}" + print >>fp,"};\n" + print >>fp, "struct reindex nfc_last[] = {" + for start,end in comp_last_ranges: + print >>fp," { %d, %d, %d}," % (start,end-start,comp_last[start]) + print >>fp," {0,0,0}" + print >>fp,"};\n" + + # FIXME: <fl> the following tables could be made static, and + # the support code moved into unicodedatabase.c + + print >>fp, "/* string literals */" + print >>fp, "const char *_PyUnicode_CategoryNames[] = {" + for name in CATEGORY_NAMES: + print >>fp, " \"%s\"," % name + print >>fp, " NULL" + print >>fp, "};" + + print >>fp, "const char *_PyUnicode_BidirectionalNames[] = {" + for name in BIDIRECTIONAL_NAMES: + print >>fp, " \"%s\"," % name + print >>fp, " NULL" + print >>fp, "};" + + print >>fp, "const char *_PyUnicode_EastAsianWidthNames[] = {" + for name in EASTASIANWIDTH_NAMES: + print >>fp, " \"%s\"," % name + print >>fp, " NULL" + print >>fp, "};" + + print >>fp, "static const char *decomp_prefix[] = {" + for name in decomp_prefix: + print >>fp, " \"%s\"," % name + print >>fp, " NULL" + print >>fp, "};" + + # split record index table + index1, index2, shift = splitbins(index, trace) + + print >>fp, "/* index tables for the database records */" + print >>fp, "#define SHIFT", shift + Array("index1", index1).dump(fp, trace) + Array("index2", index2).dump(fp, trace) + + # split decomposition index table + index1, index2, shift = splitbins(decomp_index, trace) + + print >>fp, "/* decomposition data */" + Array("decomp_data", decomp_data).dump(fp, trace) + + print >>fp, "/* index tables for the decomposition data */" + print >>fp, "#define DECOMP_SHIFT", shift + Array("decomp_index1", index1).dump(fp, trace) + Array("decomp_index2", index2).dump(fp, trace) + + index, index2, shift = splitbins(comp_data, trace) + print >>fp, "/* NFC pairs */" + print >>fp, "#define COMP_SHIFT", shift + Array("comp_index", index).dump(fp, trace) + Array("comp_data", index2).dump(fp, trace) + + # Generate delta tables for old versions + for version, table, normalization in unicode.changed: + cversion = version.replace(".","_") + records = [table[0]] + cache = {table[0]:0} + index = [0] * len(table) + for i, record in enumerate(table): + try: + index[i] = cache[record] + except KeyError: + index[i] = cache[record] = len(records) + records.append(record) + index1, index2, shift = splitbins(index, trace) + print >>fp, "static const change_record change_records_%s[] = {" % cversion + for record in records: + print >>fp, "\t{ %s }," % ", ".join(map(str,record)) + print >>fp, "};" + Array("changes_%s_index" % cversion, index1).dump(fp, trace) + Array("changes_%s_data" % cversion, index2).dump(fp, trace) + print >>fp, "static const change_record* get_change_%s(Py_UCS4 n)" % cversion + print >>fp, "{" + print >>fp, "\tint index;" + print >>fp, "\tif (n >= 0x110000) index = 0;" + print >>fp, "\telse {" + print >>fp, "\t\tindex = changes_%s_index[n>>%d];" % (cversion, shift) + print >>fp, "\t\tindex = changes_%s_data[(index<<%d)+(n & %d)];" % \ + (cversion, shift, ((1<<shift)-1)) + print >>fp, "\t}" + print >>fp, "\treturn change_records_%s+index;" % cversion + print >>fp, "}\n" + print >>fp, "static Py_UCS4 normalization_%s(Py_UCS4 n)" % cversion + print >>fp, "{" + print >>fp, "\tswitch(n) {" + for k, v in normalization: + print >>fp, "\tcase %s: return 0x%s;" % (hex(k), v) + print >>fp, "\tdefault: return 0;" + print >>fp, "\t}\n}\n" + + fp.close() + +# -------------------------------------------------------------------- +# unicode character type tables + +def makeunicodetype(unicode, trace): + + FILE = "Objects/unicodetype_db.h" + + print "--- Preparing", FILE, "..." + + # extract unicode types + dummy = (0, 0, 0, 0, 0, 0) + table = [dummy] + cache = {0: dummy} + index = [0] * len(unicode.chars) + + for char in unicode.chars: + record = unicode.table[char] + if record: + # extract database properties + category = record[2] + bidirectional = record[4] + flags = 0 + if category in ["Lm", "Lt", "Lu", "Ll", "Lo"]: + flags |= ALPHA_MASK + if category == "Ll": + flags |= LOWER_MASK + if category == "Zl" or bidirectional == "B": + flags |= LINEBREAK_MASK + if category == "Zs" or bidirectional in ("WS", "B", "S"): + flags |= SPACE_MASK + if category == "Lt": + flags |= TITLE_MASK + if category == "Lu": + flags |= UPPER_MASK + # use delta predictor for upper/lower/title + if record[12]: + upper = int(record[12], 16) - char + assert -32768 <= upper <= 32767 + upper = upper & 0xffff + else: + upper = 0 + if record[13]: + lower = int(record[13], 16) - char + assert -32768 <= lower <= 32767 + lower = lower & 0xffff + else: + lower = 0 + if record[14]: + title = int(record[14], 16) - char + assert -32768 <= lower <= 32767 + title = title & 0xffff + else: + title = 0 + # decimal digit, integer digit + decimal = 0 + if record[6]: + flags |= DECIMAL_MASK + decimal = int(record[6]) + digit = 0 + if record[7]: + flags |= DIGIT_MASK + digit = int(record[7]) + item = ( + upper, lower, title, decimal, digit, flags + ) + # add entry to index and item tables + i = cache.get(item) + if i is None: + cache[item] = i = len(table) + table.append(item) + index[char] = i + + print len(table), "unique character type entries" + + print "--- Writing", FILE, "..." + + fp = open(FILE, "w") + print >>fp, "/* this file was generated by %s %s */" % (SCRIPT, VERSION) + print >>fp + print >>fp, "/* a list of unique character type descriptors */" + print >>fp, "const _PyUnicode_TypeRecord _PyUnicode_TypeRecords[] = {" + for item in table: + print >>fp, " {%d, %d, %d, %d, %d, %d}," % item + print >>fp, "};" + print >>fp + + # split decomposition index table + index1, index2, shift = splitbins(index, trace) + + print >>fp, "/* type indexes */" + print >>fp, "#define SHIFT", shift + Array("index1", index1).dump(fp, trace) + Array("index2", index2).dump(fp, trace) + + fp.close() + +# -------------------------------------------------------------------- +# unicode name database + +def makeunicodename(unicode, trace): + + FILE = "Modules/unicodename_db.h" + + print "--- Preparing", FILE, "..." + + # collect names + names = [None] * len(unicode.chars) + + for char in unicode.chars: + record = unicode.table[char] + if record: + name = record[1].strip() + if name and name[0] != "<": + names[char] = name + chr(0) + + print len(filter(lambda n: n is not None, names)), "distinct names" + + # collect unique words from names (note that we differ between + # words inside a sentence, and words ending a sentence. the + # latter includes the trailing null byte. + + words = {} + n = b = 0 + for char in unicode.chars: + name = names[char] + if name: + w = name.split() + b = b + len(name) + n = n + len(w) + for w in w: + l = words.get(w) + if l: + l.append(None) + else: + words[w] = [len(words)] + + print n, "words in text;", b, "bytes" + + wordlist = words.items() + + # sort on falling frequency, then by name + def cmpwords((aword, alist),(bword, blist)): + r = -cmp(len(alist),len(blist)) + if r: + return r + return cmp(aword, bword) + wordlist.sort(cmpwords) + + # figure out how many phrasebook escapes we need + escapes = 0 + while escapes * 256 < len(wordlist): + escapes = escapes + 1 + print escapes, "escapes" + + short = 256 - escapes + + assert short > 0 + + print short, "short indexes in lexicon" + + # statistics + n = 0 + for i in range(short): + n = n + len(wordlist[i][1]) + print n, "short indexes in phrasebook" + + # pick the most commonly used words, and sort the rest on falling + # length (to maximize overlap) + + wordlist, wordtail = wordlist[:short], wordlist[short:] + wordtail.sort(lambda a, b: len(b[0])-len(a[0])) + wordlist.extend(wordtail) + + # generate lexicon from words + + lexicon_offset = [0] + lexicon = "" + words = {} + + # build a lexicon string + offset = 0 + for w, x in wordlist: + # encoding: bit 7 indicates last character in word (chr(128) + # indicates the last character in an entire string) + ww = w[:-1] + chr(ord(w[-1])+128) + # reuse string tails, when possible + o = lexicon.find(ww) + if o < 0: + o = offset + lexicon = lexicon + ww + offset = offset + len(w) + words[w] = len(lexicon_offset) + lexicon_offset.append(o) + + lexicon = map(ord, lexicon) + + # generate phrasebook from names and lexicon + phrasebook = [0] + phrasebook_offset = [0] * len(unicode.chars) + for char in unicode.chars: + name = names[char] + if name: + w = name.split() + phrasebook_offset[char] = len(phrasebook) + for w in w: + i = words[w] + if i < short: + phrasebook.append(i) + else: + # store as two bytes + phrasebook.append((i>>8) + short) + phrasebook.append(i&255) + + assert getsize(phrasebook) == 1 + + # + # unicode name hash table + + # extract names + data = [] + for char in unicode.chars: + record = unicode.table[char] + if record: + name = record[1].strip() + if name and name[0] != "<": + data.append((name, char)) + + # the magic number 47 was chosen to minimize the number of + # collisions on the current data set. if you like, change it + # and see what happens... + + codehash = Hash("code", data, 47) + + print "--- Writing", FILE, "..." + + fp = open(FILE, "w") + print >>fp, "/* this file was generated by %s %s */" % (SCRIPT, VERSION) + print >>fp + print >>fp, "#define NAME_MAXLEN", 256 + print >>fp + print >>fp, "/* lexicon */" + Array("lexicon", lexicon).dump(fp, trace) + Array("lexicon_offset", lexicon_offset).dump(fp, trace) + + # split decomposition index table + offset1, offset2, shift = splitbins(phrasebook_offset, trace) + + print >>fp, "/* code->name phrasebook */" + print >>fp, "#define phrasebook_shift", shift + print >>fp, "#define phrasebook_short", short + + Array("phrasebook", phrasebook).dump(fp, trace) + Array("phrasebook_offset1", offset1).dump(fp, trace) + Array("phrasebook_offset2", offset2).dump(fp, trace) + + print >>fp, "/* name->code dictionary */" + codehash.dump(fp, trace) + + fp.close() + + +def merge_old_version(version, new, old): + # Changes to exclusion file not implemented yet + if old.exclusions != new.exclusions: + raise NotImplementedError, "exclusions differ" + + # In these change records, 0xFF means "no change" + bidir_changes = [0xFF]*0x110000 + category_changes = [0xFF]*0x110000 + decimal_changes = [0xFF]*0x110000 + # In numeric data, 0 means "no change", + # -1 means "did not have a numeric value + numeric_changes = [0] * 0x110000 + # normalization_changes is a list of key-value pairs + normalization_changes = [] + for i in range(0x110000): + if new.table[i] is None: + # Characters unassigned in the new version ought to + # be unassigned in the old one + assert old.table[i] is None + continue + # check characters unassigned in the old version + if old.table[i] is None: + # category 0 is "unassigned" + category_changes[i] = 0 + continue + # check characters that differ + if old.table[i] != new.table[i]: + for k in range(len(old.table[i])): + if old.table[i][k] != new.table[i][k]: + value = old.table[i][k] + if k == 2: + #print "CATEGORY",hex(i), old.table[i][k], new.table[i][k] + category_changes[i] = CATEGORY_NAMES.index(value) + elif k == 4: + #print "BIDIR",hex(i), old.table[i][k], new.table[i][k] + bidir_changes[i] = BIDIRECTIONAL_NAMES.index(value) + elif k == 5: + #print "DECOMP",hex(i), old.table[i][k], new.table[i][k] + # We assume that all normalization changes are in 1:1 mappings + assert " " not in value + normalization_changes.append((i, value)) + elif k == 6: + #print "DECIMAL",hex(i), old.table[i][k], new.table[i][k] + # we only support changes where the old value is a single digit + assert value in "0123456789" + decimal_changes[i] = int(value) + elif k == 8: + # print "NUMERIC",hex(i), `old.table[i][k]`, new.table[i][k] + # Since 0 encodes "no change", the old value is better not 0 + assert value != "0" and value != "-1" + if not value: + numeric_changes[i] = -1 + else: + assert re.match("^[0-9]+$", value) + numeric_changes[i] = int(value) + elif k == 11: + # change to ISO comment, ignore + pass + elif k == 12: + # change to simple uppercase mapping; ignore + pass + elif k == 13: + # change to simple lowercase mapping; ignore + pass + elif k == 14: + # change to simple titlecase mapping; ignore + pass + else: + class Difference(Exception):pass + raise Difference, (hex(i), k, old.table[i], new.table[i]) + new.changed.append((version, zip(bidir_changes, category_changes, + decimal_changes, numeric_changes), + normalization_changes)) + + +# -------------------------------------------------------------------- +# the following support code is taken from the unidb utilities +# Copyright (c) 1999-2000 by Secret Labs AB + +# load a unicode-data file from disk + +import sys + +class UnicodeData: + + def __init__(self, filename, exclusions, eastasianwidth, expand=1): + self.changed = [] + file = open(filename) + table = [None] * 0x110000 + while 1: + s = file.readline() + if not s: + break + s = s.strip().split(";") + char = int(s[0], 16) + table[char] = s + + # expand first-last ranges + if expand: + field = None + for i in range(0, 0x110000): + s = table[i] + if s: + if s[1][-6:] == "First>": + s[1] = "" + field = s + elif s[1][-5:] == "Last>": + s[1] = "" + field = None + elif field: + f2 = field[:] + f2[0] = "%X" % i + table[i] = f2 + + # public attributes + self.filename = filename + self.table = table + self.chars = range(0x110000) # unicode 3.2 + + file = open(exclusions) + self.exclusions = {} + for s in file: + s = s.strip() + if not s: + continue + if s[0] == '#': + continue + char = int(s.split()[0],16) + self.exclusions[char] = 1 + + widths = [None] * 0x110000 + for s in open(eastasianwidth): + s = s.strip() + if not s: + continue + if s[0] == '#': + continue + s = s.split()[0].split(';') + if '..' in s[0]: + first, last = [int(c, 16) for c in s[0].split('..')] + chars = range(first, last+1) + else: + chars = [int(s[0], 16)] + for char in chars: + widths[char] = s[1] + for i in range(0, 0x110000): + if table[i] is not None: + table[i].append(widths[i]) + + def uselatin1(self): + # restrict character range to ISO Latin 1 + self.chars = range(256) + +# hash table tools + +# this is a straight-forward reimplementation of Python's built-in +# dictionary type, using a static data structure, and a custom string +# hash algorithm. + +def myhash(s, magic): + h = 0 + for c in map(ord, s.upper()): + h = (h * magic) + c + ix = h & 0xff000000L + if ix: + h = (h ^ ((ix>>24) & 0xff)) & 0x00ffffff + return h + +SIZES = [ + (4,3), (8,3), (16,3), (32,5), (64,3), (128,3), (256,29), (512,17), + (1024,9), (2048,5), (4096,83), (8192,27), (16384,43), (32768,3), + (65536,45), (131072,9), (262144,39), (524288,39), (1048576,9), + (2097152,5), (4194304,3), (8388608,33), (16777216,27) +] + +class Hash: + def __init__(self, name, data, magic): + # turn a (key, value) list into a static hash table structure + + # determine table size + for size, poly in SIZES: + if size > len(data): + poly = size + poly + break + else: + raise AssertionError, "ran out of polynominals" + + print size, "slots in hash table" + + table = [None] * size + + mask = size-1 + + n = 0 + + hash = myhash + + # initialize hash table + for key, value in data: + h = hash(key, magic) + i = (~h) & mask + v = table[i] + if v is None: + table[i] = value + continue + incr = (h ^ (h >> 3)) & mask; + if not incr: + incr = mask + while 1: + n = n + 1 + i = (i + incr) & mask + v = table[i] + if v is None: + table[i] = value + break + incr = incr << 1 + if incr > mask: + incr = incr ^ poly + + print n, "collisions" + self.collisions = n + + for i in range(len(table)): + if table[i] is None: + table[i] = 0 + + self.data = Array(name + "_hash", table) + self.magic = magic + self.name = name + self.size = size + self.poly = poly + + def dump(self, file, trace): + # write data to file, as a C array + self.data.dump(file, trace) + file.write("#define %s_magic %d\n" % (self.name, self.magic)) + file.write("#define %s_size %d\n" % (self.name, self.size)) + file.write("#define %s_poly %d\n" % (self.name, self.poly)) + +# stuff to deal with arrays of unsigned integers + +class Array: + + def __init__(self, name, data): + self.name = name + self.data = data + + def dump(self, file, trace=0): + # write data to file, as a C array + size = getsize(self.data) + if trace: + print >>sys.stderr, self.name+":", size*len(self.data), "bytes" + file.write("static ") + if size == 1: + file.write("unsigned char") + elif size == 2: + file.write("unsigned short") + else: + file.write("unsigned int") + file.write(" " + self.name + "[] = {\n") + if self.data: + s = " " + for item in self.data: + i = str(item) + ", " + if len(s) + len(i) > 78: + file.write(s + "\n") + s = " " + i + else: + s = s + i + if s.strip(): + file.write(s + "\n") + file.write("};\n\n") + +def getsize(data): + # return smallest possible integer size for the given array + maxdata = max(data) + if maxdata < 256: + return 1 + elif maxdata < 65536: + return 2 + else: + return 4 + +def splitbins(t, trace=0): + """t, trace=0 -> (t1, t2, shift). Split a table to save space. + + t is a sequence of ints. This function can be useful to save space if + many of the ints are the same. t1 and t2 are lists of ints, and shift + is an int, chosen to minimize the combined size of t1 and t2 (in C + code), and where for each i in range(len(t)), + t[i] == t2[(t1[i >> shift] << shift) + (i & mask)] + where mask is a bitmask isolating the last "shift" bits. + + If optional arg trace is non-zero (default zero), progress info + is printed to sys.stderr. The higher the value, the more info + you'll get. + """ + + import sys + if trace: + def dump(t1, t2, shift, bytes): + print >>sys.stderr, "%d+%d bins at shift %d; %d bytes" % ( + len(t1), len(t2), shift, bytes) + print >>sys.stderr, "Size of original table:", len(t)*getsize(t), \ + "bytes" + n = len(t)-1 # last valid index + maxshift = 0 # the most we can shift n and still have something left + if n > 0: + while n >> 1: + n >>= 1 + maxshift += 1 + del n + bytes = sys.maxint # smallest total size so far + t = tuple(t) # so slices can be dict keys + for shift in range(maxshift + 1): + t1 = [] + t2 = [] + size = 2**shift + bincache = {} + for i in range(0, len(t), size): + bin = t[i:i+size] + index = bincache.get(bin) + if index is None: + index = len(t2) + bincache[bin] = index + t2.extend(bin) + t1.append(index >> shift) + # determine memory size + b = len(t1)*getsize(t1) + len(t2)*getsize(t2) + if trace > 1: + dump(t1, t2, shift, b) + if b < bytes: + best = t1, t2, shift + bytes = b + t1, t2, shift = best + if trace: + print >>sys.stderr, "Best:", + dump(t1, t2, shift, bytes) + if __debug__: + # exhaustively verify that the decomposition is correct + mask = ~((~0) << shift) # i.e., low-bit mask of shift bits + for i in xrange(len(t)): + assert t[i] == t2[(t1[i >> shift] << shift) + (i & mask)] + return best + +if __name__ == "__main__": + maketables(1) diff --git a/sys/src/cmd/python/Tools/unicode/mkstringprep.py b/sys/src/cmd/python/Tools/unicode/mkstringprep.py new file mode 100644 index 000000000..2525f9e5e --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/mkstringprep.py @@ -0,0 +1,431 @@ +import re, unicodedata, sys + +if sys.maxunicode == 65535: + raise RuntimeError, "need UCS-4 Python" + +def gen_category(cats): + for i in range(0, 0x110000): + if unicodedata.category(unichr(i)) in cats: + yield(i) + +def gen_bidirectional(cats): + for i in range(0, 0x110000): + if unicodedata.bidirectional(unichr(i)) in cats: + yield(i) + +def compact_set(l): + single = [] + tuple = [] + prev = None + span = 0 + for e in l: + if prev is None: + prev = e + span = 0 + continue + if prev+span+1 != e: + if span > 2: + tuple.append((prev,prev+span+1)) + else: + for i in range(prev, prev+span+1): + single.append(i) + prev = e + span = 0 + else: + span += 1 + if span: + tuple.append((prev,prev+span+1)) + else: + single.append(prev) + tuple = " + ".join(["range(%d,%d)" % t for t in tuple]) + if not single: + return "set(%s)" % tuple + if not tuple: + return "set(%s)" % repr(single) + return "set(%s + %s)" % (repr(single),tuple) + +############## Read the tables in the RFC ####################### + +data = open("rfc3454.txt").readlines() + +tables = [] +curname = None +for l in data: + l = l.strip() + if not l: + continue + # Skip RFC page breaks + if l.startswith("Hoffman & Blanchet") or\ + l.startswith("RFC 3454"): + continue + # Find start/end lines + m = re.match("----- (Start|End) Table ([A-Z](.[0-9])+) -----", l) + if m: + if m.group(1) == "Start": + if curname: + raise "Double Start",(curname, l) + curname = m.group(2) + table = {} + tables.append((curname, table)) + continue + else: + if not curname: + raise "End without start", l + curname = None + continue + if not curname: + continue + # Now we are in a table + fields = l.split(";") + if len(fields) > 1: + # Drop comment field + fields = fields[:-1] + if len(fields) == 1: + fields = fields[0].split("-") + if len(fields) > 1: + # range + try: + start, end = fields + except ValueError: + raise "Unpacking problem", l + else: + start = end = fields[0] + start = int(start, 16) + end = int(end, 16) + for i in range(start, end+1): + table[i] = i + else: + code, value = fields + value = value.strip() + if value: + value = [int(v, 16) for v in value.split(" ")] + else: + # table B.1 + value = None + table[int(code, 16)] = value + +########### Generate compact Python versions of the tables ############# + +print """# This file is generated by mkstringprep.py. DO NOT EDIT. +\"\"\"Library that exposes various tables found in the StringPrep RFC 3454. + +There are two kinds of tables: sets, for which a member test is provided, +and mappings, for which a mapping function is provided. +\"\"\" + +import unicodedata +""" + +print "assert unicodedata.unidata_version == %s" % repr(unicodedata.unidata_version) + +# A.1 is the table of unassigned characters +# XXX Plane 15 PUA is listed as unassigned in Python. +name, table = tables[0] +del tables[0] +assert name == "A.1" +table = set(table.keys()) +Cn = set(gen_category(["Cn"])) + +# FDD0..FDEF are process internal codes +Cn -= set(range(0xFDD0, 0xFDF0)) +# not a character +Cn -= set(range(0xFFFE, 0x110000, 0x10000)) +Cn -= set(range(0xFFFF, 0x110000, 0x10000)) + +# assert table == Cn + +print """ +def in_table_a1(code): + if unicodedata.category(code) != 'Cn': return False + c = ord(code) + if 0xFDD0 <= c < 0xFDF0: return False + return (c & 0xFFFF) not in (0xFFFE, 0xFFFF) +""" + +# B.1 cannot easily be derived +name, table = tables[0] +del tables[0] +assert name == "B.1" +table = table.keys() +table.sort() +print """ +b1_set = """ + compact_set(table) + """ +def in_table_b1(code): + return ord(code) in b1_set +""" + +# B.2 and B.3 is case folding. +# It takes CaseFolding.txt into account, which is +# not available in the Python database. Since +# B.2 is derived from B.3, we process B.3 first. +# B.3 supposedly *is* CaseFolding-3.2.0.txt. + +name, table_b2 = tables[0] +del tables[0] +assert name == "B.2" + +name, table_b3 = tables[0] +del tables[0] +assert name == "B.3" + +# B.3 is mostly Python's .lower, except for a number +# of special cases, e.g. considering canonical forms. + +b3_exceptions = {} + +for k,v in table_b2.items(): + if map(ord, unichr(k).lower()) != v: + b3_exceptions[k] = u"".join(map(unichr,v)) + +b3 = b3_exceptions.items() +b3.sort() + +print """ +b3_exceptions = {""" +for i,(k,v) in enumerate(b3): + print "0x%x:%s," % (k, repr(v)), + if i % 4 == 3: + print +print "}" + +print """ +def map_table_b3(code): + r = b3_exceptions.get(ord(code)) + if r is not None: return r + return code.lower() +""" + +def map_table_b3(code): + r = b3_exceptions.get(ord(code)) + if r is not None: return r + return code.lower() + +# B.2 is case folding for NFKC. This is the same as B.3, +# except where NormalizeWithKC(Fold(a)) != +# NormalizeWithKC(Fold(NormalizeWithKC(Fold(a)))) + +def map_table_b2(a): + al = map_table_b3(a) + b = unicodedata.normalize("NFKC", al) + bl = u"".join([map_table_b3(ch) for ch in b]) + c = unicodedata.normalize("NFKC", bl) + if b != c: + return c + else: + return al + +specials = {} +for k,v in table_b2.items(): + if map(ord, map_table_b2(unichr(k))) != v: + specials[k] = v + +# B.3 should not add any additional special cases +assert specials == {} + +print """ +def map_table_b2(a): + al = map_table_b3(a) + b = unicodedata.normalize("NFKC", al) + bl = u"".join([map_table_b3(ch) for ch in b]) + c = unicodedata.normalize("NFKC", bl) + if b != c: + return c + else: + return al +""" + +# C.1.1 is a table with a single character +name, table = tables[0] +del tables[0] +assert name == "C.1.1" +assert table == {0x20:0x20} + +print """ +def in_table_c11(code): + return code == u" " +""" + +# C.1.2 is the rest of all space characters +name, table = tables[0] +del tables[0] +assert name == "C.1.2" + +# table = set(table.keys()) +# Zs = set(gen_category(["Zs"])) - set([0x20]) +# assert Zs == table + +print """ +def in_table_c12(code): + return unicodedata.category(code) == "Zs" and code != u" " + +def in_table_c11_c12(code): + return unicodedata.category(code) == "Zs" +""" + +# C.2.1 ASCII control characters +name, table_c21 = tables[0] +del tables[0] +assert name == "C.2.1" + +Cc = set(gen_category(["Cc"])) +Cc_ascii = Cc & set(range(128)) +table_c21 = set(table_c21.keys()) +assert Cc_ascii == table_c21 + +print """ +def in_table_c21(code): + return ord(code) < 128 and unicodedata.category(code) == "Cc" +""" + +# C.2.2 Non-ASCII control characters. It also includes +# a number of characters in category Cf. +name, table_c22 = tables[0] +del tables[0] +assert name == "C.2.2" + +Cc_nonascii = Cc - Cc_ascii +table_c22 = set(table_c22.keys()) +assert len(Cc_nonascii - table_c22) == 0 + +specials = list(table_c22 - Cc_nonascii) +specials.sort() + +print """c22_specials = """ + compact_set(specials) + """ +def in_table_c22(code): + c = ord(code) + if c < 128: return False + if unicodedata.category(code) == "Cc": return True + return c in c22_specials + +def in_table_c21_c22(code): + return unicodedata.category(code) == "Cc" or \\ + ord(code) in c22_specials +""" + +# C.3 Private use +name, table = tables[0] +del tables[0] +assert name == "C.3" + +Co = set(gen_category(["Co"])) +assert set(table.keys()) == Co + +print """ +def in_table_c3(code): + return unicodedata.category(code) == "Co" +""" + +# C.4 Non-character code points, xFFFE, xFFFF +# plus process internal codes +name, table = tables[0] +del tables[0] +assert name == "C.4" + +nonchar = set(range(0xFDD0,0xFDF0) + + range(0xFFFE,0x110000,0x10000) + + range(0xFFFF,0x110000,0x10000)) +table = set(table.keys()) +assert table == nonchar + +print """ +def in_table_c4(code): + c = ord(code) + if c < 0xFDD0: return False + if c < 0xFDF0: return True + return (ord(code) & 0xFFFF) in (0xFFFE, 0xFFFF) +""" + +# C.5 Surrogate codes +name, table = tables[0] +del tables[0] +assert name == "C.5" + +Cs = set(gen_category(["Cs"])) +assert set(table.keys()) == Cs + +print """ +def in_table_c5(code): + return unicodedata.category(code) == "Cs" +""" + +# C.6 Inappropriate for plain text +name, table = tables[0] +del tables[0] +assert name == "C.6" + +table = table.keys() +table.sort() + +print """ +c6_set = """ + compact_set(table) + """ +def in_table_c6(code): + return ord(code) in c6_set +""" + +# C.7 Inappropriate for canonical representation +name, table = tables[0] +del tables[0] +assert name == "C.7" + +table = table.keys() +table.sort() + +print """ +c7_set = """ + compact_set(table) + """ +def in_table_c7(code): + return ord(code) in c7_set +""" + +# C.8 Change display properties or are deprecated +name, table = tables[0] +del tables[0] +assert name == "C.8" + +table = table.keys() +table.sort() + +print """ +c8_set = """ + compact_set(table) + """ +def in_table_c8(code): + return ord(code) in c8_set +""" + +# C.9 Tagging characters +name, table = tables[0] +del tables[0] +assert name == "C.9" + +table = table.keys() +table.sort() + +print """ +c9_set = """ + compact_set(table) + """ +def in_table_c9(code): + return ord(code) in c9_set +""" + +# D.1 Characters with bidirectional property "R" or "AL" +name, table = tables[0] +del tables[0] +assert name == "D.1" + +RandAL = set(gen_bidirectional(["R","AL"])) +assert set(table.keys()) == RandAL + +print """ +def in_table_d1(code): + return unicodedata.bidirectional(code) in ("R","AL") +""" + +# D.2 Characters with bidirectional property "L" +name, table = tables[0] +del tables[0] +assert name == "D.2" + +L = set(gen_bidirectional(["L"])) +assert set(table.keys()) == L + +print """ +def in_table_d2(code): + return unicodedata.bidirectional(code) == "L" +""" diff --git a/sys/src/cmd/python/Tools/unicode/python-mappings/CP1140.TXT b/sys/src/cmd/python/Tools/unicode/python-mappings/CP1140.TXT new file mode 100644 index 000000000..ede5cbf6a --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/python-mappings/CP1140.TXT @@ -0,0 +1,291 @@ +# +# Name: CP1140 +# Unicode version: 3.2 +# Table version: 1.0 +# Table format: Format A +# Date: 2005-10-25 +# Authors: Marc-Andre Lemburg <mal@egenix.com> +# +# This encoding is a modified CP037 encoding (with added Euro +# currency sign). +# +# (c) Copyright Marc-Andre Lemburg, 2005. +# Licensed to PSF under a Contributor Agreement. +# +# Based on the file +# ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/EBCDIC/CP037.TXT +# which is: +# +# Copyright (c) 2002 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x009C #CONTROL +0x05 0x0009 #HORIZONTAL TABULATION +0x06 0x0086 #CONTROL +0x07 0x007F #DELETE +0x08 0x0097 #CONTROL +0x09 0x008D #CONTROL +0x0A 0x008E #CONTROL +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x009D #CONTROL +0x15 0x0085 #CONTROL +0x16 0x0008 #BACKSPACE +0x17 0x0087 #CONTROL +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x0092 #CONTROL +0x1B 0x008F #CONTROL +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0080 #CONTROL +0x21 0x0081 #CONTROL +0x22 0x0082 #CONTROL +0x23 0x0083 #CONTROL +0x24 0x0084 #CONTROL +0x25 0x000A #LINE FEED +0x26 0x0017 #END OF TRANSMISSION BLOCK +0x27 0x001B #ESCAPE +0x28 0x0088 #CONTROL +0x29 0x0089 #CONTROL +0x2A 0x008A #CONTROL +0x2B 0x008B #CONTROL +0x2C 0x008C #CONTROL +0x2D 0x0005 #ENQUIRY +0x2E 0x0006 #ACKNOWLEDGE +0x2F 0x0007 #BELL +0x30 0x0090 #CONTROL +0x31 0x0091 #CONTROL +0x32 0x0016 #SYNCHRONOUS IDLE +0x33 0x0093 #CONTROL +0x34 0x0094 #CONTROL +0x35 0x0095 #CONTROL +0x36 0x0096 #CONTROL +0x37 0x0004 #END OF TRANSMISSION +0x38 0x0098 #CONTROL +0x39 0x0099 #CONTROL +0x3A 0x009A #CONTROL +0x3B 0x009B #CONTROL +0x3C 0x0014 #DEVICE CONTROL FOUR +0x3D 0x0015 #NEGATIVE ACKNOWLEDGE +0x3E 0x009E #CONTROL +0x3F 0x001A #SUBSTITUTE +0x40 0x0020 #SPACE +0x41 0x00A0 #NO-BREAK SPACE +0x42 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0x43 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0x44 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0x45 0x00E1 #LATIN SMALL LETTER A WITH ACUTE +0x46 0x00E3 #LATIN SMALL LETTER A WITH TILDE +0x47 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0x48 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0x49 0x00F1 #LATIN SMALL LETTER N WITH TILDE +0x4A 0x00A2 #CENT SIGN +0x4B 0x002E #FULL STOP +0x4C 0x003C #LESS-THAN SIGN +0x4D 0x0028 #LEFT PARENTHESIS +0x4E 0x002B #PLUS SIGN +0x4F 0x007C #VERTICAL LINE +0x50 0x0026 #AMPERSAND +0x51 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0x52 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0x53 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0x54 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0x55 0x00ED #LATIN SMALL LETTER I WITH ACUTE +0x56 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0x57 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0x58 0x00EC #LATIN SMALL LETTER I WITH GRAVE +0x59 0x00DF #LATIN SMALL LETTER SHARP S (GERMAN) +0x5A 0x0021 #EXCLAMATION MARK +0x5B 0x0024 #DOLLAR SIGN +0x5C 0x002A #ASTERISK +0x5D 0x0029 #RIGHT PARENTHESIS +0x5E 0x003B #SEMICOLON +0x5F 0x00AC #NOT SIGN +0x60 0x002D #HYPHEN-MINUS +0x61 0x002F #SOLIDUS +0x62 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0x63 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0x64 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE +0x65 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE +0x66 0x00C3 #LATIN CAPITAL LETTER A WITH TILDE +0x67 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0x68 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA +0x69 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE +0x6A 0x00A6 #BROKEN BAR +0x6B 0x002C #COMMA +0x6C 0x0025 #PERCENT SIGN +0x6D 0x005F #LOW LINE +0x6E 0x003E #GREATER-THAN SIGN +0x6F 0x003F #QUESTION MARK +0x70 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0x71 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0x72 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0x73 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS +0x74 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE +0x75 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE +0x76 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0x77 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS +0x78 0x00CC #LATIN CAPITAL LETTER I WITH GRAVE +0x79 0x0060 #GRAVE ACCENT +0x7A 0x003A #COLON +0x7B 0x0023 #NUMBER SIGN +0x7C 0x0040 #COMMERCIAL AT +0x7D 0x0027 #APOSTROPHE +0x7E 0x003D #EQUALS SIGN +0x7F 0x0022 #QUOTATION MARK +0x80 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0x81 0x0061 #LATIN SMALL LETTER A +0x82 0x0062 #LATIN SMALL LETTER B +0x83 0x0063 #LATIN SMALL LETTER C +0x84 0x0064 #LATIN SMALL LETTER D +0x85 0x0065 #LATIN SMALL LETTER E +0x86 0x0066 #LATIN SMALL LETTER F +0x87 0x0067 #LATIN SMALL LETTER G +0x88 0x0068 #LATIN SMALL LETTER H +0x89 0x0069 #LATIN SMALL LETTER I +0x8A 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0x8B 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0x8C 0x00F0 #LATIN SMALL LETTER ETH (ICELANDIC) +0x8D 0x00FD #LATIN SMALL LETTER Y WITH ACUTE +0x8E 0x00FE #LATIN SMALL LETTER THORN (ICELANDIC) +0x8F 0x00B1 #PLUS-MINUS SIGN +0x90 0x00B0 #DEGREE SIGN +0x91 0x006A #LATIN SMALL LETTER J +0x92 0x006B #LATIN SMALL LETTER K +0x93 0x006C #LATIN SMALL LETTER L +0x94 0x006D #LATIN SMALL LETTER M +0x95 0x006E #LATIN SMALL LETTER N +0x96 0x006F #LATIN SMALL LETTER O +0x97 0x0070 #LATIN SMALL LETTER P +0x98 0x0071 #LATIN SMALL LETTER Q +0x99 0x0072 #LATIN SMALL LETTER R +0x9A 0x00AA #FEMININE ORDINAL INDICATOR +0x9B 0x00BA #MASCULINE ORDINAL INDICATOR +0x9C 0x00E6 #LATIN SMALL LIGATURE AE +0x9D 0x00B8 #CEDILLA +0x9E 0x00C6 #LATIN CAPITAL LIGATURE AE +#0x9F 0x00A4 #CURRENCY SIGN +0x9F 0x20AC # EURO SIGN +0xA0 0x00B5 #MICRO SIGN +0xA1 0x007E #TILDE +0xA2 0x0073 #LATIN SMALL LETTER S +0xA3 0x0074 #LATIN SMALL LETTER T +0xA4 0x0075 #LATIN SMALL LETTER U +0xA5 0x0076 #LATIN SMALL LETTER V +0xA6 0x0077 #LATIN SMALL LETTER W +0xA7 0x0078 #LATIN SMALL LETTER X +0xA8 0x0079 #LATIN SMALL LETTER Y +0xA9 0x007A #LATIN SMALL LETTER Z +0xAA 0x00A1 #INVERTED EXCLAMATION MARK +0xAB 0x00BF #INVERTED QUESTION MARK +0xAC 0x00D0 #LATIN CAPITAL LETTER ETH (ICELANDIC) +0xAD 0x00DD #LATIN CAPITAL LETTER Y WITH ACUTE +0xAE 0x00DE #LATIN CAPITAL LETTER THORN (ICELANDIC) +0xAF 0x00AE #REGISTERED SIGN +0xB0 0x005E #CIRCUMFLEX ACCENT +0xB1 0x00A3 #POUND SIGN +0xB2 0x00A5 #YEN SIGN +0xB3 0x00B7 #MIDDLE DOT +0xB4 0x00A9 #COPYRIGHT SIGN +0xB5 0x00A7 #SECTION SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00BC #VULGAR FRACTION ONE QUARTER +0xB8 0x00BD #VULGAR FRACTION ONE HALF +0xB9 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBA 0x005B #LEFT SQUARE BRACKET +0xBB 0x005D #RIGHT SQUARE BRACKET +0xBC 0x00AF #MACRON +0xBD 0x00A8 #DIAERESIS +0xBE 0x00B4 #ACUTE ACCENT +0xBF 0x00D7 #MULTIPLICATION SIGN +0xC0 0x007B #LEFT CURLY BRACKET +0xC1 0x0041 #LATIN CAPITAL LETTER A +0xC2 0x0042 #LATIN CAPITAL LETTER B +0xC3 0x0043 #LATIN CAPITAL LETTER C +0xC4 0x0044 #LATIN CAPITAL LETTER D +0xC5 0x0045 #LATIN CAPITAL LETTER E +0xC6 0x0046 #LATIN CAPITAL LETTER F +0xC7 0x0047 #LATIN CAPITAL LETTER G +0xC8 0x0048 #LATIN CAPITAL LETTER H +0xC9 0x0049 #LATIN CAPITAL LETTER I +0xCA 0x00AD #SOFT HYPHEN +0xCB 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xCC 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xCD 0x00F2 #LATIN SMALL LETTER O WITH GRAVE +0xCE 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xCF 0x00F5 #LATIN SMALL LETTER O WITH TILDE +0xD0 0x007D #RIGHT CURLY BRACKET +0xD1 0x004A #LATIN CAPITAL LETTER J +0xD2 0x004B #LATIN CAPITAL LETTER K +0xD3 0x004C #LATIN CAPITAL LETTER L +0xD4 0x004D #LATIN CAPITAL LETTER M +0xD5 0x004E #LATIN CAPITAL LETTER N +0xD6 0x004F #LATIN CAPITAL LETTER O +0xD7 0x0050 #LATIN CAPITAL LETTER P +0xD8 0x0051 #LATIN CAPITAL LETTER Q +0xD9 0x0052 #LATIN CAPITAL LETTER R +0xDA 0x00B9 #SUPERSCRIPT ONE +0xDB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xDC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xDD 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xDE 0x00FA #LATIN SMALL LETTER U WITH ACUTE +0xDF 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS +0xE0 0x005C #REVERSE SOLIDUS +0xE1 0x00F7 #DIVISION SIGN +0xE2 0x0053 #LATIN CAPITAL LETTER S +0xE3 0x0054 #LATIN CAPITAL LETTER T +0xE4 0x0055 #LATIN CAPITAL LETTER U +0xE5 0x0056 #LATIN CAPITAL LETTER V +0xE6 0x0057 #LATIN CAPITAL LETTER W +0xE7 0x0058 #LATIN CAPITAL LETTER X +0xE8 0x0059 #LATIN CAPITAL LETTER Y +0xE9 0x005A #LATIN CAPITAL LETTER Z +0xEA 0x00B2 #SUPERSCRIPT TWO +0xEB 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xEC 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xED 0x00D2 #LATIN CAPITAL LETTER O WITH GRAVE +0xEE 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xEF 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE +0xF0 0x0030 #DIGIT ZERO +0xF1 0x0031 #DIGIT ONE +0xF2 0x0032 #DIGIT TWO +0xF3 0x0033 #DIGIT THREE +0xF4 0x0034 #DIGIT FOUR +0xF5 0x0035 #DIGIT FIVE +0xF6 0x0036 #DIGIT SIX +0xF7 0x0037 #DIGIT SEVEN +0xF8 0x0038 #DIGIT EIGHT +0xF9 0x0039 #DIGIT NINE +0xFA 0x00B3 #SUPERSCRIPT THREE +0xFB 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xFC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xFD 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE +0xFE 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE +0xFF 0x009F #CONTROL diff --git a/sys/src/cmd/python/Tools/unicode/python-mappings/KOI8-U.TXT b/sys/src/cmd/python/Tools/unicode/python-mappings/KOI8-U.TXT new file mode 100644 index 000000000..fe9bf6a49 --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/python-mappings/KOI8-U.TXT @@ -0,0 +1,298 @@ +# +# Name: KOI8-U (RFC2319) to Unicode +# Unicode version: 3.2 +# Table version: 1.0 +# Table format: Format A +# Date: 2005-10-25 +# Authors: Marc-Andre Lemburg <mal@egenix.com> +# +# See RFC2319 for details. This encoding is a modified KOI8-R +# encoding. +# +# (c) Copyright Marc-Andre Lemburg, 2005. +# Licensed to PSF under a Contributor Agreement. +# +# Based on the file +# ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/MISC/KOI8-R.TXT +# which is: +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x2500 # BOX DRAWINGS LIGHT HORIZONTAL +0x81 0x2502 # BOX DRAWINGS LIGHT VERTICAL +0x82 0x250C # BOX DRAWINGS LIGHT DOWN AND RIGHT +0x83 0x2510 # BOX DRAWINGS LIGHT DOWN AND LEFT +0x84 0x2514 # BOX DRAWINGS LIGHT UP AND RIGHT +0x85 0x2518 # BOX DRAWINGS LIGHT UP AND LEFT +0x86 0x251C # BOX DRAWINGS LIGHT VERTICAL AND RIGHT +0x87 0x2524 # BOX DRAWINGS LIGHT VERTICAL AND LEFT +0x88 0x252C # BOX DRAWINGS LIGHT DOWN AND HORIZONTAL +0x89 0x2534 # BOX DRAWINGS LIGHT UP AND HORIZONTAL +0x8A 0x253C # BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL +0x8B 0x2580 # UPPER HALF BLOCK +0x8C 0x2584 # LOWER HALF BLOCK +0x8D 0x2588 # FULL BLOCK +0x8E 0x258C # LEFT HALF BLOCK +0x8F 0x2590 # RIGHT HALF BLOCK +0x90 0x2591 # LIGHT SHADE +0x91 0x2592 # MEDIUM SHADE +0x92 0x2593 # DARK SHADE +0x93 0x2320 # TOP HALF INTEGRAL +0x94 0x25A0 # BLACK SQUARE +0x95 0x2219 # BULLET OPERATOR +0x96 0x221A # SQUARE ROOT +0x97 0x2248 # ALMOST EQUAL TO +0x98 0x2264 # LESS-THAN OR EQUAL TO +0x99 0x2265 # GREATER-THAN OR EQUAL TO +0x9A 0x00A0 # NO-BREAK SPACE +0x9B 0x2321 # BOTTOM HALF INTEGRAL +0x9C 0x00B0 # DEGREE SIGN +0x9D 0x00B2 # SUPERSCRIPT TWO +0x9E 0x00B7 # MIDDLE DOT +0x9F 0x00F7 # DIVISION SIGN +0xA0 0x2550 # BOX DRAWINGS DOUBLE HORIZONTAL +0xA1 0x2551 # BOX DRAWINGS DOUBLE VERTICAL +0xA2 0x2552 # BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE +0xA3 0x0451 # CYRILLIC SMALL LETTER IO +#0xA4 0x2553 # BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE +0xA4 0x0454 # CYRILLIC SMALL LETTER UKRAINIAN IE +0xA5 0x2554 # BOX DRAWINGS DOUBLE DOWN AND RIGHT +#0xA6 0x2555 # BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE +0xA6 0x0456 # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +#0xA7 0x2556 # BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE +0xA7 0x0457 # CYRILLIC SMALL LETTER YI (UKRAINIAN) +0xA8 0x2557 # BOX DRAWINGS DOUBLE DOWN AND LEFT +0xA9 0x2558 # BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE +0xAA 0x2559 # BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE +0xAB 0x255A # BOX DRAWINGS DOUBLE UP AND RIGHT +0xAC 0x255B # BOX DRAWINGS UP SINGLE AND LEFT DOUBLE +#0xAD 0x255C # BOX DRAWINGS UP DOUBLE AND LEFT SINGLE +0xAD 0x0491 # CYRILLIC SMALL LETTER UKRAINIAN GHE WITH UPTURN +0xAE 0x255D # BOX DRAWINGS DOUBLE UP AND LEFT +0xAF 0x255E # BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE +0xB0 0x255F # BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE +0xB1 0x2560 # BOX DRAWINGS DOUBLE VERTICAL AND RIGHT +0xB2 0x2561 # BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE +0xB3 0x0401 # CYRILLIC CAPITAL LETTER IO +#0xB4 0x2562 # BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE +0xB4 0x0404 # CYRILLIC CAPITAL LETTER UKRAINIAN IE +0xB5 0x2563 # BOX DRAWINGS DOUBLE VERTICAL AND LEFT +#0xB6 0x2564 # BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE +0xB6 0x0406 # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +#0xB7 0x2565 # BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE +0xB7 0x0407 # CYRILLIC CAPITAL LETTER YI (UKRAINIAN) +0xB8 0x2566 # BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL +0xB9 0x2567 # BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE +0xBA 0x2568 # BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE +0xBB 0x2569 # BOX DRAWINGS DOUBLE UP AND HORIZONTAL +0xBC 0x256A # BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE +#0xBD 0x256B # BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE +0xBD 0x0490 # CYRILLIC CAPITAL LETTER UKRAINIAN GHE WITH UPTURN +0xBE 0x256C # BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL +0xBF 0x00A9 # COPYRIGHT SIGN +0xC0 0x044E # CYRILLIC SMALL LETTER YU +0xC1 0x0430 # CYRILLIC SMALL LETTER A +0xC2 0x0431 # CYRILLIC SMALL LETTER BE +0xC3 0x0446 # CYRILLIC SMALL LETTER TSE +0xC4 0x0434 # CYRILLIC SMALL LETTER DE +0xC5 0x0435 # CYRILLIC SMALL LETTER IE +0xC6 0x0444 # CYRILLIC SMALL LETTER EF +0xC7 0x0433 # CYRILLIC SMALL LETTER GHE +0xC8 0x0445 # CYRILLIC SMALL LETTER HA +0xC9 0x0438 # CYRILLIC SMALL LETTER I +0xCA 0x0439 # CYRILLIC SMALL LETTER SHORT I +0xCB 0x043A # CYRILLIC SMALL LETTER KA +0xCC 0x043B # CYRILLIC SMALL LETTER EL +0xCD 0x043C # CYRILLIC SMALL LETTER EM +0xCE 0x043D # CYRILLIC SMALL LETTER EN +0xCF 0x043E # CYRILLIC SMALL LETTER O +0xD0 0x043F # CYRILLIC SMALL LETTER PE +0xD1 0x044F # CYRILLIC SMALL LETTER YA +0xD2 0x0440 # CYRILLIC SMALL LETTER ER +0xD3 0x0441 # CYRILLIC SMALL LETTER ES +0xD4 0x0442 # CYRILLIC SMALL LETTER TE +0xD5 0x0443 # CYRILLIC SMALL LETTER U +0xD6 0x0436 # CYRILLIC SMALL LETTER ZHE +0xD7 0x0432 # CYRILLIC SMALL LETTER VE +0xD8 0x044C # CYRILLIC SMALL LETTER SOFT SIGN +0xD9 0x044B # CYRILLIC SMALL LETTER YERU +0xDA 0x0437 # CYRILLIC SMALL LETTER ZE +0xDB 0x0448 # CYRILLIC SMALL LETTER SHA +0xDC 0x044D # CYRILLIC SMALL LETTER E +0xDD 0x0449 # CYRILLIC SMALL LETTER SHCHA +0xDE 0x0447 # CYRILLIC SMALL LETTER CHE +0xDF 0x044A # CYRILLIC SMALL LETTER HARD SIGN +0xE0 0x042E # CYRILLIC CAPITAL LETTER YU +0xE1 0x0410 # CYRILLIC CAPITAL LETTER A +0xE2 0x0411 # CYRILLIC CAPITAL LETTER BE +0xE3 0x0426 # CYRILLIC CAPITAL LETTER TSE +0xE4 0x0414 # CYRILLIC CAPITAL LETTER DE +0xE5 0x0415 # CYRILLIC CAPITAL LETTER IE +0xE6 0x0424 # CYRILLIC CAPITAL LETTER EF +0xE7 0x0413 # CYRILLIC CAPITAL LETTER GHE +0xE8 0x0425 # CYRILLIC CAPITAL LETTER HA +0xE9 0x0418 # CYRILLIC CAPITAL LETTER I +0xEA 0x0419 # CYRILLIC CAPITAL LETTER SHORT I +0xEB 0x041A # CYRILLIC CAPITAL LETTER KA +0xEC 0x041B # CYRILLIC CAPITAL LETTER EL +0xED 0x041C # CYRILLIC CAPITAL LETTER EM +0xEE 0x041D # CYRILLIC CAPITAL LETTER EN +0xEF 0x041E # CYRILLIC CAPITAL LETTER O +0xF0 0x041F # CYRILLIC CAPITAL LETTER PE +0xF1 0x042F # CYRILLIC CAPITAL LETTER YA +0xF2 0x0420 # CYRILLIC CAPITAL LETTER ER +0xF3 0x0421 # CYRILLIC CAPITAL LETTER ES +0xF4 0x0422 # CYRILLIC CAPITAL LETTER TE +0xF5 0x0423 # CYRILLIC CAPITAL LETTER U +0xF6 0x0416 # CYRILLIC CAPITAL LETTER ZHE +0xF7 0x0412 # CYRILLIC CAPITAL LETTER VE +0xF8 0x042C # CYRILLIC CAPITAL LETTER SOFT SIGN +0xF9 0x042B # CYRILLIC CAPITAL LETTER YERU +0xFA 0x0417 # CYRILLIC CAPITAL LETTER ZE +0xFB 0x0428 # CYRILLIC CAPITAL LETTER SHA +0xFC 0x042D # CYRILLIC CAPITAL LETTER E +0xFD 0x0429 # CYRILLIC CAPITAL LETTER SHCHA +0xFE 0x0427 # CYRILLIC CAPITAL LETTER CHE +0xFF 0x042A # CYRILLIC CAPITAL LETTER HARD SIGN diff --git a/sys/src/cmd/python/Tools/unicode/python-mappings/TIS-620.TXT b/sys/src/cmd/python/Tools/unicode/python-mappings/TIS-620.TXT new file mode 100644 index 000000000..c2e90c233 --- /dev/null +++ b/sys/src/cmd/python/Tools/unicode/python-mappings/TIS-620.TXT @@ -0,0 +1,284 @@ +# +# Name: TIS-620 +# Unicode version: 3.2 +# Table version: 1.0 +# Table format: Format A +# Date: 2005-10-25 +# Authors: Marc-Andre Lemburg <mal@egenix.com> +# +# According to +# ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-11.TXT the +# TIS-620 is the identical to ISO_8859-11 with the 0xA0 +# (no-break space) mapping removed. +# +# (c) Copyright Marc-Andre Lemburg, 2005. +# Licensed to PSF under a Contributor Agreement. +# +# Based on the file +# ftp://ftp.unicode.org/Public/MAPPINGS/ISO8859/8859-11.TXT +# which is: +# +# Copyright (c) 2002 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # <control> +0x81 0x0081 # <control> +0x82 0x0082 # <control> +0x83 0x0083 # <control> +0x84 0x0084 # <control> +0x85 0x0085 # <control> +0x86 0x0086 # <control> +0x87 0x0087 # <control> +0x88 0x0088 # <control> +0x89 0x0089 # <control> +0x8A 0x008A # <control> +0x8B 0x008B # <control> +0x8C 0x008C # <control> +0x8D 0x008D # <control> +0x8E 0x008E # <control> +0x8F 0x008F # <control> +0x90 0x0090 # <control> +0x91 0x0091 # <control> +0x92 0x0092 # <control> +0x93 0x0093 # <control> +0x94 0x0094 # <control> +0x95 0x0095 # <control> +0x96 0x0096 # <control> +0x97 0x0097 # <control> +0x98 0x0098 # <control> +0x99 0x0099 # <control> +0x9A 0x009A # <control> +0x9B 0x009B # <control> +0x9C 0x009C # <control> +0x9D 0x009D # <control> +0x9E 0x009E # <control> +0x9F 0x009F # <control> +#0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x0E01 # THAI CHARACTER KO KAI +0xA2 0x0E02 # THAI CHARACTER KHO KHAI +0xA3 0x0E03 # THAI CHARACTER KHO KHUAT +0xA4 0x0E04 # THAI CHARACTER KHO KHWAI +0xA5 0x0E05 # THAI CHARACTER KHO KHON +0xA6 0x0E06 # THAI CHARACTER KHO RAKHANG +0xA7 0x0E07 # THAI CHARACTER NGO NGU +0xA8 0x0E08 # THAI CHARACTER CHO CHAN +0xA9 0x0E09 # THAI CHARACTER CHO CHING +0xAA 0x0E0A # THAI CHARACTER CHO CHANG +0xAB 0x0E0B # THAI CHARACTER SO SO +0xAC 0x0E0C # THAI CHARACTER CHO CHOE +0xAD 0x0E0D # THAI CHARACTER YO YING +0xAE 0x0E0E # THAI CHARACTER DO CHADA +0xAF 0x0E0F # THAI CHARACTER TO PATAK +0xB0 0x0E10 # THAI CHARACTER THO THAN +0xB1 0x0E11 # THAI CHARACTER THO NANGMONTHO +0xB2 0x0E12 # THAI CHARACTER THO PHUTHAO +0xB3 0x0E13 # THAI CHARACTER NO NEN +0xB4 0x0E14 # THAI CHARACTER DO DEK +0xB5 0x0E15 # THAI CHARACTER TO TAO +0xB6 0x0E16 # THAI CHARACTER THO THUNG +0xB7 0x0E17 # THAI CHARACTER THO THAHAN +0xB8 0x0E18 # THAI CHARACTER THO THONG +0xB9 0x0E19 # THAI CHARACTER NO NU +0xBA 0x0E1A # THAI CHARACTER BO BAIMAI +0xBB 0x0E1B # THAI CHARACTER PO PLA +0xBC 0x0E1C # THAI CHARACTER PHO PHUNG +0xBD 0x0E1D # THAI CHARACTER FO FA +0xBE 0x0E1E # THAI CHARACTER PHO PHAN +0xBF 0x0E1F # THAI CHARACTER FO FAN +0xC0 0x0E20 # THAI CHARACTER PHO SAMPHAO +0xC1 0x0E21 # THAI CHARACTER MO MA +0xC2 0x0E22 # THAI CHARACTER YO YAK +0xC3 0x0E23 # THAI CHARACTER RO RUA +0xC4 0x0E24 # THAI CHARACTER RU +0xC5 0x0E25 # THAI CHARACTER LO LING +0xC6 0x0E26 # THAI CHARACTER LU +0xC7 0x0E27 # THAI CHARACTER WO WAEN +0xC8 0x0E28 # THAI CHARACTER SO SALA +0xC9 0x0E29 # THAI CHARACTER SO RUSI +0xCA 0x0E2A # THAI CHARACTER SO SUA +0xCB 0x0E2B # THAI CHARACTER HO HIP +0xCC 0x0E2C # THAI CHARACTER LO CHULA +0xCD 0x0E2D # THAI CHARACTER O ANG +0xCE 0x0E2E # THAI CHARACTER HO NOKHUK +0xCF 0x0E2F # THAI CHARACTER PAIYANNOI +0xD0 0x0E30 # THAI CHARACTER SARA A +0xD1 0x0E31 # THAI CHARACTER MAI HAN-AKAT +0xD2 0x0E32 # THAI CHARACTER SARA AA +0xD3 0x0E33 # THAI CHARACTER SARA AM +0xD4 0x0E34 # THAI CHARACTER SARA I +0xD5 0x0E35 # THAI CHARACTER SARA II +0xD6 0x0E36 # THAI CHARACTER SARA UE +0xD7 0x0E37 # THAI CHARACTER SARA UEE +0xD8 0x0E38 # THAI CHARACTER SARA U +0xD9 0x0E39 # THAI CHARACTER SARA UU +0xDA 0x0E3A # THAI CHARACTER PHINTHU +0xDF 0x0E3F # THAI CURRENCY SYMBOL BAHT +0xE0 0x0E40 # THAI CHARACTER SARA E +0xE1 0x0E41 # THAI CHARACTER SARA AE +0xE2 0x0E42 # THAI CHARACTER SARA O +0xE3 0x0E43 # THAI CHARACTER SARA AI MAIMUAN +0xE4 0x0E44 # THAI CHARACTER SARA AI MAIMALAI +0xE5 0x0E45 # THAI CHARACTER LAKKHANGYAO +0xE6 0x0E46 # THAI CHARACTER MAIYAMOK +0xE7 0x0E47 # THAI CHARACTER MAITAIKHU +0xE8 0x0E48 # THAI CHARACTER MAI EK +0xE9 0x0E49 # THAI CHARACTER MAI THO +0xEA 0x0E4A # THAI CHARACTER MAI TRI +0xEB 0x0E4B # THAI CHARACTER MAI CHATTAWA +0xEC 0x0E4C # THAI CHARACTER THANTHAKHAT +0xED 0x0E4D # THAI CHARACTER NIKHAHIT +0xEE 0x0E4E # THAI CHARACTER YAMAKKAN +0xEF 0x0E4F # THAI CHARACTER FONGMAN +0xF0 0x0E50 # THAI DIGIT ZERO +0xF1 0x0E51 # THAI DIGIT ONE +0xF2 0x0E52 # THAI DIGIT TWO +0xF3 0x0E53 # THAI DIGIT THREE +0xF4 0x0E54 # THAI DIGIT FOUR +0xF5 0x0E55 # THAI DIGIT FIVE +0xF6 0x0E56 # THAI DIGIT SIX +0xF7 0x0E57 # THAI DIGIT SEVEN +0xF8 0x0E58 # THAI DIGIT EIGHT +0xF9 0x0E59 # THAI DIGIT NINE +0xFA 0x0E5A # THAI CHARACTER ANGKHANKHU +0xFB 0x0E5B # THAI CHARACTER KHOMUT diff --git a/sys/src/cmd/python/Tools/versioncheck/README b/sys/src/cmd/python/Tools/versioncheck/README new file mode 100644 index 000000000..a51411b04 --- /dev/null +++ b/sys/src/cmd/python/Tools/versioncheck/README @@ -0,0 +1,41 @@ +This is versioncheck 1.0, a first stab at automatic checking of versions of +Python extension packages installed on your system. + +The basic idea is that each package contains a _checkversion.py +somewhere, probably at the root level of the package. In addition, each +package maintainer makes a file available on the net, through ftp or +http, which contains the version number of the most recent distribution +and some readable text explaining the differences with previous +versions, where to download the package, etc. + +The checkversions.py script walks through the installed Python tree (or +through a tree of choice), and runs each _checkversion.py script. These +scripts retrieve the current-version file over the net, compares version +numbers and tells the user about new versions of packages available. + +A boilerplate for the _checkversion.py file can be found here. Replace +package name, version and the URL of the version-check file and put it in +your distribution. In stead of a single URL you can also specify a list +of URLs. Each of these will be checked in order until one is available, +this is handy for distributions that live in multiple places. Put the +primary distribution site (the most up-to-date site) before others. +The script is executed with execfile(), not imported, and the current +directory is the checkversion directory, so be careful with globals, +importing, etc. + +The version-check file consists of an rfc822-style header followed by +plaintext. The only header field checked currently is +'Current-Version:', which should contain te current version and is +matched against the string contained in the _checkversion.py script. +The rest of the file is human-readable text and presented to the user if +there is a version mismatch. It should contain at the very least a URL +of either the current distribution or a webpage describing it. + +Pycheckversion.py is the module that does the actual checking of versions. +It should be fine where it is, it is imported by checkversion before anything +else is done, but if imports fail you may want to move it to somewhere +along sys.path. + + Jack Jansen, CWI, 23-Dec-97. + <jack@cwi.nl> + diff --git a/sys/src/cmd/python/Tools/versioncheck/_checkversion.py b/sys/src/cmd/python/Tools/versioncheck/_checkversion.py new file mode 100644 index 000000000..7b3bb5082 --- /dev/null +++ b/sys/src/cmd/python/Tools/versioncheck/_checkversion.py @@ -0,0 +1,16 @@ +"""This file (which is sourced, not imported) checks the version of the +"versioncheck" package. It is also an example of how to format your own +_checkversion.py file""" + +import pyversioncheck + +_PACKAGE="versioncheck" +_VERSION="1.0" +_URL="http://www.cwi.nl/~jack/versioncheck/curversion.txt" + +try: + _myverbose=VERBOSE +except NameError: + _myverbose=1 + +pyversioncheck.versioncheck(_PACKAGE, _URL, _VERSION, verbose=_myverbose) diff --git a/sys/src/cmd/python/Tools/versioncheck/checkversions.py b/sys/src/cmd/python/Tools/versioncheck/checkversions.py new file mode 100644 index 000000000..fd128b600 --- /dev/null +++ b/sys/src/cmd/python/Tools/versioncheck/checkversions.py @@ -0,0 +1,52 @@ +"""Checkversions - recursively search a directory (default: sys.prefix) +for _checkversion.py files, and run each of them. This will tell you of +new versions available for any packages you have installed.""" + +import os +import getopt +import sys +import pyversioncheck + +CHECKNAME="_checkversion.py" + +VERBOSE=1 + +USAGE="""Usage: checkversions [-v verboselevel] [dir ...] +Recursively examine a tree (default: sys.prefix) and for each package +with a _checkversion.py file compare the installed version against the current +version. + +Values for verboselevel: +0 - Minimal output, one line per package +1 - Also print descriptions for outdated packages (default) +2 - Print information on each URL checked +3 - Check every URL for packages with multiple locations""" + +def check1dir(dummy, dir, files): + if CHECKNAME in files: + fullname = os.path.join(dir, CHECKNAME) + try: + execfile(fullname) + except: + print '** Exception in', fullname + +def walk1tree(tree): + os.path.walk(tree, check1dir, None) + +def main(): + global VERBOSE + try: + options, arguments = getopt.getopt(sys.argv[1:], 'v:') + except getopt.error: + print USAGE + sys.exit(1) + for o, a in options: + if o == '-v': + VERBOSE = int(a) + if not arguments: + arguments = [sys.prefix] + for dir in arguments: + walk1tree(dir) + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/versioncheck/pyversioncheck.py b/sys/src/cmd/python/Tools/versioncheck/pyversioncheck.py new file mode 100644 index 000000000..144665383 --- /dev/null +++ b/sys/src/cmd/python/Tools/versioncheck/pyversioncheck.py @@ -0,0 +1,98 @@ +"""pyversioncheck - Module to help with checking versions""" +import types +import rfc822 +import urllib +import sys + +# Verbose options +VERBOSE_SILENT=0 # Single-line reports per package +VERBOSE_NORMAL=1 # Single-line reports per package, more info if outdated +VERBOSE_EACHFILE=2 # Report on each URL checked +VERBOSE_CHECKALL=3 # Check each URL for each package + +# Test directory +## urllib bug: _TESTDIR="ftp://ftp.cwi.nl/pub/jack/python/versiontestdir/" +_TESTDIR="http://www.cwi.nl/~jack/versiontestdir/" + +def versioncheck(package, url, version, verbose=0): + ok, newversion, fp = checkonly(package, url, version, verbose) + if verbose > VERBOSE_NORMAL: + return ok + if ok < 0: + print '%s: No correctly formatted current version file found'%(package) + elif ok == 1: + print '%s: up-to-date (version %s)'%(package, version) + else: + print '%s: version %s installed, version %s found:' % \ + (package, version, newversion) + if verbose > VERBOSE_SILENT: + while 1: + line = fp.readline() + if not line: break + sys.stdout.write('\t'+line) + return ok + +def checkonly(package, url, version, verbose=0): + if verbose >= VERBOSE_EACHFILE: + print '%s:'%package + if type(url) == types.StringType: + ok, newversion, fp = _check1version(package, url, version, verbose) + else: + for u in url: + ok, newversion, fp = _check1version(package, u, version, verbose) + if ok >= 0 and verbose < VERBOSE_CHECKALL: + break + return ok, newversion, fp + +def _check1version(package, url, version, verbose=0): + if verbose >= VERBOSE_EACHFILE: + print ' Checking %s'%url + try: + fp = urllib.urlopen(url) + except IOError, arg: + if verbose >= VERBOSE_EACHFILE: + print ' Cannot open:', arg + return -1, None, None + msg = rfc822.Message(fp, seekable=0) + newversion = msg.getheader('current-version') + if not newversion: + if verbose >= VERBOSE_EACHFILE: + print ' No "Current-Version:" header in URL or URL not found' + return -1, None, None + version = version.lower().strip() + newversion = newversion.lower().strip() + if version == newversion: + if verbose >= VERBOSE_EACHFILE: + print ' Version identical (%s)'%newversion + return 1, version, fp + else: + if verbose >= VERBOSE_EACHFILE: + print ' Versions different (installed: %s, new: %s)'% \ + (version, newversion) + return 0, newversion, fp + + +def _test(): + print '--- TEST VERBOSE=1' + print '--- Testing existing and identical version file' + versioncheck('VersionTestPackage', _TESTDIR+'Version10.txt', '1.0', verbose=1) + print '--- Testing existing package with new version' + versioncheck('VersionTestPackage', _TESTDIR+'Version11.txt', '1.0', verbose=1) + print '--- Testing package with non-existing version file' + versioncheck('VersionTestPackage', _TESTDIR+'nonexistent.txt', '1.0', verbose=1) + print '--- Test package with 2 locations, first non-existing second ok' + versfiles = [_TESTDIR+'nonexistent.txt', _TESTDIR+'Version10.txt'] + versioncheck('VersionTestPackage', versfiles, '1.0', verbose=1) + print '--- TEST VERBOSE=2' + print '--- Testing existing and identical version file' + versioncheck('VersionTestPackage', _TESTDIR+'Version10.txt', '1.0', verbose=2) + print '--- Testing existing package with new version' + versioncheck('VersionTestPackage', _TESTDIR+'Version11.txt', '1.0', verbose=2) + print '--- Testing package with non-existing version file' + versioncheck('VersionTestPackage', _TESTDIR+'nonexistent.txt', '1.0', verbose=2) + print '--- Test package with 2 locations, first non-existing second ok' + versfiles = [_TESTDIR+'nonexistent.txt', _TESTDIR+'Version10.txt'] + versioncheck('VersionTestPackage', versfiles, '1.0', verbose=2) + +if __name__ == '__main__': + _test() diff --git a/sys/src/cmd/python/Tools/webchecker/README b/sys/src/cmd/python/Tools/webchecker/README new file mode 100644 index 000000000..a51bb3dd5 --- /dev/null +++ b/sys/src/cmd/python/Tools/webchecker/README @@ -0,0 +1,23 @@ +Webchecker +---------- + +This is a simple web tree checker, useful to find bad links in a web +tree. It currently checks links pointing within the same subweb for +validity. The main program is "webchecker.py". See its doc string +(or invoke it with the option "-?") for more defails. + +History: + +- Jan 1997. First release. The module robotparser.py was written by +Skip Montanaro; the rest is original work by Guido van Rossum. + +- May 1999. Sam Bayer contributed a new version, wcnew.py, which +supports checking internal links (#spam fragments in URLs) and some +other options. + +- Nov 1999. Sam Bayer contributed patches to reintegrate wcnew.py +into webchecker.py, and corresponding mods to wcgui.py and +websucker.py. + +- Mar 2004. Chris Herborth contributed a patch to let webchecker.py +handle XHTML's 'id' attribute. diff --git a/sys/src/cmd/python/Tools/webchecker/tktools.py b/sys/src/cmd/python/Tools/webchecker/tktools.py new file mode 100644 index 000000000..3a68f9ac6 --- /dev/null +++ b/sys/src/cmd/python/Tools/webchecker/tktools.py @@ -0,0 +1,366 @@ +"""Assorted Tk-related subroutines used in Grail.""" + + +from types import * +from Tkinter import * + +def _clear_entry_widget(event): + try: + widget = event.widget + widget.delete(0, INSERT) + except: pass +def install_keybindings(root): + root.bind_class('Entry', '<Control-u>', _clear_entry_widget) + + +def make_toplevel(master, title=None, class_=None): + """Create a Toplevel widget. + + This is a shortcut for a Toplevel() instantiation plus calls to + set the title and icon name of the widget. + + """ + + if class_: + widget = Toplevel(master, class_=class_) + else: + widget = Toplevel(master) + if title: + widget.title(title) + widget.iconname(title) + return widget + +def set_transient(widget, master, relx=0.5, rely=0.3, expose=1): + """Make an existing toplevel widget transient for a master. + + The widget must exist but should not yet have been placed; in + other words, this should be called after creating all the + subwidget but before letting the user interact. + """ + + widget.withdraw() # Remain invisible while we figure out the geometry + widget.transient(master) + widget.update_idletasks() # Actualize geometry information + if master.winfo_ismapped(): + m_width = master.winfo_width() + m_height = master.winfo_height() + m_x = master.winfo_rootx() + m_y = master.winfo_rooty() + else: + m_width = master.winfo_screenwidth() + m_height = master.winfo_screenheight() + m_x = m_y = 0 + w_width = widget.winfo_reqwidth() + w_height = widget.winfo_reqheight() + x = m_x + (m_width - w_width) * relx + y = m_y + (m_height - w_height) * rely + widget.geometry("+%d+%d" % (x, y)) + if expose: + widget.deiconify() # Become visible at the desired location + return widget + + +def make_scrollbars(parent, hbar, vbar, pack=1, class_=None, name=None, + takefocus=0): + + """Subroutine to create a frame with scrollbars. + + This is used by make_text_box and similar routines. + + Note: the caller is responsible for setting the x/y scroll command + properties (e.g. by calling set_scroll_commands()). + + Return a tuple containing the hbar, the vbar, and the frame, where + hbar and vbar are None if not requested. + + """ + if class_: + if name: frame = Frame(parent, class_=class_, name=name) + else: frame = Frame(parent, class_=class_) + else: + if name: frame = Frame(parent, name=name) + else: frame = Frame(parent) + + if pack: + frame.pack(fill=BOTH, expand=1) + + corner = None + if vbar: + if not hbar: + vbar = Scrollbar(frame, takefocus=takefocus) + vbar.pack(fill=Y, side=RIGHT) + else: + vbarframe = Frame(frame, borderwidth=0) + vbarframe.pack(fill=Y, side=RIGHT) + vbar = Scrollbar(frame, name="vbar", takefocus=takefocus) + vbar.pack(in_=vbarframe, expand=1, fill=Y, side=TOP) + sbwidth = vbar.winfo_reqwidth() + corner = Frame(vbarframe, width=sbwidth, height=sbwidth) + corner.propagate(0) + corner.pack(side=BOTTOM) + else: + vbar = None + + if hbar: + hbar = Scrollbar(frame, orient=HORIZONTAL, name="hbar", + takefocus=takefocus) + hbar.pack(fill=X, side=BOTTOM) + else: + hbar = None + + return hbar, vbar, frame + + +def set_scroll_commands(widget, hbar, vbar): + + """Link a scrollable widget to its scroll bars. + + The scroll bars may be empty. + + """ + + if vbar: + widget['yscrollcommand'] = (vbar, 'set') + vbar['command'] = (widget, 'yview') + + if hbar: + widget['xscrollcommand'] = (hbar, 'set') + hbar['command'] = (widget, 'xview') + + widget.vbar = vbar + widget.hbar = hbar + + +def make_text_box(parent, width=0, height=0, hbar=0, vbar=1, + fill=BOTH, expand=1, wrap=WORD, pack=1, + class_=None, name=None, takefocus=None): + + """Subroutine to create a text box. + + Create: + - a both-ways filling and expanding frame, containing: + - a text widget on the left, and + - possibly a vertical scroll bar on the right. + - possibly a horizonta; scroll bar at the bottom. + + Return the text widget and the frame widget. + + """ + hbar, vbar, frame = make_scrollbars(parent, hbar, vbar, pack, + class_=class_, name=name, + takefocus=takefocus) + + widget = Text(frame, wrap=wrap, name="text") + if width: widget.config(width=width) + if height: widget.config(height=height) + widget.pack(expand=expand, fill=fill, side=LEFT) + + set_scroll_commands(widget, hbar, vbar) + + return widget, frame + + +def make_list_box(parent, width=0, height=0, hbar=0, vbar=1, + fill=BOTH, expand=1, pack=1, class_=None, name=None, + takefocus=None): + + """Subroutine to create a list box. + + Like make_text_box(). + """ + hbar, vbar, frame = make_scrollbars(parent, hbar, vbar, pack, + class_=class_, name=name, + takefocus=takefocus) + + widget = Listbox(frame, name="listbox") + if width: widget.config(width=width) + if height: widget.config(height=height) + widget.pack(expand=expand, fill=fill, side=LEFT) + + set_scroll_commands(widget, hbar, vbar) + + return widget, frame + + +def make_canvas(parent, width=0, height=0, hbar=1, vbar=1, + fill=BOTH, expand=1, pack=1, class_=None, name=None, + takefocus=None): + + """Subroutine to create a canvas. + + Like make_text_box(). + + """ + + hbar, vbar, frame = make_scrollbars(parent, hbar, vbar, pack, + class_=class_, name=name, + takefocus=takefocus) + + widget = Canvas(frame, scrollregion=(0, 0, width, height), name="canvas") + if width: widget.config(width=width) + if height: widget.config(height=height) + widget.pack(expand=expand, fill=fill, side=LEFT) + + set_scroll_commands(widget, hbar, vbar) + + return widget, frame + + + +def make_form_entry(parent, label, borderwidth=None): + + """Subroutine to create a form entry. + + Create: + - a horizontally filling and expanding frame, containing: + - a label on the left, and + - a text entry on the right. + + Return the entry widget and the frame widget. + + """ + + frame = Frame(parent) + frame.pack(fill=X) + + label = Label(frame, text=label) + label.pack(side=LEFT) + + if borderwidth is None: + entry = Entry(frame, relief=SUNKEN) + else: + entry = Entry(frame, relief=SUNKEN, borderwidth=borderwidth) + entry.pack(side=LEFT, fill=X, expand=1) + + return entry, frame + +# This is a slightly modified version of the function above. This +# version does the proper alighnment of labels with their fields. It +# should probably eventually replace make_form_entry altogether. +# +# The one annoying bug is that the text entry field should be +# expandable while still aligning the colons. This doesn't work yet. +# +def make_labeled_form_entry(parent, label, entrywidth=20, entryheight=1, + labelwidth=0, borderwidth=None, + takefocus=None): + """Subroutine to create a form entry. + + Create: + - a horizontally filling and expanding frame, containing: + - a label on the left, and + - a text entry on the right. + + Return the entry widget and the frame widget. + """ + if label and label[-1] != ':': label = label + ':' + + frame = Frame(parent) + + label = Label(frame, text=label, width=labelwidth, anchor=E) + label.pack(side=LEFT) + if entryheight == 1: + if borderwidth is None: + entry = Entry(frame, relief=SUNKEN, width=entrywidth) + else: + entry = Entry(frame, relief=SUNKEN, width=entrywidth, + borderwidth=borderwidth) + entry.pack(side=RIGHT, expand=1, fill=X) + frame.pack(fill=X) + else: + entry = make_text_box(frame, entrywidth, entryheight, 1, 1, + takefocus=takefocus) + frame.pack(fill=BOTH, expand=1) + + return entry, frame, label + + +def make_double_frame(master=None, class_=None, name=None, relief=RAISED, + borderwidth=1): + """Create a pair of frames suitable for 'hosting' a dialog.""" + if name: + if class_: frame = Frame(master, class_=class_, name=name) + else: frame = Frame(master, name=name) + else: + if class_: frame = Frame(master, class_=class_) + else: frame = Frame(master) + top = Frame(frame, name="topframe", relief=relief, + borderwidth=borderwidth) + bottom = Frame(frame, name="bottomframe") + bottom.pack(fill=X, padx='1m', pady='1m', side=BOTTOM) + top.pack(expand=1, fill=BOTH, padx='1m', pady='1m') + frame.pack(expand=1, fill=BOTH) + top = Frame(top) + top.pack(expand=1, fill=BOTH, padx='2m', pady='2m') + + return frame, top, bottom + + +def make_group_frame(master, name=None, label=None, fill=Y, + side=None, expand=None, font=None): + """Create nested frames with a border and optional label. + + The outer frame is only used to provide the decorative border, to + control packing, and to host the label. The inner frame is packed + to fill the outer frame and should be used as the parent of all + sub-widgets. Only the inner frame is returned. + + """ + font = font or "-*-helvetica-medium-r-normal-*-*-100-*-*-*-*-*-*" + outer = Frame(master, borderwidth=2, relief=GROOVE) + outer.pack(expand=expand, fill=fill, side=side) + if label: + Label(outer, text=label, font=font, anchor=W).pack(fill=X) + inner = Frame(master, borderwidth='1m', name=name) + inner.pack(expand=1, fill=BOTH, in_=outer) + inner.forget = outer.forget + return inner + + +def unify_button_widths(*buttons): + """Make buttons passed in all have the same width. + + Works for labels and other widgets with the 'text' option. + + """ + wid = 0 + for btn in buttons: + wid = max(wid, len(btn["text"])) + for btn in buttons: + btn["width"] = wid + + +def flatten(msg): + """Turn a list or tuple into a single string -- recursively.""" + t = type(msg) + if t in (ListType, TupleType): + msg = ' '.join(map(flatten, msg)) + elif t is ClassType: + msg = msg.__name__ + else: + msg = str(msg) + return msg + + +def boolean(s): + """Test whether a string is a Tk boolean, without error checking.""" + if s.lower() in ('', '0', 'no', 'off', 'false'): return 0 + else: return 1 + + +def test(): + """Test make_text_box(), make_form_entry(), flatten(), boolean().""" + import sys + root = Tk() + entry, eframe = make_form_entry(root, 'Boolean:') + text, tframe = make_text_box(root) + def enter(event, entry=entry, text=text): + s = boolean(entry.get()) and '\nyes' or '\nno' + text.insert('end', s) + entry.bind('<Return>', enter) + entry.insert(END, flatten(sys.argv)) + root.mainloop() + + +if __name__ == '__main__': + test() diff --git a/sys/src/cmd/python/Tools/webchecker/wcgui.py b/sys/src/cmd/python/Tools/webchecker/wcgui.py new file mode 100755 index 000000000..96aed0a6b --- /dev/null +++ b/sys/src/cmd/python/Tools/webchecker/wcgui.py @@ -0,0 +1,463 @@ +#! /usr/bin/env python + +"""GUI interface to webchecker. + +This works as a Grail applet too! E.g. + + <APPLET CODE=wcgui.py NAME=CheckerWindow></APPLET> + +Checkpoints are not (yet??? ever???) supported. + +User interface: + +Enter a root to check in the text entry box. To enter more than one root, +enter them one at a time and press <Return> for each one. + +Command buttons Start, Stop and "Check one" govern the checking process in +the obvious way. Start and "Check one" also enter the root from the text +entry box if one is present. There's also a check box (enabled by default) +to decide whether actually to follow external links (since this can slow +the checking down considerably). Finally there's a Quit button. + +A series of checkbuttons determines whether the corresponding output panel +is shown. List panels are also automatically shown or hidden when their +status changes between empty to non-empty. There are six panels: + +Log -- raw output from the checker (-v, -q affect this) +To check -- links discovered but not yet checked +Checked -- links that have been checked +Bad links -- links that failed upon checking +Errors -- pages containing at least one bad link +Details -- details about one URL; double click on a URL in any of + the above list panels (not in Log) will show details + for that URL + +Use your window manager's Close command to quit. + +Command line options: + +-m bytes -- skip HTML pages larger than this size (default %(MAXPAGE)d) +-q -- quiet operation (also suppresses external links report) +-v -- verbose operation; repeating -v will increase verbosity +-t root -- specify root dir which should be treated as internal (can repeat) +-a -- don't check name anchors + +Command line arguments: + +rooturl -- URL to start checking + (default %(DEFROOT)s) + +XXX The command line options (-m, -q, -v) should be GUI accessible. + +XXX The roots should be visible as a list (?). + +XXX The multipanel user interface is clumsy. + +""" + +# ' Emacs bait + + +import sys +import getopt +from Tkinter import * +import tktools +import webchecker +import random + +# Override some for a weaker platform +if sys.platform == 'mac': + webchecker.DEFROOT = "http://grail.cnri.reston.va.us/" + webchecker.MAXPAGE = 50000 + webchecker.verbose = 4 + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], 't:m:qva') + except getopt.error, msg: + sys.stdout = sys.stderr + print msg + print __doc__%vars(webchecker) + sys.exit(2) + webchecker.verbose = webchecker.VERBOSE + webchecker.nonames = webchecker.NONAMES + webchecker.maxpage = webchecker.MAXPAGE + extra_roots = [] + for o, a in opts: + if o == '-m': + webchecker.maxpage = int(a) + if o == '-q': + webchecker.verbose = 0 + if o == '-v': + webchecker.verbose = webchecker.verbose + 1 + if o == '-t': + extra_roots.append(a) + if o == '-a': + webchecker.nonames = not webchecker.nonames + root = Tk(className='Webchecker') + root.protocol("WM_DELETE_WINDOW", root.quit) + c = CheckerWindow(root) + c.setflags(verbose=webchecker.verbose, maxpage=webchecker.maxpage, + nonames=webchecker.nonames) + if args: + for arg in args[:-1]: + c.addroot(arg) + c.suggestroot(args[-1]) + # Usually conditioned on whether external links + # will be checked, but since that's not a command + # line option, just toss them in. + for url_root in extra_roots: + # Make sure it's terminated by a slash, + # so that addroot doesn't discard the last + # directory component. + if url_root[-1] != "/": + url_root = url_root + "/" + c.addroot(url_root, add_to_do = 0) + root.mainloop() + + +class CheckerWindow(webchecker.Checker): + + def __init__(self, parent, root=webchecker.DEFROOT): + self.__parent = parent + + self.__topcontrols = Frame(parent) + self.__topcontrols.pack(side=TOP, fill=X) + self.__label = Label(self.__topcontrols, text="Root URL:") + self.__label.pack(side=LEFT) + self.__rootentry = Entry(self.__topcontrols, width=60) + self.__rootentry.pack(side=LEFT) + self.__rootentry.bind('<Return>', self.enterroot) + self.__rootentry.focus_set() + + self.__controls = Frame(parent) + self.__controls.pack(side=TOP, fill=X) + self.__running = 0 + self.__start = Button(self.__controls, text="Run", command=self.start) + self.__start.pack(side=LEFT) + self.__stop = Button(self.__controls, text="Stop", command=self.stop, + state=DISABLED) + self.__stop.pack(side=LEFT) + self.__step = Button(self.__controls, text="Check one", + command=self.step) + self.__step.pack(side=LEFT) + self.__cv = BooleanVar(parent) + self.__cv.set(self.checkext) + self.__checkext = Checkbutton(self.__controls, variable=self.__cv, + command=self.update_checkext, + text="Check nonlocal links",) + self.__checkext.pack(side=LEFT) + self.__reset = Button(self.__controls, text="Start over", command=self.reset) + self.__reset.pack(side=LEFT) + if __name__ == '__main__': # No Quit button under Grail! + self.__quit = Button(self.__controls, text="Quit", + command=self.__parent.quit) + self.__quit.pack(side=RIGHT) + + self.__status = Label(parent, text="Status: initial", anchor=W) + self.__status.pack(side=TOP, fill=X) + self.__checking = Label(parent, text="Idle", anchor=W) + self.__checking.pack(side=TOP, fill=X) + self.__mp = mp = MultiPanel(parent) + sys.stdout = self.__log = LogPanel(mp, "Log") + self.__todo = ListPanel(mp, "To check", self, self.showinfo) + self.__done = ListPanel(mp, "Checked", self, self.showinfo) + self.__bad = ListPanel(mp, "Bad links", self, self.showinfo) + self.__errors = ListPanel(mp, "Pages w/ bad links", self, self.showinfo) + self.__details = LogPanel(mp, "Details") + self.root_seed = None + webchecker.Checker.__init__(self) + if root: + root = str(root).strip() + if root: + self.suggestroot(root) + self.newstatus() + + def reset(self): + webchecker.Checker.reset(self) + for p in self.__todo, self.__done, self.__bad, self.__errors: + p.clear() + if self.root_seed: + self.suggestroot(self.root_seed) + + def suggestroot(self, root): + self.__rootentry.delete(0, END) + self.__rootentry.insert(END, root) + self.__rootentry.select_range(0, END) + self.root_seed = root + + def enterroot(self, event=None): + root = self.__rootentry.get() + root = root.strip() + if root: + self.__checking.config(text="Adding root "+root) + self.__checking.update_idletasks() + self.addroot(root) + self.__checking.config(text="Idle") + try: + i = self.__todo.items.index(root) + except (ValueError, IndexError): + pass + else: + self.__todo.list.select_clear(0, END) + self.__todo.list.select_set(i) + self.__todo.list.yview(i) + self.__rootentry.delete(0, END) + + def start(self): + self.__start.config(state=DISABLED, relief=SUNKEN) + self.__stop.config(state=NORMAL) + self.__step.config(state=DISABLED) + self.enterroot() + self.__running = 1 + self.go() + + def stop(self): + self.__stop.config(state=DISABLED, relief=SUNKEN) + self.__running = 0 + + def step(self): + self.__start.config(state=DISABLED) + self.__step.config(state=DISABLED, relief=SUNKEN) + self.enterroot() + self.__running = 0 + self.dosomething() + + def go(self): + if self.__running: + self.__parent.after_idle(self.dosomething) + else: + self.__checking.config(text="Idle") + self.__start.config(state=NORMAL, relief=RAISED) + self.__stop.config(state=DISABLED, relief=RAISED) + self.__step.config(state=NORMAL, relief=RAISED) + + __busy = 0 + + def dosomething(self): + if self.__busy: return + self.__busy = 1 + if self.todo: + l = self.__todo.selectedindices() + if l: + i = l[0] + else: + i = 0 + self.__todo.list.select_set(i) + self.__todo.list.yview(i) + url = self.__todo.items[i] + self.__checking.config(text="Checking "+self.format_url(url)) + self.__parent.update() + self.dopage(url) + else: + self.stop() + self.__busy = 0 + self.go() + + def showinfo(self, url): + d = self.__details + d.clear() + d.put("URL: %s\n" % self.format_url(url)) + if self.bad.has_key(url): + d.put("Error: %s\n" % str(self.bad[url])) + if url in self.roots: + d.put("Note: This is a root URL\n") + if self.done.has_key(url): + d.put("Status: checked\n") + o = self.done[url] + elif self.todo.has_key(url): + d.put("Status: to check\n") + o = self.todo[url] + else: + d.put("Status: unknown (!)\n") + o = [] + if (not url[1]) and self.errors.has_key(url[0]): + d.put("Bad links from this page:\n") + for triple in self.errors[url[0]]: + link, rawlink, msg = triple + d.put(" HREF %s" % self.format_url(link)) + if self.format_url(link) != rawlink: d.put(" (%s)" %rawlink) + d.put("\n") + d.put(" error %s\n" % str(msg)) + self.__mp.showpanel("Details") + for source, rawlink in o: + d.put("Origin: %s" % source) + if rawlink != self.format_url(url): + d.put(" (%s)" % rawlink) + d.put("\n") + d.text.yview("1.0") + + def setbad(self, url, msg): + webchecker.Checker.setbad(self, url, msg) + self.__bad.insert(url) + self.newstatus() + + def setgood(self, url): + webchecker.Checker.setgood(self, url) + self.__bad.remove(url) + self.newstatus() + + def newlink(self, url, origin): + webchecker.Checker.newlink(self, url, origin) + if self.done.has_key(url): + self.__done.insert(url) + elif self.todo.has_key(url): + self.__todo.insert(url) + self.newstatus() + + def markdone(self, url): + webchecker.Checker.markdone(self, url) + self.__done.insert(url) + self.__todo.remove(url) + self.newstatus() + + def seterror(self, url, triple): + webchecker.Checker.seterror(self, url, triple) + self.__errors.insert((url, '')) + self.newstatus() + + def newstatus(self): + self.__status.config(text="Status: "+self.status()) + self.__parent.update() + + def update_checkext(self): + self.checkext = self.__cv.get() + + +class ListPanel: + + def __init__(self, mp, name, checker, showinfo=None): + self.mp = mp + self.name = name + self.showinfo = showinfo + self.checker = checker + self.panel = mp.addpanel(name) + self.list, self.frame = tktools.make_list_box( + self.panel, width=60, height=5) + self.list.config(exportselection=0) + if showinfo: + self.list.bind('<Double-Button-1>', self.doubleclick) + self.items = [] + + def clear(self): + self.items = [] + self.list.delete(0, END) + self.mp.hidepanel(self.name) + + def doubleclick(self, event): + l = self.selectedindices() + if l: + self.showinfo(self.items[l[0]]) + + def selectedindices(self): + l = self.list.curselection() + if not l: return [] + return map(int, l) + + def insert(self, url): + if url not in self.items: + if not self.items: + self.mp.showpanel(self.name) + # (I tried sorting alphabetically, but the display is too jumpy) + i = len(self.items) + self.list.insert(i, self.checker.format_url(url)) + self.list.yview(i) + self.items.insert(i, url) + + def remove(self, url): + try: + i = self.items.index(url) + except (ValueError, IndexError): + pass + else: + was_selected = i in self.selectedindices() + self.list.delete(i) + del self.items[i] + if not self.items: + self.mp.hidepanel(self.name) + elif was_selected: + if i >= len(self.items): + i = len(self.items) - 1 + self.list.select_set(i) + + +class LogPanel: + + def __init__(self, mp, name): + self.mp = mp + self.name = name + self.panel = mp.addpanel(name) + self.text, self.frame = tktools.make_text_box(self.panel, height=10) + self.text.config(wrap=NONE) + + def clear(self): + self.text.delete("1.0", END) + self.text.yview("1.0") + + def put(self, s): + self.text.insert(END, s) + if '\n' in s: + self.text.yview(END) + + def write(self, s): + self.text.insert(END, s) + if '\n' in s: + self.text.yview(END) + self.panel.update() + + +class MultiPanel: + + def __init__(self, parent): + self.parent = parent + self.frame = Frame(self.parent) + self.frame.pack(expand=1, fill=BOTH) + self.topframe = Frame(self.frame, borderwidth=2, relief=RAISED) + self.topframe.pack(fill=X) + self.botframe = Frame(self.frame) + self.botframe.pack(expand=1, fill=BOTH) + self.panelnames = [] + self.panels = {} + + def addpanel(self, name, on=0): + v = StringVar(self.parent) + if on: + v.set(name) + else: + v.set("") + check = Checkbutton(self.topframe, text=name, + offvalue="", onvalue=name, variable=v, + command=self.checkpanel) + check.pack(side=LEFT) + panel = Frame(self.botframe) + label = Label(panel, text=name, borderwidth=2, relief=RAISED, anchor=W) + label.pack(side=TOP, fill=X) + t = v, check, panel + self.panelnames.append(name) + self.panels[name] = t + if on: + panel.pack(expand=1, fill=BOTH) + return panel + + def showpanel(self, name): + v, check, panel = self.panels[name] + v.set(name) + panel.pack(expand=1, fill=BOTH) + + def hidepanel(self, name): + v, check, panel = self.panels[name] + v.set("") + panel.pack_forget() + + def checkpanel(self): + for name in self.panelnames: + v, check, panel = self.panels[name] + panel.pack_forget() + for name in self.panelnames: + v, check, panel = self.panels[name] + if v.get(): + panel.pack(expand=1, fill=BOTH) + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/webchecker/wcmac.py b/sys/src/cmd/python/Tools/webchecker/wcmac.py new file mode 100644 index 000000000..9c8a19961 --- /dev/null +++ b/sys/src/cmd/python/Tools/webchecker/wcmac.py @@ -0,0 +1,7 @@ +import webchecker, sys +webchecker.DEFROOT = "http://www.python.org/python/" +webchecker.MAXPAGE = 50000 +webchecker.verbose = 2 +sys.argv.append('-x') +webchecker.main() +raw_input("\nCR to exit: ") diff --git a/sys/src/cmd/python/Tools/webchecker/webchecker.py b/sys/src/cmd/python/Tools/webchecker/webchecker.py new file mode 100755 index 000000000..b13084826 --- /dev/null +++ b/sys/src/cmd/python/Tools/webchecker/webchecker.py @@ -0,0 +1,892 @@ +#! /usr/bin/env python + +# Original code by Guido van Rossum; extensive changes by Sam Bayer, +# including code to check URL fragments. + +"""Web tree checker. + +This utility is handy to check a subweb of the world-wide web for +errors. A subweb is specified by giving one or more ``root URLs''; a +page belongs to the subweb if one of the root URLs is an initial +prefix of it. + +File URL extension: + +In order to easy the checking of subwebs via the local file system, +the interpretation of ``file:'' URLs is extended to mimic the behavior +of your average HTTP daemon: if a directory pathname is given, the +file index.html in that directory is returned if it exists, otherwise +a directory listing is returned. Now, you can point webchecker to the +document tree in the local file system of your HTTP daemon, and have +most of it checked. In fact the default works this way if your local +web tree is located at /usr/local/etc/httpd/htdpcs (the default for +the NCSA HTTP daemon and probably others). + +Report printed: + +When done, it reports pages with bad links within the subweb. When +interrupted, it reports for the pages that it has checked already. + +In verbose mode, additional messages are printed during the +information gathering phase. By default, it prints a summary of its +work status every 50 URLs (adjustable with the -r option), and it +reports errors as they are encountered. Use the -q option to disable +this output. + +Checkpoint feature: + +Whether interrupted or not, it dumps its state (a Python pickle) to a +checkpoint file and the -R option allows it to restart from the +checkpoint (assuming that the pages on the subweb that were already +processed haven't changed). Even when it has run till completion, -R +can still be useful -- it will print the reports again, and -Rq prints +the errors only. In this case, the checkpoint file is not written +again. The checkpoint file can be set with the -d option. + +The checkpoint file is written as a Python pickle. Remember that +Python's pickle module is currently quite slow. Give it the time it +needs to load and save the checkpoint file. When interrupted while +writing the checkpoint file, the old checkpoint file is not +overwritten, but all work done in the current run is lost. + +Miscellaneous: + +- You may find the (Tk-based) GUI version easier to use. See wcgui.py. + +- Webchecker honors the "robots.txt" convention. Thanks to Skip +Montanaro for his robotparser.py module (included in this directory)! +The agent name is hardwired to "webchecker". URLs that are disallowed +by the robots.txt file are reported as external URLs. + +- Because the SGML parser is a bit slow, very large SGML files are +skipped. The size limit can be set with the -m option. + +- When the server or protocol does not tell us a file's type, we guess +it based on the URL's suffix. The mimetypes.py module (also in this +directory) has a built-in table mapping most currently known suffixes, +and in addition attempts to read the mime.types configuration files in +the default locations of Netscape and the NCSA HTTP daemon. + +- We follow links indicated by <A>, <FRAME> and <IMG> tags. We also +honor the <BASE> tag. + +- We now check internal NAME anchor links, as well as toplevel links. + +- Checking external links is now done by default; use -x to *disable* +this feature. External links are now checked during normal +processing. (XXX The status of a checked link could be categorized +better. Later...) + +- If external links are not checked, you can use the -t flag to +provide specific overrides to -x. + +Usage: webchecker.py [option] ... [rooturl] ... + +Options: + +-R -- restart from checkpoint file +-d file -- checkpoint filename (default %(DUMPFILE)s) +-m bytes -- skip HTML pages larger than this size (default %(MAXPAGE)d) +-n -- reports only, no checking (use with -R) +-q -- quiet operation (also suppresses external links report) +-r number -- number of links processed per round (default %(ROUNDSIZE)d) +-t root -- specify root dir which should be treated as internal (can repeat) +-v -- verbose operation; repeating -v will increase verbosity +-x -- don't check external links (these are often slow to check) +-a -- don't check name anchors + +Arguments: + +rooturl -- URL to start checking + (default %(DEFROOT)s) + +""" + + +__version__ = "$Revision: 50851 $" + + +import sys +import os +from types import * +import StringIO +import getopt +import pickle + +import urllib +import urlparse +import sgmllib +import cgi + +import mimetypes +import robotparser + +# Extract real version number if necessary +if __version__[0] == '$': + _v = __version__.split() + if len(_v) == 3: + __version__ = _v[1] + + +# Tunable parameters +DEFROOT = "file:/usr/local/etc/httpd/htdocs/" # Default root URL +CHECKEXT = 1 # Check external references (1 deep) +VERBOSE = 1 # Verbosity level (0-3) +MAXPAGE = 150000 # Ignore files bigger than this +ROUNDSIZE = 50 # Number of links processed per round +DUMPFILE = "@webchecker.pickle" # Pickled checkpoint +AGENTNAME = "webchecker" # Agent name for robots.txt parser +NONAMES = 0 # Force name anchor checking + + +# Global variables + + +def main(): + checkext = CHECKEXT + verbose = VERBOSE + maxpage = MAXPAGE + roundsize = ROUNDSIZE + dumpfile = DUMPFILE + restart = 0 + norun = 0 + + try: + opts, args = getopt.getopt(sys.argv[1:], 'Rd:m:nqr:t:vxa') + except getopt.error, msg: + sys.stdout = sys.stderr + print msg + print __doc__%globals() + sys.exit(2) + + # The extra_roots variable collects extra roots. + extra_roots = [] + nonames = NONAMES + + for o, a in opts: + if o == '-R': + restart = 1 + if o == '-d': + dumpfile = a + if o == '-m': + maxpage = int(a) + if o == '-n': + norun = 1 + if o == '-q': + verbose = 0 + if o == '-r': + roundsize = int(a) + if o == '-t': + extra_roots.append(a) + if o == '-a': + nonames = not nonames + if o == '-v': + verbose = verbose + 1 + if o == '-x': + checkext = not checkext + + if verbose > 0: + print AGENTNAME, "version", __version__ + + if restart: + c = load_pickle(dumpfile=dumpfile, verbose=verbose) + else: + c = Checker() + + c.setflags(checkext=checkext, verbose=verbose, + maxpage=maxpage, roundsize=roundsize, + nonames=nonames + ) + + if not restart and not args: + args.append(DEFROOT) + + for arg in args: + c.addroot(arg) + + # The -t flag is only needed if external links are not to be + # checked. So -t values are ignored unless -x was specified. + if not checkext: + for root in extra_roots: + # Make sure it's terminated by a slash, + # so that addroot doesn't discard the last + # directory component. + if root[-1] != "/": + root = root + "/" + c.addroot(root, add_to_do = 0) + + try: + + if not norun: + try: + c.run() + except KeyboardInterrupt: + if verbose > 0: + print "[run interrupted]" + + try: + c.report() + except KeyboardInterrupt: + if verbose > 0: + print "[report interrupted]" + + finally: + if c.save_pickle(dumpfile): + if dumpfile == DUMPFILE: + print "Use ``%s -R'' to restart." % sys.argv[0] + else: + print "Use ``%s -R -d %s'' to restart." % (sys.argv[0], + dumpfile) + + +def load_pickle(dumpfile=DUMPFILE, verbose=VERBOSE): + if verbose > 0: + print "Loading checkpoint from %s ..." % dumpfile + f = open(dumpfile, "rb") + c = pickle.load(f) + f.close() + if verbose > 0: + print "Done." + print "Root:", "\n ".join(c.roots) + return c + + +class Checker: + + checkext = CHECKEXT + verbose = VERBOSE + maxpage = MAXPAGE + roundsize = ROUNDSIZE + nonames = NONAMES + + validflags = tuple(dir()) + + def __init__(self): + self.reset() + + def setflags(self, **kw): + for key in kw.keys(): + if key not in self.validflags: + raise NameError, "invalid keyword argument: %s" % str(key) + for key, value in kw.items(): + setattr(self, key, value) + + def reset(self): + self.roots = [] + self.todo = {} + self.done = {} + self.bad = {} + + # Add a name table, so that the name URLs can be checked. Also + # serves as an implicit cache for which URLs are done. + self.name_table = {} + + self.round = 0 + # The following are not pickled: + self.robots = {} + self.errors = {} + self.urlopener = MyURLopener() + self.changed = 0 + + def note(self, level, format, *args): + if self.verbose > level: + if args: + format = format%args + self.message(format) + + def message(self, format, *args): + if args: + format = format%args + print format + + def __getstate__(self): + return (self.roots, self.todo, self.done, self.bad, self.round) + + def __setstate__(self, state): + self.reset() + (self.roots, self.todo, self.done, self.bad, self.round) = state + for root in self.roots: + self.addrobot(root) + for url in self.bad.keys(): + self.markerror(url) + + def addroot(self, root, add_to_do = 1): + if root not in self.roots: + troot = root + scheme, netloc, path, params, query, fragment = \ + urlparse.urlparse(root) + i = path.rfind("/") + 1 + if 0 < i < len(path): + path = path[:i] + troot = urlparse.urlunparse((scheme, netloc, path, + params, query, fragment)) + self.roots.append(troot) + self.addrobot(root) + if add_to_do: + self.newlink((root, ""), ("<root>", root)) + + def addrobot(self, root): + root = urlparse.urljoin(root, "/") + if self.robots.has_key(root): return + url = urlparse.urljoin(root, "/robots.txt") + self.robots[root] = rp = robotparser.RobotFileParser() + self.note(2, "Parsing %s", url) + rp.debug = self.verbose > 3 + rp.set_url(url) + try: + rp.read() + except (OSError, IOError), msg: + self.note(1, "I/O error parsing %s: %s", url, msg) + + def run(self): + while self.todo: + self.round = self.round + 1 + self.note(0, "\nRound %d (%s)\n", self.round, self.status()) + urls = self.todo.keys() + urls.sort() + del urls[self.roundsize:] + for url in urls: + self.dopage(url) + + def status(self): + return "%d total, %d to do, %d done, %d bad" % ( + len(self.todo)+len(self.done), + len(self.todo), len(self.done), + len(self.bad)) + + def report(self): + self.message("") + if not self.todo: s = "Final" + else: s = "Interim" + self.message("%s Report (%s)", s, self.status()) + self.report_errors() + + def report_errors(self): + if not self.bad: + self.message("\nNo errors") + return + self.message("\nError Report:") + sources = self.errors.keys() + sources.sort() + for source in sources: + triples = self.errors[source] + self.message("") + if len(triples) > 1: + self.message("%d Errors in %s", len(triples), source) + else: + self.message("Error in %s", source) + # Call self.format_url() instead of referring + # to the URL directly, since the URLs in these + # triples is now a (URL, fragment) pair. The value + # of the "source" variable comes from the list of + # origins, and is a URL, not a pair. + for url, rawlink, msg in triples: + if rawlink != self.format_url(url): s = " (%s)" % rawlink + else: s = "" + self.message(" HREF %s%s\n msg %s", + self.format_url(url), s, msg) + + def dopage(self, url_pair): + + # All printing of URLs uses format_url(); argument changed to + # url_pair for clarity. + if self.verbose > 1: + if self.verbose > 2: + self.show("Check ", self.format_url(url_pair), + " from", self.todo[url_pair]) + else: + self.message("Check %s", self.format_url(url_pair)) + url, local_fragment = url_pair + if local_fragment and self.nonames: + self.markdone(url_pair) + return + try: + page = self.getpage(url_pair) + except sgmllib.SGMLParseError, msg: + msg = self.sanitize(msg) + self.note(0, "Error parsing %s: %s", + self.format_url(url_pair), msg) + # Dont actually mark the URL as bad - it exists, just + # we can't parse it! + page = None + if page: + # Store the page which corresponds to this URL. + self.name_table[url] = page + # If there is a fragment in this url_pair, and it's not + # in the list of names for the page, call setbad(), since + # it's a missing anchor. + if local_fragment and local_fragment not in page.getnames(): + self.setbad(url_pair, ("Missing name anchor `%s'" % local_fragment)) + for info in page.getlinkinfos(): + # getlinkinfos() now returns the fragment as well, + # and we store that fragment here in the "todo" dictionary. + link, rawlink, fragment = info + # However, we don't want the fragment as the origin, since + # the origin is logically a page. + origin = url, rawlink + self.newlink((link, fragment), origin) + else: + # If no page has been created yet, we want to + # record that fact. + self.name_table[url_pair[0]] = None + self.markdone(url_pair) + + def newlink(self, url, origin): + if self.done.has_key(url): + self.newdonelink(url, origin) + else: + self.newtodolink(url, origin) + + def newdonelink(self, url, origin): + if origin not in self.done[url]: + self.done[url].append(origin) + + # Call self.format_url(), since the URL here + # is now a (URL, fragment) pair. + self.note(3, " Done link %s", self.format_url(url)) + + # Make sure that if it's bad, that the origin gets added. + if self.bad.has_key(url): + source, rawlink = origin + triple = url, rawlink, self.bad[url] + self.seterror(source, triple) + + def newtodolink(self, url, origin): + # Call self.format_url(), since the URL here + # is now a (URL, fragment) pair. + if self.todo.has_key(url): + if origin not in self.todo[url]: + self.todo[url].append(origin) + self.note(3, " Seen todo link %s", self.format_url(url)) + else: + self.todo[url] = [origin] + self.note(3, " New todo link %s", self.format_url(url)) + + def format_url(self, url): + link, fragment = url + if fragment: return link + "#" + fragment + else: return link + + def markdone(self, url): + self.done[url] = self.todo[url] + del self.todo[url] + self.changed = 1 + + def inroots(self, url): + for root in self.roots: + if url[:len(root)] == root: + return self.isallowed(root, url) + return 0 + + def isallowed(self, root, url): + root = urlparse.urljoin(root, "/") + return self.robots[root].can_fetch(AGENTNAME, url) + + def getpage(self, url_pair): + # Incoming argument name is a (URL, fragment) pair. + # The page may have been cached in the name_table variable. + url, fragment = url_pair + if self.name_table.has_key(url): + return self.name_table[url] + + scheme, path = urllib.splittype(url) + if scheme in ('mailto', 'news', 'javascript', 'telnet'): + self.note(1, " Not checking %s URL" % scheme) + return None + isint = self.inroots(url) + + # Ensure that openpage gets the URL pair to + # print out its error message and record the error pair + # correctly. + if not isint: + if not self.checkext: + self.note(1, " Not checking ext link") + return None + f = self.openpage(url_pair) + if f: + self.safeclose(f) + return None + text, nurl = self.readhtml(url_pair) + + if nurl != url: + self.note(1, " Redirected to %s", nurl) + url = nurl + if text: + return Page(text, url, maxpage=self.maxpage, checker=self) + + # These next three functions take (URL, fragment) pairs as + # arguments, so that openpage() receives the appropriate tuple to + # record error messages. + def readhtml(self, url_pair): + url, fragment = url_pair + text = None + f, url = self.openhtml(url_pair) + if f: + text = f.read() + f.close() + return text, url + + def openhtml(self, url_pair): + url, fragment = url_pair + f = self.openpage(url_pair) + if f: + url = f.geturl() + info = f.info() + if not self.checkforhtml(info, url): + self.safeclose(f) + f = None + return f, url + + def openpage(self, url_pair): + url, fragment = url_pair + try: + return self.urlopener.open(url) + except (OSError, IOError), msg: + msg = self.sanitize(msg) + self.note(0, "Error %s", msg) + if self.verbose > 0: + self.show(" HREF ", url, " from", self.todo[url_pair]) + self.setbad(url_pair, msg) + return None + + def checkforhtml(self, info, url): + if info.has_key('content-type'): + ctype = cgi.parse_header(info['content-type'])[0].lower() + if ';' in ctype: + # handle content-type: text/html; charset=iso8859-1 : + ctype = ctype.split(';', 1)[0].strip() + else: + if url[-1:] == "/": + return 1 + ctype, encoding = mimetypes.guess_type(url) + if ctype == 'text/html': + return 1 + else: + self.note(1, " Not HTML, mime type %s", ctype) + return 0 + + def setgood(self, url): + if self.bad.has_key(url): + del self.bad[url] + self.changed = 1 + self.note(0, "(Clear previously seen error)") + + def setbad(self, url, msg): + if self.bad.has_key(url) and self.bad[url] == msg: + self.note(0, "(Seen this error before)") + return + self.bad[url] = msg + self.changed = 1 + self.markerror(url) + + def markerror(self, url): + try: + origins = self.todo[url] + except KeyError: + origins = self.done[url] + for source, rawlink in origins: + triple = url, rawlink, self.bad[url] + self.seterror(source, triple) + + def seterror(self, url, triple): + try: + # Because of the way the URLs are now processed, I need to + # check to make sure the URL hasn't been entered in the + # error list. The first element of the triple here is a + # (URL, fragment) pair, but the URL key is not, since it's + # from the list of origins. + if triple not in self.errors[url]: + self.errors[url].append(triple) + except KeyError: + self.errors[url] = [triple] + + # The following used to be toplevel functions; they have been + # changed into methods so they can be overridden in subclasses. + + def show(self, p1, link, p2, origins): + self.message("%s %s", p1, link) + i = 0 + for source, rawlink in origins: + i = i+1 + if i == 2: + p2 = ' '*len(p2) + if rawlink != link: s = " (%s)" % rawlink + else: s = "" + self.message("%s %s%s", p2, source, s) + + def sanitize(self, msg): + if isinstance(IOError, ClassType) and isinstance(msg, IOError): + # Do the other branch recursively + msg.args = self.sanitize(msg.args) + elif isinstance(msg, TupleType): + if len(msg) >= 4 and msg[0] == 'http error' and \ + isinstance(msg[3], InstanceType): + # Remove the Message instance -- it may contain + # a file object which prevents pickling. + msg = msg[:3] + msg[4:] + return msg + + def safeclose(self, f): + try: + url = f.geturl() + except AttributeError: + pass + else: + if url[:4] == 'ftp:' or url[:7] == 'file://': + # Apparently ftp connections don't like to be closed + # prematurely... + text = f.read() + f.close() + + def save_pickle(self, dumpfile=DUMPFILE): + if not self.changed: + self.note(0, "\nNo need to save checkpoint") + elif not dumpfile: + self.note(0, "No dumpfile, won't save checkpoint") + else: + self.note(0, "\nSaving checkpoint to %s ...", dumpfile) + newfile = dumpfile + ".new" + f = open(newfile, "wb") + pickle.dump(self, f) + f.close() + try: + os.unlink(dumpfile) + except os.error: + pass + os.rename(newfile, dumpfile) + self.note(0, "Done.") + return 1 + + +class Page: + + def __init__(self, text, url, verbose=VERBOSE, maxpage=MAXPAGE, checker=None): + self.text = text + self.url = url + self.verbose = verbose + self.maxpage = maxpage + self.checker = checker + + # The parsing of the page is done in the __init__() routine in + # order to initialize the list of names the file + # contains. Stored the parser in an instance variable. Passed + # the URL to MyHTMLParser(). + size = len(self.text) + if size > self.maxpage: + self.note(0, "Skip huge file %s (%.0f Kbytes)", self.url, (size*0.001)) + self.parser = None + return + self.checker.note(2, " Parsing %s (%d bytes)", self.url, size) + self.parser = MyHTMLParser(url, verbose=self.verbose, + checker=self.checker) + self.parser.feed(self.text) + self.parser.close() + + def note(self, level, msg, *args): + if self.checker: + apply(self.checker.note, (level, msg) + args) + else: + if self.verbose >= level: + if args: + msg = msg%args + print msg + + # Method to retrieve names. + def getnames(self): + if self.parser: + return self.parser.names + else: + return [] + + def getlinkinfos(self): + # File reading is done in __init__() routine. Store parser in + # local variable to indicate success of parsing. + + # If no parser was stored, fail. + if not self.parser: return [] + + rawlinks = self.parser.getlinks() + base = urlparse.urljoin(self.url, self.parser.getbase() or "") + infos = [] + for rawlink in rawlinks: + t = urlparse.urlparse(rawlink) + # DON'T DISCARD THE FRAGMENT! Instead, include + # it in the tuples which are returned. See Checker.dopage(). + fragment = t[-1] + t = t[:-1] + ('',) + rawlink = urlparse.urlunparse(t) + link = urlparse.urljoin(base, rawlink) + infos.append((link, rawlink, fragment)) + + return infos + + +class MyStringIO(StringIO.StringIO): + + def __init__(self, url, info): + self.__url = url + self.__info = info + StringIO.StringIO.__init__(self) + + def info(self): + return self.__info + + def geturl(self): + return self.__url + + +class MyURLopener(urllib.FancyURLopener): + + http_error_default = urllib.URLopener.http_error_default + + def __init__(*args): + self = args[0] + apply(urllib.FancyURLopener.__init__, args) + self.addheaders = [ + ('User-agent', 'Python-webchecker/%s' % __version__), + ] + + def http_error_401(self, url, fp, errcode, errmsg, headers): + return None + + def open_file(self, url): + path = urllib.url2pathname(urllib.unquote(url)) + if os.path.isdir(path): + if path[-1] != os.sep: + url = url + '/' + indexpath = os.path.join(path, "index.html") + if os.path.exists(indexpath): + return self.open_file(url + "index.html") + try: + names = os.listdir(path) + except os.error, msg: + exc_type, exc_value, exc_tb = sys.exc_info() + raise IOError, msg, exc_tb + names.sort() + s = MyStringIO("file:"+url, {'content-type': 'text/html'}) + s.write('<BASE HREF="file:%s">\n' % + urllib.quote(os.path.join(path, ""))) + for name in names: + q = urllib.quote(name) + s.write('<A HREF="%s">%s</A>\n' % (q, q)) + s.seek(0) + return s + return urllib.FancyURLopener.open_file(self, url) + + +class MyHTMLParser(sgmllib.SGMLParser): + + def __init__(self, url, verbose=VERBOSE, checker=None): + self.myverbose = verbose # now unused + self.checker = checker + self.base = None + self.links = {} + self.names = [] + self.url = url + sgmllib.SGMLParser.__init__(self) + + def check_name_id(self, attributes): + """ Check the name or id attributes on an element. + """ + # We must rescue the NAME or id (name is deprecated in XHTML) + # attributes from the anchor, in order to + # cache the internal anchors which are made + # available in the page. + for name, value in attributes: + if name == "name" or name == "id": + if value in self.names: + self.checker.message("WARNING: duplicate ID name %s in %s", + value, self.url) + else: self.names.append(value) + break + + def unknown_starttag(self, tag, attributes): + """ In XHTML, you can have id attributes on any element. + """ + self.check_name_id(attributes) + + def start_a(self, attributes): + self.link_attr(attributes, 'href') + self.check_name_id(attributes) + + def end_a(self): pass + + def do_area(self, attributes): + self.link_attr(attributes, 'href') + self.check_name_id(attributes) + + def do_body(self, attributes): + self.link_attr(attributes, 'background', 'bgsound') + self.check_name_id(attributes) + + def do_img(self, attributes): + self.link_attr(attributes, 'src', 'lowsrc') + self.check_name_id(attributes) + + def do_frame(self, attributes): + self.link_attr(attributes, 'src', 'longdesc') + self.check_name_id(attributes) + + def do_iframe(self, attributes): + self.link_attr(attributes, 'src', 'longdesc') + self.check_name_id(attributes) + + def do_link(self, attributes): + for name, value in attributes: + if name == "rel": + parts = value.lower().split() + if ( parts == ["stylesheet"] + or parts == ["alternate", "stylesheet"]): + self.link_attr(attributes, "href") + break + self.check_name_id(attributes) + + def do_object(self, attributes): + self.link_attr(attributes, 'data', 'usemap') + self.check_name_id(attributes) + + def do_script(self, attributes): + self.link_attr(attributes, 'src') + self.check_name_id(attributes) + + def do_table(self, attributes): + self.link_attr(attributes, 'background') + self.check_name_id(attributes) + + def do_td(self, attributes): + self.link_attr(attributes, 'background') + self.check_name_id(attributes) + + def do_th(self, attributes): + self.link_attr(attributes, 'background') + self.check_name_id(attributes) + + def do_tr(self, attributes): + self.link_attr(attributes, 'background') + self.check_name_id(attributes) + + def link_attr(self, attributes, *args): + for name, value in attributes: + if name in args: + if value: value = value.strip() + if value: self.links[value] = None + + def do_base(self, attributes): + for name, value in attributes: + if name == 'href': + if value: value = value.strip() + if value: + if self.checker: + self.checker.note(1, " Base %s", value) + self.base = value + self.check_name_id(attributes) + + def getlinks(self): + return self.links.keys() + + def getbase(self): + return self.base + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/webchecker/websucker.py b/sys/src/cmd/python/Tools/webchecker/websucker.py new file mode 100755 index 000000000..fdbf28869 --- /dev/null +++ b/sys/src/cmd/python/Tools/webchecker/websucker.py @@ -0,0 +1,125 @@ +#! /usr/bin/env python + +"""A variant on webchecker that creates a mirror copy of a remote site.""" + +__version__ = "$Revision: 28654 $" + +import os +import sys +import urllib +import getopt + +import webchecker + +# Extract real version number if necessary +if __version__[0] == '$': + _v = __version__.split() + if len(_v) == 3: + __version__ = _v[1] + +def main(): + verbose = webchecker.VERBOSE + try: + opts, args = getopt.getopt(sys.argv[1:], "qv") + except getopt.error, msg: + print msg + print "usage:", sys.argv[0], "[-qv] ... [rooturl] ..." + return 2 + for o, a in opts: + if o == "-q": + verbose = 0 + if o == "-v": + verbose = verbose + 1 + c = Sucker() + c.setflags(verbose=verbose) + c.urlopener.addheaders = [ + ('User-agent', 'websucker/%s' % __version__), + ] + for arg in args: + print "Adding root", arg + c.addroot(arg) + print "Run..." + c.run() + +class Sucker(webchecker.Checker): + + checkext = 0 + nonames = 1 + + # SAM 11/13/99: in general, URLs are now URL pairs. + # Since we've suppressed name anchor checking, + # we can ignore the second dimension. + + def readhtml(self, url_pair): + url = url_pair[0] + text = None + path = self.savefilename(url) + try: + f = open(path, "rb") + except IOError: + f = self.openpage(url_pair) + if f: + info = f.info() + nurl = f.geturl() + if nurl != url: + url = nurl + path = self.savefilename(url) + text = f.read() + f.close() + self.savefile(text, path) + if not self.checkforhtml(info, url): + text = None + else: + if self.checkforhtml({}, url): + text = f.read() + f.close() + return text, url + + def savefile(self, text, path): + dir, base = os.path.split(path) + makedirs(dir) + try: + f = open(path, "wb") + f.write(text) + f.close() + self.message("saved %s", path) + except IOError, msg: + self.message("didn't save %s: %s", path, str(msg)) + + def savefilename(self, url): + type, rest = urllib.splittype(url) + host, path = urllib.splithost(rest) + path = path.lstrip("/") + user, host = urllib.splituser(host) + host, port = urllib.splitnport(host) + host = host.lower() + if not path or path[-1] == "/": + path = path + "index.html" + if os.sep != "/": + path = os.sep.join(path.split("/")) + if os.name == "mac": + path = os.sep + path + path = os.path.join(host, path) + return path + +def makedirs(dir): + if not dir: + return + if os.path.exists(dir): + if not os.path.isdir(dir): + try: + os.rename(dir, dir + ".bak") + os.mkdir(dir) + os.rename(dir + ".bak", os.path.join(dir, "index.html")) + except os.error: + pass + return + head, tail = os.path.split(dir) + if not tail: + print "Huh? Don't know how to make dir", dir + return + makedirs(head) + os.mkdir(dir, 0777) + +if __name__ == '__main__': + sys.exit(main() or 0) diff --git a/sys/src/cmd/python/Tools/webchecker/wsgui.py b/sys/src/cmd/python/Tools/webchecker/wsgui.py new file mode 100755 index 000000000..0c851ca5d --- /dev/null +++ b/sys/src/cmd/python/Tools/webchecker/wsgui.py @@ -0,0 +1,242 @@ +#! /usr/bin/env python + +"""Tkinter-based GUI for websucker. + +Easy use: type or paste source URL and destination directory in +their respective text boxes, click GO or hit return, and presto. +""" + +from Tkinter import * +import Tkinter +import websucker +import sys +import os +import threading +import Queue +import time + +VERBOSE = 2 + + +try: + class Canceled(Exception): + "Exception used to cancel run()." +except (NameError, TypeError): + Canceled = __name__ + ".Canceled" + + +class SuckerThread(websucker.Sucker): + + stopit = 0 + savedir = None + rootdir = None + + def __init__(self, msgq): + self.msgq = msgq + websucker.Sucker.__init__(self) + self.setflags(verbose=VERBOSE) + self.urlopener.addheaders = [ + ('User-agent', 'websucker/%s' % websucker.__version__), + ] + + def message(self, format, *args): + if args: + format = format%args + ##print format + self.msgq.put(format) + + def run1(self, url): + try: + try: + self.reset() + self.addroot(url) + self.run() + except Canceled: + self.message("[canceled]") + else: + self.message("[done]") + finally: + self.msgq.put(None) + + def savefile(self, text, path): + if self.stopit: + raise Canceled + websucker.Sucker.savefile(self, text, path) + + def getpage(self, url): + if self.stopit: + raise Canceled + return websucker.Sucker.getpage(self, url) + + def savefilename(self, url): + path = websucker.Sucker.savefilename(self, url) + if self.savedir: + n = len(self.rootdir) + if path[:n] == self.rootdir: + path = path[n:] + while path[:1] == os.sep: + path = path[1:] + path = os.path.join(self.savedir, path) + return path + + def XXXaddrobot(self, *args): + pass + + def XXXisallowed(self, *args): + return 1 + + +class App: + + sucker = None + msgq = None + + def __init__(self, top): + self.top = top + top.columnconfigure(99, weight=1) + self.url_label = Label(top, text="URL:") + self.url_label.grid(row=0, column=0, sticky='e') + self.url_entry = Entry(top, width=60, exportselection=0) + self.url_entry.grid(row=0, column=1, sticky='we', + columnspan=99) + self.url_entry.focus_set() + self.url_entry.bind("<Key-Return>", self.go) + self.dir_label = Label(top, text="Directory:") + self.dir_label.grid(row=1, column=0, sticky='e') + self.dir_entry = Entry(top) + self.dir_entry.grid(row=1, column=1, sticky='we', + columnspan=99) + self.go_button = Button(top, text="Go", command=self.go) + self.go_button.grid(row=2, column=1, sticky='w') + self.cancel_button = Button(top, text="Cancel", + command=self.cancel, + state=DISABLED) + self.cancel_button.grid(row=2, column=2, sticky='w') + self.auto_button = Button(top, text="Paste+Go", + command=self.auto) + self.auto_button.grid(row=2, column=3, sticky='w') + self.status_label = Label(top, text="[idle]") + self.status_label.grid(row=2, column=4, sticky='w') + self.top.update_idletasks() + self.top.grid_propagate(0) + + def message(self, text, *args): + if args: + text = text % args + self.status_label.config(text=text) + + def check_msgq(self): + while not self.msgq.empty(): + msg = self.msgq.get() + if msg is None: + self.go_button.configure(state=NORMAL) + self.auto_button.configure(state=NORMAL) + self.cancel_button.configure(state=DISABLED) + if self.sucker: + self.sucker.stopit = 0 + self.top.bell() + else: + self.message(msg) + self.top.after(100, self.check_msgq) + + def go(self, event=None): + if not self.msgq: + self.msgq = Queue.Queue(0) + self.check_msgq() + if not self.sucker: + self.sucker = SuckerThread(self.msgq) + if self.sucker.stopit: + return + self.url_entry.selection_range(0, END) + url = self.url_entry.get() + url = url.strip() + if not url: + self.top.bell() + self.message("[Error: No URL entered]") + return + self.rooturl = url + dir = self.dir_entry.get().strip() + if not dir: + self.sucker.savedir = None + else: + self.sucker.savedir = dir + self.sucker.rootdir = os.path.dirname( + websucker.Sucker.savefilename(self.sucker, url)) + self.go_button.configure(state=DISABLED) + self.auto_button.configure(state=DISABLED) + self.cancel_button.configure(state=NORMAL) + self.message( '[running...]') + self.sucker.stopit = 0 + t = threading.Thread(target=self.sucker.run1, args=(url,)) + t.start() + + def cancel(self): + if self.sucker: + self.sucker.stopit = 1 + self.message("[canceling...]") + + def auto(self): + tries = ['PRIMARY', 'CLIPBOARD'] + text = "" + for t in tries: + try: + text = self.top.selection_get(selection=t) + except TclError: + continue + text = text.strip() + if text: + break + if not text: + self.top.bell() + self.message("[Error: clipboard is empty]") + return + self.url_entry.delete(0, END) + self.url_entry.insert(0, text) + self.go() + + +class AppArray: + + def __init__(self, top=None): + if not top: + top = Tk() + top.title("websucker GUI") + top.iconname("wsgui") + top.wm_protocol('WM_DELETE_WINDOW', self.exit) + self.top = top + self.appframe = Frame(self.top) + self.appframe.pack(fill='both') + self.applist = [] + self.exit_button = Button(top, text="Exit", command=self.exit) + self.exit_button.pack(side=RIGHT) + self.new_button = Button(top, text="New", command=self.addsucker) + self.new_button.pack(side=LEFT) + self.addsucker() + ##self.applist[0].url_entry.insert(END, "http://www.python.org/doc/essays/") + + def addsucker(self): + self.top.geometry("") + frame = Frame(self.appframe, borderwidth=2, relief=GROOVE) + frame.pack(fill='x') + app = App(frame) + self.applist.append(app) + + done = 0 + + def mainloop(self): + while not self.done: + time.sleep(0.1) + self.top.update() + + def exit(self): + for app in self.applist: + app.cancel() + app.message("[exiting...]") + self.done = 1 + + +def main(): + AppArray().mainloop() + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/Tools/world/README b/sys/src/cmd/python/Tools/world/README new file mode 100644 index 000000000..f7bb61021 --- /dev/null +++ b/sys/src/cmd/python/Tools/world/README @@ -0,0 +1,85 @@ +world -- Print mappings between country names and DNS country codes. + +Contact: Barry Warsaw +Email: bwarsaw@python.org + +This script will take a list of Internet addresses and print out where in the +world those addresses originate from, based on the top-level domain country +code found in the address. Addresses can be in any of the following forms: + + xx -- just the country code or top-level domain identifier + host.domain.xx -- any Internet host or network name + somebody@where.xx -- an Internet email address + +If no match is found, the address is interpreted as a regular expression [*] +and a reverse lookup is attempted. This script will search the country names +and print a list of matching entries. You can force reverse mappings with the +`-r' flag (see below). + +For example: + + %% world tz us + tz originated from Tanzania, United Republic of + us originated from United States + + %% world united + united matches 6 countries: + ae: United Arab Emirates + uk: United Kingdom (common practice) + um: United States Minor Outlying Islands + us: United States + tz: Tanzania, United Republic of + gb: United Kingdom + + + [*] Note that regular expressions must conform to Python 1.5's re.py module + syntax. The comparison is done with the search() method. + +Country codes are maintained by the RIPE Network Coordination Centre, +in coordination with the ISO 3166 Maintenance Agency at DIN Berlin. The +authoritative source of counry code mappings is: + + <url:ftp://info.ripe.net/iso3166-countrycodes> + +The latest known change to this information was: + + Thu Aug 7 17:59:51 MET DST 1997 + +This script also knows about non-geographic top-level domains. + +Usage: world [-d] [-p file] [-o] [-h] addr [addr ...] + + --dump + -d + Print mapping of all top-level domains. + + --parse file + -p file + Parse an iso3166-countrycodes file extracting the two letter country + code followed by the country name. Note that the three letter country + codes and numbers, which are also provided in the standard format + file, are ignored. + + --outputdict + -o + When used in conjunction with the `-p' option, output is in the form + of a Python dictionary, and country names are normalized + w.r.t. capitalization. This makes it appropriate for cutting and + pasting back into this file. + + --reverse + -r + Force reverse lookup. In this mode the address can be any Python + regular expression; this is matched against all country names and a + list of matching mappings is printed. In normal mode (e.g. without + this flag), reverse lookup is performed on addresses if no matching + country code is found. + + -h + --help + Print this message. + + +Local Variables: +indent-tabs-mode: nil +End: diff --git a/sys/src/cmd/python/Tools/world/world b/sys/src/cmd/python/Tools/world/world new file mode 100755 index 000000000..fb5147aeb --- /dev/null +++ b/sys/src/cmd/python/Tools/world/world @@ -0,0 +1,551 @@ +#! /usr/bin/env python + +"""world -- Print mappings between country names and DNS country codes. + +Contact: Barry Warsaw +Email: barry@python.org +Version: %(__version__)s + +This script will take a list of Internet addresses and print out where in the +world those addresses originate from, based on the top-level domain country +code found in the address. Addresses can be in any of the following forms: + + xx -- just the country code or top-level domain identifier + host.domain.xx -- any Internet host or network name + somebody@where.xx -- an Internet email address + +If no match is found, the address is interpreted as a regular expression and a +reverse lookup is attempted. This script will search the country names and +print a list of matching entries. You can force reverse mappings with the +`-r' flag (see below). + +For example: + + %% world tz us + tz originated from Tanzania, United Republic of + us originated from United States + + %% world united + united matches 6 countries: + ae: United Arab Emirates + uk: United Kingdom (common practice) + um: United States Minor Outlying Islands + us: United States + tz: Tanzania, United Republic of + gb: United Kingdom + +Country codes are maintained by the RIPE Network Coordination Centre, +in coordination with the ISO 3166 Maintenance Agency at DIN Berlin. The +authoritative source of country code mappings is: + + <url:ftp://ftp.ripe.net/iso3166-countrycodes.txt> + +The latest known change to this information was: + + Friday, 5 April 2002, 12.00 CET 2002 + +This script also knows about non-geographic top-level domains, and the +additional ccTLDs reserved by IANA. + +Usage: %(PROGRAM)s [-d] [-p file] [-o] [-h] addr [addr ...] + + --dump + -d + Print mapping of all top-level domains. + + --parse file + -p file + Parse an iso3166-countrycodes file extracting the two letter country + code followed by the country name. Note that the three letter country + codes and numbers, which are also provided in the standard format + file, are ignored. + + --outputdict + -o + When used in conjunction with the `-p' option, output is in the form + of a Python dictionary, and country names are normalized + w.r.t. capitalization. This makes it appropriate for cutting and + pasting back into this file. Output is always to standard out. + + --reverse + -r + Force reverse lookup. In this mode the address can be any Python + regular expression; this is matched against all country names and a + list of matching mappings is printed. In normal mode (e.g. without + this flag), reverse lookup is performed on addresses if no matching + country code is found. + + -h + --help + Print this message. +""" +__version__ = '$Revision: 27624 $' + + +import sys +import getopt +import re + +PROGRAM = sys.argv[0] + + + +def usage(code, msg=''): + print __doc__ % globals() + if msg: + print msg + sys.exit(code) + + + +def resolve(rawaddr): + parts = rawaddr.split('.') + if not len(parts): + # no top level domain found, bounce it to the next step + return rawaddr + addr = parts[-1] + if nameorgs.has_key(addr): + print rawaddr, 'is in the', nameorgs[addr], 'top level domain' + return None + elif countries.has_key(addr): + print rawaddr, 'originated from', countries[addr] + return None + else: + # Not resolved, bounce it to the next step + return rawaddr + + + +def reverse(regexp): + matches = [] + cre = re.compile(regexp, re.IGNORECASE) + for code, country in all.items(): + mo = cre.search(country) + if mo: + matches.append(code) + # print results + if not matches: + # not resolved, bounce it to the next step + return regexp + if len(matches) == 1: + code = matches[0] + print regexp, "matches code `%s', %s" % (code, all[code]) + else: + print regexp, 'matches %d countries:' % len(matches) + for code in matches: + print " %s: %s" % (code, all[code]) + return None + + + +def parse(file, normalize): + try: + fp = open(file) + except IOError, (err, msg): + print msg, ':', file + + cre = re.compile('(.*?)[ \t]+([A-Z]{2})[ \t]+[A-Z]{3}[ \t]+[0-9]{3}') + scanning = 0 + + if normalize: + print 'countries = {' + + while 1: + line = fp.readline() + if line == '': + break # EOF + if scanning: + mo = cre.match(line) + if not mo: + line = line.strip() + if not line: + continue + elif line[0] == '-': + break + else: + print 'Could not parse line:', line + continue + country, code = mo.group(1, 2) + if normalize: + words = country.split() + for i in range(len(words)): + w = words[i] + # XXX special cases + if w in ('AND', 'OF', 'OF)', 'name:', 'METROPOLITAN'): + words[i] = w.lower() + elif w == 'THE' and i <> 1: + words[i] = w.lower() + elif len(w) > 3 and w[1] == "'": + words[i] = w[0:3].upper() + w[3:].lower() + elif w in ('(U.S.)', 'U.S.'): + pass + elif w[0] == '(' and w <> '(local': + words[i] = '(' + w[1:].capitalize() + elif w.find('-') <> -1: + words[i] = '-'.join( + [s.capitalize() for s in w.split('-')]) + else: + words[i] = w.capitalize() + code = code.lower() + country = ' '.join(words) + print ' "%s": "%s",' % (code, country) + else: + print code, country + + elif line[0] == '-': + scanning = 1 + + if normalize: + print ' }' + + +def main(): + help = 0 + status = 0 + dump = 0 + parsefile = None + normalize = 0 + forcerev = 0 + + try: + opts, args = getopt.getopt( + sys.argv[1:], + 'p:rohd', + ['parse=', 'reverse', 'outputdict', 'help', 'dump']) + except getopt.error, msg: + usage(1, msg) + + for opt, arg in opts: + if opt in ('-h', '--help'): + help = 1 + elif opt in ('-d', '--dump'): + dump = 1 + elif opt in ('-p', '--parse'): + parsefile = arg + elif opt in ('-o', '--outputdict'): + normalize = 1 + elif opt in ('-r', '--reverse'): + forcerev = 1 + + if help: + usage(status) + + if dump: + print 'Non-geographic domains:' + codes = nameorgs.keys() + codes.sort() + for code in codes: + print ' %4s:' % code, nameorgs[code] + + print '\nCountry coded domains:' + codes = countries.keys() + codes.sort() + for code in codes: + print ' %2s:' % code, countries[code] + elif parsefile: + parse(parsefile, normalize) + else: + if not forcerev: + args = filter(None, map(resolve, args)) + args = filter(None, map(reverse, args)) + for arg in args: + print 'Where in the world is %s?' % arg + + + +# The mappings +nameorgs = { + # New top level domains as described by ICANN + # http://www.icann.org/tlds/ + "aero": "air-transport industry", + "arpa": "Arpanet", + "biz": "business", + "com": "commercial", + "coop": "cooperatives", + "edu": "educational", + "gov": "government", + "info": "unrestricted `info'", + "int": "international", + "mil": "military", + "museum": "museums", + "name": "`name' (for registration by individuals)", + "net": "networking", + "org": "non-commercial", + "pro": "professionals", + # These additional ccTLDs are included here even though they are not part + # of ISO 3166. IANA has 5 reserved ccTLDs as described here: + # + # http://www.iso.org/iso/en/prods-services/iso3166ma/04background-on-iso-3166/iso3166-1-and-ccTLDs.html + # + # but I can't find an official list anywhere. + # + # Note that `uk' is the common practice country code for the United + # Kingdom. AFAICT, the official `gb' code is routinely ignored! + # + # <D.M.Pick@qmw.ac.uk> tells me that `uk' was long in use before ISO3166 + # was adopted for top-level DNS zone names (although in the reverse order + # like uk.ac.qmw) and was carried forward (with the reversal) to avoid a + # large-scale renaming process as the UK switched from their old `Coloured + # Book' protocols over X.25 to Internet protocols over IP. + # + # See <url:ftp://ftp.ripe.net/ripe/docs/ripe-159.txt> + # + # Also, `su', while obsolete is still in limited use. + "ac": "Ascension Island", + "gg": "Guernsey", + "im": "Isle of Man", + "je": "Jersey", + "uk": "United Kingdom (common practice)", + "su": "Soviet Union (still in limited use)", + } + + + +countries = { + "af": "Afghanistan", + "al": "Albania", + "dz": "Algeria", + "as": "American Samoa", + "ad": "Andorra", + "ao": "Angola", + "ai": "Anguilla", + "aq": "Antarctica", + "ag": "Antigua and Barbuda", + "ar": "Argentina", + "am": "Armenia", + "aw": "Aruba", + "au": "Australia", + "at": "Austria", + "az": "Azerbaijan", + "bs": "Bahamas", + "bh": "Bahrain", + "bd": "Bangladesh", + "bb": "Barbados", + "by": "Belarus", + "be": "Belgium", + "bz": "Belize", + "bj": "Benin", + "bm": "Bermuda", + "bt": "Bhutan", + "bo": "Bolivia", + "ba": "Bosnia and Herzegowina", + "bw": "Botswana", + "bv": "Bouvet Island", + "br": "Brazil", + "io": "British Indian Ocean Territory", + "bn": "Brunei Darussalam", + "bg": "Bulgaria", + "bf": "Burkina Faso", + "bi": "Burundi", + "kh": "Cambodia", + "cm": "Cameroon", + "ca": "Canada", + "cv": "Cape Verde", + "ky": "Cayman Islands", + "cf": "Central African Republic", + "td": "Chad", + "cl": "Chile", + "cn": "China", + "cx": "Christmas Island", + "cc": "Cocos (Keeling) Islands", + "co": "Colombia", + "km": "Comoros", + "cg": "Congo", + "cd": "Congo, The Democratic Republic of the", + "ck": "Cook Islands", + "cr": "Costa Rica", + "ci": "Cote D'Ivoire", + "hr": "Croatia", + "cu": "Cuba", + "cy": "Cyprus", + "cz": "Czech Republic", + "dk": "Denmark", + "dj": "Djibouti", + "dm": "Dominica", + "do": "Dominican Republic", + "tp": "East Timor", + "ec": "Ecuador", + "eg": "Egypt", + "sv": "El Salvador", + "gq": "Equatorial Guinea", + "er": "Eritrea", + "ee": "Estonia", + "et": "Ethiopia", + "fk": "Falkland Islands (Malvinas)", + "fo": "Faroe Islands", + "fj": "Fiji", + "fi": "Finland", + "fr": "France", + "gf": "French Guiana", + "pf": "French Polynesia", + "tf": "French Southern Territories", + "ga": "Gabon", + "gm": "Gambia", + "ge": "Georgia", + "de": "Germany", + "gh": "Ghana", + "gi": "Gibraltar", + "gr": "Greece", + "gl": "Greenland", + "gd": "Grenada", + "gp": "Guadeloupe", + "gu": "Guam", + "gt": "Guatemala", + "gn": "Guinea", + "gw": "Guinea-Bissau", + "gy": "Guyana", + "ht": "Haiti", + "hm": "Heard Island and Mcdonald Islands", + "va": "Holy See (Vatican City State)", + "hn": "Honduras", + "hk": "Hong Kong", + "hu": "Hungary", + "is": "Iceland", + "in": "India", + "id": "Indonesia", + "ir": "Iran, Islamic Republic of", + "iq": "Iraq", + "ie": "Ireland", + "il": "Israel", + "it": "Italy", + "jm": "Jamaica", + "jp": "Japan", + "jo": "Jordan", + "kz": "Kazakstan", + "ke": "Kenya", + "ki": "Kiribati", + "kp": "Korea, Democratic People's Republic of", + "kr": "Korea, Republic of", + "kw": "Kuwait", + "kg": "Kyrgyzstan", + "la": "Lao People's Democratic Republic", + "lv": "Latvia", + "lb": "Lebanon", + "ls": "Lesotho", + "lr": "Liberia", + "ly": "Libyan Arab Jamahiriya", + "li": "Liechtenstein", + "lt": "Lithuania", + "lu": "Luxembourg", + "mo": "Macau", + "mk": "Macedonia, The Former Yugoslav Republic of", + "mg": "Madagascar", + "mw": "Malawi", + "my": "Malaysia", + "mv": "Maldives", + "ml": "Mali", + "mt": "Malta", + "mh": "Marshall Islands", + "mq": "Martinique", + "mr": "Mauritania", + "mu": "Mauritius", + "yt": "Mayotte", + "mx": "Mexico", + "fm": "Micronesia, Federated States of", + "md": "Moldova, Republic of", + "mc": "Monaco", + "mn": "Mongolia", + "ms": "Montserrat", + "ma": "Morocco", + "mz": "Mozambique", + "mm": "Myanmar", + "na": "Namibia", + "nr": "Nauru", + "np": "Nepal", + "nl": "Netherlands", + "an": "Netherlands Antilles", + "nc": "New Caledonia", + "nz": "New Zealand", + "ni": "Nicaragua", + "ne": "Niger", + "ng": "Nigeria", + "nu": "Niue", + "nf": "Norfolk Island", + "mp": "Northern Mariana Islands", + "no": "Norway", + "om": "Oman", + "pk": "Pakistan", + "pw": "Palau", + "ps": "Palestinian Territory, Occupied", + "pa": "Panama", + "pg": "Papua New Guinea", + "py": "Paraguay", + "pe": "Peru", + "ph": "Philippines", + "pn": "Pitcairn", + "pl": "Poland", + "pt": "Portugal", + "pr": "Puerto Rico", + "qa": "Qatar", + "re": "Reunion", + "ro": "Romania", + "ru": "Russian Federation", + "rw": "Rwanda", + "sh": "Saint Helena", + "kn": "Saint Kitts and Nevis", + "lc": "Saint Lucia", + "pm": "Saint Pierre and Miquelon", + "vc": "Saint Vincent and the Grenadines", + "ws": "Samoa", + "sm": "San Marino", + "st": "Sao Tome and Principe", + "sa": "Saudi Arabia", + "sn": "Senegal", + "sc": "Seychelles", + "sl": "Sierra Leone", + "sg": "Singapore", + "sk": "Slovakia", + "si": "Slovenia", + "sb": "Solomon Islands", + "so": "Somalia", + "za": "South Africa", + "gs": "South Georgia and the South Sandwich Islands", + "es": "Spain", + "lk": "Sri Lanka", + "sd": "Sudan", + "sr": "Suriname", + "sj": "Svalbard and Jan Mayen", + "sz": "Swaziland", + "se": "Sweden", + "ch": "Switzerland", + "sy": "Syrian Arab Republic", + "tw": "Taiwan, Province of China", + "tj": "Tajikistan", + "tz": "Tanzania, United Republic of", + "th": "Thailand", + "tg": "Togo", + "tk": "Tokelau", + "to": "Tonga", + "tt": "Trinidad and Tobago", + "tn": "Tunisia", + "tr": "Turkey", + "tm": "Turkmenistan", + "tc": "Turks and Caicos Islands", + "tv": "Tuvalu", + "ug": "Uganda", + "ua": "Ukraine", + "ae": "United Arab Emirates", + "gb": "United Kingdom", + "us": "United States", + "um": "United States Minor Outlying Islands", + "uy": "Uruguay", + "uz": "Uzbekistan", + "vu": "Vanuatu", + "ve": "Venezuela", + "vn": "Viet Nam", + "vg": "Virgin Islands, British", + "vi": "Virgin Islands, U.S.", + "wf": "Wallis and Futuna", + "eh": "Western Sahara", + "ye": "Yemen", + "yu": "Yugoslavia", + "zm": "Zambia", + "zw": "Zimbabwe", + } + +all = nameorgs.copy() +all.update(countries) + + +if __name__ == '__main__': + main() diff --git a/sys/src/cmd/python/mkconfig b/sys/src/cmd/python/mkconfig new file mode 100755 index 000000000..5f90e696f --- /dev/null +++ b/sys/src/cmd/python/mkconfig @@ -0,0 +1,54 @@ +#!/bin/rc + +cat <<! +/* Module configuration */ + +/* This file contains the table of built-in modules. + See init_builtin() in import.c. */ + +#include "Python.h" +! + +cat $* | awk '!/^#/ && NF>0 {if(NF==1) fn="init" $1; else fn=$2; printf("extern void %s(void);\n", fn);}' + +cat <<! + +extern void PyMarshal_Init(void); +extern void initimp(void); +extern void initgc(void); +extern void init_ast(void); +extern void init_types(void); + +struct _inittab _PyImport_Inittab[] = { + +! + +cat $* | awk '!/^#/ && NF>0 {if(NF==1) fn="init" $1; else fn=$2; printf("\t{\"%s\", %s},\n", $1, fn);}' + +cat <<! + + /* This module lives in marshal.c */ + {"marshal", PyMarshal_Init}, + + /* This lives in import.c */ + {"imp", initimp}, + + /* This lives in Python/Python-ast.c */ + {"_ast", init_ast}, + + /* This lives in Python/_types.c */ + {"_types", init_types}, + + /* These entries are here for sys.builtin_module_names */ + {"__main__", NULL}, + {"__builtin__", NULL}, + {"sys", NULL}, + {"exceptions", NULL}, + + /* This lives in gcmodule.c */ + {"gc", initgc}, + + /* Sentinel */ + {0, 0} +}; +! diff --git a/sys/src/cmd/python/mkfile b/sys/src/cmd/python/mkfile new file mode 100644 index 000000000..e0f97b812 --- /dev/null +++ b/sys/src/cmd/python/mkfile @@ -0,0 +1,52 @@ +APE=/sys/src/ape +<$APE/config + +CFLAGS=-FVwN +BIN=/$objtype/bin + +TARG=\ + python\ + +OFILES=\ + config.$O\ + plan9.$O\ + libextra.a$O\ + +LIB= \ + /$objtype/lib/ape/libpython.a\ + /$objtype/lib/ape/libssl.a\ + /$objtype/lib/ape/libcrypto.a + +LIBDIRS=Modules Objects Parser Python + +</sys/src/cmd/mkone + +CFLAGS=-c -I. -IInclude -DT$objtype -DPy_BUILD_CORE -DNDEBUG + +/$objtype/lib/ape/libpython.a: + for (i in $LIBDIRS) @{ + cd $i + mk + } + +libextra.a$O: + @{ + cd Extra + mk + } + +Extra/config: + for(i in `{du -a Extra | grep '.c$' | awk '{print $2}' | sed 's/..$//'}) + echo `{basename $i} >> Extra/config + +config.c: Modules/config Extra/config mkconfig + ./mkconfig Modules/config Extra/config >config.c + +clean:V: + for(i in $LIBDIRS Extra)@{ + cd $i + mk $target + } + rm -f *.[$OS] [$OS].out y.tab.? y.debug y.output libextra.a$O + rm -f Extra/config config.c + rm -f /$objtype/lib/ape/libpython.a diff --git a/sys/src/cmd/python/plan9.c b/sys/src/cmd/python/plan9.c new file mode 100644 index 000000000..a19392db4 --- /dev/null +++ b/sys/src/cmd/python/plan9.c @@ -0,0 +1,55 @@ +#include "Python.h" + +#define _PLAN9_SOURCE +#include <u.h> +#include <lib9.h> + +#if defined(T386) +#define FPINVAL (1<<0) +#else +Error define FPINVAL for your arch. grep /$cputype/include/u.h +#endif + +Threadarg *_threadarg; + +extern DL_EXPORT(int) Py_Main(int, char **); + +int +main(int argc, char **argv) +{ + Threadarg ta; + + setfcr(getfcr()&~FPINVAL); + memset(&ta, 0, sizeof ta); + _threadarg = &ta; + if(setjmp(ta.jb)){ + (*ta.fn)(ta.arg); + _exit(1); + } + return Py_Main(argc, argv); +} + + +char * +Py_GetPath(void) +{ + return "/sys/lib/python"; +} + +char * +Py_GetPrefix(void) +{ + return "/sys/lib/python"; +} + +char * +Py_GetExecPrefix(void) +{ + return "/sys/lib/python"; +} + +char * +Py_GetProgramFullPath(void) +{ + return "/bin/python"; +} diff --git a/sys/src/cmd/python/pyconfig.h b/sys/src/cmd/python/pyconfig.h new file mode 100644 index 000000000..aee1449a1 --- /dev/null +++ b/sys/src/cmd/python/pyconfig.h @@ -0,0 +1,984 @@ +/* pyconfig.h. Generated by configure. */ +/* pyconfig.h.in. Generated from configure.in by autoheader. */ + + +#ifndef Py_PYCONFIG_H +#define Py_PYCONFIG_H + +#define _POSIX_SOURCE +#define _BSD_EXTENSION +#define _LIMITS_EXTENSION +#define _C99_SNPRINTF_EXTENSION +#define _RESEARCH_SOURCE +#define PLAN9APE +#define PLAN9_THREADS +#define WITH_THREAD +#define HAVE_SOCK_OPTS + +typedef struct Threadarg Threadarg; + +#if defined(T386) || defined(Talpha) || defined(Tarm) || defined(Tpower) +#undef WORDS_BIGENDIAN +#elif defined(Tmips) || defined(Tsparc) +#define WORDS_BIGENDIAN +#else +Error unknown byte order +#endif + +#include <setjmp.h> + +struct Threadarg{ + void (*fn)(void*); + void *arg; + jmp_buf jb; +}; + +extern Threadarg *_threadarg; /* points to thread-local storage */ + +extern double hypot(double, double); +extern int setgrent(void); +extern int endgrent(void); +extern struct group* getgrent(void); + +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned long u_long; + +#define EISCONN 63 +#define EWOULDBLOCK 64 + +#define FD_SETSIZE 96 /* see /sys/include/ape/sys/select.h */ + +#define SIGWINCH 21 /* for curses */ + +#define S_ISSOCK S_ISFIFO /* for hg, see /sys/include/ape/sys/stat.h */ + +/* Define if --enable-ipv6 is specified */ +/* #undef ENABLE_IPV6 */ + +/* Define if getpgrp() must be called as getpgrp(0). */ +/* #define GETPGRP_HAVE_ARG 1 */ + +/* Define if gettimeofday() does not have second (timezone) argument This is + the case on Motorola V4 (R40V4.2) */ +/* #undef GETTIMEOFDAY_NO_TZ */ + +/* struct addrinfo (netdb.h) */ +/* #define HAVE_ADDRINFO 1 */ + +/* Define to 1 if you have the `alarm' function. */ +#define HAVE_ALARM 1 + +/* Define to 1 if you have the <bluetooth.h> header file. */ +/* #undef HAVE_BLUETOOTH_H */ + +/* Define if nice() returns success/failure instead of the new priority. */ +/* #undef HAVE_BROKEN_NICE */ + +/* Define if poll() sets errno on invalid file descriptors. */ +/* #undef HAVE_BROKEN_POLL */ + +/* Define if the Posix semaphores do not work on your system */ +/* #undef HAVE_BROKEN_POSIX_SEMAPHORES */ + +/* Define if pthread_sigmask() does not work on your system. */ +/* #undef HAVE_BROKEN_PTHREAD_SIGMASK */ + +/* Define to 1 if you have the `chown' function. */ +#define HAVE_CHOWN 1 + +/* Define if you have the 'chroot' function. */ +/* #undef HAVE_CHROOT */ + +/* Define to 1 if you have the `clock' function. */ +#define HAVE_CLOCK 1 + +/* Define to 1 if you have the `confstr' function. */ +/* #undef HAVE_CONFSTR */ + +/* Define to 1 if you have the <conio.h> header file. */ +/* #undef HAVE_CONIO_H */ + +/* Define to 1 if you have the `ctermid' function. */ +#define HAVE_CTERMID 1 + +/* Define if you have the 'ctermid_r' function. */ +/* #undef HAVE_CTERMID_R */ + +/* Define to 1 if you have the <curses.h> header file. */ +#define HAVE_CURSES_H 1 + +/* Define if you have the 'is_term_resized' function. */ +/* #undef HAVE_CURSES_IS_TERM_RESIZED */ + +/* Define if you have the 'resizeterm' function. */ +/* #undef HAVE_CURSES_RESIZETERM */ + +/* Define if you have the 'resize_term' function. */ +#define HAVE_CURSES_RESIZE_TERM 1 + +/* Define to 1 if you have the device macros. */ +/* #undef HAVE_DEVICE_MACROS */ + +/* Define if we have /dev/ptc. */ +/* #undef HAVE_DEV_PTC */ + +/* Define if we have /dev/ptmx. */ +/* #undef HAVE_DEV_PTMX */ + +/* Define to 1 if you have the <direct.h> header file. */ +/* #undef HAVE_DIRECT_H */ + +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the <dlfcn.h> header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define to 1 if you have the `dlopen' function. */ +/* #undef HAVE_DLOPEN */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Defined when any dynamic module loading is enabled. */ +/* #undef HAVE_DYNAMIC_LOADING */ + +/* Define to 1 if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `execv' function. */ +#define HAVE_EXECV 1 + +/* Define if you have the 'fchdir' function. */ +/* #undef HAVE_FCHDIR */ + +/* Define to 1 if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the 'fdatasync' function. */ +/* #undef HAVE_FDATASYNC */ + +/* Define if you have the 'flock' function. */ +/* #undef HAVE_FLOCK */ + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `forkpty' function. */ +/* #undef HAVE_FORKPTY */ + +/* Define to 1 if you have the `fpathconf' function. */ +#define HAVE_FPATHCONF 1 + +/* Define to 1 if you have the `fseek64' function. */ +/* #undef HAVE_FSEEK64 */ + +/* Define to 1 if you have the `fseeko' function. */ +#define HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fstatvfs' function. */ +/* #undef HAVE_FSTATVFS */ + +/* Define if you have the 'fsync' function. */ +/* #undef HAVE_FSYNC */ + +/* Define to 1 if you have the `ftell64' function. */ +/* #undef HAVE_FTELL64 */ + +/* Define to 1 if you have the `ftello' function. */ +#define HAVE_FTELLO 1 + +/* Define to 1 if you have the `ftime' function. */ +/* #undef HAVE_FTIME */ + +/* Define to 1 if you have the `ftruncate' function. */ +/* #define HAVE_FTRUNCATE 1 */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `gai_strerror' function. */ +/* #undef HAVE_GAI_STRERROR */ + +/* Define if you have the getaddrinfo function. */ +/* #undef HAVE_GETADDRINFO */ + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define this if you have flockfile(), getc_unlocked(), and funlockfile() */ +/* #undef HAVE_GETC_UNLOCKED */ + +/* Define to 1 if you have the `getgroups' function. */ +#define HAVE_GETGROUPS 1 + +/* Define to 1 if you have the `gethostbyname' function. */ +#define HAVE_GETHOSTBYNAME 1 + + + +/* Define this if you have the 3-arg version of gethostbyname_r(). */ +/* #undef HAVE_GETHOSTBYNAME_R_3_ARG */ + +/* Define this if you have the 5-arg version of gethostbyname_r(). */ +/* #undef HAVE_GETHOSTBYNAME_R_5_ARG */ + +/* Define this if you have the 6-arg version of gethostbyname_r(). */ +/* #undef HAVE_GETHOSTBYNAME_R_6_ARG */ + +/* Define to 1 if you have the `getloadavg' function. */ +/* #undef HAVE_GETLOADAVG */ + +/* Define to 1 if you have the `getlogin' function. */ +#define HAVE_GETLOGIN 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +/* #undef HAVE_GETNAMEINFO */ + +/* Define if you have the 'getpagesize' function. */ +/* #undef HAVE_GETPAGESIZE */ + +/* Define to 1 if you have the `getpeername' function. */ +#define HAVE_GETPEERNAME 1 + +/* Define to 1 if you have the `getpgid' function. */ +/* #undef HAVE_GETPGID */ + +/* Define to 1 if you have the `getpgrp' function. */ +#define HAVE_GETPGRP 1 + +/* Define to 1 if you have the `getpid' function. */ +#define HAVE_GETPID 1 + +/* Define to 1 if you have the `getpriority' function. */ +/* #undef HAVE_GETPRIORITY */ + +/* Define to 1 if you have the `getpwent' function. */ +/* #define HAVE_GETPWENT 1 */ + +/* Define to 1 if you have the `getsid' function. */ +/* #undef HAVE_GETSID */ + +/* Define to 1 if you have the `getspent' function. */ +/* #undef HAVE_GETSPENT */ + +/* Define to 1 if you have the `getspnam' function. */ +/* #undef HAVE_GETSPNAM */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getwd' function. */ +/* #undef HAVE_GETWD */ + +/* Define to 1 if you have the <grp.h> header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the 'hstrerror' function. */ +/* #undef HAVE_HSTRERROR */ + +/* Define to 1 if you have the `hypot' function. */ +#define HAVE_HYPOT 1 + +/* Define if you have the 'inet_aton' function. */ +/* #undef HAVE_INET_ATON */ + +/* Define if you have the 'inet_pton' function. */ +/* #undef HAVE_INET_PTON */ + +/* Define to 1 if you have the <inttypes.h> header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the <io.h> header file. */ +/* #undef HAVE_IO_H */ + +/* Define to 1 if you have the `kill' function. */ +#define HAVE_KILL 1 + +/* Define to 1 if you have the `killpg' function. */ +/* #undef HAVE_KILLPG */ + +/* Define to 1 if you have the <langinfo.h> header file. */ +/* #undef HAVE_LANGINFO_H */ + +/* Defined to enable large file support when an off_t is bigger than a long + and long long is available and at least as big as an off_t. You may need to + add some flags for configuration and compilation to enable this mode. (For + Solaris and Linux, the necessary defines are already defined.) */ +#define HAVE_LARGEFILE_SUPPORT 1 + +/* Define to 1 if you have the `lchown' function. */ +/* #undef HAVE_LCHOWN */ + +/* Define to 1 if you have the `dl' library (-ldl). */ +/* #undef HAVE_LIBDL */ + +/* Define to 1 if you have the `dld' library (-ldld). */ +/* #undef HAVE_LIBDLD */ + +/* Define to 1 if you have the `ieee' library (-lieee). */ +/* #undef HAVE_LIBIEEE */ + +/* Define to 1 if you have the <libintl.h> header file. */ +/* #undef HAVE_LIBINTL_H */ + +/* Define to 1 if you have the `readline' library (-lreadline). */ +/* #undef HAVE_LIBREADLINE */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +/* #undef HAVE_LIBRESOLV */ + +/* Define to 1 if you have the `termcap' library (-ltermcap). */ +/* #undef HAVE_LIBTERMCAP */ + +/* Define to 1 if you have the <libutil.h> header file. */ +/* #undef HAVE_LIBUTIL_H */ + +/* Define if you have the 'link' function. */ +#define HAVE_LINK 1 + +/* Define to 1 if you have the <linux/netlink.h> header file. */ +/* #undef HAVE_LINUX_NETLINK_H */ + +/* Define this if you have the type long long. */ +#define HAVE_LONG_LONG 1 + +/* Define to 1 if you have the `lstat' function. */ +#define HAVE_LSTAT 1 + +/* Define this if you have the makedev macro. */ +/* #undef HAVE_MAKEDEV */ + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the <memory.h> header file. */ +/* #undef HAVE_MEMORY_H */ + +/* Define to 1 if you have the `mkfifo' function. */ +#define HAVE_MKFIFO 1 + +/* Define to 1 if you have the `mknod' function. */ +/* #undef HAVE_MKNOD */ + +/* Define to 1 if you have the `mktime' function. */ +#define HAVE_MKTIME 1 + +/* Define to 1 if you have the `mremap' function. */ +/* #undef HAVE_MREMAP */ + +/* Define to 1 if you have the <ncurses.h> header file. */ +/* #undef HAVE_NCURSES_H */ + +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the <netpacket/packet.h> header file. */ +/* #undef HAVE_NETPACKET_PACKET_H */ + +/* Define to 1 if you have the `nice' function. */ +/* #undef HAVE_NICE */ + +/* Define to 1 if you have the `openpty' function. */ +/* #undef HAVE_OPENPTY */ + +/* Define to 1 if you have the `pathconf' function. */ +#define HAVE_PATHCONF 1 + +/* Define to 1 if you have the `pause' function. */ +#define HAVE_PAUSE 1 + +/* Define to 1 if you have the `plock' function. */ +/* #undef HAVE_PLOCK */ + +/* Define to 1 if you have the `poll' function. */ +/* #undef HAVE_POLL */ + +/* Define to 1 if you have the <poll.h> header file. */ +/* #undef HAVE_POLL_H */ + +/* Define to 1 if you have the <process.h> header file. */ +/* #undef HAVE_PROCESS_H */ + +/* Define if your compiler supports function prototype */ +#define HAVE_PROTOTYPES 1 + +/* Define if you have GNU PTH threads. */ +/* #undef HAVE_PTH */ + +/* Defined for Solaris 2.6 bug in pthread header. */ +/* #undef HAVE_PTHREAD_DESTRUCTOR */ + +/* Define to 1 if you have the <pthread.h> header file. */ +/* #undef HAVE_PTHREAD_H */ + +/* Define to 1 if you have the `pthread_init' function. */ +/* #undef HAVE_PTHREAD_INIT */ + +/* Define to 1 if you have the `pthread_sigmask' function. */ +/* #undef HAVE_PTHREAD_SIGMASK */ + +/* Define to 1 if you have the <pty.h> header file. */ +/* #undef HAVE_PTY_H */ + +/* Define to 1 if you have the `putenv' function. */ +#define HAVE_PUTENV 1 + +/* Define to 1 if you have the `readlink' function. */ +#define HAVE_READLINK 1 + +/* Define to 1 if you have the `realpath' function. */ +/* #undef HAVE_REALPATH */ + +/* Define if you have readline 2.1 */ +/* #undef HAVE_RL_CALLBACK */ + +/* Define if you can turn off readline's signal handling. */ +/* #undef HAVE_RL_CATCH_SIGNAL */ + +/* Define if you have readline 2.2 */ +/* #undef HAVE_RL_COMPLETION_APPEND_CHARACTER */ + +/* Define if you have readline 4.2 */ +/* #undef HAVE_RL_COMPLETION_MATCHES */ + +/* Define if you have readline 4.0 */ +/* #undef HAVE_RL_PRE_INPUT_HOOK */ + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `setegid' function. */ +/* #undef HAVE_SETEGID */ + +/* Define to 1 if you have the `seteuid' function. */ +/* #undef HAVE_SETEUID */ + +/* Define to 1 if you have the `setgid' function. */ +#define HAVE_SETGID 1 + +/* Define if you have the 'setgroups' function. */ +/* #undef HAVE_SETGROUPS */ + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setpgid' function. */ +#define HAVE_SETPGID 1 + +/* Define to 1 if you have the `setpgrp' function. */ +/* #undef HAVE_SETPGRP */ + +/* Define to 1 if you have the `setregid' function. */ +/* #undef HAVE_SETREGID */ + +/* Define to 1 if you have the `setreuid' function. */ +/* #undef HAVE_SETREUID */ + +/* Define to 1 if you have the `setsid' function. */ +#define HAVE_SETSID 1 + +/* Define to 1 if you have the `setuid' function. */ +#define HAVE_SETUID 1 + +/* Define to 1 if you have the `setvbuf' function. */ +#define HAVE_SETVBUF 1 + +/* Define to 1 if you have the <shadow.h> header file. */ +/* #undef HAVE_SHADOW_H */ + +/* Define to 1 if you have the `sigaction' function. */ +#define HAVE_SIGACTION 1 + +/* Define to 1 if you have the `siginterrupt' function. */ +/* #undef HAVE_SIGINTERRUPT */ + +/* Define to 1 if you have the <signal.h> header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the `sigrelse' function. */ +/* #undef HAVE_SIGRELSE */ + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define if sockaddr has sa_len member */ +/* #undef HAVE_SOCKADDR_SA_LEN */ + +/* struct sockaddr_storage (sys/socket.h) */ +#define HAVE_SOCKADDR_STORAGE 1 + +/* Define if you have the 'socketpair' function. */ +#define HAVE_SOCKETPAIR 1 + +/* Define if your compiler provides ssize_t */ +#define HAVE_SSIZE_T 1 + +/* Define to 1 if you have the `statvfs' function. */ +/* #undef HAVE_STATVFS */ + +/* Define if you have struct stat.st_mtim.tv_nsec */ +/* #undef HAVE_STAT_TV_NSEC */ + +/* Define if you have struct stat.st_mtimensec */ +/* #undef HAVE_STAT_TV_NSEC2 */ + +/* Define if your compiler supports variable length function prototypes (e.g. + void fprintf(FILE *, char *, ...);) *and* <stdarg.h> */ +#define HAVE_STDARG_PROTOTYPES 1 + +/* Define to 1 if you have the <stdint.h> header file. */ +/* #undef HAVE_STDINT_H */ + +/* Define to 1 if you have the <stdlib.h> header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the <strings.h> header file. */ +/* #undef HAVE_STRINGS_H */ + +/* Define to 1 if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the <stropts.h> header file. */ +/* #undef HAVE_STROPTS_H */ + +/* Define to 1 if `st_birthtime' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BIRTHTIME */ + +/* Define to 1 if `st_blksize' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BLKSIZE */ + +/* Define to 1 if `st_blocks' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_BLOCKS */ + +/* Define to 1 if `st_flags' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_FLAGS */ + +/* Define to 1 if `st_gen' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_GEN */ + +/* Define to 1 if `st_rdev' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_RDEV */ + +/* Define to 1 if `tm_zone' is member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM_TM_ZONE */ + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +/* #undef HAVE_ST_BLOCKS */ + +/* Define if you have the 'symlink' function. */ +#define HAVE_SYMLINK 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the <sysexits.h> header file. */ +/* #undef HAVE_SYSEXITS_H */ + +/* Define to 1 if you have the <sys/audioio.h> header file. */ +/* #undef HAVE_SYS_AUDIOIO_H */ + +/* Define to 1 if you have the <sys/bsdtty.h> header file. */ +/* #undef HAVE_SYS_BSDTTY_H */ + +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the <sys/file.h> header file. */ +/* #undef HAVE_SYS_FILE_H */ + +/* Define to 1 if you have the <sys/loadavg.h> header file. */ +/* #undef HAVE_SYS_LOADAVG_H */ + +/* Define to 1 if you have the <sys/lock.h> header file. */ +/* #undef HAVE_SYS_LOCK_H */ + +/* Define to 1 if you have the <sys/mkdev.h> header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the <sys/modem.h> header file. */ +/* #undef HAVE_SYS_MODEM_H */ + +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the <sys/param.h> header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the <sys/poll.h> header file. */ +/* #undef HAVE_SYS_POLL_H */ + +/* Define to 1 if you have the <sys/resource.h> header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the <sys/select.h> header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the <sys/statvfs.h> header file. */ +/* #undef HAVE_SYS_STATVFS_H */ + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the <sys/times.h> header file. */ +#define HAVE_SYS_TIMES_H 1 + +/* Define to 1 if you have the <sys/time.h> header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the <sys/types.h> header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the <sys/un.h> header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define to 1 if you have the <sys/utsname.h> header file. */ +#define HAVE_SYS_UTSNAME_H 1 + +/* Define to 1 if you have the <sys/wait.h> header file. */ +#define HAVE_SYS_WAIT_H 1 + +/* Define to 1 if you have the `tcgetpgrp' function. */ +#define HAVE_TCGETPGRP 1 + +/* Define to 1 if you have the `tcsetpgrp' function. */ +#define HAVE_TCSETPGRP 1 + +/* Define to 1 if you have the `tempnam' function. */ +/* #undef HAVE_TEMPNAM */ + +/* Define to 1 if you have the <termios.h> header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define to 1 if you have the <term.h> header file. */ +#define HAVE_TERM_H 1 + +/* Define to 1 if you have the <thread.h> header file. */ +/* #undef HAVE_THREAD_H */ + +/* Define to 1 if you have the `timegm' function. */ +/* #undef HAVE_TIMEGM */ + +/* Define to 1 if you have the `times' function. */ +#define HAVE_TIMES 1 + +/* Define to 1 if you have the `tmpfile' function. */ +#define HAVE_TMPFILE 1 + +/* Define to 1 if you have the `tmpnam' function. */ +#define HAVE_TMPNAM 1 + +/* Define to 1 if you have the `tmpnam_r' function. */ +/* #undef HAVE_TMPNAM_R */ + +/* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use + `HAVE_STRUCT_TM_TM_ZONE' instead. */ +/* #undef HAVE_TM_ZONE */ + +/* Define to 1 if you have the `truncate' function. */ +/* #undef HAVE_TRUNCATE */ + +/* Define to 1 if you don't have `tm_zone' but do have the external array + `tzname'. */ +#define HAVE_TZNAME 1 + +/* Define this if you have tcl and TCL_UTF_MAX==6 */ +/* #undef HAVE_UCS4_TCL */ + +/* Define to 1 if the system has the type `uintptr_t'. */ +/* #undef HAVE_UINTPTR_T */ + +/* Define to 1 if you have the `uname' function. */ +#define HAVE_UNAME 1 + +/* Define to 1 if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `unsetenv' function. */ +/* #undef HAVE_UNSETENV */ + +/* Define if you have a useable wchar_t type defined in wchar.h; useable means + wchar_t must be an unsigned type with at least 16 bits. (see + Include/unicodeobject.h). */ +/* #undef HAVE_USABLE_WCHAR_T */ + +/* Define to 1 if you have the `utimes' function. */ +/* #undef HAVE_UTIMES */ + +/* Define to 1 if you have the <utime.h> header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if you have the `wait3' function. */ +#define HAVE_WAIT3 1 + +/* Define to 1 if you have the `wait4' function. */ +#define HAVE_WAIT4 1 + +/* Define to 1 if you have the `waitpid' function. */ +#define HAVE_WAITPID 1 + +/* Define if the compiler provides a wchar.h header file. */ +/* #undef HAVE_WCHAR_H */ + +/* Define to 1 if you have the `wcscoll' function. */ +/* #undef HAVE_WCSCOLL */ + +/* Define if tzset() actually switches the local timezone in a meaningful way. + */ +/* #undef HAVE_WORKING_TZSET */ + +/* Define if the zlib library has inflateCopy */ +#define HAVE_ZLIB_COPY 1 + +/* Define to 1 if you have the `_getpty' function. */ +#define HAVE__GETPTY 1 + +/* Define if you are using Mach cthreads directly under /include */ +/* #undef HURD_C_THREADS */ + +/* Define if you are using Mach cthreads under mach / */ +/* #undef MACH_C_THREADS */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>. + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + <sysmacros.h>. */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Define if mvwdelch in curses.h is an expression. */ +#define MVWDELCH_IS_EXPRESSION 1 + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Define to the full name of this package. */ +/* #undef PACKAGE_NAME */ + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the version of this package. */ +/* #undef PACKAGE_VERSION */ + +/* Defined if PTHREAD_SCOPE_SYSTEM supported. */ +/* #undef PTHREAD_SYSTEM_SCHED_SUPPORTED */ + +/* Define to printf format modifier for Py_ssize_t */ +/* #undef PY_FORMAT_SIZE_T */ + +/* Define as the integral type used for Unicode representation. */ +#define PY_UNICODE_TYPE unsigned short + +/* Define if you want to build an interpreter with many run-time checks. */ +/* #undef Py_DEBUG */ + +/* Defined if Python is built as a shared library. */ +/* #undef Py_ENABLE_SHARED */ + +/* Define as the size of the unicode type. */ +#define Py_UNICODE_SIZE 2 + +/* Define if you want to have a Unicode type. */ +#define Py_USING_UNICODE 1 + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define if setpgrp() must be called as setpgrp(0, 0). */ +/* #undef SETPGRP_HAVE_ARG */ + +/* Define this to be extension of shared libraries (including the dot!). */ +#define SHLIB_EXT ".so" + +/* Define if i>>j for signed int i does not extend the sign bit when i < 0 */ +/* #undef SIGNED_RIGHT_SHIFT_ZERO_FILLS */ + +/* The size of a `double', as computed by sizeof. */ +#define SIZEOF_DOUBLE 8 + +/* The size of a `float', as computed by sizeof. */ +#define SIZEOF_FLOAT 4 + +/* The size of a `fpos_t', as computed by sizeof. */ +#define SIZEOF_FPOS_T 8 + +/* The size of a `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of a `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of a `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The number of bytes in an off_t. */ +#define SIZEOF_OFF_T 8 + +/* The number of bytes in a pthread_t. */ +/* #undef SIZEOF_PTHREAD_T */ + +/* The size of a `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* The size of a `size_t', as computed by sizeof. */ +#define SIZEOF_SIZE_T 4 + +/* The number of bytes in a time_t. */ +#define SIZEOF_TIME_T 4 + +/* The size of a `uintptr_t', as computed by sizeof. */ +/* #undef SIZEOF_UINTPTR_T */ + +/* The size of a `void *', as computed by sizeof. */ +#define SIZEOF_VOID_P 4 + +/* The size of a `wchar_t', as computed by sizeof. */ +/* #undef SIZEOF_WCHAR_T */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if you can safely include both <sys/select.h> and <sys/time.h> + (which you can't on SCO ODT 3.0). */ +#define SYS_SELECT_WITH_SYS_TIME 1 + +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 if your <sys/time.h> declares `struct tm'. */ +/* #undef TM_IN_SYS_TIME */ + +/* Define if you want to use MacPython modules on MacOSX in unix-Python. */ +/* #undef USE_TOOLBOX_OBJECT_GLUE */ + +/* Define if a va_list is an array of some kind */ +/* #undef VA_LIST_IS_ARRAY */ + +/* Define if you want SIGFPE handled (see Include/pyfpe.h). */ +/* #undef WANT_SIGFPE_HANDLER */ + +/* Define if you want wctype.h functions to be used instead of the one + supplied by Python itself. (see Include/unicodectype.h). */ +/* #undef WANT_WCTYPE_FUNCTIONS */ + +/* Define if WINDOW in curses.h offers a field _flags. */ +/* #define WINDOW_HAS_FLAGS 1 */ + +/* Define if you want documentation strings in extension modules */ +#define WITH_DOC_STRINGS 1 + +/* Define if you want to use the new-style (Openstep, Rhapsody, MacOS) dynamic + linker (dyld) instead of the old-style (NextStep) dynamic linker (rld). + Dyld is necessary to support frameworks. */ +/* #undef WITH_DYLD */ + +/* Define to 1 if libintl is needed for locale functions. */ +/* #undef WITH_LIBINTL */ + +/* Define if you want to produce an OpenStep/Rhapsody framework (shared + library plus accessory files). */ +/* #undef WITH_NEXT_FRAMEWORK */ + +/* Define if you want to compile in Python-specific mallocs */ +#define WITH_PYMALLOC 1 + +/* Define to profile with the Pentium timestamp counter */ +/* #undef WITH_TSC */ + + + /* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). + + The block below does compile-time checking for endianness on platforms + that use GCC and therefore allows compiling fat binaries on OSX by using + '-arch ppc -arch i386' as the compile flags. The phrasing was choosen + such that the configure-result is used on systems that don't use GCC. + */ +#ifdef __BIG_ENDIAN__ +#define WORDS_BIGENDIAN 1 +#else +#ifndef __LITTLE_ENDIAN__ +/* #undef WORDS_BIGENDIAN */ +#endif +#endif + +/* Define to 1 if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* # undef _ALL_SOURCE */ +#endif + +/* Define on Irix to enable u_int */ +#define _BSD_TYPES 1 + +/* This must be set to 64 on some systems to enable large file support. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define on Linux to activate all library features */ +#define _GNU_SOURCE 1 + +/* This must be defined on some systems to enable large file support. */ +/* #undef _LARGEFILE_SOURCE */ + +/* Define on NetBSD to activate all library features */ +#define _NETBSD_SOURCE 1 + +/* Define to activate features from IEEE Stds 1003.1-2001 */ +#define _POSIX_C_SOURCE 200112L + +/* Define to force use of thread-safe errno, h_errno, and other functions */ +#define _REENTRANT 1 + +/* Define to the level of X/Open that your system supports */ +#define _XOPEN_SOURCE 600 + +/* Define to activate Unix95-and-earlier features */ +#define _XOPEN_SOURCE_EXTENDED 1 + +/* Define on FreeBSD to activate all library features */ +#define __BSD_VISIBLE 1 + +/* Define to 1 if type `char' is unsigned and you are not using gcc. */ +#ifndef __CHAR_UNSIGNED__ +/* # undef __CHAR_UNSIGNED__ */ +#endif + + + + +/* Define to `int' if <sys/socket.h> does not define. */ +#define socklen_t int + + +/* Define to empty if the keyword does not work. */ +/* #undef volatile */ + + +/* Define the macros needed if on a UnixWare 7.x system. */ +#if defined(__USLC__) && defined(__SCO_VERSION__) +#define STRICT_SYSV_CURSES /* Don't use ncurses extensions */ +#endif + +#endif /*Py_PYCONFIG_H*/ + diff --git a/sys/src/cmd/python/python.proto b/sys/src/cmd/python/python.proto new file mode 100644 index 000000000..601df33df --- /dev/null +++ b/sys/src/cmd/python/python.proto @@ -0,0 +1,14 @@ +386 - sys sys + bin - sys sys + python - sys sys +sys - sys sys + lib - sys sys + python - sys sys + + - sys sys + man - sys sys + 1 - sys sys + python - sys sys + src - sys sys + cmd - sys sys + python - sys sys + + - sys sys -- cgit v1.2.3